From ef416fc25c4af449e930416117bedb12fc9924ba Mon Sep 17 00:00:00 2001 From: jlovell Date: Fri, 13 Jan 2006 01:51:53 +0000 Subject: [PATCH] Load cups into easysw/current. git-svn-id: svn+ssh://src.apple.com/svn/cups/easysw/current@2 a1ca3aef-8c08-0410-bb20-df032aa958be --- CGI.txt | 81 + CHANGES-1.0.txt | 217 + CHANGES-1.1.txt | 3462 +++ CHANGES.txt | 286 + CREDITS.txt | 33 + ENCRYPTION.txt | 142 + INSTALL.txt | 190 + LICENSE.html | 1068 + LICENSE.txt | 964 + Makedefs.in | 193 + Makefile | 171 + README.txt | 290 + backend/Dependencies | 25 + backend/Makefile | 178 + backend/betest.c | 87 + backend/easysw-firewire-design.txt | 71 + backend/easysw-firewire-linux.txt | 35 + backend/ieee1284.c | 373 + backend/ieee1394-linux.c | 877 + backend/ieee1394.c | 263 + backend/ieee1394.h | 103 + backend/ipp.c | 1468 + backend/lpd.c | 1149 + backend/parallel.c | 731 + backend/scsi-irix.c | 231 + backend/scsi-linux.c | 249 + backend/scsi.c | 223 + backend/serial.c | 1114 + backend/socket.c | 418 + backend/test1284.c | 95 + backend/usb-darwin.c | 1899 ++ backend/usb-unix.c | 620 + backend/usb.c | 273 + berkeley/Dependencies | 14 + berkeley/Makefile | 112 + berkeley/lpc.c | 524 + berkeley/lpq.c | 640 + berkeley/lpr.c | 495 + berkeley/lprm.c | 284 + cgi-bin/Dependencies | 50 + cgi-bin/Makefile | 151 + cgi-bin/admin.c | 3572 +++ cgi-bin/cgi-private.h | 44 + cgi-bin/cgi.h | 106 + cgi-bin/classes.c | 396 + cgi-bin/help-index.c | 1103 + cgi-bin/help-index.h | 73 + cgi-bin/help.c | 362 + cgi-bin/html.c | 186 + cgi-bin/ipp-var.c | 896 + cgi-bin/jobs.c | 238 + cgi-bin/multipart.dat | Bin 0 -> 50411 bytes cgi-bin/printers.c | 434 + cgi-bin/search.c | 368 + cgi-bin/template.c | 573 + cgi-bin/testcgi.c | 84 + cgi-bin/testhi.c | 116 + cgi-bin/testhi.html | 29 + cgi-bin/var.c | 1024 + conf/Makefile | 80 + conf/classes.conf | 89 + conf/client.conf | 67 + conf/cupsd.conf.in | 76 + conf/mime.convs | 119 + conf/mime.types | 169 + conf/pam.darwin | 7 + conf/pam.irix | 3 + conf/pam.std.in | 2 + conf/printcap | 2 + conf/printers.conf | 96 + config-scripts/cups-common.m4 | 197 + config-scripts/cups-compiler.m4 | 200 + config-scripts/cups-directories.m4 | 279 + config-scripts/cups-image.m4 | 98 + config-scripts/cups-largefile.m4 | 61 + config-scripts/cups-libtool.m4 | 49 + config-scripts/cups-manpages.m4 | 101 + config-scripts/cups-network.m4 | 89 + config-scripts/cups-opsys.m4 | 99 + config-scripts/cups-pam.m4 | 98 + config-scripts/cups-scripting.m4 | 91 + config-scripts/cups-sharedlibs.m4 | 156 + config-scripts/cups-slp.m4 | 48 + config-scripts/cups-ssl.m4 | 109 + config-scripts/cups-threads.m4 | 51 + config.h.in | 343 + configure.in | 57 + cups-config.in | 134 + cups.osx | 39 + cups.plist | 7 + cups.sh.in | 211 + cups.strings | 9 + cups/Dependencies | 66 + cups/Makefile | 342 + cups/api-array.shtml | 54 + cups/api-cups.shtml | 48 + cups/api-filedir.shtml | 66 + cups/api-filter.shtml | 49 + cups/api-httpipp.shtml | 48 + cups/api-ppd.shtml | 48 + cups/array.c | 828 + cups/array.h | 83 + cups/attr.c | 184 + cups/auth.c | 249 + cups/backchannel.c | 201 + cups/backend.h | 50 + cups/cups.h | 237 + cups/debug.h | 59 + cups/dest.c | 865 + cups/dir.c | 437 + cups/dir.h | 77 + cups/emit.c | 816 + cups/encode.c | 471 + cups/extended.c | 307 + cups/file.c | 1680 ++ cups/file.h | 105 + cups/getputfile.c | 435 + cups/globals.c | 202 + cups/globals.h | 156 + cups/http-addr.c | 545 + cups/http-addrlist.c | 588 + cups/http-private.h | 126 + cups/http-support.c | 1195 + cups/http.c | 2436 ++ cups/http.h | 473 + cups/i18n.h | 90 + cups/ipp-support.c | 332 + cups/ipp.c | 2763 ++ cups/ipp.h | 477 + cups/langprintf.c | 140 + cups/language.c | 1240 + cups/language.h | 122 + cups/libcups_s.exp | 21 + cups/mark.c | 443 + cups/md5-apple.h | 39 + cups/md5.c | 344 + cups/md5.h | 74 + cups/md5passwd.c | 151 + cups/normalize.c | 2177 ++ cups/normalize.h | 334 + cups/options.c | 573 + cups/page.c | 191 + cups/ppd.c | 3070 ++ cups/ppd.h | 421 + cups/sample.ppd | 299 + cups/snprintf.c | 367 + cups/string.c | 226 + cups/string.h | 130 + cups/tempfile.c | 240 + cups/testarray.c | 513 + cups/testfile.c | 400 + cups/testhttp.c | 514 + cups/testi18n.c | 791 + cups/testipp.c | 649 + cups/testlang.c | 89 + cups/transcode.c | 1668 ++ cups/transcode.h | 159 + cups/usersys.c | 463 + cups/utf8demo.txt | 213 + cups/util.c | 1892 ++ data/HPGLprolog | 37 + data/Makefile | 160 + data/classified | 277 + data/confidential | 277 + data/cups.irix | 3 + data/cups.pam | 2 + data/cups.suse | 2 + data/euc-cn.txt | 7536 +++++ data/euc-jp.txt | 15184 ++++++++++ data/euc-kr.txt | 8371 ++++++ data/euc-tw.txt | 17840 ++++++++++++ data/i18n_sdd.txt | 2337 ++ data/iso-8859-1 | 251 + data/iso-8859-1.txt | 303 + data/iso-8859-10 | 251 + data/iso-8859-10.txt | 303 + data/iso-8859-11.txt | 249 + data/iso-8859-13 | 251 + data/iso-8859-13.txt | 299 + data/iso-8859-14 | 251 + data/iso-8859-14.txt | 301 + data/iso-8859-15 | 251 + data/iso-8859-15.txt | 303 + data/iso-8859-16.txt | 299 + data/iso-8859-2 | 253 + data/iso-8859-2.txt | 303 + data/iso-8859-3 | 244 + data/iso-8859-3.txt | 296 + data/iso-8859-4 | 251 + data/iso-8859-4.txt | 303 + data/iso-8859-5 | 251 + data/iso-8859-5.txt | 303 + data/iso-8859-6 | 206 + data/iso-8859-6.txt | 260 + data/iso-8859-7 | 246 + data/iso-8859-7.txt | 302 + data/iso-8859-8 | 214 + data/iso-8859-8.txt | 270 + data/iso-8859-9 | 251 + data/iso-8859-9.txt | 307 + data/koi8-r | 261 + data/koi8-r.txt | 257 + data/koi8-u | 259 + data/koi8-u.txt | 257 + data/psglyphs | 1051 + data/secret | 277 + data/standard | 261 + data/testprint.ps | 636 + data/topsecret | 277 + data/unclassified | 277 + data/uni-comb.txt | 299 + data/uni-fold.txt | 713 + data/uni-full.txt | 788 + data/uni-line.txt | 1126 + data/uni-nfc.txt | 989 + data/uni-nfd.txt | 1312 + data/uni-nfkd.txt | 3486 +++ data/uni-prop.txt | 10620 +++++++ data/unibreak.txt | 1354 + data/utf-8 | 39 + data/windows-1250 | 254 + data/windows-1250.txt | 274 + data/windows-1251 | 258 + data/windows-1251.txt | 274 + data/windows-1252 | 254 + data/windows-1252.txt | 274 + data/windows-1253 | 243 + data/windows-1253.txt | 274 + data/windows-1254 | 252 + data/windows-1254.txt | 274 + data/windows-1255 | 236 + data/windows-1255.txt | 274 + data/windows-1256 | 259 + data/windows-1256.txt | 274 + data/windows-1257 | 247 + data/windows-1257.txt | 274 + data/windows-1258 | 250 + data/windows-1258.txt | 274 + data/windows-1361.txt | 17396 +++++++++++ data/windows-874 | 228 + data/windows-874.txt | 274 + data/windows-932.txt | 9403 ++++++ data/windows-936.txt | 24071 ++++++++++++++++ data/windows-949.txt | 17367 +++++++++++ data/windows-950.txt | 19841 +++++++++++++ doc/Makefile | 167 + doc/cmp.html | 755 + doc/cmp.pdf | Bin 0 -> 300850 bytes doc/cmp.shtml | 737 + doc/cups.css | 207 + doc/cupsdoc.css | 9 + doc/favicon.ico | Bin 0 -> 3638 bytes doc/figures.sc | Bin 0 -> 75144 bytes doc/glossary.shtml | 73 + doc/help/access_log-reference.html | 137 + doc/help/api-array.html | 399 + doc/help/api-cups.html | 1464 + doc/help/api-filedir.html | 661 + doc/help/api-filter.html | 136 + doc/help/api-httpipp.html | 3795 +++ doc/help/api-ppd.html | 1250 + doc/help/classes-conf-reference.html | 540 + doc/help/client-conf-reference.html | 62 + doc/help/cupsd-conf-reference.html | 2034 ++ doc/help/error_log-reference.html | 52 + doc/help/network.html | 431 + doc/help/overview.html | 504 + doc/help/page_log-reference.html | 53 + doc/help/printers-conf-reference.html | 581 + doc/help/spec-ppd.html | 472 + doc/help/standard.html.in | 128 + doc/help/subscriptions-conf-reference.html | 81 + doc/help/whatsnew.html | 188 + doc/idd.html | 1083 + doc/idd.pdf | Bin 0 -> 395751 bytes doc/idd.shtml | 1445 + doc/images/accept-jobs.gif | Bin 0 -> 527 bytes doc/images/add-class.gif | Bin 0 -> 484 bytes doc/images/add-printer.gif | Bin 0 -> 487 bytes doc/images/add-this-printer.gif | Bin 0 -> 577 bytes doc/images/bottom-left.gif | Bin 0 -> 122 bytes doc/images/bottom-right.gif | Bin 0 -> 123 bytes doc/images/cancel-all-jobs.gif | Bin 0 -> 568 bytes doc/images/cancel-job.gif | Bin 0 -> 474 bytes doc/images/cancel.gif | Bin 0 -> 383 bytes doc/images/change-settings.gif | Bin 0 -> 615 bytes doc/images/classes.gif | Bin 0 -> 591 bytes doc/images/continue.gif | Bin 0 -> 423 bytes doc/images/cups-black-button-2.2.scm | 80 + doc/images/cups-block-diagram.gif | Bin 0 -> 11637 bytes doc/images/cups-green-button-2.2.scm | 80 + doc/images/cups-large.gif | Bin 0 -> 7457 bytes doc/images/cups-medium.gif | Bin 0 -> 3163 bytes doc/images/cups-red-button-2.2.scm | 80 + doc/images/cups-small.gif | Bin 0 -> 1266 bytes doc/images/cups-standard-button-2.2.scm | 80 + doc/images/delete-class.gif | Bin 0 -> 520 bytes doc/images/delete-printer.gif | Bin 0 -> 508 bytes doc/images/draft.gif | Bin 0 -> 926 bytes doc/images/edit-configuration-file.gif | Bin 0 -> 699 bytes doc/images/esp-logo.gif | Bin 0 -> 2529 bytes doc/images/happy.gif | Bin 0 -> 3522 bytes doc/images/help.gif | Bin 0 -> 327 bytes doc/images/hold-job.gif | Bin 0 -> 436 bytes doc/images/logo.gif | Bin 0 -> 1958 bytes doc/images/manage-classes.gif | Bin 0 -> 619 bytes doc/images/manage-jobs.gif | Bin 0 -> 556 bytes doc/images/manage-printers.gif | Bin 0 -> 610 bytes doc/images/manage-server.gif | Bin 0 -> 599 bytes doc/images/modify-class.gif | Bin 0 -> 559 bytes doc/images/modify-printer.gif | Bin 0 -> 559 bytes doc/images/print-test-page.gif | Bin 0 -> 564 bytes doc/images/printer-idle.gif | Bin 0 -> 706 bytes doc/images/printer-processing.gif | Bin 0 -> 805 bytes doc/images/printer-stopped.gif | Bin 0 -> 794 bytes doc/images/publish-printer.gif | Bin 0 -> 550 bytes doc/images/reject-jobs.gif | Bin 0 -> 509 bytes doc/images/release-job.gif | Bin 0 -> 536 bytes doc/images/restart-job.gif | Bin 0 -> 493 bytes doc/images/save-changes.gif | Bin 0 -> 580 bytes doc/images/search.gif | Bin 0 -> 410 bytes doc/images/set-allowed-users.gif | Bin 0 -> 673 bytes doc/images/set-as-default.gif | Bin 0 -> 585 bytes doc/images/set-printer-options.gif | Bin 0 -> 649 bytes doc/images/show-active.gif | Bin 0 -> 662 bytes doc/images/show-all.gif | Bin 0 -> 570 bytes doc/images/show-ascending.gif | Bin 0 -> 638 bytes doc/images/show-completed.gif | Bin 0 -> 764 bytes doc/images/show-descending.gif | Bin 0 -> 659 bytes doc/images/show-next.gif | Bin 0 -> 514 bytes doc/images/show-previous.gif | Bin 0 -> 582 bytes doc/images/start-class.gif | Bin 0 -> 498 bytes doc/images/start-printer.gif | Bin 0 -> 500 bytes doc/images/stop-class.gif | Bin 0 -> 500 bytes doc/images/stop-printer.gif | Bin 0 -> 501 bytes doc/images/tab-left.gif | Bin 0 -> 46 bytes doc/images/tab-right.gif | Bin 0 -> 47 bytes doc/images/top-left.gif | Bin 0 -> 473 bytes doc/images/top-middle.gif | Bin 0 -> 1144 bytes doc/images/top-right.gif | Bin 0 -> 121 bytes doc/images/unpublish-printer.gif | Bin 0 -> 594 bytes doc/images/use-default-config.gif | Bin 0 -> 864 bytes doc/images/view-access-log.gif | Bin 0 -> 638 bytes doc/images/view-error-log.gif | Bin 0 -> 554 bytes doc/images/view-page-log.gif | Bin 0 -> 590 bytes doc/index.html.in | 135 + doc/ipp.html | 1473 + doc/ipp.pdf | Bin 0 -> 111519 bytes doc/ipp.shtml | 1994 ++ doc/overview.html | 598 + doc/overview.pdf | Bin 0 -> 50052 bytes doc/ppd.shtml | 334 + doc/printing-overview.shtml | 125 + doc/references.shtml | 42 + doc/robots.txt | 31 + doc/sam.html | 5281 ++++ doc/sam.pdf | Bin 0 -> 273391 bytes doc/sam.shtml | 5062 ++++ doc/sdd.html | 591 + doc/sdd.pdf | Bin 0 -> 71633 bytes doc/sdd.shtml | 564 + doc/spm.html | 8919 ++++++ doc/spm.pdf | Bin 0 -> 689586 bytes doc/spm.shtml | 10202 +++++++ doc/sps.html | 297 + doc/sps.pdf | Bin 0 -> 41182 bytes doc/sps.shtml | 457 + doc/ssr.html | 275 + doc/ssr.pdf | Bin 0 -> 39878 bytes doc/ssr.shtml | 167 + doc/stp.html | 262 + doc/stp.pdf | Bin 0 -> 43329 bytes doc/stp.shtml | 144 + doc/sum.html | 1732 ++ doc/sum.pdf | Bin 0 -> 106950 bytes doc/sum.shtml | 933 + doc/svd.html | 296 + doc/svd.pdf | Bin 0 -> 45647 bytes doc/svd.shtml | 212 + doc/system-overview.shtml | 19 + doc/translation.html | 605 + doc/translation.pdf | Bin 0 -> 50787 bytes doc/translation.shtml | 734 + filter/Dependencies | 119 + filter/Makefile | 285 + filter/common.c | 471 + filter/common.h | 92 + filter/form-main.c | 62 + filter/form-ps.c | 49 + filter/form-tree.c | 624 + filter/form.h | 177 + filter/gziptoany.c | 131 + filter/hpgl-attr.c | 454 + filter/hpgl-char.c | 640 + filter/hpgl-config.c | 645 + filter/hpgl-input.c | 258 + filter/hpgl-main.c | 274 + filter/hpgl-polygon.c | 394 + filter/hpgl-prolog.c | 377 + filter/hpgl-vector.c | 775 + filter/hpgltops.h | 241 + filter/image-bmp.c | 546 + filter/image-colorspace.c | 1565 + filter/image-gif.c | 697 + filter/image-jpeg.c | 322 + filter/image-photocd.c | 327 + filter/image-pix.c | 244 + filter/image-png.c | 271 + filter/image-pnm.c | 312 + filter/image-private.h | 208 + filter/image-sgi.c | 293 + filter/image-sgi.h | 96 + filter/image-sgilib.c | 859 + filter/image-sun.c | 406 + filter/image-tiff.c | 1766 ++ filter/image-zoom.c | 370 + filter/image.c | 845 + filter/image.h | 151 + filter/imagetops.c | 1028 + filter/imagetoraster.c | 4591 +++ filter/interpret.c | 545 + filter/pstops.c | 1997 ++ filter/raster.c | 892 + filter/raster.h | 345 + filter/rastertoepson.c | 1152 + filter/rastertohp.c | 888 + filter/rastertolabel.c | 959 + filter/testimage.c | 101 + filter/testraster.c | 210 + filter/textcommon.c | 1195 + filter/textcommon.h | 123 + filter/texttops.c | 1311 + fonts/Courier | 1494 + fonts/Courier-Bold | 1652 ++ fonts/Courier-BoldOblique | 1686 ++ fonts/Courier-Oblique | 1448 + fonts/Makefile | 62 + fonts/Symbol | 1150 + install-sh | 251 + locale/Makefile | 99 + locale/cups.footer | 5 + locale/cups.header | 26 + locale/cups.pot | 2142 ++ locale/cups_fr.po | 2148 ++ locale/locale.txt | 32 + locale/translate.c | 448 + man/Makefile | 131 + man/accept.man | 60 + man/backend.man | 348 + man/classes.conf.man | 72 + man/cups-config.man | 95 + man/cups-lpd.man | 114 + man/cups-polld.man | 46 + man/cupsaddsmb.man | 189 + man/cupsd.conf.man | 443 + man/cupsd.man | 61 + man/cupsenable.man | 67 + man/cupstestppd.man | 105 + man/filter.man | 123 + man/lp.man | 181 + man/lpadmin.man | 163 + man/lpc.man | 80 + man/lpinfo.man | 60 + man/lpmove.man | 53 + man/lpoptions.man | 128 + man/lppasswd.man | 61 + man/lpq.man | 57 + man/lpr.man | 107 + man/lprm.man | 54 + man/lpstat.man | 140 + man/mantohtml.c | 642 + man/mime.convs.man | 54 + man/mime.types.man | 102 + man/printers.conf.man | 73 + notifier/Dependencies | 8 + notifier/Makefile | 91 + notifier/mailto.c | 50 + notifier/testnotify.c | 285 + packaging/LICENSE.rtf | 462 + packaging/WELCOME.rtf | 24 + packaging/cups-desc.plist.in | 15 + packaging/cups-info.plist.in | 24 + packaging/cups.list.in | 453 + packaging/cups.spec.in | 267 + packaging/installer.tif | Bin 0 -> 6580 bytes packaging/installer.xcf.gz | Bin 0 -> 7461 bytes pdftops/Annot.cxx | 317 + pdftops/Annot.h | 73 + pdftops/Array.cxx | 73 + pdftops/Array.h | 58 + pdftops/BuiltinFont.cxx | 65 + pdftops/BuiltinFont.h | 57 + pdftops/BuiltinFontTables.cxx | 4284 +++ pdftops/BuiltinFontTables.h | 23 + pdftops/CMap.cxx | 408 + pdftops/CMap.h | 102 + pdftops/COPYING | 339 + pdftops/Catalog.cxx | 353 + pdftops/Catalog.h | 92 + pdftops/CharCodeToUnicode.cxx | 540 + pdftops/CharCodeToUnicode.h | 117 + pdftops/CharTypes.h | 24 + pdftops/CompactFontTables.h | 464 + pdftops/Decrypt.cxx | 411 + pdftops/Decrypt.h | 63 + pdftops/Dependencies | 149 + pdftops/Dict.cxx | 95 + pdftops/Dict.h | 77 + pdftops/Error.cxx | 38 + pdftops/Error.h | 23 + pdftops/ErrorCodes.h | 36 + pdftops/FoFiBase.cxx | 156 + pdftops/FoFiBase.h | 57 + pdftops/FoFiEncodings.cxx | 994 + pdftops/FoFiEncodings.h | 36 + pdftops/FoFiTrueType.cxx | 1753 ++ pdftops/FoFiTrueType.h | 140 + pdftops/FoFiType1.cxx | 207 + pdftops/FoFiType1.h | 59 + pdftops/FoFiType1C.cxx | 2481 ++ pdftops/FoFiType1C.h | 232 + pdftops/FontEncodingTables.cxx | 1824 ++ pdftops/FontEncodingTables.h | 20 + pdftops/Function.cxx | 1536 + pdftops/Function.h | 225 + pdftops/GHash.cxx | 380 + pdftops/GHash.h | 78 + pdftops/GList.cxx | 97 + pdftops/GList.h | 96 + pdftops/GMutex.h | 49 + pdftops/GString.cxx | 319 + pdftops/GString.h | 97 + pdftops/Gfx.cxx | 3623 +++ pdftops/Gfx.h | 294 + pdftops/GfxFont.cxx | 1546 + pdftops/GfxFont.h | 315 + pdftops/GfxState.cxx | 3946 +++ pdftops/GfxState.h | 1206 + pdftops/GlobalParams.cxx | 1995 ++ pdftops/GlobalParams.h | 336 + pdftops/JArithmeticDecoder.cxx | 322 + pdftops/JArithmeticDecoder.h | 109 + pdftops/JBIG2Stream.cxx | 3386 +++ pdftops/JBIG2Stream.h | 143 + pdftops/JPXStream.cxx | 2953 ++ pdftops/JPXStream.h | 349 + pdftops/Lexer.cxx | 485 + pdftops/Lexer.h | 80 + pdftops/Link.cxx | 907 + pdftops/Link.h | 409 + pdftops/Makefile | 158 + pdftops/NameToCharCode.cxx | 116 + pdftops/NameToCharCode.h | 42 + pdftops/NameToUnicodeTable.h | 1097 + pdftops/Object.cxx | 231 + pdftops/Object.h | 303 + pdftops/Outline.cxx | 151 + pdftops/Outline.h | 76 + pdftops/OutputDev.cxx | 129 + pdftops/OutputDev.h | 205 + pdftops/PDFDoc.cxx | 431 + pdftops/PDFDoc.h | 182 + pdftops/PDFDocEncoding.cxx | 44 + pdftops/PDFDocEncoding.h | 16 + pdftops/PSOutputDev.cxx | 4976 ++++ pdftops/PSOutputDev.h | 354 + pdftops/PSTokenizer.cxx | 135 + pdftops/PSTokenizer.h | 41 + pdftops/Page.cxx | 367 + pdftops/Page.h | 175 + pdftops/Parser.cxx | 214 + pdftops/Parser.h | 56 + pdftops/README | 446 + pdftops/SecurityHandler.cxx | 378 + pdftops/SecurityHandler.h | 155 + pdftops/Splash.cxx | 3191 ++ pdftops/Splash.h | 204 + pdftops/SplashBitmap.cxx | 243 + pdftops/SplashBitmap.h | 55 + pdftops/SplashClip.cxx | 270 + pdftops/SplashClip.h | 97 + pdftops/SplashErrorCodes.h | 32 + pdftops/SplashFTFont.cxx | 320 + pdftops/SplashFTFont.h | 55 + pdftops/SplashFTFontEngine.cxx | 144 + pdftops/SplashFTFontEngine.h | 61 + pdftops/SplashFTFontFile.cxx | 111 + pdftops/SplashFTFontFile.h | 70 + pdftops/SplashFont.cxx | 172 + pdftops/SplashFont.h | 97 + pdftops/SplashFontEngine.cxx | 253 + pdftops/SplashFontEngine.h | 86 + pdftops/SplashFontFile.cxx | 55 + pdftops/SplashFontFile.h | 60 + pdftops/SplashFontFileID.cxx | 23 + pdftops/SplashFontFileID.h | 30 + pdftops/SplashGlyphBitmap.h | 26 + pdftops/SplashMath.h | 78 + pdftops/SplashOutputDev.cxx | 2640 ++ pdftops/SplashOutputDev.h | 222 + pdftops/SplashPath.cxx | 178 + pdftops/SplashPath.h | 112 + pdftops/SplashPattern.cxx | 68 + pdftops/SplashPattern.h | 90 + pdftops/SplashScreen.cxx | 141 + pdftops/SplashScreen.h | 50 + pdftops/SplashState.cxx | 110 + pdftops/SplashState.h | 91 + pdftops/SplashT1Font.cxx | 264 + pdftops/SplashT1Font.h | 53 + pdftops/SplashT1FontEngine.cxx | 124 + pdftops/SplashT1FontEngine.h | 53 + pdftops/SplashT1FontFile.cxx | 96 + pdftops/SplashT1FontFile.h | 57 + pdftops/SplashTypes.h | 139 + pdftops/SplashXPath.cxx | 414 + pdftops/SplashXPath.h | 92 + pdftops/SplashXPathScanner.cxx | 277 + pdftops/SplashXPathScanner.h | 74 + pdftops/Stream-CCITT.h | 459 + pdftops/Stream.cxx | 4572 +++ pdftops/Stream.h | 846 + pdftops/UTF8.h | 56 + pdftops/UnicodeMap.cxx | 293 + pdftops/UnicodeMap.h | 123 + pdftops/UnicodeMapTables.h | 361 + pdftops/UnicodeTypeTable.cxx | 949 + pdftops/UnicodeTypeTable.h | 20 + pdftops/XRef.cxx | 888 + pdftops/XRef.h | 131 + pdftops/XpdfPluginAPI.cxx | 262 + pdftops/XpdfPluginAPI.h | 323 + pdftops/config.h | 112 + pdftops/gfile.cxx | 707 + pdftops/gfile.h | 126 + pdftops/gmem.c | 229 + pdftops/gmem.h | 62 + pdftops/gmempp.cxx | 32 + pdftops/gtypes.h | 29 + pdftops/parseargs.c | 190 + pdftops/parseargs.h | 71 + pdftops/pdftops.cxx | 345 + ppd/Makefile | 64 + ppd/deskjet.ppd | 199 + ppd/deskjet2.ppd | 218 + ppd/dymo.ppd | 156 + ppd/epson24.ppd | 139 + ppd/epson9.ppd | 137 + ppd/laserjet.ppd | 201 + ppd/okidat24.ppd | 129 + ppd/okidata9.ppd | 127 + ppd/stcolor.ppd | 133 + ppd/stcolor2.ppd | 133 + ppd/stphoto.ppd | 133 + ppd/stphoto2.ppd | 133 + ppd/zebra.ppd | 332 + ppd/zebracpl.ppd | 276 + ppd/zebraep1.ppd | 179 + ppd/zebraep2.ppd | 191 + pstoraster/README.pstoraster | 73 + pstoraster/cups.mak | 53 + pstoraster/gdevcups.c | 4464 +++ pstoraster/gs707-lib.patch | 110 + pstoraster/gs811-lib.patch | 110 + pstoraster/pstopxl | 67 + pstoraster/pstopxl.in | 67 + pstoraster/pstoraster | 52 + pstoraster/pstoraster.convs | 29 + pstoraster/pstoraster.in | 62 + pstoraster/pxlcolor.ppd | 205 + pstoraster/pxlmono.ppd | 199 + scheduler/Dependencies | 176 + scheduler/Makefile | 243 + scheduler/auth.c | 2116 ++ scheduler/auth.h | 163 + scheduler/banners.c | 210 + scheduler/banners.h | 57 + scheduler/cert.c | 296 + scheduler/cert.h | 60 + scheduler/classes.c | 844 + scheduler/classes.h | 46 + scheduler/client.c | 3484 +++ scheduler/client.h | 134 + scheduler/conf.c | 3048 ++ scheduler/conf.h | 211 + scheduler/cups-deviced.c | 441 + scheduler/cups-driverd.c | 1080 + scheduler/cups-lpd.c | 1441 + scheduler/cups-polld.c | 405 + scheduler/cups.pam | 2 + scheduler/cupsd.h | 201 + scheduler/dirsvc.c | 2635 ++ scheduler/dirsvc.h | 162 + scheduler/env.c | 224 + scheduler/filter.c | 326 + scheduler/ipp.c | 8986 ++++++ scheduler/job.c | 2718 ++ scheduler/job.h | 120 + scheduler/listen.c | 398 + scheduler/log.c | 553 + scheduler/main.c | 1508 + scheduler/mime.c | 573 + scheduler/mime.h | 147 + scheduler/network.c | 576 + scheduler/network.h | 64 + scheduler/policy.c | 337 + scheduler/policy.h | 66 + scheduler/printers.c | 2874 ++ scheduler/printers.h | 146 + scheduler/process.c | 224 + scheduler/quotas.c | 240 + scheduler/server.c | 206 + scheduler/statbuf.c | 330 + scheduler/statbuf.h | 59 + scheduler/subscriptions.c | 1530 + scheduler/subscriptions.h | 175 + scheduler/testdirsvc.c | 275 + scheduler/testmime.c | 246 + scheduler/testspeed.c | 305 + scheduler/type.c | 1165 + scheduler/util.c | 279 + scheduler/util.h | 59 + scripting/java/CUPSPrinter.java | 438 + .../java/classes/com/easysw/cups/Cups.class | Bin 0 -> 12601 bytes .../classes/com/easysw/cups/CupsJob.class | Bin 0 -> 2830 bytes .../classes/com/easysw/cups/CupsPrinter.class | Bin 0 -> 11088 bytes .../java/classes/com/easysw/cups/IPP.class | Bin 0 -> 2100 bytes .../com/easysw/cups/IPPAttribute.class | Bin 0 -> 6695 bytes .../com/easysw/cups/IPPBase64Encoder.class | Bin 0 -> 362 bytes .../classes/com/easysw/cups/IPPCalendar.class | Bin 0 -> 382 bytes .../classes/com/easysw/cups/IPPDefs.class | Bin 0 -> 7640 bytes .../classes/com/easysw/cups/IPPError.class | Bin 0 -> 2663 bytes .../classes/com/easysw/cups/IPPHttp.class | Bin 0 -> 16865 bytes .../java/classes/com/easysw/cups/IPPMD5.class | Bin 0 -> 1912 bytes .../classes/com/easysw/cups/IPPRequest.class | Bin 0 -> 627 bytes .../classes/com/easysw/cups/IPPStatus.class | Bin 0 -> 2402 bytes .../com/easysw/cups/IPPURLConnection.class | Bin 0 -> 413 bytes .../classes/com/easysw/cups/IPPValue.class | Bin 0 -> 1979 bytes scripting/java/cups.jar | Bin 0 -> 37208 bytes scripting/java/docs/allclasses-frame.html | 49 + scripting/java/docs/com/easysw/cups/Cups.html | 600 + .../java/docs/com/easysw/cups/CupsJob.html | 547 + .../docs/com/easysw/cups/CupsPrinter.html | 533 + scripting/java/docs/com/easysw/cups/IPP.html | 417 + .../docs/com/easysw/cups/IPPAttribute.html | 466 + .../java/docs/com/easysw/cups/IPPDefs.html | 3330 +++ .../java/docs/com/easysw/cups/IPPError.html | 178 + .../java/docs/com/easysw/cups/IPPHttp.html | 2596 ++ .../java/docs/com/easysw/cups/IPPRequest.html | 251 + .../java/docs/com/easysw/cups/IPPStatus.html | 185 + .../com/easysw/cups/IPPURLConnection.html | 262 + .../java/docs/com/easysw/cups/IPPValue.html | 376 + scripting/java/docs/deprecated-list.html | 89 + scripting/java/docs/help-doc.html | 138 + scripting/java/docs/index-all.html | 1588 + scripting/java/docs/index.html | 22 + scripting/java/docs/overview-tree.html | 101 + scripting/java/docs/package-list | 1 + scripting/java/docs/packages.html | 26 + scripting/java/docs/serialized-form.html | 89 + scripting/java/docs/stylesheet.css | 29 + scripting/java/example/GLP.class | Bin 0 -> 1163 bytes scripting/java/example/GLP.java | 59 + scripting/java/example/GLPcolors.class | Bin 0 -> 838 bytes scripting/java/example/GLPcolors.java | 22 + scripting/java/example/GLPdetail.class | Bin 0 -> 5600 bytes scripting/java/example/GLPdetail.java | 279 + scripting/java/example/GLPjobList.class | Bin 0 -> 3587 bytes scripting/java/example/GLPjobList.java | 150 + scripting/java/example/GLPjobTableModel.class | Bin 0 -> 1849 bytes scripting/java/example/GLPjobTableModel.java | 104 + scripting/java/example/GLPoptions$1.class | Bin 0 -> 1025 bytes .../example/GLPoptions$MyTextListener.class | Bin 0 -> 1217 bytes scripting/java/example/GLPoptions.class | Bin 0 -> 11082 bytes scripting/java/example/GLPoptions.java | 662 + scripting/java/example/GLPprinterDetail.class | Bin 0 -> 4832 bytes scripting/java/example/GLPprinterDetail.java | 244 + scripting/java/example/GLPprinters.class | Bin 0 -> 8749 bytes scripting/java/example/GLPprinters.java | 509 + scripting/java/example/GLPsearch.class | Bin 0 -> 2428 bytes scripting/java/example/GLPsearch.java | 121 + .../example/GLPsearchProgressPanel$1.class | Bin 0 -> 2470 bytes .../example/GLPsearchProgressPanel$2.class | Bin 0 -> 1188 bytes ...LPsearchProgressPanel$ButtonListener.class | Bin 0 -> 1686 bytes .../java/example/GLPsearchProgressPanel.class | Bin 0 -> 2709 bytes .../java/example/GLPsearchProgressPanel.java | 195 + scripting/java/example/GLPserver.class | Bin 0 -> 4304 bytes scripting/java/example/GLPserver.java | 192 + scripting/java/example/GLPtabs$1.class | Bin 0 -> 1097 bytes scripting/java/example/GLPtabs.class | Bin 0 -> 2611 bytes scripting/java/example/GLPtabs.java | 117 + scripting/java/example/GLPvars.class | Bin 0 -> 1592 bytes scripting/java/example/GLPvars.java | 93 + scripting/java/example/buildit | 4 + scripting/java/example/class.list | 13 + scripting/java/example/images/left.gif | Bin 0 -> 110 bytes .../java/example/images/print-test-page.gif | Bin 0 -> 519 bytes .../java/example/images/printer-idle.gif | Bin 0 -> 706 bytes .../java/example/images/printer-stopped.gif | Bin 0 -> 794 bytes scripting/java/example/images/restart-job.gif | Bin 0 -> 440 bytes scripting/java/example/images/show-active.gif | Bin 0 -> 581 bytes .../java/example/images/show-completed.gif | Bin 0 -> 657 bytes scripting/java/example/runit | 2 + scripting/java/src/com/easysw/cups/Cups.java | 1413 + .../java/src/com/easysw/cups/CupsJob.java | 216 + .../java/src/com/easysw/cups/CupsPrinter.java | 837 + scripting/java/src/com/easysw/cups/IPP.java | 251 + .../src/com/easysw/cups/IPPAttribute.java | 593 + .../src/com/easysw/cups/IPPBase64Encoder.java | 46 + .../java/src/com/easysw/cups/IPPCalendar.java | 62 + .../java/src/com/easysw/cups/IPPDefs.java | 310 + .../java/src/com/easysw/cups/IPPError.java | 159 + .../java/src/com/easysw/cups/IPPHttp.java | 1353 + .../java/src/com/easysw/cups/IPPMD5.java | 134 + .../java/src/com/easysw/cups/IPPRequest.java | 97 + .../java/src/com/easysw/cups/IPPStatus.java | 195 + .../src/com/easysw/cups/IPPURLConnection.java | 78 + .../java/src/com/easysw/cups/IPPValue.java | 264 + scripting/java/src/com/easysw/cups/buildit | 9 + scripting/java/src/com/easysw/cups/class.list | 14 + scripting/java/src/com/easysw/cups/cups.nfo | 34 + scripting/perl/CUPS.pm | 144 + scripting/perl/CUPS.xs | 270 + scripting/perl/Makefile.PL | 17 + scripting/perl/README | 35 + scripting/perl/test.pl | 17 + scripting/php/Dependencies | 6 + scripting/php/Example/phpcups.inc.php4 | 310 + scripting/php/Makefile | 107 + scripting/php/README | 21 + scripting/php/config.m4 | 60 + scripting/php/php_phpcups.h | 87 + scripting/php/phpcups.c | 1357 + scripting/php/phpcups.php | 53 + standards/pwg5100.1.pdf | Bin 0 -> 37359 bytes standards/pwg5100.2.pdf | Bin 0 -> 37360 bytes standards/pwg5100.3.pdf | Bin 0 -> 262279 bytes standards/pwg5100.4.pdf | Bin 0 -> 150078 bytes standards/rfc1179.txt | 787 + standards/rfc1321.txt | 1179 + standards/rfc2222.txt | 899 + standards/rfc2246.txt | 4483 +++ standards/rfc2487.txt | 451 + standards/rfc2554.txt | 619 + standards/rfc2565.txt | 2075 ++ standards/rfc2566.txt | 9691 +++++++ standards/rfc2567.txt | 2411 ++ standards/rfc2568.txt | 563 + standards/rfc2569.txt | 1571 + standards/rfc2595.txt | 843 + standards/rfc2616.txt | 9859 +++++++ standards/rfc2617.txt | 1907 ++ standards/rfc2639.txt | 3587 +++ standards/rfc2712.txt | 395 + standards/rfc2817.txt | 731 + standards/rfc2818.txt | 395 + standards/rfc2821.txt | 4427 +++ standards/rfc2822.txt | 2859 ++ standards/rfc2910.txt | 2579 ++ standards/rfc2911.txt | 12547 ++++++++ standards/rfc2965.txt | 1459 + standards/rfc3239.txt | 843 + standards/rfc3380.txt | 3307 +++ standards/rfc3381.txt | 955 + standards/rfc3382.txt | 2131 ++ standards/rfc3510.txt | 899 + standards/rfc3986.txt | 3419 +++ standards/rfc3995.txt | 5323 ++++ standards/rfc3996.txt | 1739 ++ standards/rfc3997.txt | 955 + standards/rfc3998.txt | 2579 ++ standards/wd-ippmailto10-20050519.pdf | Bin 0 -> 75741 bytes systemv/Dependencies | 35 + systemv/Makefile | 195 + systemv/accept.c | 294 + systemv/cancel.c | 390 + systemv/cupsaddsmb.c | 1032 + systemv/cupstestppd.c | 1386 + systemv/lp.c | 813 + systemv/lpadmin.c | 2173 ++ systemv/lpinfo.c | 466 + systemv/lpmove.c | 241 + systemv/lpoptions.c | 456 + systemv/lppasswd.c | 517 + systemv/lpstat.c | 2208 ++ templates/Makefile | 110 + templates/add-class.tmpl | 33 + templates/add-printer.tmpl | 28 + templates/admin-op.tmpl | 1 + templates/admin.tmpl | 71 + templates/choose-device.tmpl | 26 + templates/choose-make.tmpl | 42 + templates/choose-model.tmpl | 34 + templates/choose-serial.tmpl | 47 + templates/choose-uri.tmpl | 40 + templates/class-added.tmpl | 2 + templates/class-confirm.tmpl | 7 + templates/class-deleted.tmpl | 1 + templates/class-modified.tmpl | 2 + templates/classes.tmpl | 60 + templates/edit-config.tmpl.in | 90 + templates/error.tmpl | 3 + templates/header.tmpl | 62 + templates/help-header.tmpl | 28 + templates/job-cancel.tmpl | 1 + templates/job-hold.tmpl | 1 + templates/job-op.tmpl | 1 + templates/job-release.tmpl | 1 + templates/job-restart.tmpl | 1 + templates/jobs-header.tmpl | 17 + templates/jobs.tmpl | 44 + templates/modify-class.tmpl | 34 + templates/modify-printer.tmpl | 29 + templates/option-boolean.tmpl | 6 + templates/option-conflict.tmpl | 7 + templates/option-header.tmpl | 3 + templates/option-pickmany.tmpl | 6 + templates/option-pickone.tmpl | 6 + templates/option-trailer.tmpl | 5 + templates/page.tmpl | 7 + templates/printer-accept.tmpl | 1 + templates/printer-added.tmpl | 2 + templates/printer-configured.tmpl | 2 + templates/printer-confirm.tmpl | 7 + templates/printer-default.tmpl | 4 + templates/printer-deleted.tmpl | 1 + templates/printer-modified.tmpl | 2 + templates/printer-purge.tmpl | 1 + templates/printer-reject.tmpl | 1 + templates/printer-start.tmpl | 2 + templates/printer-stop.tmpl | 2 + templates/printers.tmpl | 68 + templates/restart.tmpl | 1 + templates/search.tmpl | 10 + templates/set-printer-options-header.tmpl | 3 + templates/set-printer-options-trailer.tmpl | 1 + templates/test-page.tmpl | 2 + templates/trailer.tmpl | 21 + templates/users.tmpl | 25 + test/4.1-requests.test | 140 + test/4.2-cups-printer-ops.test | 241 + test/4.3-job-ops.test | 301 + test/4.4-subscription-ops.test | 122 + test/5.1-lpadmin.sh | 64 + test/5.2-lpc.sh | 40 + test/5.3-lpq.sh | 40 + test/5.4-lpstat.sh | 40 + test/5.5-lp.sh | 71 + test/5.6-lpr.sh | 71 + test/5.7-lprm.sh | 52 + test/5.8-cancel.sh | 52 + test/5.9-lpinfo.sh | 52 + test/Dependencies | 4 + test/Makefile | 77 + test/create-job-format.test | 56 + test/create-job-sheets.test | 55 + test/create-job-timeout.test | 55 + test/create-job.test | 54 + test/get-devices.test | 21 + test/get-job-attributes.test | 27 + test/get-job-attributes2.test | 28 + test/get-ppds.test | 21 + test/get-printer-attributes.test | 43 + test/ipptest.c | 786 + test/print-job-hold.test | 33 + test/print-job.test | 32 + test/run-stp-tests.sh | 553 + test/set-attrs-hold.test | 180 + test/str-header.html | 35 + test/str-trailer.html | 5 + test/testfile.jpg | Bin 0 -> 598930 bytes test/testfile.pdf | Bin 0 -> 36613 bytes test/testfile.ps | 594 + test/testfile.txt | 60 + test/testhp.ppd | 195 + test/testps.ppd | 192 + tools/makesrcdist | 71 + tools/testosx | 87 + tools/testrpm | 28 + vcnet/config.h | 352 + vcnet/cups.sln | 21 + vcnet/libcups2.def | 247 + vcnet/libcups2.vcproj | 286 + 983 files changed, 606921 insertions(+) create mode 100644 CGI.txt create mode 100644 CHANGES-1.0.txt create mode 100644 CHANGES-1.1.txt create mode 100644 CHANGES.txt create mode 100644 CREDITS.txt create mode 100644 ENCRYPTION.txt create mode 100644 INSTALL.txt create mode 100644 LICENSE.html create mode 100644 LICENSE.txt create mode 100644 Makedefs.in create mode 100644 Makefile create mode 100644 README.txt create mode 100644 backend/Dependencies create mode 100644 backend/Makefile create mode 100644 backend/betest.c create mode 100644 backend/easysw-firewire-design.txt create mode 100644 backend/easysw-firewire-linux.txt create mode 100644 backend/ieee1284.c create mode 100644 backend/ieee1394-linux.c create mode 100644 backend/ieee1394.c create mode 100644 backend/ieee1394.h create mode 100644 backend/ipp.c create mode 100644 backend/lpd.c create mode 100644 backend/parallel.c create mode 100644 backend/scsi-irix.c create mode 100644 backend/scsi-linux.c create mode 100644 backend/scsi.c create mode 100644 backend/serial.c create mode 100644 backend/socket.c create mode 100644 backend/test1284.c create mode 100644 backend/usb-darwin.c create mode 100644 backend/usb-unix.c create mode 100644 backend/usb.c create mode 100644 berkeley/Dependencies create mode 100644 berkeley/Makefile create mode 100644 berkeley/lpc.c create mode 100644 berkeley/lpq.c create mode 100644 berkeley/lpr.c create mode 100644 berkeley/lprm.c create mode 100644 cgi-bin/Dependencies create mode 100644 cgi-bin/Makefile create mode 100644 cgi-bin/admin.c create mode 100644 cgi-bin/cgi-private.h create mode 100644 cgi-bin/cgi.h create mode 100644 cgi-bin/classes.c create mode 100644 cgi-bin/help-index.c create mode 100644 cgi-bin/help-index.h create mode 100644 cgi-bin/help.c create mode 100644 cgi-bin/html.c create mode 100644 cgi-bin/ipp-var.c create mode 100644 cgi-bin/jobs.c create mode 100644 cgi-bin/multipart.dat create mode 100644 cgi-bin/printers.c create mode 100644 cgi-bin/search.c create mode 100644 cgi-bin/template.c create mode 100644 cgi-bin/testcgi.c create mode 100644 cgi-bin/testhi.c create mode 100644 cgi-bin/testhi.html create mode 100644 cgi-bin/var.c create mode 100644 conf/Makefile create mode 100644 conf/classes.conf create mode 100644 conf/client.conf create mode 100644 conf/cupsd.conf.in create mode 100644 conf/mime.convs create mode 100644 conf/mime.types create mode 100644 conf/pam.darwin create mode 100644 conf/pam.irix create mode 100644 conf/pam.std.in create mode 100644 conf/printcap create mode 100644 conf/printers.conf create mode 100644 config-scripts/cups-common.m4 create mode 100644 config-scripts/cups-compiler.m4 create mode 100644 config-scripts/cups-directories.m4 create mode 100644 config-scripts/cups-image.m4 create mode 100644 config-scripts/cups-largefile.m4 create mode 100644 config-scripts/cups-libtool.m4 create mode 100644 config-scripts/cups-manpages.m4 create mode 100644 config-scripts/cups-network.m4 create mode 100644 config-scripts/cups-opsys.m4 create mode 100644 config-scripts/cups-pam.m4 create mode 100644 config-scripts/cups-scripting.m4 create mode 100644 config-scripts/cups-sharedlibs.m4 create mode 100644 config-scripts/cups-slp.m4 create mode 100644 config-scripts/cups-ssl.m4 create mode 100644 config-scripts/cups-threads.m4 create mode 100644 config.h.in create mode 100644 configure.in create mode 100755 cups-config.in create mode 100644 cups.osx create mode 100644 cups.plist create mode 100755 cups.sh.in create mode 100644 cups.strings create mode 100644 cups/Dependencies create mode 100644 cups/Makefile create mode 100644 cups/api-array.shtml create mode 100644 cups/api-cups.shtml create mode 100644 cups/api-filedir.shtml create mode 100644 cups/api-filter.shtml create mode 100644 cups/api-httpipp.shtml create mode 100644 cups/api-ppd.shtml create mode 100644 cups/array.c create mode 100644 cups/array.h create mode 100644 cups/attr.c create mode 100644 cups/auth.c create mode 100644 cups/backchannel.c create mode 100644 cups/backend.h create mode 100644 cups/cups.h create mode 100644 cups/debug.h create mode 100644 cups/dest.c create mode 100644 cups/dir.c create mode 100644 cups/dir.h create mode 100644 cups/emit.c create mode 100644 cups/encode.c create mode 100644 cups/extended.c create mode 100644 cups/file.c create mode 100644 cups/file.h create mode 100644 cups/getputfile.c create mode 100644 cups/globals.c create mode 100644 cups/globals.h create mode 100644 cups/http-addr.c create mode 100644 cups/http-addrlist.c create mode 100644 cups/http-private.h create mode 100644 cups/http-support.c create mode 100644 cups/http.c create mode 100644 cups/http.h create mode 100644 cups/i18n.h create mode 100644 cups/ipp-support.c create mode 100644 cups/ipp.c create mode 100644 cups/ipp.h create mode 100644 cups/langprintf.c create mode 100644 cups/language.c create mode 100644 cups/language.h create mode 100644 cups/libcups_s.exp create mode 100644 cups/mark.c create mode 100644 cups/md5-apple.h create mode 100644 cups/md5.c create mode 100644 cups/md5.h create mode 100644 cups/md5passwd.c create mode 100644 cups/normalize.c create mode 100644 cups/normalize.h create mode 100644 cups/options.c create mode 100644 cups/page.c create mode 100644 cups/ppd.c create mode 100644 cups/ppd.h create mode 100644 cups/sample.ppd create mode 100644 cups/snprintf.c create mode 100644 cups/string.c create mode 100644 cups/string.h create mode 100644 cups/tempfile.c create mode 100644 cups/testarray.c create mode 100644 cups/testfile.c create mode 100644 cups/testhttp.c create mode 100644 cups/testi18n.c create mode 100644 cups/testipp.c create mode 100644 cups/testlang.c create mode 100644 cups/transcode.c create mode 100644 cups/transcode.h create mode 100644 cups/usersys.c create mode 100644 cups/utf8demo.txt create mode 100644 cups/util.c create mode 100644 data/HPGLprolog create mode 100644 data/Makefile create mode 100644 data/classified create mode 100644 data/confidential create mode 100644 data/cups.irix create mode 100644 data/cups.pam create mode 100644 data/cups.suse create mode 100644 data/euc-cn.txt create mode 100644 data/euc-jp.txt create mode 100644 data/euc-kr.txt create mode 100644 data/euc-tw.txt create mode 100644 data/i18n_sdd.txt create mode 100644 data/iso-8859-1 create mode 100644 data/iso-8859-1.txt create mode 100644 data/iso-8859-10 create mode 100644 data/iso-8859-10.txt create mode 100644 data/iso-8859-11.txt create mode 100644 data/iso-8859-13 create mode 100644 data/iso-8859-13.txt create mode 100644 data/iso-8859-14 create mode 100644 data/iso-8859-14.txt create mode 100644 data/iso-8859-15 create mode 100644 data/iso-8859-15.txt create mode 100644 data/iso-8859-16.txt create mode 100644 data/iso-8859-2 create mode 100644 data/iso-8859-2.txt create mode 100644 data/iso-8859-3 create mode 100644 data/iso-8859-3.txt create mode 100644 data/iso-8859-4 create mode 100644 data/iso-8859-4.txt create mode 100644 data/iso-8859-5 create mode 100644 data/iso-8859-5.txt create mode 100644 data/iso-8859-6 create mode 100644 data/iso-8859-6.txt create mode 100644 data/iso-8859-7 create mode 100644 data/iso-8859-7.txt create mode 100644 data/iso-8859-8 create mode 100644 data/iso-8859-8.txt create mode 100644 data/iso-8859-9 create mode 100644 data/iso-8859-9.txt create mode 100644 data/koi8-r create mode 100644 data/koi8-r.txt create mode 100644 data/koi8-u create mode 100644 data/koi8-u.txt create mode 100644 data/psglyphs create mode 100644 data/secret create mode 100644 data/standard create mode 100644 data/testprint.ps create mode 100644 data/topsecret create mode 100644 data/unclassified create mode 100644 data/uni-comb.txt create mode 100644 data/uni-fold.txt create mode 100644 data/uni-full.txt create mode 100644 data/uni-line.txt create mode 100644 data/uni-nfc.txt create mode 100644 data/uni-nfd.txt create mode 100644 data/uni-nfkd.txt create mode 100644 data/uni-prop.txt create mode 100644 data/unibreak.txt create mode 100644 data/utf-8 create mode 100644 data/windows-1250 create mode 100644 data/windows-1250.txt create mode 100644 data/windows-1251 create mode 100644 data/windows-1251.txt create mode 100644 data/windows-1252 create mode 100644 data/windows-1252.txt create mode 100644 data/windows-1253 create mode 100644 data/windows-1253.txt create mode 100644 data/windows-1254 create mode 100644 data/windows-1254.txt create mode 100644 data/windows-1255 create mode 100644 data/windows-1255.txt create mode 100644 data/windows-1256 create mode 100644 data/windows-1256.txt create mode 100644 data/windows-1257 create mode 100644 data/windows-1257.txt create mode 100644 data/windows-1258 create mode 100644 data/windows-1258.txt create mode 100644 data/windows-1361.txt create mode 100644 data/windows-874 create mode 100644 data/windows-874.txt create mode 100644 data/windows-932.txt create mode 100644 data/windows-936.txt create mode 100644 data/windows-949.txt create mode 100644 data/windows-950.txt create mode 100644 doc/Makefile create mode 100644 doc/cmp.html create mode 100644 doc/cmp.pdf create mode 100644 doc/cmp.shtml create mode 100644 doc/cups.css create mode 100644 doc/cupsdoc.css create mode 100644 doc/favicon.ico create mode 100644 doc/figures.sc create mode 100644 doc/glossary.shtml create mode 100644 doc/help/access_log-reference.html create mode 100644 doc/help/api-array.html create mode 100644 doc/help/api-cups.html create mode 100644 doc/help/api-filedir.html create mode 100644 doc/help/api-filter.html create mode 100644 doc/help/api-httpipp.html create mode 100644 doc/help/api-ppd.html create mode 100644 doc/help/classes-conf-reference.html create mode 100644 doc/help/client-conf-reference.html create mode 100644 doc/help/cupsd-conf-reference.html create mode 100644 doc/help/error_log-reference.html create mode 100644 doc/help/network.html create mode 100644 doc/help/overview.html create mode 100644 doc/help/page_log-reference.html create mode 100644 doc/help/printers-conf-reference.html create mode 100644 doc/help/spec-ppd.html create mode 100644 doc/help/standard.html.in create mode 100644 doc/help/subscriptions-conf-reference.html create mode 100644 doc/help/whatsnew.html create mode 100644 doc/idd.html create mode 100644 doc/idd.pdf create mode 100644 doc/idd.shtml create mode 100644 doc/images/accept-jobs.gif create mode 100644 doc/images/add-class.gif create mode 100644 doc/images/add-printer.gif create mode 100644 doc/images/add-this-printer.gif create mode 100644 doc/images/bottom-left.gif create mode 100644 doc/images/bottom-right.gif create mode 100644 doc/images/cancel-all-jobs.gif create mode 100644 doc/images/cancel-job.gif create mode 100644 doc/images/cancel.gif create mode 100644 doc/images/change-settings.gif create mode 100644 doc/images/classes.gif create mode 100644 doc/images/continue.gif create mode 100644 doc/images/cups-black-button-2.2.scm create mode 100644 doc/images/cups-block-diagram.gif create mode 100644 doc/images/cups-green-button-2.2.scm create mode 100644 doc/images/cups-large.gif create mode 100644 doc/images/cups-medium.gif create mode 100644 doc/images/cups-red-button-2.2.scm create mode 100644 doc/images/cups-small.gif create mode 100644 doc/images/cups-standard-button-2.2.scm create mode 100644 doc/images/delete-class.gif create mode 100644 doc/images/delete-printer.gif create mode 100644 doc/images/draft.gif create mode 100644 doc/images/edit-configuration-file.gif create mode 100644 doc/images/esp-logo.gif create mode 100644 doc/images/happy.gif create mode 100644 doc/images/help.gif create mode 100644 doc/images/hold-job.gif create mode 100644 doc/images/logo.gif create mode 100644 doc/images/manage-classes.gif create mode 100644 doc/images/manage-jobs.gif create mode 100644 doc/images/manage-printers.gif create mode 100644 doc/images/manage-server.gif create mode 100644 doc/images/modify-class.gif create mode 100644 doc/images/modify-printer.gif create mode 100644 doc/images/print-test-page.gif create mode 100644 doc/images/printer-idle.gif create mode 100644 doc/images/printer-processing.gif create mode 100644 doc/images/printer-stopped.gif create mode 100644 doc/images/publish-printer.gif create mode 100644 doc/images/reject-jobs.gif create mode 100644 doc/images/release-job.gif create mode 100644 doc/images/restart-job.gif create mode 100644 doc/images/save-changes.gif create mode 100644 doc/images/search.gif create mode 100644 doc/images/set-allowed-users.gif create mode 100644 doc/images/set-as-default.gif create mode 100644 doc/images/set-printer-options.gif create mode 100644 doc/images/show-active.gif create mode 100644 doc/images/show-all.gif create mode 100644 doc/images/show-ascending.gif create mode 100644 doc/images/show-completed.gif create mode 100644 doc/images/show-descending.gif create mode 100644 doc/images/show-next.gif create mode 100644 doc/images/show-previous.gif create mode 100644 doc/images/start-class.gif create mode 100644 doc/images/start-printer.gif create mode 100644 doc/images/stop-class.gif create mode 100644 doc/images/stop-printer.gif create mode 100644 doc/images/tab-left.gif create mode 100644 doc/images/tab-right.gif create mode 100644 doc/images/top-left.gif create mode 100644 doc/images/top-middle.gif create mode 100644 doc/images/top-right.gif create mode 100644 doc/images/unpublish-printer.gif create mode 100644 doc/images/use-default-config.gif create mode 100644 doc/images/view-access-log.gif create mode 100644 doc/images/view-error-log.gif create mode 100644 doc/images/view-page-log.gif create mode 100644 doc/index.html.in create mode 100644 doc/ipp.html create mode 100644 doc/ipp.pdf create mode 100644 doc/ipp.shtml create mode 100644 doc/overview.html create mode 100644 doc/overview.pdf create mode 100644 doc/ppd.shtml create mode 100644 doc/printing-overview.shtml create mode 100644 doc/references.shtml create mode 100644 doc/robots.txt create mode 100644 doc/sam.html create mode 100644 doc/sam.pdf create mode 100644 doc/sam.shtml create mode 100644 doc/sdd.html create mode 100644 doc/sdd.pdf create mode 100644 doc/sdd.shtml create mode 100644 doc/spm.html create mode 100644 doc/spm.pdf create mode 100644 doc/spm.shtml create mode 100644 doc/sps.html create mode 100644 doc/sps.pdf create mode 100644 doc/sps.shtml create mode 100644 doc/ssr.html create mode 100644 doc/ssr.pdf create mode 100644 doc/ssr.shtml create mode 100644 doc/stp.html create mode 100644 doc/stp.pdf create mode 100644 doc/stp.shtml create mode 100644 doc/sum.html create mode 100644 doc/sum.pdf create mode 100644 doc/sum.shtml create mode 100644 doc/svd.html create mode 100644 doc/svd.pdf create mode 100644 doc/svd.shtml create mode 100644 doc/system-overview.shtml create mode 100644 doc/translation.html create mode 100644 doc/translation.pdf create mode 100644 doc/translation.shtml create mode 100644 filter/Dependencies create mode 100644 filter/Makefile create mode 100644 filter/common.c create mode 100644 filter/common.h create mode 100644 filter/form-main.c create mode 100644 filter/form-ps.c create mode 100644 filter/form-tree.c create mode 100644 filter/form.h create mode 100644 filter/gziptoany.c create mode 100644 filter/hpgl-attr.c create mode 100644 filter/hpgl-char.c create mode 100644 filter/hpgl-config.c create mode 100644 filter/hpgl-input.c create mode 100644 filter/hpgl-main.c create mode 100644 filter/hpgl-polygon.c create mode 100644 filter/hpgl-prolog.c create mode 100644 filter/hpgl-vector.c create mode 100644 filter/hpgltops.h create mode 100644 filter/image-bmp.c create mode 100644 filter/image-colorspace.c create mode 100644 filter/image-gif.c create mode 100644 filter/image-jpeg.c create mode 100644 filter/image-photocd.c create mode 100644 filter/image-pix.c create mode 100644 filter/image-png.c create mode 100644 filter/image-pnm.c create mode 100644 filter/image-private.h create mode 100644 filter/image-sgi.c create mode 100644 filter/image-sgi.h create mode 100644 filter/image-sgilib.c create mode 100644 filter/image-sun.c create mode 100644 filter/image-tiff.c create mode 100644 filter/image-zoom.c create mode 100644 filter/image.c create mode 100644 filter/image.h create mode 100644 filter/imagetops.c create mode 100644 filter/imagetoraster.c create mode 100644 filter/interpret.c create mode 100644 filter/pstops.c create mode 100644 filter/raster.c create mode 100644 filter/raster.h create mode 100644 filter/rastertoepson.c create mode 100644 filter/rastertohp.c create mode 100644 filter/rastertolabel.c create mode 100644 filter/testimage.c create mode 100644 filter/testraster.c create mode 100644 filter/textcommon.c create mode 100644 filter/textcommon.h create mode 100644 filter/texttops.c create mode 100644 fonts/Courier create mode 100644 fonts/Courier-Bold create mode 100644 fonts/Courier-BoldOblique create mode 100644 fonts/Courier-Oblique create mode 100644 fonts/Makefile create mode 100644 fonts/Symbol create mode 100755 install-sh create mode 100644 locale/Makefile create mode 100644 locale/cups.footer create mode 100644 locale/cups.header create mode 100644 locale/cups.pot create mode 100644 locale/cups_fr.po create mode 100644 locale/locale.txt create mode 100644 locale/translate.c create mode 100644 man/Makefile create mode 100644 man/accept.man create mode 100644 man/backend.man create mode 100644 man/classes.conf.man create mode 100644 man/cups-config.man create mode 100644 man/cups-lpd.man create mode 100644 man/cups-polld.man create mode 100644 man/cupsaddsmb.man create mode 100644 man/cupsd.conf.man create mode 100644 man/cupsd.man create mode 100644 man/cupsenable.man create mode 100644 man/cupstestppd.man create mode 100644 man/filter.man create mode 100644 man/lp.man create mode 100644 man/lpadmin.man create mode 100644 man/lpc.man create mode 100644 man/lpinfo.man create mode 100644 man/lpmove.man create mode 100644 man/lpoptions.man create mode 100644 man/lppasswd.man create mode 100644 man/lpq.man create mode 100644 man/lpr.man create mode 100644 man/lprm.man create mode 100644 man/lpstat.man create mode 100644 man/mantohtml.c create mode 100644 man/mime.convs.man create mode 100644 man/mime.types.man create mode 100644 man/printers.conf.man create mode 100644 notifier/Dependencies create mode 100644 notifier/Makefile create mode 100644 notifier/mailto.c create mode 100644 notifier/testnotify.c create mode 100644 packaging/LICENSE.rtf create mode 100644 packaging/WELCOME.rtf create mode 100644 packaging/cups-desc.plist.in create mode 100644 packaging/cups-info.plist.in create mode 100644 packaging/cups.list.in create mode 100644 packaging/cups.spec.in create mode 100644 packaging/installer.tif create mode 100644 packaging/installer.xcf.gz create mode 100644 pdftops/Annot.cxx create mode 100644 pdftops/Annot.h create mode 100644 pdftops/Array.cxx create mode 100644 pdftops/Array.h create mode 100644 pdftops/BuiltinFont.cxx create mode 100644 pdftops/BuiltinFont.h create mode 100644 pdftops/BuiltinFontTables.cxx create mode 100644 pdftops/BuiltinFontTables.h create mode 100644 pdftops/CMap.cxx create mode 100644 pdftops/CMap.h create mode 100644 pdftops/COPYING create mode 100644 pdftops/Catalog.cxx create mode 100644 pdftops/Catalog.h create mode 100644 pdftops/CharCodeToUnicode.cxx create mode 100644 pdftops/CharCodeToUnicode.h create mode 100644 pdftops/CharTypes.h create mode 100644 pdftops/CompactFontTables.h create mode 100644 pdftops/Decrypt.cxx create mode 100644 pdftops/Decrypt.h create mode 100644 pdftops/Dependencies create mode 100644 pdftops/Dict.cxx create mode 100644 pdftops/Dict.h create mode 100644 pdftops/Error.cxx create mode 100644 pdftops/Error.h create mode 100644 pdftops/ErrorCodes.h create mode 100644 pdftops/FoFiBase.cxx create mode 100644 pdftops/FoFiBase.h create mode 100644 pdftops/FoFiEncodings.cxx create mode 100644 pdftops/FoFiEncodings.h create mode 100644 pdftops/FoFiTrueType.cxx create mode 100644 pdftops/FoFiTrueType.h create mode 100644 pdftops/FoFiType1.cxx create mode 100644 pdftops/FoFiType1.h create mode 100644 pdftops/FoFiType1C.cxx create mode 100644 pdftops/FoFiType1C.h create mode 100644 pdftops/FontEncodingTables.cxx create mode 100644 pdftops/FontEncodingTables.h create mode 100644 pdftops/Function.cxx create mode 100644 pdftops/Function.h create mode 100644 pdftops/GHash.cxx create mode 100644 pdftops/GHash.h create mode 100644 pdftops/GList.cxx create mode 100644 pdftops/GList.h create mode 100644 pdftops/GMutex.h create mode 100644 pdftops/GString.cxx create mode 100644 pdftops/GString.h create mode 100644 pdftops/Gfx.cxx create mode 100644 pdftops/Gfx.h create mode 100644 pdftops/GfxFont.cxx create mode 100644 pdftops/GfxFont.h create mode 100644 pdftops/GfxState.cxx create mode 100644 pdftops/GfxState.h create mode 100644 pdftops/GlobalParams.cxx create mode 100644 pdftops/GlobalParams.h create mode 100644 pdftops/JArithmeticDecoder.cxx create mode 100644 pdftops/JArithmeticDecoder.h create mode 100644 pdftops/JBIG2Stream.cxx create mode 100644 pdftops/JBIG2Stream.h create mode 100644 pdftops/JPXStream.cxx create mode 100644 pdftops/JPXStream.h create mode 100644 pdftops/Lexer.cxx create mode 100644 pdftops/Lexer.h create mode 100644 pdftops/Link.cxx create mode 100644 pdftops/Link.h create mode 100644 pdftops/Makefile create mode 100644 pdftops/NameToCharCode.cxx create mode 100644 pdftops/NameToCharCode.h create mode 100644 pdftops/NameToUnicodeTable.h create mode 100644 pdftops/Object.cxx create mode 100644 pdftops/Object.h create mode 100644 pdftops/Outline.cxx create mode 100644 pdftops/Outline.h create mode 100644 pdftops/OutputDev.cxx create mode 100644 pdftops/OutputDev.h create mode 100644 pdftops/PDFDoc.cxx create mode 100644 pdftops/PDFDoc.h create mode 100644 pdftops/PDFDocEncoding.cxx create mode 100644 pdftops/PDFDocEncoding.h create mode 100644 pdftops/PSOutputDev.cxx create mode 100644 pdftops/PSOutputDev.h create mode 100644 pdftops/PSTokenizer.cxx create mode 100644 pdftops/PSTokenizer.h create mode 100644 pdftops/Page.cxx create mode 100644 pdftops/Page.h create mode 100644 pdftops/Parser.cxx create mode 100644 pdftops/Parser.h create mode 100644 pdftops/README create mode 100644 pdftops/SecurityHandler.cxx create mode 100644 pdftops/SecurityHandler.h create mode 100644 pdftops/Splash.cxx create mode 100644 pdftops/Splash.h create mode 100644 pdftops/SplashBitmap.cxx create mode 100644 pdftops/SplashBitmap.h create mode 100644 pdftops/SplashClip.cxx create mode 100644 pdftops/SplashClip.h create mode 100644 pdftops/SplashErrorCodes.h create mode 100644 pdftops/SplashFTFont.cxx create mode 100644 pdftops/SplashFTFont.h create mode 100644 pdftops/SplashFTFontEngine.cxx create mode 100644 pdftops/SplashFTFontEngine.h create mode 100644 pdftops/SplashFTFontFile.cxx create mode 100644 pdftops/SplashFTFontFile.h create mode 100644 pdftops/SplashFont.cxx create mode 100644 pdftops/SplashFont.h create mode 100644 pdftops/SplashFontEngine.cxx create mode 100644 pdftops/SplashFontEngine.h create mode 100644 pdftops/SplashFontFile.cxx create mode 100644 pdftops/SplashFontFile.h create mode 100644 pdftops/SplashFontFileID.cxx create mode 100644 pdftops/SplashFontFileID.h create mode 100644 pdftops/SplashGlyphBitmap.h create mode 100644 pdftops/SplashMath.h create mode 100644 pdftops/SplashOutputDev.cxx create mode 100644 pdftops/SplashOutputDev.h create mode 100644 pdftops/SplashPath.cxx create mode 100644 pdftops/SplashPath.h create mode 100644 pdftops/SplashPattern.cxx create mode 100644 pdftops/SplashPattern.h create mode 100644 pdftops/SplashScreen.cxx create mode 100644 pdftops/SplashScreen.h create mode 100644 pdftops/SplashState.cxx create mode 100644 pdftops/SplashState.h create mode 100644 pdftops/SplashT1Font.cxx create mode 100644 pdftops/SplashT1Font.h create mode 100644 pdftops/SplashT1FontEngine.cxx create mode 100644 pdftops/SplashT1FontEngine.h create mode 100644 pdftops/SplashT1FontFile.cxx create mode 100644 pdftops/SplashT1FontFile.h create mode 100644 pdftops/SplashTypes.h create mode 100644 pdftops/SplashXPath.cxx create mode 100644 pdftops/SplashXPath.h create mode 100644 pdftops/SplashXPathScanner.cxx create mode 100644 pdftops/SplashXPathScanner.h create mode 100644 pdftops/Stream-CCITT.h create mode 100644 pdftops/Stream.cxx create mode 100644 pdftops/Stream.h create mode 100644 pdftops/UTF8.h create mode 100644 pdftops/UnicodeMap.cxx create mode 100644 pdftops/UnicodeMap.h create mode 100644 pdftops/UnicodeMapTables.h create mode 100644 pdftops/UnicodeTypeTable.cxx create mode 100644 pdftops/UnicodeTypeTable.h create mode 100644 pdftops/XRef.cxx create mode 100644 pdftops/XRef.h create mode 100644 pdftops/XpdfPluginAPI.cxx create mode 100644 pdftops/XpdfPluginAPI.h create mode 100644 pdftops/config.h create mode 100644 pdftops/gfile.cxx create mode 100644 pdftops/gfile.h create mode 100644 pdftops/gmem.c create mode 100644 pdftops/gmem.h create mode 100644 pdftops/gmempp.cxx create mode 100644 pdftops/gtypes.h create mode 100644 pdftops/parseargs.c create mode 100644 pdftops/parseargs.h create mode 100644 pdftops/pdftops.cxx create mode 100644 ppd/Makefile create mode 100644 ppd/deskjet.ppd create mode 100644 ppd/deskjet2.ppd create mode 100644 ppd/dymo.ppd create mode 100644 ppd/epson24.ppd create mode 100644 ppd/epson9.ppd create mode 100644 ppd/laserjet.ppd create mode 100644 ppd/okidat24.ppd create mode 100644 ppd/okidata9.ppd create mode 100644 ppd/stcolor.ppd create mode 100644 ppd/stcolor2.ppd create mode 100644 ppd/stphoto.ppd create mode 100644 ppd/stphoto2.ppd create mode 100644 ppd/zebra.ppd create mode 100644 ppd/zebracpl.ppd create mode 100644 ppd/zebraep1.ppd create mode 100644 ppd/zebraep2.ppd create mode 100644 pstoraster/README.pstoraster create mode 100644 pstoraster/cups.mak create mode 100644 pstoraster/gdevcups.c create mode 100644 pstoraster/gs707-lib.patch create mode 100644 pstoraster/gs811-lib.patch create mode 100644 pstoraster/pstopxl create mode 100755 pstoraster/pstopxl.in create mode 100755 pstoraster/pstoraster create mode 100644 pstoraster/pstoraster.convs create mode 100755 pstoraster/pstoraster.in create mode 100644 pstoraster/pxlcolor.ppd create mode 100644 pstoraster/pxlmono.ppd create mode 100644 scheduler/Dependencies create mode 100644 scheduler/Makefile create mode 100644 scheduler/auth.c create mode 100644 scheduler/auth.h create mode 100644 scheduler/banners.c create mode 100644 scheduler/banners.h create mode 100644 scheduler/cert.c create mode 100644 scheduler/cert.h create mode 100644 scheduler/classes.c create mode 100644 scheduler/classes.h create mode 100644 scheduler/client.c create mode 100644 scheduler/client.h create mode 100644 scheduler/conf.c create mode 100644 scheduler/conf.h create mode 100644 scheduler/cups-deviced.c create mode 100644 scheduler/cups-driverd.c create mode 100644 scheduler/cups-lpd.c create mode 100644 scheduler/cups-polld.c create mode 100644 scheduler/cups.pam create mode 100644 scheduler/cupsd.h create mode 100644 scheduler/dirsvc.c create mode 100644 scheduler/dirsvc.h create mode 100644 scheduler/env.c create mode 100644 scheduler/filter.c create mode 100644 scheduler/ipp.c create mode 100644 scheduler/job.c create mode 100644 scheduler/job.h create mode 100644 scheduler/listen.c create mode 100644 scheduler/log.c create mode 100644 scheduler/main.c create mode 100644 scheduler/mime.c create mode 100644 scheduler/mime.h create mode 100644 scheduler/network.c create mode 100644 scheduler/network.h create mode 100644 scheduler/policy.c create mode 100644 scheduler/policy.h create mode 100644 scheduler/printers.c create mode 100644 scheduler/printers.h create mode 100644 scheduler/process.c create mode 100644 scheduler/quotas.c create mode 100644 scheduler/server.c create mode 100644 scheduler/statbuf.c create mode 100644 scheduler/statbuf.h create mode 100644 scheduler/subscriptions.c create mode 100644 scheduler/subscriptions.h create mode 100644 scheduler/testdirsvc.c create mode 100644 scheduler/testmime.c create mode 100644 scheduler/testspeed.c create mode 100644 scheduler/type.c create mode 100644 scheduler/util.c create mode 100644 scheduler/util.h create mode 100644 scripting/java/CUPSPrinter.java create mode 100644 scripting/java/classes/com/easysw/cups/Cups.class create mode 100644 scripting/java/classes/com/easysw/cups/CupsJob.class create mode 100644 scripting/java/classes/com/easysw/cups/CupsPrinter.class create mode 100644 scripting/java/classes/com/easysw/cups/IPP.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPAttribute.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPBase64Encoder.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPCalendar.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPDefs.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPError.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPHttp.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPMD5.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPRequest.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPStatus.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPURLConnection.class create mode 100644 scripting/java/classes/com/easysw/cups/IPPValue.class create mode 100644 scripting/java/cups.jar create mode 100644 scripting/java/docs/allclasses-frame.html create mode 100644 scripting/java/docs/com/easysw/cups/Cups.html create mode 100644 scripting/java/docs/com/easysw/cups/CupsJob.html create mode 100644 scripting/java/docs/com/easysw/cups/CupsPrinter.html create mode 100644 scripting/java/docs/com/easysw/cups/IPP.html create mode 100644 scripting/java/docs/com/easysw/cups/IPPAttribute.html create mode 100644 scripting/java/docs/com/easysw/cups/IPPDefs.html create mode 100644 scripting/java/docs/com/easysw/cups/IPPError.html create mode 100644 scripting/java/docs/com/easysw/cups/IPPHttp.html create mode 100644 scripting/java/docs/com/easysw/cups/IPPRequest.html create mode 100644 scripting/java/docs/com/easysw/cups/IPPStatus.html create mode 100644 scripting/java/docs/com/easysw/cups/IPPURLConnection.html create mode 100644 scripting/java/docs/com/easysw/cups/IPPValue.html create mode 100644 scripting/java/docs/deprecated-list.html create mode 100644 scripting/java/docs/help-doc.html create mode 100644 scripting/java/docs/index-all.html create mode 100644 scripting/java/docs/index.html create mode 100644 scripting/java/docs/overview-tree.html create mode 100644 scripting/java/docs/package-list create mode 100644 scripting/java/docs/packages.html create mode 100644 scripting/java/docs/serialized-form.html create mode 100644 scripting/java/docs/stylesheet.css create mode 100644 scripting/java/example/GLP.class create mode 100644 scripting/java/example/GLP.java create mode 100644 scripting/java/example/GLPcolors.class create mode 100644 scripting/java/example/GLPcolors.java create mode 100644 scripting/java/example/GLPdetail.class create mode 100644 scripting/java/example/GLPdetail.java create mode 100644 scripting/java/example/GLPjobList.class create mode 100644 scripting/java/example/GLPjobList.java create mode 100644 scripting/java/example/GLPjobTableModel.class create mode 100644 scripting/java/example/GLPjobTableModel.java create mode 100644 scripting/java/example/GLPoptions$1.class create mode 100644 scripting/java/example/GLPoptions$MyTextListener.class create mode 100644 scripting/java/example/GLPoptions.class create mode 100644 scripting/java/example/GLPoptions.java create mode 100644 scripting/java/example/GLPprinterDetail.class create mode 100644 scripting/java/example/GLPprinterDetail.java create mode 100644 scripting/java/example/GLPprinters.class create mode 100644 scripting/java/example/GLPprinters.java create mode 100644 scripting/java/example/GLPsearch.class create mode 100644 scripting/java/example/GLPsearch.java create mode 100644 scripting/java/example/GLPsearchProgressPanel$1.class create mode 100644 scripting/java/example/GLPsearchProgressPanel$2.class create mode 100644 scripting/java/example/GLPsearchProgressPanel$ButtonListener.class create mode 100644 scripting/java/example/GLPsearchProgressPanel.class create mode 100644 scripting/java/example/GLPsearchProgressPanel.java create mode 100644 scripting/java/example/GLPserver.class create mode 100644 scripting/java/example/GLPserver.java create mode 100644 scripting/java/example/GLPtabs$1.class create mode 100644 scripting/java/example/GLPtabs.class create mode 100644 scripting/java/example/GLPtabs.java create mode 100644 scripting/java/example/GLPvars.class create mode 100644 scripting/java/example/GLPvars.java create mode 100755 scripting/java/example/buildit create mode 100644 scripting/java/example/class.list create mode 100644 scripting/java/example/images/left.gif create mode 100644 scripting/java/example/images/print-test-page.gif create mode 100644 scripting/java/example/images/printer-idle.gif create mode 100644 scripting/java/example/images/printer-stopped.gif create mode 100644 scripting/java/example/images/restart-job.gif create mode 100644 scripting/java/example/images/show-active.gif create mode 100644 scripting/java/example/images/show-completed.gif create mode 100755 scripting/java/example/runit create mode 100644 scripting/java/src/com/easysw/cups/Cups.java create mode 100644 scripting/java/src/com/easysw/cups/CupsJob.java create mode 100644 scripting/java/src/com/easysw/cups/CupsPrinter.java create mode 100644 scripting/java/src/com/easysw/cups/IPP.java create mode 100644 scripting/java/src/com/easysw/cups/IPPAttribute.java create mode 100644 scripting/java/src/com/easysw/cups/IPPBase64Encoder.java create mode 100644 scripting/java/src/com/easysw/cups/IPPCalendar.java create mode 100644 scripting/java/src/com/easysw/cups/IPPDefs.java create mode 100644 scripting/java/src/com/easysw/cups/IPPError.java create mode 100644 scripting/java/src/com/easysw/cups/IPPHttp.java create mode 100644 scripting/java/src/com/easysw/cups/IPPMD5.java create mode 100644 scripting/java/src/com/easysw/cups/IPPRequest.java create mode 100644 scripting/java/src/com/easysw/cups/IPPStatus.java create mode 100644 scripting/java/src/com/easysw/cups/IPPURLConnection.java create mode 100644 scripting/java/src/com/easysw/cups/IPPValue.java create mode 100755 scripting/java/src/com/easysw/cups/buildit create mode 100644 scripting/java/src/com/easysw/cups/class.list create mode 100644 scripting/java/src/com/easysw/cups/cups.nfo create mode 100644 scripting/perl/CUPS.pm create mode 100644 scripting/perl/CUPS.xs create mode 100644 scripting/perl/Makefile.PL create mode 100644 scripting/perl/README create mode 100644 scripting/perl/test.pl create mode 100644 scripting/php/Dependencies create mode 100644 scripting/php/Example/phpcups.inc.php4 create mode 100644 scripting/php/Makefile create mode 100644 scripting/php/README create mode 100644 scripting/php/config.m4 create mode 100644 scripting/php/php_phpcups.h create mode 100644 scripting/php/phpcups.c create mode 100644 scripting/php/phpcups.php create mode 100644 standards/pwg5100.1.pdf create mode 100644 standards/pwg5100.2.pdf create mode 100644 standards/pwg5100.3.pdf create mode 100644 standards/pwg5100.4.pdf create mode 100644 standards/rfc1179.txt create mode 100644 standards/rfc1321.txt create mode 100644 standards/rfc2222.txt create mode 100644 standards/rfc2246.txt create mode 100644 standards/rfc2487.txt create mode 100644 standards/rfc2554.txt create mode 100644 standards/rfc2565.txt create mode 100644 standards/rfc2566.txt create mode 100644 standards/rfc2567.txt create mode 100644 standards/rfc2568.txt create mode 100644 standards/rfc2569.txt create mode 100644 standards/rfc2595.txt create mode 100644 standards/rfc2616.txt create mode 100644 standards/rfc2617.txt create mode 100644 standards/rfc2639.txt create mode 100644 standards/rfc2712.txt create mode 100644 standards/rfc2817.txt create mode 100644 standards/rfc2818.txt create mode 100644 standards/rfc2821.txt create mode 100644 standards/rfc2822.txt create mode 100644 standards/rfc2910.txt create mode 100644 standards/rfc2911.txt create mode 100644 standards/rfc2965.txt create mode 100644 standards/rfc3239.txt create mode 100644 standards/rfc3380.txt create mode 100644 standards/rfc3381.txt create mode 100644 standards/rfc3382.txt create mode 100644 standards/rfc3510.txt create mode 100644 standards/rfc3986.txt create mode 100644 standards/rfc3995.txt create mode 100644 standards/rfc3996.txt create mode 100644 standards/rfc3997.txt create mode 100644 standards/rfc3998.txt create mode 100644 standards/wd-ippmailto10-20050519.pdf create mode 100644 systemv/Dependencies create mode 100644 systemv/Makefile create mode 100644 systemv/accept.c create mode 100644 systemv/cancel.c create mode 100644 systemv/cupsaddsmb.c create mode 100644 systemv/cupstestppd.c create mode 100644 systemv/lp.c create mode 100644 systemv/lpadmin.c create mode 100644 systemv/lpinfo.c create mode 100644 systemv/lpmove.c create mode 100644 systemv/lpoptions.c create mode 100644 systemv/lppasswd.c create mode 100644 systemv/lpstat.c create mode 100644 templates/Makefile create mode 100644 templates/add-class.tmpl create mode 100644 templates/add-printer.tmpl create mode 100644 templates/admin-op.tmpl create mode 100644 templates/admin.tmpl create mode 100644 templates/choose-device.tmpl create mode 100644 templates/choose-make.tmpl create mode 100644 templates/choose-model.tmpl create mode 100644 templates/choose-serial.tmpl create mode 100644 templates/choose-uri.tmpl create mode 100644 templates/class-added.tmpl create mode 100644 templates/class-confirm.tmpl create mode 100644 templates/class-deleted.tmpl create mode 100644 templates/class-modified.tmpl create mode 100644 templates/classes.tmpl create mode 100644 templates/edit-config.tmpl.in create mode 100644 templates/error.tmpl create mode 100644 templates/header.tmpl create mode 100644 templates/help-header.tmpl create mode 100644 templates/job-cancel.tmpl create mode 100644 templates/job-hold.tmpl create mode 100644 templates/job-op.tmpl create mode 100644 templates/job-release.tmpl create mode 100644 templates/job-restart.tmpl create mode 100644 templates/jobs-header.tmpl create mode 100644 templates/jobs.tmpl create mode 100644 templates/modify-class.tmpl create mode 100644 templates/modify-printer.tmpl create mode 100644 templates/option-boolean.tmpl create mode 100644 templates/option-conflict.tmpl create mode 100644 templates/option-header.tmpl create mode 100644 templates/option-pickmany.tmpl create mode 100644 templates/option-pickone.tmpl create mode 100644 templates/option-trailer.tmpl create mode 100644 templates/page.tmpl create mode 100644 templates/printer-accept.tmpl create mode 100644 templates/printer-added.tmpl create mode 100644 templates/printer-configured.tmpl create mode 100644 templates/printer-confirm.tmpl create mode 100644 templates/printer-default.tmpl create mode 100644 templates/printer-deleted.tmpl create mode 100644 templates/printer-modified.tmpl create mode 100644 templates/printer-purge.tmpl create mode 100644 templates/printer-reject.tmpl create mode 100644 templates/printer-start.tmpl create mode 100644 templates/printer-stop.tmpl create mode 100644 templates/printers.tmpl create mode 100644 templates/restart.tmpl create mode 100644 templates/search.tmpl create mode 100644 templates/set-printer-options-header.tmpl create mode 100644 templates/set-printer-options-trailer.tmpl create mode 100644 templates/test-page.tmpl create mode 100644 templates/trailer.tmpl create mode 100644 templates/users.tmpl create mode 100644 test/4.1-requests.test create mode 100644 test/4.2-cups-printer-ops.test create mode 100644 test/4.3-job-ops.test create mode 100644 test/4.4-subscription-ops.test create mode 100644 test/5.1-lpadmin.sh create mode 100644 test/5.2-lpc.sh create mode 100644 test/5.3-lpq.sh create mode 100644 test/5.4-lpstat.sh create mode 100644 test/5.5-lp.sh create mode 100644 test/5.6-lpr.sh create mode 100644 test/5.7-lprm.sh create mode 100644 test/5.8-cancel.sh create mode 100644 test/5.9-lpinfo.sh create mode 100644 test/Dependencies create mode 100644 test/Makefile create mode 100644 test/create-job-format.test create mode 100644 test/create-job-sheets.test create mode 100644 test/create-job-timeout.test create mode 100644 test/create-job.test create mode 100644 test/get-devices.test create mode 100644 test/get-job-attributes.test create mode 100644 test/get-job-attributes2.test create mode 100644 test/get-ppds.test create mode 100644 test/get-printer-attributes.test create mode 100644 test/ipptest.c create mode 100644 test/print-job-hold.test create mode 100644 test/print-job.test create mode 100755 test/run-stp-tests.sh create mode 100644 test/set-attrs-hold.test create mode 100644 test/str-header.html create mode 100644 test/str-trailer.html create mode 100644 test/testfile.jpg create mode 100644 test/testfile.pdf create mode 100644 test/testfile.ps create mode 100644 test/testfile.txt create mode 100644 test/testhp.ppd create mode 100644 test/testps.ppd create mode 100755 tools/makesrcdist create mode 100755 tools/testosx create mode 100755 tools/testrpm create mode 100644 vcnet/config.h create mode 100644 vcnet/cups.sln create mode 100644 vcnet/libcups2.def create mode 100644 vcnet/libcups2.vcproj diff --git a/CGI.txt b/CGI.txt new file mode 100644 index 000000000..337acb891 --- /dev/null +++ b/CGI.txt @@ -0,0 +1,81 @@ +CGI - CUPS v1.1.21 - 06/29/2004 +------------------------------- + +This file describes the experimental scripting/CGI support +provided by CUPS starting with CUPS 1.1.19. + +WARNING: CGI support is not complete; you may run into problems +and limitations in the implementation of CGI in CUPS that are +not present in full-featured web servers like Apache. + + +OVERVIEW OF CGI SUPPORT IN CUPS + +CUPS has traditionally provided a dynamic web interface through +four CGI programs that are executed when users open special +directories on the CUPS server. Each CGI performs +administration, class, job, and printer functions as directed by +the user, but the actual programs that are run and functions +that are available are limited to those that were originally +designed into the scheduler. + +Starting with CUPS 1.1.19, support is now available for CGI +programs and specific scripting languages, currently Java, Perl, +PHP, and Python. The interpreters for these languages are +currently configured at compile time. Future versions may +expand the interface to allow for generic support of scripting +languages similar to the Apache "AddHandler" directive, but with +external programs instead of modules. + +The following MIME types are reserved for the CGI support in +CUPS (the names have been chosen to mirror those used by +Apache): + + application/x-httpd-cgi CGI script/program + application/x-httpd-java Java program + application/x-httpd-perl Perl script + application/x-httpd-php PHP script + application/x-httpd-python Python script + +In order to enable the corresponding type, you must create a new +/etc/cups/cgi.types file which maps the filename extensions to +the appropriate MIME type, for example: + + application/x-httpd-cgi cgi + application/x-httpd-php php + +CGI scripts/programs (application/x-httpd-cgi) also must have +execution permissions to be treated as a CGI script or program. + + +LIMITATIONS + +CUPS implements most of the CGI/1.1 specification, with the +following limitations: + + - No Location: redirection support. + - No PATH_INFO or PATH_TRANSLATED support. + - Limited HTTP field support; only the Content-Length + (CONTENT_LENGTH), Cookie (HTTP_COOKIE), and User-Agent + (HTTP_USER_AGENT) fields are placed in environment + variables at this time. + + +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/CHANGES-1.0.txt b/CHANGES-1.0.txt new file mode 100644 index 000000000..296d89f79 --- /dev/null +++ b/CHANGES-1.0.txt @@ -0,0 +1,217 @@ +CHANGES-1.0.txt +--------------- + +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/CHANGES-1.1.txt b/CHANGES-1.1.txt new file mode 100644 index 000000000..c641e794a --- /dev/null +++ b/CHANGES-1.1.txt @@ -0,0 +1,3462 @@ +CHANGES-1.1.txt +--------------- + +CHANGES IN CUPS V1.1.23 + + - Updated the Spanish man pages (STR #1041) + - The lpstat man page contained a typo (STR #1040) + - The scheduler's is_path_absolute() code could cause a + DoS (STR #1042) + - The scheduler's device loading code used the wrong + size limits for the make/model and info parameters + (STR #1035) + - The PNG loading code did not use a "long unsigned + integer" format specifier for the width and height + (STR #1032) + - The web interface only showed the first 4 or 8 + characters of "{variable-name}" for undefined template + variables (STR #1031) + - The hpgltops filter did not handle a common PCL + command to enter HP-GL/2 mode (STR #1037) + + +CHANGES IN CUPS V1.1.23rc1 + + - The lpr man page did not document the "-U" option (STR + #998) + - The scheduler no longer sends the page-set option when + printing banner pages (STR #995) + - Fixed a debug message in the imagetops filter (STR + #1012) + - The lprm man page listed the "-" option in the wrong + order (STR #911) + - The hpgltops filter contained two buffer overflows + that could potentially allow remote access to the "lp" + account (STR #1024) + - The lppasswd command did not protect against file + descriptor or ulimit attacks (STR #1023) + - The "lpc status" command used the wrong resource path + when querying the list of printers and jobs, causing + unnecessary authentication requests (STR #1018) + - The httpWait() function did not handle signal + interruptions (STR #1020) + - The USB backend used the wrong size status variable + when checking the printer status (STR #1017) + - The scheduler did not delete classes from other + classes or implicit classes, which could cause a crash + (STR #1015) + - The IPP backend now logs the remote print job ID at + log level NOTICE instead of INFO (so it shows up in + the error_log file...) + + +CHANGES IN CUPS V1.1.22 + + - The lpstat man page incorrectly listed the "-s" option + as using the equivalent of the "-p" option to list the + printers; it uses the "-v" option to list the printers + (STR #986) + - Now allow 0-length reads in the CUPS file API (STR + #985) + - cupsDoFileRequest() now sets cupsLastError() to + IPP_ERROR on network errors (STR #953) + - The pdftops filter didn't scale small pages up to the + output page size when the fitplot option was used (STR + #984) + - Fixed the ipptest program usage message (STR #959) + - Added Spanish man pages (STR #963) + - Fixed the order of comparisons in the client.conf + reading code (STR #971) + - cupsLangGet() incorrectly set the current locale (STR + #970) + + +CHANGES IN CUPS V1.1.22rc2 + + - The pdftops filter didn't check the range of all + integer attributes (STR #972) + - Documentation corrections (STR #944, STR #946) + - Also sanitize device URI in argv[0] (STR #933) + - cupsRasterReadHeader() didn't swap bytes for the + numeric fields properly (STR #930) + + +CHANGES IN CUPS V1.1.22rc1 + + - Now sanitize the device URI that is reported in the + error_log file (STR #920) + - Fixed some memory and file descriptor leaks in the job + dispatch code (STR #921) + - Deleting a printer could cause a crash with browsing + enabled (STR #865, STR #881, STR #928) + - Browsing would turn off if the scheduler got an EAGAIN + error (STR #924) + - The mime.types file didn't recognize PostScript as a + PJL language name (STR #925) + + +CHANGES IN CUPS V1.1.21 + + - The scheduler did not separate Digest authentication + parameters with commas (STR #882) + - Fixed some problems with image printing to custom page + sizes (STR #891) + - Removed the remaining scheduler code that did not use + the "close-on-exec" file descriptor flag to speed up + program invocations (STR #890) + - The "lpr -r" command removed the print file even if it + was not printed. It now only removes the file if the + job is successfully created (STR #886) + - Revamped the custom page size orientation fix (STR + #127) + - The lp, lpq, lpr, and lpstat commands now report when + an environment variable is pointing to a non-existent + printer instead of just saying "no default + destination" (STR #879) + - Queue names with 2 periods (e.g. "printer..2") were + not supported (STR #866) + + +CHANGES IN CUPS V1.1.21rc2 + + - Fixed a denial-of-service bug in the CUPS browse + protocol support (STR #863) + - The scheduler used a select() timeout of INT_MAX + seconds when there was nothing to do, which doesn't + work on IRIX (STR #864) + - Updated the cupsaddsmb program to use the new Windows + 2000 PostScript drivers instead of the Windows NT + printer drivers (STR #390) + - The gziptoany filter did not produce copies for raw + print jobs (STR #808) + - The cupsLangGet() function now uses nl_langinfo(), + when available, to get the current encoding (STR #856) + - Added a ReloadTimeout directive to control how long + the scheduler waits for jobs to complete before + restarting the scheduler (STR #861) + - Added a note to the default cupsd.conf file which + mentions that you must allow connections from + localhost for the command-line and web interfaces to + work (STR #850) + - The IPP backend incorrectly used the local port when + communicating with a remote server; this caused + problems with some custom configurations (STR #852) + - The cups-lpd mini-daemon wasn't using the right + default banner option (STR #851) + - Updated the new httpDecode64_2() and httpEncode64_2() + functions to handle arbitrary binary data, not just + text (STR #860) + - String options with quotes in their values were not + quoted properly by the scheduler (STR #839) + - Configure script changes for GNU/Hurd (STR #838) + - The lppasswd program was not installed properly by GNU + install when the installer was not root (STR #836) + - Updated the cups-lpd man page (STR #843) + - Fixed a typo in the cupsd man page (STR #833) + - The USB backend now defaults to using the newer + /dev/usb/lpN filenames; this helps on systems which + use the devfs filesystem type on Linux (STR #818) + - The config.h file did not define the HAVE_USERSEC_H + constant when the configure script detected the + usersec.h header file. This caused authentication + errors on AIX (STR #832) + - The lp and lpr commands now report the temporary + filename and error if they are unable to create a + temporary file (STR #812) + - Added ServerTokens directive to control the Server + header in HTTP responses (STR #792) + - Added new httpDecode64_2(), httpEncode64_2(), and + httpSeparate2() functions which offer buffer size + arguments (STR #797) + - The cupsGetFile() and cupsPutFile() code did not + support CDSA or GNUTLS (STR #794) + - The httpSeparate() function did not decode all + character escapes (STR #795) + - The cupstestppd program now checks for invalid Duplex + option choices and fails PPD files that use + non-standard values (STR #791) + - Updated the printer name error message to indicate + that spaces are not allowed (STR #675) + - The scheduler didn't handle HTTP GET form data + properly (STR #744) + - The pstops filter now makes sure that the prolog code + is sent before the setup code (STR #776) + - The pstops filter now handles print files that + incorrectly start @PJL commands without a language + escape (STR #734) + - Miscellaneous build fixes for NetBSD (STR #788) + - Added support for quoted system group names (STR #784) + - Added "version" option to IPP backend to workaround + serious bug in Linksys's IPP implementation (STR #767) + - Added Spanish translation of web interface (STR #772, + STR #802) + - The LPD backend now uses geteuid() instead of getuid() + when it is available (STR #752) + - The IPP backend did not report the printer state if + the wait option was set to "no" (STR #761) + - The printer state was not updated for "STATE: foo,bar" + messages (STR #745) + - Added new CUPS API convenience functions which accept + a HTTP connection to eliminate extra username/password + prompts. This resolves a previous authentication + caching issue (STR #729, STR #743) + - The scheduler did not correctly throttle the browse + broadcasts, resulting in missing printers on client + machines (STR #754) + - The scheduler did not pass the correct CUPS_ENCRYPTION + setting to CGI programs which caused problems on + systems which used non-standard encryption settings + (STR #773) + - The lpq command showed 11st, 12nd, and 13rd instead of + 11th, 12th, and 13th for the rank (STR #769) + - "make install" didn't work on some platforms due to an + error in the man page makefiles (STR #775) + - Changed some calls to snprintf() in the scheduler to + SetStringf() (STR #740) + + +CHANGES IN CUPS V1.1.21rc1 + + - Fixed some "type-punned" warnings produced by GCC when + -fstrict-aliasing is specified (STR #679) + - The PDF filter incorrectly calculated the bounding box + of a page (STR #682) + - The IPP backend did not use SSL when printing over a + port other than 443 (STR #730) + - The scheduler could crash when processing a Limit or + LimitExcept directive (STR #728) + - The lpq, lpr, and lp commands did not differentiate + between the server being unresponsive and the lack of + a default printer (STR #728) + - The PAM checks in the configure script did not stop + after the first match (STR #728) + - The cups-config man page was incorrectly placed in + section 3 (STR #728) + - The cupstestppd utility did not show a warning message + when a PPD file indicated BCP protocol support with + PJL (STR #720) + - The scheduler did not return the correct exit code + when startup failed (STR #718) + - The cupsRasterReadPixels() function checked for + EAGAIN, which caused problems on FreeBSD (STR #723) + - The cupsGetDests() function did not use the current + encryption setting (STR #653) + - The scheduler did not properly parse name-based + BrowseRelay directives in the cupsd.conf file (STR + #711) + - The IPP backend now supports the following options in + the device URI: encryption, waitjob, and waitprinter + (STR #699) + - The parallel, serial, socket, and USB backends did not + return a non-zero exit status when a job failed to + print in the middle of sending it (STR #715) + - Location directives in the cupsd.conf file were + case-sensitive for printer and class names, so + queue-specific access control was not reliable (STR + #700) + - cupsDoFileRequest() did not handle HTTP continue + status messages in all cases, causing sporatic + problems with IPP printers from some vendors (STR + #716) + - The rastertodymo driver now supports the Zebra ZPL + language (STR #713) + - The test suite no longer generates a printcap file, + which caused problems when testing as the root user + (STR #693) + - The scheduler now updates the accepting state of an + implicit class based upon the accepting state of its + member printers (STR #697) + - The pstops filter didn't properly skip leading PJL + commands (STR #664) + - The reinterpret_cast keyword was not highlighted when + printing C/C++ source files in prettyprint mode (STR + #694) + - Fixed a segfault problem with some of the client + programs (STR #668) + - When using RunAsUser, the scheduler did not correctly + set the ownership of the log files, preventing log + file rotation (STR #686) + - The image filters did not correctly load 1-bit PNG + files (STR #687) + - The pdftops filter did not show all annotation objects + in a PDF file (STR #674) + - The pdftops filter did not print the contents of + textual form elements, making it impossible to print a + filled-in form (STR #663) + - Integrated the MacOS X/Darwin USB backend into the + CUPS baseline (STR #661) + - The USB backend incorrectly reported "media tray + empty" (STR #660) + - The scheduler did not use a case-insensitive + comparison when checking for group membership, which + caused problems with Win9x clients printing via SAMBA + (STR #647) + - The scheduler did not report the addresses associated + with certain network errors, making troubleshooting + difficult (STR #648, #649) + - The cupstestppd program did not allow a default choice + of "Unknown" as required by the PPD spec (STR #651) + - The select() buffers are now allocated to be at least + as large as sizeof(fd_set) (STR #639) + - The LPD backend now supports overriding the print job + username via the device URI (STR #631) + - The scheduler did not handle an unknown MIME type when + checking for a CGI script (STR #603) + - Added a timeout optimization to the scheduler's main + loop to allow CUPS to sleep more of the time (STR + #629) + - The USB backend now retries printing to devices of the + form "usb://make/model" if any USB port shows up as + "busy" (STR #617) + - The httpGetHostByName() function did not range check + IP address values (STR #608) + - The httpUpdate() function could return HTTP_ERROR + instead of the HTTP status if the server closed the + connection before the client received the whole + response (STR #611) + - The LPD mini-daemon did not allow the administrator to + force banner pages on (STR #605) + - Added PAM support for Darwin/MacOS X (STR #550) + - The web interface now provides a "Set As Default" + button to set the default printer or class on a server + (STR #577) + - The HTTP authentication cache was broken (STR #517) + - The cupstestppd utility now fails PPD files that have + a DefaultOption keyword for a non-existance option + name (STR #476) + - Optimized the scanning of new PPD files on scheduler + startup (STR #424) + - The EPM list file did not include the bin, lib, or + sbin directories (STR #598) + - The web interface did not redirect administration + tasks to the primary server for a class or printer + (STR #491, #652) + - The cups-lpd mini-daemon did not reject print jobs to + queues that were rejecting new print jobs (STR #515) + - Some calls to the ctype functions did not account for + platforms that use a signed char type by default (STR + #518) + - The scheduler could use excess amounts of CPU if a CGI + program was sending data faster than the client could + take it (STR #595) + - Updated the Ghostscript 8.x integration stuff (STR + #484) + - The lpd backend used a source port of 732 by default, + which is outside of the range defined by RFC 1179; + also added a new (default) "reserve=any" option for + any priviledged port from 1 to 1023 (STR #474) + - The scheduler did not check for a valid Listen/Port + configuration (STR #499) + - The cupsPrintFiles() function did not always set the + last IPP error message (STR #538) + - The pstops filter did not write the PostScript header + line if the file began with a PJL escape sequence (STR + #574) + - The printer-is-accepting-jobs status of remote + printers was not sent to clients via browsing or + polling (STR #571) + - Browse packets did not indicate whether a printer + was accepting or rejecting jobs. + - The web interface did not show the printer state + history information (STR #592) + - The rastertoepson filter would crash under certain + cirsumstances (STR #583) + - The USB backend did not handle serial numbers using + the (incorrect) SN keyword and did not terminate the + make and model name strings properly (STR #471, STR + #588) + - The USB backend did not build on Solaris x86 (STR + #585) + - The cupsDoAuthentication() function did not use the + method name for Digest authentication (STR #584) + - The scheduler could crash if a print job could not be + printed and the PreserveJobHistory option was turned + off (STR #535) + - cups-lpd now logs the temporary filenames that could + not be opened in order to make troubleshooting easier + (STR #565) + - cupsGetJobs() now returns -1 on error (STR #569) + - Added localization for Belarusian (STR #575) + - The LPD backend used the full length of the hostname + when creating the data and control filenames, which + causes problems with older systems that can't handle + long filenames (STR #560) + - The scheduler did not refresh the common printer data + after a fast reload; this prevented banner and other + information from being updated (STR #562) + - The scheduler did not send common or history data to + the client when processing a CUPS-Get-Default request + (STR #559) + - The httpFlush() function did not always flush the + remaining response data in requests (STR #558) + - The scheduler could complete a job before it collected + the exit status from all filters and the backend (STR + #448) + - The PPD conformance tests did not catch group + translation strings that exceeded the maximum allowed + size (STR #454) + - Updated the client code in the scheduler to close the + client connection on errors rather than shutting down + the receive end of the socket; this caused resource + problems on some systems (STR #434) + - cups-polld didn't compile on Tru64 5.1B (STR #436) + - "lpc stat" crashed if the device URI was empty (STR + #548) + - The scheduler did not compile without zlib (STR #433) + - std:floor() cast needed on IRIX 6.5 with SGI C++ + compiler (STR #497) + - cupsRasterReadPixels() and cupsRasterWritePixels() did + not handle EAGAIN and EINTR properly (STR #473) + - RequiresPageRegion should not be consulted for Manual + Feed (STR #514) + - International characters were not substituted in + banner files properly (STR #468) + - Updated pdftops to Xpdf 2.03 code to fix printing bugs + (STR #470) + - The Digest authentication code did not include the + (required) "uri" attribute in the Authorization + response, preventing interoperation with Apache + (STR #408) + - The web interface could lockup when displaying certain + URLs (STR #459) + - The PostScript filters now convert underscores ("_") + to spaces for custom classification names (STR #555) + + +CHANGES IN CUPS V1.1.20 + + - The pstops filter didn't properly handle collated, + duplexed copies of documents with an odd number of + pages on printers that did not do their own collated + copies (STR #389) + - Tru64 doesn't define a prototype for hstrerror() (STR + #430) + - Updated the pdftops filter to use the annotation flags + instead of the subtype to determine whether to print + an annotation (STR #425) + - The French web interface localization did not use + absolute paths for the navigation bar (STR #428) + - The CUPS test suite did not undefine the PRINTER and + LPDEST environment variables. This could lead to bogus + test results (STR #380) + - The cupsLangDefault() function now works if you don't + have the base OS localization installed (STR #418) + - The pdftops filter no longer needs to create temporary + files with tmpnam (STR #406) + - The HTTP code did not use a case-insensitive + comparison when checking for the Basic authentication + method (STR #407) + - The httpEncode() function always added a trailing "=" + character, which is not required by the Base64 + encoding specification (STR #407) + - The signal handlers did not need to call sigset(); + this caused a recursion problem on some versions of + IRIX (STR #422) + - Moved the scheduler termination code into the mainline + to be consistent with the way other signals are + handled (STR #423) + - The cupsaddsmb program didn't export the new CUPS + driver for Windows properly (STR #390) + - The ppdOpen() functions did not issue an error when a + translation string exceeded the maximum allowed by the + Adobe PPD specification (STR #399) + - The default landscape orientation was not the same as + that defined in the PPD file (STR #397) + - Updated the pstoraster patch files and CUPS driver to + work with Ghostscript 8 (STR #402) + - The hpgltops filter did not skip PJL commands (STR + #379) + + +CHANGES IN CUPS V1.1.20rc6 + + - "lp -i jobid -H restart" would often return an error + even though the job restarted successfully (STR #362) + - The scheduler did not check for invalid allow/deny + addresses such as "11.22.33.44/24". It now masks off + the extra address bits and logs a warning message in + the error_log file (STR #337) + - The cupstestppd utility now checks for missing + ImageableArea and PaperDimension attributes for each + defined PageSize (STR #365) + - The IPP code did not wait for a reply indefinitely on + HTTP connections in "blocking" mode (STR #377) + - The web interfaces did not rewrite the default printer + URI properly (STR #299 and #369) + - The LPD backend passed the C and L commands in the + wrong order (STR #378) + - The Dymo label printer driver did not set the label + length properly (STR #373) + - The scheduler did not support job IDs higher than + 99999 (STR #371) + - The Visual C++ project files did not work (STR #366) + - The scheduler's cupsLangSeek() function did not reset + the "EOF" flag, preventing compressed files from being + typed properly in some cases (STR #368) + - The cupsLangGet() cache was only used if the locale + name provided an explicit character set name (STR + #354) + - The CUPS API convenience functions did not call + cupsLangFree() when they were done with the + localization data (STR #354) + - The scheduler did not return the + job-hold-until-supported or job-hold-until-default + attributes (STR #356) + - The cupsaddsmb program did not support the new CUPS + driver for Windows (STR #357) + + +CHANGES IN CUPS V1.1.20rc5 + + - The scheduler did not initialize the browse socket + file descriptor properly when only SLP browsing was + enabled (STR #259) + - The scheduler accessed the job attributes before they + were set (STR #347, fix to STR #335) + - The cupsCancelJob() function did not return 0 when the + job could not be canceled (STR #340) + + +CHANGES IN CUPS V1.1.20rc4 + + - The scheduler did not move the incoming job attributes + in the operation group to the job group (STR #335) + - The cupsDoFileRequest() function did not check for an + early HTTP response while sending the file (STR #314) + - The web interfaces did not quote #, ?, or . in printer + names, which caused some problems with the generated + URLs (STR #320) + - CUPS couldn't be completely compiled with the -dDEBUG + option (STR #331) + + +CHANGES IN CUPS V1.1.20rc3 + + - More SLP changes (STR #259) + - Revamped the child signal handling code to completely + avoid deadlock issues on Solaris (STR #325) + - The lpadmin command displayed an incorrect error + message when the "-u" option was provided with no + arguments (STR #313) + - The web admin interface did not display an error + message if the PPD file could not be loaded (STR #308) + - The ppdEmit() functions did not use the correct + orientation value position for custom page sizes (STR + #292) + + +CHANGES IN CUPS V1.1.20rc2 + + - The serial backend set the IXANY option on the port + for XON/XOFF flow control; this caused problems with + printers that returned status info but were not ready + for more print data (STR #287) + - The scheduler didn't support scripted index files + (index.php, index.pl, etc. - STR #290) + - The scheduler did not correctly localize script files + with "GET" variables (STR #268) + - Changes in job classification are now logged (STR + #289) + - Fixed a few more SLP-related bugs (STR #259) + - Updated the user/group configure checks for MacOS X + 10.3 (STR #270) + - Fixed an offset bug in the PDF filter (STR #284) + - The cupsDoRequest() and cupsDoFileRequest() functions + did not map several HTTP status codes to their IPP + counterparts. This made detecting certain conditions + very difficult (STR #277) + - Config, spool, and status files are now owned by the + scheduler user (usually root) with read permission for + the filter group (STR #283) + - The HP-GL/2 filter did not support the SI command, + some values for the AD and SD commands, and did not + rotate labels properly via the DI command (STR #282) + - The fax support did not update/set the job-hold-until + attribute when a fax job fails (STR #269) + - The cupsLangGet() function didn't support locales of + the form "ll.charset" (STR #271) + - The scheduler did not use the charset when getting the + language localization for a request; this caused extra + disk IO for every request (STR #271) + - The scheduler did not support requests with more than + one language specified (STR #267) + + +CHANGES IN CUPS V1.1.20rc1 + + - The scheduler now waits up to 60 seconds before + restarting to allow active jobs to complete printing + and pending requests to be processed (STR #226) + - The web interface did not work on systems where time_t + is 64 bits (STR #262) + - Added backend tweeks and content-length check from Red + Hat (STR #253) + - The USB backend now uses the 8255 constants instead of + the standard constants when reporting printer status + bits on Linux (STR #254) + - Added new cupsDoAuthentication(), cupsGetFd(), + cupsGetFile(), cupsPutFd(), and cupsPutFile() functions + to the CUPS API (STR #112) + - The PDF filter always scaled and offset pages; this + caused problems under MacOS X, so now the "fitplot" + option controls whether PDF files are scaled to fit + within the printable area of the page (STR #250) + - The LPD backend did not support the port number in a + URI (STR #247) + - Some filters didn't properly support boolean options + (STR #249) + - Landscape PDF files were not always offset by the + correct amount when rotating (STR #243) + - The scheduler could hang in a call to localtime() when + logging messages from the signal handler (STR #242) + - The PDF filter no longer prints form widgets; this + duplicates the behavior of Acrobat Reader (STR #241) + - cupsGetPPD() didn't handle a late termination of a + HTTP connection with the server (STR #220) + - ppdOpen() did not correctly check for "*PPD-Adobe-4." + on the first line of a PPD file. This caused incorrect + PASS results for some PPD files (STR #233) + - cupsEncodeOptions() did not allow boolean options to + use "yes" and "on" for true values (STR #227) + - The pstops filter only sent the TBCP exit sequence if + it was defined in the JCLEnd attribute in the PPD file + (STR #224) + - Support for more than 1024 files was broken on Solaris + 9 (STR #217) + - The setgroups() calls now pass in 1 group (the + configured group) instead of 0 for compatibility with + BSD and Darwin (STR #213) + - The scheduler's built-in broadcast throttling was + ineffective since incoming packets would cause the + next group of outgoing packets to be sent immediately + rather than waiting for the next time slot (STR #211) + - Added a new ppdSetConformance() function to set the + conformance requirements for PPD files. Currently only + two levels are defined, PPD_CONFORM_RELAXED and + PPD_CONFORM_STRICT, and the default is the relaxed + level (STR #212) + - The IPP backend did not correctly execute the + pictwpstops filter on OSX (STR #210) + - The LPD backend did not set the banner class when the + "banner=yes" option was specified in the device URI + (STR #209) + - The imagetoraster filter did not support all of the + page device attributes (STR #208) + - The pdftops filter incorrectly auto-rotated pages when + the user already had specified the proper orientation + (STR #207) + - Fixed AIX shared library support (STR #201) + - Added support for live testing with Valgrind (STR + #193) + - The CGI programs now collect the list of needed + attributes for the class, job, and printer template + files (STR #192) + - The scheduler now passes the first port that is bound + to the local loopback or "any" addresses to the CGI + programs rather than the port that the browser + connected to (STR #103) + - The cupstestppd program now checks for bad + JobPatchFile attributes and incorrect versions of the + Manufacturer attribute for HP printers (STR #155) + - The filter makefile incorrectly installed + libcupsimage.a in the filter directory (STR #180) + - The scheduler did not verify that the job history + files define the job-priority and + job-originating-user-name attributes (STR #178) + - The pstops filter didn't handle poorly-formed binary + PostScript files that had CTRL-D's in them (STR #156) + - The ppdOpen*() and cupsLangGet() functions did not + make a copy of the old locale strings when using the + POSIX locale when reading files, which apparently + caused problems with some implementations of the + standard C library. (STR #159) + - The pdftops filter did not work properly with some + embedded Type1C fonts (STR #177) + - Updated the pdftops filter to be based upon Xpdf + 2.02pl1 (STR #191) + - The scheduler did not reset the group list when + running CGI and filter processes (STR #185) + - The scheduler no longer calls malloc and free from the + signal handlers (STR #190) + - The USB backend now uses the manufacturer and model + strings if the description string is not available + (STR #174) + - The ppdOpen functions still supported the + VariablePaperSize attribute, which was removed in v4.0 + of the PPD spec. This caused problems with PPD files + that relocated the PageSize option to a non-standard + group (STR #158) + - The cups.list file referenced MAN1EXT, MAN3EXT, and + MAN5EXT, but none of those were actually defined (STR + #147) + - Chunked requests could cause a Denial of Service if + the connection is terminated before the first byte of + chunk data is sent/received (STR #143) + - Printers with special characters in their names were + not accessible from the web interface (STR #120) + - The lpstat command now shows the correct interface + script or PPD file, if any, for a print queue (STR #89) + - The lpstat command now shows the printer-state-message + and printer-state-reasons attributes whenever they are + not blank (STR #152) + - The French and German option-conflict.tmpl template + files did not get installed (STR #148) + - The cups.list.in file did not work when compiling + without shared libraries (STR #149) + - The DSOFLAGS included the LDFLAGS, which causes + problems on at least HP-UX (STR #150) + - The fax printer support did not keep track of the fax + capability bit (STR #144) + - The appleLangDefault() function could leak a small + amount of memory (STR #145) + - The ppdOpen() functions now mirror all normal + attributes to the attribute list; previously only + certain unassigned attributes would be added (STR + #139) + - The ppdEmitJCL() function wrote JCL commands to stdout + instead of the passed file pointer (STR #142) + - The httpGets() function could, in certain states, + block waiting for data (STR #132) + - The cupsEmitJCL() function not outputs an empty @PJL + command after the PJL language escape to work around + bugs in certain PJL implementations (STR #131) + - The cupsEmit*() functions didn't set the orientation + value properly (STR #127) + - The cups.spec file didn't list the rc2.d init + directory or the cupstestppd file (STR #134) + + +CHANGES IN CUPS V1.1.19 + + - The GNU TLS code incorrectly used + gnutls_check_pending() instead of + gnutls_record_check_pending() (STR #128) + - The ppdEmit() functions output "PageSize Custom" + instead of "CustomPageSize True" in the DSC comments. + Also, the custom page size code did not use the + ParamCustomPageSize attributes (STR #127) + - The cupstestppd command did not list the conflicting + options (STR #123) + - The lpq command did not ensure that there was + whitespace between the fields in the job listing (STR + #117) + - The German web templates had errors (STR #119) + - The configure script didn't specify the static + libraries properly when configuring with the + --disable-shared option (STR #104) + - The cups.list file used file dependencies for package + formats other than portable, RPM, and Debian (STR #98) + - cupsLangGet() didn't use its language cache (STR #97) + - "lpq -P" would segfault instead of showing a usage + message (STR #94) + - Fixed compiler warnings in pdftops filter (STR #96) + + +CHANGES IN CUPS V1.1.19rc5 + + - Jobs with banner pages that were printed to implicit + classes would get double banner pages for each + file/banner in the job (STR #68) + - The mime.convs file was missing the filter definition + for Windows BMP (image/x-bitmap) files (STR #85) + - The scheduler allowed some READ-ONLY job attributes to + be set, which could cause the scheduler to fail on the + next restart (STR #82) + - The lp and lpr commands did not report when the + scheduler was not responding; instead, the user would + incorrectly see a "no default destination" error (STR + #70) + - cupsLangGet() could fail on OSX due to a corrupt + language preference (STR #78) + - Added more checks for HTTP request timeouts. + - The scheduler dropped the first non-alpha character + after an open brace when doing attribute substitutions + in banner pages (STR #77) + - The scheduler child might send SIGUSR1 to the parent + before the signal handler was installed; this didn't + prevent the scheduler from starting but produced an + annoying error message (STR #45) + + +CHANGES IN CUPS V1.1.19rc4 + + - The lp command did not accept "-" for printing from + the standard input as required by POSIX 1003.1 (STR + #59) + - Added the job-originating-host-name information for + the page_log file documentation in the SAM (STR #31) + - The German web interface templates did not use the + right paths for job operations (STR #54) + - The scheduler would consume all available CPU if + started with a pending job in the queue (STR #35) + - The polling daemon allocated an extra localization + buffer but did not free it, causing cups-polld to + eventually use all available memory (STR #40) + + +CHANGES IN CUPS V1.1.19rc3 + + - The scheduler could get in an infinite loop cancelling + jobs using "cancel -u user dest" (STR #48) + - The "cancel -u user" command did nothing (it should + cancel all jobs on all printers owned by the named + user - STR #48) + - The scheduler would write 0-length job control files + (STR #46) + - Updated the French man pages (translation provided by + Gilles QUERRET) + - The scheduler would delete all printers from + printers.conf if a job was active when a HUP signal + was handled (STR #47) + - The cups-polld program would leak memory if it was + unable to send browse packets to the loopback + interface (STR #40) + - The scheduler did not put the + job-originating-host-name attribute in the job + attributes group. + - The text filter did not default to wrapping text as + defined by the IPP implementation document. + - Scan backends first, PPDs second (STR #37) + - Updated the Netatalk documentation in the SAM (STR #38 + and #39) + - The test suite sent text files to a non-PS print queue, + which requires ESP Ghostscript (provided separately). + Now send the JPEG test file (STR #33) + - The test suite did not show the estimated disk space + requirements (STR #33) + - The test suite did not set the MaxLogSize directive to + 0 to prevent log file rotation (STR #33) + - The test suite still setup the old CUPS Ghostscript + symlinks (STR #33) + - The pstops filter did not report the correct number of + copies for the page_log file when printing collated + copies to a printer that doesn't support them in + hardware (STR #32) + - cupsLangGet() needs to set the CTYPE locale to "C" + (POSIX) to avoid erroneous tolower/toupper values (fix + suggested by Bjoern Jacke) + - Fixed a typo in the cups.list.in file. + - Updated all of the Western European locales to default + to ISO-8859-15 (for Euro support, suggested by Bjoern + Jacke) + - Updated the German message catalog (update provided by + Bjoern Jacke) + + +CHANGES IN CUPS V1.1.19rc2 + + - cupsLangGet() now sets the encoding field based on the + trailing charset in the locale name, and doesn't look + for a message catalog in a specific locale.charset + directory. This fixes STR #26 and is more in line + with the CUPS 1.2 implementation. + - The configure script now aborts if the "ar" command or + compilers cannot be found. + - The static cupsimage library was not built by default. + - The path for the "ln" command was hardcoded in + Makedefs.in instead of being checked at configure time + (STR #28). + - Banner pages containing unescaped { characters would + not work. + - The printer-state-time collection attribute was + encoded as an enumeration instead of an integer. + - The printer-is-accepting-jobs collection attribute was + was not added to the collection value. + - The printer-state-sequence-number collection attribute + was not added to the collection value. + - Fixed typo and const mismatch in IPP backend. + - Updated the man pages for the new configuration + directives. + - Updated the SAM for MacOS 10.2, the CUPS drivers for + windows, the available LPD backend options, and the + new configuration directives. + - The imagetops filter didn't position images properly + on the page (STR #18) + - The configure script didn't add CPPFLAGS to the + compiler options or LDFLAGS to the DSO options (STR + #13) + - The scheduler would try to write a debug log message + when starting a job that contained a NULL string. + Since not all versions of snprintf() support NULL + string pointers this caused some problems (STR #20) + - The testipp program now supports reading of IPP + message files such as those used for the job history + in /var/spool/cups. + + +CHANGES IN CUPS V1.1.19rc1 + + - Added CUPS support files for Java, Perl, and PHP + (located in the "scripting" subdirectory...) + - The scheduler now supports fast-reloads of the + cupsd.conf file when it is updated via HTTP. + - The scheduler always changed the ownership of log + files; it now only does so if they are not in the /dev + directory (i.e. don't want to change the ownership and + permissions of /dev/null...) + - Added libpaper support (patch from Jeff Licquia) + - Added a new istring() rule for MIME types files that + does a case-insensitive comparison of strings. + - The cups-lpd mini-daemon now sends jobs to the default + queue when an empty queue name (or "lp" and there is + no "lp" queue) is sent. + - The scheduler now supports fax queues identified by a + "*cupsFax: True" attribute in the PPD file. When a job + can't be sent, it is held for 5 minutes by default + while other jobs are attempted. The FaxRetryLimit and + FaxRetryInterval directives control the number of + retries and the time between retries. + - The scheduler now preserves the default options of PPD + files when modifying/upgrading an existing PPD file. + When installing a new printer, the scheduler sets the + default media size to Letter or A4 as appropriate for + your locale. + - The scheduler no longer limits the number of + BrowseAddress, BrowsePoll, BrowseRelay, Listen, Port, + SSLListen, and SSLPort directives to 10. + - The scheduler now supports print files that have been + compressed using gzip. + - The scheduler used the stdio functions to read any job + ticket information in a PostScript print job. Since + some platforms limit the number of stdio files to 256, + job ticket information was ignored when the server had + a large number of clients connected to the system. + - Filters and backends may now report the total number + of pages ("PAGE: total NNN") to the scheduler. + - The LPD backend now supports timeout and + sanitize_title options (default to 300 and yes, + respectively) and has some additional changes to + reduce the chances of multiple copies being printed + when only one copy was requested. + - Fixed a polygon drawing bug in the HP-GL/2 filter. + - Added a robots.txt file to the standard install to + prevent search engines from indexing the CUPS server. + - Added support for STATE: messages + (printer-state-reasons), printer-state-history, and + printer-state-time to the scheduler. + - When using RunAsUser, the scheduler would initially + start any previously queued (pending) jobs with + RunAsUser disabled - all backends would be running as + root. + - If a backend failed for a printer, CUPS would + incorrectly requeue the job for printing again. + - Added support for IPP collections and files. + - Added experimental support for generic CGI scripts and + programs, Java, Perl, PHP, and Python to the + scheduler. See the file "CGI.txt" for more + information. + - The CUPS API now supports HTTP cookies and the Expect: + field. + - The cancel command now correctly supports the "-u + user" option to cancel all jobs for the named user. + - The Purge-Jobs operation now supports the my-jobs + boolean attribute and a new purge-jobs boolean + attribute to control whether job history data is + purged from the scheduler; the default is false for + my-jobs and true for purge-jobs to match the original + implementation. + - The scheduler would not timeout printers when only + using SLP browsing. + - If the scheduler was unable to execute a filter, it + would try to restart the job indefinitely until the + filter could be executed. + - When writing BSD printcap files, the scheduler now + includes the rm and rp attributes, allowing the file + to be exported to LPD clients. [Patch from Dominic + Kubla] + - The scheduler optimization to reference IPP attribute + data instead of performing a full copy caused problems + when the referenced data was deleted before it was + sent. It now only references attributes that change + only when the scheduler is restarted. The change also + reduced the memory footprint of a printer object to + 2k. + - The scheduler now holds signals while logging messages + to avoid potential deadlock issues when handling + signals on Solaris 8. + - The lpadmin command now allows printer access control + by group name as well as user name. + - "lpoptions -l" got in an infinite loop if no default + printer was available. + - The scheduler now logs the job-originating-host-name + attribute in the page_log file, and uses "-" for any + empty fields (patch from Dominik Kubla). + - The pdftops filter now scales PDF pages within the + printable area of the page. + - The pstops filter didn't include the page-label and + classification boxes when printing EPS or non- + conformant PS files. + - The imagetops filter didn't always correctly position + the image on the page when printing in landscape + orientation. + - The ppdEmit() functions now support the + RequiresPageRegion attribute when sending InputSlot + and ManualFeed commands. + - The PPD loading code now supports standard options + outside of OpenUI/CloseUI as required by the PPD spec. + - The cupstestppd program has been upgraded to provide a + concise PASS/FAIL report, additional detailed + conformance testing, and support for gzip'd PPD files. + - The PPD loading code is now much more strict when + loading a PPD file, and tracks more format errors. + - The scheduler ignored child signals when gathering the + list of available devices, when it should have been + using the default signal handler. + - The cupsEncodeOptions() function could encode an + option with a NULL last string. + - The socket backend could report the wrong number of + backchannel bytes if an error occurred on the link. + - The cups-polld program now only sleeps after getting + all printers and classes. This allows for longer + intervals without excessive delays before classes show + up... + - Added a new httpWait() function to support waiting for + data for a specific number of milliseconds. + - httpGets() now times out after 1 second on + non-blocking HTTP connections. + - The scheduler no longer accepts rangeOfInteger values + that are out of order (e.g. 5-1) + - The sides attribute was incorrectly sent as a name + value; it is a keyword value. + - The IPP backend now detects if the destination queue + has gone away and reports an error. + - The scheduler and HTTP API now allocate their select() + sets to support larger numbers of clients on systems + that support it. + - The scheduler now sets the CFProcessPath environment + variable under MacOS X. + - The cupsLangDefault() function now uses the + CoreFoundation localization API under MacOS X. + - The httpSeparate() function didn't handle file URIs of + the form "file:///path" properly. + - The lpadmin command now supports a "protocol" option + for specifying the binary communications protocol to + use when printing binary PostScript data. + - The scheduler did not properly parse the SystemGroup + directive, so only the first group would be used. + - Revamped how strings are stored in the scheduler, + providing a substantial improvement in memory usage + for systems with large numbers of printers. + - The PostScript filter now supports binary PostScript + files and files beginning with the PJL language escape + sequence. + - The PPD API now provides additional information from + the PPD file. + - The USB backend didn't compile on Solaris Intel. + - The cupstestppd utility now supports the "-q" option + (quiet) for use in scripts, etc. + - Merged several weight-reducing changes into the CUPS + baseline donated by Apple. + - Added preliminary support for CDSA; patch provided by + Apple. + - Implicit classes are now created from identical + printer classes on the network. + - The lp command now supports a "-H restart" option to + restart previously printed jobs. This functionality + only works if you have enabled the PreserveJobFiles + option. + - The scheduler now supports URIs in HTTP request lines + to conform to the HTTP/1.1 specification. + - The time-at-xyz attributes were not recognized in + banner files if prefixed by a question mark, e.g. + "{?time-at-creation}". + - Added support for pre-filtering application/pictwps + files on MacOS clients before sending them to a server + via IPP. + - The scheduler now allows file:/dev/null device URIs + even if FileDevices is set to No. + - CUPS uses strerror() for hostname resolution errors, + when it should have used hstrerror(). + - The USB backend no longer tries to guess the serial + number of a device from the USB devices file; this + means that printers that don't report their serial + numbers in the device ID string will not be + individually selectable. + - The pstops filter didn't handle page ranges properly + when a page contained an embedded document. + - Added a translation of the web interface to German. + - When printing using the OutputOrder=Reverse option + with duplexing, the output order is now truly + reversed; the order of sub-pages when printing N-up is + the same. + - The pstops filter did not always output the extra + blank page when printing a document with an odd number + of pages with duplexing enabled. + - The ippAddXYZ functions no longer allow the + application to add less than 1 value. + - Fixed a URL rewrite bug in the web interface - local + access was sometimes redirected away from localhost... + - The ppdOpen() functions could get in an infinite loop + if the PPD file contained a keyword or text that was + too large for the buffer. + - Added preliminary support for GNU TLS; patch provided + by Jeff Licquia. + - Now timeout IPP attribute reads after 1 second inside + an attribute definition. + - Now timeout connections that have been shutdown (due + to errors) after 30 seconds instead of the Timeout + setting (300 seconds by default). This provides + faster recovery from DoS attacks. + - A denial-of-service attack warning message was being + written to the log files by the scheduler for every + detection. This caused a DoS of its own in some + situations. The warning message is now written no more + than once per minute. + - Fixed the CIE colorspace support code in the image and + PS RIPs. + - The job-quota-period, job-page-limit, and job-k-limit + attributes were not flagged as integers, so setting + quotas would not work. + - Added an additional response check in the scheduler to + more quickly recover from denial-of-service attacks. + - The cupstestppd file was incorrectly installed in the + /usr/sbin directory instead of /usr/bin. + - The EPM list file did not include the cupstestppd + program or man page files. + + +CHANGES IN CUPS V1.1.18 + + - Fixed a bug in the Set-Job-Attributes code in the + scheduler that would cause it to crash or continuously + write a job control file. + - SECURITY FIX: The scheduler now provides a FileDevice + directive to control whether new printers can be added + using device URIs of the form "file:/filename". The + default is to not allow printers with these device + URIs. + - The scheduler did not compute the cost of filters + properly, nor did it choose a multi-filter solution + with a lower cost than a single filter solution. + - Now install CUPS PPD file test utility (cupstestppd) + to support basic conformance testing of PPD files. + - The scheduler now logs an error message when it sees a + non-conforming PPD file. + - Upgraded pdftops filter to Xpdf 2.01 with fixes for + TrueType fonts. + - Added a MaxClientsPerHost configuration directive to + provide limited protection against Denial of Service + attacks. + - SECURITY FIX: Potential underflow/overflow bug in web + interface. + - SECURITY FIX: Race condition in certificate creation. + - SECURITY FIX: Bad URIs in browse packets could be used + to exploint the web interface underflow/overflow bug. + - SECURITY FIX: Some types of Denial of Service attacks + were not handled properly, so once the attack was over + the scheduler did not close the connections + immediately on all platforms. + - SECURITY FIXES: Added integer overflow/underflow + checks for all image formats. + - The pstops filter didn't reset the showpage operator + back to its original at the end of a job; this + prevented the concatenation of documents (used + primarily for CUPS 1.2...) + - The cupsGetPPD() function didn't always set the + cupsLastError() value when an error occurred. + - The IPP media, output-bin, and sides attributes took + precedence over the corresponding PPD options, which + caused inconsistent behavior under MacOS X with some + PPD files. + - The cupsaddsmb utility specified the wrong number of + arguments to the adddriver command when adding the + Win9x PostScript drivers. + - The web interface did not always report the correct + error message. + - The scheduler did not clear the POSIX signal action + structure when waiting for the child to send it a + SIGUSR1 signal; this could cause the signal handler + not to be called properly, preventing the parent + process from returning. + + +CHANGES IN CUPS V1.1.17 + + - The "manual_copies" option did not work when the LPD + backend had to retry a print job. + - The image filters did not convert GIF images properly. + - The RunAsUser option was incompatible with the new + daemon-mode code in 1.1.16. + - Fixed a problem with the Set-Job-Attributes and + PostScript job ticket code in the scheduler - the + "last" attribute pointer was never updated, which + could cause the scheduler to crash when applying job + ticket data. + - Fixed a problem in the scheduler that caused it to + continue processing HTTP requests on a connection + after it was shutdown. + - The scheduler now allows accounts authenticated via + PAM to not have a corresponding UNIX account, but + group membership still requires the account name to be + listed in the UNIX group file(s)... + - The scheduler used a fixed-size (16k) buffer for + encoding job options for filters; it now dynamically + allocates and expands the buffer as needed depending + on the options that are sent in a job. + - The pdftops filter didn't support all of the MacOS + characters for MacRoman encoded fonts. + - The cupsEncodeOptions() and cupsParseOptions() + functions now conform to the grammer defined by the + current draft of the PAPI specification. The main + difference is that option=yes and option=no are no + longer treated as boolean options. + - The IPP backend didn't honor the encryption settings + in /etc/cups/client.conf. + - Fixed a potential bug in the HTTP code which was + caused by servers sending the status line and + newline(s) in separate packets. + - User-defined classification strings are now printed + verbatim - previously the classification box would be + empty. + - Re-added Spanish to the list of PPD languages that + CUPS supports. + - CUPS API library user and temp file updates for + Windows. + - The image filters did not properly handle grayscale + printing of Sun Raster images. + - The scheduler never reset the NumJobs variable before + loading the job list (previously this only happened on + a full start, so the problem was never apparent...) + - The HTTP and IPP read/write code didn't handle EINTR + (interrupted system call) errors. + - When under high load, the scheduler could abort due to + the wrong errno value after a select() call. This was + caused by the child signal handler. + - Added new load tests to the test target to verify that + cupsd can handle hundreds of simultaneous jobs without + error. + - The Solaris USB backend now supports the new device + URI syntax. + - The ppdOpen*() functions now reset the numeric locale + settings while loading a PPD file. + - Fixed the libtool build rules. + - The manpage make rules didn't use $(MAKE) and + $(MFLAGS) for the language subdirectories. + - Now set the LC_TIME locale category to get the + properly localized time string. + - Fixed a problem in the scheduler that would cause the + web interface problems when adding, modifying, or + configuring a printer or class. + - The backends now ignore SIGPIPE so that failed job + filters will not stop a print queue. + - The lpstat command did not allow for destination lists + ("lpstat -v printer1,printer2") + - Fixed parsing of long filter status messages in the + scheduler. + - Added some startup performance enhancements to the + scheduler so that the printer object information is + regenerated fewer times and the MIME type database is + not filled with lots of empty filters for raw/direct + queues. + - The LPD backend now sends the job title as the print + filename. + - Added support for variable sizes in the EPSON dot + matrix printer drivers. This allows for pages as + short as 1/2" (1 row of labels) and does not do an + automatic form feed. + - French translation updates. + - The filters did not quote the page label string when + embedding it in PostScript output. + - The serial backend now enumerates serial ports under + MacOS X. + - The pdftops filter contained font rasterizer code that + wasn't being used and that depended on X11. This code + has been removed. + + +CHANGES IN CUPS V1.1.16 + + - The cancel and lprm commands now both display an error + message and return a non-zero exit status if an + attempt is made to cancel a job on a non-existent + printer. + - The lpoptions command incorrectly complained if a + request to delete a non-existent printer was made. + - If the client.conf file defines an alternate server + name, the "configure printer" action in the web + interface might not work. + - The lpstat command now supports a "-W" option so that + you can display completed jobs as well as + not-completed (pending) jobs. + - The lp and lpr commands did not return an error when + one or more files in a set of files for printing could + not be printed. + - The lp, lpadmin, and lpstat commands now consistently + return with a non-zero exit status when an error + occurs. + - The scheduler would not accept print jobs sent to a + stopped remote printer. + - The texttops filter incorrectly converted the page + numbers in the prettyprint header to double-byte + characters when printing a non-Unicode text file. This + caused an extra space to appear between each digit in + the page number. + - The scheduler did not use a case-insensitive + comparison when adding filters for a printer. + - Upgraded the pdftops filter to Xpdf 1.01. + - The scheduler no longer passes the page-border and + number-up-layout attributes to filters when printing + banner pages. + - The LPD backend now uses a 30-second timeout when + sending commands and control files, and a 30-second + timeout when retrieving responses from an LPD server. + If a timeout occurs, it retries indefinitely. This + helps to make LPD printing over VPNs work more + reliably. + - The USB backend now supports device URIs based on the + printer serial number and/or model number under Linux. + This avoids the "wrong device filename" problem when + using more than one USB printer. + - Now just shutdown the receiving end of a client + connection when sending an error that requires the + server to disconnect from the client afterwards. This + fixes a problem when doing remote administration with + encryption enabled. + - The scheduler did not send a printer-state-message + attribute if the string was empty; it now always sends + this attribute. This caused the printer message to be + displayed for other printers in the web interface. + - The LPD backend now supports a "manual_copies" option, + e.g.: "lpd://server/queue?manual_copies=no", in order + to handle copies for raw jobs to printers that don't + implement the LPD protocol properly... + - The "mirror" option was not being handled by the + PostScript or image filters. + - Updated the cupsaddsmb command to support the new CUPS + driver for Windows NT/2k/XP. + - Filter status lines longer than 1023 characters could + cause the scheduler to get into an infinite loop. + - The scheduler didn't reset the job state to pending + when modifying an active printer. + - Now limit the maximum number of recursion steps when + searching for a filter for a job, in case a user + defines a circular filter rule. + - The PostScript filter would embed an invalid + requirements comment in some cases. + - Added support for embedded job tickets in PostScript + files. + - The PostScript filter now detects EPS files and should + better handle printing EPS files. + - The cancel command now ignores a trailing destination + name when cancelling a specific job ID (Solaris + compatibility). + - The scheduler now rejects jobs with copies outside the + range of 1 to MaxCopies, inclusive. + - Added new MaxCopies directive to set the maximum + number of copies that a user can request. + - The scheduler didn't block signals while it processed + others and when it forked processes. + - The scheduler checked for new jobs to print when + stopping a job. This caused jobs to restart before a + shutdown. + - Updated the CUPS startup script to better support + different timezones and to support the RedHat/Mandrake + init script functions, if available. + - The scheduler did not properly handle backslashes in + banner files; it incorrectly assumed that "\c" should + always be replaced by "c", instead of only looking for + "\{" and replacing it by "{". + - The texttops filter didn't handle prettyprint=no. + - The text and HP-GL/2 filters didn't check for other + common duplex option names like cupsMarkOptions() did. + - "lpoptions -x printer" no longer clears the "default + printer" status of the printer. + - cupsTempFd() now stops trying to create a temporary + file after 1000 tries, and aborts on any error other + than EEXIST. This should prevent lp/lpr hangs due to + a bad or missing temporary directory. + - The lpadmin command did not send the right URI to the + scheduler when setting options on classes. This + caused a client-error-bad-request error. + - The CUPS API convenience functions would attempt to + connect to the remote server name in a + "printer@server" printer name instead of dealing with + the default (usually local) server. Aside from + causing user confusion, the remote server name might + not be resolved properly, causing further problems. + - "lp -q" would cause the "lp" command to segfault, as + the program would try to print the option letter that + caused the error using the wrong index into the + command-line; bugfix from Debian. + - Fixed a minor inconsistancy in the encoding of boolean + attributes from printer options in + cupsEncodeOptions(). + - Added a FilterNice directive which sets the priority + of job filter processes that are run by the scheduler. + - Added Solaris x86 USB printer support. + - The USB backend now reports both the ulpt and unlpt + devices under *BSD. + - The "lpstat -o" command would truncate the + "printer-jobid" string if it was longer than 21 + characters. + - The PJL-based MIME type rules now look in the first + 1024 bytes instead of just the first 512 bytes to find + the language mode. + - The image file types are now listed explicitly in the + mime.convs file so that additional image file formats + do not use the standard CUPS image filters by default. + - Updated the Software Programmers Manual to include + all of the CUPS API functions. + - ppdOpen*() no longer sorts choices for an option. + - The web interface now enforces constraints in PPD + files when configuring a printer. + - When stopping a printer, the scheduler didn't set the + printer state before stopping the current job. + - The cupsaddsmb utility now lists all data files for + Win9x and WinMe clients when installing that Windows + driver. + - Jobs submitted to a class now bounce immediately to + the next available printer rather than waiting until + that printer is available. + - Filters and backends now also get the CLASS + environment variable set when a job is printed to a + printer class instead of a normal printer. + - Added French translations of the web interface, CUPS + Overview, Software Administrators Manual, and Software + Users Manual contributed by Marian REYT-LLABRES. + - Added several "hint" messages for common configuration + problems that are stored in the error_log file. + - httpSeparate() now unquotes %xx characters in the + username:password field of a URI. + - When starting the scheduler in daemon mode, the parent + process now waits for the child to signal it is ready + to accept connections. + - Added -F option to cupsd to run cupsd in the + foreground but detach from the controlling terminal + and current directory. + - The scheduler did not reload jobs when receiving a HUP + signal; this would cause problems since the pointers + into the file type database would no longer be valid + for existing jobs. + - The scheduler did not save the network interface list + update time, thus no caching of the network data was + actually provided. + - Updated the SuSE PAM configuration file. + - The LPD backend now supports a "reserve" option and no + longer reserves a priviledged port by default. + - The cupsaddsmb command now continues past printers + that do not have a PPD file to export. + - The lpstat command didn't treat printer names as + case-insensitive. + - The lpstat command now reports the printer location + attribute with "lpstat -l -p". + - Fixed a bug in the vsnprintf() emulation function, + which was used on old versions of HP-UX, IRIX, and + Solaris. + - The number-up option was incorrectly being used when + printing banner pages. + - Added support for Greek and Slovak PPD files. + - CUPS now supports printer names containing any + printable character, e.g. "123-abc", "foo-bar", etc. + - The null filter was not supported in mime.convs due to + a bug in the filter validation code. + - Changes in the default printer and printer attributes + were not always reflected in the generated printcap + file. + - Implicit classes did not inherit the location or + description from member printers. + - The httpGetHostByName() function did not handle + hostnames that started with a number. + - Updated the filters to use the %cupsRotation comment + instead of %%Orientation to auto-rotate pages, since + the use of %%Orientation is inconsistent. + - Added the RootCertDuration directive to control how + often the root authentication certificate is updated. + - Increased the size of the IPP write buffer to 32k to + allow for larger attribute values and to provide more + efficient output of large numbers of attributes. + - The polling daemon now retries the initial connection + to the remote server; this fixes a problem when the + remote server is unavailable when the scheduler starts + up... + - The scheduler didn't validate Digest users against the + system group(s), so Digest and BasicDigest + authentication didn't work for administration + operations. + - The scheduler now passes the SHLIB_PATH environment + variable to child processes (HP-UX shared libraries) + - The scheduler now maps accesses from the loopback + interface to "localhost". + - The cups-lpd mini-daemon sent a status code byte in + response to queue state commands, but those commands + only return textual data. + + +CHANGES IN CUPS V1.1.15-1 + + - The lpc and lprm sources didn't include the CUPS + string function header, which is required on systems + that don't have their own snprintf() function. + - The French manpage Makefile tried to install the + language subdirectories when it (obviously) didn't + have to. + + +CHANGES IN CUPS V1.1.15 + + - Updated the CUPS license agreement for the new MacOS + license exception. + - The printer-info attribute now defaults to the printer + name if no value has been set. + - ppdOpen() and friends now add an "Auto" InputSlot + option if none is provided to automatically select the + correct tray. + - Updated the ppdEmit() and ppdEmitFd() functions to + (re)mark the correct PageSize or PageRegion option + depending on the selected ManualFeed or InputSlot + options. + - ppdEmitFd() didn't handle custom page sizes. + - Darwin uses instead of + . + - The jobs.cgi web interface now handles all job + operations, allowing the administrator to allow "job + administrators" or operators to manage jobs (but not + queues) on the server. + - The cupsDoFileRequest() function now checks if the + filename passed into the function is a directory, and + returns the IPP_NOT_POSSIBLE error if so. + - New SCSI printer backend. + - Cleaned up handling of locales with trailing character + set definitions. + - Fixed handling of invalid PPD attributes inside + OpenUI/CloseUI. + - Fixed a problem with SSL and the job, printer, and + admin CGIs on ports other than 443. + - The scheduler didn't handle AuthClass properly. + - Added French translation of man pages. + - Updated the text filter to support the const_cast, + dynamic_cast, and static_cast keywords in ISO C++. + - Now use strlcat() and strlcpy() (or emulation + functions) for easier string/buffer protection. + - The auto-generated printcap/printers.conf files now + have a small comment header explaining where the file + comes from... + - The PostScript filter now supports 6, 9, and 16-up + output, as well as new page-border and + number-up-layout options. + - The lpoptions command didn't set options properly when + using the default printer. + - Added ConfigFilePerm and LogFilePerm directives. + - Increased maximum size of MIME types to IPP_MAX_NAME + to allow for longer printer names. + - No longer create remote printers when loading job + history data. + - The printer-make-and-model attribute wasn't set when + the PPD file didn't contain a NickName attribute. + - Now handle PPD files with translation strings longer + than 80 bytes - they are truncated if they go over... + - The scheduler didn't handle signals until after it + loaded the configuration files the first time; this + caused problems on some installations that would + restart the scheduler as the system booted into run + level 3. + - Now throttle broadcasts like we do for polling. + - Fixed a bug in the reading of PPD files using CR's + instead of CR LF's or LF's. + - The scheduler would crash if cupsd.conf contained a + BrowseProtocols line with no protocols listed. + - The HTML job operation templates now link back to the + destination printer or class. + - The serial backend now detects USB serial devices. + - The LPD mini-daemon (cups-lpd) now passes the + job-originating-host-name attribute to the scheduler + (cupsd). + - Updated the IPP backend to reconnect after downgrading + from IPP/1.1 to 1.0, and when sending requests to HP + JetDirect interfaces that don't support HTTP + Keep-Alive like they should. + - Now pass NLSPATH and DYLD_LIBRARY_PATH environment + variables, if defined, to CGI and job processes. + - Removed the pstoraster filter (based on GNU + Ghostscript 5.50) and now provide the raster "driver" + and patch file necessary to use the current GNU + Ghostscript 7.05 release. + - Removed unnecessary fonts and updated the Courier and + Symbol fonts to the latest versions to better support + non-ISOLatin1 text. + - The text filter now always embeds the Courier and + Symbol fonts to ensure that they contain the full set + of glyphs. + - The lp and lpr commands now only override the SIGINT + handler if it is not being ignored (patch from Robert + Ambrose for some interactive software that catches + SIGINT and will gracefully cancel the print...) + - The PostScript image filter (imagetops) now supports + printing CMYK images using the CMYK colorspace. + - The image filters now support CMYK JPEG files, and + correctly handles the inverted files from Photoshop + (which seems to save RGBW data, not CMYK...) + - Added a "check" target to the top-level makefile to + conform with GNU standards (same as "test"). + - The IPP code didn't always map the POSIX locale "C" to + the proper IPP language code. + - The cupsaddsmb program was updated to use the + setdriver command instead of addprinter. + - Banner pages were not handled properly for implicit + classes. + - When tunneling to a remote system using SSH, the + printer URIs for local printers on the remote system + did not reflect the correct port number. + - The Allow, Deny, BrowseAllow, BrowseDeny, and + BrowseAddress directives now support the network + interface names "@LOCAL" and "@IF(name)" for access + control and browsing based on the current interface + addresses instead of fixed names or IP addresses. + - The texttops filter did not properly recognize the + "nowrap" (wrap=false) option. + - The InstallableOptions group name in a PPD file is now + translated separately (CUPS_MSG_OPTIONS_INSTALLED) so + that UIs can accurately detect the presence of this + group. + - The scheduler no longer keeps job history data for + remote printers on the client (just on the server.) + - The parallel and USB backends now retry if the backend + detects that the printer is not connected to the + system (rather than stopping the queue...) + - The network backends now retry if the backend detects + that the printer is not connected to the network or is + unreachable (rather than stopping the queue...) + - The cupsGetDests() function no longer lists options + and instances for printers that no longer exist. + - The scheduler now converts the document language to + the correct LANG string. + - The cupsaddsmb program now supports alternative CUPS + and SAMBA server names. + - The PostScript filter now supports the Orientation + comment and rotates the page as needed automatically. + - Revamped the makefiles slightly to use automatically + generated dependencies. + - Build fixes for OS X. + - The TIFF reading code depended on the newest version + of libtiff; now conditionally compile that portion of + the loader. + - The PPD code now decodes all JCL options in the + JCLSetup group, not just those options that start with + the prefix "JCL". + - The backends now read print data using the read() + system call to ensure that the current page is printed + while the next page is being processed. + - The pdftops filter did not support shading type 3 + (radial fill) for the "sh" operator. + - The cups-polld program now throttles the local + broadcasts of polled printers and classes so that the + local system is not overwhelmed with hundreds of + printers and classes all at once. + - Updated the serial backend to support 230,400 baud for + the Linux PPC port. + - The cupsGetJobs() function wouldn't report completed + jobs that did not have a document-format attribute + value. + - The cupsEncodeOptions() function now maintains a table + of known boolean and numeric options, and encodes all + other options as strings. + - Now add a newline before the end-of-page code in the + PostScript filter; this fixes a problem with files + that don't end with a newline. + - The image filters looked for the "orientation" option + instead of the correctly named "orientation-requested" + option. + - The cupsEncodeOptions() function now handles mixed + integers and ranges. + - New translation guide for developers to provide native + language support for CUPS. + + +CHANGES IN CUPS V1.1.14 + + - The ippRead() function did not verify that the + attribute name length or string with language value + was not larger than the read buffer. + - The scheduler set the signal handlers before loading + the configuration files the first time; this prevented + the RunAsUser directive from blocking server reloads. + - Added Swedish message catalog. + - The parallel backend now recognizes the /dev/printers + device directory under Linux 2.4.x. + - MacOS X fixes. + - The cupsaddsmb utility sent the server name after the + user information when executing the rpcclient program. + This caused problems with some versions of SAMBA + 2.2.x. + - The IPP backend did not pass the requesting user name + when checking on the print job status. This prevented + it from waiting for the job to complete when + communicating with some IPP implementations that + require it. + + +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... + + +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 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 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. + + +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, Require, + Satisfy, , , and LimitRequestSize + 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 , 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. diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 000000000..b2e1670fc --- /dev/null +++ b/CHANGES.txt @@ -0,0 +1,286 @@ +CHANGES.txt - 01/12/2006 +------------------------ + +CHANGES IN CUPS V1.2.0b1 + + - The web interface now provides searching, paging, and + changing of the sort/display order of classes, jobs, + and printers. + - cupsaddsmb now accepts a password on the command-line + and supports passwords with special characters (STR + #822, STR #1236) + - ppdLoad*() no longer tries to "fix" bad characters in + UI text (STR #1101) + - Printer names can now (reliably) contain Unicode + characters (STR #896) + - The "lpstat -p" command now shows the time and date of + the last printer state change instead of the hardcoded + "Jan 01 00:00" (STR #659) + - The scheduler now adds a job-actual-printer-uri + attribute to job objects when printing to a class (STR + #116) + - The scheduler now logs log file open errors to the + system log (STR #1289) + - The scheduler now sets the job-originating-user-name to + the authenticated username, if available (STR #1318) + - The scheduler now only updates the permissions of SSL + keys and certificates when they are under the + ServerRoot directory (STR #1324) + - The rastertodymo driver has been renamed to + rastertolabel (a symlink is installed so that existing + queues continue to work) and now also supports Zebra's + CPCL language. + - The lpstat command could show the wrong active job for + a printer (STR #1301) + - Fixed a potential crash problem in the scheduler when + aborting a CGI program (STR #1290) + - Added a "cancel all jobs" button to the class and + printer web interfaces (STR #1140) + - The add-printer web page now shows the + set-printer-options page after the printer has been + added (STR #690) + - The classes web page now provides links to each of the + member printers (STR #307) + - CUPS now handles HTTP request/response lines up to 32k + in length; this is mainly for better cookie support + (STR #1274) + - Added support for the Apache PassEnv and SetEnv + directives to cupsd.conf (STR #853) + - Added large file (64-bit) support (STR #541) + - Fixed a performance issue with the ippReadIO() + implementation (STR #1284) + - Fixed a performance issue with the scheduler's implicit + class implementation (STR #1283) + - The pdftops filter now adds the Title and Creator + fields from the PDF file to the PostScript document + comments section (STR #539, STR #830) + - Added a new cups_array_t and cupsArray*() functions to + the CUPS API to support sorted lists of data. + - Made the CUPS API library thread-safe (STR #1276) + - Added "media" option support for EFI EFMediaType option + (STR #902) + - Added write buffering to the HTTP code to improve + performance (STR #547) + - The scheduler now uses the attributes-natural-language + attribute to localize banner pages (STR #386) + - The scheduler now returns the address that was used to + connect to it (STR #1076) + - Fixed a problem with N-up printing and OpenOffice (STR + #576) + - Added support for the GCC position independent + executable options (STR #1209) + - Added new BrowseLocalProtocols and + BrowseRemoteProtocols directives to cupsd.conf, + allowing for different browse protocols for local and + remote printers (STR #877) + - PPD files can now contain strings up to 256k in length + (STR #1215) + - The pstops filter now supports the IncludeFeature DSC + comment (STR #1212) + - The pstops filter now disables the setpagedevice + procedure when doing N-up printing (STR #1161) + - The serial backend now supports "stop=1", "stop=2", + "parity=space", and "parity=mark" options (STR #1155) + - "make install" no longer overwrites an existing PAM + configuration file (STR #1064) + - The scheduler now closes all files on startup when run + in daemon mode (STR #1009) + - Added a new RGBW colorspace to the CUPS raster format + (STR #1071) + - The pdftops filter now sets the page size based on the + media box when not scaling the output (STR #912) + - The pdftops filter now supports masked images (STR + #281) + - The pdftops filter produced large output when rendering + PDF files containing lot of repeated images (STR #327) + - The pdftops filter now minimizes print processing of + PDF files when using the page-ranges option (STR #273) + - Updated pdftops filter to Xpdf 3.01. + - Added new cupsBackchannelRead() and + cupsBackchannelWrite() functions, as well as + backchannel support to the parallel, serial, socket, + and USB backends (STR #1252) + - The parallel and USB backends now treat a "no space + available" error as an out-of-paper condition (STR + #1225) + - The "lpc" command now supports the "status all" command + (STR #1004) + - ippReadIO() did not read collections properly (STR + #1249) + - The "make test" script now creates the test files in + "/tmp/cups-$USER" instead of "/tmp/$USER" (STR #981) + - All backends now abort on error when printing a job to + a class - this allows the next printer in the class to + print the job (STR #1084) + - The scheduler now verifies that a printer supports + Letter or A4 media sizes before setting them as the + initial default (STR #1250) + - The cupstestppd program now flags bad Resolution + options (STR #1269) + - The USB backend now retries printing when the printer + is disconnected or turned off (STR #1267) + - Added new httpGetHostname() function to CUPS API, and + use it instead of gethostname() so that the web + interface will work correctly on systems whose hostname + is not the FQDN (STR #1266) + - The scheduler now stops printers if the backend for the + queue is missing on startup (STR #1265) + - The configure script now supports "--disable-library" + to disable particular image file format support + libraries, even if they are available on the build + system (STR #1248) + - The IPP backend did not always report on the total + number of pages that were printed (STR #1251) + - The lpstat program could display garbage date and time + values for locales whose date format exceeded 31 + characters (STR #1263) + - The cupstestppd program would segfault when testing + certain broken PPD files (STR #1268) + - Dramatically reduced the overhead of implicit classes. + - Added new cupsDir*() functions to CUPS API. + - Printers can now be published individually for sharing. + - Fixed a bug in the scheduler's startup signalling code + which caused cupsd to send the SIGUSR1 signal to the + init process instead of the original parent process + (STR #1258) + - Added new on-line help CGI to web interface to provide + searchable help. + - Devices are now tracked dynamically, with each query + doing a new device scan. This eliminates a previous + startup delay caused by slow backends and allows new + printers to be seen without restarting the server, + however it limits the amount of device URI checking + that can be done (basically now the scheduler only + requires a URI with a method that is a listed backend) + - Added new printer auto-detection, server configuration, + and log file viewing to the administration web page. + - Added new "set allowed users" web interface to set the + list of allowed users for a printer or class. + - The scheduler, command-line, and web interfaces now + limit the list of printers and classes to those + accessible by a user. + - cupsMarkOptions() now handles more non-standard + duplexing options and choices (STR #915) + - cups-lpd now honors remote banner requests with the + "standard" banner whenever a printer does not have one + defined (STR #1220) + - The scheduler's denial-of-service checks did not work + properly with IPv6 addresses (STR #1134) + - The lp and lpr commands did not error out properly when + they were unable to write to a temporary file (STR + #1129) + - The pstops filter did not handle Adobe-specific + comments in Windows NT driver output (STR #1085) + - "lpstat -l -p" incorrectly reported the printer + interface (STR #936) + - The web interface now operates exclusively with the + UTF-8 encoding, and sends the appropriate character set + and header information to the web browser (STR #919, + STR #1007) + - Added a "set allowed users" interface to the web + interface so that you can set the list of allowed or + denied users/groups for a printer or class. + - Disallow the "#" character in printer names, since it + has special meaning in the shell, config files, and in + URIs (STR #917, STR #1202) + - Added a new application/x-csource MIME type, and + support for it to the texttops filter so that you can + pretty print plain text files without the C/C++ + keywords being highlighted. + - The pdftops filter did not compile with GCC 4.0 (STR + #1226) + - The texttops filter did not highlight preprocessor + directives followed by a tab properly. + - HP PJL output now uses both JOB DISPLAY and RDYMSG + commands to show the current job on the printer's + display (STR #1218) + - Local authentication certificates are now stored in + /var/run/cups/certs by default instead of + /etc/cups/certs (STR #1211) + - Backends now use "&" to separate options in device + URIs; "+" is still recognized but is deprecated (STR + #842) + - The USB backend no longer supports the usb:/dev/foo + format on systems that support device ID queries. + - Forced classification markings did not work when the + job-sheets parameters were "none,none". + - "lpstat -l -p" incorrectly showed all users as allowed, + even if the queue was restricted to certain users (STR + #801) + - The scheduler now automatically detects SSL/TLS clients + without using the SSLPort/SSLListen directives. + - The CUPS API and scheduler no longer support SSLv2- + encrypted connections. + - Updated the cupsaddsmb utility to correctly export the + CUPS driver for Windows. + - Fixed a signal-handling bug in httpRead() which + ultimately caused the server to print multiple copies + when it was busy (STR #1184) + - The cupsFile API now uses the O_APPEND option when + opening files in append mode (STR #990) + - The md5.h header and md5_* functions are now officially + private and have been renamed to avoid conflicts with + other implementations with the same name. + - The pdftops filter incorrectly embedded some Type1 + fonts (STR #1093) + - The scheduler didn't detect a closed connection in the + middle of an IPP request (STR #1153) + - The scheduler could block trying to read the job status + if there was input pending and the job was cancelled in + the same input cycle (STR #1157) + - The scheduler could crash when deleting a class due to + infinite recursion. + - Updated the Zebra ZPL label printer driver to use the + run-length encoding and support more options. + - Updated serial backend to scan for /dev/ttyC* as well + as /dev/ttyc* for Cyclades serial ports (STR #1049) + - The scheduler could hang reading the job status under + certain circumstances (STR #1068) + - The USB backend termination signal code was inverted + (STR #1046) + - Moved enable and disable commands to sbindir to be + consistent. + - Added new cupsRasterInterpretPPD() function for RIP + filters to setup the raster page header from + PostScript commands in a PPD file. + - The CUPS browsing protocol now offers a "delete" bit + to remove printers as soon as they are deleted on the + server or as soon as the server shuts down gracefully + (STR #793) + - The CUPS_SERVER and ServerName directives (client.conf + and ~/.cupsrc) may now contain names of the form + "server:port" and "/path/to/domain/socket". + - The "cancel -u user" command now works for ordinary + users (STR #751) + - Added test run support to "make test" target (STR #64) + - Added domain socket support (STR #656) + - Added BrowseLocalOptions directive to allow the + administrator to add printer URI options to the browse + URI, e.g. "encryption=required" (STR #732) + - Added BrowseRemoteOptions directive to allow the + administrator to add standard URI options to the + remote printer URI, e.g. "encryption=required" (STR + #732) + - Now put "-I.." compiler option in front of all others + to ensure that local CUPS headers are used before + installed headers (STR #437) + - New cupsLangPrintf() and cupsLangPuts() for localized + interfaces. + - Now support custom attributes and extended options in + PPD files. + - Now provide functions to save PPD files. + - New policy mechanism allows per-operation and + per-printer control over what users and groups are + allowed to do various IPP operations. + - New error policy mechanism to control how aborted + backend errors are handled by the scheduler + (abort-job, retry-job, requeue-job, stop-printer) + - Updated the printer test page with a better color + wheel and a separate grayscale ramp. + - A single backend process is now run to send all print + data for a job. + - Backends and filters can now send and receive + backchannel data over file descriptor 3. + - Updated the raster stream format to support more + user-defined attributes and to do compression of the + page data. diff --git a/CREDITS.txt b/CREDITS.txt new file mode 100644 index 000000000..522774972 --- /dev/null +++ b/CREDITS.txt @@ -0,0 +1,33 @@ +CREDITS.txt - 04/26/2003 +------------------------ + +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. + L. Peter Deutsch - MD5 code. + Dr. ZP Han - setgid()/setuid(). + Guy Harris - *BSD shared libraries and lots of other fixes. + Bjoern Jacke - I18N stuff. + Wang Jian - CUPS RPM corrections. + Roderick Johnstone - Beta tester of the millenium. + Till Kamppeter - Bug fixes, beta testing, evangelism. + Kiko - Bug fixes. + Sergey V. Kovalyov - ESP Print Pro and CUPS beta tester. + Mark Lawrence - Microsoft interoperability testing. + Jeff Licquia - Bug fixes, beta testing, evangelism. + Jason McMullan - Original CUPS RPM distributions. + Wes Morgan - *BSD fixes. + Ulrich Oldendorf - German locale. + Giulio Orsero - Bug fixes and testing. + Kurt Pfeifle - Bug fixes, beta testing, evangelism. + Gilles QUERRET - French man pages. + Petter Reinholdtsen - HP-UX compiler stuff. + Stuart Stevens - HP JetDirect IPP information. + Andrea Suatoni - IRIX desktop integration and testing. + +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..e0e3ba9ff --- /dev/null +++ b/ENCRYPTION.txt @@ -0,0 +1,142 @@ +ENCRYPTION - CUPS v1.1.20 - 11/24/2003 +-------------------------------------- + +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, GNU +TLS, or CDSA libraries which do. + + +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, GNU TLS, or CDSA libraries 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, GNU TLS, or CDSA libraries from: + + http://www.openssl.org/ + http://www.gnutls.org/ + http://www.intel.com/labs/archive/cdsa.htm + + +CONFIGURING WITH ENCRYPTION SUPPORT + +Once you have the OpenSSL, GNU TLS, or CDSA libraries installed, +you'll need to configure CUPS to use it with the "--enable-ssl" +option: + + ./configure --enable-ssl + +If the library 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..fd2e5ec57 --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,190 @@ +INSTALL - CUPS v1.2.0a1 - 01/07/2003 +------------------------------------ + +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". + +**** IF YOU HAVE A NON-POSTSCRIPT PRINTER, YOU WILL ALSO **** +**** NEED TO INSTALL ESP GHOSTSCRIPT OR A PATCHED VERSION **** +**** OF THE STANDARD GHOSTSCRIPT RELEASES. **** + + +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. + +Also, please note that CUPS no longer includes the Ghostscript- +based pstoraster filter. You *must* download Ghostscript +separately and patch it using the files in the pstoraster +subdirectory, or download the ESP Ghostscript distribution from +the CUPS web site. For more information see the README file in +the pstoraster subdirectory. + + +COMPILING FROM CVS + +The CUPS CVS repository doesn't hold a copy of the pre-built +configure script. You'll need to run the GNU autoconf software +(2.52 or higher) before compiling the software from CVS: + + autoconf ENTER + + +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 EPM 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 ENTER + +or + + gmake ENTER + +for FreeBSD, NetBSD, and OpenBSD. The 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..2008a6312 --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,1068 @@ + + + Software License Agreement - Common UNIX Printing System + + + + +

Common UNIX Printing System License Agreement

+ +

Copyright 1997-2006 by Easy Software Products
+44141 AIRPORT VIEW DR STE 204
+HOLLYWOOD, MARYLAND 20636 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, with exceptions for Apple operating systems and the +OpenSSL toolkit. A copy of the exceptions and 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 +"cups" include directory and library files in the binary +distributions. The GNU GPL applies to the remainder of the CUPS +distribution, including the "pdftops" filter which is based upon +Xpdf and the CUPS imaging library. + +

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 +only exceptions to this are the portions of the CUPS software +covered by the Apple operating system license exceptions +outlined later in this license agreement. + +

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

License Exceptions

+ +

In addition, as the copyright holder of CUPS, Easy Software +Products grants the following special exceptions: + +

    + +
  1. Apple Operating System Development License + Exception; + +
      + +
    1. Software that is developed by any person or + entity for an Apple Operating System ("Apple + OS-Developed Software"), including but not + limited to Apple and third party printer + drivers, filters, and backends for an Apple + Operating System, that is linked to the CUPS + imaging library or based on any sample filters + or backends provided with CUPS shall not be + considered to be a derivative work or collective + work based on the CUPS program and is exempt + from the mandatory source code release clauses + of the GNU GPL. You may therefore distribute + linked combinations of the CUPS imaging library + with Apple OS-Developed Software without + releasing the source code of the Apple + OS-Developed Software. You may also use sample + filters and backends provided with CUPS to + develop Apple OS-Developed Software without + releasing the source code of the Apple + OS-Developed Software.
    2. + +
    3. An Apple Operating System means any + operating system software developed and/or + marketed by Apple Computer, Inc., including but + not limited to all existing releases and + versions of Apple's Darwin, Mac OS X, and Mac OS + X Server products and all follow-on releases and + future versions thereof.
    4. + +
    5. This exception is only available for Apple + OS-Developed Software and does not apply to + software that is distributed for use on other + operating systems.
    6. + +
    7. All CUPS software that falls under this + license exception have the following text at the + top of each source file: + +
      This file is subject to the Apple + OS-Developed Software + exception.
    8. + +
    + +
  2. OpenSSL Toolkit License Exception; + +
      + +
    1. Easy Software Products explicitly allows the + compilation and distribution of the CUPS + software with the OpenSSL Toolkit.
    2. + +
    + +
+ +

No developer is required to provide these exceptions in a +derived work. + +

Trademarks

+ +

Easy Software Products has trademarked the Common UNIX +Printing System, CUPS, and CUPS logo. You may use these names +and logos in any direct port or binary distribution of CUPS. +Please contact Easy Software Products for written permission to +use them in derivative products. 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 "pdftops" filter +that is based on the Xpdf 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: + +

+ + +

GNU GENERAL PUBLIC LICENSE

+ +

Version 2, June 1991 + +

+Copyright 1989, 1991 Free Software Foundation, Inc.
+59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+Everyone is permitted to copy and distribute verbatim
+copies of this license document, but changing it is not allowed.
+
+ +

Preamble

+ +

The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + +

When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + +

To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + +

For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + +

We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + +

Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + +

Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + +

The precise terms and conditions for copying, distribution and +modification follow. + +

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

+ +
    + +
  1. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +

    Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + +

  2. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +

    You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + +

  3. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + +
      + +
    1. You must cause the modified files to carry prominent notices +stating that you changed the files and the date of any change. + +
    2. You must cause any work that you distribute or publish, that in +whole or in part contains or is derived from the Program or any +part thereof, to be licensed as a whole at no charge to all third +parties under the terms of this License. + +
    3. if the modified program normally reads commands interactively +when run, you must cause it, when started running for such +interactive use in the most ordinary way, to print or display an +announcement including an appropriate copyright notice and a +notice that there is no warranty (or else, saying that you provide +a warranty) and that users may redistribute the program under +these conditions, and telling the user how to view a copy of this +License. (Exception: if the Program itself is interactive but +does not normally print such an announcement, your work based on +the Program is not required to print an announcement.) + +
    + +

    These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +

    Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +

    In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + +

  4. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + +
      + +
    1. Accompany it with the complete corresponding machine-readable +source code, which must be distributed under the terms of Sections +1 and 2 above on a medium customarily used for software interchange; or, + +
    2. Accompany it with a written offer, valid for at least three +years, to give any third party, for a charge no more than your +cost of physically performing source distribution, a complete +machine-readable copy of the corresponding source code, to be +distributed under the terms of Sections 1 and 2 above on a medium +customarily used for software interchange; or, + +
    3. Accompany it with the information you received as to the offer +to distribute corresponding source code. (This alternative is +allowed only for noncommercial distribution and only if you +received the program in object code or executable form with such +an offer, in accord with Subsection b above.) + +
    + +

    The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +

    If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + +

  5. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + +
  6. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + +
  7. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + +
  8. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +

    If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +

    It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +

    This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + +

  9. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + +
  10. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +

    Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + +

  11. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + +
+ +

NO WARRANTY

+ +
    + +
  1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + +
  2. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +
+ +

END OF TERMS AND CONDITIONS

+ +

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 an idea of what it does.
+Copyright (C) yyyy  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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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) year 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
+
+ + +

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

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

    + +
  1. The modified work must itself be a software library. + +

    +

  2. You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + +

    +

  3. You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + +

    +

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

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

    +

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

    +

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

    +

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

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

    +

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

+ +

How to Apply These Terms to Your New Libraries

+ +

If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + +

To apply these terms, attach the following notices to the library. 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 library's name and an idea of what it does.
+Copyright (C) year  name of author
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) any later version.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+ +

Also add information on how to contact you by electronic and paper mail. + +

You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + +

+Yoyodyne, Inc., hereby disclaims all copyright interest in
+the library `Frob' (a library for tweaking knobs) written
+by James Random Hacker.
+
+signature of Ty Coon, 1 April 1990
+Ty Coon, President of Vice
+
+ +

That's all there is to it! + + + diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..12e4af6bc --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,964 @@ + Common UNIX Printing System License Agreement + + Copyright 1997-2006 by Easy Software Products + 44141 AIRPORT VIEW DR STE 204 + HOLLYWOOD, MARYLAND 20636 USA + + Voice: +1.301.373.9600 + Email: cups-info@cups.org + WWW: http://www.cups.org + + +INTRODUCTION + +The Common UNIX Printing System(tm), ("CUPS(tm)"), is provided +under the GNU General Public License ("GPL") and GNU Library +General Public License ("LGPL"), Version 2, with exceptions for +Apple operating systems and the OpenSSL toolkit. A copy of the +exceptions and 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 +"cups" include directory and library files in the binary +distributions. The GNU GPL applies to the remainder of the CUPS +distribution, including the "pdftops" filter which is based upon +Xpdf and the CUPS imaging library. + +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 only +exceptions to this are the portions of the CUPS software covered +by the Apple operating system license exceptions outlined later +in this license agreement. + +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. + + +LICENSE EXCEPTIONS + +In addition, as the copyright holder of CUPS, Easy Software +Products grants the following special exceptions: + + 1. Apple Operating System Development License Exception; + + a. Software that is developed by any person or entity + for an Apple Operating System ("Apple OS-Developed + Software"), including but not limited to Apple and + third party printer drivers, filters, and backends + for an Apple Operating System, that is linked to the + CUPS imaging library or based on any sample filters + or backends provided with CUPS shall not be + considered to be a derivative work or collective work + based on the CUPS program and is exempt from the + mandatory source code release clauses of the GNU GPL. + You may therefore distribute linked combinations of + the CUPS imaging library with Apple OS-Developed + Software without releasing the source code of the + Apple OS-Developed Software. You may also use sample + filters and backends provided with CUPS to develop + Apple OS-Developed Software without releasing the + source code of the Apple OS-Developed Software. + + b. An Apple Operating System means any operating system + software developed and/or marketed by Apple Computer, + Inc., including but not limited to all existing + releases and versions of Apple's Darwin, Mac OS X, + and Mac OS X Server products and all follow-on + releases and future versions thereof. + + c. This exception is only available for Apple + OS-Developed Software and does not apply to software + that is distributed for use on other operating + systems. + + d. All CUPS software that falls under this license + exception have the following text at the top of each + source file: + + This file is subject to the Apple OS-Developed + Software exception. + + 2. OpenSSL Toolkit License Exception; + + a. Easy Software Products explicitly allows the + compilation and distribution of the CUPS software + with the OpenSSL Toolkit. + +No developer is required to provide these exceptions in a +derived work. + + +TRADEMARKS + +Easy Software Products has trademarked the Common UNIX Printing +System, CUPS, and CUPS logo. You may use these names and logos +in any direct port or binary distribution of CUPS. Please +contact Easy Software Products for written permission to use +them in derivative products. 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 "pdftops" filter that +is based on the Xpdf 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 + + 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. + + + Copyright (C) 19yy + + 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. + + , 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. + + 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 + + Appendix: How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. 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. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/Makedefs.in b/Makedefs.in new file mode 100644 index 000000000..7829d96b4 --- /dev/null +++ b/Makedefs.in @@ -0,0 +1,193 @@ +# +# "$Id: Makedefs.in 4836 2005-11-13 06:14:46Z mike $" +# +# Common makefile definitions for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +# +# Programs... +# + +AR = @AR@ +AWK = @AWK@ +CC = @LIBTOOL@ @CC@ +CXX = @LIBTOOL@ @CXX@ +DSO = @DSO@ +HTMLDOC = @HTMLDOC@ +INSTALL = @INSTALL@ +LIBTOOL = @LIBTOOL@ +LN = @LN@ -sf +MV = @MV@ +RANLIB = @RANLIB@ +RM = @RM@ -f +SED = @SED@ +SHELL = /bin/sh +STRIP = @STRIP@ + +# +# 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@ +LIBPAPER = @LIBPAPER@ +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@ +BACKLIBS = @BACKLIBS@ +CFLAGS = -I.. $(RC_CFLAGS) $(SSLFLAGS) @CPPFLAGS@ @CFLAGS@ \ + @LARGEFILE@ $(OPTIONS) +COMMONLIBS = @LIBS@ +CXXFLAGS = -I.. $(RC_CFLAGS) $(SSLFLAGS) @CPPFLAGS@ @CXXFLAGS@ \ + @LARGEFILE@ $(OPTIONS) +CXXLIBS = @CXXLIBS@ +DSOFLAGS = @DSOFLAGS@ +DSOLIBS = @DSOLIBS@ $(COMMONLIBS) +IMGLIBS = @IMGLIBS@ -lm +LDFLAGS = -L../cups -L../filter $(RC_CFLAGS) @LDFLAGS@ $(OPTIM) +LINKCUPS = @LINKCUPS@ $(SSLLIBS) +LINKCUPSIMAGE = @LINKCUPSIMAGE@ +LIBS = $(LINKCUPS) $(COMMONLIBS) +OPTIM = @OPTIM@ +OPTIONS = +PAMLIBS = @PAMLIBS@ +SSLFLAGS = @SSLFLAGS@ +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@ + +BUILDROOT = $(DSTROOT) + +AMANDIR = $(BUILDROOT)@AMANDIR@ +BINDIR = $(BUILDROOT)@bindir@ +CACHEDIR = $(BUILDROOT)@CUPS_CACHEDIR@ +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@ +PMANDIR = $(BUILDROOT)@PMANDIR@ +REQUESTS = $(BUILDROOT)@CUPS_REQUESTS@ +SBINDIR = $(BUILDROOT)@sbindir@ +SERVERBIN = $(BUILDROOT)@CUPS_SERVERBIN@ +SERVERROOT = $(BUILDROOT)@CUPS_SERVERROOT@ +STATEDIR = $(BUILDROOT)@CUPS_STATEDIR@ + +MAN1EXT = @MAN1EXT@ +MAN5EXT = @MAN5EXT@ +MAN8EXT = @MAN8EXT@ +MAN8DIR = @MAN8DIR@ + +PAMDIR = $(BUILDROOT)@PAMDIR@ +PAMFILE = @PAMFILE@ + + +# +# Rules... +# + +.SILENT: +.SUFFIXES: .1 .1.gz .1m .1m.gz .5 .5.gz .8 .8.gz .a .c .cxx .h .man .o .gz + +.c.o: + echo Compiling $<... + $(CC) $(OPTIM) $(CFLAGS) -c $< + +.cxx.o: + echo Compiling $<... + $(CXX) $(OPTIM) $(CXXFLAGS) -c $< + +.man.1 .man.1m .man.5 .man.8: + echo Linking $<... + $(RM) $@ + $(LN) $< $@ + +.man.1.gz .man.1m.gz .man.5.gz .man.8.gz .man.gz: + echo -n Compressing $<... + $(RM) $@ + gzip -v9 <$< >$@ + + +# +# End of "$Id: Makedefs.in 4836 2005-11-13 06:14:46Z mike $" +# diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..5d28e1bfa --- /dev/null +++ b/Makefile @@ -0,0 +1,171 @@ +# +# "$Id: Makefile 4835 2005-11-12 22:00:16Z mike $" +# +# Top-level Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2004 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-3142 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include Makedefs + +# +# Directories to make... +# + +DIRS = cups backend berkeley cgi-bin filter man pdftops \ + notifier 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 + +# +# Make dependencies +# + +depend: + for dir in $(DIRS); do\ + echo Making dependencies in $$dir... ;\ + (cd $$dir; $(MAKE) $(MFLAGS) depend) || exit 1;\ + done + + +# +# Install object and target files... +# + +install: installhdrs + 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/PrintingServices"; then \ + $(INSTALL_SCRIPT) cups.osx $(BUILDROOT)$(INITDDIR)/PrintingServices; \ + $(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 + + +# +# Install source and header files... +# + +installsrc: + gnutar --dereference --exclude=CVS -cf - . | gnutar -C $(SRCROOT) -xf - + +installhdrs: + (cd cups ; $(MAKE) $(MFLAGS) installhdrs) || exit 1;\ + (cd filter ; $(MAKE) $(MFLAGS) installhdrs) || exit 1; + + +# +# Run the test suite... +# + +check 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 packaging/cups.list + +bsd: + epm $(EPMFLAGS) -f bsd cups packaging/cups.list + +epm: + epm $(EPMFLAGS) cups packaging/cups.list + +rpm: + epm $(EPMFLAGS) -f rpm cups packaging/cups.list + +deb: + epm $(EPMFLAGS) -f deb cups packaging/cups.list + +depot: + epm $(EPMFLAGS) -f depot cups packaging/cups.list + +pkg: + epm $(EPMFLAGS) -f pkg cups packaging/cups.list + +tardist: + epm $(EPMFLAGS) -f tardist cups packaging/cups.list + +# +# End of "$Id: Makefile 4835 2005-11-12 22:00:16Z mike $". +# diff --git a/README.txt b/README.txt new file mode 100644 index 000000000..c2f964832 --- /dev/null +++ b/README.txt @@ -0,0 +1,290 @@ +README - CUPS v1.2.0b1 - 01/10/2006 +----------------------------------- + +***************************************************************** +***************************************************************** +**** **** +**** WARNING: THIS IS BETA RELEASE SOFTWARE AND MAY BE **** +**** TOTALLY UNSTABLE. DO NOT USE IN ENVIRONMENTS **** +**** WHERE RELIABLE SOFTWARE IS REQUIRED! **** +**** **** +***************************************************************** +***************************************************************** + +Looking for compile instructions? Read the file "INSTALL.txt" +instead... + +***************************************************************** +***************************************************************** +**** **** +**** IF YOU HAVE A NON-POSTSCRIPT PRINTER, YOU WILL ALSO **** +**** NEED TO INSTALL ESP GHOSTSCRIPT OR A PATCHED VERSION **** +**** OF A STANDARD GHOSTSCRIPT RELEASE. **** +**** **** +***************************************************************** +***************************************************************** + + +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 includes an image file RIP that supports printing of image +files to non-PostScript printers. A customized version of GNU +Ghostscript for CUPS called ESP Ghostscript is available +separately to support printing of PostScript files within the +CUPS driver framework. Sample drivers for Dymo, EPSON, HP, and +OKIDATA 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 + - HP-UX 11.00 or higher + - IRIX 6.5 or higher + - Linux 2.4 with glibc 2.2 or higher + - Solaris 7 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! We also +provide many discussion forums which are available at: + + http://www.cups.org/newsgroups.php + +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.2 includes a 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: + + 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-2006 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 PDF filter (pdftops) is based on the Xpdf software, +Copyright 1996-2005 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 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 +Derek B. Noonburg who developed the Xpdf software used to print +PDF files. diff --git a/backend/Dependencies b/backend/Dependencies new file mode 100644 index 000000000..70897ad97 --- /dev/null +++ b/backend/Dependencies @@ -0,0 +1,25 @@ +# DO NOT DELETE + +betest.o: ../cups/string.h ../config.h +ipp.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/md5.h +ipp.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/ppd.h +ipp.o: ../cups/file.h ../cups/language.h ../cups/array.h ../cups/string.h +lpd.o: ../cups/backend.h ../cups/http-private.h ../config.h ../cups/http.h +lpd.o: ../cups/md5.h ../cups/cups.h ../cups/ipp.h ../cups/ppd.h +lpd.o: ../cups/file.h ../cups/string.h +parallel.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +parallel.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/string.h +parallel.o: ../config.h ieee1284.c ../cups/debug.h +scsi.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +scsi.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/string.h +scsi.o: ../config.h +serial.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +serial.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/string.h +serial.o: ../config.h +socket.o: ../cups/backend.h ../cups/http-private.h ../config.h ../cups/http.h +socket.o: ../cups/md5.h ../cups/cups.h ../cups/ipp.h ../cups/ppd.h +socket.o: ../cups/file.h ../cups/string.h +test1284.o: ../cups/string.h ../config.h ieee1284.c ../cups/debug.h +usb.o: ../cups/backend.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +usb.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/string.h +usb.o: ../config.h diff --git a/backend/Makefile b/backend/Makefile new file mode 100644 index 000000000..26ce19b4f --- /dev/null +++ b/backend/Makefile @@ -0,0 +1,178 @@ +# +# "$Id: Makefile 4903 2006-01-10 20:02:46Z mike $" +# +# Backend makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2006 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# +# This file is subject to the Apple OS-Developed Software exception. +# + +include ../Makedefs + +BACKENDS = ipp lpd parallel scsi serial socket usb +TARGETS = betest test1284 $(BACKENDS) +OBJS = betest.o ipp.o lpd.o parallel.o scsi.o \ + serial.o socket.o test1284.o usb.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) http + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1 + + +# +# Install all targets... +# + +install: all + $(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) + + +# +# test1284 +# + +test1284: test1284.o ../cups/libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o test1284 test1284.o ../cups/libcups.a + + +# +# ieee1394 +# + +ieee1394: ieee1394.o ieee1394-linux.o + echo Linking $@... + $(CC) $(LDFLAGS) -o ieee1394 ieee1394.o ieee1394-linux.o -lraw1394 $(LIBS) + +ieee1394.o: ieee1394.h +ieee1394-linux.o: ieee1394.h + + +# +# ipp +# + +ipp: ipp.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o ipp ipp.o $(LIBS) + $(RM) http + $(LN) ipp http + + +# +# lpd +# + +lpd: lpd.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpd lpd.o $(LIBS) + + +# +# parallel +# + +parallel: parallel.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o parallel parallel.o $(LIBS) + + +# +# scsi +# + +scsi: scsi.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o scsi scsi.o $(LIBS) + +scsi.o: scsi.c scsi-irix.c scsi-linux.c + + +# +# serial +# + +serial: serial.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o serial serial.o $(BACKLIBS) $(LIBS) + + +# +# socket +# + +socket: socket.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o socket socket.o $(LIBS) + + +# +# usb +# + +usb: usb.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o usb usb.o $(BACKLIBS) $(LIBS) +usb.o: usb.c usb-darwin.c usb-unix.c ieee1284.c + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4903 2006-01-10 20:02:46Z mike $". +# diff --git a/backend/betest.c b/backend/betest.c new file mode 100644 index 000000000..f0ea6cdb2 --- /dev/null +++ b/backend/betest.c @@ -0,0 +1,87 @@ +/* + * "$Id: betest.c 4494 2005-02-18 02:18:11Z mike $" + * + * Backend test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Run the named backend. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include + + +/* + * 'main()' - Run the named backend. + * + * Usage: + * + * betest device-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (7 or 8) */ + char *argv[]) /* I - Command-line arguments */ +{ + char backend[255]; /* Method in URI */ + + + if (argc < 7 || argc > 8) + { + fputs("Usage: betest device-uri job-id user title copies options [file]\n", + stderr); + return (1); + } + + /* + * Extract the method from the device-uri - that's the program we want to + * execute. + */ + + if (sscanf(argv[1], "%254[^:]", backend) != 1) + { + fputs("betest: Bad device-uri - no colon!\n", stderr); + return (1); + } + + /* + * Execute and return + */ + + execl(backend, argv[1], argv[2], argv[3], argv[4], argv[5], argv[6], argv[7], + NULL); + + return (1); +} + + +/* + * End of "$Id: betest.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/backend/easysw-firewire-design.txt b/backend/easysw-firewire-design.txt new file mode 100644 index 000000000..194c487ed --- /dev/null +++ b/backend/easysw-firewire-design.txt @@ -0,0 +1,71 @@ +Preliminary Design for CUPS Firewire Printer Backend - 03/19/2002 +----------------------------------------------------------------- + +OVERVIEW + + Easy Software Products will develop an IEEE-1394, a.k.a. + Firewire, printing interface for its Common UNIX Printing + System ("CUPS") for initial use under the Linux operating + system. A follow-on implementation for MacOS X is + anticipated as well. + + The operating system interfaces for IEEE-1394 ports vary + widely; the CUPS printing interface will abstract the OS + layer to a simpler interface geared towards discovering, + opening, reading from, writing to, and closing IEEE-1394 + printers. + + The initial development of the CUPS backend will be targeted + at the EPSON Stylus Pro 10000 large format printer, which + requires the bandwidth provided by Firewire in order to + print at full speed. This printer supports printing via + Serial Bus Protocol 2 (SBP-2) using the SCSI and PWG command + sets. The CUPS backend will implement the PWG command set on + LUN 0 only. + + +OS ABSTRACTION LAYER + + The OS abstraction layer will be a thin client library that + implements the following functions: + + ieee1394_list + ieee1394_open + ieee1394_close + ieee1394_read + ieee1394_write + ieee1394_error + + The "ieee1394_list" function will list all of the available + printer devices on the bus. The device information will + consist of the device URI (ieee1394:/something) used to + access the device and the make and model information, if + available, for the device ("EPSON Stylus Printer"). + + The "ieee1394_open" and "ieee1394_close" functions will open + and close a connection to the printer, respectively. + + The "ieee1394_read" and "ieee1394_write" functions will read + and write data to and from the printer, respectively. The + read function will be non-blocking, returning data only if + there is data coming back from the printer. + + The "ieee1394_error" function will return a string + describing the last error or NULL if no error occurred. + + The library will be responsible for creating any background + threads that are needed to monitor the connection to the + printer. + + +CUPS BACKEND + + The CUPS backend will use the OS abstraction layer to list + and access the Firewire printers. The "main" function will + read and write printer data, while the "list_devices" + function will be called as necessary to identify the + available devices. + + The CUPS 1.1 backend will record any status information in + the error log file, while the 1.2 backend will supply it to + the printer driver process. diff --git a/backend/easysw-firewire-linux.txt b/backend/easysw-firewire-linux.txt new file mode 100644 index 000000000..a8e461189 --- /dev/null +++ b/backend/easysw-firewire-linux.txt @@ -0,0 +1,35 @@ +Easy Software Products +44141 Airport View Drive +Suite 204 +Hollywood, Maryland 20636 ++1.301.373.9600 +March 8, 2002 + + +Subject: EPSON Firewire Printer Driver for Linux + +Currently, no Firewire printer support exists for Linux. Since +the latest EPSON printer products depend on the Firewire +interface to print at full speed, a solution is needed to +support customers using Linux as their server platform. + +The Linux Firewire subsystem provides a user-mode driver +interface that allows driver programs to access Firewire +devices. Easy Software Products will utilize this interface to +develop a "backend" program for the Common UNIX Printing System +that will allow users to print to EPSON printers using the +Firewire interface. + +After examining the Linux interface, we estimate that it will +require approximately 30 hours of development time to write, +test, and document the Firewire backend, for a total cost of +$3,000. The new backend will become a standard part of the CUPS +software distribution and will be included with at least the +following Linux distributions: + + - Caldera Linux + - Mandrake Linux + - Red Hat Linux + - SuSE Linux + +ESP will provide EPSON with binaries for Red Hat Linux 7.2. diff --git a/backend/ieee1284.c b/backend/ieee1284.c new file mode 100644 index 000000000..6152c4c7a --- /dev/null +++ b/backend/ieee1284.c @@ -0,0 +1,373 @@ +/* + * "$Id: ieee1284.c 4903 2006-01-10 20:02:46Z mike $" + * + * IEEE-1284 support functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * get_device_id() - Get the IEEE-1284 device ID string and corresponding + * URI. + */ + +/* + * Include necessary headers. + */ + +#include +#ifdef __linux +# include +# include +# define IOCNR_GET_DEVICE_ID 1 +# define LPIOC_GET_DEVICE_ID(len) _IOC(_IOC_READ, 'P', IOCNR_GET_DEVICE_ID, len) +#endif /* __linux */ + +#ifdef __sun +# ifdef __sparc +# include +# else +# include +# include +# endif /* __sparc */ +#endif /* __sun */ + + +/* + * 'get_device_id()' - Get the IEEE-1284 device ID string and + * corresponding URI. + */ + +int /* O - 0 on success, -1 on failure */ +get_device_id( + int fd, /* I - File descriptor */ + char *device_id, /* O - 1284 device ID */ + int device_id_size, /* I - Size of buffer */ + char *make_model, /* O - Make/model */ + int make_model_size, /* I - Size of buffer */ + const char *scheme, /* I - URI scheme */ + char *uri, /* O - Device URI */ + int uri_size) /* I - Size of buffer */ +{ + char *attr, /* 1284 attribute */ + *delim, /* 1284 delimiter */ + *uriptr, /* Pointer into URI */ + *mfg, /* Manufacturer string */ + *mdl, /* Model string */ + serial_number[1024]; /* Serial number string */ +#ifdef __linux + int length; /* Length of device ID info */ +#endif /* __linux */ +#ifdef __sun + struct ecpp_device_id did; /* Device ID buffer */ +#endif /* __sun */ + + DEBUG_printf(("get_device_id(fd=%d, device_id=%p, device_id_size=%d, " + "make_model=%p, make_model_size=%d, scheme=\"%s\", " + "uri=%p, uri_size=%d)\n", fd, device_id, device_id_size, + make_model, make_model_size, scheme ? scheme : "(null)", + uri, uri_size)); + + /* + * Range check input... + */ + + if (fd < 0 || + !device_id || device_id_size < 32 || + !make_model || make_model_size < 32) + { + DEBUG_puts("get_device_id: Bad args!"); + return (-1); + } + + *device_id = '\0'; + *make_model = '\0'; + + if (uri) + *uri = '\0'; + + /* + * Get the device ID string... + */ + +#ifdef __linux + if (!ioctl(fd, LPIOC_GET_DEVICE_ID(device_id_size), device_id)) + { + /* + * Extract the length of the device ID string from the first two + * bytes. The 1284 spec says the length is stored MSB first... + */ + + length = (((unsigned)device_id[0] & 255) << 8) + + ((unsigned)device_id[1] & 255); + + /* + * Check to see if the length is larger than our buffer; first + * assume that the vendor incorrectly implemented the 1284 spec, + * and then limit the length to the size of our buffer... + */ + + if (length > (device_id_size - 2)) + length = (((unsigned)device_id[1] & 255) << 8) + + ((unsigned)device_id[0] & 255); + + if (length > (device_id_size - 2)) + length = device_id_size - 2; + + /* + * Copy the device ID text to the beginning of the buffer and + * nul-terminate. + */ + + memmove(device_id, device_id + 2, length); + device_id[length] = '\0'; + } +# ifdef DEBUG + else + printf("get_device_id: ioctl failed - %s\n", strerror(errno)); +# endif /* DEBUG */ +#endif /* __linux */ + +#if defined(__sun) && defined(ECPPIOC_GETDEVID) + did.mode = ECPP_CENTRONICS; + did.len = device_id_size - 1; + did.rlen = 0; + did.addr = device_id; + + if (!ioctl(fd, ECPPIOC_GETDEVID, &did)) + { + /* + * Nul-terminate the device ID text. + */ + + if (did.rlen < (device_id_size - 1)) + device_id[did.rlen] = '\0'; + else + device_id[device_id_size - 1] = '\0'; + } +# ifdef DEBUG + else + printf("get_device_id: ioctl failed - %s\n", strerror(errno)); +# endif /* DEBUG */ +#endif /* __sun && ECPPIOC_GETDEVID */ + + DEBUG_printf(("get_device_id: device_id=\"%s\"\n", device_id)); + + if (!*device_id) + return (-1); + + /* + * Look for the description field... + */ + + if ((attr = strstr(device_id, "DES:")) != NULL) + attr += 4; + else if ((attr = strstr(device_id, "DESCRIPTION:")) != NULL) + attr += 12; + + if (attr) + { + /* + * Make sure the description contains something useful, since some + * printer manufacturers (HP) apparently don't follow the standards + * they helped to define... + * + * Here we require the description to be 8 or more characters in length, + * containing at least one space and one letter. + */ + + if ((delim = strchr(attr, ';')) == NULL) + delim = attr + strlen(attr); + + if ((delim - attr) < 8) + attr = NULL; + else + { + char *ptr; /* Pointer into description */ + int letters, /* Number of letters seen */ + spaces; /* Number of spaces seen */ + + + for (ptr = attr, letters = 0, spaces = 0; ptr < delim; ptr ++) + { + if (isspace(*ptr & 255)) + spaces ++; + else if (isalpha(*ptr & 255)) + letters ++; + + if (spaces && letters) + break; + } + + if (!spaces || !letters) + attr = NULL; + } + } + + if ((mfg = strstr(device_id, "MANUFACTURER:")) != NULL) + mfg += 13; + else if ((mfg = strstr(device_id, "MFG:")) != NULL) + mfg += 4; + + if ((mdl = strstr(device_id, "MODEL:")) != NULL) + mdl += 6; + else if ((mdl = strstr(device_id, "MDL:")) != NULL) + mdl += 4; + + if (attr) + { + /* + * Use description... + */ + + if (!strncasecmp(attr, "Hewlett-Packard hp ", 19)) + { + /* + * Check for a common HP bug... + */ + + strlcpy(make_model, "HP ", make_model_size); + strlcpy(make_model + 3, attr + 19, make_model_size - 3); + } + else if (!strncasecmp(attr, "Hewlett-Packard ", 16)) + { + strlcpy(make_model, "HP ", make_model_size); + strlcpy(make_model + 3, attr + 16, make_model_size - 3); + } + else + { + strlcpy(make_model, attr, make_model_size); + } + } + else if (mfg && mdl) + { + /* + * Build a make-model string from the manufacturer and model attributes... + */ + + if (!strncasecmp(mfg, "Hewlett-Packard", 15)) + strlcpy(make_model, "HP", make_model_size); + else + strlcpy(make_model, mfg, make_model_size); + + if ((delim = strchr(make_model, ';')) != NULL) + *delim = '\0'; + + if (!strncasecmp(make_model, mdl, strlen(make_model))) + { + /* + * Just copy model string, since it has the manufacturer... + */ + + strlcpy(make_model, mdl, make_model_size); + } + else + { + /* + * Concatenate the make and model... + */ + + strlcat(make_model, " ", make_model_size); + strlcat(make_model, mdl, make_model_size); + } + } + else + { + /* + * Use "Unknown" as the printer make and model... + */ + + strlcpy(make_model, "Unknown", make_model_size); + } + + if ((delim = strchr(make_model, ';')) != NULL) + *delim = '\0'; + + if (scheme && uri && uri_size > 32) + { + /* + * Look for the serial number field... + */ + + if ((attr = strstr(device_id, "SERN:")) != NULL) + attr += 5; + else if ((attr = strstr(device_id, "SERIALNUMBER:")) != NULL) + attr += 13; + else if ((attr = strstr(device_id, ";SN:")) != NULL) + attr += 4; + + if (attr) + { + strlcpy(serial_number, attr, sizeof(serial_number)); + + if ((delim = strchr(serial_number, ';')) != NULL) + *delim = '\0'; + } + else + serial_number[0] = '\0'; + + /* + * Generate the device URI from the make_model and serial number strings. + */ + + snprintf(uri, uri_size, "%s://", scheme); + for (uriptr = uri + strlen(uri), delim = make_model; + *delim && uriptr < (uri + uri_size - 1); + delim ++) + if (*delim == ' ') + { + delim ++; + *uriptr++ = '/'; + break; + } + else + *uriptr++ = *delim; + + for (; *delim && uriptr < (uri + uri_size - 3); delim ++) + if (*delim == ' ') + { + *uriptr++ = '%'; + *uriptr++ = '2'; + *uriptr++ = '0'; + } + else + *uriptr++ = *delim; + + *uriptr = '\0'; + + if (serial_number[0]) + { + /* + * Add the serial number to the URI... + */ + + strlcat(uri, "?serial=", uri_size); + strlcat(uri, serial_number, uri_size); + } + } + + return (0); +} + + +/* + * End of "$Id: ieee1284.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/backend/ieee1394-linux.c b/backend/ieee1394-linux.c new file mode 100644 index 000000000..b95e8204e --- /dev/null +++ b/backend/ieee1394-linux.c @@ -0,0 +1,877 @@ +/* + * "$Id: ieee1394-linux.c 4703 2005-09-26 19:33:58Z mike $" + * + * Linux IEEE-1394 glue for the Common UNIX Printing System (CUPS). + * + * Copyright 2002 by Easy Software Products, all rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use + * of this software must display the following + * acknowledgement: + * + * This product includes software developed by Easy + * Software Products. + * + * 4. The name of Easy Software Products may not be used to + * endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Contents: + * + * get_device_id() - Get the IEEE-1284 device ID for a node... + * get_unit_type() - Get the unit type for a node... + * show_data() - Show a data node... + * show_dir() - Show a directory list... + * ieee1394_list() - List the available printer devices. + * ieee1394_open() - Open a printer device. + * ieee1394_close() - Close a printer device. + * ieee1394_read() - Read from a printer device. + * ieee1394_write() - Write data to a printer device. + * ieee1394_error() - Return the last error. + */ + +/* + * Include necessary headers. + */ + +#include "ieee1394.h" +#include +#include +#include + + +/* + * Limits... + */ + +#define MAX_NODES 100 + + +/* + * Structures... + */ + +typedef struct +{ + char uri[HTTP_MAX_URI],/* URI for this node... */ + description[128],/* Description of port */ + make_model[128];/* Make and model */ + int port, /* Port where this node is found */ + node; /* Node number */ + unsigned long long addr; /* Management address */ +} linux1394_node_t; + +typedef struct +{ + raw1394handle_t handle; /* Handle for printer device */ + int node; /* Node number for printer device */ + unsigned long long addr; /* Management address */ +} linux1394_dev_t; + + +/* + * ORB messages for communication with the device... + */ + +typedef struct /**** Login ORB Message */ +{ + unsigned char passwd_addr[8]; /* Password address */ + unsigned char resp_addr[8]; /* Login response address */ + unsigned char notify_excl; /* Notify and exclusive bits */ + unsigned char recon_func; /* Reconnect time and function */ + unsigned char lun[2]; /* Logical unit number */ + unsigned char passwd_len[2]; /* Length of password */ + unsigned char resp_len[2]; /* Length of login response */ + unsigned char fifo_addr[8]; /* Local status FIFO address */ +} login_orb_t; + +typedef struct /**** Login Response Message ****/ +{ + unsigned char length[2]; /* Length of response */ + unsigned char login_id[2]; /* Login ID */ + unsigned char cmd_addr[8]; /* Command block agent address */ + unsigned char reserved[2]; /* Reserved (0) */ + unsigned char recon_hold[2]; /* Number of seconds to hold login */ +} login_resp_t; + + +/* + * Local globals... + */ + +static char error_string[1024] = ""; +static int num_nodes; +static linux1394_node_t nodes[MAX_NODES]; + + +/* + * 'get_device_id()' - Get the IEEE-1284 device ID for a node... + */ + +static char * /* O - Device ID */ +get_device_id(raw1394handle_t handle,/* I - Handle for device */ + int node, /* I - Node number */ + unsigned long long offset,/* I - Offset to directory */ + char *id, /* O - ID string */ + int idlen) /* I - Size of ID string */ +{ + unsigned char data[1024], /* Data from ROM */ + *dataptr; /* Pointer into data */ + int length; /* Length of directory */ + int datalen; /* Length of data */ + unsigned long long dataoff; /* Offset of data */ + + + DEBUG_printf(("get_device_id(handle = %p, node = %d, offset = %llx, id = %p, idlen = %d)\n", + handle, node, offset, id, idlen)); + + *id = '\0'; + + /* + * Read the directory length from the first quadlet... + */ + + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return (NULL); + + offset += 4; + + /* + * The length is in the upper 16 bits... + */ + + length = (data[0] << 8) | data[1]; + + DEBUG_printf((" length = %d\n", length)); + + /* + * Then read the directory, looking for unit directory or device tags... + */ + + while (length > 0) + { + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return (NULL); + + DEBUG_printf((" data = %02X %02X %02X %02X\n", data[0], data[1], + data[2], data[3])); + + if (data[0] == 0xd1) + { + /* + * Found the unit directory... + */ + + offset += ((((data[1] << 8) | data[2]) << 8) | data[3]) << 2; + + return (get_device_id(handle, node, offset, id, idlen)); + } + else if (data[0] == 0x81) + { + /* + * Found potential IEEE-1284 device ID... + */ + + dataoff = offset + (((((data[1] << 8) | data[2]) << 8) | data[3]) << 2); + + if (raw1394_read(handle, 0xffc0 | node, dataoff, 4, (quadlet_t *)data) < 0) + return (NULL); + + dataoff += 4; + + /* + * Read the leaf value... + */ + + datalen = (data[0] << 8) | data[1]; + + if (datalen > (sizeof(data) / 4)) + datalen = sizeof(data) / 4; + + for (dataptr = data; datalen > 0; datalen --, dataptr += 4, dataoff += 4) + if (raw1394_read(handle, 0xffc0 | node, dataoff, 4, + (quadlet_t *)dataptr) < 0) + return (NULL); + + if (data[0] == 0 && memcmp(data + 8, "MFG:", 4) == 0) + { + /* + * Found the device ID... + */ + + datalen = dataptr - data - 8; + if (datalen >= idlen) + datalen --; + + memcpy(id, data + 8, datalen); + id[datalen] = '\0'; + + return (id); + } + } + + offset += 4; + length --; + } + + return (NULL); +} + + +/* + * 'get_man_addr()' - Get the management address for a node... + */ + +static int /* O - Unit type */ +get_man_addr(raw1394handle_t handle, /* I - Handle for device */ + int node, /* I - Node number */ + unsigned long long offset) /* I - Offset to directory */ +{ + unsigned char data[4]; /* Data from ROM */ + int length; /* Length of directory */ + + + DEBUG_printf(("get_man_addr(handle = %p, node = %d, offset = %llx)\n", + handle, node, offset)); + + /* + * Read the directory length from the first quadlet... + */ + + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return (-1); + + offset += 4; + + /* + * The length is in the upper 16 bits... + */ + + length = (data[0] << 8) | data[1]; + + DEBUG_printf((" length = %d\n", length)); + + /* + * Then read the directory, looking for unit directory or type tags... + */ + + while (length > 0) + { + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return (-1); + + DEBUG_printf((" data = %02X %02X %02X %02X\n", data[0], data[1], + data[2], data[3])); + + if (data[0] == 0xd1) + { + /* + * Found the unit directory... + */ + + offset += ((((data[1] << 8) | data[2]) << 8) | data[3]) << 2; + + return (get_man_addr(handle, node, offset)); + } + else if (data[0] == 0x54) + { + /* + * Found the management address... + */ + + return (((((data[1] << 8) | data[2]) << 8) | data[3]) << 2); + } + + offset += 4; + length --; + } + + return (-1); +} + + +/* + * 'get_unit_type()' - Get the unit type for a node... + */ + +static int /* O - Unit type */ +get_unit_type(raw1394handle_t handle,/* I - Handle for device */ + int node, /* I - Node number */ + unsigned long long offset)/* I - Offset to directory */ +{ + unsigned char data[4]; /* Data from ROM */ + int length; /* Length of directory */ + + + DEBUG_printf(("get_unit_type(handle = %p, node = %d, offset = %llx)\n", + handle, node, offset)); + + /* + * Read the directory length from the first quadlet... + */ + + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return (-1); + + offset += 4; + + /* + * The length is in the upper 16 bits... + */ + + length = (data[0] << 8) | data[1]; + + DEBUG_printf((" length = %d\n", length)); + + /* + * Then read the directory, looking for unit directory or type tags... + */ + + while (length > 0) + { + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return (-1); + + DEBUG_printf((" data = %02X %02X %02X %02X\n", data[0], data[1], + data[2], data[3])); + + if (data[0] == 0xd1) + { + /* + * Found the unit directory... + */ + + offset += ((((data[1] << 8) | data[2]) << 8) | data[3]) << 2; + + return (get_unit_type(handle, node, offset)); + } + else if (data[0] == 0x14) + { + /* + * Found the unit type... + */ + + return (data[1] & 0x1f); + } + + offset += 4; + length --; + } + + return (-1); +} + + +#ifdef DEBUG +/* + * 'show_data()' - Show a data node... + */ + +static void +show_data(raw1394handle_t handle, /* I - Handle for device */ + int node, /* I - Node number */ + unsigned long long offset, /* I - Offset to directory */ + int indent) /* Amount to indent */ +{ + int i; /* Looping var */ + unsigned char data[4]; /* Data from ROM */ + int length; /* Length of data */ + + + /* + * Read the data length from the first quadlet... + */ + + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return; + + offset += 4; + + /* + * The length is in the upper 16 bits... + */ + + length = (data[0] << 8) | data[1]; + + /* + * Then read the data... + */ + + for (i = 0; i < indent; i ++) + putchar(' '); + + printf("LEAF (%d quadlets)\n", length); + + while (length > 0) + { + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return; + + for (i = 0; i < indent; i ++) + putchar(' '); + + printf("%02X %02X %02X %02X '%c%c%c%c'\n", + data[0], data[1], data[2], data[3], + (data[0] < ' ' || data[0] >= 0x7f) ? '.' : data[0], + (data[1] < ' ' || data[1] >= 0x7f) ? '.' : data[1], + (data[2] < ' ' || data[2] >= 0x7f) ? '.' : data[2], + (data[3] < ' ' || data[3] >= 0x7f) ? '.' : data[3]); + + offset += 4; + length --; + } +} + + +/* + * 'show_dir()' - Show a directory list... + */ + +static void +show_dir(raw1394handle_t handle, /* I - Handle for device */ + int node, /* I - Node number */ + unsigned long long offset, /* I - Offset to directory */ + int indent) /* Amount to indent */ +{ + int i; /* Looping var */ + unsigned char data[4]; /* Data from ROM */ + int length; /* Length of directory */ + int value; /* Value in directory */ + + + /* + * Read the directory length from the first quadlet... + */ + + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return; + + offset += 4; + + /* + * The length is in the upper 16 bits... + */ + + length = (data[0] << 8) | data[1]; + + /* + * Then read the directory... + */ + + while (length > 0) + { + if (raw1394_read(handle, 0xffc0 | node, offset, 4, (quadlet_t *)data) < 0) + return; + + for (i = 0; i < indent; i ++) + putchar(' '); + + printf("%02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]); + + value = (((data[1] << 8) | data[2]) << 8) | data[3]; + + switch (data[0] & 0xc0) + { + case 0x00 : + for (i = -4; i < indent; i ++) + putchar(' '); + + printf("IMMEDIATE %d\n", value); + break; + + case 0x40 : + for (i = -4; i < indent; i ++) + putchar(' '); + + printf("CSR OFFSET +%06X\n", value); + break; + + case 0x80 : + show_data(handle, node, offset + value * 4, indent + 4); + break; + + case 0xc0 : + show_dir(handle, node, offset + value * 4, indent + 4); + break; + } + + offset += 4; + length --; + } +} +#endif /* DEBUG */ + + +/* + * 'ieee1394_list()' - List the available printer devices. + */ + +ieee1394_info_t * /* O - Printer information */ +ieee1394_list(int *num_devices) /* O - Number of printers */ +{ + int i, j; /* Looping vars */ + raw1394handle_t handle; /* 1394 handle */ + int num_ports; /* Number of ports */ + struct raw1394_portinfo ports[100]; /* Port data... */ + unsigned char guid[8]; /* Global unique ID */ + int vendor; /* Vendor portion of GUID */ + int unit_type; /* Unit type */ + int addr; /* Management address offset */ + char id[1024], /* Device ID string */ + *idptr, /* Pointer into ID string */ + *idsep; /* Pointer to separator */ + ieee1394_info_t *devices; /* Device list */ + + + /* + * Connect to the user-mode driver interface... + */ + + handle = raw1394_new_handle(); + num_ports = raw1394_get_port_info(handle, ports, + sizeof(ports) / sizeof(ports[0])); + + DEBUG_printf(("num_ports = %d\n", num_ports)); + + /* + * Loop through the ports to discover what nodes are available. + */ + + num_nodes = 0; + + for (i = 0; i < num_ports; i ++) + { + DEBUG_printf(("ports[%d] = { nodes = %d, name = \"%s\" }\n", i, + ports[i].nodes, ports[i].name)); + + raw1394_set_port(handle, i); + + for (j = 0; j < ports[i].nodes; j ++) + { + if (raw1394_read(handle, 0xffc0 | j, + CSR_REGISTER_BASE + CSR_CONFIG_ROM + 12, 4, + (quadlet_t *)guid) < 0) + { + DEBUG_printf((" Node #%d: Unable to contact (%s)!\n", j, + strerror(errno))); + continue; + } + else + { + raw1394_read(handle, 0xffc0 | j, + CSR_REGISTER_BASE + CSR_CONFIG_ROM + 16, 4, + (quadlet_t *)(guid + 4)); + + DEBUG_printf((" Node #%d: GUID = %02X%02X%02X%02X%02X%02X%02X%02X\n", + j, guid[0], guid[1], guid[2], guid[3], guid[4], + guid[5], guid[6], guid[7])); + + vendor = (((guid[0] << 8) | guid[1]) << 8) | guid[2]; + unit_type = get_unit_type(handle, j, + CSR_REGISTER_BASE + CSR_CONFIG_ROM + 20); + + DEBUG_printf(("vendor = %x, unit_type = %d\n", vendor, unit_type)); + + if (unit_type == 2 && num_nodes < MAX_NODES) + { + /* + * Found a printer device; add it to the nodes list... + */ + +#ifdef DEBUG + show_dir(handle, j, CSR_REGISTER_BASE + CSR_CONFIG_ROM + 20, 0); +#endif /* DEBUG */ + + memset(nodes + num_nodes, 0, sizeof(linux1394_node_t)); + + sprintf(nodes[num_nodes].uri, "ieee1394://%02X%02X%02X%02X%02X%02X%02X%02X", + guid[0], guid[1], guid[2], guid[3], guid[4], + guid[5], guid[6], guid[7]); + + nodes[num_nodes].port = i; + nodes[num_nodes].node = j; + + addr = get_man_addr(handle, j, CSR_REGISTER_BASE + CSR_CONFIG_ROM + 20); + + if (addr < 0) + continue; + + nodes[num_nodes].addr = CSR_REGISTER_BASE + addr; + + DEBUG_printf(("Node address = %llx\n", nodes[num_nodes].addr)); + + get_device_id(handle, j, CSR_REGISTER_BASE + CSR_CONFIG_ROM + 20, + id, sizeof(id)); + + if (id[0]) + { + /* + * Grab the manufacturer and model name from the device ID + * string... + */ + + idptr = id + 4; + idsep = strchr(id, ';'); + if (idsep) + *idsep++ = '\0'; + else + idsep = idptr; + + snprintf(nodes[num_nodes].description, + sizeof(nodes[num_nodes].description), + "%s Firewire Printer", idptr); + + if ((idptr = strstr(idsep, "DES:")) == NULL) + idptr = strstr(idsep, "MDL:"); + + if (idptr == NULL) + strcpy(nodes[num_nodes].make_model, "Unknown"); + else + { + /* + * Grab the DES or MDL code... + */ + + idptr += 4; + idsep = strchr(idptr, ';'); + if (idsep) + *idsep = '\0'; + + if (strncmp(id + 4, idptr, strlen(id + 4)) == 0) + { + /* + * Use the description directly... + */ + + strlcpy(nodes[num_nodes].make_model, idptr, + sizeof(nodes[num_nodes].make_model)); + } + else + { + /* + * Add the manufacturer to the front of the name... + */ + + snprintf(nodes[num_nodes].make_model, + sizeof(nodes[num_nodes].make_model), + "%s %s", id + 4, idptr); + } + } + } + else + { + /* + * Flag it as an unknown printer... + */ + + sprintf(nodes[num_nodes].description, + "Unknown%06X Firewire Printer", vendor); + strcpy(nodes[num_nodes].make_model, "Unknown"); + } + + num_nodes ++; + } + } + } + } + + /* + * Done querying the Firewire bus... + */ + + raw1394_destroy_handle(handle); + + /* + * Build an array of device info structures as needed... + */ + + if (num_devices == NULL) + return (NULL); + + *num_devices = num_nodes; + + if (num_nodes) + { + if ((devices = calloc(sizeof(ieee1394_info_t), num_nodes)) != NULL) + { + for (i = 0; i < num_nodes; i ++) + { + strcpy(devices[i].uri, nodes[i].uri); + strcpy(devices[i].description, nodes[i].description); + strcpy(devices[i].make_model, nodes[i].make_model); + } + } + + return (devices); + } + else + return (NULL); +} + + +/* + * 'ieee1394_open()' - Open a printer device. + */ + +ieee1394_dev_t /* O - Printer device or NULL */ +ieee1394_open(const char *uri) /* I - Device URI */ +{ + int i; /* Looping var */ + linux1394_dev_t *ldev; /* Linux device */ + + + /* + * Return early if we can't see any printers... + */ + + if (num_nodes == 0) + ieee1394_list(NULL); + + if (num_nodes == 0) + { + strcpy(error_string, "No IEEE-1394 printers found!"); + return (NULL); + } + + /* + * Look for the URI... + */ + + for (i = 0; i < num_nodes; i ++) + if (strcmp(nodes[i].uri, uri) == 0) + break; + + if (i >= num_nodes) + { + snprintf(error_string, sizeof(error_string), "Device %s not found!", uri); + return (NULL); + } + + /* + * Now create a new device structure... + */ + + if ((ldev = calloc(sizeof(linux1394_dev_t), 1)) == NULL) + { + strcpy(error_string, "Out of memory!"); + return (NULL); + } + + ldev->handle = raw1394_new_handle(); + ldev->node = nodes[i].node; + ldev->addr = nodes[i].addr; + + raw1394_set_port(ldev->handle, nodes[i].port); + + error_string[0] = '\0'; + + return ((ieee1394_dev_t)ldev); +} + + +/* + * 'ieee1394_close()' - Close a printer device. + */ + +int /* O - 0 on success, -1 on failure */ +ieee1394_close(ieee1394_dev_t dev) /* I - Printer device */ +{ + linux1394_dev_t *ldev; /* Linux device */ + + + ldev = (linux1394_dev_t *)dev; + + raw1394_destroy_handle(ldev->handle); + + free(ldev); + + return (0); +} + + +/* + * 'ieee1394_read()' - Read from a printer device. + */ + +int /* O - Number of bytes read or -1 */ +ieee1394_read(ieee1394_dev_t dev, /* I - Printer device */ + char *buffer, /* I - Read buffer */ + int len) /* I - Max bytes to read */ +{ + linux1394_dev_t *ldev; /* Linux device */ + + + ldev = (linux1394_dev_t *)dev; + + + return (0); +} + + +/* + * 'ieee1394_write()' - Write data to a printer device. + */ + +int /* O - Number of bytes written or -1 */ +ieee1394_write(ieee1394_dev_t dev, /* I - Printer device */ + char *buffer, /* I - Buffer to write */ + int len) /* I - Number of bytes to write */ +{ + linux1394_dev_t *ldev; /* Linux device */ + + + ldev = (linux1394_dev_t *)dev; + + +/* if (raw1394_write(handle, 0xffc0 | j, 0, , + (quadlet_t *)guid) < 0)*/ + + return (len); +} + + +/* + * 'ieee1394_error()' - Return the last error. + */ + +const char * /* O - Error string or NULL */ +ieee1394_error(void) +{ + if (error_string[0]) + return (error_string); + else + return (NULL); +} + + +/* + * End of "$Id: ieee1394-linux.c 4703 2005-09-26 19:33:58Z mike $". + */ diff --git a/backend/ieee1394.c b/backend/ieee1394.c new file mode 100644 index 000000000..0be210581 --- /dev/null +++ b/backend/ieee1394.c @@ -0,0 +1,263 @@ +/* + * "$Id: ieee1394.c 4494 2005-02-18 02:18:11Z mike $" + * + * IEEE-1394 backend for the Common UNIX Printing System (CUPS). + * + * Copyright 2002 by Easy Software Products, all rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use + * of this software must display the following + * acknowledgement: + * + * This product includes software developed by Easy + * Software Products. + * + * 4. The name of Easy Software Products may not be used to + * endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Contents: + * + * main() - Send a file to the printer. + * list_devices() - List all known printer devices... + */ + +/* + * Include necessary headers. + */ + +#include "ieee1394.h" + + +/* + * Local functions... + */ + +void list_devices(void); + + +/* + * 'main()' - Send a file to the printer. + * + * 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 */ +{ + ieee1394_dev_t dev; /* Printer device */ + int fp; /* Print file */ + int copies; /* Number of copies to print */ + int rbytes; /* Number of bytes read from device */ + size_t nbytes, /* Number of bytes read from file */ + tbytes; /* Total number of bytes written */ + char buffer[8192]; /* Input/output buffer */ +#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) + { + 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 = 0; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = open(argv[6], O_RDONLY)) < 0) + { + perror("ERROR: unable to open print file"); + return (1); + } + + copies = atoi(argv[4]); + } + + /* + * Try to open the printer device... + */ + + do + { + if ((dev = ieee1394_open(argv[0])) == NULL) + { + fputs("INFO: Firewire printer busy; will retry in 30 seconds...\n", stderr); + sleep(30); + } + } + while (dev == NULL); + + /* + * 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 != 0) + { + fputs("PAGE: 1 1\n", stderr); + lseek(fp, 0, SEEK_SET); + } + + tbytes = 0; + while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + + if (ieee1394_write(dev, buffer, nbytes) < 0) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + + if ((rbytes = ieee1394_read(dev, buffer, sizeof(buffer))) > 0) + fprintf(stderr, "INFO: Read %d bytes from printer...\n", rbytes); + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %lu bytes...\n", + (unsigned long)tbytes); + } + } + + /* + * Close the printer device and input file and return... + */ + + ieee1394_close(dev); + + if (fp != 0) + close(fp); + + fputs("INFO: Ready to print.\n", stderr); + + return (0); +} + + +/* + * 'list_devices()' - List all known devices... + */ + +void +list_devices(void) +{ + int i, /* Looping var */ + num_info; /* Number of devices */ + ieee1394_info_t *info; /* Devices... */ + + + /* + * Get the available devices... + */ + + info = ieee1394_list(&num_info); + + /* + * List them as needed... + */ + + if (num_info > 0) + { + for (i = 0; i < num_info; i ++) + printf("direct %s \"%s\" \"%s\"\n", info[i].uri, + info[i].make_model, info[i].description); + + free(info); + } +} + + +/* + * End of "$Id: ieee1394.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/backend/ieee1394.h b/backend/ieee1394.h new file mode 100644 index 000000000..19181c5c0 --- /dev/null +++ b/backend/ieee1394.h @@ -0,0 +1,103 @@ +/* + * "$Id: ieee1394.h 4494 2005-02-18 02:18:11Z mike $" + * + * IEEE-1394 header for the Common UNIX Printing System (CUPS). + * + * Copyright 2002 by Easy Software Products, all rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use + * of this software must display the following + * acknowledgement: + * + * This product includes software developed by Easy + * Software Products. + * + * 4. The name of Easy Software Products may not be used to + * endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +#else +# include +# include +#endif /* WIN32 */ + + +/* + * Device information structure... + */ + +typedef struct +{ + char uri[HTTP_MAX_URI], /* Device URI */ + description[128], /* Description of port */ + make_model[128]; /* Make and model */ +} ieee1394_info_t; + + +/* + * Private device connection information... + */ + +typedef void *ieee1394_dev_t; + + +/* + * Prototypes for standard IEEE-1394 interface... + */ + +extern ieee1394_info_t *ieee1394_list(int *num_devices); +extern ieee1394_dev_t ieee1394_open(const char *uri); +extern int ieee1394_close(ieee1394_dev_t dev); +extern int ieee1394_read(ieee1394_dev_t dev, char *buffer, int len); +extern int ieee1394_write(ieee1394_dev_t dev, char *buffer, int len); +extern const char *ieee1394_error(void); + + +/* + * End of "$Id: ieee1394.h 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/backend/ipp.c b/backend/ipp.c new file mode 100644 index 000000000..47cee2b91 --- /dev/null +++ b/backend/ipp.c @@ -0,0 +1,1468 @@ +/* + * "$Id: ipp.c 4906 2006-01-10 20:53:28Z mike $" + * + * IPP backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Send a file to the printer or server. + * check_printer_state() - Check the printer state... + * password_cb() - Disable the password prompt for + * cupsDoFileRequest(). + * report_printer_state() - Report the printer state. + * run_pictwps_filter() - Convert PICT files to PostScript when printing + * remotely. + * sigterm_handler() - Handle 'terminate' signals that stop the backend. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Globals... + */ + +static char *password = NULL; /* Password for device URI */ +#ifdef __APPLE__ +static char pstmpname[1024] = ""; /* Temporary PostScript file name */ +#endif /* __APPLE__ */ +static char tmpfilename[1024] = ""; /* Temporary spool file name */ + + +/* + * Local functions... + */ + +void check_printer_state(http_t *http, cups_lang_t *language, + const char *charset, const char *uri, /* I - Printer URI */ + const char *resource, const char *user, + int version); +const char *password_cb(const char *); +int report_printer_state(ipp_t *ipp); + +#ifdef __APPLE__ +int run_pictwps_filter(char **argv, const char *filename); +#endif /* __APPLE__ */ +static void sigterm_handler(int sig); + + +/* + * '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) */ + *optptr, /* Pointer to URI options */ + name[255], /* Name of option */ + value[255], /* Value of option */ + *ptr; /* Pointer into name or value */ + char *filename; /* 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 */ + int waitjob, /* Wait for job complete? */ + waitprinter; /* Wait for printer ready? */ + ipp_attribute_t *job_id_attr; /* job-id attribute */ + int job_id; /* job-id value */ + ipp_attribute_t *job_sheets; /* job-media-sheets-completed attribute */ + 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 */ + ipp_attribute_t *printer_state; /* printer-state attribute */ + ipp_attribute_t *printer_accepting; /* printer-is-accepting-jobs 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 */ + static const char * const pattrs[] = + { /* Printer attributes we want */ + "copies-supported", + "charset-supported", + "document-format-supported", + "printer-is-accepting-jobs", + "printer-state", + "printer-state-reasons", + }; + static const char * const jattrs[] = + { /* Job attributes we want */ + "job-media-sheets-completed", + "job-state" + }; + + + /* + * Make sure status messages are not buffered... + */ + + setbuf(stderr, NULL); + + /* + * Ignore SIGPIPE and catch SIGTERM signals... + */ + +#ifdef HAVE_SIGSET + sigset(SIGPIPE, SIG_IGN); + sigset(SIGTERM, sigterm_handler); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + 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 + signal(SIGPIPE, SIG_IGN); + signal(SIGTERM, sigterm_handler); +#endif /* HAVE_SIGSET */ + + /* + * 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 (CUPS_BACKEND_OK); + } + else if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (CUPS_BACKEND_STOP); + } + + /* + * Get the content type... + */ + + if (argc > 6) + content_type = getenv("CONTENT_TYPE"); + else + content_type = "application/vnd.cups-raw"; + + if (content_type == NULL) + content_type = "application/octet-stream"; + + /* + * Extract the hostname and printer name from the URI... + */ + + if (getenv("DEVICE_URI") != NULL) + /* authentication information is only available in the env var */ + httpSeparateURI(getenv("DEVICE_URI"), method, sizeof(method), + username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + else if (strchr(argv[0], ':') != NULL) + httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + else + { + fputs("ERROR: Missing device URI on command-line and no DEVICE_URI environment variable!\n", + stderr); + return (CUPS_BACKEND_STOP); + } + + if (!strcmp(method, "https")) + cupsSetEncryption(HTTP_ENCRYPT_ALWAYS); + + /* + * 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(tmpfilename, sizeof(tmpfilename))) < 0) + { + perror("ERROR: unable to create temporary file"); + return (CUPS_BACKEND_FAILED); + } + + 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(tmpfilename); + return (CUPS_BACKEND_FAILED); + } + + close(fd); + filename = tmpfilename; + } + else + filename = argv[6]; + + /* + * See if there are any options... + */ + + version = 1; + waitjob = 1; + waitprinter = 1; + + if ((optptr = strchr(resource, '?')) != NULL) + { + /* + * Yup, terminate the device name string and move to the first + * character of the optptr... + */ + + *optptr++ = '\0'; + + /* + * Then parse the optptr... + */ + + while (*optptr) + { + /* + * Get the name... + */ + + for (ptr = name; *optptr && *optptr != '=';) + if (ptr < (name + sizeof(name) - 1)) + *ptr++ = *optptr++; + *ptr = '\0'; + + if (*optptr == '=') + { + /* + * Get the value... + */ + + optptr ++; + + for (ptr = value; *optptr && *optptr != '+' && *optptr != '&';) + if (ptr < (value + sizeof(value) - 1)) + *ptr++ = *optptr++; + *ptr = '\0'; + + if (*optptr == '+') + optptr ++; + } + else + value[0] = '\0'; + + /* + * Process the option... + */ + + if (!strcasecmp(name, "waitjob")) + { + /* + * Wait for job completion? + */ + + waitjob = !strcasecmp(value, "on") || + !strcasecmp(value, "yes") || + !strcasecmp(value, "true"); + } + else if (!strcasecmp(name, "waitprinter")) + { + /* + * Wait for printer idle? + */ + + waitprinter = !strcasecmp(value, "on") || + !strcasecmp(value, "yes") || + !strcasecmp(value, "true"); + } + else if (!strcasecmp(name, "encryption")) + { + /* + * Enable/disable encryption? + */ + + if (!strcasecmp(value, "always")) + cupsSetEncryption(HTTP_ENCRYPT_ALWAYS); + else if (!strcasecmp(value, "required")) + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + else if (!strcasecmp(value, "never")) + cupsSetEncryption(HTTP_ENCRYPT_NEVER); + else if (!strcasecmp(value, "ifrequested")) + cupsSetEncryption(HTTP_ENCRYPT_IF_REQUESTED); + else + { + fprintf(stderr, "ERROR: Unknown encryption option value \"%s\"!\n", + value); + } + } + else if (!strcasecmp(name, "version")) + { + if (!strcmp(value, "1.0")) + version = 0; + else if (!strcmp(value, "1.1")) + version = 1; + else + { + fprintf(stderr, "ERROR: Unknown version option value \"%s\"!\n", + value); + } + } + else + { + /* + * Unknown option... + */ + + fprintf(stderr, "ERROR: Unknown option \"%s\" with value \"%s\"!\n", + name, value); + } + } + } + + /* + * Set the authentication info, if any... + */ + + cupsSetPasswordCB(password_cb); + + if (username[0]) + { + /* + * Use authenticaion information in the device URI... + */ + + if ((password = strchr(username, ':')) != NULL) + *password++ = '\0'; + + cupsSetUser(username); + } + else if (!getuid()) + { + /* + * Try loading authentication information from the a##### file. + */ + + const char *request_root; /* CUPS_REQUESTROOT env var */ + char afilename[1024], /* a##### filename */ + aline[1024]; /* Line from file */ + FILE *fp; /* File pointer */ + + + if ((request_root = getenv("CUPS_REQUESTROOT")) != NULL) + { + /* + * Try opening authentication cache file... + */ + + snprintf(afilename, sizeof(afilename), "%s/a%05d", request_root, + atoi(argv[1])); + if ((fp = fopen(afilename, "r")) != NULL) + { + /* + * Read username... + */ + + if (fgets(aline, sizeof(aline), fp)) + { + /* + * Decode username... + */ + + i = sizeof(username); + httpDecode64_2(username, &i, aline); + + /* + * Read password... + */ + + if (fgets(aline, sizeof(aline), fp)) + { + /* + * Decode password... + */ + + i = sizeof(password); + httpDecode64_2(password, &i, aline); + } + } + + /* + * Close the file... + */ + + fclose(fp); + } + } + } + + /* + * Try connecting to the remote server... + */ + + do + { + fprintf(stderr, "INFO: Connecting to %s on port %d...\n", hostname, port); + + if ((http = httpConnectEncrypt(hostname, port, cupsEncryption())) == NULL) + { + if (getenv("CLASS") != NULL) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fprintf(stderr, "INFO: Unable to connect to %s, queuing on next printer in class...\n", + hostname); + + if (argc == 6 || strcmp(filename, argv[6])) + unlink(filename); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (CUPS_BACKEND_FAILED); + } + + if (errno == ECONNREFUSED || errno == EHOSTDOWN || + errno == EHOSTUNREACH) + { + fprintf(stderr, "INFO: Network host \'%s\' is busy; will retry in 30 seconds...\n", + hostname); + sleep(30); + } + else if (h_errno) + { + fprintf(stderr, "INFO: Unable to lookup host \'%s\' - %s\n", + hostname, hstrerror(h_errno)); + sleep(30); + } + else + { + perror("ERROR: Unable to connect to IPP host"); + sleep(30); + } + } + } + while (http == NULL); + + fprintf(stderr, "INFO: Connected to %s...\n", hostname); + + /* + * 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; + 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); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", sizeof(pattrs) / sizeof(pattrs[0]), + NULL, pattrs); + + /* + * Do the request... + */ + + fputs("DEBUG: Getting supported attributes...\n", stderr); + + 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; + httpReconnect(http); + } + else if (ipp_status == IPP_NOT_FOUND) + { + fputs("ERROR: Destination printer does not exist!\n", stderr); + + if (supported) + ippDelete(supported); + + return (CUPS_BACKEND_STOP); + } + else + { + fprintf(stderr, "ERROR: Unable to get printer status (%s)!\n", + ippErrorString(ipp_status)); + sleep(10); + } + + 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); + + /* + * See if the printer is accepting jobs and is not stopped; if either + * condition is true and we are printing to a class, requeue the job... + */ + + if (getenv("CLASS") != NULL) + { + printer_state = ippFindAttribute(supported, "printer-state", + IPP_TAG_ENUM); + printer_accepting = ippFindAttribute(supported, "printer-is-accepting-jobs", + IPP_TAG_BOOLEAN); + + if (printer_state == NULL || + (printer_state->values[0].integer > IPP_PRINTER_PROCESSING && waitprinter) || + printer_accepting == NULL || + !printer_accepting->values[0].boolean) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fprintf(stderr, "INFO: Unable to queue job on %s, queuing on next printer in class...\n", + hostname); + + ippDelete(supported); + httpClose(http); + + if (argc == 6 || strcmp(filename, argv[6])) + unlink(filename); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (CUPS_BACKEND_FAILED); + } + } + + /* + * 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); + +#ifdef __APPLE__ + if (content_type != NULL && strcasecmp(content_type, "application/pictwps") == 0) + { + if (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 (format_sup == NULL || i >= format_sup->num_values) + { + /* + * Remote doesn't support "application/pictwps" (i.e. it's not MacOS X) + * so convert the document to PostScript... + */ + + if (run_pictwps_filter(argv, filename)) + return (CUPS_BACKEND_FAILED); + + filename = pstmpname; + + /* + * Change the MIME type to application/postscript... + */ + + content_type = "application/postscript"; + } + } +#endif /* __APPLE__ */ + + 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); + + /* + * If copies aren't supported, then we are likely dealing with an HP + * JetDirect. The HP IPP implementation seems to close the connection + * after every request (that is, it does *not* implement HTTP Keep- + * Alive, which is REQUIRED by HTTP/1.1... + */ + + if (!copies_sup) + httpReconnect(http); + + /* + * 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("NOTICE: Print file accepted - job ID unknown.\n", stderr); + job_id = 0; + } + else + { + job_id = job_id_attr->values[0].integer; + fprintf(stderr, "NOTICE: 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; + else + copies --; + + /* + * Wait for the job to complete... + */ + + if (!job_id || !waitjob) + 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); + + if (argv[2][0]) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, argv[2]); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", sizeof(jattrs) / sizeof(jattrs[0]), + NULL, jattrs); + + /* + * Do the request... + */ + + if (!copies_sup) + httpReconnect(http); + + 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; + } + } + + if (response != NULL) + { + 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) + { + if ((job_sheets = ippFindAttribute(response, "job-media-sheets-completed", + IPP_TAG_INTEGER)) != NULL) + fprintf(stderr, "PAGE: total %d\n", job_sheets->values[0].integer); + + ippDelete(response); + break; + } + } + } + + if (response) + ippDelete(response); + + /* + * Check the printer state and report it if necessary... + */ + +/* if (!copies_sup) + httpReconnect(http);*/ + + check_printer_state(http, language, charset, uri, resource, argv[2], + version); + + /* + * Wait 10 seconds before polling again... + */ + + sleep(10); + } + } + + /* + * Check the printer state and report it if necessary... + */ + +/* if (!copies_sup) + httpReconnect(http);*/ + + check_printer_state(http, language, charset, uri, resource, argv[2], version); + + /* + * Free memory... + */ + + httpClose(http); + + if (supported) + ippDelete(supported); + + /* + * Remove the temporary file(s) if necessary... + */ + + if (tmpfilename[0]) + unlink(tmpfilename); + +#ifdef __APPLE__ + if (pstmpname[0]) + unlink(pstmpname); +#endif /* __APPLE__ */ + + /* + * Return the queue status... + */ + + return (ipp_status > IPP_OK_CONFLICT ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); +} + + +/* + * 'check_printer_state()' - Check the printer state... + */ + +void +check_printer_state(http_t *http, /* I - HTTP connection */ + cups_lang_t *language, + /* I - Language */ + const char *charset, + /* I - Charset */ + const char *uri, /* I - Printer URI */ + const char *resource, + /* I - Resource path */ + const char *user, /* I - Username, if any */ + int version)/* I - IPP version */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + + + /* + * 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); + + if (user && user[0]) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, user); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "printer-state-reasons"); + + /* + * Do the request... + */ + + if ((response = cupsDoRequest(http, request, resource)) != NULL) + { + report_printer_state(response); + ippDelete(response); + } +} + + +/* + * 'password_cb()' - Disable the password prompt for cupsDoFileRequest(). + */ + +const char * /* O - Password */ +password_cb(const char *prompt) /* I - Prompt (not used) */ +{ + (void)prompt; + + if (password) + return (password); + else + { + /* + * If there is no password set in the device URI, return the + * "authentication required" exit code... + */ + + if (tmpfilename[0]) + unlink(tmpfilename); + +#ifdef __APPLE__ + if (pstmpname[0]) + unlink(pstmpname); +#endif /* __APPLE__ */ + + exit(CUPS_BACKEND_AUTH_REQUIRED); + } +} + + +/* + * '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 *reason; /* Current reason */ + const char *message; /* Message to show */ + char unknown[1024]; /* Unknown message string */ + const char *prefix; /* Prefix for STATE: line */ + char state[1024]; /* State string */ + + + if ((reasons = ippFindAttribute(ipp, "printer-state-reasons", + IPP_TAG_KEYWORD)) == NULL) + return (0); + + state[0] = '\0'; + prefix = "STATE: "; + + for (i = 0, count = 0; i < reasons->num_values; i ++) + { + reason = reasons->values[i].string.text; + + strlcat(state, prefix, sizeof(state)); + strlcat(state, reason, sizeof(state)); + + prefix = ","; + message = NULL; + + if (!strncmp(reason, "media-needed", 12)) + message = "Media tray needs to be filled."; + else if (!strncmp(reason, "media-jam", 9)) + message = "Media jam!"; + else if (!strncmp(reason, "moving-to-paused", 16) || + !strncmp(reason, "paused", 6) || + !strncmp(reason, "shutdown", 8)) + message = "Printer off-line."; + else if (!strncmp(reason, "toner-low", 9)) + message = "Toner low."; + else if (!strncmp(reason, "toner-empty", 11)) + message = "Out of toner!"; + else if (!strncmp(reason, "cover-open", 10)) + message = "Cover open."; + else if (!strncmp(reason, "interlock-open", 14)) + message = "Interlock open."; + else if (!strncmp(reason, "door-open", 9)) + message = "Door open."; + else if (!strncmp(reason, "input-tray-missing", 18)) + message = "Media tray missing!"; + else if (!strncmp(reason, "media-low", 9)) + message = "Media tray almost empty."; + else if (!strncmp(reason, "media-empty", 11)) + message = "Media tray empty!"; + else if (!strncmp(reason, "output-tray-missing", 19)) + message = "Output tray missing!"; + else if (!strncmp(reason, "output-area-almost-full", 23)) + message = "Output bin almost full."; + else if (!strncmp(reason, "output-area-full", 16)) + message = "Output bin full!"; + else if (!strncmp(reason, "marker-supply-low", 17)) + message = "Ink/toner almost empty."; + else if (!strncmp(reason, "marker-supply-empty", 19)) + message = "Ink/toner empty!"; + else if (!strncmp(reason, "marker-waste-almost-full", 24)) + message = "Ink/toner waste bin almost full."; + else if (!strncmp(reason, "marker-waste-full", 17)) + message = "Ink/toner waste bin full!"; + else if (!strncmp(reason, "fuser-over-temp", 15)) + message = "Fuser temperature high!"; + else if (!strncmp(reason, "fuser-under-temp", 16)) + message = "Fuser temperature low!"; + else if (!strncmp(reason, "opc-near-eol", 12)) + message = "OPC almost at end-of-life."; + else if (!strncmp(reason, "opc-life-over", 13)) + message = "OPC at end-of-life!"; + else if (!strncmp(reason, "developer-low", 13)) + message = "Developer almost empty."; + else if (!strncmp(reason, "developer-empty", 15)) + message = "Developer empty!"; + else if (strstr(reason, "error") != NULL) + { + message = unknown; + + snprintf(unknown, sizeof(unknown), "Unknown printer error (%s)!", + reason); + } + + 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); + } + } + + fprintf(stderr, "%s\n", state); + + return (count); +} + + +#ifdef __APPLE__ +/* + * 'run_pictwps_filter()' - Convert PICT files to PostScript when printing + * remotely. + * + * This step is required because the PICT format is not documented and + * subject to change, so developing a filter for other OS's is infeasible. + * Also, fonts required by the PICT file need to be embedded on the + * client side (which has the fonts), so we run the filter to get a + * PostScript file for printing... + */ + +int /* O - Exit status of filter */ +run_pictwps_filter(char **argv, /* I - Command-line arguments */ + const char *filename) /* I - Filename */ +{ + struct stat fileinfo; /* Print file information */ + const char *ppdfile; /* PPD file for destination printer */ + int pid; /* Child process ID */ + int fd; /* Temporary file descriptor */ + int status; /* Exit status of filter */ + const char *printer; /* PRINTER env var */ + static char ppdenv[1024]; /* PPD environment variable */ + + + /* + * First get the PPD file for the printer... + */ + + printer = getenv("PRINTER"); + if (!printer) + { + fputs("ERROR: PRINTER environment variable not defined!\n", stderr); + return (-1); + } + + if ((ppdfile = cupsGetPPD(printer)) == NULL) + { + fprintf(stderr, "ERROR: Unable to get PPD file for printer \"%s\" - %s.\n", + printer, ippErrorString(cupsLastError())); + /*return (-1);*/ + } + else + { + snprintf(ppdenv, sizeof(ppdenv), "PPD=%s", ppdfile); + putenv(ppdenv); + } + + /* + * Then create a temporary file for printing... + */ + + if ((fd = cupsTempFd(pstmpname, sizeof(pstmpname))) < 0) + { + fprintf(stderr, "ERROR: Unable to create temporary file - %s.\n", + strerror(errno)); + if (ppdfile) + unlink(ppdfile); + return (-1); + } + + /* + * Get the owner of the spool file - it is owned by the user we want to run + * as... + */ + + if (argv[6]) + stat(argv[6], &fileinfo); + else + { + /* + * Use the OSX defaults, as an up-stream filter created the PICT + * file... + */ + + fileinfo.st_uid = 1; + fileinfo.st_gid = 80; + } + + if (ppdfile) + chown(ppdfile, fileinfo.st_uid, fileinfo.st_gid); + + fchown(fd, fileinfo.st_uid, fileinfo.st_gid); + + /* + * Finally, run the filter to convert the file... + */ + + if ((pid = fork()) == 0) + { + /* + * Child process for pictwpstops... Redirect output of pictwpstops to a + * file... + */ + + close(1); + dup(fd); + close(fd); + + if (!getuid()) + { + /* + * Change to an unpriviledged user... + */ + + setgid(fileinfo.st_gid); + setuid(fileinfo.st_uid); + } + + execlp("pictwpstops", printer, argv[1], argv[2], argv[3], argv[4], argv[5], + filename, NULL); + perror("ERROR: Unable to exec pictwpstops"); + return (errno); + } + + close(fd); + + if (pid < 0) + { + /* + * Error! + */ + + perror("ERROR: Unable to fork pictwpstops"); + unlink(filename); + if (ppdfile) + unlink(ppdfile); + return (-1); + } + + /* + * Now wait for the filter to complete... + */ + + if (wait(&status) < 0) + { + perror("ERROR: Unable to wait for pictwpstops"); + close(fd); + unlink(filename); + if (ppdfile) + unlink(ppdfile); + return (-1); + } + + if (ppdfile) + unlink(ppdfile); + + close(fd); + + if (status) + { + if (status >= 256) + fprintf(stderr, "ERROR: pictwpstops exited with status %d!\n", + status / 256); + else + fprintf(stderr, "ERROR: pictwpstops exited on signal %d!\n", + status); + + unlink(filename); + return (status); + } + + /* + * Return with no errors.. + */ + + return (0); +} +#endif /* __APPLE__ */ + + +/* + * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend. + */ + +static void +sigterm_handler(int sig) /* I - Signal */ +{ + (void)sig; /* remove compiler warnings... */ + + /* + * Remove the temporary file(s) if necessary... + */ + + if (tmpfilename[0]) + unlink(tmpfilename); + +#ifdef __APPLE__ + if (pstmpname[0]) + unlink(pstmpname); +#endif /* __APPLE__ */ + + exit(1); +} + + +/* + * End of "$Id: ipp.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/backend/lpd.c b/backend/lpd.c new file mode 100644 index 000000000..ee6d3deaa --- /dev/null +++ b/backend/lpd.c @@ -0,0 +1,1149 @@ +/* + * "$Id: lpd.c 4906 2006-01-10 20:53:28Z mike $" + * + * Line Printer Daemon backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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_timeout() - Handle timeout alarms... + * lpd_write() - Write a buffer of data to an LPD server. + * rresvport_af() - A simple implementation of rresvport_af(). + * sigterm_handler() - Handle 'terminate' signals that stop the backend. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +#endif /* WIN32 */ + + +/* + * Globals... + */ + +static char tmpfilename[1024] = ""; /* Temporary spool file name */ +static int abort_job = 0; /* Non-zero if we get SIGTERM */ + + +/* + * The order for control and data files in LPD requests... + */ + +#define ORDER_CONTROL_DATA 0 /* Control file first, then data */ +#define ORDER_DATA_CONTROL 1 /* Data file first, then control */ + + +/* + * What to reserve... + */ + +#define RESERVE_NONE 0 /* Don't reserve a priviledged port */ +#define RESERVE_RFC1179 1 /* Reserve port 721-731 */ +#define RESERVE_ANY 2 /* Reserve port 1-1023 */ + + +/* + * Local functions... + */ + +static int lpd_command(int lpd_fd, int timeout, char *format, ...); +static int lpd_queue(const char *hostname, int port, const char *printer, + const char *filename, + const char *user, const char *title, int copies, + int banner, int format, int order, int reserve, + int manual_copies, int timeout); +static void lpd_timeout(int sig); +static int lpd_write(int lpd_fd, char *buffer, int length); +#ifndef HAVE_RRESVPORT_AF +static int rresvport_af(int *port, int family); +#endif /* !HAVE_RRESVPORT_AF */ +static void sigterm_handler(int sig); + + +/* + * '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 */ + 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, /* File to print */ + title[256]; /* Title string */ + int port; /* Port number */ + int status; /* Status of LPD job */ + int banner; /* Print banner page? */ + int format; /* Print format */ + int order; /* Order of control/data files */ + int reserve; /* Reserve priviledged port? */ + int sanitize_title; /* Sanitize title string? */ + int manual_copies, /* Do manual copies? */ + timeout, /* Timeout */ + copies; /* Number of copies */ +#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); + + /* + * Ignore SIGPIPE and catch SIGTERM signals... + */ + +#ifdef HAVE_SIGSET + sigset(SIGPIPE, SIG_IGN); + sigset(SIGTERM, sigterm_handler); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + 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 + signal(SIGPIPE, SIG_IGN); + signal(SIGTERM, sigterm_handler); +#endif /* HAVE_SIGSET */ + + /* + * Check command-line... + */ + + if (argc == 1) + { + puts("network lpd \"Unknown\" \"LPD/LPR Host or Printer\""); + return (CUPS_BACKEND_OK); + } + else if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (CUPS_BACKEND_FAILED); + } + + /* + * 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(tmpfilename, sizeof(tmpfilename))) < 0) + { + perror("ERROR: unable to create temporary file"); + return (CUPS_BACKEND_FAILED); + } + + 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(tmpfilename); + return (CUPS_BACKEND_FAILED); + } + + close(fd); + filename = tmpfilename; + } + else + filename = argv[6]; + + /* + * Extract the hostname and printer name from the URI... + */ + + httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + + if (!username[0]) + { + /* + * If no username is in the device URI, then use the print job user... + */ + + strlcpy(username, argv[2], sizeof(username)); + } + + /* + * See if there are any options... + */ + + banner = 0; + format = 'l'; + order = ORDER_CONTROL_DATA; + reserve = RESERVE_ANY; + manual_copies = 1; + timeout = 300; + sanitize_title = 1; + +#if defined(__APPLE__) + /* We want to pass utf-8 characters, not re-map them (3071945) */ + sanitize_title= 0; +#endif + + 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 != '=';) + if (ptr < (name + sizeof(name) - 1)) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '=') + { + /* + * Get the value... + */ + + options ++; + + for (ptr = value; *options && *options != '+' && *options != '&';) + if (ptr < (value + sizeof(value) - 1)) + *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); + } + else if (strcasecmp(name, "reserve") == 0) + { + /* + * Set port reservation mode... + */ + + if (!value[0] || + !strcasecmp(value, "on") || + !strcasecmp(value, "yes") || + !strcasecmp(value, "true") || + !strcasecmp(value, "rfc1179")) + reserve = RESERVE_RFC1179; + else if (!strcasecmp(value, "any")) + reserve = RESERVE_ANY; + else + reserve = RESERVE_NONE; + } + else if (strcasecmp(name, "manual_copies") == 0) + { + /* + * Set manual copies... + */ + + manual_copies = !value[0] || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "yes") == 0 || + strcasecmp(value, "true") == 0; + } + else if (strcasecmp(name, "sanitize_title") == 0) + { + /* + * Set sanitize title... + */ + + sanitize_title = !value[0] || + strcasecmp(value, "on") == 0 || + strcasecmp(value, "yes") == 0 || + strcasecmp(value, "true") == 0; + } + else if (strcasecmp(name, "timeout") == 0) + { + /* + * Set the timeout... + */ + + if (atoi(value) > 0) + timeout = atoi(value); + } + } + } + + /* + * Sanitize the document title... + */ + + strlcpy(title, argv[3], sizeof(title)); + + if (sanitize_title) + { + /* + * Sanitize the title string so that we don't cause problems on + * the remote end... + */ + + for (ptr = title; *ptr; ptr ++) + if (!isalnum(*ptr & 255) && !isspace(*ptr & 255)) + *ptr = '_'; + } + + /* + * Queue the job... + */ + + if (argc > 6) + { + if (manual_copies) + { + manual_copies = atoi(argv[4]); + copies = 1; + } + else + { + manual_copies = 1; + copies = atoi(argv[4]); + } + + status = lpd_queue(hostname, port, resource + 1, filename, + username, title, copies, + banner, format, order, reserve, manual_copies, timeout); + + if (!status) + fprintf(stderr, "PAGE: 1 %d\n", atoi(argv[4])); + } + else + status = lpd_queue(hostname, port, resource + 1, filename, + username, title, 1, + banner, format, order, reserve, 1, timeout); + + /* + * Remove the temporary file if necessary... + */ + + if (tmpfilename[0]) + unlink(tmpfilename); + + /* + * 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 */ + int timeout, /* I - Seconds to wait for a response */ + 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 */ + + + /* + * Don't try to send commands if the job has been cancelled... + */ + + if (abort_job) + return (-1); + + /* + * 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) + { + perror("ERROR: Unable to send LPD command"); + return (-1); + } + + /* + * Read back the status from the command and return it... + */ + + fprintf(stderr, "DEBUG: Reading command status...\n"); + + alarm(timeout); + + if (recv(fd, &status, 1, 0) < 1) + { + fprintf(stderr, "WARNING: Remote host did not respond with command " + "status byte after %d seconds!\n", timeout); + status = errno; + } + + alarm(0); + + 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(const char *hostname, /* I - Host to connect to */ + int port, /* I - Port to connect on */ + const char *printer, /* I - Printer/queue name */ + const char *filename, /* I - File to print */ + const char *user, /* I - Requesting user */ + const 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 */ + int reserve, /* I - Reserve ports? */ + int manual_copies, /* I - Do copies by hand... */ + int timeout) /* I - Timeout... */ +{ + FILE *fp; /* Job file */ + char localhost[255]; /* Local host name */ + int error; /* Error number */ + struct stat filestats; /* File statistics */ + int lport; /* LPD connection local port */ + int fd; /* LPD socket */ + char control[10240], /* LPD control 'file' */ + *cptr; /* Pointer into control file string */ + char status; /* Status byte from command */ + char portname[255]; /* Port name */ + http_addrlist_t *addrlist, /* Address list */ + *addr; /* Socket address */ + int copy; /* Copies written */ + size_t nbytes; /* Number of bytes written */ + off_t tbytes; /* Total bytes written */ + char buffer[65536]; /* Output buffer */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * Setup an alarm handler for timeouts... + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGALRM, lpd_timeout); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = lpd_timeout; + sigaction(SIGALRM, &action, NULL); +#else + signal(SIGALRM, lpd_timeout); +#endif /* HAVE_SIGSET */ + + /* + * Find the printer... + */ + + sprintf(portname, "%d", port); + + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + { + fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n", + hostname); + return (CUPS_BACKEND_STOP); + } + + /* + * Loop forever trying to print the file... + */ + + while (!abort_job) + { + /* + * First try to reserve a port for this connection... + */ + + fprintf(stderr, "INFO: Attempting to connect to host %s for printer %s\n", + hostname, printer); + + for (lport = reserve == RESERVE_RFC1179 ? 732 : 1024, addr = addrlist;; + addr = addr->next) + { + /* + * Stop if this job has been cancelled... + */ + + if (abort_job) + { + httpAddrFreeList(addrlist); + + return (CUPS_BACKEND_FAILED); + } + + /* + * Choose the next priviledged port... + */ + + if (!addr) + addr = addrlist; + + lport --; + + if (lport < 721 && reserve == RESERVE_RFC1179) + lport = 731; + else if (lport < 1) + lport = 1023; + +#ifdef HAVE_GETEUID + if (geteuid() || !reserve) +#else + if (getuid() || !reserve) +#endif /* HAVE_GETEUID */ + { + /* + * Just create a regular socket... + */ + + if ((fd = socket(addr->addr.addr.sa_family, SOCK_STREAM, 0)) < 0) + { + perror("ERROR: Unable to create socket"); + sleep(1); + + continue; + } + + lport = 0; + } + else + { + /* + * We're running as root and want to comply with RFC 1179. Reserve a + * priviledged lport between 721 and 731... + */ + + if ((fd = rresvport_af(&lport, addr->addr.addr.sa_family)) < 0) + { + perror("ERROR: Unable to reserve port"); + sleep(1); + + continue; + } + } + + /* + * Connect to the printer or server... + */ + + if (abort_job) + { + httpAddrFreeList(addrlist); + + close(fd); + + return (CUPS_BACKEND_FAILED); + } + + if (!connect(fd, &(addr->addr.addr), httpAddrLength(&(addr->addr)))) + break; + + error = errno; + close(fd); + fd = -1; + + if (addr->next) + continue; + + if (getenv("CLASS") != NULL) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fprintf(stderr, "INFO: Unable to connect to %s, queuing on next printer in class...\n", + hostname); + + httpAddrFreeList(addrlist); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (CUPS_BACKEND_FAILED); + } + + if (error == ECONNREFUSED || error == EHOSTDOWN || + error == EHOSTUNREACH) + { + fprintf(stderr, "WARNING: Network host \'%s\' is busy, down, or unreachable; will retry in 30 seconds...\n", + hostname); + sleep(30); + } + else if (error == EADDRINUSE) + { + /* + * Try on another port... + */ + + sleep(1); + } + else + { + perror("ERROR: Unable to connect to printer; will retry in 30 seconds..."); + sleep(30); + } + } + + fprintf(stderr, "INFO: Connected to %s...\n", hostname); + fprintf(stderr, "DEBUG: Connected on ports %d (local %d)...\n", port, + lport); + + /* + * Next, open the print file and figure out its size... + */ + + if (stat(filename, &filestats)) + { + httpAddrFreeList(addrlist); + close(fd); + + perror("ERROR: unable to stat print file"); + return (CUPS_BACKEND_FAILED); + } + + filestats.st_size *= manual_copies; + + if ((fp = fopen(filename, "rb")) == NULL) + { + httpAddrFreeList(addrlist); + close(fd); + + perror("ERROR: unable to open print file for reading"); + return (CUPS_BACKEND_FAILED); + } + + /* + * Send a job header to the printer, specifying no banner page and + * literal output... + */ + + if (lpd_command(fd, timeout, "\002%s\n", + printer)) /* Receive print job(s) */ + { + httpAddrFreeList(addrlist); + close(fd); + return (CUPS_BACKEND_FAILED); + } + + httpGetHostname(localhost, sizeof(localhost)); + + snprintf(control, sizeof(control), + "H%.31s\n" /* RFC 1179, Section 7.2 - host name <= 31 chars */ + "P%.31s\n" /* RFC 1179, Section 7.2 - user name <= 31 chars */ + "J%.99s\n", /* RFC 1179, Section 7.2 - job name <= 99 chars */ + localhost, user, title); + cptr = control + strlen(control); + + if (banner) + { + snprintf(cptr, sizeof(control) - (cptr - control), + "C%.31s\n" /* RFC 1179, Section 7.2 - class name <= 31 chars */ + "L%s\n", + localhost, user); + cptr += strlen(cptr); + } + + while (copies > 0) + { + snprintf(cptr, sizeof(control) - (cptr - control), "%cdfA%03d%.15s\n", + format, (int)getpid() % 1000, localhost); + cptr += strlen(cptr); + copies --; + } + + snprintf(cptr, sizeof(control) - (cptr - control), + "UdfA%03d%.15s\n" + "N%.131s\n", /* RFC 1179, Section 7.2 - sourcefile name <= 131 chars */ + (int)getpid() % 1000, localhost, title); + + fprintf(stderr, "DEBUG: Control file is:\n%s", control); + + if (order == ORDER_CONTROL_DATA) + { + if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control), + (int)getpid() % 1000, localhost)) + { + httpAddrFreeList(addrlist); + close(fd); + + return (CUPS_BACKEND_FAILED); + } + + fprintf(stderr, "INFO: Sending control file (%u bytes)\n", + (unsigned)strlen(control)); + + if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1)) + { + status = errno; + perror("ERROR: Unable to write control file"); + } + else + { + alarm(timeout); + + if (read(fd, &status, 1) < 1) + { + fprintf(stderr, "WARNING: Remote host did not respond with control " + "status byte after %d seconds!\n", timeout); + status = errno; + } + + alarm(0); + } + + 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... + */ + + if (lpd_command(fd, timeout, "\003" CUPS_LLFMT " dfA%03.3d%.15s\n", + CUPS_LLCAST filestats.st_size, (int)getpid() % 1000, + localhost)) + { + httpAddrFreeList(addrlist); + close(fd); + + return (CUPS_BACKEND_FAILED); + } + + fprintf(stderr, "INFO: Sending data file (" CUPS_LLFMT " bytes)\n", + CUPS_LLCAST filestats.st_size); + + tbytes = 0; + for (copy = 0; copy < manual_copies; copy ++) + { + rewind(fp); + + while ((nbytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) + { + fprintf(stderr, "INFO: Spooling LPR job, %.0f%% complete...\n", + 100.0 * 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) + { + perror("ERROR: Unable to send trailing nul to printer"); + status = errno; + } + else + { + /* + * Read the status byte from the printer; if we can't read the byte + * back now, we should set status to "errno", however at this point + * we know the printer got the whole file and we don't necessarily + * want to requeue it over and over... + */ + + alarm(timeout); + + if (recv(fd, &status, 1, 0) < 1) + { + fprintf(stderr, "WARNING: Remote host did not respond with data " + "status byte after %d seconds!\n", timeout); + status = 0; + } + + alarm(0); + } + + 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) + { + if (lpd_command(fd, timeout, "\002%d cfA%03.3d%.15s\n", strlen(control), + (int)getpid() % 1000, localhost)) + { + httpAddrFreeList(addrlist); + close(fd); + + return (CUPS_BACKEND_FAILED); + } + + fprintf(stderr, "INFO: Sending control file (%lu bytes)\n", + (unsigned long)strlen(control)); + + if (lpd_write(fd, control, strlen(control) + 1) < (strlen(control) + 1)) + { + status = errno; + perror("ERROR: Unable to write control file"); + } + else + { + alarm(timeout); + + if (read(fd, &status, 1) < 1) + { + fprintf(stderr, "WARNING: Remote host did not respond with control " + "status byte after %d seconds!\n", timeout); + status = errno; + } + + alarm(0); + } + + 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... + */ + + close(fd); + fclose(fp); + + if (status == 0) + { + httpAddrFreeList(addrlist); + + return (CUPS_BACKEND_OK); + } + + /* + * Waiting for a retry... + */ + + sleep(30); + } + + httpAddrFreeList(addrlist); + + /* + * If we get here, then the job has been cancelled... + */ + + return (CUPS_BACKEND_FAILED); +} + + +/* + * 'lpd_timeout()' - Handle timeout alarms... + */ + +static void +lpd_timeout(int sig) /* I - Signal number */ +{ + (void)sig; + +#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION) + signal(SIGALRM, lpd_timeout); +#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */ +} + + +/* + * '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 */ + + + if (abort_job) + return (-1); + + 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_AF +/* + * 'rresvport_af()' - A simple implementation of rresvport_af(). + */ + +static int /* O - Socket or -1 on error */ +rresvport_af(int *port, /* IO - Port number to bind to */ + int family) /* I - Address family */ +{ + http_addr_t addr; /* Socket address */ + int fd; /* Socket file descriptor */ + + + /* + * Try to create an IPv4 socket... + */ + + if ((fd = socket(family, SOCK_STREAM, 0)) < 0) + return (-1); + + /* + * Initialize the address buffer... + */ + + memset(&addr, 0, sizeof(addr)); + addr.addr.sa_family = family; + + /* + * Try to bind the socket to a reserved port... + */ + + while (*port > 511) + { + /* + * Set the port number... + */ + +# ifdef AF_INET6 + if (family == AF_INET6) + addr.ipv6.sin6_port = htons(*port); + else +# endif /* AF_INET6 */ + addr.ipv4.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_AF */ + + +/* + * 'sigterm_handler()' - Handle 'terminate' signals that stop the backend. + */ + +static void +sigterm_handler(int sig) /* I - Signal */ +{ + (void)sig; /* remove compiler warnings... */ + + abort_job = 1; +} + + +/* + * End of "$Id: lpd.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/backend/parallel.c b/backend/parallel.c new file mode 100644 index 000000000..d80f8e214 --- /dev/null +++ b/backend/parallel.c @@ -0,0 +1,731 @@ +/* + * "$Id: parallel.c 4906 2006-01-10 20:53:28Z mike $" + * + * Parallel port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Send a file to the specified parallel port. + * list_devices() - List all parallel devices. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ieee1284.c" + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +#endif /* WIN32 */ + +#ifdef __sgi +# include +# ifndef INV_EPP_ECP_PLP +# define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */ +# define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */ +# define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */ +# define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */ +# define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */ +# endif /* !INV_EPP_ECP_PLP */ +#endif /* __sgi */ + + +/* + * Local functions... + */ + +void list_devices(void); + + +/* + * 'main()' - Send a file to the specified parallel port. + * + * Usage: + * + * printer-uri job-id user title copies options [file] + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments (6 or 7) */ + char *argv[]) /* I - Command-line arguments */ +{ + char method[255], /* Method in URI */ + hostname[1024], /* Hostname */ + username[255], /* Username info (not used) */ + resource[1024], /* Resource info (device and options) */ + *options; /* Pointer to options */ + int port; /* Port number (not used) */ + int fp; /* Print file */ + int copies; /* Number of copies to print */ + int fd; /* Parallel device */ + int rbytes; /* Number of bytes read */ + 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 */ + fd_set input, /* Input set for select() */ + output; /* Output set for select() */ + int paperout; /* Paper out? */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ +#ifdef __linux + unsigned int status; /* Port status (off-line, out-of-paper, etc.) */ +#endif /* __linux */ + + + /* + * Make sure status messages are not buffered... + */ + + setbuf(stderr, NULL); + + /* + * Ignore SIGPIPE signals... + */ + +#ifdef HAVE_SIGSET + sigset(SIGPIPE, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Check command-line... + */ + + if (argc == 1) + { + list_devices(); + return (CUPS_BACKEND_OK); + } + else if (argc < 6 || argc > 7) + { + fputs("Usage: parallel job-id user title copies options [file]\n", stderr); + return (CUPS_BACKEND_FAILED); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = 0; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = open(argv[6], O_RDONLY)) < 0) + { + perror("ERROR: unable to open print file"); + return (CUPS_BACKEND_FAILED); + } + + copies = atoi(argv[4]); + } + + /* + * Extract the device name and options from the URI... + */ + + httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(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 (getenv("CLASS") != NULL) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fputs("INFO: Unable to open parallel port, queuing on next printer in class...\n", + stderr); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (CUPS_BACKEND_FAILED); + } + + if (errno == EBUSY) + { + fputs("INFO: Parallel port busy; will retry in 30 seconds...\n", stderr); + sleep(30); + } + else if (errno == ENXIO || errno == EIO || errno == ENOENT) + { + fputs("INFO: Printer not connected; 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 (CUPS_BACKEND_FAILED); + } + } + } + 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); + + /* + * Check printer status... + */ + + paperout = 0; + +#if defined(__linux) && defined(LP_POUTPA) + /* + * Show the printer status before we send the file... + */ + + while (!ioctl(fd, LPGETSTATUS, &status)) + { + fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status); + + if (status & LP_POUTPA) + { + fputs("WARNING: Media tray empty!\n", stderr); + fputs("STATUS: +media-tray-empty-error\n", stderr); + + paperout = 1; + } + + if (!(status & LP_PERRORP)) + fputs("WARNING: Printer fault!\n", stderr); + else if (!(status & LP_PSELECD)) + fputs("WARNING: Printer off-line.\n", stderr); + else + break; + + sleep(5); + } +#endif /* __linux && LP_POUTPA */ + + /* + * 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... + */ + + wbytes = 0; + + while (copies > 0) + { + copies --; + + if (fp != 0) + { + fputs("PAGE: 1 1\n", stderr); + lseek(fp, 0, SEEK_SET); + } + + tbytes = 0; + while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + /* + * See if we are ready to read or write... + */ + + do + { + FD_ZERO(&input); + FD_SET(fd, &input); + FD_ZERO(&output); + FD_SET(fd, &output); + } + while (select(fd + 1, &input, &output, NULL, NULL) < 0); + + if (FD_ISSET(fd, &input)) + { + /* + * Read backchannel data... + */ + + if ((rbytes = read(fd, resource, sizeof(resource))) > 0) + { + fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n", + rbytes); + cupsBackchannelWrite(resource, rbytes, 1.0); + } + } + + if (FD_ISSET(fd, &output)) + { + /* + * Write print data... + */ + + if ((wbytes = write(fd, bufptr, nbytes)) < 0) + if (errno == ENOTTY) + wbytes = write(fd, bufptr, nbytes); + + if (wbytes < 0) + { + /* + * Check for retryable errors... + */ + + if (errno == ENOSPC) + { + paperout = 1; + fputs("ERROR: Out of paper!\n", stderr); + fputs("STATUS: +media-tray-empty-error\n", stderr); + } + else if (errno != EAGAIN && errno != EINTR) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + } + else + { + /* + * Update count and pointer... + */ + + if (paperout) + { + fputs("STATUS: -media-tray-empty-error\n", stderr); + paperout = 0; + } + + nbytes -= wbytes; + bufptr += wbytes; + } + } + } + + if (wbytes < 0) + break; + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %lu bytes...\n", + (unsigned long)tbytes); + } + } + + /* + * Close the socket connection and input file and return... + */ + + close(fd); + if (fp != 0) + close(fp); + + return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); +} + + +/* + * '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 */ + basedevice[255], /* Base device filename for ports */ + device_id[1024], /* Device ID string */ + make_model[1024]; /* Make and model */ + + + if (!access("/dev/parallel/", 0)) + strcpy(basedevice, "/dev/parallel/"); + else if (!access("/dev/printers/", 0)) + strcpy(basedevice, "/dev/printers/"); + else if (!access("/dev/par0", 0)) + strcpy(basedevice, "/dev/par"); + else + strcpy(basedevice, "/dev/lp"); + + for (i = 0; i < 4; i ++) + { + /* + * Open the port, if available... + */ + + sprintf(device, "%s%d", basedevice, i); + if ((fd = open(device, O_RDWR | O_EXCL)) < 0) + fd = open(device, O_WRONLY); + + if (fd >= 0) + { + /* + * Now grab the IEEE 1284 device ID string... + */ + + if (!get_device_id(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + NULL, NULL, 0)) + printf("direct parallel:%s \"%s\" \"%s LPT #%d\" \"%s\"\n", device, + make_model, make_model, i + 1, device_id); + else + printf("direct parallel:%s \"Unknown\" \"LPT #%d\"\n", device, i + 1); + + close(fd); + } + } +#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: parallel.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/backend/scsi-irix.c b/backend/scsi-irix.c new file mode 100644 index 000000000..097071c23 --- /dev/null +++ b/backend/scsi-irix.c @@ -0,0 +1,231 @@ +/* + * "$Id: scsi-irix.c 4703 2005-09-26 19:33:58Z mike $" + * + * IRIX SCSI printer support for the Common UNIX Printing System (CUPS). + * + * Copyright 2003-2005 by Easy Software Products, all rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use + * of this software must display the following + * acknowledgement: + * + * This product includes software developed by Easy + * Software Products. + * + * 4. The name of Easy Software Products may not be used to + * endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Contents: + * + * list_devices() - List the available SCSI printer devices. + * print_device() - Print a file to a SCSI device. + */ + +/* + * Include necessary headers. + */ + +#include /* memcpy() and friends */ +#include /* SCSI interface stuff */ + + +/* + * 'list_devices()' - List the available SCSI printer devices. + */ + +void +list_devices(void) +{ + puts("direct scsi \"Unknown\" \"SCSI Printer\""); +} + + +/* + * 'print_device()' - Print a file to a SCSI device. + */ + +int /* O - Print status */ +print_device(const char *resource, /* I - SCSI device */ + int fd, /* I - File to print */ + int copies) /* I - Number of copies to print */ +{ + int scsi_fd; /* SCSI file descriptor */ + char buffer[8192]; /* Data buffer */ + int bytes; /* Number of bytes */ + int try; /* Current try */ + dsreq_t scsi_req; /* SCSI request */ + char scsi_cmd[6]; /* SCSI command data */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * Make sure we have a valid resource name... + */ + + if (strncmp(resource, "/dev/scsi/", 10) != 0) + { + fprintf(stderr, "ERROR: Bad SCSI device file \"%s\"!\n", resource); + return (CUPS_BACKEND_STOP); + } + + /* + * Open the SCSI device file... + */ + + do + { + if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1) + { + if (getenv("CLASS") != NULL) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fputs("INFO: Unable to open SCSI device, queuing on next printer in class...\n", + stderr); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (1); + } + + if (errno != EAGAIN && errno != EBUSY) + { + fprintf(stderr, "ERROR: Unable to open SCSI device \"%s\" - %s\n", + resource, strerror(errno)); + return (CUPS_BACKEND_FAILED); + } + else + { + fprintf(stderr, "INFO: SCSI device \"%s\" busy; retrying...\n", + resource); + sleep(30); + } + } + } + while (scsi_fd == -1); + + /* + * 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 (fd != 0) + { +#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 */ + } + + /* + * Copy the print file to the device... + */ + + while (copies > 0) + { + if (fd != 0) + lseek(fd, 0, SEEK_SET); + + while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) + { + memset(&scsi_req, 0, sizeof(scsi_req)); + + scsi_req.ds_flags = DSRQ_WRITE; + scsi_req.ds_time = 60 * 1000; + scsi_req.ds_cmdbuf = scsi_cmd; + scsi_req.ds_cmdlen = 6; + scsi_req.ds_databuf = buffer; + scsi_req.ds_datalen = bytes; + + scsi_cmd[0] = 0x0a; /* Group 0 print command */ + scsi_cmd[1] = 0x00; + scsi_cmd[2] = bytes / 65536; + scsi_cmd[3] = bytes / 256; + scsi_cmd[4] = bytes; + scsi_cmd[5] = 0x00; + + for (try = 0; try < 10; try ++) + if (ioctl(scsi_fd, DS_ENTER, &scsi_req) < 0 || + scsi_req.ds_status != 0) + { + fprintf(stderr, "WARNING: SCSI command timed out (%d); retrying...\n", + scsi_req.ds_status); + sleep(try + 1); + } + else + break; + + if (try >= 10) + { + fprintf(stderr, "ERROR: Unable to send print data (%d)\n", + scsi_req.ds_status); + close(scsi_fd); + return (CUPS_BACKEND_FAILED); + } + } + + copies --; + } + + /* + * Close the device and return... + */ + + close(fd); + + return (CUPS_BACKEND_OK); +} + + +/* + * End of "$Id: scsi-irix.c 4703 2005-09-26 19:33:58Z mike $". + */ diff --git a/backend/scsi-linux.c b/backend/scsi-linux.c new file mode 100644 index 000000000..b5c1d1bef --- /dev/null +++ b/backend/scsi-linux.c @@ -0,0 +1,249 @@ +/* + * "$Id: scsi-linux.c 4703 2005-09-26 19:33:58Z mike $" + * + * Linux SCSI printer support for the Common UNIX Printing System (CUPS). + * + * Copyright 2003-2005 by Easy Software Products, all rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use + * of this software must display the following + * acknowledgement: + * + * This product includes software developed by Easy + * Software Products. + * + * 4. The name of Easy Software Products may not be used to + * endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Contents: + * + * list_devices() - List the available SCSI printer devices. + * print_device() - Print a file to a SCSI device. + */ + +/* + * Include necessary headers. + */ + +#include + + +/* + * We currently only support the Linux 2.4 generic SCSI interface. + */ + +#ifndef SG_DXFER_TO_DEV +/* + * Dummy functions that do nothing on unsupported platforms... + */ +void list_devices(void) {} +int print_device(const char *resource, int fd, int copies) { return (1); } +#else + + +/* + * 'list_devices()' - List the available SCSI printer devices. + */ + +void +list_devices(void) +{ + puts("direct scsi \"Unknown\" \"SCSI Printer\""); +} + + +/* + * 'print_device()' - Print a file to a SCSI device. + */ + +int /* O - Print status */ +print_device(const char *resource, /* I - SCSI device */ + int fd, /* I - File to print */ + int copies) /* I - Number of copies to print */ +{ + int scsi_fd; /* SCSI file descriptor */ + char buffer[8192]; /* Data buffer */ + int bytes; /* Number of bytes */ + int try; /* Current try */ + sg_io_hdr_t scsi_req; /* SCSI request */ + unsigned char scsi_cmd[6], /* SCSI command data */ + scsi_sense[32]; /* SCSI sense data */ +# if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +# endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + /* + * Make sure we have a valid resource name... + */ + + if (strncmp(resource, "/dev/sg", 7) != 0) + { + fprintf(stderr, "ERROR: Bad SCSI device file \"%s\"!\n", resource); + return (CUPS_BACKEND_STOP); + } + + /* + * Open the SCSI device file... + */ + + do + { + if ((scsi_fd = open(resource, O_RDWR | O_EXCL)) == -1) + { + if (getenv("CLASS") != NULL) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fputs("INFO: Unable to open SCSI device, queuing on next printer in class...\n", + stderr); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (CUPS_BACKEND_FAILED); + } + + if (errno != EAGAIN && errno != EBUSY) + { + fprintf(stderr, "ERROR: Unable to open SCSI device \"%s\" - %s\n", + resource, strerror(errno)); + return (CUPS_BACKEND_FAILED); + } + else + { + fprintf(stderr, "INFO: SCSI device \"%s\" busy; retrying...\n", + resource); + sleep(30); + } + } + } + while (scsi_fd == -1); + + /* + * 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 (fd != 0) + { +# 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 */ + } + + /* + * Copy the print file to the device... + */ + + while (copies > 0) + { + if (fd != 0) + lseek(fd, 0, SEEK_SET); + + while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) + { + memset(&scsi_req, 0, sizeof(scsi_req)); + + scsi_req.interface_id = 'S'; + scsi_req.dxfer_direction = SG_DXFER_TO_DEV; + scsi_req.cmd_len = 6; + scsi_req.mx_sb_len = sizeof(scsi_sense); + scsi_req.iovec_count = 0; + scsi_req.dxfer_len = bytes; + scsi_req.dxferp = buffer; + scsi_req.cmdp = scsi_cmd; + scsi_req.sbp = scsi_sense; + scsi_req.timeout = 60 * 1000; + + scsi_cmd[0] = 0x0a; /* Group 0 print command */ + scsi_cmd[1] = 0x00; + scsi_cmd[2] = bytes / 65536; + scsi_cmd[3] = bytes / 256; + scsi_cmd[4] = bytes; + scsi_cmd[5] = 0x00; + + for (try = 0; try < 10; try ++) + if (ioctl(scsi_fd, SG_IO, &scsi_req) < 0 || + scsi_req.status != 0) + { + fprintf(stderr, "WARNING: SCSI command timed out (%d); retrying...\n", + scsi_req.status); + sleep(try + 1); + } + else + break; + + if (try >= 10) + { + fprintf(stderr, "ERROR: Unable to send print data (%d)\n", + scsi_req.status); + close(scsi_fd); + return (CUPS_BACKEND_FAILED); + } + } + + copies --; + } + + /* + * Close the device and return... + */ + + close(fd); + + return (CUPS_BACKEND_OK); +} +#endif /* !SG_DXFER_TO_DEV */ + + +/* + * End of "$Id: scsi-linux.c 4703 2005-09-26 19:33:58Z mike $". + */ diff --git a/backend/scsi.c b/backend/scsi.c new file mode 100644 index 000000000..fdbc7f2f3 --- /dev/null +++ b/backend/scsi.c @@ -0,0 +1,223 @@ +/* + * "$Id: scsi.c 4906 2006-01-10 20:53:28Z mike $" + * + * SCSI printer backend for the Common UNIX Printing System (CUPS). + * + * Copyright 2003-2006 by Easy Software Products, all rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * + * 3. All advertising materials mentioning features or use + * of this software must display the following + * acknowledgement: + * + * This product includes software developed by Easy + * Software Products. + * + * 4. The name of Easy Software Products may not be used to + * endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Contents: + * + * main() - Send a file to the specified SCSI printer. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +#else +# include +# include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif /* HAVE_SYS_IOCTL_H */ +#endif /* WIN32 */ + + +/* + * Local functions... + */ + +void list_devices(void); +int print_device(const char *resource, int fd, int copies); + + +#ifdef __linux__ +# include "scsi-linux.c" +#elif defined(__sgi) +# include "scsi-irix.c" +#else +/* + * Dummy functions that do nothing on unsupported platforms... + */ +void list_devices(void) {} +int print_device(const char *resource, int fd, int copies) { return (CUPS_BACKEND_FAILED); } +#endif /* __linux */ + + +/* + * 'main()' - Send a file to the specified SCSI printer. + * + * 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) */ + int fp; /* Print file */ + int copies; /* Number of copies to print */ + int status; /* Exit status */ +#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); + + /* + * Ignore SIGPIPE signals... + */ + +#ifdef HAVE_SIGSET + sigset(SIGPIPE, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Check command-line... + */ + + if (argc == 1) + { + list_devices(); + return (CUPS_BACKEND_OK); + } + else if (argc < 6 || argc > 7) + { + fputs("Usage: scsi:/dev/file job-id user title copies options [file]\n", stderr); + return (CUPS_BACKEND_FAILED); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = 0; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = open(argv[6], O_RDONLY)) < 0) + { + perror("ERROR: unable to open print file"); + return (CUPS_BACKEND_FAILED); + } + + copies = atoi(argv[4]); + } + + /* + * Extract the device name and options from the URI... + */ + + httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(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'; + } + + /* + * Finally, send the print file... + */ + + status = print_device(resource, fp, copies); + + /* + * Close input file and return... + */ + + if (fp != 0) + close(fp); + + return (status); +} + + +/* + * End of "$Id: scsi.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/backend/serial.c b/backend/serial.c new file mode 100644 index 000000000..3079eef5e --- /dev/null +++ b/backend/serial.c @@ -0,0 +1,1114 @@ +/* + * "$Id: serial.c 4906 2006-01-10 20:53:28Z mike $" + * + * Serial port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Send a file to the printer or server. + * list_devices() - List all serial devices. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __hpux +# include +#endif /* __hpux */ + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# ifdef HAVE_SYS_IOCTL_H +# include +# endif /* HAVE_SYS_IOCTL_H */ +#endif /* WIN32 */ + +#ifdef __sgi +# include +# ifndef INV_EPP_ECP_PLP +# define INV_EPP_ECP_PLP 6 /* From 6.3/6.4/6.5 sys/invent.h */ +# define INV_ASO_SERIAL 14 /* serial portion of SGI ASO board */ +# define INV_IOC3_DMA 16 /* DMA mode IOC3 serial */ +# define INV_IOC3_PIO 17 /* PIO mode IOC3 serial */ +# define INV_ISA_DMA 19 /* DMA mode ISA serial -- O2 */ +# endif /* !INV_EPP_ECP_PLP */ +#endif /* __sgi */ + +#ifndef CRTSCTS +# ifdef CNEW_RTSCTS +# define CRTSCTS CNEW_RTSCTS +# else +# define CRTSCTS 0 +# endif /* CNEW_RTSCTS */ +#endif /* !CRTSCTS */ + +#if defined(__APPLE__) +# include +# include +# include +# include +#endif /* __APPLE__ */ + + +/* + * 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) */ + int fp; /* Print file */ + int copies; /* Number of copies to print */ + int fd; /* Parallel device */ + int rbytes; /* Number of bytes read */ + 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 */ + fd_set input, /* Input set for select() */ + output; /* Output 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); + + /* + * Ignore SIGPIPE signals... + */ + +#ifdef HAVE_SIGSET + sigset(SIGPIPE, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Check command-line... + */ + + if (argc == 1) + { + list_devices(); + return (CUPS_BACKEND_OK); + } + else if (argc < 6 || argc > 7) + { + fputs("Usage: serial job-id user title copies options [file]\n", stderr); + return (CUPS_BACKEND_FAILED); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = 0; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = open(argv[6], O_RDONLY)) < 0) + { + perror("ERROR: unable to open print file"); + return (CUPS_BACKEND_FAILED); + } + + copies = atoi(argv[4]); + } + + /* + * Extract the device name and options from the URI... + */ + + httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(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 (getenv("CLASS") != NULL) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fputs("INFO: Unable to open serial port, queuing on next printer in class...\n", + stderr); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (CUPS_BACKEND_FAILED); + } + + 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 (CUPS_BACKEND_FAILED); + } + } + } + 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 != '=';) + if (ptr < (name + sizeof(name) - 1)) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '=') + { + /* + * Get the value... + */ + + options ++; + + for (ptr = value; *options && *options != '+' && *options != '&';) + if (ptr < (value + sizeof(value) - 1)) + *ptr++ = *options++; + *ptr = '\0'; + + if (*options == '+') + options ++; + } + else + value[0] = '\0'; + + /* + * Process the option... + */ + + if (!strcasecmp(name, "baud")) + { + /* + * 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 */ +# ifdef B230400 + case 230400 : + cfsetispeed(&opts, B230400); + cfsetospeed(&opts, B230400); + break; +# endif /* B230400 */ + default : + fprintf(stderr, "WARNING: Unsupported baud rate %s!\n", value); + break; + } +#endif /* B19200 == 19200 */ + } + else if (!strcasecmp(name, "bits")) + { + /* + * 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")) + { + /* + * Set parity checking... + */ + + if (!strcasecmp(value, "even")) + { + opts.c_cflag |= PARENB; + opts.c_cflag &= ~PARODD; + } + else if (!strcasecmp(value, "odd")) + { + opts.c_cflag |= PARENB; + opts.c_cflag |= PARODD; + } + else if (!strcasecmp(value, "none")) + opts.c_cflag &= ~PARENB; + else if (!strcasecmp(value, "space")) + { + /* + * Note: we only support space parity with 7 bits per character... + */ + + opts.c_cflag &= ~CSIZE; + opts.c_cflag |= CS8; + opts.c_cflag &= ~PARENB; + } + else if (!strcasecmp(value, "mark")) + { + /* + * Note: we only support mark parity with 7 bits per character + * and 1 stop bit... + */ + + opts.c_cflag &= ~CSIZE; + opts.c_cflag |= CS7; + opts.c_cflag &= ~PARENB; + opts.c_cflag |= CSTOPB; + } + } + else if (!strcasecmp(name, "flow")) + { + /* + * Set flow control... + */ + + if (!strcasecmp(value, "none")) + { + opts.c_iflag &= ~(IXON | IXOFF); + opts.c_cflag &= ~CRTSCTS; + } + else if (!strcasecmp(value, "soft")) + { + opts.c_iflag |= IXON | IXOFF; + opts.c_cflag &= ~CRTSCTS; + } + else if (!strcasecmp(value, "hard") || + !strcasecmp(value, "rtscts")) + { + opts.c_iflag &= ~(IXON | IXOFF); + opts.c_cflag |= CRTSCTS; + } + else if (!strcasecmp(value, "dtrdsr")) + { + opts.c_iflag &= ~(IXON | IXOFF); + opts.c_cflag &= ~CRTSCTS; + + dtrdsr = 1; + } + } + else if (!strcasecmp(name, "stop")) + { + switch (atoi(value)) + { + case 1 : + opts.c_cflag &= ~CSTOPB; + break; + + case 2 : + opts.c_cflag |= CSTOPB; + break; + } + } + } + + 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); + + wbytes = 0; + + while (copies > 0) + { + copies --; + + if (fp != 0) + { + fputs("PAGE: 1 1\n", stderr); + lseek(fp, 0, SEEK_SET); + } + + 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 = read(fp, buffer, bufsize)) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + /* + * See if we are ready to read or write... + */ + + do + { + FD_ZERO(&input); + FD_SET(fd, &input); + FD_ZERO(&output); + FD_SET(fd, &output); + } + while (select(fd + 1, &input, &output, NULL, NULL) < 0); + + if (FD_ISSET(fd, &input)) + { + /* + * Read backchannel data... + */ + + if ((rbytes = read(fd, resource, sizeof(resource))) > 0) + { + fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n", + rbytes); + cupsBackchannelWrite(resource, rbytes, 1.0); + } + } + + if (FD_ISSET(fd, &output)) + { + /* + * Write print data... + */ + + if ((wbytes = write(fd, bufptr, nbytes)) < 0) + if (errno == ENOTTY) + wbytes = write(fd, bufptr, nbytes); + + if (wbytes < 0) + { + /* + * Check for retryable errors... + */ + + if (errno != EAGAIN && errno != EINTR) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + } + else + { + /* + * Update count and pointer... + */ + + nbytes -= wbytes; + bufptr += wbytes; + } + } + } + + if (wbytes < 0) + break; + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %lu bytes...\n", + (unsigned long)tbytes); + } + } + + /* + * Close the serial port and input file and return... + */ + + tcsetattr(fd, TCSADRAIN, &origopts); + + close(fd); + if (fp != 0) + close(fp); + + return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); +} + + +/* + * '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__ */ + +#if defined(__linux) || defined(linux) || defined(__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); +# if defined(_ARCH_PPC) || defined(powerpc) || defined(__powerpc) + printf("serial serial:%s?baud=230400 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); +# else + printf("serial serial:%s?baud=115200 \"Unknown\" \"Serial Port #%d\"\n", + device, i + 1); +# endif /* _ARCH_PPC || powerpc || __powerpc */ + } + } + + for (i = 0; i < 16; i ++) + { + sprintf(device, "/dev/usb/ttyUSB%d", i); + if ((fd = open(device, O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) + { + close(fd); + printf("serial serial:%s?baud=230400 \"Unknown\" \"USB 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); + } + + 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); + } + } +#elif defined(__APPLE__) + /* + * Standard serial ports on MacOS X... + */ + + kern_return_t kernResult; + mach_port_t masterPort; + io_iterator_t serialPortIterator; + CFMutableDictionaryRef classesToMatch; + io_object_t serialService; + + printf("serial serial \"Unknown\" \"Serial Printer (serial)\"\n"); + + kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort); + if (KERN_SUCCESS != kernResult) + return; + + /* + * Serial devices are instances of class IOSerialBSDClient. + */ + + classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue); + if (classesToMatch != NULL) + { + CFDictionarySetValue(classesToMatch, CFSTR(kIOSerialBSDTypeKey), + CFSTR(kIOSerialBSDRS232Type)); + + kernResult = IOServiceGetMatchingServices(masterPort, classesToMatch, + &serialPortIterator); + if (kernResult == KERN_SUCCESS) + { + while ((serialService = IOIteratorNext(serialPortIterator))) + { + CFTypeRef serialNameAsCFString; + CFTypeRef bsdPathAsCFString; + char serialName[128]; + char bsdPath[1024]; + Boolean result; + + + serialNameAsCFString = + IORegistryEntryCreateCFProperty(serialService, + CFSTR(kIOTTYDeviceKey), + kCFAllocatorDefault, 0); + if (serialNameAsCFString) + { + result = CFStringGetCString(serialNameAsCFString, serialName, + sizeof(serialName), + kCFStringEncodingASCII); + CFRelease(serialNameAsCFString); + + if (result) + { + bsdPathAsCFString = + IORegistryEntryCreateCFProperty(serialService, + CFSTR(kIOCalloutDeviceKey), + kCFAllocatorDefault, 0); + if (bsdPathAsCFString) + { + result = CFStringGetCString(bsdPathAsCFString, bsdPath, + sizeof(bsdPath), + kCFStringEncodingASCII); + CFRelease(bsdPathAsCFString); + + if (result) + printf("serial serial:%s?baud=115200 \"Unknown\" \"%s\"\n", bsdPath, + serialName); + } + } + } + + IOObjectRelease(serialService); + } + + IOObjectRelease(serialPortIterator); /* Release the iterator. */ + } + } +#endif +} + + +/* + * End of "$Id: serial.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/backend/socket.c b/backend/socket.c new file mode 100644 index 000000000..54b6a7796 --- /dev/null +++ b/backend/socket.c @@ -0,0 +1,418 @@ +/* + * "$Id: socket.c 4906 2006-01-10 20:53:28Z mike $" + * + * AppSocket backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Send a file to the printer or server. + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +#else +# include +# include +# include +# include +# include +# include +#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) */ + int fp; /* Print file */ + int copies; /* Number of copies to print */ + int port; /* Port number */ + char portname[255]; /* Port name */ + int delay; /* Delay for retries... */ + int fd; /* AppSocket */ + int error; /* Error code (if any) */ + http_addrlist_t *addrlist; /* Address list */ + int rbytes; /* Number of bytes read */ + int wbytes; /* Number of bytes written */ + int nbytes; /* Number of bytes read */ + size_t 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() */ + output; /* Output 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); + + /* + * Ignore SIGPIPE signals... + */ + +#ifdef HAVE_SIGSET + sigset(SIGPIPE, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Check command-line... + */ + + if (argc == 1) + { + puts("network socket \"Unknown\" \"AppSocket/HP JetDirect\""); + return (CUPS_BACKEND_OK); + } + else if (argc < 6 || argc > 7) + { + fprintf(stderr, "Usage: %s job-id user title copies options [file]\n", + argv[0]); + return (CUPS_BACKEND_FAILED); + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = 0; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = open(argv[6], O_RDONLY)) < 0) + { + perror("ERROR: unable to open print file"); + return (CUPS_BACKEND_FAILED); + } + + copies = atoi(argv[4]); + } + + /* + * Extract the hostname and port number from the URI... + */ + + httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + + if (port == 0) + port = 9100; /* Default to HP JetDirect/Tektronix PhaserShare */ + + /* + * Then try to connect to the remote host... + */ + + sprintf(portname, "%d", port); + + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + { + fprintf(stderr, "ERROR: Unable to locate printer \'%s\'!\n", hostname); + return (CUPS_BACKEND_STOP); + } + + fprintf(stderr, "INFO: Attempting to connect to host %s on port %d\n", + hostname, port); + + wbytes = 0; + + while (copies > 0) + { + for (delay = 5;;) + { + if (!httpAddrConnect(addrlist, &fd)) + { + error = errno; + fd = -1; + + if (getenv("CLASS") != NULL) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fprintf(stderr, "INFO: Unable to connect to \"%s\", queuing on next printer in class...\n", + hostname); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (CUPS_BACKEND_FAILED); + } + + if (error == ECONNREFUSED || error == EHOSTDOWN || + error == EHOSTUNREACH) + { + 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 != 0) + { + fputs("PAGE: 1 1\n", stderr); + lseek(fp, 0, SEEK_SET); + } + + fputs("INFO: Connected to host, sending print job...\n", stderr); + + tbytes = 0; + while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + /* + * See if we are ready to read or write... + */ + + do + { + FD_ZERO(&input); + FD_SET(fd, &input); + FD_ZERO(&output); + FD_SET(fd, &output); + } + while (select(fd + 1, &input, &output, NULL, NULL) < 0); + + if (FD_ISSET(fd, &input)) + { + /* + * Read backchannel data... + */ + + if ((rbytes = recv(fd, resource, sizeof(resource), 0)) > 0) + { + fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n", + rbytes); + cupsBackchannelWrite(resource, rbytes, 1.0); + } + } + + if (FD_ISSET(fd, &output)) + { + /* + * Write print data... + */ + + if ((wbytes = send(fd, bufptr, nbytes, 0)) < 0) + { + /* + * Check for retryable errors... + */ + + if (errno != EAGAIN && errno != EINTR) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + } + else + { + /* + * Update count and pointer... + */ + + nbytes -= wbytes; + bufptr += wbytes; + } + } + } + + if (wbytes < 0) + break; + + if (argc > 6) + fprintf(stderr, "INFO: Sending print file, %lu bytes...\n", + (unsigned long)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 ((rbytes = recv(fd, resource, sizeof(resource), 0)) > 0) + { + fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n", + rbytes); + cupsBackchannelWrite(resource, rbytes, 1.0); + } + else + break; + } + else + break; + } + + /* + * Close the socket connection... + */ + + close(fd); + } + + httpAddrFreeList(addrlist); + + /* + * Close the input file and return... + */ + + if (fp != 0) + close(fp); + + if (wbytes >= 0) + fputs("INFO: Ready to print.\n", stderr); + + return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); +} + + +/* + * End of "$Id: socket.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/backend/test1284.c b/backend/test1284.c new file mode 100644 index 000000000..20a505d39 --- /dev/null +++ b/backend/test1284.c @@ -0,0 +1,95 @@ +/* + * "$Id: test1284.c 4903 2006-01-10 20:02:46Z mike $" + * + * IEEE-1284 support functions test program for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + */ + +/* + * Include necessary headers. + */ + +#include +#include +#include +#ifdef WIN32 +# include +#else +# include +# include +#endif /* WIN32 */ +#define DEBUG +#include "ieee1284.c" + + +/* + * 'main()' - Test the device-ID functions. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, /* Looping var */ + fd; /* File descriptor */ + char device_id[1024], /* 1284 device ID string */ + make_model[1024], /* make-and-model string */ + uri[1024]; /* URI string */ + + + if (argc < 2) + { + puts("Usage: test1284 device-file [... device-file-N]"); + exit(1); + } + + for (i = 1; i < argc; i ++) + { + if ((fd = open(argv[i], O_RDWR)) < 0) + { + perror(argv[i]); + return (errno); + } + + printf("%s:\n", argv[i]); + + get_device_id(fd, device_id, sizeof(device_id), make_model, + sizeof(make_model), "test", uri, sizeof(uri)); + + printf(" device_id=\"%s\"\n", device_id); + printf(" make_model=\"%s\"\n", make_model); + printf(" uri=\"%s\"\n", uri); + + close(fd); + } + + return (0); +} + + +/* + * End of "$Id: test1284.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/backend/usb-darwin.c b/backend/usb-darwin.c new file mode 100644 index 000000000..5c2ee4f4f --- /dev/null +++ b/backend/usb-darwin.c @@ -0,0 +1,1899 @@ +/* + * "$Id: usb-darwin.c 4548 2005-06-27 02:33:50Z mike $" + * + * USB port on Darwin backend for the Common UNIX Printing System (CUPS). + * + * This file is included from "usb.c" when compiled on MacOS X or Darwin. + * + * Copyright 2004 Apple Computer, Inc. All rights reserved. + * + * IMPORTANT: This Apple software is supplied to you by Apple Computer, + * Inc. ("Apple") in consideration of your agreement to the following + * terms, and your use, installation, modification or redistribution of + * this Apple software constitutes acceptance of these terms. If you do + * not agree with these terms, please do not use, install, modify or + * redistribute this Apple software. + * + * In consideration of your agreement to abide by the following terms, and + * subject to these terms, Apple grants you a personal, non-exclusive + * license, under Apple/s copyrights in this original Apple software (the + * "Apple Software"), to use, reproduce, modify and redistribute the Apple + * Software, with or without modifications, in source and/or binary forms; + * provided that if you redistribute the Apple Software in its entirety and + * without modifications, you must retain this notice and the following + * text and disclaimers in all such redistributions of the Apple Software. + * Neither the name, trademarks, service marks or logos of Apple Computer, + * Inc. may be used to endorse or promote products derived from the Apple + * Software without specific prior written permission from Apple. Except + * as expressly stated in this notice, no other rights or licenses, express + * or implied, are granted by Apple herein, including but not limited to + * any patent rights that may be infringed by your derivative works or by + * other works in which the Apple Software may be incorporated. + * + * The Apple Software is provided by Apple on an "AS IS" basis. APPLE + * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION + * THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND + * OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. + * + * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, + * MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED + * AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), + * STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Contents: + * + * print_device() - Send a file to the specified USB port. + * list_devices() - List all USB devices. + */ + +/* + * Include necessary headers... + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include /* Used for writegReadMutex */ + +#ifndef kPMPrinterURI +# define kPMPrinterURI CFSTR("Printer URI") +#endif + +/* + * Panther/10.3 kIOUSBInterfaceInterfaceID190 + * Jaguar/10.2 kIOUSBInterfaceInterfaceID182 + */ + +#define USB_INTERFACE_KIND CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID190) +#define kUSBLanguageEnglish 0x409 + +/* + * Section 5.3 USB Printing Class spec + */ + +#define kUSBPrintingSubclass 1 +#define kUSBPrintingProtocolNoOpen 0 +#define kUSBPrintingProtocolUnidirectional 1 +#define kUSBPrintingProtocolBidirectional 2 + +#define kUSBPrintClassGetDeviceID 0 +#define kUSBPrintClassGetCentronicsStatus 1 +#define kUSBPrintClassSoftReset 2 + +/* + * Apple MacOS X printer-class plugins + */ + +#define kUSBPrinterClassTypeID (CFUUIDGetConstantUUIDWithBytes(NULL, 0x06, 0x04, 0x7D, 0x16, 0x53, 0xA2, 0x11, 0xD6, 0x92, 0x06, 0x00, 0x30, 0x65, 0x52, 0x45, 0x92)) + +#define kUSBPrinterClassInterfaceID (CFUUIDGetConstantUUIDWithBytes(NULL, 0x03, 0x34, 0x6D, 0x74, 0x53, 0xA3, 0x11, 0xD6, 0x9E, 0xA1, 0x76, 0x30, 0x65, 0x52, 0x45, 0x92)) + +#define kUSBGenericPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericPrintingClass.plugin") +#define kUSBGenericTOPrinterClassDriver CFSTR("/System/Library/Printers/Libraries/USBGenericTOPrintingClass.plugin") + +#define kUSBClassDriverProperty CFSTR("USB Printing Class") +#define kUSBPrinterClassDeviceNotOpen -9664 /*kPMInvalidIOMContext*/ + +typedef union +{ + char b; + struct + { + unsigned reserved0 : 2; + unsigned paperError : 1; + unsigned select : 1; + unsigned notError : 1; + unsigned reserved1 : 3; + } status; +} CentronicsStatusByte; + +typedef struct +{ + CFStringRef manufacturer; /* manufacturer name */ + CFStringRef product; /* product name */ + CFStringRef compatible; /* compatible product name */ + CFStringRef serial; /* serial number */ + CFStringRef command; /* command set */ + CFStringRef ppdURL; /* url of the selected PPD, if any */ +} USBPrinterAddress; + +typedef IOUSBInterfaceInterface190 **USBPrinterInterface; + +typedef struct +{ + UInt8 requestType; + UInt8 request; + UInt16 value; + UInt16 index; + UInt16 length; + void *buffer; +} USBIODeviceRequest; + +typedef struct classDriverContext +{ + IUNKNOWN_C_GUTS; + CFPlugInRef plugin; /* release plugin */ + IUnknownVTbl **factory; + void *vendorReference;/* vendor class specific usage */ + UInt32 location; /* unique location in bus topology */ + UInt8 interfaceNumber; + UInt16 vendorID; + UInt16 productID; + USBPrinterInterface interface; /* identify the device to IOKit */ + UInt8 outpipe; /* mandatory bulkOut pipe */ + UInt8 inpipe; /* optional bulkIn pipe */ + /* + ** general class requests + */ + kern_return_t (*DeviceRequest)( struct classDriverContext **printer, USBIODeviceRequest *iorequest, UInt16 timeout ); + kern_return_t (*GetString)( struct classDriverContext **printer, UInt8 whichString, UInt16 language, UInt16 timeout, CFStringRef *result ); + /* + ** standard printer class requests + */ + kern_return_t (*SoftReset)( struct classDriverContext **printer, UInt16 timeout ); + kern_return_t (*GetCentronicsStatus)( struct classDriverContext **printer, CentronicsStatusByte *result, UInt16 timeout ); + kern_return_t (*GetDeviceID)( struct classDriverContext **printer, CFStringRef *devid, UInt16 timeout ); + /* + ** standard bulk device requests + */ + kern_return_t (*ReadPipe)( struct classDriverContext **printer, UInt8 *buffer, UInt32 *count ); + kern_return_t (*WritePipe)( struct classDriverContext **printer, UInt8 *buffer, UInt32 *count, Boolean eoj ); + /* + ** interface requests + */ + kern_return_t (*Open)( struct classDriverContext **printer, UInt32 location, UInt8 protocol ); + kern_return_t (*Abort)( struct classDriverContext **printer ); + kern_return_t (*Close)( struct classDriverContext **printer ); + /* + ** initialize and terminate + */ + kern_return_t (*Initialize)( struct classDriverContext **printer, struct classDriverContext **baseclass ); + kern_return_t (*Terminate)( struct classDriverContext **printer ); +} USBPrinterClassContext; + + +typedef struct usbPrinterClassType +{ + USBPrinterClassContext *classdriver; + CFUUIDRef factoryID; + UInt32 refCount; +} USBPrinterClassType; + + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Constants +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +/* + Debugging output to Console + DEBUG undefined or + DEBUG=0 production code: suppress console output + + DEBUG=1 report errors (non-zero results) + DEBUG=2 report all results, generate dumps +*/ +#if DEBUG==2 +#define DEBUG_ERR(c, x) showint(x, c) +#define DEBUG_DUMP( text, buf, len ) dump( text, buf, len ) +#define DEBUG_CFString( text, a ) showcfstring( text, a ) +#define DEBUG_CFCompareString( text, a, b ) cmpcfs( text, a, b ) +#elif DEBUG==1 +#define DEBUG_ERR(c, x) if (c) fprintf(stderr, x, c) +#define DEBUG_DUMP( text, buf, len ) +#define DEBUG_CFString( text, a ) +#define DEBUG_CFCompareString( text, a, b ) +#else +#define DEBUG_ERR(c, x) +#define DEBUG_DUMP( text, buf, len ) +#define DEBUG_CFString( text, a ) +#define DEBUG_CFCompareString( text, a, b ) +#endif + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Type Definitions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +typedef struct +{ + /* + * Tagged/Tranparent Binary Communications Protocol + * TBCP read + */ + Boolean tbcpQuoteReads; /* enable tbcp on reads */ + Boolean escapeNextRead; /* last char of last read buffer was escape */ + UInt8 *tbcpReadData; /* read buffer */ + UInt32 readLength; /* read buffer length (all used) */ + int match_endoffset, /* partial match of end TBCP sequence */ + match_startoffset; /* partial match of start TBCP sequence */ + /* + * TBCP write + */ + UInt8 *tbcpWriteData; /* write buffer */ + UInt32 tbcpBufferLength, /* write buffer allocated length */ + tbcpBufferRemaining; /* write buffer not used */ + + Boolean sendStatusNextWrite; + +} PostScriptData; + +typedef struct +{ + CFPlugInRef plugin; /* valid until plugin is release */ + USBPrinterClassContext **classdriver; /* usb printer class in user space */ + CFStringRef bundle; /* class driver URI */ + UInt32 location; /* unique location in USB topology */ + USBPrinterAddress address; /* topology independent bus address */ + CFURLRef reference; /* internal use */ +} USBPrinterInfo; + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +/* +** IOKit to CF functions +*/ +USBPrinterInfo *UsbCopyPrinter( USBPrinterInfo *aPrinter ); +CFMutableArrayRef UsbGetAllPrinters( void ); +void UsbReleasePrinter( USBPrinterInfo *aPrinter ); +void UsbReleaseAllPrinters( CFMutableArrayRef printers ); +kern_return_t UsbRegistryOpen( USBPrinterAddress *usbAddress, USBPrinterInfo **result ); +kern_return_t UsbUnloadClassDriver( USBPrinterInfo *printer ); +kern_return_t UsbLoadClassDriver( USBPrinterInfo *printer, CFUUIDRef interfaceID, CFStringRef classDriverBundle ); +CFStringRef UsbMakeFullUriAddress( USBPrinterInfo *aPrinter ); + +int UsbSamePrinter( const USBPrinterAddress *lastTime, const USBPrinterAddress *thisTime ); + +OSStatus UsbGetPrinterAddress( USBPrinterInfo *thePrinter, USBPrinterAddress *address, UInt16 timeout ); + + +/******************************************************************************* + Contains: Support IEEE-1284 DeviceID as a CFString. + + Copyright 2000-2005 by Apple Computer, Inc., all rights reserved. + + Description: + IEEE-1284 Device ID is referenced in USB and PPDT (1394.3). It allows + a computer peripheral to convey information about its required software + to the host system. + + DeviceID is defined as a stream of ASCII bytes, commencing with one 16-bit + binary integer in Little-Endian format which describes how many bytes + of data are required by the entire DeviceID. + + The stream of bytes is further characterized as a series of + key-value list pairs. In other words each key can be followed by one + or more values. Multiple key-value list pairs fill out the DeviceID stream. + + Some keys are required: COMMAND SET (or CMD), MANUFACTURER (or MFG), + and MODEL (or MDL). + + One needs to read the first two bytes of DeviceID to allocate storage + for the complete DeviceID string. Then a second read operation can + retrieve the entire string. + + Often DeviceID is not very large. By allocating a reasonable buffer one + can fetch most device's DeviceID string on the first read. + + A more formal definition of DeviceID. + + = + + + = + = :[,]*; + + = + + = + + + Some keys are defined in the standard. The standard specifies that + keys are case sensitive. White space is allowed in the key. + + The standard does not say that values are case-sensitive. + Lexmark is known to ship printers with mixed-case value: + i.e., 'CLASS:Printer' + + Required Keys: + 'COMMAND SET' or CMD + MANUFACTURER or MFG + MODEL or MDL + + Optional Keys: + CLASS + Value PRINTER is referenced in the standard. + + Observed Keys: + SN,SERN + Used by Hewlett-Packard for the serial number. + + +*******************************************************************************/ + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Pragmas +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Constants +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +#define kDeviceIDKeyCommand CFSTR("COMMAND SET:") +#define kDeviceIDKeyCommandAbbrev CFSTR( "CMD:" ) + +#define kDeviceIDKeyManufacturer CFSTR("MANUFACTURER:") +#define kDeviceIDKeyManufacturerAbbrev CFSTR( "MFG:" ) + +#define kDeviceIDKeyModel CFSTR("MODEL:") +#define kDeviceIDKeyModelAbbrev CFSTR( "MDL:" ) + +#define kDeviceIDKeySerial CFSTR("SN:") +#define kDeviceIDKeySerialAbbrev CFSTR("SERN:") + +#define kDeviceIDKeyCompatible CFSTR("COMPATIBLITY ID:") +#define kDeviceIDKeyCompatibleAbbrev CFSTR("CID:") + +/* delimiters */ +#define kDeviceIDKeyValuePairDelimiter CFSTR(";") + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Type definitions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Function prototypes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ + +static CFStringRef CreateEncodedCFString(CFStringRef string); +static CFRange DelimitSubstring( CFStringRef stringToSearch, CFStringRef delim, CFRange bounds, CFStringCompareFlags options ); +static void parseOptions(const char *options, char *serial); + +CFStringRef +DeviceIDCreateValueList( const CFStringRef deviceID, + const CFStringRef abbrevKey, + const CFStringRef key ); + +static int addPercentEscapes(const unsigned char* src, char* dst, int dstMax); +static int removePercentEscapes(const char* src, unsigned char* dst, int dstMax); + +/* Required to suppress redefinition warnings for these two symbols +*/ +#if defined(TCP_NODELAY) +#undef TCP_NODELAY +#endif +#if defined(TCP_MAXSEG) +#undef TCP_MAXSEG +#endif + +#include + + +#define PRINTER_POLLING_INTERVAL 5 /* seconds */ +#define INITIAL_LOG_INTERVAL (PRINTER_POLLING_INTERVAL) +#define SUBSEQUENT_LOG_INTERVAL (3*INITIAL_LOG_INTERVAL) + +/* WAITEOF_DELAY is number of seconds we'll wait for responses from the printer */ +/* after we've finished sending all the data */ +#define WAITEOF_DELAY 7 + +#define USB_MAX_STR_SIZE 1024 + + +static volatile int done = 0; +static int gWaitEOF = false; +static pthread_cond_t *gReadCompleteConditionPtr = NULL; +static pthread_mutex_t *gReadMutexPtr = NULL; + + + +#if DEBUG==2 + +static char +hexdigit( char c ) +{ + return ( c < 0 || c > 15 )? '?': (c < 10)? c + '0': c - 10 + 'A'; +} + +static char +asciidigit( char c ) +{ + return (c< 20 || c > 0x7E)? '.': c; +} + +void +dump( char *text, void *s, int len ) +{ + int i; + char *p = (char *) s; + char m[1+2*16+1+16+1]; + + fprintf( stderr, "%s pointer %x len %d\n", text, (unsigned int) p, len ); + + for ( ; len > 0; len -= 16 ) + { + char *q = p; + char *out = m; + *out++ = '\t'; + for ( i = 0; i < 16 && i < len; ++i, ++p ) + { + *out++ = hexdigit( (*p >> 4) & 0x0F ); + *out++ = hexdigit( *p & 0x0F ); + } + for ( ;i < 16; ++i ) + { + *out++ = ' '; + *out++ = ' '; + } + *out++ = '\t'; + for ( i = 0; i < 16 && i < len; ++i, ++q ) + *out++ = asciidigit( *q ); + *out = 0; + m[ strlen( m ) ] = '\0'; + fprintf( stderr, "%s\n", m ); + } +} + +void +printcfs( char *text, CFStringRef s ) +{ + char dest[1024]; + if ( s != NULL ) + { + if ( CFStringGetCString(s, dest, sizeof(dest), kCFStringEncodingUTF8) ) + sprintf( dest, "%s <%s>\n", text, dest ); + else + sprintf( dest, "%s [Unknown string]\n", text ); + } else { + sprintf( dest, "%s [NULL]\n", text ); + } + perror( dest ); +} + +void +cmpcfs( char *text, CFStringRef a, CFStringRef b ) +{ + CFRange found = {0, 0}; + + printcfs( text, a ); + printcfs( " ", b ); + + if (a != NULL && b != NULL) { + found = CFStringFind( a, b, kCFCompareCaseInsensitive ); + + } else if (a == NULL && b == NULL) { + found.length = 1; /* Match */ + found.location = 0; + } else { + found.length = 0; /* No match. */ + } + + if ( found.length > 0 ) + fprintf( stderr, "matched @%d:%d\n", (int) found.location, (int) found.length); + else + fprintf( stderr, "not matched\n" ); +} +#endif /*DEBUG==2 */ + +#ifdef PARSE_PS_ERRORS +static const char *nextLine (const char *buffer); +static void parsePSError (char *sockBuffer, int len); + + +static const char *nextLine (const char *buffer) +{ + const char *cptr, *lptr = NULL; + for (cptr = buffer; *cptr && lptr == NULL; cptr++) + if (*cptr == '\n' || *cptr == '\r') + lptr = cptr; + return lptr; +} + +static void parsePSError (char *sockBuffer, int len) +{ + static char gErrorBuffer[1024] = ""; + static char *gErrorBufferPtr = gErrorBuffer; + static char *gErrorBufferEndPtr = gErrorBuffer + sizeof(gErrorBuffer); + + char *pCommentBegin, *pCommentEnd, *pLineEnd; + char *logLevel; + char logstr[1024]; + int logstrlen; + + if (gErrorBufferPtr + len > gErrorBufferEndPtr - 1) + gErrorBufferPtr = gErrorBuffer; + if (len > sizeof(gErrorBuffer) - 1) + len = sizeof(gErrorBuffer) - 1; + + memcpy(gErrorBufferPtr, (const void *)sockBuffer, len); + gErrorBufferPtr += len; + *(gErrorBufferPtr + 1) = '\0'; + + + pLineEnd = (char *)nextLine((const char *)gErrorBuffer); + while (pLineEnd != NULL) + { + *pLineEnd++ = '\0'; + + pCommentBegin = strstr(gErrorBuffer,"%%["); + pCommentEnd = strstr(gErrorBuffer, "]%%"); + if (pCommentBegin != gErrorBuffer && pCommentEnd != NULL) + { + pCommentEnd += 3; /* Skip past "]%%" */ + *pCommentEnd = '\0'; /* There's always room for the nul */ + + if (strncasecmp(pCommentBegin, "%%[ Error:", 10) == 0) + logLevel = "DEBUG"; + else if (strncasecmp(pCommentBegin, "%%[ Flushing", 12) == 0) + logLevel = "DEBUG"; + else + logLevel = "INFO"; + + if ((logstrlen = snprintf(logstr, sizeof(logstr), "%s: %s\n", logLevel, pCommentBegin)) >= sizeof(logstr)) + { + /* If the string was trucnated make sure it has a linefeed before the nul */ + logstrlen = sizeof(logstr) - 1; + logstr[logstrlen - 1] = '\n'; + } + write(STDERR_FILENO, logstr, logstrlen); + } + + /* move everything over... */ + strcpy(gErrorBuffer, pLineEnd); + gErrorBufferPtr = gErrorBuffer; + pLineEnd = (char *)nextLine((const char *)gErrorBuffer); + } +} +#endif /* PARSE_PS_ERRORS */ + +void * +readthread( void *reference ) +{ + /* + ** post a read to the device and write results to stdout + ** the final pending read will be Aborted in the main thread + */ + UInt8 readbuffer[512]; + UInt32 rbytes; + kern_return_t readstatus; + USBPrinterClassContext **classdriver = (USBPrinterClassContext **) reference; + + + do + { + rbytes = sizeof(readbuffer) - 1; + readstatus = (*classdriver)->ReadPipe( classdriver, readbuffer, &rbytes ); + if ( kIOReturnSuccess == readstatus && rbytes > 0 ) + { + write( STDOUT_FILENO, readbuffer, rbytes ); + /* cntrl-d is echoed by the printer. + * NOTES: + * Xerox Phaser 6250D doesn't echo the cntrl-d. + * Xerox Phaser 6250D doesn't always send the product query. + */ + if (gWaitEOF && readbuffer[rbytes-1] == 0x4) + break; +#ifdef PARSE_PS_ERRORS + parsePSError(readbuffer, rbytes); +#endif + } + } while ( gWaitEOF || !done ); /* Abort from main thread tests error here */ + + /* Let the other thread (main thread) know that we have + * completed the read thread... + */ + pthread_mutex_lock(gReadMutexPtr); + pthread_cond_signal(gReadCompleteConditionPtr); + pthread_mutex_unlock(gReadMutexPtr); + + return NULL; +} + +/* +* 'print_device()' - Send a file to the specified USB port. +*/ + +int print_device(const char *uri, const char *hostname, const char *resource, const char *options, int fd, int copies) +{ + UInt32 wbytes, /* Number of bytes written */ + buffersize = 2048; + size_t nbytes; /* Number of bytes read */ + off_t tbytes; /* Total number of bytes written */ + char *buffer, /* Output buffer */ + *bufptr; /* Pointer into buffer */ + + pthread_cond_t readCompleteCondition; + pthread_mutex_t readMutex; + pthread_t thr; + int thread_created = 0; + + USBPrinterInfo *targetPrinter = NULL; + CFMutableArrayRef usbPrinters; + char manufacturer_buf[USB_MAX_STR_SIZE], + product_buf[USB_MAX_STR_SIZE], + serial_buf[USB_MAX_STR_SIZE]; + CFStringRef manufacturer; + CFStringRef product; + CFStringRef serial; + + OSStatus status = noErr; + + + #if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ + #endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + fprintf(stderr, "INFO: Opening the print file and connection...\n"); + + parseOptions(options, serial_buf); + + if (resource[0] == '/') + resource++; + + removePercentEscapes(hostname, manufacturer_buf, sizeof(manufacturer_buf)); + removePercentEscapes(resource, product_buf, sizeof(product_buf)); + + manufacturer = CFStringCreateWithCString(NULL, manufacturer_buf, kCFStringEncodingUTF8); + product = CFStringCreateWithCString(NULL, product_buf, kCFStringEncodingUTF8); + serial = CFStringCreateWithCString(NULL, serial_buf, kCFStringEncodingUTF8); + + USBPrinterInfo *activePrinter = NULL; + USBPrinterClassContext **classdriver; + int countdown = INITIAL_LOG_INTERVAL; + do + { + /* */ + /* given a manufacturer and product, bind to a specific printer on the bus */ + /* */ + usbPrinters = UsbGetAllPrinters(); + /* */ + /* if we have at least one element of the URI, find a printer module that matches */ + /* */ + if ( NULL != usbPrinters && (manufacturer || product ) ) + { + int i, + numPrinters = CFArrayGetCount(usbPrinters); + for ( i = 0; i < numPrinters; ++i ) + { + int match = FALSE; + USBPrinterInfo *printer = (USBPrinterInfo *) CFArrayGetValueAtIndex( usbPrinters, i ); + if ( printer ) + { + match = printer->address.manufacturer && manufacturer? CFEqual(printer->address.manufacturer, manufacturer ): FALSE; + if ( match ) + { + match = printer->address.product && product? CFEqual(printer->address.product, product ): FALSE; + } + if ( match && serial ) + { + /* Note with old queues (pre Panther) the CUPS uri may have no serial number (serial==NULL). */ + /* In this case, we will ignore serial number (as before), and we'll match to the first */ + /* printer that agrees with manufacturer and product. */ + /* If the CUPS uri does include a serial number, we'll enter this clause */ + /* which requires the printer's serial number to match the CUPS serial number. */ + /* The net effect is that for printers with a serial number, */ + /* new queues must match the serial number, while old queues match any printer */ + /* that satisfies the manufacturer/product match. */ + /* */ + match = printer->address.serial? CFEqual(printer->address.serial, serial ): FALSE; + } + if ( match ) + { + targetPrinter = UsbCopyPrinter( printer ); + break; /* for, compare partial address to address for each printer on usb bus */ + } + } + } + } + UsbReleaseAllPrinters( usbPrinters ); + if ( NULL != targetPrinter ) + status = UsbRegistryOpen( &targetPrinter->address, &activePrinter ); + + if ( NULL == activePrinter ) + { + sleep( PRINTER_POLLING_INTERVAL ); + countdown -= PRINTER_POLLING_INTERVAL; + if ( !countdown ) + { + /* periodically, write to the log so someone knows we're waiting */ + if (NULL == targetPrinter) + fprintf( stderr, "WARNING: Printer not responding\n" ); + else + fprintf( stderr, "INFO: Printer busy\n" ); + countdown = SUBSEQUENT_LOG_INTERVAL; /* subsequent log entries, every 30 minutes */ + } + } + } while ( NULL == activePrinter ); + + classdriver = activePrinter->classdriver; + if ( NULL == classdriver ) + { + perror("ERROR: Unable to open USB Printing Class port"); + return (status); + } + + /* + * 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 (fd != 0) + { +#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 */ + } + + buffer = malloc( buffersize ); + if ( !buffer ) { + fprintf( stderr, "ERROR: Couldn't allocate internal buffer\n" ); + status = -1; + } + else + { + fprintf(stderr, "INFO: Sending the print file...\n"); + if (pthread_cond_init(&readCompleteCondition, NULL) == 0) + { + gReadCompleteConditionPtr = &readCompleteCondition; + + if (pthread_mutex_init(&readMutex, NULL) == 0) + { + gReadMutexPtr = &readMutex; + + if (pthread_create(&thr, NULL, readthread, classdriver ) > 0) + fprintf(stderr, "WARNING: Couldn't create read channel\n"); + else + thread_created = 1; + } + } + } + /* + * the main thread sends the print file... + */ + while (noErr == status && copies > 0) + { + copies --; + if (STDIN_FILENO != fd) + { + fputs("PAGE: 1 1", stderr); + lseek( fd, 0, SEEK_SET ); /* rewind */ + } + + tbytes = 0; + while (noErr == status && (nbytes = read(fd, buffer, buffersize)) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0 && noErr == status ) + { + wbytes = nbytes; + status = (*classdriver)->WritePipe( classdriver, (UInt8*)bufptr, &wbytes, 0 /*nbytes > wbytes? 0: feof(fp)*/ ); + if (wbytes < 0 || noErr != status) + { + OSStatus err; + err = (*classdriver)->Abort( classdriver ); + fprintf(stderr, "ERROR: %ld: Unable to send print file to printer (canceled %ld)\n", status, err ); + break; + } + + nbytes -= wbytes; + bufptr += wbytes; + } + + if (fd != 0 && noErr == status) + fprintf(stderr, "INFO: Sending print file, %qd bytes...\n", (off_t)tbytes); + } + } + done = 1; /* stop scheduling reads */ + + if ( thread_created ) + { + /* Give the read thread WAITEOF_DELAY seconds to complete all the data. If + * we are not signaled in that time then force the thread to exit by setting + * the waiteof to be false. Plese note that this relies on us using the timeout + * class driver. + */ + struct timespec sleepUntil = { time(NULL) + WAITEOF_DELAY, 0 }; + pthread_mutex_lock(&readMutex); + if (pthread_cond_timedwait(&readCompleteCondition, &readMutex, (const struct timespec *)&sleepUntil) != 0) + gWaitEOF = false; + pthread_mutex_unlock(&readMutex); + pthread_join( thr,NULL); /* wait for the child thread to return */ + } + + (*classdriver)->Close( classdriver ); /* forces the read to stop incase we are doing a blocking read */ + UsbUnloadClassDriver( activePrinter ); + /* + * Close the socket connection and input file and return... + */ + free( buffer ); + + if (STDIN_FILENO != fd) + close(fd); + + if (gReadCompleteConditionPtr != NULL) + pthread_cond_destroy(gReadCompleteConditionPtr); + if (gReadMutexPtr != NULL) + pthread_mutex_destroy(gReadMutexPtr); + + return status == kIOReturnSuccess? 0: status; +} + +static Boolean +encodecfstr( CFStringRef cfsrc, char *dst, long len ) +{ + return CFStringGetCString(cfsrc, dst, len, kCFStringEncodingUTF8 ); +} + +/* +* 'list_devices()' - List all USB devices. +*/ +void list_devices(void) +{ + char encodedManufacturer[1024]; + char encodedProduct[1024]; + char uri[1024]; + CFMutableArrayRef usbBusPrinters = UsbGetAllPrinters(); + CFIndex i, numPrinters = NULL != usbBusPrinters? CFArrayGetCount( usbBusPrinters ): 0; + + puts("direct usb \"Unknown\" \"USB Printer (usb)\""); + for ( i = 0; i < numPrinters; ++i ) + { + USBPrinterInfo *printer = (USBPrinterInfo *) CFArrayGetValueAtIndex( usbBusPrinters, i ); + + if ( printer ) + { + CFStringRef addressRef = UsbMakeFullUriAddress( printer ); + if ( addressRef ) + { + if ( CFStringGetCString(addressRef, uri, sizeof(uri), kCFStringEncodingUTF8) ) { + + encodecfstr( printer->address.manufacturer, encodedManufacturer, sizeof(encodedManufacturer) ); + encodecfstr( printer->address.product, encodedProduct, sizeof(encodedProduct) ); + printf("direct %s \"%s %s\" \"%s\"\n", uri, encodedManufacturer, encodedProduct, encodedProduct); + } + } + } + } + UsbReleaseAllPrinters( usbBusPrinters ); + fflush(NULL); +} + + +static void parseOptions(const char *options, char *serial) +{ + char *serialnumber; /* ?serial= or ?location= */ + char optionName[255], /* Name of option */ + value[255], /* Value of option */ + *ptr; /* Pointer into name or value */ + + if (serial) + *serial = '\0'; + + if (!options) + return; + + serialnumber = NULL; + + while (*options != '\0') + { + /* + * Get the name... + */ + for (ptr = optionName; *options && *options != '=' && *options != '+' && *options != '&'; ) + *ptr++ = *options++; + + *ptr = '\0'; + value[0] = '\0'; + + if (*options == '=') + { + /* + * Get the value... + */ + + options ++; + + for (ptr = value; *options && *options != '+' && *options != '&';) + *ptr++ = *options++; + + *ptr = '\0'; + + if (*options == '+' || *options == '&') + options ++; + } + else if (*options == '+' || *options == '&') + { + options ++; + } + + /* + * Process the option... + */ + if (strcasecmp(optionName, "waiteof") == 0) + { + if (strcasecmp(value, "on") == 0 || + strcasecmp(value, "yes") == 0 || + strcasecmp(value, "true") == 0) + { + gWaitEOF = true; + } + else if (strcasecmp(value, "off") == 0 || + strcasecmp(value, "no") == 0 || + strcasecmp(value, "false") == 0) + { + gWaitEOF = false; + } + else + { + fprintf(stderr, "WARNING: Boolean expected for waiteof option \"%s\"\n", value); + } + } + else if (strcasecmp(optionName, "serial") == 0 || + strcasecmp(optionName, "location") == 0 ) + { + strcpy(serial, value); + serialnumber = serial; + } + } + + return; +} + + +/*! + * @function addPercentEscapes + * @abstract Encode a string with percent escapes + * + * @param src The source C string + * @param dst Desination buffer + * @param dstMax Size of desination buffer + * + * @result A non-zero return value for errors + */ +static int addPercentEscapes(const unsigned char* src, char* dst, int dstMax) +{ + unsigned char c; + char *dstEnd = dst + dstMax - 1; /* -1 to leave room for the NUL */ + + while (*src) + { + c = *src++; + + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || (c == '.' || c == '-' || c == '*' || c == '_')) + { + if (dst >= dstEnd) + return -1; + + *dst++ = c; + } + else + { + if (dst >= dstEnd - 2) + return -1; + + snprintf(dst, dstEnd - dst, "%%%02x", c); + dst += 3; + } + } + + *dst = '\0'; + return 0; +} + + +/*! + * @function removePercentEscapes + * @abstract Returns a string with any percent escape sequences replaced with their equivalent character + * + * @param src Source buffer + * @param srclen Number of bytes in source buffer + * @param dst Desination buffer + * @param dstMax Size of desination buffer + * + * @result A non-zero return value for errors + */ +static int removePercentEscapes(const char* src, unsigned char* dst, int dstMax) +{ + int c; + const unsigned char *dstEnd = dst + dstMax; + + while (*src && dst < dstEnd) + { + c = *src++; + + if (c == '%') + { + sscanf(src, "%02x", &c); + src += 2; + } + *dst++ = (char)c; + } + + if (dst >= dstEnd) + return -1; + + *dst = '\0'; + return 0; +} + +/*-----------------------------------------------------------------------------* + + DelimitSubstring + + Desc: Search a string from a starting location, looking for a given + delimiter. Return the range from the start of the search to the + delimiter, or end of string (whichever is shorter). + + In: stringToSearch string which contains a substring that we search + delim string which marks the end of the string + bounds start and length of substring of stringToSearch + options case sensitive, anchored, etc. + + Out: Range up to the delimiter. + +*-----------------------------------------------------------------------------*/ +static CFRange +DelimitSubstring( CFStringRef stringToSearch, CFStringRef delim, CFRange bounds, CFStringCompareFlags options ) +{ + CFRange where_delim, /* where the delimiter was found */ + value; + /* */ + /* trim leading space by changing bounds */ + /* */ + while ( bounds.length > 0 && CFStringFindWithOptions( stringToSearch, CFSTR(" "), bounds, kCFCompareAnchored, &where_delim ) ) + { + ++bounds.location; /* drop a leading ' ' */ + --bounds.length; + } + value = bounds; /* assume match to the end of string, may be NULL */ + /* */ + /* find the delimiter in the remaining string */ + /* */ + if ( bounds.length > 0 && CFStringFindWithOptions( stringToSearch, delim, bounds, options, &where_delim ) ) + { + /* */ + /* match to the delimiter */ + /* */ + value.length = where_delim.location /* delim */ - bounds.location /* start of search */; + } + DEBUG_CFString( "\tFind target", stringToSearch ); + DEBUG_CFString( "\tFind pattern", delim ); + DEBUG_ERR( (int) value.location, "\t\tFound %d\n" ); + DEBUG_ERR( (int) value.length, " length %d" ); + + return value; +} + + +/*-----------------------------------------------------------------------------* + + DeviceIDCreateValueList + + Desc: Create a new string for the value list of the specified key. + The key may be specified as two strings (an abbreviated form + and a standard form). NULL can be passed for either form of + the key. + + (Although passing NULL for both forms of the key is considered + bad form[!] it is handled correctly.) + + In: deviceID the device's IEEE-1284 DeviceID key-value list + abbrevKey the key we're interested in (NULL allowed) + key + + Out: CFString the value list + or NULL key wasn't found in deviceID + +*-----------------------------------------------------------------------------*/ +CFStringRef +DeviceIDCreateValueList( const CFStringRef deviceID, const CFStringRef abbrevKey, const CFStringRef key ) +{ + CFRange found = CFRangeMake( -1,0); /* note CFStringFind sets length 0 if string not found */ + CFStringRef valueList = NULL; + + DEBUG_CFString( "---------DeviceIDCreateValueList DeviceID:", deviceID ); + DEBUG_CFString( "---------DeviceIDCreateValueList key:", key ); + DEBUG_CFString( "---------DeviceIDCreateValueList abbrevkey:", abbrevKey ); + if ( NULL != deviceID && NULL != abbrevKey ) + found = CFStringFind( deviceID, abbrevKey, kCFCompareCaseInsensitive ); + if ( NULL != deviceID && NULL != key && found.length <= 0 ) + found = CFStringFind( deviceID, key, kCFCompareCaseInsensitive ); + if ( found.length > 0 ) + { + /* the key is at found */ + /* the value follows the key until we reach the semi-colon, or end of string */ + /* */ + CFRange search = CFRangeMake( found.location + found.length, + CFStringGetLength( deviceID ) - (found.location + found.length) ); + /* */ + /* finally extract the string */ + /* */ + valueList = CFStringCreateWithSubstring ( kCFAllocatorDefault, deviceID, + DelimitSubstring( deviceID, kDeviceIDKeyValuePairDelimiter, search, kCFCompareCaseInsensitive ) ); + DEBUG_CFString( "---------DeviceIDCreateValueList:", valueList ); + } + return valueList; + +} + + + +/******************************************************************************/ + +/*-----------------------------------------------------------------------------* + +CompareSameString + +Desc: Return the CFCompare result for two strings, either or both of which + can be NULL. + +In: + a current value + b last value + +Out: + 0 if the strings match + non-zero if the strings don't match + +*-----------------------------------------------------------------------------*/ +static int +CompareSameString( const CFStringRef a, const CFStringRef b ) +{ + if ( NULL == a && NULL == b ) + return 0; + else if ( NULL != a && NULL != b ) + return CFStringCompare( a, b, kCFCompareAnchored ); + else + return 1; /* one of a or b is NULL this time, but wasn't last time */ +} + + +/******************************************************************************/ +kern_return_t +UsbLoadClassDriver( USBPrinterInfo *printer, CFUUIDRef interfaceID, CFStringRef classDriverBundle ) +{ + kern_return_t kr = kUSBPrinterClassDeviceNotOpen; + if ( NULL != classDriverBundle ) + printer->bundle = classDriverBundle; /* vendor-specific class override */ + else +#ifdef TIMEOUT + classDriverBundle = kUSBGenericTOPrinterClassDriver; /* supply the generic TIMEOUT class driver */ +#else + classDriverBundle = kUSBGenericPrinterClassDriver; /* supply the generic class driver */ +#endif + DEBUG_CFString( "UsbLoadClassDriver classDriverBundle", classDriverBundle ); + if ( NULL != classDriverBundle ) + { + USBPrinterClassContext **classdriver = NULL; + CFURLRef classDriverURL = CFURLCreateWithFileSystemPath( NULL, classDriverBundle, kCFURLPOSIXPathStyle, TRUE ); + CFPlugInRef plugin = NULL == classDriverURL? NULL: CFPlugInCreate( NULL, classDriverURL ); + if ( NULL != plugin) + { + /* See if this plug-in implements the Test type. */ + CFArrayRef factories = CFPlugInFindFactoriesForPlugInTypeInPlugIn( kUSBPrinterClassTypeID, plugin ); + + /* If there are factories for the requested type, attempt to */ + /* get the IUnknown interface. */ + DEBUG_ERR( 0, "UsbLoadClassDriver plugin %x\n" ); + if (NULL != factories && CFArrayGetCount(factories) > 0) + { + /* Get the factory ID for the first location in the array of IDs. */ + CFUUIDRef factoryID = CFArrayGetValueAtIndex( factories, 0 ); + /* Use the factory ID to get an IUnknown interface. */ + /* Here the code for the PlugIn is loaded. */ + IUnknownVTbl **iunknown = CFPlugInInstanceCreate( NULL, factoryID, kUSBPrinterClassTypeID ); + /* If this is an IUnknown interface, query for the Test interface. */ + DEBUG_ERR( 0, "UsbLoadClassDriver factories %x\n" ); + if (NULL != iunknown) + { + DEBUG_ERR( 0, "UsbLoadClassDriver CFPlugInInstanceCreate %x\n" ); + kr = (*iunknown)->QueryInterface( iunknown, CFUUIDGetUUIDBytes(interfaceID), (LPVOID *) &classdriver ); + + (*iunknown)->Release( iunknown ); + if ( S_OK == kr && NULL != classdriver ) + { + DEBUG_ERR( kr, "UsbLoadClassDriver QueryInterface %x\n" ); + printer->plugin = plugin; + kr = (*classdriver)->Initialize( classdriver, printer->classdriver ); + + kr = kIOReturnSuccess; + printer->classdriver = classdriver; + } + else + { + DEBUG_ERR( kr, "UsbLoadClassDriver QueryInterface FAILED %x\n" ); + } + } + else + { + DEBUG_ERR( kr, "UsbLoadClassDriver CFPlugInInstanceCreate FAILED %x\n" ); + } + } + else + { + DEBUG_ERR( kr, "UsbLoadClassDriver factories FAILED %x\n" ); + } + } + else + { + DEBUG_ERR( kr, "UsbLoadClassDriver plugin FAILED %x\n" ); + } + if ( kr != kIOReturnSuccess || NULL == plugin || NULL == classdriver ) + { + UsbUnloadClassDriver( printer ); + } + } + + return kr; +} + + +kern_return_t +UsbUnloadClassDriver( USBPrinterInfo *printer ) +{ + DEBUG_ERR( kIOReturnSuccess, "UsbUnloadClassDriver %x\n" ); + if ( NULL != printer->classdriver ) + (*printer->classdriver)->Release( printer->classdriver ); + printer->classdriver = NULL; + + if ( NULL != printer->plugin ) + CFRelease( printer->plugin ); + printer->plugin = NULL; + + return kIOReturnSuccess; +} + + +/*-----------------------------------------------------------------------------* + + UsbAddressDispose + + Desc: deallocates anything used to create a persistent printer address + + In: address the printer address we've created + + Out: + +*-----------------------------------------------------------------------------*/ +void +UsbAddressDispose( USBPrinterAddress *address ) +{ + if ( address->product != NULL ) CFRelease( address->product ); + if ( address->manufacturer != NULL ) CFRelease( address->manufacturer ); + if ( address->serial != NULL ) CFRelease( address->serial ); + if ( address->command != NULL ) CFRelease( address->command ); + + address->product = + address->manufacturer = + address->serial = + address->command = NULL; + +} + +/*-----------------------------------------------------------------------------* + + UsbGetPrinterAddress + + Desc: Given a printer we're enumerating, discover it's persistent + reference. + + A "persistent reference" is one which enables us to identify + a printer regardless of where it resides on the USB topology, + and enumeration sequence. + + To do this, we actually construct a reference from information + buried inside the printer. First we look at the USB device + descripton: an ideally defined device will support strings for + manufacturer and product id, and serial number. The serial number + will be unique for each printer. + + Our prefered identification fetches the IEEE-1284 device id string. + This transparently handled IEEE-1284 compatible printers which + connected over a USB-parallel cable. Only if we can't get all the + information to uniquely identify the printer do we try the strings + referenced in the printer's USB device descriptor. (These strings + are typically absent in a USB-parallel cable.) + + If a device doesn't support serial numbers we have a problem: + we can't distinguish between two identical printers. Unique serial + numbers allow us to distinguish between two same-model, same-manufacturer + USB printers. + + In: + thePrinter iterator required for fetching device descriptor + devRefNum required to configure the interface + + Out: + address->manufacturer + address->product + address->serial + Any (and all) of these may be NULL if we can't retrieve + information for IEEE1284 DeviceID or the USB device + descriptor. Caller should be prepared to handle such a case. + address->command + May be updated. + +*-----------------------------------------------------------------------------*/ +OSStatus +UsbGetPrinterAddress( USBPrinterInfo *thePrinter, USBPrinterAddress *address, UInt16 timeout ) +{ + + /* */ + /* start by assuming the device is not IEEE-1284 compliant */ + /* and that we can't read in the required strings. */ + /* */ + OSStatus err; + CFStringRef deviceId = NULL; + USBPrinterClassContext **printer = NULL == thePrinter? NULL: thePrinter->classdriver; + + address->manufacturer = + address->product = + address->compatible = + address->serial = + address->command = NULL; + + DEBUG_DUMP( "UsbGetPrinterAddress thePrinter", thePrinter, sizeof(USBPrinterInfo) ); + + err = (*printer)->GetDeviceID( printer, &deviceId, timeout ); + if ( noErr == err && NULL != deviceId ) + { + /* the strings embedded here are defined in the IEEE1284 spec */ + /* */ + /* use the MFG/MANUFACTURER for the manufacturer */ + /* and the MDL/MODEL for the product */ + /* there is no serial number defined in IEEE1284 */ + /* but it's been observed in recent HP printers */ + /* */ + address->command = DeviceIDCreateValueList( deviceId, kDeviceIDKeyCommandAbbrev, kDeviceIDKeyCommand ); + + address->product = DeviceIDCreateValueList( deviceId, kDeviceIDKeyModelAbbrev, kDeviceIDKeyModel ); + address->compatible = DeviceIDCreateValueList( deviceId, kDeviceIDKeyCompatibleAbbrev, kDeviceIDKeyCompatible ); + + address->manufacturer = DeviceIDCreateValueList( deviceId, kDeviceIDKeyManufacturerAbbrev, kDeviceIDKeyManufacturer ); + + address->serial = DeviceIDCreateValueList( deviceId, kDeviceIDKeySerialAbbrev, kDeviceIDKeySerial ); + CFRelease( deviceId ); + } + DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->product", address->product ); + DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->compatible", address->compatible ); + DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->manufacturer", address->manufacturer ); + DEBUG_CFString( "UsbGetPrinterAddress DeviceID address->serial", address->serial ); + + if ( NULL == address->product || NULL == address->manufacturer || NULL == address->serial ) + { + /* */ + /* if the manufacturer or the product or serial number were not specified in DeviceID */ + /* try to construct the address using USB English string descriptors */ + /* */ + IOUSBDeviceDescriptor desc; + USBIODeviceRequest request; + + request.requestType = USBmakebmRequestType( kUSBIn, kUSBStandard, kUSBDevice ); + request.request = kUSBRqGetDescriptor; + request.value = (kUSBDeviceDesc << 8) | 0; + request.index = 0; /* not kUSBLanguageEnglish*/ + request.length = sizeof(desc); + request.buffer = &desc; + err = (*printer)->DeviceRequest( printer, &request, timeout ); + DEBUG_ERR( (kern_return_t) err, "UsbGetPrinterAddress: GetDescriptor %x" ); + if ( kIOReturnSuccess == err ) + { + /* once we've retrieved the device descriptor */ + /* try to fill in missing pieces of information */ + /* */ + /* Don't override any information already retrieved from DeviceID. */ + + if ( NULL == address->product) + { + err = (*printer)->GetString( printer, desc.iProduct, kUSBLanguageEnglish, timeout, &address->product ); + if ( kIOReturnSuccess != err || address->product == NULL) { + address->product = CFSTR("Unknown"); + } + } + DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->product\n", address->product ); + + if ( NULL == address->manufacturer ) + { + err = (*printer)->GetString( printer, desc.iManufacturer, kUSBLanguageEnglish, timeout, &address->manufacturer ); + if (kIOReturnSuccess != err || address->manufacturer == NULL) { + address->manufacturer = CFSTR("Unknown"); + } + } + DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->manufacturer\n", address->manufacturer ); + + if ( NULL == address->serial ) + { + /* if the printer doesn't have a serial number, use locationId */ + if ( 0 == desc.iSerialNumber ) + { + address->serial = CFStringCreateWithFormat( NULL, NULL, CFSTR("%lx"), (*printer)->location ); + } + else + { + err = (*printer)->GetString( printer, desc.iSerialNumber, kUSBLanguageEnglish, timeout, &address->serial ); + /* trailing NULs aren't handled correctly in URI */ + if ( address->serial ) + { + UniChar nulbyte = { 0 }; + CFStringRef trim = CFStringCreateWithCharacters(NULL, &nulbyte, 1); + CFMutableStringRef newserial = CFStringCreateMutableCopy(NULL, 0, address->serial); + + CFStringTrim( newserial, trim ); + + CFRelease(trim); + CFRelease( address->serial ); + + address->serial = newserial; + } + } + } + DEBUG_CFString( "UsbGetPrinterAddress: UsbGetString address->serial\n", address->serial ); + } + } + if ( NULL != address->product) + CFRetain(address->product); /* UsbGetString is really a UsbCopyString. */ + if ( NULL != address->manufacturer ) + CFRetain( address->manufacturer ); + if ( NULL != address->serial ) + CFRetain( address->serial ); + return err; +} + + +/*-----------------------------------------------------------------------------* + +UsbSamePrinter + + Desc: match two Usb printer address; return TRUE if they are the same. + + In: a the persistent address found last time + b the persistent address found this time + + Out: non-zero iff the addresses are the same + +*-----------------------------------------------------------------------------*/ +int +UsbSamePrinter( const USBPrinterAddress *a, const USBPrinterAddress *b ) +{ + int result = 0; + DEBUG_CFCompareString( "UsbSamePrinter serial", a->serial, b->serial ); + DEBUG_CFCompareString( "UsbSamePrinter product", a->product, b->product ); + DEBUG_CFCompareString( "UsbSamePrinter manufacturer", a->manufacturer, b->manufacturer ); + + result = !CompareSameString( a->serial, b->serial ); + if ( result ) result = !CompareSameString( a->product, b->product ); + if ( result ) result = !CompareSameString( a->manufacturer, b->manufacturer ); + + return result; +} + + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Method: UsbMakeFullUriAddress + + Input Parameters: + + Output Parameters: + + Description: + Fill in missing address information + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +CFStringRef +UsbMakeFullUriAddress( USBPrinterInfo *printer ) +{ + /* */ + /* fill in missing address information. */ + /* */ + CFMutableStringRef printerUri = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, CFSTR("usb://") ); + if ( NULL != printerUri ) + { + CFStringRef serial = printer->address.serial; + + CFStringAppend(printerUri, printer->address.manufacturer? CreateEncodedCFString( printer->address.manufacturer ): CFSTR("Unknown") ); + CFStringAppend(printerUri, CFSTR("/") ); + + CFStringAppend(printerUri, printer->address.product? CreateEncodedCFString( printer->address.product ): CFSTR("Unknown") ); + + /*Handle the common case where there is no serial number (S450?) */ + CFStringAppend(printerUri, serial == NULL? CFSTR("?location="): CFSTR("?serial=") ); + if ( serial == NULL) + serial = CFStringCreateWithFormat( NULL, NULL, CFSTR("%lx"), printer->location ); + + CFStringAppend(printerUri, serial? CreateEncodedCFString( serial ): CFSTR("Unknown") ); + } + + return printerUri; +} + + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Method: UsbGetAllPrinters + + Input Parameters: + + Output Parameters: + array of all USB printers on the system + + Description: + Build a list of USB printers by iterating IOKit USB objects + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +CFMutableArrayRef +UsbGetAllPrinters( void ) +{ + kern_return_t kr; /* kernel errors */ + mach_port_t master_device_port = 0; + io_service_t usbInterface = 0; + io_iterator_t iter = 0; + CFMutableArrayRef printers = CFArrayCreateMutable( NULL, 0, NULL ); /* all printers */ + + do + { + + kr = IOMasterPort( bootstrap_port, &master_device_port ); + DEBUG_ERR( kr, "UsbGetAllPrinters IOMasterPort %x\n" ); + if(kIOReturnSuccess != kr) break; + + { + CFDictionaryRef usbMatch = NULL; + + /* iterate over all interfaces. */ + usbMatch = IOServiceMatching(kIOUSBInterfaceClassName); + if ( !usbMatch ) break; + DEBUG_ERR( kr, "UsbGetAllPrinters IOServiceMatching %x\n" ); + + /* IOServiceGetMatchingServices() consumes the usbMatch reference so we don't need to release it. */ + kr = IOServiceGetMatchingServices(master_device_port, usbMatch, &iter); + usbMatch = NULL; + + DEBUG_ERR( kr, "UsbGetAllPrinters IOServiceGetMatchingServices %x\n" ); + if(kIOReturnSuccess != kr || iter == NULL) break; + } + + while ( NULL != (usbInterface = IOIteratorNext(iter)) ) + { + IOCFPlugInInterface **iodev; + USBPrinterInterface intf; + HRESULT res; + SInt32 score; + CFMutableDictionaryRef properties; + CFStringRef classDriver = NULL; + + kr = IORegistryEntryCreateCFProperties( usbInterface, &properties, kCFAllocatorDefault, kNilOptions); + if ( kIOReturnSuccess == kr && NULL != properties) + { + classDriver = (CFStringRef) CFDictionaryGetValue( properties, kUSBClassDriverProperty ); + if ( NULL != classDriver ) + CFRetain( classDriver ); + CFRelease( properties ); + } + + kr = IOCreatePlugInInterfaceForService( usbInterface, + kIOUSBInterfaceUserClientTypeID, + kIOCFPlugInInterfaceID, + &iodev, + &score); + + DEBUG_ERR( kr, "UsbGetAllPrinters IOCreatePlugInInterfaceForService %x\n" ); + if ( kIOReturnSuccess == kr ) + { + UInt8 intfClass = 0; + UInt8 intfSubClass = 0; + + res = (*iodev)->QueryInterface( iodev, USB_INTERFACE_KIND, (LPVOID *) &intf); + DEBUG_ERR( (kern_return_t) res, "UsbGetAllPrinters QueryInterface %x\n" ); + + (*iodev)->Release(iodev); + if ( noErr != res ) break; + + kr = (*intf)->GetInterfaceClass(intf, &intfClass); + DEBUG_ERR(kr, "UsbGetAllPrinters GetInterfaceClass %x\n"); + if ( kIOReturnSuccess == kr ) + kr = (*intf)->GetInterfaceSubClass(intf, &intfSubClass); + DEBUG_ERR(kr, "UsbGetAllPrinters GetInterfaceSubClass %x\n"); + + if ( kIOReturnSuccess == kr && + kUSBPrintingClass == intfClass && + kUSBPrintingSubclass == intfSubClass ) + { + + USBPrinterInfo printer, + *printerInfo; + /* + For each type of printer specified in the lookup spec array, find + all of that type of printer and add the results to the list of found + printers. + */ + /* create this printer's persistent address */ + memset( &printer, 0, sizeof(USBPrinterInfo) ); + kr = (*intf)->GetLocationID(intf, &printer.location); + DEBUG_ERR(kr, "UsbGetAllPrinters GetLocationID %x\n"); + if ( kIOReturnSuccess == kr ) + { + kr = UsbLoadClassDriver( &printer, kUSBPrinterClassInterfaceID, classDriver ); + DEBUG_ERR(kr, "UsbGetAllPrinters UsbLoadClassDriver %x\n"); + if ( kIOReturnSuccess == kr && printer.classdriver ) + { + (*(printer.classdriver))->interface = intf; + kr = UsbGetPrinterAddress( &printer, &printer.address, 60000L ); + { + /* always unload the driver */ + /* but don't mask last error */ + kern_return_t unload_err = UsbUnloadClassDriver( &printer ); + if ( kIOReturnSuccess == kr ) + kr = unload_err; + } + } + } + + printerInfo = UsbCopyPrinter( &printer ); + if ( NULL != printerInfo ) + CFArrayAppendValue( printers, (const void *) printerInfo ); /* keep track of it */ + + } /* if there's a printer */ + kr = (*intf)->Release(intf); + } /* if IOCreatePlugInInterfaceForService */ + + IOObjectRelease(usbInterface); + usbInterface = NULL; + + } /* while there's an interface */ + } while ( 0 ); + + if (iter) + { + IOObjectRelease(iter); + iter = 0; + } + + if (master_device_port) + { + mach_port_deallocate(mach_task_self(), master_device_port); + master_device_port = 0; + } + return printers; + +} /* UsbGetAllPrinters */ + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Method: UsbReleasePrinter + + Input Parameters: + + Output Parameters: + + Description: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +void +UsbReleasePrinter( USBPrinterInfo *printer ) +{ + if ( printer ) + { + UsbUnloadClassDriver( printer ); + if ( NULL != printer->address.manufacturer ) + CFRelease( printer->address.manufacturer ); + if ( NULL != printer->address.product ) + CFRelease( printer->address.product ); + if ( NULL != printer->address.serial ) + CFRelease( printer->address.serial ); + if ( NULL != printer->address.command ) + CFRelease( printer->address.command ); + if ( NULL != printer->bundle ) + CFRelease( printer->bundle ); + free( printer ); + } +} + +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + Method: UsbReleaseAllPrinters + + Input Parameters: + + Output Parameters: + + Description: +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ +void +UsbReleaseAllPrinters( CFMutableArrayRef printers ) +{ + if ( NULL != printers ) + { + CFIndex i, + numPrinters = CFArrayGetCount(printers); + for ( i = 0; i < numPrinters; ++i ) + UsbReleasePrinter( (USBPrinterInfo *) CFArrayGetValueAtIndex( printers, i ) ); + CFRelease( printers ); + } +} + +USBPrinterInfo * +UsbCopyPrinter( USBPrinterInfo *aPrinter ) +{ + /* */ + /* note this does not copy interface information, just address information */ + /* */ + USBPrinterInfo *printerInfo = (USBPrinterInfo *) calloc( 1, sizeof(USBPrinterInfo)); + if ( NULL != printerInfo && NULL != aPrinter ) + { + printerInfo->location = aPrinter->location; + if ( NULL != (printerInfo->address.manufacturer = aPrinter->address.manufacturer) ) + CFRetain( printerInfo->address.manufacturer ); + if ( NULL != (printerInfo->address.product = aPrinter->address.product) ) + CFRetain( printerInfo->address.product ); + if ( NULL != (printerInfo->address.serial = aPrinter->address.serial) ) + CFRetain( printerInfo->address.serial ); + if ( NULL != (printerInfo->address.command = aPrinter->address.command) ) + CFRetain( printerInfo->address.command ); + if ( NULL != (printerInfo->bundle = aPrinter->bundle) ) + CFRetain( printerInfo->bundle ); + } + + return printerInfo; +} + +/*-----------------------------------------------------------------------------* + + UsbRegistryOpen + + Desc: opens the USB printer which matches the supplied printerAddress + + In: myContext->printerAddress persistent name which identifies the printer + + Out: myContext->usbDeviceRef current IOKit address of this printer +*-----------------------------------------------------------------------------*/ +kern_return_t +UsbRegistryOpen( USBPrinterAddress *usbAddress, USBPrinterInfo **result ) +{ + kern_return_t kr = -1; /* indeterminate failure */ + CFMutableArrayRef printers = UsbGetAllPrinters(); + CFIndex numPrinters = NULL != printers? CFArrayGetCount( printers): 0; + CFIndex i; + + *result = NULL; /* nothing matched */ + for ( i = 0; i < numPrinters; ++i ) + { + USBPrinterInfo *thisPrinter = (USBPrinterInfo *) CFArrayGetValueAtIndex( printers, i ); + if ( NULL != thisPrinter && UsbSamePrinter( usbAddress, &thisPrinter->address ) ) + { + *result = UsbCopyPrinter( thisPrinter ); /* retains reference */ + if ( NULL != *result ) + { + /* */ + /* if we can't find a bi-di interface, settle for a known uni-directional interface */ + /* */ + USBPrinterClassContext **printer = NULL; + /* */ + /* setup the default class driver */ + /* If one is specified, allow the vendor driver to override our default implementation */ + /* */ + kr = UsbLoadClassDriver( *result, kUSBPrinterClassInterfaceID, NULL ); + if ( kIOReturnSuccess == kr && (*result)->bundle ) + kr = UsbLoadClassDriver( *result, kUSBPrinterClassInterfaceID, (*result)->bundle ); + if ( kIOReturnSuccess == kr && NULL != (*result)->classdriver ) + { + printer = (*result)->classdriver; + kr = (*printer)->Open( printer, (*result)->location, kUSBPrintingProtocolBidirectional ); + if ( kIOReturnSuccess != kr || NULL == (*printer)->interface ) + kr = (*printer)->Open( printer, (*result)->location, kUSBPrintingProtocolUnidirectional ); + /* it's possible kIOReturnSuccess == kr && NULL == (*printer)->interface */ + /* in the event that we can't open either Bidirectional or Unidirectional interface */ + if ( kIOReturnSuccess == kr ) + { + if ( NULL == (*printer)->interface ) + { + (*printer)->Close( printer ); + UsbReleasePrinter( *result ); + *result = NULL; + } + } + } + } + break; + } + } + UsbReleaseAllPrinters( printers ); /* but, copied printer is retained */ + DEBUG_ERR( kr, "UsbRegistryOpen return %x\n" ); + + return kr; +} + +/*! + * @function CreateEncodedCFString + * + * @abstract Create an encoded version of the string parameter + * so that it can be included in a URI. + * + * @param string A CFStringRef of the string to be encoded. + * @result An encoded CFString. + * + * @discussion This function will change all characters in string into URL acceptable format + * by encoding the text using the US-ASCII coded character set. The following + * are invalid characters: the octets 00-1F, 7F, and 80-FF hex. Also called out + * are the chars "<", ">", """, "#", "{", "}", "|", "\", "^", "~", "[", "]", "`". + * The reserved characters for URL syntax are also to be encoded: (so don't pass + * in a full URL here!) ";", "/", "?", ":", "@", "=", "%", and "&". + */ +static CFStringRef CreateEncodedCFString(CFStringRef string) +{ + CFStringRef result = NULL; + char *bufferUTF8 = NULL; + char *bufferEncoded = NULL; + + if (string != NULL) + { + CFIndex bufferSizeUTF8 = (3 * CFStringGetLength(string)); + if ((bufferUTF8 = (char*)malloc(bufferSizeUTF8)) != NULL) + { + CFStringGetCString(string, bufferUTF8, bufferSizeUTF8, kCFStringEncodingUTF8); + { + UInt16 bufferSizeEncoded = (3 * strlen(bufferUTF8)) + 1; + if ((bufferEncoded = (char*)malloc(bufferSizeEncoded)) != NULL) + { + addPercentEscapes(bufferUTF8, bufferEncoded, bufferSizeEncoded); + result = CFStringCreateWithCString(kCFAllocatorDefault, bufferEncoded, kCFStringEncodingUTF8); + } + } + } + } + + if (bufferUTF8) free(bufferUTF8); + if (bufferEncoded) free(bufferEncoded); + + return result; +} + +/* + * End of "$Id: usb-darwin.c 4548 2005-06-27 02:33:50Z mike $". + */ diff --git a/backend/usb-unix.c b/backend/usb-unix.c new file mode 100644 index 000000000..4470e9c65 --- /dev/null +++ b/backend/usb-unix.c @@ -0,0 +1,620 @@ +/* + * "$Id: usb-unix.c 4881 2005-12-15 22:03:40Z mike $" + * + * USB port backend for the Common UNIX Printing System (CUPS). + * + * This file is included from "usb.c" when compiled on UNIX/Linux. + * + * Copyright 1997-2005 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Send a file to the specified USB port. + * list_devices() - List all USB devices. + */ + +/* + * Include necessary headers. + */ + +#include "ieee1284.c" +#include + + +/* + * Local functions... + */ + +int open_device(const char *uri); + + +/* + * 'print_device()' - Print a file to a USB device. + */ + +int /* O - Exit status */ +print_device(const char *uri, /* I - Device URI */ + const char *hostname, /* I - Hostname/manufacturer */ + const char *resource, /* I - Resource/modelname */ + const char *options, /* I - Device options/serial number */ + int fp, /* I - File descriptor to print */ + int copies) /* I - Copies to print */ +{ + int fd; /* USB device */ + int rbytes; /* Number of bytes read */ + 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 */ + backbuf[1024]; /* Backchannel buffer */ + struct termios opts; /* Parallel port options */ + fd_set input, /* Input set for select() */ + output; /* Output set for select() */ + int paperout; /* Paper out? */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ +#ifdef __linux + unsigned int status; /* Port status (off-line, out-of-paper, etc.) */ +#endif /* __linux */ + + + /* + * Open the USB port device... + */ + + do + { + if ((fd = open_device(uri)) == -1) + { + if (getenv("CLASS") != NULL) + { + /* + * If the CLASS environment variable is set, the job was submitted + * to a class and not to a specific queue. In this case, we want + * to abort immediately so that the job can be requeued on the next + * available printer in the class. + */ + + fputs("INFO: Unable to open USB device, queuing on next printer in class...\n", + stderr); + + /* + * Sleep 5 seconds to keep the job from requeuing too rapidly... + */ + + sleep(5); + + return (CUPS_BACKEND_FAILED); + } + + if (errno == EBUSY) + { + fputs("INFO: USB port busy; will retry in 30 seconds...\n", stderr); + sleep(30); + } + else if (errno == ENXIO || errno == EIO || errno == ENOENT || errno == ENODEV) + { + fputs("INFO: Printer not connected; will retry in 30 seconds...\n", stderr); + sleep(30); + } + else + { + fprintf(stderr, "ERROR: Unable to open USB device \"%s\": %s\n", + uri, strerror(errno)); + return (CUPS_BACKEND_FAILED); + } + } + } + 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); + + /* + * Check printer status... + */ + + paperout = 0; + +#if defined(__linux) && defined(LP_POUTPA) + /* + * Show the printer status before we send the file... + */ + + while (!ioctl(fd, LPGETSTATUS, &status)) + { + fprintf(stderr, "DEBUG: LPGETSTATUS returned a port status of %02X...\n", status); + + if (status & LP_POUTPA) + { + fputs("WARNING: Media tray empty!\n", stderr); + fputs("STATUS: +media-tray-empty-error\n", stderr); + + paperout = 1; + } + + if (!(status & LP_PERRORP)) + fputs("WARNING: Printer fault!\n", stderr); + else if (!(status & LP_PSELECD)) + fputs("WARNING: Printer off-line.\n", stderr); + else + break; + + sleep(5); + } +#endif /* __linux && LP_POUTPA */ + + /* + * 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 (!fp) + { +#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... + */ + + wbytes = 0; + + while (copies > 0) + { + copies --; + + if (fp != 0) + { + fputs("PAGE: 1 1\n", stderr); + lseek(fp, 0, SEEK_SET); + } + + tbytes = 0; + while ((nbytes = read(fp, buffer, sizeof(buffer))) > 0) + { + /* + * Write the print data to the printer... + */ + + tbytes += nbytes; + bufptr = buffer; + + while (nbytes > 0) + { + /* + * See if we are ready to read or write... + */ + + do + { + FD_ZERO(&input); + FD_SET(fd, &input); + FD_ZERO(&output); + FD_SET(fd, &output); + } + while (select(fd + 1, &input, &output, NULL, NULL) < 0); + + if (FD_ISSET(fd, &input)) + { + /* + * Read backchannel data... + */ + + if ((rbytes = read(fd, backbuf, sizeof(backbuf))) > 0) + { + fprintf(stderr, "DEBUG: Received %d bytes of back-channel data!\n", + rbytes); + cupsBackchannelWrite(backbuf, rbytes, 1.0); + } + } + + if (FD_ISSET(fd, &output)) + { + /* + * Write print data... + */ + + if ((wbytes = write(fd, bufptr, nbytes)) < 0) + if (errno == ENOTTY) + wbytes = write(fd, bufptr, nbytes); + + if (wbytes < 0) + { + /* + * Check for retryable errors... + */ + + if (errno == ENOSPC) + { + paperout = 1; + fputs("ERROR: Out of paper!\n", stderr); + fputs("STATUS: +media-tray-empty-error\n", stderr); + } + else if (errno != EAGAIN && errno != EINTR) + { + perror("ERROR: Unable to send print file to printer"); + break; + } + } + else + { + /* + * Update count and pointer... + */ + + if (paperout) + { + fputs("STATUS: -media-tray-empty-error\n", stderr); + paperout = 0; + } + + nbytes -= wbytes; + bufptr += wbytes; + } + } + } + + if (wbytes < 0) + break; + + if (fp) + fprintf(stderr, "INFO: Sending print file, %lu bytes...\n", + (unsigned long)tbytes); + } + } + + /* + * Close the USB port and return... + */ + + close(fd); + + return (wbytes < 0 ? CUPS_BACKEND_FAILED : CUPS_BACKEND_OK); +} + + +/* + * 'list_devices()' - List all USB devices. + */ + +void +list_devices(void) +{ +#ifdef __linux + int i; /* Looping var */ + int fd; /* File descriptor */ + char format[255], /* Format for device filename */ + device[255], /* Device filename */ + device_id[1024], /* Device ID string */ + device_uri[1024], /* Device URI string */ + make_model[1024]; /* Make and model */ + + + /* + * First figure out which USB printer filename to use... + */ + + if (!access("/dev/usblp0", 0)) + strcpy(format, "/dev/usblp%d"); + else if (!access("/dev/usb/usblp0", 0)) + strcpy(format, "/dev/usb/usblp%d"); + else + strcpy(format, "/dev/usb/lp%d"); + + /* + * Then open each USB device... + */ + + for (i = 0; i < 16; i ++) + { + sprintf(device, format, i); + + if ((fd = open(device, O_RDWR | O_EXCL)) >= 0) + { + if (!get_device_id(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + "usb", device_uri, sizeof(device_uri))) + printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri, + make_model, make_model, i + 1, device_id); + + close(fd); + } + } +#elif defined(__sgi) +#elif defined(__sun) && defined(ECPPIOC_GETDEVID) + int i; /* Looping var */ + int fd; /* File descriptor */ + char device[255], /* Device filename */ + device_id[1024], /* Device ID string */ + device_uri[1024], /* Device URI string */ + make_model[1024]; /* Make and model */ + struct ecpp_device_id did; /* Device ID buffer */ + + + /* + * Open each USB device... + */ + + for (i = 0; i < 8; i ++) + { + sprintf(device, "/dev/usb/printer%d", i); + + if ((fd = open(device, O_RDWR | O_EXCL)) >= 0) + { + if (!get_device_id(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + "usb", device_uri, sizeof(device_uri))) + printf("direct %s \"%s\" \"%s USB #%d\" \"%s\"\n", device_uri, + make_model, make_model, i + 1, device_id); + + close(fd); + } + } +#elif defined(__hpux) +#elif defined(__osf) +#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) + int i; /* Looping var */ + char device[255]; /* Device filename */ + + + for (i = 0; i < 8; i ++) + { + sprintf(device, "/dev/ulpt%d", i); + if (!access(device, 0)) + printf("direct usb:%s \"Unknown\" \"USB Printer #%d\"\n", device, i + 1); + + sprintf(device, "/dev/unlpt%d", i); + if (!access(device, 0)) + printf("direct usb:%s \"Unknown\" \"USB Printer #%d (no reset)\"\n", device, i + 1); + } +#endif +} + + +/* + * 'open_device()' - Open a USB device... + */ + +int /* O - File descriptor or -1 on error */ +open_device(const char *uri) /* I - Device URI */ +{ + /* + * The generic implementation just treats the URI as a device filename... + * Specific operating systems may also support using the device serial + * number and/or make/model. + */ + + if (!strncmp(uri, "usb:/dev/", 9)) +#ifdef __linux + return (-1); /* Do not allow direct devices anymore */ + else if (!strncmp(uri, "usb://", 6)) + { + /* + * For Linux, try looking up the device serial number or model... + */ + + int i; /* Looping var */ + int busy; /* Are any ports busy? */ + int fd; /* File descriptor */ + char format[255], /* Format for device filename */ + device[255], /* Device filename */ + device_id[1024], /* Device ID string */ + make_model[1024], /* Make and model */ + device_uri[1024]; /* Device URI string */ + + + /* + * First figure out which USB printer filename to use... + */ + + if (!access("/dev/usblp0", 0)) + strcpy(format, "/dev/usblp%d"); + else if (!access("/dev/usb/usblp0", 0)) + strcpy(format, "/dev/usb/usblp%d"); + else + strcpy(format, "/dev/usb/lp%d"); + + /* + * Then find the correct USB device... + */ + + do + { + for (busy = 0, i = 0; i < 16; i ++) + { + sprintf(device, format, i); + + if ((fd = open(device, O_RDWR | O_EXCL)) >= 0) + { + get_device_id(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + "usb", device_uri, sizeof(device_uri)); + } + else + { + /* + * If the open failed because it was busy, flag it so we retry + * as needed... + */ + + if (errno == EBUSY) + busy = 1; + + device_uri[0] = '\0'; + } + + if (!strcmp(uri, device_uri)) + { + /* + * Yes, return this file descriptor... + */ + + fprintf(stderr, "DEBUG: Printer using device file \"%s\"...\n", device); + + return (fd); + } + + /* + * This wasn't the one... + */ + + if (fd >= 0) + close(fd); + } + + /* + * If we get here and at least one of the printer ports showed up + * as "busy", then sleep for a bit and retry... + */ + + if (busy) + { + fputs("INFO: USB printer is busy; will retry in 5 seconds...\n", + stderr); + sleep(5); + } + } + while (busy); + + /* + * Couldn't find the printer, return "no such device or address"... + */ + + errno = ENODEV; + + return (-1); + } +#elif defined(__sun) && defined(ECPPIOC_GETDEVID) + return (-1); /* Do not allow direct devices anymore */ + else if (!strncmp(uri, "usb://", 6)) + { + /* + * For Solaris, try looking up the device serial number or model... + */ + + int i; /* Looping var */ + int busy; /* Are any ports busy? */ + int fd; /* File descriptor */ + char device[255], /* Device filename */ + device_id[1024], /* Device ID string */ + make_model[1024], /* Make and model */ + device_uri[1024]; /* Device URI string */ + struct ecpp_device_id did; /* Device ID buffer */ + + + /* + * Find the correct USB device... + */ + + do + { + for (i = 0, busy = 0; i < 8; i ++) + { + sprintf(device, "/dev/usb/printer%d", i); + + if ((fd = open(device, O_RDWR | O_EXCL)) >= 0) + get_device_id(fd, device_id, sizeof(device_id), + make_model, sizeof(make_model), + "usb", device_uri, sizeof(device_uri)); + else + { + /* + * If the open failed because it was busy, flag it so we retry + * as needed... + */ + + if (errno == EBUSY) + busy = 1; + + device_uri[0] = '\0'; + } + + if (!strcmp(uri, device_uri)) + return (fd); /* Yes, return this file descriptor... */ + + /* + * This wasn't the one... + */ + + if (fd >= 0) + close(fd); + } + + /* + * If we get here and at least one of the printer ports showed up + * as "busy", then sleep for a bit and retry... + */ + + if (busy) + { + fputs("INFO: USB printer is busy; will retry in 5 seconds...\n", + stderr); + sleep(5); + } + } + while (busy); + + /* + * Couldn't find the printer, return "no such device or address"... + */ + + errno = ENODEV; + + return (-1); + } +#else + return (open(uri + 4, O_RDWR | O_EXCL)); +#endif /* __linux */ + else + { + errno = ENODEV; + return (-1); + } +} + + +/* + * End of "$Id: usb-unix.c 4881 2005-12-15 22:03:40Z mike $". + */ diff --git a/backend/usb.c b/backend/usb.c new file mode 100644 index 000000000..3ffe2d0d1 --- /dev/null +++ b/backend/usb.c @@ -0,0 +1,273 @@ +/* + * "$Id: usb.c 4906 2006-01-10 20:53:28Z mike $" + * + * USB port backend for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * list_devices() - List all available USB devices to stdout. + * print_device() - Print a file to a USB device. + * main() - Send a file to the specified USB port. + */ + +/* + * Include necessary headers. + */ + +#ifdef __APPLE__ + /* A header order dependency requires this be first */ +# include +#endif /* __APPLE__ */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +#else +# include +# include +# include +#endif /* WIN32 */ + + +/* + * Local functions... + */ + +void list_devices(void); +int print_device(const char *uri, const char *hostname, + const char *resource, const char *options, + int fp, int copies); + + +/* + * Include the vendor-specific USB implementation... + */ + +#ifdef __APPLE__ +# include "usb-darwin.c" +#elif defined(__linux) || defined(__sun) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) +# include "usb-unix.c" +#else +/* + * Use dummy functions that do nothing on unsupported platforms... + * These can be used as templates for implementing USB printing on new + * platforms... + */ + +/* + * 'list_devices()' - List all available USB devices to stdout. + */ + +void +list_devices(void) +{ + /* + * Don't have any devices to list... Use output of the form: + * + * direct usb:/make/model?serial=foo "Make Model" "USB Printer" + * + * Note that "Hewlett Packard" or any other variation MUST be mapped to + * "HP" for compatibility with the PPD and ICC specs. + */ +} + + +/* + * 'print_device()' - Print a file to a USB device. + */ + +int /* O - Exit status */ +print_device(const char *uri, /* I - Device URI */ + const char *hostname, /* I - Hostname/manufacturer */ + const char *resource, /* I - Resource/modelname */ + const char *options, /* I - Device options/serial number */ + int fp, /* I - File descriptor to print */ + int copies) /* I - Copies to print */ +{ + /* + * Can't print, so just reference the arguments to eliminate compiler + * warnings and return and exit status of 1. Normally you would use the + * arguments to send a file to the printer and return 0 if everything + * worked OK and non-zero if there was an error. + */ + + (void)uri; + (void)hostname; + (void)resource; + (void)options; + (void)fp; + (void)copies; + + return (CUPS_BACKEND_FAILED); +} +#endif /* __APPLE__ */ + + +/* + * '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 */ +{ + int fp; /* Print file */ + int copies; /* Number of copies to print */ + int status; /* Exit status */ + int port; /* Port number (not used) */ + const char *uri; /* Device URI */ + 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 */ +#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); + + /* + * Ignore SIGPIPE signals... + */ + +#ifdef HAVE_SIGSET + sigset(SIGPIPE, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_IGN); +#endif /* HAVE_SIGSET */ + + /* + * Check command-line... + */ + + if (argc == 1) + { + list_devices(); + return (CUPS_BACKEND_OK); + } + else if (argc < 6 || argc > 7) + { + fputs("Usage: usb job-id user title copies options [file]\n", stderr); + return (CUPS_BACKEND_FAILED); + } + + /* + * Extract the device name and options from the URI... + */ + + if (strncmp(argv[0], "usb:", 4)) + uri = getenv("DEVICE_URI"); + else + uri = argv[0]; + + if (!uri) + { + fputs("ERROR: No device URI found in argv[0] or in DEVICE_URI environment variable!\n", stderr); + return (1); + } + + httpSeparateURI(argv[0], method, sizeof(method), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(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'; + } + + /* + * If we have 7 arguments, print the file named on the command-line. + * Otherwise, send stdin instead... + */ + + if (argc == 6) + { + fp = 0; + copies = 1; + } + else + { + /* + * Try to open the print file... + */ + + if ((fp = open(argv[6], O_RDONLY)) < 0) + { + fprintf(stderr, "ERROR: unable to open print file %s - %s\n", + argv[6], strerror(errno)); + return (CUPS_BACKEND_FAILED); + } + + copies = atoi(argv[4]); + } + + /* + * Finally, send the print file... + */ + + status = print_device(uri, hostname, resource, options, fp, copies); + + /* + * Close the input file and return... + */ + + if (fp != 0) + close(fp); + + return (status); +} + + +/* + * End of "$Id: usb.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/berkeley/Dependencies b/berkeley/Dependencies new file mode 100644 index 000000000..ceb85278c --- /dev/null +++ b/berkeley/Dependencies @@ -0,0 +1,14 @@ +# DO NOT DELETE + +lpc.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +lpc.o: ../cups/ppd.h ../cups/file.h ../cups/i18n.h ../cups/language.h +lpc.o: ../cups/array.h ../cups/debug.h ../cups/string.h ../config.h +lpq.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h +lpq.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h +lpq.o: ../cups/i18n.h ../cups/language.h ../cups/array.h ../cups/debug.h +lpr.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h +lpr.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h +lpr.o: ../cups/i18n.h ../cups/language.h ../cups/array.h +lprm.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +lprm.o: ../cups/ppd.h ../cups/file.h ../cups/i18n.h ../cups/language.h +lprm.o: ../cups/array.h ../cups/string.h ../config.h diff --git a/berkeley/Makefile b/berkeley/Makefile new file mode 100644 index 000000000..454f6d657 --- /dev/null +++ b/berkeley/Makefile @@ -0,0 +1,112 @@ +# +# "$Id: Makefile 4494 2005-02-18 02:18:11Z mike $" +# +# Berkeley commands makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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) + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1 + + +# +# Install all targets... +# + +install: all + $(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) + + +# +# lpq +# + +lpq: lpq.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpq lpq.o $(LIBS) + + +# +# lpr +# + +lpr: lpr.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpr lpr.o $(LIBS) + + +# +# lprm +# + +lprm: lprm.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lprm lprm.o $(LIBS) + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/berkeley/lpc.c b/berkeley/lpc.c new file mode 100644 index 000000000..4b80a618d --- /dev/null +++ b/berkeley/lpc.c @@ -0,0 +1,524 @@ +/* + * "$Id: lpc.c 4906 2006-01-10 20:53:28Z mike $" + * + * "lpc" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and commands. + * compare_strings() - Compare two command-line strings. + * do_command() - Do an lpc command... + * show_help() - Show help messages. + * show_status() - Show printers. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static int compare_strings(const char *, const char *, int); +static void do_command(http_t *, const char *, const char *); +static void show_help(const char *); +static void show_status(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 */ +{ + 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 trailing whitespace... + */ + + for (params = line + strlen(line) - 1; params >= line;) + if (!isspace(*params & 255)) + break; + else + *params-- = '\0'; + + /* + * Strip leading whitespace... + */ + + for (params = line; isspace(*params & 255); params ++); + + if (params > line) + _cups_strcpy(line, params); + + if (!line[0]) + { + /* + * Nothing left, just show a prompt... + */ + + printf("lpc> "); + continue; + } + + /* + * Find any options in the string... + */ + + for (params = line; *params != '\0'; params ++) + if (isspace(*params & 255)) + break; + + /* + * Remove whitespace between the command and parameters... + */ + + while (isspace(*params & 255)) + *params++ = '\0'; + + /* + * The "quit" and "exit" commands exit; otherwise, process as needed... + */ + + if (!compare_strings(line, "quit", 1) || + !compare_strings(line, "exit", 2)) + 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(const char *s, /* I - Command-line string */ + const 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 */ + const char *command, /* I - Command string */ + const char *params) /* I - Parameters for command */ +{ + if (!compare_strings(command, "status", 4)) + show_status(http, params); + else if (!compare_strings(command, "help", 1) || !strcmp(command, "?")) + show_help(params); + else + _cupsLangPrintf(stdout, cupsLangDefault(), + _("%s is not implemented by the CUPS version of lpc.\n"), + command); +} + + +/* + * 'show_help()' - Show help messages. + */ + +static void +show_help(const char *command) /* I - Command to describe or NULL */ +{ + if (!command) + { + _cupsLangPrintf(stdout, cupsLangDefault(), + _("Commands may be abbreviated. Commands are:\n" + "\n" + "exit help quit status ?\n")); + } + else if (!compare_strings(command, "help", 1) || !strcmp(command, "?")) + _cupsLangPrintf(stdout, cupsLangDefault(), + _("help\t\tget help on commands\n")); + else if (!compare_strings(command, "status", 4)) + _cupsLangPrintf(stdout, cupsLangDefault(), + _("status\t\tshow status of daemon and queue\n")); + else + _cupsLangPrintf(stdout, cupsLangDefault(), + _("?Invalid help command unknown\n")); +} + + +/* + * 'show_status()' - Show printers. + */ + +static void +show_status(http_t *http, /* I - HTTP connection to server */ + const 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 */ + *delimiter; /* Char search result */ + ipp_pstate_t pstate; /* Printer state */ + int accepting; /* Is printer accepting jobs? */ + int jobcount; /* Count of current jobs */ + 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 */ + static const char *requested[] = /* Requested attributes */ + { + "printer-name", + "device-uri", + "printer-state", + "printer-is-accepting-jobs" + }; + + + DEBUG_printf(("show_status(http=%p, dests=\"%s\")\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, "/")) != 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") && + attr->value_tag == IPP_TAG_NAME) + printer = attr->values[0].string.text; + + if (!strcmp(attr->name, "device-uri") && + attr->value_tag == IPP_TAG_URI) + device = attr->values[0].string.text; + + if (!strcmp(attr->name, "printer-state") && + attr->value_tag == IPP_TAG_ENUM) + pstate = (ipp_pstate_t)attr->values[0].integer; + + if (!strcmp(attr->name, "printer-is-accepting-jobs") && + 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; + } + + /* + * A single 'all' printer name is special, meaning all printers. + */ + + if (dests != NULL && !strcmp(dests, "all")) + dests = NULL; + + /* + * 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 & 255) || *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 & 255))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr & 255) && *dptr != '\0') + dptr ++; + while (isspace(*dptr & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + } + } + + /* + * Display the printer entry if needed... + */ + + if (match) + { + /* + * 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); + + httpAssembleURIf(printer_uri, sizeof(printer_uri), "ipp", NULL, + "localhost", 631, "/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, "/")) != NULL) + { + /* + * Grab the number of jobs for the printer. + */ + + for (jattr = jobs->attrs; jattr != NULL; jattr = jattr->next) + if (jattr->name && !strcmp(jattr->name, "job-id")) + jobcount ++; + + ippDelete(jobs); + } + + /* + * Display it... + */ + + printf("%s:\n", printer); + if (!strncmp(device, "file:", 5)) + _cupsLangPrintf(stdout, language, + _("\tprinter is on device \'%s\' speed -1\n"), + device + 5); + else + { + /* + * Just show the scheme... + */ + + if ((delimiter = strchr(device, ':')) != NULL ) + { + *delimiter = '\0'; + _cupsLangPrintf(stdout, language, + _("\tprinter is on device \'%s\' speed -1\n"), + device); + } + } + + if (accepting) + _cupsLangPuts(stdout, language, _("\tqueuing is enabled\n")); + else + _cupsLangPuts(stdout, language, _("\tqueuing is disabled\n")); + + if (pstate != IPP_PRINTER_STOPPED) + _cupsLangPuts(stdout, language, _("\tprinting is enabled\n")); + else + _cupsLangPuts(stdout, language, _("\tprinting is disabled\n")); + + if (jobcount == 0) + _cupsLangPuts(stdout, language, _("\tno entries\n")); + else + _cupsLangPrintf(stdout, language, _("\t%d entries\n"), jobcount); + + _cupsLangPuts(stdout, language, _("\tdaemon present\n")); + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } +} + + +/* + * End of "$Id: lpc.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/berkeley/lpq.c b/berkeley/lpq.c new file mode 100644 index 000000000..a5e009171 --- /dev/null +++ b/berkeley/lpq.c @@ -0,0 +1,640 @@ +/* + * "$Id: lpq.c 4906 2006-01-10 20:53:28Z mike $" + * + * "lpq" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and commands. + * show_jobs() - Show jobs. + * show_printer() - Show printer status. + * usage() - Show program usage. + */ + +/* + * Include necessary headers... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static int show_jobs(http_t *, const char *, const char *, const int, + const int); +static void show_printer(http_t *, const char *); +static void usage(void); + + +/* + * '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 */ + *val; /* Environment variable name */ + char *instance; /* Printer instance */ + int id, /* Desired job ID */ + all, /* All printers */ + interval, /* Reporting interval */ + longstatus; /* Show file details */ + int num_dests; /* Number of destinations */ + cups_dest_t *dests; /* Destinations */ + cups_lang_t *language; /* Language */ +#ifdef HAVE_SSL + http_encryption_t encryption; /* Encryption? */ +#endif /* HAVE_SSL */ + + + language = cupsLangDefault(); + + /* + * Connect to the scheduler... + */ + + if ((http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption())) == NULL) + { + _cupsLangPuts(stderr, language, + _("lpq: Unable to contact server!\n")); + return (1); + } + + /* + * Check for command-line options... + */ + + dest = NULL; + user = NULL; + id = 0; + interval = 0; + longstatus = 0; + all = 0; + num_dests = cupsGetDests(&dests); + + 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_SSL + encryption = HTTP_ENCRYPT_REQUIRED; + + if (http) + httpEncryption(http, encryption); +#else + _cupsLangPrintf(stderr, language, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + break; + + case 'P' : /* Printer */ + if (argv[i][2]) + dest = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + httpClose(http); + cupsFreeDests(num_dests, dests); + + usage(); + } + + dest = argv[i]; + } + + if ((instance = strchr(dest, '/')) != NULL) + *instance++ = '\0'; + + if (cupsGetDest(dest, instance, num_dests, dests) == NULL) + { + if (instance) + _cupsLangPrintf(stderr, language, + _("lpq: Unknown destination \"%s/%s\"!\n"), + dest, instance); + else + _cupsLangPrintf(stderr, language, + _("lpq: Unknown destination \"%s\"!\n"), dest); + + return (1); + } + break; + + case 'a' : /* All printers */ + all = 1; + break; + + case 'l' : /* Long status */ + longstatus = 1; + break; + + default : + httpClose(http); + cupsFreeDests(num_dests, dests); + + usage(); + break; + } + } + else if (isdigit(argv[i][0] & 255)) + id = atoi(argv[i]); + else + user = argv[i]; + + if (dest == NULL && !all) + { + for (i = 0; i < num_dests; i ++) + if (dests[i].is_default) + dest = dests[i].name; + + if (dest == NULL) + { + val = NULL; + + if ((dest = getenv("LPDEST")) == NULL) + { + if ((dest = getenv("PRINTER")) != NULL) + { + if (!strcmp(dest, "lp")) + dest = NULL; + else + val = "PRINTER"; + } + } + else + val = "LPDEST"; + + if (dest && !cupsGetDest(dest, NULL, num_dests, dests)) + _cupsLangPrintf(stderr, language, + _("lp: error - %s environment variable names " + "non-existent destination \"%s\"!\n"), + val, dest); + else + _cupsLangPuts(stderr, language, + _("lpq: error - no default destination available.\n")); + httpClose(http); + cupsFreeDests(num_dests, dests); + return (1); + } + } + + /* + * 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 + { + httpAssembleURIf(resource, sizeof(resource), "ipp", NULL, "localhost", 0, + "/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) + { + _cupsLangPrintf(stderr, language, _("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; + +#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__ + _cupsLangPuts(stdout, language, + _("Rank Owner Pri Job Files" + " Total Size\n")); +#else + _cupsLangPuts(stdout, language, + _("Rank Owner Job File(s)" + " Total Size\n")); +#endif /* __osf__ */ + + jobcount ++; + + /* + * Display the job... + */ + + if (jobstate == IPP_JOB_PROCESSING) + strcpy(rankstr, "active"); + else + { + /* + * Make the rank show the "correct" suffix for each number + * (11-13 are the only special cases, for English anyways...) + */ + + if ((rank % 100) >= 11 && (rank % 100) <= 13) + snprintf(rankstr, sizeof(rankstr), "%dth", rank); + else + snprintf(rankstr, sizeof(rankstr), "%d%s", rank, ranks[rank % 10]); + + rank ++; + } + + if (longstatus) + { + _cupsLangPuts(stdout, language, ""); + + if (jobcopies > 1) + snprintf(namestr, sizeof(namestr), "%d copies of %s", jobcopies, + jobname); + else + strlcpy(namestr, jobname, sizeof(namestr)); + + _cupsLangPrintf(stdout, language, _("%s: %-33.33s [job %d localhost]\n"), + jobuser, rankstr, jobid); + _cupsLangPrintf(stdout, language, _(" %-39.39s %.0f bytes\n"), + namestr, 1024.0 * jobsize); + } + else +#ifdef __osf__ + _cupsLangPrintf(stdout, language, + _("%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n"), + rankstr, jobuser, jobpriority, jobid, jobname, + 1024.0 * jobsize); +#else + _cupsLangPrintf(stdout, language, + _("%-7s %-7.7s %-7d %-31.31s %.0f bytes\n"), + rankstr, jobuser, jobid, jobname, 1024.0 * jobsize); +#endif /* __osf */ + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, language, _("lpq: get-jobs failed: %s\n"), + ippErrorString(cupsLastError())); + return (0); + } + + if (jobcount == 0) + _cupsLangPuts(stdout, language, _("no entries\n")); + + 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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) + { + _cupsLangPrintf(stderr, language, + _("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 : + _cupsLangPrintf(stdout, language, _("%s is ready\n"), dest); + break; + case IPP_PRINTER_PROCESSING : + _cupsLangPrintf(stdout, language, _("%s is ready and printing\n"), + dest); + break; + case IPP_PRINTER_STOPPED : + _cupsLangPrintf(stdout, language, _("%s is not ready\n"), dest); + break; + } + + ippDelete(response); + } + else + _cupsLangPrintf(stderr, language, + _("lpq: get-printer-attributes failed: %s\n"), + ippErrorString(cupsLastError())); +} + + +/* + * 'usage()' - Show program usage. + */ + +static void +usage(void) +{ + _cupsLangPuts(stderr, cupsLangDefault(), + _("Usage: lpq [-P dest] [-l] [+interval]\n")); + exit(1); +} + + +/* + * End of "$Id: lpq.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/berkeley/lpr.c b/berkeley/lpr.c new file mode 100644 index 000000000..58c9202f4 --- /dev/null +++ b/berkeley/lpr.c @@ -0,0 +1,495 @@ +/* + * "$Id: lpr.c 4906 2006-01-10 20:53:28Z mike $" + * + * "lpr" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and send files for printing. + * sighandler() - Signal catcher for when we print from stdin... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + +#include +#include +#include + +#ifndef WIN32 +# include +# include + + +/* + * Local functions. + */ + +void sighandler(int); +#endif /* !WIN32 */ + + +/* + * Globals... + */ + +char tempfile[1024]; /* Temporary file for printing from stdin */ + + +/* + * 'main()' - Parse options and send files for printing. + */ + +int +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, 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 */ + *val; /* Environment variable name */ + 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 */ + cups_lang_t *language; /* Language information */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Signal action */ + struct sigaction oldaction; /* Old 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; + language = cupsLangDefault(); + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-') + switch (ch = argv[i][1]) + { + case 'E' : /* Encrypt */ +#ifdef HAVE_SSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); +#else + _cupsLangPrintf(stderr, language, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + 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) + { + _cupsLangPrintf(stderr, language, + _("lpr: error - 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 */ + _cupsLangPrintf(stderr, language, + _("lpr: 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) + { + _cupsLangPuts(stderr, language, + _("lpr: error - expected option=value after " + "-o option!\n")); + 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 */ + _cupsLangPuts(stderr, language, + _("lpr: warning - email notification is not " + "currently supported!\n")); + 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) + { + _cupsLangPuts(stderr, language, + _("lpr: error - expected destination after -P " + "option!\n")); + 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) + { + _cupsLangPuts(stderr, language, + _("lpr: error - expected copy count after -# " + "option!\n")); + return (1); + } + + num_copies = atoi(argv[i]); + } + + 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) + { + _cupsLangPrintf(stderr, language, + _("lpr: error - 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) + { + _cupsLangPuts(stderr, language, + _("lpr: error - expected username after -U " + "option!\n")); + return (1); + } + + cupsSetUser(argv[i]); + } + break; + + default : + _cupsLangPrintf(stderr, language, + _("lpr: error - unknown option \'%c\'!\n"), + argv[i][1]); + return (1); + } + else if (num_files < 1000) + { + /* + * Print a file... + */ + + if (access(argv[i], R_OK) != 0) + { + _cupsLangPrintf(stderr, language, + _("lpr: error - unable to access \"%s\" - %s\n"), + argv[i], strerror(errno)); + return (1); + } + + files[num_files] = argv[i]; + num_files ++; + + if (title == NULL) + { + if ((title = strrchr(argv[i], '/')) != NULL) + title ++; + else + title = argv[i]; + } + } + else + _cupsLangPrintf(stderr, language, + _("lpr: error - 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); + + if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) + { + printer = dest->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); + } + } + + if (printer == NULL) + { + val = NULL; + + if ((printer = getenv("LPDEST")) == NULL) + { + if ((printer = getenv("PRINTER")) != NULL) + { + if (!strcmp(printer, "lp")) + printer = NULL; + else + val = "PRINTER"; + } + } + else + val = "LPDEST"; + + if (printer && !cupsGetDest(printer, NULL, num_dests, dests)) + _cupsLangPrintf(stderr, language, + _("lpr: error - %s environment variable names " + "non-existent destination \"%s\"!\n"), + val, printer); + else if (cupsLastError() == IPP_NOT_FOUND) + _cupsLangPuts(stderr, language, + _("lpr: error - no default destination available.\n")); + else + _cupsLangPuts(stderr, language, + _("lpr: error - scheduler not responding!\n")); + + return (1); + } + + if (num_files > 0) + { + job_id = cupsPrintFiles(printer, num_files, files, title, num_options, options); + + if (deletefile && job_id > 0) + { + /* + * 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); + if (sigset(SIGINT, sighandler) == SIG_IGN) + sigset(SIGINT, SIG_IGN); + sigset(SIGTERM, sighandler); +# elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = sighandler; + + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, NULL, &oldaction); + if (oldaction.sa_handler != SIG_IGN) + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); +# else + signal(SIGHUP, sighandler); + if (signal(SIGINT, sighandler) == SIG_IGN) + signal(SIGINT, SIG_IGN); + signal(SIGTERM, sighandler); +# endif +#endif /* !WIN32 */ + + if ((temp = cupsTempFd(tempfile, sizeof(tempfile))) < 0) + { + _cupsLangPrintf(stderr, language, + _("lpr: error - unable to create temporary file " + "\"%s\" - %s\n"), + tempfile, strerror(errno)); + return (1); + } + + while ((i = read(0, buffer, sizeof(buffer))) > 0) + if (write(temp, buffer, i) < 0) + { + _cupsLangPrintf(stderr, language, + _("lpr: error - unable to write to temporary file " + "\"%s\" - %s\n"), + tempfile, strerror(errno)); + close(temp); + unlink(tempfile); + return (1); + } + + i = lseek(temp, 0, SEEK_CUR); + close(temp); + + if (i == 0) + { + _cupsLangPuts(stderr, language, + _("lpr: error - stdin is empty, so no job has been sent.\n")); + unlink(tempfile); + 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) + { + _cupsLangPrintf(stderr, language, + _("lpr: error - 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: lpr.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/berkeley/lprm.c b/berkeley/lprm.c new file mode 100644 index 000000000..f6fe9fc6b --- /dev/null +++ b/berkeley/lprm.c @@ -0,0 +1,284 @@ +/* + * "$Id: lprm.c 4906 2006-01-10 20:53:28Z mike $" + * + * "lprm" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and cancel jobs. + */ + +/* + * Include necessary headers... + */ + +#include +#include + +#include +#include +#include + + +/* + * 'main()' - Parse options and cancel jobs. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + http_t *http; /* HTTP connection to server */ + int i; /* Looping var */ + int job_id; /* Job ID */ + const char *dest; /* Destination printer */ + char *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(); + language = cupsLangDefault(); + 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) + { + _cupsLangPuts(stderr, language, _("lprm: Unable to contact server!\n")); + 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_SSL + encryption = HTTP_ENCRYPT_REQUIRED; + + httpEncryption(http, encryption); +#else + _cupsLangPrintf(stderr, language, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + 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'; + + if (cupsGetDest(dest, NULL, num_dests, dests) == NULL) + { + _cupsLangPrintf(stderr, language, + _("lprm: Unknown destination \"%s\"!\n"), dest); + cupsFreeDests(num_dests, dests); + httpClose(http); + return(1); + } + break; + + default : + _cupsLangPrintf(stderr, language, + _("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] & 255) && + cupsGetDest(argv[i], NULL, num_dests, dests) == NULL) + { + 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; + + 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) + { + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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 : + _cupsLangPuts(stderr, language, + _("lprm: Job or printer not found!\n")); + break; + case IPP_NOT_AUTHORIZED : + _cupsLangPuts(stderr, language, + _("lprm: Not authorized to lprm job(s)!\n")); + break; + case IPP_FORBIDDEN : + _cupsLangPrintf(stderr, language, + _("lprm: You don't own job ID %d!\n"), job_id); + break; + default : + if (response->request.status.status_code > IPP_OK_CONFLICT) + _cupsLangPuts(stderr, language, + _("lprm: Unable to lprm job(s)!\n")); + break; + } + + if (response->request.status.status_code > IPP_OK_CONFLICT) + { + ippDelete(response); + cupsFreeDests(num_dests, dests); + httpClose(http); + return (1); + } + + ippDelete(response); + } + else + { + _cupsLangPuts(stderr, language, + _("lprm: Unable to cancel job(s)!\n")); + 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)) + { + _cupsLangPuts(stderr, language, + _("lprm: Unable to cancel job(s)!\n")); + cupsFreeDests(num_dests, dests); + httpClose(http); + return (1); + } + + cupsFreeDests(num_dests, dests); + httpClose(http); + + return (0); +} + + +/* + * End of "$Id: lprm.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/cgi-bin/Dependencies b/cgi-bin/Dependencies new file mode 100644 index 000000000..fbcdc3d50 --- /dev/null +++ b/cgi-bin/Dependencies @@ -0,0 +1,50 @@ +# DO NOT DELETE + +help-index.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +help-index.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +help-index.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h +help-index.o: ../cups/array.h ../cups/string.h ../config.h ../cups/dir.h +html.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +html.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +html.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +html.o: ../cups/string.h ../config.h +ipp-var.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +ipp-var.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +ipp-var.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +ipp-var.o: ../cups/string.h ../config.h +search.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +search.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +search.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +search.o: ../cups/string.h ../config.h +template.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +template.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +template.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +template.o: ../cups/string.h ../config.h +var.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +var.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +var.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +var.o: ../cups/string.h ../config.h +admin.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +admin.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +admin.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +admin.o: ../cups/string.h ../config.h ../cups/file.h +classes.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +classes.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +classes.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +classes.o: ../cups/string.h ../config.h +help.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +help.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +help.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +help.o: ../cups/string.h ../config.h +jobs.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +jobs.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +jobs.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +jobs.o: ../cups/string.h ../config.h +printers.o: cgi-private.h cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +printers.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h help-index.h +printers.o: ../cups/debug.h ../cups/i18n.h ../cups/language.h ../cups/array.h +printers.o: ../cups/string.h ../config.h +testcgi.o: cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +testcgi.o: ../cups/ppd.h ../cups/file.h help-index.h +testhi.o: cgi.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +testhi.o: ../cups/ppd.h ../cups/file.h help-index.h diff --git a/cgi-bin/Makefile b/cgi-bin/Makefile new file mode 100644 index 000000000..fd218a306 --- /dev/null +++ b/cgi-bin/Makefile @@ -0,0 +1,151 @@ +# +# "$Id: Makefile 4869 2005-12-06 02:43:40Z mike $" +# +# CGI makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +CGIS = admin.cgi classes.cgi help.cgi jobs.cgi printers.cgi +TARGETS = libcgi.a $(CGIS) testcgi testhi +LIBOBJS = help-index.o html.o ipp-var.o search.o template.o var.o +OBJS = $(LIBOBJS) admin.o classes.o help.o \ + jobs.o printers.o testcgi.o testhi.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1 + + +# +# Install all targets... +# + +install: all + $(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) $@ + + +# +# admin.cgi +# + +admin.cgi: admin.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ admin.o libcgi.a $(LIBS) + + +# +# classes.cgi +# + +classes.cgi: classes.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ classes.o libcgi.a $(LIBS) + + +# +# help.cgi +# + +help.cgi: help.o ../Makedefs libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ help.o libcgi.a $(LIBS) + + +# +# jobs.cgi +# + +jobs.cgi: jobs.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ jobs.o libcgi.a $(LIBS) + + +# +# printers.cgi +# + +printers.cgi: printers.o ../Makedefs ../cups/$(LIBCUPS) libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ printers.o libcgi.a $(LIBS) + + +# +# testcgi +# + +testcgi: testcgi.o ../Makedefs libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testcgi.o libcgi.a $(LIBS) + + +# +# testhi +# + +testhi: testhi.o ../Makedefs libcgi.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testhi.o libcgi.a $(LIBS) + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4869 2005-12-06 02:43:40Z mike $". +# diff --git a/cgi-bin/admin.c b/cgi-bin/admin.c new file mode 100644 index 000000000..37be8beaa --- /dev/null +++ b/cgi-bin/admin.c @@ -0,0 +1,3572 @@ +/* + * "$Id: admin.c 4921 2006-01-12 21:26:26Z mike $" + * + * Administration CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + * compare_printer_devices() - Compare two printer devices. + * 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_config_server() - Configure server settings. + * do_delete_class() - Delete a class... + * do_delete_printer() - Delete a printer... + * do_menu() - Show the main menu... + * do_printer_op() - Do a printer operation. + * do_set_allowed_users() - Set the allowed/denied users for a queue. + * do_set_sharing() - Set printer-is-shared value... + * match_string() - Return the number of matching characters. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.h" +#include +#include + + +/* + * 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_config_server(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_menu(http_t *http, cups_lang_t *language); +static void do_printer_op(http_t *http, cups_lang_t *language, + ipp_op_t op, const char *title); +static void do_set_allowed_users(http_t *http, cups_lang_t *language); +static void do_set_sharing(http_t *http, cups_lang_t *language); +static int match_string(const char *a, const char *b); + + +/* + * '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(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + /* + * Set the web interface section... + */ + + cgiSetVariable("SECTION", "admin"); + + /* + * See if we have form data... + */ + + if (!cgiInitialize()) + { + /* + * Nope, send the administration menu... + */ + + do_menu(http, language); + } + else if ((op = cgiGetVariable("OP")) != NULL) + { + /* + * Do the operation... + */ + + if (!strcmp(op, "redirect")) + { + const char *url; /* Redirection URL... */ + + + if ((url = cgiGetVariable("URL")) != NULL) + printf("Location: %s\n\n", url); + else + puts("Location: /admin\n"); + } + else if (!strcmp(op, "start-printer")) + do_printer_op(http, language, IPP_RESUME_PRINTER, "Start Printer"); + else if (!strcmp(op, "stop-printer")) + do_printer_op(http, language, IPP_PAUSE_PRINTER, "Stop Printer"); + else if (!strcmp(op, "start-class")) + do_printer_op(http, language, IPP_RESUME_PRINTER, "Start Class"); + else if (!strcmp(op, "stop-class")) + do_printer_op(http, language, IPP_PAUSE_PRINTER, "Stop Class"); + else if (!strcmp(op, "accept-jobs")) + do_printer_op(http, language, CUPS_ACCEPT_JOBS, "Accept Jobs"); + else if (!strcmp(op, "reject-jobs")) + do_printer_op(http, language, CUPS_REJECT_JOBS, "Reject Jobs"); + else if (!strcmp(op, "purge-jobs")) + do_printer_op(http, language, IPP_PURGE_JOBS, "Purge Jobs"); + else if (!strcmp(op, "set-allowed-users")) + do_set_allowed_users(http, language); + else if (!strcmp(op, "set-as-default")) + do_printer_op(http, language, CUPS_SET_DEFAULT, "Set As Default"); + else if (!strcmp(op, "set-sharing")) + do_set_sharing(http, language); + else if (!strcmp(op, "add-class")) + do_am_class(http, language, 0); + else if (!strcmp(op, "add-printer")) + do_am_printer(http, language, 0); + else if (!strcmp(op, "modify-class")) + do_am_class(http, language, 1); + else if (!strcmp(op, "modify-printer")) + do_am_printer(http, language, 1); + else if (!strcmp(op, "delete-class")) + do_delete_class(http, language); + else if (!strcmp(op, "delete-printer")) + do_delete_printer(http, language); + else if (!strcmp(op, "set-printer-options")) + do_config_printer(http, language); + else if (!strcmp(op, "config-server")) + do_config_server(http, language); + else + { + /* + * Bad operation code... Display an error... + */ + + cgiStartHTML("Error"); + cgiCopyTemplateLang("admin-op.tmpl"); + cgiEndHTML(); + } + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + } + else + { + /* + * Form data but no operation code... Display an error... + */ + + cgiStartHTML("Error"); + cgiCopyTemplateLang("admin-op.tmpl"); + cgiEndHTML(); + } + + /* + * Free the request language... + */ + + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'compare_printer_devices()' - Compare two printer devices. + */ + +static int /* O - Result of comparison */ +compare_printer_devices(const void *a, /* I - First device */ + const void *b) /* I - Second device */ +{ + return (strcmp(*((char **)a), *((char **)b))); +} + + +/* + * '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 */ + const char *title; /* Title of page */ + static const char * const pattrs[] = /* Requested printer attributes */ + { + "member-names", + "printer-info", + "printer-location" + }; + + + title = modify ? "Modify Class" : "Add Class"; + name = cgiGetVariable("PRINTER_NAME"); + + if (cgiGetVariable("PRINTER_LOCATION") == 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")) + { + if ((ptr = strrchr(attr->values[0].string.text, '/')) != NULL && + (!name || strcasecmp(name, ptr + 1))) + { + /* + * Don't show the current class... + */ + + 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")) + { + if (!name || strcasecmp(name, attr->values[0].string.text)) + { + /* + * Don't show the current class... + */ + + cgiSetArray("MEMBER_NAMES", element, attr->values[0].string.text); + element ++; + } + } + + num_printers = cgiGetSize("MEMBER_URIS"); + + ippDelete(response); + } + else + num_printers = 0; + + 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/classes/%s", name); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", + (int)(sizeof(pattrs) / sizeof(pattrs[0])), + NULL, pattrs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if ((attr = ippFindAttribute(response, "member-names", IPP_TAG_NAME)) != 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 (!strcasecmp(attr->values[i].string.text, + cgiGetArray("MEMBER_NAMES", j))) + { + cgiSetArray("MEMBER_SELECTED", j, "SELECTED"); + break; + } + } + } + } + + if ((attr = ippFindAttribute(response, "printer-info", + IPP_TAG_TEXT)) != NULL) + cgiSetVariable("PRINTER_INFO", attr->values[0].string.text); + + if ((attr = ippFindAttribute(response, "printer-location", + IPP_TAG_TEXT)) != NULL) + cgiSetVariable("PRINTER_LOCATION", attr->values[0].string.text); + + ippDelete(response); + } + + /* + * Update the location and description of an existing printer... + */ + + cgiStartHTML(title); + cgiCopyTemplateLang("modify-class.tmpl"); + } + else + { + /* + * Get the name, location, and description for a new printer... + */ + + cgiStartHTML(title); + cgiCopyTemplateLang("add-class.tmpl"); + } + + cgiEndHTML(); + + return; + } + + for (ptr = name; *ptr; ptr ++) + if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') + break; + + if (*ptr || ptr == name || strlen(name) > 127) + { + cgiSetVariable("ERROR", "The class name may only contain up to 127 printable " + "characters and may not contain spaces, slashes (/), " + "or the pound sign (#)."); + cgiStartHTML(title); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + /* + * 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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 = cupsLastError(); + + if (status > IPP_OK_CONFLICT) + { + cgiStartHTML(title); + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + /* + * Redirect successful updates back to the class page... + */ + + char refresh[1024]; /* Refresh URL */ + + cgiFormEncode(uri, name, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/classes/%s", + uri); + cgiSetVariable("refresh_page", refresh); + + cgiStartHTML(title); + + if (modify) + cgiCopyTemplateLang("class-modified.tmpl"); + else + cgiCopyTemplateLang("class-added.tmpl"); + } + + cgiEndHTML(); +} + + +/* + * '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 cgi_file_t *file; /* Uploaded file, if any */ + 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 */ + const char *name, /* Pointer to class name */ + *ptr; /* Pointer to CGI variable */ + const char *title; /* Title of page */ + static int baudrates[] = /* Baud rates */ + { + 1200, + 2400, + 4800, + 9600, + 19200, + 38400, + 57600, + 115200, + 230400, + 460800 + }; + + + title = modify ? "Modify Printer" : "Add Printer"; + + 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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) + { + cgiStartHTML(title); + + if (modify) + { + /* + * Update the location and description of an existing printer... + */ + + if (oldinfo) + cgiSetIPPVars(oldinfo, NULL, NULL, NULL, 0); + + cgiCopyTemplateLang("modify-printer.tmpl"); + } + else + { + /* + * Get the name, location, and description for a new printer... + */ + + cgiCopyTemplateLang("add-printer.tmpl"); + } + + cgiEndHTML(); + + if (oldinfo) + ippDelete(oldinfo); + + return; + } + + for (ptr = name; *ptr; ptr ++) + if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') + break; + + if (*ptr || ptr == name || strlen(name) > 127) + { + cgiSetVariable("ERROR", "The printer name may only contain up to 127 printable " + "characters and may not contain spaces, slashes (/), " + "or the pound sign (#)."); + cgiStartHTML(title); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + file = cgiGetFile(); + + if (file) + { + fprintf(stderr, "DEBUG: file->tempfile=%s\n", file->tempfile); + fprintf(stderr, "DEBUG: file->name=%s\n", file->name); + fprintf(stderr, "DEBUG: file->filename=%s\n", file->filename); + fprintf(stderr, "DEBUG: file->mimetype=%s\n", file->mimetype); + } + + 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) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + ippDelete(response); + } + + /* + * Let the user choose... + */ + + if ((attr = ippFindAttribute(oldinfo, "device-uri", IPP_TAG_URI)) != NULL) + { + strlcpy(uri, attr->values[0].string.text, sizeof(uri)); + if ((uriptr = strchr(uri, ':')) != NULL && strncmp(uriptr, "://", 3) == 0) + *uriptr = '\0'; + + cgiSetVariable("CURRENT_DEVICE_URI", attr->values[0].string.text); + cgiSetVariable("CURRENT_DEVICE_SCHEME", uri); + } + + cgiStartHTML(title); + cgiCopyTemplateLang("choose-device.tmpl"); + cgiEndHTML(); + } + else if (strchr(var, '/') == NULL) + { + if ((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... + */ + + cgiStartHTML(title); + cgiCopyTemplateLang("choose-uri.tmpl"); + cgiEndHTML(); + } + else if (!strncmp(var, "serial:", 7) && !cgiGetVariable("BAUDRATE")) + { + /* + * 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); + } + + cgiStartHTML(title); + cgiCopyTemplateLang("choose-serial.tmpl"); + cgiEndHTML(); + } + else if (!file && (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 */ + http_status_t get_status; /* Status of GET */ + + + snprintf(uri, sizeof(uri), "/printers/%s.ppd", name); + + if (httpGet(http, uri)) + httpGet(http, uri); + + while ((get_status = httpUpdate(http)) == HTTP_CONTINUE); + + if (get_status != HTTP_OK) + { + fprintf(stderr, "ERROR: Unable to get PPD file %s: %d - %s\n", + uri, get_status, httpStatus(get_status)); + } + else 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 + { + fprintf(stderr, "ERROR: Unable to open PPD file %s: %s\n", + filename, ppdErrorString(ppdLastError(&bytes))); + } + } + else + { + httpFlush(http); + + fprintf(stderr, + "ERROR: Unable to create temporary file for PPD file: %s\n", + strerror(errno)); + } + } + else if ((uriptr = strrchr(cgiGetVariable("DEVICE_URI"), '|')) != NULL) + { + /* + * Extract make and make/model from device URI string... + */ + + char make[1024], /* Make string */ + *makeptr; /* Pointer into make */ + + + *uriptr++ = '\0'; + + strlcpy(make, uriptr, sizeof(make)); + + if ((makeptr = strchr(make, ' ')) != NULL) + *makeptr = '\0'; + else if ((makeptr = strchr(make, '-')) != NULL) + *makeptr = '\0'; + else if (!strncasecmp(make, "laserjet", 8) || + !strncasecmp(make, "deskjet", 7) || + !strncasecmp(make, "designjet", 9)) + strcpy(make, "HP"); + else if (!strncasecmp(make, "phaser", 6)) + strcpy(make, "Xerox"); + else if (!strncasecmp(make, "stylus", 6)) + strcpy(make, "Epson"); + else + strcpy(make, "Generic"); + + cgiSetVariable("CURRENT_MAKE", make); + cgiSetVariable("PPD_MAKE", make); + cgiSetVariable("CURRENT_MAKE_AND_MODEL", uriptr); + } + + /* + * 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/"); + + + if ((var = cgiGetVariable("PPD_MAKE")) != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, + "ppd-make", NULL, var); + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "ppd-make"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + /* + * Got the list of PPDs, see if the user has selected a make... + */ + + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + if (var == 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; + } + + cgiStartHTML(title); + cgiCopyTemplateLang("choose-make.tmpl"); + cgiEndHTML(); + } + else + { + /* + * Let the user choose a model... + */ + + const char *make_model; /* Current make/model string */ + + + if ((make_model = cgiGetVariable("CURRENT_MAKE_AND_MODEL")) != NULL) + { + /* + * Scan for "close" matches... + */ + + int match, /* Current match */ + best_match, /* Best match so far */ + count; /* Number of drivers */ + const char *best, /* Best matching string */ + *current; /* Current string */ + + + count = cgiGetSize("PPD_MAKE_AND_MODEL"); + + for (i = 0, best_match = 0, best = NULL; i < count; i ++) + { + current = cgiGetArray("PPD_MAKE_AND_MODEL", i); + match = match_string(make_model, current); + + if (match > best_match) + { + best_match = match; + best = current; + } + } + + if (best_match > strlen(var)) + { + /* + * Found a match longer than the make... + */ + + cgiSetVariable("CURRENT_MAKE_AND_MODEL", best); + } + } + + cgiStartHTML(title); + cgiCopyTemplateLang("choose-model.tmpl"); + cgiEndHTML(); + } + + + ippDelete(response); + } + else + { + char message[1024]; + + + snprintf(message, sizeof(message), "Unable to get list of printer drivers: %s", + ippErrorString(cupsLastError())); + cgiSetVariable("ERROR", message); + cgiStartHTML(title); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + } + } + 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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")); + + if (!file) + ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, "ppd-name", + NULL, cgiGetVariable("PPD_NAME")); + + strlcpy(uri, cgiGetVariable("DEVICE_URI"), sizeof(uri)); + + /* + * Strip make and model from URI... + */ + + if ((uriptr = strrchr(uri, '|')) != NULL) + *uriptr = '\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 (file) + response = cupsDoFileRequest(http, request, "/admin/", file->tempfile); + else + response = cupsDoRequest(http, request, "/admin/"); + + if (response) + { + status = response->request.status.status_code; + ippDelete(response); + } + else + status = cupsLastError(); + + if (status > IPP_OK_CONFLICT) + { + cgiStartHTML(title); + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + /* + * Redirect successful updates back to the printer or set-options pages... + */ + + char refresh[1024]; /* Refresh URL */ + + + cgiFormEncode(uri, name, sizeof(uri)); + + if (modify) + snprintf(refresh, sizeof(refresh), + "5;/admin?OP=redirect&URL=/printers/%s", uri); + else + snprintf(refresh, sizeof(refresh), + "5;/admin?OP=set-printer-options&PRINTER_NAME=%s", uri); + + cgiSetVariable("refresh_page", refresh); + + cgiStartHTML(title); + + if (modify) + cgiCopyTemplateLang("printer-modified.tmpl"); + else + cgiCopyTemplateLang("printer-added.tmpl"); + } + + cgiEndHTML(); + } + + 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, m; /* 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 */ + cups_file_t *in, /* Input file */ + *out; /* Output file */ + 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 */ + ppd_attr_t *protocol; /* cupsProtocol attribute */ + + + /* + * Get the printer name... + */ + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiStartHTML("Set Printer Options"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + /* + * Get the PPD file... + */ + + if ((filename = cupsGetPPD(printer)) == NULL) + { + if (cupsLastError() == IPP_NOT_FOUND) + { + /* + * No PPD file for this printer, so we can't configure it! + */ + + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_POSSIBLE)); + cgiStartHTML("Set Printer Options"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + } + else + { + /* + * Unable to access the PPD file for some reason... + */ + + cgiSetVariable("ERROR", ippErrorString(cupsLastError())); + cgiStartHTML("Set Printer Options"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + } + return; + } + + if ((ppd = ppdOpenFile(filename)) == NULL) + { + cgiSetVariable("ERROR", ippErrorString(IPP_DEVICE_ERROR)); + cgiStartHTML("Set Printer Options"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + if (cgiGetVariable("job_sheets_start") != NULL || + cgiGetVariable("job_sheets_end") != NULL) + have_options = 1; + else + have_options = 0; + + ppdMarkDefaults(ppd); + + DEBUG_printf(("

ppd->num_groups = %d\n" + "

    \n", ppd->num_groups)); + + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + { + DEBUG_printf(("
  • %s
      \n", group->text)); + + for (j = group->num_options, option = group->options; j > 0; j --, option ++) + if ((var = cgiGetVariable(option->keyword)) != NULL) + { + DEBUG_printf(("
    • %s = \"%s\"
    • \n", option->keyword, var)); + have_options = 1; + ppdMarkOption(ppd, option->keyword, var); + } +#ifdef DEBUG + else + printf("
    • %s not defined!
    • \n", option->keyword); +#endif /* DEBUG */ + + DEBUG_puts("
  • "); + } + + DEBUG_printf(("
\n" + "

ppdConflicts(ppd) = %d\n", ppdConflicts(ppd))); + + if (!have_options || ppdConflicts(ppd)) + { + /* + * Show the options to the user... + */ + + cgiStartHTML("Set Printer Options"); + cgiCopyTemplateLang("set-printer-options-header.tmpl"); + + if (ppdConflicts(ppd)) + { + for (i = ppd->num_groups, k = 0, group = ppd->groups; i > 0; i --, group ++) + for (j = group->num_options, option = group->options; j > 0; j --, option ++) + if (option->conflicted) + { + cgiSetArray("ckeyword", k, option->keyword); + cgiSetArray("ckeytext", k, option->text); + k ++; + } + + cgiCopyTemplateLang("option-conflict.tmpl"); + } + + for (i = ppd->num_groups, group = ppd->groups; + i > 0; + i --, group ++) + { + if (!strcmp(group->name, "InstallableOptions")) + cgiSetVariable("GROUP", + _cupsLangString(language, _("Options Installed"))); + else + cgiSetVariable("GROUP", group->text); + + cgiCopyTemplateLang("option-header.tmpl"); + + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + { + if (!strcmp(option->keyword, "PageRegion")) + continue; + + cgiSetVariable("KEYWORD", option->keyword); + cgiSetVariable("KEYTEXT", option->text); + + if (option->conflicted) + cgiSetVariable("CONFLICTED", "1"); + else + cgiSetVariable("CONFLICTED", "0"); + + cgiSetSize("CHOICES", 0); + cgiSetSize("TEXT", 0); + for (k = 0, m = 0; k < option->num_choices; k ++) + { + /* + * Hide custom option values... + */ + + if (!strcmp(option->choices[k].choice, "Custom")) + continue; + + cgiSetArray("CHOICES", m, option->choices[k].choice); + cgiSetArray("TEXT", m, option->choices[k].text); + + m ++; + + if (option->choices[k].marked) + cgiSetVariable("DEFCHOICE", option->choices[k].choice); + } + + switch (option->ui) + { + case PPD_UI_BOOLEAN : + cgiCopyTemplateLang("option-boolean.tmpl"); + break; + case PPD_UI_PICKONE : + cgiCopyTemplateLang("option-pickone.tmpl"); + break; + case PPD_UI_PICKMANY : + cgiCopyTemplateLang("option-pickmany.tmpl"); + break; + } + } + + cgiCopyTemplateLang("option-trailer.tmpl"); + } + + /* + * 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", 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) + { + if ((attr = ippFindAttribute(response, "job-sheets-supported", IPP_TAG_ZERO)) != NULL) + { + /* + * Add the job sheets options... + */ + + cgiSetVariable("GROUP", "Banners"); + cgiCopyTemplateLang("option-header.tmpl"); + + 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("option-pickone.tmpl"); + + cgiSetVariable("KEYWORD", "job_sheets_end"); + cgiSetVariable("KEYTEXT", "Ending Banner"); + cgiSetVariable("DEFCHOICE", attr == NULL && attr->num_values > 1 ? + "" : attr->values[1].string.text); + + cgiCopyTemplateLang("option-pickone.tmpl"); + + cgiCopyTemplateLang("option-trailer.tmpl"); + } + + if (ippFindAttribute(response, "printer-error-policy-supported", + IPP_TAG_ZERO) || + ippFindAttribute(response, "printer-op-policy-supported", + IPP_TAG_ZERO)) + { + /* + * Add the error and operation policy options... + */ + + cgiSetVariable("GROUP", "Policies"); + cgiCopyTemplateLang("option-header.tmpl"); + + /* + * Error policy... + */ + + attr = ippFindAttribute(response, "printer-error-policy-supported", + IPP_TAG_ZERO); + + if (attr) + { + 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, "printer-error-policy", + IPP_TAG_ZERO); + + cgiSetVariable("KEYWORD", "printer_error_policy"); + cgiSetVariable("KEYTEXT", "Error Policy"); + cgiSetVariable("DEFCHOICE", attr == NULL ? + "" : attr->values[0].string.text); + } + + cgiCopyTemplateLang("option-pickone.tmpl"); + + /* + * Operation policy... + */ + + attr = ippFindAttribute(response, "printer-op-policy-supported", + IPP_TAG_ZERO); + + if (attr) + { + 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, "printer-op-policy", IPP_TAG_ZERO); + + cgiSetVariable("KEYWORD", "printer_op_policy"); + cgiSetVariable("KEYTEXT", "Operation Policy"); + cgiSetVariable("DEFCHOICE", attr == NULL ? + "" : attr->values[0].string.text); + + cgiCopyTemplateLang("option-pickone.tmpl"); + } + + cgiCopyTemplateLang("option-trailer.tmpl"); + } + + ippDelete(response); + } + + /* + * Binary protocol support... + */ + + if (ppd->protocols && strstr(ppd->protocols, "BCP")) + { + protocol = ppdFindAttr(ppd, "cupsProtocol", NULL); + + cgiSetVariable("GROUP", "PS Binary Protocol"); + cgiCopyTemplateLang("option-header.tmpl"); + + cgiSetSize("CHOICES", 2); + cgiSetSize("TEXT", 2); + cgiSetArray("CHOICES", 0, "None"); + cgiSetArray("TEXT", 0, "None"); + + if (strstr(ppd->protocols, "TBCP")) + { + cgiSetArray("CHOICES", 1, "TBCP"); + cgiSetArray("TEXT", 1, "TBCP"); + } + else + { + cgiSetArray("CHOICES", 1, "BCP"); + cgiSetArray("TEXT", 1, "BCP"); + } + + cgiSetVariable("KEYWORD", "protocol"); + cgiSetVariable("KEYTEXT", "PS Binary Protocol"); + cgiSetVariable("DEFCHOICE", protocol ? protocol->value : "None"); + + cgiCopyTemplateLang("option-pickone.tmpl"); + + cgiCopyTemplateLang("option-trailer.tmpl"); + } + + cgiCopyTemplateLang("set-printer-options-trailer.tmpl"); + cgiEndHTML(); + } + else + { + /* + * Set default options... + */ + + out = cupsTempFile2(tempfile, sizeof(tempfile)); + in = cupsFileOpen(filename, "r"); + + if (!in || !out) + { + cgiSetVariable("ERROR", strerror(errno)); + cgiStartHTML("Set Printer Options"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + if (in) + cupsFileClose(in); + + if (out) + { + cupsFileClose(out); + unlink(tempfile); + } + + unlink(filename); + return; + } + + while (cupsFileGets(in, line, sizeof(line))) + { + if (!strncmp(line, "*cupsProtocol:", 14) && cgiGetVariable("protocol")) + continue; + else if (strncmp(line, "*Default", 8)) + cupsFilePrintf(out, "%s\n", line); + else + { + /* + * Get default option name... + */ + + strlcpy(keyword, line + 8, sizeof(keyword)); + + for (keyptr = keyword; *keyptr; keyptr ++) + if (*keyptr == ':' || isspace(*keyptr & 255)) + break; + + *keyptr = '\0'; + + if (!strcmp(keyword, "PageRegion")) + var = cgiGetVariable("PageSize"); + else + var = cgiGetVariable(keyword); + + if (var != NULL) + cupsFilePrintf(out, "*Default%s: %s\n", keyword, var); + else + cupsFilePrintf(out, "%s\n", line); + } + } + + if ((var = cgiGetVariable("protocol")) != NULL) + cupsFilePrintf(out, "*cupsProtocol: %s\n", cgiGetVariable("protocol")); + + cupsFileClose(in); + cupsFileClose(out); + + /* + * 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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")); + + if ((var = cgiGetVariable("printer_error_policy")) != NULL) + attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-error-policy", NULL, var); + + if ((var = cgiGetVariable("printer_op_policy")) != NULL) + attr = ippAddString(request, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-op-policy", NULL, var); + + /* + * 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 = cupsLastError(); + + if (status > IPP_OK_CONFLICT) + { + cgiStartHTML("Set Printer Options"); + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + /* + * Redirect successful updates back to the printer page... + */ + + char refresh[1024]; /* Refresh URL */ + + cgiFormEncode(uri, printer, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s", + uri); + cgiSetVariable("refresh_page", refresh); + + cgiStartHTML("Set Printer Options"); + + cgiCopyTemplateLang("printer-configured.tmpl"); + } + + cgiEndHTML(); + + unlink(tempfile); + } + + unlink(filename); +} + + +/* + * 'do_config_server()' - Configure server settings. + */ + +static void +do_config_server(http_t *http, /* I - HTTP connection */ + cups_lang_t *language) /* I - Client's language */ +{ + if (cgiIsPOST() && !cgiGetVariable("CUPSDCONF")) + { + /* + * Save basic setting changes... + */ + + http_status_t status; /* PUT status */ + cups_file_t *cupsd; /* cupsd.conf file */ + char tempfile[1024]; /* Temporary new cupsd.conf */ + int tempfd; /* Temporary file descriptor */ + cups_file_t *temp; /* Temporary file */ + char line[1024], /* Line from cupsd.conf file */ + *value; /* Value on line */ + const char *server_root; /* Location of config files */ + int linenum, /* Line number in file */ + in_policy, /* In a policy section? */ + in_cancel_job, /* In a cancel-job section? */ + in_admin_location, /* In the /admin location? */ + in_conf_location, /* In the /admin/conf location? */ + in_root_location; /* In the / location? */ + int remote_printers, /* Show remote printers */ + share_printers, /* Share local printers */ + remote_admin, /* Remote administration allowed? */ + user_cancel_any, /* Cancel-job policy set? */ + debug_logging; /* LogLevel debug set? */ + int wrote_port_listen, /* Wrote the port/listen lines? */ + wrote_browsing, /* Wrote the browsing lines? */ + wrote_policy, /* Wrote the policy? */ + wrote_loglevel, /* Wrote the LogLevel line? */ + wrote_admin_location, /* Wrote the /admin location? */ + wrote_conf_location, /* Wrote the /admin/conf location? */ + wrote_root_location; /* Wrote the / location? */ + int indent; /* Indentation */ + + + /* + * Get form variables... + */ + + remote_printers = cgiGetVariable("REMOTE_PRINTERS") != NULL; + share_printers = cgiGetVariable("SHARE_PRINTERS") != NULL; + remote_admin = cgiGetVariable("REMOTE_ADMIN") != NULL; + user_cancel_any = cgiGetVariable("USER_CANCEL_ANY") != NULL; + debug_logging = cgiGetVariable("DEBUG_LOGGING") != NULL; + + /* + * Locate the cupsd.conf file... + */ + + if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) + server_root = CUPS_SERVERROOT; + + snprintf(line, sizeof(line), "%s/cupsd.conf", server_root); + + /* + * Open the cupsd.conf file... + */ + + if ((cupsd = cupsFileOpen(line, "r")) == NULL) + { + /* + * Unable to open - log an error... + */ + + cgiStartHTML("Change Settings"); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(line); + return; + } + + /* + * Create a temporary file for the new cupsd.conf file... + */ + + if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) + { + cgiStartHTML("Change Settings"); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(tempfile); + cupsFileClose(cupsd); + return; + } + + if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL) + { + cgiStartHTML("Change Settings"); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(tempfile); + close(tempfd); + unlink(tempfile); + cupsFileClose(cupsd); + return; + } + + /* + * Copy the old file to the new, making changes along the way... + */ + + in_admin_location = 0; + in_cancel_job = 0; + in_conf_location = 0; + in_policy = 0; + in_root_location = 0; + linenum = 0; + wrote_admin_location = 0; + wrote_browsing = 0; + wrote_conf_location = 0; + wrote_loglevel = 0; + wrote_policy = 0; + wrote_port_listen = 0; + wrote_root_location = 0; + indent = 0; + + while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) + { + if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen")) + { + if (!wrote_port_listen) + { + wrote_port_listen = 1; + + if (share_printers || remote_admin) + { + cupsFilePuts(temp, "# Allow remote access\n"); + cupsFilePrintf(temp, "Listen *:%d\n", ippPort()); + } + else + { + cupsFilePuts(temp, "# Only listen for connections from the local machine.\n"); + cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort()); + } + +#ifdef CUPS_DEFAULT_DOMAINSOCKET + cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); +#endif /* CUPS_DEFAULT_DOMAINSOCKET */ + } + } + else if (!strcasecmp(line, "Browsing") || + !strcasecmp(line, "BrowseAddress") || + !strcasecmp(line, "BrowseAllow") || + !strcasecmp(line, "BrowseDeny") || + !strcasecmp(line, "BrowseOrder")) + { + if (!wrote_browsing) + { + wrote_browsing = 1; + + if (remote_printers || share_printers) + { + if (remote_printers && share_printers) + cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n"); + else if (remote_printers) + cupsFilePuts(temp, "# Show shared printers on the local network.\n"); + else + cupsFilePuts(temp, "# Share local printers on the local network.\n"); + + cupsFilePuts(temp, "Browsing On\n"); + cupsFilePuts(temp, "BrowseOrder allow,deny\n"); + + if (remote_printers) + cupsFilePuts(temp, "BrowseAllow @LOCAL\n"); + + if (share_printers) + cupsFilePuts(temp, "BrowseAddress @LOCAL\n"); + } + else + { + cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n"); + cupsFilePuts(temp, "Browsing Off\n"); + } + } + } + else if (!strcasecmp(line, "LogLevel")) + { + wrote_loglevel = 1; + + if (debug_logging) + { + cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); + cupsFilePuts(temp, "LogLevel debug\n"); + } + else + { + cupsFilePuts(temp, "# Show general information in error_log.\n"); + cupsFilePuts(temp, "LogLevel info\n"); + } + } + else if (!strcasecmp(line, "\n", line, value); + indent += 2; + } + else if (!strcasecmp(line, "")) + { + indent -= 2; + if (!wrote_policy) + { + wrote_policy = 1; + + if (!user_cancel_any) + cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n" + " \n" + " Order deny,allow\n" + " Allow @SYSTEM\n" + " Allow @OWNER\n" + " \n"); + } + + in_policy = 0; + + cupsFilePuts(temp, "\n"); + } + else if (!strcasecmp(line, "\n", line, value); + } + else if (!strcasecmp(line, "")) + { + indent -= 2; + if (in_admin_location) + { + wrote_admin_location = 1; + + if (remote_admin) + cupsFilePuts(temp, " # Allow remote administration...\n"); + else + cupsFilePuts(temp, " # Restrict access to the admin pages...\n"); + + cupsFilePuts(temp, " Order allow,deny\n"); + + if (remote_admin) + cupsFilePuts(temp, " Allow @LOCAL\n"); + else + cupsFilePuts(temp, " Allow localhost\n"); + } + else if (in_conf_location) + { + wrote_conf_location = 1; + + if (remote_admin) + cupsFilePuts(temp, " # Allow remote access to the configuration files...\n"); + else + cupsFilePuts(temp, " # Restrict access to the configuration files...\n"); + + cupsFilePuts(temp, " Order allow,deny\n"); + + if (remote_admin) + cupsFilePuts(temp, " Allow @LOCAL\n"); + else + cupsFilePuts(temp, " Allow localhost\n"); + } + else if (in_root_location) + { + wrote_root_location = 1; + + if (remote_admin && share_printers) + cupsFilePuts(temp, " # Allow shared printing and remote administration...\n"); + else if (remote_admin) + cupsFilePuts(temp, " # Allow remote administration...\n"); + else if (share_printers) + cupsFilePuts(temp, " # Allow shared printing...\n"); + else + cupsFilePuts(temp, " # Restrict access to the server...\n"); + + cupsFilePuts(temp, " Order allow,deny\n"); + + if (remote_admin || share_printers) + cupsFilePuts(temp, " Allow @LOCAL\n"); + else + cupsFilePuts(temp, " Allow localhost\n"); + } + + in_admin_location = 0; + in_conf_location = 0; + in_root_location = 0; + + cupsFilePuts(temp, "\n"); + } + else if (!strcasecmp(line, "\n"); + } + } + else if (!strcasecmp(line, "") && in_cancel_job) + { + indent -= 2; + + if (in_cancel_job == 1) + cupsFilePuts(temp, " \n"); + + wrote_policy = 1; + + if (!user_cancel_any) + cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n" + " \n" + " Order deny,allow\n" + " Require user @OWNER @SYSTEM\n" + " \n"); + + in_cancel_job = 0; + } + else if ((in_admin_location || in_conf_location || in_root_location) && + (!strcasecmp(line, "Allow") || !strcasecmp(line, "Deny") || + !strcasecmp(line, "Order"))) + continue; + else if (in_cancel_job == 2) + continue; + else if (!strcasecmp(line, "\n", line, value); + else if (line[0] == '<') + { + if (value) + { + cupsFilePrintf(temp, "%*s%s %s>\n", indent, "", line, value); + indent += 2; + } + else + { + if (line[1] == '/') + indent -= 2; + + cupsFilePrintf(temp, "%*s%s\n", indent, "", line); + } + } + else if (value) + cupsFilePrintf(temp, "%*s%s %s\n", indent, "", line, value); + else + cupsFilePrintf(temp, "%*s%s\n", indent, "", line); + } + + /* + * Write any missing info... + */ + + if (!wrote_browsing) + { + if (remote_printers || share_printers) + { + if (remote_printers && share_printers) + cupsFilePuts(temp, "# Enable printer sharing and shared printers.\n"); + else if (remote_printers) + cupsFilePuts(temp, "# Show shared printers on the local network.\n"); + else + cupsFilePuts(temp, "# Share local printers on the local network.\n"); + + cupsFilePuts(temp, "Browsing On\n"); + cupsFilePuts(temp, "BrowseOrder allow,deny\n"); + + if (remote_printers) + cupsFilePuts(temp, "BrowseAllow @LOCAL\n"); + + if (share_printers) + cupsFilePuts(temp, "BrowseAddress @LOCAL\n"); + } + else + { + cupsFilePuts(temp, "# Disable printer sharing and shared printers.\n"); + cupsFilePuts(temp, "Browsing Off\n"); + } + } + + if (!wrote_loglevel) + { + if (debug_logging) + { + cupsFilePuts(temp, "# Show troubleshooting information in error_log.\n"); + cupsFilePuts(temp, "LogLevel debug\n"); + } + else + { + cupsFilePuts(temp, "# Show general information in error_log.\n"); + cupsFilePuts(temp, "LogLevel info\n"); + } + } + + if (!wrote_port_listen) + { + if (share_printers || remote_admin) + { + cupsFilePuts(temp, "# Allow remote access\n"); + cupsFilePrintf(temp, "Listen *:%d\n", ippPort()); + } + else + { + cupsFilePuts(temp, "# Only listen for connections from the local machine.\n"); + cupsFilePrintf(temp, "Listen localhost:%d\n", ippPort()); + } + +#ifdef CUPS_DEFAULT_DOMAINSOCKET + cupsFilePuts(temp, "Listen " CUPS_DEFAULT_DOMAINSOCKET "\n"); +#endif /* CUPS_DEFAULT_DOMAINSOCKET */ + } + + if (!wrote_root_location) + { + if (remote_admin && share_printers) + cupsFilePuts(temp, "# Allow shared printing and remote administration...\n"); + else if (remote_admin) + cupsFilePuts(temp, "# Allow remote administration...\n"); + else if (share_printers) + cupsFilePuts(temp, "# Allow shared printing...\n"); + else + cupsFilePuts(temp, "# Restrict access to the server...\n"); + + cupsFilePuts(temp, "\n" + " Order allow,deny\n"); + + if (remote_admin || share_printers) + cupsFilePuts(temp, " Allow @LOCAL\n"); + else + cupsFilePuts(temp, " Allow localhost\n"); + + cupsFilePuts(temp, "\n"); + } + + if (!wrote_admin_location) + { + if (remote_admin) + cupsFilePuts(temp, "# Allow remote administration...\n"); + else + cupsFilePuts(temp, "# Restrict access to the admin pages...\n"); + + cupsFilePuts(temp, "\n" + " Order allow,deny\n"); + + if (remote_admin) + cupsFilePuts(temp, " Allow @LOCAL\n"); + else + cupsFilePuts(temp, " Allow localhost\n"); + + cupsFilePuts(temp, "\n"); + } + + if (!wrote_conf_location) + { + if (remote_admin) + cupsFilePuts(temp, "# Allow remote access to the configuration files...\n"); + else + cupsFilePuts(temp, "# Restrict access to the configuration files...\n"); + + cupsFilePuts(temp, "\n" + " AuthType Basic\n" + " Require user @SYSTEM\n" + " Order allow,deny\n"); + + if (remote_admin) + cupsFilePuts(temp, " Allow @LOCAL\n"); + else + cupsFilePuts(temp, " Allow localhost\n"); + + cupsFilePuts(temp, "\n"); + } + + if (!wrote_policy) + { + cupsFilePuts(temp, "\n" + " # Job-related operations must be done by the owner or an adminstrator...\n" + " \n" + " Require user @OWNER @SYSTEM\n" + " Order deny,allow\n" + " \n" + " # All administration operations require an adminstrator to authenticate...\n" + " \n" + " AuthType Basic\n" + " Require user @SYSTEM\n" + " Order deny,allow\n" + "\n"); + + if (!user_cancel_any) + cupsFilePuts(temp, " # Only the owner or an administrator can cancel a job...\n" + " \n" + " Require user @OWNER @SYSTEM\n" + " Order deny,allow\n" + " \n"); + + cupsFilePuts(temp, " \n" + " Order deny,allow\n" + " \n" + "\n"); + } + + cupsFileClose(cupsd); + cupsFileClose(temp); + + /* + * Upload the configuration file to the server... + */ + + status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); + + if (status != HTTP_CREATED) + { + cgiSetVariable("ERROR", httpStatus(status)); + cgiStartHTML("Change Settings"); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + cgiSetVariable("refresh_page", "5;/admin?OP=redirect"); + + cgiStartHTML("Change Settings"); + cgiCopyTemplateLang("restart.tmpl"); + } + + cgiEndHTML(); + + unlink(tempfile); + } + else if (cgiIsPOST()) + { + /* + * Save hand-edited config file... + */ + + http_status_t status; /* PUT status */ + char tempfile[1024]; /* Temporary new cupsd.conf */ + int tempfd; /* Temporary file descriptor */ + cups_file_t *temp; /* Temporary file */ + const char *start, /* Start of line */ + *end; /* End of line */ + + + /* + * Create a temporary file for the new cupsd.conf file... + */ + + if ((tempfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) + { + cgiStartHTML("Edit Configuration File"); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(tempfile); + return; + } + + if ((temp = cupsFileOpenFd(tempfd, "w")) == NULL) + { + cgiStartHTML("Edit Configuration File"); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(tempfile); + close(tempfd); + unlink(tempfile); + return; + } + + /* + * Copy the cupsd.conf text from the form variable... + */ + + start = cgiGetVariable("CUPSDCONF"); + while (start) + { + if ((end = strstr(start, "\r\n")) == NULL) + if ((end = strstr(start, "\n")) == NULL) + end = start + strlen(start); + + cupsFileWrite(temp, start, end - start); + cupsFilePutChar(temp, '\n'); + + if (*end == '\r') + start = end + 2; + else if (*end == '\n') + start = end + 1; + else + start = NULL; + } + + cupsFileClose(temp); + + /* + * Upload the configuration file to the server... + */ + + status = cupsPutFile(http, "/admin/conf/cupsd.conf", tempfile); + + if (status != HTTP_CREATED) + { + cgiSetVariable("ERROR", httpStatus(status)); + cgiStartHTML("Edit Configuration File"); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + cgiSetVariable("refresh_page", "5;/admin?OP=redirect"); + + cgiStartHTML("Edit Configuration File"); + cgiCopyTemplateLang("restart.tmpl"); + } + + cgiEndHTML(); + + unlink(tempfile); + } + else + { + struct stat info; /* cupsd.conf information */ + cups_file_t *cupsd; /* cupsd.conf file */ + char *buffer; /* Buffer for entire file */ + char filename[1024]; /* Filename */ + const char *server_root; /* Location of config files */ + + + /* + * Locate the cupsd.conf file... + */ + + if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) + server_root = CUPS_SERVERROOT; + + snprintf(filename, sizeof(filename), "%s/cupsd.conf", server_root); + + /* + * Figure out the size... + */ + + if (stat(filename, &info)) + { + cgiStartHTML("Edit Configuration File"); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(filename); + return; + } + + if (info.st_size > (1024 * 1024)) + { + cgiStartHTML("Edit Configuration File"); + cgiSetVariable("ERROR", "Unable to edit cupsd.conf files larger than 1MB!"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + fprintf(stderr, "ERROR: \"%s\" too large (%ld) to edit!\n", filename, + (long)info.st_size); + return; + } + + /* + * Open the cupsd.conf file... + */ + + if ((cupsd = cupsFileOpen(filename, "r")) == NULL) + { + /* + * Unable to open - log an error... + */ + + cgiStartHTML("Edit Configuration File"); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(filename); + return; + } + + /* + * Allocate memory and load the file into a string buffer... + */ + + buffer = calloc(1, info.st_size + 1); + + cupsFileRead(cupsd, buffer, info.st_size); + cupsFileClose(cupsd); + + cgiSetVariable("CUPSDCONF", buffer); + free(buffer); + + /* + * Show the current config file... + */ + + cgiStartHTML("Edit Configuration File"); + + printf("\n", filename); + + cgiCopyTemplateLang("edit-config.tmpl"); + + cgiEndHTML(); + } +} + + +/* + * '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) + { + cgiStartHTML("Delete Class"); + cgiCopyTemplateLang("class-confirm.tmpl"); + cgiEndHTML(); + return; + } + + if ((pclass = cgiGetVariable("PRINTER_NAME")) != NULL) + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/classes/%s", pclass); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiStartHTML("Delete Class"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + 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 = cupsLastError(); + + cgiStartHTML("Delete Class"); + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + cgiCopyTemplateLang("class-deleted.tmpl"); + + cgiEndHTML(); +} + + +/* + * '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) + { + cgiStartHTML("Delete Printer"); + cgiCopyTemplateLang("printer-confirm.tmpl"); + cgiEndHTML(); + return; + } + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiStartHTML("Delete Printer"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + 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 = cupsLastError(); + + cgiStartHTML("Delete Printer"); + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + cgiCopyTemplateLang("printer-deleted.tmpl"); + + cgiEndHTML(); +} + + +/* + * 'do_menu()' - Show the main menu... + */ + +static void +do_menu(http_t *http, /* I - HTTP connection */ + cups_lang_t *language) /* I - Client's language */ +{ + cups_file_t *cupsd; /* cupsd.conf file */ + char line[1024], /* Line from cupsd.conf file */ + *value; /* Value on line */ + const char *server_root; /* Location of config files */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* IPP attribute */ + + + /* + * Locate the cupsd.conf file... + */ + + if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) + server_root = CUPS_SERVERROOT; + + snprintf(line, sizeof(line), "%s/cupsd.conf", server_root); + + cgiStartHTML("Administration"); + + printf("\n", line); + + /* + * Open the cupsd.conf file... + */ + + if ((cupsd = cupsFileOpen(line, "r")) == NULL) + { + /* + * Unable to open - log an error... + */ + + cgiStartHTML("Administration"); + cgiSetVariable("ERROR", strerror(errno)); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + perror(line); + } + else + { + /* + * Read the file, keeping track of what settings are enabled... + */ + + int remote_access = 0, /* Remote access allowed? */ + remote_admin = 0, /* Remote administration allowed? */ + browsing = 1, /* Browsing enabled? */ + browse_allow = 1, /* Browse address set? */ + browse_address = 0, /* Browse address set? */ + cancel_policy = 1, /* Cancel-job policy set? */ + debug_logging = 0; /* LogLevel debug set? */ + int linenum = 0, /* Line number in file */ + in_policy = 0, /* In a policy section? */ + in_cancel_job = 0, /* In a cancel-job section? */ + in_admin_location = 0; /* In the /admin location? */ + + + while (cupsFileGetConf(cupsd, line, sizeof(line), &value, &linenum)) + { + if (!strcasecmp(line, "Port")) + { + remote_access = 1; + } + else if (!strcasecmp(line, "Listen")) + { + char *port; /* Pointer to port number, if any */ + + + if ((port = strrchr(value, ':')) != NULL) + *port = '\0'; + + if (strcasecmp(value, "localhost") && strcmp(value, "127.0.0.1")) + remote_access = 1; + } + else if (!strcasecmp(line, "Browsing")) + { + browsing = !strcasecmp(value, "yes") || !strcasecmp(value, "on") || + !strcasecmp(value, "true"); + } + else if (!strcasecmp(line, "BrowseAddress")) + { + browse_address = 1; + } + else if (!strcasecmp(line, "BrowseAllow")) + { + browse_allow = 1; + } + else if (!strcasecmp(line, "BrowseOrder")) + { + browse_allow = !strncasecmp(value, "deny,", 5); + } + else if (!strcasecmp(line, "LogLevel")) + { + debug_logging = !strncasecmp(value, "debug", 5); + } + else if (!strcasecmp(line, "")) + { + in_policy = 0; + } + else if (!strcasecmp(line, "")) + { + in_cancel_job = 0; + } + else if (!strcasecmp(line, "Require") && in_cancel_job) + { + cancel_policy = 0; + } + else if (!strcasecmp(line, "")) + { + in_admin_location = 0; + } + else if (!strcasecmp(line, "Allow") && in_admin_location && + strcasecmp(value, "localhost") && strcasecmp(value, "127.0.0.1")) + { + remote_admin = 1; + } + } + + cupsFileClose(cupsd); + + if (browsing && browse_allow) + cgiSetVariable("REMOTE_PRINTERS", "CHECKED"); + + if (remote_access && browsing && browse_address) + cgiSetVariable("SHARE_PRINTERS", "CHECKED"); + + if (remote_access && remote_admin) + cgiSetVariable("REMOTE_ADMIN", "CHECKED"); + + if (cancel_policy) + cgiSetVariable("USER_CANCEL_ANY", "CHECKED"); + + if (debug_logging) + cgiSetVariable("DEBUG_LOGGING", "CHECKED"); + } + + /* + * Get the list of printers and their devices... + */ + + 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_KEYWORD, + "requested-attributes", NULL, "device-uri"); + + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type", + CUPS_PRINTER_LOCAL); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, "printer-type-mask", + CUPS_PRINTER_LOCAL); + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + /* + * Got the printer list, now load the devices... + */ + + int i; /* Looping var */ + int num_printer_devices; /* Number of devices for local printers */ + char **printer_devices; /* Printer devices for local printers */ + + + /* + * Count the number of printers we have... + */ + + for (num_printer_devices = 0, + attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI); + attr; + num_printer_devices ++, + attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI)); + + if (num_printer_devices > 0) + { + /* + * Allocate an array and copy the device strings... + */ + + printer_devices = calloc(num_printer_devices, sizeof(char *)); + + for (i = 0, attr = ippFindAttribute(response, "device-uri", IPP_TAG_URI); + attr; + i ++, attr = ippFindNextAttribute(response, "device-uri", IPP_TAG_URI)) + { + printer_devices[i] = strdup(attr->values[0].string.text); + } + + /* + * Sort the printer devices as needed... + */ + + if (num_printer_devices > 1) + qsort(printer_devices, num_printer_devices, sizeof(char *), + compare_printer_devices); + } + else + printer_devices = NULL; + + /* + * Free the printer list and get the device list... + */ + + ippDelete(response); + + 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); + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + /* + * Got the device list, let's parse it... + */ + + const char *device_uri, /* device-uri attribute value */ + *device_make_and_model, /* device-make-and-model value */ + *device_info; /* device-info value */ + + + for (i = 0, attr = response->attrs; attr; attr = attr->next) + { + /* + * Skip leading attributes until we hit a device... + */ + + while (attr && attr->group_tag != IPP_TAG_PRINTER) + attr = attr->next; + + if (!attr) + break; + + /* + * Pull the needed attributes from this device... + */ + + device_info = NULL; + device_make_and_model = NULL; + device_uri = NULL; + + while (attr && attr->group_tag == IPP_TAG_PRINTER) + { + 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_and_model = 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_info && device_make_and_model && device_uri && + strcasecmp(device_make_and_model, "unknown") && + strchr(device_uri, ':')) + { + /* + * Yes, now see if there is already a printer for this + * device... + */ + + if (!bsearch(&device_uri, printer_devices, num_printer_devices, + sizeof(char *), compare_printer_devices)) + { + /* + * Not found, so it must be a new printer... + */ + + char options[1024], /* Form variables for this device */ + *options_ptr; /* Pointer into string */ + const char *ptr; /* Pointer into device string */ + + + /* + * Format the printer name variable for this device... + * + * We use the device-info string first, then device-uri, + * and finally device-make-and-model to come up with a + * suitable name. + */ + + strcpy(options, "PRINTER_NAME="); + options_ptr = options + strlen(options); + + if (strncasecmp(device_info, "unknown", 7)) + ptr = device_info; + else if ((ptr = strstr(device_uri, "://")) != NULL) + ptr += 3; + else + ptr = device_make_and_model; + + for (; + options_ptr < (options + sizeof(options) - 1) && *ptr; + ptr ++) + if (isalnum(*ptr & 255) || *ptr == '_' || *ptr == '-' || *ptr == '.') + *options_ptr++ = *ptr; + else if ((*ptr == ' ' || *ptr == '/') && options_ptr[-1] != '_') + *options_ptr++ = '_'; + else if (*ptr == '?' || *ptr == '(') + break; + + /* + * Then add the make and model in the printer info, so + * that MacOS clients see something reasonable... + */ + + strlcpy(options_ptr, "&PRINTER_LOCATION=Local+Printer" + "&PRINTER_INFO=", + sizeof(options) - (options_ptr - options)); + options_ptr += strlen(options_ptr); + + cgiFormEncode(options_ptr, device_make_and_model, + sizeof(options) - (options_ptr - options)); + options_ptr += strlen(options_ptr); + + /* + * Then copy the device URI... + */ + + strlcpy(options_ptr, "&DEVICE_URI=", + sizeof(options) - (options_ptr - options)); + options_ptr += strlen(options_ptr); + + cgiFormEncode(options_ptr, device_uri, + sizeof(options) - (options_ptr - options)); + options_ptr += strlen(options_ptr); + + if (options_ptr < (options + sizeof(options) - 1)) + { + *options_ptr++ = '|'; + cgiFormEncode(options_ptr, device_make_and_model, + sizeof(options) - (options_ptr - options)); + } + + /* + * Finally, set the form variables for this printer... + */ + + cgiSetArray("device_info", i, device_info); + cgiSetArray("device_make_and_model", i, device_make_and_model); + cgiSetArray("device_options", i, options); + cgiSetArray("device_uri", i, device_uri); + i ++; + } + } + + if (!attr) + break; + } + + /* + * Free the device list... + */ + + ippDelete(response); + + if (num_printer_devices) + free(printer_devices); + } + } + + /* + * Finally, show the main menu template... + */ + + cgiCopyTemplateLang("admin.tmpl"); + + cgiEndHTML(); +} + + +/* + * '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 */ + const char *title) /* I - Title of page */ +{ + 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) + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiStartHTML(title); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + 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 = cupsLastError(); + + if (status > IPP_OK_CONFLICT) + { + cgiStartHTML(title); + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + /* + * Redirect successful updates back to the printer page... + */ + + char refresh[1024]; /* Refresh URL */ + + cgiFormEncode(uri, printer, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s", + uri); + cgiSetVariable("refresh_page", refresh); + + cgiStartHTML(title); + + if (op == IPP_PAUSE_PRINTER) + cgiCopyTemplateLang("printer-stop.tmpl"); + else if (op == IPP_RESUME_PRINTER) + cgiCopyTemplateLang("printer-start.tmpl"); + else if (op == CUPS_ACCEPT_JOBS) + cgiCopyTemplateLang("printer-accept.tmpl"); + else if (op == CUPS_REJECT_JOBS) + cgiCopyTemplateLang("printer-reject.tmpl"); + else if (op == IPP_PURGE_JOBS) + cgiCopyTemplateLang("printer-purge.tmpl"); + else if (op == CUPS_SET_DEFAULT) + cgiCopyTemplateLang("printer-default.tmpl"); + } + + cgiEndHTML(); +} + + +/* + * 'do_set_allowed_users()' - Set the allowed/denied users for a queue. + */ + +static void +do_set_allowed_users( + http_t *http, /* I - HTTP connection */ + cups_lang_t *language) /* I - Language */ +{ + int i; /* Looping var */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Printer URI */ + const char *printer, /* Printer name (purge-jobs) */ + *users, /* List of users or groups */ + *type; /* Allow/deny type */ + int num_users; /* Number of users */ + char *ptr, /* Pointer into users string */ + *end, /* Pointer to end of users string */ + quote; /* Quote character */ + ipp_attribute_t *attr; /* Attribute */ + ipp_status_t status; /* Operation status... */ + static const char * const attrs[] = /* Requested attributes */ + { + "requesting-user-name-allowed", + "requesting-user-name-denied" + }; + + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiStartHTML("Set Allowed Users"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + users = cgiGetVariable("users"); + type = cgiGetVariable("type"); + + if (!users || !type || + (strcmp(type, "requesting-user-name-allowed") && + strcmp(type, "requesting-user-name-denied"))) + { + /* + * 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); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", + (int)(sizeof(attrs) / sizeof(attrs[0])), NULL, attrs); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + ippDelete(response); + } + else + status = cupsLastError(); + + cgiStartHTML("Set Allowed Users"); + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + cgiCopyTemplateLang("users.tmpl"); + + cgiEndHTML(); + } + else + { + /* + * Save the changes... + */ + + for (num_users = 0, ptr = (char *)users; *ptr; num_users ++) + { + /* + * Skip whitespace and commas... + */ + + while (*ptr == ',' || isspace(*ptr & 255)) + ptr ++; + + if (*ptr == '\'' || *ptr == '\"') + { + /* + * Scan quoted name... + */ + + quote = *ptr++; + + for (end = ptr; *end; end ++) + if (*end == quote) + break; + } + else + { + /* + * Scan space or comma-delimited name... + */ + + for (end = ptr; *end; end ++) + if (isspace(*end & 255) || *end == ',') + break; + } + + /* + * Advance to the next name... + */ + + ptr = end; + } + + /* + * Build a CUPS-Add-Printer request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requesting-user-name-{allowed,denied} + */ + + 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); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + if (num_users == 0) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name-allowed", NULL, "all"); + else + { + attr = ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + type, num_users, NULL, NULL); + + for (i = 0, ptr = (char *)users; *ptr; i ++) + { + /* + * Skip whitespace and commas... + */ + + while (*ptr == ',' || isspace(*ptr & 255)) + ptr ++; + + if (*ptr == '\'' || *ptr == '\"') + { + /* + * Scan quoted name... + */ + + quote = *ptr++; + + for (end = ptr; *end; end ++) + if (*end == quote) + break; + } + else + { + /* + * Scan space or comma-delimited name... + */ + + for (end = ptr; *end; end ++) + if (isspace(*end & 255) || *end == ',') + break; + } + + /* + * Terminate the name... + */ + + if (*end) + *end++ = '\0'; + + /* + * Add the name... + */ + + attr->values[i].string.text = strdup(ptr); + + /* + * Advance to the next name... + */ + + ptr = end; + } + } + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + ippDelete(response); + } + else + status = cupsLastError(); + + if (status > IPP_OK_CONFLICT) + { + cgiStartHTML("Set Allowed Users"); + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + /* + * Redirect successful updates back to the printer page... + */ + + char refresh[1024]; /* Refresh URL */ + + cgiFormEncode(uri, printer, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s", + uri); + cgiSetVariable("refresh_page", refresh); + + cgiStartHTML("Set Allowed Users"); + + cgiCopyTemplateLang("printer-modified.tmpl"); + } + + cgiEndHTML(); + } +} + + +/* + * 'do_set_sharing()' - Set printer-is-shared value... + */ + +static void +do_set_sharing(http_t *http, /* I - HTTP connection */ + cups_lang_t *language) /* I - Language */ +{ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + char uri[HTTP_MAX_URI]; /* Printer URI */ + const char *printer, /* Printer name */ + *shared; /* Sharing value */ + ipp_status_t status; /* Operation status... */ + + + if ((printer = cgiGetVariable("PRINTER_NAME")) != NULL) + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", printer); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiStartHTML("Set Publishing"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + if ((shared = cgiGetVariable("SHARED")) == NULL) + { + cgiSetVariable("ERROR", "Missing SHARED parameter"); + cgiStartHTML("Set Publishing"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + return; + } + + /* + * Build a CUPS-Add-Printer request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * printer-is-shared + */ + + 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); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddBoolean(request, IPP_TAG_OPERATION, "printer-is-shared", atoi(shared)); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/admin/")) != NULL) + { + status = response->request.status.status_code; + + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + ippDelete(response); + } + else + status = cupsLastError(); + + if (status > IPP_OK_CONFLICT) + { + cgiStartHTML("Set Publishing"); + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + { + /* + * Redirect successful updates back to the printer page... + */ + + char refresh[1024]; /* Refresh URL */ + + cgiFormEncode(uri, printer, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "5;/admin?OP=redirect&URL=/printers/%s", + uri); + cgiSetVariable("refresh_page", refresh); + + cgiStartHTML("Set Publishing"); + + cgiCopyTemplateLang("printer-modified.tmpl"); + } + + cgiEndHTML(); +} + + +/* + * 'match_string()' - Return the number of matching characters. + */ + +static int /* O - Number of matching characters */ +match_string(const char *a, /* I - First string */ + const char *b) /* I - Second string */ +{ + int count; /* Number of matching characters */ + + + /* + * Loop through both strings until we hit the end of either or we find + * a non-matching character. For the purposes of comparison, we ignore + * whitespace and do a case-insensitive comparison so that we have a + * better chance of finding a match... + */ + + for (count = 0; *a && *b; a++, b++, count ++) + { + /* + * Skip leading whitespace characters... + */ + + while (isspace(*a & 255)) + a ++; + + while (isspace(*b & 255)) + b ++; + + /* + * Break out if we run out of characters... + */ + + if (!*a || !*b) + break; + + /* + * Do a case-insensitive comparison of the next two chars... + */ + + if (tolower(*a & 255) != tolower(*b & 255)) + break; + } + + return (count); +} + + +/* + * End of "$Id: admin.c 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/cgi-private.h b/cgi-bin/cgi-private.h new file mode 100644 index 000000000..b2af6d715 --- /dev/null +++ b/cgi-bin/cgi-private.h @@ -0,0 +1,44 @@ +/* + * "$Id: cgi-private.h 4921 2006-01-12 21:26:26Z mike $" + * + * Private CGI definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Include necessary headers... + */ + +#include "cgi.h" +#include +#include +#include + + +/* + * Limits... + */ + +#define CUPS_PAGE_MAX 10 /* Maximum items per page */ + + +/* + * End of "$Id: cgi-private.h 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/cgi.h b/cgi-bin/cgi.h new file mode 100644 index 000000000..ac63c4546 --- /dev/null +++ b/cgi-bin/cgi.h @@ -0,0 +1,106 @@ +/* + * "$Id: cgi.h 4921 2006-01-12 21:26:26Z mike $" + * + * CGI support library definitions. + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_CGI_H_ +# define _CUPS_CGI_H_ + +# include +# include +# include +# include + +# ifdef WIN32 +# include +# include +# else +# include +# endif /* WIN32 */ + +# include +# include +# include "help-index.h" + + +/* + * Types... + */ + +typedef struct cgi_file_s /**** Uploaded file data ****/ +{ + char tempfile[1024], /* Temporary file containing data */ + *name, /* Variable name */ + *filename, /* Original filename */ + *mimetype; /* MIME media type */ + size_t filesize; /* Size of uploaded file */ +} cgi_file_t; + + +/* + * Prototypes... + */ + +extern void cgiAbort(const char *title, const char *stylesheet, + const char *format, ...); +extern int cgiCheckVariables(const char *names); +extern void *cgiCompileSearch(const char *query); +extern void cgiCopyTemplateFile(FILE *out, const char *tmpl); +extern void cgiCopyTemplateLang(const char *tmpl); +extern int cgiDoSearch(void *search, const char *text); +extern void cgiEndHTML(void); +extern char *cgiFormEncode(char *dst, const char *src, size_t dstsize); +extern void cgiFreeSearch(void *search); +extern const char *cgiGetArray(const char *name, int element); +extern void cgiGetAttributes(ipp_t *request, const char *tmpl); +extern char *cgiGetCookie(const char *name, char *buf, int buflen); +extern const cgi_file_t *cgiGetFile(void); +extern cups_array_t *cgiGetIPPObjects(ipp_t *response, void *search); +extern int cgiGetSize(const char *name); +extern char *cgiGetTemplateDir(void); +extern const char *cgiGetVariable(const char *name); +extern int cgiInitialize(void); +extern int cgiIsPOST(void); +extern char *cgiRewriteURL(const char *uri, char *url, int urlsize, + const char *newresource); +extern void cgiSetArray(const char *name, int element, + const char *value); +extern void cgiSetCookie(const char *name, const char *value, + const char *path, const char *domain, + time_t expires, int secure); +extern ipp_attribute_t *cgiSetIPPObjectVars(ipp_attribute_t *obj, + const char *prefix, int element); +extern int cgiSetIPPVars(ipp_t *response, const char *filter_name, + const char *filter_value, + const char *prefix, int parent_el); +extern void cgiSetServerVersion(void); +extern void cgiSetSize(const char *name, int size); +extern void cgiSetVariable(const char *name, const char *value); +extern void cgiShowJobs(http_t *http, const char *dest); +extern void cgiStartHTML(const char *title); + + +#endif /* !_CUPS_CGI_H_ */ + +/* + * End of "$Id: cgi.h 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/classes.c b/cgi-bin/classes.c new file mode 100644 index 000000000..52c12efab --- /dev/null +++ b/cgi-bin/classes.c @@ -0,0 +1,396 @@ +/* + * "$Id: classes.c 4921 2006-01-12 21:26:26Z mike $" + * + * Class status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.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 */ + static const char *def_attrs[] = /* Attributes for default printer */ + { + "printer-name", + "printer-uri-supported" + }; + + + /* + * Get any form variables... + */ + + cgiInitialize(); + op = cgiGetVariable("OP"); + + /* + * Set the web interface section... + */ + + cgiSetVariable("SECTION", "classes"); + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + /* + * Tell the client to expect UTF-8 encoded HTML... + */ + + puts("Content-Type: text/html;charset=utf-8\n"); + + /* + * See if we need to show a list of printers or the status of a + * single printer... + */ + + cgiSetServerVersion(); + + pclass = argv[0]; + if (strcmp(pclass, "/") == 0 || strcmp(pclass, "classes.cgi") == 0) + { + pclass = NULL; + cgiSetVariable("TITLE", _cupsLangString(language, _("Class"))); + } + else + cgiSetVariable("TITLE", pclass); + + if (op == NULL || strcasecmp(op, "print-test-page") != 0) + { + /* + * Show the standard header... + */ + + cgiCopyTemplateLang("header.tmpl"); + + /* + * 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); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", + sizeof(def_attrs) / sizeof(def_attrs[0]), NULL, def_attrs); + + 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 url[HTTP_MAX_URI]; /* New URL */ + + + cgiSetVariable("DEFAULT_URI", + cgiRewriteURL(attr->values[0].string.text, + url, sizeof(url), NULL)); + } + + 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; + + if (getenv("REMOTE_USER") != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + } + 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; + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/classes/%s", pclass); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + } + + cgiGetAttributes(request, "classes.tmpl"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + ippDelete(response); + } + + /* + * Write the report... + */ + + cgiCopyTemplateLang("classes.tmpl"); + + /* + * Get jobs for the specified class if a class has been chosen... + */ + + if (pclass != NULL) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/classes/%s", 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); + + if (getenv("REMOTE_USER") != NULL) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + + if (strcmp(getenv("REMOTE_USER"), "root")) + ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); + } + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, "unknown"); + + cgiGetAttributes(request, "jobs.tmpl"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + ippDelete(response); + + cgiCopyTemplateLang("jobs.tmpl"); + } + } + } + else + { + /* + * Print a test page... + */ + + char filename[1024]; /* Test page filename */ + const char *datadir; /* CUPS_DATADIR env var */ + char refresh[1024]; /* Refresh URL */ + + + cgiFormEncode(uri, pclass, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "2;/classes/%s", uri); + cgiSetVariable("refresh_page", refresh); + + if ((datadir = getenv("CUPS_DATADIR")) == NULL) + datadir = CUPS_DATADIR; + + snprintf(filename, sizeof(filename), "%s/data/testprint.ps", datadir); + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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, + filename)) != NULL) + { + status = response->request.status.status_code; + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + ippDelete(response); + } + else + status = cupsLastError(); + + cgiSetVariable("PRINTER_NAME", pclass); + + /* + * Show the standard header... + */ + + cgiCopyTemplateLang("header.tmpl"); + + /* + * Show the result... + */ + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + cgiCopyTemplateLang("test-page.tmpl"); + } + + cgiCopyTemplateLang("trailer.tmpl"); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id: classes.c 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/help-index.c b/cgi-bin/help-index.c new file mode 100644 index 000000000..0b2e53b09 --- /dev/null +++ b/cgi-bin/help-index.c @@ -0,0 +1,1103 @@ +/* + * "$Id: help-index.c 4863 2005-12-03 04:28:10Z mike $" + * + * On-line help index routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * helpDeleteIndex() - Delete an index, freeing all memory used. + * helpFindNode() - Find a node in an index. + * helpLoadIndex() - Load a help index from disk. + * helpSaveIndex() - Save a help index to disk. + * helpSearchIndex() - Search an index. + * help_compile_search() - Convert a search string into a regular expression. + * help_create_sorted() - Create the sorted node array. + * help_delete_node() - Free all memory used by a node. + * help_insert_node() - Insert a node in an index. + * help_load_directory() - Load a directory of files into an index. + * help_load_file() - Load a HTML files into an index. + * help_new_node() - Create a new node and add it to an index. + * help_sort_nodes_by_name() - Sort nodes by section, filename, and anchor. + * help_sort_nodes_by_score() - Sort nodes by score and text. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.h" +#include + + +/* + * Local functions... + */ + +static void help_create_sorted(help_index_t *hi); +static void help_delete_node(help_node_t *n); +static void help_insert_node(help_index_t *hi, help_node_t *n); +static int help_load_directory(help_index_t *hi, + const char *directory, + const char *relative); +static int help_load_file(help_index_t *hi, + const char *filename, + const char *relative, + time_t mtime); +static help_node_t *help_new_node(const char *filename, const char *anchor, + const char *section, const char *text, + time_t mtime, off_t offset, + size_t length); +static int help_sort_by_name(const void *p1, const void *p2); +static int help_sort_by_score(const void *p1, const void *p2); + + +/* + * 'helpDeleteIndex()' - Delete an index, freeing all memory used. + */ + +void +helpDeleteIndex(help_index_t *hi) +{ + int i; /* Looping var */ + + + DEBUG_printf(("helpDeleteIndex(hi=%p)\n", hi)); + + if (!hi) + return; + + if (!hi->search) + { + for (i = 0; i < hi->num_nodes; i ++) + help_delete_node(hi->nodes[i]); + } + + free(hi->nodes); + + if (hi->sorted) + free(hi->sorted); + + free(hi); +} + + +/* + * 'helpFindNode()' - Find a node in an index. + */ + +help_node_t ** /* O - Node pointer or NULL */ +helpFindNode(help_index_t *hi, /* I - Index */ + const char *filename, /* I - Filename */ + const char *anchor) /* I - Anchor */ +{ + help_node_t key, /* Search key */ + *ptr; /* Pointer to key */ + + + DEBUG_printf(("helpFindNode(hi=%p, filename=\"%s\", anchor=\"%s\")\n", + hi, filename ? filename : "(nil)", anchor ? anchor : "(nil)")); + + /* + * Range check input... + */ + + if (!hi || !filename) + return (NULL); + + /* + * Initialize the search key... + */ + + key.filename = (char *)filename; + key.anchor = (char *)anchor; + ptr = &key; + + /* + * Return any match... + */ + + return ((help_node_t **)bsearch(&ptr, hi->nodes, hi->num_nodes, + sizeof(help_node_t *), help_sort_by_name)); +} + + +/* + * 'helpLoadIndex()' - Load a help index from disk. + */ + +help_index_t * /* O - Index pointer or NULL */ +helpLoadIndex(const char *hifile, /* I - Index filename */ + const char *directory) /* I - Directory that is indexed */ +{ + help_index_t *hi; /* Help index */ + cups_file_t *fp; /* Current file */ + char line[2048], /* Line from file */ + *ptr, /* Pointer into line */ + *filename, /* Filename in line */ + *anchor, /* Anchor in line */ + *sectptr, /* Section pointer in line */ + section[1024], /* Section name */ + *text; /* Text in line */ + time_t mtime; /* Modification time */ + off_t offset; /* Offset into file */ + size_t length; /* Length in bytes */ + int update; /* Update? */ + int i; /* Looping var */ + help_node_t *node; /* Current node */ + + + DEBUG_printf(("helpLoadIndex(hifile=\"%s\", directory=\"%s\")\n", + hifile, directory)); + + /* + * Create a new, empty index. + */ + + hi = (help_index_t *)calloc(1, sizeof(help_index_t)); + + /* + * Try loading the existing index file... + */ + + if ((fp = cupsFileOpen(hifile, "r")) != NULL) + { + /* + * Lock the file and then read the first line... + */ + + cupsFileLock(fp, 1); + + if (cupsFileGets(fp, line, sizeof(line)) && !strcmp(line, "HELPV1")) + { + /* + * Got a valid header line, now read the data lines... + */ + + while (cupsFileGets(fp, line, sizeof(line))) + { + /* + * Each line looks like one of the following: + * + * filename mtime offset length "section" "text" + * filename#anchor offset length "text" + */ + + filename = line; + + if ((ptr = strchr(line, ' ')) == NULL) + break; + + while (isspace(*ptr & 255)) + *ptr++ = '\0'; + + if ((anchor = strrchr(filename, '#')) != NULL) + { + *anchor++ = '\0'; + mtime = 0; + } + else + mtime = strtol(ptr, &ptr, 10); + + offset = strtoll(ptr, &ptr, 10); + length = strtoll(ptr, &ptr, 10); + + while (isspace(*ptr & 255)) + ptr ++; + + if (!anchor) + { + /* + * Get section... + */ + + if (*ptr != '\"') + break; + + ptr ++; + sectptr = ptr; + + while (*ptr && *ptr != '\"') + ptr ++; + + if (*ptr != '\"') + break; + + *ptr++ = '\0'; + + strlcpy(section, sectptr, sizeof(section)); + + while (isspace(*ptr & 255)) + ptr ++; + } + + if (*ptr != '\"') + break; + + ptr ++; + text = ptr; + + while (*ptr && *ptr != '\"') + ptr ++; + + if (*ptr != '\"') + break; + + *ptr++ = '\0'; + + if ((node = help_new_node(filename, anchor, section, text, + mtime, offset, length)) == NULL) + break; + + help_insert_node(hi, node); + + node->score = -1; + } + } + + cupsFileClose(fp); + } + + /* + * Scan for new/updated files... + */ + + update = help_load_directory(hi, directory, NULL); + + /* + * Remove any files that are no longer installed... + */ + + for (i = 0; i < hi->num_nodes;) + { + if (hi->nodes[i]->score < 0) + { + /* + * Delete this node... + */ + + help_delete_node(hi->nodes[i]); + + hi->num_nodes --; + if (i < hi->num_nodes) + memmove(hi->nodes + i, hi->nodes + i + 1, + (hi->num_nodes - i) * sizeof(help_node_t *)); + + update = 1; + } + else + { + /* + * Keep this node... + */ + + i ++; + } + } + + /* + * Save the index if we updated it... + */ + + if (update) + helpSaveIndex(hi, hifile); + + /* + * Create the sorted array... + */ + + help_create_sorted(hi); + + /* + * Return the index... + */ + + return (hi); +} + + +/* + * 'helpSaveIndex()' - Save a help index to disk. + */ + +int /* O - 0 on success, -1 on error */ +helpSaveIndex(help_index_t *hi, /* I - Index */ + const char *hifile) /* I - Index filename */ +{ + cups_file_t *fp; /* Index file */ + int i; /* Looping var */ + help_node_t *node; /* Current node */ + + + DEBUG_printf(("helpSaveIndex(hi=%p, hifile=\"%s\")\n", hi, hifile)); + + /* + * Try creating a new index file... + */ + + if ((fp = cupsFileOpen(hifile, "w9")) == NULL) + return (-1); + + /* + * Lock the file while we write it... + */ + + cupsFileLock(fp, 1); + + cupsFilePuts(fp, "HELPV1\n"); + + for (i = 0; i < hi->num_nodes; i ++) + { + /* + * Write the current node with/without the anchor... + */ + + node = hi->nodes[i]; + + if (node->anchor) + { + if (cupsFilePrintf(fp, "%s#%s " CUPS_LLFMT " " CUPS_LLFMT " \"%s\"\n", + node->filename, node->anchor, + CUPS_LLCAST node->offset, CUPS_LLCAST node->length, + node->text) < 0) + break; + } + else + { + if (cupsFilePrintf(fp, "%s %d " CUPS_LLFMT " " CUPS_LLFMT " \"%s\" \"%s\"\n", + node->filename, node->mtime, + CUPS_LLCAST node->offset, CUPS_LLCAST node->length, + node->section ? node->section : "", node->text) < 0) + break; + } + } + + if (cupsFileClose(fp) < 0) + return (-1); + else if (i < hi->num_nodes) + return (-1); + else + return (0); +} + + +/* + * 'helpSearchIndex()' - Search an index. + */ + +help_index_t * /* O - Search index */ +helpSearchIndex(help_index_t *hi, /* I - Index */ + const char *query, /* I - Query string */ + const char *section, /* I - Limit search to this section */ + const char *filename) /* I - Limit search to this file */ +{ + int i; /* Looping var */ + help_index_t *search; /* Search index */ + help_node_t **n; /* Current node */ + void *sc; /* Search context */ + int matches; /* Number of matches */ + + + DEBUG_printf(("helpSearchIndex(hi=%p, query=\"%s\", filename=\"%s\")\n", + hi, query ? query : "(nil)", + filename ? filename : "(nil)")); + + /* + * Range check... + */ + + if (!hi || !query) + return (NULL); + + for (i = 0, n = hi->nodes; i < hi->num_nodes; i ++, n ++) + n[0]->score = 0; + + if (filename) + { + n = helpFindNode(hi, filename, NULL); + if (!n) + return (NULL); + } + else + n = hi->nodes; + + /* + * Convert the query into a regular expression... + */ + + sc = cgiCompileSearch(query); + if (!sc) + return (NULL); + + /* + * Allocate a search index... + */ + + search = calloc(1, sizeof(help_index_t)); + if (!search) + { + cgiFreeSearch(sc); + return (NULL); + } + + search->search = 1; + + /* + * Check each node in the index, adding matching nodes to the + * search index... + */ + + for (i = n - hi->nodes; i < hi->num_nodes; i ++, n ++) + if (section && strcmp(n[0]->section, section)) + continue; + else if (filename && strcmp(n[0]->filename, filename)) + continue; + else if ((matches = cgiDoSearch(sc, n[0]->text)) > 0) + { + /* + * Found a match, add the node to the search index... + */ + + help_insert_node(search, *n); + + n[0]->score = matches; + } + + /* + * Free the search context... + */ + + cgiFreeSearch(sc); + + /* + * Sort the results... + */ + + help_create_sorted(search); + + /* + * Return the results... + */ + + return (search); +} + + +/* + * 'help_create_sorted()' - Create the sorted node array. + */ + +static void +help_create_sorted(help_index_t *hi) /* I - Index */ +{ + DEBUG_printf(("help_create_sorted(hi=%p)\n", hi)); + + /* + * Free any existing sorted array... + */ + + if (hi->sorted) + free(hi->sorted); + + /* + * Create a new sorted array... + */ + + hi->sorted = calloc(hi->num_nodes, sizeof(help_node_t *)); + + if (!hi->sorted) + return; + + /* + * Copy the nodes to the new array... + */ + + memcpy(hi->sorted, hi->nodes, hi->num_nodes * sizeof(help_node_t *)); + + /* + * Sort the new array by score and text. + */ + + if (hi->num_nodes > 1) + qsort(hi->sorted, hi->num_nodes, sizeof(help_node_t *), + help_sort_by_score); +} + + +/* + * 'help_delete_node()' - Free all memory used by a node. + */ + +static void +help_delete_node(help_node_t *n) /* I - Node */ +{ + DEBUG_printf(("help_delete_node(n=%p)\n", n)); + + if (!n) + return; + + if (n->filename) + free(n->filename); + + if (n->anchor) + free(n->anchor); + + if (n->section) + free(n->section); + + if (n->text) + free(n->text); + + free(n); +} + + +/* + * 'help_insert_node()' - Insert a node in an index. + */ + +static void +help_insert_node(help_index_t *hi, /* I - Index */ + help_node_t *n) /* I - Node */ +{ + int current, /* Current node */ + left, /* Left side */ + right, /* Right side */ + diff; /* Difference between nodes */ + help_node_t **temp; /* Temporary node pointer */ + + + DEBUG_printf(("help_insert_node(hi=%p, n=%p)\n", hi, n)); + + /* + * Allocate memory as needed... + */ + + if (hi->num_nodes >= hi->alloc_nodes) + { + /* + * Expand the array in 128 node increments... + */ + + hi->alloc_nodes += 128; + if (hi->alloc_nodes == 128) + temp = (help_node_t **)malloc(hi->alloc_nodes * sizeof(help_node_t *)); + else + temp = (help_node_t **)realloc(hi->nodes, + hi->alloc_nodes * sizeof(help_node_t *)); + + if (!temp) + return; + + hi->nodes = temp; + } + + /* + * Find the insertion point... + */ + + if (hi->num_nodes == 0 || + help_sort_by_name(&n, hi->nodes + hi->num_nodes - 1) > 0) + { + /* + * Last node... + */ + + hi->nodes[hi->num_nodes] = n; + hi->num_nodes ++; + return; + } + else if (help_sort_by_name(&n, hi->nodes) < 0) + { + /* + * First node... + */ + + memmove(hi->nodes + 1, hi->nodes, hi->num_nodes * sizeof(help_node_t *)); + hi->nodes[0] = n; + hi->num_nodes ++; + return; + } + + /* + * Otherwise, do a binary insertion... + */ + + left = 0; + right = hi->num_nodes - 1; + + do + { + current = (left + right) / 2; + diff = help_sort_by_name(&n, hi->nodes + current); + + if (!diff) + break; + else if (diff < 0) + right = current; + else + left = current; + } + while ((right - left) > 1); + + if (diff > 0) + current ++; + + memmove(hi->nodes + current + 1, hi->nodes + current, + (hi->num_nodes - current) * sizeof(help_node_t *)); + hi->nodes[current] = n; + hi->num_nodes ++; +} + + +/* + * 'help_load_directory()' - Load a directory of files into an index. + */ + +static int /* O - 0 = success, -1 = error, 1 = updated */ +help_load_directory( + help_index_t *hi, /* I - Index */ + const char *directory, /* I - Directory */ + const char *relative) /* I - Relative path */ +{ + int i; /* Looping var */ + cups_dir_t *dir; /* Directory file */ + cups_dentry_t *dent; /* Directory entry */ + char *ext, /* Pointer to extension */ + filename[1024], /* Full filename */ + relname[1024]; /* Relative filename */ + int update; /* Updated? */ + help_node_t **node; /* Current node */ + + + DEBUG_printf(("help_load_directory(hi=%p, directory=\"%s\", relative=\"%s\")\n", + hi, directory ? directory : "(nil)", relative ? relative : "(nil)")); + + /* + * Open the directory and scan it... + */ + + if ((dir = cupsDirOpen(directory)) == NULL) + return (0); + + update = 0; + + while ((dent = cupsDirRead(dir)) != NULL) + { + /* + * Get absolute and relative filenames... + */ + + snprintf(filename, sizeof(filename), "%s/%s", directory, dent->filename); + if (relative) + snprintf(relname, sizeof(relname), "%s/%s", relative, dent->filename); + else + strlcpy(relname, dent->filename, sizeof(relname)); + + /* + * Check if we have a HTML file... + */ + + if ((ext = strstr(dent->filename, ".html")) != NULL && + (!ext[5] || !strcmp(ext + 5, ".gz"))) + { + /* + * HTML file, see if we have already indexed the file... + */ + + if ((node = helpFindNode(hi, relname, NULL)) != NULL) + { + /* + * File already indexed - check dates to confirm that the + * index is up-to-date... + */ + + if (node[0]->mtime == dent->fileinfo.st_mtime) + { + /* + * Same modification time, so mark all of the nodes + * for this file as up-to-date... + */ + + for (i = node - hi->nodes; i < hi->num_nodes; i ++, node ++) + if (!strcmp(node[0]->filename, relname)) + node[0]->score = 0; + else + break; + + continue; + } + } + + update = 1; + + help_load_file(hi, filename, relname, dent->fileinfo.st_mtime); + } + else if (S_ISDIR(dent->fileinfo.st_mode)) + { + /* + * Process sub-directory... + */ + + if (help_load_directory(hi, filename, relname) == 1) + update = 1; + } + } + + cupsDirClose(dir); + + return (update); +} + + +/* + * 'help_load_file()' - Load a HTML files into an index. + */ + +static int /* O - 0 = success, -1 = error */ +help_load_file( + help_index_t *hi, /* I - Index */ + const char *filename, /* I - Filename */ + const char *relative, /* I - Relative path */ + time_t mtime) /* I - Modification time */ +{ + cups_file_t *fp; /* HTML file */ + help_node_t *node, /* Current node */ + **n; /* Node pointer */ + char line[1024], /* Line from file */ + section[1024], /* Section */ + *ptr, /* Pointer into line */ + *anchor, /* Anchor name */ + *text; /* Text for anchor */ + off_t offset; /* File offset */ + char quote; /* Quote character */ + + + DEBUG_printf(("help_load_file(hi=%p, filename=\"%s\", relative=\"%s\", mtime=%ld)\n", + hi, filename ? filename : "(nil)", + relative ? relative : "(nil)", mtime)); + + if ((fp = cupsFileOpen(filename, "r")) == NULL) + return (-1); + + node = NULL; + offset = 0; + + strcpy(section, "Other"); + + while (cupsFileGets(fp, line, sizeof(line))) + { + /* + * Look for "", "<A NAME", or "<!-- SECTION:" prefix... + */ + + if (!strncasecmp(line, "<!-- SECTION:", 13)) + { + /* + * Got section line, copy it! + */ + + for (ptr = line + 13; isspace(*ptr & 255); ptr ++); + + strlcpy(section, ptr, sizeof(section)); + if ((ptr = strstr(section, "-->")) != NULL) + { + /* + * Strip comment stuff from end of line... + */ + + for (*ptr-- = '\0'; ptr > line && isspace(*ptr & 255); *ptr-- = '\0'); + + if (isspace(*ptr & 255)) + *ptr = '\0'; + } + continue; + } + + for (ptr = line; (ptr = strchr(ptr, '<')) != NULL;) + { + ptr ++; + + if (!strncasecmp(ptr, "TITLE>", 6)) + { + /* + * Found the title... + */ + + anchor = NULL; + ptr += 6; + } + else if (!strncasecmp(ptr, "A NAME=", 7)) + { + /* + * Found an anchor... + */ + + ptr += 7; + + if (*ptr == '\"' || *ptr == '\'') + { + /* + * Get quoted anchor... + */ + + quote = *ptr; + anchor = ptr + 1; + if ((ptr = strchr(anchor, quote)) != NULL) + *ptr++ = '\0'; + else + break; + } + else + { + /* + * Get unquoted anchor... + */ + + anchor = ptr + 1; + + for (ptr = anchor; *ptr && *ptr != '>' && !isspace(*ptr & 255); ptr ++); + + if (*ptr) + *ptr++ = '\0'; + else + break; + } + + /* + * Got the anchor, now lets find the end... + */ + + while (*ptr && *ptr != '>') + ptr ++; + + if (*ptr != '>') + break; + + ptr ++; + } + else + continue; + + /* + * Now collect text for the link... + */ + + text = ptr; + while ((ptr = strchr(text, '<')) == NULL) + { + ptr = text + strlen(text); + if (ptr >= (line + sizeof(line) - 2)) + break; + + *ptr++ = ' '; + + if (!cupsFileGets(fp, ptr, sizeof(line) - (ptr - line) - 1)) + break; + } + + *ptr = '\0'; + + if (node) + node->length = offset - node->offset; + + if (!*text) + { + node = NULL; + break; + } + + if ((n = helpFindNode(hi, relative, anchor)) != NULL) + { + /* + * Node already in the index, so replace the text and other + * data... + */ + + node = n[0]; + + if (node->section) + free(node->section); + + if (node->text) + free(node->text); + + node->section = section[0] ? strdup(section) : NULL; + node->text = strdup(text); + node->mtime = mtime; + node->offset = offset; + node->score = 0; + } + else + { + /* + * New node... + */ + + node = help_new_node(relative, anchor, section, text, mtime, offset, 0); + help_insert_node(hi, node); + } + + /* + * Go through the text value and replace tabs and newlines with + * whitespace and eliminate extra whitespace... + */ + + for (ptr = node->text, text = node->text; *ptr;) + if (isspace(*ptr & 255)) + { + while (isspace(*ptr & 255)) + *ptr ++; + + *text++ = ' '; + } + else if (text != ptr) + *text++ = *ptr++; + else + { + text ++; + ptr ++; + } + + *text = '\0'; + + break; + } + + /* + * Get the offset of the next line... + */ + + offset = cupsFileTell(fp); + } + + cupsFileClose(fp); + + if (node) + node->length = offset - node->offset; + + return (0); +} + + +/* + * 'help_new_node()' - Create a new node and add it to an index. + */ + +static help_node_t * /* O - Node pointer or NULL on error */ +help_new_node(const char *filename, /* I - Filename */ + const char *anchor, /* I - Anchor */ + const char *section, /* I - Section */ + const char *text, /* I - Text */ + time_t mtime, /* I - Modification time */ + off_t offset, /* I - Offset in file */ + size_t length) /* I - Length in bytes */ +{ + help_node_t *n; /* Node */ + + + DEBUG_printf(("help_new_node(filename=\"%s\", anchor=\"%s\", text=\"%s\", mtime=%ld, offset=%ld, length=%ld)\n", + filename ? filename : "(nil)", anchor ? anchor : "(nil)", + text ? text : "(nil)", mtime, offset, length)); + + n = (help_node_t *)calloc(1, sizeof(help_node_t)); + if (!n) + return (NULL); + + n->filename = strdup(filename); + n->anchor = anchor ? strdup(anchor) : NULL; + n->section = (section && *section) ? strdup(section) : NULL; + n->text = strdup(text); + n->mtime = mtime; + n->offset = offset; + n->length = length; + + return (n); +} + + +/* + * 'help_sort_nodes_by_name()' - Sort nodes by section, filename, and anchor. + */ + +static int /* O - Difference */ +help_sort_by_name(const void *p1, /* I - First node */ + const void *p2) /* I - Second node */ +{ + help_node_t **n1, /* First node */ + **n2; /* Second node */ + int diff; /* Difference */ + + + DEBUG_printf(("help_sort_by_name(p1=%p, p2=%p)\n", p1, p2)); + + n1 = (help_node_t **)p1; + n2 = (help_node_t **)p2; + + if ((diff = strcmp(n1[0]->filename, n2[0]->filename)) != 0) + return (diff); + + if (!n1[0]->anchor && !n2[0]->anchor) + return (0); + else if (!n1[0]->anchor) + return (-1); + else if (!n2[0]->anchor) + return (1); + else + return (strcmp(n1[0]->anchor, n2[0]->anchor)); +} + + +/* + * 'help_sort_nodes_by_score()' - Sort nodes by score and text. + */ + +static int /* O - Difference */ +help_sort_by_score(const void *p1, /* I - First node */ + const void *p2) /* I - Second node */ +{ + help_node_t **n1, /* First node */ + **n2; /* Second node */ + int diff; /* Difference */ + + + DEBUG_printf(("help_sort_by_score(p1=%p, p2=%p)\n", p1, p2)); + + n1 = (help_node_t **)p1; + n2 = (help_node_t **)p2; + + if (n1[0]->score != n2[0]->score) + return (n1[0]->score - n2[0]->score); + + if (n1[0]->section && !n2[0]->section) + return (1); + else if (!n1[0]->section && n2[0]->section) + return (-1); + else if (n1[0]->section && n2[0]->section && + (diff = strcmp(n1[0]->section, n2[0]->section)) != 0) + return (diff); + + return (strcasecmp(n1[0]->text, n2[0]->text)); +} + + +/* + * End of "$Id: help-index.c 4863 2005-12-03 04:28:10Z mike $". + */ diff --git a/cgi-bin/help-index.h b/cgi-bin/help-index.h new file mode 100644 index 000000000..68a898670 --- /dev/null +++ b/cgi-bin/help-index.h @@ -0,0 +1,73 @@ +/* + * "$Id: help-index.h 4863 2005-12-03 04:28:10Z mike $" + * + * On-line help index definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_HELP_INDEX_H_ +# define _CUPS_HELP_INDEX_H_ + + +/* + * Data structures... + */ + +typedef struct /**** Help node structure... ****/ +{ + char *filename; /* Filename, relative to help dir */ + char *section; /* Section name (NULL if none) */ + char *anchor; /* Anchor name (NULL if none) */ + char *text; /* Text in anchor */ + time_t mtime; /* Last modification time */ + off_t offset; /* Offset in file */ + size_t length; /* Length in bytes */ + int score; /* Search score */ +} help_node_t; + +typedef struct /**** Help index structure ****/ +{ + int search, /* 1 = search index, 0 = normal */ + num_nodes, /* Number of nodes */ + alloc_nodes; /* Allocated nodes */ + help_node_t **nodes; /* Nodes sorted by filename */ + help_node_t **sorted; /* Nodes sorted by score + text */ +} help_index_t; + + +/* + * Functions... + */ + +extern void helpDeleteIndex(help_index_t *hi); +extern help_node_t **helpFindNode(help_index_t *hi, const char *filename, + const char *anchor); +extern help_index_t *helpLoadIndex(const char *hifile, const char *directory); +extern int helpSaveIndex(help_index_t *hi, const char *hifile); +extern help_index_t *helpSearchIndex(help_index_t *hi, const char *query, + const char *section, + const char *filename); + + +#endif /* !_CUPS_HELP_INDEX_H_ */ + +/* + * End of "$Id: help-index.h 4863 2005-12-03 04:28:10Z mike $". + */ diff --git a/cgi-bin/help.c b/cgi-bin/help.c new file mode 100644 index 000000000..5071ca825 --- /dev/null +++ b/cgi-bin/help.c @@ -0,0 +1,362 @@ +/* + * "$Id$" + * + * On-line help CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.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 */ +{ + help_index_t *hi, /* Help index */ + *si; /* Search index */ + help_node_t **n; /* Current help node */ + int i, j; /* Looping vars */ + const char *query; /* Search query */ + const char *server_root; /* CUPS_SERVERROOT environment variable */ + const char *docroot; /* CUPS_DOCROOT environment variable */ + const char *helpfile; /* Current help file */ + const char *topic; /* Current topic */ + char topic_data[1024]; /* Topic form data */ + const char *section; /* Current section */ + char filename[1024], /* Filename */ + directory[1024]; /* Directory */ + cups_file_t *fp; /* Help file */ + char line[1024]; /* Line from file */ + + + /* + * Get any form variables... + */ + + cgiInitialize(); + + /* + * Set the web interface section... + */ + + cgiSetVariable("SECTION", "help"); + + /* + * Load the help index... + */ + + if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) + server_root = CUPS_SERVERROOT; + + snprintf(filename, sizeof(filename), "%s/help.index", server_root); + + if ((docroot = getenv("CUPS_DOCROOT")) == NULL) + docroot = CUPS_DOCROOT; + + snprintf(directory, sizeof(directory), "%s/help", docroot); + + fprintf(stderr, "DEBUG: helpLoadIndex(filename=\"%s\", directory=\"%s\")\n", + filename, directory); + + hi = helpLoadIndex(filename, directory); + if (!hi) + { + perror(filename); + + cgiStartHTML("Help"); + cgiSetVariable("ERROR", "Unable to load help index!"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + return (1); + } + + fprintf(stderr, "hi->num_nodes=%d\n", hi->num_nodes); + + /* + * See if we are viewing a file... + */ + + for (i = 0; i < argc; i ++) + fprintf(stderr, "argv[%d]=\"%s\"\n", i, argv[i]); + + if ((helpfile = getenv("PATH_INFO")) != NULL) + helpfile ++; + else if (strstr(argv[0], "help.cgi")) + helpfile = NULL; + else + helpfile = argv[0]; + + if (helpfile) + { + /* + * Verify that the help file exists and is part of the index... + */ + + snprintf(filename, sizeof(filename), "%s/help/%s", docroot, helpfile); + + fprintf(stderr, "DEBUG: helpfile=\"%s\", filename=\"%s\"\n", + helpfile, filename); + + if (access(filename, R_OK)) + { + perror(filename); + + cgiStartHTML("Help"); + cgiSetVariable("ERROR", "Unable to access help file!"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + return (1); + } + + if ((n = helpFindNode(hi, helpfile, NULL)) == NULL) + { + cgiStartHTML("Help"); + cgiSetVariable("ERROR", "Help file not in index!"); + cgiCopyTemplateLang("error.tmpl"); + cgiEndHTML(); + + return (1); + } + + /* + * Set the page title and save the help file... + */ + + cgiSetVariable("HELPFILE", helpfile); + cgiSetVariable("HELPTITLE", n[0]->text); + + /* + * Send a standard page header... + */ + + cgiStartHTML(n[0]->text); + } + else + { + /* + * Send a standard page header... + */ + + cgiStartHTML("Help"); + } + + /* + * Do a search as needed... + */ + + query = cgiGetVariable("QUERY"); + topic = cgiGetVariable("TOPIC"); + si = helpSearchIndex(hi, query, topic, helpfile); + + if (si) + { + help_node_t **nn; /* Parent node */ + + + fprintf(stderr, "si=%p, si->num_nodes=%d, si->sorted=%p\n", si, + si->num_nodes, si->sorted); + + for (i = 0, n = si->sorted; i < si->num_nodes; i ++, n ++) + { + if (helpfile && n[0]->anchor) + snprintf(line, sizeof(line), "#%s", n[0]->anchor); + else if (n[0]->anchor) + snprintf(line, sizeof(line), "/help/%s?QUERY=%s#%s", n[0]->filename, + query ? query : "", n[0]->anchor); + else + snprintf(line, sizeof(line), "/help/%s?QUERY=%s", n[0]->filename, + query ? query : ""); + + cgiSetArray("QTEXT", i, n[0]->text); + cgiSetArray("QLINK", i, line); + + if (!helpfile && n[0]->anchor) + { + nn = helpFindNode(hi, n[0]->filename, NULL); + + snprintf(line, sizeof(line), "/help/%s?QUERY=%s", nn[0]->filename, + query ? query : ""); + + cgiSetArray("QPTEXT", i, nn[0]->text); + cgiSetArray("QPLINK", i, line); + } + else + { + cgiSetArray("QPTEXT", i, ""); + cgiSetArray("QPLINK", i, ""); + } + + fprintf(stderr, "DEBUG: [%d] = \"%s\" @ \"%s\"\n", i, n[0]->text, line); + } + + helpDeleteIndex(si); + } + + /* + * OK, now list the bookmarks within the index... + */ + + for (i = hi->num_nodes, j = 0, n = hi->sorted, section = NULL; + i > 0; + i --, n ++) + { + if (n[0]->anchor) + continue; + + /* + * Add a section link as needed... + */ + + if (n[0]->section && + (!section || strcmp(n[0]->section, section))) + { + /* + * Add a link for this node... + */ + + snprintf(line, sizeof(line), "/help/?TOPIC=%s&QUERY=%s", + cgiFormEncode(topic_data, n[0]->section, sizeof(topic_data)), + query ? query : ""); + cgiSetArray("BMLINK", j, line); + cgiSetArray("BMTEXT", j, n[0]->section); + cgiSetArray("BMINDENT", j, "0"); + + j ++; + section = n[0]->section; + } + + if (!topic || strcmp(n[0]->section, topic)) + continue; + + /* + * Add a link for this node... + */ + + snprintf(line, sizeof(line), "/help/%s?TOPIC=%s&QUERY=%s", n[0]->filename, + cgiFormEncode(topic_data, n[0]->section, sizeof(topic_data)), + query ? query : ""); + cgiSetArray("BMLINK", j, line); + cgiSetArray("BMTEXT", j, n[0]->text); + cgiSetArray("BMINDENT", j, "1"); + + j ++; + + if (helpfile && !strcmp(helpfile, n[0]->filename)) + { + int ii; /* Looping var */ + help_node_t **nn; /* Pointer to sub-node */ + + + for (ii = hi->num_nodes, nn = hi->sorted; ii > 0; ii --, nn ++) + if (nn[0]->anchor && !strcmp(helpfile, nn[0]->filename)) + { + /* + * Add a link for this node... + */ + + snprintf(line, sizeof(line), "#%s", nn[0]->anchor); + cgiSetArray("BMLINK", j, line); + cgiSetArray("BMTEXT", j, nn[0]->text); + cgiSetArray("BMINDENT", j, "2"); + + j ++; + } + } + } + + /* + * Show the search and bookmark content... + */ + + cgiCopyTemplateLang("help-header.tmpl"); + + /* + * If we are viewing a file, copy it in now... + */ + + if (helpfile) + { + if ((fp = cupsFileOpen(filename, "r")) != NULL) + { + int inbody; /* Are we inside the body? */ + + + inbody = 0; + + while (cupsFileGets(fp, line, sizeof(line))) + { + if (inbody) + { + if (!strncasecmp(line, "</BODY>", 7)) + break; + + printf("%s\n", line); + } + else if (!strncasecmp(line, "<BODY", 5)) + inbody = 1; + } + + cupsFileClose(fp); + } + else + { + perror(filename); + cgiSetVariable("ERROR", "Unable to open help file."); + cgiCopyTemplateLang("error.tmpl"); + } + } + + /* + * Send a standard trailer... + */ + + cgiEndHTML(); + + /* + * Delete the index... + */ + + helpDeleteIndex(hi); + + /* + * 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..a51b28f94 --- /dev/null +++ b/cgi-bin/html.c @@ -0,0 +1,186 @@ +/* + * "$Id: html.c 4921 2006-01-12 21:26:26Z mike $" + * + * HTML support functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cgiEndHTML() - End a HTML page. + * cgiFormEncode() - Encode a string as a form variable... + * cgiStartHTML() - Start a HTML page. + * cgi_null_passwd() - Return a NULL password for authentication. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.h" + + +/* + * Local functions... + */ + +static const char *cgi_null_passwd(const char *prompt); + + +/* + * 'cgiEndHTML()' - End a HTML page. + */ + +void +cgiEndHTML(void) +{ + /* + * Send the standard trailer... + */ + + cgiCopyTemplateLang("trailer.tmpl"); +} + + +/* + * 'cgiFormEncode()' - Encode a string as a form variable... + */ + +char * /* O - Destination string */ +cgiFormEncode(char *dst, /* I - Destination string */ + const char *src, /* I - Source string */ + size_t dstsize) /* I - Size of destination string */ +{ + char *dstptr, /* Pointer into destination */ + *dstend; /* End of destination */ + static const char *hex = /* Hexadecimal characters */ + "0123456789ABCDEF"; + + + /* + * Mark the end of the string... + */ + + dstend = dst + dstsize - 1; + + /* + * Loop through the source string and copy... + */ + + for (dstptr = dst; *src && dstptr < dstend;) + { + switch (*src) + { + case ' ' : + /* + * Encode spaces with a "+"... + */ + + *dstptr++ = '+'; + src ++; + break; + + case '&' : + case '%' : + case '+' : + /* + * Encode special characters with %XX escape... + */ + + if (dstptr < (dstend - 2)) + { + *dstptr++ = '%'; + *dstptr++ = hex[(*src & 255) >> 4]; + *dstptr++ = hex[*src & 15]; + src ++; + } + break; + + default : + /* + * Copy other characters literally... + */ + + *dstptr++ = *src++; + break; + } + } + + /* + * Nul-terminate the destination string... + */ + + *dstptr = '\0'; + + /* + * Return the encoded string... + */ + + return (dst); +} + + +/* + * 'cgiStartHTML()' - Start a HTML page. + */ + +void +cgiStartHTML(const char *title) /* I - Title of page */ +{ + /* + * Disable any further authentication attempts... + */ + + cupsSetPasswordCB(cgi_null_passwd); + + /* + * Tell the client to expect UTF-8 encoded HTML... + */ + + puts("Content-Type: text/html;charset=utf-8\n"); + + /* + * Send a standard header... + */ + + cgiSetVariable("TITLE", title); + cgiSetServerVersion(); + + cgiCopyTemplateLang("header.tmpl"); +} + + +/* + * 'cgi_null_passwd()' - Return a NULL password for authentication. + */ + +static const char * /* O - NULL */ +cgi_null_passwd(const char *prompt) /* I - Prompt string (unused) */ +{ + (void)prompt; + + fprintf(stderr, "DEBUG: cgi_null_passwd(prompt=\"%s\") called!\n", prompt); + + return (NULL); +} + + +/* + * End of "$Id: html.c 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/ipp-var.c b/cgi-bin/ipp-var.c new file mode 100644 index 000000000..292cfea24 --- /dev/null +++ b/cgi-bin/ipp-var.c @@ -0,0 +1,896 @@ +/* + * "$Id: ipp-var.c 4921 2006-01-12 21:26:26Z mike $" + * + * CGI <-> IPP variable routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cgiGetAttributes() - Get the list of attributes that are needed + * by the template file. + * cupsGetIPPObjects() - Get the objects in an IPP response. + * cgiRewriteURL() - Rewrite a printer URI into a web browser URL... + * cgiSetIPPObjectVars() - Set CGI variables from an IPP object. + * cgiSetIPPVars() - Set CGI variables from an IPP response. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.h" + + +/* + * 'cgiGetAttributes()' - Get the list of attributes that are needed + * by the template file. + */ + +void +cgiGetAttributes(ipp_t *request, /* I - IPP request */ + const char *tmpl) /* I - Base filename */ +{ + int num_attrs; /* Number of attributes */ + char *attrs[1000]; /* Attributes */ + int i; /* Looping var */ + char filename[1024], /* Filename */ + locale[16]; /* Locale name */ + const char *directory, /* Directory */ + *lang; /* Language */ + FILE *in; /* Input file */ + int ch; /* Character from file */ + char name[255], /* Name of variable */ + *nameptr; /* Pointer into name */ + + + /* + * Convert the language to a locale name... + */ + + if ((lang = getenv("LANG")) != NULL) + { + for (i = 0; lang[i] && i < 15; i ++) + if (isalnum(lang[i] & 255)) + 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... + */ + + directory = cgiGetTemplateDir(); + + 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; + + /* + * Loop through the file adding attribute names as needed... + */ + + num_attrs = 0; + + while ((ch = getc(in)) != EOF) + if (ch == '\\') + getc(in); + else if (ch == '{' && num_attrs < (sizeof(attrs) / sizeof(attrs[0]))) + { + /* + * Grab the name... + */ + + for (nameptr = name; (ch = getc(in)) != EOF;) + if (strchr("}]<>=! \t\n", ch)) + break; + else if (nameptr > name && ch == '?') + break; + else if (nameptr < (name + sizeof(name) - 1)) + { + if (ch == '_') + *nameptr++ = '-'; + else + *nameptr++ = ch; + } + + *nameptr = '\0'; + + if (!strncmp(name, "printer_state_history", 21)) + strcpy(name, "printer_state_history"); + + /* + * Possibly add it to the list of attributes... + */ + + for (i = 0; i < num_attrs; i ++) + if (!strcmp(attrs[i], name)) + break; + + if (i >= num_attrs) + { + attrs[num_attrs] = strdup(name); + num_attrs ++; + } + } + + /* + * If we have attributes, add a requested-attributes attribute to the + * request... + */ + + if (num_attrs > 0) + { + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", num_attrs, NULL, (const char **)attrs); + + for (i = 0; i < num_attrs; i ++) + free(attrs[i]); + } +} + + +/* + * 'cupsGetIPPObjects()' - Get the objects in an IPP response. + */ + +cups_array_t * /* O - Array of objects */ +cgiGetIPPObjects(ipp_t *response, /* I - IPP response */ + void *search) /* I - Search filter */ +{ + int i; /* Looping var */ + cups_array_t *objs; /* Array of objects */ + ipp_attribute_t *attr, /* Current attribute */ + *first; /* First attribute for object */ + ipp_tag_t group; /* Current group tag */ + int add; /* Add this object to the array? */ + + + if (!response) + return (0); + + for (add = 0, first = NULL, objs = cupsArrayNew(NULL, NULL), + group = IPP_TAG_ZERO, attr = response->attrs; + attr; + attr = attr->next) + { + if (attr->group_tag != group) + { + group = attr->group_tag; + + if (group != IPP_TAG_ZERO && group != IPP_TAG_OPERATION) + { + first = attr; + add = 0; + } + else if (add && first) + { + cupsArrayAdd(objs, first); + + add = 0; + first = NULL; + } + } + + if (attr->name && attr->group_tag != IPP_TAG_OPERATION && !add) + { + if (!search) + { + /* + * Add all objects if there is no search... + */ + + add = 1; + } + else + { + /* + * Check the search string against the string and integer values. + */ + + switch (attr->value_tag) + { + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_URI : + case IPP_TAG_MIMETYPE : + for (i = 0; !add && i < attr->num_values; i ++) + if (cgiDoSearch(search, attr->values[i].string.text)) + add = 1; + break; + + case IPP_TAG_INTEGER : + for (i = 0; !add && i < attr->num_values; i ++) + { + char buf[255]; /* Number buffer */ + + + sprintf(buf, "%d", attr->values[i].integer); + + if (cgiDoSearch(search, buf)) + add = 1; + } + break; + + default : + break; + } + } + } + } + + if (add && first) + cupsArrayAdd(objs, first); + + return (objs); +} + + +/* + * 'cgiRewriteURL()' - Rewrite a printer URI into a web browser URL... + */ + +char * /* O - New URL */ +cgiRewriteURL(const char *uri, /* I - Current URI */ + char *url, /* O - New URL */ + int urlsize, /* I - Size of URL buffer */ + const char *newresource) /* I - Replacement resource */ +{ + char method[HTTP_MAX_URI], + userpass[HTTP_MAX_URI], + hostname[HTTP_MAX_URI], + rawresource[HTTP_MAX_URI], + resource[HTTP_MAX_URI], + /* URI components... */ + *rawptr, /* Pointer into rawresource */ + *resptr; /* Pointer into resource */ + int port; /* Port number */ + static int ishttps = -1; /* Using encryption? */ + static const char *server; /* Name of server */ + static char servername[1024]; + /* Local server name */ + static const char hexchars[] = "0123456789ABCDEF"; + /* Hexadecimal conversion characters */ + + + /* + * Check if we have been called before... + */ + + if (ishttps < 0) + { + /* + * No, initialize static vars for the conversion... + * + * First get the server name associated with the client interface as + * well as the locally configured hostname. We'll check *both* of + * these to see if the printer URL is local... + */ + + if ((server = getenv("SERVER_NAME")) == NULL) + server = ""; + + httpGetHostname(servername, sizeof(servername)); + + /* + * Then flag whether we are using SSL on this connection... + */ + + ishttps = getenv("HTTPS") != NULL; + } + + /* + * Convert the URI to a URL... + */ + + httpSeparateURI(uri, method, sizeof(method), userpass, sizeof(userpass), + hostname, sizeof(hostname), &port, + rawresource, sizeof(rawresource)); + + if (!strcmp(method, "ipp") || + !strcmp(method, "http") || + !strcmp(method, "https")) + { + if (newresource) + { + /* + * Force the specified resource name instead of the one in the URL... + */ + + strlcpy(resource, newresource, sizeof(resource)); + } + else + { + /* + * Rewrite the resource string so it doesn't contain any + * illegal chars... + */ + + for (rawptr = rawresource, resptr = resource; *rawptr; rawptr ++) + if ((*rawptr & 128) || *rawptr == '%' || *rawptr == ' ' || + *rawptr == '#' || *rawptr == '?' || + *rawptr == '.') /* For MSIE */ + { + if (resptr < (resource + sizeof(resource) - 3)) + { + *resptr++ = '%'; + *resptr++ = hexchars[(*rawptr >> 4) & 15]; + *resptr++ = hexchars[*rawptr & 15]; + } + } + else if (resptr < (resource + sizeof(resource) - 1)) + *resptr++ = *rawptr; + + *resptr = '\0'; + } + + /* + * Map local access to a local URI... + */ + + if (!strcasecmp(hostname, "localhost") || + !strncasecmp(hostname, "localhost.", 10) || + !strcasecmp(hostname, server) || + !strcasecmp(hostname, servername)) + { + /* + * Make URI relative to the current server... + */ + + strlcpy(url, resource, urlsize); + } + else + { + /* + * Rewrite URI with HTTP/HTTPS scheme... + */ + + if (userpass[0]) + snprintf(url, urlsize, "%s://%s@%s:%d%s", + ishttps ? "https" : "http", + userpass, hostname, port, resource); + else + snprintf(url, urlsize, "%s://%s:%d%s", + ishttps ? "https" : "http", + hostname, port, resource); + } + } + else + strlcpy(url, uri, urlsize); + + return (url); +} + + +/* + * 'cgiSetIPPObjectVars()' - Set CGI variables from an IPP object. + */ + +ipp_attribute_t * /* O - Next object */ +cgiSetIPPObjectVars( + ipp_attribute_t *obj, /* I - Response data to be copied... */ + const char *prefix, /* I - Prefix for name or NULL */ + int element) /* I - Parent element number */ +{ + ipp_attribute_t *attr; /* Attribute in response... */ + int i; /* Looping var */ + char name[1024], /* Name of attribute */ + *nameptr, /* Pointer into name */ + value[16384], /* Value(s) */ + *valptr; /* Pointer into value */ + struct tm *date; /* Date information */ + + + fprintf(stderr, "DEBUG2: cgiSetIPPObjectVars(obj=%p, prefix=\"%s\", " + "element=%d)\n", + obj, prefix, element); + + /* + * Set common CGI template variables... + */ + + if (!prefix) + cgiSetServerVersion(); + + /* + * Loop through the attributes and set them for the template... + */ + + for (attr = obj; attr && attr->group_tag != IPP_TAG_ZERO; attr = attr->next) + { + /* + * Copy the attribute name, substituting "_" for "-"... + */ + + if (!attr->name) + continue; + + if (prefix) + { + snprintf(name, sizeof(name), "%s.", prefix); + nameptr = name + strlen(name); + } + else + nameptr = name; + + for (i = 0; attr->name[i] && nameptr < (name + sizeof(name) - 1); i ++) + if (attr->name[i] == '-') + *nameptr++ = '_'; + else + *nameptr++ = attr->name[i]; + + *nameptr = '\0'; + + /* + * Add "job_printer_name" variable if we have a "job_printer_uri" + * attribute... + */ + + if (!strcmp(name, "job_printer_uri")) + { + if ((valptr = strrchr(attr->values[0].string.text, '/')) == NULL) + valptr = "unknown"; + else + valptr ++; + + cgiSetArray("job_printer_name", element, valptr); + } + + /* + * Add "admin_uri" variable if we have a "printer_uri_supported" + * attribute... + */ + + if (!strcmp(name, "printer_uri_supported")) + { + cgiRewriteURL(attr->values[0].string.text, value, sizeof(value), + "/admin/"); + + cgiSetArray("admin_uri", element, value); + } + + /* + * Copy values... + */ + + value[0] = '\0'; /* Initially an empty string */ + valptr = value; /* Start at the beginning */ + + for (i = 0; i < attr->num_values; i ++) + { + if (i) + strlcat(valptr, ",", sizeof(value) - (valptr - value)); + + valptr += strlen(valptr); + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + if (strncmp(name, "time_at_", 8) == 0) + { + time_t t; /* Temporary time value */ + + t = (time_t)attr->values[i].integer; + date = localtime(&t); + + strftime(valptr, sizeof(value) - (valptr - value), "%c", 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 : + strlcat(valptr, "novalue", sizeof(value) - (valptr - value)); + 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) + { + /* + * Rewrite URIs... + */ + + if (!strcmp(name, "member_uris")) + { + char url[1024]; /* URL for class member... */ + + + cgiRewriteURL(attr->values[i].string.text, url, + sizeof(url), NULL); + + snprintf(valptr, sizeof(value) - (valptr - value), + "<A HREF=\"%s\">%s</A>", url, + strrchr(url, '/') + 1); + } + else + cgiRewriteURL(attr->values[i].string.text, valptr, + sizeof(value) - (valptr - value), NULL); + break; + } + + case IPP_TAG_STRING : + case IPP_TAG_TEXT : + case IPP_TAG_NAME : + case IPP_TAG_KEYWORD : + case IPP_TAG_CHARSET : + case IPP_TAG_LANGUAGE : + case IPP_TAG_MIMETYPE : + strlcat(valptr, attr->values[i].string.text, + sizeof(value) - (valptr - value)); + break; + + case IPP_TAG_BEGIN_COLLECTION : + snprintf(value, sizeof(value), "%s%d", name, i + 1); + cgiSetIPPVars(attr->values[i].collection, NULL, NULL, value, + element); + break; + + default : + break; /* anti-compiler-warning-code */ + } + } + + /* + * Add the element... + */ + + if (attr->value_tag != IPP_TAG_BEGIN_COLLECTION) + { + cgiSetArray(name, element, value); + + fprintf(stderr, "DEBUG2: %s[%d]=\"%s\"\n", name, element, value); + } + } + + return (attr ? attr->next : NULL); +} + + +/* + * 'cgiSetIPPVars()' - Set CGI variables from an IPP response. + */ + +int /* O - Maximum number of elements */ +cgiSetIPPVars(ipp_t *response, /* I - Response data to be copied... */ + const char *filter_name, /* I - Filter name */ + const char *filter_value, /* I - Filter value */ + const char *prefix, /* I - Prefix for name or NULL */ + int parent_el) /* I - Parent element number */ +{ + int element; /* Element in CGI array */ + ipp_attribute_t *attr, /* Attribute in response... */ + *filter; /* Filtering attribute */ + + + fprintf(stderr, "DEBUG2: cgiSetIPPVars(response=%p, filter_name=\"%s\", " + "filter_value=\"%s\", prefix=\"%s\", parent_el=%d)\n", + response, filter_name, filter_value, prefix, parent_el); + + /* + * Set common CGI template variables... + */ + + if (!prefix) + cgiSetServerVersion(); + + /* + * Loop through the attributes and set them for the template... + */ + + attr = response->attrs; + + if (!prefix) + while (attr && attr->group_tag == IPP_TAG_OPERATION) + attr = attr->next; + + for (element = parent_el; attr; element ++) + { + /* + * Copy attributes to a separator... + */ + + while (attr && attr->group_tag == IPP_TAG_ZERO) + attr= attr->next; + + if (!attr) + break; + + 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) && + (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)) + break; + + if (!filter) + return (element + 1); + + if (filter->group_tag == IPP_TAG_ZERO) + { + attr = filter; + element --; + continue; + } + } + + attr = cgiSetIPPObjectVars(attr, prefix, element); + } + + fprintf(stderr, "DEBUG2: Returing %d from cgiSetIPPVars()...\n", element + 1); + + return (element + 1); +} + + +/* + * 'cgiShowJobs()' - Show print jobs. + */ + +void +cgiShowJobs(http_t *http, /* I - Connection to server */ + const char *dest) /* I - Destination name or NULL */ +{ + int i; /* Looping var */ + const char *which_jobs; /* Which jobs to show */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + cups_array_t *jobs; /* Array of job objects */ + ipp_attribute_t *job; /* Job object */ + int ascending, /* Order of jobs (0 = descending) */ + first, /* First job to show */ + count; /* Number of jobs */ + const char *var; /* Form variable */ + void *search; /* Search data */ + char url[1024], /* URL for prev/next/this */ + *urlptr, /* Position in URL */ + *urlend; /* End of URL */ + cups_lang_t *language; /* Language information */ + + + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + 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); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + if (dest) + { + httpAssembleURIf(url, sizeof(url), "ipp", NULL, "localhost", ippPort(), + "/printers/%s", dest); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, url); + } + else + 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); + + cgiGetAttributes(request, "jobs.tmpl"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + /* + * Get a list of matching job objects. + */ + + if (!dest && (var = cgiGetVariable("QUERY")) != NULL) + search = cgiCompileSearch(var); + else + search = NULL; + + jobs = cgiGetIPPObjects(response, search); + count = cupsArrayCount(jobs); + + if (search) + cgiFreeSearch(search); + + /* + * Figure out which jobs to display... + */ + + if ((var = cgiGetVariable("FIRST")) != NULL) + first = atoi(var); + else + first = 0; + + if (first >= count) + first = count - CUPS_PAGE_MAX; + + first = (first / CUPS_PAGE_MAX) * CUPS_PAGE_MAX; + + if (first < 0) + first = 0; + + sprintf(url, "%d", count); + cgiSetVariable("TOTAL", url); + + if ((var = cgiGetVariable("ORDER")) != NULL) + ascending = !strcasecmp(var, "asc"); + else + ascending = 1; + + if (ascending) + { + for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, first); + i < CUPS_PAGE_MAX && job; + i ++, job = (ipp_attribute_t *)cupsArrayNext(jobs)) + cgiSetIPPObjectVars(job, NULL, i); + } + else + { + for (i = 0, job = (ipp_attribute_t *)cupsArrayIndex(jobs, count - first - 1); + i < CUPS_PAGE_MAX && job; + i ++, job = (ipp_attribute_t *)cupsArrayPrev(jobs)) + cgiSetIPPObjectVars(job, NULL, i); + } + + /* + * Save navigation URLs... + */ + + urlend = url + sizeof(url); + + if (dest) + { + snprintf(url, sizeof(url), "/%s/%s?", cgiGetVariable("SECTION"), dest); + urlptr = url + strlen(url); + } + else if ((var = cgiGetVariable("QUERY")) != NULL) + { + strlcpy(url, "/jobs/?QUERY=", sizeof(url)); + urlptr = url + strlen(url); + + cgiFormEncode(urlptr, var, urlend - urlptr); + urlptr += strlen(urlptr); + + strlcpy(urlptr, "&", urlend - urlptr); + urlptr += strlen(urlptr); + } + else + { + strlcpy(url, "/jobs/?", sizeof(url)); + urlptr = url + strlen(url); + } + + if (which_jobs) + { + strlcpy(urlptr, "WHICH_JOBS=", urlend - urlptr); + urlptr += strlen(urlptr); + + cgiFormEncode(urlptr, which_jobs, urlend - urlptr); + urlptr += strlen(urlptr); + + strlcpy(urlptr, "&", urlend - urlptr); + urlptr += strlen(urlptr); + } + + snprintf(urlptr, urlend - urlptr, "FIRST=%d", first); + cgiSetVariable("THISURL", url); + + if (first > 0) + { + snprintf(urlptr, urlend - urlptr, "FIRST=%d&ORDER=%s", + first - CUPS_PAGE_MAX, ascending ? "asc" : "dec"); + cgiSetVariable("PREVURL", url); + } + + if ((first + CUPS_PAGE_MAX) < count) + { + snprintf(urlptr, urlend - urlptr, "FIRST=%d&ORDER=%s", + first + CUPS_PAGE_MAX, ascending ? "asc" : "dec"); + cgiSetVariable("NEXTURL", url); + } + + /* + * Then show everything... + */ + + if (!dest) + cgiCopyTemplateLang("search.tmpl"); + + cgiCopyTemplateLang("jobs-header.tmpl"); + + if (count > CUPS_PAGE_MAX) + cgiCopyTemplateLang("page.tmpl"); + + cgiCopyTemplateLang("jobs.tmpl"); + + if (count > CUPS_PAGE_MAX) + cgiCopyTemplateLang("page.tmpl"); + + ippDelete(response); + } +} + + + +/* + * End of "$Id: ipp-var.c 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/jobs.c b/cgi-bin/jobs.c new file mode 100644 index 000000000..648d38150 --- /dev/null +++ b/cgi-bin/jobs.c @@ -0,0 +1,238 @@ +/* + * "$Id: jobs.c 4921 2006-01-12 21:26:26Z mike $" + * + * Job status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + * do_job_op() - Do a job operation. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.h" + + +/* + * Local functions... + */ + +static void do_job_op(http_t *http, cups_lang_t *language, ipp_op_t op); + + +/* + * '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 any form variables... + */ + + cgiInitialize(); + + /* + * Set the web interface section... + */ + + cgiSetVariable("SECTION", "jobs"); + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Connect to the HTTP server... + */ + + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + /* + * Tell the client to expect UTF-8 encoded HTML... + */ + + puts("Content-Type: text/html;charset=utf-8\n"); + + /* + * Send a standard header... + */ + + cgiSetVariable("TITLE", _cupsLangString(language, _("Jobs"))); + + cgiSetServerVersion(); + + cgiCopyTemplateLang("header.tmpl"); + + if ((op = cgiGetVariable("OP")) != NULL) + { + /* + * Do the operation... + */ + + if (!strcmp(op, "cancel-job")) + do_job_op(http, language, IPP_CANCEL_JOB); + else if (!strcmp(op, "hold-job")) + do_job_op(http, language, IPP_HOLD_JOB); + else if (!strcmp(op, "release-job")) + do_job_op(http, language, IPP_RELEASE_JOB); + else if (!strcmp(op, "restart-job")) + do_job_op(http, language, IPP_RESTART_JOB); + else + { + /* + * Bad operation code... Display an error... + */ + + cgiCopyTemplateLang("job-op.tmpl"); + } + } + else + { + /* + * Show a list of jobs... + */ + + cgiShowJobs(http, NULL); + } + + cgiCopyTemplateLang("trailer.tmpl"); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * '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 */ + ipp_status_t status; /* Operation status... */ + + + if ((job = cgiGetVariable("JOB_ID")) != NULL) + snprintf(uri, sizeof(uri), "ipp://localhost/jobs/%s", job); + else + { + cgiSetVariable("ERROR", ippErrorString(IPP_NOT_FOUND)); + cgiCopyTemplateLang("error.tmpl"); + return; + } + + /* + * Build a job request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * job-uri or printer-uri (purge-jobs) + * requesting-user-name + */ + + request = ippNew(); + + request->request.op.operation_id = op; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "job-uri", + NULL, uri); + + if (getenv("REMOTE_USER") != NULL) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + + if (strcmp(getenv("REMOTE_USER"), "root")) + ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); + } + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, "unknown"); + + /* + * 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 = cupsLastError(); + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else if (op == IPP_CANCEL_JOB) + cgiCopyTemplateLang("job-cancel.tmpl"); + else if (op == IPP_HOLD_JOB) + cgiCopyTemplateLang("job-hold.tmpl"); + else if (op == IPP_RELEASE_JOB) + cgiCopyTemplateLang("job-release.tmpl"); + else if (op == IPP_RESTART_JOB) + cgiCopyTemplateLang("job-restart.tmpl"); +} + + +/* + * End of "$Id: jobs.c 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/multipart.dat b/cgi-bin/multipart.dat new file mode 100644 index 0000000000000000000000000000000000000000..91c5bb5b4c0e039c6692bc116be57983b836be68 GIT binary patch literal 50411 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 literal 0 Hc-jL100001 diff --git a/cgi-bin/printers.c b/cgi-bin/printers.c new file mode 100644 index 000000000..25bb7ea70 --- /dev/null +++ b/cgi-bin/printers.c @@ -0,0 +1,434 @@ +/* + * "$Id: printers.c 4921 2006-01-12 21:26:26Z mike $" + * + * Printer status CGI for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for CGI. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.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 */ + char refresh[1024]; /* Refresh URL */ + static const char *def_attrs[] = /* Attributes for default printer */ + { + "printer-name", + "printer-uri-supported" + }; + + + /* + * Get any form variables... + */ + + cgiInitialize(); + op = cgiGetVariable("OP"); + + /* + * Get the request language... + */ + + language = cupsLangDefault(); + + /* + * Set the web interface section... + */ + + cgiSetVariable("SECTION", "printers"); + + /* + * Connect to the HTTP server... + */ + + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + /* + * Tell the client to expect UTF-8 encoded HTML... + */ + + puts("Content-Type: text/html;charset=utf-8\n"); + + /* + * See if we need to show a list of printers or the status of a + * single printer... + */ + + cgiSetServerVersion(); + + printer = argv[0]; + if (strcmp(printer, "/") == 0 || strstr(printer, "printers.cgi") != NULL) + { + printer = NULL; + cgiSetVariable("TITLE", _cupsLangString(language, _("Printer"))); + } + else + cgiSetVariable("TITLE", printer); + + 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); + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", + sizeof(def_attrs) / sizeof(def_attrs[0]), NULL, def_attrs); + + 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 url[HTTP_MAX_URI]; /* New URL */ + + + cgiSetVariable("DEFAULT_URI", + cgiRewriteURL(attr->values[0].string.text, + url, sizeof(url), NULL)); + } + + 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; + + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, + "printer-type", 0); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, + "printer-type-mask", CUPS_PRINTER_CLASS); + + if (getenv("REMOTE_USER") != NULL) + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + } + 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; + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, + uri); + } + + cgiGetAttributes(request, "printers.tmpl"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + /* + * Got the result; set the CGI variables and check the status of a + * single-queue request... + */ + + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + if (printer && (attr = ippFindAttribute(response, "printer-state", + IPP_TAG_ENUM)) != NULL && + attr->values[0].integer == IPP_PRINTER_PROCESSING) + { + /* + * Printer is processing - automatically refresh the page until we + * are done printing... + */ + + cgiFormEncode(uri, printer, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "10;/printers/%s", uri); + cgiSetVariable("refresh_page", refresh); + } + + /* + * Delete the response... + */ + + ippDelete(response); + } + else if (printer) + fprintf(stderr, "ERROR: Get-Printer-Attributes request failed - %s (%x)\n", + ippErrorString(cupsLastError()), cupsLastError()); + else + fprintf(stderr, "ERROR: CUPS-Get-Printers request failed - %s (%x)\n", + ippErrorString(cupsLastError()), cupsLastError()); + + /* + * Show the standard header... + */ + + cgiCopyTemplateLang("header.tmpl"); + + /* + * Write the report... + */ + + cgiCopyTemplateLang("printers.tmpl"); + + /* + * Get jobs for the specified printer if a printer has been chosen... + */ + + if (printer != NULL) + { + /* + * Build an IPP_GET_JOBS request, which requires the following + * attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + */ + + request = ippNew(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", 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); + + if (getenv("REMOTE_USER") != NULL) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, getenv("REMOTE_USER")); + + if (strcmp(getenv("REMOTE_USER"), "root")) + ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); + } + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, "unknown"); + + cgiGetAttributes(request, "jobs.tmpl"); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + ippDelete(response); + + cgiCopyTemplateLang("jobs.tmpl"); + } + else + fprintf(stderr, "ERROR: Get-Jobs request failed - %s (%x)\n", + ippErrorString(cupsLastError()), cupsLastError()); + } + } + else + { + /* + * Print a test page... + */ + + char filename[1024]; /* Test page filename */ + const char *datadir; /* CUPS_DATADIR env var */ + + + cgiFormEncode(uri, printer, sizeof(uri)); + snprintf(refresh, sizeof(refresh), "2;/printers/%s", uri); + cgiSetVariable("refresh_page", refresh); + + if ((datadir = getenv("CUPS_DATADIR")) == NULL) + datadir = CUPS_DATADIR; + + snprintf(filename, sizeof(filename), "%s/data/testprint.ps", datadir); + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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, + filename)) != NULL) + { + status = response->request.status.status_code; + cgiSetIPPVars(response, NULL, NULL, NULL, 0); + + ippDelete(response); + } + else + status = cupsLastError(); + + cgiSetVariable("PRINTER_NAME", printer); + + /* + * Show the standard header... + */ + + cgiCopyTemplateLang("header.tmpl"); + + /* + * Show the result... + */ + + if (status > IPP_OK_CONFLICT) + { + cgiSetVariable("ERROR", ippErrorString(status)); + cgiCopyTemplateLang("error.tmpl"); + } + else + cgiCopyTemplateLang("test-page.tmpl"); + } + + cgiCopyTemplateLang("trailer.tmpl"); + + /* + * Close the HTTP server connection... + */ + + httpClose(http); + cupsLangFree(language); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id: printers.c 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/search.c b/cgi-bin/search.c new file mode 100644 index 000000000..4f1ea072a --- /dev/null +++ b/cgi-bin/search.c @@ -0,0 +1,368 @@ +/* + * "$Id: search.c 4859 2005-11-30 23:45:24Z mike $" + * + * Search routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cgiCompileSearch() - Compile a search string. + * cgiDoSearch() - Do a search of some text. + * cgiFreeSearch() - Free a compiled search context. + */ + +/* + * Include necessary headers... + */ + +#include "cgi-private.h" +#include <regex.h> + + +/* + * 'cgiCompileSearch()' - Compile a search string. + */ + +void * /* O - Search context */ +cgiCompileSearch(const char *query) /* I - Query string */ +{ + regex_t *re; /* Regular expression */ + char *s, /* Regular expression string */ + *sptr, /* Pointer into RE string */ + *sword; /* Pointer to start of word */ + int slen; /* Allocated size of RE string */ + const char *qptr, /* Pointer into query string */ + *qend; /* End of current word */ + const char *prefix; /* Prefix to add to next word */ + int quoted; /* Word is quoted */ + int wlen; /* Word length */ + char *lword; /* Last word in query */ + + + DEBUG_printf(("help_compile_search(query=\"%s\")\n", query ? query : "(nil)")); + + /* + * Allocate a regular expression storage structure... + */ + + re = (regex_t *)calloc(1, sizeof(regex_t)); + + /* + * Allocate a buffer to hold the regular expression string, starting + * at 1024 bytes or 3 times the length of the query string, whichever + * is greater. We'll expand the string as needed... + */ + + slen = strlen(query) * 3; + if (slen < 1024) + slen = 1024; + + s = (char *)malloc(slen); + + /* + * Copy the query string to the regular expression, handling basic + * AND and OR logic... + */ + + prefix = ".*"; + qptr = query; + sptr = s; + lword = NULL; + + while (*qptr) + { + /* + * Skip leading whitespace... + */ + + while (isspace(*qptr & 255)) + qptr ++; + + if (!*qptr) + break; + + /* + * Find the end of the current word... + */ + + if (*qptr == '\"' || *qptr == '\'') + { + /* + * Scan quoted string... + */ + + quoted = *qptr ++; + for (qend = qptr; *qend && *qend != quoted; qend ++); + + if (!*qend) + { + /* + * No closing quote, error out! + */ + + free(s); + free(re); + + if (lword) + free(lword); + + return (NULL); + } + } + else + { + /* + * Scan whitespace-delimited string... + */ + + quoted = 0; + for (qend = qptr + 1; *qend && !isspace(*qend); qend ++); + } + + wlen = qend - qptr; + + /* + * Look for logic words: AND, OR + */ + + if (wlen == 3 && !strncasecmp(qptr, "AND", 3)) + { + /* + * Logical AND with the following text... + */ + + if (sptr > s) + prefix = ".*"; + + qptr = qend; + } + else if (wlen == 2 && !strncasecmp(qptr, "OR", 2)) + { + /* + * Logical OR with the following text... + */ + + if (sptr > s) + prefix = ".*|.*"; + + qptr = qend; + } + else + { + /* + * Add a search word, making sure we have enough room for the + * string + RE overhead... + */ + + wlen = (sptr - s) + 4 * wlen + 2 * strlen(prefix) + 4; + + if (wlen > slen) + { + /* + * Expand the RE string buffer... + */ + + char *temp; /* Temporary string pointer */ + + + slen = wlen + 128; + temp = (char *)realloc(s, slen); + if (!temp) + { + free(s); + free(re); + + if (lword) + free(lword); + + return (NULL); + } + + sptr = temp + (sptr - s); + s = temp; + } + + /* + * Add the prefix string... + */ + + strcpy(sptr, prefix); + sptr += strlen(sptr); + + /* + * Then quote the remaining word characters as needed for the + * RE... + */ + + sword = sptr; + + while (qptr < qend) + { + /* + * Quote: ^ . [ $ ( ) | * + ? { \ + */ + + if (strchr("^.[$()|*+?{\\", *qptr)) + *sptr++ = '\\'; + + *sptr++ = *qptr++; + } + + /* + * For "word1 AND word2", add reciprocal "word2 AND word1"... + */ + + if (!strcmp(prefix, ".*") && lword) + { + char *lword2; /* New "last word" */ + + + lword2 = strdup(sword); + + strcpy(sptr, ".*|.*"); + sptr += 5; + + strcpy(sptr, lword2); + sptr += strlen(sptr); + + strcpy(sptr, ".*"); + sptr += 2; + + strcpy(sptr, lword); + sptr += strlen(sptr); + + free(lword); + lword = lword2; + } + else + { + if (lword) + free(lword); + + lword = strdup(sword); + } + + prefix = ".*|.*"; + } + + /* + * Advance to the next string... + */ + + if (quoted) + qptr ++; + } + + if (lword) + free(lword); + + if (sptr > s) + strcpy(sptr, ".*"); + else + { + /* + * No query data, return NULL... + */ + + free(s); + free(re); + + return (NULL); + } + + /* + * Compile the regular expression... + */ + + DEBUG_printf((" s=\"%s\"\n", s)); + + if (regcomp(re, s, REG_EXTENDED | REG_ICASE)) + { + free(re); + free(s); + + return (NULL); + } + + /* + * Free the RE string and return the new regular expression we compiled... + */ + + free(s); + + return ((void *)re); +} + + +/* + * 'cgiDoSearch()' - Do a search of some text. + */ + +int /* O - Number of matches */ +cgiDoSearch(void *search, /* I - Search context */ + const char *text) /* I - Text to search */ +{ + int i; /* Looping var */ + regmatch_t matches[100]; /* RE matches */ + + + /* + * Range check... + */ + + if (!search || !text) + return (0); + + /* + * Do a lookup... + */ + + if (!regexec((regex_t *)search, text, sizeof(matches) / sizeof(matches[0]), + matches, 0)) + { + /* + * Figure out the number of matches in the string... + */ + + for (i = 0; i < (int)(sizeof(matches) / sizeof(matches[0])); i ++) + if (matches[i].rm_so < 0) + break; + + return (i); + } + else + return (0); +} + + +/* + * 'cgiFreeSearch()' - Free a compiled search context. + */ + +void +cgiFreeSearch(void *search) /* I - Search context */ +{ + regfree((regex_t *)search); +} + + +/* + * End of "$Id: search.c 4859 2005-11-30 23:45:24Z mike $". + */ diff --git a/cgi-bin/template.c b/cgi-bin/template.c new file mode 100644 index 000000000..dfcd1b85e --- /dev/null +++ b/cgi-bin/template.c @@ -0,0 +1,573 @@ +/* + * "$Id: template.c 4921 2006-01-12 21:26:26Z mike $" + * + * CGI template function. + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cgiCopyTemplateFile() - Copy a template file and replace all the + * '{variable}' strings with the variable value. + * cgiCopyTemplateLang() - Copy a template file using a language... + * cgiGetTemplateDir() - Get the templates directory... + * cgiSetServerVersion() - Set the server name and CUPS version... + * cgi_copy() - Copy the template file, substituting as needed... + * cgi_puts() - Put a string to the output file, quoting as + * needed... + */ + +#include "cgi-private.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(const char *tmpl) /* I - Base filename */ +{ + int i; /* Looping var */ + char filename[1024], /* Filename */ + locale[16]; /* Locale name */ + const char *directory, /* Directory for templates */ + *lang; /* Language */ + FILE *in; /* Input file */ + + + /* + * Convert the language to a locale name... + */ + + if ((lang = getenv("LANG")) != NULL) + { + for (i = 0; lang[i] && i < 15; i ++) + if (isalnum(lang[i] & 255)) + 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... + */ + + directory = cgiGetTemplateDir(); + + 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(stdout, in, 0, 0); + + /* + * Close the template file and return... + */ + + fclose(in); +} + + +/* + * 'cgiGetTemplateDir()' - Get the templates directory... + */ + +char * /* O - Template directory */ +cgiGetTemplateDir(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); +} + + +/* + * 'cgiSetServerVersion()' - Set the server name and CUPS version... + */ + +void +cgiSetServerVersion(void) +{ + cgiSetVariable("SERVER_NAME", getenv("SERVER_NAME")); + cgiSetVariable("REMOTE_USER", getenv("REMOTE_USER")); + cgiSetVariable("CUPS_VERSION", CUPS_SVERSION); + +#ifdef LC_TIME + setlocale(LC_TIME, ""); +#endif /* LC_TIME */ +} + + +/* + * '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 & 255)) + { + 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] & 255)) + { + *nameptr++ = '\0'; + + if ((value = cgiGetArray(name + 1, atoi(nameptr) - 1)) != NULL) + outptr = value; + else + { + outval[0] = '\0'; + outptr = outval; + } + } + else 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] & 255)) + 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] & 255)) + { + *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 && outptr[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] & 255)) + { + *innerptr++ = '\0'; + if ((innerval = cgiGetArray(innername, atoi(innerptr) - 1)) == NULL) + *s = '\0'; + else + strlcpy(s, innerval, sizeof(compare) - (s - compare)); + } + else if (innername[0] == '?') + { + if ((innerval = cgiGetArray(innername + 1, element)) == NULL) + *s = '\0'; + else + strlcpy(s, innerval, sizeof(compare) - (s - compare)); + } + else if ((innerval = cgiGetArray(innername, element)) == NULL) + snprintf(s, sizeof(compare) - (s - compare), "{%s}", innername); + else + strlcpy(s, innerval, sizeof(compare) - (s - compare)); + + 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, /* I - String to output */ + FILE *out) /* I - Output file */ +{ + while (*s) + { + if (*s == '<') + { + /* + * Pass <A HREF="url"> and </A>, otherwise quote it... + */ + + if (!strncasecmp(s, "<A HREF=\"", 9)) + { + fputs("<A HREF=\"", out); + s += 9; + + while (*s && *s != '\"') + { + if (*s == '&') + fputs("&", out); + else + putc(*s, out); + + s ++; + } + + if (*s) + s ++; + + fputs("\">", out); + } + else if (!strncasecmp(s, "</A>", 4)) + { + fputs("</A>", out); + s += 3; + } + else + fputs("<", out); + } + else if (*s == '>') + fputs(">", out); + else if (*s == '\"') + fputs(""", out); + else if (*s == '&') + fputs("&", out); + else + putc(*s, out); + + s ++; + } +} + + +/* + * End of "$Id: template.c 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cgi-bin/testcgi.c b/cgi-bin/testcgi.c new file mode 100644 index 000000000..e9300af87 --- /dev/null +++ b/cgi-bin/testcgi.c @@ -0,0 +1,84 @@ +/* + * "$Id: testcgi.c 4869 2005-12-06 02:43:40Z mike $" + * + * CGI test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Test the help index code. + * list_nodes() - List nodes in an array... + */ + +/* + * Include necessary headers... + */ + +#include "cgi.h" + + +/* + * 'main()' - Test the CGI code. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + /* + * Test file upload/multi-part submissions... + */ + + freopen("multipart.dat", "rb", stdin); + + putenv("CONTENT_TYPE=multipart/form-data; " + "boundary=---------------------------1977426492562745908748943111"); + putenv("REQUEST_METHOD=POST"); + + printf("cgiInitialize: "); + if (cgiInitialize()) + { + const cgi_file_t *file; /* Upload file */ + + if ((file = cgiGetFile()) != NULL) + { + puts("PASS"); + printf(" tempfile=\"%s\"\n", file->tempfile); + printf(" name=\"%s\"\n", file->name); + printf(" filename=\"%s\"\n", file->filename); + printf(" mimetype=\"%s\"\n", file->mimetype); + } + else + puts("FAIL (no file!)"); + } + else + puts("FAIL (init)"); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * End of "$Id: testcgi.c 4869 2005-12-06 02:43:40Z mike $". + */ diff --git a/cgi-bin/testhi.c b/cgi-bin/testhi.c new file mode 100644 index 000000000..99d0bd29f --- /dev/null +++ b/cgi-bin/testhi.c @@ -0,0 +1,116 @@ +/* + * "$Id: testhi.c 4869 2005-12-06 02:43:40Z mike $" + * + * Help index test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Test the help index code. + * list_nodes() - List nodes in an array... + */ + +/* + * Include necessary headers... + */ + +#include "cgi.h" + + +/* + * Local functions... + */ + +static void list_nodes(const char *title, int num_nodes, help_node_t **nodes); + + +/* + * 'main()' - Test the help index code. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + help_index_t *hi, /* Help index */ + *search; /* Search index */ + + + /* + * Load the help index... + */ + + hi = helpLoadIndex("testhi.index", "."); + + list_nodes("nodes", hi->num_nodes, hi->nodes); + list_nodes("sorted", hi->num_nodes, hi->sorted); + + /* + * Do any searches... + */ + + if (argc > 1) + { + search = helpSearchIndex(hi, argv[1], NULL, argv[2]); + + if (search) + { + list_nodes(argv[1], search->num_nodes, search->sorted); + helpDeleteIndex(search); + } + else + printf("%s (0 nodes)\n", argv[1]); + } + + helpDeleteIndex(hi); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'list_nodes()' - List nodes in an array... + */ + +static void +list_nodes(const char *title, /* I - Title string */ + int num_nodes, /* I - Number of nodes */ + help_node_t **nodes) /* I - Nodes */ +{ + int i; /* Looping var */ + + + printf("%s (%d nodes):\n", title, num_nodes); + for (i = 0; i < num_nodes; i ++) + if (nodes[i]->anchor) + printf(" %d: %s#%s \"%s\"\n", i, nodes[i]->filename, nodes[i]->anchor, + nodes[i]->text); + else + printf(" %d: %s \"%s\"\n", i, nodes[i]->filename, nodes[i]->text); +} + + +/* + * End of "$Id: testhi.c 4869 2005-12-06 02:43:40Z mike $". + */ diff --git a/cgi-bin/testhi.html b/cgi-bin/testhi.html new file mode 100644 index 000000000..747b5ea31 --- /dev/null +++ b/cgi-bin/testhi.html @@ -0,0 +1,29 @@ +<HTML> +<HEAD> + <TITLE>Test File for Help Index Code + + + +

This is a test file for the help index code. The help index +code reads plain HTML and indexes the title and any anchored +text, ignoring all other markup. Anchor tags must be on a single +line, although the text they wrap may cross multiple lines and be +up to 1024 bytes in length.

+ +

This is the First Anchor

+ +

This is some text for the first anchor.

+ + +

This is the Second Anchor

+ +

This is some text for the first anchor.

+ + +

This is the Third Anchor

+ +

This is some text for the third anchor. This +is an in-line anchor that crosses a line.

+ + + diff --git a/cgi-bin/var.c b/cgi-bin/var.c new file mode 100644 index 000000000..4a1a214a7 --- /dev/null +++ b/cgi-bin/var.c @@ -0,0 +1,1024 @@ +/* + * "$Id: var.c 4869 2005-12-06 02:43:40Z mike $" + * + * CGI form variable and array functions. + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cgiCheckVariables() - Check for the presence of "required" variables. + * cgiGetArray() - Get an element from a form array... + * cgiGetFile() - Get the file (if any) that was submitted in the form. + * cgiGetSize() - Get the size of a form array value. + * cgiGetVariable() - Get a CGI variable from the database... + * cgiInitialize() - Initialize the CGI variable "database"... + * cgiIsPOST() - Determine whether this page was POSTed. + * cgiSetArray() - Set array element N to the specified string. + * cgiSetSize() - Set the array size. + * 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_multipart() - Initialize variables and file using the POST method. + * cgi_initialize_post() - Initialize variables using the POST method. + * cgi_initialize_string() - Initialize form variables from a string. + * cgi_passwd() - Catch authentication requests and notify the server. + * cgi_sort_variables() - Sort all form variables for faster lookup. + * cgi_unlink_file() - Remove the uploaded form. + */ + +/*#define DEBUG*/ +#include "cgi-private.h" +#include + + +/* + * Data structure to hold all the CGI form variables and arrays... + */ + +typedef struct /**** Form variable structure ****/ +{ + const char *name; /* Name of variable */ + int nvalues, /* Number of values */ + avalues; /* Number of values allocated */ + const char **values; /* Value(s) of variable */ +} _cgi_var_t; + + +/* + * Local globals... + */ + +static int form_count = 0, /* Form variable count */ + form_alloc = 0; /* Number of variables allocated */ +static _cgi_var_t *form_vars = NULL; + /* Form variables */ +static cgi_file_t *form_file = NULL; + /* Uploaded file */ + + +/* + * Local functions... + */ + +static void cgi_add_variable(const char *name, int element, + const char *value); +static int cgi_compare_variables(const _cgi_var_t *v1, + const _cgi_var_t *v2); +static _cgi_var_t *cgi_find_variable(const char *name); +static int cgi_initialize_get(void); +static int cgi_initialize_multipart(const char *boundary); +static int cgi_initialize_post(void); +static int cgi_initialize_string(const char *data); +static const char *cgi_passwd(const char *prompt); +static void cgi_sort_variables(void); +static void cgi_unlink_file(void); + + +/* + * '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) */ +{ + _cgi_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]); +} + + +/* + * 'cgiGetFile()' - Get the file (if any) that was submitted in the form. + */ + +const cgi_file_t * /* O - Attached file or NULL */ +cgiGetFile(void) +{ + return (form_file); +} + + +/* + * 'cgiGetSize()' - Get the size of a form array value. + */ + +int /* O - Number of elements */ +cgiGetSize(const char *name) /* I - Name of variable */ +{ + _cgi_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 _cgi_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]); +} + + +/* + * 'cgiInitialize()' - Initialize the CGI variable "database"... + */ + +int /* O - Non-zero if there was form data */ +cgiInitialize(void) +{ + const char *method; /* Form posting method */ + const char *content_type; /* Content-Type of post data */ + + + /* + * Setup a password callback for authentication... + */ + + cupsSetPasswordCB(cgi_passwd); + +#ifdef DEBUG + /* + * Disable output buffering to find bugs... + */ + + setbuf(stdout, NULL); + puts("Content-type: text/plain\n"); +#endif /* DEBUG */ + + /* + * Get the request method (GET or POST)... + */ + + method = getenv("REQUEST_METHOD"); + content_type = getenv("CONTENT_TYPE"); + if (!method) + return (0); + + /* + * Grab form data from the corresponding location... + */ + + if (!strcasecmp(method, "GET")) + return (cgi_initialize_get()); + else if (!strcasecmp(method, "POST") && content_type) + { + const char *boundary = strstr(content_type, "boundary="); + + if (boundary) + boundary += 9; + + if (content_type && !strncmp(content_type, "multipart/form-data; ", 21)) + return (cgi_initialize_multipart(boundary)); + else + return (cgi_initialize_post()); + } + else + return (0); +} + + +/* + * 'cgiIsPOST()' - Determine whether this page was POSTed. + */ + +int /* O - 1 if POST, 0 if GET */ +cgiIsPOST(void) +{ + const char *method; /* REQUEST_METHOD environment variable */ + + + if ((method = getenv("REQUEST_METHOD")) == NULL) + return (0); + else + return (!strcmp(method, "POST")); +} + + +/* + * '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 */ + _cgi_var_t *var; /* Returned variable */ + + + if (name == NULL || value == NULL || element < 0 || element > 100000) + 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 */ + _cgi_var_t *var; /* Returned variable */ + + + if (name == NULL || size < 0 || size > 100000) + 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 */ + _cgi_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 */ +{ + _cgi_var_t *var; /* New variable */ + + + if (name == NULL || value == NULL || element < 0 || element > 100000) + 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(_cgi_var_t) * 16); + else + form_vars = realloc(form_vars, (form_alloc + 16) * sizeof(_cgi_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 _cgi_var_t *v1, /* I - First variable */ + const _cgi_var_t *v2) /* I - Second variable */ +{ + return (strcasecmp(v1->name, v2->name)); +} + + +/* + * 'cgi_find_variable()' - Find a variable... + */ + +static _cgi_var_t * /* O - Variable pointer or NULL */ +cgi_find_variable(const char *name) /* I - Name of variable */ +{ + _cgi_var_t key; /* Search key */ + + + if (form_count < 1 || name == NULL) + return (NULL); + + key.name = name; + + return ((_cgi_var_t *)bsearch(&key, form_vars, form_count, sizeof(_cgi_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_multipart()' - Initialize variables and file using the POST method. + * + * TODO: Update to support files > 2GB. + */ + +static int /* O - 1 if form data was read */ +cgi_initialize_multipart( + const char *boundary) /* I - Boundary string */ +{ + char line[10240], /* MIME header line */ + name[1024], /* Form variable name */ + filename[1024], /* Form filename */ + mimetype[1024], /* MIME media type */ + bstring[256], /* Boundary string to look for */ + *ptr, /* Pointer into name/filename */ + *end; /* End of buffer */ + int ch, /* Character from file */ + fd, /* Temporary file descriptor */ + blen; /* Length of boundary string */ + + + DEBUG_printf(("cgi_initialize_multipart(boundary=\"%s\")\n", boundary)); + + /* + * Read multipart form data until we run out... + */ + + name[0] = '\0'; + filename[0] = '\0'; + mimetype[0] = '\0'; + + snprintf(bstring, sizeof(bstring), "\r\n--%s", boundary); + blen = strlen(bstring); + + while (fgets(line, sizeof(line), stdin)) + { + if (!strcmp(line, "\r\n")) + { + /* + * End of headers, grab value... + */ + + if (filename[0]) + { + /* + * Read an embedded file... + */ + + if (form_file) + { + /* + * Remove previous file... + */ + + cgi_unlink_file(); + } + + /* + * Allocate memory for the new file... + */ + + if ((form_file = calloc(1, sizeof(cgi_file_t))) == NULL) + return (0); + + form_file->name = strdup(name); + form_file->filename = strdup(filename); + form_file->mimetype = strdup(mimetype); + + fd = cupsTempFd(form_file->tempfile, sizeof(form_file->tempfile)); + + if (fd < 0) + return (0); + + atexit(cgi_unlink_file); + + /* + * Copy file data to the temp file... + */ + + ptr = line; + + while ((ch = getchar()) != EOF) + { + *ptr++ = ch; + + if ((ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen)) + { + ptr -= blen; + break; + } + + if ((ptr - line - blen) >= 8192) + { + /* + * Write out the first 8k of the buffer... + */ + + write(fd, line, 8192); + memmove(line, line + 8192, ptr - line - 8192); + ptr -= 8192; + } + } + + /* + * Write the rest of the data and close the temp file... + */ + + if (ptr > line) + write(fd, line, ptr - line); + + close(fd); + } + else + { + /* + * Just get a form variable; the current code only handles + * form values up to 10k in size... + */ + + ptr = line; + end = line + sizeof(line) - 1; + + while ((ch = getchar()) != EOF) + { + if (ptr < end) + *ptr++ = ch; + + if ((ptr - line) >= blen && !memcmp(ptr - blen, bstring, blen)) + { + ptr -= blen; + break; + } + } + + *ptr = '\0'; + + /* + * Set the form variable... + */ + + if ((ptr = strrchr(name, '-')) != NULL && isdigit(ptr[1] & 255)) + { + /* + * Set a specific index in the array... + */ + + *ptr++ = '\0'; + if (line[0]) + cgiSetArray(name, atoi(ptr) - 1, line); + } + else if (cgiGetVariable(name)) + { + /* + * Add another element in the array... + */ + + cgiSetArray(name, cgiGetSize(name), line); + } + else + { + /* + * Just set the line... + */ + + cgiSetVariable(name, line); + } + } + + /* + * Read the rest of the current line... + */ + + fgets(line, sizeof(line), stdin); + + /* + * Clear the state vars... + */ + + name[0] = '\0'; + filename[0] = '\0'; + mimetype[0] = '\0'; + } + else if (!strncasecmp(line, "Content-Disposition:", 20)) + { + if ((ptr = strstr(line + 20, " name=\"")) != NULL) + { + strlcpy(name, ptr + 7, sizeof(name)); + + if ((ptr = strchr(name, '\"')) != NULL) + *ptr = '\0'; + } + + if ((ptr = strstr(line + 20, " filename=\"")) != NULL) + { + strlcpy(filename, ptr + 11, sizeof(filename)); + + if ((ptr = strchr(filename, '\"')) != NULL) + *ptr = '\0'; + } + } + else if (!strncasecmp(line, "Content-Type:", 13)) + { + for (ptr = line + 13; isspace(*ptr & 255); ptr ++); + + strlcpy(mimetype, ptr, sizeof(mimetype)); + + for (ptr = mimetype + strlen(mimetype) - 1; + ptr > mimetype && isspace(*ptr & 255); + *ptr-- = '\0'); + } + } + + /* + * Return 1 for "form data found"... + */ + + return (1); +} + + +/* + * '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 /* O - 1 if form data was processed */ +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] & 255)) + { + *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_passwd()' - Catch authentication requests and notify the server. + * + * This function sends a Status header and exits, forcing authentication + * for this request. + */ + +static const char * /* O - NULL (no return) */ +cgi_passwd(const char *prompt) /* I - Prompt (not used) */ +{ + (void)prompt; + + fprintf(stderr, "DEBUG: cgi_passwd(prompt=\"%s\") called!\n", prompt); + + /* + * Send a 401 (unauthorized) status to the server, so it can notify + * the client that authentication is required. + */ + + puts("Status: 401\n"); + exit(0); + + /* + * This code is never executed, but is present to satisfy the compiler. + */ + + return (NULL); +} + + +/* + * '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(_cgi_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 */ +} + + +/* + * 'cgi_unlink_file()' - Remove the uploaded form. + */ + +static void +cgi_unlink_file(void) +{ + if (form_file) + { + /* + * Remove the temporary file... + */ + + unlink(form_file->tempfile); + + /* + * Free memory used... + */ + + free(form_file->name); + free(form_file->filename); + free(form_file->mimetype); + free(form_file); + + form_file = NULL; + } +} + + +/* + * End of "$Id: var.c 4869 2005-12-06 02:43:40Z mike $". + */ diff --git a/conf/Makefile b/conf/Makefile new file mode 100644 index 000000000..fe060d9c9 --- /dev/null +++ b/conf/Makefile @@ -0,0 +1,80 @@ +# +# "$Id: Makefile 4664 2005-09-17 22:56:56Z mike $" +# +# Configuration file makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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 + -if test x$(PAMDIR) != x$(BUILDROOT); then \ + $(INSTALL_DIR) $(PAMDIR); \ + if test -r $(PAMDIR)/cups/$(PAMFILE) ; then \ + $(INSTALL_DATA) $(PAMFILE) $(PAMDIR)/cups.N ; \ + else \ + $(INSTALL_DATA) $(PAMFILE) $(PAMDIR)/cups ; \ + fi ; \ + fi + + +# +# End of "$Id: Makefile 4664 2005-09-17 22:56:56Z mike $". +# diff --git a/conf/classes.conf b/conf/classes.conf new file mode 100644 index 000000000..408796883 --- /dev/null +++ b/conf/classes.conf @@ -0,0 +1,89 @@ +# +# "$Id: classes.conf 4494 2005-02-18 02:18:11Z mike $" +# +# Sample class configuration file for the Common UNIX Printing System +# (CUPS) scheduler. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is a sample class configuration file. This file is included # +# from the main configuration file (cups.conf) and lists all of the # +# printer classes known to the system. # +# # +######################################################################## + +# +# Each class starts with a definition. Class names +# can be up to 128 characters in length and are *not* case sensitive. +# +# One entry can appear in this file; if you don't +# define a default destination, the first printer or class becomes +# the default. +# + +# +# +# Info: the description for the class. +# + +#Info Acme LaserPrint 1000 Printers + +# +# Location: the location of the printer. +# + +#Location Room 101 in the activities building + +# +# State: sets the initial state of the class. Can be one of the +# following: +# +# Idle - Class is available to print new jobs. +# Stopped - Class is disabled but accepting new jobs. +# + +#State Idle + +# +# StateMessage: sets the printer-state-message attribute for the class. +# + +#StateMessage Class is idle. + +# +# Accepting: is the class accepting jobs? +# +#Accepting Yes +#Accepting No +# + +# +# Printer: adds a printer to the class. +# + +#Printer sample +#Printer sample@host2 +# + +# +# End of "$Id: classes.conf 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/conf/client.conf b/conf/client.conf new file mode 100644 index 000000000..dfe332165 --- /dev/null +++ b/conf/client.conf @@ -0,0 +1,67 @@ +# +# "$Id: client.conf 4494 2005-02-18 02:18:11Z mike $" +# +# Sample client configuration file for the Common UNIX Printing System +# (CUPS). +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# 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. ONLY ONE SERVER NAME MAY BE SPECIFIED AT A TIME. To use +# more than one server you must use a local scheduler with browsing +# and possibly polling. +# + +#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 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/conf/cupsd.conf.in b/conf/cupsd.conf.in new file mode 100644 index 000000000..e3b73ea7a --- /dev/null +++ b/conf/cupsd.conf.in @@ -0,0 +1,76 @@ +# +# "$Id: cupsd.conf.in 4817 2005-11-04 16:21:01Z mike $" +# +# Sample configuration file for the Common UNIX Printing System (CUPS) +# scheduler. See "man cupsd.conf" for a complete description of this +# file. +# + +# Log general information in error_log - change "info" to "debug" for +# troubleshooting... +LogLevel info + +# Administrator user group... +SystemGroup @CUPS_GROUP@ + +# Only listen for connections from the local machine. +Listen localhost:@DEFAULT_IPP_PORT@ +@CUPS_LISTEN_DOMAINSOCKET@ + +# Show shared printers on the local network. +Browsing On +BrowseOrder allow,deny +BrowseAllow @LOCAL + +# Default authentication type, when authentication is required... +DefaultAuthType Basic + +# Restrict access to the server... + + Order allow,deny + Allow localhost + + +# Restrict access to the admin pages... + + Order allow,deny + Allow localhost + + +# Restrict access to configuration files... + + AuthType Basic + Require user @SYSTEM + Order allow,deny + Allow localhost + + +# Set the default printer/job policies... + + # Job-related operations must be done by the owner or an adminstrator... + + Require user @OWNER @SYSTEM + Order deny,allow + + + # All administration operations require an adminstrator to authenticate... + + AuthType Basic + Require user @SYSTEM + Order deny,allow + + + # Only the owner or an administrator can cancel or authenticate a job... + + Require user @OWNER @SYSTEM + Order deny,allow + + + + Order deny,allow + + + +# +# End of "$Id: cupsd.conf.in 4817 2005-11-04 16:21:01Z mike $". +# diff --git a/conf/mime.convs b/conf/mime.convs new file mode 100644 index 000000000..b6c7004ba --- /dev/null +++ b/conf/mime.convs @@ -0,0 +1,119 @@ +# +# "$Id: mime.convs 4559 2005-08-04 18:40:13Z mike $" +# +# MIME converts file for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# +# 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 +application/x-cshell application/postscript 33 texttops +application/x-csource 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 +image/gif application/vnd.cups-postscript 66 imagetops +image/png application/vnd.cups-postscript 66 imagetops +image/jpeg application/vnd.cups-postscript 66 imagetops +image/tiff application/vnd.cups-postscript 66 imagetops +image/x-bitmap application/vnd.cups-postscript 66 imagetops +image/x-photocd application/vnd.cups-postscript 66 imagetops +image/x-portable-anymap application/vnd.cups-postscript 66 imagetops +image/x-portable-bitmap application/vnd.cups-postscript 66 imagetops +image/x-portable-graymap application/vnd.cups-postscript 66 imagetops +image/x-portable-pixmap application/vnd.cups-postscript 66 imagetops +image/x-sgi-rgb application/vnd.cups-postscript 66 imagetops +image/x-xbitmap application/vnd.cups-postscript 66 imagetops +image/x-xpixmap application/vnd.cups-postscript 66 imagetops +#image/x-xwindowdump application/vnd.cups-postscript 66 imagetops +image/x-sun-raster application/vnd.cups-postscript 66 imagetops + + +######################################################################## +# +# 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/gif application/vnd.cups-raster 100 imagetoraster +image/png application/vnd.cups-raster 100 imagetoraster +image/jpeg application/vnd.cups-raster 100 imagetoraster +image/tiff application/vnd.cups-raster 100 imagetoraster +image/x-bitmap application/vnd.cups-raster 100 imagetoraster +image/x-photocd application/vnd.cups-raster 100 imagetoraster +image/x-portable-anymap application/vnd.cups-raster 100 imagetoraster +image/x-portable-bitmap application/vnd.cups-raster 100 imagetoraster +image/x-portable-graymap application/vnd.cups-raster 100 imagetoraster +image/x-portable-pixmap application/vnd.cups-raster 100 imagetoraster +image/x-sgi-rgb application/vnd.cups-raster 100 imagetoraster +image/x-xbitmap application/vnd.cups-raster 100 imagetoraster +image/x-xpixmap application/vnd.cups-raster 100 imagetoraster +#image/x-xwindowdump application/vnd.cups-raster 100 imagetoraster +image/x-sun-raster application/vnd.cups-raster 100 imagetoraster + +# pstoraster is now part of ESP Ghostscript... +#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 4559 2005-08-04 18:40:13Z mike $". +# diff --git a/conf/mime.types b/conf/mime.types new file mode 100644 index 000000000..8d738aaed --- /dev/null +++ b/conf/mime.types @@ -0,0 +1,169 @@ +# +# "$Id: mime.types 4590 2005-08-24 19:25:49Z mike $" +# +# MIME types file for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# +# 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 +# istring(offset,"string") True if bytes are identical to +# case-insensitive 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 notation. +# + +######################################################################## +# +# Application-generated files... +# + +#application/msword doc string(0,) +application/pdf pdf string(0,%PDF) +application/postscript ai eps ps string(0,%!) string(0,<04>%!) \ + contains(0,128,<1B>%-12345X) + \ + (contains(0,1024,"LANGUAGE=POSTSCRIPT") \ + contains(0,1024,"LANGUAGE = Postscript") \ + contains(0,1024,"LANGUAGE = PostScript") \ + contains(0,1024,"LANGUAGE = POSTSCRIPT")) +application/vnd.hp-HPGL hpgl string(0,<1B>&)\ + string(0,<1B>E<1B>%0B) \ + string(0,<1B>%-1B) string(0,<201B>)\ + string(0,BP;) string(0,IN;) string(0,DF;) \ + string(0,BPINPS;) \ + (contains(0,128,<1B>%-12345X) + \ + (contains(0,1024,"LANGUAGE=HPGL") \ + contains(0,1024,"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,) &&\ + (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 string(4,<00000007>) +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) +image/x-icon ico + +######################################################################## +# +# Text files... +# + +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)) +application/x-csource c cxx cpp cc C h hpp \ + printable(0,1024) + \ + (string(0,/*) string(0,//) + string(0,#include) contains(0,1024,<0a>#include) \ + string(0,#define) contains(0,1024,<0a>#define)) +text/html html htm printable(0,1024) +\ + (istring(0,"") istring(0,"") +application/vnd.cups-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(0,1024,"LANGUAGE=PCL") \ + contains(0,1024,"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 4590 2005-08-24 19:25:49Z mike $". +# diff --git a/conf/pam.darwin b/conf/pam.darwin new file mode 100644 index 000000000..ff724da4d --- /dev/null +++ b/conf/pam.darwin @@ -0,0 +1,7 @@ +# cups: auth account password session +auth sufficient pam_securityserver.so +auth sufficient pam_unix.so +auth required pam_deny.so +account required pam_permit.so +password required pam_deny.so +session required pam_permit.so diff --git a/conf/pam.irix b/conf/pam.irix new file mode 100644 index 000000000..476383acb --- /dev/null +++ b/conf/pam.irix @@ -0,0 +1,3 @@ +#%PAM-1.0 +auth required pam_unix.so shadow nodelay nullok +account required pam_unix.so diff --git a/conf/pam.std.in b/conf/pam.std.in new file mode 100644 index 000000000..3ddcdd0d3 --- /dev/null +++ b/conf/pam.std.in @@ -0,0 +1,2 @@ +auth required @PAMMOD@ nullok shadow +account required @PAMMOD@ 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..3848459c9 --- /dev/null +++ b/conf/printers.conf @@ -0,0 +1,96 @@ +# +# "$Id: printers.conf 4494 2005-02-18 02:18:11Z mike $" +# +# Sample printer configuration file for the Common UNIX Printing System +# (CUPS) scheduler. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +######################################################################## +# # +# This is a sample printer configuration file. This file is included # +# from the main configuration file (cups.conf) and lists all of the # +# printers known to the system. # +# # +######################################################################## + +# +# Each printer starts with a definition. Printer names +# can be up to 128 characters in length and are *not* case sensitive. +# +# One entry can appear in this file; if you don't +# define a default destination, the first printer or class becomes the +# default. +# + +# +# +# Info: the description for the printer. +# + +#Info Acme LaserPrint 1000 + +# +# Location: the location of the printer. +# + +#Location Room 101 in the activities building + +# +# DeviceURI: the device URI for this printer. +# + +#DeviceURI parallel:/dev/plp +#DeviceURI serial:/dev/ttyd1?baud=38400+size=8+parity=none+flow=soft +#DeviceURI scsi:/dev/scsi/sc1d6l0 +#DeviceURI socket://hostname:port +#DeviceURI tftp://hostname/path +#DeviceURI ftp://hostname/path +#DeviceURI http://hostname[:port]/path +#DeviceURI ipp://hostname/path +#DeviceURI smb://hostname/printer + +# +# State: sets the initial state of the printer. Can be one of the +# following: +# +# Idle - Printer is available to print new jobs. +# Stopped - Printer is disabled but accepting new jobs. +# + +#State Idle + +# +# StateMessage: sets the printer-state-message attribute for the printer. +# + +#StateMessage Printer is idle. + +# +# Accepting: is the printer accepting jobs? +# +#Accepting Yes +#Accepting No + +# + +# +# End of "$Id: printers.conf 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/config-scripts/cups-common.m4 b/config-scripts/cups-common.m4 new file mode 100644 index 000000000..045991676 --- /dev/null +++ b/config-scripts/cups-common.m4 @@ -0,0 +1,197 @@ +dnl +dnl "$Id: cups-common.m4 4833 2005-11-12 21:46:52Z mike $" +dnl +dnl Common configuration stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +dnl EMail: cups-info@cups.org +dnl WWW: http://www.cups.org +dnl + +dnl We need at least autoconf 2.50... +AC_PREREQ(2.50) + +dnl Set the name of the config header file... +AC_CONFIG_HEADER(config.h) + +dnl Versio number information... +CUPS_VERSION="1.2svn" +AC_SUBST(CUPS_VERSION) +AC_DEFINE_UNQUOTED(CUPS_SVERSION, "CUPS v$CUPS_VERSION") +AC_DEFINE_UNQUOTED(CUPS_MINIMAL, "CUPS/$CUPS_VERSION") + +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(LN,ln) +AC_PATH_PROG(MV,mv) +AC_PATH_PROG(RM,rm) +AC_PATH_PROG(SED,sed) +AC_PATH_PROG(STRIP,strip) + +if test "x$AR" = x; then + AC_MSG_ERROR([Unable to find required library archive command.]) +fi +if test "x$CC" = x; then + AC_MSG_ERROR([Unable to find required C compiler command.]) +fi +if test "x$CXX" = x; then + AC_MSG_ERROR([Unable to find required C++ compiler command.]) +fi + +dnl Architecture checks... +AC_C_BIGENDIAN + +dnl Check for libraries... +AC_SEARCH_LIBS(crypt, crypt) +AC_SEARCH_LIBS(getspent, sec gen) + +LIBMALLOC="" +AC_ARG_ENABLE(mallinfo, [ --enable-mallinfo turn on malloc debug information, default=no]) + +if test x$enable_mallinfo = xyes; then + 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 +fi + +AC_SUBST(LIBMALLOC) + +dnl Check for libpaper support... +AC_ARG_ENABLE(libpaper, [ --enable-libpaper turn on libpaper support, default=no]) + +if test x$enable_libpaper = xyes; then + AC_CHECK_LIB(paper,systempapername, + AC_DEFINE(HAVE_LIBPAPER) + LIBPAPER="-lpaper", + LIBPAPER="") +else + LIBPAPER="" +fi +AC_SUBST(LIBPAPER) + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADER(crypt.h,AC_DEFINE(HAVE_CRYPT_H)) +AC_CHECK_HEADER(langinfo.h,AC_DEFINE(HAVE_LANGINFO_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(bstring.h,AC_DEFINE(HAVE_BSTRING_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 strlcat strlcpy) +if test "$uname" = "HP-UX" -a "$uversion" = "1020"; then + echo Forcing snprintf emulation for HP-UX. +else + AC_CHECK_FUNCS(snprintf vsnprintf) +fi + +dnl Checks for mkstemp and mkstemps functions. +AC_CHECK_FUNCS(mkstemp mkstemps) + +dnl Check for geteuid function. +AC_CHECK_FUNCS(geteuid) + +dnl Check for vsyslog function. +AC_CHECK_FUNCS(vsyslog) + +dnl Checks for signal functions. +case "$uname" in + Linux | GNU) + # Do not use sigset on Linux or GNU HURD + ;; + *) + # Use sigset on other platforms, if available + AC_CHECK_FUNCS(sigset) + ;; +esac + +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 ],[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 Extra platform-specific libraries... +case $uname in + Darwin*) + BACKLIBS="-framework IOKit" + LIBS="-framework CoreFoundation $LIBS" + ;; + *) + BACKLIBS="" + ;; +esac + +AC_SUBST(BACKLIBS) + +dnl New default port definition for IPP... +AC_ARG_WITH(ipp-port, [ --with-ipp-port set default port number for IPP ], + DEFAULT_IPP_PORT="$withval", + DEFAULT_IPP_PORT="631") + +AC_SUBST(DEFAULT_IPP_PORT) +AC_DEFINE_UNQUOTED(CUPS_DEFAULT_IPP_PORT,$DEFAULT_IPP_PORT) + +dnl +dnl End of "$Id: cups-common.m4 4833 2005-11-12 21:46:52Z mike $". +dnl diff --git a/config-scripts/cups-compiler.m4 b/config-scripts/cups-compiler.m4 new file mode 100644 index 000000000..f597e2773 --- /dev/null +++ b/config-scripts/cups-compiler.m4 @@ -0,0 +1,200 @@ +dnl +dnl "$Id: cups-compiler.m4 4915 2006-01-11 15:57:53Z mike $" +dnl +dnl Compiler stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2006 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 USA +dnl +dnl Voice: (301) 373-9600 +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... +CXXLIBS="" +AC_SUBST(CXXLIBS) + +if test -n "$GCC"; then + if test -z "$OPTIM"; then + if test "x$with_optim" = x; then + # Default to optimize-for-size and debug + OPTIM="-Os -g" + else + OPTIM="$with_optim $OPTIM" + fi + fi + + if test $PICFLAG = 1 -a $uname != AIX; then + OPTIM="-fPIC $OPTIM" + fi + + case $uname in + Darwin*) + if test "x$with_optim" = x; then + if test "x`uname -m`" = xi386; then + # Build universal binaries for OSX on Intel... + OPTIM="-arch i386 -arch ppc $OPTIM" + DSOFLAGS="-arch i386 -arch ppc $DSOFLAGS" + fi + fi + ;; + + Linux*) + AC_MSG_CHECKING(if GCC supports -fpie) + + OLDCFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -fpie" + AC_TRY_COMPILE(,, + OPTIM="$OPTIM -fpie" + LDFLAGS="$LDFLAGS -pie" + AC_MSG_RESULT(yes), + CFLAGS="$OLDCFLAGS" + AC_MSG_RESULT(no)) + ;; + esac + + if test "x$with_optim" = x; then + # Add useful warning options for tracking down problems... + OPTIM="-Wall -Wno-format-y2k $OPTIM" + # Additional warning options for alpha testing... + OPTIM="-Wshadow -Wunused $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 + # Show most warnings, but suppress the + # ones about arguments not being used, + # string constants assigned to const + # char *'s, etc. We only set the warning + # options on IRIX 6.2 and higher because + # of limitations in the older SGI compiler + # tools. + if test $uversion -ge 62; then + OPTIM="-fullwarn -woff 1183,1209,1349,3201 $OPTIM" + fi + 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 + # Specify "generic" SPARC output and suppress + # all of Sun's questionable warning messages... + OPTIM="-w $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 + +if test $uname = HP-UX; then + # HP-UX 10.20 (at least) needs this definition to get the + # h_errno global... + OPTIM="$OPTIM -D_XOPEN_SOURCE_EXTENDED" + + # HP-UX 11.00 (at least) needs this definition to get the + # u_short type used by the IP headers... + OPTIM="$OPTIM -D_INCLUDE_HPUX_SOURCE" +fi + +dnl +dnl End of "$Id: cups-compiler.m4 4915 2006-01-11 15:57:53Z mike $". +dnl diff --git a/config-scripts/cups-directories.m4 b/config-scripts/cups-directories.m4 new file mode 100644 index 000000000..9cbcc26aa --- /dev/null +++ b/config-scripts/cups-directories.m4 @@ -0,0 +1,279 @@ +dnl +dnl "$Id: cups-directories.m4 4873 2005-12-07 01:46:54Z mike $" +dnl +dnl Directory stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +dnl EMail: cups-info@cups.org +dnl WWW: http://www.cups.org +dnl + +AC_PREFIX_DEFAULT(/) + +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 "bindir" variable... +if test "$bindir" = "\${exec_prefix}/bin"; then + bindir="$exec_prefix/bin" +fi + +dnl Fix "sbindir" variable... +if test "$sbindir" = "\${exec_prefix}/sbin"; then + sbindir="$exec_prefix/sbin" +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 + if test "$uname" = Darwin; then + localstatedir="/private/var" + else + localstatedir="/var" + fi + 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 + if test "$uname" = Darwin; then + sysconfdir="/private/etc" + else + sysconfdir="/etc" + fi + else + sysconfdir="$prefix/etc" + fi +fi + +dnl Fix "libdir" variable for IRIX 6.x... +if test "$libdir" = "\${exec_prefix}/lib"; then + if test "$uname" = "IRIX" -a $uversion -ge 62; then + libdir="$exec_prefix/lib32" + else + libdir="$exec_prefix/lib" + fi +fi + +dnl Setup init.d locations... +AC_ARG_WITH(rcdir, [ --with-rcdir set path for rc scripts],rcdir="$withval",rcdir="") + +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... + INITDIR="" + INITDDIR="/System/Library/StartupItems/PrintingServices" + ;; + + Linux | GNU) + # Linux/HURD 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/init.d; then + # Others + INITDIR="/etc" + INITDDIR="../init.d" + else + # RedHat + INITDIR="/etc/rc.d" + 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... +# Cache data... +AC_ARG_WITH(cachedir, [ --with-cachedir set path for cache files],cachedir="$withval",cachedir="") + +if test x$cachedir = x; then + CUPS_CACHEDIR="$localstatedir/cache/cups" +else + CUPS_CACHEDIR="$cachedir" +fi +AC_DEFINE_UNQUOTED(CUPS_CACHEDIR, "$CUPS_CACHEDIR") +AC_SUBST(CUPS_CACHEDIR) + +# Data files +CUPS_DATADIR="$datadir/cups" +AC_DEFINE_UNQUOTED(CUPS_DATADIR, "$datadir/cups") +AC_SUBST(CUPS_DATADIR) + +# Documentation files +AC_ARG_WITH(docdir, [ --with-docdir set path for documentation],docdir="$withval",docdir="") + +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) + +# Fonts +AC_ARG_WITH(fontpath, [ --with-fontpath set font path for pstoraster],fontpath="$withval",fontpath="") + +if test "x$fontpath" = "x"; then + CUPS_FONTPATH="$datadir/cups/fonts" +else + CUPS_FONTPATH="$fontpath" +fi + +AC_SUBST(CUPS_FONTPATH) +AC_DEFINE_UNQUOTED(CUPS_FONTPATH, "$CUPS_FONTPATH") + +# Locale data +case "$uname" in + Linux | GNU | *BSD* | Darwin*) + CUPS_LOCALEDIR="$datadir/locale" + ;; + + OSF1* | AIX*) + CUPS_LOCALEDIR="$exec_prefix/lib/nls/msg" + ;; + + *) + # This is the standard System V location... + CUPS_LOCALEDIR="$exec_prefix/lib/locale" + ;; +esac + +AC_DEFINE_UNQUOTED(CUPS_LOCALEDIR, "$CUPS_LOCALEDIR") +AC_SUBST(CUPS_LOCALEDIR) + +# Log files... +AC_ARG_WITH(logdir, [ --with-logdir set path for log files],logdir="$withval",logdir="") + +if test x$logdir = x; then + CUPS_LOGDIR="$localstatedir/log/cups" + AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$localstatedir/log/cups") +else + CUPS_LOGDIR="$logdir" +fi +AC_DEFINE_UNQUOTED(CUPS_LOGDIR, "$CUPS_LOGDIR") +AC_SUBST(CUPS_LOGDIR) + +# Longer-term spool data +CUPS_REQUESTS="$localstatedir/spool/cups" +AC_DEFINE_UNQUOTED(CUPS_REQUESTS, "$localstatedir/spool/cups") +AC_SUBST(CUPS_REQUESTS) + +# Server executables... +case "$uname" in + *BSD* | Darwin*) + # *BSD and Darwin (MacOS X) + INSTALL_SYSV="" + CUPS_SERVERBIN="$exec_prefix/libexec/cups" + ;; + *) + # All others + INSTALL_SYSV="install-sysv" + CUPS_SERVERBIN="$libdir/cups" + ;; +esac + +AC_DEFINE_UNQUOTED(CUPS_SERVERBIN, "$CUPS_SERVERBIN") +AC_SUBST(CUPS_SERVERBIN) +AC_SUBST(INSTALL_SYSV) + +# Configuration files +CUPS_SERVERROOT="$sysconfdir/cups" +AC_DEFINE_UNQUOTED(CUPS_SERVERROOT, "$sysconfdir/cups") +AC_SUBST(CUPS_SERVERROOT) + +# Transient run-time state +CUPS_STATEDIR="$localstatedir/run/cups" +AC_DEFINE_UNQUOTED(CUPS_STATEDIR, "$localstatedir/run/cups") +AC_SUBST(CUPS_STATEDIR) + +dnl +dnl End of "$Id: cups-directories.m4 4873 2005-12-07 01:46:54Z mike $". +dnl diff --git a/config-scripts/cups-image.m4 b/config-scripts/cups-image.m4 new file mode 100644 index 000000000..940b0bbdd --- /dev/null +++ b/config-scripts/cups-image.m4 @@ -0,0 +1,98 @@ +dnl +dnl "$Id: cups-image.m4 4644 2005-09-15 18:43:06Z mike $" +dnl +dnl Image library stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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... +AC_ARG_ENABLE(jpeg, [ --enable-jpeg turn on JPEG support, default=yes]) +AC_ARG_ENABLE(png, [ --enable-png turn on PNG support, default=yes]) +AC_ARG_ENABLE(tiff, [ --enable-tiff turn on TIFF support, default=yes]) + +LIBJPEG="" +LIBPNG="" +LIBTIFF="" +LIBZ="" + +AC_SUBST(LIBJPEG) +AC_SUBST(LIBPNG) +AC_SUBST(LIBTIFF) +AC_SUBST(LIBZ) + +if test x$enable_jpeg != xno; then + AC_CHECK_HEADER(jpeglib.h, + AC_CHECK_LIB(jpeg, jpeg_destroy_decompress, + AC_DEFINE(HAVE_LIBJPEG) + LIBJPEG="-ljpeg" + LIBS="$LIBS -ljpeg")) +else + AC_MSG_NOTICE([JPEG support disabled with --disable-jpeg.]) +fi + +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) + +if test x$enable_png != xno; then + AC_CHECK_HEADER(png.h, + AC_CHECK_LIB(png, png_set_tRNS_to_alpha, + AC_DEFINE(HAVE_LIBPNG) + LIBPNG="-lpng -lm")) +else + AC_MSG_NOTICE([PNG support disabled with --disable-png.]) +fi + +if test x$enable_tiff != xno; then + AC_CHECK_HEADER(tiff.h, + AC_CHECK_LIB(tiff, TIFFReadScanline, + AC_DEFINE(HAVE_LIBTIFF) + LIBTIFF="-ltiff")) +else + AC_MSG_NOTICE([TIFF support disabled with --disable-tiff.]) +fi + +dnl Restore original LIBS settings... +LIBS="$SAVELIBS" + +EXPORT_LIBJPEG="$LIBJPEG" +EXPORT_LIBPNG="$LIBPNG" +EXPORT_LIBTIFF="$LIBTIFF" +EXPORT_LIBZ="$LIBZ" + +AC_SUBST(EXPORT_LIBJPEG) +AC_SUBST(EXPORT_LIBPNG) +AC_SUBST(EXPORT_LIBTIFF) +AC_SUBST(EXPORT_LIBZ) + +AC_CHECK_HEADER(stdlib.h,AC_DEFINE(HAVE_STDLIB_H)) + +dnl +dnl End of "$Id: cups-image.m4 4644 2005-09-15 18:43:06Z mike $". +dnl diff --git a/config-scripts/cups-largefile.m4 b/config-scripts/cups-largefile.m4 new file mode 100644 index 000000000..25400ce2d --- /dev/null +++ b/config-scripts/cups-largefile.m4 @@ -0,0 +1,61 @@ +dnl +dnl "$Id: cups-largefile.m4 4732 2005-09-30 23:23:25Z mike $" +dnl +dnl Large file support stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +dnl EMail: cups-info@cups.org +dnl WWW: http://www.cups.org +dnl + +dnl Check for largefile support... +AC_SYS_LARGEFILE + +dnl Define largefile options as needed... +LARGEFILE="" +if test x$enable_largefile != xno; then + LARGEFILE="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE" + + if test $ac_cv_sys_large_files = 1; then + LARGEFILE="$LARGEFILE -D_LARGE_FILES" + fi + + if test $ac_cv_sys_file_offset_bits = 64; then + LARGEFILE="$LARGEFILE -D_FILE_OFFSET_BITS=64" + fi +fi +AC_SUBST(LARGEFILE) + +dnl Check for "long long" support... +AC_CACHE_CHECK(for long long int, ac_cv_c_long_long, + [if test "$GCC" = yes; then + ac_cv_c_long_long=yes + else + AC_TRY_COMPILE(,[long long int i;], + ac_cv_c_long_long=yes, + ac_cv_c_long_long=no) + fi]) + +if test $ac_cv_c_long_long = yes; then + AC_DEFINE(HAVE_LONG_LONG) +fi + +AC_CHECK_FUNC(strtoll, AC_DEFINE(HAVE_STRTOLL)) + +dnl +dnl End of "$Id: cups-largefile.m4 4732 2005-09-30 23:23:25Z mike $". +dnl diff --git a/config-scripts/cups-libtool.m4 b/config-scripts/cups-libtool.m4 new file mode 100644 index 000000000..0d8673c79 --- /dev/null +++ b/config-scripts/cups-libtool.m4 @@ -0,0 +1,49 @@ +dnl +dnl "$Id: cups-libtool.m4 4494 2005-02-18 02:18:11Z mike $" +dnl +dnl Libtool stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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 4494 2005-02-18 02:18:11Z mike $". +dnl diff --git a/config-scripts/cups-manpages.m4 b/config-scripts/cups-manpages.m4 new file mode 100644 index 000000000..6a887d13d --- /dev/null +++ b/config-scripts/cups-manpages.m4 @@ -0,0 +1,101 @@ +dnl +dnl "$Id: cups-manpages.m4 4833 2005-11-12 21:46:52Z mike $" +dnl +dnl Manpage stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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 | GNU | *BSD* | AIX*) + # Darwin, MacOS X, Linux, GNU HURD, *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 + MAN1EXT=1 + MAN5EXT=5 + MAN8EXT=8 + MAN8DIR=8 + ;; + IRIX*) + # SGI IRIX + MAN1EXT=1 + MAN5EXT=5 + MAN8EXT=1m + MAN8DIR=1 + ;; + SunOS* | HP-UX*) + # Solaris and HP-UX + MAN1EXT=1 + MAN5EXT=5 + MAN8EXT=1m + MAN8DIR=1m + ;; + Linux* | GNU*) + # Linux and GNU Hurd + MAN1EXT=1.gz + MAN5EXT=5.gz + MAN8EXT=8.gz + MAN8DIR=8 + ;; + *) + # All others + MAN1EXT=1 + MAN5EXT=5 + MAN8EXT=8 + MAN8DIR=8 + ;; +esac + +AC_SUBST(MAN1EXT) +AC_SUBST(MAN5EXT) +AC_SUBST(MAN8EXT) +AC_SUBST(MAN8DIR) + +dnl +dnl End of "$Id: cups-manpages.m4 4833 2005-11-12 21:46:52Z mike $". +dnl diff --git a/config-scripts/cups-network.m4 b/config-scripts/cups-network.m4 new file mode 100644 index 000000000..e5abc8ba9 --- /dev/null +++ b/config-scripts/cups-network.m4 @@ -0,0 +1,89 @@ +dnl +dnl "$Id: cups-network.m4 4873 2005-12-07 01:46:54Z mike $" +dnl +dnl Networking stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +dnl EMail: cups-info@cups.org +dnl WWW: http://www.cups.org +dnl + +AC_SEARCH_LIBS(socket, socket) +AC_SEARCH_LIBS(gethostbyaddr, nsl) +AC_SEARCH_LIBS(getaddrinfo, nsl, AC_DEFINE(HAVE_GETADDRINFO)) +AC_SEARCH_LIBS(getifaddrs, nsl, AC_DEFINE(HAVE_GETIFADDRS)) +AC_SEARCH_LIBS(getnameinfo, nsl, AC_DEFINE(HAVE_GETNAMEINFO)) +AC_SEARCH_LIBS(hstrerror, nsl socket resolv, AC_DEFINE(HAVE_HSTRERROR)) +AC_SEARCH_LIBS(rresvport_af, nsl, AC_DEFINE(HAVE_RRESVPORT_AF)) + +AC_CHECK_MEMBER(struct sockaddr.sa_len,,, [#include ]) +AC_CHECK_HEADER(sys/sockio.h, AC_DEFINE(HAVE_SYS_SOCKIO_H)) + +if test "$uname" = "SunOS"; then + case "$uversion" in + 55* | 56*) + maxfiles=1024 + ;; + *) + maxfiles=4096 + ;; + esac +else + maxfiles=4096 +fi + +AC_ARG_WITH(maxfiles, [ --with-maxfiles=N set maximum number of file descriptors for scheduler ], + maxfiles=$withval) + +AC_DEFINE_UNQUOTED(CUPS_MAX_FDS, $maxfiles) + +CUPS_DEFAULT_DOMAINSOCKET="" + +dnl Domain socket support... +AC_ARG_WITH(domainsocket, [ --with-domainsocket set unix domain socket name], + default_domainsocket="$withval", + default_domainsocket="") + +if test x$enable_domainsocket != xno -a x$default_domainsocket != xno; then + if test "x$default_domainsocket" = x; then + case "$uname" in + Darwin*) + # Darwin and MaxOS X do their own thing... + CUPS_DEFAULT_DOMAINSOCKET="$localstatedir/run/cupsd" + ;; + *) + # All others use FHS standard... + CUPS_DEFAULT_DOMAINSOCKET="$CUPS_STATEDIR/cups.sock" + ;; + esac + else + CUPS_DEFAULT_DOMAINSOCKET="$default_domainsocket" + fi + + CUPS_LISTEN_DOMAINSOCKET="Listen $CUPS_DEFAULT_DOMAINSOCKET" + + AC_DEFINE_UNQUOTED(CUPS_DEFAULT_DOMAINSOCKET, "$CUPS_DEFAULT_DOMAINSOCKET") +else + CUPS_LISTEN_DOMAINSOCKET="" +fi + +AC_SUBST(CUPS_DEFAULT_DOMAINSOCKET) +AC_SUBST(CUPS_LISTEN_DOMAINSOCKET) + +dnl +dnl End of "$Id: cups-network.m4 4873 2005-12-07 01:46:54Z mike $". +dnl diff --git a/config-scripts/cups-opsys.m4 b/config-scripts/cups-opsys.m4 new file mode 100644 index 000000000..5b2b1502c --- /dev/null +++ b/config-scripts/cups-opsys.m4 @@ -0,0 +1,99 @@ +dnl +dnl "$Id: cups-opsys.m4 4833 2005-11-12 21:46:52Z mike $" +dnl +dnl Operating system stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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'` +case "$uname" in + GNU* | GNU/*) + uname="GNU" + ;; + IRIX*) + uname="IRIX" + ;; + Linux*) + uname="Linux" + ;; +esac + +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 -f /etc/group; then + if test x$uname = xDarwin; then + GROUP_LIST="lp admin" + else + GROUP_LIST="lpadmin sys system root" + fi + + CUPS_GROUP="" + for group in $GROUP_LIST; 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) + +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 4833 2005-11-12 21:46:52Z mike $" +dnl diff --git a/config-scripts/cups-pam.m4 b/config-scripts/cups-pam.m4 new file mode 100644 index 000000000..c86ae292e --- /dev/null +++ b/config-scripts/cups-pam.m4 @@ -0,0 +1,98 @@ +dnl +dnl "$Id: cups-pam.m4 4913 2006-01-11 01:42:04Z mike $" +dnl +dnl PAM stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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="" +PAMFILE="" +PAMLIBS="" +PAMMOD="pam_unknown.so" + +if test x$enable_pam != xno; then + SAVELIBS="$LIBS" + + AC_CHECK_LIB(dl,dlopen) + AC_CHECK_LIB(pam,pam_start) + AC_CHECK_HEADER(security/pam_appl.h) + if test x$ac_cv_header_security_pam_appl_h != xyes; then + AC_CHECK_HEADER(pam/pam_appl.h, + AC_DEFINE(HAVE_PAM_PAM_APPL_H)) + fi + + if test x$ac_cv_lib_pam_pam_start != xno; then + # Set the necessary libraries for PAM... + if test x$ac_cv_lib_dl_dlopen != xno; then + PAMLIBS="-lpam -ldl" + else + PAMLIBS="-lpam" + fi + + # Find the PAM configuration directory, if any... + for dir in /private/etc/pam.d /etc/pam.d; do + if test -d $dir; then + PAMDIR=$dir + break; + fi + done + fi + + LIBS="$SAVELIBS" + + case "$uname" in + Darwin*) + # Darwin, MacOS X + PAMFILE="pam.darwin" + ;; + IRIX) + # SGI IRIX + PAMFILE="pam.irix" + ;; + *) + # All others; this test might need to be updated + # as Linux distributors move things around... + for mod in pam_unix2.so pam_unix.so pam_pwdb.so; do + if test -f /lib/security/$mod; then + PAMMOD="$mod" + break; + fi + done + + PAMFILE="pam.std" + ;; + esac +fi + +AC_SUBST(PAMDIR) +AC_SUBST(PAMFILE) +AC_SUBST(PAMLIBS) +AC_SUBST(PAMMOD) + +dnl +dnl End of "$Id: cups-pam.m4 4913 2006-01-11 01:42:04Z mike $". +dnl diff --git a/config-scripts/cups-scripting.m4 b/config-scripts/cups-scripting.m4 new file mode 100644 index 000000000..e0c6832c6 --- /dev/null +++ b/config-scripts/cups-scripting.m4 @@ -0,0 +1,91 @@ +dnl +dnl "$Id: cups-scripting.m4 4494 2005-02-18 02:18:11Z mike $" +dnl +dnl Scripting configuration stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +dnl EMail: cups-info@cups.org +dnl WWW: http://www.cups.org +dnl + +dnl Do we have Java? +AC_ARG_WITH(java, [ --with-java set Java interpreter for web interfaces ], + CUPS_JAVA="$withval", + CUPS_JAVA="") + +if test "x$CUPS_JAVA" = x; then + AC_PATH_PROG(JAVA,java) + CUPS_JAVA="$JAVA" +fi + +AC_DEFINE_UNQUOTED(CUPS_JAVA, "$CUPS_JAVA") + +if test "x$CUPS_JAVA" != x; then + AC_DEFINE(HAVE_JAVA) +fi + +dnl Do we have Perl? +AC_ARG_WITH(perl, [ --with-perl set Perl interpreter for web interfaces ], + CUPS_PERL="$withval", + CUPS_PERL="") + +if test "x$CUPS_PERL" = x; then + AC_PATH_PROG(PERL,perl) + CUPS_PERL="$PERL" +fi + +AC_DEFINE_UNQUOTED(CUPS_PERL, "$CUPS_PERL") + +if test "x$CUPS_PERL" != x; then + AC_DEFINE(HAVE_PERL) +fi + +dnl Do we have PHP? +AC_ARG_WITH(php, [ --with-php set PHP interpreter for web interfaces ], + CUPS_PHP="$withval", + CUPS_PHP="") + +if test "x$CUPS_PHP" = x; then + AC_PATH_PROG(PHP,php) + CUPS_PHP="$PHP" +fi + +AC_DEFINE_UNQUOTED(CUPS_PHP, "$CUPS_PHP") + +if test "x$CUPS_PHP" != x; then + AC_DEFINE(HAVE_PHP) +fi + +dnl Do we have Python? +AC_ARG_WITH(python, [ --with-python set Python interpreter for web interfaces ], + CUPS_PYTHON="$withval", + CUPS_PYTHON="") + +if test "x$CUPS_PYTHON" = x; then + AC_PATH_PROG(PYTHON,python) + CUPS_PYTHON="$PYTHON" +fi + +AC_DEFINE_UNQUOTED(CUPS_PYTHON, "$CUPS_PYTHON") + +if test "x$CUPS_PYTHON" != x; then + AC_DEFINE(HAVE_PYTHON) +fi + +dnl +dnl End of "$Id: cups-scripting.m4 4494 2005-02-18 02:18:11Z mike $". +dnl diff --git a/config-scripts/cups-sharedlibs.m4 b/config-scripts/cups-sharedlibs.m4 new file mode 100644 index 000000000..8e015a5d7 --- /dev/null +++ b/config-scripts/cups-sharedlibs.m4 @@ -0,0 +1,156 @@ +dnl +dnl "$Id: cups-sharedlibs.m4 4800 2005-10-18 18:06:20Z mike $" +dnl +dnl Shared library support for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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.6,-soname,\$@ -shared \$(OPTIM)" + ;; + OSF1* | Linux | GNU | *BSD*) + LIBCUPS="libcups.so.2" + LIBCUPSIMAGE="libcupsimage.so.2" + DSO="\$(CC)" + DSOFLAGS="$DSOFLAGS -Wl,-soname,\$@ -shared \$(OPTIM)" + ;; + Darwin*) + LIBCUPS="libcups.2.dylib" + LIBCUPSIMAGE="libcupsimage.2.dylib" + DSO="\$(CC)" + DSOFLAGS="$DSOFLAGS \$(RC_CFLAGS) -dynamiclib -lc" + ;; + AIX*) + LIBCUPS="libcups_s.a" + LIBCUPSIMAGE="libcupsimage_s.a" + DSO="\$(CC)" + DSOFLAGS="$DSOFLAGS -Wl,-bexpall,-bM:SRE,-bnoentry,-blibpath:\$(libdir)" + ;; + *) + 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="../cups/libcups.a" + LINKCUPSIMAGE="../filter/libcupsimage.a" +else + if test $uname = AIX; then + LINKCUPS="-lcups_s" + LINKCUPSIMAGE="-lcupsimage_s" + else + LINKCUPS="-lcups" + LINKCUPSIMAGE="-lcupsimage" + fi +fi + +AC_SUBST(LINKCUPS) +AC_SUBST(LINKCUPSIMAGE) + +dnl Update libraries for DSOs... +EXPORT_LDFLAGS="" + +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="+s +b $libdir $DSOFLAGS" + LDFLAGS="$LDFLAGS -Wl,+s,+b,$libdir" + EXPORT_LDFLAGS="-Wl,+s,+b,$libdir" + ;; + SunOS*) + # Solaris + DSOFLAGS="-R$libdir $DSOFLAGS" + LDFLAGS="$LDFLAGS -R$libdir" + EXPORT_LDFLAGS="-R$libdir" + ;; + *BSD*) + # *BSD + DSOFLAGS="-Wl,-R$libdir $DSOFLAGS" + LDFLAGS="$LDFLAGS -Wl,-R$libdir" + EXPORT_LDFLAGS="-Wl,-R$libdir" + ;; + Linux | GNU) + # Linux and HURD + DSOFLAGS="-Wl,-rpath,$libdir $DSOFLAGS" + LDFLAGS="$LDFLAGS -Wl,-rpath,$libdir" + EXPORT_LDFLAGS="-Wl,-rpath,$libdir" + ;; + esac +else + DSOLIBS="" + IMGLIBS="\$(LIBPNG) \$(LIBTIFF) \$(LIBJPEG) \$(LIBZ)" +fi + +AC_SUBST(DSOLIBS) +AC_SUBST(IMGLIBS) +AC_SUBST(EXPORT_LDFLAGS) + +dnl +dnl End of "$Id: cups-sharedlibs.m4 4800 2005-10-18 18:06:20Z mike $". +dnl diff --git a/config-scripts/cups-slp.m4 b/config-scripts/cups-slp.m4 new file mode 100644 index 000000000..1b32e009d --- /dev/null +++ b/config-scripts/cups-slp.m4 @@ -0,0 +1,48 @@ +dnl +dnl "$Id: cups-openslp.m4 4494 2005-02-18 02:18:11Z mike $" +dnl +dnl OpenSLP configuration stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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" + CPPFLAGS="-I$withval $CPPFLAGS",) + +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 4494 2005-02-18 02:18:11Z mike $". +dnl diff --git a/config-scripts/cups-ssl.m4 b/config-scripts/cups-ssl.m4 new file mode 100644 index 000000000..166ca5897 --- /dev/null +++ b/config-scripts/cups-ssl.m4 @@ -0,0 +1,109 @@ +dnl +dnl "$Id: cups-ssl.m4 4800 2005-10-18 18:06:20Z mike $" +dnl +dnl OpenSSL/GNUTLS stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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_ENABLE(cdsassl, [ --enable-cdsassl use CDSA for SSL/TLS support, default=first]) +AC_ARG_ENABLE(gnutls, [ --enable-gnutls use GNU TLS for SSL/TLS support, default=second]) +AC_ARG_ENABLE(openssl, [ --enable-openssl use OpenSSL for SSL/TLS support, default=third]) +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" + CPPFLAGS="-I$withval $CPPFLAGS",) + +SSLFLAGS="" +SSLLIBS="" + +if test x$enable_ssl != xno; then + dnl Look for CDSA... + if test "x${SSLLIBS}" = "x" -a "x${enable_cdsassl}" != "xno"; then + if test $uname = Darwin; then + AC_CHECK_HEADER(Security/SecureTransport.h, + [SSLLIBS="-framework CoreFoundation -framework Security" + AC_DEFINE(HAVE_SSL) + AC_DEFINE(HAVE_CDSASSL)]) + fi + fi + + dnl Then look for GNU TLS... + if test "x${SSLLIBS}" = "x" -a "x${enable_gnutls}" != "xno"; then + AC_CHECK_HEADER(gnutls/gnutls.h, + dnl Save the current libraries so the crypto stuff isn't always + dnl included... + SAVELIBS="$LIBS" + + AC_CHECK_LIB(gnutls, gnutls_init, + [SSLLIBS="-lgnutls" + AC_DEFINE(HAVE_SSL) + AC_DEFINE(HAVE_GNUTLS)]) + + LIBS="$SAVELIBS") + fi + + dnl Check for the OpenSSL library last... + if test "x${SSLLIBS}" = "x" -a "x${enable_openssl}" != "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, + [SSLFLAGS="-DOPENSSL_DISABLE_OLD_DES_SUPPORT" + SSLLIBS="-lssl $libcrypto" + AC_DEFINE(HAVE_SSL) + AC_DEFINE(HAVE_LIBSSL)],, + $libcrypto) + + if test "x${SSLLIBS}" != "x"; then + break + fi + done + + LIBS="$SAVELIBS") + fi +fi + +AC_SUBST(SSLFLAGS) +AC_SUBST(SSLLIBS) + +EXPORT_SSLLIBS="$SSLLIBS" +AC_SUBST(EXPORT_SSLLIBS) + + +dnl +dnl End of "$Id: cups-ssl.m4 4800 2005-10-18 18:06:20Z mike $". +dnl diff --git a/config-scripts/cups-threads.m4 b/config-scripts/cups-threads.m4 new file mode 100644 index 000000000..788ce838c --- /dev/null +++ b/config-scripts/cups-threads.m4 @@ -0,0 +1,51 @@ +dnl +dnl "$Id$" +dnl +dnl Threading stuff for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +dnl EMail: cups-info@cups.org +dnl WWW: http://www.cups.org +dnl + +AC_ARG_ENABLE(threads, [ --enable-threads enable multi-threading support]) + +have_pthread=no + +if test "x$enable_threads" != xno; then + AC_CHECK_HEADER(pthread.h, AC_DEFINE(HAVE_PTHREAD_H)) + AC_CHECK_LIB(pthread, pthread_create) + + if test "x$ac_cv_lib_pthread_pthread_create" = xyes -a x$ac_cv_header_pthread_h = xyes; then + have_pthread=yes + else + dnl *BSD uses -pthread option... + AC_MSG_CHECKING([for pthread_create using -pthread]) + SAVELIBS="$LIBS" + LIBS="-pthread $LIBS" + AC_TRY_LINK([#include ], + [pthread_create(0, 0, 0, 0);], + have_pthread=yes, + LIBS="$SAVELIBS") + AC_MSG_RESULT([$have_pthread]) + fi +fi + + +dnl +dnl End of "$Id$". +dnl diff --git a/config.h.in b/config.h.in new file mode 100644 index 000000000..9b853da17 --- /dev/null +++ b/config.h.in @@ -0,0 +1,343 @@ +/* + * "$Id: config.h.in 4760 2005-10-08 20:11:08Z mike $" + * + * Configuration file for the Common UNIX Printing System (CUPS). + * + * @configure_input@ + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_CONFIG_H_ +#define _CUPS_CONFIG_H_ + +/* + * Version of software... + */ + +#define CUPS_SVERSION "" +#define CUPS_MINIMAL "" + + +/* + * Default user and group... + */ + +#define CUPS_DEFAULT_USER "lp" +#define CUPS_DEFAULT_GROUP "sys" + + +/* + * Default IPP port... + */ + +#define CUPS_DEFAULT_IPP_PORT 631 + + +/* + * Maximum number of file descriptors to support. + */ + +#define CUPS_MAX_FDS 4096 + + +/* + * Do we have domain socket support? + */ + +#undef CUPS_DEFAULT_DOMAINSOCKET + + +/* + * Where are files stored? + * + * Note: These are defaults, which can be overridden by environment + * variables at run-time... + */ + +#define CUPS_CACHEDIR "/var/cache/cups" +#define CUPS_DATADIR "/usr/share/cups" +#define CUPS_DOCROOT "/usr/share/doc/cups" +#define CUPS_FONTPATH "/usr/share/cups/fonts" +#define CUPS_LOCALEDIR "/usr/share/locale" +#define CUPS_LOGDIR "/var/logs/cups" +#define CUPS_REQUESTS "/var/spool/cups" +#define CUPS_SERVERBIN "/usr/lib/cups" +#define CUPS_SERVERROOT "/etc/cups" +#define CUPS_STATEDIR "/var/run/cups" + + +/* + * Do we have various image libraries? + */ + +#undef HAVE_LIBPNG +#undef HAVE_LIBZ +#undef HAVE_LIBJPEG +#undef HAVE_LIBTIFF + + +/* + * Do we have PAM stuff? + */ + +#ifndef HAVE_LIBPAM +#define HAVE_LIBPAM 0 +#endif /* !HAVE_LIBPAM */ + +#undef HAVE_PAM_PAM_APPL_H + + +/* + * Do we have ? + */ + +#undef HAVE_SHADOW_H + + +/* + * Do we have ? + */ + +#undef HAVE_CRYPT_H + + +/* + * Use , , and/or ? + */ + +#undef HAVE_STRING_H +#undef HAVE_STRINGS_H +#undef HAVE_BSTRING_H + +/* + * Do we have the long long type? + */ + +#undef HAVE_LONG_LONG + +#ifdef HAVE_LONG_LONG +# define CUPS_LLFMT "%lld" +# define CUPS_LLCAST (long long) +#else +# define CUPS_LLFMT "%ld" +# define CUPS_LLCAST (long) +#endif /* HAVE_LONG_LONG */ + +/* + * Do we have the strtoll() function? + */ + +#undef HAVE_STRTOLL + +#ifndef HAVE_STRTOLL +# define strtoll(nptr,endptr,base) strtol((nptr), (endptr), (base)) +#endif /* !HAVE_STRTOLL */ + +/* + * Do we have the strXXX() functions? + */ + +#undef HAVE_STRDUP +#undef HAVE_STRCASECMP +#undef HAVE_STRNCASECMP +#undef HAVE_STRLCAT +#undef HAVE_STRLCPY + + +/* + * Do we have the geteuid() function? + */ + +#undef HAVE_GETEUID + + +/* + * 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 langinfo.h header file? + */ + +#undef HAVE_LANGINFO_H + + +/* + * Which encryption libraries do we have? + */ + +#undef HAVE_CDSASSL +#undef HAVE_GNUTLS +#undef HAVE_LIBSSL +#undef HAVE_SSL + + +/* + * Do we have the OpenSLP library? + */ + +#undef HAVE_LIBSLP + + +/* + * Do we have libpaper? + */ + +#undef HAVE_LIBPAPER + + +/* + * Do we have ? + */ + +#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_af()? + */ + +#undef HAVE_RRESVPORT_AF + + +/* + * Do we have getaddrinfo()? + */ + +#undef HAVE_GETADDRINFO + + +/* + * Do we have getnameinfo()? + */ + +#undef HAVE_GETNAMEINFO + + +/* + * Do we have getifaddrs()? + */ + +#undef HAVE_GETIFADDRS + + +/* + * Do we have hstrerror()? + */ + +#undef HAVE_HSTRERROR + + +/* + * Do we have the header file? + */ + +#undef HAVE_SYS_SOCKIO_H + + +/* + * Does the sockaddr structure contain an sa_len parameter? + */ + +#undef HAVE_STRUCT_SOCKADDR_SA_LEN + + +/* + * Do we have the AIX usersec.h header file? + */ + +#undef HAVE_USERSEC_H + +/* + * Do we have pthread support? + */ + +#undef HAVE_PTHREAD_H + + +/* + * Various scripting languages... + */ + +#undef HAVE_JAVA +#define CUPS_JAVA "/usr/bin/java" +#undef HAVE_PERL +#define CUPS_PERL "/usr/bin/perl" +#undef HAVE_PHP +#define CUPS_PHP "/usr/bin/php" +#undef HAVE_PYTHON +#define CUPS_PYTHON "/usr/bin/python" + + +#endif /* !_CUPS_CONFIG_H_ */ + +/* + * End of "$Id: config.h.in 4760 2005-10-08 20:11:08Z mike $". + */ diff --git a/configure.in b/configure.in new file mode 100644 index 000000000..2057cd5f9 --- /dev/null +++ b/configure.in @@ -0,0 +1,57 @@ +dnl +dnl "$Id: configure.in 4873 2005-12-07 01:46:54Z mike $" +dnl +dnl Configuration script for the Common UNIX Printing System (CUPS). +dnl +dnl Copyright 1997-2005 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 USA +dnl +dnl Voice: (301) 373-9600 +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-slp.m4) +sinclude(config-scripts/cups-ssl.m4) +sinclude(config-scripts/cups-pam.m4) +sinclude(config-scripts/cups-threads.m4) +sinclude(config-scripts/cups-largefile.m4) + +MAKEDEFS="../Makedefs" +AC_SUBST(MAKEDEFS) + +sinclude(config-scripts/cups-scripting.m4) + +AC_OUTPUT(Makedefs packaging/cups.list cups.sh cups-config + conf/cupsd.conf conf/pam.std doc/index.html + doc/help/standard.html templates/edit-config.tmpl) + +chmod +x cups-config + +dnl +dnl End of "$Id: configure.in 4873 2005-12-07 01:46:54Z mike $". +dnl diff --git a/cups-config.in b/cups-config.in new file mode 100755 index 000000000..fdea47ea2 --- /dev/null +++ b/cups-config.in @@ -0,0 +1,134 @@ +#! /bin/sh +# +# "$Id: cups-config.in 4802 2005-10-19 13:48:06Z mike $" +# +# CUPS configuration utility. +# +# Copyright 2001-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +VERSION="@CUPS_VERSION@" +APIVERSION="1.2" + +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="" +LDFLAGS="@EXPORT_LDFLAGS@" +LIBS="@EXPORT_SSLLIBS@ @LIBS@" +IMGLIBS="@EXPORT_LIBTIFF@ @EXPORT_LIBJPEG@ @EXPORT_LIBPNG@ @EXPORT_LIBZ@" + +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 $IMGLIBS -lcups $LIBS + fi + else + if test $image = no; then + echo $libdir/libcups.a $LIBS + else + echo $libdir/libcupsimage.a $IMGLIBS $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: cups-config.in 4802 2005-10-19 13:48:06Z mike $". +# diff --git a/cups.osx b/cups.osx new file mode 100644 index 000000000..bff65dcc6 --- /dev/null +++ b/cups.osx @@ -0,0 +1,39 @@ +#!/bin/sh + +## +# PrintingServices - a.k.a. CUPS +## + +. /etc/rc.common + +StartService () +{ + if [ "${CUPS:=-YES-}" = "-YES-" ]; then + ConsoleMessage "Starting printing services" + /usr/sbin/cupsd + fi +} + +StopService () +{ + # Until cupsd has a pid file... + pid=`ps ax | awk '{if (match($5, ".*/cupsd$") || $5 == "cupsd") print $1}'` + if test "$pid" != ""; then + ConsoleMessage "Stopping printing services" + kill "${pid}" + fi +} + +RestartService () +{ + # Until cupsd has a pid file... + pid=`ps ax | awk '{if (match($5, ".*/cupsd$") || $5 == "cupsd") print $1}'` + if test "x$pid" != x; then + ConsoleMessage "Restarting printing services" + kill -HUP "${pid}" + else + StartService + fi +} + +RunService "$1" diff --git a/cups.plist b/cups.plist new file mode 100644 index 000000000..0633bf88a --- /dev/null +++ b/cups.plist @@ -0,0 +1,7 @@ +{ + Description = "Printing Services"; + Provides = ("PrintingServices"); + Requires = ("Resolver"); + Uses = ("Network Time"); + OrderPreference = "Late"; +} diff --git a/cups.sh.in b/cups.sh.in new file mode 100755 index 000000000..bba1d4428 --- /dev/null +++ b/cups.sh.in @@ -0,0 +1,211 @@ +#!/bin/sh +# +# "$Id: cups.sh.in 4493 2005-02-18 02:09:53Z mike $" +# +# Startup/shutdown script for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +#### 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 + + if $IS_ON verbose; then + ECHO=echo + else + ECHO=: + fi + ECHO_OK=: + ECHO_ERROR=: + ;; + + *BSD*) + IS_ON=: + ECHO=echo + ECHO_OK=: + ECHO_ERROR=: + ;; + + Darwin*) + . /etc/rc.common + + if test "${CUPS:=-YES-}" = "-NO-"; then + exit 0 + fi + + IS_ON=: + ECHO=ConsoleMessage + ECHO_OK=: + ECHO_ERROR=: + ;; + + Linux*) + IS_ON=/bin/true + if test -f /etc/init.d/functions; then + . /etc/init.d/functions + ECHO=echo + ECHO_OK="echo_success" + ECHO_ERROR="echo_failure" + else + ECHO=echo + ECHO_OK=: + ECHO_ERROR=: + fi + ;; + + *) + IS_ON=/bin/true + ECHO=echo + ECHO_OK=: + ECHO_ERROR=: + ;; +esac + +#### OS-Independent Stuff + +# +# Set the timezone, if possible... This allows the +# scheduler and all child processes to know the local +# timezone when reporting dates and times to the user. +# If no timezone information is found, then Greenwich +# Mean Time (GMT) will probably be used. +# + +for file in /etc/TIMEZONE /etc/rc.config /etc/sysconfig/clock; do + if test -f $file; then + . $file + fi +done + +if test "x$ZONE" != x; then + TZ="$ZONE" +fi + +if test "x$TIMEZONE" != x; then + TZ="$TIMEZONE" +fi + +if test "x$TZ" != x; then + export TZ +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 + if test $? != 0; then + $ECHO_FAIL + $ECHO "cups: unable to $1 scheduler." + exit 1 + fi + fi + $ECHO_OK + $ECHO "cups: ${1}ed scheduler." + fi + ;; + + stop) + if test "$pid" != ""; then + kill $pid + $ECHO_OK + $ECHO "cups: stopped scheduler." + 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: cups.sh.in 4493 2005-02-18 02:09:53Z mike $". +# diff --git a/cups.strings b/cups.strings new file mode 100644 index 000000000..d08f91972 --- /dev/null +++ b/cups.strings @@ -0,0 +1,9 @@ + + + + + Starting printing services + Starting printing services + + + diff --git a/cups/Dependencies b/cups/Dependencies new file mode 100644 index 000000000..8b3a12288 --- /dev/null +++ b/cups/Dependencies @@ -0,0 +1,66 @@ +# DO NOT DELETE + +array.o: array.h string.h ../config.h debug.h +attr.o: ppd.h file.h debug.h string.h ../config.h +auth.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h file.h +auth.o: i18n.h language.h array.h normalize.h transcode.h debug.h +backchannel.o: cups.h ipp.h http.h string.h ../config.h md5.h ppd.h file.h +dest.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h file.h +dest.o: i18n.h language.h array.h normalize.h transcode.h +dir.o: dir.h string.h ../config.h debug.h +emit.o: ppd.h file.h string.h ../config.h +encode.o: cups.h ipp.h http.h string.h ../config.h md5.h ppd.h file.h debug.h +file.o: http-private.h ../config.h http.h string.h md5.h ../cups/debug.h +file.o: file.h +getputfile.o: cups.h ipp.h http.h string.h ../config.h md5.h ppd.h file.h +getputfile.o: language.h array.h debug.h +globals.o: http-private.h ../config.h http.h string.h md5.h globals.h cups.h +globals.o: ipp.h ppd.h file.h i18n.h language.h array.h normalize.h +globals.o: transcode.h +http.o: http-private.h ../config.h http.h string.h md5.h globals.h cups.h +http.o: ipp.h ppd.h file.h i18n.h language.h array.h normalize.h transcode.h +http.o: debug.h +http-addr.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h +http-addr.o: file.h i18n.h language.h array.h normalize.h transcode.h debug.h +http-addrlist.o: http-private.h ../config.h http.h string.h md5.h globals.h +http-addrlist.o: cups.h ipp.h ppd.h file.h i18n.h language.h array.h +http-addrlist.o: normalize.h transcode.h debug.h +http-support.o: debug.h globals.h string.h ../config.h cups.h ipp.h http.h +http-support.o: md5.h ppd.h file.h i18n.h language.h array.h normalize.h +http-support.o: transcode.h +ipp.o: http-private.h ../config.h http.h string.h md5.h globals.h cups.h +ipp.o: ipp.h ppd.h file.h i18n.h language.h array.h normalize.h transcode.h +ipp.o: debug.h +ipp-support.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h +ipp-support.o: file.h i18n.h language.h array.h normalize.h transcode.h +ipp-support.o: debug.h +langprintf.o: string.h ../config.h i18n.h language.h array.h transcode.h +language.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h +language.o: file.h i18n.h language.h array.h normalize.h transcode.h debug.h +mark.o: ppd.h file.h string.h ../config.h debug.h +md5.o: md5.h string.h ../config.h +md5passwd.o: http.h string.h ../config.h md5.h +normalize.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h +normalize.o: file.h i18n.h language.h array.h normalize.h transcode.h debug.h +options.o: cups.h ipp.h http.h string.h ../config.h md5.h ppd.h file.h +options.o: debug.h +page.o: ppd.h file.h string.h ../config.h +ppd.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h file.h +ppd.o: i18n.h language.h array.h normalize.h transcode.h debug.h +snprintf.o: string.h ../config.h +string.o: string.h ../config.h +tempfile.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h +tempfile.o: file.h i18n.h language.h array.h normalize.h transcode.h debug.h +transcode.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h +transcode.o: file.h i18n.h language.h array.h normalize.h transcode.h +usersys.o: http-private.h ../config.h http.h string.h md5.h globals.h cups.h +usersys.o: ipp.h ppd.h file.h i18n.h language.h array.h normalize.h +usersys.o: transcode.h +util.o: globals.h string.h ../config.h cups.h ipp.h http.h md5.h ppd.h file.h +util.o: i18n.h language.h array.h normalize.h transcode.h debug.h +testarray.o: ../cups/string.h ../config.h string.h array.h dir.h debug.h +testfile.o: string.h ../config.h file.h debug.h +testhttp.o: http.h string.h ../config.h md5.h +testi18n.o: language.h array.h string.h ../config.h transcode.h normalize.h +testipp.o: ../cups/string.h ../config.h string.h ipp.h http.h md5.h +testlang.o: i18n.h language.h array.h diff --git a/cups/Makefile b/cups/Makefile new file mode 100644 index 000000000..1834c1312 --- /dev/null +++ b/cups/Makefile @@ -0,0 +1,342 @@ +# +# "$Id: Makefile 4918 2006-01-12 05:14:40Z mike $" +# +# API library Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2006 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# +# This file is subject to the Apple OS-Developed Software exception. +# + +include ../Makedefs + +# +# Object files... +# + +LIBOBJS = \ + array.o \ + attr.o \ + auth.o \ + backchannel.o \ + dest.o \ + dir.o \ + emit.o \ + encode.o \ + file.o \ + getputfile.o \ + globals.o \ + http.o \ + http-addr.o \ + http-addrlist.o \ + http-support.o \ + ipp.o \ + ipp-support.o \ + langprintf.o \ + language.o \ + mark.o \ + md5.o \ + md5passwd.o \ + normalize.o \ + options.o \ + page.o \ + ppd.o \ + snprintf.o \ + string.o \ + tempfile.o \ + transcode.o \ + usersys.o \ + util.o +OBJS = \ + $(LIBOBJS) \ + testarray.o \ + testfile.o \ + testhttp.o \ + testi18n.o \ + testipp.o \ + testlang.o \ + php_cups_wrap.o + + +# +# Header files to install... +# + +HEADERS = \ + array.h \ + cups.h \ + dir.h \ + file.h \ + http.h \ + i18n.h \ + ipp.h \ + language.h \ + md5.h \ + normalize.h \ + ppd.h \ + transcode.h + + +# +# Targets in this directory... +# + +TARGETS = \ + $(LIBCUPS) \ + libcups.a \ + testarray \ + testfile \ + testhttp \ + testi18n \ + testipp \ + testlang + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Remove object and target files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) `basename $(LIBCUPS) .2` libcups.dylib + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1 + + +# +# Install object and target files... +# + +install: all installhdrs + $(INSTALL_DIR) $(LIBDIR) + $(INSTALL_LIB) $(LIBCUPS) $(LIBDIR) + if test $(LIBCUPS) = "libcups.so.2" -o $(LIBCUPS) = "libcups.sl.2"; then \ + $(RM) $(LIBDIR)/`basename $(LIBCUPS) .2`; \ + $(LN) $(LIBCUPS) $(LIBDIR)/`basename $(LIBCUPS) .2`; \ + fi + if test $(LIBCUPS) = "libcups.2.dylib"; then \ + $(STRIP) -x $(LIBDIR)/$(LIBCUPS); \ + $(RM) $(LIBDIR)/libcups.dylib; \ + $(LN) $(LIBCUPS) $(LIBDIR)/libcups.dylib; \ + fi + if test $(LIBCUPS) != "libcups.a"; then \ + $(INSTALL_LIB) libcups.a $(LIBDIR); \ + $(RANLIB) $(LIBDIR)/libcups.a; \ + fi + +installhdrs: + $(INSTALL_DIR) $(INCLUDEDIR)/cups + for file in $(HEADERS); do \ + $(INSTALL_DATA) $$file $(INCLUDEDIR)/cups; \ + done + + +# +# libcups.so.2, libcups.sl.2 +# + +libcups.so.2 libcups.sl.2: $(LIBOBJS) + echo Linking $@... + $(DSO) $(DSOFLAGS) -o $@ $(LIBOBJS) $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + $(RM) `basename $@ .2` + $(LN) $@ `basename $@ .2` + + +# +# libcups.2.dylib +# + +libcups.2.dylib: $(LIBOBJS) + echo Linking $@... + $(DSO) $(DSOFLAGS) -o $@ \ + -install_name $(libdir)/libcups.dylib \ + -current_version 2.7.0 \ + -compatibility_version 2.0.0 \ + $(LIBOBJS) $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + $(RM) libcups.dylib + $(LN) $@ libcups.dylib + + +# +# libcups_s.a +# + +libcups_s.a: $(LIBOBJS) + echo Creating $@... + $(DSO) $(DSOFLAGS) -Wl,-bexport:libcups_s.exp -o libcups_s.o $(LIBOBJS) $(SSLLIBS) $(COMMONLIBS) $(LIBZ) -lm + $(RM) $@ + $(AR) $(ARFLAGS) $@ libcups_s.o + + +# +# libcups.la +# + +libcups.la: $(LIBOBJS) + echo Linking $@... + $(CC) $(DSOFLAGS) -o $@ $(LIBOBJS:.o=.lo) -rpath $(LIBDIR) \ + -version-info 2:7 $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + + +# +# libcups.a +# + +libcups.a: $(LIBOBJS) + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + + +# +# CUPS language bindings for various scripting languages... +# + +phpcups.so: $(LIBCUPS) php_cups_wrap.o + echo Linking $@... + if test `uname` = Darwin; then \ + DSOFLAGS="-bundle -flat_namespace -undefined suppress"; \ + else \ + DSOFLAGS="$(DSOFLAGS)"; \ + fi; \ + $(DSO) $$DSOFLAGS -o $@ php_cups_wrap.o $(LIBS) `php-config --ldflags --libs` + +php_cups_wrap.o: php_cups_wrap.c + echo Compiling $<... + $(CC) $(CFLAGS) `php-config --includes` -c $< +php_cups_wrap.c: cups.h + echo Creating $< using SWIG... + swig -php -o $@ -module cups cups.h + + +# +# testarray (dependency on static CUPS library is intentional) +# + +testarray: testarray.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testarray.o libcups.a \ + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + + +# +# testfile (dependency on static CUPS library is intentional) +# + +testfile: testfile.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testfile.o libcups.a \ + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + + +# +# testhttp (dependency on static CUPS library is intentional) +# + +testhttp: testhttp.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testhttp.o libcups.a \ + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + + +# +# testipp (dependency on static CUPS library is intentional) +# + +testipp: testipp.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testipp.o libcups.a \ + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + + +# +# testi18n (dependency on static CUPS library is intentional) +# + +testi18n: testi18n.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testi18n.o libcups.a \ + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + + +# +# testlang (dependency on static CUPS library is intentional) +# + +testlang: testlang.o libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testlang.o libcups.a \ + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + + +# +# Automatic API help files... +# + +apihelp: + echo Generating CUPS API help files... + mxmldoc --section "Programming" --title "Array API" \ + --intro api-array.shtml \ + array.h array.c >../doc/help/api-array.html + mxmldoc --section "Programming" --title "CUPS API" \ + --intro api-cups.shtml \ + cups.h auth.c dest.c encode.c getputfile.c language.c \ + options.c tempfile.c usersys.c \ + util.c >../doc/help/api-cups.html + mxmldoc --section "Programming" --title "File and Directory APIs" \ + --intro api-filedir.shtml \ + file.h file.c dir.h dir.c >../doc/help/api-filedir.html + mxmldoc --section "Programming" --title "PPD API" \ + --intro api-ppd.shtml \ + ppd.h attr.c emit.c mark.c page.c \ + ppd.c >../doc/help/api-ppd.html + mxmldoc --section "Programming" --title "HTTP and IPP APIs" \ + --intro api-httpipp.shtml \ + cups.h http.h ipp.h \ + auth.c dest.c encode.c getputfile.c http.c http-addr.c \ + http-support.c ipp.c ipp-support.c md5passwd.c options.c \ + usersys.c util.c >../doc/help/api-httpipp.html + mxmldoc --section "Programming" --title "Filter and Backend APIs" \ + --intro api-filter.shtml \ + backchannel.c >../doc/help/api-filter.html + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4918 2006-01-12 05:14:40Z mike $". +# diff --git a/cups/api-array.shtml b/cups/api-array.shtml new file mode 100644 index 000000000..d6297fb6a --- /dev/null +++ b/cups/api-array.shtml @@ -0,0 +1,54 @@ + + +

Introduction

+ +

The CUPS array API provides a high-performance generic array +container. The contents of the array container can be sorted and +the container itself is designed for optimal speed and memory +usage under a wide variety of conditions.

+ +

The CUPS scheduler (cupsd) and many of the CUPS API +functions use the array API to efficiently manage large lists of +data.

+ +

General Usage

+ +

The <cups/array.h> header file must be +included to use the cupsArray functions.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

All of these functions require CUPS 1.2 or higher.

diff --git a/cups/api-cups.shtml b/cups/api-cups.shtml new file mode 100644 index 000000000..a39112795 --- /dev/null +++ b/cups/api-cups.shtml @@ -0,0 +1,48 @@ + + +

Introduction

+ +

The CUPS APIs provide...

+ +

General Usage

+ +

The <cups/cups.h> header file must be included to +use the CUPS functions.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

Unless otherwise specified, the CUPS API functions require +CUPS 1.1 or higher.

diff --git a/cups/api-filedir.shtml b/cups/api-filedir.shtml new file mode 100644 index 000000000..d321cc604 --- /dev/null +++ b/cups/api-filedir.shtml @@ -0,0 +1,66 @@ + + +

Introduction

+ +

The CUPS file and directory APIs provide portable interfaces +for manipulating files and listing files and directories. Unlike +stdio FILE streams, the cupsFile functions +allow you to open more than 256 files at any given time. They +also manage the platform-specific details of locking, large file +support, line endings (CR, LF, or CR LF), and reading and writing +files using Flate ("gzip") compression. Finally, you can also +connect, read from, and write to network connections using the +cupsFile functions.

+ +

The cupsDir functions manage the platform-specific +details of directory access/listing and provide a convenient way +to get both a list of files and the information (permissions, +size, timestamp, etc.) for each of those files.

+ +

The CUPS scheduler (cupsd), mailto notifier, +and many of the CUPS API functions use these functions for +everything except console (stdin, stdout, stderr) I/O.

+ +

General Usage

+ +

The <cups/dir.h> and +<cups/file.h> header files must be included to +use the cupsDir and cupsFile functions, +respectively.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

All of these functions require CUPS 1.2 or higher.

diff --git a/cups/api-filter.shtml b/cups/api-filter.shtml new file mode 100644 index 000000000..f43a8d140 --- /dev/null +++ b/cups/api-filter.shtml @@ -0,0 +1,49 @@ + + +

Introduction

+ +

The CUPS filter and backend APIs provide...

+ +

General Usage

+ +

The <cups/backend.h> and +<cups/cups.h> header files must be included to +use the CUPS_BACKEND_ constants and +cupsBackchannel functions, respectively.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

All of these functions require CUPS 1.2 or higher.

diff --git a/cups/api-httpipp.shtml b/cups/api-httpipp.shtml new file mode 100644 index 000000000..1c1b6a43e --- /dev/null +++ b/cups/api-httpipp.shtml @@ -0,0 +1,48 @@ + + +

Introduction

+ +

The CUPS HTTP and IPP APIs provide...

+ +

General Usage

+ +

The <cups/cups.h> header file must be included to +use the HTTP and IPP functions.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

Unless otherwise specified, the HTTP and IPP API functions +require CUPS 1.1 or higher.

diff --git a/cups/api-ppd.shtml b/cups/api-ppd.shtml new file mode 100644 index 000000000..337ee3d46 --- /dev/null +++ b/cups/api-ppd.shtml @@ -0,0 +1,48 @@ + + +

Introduction

+ +

The CUPS PPD API provides...

+ +

General Usage

+ +

The <cups/ppd.h> header file must be included +to use the ppd functions.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

Unless otherwise specified, the PPD API functions require CUPS +1.1 or higher.

diff --git a/cups/array.c b/cups/array.c new file mode 100644 index 000000000..88f26cd72 --- /dev/null +++ b/cups/array.c @@ -0,0 +1,828 @@ +/* + * "$Id: array.c 4921 2006-01-12 21:26:26Z mike $" + * + * Sorted array routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsArrayAdd() - Add an element to the array. + * cupsArrayClear() - Clear the array. + * cupsArrayCount() - Get the number of elements in the array. + * cupsArrayCurrent() - Return the current element in the array. + * cupsArrayDelete() - Free all memory used by the array. + * cupsArrayDup() - Duplicate the array. + * cupsArrayFind() - Find an element in the array. + * cupsArrayFirst() - Get the first element in the array. + * cupsArrayIndex() - Get the N-th element in the array. + * cupsArrayLast() - Get the last element in the array. + * cupsArrayNew() - Create a new array. + * cupsArrayNext() - Get the next element in the array. + * cupsArrayPrev() - Get the previous element in the array. + * cupsArrayRemove() - Remove an element from the array. + * cupsArrayRestore() - Reset the current element to the last cupsArraySave. + * cupsArraySave() - Mark the current element for a later cupsArrayRestore. + * cups_find() - Find an element in the array... + */ + +/* + * Include necessary headers... + */ + +#include "array.h" +#include "string.h" +#include "debug.h" + + +/* + * Limits... + */ + +#define _CUPS_MAXSAVE 32 /**** Maximum number of saves ****/ + + +/* + * Types and structures... + */ + +struct _cups_array_s /**** CUPS array structure ****/ +{ + /* + * The current implementation uses an insertion sort into an array of + * sorted pointers. We leave the array type private/opaque so that we + * can change the underlying implementation without affecting the users + * of this API. + */ + + int num_elements, /* Number of array elements */ + alloc_elements, /* Allocated array elements */ + current, /* Current element */ + insert, /* Last inserted element */ + num_saved, /* Number of saved elements */ + saved[_CUPS_MAXSAVE]; + /* Saved elements */ + void **elements; /* Array elements */ + cups_array_func_t compare; /* Element comparison function */ + void *data; /* User data passed to compare */ +}; + + +/* + * Local functions... + */ + +static int cups_find(cups_array_t *a, void *e, int prev, int *rdiff); + + +/* + * 'cupsArrayAdd()' - Add an element to the array. + */ + +int /* O - 1 on success, 0 on failure */ +cupsArrayAdd(cups_array_t *a, /* I - Array */ + void *e) /* I - Element */ +{ + int i, /* Looping var */ + current, /* Current element */ + diff; /* Comparison with current element */ + + + DEBUG_printf(("cupsArrayAdd(a=%p, e=%p)\n", a, e)); + + /* + * Range check input... + */ + + if (!a || !e) + { + DEBUG_puts("cupsArrayAdd: returning 0"); + return (0); + } + + /* + * Verify we have room for the new element... + */ + + if (a->num_elements >= a->alloc_elements) + { + /* + * Allocate additional elements; start with 16 elements, then + * double the size until 1024 elements, then add 1024 elements + * thereafter... + */ + + void **temp; /* New array elements */ + int count; /* New allocation count */ + + + if (a->alloc_elements == 0) + { + count = 16; + temp = malloc(count * sizeof(void *)); + } + else + { + if (a->alloc_elements < 1024) + count = a->alloc_elements * 2; + else + count = a->alloc_elements + 1024; + + temp = realloc(a->elements, count * sizeof(void *)); + } + + DEBUG_printf(("cupsArrayAdd: count=%d\n", count)); + + if (!temp) + { + DEBUG_puts("cupsAddAdd: allocation failed, returning 0"); + return (0); + } + + a->alloc_elements = count; + a->elements = temp; + } + + /* + * Find the insertion point for the new element; if there is no + * compare function or elements, just add it to the end... + */ + + if (!a->num_elements || !a->compare) + { + /* + * Append to the end... + */ + + current = a->num_elements; + } + else + { + /* + * Do a binary search for the insertion point... + */ + + current = cups_find(a, e, a->insert, &diff); + + if (diff > 0) + current ++; + } + + /* + * Insert or append the element... + */ + + if (current < a->num_elements) + { + /* + * Shift other elements to the right... + */ + + memmove(a->elements + current + 1, a->elements + current, + (a->num_elements - current) * sizeof(void *)); + + if (a->current >= current) + a->current ++; + + for (i = 0; i < a->num_saved; i ++) + if (a->saved[i] >= current) + a->saved[i] ++; + + DEBUG_printf(("cupsArrayAdd: insert element at index %d...\n", current)); + } +#ifdef DEBUG + else + printf("cupsArrayAdd: append element at %d...\n", current); +#endif /* DEBUG */ + + a->elements[current] = e; + a->num_elements ++; + a->insert = current; + +#ifdef DEBUG + for (current = 0; current < a->num_elements; current ++) + printf("cupsArrayAdd: a->elements[%d]=%p\n", current, a->elements[current]); +#endif /* DEBUG */ + + DEBUG_puts("cupsArrayAdd: returning 1"); + + return (1); +} + + +/* + * 'cupsArrayClear()' - Clear the array. + */ + +void +cupsArrayClear(cups_array_t *a) /* I - Array */ +{ + /* + * Range check input... + */ + + if (!a) + return; + + /* + * Set the number of elements to 0; we don't actually free the memory + * here - that is done in cupsArrayDelete()... + */ + + a->num_elements = 0; + a->current = -1; + a->insert = -1; + a->num_saved = 0; +} + + +/* + * 'cupsArrayCount()' - Get the number of elements in the array. + */ + +int /* O - Number of elements */ +cupsArrayCount(cups_array_t *a) /* I - Array */ +{ + /* + * Range check input... + */ + + if (!a) + return (0); + + /* + * Return the number of elements... + */ + + return (a->num_elements); +} + + +/* + * 'cupsArrayCurrent()' - Return the current element in the array. + */ + +void * /* O - Element */ +cupsArrayCurrent(cups_array_t *a) /* I - Array */ +{ + /* + * Range check input... + */ + + if (!a) + return (NULL); + + /* + * Return the current element... + */ + + if (a->current >= 0 && a->current < a->num_elements) + return (a->elements[a->current]); + else + return (NULL); +} + + +/* + * 'cupsArrayDelete()' - Free all memory used by the array. + */ + +void +cupsArrayDelete(cups_array_t *a) /* I - Array */ +{ + /* + * Range check input... + */ + + if (!a) + return; + + /* + * Free the array of element pointers - the caller is responsible + * for freeing the elements themselves... + */ + + if (a->alloc_elements) + free(a->elements); + + free(a); +} + + +/* + * 'cupsArrayDup()' - Duplicate the array. + */ + +cups_array_t * /* O - Duplicate array */ +cupsArrayDup(cups_array_t *a) /* I - Array */ +{ + cups_array_t *da; /* Duplicate array */ + + + /* + * Range check input... + */ + + if (!a) + return (NULL); + + /* + * Allocate memory for the array... + */ + + da = calloc(1, sizeof(cups_array_t)); + if (!da) + return (NULL); + + da->compare = a->compare; + da->data = a->data; + da->current = a->current; + da->insert = a->insert; + da->num_saved = a->num_saved; + + memcpy(da->saved, a->saved, sizeof(a->saved)); + + if (a->num_elements) + { + /* + * Allocate memory for the elements... + */ + + da->elements = malloc(a->num_elements * sizeof(void *)); + if (!da->elements) + { + free(da); + return (NULL); + } + + /* + * Copy the element pointers... + */ + + memcpy(da->elements, a->elements, a->num_elements * sizeof(void *)); + da->num_elements = a->num_elements; + da->alloc_elements = a->num_elements; + } + + /* + * Return the new array... + */ + + return (da); +} + + +/* + * 'cupsArrayFind()' - Find an element in the array. + */ + +void * /* O - Element found or NULL */ +cupsArrayFind(cups_array_t *a, /* I - Array */ + void *e) /* I - Element */ +{ + int current, /* Current element */ + diff; /* Difference */ + + + /* + * Range check input... + */ + + if (!a || !e) + return (NULL); + + /* + * See if we have any elements... + */ + + if (!a->num_elements) + return (NULL); + + /* + * Yes, look for a match... + */ + + current = cups_find(a, e, a->current, &diff); + if (!diff) + { + /* + * Found a match... + */ + + a->current = current; + + return (a->elements[current]); + } + else + { + /* + * No match... + */ + + a->current = -1; + + return (NULL); + } +} + + +/* + * 'cupsArrayFirst()' - Get the first element in the array. + */ + +void * /* O - First element or NULL */ +cupsArrayFirst(cups_array_t *a) /* I - Array */ +{ + /* + * Range check input... + */ + + if (!a) + return (NULL); + + /* + * Return the first element... + */ + + a->current = 0; + + return (cupsArrayCurrent(a)); +} + + +/* + * 'cupsArrayIndex()' - Get the N-th element in the array. + */ + +void * /* O - N-th element or NULL */ +cupsArrayIndex(cups_array_t *a, /* I - Array */ + int n) /* I - Index into array, starting at 0 */ +{ + if (!a) + return (NULL); + + a->current = n; + + return (cupsArrayCurrent(a)); +} + + +/* + * 'cupsArrayLast()' - Get the last element in the array. + */ + +void * /* O - Last element or NULL */ +cupsArrayLast(cups_array_t *a) /* I - Array */ +{ + /* + * Range check input... + */ + + if (!a) + return (NULL); + + /* + * Return the last element... + */ + + a->current = a->num_elements - 1; + + return (cupsArrayCurrent(a)); +} + + +/* + * 'cupsArrayNew()' - Create a new array. + */ + +cups_array_t * /* O - Array */ +cupsArrayNew(cups_array_func_t f, /* I - Comparison function */ + void *d) /* I - User data */ +{ + cups_array_t *a; /* Array */ + + + /* + * Allocate memory for the array... + */ + + a = calloc(1, sizeof(cups_array_t)); + if (!a) + return (NULL); + + a->compare = f; + a->data = d; + a->current = -1; + a->insert = -1; + a->num_saved = 0; + + return (a); +} + + +/* + * 'cupsArrayNext()' - Get the next element in the array. + */ + +void * /* O - Next element or NULL */ +cupsArrayNext(cups_array_t *a) /* I - Array */ +{ + /* + * Range check input... + */ + + if (!a) + return (NULL); + + /* + * Return the next element... + */ + + if (a->current < a->num_elements) + a->current ++; + + return (cupsArrayCurrent(a)); +} + + +/* + * 'cupsArrayPrev()' - Get the previous element in the array. + */ + +void * /* O - Previous element or NULL */ +cupsArrayPrev(cups_array_t *a) /* I - Array */ +{ + /* + * Range check input... + */ + + if (!a) + return (NULL); + + /* + * Return the previous element... + */ + + if (a->current >= 0) + a->current --; + + return (cupsArrayCurrent(a)); +} + + +/* + * 'cupsArrayRemove()' - Remove an element from the array. + */ + +int /* O - 1 on success, 0 on failure */ +cupsArrayRemove(cups_array_t *a, /* I - Array */ + void *e) /* I - Element */ +{ + int i, /* Looping var */ + current, /* Current element */ + diff; /* Difference */ + + + /* + * Range check input... + */ + + if (!a || !e) + return (0); + + /* + * See if the element is in the array... + */ + + if (!a->num_elements) + return (0); + + current = cups_find(a, e, a->current, &diff); + if (diff) + return (0); + + /* + * Yes, now remove it... + */ + + a->num_elements --; + + if (current < a->num_elements) + memmove(a->elements + current, a->elements + current + 1, + (a->num_elements - current) * sizeof(void *)); + + if (current <= a->current) + a->current --; + + if (current <= a->insert) + a->insert --; + + for (i = 0; i < a->num_saved; i ++) + if (current <= a->saved[i]) + a->saved[i] --; + + return (1); +} + + +/* + * 'cupsArrayRestore()' - Reset the current element to the last cupsArraySave. + */ + +void * /* O - New current element */ +cupsArrayRestore(cups_array_t *a) /* I - Array */ +{ + if (!a) + return (NULL); + + if (a->num_saved <= 0) + return (NULL); + + a->num_saved --; + a->current = a->saved[a->num_saved]; + + if (a->current >= 0 && a->current < a->num_elements) + return (a->elements[a->current]); + else + return (NULL); +} + + +/* + * 'cupsArraySave()' - Mark the current element for a later cupsArrayRestore. + * + * The save/restore stack is guaranteed to be at least 32 elements deep. + */ + +int /* O - 1 on success, 0 on failure */ +cupsArraySave(cups_array_t *a) /* I - Array */ +{ + if (!a) + return (0); + + if (a->num_saved >= _CUPS_MAXSAVE) + return (0); + + a->saved[a->num_saved] = a->current; + a->num_saved ++; + + return (1); +} + + +/* + * 'cups_find()' - Find an element in the array... + */ + +static int /* O - Index of match */ +cups_find(cups_array_t *a, /* I - Array */ + void *e, /* I - Element */ + int prev, /* I - Previous index */ + int *rdiff) /* O - Difference of match */ +{ + int left, /* Left side of search */ + right, /* Right side of search */ + current, /* Current element */ + diff; /* Comparison with current element */ + + + DEBUG_printf(("cups_find(a=%p, e=%p, prev=%d, rdiff=%p)\n", a, e, prev, + rdiff)); + + if (a->compare) + { + /* + * Do a binary search for the element... + */ + + DEBUG_puts("cups_find: binary search"); + + if (prev >= 0 && prev < a->num_elements) + { + /* + * Start search on either side of previous... + */ + + if ((diff = (*(a->compare))(e, a->elements[prev], a->data)) == 0 || + (diff < 0 && prev == 0) || + (diff > 0 && prev == (a->num_elements - 1))) + { + /* + * Exact or edge match, return it! + */ + + DEBUG_printf(("cups_find: Returning %d, diff=%d\n", prev, diff)); + + *rdiff = diff; + + return (prev); + } + else if (diff < 0) + { + /* + * Start with previous on right side... + */ + + left = 0; + right = prev; + } + else + { + /* + * Start wih previous on left side... + */ + + left = prev; + right = a->num_elements - 1; + } + } + else + { + /* + * Start search in the middle... + */ + + left = 0; + right = a->num_elements - 1; + } + + do + { + current = (left + right) / 2; + diff = (*(a->compare))(e, a->elements[current], a->data); + + DEBUG_printf(("cups_find: left=%d, right=%d, current=%d, diff=%d\n", + left, right, current, diff)); + + if (diff == 0) + break; + else if (diff < 0) + right = current; + else + left = current; + } + while ((right - left) > 1); + + if (diff != 0) + { + /* + * Check the last 1 or 2 elements... + */ + + if ((diff = (*(a->compare))(e, a->elements[left], a->data)) <= 0) + current = left; + else + { + diff = (*(a->compare))(e, a->elements[right], a->data); + current = right; + } + } + } + else + { + /* + * Do a linear pointer search... + */ + + DEBUG_puts("cups_find: linear search"); + + diff = 0; + + for (current = 0; current < a->num_elements; current ++) + if (a->elements[current] == e) + break; + } + + /* + * Return the closest element and the difference... + */ + + DEBUG_printf(("cups_find: Returning %d, diff=%d\n", current, diff)); + + *rdiff = diff; + + return (current); +} + + +/* + * End of "$Id: array.c 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cups/array.h b/cups/array.h new file mode 100644 index 000000000..1043121e2 --- /dev/null +++ b/cups/array.h @@ -0,0 +1,83 @@ +/* + * "$Id: array.h 4921 2006-01-12 21:26:26Z mike $" + * + * Sorted array definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_ARRAY_H_ +# define _CUPS_ARRAY_H_ + +/* + * Include necessary headers... + */ + +# include + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Types and structures... + */ + +typedef struct _cups_array_s cups_array_t; + /**** CUPS array type ****/ +typedef int (*cups_array_func_t)(void *first, void *second, void *data); + /**** Array comparison function ****/ + +/* + * Functions... + */ + +extern int cupsArrayAdd(cups_array_t *a, void *e); +extern void cupsArrayClear(cups_array_t *a); +extern int cupsArrayCount(cups_array_t *a); +extern void *cupsArrayCurrent(cups_array_t *a); +extern void cupsArrayDelete(cups_array_t *a); +extern cups_array_t *cupsArrayDup(cups_array_t *a); +extern void *cupsArrayFind(cups_array_t *a, void *e); +extern void *cupsArrayFirst(cups_array_t *a); +extern void *cupsArrayIndex(cups_array_t *a, int n); +extern void *cupsArrayLast(cups_array_t *a); +extern cups_array_t *cupsArrayNew(cups_array_func_t f, void *d); +extern void *cupsArrayNext(cups_array_t *a); +extern void *cupsArrayPrev(cups_array_t *a); +extern int cupsArrayRemove(cups_array_t *a, void *e); +extern void *cupsArrayRestore(cups_array_t *a); +extern int cupsArraySave(cups_array_t *a); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_ARRAY_H_ */ + +/* + * End of "$Id: array.h 4921 2006-01-12 21:26:26Z mike $". + */ diff --git a/cups/attr.c b/cups/attr.c new file mode 100644 index 000000000..36f911d0b --- /dev/null +++ b/cups/attr.c @@ -0,0 +1,184 @@ +/* + * "$Id: attr.c 4785 2005-10-13 19:39:05Z mike $" + * + * PPD model-specific attribute routines for the Common UNIX Printing System + * (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * ppdFindAttr() - Find the first matching attribute... + * ppdFindNextAttr() - Find the next matching attribute... + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include "debug.h" +#include "string.h" +#include + + +/* + * Private function... + */ + +extern int _ppd_attr_compare(ppd_attr_t **a, ppd_attr_t **b); + + +/* + * 'ppdFindAttr()' - Find the first matching attribute... + * + * @since CUPS 1.1.19@ + */ + +ppd_attr_t * /* O - Attribute or NULL if not found */ +ppdFindAttr(ppd_file_t *ppd, /* I - PPD file data */ + const char *name, /* I - Attribute name */ + const char *spec) /* I - Specifier string or NULL */ +{ + ppd_attr_t key, /* Search key */ + *keyptr, /* Pointer to key */ + **match; /* Matching attribute */ + + + /* + * Range check input... + */ + + if (ppd == NULL || name == NULL || ppd->num_attrs == 0) + return (NULL); + + /* + * Do a binary search for a matching attribute... + */ + + memset(&key, 0, sizeof(key)); + strncpy(key.name, name, sizeof(key.name) - 1); + if (spec) + strncpy(key.spec, spec, sizeof(key.spec) - 1); + + keyptr = &key; + + match = bsearch(&keyptr, ppd->attrs, ppd->num_attrs, sizeof(ppd_attr_t *), + (int (*)(const void *, const void *))_ppd_attr_compare); + + if (match == NULL) + { + /* + * No match! + */ + + ppd->cur_attr = -1; + return (NULL); + } + + if (match > ppd->attrs && spec == NULL) + { + /* + * Find the first attribute with the same name... + */ + + while (match > ppd->attrs) + { + if (strcmp(match[-1]->name, name) != 0) + break; + + match --; + } + } + + /* + * Save the current attribute and return its value... + */ + + ppd->cur_attr = match - ppd->attrs; + + return (*match); +} + + +/* + * 'ppdFindNextAttr()' - Find the next matching attribute... + * + * @since CUPS 1.1.19@ + */ + +ppd_attr_t * /* O - Attribute or NULL if not found */ +ppdFindNextAttr(ppd_file_t *ppd, /* I - PPD file data */ + const char *name, /* I - Attribute name */ + const char *spec) /* I - Specifier string or NULL */ +{ + ppd_attr_t **match; /* Matching attribute */ + + + /* + * Range check input... + */ + + if (ppd == NULL || name == NULL || ppd->num_attrs == 0 || ppd->cur_attr < 0) + return (NULL); + + /* + * See if there are more attributes to return... + */ + + ppd->cur_attr ++; + + if (ppd->cur_attr >= ppd->num_attrs) + { + /* + * Nope... + */ + + ppd->cur_attr = -1; + return (NULL); + } + + /* + * Check the next attribute to see if it is a match... + */ + + match = ppd->attrs + ppd->cur_attr; + + if (strcmp((*match)->name, name) != 0 || + (spec != NULL && strcmp((*match)->spec, spec) != 0)) + { + /* + * Nope... + */ + + ppd->cur_attr = -1; + return (NULL); + } + + /* + * Return the next attribute's value... + */ + + return (*match); +} + + +/* + * End of "$Id: attr.c 4785 2005-10-13 19:39:05Z mike $". + */ diff --git a/cups/auth.c b/cups/auth.c new file mode 100644 index 000000000..681728fb3 --- /dev/null +++ b/cups/auth.c @@ -0,0 +1,249 @@ +/* + * "$Id: auth.c 4918 2006-01-12 05:14:40Z mike $" + * + * Authentication functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsDoAuthentication() - Authenticate a request. + * cups_local_auth() - Get the local authorization certificate if + * available/applicable... + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include "debug.h" +#include +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local functions... + */ + +static int cups_local_auth(http_t *http); + + +/* + * 'cupsDoAuthentication()' - Authenticate a request. + * + * This function should be called in response to a HTTP_UNAUTHORIZED + * status, prior to resubmitting your request. + * + * @since CUPS 1.1.20@ + */ + +int /* O - 0 on success, -1 on error */ +cupsDoAuthentication(http_t *http, /* I - HTTP connection to server */ + const char *method,/* I - Request method (GET, POST, PUT) */ + const char *resource) + /* I - Resource path */ +{ + const char *password; /* Password string */ + char prompt[1024], /* Prompt for user */ + realm[HTTP_MAX_VALUE], /* realm="xyz" string */ + nonce[HTTP_MAX_VALUE], /* nonce="xyz" string */ + encode[512]; /* Encoded username:password */ + + + DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")\n", + http, method, resource)); + DEBUG_printf(("cupsDoAuthentication: digest_tries=%d, userpass=\"%s\"\n", + http->digest_tries, http->userpass)); + + /* + * Clear the current authentication string... + */ + + http->authstring[0] = '\0'; + + /* + * See if we can do local authentication... + */ + + if (!cups_local_auth(http)) + { + DEBUG_printf(("cupsDoAuthentication: authstring=\"%s\"\n", http->authstring)); + return (0); + } + + /* + * Nope, see if we should retry the current username:password... + */ + + if (http->digest_tries > 1 || !http->userpass[0]) + { + /* + * Nope - get a new password from the user... + */ + + snprintf(prompt, sizeof(prompt), "Password for %s on %s? ", cupsUser(), + http->hostname); + + http->digest_tries = strncasecmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], + "Digest", 5) != 0; + http->userpass[0] = '\0'; + + if ((password = cupsGetPassword(prompt)) == NULL) + return (-1); + + if (!password[0]) + return (-1); + + snprintf(http->userpass, sizeof(http->userpass), "%s:%s", cupsUser(), + password); + } + else if (http->status == HTTP_UNAUTHORIZED) + http->digest_tries ++; + + /* + * Got a password; encode it for the server... + */ + + if (strncmp(http->fields[HTTP_FIELD_WWW_AUTHENTICATE], "Digest", 6)) + { + /* + * Basic authentication... + */ + + httpEncode64_2(encode, sizeof(encode), http->userpass, + strlen(http->userpass)); + snprintf(http->authstring, sizeof(http->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, strchr(http->userpass, ':') + 1, encode); + httpMD5Final(nonce, method, resource, encode); + snprintf(http->authstring, sizeof(http->authstring), + "Digest username=\"%s\", realm=\"%s\", nonce=\"%s\", " + "uri=\"%s\", response=\"%s\"", cupsUser(), realm, nonce, + resource, encode); + } + + DEBUG_printf(("cupsDoAuthentication: authstring=\"%s\"\n", http->authstring)); + + return (0); +} + + +/* + * 'cups_local_auth()' - Get the local authorization certificate if + * available/applicable... + */ + +static int /* O - 0 if available, -1 if not */ +cups_local_auth(http_t *http) /* I - HTTP connection to server */ +{ +#if defined(WIN32) || defined(__EMX__) + /* + * Currently WIN32 and OS-2 do not support the CUPS server... + */ + + return (-1); +#else + int pid; /* Current process ID */ + FILE *fp; /* Certificate file */ + char filename[1024], /* Certificate filename */ + certificate[33]; /* Certificate string */ + _cups_globals_t *cg = _cupsGlobals(); /* Global data */ + + + DEBUG_printf(("cups_local_auth(http=%p) hostaddr=%s, hostname=\"%s\"\n", + http, httpAddrString(http->hostaddr, filename, sizeof(filename)), http->hostname)); + + /* + * See if we are accessing localhost... + */ + + if (!httpAddrLocalhost(http->hostaddr) && + strcasecmp(http->hostname, "localhost") != 0) + { + DEBUG_puts("cups_local_auth: Not a local connection!"); + return (-1); + } + + /* + * Try opening a certificate file for this PID. If that fails, + * try the root certificate... + */ + + pid = getpid(); + snprintf(filename, sizeof(filename), "%s/certs/%d", cg->cups_statedir, pid); + if ((fp = fopen(filename, "r")) == NULL && pid > 0) + { + DEBUG_printf(("cups_local_auth: Unable to open file %s: %s\n", + filename, strerror(errno))); + + snprintf(filename, sizeof(filename), "%s/certs/0", cg->cups_statedir); + fp = fopen(filename, "r"); + } + + if (fp == NULL) + { + DEBUG_printf(("cups_local_auth: Unable to open file %s: %s\n", + filename, strerror(errno))); + return (-1); + } + + /* + * Read the certificate from the file... + */ + + fgets(certificate, sizeof(certificate), fp); + fclose(fp); + + /* + * Set the authorization string and return... + */ + + snprintf(http->authstring, sizeof(http->authstring), "Local %s", certificate); + + DEBUG_printf(("cups_local_auth: Returning authstring = \"%s\"\n", + http->authstring)); + + return (0); +#endif /* WIN32 || __EMX__ */ +} + + +/* + * End of "$Id: auth.c 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/backchannel.c b/cups/backchannel.c new file mode 100644 index 000000000..3cb3a0def --- /dev/null +++ b/cups/backchannel.c @@ -0,0 +1,201 @@ +/* + * "$Id: backchannel.c 4828 2005-11-11 12:53:38Z mike $" + * + * Backchannel functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsBackChannelRead() - Read data from the backchannel. + * cupsBackChannelWrite() - Write data to the backchannel. + * cups_setup() - Setup select() + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include +#ifdef WIN32 +# include +# include +#else +# include +#endif /* WIN32 */ + + +/* + * Local functions... + */ + +static void cups_setup(fd_set *set, struct timeval *tval, + double timeout); + + +/* + * 'cupsBackChannelRead()' - Read data from the backchannel. + * + * Reads up to "bytes" bytes from the backchannel. The "timeout" + * parameter controls how many seconds to wait for the data - use + * 0.0 to return immediately if there is no data, -1.0 to wait + * for data indefinitely. + * + * @since CUPS 1.2@ + */ + +int /* O - Bytes read or -1 on error */ +cupsBackchannelRead(char *buffer, /* I - Buffer to read */ + int bytes, /* I - Bytes to read */ + double timeout) /* I - Timeout in seconds */ +{ + fd_set input; /* Input set */ + struct timeval tval; /* Timeout value */ + int status; /* Select status */ + + + /* + * Wait for input ready. + */ + + do + { + cups_setup(&input, &tval, timeout); + + if (timeout < 0.0) + status = select(4, &input, NULL, NULL, NULL); + else + status = select(4, &input, NULL, NULL, &tval); + } + while (status < 0 && errno != EINTR); + + if (status < 0) + return (-1); /* Timeout! */ + + /* + * Read bytes from the pipe... + */ + + return (read(3, buffer, bytes)); +} + + +/* + * 'cupsBackChannelWrite()' - Write data to the backchannel. + * + * Writes "bytes" bytes to the backchannel. The "timeout" parameter + * controls how many seconds to wait for the data to be written - use + * 0.0 to return immediately if the data cannot be written, -1.0 to wait + * indefinitely. + * + * @since CUPS 1.2@ + */ + +int /* O - Bytes written or -1 on error */ +cupsBackchannelWrite( + const char *buffer, /* I - Buffer to write */ + int bytes, /* I - Bytes to write */ + double timeout) /* I - Timeout in seconds */ +{ + fd_set output; /* Output set */ + struct timeval tval; /* Timeout value */ + int status; /* Select status */ + int count, /* Current bytes */ + total; /* Total bytes */ + + + /* + * Write all bytes... + */ + + total = 0; + + while (total < bytes) + { + /* + * Wait for write-ready... + */ + + do + { + cups_setup(&output, &tval, timeout); + + if (timeout < 0.0) + status = select(4, NULL, &output, NULL, NULL); + else + status = select(4, NULL, &output, NULL, &tval); + } + while (status < 0 && errno != EINTR); + + if (status < 0) + return (-1); /* Timeout! */ + + /* + * Write bytes to the pipe... + */ + + count = write(3, buffer, bytes - total); + + if (count < 0) + { + /* + * Write error - abort on fatal errors... + */ + + if (errno != EINTR && errno != EAGAIN) + return (-1); + } + else + { + /* + * Write succeeded, update buffer pointer and total count... + */ + + buffer += count; + total += count; + } + } + + return (bytes); +} + + +/* + * 'cups_setup()' - Setup select() + */ + +static void +cups_setup(fd_set *set, /* I - Set for select() */ + struct timeval *tval, /* I - Timer value */ + double timeout) /* I - Timeout in seconds */ +{ + tval->tv_sec = (int)timeout; + tval->tv_usec = (int)(1000000.0 * (timeout - tval->tv_sec)); + + FD_ZERO(set); + FD_SET(3, set); +} + + +/* + * End of "$Id: backchannel.c 4828 2005-11-11 12:53:38Z mike $". + */ diff --git a/cups/backend.h b/cups/backend.h new file mode 100644 index 000000000..199780a05 --- /dev/null +++ b/cups/backend.h @@ -0,0 +1,50 @@ +/* + * "$Id: backend.h 4703 2005-09-26 19:33:58Z mike $" + * + * Backend definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_BACKEND_H_ +# define _CUPS_BACKEND_H_ + + +/* + * Constants... + */ + +typedef enum cups_backend_e /**** Backend exit codes ****/ +{ + CUPS_BACKEND_OK = 0, /* Job completed successfully */ + CUPS_BACKEND_FAILED = 1, /* Job failed, use error-policy */ + CUPS_BACKEND_CANCEL = 2, /* Job failed, cancel job */ + CUPS_BACKEND_HOLD = 3, /* Job failed, hold job */ + CUPS_BACKEND_STOP = 4, /* Job failed, stop queue */ + CUPS_BACKEND_AUTH_REQUIRED = 5 /* Job failed, authentication required */ +} cups_backend_t; + + +#endif /* !_CUPS_BACKEND_H_ */ + +/* + * End of "$Id: backend.h 4703 2005-09-26 19:33:58Z mike $". + */ diff --git a/cups/cups.h b/cups/cups.h new file mode 100644 index 000000000..84a0f3793 --- /dev/null +++ b/cups/cups.h @@ -0,0 +1,237 @@ +/* + * "$Id: cups.h 4918 2006-01-12 05:14:40Z mike $" + * + * API definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_CUPS_H_ +# define _CUPS_CUPS_H_ + +/* + * Include necessary headers... + */ + +# include "ipp.h" +# include "ppd.h" + +/* + * With GCC 3.0 and higher, we can mark old APIs "deprecated" so you get + * an error at compile-time. + */ + +# if defined(__GNUC__) && __GNUC__ > 2 +# define _CUPS_DEPRECATED __attribute__ ((__deprecated__)) +# else +# define _CUPS_DEPRECATED +# endif /* __GNUC__ && __GNUC__ > 2 */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Constants... + */ + +# define CUPS_VERSION 1.0190 +# define CUPS_VERSION_MAJOR 1 +# define CUPS_VERSION_MINOR 2 +# define CUPS_VERSION_PATCH -10 +# define CUPS_DATE_ANY -1 + + +/* + * Types and structures... + */ + +typedef unsigned cups_ptype_t; /**** Printer Type/Capability Bits ****/ +enum cups_ptype_e /* 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_FAX = 0x40000, /* Fax queue */ + CUPS_PRINTER_REJECTING = 0x80000, /* Printer is rejecting jobs */ + CUPS_PRINTER_DELETE = 0x100000, /* Delete printer @since CUPS 1.2@ */ + CUPS_PRINTER_NOT_SHARED = 0x200000, /* Printer is not shared @since CUPS 1.2@ */ + CUPS_PRINTER_AUTHENTICATED = 0x400000,/* Printer requires authentication @since CUPS 1.2@ */ + CUPS_PRINTER_OPTIONS = 0x66fffc /* ~(CLASS | REMOTE | IMPLICIT) */ +}; + +typedef const char *(*cups_password_cb_t)(const char *); + +typedef struct cups_option_s /**** Printer Options ****/ +{ + char *name; /* Name of option */ + char *value; /* Value of option */ +} cups_option_t; + +typedef struct cups_dest_s /**** 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 cups_job_s /**** 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) _CUPS_DEPRECATED; +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) _CUPS_DEPRECATED; +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) _CUPS_DEPRECATED; +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(cups_password_cb_t cb); +extern void cupsSetServer(const char *server); +extern void cupsSetUser(const char *user); +extern const char *cupsUser(void); + +/**** New in CUPS 1.1.20 ****/ +extern int cupsDoAuthentication(http_t *http, const char *method, + const char *resource); +extern http_status_t cupsGetFile(http_t *http, const char *resource, + const char *filename); +extern http_status_t cupsGetFd(http_t *http, const char *resource, int fd); +extern http_status_t cupsPutFile(http_t *http, const char *resource, + const char *filename); +extern http_status_t cupsPutFd(http_t *http, const char *resource, int fd); + +/**** New in CUPS 1.1.21 ****/ +extern const char *cupsGetDefault2(http_t *http); +extern int cupsGetDests2(http_t *http, cups_dest_t **dests); +extern int cupsGetJobs2(http_t *http, cups_job_t **jobs, + const char *dest, int myjobs, + int completed); +extern const char *cupsGetPPD2(http_t *http, const char *printer); +extern int cupsPrintFile2(http_t *http, const char *printer, + const char *filename, + const char *title, int num_options, + cups_option_t *options); +extern int cupsPrintFiles2(http_t *http, const char *printer, + int num_files, const char **files, + const char *title, int num_options, + cups_option_t *options); +extern int cupsSetDests2(http_t *http, int num_dests, + cups_dest_t *dests); + +/**** New in CUPS 1.2 ****/ +extern int cupsBackchannelRead(char *buffer, int bytes, double timeout); +extern int cupsBackchannelWrite(const char *buffer, int bytes, + double timeout); +extern void cupsEncodeOptions2(ipp_t *ipp, int num_options, + cups_option_t *options, + ipp_tag_t group_tag); +extern const char *cupsLastErrorString(void); +extern cups_file_t *cupsTempFile2(char *filename, int len); + + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_CUPS_H_ */ + +/* + * End of "$Id: cups.h 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/debug.h b/cups/debug.h new file mode 100644 index 000000000..65b1fa224 --- /dev/null +++ b/cups/debug.h @@ -0,0 +1,59 @@ +/* + * "$Id: debug.h 4493 2005-02-18 02:09:53Z mike $" + * + * Debugging macros for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_DEBUG_H_ +# define _CUPS_DEBUG_H_ + +/* + * Include necessary headers... + */ + +# include + +/* + * The debug macros are used if you compile with DEBUG defined. + * + * Usage: + * + * DEBUG_puts("string") + * DEBUG_printf(("format string", arg, arg, ...)); + * + * Note the extra parenthesis around the DEBUG_printf macro... + */ + +# ifdef DEBUG +# define DEBUG_puts(x) puts(x) +# define DEBUG_printf(x) printf x +# else +# define DEBUG_puts(x) +# define DEBUG_printf(x) +# endif /* DEBUG */ + +#endif /* !_CUPS_DEBUG_H_ */ + +/* + * End of "$Id: debug.h 4493 2005-02-18 02:09:53Z mike $". + */ diff --git a/cups/dest.c b/cups/dest.c new file mode 100644 index 000000000..042e7b54b --- /dev/null +++ b/cups/dest.c @@ -0,0 +1,865 @@ +/* + * "$Id: dest.c 4918 2006-01-12 05:14:40Z mike $" + * + * User-defined destination (and option) support for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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 from the default server. + * cupsGetDests2() - Get the list of destinations from the specified server. + * cupsSetDests() - Set the list of destinations for the default server. + * cupsSetDests2() - Set the list of destinations for the specified server. + * cups_get_dests() - Get destinations from a file. + * cups_get_sdests() - Get destinations from a server. + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include +#include + + +/* + * Local functions... + */ + +static int cups_get_dests(const char *filename, int num_dests, + cups_dest_t **dests); +static int cups_get_sdests(http_t *http, ipp_op_t op, int num_dests, + cups_dest_t **dests); + + +/* + * 'cupsAddDest()' - Add a destination to the list of destinations. + * + * Use the cupsSaveDests() function to save the updated list of destinations + * to the user's lpoptions file. + */ + +int /* O - New number of destinations */ +cupsAddDest(const char *name, /* I - Name of destination */ + const char *instance, /* I - Instance of destination or NULL for none/primary */ + 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. + * + * Use the cupsGetDests() or cupsGetDests2() functions to get a + * list of supported destinations for the current user. + */ + +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 from the default server. + */ + +int /* O - Number of destinations */ +cupsGetDests(cups_dest_t **dests) /* O - Destinations */ +{ + int num_dests; /* Number of destinations */ + http_t *http; /* HTTP connection */ + + + /* + * Connect to the CUPS server and get the destination list and options... + */ + + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + num_dests = cupsGetDests2(http, dests); + + if (http) + httpClose(http); + + return (num_dests); +} + + +/* + * 'cupsGetDests2()' - Get the list of destinations from the specified server. + * + * @since CUPS 1.1.21@ + */ + +int /* O - Number of destinations */ +cupsGetDests2(http_t *http, /* I - HTTP connection */ + 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 */ + _cups_globals_t *cg = _cupsGlobals(); /* Global data */ + + + /* + * Range check the input... + */ + + if (!http || !dests) + return (0); + + /* + * Initialize destination array... + */ + + num_dests = 0; + *dests = (cups_dest_t *)0; + + /* + * Grab the printers and classes... + */ + + num_dests = cups_get_sdests(http, CUPS_GET_PRINTERS, num_dests, dests); + num_dests = cups_get_sdests(http, 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 = cupsGetDefault2(http)) != NULL) + { + /* + * Grab printer and instance name... + */ + + strlcpy(name, defprinter, sizeof(name)); + + 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... + */ + + snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); + num_dests = cups_get_dests(filename, 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()' - Save the list of destinations for the default server. + * + * This function saves the destinations to /etc/cups/lpoptions when run + * as root and ~/.lpoptions when run as a normal user. + */ + +void +cupsSetDests(int num_dests, /* I - Number of destinations */ + cups_dest_t *dests) /* I - Destinations */ +{ + http_t *http; /* HTTP connection */ + + + /* + * Connect to the CUPS server and save the destination list and options... + */ + + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + cupsSetDests2(http, num_dests, dests); + + if (http) + httpClose(http); +} + + +/* + * 'cupsSetDests2()' - Save the list of destinations for the specified server. + * + * This function saves the destinations to /etc/cups/lpoptions when run + * as root and ~/.lpoptions when run as a normal user. + * + * @since CUPS 1.1.21@ + */ + +int /* O - 0 on success, -1 on error */ +cupsSetDests2(http_t *http, /* I - HTTP connection */ + 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 */ + _cups_globals_t *cg = _cupsGlobals(); /* Global data */ + + + /* + * Range check the input... + */ + + if (!http || !num_dests || !dests) + return (-1); + + /* + * Get the server destinations... + */ + + num_temps = cups_get_sdests(http, CUPS_GET_PRINTERS, 0, &temps); + num_temps = cups_get_sdests(http, CUPS_GET_CLASSES, num_temps, &temps); + + /* + * Figure out which file to write to... + */ + + snprintf(filename, sizeof(filename), "%s/lpoptions", cg->cups_serverroot); + +#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 (-1); + } + + /* + * 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); + + return (0); +} + + +/* + * '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] & 255)) + lineptr = line + 4; + else if (strncasecmp(line, "default", 7) == 0 && isspace(line[7] & 255)) + lineptr = line + 7; + else + continue; + + /* + * Skip leading whitespace... + */ + + while (isspace(*lineptr & 255)) + lineptr ++; + + if (!*lineptr) + continue; + + name = lineptr; + + /* + * Search for an instance... + */ + + while (!isspace(*lineptr & 255) && *lineptr && *lineptr != '/') + lineptr ++; + + if (!*lineptr) + continue; + + if (*lineptr == '/') + { + /* + * Found an instance... + */ + + *lineptr++ = '\0'; + instance = lineptr; + + /* + * Search for an instance... + */ + + while (!isspace(*lineptr & 255) && *lineptr) + lineptr ++; + } + else + instance = NULL; + + *lineptr++ = '\0'; + + /* + * See if the primary instance of the destination exists; if not, + * ignore this entry and move on... + */ + + if (cupsGetDest(name, NULL, num_dests, *dests) == NULL) + continue; + + /* + * 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(http_t *http, /* I - HTTP connection */ + 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 */ + 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 * const pattrs[] = /* Attributes we're interested in */ + { + "printer-name", + "job-sheets-default" + }; + + + /* + * 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); + + cupsLangFree(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); + } + + /* + * Return the count... + */ + + return (num_dests); +} + + +/* + * End of "$Id: dest.c 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/dir.c b/cups/dir.c new file mode 100644 index 000000000..e06edea91 --- /dev/null +++ b/cups/dir.c @@ -0,0 +1,437 @@ +/* + * "$Id$" + * + * Public directory routines for the Common UNIX Printing System (CUPS). + * + * This set of APIs abstracts enumeration of directory entries. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * _cups_dir_time() - Convert a FILETIME value to a UNIX time value. + * cupsDirClose() - Close a directory. + * cupsDirOpen() - Open a directory. + * cupsDirRead() - Read the next directory entry. + * cupsDirRewind() - Rewind to the start of the directory. + * cupsDirClose() - Close a directory. + * cupsDirOpen() - Open a directory. + * cupsDirRead() - Read the next directory entry. + * cupsDirRewind() - Rewind to the start of the directory. + */ + +/* + * Include necessary headers... + */ + +#include "dir.h" +#include "string.h" +#include "debug.h" +#include +#include + + +/* + * Windows implementation... + */ + +#ifdef WIN32 +# include + +/* + * Types and structures... + */ + +struct _cups_dir_s /**** Directory data structure ****/ +{ + char directory[1024]; /* Directory filename */ + HANDLE dir; /* Directory handle */ + cups_dentry_t entry; /* Directory entry */ +}; + + +/* + * '_cups_dir_time()' - Convert a FILETIME value to a UNIX time value. + */ + +time_t /* O - UNIX time */ +_cups_dir_time(FILETIME ft) /* I - File time */ +{ + ULONGLONG val; /* File time in 0.1 usecs */ + + + /* + * Convert file time (1/10 microseconds since Jan 1, 1601) to UNIX + * time (seconds since Jan 1, 1970). There are 11,644,732,800 seconds + * between them... + */ + + val = ft.dwLowDateTime + (ft.dwHighDateTime << 32); + return ((time_t)(val / 10000000 - 11644732800)); +} + + +/* + * 'cupsDirClose()' - Close a directory. + */ + +void +cupsDirClose(cups_dir_t *dp) /* I - Directory */ +{ + /* + * Range check input... + */ + + if (!dp) + return; + + /* + * Close an open directory handle... + */ + + if (dp->dir != INVALID_HANDLE_VALUE) + FindClose(dp->dir); + + /* + * Free memory used... + */ + + free(dp); +} + + +/* + * 'cupsDirOpen()' - Open a directory. + */ + +cups_dir_t * /* O - Directory */ +cupsDirOpen(const char *directory) /* I - Directory name */ +{ + cups_dir_t *dp; /* Directory */ + + + /* + * Range check input... + */ + + if (!directory) + return (NULL); + + /* + * Allocate memory for the directory structure... + */ + + dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t)); + if (!dp) + return (NULL); + + /* + * Copy the directory name for later use... + */ + + dp->dir = INVALID_HANDLE_VALUE; + + strlcpy(dp->directory, directory, sizeof(dp->directory)); + + /* + * Return the new directory structure... + */ + + return (dp); +} + + +/* + * 'cupsDirRead()' - Read the next directory entry. + */ + +cups_dentry_t * /* O - Directory entry */ +cupsDirRead(cups_dir_t *dp) /* I - Directory */ +{ + WIN32_FIND_DATA entry; /* Directory entry data */ + + + /* + * Range check input... + */ + + if (!dp) + return (NULL); + + /* + * See if we have already started finding files... + */ + + if (dp->dir == INVALID_HANDLE_VALUE) + { + /* + * No, find the first file... + */ + + dp->dir = FindFirstFile(dp->directory, &entry); + if (dp->dir == INVALID_HANDLE_VALUE) + return (NULL); + } + else if (!FindNextFile(dp->dir, &entry)) + return (NULL); + + /* + * Copy the name over and convert the file information... + */ + + strlcpy(dp->entry.filename, entry.cFileName, sizeof(dp->entry.filename)); + + if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + dp->entry.fileinfo.st_mode = 0755 | S_IFDIR; + else + dp->entry.fileinfo.st_mode = 0644; + + dp->entry.fileinfo.st_atime = _cups_dir_time(entry.ftLastAccessTime); + dp->entry.fileinfo.st_ctime = _cups_dir_time(entry.ftCreationTime); + dp->entry.fileinfo.st_mtime = _cups_dir_time(entry.ftLastWriteTime); + dp->entry.fileinfo.st_size = entry.nFileSizeLow + (entry.nFileSizeHigh << 32); + + /* + * Return the entry... + */ + + return (&(dp->entry)); +} + + +/* + * 'cupsDirRewind()' - Rewind to the start of the directory. + */ + +void +cupsDirRewind(cups_dir_t *dp) /* I - Directory */ +{ + /* + * Range check input... + */ + + if (!dp) + return; + + /* + * Close an open directory handle... + */ + + if (dp->dir != INVALID_HANDLE_VALUE) + { + FindClose(dp->dir); + dp->dir = INVALID_HANDLE_VALUE; + } +} + + +#else + +/* + * POSIX implementation... + */ + +# include +# include + + +/* + * Types and structures... + */ + +struct _cups_dir_s /**** Directory data structure ****/ +{ + char directory[1024]; /* Directory filename */ + DIR *dir; /* Directory file */ + cups_dentry_t entry; /* Directory entry */ +}; + + +/* + * 'cupsDirClose()' - Close a directory. + */ + +void +cupsDirClose(cups_dir_t *dp) /* I - Directory */ +{ + DEBUG_printf(("cupsDirClose(dp=%p)\n", dp)); + + /* + * Range check input... + */ + + if (!dp) + return; + + /* + * Close the directory and free memory... + */ + + closedir(dp->dir); + free(dp); +} + + +/* + * 'cupsDirOpen()' - Open a directory. + */ + +cups_dir_t * /* O - Directory */ +cupsDirOpen(const char *directory) /* I - Directory name */ +{ + cups_dir_t *dp; /* Directory */ + + + DEBUG_printf(("cupsDirOpen(directory=\"%s\")\n", directory)); + + /* + * Range check input... + */ + + if (!directory) + return (NULL); + + /* + * Allocate memory for the directory structure... + */ + + dp = (cups_dir_t *)calloc(1, sizeof(cups_dir_t)); + if (!dp) + return (NULL); + + /* + * Open the directory... + */ + + dp->dir = opendir(directory); + if (!dp->dir) + { + free(dp); + return (NULL); + } + + /* + * Copy the directory name for later use... + */ + + strlcpy(dp->directory, directory, sizeof(dp->directory)); + + /* + * Return the new directory structure... + */ + + return (dp); +} + + +/* + * 'cupsDirRead()' - Read the next directory entry. + */ + +cups_dentry_t * /* O - Directory entry */ +cupsDirRead(cups_dir_t *dp) /* I - Directory */ +{ + char buffer[sizeof(struct dirent) + 1024]; + /* Directory entry buffer */ + struct dirent *entry; /* Pointer to entry */ + char filename[1024]; /* Full filename */ + + + DEBUG_printf(("cupsDirRead(dp=%p)\n", dp)); + + /* + * Range check input... + */ + + if (!dp) + return (NULL); + + /* + * Try reading an entry that is not "." or ".."... + */ + + do + { + if (readdir_r(dp->dir, (struct dirent *)buffer, &entry)) + { + DEBUG_printf((" readdir_r() failed - %s\n", strerror(errno))); + return (NULL); + } + + if (!entry) + { + DEBUG_puts(" readdir_r() returned a NULL pointer!"); + return (NULL); + } + + DEBUG_printf((" readdir_r() returned \"%s\"...\n", entry->d_name)); + } + while (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")); + + /* + * Copy the name over and get the file information... + */ + + strlcpy(dp->entry.filename, entry->d_name, sizeof(dp->entry.filename)); + + snprintf(filename, sizeof(filename), "%s/%s", dp->directory, entry->d_name); + if (stat(filename, &(dp->entry.fileinfo))) + { + DEBUG_printf((" stat() failed for \"%s\" - %s...\n", filename, + strerror(errno))); + return (NULL); + } + + /* + * Return the entry... + */ + + return (&(dp->entry)); +} + + +/* + * 'cupsDirRewind()' - Rewind to the start of the directory. + */ + +void +cupsDirRewind(cups_dir_t *dp) /* I - Directory */ +{ + DEBUG_printf(("cupsDirRewind(dp=%p)\n", dp)); + + /* + * Range check input... + */ + + if (!dp) + return; + + /* + * Rewind the directory... + */ + + rewinddir(dp->dir); +} + + +#endif /* WIN32 */ + +/* + * End of "$Id$". + */ diff --git a/cups/dir.h b/cups/dir.h new file mode 100644 index 000000000..0fd52e8f1 --- /dev/null +++ b/cups/dir.h @@ -0,0 +1,77 @@ +/* + * "$Id$" + * + * Public directory definitions for the Common UNIX Printing System (CUPS). + * + * This set of APIs abstracts enumeration of directory entries. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_DIR_H_ +# define _CUPS_DIR_H_ + + +/* + * Include necessary headers... + */ + +# include + + +/* + * C++ magic... + */ + +# ifdef _cplusplus +extern "C" { +# endif /* _cplusplus */ + + +/* + * Data types... + */ + +typedef struct _cups_dir_s cups_dir_t; /**** Directory type ****/ + +typedef struct cups_dentry_s /**** Directory entry type ****/ +{ + char filename[260]; /* File name */ + struct stat fileinfo; /* File information */ +} cups_dentry_t; + + +/* + * Prototypes... + */ + +extern void cupsDirClose(cups_dir_t *dp); +extern cups_dir_t *cupsDirOpen(const char *directory); +extern cups_dentry_t *cupsDirRead(cups_dir_t *dp); +extern void cupsDirRewind(cups_dir_t *dp); + + +# ifdef _cplusplus +} +# endif /* _cplusplus */ +#endif /* !_CUPS_DIR_H_ */ + +/* + * End of "$Id$". + */ diff --git a/cups/emit.c b/cups/emit.c new file mode 100644 index 000000000..88ebc226c --- /dev/null +++ b/cups/emit.c @@ -0,0 +1,816 @@ +/* + * "$Id: emit.c 4785 2005-10-13 19:39:05Z mike $" + * + * PPD code emission routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * ppdCollect() - Collect all marked options that reside in the + * specified section. + * 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. + * ppdEmitJCLEnd() - Emit JCLEnd code to a file. + * ppd_handle_media() - Handle media selection... + * ppd_sort() - Sort options by ordering numbers... + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include +#include "string.h" + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local functions... + */ + +static void ppd_handle_media(ppd_file_t *ppd); +static int ppd_sort(ppd_choice_t **c1, ppd_choice_t **c2); + + +/* + * Local globals... + */ + +static const char ppd_custom_code[] = + "pop pop pop\n" + "<>setpagedevice\n"; + + +/* + * '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 */ + + + /* + * Use PageSize or PageRegion as required... + */ + + ppd_handle_media(ppd); + + /* + * Collect the options we need to emit and emit them! + */ + + 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 ((strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageSize") == 0 || + strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageRegion") == 0) && + strcasecmp(choices[i]->choice, "Custom") == 0) + { + /* + * Variable size; write out standard size options, using the + * parameter positions defined in the PPD file... + */ + + ppd_attr_t *attr; /* PPD attribute */ + int pos, /* Position of custom value */ + values[5], /* Values for custom command */ + orientation; /* Orientation to use */ + + + fputs("%%BeginFeature: *CustomPageSize True\n", fp); + + size = ppdPageSize(ppd, "Custom"); + + memset(values, 0, sizeof(values)); + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL) + { + pos = atoi(attr->value) - 1; + + if (pos < 0 || pos > 4) + pos = 0; + } + else + pos = 0; + + values[pos] = (int)size->width; + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL) + { + pos = atoi(attr->value) - 1; + + if (pos < 0 || pos > 4) + pos = 1; + } + else + pos = 1; + + values[pos] = (int)size->length; + + /* + * According to the Adobe PPD specification, an orientation of 1 + * will produce a print that comes out upside-down with the X + * axis perpendicular to the direction of feed, which is exactly + * what we want to be consistent with non-PS printers. + * + * We could also use an orientation of 3 to produce output that + * comes out rightside-up (this is the default for many large format + * printer PPDs), however for consistency we will stick with the + * value 1. + * + * If we wanted to get fancy, we could use orientations of 0 or + * 2 and swap the width and length, however we don't want to get + * fancy, we just want it to work consistently. + * + * The orientation value is range limited by the Orientation + * parameter definition, so certain non-PS printer drivers that + * only support an Orientation of 0 will get the value 0 as + * expected. + */ + + orientation = 1; + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", + "Orientation")) != NULL) + { + int min_orient, max_orient; /* Minimum and maximum orientations */ + + + if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient, + &max_orient) != 3) + pos = 4; + else + { + pos --; + + if (pos < 0 || pos > 4) + pos = 4; + + if (orientation > max_orient) + orientation = max_orient; + else if (orientation < min_orient) + orientation = min_orient; + } + } + else + pos = 4; + + values[pos] = orientation; + + fprintf(fp, "%d %d %d %d %d\n", values[0], values[1], + values[2], values[3], values[4]); + + 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(ppd_custom_code, fp); + } + } + else if (fprintf(fp, "%%%%BeginFeature: *%s %s\n", + ((ppd_option_t *)choices[i]->option)->keyword, + choices[i]->choice) < 0) + { + free(choices); + return (-1); + } + + 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 */ + custom_size; /* Non-zero if this option is a custom size */ + ppd_choice_t **choices; /* Choices */ + ppd_size_t *size; /* Custom page size */ + char buf[1024]; /* Output buffer for feature */ + + + /* + * Use PageSize or PageRegion as required... + */ + + ppd_handle_media(ppd); + + /* + * Collect the options we need to emit and emit them! + */ + + 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... + */ + + if ((strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageSize") == 0 || + strcasecmp(((ppd_option_t *)choices[i]->option)->keyword, "PageRegion") == 0) && + strcasecmp(choices[i]->choice, "Custom") == 0) + { + custom_size = 1; + + strcpy(buf, "%%BeginFeature: *CustomPageSize True\n"); + } + else + { + custom_size = 0; + + 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 (custom_size) + { + /* + * Variable size; write out standard size options, using the + * parameter positions defined in the PPD file... + */ + + ppd_attr_t *attr; /* PPD attribute */ + int pos, /* Position of custom value */ + values[5], /* Values for custom command */ + orientation; /* Orientation to use */ + + + size = ppdPageSize(ppd, "Custom"); + + memset(values, 0, sizeof(values)); + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Width")) != NULL) + { + pos = atoi(attr->value) - 1; + + if (pos < 0 || pos > 4) + pos = 0; + } + else + pos = 0; + + values[pos] = (int)size->width; + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", "Height")) != NULL) + { + pos = atoi(attr->value) - 1; + + if (pos < 0 || pos > 4) + pos = 1; + } + else + pos = 1; + + values[pos] = (int)size->length; + + if (size->width < size->length) + orientation = 1; + else + orientation = 0; + + if ((attr = ppdFindAttr(ppd, "ParamCustomPageSize", + "Orientation")) != NULL) + { + int min_orient, max_orient; /* Minimum and maximum orientations */ + + + if (sscanf(attr->value, "%d%*s%d%d", &pos, &min_orient, + &max_orient) != 3) + pos = 4; + else + { + pos --; + + if (pos < 0 || pos > 4) + pos = 4; + + if (orientation > max_orient) + orientation = max_orient; + else if (orientation < min_orient) + orientation = min_orient; + } + } + else + pos = 4; + + values[pos] = orientation; + + snprintf(buf, sizeof(buf), "%d %d %d %d %d\n", values[0], values[1], + values[2], values[3], values[4]); + + if (write(fd, buf, strlen(buf)) < 1) + { + free(choices); + return (-1); + } + + 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... + */ + + if (write(fd, ppd_custom_code, strlen(ppd_custom_code)) < 1) + { + free(choices); + return (-1); + } + } + } + + if (choices[i]->code != NULL && choices[i]->code[0] != '\0') + { + 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 */ +{ + char *ptr; /* Pointer into JCL string */ + char temp[81]; /* Local title 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)) + { + /* + * This printer uses HP PJL commands for output; filter the output + * so that we only have a single "@PJL JOB" command in the header... + * + * To avoid bugs in the PJL implementation of certain vendors' products + * (Xerox in particular), we add a dummy "@PJL" command at the beginning + * of the PJL commands to initialize PJL processing. + */ + + fputs("\033%-12345X@PJL\n", fp); + for (ptr = ppd->jcl_begin + 9; *ptr;) + if (!strncmp(ptr, "@PJL JOB", 8)) + { + /* + * 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; + + /* + * Replace double quotes with single quotes so that the title + * does not cause a PJL syntax error. + */ + + strlcpy(temp, title, sizeof(temp)); + + for (ptr = temp; *ptr; ptr ++) + if (*ptr == '\"') + *ptr = '\''; + + /* + * Send PJL JOB and PJL RDYMSG commands before we enter PostScript mode... + */ + + fprintf(fp, "@PJL JOB NAME = \"%s\" DISPLAY = \"%d %s %s\"\n", temp, + job_id, user, temp); + fprintf(fp, "@PJL RDYMSG DISPLAY = \"%d %s %s\"\n", job_id, user, temp); + } + else + fputs(ppd->jcl_begin, fp); + + ppdEmit(ppd, fp, PPD_ORDER_JCL); + fputs(ppd->jcl_ps, fp); + + return (0); +} + + +/* + * 'ppdEmitJCLEnd()' - Emit JCLEnd code to a file. + * + * @since CUPS 1.2@ + */ + +int /* O - 0 on success, -1 on failure */ +ppdEmitJCLEnd(ppd_file_t *ppd, /* I - PPD file record */ + FILE *fp) /* I - File to write to */ +{ + ppd_attr_t *attr; /* PPD attributes */ + + + /* + * Range check the input... + */ + + if (ppd == NULL) + return (0); + + if (ppd->jcl_end == NULL) + { + if (ppd->num_filters == 0) + fputc(0x04, fp); + + if ((attr = ppdFindAttr(ppd, "cupsProtocol", NULL)) != NULL && + attr->value != NULL && !strcasecmp(attr->value, "TBCP")) + fputs("\033%-12345X", stdout); + + return (0); + } + + /* + * See if the printer supports HP PJL... + */ + + if (!strncmp(ppd->jcl_end, "\033%-12345X@", 10)) + { + /* + * This printer uses HP PJL commands for output; filter the output + * so that we only have a single "@PJL JOB" command in the header... + * + * To avoid bugs in the PJL implementation of certain vendors' products + * (Xerox in particular), we add a dummy "@PJL" command at the beginning + * of the PJL commands to initialize PJL processing. + */ + + fputs("\033%-12345X@PJL\n", fp); + fputs("@PJL RDYMSG DISPLAY = \"READY\"\n", fp); + fputs(ppd->jcl_end + 9, fp); + } + else + fputs(ppd->jcl_end, fp); + + return (0); +} + + +/* + * 'ppd_handle_media()' - Handle media selection... + */ + +static void +ppd_handle_media(ppd_file_t *ppd) +{ + ppd_choice_t *manual_feed, /* ManualFeed choice, if any */ + *input_slot, /* InputSlot choice, if any */ + *page; /* PageSize/PageRegion */ + ppd_size_t *size; /* Current media size */ + ppd_attr_t *rpr; /* RequiresPageRegion value */ + + + /* + * This function determines if the user has selected a media source + * via the InputSlot or ManualFeed options; if so, it marks the + * PageRegion option corresponding to the current media size. + * Otherwise it marks the PageSize option. + */ + + if ((size = ppdPageSize(ppd, NULL)) == NULL) + return; + + manual_feed = ppdFindMarkedChoice(ppd, "ManualFeed"); + input_slot = ppdFindMarkedChoice(ppd, "InputSlot"); + + if (input_slot != NULL) + rpr = ppdFindAttr(ppd, "RequiresPageRegion", input_slot->choice); + else + rpr = NULL; + + if (!rpr) + rpr = ppdFindAttr(ppd, "RequiresPageRegion", "All"); + + if (strcasecmp(size->name, "Custom") == 0 || + (manual_feed == NULL && input_slot == NULL) || + (manual_feed != NULL && strcasecmp(manual_feed->choice, "False") == 0) || + (input_slot != NULL && (input_slot->code == NULL || !input_slot->code[0]))) + { + /* + * Manual feed was not selected and/or the input slot selection does + * not contain any PostScript code. Use the PageSize option... + */ + + ppdMarkOption(ppd, "PageSize", size->name); + } + else + { + /* + * Manual feed was selected and/or the input slot selection contains + * PostScript code. Use the PageRegion option... + */ + + ppdMarkOption(ppd, "PageRegion", size->name); + + /* + * RequiresPageRegion does not apply to manual feed so we need to + * check that we are not doing manual feed before unmarking PageRegion. + */ + + if (!(manual_feed && !strcasecmp(manual_feed->choice, "True")) && + ((rpr && rpr->value && !strcmp(rpr->value, "False")) || + (!rpr && !ppd->num_filters))) + { + /* + * Either the PPD file specifies no PageRegion code or the PPD file + * not for a CUPS raster driver and thus defaults to no PageRegion + * code... Unmark the PageRegion choice so that we don't output the + * code... + */ + + page = ppdFindMarkedChoice(ppd, "PageRegion"); + + if (page) + page->marked = 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: emit.c 4785 2005-10-13 19:39:05Z mike $". + */ diff --git a/cups/encode.c b/cups/encode.c new file mode 100644 index 000000000..be1aab28d --- /dev/null +++ b/cups/encode.c @@ -0,0 +1,471 @@ +/* + * "$Id: encode.c 4918 2006-01-12 05:14:40Z mike $" + * + * Option encoding routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsEncodeOptions() - Encode printer options into IPP attributes. + * cupsEncodeOptions2() - Encode printer options into IPP attributes for + * a group. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include +#include +#include "string.h" +#include "debug.h" + + +/* + * Local list of option names and the value tags they should use... + */ + +typedef struct +{ + const char *name; + ipp_tag_t value_tag; + ipp_tag_t group_tag; +} _ipp_option_t; + +static const _ipp_option_t ipp_options[] = +{ + { "blackplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, + { "brightness", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "columns", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "copies", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "document-format", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION }, + { "finishings", IPP_TAG_ENUM, IPP_TAG_JOB }, + { "fitplot", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, + { "gamma", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "hue", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "job-k-limit", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "job-page-limit", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "job-priority", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "job-quota-period", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "landscape", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, + { "media", IPP_TAG_KEYWORD, IPP_TAG_JOB }, + { "mirror", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, + { "natural-scaling", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "notify-charset", IPP_TAG_CHARSET, IPP_TAG_SUBSCRIPTION }, + { "notify-events", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION }, + { "notify-lease-time", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION }, + { "notify-natural-language", IPP_TAG_LANGUAGE, IPP_TAG_SUBSCRIPTION }, + { "notify-pull-method", IPP_TAG_KEYWORD, IPP_TAG_SUBSCRIPTION }, + { "notify-recipient", IPP_TAG_URI, IPP_TAG_SUBSCRIPTION }, + { "notify-time-interval", IPP_TAG_INTEGER, IPP_TAG_SUBSCRIPTION }, + { "notify-user-data", IPP_TAG_STRING, IPP_TAG_SUBSCRIPTION }, + { "number-up", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "orientation-requested", IPP_TAG_ENUM, IPP_TAG_JOB }, + { "page-bottom", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "page-left", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "page-ranges", IPP_TAG_RANGE, IPP_TAG_JOB }, + { "page-right", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "page-top", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "penwidth", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "ppi", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "prettyprint", IPP_TAG_BOOLEAN, IPP_TAG_JOB }, + { "printer-resolution", IPP_TAG_RESOLUTION, IPP_TAG_JOB }, + { "printer-uri", IPP_TAG_URI, IPP_TAG_OPERATION }, + { "print-quality", IPP_TAG_ENUM, IPP_TAG_JOB }, + { "raw", IPP_TAG_MIMETYPE, IPP_TAG_OPERATION }, + { "saturation", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "scaling", IPP_TAG_INTEGER, IPP_TAG_JOB }, + { "sides", IPP_TAG_KEYWORD, IPP_TAG_JOB }, + { "wrap", IPP_TAG_BOOLEAN, IPP_TAG_JOB } +}; + + +/* + * 'cupsEncodeOptions()' - Encode printer options into IPP attributes. + * + * This function adds operation, job, and then subscription attributes, + * in that order. Use the cupsEncodeOptions2() function to add attributes + * for a single group. + */ + +void +cupsEncodeOptions(ipp_t *ipp, /* I - Request to add to */ + int num_options, /* I - Number of options */ + cups_option_t *options) /* I - Options */ +{ + DEBUG_printf(("cupsEncodeOptions(%p, %d, %p)\n", ipp, num_options, options)); + + /* + * Add the options in the proper groups & order... + */ + + cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_OPERATION); + cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_JOB); + cupsEncodeOptions2(ipp, num_options, options, IPP_TAG_SUBSCRIPTION); +} + + +/* + * 'cupsEncodeOptions2()' - Encode printer options into IPP attributes for a group. + * + * This function only adds attributes for a single group. Call this + * function multiple times for each group, or use cupsEncodeOptions() + * to add the standard groups. + * + * @since CUPS 1.2@ + */ + +void +cupsEncodeOptions2( + ipp_t *ipp, /* I - Request to add to */ + int num_options, /* I - Number of options */ + cups_option_t *options, /* I - Options */ + ipp_tag_t group_tag) /* I - Group to encode */ +{ + int i, j; /* Looping vars */ + int count; /* Number of values */ + char *s, /* Pointer into option value */ + *val, /* Pointer to option value */ + *copy, /* Copy of option value */ + *sep; /* Option separator */ + ipp_attribute_t *attr; /* IPP attribute */ + ipp_tag_t value_tag; /* IPP value tag */ + + + DEBUG_printf(("cupsEncodeOptions2(ipp=%p, num_options=%d, options=%p, group_tag=%x)\n", + ipp, num_options, options, group_tag)); + + /* + * Range check input... + */ + + if (ipp == NULL || num_options < 1 || options == NULL) + return; + + /* + * Do special handling for the document-format/raw options... + */ + + if (group_tag == IPP_TAG_OPERATION) + { + /* + * 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 loop through the options... + */ + + for (i = 0; i < num_options; i ++) + { + /* + * Skip document format options that are handled above... + */ + + if (!strcasecmp(options[i].name, "raw") || + !strcasecmp(options[i].name, "document-format") || + !options[i].name[0]) + continue; + + /* + * Figure out the proper value and group tags for this option... + */ + + for (j = 0; j < (int)(sizeof(ipp_options) / sizeof(ipp_options[0])); j ++) + if (!strcasecmp(options[i].name, ipp_options[j].name)) + break; + + if (j < (int)(sizeof(ipp_options) / sizeof(ipp_options[0]))) + { + if (ipp_options[j].group_tag != group_tag) + continue; + + value_tag = ipp_options[j].value_tag; + } + else if (group_tag != IPP_TAG_JOB) + continue; + else if (!strcasecmp(options[i].value, "true") || + !strcasecmp(options[i].value, "false")) + value_tag = IPP_TAG_BOOLEAN; + else + value_tag = IPP_TAG_NAME; + + /* + * Count the number of values... + */ + + for (count = 1, sep = options[i].value; *sep; sep ++) + { + if (*sep == '\'') + { + /* + * Skip quoted option value... + */ + + sep ++; + + while (*sep && *sep != '\'') + sep ++; + + if (!*sep) + sep --; + } + else if (*sep == '\"') + { + /* + * Skip quoted option value... + */ + + sep ++; + + while (*sep && *sep != '\"') + sep ++; + + if (!*sep) + sep --; + } + else if (*sep == ',') + count ++; + else if (*sep == '\\' && sep[1]) + sep ++; + } + + DEBUG_printf(("cupsEncodeOptions2: option = \'%s\', count = %d\n", + options[i].name, count)); + + /* + * Allocate memory for the attribute values... + */ + + if ((attr = _ipp_add_attr(ipp, count)) == NULL) + { + /* + * Ran out of memory! + */ + + DEBUG_puts("cupsEncodeOptions2: Ran out of memory for attributes!"); + return; + } + + /* + * Now figure out what type of value we have... + */ + + attr->group_tag = group_tag; + attr->value_tag = value_tag; + + /* + * Copy the name over... + */ + + if ((attr->name = strdup(options[i].name)) == NULL) + { + /* + * Ran out of memory! + */ + + DEBUG_puts("cupsEncodeOptions2: 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("cupsEncodeOptions2: 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; + } + + /* + * Scan the value string for values... + */ + + for (j = 0; j < count; 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); + + /* + * Copy the option value(s) over as needed by the type... + */ + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + /* + * Integer/enumeration value... + */ + + attr->values[j].integer = strtol(val, &s, 0); + + DEBUG_printf(("cupsEncodeOptions2: Added integer option value %d...\n", + attr->values[j].integer)); + break; + + case IPP_TAG_BOOLEAN : + if (!strcasecmp(val, "true") || + !strcasecmp(val, "on") || + !strcasecmp(val, "yes")) + { + /* + * Boolean value - true... + */ + + attr->values[j].boolean = 1; + + DEBUG_puts("cupsEncodeOptions2: Added boolean true value..."); + } + else + { + /* + * Boolean value - false... + */ + + attr->values[j].boolean = 0; + + DEBUG_puts("cupsEncodeOptions2: Added boolean false value..."); + } + break; + + case IPP_TAG_RANGE : + /* + * Range... + */ + + if (*val == '-') + { + attr->values[j].range.lower = 1; + s = val; + } + else + attr->values[j].range.lower = strtol(val, &s, 0); + + if (*s == '-') + { + if (s[1]) + attr->values[j].range.upper = strtol(s + 1, NULL, 0); + else + attr->values[j].range.upper = 2147483647; + } + else + attr->values[j].range.upper = attr->values[j].range.lower; + + DEBUG_printf(("cupsEncodeOptions2: Added range option value %d-%d...\n", + attr->values[j].range.lower, + attr->values[j].range.upper)); + break; + + case IPP_TAG_RESOLUTION : + /* + * Resolution... + */ + + attr->values[j].resolution.xres = strtol(val, &s, 0); + + if (*s == 'x') + attr->values[j].resolution.yres = strtol(s + 1, &s, 0); + else + attr->values[j].resolution.yres = attr->values[j].resolution.xres; + + if (strcasecmp(s, "dpc") == 0) + attr->values[j].resolution.units = IPP_RES_PER_CM; + else + attr->values[j].resolution.units = IPP_RES_PER_INCH; + + DEBUG_printf(("cupsEncodeOptions2: Added resolution option value %s...\n", + val)); + break; + + case IPP_TAG_STRING : + /* + * octet-string + */ + + attr->values[j].unknown.length = strlen(val); + attr->values[j].unknown.data = strdup(val); + + DEBUG_printf(("cupsEncodeOptions2: Added octet-string value \"%s\"...\n", + attr->values[j].unknown.data)); + break; + + default : + if ((attr->values[j].string.text = strdup(val)) == NULL) + { + /* + * Ran out of memory! + */ + + DEBUG_puts("cupsEncodeOptions2: Ran out of memory for string!"); + return; + } + + DEBUG_printf(("cupsEncodeOptions2: Added string value \"%s\"...\n", + val)); + break; + } + } + } +} + + +/* + * End of "$Id: encode.c 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/extended.c b/cups/extended.c new file mode 100644 index 000000000..6bc5cfae7 --- /dev/null +++ b/cups/extended.c @@ -0,0 +1,307 @@ +/* + * "$Id: extended.c 4494 2005-02-18 02:18:11Z mike $" + * + * Extended option routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * ppdFindExtOption() - Return a pointer to the extended option. + * ppdMarkCurve() - Mark an extended curve option. + * ppdMarkGamma() - Mark an extended gamma option. + * ppdMarkInteger() - Mark an extended integer option. + * ppdMarkIntegerArray() - Mark an extended integer array option. + * ppdMarkReal() - Mark an extended real option. + * ppdMarkRealArray() - Mark an extended real array option. + * ppdMarkText() - Mark an extended text option. + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include "string.h" +#include "debug.h" + + +/* + * Local functions... + */ + +static void ppd_unmark_choices(ppd_option_t *option); + + +/* + * 'ppdFindExtOption()' - Return a pointer to the extended option. + */ + +ppd_ext_option_t * /* O - Pointer to option or NULL */ +ppdFindExtOption(ppd_file_t *ppd, /* I - PPD file data */ + const char *option) /* I - Option/Keyword name */ +{ + int i; /* Looping var */ + ppd_ext_option_t **o; /* Pointer to option */ + + + if (ppd == NULL || option == NULL) + return (NULL); + + for (i = ppd->num_extended, o = ppd->extended; i > 0; i --, o ++) + if (strcasecmp(o[0]->keyword, option) == 0) + return (*o); + + return (NULL); +} + + +/* + * 'ppdFindExtParam()' - Find an extended parameter. + */ + +ppd_ext_param_t * /* O - Parameter or NULL */ +ppdFindExtParam(ppd_ext_option_t *opt, /* I - Option */ + const char *param)/* I - Parameter name */ +{ + int i; /* Looping var */ + ppd_ext_param_t **p; /* Pointer to parameter */ + + + if (opt == NULL || param == NULL) + return (NULL); + + for (i = opt->num_params, p = opt->params; i > 0; i --, p ++) + if (strcasecmp(p[0]->keyword, param) == 0) + return (*p); + + return (NULL); +} + + +/* + * 'ppdMarkCurve()' - Mark an extended curve option. + */ + +int /* O - Number of conflicts */ +ppdMarkCurve(ppd_file_t *ppd, /* I - PPD file */ + const char *keyword, /* I - Option name */ + const char *param, /* I - Parameter name */ + float low, /* I - Lower (start) value */ + float high, /* I - Upper (end) value */ + float gvalue) /* I - Gamma value for range */ +{ + ppd_ext_option_t *o; /* Extended option */ + ppd_ext_param_t *p; /* Extended parameter */ + + + if ((o = ppdFindExtOption(ppd, keyword)) == NULL) + return (-1); + + if ((p = ppdFindExtParam(o, param)) == NULL) + return (-1); + + ppd_unmark_choices(o->option); + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppdMarkGamma()' - Mark an extended gamma option. + */ + +int /* O - Number of conflicts */ +ppdMarkGamma(ppd_file_t *ppd, /* I - PPD file */ + const char *keyword, /* I - Option name */ + const char *param, /* I - Parameter name */ + float gvalue) /* I - Gamma value */ +{ + ppd_ext_option_t *o; /* Extended option */ + ppd_ext_param_t *p; /* Extended parameter */ + + + if ((o = ppdFindExtOption(ppd, keyword)) == NULL) + return (-1); + + if ((p = ppdFindExtParam(o, param)) == NULL) + return (-1); + + ppd_unmark_choices(o->option); + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppdMarkInteger()' - Mark an extended integer option. + */ + +int /* O - Number of conflicts */ +ppdMarkInteger(ppd_file_t *ppd, /* I - PPD file */ + const char *keyword, /* I - Option name */ + const char *param, /* I - Parameter name */ + int value) /* I - Option value */ +{ + ppd_ext_option_t *o; /* Extended option */ + ppd_ext_param_t *p; /* Extended parameter */ + + + if ((o = ppdFindExtOption(ppd, keyword)) == NULL) + return (-1); + + if ((p = ppdFindExtParam(o, param)) == NULL) + return (-1); + + ppd_unmark_choices(o->option); + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppdMarkIntegerArray()' - Mark an extended integer array option. + */ + +int /* O - Number of conflicts */ +ppdMarkIntegerArray(ppd_file_t *ppd, /* I - PPD file */ + const char *keyword,/* I - Option name */ + const char *param, /* I - Parameter name */ + int num_values, + /* I - Number of values */ + const int *values) /* I - Values */ +{ + ppd_ext_option_t *o; /* Extended option */ + ppd_ext_param_t *p; /* Extended parameter */ + + + if ((o = ppdFindExtOption(ppd, keyword)) == NULL) + return (-1); + + if ((p = ppdFindExtParam(o, param)) == NULL) + return (-1); + + ppd_unmark_choices(o->option); + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppdMarkReal()' - Mark an extended real option. + */ + +int /* O - Number of conflicts */ +ppdMarkReal(ppd_file_t *ppd, /* I - PPD file */ + const char *keyword, /* I - Option name */ + const char *param, /* I - Parameter name */ + float value) /* I - Option value */ +{ + ppd_ext_option_t *o; /* Extended option */ + ppd_ext_param_t *p; /* Extended parameter */ + + + if ((o = ppdFindExtOption(ppd, keyword)) == NULL) + return (-1); + + if ((p = ppdFindExtParam(o, param)) == NULL) + return (-1); + + ppd_unmark_choices(o->option); + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppdMarkRealArray()' - Mark an extended real array option. + */ + +int /* O - Number of conflicts */ +ppdMarkRealArray(ppd_file_t *ppd, /* I - PPD file */ + const char *keyword, /* I - Option name */ + const char *param, /* I - Parameter name */ + int num_values,/* I - Number of values */ + const float *values) /* I - Values */ +{ + ppd_ext_option_t *o; /* Extended option */ + ppd_ext_param_t *p; /* Extended parameter */ + + + if ((o = ppdFindExtOption(ppd, keyword)) == NULL) + return (-1); + + if ((p = ppdFindExtParam(o, param)) == NULL) + return (-1); + + ppd_unmark_choices(o->option); + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppdMarkText()' - Mark an extended text option. + */ + +int /* O - Number of conflicts */ +ppdMarkText(ppd_file_t *ppd, /* I - PPD file */ + const char *keyword, /* I - Option name */ + const char *param, /* I - Parameter name */ + const char *value) /* I - Option value */ +{ + ppd_ext_option_t *o; /* Extended option */ + ppd_ext_param_t *p; /* Extended parameter */ + + + if ((o = ppdFindExtOption(ppd, keyword)) == NULL) + return (-1); + + if ((p = ppdFindExtParam(o, param)) == NULL) + return (-1); + + ppd_unmark_choices(o->option); + + return (ppdConflicts(ppd)); +} + + +/* + * 'ppd_unmark_choices()' - Unmark all "canned" choices. + */ + +static void +ppd_unmark_choices(ppd_option_t *option)/* I - Option choice */ +{ + int i; /* Looping var */ + ppd_choice_t *c; /* Current choice */ + + + for (i = option->num_choices, c = option->choices; i > 0; i --, c++) + c->marked = 0; +} + + +/* + * End of "$Id: extended.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/cups/file.c b/cups/file.c new file mode 100644 index 000000000..05c553031 --- /dev/null +++ b/cups/file.c @@ -0,0 +1,1680 @@ +/* + * "$Id: file.c 4844 2005-11-21 17:37:57Z mike $" + * + * File functions for the Common UNIX Printing System (CUPS). + * + * Since stdio files max out at 256 files on many systems, we have to + * write similar functions without this limit. At the same time, using + * our own file functions allows us to provide transparent support of + * gzip'd print files, PPD files, etc. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsFileClose() - Close a CUPS file. + * cupsFileCompression() - Return whether a file is compressed. + * cupsFileEOF() - Return the end-of-file status. + * cupsFileFlush() - Flush pending output. + * cupsFileGetChar() - Get a single character from a file. + * cupsFileGetConf() - Get a line from a configuration file... + * cupsFileGets() - Get a CR and/or LF-terminated line. + * cupsFileLock() - Temporarily lock access to a file. + * cupsFileNumber() - Return the file descriptor associated with a CUPS file. + * cupsFileOpen() - Open a CUPS file. + * cupsFileOpenFd() - Open a CUPS file using a file descriptor. + * cupsFilePeekChar() - Peek at the next character from a file. + * cupsFilePrintf() - Write a formatted string. + * cupsFilePutChar() - Write a character. + * cupsFilePuts() - Write a string. + * cupsFileRead() - Read from a file. + * cupsFileRewind() - Rewind a file. + * cupsFileSeek() - Seek in a file. + * cupsFileTell() - Return the current file position. + * cupsFileUnlock() - Unlock access to a file. + * cupsFileWrite() - Write to a file. + * cups_compress() - Compress a buffer of data... + * cups_fill() - Fill the input buffer... + * cups_read() - Read from a file descriptor. + * cups_write() - Write to a file descriptor. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include "http-private.h" +#include "string.h" +#include +#include +#include +#include + +#include "file.h" +#ifdef HAVE_LIBZ +# include +#endif /* HAVE_LIBZ */ +#ifdef WIN32 +# include +# include +#endif /* WIN32 */ + + +/* + * Some operating systems support large files via open flag O_LARGEFILE... + */ + +#ifndef O_LARGEFILE +# define O_LARGEFILE 0 +#endif /* !O_LARGEFILE */ + + +/* + * Types and structures... + */ + +struct _cups_file_s /**** CUPS file structure... ****/ + +{ + int fd; /* File descriptor */ + char mode, /* Mode ('r' or 'w') */ + compressed, /* Compression used? */ + eof, /* End of file? */ + buf[2048], /* Buffer */ + *ptr, /* Pointer into buffer */ + *end; /* End of buffer data */ + off_t pos; /* File position for start of buffer */ + +#ifdef HAVE_LIBZ + z_stream stream; /* (De)compression stream */ + Bytef cbuf[1024]; /* (De)compression buffer */ + uLong crc; /* (De)compression CRC */ +#endif /* HAVE_LIBZ */ +}; + + +/* + * Local functions... + */ + +#ifdef HAVE_LIBZ +static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes); +#endif /* HAVE_LIBZ */ +static ssize_t cups_fill(cups_file_t *fp); +static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes); +static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes); + + +/* + * 'cupsFileClose()' - Close a CUPS file. + */ + +int /* O - 0 on success, -1 on error */ +cupsFileClose(cups_file_t *fp) /* I - CUPS file */ +{ + int fd; /* File descriptor */ + char mode; /* Open mode */ + int status; /* Return status */ + + + DEBUG_printf(("cupsFileClose(fp=%p)\n", fp)); + + /* + * Range check... + */ + + if (!fp) + return (-1); + + /* + * Flush pending write data... + */ + + if (fp->mode == 'w') + status = cupsFileFlush(fp); + else + status = 0; + +#ifdef HAVE_LIBZ + if (fp->compressed && status >= 0) + { + if (fp->mode == 'r') + { + /* + * Free decompression data... + */ + + inflateEnd(&fp->stream); + } + else + { + /* + * Flush any remaining compressed data... + */ + + unsigned char trailer[8]; /* Trailer CRC and length */ + int done; /* Done writing... */ + + + fp->stream.avail_in = 0; + + for (done = 0;;) + { + if (fp->stream.next_out > fp->cbuf) + { + if (cups_write(fp, (char *)fp->cbuf, + fp->stream.next_out - fp->cbuf) < 0) + status = -1; + + fp->stream.next_out = fp->cbuf; + fp->stream.avail_out = sizeof(fp->cbuf); + } + + if (done || status < 0) + break; + + done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END && + fp->stream.next_out == fp->cbuf; + } + + /* + * Write the CRC and length... + */ + + trailer[0] = fp->crc; + trailer[1] = fp->crc >> 8; + trailer[2] = fp->crc >> 16; + trailer[3] = fp->crc >> 24; + trailer[4] = fp->pos; + trailer[5] = fp->pos >> 8; + trailer[6] = fp->pos >> 16; + trailer[7] = fp->pos >> 24; + + if (cups_write(fp, (char *)trailer, 8) < 0) + status = -1; + + /* + * Free all memory used by the compression stream... + */ + + deflateEnd(&(fp->stream)); + } + } +#endif /* HAVE_LIBZ */ + + /* + * Save the file descriptor we used and free memory... + */ + + fd = fp->fd; + mode = fp->mode; + + free(fp); + + /* + * Close the file, returning the close status... + */ + + if (mode == 's') + { + if (closesocket(fd) < 0) + status = -1; + } + else + { + if (close(fd) < 0) + status = -1; + } + + return (status); +} + + +/* + * 'cupsFileCompression()' - Return whether a file is compressed. + */ + +int /* O - CUPS_FILE_NONE or CUPS_FILE_GZIP */ +cupsFileCompression(cups_file_t *fp) /* I - CUPS file */ +{ + return (fp->compressed); +} + + +/* + * 'cupsFileEOF()' - Return the end-of-file status. + */ + +int /* O - 1 on EOF, 0 otherwise */ +cupsFileEOF(cups_file_t *fp) /* I - CUPS file */ +{ + return (fp->eof); +} + + +/* + * 'cupsFileFlush()' - Flush pending output. + */ + +int /* O - 0 on success, -1 on error */ +cupsFileFlush(cups_file_t *fp) /* I - CUPS file */ +{ + size_t bytes; /* Bytes to write */ + + + DEBUG_printf(("cupsFileFlush(fp=%p)\n", fp)); + + /* + * Range check input... + */ + + if (!fp || fp->mode != 'w') + { + DEBUG_puts(" Attempt to flush a read-only file..."); + return (-1); + } + + bytes = fp->ptr - fp->buf; + + if (bytes > 0) + { +#ifdef HAVE_LIBZ + if (fp->compressed) + bytes = cups_compress(fp, fp->buf, bytes); + else +#endif /* HAVE_LIBZ */ + bytes = cups_write(fp, fp->buf, bytes); + + if (bytes < 0) + return (-1); + + fp->ptr = fp->buf; + } + + return (0); +} + + +/* + * 'cupsFileGetChar()' - Get a single character from a file. + */ + +int /* O - Character or -1 on EOF */ +cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */ +{ + /* + * Range check input... + */ + + if (!fp || (fp->mode != 'r' && fp->mode != 's')) + return (-1); + + /* + * If the input buffer is empty, try to read more data... + */ + + if (fp->ptr >= fp->end) + if (cups_fill(fp) < 0) + return (-1); + + /* + * Return the next character in the buffer... + */ + + return (*(fp->ptr)++ & 255); +} + + +/* + * 'cupsFileGetConf()' - Get a line from a configuration file... + */ + +char * /* O - Line read of NULL on eof/error */ +cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */ + char *buf, /* O - String buffer */ + size_t buflen, /* I - Size of string buffer */ + char **value, /* O - Pointer to value */ + int *linenum) /* IO - Current line number */ +{ + char *ptr; /* Pointer into line */ + + + /* + * Range check input... + */ + + if (!fp || (fp->mode != 'r' && fp->mode != 's') || + !buf || buflen < 2 || !value) + { + if (value) + *value = NULL; + + return (NULL); + } + + /* + * Read the next non-comment line... + */ + + *value = NULL; + + while (cupsFileGets(fp, buf, buflen)) + { + (*linenum) ++; + + /* + * Strip any comments... + */ + + if ((ptr = strchr(buf, '#')) != NULL) + { + while (ptr > buf) + { + if (!isspace(ptr[-1] & 255)) + break; + + ptr --; + } + + *ptr = '\0'; + } + + /* + * Strip leading whitespace... + */ + + for (ptr = buf; isspace(*ptr & 255); ptr ++); + + if (ptr > buf) + _cups_strcpy(buf, ptr); + + /* + * See if there is anything left... + */ + + if (buf[0]) + { + /* + * Yes, grab any value and return... + */ + + for (ptr = buf; *ptr; ptr ++) + if (isspace(*ptr & 255)) + break; + + if (*ptr) + { + /* + * Have a value, skip any other spaces... + */ + + while (isspace(*ptr & 255)) + *ptr++ = '\0'; + + if (*ptr) + *value = ptr; + + /* + * Strip trailing whitespace and > for lines that begin with <... + */ + + ptr += strlen(ptr) - 1; + + if (buf[0] == '<' && *ptr == '>') + *ptr-- = '\0'; + else if (buf[0] == '<' && *ptr != '>') + { + /* + * Syntax error... + */ + + *value = NULL; + return (buf); + } + + while (ptr > *value && isspace(*ptr & 255)) + *ptr-- = '\0'; + } + + /* + * Return the line... + */ + + return (buf); + } + } + + return (NULL); +} + + +/* + * 'cupsFileGets()' - Get a CR and/or LF-terminated line. + */ + +char * /* O - Line read or NULL on eof/error */ +cupsFileGets(cups_file_t *fp, /* I - CUPS file */ + char *buf, /* O - String buffer */ + size_t buflen) /* I - Size of string buffer */ +{ + int ch; /* Character from file */ + char *ptr, /* Current position in line buffer */ + *end; /* End of line buffer */ + + + /* + * Range check input... + */ + + if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2) + return (NULL); + + /* + * Now loop until we have a valid line... + */ + + for (ptr = buf, end = buf + buflen - 1; ptr < end ;) + { + if (fp->ptr >= fp->end) + if (cups_fill(fp) <= 0) + { + if (ptr == buf) + return (NULL); + else + break; + } + + ch = *(fp->ptr)++; + + if (ch == '\r') + { + /* + * Check for CR LF... + */ + + if (fp->ptr >= fp->end) + if (cups_fill(fp) <= 0) + break; + + if (*(fp->ptr) == '\n') + fp->ptr ++; + + break; + } + else if (ch == '\n') + { + /* + * Line feed ends a line... + */ + + break; + } + else + *ptr++ = ch; + } + + *ptr = '\0'; + + return (buf); +} + + +/* + * 'cupsFileLock()' - Temporarily lock access to a file. + */ + +int /* O - 0 on success, -1 on error */ +cupsFileLock(cups_file_t *fp, /* I - File to lock */ + int block) /* I - 1 to wait for the lock, 0 to fail right away */ +{ + /* + * Range check... + */ + + if (!fp || fp->mode == 's') + return (-1); + + /* + * Try the lock... + */ + +#ifdef WIN32 + return (locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0)); +#else + return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0)); +#endif /* WIN32 */ +} + + +/* + * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file. + */ + +int /* O - File descriptor */ +cupsFileNumber(cups_file_t *fp) /* I - CUPS file */ +{ + return (fp->fd); +} + + +/* + * 'cupsFileOpen()' - Open a CUPS file. + */ + +cups_file_t * /* O - CUPS file or NULL */ +cupsFileOpen(const char *filename, /* I - Name of file */ + const char *mode) /* I - Open mode */ +{ + cups_file_t *fp; /* New CUPS file */ + int fd; /* File descriptor */ + char hostname[1024], /* Hostname */ + *portname; /* Port "name" (number or service) */ + http_addrlist_t *addrlist; /* Host address list */ + + + /* + * Range check input... + */ + + if (!filename || !mode || + (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's')) + return (NULL); + + /* + * Open the file... + */ + + switch (*mode) + { + case 'a' : /* Append file */ + fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE, 0666); + break; + + case 'r' : /* Read file */ + fd = open(filename, O_RDONLY | O_LARGEFILE, 0); + break; + + case 'w' : /* Write file */ + fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE, 0666); + break; + + case 's' : /* Read/write socket */ + strlcpy(hostname, filename, sizeof(hostname)); + if ((portname = strrchr(hostname, ':')) != NULL) + *portname++ = '\0'; + else + return (NULL); + + /* + * Lookup the hostname and service... + */ + + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + return (NULL); + + /* + * Connect to the server... + */ + + if (!httpAddrConnect(addrlist, &fd)) + { + httpAddrFreeList(addrlist); + return (NULL); + } + + httpAddrFreeList(addrlist); + break; + + default : /* Remove bogus compiler warning... */ + return (NULL); + } + + if (fd < 0) + return (NULL); + + /* + * Create the CUPS file structure... + */ + + if ((fp = cupsFileOpenFd(fd, mode)) == NULL) + { + if (*mode == 's') + closesocket(fd); + else + close(fd); + } + + /* + * Return it... + */ + + return (fp); +} + +/* + * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor. + */ + +cups_file_t * /* O - CUPS file or NULL */ +cupsFileOpenFd(int fd, /* I - File descriptor */ + const char *mode) /* I - Open mode */ +{ + cups_file_t *fp; /* New CUPS file */ + + + /* + * Range check input... + */ + + if (fd < 0 || !mode || + (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's')) + return (NULL); + + /* + * Allocate memory... + */ + + if ((fp = calloc(1, sizeof(cups_file_t))) == NULL) + return (NULL); + + /* + * Open the file... + */ + + fp->fd = fd; + + switch (*mode) + { + case 'w' : + case 'a' : + fp->mode = 'w'; + fp->ptr = fp->buf; + fp->end = fp->buf + sizeof(fp->buf); + +#ifdef HAVE_LIBZ + if (mode[1] >= '1' && mode[1] <= '9') + { + /* + * Open a compressed stream, so write the standard gzip file + * header... + */ + + unsigned char header[10]; /* gzip file header */ + time_t curtime; /* Current time */ + + + curtime = time(NULL); + header[0] = 0x1f; + header[1] = 0x8b; + header[2] = Z_DEFLATED; + header[3] = 0; + header[4] = curtime; + header[5] = curtime >> 8; + header[6] = curtime >> 16; + header[7] = curtime >> 24; + header[8] = 0; + header[9] = 0x03; + + cups_write(fp, (char *)header, 10); + + /* + * Initialize the compressor... + */ + + deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8, + Z_DEFAULT_STRATEGY); + + fp->stream.next_out = fp->cbuf; + fp->stream.avail_out = sizeof(fp->cbuf); + fp->compressed = 1; + fp->crc = crc32(0L, Z_NULL, 0); + } +#endif /* HAVE_LIBZ */ + break; + + case 'r' : + fp->mode = 'r'; + break; + + case 's' : + fp->mode = 's'; + break; + + default : /* Remove bogus compiler warning... */ + return (NULL); + } + + /* + * Don't pass this file to child processes... + */ + +#ifndef WIN32 + fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC); +#endif /* !WIN32 */ + + return (fp); +} + + +/* + * 'cupsFilePeekChar()' - Peek at the next character from a file. + */ + +int /* O - Character or -1 on EOF */ +cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */ +{ + /* + * Range check input... + */ + + if (!fp || (fp->mode != 'r' && fp->mode != 's')) + return (-1); + + /* + * If the input buffer is empty, try to read more data... + */ + + if (fp->ptr >= fp->end) + if (cups_fill(fp) < 0) + return (-1); + + /* + * Return the next character in the buffer... + */ + + return (*(fp->ptr) & 255); +} + + +/* + * 'cupsFilePrintf()' - Write a formatted string. + */ + +int /* O - Number of bytes written or -1 */ +cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */ + const char *format, /* I - Printf-style format string */ + ...) /* I - Additional args as necessary */ +{ + va_list ap; /* Argument list */ + size_t bytes; /* Formatted size */ + char buf[2048]; /* Formatted text */ + + + if (!fp || !format || (fp->mode != 'w' && fp->mode != 's')) + return (-1); + + va_start(ap, format); + bytes = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + if (fp->mode == 's') + return (cups_write(fp, buf, bytes)); + + if ((fp->ptr + bytes) > fp->end) + if (cupsFileFlush(fp)) + return (-1); + + fp->pos += bytes; + + if (bytes > sizeof(fp->buf)) + { +#ifdef HAVE_LIBZ + if (fp->compressed) + return (cups_compress(fp, buf, bytes)); + else +#endif /* HAVE_LIBZ */ + return (cups_write(fp, buf, bytes)); + } + else + { + memcpy(fp->ptr, buf, bytes); + fp->ptr += bytes; + return (bytes); + } +} + + +/* + * 'cupsFilePutChar()' - Write a character. + */ + +int /* O - 0 on success, -1 on error */ +cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */ + int c) /* I - Character to write */ +{ + /* + * Range check input... + */ + + if (!fp || (fp->mode != 'w' && fp->mode != 's')) + return (-1); + + if (fp->mode == 's') + { + /* + * Send character immediately over socket... + */ + + char ch; /* Output character */ + + + ch = c; + + if (send(fp->fd, &ch, 1, 0) < 1) + return (-1); + } + else + { + /* + * Buffer it up... + */ + + if (fp->ptr >= fp->end) + if (cupsFileFlush(fp)) + return (-1); + + *(fp->ptr) ++ = c; + } + + fp->pos ++; + + return (0); +} + + +/* + * 'cupsFilePuts()' - Write a string. + */ + +int /* O - Number of bytes written or -1 */ +cupsFilePuts(cups_file_t *fp, /* I - CUPS file */ + const char *s) /* I - String to write */ +{ + size_t bytes; /* Bytes to write */ + + + /* + * Range check input... + */ + + if (!fp || !s || (fp->mode != 'w' && fp->mode != 's')) + return (-1); + + /* + * Write the string... + */ + + bytes = strlen(s); + + if (fp->mode == 's') + { + if (cups_write(fp, s, bytes) < 0) + return (-1); + + fp->pos += bytes; + + return (bytes); + } + + if ((fp->ptr + bytes) > fp->end) + if (cupsFileFlush(fp)) + return (-1); + + fp->pos += bytes; + + if (bytes > sizeof(fp->buf)) + { +#ifdef HAVE_LIBZ + if (fp->compressed) + return (cups_compress(fp, s, bytes)); + else +#endif /* HAVE_LIBZ */ + return (cups_write(fp, s, bytes)); + } + else + { + memcpy(fp->ptr, s, bytes); + fp->ptr += bytes; + return (bytes); + } +} + + +/* + * 'cupsFileRead()' - Read from a file. + */ + +ssize_t /* O - Number of bytes read or -1 */ +cupsFileRead(cups_file_t *fp, /* I - CUPS file */ + char *buf, /* O - Buffer */ + size_t bytes) /* I - Number of bytes to read */ +{ + size_t total, /* Total bytes read */ + count; /* Bytes read */ + + + DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=%ld)\n", fp, buf, + (long)bytes)); + + /* + * Range check input... + */ + + if (!fp || !buf || bytes < 0 || (fp->mode != 'r' && fp->mode != 's')) + return (-1); + + if (bytes == 0) + return (0); + + /* + * Loop until all bytes are read... + */ + + total = 0; + while (bytes > 0) + { + if (fp->ptr >= fp->end) + if (cups_fill(fp) <= 0) + { + DEBUG_printf((" cups_fill() returned -1, total=%d\n", total)); + + if (total > 0) + return (total); + else + return (-1); + } + + count = fp->end - fp->ptr; + if (count > bytes) + count = bytes; + + memcpy(buf, fp->ptr, count); + fp->ptr += count; + + /* + * Update the counts for the last read... + */ + + bytes -= count; + total += count; + buf += count; + } + + /* + * Return the total number of bytes read... + */ + + DEBUG_printf((" total=%d\n", total)); + + return (total); +} + + +/* + * 'cupsFileRewind()' - Rewind a file. + */ + +off_t /* O - New file position or -1 */ +cupsFileRewind(cups_file_t *fp) /* I - CUPS file */ +{ + return (cupsFileSeek(fp, 0L)); +} + + +/* + * 'cupsFileSeek()' - Seek in a file. + */ + +off_t /* O - New file position or -1 */ +cupsFileSeek(cups_file_t *fp, /* I - CUPS file */ + off_t pos) /* I - Position in file */ +{ + size_t bytes; /* Number bytes in buffer */ + + + DEBUG_printf(("cupsFileSeek(fp=%p, pos=%ld)\n", fp, (long)pos)); + DEBUG_printf((" fp->pos=%ld\n", (long)fp->pos)); + + /* + * Range check input... + */ + + if (!fp || pos < 0 || fp->mode != 'r') + return (-1); + + /* + * Figure out the number of bytes in the current buffer, and then + * see if we are outside of it... + */ + + bytes = fp->end - fp->buf; + fp->eof = 0; + + if (pos < fp->pos) + { + /* + * Need to seek backwards... + */ + +#ifdef HAVE_LIBZ + if (fp->compressed) + { + inflateEnd(&fp->stream); + + lseek(fp->fd, 0, SEEK_SET); + fp->pos = 0; + fp->ptr = NULL; + fp->end = NULL; + + while ((bytes = cups_fill(fp)) > 0) + if (pos >= fp->pos && pos < (fp->pos + bytes)) + break; + + if (bytes <= 0) + return (-1); + } + else +#endif /* HAVE_LIBZ */ + { + fp->pos = lseek(fp->fd, pos, SEEK_SET); + DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos)); + fp->ptr = NULL; + fp->end = NULL; + } + } + else if (pos >= (fp->pos + bytes)) + { + /* + * Need to seek forwards... + */ + +#ifdef HAVE_LIBZ + if (fp->compressed) + { + while ((bytes = cups_fill(fp)) > 0) + if (pos >= fp->pos && pos < (fp->pos + bytes)) + break; + + if (bytes <= 0) + return (-1); + } + else +#endif /* HAVE_LIBZ */ + { + fp->pos = lseek(fp->fd, pos, SEEK_SET); + DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos)); + fp->ptr = NULL; + fp->end = NULL; + } + } + else + { + /* + * Just reposition the current pointer, since we have the right + * range... + */ + + fp->ptr = fp->buf + pos - fp->pos; + DEBUG_puts((" seek inside buffer...")); + } + + return (fp->pos); +} + + +/* + * 'cupsFileTell()' - Return the current file position. + */ + +off_t /* O - File position */ +cupsFileTell(cups_file_t *fp) /* I - CUPS file */ +{ + return (fp->pos); +} + + +/* + * 'cupsFileUnlock()' - Unlock access to a file. + */ + +int /* O - 0 on success, -1 on error */ +cupsFileUnlock(cups_file_t *fp) /* I - File to lock */ +{ + /* + * Range check... + */ + + if (!fp || fp->mode == 's') + return (-1); + + /* + * Unlock... + */ + +#ifdef WIN32 + return (locking(fp->fd, _LK_UNLCK, 0)); +#else + return (lockf(fp->fd, F_ULOCK, 0)); +#endif /* WIN32 */ +} + + +/* + * 'cupsFileWrite()' - Write to a file. + */ + +ssize_t /* O - Number of bytes written */ +cupsFileWrite(cups_file_t *fp, /* I - CUPS file */ + const char *buf, /* I - Buffer */ + size_t bytes) /* I - Number of bytes to write */ +{ + /* + * Range check input... + */ + + if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's')) + return (-1); + + if (bytes == 0) + return (0); + + /* + * Write the buffer... + */ + + if (fp->mode == 's') + { + if (cups_write(fp, buf, bytes) < 0) + return (-1); + + fp->pos += bytes; + + return (bytes); + } + + if ((fp->ptr + bytes) > fp->end) + if (cupsFileFlush(fp)) + return (-1); + + fp->pos += bytes; + + if (bytes > sizeof(fp->buf)) + { +#ifdef HAVE_LIBZ + if (fp->compressed) + return (cups_compress(fp, buf, bytes)); + else +#endif /* HAVE_LIBZ */ + return (cups_write(fp, buf, bytes)); + } + else + { + memcpy(fp->ptr, buf, bytes); + fp->ptr += bytes; + return (bytes); + } +} + + +#ifdef HAVE_LIBZ +/* + * 'cups_compress()' - Compress a buffer of data... + */ + +static ssize_t /* O - Number of bytes written or -1 */ +cups_compress(cups_file_t *fp, /* I - CUPS file */ + const char *buf, /* I - Buffer */ + size_t bytes) /* I - Number bytes */ +{ + /* + * Update the CRC... + */ + + fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes); + + /* + * Deflate the bytes... + */ + + fp->stream.next_in = (Bytef *)buf; + fp->stream.avail_in = bytes; + + while (fp->stream.avail_in > 0) + { + /* + * Flush the current buffer... + */ + + if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8)) + { + if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0) + return (-1); + } + + deflate(&(fp->stream), Z_NO_FLUSH); + } + + return (bytes); +} +#endif /* HAVE_LIBZ */ + + +/* + * 'cups_fill()' - Fill the input buffer... + */ + +static ssize_t /* O - Number of bytes or -1 */ +cups_fill(cups_file_t *fp) /* I - CUPS file */ +{ + ssize_t bytes; /* Number of bytes read */ +#ifdef HAVE_LIBZ + const unsigned char *ptr, /* Pointer into buffer */ + *end; /* End of buffer */ +#endif /* HAVE_LIBZ */ + + + DEBUG_printf(("cups_fill(fp=%p)\n", fp)); + DEBUG_printf((" fp->ptr=%p, fp->end=%p, fp->buf=%p, fp->pos=%ld\n", + fp->ptr, fp->end, fp->buf, (long)fp->pos)); + + /* + * Update the "pos" element as needed... + */ + + if (fp->ptr && fp->end) + fp->pos += fp->end - fp->buf; + +#ifdef HAVE_LIBZ + while (!fp->ptr || fp->compressed) + { + /* + * Check to see if we have read any data yet; if not, see if we have a + * compressed file... + */ + + if (!fp->ptr) + { + /* + * Reset the file position in case we are seeking... + */ + + fp->compressed = 0; + fp->pos = 0; + + /* + * Read the first bytes in the file to determine if we have a gzip'd + * file... + */ + + if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) < 0) + { + /* + * Can't read from file! + */ + + return (-1); + } + + if (bytes < 10 || fp->cbuf[0] != 0x1f || fp->cbuf[1] != 0x8b || + fp->cbuf[2] != 8 || (fp->cbuf[3] & 0xe0) != 0) + { + /* + * Not a gzip'd file! + */ + + memcpy(fp->buf, fp->cbuf, bytes); + + fp->ptr = fp->buf; + fp->end = fp->buf + bytes; + + return (bytes); + } + + /* + * Parse header junk: extra data, original name, and comment... + */ + + ptr = (unsigned char *)fp->cbuf + 10; + end = (unsigned char *)fp->cbuf + bytes; + + if (fp->cbuf[3] & 0x04) + { + /* + * Skip extra data... + */ + + if ((ptr + 2) > end) + { + /* + * Can't read from file! + */ + + return (-1); + } + + bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0]; + ptr += 2 + bytes; + + if (ptr > end) + { + /* + * Can't read from file! + */ + + return (-1); + } + } + + if (fp->cbuf[3] & 0x08) + { + /* + * Skip original name data... + */ + + while (ptr < end && *ptr) + ptr ++; + + if (ptr < end) + ptr ++; + else + { + /* + * Can't read from file! + */ + + return (-1); + } + } + + if (fp->cbuf[3] & 0x10) + { + /* + * Skip comment data... + */ + + while (ptr < end && *ptr) + ptr ++; + + if (ptr < end) + ptr ++; + else + { + /* + * Can't read from file! + */ + + return (-1); + } + } + + if (fp->cbuf[3] & 0x02) + { + /* + * Skip header CRC data... + */ + + ptr += 2; + + if (ptr > end) + { + /* + * Can't read from file! + */ + + return (-1); + } + } + + /* + * Setup the decompressor data... + */ + + fp->stream.zalloc = (alloc_func)0; + fp->stream.zfree = (free_func)0; + fp->stream.opaque = (voidpf)0; + fp->stream.next_in = (Bytef *)ptr; + fp->stream.next_out = NULL; + fp->stream.avail_in = end - ptr; + fp->stream.avail_out = 0; + fp->crc = crc32(0L, Z_NULL, 0); + + if (inflateInit2(&(fp->stream), -15) != Z_OK) + return (-1); + + fp->compressed = 1; + } + + if (fp->compressed) + { + /* + * If we have reached end-of-file, return immediately... + */ + + if (fp->eof) + return (-1); + + /* + * Fill the decompression buffer as needed... + */ + + if (fp->stream.avail_in == 0) + { + if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0) + return (-1); + + fp->stream.next_in = fp->cbuf; + fp->stream.avail_in = bytes; + } + + /* + * Decompress data from the buffer... + */ + + fp->stream.next_out = (Bytef *)fp->buf; + fp->stream.avail_out = sizeof(fp->buf); + + if (inflate(&(fp->stream), Z_NO_FLUSH) == Z_STREAM_END) + { + /* + * Read the CRC and length... + */ + + unsigned char trailer[8]; /* Trailer bytes */ + uLong tcrc; /* Trailer CRC */ + + + if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer)) + { + /* + * Can't get it, so mark end-of-file... + */ + + fp->eof = 1; + return (-1); + } + + tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) | + trailer[0]; + + if (tcrc != fp->crc) + { + /* + * Bad CRC, mark end-of-file... + */ + fp->eof = 1; + + return (-1); + } + + /* + * Otherwise, reset the current pointer so that we re-read the + * file header... + */ + + fp->ptr = NULL; + continue; + } + + bytes = sizeof(fp->buf) - fp->stream.avail_out; + + /* + * Return the decompressed data... + */ + + fp->ptr = fp->buf; + fp->end = fp->buf + bytes; + + return (bytes); + } + } +#endif /* HAVE_LIBZ */ + + /* + * Read a buffer's full of data... + */ + + if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0) + { + /* + * Can't read from file! + */ + + fp->eof = 1; + fp->ptr = fp->buf; + fp->end = fp->buf; + + return (-1); + } + + /* + * Return the bytes we read... + */ + + fp->eof = 0; + fp->ptr = fp->buf; + fp->end = fp->buf + bytes; + + return (bytes); +} + + +/* + * 'cups_read()' - Read from a file descriptor. + */ + +static ssize_t /* O - Number of bytes read or -1 */ +cups_read(cups_file_t *fp, /* I - CUPS file */ + char *buf, /* I - Buffer */ + size_t bytes) /* I - Number bytes */ +{ + ssize_t total; /* Total bytes read */ + + + /* + * Loop until we read at least 0 bytes... + */ + + for (;;) + { + if (fp->mode == 's') + total = recv(fp->fd, buf, bytes, 0); + else + total = read(fp->fd, buf, bytes); + + if (total >= 0) + break; + + /* + * Reads can be interrupted by signals and unavailable resources... + */ + + if (errno == EAGAIN || errno == EINTR) + continue; + else + return (-1); + } + + /* + * Return the total number of bytes read... + */ + + return (total); +} + + +/* + * 'cups_write()' - Write to a file descriptor. + */ + +static ssize_t /* O - Number of bytes written or -1 */ +cups_write(cups_file_t *fp, /* I - CUPS file */ + const char *buf, /* I - Buffer */ + size_t bytes) /* I - Number bytes */ +{ + size_t total, /* Total bytes written */ + count; /* Count this time */ + + + /* + * Loop until all bytes are written... + */ + + total = 0; + while (bytes > 0) + { + if (fp->mode == 's') + count = send(fp->fd, buf, bytes, 0); + else + count = write(fp->fd, buf, bytes); + + if (count < 0) + { + /* + * Writes can be interrupted by signals and unavailable resources... + */ + + if (errno == EAGAIN || errno == EINTR) + continue; + else + return (-1); + } + + /* + * Update the counts for the last write call... + */ + + bytes -= count; + total += count; + buf += count; + } + + /* + * Return the total number of bytes written... + */ + + return (total); +} + + +/* + * End of "$Id: file.c 4844 2005-11-21 17:37:57Z mike $". + */ diff --git a/cups/file.h b/cups/file.h new file mode 100644 index 000000000..c7de9ef0f --- /dev/null +++ b/cups/file.h @@ -0,0 +1,105 @@ +/* + * "$Id: file.h 4857 2005-11-30 19:25:17Z mike $" + * + * Public file definitions for the Common UNIX Printing System (CUPS). + * + * Since stdio files max out at 256 files on many systems, we have to + * write similar functions without this limit. At the same time, using + * our own file functions allows us to provide transparent support of + * gzip'd print files, PPD files, etc. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_FILE_H_ +# define _CUPS_FILE_H_ + + +/* + * Include necessary headers... + */ + +# include + +# ifdef WIN32 +/* Windows does not support the ssize_t type, so map it to off_t... */ +typedef off_t ssize_t; /* @private@ */ +# endif /* WIN32 */ + + +/* + * C++ magic... + */ + +# ifdef _cplusplus +extern "C" { +# endif /* _cplusplus */ + + +/* + * CUPS file definitions... + */ + +# define CUPS_FILE_NONE 0 /* No compression */ +# define CUPS_FILE_GZIP 1 /* GZIP compression */ + + +/* + * Types and structures... + */ + +typedef struct _cups_file_s cups_file_t;/**** CUPS file type ****/ + + +/* + * Prototypes... + */ + +extern int cupsFileClose(cups_file_t *fp); +extern int cupsFileCompression(cups_file_t *fp); +extern int cupsFileEOF(cups_file_t *fp); +extern int cupsFileFlush(cups_file_t *fp); +extern int cupsFileGetChar(cups_file_t *fp); +extern char *cupsFileGetConf(cups_file_t *fp, char *buf, size_t buflen, + char **value, int *linenum); +extern char *cupsFileGets(cups_file_t *fp, char *buf, size_t buflen); +extern int cupsFileLock(cups_file_t *fp, int block); +extern int cupsFileNumber(cups_file_t *fp); +extern cups_file_t *cupsFileOpen(const char *filename, const char *mode); +extern cups_file_t *cupsFileOpenFd(int fd, const char *mode); +extern int cupsFilePeekChar(cups_file_t *fp); +extern int cupsFilePrintf(cups_file_t *fp, const char *format, ...); +extern int cupsFilePutChar(cups_file_t *fp, int c); +extern int cupsFilePuts(cups_file_t *fp, const char *s); +extern ssize_t cupsFileRead(cups_file_t *fp, char *buf, size_t bytes); +extern off_t cupsFileRewind(cups_file_t *fp); +extern off_t cupsFileSeek(cups_file_t *fp, off_t pos); +extern off_t cupsFileTell(cups_file_t *fp); +extern int cupsFileUnlock(cups_file_t *fp); +extern ssize_t cupsFileWrite(cups_file_t *fp, const char *buf, size_t bytes); + + +# ifdef _cplusplus +} +# endif /* _cplusplus */ +#endif /* !_CUPS_FILE_H_ */ + +/* + * End of "$Id: file.h 4857 2005-11-30 19:25:17Z mike $". + */ diff --git a/cups/getputfile.c b/cups/getputfile.c new file mode 100644 index 000000000..8a5dc9330 --- /dev/null +++ b/cups/getputfile.c @@ -0,0 +1,435 @@ +/* + * "$Id: getputfile.c 4918 2006-01-12 05:14:40Z mike $" + * + * Get/put file functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsGetFd() - Get a file from the server. + * cupsGetFile() - Get a file from the server. + * cupsPutFd() - Put a file on the server. + * cupsPutFile() - Put a file on the server. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include "ipp.h" +#include "language.h" +#include "string.h" +#include "debug.h" +#include +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * 'cupsGetFd()' - Get a file from the server. + * + * This function returns HTTP_OK when the file is successfully retrieved. + * + * @since CUPS 1.1.20@ + */ + +http_status_t /* O - Status */ +cupsGetFd(http_t *http, /* I - HTTP connection to server */ + const char *resource, /* I - Resource name */ + int fd) /* I - File descriptor */ +{ + int bytes; /* Number of bytes read */ + char buffer[8192]; /* Buffer for file */ + http_status_t status; /* HTTP status from server */ + + + /* + * Range check input... + */ + + DEBUG_printf(("cupsGetFd(http=%p, resource=\"%s\", fd=%d)\n", http, + resource, fd)); + + if (!http || !resource || fd < 0) + { + if (http) + http->error = EINVAL; + + return (HTTP_ERROR); + } + + /* + * Then send GET requests to the HTTP server... + */ + + do + { + httpClearFields(http); + httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); + + if (httpGet(http, resource)) + { + if (httpReconnect(http)) + { + status = HTTP_ERROR; + break; + } + else + { + status = HTTP_UNAUTHORIZED; + continue; + } + } + + while ((status = httpUpdate(http)) == HTTP_CONTINUE); + + if (status == HTTP_UNAUTHORIZED) + { + /* + * Flush any error message... + */ + + httpFlush(http); + + /* + * See if we can do authentication... + */ + + if (cupsDoAuthentication(http, "GET", resource)) + break; + + httpReconnect(http); + + continue; + } +#ifdef HAVE_SSL + else if (status == HTTP_UPGRADE_REQUIRED) + { + /* Flush any error message... */ + httpFlush(http); + + /* Reconnect... */ + httpReconnect(http); + + /* Upgrade with encryption... */ + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); + + /* Try again, this time with encryption enabled... */ + continue; + } +#endif /* HAVE_SSL */ + } + while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED); + + /* + * See if we actually got the file or an error... + */ + + if (status == HTTP_OK) + { + /* + * Yes, copy the file... + */ + + while ((bytes = httpRead(http, buffer, sizeof(buffer))) > 0) + write(fd, buffer, bytes); + } + else + httpFlush(http); + + /* + * Return the request status... + */ + + return (status); +} + + +/* + * 'cupsGetFile()' - Get a file from the server. + * + * This function returns HTTP_OK when the file is successfully retrieved. + * + * @since CUPS 1.1.20@ + */ + +http_status_t /* O - Status */ +cupsGetFile(http_t *http, /* I - HTTP connection to server */ + const char *resource, /* I - Resource name */ + const char *filename) /* I - Filename */ +{ + int fd; /* File descriptor */ + http_status_t status; /* Status */ + + + /* + * Range check input... + */ + + if (!http || !resource || !filename) + { + if (http) + http->error = EINVAL; + + return (HTTP_ERROR); + } + + /* + * Create the file... + */ + + if ((fd = open(filename, O_WRONLY | O_EXCL | O_TRUNC)) < 0) + { + /* + * Couldn't open the file! + */ + + http->error = errno; + + return (HTTP_ERROR); + } + + /* + * Get the file... + */ + + status = cupsGetFd(http, resource, fd); + + /* + * If the file couldn't be gotten, then remove the file... + */ + + close(fd); + + if (status != HTTP_OK) + unlink(filename); + + /* + * Return the HTTP status code... + */ + + return (status); +} + + +/* + * 'cupsPutFd()' - Put a file on the server. + * + * This function returns HTTP_CREATED when the file is stored successfully. + * + * @since CUPS 1.1.20@ + */ + +http_status_t /* O - Status */ +cupsPutFd(http_t *http, /* I - HTTP connection to server */ + const char *resource, /* I - Resource name */ + int fd) /* I - File descriptor */ +{ + int bytes; /* Number of bytes read */ + char buffer[8192]; /* Buffer for file */ + http_status_t status; /* HTTP status from server */ + + + /* + * Range check input... + */ + + DEBUG_printf(("cupsPutFd(http=%p, resource=\"%s\", fd=%d)\n", http, + resource, fd)); + + if (!http || !resource || fd < 0) + { + if (http) + http->error = EINVAL; + + return (HTTP_ERROR); + } + + /* + * Then send PUT requests to the HTTP server... + */ + + do + { + DEBUG_printf(("cupsPutFd: starting attempt, authstring=\"%s\"...\n", + http->authstring)); + + httpClearFields(http); + httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); + httpSetField(http, HTTP_FIELD_TRANSFER_ENCODING, "chunked"); + + if (httpPut(http, resource)) + { + if (httpReconnect(http)) + { + status = HTTP_ERROR; + break; + } + else + { + status = HTTP_UNAUTHORIZED; + continue; + } + } + + /* + * Copy the file... + */ + + lseek(fd, 0, SEEK_SET); + + status = HTTP_CONTINUE; + + while ((bytes = read(fd, buffer, sizeof(buffer))) > 0) + if (httpCheck(http)) + { + if ((status = httpUpdate(http)) != HTTP_CONTINUE) + break; + } + else + httpWrite(http, buffer, bytes); + + if (status == HTTP_CONTINUE) + { + httpWrite(http, buffer, 0); + + while ((status = httpUpdate(http)) == HTTP_CONTINUE); + } + + DEBUG_printf(("cupsPutFd: status=%d\n", status)); + + if (status == HTTP_UNAUTHORIZED) + { + /* + * Flush any error message... + */ + + httpFlush(http); + + /* + * See if we can do authentication... + */ + + if (cupsDoAuthentication(http, "PUT", resource)) + break; + + httpReconnect(http); + + continue; + } +#ifdef HAVE_SSL + else if (status == HTTP_UPGRADE_REQUIRED) + { + /* Flush any error message... */ + httpFlush(http); + + /* Reconnect... */ + httpReconnect(http); + + /* Upgrade with encryption... */ + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); + + /* Try again, this time with encryption enabled... */ + continue; + } +#endif /* HAVE_SSL */ + } + while (status == HTTP_UNAUTHORIZED || status == HTTP_UPGRADE_REQUIRED); + + /* + * See if we actually put the file or an error... + */ + + if (status != HTTP_CREATED) + httpFlush(http); + + return (status); +} + + +/* + * 'cupsPutFile()' - Put a file on the server. + * + * This function returns HTTP_CREATED when the file is stored successfully. + * + * @since CUPS 1.1.20@ + */ + +http_status_t /* O - Status */ +cupsPutFile(http_t *http, /* I - HTTP connection to server */ + const char *resource, /* I - Resource name */ + const char *filename) /* I - Filename */ +{ + int fd; /* File descriptor */ + http_status_t status; /* Status */ + + + /* + * Range check input... + */ + + if (!http || !resource || !filename) + { + if (http) + http->error = EINVAL; + + return (HTTP_ERROR); + } + + /* + * Open the local file... + */ + + if ((fd = open(filename, O_RDONLY)) < 0) + { + /* + * Couldn't open the file! + */ + + http->error = errno; + + return (HTTP_ERROR); + } + + /* + * Put the file... + */ + + status = cupsPutFd(http, resource, fd); + + close(fd); + + return (status); +} + + +/* + * End of "$Id: getputfile.c 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/globals.c b/cups/globals.c new file mode 100644 index 000000000..d7c6ac293 --- /dev/null +++ b/cups/globals.c @@ -0,0 +1,202 @@ +/* + * "$Id: globals.c 4922 2006-01-12 22:05:06Z mike $" + * + * Global variable access routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsGlobals() - Return a pointer to thread local storage. + * cups_env_init() - Initialize environment variables. + * globals_init() - Initialize globals once. + * globals_destructor() - Free memory allocated by _cupsGlobals(). + */ + +/* + * Include necessary headers... + */ + +#include "http-private.h" +#include "globals.h" +#include + + +/* + * 'cups_env_init()' - Initialize environment variables. + */ + +static void +cups_env_init(_cups_globals_t *g) /* I - Global data */ +{ + if ((g->cups_datadir = getenv("CUPS_DATADIR")) == NULL) + g->cups_datadir = CUPS_DATADIR; + + if ((g->cups_serverbin = getenv("CUPS_SERVERBIN")) == NULL) + g->cups_serverbin = CUPS_SERVERBIN; + + if ((g->cups_serverroot = getenv("CUPS_SERVERROOT")) == NULL) + g->cups_serverroot = CUPS_SERVERROOT; + + if ((g->cups_statedir = getenv("CUPS_STATEDIR")) == NULL) + g->cups_statedir = CUPS_STATEDIR; + + if ((g->localedir = getenv("LOCALEDIR")) == NULL) + g->localedir = CUPS_LOCALEDIR; +} + + +#ifdef HAVE_PTHREAD_H +/* + * Implement per-thread globals... + */ + +/* + * Local globals... + */ + +static pthread_key_t globals_key = -1; + /* Thread local storage key */ +static pthread_once_t globals_key_once = PTHREAD_ONCE_INIT; + /* One-time initialization object */ + + +/* + * Local functions... + */ + +static void globals_init(); +static void globals_destructor(void *value); + + +/* + * '_cupsGlobals()' - Return a pointer to thread local storage + */ + +_cups_globals_t * /* O - Pointer to global data */ +_cupsGlobals(void) +{ + _cups_globals_t *globals; /* Pointer to global data */ + + + /* + * Initialize the global data exactly once... + */ + + pthread_once(&globals_key_once, globals_init); + + /* + * See if we have allocated the data yet... + */ + + if ((globals = (_cups_globals_t *)pthread_getspecific(globals_key)) == NULL) + { + /* + * No, allocate memory as set the pointer for the key... + */ + + globals = calloc(1, sizeof(_cups_globals_t)); + pthread_setspecific(globals_key, globals); + + /* + * Initialize variables that have non-zero values + */ + + globals->encryption = (http_encryption_t)-1; + globals->password_cb = _cupsGetPassword; + + cups_env_init(globals); + } + + /* + * Return the pointer to the data... + */ + + return (globals); +} + + +/* + * 'globals_init()' - Initialize globals once. + */ + +static void +globals_init() +{ + pthread_key_create(&globals_key, globals_destructor); +} + + +/* + * 'globals_destructor()' - Free memory allocated by _cupsGlobals(). + */ + +static void +globals_destructor(void *value) /* I - Data to free */ +{ + free(value); +} + + +#else +/* + * Implement static globals... + */ + +/* + * '_cupsGlobals()' - Return a pointer to thread local storage. + */ + +_cups_globals_t * /* O - Pointer to global data */ +_cupsGlobals(void) +{ + static _cups_globals_t globals; /* Global data */ + static int initialized = 0;/* Global data initialized? */ + + + /* + * Initialize global data as needed... + */ + + if (!initialized) + { + initialized = 1; + + /* + * Initialize global variables... + */ + + memset(&globals, 0, sizeof(globals)); + + globals.encryption = (http_encryption_t)-1; + globals.password_cb = _cupsGetPassword; + + cups_env_init(&globals); + } + + return (&globals); +} +#endif /* HAVE_PTHREAD_H */ + + +/* + * End of "$Id: globals.c 4922 2006-01-12 22:05:06Z mike $". + */ diff --git a/cups/globals.h b/cups/globals.h new file mode 100644 index 000000000..cff946a96 --- /dev/null +++ b/cups/globals.h @@ -0,0 +1,156 @@ +/* + * "$Id: globals.h 4918 2006-01-12 05:14:40Z mike $" + * + * Global variable definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_GLOBALS_H_ +# define _CUPS_GLOBALS_H_ + +/* + * Include necessary headers... + */ + +# include "string.h" +# include "cups.h" +# include "i18n.h" +# include "normalize.h" +# include "transcode.h" + +# ifdef HAVE_PTHREAD_H +# include +# endif /* HAVE_PTHREAD_H */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * To make libcups thread safe, define thread safe globals (aka thread- + * specific data) for the static variables used in the library. + */ + +typedef struct _cups_globals_s /**** CUPS global state data ****/ +{ + /* Multiple places... */ + const char *cups_datadir, /* CUPS_DATADIR environment var */ + *cups_serverbin,/* CUPS_SERVERBIN environment var */ + *cups_serverroot, + /* CUPS_SERVERROOT environment var */ + *cups_statedir, /* CUPS_STATEDIR environment var */ + *localedir; /* LOCALDIR environment var */ + + /* http.c */ + char http_date[256]; /* Date+time buffer */ + + /* http-addr.c */ + unsigned ip_addr; /* Packed IPv4 address */ + char *ip_ptrs[2]; /* Pointer to packed address */ + struct hostent hostent; /* Host entry for IP address */ +# ifdef HAVE_GETADDRINFO + char hostname[1024]; /* Hostname */ +# endif /* HAVE_GETADDRINFO */ + + /* ipp.c */ + ipp_uchar_t ipp_date[11]; /* RFC-1903 date/time data */ + + /* ipp-support.c */ + int ipp_port; /* IPP port number */ + char ipp_unknown[255]; + /* Unknown error statuses */ + + /* normalize.c */ + _cups_norm_map_t *normmap_cache; /* Normalize Map cache */ + _cups_fold_map_t *foldmap_cache; /* Case Fold cache */ + _cups_prop_map_t *propmap_cache; /* Char Prop Map Cache */ + _cups_comb_map_t *combmap_cache; /* Comb Class Map Cache */ + _cups_break_map_t *breakmap_cache;/* Line Break Map Cache */ + + /* language.c */ + cups_lang_t *lang_cache; /* Language string cache */ +# ifdef __APPLE__ +# ifdef HAVE_CF_LOCALE_ID + char language[32]; /* Cached language */ +# else + const char *language; /* Cached language */ +# endif /* HAVE_CF_LOCALE_ID */ +# endif /* __APPLE__ */ + + /* ppd.c */ + ppd_status_t ppd_status; /* Status of last ppdOpen*() */ + int ppd_line; /* Current line number */ + ppd_conform_t ppd_conform; /* Level of conformance required */ + + /* tempfile.c */ + char tempfile[1024]; /* cupsTempFd/File buffer */ + + /* transcode.c */ + _cups_cmap_t *cmap_cache; /* SBCS Charmap Cache */ + _cups_vmap_t *vmap_cache; /* VBCS Charmap Cache */ + + /* usersys.c */ + http_encryption_t encryption; /* Encryption setting */ + char user[65], /* User name */ + server[256], /* Server address */ + servername[256];/* Server hostname */ + cups_password_cb_t password_cb; /* Password callback */ + + /* util.c */ + http_t *http; /* Current server connection */ + ipp_status_t last_error; /* Last IPP error */ + char *last_status_message; + /* Last IPP status-message */ + + char def_printer[256]; + /* Default printer */ + char ppd_filename[HTTP_MAX_URI]; + /* PPD filename */ +} _cups_globals_t; + + +/* + * Prototypes... + */ + +extern const char *_cupsGetPassword(const char *prompt); +extern _cups_globals_t *_cupsGlobals(void); + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_GLOBALS_H_ */ + +/* + * End of "$Id: globals.h 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/http-addr.c b/cups/http-addr.c new file mode 100644 index 000000000..ac4763bd2 --- /dev/null +++ b/cups/http-addr.c @@ -0,0 +1,545 @@ +/* + * "$Id: http-addr.c 4806 2005-10-21 18:49:24Z mike $" + * + * HTTP address routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * httpAddrAny() - Check for the "any" address. + * httpAddrEqual() - Compare two addresses. + * httpAddrLocalhost() - Check for the local loopback address. + * httpAddrLookup() - Lookup the hostname associated with the address. + * httpAddrString() - Convert an IP address to a dotted string. + * httpGetHostByName() - Lookup a hostname or IP address, and return + * address records for the specified name. + * httpGetHostname() - Get the FQDN for the local system. + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include "debug.h" +#include +#include + + +/* + * 'httpAddrAny()' - Check for the "any" address. + * + * @since CUPS 1.2@ + */ + +int /* O - 1 if "any", 0 otherwise */ +httpAddrAny(const http_addr_t *addr) /* I - Address to check */ +{ +#ifdef AF_INET6 + if (addr->addr.sa_family == AF_INET6 && + IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr))) + return (1); +#endif /* AF_INET6 */ + + if (addr->addr.sa_family == AF_INET && + ntohl(addr->ipv4.sin_addr.s_addr) == 0x00000000) + return (1); + + return (0); +} + + +/* + * 'httpAddrEqual()' - Compare two addresses. + * + * @since CUPS 1.2@ + */ + +int /* O - 1 if equal, 0 if != */ +httpAddrEqual(const http_addr_t *addr1, /* I - First address */ + const http_addr_t *addr2) /* I - Second address */ +{ + if (addr1->addr.sa_family != addr2->addr.sa_family) + return (0); + +#ifdef AF_LOCAL + if (addr1->addr.sa_family == AF_LOCAL) + return (!strcmp(addr1->un.sun_path, addr2->un.sun_path)); +#endif /* AF_LOCAL */ + +#ifdef AF_INET6 + if (addr1->addr.sa_family == AF_INET6) + return (!memcmp(&(addr1->ipv6.sin6_addr), &(addr2->ipv6.sin6_addr), 16)); +#endif /* AF_INET6 */ + + return (addr1->ipv4.sin_addr.s_addr == addr2->ipv4.sin_addr.s_addr); +} + + +/* + * 'httpAddrLength()' - Return the length of the address in bytes. + * + * @since CUPS 1.2@ + */ + +int /* O - Length in bytes */ +httpAddrLength(const http_addr_t *addr) /* I - Address */ +{ +#ifdef AF_INET6 + if (addr->addr.sa_family == AF_INET6) + return (sizeof(addr->ipv6)); + else +#endif /* AF_INET6 */ +#ifdef AF_LOCAL + if (addr->addr.sa_family == AF_LOCAL) + return (offsetof(struct sockaddr_un, sun_path) + + strlen(addr->un.sun_path) + 1); + else +#endif /* AF_LOCAL */ + if (addr->addr.sa_family == AF_INET) + return (sizeof(addr->ipv4)); + else + return (0); + +} + + +/* + * 'httpAddrLocalhost()' - Check for the local loopback address. + * + * @since CUPS 1.2@ + */ + +int /* O - 1 if local host, 0 otherwise */ +httpAddrLocalhost( + const http_addr_t *addr) /* I - Address to check */ +{ +#ifdef AF_INET6 + if (addr->addr.sa_family == AF_INET6 && + (IN6_IS_ADDR_LOOPBACK(&(addr->ipv6.sin6_addr)) || + IN6_IS_ADDR_UNSPECIFIED(&(addr->ipv6.sin6_addr)))) + return (1); +#endif /* AF_INET6 */ + +#ifdef AF_LOCAL + if (addr->addr.sa_family == AF_LOCAL) + return (1); +#endif /* AF_LOCAL */ + + if (addr->addr.sa_family == AF_INET && + ntohl(addr->ipv4.sin_addr.s_addr) == 0x7f000001) + return (1); + + return (0); +} + + +#ifdef __sgi +# define ADDR_CAST (struct sockaddr *) +#else +# define ADDR_CAST (char *) +#endif /* __sgi */ + + +/* + * 'httpAddrLookup()' - Lookup the hostname associated with the address. + * + * @since CUPS 1.2@ + */ + +char * /* O - Host name */ +httpAddrLookup(const http_addr_t *addr, /* I - Address to lookup */ + char *name, /* I - Host name buffer */ + int namelen) /* I - Size of name buffer */ +{ + DEBUG_printf(("httpAddrLookup(addr=%p, name=%p, namelen=%d)\n", + addr, name, namelen)); + + /* + * Range check input... + */ + + if (!addr || !name || namelen <= 2) + { + if (name && namelen >= 1) + *name = '\0'; + + return (NULL); + } + +#ifdef AF_LOCAL + if (addr->addr.sa_family == AF_LOCAL) + strlcpy(name, addr->un.sun_path, namelen); + else +#endif /* AF_LOCAL */ +#ifdef HAVE_GETNAMEINFO + { + char servname[1024]; /* Service name (not used) */ + + + if (getnameinfo(&addr->addr, httpAddrLength(addr), name, namelen, + servname, sizeof(servname), 0)) + { + /* + * If we get an error back, then the address type is not supported + * and we should zero out the buffer... + */ + + name[0] = '\0'; + + return (NULL); + } + } +#else + { + struct hostent *host; /* Host from name service */ + + +# ifdef AF_INET6 + if (addr->addr.sa_family == AF_INET6) + host = gethostbyaddr(ADDR_CAST &(addr->ipv6.sin6_addr), + sizeof(struct in_addr), AF_INET6); + else +# endif /* AF_INET6 */ + host = gethostbyaddr(ADDR_CAST &(addr->ipv4.sin_addr), + sizeof(struct in_addr), AF_INET); + + if (host == NULL) + { + /* + * No hostname, so return the raw address... + */ + + httpAddrString(addr, name, namelen); + return (NULL); + } + + strlcpy(name, host->h_name, namelen); + } +#endif /* HAVE_GETNAMEINFO */ + + return (name); +} + + +/* + * 'httpAddrString()' - Convert an IP address to a dotted string. + * + * @since CUPS 1.2@ + */ + +char * /* O - IP string */ +httpAddrString(const http_addr_t *addr, /* I - Address to convert */ + char *s, /* I - String buffer */ + int slen) /* I - Length of string */ +{ + DEBUG_printf(("httpAddrString(addr=%p, s=%p, slen=%d)\n", + addr, s, slen)); + + /* + * Range check input... + */ + + if (!addr || !s || slen <= 2) + { + if (s && slen >= 1) + *s = '\0'; + + return (NULL); + } + +#ifdef AF_LOCAL + if (addr->addr.sa_family == AF_LOCAL) + strlcpy(s, addr->un.sun_path, slen); + else +#endif /* AF_LOCAL */ +#ifdef HAVE_GETNAMEINFO + { + char servname[1024]; /* Service name (not used) */ + + + if (getnameinfo(&addr->addr, httpAddrLength(addr), s, slen, + servname, sizeof(servname), NI_NUMERICHOST)) + { + /* + * If we get an error back, then the address type is not supported + * and we should zero out the buffer... + */ + + s[0] = '\0'; + + return (NULL); + } + } +#else + { +#ifdef AF_INET6 + if (addr->addr.sa_family == AF_INET6) + { + char *sptr; /* Pointer into string */ + int i; /* Looping var */ + unsigned temp; /* Current value */ + const char *prefix; /* Prefix for address */ + + + prefix = ""; + for (sptr = s, i = 0; i < 4 && addr->ipv6.sin6_addr.s6_addr32[i]; i ++) + { + temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]); + + snprintf(sptr, slen, "%s%x", prefix, (temp >> 16) & 0xffff); + prefix = ":"; + slen -= strlen(sptr); + sptr += strlen(sptr); + + temp &= 0xffff; + + if (temp || i == 3 || addr->ipv6.sin6_addr.s6_addr32[i + 1]) + { + snprintf(sptr, slen, "%s%x", prefix, temp); + slen -= strlen(sptr); + sptr += strlen(sptr); + } + } + + if (i < 4) + { + while (i < 4 && !addr->ipv6.sin6_addr.s6_addr32[i]) + i ++; + + if (i < 4) + { + snprintf(sptr, slen, "%s:", prefix); + prefix = ":"; + slen -= strlen(sptr); + sptr += strlen(sptr); + + for (; i < 4; i ++) + { + temp = ntohl(addr->ipv6.sin6_addr.s6_addr32[i]); + + if ((temp & 0xffff0000) || addr->ipv6.sin6_addr.s6_addr32[i - 1]) + { + snprintf(sptr, slen, "%s%x", prefix, (temp >> 16) & 0xffff); + slen -= strlen(sptr); + sptr += strlen(sptr); + } + + snprintf(sptr, slen, "%s%x", prefix, temp & 0xffff); + slen -= strlen(sptr); + sptr += strlen(sptr); + } + } + else if (sptr == s) + { + /* + * Empty address... + */ + + strlcpy(s, "::", slen); + sptr = s + 2; + slen -= 2; + } + else + { + /* + * Empty at end... + */ + + strlcpy(sptr, "::", slen); + sptr += 2; + slen -= 2; + } + } + } + else +#endif /* AF_INET6 */ + if (addr->addr.sa_family == AF_INET) + { + unsigned temp; /* Temporary address */ + + + temp = ntohl(addr->ipv4.sin_addr.s_addr); + + snprintf(s, slen, "%d.%d.%d.%d", (temp >> 24) & 255, + (temp >> 16) & 255, (temp >> 8) & 255, temp & 255); + } + else + strlcpy(s, "UNKNOWN", slen); + } +#endif /* HAVE_GETNAMEINFO */ + + DEBUG_printf(("httpAddrString: returning \"%s\"...\n", s)); + + return (s); +} + + +/* + * 'httpGetHostByName()' - Lookup a hostname or IPv4 address, and return + * address records for the specified name. + * + * @deprecated@ + */ + +struct hostent * /* O - Host entry */ +httpGetHostByName(const char *name) /* I - Hostname or IP address */ +{ + const char *nameptr; /* Pointer into name */ + unsigned ip[4]; /* IP address components */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + DEBUG_printf(("httpGetHostByName(name=\"%s\")\n", name)); + + /* + * Avoid lookup delays and configuration problems when connecting + * to the localhost address... + */ + + if (!strcmp(name, "localhost")) + name = "127.0.0.1"; + + /* + * This function is needed because some operating systems have a + * buggy implementation of gethostbyname() 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. + * + * We also support domain sockets when supported by the underlying + * OS... + */ + +#ifdef AF_LOCAL + if (name[0] == '/') + { + /* + * A domain socket address, so make an AF_LOCAL entry and return it... + */ + + cg->hostent.h_name = (char *)name; + cg->hostent.h_aliases = NULL; + cg->hostent.h_addrtype = AF_LOCAL; + cg->hostent.h_length = strlen(name) + 1; + cg->hostent.h_addr_list = cg->ip_ptrs; + cg->ip_ptrs[0] = (char *)name; + cg->ip_ptrs[1] = NULL; + + DEBUG_puts("httpGetHostByName: returning domain socket address..."); + + return (&cg->hostent); + } +#endif /* AF_LOCAL */ + + for (nameptr = name; isdigit(*nameptr & 255) || *nameptr == '.'; nameptr ++); + + if (!*nameptr) + { + /* + * We have an IPv4 address; break it up and provide the host entry + * to the caller. + */ + + if (sscanf(name, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) != 4) + return (NULL); /* Must have 4 numbers */ + + if (ip[0] > 255 || ip[1] > 255 || ip[2] > 255 || ip[3] > 255) + return (NULL); /* Invalid byte ranges! */ + + cg->ip_addr = htonl(((((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8) | + ip[3])); + + /* + * Fill in the host entry and return it... + */ + + cg->hostent.h_name = (char *)name; + cg->hostent.h_aliases = NULL; + cg->hostent.h_addrtype = AF_INET; + cg->hostent.h_length = 4; + cg->hostent.h_addr_list = cg->ip_ptrs; + cg->ip_ptrs[0] = (char *)&(cg->ip_addr); + cg->ip_ptrs[1] = NULL; + + DEBUG_puts("httpGetHostByName: returning IPv4 address..."); + + return (&cg->hostent); + } + else + { + /* + * Use the gethostbyname() function to get the IPv4 address for + * the name... + */ + + DEBUG_puts("httpGetHostByName: returning domain lookup address(es)..."); + + return (gethostbyname(name)); + } +} + + +/* + * 'httpGetHostname()' - Get the FQDN for the local system. + * + * This function uses both gethostname() and gethostbyname() to + * get the local hostname with domain. + * + * @since CUPS 1.2@ + */ + +const char * /* O - FQDN for this system */ +httpGetHostname(char *s, /* I - String buffer for name */ + int slen) /* I - Size of buffer */ +{ + struct hostent *host; /* Host entry to get FQDN */ + + + /* + * Get the hostname... + */ + + gethostname(s, slen); + + if (!strchr(s, '.')) + { + /* + * The hostname is not a FQDN, so look it up... + */ + + if ((host = gethostbyname(s)) != NULL) + strlcpy(s, host->h_name, slen); + } + + /* + * Return the hostname with as much domain info as we have... + */ + + return (s); +} + + +/* + * End of "$Id: http-addr.c 4806 2005-10-21 18:49:24Z mike $". + */ diff --git a/cups/http-addrlist.c b/cups/http-addrlist.c new file mode 100644 index 000000000..ed6194471 --- /dev/null +++ b/cups/http-addrlist.c @@ -0,0 +1,588 @@ +/* + * "$Id: http-addrlist.c 4815 2005-10-31 20:40:17Z mike $" + * + * HTTP address list routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * httpAddrConnect() - Connect to any of the addresses in the list. + * httpAddrFreeList() - Free an address list. + * httpAddrGetList() - Get a list of addresses for a hostname. + */ + +/* + * Include necessary headers... + */ + +#include "http-private.h" +#include "globals.h" +#include "debug.h" +#include + + +/* + * 'httpAddrConnect()' - Connect to any of the addresses in the list. + * + * @since CUPS 1.2@ + */ + +http_addrlist_t * /* O - Connected address or NULL on failure */ +httpAddrConnect( + http_addrlist_t *addrlist, /* I - List of potential addresses */ + int *sock) /* O - Socket */ +{ + int val; /* Socket option value */ + + + /* + * Loop through each address until we connect or run out of addresses... + */ + + while (addrlist) + { + /* + * Create the socket... + */ + + if ((*sock = socket(addrlist->addr.addr.sa_family, SOCK_STREAM, 0)) < 0) + { + /* + * Don't abort yet, as this could just be an issue with the local + * system not being configured with IPv4/IPv6/domain socket enabled... + */ + + addrlist = addrlist->next; + continue; + } + + /* + * Set options... + */ + + val = 1; +#ifdef WIN32 + setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&val, + sizeof(val)); +#else + setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); +#endif /* WIN32 */ + +#ifdef SO_REUSEPORT + val = 1; + setsockopt(*sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val)); +#endif /* SO_REUSEPORT */ + + /* + * Using TCP_NODELAY improves responsiveness, especially on systems + * with a slow loopback interface... + */ + + val = 1; +#ifdef WIN32 + setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&val, + sizeof(val)); +#else + setsockopt(*sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)); +#endif /* WIN32 */ + +#ifdef FD_CLOEXEC + /* + * Close this socket when starting another process... + */ + + fcntl(*sock, F_SETFD, FD_CLOEXEC); +#endif /* FD_CLOEXEC */ + + /* + * Then connect... + */ + + if (!connect(*sock, &(addrlist->addr.addr), + httpAddrLength(&(addrlist->addr)))) + break; + + /* + * Close this socket and move to the next address... + */ + + closesocket(*sock); + + addrlist = addrlist->next; + } + + return (addrlist); +} + + +/* + * 'httpAddrFreeList()' - Free an address list. + * + * @since CUPS 1.2@ + */ + +void +httpAddrFreeList( + http_addrlist_t *addrlist) /* I - Address list to free */ +{ + http_addrlist_t *next; /* Next address in list */ + + + /* + * Free each address in the list... + */ + + while (addrlist) + { + next = addrlist->next; + + free(addrlist); + + addrlist = next; + } +} + + +/* + * 'httpAddrGetList()' - Get a list of addresses for a hostname. + * + * @since CUPS 1.2@ + */ + +http_addrlist_t * /* O - List of addresses or NULL */ +httpAddrGetList(const char *hostname, /* I - Hostname, IP address, or NULL for passive listen address */ + int family, /* I - Address family or AF_UNSPEC */ + const char *service) /* I - Service name or port number */ +{ + http_addrlist_t *first, /* First address in list */ + *addr, /* Current address in list */ + *temp; /* New address */ + + +#ifdef DEBUG + printf("httpAddrGetList(hostname=\"%s\", family=AF_%s, service=\"%s\")\n", + hostname ? hostname : "(nil)", + family == AF_UNSPEC ? "UNSPEC" : +# ifdef AF_LOCAL + family == AF_LOCAL ? "LOCAL" : +# endif /* AF_LOCAL */ +# ifdef AF_INET6 + family == AF_INET6 ? "INET6" : +# endif /* AF_INET6 */ + family == AF_INET ? "INET" : "???", service); +#endif /* DEBUG */ + + /* + * Lookup the address the best way we can... + */ + + first = addr = NULL; + +#ifdef AF_LOCAL + if (hostname && hostname[0] == '/') + { + /* + * Domain socket address... + */ + + first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + first->addr.un.sun_family = AF_LOCAL; + strlcpy(first->addr.un.sun_path, hostname, sizeof(first->addr.un.sun_path)); + } + else +#endif /* AF_LOCAL */ + { +#ifdef HAVE_GETADDRINFO + struct addrinfo hints, /* Address lookup hints */ + *results, /* Address lookup results */ + *current; /* Current result */ + char ipv6[1024], /* IPv6 address */ + *ipv6zone; /* Pointer to zone separator */ + int ipv6len; /* Length of IPv6 address */ + + /* + * Lookup the address as needed... + */ + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; + hints.ai_flags = hostname ? 0 : AI_PASSIVE; + hints.ai_socktype = SOCK_STREAM; + + if (hostname && *hostname == '[') + { + /* + * Remove brackets from numeric IPv6 address... + */ + + if (!strncmp(hostname, "[v1.", 4)) + { + /* + * Copy the newer address format which supports link-local addresses... + */ + + strlcpy(ipv6, hostname + 4, sizeof(ipv6)); + if ((ipv6len = strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') + { + ipv6[ipv6len] = '\0'; + hostname = ipv6; + + /* + * Convert "+zone" in address to "%zone"... + */ + + if ((ipv6zone = strrchr(ipv6, '+')) != NULL) + *ipv6zone = '%'; + } + } + else + { + /* + * Copy the regular non-link-local IPv6 address... + */ + + strlcpy(ipv6, hostname + 1, sizeof(ipv6)); + if ((ipv6len = strlen(ipv6) - 1) >= 0 && ipv6[ipv6len] == ']') + { + ipv6[ipv6len] = '\0'; + hostname = ipv6; + } + } + } + + if (!getaddrinfo(hostname, service, &hints, &results)) + { + /* + * Copy the results to our own address list structure... + */ + + for (current = results; current; current = current->ai_next) + if (current->ai_family == AF_INET || current->ai_family == AF_INET6) + { + /* + * Copy the address over... + */ + + temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!temp) + { + httpAddrFreeList(first); + return (NULL); + } + + if (current->ai_family == AF_INET6) + memcpy(&(temp->addr.ipv6), current->ai_addr, + sizeof(temp->addr.ipv6)); + else + memcpy(&(temp->addr.ipv4), current->ai_addr, + sizeof(temp->addr.ipv4)); + + /* + * Append the address to the list... + */ + + if (!first) + first = temp; + + if (addr) + addr->next = temp; + + addr = temp; + } + + /* + * Free the results from getaddrinfo()... + */ + + freeaddrinfo(results); + } +#else + if (hostname) + { + int i; /* Looping vars */ + unsigned ip[4]; /* IPv4 address components */ + const char *ptr; /* Pointer into hostname */ + struct hostent *host; /* Result of lookup */ + struct servent *port; /* Port number for service */ + int portnum; /* Port number */ + + + /* + * Lookup the service... + */ + + if (!service) + portnum = 0; + else if (isdigit(*service & 255)) + portnum = atoi(service); + else if ((port = getservbyname(service, NULL)) != NULL) + portnum = ntohs(port->s_port); + else if (!strcmp(service, "http")) + portnum = 80; + else if (!strcmp(service, "https")) + portnum = 443; + else if (!strcmp(service, "ipp")) + portnum = 631; + else if (!strcmp(service, "lpd")) + portnum = 515; + else if (!strcmp(service, "socket")) + portnum = 9100; + else + return (NULL); + + /* + * This code is needed because some operating systems have a + * buggy implementation of gethostbyname() that does not support + * IPv4 addresses. If the hostname string is an IPv4 address, then + * sscanf() is used to extract the IPv4 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. + */ + + for (ptr = hostname; isdigit(*ptr & 255) || *ptr == '.'; ptr ++); + + if (!*ptr) + { + /* + * We have an IPv4 address; break it up and create an IPv4 address... + */ + + if (sscanf(hostname, "%u.%u.%u.%u", ip, ip + 1, ip + 2, ip + 3) == 4 && + ip[0] <= 255 && ip[1] <= 255 && ip[2] <= 255 && ip[3] <= 255) + { + first = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!first) + return (NULL); + + first->addr.ipv4.sin_family = AF_INET; + first->addr.ipv4.sin_addr.s_addr = htonl(((((((ip[0] << 8) | + ip[1]) << 8) | + ip[2]) << 8) | ip[3])); + first->addr.ipv4.sin_port = htons(portnum); + } + } + else if ((host = gethostbyname(hostname)) != NULL && +# ifdef AF_INET6 + (host->h_addrtype == AF_INET || host->h_addrtype == AF_INET6)) +# else + host->h_addrtype == AF_INET) +# endif /* AF_INET6 */ + { + for (i = 0; host->h_addr_list[i]; i ++) + { + /* + * Copy the address over... + */ + + temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!temp) + { + httpAddrFreeList(first); + return (NULL); + } + +# ifdef AF_INET6 + if (host->h_addrtype == AF_INET6) + { + first->addr.ipv6.sin6_family = AF_INET6; + memcpy(&(temp->addr.ipv6), host->h_addr_list[i], + sizeof(temp->addr.ipv6)); + temp->addr.ipv6.sin6_port = htons(portnum); + } + else +# endif /* AF_INET6 */ + { + first->addr.ipv4.sin_family = AF_INET; + memcpy(&(temp->addr.ipv4), host->h_addr_list[i], + sizeof(temp->addr.ipv4)); + temp->addr.ipv4.sin_port = htons(portnum); + } + + /* + * Append the address to the list... + */ + + if (!first) + first = temp; + + if (addr) + addr->next = temp; + + addr = temp; + } + } + } +#endif /* HAVE_GETADDRINFO */ + } + + /* + * Detect some common errors and handle them sanely... + */ + + if (!addr && (!hostname || !strcmp(hostname, "localhost"))) + { + struct servent *port; /* Port number for service */ + int portnum; /* Port number */ + + + /* + * Lookup the service... + */ + + if (!service) + portnum = 0; + else if (isdigit(*service & 255)) + portnum = atoi(service); + else if ((port = getservbyname(service, NULL)) != NULL) + portnum = ntohs(port->s_port); + else if (!strcmp(service, "http")) + portnum = 80; + else if (!strcmp(service, "https")) + portnum = 443; + else if (!strcmp(service, "ipp")) + portnum = 631; + else if (!strcmp(service, "lpd")) + portnum = 515; + else if (!strcmp(service, "socket")) + portnum = 9100; + else + return (NULL); + + if (hostname && !strcmp(hostname, "localhost")) + { + /* + * Unfortunately, some users ignore all of the warnings in the + * /etc/hosts file and delete "localhost" from it. If we get here + * then we were unable to resolve the name, so use the IPv6 and/or + * IPv4 loopback interface addresses... + */ + +#ifdef AF_INET6 + if (family != AF_INET) + { + /* + * Add [::1] to the address list... + */ + + temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!temp) + { + httpAddrFreeList(first); + return (NULL); + } + + temp->addr.ipv6.sin6_family = AF_INET6; + temp->addr.ipv6.sin6_port = htons(portnum); +# ifdef WIN32 + temp->addr.ipv6.sin6_addr.u.Byte[15] = 1; +# else + temp->addr.ipv6.sin6_addr.s6_addr32[3] = htonl(1); +# endif /* WIN32 */ + + addr = temp; + } + + if (family != AF_INET6) +#endif /* AF_INET6 */ + { + /* + * Add 127.0.0.1 to the address list... + */ + + temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!temp) + { + httpAddrFreeList(first); + return (NULL); + } + + temp->addr.ipv4.sin_family = AF_INET; + temp->addr.ipv4.sin_port = htons(portnum); + temp->addr.ipv4.sin_addr.s_addr = htonl(0x7f000001); + + if (addr) + addr->next = temp; + else + addr = temp; + } + } + else if (!hostname) + { + /* + * Provide one or more passive listening addresses... + */ + +#ifdef AF_INET6 + if (family != AF_INET) + { + /* + * Add [::] to the address list... + */ + + temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!temp) + { + httpAddrFreeList(first); + return (NULL); + } + + temp->addr.ipv6.sin6_family = AF_INET6; + temp->addr.ipv6.sin6_port = htons(portnum); + + addr = temp; + } + + if (family != AF_INET6) +#endif /* AF_INET6 */ + { + /* + * Add 0.0.0.0 to the address list... + */ + + temp = (http_addrlist_t *)calloc(1, sizeof(http_addrlist_t)); + if (!temp) + { + httpAddrFreeList(first); + return (NULL); + } + + temp->addr.ipv4.sin_family = AF_INET; + temp->addr.ipv4.sin_port = htons(portnum); + + if (addr) + addr->next = temp; + else + addr = temp; + } + } + } + + /* + * Return the address list... + */ + + return (first); +} + + +/* + * End of "$Id: http-addrlist.c 4815 2005-10-31 20:40:17Z mike $". + */ diff --git a/cups/http-private.h b/cups/http-private.h new file mode 100644 index 000000000..5ecf57983 --- /dev/null +++ b/cups/http-private.h @@ -0,0 +1,126 @@ +/* + * "$Id: http-private.h 4800 2005-10-18 18:06:20Z mike $" + * + * Private HTTP definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_HTTP_PRIVATE_H_ +# define _CUPS_HTTP_PRIVATE_H_ + +/* + * Include necessary headers... + */ + +# include "config.h" + +# ifdef __sun +/* + * Define FD_SETSIZE to CUPS_MAX_FDS on Solaris to get the correct version of + * select() for large numbers of file descriptors. + */ + +# define FD_SETSIZE CUPS_MAX_FDS +# include +# endif /* __sun */ + +# include +# ifdef WIN32 +# include +# include +# else +# include +# include +# include +# define closesocket(f) close(f) +# endif /* WIN32 */ + +# ifdef __sgi +/* + * IRIX does not define socklen_t, and in fact uses an int instead of + * unsigned type for length values... + */ + +typedef int socklen_t; +# endif /* __sgi */ + +# include "http.h" + +# if defined HAVE_LIBSSL +/* + * The OpenSSL library provides its own SSL/TLS context structure for its + * IO and protocol management... + */ + +# include +# include +# include + +typedef SSL http_tls_t; + +# elif defined HAVE_GNUTLS +/* + * The GNU TLS library is more of a "bare metal" SSL/TLS library... + */ +# include + +typedef struct +{ + gnutls_session session; /* GNU TLS session object */ + void *credentials; /* GNU TLS credentials object */ +} http_tls_t; + +# elif defined(HAVE_CDSASSL) +/* + * Darwin's Security framework provides its own SSL/TLS context structure + * for its IO and protocol management... + */ + +# include + +typedef SSLConnectionRef http_tls_t; + +extern OSStatus _httpReadCDSA(SSLConnectionRef connection, void *data, + size_t *dataLength); +extern OSStatus _httpWriteCDSA(SSLConnectionRef connection, const void *data, + size_t *dataLength); +# endif /* HAVE_LIBSSL */ + +/* + * Some OS's don't have hstrerror(), most notably Solaris... + */ + +# ifndef HAVE_HSTRERROR +extern const char *_cups_hstrerror(int error); +# define hstrerror _cups_hstrerror +# elif defined(_AIX) || defined(__osf__) +/* + * AIX and Tru64 UNIX don't provide a prototype but do provide the function... + */ +extern const char *hstrerror(int error); +# endif /* !HAVE_HSTRERROR */ + +#endif /* !_CUPS_HTTP_PRIVATE_H_ */ + +/* + * End of "$Id: http-private.h 4800 2005-10-18 18:06:20Z mike $". + */ diff --git a/cups/http-support.c b/cups/http-support.c new file mode 100644 index 000000000..b62496a3e --- /dev/null +++ b/cups/http-support.c @@ -0,0 +1,1195 @@ +/* + * "$Id: http-support.c 4903 2006-01-10 20:02:46Z mike $" + * + * HTTP support routines for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * httpAssembleURI() - Assemble a uniform resource identifier from its + * components. + * httpAssembleURIf() - Assemble a uniform resource identifier from its + * components with a formatted resource. + * httpDecode64() - Base64-decode a string. + * httpDecode64_2() - Base64-decode a string. + * httpEncode64() - Base64-encode a string. + * httpEncode64_2() - Base64-encode a string. + * httpGetDateString() - Get a formatted date/time string from a time value. + * httpGetDateString2() - Get a formatted date/time string from a time value. + * httpGetDateTime() - Get a time value from a formatted date/time string. + * httpSeparate() - Separate a Universal Resource Identifier into its + * components. + * httpSeparate2() - Separate a Universal Resource Identifier into its + * components. + * httpSeparateURI() - Separate a Universal Resource Identifier into its + * components. + * httpStatus() - Return a short string describing a HTTP status code. + * _cups_hstrerror() - hstrerror() emulation function for Solaris and + * others... + * http_copy_decode() - Copy and decode a URI. + * http_copy_encode() - Copy and encode a URI. + */ + +/* + * Include necessary headers... + */ + +#include "debug.h" +#include "globals.h" +#include + + +/* + * Local globals... + */ + +static const char * const http_days[7] = + { + "Sun", "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" + }; +static const char * const http_months[12] = + { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + +/* + * Local functions... + */ + +static const char *http_copy_decode(char *dst, const char *src, + int dstsize, const char *term); +static char *http_copy_encode(char *dst, const char *src, + char *dstend, const char *reserved); + + +/* + * 'httpAssembleURI()' - Assemble a uniform resource identifier from its + * components. + * + * This function properly escapes all reserved characters in a URI. You + * should use this function in place of traditional string functions + * whenever you need to create a URI string. + * + * @since CUPS 1.2@ + */ + +http_uri_status_t /* O - URI status */ +httpAssembleURI(char *uri, /* I - URI buffer */ + int urilen, /* I - Size of URI buffer */ + const char *scheme, /* I - Scheme name */ + const char *username, /* I - Username */ + const char *host, /* I - Hostname or address */ + int port, /* I - Port number */ + const char *resource) /* I - Resource */ +{ + return (httpAssembleURIf(uri, urilen, scheme, username, host, port, "%s", + resource)); +} + + +/* + * 'httpAssembleURIf()' - Assemble a uniform resource identifier from its + * components with a formatted resource. + * + * This function creates a formatted version of the resource string + * argument "resourcef" and properly escapes all reserved characters + * in a URI. You should use this function in place of traditional + * string functions whenever you need to create a URI string. + * + * @since CUPS 1.2@ + */ + +http_uri_status_t /* O - URI status */ +httpAssembleURIf(char *uri, /* I - URI buffer */ + int urilen, /* I - Size of URI buffer */ + const char *scheme, /* I - Scheme name */ + const char *username, /* I - Username */ + const char *host, /* I - Hostname or address */ + int port, /* I - Port number */ + const char *resourcef, /* I - Printf-style resource */ + ...) /* I - Additional arguments as needed */ +{ + char *ptr, /* Pointer into URI buffer */ + *end; /* End of URI buffer */ + va_list ap; /* Pointer to additional arguments */ + char resource[1024]; /* Formatted resource string */ + int bytes; /* Bytes in formatted string */ + + + /* + * Range check input... + */ + + if (!uri || urilen < 1 || !scheme || port < 0) + { + if (uri) + *uri = '\0'; + + return (HTTP_URI_BAD_ARGUMENTS); + } + + /* + * Assemble the URI starting with the scheme... + */ + + end = uri + urilen - 1; + ptr = http_copy_encode(uri, scheme, end, NULL); + + if (!ptr) + goto assemble_overflow; + + if (!strcmp(scheme, "mailto:")) + { + /* + * mailto: only has :, no //... + */ + + if (ptr < end) + *ptr++ = ':'; + else + goto assemble_overflow; + } + else + { + /* + * Schemes other than mailto: all have //... + */ + + if ((ptr + 2) < end) + { + *ptr++ = ':'; + *ptr++ = '/'; + *ptr++ = '/'; + } + else + goto assemble_overflow; + } + + /* + * Next the username and hostname, if any... + */ + + if (host) + { + if (username && *username) + { + /* + * Add username@ first... + */ + + ptr = http_copy_encode(ptr, username, end, "/?@"); + + if (!ptr) + goto assemble_overflow; + + if (ptr < end) + *ptr++ = '@'; + else + goto assemble_overflow; + } + + /* + * Then add the hostname. Since IPv6 is a particular pain to deal + * with, we have several special cases to deal with... If we get + * an IPv6 address with brackets around it, assume it is already in + * URI format... + */ + + if (host[0] != '[' && strchr(host, ':')) + { + /* + * We have an IPv6 address... + */ + + if (strchr(host, '%')) + { + /* + * We have a link-local address, add "[v1." prefix... + */ + + if ((ptr + 4) < end) + { + *ptr++ = '['; + *ptr++ = 'v'; + *ptr++ = '1'; + *ptr++ = '.'; + } + else + goto assemble_overflow; + } + else + { + /* + * We have a normal address, add "[" prefix... + */ + + if (ptr < end) + *ptr++ = '['; + else + goto assemble_overflow; + } + + /* + * Copy the rest of the IPv6 address, and terminate with "]". + */ + + while (ptr < end && *host) + { + if (*host == '%') + { + *ptr++ = '+'; /* Convert zone separator */ + host ++; + } + else + *ptr++ = *host++; + } + + if (*host) + goto assemble_overflow; + + if (ptr < end) + *ptr++ = ']'; + else + goto assemble_overflow; + } + else + { + /* + * Otherwise, just copy the host string... + */ + + ptr = http_copy_encode(ptr, host, end, NULL); + + if (!ptr) + goto assemble_overflow; + } + + /* + * Finish things off with the port number... + */ + + if (port > 0) + { + snprintf(ptr, end - ptr + 1, ":%d", port); + ptr += strlen(ptr); + + if (ptr >= end) + goto assemble_overflow; + } + } + + /* + * Last but not least, add the resource string... + */ + + if (resourcef) + { + va_start(ap, resourcef); + bytes = vsnprintf(resource, sizeof(resource), resourcef, ap); + va_end(ap); + + if (bytes >= sizeof(resource)) + goto assemble_overflow; + + ptr = http_copy_encode(ptr, resource, end, NULL); + if (!ptr) + goto assemble_overflow; + } + else if (ptr < end) + *ptr++ = '/'; + else + goto assemble_overflow; + + /* + * Nul-terminate the URI buffer and return with no errors... + */ + + *ptr = '\0'; + + return (HTTP_URI_OK); + + /* + * Clear the URI string and return an overflow error; I don't usually + * like goto's, but in this case it makes sense... + */ + + assemble_overflow: + + *uri = '\0'; + return (HTTP_URI_OVERFLOW); +} + + +/* + * '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 outlen; /* Output buffer length */ + + + /* + * Use the old maximum buffer size for binary compatibility... + */ + + outlen = 512; + + return (httpDecode64_2(out, &outlen, in)); +} + + +/* + * 'httpDecode64_2()' - Base64-decode a string. + * + * @since CUPS 1.1.21@ + */ + +char * /* O - Decoded string */ +httpDecode64_2(char *out, /* I - String to write to */ + int *outlen, /* IO - Size of output string */ + const char *in) /* I - String to read from */ +{ + int pos, /* Bit position */ + base64; /* Value of this character */ + char *outptr, /* Output pointer */ + *outend; /* End of output buffer */ + + + /* + * Range check input... + */ + + if (!out || !outlen || *outlen < 1 || !in || !*in) + return (NULL); + + /* + * Convert from base-64 to bytes... + */ + + for (outptr = out, outend = out + *outlen - 1, 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 : + if (outptr < outend) + *outptr = base64 << 2; + pos ++; + break; + case 1 : + if (outptr < outend) + *outptr++ |= (base64 >> 4) & 3; + if (outptr < outend) + *outptr = (base64 << 4) & 255; + pos ++; + break; + case 2 : + if (outptr < outend) + *outptr++ |= (base64 >> 2) & 15; + if (outptr < outend) + *outptr = (base64 << 6) & 255; + pos ++; + break; + case 3 : + if (outptr < outend) + *outptr++ |= base64; + pos = 0; + break; + } + } + + *outptr = '\0'; + + /* + * Return the decoded string and size... + */ + + *outlen = (int)(outptr - out); + + 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 */ +{ + return (httpEncode64_2(out, 512, in, strlen(in))); +} + + +/* + * 'httpEncode64_2()' - Base64-encode a string. + * + * @since CUPS 1.1.21@ + */ + +char * /* O - Encoded string */ +httpEncode64_2(char *out, /* I - String to write to */ + int outlen, /* I - Size of output string */ + const char *in, /* I - String to read from */ + int inlen) /* I - Size of input string */ +{ + char *outptr, /* Output pointer */ + *outend; /* End of output buffer */ + static const char base64[] = /* Base64 characters... */ + { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "+/" + }; + + + /* + * Range check input... + */ + + if (!out || outlen < 1 || !in) + return (NULL); + + /* + * Convert bytes to base-64... + */ + + for (outptr = out, outend = out + outlen - 1; inlen > 0; in ++, inlen --) + { + /* + * Encode the up to 3 characters as 4 Base64 numbers... + */ + + if (outptr < outend) + *outptr ++ = base64[(in[0] & 255) >> 2]; + if (outptr < outend) + *outptr ++ = base64[(((in[0] & 255) << 4) | ((in[1] & 255) >> 4)) & 63]; + + in ++; + inlen --; + if (inlen <= 0) + { + if (outptr < outend) + *outptr ++ = '='; + if (outptr < outend) + *outptr ++ = '='; + break; + } + + if (outptr < outend) + *outptr ++ = base64[(((in[0] & 255) << 2) | ((in[1] & 255) >> 6)) & 63]; + + in ++; + inlen --; + if (inlen <= 0) + { + if (outptr < outend) + *outptr ++ = '='; + break; + } + + if (outptr < outend) + *outptr ++ = base64[in[0] & 63]; + } + + *outptr = '\0'; + + /* + * Return the encoded string... + */ + + return (out); +} + + +/* + * 'httpGetDateString()' - Get a formatted date/time string from a time value. + * + * @deprecated@ + */ + +const char * /* O - Date/time string */ +httpGetDateString(time_t t) /* I - UNIX time */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + return (httpGetDateString2(t, cg->http_date, sizeof(cg->http_date))); +} + + +/* + * 'httpGetDateString2()' - Get a formatted date/time string from a time value. + * + * @since CUPS 1.2@ + */ + +const char * /* O - Date/time string */ +httpGetDateString2(time_t t, /* I - UNIX time */ + char *s, /* I - String buffer */ + int slen) /* I - Size of string buffer */ +{ + struct tm *tdate; /* UNIX date/time data */ + + + tdate = gmtime(&t); + snprintf(s, slen, "%s, %02d %s %d %02d:%02d:%02d GMT", + http_days[tdate->tm_wday], tdate->tm_mday, + http_months[tdate->tm_mon], tdate->tm_year + 1900, + tdate->tm_hour, tdate->tm_min, tdate->tm_sec); + + return (s); +} + + +/* + * '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 */ + char mon[16]; /* Abbreviated month name */ + int day, year; /* Day of month and year */ + int hour, min, sec; /* Time */ + int days; /* Number of days since 1970 */ + static const int normal_days[] = /* Days to a month, normal years */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }; + static const int leap_days[] = /* Days to a month, leap years */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }; + + + DEBUG_printf(("httpGetDateTime(s=\"%s\")\n", s)); + + /* + * Extract the date and time from the formatted string... + */ + + if (sscanf(s, "%*s%d%15s%d%d:%d:%d", &day, mon, &year, &hour, &min, &sec) < 6) + return (0); + + DEBUG_printf((" day=%d, mon=\"%s\", year=%d, hour=%d, min=%d, sec=%d\n", + day, mon, year, hour, min, sec)); + + /* + * Convert the month name to a number from 0 to 11. + */ + + for (i = 0; i < 12; i ++) + if (!strcasecmp(mon, http_months[i])) + break; + + if (i >= 12) + return (0); + + DEBUG_printf((" i=%d\n", i)); + + /* + * Now convert the date and time to a UNIX time value in seconds since + * 1970. We can't use mktime() since the timezone may not be UTC but + * the date/time string *is* UTC. + */ + + if ((year & 3) == 0 && ((year % 100) != 0 || (year % 400) == 0)) + days = leap_days[i] + day - 1; + else + days = normal_days[i] + day - 1; + + DEBUG_printf((" days=%d\n", days)); + + days += (year - 1970) * 365 + /* 365 days per year (normally) */ + ((year - 1) / 4 - 492) - /* + leap days */ + ((year - 1) / 100 - 19) + /* - 100 year days */ + ((year - 1) / 400 - 4); /* + 400 year days */ + + DEBUG_printf((" days=%d\n", days)); + + return (days * 86400 + hour * 3600 + min * 60 + sec); +} + + +/* + * 'httpSeparate()' - Separate a Universal Resource Identifier into its + * components. + */ + +void +httpSeparate(const char *uri, /* I - Universal Resource Identifier */ + char *scheme, /* O - Scheme [32] (http, https, etc.) */ + char *username, /* O - Username [1024] */ + char *host, /* O - Hostname [1024] */ + int *port, /* O - Port number to use */ + char *resource) /* O - Resource/filename [1024] */ +{ + httpSeparateURI(uri, scheme, 32, username, HTTP_MAX_URI, host, HTTP_MAX_URI, + port, resource, HTTP_MAX_URI); +} + + +/* + * 'httpSeparate2()' - Separate a Universal Resource Identifier into its + * components. + * + * @since CUPS 1.1.21@ + */ + +void +httpSeparate2(const char *uri, /* I - Universal Resource Identifier */ + char *scheme, /* O - Scheme (http, https, etc.) */ + int schemelen, /* I - Size of scheme buffer */ + char *username, /* O - Username */ + int usernamelen, /* I - Size of username buffer */ + char *host, /* O - Hostname */ + int hostlen, /* I - Size of hostname buffer */ + int *port, /* O - Port number to use */ + char *resource, /* O - Resource/filename */ + int resourcelen) /* I - Size of resource buffer */ +{ + httpSeparateURI(uri, scheme, schemelen, username, usernamelen, host, hostlen, + port, resource, resourcelen); +} + + +/* + * 'httpSeparateURI()' - Separate a Universal Resource Identifier into its + * components. + * + * @since CUPS 1.2@ + */ + +http_uri_status_t /* O - Result of separation */ +httpSeparateURI(const char *uri, /* I - Universal Resource Identifier */ + char *scheme, /* O - Scheme (http, https, etc.) */ + int schemelen, /* I - Size of scheme buffer */ + char *username, /* O - Username */ + int usernamelen, /* I - Size of username buffer */ + char *host, /* O - Hostname */ + int hostlen, /* I - Size of hostname buffer */ + int *port, /* O - Port number to use */ + char *resource, /* O - Resource/filename */ + int resourcelen) /* I - Size of resource buffer */ +{ + char *ptr, /* Pointer into string... */ + *end; /* End of string */ + const char *sep; /* Separator character */ + http_uri_status_t status; /* Result of separation */ + + + /* + * Initialize everything to blank... + */ + + if (scheme && schemelen > 0) + *scheme = '\0'; + + if (username && usernamelen > 0) + *username = '\0'; + + if (host && hostlen > 0) + *host = '\0'; + + if (port) + *port = 0; + + if (resource && resourcelen > 0) + *resource = '\0'; + + /* + * Range check input... + */ + + if (!uri || !port || !scheme || schemelen <= 0 || !username || + usernamelen <= 0 || !host || hostlen <= 0 || !resource || + resourcelen <= 0) + return (HTTP_URI_BAD_ARGUMENTS); + + if (!*uri) + return (HTTP_URI_BAD_URI); + + /* + * Grab the scheme portion of the URI... + */ + + status = HTTP_URI_OK; + + if (!strncmp(uri, "//", 2)) + { + /* + * Workaround for HP IPP client bug... + */ + + strlcpy(scheme, "ipp", schemelen); + status = HTTP_URI_MISSING_SCHEME; + } + else if (*uri == '/') + { + /* + * Filename... + */ + + strlcpy(scheme, "file", schemelen); + status = HTTP_URI_MISSING_SCHEME; + } + else + { + /* + * Standard URI with scheme... + */ + + for (ptr = scheme, end = scheme + schemelen - 1; + *uri && *uri != ':' && ptr < end;) + if (isalnum(*uri & 255) || *uri == '-' || *uri == '+' || *uri == '.') + *ptr++ = *uri++; + else + break; + + *ptr = '\0'; + + if (*uri != ':') + { + *scheme = '\0'; + return (HTTP_URI_BAD_SCHEME); + } + + uri ++; + } + + /* + * Set the default port number... + */ + + if (!strcmp(scheme, "http")) + *port = 80; + else if (!strcmp(scheme, "https")) + *port = 443; + else if (!strcmp(scheme, "ipp")) + *port = 631; + else if (!strcasecmp(scheme, "lpd")) + *port = 515; + else if (!strcmp(scheme, "socket")) /* Not yet registered with IANA... */ + *port = 9100; + else if (strcmp(scheme, "file") && strcmp(scheme, "mailto")) + status = HTTP_URI_UNKNOWN_SCHEME; + + /* + * Now see if we have a hostname... + */ + + if (!strncmp(uri, "//", 2)) + { + /* + * Yes, extract it... + */ + + uri += 2; + + /* + * Grab the username, if any... + */ + + if ((sep = strpbrk(uri, "@/")) != NULL && *sep == '@') + { + /* + * Get a username:password combo... + */ + + uri = http_copy_decode(username, uri, usernamelen, "@"); + + if (!uri) + { + *username = '\0'; + return (HTTP_URI_BAD_USERNAME); + } + + uri ++; + } + + /* + * Then the hostname/IP address... + */ + + if (*uri == '[') + { + /* + * Grab IPv6 address... + */ + + uri ++; + if (!strncmp(uri, "v1.", 3)) + uri += 3; /* Skip IPvN leader... */ + + uri = http_copy_decode(host, uri, hostlen, "]"); + + if (!uri) + { + *host = '\0'; + return (HTTP_URI_BAD_HOSTNAME); + } + + /* + * Validate value... + */ + + if (*uri != ']') + { + *host = '\0'; + return (HTTP_URI_BAD_HOSTNAME); + } + + uri ++; + + for (ptr = host; *ptr; ptr ++) + if (*ptr == '+') + { + /* + * Convert zone separator to % and stop here... + */ + + *ptr = '%'; + break; + } + else if (*ptr != ':' && *ptr != '.' && !isxdigit(*ptr & 255)) + { + *host = '\0'; + return (HTTP_URI_BAD_HOSTNAME); + } + } + else + { + /* + * Grab hostname or IPv4 address... + */ + + uri = http_copy_decode(host, uri, hostlen, ":?/"); + + if (!uri) + { + *host = '\0'; + return (HTTP_URI_BAD_HOSTNAME); + } + + /* + * Validate value... + */ + + for (ptr = host; *ptr; ptr ++) + if (!strchr("abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "-._~" + "!$&'()*+,;=", *ptr)) + { + *host = '\0'; + return (HTTP_URI_BAD_HOSTNAME); + } + } + + /* + * Validate hostname for file scheme - only empty and localhost are + * acceptable. + */ + + if (!strcmp(scheme, "file") && strcmp(host, "localhost") && host[0]) + { + *host = '\0'; + return (HTTP_URI_BAD_HOSTNAME); + } + + /* + * See if we have a port number... + */ + + if (*uri == ':') + { + /* + * Yes, collect the port number... + */ + + *port = strtol(uri + 1, (char **)&uri, 10); + + if (*uri != '/') + { + *port = 0; + return (HTTP_URI_BAD_PORT); + } + } + } + + /* + * The remaining portion is the resource string... + */ + + if (*uri == '?' || !*uri) + { + /* + * Hostname but no path... + */ + + status = HTTP_URI_MISSING_RESOURCE; + *resource = '/'; + uri = http_copy_decode(resource + 1, uri, resourcelen - 1, ""); + } + else + uri = http_copy_decode(resource, uri, resourcelen, ""); + + if (!uri) + { + *resource = '\0'; + return (HTTP_URI_BAD_RESOURCE); + } + + /* + * Return the URI separation status... + */ + + return (status); +} + + +/* + * '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"); + } +} + + +#ifndef HAVE_HSTRERROR +/* + * '_cups_hstrerror()' - hstrerror() emulation function for Solaris and others... + */ + +const char * /* O - Error string */ +_cups_hstrerror(int error) /* I - Error number */ +{ + static const char * const errors[] = /* Error strings */ + { + "OK", + "Host not found.", + "Try again.", + "Unrecoverable lookup error.", + "No data associated with name." + }; + + + if (error < 0 || error > 4) + return ("Unknown hostname lookup error."); + else + return (errors[error]); +} +#endif /* !HAVE_HSTRERROR */ + + +/* + * 'http_copy_decode()' - Copy and decode a URI. + */ + +static const char * /* O - New source pointer or NULL on error */ +http_copy_decode(char *dst, /* O - Destination buffer */ + const char *src, /* I - Source pointer */ + int dstsize, /* I - Destination size */ + const char *term) /* I - Terminating characters */ +{ + char *ptr, /* Pointer into buffer */ + *end; /* End of buffer */ + int quoted; /* Quoted character */ + + + /* + * Copy the src to the destination until we hit a terminating character + * or the end of the string. + */ + + for (ptr = dst, end = dst + dstsize - 1; *src && !strchr(term, *src); src ++) + if (ptr < end) + { + if (*src == '%') + { + if (isxdigit(src[1] & 255) && isxdigit(src[2] & 255)) + { + /* + * Grab a hex-encoded character... + */ + + src ++; + if (isalpha(*src)) + quoted = (tolower(*src) - 'a' + 10) << 4; + else + quoted = (*src - '0') << 4; + + src ++; + if (isalpha(*src)) + quoted |= tolower(*src) - 'a' + 10; + else + quoted |= *src - '0'; + + *ptr++ = quoted; + } + else + { + /* + * Bad hex-encoded character... + */ + + *ptr = '\0'; + return (NULL); + } + } + else + *ptr++ = *src; + } + + *ptr = '\0'; + + return (src); +} + + +/* + * 'http_copy_encode()' - Copy and encode a URI. + */ + +static char * /* O - End of current URI */ +http_copy_encode(char *dst, /* O - Destination buffer */ + const char *src, /* I - Source pointer */ + char *dstend, /* I - End of destination buffer */ + const char *reserved) /* I - Extra reserved characters */ +{ + static const char *hex = "0123456789ABCDEF"; + + + while (*src && dst < dstend) + { + if (*src == '%' || *src <= ' ' || *src & 128 || + (reserved && strchr(reserved, *src))) + { + /* + * Hex encode reserved characters... + */ + + if ((dst + 2) >= dstend) + break; + + *dst++ = '%'; + *dst++ = hex[(*src >> 4) & 15]; + *dst++ = hex[*src & 15]; + + src ++; + } + else + *dst++ = *src++; + } + + if (*src) + return (NULL); + else + return (dst); +} + + +/* + * End of "$Id: http-support.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/cups/http.c b/cups/http.c new file mode 100644 index 000000000..2ef480b4a --- /dev/null +++ b/cups/http.c @@ -0,0 +1,2436 @@ +/* + * "$Id: http.c 4914 2006-01-11 02:04:22Z mike $" + * + * HTTP routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * httpCheck() - Check to see if there is a pending response from + * the server. + * httpClearCookie() - Clear the cookie value(s). + * httpClose() - Close an HTTP connection... + * httpConnect() - Connect to a HTTP server. + * httpConnectEncrypt() - Connect to a HTTP server using encryption. + * httpDelete() - Send a DELETE request to the server. + * httpEncryption() - Set the required encryption on the link. + * httpFlush() - Flush data from a HTTP connection. + * httpFlushWrite() - Flush data in write buffer. + * httpGet() - Send a GET request to the server. + * httpGetLength() - Get the amount of data remaining from the + * content-length or transfer-encoding fields. + * httpGetLength2() - Get the amount of data remaining from the + * content-length or transfer-encoding fields. + * httpGetSubField() - Get a sub-field value. + * httpGets() - Get a line of text from a HTTP connection. + * httpHead() - Send a HEAD request to the server. + * httpInitialize() - Initialize the HTTP interface library and set the + * default HTTP proxy (if any). + * httpOptions() - Send an OPTIONS request to the server. + * httpPost() - Send a POST request to the server. + * httpPrintf() - Print a formatted string to a HTTP connection. + * httpPut() - Send a PUT request to the server. + * httpRead() - Read data from a HTTP connection. + * _httpReadCDSA() - Read function for CDSA decryption code. + * httpReconnect() - Reconnect to a HTTP server... + * httpSetCookie() - Set the cookie value(s)... + * httpSetField() - Set the value of an HTTP header. + * httpSetLength() - Set the content-length and transfer-encoding. + * httpTrace() - Send an TRACE request to the server. + * httpUpdate() - Update the current HTTP state for incoming data. + * httpWait() - Wait for data available on a connection. + * httpWrite() - Write data to a HTTP connection. + * _httpWriteCDSA() - Write function for CDSA encryption code. + * http_field() - Return the field index for a field name. + * http_read_ssl() - Read from a SSL/TLS connection. + * http_send() - Send a request with all fields and the trailing + * blank line. + * http_setup_ssl() - Set up SSL/TLS on a connection. + * http_shutdown_ssl() - Shut down SSL/TLS on a connection. + * http_upgrade() - Force upgrade to TLS encryption. + * http_wait() - Wait for data available on a connection. + * http_write() - Write data to a connection. + * http_write_ssl() - Write to a SSL/TLS connection. + */ + +/* + * Include necessary headers... + */ + +#include "http-private.h" +#include "globals.h" +#include "debug.h" +#include +#include +#include +#ifndef WIN32 +# include +# include +# include +#endif /* !WIN32 */ + + +/* + * 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); +static int http_wait(http_t *http, int msec); +static int http_write(http_t *http, const char *buffer, + int length); +static int http_write_chunk(http_t *http, const char *buffer, + int length); +#ifdef HAVE_SSL +static int http_read_ssl(http_t *http, char *buf, int len); +static int http_setup_ssl(http_t *http); +static void http_shutdown_ssl(http_t *http); +static int http_upgrade(http_t *http); +static int http_write_ssl(http_t *http, const char *buf, int len); +#endif /* HAVE_SSL */ + + +/* + * Local globals... + */ + +static const char * const 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" + }; + + +/* + * '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 */ +{ + return (httpWait(http, 0)); +} + + +/* + * 'httpClearCookie()' - Clear the cookie value(s). + * + * @since CUPS 1.1.19@ + */ + +void +httpClearCookie(http_t *http) /* I - Connection */ +{ + if (!http) + return; + + if (http->cookie) + { + free(http->cookie); + http->cookie = NULL; + } +} + + +/* + * 'httpClose()' - Close an HTTP connection... + */ + +void +httpClose(http_t *http) /* I - Connection to close */ +{ + DEBUG_printf(("httpClose(http=%p)\n", http)); + + if (!http) + return; + + httpAddrFreeList(http->addrlist); + + if (http->input_set) + free(http->input_set); + + if (http->cookie) + free(http->cookie); + +#ifdef HAVE_SSL + if (http->tls) + http_shutdown_ssl(http); +#endif /* HAVE_SSL */ + +#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 encryption; /* Type of encryption to use */ + + + /* + * Set the default encryption status... + */ + + if (port == 443) + encryption = HTTP_ENCRYPT_ALWAYS; + else + encryption = HTTP_ENCRYPT_IF_REQUESTED; + + return (httpConnectEncrypt(host, port, encryption)); +} + + +/* + * '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 encryption) /* I - Type of encryption to use */ +{ + http_t *http; /* New HTTP connection */ + http_addrlist_t *addrlist; /* Host address data */ + char service[255]; /* Service name */ + + + DEBUG_printf(("httpConnectEncrypt(host=\"%s\", port=%d, encryption=%d)\n", + host ? host : "(null)", port, encryption)); + + if (!host) + return (NULL); + + httpInitialize(); + + /* + * Lookup the host... + */ + + sprintf(service, "%d", port); + + if ((addrlist = httpAddrGetList(host, AF_UNSPEC, service)) == NULL) + return (NULL); + + /* + * Allocate memory for the structure... + */ + + http = calloc(sizeof(http_t), 1); + if (http == NULL) + return (NULL); + + http->version = HTTP_1_1; + http->blocking = 1; + http->activity = time(NULL); + http->fd = -1; + + /* + * Set the encryption status... + */ + + if (port == 443) /* Always use encryption for https */ + http->encryption = HTTP_ENCRYPT_ALWAYS; + else + http->encryption = encryption; + + /* + * Loop through the addresses we have until one of them connects... + */ + + strlcpy(http->hostname, host, sizeof(http->hostname)); + + /* + * Connect to the remote system... + */ + + http->addrlist = addrlist; + + if (!httpReconnect(http)) + return (http); + + /* + * Could not connect to any known address - bail out! + */ + + httpAddrFreeList(addrlist); + + free(http); + + return (NULL); +} + + +/* + * '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)); +} + + +/* + * '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 */ +{ + DEBUG_printf(("httpEncryption(http=%p, e=%d)\n", http, e)); + +#ifdef HAVE_SSL + 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_SSL */ +} + + +/* + * 'httpFlush()' - Flush data from a HTTP connection. + */ + +void +httpFlush(http_t *http) /* I - HTTP data */ +{ + char buffer[8192]; /* Junk buffer */ + + + DEBUG_printf(("httpFlush(http=%p), state=%d\n", http, http->state)); + + while (httpRead(http, buffer, sizeof(buffer)) > 0); +} + + +/* + * 'httpFlushWrite()' - Flush data in write buffer. + * + * @since CUPS 1.2@ + */ + +int /* O - Bytes written or -1 on error */ +httpFlushWrite(http_t *http) /* I - HTTP data */ +{ + int bytes; /* Bytes written */ + + + DEBUG_printf(("httpFlushWrite(http=%p)\n", http)); + + if (!http || !http->wused) + return (0); + + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + bytes = http_write_chunk(http, http->wbuffer, http->wused); + else + bytes = http_write(http, http->wbuffer, http->wused); + + http->wused = 0; + + return (bytes); +} + + +/* + * '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)); +} + + +/* + * 'httpGetSubField()' - Get a sub-field value. + * + * @deprecated@ + */ + +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 */ +{ + return (httpGetSubField2(http, field, name, value, HTTP_MAX_VALUE)); +} + + +/* + * 'httpGetSubField2()' - Get a sub-field value. + * + * @since CUPS 1.2@ + */ + +char * /* O - Value or NULL */ +httpGetSubField2(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 */ + int valuelen) /* I - Size of value buffer */ +{ + const char *fptr; /* Pointer into field */ + char temp[HTTP_MAX_VALUE], /* Temporary buffer for name */ + *ptr, /* Pointer into string buffer */ + *end; /* End of value buffer */ + + DEBUG_printf(("httpGetSubField2(http=%p, field=%d, name=\"%s\", value=%p, valuelen=%d)\n", + http, field, name, value, valuelen)); + + if (!http || !name || !value || valuelen < 2 || + field < HTTP_FIELD_ACCEPT_LANGUAGE || + field > HTTP_FIELD_WWW_AUTHENTICATE) + return (NULL); + + end = value + valuelen - 1; + + for (fptr = http->fields[field]; *fptr;) + { + /* + * Skip leading whitespace... + */ + + while (isspace(*fptr & 255)) + fptr ++; + + if (*fptr == ',') + { + fptr ++; + continue; + } + + /* + * Get the sub-field name... + */ + + for (ptr = temp; + *fptr && *fptr != '=' && !isspace(*fptr & 255) && + ptr < (temp + sizeof(temp) - 1); + *ptr++ = *fptr++); + + *ptr = '\0'; + + DEBUG_printf(("httpGetSubField: name=\"%s\"\n", temp)); + + /* + * Skip trailing chars up to the '='... + */ + + while (isspace(*fptr & 255)) + fptr ++; + + if (!*fptr) + break; + + if (*fptr != '=') + continue; + + /* + * Skip = and leading whitespace... + */ + + fptr ++; + + while (isspace(*fptr & 255)) + fptr ++; + + if (*fptr == '\"') + { + /* + * Read quoted string... + */ + + for (ptr = value, fptr ++; + *fptr && *fptr != '\"' && ptr < end; + *ptr++ = *fptr++); + + *ptr = '\0'; + + while (*fptr && *fptr != '\"') + fptr ++; + + if (*fptr) + fptr ++; + } + else + { + /* + * Read unquoted string... + */ + + for (ptr = value; + *fptr && !isspace(*fptr & 255) && *fptr != ',' && ptr < end; + *ptr++ = *fptr++); + + *ptr = '\0'; + + while (*fptr && !isspace(*fptr & 255) && *fptr != ',') + fptr ++; + } + + DEBUG_printf(("httpGetSubField: value=\"%s\"\n", value)); + + /* + * See if this is the one... + */ + + if (!strcmp(name, temp)) + return (value); + } + + value[0] = '\0'; + + return (NULL); +} + + +/* + * 'httpGetLength()' - Get the amount of data remaining from the + * content-length or transfer-encoding fields. + * + * This function is deprecated and will not return lengths larger than + * 2^31 - 1; use httpGetLength2() instead. + * + * @since CUPS 1.2@ + */ + +int /* O - Content length */ +httpGetLength(http_t *http) /* I - HTTP data */ +{ + /* + * Get the read content length and return the 32-bit value. + */ + + httpGetLength2(http); + + return (http->_data_remaining); +} + + +/* + * 'httpGetLength2()' - Get the amount of data remaining from the + * content-length or transfer-encoding fields. + * + * This function returns the complete content length, even for + * content larger than 2^31 - 1. + */ + +off_t /* O - Content length */ +httpGetLength2(http_t *http) /* I - HTTP data */ +{ + DEBUG_printf(("httpGetLength2(http=%p), state=%d\n", http, http->state)); + + if (!strcasecmp(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked")) + { + DEBUG_puts("httpGetLength2: 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 = strtoll(http->fields[HTTP_FIELD_CONTENT_LENGTH], + NULL, 10); + + DEBUG_printf(("httpGetLength2: content_length=" CUPS_LLFMT "\n", + CUPS_LLCAST http->data_remaining)); + } + + if (http->data_remaining <= INT_MAX) + http->_data_remaining = (int)http->data_remaining; + else + http->_data_remaining = INT_MAX; + + return (http->data_remaining); +} + + +/* + * '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 */ + *lineend, /* End of line */ + *bufptr, /* Pointer into input buffer */ + *bufend; /* Pointer to end of buffer */ + int bytes, /* Number of bytes read */ + eol; /* End-of-line? */ + + + DEBUG_printf(("httpGets(line=%p, length=%d, http=%p)\n", line, length, http)); + + if (http == NULL || line == NULL) + return (NULL); + + /* + * Read a line from the buffer... + */ + + lineptr = line; + lineend = line + length - 1; + eol = 0; + + while (lineptr < lineend) + { + /* + * Pre-load the buffer as needed... + */ + +#ifdef WIN32 + WSASetLastError(0); +#else + errno = 0; +#endif /* WIN32 */ + + while (http->used == 0) + { + /* + * No newline; see if there is more data to be read... + */ + + if (!http->blocking && !http_wait(http, 1000)) + return (NULL); + +#ifdef HAVE_SSL + if (http->tls) + bytes = http_read_ssl(http, http->buffer + http->used, + HTTP_MAX_BUFFER - http->used); + else +#endif /* HAVE_SSL */ + bytes = recv(http->fd, http->buffer + http->used, + HTTP_MAX_BUFFER - http->used, 0); + + DEBUG_printf(("httpGets: read %d bytes...\n", bytes)); + + 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 + DEBUG_printf(("httpGets: recv() error %d!\n", errno)); + + if (errno == EINTR) + continue; + else if (errno != http->error) + { + http->error = errno; + continue; + } +#endif /* WIN32 */ + + return (NULL); + } + else if (bytes == 0) + { + http->error = EPIPE; + + return (NULL); + } + + /* + * Yup, update the amount used... + */ + + http->used += bytes; + } + + /* + * Now copy as much of the current line as possible... + */ + + for (bufptr = http->buffer, bufend = http->buffer + http->used; + lineptr < lineend && bufptr < bufend;) + { + if (*bufptr == 0x0a) + { + eol = 1; + bufptr ++; + break; + } + else if (*bufptr == 0x0d) + bufptr ++; + else + *lineptr++ = *bufptr++; + } + + http->used -= bufptr - http->buffer; + if (http->used > 0) + memmove(http->buffer, bufptr, http->used); + + if (eol) + { + /* + * End of line... + */ + + http->activity = time(NULL); + + *lineptr = '\0'; + + DEBUG_printf(("httpGets: Returning \"%s\"\n", line)); + + return (line); + } + } + + DEBUG_puts("httpGets: No new line available!"); + + return (NULL); +} + + +/* + * '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)); +} + + +/* + * 'httpInitialize()' - Initialize the HTTP interface library and set the + * default HTTP proxy (if any). + */ + +void +httpInitialize(void) +{ +#ifdef HAVE_LIBSSL +# ifndef WIN32 + struct timeval curtime; /* Current time in microseconds */ +# endif /* !WIN32 */ + 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_GNUTLS + gnutls_global_init(); +#endif /* HAVE_GNUTLS */ + +#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...) + */ + +#ifdef WIN32 +#else + gettimeofday(&curtime, NULL); + srand(curtime.tv_sec + curtime.tv_usec); +#endif /* WIN32 */ + + 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 */ +} + + +/* + * '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 */ +{ + return (http_send(http, HTTP_POST, uri)); +} + + +/* + * '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 */ + char buf[16384]; /* Buffer for formatted string */ + va_list ap; /* Variable argument pointer */ + + + DEBUG_printf(("httpPrintf(http=%p, format=\"%s\", ...)\n", http, format)); + + va_start(ap, format); + bytes = vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + DEBUG_printf(("httpPrintf: %s", buf)); + + if (http->wused) + { + DEBUG_puts(" flushing existing data..."); + + if (httpFlushWrite(http) < 0) + return (-1); + } + + return (http_write(http, buf, bytes)); +} + + +/* + * '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 */ +{ + return (http_send(http, HTTP_PUT, uri)); +} + + +/* + * '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(http=%p, buffer=%p, length=%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 = strtoll(len, NULL, 16); + if (http->data_remaining < 0) + { + DEBUG_puts("httpRead: Negative chunk length!"); + return (0); + } + } + + DEBUG_printf(("httpRead: data_remaining=" CUPS_LLFMT "\n", + CUPS_LLCAST 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; + + /* + * Prevent future reads for this request... + */ + + http->data_encoding = HTTP_ENCODE_LENGTH; + + 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->blocking && !httpWait(http, 1000)) + return (0); + + if (http->data_remaining > sizeof(http->buffer)) + bytes = sizeof(http->buffer); + else + bytes = http->data_remaining; + +#ifdef HAVE_SSL + if (http->tls) + bytes = http_read_ssl(http, http->buffer, bytes); + else +#endif /* HAVE_SSL */ + { + 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(); + return (-1); +#else + if (errno != EINTR) + { + http->error = errno; + return (-1); + } +#endif /* WIN32 */ + } + else + { + http->error = EPIPE; + 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) + memmove(http->buffer, http->buffer + length, http->used); + } +#ifdef HAVE_SSL + else if (http->tls) + { + if (!http->blocking && !httpWait(http, 1000)) + return (0); + + bytes = http_read_ssl(http, buffer, length); + } +#endif /* HAVE_SSL */ + else + { + if (!http->blocking && !httpWait(http, 1000)) + return (0); + + DEBUG_printf(("httpRead: reading %d bytes from socket...\n", length)); + + while ((bytes = recv(http->fd, buffer, length, 0)) < 0) + if (errno != EINTR) + break; + + DEBUG_printf(("httpRead: read %d bytes from socket...\n", bytes)); + } + + if (bytes > 0) + { + http->data_remaining -= bytes; + + if (http->data_remaining <= INT_MAX) + http->_data_remaining = (int)http->data_remaining; + else + http->_data_remaining = INT_MAX; + } + else if (bytes < 0) + { +#ifdef WIN32 + http->error = WSAGetLastError(); +#else + if (errno == EINTR) + bytes = 0; + else + http->error = errno; +#endif /* WIN32 */ + } + else + { + http->error = EPIPE; + return (0); + } + + 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; + } + } + +#ifdef DEBUG + { + int i, j, ch; + printf("httpRead: Read %d bytes:\n", bytes); + for (i = 0; i < bytes; i += 16) + { + printf(" "); + + for (j = 0; j < 16 && (i + j) < bytes; j ++) + printf(" %02X", buffer[i + j] & 255); + + while (j < 16) + { + printf(" "); + j ++; + } + + printf(" "); + for (j = 0; j < 16 && (i + j) < bytes; j ++) + { + ch = buffer[i + j] & 255; + + if (ch < ' ' || ch == 127) + ch = '.'; + + putchar(ch); + } + putchar('\n'); + } + } +#endif /* DEBUG */ + + return (bytes); +} + + +#if defined(HAVE_SSL) && defined(HAVE_CDSASSL) +/* + * '_httpReadCDSA()' - Read function for CDSA decryption code. + */ + +OSStatus /* O - -1 on error, 0 on success */ +_httpReadCDSA( + SSLConnectionRef connection, /* I - SSL/TLS connection */ + void *data, /* I - Data buffer */ + size_t *dataLength) /* IO - Number of bytes */ +{ + ssize_t bytes; /* Number of bytes read */ + + + bytes = recv((int)connection, data, *dataLength, 0); + if (bytes >= 0) + { + *dataLength = bytes; + return (0); + } + else + return (-1); +} +#endif /* HAVE_SSL && HAVE_CDSASSL */ + + +/* + * 'httpReconnect()' - Reconnect to a HTTP server... + */ + +int /* O - 0 on success, non-zero on failure */ +httpReconnect(http_t *http) /* I - HTTP data */ +{ + http_addrlist_t *addr; /* Connected address */ + + + DEBUG_printf(("httpReconnect(http=%p)\n", http)); + + if (!http) + return (-1); + +#ifdef HAVE_SSL + if (http->tls) + http_shutdown_ssl(http); +#endif /* HAVE_SSL */ + + /* + * Close any previously open socket... + */ + + if (http->fd >= 0) +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif /* WIN32 */ + + /* + * Connect to the server... + */ + + if ((addr = httpAddrConnect(http->addrlist, &(http->fd))) == NULL) + { + /* + * Unable to connect... + */ + +#ifdef WIN32 + http->error = WSAGetLastError(); +#else + http->error = errno; +#endif /* WIN32 */ + http->status = HTTP_ERROR; + + return (-1); + } + + http->hostaddr = &(addr->addr); + http->error = 0; + http->status = HTTP_CONTINUE; + +#ifdef HAVE_SSL + if (http->encryption == HTTP_ENCRYPT_ALWAYS) + { + /* + * Always do encryption via SSL. + */ + + if (http_setup_ssl(http) != 0) + { +#ifdef WIN32 + closesocket(http->fd); +#else + close(http->fd); +#endif /* WIN32 */ + + return (-1); + } + } + else if (http->encryption == HTTP_ENCRYPT_REQUIRED) + return (http_upgrade(http)); +#endif /* HAVE_SSL */ + + return (0); +} + + +/* + * 'httpSetCookie()' - Set the cookie value(s)... + * + * @since CUPS 1.1.19@ + */ + +void +httpSetCookie(http_t *http, /* I - Connection */ + const char *cookie) /* I - Cookie string */ +{ + if (!http) + return; + + if (http->cookie) + free(http->cookie); + + if (cookie) + http->cookie = strdup(cookie); + else + http->cookie = 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; + + strlcpy(http->fields[field], value, HTTP_MAX_VALUE); +} + + +/* + * 'httpSetLength()' - Set the content-length and content-encoding. + * + * @since CUPS 1.2@ + */ + +void +httpSetLength(http_t *http, /* I - HTTP data */ + size_t length) /* I - Length (0 for chunked) */ +{ + if (!http) + return; + + if (!length) + { + strcpy(http->fields[HTTP_FIELD_TRANSFER_ENCODING], "chunked"); + http->fields[HTTP_FIELD_CONTENT_LENGTH][0] = '\0'; + } + else + { + http->fields[HTTP_FIELD_TRANSFER_ENCODING][0] = '\0'; + snprintf(http->fields[HTTP_FIELD_CONTENT_LENGTH], HTTP_MAX_VALUE, + CUPS_LLFMT, CUPS_LLCAST length); + } +} + + +/* + * '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)); +} + + +/* + * 'httpUpdate()' - Update the current HTTP state for incoming data. + */ + +http_status_t /* O - HTTP status */ +httpUpdate(http_t *http) /* I - HTTP data */ +{ + char line[32768], /* Line from connection... */ + *value; /* Pointer to value on line */ + http_field_t field; /* Field index */ + int major, minor, /* HTTP version numbers */ + status; /* Request status */ + + + DEBUG_printf(("httpUpdate(http=%p), state=%d\n", http, http->state)); + + /* + * Flush pending data, if any... + */ + + if (http->wused) + { + DEBUG_puts(" flushing buffer..."); + + if (httpFlushWrite(http) < 0) + return (HTTP_ERROR); + } + + /* + * 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_printf(("httpUpdate: Got \"%s\"\n", 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); + + if (http->status < HTTP_BAD_REQUEST) + http->digest_tries = 0; + +#ifdef HAVE_SSL + if (http->status == HTTP_SWITCHING_PROTOCOLS && !http->tls) + { + if (http_setup_ssl(http) != 0) + { +# ifdef WIN32 + closesocket(http->fd); +# else + close(http->fd); +# endif /* WIN32 */ + + return (HTTP_ERROR); + } + + return (HTTP_CONTINUE); + } +#endif /* HAVE_SSL */ + + httpGetLength2(http); + + switch (http->state) + { + case HTTP_GET : + case HTTP_POST : + case HTTP_POST_RECV : + case HTTP_PUT : + http->state ++; + case HTTP_POST_SEND : + break; + + default : + http->state = HTTP_WAITING; + break; + } + + return (http->status); + } + else if (strncmp(line, "HTTP/", 5) == 0) + { + /* + * Got the beginning of a response... + */ + + if (sscanf(line, "HTTP/%d.%d%d", &major, &minor, &status) != 3) + return (HTTP_ERROR); + + http->version = (http_version_t)(major * 100 + minor); + http->status = (http_status_t)status; + } + else if ((value = strchr(line, ':')) != NULL) + { + /* + * Got a value... + */ + + *value++ = '\0'; + while (isspace(*value & 255)) + value ++; + + /* + * Be tolerants of servers that send unknown attribute fields... + */ + + if (!strcasecmp(line, "expect")) + { + /* + * "Expect: 100-continue" or similar... + */ + + http->expect = (http_status_t)atoi(value); + } + else if (!strcasecmp(line, "cookie")) + { + /* + * "Cookie: name=value[; name=value ...]" - replaces previous cookies... + */ + + httpSetCookie(http, value); + } + else if ((field = http_field(line)) == HTTP_FIELD_UNKNOWN) + { + DEBUG_printf(("httpUpdate: unknown field %s seen!\n", line)); + continue; + } + else + httpSetField(http, field, value); + } + else + { + http->status = HTTP_ERROR; + return (HTTP_ERROR); + } + } + + /* + * See if there was an error... + */ + + if (http->error == EPIPE && http->status > HTTP_CONTINUE) + return (http->status); + + if (http->error) + { + DEBUG_printf(("httpUpdate: socket error %d - %s\n", http->error, + strerror(http->error))); + http->status = HTTP_ERROR; + return (HTTP_ERROR); + } + + /* + * If we haven't already returned, then there is nothing new... + */ + + return (HTTP_CONTINUE); +} + + +/* + * 'httpWait()' - Wait for data available on a connection. + * + * @since CUPS 1.1.19@ + */ + +int /* O - 1 if data is available, 0 otherwise */ +httpWait(http_t *http, /* I - HTTP data */ + int msec) /* I - Milliseconds to wait */ +{ + /* + * First see if there is data in the buffer... + */ + + if (http == NULL) + return (0); + + if (http->used) + return (1); + + /* + * If not, check the SSL/TLS buffers and do a select() on the connection... + */ + + return (http_wait(http, msec)); +} + + +/* + * '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 bytes; /* Bytes written */ + + + DEBUG_printf(("httpWrite(http=%p, buffer=%p, length=%d)\n", http, + buffer, length)); + + /* + * Range check input... + */ + + if (http == NULL || buffer == NULL) + return (-1); + + /* + * Mark activity on the connection... + */ + + http->activity = time(NULL); + + /* + * Buffer small writes for better performance... + */ + + if (length > 0) + { + if (http->wused && (length + http->wused) > sizeof(http->wbuffer)) + { + DEBUG_printf((" flushing buffer (wused=%d, length=%d)\n", + http->wused, length)); + + httpFlushWrite(http); + } + + if ((length + http->wused) <= sizeof(http->wbuffer)) + { + /* + * Write to buffer... + */ + + DEBUG_printf((" copying %d bytes to wbuffer...\n", length)); + + memcpy(http->wbuffer + http->wused, buffer, length); + http->wused += length; + bytes = length; + } + else + { + /* + * Otherwise write the data directly... + */ + + DEBUG_printf((" writing %d bytes to socket...\n", length)); + + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + bytes = http_write_chunk(http, buffer, length); + else + bytes = http_write(http, buffer, length); + + DEBUG_printf((" wrote %d bytes...\n", bytes)); + } + + if (http->data_encoding == HTTP_ENCODE_LENGTH) + http->data_remaining -= bytes; + } + else + bytes = 0; + + /* + * Handle end-of-request processing... + */ + + if ((http->data_encoding == HTTP_ENCODE_CHUNKED && length == 0) || + (http->data_encoding == HTTP_ENCODE_LENGTH && http->data_remaining == 0)) + { + /* + * Finished with the transfer; unless we are sending POST or PUT + * data, go idle... + */ + + DEBUG_puts("httpWrite: changing states..."); + + if (http->wused) + httpFlushWrite(http); + + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + { + /* + * Send a 0-length chunk at the end of the request... + */ + + http_write(http, "0\r\n\r\n", 5); + + /* + * Reset the data state... + */ + + http->data_encoding = HTTP_ENCODE_LENGTH; + http->data_remaining = 0; + } + + if (http->state == HTTP_POST_RECV) + http->state ++; + else if (http->state == HTTP_PUT_RECV) + http->state = HTTP_STATUS; + else + http->state = HTTP_WAITING; + } + + return (bytes); +} + + +#if defined(HAVE_SSL) && defined(HAVE_CDSASSL) +/* + * '_httpWriteCDSA()' - Write function for CDSA encryption code. + */ + +OSStatus /* O - -1 on error, 0 on success */ +_httpWriteCDSA( + SSLConnectionRef connection, /* I - SSL/TLS connection */ + const void *data, /* I - Data buffer */ + size_t *dataLength) /* IO - Number of bytes */ +{ + ssize_t bytes; /* Number of write written */ + + + bytes = write((int)connection, data, *dataLength); + if (bytes >= 0) + { + *dataLength = bytes; + return (0); + } + else + return (-1); +} +#endif /* HAVE_SSL && HAVE_CDSASSL */ + + +/* + * '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); +} + + +#ifdef HAVE_SSL +/* + * 'http_read_ssl()' - Read from a SSL/TLS connection. + */ + +static int /* O - Bytes read */ +http_read_ssl(http_t *http, /* I - HTTP data */ + char *buf, /* I - Buffer to store data */ + int len) /* I - Length of buffer */ +{ +# if defined(HAVE_LIBSSL) + return (SSL_read((SSL *)(http->tls), buf, len)); + +# elif defined(HAVE_GNUTLS) + return (gnutls_record_recv(((http_tls_t *)(http->tls))->session, buf, len)); + +# elif defined(HAVE_CDSASSL) + OSStatus error; /* Error info */ + size_t processed; /* Number of bytes processed */ + + + error = SSLRead((SSLContextRef)http->tls, buf, len, &processed); + + if (error == 0) + return (processed); + else + { + http->error = error; + + return (-1); + } +# endif /* HAVE_LIBSSL */ +} +#endif /* HAVE_SSL */ + + +/* + * '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 * const codes[] = + { /* Request code strings */ + NULL, + "OPTIONS", + "GET", + NULL, + "HEAD", + "POST", + NULL, + NULL, + "PUT", + NULL, + "DELETE", + "TRACE", + "CLOSE" + }; + static const char hex[] = "0123456789ABCDEF"; + /* Hex digits */ + + + DEBUG_printf(("http_send(http=%p, request=HTTP_%s, uri=\"%s\")\n", + http, codes[request], uri)); + + if (http == NULL || uri == NULL) + return (-1); + + /* + * Set the User-Agent field if it isn't already... + */ + + if (!http->fields[HTTP_FIELD_USER_AGENT][0]) + httpSetField(http, HTTP_FIELD_USER_AGENT, CUPS_MINIMAL); + + /* + * 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_SSL + 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_SSL */ + + 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 (http->cookie) + if (httpPrintf(http, "Cookie: $Version=0; %s\r\n", http->cookie) < 1) + { + http->status = HTTP_ERROR; + return (-1); + } + + if (httpPrintf(http, "\r\n") < 1) + { + http->status = HTTP_ERROR; + return (-1); + } + + httpGetLength2(http); + httpClearFields(http); + + return (0); +} + + +#ifdef HAVE_SSL +/* + * 'http_setup_ssl()' - Set up SSL/TLS support on a connection. + */ + +static int /* O - Status of connection */ +http_setup_ssl(http_t *http) /* I - HTTP data */ +{ +# ifdef HAVE_LIBSSL + SSL_CTX *context; /* Context for encryption */ + SSL *conn; /* Connection for encryption */ +# elif defined(HAVE_GNUTLS) + http_tls_t *conn; /* TLS session object */ + gnutls_certificate_client_credentials *credentials; + /* TLS credentials */ +# elif defined(HAVE_CDSASSL) + SSLContextRef conn; /* Context for encryption */ + OSStatus error; /* Error info */ +# endif /* HAVE_LIBSSL */ + + + DEBUG_printf(("http_setup_ssl(http=%p)\n", http)); + +# ifdef HAVE_LIBSSL + context = SSL_CTX_new(SSLv23_client_method()); + + SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */ + + conn = SSL_new(context); + + SSL_set_fd(conn, http->fd); + if (SSL_connect(conn) != 1) + { +# ifdef DEBUG + unsigned long error; /* Error code */ + + while ((error = ERR_get_error()) != 0) + printf("http_setup_ssl: %s\n", ERR_error_string(error, NULL)); +# endif /* DEBUG */ + + SSL_CTX_free(context); + SSL_free(conn); + +# ifdef WIN32 + http->error = WSAGetLastError(); +# else + http->error = errno; +# endif /* WIN32 */ + http->status = HTTP_ERROR; + + return (HTTP_ERROR); + } + +# elif defined(HAVE_GNUTLS) + conn = (http_tls_t *)malloc(sizeof(http_tls_t)); + + if (conn == NULL) + { + http->error = errno; + http->status = HTTP_ERROR; + + return (-1); + } + + credentials = (gnutls_certificate_client_credentials *) + malloc(sizeof(gnutls_certificate_client_credentials)); + if (credentials == NULL) + { + free(conn); + + http->error = errno; + http->status = HTTP_ERROR; + + return (-1); + } + + gnutls_certificate_allocate_credentials(credentials); + + gnutls_init(&(conn->session), GNUTLS_CLIENT); + gnutls_set_default_priority(conn->session); + gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials); + gnutls_transport_set_ptr(conn->session, http->fd); + + if ((gnutls_handshake(conn->session)) != GNUTLS_E_SUCCESS) + { + http->error = errno; + http->status = HTTP_ERROR; + + return (-1); + } + + conn->credentials = credentials; + +# elif defined(HAVE_CDSASSL) + error = SSLNewContext(false, &conn); + + if (!error) + error = SSLSetIOFuncs(conn, _httpReadCDSA, _httpWriteCDSA); + + if (!error) + error = SSLSetConnection(conn, (SSLConnectionRef)http->fd); + + if (!error) + error = SSLSetAllowsExpiredCerts(conn, true); + + if (!error) + error = SSLSetAllowsAnyRoot(conn, true); + + if (!error) + error = SSLHandshake(conn); + + if (error != 0) + { + http->error = error; + http->status = HTTP_ERROR; + + SSLDisposeContext(conn); + + close(http->fd); + + return (-1); + } +# endif /* HAVE_CDSASSL */ + + http->tls = conn; + return (0); +} +#endif /* HAVE_SSL */ + + +#ifdef HAVE_SSL +/* + * 'http_shutdown_ssl()' - Shut down SSL/TLS on a connection. + */ + +static void +http_shutdown_ssl(http_t *http) /* I - HTTP data */ +{ +# ifdef HAVE_LIBSSL + SSL_CTX *context; /* Context for encryption */ + SSL *conn; /* Connection for encryption */ + + + conn = (SSL *)(http->tls); + context = SSL_get_SSL_CTX(conn); + + SSL_shutdown(conn); + SSL_CTX_free(context); + SSL_free(conn); + +# elif defined(HAVE_GNUTLS) + http_tls_t *conn; /* Encryption session */ + gnutls_certificate_client_credentials *credentials; + /* TLS credentials */ + + + conn = (http_tls_t *)(http->tls); + credentials = (gnutls_certificate_client_credentials *)(conn->credentials); + + gnutls_bye(conn->session, GNUTLS_SHUT_RDWR); + gnutls_deinit(conn->session); + gnutls_certificate_free_credentials(*credentials); + free(credentials); + free(conn); + +# elif defined(HAVE_CDSASSL) + SSLClose((SSLContextRef)http->tls); + SSLDisposeContext((SSLContextRef)http->tls); +# endif /* HAVE_LIBSSL */ + + http->tls = NULL; +} +#endif /* HAVE_SSL */ + + +#ifdef HAVE_SSL +/* + * '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_SSL */ + + +/* + * 'http_wait()' - Wait for data available on a connection. + */ + +static int /* O - 1 if data is available, 0 otherwise */ +http_wait(http_t *http, /* I - HTTP data */ + int msec) /* I - Milliseconds to wait */ +{ +#ifndef WIN32 + struct rlimit limit; /* Runtime limit */ + int set_size; /* Size of select set */ +#endif /* !WIN32 */ + struct timeval timeout; /* Timeout */ + int nfds; /* Result from select() */ + + + DEBUG_printf(("http_wait(http=%p, msec=%d)\n", http, msec)); + + /* + * Check the SSL/TLS buffers for data first... + */ + +#ifdef HAVE_SSL + if (http->tls) + { +# ifdef HAVE_LIBSSL + if (SSL_pending((SSL *)(http->tls))) + return (1); +# elif defined(HAVE_GNUTLS) + if (gnutls_record_check_pending(((http_tls_t *)(http->tls))->session)) + return (1); +# elif defined(HAVE_CDSASSL) + size_t bytes; /* Bytes that are available */ + + if (!SSLGetBufferedReadSize((SSLContextRef)http->tls, &bytes) && bytes > 0) + return (1); +# endif /* HAVE_LIBSSL */ + } +#endif /* HAVE_SSL */ + + /* + * Then try doing a select() to poll the socket... + */ + + if (!http->input_set) + { +#ifdef WIN32 + /* + * Windows has a fixed-size select() structure, different (surprise, + * surprise!) from all UNIX implementations. Just allocate this + * fixed structure... + */ + + http->input_set = calloc(1, sizeof(fd_set)); +#else + /* + * Allocate the select() input set based upon the max number of file + * descriptors available for this process... + */ + + getrlimit(RLIMIT_NOFILE, &limit); + + set_size = (limit.rlim_cur + 31) / 8 + 4; + if (set_size < sizeof(fd_set)) + set_size = sizeof(fd_set); + + http->input_set = calloc(1, set_size); +#endif /* WIN32 */ + + if (!http->input_set) + return (0); + } + + do + { + FD_SET(http->fd, http->input_set); + + if (msec >= 0) + { + timeout.tv_sec = msec / 1000; + timeout.tv_usec = (msec % 1000) * 1000; + + nfds = select(http->fd + 1, http->input_set, NULL, NULL, &timeout); + } + else + nfds = select(http->fd + 1, http->input_set, NULL, NULL, NULL); + } +#ifdef WIN32 + while (nfds < 0 && WSAGetLastError() == WSAEINTR); +#else + while (nfds < 0 && errno == EINTR); +#endif /* WIN32 */ + + FD_CLR(http->fd, http->input_set); + + return (nfds > 0); +} + + +/* + * 'http_write()' - Write a buffer to a HTTP connection. + */ + +static int /* O - Number of bytes written */ +http_write(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 */ + + + tbytes = 0; + + while (length > 0) + { +#ifdef HAVE_SSL + if (http->tls) + bytes = http_write_ssl(http, buffer, length); + else +#endif /* HAVE_SSL */ + bytes = send(http->fd, buffer, length, 0); + + if (bytes < 0) + { +#ifdef WIN32 + if (WSAGetLastError() != http->error) + { + http->error = WSAGetLastError(); + continue; + } +#else + if (errno == EINTR) + continue; + else if (errno != http->error && errno != ECONNRESET) + { + http->error = errno; + continue; + } +#endif /* WIN32 */ + + DEBUG_puts("http_write: error writing data...\n"); + + return (-1); + } + + buffer += bytes; + tbytes += bytes; + length -= bytes; + } + +#ifdef DEBUG + { + int i, j, ch; + printf("http_write: wrote %d bytes: \n", tbytes); + for (i = 0, buffer -= tbytes; i < tbytes; i += 16) + { + printf(" "); + + for (j = 0; j < 16 && (i + j) < tbytes; j ++) + printf(" %02X", buffer[i + j] & 255); + + while (j < 16) + { + printf(" "); + j ++; + } + + printf(" "); + for (j = 0; j < 16 && (i + j) < tbytes; j ++) + { + ch = buffer[i + j] & 255; + + if (ch < ' ' || ch == 127) + ch = '.'; + + putchar(ch); + } + putchar('\n'); + } + } +#endif /* DEBUG */ + + return (tbytes); +} + + +/* + * 'http_write_chunk()' - Write a chunked buffer. + */ + +static int /* O - Number bytes written */ +http_write_chunk(http_t *http, /* I - HTTP data */ + const char *buffer, /* I - Buffer to write */ + int length) /* I - Length of buffer */ +{ + char header[255]; /* Chunk header */ + int bytes; /* Bytes written */ + + DEBUG_printf(("http_write_chunk(http=%p, buffer=%p, length=%d)\n", + http, buffer, length)); + + /* + * Write the chunk header, data, and trailer. + */ + + sprintf(header, "%x\r\n", length); + if (http_write(http, header, strlen(header)) < 0) + { + DEBUG_puts(" http_write of length failed!"); + return (-1); + } + + if ((bytes = http_write(http, buffer, length)) < 0) + { + DEBUG_puts(" http_write of buffer failed!"); + return (-1); + } + + if (http_write(http, "\r\n", 2) < 0) + { + DEBUG_puts(" http_write of CR LF failed!"); + return (-1); + } + + return (bytes); +} + + +#ifdef HAVE_SSL +/* + * 'http_write_ssl()' - Write to a SSL/TLS connection. + */ + +static int /* O - Bytes written */ +http_write_ssl(http_t *http, /* I - HTTP data */ + const char *buf, /* I - Buffer holding data */ + int len) /* I - Length of buffer */ +{ +# if defined(HAVE_LIBSSL) + return (SSL_write((SSL *)(http->tls), buf, len)); + +# elif defined(HAVE_GNUTLS) + return (gnutls_record_send(((http_tls_t *)(http->tls))->session, buf, len)); +# elif defined(HAVE_CDSASSL) + OSStatus error; /* Error info */ + size_t processed; /* Number of bytes processed */ + + + error = SSLWrite((SSLContextRef)http->tls, buf, len, &processed); + + if (error == 0) + return (processed); + else + { + http->error = error; + return (-1); + } +# endif /* HAVE_LIBSSL */ +} +#endif /* HAVE_SSL */ + + +/* + * End of "$Id: http.c 4914 2006-01-11 02:04:22Z mike $". + */ diff --git a/cups/http.h b/cups/http.h new file mode 100644 index 000000000..2a2e645ae --- /dev/null +++ b/cups/http.h @@ -0,0 +1,473 @@ +/* + * "$Id: http.h 4906 2006-01-10 20:53:28Z mike $" + * + * Hyper-Text Transport Protocol definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_HTTP_H_ +# define _CUPS_HTTP_H_ + +/* + * Include necessary headers... + */ + +# include +# include +# include +# ifdef WIN32 +# include +# include +# else +# include +# include +# include +# include +# include +# include +# include +# include +# if !defined(__APPLE__) || !defined(TCP_NODELAY) +# include +# endif /* !__APPLE__ || !TCP_NODELAY */ +# ifdef AF_LOCAL +# include +# endif /* AF_LOCAL */ +# endif /* WIN32 */ + +# include "md5.h" + +/* + * With GCC 3.0 and higher, we can mark old APIs "deprecated" so you get + * an error at compile-time. + */ + +# if defined(__GNUC__) && __GNUC__ > 2 +# define _HTTP_DEPRECATED __attribute__ ((__deprecated__)) +# else +# define _HTTP_DEPRECATED +# endif /* __GNUC__ && __GNUC__ > 2 */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Oh, the wonderful world of IPv6 compatibility. Apparently some + * implementations expose the (more logical) 32-bit address parts + * to everyone, while others only expose it to kernel code... To + * make supporting IPv6 even easier, each vendor chose different + * core structure and union names, so the same defines or code + * can't be used on all platforms. + * + * The following will likely need tweaking on new platforms that + * support IPv6 - the "s6_addr32" define maps to the 32-bit integer + * array in the in6_addr union, which is named differently on various + * platforms. + */ + +#if defined(AF_INET6) && !defined(s6_addr32) +# if defined(__sun) +# define s6_addr32 _S6_un._S6_u32 +# elif defined(__FreeBSD__) || defined(__APPLE__) +# define s6_addr32 __u6_addr.__u6_addr32 +# elif defined(WIN32) +/* + * Windows only defines byte and 16-bit word members of the union and + * requires special casing of all raw address code... + */ +# define s6_addr32 error_need_win32_specific_code +# endif /* __sun */ +#endif /* AF_INET6 && !s6_addr32 */ + + +/* + * 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 1024 /* Max length of data buffer */ +# define HTTP_MAX_VALUE 256 /* Max header field value length */ + + +/* + * Types and structures... + */ + +typedef enum http_auth_e /**** HTTP authentication types ****/ +{ + 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; + +typedef enum http_encoding_e /**** HTTP transfer encoding values ****/ +{ + HTTP_ENCODE_LENGTH, /* Data is sent with Content-Length */ + HTTP_ENCODE_CHUNKED /* Data is chunked */ +} http_encoding_t; + +typedef enum http_encryption_e /**** HTTP encryption values ****/ +{ + 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; + +typedef enum http_field_e /**** HTTP field names ****/ +{ + HTTP_FIELD_UNKNOWN = -1, /* Unknown field */ + HTTP_FIELD_ACCEPT_LANGUAGE, /* Accept-Language field */ + HTTP_FIELD_ACCEPT_RANGES, /* Accept-Ranges field */ + HTTP_FIELD_AUTHORIZATION, /* Authorization field */ + HTTP_FIELD_CONNECTION, /* Connection field */ + HTTP_FIELD_CONTENT_ENCODING, /* Content-Encoding field */ + HTTP_FIELD_CONTENT_LANGUAGE, /* Content-Language field */ + HTTP_FIELD_CONTENT_LENGTH, /* Content-Length field */ + HTTP_FIELD_CONTENT_LOCATION, /* Content-Location field */ + HTTP_FIELD_CONTENT_MD5, /* Content-MD5 field */ + HTTP_FIELD_CONTENT_RANGE, /* Content-Range field */ + HTTP_FIELD_CONTENT_TYPE, /* Content-Type field */ + HTTP_FIELD_CONTENT_VERSION, /* Content-Version field */ + HTTP_FIELD_DATE, /* Date field */ + HTTP_FIELD_HOST, /* Host field */ + HTTP_FIELD_IF_MODIFIED_SINCE, /* If-Modified-Since field */ + HTTP_FIELD_IF_UNMODIFIED_SINCE, /* If-Unmodified-Since field */ + HTTP_FIELD_KEEP_ALIVE, /* Keep-Alive field */ + HTTP_FIELD_LAST_MODIFIED, /* Last-Modified field */ + HTTP_FIELD_LINK, /* Link field */ + HTTP_FIELD_LOCATION, /* Location field */ + HTTP_FIELD_RANGE, /* Range field */ + HTTP_FIELD_REFERER, /* Referer field */ + HTTP_FIELD_RETRY_AFTER, /* Retry-After field */ + HTTP_FIELD_TRANSFER_ENCODING, /* Transfer-Encoding field */ + HTTP_FIELD_UPGRADE, /* Upgrade field */ + HTTP_FIELD_USER_AGENT, /* User-Agent field */ + HTTP_FIELD_WWW_AUTHENTICATE, /* WWW-Authenticate field */ + HTTP_FIELD_MAX /* Maximum field index */ +} http_field_t; + +typedef enum http_keepalive_e /**** HTTP keep-alive values ****/ +{ + HTTP_KEEPALIVE_OFF = 0, /* No keep alive support */ + HTTP_KEEPALIVE_ON /* Use keep alive */ +} http_keepalive_t; + +typedef enum http_state_e /**** HTTP state values; 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; + +typedef enum http_status_e /**** HTTP status codes ****/ +{ + 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; + +typedef enum http_uri_status_e /**** URI separation status @since CUPS1.2@ ****/ +{ + HTTP_URI_OVERFLOW = -8, /* URI buffer for httpAssembleURI is too small */ + HTTP_URI_BAD_ARGUMENTS = -7, /* Bad arguments to function (error) */ + HTTP_URI_BAD_RESOURCE = -6, /* Bad resource in URI (error) */ + HTTP_URI_BAD_PORT = -5, /* Bad port number in URI (error) */ + HTTP_URI_BAD_HOSTNAME = -4, /* Bad hostname in URI (error) */ + HTTP_URI_BAD_USERNAME = -3, /* Bad username in URI (error) */ + HTTP_URI_BAD_SCHEME = -2, /* Bad scheme in URI (error) */ + HTTP_URI_BAD_URI = -1, /* Bad/empty URI (error) */ + HTTP_URI_OK = 0, /* URI decoded OK */ + HTTP_URI_MISSING_SCHEME, /* Missing scheme in URI (warning) */ + HTTP_URI_UNKNOWN_SCHEME, /* Unknown scheme in URI (warning) */ + HTTP_URI_MISSING_RESOURCE /* Missing resource in URI (warning) */ +} http_uri_status_t; + +typedef enum http_version_e /**** HTTP version numbers ****/ +{ + HTTP_0_9 = 9, /* HTTP/0.9 */ + HTTP_1_0 = 100, /* HTTP/1.0 */ + HTTP_1_1 = 101 /* HTTP/1.1 */ +} http_version_t; + +typedef union http_addr_u /**** Socket address union, which + **** makes using IPv6 and other + **** address types easier and + **** more portable. @since CUPS 1.2@ + ****/ +{ + struct sockaddr addr; /* Base structure for family value */ + struct sockaddr_in ipv4; /* IPv4 address */ +#ifdef AF_INET6 + struct sockaddr_in6 ipv6; /* IPv6 address */ +#endif /* AF_INET6 */ +#ifdef AF_LOCAL + struct sockaddr_un un; /* Domain socket file */ +#endif /* AF_LOCAL */ + char pad[256]; /* Padding to ensure binary compatibility */ +} http_addr_t; + +typedef struct http_addrlist_s /**** Socket address list, which is + **** used to enumerate all of the + **** addresses that are associated + **** with a hostname. @since CUPS 1.2@ + ****/ +{ + struct http_addrlist_s *next; /* Pointer to next address in list */ + http_addr_t addr; /* Address */ +} http_addrlist_t; + +typedef struct http_s /**** HTTP connection structure. ****/ +{ + 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 @deprecated@ */ + 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 @deprecated@ */ + int used; /* Number of bytes used in buffer */ + char buffer[HTTP_MAX_BUFFER]; + /* Buffer for incoming data */ + char wbuffer[HTTP_MAX_BUFFER]; + /* Buffer for outgoing data */ + int auth_type; /* Authentication in use */ + _cups_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 */ + /**** New in CUPS 1.1.19 ****/ + fd_set *input_set; /* select() set for httpWait() @since CUPS 1.1.19@ */ + http_status_t expect; /* Expect: header @since CUPS 1.1.19@ */ + char *cookie; /* Cookie value(s) @since CUPS 1.1.19@ */ + /**** New in CUPS 1.1.20 ****/ + char authstring[HTTP_MAX_VALUE], + /* Current Authentication value @since CUPS 1.1.20@ */ + userpass[HTTP_MAX_VALUE]; + /* Username:password string @since CUPS 1.1.20@ */ + int digest_tries; /* Number of tries for digest auth @since CUPS 1.1.20@ */ + /**** New in CUPS 1.2 ****/ + http_addr_t *hostaddr; /* Current host address and port @since CUPS 1.2@ */ + http_addrlist_t *addrlist; /* List of valid addresses @since CUPS 1.2@ */ + int wused; /* Write buffer bytes used @since CUPS 1.2@ */ + off_t data_remaining; /* Number of bytes left @since CUPS 1.2@ */ +} 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 encryption); +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, ...) +# ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 2, 3))) +# endif /* __GNUC__ */ +; +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) _HTTP_DEPRECATED; +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) _HTTP_DEPRECATED; +extern char *httpDecode64(char *out, const char *in) _HTTP_DEPRECATED; +extern int httpGetLength(http_t *http) _HTTP_DEPRECATED; +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 unsigned char *, char [33]); + +/**** New in CUPS 1.1.19 ****/ +extern void httpClearCookie(http_t *http); +#define httpGetCookie(http) ((http)->cookie) +extern void httpSetCookie(http_t *http, const char *cookie); +extern int httpWait(http_t *http, int msec); + +/**** New in CUPS 1.1.21 ****/ +extern char *httpDecode64_2(char *out, int *outlen, const char *in); +extern char *httpEncode64_2(char *out, int outlen, const char *in, + int inlen); +extern void httpSeparate2(const char *uri, + char *method, int methodlen, + char *username, int usernamelen, + char *host, int hostlen, int *port, + char *resource, int resourcelen) _HTTP_DEPRECATED; + +/**** New in CUPS 1.2 ****/ +extern int httpAddrAny(const http_addr_t *addr); +extern http_addrlist_t *httpAddrConnect(http_addrlist_t *addrlist, int *sock); +extern int httpAddrEqual(const http_addr_t *addr1, + const http_addr_t *addr2); +extern void httpAddrFreeList(http_addrlist_t *addrlist); +extern http_addrlist_t *httpAddrGetList(const char *hostname, int family, + const char *service); +extern int httpAddrLength(const http_addr_t *addr); +extern int httpAddrLocalhost(const http_addr_t *addr); +extern char *httpAddrLookup(const http_addr_t *addr, + char *name, int namelen); +extern char *httpAddrString(const http_addr_t *addr, + char *s, int slen); +extern http_uri_status_t httpAssembleURI(char *uri, int urilen, + const char *scheme, + const char *username, + const char *host, int port, + const char *resource); +extern http_uri_status_t httpAssembleURIf(char *uri, int urilen, + const char *scheme, + const char *username, + const char *host, int port, + const char *resourcef, ...); +extern int httpFlushWrite(http_t *http); +extern const char *httpGetDateString2(time_t t, char *s, int slen); +extern const char *httpGetHostname(char *s, int slen); +extern off_t httpGetLength2(http_t *http); +extern char *httpGetSubField2(http_t *http, http_field_t field, + const char *name, char *value, + int valuelen); +extern http_uri_status_t httpSeparateURI(const char *uri, + char *scheme, int schemelen, + char *username, int usernamelen, + char *host, int hostlen, int *port, + char *resource, int resourcelen); +extern void httpSetLength(http_t *http, size_t length); + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_HTTP_H_ */ + +/* + * End of "$Id: http.h 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/cups/i18n.h b/cups/i18n.h new file mode 100644 index 000000000..00a597f95 --- /dev/null +++ b/cups/i18n.h @@ -0,0 +1,90 @@ +/* + * "$Id: i18n.h 4903 2006-01-10 20:02:46Z mike $" + * + * (Private) localization support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_I18N_H_ +# define _CUPS_I18N_H_ + +/* + * Include necessary headers... + */ + +# include "language.h" + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Macro for localized text... + */ + +# define _(x) x + + +/* + * Types... + */ + +typedef struct _cups_message_s /**** Message catalog entry ****/ +{ + char *id, /* Original string */ + *str; /* Localized string */ +} _cups_message_t; + + +/* + * Prototypes... + */ + +/**** New in CUPS 1.1.20 ****/ +extern void _cupsRestoreLocale(int category, char *oldlocale); +extern char *_cupsSaveLocale(int category, const char *locale); + +/**** New in CUPS 1.2 ****/ +extern const char *_cupsEncodingName(cups_encoding_t encoding); +extern int _cupsLangPrintf(FILE *fp, cups_lang_t *lang, + const char *message, ...) +# ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 3, 4))) +# endif /* __GNUC__ */ +; +extern int _cupsLangPuts(FILE *fp, cups_lang_t *lang, + const char *message); +extern const char *_cupsLangString(cups_lang_t *lang, const char *message); +extern void _cupsMessageFree(cups_array_t *a); +extern cups_array_t *_cupsMessageLoad(const char *filename); +extern const char *_cupsMessageLookup(cups_array_t *a, const char *m); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_I18N_H_ */ + +/* + * End of "$Id: i18n.h 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/cups/ipp-support.c b/cups/ipp-support.c new file mode 100644 index 000000000..cceda0ff1 --- /dev/null +++ b/cups/ipp-support.c @@ -0,0 +1,332 @@ +/* + * "$Id: ipp-support.c 4785 2005-10-13 19:39:05Z mike $" + * + * Internet Printing Protocol support functions for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * ippErrorString() - Return a name for the given status code. + * ippErrorValue() - Return a status code for the given name. + * ippOpString() - Return a name for the given operation id. + * ippOpValue() - Return an operation id for the given name. + * ippPort() - Return the default IPP port number. + * ippSetPort() - Set the default port number. + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include "debug.h" +#include + + +/* + * Local globals... + */ + +static const char * const ipp_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" + }, + * const ipp_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" + }, + * const ipp_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" + }; +static char * const ipp_std_ops[] = + { + /* 0x0000 - 0x000f */ + "", "", "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", "", + + /* 0x0010 - 0x001f */ + "Pause-Printer", "Resume-Printer", + "Purge-Jobs", "Set-Printer-Attributes", + "Set-Job-Attributes", + "Get-Printer-Supported-Values", + "Create-Printer-Subscription", + "Create-Job-Subscription", + "Get-Subscription-Attributes", + "Get-Subscriptions", "Renew-Subscription", + "Cancel-Subscription", "Get-Notifications", + "Send-Notifications", "", "", + + /* 0x0020 - 0x002f */ + "", + "Get-Printer-Support-Files", + "Enable-Printer", + "Disable-Printer", + "Pause-Printer-After-Current-Job", + "Hold-New-Jobs", + "Release-Held-New-Jobs", + "Deactivate-Printer", + "Activate-Printer", + "Restart-Printer", + "Shutdown-Printer", + "Startup-Printer", + "Reprocess-Job", + "Cancel-Current-Job", + "Suspend-Current-Job", + "Resume-Job", + + /* 0x0030 - 0x0031 */ + "Promote-Job", + "Schedule-Job-After" + }, + * const ipp_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", + "CUPS-Authenticate-Job" + }; + + +/* + * 'ippErrorString()' - Return a name for the given status code. + */ + +const char * /* O - Text string */ +ippErrorString(ipp_status_t error) /* I - Error status */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * See if the error code is a known value... + */ + + if (error >= IPP_OK && error <= IPP_OK_BUT_CANCEL_SUBSCRIPTION) + return (ipp_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 (ipp_status_400s[error - IPP_BAD_REQUEST]); + else if (error >= IPP_INTERNAL_ERROR && error <= IPP_PRINTER_IS_DEACTIVATED) + return (ipp_status_500s[error - IPP_INTERNAL_ERROR]); + + /* + * No, build an "unknown-xxxx" error string... + */ + + sprintf(cg->ipp_unknown, "unknown-%04x", error); + + return (cg->ipp_unknown); +} + + +/* + * 'ippErrorValue()' - Return a status code for the given name. + * + * @since CUPS 1.2@ + */ + +ipp_status_t /* O - IPP status code */ +ippErrorValue(const char *name) /* I - Name */ +{ + int i; + + + for (i = 0; i < (sizeof(ipp_status_oks) / sizeof(ipp_status_oks[0])); i ++) + if (!strcasecmp(name, ipp_status_oks[i])) + return ((ipp_status_t)i); + + if (!strcasecmp(name, "redirection-other-site")) + return (IPP_REDIRECTION_OTHER_SITE); + + for (i = 0; i < (sizeof(ipp_status_400s) / sizeof(ipp_status_400s[0])); i ++) + if (!strcasecmp(name, ipp_status_400s[i])) + return ((ipp_status_t)(i + 0x400)); + + for (i = 0; i < (sizeof(ipp_status_500s) / sizeof(ipp_status_500s[0])); i ++) + if (!strcasecmp(name, ipp_status_500s[i])) + return ((ipp_status_t)(i + 0x500)); + + return ((ipp_status_t)-1); +} + + +/* + * 'ippOpString()' - Return a name for the given operation id. + * + * @since CUPS 1.2@ + */ + +const char * /* O - Name */ +ippOpString(ipp_op_t op) /* I - Operation ID */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * See if the operation ID is a known value... + */ + + if (op >= IPP_PRINT_JOB && op <= IPP_SCHEDULE_JOB_AFTER) + return (ipp_std_ops[op]); + else if (op == IPP_PRIVATE) + return ("windows-ext"); + else if (op >= CUPS_GET_DEFAULT && op <= CUPS_AUTHENTICATE_JOB) + return (ipp_cups_ops[op - CUPS_GET_DEFAULT]); + + /* + * No, build an "unknown-xxxx" operation string... + */ + + sprintf(cg->ipp_unknown, "unknown-%04x", op); + + return (cg->ipp_unknown); +} + + +/* + * 'ippOpValue()' - Return an operation id for the given name. + * + * @since CUPS 1.2@ + */ + +ipp_op_t /* O - Operation ID */ +ippOpValue(const char *name) /* I - Textual name */ +{ + int i; + + + for (i = 0; i < (sizeof(ipp_std_ops) / sizeof(ipp_std_ops[0])); i ++) + if (!strcasecmp(name, ipp_std_ops[i])) + return ((ipp_op_t)i); + + if (!strcasecmp(name, "windows-ext")) + return (IPP_PRIVATE); + + for (i = 0; i < (sizeof(ipp_cups_ops) / sizeof(ipp_cups_ops[0])); i ++) + if (!strcasecmp(name, ipp_cups_ops[i])) + return ((ipp_op_t)(i + 0x4001)); + + return ((ipp_op_t)-1); +} + + +/* + * 'ippPort()' - Return the default IPP port number. + */ + +int /* O - Port number */ +ippPort(void) +{ + const char *ipp_port; /* IPP_PORT environment variable */ + struct servent *port; /* Port number info */ + int portnum; /* Port number */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + if (!cg->ipp_port) + { + if ((ipp_port = getenv("IPP_PORT")) != NULL) + portnum = atoi(ipp_port); + else if ((port = getservbyname("ipp", NULL)) == NULL) + portnum = CUPS_DEFAULT_IPP_PORT; + else + portnum = ntohs(port->s_port); + + if (portnum > 0) + cg->ipp_port = portnum; + } + + return (cg->ipp_port); +} + + +/* + * 'ippSetPort()' - Set the default port number. + */ + +void +ippSetPort(int p) /* I - Port number to use */ +{ + fprintf(stderr, "ippSetPort(p=%d)\n", p); + + _cupsGlobals()->ipp_port = p; +} + + +/* + * End of "$Id: ipp-support.c 4785 2005-10-13 19:39:05Z mike $". + */ diff --git a/cups/ipp.c b/cups/ipp.c new file mode 100644 index 000000000..bc9045b22 --- /dev/null +++ b/cups/ipp.c @@ -0,0 +1,2763 @@ +/* + * "$Id: ipp.c 4922 2006-01-12 22:05:06Z mike $" + * + * Internet Printing Protocol support functions for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * ippAddBoolean() - Add a boolean attribute to an IPP message. + * ippAddBooleans() - Add an array of boolean values. + * ippAddDate() - Add a date attribute to an IPP message. + * ippAddInteger() - Add a integer attribute to an IPP message. + * ippAddIntegers() - Add an array of integer values. + * ippAddOctetString() - Add an octetString value to an IPP message. + * ippAddString() - Add a language-encoded string to an IPP message. + * ippAddStrings() - Add language-encoded strings to an IPP message. + * ippAddRange() - Add a range of values to an IPP message. + * ippAddRanges() - Add ranges of values to an IPP message. + * ippAddResolution() - Add a resolution value to an IPP message. + * ippAddResolutions() - Add resolution values to an IPP message. + * ippAddSeparator() - Add a group separator to an IPP message. + * ippDateToTime() - Convert from RFC 1903 Date/Time format to + * UNIX time in seconds. + * ippDelete() - Delete an IPP message. + * ippDeleteAttribute() - Delete a single attribute in an IPP 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 message. + * ippNew() - Allocate a new IPP message. + * ippNewRequest() - Allocate a new IPP message. + * ippRead() - Read data for an IPP message from a HTTP + * connection. + * ippReadFile() - Read data for an IPP message from a file. + * ippReadIO() - Read data for an IPP message. + * ippTimeToDate() - Convert from UNIX time to RFC 1903 format. + * ippWrite() - Write data for an IPP message to a HTTP + * connection. + * ippWriteFile() - Write data for an IPP message to a file. + * ippWriteIO() - Write data for an IPP message. + * _ipp_add_attr() - Add a new attribute to the request. + * _ipp_free_attr() - Free an attribute. + * ipp_length() - Compute the length of an IPP message or + * collection value. + * ipp_read_http() - Semi-blocking read on a HTTP connection... + * ipp_read_file() - Read IPP data from a file. + * ipp_write_file() - Write IPP data to a file. + */ + +/* + * Include necessary headers... + */ + +#include "http-private.h" +#include "globals.h" +#include "debug.h" +#include +#include +#ifdef WIN32 +# include +#endif /* WIN32 */ + + +/* + * Local functions... + */ + +static size_t ipp_length(ipp_t *ipp, int collection); +static int ipp_read_http(http_t *http, ipp_uchar_t *buffer, int length); +static int ipp_read_file(int *fd, ipp_uchar_t *buffer, int length); +static int ipp_write_file(int *fd, ipp_uchar_t *buffer, int length); + + +/* + * 'ippAddBoolean()' - Add a boolean attribute to an IPP message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddBoolean(ipp_t *ipp, /* I - IPP message */ + 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 message */ + 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 || num_values < 1) + 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); +} + + +/* + * 'ippAddCollection()' - Add a collection value. + * + * @since CUPS 1.1.19@ + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddCollection(ipp_t *ipp, /* I - IPP message */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + ipp_t *value) /* I - Value */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + DEBUG_printf(("ippAddCollection(%p, %02x, \'%s\', %p)\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_BEGIN_COLLECTION; + attr->values[0].collection = value; + + return (attr); +} + + +/* + * 'ippAddCollections()' - Add an array of collection values. + * + * @since CUPS 1.1.19@ + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddCollections( + ipp_t *ipp, /* I - IPP message */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + int num_values, /* I - Number of values */ + const ipp_t **values) /* I - Values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + ipp_value_t *value; /* Current value */ + + + DEBUG_printf(("ippAddCollections(%p, %02x, \'%s\', %d, %p)\n", ipp, + group, name, num_values, values)); + + if (ipp == NULL || name == NULL || num_values < 1) + 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_BEGIN_COLLECTION; + + if (values != NULL) + for (i = 0, value = attr->values; + i < num_values; + i ++, value ++) + value->collection = (ipp_t *)values[i]; + + return (attr); +} + + +/* + * 'ippAddDate()' - Add a date attribute to an IPP message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddDate(ipp_t *ipp, /* I - IPP message */ + 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 message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddInteger(ipp_t *ipp, /* I - IPP message */ + 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 message */ + 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 || num_values < 1) + 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); +} + + +/* + * 'ippAddOctetString()' - Add an octetString value to an IPP message. + * + * @since CUPS 1.2@ + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddOctetString(ipp_t *ipp, /* I - IPP message */ + ipp_tag_t group, /* I - IPP group */ + const char *name, /* I - Name of attribute */ + const void *data, /* I - octetString data */ + int datalen) /* I - Length of data in bytes */ +{ + ipp_attribute_t *attr; /* New attribute */ + + + if (ipp == NULL || name == NULL) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, 1)) == NULL) + return (NULL); + + /* + * Initialize the attribute data... + */ + + attr->name = strdup(name); + attr->group_tag = group; + attr->value_tag = IPP_TAG_STRING; + attr->values[0].unknown.length = datalen; + + if (data) + { + attr->values[0].unknown.data = malloc(datalen); + memcpy(attr->values[0].unknown.data, data, datalen); + } + + /* + * Return the new attribute... + */ + + return (attr); +} + + +/* + * 'ippAddString()' - Add a language-encoded string to an IPP message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddString(ipp_t *ipp, /* I - IPP message */ + 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); + + /* + * Force value to be English for the POSIX locale... + */ + + if (type == IPP_TAG_LANGUAGE && strcasecmp(value, "C") == 0) + value = "en"; + + /* + * Initialize the attribute data... + */ + + 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; + + /* + * Convert language values to lowercase and change _ to - as needed... + */ + + if ((type == IPP_TAG_LANGUAGE || type == IPP_TAG_CHARSET) && + attr->values[0].string.text) + { + char *p; + + + for (p = attr->values[0].string.text; *p; p ++) + if (*p == '_') + *p = '-'; + else + *p = tolower(*p & 255); + } + + return (attr); +} + + +/* + * 'ippAddStrings()' - Add language-encoded strings to an IPP message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddStrings( + ipp_t *ipp, /* I - IPP message */ + 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 * const *values) /* I - Values */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* New attribute */ + ipp_value_t *value; /* Current value */ + + + if (ipp == NULL || name == NULL || num_values < 1) + return (NULL); + + if ((attr = _ipp_add_attr(ipp, num_values)) == NULL) + return (NULL); + + /* + * Initialize the attribute data... + */ + + 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) + { + /* + * Force language to be English for the POSIX locale... + */ + + if (type == IPP_TAG_LANGUAGE && strcasecmp(values[i], "C") == 0) + value->string.text = ((int)type & IPP_TAG_COPY) ? "en" : + strdup("en"); + else + 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 message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddRange(ipp_t *ipp, /* I - IPP message */ + 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 message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddRanges(ipp_t *ipp, /* I - IPP message */ + 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 || num_values < 1) + 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 message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddResolution(ipp_t *ipp, /* I - IPP message */ + 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 message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddResolutions(ipp_t *ipp, /* I - IPP message */ + 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 || num_values < 1) + 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 message. + */ + +ipp_attribute_t * /* O - New attribute */ +ippAddSeparator(ipp_t *ipp) /* I - IPP message */ +{ + 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 message. + */ + +void +ippDelete(ipp_t *ipp) /* I - IPP message */ +{ + 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); +} + + +/* + * 'ippDeleteAttribute()' - Delete a single attribute in an IPP message. + * + * @since CUPS 1.1.19@ + */ + +void +ippDeleteAttribute( + ipp_t *ipp, /* I - IPP message */ + ipp_attribute_t *attr) /* I - Attribute to delete */ +{ + ipp_attribute_t *current, /* Current attribute */ + *prev; /* Previous attribute */ + + + /* + * Find the attribute in the list... + */ + + for (current = ipp->attrs, prev = NULL; + current != NULL && current != attr; + prev = current, current = current->next); + + if (current) + { + /* + * Found it, remove the attribute from the list... + */ + + if (prev) + prev->next = current->next; + else + ipp->attrs = current->next; + + if (current == ipp->last) + ipp->last = prev; + + /* + * Free memory used by the attribute... + */ + + _ipp_free_attr(current); + } +} + + +/* + * 'ippFindAttribute()' - Find a named attribute in a request... + */ + +ipp_attribute_t * /* O - Matching attribute */ +ippFindAttribute(ipp_t *ipp, /* I - IPP message */ + 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 message */ + 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) + { + ipp->prev = ipp->current; + attr = ipp->current->next; + } + else + { + ipp->prev = NULL; + attr = ipp->attrs; + } + + for (; attr != NULL; ipp->prev = attr, 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; + ipp->prev = NULL; + + return (NULL); +} + + +/* + * 'ippLength()' - Compute the length of an IPP message. + */ + +size_t /* O - Size of IPP message */ +ippLength(ipp_t *ipp) /* I - IPP message */ +{ + return (ipp_length(ipp, 0)); +} + + +/* + * 'ippNew()' - Allocate a new IPP message. + */ + +ipp_t * /* O - New IPP message */ +ippNew(void) +{ + ipp_t *temp; /* New IPP message */ + + + DEBUG_puts("ippNew()"); + + 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); +} + + +/* + * 'ippNewRequest()' - Allocate a new IPP request message. + * + * The new request message is initialized with the attributes-charset and + * attributes-natural-language attributes added. The + * attributes-natural-language value is derived from the current locale. + * + * @since CUPS 1.2@ + */ + +ipp_t * /* O - IPP request message */ +ippNewRequest(ipp_op_t op) /* I - Operation code */ +{ + ipp_t *request; /* IPP request message */ + cups_lang_t *language; /* Current language localization */ + + + /* + * Create a new IPP message... + */ + + if ((request = ippNew()) == NULL) + return (NULL); + + /* + * Set the operation and request ID... + */ + + request->request.op.operation_id = op; + request->request.op.request_id = 1; + + /* + * Use UTF-8 as the character set... + */ + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, "utf-8"); + + /* + * Get the language from the current locale... + */ + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + /* + * Return the new request... + */ + + return (request); +} + + +/* + * 'ippRead()' - Read data for an IPP message from a HTTP connection. + */ + +ipp_state_t /* O - Current state */ +ippRead(http_t *http, /* I - HTTP connection */ + ipp_t *ipp) /* I - IPP data */ +{ + DEBUG_printf(("ippRead(http=%p, ipp=%p), data_remaining=" CUPS_LLFMT "\n", + http, ipp, CUPS_LLCAST (http ? http->data_remaining : -1))); + + if (http == NULL) + return (IPP_ERROR); + + DEBUG_printf(("http->state = %d\n", http->state)); + + return (ippReadIO(http, (ipp_iocb_t)ipp_read_http, + http->blocking || http->used != 0, NULL, ipp)); +} + + +/* + * 'ippReadFile()' - Read data for an IPP message from a file. + * + * @since CUPS 1.1.19@ + */ + +ipp_state_t /* O - Current state */ +ippReadFile(int fd, /* I - HTTP data */ + ipp_t *ipp) /* I - IPP data */ +{ + DEBUG_printf(("ippReadFile(%d, %p)\n", fd, ipp)); + + return (ippReadIO(&fd, (ipp_iocb_t)ipp_read_file, 1, NULL, ipp)); +} + + +/* + * 'ippReadIO()' - Read data for an IPP message. + * + * @since CUPS 1.1.19@ + */ + +ipp_state_t /* O - Current state */ +ippReadIO(void *src, /* I - Data source */ + ipp_iocb_t cb, /* I - Read callback function */ + int blocking, /* I - Use blocking IO? */ + ipp_t *parent, /* I - Parent request, if any */ + ipp_t *ipp) /* I - IPP data */ +{ + int n; /* Length of data */ + unsigned char buffer[32768], /* 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(("ippReadIO(%p, %p, %d, %p, %p)\n", src, cb, blocking, + parent, ipp)); + + if (src == NULL || ipp == NULL) + return (IPP_ERROR); + + switch (ipp->state) + { + case IPP_IDLE : + ipp->state ++; /* Avoid common problem... */ + + case IPP_HEADER : + if (parent == NULL) + { + /* + * Get the request header... + */ + + if ((n = (*cb)(src, buffer, 8)) < 8) + { + DEBUG_printf(("ippReadIO: 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(("ippReadIO: 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]; + + DEBUG_printf(("ippReadIO: version=%d.%d\n", buffer[0], buffer[1])); + DEBUG_printf(("ippReadIO: op_status=%04x\n", + ipp->request.any.op_status)); + DEBUG_printf(("ippReadIO: request_id=%d\n", + ipp->request.any.request_id)); + } + + ipp->state = IPP_ATTRIBUTE; + ipp->current = NULL; + ipp->curtag = IPP_TAG_ZERO; + ipp->prev = ipp->last; + + /* + * If blocking is disabled, stop here... + */ + + if (!blocking) + break; + + case IPP_ATTRIBUTE : + while ((*cb)(src, buffer, 1) > 0) + { + DEBUG_printf(("ippReadIO: ipp->current=%p, ipp->prev=%p\n", + ipp->current, ipp->prev)); + + /* + * Read this attribute... + */ + + tag = (ipp_tag_t)buffer[0]; + + if (tag == IPP_TAG_END) + { + /* + * No more attributes left... + */ + + DEBUG_puts("ippReadIO: 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) + ipp->prev = ippAddSeparator(ipp); + else if (ipp->current) + ipp->prev = ipp->current; + + ipp->curtag = tag; + ipp->current = NULL; + DEBUG_printf(("ippReadIO: group tag = %x, ipp->prev=%p\n", tag, + ipp->prev)); + continue; + } + + DEBUG_printf(("ippReadIO: value tag = %x\n", tag)); + + /* + * Get the name... + */ + + if ((*cb)(src, buffer, 2) < 2) + { + DEBUG_puts("ippReadIO: unable to read name length!"); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + + if (n > (sizeof(buffer) - 1)) + { + DEBUG_printf(("ippReadIO: bad name length %d!\n", n)); + return (IPP_ERROR); + } + + DEBUG_printf(("ippReadIO: name length = %d\n", n)); + + if (n == 0 && tag != IPP_TAG_MEMBERNAME && + tag != IPP_TAG_END_COLLECTION) + { + /* + * 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_ZERO) + { + /* + * Setting the value of a collection member... + */ + + attr->value_tag = tag; + } + else 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 == 1 || + (attr->num_values > 0 && + (attr->num_values & (IPP_MAX_VALUES - 1)) == 0)) + { + ipp_attribute_t *temp; /* Pointer to new buffer */ + + + DEBUG_printf(("ippReadIO: reallocating for up to %d values...\n", + attr->num_values + IPP_MAX_VALUES)); + + /* + * 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); + + if (temp != attr) + { + /* + * Reset pointers in the list... + */ + + if (ipp->prev) + ipp->prev->next = temp; + else + ipp->attrs = temp; + + attr = ipp->current = ipp->last = temp; + } + } + } + else if (tag == IPP_TAG_MEMBERNAME) + { + /* + * Name must be length 0! + */ + + if (n) + { + DEBUG_puts("ippReadIO: member name not empty!"); + return (IPP_ERROR); + } + + if (ipp->current) + ipp->prev = ipp->current; + + attr = ipp->current = _ipp_add_attr(ipp, 1); + + DEBUG_printf(("ippReadIO: membername, ipp->current=%p, ipp->prev=%p\n", + ipp->current, ipp->prev)); + + attr->group_tag = ipp->curtag; + attr->value_tag = IPP_TAG_ZERO; + attr->num_values = 0; + } + else if (tag != IPP_TAG_END_COLLECTION) + { + /* + * New attribute; read the name and add it... + */ + + if ((*cb)(src, buffer, n) < n) + { + DEBUG_puts("ippReadIO: unable to read name!"); + return (IPP_ERROR); + } + + buffer[n] = '\0'; + + if (ipp->current) + ipp->prev = ipp->current; + + attr = ipp->current = _ipp_add_attr(ipp, 1); + + DEBUG_printf(("ippReadIO: name=\'%s\', ipp->current=%p, ipp->prev=%p\n", + buffer, ipp->current, ipp->prev)); + + attr->group_tag = ipp->curtag; + attr->value_tag = tag; + attr->name = strdup((char *)buffer); + attr->num_values = 0; + } + else + attr = NULL; + + if (tag != IPP_TAG_END_COLLECTION) + value = attr->values + attr->num_values; + else + value = NULL; + + if ((*cb)(src, buffer, 2) < 2) + { + DEBUG_puts("ippReadIO: unable to read value length!"); + return (IPP_ERROR); + } + + n = (buffer[0] << 8) | buffer[1]; + DEBUG_printf(("ippReadIO: value length = %d\n", n)); + + switch (tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + if ((*cb)(src, buffer, 4) < 4) + { + DEBUG_puts("ippReadIO: Unable to read integer value!"); + return (IPP_ERROR); + } + + n = (((((buffer[0] << 8) | buffer[1]) << 8) | buffer[2]) << 8) | + buffer[3]; + + value->integer = n; + break; + case IPP_TAG_BOOLEAN : + if ((*cb)(src, buffer, 1) < 1) + { + DEBUG_puts("ippReadIO: Unable to read boolean value!"); + 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 ((*cb)(src, (ipp_uchar_t *)value->string.text, n) < n) + { + DEBUG_puts("ippReadIO: Unable to read string value!"); + return (IPP_ERROR); + } + + DEBUG_printf(("ippReadIO: value = \'%s\'\n", + value->string.text)); + break; + case IPP_TAG_DATE : + if ((*cb)(src, value->date, 11) < 11) + { + DEBUG_puts("ippReadIO: Unable to date integer value!"); + return (IPP_ERROR); + } + break; + case IPP_TAG_RESOLUTION : + if ((*cb)(src, buffer, 9) < 9) + { + DEBUG_puts("ippReadIO: Unable to read resolution value!"); + 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 ((*cb)(src, buffer, 8) < 8) + { + DEBUG_puts("ippReadIO: Unable to read range value!"); + 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 (n > sizeof(buffer) || n < 4) + { + DEBUG_printf(("ippReadIO: bad value length %d!\n", n)); + return (IPP_ERROR); + } + + if ((*cb)(src, buffer, n) < n) + { + DEBUG_puts("ippReadIO: Unable to read string w/language value!"); + 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; + + case IPP_TAG_BEGIN_COLLECTION : + /* + * Oh, boy, here comes a collection value, so read it... + */ + + value->collection = ippNew(); + + if (n > 0) + { + DEBUG_puts("ippReadIO: begCollection tag with value length > 0!"); + return (IPP_ERROR); + } + + if (ippReadIO(src, cb, 1, ipp, value->collection) == IPP_ERROR) + { + DEBUG_puts("ippReadIO: Unable to read collection value!"); + return (IPP_ERROR); + } + break; + + case IPP_TAG_END_COLLECTION : + if (n > 0) + { + DEBUG_puts("ippReadIO: endCollection tag with value length > 0!"); + return (IPP_ERROR); + } + + DEBUG_puts("ippReadIO: endCollection tag..."); + + return (ipp->state = IPP_DATA); + + case IPP_TAG_MEMBERNAME : + /* + * The value is the name of the member in the collection, + * which we need to carry over... + */ + + attr->name = calloc(n + 1, 1); + + if ((*cb)(src, (ipp_uchar_t *)attr->name, n) < n) + { + DEBUG_puts("ippReadIO: Unable to read member name value!"); + return (IPP_ERROR); + } + + /* + * Since collection members are encoded differently than + * regular attributes, make sure we don't start with an + * empty value... + */ + + attr->num_values --; + + DEBUG_printf(("ippReadIO: member name = \"%s\"\n", attr->name)); + break; + + default : /* Other unsupported values */ + value->unknown.length = n; + if (n > 0) + { + value->unknown.data = malloc(n); + if ((*cb)(src, value->unknown.data, n) < n) + { + DEBUG_puts("ippReadIO: Unable to read unsupported value!"); + return (IPP_ERROR); + } + } + else + value->unknown.data = NULL; + break; + } + + attr->num_values ++; + + /* + * If blocking is disabled, stop here... + */ + + if (!blocking) + 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 */ + ipp_uchar_t *date = _cupsGlobals()->ipp_date; + /* 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 message to a HTTP connection. + */ + +ipp_state_t /* O - Current state */ +ippWrite(http_t *http, /* I - HTTP connection */ + ipp_t *ipp) /* I - IPP data */ +{ + DEBUG_printf(("ippWrite(%p, %p)\n", http, ipp)); + + if (http == NULL) + return (IPP_ERROR); + + return (ippWriteIO(http, (ipp_iocb_t)httpWrite, + http->blocking, NULL, ipp)); +} + + +/* + * 'ippWriteFile()' - Write data for an IPP message to a file. + * + * @since CUPS 1.1.19@ + */ + +ipp_state_t /* O - Current state */ +ippWriteFile(int fd, /* I - HTTP data */ + ipp_t *ipp) /* I - IPP data */ +{ + DEBUG_printf(("ippWriteFile(%d, %p)\n", fd, ipp)); + + ipp->state = IPP_IDLE; + + return (ippWriteIO(&fd, (ipp_iocb_t)ipp_write_file, 1, NULL, ipp)); +} + + +/* + * 'ippWriteIO()' - Write data for an IPP message. + * + * @since CUPS 1.1.19@ + */ + +ipp_state_t /* O - Current state */ +ippWriteIO(void *dst, /* I - Destination */ + ipp_iocb_t cb, /* I - Write callback function */ + int blocking, /* I - Use blocking IO? */ + ipp_t *parent, /* I - Parent IPP message */ + ipp_t *ipp) /* I - IPP data */ +{ + int i; /* Looping var */ + int n; /* Length of data */ + unsigned char buffer[32768], /* Data buffer */ + *bufptr; /* Pointer into buffer */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_value_t *value; /* Current value */ + + + DEBUG_printf(("ippWriteIO(%p, %p, %d, %p, %p)\n", dst, cb, blocking, + parent, ipp)); + + if (dst == NULL || ipp == NULL) + return (IPP_ERROR); + + switch (ipp->state) + { + case IPP_IDLE : + ipp->state ++; /* Avoid common problem... */ + + case IPP_HEADER : + if (parent == NULL) + { + /* + * Send the request header: + * + * Version = 2 bytes + * Operation/Status Code = 2 bytes + * Request ID = 4 bytes + * Total = 8 bytes + */ + + 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 ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP header..."); + return (IPP_ERROR); + } + } + + /* + * Reset the state engine to point to the first attribute + * in the request/response, with no current group. + */ + + 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 (!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 && parent == NULL) + { + /* + * Send a group tag byte... + */ + + 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; + } + + /* + * Write the attribute tag and name. The current implementation + * does not support the extension value tags above 0x7f, so all + * value tags are 1 byte. + * + * The attribute name length does not include the trailing nul + * character in the source string. + * + * Collection values (parent != NULL) are written differently... + */ + + if (parent == NULL) + { + /* + * Get the length of the attribute name, and make sure it won't + * overflow the buffer... + */ + + if ((n = (int)strlen(attr->name)) > (sizeof(buffer) - 4)) + return (IPP_ERROR); + + /* + * Write the value tag, name length, and name string... + */ + + 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; + } + else + { + /* + * Get the length of the attribute name, and make sure it won't + * overflow the buffer... + */ + + if ((n = (int)strlen(attr->name)) > (sizeof(buffer) - 7)) + return (IPP_ERROR); + + /* + * Write the member name tag, name length, name string, value tag, + * and empty name for the collection member attribute... + */ + + DEBUG_printf(("ippWrite: writing value tag = %x\n", + IPP_TAG_MEMBERNAME)); + DEBUG_printf(("ippWrite: writing name = %d, \'%s\'\n", n, attr->name)); + DEBUG_printf(("ippWrite: writing value tag = %x\n", attr->value_tag)); + DEBUG_puts("ippWrite: writing name = 0, \'\'\n"); + + *bufptr++ = IPP_TAG_MEMBERNAME; + *bufptr++ = 0; + *bufptr++ = 0; + *bufptr++ = n >> 8; + *bufptr++ = n; + memcpy(bufptr, attr->name, n); + bufptr += n; + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + /* + * Now write the attribute value(s)... + */ + + 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 ((*cb)(dst, buffer, (int)(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; + } + + /* + * Integers and enumerations are both 4-byte signed + * (twos-complement) values. + * + * Put the 2-byte length and 4-byte value into the buffer... + */ + + *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 ((*cb)(dst, buffer, (int)(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; + } + + /* + * Boolean values are 1-byte; 0 = false, 1 = true. + * + * Put the 2-byte length and 1-byte value into the buffer... + */ + + *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 ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + if (value->string.text != NULL) + n = (int)strlen(value->string.text); + else + n = 0; + + if (n > (sizeof(buffer) - 2)) + return (IPP_ERROR); + + DEBUG_printf(("ippWrite: writing string = %d, \'%s\'\n", n, + value->string.text)); + + if ((int)(sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + /* + * All simple strings consist of the 2-byte length and + * character data without the trailing nul normally found + * in C strings. Also, strings cannot be longer than 32767 + * bytes since the 2-byte length is a signed (twos-complement) + * value. + * + * Put the 2-byte length and string characters in the buffer. + */ + + *bufptr++ = n >> 8; + *bufptr++ = n; + + if (n > 0) + { + 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 ((*cb)(dst, buffer, (int)(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; + } + + /* + * Date values consist of a 2-byte length and an + * 11-byte date/time structure defined by RFC 1903. + * + * Put the 2-byte length and 11-byte date/time + * structure in the buffer. + */ + + *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 ((*cb)(dst, buffer, (int)(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; + } + + /* + * Resolution values consist of a 2-byte length, + * 4-byte horizontal resolution value, 4-byte vertical + * resolution value, and a 1-byte units value. + * + * Put the 2-byte length and resolution value data + * into the buffer. + */ + + *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 ((*cb)(dst, buffer, (int)(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; + } + + /* + * Range values consist of a 2-byte length, + * 4-byte lower value, and 4-byte upper value. + * + * Put the 2-byte length and range value data + * into the buffer. + */ + + *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 ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + /* + * textWithLanguage and nameWithLanguage values consist + * of a 2-byte length for both strings and their + * individual lengths, a 2-byte length for the + * character string, the character string without the + * trailing nul, a 2-byte length for the character + * set string, and the character set string without + * the trailing nul. + */ + + n = 4; + + if (value->string.charset != NULL) + n += strlen(value->string.charset); + + if (value->string.text != NULL) + n += strlen(value->string.text); + + if (n > (sizeof(buffer) - 2)) + return (IPP_ERROR); + + if ((int)(sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if ((*cb)(dst, buffer, (int)(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 */ + if (value->string.charset != NULL) + n = (int)strlen(value->string.charset); + else + n = 0; + + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Charset */ + if (n > 0) + { + memcpy(bufptr, value->string.charset, n); + bufptr += n; + } + + /* Length of text */ + if (value->string.text != NULL) + n = (int)strlen(value->string.text); + else + n = 0; + + *bufptr++ = n >> 8; + *bufptr++ = n; + + /* Text */ + if (n > 0) + { + memcpy(bufptr, value->string.text, n); + bufptr += n; + } + } + break; + + case IPP_TAG_BEGIN_COLLECTION : + for (i = 0, value = attr->values; + i < attr->num_values; + i ++, value ++) + { + /* + * Collections are written with the begin-collection + * tag first with a value of 0 length, followed by the + * attributes in the collection, then the end-collection + * value... + */ + + if ((sizeof(buffer) - (bufptr - buffer)) < 5) + { + if ((*cb)(dst, buffer, (int)(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; + } + + /* + * Write a data length of 0 and flush the buffer... + */ + + *bufptr++ = 0; + *bufptr++ = 0; + + if ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + + /* + * Then write the collection attribute... + */ + + value->collection->state = IPP_IDLE; + + if (ippWriteIO(dst, cb, 1, ipp, value->collection) == IPP_ERROR) + return (IPP_ERROR); + } + 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 ((*cb)(dst, buffer, (int)(bufptr - buffer)) < 0) + { + DEBUG_puts("ippWrite: Could not write IPP attribute..."); + return (IPP_ERROR); + } + + bufptr = buffer; + } + + *bufptr++ = attr->value_tag; + *bufptr++ = 0; + *bufptr++ = 0; + } + + /* + * An unknown value might some new value that a + * vendor has come up with. It consists of a + * 2-byte length and the bytes in the unknown + * value buffer. + */ + + n = value->unknown.length; + + if (n > (sizeof(buffer) - 2)) + return (IPP_ERROR); + + if ((int)(sizeof(buffer) - (bufptr - buffer)) < (n + 2)) + { + if ((*cb)(dst, buffer, (int)(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 ((*cb)(dst, buffer, (int)(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 (!blocking) + break; + } + + if (ipp->current == NULL) + { + /* + * Done with all of the attributes; add the end-of-attributes + * tag or end-collection attribute... + */ + + if (parent == NULL) + { + buffer[0] = IPP_TAG_END; + n = 1; + } + else + { + buffer[0] = IPP_TAG_END_COLLECTION; + buffer[1] = 0; /* empty name */ + buffer[2] = 0; + buffer[3] = 0; /* empty value */ + buffer[4] = 0; + n = 5; + } + + if ((*cb)(dst, buffer, n) < 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); +} + + +/* + * '_ipp_add_attr()' - Add a new attribute to the request. + */ + +ipp_attribute_t * /* O - New attribute */ +_ipp_add_attr(ipp_t *ipp, /* I - IPP message */ + 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) + { + 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_length()' - Compute the length of an IPP message or collection value. + */ + +static size_t /* O - Size of IPP message */ +ipp_length(ipp_t *ipp, /* I - IPP message or collection */ + int collection) /* I - 1 if a collection, 0 otherwise */ +{ + 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 message header... + */ + + bytes = collection ? 0 : 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 && !collection) + { + group = attr->group_tag; + if (group == IPP_TAG_ZERO) + continue; + + bytes ++; /* Group tag */ + } + + if (!attr->name) + continue; + + 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 */ + + if (collection) + bytes += 5; /* Add membername overhead */ + + 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 ++) + if (value->string.text != NULL) + 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 ++) + { + if (value->string.charset != NULL) + bytes += strlen(value->string.charset); + + if (value->string.text != NULL) + bytes += strlen(value->string.text); + } + break; + + case IPP_TAG_BEGIN_COLLECTION : + for (i = 0, value = attr->values; + i < attr->num_values; + i ++, value ++) + bytes += ipp_length(attr->values[i].collection, 1); + 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 or 5 bytes + * for the "end of collection" tag and return... + */ + + if (collection) + bytes += 5; + else + bytes ++; + + DEBUG_printf(("bytes = %d\n", bytes)); + + return (bytes); +} + + +/* + * 'ipp_read_http()' - Semi-blocking read on a HTTP connection... + */ + +static int /* O - Number of bytes read */ +ipp_read_http(http_t *http, /* I - Client connection */ + ipp_uchar_t *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 */ + + + DEBUG_printf(("ipp_read_http(http=%p, buffer=%p, length=%d)\n", + http, buffer, length)); + + /* + * Loop until all bytes are read... + */ + + for (tbytes = 0, bytes = 0; tbytes < length; tbytes += bytes, buffer += bytes) + { + DEBUG_printf(("tbytes = %d, http->state = %d\n", tbytes, http->state)); + + if (http->state == HTTP_WAITING) + break; + + if (http->used > 0 && http->data_encoding == HTTP_ENCODE_LENGTH) + { + /* + * 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->data_remaining <= INT_MAX) + http->_data_remaining = (int)http->data_remaining; + else + http->_data_remaining = INT_MAX; + + if (http->used > 0) + memmove(http->buffer, http->buffer + bytes, http->used); + + if (http->data_remaining == 0) + { + if (http->data_encoding == HTTP_ENCODE_CHUNKED) + { + /* + * Get the trailing CR LF after the chunk... + */ + + if (!httpGets(len, sizeof(len), http)) + return (-1); + } + + if (http->data_encoding != HTTP_ENCODE_CHUNKED) + { + if (http->state == HTTP_POST_RECV) + http->state ++; + else + http->state = HTTP_WAITING; + } + } + } + else + { + /* + * Wait a maximum of 1 second for data... + */ + + if (!http->blocking) + { + /* + * Wait up to 1 second for more data on non-blocking sockets... + */ + + if (!httpWait(http, 1000)) + { + /* + * Signal no data... + */ + + bytes = -1; + break; + } + } + + if ((bytes = httpRead(http, (char *)buffer, length - tbytes)) <= 0) + break; + } + } + + /* + * Return the number of bytes read... + */ + + if (tbytes == 0 && bytes < 0) + tbytes = -1; + + DEBUG_printf(("returning %d bytes...\n", tbytes)); + + return (tbytes); +} + + +/* + * 'ipp_read_file()' - Read IPP data from a file. + */ + +static int /* O - Number of bytes read */ +ipp_read_file(int *fd, /* I - File descriptor */ + ipp_uchar_t *buffer, /* O - Read buffer */ + int length) /* I - Number of bytes to read */ +{ + return (read(*fd, buffer, length)); +} + + +/* + * 'ipp_write_file()' - Write IPP data to a file. + */ + +static int /* O - Number of bytes written */ +ipp_write_file(int *fd, /* I - File descriptor */ + ipp_uchar_t *buffer, /* I - Data to write */ + int length) /* I - Number of bytes to write */ +{ + return (write(*fd, buffer, length)); +} + + +/* + * End of "$Id: ipp.c 4922 2006-01-12 22:05:06Z mike $". + */ diff --git a/cups/ipp.h b/cups/ipp.h new file mode 100644 index 000000000..24b64a1de --- /dev/null +++ b/cups/ipp.h @@ -0,0 +1,477 @@ +/* + * "$Id: ipp.h 4922 2006-01-12 22:05:06Z mike $" + * + * Internet Printing Protocol definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#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\001" + +/* + * IPP registered port number... + * + * Note: Applications should never use IPP_PORT, but instead use the + * ippPort() function to allow overrides via the IPP_PORT environment + * variable and services file if needed! + */ + +# define IPP_PORT 631 + +/* + * Common limits... + */ + +# define IPP_MAX_NAME 256 +# define IPP_MAX_VALUES 8 /* Power-of-2 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_AUTHENTICATE_JOB +} 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 ****/ + +/**** New in CUPS 1.1.19 ****/ +typedef int (*ipp_iocb_t)(void *, ipp_uchar_t *, int); + /**** IPP IO Callback Function ****/ + +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; + + /**** New in CUPS 1.1.19 ****/ + struct /* Event Header */ + { + ipp_uchar_t version[2]; /* Protocol version number */ + ipp_status_t status_code; /* Status code */ + int request_id; /* Request ID */ + } event; +} ipp_request_t; + +/**** New in CUPS 1.1.19 ****/ +typedef struct ipp_str ipp_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 */ + +/**** New in CUPS 1.1.19 ****/ + ipp_t *collection; /* Collection value */ +} 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; + +struct ipp_str /**** IPP Request/Response/Notification ****/ +{ + 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 */ + +/**** New in CUPS 1.2 ****/ + ipp_attribute_t *prev; /* Previous attribute (for read) */ +}; + + +/* + * 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 * const *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); + +/**** New in CUPS 1.1.19 ****/ +extern ipp_attribute_t *ippAddCollection(ipp_t *ipp, ipp_tag_t group, const char *name, ipp_t *value); +extern ipp_attribute_t *ippAddCollections(ipp_t *ipp, ipp_tag_t group, const char *name, int num_values, const ipp_t **values); +extern void ippDeleteAttribute(ipp_t *ipp, ipp_attribute_t *attr); +extern ipp_state_t ippReadFile(int fd, ipp_t *ipp); +extern ipp_state_t ippReadIO(void *src, ipp_iocb_t cb, int blocking, ipp_t *parent, ipp_t *ipp); +extern ipp_state_t ippWriteFile(int fd, ipp_t *ipp); +extern ipp_state_t ippWriteIO(void *dst, ipp_iocb_t cb, int blocking, ipp_t *parent, ipp_t *ipp); + +/**** New in CUPS 1.2 ****/ +extern ipp_attribute_t *ippAddOctetString(ipp_t *ipp, ipp_tag_t group, + const char *name, + const void *data, int datalen); +extern ipp_status_t ippErrorValue(const char *name); +extern ipp_t *ippNewRequest(ipp_op_t op); +extern const char *ippOpString(ipp_op_t op); +extern ipp_op_t ippOpValue(const char *name); + +/* + * "Private" functions used internally by CUPS... + */ + +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: ipp.h 4922 2006-01-12 22:05:06Z mike $". + */ diff --git a/cups/langprintf.c b/cups/langprintf.c new file mode 100644 index 000000000..5f0b40b84 --- /dev/null +++ b/cups/langprintf.c @@ -0,0 +1,140 @@ +/* + * "$Id: langprintf.c 4898 2006-01-08 23:13:20Z mike $" + * + * Localized printf/puts functions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsLangPrintf() - Print a formatted message string to a file. + * _cupsLangPuts() - Print a static message string to a file. + */ + +/* + * Include necessary headers... + */ + +#include +#include "string.h" +#include "i18n.h" +#include "transcode.h" + + +/* + * '_cupsLangPrintf()' - Print a formatted message string to a file. + */ + +int /* O - Number of bytes written */ +_cupsLangPrintf(FILE *fp, /* I - File to write to */ + cups_lang_t *language, /* I - Language to use */ + const char *message, /* I - Message string to use */ + ...) /* I - Additional arguments as needed */ +{ + int bytes; /* Number of bytes formatted */ + char buffer[2048], /* Message buffer */ + output[8192]; /* Output buffer */ + va_list ap; /* Pointer to additional arguments */ + + + /* + * Range check... + */ + + if (!fp || !message) + return (-1); + + if (!language) + language = cupsLangDefault(); + + /* + * Format the string... + */ + + va_start(ap, message); + bytes = vsnprintf(buffer, sizeof(buffer), + _cupsLangString(language, message), ap); + va_end(ap); + + /* + * Transcode to the destination charset... + */ + + bytes = cupsUTF8ToCharset(output, (cups_utf8_t *)buffer, sizeof(output), + language->encoding); + + /* + * Write the string and return the number of bytes written... + */ + + if (bytes > 0) + return (fwrite(output, 1, bytes, fp)); + else + return (bytes); +} + + +/* + * '_cupsLangPuts()' - Print a static message string to a file. + */ + +int /* O - Number of bytes written */ +_cupsLangPuts(FILE *fp, /* I - File to write to */ + cups_lang_t *language, /* I - Language to use */ + const char *message) /* I - Message string to use */ +{ + int bytes; /* Number of bytes formatted */ + char output[2048]; /* Message buffer */ + + + /* + * Range check... + */ + + if (!fp || !message) + return (-1); + + if (!language) + language = cupsLangDefault(); + + /* + * Transcode to the destination charset... + */ + + bytes = cupsUTF8ToCharset(output, + (cups_utf8_t *)_cupsLangString(language, message), + sizeof(output), language->encoding); + + /* + * Write the string and return the number of bytes written... + */ + + if (bytes > 0) + return (fwrite(output, 1, bytes, fp)); + else + return (bytes); +} + + +/* + * End of "$Id: langprintf.c 4898 2006-01-08 23:13:20Z mike $". + */ diff --git a/cups/language.c b/cups/language.c new file mode 100644 index 000000000..aa263878e --- /dev/null +++ b/cups/language.c @@ -0,0 +1,1240 @@ +/* + * "$Id: language.c 4922 2006-01-12 22:05:06Z mike $" + * + * I18N/language support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsEncodingName() - Return the character encoding name string + * for the given encoding enumeration. + * cupsLangDefault() - Return the default language. + * 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. + * _cupsLangString() - Get a message string. + * _cupsMessageFree() - Free a messages array. + * _cupsMessageLoad() - Load a .po file into a messages array. + * _cupsMessageLookup() - Lookup a message string. + * _cupsRestoreLocale() - Restore the original locale... + * _cupsSaveLocale() - Set the locale and save a copy of the old locale... + * appleLangDefault() - Get the default locale string. + * cups_cache_lookup() - Lookup a language in the cache... + * cups_message_compare() - Compare two messages. + * cups_unquote() - Unquote characters in strings... + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include "debug.h" +#include +#ifdef HAVE_LANGINFO_H +# include +#endif /* HAVE_LANGINFO_H */ +#ifdef WIN32 +# include +#else +# include +#endif /* WIN32 */ + + +/* + * Local functions... + */ + +#ifdef __APPLE__ +# include +static const char *appleLangDefault(void); +#endif /* __APPLE__ */ +static cups_lang_t *cups_cache_lookup(const char *name, + cups_encoding_t encoding); +static int cups_message_compare(_cups_message_t *m1, + _cups_message_t *m2); +static void cups_unquote(char *d, const char *s); + + +/* + * Local globals... + */ + +static const char * const 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", "iso-8859-11", + "iso-8859-16", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "windows-932", "windows-936", + "windows-949", "windows-950", + "windows-1361", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "unknown", "unknown", + "euc-cn", "euc-jp", + "euc-kr", "euc-tw" + }; + + +/* + * '_cupsEncodingName()' - Return the character encoding name string + * for the given encoding enumeration. + */ + +const char * /* O - Character encoding */ +_cupsEncodingName( + cups_encoding_t encoding) /* I - Encoding value */ +{ + if (encoding < 0 || + encoding >= (sizeof(lang_encodings) / sizeof(const char *))) + return (lang_encodings[0]); + else + return (lang_encodings[encoding]); +} + + +/* + * 'cupsLangDefault()' - Return the default language. + */ + +cups_lang_t * /* O - Language data */ +cupsLangDefault(void) +{ + return (cupsLangGet(NULL)); +} + + +/* + * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.) + * for the given language. + */ + +const char * /* O - Character encoding */ +cupsLangEncoding(cups_lang_t *lang) /* I - Language data */ +{ + if (lang == NULL) + return ((char*)lang_encodings[0]); + else + return ((char*)lang_encodings[lang->encoding]); +} + + +/* + * 'cupsLangFlush()' - Flush all language data out of the cache. + */ + +void +cupsLangFlush(void) +{ + cups_lang_t *lang, /* Current language */ + *next; /* Next language */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * Free all languages in the cache... + */ + + for (lang = cg->lang_cache; lang != NULL; lang = next) + { + /* + * Free all messages... + */ + + _cupsMessageFree(lang->strings); + + /* + * Then free the language structure itself... + */ + + next = lang->next; + free(lang); + } + + cg->lang_cache = NULL; +} + + +/* + * '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; /* Looping var */ + char locale[255], /* Copy of locale name */ + langname[16], /* Requested language name */ + country[16], /* Country code */ + charset[16], /* Character set */ +#ifdef CODESET + *csptr, /* Pointer to CODESET string */ +#endif /* CODESET */ + *ptr, /* Pointer into language/charset */ + real[48], /* Real language name */ + filename[1024]; /* Filename for language locale file */ + cups_encoding_t encoding; /* Encoding to use */ + cups_lang_t *lang; /* Current language... */ + char *oldlocale; /* Old locale name */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + static const char * const locale_encodings[] = + { /* Locale charset names */ + "ASCII", "ISO88591", "ISO88592", "ISO88593", + "ISO88594", "ISO88595", "ISO88596", "ISO88597", + "ISO88598", "ISO88599", "ISO885910", "UTF8", + "ISO885913", "ISO885914", "ISO885915", "CP874", + "CP1250", "CP1251", "CP1252", "CP1253", + "CP1254", "CP1255", "CP1256", "CP1257", + "CP1258", "KOI8R", "KOI8U", "ISO885911", + "ISO885916", "", "", "", + + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + + "CP932", "CP936", "CP949", "CP950", + "CP1361", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + "", "", "", "", + + "EUCCN", "EUCJP", "EUCKR", "EUCTW" + }; + + + DEBUG_printf(("cupsLangGet(language=\"%s\")\n", language ? language : "(null)")); + +#ifdef __APPLE__ + /* + * Apple's setlocale doesn't give us the user's localization + * preference so we have to look it up this way... + */ + + if (language == NULL) + language = appleLangDefault(); +#else + if (language == NULL) + { + /* + * First see if the locale has been set; if it is still "C" or + * "POSIX", set the locale to the default... + */ + +# ifdef LC_MESSAGES + ptr = setlocale(LC_MESSAGES, NULL); +# else + ptr = setlocale(LC_ALL, NULL); +# endif /* LC_MESSAGES */ + + DEBUG_printf(("cupsLangGet: current locale is \"%s\"\n", + ptr ? ptr : "(null)")); + + if (!ptr || !strcmp(ptr, "C") || !strcmp(ptr, "POSIX")) +# ifdef LC_MESSAGES + { + ptr = setlocale(LC_MESSAGES, ""); + setlocale(LC_CTYPE, ""); + } +# else + ptr = setlocale(LC_ALL, ""); +# endif /* LC_MESSAGES */ + + if (ptr) + { + strlcpy(locale, ptr, sizeof(locale)); + language = locale; + + DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n", + language ? language : "(null)")); + } + } +#endif /* __APPLE__ */ + + /* + * If "language" is NULL at this point, then chances are we are using + * a language that is not installed for the base OS. + */ + + if (!language) + { + /* + * Switch to the value of the "LANG" environment variable, and if + * that is NULL as well, use "C". + */ + + if ((language = getenv("LANG")) == NULL) + language = "C"; + } + + /* + * Set the charset to "unknown"... + */ + + charset[0] = '\0'; + +#ifdef CODESET + /* + * On systems that support the nl_langinfo(CODESET) call, use + * this value as the character set... + */ + + if ((csptr = nl_langinfo(CODESET)) != NULL) + { + /* + * Copy all of the letters and numbers in the CODESET string... + */ + + for (ptr = charset; *csptr; csptr ++) + if (isalnum(*csptr & 255) && ptr < (charset + sizeof(charset) - 1)) + *ptr++ = *csptr; + + *ptr = '\0'; + + DEBUG_printf(("cupsLangGet: charset set to \"%s\" via nl_langinfo(CODESET)...\n", + charset)); + } +#endif /* CODESET */ + + /* + * Set the locale back to POSIX while we do string ops, since + * apparently some buggy C libraries break ctype() for non-I18N + * chars... + */ + +#if defined(__APPLE__) + /* The ctype bug isn't in Apple's libc */ + (void)locale; /* anti-compiler-warning-code */ + (void)oldlocale; /* anti-compiler-warning-code */ +#elif !defined(LC_CTYPE) + oldlocale = _cupsSaveLocale(LC_ALL, "C"); +#else + oldlocale = _cupsSaveLocale(LC_CTYPE, "C"); +#endif /* __APPLE__ */ + + /* + * Parse 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[.charset] (language-country) + * to ll_CC[.CHARSET] to match the file naming convention used by all + * POSIX-compliant operating systems. Invalid language names are mapped + * to the POSIX locale. + */ + + country[0] = '\0'; + + if (language == NULL || !language[0] || + !strcmp(language, "POSIX")) + strcpy(langname, "C"); + else + { + /* + * Copy the parts of the locale string over safely... + */ + + for (ptr = langname; *language; language ++) + if (*language == '_' || *language == '-' || *language == '.') + break; + else if (ptr < (langname + sizeof(langname) - 1)) + *ptr++ = tolower(*language & 255); + + *ptr = '\0'; + + if (*language == '_' || *language == '-') + { + /* + * Copy the country code... + */ + + for (language ++, ptr = country; *language; language ++) + if (*language == '.') + break; + else if (ptr < (country + sizeof(country) - 1)) + *ptr++ = toupper(*language & 255); + + *ptr = '\0'; + } + + if (*language == '.' && !charset[0]) + { + /* + * Copy the encoding... + */ + + for (language ++, ptr = charset; *language; language ++) + if (isalnum(*language & 255) && ptr < (charset + sizeof(charset) - 1)) + *ptr++ = toupper(*language & 255); + + *ptr = '\0'; + } + + /* + * Force a POSIX locale for an invalid language name... + */ + + if (strlen(langname) != 2) + { + strcpy(langname, "C"); + country[0] = '\0'; + charset[0] = '\0'; + } + } + + /* + * Restore the locale... + */ + +#if defined(__APPLE__) + /* The ctype bug isn't in Apple's libc */ +#elif !defined(LC_CTYPE) + _cupsRestoreLocale(LC_ALL, oldlocale); +#else + _cupsRestoreLocale(LC_CTYPE, oldlocale); +#endif /* __APPLE__ */ + + DEBUG_printf(("cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"\n", + langname, country, charset)); + + /* + * Figure out the desired encoding... + */ + + encoding = CUPS_AUTO_ENCODING; + + if (charset[0]) + { + for (i = 0; i < (int)(sizeof(locale_encodings) / sizeof(locale_encodings[0])); i ++) + if (!strcasecmp(charset, locale_encodings[i])) + { + encoding = (cups_encoding_t)i; + break; + } + } + + DEBUG_printf(("cupsLangGet: encoding=%d(%s)\n", encoding, + encoding == CUPS_AUTO_ENCODING ? "auto" : + lang_encodings[encoding])); + + /* + * See if we already have this language/country loaded... + */ + + snprintf(real, sizeof(real), "%s_%s", langname, country); + + if ((lang = cups_cache_lookup(real, encoding)) != NULL) + return (lang); + + snprintf(filename, sizeof(filename), "%s/%s/cups_%s", cg->localedir, + real, real); + + if (!country[0] || access(filename, 0)) + { + /* + * Country localization not available, look for generic localization... + */ + + if ((lang = cups_cache_lookup(langname, encoding)) != NULL) + return (lang); + + snprintf(filename, sizeof(filename), "%s/%s/cups_%s", cg->localedir, + langname, langname); + + if (access(filename, 0)) + { + /* + * No generic localization, so use POSIX... + */ + + strcpy(real, "C"); + snprintf(filename, sizeof(filename), "%s/C/cups_C", cg->localedir); + } + else + strcpy(real, langname); + } + + /* + * See if there is a free language available; if so, use that + * record... + */ + + for (lang = cg->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) + return (NULL); + + lang->next = cg->lang_cache; + cg->lang_cache = lang; + } + + /* + * Free all old strings as needed... + */ + + _cupsMessageFree(lang->strings); + + /* + * Then assign the language and encoding fields... + */ + + lang->used ++; + strlcpy(lang->language, real, sizeof(lang->language)); + + if (encoding != CUPS_AUTO_ENCODING) + lang->encoding = encoding; + else + lang->encoding = CUPS_UTF8; + + /* + * Read the strings from the file... + */ + + lang->strings = _cupsMessageLoad(filename); + + /* + * Return... + */ + + return (lang); +} + + +/* + * '_cupsLangString()' - Get a message string. + * + * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to + * convert the string to the language encoding. + */ + +const char * /* O - Localized message */ +_cupsLangString(cups_lang_t *lang, /* I - Language */ + const char *message) /* I - Message */ +{ + /* + * Range check input... + */ + + if (!lang || !message) + return (message); + + return (_cupsMessageLookup(lang->strings, message)); +} + + +/* + * '_cupsMessageFree()' - Free a messages array. + */ + +void +_cupsMessageFree(cups_array_t *a) /* I - Message array */ +{ + _cups_message_t *m; /* Current message */ + + + for (m = (_cups_message_t *)cupsArrayFirst(a); + m; + m = (_cups_message_t *)cupsArrayNext(a)) + { + /* + * Remove the message from the array, then free the message and strings. + */ + + cupsArrayRemove(a, m); + + if (m->id) + free(m->id); + + if (m->str) + free(m->str); + + free(m); + } + + /* + * Free the array... + */ + + cupsArrayDelete(a); +} + + +/* + * '_cupsMessageLoad()' - Load a .po file into a messages array. + */ + +cups_array_t * /* O - New message array */ +_cupsMessageLoad(const char *filename) /* I - Message catalog to load */ +{ + cups_file_t *fp; /* Message file */ + cups_array_t *a; /* Message array */ + _cups_message_t *m; /* Current message */ + char s[4096], /* String buffer */ + *ptr, /* Pointer into buffer */ + *temp; /* New string */ + int length; /* Length of combined strings */ + + + /* + * Create an array to hold the messages... + */ + + if ((a = cupsArrayNew((cups_array_func_t)cups_message_compare, NULL)) == NULL) + return (NULL); + + /* + * Open the message catalog file... + */ + + if ((fp = cupsFileOpen(filename, "r")) == NULL) + return (a); + + /* + * Read messages from the catalog file until EOF... + * + * The format is the GNU gettext .po format, which is fairly simple: + * + * msgid "some text" + * msgstr "localized text" + * + * The localized text can span multiple lines using the form: + * + * msgid "some long text" + * msgstr "localized text spanning " + * "multiple lines" + */ + + m = NULL; + + while (cupsFileGets(fp, s, sizeof(s)) != NULL) + { + /* + * Skip blank and comment lines... + */ + + if (s[0] == '#' || !s[0]) + continue; + + /* + * Strip the trailing quote... + */ + + if ((ptr = strrchr(s, '\"')) == NULL) + continue; + + *ptr = '\0'; + + /* + * Find start of value... + */ + + if ((ptr = strchr(s, '\"')) == NULL) + continue; + + ptr ++; + + /* + * Unquote the text... + */ + + cups_unquote(ptr, ptr); + + /* + * Create or add to a message... + */ + + if (!strncmp(s, "msgid", 5)) + { + if ((m = (_cups_message_t *)calloc(1, sizeof(_cups_message_t))) == NULL) + { + cupsFileClose(fp); + return (a); + } + + m->id = strdup(ptr); + cupsArrayAdd(a, m); + } + else if ((s[0] == '\"' || !strncmp(s, "msgstr", 6)) && m) + { + if (m->str) + { + /* + * Append the string... + */ + + length = strlen(m->str); + + if ((temp = realloc(m->str, length + strlen(ptr) + 1)) == NULL) + { + cupsFileClose(fp); + return (a); + } + else + m->str = temp; + + /* + * Copy the new portion at the end - safe because the buffer is + * allocated to the correct size... + */ + + strcpy(m->str + length, ptr); + } + else + { + /* + * Set the string... + */ + + m->str = strdup(ptr); + } + } + } + + /* + * Close the message catalog file and return the new array... + */ + + cupsFileClose(fp); + + return (a); +} + + +/* + * '_cupsMessageLookup()' - Lookup a message string. + */ + +const char * /* O - Localized message */ +_cupsMessageLookup(cups_array_t *a, /* I - Message array */ + const char *m) /* I - Message */ +{ + _cups_message_t key, /* Search key */ + *match; /* Matching message */ + + + /* + * Lookup the message string; if it doesn't exist in the catalog, + * then return the message that was passed to us... + */ + + key.id = (char *)m; + match = (_cups_message_t *)cupsArrayFind(a, &key); + + if (match && match->str) + return (match->str); + else + return (m); +} + + +/* + * '_cupsRestoreLocale()' - Restore the original locale... + */ + +void +_cupsRestoreLocale(int category, /* I - Category */ + char *oldlocale) /* I - Old locale or NULL */ +{ + DEBUG_printf(("_cupsRestoreLocale(category=%d, oldlocale=\"%s\")\n", + category, oldlocale)); + + if (oldlocale) + { + /* + * Reset the locale and free the locale string... + */ + + setlocale(category, oldlocale); + free(oldlocale); + } +} + + +/* + * '_cupsSaveLocale()' - Set the locale and save a copy of the old locale... + */ + +char * /* O - Old locale or NULL */ +_cupsSaveLocale(int category, /* I - Category */ + const char *locale) /* I - New locale or NULL */ +{ + char *oldlocale; /* Old locale */ + + + DEBUG_printf(("_cupsSaveLocale(category=%d, locale=\"%s\")\n", + category, locale)); + + /* + * Get the old locale and copy it... + */ + + if ((oldlocale = setlocale(category, NULL)) != NULL) + oldlocale = strdup(oldlocale); + + DEBUG_printf((" oldlocale=\"%s\"\n", oldlocale ? oldlocale : "(null)")); + + /* + * Set the new locale... + */ + + setlocale(category, locale); + + /* + * Return a copy of the old locale... + */ + + return (oldlocale); +} + + +#ifdef __APPLE__ +/* + * Code & data to translate OSX's language names to their ISO 639-1 locale. + * + * The first version uses the new CoreFoundation API added in 10.3 (Panther), + * the second is for 10.2 (Jaguar). + */ + +# ifdef HAVE_CF_LOCALE_ID +/* + * 'appleLangDefault()' - Get the default locale string. + */ + +static const char * /* O - Locale string */ +appleLangDefault(void) +{ + CFPropertyListRef localizationList; + /* List of localization data */ + CFStringRef languageName; /* Current name */ + CFStringRef localeName; /* Canonical from of name */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Only do the lookup and translation the first time. + */ + + if (!cg->language[0]) + { + localizationList = + CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), + kCFPreferencesCurrentApplication); + + if (localizationList != NULL) + { + if (CFGetTypeID(localizationList) == CFArrayGetTypeID() && + CFArrayGetCount(localizationList) > 0) + { + languageName = CFArrayGetValueAtIndex(localizationList, 0); + + if (languageName != NULL && + CFGetTypeID(languageName) == CFStringGetTypeID()) + { + localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString( + kCFAllocatorDefault, languageName); + + if (localeName != NULL) + { + CFStringGetCString(localeName, cg->language, sizeof(cg->language), + kCFStringEncodingASCII); + CFRelease(localeName); + + if (!strcmp(cg->language, "en")) + strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language)); + else if (strchr(cg->language, '.') == NULL) + strlcat(cg->language, ".UTF-8", sizeof(cg->language)); + } + } + } + + CFRelease(localizationList); + } + + /* + * If we didn't find the language, default to en_US... + */ + + if (!cg->language[0]) + strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language)); + } + + /* + * Return the cached locale... + */ + + return (cg->language); +} +# else +/* + * Code & data to translate OSX 10.2's language names to their ISO 639-1 + * locale. + */ + +typedef struct +{ + const char * const name; /* Language name */ + const char * const locale; /* Locale name */ +} _apple_name_locale_t; + +static const _apple_name_locale_t apple_name_locale[] = +{ + { "English" , "en_US.UTF-8" }, { "French" , "fr.UTF-8" }, + { "German" , "de.UTF-8" }, { "Italian" , "it.UTF-8" }, + { "Dutch" , "nl.UTF-8" }, { "Swedish" , "sv.UTF-8" }, + { "Spanish" , "es.UTF-8" }, { "Danish" , "da.UTF-8" }, + { "Portuguese" , "pt.UTF-8" }, { "Norwegian" , "no.UTF-8" }, + { "Hebrew" , "he.UTF-8" }, { "Japanese" , "ja.UTF-8" }, + { "Arabic" , "ar.UTF-8" }, { "Finnish" , "fi.UTF-8" }, + { "Greek" , "el.UTF-8" }, { "Icelandic" , "is.UTF-8" }, + { "Maltese" , "mt.UTF-8" }, { "Turkish" , "tr.UTF-8" }, + { "Croatian" , "hr.UTF-8" }, { "Chinese" , "zh.UTF-8" }, + { "Urdu" , "ur.UTF-8" }, { "Hindi" , "hi.UTF-8" }, + { "Thai" , "th.UTF-8" }, { "Korean" , "ko.UTF-8" }, + { "Lithuanian" , "lt.UTF-8" }, { "Polish" , "pl.UTF-8" }, + { "Hungarian" , "hu.UTF-8" }, { "Estonian" , "et.UTF-8" }, + { "Latvian" , "lv.UTF-8" }, { "Sami" , "se.UTF-8" }, + { "Faroese" , "fo.UTF-8" }, { "Farsi" , "fa.UTF-8" }, + { "Russian" , "ru.UTF-8" }, { "Chinese" , "zh.UTF-8" }, + { "Dutch" , "nl.UTF-8" }, { "Irish" , "ga.UTF-8" }, + { "Albanian" , "sq.UTF-8" }, { "Romanian" , "ro.UTF-8" }, + { "Czech" , "cs.UTF-8" }, { "Slovak" , "sk.UTF-8" }, + { "Slovenian" , "sl.UTF-8" }, { "Yiddish" , "yi.UTF-8" }, + { "Serbian" , "sr.UTF-8" }, { "Macedonian" , "mk.UTF-8" }, + { "Bulgarian" , "bg.UTF-8" }, { "Ukrainian" , "uk.UTF-8" }, + { "Byelorussian", "be.UTF-8" }, { "Uzbek" , "uz.UTF-8" }, + { "Kazakh" , "kk.UTF-8" }, { "Azerbaijani", "az.UTF-8" }, + { "Azerbaijani" , "az.UTF-8" }, { "Armenian" , "hy.UTF-8" }, + { "Georgian" , "ka.UTF-8" }, { "Moldavian" , "mo.UTF-8" }, + { "Kirghiz" , "ky.UTF-8" }, { "Tajiki" , "tg.UTF-8" }, + { "Turkmen" , "tk.UTF-8" }, { "Mongolian" , "mn.UTF-8" }, + { "Mongolian" , "mn.UTF-8" }, { "Pashto" , "ps.UTF-8" }, + { "Kurdish" , "ku.UTF-8" }, { "Kashmiri" , "ks.UTF-8" }, + { "Sindhi" , "sd.UTF-8" }, { "Tibetan" , "bo.UTF-8" }, + { "Nepali" , "ne.UTF-8" }, { "Sanskrit" , "sa.UTF-8" }, + { "Marathi" , "mr.UTF-8" }, { "Bengali" , "bn.UTF-8" }, + { "Assamese" , "as.UTF-8" }, { "Gujarati" , "gu.UTF-8" }, + { "Punjabi" , "pa.UTF-8" }, { "Oriya" , "or.UTF-8" }, + { "Malayalam" , "ml.UTF-8" }, { "Kannada" , "kn.UTF-8" }, + { "Tamil" , "ta.UTF-8" }, { "Telugu" , "te.UTF-8" }, + { "Sinhalese" , "si.UTF-8" }, { "Burmese" , "my.UTF-8" }, + { "Khmer" , "km.UTF-8" }, { "Lao" , "lo.UTF-8" }, + { "Vietnamese" , "vi.UTF-8" }, { "Indonesian" , "id.UTF-8" }, + { "Tagalog" , "tl.UTF-8" }, { "Malay" , "ms.UTF-8" }, + { "Malay" , "ms.UTF-8" }, { "Amharic" , "am.UTF-8" }, + { "Tigrinya" , "ti.UTF-8" }, { "Oromo" , "om.UTF-8" }, + { "Somali" , "so.UTF-8" }, { "Swahili" , "sw.UTF-8" }, + { "Kinyarwanda" , "rw.UTF-8" }, { "Rundi" , "rn.UTF-8" }, + { "Nyanja" , "" }, { "Malagasy" , "mg.UTF-8" }, + { "Esperanto" , "eo.UTF-8" }, { "Welsh" , "cy.UTF-8" }, + { "Basque" , "eu.UTF-8" }, { "Catalan" , "ca.UTF-8" }, + { "Latin" , "la.UTF-8" }, { "Quechua" , "qu.UTF-8" }, + { "Guarani" , "gn.UTF-8" }, { "Aymara" , "ay.UTF-8" }, + { "Tatar" , "tt.UTF-8" }, { "Uighur" , "ug.UTF-8" }, + { "Dzongkha" , "dz.UTF-8" }, { "Javanese" , "jv.UTF-8" }, + { "Sundanese" , "su.UTF-8" }, { "Galician" , "gl.UTF-8" }, + { "Afrikaans" , "af.UTF-8" }, { "Breton" , "br.UTF-8" }, + { "Inuktitut" , "iu.UTF-8" }, { "Scottish" , "gd.UTF-8" }, + { "Manx" , "gv.UTF-8" }, { "Irish" , "ga.UTF-8" }, + { "Tongan" , "to.UTF-8" }, { "Greek" , "el.UTF-8" }, + { "Greenlandic" , "kl.UTF-8" }, { "Azerbaijani", "az.UTF-8" } +}; + + +/* + * 'appleLangDefault()' - Get the default locale string. + */ + +static const char * /* O - Locale string */ +appleLangDefault(void) +{ + int i; /* Looping var */ + CFPropertyListRef localizationList; + /* List of localization data */ + CFStringRef localizationName; + /* Current name */ + char buff[256]; /* Temporary buffer */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Only do the lookup and translation the first time. + */ + + if (cg->language == NULL) + { + localizationList = + CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), + kCFPreferencesCurrentApplication); + + if (localizationList != NULL) + { + if (CFGetTypeID(localizationList) == CFArrayGetTypeID() && + CFArrayGetCount(localizationList) > 0) + { + localizationName = CFArrayGetValueAtIndex(localizationList, 0); + + if (localizationName != NULL && + CFGetTypeID(localizationName) == CFStringGetTypeID()) + { + CFIndex length = CFStringGetLength(localizationName); + + if (length <= sizeof(buff) && + CFStringGetCString(localizationName, buff, sizeof(buff), + kCFStringEncodingASCII)) + { + buff[sizeof(buff) - 1] = '\0'; + + for (i = 0; + i < sizeof(apple_name_locale) / sizeof(apple_name_locale[0]); + i++) + { + if (!strcasecmp(buff, apple_name_locale[i].name)) + { + cg->language = apple_name_locale[i].locale; + break; + } + } + } + } + } + + CFRelease(localizationList); + } + + /* + * If we didn't find the language, default to en_US... + */ + + if (cg->language == NULL) + cg->language = apple_name_locale[0].locale; + } + + /* + * Return the cached locale... + */ + + return (cg->language); +} +# endif /* HAVE_CF_LOCALE_ID */ +#endif /* __APPLE__ */ + + +/* + * 'cups_cache_lookup()' - Lookup a language in the cache... + */ + +static cups_lang_t * /* O - Language data or NULL */ +cups_cache_lookup(const char *name,/* I - Name of locale */ + cups_encoding_t encoding) + /* I - Encoding of locale */ +{ + cups_lang_t *lang; /* Current language */ + + + DEBUG_printf(("cups_cache_lookup(name=\"%s\", encoding=%d(%s))\n", name, + encoding, encoding == CUPS_AUTO_ENCODING ? "auto" : + lang_encodings[encoding])); + + /* + * Loop through the cache and return a match if found... + */ + + for (lang = _cupsGlobals()->lang_cache; lang != NULL; lang = lang->next) + { + DEBUG_printf(("cups_cache_lookup: lang=%p, language=\"%s\", encoding=%d(%s)\n", + lang, lang->language, lang->encoding, + lang_encodings[lang->encoding])); + + if (!strcmp(lang->language, name) && + (encoding == CUPS_AUTO_ENCODING || encoding == lang->encoding)) + { + lang->used ++; + + DEBUG_puts("cups_cache_lookup: returning match!"); + + return (lang); + } + } + + DEBUG_puts("cups_cache_lookup: returning NULL!"); + + return (NULL); +} + + +/* + * 'cups_message_compare()' - Compare two messages. + */ + +static int /* O - Result of comparison */ +cups_message_compare( + _cups_message_t *m1, /* I - First message */ + _cups_message_t *m2) /* I - Second message */ +{ + return (strcmp(m1->id, m2->id)); +} + + +/* + * 'cups_unquote()' - Unquote characters in strings... + */ + +static void +cups_unquote(char *d, /* O - Unquoted string */ + const char *s) /* I - Original string */ +{ + while (*s) + { + if (*s == '\\') + { + s ++; + if (isdigit(*s)) + { + *d = 0; + + while (isdigit(*s)) + { + *d = *d * 8 + *s - '0'; + s ++; + } + } + else + { + if (*s == 'n') + *d ++ = '\n'; + else if (*s == 'r') + *d ++ = '\r'; + else if (*s == 't') + *d ++ = '\t'; + else + *d++ = *s; + + s ++; + } + } + else + *d++ = *s++; + } + + *d = '\0'; +} + + +/* + * End of "$Id: language.c 4922 2006-01-12 22:05:06Z mike $". + */ diff --git a/cups/language.h b/cups/language.h new file mode 100644 index 000000000..1f697cc1d --- /dev/null +++ b/cups/language.h @@ -0,0 +1,122 @@ +/* + * "$Id: language.h 4903 2006-01-10 20:02:46Z mike $" + * + * Multi-language support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_LANGUAGE_H_ +# define _CUPS_LANGUAGE_H_ + +/* + * Include necessary headers... + */ + +# include +# include "array.h" + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Types... + */ + +typedef enum cups_encoding_e /**** Language Encodings ****/ +{ + CUPS_AUTO_ENCODING = -1, /* Auto-detect the encoding @private@ */ + CUPS_US_ASCII, /* US ASCII */ + CUPS_ISO8859_1, /* ISO-8859-1 */ + CUPS_ISO8859_2, /* ISO-8859-2 */ + CUPS_ISO8859_3, /* ISO-8859-3 */ + CUPS_ISO8859_4, /* ISO-8859-4 */ + CUPS_ISO8859_5, /* ISO-8859-5 */ + CUPS_ISO8859_6, /* ISO-8859-6 */ + CUPS_ISO8859_7, /* ISO-8859-7 */ + CUPS_ISO8859_8, /* ISO-8859-8 */ + CUPS_ISO8859_9, /* ISO-8859-9 */ + CUPS_ISO8859_10, /* ISO-8859-10 */ + CUPS_UTF8, /* UTF-8 */ + CUPS_ISO8859_13, /* ISO-8859-13 */ + CUPS_ISO8859_14, /* ISO-8859-14 */ + CUPS_ISO8859_15, /* ISO-8859-15 */ + CUPS_WINDOWS_874, /* CP-874 */ + CUPS_WINDOWS_1250, /* CP-1250 */ + CUPS_WINDOWS_1251, /* CP-1251 */ + CUPS_WINDOWS_1252, /* CP-1252 */ + CUPS_WINDOWS_1253, /* CP-1253 */ + CUPS_WINDOWS_1254, /* CP-1254 */ + CUPS_WINDOWS_1255, /* CP-1255 */ + CUPS_WINDOWS_1256, /* CP-1256 */ + CUPS_WINDOWS_1257, /* CP-1257 */ + CUPS_WINDOWS_1258, /* CP-1258 */ + CUPS_KOI8_R, /* KOI-8-R */ + CUPS_KOI8_U, /* KOI-8-U */ + CUPS_ISO8859_11, /* ISO-8859-11 */ + CUPS_ISO8859_16, /* ISO-8859-16 */ + CUPS_ENCODING_SBCS_END = 63, /* End of single-bybte encodings @private@ */ + + CUPS_WINDOWS_932, /* Japanese JIS X0208-1990 */ + CUPS_WINDOWS_936, /* Simplified Chinese GB 2312-80 */ + CUPS_WINDOWS_949, /* Korean KS C5601-1992 */ + CUPS_WINDOWS_950, /* Traditional Chinese Big Five */ + CUPS_WINDOWS_1361, /* Korean Johab */ + CUPS_ENCODING_DBCS_END = 127, /* End of double-byte encodings @private@ */ + + CUPS_EUC_CN, /* EUC Simplified Chinese */ + CUPS_EUC_JP, /* EUC Japanese */ + CUPS_EUC_KR, /* EUC Korean */ + CUPS_EUC_TW, /* EUC Traditional Chinese */ + CUPS_ENCODING_VBCS_END = 191 /* End of variable-length encodings @private@ */ +} cups_encoding_t; + +typedef struct cups_lang_s /**** Language Cache Structure ****/ +{ + struct cups_lang_s *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 */ + cups_array_t *strings; /* Message strings @private@ */ +} cups_lang_t; + + +/* + * Prototypes... + */ + +extern cups_lang_t *cupsLangDefault(void); +extern const 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); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_LANGUAGE_H_ */ + +/* + * End of "$Id: language.h 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/cups/libcups_s.exp b/cups/libcups_s.exp new file mode 100644 index 000000000..000766cdf --- /dev/null +++ b/cups/libcups_s.exp @@ -0,0 +1,21 @@ +_cups_hstrerror +_cups_md5_append +_cups_md5_finish +_cups_md5_init +_cups_strlcat +_cups_strlcpy +_cupsEncodingName +_cupsGetPassword +_cupsGlobals +_cupsLangPrintf +_cupsLangPuts +_cupsLangString +_cupsMessageFree +_cupsMessageLoad +_cupsMessageLookup +_cupsRestoreLocale +_cupsSaveLocale +_httpReadCDSA +_httpWriteCDSA +_ipp_add_attr +_ipp_free_attr diff --git a/cups/mark.c b/cups/mark.c new file mode 100644 index 000000000..cbeb54ff1 --- /dev/null +++ b/cups/mark.c @@ -0,0 +1,443 @@ +/* + * "$Id: mark.c 4494 2005-02-18 02:18:11Z mike $" + * + * Option marking routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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: mark.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/cups/md5-apple.h b/cups/md5-apple.h new file mode 100644 index 000000000..d4770ccd1 --- /dev/null +++ b/cups/md5-apple.h @@ -0,0 +1,39 @@ +/* + * "$Id: md5-apple.h 4695 2005-09-23 17:07:14Z mike $" + * + * MD5 MacOS X compatibility header for the Common UNIX Printing + * System (CUPS). + * + * This file just defines aliases to the (private) CUPS MD5 functions. + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +void md5_init(_cups_md5_state_t *pms) + { _cups_md5_init(pms); } +void md5_append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes) + { _cups_md5_append(pms, data, nbytes); } +void md5_finish(_cups_md5_state_t *pms, unsigned char digest[16]) + { _cups_md5_finish(pms, digest); } + +/* + * End of "$Id: md5-apple.h 4695 2005-09-23 17:07:14Z mike $". + */ diff --git a/cups/md5.c b/cups/md5.c new file mode 100644 index 000000000..a0469408c --- /dev/null +++ b/cups/md5.c @@ -0,0 +1,344 @@ +/* + Copyright 2005 by Easy Software Products + + This source file implements private APIs and should not be used in + CUPS-based applications. + + 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: md5.c 4695 2005-09-23 17:07:14Z mike $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include "string.h" +#ifdef __APPLE__ +# include "md5-apple.h" +#endif /* __APPLE__ */ + +#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 +_cups_md5_process(_cups_md5_state_t *pms, const unsigned char *data /*[64]*/) +{ + unsigned int + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + unsigned int 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.) + */ + unsigned int X[16]; + const unsigned char *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. + */ + unsigned int xbuf[16]; + const unsigned int *X; + + if (!((data - (const unsigned char *)0) & 3)) { + /* data are properly aligned */ + X = (const unsigned int *)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 +_cups_md5_init(_cups_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 +_cups_md5_append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes) +{ + const unsigned char *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + unsigned int nbits = (unsigned int)(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; + _cups_md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + _cups_md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +_cups_md5_finish(_cups_md5_state_t *pms, unsigned char digest[16]) +{ + static const unsigned char 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 + }; + unsigned char data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (unsigned char)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + _cups_md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + _cups_md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (unsigned char)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/cups/md5.h b/cups/md5.h new file mode 100644 index 000000000..72b338b50 --- /dev/null +++ b/cups/md5.h @@ -0,0 +1,74 @@ +/* + Copyright 2005 by Easy Software Products + + This header file defines private APIs and should not be used in + CUPS-based applications. + + 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: md5.h 4512 2005-05-12 19:47:56Z mike $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321. + It is derived directly from the text of the RFC and not from the + reference implementation. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef _CUPS_MD5_H_ +# define _CUPS_MD5_H_ + +/* Define the state of the MD5 Algorithm. */ +typedef struct _cups_md5_state_s { + unsigned int count[2]; /* message length in bits, lsw first */ + unsigned int abcd[4]; /* digest buffer */ + unsigned char buf[64]; /* accumulate block */ +} _cups_md5_state_t; + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +/* Initialize the algorithm. */ +void _cups_md5_init(_cups_md5_state_t *pms); + +/* Append a string to the message. */ +void _cups_md5_append(_cups_md5_state_t *pms, const unsigned char *data, int nbytes); + +/* Finish the message and return the digest. */ +void _cups_md5_finish(_cups_md5_state_t *pms, unsigned char digest[16]); + +# ifdef __cplusplus +} /* end extern "C" */ +# endif /* __cplusplus */ +#endif /* !_CUPS_MD5_H_ */ diff --git a/cups/md5passwd.c b/cups/md5passwd.c new file mode 100644 index 000000000..1b9029a29 --- /dev/null +++ b/cups/md5passwd.c @@ -0,0 +1,151 @@ +/* + * "$Id: md5passwd.c 4828 2005-11-11 12:53:38Z mike $" + * + * MD5 password support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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 */ +{ + _cups_md5_state_t state; /* MD5 state info */ + unsigned char 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); + _cups_md5_init(&state); + _cups_md5_append(&state, (unsigned char *)line, (int)strlen(line)); + _cups_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 */ +{ + _cups_md5_state_t state; /* MD5 state info */ + unsigned char 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); + _cups_md5_init(&state); + _cups_md5_append(&state, (unsigned char *)line, (int)strlen(line)); + _cups_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); + + _cups_md5_init(&state); + _cups_md5_append(&state, (unsigned char *)line, (int)strlen(line)); + _cups_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 unsigned char *sum, /* I - MD5 sum data */ + char md5[33]) + /* O - MD5 sum in hex */ +{ + int i; /* Looping var */ + char *md5ptr; /* Pointer into MD5 string */ + static const 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: md5passwd.c 4828 2005-11-11 12:53:38Z mike $". + */ diff --git a/cups/normalize.c b/cups/normalize.c new file mode 100644 index 000000000..cbeb3daae --- /dev/null +++ b/cups/normalize.c @@ -0,0 +1,2177 @@ +/* + * "$Id: normalize.c 4903 2006-01-10 20:02:46Z mike $" + * + * Unicode normalization for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are + * the property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the + * file "LICENSE.txt" which should have been included with this file. + * If this file is missing or damaged please contact Easy Software + * Products at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsNormalizeMapsGet() - Get all norm maps to cache. + * cupsNormalizeMapsFree() - Free all norm maps in cache. + * cupsNormalizeMapsFlush() - Flush all norm maps in cache. + * cupsUTF8Normalize() - Normalize UTF-8 string. + * cupsUTF32Normalize() - Normalize UTF-32 string. + * cupsUTF8CaseFold() - Case fold UTF-8 string. + * cupsUTF32CaseFold() - Case fold UTF-32 string. + * cupsUTF8CompareCaseless() - Compare case folded UTF-8 strings. + * cupsUTF32CompareCaseless() - Compare case folded UTF-32 strings. + * cupsUTF8CompareIdentifier() - Compare folded NFKC UTF-8 strings. + * cupsUTF32CompareIdentifier() - Compare folded NFKC UTF-32 strings. + * cupsUTF32CharacterProperty() - Get UTF-32 character property. + * get_general_category() - Get UTF-32 Char General Category. + * get_bidi_category() - Get UTF-32 Char Bidi Category. + * get_combining_class() - Get UTF-32 Char Combining Class. + * get_break_class() - Get UTF-32 Char Line Break Class. + * get_map_count() - Count lines in a map file. + * get_normmap() - Get Unicode norm map to cache. + * get_foldmap() - Get Unicode casefold map to cache. + * get_propmap() - Get Unicode property map to cache. + * get_combmap() - Get Unicode combining map to cache. + * get_breakmap() - Get Unicode break map to cache. + * compare_compose() - Compare key for compose match. + * compare_decompose() - Compare key for decompose match. + * compare_foldchar() - Compare key for case fold match. + * compare_combchar() - Compare key for combining match. + * compare_breakchar() - Compare key for line break match. + * compare_propchar() - Compare key for property char match. + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include "debug.h" +#include +#include +#include + + +typedef struct /**** General Category Index Struct****/ +{ + cups_gencat_t gencat; /* General Category Value */ + const char *str; /* General Category String */ +} gencat_t; + +static const gencat_t gencat_index[] = /* General Category Index */ +{ + { CUPS_GENCAT_LU, "Lu" }, /* Letter, Uppercase */ + { CUPS_GENCAT_LL, "Ll" }, /* Letter, Lowercase */ + { CUPS_GENCAT_LT, "Lt" }, /* Letter, Titlecase */ + { CUPS_GENCAT_LM, "Lm" }, /* Letter, Modifier */ + { CUPS_GENCAT_LO, "Lo" }, /* Letter, Other */ + { CUPS_GENCAT_MN, "Mn" }, /* Mark, Non-Spacing */ + { CUPS_GENCAT_MC, "Mc" }, /* Mark, Spacing Combining */ + { CUPS_GENCAT_ME, "Me" }, /* Mark, Enclosing */ + { CUPS_GENCAT_ND, "Nd" }, /* Number, Decimal Digit */ + { CUPS_GENCAT_NL, "Nl" }, /* Number, Letter */ + { CUPS_GENCAT_NO, "No" }, /* Number, Other */ + { CUPS_GENCAT_PC, "Pc" }, /* Punctuation, Connector */ + { CUPS_GENCAT_PD, "Pd" }, /* Punctuation, Dash */ + { CUPS_GENCAT_PS, "Ps" }, /* Punctuation, Open (start) */ + { CUPS_GENCAT_PE, "Pe" }, /* Punctuation, Close (end) */ + { CUPS_GENCAT_PI, "Pi" }, /* Punctuation, Initial Quote */ + { CUPS_GENCAT_PF, "Pf" }, /* Punctuation, Final Quote */ + { CUPS_GENCAT_PO, "Po" }, /* Punctuation, Other */ + { CUPS_GENCAT_SM, "Sm" }, /* Symbol, Math */ + { CUPS_GENCAT_SC, "Sc" }, /* Symbol, Currency */ + { CUPS_GENCAT_SK, "Sk" }, /* Symbol, Modifier */ + { CUPS_GENCAT_SO, "So" }, /* Symbol, Other */ + { CUPS_GENCAT_ZS, "Zs" }, /* Separator, Space */ + { CUPS_GENCAT_ZL, "Zl" }, /* Separator, Line */ + { CUPS_GENCAT_ZP, "Zp" }, /* Separator, Paragraph */ + { CUPS_GENCAT_CC, "Cc" }, /* Other, Control */ + { CUPS_GENCAT_CF, "Cf" }, /* Other, Format */ + { CUPS_GENCAT_CS, "Cs" }, /* Other, Surrogate */ + { CUPS_GENCAT_CO, "Co" }, /* Other, Private Use */ + { CUPS_GENCAT_CN, "Cn" }, /* Other, Not Assigned */ + { 0, NULL } +}; + +static const char * const bidicat_index[] = + /* Bidi Category Index */ +{ + "L", /* Left-to-Right (Alpha, Syllabic, Ideographic) */ + "LRE", /* Left-to-Right Embedding (explicit) */ + "LRO", /* Left-to-Right Override (explicit) */ + "R", /* Right-to-Left (Hebrew alphabet and most punct) */ + "AL", /* Right-to-Left Arabic (Arabic, Thaana, Syriac) */ + "RLE", /* Right-to-Left Embedding (explicit) */ + "RLO", /* Right-to-Left Override (explicit) */ + "PDF", /* Pop Directional Format */ + "EN", /* Euro Number (Euro and East Arabic-Indic digits) */ + "ES", /* Euro Number Separator (Slash) */ + "ET", /* Euro Number Termintor (Plus, Minus, Degree, etc) */ + "AN", /* Arabic Number (Arabic-Indic digits, separators) */ + "CS", /* Common Number Separator (Colon, Comma, Dot, etc) */ + "NSM", /* Non-Spacing Mark (category Mn / Me in UCD) */ + "BN", /* Boundary Neutral (Formatting / Control chars) */ + "B", /* Paragraph Separator */ + "S", /* Segment Separator (Tab) */ + "WS", /* Whitespace Space (Space, Line Separator, etc) */ + "ON", /* Other Neutrals */ + NULL +}; + +typedef struct /**** Line Break Class Index Struct****/ +{ + cups_break_class_t breakclass; /* Line Break Class Value */ + const char *str; /* Line Break Class String */ +} _cups_break_t; + +static const _cups_break_t break_index[] = /* Line Break Class Index */ +{ + { CUPS_BREAK_AI, "AI" }, /* Ambiguous (Alphabetic or Ideograph) */ + { CUPS_BREAK_AL, "AL" }, /* Ordinary Alpha/Symbol Chars (XP) */ + { CUPS_BREAK_BA, "BA" }, /* Break Opportunity After Chars (A) */ + { CUPS_BREAK_BB, "BB" }, /* Break Opportunities Before Chars (B) */ + { CUPS_BREAK_B2, "B2" }, /* Break Opportunity Either (B/A/XP) */ + { CUPS_BREAK_BK, "BK" }, /* Mandatory Break (A) (norm) */ + { CUPS_BREAK_CB, "CB" }, /* Contingent Break (B/A) (norm) */ + { CUPS_BREAK_CL, "CL" }, /* Closing Punctuation (XB) */ + { CUPS_BREAK_CM, "CM" }, /* Attached/Combining (XB) (norm) */ + { CUPS_BREAK_CR, "CR" }, /* Carriage Return (A) (norm) */ + { CUPS_BREAK_EX, "EX" }, /* Exclamation / Interrogation (XB) */ + { CUPS_BREAK_GL, "GL" }, /* Non-breaking ("Glue") (XB/XA) (norm) */ + { CUPS_BREAK_HY, "HY" }, /* Hyphen (XA) */ + { CUPS_BREAK_ID, "ID" }, /* Ideographic (B/A) */ + { CUPS_BREAK_IN, "IN" }, /* Inseparable chars (XP) */ + { CUPS_BREAK_IS, "IS" }, /* Numeric Separator (Infix) (XB) */ + { CUPS_BREAK_LF, "LF" }, /* Line Feed (A) (norm) */ + { CUPS_BREAK_NS, "NS" }, /* Non-starters (XB) */ + { CUPS_BREAK_NU, "NU" }, /* Numeric (XP) */ + { CUPS_BREAK_OP, "OP" }, /* Opening Punctuation (XA) */ + { CUPS_BREAK_PO, "PO" }, /* Postfix (Numeric) (XB) */ + { CUPS_BREAK_PR, "PR" }, /* Prefix (Numeric) (XA) */ + { CUPS_BREAK_QU, "QU" }, /* Ambiguous Quotation (XB/XA) */ + { CUPS_BREAK_SA, "SA" }, /* Context Dependent (SE Asian) (P) */ + { CUPS_BREAK_SG, "SG" }, /* Surrogates (XP) (norm) */ + { CUPS_BREAK_SP, "SP" }, /* Space (A) (norm) */ + { CUPS_BREAK_SY, "SY" }, /* Symbols Allowing Break After (A) */ + { CUPS_BREAK_XX, "XX" }, /* Unknown (XP) */ + { CUPS_BREAK_ZW, "ZW" }, /* Zero Width Space (A) (norm) */ + { 0, NULL } +}; + +/* + * Prototypes... + */ + +static int compare_breakchar(const void *k1, const void *k2); +static int compare_combchar(const void *k1, const void *k2); +static int compare_compose(const void *k1, const void *k2); +static int compare_decompose(const void *k1, const void *k2); +static int compare_foldchar(const void *k1, const void *k2); +static int compare_propchar(const void *k1, const void *k2); +static int get_bidi_category(const cups_utf32_t ch); +static int get_break_class(const cups_utf32_t ch); +static int get_breakmap(void); +static int get_combining_class(const cups_utf32_t ch); +static int get_combmap(void); +static int get_foldmap(const cups_folding_t fold); +static int get_general_category(const cups_utf32_t ch); +static int get_map_count(const char *filename); +static int get_normmap(const cups_normalize_t normalize); +static int get_propmap(void); + + +/* + * 'cupsNormalizeMapsGet()' - Get all normalization maps to cache. + */ + +int /* O - Zero or -1 on error */ +cupsNormalizeMapsGet(void) +{ + _cups_norm_map_t *nmap; /* Unicode Normalization Map */ + _cups_fold_map_t *fmap; /* Unicode Case Folding Map */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * See if we already have normalization maps loaded... + */ + + if (cg->normmap_cache) + { + for (nmap = cg->normmap_cache; nmap != NULL; nmap = nmap->next) + nmap->used ++; + + for (fmap = cg->foldmap_cache; fmap != NULL; fmap = fmap->next) + fmap->used ++; + + if (cg->combmap_cache) + cg->combmap_cache->used ++; + + if (cg->propmap_cache) + cg->propmap_cache->used ++; + + if (cg->breakmap_cache) + cg->breakmap_cache->used ++; + + return (0); + } + + /* + * Get normalization maps... + */ + + if (get_normmap(CUPS_NORM_NFD) < 0) + return (-1); + + if (get_normmap(CUPS_NORM_NFKD) < 0) + return (-1); + + if (get_normmap(CUPS_NORM_NFC) < 0) + return (-1); + + /* + * Get case folding, combining class, character property maps... + */ + + if (get_foldmap(CUPS_FOLD_SIMPLE) < 0) + return (-1); + + if (get_foldmap(CUPS_FOLD_FULL) < 0) + return (-1); + + if (get_propmap() < 0) + return (-1); + + if (get_combmap() < 0) + return (-1); + + if (get_breakmap() < 0) + return (-1); + + return (0); +} + + +/* + * 'cupsNormalizeMapsFree()' - Free all normalization maps in cache. + * + * This does not actually free; use 'cupsNormalizeMapsFlush()' for that. + */ + +int /* O - Zero or -1 on error */ +cupsNormalizeMapsFree(void) +{ + _cups_norm_map_t *nmap; /* Unicode Normalization Map */ + _cups_fold_map_t *fmap; /* Unicode Case Folding Map */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * See if we already have normalization maps loaded... + */ + + if (cg->normmap_cache == NULL) + return (-1); + + for (nmap = cg->normmap_cache; nmap != NULL; nmap = nmap->next) + if (nmap->used > 0) + nmap->used --; + + for (fmap = cg->foldmap_cache; fmap != NULL; fmap = fmap->next) + if (fmap->used > 0) + fmap->used --; + + if (cg->propmap_cache && (cg->propmap_cache->used > 0)) + cg->propmap_cache->used --; + + if (cg->combmap_cache && (cg->combmap_cache->used > 0)) + cg->combmap_cache->used --; + + if (cg->breakmap_cache && (cg->breakmap_cache->used > 0)) + cg->breakmap_cache->used --; + + return (0); +} + + +/* + * 'cupsNormalizeMapsFlush()' - Flush all normalization maps in cache. + */ + +void +cupsNormalizeMapsFlush(void) +{ + _cups_norm_map_t *nmap; /* Unicode Normalization Map */ + _cups_norm_map_t *nextnorm; /* Next Unicode Normalization Map */ + _cups_fold_map_t *fmap; /* Unicode Case Folding Map */ + _cups_fold_map_t *nextfold; /* Next Unicode Case Folding Map */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Flush all normalization maps... + */ + + for (nmap = cg->normmap_cache; nmap != NULL; nmap = nextnorm) + { + free(nmap->uni2norm); + nextnorm = nmap->next; + free(nmap); + } + + cg->normmap_cache = NULL; + + for (fmap = cg->foldmap_cache; fmap != NULL; fmap = nextfold) + { + free(fmap->uni2fold); + nextfold = fmap->next; + free(fmap); + } + + cg->foldmap_cache = NULL; + + if (cg->propmap_cache) + { + free(cg->propmap_cache->uni2prop); + free(cg->propmap_cache); + cg->propmap_cache = NULL; + } + + if (cg->combmap_cache) + { + free(cg->combmap_cache->uni2comb); + free(cg->combmap_cache); + cg->combmap_cache = NULL; + } + + if (cg->breakmap_cache) + { + free(cg->breakmap_cache->uni2break); + free(cg->breakmap_cache); + cg->breakmap_cache = NULL; + } +} + + +/* + * 'cupsUTF8Normalize()' - Normalize UTF-8 string. + * + * Normalize UTF-8 string to Unicode UAX-15 Normalization Form + * Note - Compatibility Normalization Forms (NFKD/NFKC) are + * unsafe for subsequent transcoding to legacy charsets + */ + +int /* O - Count or -1 on error */ +cupsUTF8Normalize( + cups_utf8_t *dest, /* O - Target string */ + const cups_utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_normalize_t normalize) /* I - Normalization */ +{ + int len; /* String length */ + cups_utf32_t work1[CUPS_MAX_USTRING];/* First internal UCS-4 string */ + cups_utf32_t work2[CUPS_MAX_USTRING];/* Second internal UCS-4 string */ + + + /* + * Check for valid arguments and clear output... + */ + + if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING) + return (-1); + + *dest = 0; + + /* + * Convert input UTF-8 to internal UCS-4 (and insert BOM)... + */ + + len = cupsUTF8ToUTF32(work1, src, CUPS_MAX_USTRING); + + if (len < 0) + return (-1); + + /* + * Normalize internal UCS-4 to second internal UCS-4... + */ + + len = cupsUTF32Normalize(work2, work1, CUPS_MAX_USTRING, normalize); + + if (len < 0) + return (-1); + + /* + * Convert internal UCS-4 to output UTF-8 (and delete BOM)... + */ + + len = cupsUTF32ToUTF8(dest, work2, maxout); + + return (len); +} + + +/* + * 'cupsUTF32Normalize()' - Normalize UTF-32 string. + * + * Normalize UTF-32 string to Unicode UAX-15 Normalization Form + * Note - Compatibility Normalization Forms (NFKD/NFKC) are + * unsafe for subsequent transcoding to legacy charsets + */ + +int /* O - Count or -1 on error */ +cupsUTF32Normalize( + cups_utf32_t *dest, /* O - Target string */ + const cups_utf32_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_normalize_t normalize) /* I - Normalization */ +{ + int i; /* Looping variable */ + int result; /* Result Value */ + cups_ucs2_t *mp; /* Map char pointer */ + int pass; /* Pass count for each transform */ + int hit; /* Hit count from binary search */ + cups_utf32_t unichar1; /* Unicode character value */ + cups_utf32_t unichar2; /* Unicode character value */ + _cups_comb_class_t class1; /* First Combining Class */ + _cups_comb_class_t class2; /* Second Combining Class */ + int len; /* String length */ + cups_utf32_t work1[CUPS_MAX_USTRING]; + /* First internal UCS-4 string */ + cups_utf32_t work2[CUPS_MAX_USTRING]; + /* Second internal UCS-4 string */ + cups_utf32_t *p1; /* First UCS-4 string pointer */ + cups_utf32_t *p2; /* Second UCS-4 string pointer */ + _cups_norm_map_t *nmap; /* Unicode Normalization Map */ + cups_normalize_t decompose; /* Decomposition Type */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Check for valid arguments and clear output... + */ + + if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING) + return (-1); + + *dest = 0; + + result = cupsNormalizeMapsGet(); + + if (result < 0) + return (-1); + + /* + * Find decomposition map... + */ + + switch (normalize) + { + case CUPS_NORM_NFD: + case CUPS_NORM_NFC: + decompose = CUPS_NORM_NFD; + break; + + case CUPS_NORM_NFKD: + case CUPS_NORM_NFKC: + decompose = CUPS_NORM_NFKD; + break; + + default: + return (-1); + } + + for (nmap = cg->normmap_cache; nmap != NULL; nmap = nmap->next) + if (nmap->normalize == decompose) + break; + + if (nmap == NULL) + return (-1); + + /* + * Copy input to internal buffer... + */ + + p1 = &work1[0]; + + for (i = 0; i < CUPS_MAX_USTRING; i ++) + { + if (*src == 0) + break; + + *p1 ++ = *src ++; + } + + *p1 = 0; + len = i; + + /* + * Decompose until no further decomposition... + */ + + for (pass = 0; pass < 20; pass ++) + { + p1 = &work1[0]; + p2 = &work2[0]; + + for (hit = 0; *p1 != 0; p1 ++) + { + /* + * Check for decomposition defined... + */ + + mp = (cups_ucs2_t *)bsearch(p1, nmap->uni2norm, nmap->normcount, + (sizeof(cups_ucs2_t) * 3), compare_decompose); + if (mp == NULL) + { + *p2 ++ = *p1; + continue; + } + + /* + * Decompose input character to one or two output characters... + */ + + hit ++; + mp ++; + *p2 ++ = (cups_utf32_t) *mp ++; + + if (*mp != 0) + *p2 ++ = (cups_utf32_t) *mp; + } + + *p2 = 0; + len = (int)(p2 - &work2[0]); + + /* + * Check for decomposition finished... + */ + if (hit == 0) + break; + memcpy (work1, work2, sizeof(cups_utf32_t) * (len + 1)); + } + + /* + * Canonical reorder until no further reordering... + */ + + for (pass = 0; pass < 20; pass ++) + { + p1 = &work1[0]; + + for (hit = 0; *p1 != 0; p1 ++) + { + /* + * Check for combining characters to reorder... + */ + + unichar1 = *p1; + unichar2 = *(p1 + 1); + + if (unichar2 == 0) + break; + + class1 = get_combining_class(unichar1); + class2 = get_combining_class(unichar2); + + if ((class1 < 0) || (class2 < 0)) + return (-1); + + if ((class1 == 0) || (class2 == 0)) + continue; + + if (class1 <= class2) + continue; + + /* + * Swap two combining characters... + */ + + *p1 = unichar2; + p1 ++; + *p1 = unichar1; + hit ++; + } + + if (hit == 0) + break; + } + + /* + * Check for decomposition only... + */ + + if (normalize == CUPS_NORM_NFD || normalize == CUPS_NORM_NFKD) + { + memcpy(dest, work1, sizeof(cups_utf32_t) * (len + 1)); + return (len); + } + + /* + * Find composition map... + */ + + for (nmap = cg->normmap_cache; nmap != NULL; nmap = nmap->next) + if (nmap->normalize == CUPS_NORM_NFC) + break; + + if (nmap == NULL) + return (-1); + + /* + * Compose until no further composition... + */ + + for (pass = 0; pass < 20; pass ++) + { + p1 = &work1[0]; + p2 = &work2[0]; + + for (hit = 0; *p1 != 0; p1 ++) + { + /* + * Check for composition defined... + */ + + unichar1 = *p1; + unichar2 = *(p1 + 1); + + if (unichar2 == 0) + { + *p2 ++ = unichar1; + break; + } + + mp = (cups_ucs2_t *)bsearch(p1, nmap->uni2norm, nmap->normcount, + (sizeof(cups_ucs2_t) * 3), compare_compose); + if (mp == NULL) + { + *p2 ++ = *p1; + continue; + } + + /* + * Compose two input characters to one output character... + */ + + hit ++; + mp += 2; + *p2 ++ = (cups_utf32_t) *mp; + p1 ++; + } + + *p2 = 0; + len = (int) (p2 - &work2[0]); + + /* + * Check for composition finished... + */ + + if (hit == 0) + break; + + memcpy (work1, work2, sizeof(cups_utf32_t) * (len + 1)); + } + + memcpy (dest, work1, sizeof(cups_utf32_t) * (len + 1)); + + cupsNormalizeMapsFree(); + + return (len); +} + + +/* + * 'cupsUTF8CaseFold()' - Case fold UTF-8 string. + * + * Case Fold UTF-8 string per Unicode UAX-21 Section 2.3 + * Note - Case folding output is + * unsafe for subsequent transcoding to legacy charsets + */ + +int /* O - Count or -1 on error */ +cupsUTF8CaseFold( + cups_utf8_t *dest, /* O - Target string */ + const cups_utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_folding_t fold) /* I - Fold Mode */ +{ + int len; /* String length */ + cups_utf32_t work1[CUPS_MAX_USTRING];/* First internal UCS-4 string */ + cups_utf32_t work2[CUPS_MAX_USTRING];/* Second internal UCS-4 string */ + + + /* + * Check for valid arguments and clear output... + */ + + if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING) + return (-1); + + *dest = 0; + + if (fold != CUPS_FOLD_SIMPLE && fold != CUPS_FOLD_FULL) + return (-1); + + /* + * Convert input UTF-8 to internal UCS-4 (and insert BOM)... + */ + + len = cupsUTF8ToUTF32(work1, src, CUPS_MAX_USTRING); + + if (len < 0) + return (-1); + + /* + * Case Fold internal UCS-4 to second internal UCS-4... + */ + + len = cupsUTF32CaseFold(work2, work1, CUPS_MAX_USTRING, fold); + + if (len < 0) + return (-1); + + /* + * Convert internal UCS-4 to output UTF-8 (and delete BOM)... + */ + + len = cupsUTF32ToUTF8(dest, work2, maxout); + + return (len); +} + + +/* + * 'cupsUTF32CaseFold()' - Case fold UTF-32 string. + * + * Case Fold UTF-32 string per Unicode UAX-21 Section 2.3 + * Note - Case folding output is + * unsafe for subsequent transcoding to legacy charsets + */ + +int /* O - Count or -1 on error */ +cupsUTF32CaseFold( + cups_utf32_t *dest, /* O - Target string */ + const cups_utf32_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_folding_t fold) /* I - Fold Mode */ +{ + cups_utf32_t *start = dest; /* Start of destination string */ + int i; /* Looping variable */ + int result; /* Result Value */ + cups_ucs2_t *mp; /* Map char pointer */ + _cups_fold_map_t *fmap; /* Unicode Case Folding Map */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Check for valid arguments and clear output... + */ + + if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING) + return (-1); + + *dest = 0; + + if (fold != CUPS_FOLD_SIMPLE && fold != CUPS_FOLD_FULL) + return (-1); + + /* + * Find case folding map... + */ + + result = cupsNormalizeMapsGet(); + + if (result < 0) + return (-1); + + for (fmap = cg->foldmap_cache; fmap != NULL; fmap = fmap->next) + if (fmap->fold == fold) + break; + + if (fmap == NULL) + return (-1); + + /* + * Case fold input string to output string... + */ + + for (i = 0; i < (maxout - 1); i ++, src ++) + { + /* + * Check for case folding defined... + */ + + mp = (cups_ucs2_t *)bsearch(src, fmap->uni2fold, fmap->foldcount, + (sizeof(cups_ucs2_t) * 4), compare_foldchar); + if (mp == NULL) + { + *dest ++ = *src; + continue; + } + + /* + * Case fold input character to one or two output characters... + */ + + mp ++; + *dest ++ = (cups_utf32_t) *mp ++; + + if (*mp != 0 && fold == CUPS_FOLD_FULL) + { + i ++; + if (i >= (maxout - 1)) + break; + + *dest ++ = (cups_utf32_t) *mp; + } + } + + *dest = 0; + + cupsNormalizeMapsFree(); + + return ((int)(dest - start)); +} + + +/* + * 'cupsUTF8CompareCaseless()' - Compare case folded UTF-8 strings. + */ + +int /* O - Difference of strings */ +cupsUTF8CompareCaseless( + const cups_utf8_t *s1, /* I - String1 */ + const cups_utf8_t *s2) /* I - String2 */ +{ + int difference; /* Difference of two strings */ + int len; /* String length */ + cups_utf32_t work1[CUPS_MAX_USTRING];/* First internal UCS-4 string */ + cups_utf32_t work2[CUPS_MAX_USTRING];/* Second internal UCS-4 string */ + + + /* + * Check for valid arguments... + */ + + if (!s1 || !s2) + return (-1); + + /* + * Convert input UTF-8 to internal UCS-4 (and insert BOM)... + */ + + len = cupsUTF8ToUTF32(work1, s1, CUPS_MAX_USTRING); + + if (len < 0) + return (-1); + + len = cupsUTF8ToUTF32(work2, s2, CUPS_MAX_USTRING); + + if (len < 0) + return (-1); + + /* + * Compare first internal UCS-4 to second internal UCS-4... + */ + + difference = cupsUTF32CompareCaseless(work1, work2); + + return (difference); +} + + +/* + * 'cupsUTF32CompareCaseless()' - Compare case folded UTF-32 strings. + */ + +int /* O - Difference of strings */ +cupsUTF32CompareCaseless( + const cups_utf32_t *s1, /* I - String1 */ + const cups_utf32_t *s2) /* I - String2 */ +{ + int difference; /* Difference of two strings */ + int len; /* String length */ + cups_folding_t fold = CUPS_FOLD_FULL; + /* Case folding mode */ + cups_utf32_t fold1[CUPS_MAX_USTRING]; + /* First UCS-4 folded string */ + cups_utf32_t fold2[CUPS_MAX_USTRING]; + /* Second UCS-4 folded string */ + cups_utf32_t *p1; /* First UCS-4 string pointer */ + cups_utf32_t *p2; /* Second UCS-4 string pointer */ + + + /* + * Check for valid arguments... + */ + + if (!s1 || !s2) + return (-1); + + /* + * Case Fold input UTF-32 strings to internal UCS-4 strings... + */ + + len = cupsUTF32CaseFold(fold1, s1, CUPS_MAX_USTRING, fold); + + if (len < 0) + return (-1); + + len = cupsUTF32CaseFold(fold2, s2, CUPS_MAX_USTRING, fold); + + if (len < 0) + return (-1); + + /* + * Compare first internal UCS-4 to second internal UCS-4... + */ + + p1 = &fold1[0]; + p2 = &fold2[0]; + + for (;; p1 ++, p2 ++) + { + difference = (int) (*p1 - *p2); + + if (difference != 0) + break; + + if ((*p1 == 0) && (*p2 == 0)) + break; + } + + return (difference); +} + + +/* + * 'cupsUTF8CompareIdentifier()' - Compare folded NFKC UTF-8 strings. + */ + +int /* O - Result of comparison */ +cupsUTF8CompareIdentifier( + const cups_utf8_t *s1, /* I - String1 */ + const cups_utf8_t *s2) /* I - String2 */ +{ + int difference; /* Difference of two strings */ + int len; /* String length */ + cups_utf32_t work1[CUPS_MAX_USTRING];/* First internal UCS-4 string */ + cups_utf32_t work2[CUPS_MAX_USTRING];/* Second internal UCS-4 string */ + + + /* + * Check for valid arguments... + */ + + if (!s1 || !s2) + return (-1); + + /* + * Convert input UTF-8 to internal UCS-4 (and insert BOM)... + */ + + len = cupsUTF8ToUTF32(work1, s1, CUPS_MAX_USTRING); + + if (len < 0) + return (-1); + + len = cupsUTF8ToUTF32(work2, s2, CUPS_MAX_USTRING); + + if (len < 0) + return (-1); + + /* + * Compare first internal UCS-4 to second internal UCS-4... + */ + + difference = cupsUTF32CompareIdentifier(work1, work2); + + return (difference); +} + + +/* + * 'cupsUTF32CompareIdentifier()' - Compare folded NFKC UTF-32 strings. + */ + +int /* O - Result of comparison */ +cupsUTF32CompareIdentifier( + const cups_utf32_t *s1, /* I - String1 */ + const cups_utf32_t *s2) /* I - String2 */ +{ + int difference; /* Difference of two strings */ + int len; /* String length */ + cups_folding_t fold = CUPS_FOLD_FULL; + /* Case folding mode */ + cups_utf32_t fold1[CUPS_MAX_USTRING]; + /* First UCS-4 folded string */ + cups_utf32_t fold2[CUPS_MAX_USTRING]; + /* Second UCS-4 folded string */ + cups_normalize_t normalize = CUPS_NORM_NFKC; + /* Normalization form */ + cups_utf32_t norm1[CUPS_MAX_USTRING]; + /* First UCS-4 normalized string */ + cups_utf32_t norm2[CUPS_MAX_USTRING]; + /* Second UCS-4 normalized string */ + cups_utf32_t *p1; /* First UCS-4 string pointer */ + cups_utf32_t *p2; /* Second UCS-4 string pointer */ + + + /* + * Check for valid arguments... + */ + + if (!s1 || !s2) + return (-1); + + /* + * Case Fold input UTF-32 strings to internal UCS-4 strings... + */ + + len = cupsUTF32CaseFold(fold1, s1, CUPS_MAX_USTRING, fold); + + if (len < 0) + return (-1); + + len = cupsUTF32CaseFold(fold2, s2, CUPS_MAX_USTRING, fold); + + if (len < 0) + return (-1); + + /* + * Normalize internal UCS-4 strings to NFKC... + */ + + len = cupsUTF32Normalize(norm1, fold1, CUPS_MAX_USTRING, normalize); + + if (len < 0) + return (-1); + + len = cupsUTF32Normalize(norm2, fold2, CUPS_MAX_USTRING, normalize); + + if (len < 0) + return (-1); + + /* + * Compare first internal UCS-4 to second internal UCS-4... + */ + + p1 = &norm1[0]; + p2 = &norm2[0]; + + for (;; p1 ++, p2 ++) + { + difference = (int) (*p1 - *p2); + + if (difference != 0) + break; + + if ((*p1 == 0) && (*p2 == 0)) + break; + } + + return (difference); +} + + +/* + * 'cupsUTF32CharacterProperty()' - Get UTF-32 character property. + */ + +int /* O - Result of comparison */ +cupsUTF32CharacterProperty( + const cups_utf32_t ch, /* I - Source char */ + const cups_property_t prop) /* I - Char Property */ +{ + int result; /* Result Value */ + + + /* + * Check for valid arguments... + */ + + if (ch == 0) + return (-1); + + /* + * Find character property... + */ + + switch (prop) + { + case CUPS_PROP_GENERAL_CATEGORY: + result = (get_general_category(ch)); + break; + + case CUPS_PROP_BIDI_CATEGORY: + result = (get_bidi_category(ch)); + break; + + case CUPS_PROP_COMBINING_CLASS: + result = (get_combining_class(ch)); + break; + case CUPS_PROP_BREAK_CLASS: + result = (get_break_class(ch)); + break; + + default: + return (-1); + } + + return (result); +} + + +/* + * 'get_general_category()' - Get UTF-32 Character General Category. + */ + +static int /* O - Class or -1 on error */ +get_general_category( + const cups_utf32_t ch) /* I - Source char */ +{ + int result; /* Result Value */ + cups_gencat_t gencat; /* General Category Value */ + _cups_prop_map_t *pmap; /* Unicode Property Map */ + _cups_prop_t *uni2prop; /* Unicode Char -> Properties */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Check for valid argument... + */ + + if (ch == 0) + return (-1); + + /* + * Find property map... + */ + + result = cupsNormalizeMapsGet(); + + if (result < 0) + return (-1); + + pmap = cg->propmap_cache; + + if (pmap == NULL) + return (-1); + + /* + * Find character in map... + */ + + uni2prop = (_cups_prop_t *)bsearch(&ch, pmap->uni2prop, pmap->propcount, + (sizeof(_cups_prop_t)), compare_propchar); + + cupsNormalizeMapsFree(); + + if (uni2prop == NULL) + gencat = CUPS_GENCAT_CN; /* Other, Not Assigned */ + else + gencat = (cups_gencat_t)uni2prop->gencat; + + result = (int)gencat; + + return (result); +} + + +/* + * 'get_bidi_category()' - Get UTF-32 Character Bidi Category. + */ + +static int /* O - Class or -1 on error */ +get_bidi_category(const cups_utf32_t ch)/* I - Source char */ +{ + int result; /* Result Value */ + cups_bidi_t bidicat; /* Bidi Category Value */ + _cups_prop_map_t *pmap; /* Unicode Property Map */ + _cups_prop_t *uni2prop; /* Unicode Char -> Properties */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Check for valid argument... + */ + + if (ch == 0) + return (-1); + + /* + * Find property map... + */ + + result = cupsNormalizeMapsGet(); + + if (result < 0) + return (-1); + + pmap = cg->propmap_cache; + + if (pmap == NULL) + return (-1); + + /* + * Find character in map... + */ + + uni2prop = (_cups_prop_t *)bsearch(&ch, pmap->uni2prop, pmap->propcount, + (sizeof(_cups_prop_t)), compare_propchar); + + cupsNormalizeMapsFree(); + + if (uni2prop == NULL) + bidicat = CUPS_BIDI_ON; /* Other Neutral */ + else + bidicat = (cups_bidi_t)uni2prop->bidicat; + + result = (int)bidicat; + + return (result); +} + +/* + * 'get_combining_class()' - Get UTF-32 Character Combining Class. + * + * Note - Zero is non-combining (base character) + */ + +static int /* O - Class or -1 on error */ +get_combining_class( + const cups_utf32_t ch) /* I - Source char */ +{ + int result; /* Result Value */ + _cups_comb_map_t *cmap; /* Unicode Combining Class Map */ + _cups_comb_class_t combclass; /* Unicode Combining Class */ + _cups_comb_t *uni2comb; /* Unicode Char -> Combining Class */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Check for valid argument... + */ + + if (ch == 0) + return (-1); + + /* + * Find combining class map... + */ + + result = cupsNormalizeMapsGet(); + + if (result < 0) + return (-1); + + cmap = cg->combmap_cache; + + if (cmap == NULL) + return (-1); + + /* + * Find combining character in map... + */ + + uni2comb = (_cups_comb_t *)bsearch(&ch, cmap->uni2comb, cmap->combcount, + (sizeof(_cups_comb_t)), compare_combchar); + + cupsNormalizeMapsFree(); + + if (uni2comb == NULL) + combclass = 0; + else + combclass = (_cups_comb_class_t)uni2comb->combclass; + + result = (int)combclass; + + return (result); +} + + +/* + * 'get_break_class()' - Get UTF-32 Character Line Break Class. + */ + +static int /* O - Class or -1 on error */ +get_break_class(const cups_utf32_t ch) /* I - Source char */ +{ + int result; /* Result Value */ + _cups_break_map_t *bmap; /* Unicode Line Break Class Map */ + cups_break_class_t breakclass; /* Unicode Line Break Class */ + cups_ucs2_t *uni2break; /* Unicode -> Line Break Class */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * Check for valid argument... + */ + + if (ch == 0) + return (-1); + + /* + * Find line break class map... + */ + + result = cupsNormalizeMapsGet(); + + if (result < 0) + return (-1); + + bmap = cg->breakmap_cache; + + if (bmap == NULL) + return (-1); + + /* + * Find line break character in map... + */ + + uni2break = (cups_ucs2_t *)bsearch(&ch, bmap->uni2break, bmap->breakcount, + (sizeof(cups_ucs2_t) * 3), + compare_breakchar); + + cupsNormalizeMapsFree(); + + if (uni2break == NULL) + breakclass = CUPS_BREAK_AI; + else + breakclass = (cups_break_class_t)*(uni2break + 2); + + result = (int)breakclass; + + return (result); +} + + +/* + * 'get_map_count()' - Count lines in a map file. + */ + +static int /* O - Count or -1 on error */ +get_map_count(const char *filename) /* I - Map Filename */ +{ + int i; /* Looping variable */ + cups_file_t *fp; /* Map input file pointer */ + char *s; /* Line parsing pointer */ + char line[256]; /* Line from input map file */ + cups_utf32_t unichar; /* Unicode character value */ + + + /* + * Open map input file... + */ + + if (!filename || !*filename) + return (-1); + + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (-1); + + /* + * Count lines in map input file... + */ + + for (i = 0; i < 50000;) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + if (strncmp (s, "0x", 2) == 0) + s += 2; + if (sscanf(s, "%lx", &unichar) != 1) + break; + if (unichar > 0xffff) + break; + i ++; + } + if (i == 0) + i = -1; + + /* + * Close file and return map count (non-comment line count)... + */ + + cupsFileClose(fp); + + return (i); +} + + +/* + * 'get_normmap()' - Get Unicode normalization map to cache. + */ + +static int /* O - Zero or -1 on error */ +get_normmap( + const cups_normalize_t normalize) /* I - Normalization Form */ +{ + int i; /* Looping variable */ + cups_utf32_t unichar1; /* Unicode character value */ + cups_utf32_t unichar2; /* Unicode character value */ + cups_utf32_t unichar3; /* Unicode character value */ + _cups_norm_map_t *nmap; /* Unicode Normalization Map */ + int normcount; /* Count of Unicode Source Chars */ + cups_ucs2_t *uni2norm; /* Unicode Char -> Normalization */ + char *mapname; /* Normalization map name */ + char filename[1024]; /* Filename for charset map file */ + cups_file_t *fp; /* Normalization map file pointer */ + char *s; /* Line parsing pointer */ + char line[256]; /* Line from input map file */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * See if we already have this normalization map loaded... + */ + + for (nmap = cg->normmap_cache; nmap != NULL; nmap = nmap->next) + if (nmap->normalize == normalize) + return (0); + + /* + * Get the mapping name... + */ + + switch (normalize) + { + case CUPS_NORM_NFD: /* Canonical Decomposition */ + mapname = "uni-nfd.txt"; + break; + + case CUPS_NORM_NFKD: /* Compatibility Decomposition */ + mapname = "uni-nfkd.txt"; + break; + + case CUPS_NORM_NFC: /* Canonical Composition */ + mapname = "uni-nfc.txt"; + break; + + case CUPS_NORM_NFKC: /* no such map file... */ + default: + return (-1); + } + + /* + * Open normalization map input file... + */ + + snprintf(filename, sizeof(filename), "%s/charmaps/%s", + cg->cups_datadir, mapname); + if ((normcount = get_map_count(filename)) <= 0) + return (-1); + + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (-1); + + /* + * Allocate memory for normalization map and add to cache... + */ + + nmap = (_cups_norm_map_t *)calloc(1, sizeof(_cups_norm_map_t)); + if (nmap == NULL) + { + cupsFileClose(fp); + return (-1); + } + + uni2norm = (cups_ucs2_t *)calloc(1, sizeof(cups_ucs2_t) * 3 * normcount); + if (uni2norm == NULL) + { + free(nmap); + cupsFileClose(fp); + return (-1); + } + nmap->next = cg->normmap_cache; + cg->normmap_cache = nmap; + nmap->used ++; + nmap->normalize = normalize; + nmap->normcount = normcount; + nmap->uni2norm = uni2norm; + + /* + * Save normalization map into memory for later use... + */ + for (i = 0; i < normcount; ) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + if (sscanf(s, "%lx %lx %lx", &unichar1, &unichar2, &unichar3) != 3) + break; + if ((unichar1 > 0xffff) + || (unichar2 > 0xffff) + || (unichar3 > 0xffff)) + break; + *uni2norm ++ = (cups_ucs2_t) unichar1; + *uni2norm ++ = (cups_ucs2_t) unichar2; + *uni2norm ++ = (cups_ucs2_t) unichar3; + i ++; + } + if (i < normcount) + nmap->normcount = i; + cupsFileClose(fp); + return (0); +} + + +/* + * 'get_foldmap()' - Get Unicode case folding map to cache. + */ + +static int /* O - Zero or -1 on error */ +get_foldmap(const cups_folding_t fold) /* I - Case folding type */ +{ + int i; /* Looping variable */ + cups_utf32_t unichar1; /* Unicode character value */ + cups_utf32_t unichar2; /* Unicode character value */ + cups_utf32_t unichar3; /* Unicode character value */ + cups_utf32_t unichar4; /* Unicode character value */ + _cups_fold_map_t *fmap; /* Unicode Case Folding Map */ + int foldcount; /* Count of Unicode Source Chars */ + cups_ucs2_t *uni2fold; /* Unicode -> Folded Char(s) */ + char *mapname; /* Case Folding map name */ + char filename[1024]; /* Filename for charset map file */ + cups_file_t *fp; /* Case Folding map file pointer */ + char *s; /* Line parsing pointer */ + char line[256]; /* Line from input map file */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * See if we already have this case folding map loaded... + */ + + for (fmap = cg->foldmap_cache; fmap != NULL; fmap = fmap->next) + if (fmap->fold == fold) + return (0); + + /* + * Get the mapping name... + */ + + switch (fold) + { + case CUPS_FOLD_SIMPLE: /* Simple case folding */ + mapname = "uni-fold.txt"; + break; + case CUPS_FOLD_FULL: /* Full case folding */ + mapname = "uni-full.txt"; + break; + default: + return (-1); + } + + /* + * Open case folding map input file... + */ + + snprintf(filename, sizeof(filename), "%s/charmaps/%s", + cg->cups_datadir, mapname); + if ((foldcount = get_map_count(filename)) <= 0) + return (-1); + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (-1); + + /* + * Allocate memory for case folding map and add to cache... + */ + fmap = (_cups_fold_map_t *)calloc(1, sizeof(_cups_fold_map_t)); + if (fmap == NULL) + { + cupsFileClose(fp); + return (-1); + } + uni2fold = (cups_ucs2_t *)calloc(1, sizeof(cups_ucs2_t) * 4 * foldcount); + if (uni2fold == NULL) + { + free(fmap); + cupsFileClose(fp); + return (-1); + } + fmap->next = cg->foldmap_cache; + cg->foldmap_cache = fmap; + fmap->used ++; + fmap->fold = fold; + fmap->foldcount = foldcount; + fmap->uni2fold = uni2fold; + + /* + * Save case folding map into memory for later use... + */ + + for (i = 0; i < foldcount; ) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + unichar1 = unichar2 = unichar3 = unichar4 = 0; + if ((fold == CUPS_FOLD_SIMPLE) + && (sscanf(s, "%lx %lx", &unichar1, &unichar2) != 2)) + break; + if ((fold == CUPS_FOLD_FULL) + && (sscanf(s, "%lx %lx %lx %lx", + &unichar1, &unichar2, &unichar3, &unichar4) != 4)) + break; + if ((unichar1 > 0xffff) + || (unichar2 > 0xffff) + || (unichar3 > 0xffff) + || (unichar4 > 0xffff)) + break; + *uni2fold ++ = (cups_ucs2_t) unichar1; + *uni2fold ++ = (cups_ucs2_t) unichar2; + *uni2fold ++ = (cups_ucs2_t) unichar3; + *uni2fold ++ = (cups_ucs2_t) unichar4; + i ++; + } + if (i < foldcount) + fmap->foldcount = i; + cupsFileClose(fp); + return (0); +} + +/* + * 'get_propmap()' - Get Unicode character property map to cache. + */ + +static int /* O - Zero or -1 on error */ +get_propmap(void) +{ + int i, j; /* Looping variables */ + size_t len; /* String length */ + cups_utf32_t unichar; /* Unicode character value */ + cups_gencat_t gencat; /* General Category Value */ + cups_bidi_t bidicat; /* Bidi Category Value */ + _cups_prop_map_t *pmap; /* Unicode Char Property Map */ + int propcount; /* Count of Unicode Source Chars */ + _cups_prop_t *uni2prop; /* Unicode Char -> Properties */ + char *mapname; /* Char Property map name */ + char filename[1024]; /* Filename for charset map file */ + cups_file_t *fp; /* Char Property map file pointer */ + char *s; /* Line parsing pointer */ + char line[256]; /* Line from input map file */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * See if we already have this char properties map loaded... + */ + + if ((pmap = cg->propmap_cache) != NULL) + return (0); + + /* + * Get the mapping name... + */ + + mapname = "uni-prop.txt"; + + /* + * Open char properties map input file... + */ + snprintf(filename, sizeof(filename), "%s/charmaps/%s", + cg->cups_datadir, mapname); + if ((propcount = get_map_count(filename)) <= 0) + return (-1); + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (-1); + + /* + * Allocate memory for char properties map and add to cache... + */ + pmap = (_cups_prop_map_t *)calloc(1, sizeof(_cups_prop_map_t)); + if (pmap == NULL) + { + cupsFileClose(fp); + return (-1); + } + uni2prop = (_cups_prop_t *)calloc(1, sizeof(_cups_prop_t) * propcount); + if (uni2prop == NULL) + { + free(pmap); + cupsFileClose(fp); + return (-1); + } + cg->propmap_cache = pmap; + pmap->used ++; + pmap->propcount = propcount; + pmap->uni2prop = uni2prop; + + /* + * Save char properties map into memory for later use... + */ + for (i = 0; i < propcount; ) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if (strlen(s) > 0) + *(s + strlen(s) - 1) = '\0'; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + if (sscanf(s, "%lx", &unichar) != 1) + break; + if (unichar > 0xffff) + break; + while ((*s != '\0') && (*s != ';')) + s ++; + if (*s != ';') + break; + s ++; + for (j = 0; gencat_index[j].str != NULL; j ++) + { + len = strlen(gencat_index[j].str); + if (strncmp (s, gencat_index[j].str, len) == 0) + break; + } + if (gencat_index[j].str == NULL) + return (-1); + gencat = gencat_index[j].gencat; + while ((*s != '\0') && (*s != ';')) + s ++; + if (*s != ';') + break; + s ++; + for (j = 0; bidicat_index[j] != NULL; j ++) + { + len = strlen(bidicat_index[j]); + if (strncmp (s, bidicat_index[j], len) == 0) + break; + } + if (bidicat_index[j] == NULL) + return (-1); + bidicat = (cups_bidi_t) j; + uni2prop->ch = (cups_ucs2_t) unichar; + uni2prop->gencat = (unsigned char) gencat; + uni2prop->bidicat = (unsigned char) bidicat; + uni2prop ++; + i ++; + } + if (i < propcount) + pmap->propcount = i; + cupsFileClose(fp); + return (0); +} + + +/* + * 'get_combmap()' - Get Unicode combining class map to cache. + */ + +static int /* O - Zero or -1 on error */ +get_combmap(void) +{ + int i; /* Looping variable */ + cups_utf32_t unichar; /* Unicode character value */ + int combclass; /* Unicode char combining class */ + _cups_comb_map_t *cmap; /* Unicode Comb Class Map */ + int combcount; /* Count of Unicode Source Chars */ + _cups_comb_t *uni2comb; /* Unicode Char -> Combining Class */ + char *mapname; /* Comb Class map name */ + char filename[1024]; /* Filename for charset map file */ + cups_file_t *fp; /* Comb Class map file pointer */ + char *s; /* Line parsing pointer */ + char line[256]; /* Line from input map file */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * See if we already have this combining class map loaded... + */ + + if ((cmap = cg->combmap_cache) != NULL) + return (0); + + /* + * Get the mapping name... + */ + + mapname = "uni-comb.txt"; + + /* + * Open combining class map input file... + */ + + snprintf(filename, sizeof(filename), "%s/charmaps/%s", + cg->cups_datadir, mapname); + if ((combcount = get_map_count(filename)) <= 0) + return (-1); + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (-1); + + /* + * Allocate memory for combining class map and add to cache... + */ + + cmap = (_cups_comb_map_t *)calloc(1, sizeof(_cups_comb_map_t)); + if (cmap == NULL) + { + cupsFileClose(fp); + return (-1); + } + + uni2comb = (_cups_comb_t *)calloc(1, sizeof(_cups_comb_t) * combcount); + if (uni2comb == NULL) + { + free(cmap); + cupsFileClose(fp); + return (-1); + } + cg->combmap_cache = cmap; + cmap->used ++; + cmap->combcount = combcount; + cmap->uni2comb = uni2comb; + + /* + * Save combining class map into memory for later use... + */ + for (i = 0; i < combcount; ) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + if (sscanf(s, "%lx", &unichar) != 1) + break; + if (unichar > 0xffff) + break; + while ((*s != '\0') && (*s != ';')) + s ++; + if (*s != ';') + break; + s ++; + if (sscanf(s, "%d", &combclass) != 1) + break; + uni2comb->ch = (cups_ucs2_t) unichar; + uni2comb->combclass = (unsigned char) combclass; + uni2comb ++; + i ++; + } + if (i < combcount) + cmap->combcount = i; + cupsFileClose(fp); + return (0); +} + + +/* + * 'get_breakmap()' - Get Unicode line break class map to cache. + */ + +static int /* O - Zero or -1 on error */ +get_breakmap(void) +{ + int i, j; /* Looping variables */ + int len; /* String length */ + cups_utf32_t unichar1; /* Unicode character value */ + cups_utf32_t unichar2; /* Unicode character value */ + cups_break_class_t breakclass; /* Unicode char line break class */ + _cups_break_map_t *bmap; /* Unicode Line Break Class Map */ + int breakcount; /* Count of Unicode Source Chars */ + cups_ucs2_t *uni2break; /* Unicode -> Line Break Class */ + char *mapname; /* Comb Class map name */ + char filename[1024]; /* Filename for charset map file */ + cups_file_t *fp; /* Comb Class map file pointer */ + char *s; /* Line parsing pointer */ + char line[256]; /* Line from input map file */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + + /* + * See if we already have this line break class map loaded... + */ + + if ((bmap = cg->breakmap_cache) != NULL) + return (0); + + /* + * Get the mapping name... + */ + + mapname = "uni-line.txt"; + + /* + * Open line break class map input file... + */ + + snprintf(filename, sizeof(filename), "%s/charmaps/%s", + cg->cups_datadir, mapname); + if ((breakcount = get_map_count(filename)) <= 0) + return (-1); + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (-1); + + /* + * Allocate memory for line break class map and add to cache... + */ + + bmap = (_cups_break_map_t *)calloc(1, sizeof(_cups_break_map_t)); + if (bmap == NULL) + { + cupsFileClose(fp); + return (-1); + } + + uni2break = (cups_ucs2_t *)calloc(1, sizeof(cups_ucs2_t) * 3 * breakcount); + if (uni2break == NULL) + { + free(bmap); + cupsFileClose(fp); + return (-1); + } + cg->breakmap_cache = bmap; + bmap->used ++; + bmap->breakcount = breakcount; + bmap->uni2break = uni2break; + + /* + * Save line break class map into memory for later use... + */ + for (i = 0; i < breakcount; ) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if (strlen(s) > 0) + *(s + strlen(s) - 1) = '\0'; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + if (sscanf(s, "%lx %lx", &unichar1, &unichar2) != 2) + break; + if ((unichar1 > 0xffff) + || (unichar2 > 0xffff)) + break; + while ((*s != '\0') && (*s != ';')) + s ++; + if (*s != ';') + break; + s ++; + for (j = 0; break_index[j].str != NULL; j ++) + { + len = strlen (break_index[j].str); + if (strncmp (s, break_index[j].str, len) == 0) + break; + } + if (break_index[j].str == NULL) + return (-1); + breakclass = break_index[j].breakclass; + *uni2break ++ = (cups_ucs2_t) unichar1; + *uni2break ++ = (cups_ucs2_t) unichar2; + *uni2break ++ = (cups_ucs2_t) breakclass; + i ++; + } + if (i < breakcount) + bmap->breakcount = i; + cupsFileClose(fp); + return (0); +} + + +/* + * 'compare_compose()' - Compare key for compose match. + * + * Note - This function cannot be easily modified for 32-bit Unicode. + */ + +static int /* O - Result of comparison */ +compare_compose(const void *k1, /* I - Key char */ + const void *k2) /* I - Map char */ +{ + cups_utf32_t *kp = (cups_utf32_t *)k1; + /* Key char pointer */ + cups_ucs2_t *mp = (cups_ucs2_t *)k2;/* Map char pointer */ + unsigned long key; /* Pair of key characters */ + unsigned long map; /* Pair of map characters */ + int result; /* Result Value */ + + + key = (*kp << 16); + key |= *(kp + 1); + map = (unsigned long) (*mp << 16); + map |= (unsigned long) *(mp + 1); + + if (key >= map) + result = (int) (key - map); + else + result = -1 * ((int) (map - key)); + + return (result); +} + + +/* + * 'compare_decompose()' - Compare key for decompose match. + */ + +static int /* O - Result of comparison */ +compare_decompose(const void *k1, /* I - Key char */ + const void *k2) /* I - Map char */ +{ + cups_utf32_t *kp = (cups_utf32_t *)k1; + /* Key char pointer */ + cups_ucs2_t *mp = (cups_ucs2_t *)k2;/* Map char pointer */ + cups_ucs2_t ch; /* Key char as UCS-2 */ + int result; /* Result Value */ + + + ch = (cups_ucs2_t) *kp; + + if (ch >= *mp) + result = (int) (ch - *mp); + else + result = -1 * ((int) (*mp - ch)); + + return (result); +} + + +/* + * 'compare_foldchar()' - Compare key for case fold match. + */ + +static int /* O - Result of comparison */ +compare_foldchar(const void *k1, /* I - Key char */ + const void *k2) /* I - Map char */ +{ + cups_utf32_t *kp = (cups_utf32_t *)k1; + /* Key char pointer */ + cups_ucs2_t *mp = (cups_ucs2_t *)k2;/* Map char pointer */ + cups_ucs2_t ch; /* Key char as UCS-2 */ + int result; /* Result Value */ + + + ch = (cups_ucs2_t) *kp; + + if (ch >= *mp) + result = (int) (ch - *mp); + else + result = -1 * ((int) (*mp - ch)); + + return (result); +} + + +/* + * 'compare_combchar()' - Compare key for combining char match. + */ + +static int /* O - Result of comparison */ +compare_combchar(const void *k1, /* I - Key char */ + const void *k2) /* I - Map char */ +{ + cups_utf32_t *kp = (cups_utf32_t *)k1; + /* Key char pointer */ + _cups_comb_t *cp = (_cups_comb_t *)k2;/* Combining map row pointer */ + cups_ucs2_t ch; /* Key char as UCS-2 */ + int result; /* Result Value */ + + + ch = (cups_ucs2_t) *kp; + + if (ch >= cp->ch) + result = (int) (ch - cp->ch); + else + result = -1 * ((int) (cp->ch - ch)); + + return (result); +} + + +/* + * 'compare_breakchar()' - Compare key for line break char match. + */ + +static int /* O - Result of comparison */ +compare_breakchar(const void *k1, /* I - Key char */ + const void *k2) /* I - Map char */ +{ + cups_utf32_t *kp = (cups_utf32_t *)k1; + /* Key char pointer */ + cups_ucs2_t *mp = (cups_ucs2_t *)k2;/* Map char pointer */ + cups_ucs2_t ch; /* Key char as UCS-2 */ + int result; /* Result Value */ + + + ch = (cups_ucs2_t) *kp; + + if (ch < *mp) + result = -1 * (int) (*mp - ch); + else if (ch > *(mp + 1)) + result = (int) (ch - *(mp + 1)); + else + result = 0; + + return (result); +} + + +/* + * 'compare_propchar()' - Compare key for property char match. + */ + +static int /* O - Result of comparison */ +compare_propchar(const void *k1, /* I - Key char */ + const void *k2) /* I - Map char */ +{ + cups_utf32_t *kp = (cups_utf32_t *)k1; + /* Key char pointer */ + _cups_prop_t *pp = (_cups_prop_t *)k2;/* Property map row pointer */ + cups_ucs2_t ch; /* Key char as UCS-2 */ + int result; /* Result Value */ + + + ch = (cups_ucs2_t) *kp; + + if (ch >= pp->ch) + result = (int) (ch - pp->ch); + else + result = -1 * ((int) (pp->ch - ch)); + + return (result); +} + + +/* + * End of "$Id: normalize.c 4903 2006-01-10 20:02:46Z mike $" + */ diff --git a/cups/normalize.h b/cups/normalize.h new file mode 100644 index 000000000..e1a3da82e --- /dev/null +++ b/cups/normalize.h @@ -0,0 +1,334 @@ +/* + * "$Id: normalize.h 4684 2005-09-22 02:15:56Z mike $" + * + * Unicode normalization for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are + * the property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the + * file "LICENSE.txt" which should have been included with this file. + * If this file is missing or damaged please contact Easy Software + * Products at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_NORMALIZE_H_ +# define _CUPS_NORMALIZE_H_ + +/* + * Include necessary headers... + */ + +#include "transcode.h" + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Types... + */ + +typedef enum /**** Normalizataion Types ****/ +{ + CUPS_NORM_NFD, /* Canonical Decomposition */ + CUPS_NORM_NFKD, /* Compatibility Decomposition */ + CUPS_NORM_NFC, /* NFD, them Canonical Composition */ + CUPS_NORM_NFKC /* NFKD, them Canonical Composition */ +} cups_normalize_t; + +typedef enum /**** Case Folding Types ****/ +{ + CUPS_FOLD_SIMPLE, /* Simple - no expansion in size */ + CUPS_FOLD_FULL /* Full - possible expansion in size */ +} cups_folding_t; + +typedef enum /**** Unicode Char Property Types ****/ +{ + CUPS_PROP_GENERAL_CATEGORY, /* See 'cups_gencat_t' enum */ + CUPS_PROP_BIDI_CATEGORY, /* See 'cups_bidi_t' enum */ + CUPS_PROP_COMBINING_CLASS, /* See '_cups_comb_class_t' type */ + CUPS_PROP_BREAK_CLASS /* See 'cups_break_class_t' enum */ +} cups_property_t; + + +/* + * Note - Use major classes for logic optimizations (by mask). + */ + +typedef enum /**** Unicode General Category ****/ +{ + CUPS_GENCAT_L = 0x10, /* Letter major class */ + CUPS_GENCAT_LU = 0x11, /* Lu Letter, Uppercase */ + CUPS_GENCAT_LL = 0x12, /* Ll Letter, Lowercase */ + CUPS_GENCAT_LT = 0x13, /* Lt Letter, Titlecase */ + CUPS_GENCAT_LM = 0x14, /* Lm Letter, Modifier */ + CUPS_GENCAT_LO = 0x15, /* Lo Letter, Other */ + CUPS_GENCAT_M = 0x20, /* Mark major class */ + CUPS_GENCAT_MN = 0x21, /* Mn Mark, Non-Spacing */ + CUPS_GENCAT_MC = 0x22, /* Mc Mark, Spacing Combining */ + CUPS_GENCAT_ME = 0x23, /* Me Mark, Enclosing */ + CUPS_GENCAT_N = 0x30, /* Number major class */ + CUPS_GENCAT_ND = 0x31, /* Nd Number, Decimal Digit */ + CUPS_GENCAT_NL = 0x32, /* Nl Number, Letter */ + CUPS_GENCAT_NO = 0x33, /* No Number, Other */ + CUPS_GENCAT_P = 0x40, /* Punctuation major class */ + CUPS_GENCAT_PC = 0x41, /* Pc Punctuation, Connector */ + CUPS_GENCAT_PD = 0x42, /* Pd Punctuation, Dash */ + CUPS_GENCAT_PS = 0x43, /* Ps Punctuation, Open (start) */ + CUPS_GENCAT_PE = 0x44, /* Pe Punctuation, Close (end) */ + CUPS_GENCAT_PI = 0x45, /* Pi Punctuation, Initial Quote */ + CUPS_GENCAT_PF = 0x46, /* Pf Punctuation, Final Quote */ + CUPS_GENCAT_PO = 0x47, /* Po Punctuation, Other */ + CUPS_GENCAT_S = 0x50, /* Symbol major class */ + CUPS_GENCAT_SM = 0x51, /* Sm Symbol, Math */ + CUPS_GENCAT_SC = 0x52, /* Sc Symbol, Currency */ + CUPS_GENCAT_SK = 0x53, /* Sk Symbol, Modifier */ + CUPS_GENCAT_SO = 0x54, /* So Symbol, Other */ + CUPS_GENCAT_Z = 0x60, /* Separator major class */ + CUPS_GENCAT_ZS = 0x61, /* Zs Separator, Space */ + CUPS_GENCAT_ZL = 0x62, /* Zl Separator, Line */ + CUPS_GENCAT_ZP = 0x63, /* Zp Separator, Paragraph */ + CUPS_GENCAT_C = 0x70, /* Other (miscellaneous) major class */ + CUPS_GENCAT_CC = 0x71, /* Cc Other, Control */ + CUPS_GENCAT_CF = 0x72, /* Cf Other, Format */ + CUPS_GENCAT_CS = 0x73, /* Cs Other, Surrogate */ + CUPS_GENCAT_CO = 0x74, /* Co Other, Private Use */ + CUPS_GENCAT_CN = 0x75 /* Cn Other, Not Assigned */ +} cups_gencat_t; + +typedef enum /**** Unicode Bidi Category ****/ +{ + CUPS_BIDI_L, /* Left-to-Right (Alpha, Ideographic) */ + CUPS_BIDI_LRE, /* Left-to-Right Embedding (explicit) */ + CUPS_BIDI_LRO, /* Left-to-Right Override (explicit) */ + CUPS_BIDI_R, /* Right-to-Left (Hebrew alpha/punct) */ + CUPS_BIDI_AL, /* Right-to-Left Arabic (Arabic, etc) */ + CUPS_BIDI_RLE, /* Right-to-Left Embedding (explicit) */ + CUPS_BIDI_RLO, /* Right-to-Left Override (explicit) */ + CUPS_BIDI_PDF, /* Pop Directional Format */ + CUPS_BIDI_EN, /* Euro Number (Euro & Indic digits) */ + CUPS_BIDI_ES, /* Euro Number Separator (Slash) */ + CUPS_BIDI_ET, /* Euro Number Terminator */ + CUPS_BIDI_AN, /* Arabic Number (digits, separators) */ + CUPS_BIDI_CS, /* Common Number Separator */ + CUPS_BIDI_NSM, /* Non-Spacing Mark (Mn/Me in UCD) */ + CUPS_BIDI_BN, /* Boundary Neutral (formatting, etc) */ + CUPS_BIDI_B, /* Paragraph Separator */ + CUPS_BIDI_S, /* Segment Separator (Tab) */ + CUPS_BIDI_WS, /* Whitespace Space (Space, etc) */ + CUPS_BIDI_ON /* Other Neutrals */ +} cups_bidi_t; + +/* + * Note - add state table from UAX-14, section 7.3. + * Remember to do BK and SP in outer loop (not in state table). + * Consider optimization for CM (combining mark). + * See 'LineBreak.txt' (12,875) and 'DerivedLineBreak.txt' (1,350). + */ + +typedef enum /**** Unicode Line Break Class ****/ +{ + /* + * (A) - Allow Break AFTER + * (XA) - Prevent Break AFTER + * (B) - Allow Break BEFORE + * (XB) - Prevent Break BEFORE + * (P) - Allow Break For Pair + * (XP) - Prevent Break For Pair + */ + CUPS_BREAK_AI, /* Ambiguous Alphabetic or Ideograph */ + CUPS_BREAK_AL, /* Ordinary Alpha/Symbol Chars (XP) */ + CUPS_BREAK_BA, /* Break Opportunity After Chars (A) */ + CUPS_BREAK_BB, /* Break Opportunity Before Chars (B) */ + CUPS_BREAK_B2, /* Break Opportunity Either (B/A/XP) */ + CUPS_BREAK_BK, /* Mandatory Break (A) (norm) */ + CUPS_BREAK_CB, /* Contingent Break (B/A) (norm) */ + CUPS_BREAK_CL, /* Closing Punctuation (XB) */ + CUPS_BREAK_CM, /* Attached/Combining (XB) (norm) */ + CUPS_BREAK_CR, /* Carriage Return (A) (norm) */ + CUPS_BREAK_EX, /* Exclamation/Interrogation (XB) */ + CUPS_BREAK_GL, /* Non-breaking "Glue" (XB/XA) (norm) */ + CUPS_BREAK_HY, /* Hyphen (XA) */ + CUPS_BREAK_ID, /* Ideographic (B/A) */ + CUPS_BREAK_IN, /* Inseparable chars (XP) */ + CUPS_BREAK_IS, /* Numeric Separator (Infix) (XB) */ + CUPS_BREAK_LF, /* Line Feed (A) (norm) */ + CUPS_BREAK_NS, /* Non-starters (XB) */ + CUPS_BREAK_NU, /* Numeric (XP) */ + CUPS_BREAK_OP, /* Opening Punctuation (XA) */ + CUPS_BREAK_PO, /* Postfix (Numeric) (XB) */ + CUPS_BREAK_PR, /* Prefix (Numeric) (XA) */ + CUPS_BREAK_QU, /* Ambiguous Quotation (XB/XA) */ + CUPS_BREAK_SA, /* Context Dependent (SE Asian) (P) */ + CUPS_BREAK_SG, /* Surrogates (XP) (norm) */ + CUPS_BREAK_SP, /* Space (A) (norm) */ + CUPS_BREAK_SY, /* Symbols Allowing Break After (A) */ + CUPS_BREAK_XX, /* Unknown (XP) */ + CUPS_BREAK_ZW /* Zero Width Space (A) (norm) */ +} cups_break_class_t; + +typedef int _cups_comb_class_t; /**** Unicode Combining Class ****/ + /* 0=base, 1..254=combining char */ + +/* + * Structures... + */ + +typedef struct _cups_normmap_s /**** Normalize Map Cache Struct ****/ +{ + struct _cups_normmap_s *next; /* Next normalize in cache */ + int used; /* Number of times entry used */ + cups_normalize_t normalize; /* Normalization type */ + int normcount; /* Count of Source Chars */ + cups_ucs2_t *uni2norm; /* Char -> Normalization */ + /* ...only supports UCS-2 */ +} _cups_norm_map_t; + +typedef struct _cups_foldmap_s /**** Case Fold Map Cache Struct ****/ +{ + struct _cups_foldmap_s *next; /* Next case fold in cache */ + int used; /* Number of times entry used */ + cups_folding_t fold; /* Case folding type */ + int foldcount; /* Count of Source Chars */ + cups_ucs2_t *uni2fold; /* Char -> Folded Char(s) */ + /* ...only supports UCS-2 */ +} _cups_fold_map_t; + +typedef struct _cups_prop_s /**** Char Property Struct ****/ +{ + cups_ucs2_t ch; /* Unicode Char as UCS-2 */ + unsigned char gencat; /* General Category */ + unsigned char bidicat; /* Bidirectional Category */ +} _cups_prop_t; + +typedef struct _cups_prop_map_s /**** Char Property Map Struct ****/ +{ + int used; /* Number of times entry used */ + int propcount; /* Count of Source Chars */ + _cups_prop_t *uni2prop; /* Char -> Properties */ +} _cups_prop_map_t; + +typedef struct _cups_break_map_s /**** Line Break Class Map Struct ****/ +{ + int used; /* Number of times entry used */ + int breakcount; /* Count of Source Chars */ + cups_ucs2_t *uni2break; /* Char -> Line Break Class */ +} _cups_break_map_t; + +typedef struct _cups_comb_s /**** Char Combining Class Struct ****/ +{ + cups_ucs2_t ch; /* Unicode Char as UCS-2 */ + unsigned char combclass; /* Combining Class */ + unsigned char reserved; /* Reserved for alignment */ +} _cups_comb_t; + +typedef struct _cups_comb_map_s /**** Combining Class Map Struct ****/ +{ + int used; /* Number of times entry used */ + int combcount; /* Count of Source Chars */ + _cups_comb_t *uni2comb; /* Char -> Combining Class */ +} _cups_comb_map_t; + +/* + * Prototypes... + */ + +/* + * Utility functions for normalization module + */ +extern int cupsNormalizeMapsGet(void); +extern int cupsNormalizeMapsFree(void); +extern void cupsNormalizeMapsFlush(void); + +/* + * Normalize UTF-8 string to Unicode UAX-15 Normalization Form + * Note - Compatibility Normalization Forms (NFKD/NFKC) are + * unsafe for subsequent transcoding to legacy charsets + */ +extern int cupsUTF8Normalize(cups_utf8_t *dest, + const cups_utf8_t *src, + const int maxout, + const cups_normalize_t normalize); + +/* + * Normalize UTF-32 string to Unicode UAX-15 Normalization Form + * Note - Compatibility Normalization Forms (NFKD/NFKC) are + * unsafe for subsequent transcoding to legacy charsets + */ +extern int cupsUTF32Normalize(cups_utf32_t *dest, + const cups_utf32_t *src, + const int maxout, + const cups_normalize_t normalize); + +/* + * Case Fold UTF-8 string per Unicode UAX-21 Section 2.3 + * Note - Case folding output is + * unsafe for subsequent transcoding to legacy charsets + */ +extern int cupsUTF8CaseFold(cups_utf8_t *dest, + const cups_utf8_t *src, + const int maxout, + const cups_folding_t fold); + +/* + * Case Fold UTF-32 string per Unicode UAX-21 Section 2.3 + * Note - Case folding output is + * unsafe for subsequent transcoding to legacy charsets + */ +extern int cupsUTF32CaseFold(cups_utf32_t *dest, + const cups_utf32_t *src, + const int maxout, + const cups_folding_t fold); + +/* + * Compare UTF-8 strings after case folding + */ +extern int cupsUTF8CompareCaseless(const cups_utf8_t *s1, + const cups_utf8_t *s2); + +/* + * Compare UTF-32 strings after case folding + */ +extern int cupsUTF32CompareCaseless(const cups_utf32_t *s1, + const cups_utf32_t *s2); + +/* + * Compare UTF-8 strings after case folding and NFKC normalization + */ +extern int cupsUTF8CompareIdentifier(const cups_utf8_t *s1, + const cups_utf8_t *s2); + +/* + * Compare UTF-32 strings after case folding and NFKC normalization + */ +extern int cupsUTF32CompareIdentifier(const cups_utf32_t *s1, + const cups_utf32_t *s2); + +/* + * Get UTF-32 character property + */ +extern int cupsUTF32CharacterProperty(const cups_utf32_t ch, + const cups_property_t prop); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_NORMALIZE_H_ */ + + +/* + * End of "$Id: normalize.h 4684 2005-09-22 02:15:56Z mike $" + */ diff --git a/cups/options.c b/cups/options.c new file mode 100644 index 000000000..f6883d4b0 --- /dev/null +++ b/cups/options.c @@ -0,0 +1,573 @@ +/* + * "$Id: options.c 4918 2006-01-12 05:14:40Z mike $" + * + * Option routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsAddOption() - Add an option to an option array. + * cupsFreeOptions() - Free all memory used by options. + * cupsGetOption() - Get an option value. + * cupsParseOptions() - Parse options from a command-line argument. + * cupsMarkOptions() - Mark command-line options in a PPD file. + */ + +/* + * Include necessary headers... + */ + +#include "cups.h" +#include +#include +#include "string.h" +#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. + * + * This function converts space-delimited name/value pairs according + * to the PAPI text option ABNF specification. Collection values + * ("name={a=... b=... c=...}") are stored with the curley brackets + * intact - use cupsParseOptions() on the value to extract the collection + * attributes. + */ + +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 & 255)) + ptr ++; + + /* + * Loop through the string... + */ + + while (*ptr != '\0') + { + /* + * Get the name up to a SPACE, =, or end-of-string... + */ + + name = ptr; + while (!isspace(*ptr & 255) && *ptr != '=' && *ptr != '\0') + ptr ++; + + /* + * Avoid an empty name... + */ + + if (ptr == name) + break; + + /* + * Skip trailing spaces... + */ + + while (isspace(*ptr & 255)) + *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') + { + if (*ptr == '\\') + _cups_strcpy(ptr, ptr + 1); + + ptr ++; + } + + if (*ptr != '\0') + *ptr++ = '\0'; + } + else if (*ptr == '\"') + { + /* + * Double-quoted string constant... + */ + + ptr ++; + value = ptr; + + while (*ptr != '\"' && *ptr != '\0') + { + if (*ptr == '\\') + _cups_strcpy(ptr, ptr + 1); + + ptr ++; + } + + if (*ptr != '\0') + *ptr++ = '\0'; + } + else if (*ptr == '{') + { + /* + * Collection value... + */ + + int depth; + + value = ptr; + + for (depth = 1; *ptr; ptr ++) + if (*ptr == '{') + depth ++; + else if (*ptr == '}') + { + depth --; + if (!depth) + { + ptr ++; + + if (*ptr != ',') + break; + } + } + else if (*ptr == '\\') + _cups_strcpy(ptr, ptr + 1); + + if (*ptr != '\0') + *ptr++ = '\0'; + } + else + { + /* + * Normal space-delimited string... + */ + + value = ptr; + + while (!isspace(*ptr & 255) && *ptr != '\0') + { + if (*ptr == '\\') + _cups_strcpy(ptr, ptr + 1); + + ptr ++; + } + } + + /* + * Skip trailing whitespace... + */ + + while (isspace(*ptr & 255)) + *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, j, k; /* Looping vars */ + int conflict; /* Option conflicts */ + char *val, /* Pointer into value */ + *ptr, /* Pointer into string */ + s[255]; /* Temporary string */ + cups_option_t *optptr; /* Current option */ + ppd_option_t *option; /* PPD option */ + static const char * const duplex_options[] = + { /* Duplex option names */ + "Duplex", /* Adobe */ + "EFDuplex", /* EFI */ + "EFDuplexing", /* EFI */ + "KD03Duplex", /* Kodak */ + "JCLDuplex" /* Samsung */ + }; + static const char * const duplex_one[] = + { /* one-sided names */ + "None", + "False" + }; + static const char * const duplex_two_long[] = + { /* two-sided-long-edge names */ + "DuplexNoTumble", /* Adobe */ + "LongEdge", /* EFI */ + "Top" /* EFI */ + }; + static const char * const duplex_two_short[] = + { /* two-sided-long-edge names */ + "DuplexTumble", /* Adobe */ + "ShortEdge", /* EFI */ + "Bottom" /* EFI */ + }; + + + /* + * Check arguments... + */ + + if (ppd == NULL || num_options <= 0 || options == NULL) + return (0); + + /* + * Mark options... + */ + + conflict = 0; + + for (i = num_options, optptr = options; i > 0; i --, optptr ++) + if (!strcasecmp(optptr->name, "media")) + { + /* + * Loop through the option string, separating it at commas and + * marking each individual option. + */ + + for (val = optptr->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 (cupsGetOption("PageSize", num_options, options) == NULL) + if (ppdMarkOption(ppd, "PageSize", s)) + conflict = 1; + + if (cupsGetOption("InputSlot", num_options, options) == NULL) + if (ppdMarkOption(ppd, "InputSlot", s)) + conflict = 1; + + if (cupsGetOption("MediaType", num_options, options) == NULL) + if (ppdMarkOption(ppd, "MediaType", s)) + conflict = 1; + + if (cupsGetOption("EFMediaType", num_options, options) == NULL) + if (ppdMarkOption(ppd, "EFMediaType", s)) + conflict = 1; + + if (cupsGetOption("EFMediaQualityMode", num_options, options) == NULL) + if (ppdMarkOption(ppd, "EFMediaQualityMode", s)) /* EFI */ + conflict = 1; + + if (strcasecmp(s, "manual") == 0 && + cupsGetOption("ManualFeed", num_options, options) == NULL) + if (ppdMarkOption(ppd, "ManualFeed", "True")) + conflict = 1; + } + } + else if (!strcasecmp(optptr->name, "sides")) + { + for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) + if (cupsGetOption(duplex_options[j], num_options, options) != NULL) + break; + + if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) + { + /* + * Don't override the PPD option with the IPP attribute... + */ + + continue; + } + + if (!strcasecmp(optptr->value, "one-sided")) + { + /* + * Mark the appropriate duplex option for one-sided output... + */ + + for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) + if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) + break; + + if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) + { + for (k = 0; k < (int)(sizeof(duplex_one) / sizeof(duplex_one[0])); k ++) + if (ppdFindChoice(option, duplex_one[k])) + { + if (ppdMarkOption(ppd, duplex_options[j], duplex_one[k])) + conflict = 1; + + break; + } + } + } + else if (!strcasecmp(optptr->value, "two-sided-long-edge")) + { + /* + * Mark the appropriate duplex option for two-sided-long-edge output... + */ + + for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) + if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) + break; + + if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) + { + for (k = 0; k < (int)(sizeof(duplex_two_long) / sizeof(duplex_two_long[0])); k ++) + if (ppdFindChoice(option, duplex_two_long[k])) + { + if (ppdMarkOption(ppd, duplex_options[j], duplex_two_long[k])) + conflict = 1; + + break; + } + } + } + else if (!strcasecmp(optptr->value, "two-sided-short-edge")) + { + /* + * Mark the appropriate duplex option for two-sided-short-edge output... + */ + + for (j = 0; j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0])); j ++) + if ((option = ppdFindOption(ppd, duplex_options[j])) != NULL) + break; + + if (j < (int)(sizeof(duplex_options) / sizeof(duplex_options[0]))) + { + for (k = 0; k < (int)(sizeof(duplex_two_short) / sizeof(duplex_two_short[0])); k ++) + if (ppdFindChoice(option, duplex_two_short[k])) + { + if (ppdMarkOption(ppd, duplex_options[j], duplex_two_short[k])) + conflict = 1; + + break; + } + } + } + } + else if (!strcasecmp(optptr->name, "resolution") || + !strcasecmp(optptr->name, "printer-resolution")) + { + if (ppdMarkOption(ppd, "Resolution", optptr->value)) + conflict = 1; + if (ppdMarkOption(ppd, "SetResolution", optptr->value)) + /* Calcomp, Linotype, QMS, Summagraphics, Tektronix, Varityper */ + conflict = 1; + if (ppdMarkOption(ppd, "JCLResolution", optptr->value)) /* HP */ + conflict = 1; + if (ppdMarkOption(ppd, "CNRes_PGP", optptr->value)) /* Canon */ + conflict = 1; + } + else if (!strcasecmp(optptr->name, "output-bin")) + { + if (cupsGetOption("OutputBin", num_options, options) == NULL) + if (ppdMarkOption(ppd, "OutputBin", optptr->value)) + conflict = 1; + } + else if (ppdMarkOption(ppd, optptr->name, optptr->value)) + conflict = 1; + + return (conflict); +} + + +/* + * End of "$Id: options.c 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/page.c b/cups/page.c new file mode 100644 index 000000000..0c340297a --- /dev/null +++ b/cups/page.c @@ -0,0 +1,191 @@ +/* + * "$Id: page.c 4494 2005-02-18 02:18:11Z mike $" + * + * Page size functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * ppdPageSize() - Get the page size record for the given size. + * ppdPageWidth() - Get the page width for the given size. + * ppdPageLength() - Get the page length for the given size. + */ + +/* + * Include necessary headers... + */ + +#include "ppd.h" +#include "string.h" +#include + + +/* + * 'ppdPageSize()' - Get the page size record for the given size. + */ + +ppd_size_t * /* O - Size record for page or NULL */ +ppdPageSize(ppd_file_t *ppd, /* I - PPD file record */ + const char *name) /* I - Size name */ +{ + int i; /* Looping var */ + float w, l; /* Width and length of page */ + char units[255]; /* Page size units... */ + + + if (ppd == NULL) + return (NULL); + + if (name != NULL) + { + if (strncmp(name, "Custom.", 7) == 0 && ppd->variable_sizes) + { + /* + * Find the custom page size... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (strcmp("Custom", ppd->sizes[i].name) == 0) + break; + + if (i == ppd->num_sizes) + return (NULL); + + /* + * Variable size; size name can be one of the following: + * + * Custom.WIDTHxLENGTHin - Size in inches + * Custom.WIDTHxLENGTHcm - Size in centimeters + * Custom.WIDTHxLENGTHmm - Size in millimeters + * Custom.WIDTHxLENGTH[pt] - Size in points + */ + + units[0] = '\0'; + if (sscanf(name + 7, "%fx%f%254s", &w, &l, units) < 2) + return (NULL); + + if (strcasecmp(units, "in") == 0) + { + ppd->sizes[i].width = w * 72.0f; + ppd->sizes[i].length = l * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l * 72.0f - ppd->custom_margins[3]; + } + else if (strcasecmp(units, "cm") == 0) + { + ppd->sizes[i].width = w / 2.54f * 72.0f; + ppd->sizes[i].length = l / 2.54f * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w / 2.54f * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l / 2.54f * 72.0f - ppd->custom_margins[3]; + } + else if (strcasecmp(units, "mm") == 0) + { + ppd->sizes[i].width = w / 25.4f * 72.0f; + ppd->sizes[i].length = l / 25.4f * 72.0f; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w / 25.4f * 72.0f - ppd->custom_margins[2]; + ppd->sizes[i].top = l / 25.4f * 72.0f - ppd->custom_margins[3]; + } + else + { + ppd->sizes[i].width = w; + ppd->sizes[i].length = l; + ppd->sizes[i].left = ppd->custom_margins[0]; + ppd->sizes[i].bottom = ppd->custom_margins[1]; + ppd->sizes[i].right = w - ppd->custom_margins[2]; + ppd->sizes[i].top = l - ppd->custom_margins[3]; + } + + return (ppd->sizes + i); + } + else + { + /* + * Lookup by name... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (strcmp(name, ppd->sizes[i].name) == 0) + return (ppd->sizes + i); + } + } + else + { + /* + * Find default... + */ + + for (i = 0; i < ppd->num_sizes; i ++) + if (ppd->sizes[i].marked) + return (ppd->sizes + i); + } + + return (NULL); +} + + +/* + * 'ppdPageWidth()' - Get the page width for the given size. + */ + +float /* O - Width of page in points or 0.0 */ +ppdPageWidth(ppd_file_t *ppd, /* I - PPD file record */ + const char *name) /* I - Size name */ +{ + ppd_size_t *size; /* Page size */ + + + if ((size = ppdPageSize(ppd, name)) == NULL) + return (0.0); + else + return (size->width); +} + + +/* + * 'ppdPageLength()' - Get the page length for the given size. + */ + +float /* O - Length of page in points or 0.0 */ +ppdPageLength(ppd_file_t *ppd, /* I - PPD file */ + const char *name) /* I - Size name */ +{ + ppd_size_t *size; /* Page size */ + + + if ((size = ppdPageSize(ppd, name)) == NULL) + return (0.0); + else + return (size->length); +} + + +/* + * End of "$Id: page.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/cups/ppd.c b/cups/ppd.c new file mode 100644 index 000000000..91f0c5535 --- /dev/null +++ b/cups/ppd.c @@ -0,0 +1,3070 @@ +/* + * "$Id: ppd.c 4910 2006-01-10 21:30:48Z mike $" + * + * PPD file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * 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. + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _ppd_attr_compare() - Compare two attributes. + * ppdClose() - Free all memory used by the PPD file. + * ppdErrorString() - Returns the text assocated with a status. + * ppdLastError() - Return the status from the last ppdOpen*(). + * ppdOpen() - Read a PPD file into memory. + * ppdOpenFd() - Read a PPD file into memory. + * ppdOpenFile() - Read a PPD file into memory. + * ppdSetConformance() - Set the conformance level for PPD files. + * ppd_add_attr() - Add an attribute to the PPD data. + * ppd_add_choice() - Add a choice to an option. + * ppd_add_size() - Add a page size. + * ppd_compare_groups() - Compare two groups. + * ppd_compare_options() - Compare two options. + * ppd_decode() - Decode a string value... + * ppd_free_group() - Free a single UI group. + * ppd_free_option() - Free a single option. + * ppd_get_extoption() - Get an extended option record. + * ppd_get_extparam() - Get an extended parameter record. + * ppd_get_group() - Find or create the named group as needed. + * ppd_get_option() - Find or create the named option as needed. + * ppd_read() - Read a line from a PPD file, skipping comment + * lines as necessary. + */ + +/* + * Include necessary headers. + */ + +#include "globals.h" +#include "debug.h" +#include + + +/* + * 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 ppd_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 ppd_attr_t *ppd_add_attr(ppd_file_t *ppd, const char *name, + const char *spec, const char *text, + const char *value); +static ppd_choice_t *ppd_add_choice(ppd_option_t *option, const char *name); +static ppd_size_t *ppd_add_size(ppd_file_t *ppd, const char *name); +#ifndef __APPLE__ +static int ppd_compare_groups(ppd_group_t *g0, ppd_group_t *g1); +static int ppd_compare_options(ppd_option_t *o0, ppd_option_t *o1); +#endif /* !__APPLE__ */ +static int ppd_decode(char *string); +static void ppd_free_group(ppd_group_t *group); +static void ppd_free_option(ppd_option_t *option); +#if 0 +static ppd_ext_option_t *ppd_get_extoption(ppd_file_t *ppd, const char *name); +static ppd_ext_param_t *ppd_get_extparam(ppd_ext_option_t *opt, + const char *param, + const char *text); +#endif /* 0 */ +static ppd_group_t *ppd_get_group(ppd_file_t *ppd, const char *name, + const char *text, _cups_globals_t *cg); +static ppd_option_t *ppd_get_option(ppd_group_t *group, const char *name); +static int ppd_read(cups_file_t *fp, char *keyword, char *option, + char *text, char **string, int ignoreblank, + _cups_globals_t *cg); + + +/* + * '_ppd_attr_compare()' - Compare two attributes. + */ + +int /* O - Result of comparison */ +_ppd_attr_compare(ppd_attr_t **a, /* I - First attribute */ + ppd_attr_t **b) /* I - Second attribute */ +{ + int ret; /* Result of comparison */ + + + if ((ret = strcasecmp((*a)->name, (*b)->name)) != 0) + return (ret); + else if ((*a)->spec[0] && (*b)->spec[0]) + return (strcasecmp((*a)->spec, (*b)->spec)); + else + return (0); +} + + +/* + * '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 */ + ppd_attr_t **attr; /* Current attribute */ +#if 0 + int j; /* Looping var */ + ppd_ext_option_t **opt; /* Current extended option */ + ppd_ext_param_t **param; /* Current extended parameter */ +#endif /* 0 */ + + + /* + * Range check the PPD file record... + */ + + if (ppd == NULL) + return; + + /* + * Free all strings at the top level... + */ + + ppd_free(ppd->patches); + ppd_free(ppd->jcl_begin); + ppd_free(ppd->jcl_end); + ppd_free(ppd->jcl_ps); + + /* + * Free any emulations... + */ + + if (ppd->num_emulations > 0) + { + for (i = ppd->num_emulations, emul = ppd->emulations; i > 0; i --, emul ++) + { + ppd_free(emul->start); + ppd_free(emul->stop); + } + + ppd_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); + + ppd_free(ppd->groups); + } + + /* + * Free any page sizes... + */ + + if (ppd->num_sizes > 0) + { + ppd_free(ppd->sizes); + } + + /* + * Free any constraints... + */ + + if (ppd->num_consts > 0) + { + ppd_free(ppd->consts); + } + + /* + * Free any filters... + */ + + if (ppd->num_filters > 0) + { + for (i = ppd->num_filters, filter = ppd->filters; i > 0; i --, filter ++) + { + ppd_free(*filter); + } + + ppd_free(ppd->filters); + } + + /* + * Free any fonts... + */ + + if (ppd->num_fonts > 0) + { + for (i = ppd->num_fonts, font = ppd->fonts; i > 0; i --, font ++) + { + ppd_free(*font); + } + + ppd_free(ppd->fonts); + } + + /* + * Free any profiles... + */ + + if (ppd->num_profiles > 0) + { + ppd_free(ppd->profiles); + } + + /* + * Free any attributes... + */ + + if (ppd->num_attrs > 0) + { + for (i = ppd->num_attrs, attr = ppd->attrs; i > 0; i --, attr ++) + { + ppd_free((*attr)->value); + ppd_free(*attr); + } + + ppd_free(ppd->attrs); + } + +#if 0 + if (ppd->num_extended) + { + for (i = ppd->num_extended, opt = ppd->extended; i > 0; i --, opt ++) + { + ppd_free((*opt)->code); + + for (j = (*opt)->num_params, param = (*opt)->params; j > 0; j --, param ++) + ppd_free((*param)->value); + + ppd_free((*opt)->params); + } + + ppd_free(ppd->extended); + } +#endif /* 0 */ + + /* + * Free the whole record... + */ + + ppd_free(ppd); +} + + +/* + * 'ppdErrorString()' - Returns the text assocated with a status. + * + * @since CUPS 1.1.19@ + */ + +const char * /* O - Status string */ +ppdErrorString(ppd_status_t status) /* I - PPD status */ +{ + static const char * const messages[] =/* Status messages */ + { + "OK", + "Unable to open PPD file", + "NULL PPD file pointer", + "Memory allocation error", + "Missing PPD-Adobe-4.x header", + "Missing value string", + "Internal error", + "Bad OpenGroup", + "OpenGroup without a CloseGroup first", + "Bad OpenUI/JCLOpenUI", + "OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first", + "Bad OrderDependency", + "Bad UIConstraints", + "Missing asterisk in column 1", + "Line longer than the maximum allowed (255 characters)", + "Illegal control character", + "Illegal main keyword string", + "Illegal option keyword string", + "Illegal translation string", + "Illegal whitespace character" + }; + + + if (status < PPD_OK || status > PPD_ILLEGAL_WHITESPACE) + return ("Unknown"); + else + return (messages[status]); +} + + +/* + * 'ppdLastError()' - Return the status from the last ppdOpen*(). + * + * @since CUPS 1.1.19@ + */ + +ppd_status_t /* O - Status code */ +ppdLastError(int *line) /* O - Line number */ +{ + _cups_globals_t *cg = _cupsGlobals(); + /* Global data */ + + + if (line) + *line = cg->ppd_line; + + return (cg->ppd_status); +} + + +/* + * 'ppdOpen()' - Read a PPD file into memory. + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpen(FILE *fp) /* I - File to read from */ +{ + ppd_file_t *ppd; /* PPD file record */ + cups_file_t *cf; /* CUPS file */ + + + /* + * Reopen the stdio file as a CUPS file... + */ + + if ((cf = cupsFileOpenFd(fileno(fp), "r")) == NULL) + return (NULL); + + /* + * Load the PPD file using the newer API... + */ + + ppd = ppdOpen2(cf); + + /* + * Close the CUPS file and return the PPD... + */ + + cupsFileClose(cf); + + return (ppd); +} + + +/* + * 'ppdOpen2()' - Read a PPD file into memory. + * + * @since CUPS 1.2@ + */ + +ppd_file_t * /* O - PPD file record */ +ppdOpen2(cups_file_t *fp) /* I - File to read from */ +{ + char *oldlocale; /* Old locale settings */ + 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_LINE], + /* 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 */ + int ui_keyword; /* Is this line a UI keyword? */ + _cups_globals_t *cg = _cupsGlobals(); + /* Global data */ + static const char * const ui_keywords[] = + { + /* Boolean keywords */ + "BlackSubstitution", + "Booklet", + "Collate", + "ManualFeed", + "MirrorPrint", + "NegativePrint", + "Sorter", + "TraySwitch", + + /* PickOne keywords */ + "AdvanceMedia", + "BindColor", + "BindEdge", + "BindType", + "BindWhen", + "BitsPerPixel", + "ColorModel", + "CutMedia", + "Duplex", + "FoldType", + "FoldWhen", + "InputSlot", + "JCLFrameBufferSize", + "JCLResolution", + "Jog", + "MediaColor", + "MediaType", + "MediaWeight", + "OutputBin", + "OutputMode", + "OutputOrder", + "PageRegion", + "PageSize", + "Resolution", + "Separations", + "Signature", + "Slipsheet", + "Smoothing", + "StapleLocation", + "StapleOrientation", + "StapleWhen", + "StapleX", + "StapleY" + }; + + + /* + * Default to "OK" status... + */ + + cg->ppd_status = PPD_OK; + cg->ppd_line = 0; + + /* + * Range check input... + */ + + if (fp == NULL) + { + cg->ppd_status = PPD_NULL_FILE; + return (NULL); + } + + /* + * Grab the first line and make sure it reads '*PPD-Adobe: "major.minor"'... + */ + + mask = ppd_read(fp, keyword, name, text, &string, 0, cg); + + DEBUG_printf(("mask=%x, keyword=\"%s\"...\n", mask, keyword)); + + if (mask == 0 || + strcmp(keyword, "PPD-Adobe") || + string == NULL || string[0] != '4') + { + /* + * Either this is not a PPD file, or it is not a 4.x PPD file. + */ + + if (cg->ppd_status == PPD_OK) + cg->ppd_status = PPD_MISSING_PPDADOBE4; + + ppd_free(string); + + return (NULL); + } + + DEBUG_printf(("ppdOpen: keyword = %s, string = %p\n", keyword, string)); + + ppd_free(string); + + /* + * Allocate memory for the PPD file record... + */ + + if ((ppd = calloc(1, sizeof(ppd_file_t))) == NULL) + { + cg->ppd_status = PPD_ALLOC_ERROR; + + return (NULL); + } + + ppd->language_level = 1; + ppd->color_device = 0; + ppd->colorspace = PPD_CS_GRAY; + ppd->landscape = -90; + + /* + * Get the default language for the user... + */ + + language = cupsLangDefault(); + +#ifdef LC_NUMERIC + oldlocale = _cupsSaveLocale(LC_NUMERIC, "C"); +#else + oldlocale = _cupsSaveLocale(LC_ALL, "C"); +#endif /* LC_NUMERIC */ + + /* + * Read lines from the PPD file and add them to the file record... + */ + + group = NULL; + subgroup = NULL; + option = NULL; + choice = NULL; + ui_keyword = 0; + + while ((mask = ppd_read(fp, keyword, name, text, &string, 1, cg)) != 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 = %p", string); + else + printf(", string = \"%s\"", string); + } + + puts(""); +#endif /* DEBUG */ + + if (strcmp(keyword, "CloseUI") && strcmp(keyword, "CloseGroup") && + strcmp(keyword, "CloseSubGroup") && strncmp(keyword, "Default", 7) && + strcmp(keyword, "JCLCloseUI") && strcmp(keyword, "JCLOpenUI") && + strcmp(keyword, "OpenUI") && strcmp(keyword, "OpenGroup") && + strcmp(keyword, "OpenSubGroup") && string == NULL) + { + /* + * Need a string value! + */ + + cg->ppd_status = PPD_MISSING_VALUE; + + goto error; + } + + /* + * Certain main keywords (as defined by the PPD spec) may be used + * without the usual OpenUI/CloseUI stuff. Presumably this is just + * so that Adobe wouldn't completely break compatibility with PPD + * files prior to v4.0 of the spec, but it is hopelessly + * inconsistent... Catch these main keywords and automatically + * create the corresponding option, as needed... + */ + + if (ui_keyword) + { + /* + * Previous line was a UI keyword... + */ + + option = NULL; + ui_keyword = 0; + } + + if (option == NULL && + (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) == + (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) + { + for (i = 0; i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0])); i ++) + if (!strcmp(keyword, ui_keywords[i])) + break; + + if (i < (int)(sizeof(ui_keywords) / sizeof(ui_keywords[0]))) + { + /* + * Create the option in the appropriate group... + */ + + ui_keyword = 1; + + DEBUG_printf(("**** FOUND ADOBE UI KEYWORD %s WITHOUT OPENUI!\n", + keyword)); + + if (!group) + { + if (strcmp(keyword, "Collate") && strcmp(keyword, "Duplex") && + strcmp(keyword, "InputSlot") && strcmp(keyword, "ManualFeed") && + strcmp(keyword, "MediaType") && strcmp(keyword, "MediaColor") && + strcmp(keyword, "MediaWeight") && strcmp(keyword, "OutputBin") && + strcmp(keyword, "OutputMode") && strcmp(keyword, "OutputOrder") && + strcmp(keyword, "PageSize") && strcmp(keyword, "PageRegion")) + group = ppd_get_group(ppd, "Extra", _("Extra"), cg); + else + group = ppd_get_group(ppd, "General", _("General"), cg); + + if (group == NULL) + goto error; + + DEBUG_printf(("Adding to group %s...\n", group->text)); + option = ppd_get_option(group, keyword); + group = NULL; + } + else + option = ppd_get_option(group, keyword); + + if (option == NULL) + { + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + /* + * Now fill in the initial information for the option... + */ + + if (!strncmp(keyword, "JCL", 3)) + option->section = PPD_ORDER_JCL; + else + option->section = PPD_ORDER_ANY; + + option->order = 10.0f; + + if (i < 8) + option->ui = PPD_UI_BOOLEAN; + else + option->ui = PPD_UI_PICKONE; + + for (j = 0; j < ppd->num_attrs; j ++) + if (!strncmp(ppd->attrs[j]->name, "Default", 7) && + !strcmp(ppd->attrs[j]->name + 7, keyword) && + ppd->attrs[j]->value) + { + DEBUG_printf(("Setting Default%s to %s via attribute...\n", + option->keyword, ppd->attrs[j]->value)); + strlcpy(option->defchoice, ppd->attrs[j]->value, + sizeof(option->defchoice)); + break; + } + + if (!strcmp(keyword, "PageSize")) + strlcpy(option->text, _("Media Size"), sizeof(option->text)); + else if (!strcmp(keyword, "MediaType")) + strlcpy(option->text, _("Media Type"), sizeof(option->text)); + else if (!strcmp(keyword, "InputSlot")) + strlcpy(option->text, _("Media Source"), sizeof(option->text)); + else if (!strcmp(keyword, "ColorModel")) + strlcpy(option->text, _("Output Mode"), sizeof(option->text)); + else if (!strcmp(keyword, "Resolution")) + strlcpy(option->text, _("Resolution"), sizeof(option->text)); + else + strlcpy(option->text, keyword, sizeof(option->text)); + } + } + + if (!strcmp(keyword, "LanguageLevel")) + ppd->language_level = atoi(string); + else if (!strcmp(keyword, "LanguageEncoding")) + ppd->lang_encoding = string; + else if (!strcmp(keyword, "LanguageVersion")) + ppd->lang_version = string; + else if (!strcmp(keyword, "Manufacturer")) + ppd->manufacturer = string; + else if (!strcmp(keyword, "ModelName")) + ppd->modelname = string; + else if (!strcmp(keyword, "Protocols")) + ppd->protocols = string; + else if (!strcmp(keyword, "PCFileName")) + ppd->pcfilename = string; + else if (!strcmp(keyword, "NickName")) + ppd->nickname = string; + else if (!strcmp(keyword, "Product")) + ppd->product = string; + else if (!strcmp(keyword, "ShortNickName")) + ppd->shortnickname = string; + else if (!strcmp(keyword, "TTRasterizer")) + ppd->ttrasterizer = string; + else if (!strcmp(keyword, "JCLBegin")) + { + ppd->jcl_begin = strdup(string); + ppd_decode(ppd->jcl_begin); /* Decode quoted string */ + } + else if (!strcmp(keyword, "JCLEnd")) + { + ppd->jcl_end = strdup(string); + ppd_decode(ppd->jcl_end); /* Decode quoted string */ + } + else if (!strcmp(keyword, "JCLToPSInterpreter")) + { + ppd->jcl_ps = strdup(string); + ppd_decode(ppd->jcl_ps); /* Decode quoted string */ + } + else if (!strcmp(keyword, "AccurateScreensSupport")) + ppd->accurate_screens = !strcmp(string, "True"); + else if (!strcmp(keyword, "ColorDevice")) + ppd->color_device = !strcmp(string, "True"); + else if (!strcmp(keyword, "ContoneOnly")) + ppd->contone_only = !strcmp(string, "True"); + else if (!strcmp(keyword, "cupsFlipDuplex")) + ppd->flip_duplex = !strcmp(string, "True"); + else if (!strcmp(keyword, "cupsManualCopies")) + ppd->manual_copies = !strcmp(string, "True"); + else if (!strcmp(keyword, "cupsModelNumber")) + ppd->model_number = atoi(string); + else if (!strcmp(keyword, "cupsColorProfile")) + { + 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)); + strlcpy(profile->resolution, name, sizeof(profile->resolution)); + strlcpy(profile->media_type, text, sizeof(profile->media_type)); + 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")) + { + if (ppd->num_filters == 0) + filter = malloc(sizeof(char *)); + else + filter = realloc(ppd->filters, sizeof(char *) * (ppd->num_filters + 1)); + + if (filter == NULL) + { + ppd_free(filter); + + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + 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")) + ppd->throughput = atoi(string); + else if (!strcmp(keyword, "Font")) + { + /* + * 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) + { + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + ppd->fonts = tempfonts; + ppd->fonts[ppd->num_fonts] = strdup(name); + ppd->num_fonts ++; + } + else if (!strcmp(keyword, "ParamCustomPageSize")) + { + if (!strcmp(name, "Width")) + sscanf(string, "%*s%*s%f%f", ppd->custom_min + 0, + ppd->custom_max + 0); + else if (!strcmp(name, "Height")) + sscanf(string, "%*s%*s%f%f", ppd->custom_min + 1, + ppd->custom_max + 1); + } + else if (!strcmp(keyword, "HWMargins")) + 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") && + !strcmp(name, "True")) + { + DEBUG_puts("Processing CustomPageSize..."); + + 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 *gtemp; + + + DEBUG_puts("PageSize option not found for CustomPageSize..."); + + if ((gtemp = ppd_get_group(ppd, "General", _("General"), cg)) == NULL) + { + DEBUG_puts("Unable to get general group!"); + + goto error; + } + + if ((option = ppd_get_option(gtemp, "PageSize")) == NULL) + { + DEBUG_puts("Unable to get PageSize option!"); + + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + } + + if ((choice = ppd_add_choice(option, "Custom")) == NULL) + { + DEBUG_puts("Unable to add Custom choice!"); + + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + strlcpy(choice->text, _("Variable"), sizeof(choice->text)); + option = NULL; + } + + if ((option = ppdFindOption(ppd, "PageSize")) == NULL) + { + DEBUG_puts("Unable to find PageSize option!"); + + cg->ppd_status = PPD_INTERNAL_ERROR; + + goto error; + } + + if ((choice = ppdFindChoice(option, "Custom")) == NULL) + { + DEBUG_puts("Unable to find Custom choice!"); + + cg->ppd_status = PPD_INTERNAL_ERROR; + + goto error; + } + + choice->code = string; + option = NULL; + string = NULL; /* Don't add as an attribute below */ + } + else if (!strcmp(keyword, "LandscapeOrientation")) + { + if (!strcmp(string, "Minus90")) + ppd->landscape = -90; + else if (!strcmp(string, "Plus90")) + ppd->landscape = 90; + } + else if (!strcmp(keyword, "Emulators")) + { + for (count = 1, sptr = string; sptr != NULL;) + if ((sptr = strchr(sptr, ' ')) != NULL) + { + count ++; + while (*sptr == ' ') + sptr ++; + } + + ppd->num_emulations = count; + ppd->emulations = calloc(count, sizeof(ppd_emul_t)); + + 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)) + { + ppd_decode(string); + + for (i = 0; i < ppd->num_emulations; i ++) + if (!strcmp(keyword + 14, ppd->emulations[i].name)) + { + ppd->emulations[i].start = string; + string = NULL; + } + } + else if (!strncmp(keyword, "StopEmulator_", 13)) + { + ppd_decode(string); + + for (i = 0; i < ppd->num_emulations; i ++) + if (!strcmp(keyword + 13, ppd->emulations[i].name)) + { + ppd->emulations[i].stop = string; + string = NULL; + } + } + else if (!strcmp(keyword, "JobPatchFile")) + { + if (ppd->patches == NULL) + ppd->patches = strdup(string); + else + { + temp = realloc(ppd->patches, strlen(ppd->patches) + + strlen(string) + 1); + if (temp == NULL) + { + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + ppd->patches = temp; + + strcpy(ppd->patches + strlen(ppd->patches), string); + } + } + else if (!strcmp(keyword, "OpenUI")) + { + /* + * Don't allow nesting of options... + */ + + if (option && cg->ppd_conform == PPD_CONFORM_STRICT) + { + cg->ppd_status = PPD_NESTED_OPEN_UI; + + goto error; + } + + /* + * Add an option record to the current sub-group, group, or file... + */ + + if (name[0] == '*') + _cups_strcpy(name, name + 1); /* Eliminate leading asterisk */ + + for (i = (int)strlen(name) - 1; i > 0 && isspace(name[i] & 255); 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") && strcmp(name, "Duplex") && + strcmp(name, "InputSlot") && strcmp(name, "ManualFeed") && + strcmp(name, "MediaType") && strcmp(name, "MediaColor") && + strcmp(name, "MediaWeight") && strcmp(name, "OutputBin") && + strcmp(name, "OutputMode") && strcmp(name, "OutputOrder") && + strcmp(name, "PageSize") && strcmp(name, "PageRegion")) + group = ppd_get_group(ppd, "Extra", _("Extra"), cg); + else + group = ppd_get_group(ppd, "General", _("General"), cg); + + if (group == NULL) + goto error; + + 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) + { + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + /* + * Now fill in the initial information for the option... + */ + + if (string && !strcmp(string, "PickMany")) + option->ui = PPD_UI_PICKMANY; + else if (string && !strcmp(string, "Boolean")) + option->ui = PPD_UI_BOOLEAN; + else if (string && !strcmp(string, "PickOne")) + option->ui = PPD_UI_PICKONE; + else if (cg->ppd_conform == PPD_CONFORM_STRICT) + { + cg->ppd_status = PPD_BAD_OPEN_UI; + + goto error; + } + else + option->ui = PPD_UI_PICKONE; + + for (j = 0; j < ppd->num_attrs; j ++) + if (!strncmp(ppd->attrs[j]->name, "Default", 7) && + !strcmp(ppd->attrs[j]->name + 7, name) && + ppd->attrs[j]->value) + { + DEBUG_printf(("Setting Default%s to %s via attribute...\n", + option->keyword, ppd->attrs[j]->value)); + strlcpy(option->defchoice, ppd->attrs[j]->value, + sizeof(option->defchoice)); + break; + } + + if (text[0]) + strlcpy(option->text, text, sizeof(option->text)); + else + { + if (!strcmp(name, "PageSize")) + strlcpy(option->text, _("Media Size"), sizeof(option->text)); + else if (!strcmp(name, "MediaType")) + strlcpy(option->text, _("Media Type"), sizeof(option->text)); + else if (!strcmp(name, "InputSlot")) + strlcpy(option->text, _("Media Source"), sizeof(option->text)); + else if (!strcmp(name, "ColorModel")) + strlcpy(option->text, _("Output Mode"), sizeof(option->text)); + else if (!strcmp(name, "Resolution")) + strlcpy(option->text, _("Resolution"), sizeof(option->text)); + else + strlcpy(option->text, name, sizeof(option->text)); + } + + option->section = PPD_ORDER_ANY; + + ppd_free(string); + string = NULL; + } + else if (!strcmp(keyword, "JCLOpenUI")) + { + /* + * Don't allow nesting of options... + */ + + if (option && cg->ppd_conform == PPD_CONFORM_STRICT) + { + cg->ppd_status = PPD_NESTED_OPEN_UI; + + goto error; + } + + /* + * Find the JCL group, and add if needed... + */ + + group = ppd_get_group(ppd, "JCL", "JCL", cg); + + if (group == NULL) + goto error; + + /* + * Add an option record to the current JCLs... + */ + + if (name[0] == '*') + _cups_strcpy(name, name + 1); + + option = ppd_get_option(group, name); + + if (option == NULL) + { + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + /* + * Now fill in the initial information for the option... + */ + + if (string && !strcmp(string, "PickMany")) + option->ui = PPD_UI_PICKMANY; + else if (string && !strcmp(string, "Boolean")) + option->ui = PPD_UI_BOOLEAN; + else if (string && !strcmp(string, "PickOne")) + option->ui = PPD_UI_PICKONE; + else + { + cg->ppd_status = PPD_BAD_OPEN_UI; + + goto error; + } + + for (j = 0; j < ppd->num_attrs; j ++) + if (!strncmp(ppd->attrs[j]->name, "Default", 7) && + !strcmp(ppd->attrs[j]->name + 7, name) && + ppd->attrs[j]->value) + { + DEBUG_printf(("Setting Default%s to %s via attribute...\n", + option->keyword, ppd->attrs[j]->value)); + strlcpy(option->defchoice, ppd->attrs[j]->value, + sizeof(option->defchoice)); + break; + } + + strlcpy(option->text, text, sizeof(option->text)); + + option->section = PPD_ORDER_JCL; + group = NULL; + + ppd_free(string); + string = NULL; + } + else if (!strcmp(keyword, "CloseUI") || !strcmp(keyword, "JCLCloseUI")) + { + option = NULL; + + ppd_free(string); + string = NULL; + } + else if (!strcmp(keyword, "OpenGroup")) + { + /* + * Open a new group... + */ + + if (group != NULL) + { + cg->ppd_status = PPD_NESTED_OPEN_GROUP; + + goto error; + } + + if (!string) + { + cg->ppd_status = PPD_BAD_OPEN_GROUP; + + goto error; + } + + /* + * Separate the group name from the text (name/text)... + */ + + if ((sptr = strchr(string, '/')) != NULL) + *sptr++ = '\0'; + else + sptr = string; + + /* + * Fix up the text... + */ + + ppd_decode(sptr); + + /* + * Find/add the group... + */ + + group = ppd_get_group(ppd, string, sptr, cg); + + if (group == NULL) + goto error; + + ppd_free(string); + string = NULL; + } + else if (!strcmp(keyword, "CloseGroup")) + { + group = NULL; + + ppd_free(string); + string = NULL; + } + else if (!strcmp(keyword, "OrderDependency") || + !strcmp(keyword, "NonUIOrderDependency")) + { + if (sscanf(string, "%f%40s%40s", &order, name, keyword) != 3) + { + cg->ppd_status = PPD_BAD_ORDER_DEPENDENCY; + + goto error; + } + + if (keyword[0] == '*') + _cups_strcpy(keyword, keyword + 1); + + if (!strcmp(name, "ExitServer")) + section = PPD_ORDER_EXIT; + else if (!strcmp(name, "Prolog")) + section = PPD_ORDER_PROLOG; + else if (!strcmp(name, "DocumentSetup")) + section = PPD_ORDER_DOCUMENT; + else if (!strcmp(name, "PageSetup")) + section = PPD_ORDER_PAGE; + else if (!strcmp(name, "JCLSetup")) + section = PPD_ORDER_JCL; + else + section = PPD_ORDER_ANY; + + if (option == NULL) + { + ppd_group_t *gtemp; + + + /* + * Only valid for Non-UI options... + */ + + for (i = ppd->num_groups, gtemp = ppd->groups; i > 0; i --, gtemp ++) + if (gtemp->text[0] == '\0') + break; + + if (i > 0) + for (i = 0; i < gtemp->num_options; i ++) + if (!strcmp(keyword, gtemp->options[i].keyword)) + { + gtemp->options[i].section = section; + gtemp->options[i].order = order; + break; + } + } + else + { + option->section = section; + option->order = order; + } + + ppd_free(string); + string = NULL; + } + else if (!strncmp(keyword, "Default", 7)) + { + if (string == NULL) + continue; + + /* + * Drop UI text, if any, from value... + */ + + if (strchr(string, '/') != NULL) + *strchr(string, '/') = '\0'; + + /* + * Assign the default value as appropriate... + */ + + if (!strcmp(keyword, "DefaultColorSpace")) + { + /* + * Set default colorspace... + */ + + if (!strcmp(string, "CMY")) + ppd->colorspace = PPD_CS_CMY; + else if (!strcmp(string, "CMYK")) + ppd->colorspace = PPD_CS_CMYK; + else if (!strcmp(string, "RGB")) + ppd->colorspace = PPD_CS_RGB; + else if (!strcmp(string, "RGBK")) + ppd->colorspace = PPD_CS_RGBK; + else if (!strcmp(string, "N")) + ppd->colorspace = PPD_CS_N; + else + ppd->colorspace = PPD_CS_GRAY; + } + else if (option && !strcmp(keyword + 7, option->keyword)) + { + /* + * Set the default as part of the current option... + */ + + DEBUG_printf(("Setting %s to %s...\n", keyword, string)); + + strlcpy(option->defchoice, string, sizeof(option->defchoice)); + + DEBUG_printf(("%s is now %s...\n", keyword, option->defchoice)); + } + else + { + /* + * Lookup option and set if it has been defined... + */ + + ppd_option_t *toption; /* Temporary option */ + + + if ((toption = ppdFindOption(ppd, keyword + 7)) != NULL) + { + DEBUG_printf(("Setting %s to %s...\n", keyword, string)); + strlcpy(toption->defchoice, string, sizeof(toption->defchoice)); + } + } + } + else if (!strcmp(keyword, "UIConstraints") || + !strcmp(keyword, "NonUIConstraints")) + { + if (ppd->num_consts == 0) + constraint = calloc(1, sizeof(ppd_const_t)); + else + constraint = realloc(ppd->consts, + (ppd->num_consts + 1) * sizeof(ppd_const_t)); + + if (constraint == NULL) + { + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + 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 */ + cg->ppd_status = PPD_BAD_UI_CONSTRAINTS; + goto error; + + 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] == '*') + _cups_strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->choice1[0] == '*') + _cups_strcpy(constraint->option2, constraint->choice1 + 1); + else + _cups_strcpy(constraint->option2, constraint->choice1); + + constraint->choice1[0] = '\0'; + constraint->choice2[0] = '\0'; + break; + + case 3 : /* Two options, one choice... */ + /* + * The following _cups_strcpy's are safe, as optionN and + * choiceN are all the same size (size defined by PPD spec...) + */ + + if (constraint->option1[0] == '*') + _cups_strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->choice1[0] == '*') + { + _cups_strcpy(constraint->choice2, constraint->option2); + _cups_strcpy(constraint->option2, constraint->choice1 + 1); + constraint->choice1[0] = '\0'; + } + else + { + if (constraint->option2[0] == '*') + _cups_strcpy(constraint->option2, constraint->option2 + 1); + + constraint->choice2[0] = '\0'; + } + break; + + case 4 : /* Two options, two choices... */ + if (constraint->option1[0] == '*') + _cups_strcpy(constraint->option1, constraint->option1 + 1); + + if (constraint->option2[0] == '*') + _cups_strcpy(constraint->option2, constraint->option2 + 1); + break; + } + + ppd_free(string); + string = NULL; + } + else if (!strcmp(keyword, "PaperDimension")) + { + if ((size = ppdPageSize(ppd, name)) == NULL) + size = ppd_add_size(ppd, name); + + if (size == NULL) + { + /* + * Unable to add or find size! + */ + + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + sscanf(string, "%f%f", &(size->width), &(size->length)); + + ppd_free(string); + string = NULL; + } + else if (!strcmp(keyword, "ImageableArea")) + { + if ((size = ppdPageSize(ppd, name)) == NULL) + size = ppd_add_size(ppd, name); + + if (size == NULL) + { + /* + * Unable to add or find size! + */ + + cg->ppd_status = PPD_ALLOC_ERROR; + + goto error; + } + + sscanf(string, "%f%f%f%f", &(size->left), &(size->bottom), + &(size->right), &(size->top)); + + ppd_free(string); + string = NULL; + } + else if (option != NULL && + (mask & (PPD_KEYWORD | PPD_OPTION | PPD_STRING)) == + (PPD_KEYWORD | PPD_OPTION | PPD_STRING) && + !strcmp(keyword, option->keyword)) + { + DEBUG_printf(("group = %p, subgroup = %p\n", group, subgroup)); + + if (!strcmp(keyword, "PageSize")) + { + /* + * 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) + strlcpy(choice->text, text, sizeof(choice->text)); + else if (!strcmp(name, "True")) + strcpy(choice->text, _("Yes")); + else if (!strcmp(name, "False")) + strcpy(choice->text, _("No")); + else + strlcpy(choice->text, name, sizeof(choice->text)); + + if (option->section == PPD_ORDER_JCL) + ppd_decode(string); /* Decode quoted string */ + + choice->code = string; + string = NULL; /* Don't add as an attribute below */ + } +#if 0 + else if (strcmp(keyword, "cupsUIType") == 0 && + (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING) && + option != NULL) + { + /* + * Define an extended option value type... + */ + + extopt = ppd_get_extoption(ppd, name); + + if (strcmp(string, "Text") == 0) + option->ui = PPD_UI_CUPS_TEXT; + else if (strcmp(string, "Integer") == 0) + { + option->ui = PPD_UI_CUPS_INTEGER; + extopt->defval.integer = 0; + extopt->minval.integer = 0; + extopt->maxval.integer = 100; + } + else if (strcmp(string, "Real") == 0) + { + option->ui = PPD_UI_CUPS_REAL; + extopt->defval.real = 0.0; + extopt->minval.real = 0.0; + extopt->maxval.real = 1.0; + } + else if (strcmp(string, "Gamma") == 0) + { + option->ui = PPD_UI_CUPS_GAMMA; + extopt->defval.gamma = 1.0; + extopt->minval.gamma = 1.0; + extopt->maxval.gamma = 10.0; + } + else if (strcmp(string, "Curve") == 0) + { + option->ui = PPD_UI_CUPS_CURVE; + extopt->defval.curve.start = 0.0; + extopt->defval.curve.end = 0.0; + extopt->defval.curve.gamma = 1.0; + extopt->minval.curve.start = 0.0; + extopt->minval.curve.end = 0.0; + extopt->minval.curve.gamma = 1.0; + extopt->maxval.curve.start = 1.0; + extopt->maxval.curve.end = 1.0; + extopt->maxval.curve.gamma = 10.0; + } + else if (strcmp(string, "IntegerArray") == 0) + { + option->ui = PPD_UI_CUPS_INTEGER_ARRAY; + extopt->defval.integer_array.num_elements = 2; + extopt->minval.integer_array.num_elements = 2; + extopt->maxval.integer_array.num_elements = 16; + } + else if (strcmp(string, "RealArray") == 0) + { + option->ui = PPD_UI_CUPS_REAL_ARRAY; + extopt->defval.real_array.num_elements = 2; + extopt->minval.real_array.num_elements = 2; + extopt->maxval.real_array.num_elements = 16; + } + } + else if (strcmp(keyword, "cupsUIDefault") == 0 && + (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING) && + option != NULL) + { + /* + * Define an extended option minimum value... + */ + + extopt = ppd_get_extoption(ppd, name); + + switch (option->ui) + { + case PPD_UI_CUPS_INTEGER : + sscanf(string, "%d", &(extopt->defval.integer)); + break; + + case PPD_UI_CUPS_REAL : + sscanf(string, "%f", &(extopt->defval.real)); + break; + + case PPD_UI_CUPS_GAMMA : + sscanf(string, "%f", &(extopt->defval.gamma)); + break; + + case PPD_UI_CUPS_CURVE : + sscanf(string, "%f%f%f", &(extopt->defval.curve.start), + &(extopt->defval.curve.end), + &(extopt->defval.curve.gamma)); + break; + + case PPD_UI_CUPS_INTEGER_ARRAY : + extopt->defval.integer_array.elements = calloc(1, sizeof(int)); + sscanf(string, "%d%d", &(extopt->defval.integer_array.num_elements), + extopt->defval.integer_array.elements); + break; + + case PPD_UI_CUPS_REAL_ARRAY : + extopt->defval.real_array.elements = calloc(1, sizeof(float)); + sscanf(string, "%d%f", &(extopt->defval.real_array.num_elements), + extopt->defval.real_array.elements); + break; + + default : + break; + } + } + else if (strcmp(keyword, "cupsUIMinimum") == 0 && + (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING) && + option != NULL) + { + /* + * Define an extended option minimum value... + */ + + extopt = ppd_get_extoption(ppd, name); + + switch (option->ui) + { + case PPD_UI_CUPS_INTEGER : + sscanf(string, "%d", &(extopt->minval.integer)); + break; + + case PPD_UI_CUPS_REAL : + sscanf(string, "%f", &(extopt->minval.real)); + break; + + case PPD_UI_CUPS_GAMMA : + sscanf(string, "%f", &(extopt->minval.gamma)); + break; + + case PPD_UI_CUPS_CURVE : + sscanf(string, "%f%f%f", &(extopt->minval.curve.start), + &(extopt->minval.curve.end), + &(extopt->minval.curve.gamma)); + break; + + case PPD_UI_CUPS_INTEGER_ARRAY : + extopt->minval.integer_array.elements = calloc(1, sizeof(int)); + sscanf(string, "%d%d", &(extopt->minval.integer_array.num_elements), + extopt->minval.integer_array.elements); + break; + + case PPD_UI_CUPS_REAL_ARRAY : + extopt->minval.real_array.elements = calloc(1, sizeof(float)); + sscanf(string, "%d%f", &(extopt->minval.real_array.num_elements), + extopt->minval.real_array.elements); + break; + + default : + break; + } + } + else if (strcmp(keyword, "cupsUIMaximum") == 0 && + (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING) && + option != NULL) + { + /* + * Define an extended option maximum value... + */ + + extopt = ppd_get_extoption(ppd, name); + + switch (option->ui) + { + case PPD_UI_CUPS_INTEGER : + sscanf(string, "%d", &(extopt->maxval.integer)); + break; + + case PPD_UI_CUPS_REAL : + sscanf(string, "%f", &(extopt->maxval.real)); + break; + + case PPD_UI_CUPS_GAMMA : + sscanf(string, "%f", &(extopt->maxval.gamma)); + break; + + case PPD_UI_CUPS_CURVE : + sscanf(string, "%f%f%f", &(extopt->maxval.curve.start), + &(extopt->maxval.curve.end), + &(extopt->maxval.curve.gamma)); + break; + + case PPD_UI_CUPS_INTEGER_ARRAY : + extopt->maxval.integer_array.elements = calloc(1, sizeof(int)); + sscanf(string, "%d%d", &(extopt->maxval.integer_array.num_elements), + extopt->maxval.integer_array.elements); + break; + + case PPD_UI_CUPS_REAL_ARRAY : + extopt->maxval.real_array.elements = calloc(1, sizeof(float)); + sscanf(string, "%d%f", &(extopt->maxval.real_array.num_elements), + extopt->maxval.real_array.elements); + break; + + default : + break; + } + } + else if (strcmp(keyword, "cupsUICommand") == 0 && + (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING) && + option != NULL) + { + /* + * Define an extended option command... + */ + + extopt = ppd_get_extoption(ppd, name); + + extopt->command = string; + string = NULL; + } +#endif /* 0 */ + + /* + * Add remaining lines with keywords and string values as attributes... + */ + + if (string && + (mask & (PPD_KEYWORD | PPD_STRING)) == (PPD_KEYWORD | PPD_STRING)) + ppd_add_attr(ppd, keyword, name, text, string); + else + { + ppd_free(string); + } + } + + /* + * Reset language preferences... + */ + + cupsLangFree(language); + +#ifdef LC_NUMERIC + _cupsRestoreLocale(LC_NUMERIC, oldlocale); +#else + _cupsRestoreLocale(LC_ALL, oldlocale); +#endif /* LC_NUMERIC */ + +#ifdef DEBUG + if (!feof(fp)) + printf("Premature EOF at %lu...\n", (unsigned long)ftell(fp)); +#endif /* DEBUG */ + + if (cg->ppd_status != PPD_OK) + { + /* + * Had an error reading the PPD file, cannot continue! + */ + + ppdClose(ppd); + + return (NULL); + } + +#ifndef __APPLE__ + /* + * Make sure that all PPD files with an InputSlot option have an + * "auto" choice that maps to no specific tray or media type. + */ + + if ((option = ppdFindOption(ppd, "InputSlot")) != NULL) + { + for (i = 0; i < option->num_choices; i ++) + if (option->choices[i].code == NULL || !option->choices[i].code[0] || + !strncasecmp(option->choices[i].choice, "Auto", 4)) + break; + + if (i >= option->num_choices) + { + /* + * No "auto" input slot, add one... + */ + + choice = ppd_add_choice(option, "Auto"); + + strlcpy(choice->text, _("Auto"), sizeof(choice->text)); + choice->code = NULL; + } + } +#endif /* !__APPLE__ */ + + /* + * Set the option back-pointer for each choice... + */ + +#ifndef __APPLE__ + qsort(ppd->groups, ppd->num_groups, sizeof(ppd_group_t), + (int (*)(const void *, const void *))ppd_compare_groups); +#endif /* !__APPLE__ */ + + for (i = ppd->num_groups, group = ppd->groups; + i > 0; + i --, group ++) + { +#ifndef __APPLE__ + qsort(group->options, group->num_options, sizeof(ppd_option_t), + (int (*)(const void *, const void *))ppd_compare_options); +#endif /* !__APPLE__ */ + + for (j = group->num_options, option = group->options; + j > 0; + j --, option ++) + { + for (k = 0; k < option->num_choices; k ++) + option->choices[k].option = (void *)option; + } + +#ifndef __APPLE__ + qsort(group->subgroups, group->num_subgroups, sizeof(ppd_group_t), + (int (*)(const void *, const void *))ppd_compare_groups); +#endif /* !__APPLE__ */ + + for (j = group->num_subgroups, subgroup = group->subgroups; + j > 0; + j --, subgroup ++) + { +#ifndef __APPLE__ + qsort(subgroup->options, subgroup->num_options, sizeof(ppd_option_t), + (int (*)(const void *, const void *))ppd_compare_options); +#endif /* !__APPLE__ */ + + for (k = group->num_options, option = group->options; + k > 0; + k --, option ++) + { + for (m = 0; m < option->num_choices; m ++) + option->choices[m].option = (void *)option; + } + } + } + +#if 0 + /* + * Set the option pointers for all extended options... + */ + + for (i = 0; i < ppd->num_extended; i ++) + ppd->extended[i]->option = ppdFindOption(ppd, ppd->extended[i]->keyword); +#endif /* 0 */ + + /* + * Sort the attributes... + */ + + if (ppd->num_attrs > 1) + qsort(ppd->attrs, ppd->num_attrs, sizeof(ppd_attr_t *), + (int (*)(const void *, const void *))_ppd_attr_compare); + + /* + * Return the PPD file structure... + */ + + return (ppd); + + /* + * Common exit point for errors to save code size... + */ + + error: + + ppd_free(string); + + ppdClose(ppd); + + cupsLangFree(language); + +#ifdef LC_NUMERIC + _cupsRestoreLocale(LC_NUMERIC, oldlocale); +#else + _cupsRestoreLocale(LC_ALL, oldlocale); +#endif /* LC_NUMERIC */ + + return (NULL); +} + + +/* + * '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 */ + _cups_globals_t *cg = _cupsGlobals(); + /* Global data */ + + + /* + * Set the line number to 0... + */ + + cg->ppd_line = 0; + + /* + * Range check input... + */ + + if (fd < 0) + { + cg->ppd_status = PPD_NULL_FILE; + + return (NULL); + } + + /* + * Try to open the file and parse it... + */ + + if ((fp = fdopen(fd, "r")) != NULL) + { + setbuf(fp, NULL); + + ppd = ppdOpen(fp); + + fclose(fp); + } + else + { + cg->ppd_status = PPD_FILE_OPEN_ERROR; + 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 */ +{ + cups_file_t *fp; /* File pointer */ + ppd_file_t *ppd; /* PPD file record */ + _cups_globals_t *cg = _cupsGlobals(); + /* Global data */ + + + /* + * Set the line number to 0... + */ + + cg->ppd_line = 0; + + /* + * Range check input... + */ + + if (filename == NULL) + { + cg->ppd_status = PPD_NULL_FILE; + + return (NULL); + } + + /* + * Try to open the file and parse it... + */ + + if ((fp = cupsFileOpen(filename, "r")) != NULL) + { + ppd = ppdOpen2(fp); + + cupsFileClose(fp); + } + else + { + cg->ppd_status = PPD_FILE_OPEN_ERROR; + ppd = NULL; + } + + return (ppd); +} + + +/* + * 'ppdSetConformance()' - Set the conformance level for PPD files. + * + * @since CUPS 1.1.20@ + */ + +void +ppdSetConformance(ppd_conform_t c) /* I - Conformance level */ +{ + _cups_globals_t *cg = _cupsGlobals(); + /* Global data */ + + + cg->ppd_conform = c; +} + + +/* + * 'ppd_add_attr()' - Add an attribute to the PPD data. + */ + +static ppd_attr_t * /* O - New attribute */ +ppd_add_attr(ppd_file_t *ppd, /* I - PPD file data */ + const char *name, /* I - Attribute name */ + const char *spec, /* I - Specifier string, if any */ + const char *text, /* I - Text string, if any */ + const char *value) /* I - Value of attribute */ +{ + ppd_attr_t **ptr, /* New array */ + *temp; /* New attribute */ + + + /* + * Range check input... + */ + + if (ppd == NULL || name == NULL || spec == NULL) + return (NULL); + + /* + * Allocate memory for the new attribute... + */ + + if (ppd->num_attrs == 0) + ptr = malloc(sizeof(ppd_attr_t *)); + else + ptr = realloc(ppd->attrs, (ppd->num_attrs + 1) * sizeof(ppd_attr_t *)); + + if (ptr == NULL) + return (NULL); + + ppd->attrs = ptr; + ptr += ppd->num_attrs; + + if ((temp = calloc(1, sizeof(ppd_attr_t))) == NULL) + return (NULL); + + *ptr = temp; + + ppd->num_attrs ++; + + /* + * Copy data over... + */ + + strlcpy(temp->name, name, sizeof(temp->name)); + strlcpy(temp->spec, spec, sizeof(temp->spec)); + strlcpy(temp->text, text, sizeof(temp->text)); + temp->value = (char *)value; + + /* + * Return the attribute... + */ + + return (temp); +} + + +/* + * '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 */ + const 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)); + strlcpy(choice->choice, name, sizeof(choice->choice)); + + 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 */ + const 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)); + strlcpy(size->name, name, sizeof(size->name)); + + return (size); +} + + +#ifndef __APPLE__ +/* + * 'ppd_compare_groups()' - Compare two groups. + */ + +static int /* O - Result of comparison */ +ppd_compare_groups(ppd_group_t *g0, /* I - First group */ + ppd_group_t *g1) /* I - Second group */ +{ + return (strcasecmp(g0->text, g1->text)); +} + + +/* + * 'ppd_compare_options()' - Compare two options. + */ + +static int /* O - Result of comparison */ +ppd_compare_options(ppd_option_t *o0, /* I - First option */ + ppd_option_t *o1) /* I - Second option */ +{ + return (strcasecmp(o0->text, o1->text)); +} +#endif /* !__APPLE__ */ + + +/* + * 'ppd_decode()' - Decode a string value... + */ + +static int /* O - Length of decoded string */ +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] & 255)) + { + /* + * Convert hex to 8-bit values... + */ + + inptr ++; + while (isxdigit(*inptr & 255)) + { + if (isalpha(*inptr)) + *outptr = (tolower(*inptr) - 'a' + 10) << 4; + else + *outptr = (*inptr - '0') << 4; + + inptr ++; + + if (!isxdigit(*inptr & 255)) + break; + + 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'; + + return ((int)(outptr - string)); +} + + +/* + * '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); + + ppd_free(group->options); + } + + if (group->num_subgroups > 0) + { + for (i = group->num_subgroups, subgroup = group->subgroups; + i > 0; + i --, subgroup ++) + ppd_free_group(subgroup); + + ppd_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 ++) + { + ppd_free(choice->code); + } + + ppd_free(option->choices); + } +} + + +#if 0 +/* + * 'ppd_get_extoption()' - Get an extended option record. + */ + +static ppd_ext_option_t * /* O - Extended option... */ +ppd_get_extoption(ppd_file_t *ppd, /* I - PPD file */ + const char *name) /* I - Name of option */ +{ + ppd_ext_option_t **temp, /* New array pointer */ + *extopt; /* New extended option */ + + + /* + * See if the option already exists... + */ + + if ((extopt = ppdFindExtOption(ppd, name)) != NULL) + return (extopt); + + /* + * Not found, so create the extended option record... + */ + + if ((extopt = calloc(1, sizeof(ppd_ext_option_t))) == NULL) + return (NULL); + + strlcpy(extopt->keyword, name, sizeof(extopt->keyword)); + + /* + * Add this record to the end of the array... + */ + + if (ppd->num_extended == 0) + temp = malloc(sizeof(ppd_ext_option_t *)); + else + temp = realloc(ppd->extended, sizeof(ppd_ext_option_t *) * + (ppd->num_extended + 1)); + + if (temp == NULL) + { + free(extopt); + return (NULL); + } + + ppd->extended = temp; + temp[ppd->num_extended] = extopt; + + ppd->num_extended ++; + + /* + * Return the new record... + */ + + return (extopt); +} + + +/* + * 'ppd_get_extparam()' - Get an extended parameter record. + */ + +static ppd_ext_param_t * /* O - Extended option... */ +ppd_get_extparam(ppd_ext_option_t *opt, /* I - PPD file */ + const char *param,/* I - Name of parameter */ + const char *text) /* I - Human-readable text */ +{ + ppd_ext_param_t **temp, /* New array pointer */ + *extparam; /* New extended parameter */ + + + /* + * See if the parameter already exists... + */ + + if ((extparam = ppdFindExtParam(opt, param)) != NULL) + return (extparam); + + /* + * Not found, so create the extended parameter record... + */ + + if ((extparam = calloc(1, sizeof(ppd_ext_param_t))) == NULL) + return (NULL); + + if ((extparam->value = calloc(4, sizeof(ppd_ext_value_t))) == NULL) + { + ppd_free(extparam); + return (NULL); + } + + extparam->defval = extparam->value + 1; + extparam->minval = extparam->value + 2; + extparam->maxval = extparam->value + 3; + + strlcpy(extparam->keyword, param, sizeof(extparam->keyword)); + strlcpy(extparam->text, text, sizeof(extparam->text)); + + /* + * Add this record to the end of the array... + */ + + if (opt->num_params == 0) + temp = malloc(sizeof(ppd_ext_param_t *)); + else + temp = realloc(opt->params, sizeof(ppd_ext_param_t *) * + (opt->num_params + 1)); + + if (temp == NULL) + { + free(extparam); + return (NULL); + } + + opt->params = temp; + temp[opt->num_params] = extparam; + + opt->num_params ++; + + /* + * Return the new record... + */ + + return (extparam); +} +#endif /* 0 */ + + +/* + * '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 */ + const char *name, /* I - Name of group */ + const char *text, /* I - Text for group */ + _cups_globals_t *cg) /* I - Global data */ +{ + int i; /* Looping var */ + ppd_group_t *group; /* Group */ + + + DEBUG_printf(("ppd_get_group(ppd=%p, name=\"%s\", text=\"%s\", cg=%p)\n", + ppd, name, text, cg)); + + for (i = ppd->num_groups, group = ppd->groups; i > 0; i --, group ++) + if (!strcmp(group->name, name)) + break; + + if (i == 0) + { + DEBUG_printf(("Adding group %s...\n", name)); + + if (cg->ppd_conform == PPD_CONFORM_STRICT && strlen(text) >= sizeof(group->text)) + { + cg->ppd_status = PPD_ILLEGAL_TRANSLATION; + + return (NULL); + } + + 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) + { + cg->ppd_status = PPD_ALLOC_ERROR; + + return (NULL); + } + + ppd->groups = group; + group += ppd->num_groups; + ppd->num_groups ++; + + memset(group, 0, sizeof(ppd_group_t)); + strlcpy(group->name, name, sizeof(group->name)); + strlcpy(group->text, text, sizeof(group->text)); + } + + 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 */ + const char *name) /* I - Name of option */ +{ + int i; /* Looping var */ + ppd_option_t *option; /* Option */ + + + DEBUG_printf(("ppd_get_option(group=%p(\"%s\"), name=\"%s\")\n", + group, group->name, name)); + + for (i = group->num_options, option = group->options; i > 0; i --, option ++) + if (!strcmp(option->keyword, name)) + 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)); + strlcpy(option->keyword, name, sizeof(option->keyword)); + } + + return (option); +} + + +/* + * 'ppd_read()' - Read a line from a PPD file, skipping comment lines as + * necessary. + */ + +static int /* O - Bitmask of fields read */ +ppd_read(cups_file_t *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 ignoreblank, /* I - Ignore blank lines? */ + _cups_globals_t *cg) /* I - Global data */ +{ + int ch, /* Character from file */ + col, /* Column in line */ + colon, /* Colon seen? */ + endquote, /* Waiting for an end quote */ + mask, /* Mask to be returned */ + startline, /* Start line */ + textlen; /* Length of text */ + char *keyptr, /* Keyword pointer */ + *optptr, /* Option pointer */ + *textptr, /* Text pointer */ + *strptr, /* Pointer into string */ + *lineptr, /* Current position in line buffer */ + *line; /* Line buffer */ + int linesize; /* Current size of line buffer */ + + /* + * Range check everything... + */ + + if (!fp || !keyword || !option || !text || !string) + return (0); + + /* + * Now loop until we have a valid line... + */ + + *string = NULL; + col = 0; + startline = cg->ppd_line + 1; + linesize = 1024; + line = malloc(linesize); + + if (!line) + return (0); + + do + { + /* + * Read the line... + */ + + lineptr = line; + endquote = 0; + colon = 0; + + while ((ch = cupsFileGetChar(fp)) != EOF) + { + if (lineptr >= (line + linesize - 1)) + { + /* + * Expand the line buffer... + */ + + char *temp; /* Temporary line pointer */ + + + linesize += 1024; + if (linesize > 262144) + { + /* + * Don't allow lines longer than 256k! + */ + + cg->ppd_line = startline; + cg->ppd_status = PPD_LINE_TOO_LONG; + + free(line); + + return (0); + } + + temp = realloc(line, linesize); + if (!temp) + { + cg->ppd_line = startline; + cg->ppd_status = PPD_LINE_TOO_LONG; + + free(line); + + return (0); + } + + lineptr = temp + (lineptr - line); + line = temp; + } + + if (ch == '\r' || ch == '\n') + { + /* + * Line feed or carriage return... + */ + + cg->ppd_line ++; + col = 0; + + if (ch == '\r') + { + /* + * Check for a trailing line feed... + */ + + if ((ch = cupsFilePeekChar(fp)) == EOF) + break; + if (ch == 0x0a) + cupsFileGetChar(fp); + } + + if (lineptr == line && ignoreblank) + continue; /* Skip blank lines */ + + ch = '\n'; + + if (!endquote) /* Continue for multi-line text */ + break; + + *lineptr++ = '\n'; + } + else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT) + { + /* + * Other control characters... + */ + + cg->ppd_line = startline; + cg->ppd_status = PPD_ILLEGAL_CHARACTER; + + free(line); + + return (0); + } + else if (ch != 0x1a) + { + /* + * Any other character... + */ + + *lineptr++ = ch; + col ++; + + if (col > (PPD_MAX_LINE - 1)) + { + /* + * Line is too long... + */ + + cg->ppd_line = startline; + cg->ppd_status = PPD_LINE_TOO_LONG; + + free(line); + + return (0); + } + + if (ch == ':' && strncmp(line, "*%", 2) != 0) + colon = 1; + + if (ch == '\"' && colon) + endquote = !endquote; + } + } + + if (endquote) + { + /* + * Didn't finish this quoted string... + */ + + while ((ch = cupsFileGetChar(fp)) != EOF) + if (ch == '\"') + break; + else if (ch == '\r' || ch == '\n') + { + cg->ppd_line ++; + col = 0; + + if (ch == '\r') + { + /* + * Check for a trailing line feed... + */ + + if ((ch = cupsFilePeekChar(fp)) == EOF) + break; + if (ch == 0x0a) + cupsFileGetChar(fp); + } + + ch = '\n'; + } + else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT) + { + /* + * Other control characters... + */ + + cg->ppd_line = startline; + cg->ppd_status = PPD_ILLEGAL_CHARACTER; + + free(line); + + return (0); + } + else if (ch != 0x1a) + { + col ++; + + if (col > (PPD_MAX_LINE - 1)) + { + /* + * Line is too long... + */ + + cg->ppd_line = startline; + cg->ppd_status = PPD_LINE_TOO_LONG; + + free(line); + + return (0); + } + } + } + + if (ch != '\n') + { + /* + * Didn't finish this line... + */ + + while ((ch = cupsFileGetChar(fp)) != EOF) + if (ch == '\r' || ch == '\n') + { + /* + * Line feed or carriage return... + */ + + cg->ppd_line ++; + col = 0; + + if (ch == '\r') + { + /* + * Check for a trailing line feed... + */ + + if ((ch = cupsFilePeekChar(fp)) == EOF) + break; + if (ch == 0x0a) + cupsFileGetChar(fp); + } + + break; + } + else if (ch < ' ' && ch != '\t' && cg->ppd_conform == PPD_CONFORM_STRICT) + { + /* + * Other control characters... + */ + + cg->ppd_line = startline; + cg->ppd_status = PPD_ILLEGAL_CHARACTER; + + free(line); + + return (0); + } + else if (ch != 0x1a) + { + col ++; + + if (col > (PPD_MAX_LINE - 1)) + { + /* + * Line is too long... + */ + + cg->ppd_line = startline; + cg->ppd_status = PPD_LINE_TOO_LONG; + + free(line); + + return (0); + } + } + } + + if (lineptr > line && lineptr[-1] == '\n') + lineptr --; + + *lineptr = '\0'; + + DEBUG_printf(("LINE = \"%s\"\n", line)); + + if (ch == EOF && lineptr == line) + { + free(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] || /* Blank line */ + !strncmp(line, "*%", 2) || /* Comment line */ + !strcmp(line, "*End")) && /* End of multi-line string */ + ignoreblank) /* Ignore these? */ + { + startline = cg->ppd_line + 1; + continue; + } + + if (!strcmp(line, "*")) /* (Bad) comment line */ + { + if (cg->ppd_conform == PPD_CONFORM_RELAXED) + { + startline = cg->ppd_line + 1; + continue; + } + else + { + cg->ppd_line = startline; + cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD; + + free(line); + return (0); + } + } + + if (line[0] != '*') /* All lines start with an asterisk */ + { + if (cg->ppd_conform == PPD_CONFORM_STRICT) + { + cg->ppd_status = PPD_MISSING_ASTERISK; + free(line); + return (0); + } + + /* + * Allow lines consisting of just whitespace... + */ + + for (lineptr = line; *lineptr; lineptr ++) + if (!isspace(*lineptr & 255)) + break; + + if (*lineptr) + { + cg->ppd_status = PPD_MISSING_ASTERISK; + free(line); + return (0); + } + else if (ignoreblank) + continue; + else + { + free(line); + return (0); + } + } + + /* + * Get a keyword... + */ + + keyptr = keyword; + + while (*lineptr != '\0' && *lineptr != ':' && !isspace(*lineptr & 255)) + { + if (*lineptr <= ' ' || *lineptr > 126 || *lineptr == '/' || + (keyptr - keyword) >= (PPD_MAX_NAME - 1)) + { + cg->ppd_status = PPD_ILLEGAL_MAIN_KEYWORD; + free(line); + return (0); + } + + *keyptr++ = *lineptr++; + } + + *keyptr = '\0'; + + if (!strcmp(keyword, "End")) + continue; + + mask |= PPD_KEYWORD; + +/* DEBUG_printf(("keyword = \"%s\", lineptr = \"%s\"\n", keyword, lineptr));*/ + + if (isspace(*lineptr & 255)) + { + /* + * Get an option name... + */ + + while (isspace(*lineptr & 255)) + lineptr ++; + + optptr = option; + + while (*lineptr != '\0' && !isspace(*lineptr & 255) && *lineptr != ':' && + *lineptr != '/') + { + if (*lineptr <= ' ' || *lineptr > 126 || + (optptr - option) >= (PPD_MAX_NAME - 1)) + { + cg->ppd_status = PPD_ILLEGAL_OPTION_KEYWORD; + free(line); + return (0); + } + + *optptr++ = *lineptr++; + } + + *optptr = '\0'; + + if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT) + { + cg->ppd_status = PPD_ILLEGAL_WHITESPACE; + free(line); + return (0); + } + + while (isspace(*lineptr & 255)) + lineptr ++; + + 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 != ':') + { + if (((unsigned char)*lineptr < ' ' && *lineptr != '\t') || + (textptr - text) >= (PPD_MAX_LINE - 1)) + { + cg->ppd_status = PPD_ILLEGAL_TRANSLATION; + free(line); + return (0); + } + + *textptr++ = *lineptr++; + } + + *textptr = '\0'; + textlen = ppd_decode(text); + + if (textlen > PPD_MAX_TEXT && cg->ppd_conform == PPD_CONFORM_STRICT) + { + cg->ppd_status = PPD_ILLEGAL_TRANSLATION; + free(line); + return (0); + } + + mask |= PPD_TEXT; + } + +/* DEBUG_printf(("text = \"%s\", lineptr = \"%s\"\n", text, lineptr));*/ + } + + if (isspace(*lineptr & 255) && cg->ppd_conform == PPD_CONFORM_STRICT) + { + cg->ppd_status = PPD_ILLEGAL_WHITESPACE; + free(line); + return (0); + } + + while (isspace(*lineptr & 255)) + lineptr ++; + + if (*lineptr == ':') + { + /* + * Get string after triming leading and trailing whitespace... + */ + + lineptr ++; + while (isspace(*lineptr & 255)) + lineptr ++; + + strptr = lineptr + strlen(lineptr) - 1; + while (strptr >= lineptr && isspace(*strptr & 255)) + *strptr-- = '\0'; + + if (*strptr == '\"') + { + /* + * Quoted string by itself... + */ + + *string = malloc(strlen(lineptr) + 1); + + strptr = *string; + + for (; *lineptr != '\0'; lineptr ++) + if (*lineptr != '\"') + *strptr++ = *lineptr; + + *strptr = '\0'; + } + else + *string = strdup(lineptr); + +/* DEBUG_printf(("string = \"%s\", lineptr = \"%s\"\n", *string, lineptr));*/ + + mask |= PPD_STRING; + } + } + while (mask == 0); + + free(line); + + return (mask); +} + + +/* + * End of "$Id: ppd.c 4910 2006-01-10 21:30:48Z mike $". + */ diff --git a/cups/ppd.h b/cups/ppd.h new file mode 100644 index 000000000..0edef2410 --- /dev/null +++ b/cups/ppd.h @@ -0,0 +1,421 @@ +/* + * "$Id: ppd.h 4785 2005-10-13 19:39:05Z mike $" + * + * PostScript Printer Description definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * 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. + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_PPD_H_ +# define _CUPS_PPD_H_ + +/* + * Include necessary headers... + */ + +# include +# include "file.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 ppd_ui_e /**** 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 ppd_section_e /**** 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 ppd_cs_e /**** 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 enum ppd_status_e /**** Status Codes @since CUPS 1.1.19@ ****/ +{ + PPD_OK = 0, /* OK */ + PPD_FILE_OPEN_ERROR, /* Unable to open PPD file */ + PPD_NULL_FILE, /* NULL PPD file pointer */ + PPD_ALLOC_ERROR, /* Memory allocation error */ + PPD_MISSING_PPDADOBE4, /* Missing PPD-Adobe-4.x header */ + PPD_MISSING_VALUE, /* Missing value string */ + PPD_INTERNAL_ERROR, /* Internal error */ + PPD_BAD_OPEN_GROUP, /* Bad OpenGroup */ + PPD_NESTED_OPEN_GROUP, /* OpenGroup without a CloseGroup first */ + PPD_BAD_OPEN_UI, /* Bad OpenUI/JCLOpenUI */ + PPD_NESTED_OPEN_UI, /* OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first */ + PPD_BAD_ORDER_DEPENDENCY, /* Bad OrderDependency */ + PPD_BAD_UI_CONSTRAINTS, /* Bad UIConstraints */ + PPD_MISSING_ASTERISK, /* Missing asterisk in column 0 */ + PPD_LINE_TOO_LONG, /* Line longer than 255 chars */ + PPD_ILLEGAL_CHARACTER, /* Illegal control character */ + PPD_ILLEGAL_MAIN_KEYWORD, /* Illegal main keyword string */ + PPD_ILLEGAL_OPTION_KEYWORD, /* Illegal option keyword string */ + PPD_ILLEGAL_TRANSLATION, /* Illegal translation string */ + PPD_ILLEGAL_WHITESPACE /* Illegal whitespace character */ +} ppd_status_t; + +typedef enum ppd_conform_e /**** Conformance Levels ****/ +{ + PPD_CONFORM_RELAXED, /* Relax whitespace and control char */ + PPD_CONFORM_STRICT /* Require strict conformance */ +} ppd_conform_t; + +typedef struct ppd_attr_str /**** PPD Attribute Structure @since CUPS 1.1.19@ ****/ +{ + char name[PPD_MAX_NAME]; + /* Name of attribute (cupsXYZ) */ + char spec[PPD_MAX_NAME]; + /* Specifier string, if any */ + char text[PPD_MAX_TEXT]; + /* Human-readable text, if any */ + char *value; /* Value string */ +} ppd_attr_t; + +typedef struct ppd_option_str ppd_option_t; + /**** Options ****/ + +typedef struct ppd_choice_str /**** Option choices ****/ +{ + char marked; /* 0 if not selected, 1 otherwise */ + char choice[PPD_MAX_NAME]; + /* Computer-readable option name */ + char text[PPD_MAX_TEXT]; + /* Human-readable option name */ + char *code; /* Code to send for this option */ + ppd_option_t *option; /* Pointer to parent option structure */ +} ppd_choice_t; + +struct ppd_option_str /**** Options ****/ +{ + char conflicted; /* 0 if no conflicts exist, 1 otherwise */ + char keyword[PPD_MAX_NAME]; + /* Option keyword name ("PageSize", etc.) */ + char defchoice[PPD_MAX_NAME]; + /* Default option choice */ + char 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 */ +}; + +typedef struct ppd_group_str /**** Groups ****/ +{ + /**** Group text strings are limited to 39 chars + nul in order to + **** preserve binary compatibility and allow applications to get + **** the group's keyword name. + ****/ + char text[PPD_MAX_TEXT - PPD_MAX_NAME]; + /* Human-readable group name */ + char name[PPD_MAX_NAME]; + /* Group name @since CUPS 1.1.18@ */ + 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 */ + char choice1[PPD_MAX_NAME]; + /* First option/choice (blank for all) */ + char option2[PPD_MAX_NAME]; + /* Second keyword */ + char choice2[PPD_MAX_NAME]; + /* Second option/choice (blank for all) */ +} ppd_const_t; + +typedef struct ppd_size_str /**** Page Sizes ****/ +{ + int marked; /* Page size selected? */ + char name[PPD_MAX_NAME]; + /* Media size option */ + float width; /* Width of media in points */ + float length; /* Length of media in points */ + float left; /* Left printable margin in points */ + float bottom; /* Bottom printable margin in points */ + float right; /* Right printable margin in points */ + float top; /* Top printable margin in points */ +} ppd_size_t; + +typedef struct ppd_emul_str /**** Emulators ****/ +{ + char name[PPD_MAX_NAME]; + /* Emulator name */ + char *start; /* Code to switch to this emulation */ + char *stop; /* Code to stop this emulation */ +} ppd_emul_t; + +typedef struct ppd_profile_str /**** sRGB Color Profiles ****/ +{ + char resolution[PPD_MAX_NAME]; + /* Resolution or "-" */ + char media_type[PPD_MAX_NAME]; + /* Media type or "-" */ + float density; /* Ink density to use */ + float gamma; /* Gamma correction to use */ + float matrix[3][3]; /* Transform matrix */ +} ppd_profile_t; + +/**** New in CUPS 1.2 ****/ +# if 0 +typedef enum ppd_ext_ui_e /**** Extended UI Types @since CUPS 1.2@ ****/ +{ + PPD_UI_CUPS_TEXT, /* Specify a string */ + PPD_UI_CUPS_INTEGER, /* Specify an integer number */ + PPD_UI_CUPS_REAL, /* Specify a real number */ + PPD_UI_CUPS_GAMMA, /* Specify a gamma number */ + PPD_UI_CUPS_CURVE, /* Specify start, end, and gamma numbers */ + PPD_UI_CUPS_INTEGER_ARRAY, /* Specify an array of integer numbers */ + PPD_UI_CUPS_REAL_ARRAY, /* Specify an array of real numbers */ + PPD_UI_CUPS_XY_ARRAY /* Specify an array of X/Y real numbers */ +} ppd_ext_ui_t; + +typedef union ppd_ext_value_u /**** Extended Values @since CUPS 1.2@ ****/ +{ + char *text; /* Text value */ + int integer; /* Integer value */ + float real; /* Real value */ + float gamma; /* Gamma value */ + struct + { + float start; /* Linear (density) start value for curve */ + float end; /* Linear (density) end value for curve */ + float gamma; /* Gamma correction */ + } curve; /* Curve values */ + struct + { + int num_elements; /* Number of array elements */ + int *elements; /* Array of integer values */ + } integer_array; /* Integer array value */ + struct + { + int num_elements; /* Number of array elements */ + float *elements; /* Array of real values */ + } real_array; /* Real array value */ + struct + { + int num_elements; /* Number of array elements */ + float *elements; /* Array of XY values */ + } xy_array; /* XY array value */ +} ppd_ext_value_t; + +typedef struct ppd_ext_param_str/**** Extended Parameter @since CUPS 1.2@ ****/ +{ + char keyword[PPD_MAX_NAME]; + /* Parameter name */ + char text[PPD_MAX_TEXT]; + /* Human-readable text */ + ppd_ext_value_t *value; /* Current values */ + ppd_ext_value_t *defval; /* Default values */ + ppd_ext_value_t *minval; /* Minimum numeric values */ + ppd_ext_value_t *maxval; /* Maximum numeric values */ +} ppd_ext_param_t; + +typedef struct ppd_ext_option_str + /**** Extended Options @since CUPS 1.2@ ****/ +{ + char keyword[PPD_MAX_NAME]; + /* Name of option that is being extended... */ + ppd_option_t *option; /* Option that is being extended... */ + int marked; /* Extended option is marked */ + char *code; /* Generic PS code for extended options */ + int num_params; /* Number of parameters */ + ppd_ext_param_t **params; /* Parameters */ +} ppd_ext_option_t; +# endif /* 0 */ + +typedef struct ppd_file_str /**** Files ****/ +{ + int language_level; /* Language level of device */ + int color_device; /* 1 = color device, 0 = grayscale */ + int variable_sizes; /* 1 = supports variable sizes, 0 = doesn't */ + int accurate_screens; + /* 1 = supports accurate screens, 0 = not */ + int contone_only; /* 1 = continuous tone only, 0 = not */ + int landscape; /* -90 or 90 */ + int model_number; /* Device-specific model number */ + int manual_copies; /* 1 = Copies done manually, 0 = hardware */ + int 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 */ + char *jcl_ps; /* Enter PostScript interpreter */ + char *jcl_end; /* End JCL commands */ + char *lang_encoding; /* Language encoding */ + char *lang_version; /* Language version (English, Spanish, etc.) */ + char *modelname; /* Model name (general) */ + char *ttrasterizer; /* Truetype rasterizer */ + char *manufacturer; /* Manufacturer name */ + char *product; /* Product name (from PS RIP/interpreter) */ + char *nickname; /* Nickname (specific) */ + char *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 */ + float custom_max[2]; /* Maximum variable page size */ + float 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... */ + + /**** New in CUPS 1.1 ****/ + int flip_duplex; /* 1 = Flip page for back sides @since CUPS 1.1@ */ + + /**** New in CUPS 1.1.19 ****/ + char *protocols; /* Protocols (BCP, TBCP) string @since CUPS 1.1.19@ */ + char *pcfilename; /* PCFileName string @since CUPS 1.1.19@ */ + int num_attrs; /* Number of attributes @since CUPS 1.1.19@ */ + int cur_attr; /* Current attribute @since CUPS 1.1.19@ */ + ppd_attr_t **attrs; /* Attributes @since CUPS 1.1.19@ */ + + /**** New in CUPS 1.2 ****/ +# if 0 + int num_extended; /* Number of extended options @since CUPS 1.2@ */ + ppd_ext_option_t **extended; /* Extended options @since CUPS 1.2@ */ +# endif /* 0 */ +} 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 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 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_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); + +/**** New in CUPS 1.1.19 ****/ +extern const char *ppdErrorString(ppd_status_t status); +extern ppd_attr_t *ppdFindAttr(ppd_file_t *ppd, const char *name, + const char *spec); +extern ppd_attr_t *ppdFindNextAttr(ppd_file_t *ppd, const char *name, + const char *spec); +extern ppd_status_t ppdLastError(int *line); + +/**** New in CUPS 1.1.20 ****/ +extern void ppdSetConformance(ppd_conform_t c); + +/**** New in CUPS 1.2 ****/ +extern int ppdEmitJCLEnd(ppd_file_t *ppd, FILE *fp); +extern ppd_file_t *ppdOpen2(cups_file_t *fp); + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !_CUPS_PPD_H_ */ + +/* + * End of "$Id: ppd.h 4785 2005-10-13 19:39:05Z mike $". + */ diff --git a/cups/sample.ppd b/cups/sample.ppd new file mode 100644 index 000000000..87e56006c --- /dev/null +++ b/cups/sample.ppd @@ -0,0 +1,299 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: sample.ppd 2620 2002-08-14 05:34:15Z mike $" +*% +*% 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: "<>setpagedevice" +*PageSize Legal/US Legal: "<>setpagedevice" +*PageSize Executive/US Executive: "<>setpagedevice" +*PageSize Tabloid/US Tabloid: "<>setpagedevice" +*PageSize A3/A3: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/US Letter: "<>setpagedevice" +*PageRegion Legal/US Legal: "<>setpagedevice" +*PageRegion Executive/US Executive: "<>setpagedevice" +*PageRegion Tabloid/US Tabloid: "<>setpagedevice" +*PageRegion A3/A3: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "18 36 594 756" +*ImageableArea Legal/US Legal: "18 36 594 972" +*ImageableArea Executive/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: "<>setpagedevice" +*MediaType Bond/Bond Paper: "<>setpagedevice" +*MediaType Special/Special Paper: "<>setpagedevice" +*MediaType Transparency/Transparency: "<>setpagedevice" +*MediaType Glossy/Glossy Paper: "<>setpagedevice" +*CloseUI: *MediaType + +*OpenUI *InputSlot/Media Source: PickOne +*OrderDependency: 10 AnySetup *InputSlot +*DefaultInputSlot: Tray +*InputSlot Tray/Tray: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 300dpi +*Resolution 150dpi/150 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/CMYK Color: "<>setpagedevice" +*ColorModel RGB/CMY Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*OpenGroup Extended/Extended Options + +*OpenUI IntOption/Integer: PickOne +*OrderDependency: 10 AnySetup *IntOption +*DefaultIntOption: None +*IntOption None: "" +*IntOption 1: "<>setpagedevice" +*IntOption 2: "<>setpagedevice" +*IntOption 3: "<>setpagedevice" +*IntOption 4: "<>setpagedevice" +*IntOption 5: "<>setpagedevice" +*cupsUIType IntOption: Integer +*cupsUIMinimum IntOption: "1" +*cupsUIMaximum IntOption: "5" +*cupsUICommand IntOption: "<>setpagedevice>>" +*CloseUI: *IntOption + +*OpenUI RealOption/Real Number: PickOne +*OrderDependency: 10 AnySetup *RealOption +*DefaultRealOption: None +*RealOption None: "" +*RealOption 1: "<>setpagedevice" +*RealOption 2: "<>setpagedevice" +*RealOption 3: "<>setpagedevice" +*RealOption 4: "<>setpagedevice" +*RealOption 5: "<>setpagedevice" +*cupsUIType RealOption: Real +*cupsUIMinimum RealOption: "1" +*cupsUIMaximum RealOption: "5" +*cupsUICommand RealOption: "<>setpagedevice>>" +*CloseUI: *RealOption + +*OpenUI TextOption/Text: PickOne +*OrderDependency: 10 AnySetup *TextOption +*DefaultTextOption: None +*TextOption None: "" +*TextOption NOFORN: "<>setpagedevice" +*TextOption FOIA: "<>setpagedevice" +*TextOption FOUO: "<>setpagedevice" +*cupsUIType TextOption: Text +*cupsUICommand TextOption: "<>setpagedevice>>" +*CloseUI: *TextOption + +*OpenUI GammaOption/Gamma Curve: PickOne +*OrderDependency: 10 AnySetup *GammaOption +*DefaultGammaOption: None +*GammaOption None: "" +*GammaOption 1: "<>setpagedevice" +*GammaOption 1.5: "<>setpagedevice" +*GammaOption 2.0: "<>setpagedevice" +*GammaOption 2.5: "<>setpagedevice" +*GammaOption 3.0: "<>setpagedevice" +*cupsUIType GammaOption: Integer +*cupsUIMinimum GammaOption: "1" +*cupsUIMaximum GammaOption: "3" +*cupsUICommand GammaOption: "<>setpagedevice>>" +*CloseUI: *GammaOption + +*OpenUI CurveOption/Curve: PickOne +*OrderDependency: 10 AnySetup *CurveOption +*DefaultCurveOption: None +*CurveOption None: "" +*CurveOption 1: "<>setpagedevice" +*CurveOption 2: "<>setpagedevice" +*CurveOption 3: "<>setpagedevice" +*CurveOption 4: "<>setpagedevice" +*CurveOption 5: "<>setpagedevice" +*cupsUIType CurveOption: Curve +*cupsUIMinimum CurveOption: "0 0 1" +*cupsUIMaximum CurveOption: "1 1 5" +*cupsUICommand CurveOption: "<>setpagedevice pop pop pop>>" +*CloseUI: *CurveOption + +*OpenUI IntArrayOption/Integer Array: PickOne +*OrderDependency: 10 AnySetup *IntArrayOption +*DefaultIntArrayOption: None +*IntArrayOption None: "" +*IntArrayOption Linear: "<>setpagedevice" +*IntArrayOption Parametric: "<>setpagedevice" +*IntArrayOption Sine: "<>setpagedevice" +*cupsUIType IntArrayOption: IntegerArray +*cupsUIMinimum IntArrayOption: "2 0" +*cupsUIMaximum IntArrayOption: "16 255" +*cupsUICommand IntArrayOption: "<>setpagedevice>>" +*CloseUI: *IntArrayOption + +*OpenUI RealArrayOption/Real Array: PickOne +*OrderDependency: 10 AnySetup *RealArrayOption +*DefaultRealArrayOption: None +*RealArrayOption None: "" +*RealArrayOption Linear: "<>setpagedevice" +*RealArrayOption Parametric: "<>setpagedevice" +*RealArrayOption Sine: "<>setpagedevice" +*cupsUIType RealArrayOption: RealArray +*cupsUIMinimum RealArrayOption: "2 0" +*cupsUIMaximum RealArrayOption: "16 255" +*cupsUICommand RealArrayOption: "<>setpagedevice>>" +*CloseUI: *RealArrayOption + +*CloseGroup + +*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: sample.ppd 2620 2002-08-14 05:34:15Z mike $". +*% diff --git a/cups/snprintf.c b/cups/snprintf.c new file mode 100644 index 000000000..86f8c3f63 --- /dev/null +++ b/cups/snprintf.c @@ -0,0 +1,367 @@ +/* + * "$Id: snprintf.c 4683 2005-09-21 22:17:44Z mike $" + * + * snprintf functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cups_vsnprintf() - Format a string into a fixed size buffer. + * _cups_snprintf() - Format a string into a fixed size buffer. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "string.h" + + +#ifndef HAVE_VSNPRINTF +/* + * '_cups_vsnprintf()' - Format a string into a fixed size buffer. + */ + +int /* O - Number of bytes formatted */ +_cups_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 */ + int width, /* Width of field */ + prec; /* Number of characters of precision */ + char tformat[100], /* Temporary format string for sprintf() */ + *tptr, /* Pointer into temporary format */ + temp[1024]; /* Buffer for formatted numbers */ + char *s; /* Pointer to string */ + int slen; /* Length of string */ + int bytes; /* Total number of bytes needed */ + + + /* + * Loop through the format string, formatting as needed... + */ + + bufptr = buffer; + bufend = buffer + bufsize - 1; + bytes = 0; + + while (*format) + { + if (*format == '%') + { + tptr = tformat; + *tptr++ = *format++; + + if (*format == '%') + { + if (bufptr && bufptr < bufend) *bufptr++ = *format; + bytes ++; + format ++; + continue; + } + else if (strchr(" -+#\'", *format)) + { + *tptr++ = *format; + sign = *format++; + } + else + sign = 0; + + if (*format == '*') + { + // Get width from argument... + format ++; + width = va_arg(ap, int); + + snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width); + tptr += strlen(tptr); + } + else + { + width = 0; + + while (isdigit(*format & 255)) + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + width = width * 10 + *format++ - '0'; + } + } + + if (*format == '.') + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + format ++; + + if (*format == '*') + { + // Get precision from argument... + format ++; + prec = va_arg(ap, int); + + snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec); + tptr += strlen(tptr); + } + else + { + prec = 0; + + while (isdigit(*format & 255)) + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + prec = prec * 10 + *format++ - '0'; + } + } + } + else + prec = -1; + + if (*format == 'l' && format[1] == 'l') + { + size = 'L'; + + if (tptr < (tformat + sizeof(tformat) - 2)) + { + *tptr++ = 'l'; + *tptr++ = 'l'; + } + + format += 2; + } + else if (*format == 'h' || *format == 'l' || *format == 'L') + { + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + size = *format++; + } + + if (!*format) + break; + + if (tptr < (tformat + sizeof(tformat) - 1)) + *tptr++ = *format; + + type = *format++; + *tptr = '\0'; + + switch (type) + { + case 'E' : /* Floating point formats */ + case 'G' : + case 'e' : + case 'f' : + case 'g' : + if ((width + 2) > sizeof(temp)) + break; + + sprintf(temp, tformat, va_arg(ap, double)); + + bytes += strlen(temp); + + if (bufptr) + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + 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 ((width + 2) > sizeof(temp)) + break; + + sprintf(temp, tformat, va_arg(ap, int)); + + bytes += strlen(temp); + + if (bufptr) + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'p' : /* Pointer value */ + if ((width + 2) > sizeof(temp)) + break; + + sprintf(temp, tformat, va_arg(ap, void *)); + + bytes += strlen(temp); + + if (bufptr) + { + if ((bufptr + strlen(temp)) > bufend) + { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } + else + { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'c' : /* Character or character array */ + bytes += width; + + if (bufptr) + { + if (width <= 1) + *bufptr++ = va_arg(ap, int); + else + { + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + memcpy(bufptr, va_arg(ap, char *), (size_t)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; + + bytes += width; + + if (bufptr) + { + if ((bufptr + width) > bufend) + width = bufend - bufptr; + + if (slen > width) + slen = width; + + if (sign == '-') + { + strncpy(bufptr, s, (size_t)slen); + memset(bufptr + slen, ' ', (size_t)(width - slen)); + } + else + { + memset(bufptr, ' ', (size_t)(width - slen)); + strncpy(bufptr + width - slen, s, (size_t)slen); + } + + bufptr += width; + } + break; + + case 'n' : /* Output number of chars so far */ + *(va_arg(ap, int *)) = bytes; + break; + } + } + else + { + bytes ++; + + if (bufptr && bufptr < bufend) + *bufptr++ = *format; + + format ++; + } + } + + /* + * Nul-terminate the string and return the number of characters needed. + */ + + *bufptr = '\0'; + + return (bytes); +} +#endif /* !HAVE_VSNPRINT */ + + +#ifndef HAVE_SNPRINTF +/* + * '_cups_snprintf()' - Format a string into a fixed size buffer. + */ + +int /* O - Number of bytes formatted */ +_cups_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: snprintf.c 4683 2005-09-21 22:17:44Z mike $". + */ + diff --git a/cups/string.c b/cups/string.c new file mode 100644 index 000000000..d071d8519 --- /dev/null +++ b/cups/string.c @@ -0,0 +1,226 @@ +/* + * "$Id: string.c 4683 2005-09-21 22:17:44Z mike $" + * + * String functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cups_strcpy() - Copy a string allowing for overlapping strings. + * _cups_strdup() - Duplicate a string. + * _cups_strcasecmp() - Do a case-insensitive comparison. + * _cups_strncasecmp() - Do a case-insensitive comparison on up to N chars. + * _cups_strlcat() - Safely concatenate two strings. + * _cups_strlcpy() - Safely copy two strings. + */ + +/* + * Include necessary headers... + */ + +#include "string.h" + + +/* + * '_cups_strcpy()' - Copy a string allowing for overlapping strings. + */ + +void +_cups_strcpy(char *dst, /* I - Destination string */ + const char *src) /* I - Source string */ +{ + while (*src) + *dst++ = *src++; + + *dst = '\0'; +} + + +/* + * '_cups_strdup()' - Duplicate a string. + */ + +#ifndef HAVE_STRDUP +char * /* O - New string pointer */ +_cups_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 */ + + +/* + * '_cups_strcasecmp()' - Do a case-insensitive comparison. + */ + +#ifndef HAVE_STRCASECMP +int /* O - Result of comparison (-1, 0, or 1) */ +_cups_strcasecmp(const char *s, /* I - First string */ + const char *t) /* I - Second string */ +{ + while (*s != '\0' && *t != '\0') + { + if (tolower(*s & 255) < tolower(*t & 255)) + return (-1); + else if (tolower(*s & 255) > tolower(*t & 255)) + return (1); + + s ++; + t ++; + } + + if (*s == '\0' && *t == '\0') + return (0); + else if (*s != '\0') + return (1); + else + return (-1); +} +#endif /* !HAVE_STRCASECMP */ + +/* + * '_cups_strncasecmp()' - Do a case-insensitive comparison on up to N chars. + */ + +#ifndef HAVE_STRNCASECMP +int /* O - Result of comparison (-1, 0, or 1) */ +_cups_strncasecmp(const char *s, /* I - First string */ + vconst 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 & 255) < tolower(*t & 255)) + return (-1); + else if (tolower(*s & 255) > tolower(*t & 255)) + 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 */ + + +#ifndef HAVE_STRLCAT +/* + * '_cups_strlcat()' - Safely concatenate two strings. + */ + +size_t /* O - Length of string */ +_cups_strlcat(char *dst, /* O - Destination string */ + const char *src, /* I - Source string */ + size_t size) /* I - Size of destination string buffer */ +{ + size_t srclen; /* Length of source string */ + size_t dstlen; /* Length of destination string */ + + + /* + * Figure out how much room is left... + */ + + dstlen = strlen(dst); + size -= dstlen + 1; + + if (!size) + return (dstlen); /* No room, return immediately... */ + + /* + * Figure out how much room is needed... + */ + + srclen = strlen(src); + + /* + * Copy the appropriate amount... + */ + + if (srclen > size) + srclen = size; + + memcpy(dst + dstlen, src, srclen); + dst[dstlen + srclen] = '\0'; + + return (dstlen + srclen); +} +#endif /* !HAVE_STRLCAT */ + + +#ifndef HAVE_STRLCPY +/* + * '_cups_strlcpy()' - Safely copy two strings. + */ + +size_t /* O - Length of string */ +_cups_strlcpy(char *dst, /* O - Destination string */ + const char *src, /* I - Source string */ + size_t size) /* I - Size of destination string buffer */ +{ + size_t srclen; /* Length of source string */ + + + /* + * Figure out how much room is needed... + */ + + size --; + + srclen = strlen(src); + + /* + * Copy the appropriate amount... + */ + + if (srclen > size) + srclen = size; + + memcpy(dst, src, srclen); + dst[srclen] = '\0'; + + return (srclen); +} +#endif /* !HAVE_STRLCPY */ + + +/* + * End of "$Id: string.c 4683 2005-09-21 22:17:44Z mike $". + */ diff --git a/cups/string.h b/cups/string.h new file mode 100644 index 000000000..5d2e778f0 --- /dev/null +++ b/cups/string.h @@ -0,0 +1,130 @@ +/* + * "$Id: string.h 4683 2005-09-21 22:17:44Z mike $" + * + * String definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_STRING_H_ +# define _CUPS_STRING_H_ + +/* + * Include necessary headers... + */ + +# include + +# include +# include +# include + +# ifdef HAVE_STRING_H +# include +# endif /* HAVE_STRING_H */ + +# ifdef HAVE_STRINGS_H +# include +# endif /* HAVE_STRINGS_H */ + +# ifdef HAVE_BSTRING_H +# include +# endif /* HAVE_BSTRING_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... + */ + +extern void _cups_strcpy(char *dst, const char *src); + +# ifndef HAVE_STRDUP +extern char *_cups_strdup(const char *); +# define strdup _cups_strdup +# endif /* !HAVE_STRDUP */ + +# ifndef HAVE_STRCASECMP +extern int _cups_strcasecmp(const char *, const char *); +# define strcasecmp _cups_strcasecmp +# endif /* !HAVE_STRCASECMP */ + +# ifndef HAVE_STRNCASECMP +extern int _cups_strncasecmp(const char *, const char *, size_t n); +# define strncasecmp _cups_strncasecmp +# endif /* !HAVE_STRNCASECMP */ + +# ifndef HAVE_STRLCAT +extern size_t _cups_strlcat(char *, const char *, size_t); +# define strlcat _cups_strlcat +# endif /* !HAVE_STRLCAT */ + +# ifndef HAVE_STRLCPY +extern size_t _cups_strlcpy(char *, const char *, size_t); +# define strlcpy _cups_strlcpy +# endif /* !HAVE_STRLCPY */ + +# ifndef HAVE_SNPRINTF +extern int _cups_snprintf(char *, size_t, const char *, ...) +# ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 3, 4))) +# endif /* __GNUC__ */ +; +# define snprintf _cups_snprintf +# endif /* !HAVE_SNPRINTF */ + +# ifndef HAVE_VSNPRINTF +extern int _cups_vsnprintf(char *, size_t, const char *, va_list); +# define vsnprintf _cups_vsnprintf +# endif /* !HAVE_VSNPRINTF */ + + +/* + * C++ magic... + */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_STRING_H_ */ + +/* + * End of "$Id: string.h 4683 2005-09-21 22:17:44Z mike $". + */ diff --git a/cups/tempfile.c b/cups/tempfile.c new file mode 100644 index 000000000..0e64565b0 --- /dev/null +++ b/cups/tempfile.c @@ -0,0 +1,240 @@ +/* + * "$Id: tempfile.c 4918 2006-01-12 05:14:40Z mike $" + * + * Temp file utilities for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsTempFd() - Create a temporary file. + * cupsTempFile() - Generate a temporary filename. + * cupsTempFile2() - Create a temporary CUPS file. + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include "debug.h" +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * 'cupsTempFd()' - Create a temporary file. + * + * The temporary filename is stored in the filename buffer. + */ + +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 */ + int tries; /* Number of tries */ + const char *tmpdir; /* TMPDIR environment var */ +#ifdef WIN32 + char tmppath[1024]; /* Windows temporary directory */ + DWORD curtime; /* Current time */ +#else + struct timeval curtime; /* Current time */ +#endif /* WIN32 */ + + + /* + * See if TMPDIR is defined... + */ + +#ifdef WIN32 + if ((tmpdir = getenv("TEMP")) == NULL) + { + GetTempPath(sizeof(tmppath), tmppath); + tmpdir = tmppath; + } +#else + if ((tmpdir = getenv("TMPDIR")) == NULL) + { + /* + * Put root temp files in restricted temp directory... + */ + + if (getuid() == 0) + tmpdir = CUPS_REQUESTS "/tmp"; + else + tmpdir = "/tmp"; + } +#endif /* WIN32 */ + + /* + * Make the temporary name using the specified directory... + */ + + tries = 0; + + do + { +#ifdef WIN32 + /* + * Get the current time of day... + */ + + curtime = GetTickCount() + tries; + + /* + * Format a string using the hex time values... + */ + + snprintf(filename, len - 1, "%s/%05lx%08lx", tmpdir, + GetCurrentProcessId(), 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, + (unsigned long)curtime.tv_sec, (unsigned long)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 WIN32 + fd = open(filename, _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY, + _S_IREAD | _S_IWRITE); +#elif defined(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 /* WIN32 */ + + if (fd < 0 && errno != EEXIST) + break; + + tries ++; + } + while (fd < 0 && tries < 1000); + + /* + * Return the file descriptor... + */ + + return (fd); +} + + +/* + * 'cupsTempFile()' - Generate a temporary filename. + * + * The temporary filename is stored in the filename buffer. + * This function is deprecated - use cupsTempFd() or cupsTempFile2() + * instead. + * + * @deprecated@ + */ + +char * /* O - Filename */ +cupsTempFile(char *filename, /* I - Pointer to buffer */ + int len) /* I - Size of buffer */ +{ + int fd; /* File descriptor for temp file */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * See if a filename was specified... + */ + + if (filename == NULL) + { + filename = cg->tempfile; + len = sizeof(cg->tempfile); + } + + /* + * 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); +} + + +/* + * 'cupsTempFile2()' - Create a temporary CUPS file. + * + * The temporary filename is stored in the filename buffer. + * + * @since CUPS 1.2@ + */ + +cups_file_t * /* O - CUPS file or NULL on error */ +cupsTempFile2(char *filename, /* I - Pointer to buffer */ + int len) /* I - Size of buffer */ +{ + cups_file_t *file; /* CUPS file */ + int fd; /* File descriptor */ + + + if ((fd = cupsTempFd(filename, len)) < 0) + return (NULL); + else if ((file = cupsFileOpenFd(fd, "w")) == NULL) + { + close(fd); + unlink(filename); + return (NULL); + } + else + return (file); +} + + +/* + * End of "$Id: tempfile.c 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/testarray.c b/cups/testarray.c new file mode 100644 index 000000000..8dcbf7a37 --- /dev/null +++ b/cups/testarray.c @@ -0,0 +1,513 @@ +/* + * "$Id: testarray.c 4903 2006-01-10 20:02:46Z mike $" + * + * Array test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Main entry. + * get_seconds() - Get the current time in seconds... + * load_words() - Load words from a file. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include "array.h" +#include "dir.h" +#include "debug.h" + + +/* + * Local functions... + */ + +static double get_seconds(void); +static int load_words(const char *filename, cups_array_t *array); + + +/* + * '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 */ + cups_array_t *array, /* Test array */ + *dup_array; /* Duplicate array */ + int status; /* Exit status */ + char *text; /* Text from array */ + char word[256]; /* Word from file */ + double start, /* Start time */ + end; /* End time */ + cups_dir_t *dir; /* Current directory */ + cups_dentry_t *dent; /* Directory entry */ + char *saved[32]; /* Saved entries */ + + + /* + * No errors so far... + */ + + status = 0; + + /* + * cupsArrayNew() + */ + + fputs("cupsArrayNew: ", stdout); + + array = cupsArrayNew((cups_array_func_t)strcmp, NULL); + + if (array) + puts("PASS"); + else + { + puts("FAIL (returned NULL, expected pointer)"); + status ++; + } + + /* + * cupsArrayAdd() + */ + + fputs("cupsArrayAdd: ", stdout); + + if (!cupsArrayAdd(array, strdup("One Fish"))) + { + puts("FAIL (\"One Fish\")"); + status ++; + } + else + { +#ifdef DEBUG + putchar('\n'); + for (text = (char *)cupsArrayFirst(array), i = 0; + text; + text = (char *)cupsArrayNext(array), i ++) + printf(" #1 array[%d]=\"%s\"\n", i, text); +#endif /* DEBUG */ + + if (!cupsArrayAdd(array, strdup("Two Fish"))) + { + puts("FAIL (\"Two Fish\")"); + status ++; + } + else + { +#ifdef DEBUG + for (text = (char *)cupsArrayFirst(array), i = 0; + text; + text = (char *)cupsArrayNext(array), i ++) + printf(" #2 array[%d]=\"%s\"\n", i, text); +#endif /* DEBUG */ + + if (!cupsArrayAdd(array, strdup("Red Fish"))) + { + puts("FAIL (\"Red Fish\")"); + status ++; + } + else + { +#ifdef DEBUG + for (text = (char *)cupsArrayFirst(array), i = 0; + text; + text = (char *)cupsArrayNext(array), i ++) + printf(" #3 array[%d]=\"%s\"\n", i, text); +#endif /* DEBUG */ + + if (!cupsArrayAdd(array, strdup("Blue Fish"))) + { + puts("FAIL (\"Blue Fish\")"); + status ++; + } + else + { +#ifdef DEBUG + for (text = (char *)cupsArrayFirst(array), i = 0; + text; + text = (char *)cupsArrayNext(array), i ++) + printf(" #4 array[%d]=\"%s\"\n", i, text); +#endif /* DEBUG */ + + puts("PASS"); + } + } + } + } + + /* + * cupsArrayCount() + */ + + fputs("cupsArrayCount: ", stdout); + if (cupsArrayCount(array) == 4) + puts("PASS"); + else + { + printf("FAIL (returned %d, expected 4)\n", cupsArrayCount(array)); + status ++; + } + + /* + * cupsArrayFirst() + */ + + fputs("cupsArrayFirst: ", stdout); + if ((text = (char *)cupsArrayFirst(array)) != NULL && + !strcmp(text, "Blue Fish")) + puts("PASS"); + else + { + printf("FAIL (returned \"%s\", expected \"Blue Fish\")\n", text); + status ++; + } + + /* + * cupsArrayNext() + */ + + fputs("cupsArrayNext: ", stdout); + if ((text = (char *)cupsArrayNext(array)) != NULL && + !strcmp(text, "One Fish")) + puts("PASS"); + else + { + printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text); + status ++; + } + + /* + * cupsArrayLast() + */ + + fputs("cupsArrayLast: ", stdout); + if ((text = (char *)cupsArrayLast(array)) != NULL && + !strcmp(text, "Two Fish")) + puts("PASS"); + else + { + printf("FAIL (returned \"%s\", expected \"Two Fish\")\n", text); + status ++; + } + + /* + * cupsArrayPrev() + */ + + fputs("cupsArrayPrev: ", stdout); + if ((text = (char *)cupsArrayPrev(array)) != NULL && + !strcmp(text, "Red Fish")) + puts("PASS"); + else + { + printf("FAIL (returned \"%s\", expected \"Red Fish\")\n", text); + status ++; + } + + /* + * cupsArrayFind() + */ + + fputs("cupsArrayFind: ", stdout); + if ((text = (char *)cupsArrayFind(array, (void *)"One Fish")) != NULL && + !strcmp(text, "One Fish")) + puts("PASS"); + else + { + printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text); + status ++; + } + + /* + * cupsArrayCurrent() + */ + + fputs("cupsArrayCurrent: ", stdout); + if ((text = (char *)cupsArrayCurrent(array)) != NULL && + !strcmp(text, "One Fish")) + puts("PASS"); + else + { + printf("FAIL (returned \"%s\", expected \"One Fish\")\n", text); + status ++; + } + + /* + * cupsArrayDup() + */ + + fputs("cupsArrayDup: ", stdout); + if ((dup_array = cupsArrayDup(array)) != NULL && + cupsArrayCount(dup_array) == 4) + puts("PASS"); + else + { + printf("FAIL (returned %p with %d elements, expected pointer with 4 elements)\n", + dup_array, cupsArrayCount(dup_array)); + status ++; + } + + /* + * cupsArrayRemove() + */ + + fputs("cupsArrayRemove: ", stdout); + if (cupsArrayRemove(array, (void *)"One Fish") && + cupsArrayCount(array) == 3) + puts("PASS"); + else + { + printf("FAIL (returned 0 with %d elements, expected 1 with 4 elements)\n", + cupsArrayCount(array)); + status ++; + } + + /* + * cupsArrayClear() + */ + + fputs("cupsArrayClear: ", stdout); + cupsArrayClear(array); + if (cupsArrayCount(array) == 0) + puts("PASS"); + else + { + printf("FAIL (%d elements, expected 0 elements)\n", + cupsArrayCount(array)); + status ++; + } + + /* + * Now load this source file and grab all of the unique words... + */ + + fputs("Load unique words: ", stdout); + fflush(stdout); + + start = get_seconds(); + + if ((dir = cupsDirOpen(".")) == NULL) + { + puts("FAIL (cupsDirOpen failed)"); + status ++; + } + else + { + while ((dent = cupsDirRead(dir)) != NULL) + { + i = strlen(dent->filename) - 2; + + if (i > 0 && dent->filename[i] == '.' && + (dent->filename[i + 1] == 'c' || + dent->filename[i + 1] == 'h')) + load_words(dent->filename, array); + } + + cupsDirClose(dir); + + end = get_seconds(); + + printf("%d words in %.3f seconds (%.0f words/sec), ", cupsArrayCount(array), + end - start, cupsArrayCount(array) / (end - start)); + fflush(stdout); + + for (text = (char *)cupsArrayFirst(array); text;) + { + /* + * Copy this word to the word buffer (safe because we strdup'd from + * the same buffer in the first place... :) + */ + + strcpy(word, text); + + /* + * Grab the next word and compare... + */ + + if ((text = (char *)cupsArrayNext(array)) == NULL) + break; + + if (strcmp(word, text) >= 0) + break; + } + + if (text) + { + printf("FAIL (\"%s\" >= \"%s\"!)\n", word, text); + status ++; + } + else + puts("PASS"); + } + + /* + * Test deleting with iteration... + */ + + fputs("Delete While Iterating: ", stdout); + + text = (char *)cupsArrayFirst(array); + cupsArrayRemove(array, text); + free(text); + + text = (char *)cupsArrayNext(array); + if (!text) + { + puts("FAIL (cupsArrayNext returned NULL!)"); + status ++; + } + else + puts("PASS"); + + /* + * Test save/restore... + */ + + fputs("cupsArraySave: ", stdout); + + for (i = 0, text = (char *)cupsArrayFirst(array); + i < 32; + i ++, text = (char *)cupsArrayNext(array)) + { + saved[i] = text; + + if (!cupsArraySave(array)) + break; + } + + if (i < 32) + printf("FAIL (depth = %d)\n", i); + else + puts("PASS"); + + fputs("cupsArrayRestore: ", stdout); + + while (i > 0) + { + i --; + + text = cupsArrayRestore(array); + if (text != saved[i]) + break; + } + + if (i) + printf("FAIL (depth = %d)\n", i); + else + puts("PASS"); + + /* + * Delete the arrays... + */ + + cupsArrayDelete(array); + cupsArrayDelete(dup_array); + + /* + * Summarize the results and return... + */ + + if (!status) + puts("\nALL TESTS PASSED!"); + else + printf("\n%d TEST(S) FAILED!\n", status); + + return (status); +} + + +/* + * 'get_seconds()' - Get the current time in seconds... + */ + +#ifdef WIN32 +# include + + +static double +get_seconds(void) +{ +} +#else +# include + + +static double +get_seconds(void) +{ + struct timeval curtime; /* Current time */ + + + gettimeofday(&curtime, NULL); + return (curtime.tv_sec + 0.000001 * curtime.tv_usec); +} +#endif /* WIN32 */ + + +/* + * 'load_words()' - Load words from a file. + */ + +static int /* O - 1 on success, 0 on failure */ +load_words(const char *filename, /* I - File to load */ + cups_array_t *array) /* I - Array to add to */ +{ + FILE *fp; /* Test file */ + char word[256]; /* Word from file */ + + + DEBUG_printf((" Loading \"%s\"...\n", filename)); + + if ((fp = fopen(filename, "r")) == NULL) + { + perror(filename); + return (0); + } + + while (fscanf(fp, "%255s", word) == 1) + { + if (!cupsArrayFind(array, word)) + { + DEBUG_printf((" Adding \"%s\"...\n", word)); + + cupsArrayAdd(array, strdup(word)); + } + } + + fclose(fp); + + return (1); +} + + +/* + * End of "$Id: testarray.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/cups/testfile.c b/cups/testfile.c new file mode 100644 index 000000000..de50fc5e2 --- /dev/null +++ b/cups/testfile.c @@ -0,0 +1,400 @@ +/* + * "$Id: testfile.c 4754 2005-10-08 04:01:46Z mike $" + * + * File test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Main entry. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include "string.h" +#include "file.h" +#include "debug.h" +#include + + +/* + * Local functions... + */ + +static int read_write_tests(int compression); + + +/* + * 'main()' - Main entry. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int status; /* Exit status */ + + + /* + * Do uncompressed file tests... + */ + + status = read_write_tests(0); + +#ifdef HAVE_LIBZ + /* + * Do compressed file tests... + */ + + putchar('\n'); + + status += read_write_tests(1); +#endif /* HAVE_LIBZ */ + + /* + * Summarize the results and return... + */ + + if (!status) + puts("\nALL TESTS PASSED!"); + else + printf("\n%d TEST(S) FAILED!\n", status); + + return (status); +} + + +/* + * 'read_write_tests()' - Perform read/write tests. + */ + +static int /* O - Status */ +read_write_tests(int compression) /* I - Use compression? */ +{ + int i; /* Looping var */ + cups_file_t *fp; /* First file */ + int status; /* Exit status */ + char line[1024], /* Line from file */ + *value; /* Directive value from line */ + int linenum; /* Line number */ + unsigned char readbuf[8192], /* Read buffer */ + writebuf[8192]; /* Write buffer */ + int byte; /* Byte from file */ + + + /* + * No errors so far... + */ + + status = 0; + + /* + * Initialize the write buffer with random data... + */ + + srand(time(NULL)); + for (i = 0; i < (int)sizeof(writebuf); i ++) + writebuf[i] = rand(); + + /* + * cupsFileOpen(write) + */ + + printf("cupsFileOpen(write%s): ", compression ? " compressed" : ""); + + fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat", + compression ? "w9" : "w"); + if (fp) + { + puts("PASS"); + + /* + * cupsFileCompression() + */ + + fputs("cupsFileCompression(): ", stdout); + + if (cupsFileCompression(fp) == compression) + puts("PASS"); + else + { + printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp), + compression); + status ++; + } + + /* + * cupsFilePuts() + */ + + fputs("cupsFilePuts(): ", stdout); + + if (cupsFilePuts(fp, "# Hello, World\n") > 0) + puts("PASS"); + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsFilePrintf() + */ + + fputs("cupsFilePrintf(): ", stdout); + + for (i = 0; i < 1000; i ++) + if (cupsFilePrintf(fp, "TestLine %d\n", i) < 0) + break; + + if (i >= 1000) + puts("PASS"); + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsFilePutChar() + */ + + fputs("cupsFilePutChar(): ", stdout); + + for (i = 0; i < 256; i ++) + if (cupsFilePutChar(fp, i) < 0) + break; + + if (i >= 256) + puts("PASS"); + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsFileWrite() + */ + + fputs("cupsFileWrite(): ", stdout); + + for (i = 0; i < 100; i ++) + if (cupsFileWrite(fp, (char *)writebuf, sizeof(writebuf)) < 0) + break; + + if (i >= 100) + puts("PASS"); + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsFileClose() + */ + + fputs("cupsFileClose(): ", stdout); + + if (!cupsFileClose(fp)) + puts("PASS"); + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + } + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsFileOpen(read) + */ + + fputs("cupsFileOpen(read): ", stdout); + + fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat", "r"); + if (fp) + { + puts("PASS"); + + /* + * cupsFileGets() + */ + + fputs("cupsFileGets(): ", stdout); + + if (cupsFileGets(fp, line, sizeof(line))) + { + if (line[0] == '#') + puts("PASS"); + else + { + printf("FAIL (Got line \"%s\", expected comment line)\n", line); + status ++; + } + } + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsFileCompression() + */ + + fputs("cupsFileCompression(): ", stdout); + + if (cupsFileCompression(fp) == compression) + puts("PASS"); + else + { + printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp), + compression); + status ++; + } + + /* + * cupsFileGetConf() + */ + + linenum = 1; + + fputs("cupsFileGetConf(): ", stdout); + + for (i = 0; i < 1000; i ++) + if (!cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + break; + else if (strcasecmp(line, "TestLine") || !value || atoi(value) != i || + linenum != (i + 2)) + break; + + if (i >= 1000) + puts("PASS"); + else if (line[0]) + { + printf("FAIL (Line %d, directive \"%s\", value \"%s\")\n", linenum, + line, value ? value : "(null)"); + status ++; + } + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsGetChar() + */ + + fputs("cupsGetChar(): ", stdout); + + for (i = 0; i < 256; i ++) + if ((byte = cupsFileGetChar(fp)) != i) + break; + + if (i >= 256) + puts("PASS"); + else if (byte >= 0) + { + printf("FAIL (Got %d, expected %d)\n", byte, i); + status ++; + } + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsFileRead() + */ + + fputs("cupsFileRead(): ", stdout); + + for (i = 0; i < 100; i ++) + if ((byte = cupsFileRead(fp, (char *)readbuf, sizeof(readbuf))) < 0) + break; + else if (memcmp(readbuf, writebuf, sizeof(readbuf))) + break; + + if (i >= 100) + puts("PASS"); + else if (byte > 0) + { + printf("FAIL (Pass %d, ", i); + + for (i = 0; i < (int)sizeof(readbuf); i ++) + if (readbuf[i] != writebuf[i]) + break; + + printf("match failed at offset %d - got %02X, expected %02X)\n", + i, readbuf[i], writebuf[i]); + } + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * cupsFileClose() + */ + + fputs("cupsFileClose(): ", stdout); + + if (!cupsFileClose(fp)) + puts("PASS"); + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + } + else + { + printf("FAIL (%s)\n", strerror(errno)); + status ++; + } + + /* + * Return the test status... + */ + + return (status); +} + + +/* + * End of "$Id: testfile.c 4754 2005-10-08 04:01:46Z mike $". + */ diff --git a/cups/testhttp.c b/cups/testhttp.c new file mode 100644 index 000000000..57e94c900 --- /dev/null +++ b/cups/testhttp.c @@ -0,0 +1,514 @@ +/* + * "$Id: testhttp.c 4809 2005-10-21 19:43:55Z mike $" + * + * HTTP test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Main entry. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "http.h" +#include "string.h" + + +/* + * Types and structures... + */ + +typedef struct uri_test_s /**** URI test cases ****/ +{ + http_uri_status_t result; /* Expected return value */ + const char *uri, /* URI */ + *scheme, /* Scheme string */ + *username, /* Username:password string */ + *hostname, /* Hostname string */ + *resource; /* Resource string */ + int port, /* Port number */ + assemble_port; /* Port number for httpAssembleURI() */ +} uri_test_t; + + +/* + * Local globals... + */ + +static uri_test_t uri_tests[] = /* URI test data */ + { + /* Start with valid URIs */ + { HTTP_URI_OK, "file:/filename", + "file", "", "", "/filename", 0, 0 }, + { HTTP_URI_OK, "file:/filename%20with%20spaces", + "file", "", "", "/filename with spaces", 0, 0 }, + { HTTP_URI_OK, "file:///filename", + "file", "", "", "/filename", 0, 0 }, + { HTTP_URI_OK, "file:///filename%20with%20spaces", + "file", "", "", "/filename with spaces", 0, 0 }, + { HTTP_URI_OK, "file://localhost/filename", + "file", "", "localhost", "/filename", 0, 0 }, + { HTTP_URI_OK, "file://localhost/filename%20with%20spaces", + "file", "", "localhost", "/filename with spaces", 0, 0 }, + { HTTP_URI_OK, "http://server/", + "http", "", "server", "/", 80, 0 }, + { HTTP_URI_OK, "http://username@server/", + "http", "username", "server", "/", 80, 0 }, + { HTTP_URI_OK, "http://username:passwor%64@server/", + "http", "username:password", "server", "/", 80, 0 }, + { HTTP_URI_OK, "http://username:passwor%64@server:8080/", + "http", "username:password", "server", "/", 8080, 8080 }, + { HTTP_URI_OK, "http://username:passwor%64@server:8080/directory/filename", + "http", "username:password", "server", "/directory/filename", 8080, 8080 }, + { HTTP_URI_OK, "https://username:passwor%64@server/directory/filename", + "https", "username:password", "server", "/directory/filename", 443, 0 }, + { HTTP_URI_OK, "ipp://username:passwor%64@[::1]/ipp", + "ipp", "username:password", "::1", "/ipp", 631, 0 }, + { HTTP_URI_OK, "lpd://server/queue?reserve=yes", + "lpd", "", "server", "/queue?reserve=yes", 515, 0 }, + { HTTP_URI_OK, "mailto:user@domain.com", + "mailto", "", "", "user@domain.com", 0, 0 }, + { HTTP_URI_OK, "socket://server/", + "socket", "", "server", "/", 9100, 0 }, + { HTTP_URI_OK, "ipp://username:password@[v1.fe80::200:1234:5678:9abc+eth0]:999/ipp", + "ipp", "username:password", "fe80::200:1234:5678:9abc%eth0", "/ipp", 999, 999 }, + + /* Missing scheme */ + { HTTP_URI_MISSING_SCHEME, "/path/to/file/index.html", + "file", "", "", "/path/to/file/index.html", 0, 0 }, + { HTTP_URI_MISSING_SCHEME, "//server/ipp", + "ipp", "", "server", "/ipp", 631, 0 }, + + /* Unknown scheme */ + { HTTP_URI_UNKNOWN_SCHEME, "vendor://server/resource", + "vendor", "", "server", "/resource", 0, 0 }, + + /* Missing resource */ + { HTTP_URI_MISSING_RESOURCE, "socket://[::192.168.2.1]", + "socket", "", "::192.168.2.1", "/", 9100, 0 }, + + /* Bad URI */ + { HTTP_URI_BAD_URI, "", + "", "", "", "", 0, 0 }, + + /* Bad scheme */ + { HTTP_URI_BAD_SCHEME, "bad_scheme://server/resource", + "", "", "", "", 0, 0 }, + + /* Bad username */ + { HTTP_URI_BAD_USERNAME, "http://username:passwor%6@server/resource", + "http", "", "", "", 80, 0 }, + + /* Bad hostname */ + { HTTP_URI_BAD_HOSTNAME, "http://[/::1]/index.html", + "http", "", "", "", 80, 0 }, + { HTTP_URI_BAD_HOSTNAME, "http://[", + "http", "", "", "", 80, 0 }, + { HTTP_URI_BAD_HOSTNAME, "http://serve%7/index.html", + "http", "", "", "", 80, 0 }, + + /* Bad port number */ + { HTTP_URI_BAD_PORT, "http://127.0.0.1:9999a/index.html", + "http", "", "127.0.0.1", "", 0, 0 }, + + /* Bad resource */ + { HTTP_URI_BAD_RESOURCE, "http://server/index.html%", + "http", "", "server", "", 80, 0 } + }; +static const char * const base64_tests[][2] = + { + { "A", "QQ==" }, + /* 010000 01 */ + { "AB", "QUI=" }, + /* 010000 010100 0010 */ + { "ABC", "QUJD" }, + /* 010000 010100 001001 000011 */ + { "ABCD", "QUJDRA==" }, + /* 010000 010100 001001 000011 010001 00 */ + { "ABCDE", "QUJDREU=" }, + /* 010000 010100 001001 000011 010001 000100 0101 */ + { "ABCDEF", "QUJDREVG" }, + /* 010000 010100 001001 000011 010001 000100 010101 000110 */ + }; + + +/* + * '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, k; /* Looping vars */ + http_t *http; /* HTTP connection */ + http_status_t status; /* Status of GET command */ + int failures; /* Number of test failures */ + char buffer[8192]; /* Input buffer */ + long bytes; /* Number of bytes read */ + FILE *out; /* Output file */ + char encode[256], /* Base64-encoded string */ + decode[256]; /* Base64-decoded string */ + int decodelen; /* Length of decoded string */ + char scheme[HTTP_MAX_URI], /* Scheme from URI */ + hostname[HTTP_MAX_URI], /* Hostname from URI */ + username[HTTP_MAX_URI], /* Username:password from URI */ + resource[HTTP_MAX_URI]; /* Resource from URI */ + int port; /* Port number from URI */ + http_uri_status_t uri_status; /* Status of URI separation */ + http_addrlist_t *addrlist, /* Address list */ + *addr; /* Current address */ + off_t length, total; /* Length and total bytes */ + time_t start, current; /* Start and end time */ + static const char * const uri_status_strings[] = + { + "HTTP_URI_OVERFLOW", + "HTTP_URI_BAD_ARGUMENTS", + "HTTP_URI_BAD_RESOURCE", + "HTTP_URI_BAD_PORT", + "HTTP_URI_BAD_HOSTNAME", + "HTTP_URI_BAD_USERNAME", + "HTTP_URI_BAD_SCHEME", + "HTTP_URI_BAD_URI", + "HTTP_URI_OK", + "HTTP_URI_MISSING_SCHEME", + "HTTP_URI_UNKNOWN_SCHEME", + "HTTP_URI_MISSING_RESOURCE" + }; + + + /* + * Do API tests if we don't have a URL on the command-line... + */ + + if (argc == 1) + { + failures = 0; + + /* + * httpGetDateString()/httpGetDateTime() + */ + + fputs("httpGetDateString()/httpGetDateTime(): ", stdout); + + start = time(NULL); + strcpy(buffer, httpGetDateString(start)); + current = httpGetDateTime(buffer); + + i = (int)(current - start); + if (i < 0) + i = -i; + + if (!i) + puts("PASS"); + else + { + failures ++; + puts("FAIL"); + printf(" Difference is %d seconds, %02d:%02d:%02d...\n", i, i / 3600, + (i / 60) % 60, i % 60); + printf(" httpGetDateString(%d) returned \"%s\"\n", (int)start, buffer); + printf(" httpGetDateTime(\"%s\") returned %d\n", buffer, (int)current); + printf(" httpGetDateString(%d) returned \"%s\"\n", (int)current, + httpGetDateString(current)); + } + + /* + * httpDecode64_2()/httpEncode64_2() + */ + + fputs("httpDecode64_2()/httpEncode64_2(): ", stdout); + + for (i = 0, j = 0; i < (int)(sizeof(base64_tests) / sizeof(base64_tests[0])); i ++) + { + httpEncode64_2(encode, sizeof(encode), base64_tests[i][0], + strlen(base64_tests[i][0])); + decodelen = (int)sizeof(decode); + httpDecode64_2(decode, &decodelen, base64_tests[i][1]); + + if (strcmp(decode, base64_tests[i][0])) + { + failures ++; + + if (j) + { + puts("FAIL"); + j = 1; + } + + printf(" httpDecode64_2() returned \"%s\", expected \"%s\"...\n", + decode, base64_tests[i][0]); + } + + if (strcmp(encode, base64_tests[i][1])) + { + failures ++; + + if (j) + { + puts("FAIL"); + j = 1; + } + + printf(" httpEncode64_2() returned \"%s\", expected \"%s\"...\n", + encode, base64_tests[i][1]); + } + } + + if (!j) + puts("PASS"); + + /* + * httpGetHostname() + */ + + fputs("httpGetHostname(): ", stdout); + + if (httpGetHostname(hostname, sizeof(hostname))) + printf("PASS (%s)\n", hostname); + else + { + failures ++; + puts("FAIL"); + } + + /* + * httpAddrGetList() + */ + + fputs("httpAddrGetList(): ", stdout); + + addrlist = httpAddrGetList(hostname, AF_UNSPEC, NULL); + if (addrlist) + { + for (i = 0, addr = addrlist; addr; i ++, addr = addr->next); + + printf("PASS (%d address(es) for %s)\n", i, hostname); + httpAddrFreeList(addrlist); + } + else + { + failures ++; + puts("FAIL"); + } + + /* + * Test httpSeparateURI()... + */ + + fputs("httpSeparateURI(): ", stdout); + for (i = 0, j = 0; i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); i ++) + { + uri_status = httpSeparateURI(uri_tests[i].uri, scheme, sizeof(scheme), + username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + if (uri_status != uri_tests[i].result || + strcmp(scheme, uri_tests[i].scheme) || + strcmp(username, uri_tests[i].username) || + strcmp(hostname, uri_tests[i].hostname) || + port != uri_tests[i].port || + strcmp(resource, uri_tests[i].resource)) + { + failures ++; + + if (!j) + { + puts("FAIL"); + j = 1; + } + + printf(" \"%s\":\n", uri_tests[i].uri); + + if (uri_status != uri_tests[i].result) + printf(" Returned %s instead of %s\n", + uri_status_strings[uri_status + 8], + uri_status_strings[uri_tests[i].result + 8]); + + if (strcmp(scheme, uri_tests[i].scheme)) + printf(" Scheme \"%s\" instead of \"%s\"\n", + scheme, uri_tests[i].scheme); + + if (strcmp(username, uri_tests[i].username)) + printf(" Username \"%s\" instead of \"%s\"\n", + username, uri_tests[i].username); + + if (strcmp(hostname, uri_tests[i].hostname)) + printf(" Hostname \"%s\" instead of \"%s\"\n", + hostname, uri_tests[i].hostname); + + if (port != uri_tests[i].port) + printf(" Port %d instead of %d\n", + port, uri_tests[i].port); + + if (strcmp(resource, uri_tests[i].resource)) + printf(" Resource \"%s\" instead of \"%s\"\n", + resource, uri_tests[i].resource); + } + } + + if (!j) + printf("PASS (%d URIs tested)\n", + (int)(sizeof(uri_tests) / sizeof(uri_tests[0]))); + + /* + * Test httpAssembleURI()... + */ + + fputs("httpAssembleURI(): ", stdout); + for (i = 0, j = 0, k = 0; + i < (int)(sizeof(uri_tests) / sizeof(uri_tests[0])); + i ++) + if (uri_tests[i].result == HTTP_URI_OK && + !strstr(uri_tests[i].uri, "%64") && + strstr(uri_tests[i].uri, "//")) + { + k ++; + uri_status = httpAssembleURI(buffer, sizeof(buffer), + uri_tests[i].scheme, + uri_tests[i].username, + uri_tests[i].hostname, + uri_tests[i].assemble_port, + uri_tests[i].resource); + + if (uri_status != HTTP_URI_OK) + { + failures ++; + + if (!j) + { + puts("FAIL"); + j = 1; + } + + printf(" \"%s\": %s\n", uri_tests[i].uri, + uri_status_strings[uri_status + 8]); + } + else if (strcmp(buffer, uri_tests[i].uri)) + { + failures ++; + + if (!j) + { + puts("FAIL"); + j = 1; + } + + printf(" \"%s\": assembled = \"%s\"\n", uri_tests[i].uri, + buffer); + } + } + + if (!j) + printf("PASS (%d URIs tested)\n", k); + + /* + * Show a summary and return... + */ + + if (failures) + printf("\n%d TESTS FAILED!\n", failures); + else + puts("\nALL TESTS PASSED!"); + + return (failures); + } + + /* + * Test HTTP GET requests... + */ + + http = NULL; + out = stdout; + + for (i = 1; i < argc; i ++) + { + if (!strcmp(argv[i], "-o")) + { + i ++; + if (i >= argc) + break; + + out = fopen(argv[i], "wb"); + continue; + } + + httpSeparateURI(argv[i], scheme, sizeof(scheme), username, sizeof(username), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + + http = httpConnectEncrypt(hostname, port, HTTP_ENCRYPT_IF_REQUESTED); + if (http == NULL) + { + perror(hostname); + 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 = httpGetLength2(http); + 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" CUPS_LLFMT "/" CUPS_LLFMT " bytes (" + CUPS_LLFMT " 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: testhttp.c 4809 2005-10-21 19:43:55Z mike $". + */ diff --git a/cups/testi18n.c b/cups/testi18n.c new file mode 100644 index 000000000..a141d80f4 --- /dev/null +++ b/cups/testi18n.c @@ -0,0 +1,791 @@ +/* + * "$Id: testi18n.c 4767 2005-10-10 19:23:23Z mike $" + * + * Internationalization test for Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are + * the property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the + * file "LICENSE.txt" which should have been included with this file. + * If this file is missing or damaged please contact Easy Software + * Products at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for internationalization test module. + * print_synopsis() - Print program synopsis (help). + * print_utf8() - Print UTF-8 string with (optional) message. + * print_utf16() - Print UTF-16 string with (optional) message. + * print_utf32() - Print UTF-32 string with (optional) message. + * test_transcode() - Test 'transcode.c' module. + * test_normalize() - Test 'normalize.c' module. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include + +#include "language.h" +#include "string.h" +#include "transcode.h" +#include "normalize.h" + + +/* + * Local Globals... + */ + +static const char *program_synopsis[] = /* Program help */ +{ + "testi18n [-vh]", + " -v verbose (print each called function and result)", + " -h help (print this synopsis)", + "", + "'testi18n' is a utility to test CUPS internationalization", + "Copyright 1997-2005 by Easy Software Products.", + NULL +}; +static int error_count = 0; /* Total error count */ + + +/* + * Local functions... + */ + +static void print_synopsis(void); +static void print_utf8(const char *msg, const cups_utf8_t *src); +static void print_utf16(const char *msg, const cups_utf16_t *src); +static void print_utf32(const char *msg, const cups_utf32_t *src); +static int test_transcode(const int verbose); +static int test_normalize(const int verbose); + + +/* + * 'main()' - Main entry for internationalization test module. + */ + +int /* O - Exit code */ +main(int argc, /* I - Argument Count */ + char *argv[]) /* I - Arguments */ +{ + int ai; /* Argument index */ + char *ap; /* Argument pointer */ + int verbose; /* Verbose flag */ + int errors; /* Error count */ + + + /* + * Check for switches... + */ + + verbose = 0; + + for (ai = 1; ai < argc; ai ++) + { + ap = argv[ai]; + if (*ap != '-') + break; + + for (ap ++; *ap != '\0'; ap ++) + { + switch (*ap) + { + case 'v': /* verbose */ + verbose = 1; + break; + + case 'h': /* help */ + print_synopsis(); + return (0); + + default: + print_synopsis(); + return (1); + } + } + } + + /* + * Test all internationalization modules and functions... + */ + + errors = test_transcode(verbose); + error_count += errors; + printf("\ntesti18n: %d errors found in 'transcode.c'\n", errors); + + errors = test_normalize(verbose); + error_count += errors; + printf("\ntesti18n: %d errors found in 'normalize.c'\n", errors); + + return (error_count > 0); +} + + +/* + * 'print_synopsis()' - Print program synopsis (help). + */ + +static void +print_synopsis(void) +{ + int i; /* Looping variable */ + + + for (i = 0; program_synopsis[i]; i ++) + puts(program_synopsis[i]); +} + + +/* + * 'print_utf8()' - Print UTF-8 string with (optional) message. + */ + +void +print_utf8(const char *msg, /* I - Message String */ + const cups_utf8_t *src) /* I - UTF-8 Source String */ +{ + if (msg != NULL) + printf("%s:", msg); + + for (; *src; src ++) + printf(" %02x", *src); + printf("\n"); + return; +} + + +/* + * 'print_utf16()' - Print UTF-16 string with (optional) message. + */ + +void +print_utf16(const char *msg, /* I - Message String */ + const cups_utf16_t *src) /* I - UTF-16 Source String */ +{ + if (msg != NULL) + printf("%s:", msg); + for (; *src; src ++) + printf(" %04x", (int) *src); + printf("\n"); + return; +} + + +/* + * 'print_utf32()' - Print UTF-32 string with (optional) message. + */ + +void +print_utf32(const char *msg, /* I - Message String */ + const cups_utf32_t *src) /* I - UTF-32 Source String */ +{ + if (msg != NULL) + printf("%s:", msg); + for (; *src; src ++) + printf(" %04x", (int) *src); + printf("\n"); + return; +} + + +/* + * 'test_transcode()' - Test 'transcode.c' module. + */ + +static int /* O - Zero or error count */ +test_transcode(const int verbose) /* I - Verbose flag */ +{ + FILE *fp; /* File pointer */ + int count; /* File line counter */ + char line[1024]; /* File line source string */ + int len; /* Length (count) of string */ + char legsrc[1024]; /* Legacy source string */ + char legdest[1024]; /* Legacy destination string */ + cups_utf8_t utf8latin[] = /* UTF-8 Latin-1 source */ + { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xC3, 0x84, 0x2E, 0x00 }; + /* "A != ." - use ISO 8859-1 */ + cups_utf8_t utf8repla[] = /* UTF-8 Latin-1 replacement */ + { 0x41, 0x20, 0xE2, 0x89, 0xA2, 0x20, 0xC3, 0x84, 0x2E, 0x00 }; + /* "A ." */ + cups_utf8_t utf8greek[] = /* UTF-8 Greek source string */ + { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xCE, 0x91, 0x2E, 0x00 }; + /* "A != ." - use ISO 8859-7 */ + cups_utf8_t utf8japan[] = /* UTF-8 Japanese source */ + { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xEE, 0x9C, 0x80, 0x2E, 0x00 }; + /* "A != ." - use Windows 932 or EUC-JP */ + cups_utf8_t utf8taiwan[] = /* UTF-8 Chinese source */ + { 0x41, 0x20, 0x21, 0x3D, 0x20, 0xE4, 0xB9, 0x82, 0x2E, 0x00 }; + /* "A != ." - use Windows 950 (Big5) or EUC-TW */ + cups_utf8_t utf8good[] = /* UTF-8 good 16-bit source */ + { 0x41, 0x20, 0xE2, 0x89, 0xA2, 0x20, 0xC3, 0x84, 0x2E, 0x00 }; + /* "A ." */ + cups_utf8_t utf8bad[] = /* UTF-8 bad 16-bit source */ + { 0x41, 0x20, 0xE2, 0x89, 0xA2, 0x20, 0xF8, 0x84, 0x2E, 0x00 }; + /* "A <...bad stuff...>." */ + cups_utf8_t utf8dest[1024]; /* UTF-8 destination string */ + cups_utf16_t utf16sur[] = /* UTF-16 with surrogates */ + { 0xD800, 0xDC00, 0x20, 0x21, 0x3D, 0x20, 0xC4, 0x2E, 0x00 }; + /* " != ." */ + cups_utf16_t utf16src[1024]; /* UTF-16 source string */ + cups_utf16_t utf16dest[1024]; /* UTF-16 destination string */ + cups_utf32_t utf32src[1024]; /* UTF-32 source string */ + cups_utf32_t utf32dest[1024]; /* UTF-32 destination string */ + _cups_vmap_t *vmap; /* VBCS charmap pointer */ + + + /* + * Test with (inserted) and (deleted) leading BOM... + */ + + if (verbose) + { + printf("\ntesti18n: Testing 'transcode.c'...\n"); + printf(" testing with insert/delete leading BOM...\n"); + } + + /* + * Test UTF-8 to UTF-32/EUC-JP on demo file... + */ + + if (verbose) + { + printf("\ntesti18n: Testing UTF-8 source 'utf8demo.txt'...\n"); + printf(" testing UTF-8 to UTF-32...\n"); + printf(" testing UTF-8 to EUC-JP...\n"); + } + + if ((fp = fopen("utf8demo.txt", "r")) == NULL) + return (1); + + for (count = 0;;) + { + if (fgets(line, 1024, fp) == NULL) + break; + + count ++; + + len = cupsUTF8ToUTF32(utf32dest, (cups_utf8_t *)line, 1024); + if (len < 0) + printf(" error line: %d (UTF-8 to UTF-32)\n", count); + + len = cupsUTF8ToCharset(legdest, (cups_utf8_t *)line, 1024, CUPS_EUC_JP); + if (len < 0) + printf(" error line: %d (UTF-8 to EUC-JP)\n", count); + } + + fclose(fp); + + if (verbose) + printf(" total lines: %d\n", count); + + /* + * Test VBCS charmap load for EUC-JP... + */ + + if (verbose) + printf("\ntesti18n: Loading VBCS charmap EUC-JP (Japanese)...\n"); + + vmap = (_cups_vmap_t *) cupsCharmapGet(CUPS_EUC_JP); + if (vmap == NULL) + return (1); + + if (verbose) + { + printf(" charcount: %d\n", vmap->charcount); + printf(" widecount: %d\n", vmap->widecount); + } + + /* + * Test VBCS charmap load for EUC-TW... + */ + + if (verbose) + printf("\ntesti18n: Loading VBCS charmap EUC-TW (Taiwan)...\n"); + + vmap = (_cups_vmap_t *) cupsCharmapGet(CUPS_EUC_TW); + if (vmap == NULL) + return (1); + + if (verbose) + { + printf(" charcount: %d\n", vmap->charcount); + printf(" widecount: %d\n", vmap->widecount); + } + + /* + * Test UTF-8 to legacy charset (ISO 8859-1)... + */ + + if (verbose) + printf("\ntesti18n: Testing UTF-8 to ISO 8859-1 (Latin1)...\n"); + + legdest[0] = 0; + + len = cupsUTF8ToCharset(legdest, utf8latin, 1024, CUPS_ISO8859_1); + if (len < 0) + return (1); + + if (verbose) + { + print_utf8(" utf8latin", utf8latin); + print_utf8(" legdest ", (cups_utf8_t *) legdest); + } + + strcpy(legsrc, legdest); + + len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_ISO8859_1); + + if (len < 0) + return (1); + + if (len != strlen ((char *) utf8latin)) + return (1); + + if (memcmp(utf8latin, utf8dest, len) != 0) + return (1); + + /* + * Test UTF-8 to Latin-1 (ISO 8859-1) with replacement... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 to ISO 8859-1 w/ replace...\n"); + len = cupsUTF8ToCharset(legdest, utf8repla, 1024, CUPS_ISO8859_1); + if (len < 0) + return (1); + if (verbose) + { + print_utf8(" utf8repla", utf8repla); + print_utf8(" legdest ", (cups_utf8_t *) legdest); + } + + /* + * Test UTF-8 to legacy charset (ISO 8859-7)... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 to ISO 8859-7 (Greek)...\n"); + legdest[0] = 0; + len = cupsUTF8ToCharset(legdest, utf8greek, 1024, CUPS_ISO8859_7); + if (len < 0) + return (1); + if (verbose) + { + print_utf8(" utf8greek", utf8greek); + print_utf8(" legdest ", (cups_utf8_t *) legdest); + } + strcpy(legsrc, legdest); + len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_ISO8859_7); + if (len < 0) + return (1); + if (len != strlen ((char *) utf8greek)) + return (1); + if (memcmp(utf8greek, utf8dest, len) != 0) + return (1); + + /* + * Test UTF-8 to legacy charset (Windows 932)... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 to Windows 932 (Japanese)...\n"); + legdest[0] = 0; + len = cupsUTF8ToCharset(legdest, utf8japan, 1024, CUPS_WINDOWS_932); + if (len < 0) + return (1); + if (verbose) + { + print_utf8(" utf8japan", utf8japan); + print_utf8(" legdest ", (cups_utf8_t *) legdest); + } + strcpy(legsrc, legdest); + len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_WINDOWS_932); + if (len < 0) + return (1); + if (len != strlen ((char *) utf8japan)) + return (1); + if (memcmp(utf8japan, utf8dest, len) != 0) + return (1); + + /* + * Test UTF-8 to legacy charset (EUC-JP)... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 to EUC-JP (Japanese)...\n"); + legdest[0] = 0; + len = cupsUTF8ToCharset(legdest, utf8japan, 1024, CUPS_EUC_JP); + if (len < 0) + return (1); + if (verbose) + { + print_utf8(" utf8japan", utf8japan); + print_utf8(" legdest ", (cups_utf8_t *) legdest); + } + strcpy(legsrc, legdest); + len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_EUC_JP); + if (len < 0) + return (1); + if (len != strlen ((char *) utf8japan)) + return (1); + if (memcmp(utf8japan, utf8dest, len) != 0) + return (1); + + /* + * Test UTF-8 to legacy charset (Windows 950)... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 to Windows 950 (Chinese)...\n"); + legdest[0] = 0; + len = cupsUTF8ToCharset(legdest, utf8taiwan, 1024, CUPS_WINDOWS_950); + if (len < 0) + return (1); + if (verbose) + { + print_utf8(" utf8taiwan", utf8taiwan); + print_utf8(" legdest ", (cups_utf8_t *) legdest); + } + strcpy(legsrc, legdest); + len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_WINDOWS_950); + if (len < 0) + return (1); + if (len != strlen ((char *) utf8taiwan)) + return (1); + if (memcmp(utf8taiwan, utf8dest, len) != 0) + return (1); + + /* + * Test UTF-8 to legacy charset (EUC-TW)... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 to EUC-TW (Chinese)...\n"); + legdest[0] = 0; + len = cupsUTF8ToCharset(legdest, utf8taiwan, 1024, CUPS_EUC_TW); + if (len < 0) + return (1); + if (verbose) + { + print_utf8(" utf8taiwan", utf8taiwan); + print_utf8(" legdest ", (cups_utf8_t *) legdest); + } + strcpy(legsrc, legdest); + len = cupsCharsetToUTF8(utf8dest, legsrc, 1024, CUPS_EUC_TW); + if (len < 0) + return (1); + if (len != strlen ((char *) utf8taiwan)) + return (1); + if (memcmp(utf8taiwan, utf8dest, len) != 0) + return (1); + + /* + * Test UTF-8 (16-bit) to UTF-32 (w/ BOM)... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 to UTF-32 (w/ BOM)...\n"); + len = cupsUTF8ToUTF32(utf32dest, utf8good, 1024); + if (len < 0) + return (1); + if (verbose) + { + print_utf8(" utf8good ", utf8good); + print_utf32(" utf32dest", utf32dest); + } + memcpy (utf32src, utf32dest, (len + 1) * sizeof(cups_utf32_t)); + len = cupsUTF32ToUTF8(utf8dest, utf32src, 1024); + if (len < 0) + return (1); + if (len != strlen ((char *) utf8good)) + return (1); + if (memcmp(utf8good, utf8dest, len) != 0) + return (1); + + /* + * Test invalid UTF-8 (16-bit) to UTF-32 (w/ BOM)... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 bad 16-bit source string...\n"); + len = cupsUTF8ToUTF32(utf32dest, utf8bad, 1024); + if (len >= 0) + return (1); + if (verbose) + print_utf8(" utf8bad ", utf8bad); + + /* + * Test UTF-8 (16-bit) to UTF-16 (w/ BOM)... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 to UTF-16 (w/ BOM)...\n"); + len = cupsUTF8ToUTF16(utf16dest, utf8good, 1024); + if (len < 0) + return (1); + if (verbose) + { + print_utf8(" utf8good ", utf8good); + print_utf16(" utf16dest", utf16dest); + } + memcpy (utf16src, utf16dest, (len + 1) * sizeof(cups_utf16_t)); + len = cupsUTF16ToUTF8(utf8dest, utf16src, 1024); + if (len < 0) + return (1); + if (len != strlen ((char *) utf8good)) + return (1); + if (memcmp(utf8good, utf8dest, len) != 0) + return (1); + + /* + * Test UTF-16 to UTF-32 with surrogates... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-16 to UTF-32 w/ surrogates...\n"); + len = cupsUTF16ToUTF32(utf32dest, utf16sur, 1024); + if (len < 0) + return (1); + if (verbose) + { + print_utf16(" utf16sur ", utf16sur); + print_utf32(" utf32dest", utf32dest); + } + + /* + * Test cupsCharmapFlush()... + */ + if (verbose) + printf("\ntesti18n: Testing cupsCharmapFlush()...\n"); + cupsCharmapFlush(); + return (0); +} + + +/* + * 'test_normalize()' - Test 'normalize.c' module. + */ + +static int /* O - Zero or error count */ +test_normalize(const int verbose) /* I - Verbose flag */ +{ + FILE *fp; /* File pointer */ + int count; /* File line counter */ + char line[1024]; /* File line source string */ + int len; /* Length (count) of string */ + int diff; /* Difference of two strings */ + int prop; /* Property of a character */ + int i; /* Looping variable */ + cups_utf32_t utf32char; /* UTF-32 character */ + cups_utf8_t utf8src[1024]; /* UTF-8 source string */ + cups_utf8_t utf8dest[1024]; /* UTF-8 destination string */ + cups_utf16_t utf16src[] = /* UTF-16 non-normal source */ + { 0x0149, 0x20, 0x21, 0x3D, 0x20, 0xC4, 0x2E, 0x00 }; + /* " != ." */ + cups_utf16_t utf16dest[1024]; /* UTF-16 destination string */ + cups_utf32_t utf32dest[1024]; /* UTF-32 destination string */ + + if (verbose) + printf("\ntesti18n: Testing 'normalize.c'...\n"); + + /* + * Test UTF-8 to NFKD/NFC/Properties on demo file... + */ + if (verbose) + { + printf("\ntesti18n: Testing UTF-8 source 'utf8demo.txt'...\n"); + printf(" testing UTF-8 to NFKD...\n"); + printf(" testing UTF-8 to NFC...\n"); + printf(" testing UTF-8 to Character Properties...\n"); + } + if ((fp = fopen("utf8demo.txt", "r")) == NULL) + return (1); + for (count = 0;;) + { + if (fgets(line, 1024, fp) == NULL) + break; + count ++; + len = cupsUTF8Normalize(utf8dest, (cups_utf8_t *)line, 1024, CUPS_NORM_NFKD); + if (len < 0) + printf(" error line: %d (UTF-8 to NFKD)\n", count); + len = cupsUTF8Normalize(utf8dest, (cups_utf8_t *)line, 1024, CUPS_NORM_NFC); + if (len < 0) + printf(" error line: %d (UTF-8 to NFC)\n", count); + len = cupsUTF8ToUTF32(utf32dest, (cups_utf8_t *)line, 1024); + if (len < 0) + { + printf(" error line: %d (UTF-8 to UTF-32)\n", count); + continue; + } + for (i = 0; i < len; i ++) + { + prop = cupsUTF32CharacterProperty(utf32dest[i], + CUPS_PROP_GENERAL_CATEGORY); + if (prop < 0) + printf(" error line: %d (Prop - General Category)\n", count); + prop = cupsUTF32CharacterProperty(utf32dest[i], + CUPS_PROP_BIDI_CATEGORY); + if (prop < 0) + printf(" error line: %d (Prop - Bidi Category)\n", count); + prop = cupsUTF32CharacterProperty(utf32dest[i], + CUPS_PROP_COMBINING_CLASS); + if (prop < 0) + printf(" error line: %d (Prop - Combining Class)\n", count); + prop = cupsUTF32CharacterProperty(utf32dest[i], + CUPS_PROP_BREAK_CLASS); + if (prop < 0) + printf(" error line: %d (Prop - Break Class)\n", count); + } + } + fclose(fp); + if (verbose) + printf(" total lines: %d\n", count); + + /* + * Test UTF-8 normalization NFKD... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 normalization NFKD...\n"); + len = cupsUTF16ToUTF8(utf8dest, utf16src, 1024); + if (len < 0) + return (1); + strcpy((char *) utf8src, (char *) utf8dest); + len = cupsUTF8Normalize(utf8dest, utf8src, 1024, CUPS_NORM_NFKD); + if (len < 0) + return (1); + len = cupsUTF8ToUTF16(utf16dest, utf8dest, 1024); + if (len < 0) + return (1); + if (verbose) + { + print_utf16(" utf16src ", utf16src); + print_utf16(" utf16dest", utf16dest); + } + + /* + * Test UTF-8 normalization NFD... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 normalization NFD...\n"); + len = cupsUTF8Normalize(utf8dest, utf8src, 1024, CUPS_NORM_NFD); + if (len < 0) + return (1); + len = cupsUTF8ToUTF16(utf16dest, utf8dest, 1024); + if (len < 0) + return (1); + if (verbose) + { + print_utf16(" utf16src ", utf16src); + print_utf16(" utf16dest", utf16dest); + } + + /* + * Test UTF-8 normalization NFC... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 normalization NFC...\n"); + len = cupsUTF8Normalize(utf8dest, utf8src, 1024, CUPS_NORM_NFC); + if (len < 0) + return (1); + len = cupsUTF8ToUTF16(utf16dest, utf8dest, 1024); + if (len < 0) + return (1); + if (verbose) + { + print_utf16(" utf16src ", utf16src); + print_utf16(" utf16dest", utf16dest); + } + + /* + * Test UTF-8 simple case folding... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 simple case folding...\n"); + len = cupsUTF8CaseFold(utf8dest, utf8src, 1024, CUPS_FOLD_SIMPLE); + if (len < 0) + return (1); + len = cupsUTF8ToUTF16(utf16dest, utf8dest, 1024); + if (len < 0) + return (1); + if (verbose) + { + print_utf16(" utf16src ", utf16src); + print_utf16(" utf16dest", utf16dest); + } + + /* + * Test UTF-8 full case folding... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 full case folding...\n"); + len = cupsUTF8CaseFold(utf8dest, utf8src, 1024, CUPS_FOLD_FULL); + if (len < 0) + return (1); + len = cupsUTF8ToUTF16(utf16dest, utf8dest, 1024); + if (len < 0) + return (1); + if (verbose) + { + print_utf16(" utf16src ", utf16src); + print_utf16(" utf16dest", utf16dest); + } + + /* + * Test UTF-8 caseless comparison... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-8 caseless comparison..\n"); + diff = cupsUTF8CompareCaseless(utf8src, utf8dest); + if (verbose) + printf(" diff: %d\n", diff); + if (verbose) + printf("\ntesti18n: Testing UTF-8 identifier comparison..\n"); + diff = cupsUTF8CompareIdentifier(utf8src, utf8dest); + if (verbose) + printf(" diff: %d\n", diff); + + /* + * Test UTF-32 character properties... + */ + if (verbose) + printf("\ntesti18n: Testing UTF-32 character properties..\n"); + utf32char = 0x02B0; + prop = cupsUTF32CharacterProperty (utf32char, + CUPS_PROP_GENERAL_CATEGORY); + if (verbose) + printf(" utf32char: %04lx general category %d\n", utf32char, prop); + utf32char = 0x0621; + prop = cupsUTF32CharacterProperty (utf32char, + CUPS_PROP_BIDI_CATEGORY); + if (verbose) + printf(" utf32char: %04lx bidi category %d\n", utf32char, prop); + utf32char = 0x0308; + prop = cupsUTF32CharacterProperty (utf32char, + CUPS_PROP_COMBINING_CLASS); + if (verbose) + printf(" utf32char: %04lx combining class %d\n", utf32char, prop); + utf32char = 0x0009; + prop = cupsUTF32CharacterProperty (utf32char, + CUPS_PROP_BREAK_CLASS); + if (verbose) + printf(" utf32char: %04lx break class %d\n", utf32char, prop); + + /* + * Test cupsNormalizeMapsFlush()... + */ + if (verbose) + printf("\ntesti18n: Testing cupsNormalizeMapsFlush()...\n"); + cupsNormalizeMapsFlush(); + return (0); +} + + +/* + * End of "$Id: testi18n.c 4767 2005-10-10 19:23:23Z mike $" + */ diff --git a/cups/testipp.c b/cups/testipp.c new file mode 100644 index 000000000..dbe50b54d --- /dev/null +++ b/cups/testipp.c @@ -0,0 +1,649 @@ +/* + * "$Id: testipp.c 4731 2005-09-30 23:11:10Z mike $" + * + * IPP test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Main entry. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include "ipp.h" +#ifdef WIN32 +# include +#else +# include +# include +#endif /* WIN32 */ + + +/* + * Local globals... + */ + +int rpos; /* Current position in buffer */ +ipp_uchar_t wbuffer[8192]; /* Write buffer */ +int wused; /* Number of bytes in buffer */ +ipp_uchar_t collection[] = /* Collection buffer */ + { + 0x01, 0x01, /* IPP version */ + 0x00, 0x02, /* Print-Job operation */ + 0x00, 0x00, 0x00, 0x01, /* Request ID */ + + IPP_TAG_OPERATION, + + IPP_TAG_CHARSET, + 0x00, 0x12, /* Name length + name */ + 'a','t','t','r','i','b','u','t','e','s','-', + 'c','h','a','r','s','e','t', + 0x00, 0x05, /* Value length + value */ + 'u','t','f','-','8', + + IPP_TAG_LANGUAGE, + 0x00, 0x1b, /* Name length + name */ + 'a','t','t','r','i','b','u','t','e','s','-', + 'n','a','t','u','r','a','l','-','l','a','n', + 'g','u','a','g','e', + 0x00, 0x02, /* Value length + value */ + 'e','n', + + IPP_TAG_URI, + 0x00, 0x0b, /* Name length + name */ + 'p','r','i','n','t','e','r','-','u','r','i', + 0x00, 0x1c, /* Value length + value */ + 'i','p','p',':','/','/','l','o','c','a','l', + 'h','o','s','t','/','p','r','i','n','t','e', + 'r','s','/','f','o','o', + + IPP_TAG_JOB, /* job group tag */ + + IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */ + 0x00, 0x09, /* Name length + name */ + 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', + 0x00, 0x00, /* No value */ + IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x0b, /* Value length + value */ + 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r', + IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x04, /* Value length + value */ + 'b', 'l', 'u', 'e', + + IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x0a, /* Value length + value */ + 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e', + IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x05, /* Value length + value */ + 'p', 'l', 'a', 'i', 'n', + IPP_TAG_END_COLLECTION, /* endCollection tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x00, /* No value */ + + IPP_TAG_BEGIN_COLLECTION, /* begCollection tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x00, /* No value */ + IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x0b, /* Value length + value */ + 'm', 'e', 'd', 'i', 'a', '-', 'c', 'o', 'l', 'o', 'r', + IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x05, /* Value length + value */ + 'p', 'l', 'a', 'i', 'd', + + IPP_TAG_MEMBERNAME, /* memberAttrName tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x0a, /* Value length + value */ + 'm', 'e', 'd', 'i', 'a', '-', 't', 'y', 'p', 'e', + IPP_TAG_KEYWORD, /* keyword tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x06, /* Value length + value */ + 'g', 'l', 'o', 's', 's', 'y', + IPP_TAG_END_COLLECTION, /* endCollection tag */ + 0x00, 0x00, /* No name */ + 0x00, 0x00, /* No value */ + + IPP_TAG_END /* end tag */ + }; + + +/* + * Local functions... + */ + +void hex_dump(const char *title, ipp_uchar_t *buffer, int bytes); +void print_attributes(ipp_t *ipp, int indent); +int read_cb(void *data, ipp_uchar_t *buffer, int bytes); +int write_cb(void *data, ipp_uchar_t *buffer, int bytes); + + +/* + * 'main()' - Main entry. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + ipp_t *cols[2]; /* Collections */ + ipp_t *request; /* Request */ + ipp_state_t state; /* State */ + int length; /* Length of data */ + int fd; /* File descriptor */ + int i; /* Looping var */ + int status; /* Status of tests (0 = success, 1 = fail) */ + + + status = 0; + + if (argc == 1) + { + /* + * Test request generation code... + */ + + printf("Create Sample Request: "); + + request = ippNew(); + request->request.op.version[0] = 0x01; + request->request.op.version[1] = 0x01; + 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, "utf-8"); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, "en"); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, "ipp://localhost/printers/foo"); + + cols[0] = ippNew(); + ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "blue"); + ippAddString(cols[0], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, "plain"); + + cols[1] = ippNew(); + ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-color", NULL, "plaid"); + ippAddString(cols[1], IPP_TAG_JOB, IPP_TAG_KEYWORD, "media-type", NULL, "glossy"); + + ippAddCollections(request, IPP_TAG_JOB, "media-col", 2, (const ipp_t **)cols); + + length = ippLength(request); + if (length != sizeof(collection)) + { + printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", + length, (int)sizeof(collection)); + status = 1; + } + else + puts("PASS"); + + /* + * Write test #1... + */ + + printf("Write Sample to Memory: "); + + wused = 0; + while ((state = ippWriteIO(wbuffer, write_cb, 1, NULL, request)) != IPP_DATA) + if (state == IPP_ERROR) + break; + + if (state != IPP_DATA) + { + printf("FAIL - %d bytes written.\n", wused); + status = 1; + } + else if (wused != sizeof(collection)) + { + printf("FAIL - wrote %d bytes, expected %d bytes!\n", wused, + (int)sizeof(collection)); + hex_dump("Bytes Written", wbuffer, wused); + hex_dump("Baseline", collection, sizeof(collection)); + status = 1; + } + else if (memcmp(wbuffer, collection, wused)) + { + puts("FAIL - output does not match baseline!"); + hex_dump("Bytes Written", wbuffer, wused); + hex_dump("Baseline", collection, sizeof(collection)); + status = 1; + } + else + puts("PASS"); + + ippDelete(request); + + /* + * Read the data back in and confirm... + */ + + printf("Read Sample from Memory: "); + + request = ippNew(); + rpos = 0; + + while ((state = ippReadIO(wbuffer, read_cb, 1, NULL, request)) != IPP_DATA) + if (state == IPP_ERROR) + break; + + length = ippLength(request); + + if (state != IPP_DATA) + { + printf("FAIL - %d bytes read.\n", rpos); + status = 1; + } + else if (rpos != wused) + { + printf("FAIL - read %d bytes, expected %d bytes!\n", rpos, wused); + print_attributes(request, 8); + status = 1; + } + else if (length != sizeof(collection)) + { + printf("FAIL - wrong ippLength(), %d instead of %d bytes!\n", + length, (int)sizeof(collection)); + print_attributes(request, 8); + status = 1; + } + else + puts("PASS"); + + ippDelete(request); + + /* + * Summarize... + */ + + putchar('\n'); + + if (status) + puts("Core IPP tests failed."); + else + puts("Core IPP tests passed."); + } + else + { + /* + * Read IPP files... + */ + + for (i = 1; i < argc; i ++) + { + if ((fd = open(argv[i], O_RDONLY)) < 0) + { + printf("Unable to open \"%s\" - %s\n", argv[i], strerror(errno)); + status = 1; + continue; + } + + request = ippNew(); + while ((state = ippReadFile(fd, request)) == IPP_ATTRIBUTE); + + if (state != IPP_DATA) + { + printf("Error reading IPP message from \"%s\"!\n", argv[i]); + status = 1; + } + else + { + printf("\n%s:\n", argv[i]); + print_attributes(request, 4); + } + + ippDelete(request); + close(fd); + } + } + + return (status); +} + + +/* + * 'hex_dump()' - Produce a hex dump of a buffer. + */ + +void +hex_dump(const char *title, /* I - Title */ + ipp_uchar_t *buffer, /* I - Buffer to dump */ + int bytes) /* I - Number of bytes */ +{ + int i, j; /* Looping vars */ + int ch; /* Current ASCII char */ + + + /* + * Show lines of 16 bytes at a time... + */ + + printf(" %s:\n", title); + + for (i = 0; i < bytes; i += 16) + { + /* + * Show the offset... + */ + + printf(" %04x ", i); + + /* + * Then up to 16 bytes in hex... + */ + + for (j = 0; j < 16; j ++) + if ((i + j) < bytes) + printf(" %02x", buffer[i + j]); + else + printf(" "); + + /* + * Then the ASCII representation of the bytes... + */ + + putchar(' '); + putchar(' '); + + for (j = 0; j < 16 && (i + j) < bytes; j ++) + { + ch = buffer[i + j] & 127; + + if (ch < ' ' || ch == 127) + putchar('.'); + else + putchar(ch); + } + + putchar('\n'); + } +} + + +/* + * 'print_attributes()' - Print the attributes in a request... + */ + +void +print_attributes(ipp_t *ipp, /* I - IPP request */ + int indent) /* I - Indentation */ +{ + int i; /* Looping var */ + ipp_tag_t group; /* Current group */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_value_t *val; /* Current value */ + static const char * const tags[] = /* Value/group tag strings */ + { + "reserved-00", + "operation-attributes-tag", + "job-attributes-tag", + "end-of-attributes-tag", + "printer-attributes-tag", + "unsupported-attributes-tag", + "subscription-attributes-tag", + "event-attributes-tag", + "reserved-08", + "reserved-09", + "reserved-0A", + "reserved-0B", + "reserved-0C", + "reserved-0D", + "reserved-0E", + "reserved-0F", + "unsupported", + "default", + "unknown", + "no-value", + "reserved-14", + "not-settable", + "delete-attr", + "admin-define", + "reserved-18", + "reserved-19", + "reserved-1A", + "reserved-1B", + "reserved-1C", + "reserved-1D", + "reserved-1E", + "reserved-1F", + "reserved-20", + "integer", + "boolean", + "enum", + "reserved-24", + "reserved-25", + "reserved-26", + "reserved-27", + "reserved-28", + "reserved-29", + "reserved-2a", + "reserved-2b", + "reserved-2c", + "reserved-2d", + "reserved-2e", + "reserved-2f", + "octetString", + "dateTime", + "resolution", + "rangeOfInteger", + "begCollection", + "textWithLanguage", + "nameWithLanguage", + "endCollection", + "reserved-38", + "reserved-39", + "reserved-3a", + "reserved-3b", + "reserved-3c", + "reserved-3d", + "reserved-3e", + "reserved-3f", + "reserved-40", + "textWithoutLanguage", + "nameWithoutLanguage", + "reserved-43", + "keyword", + "uri", + "uriScheme", + "charset", + "naturalLanguage", + "mimeMediaType", + "memberName" + }; + + + for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next) + { + if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name) + { + group = IPP_TAG_ZERO; + putchar('\n'); + continue; + } + + if (group != attr->group_tag) + { + group = attr->group_tag; + + putchar('\n'); + for (i = 4; i < indent; i ++) + putchar(' '); + + printf("%s:\n\n", tags[group]); + } + + for (i = 0; i < indent; i ++) + putchar(' '); + + printf("%s (", attr->name); + if (attr->num_values > 1) + printf("1setOf "); + printf("%s):", tags[attr->value_tag]); + + switch (attr->value_tag) + { + case IPP_TAG_ENUM : + case IPP_TAG_INTEGER : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + printf(" %d", val->integer); + putchar('\n'); + break; + + case IPP_TAG_BOOLEAN : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + printf(" %s", val->boolean ? "true" : "false"); + putchar('\n'); + break; + + case IPP_TAG_RANGE : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + printf(" %d-%d", val->range.lower, val->range.upper); + putchar('\n'); + break; + + case IPP_TAG_DATE : + { + time_t vtime; /* Date/Time value */ + struct tm *vdate; /* Date info */ + char vstring[256]; /* Formatted time */ + + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + { + vtime = ippDateToTime(val->date); + vdate = localtime(&vtime); + strftime(vstring, sizeof(vstring), "%c", vdate); + printf(" (%s)", vstring); + } + } + putchar('\n'); + break; + + case IPP_TAG_RESOLUTION : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + printf(" %dx%d%s", val->resolution.xres, val->resolution.yres, + val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); + putchar('\n'); + break; + + case IPP_TAG_STRING : + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + 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 : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + printf(" \"%s\"", val->string.text); + putchar('\n'); + break; + + case IPP_TAG_BEGIN_COLLECTION : + putchar('\n'); + + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + { + if (i) + putchar('\n'); + print_attributes(val->collection, indent + 4); + } + break; + + default : + printf("UNKNOWN (%d values)\n", attr->num_values); + break; + } + } +} + + +/* + * 'read_cb()' - Read data from a buffer. + */ + +int /* O - Number of bytes read */ +read_cb(void *data, /* I - Data */ + ipp_uchar_t *buffer, /* O - Buffer to read */ + int bytes) /* I - Number of bytes to read */ +{ + int count; /* Number of bytes */ + + + /* + * Copy bytes from the data buffer to the read buffer... + */ + + for (count = bytes; count > 0 && rpos < wused; count --, rpos ++) + *buffer++ = wbuffer[rpos]; + + /* + * Return the number of bytes read... + */ + + return (bytes - count); +} + + +/* + * 'write_cb()' - Write data into a buffer. + */ + +int /* O - Number of bytes written */ +write_cb(void *data, /* I - Data */ + ipp_uchar_t *buffer, /* I - Buffer to write */ + int bytes) /* I - Number of bytes to write */ +{ + int count; /* Number of bytes */ + + + /* + * Loop until all bytes are written... + */ + + for (count = bytes; count > 0 && wused < sizeof(wbuffer); count --, wused ++) + wbuffer[wused] = *buffer++; + + /* + * Return the number of bytes written... + */ + + return (bytes - count); +} + + +/* + * End of "$Id: testipp.c 4731 2005-09-30 23:11:10Z mike $". + */ diff --git a/cups/testlang.c b/cups/testlang.c new file mode 100644 index 000000000..f41408b03 --- /dev/null +++ b/cups/testlang.c @@ -0,0 +1,89 @@ +/* + * "$Id: testlang.c 4903 2006-01-10 20:02:46Z mike $" + * + * Localization test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Load the specified language and show the strings for yes and no. + */ + +/* + * Include necessary headers... + */ + +#include +#include "i18n.h" + + +/* + * 'main()' - Load the specified language and show the strings for yes and no. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_lang_t *language; /* Message catalog */ + cups_lang_t *language2; /* Message catalog */ + + + if (argc == 1) + { + language = cupsLangDefault(); + language2 = cupsLangDefault(); + } + else + { + language = cupsLangGet(argv[1]); + language2 = cupsLangGet(argv[1]); + } + + if (language != language2) + { + puts("**** ERROR: Language cache did not work! ****"); + puts("First result from cupsLangGet:"); + } + + printf("Language = \"%s\"\n", language->language); + printf("Encoding = \"%s\"\n", _cupsEncodingName(language->encoding)); + printf("No = \"%s\"\n", _cupsLangString(language, "No")); + printf("Yes = \"%s\"\n", _cupsLangString(language, "Yes")); + + if (language != language2) + { + puts("Second result from cupsLangGet:"); + + printf("Language = \"%s\"\n", language2->language); + printf("Encoding = \"%s\"\n", _cupsEncodingName(language2->encoding)); + printf("No = \"%s\"\n", _cupsLangString(language2, "No")); + printf("Yes = \"%s\"\n", _cupsLangString(language2, "Yes")); + } + + return (0); +} + + +/* + * End of "$Id: testlang.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/cups/transcode.c b/cups/transcode.c new file mode 100644 index 000000000..b525b36f7 --- /dev/null +++ b/cups/transcode.c @@ -0,0 +1,1668 @@ +/* + * "$Id: transcode.c 4903 2006-01-10 20:02:46Z mike $" + * + * Transcoding support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are + * the property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the + * file "LICENSE.txt" which should have been included with this file. + * If this file is missing or damaged please contact Easy Software + * Products at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsCharmapGet() - Get a character set map. + * cupsCharmapFree() - Free a character set map. + * cupsCharmapFlush() - Flush all character set maps out of cache. + * cupsUTF8ToCharset() - Convert UTF-8 to legacy character set. + * cupsCharsetToUTF8() - Convert legacy character set to UTF-8. + * cupsUTF8ToUTF16() - Convert UTF-8 to UTF-16. + * cupsUTF16ToUTF8() - Convert UTF-16 to UTF-8. + * cupsUTF8ToUTF32() - Convert UTF-8 to UTF-32. + * cupsUTF32ToUTF8() - Convert UTF-32 to UTF-8. + * cupsUTF16ToUTF32() - Convert UTF-16 to UTF-32. + * cupsUTF32ToUTF16() - Convert UTF-32 to UTF-16. + * get_charmap_count() - Count lines in a charmap file. + * get_sbcs_charmap() - Get SBCS Charmap. + * get_vbcs_charmap() - Get DBCS/VBCS Charmap. + * conv_utf8_to_sbcs() - Convert UTF-8 to legacy SBCS. + * conv_utf8_to_vbcs() - Convert UTF-8 to legacy DBCS/VBCS. + * conv_sbcs_to_utf8() - Convert legacy SBCS to UTF-8. + * conv_vbcs_to_utf8() - Convert legacy DBCS/VBCS to UTF-8. + * compare_wide() - Compare key for wide (VBCS) match. + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include +#include +#include + + +/* + * Prototypes... + */ + +static int get_charmap_count(const char *filename); +static _cups_cmap_t *get_sbcs_charmap(const cups_encoding_t encoding, + const char *filename); +static _cups_vmap_t *get_vbcs_charmap(const cups_encoding_t encoding, + const char *filename); + +static int conv_utf8_to_sbcs(char *dest, + const cups_utf8_t *src, + const int maxout, + const cups_encoding_t encoding); +static int conv_utf8_to_vbcs(char *dest, + const cups_utf8_t *src, + const int maxout, + const cups_encoding_t encoding); + +static int conv_sbcs_to_utf8(cups_utf8_t *dest, + const char *src, + const int maxout, + const cups_encoding_t encoding); +static int conv_vbcs_to_utf8(cups_utf8_t *dest, + const char *src, + const int maxout, + const cups_encoding_t encoding); + +static int compare_wide(const void *k1, const void *k2); + +/* + * 'cupsCharmapGet()' - Get a character set map. + * + * This code handles single-byte (SBCS), double-byte (DBCS), and + * variable-byte (VBCS) character sets _without_ charset escapes... + * This code does not handle multiple-byte character sets (MBCS) + * (such as ISO-2022-JP) with charset switching via escapes... + */ + +void * /* O - Charset map pointer */ +cupsCharmapGet( + const cups_encoding_t encoding) /* I - Encoding */ +{ + char mapname[80]; /* Name of charset map */ + char filename[1024]; /* Filename for charset map file */ + _cups_globals_t *cg = _cupsGlobals(); /* Global data */ + + + /* + * Check for valid arguments... + */ + + if ((encoding < 0) || (encoding >= CUPS_ENCODING_VBCS_END)) + return (NULL); + + /* + * Get the data directory and charset map name... + */ + + snprintf(mapname, sizeof(mapname), "%s.txt", _cupsEncodingName(encoding)); + snprintf(filename, sizeof(filename), "%s/charmaps/%s", + cg->cups_datadir, mapname); + + /* + * Read charset map input file into cache... + */ + + if (encoding < CUPS_ENCODING_SBCS_END) + return (get_sbcs_charmap(encoding, filename)); + else if (encoding < CUPS_ENCODING_VBCS_END) + return (get_vbcs_charmap(encoding, filename)); + else + return (NULL); +} + +/* + * 'cupsCharmapFree()' - Free a character set map. + * + * This does not actually free; use 'cupsCharmapFlush()' for that. + */ +void +cupsCharmapFree(const cups_encoding_t encoding) + /* I - Encoding */ +{ + _cups_cmap_t *cmap; /* Legacy SBCS / Unicode Charset Map */ + _cups_vmap_t *vmap; /* Legacy VBCS / Unicode Charset Map */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + /* + * See if we already have this SBCS charset map loaded... + */ + for (cmap = cg->cmap_cache; cmap != NULL; cmap = cmap->next) + { + if (cmap->encoding == encoding) + { + if (cmap->used > 0) + cmap->used --; + return; + } + } + + /* + * See if we already have this DBCS/VBCS charset map loaded... + */ + for (vmap = cg->vmap_cache; vmap != NULL; vmap = vmap->next) + { + if (vmap->encoding == encoding) + { + if (vmap->used > 0) + vmap->used --; + return; + } + } + return; +} + +/* + * 'cupsCharmapFlush()' - Flush all character set maps out of cache. + */ +void +cupsCharmapFlush(void) +{ + int i; /* Looping variable */ + _cups_cmap_t *cmap; /* Legacy SBCS / Unicode Charset Map */ + _cups_vmap_t *vmap; /* Legacy VBCS / Unicode Charset Map */ + _cups_cmap_t *cnext; /* Next Legacy SBCS Charset Map */ + _cups_vmap_t *vnext; /* Next Legacy VBCS Charset Map */ + cups_ucs2_t *crow; /* Pointer to UCS-2 row in 'char2uni' */ + cups_sbcs_t *srow; /* Pointer to SBCS row in 'uni2char' */ + cups_vbcs_t *vrow; /* Pointer to VBCS row in 'uni2char' */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + /* + * Loop through SBCS charset map cache, free all memory... + */ + for (cmap = cg->cmap_cache; cmap != NULL; cmap = cnext) + { + for (i = 0; i < 256; i ++) + { + if ((srow = cmap->uni2char[i]) != NULL) + free(srow); + } + cnext = cmap->next; + free(cmap); + } + cg->cmap_cache = NULL; + + /* + * Loop through DBCS/VBCS charset map cache, free all memory... + */ + for (vmap = cg->vmap_cache; vmap != NULL; vmap = vnext) + { + for (i = 0; i < 256; i ++) + { + if ((crow = vmap->char2uni[i]) != NULL) + free(crow); + } + for (i = 0; i < 256; i ++) + { + if ((vrow = vmap->uni2char[i]) != NULL) + free(vrow); + } + if (vmap->wide2uni) + free(vmap->wide2uni); + vnext = vmap->next; + free(vmap); + } + cg->vmap_cache = NULL; + return; +} + +/* + * 'cupsUTF8ToCharset()' - Convert UTF-8 to legacy character set. + * + * This code handles single-byte (SBCS), double-byte (DBCS), and + * variable-byte (VBCS) character sets _without_ charset escapes... + * This code does not handle multiple-byte character sets (MBCS) + * (such as ISO-2022-JP) with charset switching via escapes... + */ +int /* O - Count or -1 on error */ +cupsUTF8ToCharset(char *dest, /* O - Target string */ + const cups_utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_encoding_t encoding) /* I - Encoding */ +{ + /* + * Check for valid arguments... + */ + + if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING) + return (-1); + + /* + * Handle identity conversions... + */ + + if (encoding == CUPS_UTF8 || + encoding < 0 || encoding >= CUPS_ENCODING_VBCS_END) + { + strlcpy(dest, (char *)src, maxout); + return (strlen(dest)); + } + + /* + * Convert input UTF-8 to legacy charset... + */ + if (encoding < CUPS_ENCODING_SBCS_END) + return (conv_utf8_to_sbcs(dest, src, maxout, encoding)); + else if (encoding < CUPS_ENCODING_VBCS_END) + return (conv_utf8_to_vbcs(dest, src, maxout, encoding)); + else + return (-1); +} + +/* + * 'cupsCharsetToUTF8()' - Convert legacy character set to UTF-8. + * + * This code handles single-byte (SBCS), double-byte (DBCS), and + * variable-byte (VBCS) character sets _without_ charset escapes... + * This code does not handle multiple-byte character sets (MBCS) + * (such as ISO-2022-JP) with charset switching via escapes... + */ +int /* O - Count or -1 on error */ +cupsCharsetToUTF8(cups_utf8_t *dest, /* O - Target string */ + const char *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_encoding_t encoding) /* I - Encoding */ +{ + /* + * Check for valid arguments... + */ + + if (!dest || !src || maxout < 1 || maxout > CUPS_MAX_USTRING) + return (-1); + + /* + * Handle identity conversions... + */ + + if (encoding == CUPS_UTF8 || + encoding < 0 || encoding >= CUPS_ENCODING_VBCS_END) + { + strlcpy((char *)dest, src, maxout); + return (strlen((char *)dest)); + } + + /* + * Convert input legacy charset to UTF-8... + */ + if (encoding < CUPS_ENCODING_SBCS_END) + return (conv_sbcs_to_utf8(dest, src, maxout, encoding)); + else if (encoding < CUPS_ENCODING_VBCS_END) + return (conv_vbcs_to_utf8(dest, src, maxout, encoding)); + else + return (-1); +} + +/* + * 'cupsUTF8ToUTF16()' - Convert UTF-8 to UTF-16. + * + * This code does not support Unicode beyond 16-bits (Plane 0)... + */ +int /* O - Count or -1 on error */ +cupsUTF8ToUTF16(cups_utf16_t *dest, /* O - Target string */ + const cups_utf8_t *src, /* I - Source string */ + const int maxout) /* I - Max output */ +{ + int worklen; /* Internal UCS-4 string length */ + cups_utf32_t work[CUPS_MAX_USTRING]; + /* Internal UCS-4 string */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING)) + return (-1); + *dest = 0; + + /* + * Convert input UTF-8 to internal UCS-4 (and insert BOM)... + */ + worklen = cupsUTF8ToUTF32(work, src, CUPS_MAX_USTRING); + if (worklen < 0) + return (-1); + + /* + * Convert internal UCS-4 to output UTF-16... + */ + worklen = cupsUTF32ToUTF16(dest, work, maxout); + return (worklen); +} + +/* + * 'cupsUTF16ToUTF8()' - Convert UTF-16 to UTF-8. + * + * This code does not support Unicode beyond 16-bits (Plane 0)... + */ +int /* O - Count or -1 on error */ +cupsUTF16ToUTF8(cups_utf8_t *dest, /* O - Target string */ + const cups_utf16_t *src, /* I - Source string */ + const int maxout) /* I - Max output */ +{ + int worklen; /* Internal UCS-4 string length */ + cups_utf32_t work[CUPS_MAX_USTRING]; + /* Internal UCS-4 string */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING)) + return (-1); + *dest = 0; + + /* + * Convert input UTF-16 to internal UCS-4 (and byte-swap)... + */ + worklen = cupsUTF16ToUTF32(work, src, CUPS_MAX_USTRING); + if (worklen < 0) + return (-1); + + /* + * Convert internal UCS-4 to output UTF-8 (and delete BOM)... + */ + worklen = cupsUTF32ToUTF8(dest, work, maxout); + return (worklen); +} + +/* + * 'cupsUTF8ToUTF32()' - Convert UTF-8 to UTF-32. + * + * 32-bit UTF-32 (actually 21-bit) maps to UTF-8 as follows... + * + * UTF-32 char UTF-8 char(s) + * -------------------------------------------------- + * 0 to 127 = 0xxxxxxx (US-ASCII) + * 128 to 2047 = 110xxxxx 10yyyyyy + * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz + * > 65535 = 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx + * + * UTF-32 prohibits chars beyond Plane 16 (> 0x10ffff) in UCS-4, + * which would convert to five- or six-octet UTF-8 sequences... + * + * This code does not support Unicode beyond 16-bits (Plane 0)... + */ +int /* O - Count or -1 on error */ +cupsUTF8ToUTF32(cups_utf32_t *dest, /* O - Target string */ + const cups_utf8_t *src, /* I - Source string */ + const int maxout) /* I - Max output */ +{ + cups_utf8_t *first = (cups_utf8_t *) src; + size_t srclen; /* Source string length */ + int i; /* Looping variable */ + cups_utf32_t ch; /* Character value */ + cups_utf32_t next; /* Next character value */ + cups_utf32_t ch32; /* UTF-32 character value */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING)) + return (-1); + *dest = 0; + + /* + * Convert input UTF-8 to output UTF-32 (and insert BOM)... + */ + *dest = 0xfeff; + dest ++; + srclen = strlen((char *) src); + for (i = 1; i < (maxout - 1); src ++, dest ++) + { + ch = (cups_utf32_t) *src; + ch &= 0xff; + if (ch == 0) + break; + i ++; + + /* + * Convert UTF-8 character(s) to UTF-32 character... + */ + if ((ch & 0x7f) == ch) + { + /* + * One-octet UTF-8 <= 127 (US-ASCII)... + */ + *dest = ch; + } + else if ((ch & 0xe0) == 0xc0) + { + /* + * Two-octet UTF-8 <= 2047 (Latin-x)... + */ + src ++; + next = (cups_utf32_t) *src; + next &= 0xff; + if (next == 0) + return (-1); + ch32 = ((ch & 0x1f) << 6) | (next & 0x3f); + + /* + * Check for non-shortest form (invalid UTF-8)... + */ + if (ch32 <= 127) + return (-1); + *dest = ch32; + } + else if ((ch & 0xf0) == 0xe0) + { + /* + * Three-octet UTF-8 <= 65535 (Plane 0 - BMP)... + */ + src ++; + next = (cups_utf32_t) *src; + next &= 0xff; + if (next == 0) + return (-1); + ch32 = ((ch & 0x1f) << 6) | (next & 0x3f); + src ++; + next = (cups_utf32_t) *src; + next &= 0xff; + if (next == 0) + return (-1); + ch32 = ((ch32 << 6) | (next & 0x3f)); + + /* + * Check for non-shortest form (invalid UTF-8)... + */ + if (ch32 <= 2047) + return (-1); + *dest = ch32; + } + else if ((ch & 0xf8) == 0xf0) + { + /* + * Four-octet UTF-8 to Replacement Character... + */ + if (((src - first) + 3) >= srclen) + return (-1); + src += 3; + *dest = 0xfffd; + } + else if ((ch & 0xfc) == 0xf8) + { + /* + * Five-octet UTF-8 (invalid strict UTF-32)... + */ + return (-1); + } + else if ((ch & 0xfe) == 0xfc) + { + /* + * Six-octet UTF-8 (invalid strict UTF-32)... + */ + return (-1); + } + else + { + /* + * More than six-octet (invalid UTF-8 sequence)... + */ + return (-1); + } + + /* + * Check for UTF-16 surrogate (illegal UTF-8)... + */ + if ((*dest >= 0xd800) && (*dest <= 0xdfff)) + return (-1); + + /* + * Check for beyond Plane 16 (invalid UTF-8)... + */ + if (*dest > 0x10ffff) + return (-1); + } + *dest = 0; + return (i); +} + +/* + * 'cupsUTF32ToUTF8()' - Convert UTF-32 to UTF-8. + * + * 32-bit UTF-32 (actually 21-bit) maps to UTF-8 as follows... + * + * UTF-32 char UTF-8 char(s) + * -------------------------------------------------- + * 0 to 127 = 0xxxxxxx (US-ASCII) + * 128 to 2047 = 110xxxxx 10yyyyyy + * 2048 to 65535 = 1110xxxx 10yyyyyy 10zzzzzz + * > 65535 = 11110xxx 10yyyyyy 10zzzzzz 10xxxxxx + * + * UTF-32 prohibits chars beyond Plane 16 (> 0x10ffff) in UCS-4, + * which would convert to five- or six-octet UTF-8 sequences... + * + * This code does not support Unicode beyond 16-bits (Plane 0)... + */ +int /* O - Count or -1 on error */ +cupsUTF32ToUTF8(cups_utf8_t *dest, /* O - Target string */ + const cups_utf32_t *src, /* I - Source string */ + const int maxout) /* I - Max output */ +{ + cups_utf32_t *first = (cups_utf32_t *) src; + /* First source char */ + cups_utf8_t *start = dest; /* Start of destination string */ + int i; /* Looping variable */ + int swap = 0; /* Byte-swap input to output */ + cups_utf32_t ch; /* Character value */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1)) + return (-1); + *dest = '\0'; + + /* + * Check for leading BOM in UTF-32 and inverted BOM... + */ + if (*src == 0xfffe0000) + swap = 1; + + /* + * Convert input UTF-32 to output UTF-8... + */ + for (i = 0; i < (maxout - 1); src ++) + { + ch = *src; + if (ch == 0) + break; + + /* + * Byte swap input UTF-32, if necessary... + */ + if (swap) + ch = ((ch >> 24) | ((ch >> 8) & 0xff00) | ((ch << 8) & 0xff0000)); + + /* + * Check for leading BOM (and delete from output)... + */ + if ((src == first) && (ch == 0xfeff)) + continue; + + /* + * Check for beyond Plane 16 (invalid UTF-32)... + */ + if (ch > 0x10ffff) + return (-1); + + /* + * Convert beyond Plane 0 (BMP) to Replacement Character... + */ + if (ch > 0xffff) + ch = 0xfffd; + + /* + * Convert UTF-32 character to UTF-8 character(s)... + */ + if (ch <= 0x7f) + { + /* + * One-octet UTF-8 <= 127 (US-ASCII)... + */ + *dest = (cups_utf8_t) ch; + dest ++; + i ++; + } + else if (ch <= 0x7ff) + { + /* + * Two-octet UTF-8 <= 2047 (Latin-x)... + */ + if (i > (maxout - 2)) + break; + *dest = (cups_utf8_t) (0xc0 | ((ch >> 6) & 0x1f)); + dest ++; + i ++; + *dest = (cups_utf8_t) (0x80 | (ch & 0x3f)); + dest ++; + i ++; + } + else + { + /* + * Three-octet UTF-8 <= 65535 (Plane 0 - BMP)... + */ + if (i > (maxout - 3)) + break; + *dest = (cups_utf8_t) (0xe0 | ((ch >> 12) & 0x0f)); + dest ++; + i ++; + *dest = (cups_utf8_t) (0x80 | ((ch >> 6) & 0x3f)); + dest ++; + i ++; + *dest = (cups_utf8_t) (0x80 | (ch & 0x3f)); + dest ++; + i ++; + } + } + *dest = '\0'; + i = (int) (dest - start); + return (i); +} + +/* + * 'cupsUTF16ToUTF32()' - Convert UTF-16 to UTF-32. + * + * This code does not support Unicode beyond 16-bits (Plane 0)... + */ +int /* O - Count or -1 on error */ +cupsUTF16ToUTF32(cups_utf32_t *dest, /* O - Target string */ + const cups_utf16_t *src, /* I - Source string */ + const int maxout) /* I - Max output */ +{ + int i; /* Looping variable */ + int swap = 0; /* Byte-swap input to output */ + int surrogate = 0; /* Expecting low-half surrogate */ + cups_utf32_t ch; /* Character value */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING)) + return (-1); + *dest = 0; + + /* + * Check for leading BOM in UTF-16 and inverted BOM... + */ + if (*src == 0xfffe) + swap = 1; + + /* + * Convert input UTF-16 to output UTF-32... + */ + for (i = 0; i < (maxout - 1); src ++) + { + ch = (cups_utf32_t) (*src & 0xffff); + if (ch == 0) + break; + i ++; + + /* + * Byte swap input UTF-16, if necessary... + */ + if (swap) + ch = (cups_utf32_t) ((ch << 8) | (ch >> 8)); + + /* + * Discard expected UTF-16 low-half surrogate... + */ + if ((ch >= 0xdc00) && (ch <= 0xdfff)) + { + if (surrogate == 0) + return (-1); + surrogate = 0; + continue; + } + + /* + * Convert UTF-16 high-half surrogate to Replacement Character... + */ + if ((ch >= 0xd800) && (ch <= 0xdbff)) + { + if (surrogate == 1) + return (-1); + surrogate = 1; + ch = 0xfffd; + } + *dest = ch; + dest ++; + } + *dest = 0; + return (i); +} + +/* + * 'cupsUTF32ToUTF16()' - Convert UTF-32 to UTF-16. + * + * This code does not support Unicode beyond 16-bits (Plane 0)... + */ +int /* O - Count or -1 on error */ +cupsUTF32ToUTF16(cups_utf16_t *dest, /* O - Target string */ + const cups_utf32_t *src, /* I - Source string */ + const int maxout) /* I - Max output */ +{ + int i; /* Looping variable */ + int swap = 0; /* Byte-swap input to output */ + cups_utf32_t ch; /* Character value */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING)) + return (-1); + *dest = 0; + + /* + * Check for leading BOM in UTF-32 and inverted BOM... + */ + if (*src == 0xfffe0000) + swap = 1; + + /* + * Convert input UTF-32 to output UTF-16 (w/out surrogate pairs)... + */ + for (i = 0; i < (maxout - 1); src ++, dest ++) + { + ch = *src; + if (ch == 0) + break; + i ++; + + /* + * Byte swap input UTF-32, if necessary... + */ + if (swap) + ch = ((ch >> 24) | ((ch >> 8) & 0xff00) | ((ch << 8) & 0xff0000)); + + /* + * Check for UTF-16 surrogate (illegal UTF-32)... + */ + if ((ch >= 0xd800) && (ch <= 0xdfff)) + return (-1); + + /* + * Check for beyond Plane 16 (invalid UTF-32)... + */ + if (ch > 0x10ffff) + return (-1); + + /* + * Convert beyond Plane 0 (BMP) to Replacement Character... + */ + if (ch > 0xffff) + ch = 0xfffd; + *dest = (cups_utf16_t) ch; + } + *dest = 0; + return (i); +} + +/* + * 'get_charmap_count()' - Count lines in a charmap file. + */ +static int /* O - Count or -1 on error */ +get_charmap_count(const char *filename) /* I - Charmap Filename */ +{ + int i; /* Looping variable */ + cups_file_t *fp; /* Map input file pointer */ + char *s; /* Line parsing pointer */ + char line[256]; /* Line from input map file */ + cups_utf32_t unichar; /* Unicode character value */ + + /* + * Open map input file... + */ + if ((filename == NULL) || (*filename == '\0')) + return (-1); + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (-1); + + /* + * Count lines in map input file... + */ + for (i = 0; i < CUPS_MAX_CHARMAP_LINES;) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + while ((*s != 0) && (*s != ' ') && (*s != '\t')) + s ++; + while ((*s == ' ') || (*s == '\t')) + s ++; + if (strncmp (s, "0x", 2) == 0) + s += 2; + if ((sscanf(s, "%lx", &unichar) != 1) + || (unichar > 0xffff)) + { + cupsFileClose(fp); + return (-1); + } + i ++; + } + if (i == 0) + i = -1; + + /* + * Close file and return charmap count (non-comment line count)... + */ + cupsFileClose(fp); + return (i); +} + +/* + * 'get_sbcs_charmap()' - Get SBCS Charmap. + */ +static _cups_cmap_t * /* O - Charmap or 0 on error */ +get_sbcs_charmap(const cups_encoding_t encoding, + /* I - Charmap Encoding */ + const char *filename) /* I - Charmap Filename */ +{ + int i; /* Loop variable */ + unsigned long legchar; /* Legacy character value */ + cups_utf32_t unichar; /* Unicode character value */ + _cups_cmap_t *cmap; /* Legacy SBCS / Unicode Charset Map */ + cups_file_t *fp; /* Charset map file pointer */ + char *s; /* Line parsing pointer */ + cups_ucs2_t *crow; /* Pointer to UCS-2 row in 'char2uni' */ + cups_sbcs_t *srow; /* Pointer to SBCS row in 'uni2char' */ + char line[256]; /* Line from charset map file */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + /* + * Check for valid arguments... + */ + if ((encoding < 0) || (filename == NULL)) + return (NULL); + + /* + * See if we already have this SBCS charset map loaded... + */ + for (cmap = cg->cmap_cache; cmap != NULL; cmap = cmap->next) + { + if (cmap->encoding == encoding) + { + cmap->used ++; + return ((void *) cmap); + } + } + + /* + * Open SBCS charset map input file... + */ + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (NULL); + + /* + * Allocate memory for SBCS charset map and add to cache... + */ + cmap = (_cups_cmap_t *) calloc(1, sizeof(_cups_cmap_t)); + if (cmap == NULL) + { + cupsFileClose(fp); + return (NULL); + } + cmap->next = cg->cmap_cache; + cg->cmap_cache = cmap; + cmap->used ++; + cmap->encoding = encoding; + + /* + * Save SBCS charset map into memory for transcoding... + */ + for (i = 0; i < CUPS_MAX_CHARMAP_LINES;) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + if (strncmp (s, "0x", 2) == 0) + s += 2; + if ((sscanf(s, "%lx", &legchar) != 1) + || (legchar > 0xff)) + { + cupsFileClose(fp); + cupsCharmapFlush(); + return (NULL); + } + while ((*s != 0) && (*s != ' ') && (*s != '\t')) + s ++; + while ((*s == ' ') || (*s == '\t')) + s ++; + if (strncmp (s, "0x", 2) == 0) + s += 2; + if (sscanf(s, "%lx", &unichar) != 1) + { + cupsFileClose(fp); + cupsCharmapFlush(); + return (NULL); + } + i ++; + + /* + * Convert beyond Plane 0 (BMP) to Replacement Character... + */ + if (unichar > 0xffff) + unichar = 0xfffd; + + /* + * Save legacy to Unicode mapping in direct lookup table... + */ + crow = &cmap->char2uni[(int) legchar]; + *crow = (cups_ucs2_t) (unichar & 0xffff); + + /* + * Save Unicode to legacy mapping in indirect lookup table... + */ + srow = cmap->uni2char[(int) ((unichar >> 8) & 0xff)]; + if (srow == NULL) + { + srow = (cups_sbcs_t *) calloc(256, sizeof(cups_sbcs_t)); + if (srow == NULL) + { + cupsFileClose(fp); + cupsCharmapFlush(); + return (NULL); + } + cmap->uni2char[(int) ((unichar >> 8) & 0xff)] = srow; + } + srow += (int) (unichar & 0xff); + + /* + * Convert Replacement Character to visible replacement... + */ + if (unichar == 0xfffd) + legchar = (unsigned long) '?'; + + /* + * First (oldest) legacy character uses Unicode mapping cell... + */ + if (*srow == 0) + *srow = (cups_sbcs_t) legchar; + } + cupsFileClose(fp); + return (cmap); +} + +/* + * 'get_vbcs_charmap()' - Get DBCS/VBCS Charmap. + */ +static _cups_vmap_t * /* O - Charmap or 0 on error */ +get_vbcs_charmap(const cups_encoding_t encoding, + /* I - Charmap Encoding */ + const char *filename) /* I - Charmap Filename */ +{ + _cups_vmap_t *vmap; /* Legacy VBCS / Unicode Charset Map */ + cups_ucs2_t *crow; /* Pointer to UCS-2 row in 'char2uni' */ + cups_vbcs_t *vrow; /* Pointer to VBCS row in 'uni2char' */ + _cups_wide2uni_t *wide2uni; /* Pointer to row in 'wide2uni' */ + cups_sbcs_t leadchar; /* Lead char of 2-byte legacy char */ + unsigned long legchar; /* Legacy character value */ + cups_utf32_t unichar; /* Unicode character value */ + int mapcount; /* Count of lines in charmap file */ + cups_file_t *fp; /* Charset map file pointer */ + char *s; /* Line parsing pointer */ + char line[256]; /* Line from charset map file */ + int i; /* Loop variable */ + int wide; /* 32-bit legacy char */ + _cups_globals_t *cg = _cupsGlobals(); + /* Pointer to library globals */ + + /* + * Check for valid arguments... + */ + if ((encoding < 0) || (filename == NULL)) + return (NULL); + + /* + * See if we already have this DBCS/VBCS charset map loaded... + */ + for (vmap = cg->vmap_cache; vmap != NULL; vmap = vmap->next) + { + if (vmap->encoding == encoding) + { + vmap->used ++; + return ((void *) vmap); + } + } + + /* + * Count lines in charmap file... + */ + mapcount = get_charmap_count(filename); + if (mapcount <= 0) + return (NULL); + + /* + * Open VBCS charset map input file... + */ + fp = cupsFileOpen(filename, "r"); + if (fp == NULL) + return (NULL); + + /* + * Allocate memory for DBCS/VBCS charset map and add to cache... + */ + vmap = (_cups_vmap_t *) calloc(1, sizeof(_cups_vmap_t)); + if (vmap == NULL) + { + cupsFileClose(fp); + return (NULL); + } + vmap->next = cg->vmap_cache; + cg->vmap_cache = vmap; + vmap->used ++; + vmap->encoding = encoding; + + /* + * Save DBCS/VBCS charset map into memory for transcoding... + */ + leadchar = 0; + wide2uni = NULL; + + for (i = 0, wide = 0; i < mapcount; ) + { + s = cupsFileGets(fp, line, sizeof(line)); + if (s == NULL) + break; + if ((*s == '#') || (*s == '\n') || (*s == '\0')) + continue; + if (strncmp (s, "0x", 2) == 0) + s += 2; + if ((sscanf(s, "%lx", &legchar) != 1) + || ((legchar > 0xffff) && (encoding < CUPS_ENCODING_DBCS_END))) + { + cupsFileClose(fp); + cupsCharmapFlush(); + return (NULL); + } + while ((*s != 0) && (*s != ' ') && (*s != '\t')) + s ++; + while ((*s == ' ') || (*s == '\t')) + s ++; + if (strncmp (s, "0x", 2) == 0) + s += 2; + if (sscanf(s, "%lx", &unichar) != 1) + { + cupsFileClose(fp); + cupsCharmapFlush(); + return (NULL); + } + i ++; + + /* + * Convert beyond Plane 0 (BMP) to Replacement Character... + */ + if (unichar > 0xffff) + unichar = 0xfffd; + + /* + * Save lead char of 2/3/4-byte legacy char... + */ + if ((legchar > 0xff) && (legchar <= 0xffff)) + { + leadchar = (cups_sbcs_t) (legchar >> 8); + vmap->lead2char[leadchar] = leadchar; + } + if ((legchar > 0xffff) && (legchar <= 0xffffff)) + { + leadchar = (cups_sbcs_t) (legchar >> 16); + vmap->lead3char[leadchar] = leadchar; + } + if (legchar > 0xffffff) + { + leadchar = (cups_sbcs_t) (legchar >> 24); + vmap->lead4char[leadchar] = leadchar; + } + + /* + * Save Legacy to Unicode mapping... + */ + if (legchar <= 0xffff) + { + /* + * Save DBCS 16-bit to Unicode mapping in indirect lookup table... + */ + crow = vmap->char2uni[(int) leadchar]; + if (crow == NULL) + { + crow = (cups_ucs2_t *) calloc(256, sizeof(cups_ucs2_t)); + if (crow == NULL) + { + cupsFileClose(fp); + cupsCharmapFlush(); + return (NULL); + } + vmap->char2uni[(int) leadchar] = crow; + } + crow += (int) (legchar & 0xff); + *crow = (cups_ucs2_t) unichar; + } + else + { + /* + * Save VBCS 32-bit to Unicode mapping in sorted list table... + */ + if (wide == 0) + { + wide = 1; + vmap->widecount = (mapcount - i + 1); + wide2uni = (_cups_wide2uni_t *) + calloc(vmap->widecount, sizeof(_cups_wide2uni_t)); + if (wide2uni == NULL) + { + cupsFileClose(fp); + cupsCharmapFlush(); + return (NULL); + } + vmap->wide2uni = wide2uni; + } + wide2uni->widechar = (cups_vbcs_t) legchar; + wide2uni->unichar = (cups_ucs2_t)unichar; + wide2uni ++; + } + + /* + * Save Unicode to legacy mapping in indirect lookup table... + */ + vrow = vmap->uni2char[(int) ((unichar >> 8) & 0xff)]; + if (vrow == NULL) + { + vrow = (cups_vbcs_t *) calloc(256, sizeof(cups_vbcs_t)); + if (vrow == NULL) + { + cupsFileClose(fp); + cupsCharmapFlush(); + return (NULL); + } + vmap->uni2char[(int) ((unichar >> 8) & 0xff)] = vrow; + } + vrow += (int) (unichar & 0xff); + + /* + * Convert Replacement Character to visible replacement... + */ + if (unichar == 0xfffd) + legchar = (unsigned long) '?'; + + /* + * First (oldest) legacy character uses Unicode mapping cell... + */ + if (*vrow == 0) + *vrow = (cups_vbcs_t) legchar; + } + vmap->charcount = (i - vmap->widecount); + cupsFileClose(fp); + return (vmap); +} + +/* + * 'conv_utf8_to_sbcs()' - Convert UTF-8 to legacy SBCS. + */ +static int /* O - Count or -1 on error */ +conv_utf8_to_sbcs(char *dest, /* O - Target string */ + const cups_utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_encoding_t encoding) /* I - Encoding */ +{ + char *start = dest; /* Start of destination string */ + _cups_cmap_t *cmap; /* Legacy SBCS / Unicode Charset Map */ + cups_sbcs_t *srow; /* Pointer to SBCS row in 'uni2char' */ + cups_utf32_t unichar; /* Character value */ + int worklen; /* Internal UCS-4 string length */ + cups_utf32_t work[CUPS_MAX_USTRING]; + /* Internal UCS-4 string */ + int i; /* Looping variable */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING) + || (encoding == CUPS_UTF8)) + return (-1); + *dest = '\0'; + + /* + * Find legacy charset map in cache... + */ + cmap = (_cups_cmap_t *) cupsCharmapGet(encoding); + if (cmap == NULL) + return (-1); + + /* + * Convert input UTF-8 to internal UCS-4 (and insert BOM)... + */ + worklen = cupsUTF8ToUTF32(work, src, CUPS_MAX_USTRING); + if (worklen < 0) + return (-1); + + /* + * Convert internal UCS-4 to SBCS legacy charset (and delete BOM)... + */ + for (i = 0; i < worklen;) + { + unichar = work[i]; + if (unichar == 0) + break; + i ++; + + /* + * Check for leading BOM (and delete from output)... + */ + if ((i == 1) && (unichar == 0xfeff)) + continue; + + /* + * Convert ASCII verbatim (optimization)... + */ + if (unichar <= 0x7f) + { + *dest = (char) unichar; + dest ++; + continue; + } + + /* + * Convert unknown character to visible replacement... + */ + srow = cmap->uni2char[(int) ((unichar >> 8) & 0xff)]; + if (srow) + srow += (int) (unichar & 0xff); + if ((srow == NULL) || (*srow == 0)) + *dest = '?'; + else + *dest = (char) (*srow); + dest ++; + } + *dest = '\0'; + worklen = (int) (dest - start); + cupsCharmapFree(encoding); + return (worklen); +} + +/* + * 'conv_utf8_to_vbcs()' - Convert UTF-8 to legacy DBCS/VBCS. + */ +static int /* O - Count or -1 on error */ +conv_utf8_to_vbcs(char *dest, /* O - Target string */ + const cups_utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_encoding_t encoding) /* I - Encoding */ +{ + char *start = dest; /* Start of destination string */ + _cups_vmap_t *vmap; /* Legacy DBCS / Unicode Charset Map */ + cups_vbcs_t *vrow; /* Pointer to VBCS row in 'uni2char' */ + cups_utf32_t unichar; /* Character value */ + cups_vbcs_t legchar; /* Legacy character value */ + int worklen; /* Internal UCS-4 string length */ + cups_utf32_t work[CUPS_MAX_USTRING]; + /* Internal UCS-4 string */ + int i; /* Looping variable */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING) + || (encoding == CUPS_UTF8)) + return (-1); + *dest = '\0'; + + /* + * Find legacy charset map in cache... + */ + vmap = (_cups_vmap_t *) cupsCharmapGet(encoding); + if (vmap == NULL) + return (-1); + + /* + * Convert input UTF-8 to internal UCS-4 (and insert BOM)... + */ + worklen = cupsUTF8ToUTF32(work, src, CUPS_MAX_USTRING); + if (worklen < 0) + return (-1); + + /* + * Convert internal UCS-4 to VBCS legacy charset (and delete BOM)... + */ + for (i = 0; i < worklen;) + { + unichar = work[i]; + if (unichar == 0) + break; + i ++; + + /* + * Check for leading BOM (and delete from output)... + */ + if ((i == 1) && (unichar == 0xfeff)) + continue; + + /* + * Convert ASCII verbatim (optimization)... + */ + if (unichar <= 0x7f) + { + *dest = (char) unichar; + dest ++; + continue; + } + + /* + * Convert unknown character to visible replacement... + */ + vrow = vmap->uni2char[(int) ((unichar >> 8) & 0xff)]; + if (vrow) + vrow += (int) (unichar & 0xff); + if ((vrow == NULL) || (*vrow == 0)) + legchar = (cups_vbcs_t) '?'; + else + legchar = (cups_vbcs_t) *vrow; + + /* + * Save n-byte legacy character... + */ + if (legchar > 0xffffff) + { + *dest = (char) ((legchar >> 24) & 0xff); + dest++; + } + if (legchar > 0xffff) + { + *dest = (char) ((legchar >> 16) & 0xff); + dest++; + } + if (legchar > 0xff) + { + *dest = (char) ((legchar >> 8) & 0xff); + dest++; + } + *dest = (char) (legchar & 0xff); + dest ++; + } + *dest = '\0'; + worklen = (int) (dest - start); + cupsCharmapFree(encoding); + return (worklen); +} + +/* + * 'conv_sbcs_to_utf8()' - Convert legacy SBCS to UTF-8. + */ +static int /* O - Count or -1 on error */ +conv_sbcs_to_utf8(cups_utf8_t *dest, /* O - Target string */ + const char *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_encoding_t encoding) /* I - Encoding */ +{ + _cups_cmap_t *cmap; /* Legacy SBCS / Unicode Charset Map */ + cups_ucs2_t *crow; /* Pointer to UCS-2 row in 'char2uni' */ + unsigned long legchar; /* Legacy character value */ + cups_utf32_t unichar; /* Unicode character value */ + int worklen; /* Internal UCS-4 string length */ + cups_utf32_t work[CUPS_MAX_USTRING]; + /* Internal UCS-4 string */ + int i; /* Looping variable */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING) + || (encoding == CUPS_UTF8)) + return (-1); + *dest = '\0'; + + /* + * Find legacy charset map in cache... + */ + cmap = (_cups_cmap_t *) cupsCharmapGet(encoding); + if (cmap == NULL) + return (-1); + + /* + * Convert input legacy charset to internal UCS-4 (and insert BOM)... + */ + work[0] = 0xfeff; + for (i = 1; i < (CUPS_MAX_USTRING - 1); src ++) + { + if (*src == '\0') + break; + legchar = (unsigned long) *src; + + /* + * Convert ASCII verbatim (optimization)... + */ + if (legchar <= 0x7f) + { + work[i] = (cups_utf32_t) legchar; + i ++; + continue; + } + + /* + * Convert unknown character to Replacement Character... + */ + crow = &cmap->char2uni[0]; + crow += (int) legchar; + if (*crow == 0) + unichar = 0xfffd; + else + unichar = (cups_utf32_t) *crow; + work[i] = unichar; + i ++; + } + work[i] = 0; + + /* + * Convert internal UCS-4 to output UTF-8 (and delete BOM)... + */ + worklen = cupsUTF32ToUTF8(dest, work, maxout); + cupsCharmapFree(encoding); + return (worklen); +} + + +/* + * 'conv_vbcs_to_utf8()' - Convert legacy DBCS/VBCS to UTF-8. + */ +static int /* O - Count or -1 on error */ +conv_vbcs_to_utf8(cups_utf8_t *dest, /* O - Target string */ + const char *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_encoding_t encoding) /* I - Encoding */ +{ + _cups_vmap_t *vmap; /* Legacy VBCS / Unicode Charset Map */ + cups_ucs2_t *crow; /* Pointer to UCS-2 row in 'char2uni' */ + _cups_wide2uni_t *wide2uni; /* Pointer to row in 'wide2uni' */ + cups_sbcs_t leadchar; /* Lead char of n-byte legacy char */ + cups_vbcs_t legchar; /* Legacy character value */ + cups_utf32_t unichar; /* Unicode character value */ + int i; /* Looping variable */ + int worklen; /* Internal UCS-4 string length */ + cups_utf32_t work[CUPS_MAX_USTRING]; + /* Internal UCS-4 string */ + + /* + * Check for valid arguments and clear output... + */ + if ((dest == NULL) + || (src == NULL) + || (maxout < 1) + || (maxout > CUPS_MAX_USTRING) + || (encoding == CUPS_UTF8)) + return (-1); + *dest = '\0'; + + /* + * Find legacy charset map in cache... + */ + vmap = (_cups_vmap_t *) cupsCharmapGet(encoding); + if (vmap == NULL) + return (-1); + + /* + * Convert input legacy charset to internal UCS-4 (and insert BOM)... + */ + work[0] = 0xfeff; + for (i = 1; i < (CUPS_MAX_USTRING - 1); src ++) + { + if (*src == '\0') + break; + legchar = (cups_vbcs_t) *src; + leadchar = (cups_sbcs_t) *src; + + /* + * Convert ASCII verbatim (optimization)... + */ + if (legchar <= 0x7f) + { + work[i] = (cups_utf32_t) legchar; + i ++; + continue; + } + + /* + * Convert 2-byte legacy character... + */ + if (vmap->lead2char[(int) leadchar] == leadchar) + { + src ++; + if (*src == '\0') + return (-1); + legchar = (legchar << 8) | (cups_vbcs_t) *src; + + /* + * Convert unknown character to Replacement Character... + */ + crow = vmap->char2uni[(int) ((legchar >> 8) & 0xff)]; + if (crow) + crow += (int) (legchar & 0xff); + if ((crow == NULL) || (*crow == 0)) + unichar = 0xfffd; + else + unichar = (cups_utf32_t) *crow; + work[i] = unichar; + i ++; + continue; + } + + /* + * Fetch 3-byte or 4-byte legacy character... + */ + if (vmap->lead3char[(int) leadchar] == leadchar) + { + src ++; + if (*src == '\0') + return (-1); + legchar = (legchar << 8) | (cups_vbcs_t) *src; + src ++; + if (*src == '\0') + return (-1); + legchar = (legchar << 8) | (cups_vbcs_t) *src; + } + else if (vmap->lead4char[(int) leadchar] == leadchar) + { + src ++; + if (*src == '\0') + return (-1); + legchar = (legchar << 8) | (cups_vbcs_t) *src; + src ++; + if (*src == '\0') + return (-1); + legchar = (legchar << 8) | (cups_vbcs_t) *src; + src ++; + if (*src == '\0') + return (-1); + legchar = (legchar << 8) | (cups_vbcs_t) *src; + } + else + return (-1); + + /* + * Find 3-byte or 4-byte legacy character... + */ + wide2uni = vmap->wide2uni; + wide2uni = (_cups_wide2uni_t *) bsearch(&legchar, + vmap->wide2uni, + vmap->widecount, + sizeof(_cups_wide2uni_t), + compare_wide); + + /* + * Convert unknown character to Replacement Character... + */ + if ((wide2uni == NULL) || (wide2uni->unichar == 0)) + unichar = 0xfffd; + else + unichar = wide2uni->unichar; + work[i] = unichar; + i ++; + } + work[i] = 0; + + /* + * Convert internal UCS-4 to output UTF-8 (and delete BOM)... + */ + worklen = cupsUTF32ToUTF8(dest, work, maxout); + cupsCharmapFree(encoding); + return (worklen); +} + +/* + * 'compare_wide()' - Compare key for wide (VBCS) match. + */ +static int +compare_wide(const void *k1, /* I - Key char */ + const void *k2) /* I - Map char */ +{ + cups_vbcs_t *kp = (cups_vbcs_t *) k1; + /* Key char pointer */ + _cups_wide2uni_t *mp = (_cups_wide2uni_t *) k2; + /* Map char pointer */ + cups_vbcs_t key; /* Legacy key character */ + cups_vbcs_t map; /* Legacy map character */ + int result; /* Result Value */ + + key = *kp; + map = mp->widechar; + if (key >= map) + result = (int) (key - map); + else + result = -1 * ((int) (map - key)); + return (result); +} + + +/* + * End of "$Id: transcode.c 4903 2006-01-10 20:02:46Z mike $" + */ diff --git a/cups/transcode.h b/cups/transcode.h new file mode 100644 index 000000000..5ed8fd8aa --- /dev/null +++ b/cups/transcode.h @@ -0,0 +1,159 @@ +/* + * "$Id: transcode.h 4903 2006-01-10 20:02:46Z mike $" + * + * Transcoding support for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are + * the property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the + * file "LICENSE.txt" which should have been included with this file. + * If this file is missing or damaged please contact Easy Software + * Products at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_TRANSCODE_H_ +# define _CUPS_TRANSCODE_H_ + +/* + * Include necessary headers... + */ + +# include "language.h" + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + + +/* + * Types... + */ + +typedef unsigned char cups_utf8_t; /* UTF-8 Unicode/ISO-10646 unit */ +typedef unsigned short cups_utf16_t; /* UTF-16 Unicode/ISO-10646 unit */ +typedef unsigned long cups_utf32_t; /* UTF-32 Unicode/ISO-10646 unit */ +typedef unsigned short cups_ucs2_t; /* UCS-2 Unicode/ISO-10646 unit */ +typedef unsigned long cups_ucs4_t; /* UCS-4 Unicode/ISO-10646 unit */ +typedef unsigned char cups_sbcs_t; /* SBCS Legacy 8-bit unit */ +typedef unsigned short cups_dbcs_t; /* DBCS Legacy 16-bit unit */ +typedef unsigned long cups_vbcs_t; /* VBCS Legacy 32-bit unit */ + /* EUC uses 8, 16, 24, 32-bit */ + + +/* + * Structures... + */ + +typedef struct _cups_cmap_s /**** SBCS Charmap Struct ****/ +{ + struct _cups_cmap_s *next; /* Next charmap in cache */ + int used; /* Number of times entry used */ + cups_encoding_t encoding; /* Legacy charset encoding */ + cups_ucs2_t char2uni[256]; /* Map Legacy SBCS -> UCS-2 */ + cups_sbcs_t *uni2char[256]; /* Map UCS-2 -> Legacy SBCS */ +} _cups_cmap_t; + +typedef struct _cups_wide2uni_s /**** Wide to Unicode ****/ +{ + cups_vbcs_t widechar; /* VBCS 32-bit Char (EUC) */ + cups_ucs2_t unichar; /* UCS-2 Char */ +} _cups_wide2uni_t; + +typedef struct _cups_vmap_s /**** VBCS Charmap Struct ****/ +{ + struct _cups_vmap_s *next; /* Next charmap in cache */ + int used; /* Number of times entry used */ + cups_encoding_t encoding; /* Legacy charset encoding */ + cups_ucs2_t *char2uni[256]; /* Map 16-bit Char -> UCS-2 */ + int charcount; /* Count of 16-bit VBCS Chars */ + _cups_wide2uni_t *wide2uni; /* Map 32-bit Char -> UCS-2 */ + int widecount; /* Count of 32-bit VBCS Chars */ + cups_vbcs_t *uni2char[256]; /* Map UCS-2 -> 32-bit VBCS */ + cups_sbcs_t lead2char[256]; /* Legacy Lead Char - 2-byte */ + cups_sbcs_t lead3char[256]; /* Legacy Lead Char - 3-byte */ + cups_sbcs_t lead4char[256]; /* Legacy Lead Char - 4-byte */ +} _cups_vmap_t; + + +/* + * Constants... + */ + +# define CUPS_MAX_USTRING 8192 /* Max size of Unicode string */ +# define CUPS_MAX_CHARMAP_LINES 100000 /* Max lines in charmap file */ + + +/* + * Prototypes... + */ + +/* + * Utility functions for character set maps + */ +extern void *cupsCharmapGet(const cups_encoding_t encoding); +extern void cupsCharmapFree(const cups_encoding_t encoding); +extern void cupsCharmapFlush(void); + +/* + * Convert UTF-8 to and from legacy character set + */ +extern int cupsUTF8ToCharset(char *dest, + const cups_utf8_t *src, + const int maxout, + const cups_encoding_t encoding); +extern int cupsCharsetToUTF8(cups_utf8_t *dest, + const char *src, + const int maxout, + const cups_encoding_t encoding); + +/* + * Convert UTF-8 to and from UTF-16 + */ +extern int cupsUTF8ToUTF16(cups_utf16_t *dest, + const cups_utf8_t *src, + const int maxout); +extern int cupsUTF16ToUTF8(cups_utf8_t *dest, + const cups_utf16_t *src, + const int maxout); + +/* + * Convert UTF-8 to and from UTF-32 + */ +extern int cupsUTF8ToUTF32(cups_utf32_t *dest, + const cups_utf8_t *src, + const int maxout); +extern int cupsUTF32ToUTF8(cups_utf8_t *dest, + const cups_utf32_t *src, + const int maxout); + +/* + * Convert UTF-16 to and from UTF-32 + */ +extern int cupsUTF16ToUTF32(cups_utf32_t *dest, + const cups_utf16_t *src, + const int maxout); +extern int cupsUTF32ToUTF16(cups_utf16_t *dest, + const cups_utf32_t *src, + const int maxout); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_TRANSCODE_H_ */ + + +/* + * End of "$Id: transcode.h 4903 2006-01-10 20:02:46Z mike $" + */ diff --git a/cups/usersys.c b/cups/usersys.c new file mode 100644 index 000000000..1b73cbdae --- /dev/null +++ b/cups/usersys.c @@ -0,0 +1,463 @@ +/* + * "$Id: usersys.c 4918 2006-01-12 05:14:40Z mike $" + * + * User, system, and password routines for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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. + * _cupsGetPassword() - Get a password from the user. + */ + +/* + * Include necessary headers... + */ + +#include "http-private.h" +#include "globals.h" +#include +#ifdef WIN32 +# include +#endif /* WIN32 */ + + +/* + * 'cupsEncryption()' - Get the default encryption settings. + * + * The default encryption setting comes from the CUPS_ENCRYPTION + * environment variable, then the ~/.cupsrc file, and finally the + * /etc/cups/client.conf file. If not set, the default is + * HTTP_ENCRYPT_IF_REQUESTED. + */ + +http_encryption_t /* O - Encryption settings */ +cupsEncryption(void) +{ + cups_file_t *fp; /* client.conf file */ + char *encryption; /* CUPS_ENCRYPTION variable */ + const char *home; /* Home directory of user */ + char line[1024], /* Line from file */ + *value; /* Value on line */ + int linenum; /* Line number */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * First see if we have already set the encryption stuff... + */ + + if (cg->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 = cupsFileOpen(line, "r"); + } + else + fp = NULL; + + if (fp == NULL) + { + snprintf(line, sizeof(line), "%s/client.conf", cg->cups_serverroot); + fp = cupsFileOpen(line, "r"); + } + + encryption = "IfRequested"; + + if (fp != NULL) + { + /* + * Read the config file and look for an Encryption line... + */ + + linenum = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum) != NULL) + if (!strcasecmp(line, "Encryption") && value) + { + /* + * Got it! + */ + + encryption = value; + break; + } + + cupsFileClose(fp); + } + } + + /* + * Set the encryption preference... + */ + + if (!strcasecmp(encryption, "never")) + cg->encryption = HTTP_ENCRYPT_NEVER; + else if (!strcasecmp(encryption, "always")) + cg->encryption = HTTP_ENCRYPT_ALWAYS; + else if (!strcasecmp(encryption, "required")) + cg->encryption = HTTP_ENCRYPT_REQUIRED; + else + cg->encryption = HTTP_ENCRYPT_IF_REQUESTED; + } + + return (cg->encryption); +} + + +/* + * 'cupsGetPassword()' - Get a password from the user. + * + * Returns NULL if the user does not provide a password. + */ + +const char * /* O - Password */ +cupsGetPassword(const char *prompt) /* I - Prompt string */ +{ + return ((*_cupsGlobals()->password_cb)(prompt)); +} + + +/* + * 'cupsSetEncryption()' - Set the encryption preference. + */ + +void +cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */ +{ + _cupsGlobals()->encryption = e; +} + + +/* + * 'cupsServer()' - Return the hostname/address of the default server. + * + * The returned value can be a fully-qualified hostname, a numeric + * IPv4 or IPv6 address, or a domain socket pathname. + */ + +const char * /* O - Server name */ +cupsServer(void) +{ + cups_file_t *fp; /* client.conf file */ + char *server; /* Pointer to server name */ + const char *home; /* Home directory of user */ + char *port; /* Port number */ + char line[1024], /* Line from file */ + *value; /* Value on line */ + int linenum; /* Line number in file */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * First see if we have already set the server name... + */ + + if (!cg->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 = cupsFileOpen(line, "r"); + } + else + fp = NULL; + + if (fp == NULL) + { + snprintf(line, sizeof(line), "%s/client.conf", cg->cups_serverroot); + fp = cupsFileOpen(line, "r"); + } + +#ifdef CUPS_DEFAULT_DOMAINSOCKET + if (!access(CUPS_DEFAULT_DOMAINSOCKET, 0)) + server = CUPS_DEFAULT_DOMAINSOCKET; + else +#endif /* CUPS_DEFAULT_DOMAINSOCKET */ + server = "localhost"; + + if (fp != NULL) + { + /* + * Read the config file and look for a ServerName line... + */ + + linenum = 0; + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum) != NULL) + if (!strcasecmp(line, "ServerName") && value) + { + /* + * Got it! + */ + + server = value; + break; + } + + cupsFileClose(fp); + } + } + + /* + * Copy the server name over and set the port number, if any... + */ + + strlcpy(cg->server, server, sizeof(cg->server)); + + if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL && + !strchr(port, ']') && isdigit(port[1] & 255)) + { + *port++ = '\0'; + + ippSetPort(atoi(port)); + } + + if (cg->server[0] == '/') + strcpy(cg->servername, "localhost"); + else + strlcpy(cg->servername, cg->server, sizeof(cg->servername)); + } + + return (cg->server); +} + + +/* + * 'cupsSetPasswordCB()' - Set the password callback for CUPS. + * + * Pass NULL to restore the default (console) password callback. + */ + +void +cupsSetPasswordCB(cups_password_cb_t cb)/* I - Callback function */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + if (cb == (const char *(*)(const char *))0) + cg->password_cb = _cupsGetPassword; + else + cg->password_cb = cb; +} + + +/* + * 'cupsSetServer()' - Set the default server name. + * + * The "server" string can be a fully-qualified hostname, a numeric + * IPv4 or IPv6 address, or a domain socket pathname. Pass NULL to + * restore the default server name. + */ + +void +cupsSetServer(const char *server) /* I - Server name */ +{ + char *port; /* Pointer to port */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + if (server) + { + strlcpy(cg->server, server, sizeof(cg->server)); + + if (cg->server[0] != '/' && (port = strrchr(cg->server, ':')) != NULL && + !strchr(port, ']') && isdigit(port[1] & 255)) + { + *port++ = '\0'; + + ippSetPort(atoi(port)); + } + + if (cg->server[0] == '/') + strcpy(cg->servername, "localhost"); + else + strlcpy(cg->servername, cg->server, sizeof(cg->servername)); + } + else + { + cg->server[0] = '\0'; + cg->servername[0] = '\0'; + } +} + + +/* + * 'cupsSetUser()' - Set the default user name. + * + * Pass NULL to restore the default user name. + */ + +void +cupsSetUser(const char *user) /* I - User name */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + if (user) + strlcpy(cg->user, user, sizeof(cg->user)); + else + cg->user[0] = '\0'; +} + + +#if defined(WIN32) +/* + * WIN32 username and password stuff. + */ + +/* + * 'cupsUser()' - Return the current user's name. + */ + +const char * /* O - User name */ +cupsUser(void) +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + if (!cg->user[0]) + { + DWORD size; /* Size of string */ + + + size = sizeof(cg->user); + if (!GetUserName(cg->user, &size)) + { + /* + * Use the default username... + */ + + strcpy(cg->user, "unknown"); + } + } + + return (cg->user); +} + + +/* + * '_cupsGetPassword()' - Get a password from the user. + */ + +const char * /* O - Password */ +_cupsGetPassword(const char *prompt) /* I - Prompt string */ +{ + return (NULL); +} +#else +/* + * UNIX username and password stuff... + */ + +# include + +/* + * 'cupsUser()' - Return the current user's name. + */ + +const char * /* O - User name */ +cupsUser(void) +{ + struct passwd *pwd; /* User/password entry */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + if (!cg->user[0]) + { + /* + * Rewind the password file... + */ + + setpwent(); + + /* + * Lookup the password entry for the current user. + */ + + if ((pwd = getpwuid(getuid())) == NULL) + strcpy(cg->user, "unknown"); /* Unknown user! */ + else + { + /* + * Copy the username... + */ + + setpwent(); + + strlcpy(cg->user, pwd->pw_name, sizeof(cg->user)); + } + + /* + * Rewind the password file again... + */ + + setpwent(); + } + + return (cg->user); +} + + +/* + * '_cupsGetPassword()' - Get a password from the user. + */ + +const char * /* O - Password */ +_cupsGetPassword(const char *prompt) /* I - Prompt string */ +{ + return (getpass(prompt)); +} +#endif /* WIN32 */ + + +/* + * End of "$Id: usersys.c 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/cups/utf8demo.txt b/cups/utf8demo.txt new file mode 100644 index 000000000..03802e4d7 --- /dev/null +++ b/cups/utf8demo.txt @@ -0,0 +1,213 @@ +UTF-8 encoded sample plain-text file +‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾ + +Markus Kuhn [ˈmaʳkʊs kuːn] — 2002-07-25 + + +The ASCII compatible UTF-8 encoding used in this plain-text file +is defined in Unicode, ISO 10646-1, and RFC 2279. + + +Using Unicode/UTF-8, you can write in emails and source code things such as + +Mathematics and sciences: + + ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ⎧⎡⎛┌─────┐⎞⎤⎫ + ⎪⎢⎜│a²+b³ ⎟⎥⎪ + ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), ⎪⎢⎜│───── ⎟⎥⎪ + ⎪⎢⎜⎷ c₈ ⎟⎥⎪ + ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⎨⎢⎜ ⎟⎥⎬ + ⎪⎢⎜ ∞ ⎟⎥⎪ + ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (⟦A⟧ ⇔ ⟪B⟫), ⎪⎢⎜ ⎲ ⎟⎥⎪ + ⎪⎢⎜ ⎳aⁱ-bⁱ⎟⎥⎪ + 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm ⎩⎣⎝i=1 ⎠⎦⎭ + +Linguistics and dictionaries: + + ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn + Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ] + +APL: + + ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ + +Nicer typography in plain text files: + + ╔══════════════════════════════════════════╗ + ║ ║ + ║ • ‘single’ and “double” quotes ║ + ║ ║ + ║ • Curly apostrophes: “We’ve been here” ║ + ║ ║ + ║ • Latin-1 apostrophe and accents: '´` ║ + ║ ║ + ║ • ‚deutsche‘ „Anführungszeichen“ ║ + ║ ║ + ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ + ║ ║ + ║ • ASCII safety test: 1lI|, 0OD, 8B ║ + ║ ╭─────────╮ ║ + ║ • the euro symbol: │ 14.95 € │ ║ + ║ ╰─────────╯ ║ + ╚══════════════════════════════════════════╝ + +Combining characters: + + STARGΛ̊TE SG-1, a = v̇ = r̈, a⃑ ⊥ b⃑ + +Greek (in Polytonic): + + The Greek anthem: + + Σὲ γνωρίζω ἀπὸ τὴν κόψη + τοῦ σπαθιοῦ τὴν τρομερή, + σὲ γνωρίζω ἀπὸ τὴν ὄψη + ποὺ μὲ βία μετράει τὴ γῆ. + + ᾿Απ᾿ τὰ κόκκαλα βγαλμένη + τῶν ῾Ελλήνων τὰ ἱερά + καὶ σὰν πρῶτα ἀνδρειωμένη + χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά! + + From a speech of Demosthenes in the 4th century BC: + + Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, + ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς + λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ + τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿ + εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ + πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν + οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι, + οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν + ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον + τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι + γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν + προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους + σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ + τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ + τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς + τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον. + + Δημοσθένους, Γ´ ᾿Ολυνθιακὸς + +Georgian: + + From a Unicode conference invitation: + + გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო + კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს, + ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს + ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი, + ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება + ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში, + ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში. + +Russian: + + From a Unicode conference invitation: + + Зарегистрируйтесь сейчас на Десятую Международную Конференцию по + Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии. + Конференция соберет широкий круг экспертов по вопросам глобального + Интернета и Unicode, локализации и интернационализации, воплощению и + применению Unicode в различных операционных системах и программных + приложениях, шрифтах, верстке и многоязычных компьютерных системах. + +Thai (UCS Level 2): + + Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese + classic 'San Gua'): + + [----------------------------|------------------------] + ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ + สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา + ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา + โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ + เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ + ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ + พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้ + ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ + + (The above is a two-column text. If combining characters are handled + correctly, the lines of the second column should be aligned with the + | character above.) + +Ethiopian: + + Proverbs in the Amharic language: + + ሰማይ አይታረስ ንጉሥ አይከሰስ። + ብላ ካለኝ እንደአባቴ በቆመጠኝ። + ጌጥ ያለቤቱ ቁምጥና ነው። + ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው። + የአፍ ወለምታ በቅቤ አይታሽም። + አይጥ በበላ ዳዋ ተመታ። + ሲተረጉሙ ይደረግሙ። + ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል። + ድር ቢያብር አንበሳ ያስር። + ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም። + እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም። + የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ። + ሥራ ከመፍታት ልጄን ላፋታት። + ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል። + የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ። + ተንጋሎ ቢተፉ ተመልሶ ባፉ። + ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው። + እግርህን በፍራሽህ ልክ ዘርጋ። + +Runes: + + ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ + + (Old English, which transcribed into Latin reads 'He cwaeth that he + bude thaem lande northweardum with tha Westsae.' and means 'He said + that he lived in the northern land near the Western Sea.') + +Braille: + + ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ + + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞ + ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎ + ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂ + ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙ + ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑ + ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲ + + ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹ + ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞ + ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕ + ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹ + ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎ + ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎ + ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳ + ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞ + ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ + + (The first couple of paragraphs of "A Christmas Carol" by Dickens) + +Compact font selection example text: + + ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 + abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ + –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд + ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi?⑀₂ἠḂӥẄɐː⍎אԱა + +Greetings in various languages: + + Hello world, Καλημέρα κόσμε, コンニチハ + +Box drawing alignment tests: █ + ▉ + ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ + ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ + ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ + ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ + ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ + ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ + ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ ▗▄▖▛▀▜ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ + ▝▀▘▙▄▟ + + diff --git a/cups/util.c b/cups/util.c new file mode 100644 index 000000000..7144ecec4 --- /dev/null +++ b/cups/util.c @@ -0,0 +1,1892 @@ +/* + * "$Id: util.c 4918 2006-01-12 05:14:40Z mike $" + * + * Printing utilities for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsCancelJob() - Cancel a print job on the default server. + * cupsDoFileRequest() - Do an IPP request. + * cupsFreeJobs() - Free memory used by job data. + * cupsGetClasses() - Get a list of printer classes from the default server. + * cupsGetDefault() - Get the default printer or class from the default server. + * cupsGetDefault2() - Get the default printer or class from the specified server. + * cupsGetJobs() - Get the jobs from the default server. + * cupsGetJobs2() - Get the jobs from the specified server. + * cupsGetPPD() - Get the PPD file for a printer on the default server. + * cupsGetPPD2() - Get the PPD file for a printer on the specified server. + * cupsGetPrinters() - Get a list of printers from the default server. + * cupsLastError() - Return the last IPP status code. + * cupsLastErrorString() - Return the last IPP status-message. + * cupsPrintFile() - Print a file to a printer or class on the default server. + * cupsPrintFile2() - Print a file to a printer or class on the specified server. + * cupsPrintFiles() - Print one or more files to a printer or class on the default server. + * cupsPrintFiles2() - Print one or more files to a printer or class on the specified server. + * cups_connect() - Connect to the specified host... + * cups_set_error() - Set the last IPP status code and status-message. + */ + +/* + * Include necessary headers... + */ + +#include "globals.h" +#include "debug.h" +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local functions... + */ + +static char *cups_connect(const char *name, char *printer, char *hostname); +static void cups_set_error(ipp_status_t status, const char *message); + + +/* + * 'cupsCancelJob()' - Cancel a print job on the default server. + * + * Use the cupsLastError() and cupsLastErrorString() functions to get + * the cause of any failure. + */ + +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 */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * See if we can connect to the server... + */ + + if (!cups_connect(name, printer, hostname)) + { + DEBUG_puts("Unable to connect to server!"); + + return (0); + } + + /* + * Create a printer URI... + */ + + if (httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", printer) != HTTP_URI_OK) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + 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"); + + cupsLangFree(language); + + 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(cg->http, request, "/jobs/")) != NULL) + ippDelete(response); + + return (cg->last_error < IPP_REDIRECTION_OTHER_SITE); +} + + +/* + * 'cupsDoFileRequest()' - Do an IPP request. + * + * This function sends any IPP request to the specified server, retrying + * and authenticating as necessary. + */ + +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 for none */ +{ + ipp_t *response; /* IPP response data */ + size_t length; /* Content-Length value */ + 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[65536]; /* Output buffer */ + + + DEBUG_printf(("cupsDoFileRequest(%p, %p, \'%s\', \'%s\')\n", + http, request, resource ? resource : "(null)", + filename ? filename : "(null)")); + + if (http == NULL || request == NULL || resource == NULL) + { + if (request != NULL) + ippDelete(request); + + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (NULL); + } + + /* + * See if we have a file to send... + */ + + if (filename != NULL) + { + if (stat(filename, &fileinfo)) + { + /* + * Can't get file information! + */ + + cups_set_error(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, + strerror(errno)); + + ippDelete(request); + + return (NULL); + } + +#ifdef WIN32 + if (fileinfo.st_mode & _S_IFDIR) +#else + if (S_ISDIR(fileinfo.st_mode)) +#endif /* WIN32 */ + { + /* + * Can't send a directory... + */ + + ippDelete(request); + + cups_set_error(IPP_NOT_POSSIBLE, NULL); + + return (NULL); + } + + if ((file = fopen(filename, "rb")) == NULL) + { + /* + * Can't open file! + */ + + cups_set_error(errno == ENOENT ? IPP_NOT_FOUND : IPP_NOT_AUTHORIZED, + strerror(errno)); + + ippDelete(request); + + return (NULL); + } + } + else + file = NULL; + + /* + * Loop until we can send the request without authorization problems. + */ + + response = NULL; + status = HTTP_ERROR; + + while (response == NULL) + { + DEBUG_puts("cupsDoFileRequest: setup..."); + + /* + * Setup the HTTP variables needed... + */ + + length = ippLength(request); + if (filename) + length += fileinfo.st_size; + + httpClearFields(http); + httpSetLength(http, length); + httpSetField(http, HTTP_FIELD_CONTENT_TYPE, "application/ipp"); + httpSetField(http, HTTP_FIELD_AUTHORIZATION, http->authstring); + + DEBUG_printf(("cupsDoFileRequest: authstring=\"%s\"\n", http->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; + status = HTTP_CONTINUE; + + if (ippWrite(http, request) != IPP_ERROR) + if (filename != NULL) + { + DEBUG_puts("cupsDoFileRequest: file write..."); + + /* + * Send the file... + */ + + rewind(file); + + while ((bytes = (int)fread(buffer, 1, sizeof(buffer), file)) > 0) + { + if (httpCheck(http)) + { + if ((status = httpUpdate(http)) != HTTP_CONTINUE) + break; + } + + if (httpWrite(http, buffer, bytes) < bytes) + break; + } + } + + /* + * Get the server's return status... + */ + + DEBUG_puts("cupsDoFileRequest: update..."); + + while (status == HTTP_CONTINUE) + status = httpUpdate(http); + + DEBUG_printf(("cupsDoFileRequest: status = %d\n", status)); + + if (status == HTTP_UNAUTHORIZED) + { + DEBUG_puts("cupsDoFileRequest: unauthorized..."); + + /* + * Flush any error message... + */ + + httpFlush(http); + + /* + * See if we can do authentication... + */ + + if (cupsDoAuthentication(http, "POST", resource)) + break; + + httpReconnect(http); + + 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_SSL + else if (status == HTTP_UPGRADE_REQUIRED) + { + /* Flush any error message... */ + httpFlush(http); + + /* Reconnect... */ + if (httpReconnect(http)) + { + status = HTTP_ERROR; + break; + } + + /* Upgrade with encryption... */ + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); + + /* Try again, this time with encryption enabled... */ + continue; + } +#endif /* HAVE_SSL */ + 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... + */ + + DEBUG_puts("IPP read error!"); + ippDelete(response); + response = NULL; + + cups_set_error(IPP_SERVICE_UNAVAILABLE, strerror(errno)); + + 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) + { + ipp_attribute_t *attr; /* status-message attribute */ + + + attr = ippFindAttribute(response, "status-message", IPP_TAG_TEXT); + + cups_set_error(response->request.status.status_code, + attr ? attr->values[0].string.text : + ippErrorString(response->request.status.status_code)); + } + else if (status != HTTP_OK) + { + switch (status) + { + case HTTP_NOT_FOUND : + cups_set_error(IPP_NOT_FOUND, httpStatus(status)); + break; + + case HTTP_UNAUTHORIZED : + cups_set_error(IPP_NOT_AUTHORIZED, httpStatus(status)); + break; + + case HTTP_FORBIDDEN : + cups_set_error(IPP_FORBIDDEN, httpStatus(status)); + break; + + case HTTP_BAD_REQUEST : + cups_set_error(IPP_BAD_REQUEST, httpStatus(status)); + break; + + case HTTP_REQUEST_TOO_LARGE : + cups_set_error(IPP_REQUEST_VALUE, httpStatus(status)); + break; + + case HTTP_NOT_IMPLEMENTED : + cups_set_error(IPP_OPERATION_NOT_SUPPORTED, httpStatus(status)); + break; + + case HTTP_NOT_SUPPORTED : + cups_set_error(IPP_VERSION_NOT_SUPPORTED, httpStatus(status)); + break; + + default : + DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n", + status)); + cups_set_error(IPP_SERVICE_UNAVAILABLE, httpStatus(status)); + break; + } + } + + 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 from the default server. + * + * This function is deprecated - use cupsGetDests() instead. + * + * @deprecated@ + */ + +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 */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + if (classes == NULL) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (0); + } + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + DEBUG_puts("Unable to connect to server!"); + + 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); + + cupsLangFree(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(cg->http, request, "/")) != NULL) + { + 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); + } + + return (n); +} + + +/* + * 'cupsGetDefault()' - Get the default printer or class for the default server. + * + * This function returns the default printer or class as defined by + * the LPDEST or PRINTER environment variables. If these environment + * variables are not set, the server default destination is returned. + * Applications should use the cupsGetDests() and cupsGetDest() functions + * to get the user-defined default printer, as this function does not + * support the lpoptions-defined default printer. + */ + +const char * /* O - Default printer or NULL */ +cupsGetDefault(void) +{ + const char *var; /* Environment variable */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * 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)) + { + DEBUG_puts("Unable to connect to server!"); + + return (NULL); + } + + /* + * Return the default printer... + */ + + return (cupsGetDefault2(cg->http)); +} + + +/* + * 'cupsGetDefault2()' - Get the default printer or class for the specified server. + * + * This function returns the default printer or class as defined by + * the LPDEST or PRINTER environment variables. If these environment + * variables are not set, the server default destination is returned. + * Applications should use the cupsGetDests() and cupsGetDest() functions + * to get the user-defined default printer, as this function does not + * support the lpoptions-defined default printer. + * + * @since CUPS 1.1.21@ + */ + +const char * /* O - Default printer or NULL */ +cupsGetDefault2(http_t *http) /* I - HTTP connection */ +{ + 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 */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + /* + * 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); + + /* + * Range check input... + */ + + if (!http) + 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); + + cupsLangFree(language); + + /* + * Do the request and get back a response... + */ + + if ((response = cupsDoRequest(http, request, "/")) != NULL) + { + if ((attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME)) != NULL) + { + strlcpy(cg->def_printer, attr->values[0].string.text, sizeof(cg->def_printer)); + ippDelete(response); + return (cg->def_printer); + } + + ippDelete(response); + } + + return (NULL); +} + + +/* + * 'cupsGetJobs()' - Get the jobs from the default 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? */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + DEBUG_puts("Unable to connect to server!"); + + return (-1); + } + + /* + * Return the jobs... + */ + + return (cupsGetJobs2(cg->http, jobs, mydest, myjobs, completed)); +} + + + +/* + * 'cupsGetJobs2()' - Get the jobs from the specified server. + * + * @since CUPS 1.1.21@ + */ + +int /* O - Number of jobs */ +cupsGetJobs2(http_t *http, /* I - HTTP connection */ + 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 */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + static const char * const 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" + }; + + + /* + * Range check input... + */ + + if (!http || !jobs) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (-1); + } + + /* + * Get the right URI... + */ + + if (mydest) + { + if (httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", mydest) != HTTP_URI_OK) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (-1); + } + } + else + strcpy(uri, "ipp://localhost/jobs"); + + + /* + * 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); + + cupsLangFree(language); + + 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(http, request, "/")) != NULL) + { + 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 = "unknown"; + dest = NULL; + format = "application/octet-stream"; + title = "untitled"; + 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 || + attr->value_tag == IPP_TAG_NAME)) + title = attr->values[0].string.text; + + attr = attr->next; + } + + /* + * See if we have everything needed... + */ + + if (dest == 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; + + if (attr == NULL) + break; + } + + ippDelete(response); + } + + if (n == 0 && cg->last_error >= IPP_BAD_REQUEST) + return (-1); + else + return (n); +} + + +/* + * 'cupsGetPPD()' - Get the PPD file for a printer on the default server. + * + * For classes, cupsGetPPD() returns the PPD file for the first printer + * in the class. + */ + +const char * /* O - Filename for PPD file */ +cupsGetPPD(const char *name) /* I - Printer name */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + /* + * See if we can connect to the server... + */ + + if (!cups_connect(name, NULL, NULL)) + { + DEBUG_puts("Unable to connect to server!"); + + return (NULL); + } + + /* + * Return the PPD file... + */ + + return (cupsGetPPD2(cg->http, name)); +} + + +/* + * 'cupsGetPPD2()' - Get the PPD file for a printer from the specified server. + * + * For classes, cupsGetPPD2() returns the PPD file for the first printer + * in the class. + * + * @since CUPS 1.1.21@ + */ + +const char * /* O - Filename for PPD file */ +cupsGetPPD2(http_t *http, /* I - HTTP connection */ + const char *name) /* I - Printer name */ +{ + int i; /* Looping var */ + int http_port; /* Port number */ + http_t *http2; /* Alternate HTTP connection */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Local language */ + int fd; /* PPD file */ + char uri[HTTP_MAX_URI], /* Printer URI */ + 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 */ + http_status_t status; /* HTTP status from server */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + static const char * const requested_attrs[] = + { /* Requested attributes */ + "printer-uri-supported", + "printer-type", + "member-uris" + }; + + + /* + * Range check input... + */ + + DEBUG_printf(("cupsGetPPD2(http=%p, name=\"%s\")\n", http, + name ? name : "(null)")); + + if (!http || !name) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (NULL); + } + + /* + * Setup the printer URI... + */ + + if (httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", name) != HTTP_URI_OK) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (NULL); + } + + /* + * Get the port number we are connect to... + */ + +#ifdef AF_INET6 + if (http->hostaddr->addr.sa_family == AF_INET6) + http_port = ntohs(http->hostaddr->ipv6.sin6_port); + else +#endif /* AF_INET6 */ + if (http->hostaddr->addr.sa_family == AF_INET) + http_port = ntohs(http->hostaddr->ipv4.sin_port); + else + http_port = ippPort(); + + port = http_port; + + /* + * 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); + + cupsLangFree(language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + DEBUG_printf(("cupsGetPPD2: printer-uri=\"%s\"\n", uri)); + + 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(http, request, "/")) != NULL) + { + 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 ++) + { + httpSeparateURI(attr->values[i].string.text, method, sizeof(method), + username, sizeof(username), hostname, sizeof(hostname), + &port, resource, sizeof(resource)); + if (!strncmp(resource, "/printers/", 10)) + { + /* + * Found a printer! + */ + + strlcpy(printer, resource + 10, sizeof(printer)); + break; + } + } + } + else if ((attr = ippFindAttribute(response, "printer-uri-supported", + IPP_TAG_URI)) != NULL) + { + /* + * Get the actual server and printer names... + */ + + httpSeparateURI(attr->values[0].string.text, method, sizeof(method), + username, sizeof(username), hostname, sizeof(hostname), + &port, resource, sizeof(resource)); + + strlcpy(printer, strrchr(resource, '/') + 1, sizeof(printer)); + } + + ippDelete(response); + + /* + * Remap local hostname to localhost... + */ + + httpGetHostname(uri, sizeof(uri)); + + if (!strcasecmp(uri, hostname)) + strcpy(hostname, "localhost"); + } + + if (!printer[0]) + { + cups_set_error(IPP_NOT_FOUND, NULL); + return (NULL); + } + + /* + * Reconnect to the correct server as needed... + */ + + if (!strcasecmp(http->hostname, hostname) && port == http_port) + http2 = http; + else if ((http2 = httpConnectEncrypt(hostname, port, + cupsEncryption())) == NULL) + { + DEBUG_puts("Unable to connect to server!"); + + return (NULL); + } + + /* + * Get a temp file... + */ + + if ((fd = cupsTempFd(cg->ppd_filename, sizeof(cg->ppd_filename))) < 0) + { + /* + * Can't open file; close the server connection and return NULL... + */ + + cups_set_error(IPP_INTERNAL_ERROR, strerror(errno)); + + if (http2 != http) + httpClose(http2); + + return (NULL); + } + + /* + * And send a request to the HTTP server... + */ + + snprintf(resource, sizeof(resource), "/printers/%s.ppd", printer); + + status = cupsGetFd(http2, resource, fd); + + close(fd); + + if (http2 != http) + httpClose(http2); + + /* + * See if we actually got the file or an error... + */ + + if (status != HTTP_OK) + { + switch (status) + { + case HTTP_NOT_FOUND : + cups_set_error(IPP_NOT_FOUND, httpStatus(status)); + break; + + case HTTP_UNAUTHORIZED : + cups_set_error(IPP_NOT_AUTHORIZED, httpStatus(status)); + break; + + default : + DEBUG_printf(("HTTP error %d mapped to IPP_SERVICE_UNAVAILABLE!\n", + status)); + cups_set_error(IPP_SERVICE_UNAVAILABLE, httpStatus(status)); + break; + } + + unlink(cg->ppd_filename); + + return (NULL); + } + + /* + * Return the PPD file... + */ + + return (cg->ppd_filename); +} + + +/* + * 'cupsGetPrinters()' - Get a list of printers from the default server. + * + * This function is deprecated - use cupsGetDests() instead. + * + * @deprecated@ + */ + +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 */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + if (printers == NULL) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (0); + } + + /* + * Try to connect to the server... + */ + + if (!cups_connect("default", NULL, NULL)) + { + DEBUG_puts("Unable to connect to server!"); + + 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); + + cupsLangFree(language); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", NULL, "printer-name"); + + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, + "printer-type", 0); + + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, + "printer-type-mask", CUPS_PRINTER_CLASS); + + /* + * Do the request and get back a response... + */ + + n = 0; + *printers = NULL; + + if ((response = cupsDoRequest(cg->http, request, "/")) != NULL) + { + 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); + } + + return (n); +} + + +/* + * 'cupsLastError()' - Return the last IPP status code. + */ + +ipp_status_t /* O - IPP status code from last request */ +cupsLastError(void) +{ + return (_cupsGlobals()->last_error); +} + + +/* + * 'cupsLastErrorString()' - Return the last IPP status-message. + * + * @since CUPS 1.2@ + */ + +const char * /* O - status-message text from last request */ +cupsLastErrorString(void) +{ + return (_cupsGlobals()->last_status_message); +} + + +/* + * 'cupsPrintFile()' - Print a file to a printer or class on the default server. + */ + +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(name=\"%s\", filename=\"%s\", " + "title=\"%s\", num_options=%d, options=%p)\n", + name, filename, title, num_options, options)); + + return (cupsPrintFiles(name, 1, &filename, title, num_options, options)); +} + + +/* + * 'cupsPrintFile2()' - Print a file to a printer or class on the specified server. + * + * @since CUPS 1.1.21@ + */ + +int /* O - Job ID */ +cupsPrintFile2(http_t *http, /* I - HTTP connection */ + 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(("cupsPrintFile2(http=%p, name=\"%s\", filename=\"%s\", " + "title=\"%s\", num_options=%d, options=%p)\n", + http, name, filename, title, num_options, options)); + + return (cupsPrintFiles2(http, name, 1, &filename, title, num_options, options)); +} + + +/* + * 'cupsPrintFiles()' - Print one or more files to a printer or class on the default server. + */ + +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 */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + DEBUG_printf(("cupsPrintFiles(name=\"%s\", num_files=%d, " + "files=%p, title=\"%s\", num_options=%d, options=%p)\n", + name, num_files, files, title, num_options, options)); + + + /* + * Setup a connection and request data... + */ + + if (!cups_connect(name, NULL, NULL)) + { + DEBUG_printf(("cupsPrintFiles: Unable to open connection - %s.\n", + strerror(errno))); + DEBUG_puts("Unable to connect to server!"); + + return (0); + } + + /* + * Print the file(s)... + */ + + return (cupsPrintFiles2(cg->http, name, num_files, files, title, + num_options, options)); +} + + + +/* + * 'cupsPrintFiles2()' - Print one or more files to a printer or class on the specified server. + * + * @since CUPS 1.1.21@ + */ + +int /* O - Job ID */ +cupsPrintFiles2(http_t *http, /* I - HTTP connection */ + 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 uri[HTTP_MAX_URI]; /* Printer URI */ + cups_lang_t *language; /* Language to use */ + int jobid; /* New job ID */ + + + DEBUG_printf(("cupsPrintFiles(http=%p, name=\"%s\", num_files=%d, " + "files=%p, title=\"%s\", num_options=%d, options=%p)\n", + http, name, num_files, files, title, num_options, options)); + + /* + * Range check input... + */ + + if (!http || !name || num_files < 1 || files == NULL) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (0); + } + + /* + * Setup the printer URI... + */ + + if (httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", name) != HTTP_URI_OK) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (0); + } + + /* + * Setup the request data... + */ + + language = cupsLangDefault(); + + /* + * Build a standard CUPS URI for the printer and fill the standard IPP + * attributes... + */ + + if ((request = ippNew()) == NULL) + { + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + return (0); + } + + request->request.op.operation_id = num_files == 1 ? IPP_PRINT_JOB : + IPP_CREATE_JOB; + request->request.op.request_id = 1; + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + 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", name); + + if (num_files == 1) + response = cupsDoFileRequest(http, request, uri, *files); + else + response = cupsDoRequest(http, 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!"); + + cups_set_error(IPP_INTERNAL_ERROR, NULL); + + 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://localhost/jobs/%d", 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", name); + + if ((response = cupsDoFileRequest(http, request, uri, + files[i])) != NULL) + ippDelete(response); + } + + cupsLangFree(language); + + 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 */ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + DEBUG_printf(("cups_connect(\"%s\", %p, %p)\n", name, printer, hostname)); + + if (name == NULL) + { + cups_set_error(IPP_BAD_REQUEST, NULL); + + return (NULL); + } + + /* + * All jobs are now queued to cupsServer() to avoid hostname + * resolution problems and to ensure that the user sees all + * locally queued jobs locally. + */ + + strlcpy(hostbuf, cupsServer(), sizeof(hostbuf)); + + if (hostname != NULL) + strlcpy(hostname, hostbuf, HTTP_MAX_URI); + else + hostname = hostbuf; + + if (printer != NULL) + strlcpy(printer, name, HTTP_MAX_URI); + else + printer = (char *)name; + + if (cg->http != NULL) + { + if (!strcasecmp(cg->http->hostname, hostname)) + return (printer); + + httpClose(cg->http); + } + + DEBUG_printf(("connecting to %s on port %d...\n", hostname, ippPort())); + + if ((cg->http = httpConnectEncrypt(hostname, ippPort(), + cupsEncryption())) == NULL) + { + DEBUG_puts("Unable to connect to server!"); + + cups_set_error(IPP_SERVICE_UNAVAILABLE, strerror(errno)); + + return (NULL); + } + else + return (printer); +} + + +/* + * 'cups_set_error()' - Set the last IPP status code and status-message. + */ + +static void +cups_set_error(ipp_status_t status, /* I - IPP status code */ + const char *message) /* I - status-message value */ +{ + _cups_globals_t *cg; /* Global data */ + + + cg = _cupsGlobals(); + cg->last_error = status; + + if (cg->last_status_message) + { + free(cg->last_status_message); + + cg->last_status_message = NULL; + } + + if (message) + cg->last_status_message = strdup(message); +} + + +/* + * End of "$Id: util.c 4918 2006-01-12 05:14:40Z mike $". + */ diff --git a/data/HPGLprolog b/data/HPGLprolog new file mode 100644 index 000000000..eed0a0487 --- /dev/null +++ b/data/HPGLprolog @@ -0,0 +1,37 @@ +%%BeginResource: procset hpgltops 1.1 0 +% +% "$Id: HPGLprolog 4494 2005-02-18 02:18:11Z 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-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/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..bf9e47d18 --- /dev/null +++ b/data/Makefile @@ -0,0 +1,160 @@ +# +# "$Id: Makefile 4494 2005-02-18 02:18:11Z mike $" +# +# Datafile makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Data files... +# + +BANNERS = \ + classified \ + confidential \ + secret \ + standard \ + topsecret \ + unclassified + +CHARMAPS = \ + euc-cn.txt \ + euc-jp.txt \ + euc-kr.txt \ + euc-tw.txt \ + i18n_sdd.txt \ + iso-8859-10.txt \ + iso-8859-11.txt \ + iso-8859-13.txt \ + iso-8859-14.txt \ + iso-8859-15.txt \ + iso-8859-16.txt \ + iso-8859-1.txt \ + iso-8859-2.txt \ + iso-8859-3.txt \ + iso-8859-4.txt \ + iso-8859-5.txt \ + iso-8859-6.txt \ + iso-8859-7.txt \ + iso-8859-8.txt \ + iso-8859-9.txt \ + koi8-r.txt \ + koi8-u.txt \ + unibreak.txt \ + uni-comb.txt \ + uni-fold.txt \ + uni-full.txt \ + uni-line.txt \ + uni-nfc.txt \ + uni-nfd.txt \ + uni-nfkd.txt \ + uni-prop.txt \ + windows-1250.txt \ + windows-1251.txt \ + windows-1252.txt \ + windows-1253.txt \ + windows-1254.txt \ + windows-1255.txt \ + windows-1256.txt \ + windows-1257.txt \ + windows-1258.txt \ + windows-1361.txt \ + windows-874.txt \ + windows-932.txt \ + windows-936.txt \ + windows-949.txt \ + windows-950.txt + +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 \ + 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)/charmaps + for file in $(CHARMAPS); do \ + $(INSTALL_DATA) $$file $(DATADIR)/charmaps; \ + 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 + + +# +# End of "$Id: Makefile 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/data/classified b/data/classified new file mode 100644 index 000000000..3f8a1ab82 --- /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-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/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 4494 2005-02-18 02:18:11Z mike $". +% +%%EOF diff --git a/data/confidential b/data/confidential new file mode 100644 index 000000000..27d29fbcc --- /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-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/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 4494 2005-02-18 02:18:11Z 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..a9369e161 --- /dev/null +++ b/data/cups.suse @@ -0,0 +1,2 @@ +auth required pam_unix2.so nullok shadow +account required pam_unix2.so diff --git a/data/euc-cn.txt b/data/euc-cn.txt new file mode 100644 index 000000000..72726c5fa --- /dev/null +++ b/data/euc-cn.txt @@ -0,0 +1,7536 @@ +# euc-cn.txt - EUC to Unicode charmap +0x00000000 0x0000 # 0 +0x00000001 0x0001 # 0 +0x00000002 0x0002 # 0 +0x00000003 0x0003 # 0 +0x00000004 0x0004 # 0 +0x00000005 0x0005 # 0 +0x00000006 0x0006 # 0 +0x00000007 0x0007 # 0 +0x00000008 0x0008 # 0 +0x00000009 0x0009 # 0 +0x0000000A 0x000A # 0 +0x0000000B 0x000B # 0 +0x0000000C 0x000C # 0 +0x0000000D 0x000D # 0 +0x0000000E 0x000E # 0 +0x0000000F 0x000F # 0 +0x00000010 0x0010 # 0 +0x00000011 0x0011 # 0 +0x00000012 0x0012 # 0 +0x00000013 0x0013 # 0 +0x00000014 0x0014 # 0 +0x00000015 0x0015 # 0 +0x00000016 0x0016 # 0 +0x00000017 0x0017 # 0 +0x00000018 0x0018 # 0 +0x00000019 0x0019 # 0 +0x0000001A 0x001A # 0 +0x0000001B 0x001B # 0 +0x0000001C 0x001C # 0 +0x0000001D 0x001D # 0 +0x0000001E 0x001E # 0 +0x0000001F 0x001F # 0 +0x00000020 0x0020 # 0 +0x00000021 0x0021 # 0 +0x00000022 0x0022 # 0 +0x00000023 0x0023 # 0 +0x00000024 0x0024 # 0 +0x00000025 0x0025 # 0 +0x00000026 0x0026 # 0 +0x00000027 0x0027 # 0 +0x00000028 0x0028 # 0 +0x00000029 0x0029 # 0 +0x0000002A 0x002A # 0 +0x0000002B 0x002B # 0 +0x0000002C 0x002C # 0 +0x0000002D 0x002D # 0 +0x0000002E 0x002E # 0 +0x0000002F 0x002F # 0 +0x00000030 0x0030 # 0 +0x00000031 0x0031 # 0 +0x00000032 0x0032 # 0 +0x00000033 0x0033 # 0 +0x00000034 0x0034 # 0 +0x00000035 0x0035 # 0 +0x00000036 0x0036 # 0 +0x00000037 0x0037 # 0 +0x00000038 0x0038 # 0 +0x00000039 0x0039 # 0 +0x0000003A 0x003A # 0 +0x0000003B 0x003B # 0 +0x0000003C 0x003C # 0 +0x0000003D 0x003D # 0 +0x0000003E 0x003E # 0 +0x0000003F 0x003F # 0 +0x00000040 0x0040 # 0 +0x00000041 0x0041 # 0 +0x00000042 0x0042 # 0 +0x00000043 0x0043 # 0 +0x00000044 0x0044 # 0 +0x00000045 0x0045 # 0 +0x00000046 0x0046 # 0 +0x00000047 0x0047 # 0 +0x00000048 0x0048 # 0 +0x00000049 0x0049 # 0 +0x0000004A 0x004A # 0 +0x0000004B 0x004B # 0 +0x0000004C 0x004C # 0 +0x0000004D 0x004D # 0 +0x0000004E 0x004E # 0 +0x0000004F 0x004F # 0 +0x00000050 0x0050 # 0 +0x00000051 0x0051 # 0 +0x00000052 0x0052 # 0 +0x00000053 0x0053 # 0 +0x00000054 0x0054 # 0 +0x00000055 0x0055 # 0 +0x00000056 0x0056 # 0 +0x00000057 0x0057 # 0 +0x00000058 0x0058 # 0 +0x00000059 0x0059 # 0 +0x0000005A 0x005A # 0 +0x0000005B 0x005B # 0 +0x0000005C 0x005C # 0 +0x0000005D 0x005D # 0 +0x0000005E 0x005E # 0 +0x0000005F 0x005F # 0 +0x00000060 0x0060 # 0 +0x00000061 0x0061 # 0 +0x00000062 0x0062 # 0 +0x00000063 0x0063 # 0 +0x00000064 0x0064 # 0 +0x00000065 0x0065 # 0 +0x00000066 0x0066 # 0 +0x00000067 0x0067 # 0 +0x00000068 0x0068 # 0 +0x00000069 0x0069 # 0 +0x0000006A 0x006A # 0 +0x0000006B 0x006B # 0 +0x0000006C 0x006C # 0 +0x0000006D 0x006D # 0 +0x0000006E 0x006E # 0 +0x0000006F 0x006F # 0 +0x00000070 0x0070 # 0 +0x00000071 0x0071 # 0 +0x00000072 0x0072 # 0 +0x00000073 0x0073 # 0 +0x00000074 0x0074 # 0 +0x00000075 0x0075 # 0 +0x00000076 0x0076 # 0 +0x00000077 0x0077 # 0 +0x00000078 0x0078 # 0 +0x00000079 0x0079 # 0 +0x0000007A 0x007A # 0 +0x0000007B 0x007B # 0 +0x0000007C 0x007C # 0 +0x0000007D 0x007D # 0 +0x0000007E 0x007E # 0 +0x0000007F 0x007F # 0 +0x0000A1A1 0x3000 # 0 +0x0000A1A2 0x3001 # 0 +0x0000A1A3 0x3002 # 0 +0x0000A1A4 0x30FB # 0 +0x0000A1A5 0x203E # 0 +0x0000A1A6 0x02C7 # 0 +0x0000A1A7 0x00A8 # 0 +0x0000A1A8 0x3003 # 0 +0x0000A1A9 0x3005 # 0 +0x0000A1AA 0x2015 # 0 +0x0000A1AB 0x30FC # 0 +0x0000A1AC 0x2225 # 0 +0x0000A1AD 0x2026 # 0 +0x0000A1AE 0x2018 # 0 +0x0000A1AF 0x2019 # 0 +0x0000A1B0 0x201C # 0 +0x0000A1B1 0x201D # 0 +0x0000A1B2 0x3014 # 0 +0x0000A1B3 0x3015 # 0 +0x0000A1B4 0x3008 # 0 +0x0000A1B5 0x3009 # 0 +0x0000A1B6 0x300A # 0 +0x0000A1B7 0x300B # 0 +0x0000A1B8 0x300C # 0 +0x0000A1B9 0x300D # 0 +0x0000A1BA 0x300E # 0 +0x0000A1BB 0x300F # 0 +0x0000A1BC 0x3016 # 0 +0x0000A1BD 0x3017 # 0 +0x0000A1BE 0x3010 # 0 +0x0000A1BF 0x3011 # 0 +0x0000A1C0 0x00B1 # 0 +0x0000A1C1 0x00D7 # 0 +0x0000A1C2 0x00F7 # 0 +0x0000A1C3 0x2236 # 0 +0x0000A1C4 0x2227 # 0 +0x0000A1C5 0x2228 # 0 +0x0000A1C6 0x2211 # 0 +0x0000A1C7 0x220F # 0 +0x0000A1C8 0x222A # 0 +0x0000A1C9 0x2229 # 0 +0x0000A1CA 0x2208 # 0 +0x0000A1CB 0x2237 # 0 +0x0000A1CC 0x221A # 0 +0x0000A1CD 0x22A5 # 0 +0x0000A1CF 0x2220 # 0 +0x0000A1D0 0x2312 # 0 +0x0000A1D1 0x2299 # 0 +0x0000A1D2 0x222B # 0 +0x0000A1D3 0x222E # 0 +0x0000A1D4 0x2261 # 0 +0x0000A1D5 0x224C # 0 +0x0000A1D6 0x2248 # 0 +0x0000A1D7 0x223D # 0 +0x0000A1D8 0x221D # 0 +0x0000A1D9 0x2260 # 0 +0x0000A1DA 0x226E # 0 +0x0000A1DB 0x226F # 0 +0x0000A1DC 0x2264 # 0 +0x0000A1DD 0x2265 # 0 +0x0000A1DE 0x221E # 0 +0x0000A1DF 0x2235 # 0 +0x0000A1E0 0x2234 # 0 +0x0000A1E1 0x2642 # 0 +0x0000A1E2 0x2640 # 0 +0x0000A1E3 0x00B0 # 0 +0x0000A1E4 0x2032 # 0 +0x0000A1E5 0x2033 # 0 +0x0000A1E6 0x2103 # 0 +0x0000A1E8 0x00A4 # 0 +0x0000A1E9 0x00A2 # 0 +0x0000A1EA 0x00A3 # 0 +0x0000A1EB 0x2030 # 0 +0x0000A1EC 0x00A7 # 0 +0x0000A1ED 0x2116 # 0 +0x0000A1EE 0x2606 # 0 +0x0000A1EF 0x2605 # 0 +0x0000A1F0 0x25CB # 0 +0x0000A1F1 0x25CF # 0 +0x0000A1F2 0x25CE # 0 +0x0000A1F3 0x25C7 # 0 +0x0000A1F4 0x25C6 # 0 +0x0000A1F5 0x25A1 # 0 +0x0000A1F6 0x25A0 # 0 +0x0000A1F7 0x25B3 # 0 +0x0000A1F8 0x25B2 # 0 +0x0000A1F9 0x203B # 0 +0x0000A1FA 0x2192 # 0 +0x0000A1FB 0x2190 # 0 +0x0000A1FC 0x2191 # 0 +0x0000A1FD 0x2193 # 0 +0x0000A1FE 0x3013 # 0 +0x0000A2B1 0x2488 # 0 +0x0000A2B2 0x2489 # 0 +0x0000A2B3 0x248A # 0 +0x0000A2B4 0x248B # 0 +0x0000A2B5 0x248C # 0 +0x0000A2B6 0x248D # 0 +0x0000A2B7 0x248E # 0 +0x0000A2B8 0x248F # 0 +0x0000A2B9 0x2490 # 0 +0x0000A2BA 0x2491 # 0 +0x0000A2BB 0x2492 # 0 +0x0000A2BC 0x2493 # 0 +0x0000A2BD 0x2494 # 0 +0x0000A2BE 0x2495 # 0 +0x0000A2BF 0x2496 # 0 +0x0000A2C0 0x2497 # 0 +0x0000A2C1 0x2498 # 0 +0x0000A2C2 0x2499 # 0 +0x0000A2C3 0x249A # 0 +0x0000A2C4 0x249B # 0 +0x0000A2C5 0x2474 # 0 +0x0000A2C6 0x2475 # 0 +0x0000A2C7 0x2476 # 0 +0x0000A2C8 0x2477 # 0 +0x0000A2C9 0x2478 # 0 +0x0000A2CA 0x2479 # 0 +0x0000A2CB 0x247A # 0 +0x0000A2CC 0x247B # 0 +0x0000A2CD 0x247C # 0 +0x0000A2CE 0x247D # 0 +0x0000A2CF 0x247E # 0 +0x0000A2D0 0x247F # 0 +0x0000A2D1 0x2480 # 0 +0x0000A2D2 0x2481 # 0 +0x0000A2D3 0x2482 # 0 +0x0000A2D4 0x2483 # 0 +0x0000A2D5 0x2484 # 0 +0x0000A2D6 0x2485 # 0 +0x0000A2D7 0x2486 # 0 +0x0000A2D8 0x2487 # 0 +0x0000A2D9 0x2460 # 0 +0x0000A2DA 0x2461 # 0 +0x0000A2DB 0x2462 # 0 +0x0000A2DC 0x2463 # 0 +0x0000A2DD 0x2464 # 0 +0x0000A2DE 0x2465 # 0 +0x0000A2DF 0x2466 # 0 +0x0000A2E0 0x2467 # 0 +0x0000A2E1 0x2468 # 0 +0x0000A2E2 0x2469 # 0 +0x0000A2F1 0x2160 # 0 +0x0000A2F2 0x2161 # 0 +0x0000A2F3 0x2162 # 0 +0x0000A2F4 0x2163 # 0 +0x0000A2F5 0x2164 # 0 +0x0000A2F6 0x2165 # 0 +0x0000A2F7 0x2166 # 0 +0x0000A2F8 0x2167 # 0 +0x0000A2F9 0x2168 # 0 +0x0000A2FA 0x2169 # 0 +0x0000A2FB 0x216A # 0 +0x0000A2FC 0x216B # 0 +0x0000A3A1 0xFF01 # 0 +0x0000A3A2 0xFF02 # 0 +0x0000A3A3 0xFF03 # 0 +0x0000A3A4 0xFF04 # 0 +0x0000A3A5 0xFF05 # 0 +0x0000A3A6 0xFF06 # 0 +0x0000A3A7 0xFF07 # 0 +0x0000A3A8 0xFF08 # 0 +0x0000A3A9 0xFF09 # 0 +0x0000A3AA 0xFF0A # 0 +0x0000A3AB 0xFF0B # 0 +0x0000A3AC 0xFF0C # 0 +0x0000A3AD 0xFF0D # 0 +0x0000A3AE 0xFF0E # 0 +0x0000A3AF 0xFF0F # 0 +0x0000A3B0 0xFF10 # 0 +0x0000A3B1 0xFF11 # 0 +0x0000A3B2 0xFF12 # 0 +0x0000A3B3 0xFF13 # 0 +0x0000A3B4 0xFF14 # 0 +0x0000A3B5 0xFF15 # 0 +0x0000A3B6 0xFF16 # 0 +0x0000A3B7 0xFF17 # 0 +0x0000A3B8 0xFF18 # 0 +0x0000A3B9 0xFF19 # 0 +0x0000A3BA 0xFF1A # 0 +0x0000A3BB 0xFF1B # 0 +0x0000A3BC 0xFF1C # 0 +0x0000A3BD 0xFF1D # 0 +0x0000A3BE 0xFF1E # 0 +0x0000A3BF 0xFF1F # 0 +0x0000A3C0 0xFF20 # 0 +0x0000A3C1 0xFF21 # 0 +0x0000A3C2 0xFF22 # 0 +0x0000A3C3 0xFF23 # 0 +0x0000A3C4 0xFF24 # 0 +0x0000A3C5 0xFF25 # 0 +0x0000A3C6 0xFF26 # 0 +0x0000A3C7 0xFF27 # 0 +0x0000A3C8 0xFF28 # 0 +0x0000A3C9 0xFF29 # 0 +0x0000A3CA 0xFF2A # 0 +0x0000A3CB 0xFF2B # 0 +0x0000A3CC 0xFF2C # 0 +0x0000A3CD 0xFF2D # 0 +0x0000A3CE 0xFF2E # 0 +0x0000A3CF 0xFF2F # 0 +0x0000A3D0 0xFF30 # 0 +0x0000A3D1 0xFF31 # 0 +0x0000A3D2 0xFF32 # 0 +0x0000A3D3 0xFF33 # 0 +0x0000A3D4 0xFF34 # 0 +0x0000A3D5 0xFF35 # 0 +0x0000A3D6 0xFF36 # 0 +0x0000A3D7 0xFF37 # 0 +0x0000A3D8 0xFF38 # 0 +0x0000A3D9 0xFF39 # 0 +0x0000A3DA 0xFF3A # 0 +0x0000A3DB 0xFF3B # 0 +0x0000A3DC 0xFF3C # 0 +0x0000A3DD 0xFF3D # 0 +0x0000A3DE 0xFF3E # 0 +0x0000A3DF 0xFF3F # 0 +0x0000A3E0 0xFF40 # 0 +0x0000A3E1 0xFF41 # 0 +0x0000A3E2 0xFF42 # 0 +0x0000A3E3 0xFF43 # 0 +0x0000A3E4 0xFF44 # 0 +0x0000A3E5 0xFF45 # 0 +0x0000A3E6 0xFF46 # 0 +0x0000A3E7 0xFF47 # 0 +0x0000A3E8 0xFF48 # 0 +0x0000A3E9 0xFF49 # 0 +0x0000A3EA 0xFF4A # 0 +0x0000A3EB 0xFF4B # 0 +0x0000A3EC 0xFF4C # 0 +0x0000A3ED 0xFF4D # 0 +0x0000A3EE 0xFF4E # 0 +0x0000A3EF 0xFF4F # 0 +0x0000A3F0 0xFF50 # 0 +0x0000A3F1 0xFF51 # 0 +0x0000A3F2 0xFF52 # 0 +0x0000A3F3 0xFF53 # 0 +0x0000A3F4 0xFF54 # 0 +0x0000A3F5 0xFF55 # 0 +0x0000A3F6 0xFF56 # 0 +0x0000A3F7 0xFF57 # 0 +0x0000A3F8 0xFF58 # 0 +0x0000A3F9 0xFF59 # 0 +0x0000A3FA 0xFF5A # 0 +0x0000A3FB 0xFF5B # 0 +0x0000A3FC 0xFF5C # 0 +0x0000A3FD 0xFF5D # 0 +0x0000A3FE 0xFF5E # 0 +0x0000A4A1 0x3041 # 0 +0x0000A4A2 0x3042 # 0 +0x0000A4A3 0x3043 # 0 +0x0000A4A4 0x3044 # 0 +0x0000A4A5 0x3045 # 0 +0x0000A4A6 0x3046 # 0 +0x0000A4A7 0x3047 # 0 +0x0000A4A8 0x3048 # 0 +0x0000A4A9 0x3049 # 0 +0x0000A4AA 0x304A # 0 +0x0000A4AB 0x304B # 0 +0x0000A4AC 0x304C # 0 +0x0000A4AD 0x304D # 0 +0x0000A4AE 0x304E # 0 +0x0000A4AF 0x304F # 0 +0x0000A4B0 0x3050 # 0 +0x0000A4B1 0x3051 # 0 +0x0000A4B2 0x3052 # 0 +0x0000A4B3 0x3053 # 0 +0x0000A4B4 0x3054 # 0 +0x0000A4B5 0x3055 # 0 +0x0000A4B6 0x3056 # 0 +0x0000A4B7 0x3057 # 0 +0x0000A4B8 0x3058 # 0 +0x0000A4B9 0x3059 # 0 +0x0000A4BA 0x305A # 0 +0x0000A4BB 0x305B # 0 +0x0000A4BC 0x305C # 0 +0x0000A4BD 0x305D # 0 +0x0000A4BE 0x305E # 0 +0x0000A4BF 0x305F # 0 +0x0000A4C0 0x3060 # 0 +0x0000A4C1 0x3061 # 0 +0x0000A4C2 0x3062 # 0 +0x0000A4C3 0x3063 # 0 +0x0000A4C4 0x3064 # 0 +0x0000A4C5 0x3065 # 0 +0x0000A4C6 0x3066 # 0 +0x0000A4C7 0x3067 # 0 +0x0000A4C8 0x3068 # 0 +0x0000A4C9 0x3069 # 0 +0x0000A4CA 0x306A # 0 +0x0000A4CB 0x306B # 0 +0x0000A4CC 0x306C # 0 +0x0000A4CD 0x306D # 0 +0x0000A4CE 0x306E # 0 +0x0000A4CF 0x306F # 0 +0x0000A4D0 0x3070 # 0 +0x0000A4D1 0x3071 # 0 +0x0000A4D2 0x3072 # 0 +0x0000A4D3 0x3073 # 0 +0x0000A4D4 0x3074 # 0 +0x0000A4D5 0x3075 # 0 +0x0000A4D6 0x3076 # 0 +0x0000A4D7 0x3077 # 0 +0x0000A4D8 0x3078 # 0 +0x0000A4D9 0x3079 # 0 +0x0000A4DA 0x307A # 0 +0x0000A4DB 0x307B # 0 +0x0000A4DC 0x307C # 0 +0x0000A4DD 0x307D # 0 +0x0000A4DE 0x307E # 0 +0x0000A4DF 0x307F # 0 +0x0000A4E0 0x3080 # 0 +0x0000A4E1 0x3081 # 0 +0x0000A4E2 0x3082 # 0 +0x0000A4E3 0x3083 # 0 +0x0000A4E4 0x3084 # 0 +0x0000A4E5 0x3085 # 0 +0x0000A4E6 0x3086 # 0 +0x0000A4E7 0x3087 # 0 +0x0000A4E8 0x3088 # 0 +0x0000A4E9 0x3089 # 0 +0x0000A4EA 0x308A # 0 +0x0000A4EB 0x308B # 0 +0x0000A4EC 0x308C # 0 +0x0000A4ED 0x308D # 0 +0x0000A4EE 0x308E # 0 +0x0000A4EF 0x308F # 0 +0x0000A4F0 0x3090 # 0 +0x0000A4F1 0x3091 # 0 +0x0000A4F2 0x3092 # 0 +0x0000A4F3 0x3093 # 0 +0x0000A5A1 0x30A1 # 0 +0x0000A5A2 0x30A2 # 0 +0x0000A5A3 0x30A3 # 0 +0x0000A5A4 0x30A4 # 0 +0x0000A5A5 0x30A5 # 0 +0x0000A5A6 0x30A6 # 0 +0x0000A5A7 0x30A7 # 0 +0x0000A5A8 0x30A8 # 0 +0x0000A5A9 0x30A9 # 0 +0x0000A5AA 0x30AA # 0 +0x0000A5AB 0x30AB # 0 +0x0000A5AC 0x30AC # 0 +0x0000A5AD 0x30AD # 0 +0x0000A5AE 0x30AE # 0 +0x0000A5AF 0x30AF # 0 +0x0000A5B0 0x30B0 # 0 +0x0000A5B1 0x30B1 # 0 +0x0000A5B2 0x30B2 # 0 +0x0000A5B3 0x30B3 # 0 +0x0000A5B4 0x30B4 # 0 +0x0000A5B5 0x30B5 # 0 +0x0000A5B6 0x30B6 # 0 +0x0000A5B7 0x30B7 # 0 +0x0000A5B8 0x30B8 # 0 +0x0000A5B9 0x30B9 # 0 +0x0000A5BA 0x30BA # 0 +0x0000A5BB 0x30BB # 0 +0x0000A5BC 0x30BC # 0 +0x0000A5BD 0x30BD # 0 +0x0000A5BE 0x30BE # 0 +0x0000A5BF 0x30BF # 0 +0x0000A5C0 0x30C0 # 0 +0x0000A5C1 0x30C1 # 0 +0x0000A5C2 0x30C2 # 0 +0x0000A5C3 0x30C3 # 0 +0x0000A5C4 0x30C4 # 0 +0x0000A5C5 0x30C5 # 0 +0x0000A5C6 0x30C6 # 0 +0x0000A5C7 0x30C7 # 0 +0x0000A5C8 0x30C8 # 0 +0x0000A5C9 0x30C9 # 0 +0x0000A5CA 0x30CA # 0 +0x0000A5CB 0x30CB # 0 +0x0000A5CC 0x30CC # 0 +0x0000A5CD 0x30CD # 0 +0x0000A5CE 0x30CE # 0 +0x0000A5CF 0x30CF # 0 +0x0000A5D0 0x30D0 # 0 +0x0000A5D1 0x30D1 # 0 +0x0000A5D2 0x30D2 # 0 +0x0000A5D3 0x30D3 # 0 +0x0000A5D4 0x30D4 # 0 +0x0000A5D5 0x30D5 # 0 +0x0000A5D6 0x30D6 # 0 +0x0000A5D7 0x30D7 # 0 +0x0000A5D8 0x30D8 # 0 +0x0000A5D9 0x30D9 # 0 +0x0000A5DA 0x30DA # 0 +0x0000A5DB 0x30DB # 0 +0x0000A5DC 0x30DC # 0 +0x0000A5DD 0x30DD # 0 +0x0000A5DE 0x30DE # 0 +0x0000A5DF 0x30DF # 0 +0x0000A5E0 0x30E0 # 0 +0x0000A5E1 0x30E1 # 0 +0x0000A5E2 0x30E2 # 0 +0x0000A5E3 0x30E3 # 0 +0x0000A5E4 0x30E4 # 0 +0x0000A5E5 0x30E5 # 0 +0x0000A5E6 0x30E6 # 0 +0x0000A5E7 0x30E7 # 0 +0x0000A5E8 0x30E8 # 0 +0x0000A5E9 0x30E9 # 0 +0x0000A5EA 0x30EA # 0 +0x0000A5EB 0x30EB # 0 +0x0000A5EC 0x30EC # 0 +0x0000A5ED 0x30ED # 0 +0x0000A5EE 0x30EE # 0 +0x0000A5EF 0x30EF # 0 +0x0000A5F0 0x30F0 # 0 +0x0000A5F1 0x30F1 # 0 +0x0000A5F2 0x30F2 # 0 +0x0000A5F3 0x30F3 # 0 +0x0000A5F4 0x30F4 # 0 +0x0000A5F5 0x30F5 # 0 +0x0000A5F6 0x30F6 # 0 +0x0000A6A1 0x0391 # 0 +0x0000A6A2 0x0392 # 0 +0x0000A6A3 0x0393 # 0 +0x0000A6A4 0x0394 # 0 +0x0000A6A5 0x0395 # 0 +0x0000A6A6 0x0396 # 0 +0x0000A6A7 0x0397 # 0 +0x0000A6A8 0x0398 # 0 +0x0000A6A9 0x0399 # 0 +0x0000A6AA 0x039A # 0 +0x0000A6AB 0x039B # 0 +0x0000A6AC 0x039C # 0 +0x0000A6AD 0x039D # 0 +0x0000A6AE 0x039E # 0 +0x0000A6AF 0x039F # 0 +0x0000A6B0 0x03A0 # 0 +0x0000A6B1 0x03A1 # 0 +0x0000A6B2 0x03A3 # 0 +0x0000A6B3 0x03A4 # 0 +0x0000A6B4 0x03A5 # 0 +0x0000A6B5 0x03A6 # 0 +0x0000A6B6 0x03A7 # 0 +0x0000A6B7 0x03A8 # 0 +0x0000A6B8 0x03A9 # 0 +0x0000A6C1 0x03B1 # 0 +0x0000A6C2 0x03B2 # 0 +0x0000A6C3 0x03B3 # 0 +0x0000A6C4 0x03B4 # 0 +0x0000A6C5 0x03B5 # 0 +0x0000A6C6 0x03B6 # 0 +0x0000A6C7 0x03B7 # 0 +0x0000A6C8 0x03B8 # 0 +0x0000A6C9 0x03B9 # 0 +0x0000A6CA 0x03BA # 0 +0x0000A6CB 0x03BB # 0 +0x0000A6CC 0x03BC # 0 +0x0000A6CD 0x03BD # 0 +0x0000A6CE 0x03BE # 0 +0x0000A6CF 0x03BF # 0 +0x0000A6D0 0x03C0 # 0 +0x0000A6D1 0x03C1 # 0 +0x0000A6D2 0x03C3 # 0 +0x0000A6D3 0x03C4 # 0 +0x0000A6D4 0x03C5 # 0 +0x0000A6D5 0x03C6 # 0 +0x0000A6D6 0x03C7 # 0 +0x0000A6D7 0x03C8 # 0 +0x0000A6D8 0x03C9 # 0 +0x0000A7A1 0x0410 # 0 +0x0000A7A2 0x0411 # 0 +0x0000A7A3 0x0412 # 0 +0x0000A7A4 0x0413 # 0 +0x0000A7A5 0x0414 # 0 +0x0000A7A6 0x0415 # 0 +0x0000A7A7 0x0401 # 0 +0x0000A7A8 0x0416 # 0 +0x0000A7A9 0x0417 # 0 +0x0000A7AA 0x0418 # 0 +0x0000A7AB 0x0419 # 0 +0x0000A7AC 0x041A # 0 +0x0000A7AD 0x041B # 0 +0x0000A7AE 0x041C # 0 +0x0000A7AF 0x041D # 0 +0x0000A7B0 0x041E # 0 +0x0000A7B1 0x041F # 0 +0x0000A7B2 0x0420 # 0 +0x0000A7B3 0x0421 # 0 +0x0000A7B4 0x0422 # 0 +0x0000A7B5 0x0423 # 0 +0x0000A7B6 0x0424 # 0 +0x0000A7B7 0x0425 # 0 +0x0000A7B8 0x0426 # 0 +0x0000A7B9 0x0427 # 0 +0x0000A7BA 0x0428 # 0 +0x0000A7BB 0x0429 # 0 +0x0000A7BC 0x042A # 0 +0x0000A7BD 0x042B # 0 +0x0000A7BE 0x042C # 0 +0x0000A7BF 0x042D # 0 +0x0000A7C0 0x042E # 0 +0x0000A7C1 0x042F # 0 +0x0000A7D1 0x0430 # 0 +0x0000A7D2 0x0431 # 0 +0x0000A7D3 0x0432 # 0 +0x0000A7D4 0x0433 # 0 +0x0000A7D5 0x0434 # 0 +0x0000A7D6 0x0435 # 0 +0x0000A7D7 0x0451 # 0 +0x0000A7D8 0x0436 # 0 +0x0000A7D9 0x0437 # 0 +0x0000A7DA 0x0438 # 0 +0x0000A7DB 0x0439 # 0 +0x0000A7DC 0x043A # 0 +0x0000A7DD 0x043B # 0 +0x0000A7DE 0x043C # 0 +0x0000A7DF 0x043D # 0 +0x0000A7E0 0x043E # 0 +0x0000A7E1 0x043F # 0 +0x0000A7E2 0x0440 # 0 +0x0000A7E3 0x0441 # 0 +0x0000A7E4 0x0442 # 0 +0x0000A7E5 0x0443 # 0 +0x0000A7E6 0x0444 # 0 +0x0000A7E7 0x0445 # 0 +0x0000A7E8 0x0446 # 0 +0x0000A7E9 0x0447 # 0 +0x0000A7EA 0x0448 # 0 +0x0000A7EB 0x0449 # 0 +0x0000A7EC 0x044A # 0 +0x0000A7ED 0x044B # 0 +0x0000A7EE 0x044C # 0 +0x0000A7EF 0x044D # 0 +0x0000A7F0 0x044E # 0 +0x0000A7F1 0x044F # 0 +0x0000A8C5 0x3105 # 0 +0x0000A8C6 0x3106 # 0 +0x0000A8C7 0x3107 # 0 +0x0000A8C8 0x3108 # 0 +0x0000A8C9 0x3109 # 0 +0x0000A8CA 0x310A # 0 +0x0000A8CB 0x310B # 0 +0x0000A8CC 0x310C # 0 +0x0000A8CD 0x310D # 0 +0x0000A8CE 0x310E # 0 +0x0000A8CF 0x310F # 0 +0x0000A8D0 0x3110 # 0 +0x0000A8D1 0x3111 # 0 +0x0000A8D2 0x3112 # 0 +0x0000A8D3 0x3113 # 0 +0x0000A8D4 0x3114 # 0 +0x0000A8D5 0x3115 # 0 +0x0000A8D6 0x3116 # 0 +0x0000A8D7 0x3117 # 0 +0x0000A8D8 0x3118 # 0 +0x0000A8D9 0x3119 # 0 +0x0000A8DA 0x311A # 0 +0x0000A8DB 0x311B # 0 +0x0000A8DC 0x311C # 0 +0x0000A8DD 0x311D # 0 +0x0000A8DE 0x311E # 0 +0x0000A8DF 0x311F # 0 +0x0000A8E0 0x3120 # 0 +0x0000A8E1 0x3121 # 0 +0x0000A8E2 0x3122 # 0 +0x0000A8E3 0x3123 # 0 +0x0000A8E4 0x3124 # 0 +0x0000A8E5 0x3125 # 0 +0x0000A8E6 0x3126 # 0 +0x0000A8E7 0x3127 # 0 +0x0000A8E8 0x3128 # 0 +0x0000A8E9 0x3129 # 0 +0x0000A9A4 0x2500 # 0 +0x0000A9A5 0x2501 # 0 +0x0000A9A6 0x2502 # 0 +0x0000A9A7 0x2503 # 0 +0x0000A9A8 0x2504 # 0 +0x0000A9A9 0x2505 # 0 +0x0000A9AA 0x2506 # 0 +0x0000A9AB 0x2507 # 0 +0x0000A9AC 0x2508 # 0 +0x0000A9AD 0x2509 # 0 +0x0000A9AE 0x250A # 0 +0x0000A9AF 0x250B # 0 +0x0000A9B0 0x250C # 0 +0x0000A9B1 0x250D # 0 +0x0000A9B2 0x250E # 0 +0x0000A9B3 0x250F # 0 +0x0000A9B4 0x2510 # 0 +0x0000A9B5 0x2511 # 0 +0x0000A9B6 0x2512 # 0 +0x0000A9B7 0x2513 # 0 +0x0000A9B8 0x2514 # 0 +0x0000A9B9 0x2515 # 0 +0x0000A9BA 0x2516 # 0 +0x0000A9BB 0x2517 # 0 +0x0000A9BC 0x2518 # 0 +0x0000A9BD 0x2519 # 0 +0x0000A9BE 0x251A # 0 +0x0000A9BF 0x251B # 0 +0x0000A9C0 0x251C # 0 +0x0000A9C1 0x251D # 0 +0x0000A9C2 0x251E # 0 +0x0000A9C3 0x251F # 0 +0x0000A9C4 0x2520 # 0 +0x0000A9C5 0x2521 # 0 +0x0000A9C6 0x2522 # 0 +0x0000A9C7 0x2523 # 0 +0x0000A9C8 0x2524 # 0 +0x0000A9C9 0x2525 # 0 +0x0000A9CA 0x2526 # 0 +0x0000A9CB 0x2527 # 0 +0x0000A9CC 0x2528 # 0 +0x0000A9CD 0x2529 # 0 +0x0000A9CE 0x252A # 0 +0x0000A9CF 0x252B # 0 +0x0000A9D0 0x252C # 0 +0x0000A9D1 0x252D # 0 +0x0000A9D2 0x252E # 0 +0x0000A9D3 0x252F # 0 +0x0000A9D4 0x2530 # 0 +0x0000A9D5 0x2531 # 0 +0x0000A9D6 0x2532 # 0 +0x0000A9D7 0x2533 # 0 +0x0000A9D8 0x2534 # 0 +0x0000A9D9 0x2535 # 0 +0x0000A9DA 0x2536 # 0 +0x0000A9DB 0x2537 # 0 +0x0000A9DC 0x2538 # 0 +0x0000A9DD 0x2539 # 0 +0x0000A9DE 0x253A # 0 +0x0000A9DF 0x253B # 0 +0x0000A9E0 0x253C # 0 +0x0000A9E1 0x253D # 0 +0x0000A9E2 0x253E # 0 +0x0000A9E3 0x253F # 0 +0x0000A9E4 0x2540 # 0 +0x0000A9E5 0x2541 # 0 +0x0000A9E6 0x2542 # 0 +0x0000A9E7 0x2543 # 0 +0x0000A9E8 0x2544 # 0 +0x0000A9E9 0x2545 # 0 +0x0000A9EA 0x2546 # 0 +0x0000A9EB 0x2547 # 0 +0x0000A9EC 0x2548 # 0 +0x0000A9ED 0x2549 # 0 +0x0000A9EE 0x254A # 0 +0x0000A9EF 0x254B # 0 +0x0000B0A1 0x554A # 0 +0x0000B0A2 0x963F # 0 +0x0000B0A3 0x57C3 # 0 +0x0000B0A4 0x6328 # 0 +0x0000B0A5 0x54CE # 0 +0x0000B0A6 0x5509 # 0 +0x0000B0A7 0x54C0 # 0 +0x0000B0A8 0x7691 # 0 +0x0000B0A9 0x764C # 0 +0x0000B0AA 0x853C # 0 +0x0000B0AB 0x77EE # 0 +0x0000B0AC 0x827E # 0 +0x0000B0AD 0x788D # 0 +0x0000B0AE 0x7231 # 0 +0x0000B0AF 0x9698 # 0 +0x0000B0B0 0x978D # 0 +0x0000B0B1 0x6C28 # 0 +0x0000B0B2 0x5B89 # 0 +0x0000B0B3 0x4FFA # 0 +0x0000B0B4 0x6309 # 0 +0x0000B0B5 0x6697 # 0 +0x0000B0B6 0x5CB8 # 0 +0x0000B0B7 0x80FA # 0 +0x0000B0B8 0x6848 # 0 +0x0000B0B9 0x80AE # 0 +0x0000B0BA 0x6602 # 0 +0x0000B0BB 0x76CE # 0 +0x0000B0BC 0x51F9 # 0 +0x0000B0BD 0x6556 # 0 +0x0000B0BE 0x71AC # 0 +0x0000B0BF 0x7FF1 # 0 +0x0000B0C0 0x8884 # 0 +0x0000B0C1 0x50B2 # 0 +0x0000B0C2 0x5965 # 0 +0x0000B0C3 0x61CA # 0 +0x0000B0C4 0x6FB3 # 0 +0x0000B0C5 0x82AD # 0 +0x0000B0C6 0x634C # 0 +0x0000B0C7 0x6252 # 0 +0x0000B0C8 0x53ED # 0 +0x0000B0C9 0x5427 # 0 +0x0000B0CA 0x7B06 # 0 +0x0000B0CB 0x516B # 0 +0x0000B0CC 0x75A4 # 0 +0x0000B0CD 0x5DF4 # 0 +0x0000B0CE 0x62D4 # 0 +0x0000B0CF 0x8DCB # 0 +0x0000B0D0 0x9776 # 0 +0x0000B0D1 0x628A # 0 +0x0000B0D2 0x8019 # 0 +0x0000B0D3 0x575D # 0 +0x0000B0D4 0x9738 # 0 +0x0000B0D5 0x7F62 # 0 +0x0000B0D6 0x7238 # 0 +0x0000B0D7 0x767D # 0 +0x0000B0D8 0x67CF # 0 +0x0000B0D9 0x767E # 0 +0x0000B0DA 0x6446 # 0 +0x0000B0DB 0x4F70 # 0 +0x0000B0DC 0x8D25 # 0 +0x0000B0DD 0x62DC # 0 +0x0000B0DE 0x7A17 # 0 +0x0000B0DF 0x6591 # 0 +0x0000B0E0 0x73ED # 0 +0x0000B0E1 0x642C # 0 +0x0000B0E2 0x6273 # 0 +0x0000B0E3 0x822C # 0 +0x0000B0E4 0x9881 # 0 +0x0000B0E5 0x677F # 0 +0x0000B0E6 0x7248 # 0 +0x0000B0E7 0x626E # 0 +0x0000B0E8 0x62CC # 0 +0x0000B0E9 0x4F34 # 0 +0x0000B0EA 0x74E3 # 0 +0x0000B0EB 0x534A # 0 +0x0000B0EC 0x529E # 0 +0x0000B0ED 0x7ECA # 0 +0x0000B0EE 0x90A6 # 0 +0x0000B0EF 0x5E2E # 0 +0x0000B0F0 0x6886 # 0 +0x0000B0F1 0x699C # 0 +0x0000B0F2 0x8180 # 0 +0x0000B0F3 0x7ED1 # 0 +0x0000B0F4 0x68D2 # 0 +0x0000B0F5 0x78C5 # 0 +0x0000B0F6 0x868C # 0 +0x0000B0F7 0x9551 # 0 +0x0000B0F8 0x508D # 0 +0x0000B0F9 0x8C24 # 0 +0x0000B0FA 0x82DE # 0 +0x0000B0FB 0x80DE # 0 +0x0000B0FC 0x5305 # 0 +0x0000B0FD 0x8912 # 0 +0x0000B0FE 0x5265 # 0 +0x0000B1A1 0x8584 # 0 +0x0000B1A2 0x96F9 # 0 +0x0000B1A3 0x4FDD # 0 +0x0000B1A4 0x5821 # 0 +0x0000B1A5 0x9971 # 0 +0x0000B1A6 0x5B9D # 0 +0x0000B1A7 0x62B1 # 0 +0x0000B1A8 0x62A5 # 0 +0x0000B1A9 0x66B4 # 0 +0x0000B1AA 0x8C79 # 0 +0x0000B1AB 0x9C8D # 0 +0x0000B1AC 0x7206 # 0 +0x0000B1AD 0x676F # 0 +0x0000B1AE 0x7891 # 0 +0x0000B1AF 0x60B2 # 0 +0x0000B1B0 0x5351 # 0 +0x0000B1B1 0x5317 # 0 +0x0000B1B2 0x8F88 # 0 +0x0000B1B3 0x80CC # 0 +0x0000B1B4 0x8D1D # 0 +0x0000B1B5 0x94A1 # 0 +0x0000B1B6 0x500D # 0 +0x0000B1B7 0x72C8 # 0 +0x0000B1B8 0x5907 # 0 +0x0000B1B9 0x60EB # 0 +0x0000B1BA 0x7119 # 0 +0x0000B1BB 0x88AB # 0 +0x0000B1BC 0x5954 # 0 +0x0000B1BD 0x82EF # 0 +0x0000B1BE 0x672C # 0 +0x0000B1BF 0x7B28 # 0 +0x0000B1C0 0x5D29 # 0 +0x0000B1C1 0x7EF7 # 0 +0x0000B1C2 0x752D # 0 +0x0000B1C3 0x6CF5 # 0 +0x0000B1C4 0x8E66 # 0 +0x0000B1C5 0x8FF8 # 0 +0x0000B1C6 0x903C # 0 +0x0000B1C7 0x9F3B # 0 +0x0000B1C8 0x6BD4 # 0 +0x0000B1C9 0x9119 # 0 +0x0000B1CA 0x7B14 # 0 +0x0000B1CB 0x5F7C # 0 +0x0000B1CC 0x78A7 # 0 +0x0000B1CD 0x84D6 # 0 +0x0000B1CE 0x853D # 0 +0x0000B1CF 0x6BD5 # 0 +0x0000B1D0 0x6BD9 # 0 +0x0000B1D1 0x6BD6 # 0 +0x0000B1D2 0x5E01 # 0 +0x0000B1D3 0x5E87 # 0 +0x0000B1D4 0x75F9 # 0 +0x0000B1D5 0x95ED # 0 +0x0000B1D6 0x655D # 0 +0x0000B1D7 0x5F0A # 0 +0x0000B1D8 0x5FC5 # 0 +0x0000B1D9 0x8F9F # 0 +0x0000B1DA 0x58C1 # 0 +0x0000B1DB 0x81C2 # 0 +0x0000B1DC 0x907F # 0 +0x0000B1DD 0x965B # 0 +0x0000B1DE 0x97AD # 0 +0x0000B1DF 0x8FB9 # 0 +0x0000B1E0 0x7F16 # 0 +0x0000B1E1 0x8D2C # 0 +0x0000B1E2 0x6241 # 0 +0x0000B1E3 0x4FBF # 0 +0x0000B1E4 0x53D8 # 0 +0x0000B1E5 0x535E # 0 +0x0000B1E6 0x8FA8 # 0 +0x0000B1E7 0x8FA9 # 0 +0x0000B1E8 0x8FAB # 0 +0x0000B1E9 0x904D # 0 +0x0000B1EA 0x6807 # 0 +0x0000B1EB 0x5F6A # 0 +0x0000B1EC 0x8198 # 0 +0x0000B1ED 0x8868 # 0 +0x0000B1EE 0x9CD6 # 0 +0x0000B1EF 0x618B # 0 +0x0000B1F0 0x522B # 0 +0x0000B1F1 0x762A # 0 +0x0000B1F2 0x5F6C # 0 +0x0000B1F3 0x658C # 0 +0x0000B1F4 0x6FD2 # 0 +0x0000B1F5 0x6EE8 # 0 +0x0000B1F6 0x5BBE # 0 +0x0000B1F7 0x6448 # 0 +0x0000B1F8 0x5175 # 0 +0x0000B1F9 0x51B0 # 0 +0x0000B1FA 0x67C4 # 0 +0x0000B1FB 0x4E19 # 0 +0x0000B1FC 0x79C9 # 0 +0x0000B1FD 0x997C # 0 +0x0000B1FE 0x70B3 # 0 +0x0000B2A1 0x75C5 # 0 +0x0000B2A2 0x5E76 # 0 +0x0000B2A3 0x73BB # 0 +0x0000B2A4 0x83E0 # 0 +0x0000B2A5 0x64AD # 0 +0x0000B2A6 0x62E8 # 0 +0x0000B2A7 0x94B5 # 0 +0x0000B2A8 0x6CE2 # 0 +0x0000B2A9 0x535A # 0 +0x0000B2AA 0x52C3 # 0 +0x0000B2AB 0x640F # 0 +0x0000B2AC 0x94C2 # 0 +0x0000B2AD 0x7B94 # 0 +0x0000B2AE 0x4F2F # 0 +0x0000B2AF 0x5E1B # 0 +0x0000B2B0 0x8236 # 0 +0x0000B2B1 0x8116 # 0 +0x0000B2B2 0x818A # 0 +0x0000B2B3 0x6E24 # 0 +0x0000B2B4 0x6CCA # 0 +0x0000B2B5 0x9A73 # 0 +0x0000B2B6 0x6355 # 0 +0x0000B2B7 0x535C # 0 +0x0000B2B8 0x54FA # 0 +0x0000B2B9 0x8865 # 0 +0x0000B2BA 0x57E0 # 0 +0x0000B2BB 0x4E0D # 0 +0x0000B2BC 0x5E03 # 0 +0x0000B2BD 0x6B65 # 0 +0x0000B2BE 0x7C3F # 0 +0x0000B2BF 0x90E8 # 0 +0x0000B2C0 0x6016 # 0 +0x0000B2C1 0x64E6 # 0 +0x0000B2C2 0x731C # 0 +0x0000B2C3 0x88C1 # 0 +0x0000B2C4 0x6750 # 0 +0x0000B2C5 0x624D # 0 +0x0000B2C6 0x8D22 # 0 +0x0000B2C7 0x776C # 0 +0x0000B2C8 0x8E29 # 0 +0x0000B2C9 0x91C7 # 0 +0x0000B2CA 0x5F69 # 0 +0x0000B2CB 0x83DC # 0 +0x0000B2CC 0x8521 # 0 +0x0000B2CD 0x9910 # 0 +0x0000B2CE 0x53C2 # 0 +0x0000B2CF 0x8695 # 0 +0x0000B2D0 0x6B8B # 0 +0x0000B2D1 0x60ED # 0 +0x0000B2D2 0x60E8 # 0 +0x0000B2D3 0x707F # 0 +0x0000B2D4 0x82CD # 0 +0x0000B2D5 0x8231 # 0 +0x0000B2D6 0x4ED3 # 0 +0x0000B2D7 0x6CA7 # 0 +0x0000B2D8 0x85CF # 0 +0x0000B2D9 0x64CD # 0 +0x0000B2DA 0x7CD9 # 0 +0x0000B2DB 0x69FD # 0 +0x0000B2DC 0x66F9 # 0 +0x0000B2DD 0x8349 # 0 +0x0000B2DE 0x5395 # 0 +0x0000B2DF 0x7B56 # 0 +0x0000B2E0 0x4FA7 # 0 +0x0000B2E1 0x518C # 0 +0x0000B2E2 0x6D4B # 0 +0x0000B2E3 0x5C42 # 0 +0x0000B2E4 0x8E6D # 0 +0x0000B2E5 0x63D2 # 0 +0x0000B2E6 0x53C9 # 0 +0x0000B2E7 0x832C # 0 +0x0000B2E8 0x8336 # 0 +0x0000B2E9 0x67E5 # 0 +0x0000B2EA 0x78B4 # 0 +0x0000B2EB 0x643D # 0 +0x0000B2EC 0x5BDF # 0 +0x0000B2ED 0x5C94 # 0 +0x0000B2EE 0x5DEE # 0 +0x0000B2EF 0x8BE7 # 0 +0x0000B2F0 0x62C6 # 0 +0x0000B2F1 0x67F4 # 0 +0x0000B2F2 0x8C7A # 0 +0x0000B2F3 0x6400 # 0 +0x0000B2F4 0x63BA # 0 +0x0000B2F5 0x8749 # 0 +0x0000B2F6 0x998B # 0 +0x0000B2F7 0x8C17 # 0 +0x0000B2F8 0x7F20 # 0 +0x0000B2F9 0x94F2 # 0 +0x0000B2FA 0x4EA7 # 0 +0x0000B2FB 0x9610 # 0 +0x0000B2FC 0x98A4 # 0 +0x0000B2FD 0x660C # 0 +0x0000B2FE 0x7316 # 0 +0x0000B3A1 0x573A # 0 +0x0000B3A2 0x5C1D # 0 +0x0000B3A3 0x5E38 # 0 +0x0000B3A4 0x957F # 0 +0x0000B3A5 0x507F # 0 +0x0000B3A6 0x80A0 # 0 +0x0000B3A7 0x5382 # 0 +0x0000B3A8 0x655E # 0 +0x0000B3A9 0x7545 # 0 +0x0000B3AA 0x5531 # 0 +0x0000B3AB 0x5021 # 0 +0x0000B3AC 0x8D85 # 0 +0x0000B3AD 0x6284 # 0 +0x0000B3AE 0x949E # 0 +0x0000B3AF 0x671D # 0 +0x0000B3B0 0x5632 # 0 +0x0000B3B1 0x6F6E # 0 +0x0000B3B2 0x5DE2 # 0 +0x0000B3B3 0x5435 # 0 +0x0000B3B4 0x7092 # 0 +0x0000B3B5 0x8F66 # 0 +0x0000B3B6 0x626F # 0 +0x0000B3B7 0x64A4 # 0 +0x0000B3B8 0x63A3 # 0 +0x0000B3B9 0x5F7B # 0 +0x0000B3BA 0x6F88 # 0 +0x0000B3BB 0x90F4 # 0 +0x0000B3BC 0x81E3 # 0 +0x0000B3BD 0x8FB0 # 0 +0x0000B3BE 0x5C18 # 0 +0x0000B3BF 0x6668 # 0 +0x0000B3C0 0x5FF1 # 0 +0x0000B3C1 0x6C89 # 0 +0x0000B3C2 0x9648 # 0 +0x0000B3C3 0x8D81 # 0 +0x0000B3C4 0x886C # 0 +0x0000B3C5 0x6491 # 0 +0x0000B3C6 0x79F0 # 0 +0x0000B3C7 0x57CE # 0 +0x0000B3C8 0x6A59 # 0 +0x0000B3C9 0x6210 # 0 +0x0000B3CA 0x5448 # 0 +0x0000B3CB 0x4E58 # 0 +0x0000B3CC 0x7A0B # 0 +0x0000B3CD 0x60E9 # 0 +0x0000B3CE 0x6F84 # 0 +0x0000B3CF 0x8BDA # 0 +0x0000B3D0 0x627F # 0 +0x0000B3D1 0x901E # 0 +0x0000B3D2 0x9A8B # 0 +0x0000B3D3 0x79E4 # 0 +0x0000B3D4 0x5403 # 0 +0x0000B3D5 0x75F4 # 0 +0x0000B3D6 0x6301 # 0 +0x0000B3D7 0x5319 # 0 +0x0000B3D8 0x6C60 # 0 +0x0000B3D9 0x8FDF # 0 +0x0000B3DA 0x5F1B # 0 +0x0000B3DB 0x9A70 # 0 +0x0000B3DC 0x803B # 0 +0x0000B3DD 0x9F7F # 0 +0x0000B3DE 0x4F88 # 0 +0x0000B3DF 0x5C3A # 0 +0x0000B3E0 0x8D64 # 0 +0x0000B3E1 0x7FC5 # 0 +0x0000B3E2 0x65A5 # 0 +0x0000B3E3 0x70BD # 0 +0x0000B3E4 0x5145 # 0 +0x0000B3E5 0x51B2 # 0 +0x0000B3E6 0x866B # 0 +0x0000B3E7 0x5D07 # 0 +0x0000B3E8 0x5BA0 # 0 +0x0000B3E9 0x62BD # 0 +0x0000B3EA 0x916C # 0 +0x0000B3EB 0x7574 # 0 +0x0000B3EC 0x8E0C # 0 +0x0000B3ED 0x7A20 # 0 +0x0000B3EE 0x6101 # 0 +0x0000B3EF 0x7B79 # 0 +0x0000B3F0 0x4EC7 # 0 +0x0000B3F1 0x7EF8 # 0 +0x0000B3F2 0x7785 # 0 +0x0000B3F3 0x4E11 # 0 +0x0000B3F4 0x81ED # 0 +0x0000B3F5 0x521D # 0 +0x0000B3F6 0x51FA # 0 +0x0000B3F7 0x6A71 # 0 +0x0000B3F8 0x53A8 # 0 +0x0000B3F9 0x8E87 # 0 +0x0000B3FA 0x9504 # 0 +0x0000B3FB 0x96CF # 0 +0x0000B3FC 0x6EC1 # 0 +0x0000B3FD 0x9664 # 0 +0x0000B3FE 0x695A # 0 +0x0000B4A1 0x7840 # 0 +0x0000B4A2 0x50A8 # 0 +0x0000B4A3 0x77D7 # 0 +0x0000B4A4 0x6410 # 0 +0x0000B4A5 0x89E6 # 0 +0x0000B4A6 0x5904 # 0 +0x0000B4A7 0x63E3 # 0 +0x0000B4A8 0x5DDD # 0 +0x0000B4A9 0x7A7F # 0 +0x0000B4AA 0x693D # 0 +0x0000B4AB 0x4F20 # 0 +0x0000B4AC 0x8239 # 0 +0x0000B4AD 0x5598 # 0 +0x0000B4AE 0x4E32 # 0 +0x0000B4AF 0x75AE # 0 +0x0000B4B0 0x7A97 # 0 +0x0000B4B1 0x5E62 # 0 +0x0000B4B2 0x5E8A # 0 +0x0000B4B3 0x95EF # 0 +0x0000B4B4 0x521B # 0 +0x0000B4B5 0x5439 # 0 +0x0000B4B6 0x708A # 0 +0x0000B4B7 0x6376 # 0 +0x0000B4B8 0x9524 # 0 +0x0000B4B9 0x5782 # 0 +0x0000B4BA 0x6625 # 0 +0x0000B4BB 0x693F # 0 +0x0000B4BC 0x9187 # 0 +0x0000B4BD 0x5507 # 0 +0x0000B4BE 0x6DF3 # 0 +0x0000B4BF 0x7EAF # 0 +0x0000B4C0 0x8822 # 0 +0x0000B4C1 0x6233 # 0 +0x0000B4C2 0x7EF0 # 0 +0x0000B4C3 0x75B5 # 0 +0x0000B4C4 0x8328 # 0 +0x0000B4C5 0x78C1 # 0 +0x0000B4C6 0x96CC # 0 +0x0000B4C7 0x8F9E # 0 +0x0000B4C8 0x6148 # 0 +0x0000B4C9 0x74F7 # 0 +0x0000B4CA 0x8BCD # 0 +0x0000B4CB 0x6B64 # 0 +0x0000B4CC 0x523A # 0 +0x0000B4CD 0x8D50 # 0 +0x0000B4CE 0x6B21 # 0 +0x0000B4CF 0x806A # 0 +0x0000B4D0 0x8471 # 0 +0x0000B4D1 0x56F1 # 0 +0x0000B4D2 0x5306 # 0 +0x0000B4D3 0x4ECE # 0 +0x0000B4D4 0x4E1B # 0 +0x0000B4D5 0x51D1 # 0 +0x0000B4D6 0x7C97 # 0 +0x0000B4D7 0x918B # 0 +0x0000B4D8 0x7C07 # 0 +0x0000B4D9 0x4FC3 # 0 +0x0000B4DA 0x8E7F # 0 +0x0000B4DB 0x7BE1 # 0 +0x0000B4DC 0x7A9C # 0 +0x0000B4DD 0x6467 # 0 +0x0000B4DE 0x5D14 # 0 +0x0000B4DF 0x50AC # 0 +0x0000B4E0 0x8106 # 0 +0x0000B4E1 0x7601 # 0 +0x0000B4E2 0x7CB9 # 0 +0x0000B4E3 0x6DEC # 0 +0x0000B4E4 0x7FE0 # 0 +0x0000B4E5 0x6751 # 0 +0x0000B4E6 0x5B58 # 0 +0x0000B4E7 0x5BF8 # 0 +0x0000B4E8 0x78CB # 0 +0x0000B4E9 0x64AE # 0 +0x0000B4EA 0x6413 # 0 +0x0000B4EB 0x63AA # 0 +0x0000B4EC 0x632B # 0 +0x0000B4ED 0x9519 # 0 +0x0000B4EE 0x642D # 0 +0x0000B4EF 0x8FBE # 0 +0x0000B4F0 0x7B54 # 0 +0x0000B4F1 0x7629 # 0 +0x0000B4F2 0x6253 # 0 +0x0000B4F3 0x5927 # 0 +0x0000B4F4 0x5446 # 0 +0x0000B4F5 0x6B79 # 0 +0x0000B4F6 0x50A3 # 0 +0x0000B4F7 0x6234 # 0 +0x0000B4F8 0x5E26 # 0 +0x0000B4F9 0x6B86 # 0 +0x0000B4FA 0x4EE3 # 0 +0x0000B4FB 0x8D37 # 0 +0x0000B4FC 0x888B # 0 +0x0000B4FD 0x5F85 # 0 +0x0000B4FE 0x902E # 0 +0x0000B5A1 0x6020 # 0 +0x0000B5A2 0x803D # 0 +0x0000B5A3 0x62C5 # 0 +0x0000B5A4 0x4E39 # 0 +0x0000B5A5 0x5355 # 0 +0x0000B5A6 0x90F8 # 0 +0x0000B5A7 0x63B8 # 0 +0x0000B5A8 0x80C6 # 0 +0x0000B5A9 0x65E6 # 0 +0x0000B5AA 0x6C2E # 0 +0x0000B5AB 0x4F46 # 0 +0x0000B5AC 0x60EE # 0 +0x0000B5AD 0x6DE1 # 0 +0x0000B5AE 0x8BDE # 0 +0x0000B5AF 0x5F39 # 0 +0x0000B5B0 0x86CB # 0 +0x0000B5B1 0x5F53 # 0 +0x0000B5B2 0x6321 # 0 +0x0000B5B3 0x515A # 0 +0x0000B5B4 0x8361 # 0 +0x0000B5B5 0x6863 # 0 +0x0000B5B6 0x5200 # 0 +0x0000B5B7 0x6363 # 0 +0x0000B5B8 0x8E48 # 0 +0x0000B5B9 0x5012 # 0 +0x0000B5BA 0x5C9B # 0 +0x0000B5BB 0x7977 # 0 +0x0000B5BC 0x5BFC # 0 +0x0000B5BD 0x5230 # 0 +0x0000B5BE 0x7A3B # 0 +0x0000B5BF 0x60BC # 0 +0x0000B5C0 0x9053 # 0 +0x0000B5C1 0x76D7 # 0 +0x0000B5C2 0x5FB7 # 0 +0x0000B5C3 0x5F97 # 0 +0x0000B5C4 0x7684 # 0 +0x0000B5C5 0x8E6C # 0 +0x0000B5C6 0x706F # 0 +0x0000B5C7 0x767B # 0 +0x0000B5C8 0x7B49 # 0 +0x0000B5C9 0x77AA # 0 +0x0000B5CA 0x51F3 # 0 +0x0000B5CB 0x9093 # 0 +0x0000B5CC 0x5824 # 0 +0x0000B5CD 0x4F4E # 0 +0x0000B5CE 0x6EF4 # 0 +0x0000B5CF 0x8FEA # 0 +0x0000B5D0 0x654C # 0 +0x0000B5D1 0x7B1B # 0 +0x0000B5D2 0x72C4 # 0 +0x0000B5D3 0x6DA4 # 0 +0x0000B5D4 0x7FDF # 0 +0x0000B5D5 0x5AE1 # 0 +0x0000B5D6 0x62B5 # 0 +0x0000B5D7 0x5E95 # 0 +0x0000B5D8 0x5730 # 0 +0x0000B5D9 0x8482 # 0 +0x0000B5DA 0x7B2C # 0 +0x0000B5DB 0x5E1D # 0 +0x0000B5DC 0x5F1F # 0 +0x0000B5DD 0x9012 # 0 +0x0000B5DE 0x7F14 # 0 +0x0000B5DF 0x98A0 # 0 +0x0000B5E0 0x6382 # 0 +0x0000B5E1 0x6EC7 # 0 +0x0000B5E2 0x7898 # 0 +0x0000B5E3 0x70B9 # 0 +0x0000B5E4 0x5178 # 0 +0x0000B5E5 0x975B # 0 +0x0000B5E6 0x57AB # 0 +0x0000B5E7 0x7535 # 0 +0x0000B5E8 0x4F43 # 0 +0x0000B5E9 0x7538 # 0 +0x0000B5EA 0x5E97 # 0 +0x0000B5EB 0x60E6 # 0 +0x0000B5EC 0x5960 # 0 +0x0000B5ED 0x6DC0 # 0 +0x0000B5EE 0x6BBF # 0 +0x0000B5EF 0x7889 # 0 +0x0000B5F0 0x53FC # 0 +0x0000B5F1 0x96D5 # 0 +0x0000B5F2 0x51CB # 0 +0x0000B5F3 0x5201 # 0 +0x0000B5F4 0x6389 # 0 +0x0000B5F5 0x540A # 0 +0x0000B5F6 0x9493 # 0 +0x0000B5F7 0x8C03 # 0 +0x0000B5F8 0x8DCC # 0 +0x0000B5F9 0x7239 # 0 +0x0000B5FA 0x789F # 0 +0x0000B5FB 0x8776 # 0 +0x0000B5FC 0x8FED # 0 +0x0000B5FD 0x8C0D # 0 +0x0000B5FE 0x53E0 # 0 +0x0000B6A1 0x4E01 # 0 +0x0000B6A2 0x76EF # 0 +0x0000B6A3 0x53EE # 0 +0x0000B6A4 0x9489 # 0 +0x0000B6A5 0x9876 # 0 +0x0000B6A6 0x9F0E # 0 +0x0000B6A7 0x952D # 0 +0x0000B6A8 0x5B9A # 0 +0x0000B6A9 0x8BA2 # 0 +0x0000B6AA 0x4E22 # 0 +0x0000B6AB 0x4E1C # 0 +0x0000B6AC 0x51AC # 0 +0x0000B6AD 0x8463 # 0 +0x0000B6AE 0x61C2 # 0 +0x0000B6AF 0x52A8 # 0 +0x0000B6B0 0x680B # 0 +0x0000B6B1 0x4F97 # 0 +0x0000B6B2 0x606B # 0 +0x0000B6B3 0x51BB # 0 +0x0000B6B4 0x6D1E # 0 +0x0000B6B5 0x515C # 0 +0x0000B6B6 0x6296 # 0 +0x0000B6B7 0x6597 # 0 +0x0000B6B8 0x9661 # 0 +0x0000B6B9 0x8C46 # 0 +0x0000B6BA 0x9017 # 0 +0x0000B6BB 0x75D8 # 0 +0x0000B6BC 0x90FD # 0 +0x0000B6BD 0x7763 # 0 +0x0000B6BE 0x6BD2 # 0 +0x0000B6BF 0x728A # 0 +0x0000B6C0 0x72EC # 0 +0x0000B6C1 0x8BFB # 0 +0x0000B6C2 0x5835 # 0 +0x0000B6C3 0x7779 # 0 +0x0000B6C4 0x8D4C # 0 +0x0000B6C5 0x675C # 0 +0x0000B6C6 0x9540 # 0 +0x0000B6C7 0x809A # 0 +0x0000B6C8 0x5EA6 # 0 +0x0000B6C9 0x6E21 # 0 +0x0000B6CA 0x5992 # 0 +0x0000B6CB 0x7AEF # 0 +0x0000B6CC 0x77ED # 0 +0x0000B6CD 0x953B # 0 +0x0000B6CE 0x6BB5 # 0 +0x0000B6CF 0x65AD # 0 +0x0000B6D0 0x7F0E # 0 +0x0000B6D1 0x5806 # 0 +0x0000B6D2 0x5151 # 0 +0x0000B6D3 0x961F # 0 +0x0000B6D4 0x5BF9 # 0 +0x0000B6D5 0x58A9 # 0 +0x0000B6D6 0x5428 # 0 +0x0000B6D7 0x8E72 # 0 +0x0000B6D8 0x6566 # 0 +0x0000B6D9 0x987F # 0 +0x0000B6DA 0x56E4 # 0 +0x0000B6DB 0x949D # 0 +0x0000B6DC 0x76FE # 0 +0x0000B6DD 0x9041 # 0 +0x0000B6DE 0x6387 # 0 +0x0000B6DF 0x54C6 # 0 +0x0000B6E0 0x591A # 0 +0x0000B6E1 0x593A # 0 +0x0000B6E2 0x579B # 0 +0x0000B6E3 0x8EB2 # 0 +0x0000B6E4 0x6735 # 0 +0x0000B6E5 0x8DFA # 0 +0x0000B6E6 0x8235 # 0 +0x0000B6E7 0x5241 # 0 +0x0000B6E8 0x60F0 # 0 +0x0000B6E9 0x5815 # 0 +0x0000B6EA 0x86FE # 0 +0x0000B6EB 0x5CE8 # 0 +0x0000B6EC 0x9E45 # 0 +0x0000B6ED 0x4FC4 # 0 +0x0000B6EE 0x989D # 0 +0x0000B6EF 0x8BB9 # 0 +0x0000B6F0 0x5A25 # 0 +0x0000B6F1 0x6076 # 0 +0x0000B6F2 0x5384 # 0 +0x0000B6F3 0x627C # 0 +0x0000B6F4 0x904F # 0 +0x0000B6F5 0x9102 # 0 +0x0000B6F6 0x997F # 0 +0x0000B6F7 0x6069 # 0 +0x0000B6F8 0x800C # 0 +0x0000B6F9 0x513F # 0 +0x0000B6FA 0x8033 # 0 +0x0000B6FB 0x5C14 # 0 +0x0000B6FC 0x9975 # 0 +0x0000B6FD 0x6D31 # 0 +0x0000B6FE 0x4E8C # 0 +0x0000B7A1 0x8D30 # 0 +0x0000B7A2 0x53D1 # 0 +0x0000B7A3 0x7F5A # 0 +0x0000B7A4 0x7B4F # 0 +0x0000B7A5 0x4F10 # 0 +0x0000B7A6 0x4E4F # 0 +0x0000B7A7 0x9600 # 0 +0x0000B7A8 0x6CD5 # 0 +0x0000B7A9 0x73D0 # 0 +0x0000B7AA 0x85E9 # 0 +0x0000B7AB 0x5E06 # 0 +0x0000B7AC 0x756A # 0 +0x0000B7AD 0x7FFB # 0 +0x0000B7AE 0x6A0A # 0 +0x0000B7AF 0x77FE # 0 +0x0000B7B0 0x9492 # 0 +0x0000B7B1 0x7E41 # 0 +0x0000B7B2 0x51E1 # 0 +0x0000B7B3 0x70E6 # 0 +0x0000B7B4 0x53CD # 0 +0x0000B7B5 0x8FD4 # 0 +0x0000B7B6 0x8303 # 0 +0x0000B7B7 0x8D29 # 0 +0x0000B7B8 0x72AF # 0 +0x0000B7B9 0x996D # 0 +0x0000B7BA 0x6CDB # 0 +0x0000B7BB 0x574A # 0 +0x0000B7BC 0x82B3 # 0 +0x0000B7BD 0x65B9 # 0 +0x0000B7BE 0x80AA # 0 +0x0000B7BF 0x623F # 0 +0x0000B7C0 0x9632 # 0 +0x0000B7C1 0x59A8 # 0 +0x0000B7C2 0x4EFF # 0 +0x0000B7C3 0x8BBF # 0 +0x0000B7C4 0x7EBA # 0 +0x0000B7C5 0x653E # 0 +0x0000B7C6 0x83F2 # 0 +0x0000B7C7 0x975E # 0 +0x0000B7C8 0x5561 # 0 +0x0000B7C9 0x98DE # 0 +0x0000B7CA 0x80A5 # 0 +0x0000B7CB 0x532A # 0 +0x0000B7CC 0x8BFD # 0 +0x0000B7CD 0x5420 # 0 +0x0000B7CE 0x80BA # 0 +0x0000B7CF 0x5E9F # 0 +0x0000B7D0 0x6CB8 # 0 +0x0000B7D1 0x8D39 # 0 +0x0000B7D2 0x82AC # 0 +0x0000B7D3 0x915A # 0 +0x0000B7D4 0x5429 # 0 +0x0000B7D5 0x6C1B # 0 +0x0000B7D6 0x5206 # 0 +0x0000B7D7 0x7EB7 # 0 +0x0000B7D8 0x575F # 0 +0x0000B7D9 0x711A # 0 +0x0000B7DA 0x6C7E # 0 +0x0000B7DB 0x7C89 # 0 +0x0000B7DC 0x594B # 0 +0x0000B7DD 0x4EFD # 0 +0x0000B7DE 0x5FFF # 0 +0x0000B7DF 0x6124 # 0 +0x0000B7E0 0x7CAA # 0 +0x0000B7E1 0x4E30 # 0 +0x0000B7E2 0x5C01 # 0 +0x0000B7E3 0x67AB # 0 +0x0000B7E4 0x8702 # 0 +0x0000B7E5 0x5CF0 # 0 +0x0000B7E6 0x950B # 0 +0x0000B7E7 0x98CE # 0 +0x0000B7E8 0x75AF # 0 +0x0000B7E9 0x70FD # 0 +0x0000B7EA 0x9022 # 0 +0x0000B7EB 0x51AF # 0 +0x0000B7EC 0x7F1D # 0 +0x0000B7ED 0x8BBD # 0 +0x0000B7EE 0x5949 # 0 +0x0000B7EF 0x51E4 # 0 +0x0000B7F0 0x4F5B # 0 +0x0000B7F1 0x5426 # 0 +0x0000B7F2 0x592B # 0 +0x0000B7F3 0x6577 # 0 +0x0000B7F4 0x80A4 # 0 +0x0000B7F5 0x5B75 # 0 +0x0000B7F6 0x6276 # 0 +0x0000B7F7 0x62C2 # 0 +0x0000B7F8 0x8F90 # 0 +0x0000B7F9 0x5E45 # 0 +0x0000B7FA 0x6C1F # 0 +0x0000B7FB 0x7B26 # 0 +0x0000B7FC 0x4F0F # 0 +0x0000B7FD 0x4FD8 # 0 +0x0000B7FE 0x670D # 0 +0x0000B8A1 0x6D6E # 0 +0x0000B8A2 0x6DAA # 0 +0x0000B8A3 0x798F # 0 +0x0000B8A4 0x88B1 # 0 +0x0000B8A5 0x5F17 # 0 +0x0000B8A6 0x752B # 0 +0x0000B8A7 0x629A # 0 +0x0000B8A8 0x8F85 # 0 +0x0000B8A9 0x4FEF # 0 +0x0000B8AA 0x91DC # 0 +0x0000B8AB 0x65A7 # 0 +0x0000B8AC 0x812F # 0 +0x0000B8AD 0x8151 # 0 +0x0000B8AE 0x5E9C # 0 +0x0000B8AF 0x8150 # 0 +0x0000B8B0 0x8D74 # 0 +0x0000B8B1 0x526F # 0 +0x0000B8B2 0x8986 # 0 +0x0000B8B3 0x8D4B # 0 +0x0000B8B4 0x590D # 0 +0x0000B8B5 0x5085 # 0 +0x0000B8B6 0x4ED8 # 0 +0x0000B8B7 0x961C # 0 +0x0000B8B8 0x7236 # 0 +0x0000B8B9 0x8179 # 0 +0x0000B8BA 0x8D1F # 0 +0x0000B8BB 0x5BCC # 0 +0x0000B8BC 0x8BA3 # 0 +0x0000B8BD 0x9644 # 0 +0x0000B8BE 0x5987 # 0 +0x0000B8BF 0x7F1A # 0 +0x0000B8C0 0x5490 # 0 +0x0000B8C1 0x5676 # 0 +0x0000B8C2 0x560E # 0 +0x0000B8C3 0x8BE5 # 0 +0x0000B8C4 0x6539 # 0 +0x0000B8C5 0x6982 # 0 +0x0000B8C6 0x9499 # 0 +0x0000B8C7 0x76D6 # 0 +0x0000B8C8 0x6E89 # 0 +0x0000B8C9 0x5E72 # 0 +0x0000B8CA 0x7518 # 0 +0x0000B8CB 0x6746 # 0 +0x0000B8CC 0x67D1 # 0 +0x0000B8CD 0x7AFF # 0 +0x0000B8CE 0x809D # 0 +0x0000B8CF 0x8D76 # 0 +0x0000B8D0 0x611F # 0 +0x0000B8D1 0x79C6 # 0 +0x0000B8D2 0x6562 # 0 +0x0000B8D3 0x8D63 # 0 +0x0000B8D4 0x5188 # 0 +0x0000B8D5 0x521A # 0 +0x0000B8D6 0x94A2 # 0 +0x0000B8D7 0x7F38 # 0 +0x0000B8D8 0x809B # 0 +0x0000B8D9 0x7EB2 # 0 +0x0000B8DA 0x5C97 # 0 +0x0000B8DB 0x6E2F # 0 +0x0000B8DC 0x6760 # 0 +0x0000B8DD 0x7BD9 # 0 +0x0000B8DE 0x768B # 0 +0x0000B8DF 0x9AD8 # 0 +0x0000B8E0 0x818F # 0 +0x0000B8E1 0x7F94 # 0 +0x0000B8E2 0x7CD5 # 0 +0x0000B8E3 0x641E # 0 +0x0000B8E4 0x9550 # 0 +0x0000B8E5 0x7A3F # 0 +0x0000B8E6 0x544A # 0 +0x0000B8E7 0x54E5 # 0 +0x0000B8E8 0x6B4C # 0 +0x0000B8E9 0x6401 # 0 +0x0000B8EA 0x6208 # 0 +0x0000B8EB 0x9E3D # 0 +0x0000B8EC 0x80F3 # 0 +0x0000B8ED 0x7599 # 0 +0x0000B8EE 0x5272 # 0 +0x0000B8EF 0x9769 # 0 +0x0000B8F0 0x845B # 0 +0x0000B8F1 0x683C # 0 +0x0000B8F2 0x86E4 # 0 +0x0000B8F3 0x9601 # 0 +0x0000B8F4 0x9694 # 0 +0x0000B8F5 0x94EC # 0 +0x0000B8F6 0x4E2A # 0 +0x0000B8F7 0x5404 # 0 +0x0000B8F8 0x7ED9 # 0 +0x0000B8F9 0x6839 # 0 +0x0000B8FA 0x8DDF # 0 +0x0000B8FB 0x8015 # 0 +0x0000B8FC 0x66F4 # 0 +0x0000B8FD 0x5E9A # 0 +0x0000B8FE 0x7FB9 # 0 +0x0000B9A1 0x57C2 # 0 +0x0000B9A2 0x803F # 0 +0x0000B9A3 0x6897 # 0 +0x0000B9A4 0x5DE5 # 0 +0x0000B9A5 0x653B # 0 +0x0000B9A6 0x529F # 0 +0x0000B9A7 0x606D # 0 +0x0000B9A8 0x9F9A # 0 +0x0000B9A9 0x4F9B # 0 +0x0000B9AA 0x8EAC # 0 +0x0000B9AB 0x516C # 0 +0x0000B9AC 0x5BAB # 0 +0x0000B9AD 0x5F13 # 0 +0x0000B9AE 0x5DE9 # 0 +0x0000B9AF 0x6C5E # 0 +0x0000B9B0 0x62F1 # 0 +0x0000B9B1 0x8D21 # 0 +0x0000B9B2 0x5171 # 0 +0x0000B9B3 0x94A9 # 0 +0x0000B9B4 0x52FE # 0 +0x0000B9B5 0x6C9F # 0 +0x0000B9B6 0x82DF # 0 +0x0000B9B7 0x72D7 # 0 +0x0000B9B8 0x57A2 # 0 +0x0000B9B9 0x6784 # 0 +0x0000B9BA 0x8D2D # 0 +0x0000B9BB 0x591F # 0 +0x0000B9BC 0x8F9C # 0 +0x0000B9BD 0x83C7 # 0 +0x0000B9BE 0x5495 # 0 +0x0000B9BF 0x7B8D # 0 +0x0000B9C0 0x4F30 # 0 +0x0000B9C1 0x6CBD # 0 +0x0000B9C2 0x5B64 # 0 +0x0000B9C3 0x59D1 # 0 +0x0000B9C4 0x9F13 # 0 +0x0000B9C5 0x53E4 # 0 +0x0000B9C6 0x86CA # 0 +0x0000B9C7 0x9AA8 # 0 +0x0000B9C8 0x8C37 # 0 +0x0000B9C9 0x80A1 # 0 +0x0000B9CA 0x6545 # 0 +0x0000B9CB 0x987E # 0 +0x0000B9CC 0x56FA # 0 +0x0000B9CD 0x96C7 # 0 +0x0000B9CE 0x522E # 0 +0x0000B9CF 0x74DC # 0 +0x0000B9D0 0x5250 # 0 +0x0000B9D1 0x5BE1 # 0 +0x0000B9D2 0x6302 # 0 +0x0000B9D3 0x8902 # 0 +0x0000B9D4 0x4E56 # 0 +0x0000B9D5 0x62D0 # 0 +0x0000B9D6 0x602A # 0 +0x0000B9D7 0x68FA # 0 +0x0000B9D8 0x5173 # 0 +0x0000B9D9 0x5B98 # 0 +0x0000B9DA 0x51A0 # 0 +0x0000B9DB 0x89C2 # 0 +0x0000B9DC 0x7BA1 # 0 +0x0000B9DD 0x9986 # 0 +0x0000B9DE 0x7F50 # 0 +0x0000B9DF 0x60EF # 0 +0x0000B9E0 0x704C # 0 +0x0000B9E1 0x8D2F # 0 +0x0000B9E2 0x5149 # 0 +0x0000B9E3 0x5E7F # 0 +0x0000B9E4 0x901B # 0 +0x0000B9E5 0x7470 # 0 +0x0000B9E6 0x89C4 # 0 +0x0000B9E7 0x572D # 0 +0x0000B9E8 0x7845 # 0 +0x0000B9E9 0x5F52 # 0 +0x0000B9EA 0x9F9F # 0 +0x0000B9EB 0x95FA # 0 +0x0000B9EC 0x8F68 # 0 +0x0000B9ED 0x9B3C # 0 +0x0000B9EE 0x8BE1 # 0 +0x0000B9EF 0x7678 # 0 +0x0000B9F0 0x6842 # 0 +0x0000B9F1 0x67DC # 0 +0x0000B9F2 0x8DEA # 0 +0x0000B9F3 0x8D35 # 0 +0x0000B9F4 0x523D # 0 +0x0000B9F5 0x8F8A # 0 +0x0000B9F6 0x6EDA # 0 +0x0000B9F7 0x68CD # 0 +0x0000B9F8 0x9505 # 0 +0x0000B9F9 0x90ED # 0 +0x0000B9FA 0x56FD # 0 +0x0000B9FB 0x679C # 0 +0x0000B9FC 0x88F9 # 0 +0x0000B9FD 0x8FC7 # 0 +0x0000B9FE 0x54C8 # 0 +0x0000BAA1 0x9AB8 # 0 +0x0000BAA2 0x5B69 # 0 +0x0000BAA3 0x6D77 # 0 +0x0000BAA4 0x6C26 # 0 +0x0000BAA5 0x4EA5 # 0 +0x0000BAA6 0x5BB3 # 0 +0x0000BAA7 0x9A87 # 0 +0x0000BAA8 0x9163 # 0 +0x0000BAA9 0x61A8 # 0 +0x0000BAAA 0x90AF # 0 +0x0000BAAB 0x97E9 # 0 +0x0000BAAC 0x542B # 0 +0x0000BAAD 0x6DB5 # 0 +0x0000BAAE 0x5BD2 # 0 +0x0000BAAF 0x51FD # 0 +0x0000BAB0 0x558A # 0 +0x0000BAB1 0x7F55 # 0 +0x0000BAB2 0x7FF0 # 0 +0x0000BAB3 0x64BC # 0 +0x0000BAB4 0x634D # 0 +0x0000BAB5 0x65F1 # 0 +0x0000BAB6 0x61BE # 0 +0x0000BAB7 0x608D # 0 +0x0000BAB8 0x710A # 0 +0x0000BAB9 0x6C57 # 0 +0x0000BABA 0x6C49 # 0 +0x0000BABB 0x592F # 0 +0x0000BABC 0x676D # 0 +0x0000BABD 0x822A # 0 +0x0000BABE 0x58D5 # 0 +0x0000BABF 0x568E # 0 +0x0000BAC0 0x8C6A # 0 +0x0000BAC1 0x6BEB # 0 +0x0000BAC2 0x90DD # 0 +0x0000BAC3 0x597D # 0 +0x0000BAC4 0x8017 # 0 +0x0000BAC5 0x53F7 # 0 +0x0000BAC6 0x6D69 # 0 +0x0000BAC7 0x5475 # 0 +0x0000BAC8 0x559D # 0 +0x0000BAC9 0x8377 # 0 +0x0000BACA 0x83CF # 0 +0x0000BACB 0x6838 # 0 +0x0000BACC 0x79BE # 0 +0x0000BACD 0x548C # 0 +0x0000BACE 0x4F55 # 0 +0x0000BACF 0x5408 # 0 +0x0000BAD0 0x76D2 # 0 +0x0000BAD1 0x8C89 # 0 +0x0000BAD2 0x9602 # 0 +0x0000BAD3 0x6CB3 # 0 +0x0000BAD4 0x6DB8 # 0 +0x0000BAD5 0x8D6B # 0 +0x0000BAD6 0x8910 # 0 +0x0000BAD7 0x9E64 # 0 +0x0000BAD8 0x8D3A # 0 +0x0000BAD9 0x563F # 0 +0x0000BADA 0x9ED1 # 0 +0x0000BADB 0x75D5 # 0 +0x0000BADC 0x5F88 # 0 +0x0000BADD 0x72E0 # 0 +0x0000BADE 0x6068 # 0 +0x0000BADF 0x54FC # 0 +0x0000BAE0 0x4EA8 # 0 +0x0000BAE1 0x6A2A # 0 +0x0000BAE2 0x8861 # 0 +0x0000BAE3 0x6052 # 0 +0x0000BAE4 0x8F70 # 0 +0x0000BAE5 0x54C4 # 0 +0x0000BAE6 0x70D8 # 0 +0x0000BAE7 0x8679 # 0 +0x0000BAE8 0x9E3F # 0 +0x0000BAE9 0x6D2A # 0 +0x0000BAEA 0x5B8F # 0 +0x0000BAEB 0x5F18 # 0 +0x0000BAEC 0x7EA2 # 0 +0x0000BAED 0x5589 # 0 +0x0000BAEE 0x4FAF # 0 +0x0000BAEF 0x7334 # 0 +0x0000BAF0 0x543C # 0 +0x0000BAF1 0x539A # 0 +0x0000BAF2 0x5019 # 0 +0x0000BAF3 0x540E # 0 +0x0000BAF4 0x547C # 0 +0x0000BAF5 0x4E4E # 0 +0x0000BAF6 0x5FFD # 0 +0x0000BAF7 0x745A # 0 +0x0000BAF8 0x58F6 # 0 +0x0000BAF9 0x846B # 0 +0x0000BAFA 0x80E1 # 0 +0x0000BAFB 0x8774 # 0 +0x0000BAFC 0x72D0 # 0 +0x0000BAFD 0x7CCA # 0 +0x0000BAFE 0x6E56 # 0 +0x0000BBA1 0x5F27 # 0 +0x0000BBA2 0x864E # 0 +0x0000BBA3 0x552C # 0 +0x0000BBA4 0x62A4 # 0 +0x0000BBA5 0x4E92 # 0 +0x0000BBA6 0x6CAA # 0 +0x0000BBA7 0x6237 # 0 +0x0000BBA8 0x82B1 # 0 +0x0000BBA9 0x54D7 # 0 +0x0000BBAA 0x534E # 0 +0x0000BBAB 0x733E # 0 +0x0000BBAC 0x6ED1 # 0 +0x0000BBAD 0x753B # 0 +0x0000BBAE 0x5212 # 0 +0x0000BBAF 0x5316 # 0 +0x0000BBB0 0x8BDD # 0 +0x0000BBB1 0x69D0 # 0 +0x0000BBB2 0x5F8A # 0 +0x0000BBB3 0x6000 # 0 +0x0000BBB4 0x6DEE # 0 +0x0000BBB5 0x574F # 0 +0x0000BBB6 0x6B22 # 0 +0x0000BBB7 0x73AF # 0 +0x0000BBB8 0x6853 # 0 +0x0000BBB9 0x8FD8 # 0 +0x0000BBBA 0x7F13 # 0 +0x0000BBBB 0x6362 # 0 +0x0000BBBC 0x60A3 # 0 +0x0000BBBD 0x5524 # 0 +0x0000BBBE 0x75EA # 0 +0x0000BBBF 0x8C62 # 0 +0x0000BBC0 0x7115 # 0 +0x0000BBC1 0x6DA3 # 0 +0x0000BBC2 0x5BA6 # 0 +0x0000BBC3 0x5E7B # 0 +0x0000BBC4 0x8352 # 0 +0x0000BBC5 0x614C # 0 +0x0000BBC6 0x9EC4 # 0 +0x0000BBC7 0x78FA # 0 +0x0000BBC8 0x8757 # 0 +0x0000BBC9 0x7C27 # 0 +0x0000BBCA 0x7687 # 0 +0x0000BBCB 0x51F0 # 0 +0x0000BBCC 0x60F6 # 0 +0x0000BBCD 0x714C # 0 +0x0000BBCE 0x6643 # 0 +0x0000BBCF 0x5E4C # 0 +0x0000BBD0 0x604D # 0 +0x0000BBD1 0x8C0E # 0 +0x0000BBD2 0x7070 # 0 +0x0000BBD3 0x6325 # 0 +0x0000BBD4 0x8F89 # 0 +0x0000BBD5 0x5FBD # 0 +0x0000BBD6 0x6062 # 0 +0x0000BBD7 0x86D4 # 0 +0x0000BBD8 0x56DE # 0 +0x0000BBD9 0x6BC1 # 0 +0x0000BBDA 0x6094 # 0 +0x0000BBDB 0x6167 # 0 +0x0000BBDC 0x5349 # 0 +0x0000BBDD 0x60E0 # 0 +0x0000BBDE 0x6666 # 0 +0x0000BBDF 0x8D3F # 0 +0x0000BBE0 0x79FD # 0 +0x0000BBE1 0x4F1A # 0 +0x0000BBE2 0x70E9 # 0 +0x0000BBE3 0x6C47 # 0 +0x0000BBE4 0x8BB3 # 0 +0x0000BBE5 0x8BF2 # 0 +0x0000BBE6 0x7ED8 # 0 +0x0000BBE7 0x8364 # 0 +0x0000BBE8 0x660F # 0 +0x0000BBE9 0x5A5A # 0 +0x0000BBEA 0x9B42 # 0 +0x0000BBEB 0x6D51 # 0 +0x0000BBEC 0x6DF7 # 0 +0x0000BBED 0x8C41 # 0 +0x0000BBEE 0x6D3B # 0 +0x0000BBEF 0x4F19 # 0 +0x0000BBF0 0x706B # 0 +0x0000BBF1 0x83B7 # 0 +0x0000BBF2 0x6216 # 0 +0x0000BBF3 0x60D1 # 0 +0x0000BBF4 0x970D # 0 +0x0000BBF5 0x8D27 # 0 +0x0000BBF6 0x7978 # 0 +0x0000BBF7 0x51FB # 0 +0x0000BBF8 0x573E # 0 +0x0000BBF9 0x57FA # 0 +0x0000BBFA 0x673A # 0 +0x0000BBFB 0x7578 # 0 +0x0000BBFC 0x7A3D # 0 +0x0000BBFD 0x79EF # 0 +0x0000BBFE 0x7B95 # 0 +0x0000BCA1 0x808C # 0 +0x0000BCA2 0x9965 # 0 +0x0000BCA3 0x8FF9 # 0 +0x0000BCA4 0x6FC0 # 0 +0x0000BCA5 0x8BA5 # 0 +0x0000BCA6 0x9E21 # 0 +0x0000BCA7 0x59EC # 0 +0x0000BCA8 0x7EE9 # 0 +0x0000BCA9 0x7F09 # 0 +0x0000BCAA 0x5409 # 0 +0x0000BCAB 0x6781 # 0 +0x0000BCAC 0x68D8 # 0 +0x0000BCAD 0x8F91 # 0 +0x0000BCAE 0x7C4D # 0 +0x0000BCAF 0x96C6 # 0 +0x0000BCB0 0x53CA # 0 +0x0000BCB1 0x6025 # 0 +0x0000BCB2 0x75BE # 0 +0x0000BCB3 0x6C72 # 0 +0x0000BCB4 0x5373 # 0 +0x0000BCB5 0x5AC9 # 0 +0x0000BCB6 0x7EA7 # 0 +0x0000BCB7 0x6324 # 0 +0x0000BCB8 0x51E0 # 0 +0x0000BCB9 0x810A # 0 +0x0000BCBA 0x5DF1 # 0 +0x0000BCBB 0x84DF # 0 +0x0000BCBC 0x6280 # 0 +0x0000BCBD 0x5180 # 0 +0x0000BCBE 0x5B63 # 0 +0x0000BCBF 0x4F0E # 0 +0x0000BCC0 0x796D # 0 +0x0000BCC1 0x5242 # 0 +0x0000BCC2 0x60B8 # 0 +0x0000BCC3 0x6D4E # 0 +0x0000BCC4 0x5BC4 # 0 +0x0000BCC5 0x5BC2 # 0 +0x0000BCC6 0x8BA1 # 0 +0x0000BCC7 0x8BB0 # 0 +0x0000BCC8 0x65E2 # 0 +0x0000BCC9 0x5FCC # 0 +0x0000BCCA 0x9645 # 0 +0x0000BCCB 0x5993 # 0 +0x0000BCCC 0x7EE7 # 0 +0x0000BCCD 0x7EAA # 0 +0x0000BCCE 0x5609 # 0 +0x0000BCCF 0x67B7 # 0 +0x0000BCD0 0x5939 # 0 +0x0000BCD1 0x4F73 # 0 +0x0000BCD2 0x5BB6 # 0 +0x0000BCD3 0x52A0 # 0 +0x0000BCD4 0x835A # 0 +0x0000BCD5 0x988A # 0 +0x0000BCD6 0x8D3E # 0 +0x0000BCD7 0x7532 # 0 +0x0000BCD8 0x94BE # 0 +0x0000BCD9 0x5047 # 0 +0x0000BCDA 0x7A3C # 0 +0x0000BCDB 0x4EF7 # 0 +0x0000BCDC 0x67B6 # 0 +0x0000BCDD 0x9A7E # 0 +0x0000BCDE 0x5AC1 # 0 +0x0000BCDF 0x6B7C # 0 +0x0000BCE0 0x76D1 # 0 +0x0000BCE1 0x575A # 0 +0x0000BCE2 0x5C16 # 0 +0x0000BCE3 0x7B3A # 0 +0x0000BCE4 0x95F4 # 0 +0x0000BCE5 0x714E # 0 +0x0000BCE6 0x517C # 0 +0x0000BCE7 0x80A9 # 0 +0x0000BCE8 0x8270 # 0 +0x0000BCE9 0x5978 # 0 +0x0000BCEA 0x7F04 # 0 +0x0000BCEB 0x8327 # 0 +0x0000BCEC 0x68C0 # 0 +0x0000BCED 0x67EC # 0 +0x0000BCEE 0x78B1 # 0 +0x0000BCEF 0x7877 # 0 +0x0000BCF0 0x62E3 # 0 +0x0000BCF1 0x6361 # 0 +0x0000BCF2 0x7B80 # 0 +0x0000BCF3 0x4FED # 0 +0x0000BCF4 0x526A # 0 +0x0000BCF5 0x51CF # 0 +0x0000BCF6 0x8350 # 0 +0x0000BCF7 0x69DB # 0 +0x0000BCF8 0x9274 # 0 +0x0000BCF9 0x8DF5 # 0 +0x0000BCFA 0x8D31 # 0 +0x0000BCFB 0x89C1 # 0 +0x0000BCFC 0x952E # 0 +0x0000BCFD 0x7BAD # 0 +0x0000BCFE 0x4EF6 # 0 +0x0000BDA1 0x5065 # 0 +0x0000BDA2 0x8230 # 0 +0x0000BDA3 0x5251 # 0 +0x0000BDA4 0x996F # 0 +0x0000BDA5 0x6E10 # 0 +0x0000BDA6 0x6E85 # 0 +0x0000BDA7 0x6DA7 # 0 +0x0000BDA8 0x5EFA # 0 +0x0000BDA9 0x50F5 # 0 +0x0000BDAA 0x59DC # 0 +0x0000BDAB 0x5C06 # 0 +0x0000BDAC 0x6D46 # 0 +0x0000BDAD 0x6C5F # 0 +0x0000BDAE 0x7586 # 0 +0x0000BDAF 0x848B # 0 +0x0000BDB0 0x6868 # 0 +0x0000BDB1 0x5956 # 0 +0x0000BDB2 0x8BB2 # 0 +0x0000BDB3 0x5320 # 0 +0x0000BDB4 0x9171 # 0 +0x0000BDB5 0x964D # 0 +0x0000BDB6 0x8549 # 0 +0x0000BDB7 0x6912 # 0 +0x0000BDB8 0x7901 # 0 +0x0000BDB9 0x7126 # 0 +0x0000BDBA 0x80F6 # 0 +0x0000BDBB 0x4EA4 # 0 +0x0000BDBC 0x90CA # 0 +0x0000BDBD 0x6D47 # 0 +0x0000BDBE 0x9A84 # 0 +0x0000BDBF 0x5A07 # 0 +0x0000BDC0 0x56BC # 0 +0x0000BDC1 0x6405 # 0 +0x0000BDC2 0x94F0 # 0 +0x0000BDC3 0x77EB # 0 +0x0000BDC4 0x4FA5 # 0 +0x0000BDC5 0x811A # 0 +0x0000BDC6 0x72E1 # 0 +0x0000BDC7 0x89D2 # 0 +0x0000BDC8 0x997A # 0 +0x0000BDC9 0x7F34 # 0 +0x0000BDCA 0x7EDE # 0 +0x0000BDCB 0x527F # 0 +0x0000BDCC 0x6559 # 0 +0x0000BDCD 0x9175 # 0 +0x0000BDCE 0x8F7F # 0 +0x0000BDCF 0x8F83 # 0 +0x0000BDD0 0x53EB # 0 +0x0000BDD1 0x7A96 # 0 +0x0000BDD2 0x63ED # 0 +0x0000BDD3 0x63A5 # 0 +0x0000BDD4 0x7686 # 0 +0x0000BDD5 0x79F8 # 0 +0x0000BDD6 0x8857 # 0 +0x0000BDD7 0x9636 # 0 +0x0000BDD8 0x622A # 0 +0x0000BDD9 0x52AB # 0 +0x0000BDDA 0x8282 # 0 +0x0000BDDB 0x6854 # 0 +0x0000BDDC 0x6770 # 0 +0x0000BDDD 0x6377 # 0 +0x0000BDDE 0x776B # 0 +0x0000BDDF 0x7AED # 0 +0x0000BDE0 0x6D01 # 0 +0x0000BDE1 0x7ED3 # 0 +0x0000BDE2 0x89E3 # 0 +0x0000BDE3 0x59D0 # 0 +0x0000BDE4 0x6212 # 0 +0x0000BDE5 0x85C9 # 0 +0x0000BDE6 0x82A5 # 0 +0x0000BDE7 0x754C # 0 +0x0000BDE8 0x501F # 0 +0x0000BDE9 0x4ECB # 0 +0x0000BDEA 0x75A5 # 0 +0x0000BDEB 0x8BEB # 0 +0x0000BDEC 0x5C4A # 0 +0x0000BDED 0x5DFE # 0 +0x0000BDEE 0x7B4B # 0 +0x0000BDEF 0x65A4 # 0 +0x0000BDF0 0x91D1 # 0 +0x0000BDF1 0x4ECA # 0 +0x0000BDF2 0x6D25 # 0 +0x0000BDF3 0x895F # 0 +0x0000BDF4 0x7D27 # 0 +0x0000BDF5 0x9526 # 0 +0x0000BDF6 0x4EC5 # 0 +0x0000BDF7 0x8C28 # 0 +0x0000BDF8 0x8FDB # 0 +0x0000BDF9 0x9773 # 0 +0x0000BDFA 0x664B # 0 +0x0000BDFB 0x7981 # 0 +0x0000BDFC 0x8FD1 # 0 +0x0000BDFD 0x70EC # 0 +0x0000BDFE 0x6D78 # 0 +0x0000BEA1 0x5C3D # 0 +0x0000BEA2 0x52B2 # 0 +0x0000BEA3 0x8346 # 0 +0x0000BEA4 0x5162 # 0 +0x0000BEA5 0x830E # 0 +0x0000BEA6 0x775B # 0 +0x0000BEA7 0x6676 # 0 +0x0000BEA8 0x9CB8 # 0 +0x0000BEA9 0x4EAC # 0 +0x0000BEAA 0x60CA # 0 +0x0000BEAB 0x7CBE # 0 +0x0000BEAC 0x7CB3 # 0 +0x0000BEAD 0x7ECF # 0 +0x0000BEAE 0x4E95 # 0 +0x0000BEAF 0x8B66 # 0 +0x0000BEB0 0x666F # 0 +0x0000BEB1 0x9888 # 0 +0x0000BEB2 0x9759 # 0 +0x0000BEB3 0x5883 # 0 +0x0000BEB4 0x656C # 0 +0x0000BEB5 0x955C # 0 +0x0000BEB6 0x5F84 # 0 +0x0000BEB7 0x75C9 # 0 +0x0000BEB8 0x9756 # 0 +0x0000BEB9 0x7ADF # 0 +0x0000BEBA 0x7ADE # 0 +0x0000BEBB 0x51C0 # 0 +0x0000BEBC 0x70AF # 0 +0x0000BEBD 0x7A98 # 0 +0x0000BEBE 0x63EA # 0 +0x0000BEBF 0x7A76 # 0 +0x0000BEC0 0x7EA0 # 0 +0x0000BEC1 0x7396 # 0 +0x0000BEC2 0x97ED # 0 +0x0000BEC3 0x4E45 # 0 +0x0000BEC4 0x7078 # 0 +0x0000BEC5 0x4E5D # 0 +0x0000BEC6 0x9152 # 0 +0x0000BEC7 0x53A9 # 0 +0x0000BEC8 0x6551 # 0 +0x0000BEC9 0x65E7 # 0 +0x0000BECA 0x81FC # 0 +0x0000BECB 0x8205 # 0 +0x0000BECC 0x548E # 0 +0x0000BECD 0x5C31 # 0 +0x0000BECE 0x759A # 0 +0x0000BECF 0x97A0 # 0 +0x0000BED0 0x62D8 # 0 +0x0000BED1 0x72D9 # 0 +0x0000BED2 0x75BD # 0 +0x0000BED3 0x5C45 # 0 +0x0000BED4 0x9A79 # 0 +0x0000BED5 0x83CA # 0 +0x0000BED6 0x5C40 # 0 +0x0000BED7 0x5480 # 0 +0x0000BED8 0x77E9 # 0 +0x0000BED9 0x4E3E # 0 +0x0000BEDA 0x6CAE # 0 +0x0000BEDB 0x805A # 0 +0x0000BEDC 0x62D2 # 0 +0x0000BEDD 0x636E # 0 +0x0000BEDE 0x5DE8 # 0 +0x0000BEDF 0x5177 # 0 +0x0000BEE0 0x8DDD # 0 +0x0000BEE1 0x8E1E # 0 +0x0000BEE2 0x952F # 0 +0x0000BEE3 0x4FF1 # 0 +0x0000BEE4 0x53E5 # 0 +0x0000BEE5 0x60E7 # 0 +0x0000BEE6 0x70AC # 0 +0x0000BEE7 0x5267 # 0 +0x0000BEE8 0x6350 # 0 +0x0000BEE9 0x9E43 # 0 +0x0000BEEA 0x5A1F # 0 +0x0000BEEB 0x5026 # 0 +0x0000BEEC 0x7737 # 0 +0x0000BEED 0x5377 # 0 +0x0000BEEE 0x7EE2 # 0 +0x0000BEEF 0x6485 # 0 +0x0000BEF0 0x652B # 0 +0x0000BEF1 0x6289 # 0 +0x0000BEF2 0x6398 # 0 +0x0000BEF3 0x5014 # 0 +0x0000BEF4 0x7235 # 0 +0x0000BEF5 0x89C9 # 0 +0x0000BEF6 0x51B3 # 0 +0x0000BEF7 0x8BC0 # 0 +0x0000BEF8 0x7EDD # 0 +0x0000BEF9 0x5747 # 0 +0x0000BEFA 0x83CC # 0 +0x0000BEFB 0x94A7 # 0 +0x0000BEFC 0x519B # 0 +0x0000BEFD 0x541B # 0 +0x0000BEFE 0x5CFB # 0 +0x0000BFA1 0x4FCA # 0 +0x0000BFA2 0x7AE3 # 0 +0x0000BFA3 0x6D5A # 0 +0x0000BFA4 0x90E1 # 0 +0x0000BFA5 0x9A8F # 0 +0x0000BFA6 0x5580 # 0 +0x0000BFA7 0x5496 # 0 +0x0000BFA8 0x5361 # 0 +0x0000BFA9 0x54AF # 0 +0x0000BFAA 0x5F00 # 0 +0x0000BFAB 0x63E9 # 0 +0x0000BFAC 0x6977 # 0 +0x0000BFAD 0x51EF # 0 +0x0000BFAE 0x6168 # 0 +0x0000BFAF 0x520A # 0 +0x0000BFB0 0x582A # 0 +0x0000BFB1 0x52D8 # 0 +0x0000BFB2 0x574E # 0 +0x0000BFB3 0x780D # 0 +0x0000BFB4 0x770B # 0 +0x0000BFB5 0x5EB7 # 0 +0x0000BFB6 0x6177 # 0 +0x0000BFB7 0x7CE0 # 0 +0x0000BFB8 0x625B # 0 +0x0000BFB9 0x6297 # 0 +0x0000BFBA 0x4EA2 # 0 +0x0000BFBB 0x7095 # 0 +0x0000BFBC 0x8003 # 0 +0x0000BFBD 0x62F7 # 0 +0x0000BFBE 0x70E4 # 0 +0x0000BFBF 0x9760 # 0 +0x0000BFC0 0x5777 # 0 +0x0000BFC1 0x82DB # 0 +0x0000BFC2 0x67EF # 0 +0x0000BFC3 0x68F5 # 0 +0x0000BFC4 0x78D5 # 0 +0x0000BFC5 0x9897 # 0 +0x0000BFC6 0x79D1 # 0 +0x0000BFC7 0x58F3 # 0 +0x0000BFC8 0x54B3 # 0 +0x0000BFC9 0x53EF # 0 +0x0000BFCA 0x6E34 # 0 +0x0000BFCB 0x514B # 0 +0x0000BFCC 0x523B # 0 +0x0000BFCD 0x5BA2 # 0 +0x0000BFCE 0x8BFE # 0 +0x0000BFCF 0x80AF # 0 +0x0000BFD0 0x5543 # 0 +0x0000BFD1 0x57A6 # 0 +0x0000BFD2 0x6073 # 0 +0x0000BFD3 0x5751 # 0 +0x0000BFD4 0x542D # 0 +0x0000BFD5 0x7A7A # 0 +0x0000BFD6 0x6050 # 0 +0x0000BFD7 0x5B54 # 0 +0x0000BFD8 0x63A7 # 0 +0x0000BFD9 0x62A0 # 0 +0x0000BFDA 0x53E3 # 0 +0x0000BFDB 0x6263 # 0 +0x0000BFDC 0x5BC7 # 0 +0x0000BFDD 0x67AF # 0 +0x0000BFDE 0x54ED # 0 +0x0000BFDF 0x7A9F # 0 +0x0000BFE0 0x82E6 # 0 +0x0000BFE1 0x9177 # 0 +0x0000BFE2 0x5E93 # 0 +0x0000BFE3 0x88E4 # 0 +0x0000BFE4 0x5938 # 0 +0x0000BFE5 0x57AE # 0 +0x0000BFE6 0x630E # 0 +0x0000BFE7 0x8DE8 # 0 +0x0000BFE8 0x80EF # 0 +0x0000BFE9 0x5757 # 0 +0x0000BFEA 0x7B77 # 0 +0x0000BFEB 0x4FA9 # 0 +0x0000BFEC 0x5FEB # 0 +0x0000BFED 0x5BBD # 0 +0x0000BFEE 0x6B3E # 0 +0x0000BFEF 0x5321 # 0 +0x0000BFF0 0x7B50 # 0 +0x0000BFF1 0x72C2 # 0 +0x0000BFF2 0x6846 # 0 +0x0000BFF3 0x77FF # 0 +0x0000BFF4 0x7736 # 0 +0x0000BFF5 0x65F7 # 0 +0x0000BFF6 0x51B5 # 0 +0x0000BFF7 0x4E8F # 0 +0x0000BFF8 0x76D4 # 0 +0x0000BFF9 0x5CBF # 0 +0x0000BFFA 0x7AA5 # 0 +0x0000BFFB 0x8475 # 0 +0x0000BFFC 0x594E # 0 +0x0000BFFD 0x9B41 # 0 +0x0000BFFE 0x5080 # 0 +0x0000C0A1 0x9988 # 0 +0x0000C0A2 0x6127 # 0 +0x0000C0A3 0x6E83 # 0 +0x0000C0A4 0x5764 # 0 +0x0000C0A5 0x6606 # 0 +0x0000C0A6 0x6346 # 0 +0x0000C0A7 0x56F0 # 0 +0x0000C0A8 0x62EC # 0 +0x0000C0A9 0x6269 # 0 +0x0000C0AA 0x5ED3 # 0 +0x0000C0AB 0x9614 # 0 +0x0000C0AC 0x5783 # 0 +0x0000C0AD 0x62C9 # 0 +0x0000C0AE 0x5587 # 0 +0x0000C0AF 0x8721 # 0 +0x0000C0B0 0x814A # 0 +0x0000C0B1 0x8FA3 # 0 +0x0000C0B2 0x5566 # 0 +0x0000C0B3 0x83B1 # 0 +0x0000C0B4 0x6765 # 0 +0x0000C0B5 0x8D56 # 0 +0x0000C0B6 0x84DD # 0 +0x0000C0B7 0x5A6A # 0 +0x0000C0B8 0x680F # 0 +0x0000C0B9 0x62E6 # 0 +0x0000C0BA 0x7BEE # 0 +0x0000C0BB 0x9611 # 0 +0x0000C0BC 0x5170 # 0 +0x0000C0BD 0x6F9C # 0 +0x0000C0BE 0x8C30 # 0 +0x0000C0BF 0x63FD # 0 +0x0000C0C0 0x89C8 # 0 +0x0000C0C1 0x61D2 # 0 +0x0000C0C2 0x7F06 # 0 +0x0000C0C3 0x70C2 # 0 +0x0000C0C4 0x6EE5 # 0 +0x0000C0C5 0x7405 # 0 +0x0000C0C6 0x6994 # 0 +0x0000C0C7 0x72FC # 0 +0x0000C0C8 0x5ECA # 0 +0x0000C0C9 0x90CE # 0 +0x0000C0CA 0x6717 # 0 +0x0000C0CB 0x6D6A # 0 +0x0000C0CC 0x635E # 0 +0x0000C0CD 0x52B3 # 0 +0x0000C0CE 0x7262 # 0 +0x0000C0CF 0x8001 # 0 +0x0000C0D0 0x4F6C # 0 +0x0000C0D1 0x59E5 # 0 +0x0000C0D2 0x916A # 0 +0x0000C0D3 0x70D9 # 0 +0x0000C0D4 0x6D9D # 0 +0x0000C0D5 0x52D2 # 0 +0x0000C0D6 0x4E50 # 0 +0x0000C0D7 0x96F7 # 0 +0x0000C0D8 0x956D # 0 +0x0000C0D9 0x857E # 0 +0x0000C0DA 0x78CA # 0 +0x0000C0DB 0x7D2F # 0 +0x0000C0DC 0x5121 # 0 +0x0000C0DD 0x5792 # 0 +0x0000C0DE 0x64C2 # 0 +0x0000C0DF 0x808B # 0 +0x0000C0E0 0x7C7B # 0 +0x0000C0E1 0x6CEA # 0 +0x0000C0E2 0x68F1 # 0 +0x0000C0E3 0x695E # 0 +0x0000C0E4 0x51B7 # 0 +0x0000C0E5 0x5398 # 0 +0x0000C0E6 0x68A8 # 0 +0x0000C0E7 0x7281 # 0 +0x0000C0E8 0x9ECE # 0 +0x0000C0E9 0x7BF1 # 0 +0x0000C0EA 0x72F8 # 0 +0x0000C0EB 0x79BB # 0 +0x0000C0EC 0x6F13 # 0 +0x0000C0ED 0x7406 # 0 +0x0000C0EE 0x674E # 0 +0x0000C0EF 0x91CC # 0 +0x0000C0F0 0x9CA4 # 0 +0x0000C0F1 0x793C # 0 +0x0000C0F2 0x8389 # 0 +0x0000C0F3 0x8354 # 0 +0x0000C0F4 0x540F # 0 +0x0000C0F5 0x6817 # 0 +0x0000C0F6 0x4E3D # 0 +0x0000C0F7 0x5389 # 0 +0x0000C0F8 0x52B1 # 0 +0x0000C0F9 0x783E # 0 +0x0000C0FA 0x5386 # 0 +0x0000C0FB 0x5229 # 0 +0x0000C0FC 0x5088 # 0 +0x0000C0FD 0x4F8B # 0 +0x0000C0FE 0x4FD0 # 0 +0x0000C1A1 0x75E2 # 0 +0x0000C1A2 0x7ACB # 0 +0x0000C1A3 0x7C92 # 0 +0x0000C1A4 0x6CA5 # 0 +0x0000C1A5 0x96B6 # 0 +0x0000C1A6 0x529B # 0 +0x0000C1A7 0x7483 # 0 +0x0000C1A8 0x54E9 # 0 +0x0000C1A9 0x4FE9 # 0 +0x0000C1AA 0x8054 # 0 +0x0000C1AB 0x83B2 # 0 +0x0000C1AC 0x8FDE # 0 +0x0000C1AD 0x9570 # 0 +0x0000C1AE 0x5EC9 # 0 +0x0000C1AF 0x601C # 0 +0x0000C1B0 0x6D9F # 0 +0x0000C1B1 0x5E18 # 0 +0x0000C1B2 0x655B # 0 +0x0000C1B3 0x8138 # 0 +0x0000C1B4 0x94FE # 0 +0x0000C1B5 0x604B # 0 +0x0000C1B6 0x70BC # 0 +0x0000C1B7 0x7EC3 # 0 +0x0000C1B8 0x7CAE # 0 +0x0000C1B9 0x51C9 # 0 +0x0000C1BA 0x6881 # 0 +0x0000C1BB 0x7CB1 # 0 +0x0000C1BC 0x826F # 0 +0x0000C1BD 0x4E24 # 0 +0x0000C1BE 0x8F86 # 0 +0x0000C1BF 0x91CF # 0 +0x0000C1C0 0x667E # 0 +0x0000C1C1 0x4EAE # 0 +0x0000C1C2 0x8C05 # 0 +0x0000C1C3 0x64A9 # 0 +0x0000C1C4 0x804A # 0 +0x0000C1C5 0x50DA # 0 +0x0000C1C6 0x7597 # 0 +0x0000C1C7 0x71CE # 0 +0x0000C1C8 0x5BE5 # 0 +0x0000C1C9 0x8FBD # 0 +0x0000C1CA 0x6F66 # 0 +0x0000C1CB 0x4E86 # 0 +0x0000C1CC 0x6482 # 0 +0x0000C1CD 0x9563 # 0 +0x0000C1CE 0x5ED6 # 0 +0x0000C1CF 0x6599 # 0 +0x0000C1D0 0x5217 # 0 +0x0000C1D1 0x88C2 # 0 +0x0000C1D2 0x70C8 # 0 +0x0000C1D3 0x52A3 # 0 +0x0000C1D4 0x730E # 0 +0x0000C1D5 0x7433 # 0 +0x0000C1D6 0x6797 # 0 +0x0000C1D7 0x78F7 # 0 +0x0000C1D8 0x9716 # 0 +0x0000C1D9 0x4E34 # 0 +0x0000C1DA 0x90BB # 0 +0x0000C1DB 0x9CDE # 0 +0x0000C1DC 0x6DCB # 0 +0x0000C1DD 0x51DB # 0 +0x0000C1DE 0x8D41 # 0 +0x0000C1DF 0x541D # 0 +0x0000C1E0 0x62CE # 0 +0x0000C1E1 0x73B2 # 0 +0x0000C1E2 0x83F1 # 0 +0x0000C1E3 0x96F6 # 0 +0x0000C1E4 0x9F84 # 0 +0x0000C1E5 0x94C3 # 0 +0x0000C1E6 0x4F36 # 0 +0x0000C1E7 0x7F9A # 0 +0x0000C1E8 0x51CC # 0 +0x0000C1E9 0x7075 # 0 +0x0000C1EA 0x9675 # 0 +0x0000C1EB 0x5CAD # 0 +0x0000C1EC 0x9886 # 0 +0x0000C1ED 0x53E6 # 0 +0x0000C1EE 0x4EE4 # 0 +0x0000C1EF 0x6E9C # 0 +0x0000C1F0 0x7409 # 0 +0x0000C1F1 0x69B4 # 0 +0x0000C1F2 0x786B # 0 +0x0000C1F3 0x998F # 0 +0x0000C1F4 0x7559 # 0 +0x0000C1F5 0x5218 # 0 +0x0000C1F6 0x7624 # 0 +0x0000C1F7 0x6D41 # 0 +0x0000C1F8 0x67F3 # 0 +0x0000C1F9 0x516D # 0 +0x0000C1FA 0x9F99 # 0 +0x0000C1FB 0x804B # 0 +0x0000C1FC 0x5499 # 0 +0x0000C1FD 0x7B3C # 0 +0x0000C1FE 0x7ABF # 0 +0x0000C2A1 0x9686 # 0 +0x0000C2A2 0x5784 # 0 +0x0000C2A3 0x62E2 # 0 +0x0000C2A4 0x9647 # 0 +0x0000C2A5 0x697C # 0 +0x0000C2A6 0x5A04 # 0 +0x0000C2A7 0x6402 # 0 +0x0000C2A8 0x7BD3 # 0 +0x0000C2A9 0x6F0F # 0 +0x0000C2AA 0x964B # 0 +0x0000C2AB 0x82A6 # 0 +0x0000C2AC 0x5362 # 0 +0x0000C2AD 0x9885 # 0 +0x0000C2AE 0x5E90 # 0 +0x0000C2AF 0x7089 # 0 +0x0000C2B0 0x63B3 # 0 +0x0000C2B1 0x5364 # 0 +0x0000C2B2 0x864F # 0 +0x0000C2B3 0x9C81 # 0 +0x0000C2B4 0x9E93 # 0 +0x0000C2B5 0x788C # 0 +0x0000C2B6 0x9732 # 0 +0x0000C2B7 0x8DEF # 0 +0x0000C2B8 0x8D42 # 0 +0x0000C2B9 0x9E7F # 0 +0x0000C2BA 0x6F5E # 0 +0x0000C2BB 0x7984 # 0 +0x0000C2BC 0x5F55 # 0 +0x0000C2BD 0x9646 # 0 +0x0000C2BE 0x622E # 0 +0x0000C2BF 0x9A74 # 0 +0x0000C2C0 0x5415 # 0 +0x0000C2C1 0x94DD # 0 +0x0000C2C2 0x4FA3 # 0 +0x0000C2C3 0x65C5 # 0 +0x0000C2C4 0x5C65 # 0 +0x0000C2C5 0x5C61 # 0 +0x0000C2C6 0x7F15 # 0 +0x0000C2C7 0x8651 # 0 +0x0000C2C8 0x6C2F # 0 +0x0000C2C9 0x5F8B # 0 +0x0000C2CA 0x7387 # 0 +0x0000C2CB 0x6EE4 # 0 +0x0000C2CC 0x7EFF # 0 +0x0000C2CD 0x5CE6 # 0 +0x0000C2CE 0x631B # 0 +0x0000C2CF 0x5B6A # 0 +0x0000C2D0 0x6EE6 # 0 +0x0000C2D1 0x5375 # 0 +0x0000C2D2 0x4E71 # 0 +0x0000C2D3 0x63A0 # 0 +0x0000C2D4 0x7565 # 0 +0x0000C2D5 0x62A1 # 0 +0x0000C2D6 0x8F6E # 0 +0x0000C2D7 0x4F26 # 0 +0x0000C2D8 0x4ED1 # 0 +0x0000C2D9 0x6CA6 # 0 +0x0000C2DA 0x7EB6 # 0 +0x0000C2DB 0x8BBA # 0 +0x0000C2DC 0x841D # 0 +0x0000C2DD 0x87BA # 0 +0x0000C2DE 0x7F57 # 0 +0x0000C2DF 0x903B # 0 +0x0000C2E0 0x9523 # 0 +0x0000C2E1 0x7BA9 # 0 +0x0000C2E2 0x9AA1 # 0 +0x0000C2E3 0x88F8 # 0 +0x0000C2E4 0x843D # 0 +0x0000C2E5 0x6D1B # 0 +0x0000C2E6 0x9A86 # 0 +0x0000C2E7 0x7EDC # 0 +0x0000C2E8 0x5988 # 0 +0x0000C2E9 0x9EBB # 0 +0x0000C2EA 0x739B # 0 +0x0000C2EB 0x7801 # 0 +0x0000C2EC 0x8682 # 0 +0x0000C2ED 0x9A6C # 0 +0x0000C2EE 0x9A82 # 0 +0x0000C2EF 0x561B # 0 +0x0000C2F0 0x5417 # 0 +0x0000C2F1 0x57CB # 0 +0x0000C2F2 0x4E70 # 0 +0x0000C2F3 0x9EA6 # 0 +0x0000C2F4 0x5356 # 0 +0x0000C2F5 0x8FC8 # 0 +0x0000C2F6 0x8109 # 0 +0x0000C2F7 0x7792 # 0 +0x0000C2F8 0x9992 # 0 +0x0000C2F9 0x86EE # 0 +0x0000C2FA 0x6EE1 # 0 +0x0000C2FB 0x8513 # 0 +0x0000C2FC 0x66FC # 0 +0x0000C2FD 0x6162 # 0 +0x0000C2FE 0x6F2B # 0 +0x0000C3A1 0x8C29 # 0 +0x0000C3A2 0x8292 # 0 +0x0000C3A3 0x832B # 0 +0x0000C3A4 0x76F2 # 0 +0x0000C3A5 0x6C13 # 0 +0x0000C3A6 0x5FD9 # 0 +0x0000C3A7 0x83BD # 0 +0x0000C3A8 0x732B # 0 +0x0000C3A9 0x8305 # 0 +0x0000C3AA 0x951A # 0 +0x0000C3AB 0x6BDB # 0 +0x0000C3AC 0x77DB # 0 +0x0000C3AD 0x94C6 # 0 +0x0000C3AE 0x536F # 0 +0x0000C3AF 0x8302 # 0 +0x0000C3B0 0x5192 # 0 +0x0000C3B1 0x5E3D # 0 +0x0000C3B2 0x8C8C # 0 +0x0000C3B3 0x8D38 # 0 +0x0000C3B4 0x4E48 # 0 +0x0000C3B5 0x73AB # 0 +0x0000C3B6 0x679A # 0 +0x0000C3B7 0x6885 # 0 +0x0000C3B8 0x9176 # 0 +0x0000C3B9 0x9709 # 0 +0x0000C3BA 0x7164 # 0 +0x0000C3BB 0x6CA1 # 0 +0x0000C3BC 0x7709 # 0 +0x0000C3BD 0x5A92 # 0 +0x0000C3BE 0x9541 # 0 +0x0000C3BF 0x6BCF # 0 +0x0000C3C0 0x7F8E # 0 +0x0000C3C1 0x6627 # 0 +0x0000C3C2 0x5BD0 # 0 +0x0000C3C3 0x59B9 # 0 +0x0000C3C4 0x5A9A # 0 +0x0000C3C5 0x95E8 # 0 +0x0000C3C6 0x95F7 # 0 +0x0000C3C7 0x4EEC # 0 +0x0000C3C8 0x840C # 0 +0x0000C3C9 0x8499 # 0 +0x0000C3CA 0x6AAC # 0 +0x0000C3CB 0x76DF # 0 +0x0000C3CC 0x9530 # 0 +0x0000C3CD 0x731B # 0 +0x0000C3CE 0x68A6 # 0 +0x0000C3CF 0x5B5F # 0 +0x0000C3D0 0x772F # 0 +0x0000C3D1 0x919A # 0 +0x0000C3D2 0x9761 # 0 +0x0000C3D3 0x7CDC # 0 +0x0000C3D4 0x8FF7 # 0 +0x0000C3D5 0x8C1C # 0 +0x0000C3D6 0x5F25 # 0 +0x0000C3D7 0x7C73 # 0 +0x0000C3D8 0x79D8 # 0 +0x0000C3D9 0x89C5 # 0 +0x0000C3DA 0x6CCC # 0 +0x0000C3DB 0x871C # 0 +0x0000C3DC 0x5BC6 # 0 +0x0000C3DD 0x5E42 # 0 +0x0000C3DE 0x68C9 # 0 +0x0000C3DF 0x7720 # 0 +0x0000C3E0 0x7EF5 # 0 +0x0000C3E1 0x5195 # 0 +0x0000C3E2 0x514D # 0 +0x0000C3E3 0x52C9 # 0 +0x0000C3E4 0x5A29 # 0 +0x0000C3E5 0x7F05 # 0 +0x0000C3E6 0x9762 # 0 +0x0000C3E7 0x82D7 # 0 +0x0000C3E8 0x63CF # 0 +0x0000C3E9 0x7784 # 0 +0x0000C3EA 0x85D0 # 0 +0x0000C3EB 0x79D2 # 0 +0x0000C3EC 0x6E3A # 0 +0x0000C3ED 0x5E99 # 0 +0x0000C3EE 0x5999 # 0 +0x0000C3EF 0x8511 # 0 +0x0000C3F0 0x706D # 0 +0x0000C3F1 0x6C11 # 0 +0x0000C3F2 0x62BF # 0 +0x0000C3F3 0x76BF # 0 +0x0000C3F4 0x654F # 0 +0x0000C3F5 0x60AF # 0 +0x0000C3F6 0x95FD # 0 +0x0000C3F7 0x660E # 0 +0x0000C3F8 0x879F # 0 +0x0000C3F9 0x9E23 # 0 +0x0000C3FA 0x94ED # 0 +0x0000C3FB 0x540D # 0 +0x0000C3FC 0x547D # 0 +0x0000C3FD 0x8C2C # 0 +0x0000C3FE 0x6478 # 0 +0x0000C4A1 0x6479 # 0 +0x0000C4A2 0x8611 # 0 +0x0000C4A3 0x6A21 # 0 +0x0000C4A4 0x819C # 0 +0x0000C4A5 0x78E8 # 0 +0x0000C4A6 0x6469 # 0 +0x0000C4A7 0x9B54 # 0 +0x0000C4A8 0x62B9 # 0 +0x0000C4A9 0x672B # 0 +0x0000C4AA 0x83AB # 0 +0x0000C4AB 0x58A8 # 0 +0x0000C4AC 0x9ED8 # 0 +0x0000C4AD 0x6CAB # 0 +0x0000C4AE 0x6F20 # 0 +0x0000C4AF 0x5BDE # 0 +0x0000C4B0 0x964C # 0 +0x0000C4B1 0x8C0B # 0 +0x0000C4B2 0x725F # 0 +0x0000C4B3 0x67D0 # 0 +0x0000C4B4 0x62C7 # 0 +0x0000C4B5 0x7261 # 0 +0x0000C4B6 0x4EA9 # 0 +0x0000C4B7 0x59C6 # 0 +0x0000C4B8 0x6BCD # 0 +0x0000C4B9 0x5893 # 0 +0x0000C4BA 0x66AE # 0 +0x0000C4BB 0x5E55 # 0 +0x0000C4BC 0x52DF # 0 +0x0000C4BD 0x6155 # 0 +0x0000C4BE 0x6728 # 0 +0x0000C4BF 0x76EE # 0 +0x0000C4C0 0x7766 # 0 +0x0000C4C1 0x7267 # 0 +0x0000C4C2 0x7A46 # 0 +0x0000C4C3 0x62FF # 0 +0x0000C4C4 0x54EA # 0 +0x0000C4C5 0x5450 # 0 +0x0000C4C6 0x94A0 # 0 +0x0000C4C7 0x90A3 # 0 +0x0000C4C8 0x5A1C # 0 +0x0000C4C9 0x7EB3 # 0 +0x0000C4CA 0x6C16 # 0 +0x0000C4CB 0x4E43 # 0 +0x0000C4CC 0x5976 # 0 +0x0000C4CD 0x8010 # 0 +0x0000C4CE 0x5948 # 0 +0x0000C4CF 0x5357 # 0 +0x0000C4D0 0x7537 # 0 +0x0000C4D1 0x96BE # 0 +0x0000C4D2 0x56CA # 0 +0x0000C4D3 0x6320 # 0 +0x0000C4D4 0x8111 # 0 +0x0000C4D5 0x607C # 0 +0x0000C4D6 0x95F9 # 0 +0x0000C4D7 0x6DD6 # 0 +0x0000C4D8 0x5462 # 0 +0x0000C4D9 0x9981 # 0 +0x0000C4DA 0x5185 # 0 +0x0000C4DB 0x5AE9 # 0 +0x0000C4DC 0x80FD # 0 +0x0000C4DD 0x59AE # 0 +0x0000C4DE 0x9713 # 0 +0x0000C4DF 0x502A # 0 +0x0000C4E0 0x6CE5 # 0 +0x0000C4E1 0x5C3C # 0 +0x0000C4E2 0x62DF # 0 +0x0000C4E3 0x4F60 # 0 +0x0000C4E4 0x533F # 0 +0x0000C4E5 0x817B # 0 +0x0000C4E6 0x9006 # 0 +0x0000C4E7 0x6EBA # 0 +0x0000C4E8 0x852B # 0 +0x0000C4E9 0x62C8 # 0 +0x0000C4EA 0x5E74 # 0 +0x0000C4EB 0x78BE # 0 +0x0000C4EC 0x64B5 # 0 +0x0000C4ED 0x637B # 0 +0x0000C4EE 0x5FF5 # 0 +0x0000C4EF 0x5A18 # 0 +0x0000C4F0 0x917F # 0 +0x0000C4F1 0x9E1F # 0 +0x0000C4F2 0x5C3F # 0 +0x0000C4F3 0x634F # 0 +0x0000C4F4 0x8042 # 0 +0x0000C4F5 0x5B7D # 0 +0x0000C4F6 0x556E # 0 +0x0000C4F7 0x954A # 0 +0x0000C4F8 0x954D # 0 +0x0000C4F9 0x6D85 # 0 +0x0000C4FA 0x60A8 # 0 +0x0000C4FB 0x67E0 # 0 +0x0000C4FC 0x72DE # 0 +0x0000C4FD 0x51DD # 0 +0x0000C4FE 0x5B81 # 0 +0x0000C5A1 0x62E7 # 0 +0x0000C5A2 0x6CDE # 0 +0x0000C5A3 0x725B # 0 +0x0000C5A4 0x626D # 0 +0x0000C5A5 0x94AE # 0 +0x0000C5A6 0x7EBD # 0 +0x0000C5A7 0x8113 # 0 +0x0000C5A8 0x6D53 # 0 +0x0000C5A9 0x519C # 0 +0x0000C5AA 0x5F04 # 0 +0x0000C5AB 0x5974 # 0 +0x0000C5AC 0x52AA # 0 +0x0000C5AD 0x6012 # 0 +0x0000C5AE 0x5973 # 0 +0x0000C5AF 0x6696 # 0 +0x0000C5B0 0x8650 # 0 +0x0000C5B1 0x759F # 0 +0x0000C5B2 0x632A # 0 +0x0000C5B3 0x61E6 # 0 +0x0000C5B4 0x7CEF # 0 +0x0000C5B5 0x8BFA # 0 +0x0000C5B6 0x54E6 # 0 +0x0000C5B7 0x6B27 # 0 +0x0000C5B8 0x9E25 # 0 +0x0000C5B9 0x6BB4 # 0 +0x0000C5BA 0x85D5 # 0 +0x0000C5BB 0x5455 # 0 +0x0000C5BC 0x5076 # 0 +0x0000C5BD 0x6CA4 # 0 +0x0000C5BE 0x556A # 0 +0x0000C5BF 0x8DB4 # 0 +0x0000C5C0 0x722C # 0 +0x0000C5C1 0x5E15 # 0 +0x0000C5C2 0x6015 # 0 +0x0000C5C3 0x7436 # 0 +0x0000C5C4 0x62CD # 0 +0x0000C5C5 0x6392 # 0 +0x0000C5C6 0x724C # 0 +0x0000C5C7 0x5F98 # 0 +0x0000C5C8 0x6E43 # 0 +0x0000C5C9 0x6D3E # 0 +0x0000C5CA 0x6500 # 0 +0x0000C5CB 0x6F58 # 0 +0x0000C5CC 0x76D8 # 0 +0x0000C5CD 0x78D0 # 0 +0x0000C5CE 0x76FC # 0 +0x0000C5CF 0x7554 # 0 +0x0000C5D0 0x5224 # 0 +0x0000C5D1 0x53DB # 0 +0x0000C5D2 0x4E53 # 0 +0x0000C5D3 0x5E9E # 0 +0x0000C5D4 0x65C1 # 0 +0x0000C5D5 0x802A # 0 +0x0000C5D6 0x80D6 # 0 +0x0000C5D7 0x629B # 0 +0x0000C5D8 0x5486 # 0 +0x0000C5D9 0x5228 # 0 +0x0000C5DA 0x70AE # 0 +0x0000C5DB 0x888D # 0 +0x0000C5DC 0x8DD1 # 0 +0x0000C5DD 0x6CE1 # 0 +0x0000C5DE 0x5478 # 0 +0x0000C5DF 0x80DA # 0 +0x0000C5E0 0x57F9 # 0 +0x0000C5E1 0x88F4 # 0 +0x0000C5E2 0x8D54 # 0 +0x0000C5E3 0x966A # 0 +0x0000C5E4 0x914D # 0 +0x0000C5E5 0x4F69 # 0 +0x0000C5E6 0x6C9B # 0 +0x0000C5E7 0x55B7 # 0 +0x0000C5E8 0x76C6 # 0 +0x0000C5E9 0x7830 # 0 +0x0000C5EA 0x62A8 # 0 +0x0000C5EB 0x70F9 # 0 +0x0000C5EC 0x6F8E # 0 +0x0000C5ED 0x5F6D # 0 +0x0000C5EE 0x84EC # 0 +0x0000C5EF 0x68DA # 0 +0x0000C5F0 0x787C # 0 +0x0000C5F1 0x7BF7 # 0 +0x0000C5F2 0x81A8 # 0 +0x0000C5F3 0x670B # 0 +0x0000C5F4 0x9E4F # 0 +0x0000C5F5 0x6367 # 0 +0x0000C5F6 0x78B0 # 0 +0x0000C5F7 0x576F # 0 +0x0000C5F8 0x7812 # 0 +0x0000C5F9 0x9739 # 0 +0x0000C5FA 0x6279 # 0 +0x0000C5FB 0x62AB # 0 +0x0000C5FC 0x5288 # 0 +0x0000C5FD 0x7435 # 0 +0x0000C5FE 0x6BD7 # 0 +0x0000C6A1 0x5564 # 0 +0x0000C6A2 0x813E # 0 +0x0000C6A3 0x75B2 # 0 +0x0000C6A4 0x76AE # 0 +0x0000C6A5 0x5339 # 0 +0x0000C6A6 0x75DE # 0 +0x0000C6A7 0x50FB # 0 +0x0000C6A8 0x5C41 # 0 +0x0000C6A9 0x8B6C # 0 +0x0000C6AA 0x7BC7 # 0 +0x0000C6AB 0x504F # 0 +0x0000C6AC 0x7247 # 0 +0x0000C6AD 0x9A97 # 0 +0x0000C6AE 0x98D8 # 0 +0x0000C6AF 0x6F02 # 0 +0x0000C6B0 0x74E2 # 0 +0x0000C6B1 0x7968 # 0 +0x0000C6B2 0x6487 # 0 +0x0000C6B3 0x77A5 # 0 +0x0000C6B4 0x62FC # 0 +0x0000C6B5 0x9891 # 0 +0x0000C6B6 0x8D2B # 0 +0x0000C6B7 0x54C1 # 0 +0x0000C6B8 0x8058 # 0 +0x0000C6B9 0x4E52 # 0 +0x0000C6BA 0x576A # 0 +0x0000C6BB 0x82F9 # 0 +0x0000C6BC 0x840D # 0 +0x0000C6BD 0x5E73 # 0 +0x0000C6BE 0x51ED # 0 +0x0000C6BF 0x74F6 # 0 +0x0000C6C0 0x8BC4 # 0 +0x0000C6C1 0x5C4F # 0 +0x0000C6C2 0x5761 # 0 +0x0000C6C3 0x6CFC # 0 +0x0000C6C4 0x9887 # 0 +0x0000C6C5 0x5A46 # 0 +0x0000C6C6 0x7834 # 0 +0x0000C6C7 0x9B44 # 0 +0x0000C6C8 0x8FEB # 0 +0x0000C6C9 0x7C95 # 0 +0x0000C6CA 0x5256 # 0 +0x0000C6CB 0x6251 # 0 +0x0000C6CC 0x94FA # 0 +0x0000C6CD 0x4EC6 # 0 +0x0000C6CE 0x8386 # 0 +0x0000C6CF 0x8461 # 0 +0x0000C6D0 0x83E9 # 0 +0x0000C6D1 0x84B2 # 0 +0x0000C6D2 0x57D4 # 0 +0x0000C6D3 0x6734 # 0 +0x0000C6D4 0x5703 # 0 +0x0000C6D5 0x666E # 0 +0x0000C6D6 0x6D66 # 0 +0x0000C6D7 0x8C31 # 0 +0x0000C6D8 0x66DD # 0 +0x0000C6D9 0x7011 # 0 +0x0000C6DA 0x671F # 0 +0x0000C6DB 0x6B3A # 0 +0x0000C6DC 0x6816 # 0 +0x0000C6DD 0x621A # 0 +0x0000C6DE 0x59BB # 0 +0x0000C6DF 0x4E03 # 0 +0x0000C6E0 0x51C4 # 0 +0x0000C6E1 0x6F06 # 0 +0x0000C6E2 0x67D2 # 0 +0x0000C6E3 0x6C8F # 0 +0x0000C6E4 0x5176 # 0 +0x0000C6E5 0x68CB # 0 +0x0000C6E6 0x5947 # 0 +0x0000C6E7 0x6B67 # 0 +0x0000C6E8 0x7566 # 0 +0x0000C6E9 0x5D0E # 0 +0x0000C6EA 0x8110 # 0 +0x0000C6EB 0x9F50 # 0 +0x0000C6EC 0x65D7 # 0 +0x0000C6ED 0x7948 # 0 +0x0000C6EE 0x7941 # 0 +0x0000C6EF 0x9A91 # 0 +0x0000C6F0 0x8D77 # 0 +0x0000C6F1 0x5C82 # 0 +0x0000C6F2 0x4E5E # 0 +0x0000C6F3 0x4F01 # 0 +0x0000C6F4 0x542F # 0 +0x0000C6F5 0x5951 # 0 +0x0000C6F6 0x780C # 0 +0x0000C6F7 0x5668 # 0 +0x0000C6F8 0x6C14 # 0 +0x0000C6F9 0x8FC4 # 0 +0x0000C6FA 0x5F03 # 0 +0x0000C6FB 0x6C7D # 0 +0x0000C6FC 0x6CE3 # 0 +0x0000C6FD 0x8BAB # 0 +0x0000C6FE 0x6390 # 0 +0x0000C7A1 0x6070 # 0 +0x0000C7A2 0x6D3D # 0 +0x0000C7A3 0x7275 # 0 +0x0000C7A4 0x6266 # 0 +0x0000C7A5 0x948E # 0 +0x0000C7A6 0x94C5 # 0 +0x0000C7A7 0x5343 # 0 +0x0000C7A8 0x8FC1 # 0 +0x0000C7A9 0x7B7E # 0 +0x0000C7AA 0x4EDF # 0 +0x0000C7AB 0x8C26 # 0 +0x0000C7AC 0x4E7E # 0 +0x0000C7AD 0x9ED4 # 0 +0x0000C7AE 0x94B1 # 0 +0x0000C7AF 0x94B3 # 0 +0x0000C7B0 0x524D # 0 +0x0000C7B1 0x6F5C # 0 +0x0000C7B2 0x9063 # 0 +0x0000C7B3 0x6D45 # 0 +0x0000C7B4 0x8C34 # 0 +0x0000C7B5 0x5811 # 0 +0x0000C7B6 0x5D4C # 0 +0x0000C7B7 0x6B20 # 0 +0x0000C7B8 0x6B49 # 0 +0x0000C7B9 0x67AA # 0 +0x0000C7BA 0x545B # 0 +0x0000C7BB 0x8154 # 0 +0x0000C7BC 0x7F8C # 0 +0x0000C7BD 0x5899 # 0 +0x0000C7BE 0x8537 # 0 +0x0000C7BF 0x5F3A # 0 +0x0000C7C0 0x62A2 # 0 +0x0000C7C1 0x6A47 # 0 +0x0000C7C2 0x9539 # 0 +0x0000C7C3 0x6572 # 0 +0x0000C7C4 0x6084 # 0 +0x0000C7C5 0x6865 # 0 +0x0000C7C6 0x77A7 # 0 +0x0000C7C7 0x4E54 # 0 +0x0000C7C8 0x4FA8 # 0 +0x0000C7C9 0x5DE7 # 0 +0x0000C7CA 0x9798 # 0 +0x0000C7CB 0x64AC # 0 +0x0000C7CC 0x7FD8 # 0 +0x0000C7CD 0x5CED # 0 +0x0000C7CE 0x4FCF # 0 +0x0000C7CF 0x7A8D # 0 +0x0000C7D0 0x5207 # 0 +0x0000C7D1 0x8304 # 0 +0x0000C7D2 0x4E14 # 0 +0x0000C7D3 0x602F # 0 +0x0000C7D4 0x7A83 # 0 +0x0000C7D5 0x94A6 # 0 +0x0000C7D6 0x4FB5 # 0 +0x0000C7D7 0x4EB2 # 0 +0x0000C7D8 0x79E6 # 0 +0x0000C7D9 0x7434 # 0 +0x0000C7DA 0x52E4 # 0 +0x0000C7DB 0x82B9 # 0 +0x0000C7DC 0x64D2 # 0 +0x0000C7DD 0x79BD # 0 +0x0000C7DE 0x5BDD # 0 +0x0000C7DF 0x6C81 # 0 +0x0000C7E0 0x9752 # 0 +0x0000C7E1 0x8F7B # 0 +0x0000C7E2 0x6C22 # 0 +0x0000C7E3 0x503E # 0 +0x0000C7E4 0x537F # 0 +0x0000C7E5 0x6E05 # 0 +0x0000C7E6 0x64CE # 0 +0x0000C7E7 0x6674 # 0 +0x0000C7E8 0x6C30 # 0 +0x0000C7E9 0x60C5 # 0 +0x0000C7EA 0x9877 # 0 +0x0000C7EB 0x8BF7 # 0 +0x0000C7EC 0x5E86 # 0 +0x0000C7ED 0x743C # 0 +0x0000C7EE 0x7A77 # 0 +0x0000C7EF 0x79CB # 0 +0x0000C7F0 0x4E18 # 0 +0x0000C7F1 0x90B1 # 0 +0x0000C7F2 0x7403 # 0 +0x0000C7F3 0x6C42 # 0 +0x0000C7F4 0x56DA # 0 +0x0000C7F5 0x914B # 0 +0x0000C7F6 0x6CC5 # 0 +0x0000C7F7 0x8D8B # 0 +0x0000C7F8 0x533A # 0 +0x0000C7F9 0x86C6 # 0 +0x0000C7FA 0x66F2 # 0 +0x0000C7FB 0x8EAF # 0 +0x0000C7FC 0x5C48 # 0 +0x0000C7FD 0x9A71 # 0 +0x0000C7FE 0x6E20 # 0 +0x0000C8A1 0x53D6 # 0 +0x0000C8A2 0x5A36 # 0 +0x0000C8A3 0x9F8B # 0 +0x0000C8A4 0x8DA3 # 0 +0x0000C8A5 0x53BB # 0 +0x0000C8A6 0x5708 # 0 +0x0000C8A7 0x98A7 # 0 +0x0000C8A8 0x6743 # 0 +0x0000C8A9 0x919B # 0 +0x0000C8AA 0x6CC9 # 0 +0x0000C8AB 0x5168 # 0 +0x0000C8AC 0x75CA # 0 +0x0000C8AD 0x62F3 # 0 +0x0000C8AE 0x72AC # 0 +0x0000C8AF 0x5238 # 0 +0x0000C8B0 0x529D # 0 +0x0000C8B1 0x7F3A # 0 +0x0000C8B2 0x7094 # 0 +0x0000C8B3 0x7638 # 0 +0x0000C8B4 0x5374 # 0 +0x0000C8B5 0x9E4A # 0 +0x0000C8B6 0x69B7 # 0 +0x0000C8B7 0x786E # 0 +0x0000C8B8 0x96C0 # 0 +0x0000C8B9 0x88D9 # 0 +0x0000C8BA 0x7FA4 # 0 +0x0000C8BB 0x7136 # 0 +0x0000C8BC 0x71C3 # 0 +0x0000C8BD 0x5189 # 0 +0x0000C8BE 0x67D3 # 0 +0x0000C8BF 0x74E4 # 0 +0x0000C8C0 0x58E4 # 0 +0x0000C8C1 0x6518 # 0 +0x0000C8C2 0x56B7 # 0 +0x0000C8C3 0x8BA9 # 0 +0x0000C8C4 0x9976 # 0 +0x0000C8C5 0x6270 # 0 +0x0000C8C6 0x7ED5 # 0 +0x0000C8C7 0x60F9 # 0 +0x0000C8C8 0x70ED # 0 +0x0000C8C9 0x58EC # 0 +0x0000C8CA 0x4EC1 # 0 +0x0000C8CB 0x4EBA # 0 +0x0000C8CC 0x5FCD # 0 +0x0000C8CD 0x97E7 # 0 +0x0000C8CE 0x4EFB # 0 +0x0000C8CF 0x8BA4 # 0 +0x0000C8D0 0x5203 # 0 +0x0000C8D1 0x598A # 0 +0x0000C8D2 0x7EAB # 0 +0x0000C8D3 0x6254 # 0 +0x0000C8D4 0x4ECD # 0 +0x0000C8D5 0x65E5 # 0 +0x0000C8D6 0x620E # 0 +0x0000C8D7 0x8338 # 0 +0x0000C8D8 0x84C9 # 0 +0x0000C8D9 0x8363 # 0 +0x0000C8DA 0x878D # 0 +0x0000C8DB 0x7194 # 0 +0x0000C8DC 0x6EB6 # 0 +0x0000C8DD 0x5BB9 # 0 +0x0000C8DE 0x7ED2 # 0 +0x0000C8DF 0x5197 # 0 +0x0000C8E0 0x63C9 # 0 +0x0000C8E1 0x67D4 # 0 +0x0000C8E2 0x8089 # 0 +0x0000C8E3 0x8339 # 0 +0x0000C8E4 0x8815 # 0 +0x0000C8E5 0x5112 # 0 +0x0000C8E6 0x5B7A # 0 +0x0000C8E7 0x5982 # 0 +0x0000C8E8 0x8FB1 # 0 +0x0000C8E9 0x4E73 # 0 +0x0000C8EA 0x6C5D # 0 +0x0000C8EB 0x5165 # 0 +0x0000C8EC 0x8925 # 0 +0x0000C8ED 0x8F6F # 0 +0x0000C8EE 0x962E # 0 +0x0000C8EF 0x854A # 0 +0x0000C8F0 0x745E # 0 +0x0000C8F1 0x9510 # 0 +0x0000C8F2 0x95F0 # 0 +0x0000C8F3 0x6DA6 # 0 +0x0000C8F4 0x82E5 # 0 +0x0000C8F5 0x5F31 # 0 +0x0000C8F6 0x6492 # 0 +0x0000C8F7 0x6D12 # 0 +0x0000C8F8 0x8428 # 0 +0x0000C8F9 0x816E # 0 +0x0000C8FA 0x9CC3 # 0 +0x0000C8FB 0x585E # 0 +0x0000C8FC 0x8D5B # 0 +0x0000C8FD 0x4E09 # 0 +0x0000C8FE 0x53C1 # 0 +0x0000C9A1 0x4F1E # 0 +0x0000C9A2 0x6563 # 0 +0x0000C9A3 0x6851 # 0 +0x0000C9A4 0x55D3 # 0 +0x0000C9A5 0x4E27 # 0 +0x0000C9A6 0x6414 # 0 +0x0000C9A7 0x9A9A # 0 +0x0000C9A8 0x626B # 0 +0x0000C9A9 0x5AC2 # 0 +0x0000C9AA 0x745F # 0 +0x0000C9AB 0x8272 # 0 +0x0000C9AC 0x6DA9 # 0 +0x0000C9AD 0x68EE # 0 +0x0000C9AE 0x50E7 # 0 +0x0000C9AF 0x838E # 0 +0x0000C9B0 0x7802 # 0 +0x0000C9B1 0x6740 # 0 +0x0000C9B2 0x5239 # 0 +0x0000C9B3 0x6C99 # 0 +0x0000C9B4 0x7EB1 # 0 +0x0000C9B5 0x50BB # 0 +0x0000C9B6 0x5565 # 0 +0x0000C9B7 0x715E # 0 +0x0000C9B8 0x7B5B # 0 +0x0000C9B9 0x6652 # 0 +0x0000C9BA 0x73CA # 0 +0x0000C9BB 0x82EB # 0 +0x0000C9BC 0x6749 # 0 +0x0000C9BD 0x5C71 # 0 +0x0000C9BE 0x5220 # 0 +0x0000C9BF 0x717D # 0 +0x0000C9C0 0x886B # 0 +0x0000C9C1 0x95EA # 0 +0x0000C9C2 0x9655 # 0 +0x0000C9C3 0x64C5 # 0 +0x0000C9C4 0x8D61 # 0 +0x0000C9C5 0x81B3 # 0 +0x0000C9C6 0x5584 # 0 +0x0000C9C7 0x6C55 # 0 +0x0000C9C8 0x6247 # 0 +0x0000C9C9 0x7F2E # 0 +0x0000C9CA 0x5892 # 0 +0x0000C9CB 0x4F24 # 0 +0x0000C9CC 0x5546 # 0 +0x0000C9CD 0x8D4F # 0 +0x0000C9CE 0x664C # 0 +0x0000C9CF 0x4E0A # 0 +0x0000C9D0 0x5C1A # 0 +0x0000C9D1 0x88F3 # 0 +0x0000C9D2 0x68A2 # 0 +0x0000C9D3 0x634E # 0 +0x0000C9D4 0x7A0D # 0 +0x0000C9D5 0x70E7 # 0 +0x0000C9D6 0x828D # 0 +0x0000C9D7 0x52FA # 0 +0x0000C9D8 0x97F6 # 0 +0x0000C9D9 0x5C11 # 0 +0x0000C9DA 0x54E8 # 0 +0x0000C9DB 0x90B5 # 0 +0x0000C9DC 0x7ECD # 0 +0x0000C9DD 0x5962 # 0 +0x0000C9DE 0x8D4A # 0 +0x0000C9DF 0x86C7 # 0 +0x0000C9E0 0x820C # 0 +0x0000C9E1 0x820D # 0 +0x0000C9E2 0x8D66 # 0 +0x0000C9E3 0x6444 # 0 +0x0000C9E4 0x5C04 # 0 +0x0000C9E5 0x6151 # 0 +0x0000C9E6 0x6D89 # 0 +0x0000C9E7 0x793E # 0 +0x0000C9E8 0x8BBE # 0 +0x0000C9E9 0x7837 # 0 +0x0000C9EA 0x7533 # 0 +0x0000C9EB 0x547B # 0 +0x0000C9EC 0x4F38 # 0 +0x0000C9ED 0x8EAB # 0 +0x0000C9EE 0x6DF1 # 0 +0x0000C9EF 0x5A20 # 0 +0x0000C9F0 0x7EC5 # 0 +0x0000C9F1 0x795E # 0 +0x0000C9F2 0x6C88 # 0 +0x0000C9F3 0x5BA1 # 0 +0x0000C9F4 0x5A76 # 0 +0x0000C9F5 0x751A # 0 +0x0000C9F6 0x80BE # 0 +0x0000C9F7 0x614E # 0 +0x0000C9F8 0x6E17 # 0 +0x0000C9F9 0x58F0 # 0 +0x0000C9FA 0x751F # 0 +0x0000C9FB 0x7525 # 0 +0x0000C9FC 0x7272 # 0 +0x0000C9FD 0x5347 # 0 +0x0000C9FE 0x7EF3 # 0 +0x0000CAA1 0x7701 # 0 +0x0000CAA2 0x76DB # 0 +0x0000CAA3 0x5269 # 0 +0x0000CAA4 0x80DC # 0 +0x0000CAA5 0x5723 # 0 +0x0000CAA6 0x5E08 # 0 +0x0000CAA7 0x5931 # 0 +0x0000CAA8 0x72EE # 0 +0x0000CAA9 0x65BD # 0 +0x0000CAAA 0x6E7F # 0 +0x0000CAAB 0x8BD7 # 0 +0x0000CAAC 0x5C38 # 0 +0x0000CAAD 0x8671 # 0 +0x0000CAAE 0x5341 # 0 +0x0000CAAF 0x77F3 # 0 +0x0000CAB0 0x62FE # 0 +0x0000CAB1 0x65F6 # 0 +0x0000CAB2 0x4EC0 # 0 +0x0000CAB3 0x98DF # 0 +0x0000CAB4 0x8680 # 0 +0x0000CAB5 0x5B9E # 0 +0x0000CAB6 0x8BC6 # 0 +0x0000CAB7 0x53F2 # 0 +0x0000CAB8 0x77E2 # 0 +0x0000CAB9 0x4F7F # 0 +0x0000CABA 0x5C4E # 0 +0x0000CABB 0x9A76 # 0 +0x0000CABC 0x59CB # 0 +0x0000CABD 0x5F0F # 0 +0x0000CABE 0x793A # 0 +0x0000CABF 0x58EB # 0 +0x0000CAC0 0x4E16 # 0 +0x0000CAC1 0x67FF # 0 +0x0000CAC2 0x4E8B # 0 +0x0000CAC3 0x62ED # 0 +0x0000CAC4 0x8A93 # 0 +0x0000CAC5 0x901D # 0 +0x0000CAC6 0x52BF # 0 +0x0000CAC7 0x662F # 0 +0x0000CAC8 0x55DC # 0 +0x0000CAC9 0x566C # 0 +0x0000CACA 0x9002 # 0 +0x0000CACB 0x4ED5 # 0 +0x0000CACC 0x4F8D # 0 +0x0000CACD 0x91CA # 0 +0x0000CACE 0x9970 # 0 +0x0000CACF 0x6C0F # 0 +0x0000CAD0 0x5E02 # 0 +0x0000CAD1 0x6043 # 0 +0x0000CAD2 0x5BA4 # 0 +0x0000CAD3 0x89C6 # 0 +0x0000CAD4 0x8BD5 # 0 +0x0000CAD5 0x6536 # 0 +0x0000CAD6 0x624B # 0 +0x0000CAD7 0x9996 # 0 +0x0000CAD8 0x5B88 # 0 +0x0000CAD9 0x5BFF # 0 +0x0000CADA 0x6388 # 0 +0x0000CADB 0x552E # 0 +0x0000CADC 0x53D7 # 0 +0x0000CADD 0x7626 # 0 +0x0000CADE 0x517D # 0 +0x0000CADF 0x852C # 0 +0x0000CAE0 0x67A2 # 0 +0x0000CAE1 0x68B3 # 0 +0x0000CAE2 0x6B8A # 0 +0x0000CAE3 0x6292 # 0 +0x0000CAE4 0x8F93 # 0 +0x0000CAE5 0x53D4 # 0 +0x0000CAE6 0x8212 # 0 +0x0000CAE7 0x6DD1 # 0 +0x0000CAE8 0x758F # 0 +0x0000CAE9 0x4E66 # 0 +0x0000CAEA 0x8D4E # 0 +0x0000CAEB 0x5B70 # 0 +0x0000CAEC 0x719F # 0 +0x0000CAED 0x85AF # 0 +0x0000CAEE 0x6691 # 0 +0x0000CAEF 0x66D9 # 0 +0x0000CAF0 0x7F72 # 0 +0x0000CAF1 0x8700 # 0 +0x0000CAF2 0x9ECD # 0 +0x0000CAF3 0x9F20 # 0 +0x0000CAF4 0x5C5E # 0 +0x0000CAF5 0x672F # 0 +0x0000CAF6 0x8FF0 # 0 +0x0000CAF7 0x6811 # 0 +0x0000CAF8 0x675F # 0 +0x0000CAF9 0x620D # 0 +0x0000CAFA 0x7AD6 # 0 +0x0000CAFB 0x5885 # 0 +0x0000CAFC 0x5EB6 # 0 +0x0000CAFD 0x6570 # 0 +0x0000CAFE 0x6F31 # 0 +0x0000CBA1 0x6055 # 0 +0x0000CBA2 0x5237 # 0 +0x0000CBA3 0x800D # 0 +0x0000CBA4 0x6454 # 0 +0x0000CBA5 0x8870 # 0 +0x0000CBA6 0x7529 # 0 +0x0000CBA7 0x5E05 # 0 +0x0000CBA8 0x6813 # 0 +0x0000CBA9 0x62F4 # 0 +0x0000CBAA 0x971C # 0 +0x0000CBAB 0x53CC # 0 +0x0000CBAC 0x723D # 0 +0x0000CBAD 0x8C01 # 0 +0x0000CBAE 0x6C34 # 0 +0x0000CBAF 0x7761 # 0 +0x0000CBB0 0x7A0E # 0 +0x0000CBB1 0x542E # 0 +0x0000CBB2 0x77AC # 0 +0x0000CBB3 0x987A # 0 +0x0000CBB4 0x821C # 0 +0x0000CBB5 0x8BF4 # 0 +0x0000CBB6 0x7855 # 0 +0x0000CBB7 0x6714 # 0 +0x0000CBB8 0x70C1 # 0 +0x0000CBB9 0x65AF # 0 +0x0000CBBA 0x6495 # 0 +0x0000CBBB 0x5636 # 0 +0x0000CBBC 0x601D # 0 +0x0000CBBD 0x79C1 # 0 +0x0000CBBE 0x53F8 # 0 +0x0000CBBF 0x4E1D # 0 +0x0000CBC0 0x6B7B # 0 +0x0000CBC1 0x8086 # 0 +0x0000CBC2 0x5BFA # 0 +0x0000CBC3 0x55E3 # 0 +0x0000CBC4 0x56DB # 0 +0x0000CBC5 0x4F3A # 0 +0x0000CBC6 0x4F3C # 0 +0x0000CBC7 0x9972 # 0 +0x0000CBC8 0x5DF3 # 0 +0x0000CBC9 0x677E # 0 +0x0000CBCA 0x8038 # 0 +0x0000CBCB 0x6002 # 0 +0x0000CBCC 0x9882 # 0 +0x0000CBCD 0x9001 # 0 +0x0000CBCE 0x5B8B # 0 +0x0000CBCF 0x8BBC # 0 +0x0000CBD0 0x8BF5 # 0 +0x0000CBD1 0x641C # 0 +0x0000CBD2 0x8258 # 0 +0x0000CBD3 0x64DE # 0 +0x0000CBD4 0x55FD # 0 +0x0000CBD5 0x82CF # 0 +0x0000CBD6 0x9165 # 0 +0x0000CBD7 0x4FD7 # 0 +0x0000CBD8 0x7D20 # 0 +0x0000CBD9 0x901F # 0 +0x0000CBDA 0x7C9F # 0 +0x0000CBDB 0x50F3 # 0 +0x0000CBDC 0x5851 # 0 +0x0000CBDD 0x6EAF # 0 +0x0000CBDE 0x5BBF # 0 +0x0000CBDF 0x8BC9 # 0 +0x0000CBE0 0x8083 # 0 +0x0000CBE1 0x9178 # 0 +0x0000CBE2 0x849C # 0 +0x0000CBE3 0x7B97 # 0 +0x0000CBE4 0x867D # 0 +0x0000CBE5 0x968B # 0 +0x0000CBE6 0x968F # 0 +0x0000CBE7 0x7EE5 # 0 +0x0000CBE8 0x9AD3 # 0 +0x0000CBE9 0x788E # 0 +0x0000CBEA 0x5C81 # 0 +0x0000CBEB 0x7A57 # 0 +0x0000CBEC 0x9042 # 0 +0x0000CBED 0x96A7 # 0 +0x0000CBEE 0x795F # 0 +0x0000CBEF 0x5B59 # 0 +0x0000CBF0 0x635F # 0 +0x0000CBF1 0x7B0B # 0 +0x0000CBF2 0x84D1 # 0 +0x0000CBF3 0x68AD # 0 +0x0000CBF4 0x5506 # 0 +0x0000CBF5 0x7F29 # 0 +0x0000CBF6 0x7410 # 0 +0x0000CBF7 0x7D22 # 0 +0x0000CBF8 0x9501 # 0 +0x0000CBF9 0x6240 # 0 +0x0000CBFA 0x584C # 0 +0x0000CBFB 0x4ED6 # 0 +0x0000CBFC 0x5B83 # 0 +0x0000CBFD 0x5979 # 0 +0x0000CBFE 0x5854 # 0 +0x0000CCA1 0x736D # 0 +0x0000CCA2 0x631E # 0 +0x0000CCA3 0x8E4B # 0 +0x0000CCA4 0x8E0F # 0 +0x0000CCA5 0x80CE # 0 +0x0000CCA6 0x82D4 # 0 +0x0000CCA7 0x62AC # 0 +0x0000CCA8 0x53F0 # 0 +0x0000CCA9 0x6CF0 # 0 +0x0000CCAA 0x915E # 0 +0x0000CCAB 0x592A # 0 +0x0000CCAC 0x6001 # 0 +0x0000CCAD 0x6C70 # 0 +0x0000CCAE 0x574D # 0 +0x0000CCAF 0x644A # 0 +0x0000CCB0 0x8D2A # 0 +0x0000CCB1 0x762B # 0 +0x0000CCB2 0x6EE9 # 0 +0x0000CCB3 0x575B # 0 +0x0000CCB4 0x6A80 # 0 +0x0000CCB5 0x75F0 # 0 +0x0000CCB6 0x6F6D # 0 +0x0000CCB7 0x8C2D # 0 +0x0000CCB8 0x8C08 # 0 +0x0000CCB9 0x5766 # 0 +0x0000CCBA 0x6BEF # 0 +0x0000CCBB 0x8892 # 0 +0x0000CCBC 0x78B3 # 0 +0x0000CCBD 0x63A2 # 0 +0x0000CCBE 0x53F9 # 0 +0x0000CCBF 0x70AD # 0 +0x0000CCC0 0x6C64 # 0 +0x0000CCC1 0x5858 # 0 +0x0000CCC2 0x642A # 0 +0x0000CCC3 0x5802 # 0 +0x0000CCC4 0x68E0 # 0 +0x0000CCC5 0x819B # 0 +0x0000CCC6 0x5510 # 0 +0x0000CCC7 0x7CD6 # 0 +0x0000CCC8 0x5018 # 0 +0x0000CCC9 0x8EBA # 0 +0x0000CCCA 0x6DCC # 0 +0x0000CCCB 0x8D9F # 0 +0x0000CCCC 0x70EB # 0 +0x0000CCCD 0x638F # 0 +0x0000CCCE 0x6D9B # 0 +0x0000CCCF 0x6ED4 # 0 +0x0000CCD0 0x7EE6 # 0 +0x0000CCD1 0x8404 # 0 +0x0000CCD2 0x6843 # 0 +0x0000CCD3 0x9003 # 0 +0x0000CCD4 0x6DD8 # 0 +0x0000CCD5 0x9676 # 0 +0x0000CCD6 0x8BA8 # 0 +0x0000CCD7 0x5957 # 0 +0x0000CCD8 0x7279 # 0 +0x0000CCD9 0x85E4 # 0 +0x0000CCDA 0x817E # 0 +0x0000CCDB 0x75BC # 0 +0x0000CCDC 0x8A8A # 0 +0x0000CCDD 0x68AF # 0 +0x0000CCDE 0x5254 # 0 +0x0000CCDF 0x8E22 # 0 +0x0000CCE0 0x9511 # 0 +0x0000CCE1 0x63D0 # 0 +0x0000CCE2 0x9898 # 0 +0x0000CCE3 0x8E44 # 0 +0x0000CCE4 0x557C # 0 +0x0000CCE5 0x4F53 # 0 +0x0000CCE6 0x66FF # 0 +0x0000CCE7 0x568F # 0 +0x0000CCE8 0x60D5 # 0 +0x0000CCE9 0x6D95 # 0 +0x0000CCEA 0x5243 # 0 +0x0000CCEB 0x5C49 # 0 +0x0000CCEC 0x5929 # 0 +0x0000CCED 0x6DFB # 0 +0x0000CCEE 0x586B # 0 +0x0000CCEF 0x7530 # 0 +0x0000CCF0 0x751C # 0 +0x0000CCF1 0x606C # 0 +0x0000CCF2 0x8214 # 0 +0x0000CCF3 0x8146 # 0 +0x0000CCF4 0x6311 # 0 +0x0000CCF5 0x6761 # 0 +0x0000CCF6 0x8FE2 # 0 +0x0000CCF7 0x773A # 0 +0x0000CCF8 0x8DF3 # 0 +0x0000CCF9 0x8D34 # 0 +0x0000CCFA 0x94C1 # 0 +0x0000CCFB 0x5E16 # 0 +0x0000CCFC 0x5385 # 0 +0x0000CCFD 0x542C # 0 +0x0000CCFE 0x70C3 # 0 +0x0000CDA1 0x6C40 # 0 +0x0000CDA2 0x5EF7 # 0 +0x0000CDA3 0x505C # 0 +0x0000CDA4 0x4EAD # 0 +0x0000CDA5 0x5EAD # 0 +0x0000CDA6 0x633A # 0 +0x0000CDA7 0x8247 # 0 +0x0000CDA8 0x901A # 0 +0x0000CDA9 0x6850 # 0 +0x0000CDAA 0x916E # 0 +0x0000CDAB 0x77B3 # 0 +0x0000CDAC 0x540C # 0 +0x0000CDAD 0x94DC # 0 +0x0000CDAE 0x5F64 # 0 +0x0000CDAF 0x7AE5 # 0 +0x0000CDB0 0x6876 # 0 +0x0000CDB1 0x6345 # 0 +0x0000CDB2 0x7B52 # 0 +0x0000CDB3 0x7EDF # 0 +0x0000CDB4 0x75DB # 0 +0x0000CDB5 0x5077 # 0 +0x0000CDB6 0x6295 # 0 +0x0000CDB7 0x5934 # 0 +0x0000CDB8 0x900F # 0 +0x0000CDB9 0x51F8 # 0 +0x0000CDBA 0x79C3 # 0 +0x0000CDBB 0x7A81 # 0 +0x0000CDBC 0x56FE # 0 +0x0000CDBD 0x5F92 # 0 +0x0000CDBE 0x9014 # 0 +0x0000CDBF 0x6D82 # 0 +0x0000CDC0 0x5C60 # 0 +0x0000CDC1 0x571F # 0 +0x0000CDC2 0x5410 # 0 +0x0000CDC3 0x5154 # 0 +0x0000CDC4 0x6E4D # 0 +0x0000CDC5 0x56E2 # 0 +0x0000CDC6 0x63A8 # 0 +0x0000CDC7 0x9893 # 0 +0x0000CDC8 0x817F # 0 +0x0000CDC9 0x8715 # 0 +0x0000CDCA 0x892A # 0 +0x0000CDCB 0x9000 # 0 +0x0000CDCC 0x541E # 0 +0x0000CDCD 0x5C6F # 0 +0x0000CDCE 0x81C0 # 0 +0x0000CDCF 0x62D6 # 0 +0x0000CDD0 0x6258 # 0 +0x0000CDD1 0x8131 # 0 +0x0000CDD2 0x9E35 # 0 +0x0000CDD3 0x9640 # 0 +0x0000CDD4 0x9A6E # 0 +0x0000CDD5 0x9A7C # 0 +0x0000CDD6 0x692D # 0 +0x0000CDD7 0x59A5 # 0 +0x0000CDD8 0x62D3 # 0 +0x0000CDD9 0x553E # 0 +0x0000CDDA 0x6316 # 0 +0x0000CDDB 0x54C7 # 0 +0x0000CDDC 0x86D9 # 0 +0x0000CDDD 0x6D3C # 0 +0x0000CDDE 0x5A03 # 0 +0x0000CDDF 0x74E6 # 0 +0x0000CDE0 0x889C # 0 +0x0000CDE1 0x6B6A # 0 +0x0000CDE2 0x5916 # 0 +0x0000CDE3 0x8C4C # 0 +0x0000CDE4 0x5F2F # 0 +0x0000CDE5 0x6E7E # 0 +0x0000CDE6 0x73A9 # 0 +0x0000CDE7 0x987D # 0 +0x0000CDE8 0x4E38 # 0 +0x0000CDE9 0x70F7 # 0 +0x0000CDEA 0x5B8C # 0 +0x0000CDEB 0x7897 # 0 +0x0000CDEC 0x633D # 0 +0x0000CDED 0x665A # 0 +0x0000CDEE 0x7696 # 0 +0x0000CDEF 0x60CB # 0 +0x0000CDF0 0x5B9B # 0 +0x0000CDF1 0x5A49 # 0 +0x0000CDF2 0x4E07 # 0 +0x0000CDF3 0x8155 # 0 +0x0000CDF4 0x6C6A # 0 +0x0000CDF5 0x738B # 0 +0x0000CDF6 0x4EA1 # 0 +0x0000CDF7 0x6789 # 0 +0x0000CDF8 0x7F51 # 0 +0x0000CDF9 0x5F80 # 0 +0x0000CDFA 0x65FA # 0 +0x0000CDFB 0x671B # 0 +0x0000CDFC 0x5FD8 # 0 +0x0000CDFD 0x5984 # 0 +0x0000CDFE 0x5A01 # 0 +0x0000CEA1 0x5DCD # 0 +0x0000CEA2 0x5FAE # 0 +0x0000CEA3 0x5371 # 0 +0x0000CEA4 0x97E6 # 0 +0x0000CEA5 0x8FDD # 0 +0x0000CEA6 0x6845 # 0 +0x0000CEA7 0x56F4 # 0 +0x0000CEA8 0x552F # 0 +0x0000CEA9 0x60DF # 0 +0x0000CEAA 0x4E3A # 0 +0x0000CEAB 0x6F4D # 0 +0x0000CEAC 0x7EF4 # 0 +0x0000CEAD 0x82C7 # 0 +0x0000CEAE 0x840E # 0 +0x0000CEAF 0x59D4 # 0 +0x0000CEB0 0x4F1F # 0 +0x0000CEB1 0x4F2A # 0 +0x0000CEB2 0x5C3E # 0 +0x0000CEB3 0x7EAC # 0 +0x0000CEB4 0x672A # 0 +0x0000CEB5 0x851A # 0 +0x0000CEB6 0x5473 # 0 +0x0000CEB7 0x754F # 0 +0x0000CEB8 0x80C3 # 0 +0x0000CEB9 0x5582 # 0 +0x0000CEBA 0x9B4F # 0 +0x0000CEBB 0x4F4D # 0 +0x0000CEBC 0x6E2D # 0 +0x0000CEBD 0x8C13 # 0 +0x0000CEBE 0x5C09 # 0 +0x0000CEBF 0x6170 # 0 +0x0000CEC0 0x536B # 0 +0x0000CEC1 0x761F # 0 +0x0000CEC2 0x6E29 # 0 +0x0000CEC3 0x868A # 0 +0x0000CEC4 0x6587 # 0 +0x0000CEC5 0x95FB # 0 +0x0000CEC6 0x7EB9 # 0 +0x0000CEC7 0x543B # 0 +0x0000CEC8 0x7A33 # 0 +0x0000CEC9 0x7D0A # 0 +0x0000CECA 0x95EE # 0 +0x0000CECB 0x55E1 # 0 +0x0000CECC 0x7FC1 # 0 +0x0000CECD 0x74EE # 0 +0x0000CECE 0x631D # 0 +0x0000CECF 0x8717 # 0 +0x0000CED0 0x6DA1 # 0 +0x0000CED1 0x7A9D # 0 +0x0000CED2 0x6211 # 0 +0x0000CED3 0x65A1 # 0 +0x0000CED4 0x5367 # 0 +0x0000CED5 0x63E1 # 0 +0x0000CED6 0x6C83 # 0 +0x0000CED7 0x5DEB # 0 +0x0000CED8 0x545C # 0 +0x0000CED9 0x94A8 # 0 +0x0000CEDA 0x4E4C # 0 +0x0000CEDB 0x6C61 # 0 +0x0000CEDC 0x8BEC # 0 +0x0000CEDD 0x5C4B # 0 +0x0000CEDE 0x65E0 # 0 +0x0000CEDF 0x829C # 0 +0x0000CEE0 0x68A7 # 0 +0x0000CEE1 0x543E # 0 +0x0000CEE2 0x5434 # 0 +0x0000CEE3 0x6BCB # 0 +0x0000CEE4 0x6B66 # 0 +0x0000CEE5 0x4E94 # 0 +0x0000CEE6 0x6342 # 0 +0x0000CEE7 0x5348 # 0 +0x0000CEE8 0x821E # 0 +0x0000CEE9 0x4F0D # 0 +0x0000CEEA 0x4FAE # 0 +0x0000CEEB 0x575E # 0 +0x0000CEEC 0x620A # 0 +0x0000CEED 0x96FE # 0 +0x0000CEEE 0x6664 # 0 +0x0000CEEF 0x7269 # 0 +0x0000CEF0 0x52FF # 0 +0x0000CEF1 0x52A1 # 0 +0x0000CEF2 0x609F # 0 +0x0000CEF3 0x8BEF # 0 +0x0000CEF4 0x6614 # 0 +0x0000CEF5 0x7199 # 0 +0x0000CEF6 0x6790 # 0 +0x0000CEF7 0x897F # 0 +0x0000CEF8 0x7852 # 0 +0x0000CEF9 0x77FD # 0 +0x0000CEFA 0x6670 # 0 +0x0000CEFB 0x563B # 0 +0x0000CEFC 0x5438 # 0 +0x0000CEFD 0x9521 # 0 +0x0000CEFE 0x727A # 0 +0x0000CFA1 0x7A00 # 0 +0x0000CFA2 0x606F # 0 +0x0000CFA3 0x5E0C # 0 +0x0000CFA4 0x6089 # 0 +0x0000CFA5 0x819D # 0 +0x0000CFA6 0x5915 # 0 +0x0000CFA7 0x60DC # 0 +0x0000CFA8 0x7184 # 0 +0x0000CFA9 0x70EF # 0 +0x0000CFAA 0x6EAA # 0 +0x0000CFAB 0x6C50 # 0 +0x0000CFAC 0x7280 # 0 +0x0000CFAD 0x6A84 # 0 +0x0000CFAE 0x88AD # 0 +0x0000CFAF 0x5E2D # 0 +0x0000CFB0 0x4E60 # 0 +0x0000CFB1 0x5AB3 # 0 +0x0000CFB2 0x559C # 0 +0x0000CFB3 0x94E3 # 0 +0x0000CFB4 0x6D17 # 0 +0x0000CFB5 0x7CFB # 0 +0x0000CFB6 0x9699 # 0 +0x0000CFB7 0x620F # 0 +0x0000CFB8 0x7EC6 # 0 +0x0000CFB9 0x778E # 0 +0x0000CFBA 0x867E # 0 +0x0000CFBB 0x5323 # 0 +0x0000CFBC 0x971E # 0 +0x0000CFBD 0x8F96 # 0 +0x0000CFBE 0x6687 # 0 +0x0000CFBF 0x5CE1 # 0 +0x0000CFC0 0x4FA0 # 0 +0x0000CFC1 0x72ED # 0 +0x0000CFC2 0x4E0B # 0 +0x0000CFC3 0x53A6 # 0 +0x0000CFC4 0x590F # 0 +0x0000CFC5 0x5413 # 0 +0x0000CFC6 0x6380 # 0 +0x0000CFC7 0x9528 # 0 +0x0000CFC8 0x5148 # 0 +0x0000CFC9 0x4ED9 # 0 +0x0000CFCA 0x9C9C # 0 +0x0000CFCB 0x7EA4 # 0 +0x0000CFCC 0x54B8 # 0 +0x0000CFCD 0x8D24 # 0 +0x0000CFCE 0x8854 # 0 +0x0000CFCF 0x8237 # 0 +0x0000CFD0 0x95F2 # 0 +0x0000CFD1 0x6D8E # 0 +0x0000CFD2 0x5F26 # 0 +0x0000CFD3 0x5ACC # 0 +0x0000CFD4 0x663E # 0 +0x0000CFD5 0x9669 # 0 +0x0000CFD6 0x73B0 # 0 +0x0000CFD7 0x732E # 0 +0x0000CFD8 0x53BF # 0 +0x0000CFD9 0x817A # 0 +0x0000CFDA 0x9985 # 0 +0x0000CFDB 0x7FA1 # 0 +0x0000CFDC 0x5BAA # 0 +0x0000CFDD 0x9677 # 0 +0x0000CFDE 0x9650 # 0 +0x0000CFDF 0x7EBF # 0 +0x0000CFE0 0x76F8 # 0 +0x0000CFE1 0x53A2 # 0 +0x0000CFE2 0x9576 # 0 +0x0000CFE3 0x9999 # 0 +0x0000CFE4 0x7BB1 # 0 +0x0000CFE5 0x8944 # 0 +0x0000CFE6 0x6E58 # 0 +0x0000CFE7 0x4E61 # 0 +0x0000CFE8 0x7FD4 # 0 +0x0000CFE9 0x7965 # 0 +0x0000CFEA 0x8BE6 # 0 +0x0000CFEB 0x60F3 # 0 +0x0000CFEC 0x54CD # 0 +0x0000CFED 0x4EAB # 0 +0x0000CFEE 0x9879 # 0 +0x0000CFEF 0x5DF7 # 0 +0x0000CFF0 0x6A61 # 0 +0x0000CFF1 0x50CF # 0 +0x0000CFF2 0x5411 # 0 +0x0000CFF3 0x8C61 # 0 +0x0000CFF4 0x8427 # 0 +0x0000CFF5 0x785D # 0 +0x0000CFF6 0x9704 # 0 +0x0000CFF7 0x524A # 0 +0x0000CFF8 0x54EE # 0 +0x0000CFF9 0x56A3 # 0 +0x0000CFFA 0x9500 # 0 +0x0000CFFB 0x6D88 # 0 +0x0000CFFC 0x5BB5 # 0 +0x0000CFFD 0x6DC6 # 0 +0x0000CFFE 0x6653 # 0 +0x0000D0A1 0x5C0F # 0 +0x0000D0A2 0x5B5D # 0 +0x0000D0A3 0x6821 # 0 +0x0000D0A4 0x8096 # 0 +0x0000D0A5 0x5578 # 0 +0x0000D0A6 0x7B11 # 0 +0x0000D0A7 0x6548 # 0 +0x0000D0A8 0x6954 # 0 +0x0000D0A9 0x4E9B # 0 +0x0000D0AA 0x6B47 # 0 +0x0000D0AB 0x874E # 0 +0x0000D0AC 0x978B # 0 +0x0000D0AD 0x534F # 0 +0x0000D0AE 0x631F # 0 +0x0000D0AF 0x643A # 0 +0x0000D0B0 0x90AA # 0 +0x0000D0B1 0x659C # 0 +0x0000D0B2 0x80C1 # 0 +0x0000D0B3 0x8C10 # 0 +0x0000D0B4 0x5199 # 0 +0x0000D0B5 0x68B0 # 0 +0x0000D0B6 0x5378 # 0 +0x0000D0B7 0x87F9 # 0 +0x0000D0B8 0x61C8 # 0 +0x0000D0B9 0x6CC4 # 0 +0x0000D0BA 0x6CFB # 0 +0x0000D0BB 0x8C22 # 0 +0x0000D0BC 0x5C51 # 0 +0x0000D0BD 0x85AA # 0 +0x0000D0BE 0x82AF # 0 +0x0000D0BF 0x950C # 0 +0x0000D0C0 0x6B23 # 0 +0x0000D0C1 0x8F9B # 0 +0x0000D0C2 0x65B0 # 0 +0x0000D0C3 0x5FFB # 0 +0x0000D0C4 0x5FC3 # 0 +0x0000D0C5 0x4FE1 # 0 +0x0000D0C6 0x8845 # 0 +0x0000D0C7 0x661F # 0 +0x0000D0C8 0x8165 # 0 +0x0000D0C9 0x7329 # 0 +0x0000D0CA 0x60FA # 0 +0x0000D0CB 0x5174 # 0 +0x0000D0CC 0x5211 # 0 +0x0000D0CD 0x578B # 0 +0x0000D0CE 0x5F62 # 0 +0x0000D0CF 0x90A2 # 0 +0x0000D0D0 0x884C # 0 +0x0000D0D1 0x9192 # 0 +0x0000D0D2 0x5E78 # 0 +0x0000D0D3 0x674F # 0 +0x0000D0D4 0x6027 # 0 +0x0000D0D5 0x59D3 # 0 +0x0000D0D6 0x5144 # 0 +0x0000D0D7 0x51F6 # 0 +0x0000D0D8 0x80F8 # 0 +0x0000D0D9 0x5308 # 0 +0x0000D0DA 0x6C79 # 0 +0x0000D0DB 0x96C4 # 0 +0x0000D0DC 0x718A # 0 +0x0000D0DD 0x4F11 # 0 +0x0000D0DE 0x4FEE # 0 +0x0000D0DF 0x7F9E # 0 +0x0000D0E0 0x673D # 0 +0x0000D0E1 0x55C5 # 0 +0x0000D0E2 0x9508 # 0 +0x0000D0E3 0x79C0 # 0 +0x0000D0E4 0x8896 # 0 +0x0000D0E5 0x7EE3 # 0 +0x0000D0E6 0x589F # 0 +0x0000D0E7 0x620C # 0 +0x0000D0E8 0x9700 # 0 +0x0000D0E9 0x865A # 0 +0x0000D0EA 0x5618 # 0 +0x0000D0EB 0x987B # 0 +0x0000D0EC 0x5F90 # 0 +0x0000D0ED 0x8BB8 # 0 +0x0000D0EE 0x84C4 # 0 +0x0000D0EF 0x9157 # 0 +0x0000D0F0 0x53D9 # 0 +0x0000D0F1 0x65ED # 0 +0x0000D0F2 0x5E8F # 0 +0x0000D0F3 0x755C # 0 +0x0000D0F4 0x6064 # 0 +0x0000D0F5 0x7D6E # 0 +0x0000D0F6 0x5A7F # 0 +0x0000D0F7 0x7EEA # 0 +0x0000D0F8 0x7EED # 0 +0x0000D0F9 0x8F69 # 0 +0x0000D0FA 0x55A7 # 0 +0x0000D0FB 0x5BA3 # 0 +0x0000D0FC 0x60AC # 0 +0x0000D0FD 0x65CB # 0 +0x0000D0FE 0x7384 # 0 +0x0000D1A1 0x9009 # 0 +0x0000D1A2 0x7663 # 0 +0x0000D1A3 0x7729 # 0 +0x0000D1A4 0x7EDA # 0 +0x0000D1A5 0x9774 # 0 +0x0000D1A6 0x859B # 0 +0x0000D1A7 0x5B66 # 0 +0x0000D1A8 0x7A74 # 0 +0x0000D1A9 0x96EA # 0 +0x0000D1AA 0x8840 # 0 +0x0000D1AB 0x52CB # 0 +0x0000D1AC 0x718F # 0 +0x0000D1AD 0x5FAA # 0 +0x0000D1AE 0x65EC # 0 +0x0000D1AF 0x8BE2 # 0 +0x0000D1B0 0x5BFB # 0 +0x0000D1B1 0x9A6F # 0 +0x0000D1B2 0x5DE1 # 0 +0x0000D1B3 0x6B89 # 0 +0x0000D1B4 0x6C5B # 0 +0x0000D1B5 0x8BAD # 0 +0x0000D1B6 0x8BAF # 0 +0x0000D1B7 0x900A # 0 +0x0000D1B8 0x8FC5 # 0 +0x0000D1B9 0x538B # 0 +0x0000D1BA 0x62BC # 0 +0x0000D1BB 0x9E26 # 0 +0x0000D1BC 0x9E2D # 0 +0x0000D1BD 0x5440 # 0 +0x0000D1BE 0x4E2B # 0 +0x0000D1BF 0x82BD # 0 +0x0000D1C0 0x7259 # 0 +0x0000D1C1 0x869C # 0 +0x0000D1C2 0x5D16 # 0 +0x0000D1C3 0x8859 # 0 +0x0000D1C4 0x6DAF # 0 +0x0000D1C5 0x96C5 # 0 +0x0000D1C6 0x54D1 # 0 +0x0000D1C7 0x4E9A # 0 +0x0000D1C8 0x8BB6 # 0 +0x0000D1C9 0x7109 # 0 +0x0000D1CA 0x54BD # 0 +0x0000D1CB 0x9609 # 0 +0x0000D1CC 0x70DF # 0 +0x0000D1CD 0x6DF9 # 0 +0x0000D1CE 0x76D0 # 0 +0x0000D1CF 0x4E25 # 0 +0x0000D1D0 0x7814 # 0 +0x0000D1D1 0x8712 # 0 +0x0000D1D2 0x5CA9 # 0 +0x0000D1D3 0x5EF6 # 0 +0x0000D1D4 0x8A00 # 0 +0x0000D1D5 0x989C # 0 +0x0000D1D6 0x960E # 0 +0x0000D1D7 0x708E # 0 +0x0000D1D8 0x6CBF # 0 +0x0000D1D9 0x5944 # 0 +0x0000D1DA 0x63A9 # 0 +0x0000D1DB 0x773C # 0 +0x0000D1DC 0x884D # 0 +0x0000D1DD 0x6F14 # 0 +0x0000D1DE 0x8273 # 0 +0x0000D1DF 0x5830 # 0 +0x0000D1E0 0x71D5 # 0 +0x0000D1E1 0x538C # 0 +0x0000D1E2 0x781A # 0 +0x0000D1E3 0x96C1 # 0 +0x0000D1E4 0x5501 # 0 +0x0000D1E5 0x5F66 # 0 +0x0000D1E6 0x7130 # 0 +0x0000D1E7 0x5BB4 # 0 +0x0000D1E8 0x8C1A # 0 +0x0000D1E9 0x9A8C # 0 +0x0000D1EA 0x6B83 # 0 +0x0000D1EB 0x592E # 0 +0x0000D1EC 0x9E2F # 0 +0x0000D1ED 0x79E7 # 0 +0x0000D1EE 0x6768 # 0 +0x0000D1EF 0x626C # 0 +0x0000D1F0 0x4F6F # 0 +0x0000D1F1 0x75A1 # 0 +0x0000D1F2 0x7F8A # 0 +0x0000D1F3 0x6D0B # 0 +0x0000D1F4 0x9633 # 0 +0x0000D1F5 0x6C27 # 0 +0x0000D1F6 0x4EF0 # 0 +0x0000D1F7 0x75D2 # 0 +0x0000D1F8 0x517B # 0 +0x0000D1F9 0x6837 # 0 +0x0000D1FA 0x6F3E # 0 +0x0000D1FB 0x9080 # 0 +0x0000D1FC 0x8170 # 0 +0x0000D1FD 0x5996 # 0 +0x0000D1FE 0x7476 # 0 +0x0000D2A1 0x6447 # 0 +0x0000D2A2 0x5C27 # 0 +0x0000D2A3 0x9065 # 0 +0x0000D2A4 0x7A91 # 0 +0x0000D2A5 0x8C23 # 0 +0x0000D2A6 0x59DA # 0 +0x0000D2A7 0x54AC # 0 +0x0000D2A8 0x8200 # 0 +0x0000D2A9 0x836F # 0 +0x0000D2AA 0x8981 # 0 +0x0000D2AB 0x8000 # 0 +0x0000D2AC 0x6930 # 0 +0x0000D2AD 0x564E # 0 +0x0000D2AE 0x8036 # 0 +0x0000D2AF 0x7237 # 0 +0x0000D2B0 0x91CE # 0 +0x0000D2B1 0x51B6 # 0 +0x0000D2B2 0x4E5F # 0 +0x0000D2B3 0x9875 # 0 +0x0000D2B4 0x6396 # 0 +0x0000D2B5 0x4E1A # 0 +0x0000D2B6 0x53F6 # 0 +0x0000D2B7 0x66F3 # 0 +0x0000D2B8 0x814B # 0 +0x0000D2B9 0x591C # 0 +0x0000D2BA 0x6DB2 # 0 +0x0000D2BB 0x4E00 # 0 +0x0000D2BC 0x58F9 # 0 +0x0000D2BD 0x533B # 0 +0x0000D2BE 0x63D6 # 0 +0x0000D2BF 0x94F1 # 0 +0x0000D2C0 0x4F9D # 0 +0x0000D2C1 0x4F0A # 0 +0x0000D2C2 0x8863 # 0 +0x0000D2C3 0x9890 # 0 +0x0000D2C4 0x5937 # 0 +0x0000D2C5 0x9057 # 0 +0x0000D2C6 0x79FB # 0 +0x0000D2C7 0x4EEA # 0 +0x0000D2C8 0x80F0 # 0 +0x0000D2C9 0x7591 # 0 +0x0000D2CA 0x6C82 # 0 +0x0000D2CB 0x5B9C # 0 +0x0000D2CC 0x59E8 # 0 +0x0000D2CD 0x5F5D # 0 +0x0000D2CE 0x6905 # 0 +0x0000D2CF 0x8681 # 0 +0x0000D2D0 0x501A # 0 +0x0000D2D1 0x5DF2 # 0 +0x0000D2D2 0x4E59 # 0 +0x0000D2D3 0x77E3 # 0 +0x0000D2D4 0x4EE5 # 0 +0x0000D2D5 0x827A # 0 +0x0000D2D6 0x6291 # 0 +0x0000D2D7 0x6613 # 0 +0x0000D2D8 0x9091 # 0 +0x0000D2D9 0x5C79 # 0 +0x0000D2DA 0x4EBF # 0 +0x0000D2DB 0x5F79 # 0 +0x0000D2DC 0x81C6 # 0 +0x0000D2DD 0x9038 # 0 +0x0000D2DE 0x8084 # 0 +0x0000D2DF 0x75AB # 0 +0x0000D2E0 0x4EA6 # 0 +0x0000D2E1 0x88D4 # 0 +0x0000D2E2 0x610F # 0 +0x0000D2E3 0x6BC5 # 0 +0x0000D2E4 0x5FC6 # 0 +0x0000D2E5 0x4E49 # 0 +0x0000D2E6 0x76CA # 0 +0x0000D2E7 0x6EA2 # 0 +0x0000D2E8 0x8BE3 # 0 +0x0000D2E9 0x8BAE # 0 +0x0000D2EA 0x8C0A # 0 +0x0000D2EB 0x8BD1 # 0 +0x0000D2EC 0x5F02 # 0 +0x0000D2ED 0x7FFC # 0 +0x0000D2EE 0x7FCC # 0 +0x0000D2EF 0x7ECE # 0 +0x0000D2F0 0x8335 # 0 +0x0000D2F1 0x836B # 0 +0x0000D2F2 0x56E0 # 0 +0x0000D2F3 0x6BB7 # 0 +0x0000D2F4 0x97F3 # 0 +0x0000D2F5 0x9634 # 0 +0x0000D2F6 0x59FB # 0 +0x0000D2F7 0x541F # 0 +0x0000D2F8 0x94F6 # 0 +0x0000D2F9 0x6DEB # 0 +0x0000D2FA 0x5BC5 # 0 +0x0000D2FB 0x996E # 0 +0x0000D2FC 0x5C39 # 0 +0x0000D2FD 0x5F15 # 0 +0x0000D2FE 0x9690 # 0 +0x0000D3A1 0x5370 # 0 +0x0000D3A2 0x82F1 # 0 +0x0000D3A3 0x6A31 # 0 +0x0000D3A4 0x5A74 # 0 +0x0000D3A5 0x9E70 # 0 +0x0000D3A6 0x5E94 # 0 +0x0000D3A7 0x7F28 # 0 +0x0000D3A8 0x83B9 # 0 +0x0000D3A9 0x8424 # 0 +0x0000D3AA 0x8425 # 0 +0x0000D3AB 0x8367 # 0 +0x0000D3AC 0x8747 # 0 +0x0000D3AD 0x8FCE # 0 +0x0000D3AE 0x8D62 # 0 +0x0000D3AF 0x76C8 # 0 +0x0000D3B0 0x5F71 # 0 +0x0000D3B1 0x9896 # 0 +0x0000D3B2 0x786C # 0 +0x0000D3B3 0x6620 # 0 +0x0000D3B4 0x54DF # 0 +0x0000D3B5 0x62E5 # 0 +0x0000D3B6 0x4F63 # 0 +0x0000D3B7 0x81C3 # 0 +0x0000D3B8 0x75C8 # 0 +0x0000D3B9 0x5EB8 # 0 +0x0000D3BA 0x96CD # 0 +0x0000D3BB 0x8E0A # 0 +0x0000D3BC 0x86F9 # 0 +0x0000D3BD 0x548F # 0 +0x0000D3BE 0x6CF3 # 0 +0x0000D3BF 0x6D8C # 0 +0x0000D3C0 0x6C38 # 0 +0x0000D3C1 0x607F # 0 +0x0000D3C2 0x52C7 # 0 +0x0000D3C3 0x7528 # 0 +0x0000D3C4 0x5E7D # 0 +0x0000D3C5 0x4F18 # 0 +0x0000D3C6 0x60A0 # 0 +0x0000D3C7 0x5FE7 # 0 +0x0000D3C8 0x5C24 # 0 +0x0000D3C9 0x7531 # 0 +0x0000D3CA 0x90AE # 0 +0x0000D3CB 0x94C0 # 0 +0x0000D3CC 0x72B9 # 0 +0x0000D3CD 0x6CB9 # 0 +0x0000D3CE 0x6E38 # 0 +0x0000D3CF 0x9149 # 0 +0x0000D3D0 0x6709 # 0 +0x0000D3D1 0x53CB # 0 +0x0000D3D2 0x53F3 # 0 +0x0000D3D3 0x4F51 # 0 +0x0000D3D4 0x91C9 # 0 +0x0000D3D5 0x8BF1 # 0 +0x0000D3D6 0x53C8 # 0 +0x0000D3D7 0x5E7C # 0 +0x0000D3D8 0x8FC2 # 0 +0x0000D3D9 0x6DE4 # 0 +0x0000D3DA 0x4E8E # 0 +0x0000D3DB 0x76C2 # 0 +0x0000D3DC 0x6986 # 0 +0x0000D3DD 0x865E # 0 +0x0000D3DE 0x611A # 0 +0x0000D3DF 0x8206 # 0 +0x0000D3E0 0x4F59 # 0 +0x0000D3E1 0x4FDE # 0 +0x0000D3E2 0x903E # 0 +0x0000D3E3 0x9C7C # 0 +0x0000D3E4 0x6109 # 0 +0x0000D3E5 0x6E1D # 0 +0x0000D3E6 0x6E14 # 0 +0x0000D3E7 0x9685 # 0 +0x0000D3E8 0x4E88 # 0 +0x0000D3E9 0x5A31 # 0 +0x0000D3EA 0x96E8 # 0 +0x0000D3EB 0x4E0E # 0 +0x0000D3EC 0x5C7F # 0 +0x0000D3ED 0x79B9 # 0 +0x0000D3EE 0x5B87 # 0 +0x0000D3EF 0x8BED # 0 +0x0000D3F0 0x7FBD # 0 +0x0000D3F1 0x7389 # 0 +0x0000D3F2 0x57DF # 0 +0x0000D3F3 0x828B # 0 +0x0000D3F4 0x90C1 # 0 +0x0000D3F5 0x5401 # 0 +0x0000D3F6 0x9047 # 0 +0x0000D3F7 0x55BB # 0 +0x0000D3F8 0x5CEA # 0 +0x0000D3F9 0x5FA1 # 0 +0x0000D3FA 0x6108 # 0 +0x0000D3FB 0x6B32 # 0 +0x0000D3FC 0x72F1 # 0 +0x0000D3FD 0x80B2 # 0 +0x0000D3FE 0x8A89 # 0 +0x0000D4A1 0x6D74 # 0 +0x0000D4A2 0x5BD3 # 0 +0x0000D4A3 0x88D5 # 0 +0x0000D4A4 0x9884 # 0 +0x0000D4A5 0x8C6B # 0 +0x0000D4A6 0x9A6D # 0 +0x0000D4A7 0x9E33 # 0 +0x0000D4A8 0x6E0A # 0 +0x0000D4A9 0x51A4 # 0 +0x0000D4AA 0x5143 # 0 +0x0000D4AB 0x57A3 # 0 +0x0000D4AC 0x8881 # 0 +0x0000D4AD 0x539F # 0 +0x0000D4AE 0x63F4 # 0 +0x0000D4AF 0x8F95 # 0 +0x0000D4B0 0x56ED # 0 +0x0000D4B1 0x5458 # 0 +0x0000D4B2 0x5706 # 0 +0x0000D4B3 0x733F # 0 +0x0000D4B4 0x6E90 # 0 +0x0000D4B5 0x7F18 # 0 +0x0000D4B6 0x8FDC # 0 +0x0000D4B7 0x82D1 # 0 +0x0000D4B8 0x613F # 0 +0x0000D4B9 0x6028 # 0 +0x0000D4BA 0x9662 # 0 +0x0000D4BB 0x66F0 # 0 +0x0000D4BC 0x7EA6 # 0 +0x0000D4BD 0x8D8A # 0 +0x0000D4BE 0x8DC3 # 0 +0x0000D4BF 0x94A5 # 0 +0x0000D4C0 0x5CB3 # 0 +0x0000D4C1 0x7CA4 # 0 +0x0000D4C2 0x6708 # 0 +0x0000D4C3 0x60A6 # 0 +0x0000D4C4 0x9605 # 0 +0x0000D4C5 0x8018 # 0 +0x0000D4C6 0x4E91 # 0 +0x0000D4C7 0x90E7 # 0 +0x0000D4C8 0x5300 # 0 +0x0000D4C9 0x9668 # 0 +0x0000D4CA 0x5141 # 0 +0x0000D4CB 0x8FD0 # 0 +0x0000D4CC 0x8574 # 0 +0x0000D4CD 0x915D # 0 +0x0000D4CE 0x6655 # 0 +0x0000D4CF 0x97F5 # 0 +0x0000D4D0 0x5B55 # 0 +0x0000D4D1 0x531D # 0 +0x0000D4D2 0x7838 # 0 +0x0000D4D3 0x6742 # 0 +0x0000D4D4 0x683D # 0 +0x0000D4D5 0x54C9 # 0 +0x0000D4D6 0x707E # 0 +0x0000D4D7 0x5BB0 # 0 +0x0000D4D8 0x8F7D # 0 +0x0000D4D9 0x518D # 0 +0x0000D4DA 0x5728 # 0 +0x0000D4DB 0x54B1 # 0 +0x0000D4DC 0x6512 # 0 +0x0000D4DD 0x6682 # 0 +0x0000D4DE 0x8D5E # 0 +0x0000D4DF 0x8D43 # 0 +0x0000D4E0 0x810F # 0 +0x0000D4E1 0x846C # 0 +0x0000D4E2 0x906D # 0 +0x0000D4E3 0x7CDF # 0 +0x0000D4E4 0x51FF # 0 +0x0000D4E5 0x85FB # 0 +0x0000D4E6 0x67A3 # 0 +0x0000D4E7 0x65E9 # 0 +0x0000D4E8 0x6FA1 # 0 +0x0000D4E9 0x86A4 # 0 +0x0000D4EA 0x8E81 # 0 +0x0000D4EB 0x566A # 0 +0x0000D4EC 0x9020 # 0 +0x0000D4ED 0x7682 # 0 +0x0000D4EE 0x7076 # 0 +0x0000D4EF 0x71E5 # 0 +0x0000D4F0 0x8D23 # 0 +0x0000D4F1 0x62E9 # 0 +0x0000D4F2 0x5219 # 0 +0x0000D4F3 0x6CFD # 0 +0x0000D4F4 0x8D3C # 0 +0x0000D4F5 0x600E # 0 +0x0000D4F6 0x589E # 0 +0x0000D4F7 0x618E # 0 +0x0000D4F8 0x66FE # 0 +0x0000D4F9 0x8D60 # 0 +0x0000D4FA 0x624E # 0 +0x0000D4FB 0x55B3 # 0 +0x0000D4FC 0x6E23 # 0 +0x0000D4FD 0x672D # 0 +0x0000D4FE 0x8F67 # 0 +0x0000D5A1 0x94E1 # 0 +0x0000D5A2 0x95F8 # 0 +0x0000D5A3 0x7728 # 0 +0x0000D5A4 0x6805 # 0 +0x0000D5A5 0x69A8 # 0 +0x0000D5A6 0x548B # 0 +0x0000D5A7 0x4E4D # 0 +0x0000D5A8 0x70B8 # 0 +0x0000D5A9 0x8BC8 # 0 +0x0000D5AA 0x6458 # 0 +0x0000D5AB 0x658B # 0 +0x0000D5AC 0x5B85 # 0 +0x0000D5AD 0x7A84 # 0 +0x0000D5AE 0x503A # 0 +0x0000D5AF 0x5BE8 # 0 +0x0000D5B0 0x77BB # 0 +0x0000D5B1 0x6BE1 # 0 +0x0000D5B2 0x8A79 # 0 +0x0000D5B3 0x7C98 # 0 +0x0000D5B4 0x6CBE # 0 +0x0000D5B5 0x76CF # 0 +0x0000D5B6 0x65A9 # 0 +0x0000D5B7 0x8F97 # 0 +0x0000D5B8 0x5D2D # 0 +0x0000D5B9 0x5C55 # 0 +0x0000D5BA 0x8638 # 0 +0x0000D5BB 0x6808 # 0 +0x0000D5BC 0x5360 # 0 +0x0000D5BD 0x6218 # 0 +0x0000D5BE 0x7AD9 # 0 +0x0000D5BF 0x6E5B # 0 +0x0000D5C0 0x7EFD # 0 +0x0000D5C1 0x6A1F # 0 +0x0000D5C2 0x7AE0 # 0 +0x0000D5C3 0x5F70 # 0 +0x0000D5C4 0x6F33 # 0 +0x0000D5C5 0x5F20 # 0 +0x0000D5C6 0x638C # 0 +0x0000D5C7 0x6DA8 # 0 +0x0000D5C8 0x6756 # 0 +0x0000D5C9 0x4E08 # 0 +0x0000D5CA 0x5E10 # 0 +0x0000D5CB 0x8D26 # 0 +0x0000D5CC 0x4ED7 # 0 +0x0000D5CD 0x80C0 # 0 +0x0000D5CE 0x7634 # 0 +0x0000D5CF 0x969C # 0 +0x0000D5D0 0x62DB # 0 +0x0000D5D1 0x662D # 0 +0x0000D5D2 0x627E # 0 +0x0000D5D3 0x6CBC # 0 +0x0000D5D4 0x8D75 # 0 +0x0000D5D5 0x7167 # 0 +0x0000D5D6 0x7F69 # 0 +0x0000D5D7 0x5146 # 0 +0x0000D5D8 0x8087 # 0 +0x0000D5D9 0x53EC # 0 +0x0000D5DA 0x906E # 0 +0x0000D5DB 0x6298 # 0 +0x0000D5DC 0x54F2 # 0 +0x0000D5DD 0x86F0 # 0 +0x0000D5DE 0x8F99 # 0 +0x0000D5DF 0x8005 # 0 +0x0000D5E0 0x9517 # 0 +0x0000D5E1 0x8517 # 0 +0x0000D5E2 0x8FD9 # 0 +0x0000D5E3 0x6D59 # 0 +0x0000D5E4 0x73CD # 0 +0x0000D5E5 0x659F # 0 +0x0000D5E6 0x771F # 0 +0x0000D5E7 0x7504 # 0 +0x0000D5E8 0x7827 # 0 +0x0000D5E9 0x81FB # 0 +0x0000D5EA 0x8D1E # 0 +0x0000D5EB 0x9488 # 0 +0x0000D5EC 0x4FA6 # 0 +0x0000D5ED 0x6795 # 0 +0x0000D5EE 0x75B9 # 0 +0x0000D5EF 0x8BCA # 0 +0x0000D5F0 0x9707 # 0 +0x0000D5F1 0x632F # 0 +0x0000D5F2 0x9547 # 0 +0x0000D5F3 0x9635 # 0 +0x0000D5F4 0x84B8 # 0 +0x0000D5F5 0x6323 # 0 +0x0000D5F6 0x7741 # 0 +0x0000D5F7 0x5F81 # 0 +0x0000D5F8 0x72F0 # 0 +0x0000D5F9 0x4E89 # 0 +0x0000D5FA 0x6014 # 0 +0x0000D5FB 0x6574 # 0 +0x0000D5FC 0x62EF # 0 +0x0000D5FD 0x6B63 # 0 +0x0000D5FE 0x653F # 0 +0x0000D6A1 0x5E27 # 0 +0x0000D6A2 0x75C7 # 0 +0x0000D6A3 0x90D1 # 0 +0x0000D6A4 0x8BC1 # 0 +0x0000D6A5 0x829D # 0 +0x0000D6A6 0x679D # 0 +0x0000D6A7 0x652F # 0 +0x0000D6A8 0x5431 # 0 +0x0000D6A9 0x8718 # 0 +0x0000D6AA 0x77E5 # 0 +0x0000D6AB 0x80A2 # 0 +0x0000D6AC 0x8102 # 0 +0x0000D6AD 0x6C41 # 0 +0x0000D6AE 0x4E4B # 0 +0x0000D6AF 0x7EC7 # 0 +0x0000D6B0 0x804C # 0 +0x0000D6B1 0x76F4 # 0 +0x0000D6B2 0x690D # 0 +0x0000D6B3 0x6B96 # 0 +0x0000D6B4 0x6267 # 0 +0x0000D6B5 0x503C # 0 +0x0000D6B6 0x4F84 # 0 +0x0000D6B7 0x5740 # 0 +0x0000D6B8 0x6307 # 0 +0x0000D6B9 0x6B62 # 0 +0x0000D6BA 0x8DBE # 0 +0x0000D6BB 0x53EA # 0 +0x0000D6BC 0x65E8 # 0 +0x0000D6BD 0x7EB8 # 0 +0x0000D6BE 0x5FD7 # 0 +0x0000D6BF 0x631A # 0 +0x0000D6C0 0x63B7 # 0 +0x0000D6C1 0x81F3 # 0 +0x0000D6C2 0x81F4 # 0 +0x0000D6C3 0x7F6E # 0 +0x0000D6C4 0x5E1C # 0 +0x0000D6C5 0x5CD9 # 0 +0x0000D6C6 0x5236 # 0 +0x0000D6C7 0x667A # 0 +0x0000D6C8 0x79E9 # 0 +0x0000D6C9 0x7A1A # 0 +0x0000D6CA 0x8D28 # 0 +0x0000D6CB 0x7099 # 0 +0x0000D6CC 0x75D4 # 0 +0x0000D6CD 0x6EDE # 0 +0x0000D6CE 0x6CBB # 0 +0x0000D6CF 0x7A92 # 0 +0x0000D6D0 0x4E2D # 0 +0x0000D6D1 0x76C5 # 0 +0x0000D6D2 0x5FE0 # 0 +0x0000D6D3 0x949F # 0 +0x0000D6D4 0x8877 # 0 +0x0000D6D5 0x7EC8 # 0 +0x0000D6D6 0x79CD # 0 +0x0000D6D7 0x80BF # 0 +0x0000D6D8 0x91CD # 0 +0x0000D6D9 0x4EF2 # 0 +0x0000D6DA 0x4F17 # 0 +0x0000D6DB 0x821F # 0 +0x0000D6DC 0x5468 # 0 +0x0000D6DD 0x5DDE # 0 +0x0000D6DE 0x6D32 # 0 +0x0000D6DF 0x8BCC # 0 +0x0000D6E0 0x7CA5 # 0 +0x0000D6E1 0x8F74 # 0 +0x0000D6E2 0x8098 # 0 +0x0000D6E3 0x5E1A # 0 +0x0000D6E4 0x5492 # 0 +0x0000D6E5 0x76B1 # 0 +0x0000D6E6 0x5B99 # 0 +0x0000D6E7 0x663C # 0 +0x0000D6E8 0x9AA4 # 0 +0x0000D6E9 0x73E0 # 0 +0x0000D6EA 0x682A # 0 +0x0000D6EB 0x86DB # 0 +0x0000D6EC 0x6731 # 0 +0x0000D6ED 0x732A # 0 +0x0000D6EE 0x8BF8 # 0 +0x0000D6EF 0x8BDB # 0 +0x0000D6F0 0x9010 # 0 +0x0000D6F1 0x7AF9 # 0 +0x0000D6F2 0x70DB # 0 +0x0000D6F3 0x716E # 0 +0x0000D6F4 0x62C4 # 0 +0x0000D6F5 0x77A9 # 0 +0x0000D6F6 0x5631 # 0 +0x0000D6F7 0x4E3B # 0 +0x0000D6F8 0x8457 # 0 +0x0000D6F9 0x67F1 # 0 +0x0000D6FA 0x52A9 # 0 +0x0000D6FB 0x86C0 # 0 +0x0000D6FC 0x8D2E # 0 +0x0000D6FD 0x94F8 # 0 +0x0000D6FE 0x7B51 # 0 +0x0000D7A1 0x4F4F # 0 +0x0000D7A2 0x6CE8 # 0 +0x0000D7A3 0x795D # 0 +0x0000D7A4 0x9A7B # 0 +0x0000D7A5 0x6293 # 0 +0x0000D7A6 0x722A # 0 +0x0000D7A7 0x62FD # 0 +0x0000D7A8 0x4E13 # 0 +0x0000D7A9 0x7816 # 0 +0x0000D7AA 0x8F6C # 0 +0x0000D7AB 0x64B0 # 0 +0x0000D7AC 0x8D5A # 0 +0x0000D7AD 0x7BC6 # 0 +0x0000D7AE 0x6869 # 0 +0x0000D7AF 0x5E84 # 0 +0x0000D7B0 0x88C5 # 0 +0x0000D7B1 0x5986 # 0 +0x0000D7B2 0x649E # 0 +0x0000D7B3 0x58EE # 0 +0x0000D7B4 0x72B6 # 0 +0x0000D7B5 0x690E # 0 +0x0000D7B6 0x9525 # 0 +0x0000D7B7 0x8FFD # 0 +0x0000D7B8 0x8D58 # 0 +0x0000D7B9 0x5760 # 0 +0x0000D7BA 0x7F00 # 0 +0x0000D7BB 0x8C06 # 0 +0x0000D7BC 0x51C6 # 0 +0x0000D7BD 0x6349 # 0 +0x0000D7BE 0x62D9 # 0 +0x0000D7BF 0x5353 # 0 +0x0000D7C0 0x684C # 0 +0x0000D7C1 0x7422 # 0 +0x0000D7C2 0x8301 # 0 +0x0000D7C3 0x914C # 0 +0x0000D7C4 0x5544 # 0 +0x0000D7C5 0x7740 # 0 +0x0000D7C6 0x707C # 0 +0x0000D7C7 0x6D4A # 0 +0x0000D7C8 0x5179 # 0 +0x0000D7C9 0x54A8 # 0 +0x0000D7CA 0x8D44 # 0 +0x0000D7CB 0x59FF # 0 +0x0000D7CC 0x6ECB # 0 +0x0000D7CD 0x6DC4 # 0 +0x0000D7CE 0x5B5C # 0 +0x0000D7CF 0x7D2B # 0 +0x0000D7D0 0x4ED4 # 0 +0x0000D7D1 0x7C7D # 0 +0x0000D7D2 0x6ED3 # 0 +0x0000D7D3 0x5B50 # 0 +0x0000D7D4 0x81EA # 0 +0x0000D7D5 0x6E0D # 0 +0x0000D7D6 0x5B57 # 0 +0x0000D7D7 0x9B03 # 0 +0x0000D7D8 0x68D5 # 0 +0x0000D7D9 0x8E2A # 0 +0x0000D7DA 0x5B97 # 0 +0x0000D7DB 0x7EFC # 0 +0x0000D7DC 0x603B # 0 +0x0000D7DD 0x7EB5 # 0 +0x0000D7DE 0x90B9 # 0 +0x0000D7DF 0x8D70 # 0 +0x0000D7E0 0x594F # 0 +0x0000D7E1 0x63CD # 0 +0x0000D7E2 0x79DF # 0 +0x0000D7E3 0x8DB3 # 0 +0x0000D7E4 0x5352 # 0 +0x0000D7E5 0x65CF # 0 +0x0000D7E6 0x7956 # 0 +0x0000D7E7 0x8BC5 # 0 +0x0000D7E8 0x963B # 0 +0x0000D7E9 0x7EC4 # 0 +0x0000D7EA 0x94BB # 0 +0x0000D7EB 0x7E82 # 0 +0x0000D7EC 0x5634 # 0 +0x0000D7ED 0x9189 # 0 +0x0000D7EE 0x6700 # 0 +0x0000D7EF 0x7F6A # 0 +0x0000D7F0 0x5C0A # 0 +0x0000D7F1 0x9075 # 0 +0x0000D7F2 0x6628 # 0 +0x0000D7F3 0x5DE6 # 0 +0x0000D7F4 0x4F50 # 0 +0x0000D7F5 0x67DE # 0 +0x0000D7F6 0x505A # 0 +0x0000D7F7 0x4F5C # 0 +0x0000D7F8 0x5750 # 0 +0x0000D7F9 0x5EA7 # 0 +0x0000D8A1 0x4E8D # 0 +0x0000D8A2 0x4E0C # 0 +0x0000D8A3 0x5140 # 0 +0x0000D8A4 0x4E10 # 0 +0x0000D8A5 0x5EFF # 0 +0x0000D8A6 0x5345 # 0 +0x0000D8A7 0x4E15 # 0 +0x0000D8A8 0x4E98 # 0 +0x0000D8A9 0x4E1E # 0 +0x0000D8AA 0x9B32 # 0 +0x0000D8AB 0x5B6C # 0 +0x0000D8AC 0x5669 # 0 +0x0000D8AD 0x4E28 # 0 +0x0000D8AE 0x79BA # 0 +0x0000D8AF 0x4E3F # 0 +0x0000D8B0 0x5315 # 0 +0x0000D8B1 0x4E47 # 0 +0x0000D8B2 0x592D # 0 +0x0000D8B3 0x723B # 0 +0x0000D8B4 0x536E # 0 +0x0000D8B5 0x6C10 # 0 +0x0000D8B6 0x56DF # 0 +0x0000D8B7 0x80E4 # 0 +0x0000D8B8 0x9997 # 0 +0x0000D8B9 0x6BD3 # 0 +0x0000D8BA 0x777E # 0 +0x0000D8BB 0x9F17 # 0 +0x0000D8BC 0x4E36 # 0 +0x0000D8BD 0x4E9F # 0 +0x0000D8BE 0x9F10 # 0 +0x0000D8BF 0x4E5C # 0 +0x0000D8C0 0x4E69 # 0 +0x0000D8C1 0x4E93 # 0 +0x0000D8C2 0x8288 # 0 +0x0000D8C3 0x5B5B # 0 +0x0000D8C4 0x556C # 0 +0x0000D8C5 0x560F # 0 +0x0000D8C6 0x4EC4 # 0 +0x0000D8C7 0x538D # 0 +0x0000D8C8 0x539D # 0 +0x0000D8C9 0x53A3 # 0 +0x0000D8CA 0x53A5 # 0 +0x0000D8CB 0x53AE # 0 +0x0000D8CC 0x9765 # 0 +0x0000D8CD 0x8D5D # 0 +0x0000D8CE 0x531A # 0 +0x0000D8CF 0x53F5 # 0 +0x0000D8D0 0x5326 # 0 +0x0000D8D1 0x532E # 0 +0x0000D8D2 0x533E # 0 +0x0000D8D3 0x8D5C # 0 +0x0000D8D4 0x5366 # 0 +0x0000D8D5 0x5363 # 0 +0x0000D8D6 0x5202 # 0 +0x0000D8D7 0x5208 # 0 +0x0000D8D8 0x520E # 0 +0x0000D8D9 0x522D # 0 +0x0000D8DA 0x5233 # 0 +0x0000D8DB 0x523F # 0 +0x0000D8DC 0x5240 # 0 +0x0000D8DD 0x524C # 0 +0x0000D8DE 0x525E # 0 +0x0000D8DF 0x5261 # 0 +0x0000D8E0 0x525C # 0 +0x0000D8E1 0x84AF # 0 +0x0000D8E2 0x527D # 0 +0x0000D8E3 0x5282 # 0 +0x0000D8E4 0x5281 # 0 +0x0000D8E5 0x5290 # 0 +0x0000D8E6 0x5293 # 0 +0x0000D8E7 0x5182 # 0 +0x0000D8E8 0x7F54 # 0 +0x0000D8E9 0x4EBB # 0 +0x0000D8EA 0x4EC3 # 0 +0x0000D8EB 0x4EC9 # 0 +0x0000D8EC 0x4EC2 # 0 +0x0000D8ED 0x4EE8 # 0 +0x0000D8EE 0x4EE1 # 0 +0x0000D8EF 0x4EEB # 0 +0x0000D8F0 0x4EDE # 0 +0x0000D8F1 0x4F1B # 0 +0x0000D8F2 0x4EF3 # 0 +0x0000D8F3 0x4F22 # 0 +0x0000D8F4 0x4F64 # 0 +0x0000D8F5 0x4EF5 # 0 +0x0000D8F6 0x4F25 # 0 +0x0000D8F7 0x4F27 # 0 +0x0000D8F8 0x4F09 # 0 +0x0000D8F9 0x4F2B # 0 +0x0000D8FA 0x4F5E # 0 +0x0000D8FB 0x4F67 # 0 +0x0000D8FC 0x6538 # 0 +0x0000D8FD 0x4F5A # 0 +0x0000D8FE 0x4F5D # 0 +0x0000D9A1 0x4F5F # 0 +0x0000D9A2 0x4F57 # 0 +0x0000D9A3 0x4F32 # 0 +0x0000D9A4 0x4F3D # 0 +0x0000D9A5 0x4F76 # 0 +0x0000D9A6 0x4F74 # 0 +0x0000D9A7 0x4F91 # 0 +0x0000D9A8 0x4F89 # 0 +0x0000D9A9 0x4F83 # 0 +0x0000D9AA 0x4F8F # 0 +0x0000D9AB 0x4F7E # 0 +0x0000D9AC 0x4F7B # 0 +0x0000D9AD 0x4FAA # 0 +0x0000D9AE 0x4F7C # 0 +0x0000D9AF 0x4FAC # 0 +0x0000D9B0 0x4F94 # 0 +0x0000D9B1 0x4FE6 # 0 +0x0000D9B2 0x4FE8 # 0 +0x0000D9B3 0x4FEA # 0 +0x0000D9B4 0x4FC5 # 0 +0x0000D9B5 0x4FDA # 0 +0x0000D9B6 0x4FE3 # 0 +0x0000D9B7 0x4FDC # 0 +0x0000D9B8 0x4FD1 # 0 +0x0000D9B9 0x4FDF # 0 +0x0000D9BA 0x4FF8 # 0 +0x0000D9BB 0x5029 # 0 +0x0000D9BC 0x504C # 0 +0x0000D9BD 0x4FF3 # 0 +0x0000D9BE 0x502C # 0 +0x0000D9BF 0x500F # 0 +0x0000D9C0 0x502E # 0 +0x0000D9C1 0x502D # 0 +0x0000D9C2 0x4FFE # 0 +0x0000D9C3 0x501C # 0 +0x0000D9C4 0x500C # 0 +0x0000D9C5 0x5025 # 0 +0x0000D9C6 0x5028 # 0 +0x0000D9C7 0x507E # 0 +0x0000D9C8 0x5043 # 0 +0x0000D9C9 0x5055 # 0 +0x0000D9CA 0x5048 # 0 +0x0000D9CB 0x504E # 0 +0x0000D9CC 0x506C # 0 +0x0000D9CD 0x507B # 0 +0x0000D9CE 0x50A5 # 0 +0x0000D9CF 0x50A7 # 0 +0x0000D9D0 0x50A9 # 0 +0x0000D9D1 0x50BA # 0 +0x0000D9D2 0x50D6 # 0 +0x0000D9D3 0x5106 # 0 +0x0000D9D4 0x50ED # 0 +0x0000D9D5 0x50EC # 0 +0x0000D9D6 0x50E6 # 0 +0x0000D9D7 0x50EE # 0 +0x0000D9D8 0x5107 # 0 +0x0000D9D9 0x510B # 0 +0x0000D9DA 0x4EDD # 0 +0x0000D9DB 0x6C3D # 0 +0x0000D9DC 0x4F58 # 0 +0x0000D9DD 0x4F65 # 0 +0x0000D9DE 0x4FCE # 0 +0x0000D9DF 0x9FA0 # 0 +0x0000D9E0 0x6C46 # 0 +0x0000D9E1 0x7C74 # 0 +0x0000D9E2 0x516E # 0 +0x0000D9E3 0x5DFD # 0 +0x0000D9E4 0x9EC9 # 0 +0x0000D9E5 0x9998 # 0 +0x0000D9E6 0x5181 # 0 +0x0000D9E7 0x5914 # 0 +0x0000D9E8 0x52F9 # 0 +0x0000D9E9 0x530D # 0 +0x0000D9EA 0x8A07 # 0 +0x0000D9EB 0x5310 # 0 +0x0000D9EC 0x51EB # 0 +0x0000D9ED 0x5919 # 0 +0x0000D9EE 0x5155 # 0 +0x0000D9EF 0x4EA0 # 0 +0x0000D9F0 0x5156 # 0 +0x0000D9F1 0x4EB3 # 0 +0x0000D9F2 0x886E # 0 +0x0000D9F3 0x88A4 # 0 +0x0000D9F4 0x4EB5 # 0 +0x0000D9F5 0x8114 # 0 +0x0000D9F6 0x88D2 # 0 +0x0000D9F7 0x7980 # 0 +0x0000D9F8 0x5B34 # 0 +0x0000D9F9 0x8803 # 0 +0x0000D9FA 0x7FB8 # 0 +0x0000D9FB 0x51AB # 0 +0x0000D9FC 0x51B1 # 0 +0x0000D9FD 0x51BD # 0 +0x0000D9FE 0x51BC # 0 +0x0000DAA1 0x51C7 # 0 +0x0000DAA2 0x5196 # 0 +0x0000DAA3 0x51A2 # 0 +0x0000DAA4 0x51A5 # 0 +0x0000DAA5 0x8BA0 # 0 +0x0000DAA6 0x8BA6 # 0 +0x0000DAA7 0x8BA7 # 0 +0x0000DAA8 0x8BAA # 0 +0x0000DAA9 0x8BB4 # 0 +0x0000DAAA 0x8BB5 # 0 +0x0000DAAB 0x8BB7 # 0 +0x0000DAAC 0x8BC2 # 0 +0x0000DAAD 0x8BC3 # 0 +0x0000DAAE 0x8BCB # 0 +0x0000DAAF 0x8BCF # 0 +0x0000DAB0 0x8BCE # 0 +0x0000DAB1 0x8BD2 # 0 +0x0000DAB2 0x8BD3 # 0 +0x0000DAB3 0x8BD4 # 0 +0x0000DAB4 0x8BD6 # 0 +0x0000DAB5 0x8BD8 # 0 +0x0000DAB6 0x8BD9 # 0 +0x0000DAB7 0x8BDC # 0 +0x0000DAB8 0x8BDF # 0 +0x0000DAB9 0x8BE0 # 0 +0x0000DABA 0x8BE4 # 0 +0x0000DABB 0x8BE8 # 0 +0x0000DABC 0x8BE9 # 0 +0x0000DABD 0x8BEE # 0 +0x0000DABE 0x8BF0 # 0 +0x0000DABF 0x8BF3 # 0 +0x0000DAC0 0x8BF6 # 0 +0x0000DAC1 0x8BF9 # 0 +0x0000DAC2 0x8BFC # 0 +0x0000DAC3 0x8BFF # 0 +0x0000DAC4 0x8C00 # 0 +0x0000DAC5 0x8C02 # 0 +0x0000DAC6 0x8C04 # 0 +0x0000DAC7 0x8C07 # 0 +0x0000DAC8 0x8C0C # 0 +0x0000DAC9 0x8C0F # 0 +0x0000DACA 0x8C11 # 0 +0x0000DACB 0x8C12 # 0 +0x0000DACC 0x8C14 # 0 +0x0000DACD 0x8C15 # 0 +0x0000DACE 0x8C16 # 0 +0x0000DACF 0x8C19 # 0 +0x0000DAD0 0x8C1B # 0 +0x0000DAD1 0x8C18 # 0 +0x0000DAD2 0x8C1D # 0 +0x0000DAD3 0x8C1F # 0 +0x0000DAD4 0x8C20 # 0 +0x0000DAD5 0x8C21 # 0 +0x0000DAD6 0x8C25 # 0 +0x0000DAD7 0x8C27 # 0 +0x0000DAD8 0x8C2A # 0 +0x0000DAD9 0x8C2B # 0 +0x0000DADA 0x8C2E # 0 +0x0000DADB 0x8C2F # 0 +0x0000DADC 0x8C32 # 0 +0x0000DADD 0x8C33 # 0 +0x0000DADE 0x8C35 # 0 +0x0000DADF 0x8C36 # 0 +0x0000DAE0 0x5369 # 0 +0x0000DAE1 0x537A # 0 +0x0000DAE2 0x961D # 0 +0x0000DAE3 0x9622 # 0 +0x0000DAE4 0x9621 # 0 +0x0000DAE5 0x9631 # 0 +0x0000DAE6 0x962A # 0 +0x0000DAE7 0x963D # 0 +0x0000DAE8 0x963C # 0 +0x0000DAE9 0x9642 # 0 +0x0000DAEA 0x9649 # 0 +0x0000DAEB 0x9654 # 0 +0x0000DAEC 0x965F # 0 +0x0000DAED 0x9667 # 0 +0x0000DAEE 0x966C # 0 +0x0000DAEF 0x9672 # 0 +0x0000DAF0 0x9674 # 0 +0x0000DAF1 0x9688 # 0 +0x0000DAF2 0x968D # 0 +0x0000DAF3 0x9697 # 0 +0x0000DAF4 0x96B0 # 0 +0x0000DAF5 0x9097 # 0 +0x0000DAF6 0x909B # 0 +0x0000DAF7 0x909D # 0 +0x0000DAF8 0x9099 # 0 +0x0000DAF9 0x90AC # 0 +0x0000DAFA 0x90A1 # 0 +0x0000DAFB 0x90B4 # 0 +0x0000DAFC 0x90B3 # 0 +0x0000DAFD 0x90B6 # 0 +0x0000DAFE 0x90BA # 0 +0x0000DBA1 0x90B8 # 0 +0x0000DBA2 0x90B0 # 0 +0x0000DBA3 0x90CF # 0 +0x0000DBA4 0x90C5 # 0 +0x0000DBA5 0x90BE # 0 +0x0000DBA6 0x90D0 # 0 +0x0000DBA7 0x90C4 # 0 +0x0000DBA8 0x90C7 # 0 +0x0000DBA9 0x90D3 # 0 +0x0000DBAA 0x90E6 # 0 +0x0000DBAB 0x90E2 # 0 +0x0000DBAC 0x90DC # 0 +0x0000DBAD 0x90D7 # 0 +0x0000DBAE 0x90DB # 0 +0x0000DBAF 0x90EB # 0 +0x0000DBB0 0x90EF # 0 +0x0000DBB1 0x90FE # 0 +0x0000DBB2 0x9104 # 0 +0x0000DBB3 0x9122 # 0 +0x0000DBB4 0x911E # 0 +0x0000DBB5 0x9123 # 0 +0x0000DBB6 0x9131 # 0 +0x0000DBB7 0x912F # 0 +0x0000DBB8 0x9139 # 0 +0x0000DBB9 0x9143 # 0 +0x0000DBBA 0x9146 # 0 +0x0000DBBB 0x520D # 0 +0x0000DBBC 0x5942 # 0 +0x0000DBBD 0x52A2 # 0 +0x0000DBBE 0x52AC # 0 +0x0000DBBF 0x52AD # 0 +0x0000DBC0 0x52BE # 0 +0x0000DBC1 0x54FF # 0 +0x0000DBC2 0x52D0 # 0 +0x0000DBC3 0x52D6 # 0 +0x0000DBC4 0x52F0 # 0 +0x0000DBC5 0x53DF # 0 +0x0000DBC6 0x71EE # 0 +0x0000DBC7 0x77CD # 0 +0x0000DBC8 0x5EF4 # 0 +0x0000DBC9 0x51F5 # 0 +0x0000DBCA 0x51FC # 0 +0x0000DBCB 0x9B2F # 0 +0x0000DBCC 0x53B6 # 0 +0x0000DBCD 0x5F01 # 0 +0x0000DBCE 0x755A # 0 +0x0000DBCF 0x5DEF # 0 +0x0000DBD0 0x574C # 0 +0x0000DBD1 0x57A9 # 0 +0x0000DBD2 0x57A1 # 0 +0x0000DBD3 0x587E # 0 +0x0000DBD4 0x58BC # 0 +0x0000DBD5 0x58C5 # 0 +0x0000DBD6 0x58D1 # 0 +0x0000DBD7 0x5729 # 0 +0x0000DBD8 0x572C # 0 +0x0000DBD9 0x572A # 0 +0x0000DBDA 0x5733 # 0 +0x0000DBDB 0x5739 # 0 +0x0000DBDC 0x572E # 0 +0x0000DBDD 0x572F # 0 +0x0000DBDE 0x575C # 0 +0x0000DBDF 0x573B # 0 +0x0000DBE0 0x5742 # 0 +0x0000DBE1 0x5769 # 0 +0x0000DBE2 0x5785 # 0 +0x0000DBE3 0x576B # 0 +0x0000DBE4 0x5786 # 0 +0x0000DBE5 0x577C # 0 +0x0000DBE6 0x577B # 0 +0x0000DBE7 0x5768 # 0 +0x0000DBE8 0x576D # 0 +0x0000DBE9 0x5776 # 0 +0x0000DBEA 0x5773 # 0 +0x0000DBEB 0x57AD # 0 +0x0000DBEC 0x57A4 # 0 +0x0000DBED 0x578C # 0 +0x0000DBEE 0x57B2 # 0 +0x0000DBEF 0x57CF # 0 +0x0000DBF0 0x57A7 # 0 +0x0000DBF1 0x57B4 # 0 +0x0000DBF2 0x5793 # 0 +0x0000DBF3 0x57A0 # 0 +0x0000DBF4 0x57D5 # 0 +0x0000DBF5 0x57D8 # 0 +0x0000DBF6 0x57DA # 0 +0x0000DBF7 0x57D9 # 0 +0x0000DBF8 0x57D2 # 0 +0x0000DBF9 0x57B8 # 0 +0x0000DBFA 0x57F4 # 0 +0x0000DBFB 0x57EF # 0 +0x0000DBFC 0x57F8 # 0 +0x0000DBFD 0x57E4 # 0 +0x0000DBFE 0x57DD # 0 +0x0000DCA1 0x580B # 0 +0x0000DCA2 0x580D # 0 +0x0000DCA3 0x57FD # 0 +0x0000DCA4 0x57ED # 0 +0x0000DCA5 0x5800 # 0 +0x0000DCA6 0x581E # 0 +0x0000DCA7 0x5819 # 0 +0x0000DCA8 0x5844 # 0 +0x0000DCA9 0x5820 # 0 +0x0000DCAA 0x5865 # 0 +0x0000DCAB 0x586C # 0 +0x0000DCAC 0x5881 # 0 +0x0000DCAD 0x5889 # 0 +0x0000DCAE 0x589A # 0 +0x0000DCAF 0x5880 # 0 +0x0000DCB0 0x99A8 # 0 +0x0000DCB1 0x9F19 # 0 +0x0000DCB2 0x61FF # 0 +0x0000DCB3 0x8279 # 0 +0x0000DCB4 0x827D # 0 +0x0000DCB5 0x827F # 0 +0x0000DCB6 0x828F # 0 +0x0000DCB7 0x828A # 0 +0x0000DCB8 0x82A8 # 0 +0x0000DCB9 0x8284 # 0 +0x0000DCBA 0x828E # 0 +0x0000DCBB 0x8291 # 0 +0x0000DCBC 0x8297 # 0 +0x0000DCBD 0x8299 # 0 +0x0000DCBE 0x82AB # 0 +0x0000DCBF 0x82B8 # 0 +0x0000DCC0 0x82BE # 0 +0x0000DCC1 0x82B0 # 0 +0x0000DCC2 0x82C8 # 0 +0x0000DCC3 0x82CA # 0 +0x0000DCC4 0x82E3 # 0 +0x0000DCC5 0x8298 # 0 +0x0000DCC6 0x82B7 # 0 +0x0000DCC7 0x82AE # 0 +0x0000DCC8 0x82CB # 0 +0x0000DCC9 0x82CC # 0 +0x0000DCCA 0x82C1 # 0 +0x0000DCCB 0x82A9 # 0 +0x0000DCCC 0x82B4 # 0 +0x0000DCCD 0x82A1 # 0 +0x0000DCCE 0x82AA # 0 +0x0000DCCF 0x829F # 0 +0x0000DCD0 0x82C4 # 0 +0x0000DCD1 0x82CE # 0 +0x0000DCD2 0x82A4 # 0 +0x0000DCD3 0x82E1 # 0 +0x0000DCD4 0x8309 # 0 +0x0000DCD5 0x82F7 # 0 +0x0000DCD6 0x82E4 # 0 +0x0000DCD7 0x830F # 0 +0x0000DCD8 0x8307 # 0 +0x0000DCD9 0x82DC # 0 +0x0000DCDA 0x82F4 # 0 +0x0000DCDB 0x82D2 # 0 +0x0000DCDC 0x82D8 # 0 +0x0000DCDD 0x830C # 0 +0x0000DCDE 0x82FB # 0 +0x0000DCDF 0x82D3 # 0 +0x0000DCE0 0x8311 # 0 +0x0000DCE1 0x831A # 0 +0x0000DCE2 0x8306 # 0 +0x0000DCE3 0x8314 # 0 +0x0000DCE4 0x8315 # 0 +0x0000DCE5 0x82E0 # 0 +0x0000DCE6 0x82D5 # 0 +0x0000DCE7 0x831C # 0 +0x0000DCE8 0x8351 # 0 +0x0000DCE9 0x835B # 0 +0x0000DCEA 0x835C # 0 +0x0000DCEB 0x8308 # 0 +0x0000DCEC 0x8392 # 0 +0x0000DCED 0x833C # 0 +0x0000DCEE 0x8334 # 0 +0x0000DCEF 0x8331 # 0 +0x0000DCF0 0x839B # 0 +0x0000DCF1 0x835E # 0 +0x0000DCF2 0x832F # 0 +0x0000DCF3 0x834F # 0 +0x0000DCF4 0x8347 # 0 +0x0000DCF5 0x8343 # 0 +0x0000DCF6 0x835F # 0 +0x0000DCF7 0x8340 # 0 +0x0000DCF8 0x8317 # 0 +0x0000DCF9 0x8360 # 0 +0x0000DCFA 0x832D # 0 +0x0000DCFB 0x833A # 0 +0x0000DCFC 0x8333 # 0 +0x0000DCFD 0x8366 # 0 +0x0000DCFE 0x8365 # 0 +0x0000DDA1 0x8368 # 0 +0x0000DDA2 0x831B # 0 +0x0000DDA3 0x8369 # 0 +0x0000DDA4 0x836C # 0 +0x0000DDA5 0x836A # 0 +0x0000DDA6 0x836D # 0 +0x0000DDA7 0x836E # 0 +0x0000DDA8 0x83B0 # 0 +0x0000DDA9 0x8378 # 0 +0x0000DDAA 0x83B3 # 0 +0x0000DDAB 0x83B4 # 0 +0x0000DDAC 0x83A0 # 0 +0x0000DDAD 0x83AA # 0 +0x0000DDAE 0x8393 # 0 +0x0000DDAF 0x839C # 0 +0x0000DDB0 0x8385 # 0 +0x0000DDB1 0x837C # 0 +0x0000DDB2 0x83B6 # 0 +0x0000DDB3 0x83A9 # 0 +0x0000DDB4 0x837D # 0 +0x0000DDB5 0x83B8 # 0 +0x0000DDB6 0x837B # 0 +0x0000DDB7 0x8398 # 0 +0x0000DDB8 0x839E # 0 +0x0000DDB9 0x83A8 # 0 +0x0000DDBA 0x83BA # 0 +0x0000DDBB 0x83BC # 0 +0x0000DDBC 0x83C1 # 0 +0x0000DDBD 0x8401 # 0 +0x0000DDBE 0x83E5 # 0 +0x0000DDBF 0x83D8 # 0 +0x0000DDC0 0x5807 # 0 +0x0000DDC1 0x8418 # 0 +0x0000DDC2 0x840B # 0 +0x0000DDC3 0x83DD # 0 +0x0000DDC4 0x83FD # 0 +0x0000DDC5 0x83D6 # 0 +0x0000DDC6 0x841C # 0 +0x0000DDC7 0x8438 # 0 +0x0000DDC8 0x8411 # 0 +0x0000DDC9 0x8406 # 0 +0x0000DDCA 0x83D4 # 0 +0x0000DDCB 0x83DF # 0 +0x0000DDCC 0x840F # 0 +0x0000DDCD 0x8403 # 0 +0x0000DDCE 0x83F8 # 0 +0x0000DDCF 0x83F9 # 0 +0x0000DDD0 0x83EA # 0 +0x0000DDD1 0x83C5 # 0 +0x0000DDD2 0x83C0 # 0 +0x0000DDD3 0x8426 # 0 +0x0000DDD4 0x83F0 # 0 +0x0000DDD5 0x83E1 # 0 +0x0000DDD6 0x845C # 0 +0x0000DDD7 0x8451 # 0 +0x0000DDD8 0x845A # 0 +0x0000DDD9 0x8459 # 0 +0x0000DDDA 0x8473 # 0 +0x0000DDDB 0x8487 # 0 +0x0000DDDC 0x8488 # 0 +0x0000DDDD 0x847A # 0 +0x0000DDDE 0x8489 # 0 +0x0000DDDF 0x8478 # 0 +0x0000DDE0 0x843C # 0 +0x0000DDE1 0x8446 # 0 +0x0000DDE2 0x8469 # 0 +0x0000DDE3 0x8476 # 0 +0x0000DDE4 0x848C # 0 +0x0000DDE5 0x848E # 0 +0x0000DDE6 0x8431 # 0 +0x0000DDE7 0x846D # 0 +0x0000DDE8 0x84C1 # 0 +0x0000DDE9 0x84CD # 0 +0x0000DDEA 0x84D0 # 0 +0x0000DDEB 0x84E6 # 0 +0x0000DDEC 0x84BD # 0 +0x0000DDED 0x84D3 # 0 +0x0000DDEE 0x84CA # 0 +0x0000DDEF 0x84BF # 0 +0x0000DDF0 0x84BA # 0 +0x0000DDF1 0x84E0 # 0 +0x0000DDF2 0x84A1 # 0 +0x0000DDF3 0x84B9 # 0 +0x0000DDF4 0x84B4 # 0 +0x0000DDF5 0x8497 # 0 +0x0000DDF6 0x84E5 # 0 +0x0000DDF7 0x84E3 # 0 +0x0000DDF8 0x850C # 0 +0x0000DDF9 0x750D # 0 +0x0000DDFA 0x8538 # 0 +0x0000DDFB 0x84F0 # 0 +0x0000DDFC 0x8539 # 0 +0x0000DDFD 0x851F # 0 +0x0000DDFE 0x853A # 0 +0x0000DEA1 0x8556 # 0 +0x0000DEA2 0x853B # 0 +0x0000DEA3 0x84FF # 0 +0x0000DEA4 0x84FC # 0 +0x0000DEA5 0x8559 # 0 +0x0000DEA6 0x8548 # 0 +0x0000DEA7 0x8568 # 0 +0x0000DEA8 0x8564 # 0 +0x0000DEA9 0x855E # 0 +0x0000DEAA 0x857A # 0 +0x0000DEAB 0x77A2 # 0 +0x0000DEAC 0x8543 # 0 +0x0000DEAD 0x8572 # 0 +0x0000DEAE 0x857B # 0 +0x0000DEAF 0x85A4 # 0 +0x0000DEB0 0x85A8 # 0 +0x0000DEB1 0x8587 # 0 +0x0000DEB2 0x858F # 0 +0x0000DEB3 0x8579 # 0 +0x0000DEB4 0x85AE # 0 +0x0000DEB5 0x859C # 0 +0x0000DEB6 0x8585 # 0 +0x0000DEB7 0x85B9 # 0 +0x0000DEB8 0x85B7 # 0 +0x0000DEB9 0x85B0 # 0 +0x0000DEBA 0x85D3 # 0 +0x0000DEBB 0x85C1 # 0 +0x0000DEBC 0x85DC # 0 +0x0000DEBD 0x85FF # 0 +0x0000DEBE 0x8627 # 0 +0x0000DEBF 0x8605 # 0 +0x0000DEC0 0x8629 # 0 +0x0000DEC1 0x8616 # 0 +0x0000DEC2 0x863C # 0 +0x0000DEC3 0x5EFE # 0 +0x0000DEC4 0x5F08 # 0 +0x0000DEC5 0x593C # 0 +0x0000DEC6 0x5941 # 0 +0x0000DEC7 0x8037 # 0 +0x0000DEC8 0x5955 # 0 +0x0000DEC9 0x595A # 0 +0x0000DECA 0x5958 # 0 +0x0000DECB 0x530F # 0 +0x0000DECC 0x5C22 # 0 +0x0000DECD 0x5C25 # 0 +0x0000DECE 0x5C2C # 0 +0x0000DECF 0x5C34 # 0 +0x0000DED0 0x624C # 0 +0x0000DED1 0x626A # 0 +0x0000DED2 0x629F # 0 +0x0000DED3 0x62BB # 0 +0x0000DED4 0x62CA # 0 +0x0000DED5 0x62DA # 0 +0x0000DED6 0x62D7 # 0 +0x0000DED7 0x62EE # 0 +0x0000DED8 0x6322 # 0 +0x0000DED9 0x62F6 # 0 +0x0000DEDA 0x6339 # 0 +0x0000DEDB 0x634B # 0 +0x0000DEDC 0x6343 # 0 +0x0000DEDD 0x63AD # 0 +0x0000DEDE 0x63F6 # 0 +0x0000DEDF 0x6371 # 0 +0x0000DEE0 0x637A # 0 +0x0000DEE1 0x638E # 0 +0x0000DEE2 0x63B4 # 0 +0x0000DEE3 0x636D # 0 +0x0000DEE4 0x63AC # 0 +0x0000DEE5 0x638A # 0 +0x0000DEE6 0x6369 # 0 +0x0000DEE7 0x63AE # 0 +0x0000DEE8 0x63BC # 0 +0x0000DEE9 0x63F2 # 0 +0x0000DEEA 0x63F8 # 0 +0x0000DEEB 0x63E0 # 0 +0x0000DEEC 0x63FF # 0 +0x0000DEED 0x63C4 # 0 +0x0000DEEE 0x63DE # 0 +0x0000DEEF 0x63CE # 0 +0x0000DEF0 0x6452 # 0 +0x0000DEF1 0x63C6 # 0 +0x0000DEF2 0x63BE # 0 +0x0000DEF3 0x6445 # 0 +0x0000DEF4 0x6441 # 0 +0x0000DEF5 0x640B # 0 +0x0000DEF6 0x641B # 0 +0x0000DEF7 0x6420 # 0 +0x0000DEF8 0x640C # 0 +0x0000DEF9 0x6426 # 0 +0x0000DEFA 0x6421 # 0 +0x0000DEFB 0x645E # 0 +0x0000DEFC 0x6484 # 0 +0x0000DEFD 0x646D # 0 +0x0000DEFE 0x6496 # 0 +0x0000DFA1 0x647A # 0 +0x0000DFA2 0x64B7 # 0 +0x0000DFA3 0x64B8 # 0 +0x0000DFA4 0x6499 # 0 +0x0000DFA5 0x64BA # 0 +0x0000DFA6 0x64C0 # 0 +0x0000DFA7 0x64D0 # 0 +0x0000DFA8 0x64D7 # 0 +0x0000DFA9 0x64E4 # 0 +0x0000DFAA 0x64E2 # 0 +0x0000DFAB 0x6509 # 0 +0x0000DFAC 0x6525 # 0 +0x0000DFAD 0x652E # 0 +0x0000DFAE 0x5F0B # 0 +0x0000DFAF 0x5FD2 # 0 +0x0000DFB0 0x7519 # 0 +0x0000DFB1 0x5F11 # 0 +0x0000DFB2 0x535F # 0 +0x0000DFB3 0x53F1 # 0 +0x0000DFB4 0x53FD # 0 +0x0000DFB5 0x53E9 # 0 +0x0000DFB6 0x53E8 # 0 +0x0000DFB7 0x53FB # 0 +0x0000DFB8 0x5412 # 0 +0x0000DFB9 0x5416 # 0 +0x0000DFBA 0x5406 # 0 +0x0000DFBB 0x544B # 0 +0x0000DFBC 0x5452 # 0 +0x0000DFBD 0x5453 # 0 +0x0000DFBE 0x5454 # 0 +0x0000DFBF 0x5456 # 0 +0x0000DFC0 0x5443 # 0 +0x0000DFC1 0x5421 # 0 +0x0000DFC2 0x5457 # 0 +0x0000DFC3 0x5459 # 0 +0x0000DFC4 0x5423 # 0 +0x0000DFC5 0x5432 # 0 +0x0000DFC6 0x5482 # 0 +0x0000DFC7 0x5494 # 0 +0x0000DFC8 0x5477 # 0 +0x0000DFC9 0x5471 # 0 +0x0000DFCA 0x5464 # 0 +0x0000DFCB 0x549A # 0 +0x0000DFCC 0x549B # 0 +0x0000DFCD 0x5484 # 0 +0x0000DFCE 0x5476 # 0 +0x0000DFCF 0x5466 # 0 +0x0000DFD0 0x549D # 0 +0x0000DFD1 0x54D0 # 0 +0x0000DFD2 0x54AD # 0 +0x0000DFD3 0x54C2 # 0 +0x0000DFD4 0x54B4 # 0 +0x0000DFD5 0x54D2 # 0 +0x0000DFD6 0x54A7 # 0 +0x0000DFD7 0x54A6 # 0 +0x0000DFD8 0x54D3 # 0 +0x0000DFD9 0x54D4 # 0 +0x0000DFDA 0x5472 # 0 +0x0000DFDB 0x54A3 # 0 +0x0000DFDC 0x54D5 # 0 +0x0000DFDD 0x54BB # 0 +0x0000DFDE 0x54BF # 0 +0x0000DFDF 0x54CC # 0 +0x0000DFE0 0x54D9 # 0 +0x0000DFE1 0x54DA # 0 +0x0000DFE2 0x54DC # 0 +0x0000DFE3 0x54A9 # 0 +0x0000DFE4 0x54AA # 0 +0x0000DFE5 0x54A4 # 0 +0x0000DFE6 0x54DD # 0 +0x0000DFE7 0x54CF # 0 +0x0000DFE8 0x54DE # 0 +0x0000DFE9 0x551B # 0 +0x0000DFEA 0x54E7 # 0 +0x0000DFEB 0x5520 # 0 +0x0000DFEC 0x54FD # 0 +0x0000DFED 0x5514 # 0 +0x0000DFEE 0x54F3 # 0 +0x0000DFEF 0x5522 # 0 +0x0000DFF0 0x5523 # 0 +0x0000DFF1 0x550F # 0 +0x0000DFF2 0x5511 # 0 +0x0000DFF3 0x5527 # 0 +0x0000DFF4 0x552A # 0 +0x0000DFF5 0x5567 # 0 +0x0000DFF6 0x558F # 0 +0x0000DFF7 0x55B5 # 0 +0x0000DFF8 0x5549 # 0 +0x0000DFF9 0x556D # 0 +0x0000DFFA 0x5541 # 0 +0x0000DFFB 0x5555 # 0 +0x0000DFFC 0x553F # 0 +0x0000DFFD 0x5550 # 0 +0x0000DFFE 0x553C # 0 +0x0000E0A1 0x5537 # 0 +0x0000E0A2 0x5556 # 0 +0x0000E0A3 0x5575 # 0 +0x0000E0A4 0x5576 # 0 +0x0000E0A5 0x5577 # 0 +0x0000E0A6 0x5533 # 0 +0x0000E0A7 0x5530 # 0 +0x0000E0A8 0x555C # 0 +0x0000E0A9 0x558B # 0 +0x0000E0AA 0x55D2 # 0 +0x0000E0AB 0x5583 # 0 +0x0000E0AC 0x55B1 # 0 +0x0000E0AD 0x55B9 # 0 +0x0000E0AE 0x5588 # 0 +0x0000E0AF 0x5581 # 0 +0x0000E0B0 0x559F # 0 +0x0000E0B1 0x557E # 0 +0x0000E0B2 0x55D6 # 0 +0x0000E0B3 0x5591 # 0 +0x0000E0B4 0x557B # 0 +0x0000E0B5 0x55DF # 0 +0x0000E0B6 0x55BD # 0 +0x0000E0B7 0x55BE # 0 +0x0000E0B8 0x5594 # 0 +0x0000E0B9 0x5599 # 0 +0x0000E0BA 0x55EA # 0 +0x0000E0BB 0x55F7 # 0 +0x0000E0BC 0x55C9 # 0 +0x0000E0BD 0x561F # 0 +0x0000E0BE 0x55D1 # 0 +0x0000E0BF 0x55EB # 0 +0x0000E0C0 0x55EC # 0 +0x0000E0C1 0x55D4 # 0 +0x0000E0C2 0x55E6 # 0 +0x0000E0C3 0x55DD # 0 +0x0000E0C4 0x55C4 # 0 +0x0000E0C5 0x55EF # 0 +0x0000E0C6 0x55E5 # 0 +0x0000E0C7 0x55F2 # 0 +0x0000E0C8 0x55F3 # 0 +0x0000E0C9 0x55CC # 0 +0x0000E0CA 0x55CD # 0 +0x0000E0CB 0x55E8 # 0 +0x0000E0CC 0x55F5 # 0 +0x0000E0CD 0x55E4 # 0 +0x0000E0CE 0x8F94 # 0 +0x0000E0CF 0x561E # 0 +0x0000E0D0 0x5608 # 0 +0x0000E0D1 0x560C # 0 +0x0000E0D2 0x5601 # 0 +0x0000E0D3 0x5624 # 0 +0x0000E0D4 0x5623 # 0 +0x0000E0D5 0x55FE # 0 +0x0000E0D6 0x5600 # 0 +0x0000E0D7 0x5627 # 0 +0x0000E0D8 0x562D # 0 +0x0000E0D9 0x5658 # 0 +0x0000E0DA 0x5639 # 0 +0x0000E0DB 0x5657 # 0 +0x0000E0DC 0x562C # 0 +0x0000E0DD 0x564D # 0 +0x0000E0DE 0x5662 # 0 +0x0000E0DF 0x5659 # 0 +0x0000E0E0 0x565C # 0 +0x0000E0E1 0x564C # 0 +0x0000E0E2 0x5654 # 0 +0x0000E0E3 0x5686 # 0 +0x0000E0E4 0x5664 # 0 +0x0000E0E5 0x5671 # 0 +0x0000E0E6 0x566B # 0 +0x0000E0E7 0x567B # 0 +0x0000E0E8 0x567C # 0 +0x0000E0E9 0x5685 # 0 +0x0000E0EA 0x5693 # 0 +0x0000E0EB 0x56AF # 0 +0x0000E0EC 0x56D4 # 0 +0x0000E0ED 0x56D7 # 0 +0x0000E0EE 0x56DD # 0 +0x0000E0EF 0x56E1 # 0 +0x0000E0F0 0x56F5 # 0 +0x0000E0F1 0x56EB # 0 +0x0000E0F2 0x56F9 # 0 +0x0000E0F3 0x56FF # 0 +0x0000E0F4 0x5704 # 0 +0x0000E0F5 0x570A # 0 +0x0000E0F6 0x5709 # 0 +0x0000E0F7 0x571C # 0 +0x0000E0F8 0x5E0F # 0 +0x0000E0F9 0x5E19 # 0 +0x0000E0FA 0x5E14 # 0 +0x0000E0FB 0x5E11 # 0 +0x0000E0FC 0x5E31 # 0 +0x0000E0FD 0x5E3B # 0 +0x0000E0FE 0x5E3C # 0 +0x0000E1A1 0x5E37 # 0 +0x0000E1A2 0x5E44 # 0 +0x0000E1A3 0x5E54 # 0 +0x0000E1A4 0x5E5B # 0 +0x0000E1A5 0x5E5E # 0 +0x0000E1A6 0x5E61 # 0 +0x0000E1A7 0x5C8C # 0 +0x0000E1A8 0x5C7A # 0 +0x0000E1A9 0x5C8D # 0 +0x0000E1AA 0x5C90 # 0 +0x0000E1AB 0x5C96 # 0 +0x0000E1AC 0x5C88 # 0 +0x0000E1AD 0x5C98 # 0 +0x0000E1AE 0x5C99 # 0 +0x0000E1AF 0x5C91 # 0 +0x0000E1B0 0x5C9A # 0 +0x0000E1B1 0x5C9C # 0 +0x0000E1B2 0x5CB5 # 0 +0x0000E1B3 0x5CA2 # 0 +0x0000E1B4 0x5CBD # 0 +0x0000E1B5 0x5CAC # 0 +0x0000E1B6 0x5CAB # 0 +0x0000E1B7 0x5CB1 # 0 +0x0000E1B8 0x5CA3 # 0 +0x0000E1B9 0x5CC1 # 0 +0x0000E1BA 0x5CB7 # 0 +0x0000E1BB 0x5CC4 # 0 +0x0000E1BC 0x5CD2 # 0 +0x0000E1BD 0x5CE4 # 0 +0x0000E1BE 0x5CCB # 0 +0x0000E1BF 0x5CE5 # 0 +0x0000E1C0 0x5D02 # 0 +0x0000E1C1 0x5D03 # 0 +0x0000E1C2 0x5D27 # 0 +0x0000E1C3 0x5D26 # 0 +0x0000E1C4 0x5D2E # 0 +0x0000E1C5 0x5D24 # 0 +0x0000E1C6 0x5D1E # 0 +0x0000E1C7 0x5D06 # 0 +0x0000E1C8 0x5D1B # 0 +0x0000E1C9 0x5D58 # 0 +0x0000E1CA 0x5D3E # 0 +0x0000E1CB 0x5D34 # 0 +0x0000E1CC 0x5D3D # 0 +0x0000E1CD 0x5D6C # 0 +0x0000E1CE 0x5D5B # 0 +0x0000E1CF 0x5D6F # 0 +0x0000E1D0 0x5D5D # 0 +0x0000E1D1 0x5D6B # 0 +0x0000E1D2 0x5D4B # 0 +0x0000E1D3 0x5D4A # 0 +0x0000E1D4 0x5D69 # 0 +0x0000E1D5 0x5D74 # 0 +0x0000E1D6 0x5D82 # 0 +0x0000E1D7 0x5D99 # 0 +0x0000E1D8 0x5D9D # 0 +0x0000E1D9 0x8C73 # 0 +0x0000E1DA 0x5DB7 # 0 +0x0000E1DB 0x5DC5 # 0 +0x0000E1DC 0x5F73 # 0 +0x0000E1DD 0x5F77 # 0 +0x0000E1DE 0x5F82 # 0 +0x0000E1DF 0x5F87 # 0 +0x0000E1E0 0x5F89 # 0 +0x0000E1E1 0x5F8C # 0 +0x0000E1E2 0x5F95 # 0 +0x0000E1E3 0x5F99 # 0 +0x0000E1E4 0x5F9C # 0 +0x0000E1E5 0x5FA8 # 0 +0x0000E1E6 0x5FAD # 0 +0x0000E1E7 0x5FB5 # 0 +0x0000E1E8 0x5FBC # 0 +0x0000E1E9 0x8862 # 0 +0x0000E1EA 0x5F61 # 0 +0x0000E1EB 0x72AD # 0 +0x0000E1EC 0x72B0 # 0 +0x0000E1ED 0x72B4 # 0 +0x0000E1EE 0x72B7 # 0 +0x0000E1EF 0x72B8 # 0 +0x0000E1F0 0x72C3 # 0 +0x0000E1F1 0x72C1 # 0 +0x0000E1F2 0x72CE # 0 +0x0000E1F3 0x72CD # 0 +0x0000E1F4 0x72D2 # 0 +0x0000E1F5 0x72E8 # 0 +0x0000E1F6 0x72EF # 0 +0x0000E1F7 0x72E9 # 0 +0x0000E1F8 0x72F2 # 0 +0x0000E1F9 0x72F4 # 0 +0x0000E1FA 0x72F7 # 0 +0x0000E1FB 0x7301 # 0 +0x0000E1FC 0x72F3 # 0 +0x0000E1FD 0x7303 # 0 +0x0000E1FE 0x72FA # 0 +0x0000E2A1 0x72FB # 0 +0x0000E2A2 0x7317 # 0 +0x0000E2A3 0x7313 # 0 +0x0000E2A4 0x7321 # 0 +0x0000E2A5 0x730A # 0 +0x0000E2A6 0x731E # 0 +0x0000E2A7 0x731D # 0 +0x0000E2A8 0x7315 # 0 +0x0000E2A9 0x7322 # 0 +0x0000E2AA 0x7339 # 0 +0x0000E2AB 0x7325 # 0 +0x0000E2AC 0x732C # 0 +0x0000E2AD 0x7338 # 0 +0x0000E2AE 0x7331 # 0 +0x0000E2AF 0x7350 # 0 +0x0000E2B0 0x734D # 0 +0x0000E2B1 0x7357 # 0 +0x0000E2B2 0x7360 # 0 +0x0000E2B3 0x736C # 0 +0x0000E2B4 0x736F # 0 +0x0000E2B5 0x737E # 0 +0x0000E2B6 0x821B # 0 +0x0000E2B7 0x5925 # 0 +0x0000E2B8 0x98E7 # 0 +0x0000E2B9 0x5924 # 0 +0x0000E2BA 0x5902 # 0 +0x0000E2BB 0x9963 # 0 +0x0000E2BC 0x9967 # 0 +0x0000E2BD 0x9968 # 0 +0x0000E2BE 0x9969 # 0 +0x0000E2BF 0x996A # 0 +0x0000E2C0 0x996B # 0 +0x0000E2C1 0x996C # 0 +0x0000E2C2 0x9974 # 0 +0x0000E2C3 0x9977 # 0 +0x0000E2C4 0x997D # 0 +0x0000E2C5 0x9980 # 0 +0x0000E2C6 0x9984 # 0 +0x0000E2C7 0x9987 # 0 +0x0000E2C8 0x998A # 0 +0x0000E2C9 0x998D # 0 +0x0000E2CA 0x9990 # 0 +0x0000E2CB 0x9991 # 0 +0x0000E2CC 0x9993 # 0 +0x0000E2CD 0x9994 # 0 +0x0000E2CE 0x9995 # 0 +0x0000E2CF 0x5E80 # 0 +0x0000E2D0 0x5E91 # 0 +0x0000E2D1 0x5E8B # 0 +0x0000E2D2 0x5E96 # 0 +0x0000E2D3 0x5EA5 # 0 +0x0000E2D4 0x5EA0 # 0 +0x0000E2D5 0x5EB9 # 0 +0x0000E2D6 0x5EB5 # 0 +0x0000E2D7 0x5EBE # 0 +0x0000E2D8 0x5EB3 # 0 +0x0000E2D9 0x8D53 # 0 +0x0000E2DA 0x5ED2 # 0 +0x0000E2DB 0x5ED1 # 0 +0x0000E2DC 0x5EDB # 0 +0x0000E2DD 0x5EE8 # 0 +0x0000E2DE 0x5EEA # 0 +0x0000E2DF 0x81BA # 0 +0x0000E2E0 0x5FC4 # 0 +0x0000E2E1 0x5FC9 # 0 +0x0000E2E2 0x5FD6 # 0 +0x0000E2E3 0x5FCF # 0 +0x0000E2E4 0x6003 # 0 +0x0000E2E5 0x5FEE # 0 +0x0000E2E6 0x6004 # 0 +0x0000E2E7 0x5FE1 # 0 +0x0000E2E8 0x5FE4 # 0 +0x0000E2E9 0x5FFE # 0 +0x0000E2EA 0x6005 # 0 +0x0000E2EB 0x6006 # 0 +0x0000E2EC 0x5FEA # 0 +0x0000E2ED 0x5FED # 0 +0x0000E2EE 0x5FF8 # 0 +0x0000E2EF 0x6019 # 0 +0x0000E2F0 0x6035 # 0 +0x0000E2F1 0x6026 # 0 +0x0000E2F2 0x601B # 0 +0x0000E2F3 0x600F # 0 +0x0000E2F4 0x600D # 0 +0x0000E2F5 0x6029 # 0 +0x0000E2F6 0x602B # 0 +0x0000E2F7 0x600A # 0 +0x0000E2F8 0x603F # 0 +0x0000E2F9 0x6021 # 0 +0x0000E2FA 0x6078 # 0 +0x0000E2FB 0x6079 # 0 +0x0000E2FC 0x607B # 0 +0x0000E2FD 0x607A # 0 +0x0000E2FE 0x6042 # 0 +0x0000E3A1 0x606A # 0 +0x0000E3A2 0x607D # 0 +0x0000E3A3 0x6096 # 0 +0x0000E3A4 0x609A # 0 +0x0000E3A5 0x60AD # 0 +0x0000E3A6 0x609D # 0 +0x0000E3A7 0x6083 # 0 +0x0000E3A8 0x6092 # 0 +0x0000E3A9 0x608C # 0 +0x0000E3AA 0x609B # 0 +0x0000E3AB 0x60EC # 0 +0x0000E3AC 0x60BB # 0 +0x0000E3AD 0x60B1 # 0 +0x0000E3AE 0x60DD # 0 +0x0000E3AF 0x60D8 # 0 +0x0000E3B0 0x60C6 # 0 +0x0000E3B1 0x60DA # 0 +0x0000E3B2 0x60B4 # 0 +0x0000E3B3 0x6120 # 0 +0x0000E3B4 0x6126 # 0 +0x0000E3B5 0x6115 # 0 +0x0000E3B6 0x6123 # 0 +0x0000E3B7 0x60F4 # 0 +0x0000E3B8 0x6100 # 0 +0x0000E3B9 0x610E # 0 +0x0000E3BA 0x612B # 0 +0x0000E3BB 0x614A # 0 +0x0000E3BC 0x6175 # 0 +0x0000E3BD 0x61AC # 0 +0x0000E3BE 0x6194 # 0 +0x0000E3BF 0x61A7 # 0 +0x0000E3C0 0x61B7 # 0 +0x0000E3C1 0x61D4 # 0 +0x0000E3C2 0x61F5 # 0 +0x0000E3C3 0x5FDD # 0 +0x0000E3C4 0x96B3 # 0 +0x0000E3C5 0x95E9 # 0 +0x0000E3C6 0x95EB # 0 +0x0000E3C7 0x95F1 # 0 +0x0000E3C8 0x95F3 # 0 +0x0000E3C9 0x95F5 # 0 +0x0000E3CA 0x95F6 # 0 +0x0000E3CB 0x95FC # 0 +0x0000E3CC 0x95FE # 0 +0x0000E3CD 0x9603 # 0 +0x0000E3CE 0x9604 # 0 +0x0000E3CF 0x9606 # 0 +0x0000E3D0 0x9608 # 0 +0x0000E3D1 0x960A # 0 +0x0000E3D2 0x960B # 0 +0x0000E3D3 0x960C # 0 +0x0000E3D4 0x960D # 0 +0x0000E3D5 0x960F # 0 +0x0000E3D6 0x9612 # 0 +0x0000E3D7 0x9615 # 0 +0x0000E3D8 0x9616 # 0 +0x0000E3D9 0x9617 # 0 +0x0000E3DA 0x9619 # 0 +0x0000E3DB 0x961A # 0 +0x0000E3DC 0x4E2C # 0 +0x0000E3DD 0x723F # 0 +0x0000E3DE 0x6215 # 0 +0x0000E3DF 0x6C35 # 0 +0x0000E3E0 0x6C54 # 0 +0x0000E3E1 0x6C5C # 0 +0x0000E3E2 0x6C4A # 0 +0x0000E3E3 0x6CA3 # 0 +0x0000E3E4 0x6C85 # 0 +0x0000E3E5 0x6C90 # 0 +0x0000E3E6 0x6C94 # 0 +0x0000E3E7 0x6C8C # 0 +0x0000E3E8 0x6C68 # 0 +0x0000E3E9 0x6C69 # 0 +0x0000E3EA 0x6C74 # 0 +0x0000E3EB 0x6C76 # 0 +0x0000E3EC 0x6C86 # 0 +0x0000E3ED 0x6CA9 # 0 +0x0000E3EE 0x6CD0 # 0 +0x0000E3EF 0x6CD4 # 0 +0x0000E3F0 0x6CAD # 0 +0x0000E3F1 0x6CF7 # 0 +0x0000E3F2 0x6CF8 # 0 +0x0000E3F3 0x6CF1 # 0 +0x0000E3F4 0x6CD7 # 0 +0x0000E3F5 0x6CB2 # 0 +0x0000E3F6 0x6CE0 # 0 +0x0000E3F7 0x6CD6 # 0 +0x0000E3F8 0x6CFA # 0 +0x0000E3F9 0x6CEB # 0 +0x0000E3FA 0x6CEE # 0 +0x0000E3FB 0x6CB1 # 0 +0x0000E3FC 0x6CD3 # 0 +0x0000E3FD 0x6CEF # 0 +0x0000E3FE 0x6CFE # 0 +0x0000E4A1 0x6D39 # 0 +0x0000E4A2 0x6D27 # 0 +0x0000E4A3 0x6D0C # 0 +0x0000E4A4 0x6D43 # 0 +0x0000E4A5 0x6D48 # 0 +0x0000E4A6 0x6D07 # 0 +0x0000E4A7 0x6D04 # 0 +0x0000E4A8 0x6D19 # 0 +0x0000E4A9 0x6D0E # 0 +0x0000E4AA 0x6D2B # 0 +0x0000E4AB 0x6D4D # 0 +0x0000E4AC 0x6D2E # 0 +0x0000E4AD 0x6D35 # 0 +0x0000E4AE 0x6D1A # 0 +0x0000E4AF 0x6D4F # 0 +0x0000E4B0 0x6D52 # 0 +0x0000E4B1 0x6D54 # 0 +0x0000E4B2 0x6D33 # 0 +0x0000E4B3 0x6D91 # 0 +0x0000E4B4 0x6D6F # 0 +0x0000E4B5 0x6D9E # 0 +0x0000E4B6 0x6DA0 # 0 +0x0000E4B7 0x6D5E # 0 +0x0000E4B8 0x6D93 # 0 +0x0000E4B9 0x6D94 # 0 +0x0000E4BA 0x6D5C # 0 +0x0000E4BB 0x6D60 # 0 +0x0000E4BC 0x6D7C # 0 +0x0000E4BD 0x6D63 # 0 +0x0000E4BE 0x6E1A # 0 +0x0000E4BF 0x6DC7 # 0 +0x0000E4C0 0x6DC5 # 0 +0x0000E4C1 0x6DDE # 0 +0x0000E4C2 0x6E0E # 0 +0x0000E4C3 0x6DBF # 0 +0x0000E4C4 0x6DE0 # 0 +0x0000E4C5 0x6E11 # 0 +0x0000E4C6 0x6DE6 # 0 +0x0000E4C7 0x6DDD # 0 +0x0000E4C8 0x6DD9 # 0 +0x0000E4C9 0x6E16 # 0 +0x0000E4CA 0x6DAB # 0 +0x0000E4CB 0x6E0C # 0 +0x0000E4CC 0x6DAE # 0 +0x0000E4CD 0x6E2B # 0 +0x0000E4CE 0x6E6E # 0 +0x0000E4CF 0x6E4E # 0 +0x0000E4D0 0x6E6B # 0 +0x0000E4D1 0x6EB2 # 0 +0x0000E4D2 0x6E5F # 0 +0x0000E4D3 0x6E86 # 0 +0x0000E4D4 0x6E53 # 0 +0x0000E4D5 0x6E54 # 0 +0x0000E4D6 0x6E32 # 0 +0x0000E4D7 0x6E25 # 0 +0x0000E4D8 0x6E44 # 0 +0x0000E4D9 0x6EDF # 0 +0x0000E4DA 0x6EB1 # 0 +0x0000E4DB 0x6E98 # 0 +0x0000E4DC 0x6EE0 # 0 +0x0000E4DD 0x6F2D # 0 +0x0000E4DE 0x6EE2 # 0 +0x0000E4DF 0x6EA5 # 0 +0x0000E4E0 0x6EA7 # 0 +0x0000E4E1 0x6EBD # 0 +0x0000E4E2 0x6EBB # 0 +0x0000E4E3 0x6EB7 # 0 +0x0000E4E4 0x6ED7 # 0 +0x0000E4E5 0x6EB4 # 0 +0x0000E4E6 0x6ECF # 0 +0x0000E4E7 0x6E8F # 0 +0x0000E4E8 0x6EC2 # 0 +0x0000E4E9 0x6E9F # 0 +0x0000E4EA 0x6F62 # 0 +0x0000E4EB 0x6F46 # 0 +0x0000E4EC 0x6F47 # 0 +0x0000E4ED 0x6F24 # 0 +0x0000E4EE 0x6F15 # 0 +0x0000E4EF 0x6EF9 # 0 +0x0000E4F0 0x6F2F # 0 +0x0000E4F1 0x6F36 # 0 +0x0000E4F2 0x6F4B # 0 +0x0000E4F3 0x6F74 # 0 +0x0000E4F4 0x6F2A # 0 +0x0000E4F5 0x6F09 # 0 +0x0000E4F6 0x6F29 # 0 +0x0000E4F7 0x6F89 # 0 +0x0000E4F8 0x6F8D # 0 +0x0000E4F9 0x6F8C # 0 +0x0000E4FA 0x6F78 # 0 +0x0000E4FB 0x6F72 # 0 +0x0000E4FC 0x6F7C # 0 +0x0000E4FD 0x6F7A # 0 +0x0000E4FE 0x6FD1 # 0 +0x0000E5A1 0x6FC9 # 0 +0x0000E5A2 0x6FA7 # 0 +0x0000E5A3 0x6FB9 # 0 +0x0000E5A4 0x6FB6 # 0 +0x0000E5A5 0x6FC2 # 0 +0x0000E5A6 0x6FE1 # 0 +0x0000E5A7 0x6FEE # 0 +0x0000E5A8 0x6FDE # 0 +0x0000E5A9 0x6FE0 # 0 +0x0000E5AA 0x6FEF # 0 +0x0000E5AB 0x701A # 0 +0x0000E5AC 0x7023 # 0 +0x0000E5AD 0x701B # 0 +0x0000E5AE 0x7039 # 0 +0x0000E5AF 0x7035 # 0 +0x0000E5B0 0x704F # 0 +0x0000E5B1 0x705E # 0 +0x0000E5B2 0x5B80 # 0 +0x0000E5B3 0x5B84 # 0 +0x0000E5B4 0x5B95 # 0 +0x0000E5B5 0x5B93 # 0 +0x0000E5B6 0x5BA5 # 0 +0x0000E5B7 0x5BB8 # 0 +0x0000E5B8 0x752F # 0 +0x0000E5B9 0x9A9E # 0 +0x0000E5BA 0x6434 # 0 +0x0000E5BB 0x5BE4 # 0 +0x0000E5BC 0x5BEE # 0 +0x0000E5BD 0x8930 # 0 +0x0000E5BE 0x5BF0 # 0 +0x0000E5BF 0x8E47 # 0 +0x0000E5C0 0x8B07 # 0 +0x0000E5C1 0x8FB6 # 0 +0x0000E5C2 0x8FD3 # 0 +0x0000E5C3 0x8FD5 # 0 +0x0000E5C4 0x8FE5 # 0 +0x0000E5C5 0x8FEE # 0 +0x0000E5C6 0x8FE4 # 0 +0x0000E5C7 0x8FE9 # 0 +0x0000E5C8 0x8FE6 # 0 +0x0000E5C9 0x8FF3 # 0 +0x0000E5CA 0x8FE8 # 0 +0x0000E5CB 0x9005 # 0 +0x0000E5CC 0x9004 # 0 +0x0000E5CD 0x900B # 0 +0x0000E5CE 0x9026 # 0 +0x0000E5CF 0x9011 # 0 +0x0000E5D0 0x900D # 0 +0x0000E5D1 0x9016 # 0 +0x0000E5D2 0x9021 # 0 +0x0000E5D3 0x9035 # 0 +0x0000E5D4 0x9036 # 0 +0x0000E5D5 0x902D # 0 +0x0000E5D6 0x902F # 0 +0x0000E5D7 0x9044 # 0 +0x0000E5D8 0x9051 # 0 +0x0000E5D9 0x9052 # 0 +0x0000E5DA 0x9050 # 0 +0x0000E5DB 0x9068 # 0 +0x0000E5DC 0x9058 # 0 +0x0000E5DD 0x9062 # 0 +0x0000E5DE 0x905B # 0 +0x0000E5DF 0x66B9 # 0 +0x0000E5E0 0x9074 # 0 +0x0000E5E1 0x907D # 0 +0x0000E5E2 0x9082 # 0 +0x0000E5E3 0x9088 # 0 +0x0000E5E4 0x9083 # 0 +0x0000E5E5 0x908B # 0 +0x0000E5E6 0x5F50 # 0 +0x0000E5E7 0x5F57 # 0 +0x0000E5E8 0x5F56 # 0 +0x0000E5E9 0x5F58 # 0 +0x0000E5EA 0x5C3B # 0 +0x0000E5EB 0x54AB # 0 +0x0000E5EC 0x5C50 # 0 +0x0000E5ED 0x5C59 # 0 +0x0000E5EE 0x5B71 # 0 +0x0000E5EF 0x5C63 # 0 +0x0000E5F0 0x5C66 # 0 +0x0000E5F1 0x7FBC # 0 +0x0000E5F2 0x5F2A # 0 +0x0000E5F3 0x5F29 # 0 +0x0000E5F4 0x5F2D # 0 +0x0000E5F5 0x8274 # 0 +0x0000E5F6 0x5F3C # 0 +0x0000E5F7 0x9B3B # 0 +0x0000E5F8 0x5C6E # 0 +0x0000E5F9 0x5981 # 0 +0x0000E5FA 0x5983 # 0 +0x0000E5FB 0x598D # 0 +0x0000E5FC 0x59A9 # 0 +0x0000E5FD 0x59AA # 0 +0x0000E5FE 0x59A3 # 0 +0x0000E6A1 0x5997 # 0 +0x0000E6A2 0x59CA # 0 +0x0000E6A3 0x59AB # 0 +0x0000E6A4 0x599E # 0 +0x0000E6A5 0x59A4 # 0 +0x0000E6A6 0x59D2 # 0 +0x0000E6A7 0x59B2 # 0 +0x0000E6A8 0x59AF # 0 +0x0000E6A9 0x59D7 # 0 +0x0000E6AA 0x59BE # 0 +0x0000E6AB 0x5A05 # 0 +0x0000E6AC 0x5A06 # 0 +0x0000E6AD 0x59DD # 0 +0x0000E6AE 0x5A08 # 0 +0x0000E6AF 0x59E3 # 0 +0x0000E6B0 0x59D8 # 0 +0x0000E6B1 0x59F9 # 0 +0x0000E6B2 0x5A0C # 0 +0x0000E6B3 0x5A09 # 0 +0x0000E6B4 0x5A32 # 0 +0x0000E6B5 0x5A34 # 0 +0x0000E6B6 0x5A11 # 0 +0x0000E6B7 0x5A23 # 0 +0x0000E6B8 0x5A13 # 0 +0x0000E6B9 0x5A40 # 0 +0x0000E6BA 0x5A67 # 0 +0x0000E6BB 0x5A4A # 0 +0x0000E6BC 0x5A55 # 0 +0x0000E6BD 0x5A3C # 0 +0x0000E6BE 0x5A62 # 0 +0x0000E6BF 0x5A75 # 0 +0x0000E6C0 0x80EC # 0 +0x0000E6C1 0x5AAA # 0 +0x0000E6C2 0x5A9B # 0 +0x0000E6C3 0x5A77 # 0 +0x0000E6C4 0x5A7A # 0 +0x0000E6C5 0x5ABE # 0 +0x0000E6C6 0x5AEB # 0 +0x0000E6C7 0x5AB2 # 0 +0x0000E6C8 0x5AD2 # 0 +0x0000E6C9 0x5AD4 # 0 +0x0000E6CA 0x5AB8 # 0 +0x0000E6CB 0x5AE0 # 0 +0x0000E6CC 0x5AE3 # 0 +0x0000E6CD 0x5AF1 # 0 +0x0000E6CE 0x5AD6 # 0 +0x0000E6CF 0x5AE6 # 0 +0x0000E6D0 0x5AD8 # 0 +0x0000E6D1 0x5ADC # 0 +0x0000E6D2 0x5B09 # 0 +0x0000E6D3 0x5B17 # 0 +0x0000E6D4 0x5B16 # 0 +0x0000E6D5 0x5B32 # 0 +0x0000E6D6 0x5B37 # 0 +0x0000E6D7 0x5B40 # 0 +0x0000E6D8 0x5C15 # 0 +0x0000E6D9 0x5C1C # 0 +0x0000E6DA 0x5B5A # 0 +0x0000E6DB 0x5B65 # 0 +0x0000E6DC 0x5B73 # 0 +0x0000E6DD 0x5B51 # 0 +0x0000E6DE 0x5B53 # 0 +0x0000E6DF 0x5B62 # 0 +0x0000E6E0 0x9A75 # 0 +0x0000E6E1 0x9A77 # 0 +0x0000E6E2 0x9A78 # 0 +0x0000E6E3 0x9A7A # 0 +0x0000E6E4 0x9A7F # 0 +0x0000E6E5 0x9A7D # 0 +0x0000E6E6 0x9A80 # 0 +0x0000E6E7 0x9A81 # 0 +0x0000E6E8 0x9A85 # 0 +0x0000E6E9 0x9A88 # 0 +0x0000E6EA 0x9A8A # 0 +0x0000E6EB 0x9A90 # 0 +0x0000E6EC 0x9A92 # 0 +0x0000E6ED 0x9A93 # 0 +0x0000E6EE 0x9A96 # 0 +0x0000E6EF 0x9A98 # 0 +0x0000E6F0 0x9A9B # 0 +0x0000E6F1 0x9A9C # 0 +0x0000E6F2 0x9A9D # 0 +0x0000E6F3 0x9A9F # 0 +0x0000E6F4 0x9AA0 # 0 +0x0000E6F5 0x9AA2 # 0 +0x0000E6F6 0x9AA3 # 0 +0x0000E6F7 0x9AA5 # 0 +0x0000E6F8 0x9AA7 # 0 +0x0000E6F9 0x7E9F # 0 +0x0000E6FA 0x7EA1 # 0 +0x0000E6FB 0x7EA3 # 0 +0x0000E6FC 0x7EA5 # 0 +0x0000E6FD 0x7EA8 # 0 +0x0000E6FE 0x7EA9 # 0 +0x0000E7A1 0x7EAD # 0 +0x0000E7A2 0x7EB0 # 0 +0x0000E7A3 0x7EBE # 0 +0x0000E7A4 0x7EC0 # 0 +0x0000E7A5 0x7EC1 # 0 +0x0000E7A6 0x7EC2 # 0 +0x0000E7A7 0x7EC9 # 0 +0x0000E7A8 0x7ECB # 0 +0x0000E7A9 0x7ECC # 0 +0x0000E7AA 0x7ED0 # 0 +0x0000E7AB 0x7ED4 # 0 +0x0000E7AC 0x7ED7 # 0 +0x0000E7AD 0x7EDB # 0 +0x0000E7AE 0x7EE0 # 0 +0x0000E7AF 0x7EE1 # 0 +0x0000E7B0 0x7EE8 # 0 +0x0000E7B1 0x7EEB # 0 +0x0000E7B2 0x7EEE # 0 +0x0000E7B3 0x7EEF # 0 +0x0000E7B4 0x7EF1 # 0 +0x0000E7B5 0x7EF2 # 0 +0x0000E7B6 0x7F0D # 0 +0x0000E7B7 0x7EF6 # 0 +0x0000E7B8 0x7EFA # 0 +0x0000E7B9 0x7EFB # 0 +0x0000E7BA 0x7EFE # 0 +0x0000E7BB 0x7F01 # 0 +0x0000E7BC 0x7F02 # 0 +0x0000E7BD 0x7F03 # 0 +0x0000E7BE 0x7F07 # 0 +0x0000E7BF 0x7F08 # 0 +0x0000E7C0 0x7F0B # 0 +0x0000E7C1 0x7F0C # 0 +0x0000E7C2 0x7F0F # 0 +0x0000E7C3 0x7F11 # 0 +0x0000E7C4 0x7F12 # 0 +0x0000E7C5 0x7F17 # 0 +0x0000E7C6 0x7F19 # 0 +0x0000E7C7 0x7F1C # 0 +0x0000E7C8 0x7F1B # 0 +0x0000E7C9 0x7F1F # 0 +0x0000E7CA 0x7F21 # 0 +0x0000E7CB 0x7F22 # 0 +0x0000E7CC 0x7F23 # 0 +0x0000E7CD 0x7F24 # 0 +0x0000E7CE 0x7F25 # 0 +0x0000E7CF 0x7F26 # 0 +0x0000E7D0 0x7F27 # 0 +0x0000E7D1 0x7F2A # 0 +0x0000E7D2 0x7F2B # 0 +0x0000E7D3 0x7F2C # 0 +0x0000E7D4 0x7F2D # 0 +0x0000E7D5 0x7F2F # 0 +0x0000E7D6 0x7F30 # 0 +0x0000E7D7 0x7F31 # 0 +0x0000E7D8 0x7F32 # 0 +0x0000E7D9 0x7F33 # 0 +0x0000E7DA 0x7F35 # 0 +0x0000E7DB 0x5E7A # 0 +0x0000E7DC 0x757F # 0 +0x0000E7DD 0x5DDB # 0 +0x0000E7DE 0x753E # 0 +0x0000E7DF 0x9095 # 0 +0x0000E7E0 0x738E # 0 +0x0000E7E1 0x7391 # 0 +0x0000E7E2 0x73AE # 0 +0x0000E7E3 0x73A2 # 0 +0x0000E7E4 0x739F # 0 +0x0000E7E5 0x73CF # 0 +0x0000E7E6 0x73C2 # 0 +0x0000E7E7 0x73D1 # 0 +0x0000E7E8 0x73B7 # 0 +0x0000E7E9 0x73B3 # 0 +0x0000E7EA 0x73C0 # 0 +0x0000E7EB 0x73C9 # 0 +0x0000E7EC 0x73C8 # 0 +0x0000E7ED 0x73E5 # 0 +0x0000E7EE 0x73D9 # 0 +0x0000E7EF 0x987C # 0 +0x0000E7F0 0x740A # 0 +0x0000E7F1 0x73E9 # 0 +0x0000E7F2 0x73E7 # 0 +0x0000E7F3 0x73DE # 0 +0x0000E7F4 0x73BA # 0 +0x0000E7F5 0x73F2 # 0 +0x0000E7F6 0x740F # 0 +0x0000E7F7 0x742A # 0 +0x0000E7F8 0x745B # 0 +0x0000E7F9 0x7426 # 0 +0x0000E7FA 0x7425 # 0 +0x0000E7FB 0x7428 # 0 +0x0000E7FC 0x7430 # 0 +0x0000E7FD 0x742E # 0 +0x0000E7FE 0x742C # 0 +0x0000E8A1 0x741B # 0 +0x0000E8A2 0x741A # 0 +0x0000E8A3 0x7441 # 0 +0x0000E8A4 0x745C # 0 +0x0000E8A5 0x7457 # 0 +0x0000E8A6 0x7455 # 0 +0x0000E8A7 0x7459 # 0 +0x0000E8A8 0x7477 # 0 +0x0000E8A9 0x746D # 0 +0x0000E8AA 0x747E # 0 +0x0000E8AB 0x749C # 0 +0x0000E8AC 0x748E # 0 +0x0000E8AD 0x7480 # 0 +0x0000E8AE 0x7481 # 0 +0x0000E8AF 0x7487 # 0 +0x0000E8B0 0x748B # 0 +0x0000E8B1 0x749E # 0 +0x0000E8B2 0x74A8 # 0 +0x0000E8B3 0x74A9 # 0 +0x0000E8B4 0x7490 # 0 +0x0000E8B5 0x74A7 # 0 +0x0000E8B6 0x74D2 # 0 +0x0000E8B7 0x74BA # 0 +0x0000E8B8 0x97EA # 0 +0x0000E8B9 0x97EB # 0 +0x0000E8BA 0x97EC # 0 +0x0000E8BB 0x674C # 0 +0x0000E8BC 0x6753 # 0 +0x0000E8BD 0x675E # 0 +0x0000E8BE 0x6748 # 0 +0x0000E8BF 0x6769 # 0 +0x0000E8C0 0x67A5 # 0 +0x0000E8C1 0x6787 # 0 +0x0000E8C2 0x676A # 0 +0x0000E8C3 0x6773 # 0 +0x0000E8C4 0x6798 # 0 +0x0000E8C5 0x67A7 # 0 +0x0000E8C6 0x6775 # 0 +0x0000E8C7 0x67A8 # 0 +0x0000E8C8 0x679E # 0 +0x0000E8C9 0x67AD # 0 +0x0000E8CA 0x678B # 0 +0x0000E8CB 0x6777 # 0 +0x0000E8CC 0x677C # 0 +0x0000E8CD 0x67F0 # 0 +0x0000E8CE 0x6809 # 0 +0x0000E8CF 0x67D8 # 0 +0x0000E8D0 0x680A # 0 +0x0000E8D1 0x67E9 # 0 +0x0000E8D2 0x67B0 # 0 +0x0000E8D3 0x680C # 0 +0x0000E8D4 0x67D9 # 0 +0x0000E8D5 0x67B5 # 0 +0x0000E8D6 0x67DA # 0 +0x0000E8D7 0x67B3 # 0 +0x0000E8D8 0x67DD # 0 +0x0000E8D9 0x6800 # 0 +0x0000E8DA 0x67C3 # 0 +0x0000E8DB 0x67B8 # 0 +0x0000E8DC 0x67E2 # 0 +0x0000E8DD 0x680E # 0 +0x0000E8DE 0x67C1 # 0 +0x0000E8DF 0x67FD # 0 +0x0000E8E0 0x6832 # 0 +0x0000E8E1 0x6833 # 0 +0x0000E8E2 0x6860 # 0 +0x0000E8E3 0x6861 # 0 +0x0000E8E4 0x684E # 0 +0x0000E8E5 0x6862 # 0 +0x0000E8E6 0x6844 # 0 +0x0000E8E7 0x6864 # 0 +0x0000E8E8 0x6883 # 0 +0x0000E8E9 0x681D # 0 +0x0000E8EA 0x6855 # 0 +0x0000E8EB 0x6866 # 0 +0x0000E8EC 0x6841 # 0 +0x0000E8ED 0x6867 # 0 +0x0000E8EE 0x6840 # 0 +0x0000E8EF 0x683E # 0 +0x0000E8F0 0x684A # 0 +0x0000E8F1 0x6849 # 0 +0x0000E8F2 0x6829 # 0 +0x0000E8F3 0x68B5 # 0 +0x0000E8F4 0x688F # 0 +0x0000E8F5 0x6874 # 0 +0x0000E8F6 0x6877 # 0 +0x0000E8F7 0x6893 # 0 +0x0000E8F8 0x686B # 0 +0x0000E8F9 0x68C2 # 0 +0x0000E8FA 0x696E # 0 +0x0000E8FB 0x68FC # 0 +0x0000E8FC 0x691F # 0 +0x0000E8FD 0x6920 # 0 +0x0000E8FE 0x68F9 # 0 +0x0000E9A1 0x6924 # 0 +0x0000E9A2 0x68F0 # 0 +0x0000E9A3 0x690B # 0 +0x0000E9A4 0x6901 # 0 +0x0000E9A5 0x6957 # 0 +0x0000E9A6 0x68E3 # 0 +0x0000E9A7 0x6910 # 0 +0x0000E9A8 0x6971 # 0 +0x0000E9A9 0x6939 # 0 +0x0000E9AA 0x6960 # 0 +0x0000E9AB 0x6942 # 0 +0x0000E9AC 0x695D # 0 +0x0000E9AD 0x6984 # 0 +0x0000E9AE 0x696B # 0 +0x0000E9AF 0x6980 # 0 +0x0000E9B0 0x6998 # 0 +0x0000E9B1 0x6978 # 0 +0x0000E9B2 0x6934 # 0 +0x0000E9B3 0x69CC # 0 +0x0000E9B4 0x6987 # 0 +0x0000E9B5 0x6988 # 0 +0x0000E9B6 0x69CE # 0 +0x0000E9B7 0x6989 # 0 +0x0000E9B8 0x6966 # 0 +0x0000E9B9 0x6963 # 0 +0x0000E9BA 0x6979 # 0 +0x0000E9BB 0x699B # 0 +0x0000E9BC 0x69A7 # 0 +0x0000E9BD 0x69BB # 0 +0x0000E9BE 0x69AB # 0 +0x0000E9BF 0x69AD # 0 +0x0000E9C0 0x69D4 # 0 +0x0000E9C1 0x69B1 # 0 +0x0000E9C2 0x69C1 # 0 +0x0000E9C3 0x69CA # 0 +0x0000E9C4 0x69DF # 0 +0x0000E9C5 0x6995 # 0 +0x0000E9C6 0x69E0 # 0 +0x0000E9C7 0x698D # 0 +0x0000E9C8 0x69FF # 0 +0x0000E9C9 0x6A2F # 0 +0x0000E9CA 0x69ED # 0 +0x0000E9CB 0x6A17 # 0 +0x0000E9CC 0x6A18 # 0 +0x0000E9CD 0x6A65 # 0 +0x0000E9CE 0x69F2 # 0 +0x0000E9CF 0x6A44 # 0 +0x0000E9D0 0x6A3E # 0 +0x0000E9D1 0x6AA0 # 0 +0x0000E9D2 0x6A50 # 0 +0x0000E9D3 0x6A5B # 0 +0x0000E9D4 0x6A35 # 0 +0x0000E9D5 0x6A8E # 0 +0x0000E9D6 0x6A79 # 0 +0x0000E9D7 0x6A3D # 0 +0x0000E9D8 0x6A28 # 0 +0x0000E9D9 0x6A58 # 0 +0x0000E9DA 0x6A7C # 0 +0x0000E9DB 0x6A91 # 0 +0x0000E9DC 0x6A90 # 0 +0x0000E9DD 0x6AA9 # 0 +0x0000E9DE 0x6A97 # 0 +0x0000E9DF 0x6AAB # 0 +0x0000E9E0 0x7337 # 0 +0x0000E9E1 0x7352 # 0 +0x0000E9E2 0x6B81 # 0 +0x0000E9E3 0x6B82 # 0 +0x0000E9E4 0x6B87 # 0 +0x0000E9E5 0x6B84 # 0 +0x0000E9E6 0x6B92 # 0 +0x0000E9E7 0x6B93 # 0 +0x0000E9E8 0x6B8D # 0 +0x0000E9E9 0x6B9A # 0 +0x0000E9EA 0x6B9B # 0 +0x0000E9EB 0x6BA1 # 0 +0x0000E9EC 0x6BAA # 0 +0x0000E9ED 0x8F6B # 0 +0x0000E9EE 0x8F6D # 0 +0x0000E9EF 0x8F71 # 0 +0x0000E9F0 0x8F72 # 0 +0x0000E9F1 0x8F73 # 0 +0x0000E9F2 0x8F75 # 0 +0x0000E9F3 0x8F76 # 0 +0x0000E9F4 0x8F78 # 0 +0x0000E9F5 0x8F77 # 0 +0x0000E9F6 0x8F79 # 0 +0x0000E9F7 0x8F7A # 0 +0x0000E9F8 0x8F7C # 0 +0x0000E9F9 0x8F7E # 0 +0x0000E9FA 0x8F81 # 0 +0x0000E9FB 0x8F82 # 0 +0x0000E9FC 0x8F84 # 0 +0x0000E9FD 0x8F87 # 0 +0x0000E9FE 0x8F8B # 0 +0x0000EAA1 0x8F8D # 0 +0x0000EAA2 0x8F8E # 0 +0x0000EAA3 0x8F8F # 0 +0x0000EAA4 0x8F98 # 0 +0x0000EAA5 0x8F9A # 0 +0x0000EAA6 0x8ECE # 0 +0x0000EAA7 0x620B # 0 +0x0000EAA8 0x6217 # 0 +0x0000EAA9 0x621B # 0 +0x0000EAAA 0x621F # 0 +0x0000EAAB 0x6222 # 0 +0x0000EAAC 0x6221 # 0 +0x0000EAAD 0x6225 # 0 +0x0000EAAE 0x6224 # 0 +0x0000EAAF 0x622C # 0 +0x0000EAB0 0x81E7 # 0 +0x0000EAB1 0x74EF # 0 +0x0000EAB2 0x74F4 # 0 +0x0000EAB3 0x74FF # 0 +0x0000EAB4 0x750F # 0 +0x0000EAB5 0x7511 # 0 +0x0000EAB6 0x7513 # 0 +0x0000EAB7 0x6534 # 0 +0x0000EAB8 0x65EE # 0 +0x0000EAB9 0x65EF # 0 +0x0000EABA 0x65F0 # 0 +0x0000EABB 0x660A # 0 +0x0000EABC 0x6619 # 0 +0x0000EABD 0x6772 # 0 +0x0000EABE 0x6603 # 0 +0x0000EABF 0x6615 # 0 +0x0000EAC0 0x6600 # 0 +0x0000EAC1 0x7085 # 0 +0x0000EAC2 0x66F7 # 0 +0x0000EAC3 0x661D # 0 +0x0000EAC4 0x6634 # 0 +0x0000EAC5 0x6631 # 0 +0x0000EAC6 0x6636 # 0 +0x0000EAC7 0x6635 # 0 +0x0000EAC8 0x8006 # 0 +0x0000EAC9 0x665F # 0 +0x0000EACA 0x6654 # 0 +0x0000EACB 0x6641 # 0 +0x0000EACC 0x664F # 0 +0x0000EACD 0x6656 # 0 +0x0000EACE 0x6661 # 0 +0x0000EACF 0x6657 # 0 +0x0000EAD0 0x6677 # 0 +0x0000EAD1 0x6684 # 0 +0x0000EAD2 0x668C # 0 +0x0000EAD3 0x66A7 # 0 +0x0000EAD4 0x669D # 0 +0x0000EAD5 0x66BE # 0 +0x0000EAD6 0x66DB # 0 +0x0000EAD7 0x66DC # 0 +0x0000EAD8 0x66E6 # 0 +0x0000EAD9 0x66E9 # 0 +0x0000EADA 0x8D32 # 0 +0x0000EADB 0x8D33 # 0 +0x0000EADC 0x8D36 # 0 +0x0000EADD 0x8D3B # 0 +0x0000EADE 0x8D3D # 0 +0x0000EADF 0x8D40 # 0 +0x0000EAE0 0x8D45 # 0 +0x0000EAE1 0x8D46 # 0 +0x0000EAE2 0x8D48 # 0 +0x0000EAE3 0x8D49 # 0 +0x0000EAE4 0x8D47 # 0 +0x0000EAE5 0x8D4D # 0 +0x0000EAE6 0x8D55 # 0 +0x0000EAE7 0x8D59 # 0 +0x0000EAE8 0x89C7 # 0 +0x0000EAE9 0x89CA # 0 +0x0000EAEA 0x89CB # 0 +0x0000EAEB 0x89CC # 0 +0x0000EAEC 0x89CE # 0 +0x0000EAED 0x89CF # 0 +0x0000EAEE 0x89D0 # 0 +0x0000EAEF 0x89D1 # 0 +0x0000EAF0 0x726E # 0 +0x0000EAF1 0x729F # 0 +0x0000EAF2 0x725D # 0 +0x0000EAF3 0x7266 # 0 +0x0000EAF4 0x726F # 0 +0x0000EAF5 0x727E # 0 +0x0000EAF6 0x727F # 0 +0x0000EAF7 0x7284 # 0 +0x0000EAF8 0x728B # 0 +0x0000EAF9 0x728D # 0 +0x0000EAFA 0x728F # 0 +0x0000EAFB 0x7292 # 0 +0x0000EAFC 0x6308 # 0 +0x0000EAFD 0x6332 # 0 +0x0000EAFE 0x63B0 # 0 +0x0000EBA1 0x643F # 0 +0x0000EBA2 0x64D8 # 0 +0x0000EBA3 0x8004 # 0 +0x0000EBA4 0x6BEA # 0 +0x0000EBA5 0x6BF3 # 0 +0x0000EBA6 0x6BFD # 0 +0x0000EBA7 0x6BF5 # 0 +0x0000EBA8 0x6BF9 # 0 +0x0000EBA9 0x6C05 # 0 +0x0000EBAA 0x6C07 # 0 +0x0000EBAB 0x6C06 # 0 +0x0000EBAC 0x6C0D # 0 +0x0000EBAD 0x6C15 # 0 +0x0000EBAE 0x6C18 # 0 +0x0000EBAF 0x6C19 # 0 +0x0000EBB0 0x6C1A # 0 +0x0000EBB1 0x6C21 # 0 +0x0000EBB2 0x6C29 # 0 +0x0000EBB3 0x6C24 # 0 +0x0000EBB4 0x6C2A # 0 +0x0000EBB5 0x6C32 # 0 +0x0000EBB6 0x6535 # 0 +0x0000EBB7 0x6555 # 0 +0x0000EBB8 0x656B # 0 +0x0000EBB9 0x724D # 0 +0x0000EBBA 0x7252 # 0 +0x0000EBBB 0x7256 # 0 +0x0000EBBC 0x7230 # 0 +0x0000EBBD 0x8662 # 0 +0x0000EBBE 0x5216 # 0 +0x0000EBBF 0x809F # 0 +0x0000EBC0 0x809C # 0 +0x0000EBC1 0x8093 # 0 +0x0000EBC2 0x80BC # 0 +0x0000EBC3 0x670A # 0 +0x0000EBC4 0x80BD # 0 +0x0000EBC5 0x80B1 # 0 +0x0000EBC6 0x80AB # 0 +0x0000EBC7 0x80AD # 0 +0x0000EBC8 0x80B4 # 0 +0x0000EBC9 0x80B7 # 0 +0x0000EBCA 0x80E7 # 0 +0x0000EBCB 0x80E8 # 0 +0x0000EBCC 0x80E9 # 0 +0x0000EBCD 0x80EA # 0 +0x0000EBCE 0x80DB # 0 +0x0000EBCF 0x80C2 # 0 +0x0000EBD0 0x80C4 # 0 +0x0000EBD1 0x80D9 # 0 +0x0000EBD2 0x80CD # 0 +0x0000EBD3 0x80D7 # 0 +0x0000EBD4 0x6710 # 0 +0x0000EBD5 0x80DD # 0 +0x0000EBD6 0x80EB # 0 +0x0000EBD7 0x80F1 # 0 +0x0000EBD8 0x80F4 # 0 +0x0000EBD9 0x80ED # 0 +0x0000EBDA 0x810D # 0 +0x0000EBDB 0x810E # 0 +0x0000EBDC 0x80F2 # 0 +0x0000EBDD 0x80FC # 0 +0x0000EBDE 0x6715 # 0 +0x0000EBDF 0x8112 # 0 +0x0000EBE0 0x8C5A # 0 +0x0000EBE1 0x8136 # 0 +0x0000EBE2 0x811E # 0 +0x0000EBE3 0x812C # 0 +0x0000EBE4 0x8118 # 0 +0x0000EBE5 0x8132 # 0 +0x0000EBE6 0x8148 # 0 +0x0000EBE7 0x814C # 0 +0x0000EBE8 0x8153 # 0 +0x0000EBE9 0x8174 # 0 +0x0000EBEA 0x8159 # 0 +0x0000EBEB 0x815A # 0 +0x0000EBEC 0x8171 # 0 +0x0000EBED 0x8160 # 0 +0x0000EBEE 0x8169 # 0 +0x0000EBEF 0x817C # 0 +0x0000EBF0 0x817D # 0 +0x0000EBF1 0x816D # 0 +0x0000EBF2 0x8167 # 0 +0x0000EBF3 0x584D # 0 +0x0000EBF4 0x5AB5 # 0 +0x0000EBF5 0x8188 # 0 +0x0000EBF6 0x8182 # 0 +0x0000EBF7 0x8191 # 0 +0x0000EBF8 0x6ED5 # 0 +0x0000EBF9 0x81A3 # 0 +0x0000EBFA 0x81AA # 0 +0x0000EBFB 0x81CC # 0 +0x0000EBFC 0x6726 # 0 +0x0000EBFD 0x81CA # 0 +0x0000EBFE 0x81BB # 0 +0x0000ECA1 0x81C1 # 0 +0x0000ECA2 0x81A6 # 0 +0x0000ECA3 0x6B24 # 0 +0x0000ECA4 0x6B37 # 0 +0x0000ECA5 0x6B39 # 0 +0x0000ECA6 0x6B43 # 0 +0x0000ECA7 0x6B46 # 0 +0x0000ECA8 0x6B59 # 0 +0x0000ECA9 0x98D1 # 0 +0x0000ECAA 0x98D2 # 0 +0x0000ECAB 0x98D3 # 0 +0x0000ECAC 0x98D5 # 0 +0x0000ECAD 0x98D9 # 0 +0x0000ECAE 0x98DA # 0 +0x0000ECAF 0x6BB3 # 0 +0x0000ECB0 0x5F40 # 0 +0x0000ECB1 0x6BC2 # 0 +0x0000ECB2 0x89F3 # 0 +0x0000ECB3 0x6590 # 0 +0x0000ECB4 0x9F51 # 0 +0x0000ECB5 0x6593 # 0 +0x0000ECB6 0x65BC # 0 +0x0000ECB7 0x65C6 # 0 +0x0000ECB8 0x65C4 # 0 +0x0000ECB9 0x65C3 # 0 +0x0000ECBA 0x65CC # 0 +0x0000ECBB 0x65CE # 0 +0x0000ECBC 0x65D2 # 0 +0x0000ECBD 0x65D6 # 0 +0x0000ECBE 0x7080 # 0 +0x0000ECBF 0x709C # 0 +0x0000ECC0 0x7096 # 0 +0x0000ECC1 0x709D # 0 +0x0000ECC2 0x70BB # 0 +0x0000ECC3 0x70C0 # 0 +0x0000ECC4 0x70B7 # 0 +0x0000ECC5 0x70AB # 0 +0x0000ECC6 0x70B1 # 0 +0x0000ECC7 0x70E8 # 0 +0x0000ECC8 0x70CA # 0 +0x0000ECC9 0x7110 # 0 +0x0000ECCA 0x7113 # 0 +0x0000ECCB 0x7116 # 0 +0x0000ECCC 0x712F # 0 +0x0000ECCD 0x7131 # 0 +0x0000ECCE 0x7173 # 0 +0x0000ECCF 0x715C # 0 +0x0000ECD0 0x7168 # 0 +0x0000ECD1 0x7145 # 0 +0x0000ECD2 0x7172 # 0 +0x0000ECD3 0x714A # 0 +0x0000ECD4 0x7178 # 0 +0x0000ECD5 0x717A # 0 +0x0000ECD6 0x7198 # 0 +0x0000ECD7 0x71B3 # 0 +0x0000ECD8 0x71B5 # 0 +0x0000ECD9 0x71A8 # 0 +0x0000ECDA 0x71A0 # 0 +0x0000ECDB 0x71E0 # 0 +0x0000ECDC 0x71D4 # 0 +0x0000ECDD 0x71E7 # 0 +0x0000ECDE 0x71F9 # 0 +0x0000ECDF 0x721D # 0 +0x0000ECE0 0x7228 # 0 +0x0000ECE1 0x706C # 0 +0x0000ECE2 0x7118 # 0 +0x0000ECE3 0x7166 # 0 +0x0000ECE4 0x71B9 # 0 +0x0000ECE5 0x623E # 0 +0x0000ECE6 0x623D # 0 +0x0000ECE7 0x6243 # 0 +0x0000ECE8 0x6248 # 0 +0x0000ECE9 0x6249 # 0 +0x0000ECEA 0x793B # 0 +0x0000ECEB 0x7940 # 0 +0x0000ECEC 0x7946 # 0 +0x0000ECED 0x7949 # 0 +0x0000ECEE 0x795B # 0 +0x0000ECEF 0x795C # 0 +0x0000ECF0 0x7953 # 0 +0x0000ECF1 0x795A # 0 +0x0000ECF2 0x7962 # 0 +0x0000ECF3 0x7957 # 0 +0x0000ECF4 0x7960 # 0 +0x0000ECF5 0x796F # 0 +0x0000ECF6 0x7967 # 0 +0x0000ECF7 0x797A # 0 +0x0000ECF8 0x7985 # 0 +0x0000ECF9 0x798A # 0 +0x0000ECFA 0x799A # 0 +0x0000ECFB 0x79A7 # 0 +0x0000ECFC 0x79B3 # 0 +0x0000ECFD 0x5FD1 # 0 +0x0000ECFE 0x5FD0 # 0 +0x0000EDA1 0x603C # 0 +0x0000EDA2 0x605D # 0 +0x0000EDA3 0x605A # 0 +0x0000EDA4 0x6067 # 0 +0x0000EDA5 0x6041 # 0 +0x0000EDA6 0x6059 # 0 +0x0000EDA7 0x6063 # 0 +0x0000EDA8 0x60AB # 0 +0x0000EDA9 0x6106 # 0 +0x0000EDAA 0x610D # 0 +0x0000EDAB 0x615D # 0 +0x0000EDAC 0x61A9 # 0 +0x0000EDAD 0x619D # 0 +0x0000EDAE 0x61CB # 0 +0x0000EDAF 0x61D1 # 0 +0x0000EDB0 0x6206 # 0 +0x0000EDB1 0x8080 # 0 +0x0000EDB2 0x807F # 0 +0x0000EDB3 0x6C93 # 0 +0x0000EDB4 0x6CF6 # 0 +0x0000EDB5 0x6DFC # 0 +0x0000EDB6 0x77F6 # 0 +0x0000EDB7 0x77F8 # 0 +0x0000EDB8 0x7800 # 0 +0x0000EDB9 0x7809 # 0 +0x0000EDBA 0x7817 # 0 +0x0000EDBB 0x7818 # 0 +0x0000EDBC 0x7811 # 0 +0x0000EDBD 0x65AB # 0 +0x0000EDBE 0x782D # 0 +0x0000EDBF 0x781C # 0 +0x0000EDC0 0x781D # 0 +0x0000EDC1 0x7839 # 0 +0x0000EDC2 0x783A # 0 +0x0000EDC3 0x783B # 0 +0x0000EDC4 0x781F # 0 +0x0000EDC5 0x783C # 0 +0x0000EDC6 0x7825 # 0 +0x0000EDC7 0x782C # 0 +0x0000EDC8 0x7823 # 0 +0x0000EDC9 0x7829 # 0 +0x0000EDCA 0x784E # 0 +0x0000EDCB 0x786D # 0 +0x0000EDCC 0x7856 # 0 +0x0000EDCD 0x7857 # 0 +0x0000EDCE 0x7826 # 0 +0x0000EDCF 0x7850 # 0 +0x0000EDD0 0x7847 # 0 +0x0000EDD1 0x784C # 0 +0x0000EDD2 0x786A # 0 +0x0000EDD3 0x789B # 0 +0x0000EDD4 0x7893 # 0 +0x0000EDD5 0x789A # 0 +0x0000EDD6 0x7887 # 0 +0x0000EDD7 0x789C # 0 +0x0000EDD8 0x78A1 # 0 +0x0000EDD9 0x78A3 # 0 +0x0000EDDA 0x78B2 # 0 +0x0000EDDB 0x78B9 # 0 +0x0000EDDC 0x78A5 # 0 +0x0000EDDD 0x78D4 # 0 +0x0000EDDE 0x78D9 # 0 +0x0000EDDF 0x78C9 # 0 +0x0000EDE0 0x78EC # 0 +0x0000EDE1 0x78F2 # 0 +0x0000EDE2 0x7905 # 0 +0x0000EDE3 0x78F4 # 0 +0x0000EDE4 0x7913 # 0 +0x0000EDE5 0x7924 # 0 +0x0000EDE6 0x791E # 0 +0x0000EDE7 0x7934 # 0 +0x0000EDE8 0x9F9B # 0 +0x0000EDE9 0x9EF9 # 0 +0x0000EDEA 0x9EFB # 0 +0x0000EDEB 0x9EFC # 0 +0x0000EDEC 0x76F1 # 0 +0x0000EDED 0x7704 # 0 +0x0000EDEE 0x770D # 0 +0x0000EDEF 0x76F9 # 0 +0x0000EDF0 0x7707 # 0 +0x0000EDF1 0x7708 # 0 +0x0000EDF2 0x771A # 0 +0x0000EDF3 0x7722 # 0 +0x0000EDF4 0x7719 # 0 +0x0000EDF5 0x772D # 0 +0x0000EDF6 0x7726 # 0 +0x0000EDF7 0x7735 # 0 +0x0000EDF8 0x7738 # 0 +0x0000EDF9 0x7750 # 0 +0x0000EDFA 0x7751 # 0 +0x0000EDFB 0x7747 # 0 +0x0000EDFC 0x7743 # 0 +0x0000EDFD 0x775A # 0 +0x0000EDFE 0x7768 # 0 +0x0000EEA1 0x7762 # 0 +0x0000EEA2 0x7765 # 0 +0x0000EEA3 0x777F # 0 +0x0000EEA4 0x778D # 0 +0x0000EEA5 0x777D # 0 +0x0000EEA6 0x7780 # 0 +0x0000EEA7 0x778C # 0 +0x0000EEA8 0x7791 # 0 +0x0000EEA9 0x779F # 0 +0x0000EEAA 0x77A0 # 0 +0x0000EEAB 0x77B0 # 0 +0x0000EEAC 0x77B5 # 0 +0x0000EEAD 0x77BD # 0 +0x0000EEAE 0x753A # 0 +0x0000EEAF 0x7540 # 0 +0x0000EEB0 0x754E # 0 +0x0000EEB1 0x754B # 0 +0x0000EEB2 0x7548 # 0 +0x0000EEB3 0x755B # 0 +0x0000EEB4 0x7572 # 0 +0x0000EEB5 0x7579 # 0 +0x0000EEB6 0x7583 # 0 +0x0000EEB7 0x7F58 # 0 +0x0000EEB8 0x7F61 # 0 +0x0000EEB9 0x7F5F # 0 +0x0000EEBA 0x8A48 # 0 +0x0000EEBB 0x7F68 # 0 +0x0000EEBC 0x7F74 # 0 +0x0000EEBD 0x7F71 # 0 +0x0000EEBE 0x7F79 # 0 +0x0000EEBF 0x7F81 # 0 +0x0000EEC0 0x7F7E # 0 +0x0000EEC1 0x76CD # 0 +0x0000EEC2 0x76E5 # 0 +0x0000EEC3 0x8832 # 0 +0x0000EEC4 0x9485 # 0 +0x0000EEC5 0x9486 # 0 +0x0000EEC6 0x9487 # 0 +0x0000EEC7 0x948B # 0 +0x0000EEC8 0x948A # 0 +0x0000EEC9 0x948C # 0 +0x0000EECA 0x948D # 0 +0x0000EECB 0x948F # 0 +0x0000EECC 0x9490 # 0 +0x0000EECD 0x9494 # 0 +0x0000EECE 0x9497 # 0 +0x0000EECF 0x9495 # 0 +0x0000EED0 0x949A # 0 +0x0000EED1 0x949B # 0 +0x0000EED2 0x949C # 0 +0x0000EED3 0x94A3 # 0 +0x0000EED4 0x94A4 # 0 +0x0000EED5 0x94AB # 0 +0x0000EED6 0x94AA # 0 +0x0000EED7 0x94AD # 0 +0x0000EED8 0x94AC # 0 +0x0000EED9 0x94AF # 0 +0x0000EEDA 0x94B0 # 0 +0x0000EEDB 0x94B2 # 0 +0x0000EEDC 0x94B4 # 0 +0x0000EEDD 0x94B6 # 0 +0x0000EEDE 0x94B7 # 0 +0x0000EEDF 0x94B8 # 0 +0x0000EEE0 0x94B9 # 0 +0x0000EEE1 0x94BA # 0 +0x0000EEE2 0x94BC # 0 +0x0000EEE3 0x94BD # 0 +0x0000EEE4 0x94BF # 0 +0x0000EEE5 0x94C4 # 0 +0x0000EEE6 0x94C8 # 0 +0x0000EEE7 0x94C9 # 0 +0x0000EEE8 0x94CA # 0 +0x0000EEE9 0x94CB # 0 +0x0000EEEA 0x94CC # 0 +0x0000EEEB 0x94CD # 0 +0x0000EEEC 0x94CE # 0 +0x0000EEED 0x94D0 # 0 +0x0000EEEE 0x94D1 # 0 +0x0000EEEF 0x94D2 # 0 +0x0000EEF0 0x94D5 # 0 +0x0000EEF1 0x94D6 # 0 +0x0000EEF2 0x94D7 # 0 +0x0000EEF3 0x94D9 # 0 +0x0000EEF4 0x94D8 # 0 +0x0000EEF5 0x94DB # 0 +0x0000EEF6 0x94DE # 0 +0x0000EEF7 0x94DF # 0 +0x0000EEF8 0x94E0 # 0 +0x0000EEF9 0x94E2 # 0 +0x0000EEFA 0x94E4 # 0 +0x0000EEFB 0x94E5 # 0 +0x0000EEFC 0x94E7 # 0 +0x0000EEFD 0x94E8 # 0 +0x0000EEFE 0x94EA # 0 +0x0000EFA1 0x94E9 # 0 +0x0000EFA2 0x94EB # 0 +0x0000EFA3 0x94EE # 0 +0x0000EFA4 0x94EF # 0 +0x0000EFA5 0x94F3 # 0 +0x0000EFA6 0x94F4 # 0 +0x0000EFA7 0x94F5 # 0 +0x0000EFA8 0x94F7 # 0 +0x0000EFA9 0x94F9 # 0 +0x0000EFAA 0x94FC # 0 +0x0000EFAB 0x94FD # 0 +0x0000EFAC 0x94FF # 0 +0x0000EFAD 0x9503 # 0 +0x0000EFAE 0x9502 # 0 +0x0000EFAF 0x9506 # 0 +0x0000EFB0 0x9507 # 0 +0x0000EFB1 0x9509 # 0 +0x0000EFB2 0x950A # 0 +0x0000EFB3 0x950D # 0 +0x0000EFB4 0x950E # 0 +0x0000EFB5 0x950F # 0 +0x0000EFB6 0x9512 # 0 +0x0000EFB7 0x9513 # 0 +0x0000EFB8 0x9514 # 0 +0x0000EFB9 0x9515 # 0 +0x0000EFBA 0x9516 # 0 +0x0000EFBB 0x9518 # 0 +0x0000EFBC 0x951B # 0 +0x0000EFBD 0x951D # 0 +0x0000EFBE 0x951E # 0 +0x0000EFBF 0x951F # 0 +0x0000EFC0 0x9522 # 0 +0x0000EFC1 0x952A # 0 +0x0000EFC2 0x952B # 0 +0x0000EFC3 0x9529 # 0 +0x0000EFC4 0x952C # 0 +0x0000EFC5 0x9531 # 0 +0x0000EFC6 0x9532 # 0 +0x0000EFC7 0x9534 # 0 +0x0000EFC8 0x9536 # 0 +0x0000EFC9 0x9537 # 0 +0x0000EFCA 0x9538 # 0 +0x0000EFCB 0x953C # 0 +0x0000EFCC 0x953E # 0 +0x0000EFCD 0x953F # 0 +0x0000EFCE 0x9542 # 0 +0x0000EFCF 0x9535 # 0 +0x0000EFD0 0x9544 # 0 +0x0000EFD1 0x9545 # 0 +0x0000EFD2 0x9546 # 0 +0x0000EFD3 0x9549 # 0 +0x0000EFD4 0x954C # 0 +0x0000EFD5 0x954E # 0 +0x0000EFD6 0x954F # 0 +0x0000EFD7 0x9552 # 0 +0x0000EFD8 0x9553 # 0 +0x0000EFD9 0x9554 # 0 +0x0000EFDA 0x9556 # 0 +0x0000EFDB 0x9557 # 0 +0x0000EFDC 0x9558 # 0 +0x0000EFDD 0x9559 # 0 +0x0000EFDE 0x955B # 0 +0x0000EFDF 0x955E # 0 +0x0000EFE0 0x955F # 0 +0x0000EFE1 0x955D # 0 +0x0000EFE2 0x9561 # 0 +0x0000EFE3 0x9562 # 0 +0x0000EFE4 0x9564 # 0 +0x0000EFE5 0x9565 # 0 +0x0000EFE6 0x9566 # 0 +0x0000EFE7 0x9567 # 0 +0x0000EFE8 0x9568 # 0 +0x0000EFE9 0x9569 # 0 +0x0000EFEA 0x956A # 0 +0x0000EFEB 0x956B # 0 +0x0000EFEC 0x956C # 0 +0x0000EFED 0x956F # 0 +0x0000EFEE 0x9571 # 0 +0x0000EFEF 0x9572 # 0 +0x0000EFF0 0x9573 # 0 +0x0000EFF1 0x953A # 0 +0x0000EFF2 0x77E7 # 0 +0x0000EFF3 0x77EC # 0 +0x0000EFF4 0x96C9 # 0 +0x0000EFF5 0x79D5 # 0 +0x0000EFF6 0x79ED # 0 +0x0000EFF7 0x79E3 # 0 +0x0000EFF8 0x79EB # 0 +0x0000EFF9 0x7A06 # 0 +0x0000EFFA 0x5D47 # 0 +0x0000EFFB 0x7A03 # 0 +0x0000EFFC 0x7A02 # 0 +0x0000EFFD 0x7A1E # 0 +0x0000EFFE 0x7A14 # 0 +0x0000F0A1 0x7A39 # 0 +0x0000F0A2 0x7A37 # 0 +0x0000F0A3 0x7A51 # 0 +0x0000F0A4 0x9ECF # 0 +0x0000F0A5 0x99A5 # 0 +0x0000F0A6 0x7A70 # 0 +0x0000F0A7 0x7688 # 0 +0x0000F0A8 0x768E # 0 +0x0000F0A9 0x7693 # 0 +0x0000F0AA 0x7699 # 0 +0x0000F0AB 0x76A4 # 0 +0x0000F0AC 0x74DE # 0 +0x0000F0AD 0x74E0 # 0 +0x0000F0AE 0x752C # 0 +0x0000F0AF 0x9E20 # 0 +0x0000F0B0 0x9E22 # 0 +0x0000F0B1 0x9E28 # 0 +0x0000F0B2 0x9E29 # 0 +0x0000F0B3 0x9E2A # 0 +0x0000F0B4 0x9E2B # 0 +0x0000F0B5 0x9E2C # 0 +0x0000F0B6 0x9E32 # 0 +0x0000F0B7 0x9E31 # 0 +0x0000F0B8 0x9E36 # 0 +0x0000F0B9 0x9E38 # 0 +0x0000F0BA 0x9E37 # 0 +0x0000F0BB 0x9E39 # 0 +0x0000F0BC 0x9E3A # 0 +0x0000F0BD 0x9E3E # 0 +0x0000F0BE 0x9E41 # 0 +0x0000F0BF 0x9E42 # 0 +0x0000F0C0 0x9E44 # 0 +0x0000F0C1 0x9E46 # 0 +0x0000F0C2 0x9E47 # 0 +0x0000F0C3 0x9E48 # 0 +0x0000F0C4 0x9E49 # 0 +0x0000F0C5 0x9E4B # 0 +0x0000F0C6 0x9E4C # 0 +0x0000F0C7 0x9E4E # 0 +0x0000F0C8 0x9E51 # 0 +0x0000F0C9 0x9E55 # 0 +0x0000F0CA 0x9E57 # 0 +0x0000F0CB 0x9E5A # 0 +0x0000F0CC 0x9E5B # 0 +0x0000F0CD 0x9E5C # 0 +0x0000F0CE 0x9E5E # 0 +0x0000F0CF 0x9E63 # 0 +0x0000F0D0 0x9E66 # 0 +0x0000F0D1 0x9E67 # 0 +0x0000F0D2 0x9E68 # 0 +0x0000F0D3 0x9E69 # 0 +0x0000F0D4 0x9E6A # 0 +0x0000F0D5 0x9E6B # 0 +0x0000F0D6 0x9E6C # 0 +0x0000F0D7 0x9E71 # 0 +0x0000F0D8 0x9E6D # 0 +0x0000F0D9 0x9E73 # 0 +0x0000F0DA 0x7592 # 0 +0x0000F0DB 0x7594 # 0 +0x0000F0DC 0x7596 # 0 +0x0000F0DD 0x75A0 # 0 +0x0000F0DE 0x759D # 0 +0x0000F0DF 0x75AC # 0 +0x0000F0E0 0x75A3 # 0 +0x0000F0E1 0x75B3 # 0 +0x0000F0E2 0x75B4 # 0 +0x0000F0E3 0x75B8 # 0 +0x0000F0E4 0x75C4 # 0 +0x0000F0E5 0x75B1 # 0 +0x0000F0E6 0x75B0 # 0 +0x0000F0E7 0x75C3 # 0 +0x0000F0E8 0x75C2 # 0 +0x0000F0E9 0x75D6 # 0 +0x0000F0EA 0x75CD # 0 +0x0000F0EB 0x75E3 # 0 +0x0000F0EC 0x75E8 # 0 +0x0000F0ED 0x75E6 # 0 +0x0000F0EE 0x75E4 # 0 +0x0000F0EF 0x75EB # 0 +0x0000F0F0 0x75E7 # 0 +0x0000F0F1 0x7603 # 0 +0x0000F0F2 0x75F1 # 0 +0x0000F0F3 0x75FC # 0 +0x0000F0F4 0x75FF # 0 +0x0000F0F5 0x7610 # 0 +0x0000F0F6 0x7600 # 0 +0x0000F0F7 0x7605 # 0 +0x0000F0F8 0x760C # 0 +0x0000F0F9 0x7617 # 0 +0x0000F0FA 0x760A # 0 +0x0000F0FB 0x7625 # 0 +0x0000F0FC 0x7618 # 0 +0x0000F0FD 0x7615 # 0 +0x0000F0FE 0x7619 # 0 +0x0000F1A1 0x761B # 0 +0x0000F1A2 0x763C # 0 +0x0000F1A3 0x7622 # 0 +0x0000F1A4 0x7620 # 0 +0x0000F1A5 0x7640 # 0 +0x0000F1A6 0x762D # 0 +0x0000F1A7 0x7630 # 0 +0x0000F1A8 0x763F # 0 +0x0000F1A9 0x7635 # 0 +0x0000F1AA 0x7643 # 0 +0x0000F1AB 0x763E # 0 +0x0000F1AC 0x7633 # 0 +0x0000F1AD 0x764D # 0 +0x0000F1AE 0x765E # 0 +0x0000F1AF 0x7654 # 0 +0x0000F1B0 0x765C # 0 +0x0000F1B1 0x7656 # 0 +0x0000F1B2 0x766B # 0 +0x0000F1B3 0x766F # 0 +0x0000F1B4 0x7FCA # 0 +0x0000F1B5 0x7AE6 # 0 +0x0000F1B6 0x7A78 # 0 +0x0000F1B7 0x7A79 # 0 +0x0000F1B8 0x7A80 # 0 +0x0000F1B9 0x7A86 # 0 +0x0000F1BA 0x7A88 # 0 +0x0000F1BB 0x7A95 # 0 +0x0000F1BC 0x7AA6 # 0 +0x0000F1BD 0x7AA0 # 0 +0x0000F1BE 0x7AAC # 0 +0x0000F1BF 0x7AA8 # 0 +0x0000F1C0 0x7AAD # 0 +0x0000F1C1 0x7AB3 # 0 +0x0000F1C2 0x8864 # 0 +0x0000F1C3 0x8869 # 0 +0x0000F1C4 0x8872 # 0 +0x0000F1C5 0x887D # 0 +0x0000F1C6 0x887F # 0 +0x0000F1C7 0x8882 # 0 +0x0000F1C8 0x88A2 # 0 +0x0000F1C9 0x88C6 # 0 +0x0000F1CA 0x88B7 # 0 +0x0000F1CB 0x88BC # 0 +0x0000F1CC 0x88C9 # 0 +0x0000F1CD 0x88E2 # 0 +0x0000F1CE 0x88CE # 0 +0x0000F1CF 0x88E3 # 0 +0x0000F1D0 0x88E5 # 0 +0x0000F1D1 0x88F1 # 0 +0x0000F1D2 0x891A # 0 +0x0000F1D3 0x88FC # 0 +0x0000F1D4 0x88E8 # 0 +0x0000F1D5 0x88FE # 0 +0x0000F1D6 0x88F0 # 0 +0x0000F1D7 0x8921 # 0 +0x0000F1D8 0x8919 # 0 +0x0000F1D9 0x8913 # 0 +0x0000F1DA 0x891B # 0 +0x0000F1DB 0x890A # 0 +0x0000F1DC 0x8934 # 0 +0x0000F1DD 0x892B # 0 +0x0000F1DE 0x8936 # 0 +0x0000F1DF 0x8941 # 0 +0x0000F1E0 0x8966 # 0 +0x0000F1E1 0x897B # 0 +0x0000F1E2 0x758B # 0 +0x0000F1E3 0x80E5 # 0 +0x0000F1E4 0x76B2 # 0 +0x0000F1E5 0x76B4 # 0 +0x0000F1E6 0x77DC # 0 +0x0000F1E7 0x8012 # 0 +0x0000F1E8 0x8014 # 0 +0x0000F1E9 0x8016 # 0 +0x0000F1EA 0x801C # 0 +0x0000F1EB 0x8020 # 0 +0x0000F1EC 0x8022 # 0 +0x0000F1ED 0x8025 # 0 +0x0000F1EE 0x8026 # 0 +0x0000F1EF 0x8027 # 0 +0x0000F1F0 0x8029 # 0 +0x0000F1F1 0x8028 # 0 +0x0000F1F2 0x8031 # 0 +0x0000F1F3 0x800B # 0 +0x0000F1F4 0x8035 # 0 +0x0000F1F5 0x8043 # 0 +0x0000F1F6 0x8046 # 0 +0x0000F1F7 0x804D # 0 +0x0000F1F8 0x8052 # 0 +0x0000F1F9 0x8069 # 0 +0x0000F1FA 0x8071 # 0 +0x0000F1FB 0x8983 # 0 +0x0000F1FC 0x9878 # 0 +0x0000F1FD 0x9880 # 0 +0x0000F1FE 0x9883 # 0 +0x0000F2A1 0x9889 # 0 +0x0000F2A2 0x988C # 0 +0x0000F2A3 0x988D # 0 +0x0000F2A4 0x988F # 0 +0x0000F2A5 0x9894 # 0 +0x0000F2A6 0x989A # 0 +0x0000F2A7 0x989B # 0 +0x0000F2A8 0x989E # 0 +0x0000F2A9 0x989F # 0 +0x0000F2AA 0x98A1 # 0 +0x0000F2AB 0x98A2 # 0 +0x0000F2AC 0x98A5 # 0 +0x0000F2AD 0x98A6 # 0 +0x0000F2AE 0x864D # 0 +0x0000F2AF 0x8654 # 0 +0x0000F2B0 0x866C # 0 +0x0000F2B1 0x866E # 0 +0x0000F2B2 0x867F # 0 +0x0000F2B3 0x867A # 0 +0x0000F2B4 0x867C # 0 +0x0000F2B5 0x867B # 0 +0x0000F2B6 0x86A8 # 0 +0x0000F2B7 0x868D # 0 +0x0000F2B8 0x868B # 0 +0x0000F2B9 0x86AC # 0 +0x0000F2BA 0x869D # 0 +0x0000F2BB 0x86A7 # 0 +0x0000F2BC 0x86A3 # 0 +0x0000F2BD 0x86AA # 0 +0x0000F2BE 0x8693 # 0 +0x0000F2BF 0x86A9 # 0 +0x0000F2C0 0x86B6 # 0 +0x0000F2C1 0x86C4 # 0 +0x0000F2C2 0x86B5 # 0 +0x0000F2C3 0x86CE # 0 +0x0000F2C4 0x86B0 # 0 +0x0000F2C5 0x86BA # 0 +0x0000F2C6 0x86B1 # 0 +0x0000F2C7 0x86AF # 0 +0x0000F2C8 0x86C9 # 0 +0x0000F2C9 0x86CF # 0 +0x0000F2CA 0x86B4 # 0 +0x0000F2CB 0x86E9 # 0 +0x0000F2CC 0x86F1 # 0 +0x0000F2CD 0x86F2 # 0 +0x0000F2CE 0x86ED # 0 +0x0000F2CF 0x86F3 # 0 +0x0000F2D0 0x86D0 # 0 +0x0000F2D1 0x8713 # 0 +0x0000F2D2 0x86DE # 0 +0x0000F2D3 0x86F4 # 0 +0x0000F2D4 0x86DF # 0 +0x0000F2D5 0x86D8 # 0 +0x0000F2D6 0x86D1 # 0 +0x0000F2D7 0x8703 # 0 +0x0000F2D8 0x8707 # 0 +0x0000F2D9 0x86F8 # 0 +0x0000F2DA 0x8708 # 0 +0x0000F2DB 0x870A # 0 +0x0000F2DC 0x870D # 0 +0x0000F2DD 0x8709 # 0 +0x0000F2DE 0x8723 # 0 +0x0000F2DF 0x873B # 0 +0x0000F2E0 0x871E # 0 +0x0000F2E1 0x8725 # 0 +0x0000F2E2 0x872E # 0 +0x0000F2E3 0x871A # 0 +0x0000F2E4 0x873E # 0 +0x0000F2E5 0x8748 # 0 +0x0000F2E6 0x8734 # 0 +0x0000F2E7 0x8731 # 0 +0x0000F2E8 0x8729 # 0 +0x0000F2E9 0x8737 # 0 +0x0000F2EA 0x873F # 0 +0x0000F2EB 0x8782 # 0 +0x0000F2EC 0x8722 # 0 +0x0000F2ED 0x877D # 0 +0x0000F2EE 0x877E # 0 +0x0000F2EF 0x877B # 0 +0x0000F2F0 0x8760 # 0 +0x0000F2F1 0x8770 # 0 +0x0000F2F2 0x874C # 0 +0x0000F2F3 0x876E # 0 +0x0000F2F4 0x878B # 0 +0x0000F2F5 0x8753 # 0 +0x0000F2F6 0x8763 # 0 +0x0000F2F7 0x877C # 0 +0x0000F2F8 0x8764 # 0 +0x0000F2F9 0x8759 # 0 +0x0000F2FA 0x8765 # 0 +0x0000F2FB 0x8793 # 0 +0x0000F2FC 0x87AF # 0 +0x0000F2FD 0x87A8 # 0 +0x0000F2FE 0x87D2 # 0 +0x0000F3A1 0x87C6 # 0 +0x0000F3A2 0x8788 # 0 +0x0000F3A3 0x8785 # 0 +0x0000F3A4 0x87AD # 0 +0x0000F3A5 0x8797 # 0 +0x0000F3A6 0x8783 # 0 +0x0000F3A7 0x87AB # 0 +0x0000F3A8 0x87E5 # 0 +0x0000F3A9 0x87AC # 0 +0x0000F3AA 0x87B5 # 0 +0x0000F3AB 0x87B3 # 0 +0x0000F3AC 0x87CB # 0 +0x0000F3AD 0x87D3 # 0 +0x0000F3AE 0x87BD # 0 +0x0000F3AF 0x87D1 # 0 +0x0000F3B0 0x87C0 # 0 +0x0000F3B1 0x87CA # 0 +0x0000F3B2 0x87DB # 0 +0x0000F3B3 0x87EA # 0 +0x0000F3B4 0x87E0 # 0 +0x0000F3B5 0x87EE # 0 +0x0000F3B6 0x8816 # 0 +0x0000F3B7 0x8813 # 0 +0x0000F3B8 0x87FE # 0 +0x0000F3B9 0x880A # 0 +0x0000F3BA 0x881B # 0 +0x0000F3BB 0x8821 # 0 +0x0000F3BC 0x8839 # 0 +0x0000F3BD 0x883C # 0 +0x0000F3BE 0x7F36 # 0 +0x0000F3BF 0x7F42 # 0 +0x0000F3C0 0x7F44 # 0 +0x0000F3C1 0x7F45 # 0 +0x0000F3C2 0x8210 # 0 +0x0000F3C3 0x7AFA # 0 +0x0000F3C4 0x7AFD # 0 +0x0000F3C5 0x7B08 # 0 +0x0000F3C6 0x7B03 # 0 +0x0000F3C7 0x7B04 # 0 +0x0000F3C8 0x7B15 # 0 +0x0000F3C9 0x7B0A # 0 +0x0000F3CA 0x7B2B # 0 +0x0000F3CB 0x7B0F # 0 +0x0000F3CC 0x7B47 # 0 +0x0000F3CD 0x7B38 # 0 +0x0000F3CE 0x7B2A # 0 +0x0000F3CF 0x7B19 # 0 +0x0000F3D0 0x7B2E # 0 +0x0000F3D1 0x7B31 # 0 +0x0000F3D2 0x7B20 # 0 +0x0000F3D3 0x7B25 # 0 +0x0000F3D4 0x7B24 # 0 +0x0000F3D5 0x7B33 # 0 +0x0000F3D6 0x7B3E # 0 +0x0000F3D7 0x7B1E # 0 +0x0000F3D8 0x7B58 # 0 +0x0000F3D9 0x7B5A # 0 +0x0000F3DA 0x7B45 # 0 +0x0000F3DB 0x7B75 # 0 +0x0000F3DC 0x7B4C # 0 +0x0000F3DD 0x7B5D # 0 +0x0000F3DE 0x7B60 # 0 +0x0000F3DF 0x7B6E # 0 +0x0000F3E0 0x7B7B # 0 +0x0000F3E1 0x7B62 # 0 +0x0000F3E2 0x7B72 # 0 +0x0000F3E3 0x7B71 # 0 +0x0000F3E4 0x7B90 # 0 +0x0000F3E5 0x7BA6 # 0 +0x0000F3E6 0x7BA7 # 0 +0x0000F3E7 0x7BB8 # 0 +0x0000F3E8 0x7BAC # 0 +0x0000F3E9 0x7B9D # 0 +0x0000F3EA 0x7BA8 # 0 +0x0000F3EB 0x7B85 # 0 +0x0000F3EC 0x7BAA # 0 +0x0000F3ED 0x7B9C # 0 +0x0000F3EE 0x7BA2 # 0 +0x0000F3EF 0x7BAB # 0 +0x0000F3F0 0x7BB4 # 0 +0x0000F3F1 0x7BD1 # 0 +0x0000F3F2 0x7BC1 # 0 +0x0000F3F3 0x7BCC # 0 +0x0000F3F4 0x7BDD # 0 +0x0000F3F5 0x7BDA # 0 +0x0000F3F6 0x7BE5 # 0 +0x0000F3F7 0x7BE6 # 0 +0x0000F3F8 0x7BEA # 0 +0x0000F3F9 0x7C0C # 0 +0x0000F3FA 0x7BFE # 0 +0x0000F3FB 0x7BFC # 0 +0x0000F3FC 0x7C0F # 0 +0x0000F3FD 0x7C16 # 0 +0x0000F3FE 0x7C0B # 0 +0x0000F4A1 0x7C1F # 0 +0x0000F4A2 0x7C2A # 0 +0x0000F4A3 0x7C26 # 0 +0x0000F4A4 0x7C38 # 0 +0x0000F4A5 0x7C41 # 0 +0x0000F4A6 0x7C40 # 0 +0x0000F4A7 0x81FE # 0 +0x0000F4A8 0x8201 # 0 +0x0000F4A9 0x8202 # 0 +0x0000F4AA 0x8204 # 0 +0x0000F4AB 0x81EC # 0 +0x0000F4AC 0x8844 # 0 +0x0000F4AD 0x8221 # 0 +0x0000F4AE 0x8222 # 0 +0x0000F4AF 0x8223 # 0 +0x0000F4B0 0x822D # 0 +0x0000F4B1 0x822F # 0 +0x0000F4B2 0x8228 # 0 +0x0000F4B3 0x822B # 0 +0x0000F4B4 0x8238 # 0 +0x0000F4B5 0x823B # 0 +0x0000F4B6 0x8233 # 0 +0x0000F4B7 0x8234 # 0 +0x0000F4B8 0x823E # 0 +0x0000F4B9 0x8244 # 0 +0x0000F4BA 0x8249 # 0 +0x0000F4BB 0x824B # 0 +0x0000F4BC 0x824F # 0 +0x0000F4BD 0x825A # 0 +0x0000F4BE 0x825F # 0 +0x0000F4BF 0x8268 # 0 +0x0000F4C0 0x887E # 0 +0x0000F4C1 0x8885 # 0 +0x0000F4C2 0x8888 # 0 +0x0000F4C3 0x88D8 # 0 +0x0000F4C4 0x88DF # 0 +0x0000F4C5 0x895E # 0 +0x0000F4C6 0x7F9D # 0 +0x0000F4C7 0x7F9F # 0 +0x0000F4C8 0x7FA7 # 0 +0x0000F4C9 0x7FAF # 0 +0x0000F4CA 0x7FB0 # 0 +0x0000F4CB 0x7FB2 # 0 +0x0000F4CC 0x7C7C # 0 +0x0000F4CD 0x6549 # 0 +0x0000F4CE 0x7C91 # 0 +0x0000F4CF 0x7C9D # 0 +0x0000F4D0 0x7C9C # 0 +0x0000F4D1 0x7C9E # 0 +0x0000F4D2 0x7CA2 # 0 +0x0000F4D3 0x7CB2 # 0 +0x0000F4D4 0x7CBC # 0 +0x0000F4D5 0x7CBD # 0 +0x0000F4D6 0x7CC1 # 0 +0x0000F4D7 0x7CC7 # 0 +0x0000F4D8 0x7CCC # 0 +0x0000F4D9 0x7CCD # 0 +0x0000F4DA 0x7CC8 # 0 +0x0000F4DB 0x7CC5 # 0 +0x0000F4DC 0x7CD7 # 0 +0x0000F4DD 0x7CE8 # 0 +0x0000F4DE 0x826E # 0 +0x0000F4DF 0x66A8 # 0 +0x0000F4E0 0x7FBF # 0 +0x0000F4E1 0x7FCE # 0 +0x0000F4E2 0x7FD5 # 0 +0x0000F4E3 0x7FE5 # 0 +0x0000F4E4 0x7FE1 # 0 +0x0000F4E5 0x7FE6 # 0 +0x0000F4E6 0x7FE9 # 0 +0x0000F4E7 0x7FEE # 0 +0x0000F4E8 0x7FF3 # 0 +0x0000F4E9 0x7CF8 # 0 +0x0000F4EA 0x7D77 # 0 +0x0000F4EB 0x7DA6 # 0 +0x0000F4EC 0x7DAE # 0 +0x0000F4ED 0x7E47 # 0 +0x0000F4EE 0x7E9B # 0 +0x0000F4EF 0x9EB8 # 0 +0x0000F4F0 0x9EB4 # 0 +0x0000F4F1 0x8D73 # 0 +0x0000F4F2 0x8D84 # 0 +0x0000F4F3 0x8D94 # 0 +0x0000F4F4 0x8D91 # 0 +0x0000F4F5 0x8DB1 # 0 +0x0000F4F6 0x8D67 # 0 +0x0000F4F7 0x8D6D # 0 +0x0000F4F8 0x8C47 # 0 +0x0000F4F9 0x8C49 # 0 +0x0000F4FA 0x914A # 0 +0x0000F4FB 0x9150 # 0 +0x0000F4FC 0x914E # 0 +0x0000F4FD 0x914F # 0 +0x0000F4FE 0x9164 # 0 +0x0000F5A1 0x9162 # 0 +0x0000F5A2 0x9161 # 0 +0x0000F5A3 0x9170 # 0 +0x0000F5A4 0x9169 # 0 +0x0000F5A5 0x916F # 0 +0x0000F5A6 0x917D # 0 +0x0000F5A7 0x917E # 0 +0x0000F5A8 0x9172 # 0 +0x0000F5A9 0x9174 # 0 +0x0000F5AA 0x9179 # 0 +0x0000F5AB 0x918C # 0 +0x0000F5AC 0x9185 # 0 +0x0000F5AD 0x9190 # 0 +0x0000F5AE 0x918D # 0 +0x0000F5AF 0x9191 # 0 +0x0000F5B0 0x91A2 # 0 +0x0000F5B1 0x91A3 # 0 +0x0000F5B2 0x91AA # 0 +0x0000F5B3 0x91AD # 0 +0x0000F5B4 0x91AE # 0 +0x0000F5B5 0x91AF # 0 +0x0000F5B6 0x91B5 # 0 +0x0000F5B7 0x91B4 # 0 +0x0000F5B8 0x91BA # 0 +0x0000F5B9 0x8C55 # 0 +0x0000F5BA 0x9E7E # 0 +0x0000F5BB 0x8DB8 # 0 +0x0000F5BC 0x8DEB # 0 +0x0000F5BD 0x8E05 # 0 +0x0000F5BE 0x8E59 # 0 +0x0000F5BF 0x8E69 # 0 +0x0000F5C0 0x8DB5 # 0 +0x0000F5C1 0x8DBF # 0 +0x0000F5C2 0x8DBC # 0 +0x0000F5C3 0x8DBA # 0 +0x0000F5C4 0x8DC4 # 0 +0x0000F5C5 0x8DD6 # 0 +0x0000F5C6 0x8DD7 # 0 +0x0000F5C7 0x8DDA # 0 +0x0000F5C8 0x8DDE # 0 +0x0000F5C9 0x8DCE # 0 +0x0000F5CA 0x8DCF # 0 +0x0000F5CB 0x8DDB # 0 +0x0000F5CC 0x8DC6 # 0 +0x0000F5CD 0x8DEC # 0 +0x0000F5CE 0x8DF7 # 0 +0x0000F5CF 0x8DF8 # 0 +0x0000F5D0 0x8DE3 # 0 +0x0000F5D1 0x8DF9 # 0 +0x0000F5D2 0x8DFB # 0 +0x0000F5D3 0x8DE4 # 0 +0x0000F5D4 0x8E09 # 0 +0x0000F5D5 0x8DFD # 0 +0x0000F5D6 0x8E14 # 0 +0x0000F5D7 0x8E1D # 0 +0x0000F5D8 0x8E1F # 0 +0x0000F5D9 0x8E2C # 0 +0x0000F5DA 0x8E2E # 0 +0x0000F5DB 0x8E23 # 0 +0x0000F5DC 0x8E2F # 0 +0x0000F5DD 0x8E3A # 0 +0x0000F5DE 0x8E40 # 0 +0x0000F5DF 0x8E39 # 0 +0x0000F5E0 0x8E35 # 0 +0x0000F5E1 0x8E3D # 0 +0x0000F5E2 0x8E31 # 0 +0x0000F5E3 0x8E49 # 0 +0x0000F5E4 0x8E41 # 0 +0x0000F5E5 0x8E42 # 0 +0x0000F5E6 0x8E51 # 0 +0x0000F5E7 0x8E52 # 0 +0x0000F5E8 0x8E4A # 0 +0x0000F5E9 0x8E70 # 0 +0x0000F5EA 0x8E76 # 0 +0x0000F5EB 0x8E7C # 0 +0x0000F5EC 0x8E6F # 0 +0x0000F5ED 0x8E74 # 0 +0x0000F5EE 0x8E85 # 0 +0x0000F5EF 0x8E8F # 0 +0x0000F5F0 0x8E94 # 0 +0x0000F5F1 0x8E90 # 0 +0x0000F5F2 0x8E9C # 0 +0x0000F5F3 0x8E9E # 0 +0x0000F5F4 0x8C78 # 0 +0x0000F5F5 0x8C82 # 0 +0x0000F5F6 0x8C8A # 0 +0x0000F5F7 0x8C85 # 0 +0x0000F5F8 0x8C98 # 0 +0x0000F5F9 0x8C94 # 0 +0x0000F5FA 0x659B # 0 +0x0000F5FB 0x89D6 # 0 +0x0000F5FC 0x89DE # 0 +0x0000F5FD 0x89DA # 0 +0x0000F5FE 0x89DC # 0 +0x0000F6A1 0x89E5 # 0 +0x0000F6A2 0x89EB # 0 +0x0000F6A3 0x89EF # 0 +0x0000F6A4 0x8A3E # 0 +0x0000F6A5 0x8B26 # 0 +0x0000F6A6 0x9753 # 0 +0x0000F6A7 0x96E9 # 0 +0x0000F6A8 0x96F3 # 0 +0x0000F6A9 0x96EF # 0 +0x0000F6AA 0x9706 # 0 +0x0000F6AB 0x9701 # 0 +0x0000F6AC 0x9708 # 0 +0x0000F6AD 0x970F # 0 +0x0000F6AE 0x970E # 0 +0x0000F6AF 0x972A # 0 +0x0000F6B0 0x972D # 0 +0x0000F6B1 0x9730 # 0 +0x0000F6B2 0x973E # 0 +0x0000F6B3 0x9F80 # 0 +0x0000F6B4 0x9F83 # 0 +0x0000F6B5 0x9F85 # 0 +0x0000F6B6 0x9F86 # 0 +0x0000F6B7 0x9F87 # 0 +0x0000F6B8 0x9F88 # 0 +0x0000F6B9 0x9F89 # 0 +0x0000F6BA 0x9F8A # 0 +0x0000F6BB 0x9F8C # 0 +0x0000F6BC 0x9EFE # 0 +0x0000F6BD 0x9F0B # 0 +0x0000F6BE 0x9F0D # 0 +0x0000F6BF 0x96B9 # 0 +0x0000F6C0 0x96BC # 0 +0x0000F6C1 0x96BD # 0 +0x0000F6C2 0x96CE # 0 +0x0000F6C3 0x96D2 # 0 +0x0000F6C4 0x77BF # 0 +0x0000F6C5 0x96E0 # 0 +0x0000F6C6 0x928E # 0 +0x0000F6C7 0x92AE # 0 +0x0000F6C8 0x92C8 # 0 +0x0000F6C9 0x933E # 0 +0x0000F6CA 0x936A # 0 +0x0000F6CB 0x93CA # 0 +0x0000F6CC 0x938F # 0 +0x0000F6CD 0x943E # 0 +0x0000F6CE 0x946B # 0 +0x0000F6CF 0x9C7F # 0 +0x0000F6D0 0x9C82 # 0 +0x0000F6D1 0x9C85 # 0 +0x0000F6D2 0x9C86 # 0 +0x0000F6D3 0x9C87 # 0 +0x0000F6D4 0x9C88 # 0 +0x0000F6D5 0x7A23 # 0 +0x0000F6D6 0x9C8B # 0 +0x0000F6D7 0x9C8E # 0 +0x0000F6D8 0x9C90 # 0 +0x0000F6D9 0x9C91 # 0 +0x0000F6DA 0x9C92 # 0 +0x0000F6DB 0x9C94 # 0 +0x0000F6DC 0x9C95 # 0 +0x0000F6DD 0x9C9A # 0 +0x0000F6DE 0x9C9B # 0 +0x0000F6DF 0x9C9E # 0 +0x0000F6E0 0x9C9F # 0 +0x0000F6E1 0x9CA0 # 0 +0x0000F6E2 0x9CA1 # 0 +0x0000F6E3 0x9CA2 # 0 +0x0000F6E4 0x9CA3 # 0 +0x0000F6E5 0x9CA5 # 0 +0x0000F6E6 0x9CA6 # 0 +0x0000F6E7 0x9CA7 # 0 +0x0000F6E8 0x9CA8 # 0 +0x0000F6E9 0x9CA9 # 0 +0x0000F6EA 0x9CAB # 0 +0x0000F6EB 0x9CAD # 0 +0x0000F6EC 0x9CAE # 0 +0x0000F6ED 0x9CB0 # 0 +0x0000F6EE 0x9CB1 # 0 +0x0000F6EF 0x9CB2 # 0 +0x0000F6F0 0x9CB3 # 0 +0x0000F6F1 0x9CB4 # 0 +0x0000F6F2 0x9CB5 # 0 +0x0000F6F3 0x9CB6 # 0 +0x0000F6F4 0x9CB7 # 0 +0x0000F6F5 0x9CBA # 0 +0x0000F6F6 0x9CBB # 0 +0x0000F6F7 0x9CBC # 0 +0x0000F6F8 0x9CBD # 0 +0x0000F6F9 0x9CC4 # 0 +0x0000F6FA 0x9CC5 # 0 +0x0000F6FB 0x9CC6 # 0 +0x0000F6FC 0x9CC7 # 0 +0x0000F6FD 0x9CCA # 0 +0x0000F6FE 0x9CCB # 0 +0x0000F7A1 0x9CCC # 0 +0x0000F7A2 0x9CCD # 0 +0x0000F7A3 0x9CCE # 0 +0x0000F7A4 0x9CCF # 0 +0x0000F7A5 0x9CD0 # 0 +0x0000F7A6 0x9CD3 # 0 +0x0000F7A7 0x9CD4 # 0 +0x0000F7A8 0x9CD5 # 0 +0x0000F7A9 0x9CD7 # 0 +0x0000F7AA 0x9CD8 # 0 +0x0000F7AB 0x9CD9 # 0 +0x0000F7AC 0x9CDC # 0 +0x0000F7AD 0x9CDD # 0 +0x0000F7AE 0x9CDF # 0 +0x0000F7AF 0x9CE2 # 0 +0x0000F7B0 0x977C # 0 +0x0000F7B1 0x9785 # 0 +0x0000F7B2 0x9791 # 0 +0x0000F7B3 0x9792 # 0 +0x0000F7B4 0x9794 # 0 +0x0000F7B5 0x97AF # 0 +0x0000F7B6 0x97AB # 0 +0x0000F7B7 0x97A3 # 0 +0x0000F7B8 0x97B2 # 0 +0x0000F7B9 0x97B4 # 0 +0x0000F7BA 0x9AB1 # 0 +0x0000F7BB 0x9AB0 # 0 +0x0000F7BC 0x9AB7 # 0 +0x0000F7BD 0x9E58 # 0 +0x0000F7BE 0x9AB6 # 0 +0x0000F7BF 0x9ABA # 0 +0x0000F7C0 0x9ABC # 0 +0x0000F7C1 0x9AC1 # 0 +0x0000F7C2 0x9AC0 # 0 +0x0000F7C3 0x9AC5 # 0 +0x0000F7C4 0x9AC2 # 0 +0x0000F7C5 0x9ACB # 0 +0x0000F7C6 0x9ACC # 0 +0x0000F7C7 0x9AD1 # 0 +0x0000F7C8 0x9B45 # 0 +0x0000F7C9 0x9B43 # 0 +0x0000F7CA 0x9B47 # 0 +0x0000F7CB 0x9B49 # 0 +0x0000F7CC 0x9B48 # 0 +0x0000F7CD 0x9B4D # 0 +0x0000F7CE 0x9B51 # 0 +0x0000F7CF 0x98E8 # 0 +0x0000F7D0 0x990D # 0 +0x0000F7D1 0x992E # 0 +0x0000F7D2 0x9955 # 0 +0x0000F7D3 0x9954 # 0 +0x0000F7D4 0x9ADF # 0 +0x0000F7D5 0x9AE1 # 0 +0x0000F7D6 0x9AE6 # 0 +0x0000F7D7 0x9AEF # 0 +0x0000F7D8 0x9AEB # 0 +0x0000F7D9 0x9AFB # 0 +0x0000F7DA 0x9AED # 0 +0x0000F7DB 0x9AF9 # 0 +0x0000F7DC 0x9B08 # 0 +0x0000F7DD 0x9B0F # 0 +0x0000F7DE 0x9B13 # 0 +0x0000F7DF 0x9B1F # 0 +0x0000F7E0 0x9B23 # 0 +0x0000F7E1 0x9EBD # 0 +0x0000F7E2 0x9EBE # 0 +0x0000F7E3 0x7E3B # 0 +0x0000F7E4 0x9E82 # 0 +0x0000F7E5 0x9E87 # 0 +0x0000F7E6 0x9E88 # 0 +0x0000F7E7 0x9E8B # 0 +0x0000F7E8 0x9E92 # 0 +0x0000F7E9 0x93D6 # 0 +0x0000F7EA 0x9E9D # 0 +0x0000F7EB 0x9E9F # 0 +0x0000F7EC 0x9EDB # 0 +0x0000F7ED 0x9EDC # 0 +0x0000F7EE 0x9EDD # 0 +0x0000F7EF 0x9EE0 # 0 +0x0000F7F0 0x9EDF # 0 +0x0000F7F1 0x9EE2 # 0 +0x0000F7F2 0x9EE9 # 0 +0x0000F7F3 0x9EE7 # 0 +0x0000F7F4 0x9EE5 # 0 +0x0000F7F5 0x9EEA # 0 +0x0000F7F6 0x9EEF # 0 +0x0000F7F7 0x9F22 # 0 +0x0000F7F8 0x9F2C # 0 +0x0000F7F9 0x9F2F # 0 +0x0000F7FA 0x9F39 # 0 +0x0000F7FB 0x9F37 # 0 +0x0000F7FC 0x9F3D # 0 +0x0000F7FD 0x9F3E # 0 +0x0000F7FE 0x9F44 # 0 diff --git a/data/euc-jp.txt b/data/euc-jp.txt new file mode 100644 index 000000000..87af725e3 --- /dev/null +++ b/data/euc-jp.txt @@ -0,0 +1,15184 @@ +# euc-jp.txt - EUC to Unicode charmap +0x00000000 0x0000 # 0 +0x00000001 0x0001 # 0 +0x00000002 0x0002 # 0 +0x00000003 0x0003 # 0 +0x00000004 0x0004 # 0 +0x00000005 0x0005 # 0 +0x00000006 0x0006 # 0 +0x00000007 0x0007 # 0 +0x00000008 0x0008 # 0 +0x00000009 0x0009 # 0 +0x0000000A 0x000A # 0 +0x0000000B 0x000B # 0 +0x0000000C 0x000C # 0 +0x0000000D 0x000D # 0 +0x0000000E 0x000E # 0 +0x0000000F 0x000F # 0 +0x00000010 0x0010 # 0 +0x00000011 0x0011 # 0 +0x00000012 0x0012 # 0 +0x00000013 0x0013 # 0 +0x00000014 0x0014 # 0 +0x00000015 0x0015 # 0 +0x00000016 0x0016 # 0 +0x00000017 0x0017 # 0 +0x00000018 0x0018 # 0 +0x00000019 0x0019 # 0 +0x0000001A 0x001A # 0 +0x0000001B 0x001B # 0 +0x0000001C 0x001C # 0 +0x0000001D 0x001D # 0 +0x0000001E 0x001E # 0 +0x0000001F 0x001F # 0 +0x00000020 0x0020 # 0 +0x00000021 0x0021 # 0 +0x00000022 0x0022 # 0 +0x00000023 0x0023 # 0 +0x00000024 0x0024 # 0 +0x00000025 0x0025 # 0 +0x00000026 0x0026 # 0 +0x00000027 0x0027 # 0 +0x00000028 0x0028 # 0 +0x00000029 0x0029 # 0 +0x0000002A 0x002A # 0 +0x0000002B 0x002B # 0 +0x0000002C 0x002C # 0 +0x0000002D 0x002D # 0 +0x0000002E 0x002E # 0 +0x0000002F 0x002F # 0 +0x00000030 0x0030 # 0 +0x00000031 0x0031 # 0 +0x00000032 0x0032 # 0 +0x00000033 0x0033 # 0 +0x00000034 0x0034 # 0 +0x00000035 0x0035 # 0 +0x00000036 0x0036 # 0 +0x00000037 0x0037 # 0 +0x00000038 0x0038 # 0 +0x00000039 0x0039 # 0 +0x0000003A 0x003A # 0 +0x0000003B 0x003B # 0 +0x0000003C 0x003C # 0 +0x0000003D 0x003D # 0 +0x0000003E 0x003E # 0 +0x0000003F 0x003F # 0 +0x00000040 0x0040 # 0 +0x00000041 0x0041 # 0 +0x00000042 0x0042 # 0 +0x00000043 0x0043 # 0 +0x00000044 0x0044 # 0 +0x00000045 0x0045 # 0 +0x00000046 0x0046 # 0 +0x00000047 0x0047 # 0 +0x00000048 0x0048 # 0 +0x00000049 0x0049 # 0 +0x0000004A 0x004A # 0 +0x0000004B 0x004B # 0 +0x0000004C 0x004C # 0 +0x0000004D 0x004D # 0 +0x0000004E 0x004E # 0 +0x0000004F 0x004F # 0 +0x00000050 0x0050 # 0 +0x00000051 0x0051 # 0 +0x00000052 0x0052 # 0 +0x00000053 0x0053 # 0 +0x00000054 0x0054 # 0 +0x00000055 0x0055 # 0 +0x00000056 0x0056 # 0 +0x00000057 0x0057 # 0 +0x00000058 0x0058 # 0 +0x00000059 0x0059 # 0 +0x0000005A 0x005A # 0 +0x0000005B 0x005B # 0 +0x0000005C 0x005C # 0 +0x0000005D 0x005D # 0 +0x0000005E 0x005E # 0 +0x0000005F 0x005F # 0 +0x00000060 0x0060 # 0 +0x00000061 0x0061 # 0 +0x00000062 0x0062 # 0 +0x00000063 0x0063 # 0 +0x00000064 0x0064 # 0 +0x00000065 0x0065 # 0 +0x00000066 0x0066 # 0 +0x00000067 0x0067 # 0 +0x00000068 0x0068 # 0 +0x00000069 0x0069 # 0 +0x0000006A 0x006A # 0 +0x0000006B 0x006B # 0 +0x0000006C 0x006C # 0 +0x0000006D 0x006D # 0 +0x0000006E 0x006E # 0 +0x0000006F 0x006F # 0 +0x00000070 0x0070 # 0 +0x00000071 0x0071 # 0 +0x00000072 0x0072 # 0 +0x00000073 0x0073 # 0 +0x00000074 0x0074 # 0 +0x00000075 0x0075 # 0 +0x00000076 0x0076 # 0 +0x00000077 0x0077 # 0 +0x00000078 0x0078 # 0 +0x00000079 0x0079 # 0 +0x0000007A 0x007A # 0 +0x0000007B 0x007B # 0 +0x0000007C 0x007C # 0 +0x0000007D 0x007D # 0 +0x0000007E 0x007E # 0 +0x0000007F 0x007F # 0 +0x00008EA1 0xFF61 # 0 +0x00008EA2 0xFF62 # 0 +0x00008EA3 0xFF63 # 0 +0x00008EA4 0xFF64 # 0 +0x00008EA5 0xFF65 # 0 +0x00008EA6 0xFF66 # 0 +0x00008EA7 0xFF67 # 0 +0x00008EA8 0xFF68 # 0 +0x00008EA9 0xFF69 # 0 +0x00008EAA 0xFF6A # 0 +0x00008EAB 0xFF6B # 0 +0x00008EAC 0xFF6C # 0 +0x00008EAD 0xFF6D # 0 +0x00008EAE 0xFF6E # 0 +0x00008EAF 0xFF6F # 0 +0x00008EB0 0xFF70 # 0 +0x00008EB1 0xFF71 # 0 +0x00008EB2 0xFF72 # 0 +0x00008EB3 0xFF73 # 0 +0x00008EB4 0xFF74 # 0 +0x00008EB5 0xFF75 # 0 +0x00008EB6 0xFF76 # 0 +0x00008EB7 0xFF77 # 0 +0x00008EB8 0xFF78 # 0 +0x00008EB9 0xFF79 # 0 +0x00008EBA 0xFF7A # 0 +0x00008EBB 0xFF7B # 0 +0x00008EBC 0xFF7C # 0 +0x00008EBD 0xFF7D # 0 +0x00008EBE 0xFF7E # 0 +0x00008EBF 0xFF7F # 0 +0x00008EC0 0xFF80 # 0 +0x00008EC1 0xFF81 # 0 +0x00008EC2 0xFF82 # 0 +0x00008EC3 0xFF83 # 0 +0x00008EC4 0xFF84 # 0 +0x00008EC5 0xFF85 # 0 +0x00008EC6 0xFF86 # 0 +0x00008EC7 0xFF87 # 0 +0x00008EC8 0xFF88 # 0 +0x00008EC9 0xFF89 # 0 +0x00008ECA 0xFF8A # 0 +0x00008ECB 0xFF8B # 0 +0x00008ECC 0xFF8C # 0 +0x00008ECD 0xFF8D # 0 +0x00008ECE 0xFF8E # 0 +0x00008ECF 0xFF8F # 0 +0x00008ED0 0xFF90 # 0 +0x00008ED1 0xFF91 # 0 +0x00008ED2 0xFF92 # 0 +0x00008ED3 0xFF93 # 0 +0x00008ED4 0xFF94 # 0 +0x00008ED5 0xFF95 # 0 +0x00008ED6 0xFF96 # 0 +0x00008ED7 0xFF97 # 0 +0x00008ED8 0xFF98 # 0 +0x00008ED9 0xFF99 # 0 +0x00008EDA 0xFF9A # 0 +0x00008EDB 0xFF9B # 0 +0x00008EDC 0xFF9C # 0 +0x00008EDD 0xFF9D # 0 +0x00008EDE 0xFF9E # 0 +0x00008EDF 0xFF9F # 0 +0x0000A1A1 0x3000 # 0 +0x0000A1A2 0x3001 # 0 +0x0000A1A3 0x3002 # 0 +0x0000A1A4 0xFF0C # 0 +0x0000A1A5 0xFF0E # 0 +0x0000A1A6 0x30FB # 0 +0x0000A1A7 0xFF1A # 0 +0x0000A1A8 0xFF1B # 0 +0x0000A1A9 0xFF1F # 0 +0x0000A1AA 0xFF01 # 0 +0x0000A1AB 0x309B # 0 +0x0000A1AC 0x309C # 0 +0x0000A1AD 0x00B4 # 0 +0x0000A1AE 0xFF40 # 0 +0x0000A1AF 0x00A8 # 0 +0x0000A1B0 0xFF3E # 0 +0x0000A1B1 0xFFE3 # 0 +0x0000A1B2 0xFF3F # 0 +0x0000A1B3 0x30FD # 0 +0x0000A1B4 0x30FE # 0 +0x0000A1B5 0x309D # 0 +0x0000A1B6 0x309E # 0 +0x0000A1B7 0x3003 # 0 +0x0000A1B8 0x4EDD # 0 +0x0000A1B9 0x3005 # 0 +0x0000A1BA 0x3006 # 0 +0x0000A1BB 0x3007 # 0 +0x0000A1BC 0x30FC # 0 +0x0000A1BD 0x2015 # 0 +0x0000A1BE 0x2010 # 0 +0x0000A1BF 0xFF0F # 0 +0x0000A1C0 0xFF3C # 0 +0x0000A1C1 0x301C # 0 +0x0000A1C2 0x2016 # 0 +0x0000A1C3 0xFF5C # 0 +0x0000A1C4 0x2026 # 0 +0x0000A1C5 0x2025 # 0 +0x0000A1C6 0x2018 # 0 +0x0000A1C7 0x2019 # 0 +0x0000A1C8 0x201C # 0 +0x0000A1C9 0x201D # 0 +0x0000A1CA 0xFF08 # 0 +0x0000A1CB 0xFF09 # 0 +0x0000A1CC 0x3014 # 0 +0x0000A1CD 0x3015 # 0 +0x0000A1CE 0xFF3B # 0 +0x0000A1CF 0xFF3D # 0 +0x0000A1D0 0xFF5B # 0 +0x0000A1D1 0xFF5D # 0 +0x0000A1D2 0x3008 # 0 +0x0000A1D3 0x3009 # 0 +0x0000A1D4 0x300A # 0 +0x0000A1D5 0x300B # 0 +0x0000A1D6 0x300C # 0 +0x0000A1D7 0x300D # 0 +0x0000A1D8 0x300E # 0 +0x0000A1D9 0x300F # 0 +0x0000A1DA 0x3010 # 0 +0x0000A1DB 0x3011 # 0 +0x0000A1DC 0xFF0B # 0 +0x0000A1DD 0x2212 # 0 +0x0000A1DE 0x00B1 # 0 +0x0000A1DF 0x00D7 # 0 +0x0000A1E0 0x00F7 # 0 +0x0000A1E1 0xFF1D # 0 +0x0000A1E2 0x2260 # 0 +0x0000A1E3 0xFF1C # 0 +0x0000A1E4 0xFF1E # 0 +0x0000A1E5 0x2266 # 0 +0x0000A1E6 0x2267 # 0 +0x0000A1E7 0x221E # 0 +0x0000A1E8 0x2234 # 0 +0x0000A1E9 0x2642 # 0 +0x0000A1EA 0x2640 # 0 +0x0000A1EB 0x00B0 # 0 +0x0000A1EC 0x2032 # 0 +0x0000A1ED 0x2033 # 0 +0x0000A1EE 0x2103 # 0 +0x0000A1EF 0xFFE5 # 0 +0x0000A1F0 0xFF04 # 0 +0x0000A1F1 0x00A2 # 0 +0x0000A1F2 0x00A3 # 0 +0x0000A1F3 0xFF05 # 0 +0x0000A1F4 0xFF03 # 0 +0x0000A1F5 0xFF06 # 0 +0x0000A1F6 0xFF0A # 0 +0x0000A1F7 0xFF20 # 0 +0x0000A1F8 0x00A7 # 0 +0x0000A1F9 0x2606 # 0 +0x0000A1FA 0x2605 # 0 +0x0000A1FB 0x25CB # 0 +0x0000A1FC 0x25CF # 0 +0x0000A1FD 0x25CE # 0 +0x0000A1FE 0x25C7 # 0 +0x0000A2A1 0x25C6 # 0 +0x0000A2A2 0x25A1 # 0 +0x0000A2A3 0x25A0 # 0 +0x0000A2A4 0x25B3 # 0 +0x0000A2A5 0x25B2 # 0 +0x0000A2A6 0x25BD # 0 +0x0000A2A7 0x25BC # 0 +0x0000A2A8 0x203B # 0 +0x0000A2A9 0x3012 # 0 +0x0000A2AA 0x2192 # 0 +0x0000A2AB 0x2190 # 0 +0x0000A2AC 0x2191 # 0 +0x0000A2AD 0x2193 # 0 +0x0000A2AE 0x3013 # 0 +0x0000A2BA 0x2208 # 0 +0x0000A2BB 0x220B # 0 +0x0000A2BC 0x2286 # 0 +0x0000A2BD 0x2287 # 0 +0x0000A2BE 0x2282 # 0 +0x0000A2BF 0x2283 # 0 +0x0000A2C0 0x222A # 0 +0x0000A2C1 0x2229 # 0 +0x0000A2CA 0x2227 # 0 +0x0000A2CB 0x2228 # 0 +0x0000A2CC 0x00AC # 0 +0x0000A2CD 0x21D2 # 0 +0x0000A2CE 0x21D4 # 0 +0x0000A2CF 0x2200 # 0 +0x0000A2D0 0x2203 # 0 +0x0000A2DC 0x2220 # 0 +0x0000A2DD 0x22A5 # 0 +0x0000A2DE 0x2312 # 0 +0x0000A2DF 0x2202 # 0 +0x0000A2E0 0x2207 # 0 +0x0000A2E1 0x2261 # 0 +0x0000A2E2 0x2252 # 0 +0x0000A2E3 0x226A # 0 +0x0000A2E4 0x226B # 0 +0x0000A2E5 0x221A # 0 +0x0000A2E6 0x223D # 0 +0x0000A2E7 0x221D # 0 +0x0000A2E8 0x2235 # 0 +0x0000A2E9 0x222B # 0 +0x0000A2EA 0x222C # 0 +0x0000A2F2 0x212B # 0 +0x0000A2F3 0x2030 # 0 +0x0000A2F4 0x266F # 0 +0x0000A2F5 0x266D # 0 +0x0000A2F6 0x266A # 0 +0x0000A2F7 0x2020 # 0 +0x0000A2F8 0x2021 # 0 +0x0000A2F9 0x00B6 # 0 +0x0000A2FE 0x25EF # 0 +0x0000A3B0 0xFF10 # 0 +0x0000A3B1 0xFF11 # 0 +0x0000A3B2 0xFF12 # 0 +0x0000A3B3 0xFF13 # 0 +0x0000A3B4 0xFF14 # 0 +0x0000A3B5 0xFF15 # 0 +0x0000A3B6 0xFF16 # 0 +0x0000A3B7 0xFF17 # 0 +0x0000A3B8 0xFF18 # 0 +0x0000A3B9 0xFF19 # 0 +0x0000A3C1 0xFF21 # 0 +0x0000A3C2 0xFF22 # 0 +0x0000A3C3 0xFF23 # 0 +0x0000A3C4 0xFF24 # 0 +0x0000A3C5 0xFF25 # 0 +0x0000A3C6 0xFF26 # 0 +0x0000A3C7 0xFF27 # 0 +0x0000A3C8 0xFF28 # 0 +0x0000A3C9 0xFF29 # 0 +0x0000A3CA 0xFF2A # 0 +0x0000A3CB 0xFF2B # 0 +0x0000A3CC 0xFF2C # 0 +0x0000A3CD 0xFF2D # 0 +0x0000A3CE 0xFF2E # 0 +0x0000A3CF 0xFF2F # 0 +0x0000A3D0 0xFF30 # 0 +0x0000A3D1 0xFF31 # 0 +0x0000A3D2 0xFF32 # 0 +0x0000A3D3 0xFF33 # 0 +0x0000A3D4 0xFF34 # 0 +0x0000A3D5 0xFF35 # 0 +0x0000A3D6 0xFF36 # 0 +0x0000A3D7 0xFF37 # 0 +0x0000A3D8 0xFF38 # 0 +0x0000A3D9 0xFF39 # 0 +0x0000A3DA 0xFF3A # 0 +0x0000A3E1 0xFF41 # 0 +0x0000A3E2 0xFF42 # 0 +0x0000A3E3 0xFF43 # 0 +0x0000A3E4 0xFF44 # 0 +0x0000A3E5 0xFF45 # 0 +0x0000A3E6 0xFF46 # 0 +0x0000A3E7 0xFF47 # 0 +0x0000A3E8 0xFF48 # 0 +0x0000A3E9 0xFF49 # 0 +0x0000A3EA 0xFF4A # 0 +0x0000A3EB 0xFF4B # 0 +0x0000A3EC 0xFF4C # 0 +0x0000A3ED 0xFF4D # 0 +0x0000A3EE 0xFF4E # 0 +0x0000A3EF 0xFF4F # 0 +0x0000A3F0 0xFF50 # 0 +0x0000A3F1 0xFF51 # 0 +0x0000A3F2 0xFF52 # 0 +0x0000A3F3 0xFF53 # 0 +0x0000A3F4 0xFF54 # 0 +0x0000A3F5 0xFF55 # 0 +0x0000A3F6 0xFF56 # 0 +0x0000A3F7 0xFF57 # 0 +0x0000A3F8 0xFF58 # 0 +0x0000A3F9 0xFF59 # 0 +0x0000A3FA 0xFF5A # 0 +0x0000A4A1 0x3041 # 0 +0x0000A4A2 0x3042 # 0 +0x0000A4A3 0x3043 # 0 +0x0000A4A4 0x3044 # 0 +0x0000A4A5 0x3045 # 0 +0x0000A4A6 0x3046 # 0 +0x0000A4A7 0x3047 # 0 +0x0000A4A8 0x3048 # 0 +0x0000A4A9 0x3049 # 0 +0x0000A4AA 0x304A # 0 +0x0000A4AB 0x304B # 0 +0x0000A4AC 0x304C # 0 +0x0000A4AD 0x304D # 0 +0x0000A4AE 0x304E # 0 +0x0000A4AF 0x304F # 0 +0x0000A4B0 0x3050 # 0 +0x0000A4B1 0x3051 # 0 +0x0000A4B2 0x3052 # 0 +0x0000A4B3 0x3053 # 0 +0x0000A4B4 0x3054 # 0 +0x0000A4B5 0x3055 # 0 +0x0000A4B6 0x3056 # 0 +0x0000A4B7 0x3057 # 0 +0x0000A4B8 0x3058 # 0 +0x0000A4B9 0x3059 # 0 +0x0000A4BA 0x305A # 0 +0x0000A4BB 0x305B # 0 +0x0000A4BC 0x305C # 0 +0x0000A4BD 0x305D # 0 +0x0000A4BE 0x305E # 0 +0x0000A4BF 0x305F # 0 +0x0000A4C0 0x3060 # 0 +0x0000A4C1 0x3061 # 0 +0x0000A4C2 0x3062 # 0 +0x0000A4C3 0x3063 # 0 +0x0000A4C4 0x3064 # 0 +0x0000A4C5 0x3065 # 0 +0x0000A4C6 0x3066 # 0 +0x0000A4C7 0x3067 # 0 +0x0000A4C8 0x3068 # 0 +0x0000A4C9 0x3069 # 0 +0x0000A4CA 0x306A # 0 +0x0000A4CB 0x306B # 0 +0x0000A4CC 0x306C # 0 +0x0000A4CD 0x306D # 0 +0x0000A4CE 0x306E # 0 +0x0000A4CF 0x306F # 0 +0x0000A4D0 0x3070 # 0 +0x0000A4D1 0x3071 # 0 +0x0000A4D2 0x3072 # 0 +0x0000A4D3 0x3073 # 0 +0x0000A4D4 0x3074 # 0 +0x0000A4D5 0x3075 # 0 +0x0000A4D6 0x3076 # 0 +0x0000A4D7 0x3077 # 0 +0x0000A4D8 0x3078 # 0 +0x0000A4D9 0x3079 # 0 +0x0000A4DA 0x307A # 0 +0x0000A4DB 0x307B # 0 +0x0000A4DC 0x307C # 0 +0x0000A4DD 0x307D # 0 +0x0000A4DE 0x307E # 0 +0x0000A4DF 0x307F # 0 +0x0000A4E0 0x3080 # 0 +0x0000A4E1 0x3081 # 0 +0x0000A4E2 0x3082 # 0 +0x0000A4E3 0x3083 # 0 +0x0000A4E4 0x3084 # 0 +0x0000A4E5 0x3085 # 0 +0x0000A4E6 0x3086 # 0 +0x0000A4E7 0x3087 # 0 +0x0000A4E8 0x3088 # 0 +0x0000A4E9 0x3089 # 0 +0x0000A4EA 0x308A # 0 +0x0000A4EB 0x308B # 0 +0x0000A4EC 0x308C # 0 +0x0000A4ED 0x308D # 0 +0x0000A4EE 0x308E # 0 +0x0000A4EF 0x308F # 0 +0x0000A4F0 0x3090 # 0 +0x0000A4F1 0x3091 # 0 +0x0000A4F2 0x3092 # 0 +0x0000A4F3 0x3093 # 0 +0x0000A5A1 0x30A1 # 0 +0x0000A5A2 0x30A2 # 0 +0x0000A5A3 0x30A3 # 0 +0x0000A5A4 0x30A4 # 0 +0x0000A5A5 0x30A5 # 0 +0x0000A5A6 0x30A6 # 0 +0x0000A5A7 0x30A7 # 0 +0x0000A5A8 0x30A8 # 0 +0x0000A5A9 0x30A9 # 0 +0x0000A5AA 0x30AA # 0 +0x0000A5AB 0x30AB # 0 +0x0000A5AC 0x30AC # 0 +0x0000A5AD 0x30AD # 0 +0x0000A5AE 0x30AE # 0 +0x0000A5AF 0x30AF # 0 +0x0000A5B0 0x30B0 # 0 +0x0000A5B1 0x30B1 # 0 +0x0000A5B2 0x30B2 # 0 +0x0000A5B3 0x30B3 # 0 +0x0000A5B4 0x30B4 # 0 +0x0000A5B5 0x30B5 # 0 +0x0000A5B6 0x30B6 # 0 +0x0000A5B7 0x30B7 # 0 +0x0000A5B8 0x30B8 # 0 +0x0000A5B9 0x30B9 # 0 +0x0000A5BA 0x30BA # 0 +0x0000A5BB 0x30BB # 0 +0x0000A5BC 0x30BC # 0 +0x0000A5BD 0x30BD # 0 +0x0000A5BE 0x30BE # 0 +0x0000A5BF 0x30BF # 0 +0x0000A5C0 0x30C0 # 0 +0x0000A5C1 0x30C1 # 0 +0x0000A5C2 0x30C2 # 0 +0x0000A5C3 0x30C3 # 0 +0x0000A5C4 0x30C4 # 0 +0x0000A5C5 0x30C5 # 0 +0x0000A5C6 0x30C6 # 0 +0x0000A5C7 0x30C7 # 0 +0x0000A5C8 0x30C8 # 0 +0x0000A5C9 0x30C9 # 0 +0x0000A5CA 0x30CA # 0 +0x0000A5CB 0x30CB # 0 +0x0000A5CC 0x30CC # 0 +0x0000A5CD 0x30CD # 0 +0x0000A5CE 0x30CE # 0 +0x0000A5CF 0x30CF # 0 +0x0000A5D0 0x30D0 # 0 +0x0000A5D1 0x30D1 # 0 +0x0000A5D2 0x30D2 # 0 +0x0000A5D3 0x30D3 # 0 +0x0000A5D4 0x30D4 # 0 +0x0000A5D5 0x30D5 # 0 +0x0000A5D6 0x30D6 # 0 +0x0000A5D7 0x30D7 # 0 +0x0000A5D8 0x30D8 # 0 +0x0000A5D9 0x30D9 # 0 +0x0000A5DA 0x30DA # 0 +0x0000A5DB 0x30DB # 0 +0x0000A5DC 0x30DC # 0 +0x0000A5DD 0x30DD # 0 +0x0000A5DE 0x30DE # 0 +0x0000A5DF 0x30DF # 0 +0x0000A5E0 0x30E0 # 0 +0x0000A5E1 0x30E1 # 0 +0x0000A5E2 0x30E2 # 0 +0x0000A5E3 0x30E3 # 0 +0x0000A5E4 0x30E4 # 0 +0x0000A5E5 0x30E5 # 0 +0x0000A5E6 0x30E6 # 0 +0x0000A5E7 0x30E7 # 0 +0x0000A5E8 0x30E8 # 0 +0x0000A5E9 0x30E9 # 0 +0x0000A5EA 0x30EA # 0 +0x0000A5EB 0x30EB # 0 +0x0000A5EC 0x30EC # 0 +0x0000A5ED 0x30ED # 0 +0x0000A5EE 0x30EE # 0 +0x0000A5EF 0x30EF # 0 +0x0000A5F0 0x30F0 # 0 +0x0000A5F1 0x30F1 # 0 +0x0000A5F2 0x30F2 # 0 +0x0000A5F3 0x30F3 # 0 +0x0000A5F4 0x30F4 # 0 +0x0000A5F5 0x30F5 # 0 +0x0000A5F6 0x30F6 # 0 +0x0000A6A1 0x0391 # 0 +0x0000A6A2 0x0392 # 0 +0x0000A6A3 0x0393 # 0 +0x0000A6A4 0x0394 # 0 +0x0000A6A5 0x0395 # 0 +0x0000A6A6 0x0396 # 0 +0x0000A6A7 0x0397 # 0 +0x0000A6A8 0x0398 # 0 +0x0000A6A9 0x0399 # 0 +0x0000A6AA 0x039A # 0 +0x0000A6AB 0x039B # 0 +0x0000A6AC 0x039C # 0 +0x0000A6AD 0x039D # 0 +0x0000A6AE 0x039E # 0 +0x0000A6AF 0x039F # 0 +0x0000A6B0 0x03A0 # 0 +0x0000A6B1 0x03A1 # 0 +0x0000A6B2 0x03A3 # 0 +0x0000A6B3 0x03A4 # 0 +0x0000A6B4 0x03A5 # 0 +0x0000A6B5 0x03A6 # 0 +0x0000A6B6 0x03A7 # 0 +0x0000A6B7 0x03A8 # 0 +0x0000A6B8 0x03A9 # 0 +0x0000A6C1 0x03B1 # 0 +0x0000A6C2 0x03B2 # 0 +0x0000A6C3 0x03B3 # 0 +0x0000A6C4 0x03B4 # 0 +0x0000A6C5 0x03B5 # 0 +0x0000A6C6 0x03B6 # 0 +0x0000A6C7 0x03B7 # 0 +0x0000A6C8 0x03B8 # 0 +0x0000A6C9 0x03B9 # 0 +0x0000A6CA 0x03BA # 0 +0x0000A6CB 0x03BB # 0 +0x0000A6CC 0x03BC # 0 +0x0000A6CD 0x03BD # 0 +0x0000A6CE 0x03BE # 0 +0x0000A6CF 0x03BF # 0 +0x0000A6D0 0x03C0 # 0 +0x0000A6D1 0x03C1 # 0 +0x0000A6D2 0x03C3 # 0 +0x0000A6D3 0x03C4 # 0 +0x0000A6D4 0x03C5 # 0 +0x0000A6D5 0x03C6 # 0 +0x0000A6D6 0x03C7 # 0 +0x0000A6D7 0x03C8 # 0 +0x0000A6D8 0x03C9 # 0 +0x0000A7A1 0x0410 # 0 +0x0000A7A2 0x0411 # 0 +0x0000A7A3 0x0412 # 0 +0x0000A7A4 0x0413 # 0 +0x0000A7A5 0x0414 # 0 +0x0000A7A6 0x0415 # 0 +0x0000A7A7 0x0401 # 0 +0x0000A7A8 0x0416 # 0 +0x0000A7A9 0x0417 # 0 +0x0000A7AA 0x0418 # 0 +0x0000A7AB 0x0419 # 0 +0x0000A7AC 0x041A # 0 +0x0000A7AD 0x041B # 0 +0x0000A7AE 0x041C # 0 +0x0000A7AF 0x041D # 0 +0x0000A7B0 0x041E # 0 +0x0000A7B1 0x041F # 0 +0x0000A7B2 0x0420 # 0 +0x0000A7B3 0x0421 # 0 +0x0000A7B4 0x0422 # 0 +0x0000A7B5 0x0423 # 0 +0x0000A7B6 0x0424 # 0 +0x0000A7B7 0x0425 # 0 +0x0000A7B8 0x0426 # 0 +0x0000A7B9 0x0427 # 0 +0x0000A7BA 0x0428 # 0 +0x0000A7BB 0x0429 # 0 +0x0000A7BC 0x042A # 0 +0x0000A7BD 0x042B # 0 +0x0000A7BE 0x042C # 0 +0x0000A7BF 0x042D # 0 +0x0000A7C0 0x042E # 0 +0x0000A7C1 0x042F # 0 +0x0000A7D1 0x0430 # 0 +0x0000A7D2 0x0431 # 0 +0x0000A7D3 0x0432 # 0 +0x0000A7D4 0x0433 # 0 +0x0000A7D5 0x0434 # 0 +0x0000A7D6 0x0435 # 0 +0x0000A7D7 0x0451 # 0 +0x0000A7D8 0x0436 # 0 +0x0000A7D9 0x0437 # 0 +0x0000A7DA 0x0438 # 0 +0x0000A7DB 0x0439 # 0 +0x0000A7DC 0x043A # 0 +0x0000A7DD 0x043B # 0 +0x0000A7DE 0x043C # 0 +0x0000A7DF 0x043D # 0 +0x0000A7E0 0x043E # 0 +0x0000A7E1 0x043F # 0 +0x0000A7E2 0x0440 # 0 +0x0000A7E3 0x0441 # 0 +0x0000A7E4 0x0442 # 0 +0x0000A7E5 0x0443 # 0 +0x0000A7E6 0x0444 # 0 +0x0000A7E7 0x0445 # 0 +0x0000A7E8 0x0446 # 0 +0x0000A7E9 0x0447 # 0 +0x0000A7EA 0x0448 # 0 +0x0000A7EB 0x0449 # 0 +0x0000A7EC 0x044A # 0 +0x0000A7ED 0x044B # 0 +0x0000A7EE 0x044C # 0 +0x0000A7EF 0x044D # 0 +0x0000A7F0 0x044E # 0 +0x0000A7F1 0x044F # 0 +0x0000A8A1 0x2500 # 0 +0x0000A8A2 0x2502 # 0 +0x0000A8A3 0x250C # 0 +0x0000A8A4 0x2510 # 0 +0x0000A8A5 0x2518 # 0 +0x0000A8A6 0x2514 # 0 +0x0000A8A7 0x251C # 0 +0x0000A8A8 0x252C # 0 +0x0000A8A9 0x2524 # 0 +0x0000A8AA 0x2534 # 0 +0x0000A8AB 0x253C # 0 +0x0000A8AC 0x2501 # 0 +0x0000A8AD 0x2503 # 0 +0x0000A8AE 0x250F # 0 +0x0000A8AF 0x2513 # 0 +0x0000A8B0 0x251B # 0 +0x0000A8B1 0x2517 # 0 +0x0000A8B2 0x2523 # 0 +0x0000A8B3 0x2533 # 0 +0x0000A8B4 0x252B # 0 +0x0000A8B5 0x253B # 0 +0x0000A8B6 0x254B # 0 +0x0000A8B7 0x2520 # 0 +0x0000A8B8 0x252F # 0 +0x0000A8B9 0x2528 # 0 +0x0000A8BA 0x2537 # 0 +0x0000A8BB 0x253F # 0 +0x0000A8BC 0x251D # 0 +0x0000A8BD 0x2530 # 0 +0x0000A8BE 0x2525 # 0 +0x0000A8BF 0x2538 # 0 +0x0000A8C0 0x2542 # 0 +0x0000ADA1 0x2460 # 0 +0x0000ADA2 0x2461 # 0 +0x0000ADA3 0x2462 # 0 +0x0000ADA4 0x2463 # 0 +0x0000ADA5 0x2464 # 0 +0x0000ADA6 0x2465 # 0 +0x0000ADA7 0x2466 # 0 +0x0000ADA8 0x2467 # 0 +0x0000ADA9 0x2468 # 0 +0x0000ADAA 0x2469 # 0 +0x0000ADAB 0x246A # 0 +0x0000ADAC 0x246B # 0 +0x0000ADAD 0x246C # 0 +0x0000ADAE 0x246D # 0 +0x0000ADAF 0x246E # 0 +0x0000ADB0 0x246F # 0 +0x0000ADB1 0x2470 # 0 +0x0000ADB2 0x2471 # 0 +0x0000ADB3 0x2472 # 0 +0x0000ADB4 0x2473 # 0 +0x0000ADB5 0x2160 # 0 +0x0000ADB6 0x2161 # 0 +0x0000ADB7 0x2162 # 0 +0x0000ADB8 0x2163 # 0 +0x0000ADB9 0x2164 # 0 +0x0000ADBA 0x2165 # 0 +0x0000ADBB 0x2166 # 0 +0x0000ADBC 0x2167 # 0 +0x0000ADBD 0x2168 # 0 +0x0000ADBE 0x2169 # 0 +0x0000ADC0 0x3349 # 0 +0x0000ADC1 0x3314 # 0 +0x0000ADC2 0x3322 # 0 +0x0000ADC3 0x334D # 0 +0x0000ADC4 0x3318 # 0 +0x0000ADC5 0x3327 # 0 +0x0000ADC6 0x3303 # 0 +0x0000ADC7 0x3336 # 0 +0x0000ADC8 0x3351 # 0 +0x0000ADC9 0x3357 # 0 +0x0000ADCA 0x330D # 0 +0x0000ADCB 0x3326 # 0 +0x0000ADCC 0x3323 # 0 +0x0000ADCD 0x332B # 0 +0x0000ADCE 0x334A # 0 +0x0000ADCF 0x333B # 0 +0x0000ADD0 0x339C # 0 +0x0000ADD1 0x339D # 0 +0x0000ADD2 0x339E # 0 +0x0000ADD3 0x338E # 0 +0x0000ADD4 0x338F # 0 +0x0000ADD5 0x33C4 # 0 +0x0000ADD6 0x33A1 # 0 +0x0000ADDF 0x337B # 0 +0x0000ADE0 0x301D # 0 +0x0000ADE1 0x301F # 0 +0x0000ADE3 0x33CD # 0 +0x0000ADE4 0x2121 # 0 +0x0000ADE5 0x32A4 # 0 +0x0000ADE6 0x32A5 # 0 +0x0000ADE7 0x32A6 # 0 +0x0000ADE8 0x32A7 # 0 +0x0000ADE9 0x32A8 # 0 +0x0000ADEA 0x3231 # 0 +0x0000ADEB 0x3232 # 0 +0x0000ADEC 0x3239 # 0 +0x0000ADED 0x337E # 0 +0x0000ADEE 0x337D # 0 +0x0000ADEF 0x337C # 0 +0x0000ADF3 0x222E # 0 +0x0000ADF4 0x2211 # 0 +0x0000ADF8 0x221F # 0 +0x0000ADF9 0x22BF # 0 +0x0000B0A1 0x4E9C # 0 +0x0000B0A2 0x5516 # 0 +0x0000B0A3 0x5A03 # 0 +0x0000B0A4 0x963F # 0 +0x0000B0A5 0x54C0 # 0 +0x0000B0A6 0x611B # 0 +0x0000B0A7 0x6328 # 0 +0x0000B0A8 0x59F6 # 0 +0x0000B0A9 0x9022 # 0 +0x0000B0AA 0x8475 # 0 +0x0000B0AB 0x831C # 0 +0x0000B0AC 0x7A50 # 0 +0x0000B0AD 0x60AA # 0 +0x0000B0AE 0x63E1 # 0 +0x0000B0AF 0x6E25 # 0 +0x0000B0B0 0x65ED # 0 +0x0000B0B1 0x8466 # 0 +0x0000B0B2 0x82A6 # 0 +0x0000B0B3 0x9BF5 # 0 +0x0000B0B4 0x6893 # 0 +0x0000B0B5 0x5727 # 0 +0x0000B0B6 0x65A1 # 0 +0x0000B0B7 0x6271 # 0 +0x0000B0B8 0x5B9B # 0 +0x0000B0B9 0x59D0 # 0 +0x0000B0BA 0x867B # 0 +0x0000B0BB 0x98F4 # 0 +0x0000B0BC 0x7D62 # 0 +0x0000B0BD 0x7DBE # 0 +0x0000B0BE 0x9B8E # 0 +0x0000B0BF 0x6216 # 0 +0x0000B0C0 0x7C9F # 0 +0x0000B0C1 0x88B7 # 0 +0x0000B0C2 0x5B89 # 0 +0x0000B0C3 0x5EB5 # 0 +0x0000B0C4 0x6309 # 0 +0x0000B0C5 0x6697 # 0 +0x0000B0C6 0x6848 # 0 +0x0000B0C7 0x95C7 # 0 +0x0000B0C8 0x978D # 0 +0x0000B0C9 0x674F # 0 +0x0000B0CA 0x4EE5 # 0 +0x0000B0CB 0x4F0A # 0 +0x0000B0CC 0x4F4D # 0 +0x0000B0CD 0x4F9D # 0 +0x0000B0CE 0x5049 # 0 +0x0000B0CF 0x56F2 # 0 +0x0000B0D0 0x5937 # 0 +0x0000B0D1 0x59D4 # 0 +0x0000B0D2 0x5A01 # 0 +0x0000B0D3 0x5C09 # 0 +0x0000B0D4 0x60DF # 0 +0x0000B0D5 0x610F # 0 +0x0000B0D6 0x6170 # 0 +0x0000B0D7 0x6613 # 0 +0x0000B0D8 0x6905 # 0 +0x0000B0D9 0x70BA # 0 +0x0000B0DA 0x754F # 0 +0x0000B0DB 0x7570 # 0 +0x0000B0DC 0x79FB # 0 +0x0000B0DD 0x7DAD # 0 +0x0000B0DE 0x7DEF # 0 +0x0000B0DF 0x80C3 # 0 +0x0000B0E0 0x840E # 0 +0x0000B0E1 0x8863 # 0 +0x0000B0E2 0x8B02 # 0 +0x0000B0E3 0x9055 # 0 +0x0000B0E4 0x907A # 0 +0x0000B0E5 0x533B # 0 +0x0000B0E6 0x4E95 # 0 +0x0000B0E7 0x4EA5 # 0 +0x0000B0E8 0x57DF # 0 +0x0000B0E9 0x80B2 # 0 +0x0000B0EA 0x90C1 # 0 +0x0000B0EB 0x78EF # 0 +0x0000B0EC 0x4E00 # 0 +0x0000B0ED 0x58F1 # 0 +0x0000B0EE 0x6EA2 # 0 +0x0000B0EF 0x9038 # 0 +0x0000B0F0 0x7A32 # 0 +0x0000B0F1 0x8328 # 0 +0x0000B0F2 0x828B # 0 +0x0000B0F3 0x9C2F # 0 +0x0000B0F4 0x5141 # 0 +0x0000B0F5 0x5370 # 0 +0x0000B0F6 0x54BD # 0 +0x0000B0F7 0x54E1 # 0 +0x0000B0F8 0x56E0 # 0 +0x0000B0F9 0x59FB # 0 +0x0000B0FA 0x5F15 # 0 +0x0000B0FB 0x98F2 # 0 +0x0000B0FC 0x6DEB # 0 +0x0000B0FD 0x80E4 # 0 +0x0000B0FE 0x852D # 0 +0x0000B1A1 0x9662 # 0 +0x0000B1A2 0x9670 # 0 +0x0000B1A3 0x96A0 # 0 +0x0000B1A4 0x97FB # 0 +0x0000B1A5 0x540B # 0 +0x0000B1A6 0x53F3 # 0 +0x0000B1A7 0x5B87 # 0 +0x0000B1A8 0x70CF # 0 +0x0000B1A9 0x7FBD # 0 +0x0000B1AA 0x8FC2 # 0 +0x0000B1AB 0x96E8 # 0 +0x0000B1AC 0x536F # 0 +0x0000B1AD 0x9D5C # 0 +0x0000B1AE 0x7ABA # 0 +0x0000B1AF 0x4E11 # 0 +0x0000B1B0 0x7893 # 0 +0x0000B1B1 0x81FC # 0 +0x0000B1B2 0x6E26 # 0 +0x0000B1B3 0x5618 # 0 +0x0000B1B4 0x5504 # 0 +0x0000B1B5 0x6B1D # 0 +0x0000B1B6 0x851A # 0 +0x0000B1B7 0x9C3B # 0 +0x0000B1B8 0x59E5 # 0 +0x0000B1B9 0x53A9 # 0 +0x0000B1BA 0x6D66 # 0 +0x0000B1BB 0x74DC # 0 +0x0000B1BC 0x958F # 0 +0x0000B1BD 0x5642 # 0 +0x0000B1BE 0x4E91 # 0 +0x0000B1BF 0x904B # 0 +0x0000B1C0 0x96F2 # 0 +0x0000B1C1 0x834F # 0 +0x0000B1C2 0x990C # 0 +0x0000B1C3 0x53E1 # 0 +0x0000B1C4 0x55B6 # 0 +0x0000B1C5 0x5B30 # 0 +0x0000B1C6 0x5F71 # 0 +0x0000B1C7 0x6620 # 0 +0x0000B1C8 0x66F3 # 0 +0x0000B1C9 0x6804 # 0 +0x0000B1CA 0x6C38 # 0 +0x0000B1CB 0x6CF3 # 0 +0x0000B1CC 0x6D29 # 0 +0x0000B1CD 0x745B # 0 +0x0000B1CE 0x76C8 # 0 +0x0000B1CF 0x7A4E # 0 +0x0000B1D0 0x9834 # 0 +0x0000B1D1 0x82F1 # 0 +0x0000B1D2 0x885B # 0 +0x0000B1D3 0x8A60 # 0 +0x0000B1D4 0x92ED # 0 +0x0000B1D5 0x6DB2 # 0 +0x0000B1D6 0x75AB # 0 +0x0000B1D7 0x76CA # 0 +0x0000B1D8 0x99C5 # 0 +0x0000B1D9 0x60A6 # 0 +0x0000B1DA 0x8B01 # 0 +0x0000B1DB 0x8D8A # 0 +0x0000B1DC 0x95B2 # 0 +0x0000B1DD 0x698E # 0 +0x0000B1DE 0x53AD # 0 +0x0000B1DF 0x5186 # 0 +0x0000B1E0 0x5712 # 0 +0x0000B1E1 0x5830 # 0 +0x0000B1E2 0x5944 # 0 +0x0000B1E3 0x5BB4 # 0 +0x0000B1E4 0x5EF6 # 0 +0x0000B1E5 0x6028 # 0 +0x0000B1E6 0x63A9 # 0 +0x0000B1E7 0x63F4 # 0 +0x0000B1E8 0x6CBF # 0 +0x0000B1E9 0x6F14 # 0 +0x0000B1EA 0x708E # 0 +0x0000B1EB 0x7114 # 0 +0x0000B1EC 0x7159 # 0 +0x0000B1ED 0x71D5 # 0 +0x0000B1EE 0x733F # 0 +0x0000B1EF 0x7E01 # 0 +0x0000B1F0 0x8276 # 0 +0x0000B1F1 0x82D1 # 0 +0x0000B1F2 0x8597 # 0 +0x0000B1F3 0x9060 # 0 +0x0000B1F4 0x925B # 0 +0x0000B1F5 0x9D1B # 0 +0x0000B1F6 0x5869 # 0 +0x0000B1F7 0x65BC # 0 +0x0000B1F8 0x6C5A # 0 +0x0000B1F9 0x7525 # 0 +0x0000B1FA 0x51F9 # 0 +0x0000B1FB 0x592E # 0 +0x0000B1FC 0x5965 # 0 +0x0000B1FD 0x5F80 # 0 +0x0000B1FE 0x5FDC # 0 +0x0000B2A1 0x62BC # 0 +0x0000B2A2 0x65FA # 0 +0x0000B2A3 0x6A2A # 0 +0x0000B2A4 0x6B27 # 0 +0x0000B2A5 0x6BB4 # 0 +0x0000B2A6 0x738B # 0 +0x0000B2A7 0x7FC1 # 0 +0x0000B2A8 0x8956 # 0 +0x0000B2A9 0x9D2C # 0 +0x0000B2AA 0x9D0E # 0 +0x0000B2AB 0x9EC4 # 0 +0x0000B2AC 0x5CA1 # 0 +0x0000B2AD 0x6C96 # 0 +0x0000B2AE 0x837B # 0 +0x0000B2AF 0x5104 # 0 +0x0000B2B0 0x5C4B # 0 +0x0000B2B1 0x61B6 # 0 +0x0000B2B2 0x81C6 # 0 +0x0000B2B3 0x6876 # 0 +0x0000B2B4 0x7261 # 0 +0x0000B2B5 0x4E59 # 0 +0x0000B2B6 0x4FFA # 0 +0x0000B2B7 0x5378 # 0 +0x0000B2B8 0x6069 # 0 +0x0000B2B9 0x6E29 # 0 +0x0000B2BA 0x7A4F # 0 +0x0000B2BB 0x97F3 # 0 +0x0000B2BC 0x4E0B # 0 +0x0000B2BD 0x5316 # 0 +0x0000B2BE 0x4EEE # 0 +0x0000B2BF 0x4F55 # 0 +0x0000B2C0 0x4F3D # 0 +0x0000B2C1 0x4FA1 # 0 +0x0000B2C2 0x4F73 # 0 +0x0000B2C3 0x52A0 # 0 +0x0000B2C4 0x53EF # 0 +0x0000B2C5 0x5609 # 0 +0x0000B2C6 0x590F # 0 +0x0000B2C7 0x5AC1 # 0 +0x0000B2C8 0x5BB6 # 0 +0x0000B2C9 0x5BE1 # 0 +0x0000B2CA 0x79D1 # 0 +0x0000B2CB 0x6687 # 0 +0x0000B2CC 0x679C # 0 +0x0000B2CD 0x67B6 # 0 +0x0000B2CE 0x6B4C # 0 +0x0000B2CF 0x6CB3 # 0 +0x0000B2D0 0x706B # 0 +0x0000B2D1 0x73C2 # 0 +0x0000B2D2 0x798D # 0 +0x0000B2D3 0x79BE # 0 +0x0000B2D4 0x7A3C # 0 +0x0000B2D5 0x7B87 # 0 +0x0000B2D6 0x82B1 # 0 +0x0000B2D7 0x82DB # 0 +0x0000B2D8 0x8304 # 0 +0x0000B2D9 0x8377 # 0 +0x0000B2DA 0x83EF # 0 +0x0000B2DB 0x83D3 # 0 +0x0000B2DC 0x8766 # 0 +0x0000B2DD 0x8AB2 # 0 +0x0000B2DE 0x5629 # 0 +0x0000B2DF 0x8CA8 # 0 +0x0000B2E0 0x8FE6 # 0 +0x0000B2E1 0x904E # 0 +0x0000B2E2 0x971E # 0 +0x0000B2E3 0x868A # 0 +0x0000B2E4 0x4FC4 # 0 +0x0000B2E5 0x5CE8 # 0 +0x0000B2E6 0x6211 # 0 +0x0000B2E7 0x7259 # 0 +0x0000B2E8 0x753B # 0 +0x0000B2E9 0x81E5 # 0 +0x0000B2EA 0x82BD # 0 +0x0000B2EB 0x86FE # 0 +0x0000B2EC 0x8CC0 # 0 +0x0000B2ED 0x96C5 # 0 +0x0000B2EE 0x9913 # 0 +0x0000B2EF 0x99D5 # 0 +0x0000B2F0 0x4ECB # 0 +0x0000B2F1 0x4F1A # 0 +0x0000B2F2 0x89E3 # 0 +0x0000B2F3 0x56DE # 0 +0x0000B2F4 0x584A # 0 +0x0000B2F5 0x58CA # 0 +0x0000B2F6 0x5EFB # 0 +0x0000B2F7 0x5FEB # 0 +0x0000B2F8 0x602A # 0 +0x0000B2F9 0x6094 # 0 +0x0000B2FA 0x6062 # 0 +0x0000B2FB 0x61D0 # 0 +0x0000B2FC 0x6212 # 0 +0x0000B2FD 0x62D0 # 0 +0x0000B2FE 0x6539 # 0 +0x0000B3A1 0x9B41 # 0 +0x0000B3A2 0x6666 # 0 +0x0000B3A3 0x68B0 # 0 +0x0000B3A4 0x6D77 # 0 +0x0000B3A5 0x7070 # 0 +0x0000B3A6 0x754C # 0 +0x0000B3A7 0x7686 # 0 +0x0000B3A8 0x7D75 # 0 +0x0000B3A9 0x82A5 # 0 +0x0000B3AA 0x87F9 # 0 +0x0000B3AB 0x958B # 0 +0x0000B3AC 0x968E # 0 +0x0000B3AD 0x8C9D # 0 +0x0000B3AE 0x51F1 # 0 +0x0000B3AF 0x52BE # 0 +0x0000B3B0 0x5916 # 0 +0x0000B3B1 0x54B3 # 0 +0x0000B3B2 0x5BB3 # 0 +0x0000B3B3 0x5D16 # 0 +0x0000B3B4 0x6168 # 0 +0x0000B3B5 0x6982 # 0 +0x0000B3B6 0x6DAF # 0 +0x0000B3B7 0x788D # 0 +0x0000B3B8 0x84CB # 0 +0x0000B3B9 0x8857 # 0 +0x0000B3BA 0x8A72 # 0 +0x0000B3BB 0x93A7 # 0 +0x0000B3BC 0x9AB8 # 0 +0x0000B3BD 0x6D6C # 0 +0x0000B3BE 0x99A8 # 0 +0x0000B3BF 0x86D9 # 0 +0x0000B3C0 0x57A3 # 0 +0x0000B3C1 0x67FF # 0 +0x0000B3C2 0x86CE # 0 +0x0000B3C3 0x920E # 0 +0x0000B3C4 0x5283 # 0 +0x0000B3C5 0x5687 # 0 +0x0000B3C6 0x5404 # 0 +0x0000B3C7 0x5ED3 # 0 +0x0000B3C8 0x62E1 # 0 +0x0000B3C9 0x64B9 # 0 +0x0000B3CA 0x683C # 0 +0x0000B3CB 0x6838 # 0 +0x0000B3CC 0x6BBB # 0 +0x0000B3CD 0x7372 # 0 +0x0000B3CE 0x78BA # 0 +0x0000B3CF 0x7A6B # 0 +0x0000B3D0 0x899A # 0 +0x0000B3D1 0x89D2 # 0 +0x0000B3D2 0x8D6B # 0 +0x0000B3D3 0x8F03 # 0 +0x0000B3D4 0x90ED # 0 +0x0000B3D5 0x95A3 # 0 +0x0000B3D6 0x9694 # 0 +0x0000B3D7 0x9769 # 0 +0x0000B3D8 0x5B66 # 0 +0x0000B3D9 0x5CB3 # 0 +0x0000B3DA 0x697D # 0 +0x0000B3DB 0x984D # 0 +0x0000B3DC 0x984E # 0 +0x0000B3DD 0x639B # 0 +0x0000B3DE 0x7B20 # 0 +0x0000B3DF 0x6A2B # 0 +0x0000B3E0 0x6A7F # 0 +0x0000B3E1 0x68B6 # 0 +0x0000B3E2 0x9C0D # 0 +0x0000B3E3 0x6F5F # 0 +0x0000B3E4 0x5272 # 0 +0x0000B3E5 0x559D # 0 +0x0000B3E6 0x6070 # 0 +0x0000B3E7 0x62EC # 0 +0x0000B3E8 0x6D3B # 0 +0x0000B3E9 0x6E07 # 0 +0x0000B3EA 0x6ED1 # 0 +0x0000B3EB 0x845B # 0 +0x0000B3EC 0x8910 # 0 +0x0000B3ED 0x8F44 # 0 +0x0000B3EE 0x4E14 # 0 +0x0000B3EF 0x9C39 # 0 +0x0000B3F0 0x53F6 # 0 +0x0000B3F1 0x691B # 0 +0x0000B3F2 0x6A3A # 0 +0x0000B3F3 0x9784 # 0 +0x0000B3F4 0x682A # 0 +0x0000B3F5 0x515C # 0 +0x0000B3F6 0x7AC3 # 0 +0x0000B3F7 0x84B2 # 0 +0x0000B3F8 0x91DC # 0 +0x0000B3F9 0x938C # 0 +0x0000B3FA 0x565B # 0 +0x0000B3FB 0x9D28 # 0 +0x0000B3FC 0x6822 # 0 +0x0000B3FD 0x8305 # 0 +0x0000B3FE 0x8431 # 0 +0x0000B4A1 0x7CA5 # 0 +0x0000B4A2 0x5208 # 0 +0x0000B4A3 0x82C5 # 0 +0x0000B4A4 0x74E6 # 0 +0x0000B4A5 0x4E7E # 0 +0x0000B4A6 0x4F83 # 0 +0x0000B4A7 0x51A0 # 0 +0x0000B4A8 0x5BD2 # 0 +0x0000B4A9 0x520A # 0 +0x0000B4AA 0x52D8 # 0 +0x0000B4AB 0x52E7 # 0 +0x0000B4AC 0x5DFB # 0 +0x0000B4AD 0x559A # 0 +0x0000B4AE 0x582A # 0 +0x0000B4AF 0x59E6 # 0 +0x0000B4B0 0x5B8C # 0 +0x0000B4B1 0x5B98 # 0 +0x0000B4B2 0x5BDB # 0 +0x0000B4B3 0x5E72 # 0 +0x0000B4B4 0x5E79 # 0 +0x0000B4B5 0x60A3 # 0 +0x0000B4B6 0x611F # 0 +0x0000B4B7 0x6163 # 0 +0x0000B4B8 0x61BE # 0 +0x0000B4B9 0x63DB # 0 +0x0000B4BA 0x6562 # 0 +0x0000B4BB 0x67D1 # 0 +0x0000B4BC 0x6853 # 0 +0x0000B4BD 0x68FA # 0 +0x0000B4BE 0x6B3E # 0 +0x0000B4BF 0x6B53 # 0 +0x0000B4C0 0x6C57 # 0 +0x0000B4C1 0x6F22 # 0 +0x0000B4C2 0x6F97 # 0 +0x0000B4C3 0x6F45 # 0 +0x0000B4C4 0x74B0 # 0 +0x0000B4C5 0x7518 # 0 +0x0000B4C6 0x76E3 # 0 +0x0000B4C7 0x770B # 0 +0x0000B4C8 0x7AFF # 0 +0x0000B4C9 0x7BA1 # 0 +0x0000B4CA 0x7C21 # 0 +0x0000B4CB 0x7DE9 # 0 +0x0000B4CC 0x7F36 # 0 +0x0000B4CD 0x7FF0 # 0 +0x0000B4CE 0x809D # 0 +0x0000B4CF 0x8266 # 0 +0x0000B4D0 0x839E # 0 +0x0000B4D1 0x89B3 # 0 +0x0000B4D2 0x8ACC # 0 +0x0000B4D3 0x8CAB # 0 +0x0000B4D4 0x9084 # 0 +0x0000B4D5 0x9451 # 0 +0x0000B4D6 0x9593 # 0 +0x0000B4D7 0x9591 # 0 +0x0000B4D8 0x95A2 # 0 +0x0000B4D9 0x9665 # 0 +0x0000B4DA 0x97D3 # 0 +0x0000B4DB 0x9928 # 0 +0x0000B4DC 0x8218 # 0 +0x0000B4DD 0x4E38 # 0 +0x0000B4DE 0x542B # 0 +0x0000B4DF 0x5CB8 # 0 +0x0000B4E0 0x5DCC # 0 +0x0000B4E1 0x73A9 # 0 +0x0000B4E2 0x764C # 0 +0x0000B4E3 0x773C # 0 +0x0000B4E4 0x5CA9 # 0 +0x0000B4E5 0x7FEB # 0 +0x0000B4E6 0x8D0B # 0 +0x0000B4E7 0x96C1 # 0 +0x0000B4E8 0x9811 # 0 +0x0000B4E9 0x9854 # 0 +0x0000B4EA 0x9858 # 0 +0x0000B4EB 0x4F01 # 0 +0x0000B4EC 0x4F0E # 0 +0x0000B4ED 0x5371 # 0 +0x0000B4EE 0x559C # 0 +0x0000B4EF 0x5668 # 0 +0x0000B4F0 0x57FA # 0 +0x0000B4F1 0x5947 # 0 +0x0000B4F2 0x5B09 # 0 +0x0000B4F3 0x5BC4 # 0 +0x0000B4F4 0x5C90 # 0 +0x0000B4F5 0x5E0C # 0 +0x0000B4F6 0x5E7E # 0 +0x0000B4F7 0x5FCC # 0 +0x0000B4F8 0x63EE # 0 +0x0000B4F9 0x673A # 0 +0x0000B4FA 0x65D7 # 0 +0x0000B4FB 0x65E2 # 0 +0x0000B4FC 0x671F # 0 +0x0000B4FD 0x68CB # 0 +0x0000B4FE 0x68C4 # 0 +0x0000B5A1 0x6A5F # 0 +0x0000B5A2 0x5E30 # 0 +0x0000B5A3 0x6BC5 # 0 +0x0000B5A4 0x6C17 # 0 +0x0000B5A5 0x6C7D # 0 +0x0000B5A6 0x757F # 0 +0x0000B5A7 0x7948 # 0 +0x0000B5A8 0x5B63 # 0 +0x0000B5A9 0x7A00 # 0 +0x0000B5AA 0x7D00 # 0 +0x0000B5AB 0x5FBD # 0 +0x0000B5AC 0x898F # 0 +0x0000B5AD 0x8A18 # 0 +0x0000B5AE 0x8CB4 # 0 +0x0000B5AF 0x8D77 # 0 +0x0000B5B0 0x8ECC # 0 +0x0000B5B1 0x8F1D # 0 +0x0000B5B2 0x98E2 # 0 +0x0000B5B3 0x9A0E # 0 +0x0000B5B4 0x9B3C # 0 +0x0000B5B5 0x4E80 # 0 +0x0000B5B6 0x507D # 0 +0x0000B5B7 0x5100 # 0 +0x0000B5B8 0x5993 # 0 +0x0000B5B9 0x5B9C # 0 +0x0000B5BA 0x622F # 0 +0x0000B5BB 0x6280 # 0 +0x0000B5BC 0x64EC # 0 +0x0000B5BD 0x6B3A # 0 +0x0000B5BE 0x72A0 # 0 +0x0000B5BF 0x7591 # 0 +0x0000B5C0 0x7947 # 0 +0x0000B5C1 0x7FA9 # 0 +0x0000B5C2 0x87FB # 0 +0x0000B5C3 0x8ABC # 0 +0x0000B5C4 0x8B70 # 0 +0x0000B5C5 0x63AC # 0 +0x0000B5C6 0x83CA # 0 +0x0000B5C7 0x97A0 # 0 +0x0000B5C8 0x5409 # 0 +0x0000B5C9 0x5403 # 0 +0x0000B5CA 0x55AB # 0 +0x0000B5CB 0x6854 # 0 +0x0000B5CC 0x6A58 # 0 +0x0000B5CD 0x8A70 # 0 +0x0000B5CE 0x7827 # 0 +0x0000B5CF 0x6775 # 0 +0x0000B5D0 0x9ECD # 0 +0x0000B5D1 0x5374 # 0 +0x0000B5D2 0x5BA2 # 0 +0x0000B5D3 0x811A # 0 +0x0000B5D4 0x8650 # 0 +0x0000B5D5 0x9006 # 0 +0x0000B5D6 0x4E18 # 0 +0x0000B5D7 0x4E45 # 0 +0x0000B5D8 0x4EC7 # 0 +0x0000B5D9 0x4F11 # 0 +0x0000B5DA 0x53CA # 0 +0x0000B5DB 0x5438 # 0 +0x0000B5DC 0x5BAE # 0 +0x0000B5DD 0x5F13 # 0 +0x0000B5DE 0x6025 # 0 +0x0000B5DF 0x6551 # 0 +0x0000B5E0 0x673D # 0 +0x0000B5E1 0x6C42 # 0 +0x0000B5E2 0x6C72 # 0 +0x0000B5E3 0x6CE3 # 0 +0x0000B5E4 0x7078 # 0 +0x0000B5E5 0x7403 # 0 +0x0000B5E6 0x7A76 # 0 +0x0000B5E7 0x7AAE # 0 +0x0000B5E8 0x7B08 # 0 +0x0000B5E9 0x7D1A # 0 +0x0000B5EA 0x7CFE # 0 +0x0000B5EB 0x7D66 # 0 +0x0000B5EC 0x65E7 # 0 +0x0000B5ED 0x725B # 0 +0x0000B5EE 0x53BB # 0 +0x0000B5EF 0x5C45 # 0 +0x0000B5F0 0x5DE8 # 0 +0x0000B5F1 0x62D2 # 0 +0x0000B5F2 0x62E0 # 0 +0x0000B5F3 0x6319 # 0 +0x0000B5F4 0x6E20 # 0 +0x0000B5F5 0x865A # 0 +0x0000B5F6 0x8A31 # 0 +0x0000B5F7 0x8DDD # 0 +0x0000B5F8 0x92F8 # 0 +0x0000B5F9 0x6F01 # 0 +0x0000B5FA 0x79A6 # 0 +0x0000B5FB 0x9B5A # 0 +0x0000B5FC 0x4EA8 # 0 +0x0000B5FD 0x4EAB # 0 +0x0000B5FE 0x4EAC # 0 +0x0000B6A1 0x4F9B # 0 +0x0000B6A2 0x4FA0 # 0 +0x0000B6A3 0x50D1 # 0 +0x0000B6A4 0x5147 # 0 +0x0000B6A5 0x7AF6 # 0 +0x0000B6A6 0x5171 # 0 +0x0000B6A7 0x51F6 # 0 +0x0000B6A8 0x5354 # 0 +0x0000B6A9 0x5321 # 0 +0x0000B6AA 0x537F # 0 +0x0000B6AB 0x53EB # 0 +0x0000B6AC 0x55AC # 0 +0x0000B6AD 0x5883 # 0 +0x0000B6AE 0x5CE1 # 0 +0x0000B6AF 0x5F37 # 0 +0x0000B6B0 0x5F4A # 0 +0x0000B6B1 0x602F # 0 +0x0000B6B2 0x6050 # 0 +0x0000B6B3 0x606D # 0 +0x0000B6B4 0x631F # 0 +0x0000B6B5 0x6559 # 0 +0x0000B6B6 0x6A4B # 0 +0x0000B6B7 0x6CC1 # 0 +0x0000B6B8 0x72C2 # 0 +0x0000B6B9 0x72ED # 0 +0x0000B6BA 0x77EF # 0 +0x0000B6BB 0x80F8 # 0 +0x0000B6BC 0x8105 # 0 +0x0000B6BD 0x8208 # 0 +0x0000B6BE 0x854E # 0 +0x0000B6BF 0x90F7 # 0 +0x0000B6C0 0x93E1 # 0 +0x0000B6C1 0x97FF # 0 +0x0000B6C2 0x9957 # 0 +0x0000B6C3 0x9A5A # 0 +0x0000B6C4 0x4EF0 # 0 +0x0000B6C5 0x51DD # 0 +0x0000B6C6 0x5C2D # 0 +0x0000B6C7 0x6681 # 0 +0x0000B6C8 0x696D # 0 +0x0000B6C9 0x5C40 # 0 +0x0000B6CA 0x66F2 # 0 +0x0000B6CB 0x6975 # 0 +0x0000B6CC 0x7389 # 0 +0x0000B6CD 0x6850 # 0 +0x0000B6CE 0x7C81 # 0 +0x0000B6CF 0x50C5 # 0 +0x0000B6D0 0x52E4 # 0 +0x0000B6D1 0x5747 # 0 +0x0000B6D2 0x5DFE # 0 +0x0000B6D3 0x9326 # 0 +0x0000B6D4 0x65A4 # 0 +0x0000B6D5 0x6B23 # 0 +0x0000B6D6 0x6B3D # 0 +0x0000B6D7 0x7434 # 0 +0x0000B6D8 0x7981 # 0 +0x0000B6D9 0x79BD # 0 +0x0000B6DA 0x7B4B # 0 +0x0000B6DB 0x7DCA # 0 +0x0000B6DC 0x82B9 # 0 +0x0000B6DD 0x83CC # 0 +0x0000B6DE 0x887F # 0 +0x0000B6DF 0x895F # 0 +0x0000B6E0 0x8B39 # 0 +0x0000B6E1 0x8FD1 # 0 +0x0000B6E2 0x91D1 # 0 +0x0000B6E3 0x541F # 0 +0x0000B6E4 0x9280 # 0 +0x0000B6E5 0x4E5D # 0 +0x0000B6E6 0x5036 # 0 +0x0000B6E7 0x53E5 # 0 +0x0000B6E8 0x533A # 0 +0x0000B6E9 0x72D7 # 0 +0x0000B6EA 0x7396 # 0 +0x0000B6EB 0x77E9 # 0 +0x0000B6EC 0x82E6 # 0 +0x0000B6ED 0x8EAF # 0 +0x0000B6EE 0x99C6 # 0 +0x0000B6EF 0x99C8 # 0 +0x0000B6F0 0x99D2 # 0 +0x0000B6F1 0x5177 # 0 +0x0000B6F2 0x611A # 0 +0x0000B6F3 0x865E # 0 +0x0000B6F4 0x55B0 # 0 +0x0000B6F5 0x7A7A # 0 +0x0000B6F6 0x5076 # 0 +0x0000B6F7 0x5BD3 # 0 +0x0000B6F8 0x9047 # 0 +0x0000B6F9 0x9685 # 0 +0x0000B6FA 0x4E32 # 0 +0x0000B6FB 0x6ADB # 0 +0x0000B6FC 0x91E7 # 0 +0x0000B6FD 0x5C51 # 0 +0x0000B6FE 0x5C48 # 0 +0x0000B7A1 0x6398 # 0 +0x0000B7A2 0x7A9F # 0 +0x0000B7A3 0x6C93 # 0 +0x0000B7A4 0x9774 # 0 +0x0000B7A5 0x8F61 # 0 +0x0000B7A6 0x7AAA # 0 +0x0000B7A7 0x718A # 0 +0x0000B7A8 0x9688 # 0 +0x0000B7A9 0x7C82 # 0 +0x0000B7AA 0x6817 # 0 +0x0000B7AB 0x7E70 # 0 +0x0000B7AC 0x6851 # 0 +0x0000B7AD 0x936C # 0 +0x0000B7AE 0x52F2 # 0 +0x0000B7AF 0x541B # 0 +0x0000B7B0 0x85AB # 0 +0x0000B7B1 0x8A13 # 0 +0x0000B7B2 0x7FA4 # 0 +0x0000B7B3 0x8ECD # 0 +0x0000B7B4 0x90E1 # 0 +0x0000B7B5 0x5366 # 0 +0x0000B7B6 0x8888 # 0 +0x0000B7B7 0x7941 # 0 +0x0000B7B8 0x4FC2 # 0 +0x0000B7B9 0x50BE # 0 +0x0000B7BA 0x5211 # 0 +0x0000B7BB 0x5144 # 0 +0x0000B7BC 0x5553 # 0 +0x0000B7BD 0x572D # 0 +0x0000B7BE 0x73EA # 0 +0x0000B7BF 0x578B # 0 +0x0000B7C0 0x5951 # 0 +0x0000B7C1 0x5F62 # 0 +0x0000B7C2 0x5F84 # 0 +0x0000B7C3 0x6075 # 0 +0x0000B7C4 0x6176 # 0 +0x0000B7C5 0x6167 # 0 +0x0000B7C6 0x61A9 # 0 +0x0000B7C7 0x63B2 # 0 +0x0000B7C8 0x643A # 0 +0x0000B7C9 0x656C # 0 +0x0000B7CA 0x666F # 0 +0x0000B7CB 0x6842 # 0 +0x0000B7CC 0x6E13 # 0 +0x0000B7CD 0x7566 # 0 +0x0000B7CE 0x7A3D # 0 +0x0000B7CF 0x7CFB # 0 +0x0000B7D0 0x7D4C # 0 +0x0000B7D1 0x7D99 # 0 +0x0000B7D2 0x7E4B # 0 +0x0000B7D3 0x7F6B # 0 +0x0000B7D4 0x830E # 0 +0x0000B7D5 0x834A # 0 +0x0000B7D6 0x86CD # 0 +0x0000B7D7 0x8A08 # 0 +0x0000B7D8 0x8A63 # 0 +0x0000B7D9 0x8B66 # 0 +0x0000B7DA 0x8EFD # 0 +0x0000B7DB 0x981A # 0 +0x0000B7DC 0x9D8F # 0 +0x0000B7DD 0x82B8 # 0 +0x0000B7DE 0x8FCE # 0 +0x0000B7DF 0x9BE8 # 0 +0x0000B7E0 0x5287 # 0 +0x0000B7E1 0x621F # 0 +0x0000B7E2 0x6483 # 0 +0x0000B7E3 0x6FC0 # 0 +0x0000B7E4 0x9699 # 0 +0x0000B7E5 0x6841 # 0 +0x0000B7E6 0x5091 # 0 +0x0000B7E7 0x6B20 # 0 +0x0000B7E8 0x6C7A # 0 +0x0000B7E9 0x6F54 # 0 +0x0000B7EA 0x7A74 # 0 +0x0000B7EB 0x7D50 # 0 +0x0000B7EC 0x8840 # 0 +0x0000B7ED 0x8A23 # 0 +0x0000B7EE 0x6708 # 0 +0x0000B7EF 0x4EF6 # 0 +0x0000B7F0 0x5039 # 0 +0x0000B7F1 0x5026 # 0 +0x0000B7F2 0x5065 # 0 +0x0000B7F3 0x517C # 0 +0x0000B7F4 0x5238 # 0 +0x0000B7F5 0x5263 # 0 +0x0000B7F6 0x55A7 # 0 +0x0000B7F7 0x570F # 0 +0x0000B7F8 0x5805 # 0 +0x0000B7F9 0x5ACC # 0 +0x0000B7FA 0x5EFA # 0 +0x0000B7FB 0x61B2 # 0 +0x0000B7FC 0x61F8 # 0 +0x0000B7FD 0x62F3 # 0 +0x0000B7FE 0x6372 # 0 +0x0000B8A1 0x691C # 0 +0x0000B8A2 0x6A29 # 0 +0x0000B8A3 0x727D # 0 +0x0000B8A4 0x72AC # 0 +0x0000B8A5 0x732E # 0 +0x0000B8A6 0x7814 # 0 +0x0000B8A7 0x786F # 0 +0x0000B8A8 0x7D79 # 0 +0x0000B8A9 0x770C # 0 +0x0000B8AA 0x80A9 # 0 +0x0000B8AB 0x898B # 0 +0x0000B8AC 0x8B19 # 0 +0x0000B8AD 0x8CE2 # 0 +0x0000B8AE 0x8ED2 # 0 +0x0000B8AF 0x9063 # 0 +0x0000B8B0 0x9375 # 0 +0x0000B8B1 0x967A # 0 +0x0000B8B2 0x9855 # 0 +0x0000B8B3 0x9A13 # 0 +0x0000B8B4 0x9E78 # 0 +0x0000B8B5 0x5143 # 0 +0x0000B8B6 0x539F # 0 +0x0000B8B7 0x53B3 # 0 +0x0000B8B8 0x5E7B # 0 +0x0000B8B9 0x5F26 # 0 +0x0000B8BA 0x6E1B # 0 +0x0000B8BB 0x6E90 # 0 +0x0000B8BC 0x7384 # 0 +0x0000B8BD 0x73FE # 0 +0x0000B8BE 0x7D43 # 0 +0x0000B8BF 0x8237 # 0 +0x0000B8C0 0x8A00 # 0 +0x0000B8C1 0x8AFA # 0 +0x0000B8C2 0x9650 # 0 +0x0000B8C3 0x4E4E # 0 +0x0000B8C4 0x500B # 0 +0x0000B8C5 0x53E4 # 0 +0x0000B8C6 0x547C # 0 +0x0000B8C7 0x56FA # 0 +0x0000B8C8 0x59D1 # 0 +0x0000B8C9 0x5B64 # 0 +0x0000B8CA 0x5DF1 # 0 +0x0000B8CB 0x5EAB # 0 +0x0000B8CC 0x5F27 # 0 +0x0000B8CD 0x6238 # 0 +0x0000B8CE 0x6545 # 0 +0x0000B8CF 0x67AF # 0 +0x0000B8D0 0x6E56 # 0 +0x0000B8D1 0x72D0 # 0 +0x0000B8D2 0x7CCA # 0 +0x0000B8D3 0x88B4 # 0 +0x0000B8D4 0x80A1 # 0 +0x0000B8D5 0x80E1 # 0 +0x0000B8D6 0x83F0 # 0 +0x0000B8D7 0x864E # 0 +0x0000B8D8 0x8A87 # 0 +0x0000B8D9 0x8DE8 # 0 +0x0000B8DA 0x9237 # 0 +0x0000B8DB 0x96C7 # 0 +0x0000B8DC 0x9867 # 0 +0x0000B8DD 0x9F13 # 0 +0x0000B8DE 0x4E94 # 0 +0x0000B8DF 0x4E92 # 0 +0x0000B8E0 0x4F0D # 0 +0x0000B8E1 0x5348 # 0 +0x0000B8E2 0x5449 # 0 +0x0000B8E3 0x543E # 0 +0x0000B8E4 0x5A2F # 0 +0x0000B8E5 0x5F8C # 0 +0x0000B8E6 0x5FA1 # 0 +0x0000B8E7 0x609F # 0 +0x0000B8E8 0x68A7 # 0 +0x0000B8E9 0x6A8E # 0 +0x0000B8EA 0x745A # 0 +0x0000B8EB 0x7881 # 0 +0x0000B8EC 0x8A9E # 0 +0x0000B8ED 0x8AA4 # 0 +0x0000B8EE 0x8B77 # 0 +0x0000B8EF 0x9190 # 0 +0x0000B8F0 0x4E5E # 0 +0x0000B8F1 0x9BC9 # 0 +0x0000B8F2 0x4EA4 # 0 +0x0000B8F3 0x4F7C # 0 +0x0000B8F4 0x4FAF # 0 +0x0000B8F5 0x5019 # 0 +0x0000B8F6 0x5016 # 0 +0x0000B8F7 0x5149 # 0 +0x0000B8F8 0x516C # 0 +0x0000B8F9 0x529F # 0 +0x0000B8FA 0x52B9 # 0 +0x0000B8FB 0x52FE # 0 +0x0000B8FC 0x539A # 0 +0x0000B8FD 0x53E3 # 0 +0x0000B8FE 0x5411 # 0 +0x0000B9A1 0x540E # 0 +0x0000B9A2 0x5589 # 0 +0x0000B9A3 0x5751 # 0 +0x0000B9A4 0x57A2 # 0 +0x0000B9A5 0x597D # 0 +0x0000B9A6 0x5B54 # 0 +0x0000B9A7 0x5B5D # 0 +0x0000B9A8 0x5B8F # 0 +0x0000B9A9 0x5DE5 # 0 +0x0000B9AA 0x5DE7 # 0 +0x0000B9AB 0x5DF7 # 0 +0x0000B9AC 0x5E78 # 0 +0x0000B9AD 0x5E83 # 0 +0x0000B9AE 0x5E9A # 0 +0x0000B9AF 0x5EB7 # 0 +0x0000B9B0 0x5F18 # 0 +0x0000B9B1 0x6052 # 0 +0x0000B9B2 0x614C # 0 +0x0000B9B3 0x6297 # 0 +0x0000B9B4 0x62D8 # 0 +0x0000B9B5 0x63A7 # 0 +0x0000B9B6 0x653B # 0 +0x0000B9B7 0x6602 # 0 +0x0000B9B8 0x6643 # 0 +0x0000B9B9 0x66F4 # 0 +0x0000B9BA 0x676D # 0 +0x0000B9BB 0x6821 # 0 +0x0000B9BC 0x6897 # 0 +0x0000B9BD 0x69CB # 0 +0x0000B9BE 0x6C5F # 0 +0x0000B9BF 0x6D2A # 0 +0x0000B9C0 0x6D69 # 0 +0x0000B9C1 0x6E2F # 0 +0x0000B9C2 0x6E9D # 0 +0x0000B9C3 0x7532 # 0 +0x0000B9C4 0x7687 # 0 +0x0000B9C5 0x786C # 0 +0x0000B9C6 0x7A3F # 0 +0x0000B9C7 0x7CE0 # 0 +0x0000B9C8 0x7D05 # 0 +0x0000B9C9 0x7D18 # 0 +0x0000B9CA 0x7D5E # 0 +0x0000B9CB 0x7DB1 # 0 +0x0000B9CC 0x8015 # 0 +0x0000B9CD 0x8003 # 0 +0x0000B9CE 0x80AF # 0 +0x0000B9CF 0x80B1 # 0 +0x0000B9D0 0x8154 # 0 +0x0000B9D1 0x818F # 0 +0x0000B9D2 0x822A # 0 +0x0000B9D3 0x8352 # 0 +0x0000B9D4 0x884C # 0 +0x0000B9D5 0x8861 # 0 +0x0000B9D6 0x8B1B # 0 +0x0000B9D7 0x8CA2 # 0 +0x0000B9D8 0x8CFC # 0 +0x0000B9D9 0x90CA # 0 +0x0000B9DA 0x9175 # 0 +0x0000B9DB 0x9271 # 0 +0x0000B9DC 0x783F # 0 +0x0000B9DD 0x92FC # 0 +0x0000B9DE 0x95A4 # 0 +0x0000B9DF 0x964D # 0 +0x0000B9E0 0x9805 # 0 +0x0000B9E1 0x9999 # 0 +0x0000B9E2 0x9AD8 # 0 +0x0000B9E3 0x9D3B # 0 +0x0000B9E4 0x525B # 0 +0x0000B9E5 0x52AB # 0 +0x0000B9E6 0x53F7 # 0 +0x0000B9E7 0x5408 # 0 +0x0000B9E8 0x58D5 # 0 +0x0000B9E9 0x62F7 # 0 +0x0000B9EA 0x6FE0 # 0 +0x0000B9EB 0x8C6A # 0 +0x0000B9EC 0x8F5F # 0 +0x0000B9ED 0x9EB9 # 0 +0x0000B9EE 0x514B # 0 +0x0000B9EF 0x523B # 0 +0x0000B9F0 0x544A # 0 +0x0000B9F1 0x56FD # 0 +0x0000B9F2 0x7A40 # 0 +0x0000B9F3 0x9177 # 0 +0x0000B9F4 0x9D60 # 0 +0x0000B9F5 0x9ED2 # 0 +0x0000B9F6 0x7344 # 0 +0x0000B9F7 0x6F09 # 0 +0x0000B9F8 0x8170 # 0 +0x0000B9F9 0x7511 # 0 +0x0000B9FA 0x5FFD # 0 +0x0000B9FB 0x60DA # 0 +0x0000B9FC 0x9AA8 # 0 +0x0000B9FD 0x72DB # 0 +0x0000B9FE 0x8FBC # 0 +0x0000BAA1 0x6B64 # 0 +0x0000BAA2 0x9803 # 0 +0x0000BAA3 0x4ECA # 0 +0x0000BAA4 0x56F0 # 0 +0x0000BAA5 0x5764 # 0 +0x0000BAA6 0x58BE # 0 +0x0000BAA7 0x5A5A # 0 +0x0000BAA8 0x6068 # 0 +0x0000BAA9 0x61C7 # 0 +0x0000BAAA 0x660F # 0 +0x0000BAAB 0x6606 # 0 +0x0000BAAC 0x6839 # 0 +0x0000BAAD 0x68B1 # 0 +0x0000BAAE 0x6DF7 # 0 +0x0000BAAF 0x75D5 # 0 +0x0000BAB0 0x7D3A # 0 +0x0000BAB1 0x826E # 0 +0x0000BAB2 0x9B42 # 0 +0x0000BAB3 0x4E9B # 0 +0x0000BAB4 0x4F50 # 0 +0x0000BAB5 0x53C9 # 0 +0x0000BAB6 0x5506 # 0 +0x0000BAB7 0x5D6F # 0 +0x0000BAB8 0x5DE6 # 0 +0x0000BAB9 0x5DEE # 0 +0x0000BABA 0x67FB # 0 +0x0000BABB 0x6C99 # 0 +0x0000BABC 0x7473 # 0 +0x0000BABD 0x7802 # 0 +0x0000BABE 0x8A50 # 0 +0x0000BABF 0x9396 # 0 +0x0000BAC0 0x88DF # 0 +0x0000BAC1 0x5750 # 0 +0x0000BAC2 0x5EA7 # 0 +0x0000BAC3 0x632B # 0 +0x0000BAC4 0x50B5 # 0 +0x0000BAC5 0x50AC # 0 +0x0000BAC6 0x518D # 0 +0x0000BAC7 0x6700 # 0 +0x0000BAC8 0x54C9 # 0 +0x0000BAC9 0x585E # 0 +0x0000BACA 0x59BB # 0 +0x0000BACB 0x5BB0 # 0 +0x0000BACC 0x5F69 # 0 +0x0000BACD 0x624D # 0 +0x0000BACE 0x63A1 # 0 +0x0000BACF 0x683D # 0 +0x0000BAD0 0x6B73 # 0 +0x0000BAD1 0x6E08 # 0 +0x0000BAD2 0x707D # 0 +0x0000BAD3 0x91C7 # 0 +0x0000BAD4 0x7280 # 0 +0x0000BAD5 0x7815 # 0 +0x0000BAD6 0x7826 # 0 +0x0000BAD7 0x796D # 0 +0x0000BAD8 0x658E # 0 +0x0000BAD9 0x7D30 # 0 +0x0000BADA 0x83DC # 0 +0x0000BADB 0x88C1 # 0 +0x0000BADC 0x8F09 # 0 +0x0000BADD 0x969B # 0 +0x0000BADE 0x5264 # 0 +0x0000BADF 0x5728 # 0 +0x0000BAE0 0x6750 # 0 +0x0000BAE1 0x7F6A # 0 +0x0000BAE2 0x8CA1 # 0 +0x0000BAE3 0x51B4 # 0 +0x0000BAE4 0x5742 # 0 +0x0000BAE5 0x962A # 0 +0x0000BAE6 0x583A # 0 +0x0000BAE7 0x698A # 0 +0x0000BAE8 0x80B4 # 0 +0x0000BAE9 0x54B2 # 0 +0x0000BAEA 0x5D0E # 0 +0x0000BAEB 0x57FC # 0 +0x0000BAEC 0x7895 # 0 +0x0000BAED 0x9DFA # 0 +0x0000BAEE 0x4F5C # 0 +0x0000BAEF 0x524A # 0 +0x0000BAF0 0x548B # 0 +0x0000BAF1 0x643E # 0 +0x0000BAF2 0x6628 # 0 +0x0000BAF3 0x6714 # 0 +0x0000BAF4 0x67F5 # 0 +0x0000BAF5 0x7A84 # 0 +0x0000BAF6 0x7B56 # 0 +0x0000BAF7 0x7D22 # 0 +0x0000BAF8 0x932F # 0 +0x0000BAF9 0x685C # 0 +0x0000BAFA 0x9BAD # 0 +0x0000BAFB 0x7B39 # 0 +0x0000BAFC 0x5319 # 0 +0x0000BAFD 0x518A # 0 +0x0000BAFE 0x5237 # 0 +0x0000BBA1 0x5BDF # 0 +0x0000BBA2 0x62F6 # 0 +0x0000BBA3 0x64AE # 0 +0x0000BBA4 0x64E6 # 0 +0x0000BBA5 0x672D # 0 +0x0000BBA6 0x6BBA # 0 +0x0000BBA7 0x85A9 # 0 +0x0000BBA8 0x96D1 # 0 +0x0000BBA9 0x7690 # 0 +0x0000BBAA 0x9BD6 # 0 +0x0000BBAB 0x634C # 0 +0x0000BBAC 0x9306 # 0 +0x0000BBAD 0x9BAB # 0 +0x0000BBAE 0x76BF # 0 +0x0000BBAF 0x6652 # 0 +0x0000BBB0 0x4E09 # 0 +0x0000BBB1 0x5098 # 0 +0x0000BBB2 0x53C2 # 0 +0x0000BBB3 0x5C71 # 0 +0x0000BBB4 0x60E8 # 0 +0x0000BBB5 0x6492 # 0 +0x0000BBB6 0x6563 # 0 +0x0000BBB7 0x685F # 0 +0x0000BBB8 0x71E6 # 0 +0x0000BBB9 0x73CA # 0 +0x0000BBBA 0x7523 # 0 +0x0000BBBB 0x7B97 # 0 +0x0000BBBC 0x7E82 # 0 +0x0000BBBD 0x8695 # 0 +0x0000BBBE 0x8B83 # 0 +0x0000BBBF 0x8CDB # 0 +0x0000BBC0 0x9178 # 0 +0x0000BBC1 0x9910 # 0 +0x0000BBC2 0x65AC # 0 +0x0000BBC3 0x66AB # 0 +0x0000BBC4 0x6B8B # 0 +0x0000BBC5 0x4ED5 # 0 +0x0000BBC6 0x4ED4 # 0 +0x0000BBC7 0x4F3A # 0 +0x0000BBC8 0x4F7F # 0 +0x0000BBC9 0x523A # 0 +0x0000BBCA 0x53F8 # 0 +0x0000BBCB 0x53F2 # 0 +0x0000BBCC 0x55E3 # 0 +0x0000BBCD 0x56DB # 0 +0x0000BBCE 0x58EB # 0 +0x0000BBCF 0x59CB # 0 +0x0000BBD0 0x59C9 # 0 +0x0000BBD1 0x59FF # 0 +0x0000BBD2 0x5B50 # 0 +0x0000BBD3 0x5C4D # 0 +0x0000BBD4 0x5E02 # 0 +0x0000BBD5 0x5E2B # 0 +0x0000BBD6 0x5FD7 # 0 +0x0000BBD7 0x601D # 0 +0x0000BBD8 0x6307 # 0 +0x0000BBD9 0x652F # 0 +0x0000BBDA 0x5B5C # 0 +0x0000BBDB 0x65AF # 0 +0x0000BBDC 0x65BD # 0 +0x0000BBDD 0x65E8 # 0 +0x0000BBDE 0x679D # 0 +0x0000BBDF 0x6B62 # 0 +0x0000BBE0 0x6B7B # 0 +0x0000BBE1 0x6C0F # 0 +0x0000BBE2 0x7345 # 0 +0x0000BBE3 0x7949 # 0 +0x0000BBE4 0x79C1 # 0 +0x0000BBE5 0x7CF8 # 0 +0x0000BBE6 0x7D19 # 0 +0x0000BBE7 0x7D2B # 0 +0x0000BBE8 0x80A2 # 0 +0x0000BBE9 0x8102 # 0 +0x0000BBEA 0x81F3 # 0 +0x0000BBEB 0x8996 # 0 +0x0000BBEC 0x8A5E # 0 +0x0000BBED 0x8A69 # 0 +0x0000BBEE 0x8A66 # 0 +0x0000BBEF 0x8A8C # 0 +0x0000BBF0 0x8AEE # 0 +0x0000BBF1 0x8CC7 # 0 +0x0000BBF2 0x8CDC # 0 +0x0000BBF3 0x96CC # 0 +0x0000BBF4 0x98FC # 0 +0x0000BBF5 0x6B6F # 0 +0x0000BBF6 0x4E8B # 0 +0x0000BBF7 0x4F3C # 0 +0x0000BBF8 0x4F8D # 0 +0x0000BBF9 0x5150 # 0 +0x0000BBFA 0x5B57 # 0 +0x0000BBFB 0x5BFA # 0 +0x0000BBFC 0x6148 # 0 +0x0000BBFD 0x6301 # 0 +0x0000BBFE 0x6642 # 0 +0x0000BCA1 0x6B21 # 0 +0x0000BCA2 0x6ECB # 0 +0x0000BCA3 0x6CBB # 0 +0x0000BCA4 0x723E # 0 +0x0000BCA5 0x74BD # 0 +0x0000BCA6 0x75D4 # 0 +0x0000BCA7 0x78C1 # 0 +0x0000BCA8 0x793A # 0 +0x0000BCA9 0x800C # 0 +0x0000BCAA 0x8033 # 0 +0x0000BCAB 0x81EA # 0 +0x0000BCAC 0x8494 # 0 +0x0000BCAD 0x8F9E # 0 +0x0000BCAE 0x6C50 # 0 +0x0000BCAF 0x9E7F # 0 +0x0000BCB0 0x5F0F # 0 +0x0000BCB1 0x8B58 # 0 +0x0000BCB2 0x9D2B # 0 +0x0000BCB3 0x7AFA # 0 +0x0000BCB4 0x8EF8 # 0 +0x0000BCB5 0x5B8D # 0 +0x0000BCB6 0x96EB # 0 +0x0000BCB7 0x4E03 # 0 +0x0000BCB8 0x53F1 # 0 +0x0000BCB9 0x57F7 # 0 +0x0000BCBA 0x5931 # 0 +0x0000BCBB 0x5AC9 # 0 +0x0000BCBC 0x5BA4 # 0 +0x0000BCBD 0x6089 # 0 +0x0000BCBE 0x6E7F # 0 +0x0000BCBF 0x6F06 # 0 +0x0000BCC0 0x75BE # 0 +0x0000BCC1 0x8CEA # 0 +0x0000BCC2 0x5B9F # 0 +0x0000BCC3 0x8500 # 0 +0x0000BCC4 0x7BE0 # 0 +0x0000BCC5 0x5072 # 0 +0x0000BCC6 0x67F4 # 0 +0x0000BCC7 0x829D # 0 +0x0000BCC8 0x5C61 # 0 +0x0000BCC9 0x854A # 0 +0x0000BCCA 0x7E1E # 0 +0x0000BCCB 0x820E # 0 +0x0000BCCC 0x5199 # 0 +0x0000BCCD 0x5C04 # 0 +0x0000BCCE 0x6368 # 0 +0x0000BCCF 0x8D66 # 0 +0x0000BCD0 0x659C # 0 +0x0000BCD1 0x716E # 0 +0x0000BCD2 0x793E # 0 +0x0000BCD3 0x7D17 # 0 +0x0000BCD4 0x8005 # 0 +0x0000BCD5 0x8B1D # 0 +0x0000BCD6 0x8ECA # 0 +0x0000BCD7 0x906E # 0 +0x0000BCD8 0x86C7 # 0 +0x0000BCD9 0x90AA # 0 +0x0000BCDA 0x501F # 0 +0x0000BCDB 0x52FA # 0 +0x0000BCDC 0x5C3A # 0 +0x0000BCDD 0x6753 # 0 +0x0000BCDE 0x707C # 0 +0x0000BCDF 0x7235 # 0 +0x0000BCE0 0x914C # 0 +0x0000BCE1 0x91C8 # 0 +0x0000BCE2 0x932B # 0 +0x0000BCE3 0x82E5 # 0 +0x0000BCE4 0x5BC2 # 0 +0x0000BCE5 0x5F31 # 0 +0x0000BCE6 0x60F9 # 0 +0x0000BCE7 0x4E3B # 0 +0x0000BCE8 0x53D6 # 0 +0x0000BCE9 0x5B88 # 0 +0x0000BCEA 0x624B # 0 +0x0000BCEB 0x6731 # 0 +0x0000BCEC 0x6B8A # 0 +0x0000BCED 0x72E9 # 0 +0x0000BCEE 0x73E0 # 0 +0x0000BCEF 0x7A2E # 0 +0x0000BCF0 0x816B # 0 +0x0000BCF1 0x8DA3 # 0 +0x0000BCF2 0x9152 # 0 +0x0000BCF3 0x9996 # 0 +0x0000BCF4 0x5112 # 0 +0x0000BCF5 0x53D7 # 0 +0x0000BCF6 0x546A # 0 +0x0000BCF7 0x5BFF # 0 +0x0000BCF8 0x6388 # 0 +0x0000BCF9 0x6A39 # 0 +0x0000BCFA 0x7DAC # 0 +0x0000BCFB 0x9700 # 0 +0x0000BCFC 0x56DA # 0 +0x0000BCFD 0x53CE # 0 +0x0000BCFE 0x5468 # 0 +0x0000BDA1 0x5B97 # 0 +0x0000BDA2 0x5C31 # 0 +0x0000BDA3 0x5DDE # 0 +0x0000BDA4 0x4FEE # 0 +0x0000BDA5 0x6101 # 0 +0x0000BDA6 0x62FE # 0 +0x0000BDA7 0x6D32 # 0 +0x0000BDA8 0x79C0 # 0 +0x0000BDA9 0x79CB # 0 +0x0000BDAA 0x7D42 # 0 +0x0000BDAB 0x7E4D # 0 +0x0000BDAC 0x7FD2 # 0 +0x0000BDAD 0x81ED # 0 +0x0000BDAE 0x821F # 0 +0x0000BDAF 0x8490 # 0 +0x0000BDB0 0x8846 # 0 +0x0000BDB1 0x8972 # 0 +0x0000BDB2 0x8B90 # 0 +0x0000BDB3 0x8E74 # 0 +0x0000BDB4 0x8F2F # 0 +0x0000BDB5 0x9031 # 0 +0x0000BDB6 0x914B # 0 +0x0000BDB7 0x916C # 0 +0x0000BDB8 0x96C6 # 0 +0x0000BDB9 0x919C # 0 +0x0000BDBA 0x4EC0 # 0 +0x0000BDBB 0x4F4F # 0 +0x0000BDBC 0x5145 # 0 +0x0000BDBD 0x5341 # 0 +0x0000BDBE 0x5F93 # 0 +0x0000BDBF 0x620E # 0 +0x0000BDC0 0x67D4 # 0 +0x0000BDC1 0x6C41 # 0 +0x0000BDC2 0x6E0B # 0 +0x0000BDC3 0x7363 # 0 +0x0000BDC4 0x7E26 # 0 +0x0000BDC5 0x91CD # 0 +0x0000BDC6 0x9283 # 0 +0x0000BDC7 0x53D4 # 0 +0x0000BDC8 0x5919 # 0 +0x0000BDC9 0x5BBF # 0 +0x0000BDCA 0x6DD1 # 0 +0x0000BDCB 0x795D # 0 +0x0000BDCC 0x7E2E # 0 +0x0000BDCD 0x7C9B # 0 +0x0000BDCE 0x587E # 0 +0x0000BDCF 0x719F # 0 +0x0000BDD0 0x51FA # 0 +0x0000BDD1 0x8853 # 0 +0x0000BDD2 0x8FF0 # 0 +0x0000BDD3 0x4FCA # 0 +0x0000BDD4 0x5CFB # 0 +0x0000BDD5 0x6625 # 0 +0x0000BDD6 0x77AC # 0 +0x0000BDD7 0x7AE3 # 0 +0x0000BDD8 0x821C # 0 +0x0000BDD9 0x99FF # 0 +0x0000BDDA 0x51C6 # 0 +0x0000BDDB 0x5FAA # 0 +0x0000BDDC 0x65EC # 0 +0x0000BDDD 0x696F # 0 +0x0000BDDE 0x6B89 # 0 +0x0000BDDF 0x6DF3 # 0 +0x0000BDE0 0x6E96 # 0 +0x0000BDE1 0x6F64 # 0 +0x0000BDE2 0x76FE # 0 +0x0000BDE3 0x7D14 # 0 +0x0000BDE4 0x5DE1 # 0 +0x0000BDE5 0x9075 # 0 +0x0000BDE6 0x9187 # 0 +0x0000BDE7 0x9806 # 0 +0x0000BDE8 0x51E6 # 0 +0x0000BDE9 0x521D # 0 +0x0000BDEA 0x6240 # 0 +0x0000BDEB 0x6691 # 0 +0x0000BDEC 0x66D9 # 0 +0x0000BDED 0x6E1A # 0 +0x0000BDEE 0x5EB6 # 0 +0x0000BDEF 0x7DD2 # 0 +0x0000BDF0 0x7F72 # 0 +0x0000BDF1 0x66F8 # 0 +0x0000BDF2 0x85AF # 0 +0x0000BDF3 0x85F7 # 0 +0x0000BDF4 0x8AF8 # 0 +0x0000BDF5 0x52A9 # 0 +0x0000BDF6 0x53D9 # 0 +0x0000BDF7 0x5973 # 0 +0x0000BDF8 0x5E8F # 0 +0x0000BDF9 0x5F90 # 0 +0x0000BDFA 0x6055 # 0 +0x0000BDFB 0x92E4 # 0 +0x0000BDFC 0x9664 # 0 +0x0000BDFD 0x50B7 # 0 +0x0000BDFE 0x511F # 0 +0x0000BEA1 0x52DD # 0 +0x0000BEA2 0x5320 # 0 +0x0000BEA3 0x5347 # 0 +0x0000BEA4 0x53EC # 0 +0x0000BEA5 0x54E8 # 0 +0x0000BEA6 0x5546 # 0 +0x0000BEA7 0x5531 # 0 +0x0000BEA8 0x5617 # 0 +0x0000BEA9 0x5968 # 0 +0x0000BEAA 0x59BE # 0 +0x0000BEAB 0x5A3C # 0 +0x0000BEAC 0x5BB5 # 0 +0x0000BEAD 0x5C06 # 0 +0x0000BEAE 0x5C0F # 0 +0x0000BEAF 0x5C11 # 0 +0x0000BEB0 0x5C1A # 0 +0x0000BEB1 0x5E84 # 0 +0x0000BEB2 0x5E8A # 0 +0x0000BEB3 0x5EE0 # 0 +0x0000BEB4 0x5F70 # 0 +0x0000BEB5 0x627F # 0 +0x0000BEB6 0x6284 # 0 +0x0000BEB7 0x62DB # 0 +0x0000BEB8 0x638C # 0 +0x0000BEB9 0x6377 # 0 +0x0000BEBA 0x6607 # 0 +0x0000BEBB 0x660C # 0 +0x0000BEBC 0x662D # 0 +0x0000BEBD 0x6676 # 0 +0x0000BEBE 0x677E # 0 +0x0000BEBF 0x68A2 # 0 +0x0000BEC0 0x6A1F # 0 +0x0000BEC1 0x6A35 # 0 +0x0000BEC2 0x6CBC # 0 +0x0000BEC3 0x6D88 # 0 +0x0000BEC4 0x6E09 # 0 +0x0000BEC5 0x6E58 # 0 +0x0000BEC6 0x713C # 0 +0x0000BEC7 0x7126 # 0 +0x0000BEC8 0x7167 # 0 +0x0000BEC9 0x75C7 # 0 +0x0000BECA 0x7701 # 0 +0x0000BECB 0x785D # 0 +0x0000BECC 0x7901 # 0 +0x0000BECD 0x7965 # 0 +0x0000BECE 0x79F0 # 0 +0x0000BECF 0x7AE0 # 0 +0x0000BED0 0x7B11 # 0 +0x0000BED1 0x7CA7 # 0 +0x0000BED2 0x7D39 # 0 +0x0000BED3 0x8096 # 0 +0x0000BED4 0x83D6 # 0 +0x0000BED5 0x848B # 0 +0x0000BED6 0x8549 # 0 +0x0000BED7 0x885D # 0 +0x0000BED8 0x88F3 # 0 +0x0000BED9 0x8A1F # 0 +0x0000BEDA 0x8A3C # 0 +0x0000BEDB 0x8A54 # 0 +0x0000BEDC 0x8A73 # 0 +0x0000BEDD 0x8C61 # 0 +0x0000BEDE 0x8CDE # 0 +0x0000BEDF 0x91A4 # 0 +0x0000BEE0 0x9266 # 0 +0x0000BEE1 0x937E # 0 +0x0000BEE2 0x9418 # 0 +0x0000BEE3 0x969C # 0 +0x0000BEE4 0x9798 # 0 +0x0000BEE5 0x4E0A # 0 +0x0000BEE6 0x4E08 # 0 +0x0000BEE7 0x4E1E # 0 +0x0000BEE8 0x4E57 # 0 +0x0000BEE9 0x5197 # 0 +0x0000BEEA 0x5270 # 0 +0x0000BEEB 0x57CE # 0 +0x0000BEEC 0x5834 # 0 +0x0000BEED 0x58CC # 0 +0x0000BEEE 0x5B22 # 0 +0x0000BEEF 0x5E38 # 0 +0x0000BEF0 0x60C5 # 0 +0x0000BEF1 0x64FE # 0 +0x0000BEF2 0x6761 # 0 +0x0000BEF3 0x6756 # 0 +0x0000BEF4 0x6D44 # 0 +0x0000BEF5 0x72B6 # 0 +0x0000BEF6 0x7573 # 0 +0x0000BEF7 0x7A63 # 0 +0x0000BEF8 0x84B8 # 0 +0x0000BEF9 0x8B72 # 0 +0x0000BEFA 0x91B8 # 0 +0x0000BEFB 0x9320 # 0 +0x0000BEFC 0x5631 # 0 +0x0000BEFD 0x57F4 # 0 +0x0000BEFE 0x98FE # 0 +0x0000BFA1 0x62ED # 0 +0x0000BFA2 0x690D # 0 +0x0000BFA3 0x6B96 # 0 +0x0000BFA4 0x71ED # 0 +0x0000BFA5 0x7E54 # 0 +0x0000BFA6 0x8077 # 0 +0x0000BFA7 0x8272 # 0 +0x0000BFA8 0x89E6 # 0 +0x0000BFA9 0x98DF # 0 +0x0000BFAA 0x8755 # 0 +0x0000BFAB 0x8FB1 # 0 +0x0000BFAC 0x5C3B # 0 +0x0000BFAD 0x4F38 # 0 +0x0000BFAE 0x4FE1 # 0 +0x0000BFAF 0x4FB5 # 0 +0x0000BFB0 0x5507 # 0 +0x0000BFB1 0x5A20 # 0 +0x0000BFB2 0x5BDD # 0 +0x0000BFB3 0x5BE9 # 0 +0x0000BFB4 0x5FC3 # 0 +0x0000BFB5 0x614E # 0 +0x0000BFB6 0x632F # 0 +0x0000BFB7 0x65B0 # 0 +0x0000BFB8 0x664B # 0 +0x0000BFB9 0x68EE # 0 +0x0000BFBA 0x699B # 0 +0x0000BFBB 0x6D78 # 0 +0x0000BFBC 0x6DF1 # 0 +0x0000BFBD 0x7533 # 0 +0x0000BFBE 0x75B9 # 0 +0x0000BFBF 0x771F # 0 +0x0000BFC0 0x795E # 0 +0x0000BFC1 0x79E6 # 0 +0x0000BFC2 0x7D33 # 0 +0x0000BFC3 0x81E3 # 0 +0x0000BFC4 0x82AF # 0 +0x0000BFC5 0x85AA # 0 +0x0000BFC6 0x89AA # 0 +0x0000BFC7 0x8A3A # 0 +0x0000BFC8 0x8EAB # 0 +0x0000BFC9 0x8F9B # 0 +0x0000BFCA 0x9032 # 0 +0x0000BFCB 0x91DD # 0 +0x0000BFCC 0x9707 # 0 +0x0000BFCD 0x4EBA # 0 +0x0000BFCE 0x4EC1 # 0 +0x0000BFCF 0x5203 # 0 +0x0000BFD0 0x5875 # 0 +0x0000BFD1 0x58EC # 0 +0x0000BFD2 0x5C0B # 0 +0x0000BFD3 0x751A # 0 +0x0000BFD4 0x5C3D # 0 +0x0000BFD5 0x814E # 0 +0x0000BFD6 0x8A0A # 0 +0x0000BFD7 0x8FC5 # 0 +0x0000BFD8 0x9663 # 0 +0x0000BFD9 0x976D # 0 +0x0000BFDA 0x7B25 # 0 +0x0000BFDB 0x8ACF # 0 +0x0000BFDC 0x9808 # 0 +0x0000BFDD 0x9162 # 0 +0x0000BFDE 0x56F3 # 0 +0x0000BFDF 0x53A8 # 0 +0x0000BFE0 0x9017 # 0 +0x0000BFE1 0x5439 # 0 +0x0000BFE2 0x5782 # 0 +0x0000BFE3 0x5E25 # 0 +0x0000BFE4 0x63A8 # 0 +0x0000BFE5 0x6C34 # 0 +0x0000BFE6 0x708A # 0 +0x0000BFE7 0x7761 # 0 +0x0000BFE8 0x7C8B # 0 +0x0000BFE9 0x7FE0 # 0 +0x0000BFEA 0x8870 # 0 +0x0000BFEB 0x9042 # 0 +0x0000BFEC 0x9154 # 0 +0x0000BFED 0x9310 # 0 +0x0000BFEE 0x9318 # 0 +0x0000BFEF 0x968F # 0 +0x0000BFF0 0x745E # 0 +0x0000BFF1 0x9AC4 # 0 +0x0000BFF2 0x5D07 # 0 +0x0000BFF3 0x5D69 # 0 +0x0000BFF4 0x6570 # 0 +0x0000BFF5 0x67A2 # 0 +0x0000BFF6 0x8DA8 # 0 +0x0000BFF7 0x96DB # 0 +0x0000BFF8 0x636E # 0 +0x0000BFF9 0x6749 # 0 +0x0000BFFA 0x6919 # 0 +0x0000BFFB 0x83C5 # 0 +0x0000BFFC 0x9817 # 0 +0x0000BFFD 0x96C0 # 0 +0x0000BFFE 0x88FE # 0 +0x0000C0A1 0x6F84 # 0 +0x0000C0A2 0x647A # 0 +0x0000C0A3 0x5BF8 # 0 +0x0000C0A4 0x4E16 # 0 +0x0000C0A5 0x702C # 0 +0x0000C0A6 0x755D # 0 +0x0000C0A7 0x662F # 0 +0x0000C0A8 0x51C4 # 0 +0x0000C0A9 0x5236 # 0 +0x0000C0AA 0x52E2 # 0 +0x0000C0AB 0x59D3 # 0 +0x0000C0AC 0x5F81 # 0 +0x0000C0AD 0x6027 # 0 +0x0000C0AE 0x6210 # 0 +0x0000C0AF 0x653F # 0 +0x0000C0B0 0x6574 # 0 +0x0000C0B1 0x661F # 0 +0x0000C0B2 0x6674 # 0 +0x0000C0B3 0x68F2 # 0 +0x0000C0B4 0x6816 # 0 +0x0000C0B5 0x6B63 # 0 +0x0000C0B6 0x6E05 # 0 +0x0000C0B7 0x7272 # 0 +0x0000C0B8 0x751F # 0 +0x0000C0B9 0x76DB # 0 +0x0000C0BA 0x7CBE # 0 +0x0000C0BB 0x8056 # 0 +0x0000C0BC 0x58F0 # 0 +0x0000C0BD 0x88FD # 0 +0x0000C0BE 0x897F # 0 +0x0000C0BF 0x8AA0 # 0 +0x0000C0C0 0x8A93 # 0 +0x0000C0C1 0x8ACB # 0 +0x0000C0C2 0x901D # 0 +0x0000C0C3 0x9192 # 0 +0x0000C0C4 0x9752 # 0 +0x0000C0C5 0x9759 # 0 +0x0000C0C6 0x6589 # 0 +0x0000C0C7 0x7A0E # 0 +0x0000C0C8 0x8106 # 0 +0x0000C0C9 0x96BB # 0 +0x0000C0CA 0x5E2D # 0 +0x0000C0CB 0x60DC # 0 +0x0000C0CC 0x621A # 0 +0x0000C0CD 0x65A5 # 0 +0x0000C0CE 0x6614 # 0 +0x0000C0CF 0x6790 # 0 +0x0000C0D0 0x77F3 # 0 +0x0000C0D1 0x7A4D # 0 +0x0000C0D2 0x7C4D # 0 +0x0000C0D3 0x7E3E # 0 +0x0000C0D4 0x810A # 0 +0x0000C0D5 0x8CAC # 0 +0x0000C0D6 0x8D64 # 0 +0x0000C0D7 0x8DE1 # 0 +0x0000C0D8 0x8E5F # 0 +0x0000C0D9 0x78A9 # 0 +0x0000C0DA 0x5207 # 0 +0x0000C0DB 0x62D9 # 0 +0x0000C0DC 0x63A5 # 0 +0x0000C0DD 0x6442 # 0 +0x0000C0DE 0x6298 # 0 +0x0000C0DF 0x8A2D # 0 +0x0000C0E0 0x7A83 # 0 +0x0000C0E1 0x7BC0 # 0 +0x0000C0E2 0x8AAC # 0 +0x0000C0E3 0x96EA # 0 +0x0000C0E4 0x7D76 # 0 +0x0000C0E5 0x820C # 0 +0x0000C0E6 0x8749 # 0 +0x0000C0E7 0x4ED9 # 0 +0x0000C0E8 0x5148 # 0 +0x0000C0E9 0x5343 # 0 +0x0000C0EA 0x5360 # 0 +0x0000C0EB 0x5BA3 # 0 +0x0000C0EC 0x5C02 # 0 +0x0000C0ED 0x5C16 # 0 +0x0000C0EE 0x5DDD # 0 +0x0000C0EF 0x6226 # 0 +0x0000C0F0 0x6247 # 0 +0x0000C0F1 0x64B0 # 0 +0x0000C0F2 0x6813 # 0 +0x0000C0F3 0x6834 # 0 +0x0000C0F4 0x6CC9 # 0 +0x0000C0F5 0x6D45 # 0 +0x0000C0F6 0x6D17 # 0 +0x0000C0F7 0x67D3 # 0 +0x0000C0F8 0x6F5C # 0 +0x0000C0F9 0x714E # 0 +0x0000C0FA 0x717D # 0 +0x0000C0FB 0x65CB # 0 +0x0000C0FC 0x7A7F # 0 +0x0000C0FD 0x7BAD # 0 +0x0000C0FE 0x7DDA # 0 +0x0000C1A1 0x7E4A # 0 +0x0000C1A2 0x7FA8 # 0 +0x0000C1A3 0x817A # 0 +0x0000C1A4 0x821B # 0 +0x0000C1A5 0x8239 # 0 +0x0000C1A6 0x85A6 # 0 +0x0000C1A7 0x8A6E # 0 +0x0000C1A8 0x8CCE # 0 +0x0000C1A9 0x8DF5 # 0 +0x0000C1AA 0x9078 # 0 +0x0000C1AB 0x9077 # 0 +0x0000C1AC 0x92AD # 0 +0x0000C1AD 0x9291 # 0 +0x0000C1AE 0x9583 # 0 +0x0000C1AF 0x9BAE # 0 +0x0000C1B0 0x524D # 0 +0x0000C1B1 0x5584 # 0 +0x0000C1B2 0x6F38 # 0 +0x0000C1B3 0x7136 # 0 +0x0000C1B4 0x5168 # 0 +0x0000C1B5 0x7985 # 0 +0x0000C1B6 0x7E55 # 0 +0x0000C1B7 0x81B3 # 0 +0x0000C1B8 0x7CCE # 0 +0x0000C1B9 0x564C # 0 +0x0000C1BA 0x5851 # 0 +0x0000C1BB 0x5CA8 # 0 +0x0000C1BC 0x63AA # 0 +0x0000C1BD 0x66FE # 0 +0x0000C1BE 0x66FD # 0 +0x0000C1BF 0x695A # 0 +0x0000C1C0 0x72D9 # 0 +0x0000C1C1 0x758F # 0 +0x0000C1C2 0x758E # 0 +0x0000C1C3 0x790E # 0 +0x0000C1C4 0x7956 # 0 +0x0000C1C5 0x79DF # 0 +0x0000C1C6 0x7C97 # 0 +0x0000C1C7 0x7D20 # 0 +0x0000C1C8 0x7D44 # 0 +0x0000C1C9 0x8607 # 0 +0x0000C1CA 0x8A34 # 0 +0x0000C1CB 0x963B # 0 +0x0000C1CC 0x9061 # 0 +0x0000C1CD 0x9F20 # 0 +0x0000C1CE 0x50E7 # 0 +0x0000C1CF 0x5275 # 0 +0x0000C1D0 0x53CC # 0 +0x0000C1D1 0x53E2 # 0 +0x0000C1D2 0x5009 # 0 +0x0000C1D3 0x55AA # 0 +0x0000C1D4 0x58EE # 0 +0x0000C1D5 0x594F # 0 +0x0000C1D6 0x723D # 0 +0x0000C1D7 0x5B8B # 0 +0x0000C1D8 0x5C64 # 0 +0x0000C1D9 0x531D # 0 +0x0000C1DA 0x60E3 # 0 +0x0000C1DB 0x60F3 # 0 +0x0000C1DC 0x635C # 0 +0x0000C1DD 0x6383 # 0 +0x0000C1DE 0x633F # 0 +0x0000C1DF 0x63BB # 0 +0x0000C1E0 0x64CD # 0 +0x0000C1E1 0x65E9 # 0 +0x0000C1E2 0x66F9 # 0 +0x0000C1E3 0x5DE3 # 0 +0x0000C1E4 0x69CD # 0 +0x0000C1E5 0x69FD # 0 +0x0000C1E6 0x6F15 # 0 +0x0000C1E7 0x71E5 # 0 +0x0000C1E8 0x4E89 # 0 +0x0000C1E9 0x75E9 # 0 +0x0000C1EA 0x76F8 # 0 +0x0000C1EB 0x7A93 # 0 +0x0000C1EC 0x7CDF # 0 +0x0000C1ED 0x7DCF # 0 +0x0000C1EE 0x7D9C # 0 +0x0000C1EF 0x8061 # 0 +0x0000C1F0 0x8349 # 0 +0x0000C1F1 0x8358 # 0 +0x0000C1F2 0x846C # 0 +0x0000C1F3 0x84BC # 0 +0x0000C1F4 0x85FB # 0 +0x0000C1F5 0x88C5 # 0 +0x0000C1F6 0x8D70 # 0 +0x0000C1F7 0x9001 # 0 +0x0000C1F8 0x906D # 0 +0x0000C1F9 0x9397 # 0 +0x0000C1FA 0x971C # 0 +0x0000C1FB 0x9A12 # 0 +0x0000C1FC 0x50CF # 0 +0x0000C1FD 0x5897 # 0 +0x0000C1FE 0x618E # 0 +0x0000C2A1 0x81D3 # 0 +0x0000C2A2 0x8535 # 0 +0x0000C2A3 0x8D08 # 0 +0x0000C2A4 0x9020 # 0 +0x0000C2A5 0x4FC3 # 0 +0x0000C2A6 0x5074 # 0 +0x0000C2A7 0x5247 # 0 +0x0000C2A8 0x5373 # 0 +0x0000C2A9 0x606F # 0 +0x0000C2AA 0x6349 # 0 +0x0000C2AB 0x675F # 0 +0x0000C2AC 0x6E2C # 0 +0x0000C2AD 0x8DB3 # 0 +0x0000C2AE 0x901F # 0 +0x0000C2AF 0x4FD7 # 0 +0x0000C2B0 0x5C5E # 0 +0x0000C2B1 0x8CCA # 0 +0x0000C2B2 0x65CF # 0 +0x0000C2B3 0x7D9A # 0 +0x0000C2B4 0x5352 # 0 +0x0000C2B5 0x8896 # 0 +0x0000C2B6 0x5176 # 0 +0x0000C2B7 0x63C3 # 0 +0x0000C2B8 0x5B58 # 0 +0x0000C2B9 0x5B6B # 0 +0x0000C2BA 0x5C0A # 0 +0x0000C2BB 0x640D # 0 +0x0000C2BC 0x6751 # 0 +0x0000C2BD 0x905C # 0 +0x0000C2BE 0x4ED6 # 0 +0x0000C2BF 0x591A # 0 +0x0000C2C0 0x592A # 0 +0x0000C2C1 0x6C70 # 0 +0x0000C2C2 0x8A51 # 0 +0x0000C2C3 0x553E # 0 +0x0000C2C4 0x5815 # 0 +0x0000C2C5 0x59A5 # 0 +0x0000C2C6 0x60F0 # 0 +0x0000C2C7 0x6253 # 0 +0x0000C2C8 0x67C1 # 0 +0x0000C2C9 0x8235 # 0 +0x0000C2CA 0x6955 # 0 +0x0000C2CB 0x9640 # 0 +0x0000C2CC 0x99C4 # 0 +0x0000C2CD 0x9A28 # 0 +0x0000C2CE 0x4F53 # 0 +0x0000C2CF 0x5806 # 0 +0x0000C2D0 0x5BFE # 0 +0x0000C2D1 0x8010 # 0 +0x0000C2D2 0x5CB1 # 0 +0x0000C2D3 0x5E2F # 0 +0x0000C2D4 0x5F85 # 0 +0x0000C2D5 0x6020 # 0 +0x0000C2D6 0x614B # 0 +0x0000C2D7 0x6234 # 0 +0x0000C2D8 0x66FF # 0 +0x0000C2D9 0x6CF0 # 0 +0x0000C2DA 0x6EDE # 0 +0x0000C2DB 0x80CE # 0 +0x0000C2DC 0x817F # 0 +0x0000C2DD 0x82D4 # 0 +0x0000C2DE 0x888B # 0 +0x0000C2DF 0x8CB8 # 0 +0x0000C2E0 0x9000 # 0 +0x0000C2E1 0x902E # 0 +0x0000C2E2 0x968A # 0 +0x0000C2E3 0x9EDB # 0 +0x0000C2E4 0x9BDB # 0 +0x0000C2E5 0x4EE3 # 0 +0x0000C2E6 0x53F0 # 0 +0x0000C2E7 0x5927 # 0 +0x0000C2E8 0x7B2C # 0 +0x0000C2E9 0x918D # 0 +0x0000C2EA 0x984C # 0 +0x0000C2EB 0x9DF9 # 0 +0x0000C2EC 0x6EDD # 0 +0x0000C2ED 0x7027 # 0 +0x0000C2EE 0x5353 # 0 +0x0000C2EF 0x5544 # 0 +0x0000C2F0 0x5B85 # 0 +0x0000C2F1 0x6258 # 0 +0x0000C2F2 0x629E # 0 +0x0000C2F3 0x62D3 # 0 +0x0000C2F4 0x6CA2 # 0 +0x0000C2F5 0x6FEF # 0 +0x0000C2F6 0x7422 # 0 +0x0000C2F7 0x8A17 # 0 +0x0000C2F8 0x9438 # 0 +0x0000C2F9 0x6FC1 # 0 +0x0000C2FA 0x8AFE # 0 +0x0000C2FB 0x8338 # 0 +0x0000C2FC 0x51E7 # 0 +0x0000C2FD 0x86F8 # 0 +0x0000C2FE 0x53EA # 0 +0x0000C3A1 0x53E9 # 0 +0x0000C3A2 0x4F46 # 0 +0x0000C3A3 0x9054 # 0 +0x0000C3A4 0x8FB0 # 0 +0x0000C3A5 0x596A # 0 +0x0000C3A6 0x8131 # 0 +0x0000C3A7 0x5DFD # 0 +0x0000C3A8 0x7AEA # 0 +0x0000C3A9 0x8FBF # 0 +0x0000C3AA 0x68DA # 0 +0x0000C3AB 0x8C37 # 0 +0x0000C3AC 0x72F8 # 0 +0x0000C3AD 0x9C48 # 0 +0x0000C3AE 0x6A3D # 0 +0x0000C3AF 0x8AB0 # 0 +0x0000C3B0 0x4E39 # 0 +0x0000C3B1 0x5358 # 0 +0x0000C3B2 0x5606 # 0 +0x0000C3B3 0x5766 # 0 +0x0000C3B4 0x62C5 # 0 +0x0000C3B5 0x63A2 # 0 +0x0000C3B6 0x65E6 # 0 +0x0000C3B7 0x6B4E # 0 +0x0000C3B8 0x6DE1 # 0 +0x0000C3B9 0x6E5B # 0 +0x0000C3BA 0x70AD # 0 +0x0000C3BB 0x77ED # 0 +0x0000C3BC 0x7AEF # 0 +0x0000C3BD 0x7BAA # 0 +0x0000C3BE 0x7DBB # 0 +0x0000C3BF 0x803D # 0 +0x0000C3C0 0x80C6 # 0 +0x0000C3C1 0x86CB # 0 +0x0000C3C2 0x8A95 # 0 +0x0000C3C3 0x935B # 0 +0x0000C3C4 0x56E3 # 0 +0x0000C3C5 0x58C7 # 0 +0x0000C3C6 0x5F3E # 0 +0x0000C3C7 0x65AD # 0 +0x0000C3C8 0x6696 # 0 +0x0000C3C9 0x6A80 # 0 +0x0000C3CA 0x6BB5 # 0 +0x0000C3CB 0x7537 # 0 +0x0000C3CC 0x8AC7 # 0 +0x0000C3CD 0x5024 # 0 +0x0000C3CE 0x77E5 # 0 +0x0000C3CF 0x5730 # 0 +0x0000C3D0 0x5F1B # 0 +0x0000C3D1 0x6065 # 0 +0x0000C3D2 0x667A # 0 +0x0000C3D3 0x6C60 # 0 +0x0000C3D4 0x75F4 # 0 +0x0000C3D5 0x7A1A # 0 +0x0000C3D6 0x7F6E # 0 +0x0000C3D7 0x81F4 # 0 +0x0000C3D8 0x8718 # 0 +0x0000C3D9 0x9045 # 0 +0x0000C3DA 0x99B3 # 0 +0x0000C3DB 0x7BC9 # 0 +0x0000C3DC 0x755C # 0 +0x0000C3DD 0x7AF9 # 0 +0x0000C3DE 0x7B51 # 0 +0x0000C3DF 0x84C4 # 0 +0x0000C3E0 0x9010 # 0 +0x0000C3E1 0x79E9 # 0 +0x0000C3E2 0x7A92 # 0 +0x0000C3E3 0x8336 # 0 +0x0000C3E4 0x5AE1 # 0 +0x0000C3E5 0x7740 # 0 +0x0000C3E6 0x4E2D # 0 +0x0000C3E7 0x4EF2 # 0 +0x0000C3E8 0x5B99 # 0 +0x0000C3E9 0x5FE0 # 0 +0x0000C3EA 0x62BD # 0 +0x0000C3EB 0x663C # 0 +0x0000C3EC 0x67F1 # 0 +0x0000C3ED 0x6CE8 # 0 +0x0000C3EE 0x866B # 0 +0x0000C3EF 0x8877 # 0 +0x0000C3F0 0x8A3B # 0 +0x0000C3F1 0x914E # 0 +0x0000C3F2 0x92F3 # 0 +0x0000C3F3 0x99D0 # 0 +0x0000C3F4 0x6A17 # 0 +0x0000C3F5 0x7026 # 0 +0x0000C3F6 0x732A # 0 +0x0000C3F7 0x82E7 # 0 +0x0000C3F8 0x8457 # 0 +0x0000C3F9 0x8CAF # 0 +0x0000C3FA 0x4E01 # 0 +0x0000C3FB 0x5146 # 0 +0x0000C3FC 0x51CB # 0 +0x0000C3FD 0x558B # 0 +0x0000C3FE 0x5BF5 # 0 +0x0000C4A1 0x5E16 # 0 +0x0000C4A2 0x5E33 # 0 +0x0000C4A3 0x5E81 # 0 +0x0000C4A4 0x5F14 # 0 +0x0000C4A5 0x5F35 # 0 +0x0000C4A6 0x5F6B # 0 +0x0000C4A7 0x5FB4 # 0 +0x0000C4A8 0x61F2 # 0 +0x0000C4A9 0x6311 # 0 +0x0000C4AA 0x66A2 # 0 +0x0000C4AB 0x671D # 0 +0x0000C4AC 0x6F6E # 0 +0x0000C4AD 0x7252 # 0 +0x0000C4AE 0x753A # 0 +0x0000C4AF 0x773A # 0 +0x0000C4B0 0x8074 # 0 +0x0000C4B1 0x8139 # 0 +0x0000C4B2 0x8178 # 0 +0x0000C4B3 0x8776 # 0 +0x0000C4B4 0x8ABF # 0 +0x0000C4B5 0x8ADC # 0 +0x0000C4B6 0x8D85 # 0 +0x0000C4B7 0x8DF3 # 0 +0x0000C4B8 0x929A # 0 +0x0000C4B9 0x9577 # 0 +0x0000C4BA 0x9802 # 0 +0x0000C4BB 0x9CE5 # 0 +0x0000C4BC 0x52C5 # 0 +0x0000C4BD 0x6357 # 0 +0x0000C4BE 0x76F4 # 0 +0x0000C4BF 0x6715 # 0 +0x0000C4C0 0x6C88 # 0 +0x0000C4C1 0x73CD # 0 +0x0000C4C2 0x8CC3 # 0 +0x0000C4C3 0x93AE # 0 +0x0000C4C4 0x9673 # 0 +0x0000C4C5 0x6D25 # 0 +0x0000C4C6 0x589C # 0 +0x0000C4C7 0x690E # 0 +0x0000C4C8 0x69CC # 0 +0x0000C4C9 0x8FFD # 0 +0x0000C4CA 0x939A # 0 +0x0000C4CB 0x75DB # 0 +0x0000C4CC 0x901A # 0 +0x0000C4CD 0x585A # 0 +0x0000C4CE 0x6802 # 0 +0x0000C4CF 0x63B4 # 0 +0x0000C4D0 0x69FB # 0 +0x0000C4D1 0x4F43 # 0 +0x0000C4D2 0x6F2C # 0 +0x0000C4D3 0x67D8 # 0 +0x0000C4D4 0x8FBB # 0 +0x0000C4D5 0x8526 # 0 +0x0000C4D6 0x7DB4 # 0 +0x0000C4D7 0x9354 # 0 +0x0000C4D8 0x693F # 0 +0x0000C4D9 0x6F70 # 0 +0x0000C4DA 0x576A # 0 +0x0000C4DB 0x58F7 # 0 +0x0000C4DC 0x5B2C # 0 +0x0000C4DD 0x7D2C # 0 +0x0000C4DE 0x722A # 0 +0x0000C4DF 0x540A # 0 +0x0000C4E0 0x91E3 # 0 +0x0000C4E1 0x9DB4 # 0 +0x0000C4E2 0x4EAD # 0 +0x0000C4E3 0x4F4E # 0 +0x0000C4E4 0x505C # 0 +0x0000C4E5 0x5075 # 0 +0x0000C4E6 0x5243 # 0 +0x0000C4E7 0x8C9E # 0 +0x0000C4E8 0x5448 # 0 +0x0000C4E9 0x5824 # 0 +0x0000C4EA 0x5B9A # 0 +0x0000C4EB 0x5E1D # 0 +0x0000C4EC 0x5E95 # 0 +0x0000C4ED 0x5EAD # 0 +0x0000C4EE 0x5EF7 # 0 +0x0000C4EF 0x5F1F # 0 +0x0000C4F0 0x608C # 0 +0x0000C4F1 0x62B5 # 0 +0x0000C4F2 0x633A # 0 +0x0000C4F3 0x63D0 # 0 +0x0000C4F4 0x68AF # 0 +0x0000C4F5 0x6C40 # 0 +0x0000C4F6 0x7887 # 0 +0x0000C4F7 0x798E # 0 +0x0000C4F8 0x7A0B # 0 +0x0000C4F9 0x7DE0 # 0 +0x0000C4FA 0x8247 # 0 +0x0000C4FB 0x8A02 # 0 +0x0000C4FC 0x8AE6 # 0 +0x0000C4FD 0x8E44 # 0 +0x0000C4FE 0x9013 # 0 +0x0000C5A1 0x90B8 # 0 +0x0000C5A2 0x912D # 0 +0x0000C5A3 0x91D8 # 0 +0x0000C5A4 0x9F0E # 0 +0x0000C5A5 0x6CE5 # 0 +0x0000C5A6 0x6458 # 0 +0x0000C5A7 0x64E2 # 0 +0x0000C5A8 0x6575 # 0 +0x0000C5A9 0x6EF4 # 0 +0x0000C5AA 0x7684 # 0 +0x0000C5AB 0x7B1B # 0 +0x0000C5AC 0x9069 # 0 +0x0000C5AD 0x93D1 # 0 +0x0000C5AE 0x6EBA # 0 +0x0000C5AF 0x54F2 # 0 +0x0000C5B0 0x5FB9 # 0 +0x0000C5B1 0x64A4 # 0 +0x0000C5B2 0x8F4D # 0 +0x0000C5B3 0x8FED # 0 +0x0000C5B4 0x9244 # 0 +0x0000C5B5 0x5178 # 0 +0x0000C5B6 0x586B # 0 +0x0000C5B7 0x5929 # 0 +0x0000C5B8 0x5C55 # 0 +0x0000C5B9 0x5E97 # 0 +0x0000C5BA 0x6DFB # 0 +0x0000C5BB 0x7E8F # 0 +0x0000C5BC 0x751C # 0 +0x0000C5BD 0x8CBC # 0 +0x0000C5BE 0x8EE2 # 0 +0x0000C5BF 0x985B # 0 +0x0000C5C0 0x70B9 # 0 +0x0000C5C1 0x4F1D # 0 +0x0000C5C2 0x6BBF # 0 +0x0000C5C3 0x6FB1 # 0 +0x0000C5C4 0x7530 # 0 +0x0000C5C5 0x96FB # 0 +0x0000C5C6 0x514E # 0 +0x0000C5C7 0x5410 # 0 +0x0000C5C8 0x5835 # 0 +0x0000C5C9 0x5857 # 0 +0x0000C5CA 0x59AC # 0 +0x0000C5CB 0x5C60 # 0 +0x0000C5CC 0x5F92 # 0 +0x0000C5CD 0x6597 # 0 +0x0000C5CE 0x675C # 0 +0x0000C5CF 0x6E21 # 0 +0x0000C5D0 0x767B # 0 +0x0000C5D1 0x83DF # 0 +0x0000C5D2 0x8CED # 0 +0x0000C5D3 0x9014 # 0 +0x0000C5D4 0x90FD # 0 +0x0000C5D5 0x934D # 0 +0x0000C5D6 0x7825 # 0 +0x0000C5D7 0x783A # 0 +0x0000C5D8 0x52AA # 0 +0x0000C5D9 0x5EA6 # 0 +0x0000C5DA 0x571F # 0 +0x0000C5DB 0x5974 # 0 +0x0000C5DC 0x6012 # 0 +0x0000C5DD 0x5012 # 0 +0x0000C5DE 0x515A # 0 +0x0000C5DF 0x51AC # 0 +0x0000C5E0 0x51CD # 0 +0x0000C5E1 0x5200 # 0 +0x0000C5E2 0x5510 # 0 +0x0000C5E3 0x5854 # 0 +0x0000C5E4 0x5858 # 0 +0x0000C5E5 0x5957 # 0 +0x0000C5E6 0x5B95 # 0 +0x0000C5E7 0x5CF6 # 0 +0x0000C5E8 0x5D8B # 0 +0x0000C5E9 0x60BC # 0 +0x0000C5EA 0x6295 # 0 +0x0000C5EB 0x642D # 0 +0x0000C5EC 0x6771 # 0 +0x0000C5ED 0x6843 # 0 +0x0000C5EE 0x68BC # 0 +0x0000C5EF 0x68DF # 0 +0x0000C5F0 0x76D7 # 0 +0x0000C5F1 0x6DD8 # 0 +0x0000C5F2 0x6E6F # 0 +0x0000C5F3 0x6D9B # 0 +0x0000C5F4 0x706F # 0 +0x0000C5F5 0x71C8 # 0 +0x0000C5F6 0x5F53 # 0 +0x0000C5F7 0x75D8 # 0 +0x0000C5F8 0x7977 # 0 +0x0000C5F9 0x7B49 # 0 +0x0000C5FA 0x7B54 # 0 +0x0000C5FB 0x7B52 # 0 +0x0000C5FC 0x7CD6 # 0 +0x0000C5FD 0x7D71 # 0 +0x0000C5FE 0x5230 # 0 +0x0000C6A1 0x8463 # 0 +0x0000C6A2 0x8569 # 0 +0x0000C6A3 0x85E4 # 0 +0x0000C6A4 0x8A0E # 0 +0x0000C6A5 0x8B04 # 0 +0x0000C6A6 0x8C46 # 0 +0x0000C6A7 0x8E0F # 0 +0x0000C6A8 0x9003 # 0 +0x0000C6A9 0x900F # 0 +0x0000C6AA 0x9419 # 0 +0x0000C6AB 0x9676 # 0 +0x0000C6AC 0x982D # 0 +0x0000C6AD 0x9A30 # 0 +0x0000C6AE 0x95D8 # 0 +0x0000C6AF 0x50CD # 0 +0x0000C6B0 0x52D5 # 0 +0x0000C6B1 0x540C # 0 +0x0000C6B2 0x5802 # 0 +0x0000C6B3 0x5C0E # 0 +0x0000C6B4 0x61A7 # 0 +0x0000C6B5 0x649E # 0 +0x0000C6B6 0x6D1E # 0 +0x0000C6B7 0x77B3 # 0 +0x0000C6B8 0x7AE5 # 0 +0x0000C6B9 0x80F4 # 0 +0x0000C6BA 0x8404 # 0 +0x0000C6BB 0x9053 # 0 +0x0000C6BC 0x9285 # 0 +0x0000C6BD 0x5CE0 # 0 +0x0000C6BE 0x9D07 # 0 +0x0000C6BF 0x533F # 0 +0x0000C6C0 0x5F97 # 0 +0x0000C6C1 0x5FB3 # 0 +0x0000C6C2 0x6D9C # 0 +0x0000C6C3 0x7279 # 0 +0x0000C6C4 0x7763 # 0 +0x0000C6C5 0x79BF # 0 +0x0000C6C6 0x7BE4 # 0 +0x0000C6C7 0x6BD2 # 0 +0x0000C6C8 0x72EC # 0 +0x0000C6C9 0x8AAD # 0 +0x0000C6CA 0x6803 # 0 +0x0000C6CB 0x6A61 # 0 +0x0000C6CC 0x51F8 # 0 +0x0000C6CD 0x7A81 # 0 +0x0000C6CE 0x6934 # 0 +0x0000C6CF 0x5C4A # 0 +0x0000C6D0 0x9CF6 # 0 +0x0000C6D1 0x82EB # 0 +0x0000C6D2 0x5BC5 # 0 +0x0000C6D3 0x9149 # 0 +0x0000C6D4 0x701E # 0 +0x0000C6D5 0x5678 # 0 +0x0000C6D6 0x5C6F # 0 +0x0000C6D7 0x60C7 # 0 +0x0000C6D8 0x6566 # 0 +0x0000C6D9 0x6C8C # 0 +0x0000C6DA 0x8C5A # 0 +0x0000C6DB 0x9041 # 0 +0x0000C6DC 0x9813 # 0 +0x0000C6DD 0x5451 # 0 +0x0000C6DE 0x66C7 # 0 +0x0000C6DF 0x920D # 0 +0x0000C6E0 0x5948 # 0 +0x0000C6E1 0x90A3 # 0 +0x0000C6E2 0x5185 # 0 +0x0000C6E3 0x4E4D # 0 +0x0000C6E4 0x51EA # 0 +0x0000C6E5 0x8599 # 0 +0x0000C6E6 0x8B0E # 0 +0x0000C6E7 0x7058 # 0 +0x0000C6E8 0x637A # 0 +0x0000C6E9 0x934B # 0 +0x0000C6EA 0x6962 # 0 +0x0000C6EB 0x99B4 # 0 +0x0000C6EC 0x7E04 # 0 +0x0000C6ED 0x7577 # 0 +0x0000C6EE 0x5357 # 0 +0x0000C6EF 0x6960 # 0 +0x0000C6F0 0x8EDF # 0 +0x0000C6F1 0x96E3 # 0 +0x0000C6F2 0x6C5D # 0 +0x0000C6F3 0x4E8C # 0 +0x0000C6F4 0x5C3C # 0 +0x0000C6F5 0x5F10 # 0 +0x0000C6F6 0x8FE9 # 0 +0x0000C6F7 0x5302 # 0 +0x0000C6F8 0x8CD1 # 0 +0x0000C6F9 0x8089 # 0 +0x0000C6FA 0x8679 # 0 +0x0000C6FB 0x5EFF # 0 +0x0000C6FC 0x65E5 # 0 +0x0000C6FD 0x4E73 # 0 +0x0000C6FE 0x5165 # 0 +0x0000C7A1 0x5982 # 0 +0x0000C7A2 0x5C3F # 0 +0x0000C7A3 0x97EE # 0 +0x0000C7A4 0x4EFB # 0 +0x0000C7A5 0x598A # 0 +0x0000C7A6 0x5FCD # 0 +0x0000C7A7 0x8A8D # 0 +0x0000C7A8 0x6FE1 # 0 +0x0000C7A9 0x79B0 # 0 +0x0000C7AA 0x7962 # 0 +0x0000C7AB 0x5BE7 # 0 +0x0000C7AC 0x8471 # 0 +0x0000C7AD 0x732B # 0 +0x0000C7AE 0x71B1 # 0 +0x0000C7AF 0x5E74 # 0 +0x0000C7B0 0x5FF5 # 0 +0x0000C7B1 0x637B # 0 +0x0000C7B2 0x649A # 0 +0x0000C7B3 0x71C3 # 0 +0x0000C7B4 0x7C98 # 0 +0x0000C7B5 0x4E43 # 0 +0x0000C7B6 0x5EFC # 0 +0x0000C7B7 0x4E4B # 0 +0x0000C7B8 0x57DC # 0 +0x0000C7B9 0x56A2 # 0 +0x0000C7BA 0x60A9 # 0 +0x0000C7BB 0x6FC3 # 0 +0x0000C7BC 0x7D0D # 0 +0x0000C7BD 0x80FD # 0 +0x0000C7BE 0x8133 # 0 +0x0000C7BF 0x81BF # 0 +0x0000C7C0 0x8FB2 # 0 +0x0000C7C1 0x8997 # 0 +0x0000C7C2 0x86A4 # 0 +0x0000C7C3 0x5DF4 # 0 +0x0000C7C4 0x628A # 0 +0x0000C7C5 0x64AD # 0 +0x0000C7C6 0x8987 # 0 +0x0000C7C7 0x6777 # 0 +0x0000C7C8 0x6CE2 # 0 +0x0000C7C9 0x6D3E # 0 +0x0000C7CA 0x7436 # 0 +0x0000C7CB 0x7834 # 0 +0x0000C7CC 0x5A46 # 0 +0x0000C7CD 0x7F75 # 0 +0x0000C7CE 0x82AD # 0 +0x0000C7CF 0x99AC # 0 +0x0000C7D0 0x4FF3 # 0 +0x0000C7D1 0x5EC3 # 0 +0x0000C7D2 0x62DD # 0 +0x0000C7D3 0x6392 # 0 +0x0000C7D4 0x6557 # 0 +0x0000C7D5 0x676F # 0 +0x0000C7D6 0x76C3 # 0 +0x0000C7D7 0x724C # 0 +0x0000C7D8 0x80CC # 0 +0x0000C7D9 0x80BA # 0 +0x0000C7DA 0x8F29 # 0 +0x0000C7DB 0x914D # 0 +0x0000C7DC 0x500D # 0 +0x0000C7DD 0x57F9 # 0 +0x0000C7DE 0x5A92 # 0 +0x0000C7DF 0x6885 # 0 +0x0000C7E0 0x6973 # 0 +0x0000C7E1 0x7164 # 0 +0x0000C7E2 0x72FD # 0 +0x0000C7E3 0x8CB7 # 0 +0x0000C7E4 0x58F2 # 0 +0x0000C7E5 0x8CE0 # 0 +0x0000C7E6 0x966A # 0 +0x0000C7E7 0x9019 # 0 +0x0000C7E8 0x877F # 0 +0x0000C7E9 0x79E4 # 0 +0x0000C7EA 0x77E7 # 0 +0x0000C7EB 0x8429 # 0 +0x0000C7EC 0x4F2F # 0 +0x0000C7ED 0x5265 # 0 +0x0000C7EE 0x535A # 0 +0x0000C7EF 0x62CD # 0 +0x0000C7F0 0x67CF # 0 +0x0000C7F1 0x6CCA # 0 +0x0000C7F2 0x767D # 0 +0x0000C7F3 0x7B94 # 0 +0x0000C7F4 0x7C95 # 0 +0x0000C7F5 0x8236 # 0 +0x0000C7F6 0x8584 # 0 +0x0000C7F7 0x8FEB # 0 +0x0000C7F8 0x66DD # 0 +0x0000C7F9 0x6F20 # 0 +0x0000C7FA 0x7206 # 0 +0x0000C7FB 0x7E1B # 0 +0x0000C7FC 0x83AB # 0 +0x0000C7FD 0x99C1 # 0 +0x0000C7FE 0x9EA6 # 0 +0x0000C8A1 0x51FD # 0 +0x0000C8A2 0x7BB1 # 0 +0x0000C8A3 0x7872 # 0 +0x0000C8A4 0x7BB8 # 0 +0x0000C8A5 0x8087 # 0 +0x0000C8A6 0x7B48 # 0 +0x0000C8A7 0x6AE8 # 0 +0x0000C8A8 0x5E61 # 0 +0x0000C8A9 0x808C # 0 +0x0000C8AA 0x7551 # 0 +0x0000C8AB 0x7560 # 0 +0x0000C8AC 0x516B # 0 +0x0000C8AD 0x9262 # 0 +0x0000C8AE 0x6E8C # 0 +0x0000C8AF 0x767A # 0 +0x0000C8B0 0x9197 # 0 +0x0000C8B1 0x9AEA # 0 +0x0000C8B2 0x4F10 # 0 +0x0000C8B3 0x7F70 # 0 +0x0000C8B4 0x629C # 0 +0x0000C8B5 0x7B4F # 0 +0x0000C8B6 0x95A5 # 0 +0x0000C8B7 0x9CE9 # 0 +0x0000C8B8 0x567A # 0 +0x0000C8B9 0x5859 # 0 +0x0000C8BA 0x86E4 # 0 +0x0000C8BB 0x96BC # 0 +0x0000C8BC 0x4F34 # 0 +0x0000C8BD 0x5224 # 0 +0x0000C8BE 0x534A # 0 +0x0000C8BF 0x53CD # 0 +0x0000C8C0 0x53DB # 0 +0x0000C8C1 0x5E06 # 0 +0x0000C8C2 0x642C # 0 +0x0000C8C3 0x6591 # 0 +0x0000C8C4 0x677F # 0 +0x0000C8C5 0x6C3E # 0 +0x0000C8C6 0x6C4E # 0 +0x0000C8C7 0x7248 # 0 +0x0000C8C8 0x72AF # 0 +0x0000C8C9 0x73ED # 0 +0x0000C8CA 0x7554 # 0 +0x0000C8CB 0x7E41 # 0 +0x0000C8CC 0x822C # 0 +0x0000C8CD 0x85E9 # 0 +0x0000C8CE 0x8CA9 # 0 +0x0000C8CF 0x7BC4 # 0 +0x0000C8D0 0x91C6 # 0 +0x0000C8D1 0x7169 # 0 +0x0000C8D2 0x9812 # 0 +0x0000C8D3 0x98EF # 0 +0x0000C8D4 0x633D # 0 +0x0000C8D5 0x6669 # 0 +0x0000C8D6 0x756A # 0 +0x0000C8D7 0x76E4 # 0 +0x0000C8D8 0x78D0 # 0 +0x0000C8D9 0x8543 # 0 +0x0000C8DA 0x86EE # 0 +0x0000C8DB 0x532A # 0 +0x0000C8DC 0x5351 # 0 +0x0000C8DD 0x5426 # 0 +0x0000C8DE 0x5983 # 0 +0x0000C8DF 0x5E87 # 0 +0x0000C8E0 0x5F7C # 0 +0x0000C8E1 0x60B2 # 0 +0x0000C8E2 0x6249 # 0 +0x0000C8E3 0x6279 # 0 +0x0000C8E4 0x62AB # 0 +0x0000C8E5 0x6590 # 0 +0x0000C8E6 0x6BD4 # 0 +0x0000C8E7 0x6CCC # 0 +0x0000C8E8 0x75B2 # 0 +0x0000C8E9 0x76AE # 0 +0x0000C8EA 0x7891 # 0 +0x0000C8EB 0x79D8 # 0 +0x0000C8EC 0x7DCB # 0 +0x0000C8ED 0x7F77 # 0 +0x0000C8EE 0x80A5 # 0 +0x0000C8EF 0x88AB # 0 +0x0000C8F0 0x8AB9 # 0 +0x0000C8F1 0x8CBB # 0 +0x0000C8F2 0x907F # 0 +0x0000C8F3 0x975E # 0 +0x0000C8F4 0x98DB # 0 +0x0000C8F5 0x6A0B # 0 +0x0000C8F6 0x7C38 # 0 +0x0000C8F7 0x5099 # 0 +0x0000C8F8 0x5C3E # 0 +0x0000C8F9 0x5FAE # 0 +0x0000C8FA 0x6787 # 0 +0x0000C8FB 0x6BD8 # 0 +0x0000C8FC 0x7435 # 0 +0x0000C8FD 0x7709 # 0 +0x0000C8FE 0x7F8E # 0 +0x0000C9A1 0x9F3B # 0 +0x0000C9A2 0x67CA # 0 +0x0000C9A3 0x7A17 # 0 +0x0000C9A4 0x5339 # 0 +0x0000C9A5 0x758B # 0 +0x0000C9A6 0x9AED # 0 +0x0000C9A7 0x5F66 # 0 +0x0000C9A8 0x819D # 0 +0x0000C9A9 0x83F1 # 0 +0x0000C9AA 0x8098 # 0 +0x0000C9AB 0x5F3C # 0 +0x0000C9AC 0x5FC5 # 0 +0x0000C9AD 0x7562 # 0 +0x0000C9AE 0x7B46 # 0 +0x0000C9AF 0x903C # 0 +0x0000C9B0 0x6867 # 0 +0x0000C9B1 0x59EB # 0 +0x0000C9B2 0x5A9B # 0 +0x0000C9B3 0x7D10 # 0 +0x0000C9B4 0x767E # 0 +0x0000C9B5 0x8B2C # 0 +0x0000C9B6 0x4FF5 # 0 +0x0000C9B7 0x5F6A # 0 +0x0000C9B8 0x6A19 # 0 +0x0000C9B9 0x6C37 # 0 +0x0000C9BA 0x6F02 # 0 +0x0000C9BB 0x74E2 # 0 +0x0000C9BC 0x7968 # 0 +0x0000C9BD 0x8868 # 0 +0x0000C9BE 0x8A55 # 0 +0x0000C9BF 0x8C79 # 0 +0x0000C9C0 0x5EDF # 0 +0x0000C9C1 0x63CF # 0 +0x0000C9C2 0x75C5 # 0 +0x0000C9C3 0x79D2 # 0 +0x0000C9C4 0x82D7 # 0 +0x0000C9C5 0x9328 # 0 +0x0000C9C6 0x92F2 # 0 +0x0000C9C7 0x849C # 0 +0x0000C9C8 0x86ED # 0 +0x0000C9C9 0x9C2D # 0 +0x0000C9CA 0x54C1 # 0 +0x0000C9CB 0x5F6C # 0 +0x0000C9CC 0x658C # 0 +0x0000C9CD 0x6D5C # 0 +0x0000C9CE 0x7015 # 0 +0x0000C9CF 0x8CA7 # 0 +0x0000C9D0 0x8CD3 # 0 +0x0000C9D1 0x983B # 0 +0x0000C9D2 0x654F # 0 +0x0000C9D3 0x74F6 # 0 +0x0000C9D4 0x4E0D # 0 +0x0000C9D5 0x4ED8 # 0 +0x0000C9D6 0x57E0 # 0 +0x0000C9D7 0x592B # 0 +0x0000C9D8 0x5A66 # 0 +0x0000C9D9 0x5BCC # 0 +0x0000C9DA 0x51A8 # 0 +0x0000C9DB 0x5E03 # 0 +0x0000C9DC 0x5E9C # 0 +0x0000C9DD 0x6016 # 0 +0x0000C9DE 0x6276 # 0 +0x0000C9DF 0x6577 # 0 +0x0000C9E0 0x65A7 # 0 +0x0000C9E1 0x666E # 0 +0x0000C9E2 0x6D6E # 0 +0x0000C9E3 0x7236 # 0 +0x0000C9E4 0x7B26 # 0 +0x0000C9E5 0x8150 # 0 +0x0000C9E6 0x819A # 0 +0x0000C9E7 0x8299 # 0 +0x0000C9E8 0x8B5C # 0 +0x0000C9E9 0x8CA0 # 0 +0x0000C9EA 0x8CE6 # 0 +0x0000C9EB 0x8D74 # 0 +0x0000C9EC 0x961C # 0 +0x0000C9ED 0x9644 # 0 +0x0000C9EE 0x4FAE # 0 +0x0000C9EF 0x64AB # 0 +0x0000C9F0 0x6B66 # 0 +0x0000C9F1 0x821E # 0 +0x0000C9F2 0x8461 # 0 +0x0000C9F3 0x856A # 0 +0x0000C9F4 0x90E8 # 0 +0x0000C9F5 0x5C01 # 0 +0x0000C9F6 0x6953 # 0 +0x0000C9F7 0x98A8 # 0 +0x0000C9F8 0x847A # 0 +0x0000C9F9 0x8557 # 0 +0x0000C9FA 0x4F0F # 0 +0x0000C9FB 0x526F # 0 +0x0000C9FC 0x5FA9 # 0 +0x0000C9FD 0x5E45 # 0 +0x0000C9FE 0x670D # 0 +0x0000CAA1 0x798F # 0 +0x0000CAA2 0x8179 # 0 +0x0000CAA3 0x8907 # 0 +0x0000CAA4 0x8986 # 0 +0x0000CAA5 0x6DF5 # 0 +0x0000CAA6 0x5F17 # 0 +0x0000CAA7 0x6255 # 0 +0x0000CAA8 0x6CB8 # 0 +0x0000CAA9 0x4ECF # 0 +0x0000CAAA 0x7269 # 0 +0x0000CAAB 0x9B92 # 0 +0x0000CAAC 0x5206 # 0 +0x0000CAAD 0x543B # 0 +0x0000CAAE 0x5674 # 0 +0x0000CAAF 0x58B3 # 0 +0x0000CAB0 0x61A4 # 0 +0x0000CAB1 0x626E # 0 +0x0000CAB2 0x711A # 0 +0x0000CAB3 0x596E # 0 +0x0000CAB4 0x7C89 # 0 +0x0000CAB5 0x7CDE # 0 +0x0000CAB6 0x7D1B # 0 +0x0000CAB7 0x96F0 # 0 +0x0000CAB8 0x6587 # 0 +0x0000CAB9 0x805E # 0 +0x0000CABA 0x4E19 # 0 +0x0000CABB 0x4F75 # 0 +0x0000CABC 0x5175 # 0 +0x0000CABD 0x5840 # 0 +0x0000CABE 0x5E63 # 0 +0x0000CABF 0x5E73 # 0 +0x0000CAC0 0x5F0A # 0 +0x0000CAC1 0x67C4 # 0 +0x0000CAC2 0x4E26 # 0 +0x0000CAC3 0x853D # 0 +0x0000CAC4 0x9589 # 0 +0x0000CAC5 0x965B # 0 +0x0000CAC6 0x7C73 # 0 +0x0000CAC7 0x9801 # 0 +0x0000CAC8 0x50FB # 0 +0x0000CAC9 0x58C1 # 0 +0x0000CACA 0x7656 # 0 +0x0000CACB 0x78A7 # 0 +0x0000CACC 0x5225 # 0 +0x0000CACD 0x77A5 # 0 +0x0000CACE 0x8511 # 0 +0x0000CACF 0x7B86 # 0 +0x0000CAD0 0x504F # 0 +0x0000CAD1 0x5909 # 0 +0x0000CAD2 0x7247 # 0 +0x0000CAD3 0x7BC7 # 0 +0x0000CAD4 0x7DE8 # 0 +0x0000CAD5 0x8FBA # 0 +0x0000CAD6 0x8FD4 # 0 +0x0000CAD7 0x904D # 0 +0x0000CAD8 0x4FBF # 0 +0x0000CAD9 0x52C9 # 0 +0x0000CADA 0x5A29 # 0 +0x0000CADB 0x5F01 # 0 +0x0000CADC 0x97AD # 0 +0x0000CADD 0x4FDD # 0 +0x0000CADE 0x8217 # 0 +0x0000CADF 0x92EA # 0 +0x0000CAE0 0x5703 # 0 +0x0000CAE1 0x6355 # 0 +0x0000CAE2 0x6B69 # 0 +0x0000CAE3 0x752B # 0 +0x0000CAE4 0x88DC # 0 +0x0000CAE5 0x8F14 # 0 +0x0000CAE6 0x7A42 # 0 +0x0000CAE7 0x52DF # 0 +0x0000CAE8 0x5893 # 0 +0x0000CAE9 0x6155 # 0 +0x0000CAEA 0x620A # 0 +0x0000CAEB 0x66AE # 0 +0x0000CAEC 0x6BCD # 0 +0x0000CAED 0x7C3F # 0 +0x0000CAEE 0x83E9 # 0 +0x0000CAEF 0x5023 # 0 +0x0000CAF0 0x4FF8 # 0 +0x0000CAF1 0x5305 # 0 +0x0000CAF2 0x5446 # 0 +0x0000CAF3 0x5831 # 0 +0x0000CAF4 0x5949 # 0 +0x0000CAF5 0x5B9D # 0 +0x0000CAF6 0x5CF0 # 0 +0x0000CAF7 0x5CEF # 0 +0x0000CAF8 0x5D29 # 0 +0x0000CAF9 0x5E96 # 0 +0x0000CAFA 0x62B1 # 0 +0x0000CAFB 0x6367 # 0 +0x0000CAFC 0x653E # 0 +0x0000CAFD 0x65B9 # 0 +0x0000CAFE 0x670B # 0 +0x0000CBA1 0x6CD5 # 0 +0x0000CBA2 0x6CE1 # 0 +0x0000CBA3 0x70F9 # 0 +0x0000CBA4 0x7832 # 0 +0x0000CBA5 0x7E2B # 0 +0x0000CBA6 0x80DE # 0 +0x0000CBA7 0x82B3 # 0 +0x0000CBA8 0x840C # 0 +0x0000CBA9 0x84EC # 0 +0x0000CBAA 0x8702 # 0 +0x0000CBAB 0x8912 # 0 +0x0000CBAC 0x8A2A # 0 +0x0000CBAD 0x8C4A # 0 +0x0000CBAE 0x90A6 # 0 +0x0000CBAF 0x92D2 # 0 +0x0000CBB0 0x98FD # 0 +0x0000CBB1 0x9CF3 # 0 +0x0000CBB2 0x9D6C # 0 +0x0000CBB3 0x4E4F # 0 +0x0000CBB4 0x4EA1 # 0 +0x0000CBB5 0x508D # 0 +0x0000CBB6 0x5256 # 0 +0x0000CBB7 0x574A # 0 +0x0000CBB8 0x59A8 # 0 +0x0000CBB9 0x5E3D # 0 +0x0000CBBA 0x5FD8 # 0 +0x0000CBBB 0x5FD9 # 0 +0x0000CBBC 0x623F # 0 +0x0000CBBD 0x66B4 # 0 +0x0000CBBE 0x671B # 0 +0x0000CBBF 0x67D0 # 0 +0x0000CBC0 0x68D2 # 0 +0x0000CBC1 0x5192 # 0 +0x0000CBC2 0x7D21 # 0 +0x0000CBC3 0x80AA # 0 +0x0000CBC4 0x81A8 # 0 +0x0000CBC5 0x8B00 # 0 +0x0000CBC6 0x8C8C # 0 +0x0000CBC7 0x8CBF # 0 +0x0000CBC8 0x927E # 0 +0x0000CBC9 0x9632 # 0 +0x0000CBCA 0x5420 # 0 +0x0000CBCB 0x982C # 0 +0x0000CBCC 0x5317 # 0 +0x0000CBCD 0x50D5 # 0 +0x0000CBCE 0x535C # 0 +0x0000CBCF 0x58A8 # 0 +0x0000CBD0 0x64B2 # 0 +0x0000CBD1 0x6734 # 0 +0x0000CBD2 0x7267 # 0 +0x0000CBD3 0x7766 # 0 +0x0000CBD4 0x7A46 # 0 +0x0000CBD5 0x91E6 # 0 +0x0000CBD6 0x52C3 # 0 +0x0000CBD7 0x6CA1 # 0 +0x0000CBD8 0x6B86 # 0 +0x0000CBD9 0x5800 # 0 +0x0000CBDA 0x5E4C # 0 +0x0000CBDB 0x5954 # 0 +0x0000CBDC 0x672C # 0 +0x0000CBDD 0x7FFB # 0 +0x0000CBDE 0x51E1 # 0 +0x0000CBDF 0x76C6 # 0 +0x0000CBE0 0x6469 # 0 +0x0000CBE1 0x78E8 # 0 +0x0000CBE2 0x9B54 # 0 +0x0000CBE3 0x9EBB # 0 +0x0000CBE4 0x57CB # 0 +0x0000CBE5 0x59B9 # 0 +0x0000CBE6 0x6627 # 0 +0x0000CBE7 0x679A # 0 +0x0000CBE8 0x6BCE # 0 +0x0000CBE9 0x54E9 # 0 +0x0000CBEA 0x69D9 # 0 +0x0000CBEB 0x5E55 # 0 +0x0000CBEC 0x819C # 0 +0x0000CBED 0x6795 # 0 +0x0000CBEE 0x9BAA # 0 +0x0000CBEF 0x67FE # 0 +0x0000CBF0 0x9C52 # 0 +0x0000CBF1 0x685D # 0 +0x0000CBF2 0x4EA6 # 0 +0x0000CBF3 0x4FE3 # 0 +0x0000CBF4 0x53C8 # 0 +0x0000CBF5 0x62B9 # 0 +0x0000CBF6 0x672B # 0 +0x0000CBF7 0x6CAB # 0 +0x0000CBF8 0x8FC4 # 0 +0x0000CBF9 0x4FAD # 0 +0x0000CBFA 0x7E6D # 0 +0x0000CBFB 0x9EBF # 0 +0x0000CBFC 0x4E07 # 0 +0x0000CBFD 0x6162 # 0 +0x0000CBFE 0x6E80 # 0 +0x0000CCA1 0x6F2B # 0 +0x0000CCA2 0x8513 # 0 +0x0000CCA3 0x5473 # 0 +0x0000CCA4 0x672A # 0 +0x0000CCA5 0x9B45 # 0 +0x0000CCA6 0x5DF3 # 0 +0x0000CCA7 0x7B95 # 0 +0x0000CCA8 0x5CAC # 0 +0x0000CCA9 0x5BC6 # 0 +0x0000CCAA 0x871C # 0 +0x0000CCAB 0x6E4A # 0 +0x0000CCAC 0x84D1 # 0 +0x0000CCAD 0x7A14 # 0 +0x0000CCAE 0x8108 # 0 +0x0000CCAF 0x5999 # 0 +0x0000CCB0 0x7C8D # 0 +0x0000CCB1 0x6C11 # 0 +0x0000CCB2 0x7720 # 0 +0x0000CCB3 0x52D9 # 0 +0x0000CCB4 0x5922 # 0 +0x0000CCB5 0x7121 # 0 +0x0000CCB6 0x725F # 0 +0x0000CCB7 0x77DB # 0 +0x0000CCB8 0x9727 # 0 +0x0000CCB9 0x9D61 # 0 +0x0000CCBA 0x690B # 0 +0x0000CCBB 0x5A7F # 0 +0x0000CCBC 0x5A18 # 0 +0x0000CCBD 0x51A5 # 0 +0x0000CCBE 0x540D # 0 +0x0000CCBF 0x547D # 0 +0x0000CCC0 0x660E # 0 +0x0000CCC1 0x76DF # 0 +0x0000CCC2 0x8FF7 # 0 +0x0000CCC3 0x9298 # 0 +0x0000CCC4 0x9CF4 # 0 +0x0000CCC5 0x59EA # 0 +0x0000CCC6 0x725D # 0 +0x0000CCC7 0x6EC5 # 0 +0x0000CCC8 0x514D # 0 +0x0000CCC9 0x68C9 # 0 +0x0000CCCA 0x7DBF # 0 +0x0000CCCB 0x7DEC # 0 +0x0000CCCC 0x9762 # 0 +0x0000CCCD 0x9EBA # 0 +0x0000CCCE 0x6478 # 0 +0x0000CCCF 0x6A21 # 0 +0x0000CCD0 0x8302 # 0 +0x0000CCD1 0x5984 # 0 +0x0000CCD2 0x5B5F # 0 +0x0000CCD3 0x6BDB # 0 +0x0000CCD4 0x731B # 0 +0x0000CCD5 0x76F2 # 0 +0x0000CCD6 0x7DB2 # 0 +0x0000CCD7 0x8017 # 0 +0x0000CCD8 0x8499 # 0 +0x0000CCD9 0x5132 # 0 +0x0000CCDA 0x6728 # 0 +0x0000CCDB 0x9ED9 # 0 +0x0000CCDC 0x76EE # 0 +0x0000CCDD 0x6762 # 0 +0x0000CCDE 0x52FF # 0 +0x0000CCDF 0x9905 # 0 +0x0000CCE0 0x5C24 # 0 +0x0000CCE1 0x623B # 0 +0x0000CCE2 0x7C7E # 0 +0x0000CCE3 0x8CB0 # 0 +0x0000CCE4 0x554F # 0 +0x0000CCE5 0x60B6 # 0 +0x0000CCE6 0x7D0B # 0 +0x0000CCE7 0x9580 # 0 +0x0000CCE8 0x5301 # 0 +0x0000CCE9 0x4E5F # 0 +0x0000CCEA 0x51B6 # 0 +0x0000CCEB 0x591C # 0 +0x0000CCEC 0x723A # 0 +0x0000CCED 0x8036 # 0 +0x0000CCEE 0x91CE # 0 +0x0000CCEF 0x5F25 # 0 +0x0000CCF0 0x77E2 # 0 +0x0000CCF1 0x5384 # 0 +0x0000CCF2 0x5F79 # 0 +0x0000CCF3 0x7D04 # 0 +0x0000CCF4 0x85AC # 0 +0x0000CCF5 0x8A33 # 0 +0x0000CCF6 0x8E8D # 0 +0x0000CCF7 0x9756 # 0 +0x0000CCF8 0x67F3 # 0 +0x0000CCF9 0x85AE # 0 +0x0000CCFA 0x9453 # 0 +0x0000CCFB 0x6109 # 0 +0x0000CCFC 0x6108 # 0 +0x0000CCFD 0x6CB9 # 0 +0x0000CCFE 0x7652 # 0 +0x0000CDA1 0x8AED # 0 +0x0000CDA2 0x8F38 # 0 +0x0000CDA3 0x552F # 0 +0x0000CDA4 0x4F51 # 0 +0x0000CDA5 0x512A # 0 +0x0000CDA6 0x52C7 # 0 +0x0000CDA7 0x53CB # 0 +0x0000CDA8 0x5BA5 # 0 +0x0000CDA9 0x5E7D # 0 +0x0000CDAA 0x60A0 # 0 +0x0000CDAB 0x6182 # 0 +0x0000CDAC 0x63D6 # 0 +0x0000CDAD 0x6709 # 0 +0x0000CDAE 0x67DA # 0 +0x0000CDAF 0x6E67 # 0 +0x0000CDB0 0x6D8C # 0 +0x0000CDB1 0x7336 # 0 +0x0000CDB2 0x7337 # 0 +0x0000CDB3 0x7531 # 0 +0x0000CDB4 0x7950 # 0 +0x0000CDB5 0x88D5 # 0 +0x0000CDB6 0x8A98 # 0 +0x0000CDB7 0x904A # 0 +0x0000CDB8 0x9091 # 0 +0x0000CDB9 0x90F5 # 0 +0x0000CDBA 0x96C4 # 0 +0x0000CDBB 0x878D # 0 +0x0000CDBC 0x5915 # 0 +0x0000CDBD 0x4E88 # 0 +0x0000CDBE 0x4F59 # 0 +0x0000CDBF 0x4E0E # 0 +0x0000CDC0 0x8A89 # 0 +0x0000CDC1 0x8F3F # 0 +0x0000CDC2 0x9810 # 0 +0x0000CDC3 0x50AD # 0 +0x0000CDC4 0x5E7C # 0 +0x0000CDC5 0x5996 # 0 +0x0000CDC6 0x5BB9 # 0 +0x0000CDC7 0x5EB8 # 0 +0x0000CDC8 0x63DA # 0 +0x0000CDC9 0x63FA # 0 +0x0000CDCA 0x64C1 # 0 +0x0000CDCB 0x66DC # 0 +0x0000CDCC 0x694A # 0 +0x0000CDCD 0x69D8 # 0 +0x0000CDCE 0x6D0B # 0 +0x0000CDCF 0x6EB6 # 0 +0x0000CDD0 0x7194 # 0 +0x0000CDD1 0x7528 # 0 +0x0000CDD2 0x7AAF # 0 +0x0000CDD3 0x7F8A # 0 +0x0000CDD4 0x8000 # 0 +0x0000CDD5 0x8449 # 0 +0x0000CDD6 0x84C9 # 0 +0x0000CDD7 0x8981 # 0 +0x0000CDD8 0x8B21 # 0 +0x0000CDD9 0x8E0A # 0 +0x0000CDDA 0x9065 # 0 +0x0000CDDB 0x967D # 0 +0x0000CDDC 0x990A # 0 +0x0000CDDD 0x617E # 0 +0x0000CDDE 0x6291 # 0 +0x0000CDDF 0x6B32 # 0 +0x0000CDE0 0x6C83 # 0 +0x0000CDE1 0x6D74 # 0 +0x0000CDE2 0x7FCC # 0 +0x0000CDE3 0x7FFC # 0 +0x0000CDE4 0x6DC0 # 0 +0x0000CDE5 0x7F85 # 0 +0x0000CDE6 0x87BA # 0 +0x0000CDE7 0x88F8 # 0 +0x0000CDE8 0x6765 # 0 +0x0000CDE9 0x83B1 # 0 +0x0000CDEA 0x983C # 0 +0x0000CDEB 0x96F7 # 0 +0x0000CDEC 0x6D1B # 0 +0x0000CDED 0x7D61 # 0 +0x0000CDEE 0x843D # 0 +0x0000CDEF 0x916A # 0 +0x0000CDF0 0x4E71 # 0 +0x0000CDF1 0x5375 # 0 +0x0000CDF2 0x5D50 # 0 +0x0000CDF3 0x6B04 # 0 +0x0000CDF4 0x6FEB # 0 +0x0000CDF5 0x85CD # 0 +0x0000CDF6 0x862D # 0 +0x0000CDF7 0x89A7 # 0 +0x0000CDF8 0x5229 # 0 +0x0000CDF9 0x540F # 0 +0x0000CDFA 0x5C65 # 0 +0x0000CDFB 0x674E # 0 +0x0000CDFC 0x68A8 # 0 +0x0000CDFD 0x7406 # 0 +0x0000CDFE 0x7483 # 0 +0x0000CEA1 0x75E2 # 0 +0x0000CEA2 0x88CF # 0 +0x0000CEA3 0x88E1 # 0 +0x0000CEA4 0x91CC # 0 +0x0000CEA5 0x96E2 # 0 +0x0000CEA6 0x9678 # 0 +0x0000CEA7 0x5F8B # 0 +0x0000CEA8 0x7387 # 0 +0x0000CEA9 0x7ACB # 0 +0x0000CEAA 0x844E # 0 +0x0000CEAB 0x63A0 # 0 +0x0000CEAC 0x7565 # 0 +0x0000CEAD 0x5289 # 0 +0x0000CEAE 0x6D41 # 0 +0x0000CEAF 0x6E9C # 0 +0x0000CEB0 0x7409 # 0 +0x0000CEB1 0x7559 # 0 +0x0000CEB2 0x786B # 0 +0x0000CEB3 0x7C92 # 0 +0x0000CEB4 0x9686 # 0 +0x0000CEB5 0x7ADC # 0 +0x0000CEB6 0x9F8D # 0 +0x0000CEB7 0x4FB6 # 0 +0x0000CEB8 0x616E # 0 +0x0000CEB9 0x65C5 # 0 +0x0000CEBA 0x865C # 0 +0x0000CEBB 0x4E86 # 0 +0x0000CEBC 0x4EAE # 0 +0x0000CEBD 0x50DA # 0 +0x0000CEBE 0x4E21 # 0 +0x0000CEBF 0x51CC # 0 +0x0000CEC0 0x5BEE # 0 +0x0000CEC1 0x6599 # 0 +0x0000CEC2 0x6881 # 0 +0x0000CEC3 0x6DBC # 0 +0x0000CEC4 0x731F # 0 +0x0000CEC5 0x7642 # 0 +0x0000CEC6 0x77AD # 0 +0x0000CEC7 0x7A1C # 0 +0x0000CEC8 0x7CE7 # 0 +0x0000CEC9 0x826F # 0 +0x0000CECA 0x8AD2 # 0 +0x0000CECB 0x907C # 0 +0x0000CECC 0x91CF # 0 +0x0000CECD 0x9675 # 0 +0x0000CECE 0x9818 # 0 +0x0000CECF 0x529B # 0 +0x0000CED0 0x7DD1 # 0 +0x0000CED1 0x502B # 0 +0x0000CED2 0x5398 # 0 +0x0000CED3 0x6797 # 0 +0x0000CED4 0x6DCB # 0 +0x0000CED5 0x71D0 # 0 +0x0000CED6 0x7433 # 0 +0x0000CED7 0x81E8 # 0 +0x0000CED8 0x8F2A # 0 +0x0000CED9 0x96A3 # 0 +0x0000CEDA 0x9C57 # 0 +0x0000CEDB 0x9E9F # 0 +0x0000CEDC 0x7460 # 0 +0x0000CEDD 0x5841 # 0 +0x0000CEDE 0x6D99 # 0 +0x0000CEDF 0x7D2F # 0 +0x0000CEE0 0x985E # 0 +0x0000CEE1 0x4EE4 # 0 +0x0000CEE2 0x4F36 # 0 +0x0000CEE3 0x4F8B # 0 +0x0000CEE4 0x51B7 # 0 +0x0000CEE5 0x52B1 # 0 +0x0000CEE6 0x5DBA # 0 +0x0000CEE7 0x601C # 0 +0x0000CEE8 0x73B2 # 0 +0x0000CEE9 0x793C # 0 +0x0000CEEA 0x82D3 # 0 +0x0000CEEB 0x9234 # 0 +0x0000CEEC 0x96B7 # 0 +0x0000CEED 0x96F6 # 0 +0x0000CEEE 0x970A # 0 +0x0000CEEF 0x9E97 # 0 +0x0000CEF0 0x9F62 # 0 +0x0000CEF1 0x66A6 # 0 +0x0000CEF2 0x6B74 # 0 +0x0000CEF3 0x5217 # 0 +0x0000CEF4 0x52A3 # 0 +0x0000CEF5 0x70C8 # 0 +0x0000CEF6 0x88C2 # 0 +0x0000CEF7 0x5EC9 # 0 +0x0000CEF8 0x604B # 0 +0x0000CEF9 0x6190 # 0 +0x0000CEFA 0x6F23 # 0 +0x0000CEFB 0x7149 # 0 +0x0000CEFC 0x7C3E # 0 +0x0000CEFD 0x7DF4 # 0 +0x0000CEFE 0x806F # 0 +0x0000CFA1 0x84EE # 0 +0x0000CFA2 0x9023 # 0 +0x0000CFA3 0x932C # 0 +0x0000CFA4 0x5442 # 0 +0x0000CFA5 0x9B6F # 0 +0x0000CFA6 0x6AD3 # 0 +0x0000CFA7 0x7089 # 0 +0x0000CFA8 0x8CC2 # 0 +0x0000CFA9 0x8DEF # 0 +0x0000CFAA 0x9732 # 0 +0x0000CFAB 0x52B4 # 0 +0x0000CFAC 0x5A41 # 0 +0x0000CFAD 0x5ECA # 0 +0x0000CFAE 0x5F04 # 0 +0x0000CFAF 0x6717 # 0 +0x0000CFB0 0x697C # 0 +0x0000CFB1 0x6994 # 0 +0x0000CFB2 0x6D6A # 0 +0x0000CFB3 0x6F0F # 0 +0x0000CFB4 0x7262 # 0 +0x0000CFB5 0x72FC # 0 +0x0000CFB6 0x7BED # 0 +0x0000CFB7 0x8001 # 0 +0x0000CFB8 0x807E # 0 +0x0000CFB9 0x874B # 0 +0x0000CFBA 0x90CE # 0 +0x0000CFBB 0x516D # 0 +0x0000CFBC 0x9E93 # 0 +0x0000CFBD 0x7984 # 0 +0x0000CFBE 0x808B # 0 +0x0000CFBF 0x9332 # 0 +0x0000CFC0 0x8AD6 # 0 +0x0000CFC1 0x502D # 0 +0x0000CFC2 0x548C # 0 +0x0000CFC3 0x8A71 # 0 +0x0000CFC4 0x6B6A # 0 +0x0000CFC5 0x8CC4 # 0 +0x0000CFC6 0x8107 # 0 +0x0000CFC7 0x60D1 # 0 +0x0000CFC8 0x67A0 # 0 +0x0000CFC9 0x9DF2 # 0 +0x0000CFCA 0x4E99 # 0 +0x0000CFCB 0x4E98 # 0 +0x0000CFCC 0x9C10 # 0 +0x0000CFCD 0x8A6B # 0 +0x0000CFCE 0x85C1 # 0 +0x0000CFCF 0x8568 # 0 +0x0000CFD0 0x6900 # 0 +0x0000CFD1 0x6E7E # 0 +0x0000CFD2 0x7897 # 0 +0x0000CFD3 0x8155 # 0 +0x0000D0A1 0x5F0C # 0 +0x0000D0A2 0x4E10 # 0 +0x0000D0A3 0x4E15 # 0 +0x0000D0A4 0x4E2A # 0 +0x0000D0A5 0x4E31 # 0 +0x0000D0A6 0x4E36 # 0 +0x0000D0A7 0x4E3C # 0 +0x0000D0A8 0x4E3F # 0 +0x0000D0A9 0x4E42 # 0 +0x0000D0AA 0x4E56 # 0 +0x0000D0AB 0x4E58 # 0 +0x0000D0AC 0x4E82 # 0 +0x0000D0AD 0x4E85 # 0 +0x0000D0AE 0x8C6B # 0 +0x0000D0AF 0x4E8A # 0 +0x0000D0B0 0x8212 # 0 +0x0000D0B1 0x5F0D # 0 +0x0000D0B2 0x4E8E # 0 +0x0000D0B3 0x4E9E # 0 +0x0000D0B4 0x4E9F # 0 +0x0000D0B5 0x4EA0 # 0 +0x0000D0B6 0x4EA2 # 0 +0x0000D0B7 0x4EB0 # 0 +0x0000D0B8 0x4EB3 # 0 +0x0000D0B9 0x4EB6 # 0 +0x0000D0BA 0x4ECE # 0 +0x0000D0BB 0x4ECD # 0 +0x0000D0BC 0x4EC4 # 0 +0x0000D0BD 0x4EC6 # 0 +0x0000D0BE 0x4EC2 # 0 +0x0000D0BF 0x4ED7 # 0 +0x0000D0C0 0x4EDE # 0 +0x0000D0C1 0x4EED # 0 +0x0000D0C2 0x4EDF # 0 +0x0000D0C3 0x4EF7 # 0 +0x0000D0C4 0x4F09 # 0 +0x0000D0C5 0x4F5A # 0 +0x0000D0C6 0x4F30 # 0 +0x0000D0C7 0x4F5B # 0 +0x0000D0C8 0x4F5D # 0 +0x0000D0C9 0x4F57 # 0 +0x0000D0CA 0x4F47 # 0 +0x0000D0CB 0x4F76 # 0 +0x0000D0CC 0x4F88 # 0 +0x0000D0CD 0x4F8F # 0 +0x0000D0CE 0x4F98 # 0 +0x0000D0CF 0x4F7B # 0 +0x0000D0D0 0x4F69 # 0 +0x0000D0D1 0x4F70 # 0 +0x0000D0D2 0x4F91 # 0 +0x0000D0D3 0x4F6F # 0 +0x0000D0D4 0x4F86 # 0 +0x0000D0D5 0x4F96 # 0 +0x0000D0D6 0x5118 # 0 +0x0000D0D7 0x4FD4 # 0 +0x0000D0D8 0x4FDF # 0 +0x0000D0D9 0x4FCE # 0 +0x0000D0DA 0x4FD8 # 0 +0x0000D0DB 0x4FDB # 0 +0x0000D0DC 0x4FD1 # 0 +0x0000D0DD 0x4FDA # 0 +0x0000D0DE 0x4FD0 # 0 +0x0000D0DF 0x4FE4 # 0 +0x0000D0E0 0x4FE5 # 0 +0x0000D0E1 0x501A # 0 +0x0000D0E2 0x5028 # 0 +0x0000D0E3 0x5014 # 0 +0x0000D0E4 0x502A # 0 +0x0000D0E5 0x5025 # 0 +0x0000D0E6 0x5005 # 0 +0x0000D0E7 0x4F1C # 0 +0x0000D0E8 0x4FF6 # 0 +0x0000D0E9 0x5021 # 0 +0x0000D0EA 0x5029 # 0 +0x0000D0EB 0x502C # 0 +0x0000D0EC 0x4FFE # 0 +0x0000D0ED 0x4FEF # 0 +0x0000D0EE 0x5011 # 0 +0x0000D0EF 0x5006 # 0 +0x0000D0F0 0x5043 # 0 +0x0000D0F1 0x5047 # 0 +0x0000D0F2 0x6703 # 0 +0x0000D0F3 0x5055 # 0 +0x0000D0F4 0x5050 # 0 +0x0000D0F5 0x5048 # 0 +0x0000D0F6 0x505A # 0 +0x0000D0F7 0x5056 # 0 +0x0000D0F8 0x506C # 0 +0x0000D0F9 0x5078 # 0 +0x0000D0FA 0x5080 # 0 +0x0000D0FB 0x509A # 0 +0x0000D0FC 0x5085 # 0 +0x0000D0FD 0x50B4 # 0 +0x0000D0FE 0x50B2 # 0 +0x0000D1A1 0x50C9 # 0 +0x0000D1A2 0x50CA # 0 +0x0000D1A3 0x50B3 # 0 +0x0000D1A4 0x50C2 # 0 +0x0000D1A5 0x50D6 # 0 +0x0000D1A6 0x50DE # 0 +0x0000D1A7 0x50E5 # 0 +0x0000D1A8 0x50ED # 0 +0x0000D1A9 0x50E3 # 0 +0x0000D1AA 0x50EE # 0 +0x0000D1AB 0x50F9 # 0 +0x0000D1AC 0x50F5 # 0 +0x0000D1AD 0x5109 # 0 +0x0000D1AE 0x5101 # 0 +0x0000D1AF 0x5102 # 0 +0x0000D1B0 0x5116 # 0 +0x0000D1B1 0x5115 # 0 +0x0000D1B2 0x5114 # 0 +0x0000D1B3 0x511A # 0 +0x0000D1B4 0x5121 # 0 +0x0000D1B5 0x513A # 0 +0x0000D1B6 0x5137 # 0 +0x0000D1B7 0x513C # 0 +0x0000D1B8 0x513B # 0 +0x0000D1B9 0x513F # 0 +0x0000D1BA 0x5140 # 0 +0x0000D1BB 0x5152 # 0 +0x0000D1BC 0x514C # 0 +0x0000D1BD 0x5154 # 0 +0x0000D1BE 0x5162 # 0 +0x0000D1BF 0x7AF8 # 0 +0x0000D1C0 0x5169 # 0 +0x0000D1C1 0x516A # 0 +0x0000D1C2 0x516E # 0 +0x0000D1C3 0x5180 # 0 +0x0000D1C4 0x5182 # 0 +0x0000D1C5 0x56D8 # 0 +0x0000D1C6 0x518C # 0 +0x0000D1C7 0x5189 # 0 +0x0000D1C8 0x518F # 0 +0x0000D1C9 0x5191 # 0 +0x0000D1CA 0x5193 # 0 +0x0000D1CB 0x5195 # 0 +0x0000D1CC 0x5196 # 0 +0x0000D1CD 0x51A4 # 0 +0x0000D1CE 0x51A6 # 0 +0x0000D1CF 0x51A2 # 0 +0x0000D1D0 0x51A9 # 0 +0x0000D1D1 0x51AA # 0 +0x0000D1D2 0x51AB # 0 +0x0000D1D3 0x51B3 # 0 +0x0000D1D4 0x51B1 # 0 +0x0000D1D5 0x51B2 # 0 +0x0000D1D6 0x51B0 # 0 +0x0000D1D7 0x51B5 # 0 +0x0000D1D8 0x51BD # 0 +0x0000D1D9 0x51C5 # 0 +0x0000D1DA 0x51C9 # 0 +0x0000D1DB 0x51DB # 0 +0x0000D1DC 0x51E0 # 0 +0x0000D1DD 0x8655 # 0 +0x0000D1DE 0x51E9 # 0 +0x0000D1DF 0x51ED # 0 +0x0000D1E0 0x51F0 # 0 +0x0000D1E1 0x51F5 # 0 +0x0000D1E2 0x51FE # 0 +0x0000D1E3 0x5204 # 0 +0x0000D1E4 0x520B # 0 +0x0000D1E5 0x5214 # 0 +0x0000D1E6 0x520E # 0 +0x0000D1E7 0x5227 # 0 +0x0000D1E8 0x522A # 0 +0x0000D1E9 0x522E # 0 +0x0000D1EA 0x5233 # 0 +0x0000D1EB 0x5239 # 0 +0x0000D1EC 0x524F # 0 +0x0000D1ED 0x5244 # 0 +0x0000D1EE 0x524B # 0 +0x0000D1EF 0x524C # 0 +0x0000D1F0 0x525E # 0 +0x0000D1F1 0x5254 # 0 +0x0000D1F2 0x526A # 0 +0x0000D1F3 0x5274 # 0 +0x0000D1F4 0x5269 # 0 +0x0000D1F5 0x5273 # 0 +0x0000D1F6 0x527F # 0 +0x0000D1F7 0x527D # 0 +0x0000D1F8 0x528D # 0 +0x0000D1F9 0x5294 # 0 +0x0000D1FA 0x5292 # 0 +0x0000D1FB 0x5271 # 0 +0x0000D1FC 0x5288 # 0 +0x0000D1FD 0x5291 # 0 +0x0000D1FE 0x8FA8 # 0 +0x0000D2A1 0x8FA7 # 0 +0x0000D2A2 0x52AC # 0 +0x0000D2A3 0x52AD # 0 +0x0000D2A4 0x52BC # 0 +0x0000D2A5 0x52B5 # 0 +0x0000D2A6 0x52C1 # 0 +0x0000D2A7 0x52CD # 0 +0x0000D2A8 0x52D7 # 0 +0x0000D2A9 0x52DE # 0 +0x0000D2AA 0x52E3 # 0 +0x0000D2AB 0x52E6 # 0 +0x0000D2AC 0x98ED # 0 +0x0000D2AD 0x52E0 # 0 +0x0000D2AE 0x52F3 # 0 +0x0000D2AF 0x52F5 # 0 +0x0000D2B0 0x52F8 # 0 +0x0000D2B1 0x52F9 # 0 +0x0000D2B2 0x5306 # 0 +0x0000D2B3 0x5308 # 0 +0x0000D2B4 0x7538 # 0 +0x0000D2B5 0x530D # 0 +0x0000D2B6 0x5310 # 0 +0x0000D2B7 0x530F # 0 +0x0000D2B8 0x5315 # 0 +0x0000D2B9 0x531A # 0 +0x0000D2BA 0x5323 # 0 +0x0000D2BB 0x532F # 0 +0x0000D2BC 0x5331 # 0 +0x0000D2BD 0x5333 # 0 +0x0000D2BE 0x5338 # 0 +0x0000D2BF 0x5340 # 0 +0x0000D2C0 0x5346 # 0 +0x0000D2C1 0x5345 # 0 +0x0000D2C2 0x4E17 # 0 +0x0000D2C3 0x5349 # 0 +0x0000D2C4 0x534D # 0 +0x0000D2C5 0x51D6 # 0 +0x0000D2C6 0x535E # 0 +0x0000D2C7 0x5369 # 0 +0x0000D2C8 0x536E # 0 +0x0000D2C9 0x5918 # 0 +0x0000D2CA 0x537B # 0 +0x0000D2CB 0x5377 # 0 +0x0000D2CC 0x5382 # 0 +0x0000D2CD 0x5396 # 0 +0x0000D2CE 0x53A0 # 0 +0x0000D2CF 0x53A6 # 0 +0x0000D2D0 0x53A5 # 0 +0x0000D2D1 0x53AE # 0 +0x0000D2D2 0x53B0 # 0 +0x0000D2D3 0x53B6 # 0 +0x0000D2D4 0x53C3 # 0 +0x0000D2D5 0x7C12 # 0 +0x0000D2D6 0x96D9 # 0 +0x0000D2D7 0x53DF # 0 +0x0000D2D8 0x66FC # 0 +0x0000D2D9 0x71EE # 0 +0x0000D2DA 0x53EE # 0 +0x0000D2DB 0x53E8 # 0 +0x0000D2DC 0x53ED # 0 +0x0000D2DD 0x53FA # 0 +0x0000D2DE 0x5401 # 0 +0x0000D2DF 0x543D # 0 +0x0000D2E0 0x5440 # 0 +0x0000D2E1 0x542C # 0 +0x0000D2E2 0x542D # 0 +0x0000D2E3 0x543C # 0 +0x0000D2E4 0x542E # 0 +0x0000D2E5 0x5436 # 0 +0x0000D2E6 0x5429 # 0 +0x0000D2E7 0x541D # 0 +0x0000D2E8 0x544E # 0 +0x0000D2E9 0x548F # 0 +0x0000D2EA 0x5475 # 0 +0x0000D2EB 0x548E # 0 +0x0000D2EC 0x545F # 0 +0x0000D2ED 0x5471 # 0 +0x0000D2EE 0x5477 # 0 +0x0000D2EF 0x5470 # 0 +0x0000D2F0 0x5492 # 0 +0x0000D2F1 0x547B # 0 +0x0000D2F2 0x5480 # 0 +0x0000D2F3 0x5476 # 0 +0x0000D2F4 0x5484 # 0 +0x0000D2F5 0x5490 # 0 +0x0000D2F6 0x5486 # 0 +0x0000D2F7 0x54C7 # 0 +0x0000D2F8 0x54A2 # 0 +0x0000D2F9 0x54B8 # 0 +0x0000D2FA 0x54A5 # 0 +0x0000D2FB 0x54AC # 0 +0x0000D2FC 0x54C4 # 0 +0x0000D2FD 0x54C8 # 0 +0x0000D2FE 0x54A8 # 0 +0x0000D3A1 0x54AB # 0 +0x0000D3A2 0x54C2 # 0 +0x0000D3A3 0x54A4 # 0 +0x0000D3A4 0x54BE # 0 +0x0000D3A5 0x54BC # 0 +0x0000D3A6 0x54D8 # 0 +0x0000D3A7 0x54E5 # 0 +0x0000D3A8 0x54E6 # 0 +0x0000D3A9 0x550F # 0 +0x0000D3AA 0x5514 # 0 +0x0000D3AB 0x54FD # 0 +0x0000D3AC 0x54EE # 0 +0x0000D3AD 0x54ED # 0 +0x0000D3AE 0x54FA # 0 +0x0000D3AF 0x54E2 # 0 +0x0000D3B0 0x5539 # 0 +0x0000D3B1 0x5540 # 0 +0x0000D3B2 0x5563 # 0 +0x0000D3B3 0x554C # 0 +0x0000D3B4 0x552E # 0 +0x0000D3B5 0x555C # 0 +0x0000D3B6 0x5545 # 0 +0x0000D3B7 0x5556 # 0 +0x0000D3B8 0x5557 # 0 +0x0000D3B9 0x5538 # 0 +0x0000D3BA 0x5533 # 0 +0x0000D3BB 0x555D # 0 +0x0000D3BC 0x5599 # 0 +0x0000D3BD 0x5580 # 0 +0x0000D3BE 0x54AF # 0 +0x0000D3BF 0x558A # 0 +0x0000D3C0 0x559F # 0 +0x0000D3C1 0x557B # 0 +0x0000D3C2 0x557E # 0 +0x0000D3C3 0x5598 # 0 +0x0000D3C4 0x559E # 0 +0x0000D3C5 0x55AE # 0 +0x0000D3C6 0x557C # 0 +0x0000D3C7 0x5583 # 0 +0x0000D3C8 0x55A9 # 0 +0x0000D3C9 0x5587 # 0 +0x0000D3CA 0x55A8 # 0 +0x0000D3CB 0x55DA # 0 +0x0000D3CC 0x55C5 # 0 +0x0000D3CD 0x55DF # 0 +0x0000D3CE 0x55C4 # 0 +0x0000D3CF 0x55DC # 0 +0x0000D3D0 0x55E4 # 0 +0x0000D3D1 0x55D4 # 0 +0x0000D3D2 0x5614 # 0 +0x0000D3D3 0x55F7 # 0 +0x0000D3D4 0x5616 # 0 +0x0000D3D5 0x55FE # 0 +0x0000D3D6 0x55FD # 0 +0x0000D3D7 0x561B # 0 +0x0000D3D8 0x55F9 # 0 +0x0000D3D9 0x564E # 0 +0x0000D3DA 0x5650 # 0 +0x0000D3DB 0x71DF # 0 +0x0000D3DC 0x5634 # 0 +0x0000D3DD 0x5636 # 0 +0x0000D3DE 0x5632 # 0 +0x0000D3DF 0x5638 # 0 +0x0000D3E0 0x566B # 0 +0x0000D3E1 0x5664 # 0 +0x0000D3E2 0x562F # 0 +0x0000D3E3 0x566C # 0 +0x0000D3E4 0x566A # 0 +0x0000D3E5 0x5686 # 0 +0x0000D3E6 0x5680 # 0 +0x0000D3E7 0x568A # 0 +0x0000D3E8 0x56A0 # 0 +0x0000D3E9 0x5694 # 0 +0x0000D3EA 0x568F # 0 +0x0000D3EB 0x56A5 # 0 +0x0000D3EC 0x56AE # 0 +0x0000D3ED 0x56B6 # 0 +0x0000D3EE 0x56B4 # 0 +0x0000D3EF 0x56C2 # 0 +0x0000D3F0 0x56BC # 0 +0x0000D3F1 0x56C1 # 0 +0x0000D3F2 0x56C3 # 0 +0x0000D3F3 0x56C0 # 0 +0x0000D3F4 0x56C8 # 0 +0x0000D3F5 0x56CE # 0 +0x0000D3F6 0x56D1 # 0 +0x0000D3F7 0x56D3 # 0 +0x0000D3F8 0x56D7 # 0 +0x0000D3F9 0x56EE # 0 +0x0000D3FA 0x56F9 # 0 +0x0000D3FB 0x5700 # 0 +0x0000D3FC 0x56FF # 0 +0x0000D3FD 0x5704 # 0 +0x0000D3FE 0x5709 # 0 +0x0000D4A1 0x5708 # 0 +0x0000D4A2 0x570B # 0 +0x0000D4A3 0x570D # 0 +0x0000D4A4 0x5713 # 0 +0x0000D4A5 0x5718 # 0 +0x0000D4A6 0x5716 # 0 +0x0000D4A7 0x55C7 # 0 +0x0000D4A8 0x571C # 0 +0x0000D4A9 0x5726 # 0 +0x0000D4AA 0x5737 # 0 +0x0000D4AB 0x5738 # 0 +0x0000D4AC 0x574E # 0 +0x0000D4AD 0x573B # 0 +0x0000D4AE 0x5740 # 0 +0x0000D4AF 0x574F # 0 +0x0000D4B0 0x5769 # 0 +0x0000D4B1 0x57C0 # 0 +0x0000D4B2 0x5788 # 0 +0x0000D4B3 0x5761 # 0 +0x0000D4B4 0x577F # 0 +0x0000D4B5 0x5789 # 0 +0x0000D4B6 0x5793 # 0 +0x0000D4B7 0x57A0 # 0 +0x0000D4B8 0x57B3 # 0 +0x0000D4B9 0x57A4 # 0 +0x0000D4BA 0x57AA # 0 +0x0000D4BB 0x57B0 # 0 +0x0000D4BC 0x57C3 # 0 +0x0000D4BD 0x57C6 # 0 +0x0000D4BE 0x57D4 # 0 +0x0000D4BF 0x57D2 # 0 +0x0000D4C0 0x57D3 # 0 +0x0000D4C1 0x580A # 0 +0x0000D4C2 0x57D6 # 0 +0x0000D4C3 0x57E3 # 0 +0x0000D4C4 0x580B # 0 +0x0000D4C5 0x5819 # 0 +0x0000D4C6 0x581D # 0 +0x0000D4C7 0x5872 # 0 +0x0000D4C8 0x5821 # 0 +0x0000D4C9 0x5862 # 0 +0x0000D4CA 0x584B # 0 +0x0000D4CB 0x5870 # 0 +0x0000D4CC 0x6BC0 # 0 +0x0000D4CD 0x5852 # 0 +0x0000D4CE 0x583D # 0 +0x0000D4CF 0x5879 # 0 +0x0000D4D0 0x5885 # 0 +0x0000D4D1 0x58B9 # 0 +0x0000D4D2 0x589F # 0 +0x0000D4D3 0x58AB # 0 +0x0000D4D4 0x58BA # 0 +0x0000D4D5 0x58DE # 0 +0x0000D4D6 0x58BB # 0 +0x0000D4D7 0x58B8 # 0 +0x0000D4D8 0x58AE # 0 +0x0000D4D9 0x58C5 # 0 +0x0000D4DA 0x58D3 # 0 +0x0000D4DB 0x58D1 # 0 +0x0000D4DC 0x58D7 # 0 +0x0000D4DD 0x58D9 # 0 +0x0000D4DE 0x58D8 # 0 +0x0000D4DF 0x58E5 # 0 +0x0000D4E0 0x58DC # 0 +0x0000D4E1 0x58E4 # 0 +0x0000D4E2 0x58DF # 0 +0x0000D4E3 0x58EF # 0 +0x0000D4E4 0x58FA # 0 +0x0000D4E5 0x58F9 # 0 +0x0000D4E6 0x58FB # 0 +0x0000D4E7 0x58FC # 0 +0x0000D4E8 0x58FD # 0 +0x0000D4E9 0x5902 # 0 +0x0000D4EA 0x590A # 0 +0x0000D4EB 0x5910 # 0 +0x0000D4EC 0x591B # 0 +0x0000D4ED 0x68A6 # 0 +0x0000D4EE 0x5925 # 0 +0x0000D4EF 0x592C # 0 +0x0000D4F0 0x592D # 0 +0x0000D4F1 0x5932 # 0 +0x0000D4F2 0x5938 # 0 +0x0000D4F3 0x593E # 0 +0x0000D4F4 0x7AD2 # 0 +0x0000D4F5 0x5955 # 0 +0x0000D4F6 0x5950 # 0 +0x0000D4F7 0x594E # 0 +0x0000D4F8 0x595A # 0 +0x0000D4F9 0x5958 # 0 +0x0000D4FA 0x5962 # 0 +0x0000D4FB 0x5960 # 0 +0x0000D4FC 0x5967 # 0 +0x0000D4FD 0x596C # 0 +0x0000D4FE 0x5969 # 0 +0x0000D5A1 0x5978 # 0 +0x0000D5A2 0x5981 # 0 +0x0000D5A3 0x599D # 0 +0x0000D5A4 0x4F5E # 0 +0x0000D5A5 0x4FAB # 0 +0x0000D5A6 0x59A3 # 0 +0x0000D5A7 0x59B2 # 0 +0x0000D5A8 0x59C6 # 0 +0x0000D5A9 0x59E8 # 0 +0x0000D5AA 0x59DC # 0 +0x0000D5AB 0x598D # 0 +0x0000D5AC 0x59D9 # 0 +0x0000D5AD 0x59DA # 0 +0x0000D5AE 0x5A25 # 0 +0x0000D5AF 0x5A1F # 0 +0x0000D5B0 0x5A11 # 0 +0x0000D5B1 0x5A1C # 0 +0x0000D5B2 0x5A09 # 0 +0x0000D5B3 0x5A1A # 0 +0x0000D5B4 0x5A40 # 0 +0x0000D5B5 0x5A6C # 0 +0x0000D5B6 0x5A49 # 0 +0x0000D5B7 0x5A35 # 0 +0x0000D5B8 0x5A36 # 0 +0x0000D5B9 0x5A62 # 0 +0x0000D5BA 0x5A6A # 0 +0x0000D5BB 0x5A9A # 0 +0x0000D5BC 0x5ABC # 0 +0x0000D5BD 0x5ABE # 0 +0x0000D5BE 0x5ACB # 0 +0x0000D5BF 0x5AC2 # 0 +0x0000D5C0 0x5ABD # 0 +0x0000D5C1 0x5AE3 # 0 +0x0000D5C2 0x5AD7 # 0 +0x0000D5C3 0x5AE6 # 0 +0x0000D5C4 0x5AE9 # 0 +0x0000D5C5 0x5AD6 # 0 +0x0000D5C6 0x5AFA # 0 +0x0000D5C7 0x5AFB # 0 +0x0000D5C8 0x5B0C # 0 +0x0000D5C9 0x5B0B # 0 +0x0000D5CA 0x5B16 # 0 +0x0000D5CB 0x5B32 # 0 +0x0000D5CC 0x5AD0 # 0 +0x0000D5CD 0x5B2A # 0 +0x0000D5CE 0x5B36 # 0 +0x0000D5CF 0x5B3E # 0 +0x0000D5D0 0x5B43 # 0 +0x0000D5D1 0x5B45 # 0 +0x0000D5D2 0x5B40 # 0 +0x0000D5D3 0x5B51 # 0 +0x0000D5D4 0x5B55 # 0 +0x0000D5D5 0x5B5A # 0 +0x0000D5D6 0x5B5B # 0 +0x0000D5D7 0x5B65 # 0 +0x0000D5D8 0x5B69 # 0 +0x0000D5D9 0x5B70 # 0 +0x0000D5DA 0x5B73 # 0 +0x0000D5DB 0x5B75 # 0 +0x0000D5DC 0x5B78 # 0 +0x0000D5DD 0x6588 # 0 +0x0000D5DE 0x5B7A # 0 +0x0000D5DF 0x5B80 # 0 +0x0000D5E0 0x5B83 # 0 +0x0000D5E1 0x5BA6 # 0 +0x0000D5E2 0x5BB8 # 0 +0x0000D5E3 0x5BC3 # 0 +0x0000D5E4 0x5BC7 # 0 +0x0000D5E5 0x5BC9 # 0 +0x0000D5E6 0x5BD4 # 0 +0x0000D5E7 0x5BD0 # 0 +0x0000D5E8 0x5BE4 # 0 +0x0000D5E9 0x5BE6 # 0 +0x0000D5EA 0x5BE2 # 0 +0x0000D5EB 0x5BDE # 0 +0x0000D5EC 0x5BE5 # 0 +0x0000D5ED 0x5BEB # 0 +0x0000D5EE 0x5BF0 # 0 +0x0000D5EF 0x5BF6 # 0 +0x0000D5F0 0x5BF3 # 0 +0x0000D5F1 0x5C05 # 0 +0x0000D5F2 0x5C07 # 0 +0x0000D5F3 0x5C08 # 0 +0x0000D5F4 0x5C0D # 0 +0x0000D5F5 0x5C13 # 0 +0x0000D5F6 0x5C20 # 0 +0x0000D5F7 0x5C22 # 0 +0x0000D5F8 0x5C28 # 0 +0x0000D5F9 0x5C38 # 0 +0x0000D5FA 0x5C39 # 0 +0x0000D5FB 0x5C41 # 0 +0x0000D5FC 0x5C46 # 0 +0x0000D5FD 0x5C4E # 0 +0x0000D5FE 0x5C53 # 0 +0x0000D6A1 0x5C50 # 0 +0x0000D6A2 0x5C4F # 0 +0x0000D6A3 0x5B71 # 0 +0x0000D6A4 0x5C6C # 0 +0x0000D6A5 0x5C6E # 0 +0x0000D6A6 0x4E62 # 0 +0x0000D6A7 0x5C76 # 0 +0x0000D6A8 0x5C79 # 0 +0x0000D6A9 0x5C8C # 0 +0x0000D6AA 0x5C91 # 0 +0x0000D6AB 0x5C94 # 0 +0x0000D6AC 0x599B # 0 +0x0000D6AD 0x5CAB # 0 +0x0000D6AE 0x5CBB # 0 +0x0000D6AF 0x5CB6 # 0 +0x0000D6B0 0x5CBC # 0 +0x0000D6B1 0x5CB7 # 0 +0x0000D6B2 0x5CC5 # 0 +0x0000D6B3 0x5CBE # 0 +0x0000D6B4 0x5CC7 # 0 +0x0000D6B5 0x5CD9 # 0 +0x0000D6B6 0x5CE9 # 0 +0x0000D6B7 0x5CFD # 0 +0x0000D6B8 0x5CFA # 0 +0x0000D6B9 0x5CED # 0 +0x0000D6BA 0x5D8C # 0 +0x0000D6BB 0x5CEA # 0 +0x0000D6BC 0x5D0B # 0 +0x0000D6BD 0x5D15 # 0 +0x0000D6BE 0x5D17 # 0 +0x0000D6BF 0x5D5C # 0 +0x0000D6C0 0x5D1F # 0 +0x0000D6C1 0x5D1B # 0 +0x0000D6C2 0x5D11 # 0 +0x0000D6C3 0x5D14 # 0 +0x0000D6C4 0x5D22 # 0 +0x0000D6C5 0x5D1A # 0 +0x0000D6C6 0x5D19 # 0 +0x0000D6C7 0x5D18 # 0 +0x0000D6C8 0x5D4C # 0 +0x0000D6C9 0x5D52 # 0 +0x0000D6CA 0x5D4E # 0 +0x0000D6CB 0x5D4B # 0 +0x0000D6CC 0x5D6C # 0 +0x0000D6CD 0x5D73 # 0 +0x0000D6CE 0x5D76 # 0 +0x0000D6CF 0x5D87 # 0 +0x0000D6D0 0x5D84 # 0 +0x0000D6D1 0x5D82 # 0 +0x0000D6D2 0x5DA2 # 0 +0x0000D6D3 0x5D9D # 0 +0x0000D6D4 0x5DAC # 0 +0x0000D6D5 0x5DAE # 0 +0x0000D6D6 0x5DBD # 0 +0x0000D6D7 0x5D90 # 0 +0x0000D6D8 0x5DB7 # 0 +0x0000D6D9 0x5DBC # 0 +0x0000D6DA 0x5DC9 # 0 +0x0000D6DB 0x5DCD # 0 +0x0000D6DC 0x5DD3 # 0 +0x0000D6DD 0x5DD2 # 0 +0x0000D6DE 0x5DD6 # 0 +0x0000D6DF 0x5DDB # 0 +0x0000D6E0 0x5DEB # 0 +0x0000D6E1 0x5DF2 # 0 +0x0000D6E2 0x5DF5 # 0 +0x0000D6E3 0x5E0B # 0 +0x0000D6E4 0x5E1A # 0 +0x0000D6E5 0x5E19 # 0 +0x0000D6E6 0x5E11 # 0 +0x0000D6E7 0x5E1B # 0 +0x0000D6E8 0x5E36 # 0 +0x0000D6E9 0x5E37 # 0 +0x0000D6EA 0x5E44 # 0 +0x0000D6EB 0x5E43 # 0 +0x0000D6EC 0x5E40 # 0 +0x0000D6ED 0x5E4E # 0 +0x0000D6EE 0x5E57 # 0 +0x0000D6EF 0x5E54 # 0 +0x0000D6F0 0x5E5F # 0 +0x0000D6F1 0x5E62 # 0 +0x0000D6F2 0x5E64 # 0 +0x0000D6F3 0x5E47 # 0 +0x0000D6F4 0x5E75 # 0 +0x0000D6F5 0x5E76 # 0 +0x0000D6F6 0x5E7A # 0 +0x0000D6F7 0x9EBC # 0 +0x0000D6F8 0x5E7F # 0 +0x0000D6F9 0x5EA0 # 0 +0x0000D6FA 0x5EC1 # 0 +0x0000D6FB 0x5EC2 # 0 +0x0000D6FC 0x5EC8 # 0 +0x0000D6FD 0x5ED0 # 0 +0x0000D6FE 0x5ECF # 0 +0x0000D7A1 0x5ED6 # 0 +0x0000D7A2 0x5EE3 # 0 +0x0000D7A3 0x5EDD # 0 +0x0000D7A4 0x5EDA # 0 +0x0000D7A5 0x5EDB # 0 +0x0000D7A6 0x5EE2 # 0 +0x0000D7A7 0x5EE1 # 0 +0x0000D7A8 0x5EE8 # 0 +0x0000D7A9 0x5EE9 # 0 +0x0000D7AA 0x5EEC # 0 +0x0000D7AB 0x5EF1 # 0 +0x0000D7AC 0x5EF3 # 0 +0x0000D7AD 0x5EF0 # 0 +0x0000D7AE 0x5EF4 # 0 +0x0000D7AF 0x5EF8 # 0 +0x0000D7B0 0x5EFE # 0 +0x0000D7B1 0x5F03 # 0 +0x0000D7B2 0x5F09 # 0 +0x0000D7B3 0x5F5D # 0 +0x0000D7B4 0x5F5C # 0 +0x0000D7B5 0x5F0B # 0 +0x0000D7B6 0x5F11 # 0 +0x0000D7B7 0x5F16 # 0 +0x0000D7B8 0x5F29 # 0 +0x0000D7B9 0x5F2D # 0 +0x0000D7BA 0x5F38 # 0 +0x0000D7BB 0x5F41 # 0 +0x0000D7BC 0x5F48 # 0 +0x0000D7BD 0x5F4C # 0 +0x0000D7BE 0x5F4E # 0 +0x0000D7BF 0x5F2F # 0 +0x0000D7C0 0x5F51 # 0 +0x0000D7C1 0x5F56 # 0 +0x0000D7C2 0x5F57 # 0 +0x0000D7C3 0x5F59 # 0 +0x0000D7C4 0x5F61 # 0 +0x0000D7C5 0x5F6D # 0 +0x0000D7C6 0x5F73 # 0 +0x0000D7C7 0x5F77 # 0 +0x0000D7C8 0x5F83 # 0 +0x0000D7C9 0x5F82 # 0 +0x0000D7CA 0x5F7F # 0 +0x0000D7CB 0x5F8A # 0 +0x0000D7CC 0x5F88 # 0 +0x0000D7CD 0x5F91 # 0 +0x0000D7CE 0x5F87 # 0 +0x0000D7CF 0x5F9E # 0 +0x0000D7D0 0x5F99 # 0 +0x0000D7D1 0x5F98 # 0 +0x0000D7D2 0x5FA0 # 0 +0x0000D7D3 0x5FA8 # 0 +0x0000D7D4 0x5FAD # 0 +0x0000D7D5 0x5FBC # 0 +0x0000D7D6 0x5FD6 # 0 +0x0000D7D7 0x5FFB # 0 +0x0000D7D8 0x5FE4 # 0 +0x0000D7D9 0x5FF8 # 0 +0x0000D7DA 0x5FF1 # 0 +0x0000D7DB 0x5FDD # 0 +0x0000D7DC 0x60B3 # 0 +0x0000D7DD 0x5FFF # 0 +0x0000D7DE 0x6021 # 0 +0x0000D7DF 0x6060 # 0 +0x0000D7E0 0x6019 # 0 +0x0000D7E1 0x6010 # 0 +0x0000D7E2 0x6029 # 0 +0x0000D7E3 0x600E # 0 +0x0000D7E4 0x6031 # 0 +0x0000D7E5 0x601B # 0 +0x0000D7E6 0x6015 # 0 +0x0000D7E7 0x602B # 0 +0x0000D7E8 0x6026 # 0 +0x0000D7E9 0x600F # 0 +0x0000D7EA 0x603A # 0 +0x0000D7EB 0x605A # 0 +0x0000D7EC 0x6041 # 0 +0x0000D7ED 0x606A # 0 +0x0000D7EE 0x6077 # 0 +0x0000D7EF 0x605F # 0 +0x0000D7F0 0x604A # 0 +0x0000D7F1 0x6046 # 0 +0x0000D7F2 0x604D # 0 +0x0000D7F3 0x6063 # 0 +0x0000D7F4 0x6043 # 0 +0x0000D7F5 0x6064 # 0 +0x0000D7F6 0x6042 # 0 +0x0000D7F7 0x606C # 0 +0x0000D7F8 0x606B # 0 +0x0000D7F9 0x6059 # 0 +0x0000D7FA 0x6081 # 0 +0x0000D7FB 0x608D # 0 +0x0000D7FC 0x60E7 # 0 +0x0000D7FD 0x6083 # 0 +0x0000D7FE 0x609A # 0 +0x0000D8A1 0x6084 # 0 +0x0000D8A2 0x609B # 0 +0x0000D8A3 0x6096 # 0 +0x0000D8A4 0x6097 # 0 +0x0000D8A5 0x6092 # 0 +0x0000D8A6 0x60A7 # 0 +0x0000D8A7 0x608B # 0 +0x0000D8A8 0x60E1 # 0 +0x0000D8A9 0x60B8 # 0 +0x0000D8AA 0x60E0 # 0 +0x0000D8AB 0x60D3 # 0 +0x0000D8AC 0x60B4 # 0 +0x0000D8AD 0x5FF0 # 0 +0x0000D8AE 0x60BD # 0 +0x0000D8AF 0x60C6 # 0 +0x0000D8B0 0x60B5 # 0 +0x0000D8B1 0x60D8 # 0 +0x0000D8B2 0x614D # 0 +0x0000D8B3 0x6115 # 0 +0x0000D8B4 0x6106 # 0 +0x0000D8B5 0x60F6 # 0 +0x0000D8B6 0x60F7 # 0 +0x0000D8B7 0x6100 # 0 +0x0000D8B8 0x60F4 # 0 +0x0000D8B9 0x60FA # 0 +0x0000D8BA 0x6103 # 0 +0x0000D8BB 0x6121 # 0 +0x0000D8BC 0x60FB # 0 +0x0000D8BD 0x60F1 # 0 +0x0000D8BE 0x610D # 0 +0x0000D8BF 0x610E # 0 +0x0000D8C0 0x6147 # 0 +0x0000D8C1 0x613E # 0 +0x0000D8C2 0x6128 # 0 +0x0000D8C3 0x6127 # 0 +0x0000D8C4 0x614A # 0 +0x0000D8C5 0x613F # 0 +0x0000D8C6 0x613C # 0 +0x0000D8C7 0x612C # 0 +0x0000D8C8 0x6134 # 0 +0x0000D8C9 0x613D # 0 +0x0000D8CA 0x6142 # 0 +0x0000D8CB 0x6144 # 0 +0x0000D8CC 0x6173 # 0 +0x0000D8CD 0x6177 # 0 +0x0000D8CE 0x6158 # 0 +0x0000D8CF 0x6159 # 0 +0x0000D8D0 0x615A # 0 +0x0000D8D1 0x616B # 0 +0x0000D8D2 0x6174 # 0 +0x0000D8D3 0x616F # 0 +0x0000D8D4 0x6165 # 0 +0x0000D8D5 0x6171 # 0 +0x0000D8D6 0x615F # 0 +0x0000D8D7 0x615D # 0 +0x0000D8D8 0x6153 # 0 +0x0000D8D9 0x6175 # 0 +0x0000D8DA 0x6199 # 0 +0x0000D8DB 0x6196 # 0 +0x0000D8DC 0x6187 # 0 +0x0000D8DD 0x61AC # 0 +0x0000D8DE 0x6194 # 0 +0x0000D8DF 0x619A # 0 +0x0000D8E0 0x618A # 0 +0x0000D8E1 0x6191 # 0 +0x0000D8E2 0x61AB # 0 +0x0000D8E3 0x61AE # 0 +0x0000D8E4 0x61CC # 0 +0x0000D8E5 0x61CA # 0 +0x0000D8E6 0x61C9 # 0 +0x0000D8E7 0x61F7 # 0 +0x0000D8E8 0x61C8 # 0 +0x0000D8E9 0x61C3 # 0 +0x0000D8EA 0x61C6 # 0 +0x0000D8EB 0x61BA # 0 +0x0000D8EC 0x61CB # 0 +0x0000D8ED 0x7F79 # 0 +0x0000D8EE 0x61CD # 0 +0x0000D8EF 0x61E6 # 0 +0x0000D8F0 0x61E3 # 0 +0x0000D8F1 0x61F6 # 0 +0x0000D8F2 0x61FA # 0 +0x0000D8F3 0x61F4 # 0 +0x0000D8F4 0x61FF # 0 +0x0000D8F5 0x61FD # 0 +0x0000D8F6 0x61FC # 0 +0x0000D8F7 0x61FE # 0 +0x0000D8F8 0x6200 # 0 +0x0000D8F9 0x6208 # 0 +0x0000D8FA 0x6209 # 0 +0x0000D8FB 0x620D # 0 +0x0000D8FC 0x620C # 0 +0x0000D8FD 0x6214 # 0 +0x0000D8FE 0x621B # 0 +0x0000D9A1 0x621E # 0 +0x0000D9A2 0x6221 # 0 +0x0000D9A3 0x622A # 0 +0x0000D9A4 0x622E # 0 +0x0000D9A5 0x6230 # 0 +0x0000D9A6 0x6232 # 0 +0x0000D9A7 0x6233 # 0 +0x0000D9A8 0x6241 # 0 +0x0000D9A9 0x624E # 0 +0x0000D9AA 0x625E # 0 +0x0000D9AB 0x6263 # 0 +0x0000D9AC 0x625B # 0 +0x0000D9AD 0x6260 # 0 +0x0000D9AE 0x6268 # 0 +0x0000D9AF 0x627C # 0 +0x0000D9B0 0x6282 # 0 +0x0000D9B1 0x6289 # 0 +0x0000D9B2 0x627E # 0 +0x0000D9B3 0x6292 # 0 +0x0000D9B4 0x6293 # 0 +0x0000D9B5 0x6296 # 0 +0x0000D9B6 0x62D4 # 0 +0x0000D9B7 0x6283 # 0 +0x0000D9B8 0x6294 # 0 +0x0000D9B9 0x62D7 # 0 +0x0000D9BA 0x62D1 # 0 +0x0000D9BB 0x62BB # 0 +0x0000D9BC 0x62CF # 0 +0x0000D9BD 0x62FF # 0 +0x0000D9BE 0x62C6 # 0 +0x0000D9BF 0x64D4 # 0 +0x0000D9C0 0x62C8 # 0 +0x0000D9C1 0x62DC # 0 +0x0000D9C2 0x62CC # 0 +0x0000D9C3 0x62CA # 0 +0x0000D9C4 0x62C2 # 0 +0x0000D9C5 0x62C7 # 0 +0x0000D9C6 0x629B # 0 +0x0000D9C7 0x62C9 # 0 +0x0000D9C8 0x630C # 0 +0x0000D9C9 0x62EE # 0 +0x0000D9CA 0x62F1 # 0 +0x0000D9CB 0x6327 # 0 +0x0000D9CC 0x6302 # 0 +0x0000D9CD 0x6308 # 0 +0x0000D9CE 0x62EF # 0 +0x0000D9CF 0x62F5 # 0 +0x0000D9D0 0x6350 # 0 +0x0000D9D1 0x633E # 0 +0x0000D9D2 0x634D # 0 +0x0000D9D3 0x641C # 0 +0x0000D9D4 0x634F # 0 +0x0000D9D5 0x6396 # 0 +0x0000D9D6 0x638E # 0 +0x0000D9D7 0x6380 # 0 +0x0000D9D8 0x63AB # 0 +0x0000D9D9 0x6376 # 0 +0x0000D9DA 0x63A3 # 0 +0x0000D9DB 0x638F # 0 +0x0000D9DC 0x6389 # 0 +0x0000D9DD 0x639F # 0 +0x0000D9DE 0x63B5 # 0 +0x0000D9DF 0x636B # 0 +0x0000D9E0 0x6369 # 0 +0x0000D9E1 0x63BE # 0 +0x0000D9E2 0x63E9 # 0 +0x0000D9E3 0x63C0 # 0 +0x0000D9E4 0x63C6 # 0 +0x0000D9E5 0x63E3 # 0 +0x0000D9E6 0x63C9 # 0 +0x0000D9E7 0x63D2 # 0 +0x0000D9E8 0x63F6 # 0 +0x0000D9E9 0x63C4 # 0 +0x0000D9EA 0x6416 # 0 +0x0000D9EB 0x6434 # 0 +0x0000D9EC 0x6406 # 0 +0x0000D9ED 0x6413 # 0 +0x0000D9EE 0x6426 # 0 +0x0000D9EF 0x6436 # 0 +0x0000D9F0 0x651D # 0 +0x0000D9F1 0x6417 # 0 +0x0000D9F2 0x6428 # 0 +0x0000D9F3 0x640F # 0 +0x0000D9F4 0x6467 # 0 +0x0000D9F5 0x646F # 0 +0x0000D9F6 0x6476 # 0 +0x0000D9F7 0x644E # 0 +0x0000D9F8 0x652A # 0 +0x0000D9F9 0x6495 # 0 +0x0000D9FA 0x6493 # 0 +0x0000D9FB 0x64A5 # 0 +0x0000D9FC 0x64A9 # 0 +0x0000D9FD 0x6488 # 0 +0x0000D9FE 0x64BC # 0 +0x0000DAA1 0x64DA # 0 +0x0000DAA2 0x64D2 # 0 +0x0000DAA3 0x64C5 # 0 +0x0000DAA4 0x64C7 # 0 +0x0000DAA5 0x64BB # 0 +0x0000DAA6 0x64D8 # 0 +0x0000DAA7 0x64C2 # 0 +0x0000DAA8 0x64F1 # 0 +0x0000DAA9 0x64E7 # 0 +0x0000DAAA 0x8209 # 0 +0x0000DAAB 0x64E0 # 0 +0x0000DAAC 0x64E1 # 0 +0x0000DAAD 0x62AC # 0 +0x0000DAAE 0x64E3 # 0 +0x0000DAAF 0x64EF # 0 +0x0000DAB0 0x652C # 0 +0x0000DAB1 0x64F6 # 0 +0x0000DAB2 0x64F4 # 0 +0x0000DAB3 0x64F2 # 0 +0x0000DAB4 0x64FA # 0 +0x0000DAB5 0x6500 # 0 +0x0000DAB6 0x64FD # 0 +0x0000DAB7 0x6518 # 0 +0x0000DAB8 0x651C # 0 +0x0000DAB9 0x6505 # 0 +0x0000DABA 0x6524 # 0 +0x0000DABB 0x6523 # 0 +0x0000DABC 0x652B # 0 +0x0000DABD 0x6534 # 0 +0x0000DABE 0x6535 # 0 +0x0000DABF 0x6537 # 0 +0x0000DAC0 0x6536 # 0 +0x0000DAC1 0x6538 # 0 +0x0000DAC2 0x754B # 0 +0x0000DAC3 0x6548 # 0 +0x0000DAC4 0x6556 # 0 +0x0000DAC5 0x6555 # 0 +0x0000DAC6 0x654D # 0 +0x0000DAC7 0x6558 # 0 +0x0000DAC8 0x655E # 0 +0x0000DAC9 0x655D # 0 +0x0000DACA 0x6572 # 0 +0x0000DACB 0x6578 # 0 +0x0000DACC 0x6582 # 0 +0x0000DACD 0x6583 # 0 +0x0000DACE 0x8B8A # 0 +0x0000DACF 0x659B # 0 +0x0000DAD0 0x659F # 0 +0x0000DAD1 0x65AB # 0 +0x0000DAD2 0x65B7 # 0 +0x0000DAD3 0x65C3 # 0 +0x0000DAD4 0x65C6 # 0 +0x0000DAD5 0x65C1 # 0 +0x0000DAD6 0x65C4 # 0 +0x0000DAD7 0x65CC # 0 +0x0000DAD8 0x65D2 # 0 +0x0000DAD9 0x65DB # 0 +0x0000DADA 0x65D9 # 0 +0x0000DADB 0x65E0 # 0 +0x0000DADC 0x65E1 # 0 +0x0000DADD 0x65F1 # 0 +0x0000DADE 0x6772 # 0 +0x0000DADF 0x660A # 0 +0x0000DAE0 0x6603 # 0 +0x0000DAE1 0x65FB # 0 +0x0000DAE2 0x6773 # 0 +0x0000DAE3 0x6635 # 0 +0x0000DAE4 0x6636 # 0 +0x0000DAE5 0x6634 # 0 +0x0000DAE6 0x661C # 0 +0x0000DAE7 0x664F # 0 +0x0000DAE8 0x6644 # 0 +0x0000DAE9 0x6649 # 0 +0x0000DAEA 0x6641 # 0 +0x0000DAEB 0x665E # 0 +0x0000DAEC 0x665D # 0 +0x0000DAED 0x6664 # 0 +0x0000DAEE 0x6667 # 0 +0x0000DAEF 0x6668 # 0 +0x0000DAF0 0x665F # 0 +0x0000DAF1 0x6662 # 0 +0x0000DAF2 0x6670 # 0 +0x0000DAF3 0x6683 # 0 +0x0000DAF4 0x6688 # 0 +0x0000DAF5 0x668E # 0 +0x0000DAF6 0x6689 # 0 +0x0000DAF7 0x6684 # 0 +0x0000DAF8 0x6698 # 0 +0x0000DAF9 0x669D # 0 +0x0000DAFA 0x66C1 # 0 +0x0000DAFB 0x66B9 # 0 +0x0000DAFC 0x66C9 # 0 +0x0000DAFD 0x66BE # 0 +0x0000DAFE 0x66BC # 0 +0x0000DBA1 0x66C4 # 0 +0x0000DBA2 0x66B8 # 0 +0x0000DBA3 0x66D6 # 0 +0x0000DBA4 0x66DA # 0 +0x0000DBA5 0x66E0 # 0 +0x0000DBA6 0x663F # 0 +0x0000DBA7 0x66E6 # 0 +0x0000DBA8 0x66E9 # 0 +0x0000DBA9 0x66F0 # 0 +0x0000DBAA 0x66F5 # 0 +0x0000DBAB 0x66F7 # 0 +0x0000DBAC 0x670F # 0 +0x0000DBAD 0x6716 # 0 +0x0000DBAE 0x671E # 0 +0x0000DBAF 0x6726 # 0 +0x0000DBB0 0x6727 # 0 +0x0000DBB1 0x9738 # 0 +0x0000DBB2 0x672E # 0 +0x0000DBB3 0x673F # 0 +0x0000DBB4 0x6736 # 0 +0x0000DBB5 0x6741 # 0 +0x0000DBB6 0x6738 # 0 +0x0000DBB7 0x6737 # 0 +0x0000DBB8 0x6746 # 0 +0x0000DBB9 0x675E # 0 +0x0000DBBA 0x6760 # 0 +0x0000DBBB 0x6759 # 0 +0x0000DBBC 0x6763 # 0 +0x0000DBBD 0x6764 # 0 +0x0000DBBE 0x6789 # 0 +0x0000DBBF 0x6770 # 0 +0x0000DBC0 0x67A9 # 0 +0x0000DBC1 0x677C # 0 +0x0000DBC2 0x676A # 0 +0x0000DBC3 0x678C # 0 +0x0000DBC4 0x678B # 0 +0x0000DBC5 0x67A6 # 0 +0x0000DBC6 0x67A1 # 0 +0x0000DBC7 0x6785 # 0 +0x0000DBC8 0x67B7 # 0 +0x0000DBC9 0x67EF # 0 +0x0000DBCA 0x67B4 # 0 +0x0000DBCB 0x67EC # 0 +0x0000DBCC 0x67B3 # 0 +0x0000DBCD 0x67E9 # 0 +0x0000DBCE 0x67B8 # 0 +0x0000DBCF 0x67E4 # 0 +0x0000DBD0 0x67DE # 0 +0x0000DBD1 0x67DD # 0 +0x0000DBD2 0x67E2 # 0 +0x0000DBD3 0x67EE # 0 +0x0000DBD4 0x67B9 # 0 +0x0000DBD5 0x67CE # 0 +0x0000DBD6 0x67C6 # 0 +0x0000DBD7 0x67E7 # 0 +0x0000DBD8 0x6A9C # 0 +0x0000DBD9 0x681E # 0 +0x0000DBDA 0x6846 # 0 +0x0000DBDB 0x6829 # 0 +0x0000DBDC 0x6840 # 0 +0x0000DBDD 0x684D # 0 +0x0000DBDE 0x6832 # 0 +0x0000DBDF 0x684E # 0 +0x0000DBE0 0x68B3 # 0 +0x0000DBE1 0x682B # 0 +0x0000DBE2 0x6859 # 0 +0x0000DBE3 0x6863 # 0 +0x0000DBE4 0x6877 # 0 +0x0000DBE5 0x687F # 0 +0x0000DBE6 0x689F # 0 +0x0000DBE7 0x688F # 0 +0x0000DBE8 0x68AD # 0 +0x0000DBE9 0x6894 # 0 +0x0000DBEA 0x689D # 0 +0x0000DBEB 0x689B # 0 +0x0000DBEC 0x6883 # 0 +0x0000DBED 0x6AAE # 0 +0x0000DBEE 0x68B9 # 0 +0x0000DBEF 0x6874 # 0 +0x0000DBF0 0x68B5 # 0 +0x0000DBF1 0x68A0 # 0 +0x0000DBF2 0x68BA # 0 +0x0000DBF3 0x690F # 0 +0x0000DBF4 0x688D # 0 +0x0000DBF5 0x687E # 0 +0x0000DBF6 0x6901 # 0 +0x0000DBF7 0x68CA # 0 +0x0000DBF8 0x6908 # 0 +0x0000DBF9 0x68D8 # 0 +0x0000DBFA 0x6922 # 0 +0x0000DBFB 0x6926 # 0 +0x0000DBFC 0x68E1 # 0 +0x0000DBFD 0x690C # 0 +0x0000DBFE 0x68CD # 0 +0x0000DCA1 0x68D4 # 0 +0x0000DCA2 0x68E7 # 0 +0x0000DCA3 0x68D5 # 0 +0x0000DCA4 0x6936 # 0 +0x0000DCA5 0x6912 # 0 +0x0000DCA6 0x6904 # 0 +0x0000DCA7 0x68D7 # 0 +0x0000DCA8 0x68E3 # 0 +0x0000DCA9 0x6925 # 0 +0x0000DCAA 0x68F9 # 0 +0x0000DCAB 0x68E0 # 0 +0x0000DCAC 0x68EF # 0 +0x0000DCAD 0x6928 # 0 +0x0000DCAE 0x692A # 0 +0x0000DCAF 0x691A # 0 +0x0000DCB0 0x6923 # 0 +0x0000DCB1 0x6921 # 0 +0x0000DCB2 0x68C6 # 0 +0x0000DCB3 0x6979 # 0 +0x0000DCB4 0x6977 # 0 +0x0000DCB5 0x695C # 0 +0x0000DCB6 0x6978 # 0 +0x0000DCB7 0x696B # 0 +0x0000DCB8 0x6954 # 0 +0x0000DCB9 0x697E # 0 +0x0000DCBA 0x696E # 0 +0x0000DCBB 0x6939 # 0 +0x0000DCBC 0x6974 # 0 +0x0000DCBD 0x693D # 0 +0x0000DCBE 0x6959 # 0 +0x0000DCBF 0x6930 # 0 +0x0000DCC0 0x6961 # 0 +0x0000DCC1 0x695E # 0 +0x0000DCC2 0x695D # 0 +0x0000DCC3 0x6981 # 0 +0x0000DCC4 0x696A # 0 +0x0000DCC5 0x69B2 # 0 +0x0000DCC6 0x69AE # 0 +0x0000DCC7 0x69D0 # 0 +0x0000DCC8 0x69BF # 0 +0x0000DCC9 0x69C1 # 0 +0x0000DCCA 0x69D3 # 0 +0x0000DCCB 0x69BE # 0 +0x0000DCCC 0x69CE # 0 +0x0000DCCD 0x5BE8 # 0 +0x0000DCCE 0x69CA # 0 +0x0000DCCF 0x69DD # 0 +0x0000DCD0 0x69BB # 0 +0x0000DCD1 0x69C3 # 0 +0x0000DCD2 0x69A7 # 0 +0x0000DCD3 0x6A2E # 0 +0x0000DCD4 0x6991 # 0 +0x0000DCD5 0x69A0 # 0 +0x0000DCD6 0x699C # 0 +0x0000DCD7 0x6995 # 0 +0x0000DCD8 0x69B4 # 0 +0x0000DCD9 0x69DE # 0 +0x0000DCDA 0x69E8 # 0 +0x0000DCDB 0x6A02 # 0 +0x0000DCDC 0x6A1B # 0 +0x0000DCDD 0x69FF # 0 +0x0000DCDE 0x6B0A # 0 +0x0000DCDF 0x69F9 # 0 +0x0000DCE0 0x69F2 # 0 +0x0000DCE1 0x69E7 # 0 +0x0000DCE2 0x6A05 # 0 +0x0000DCE3 0x69B1 # 0 +0x0000DCE4 0x6A1E # 0 +0x0000DCE5 0x69ED # 0 +0x0000DCE6 0x6A14 # 0 +0x0000DCE7 0x69EB # 0 +0x0000DCE8 0x6A0A # 0 +0x0000DCE9 0x6A12 # 0 +0x0000DCEA 0x6AC1 # 0 +0x0000DCEB 0x6A23 # 0 +0x0000DCEC 0x6A13 # 0 +0x0000DCED 0x6A44 # 0 +0x0000DCEE 0x6A0C # 0 +0x0000DCEF 0x6A72 # 0 +0x0000DCF0 0x6A36 # 0 +0x0000DCF1 0x6A78 # 0 +0x0000DCF2 0x6A47 # 0 +0x0000DCF3 0x6A62 # 0 +0x0000DCF4 0x6A59 # 0 +0x0000DCF5 0x6A66 # 0 +0x0000DCF6 0x6A48 # 0 +0x0000DCF7 0x6A38 # 0 +0x0000DCF8 0x6A22 # 0 +0x0000DCF9 0x6A90 # 0 +0x0000DCFA 0x6A8D # 0 +0x0000DCFB 0x6AA0 # 0 +0x0000DCFC 0x6A84 # 0 +0x0000DCFD 0x6AA2 # 0 +0x0000DCFE 0x6AA3 # 0 +0x0000DDA1 0x6A97 # 0 +0x0000DDA2 0x8617 # 0 +0x0000DDA3 0x6ABB # 0 +0x0000DDA4 0x6AC3 # 0 +0x0000DDA5 0x6AC2 # 0 +0x0000DDA6 0x6AB8 # 0 +0x0000DDA7 0x6AB3 # 0 +0x0000DDA8 0x6AAC # 0 +0x0000DDA9 0x6ADE # 0 +0x0000DDAA 0x6AD1 # 0 +0x0000DDAB 0x6ADF # 0 +0x0000DDAC 0x6AAA # 0 +0x0000DDAD 0x6ADA # 0 +0x0000DDAE 0x6AEA # 0 +0x0000DDAF 0x6AFB # 0 +0x0000DDB0 0x6B05 # 0 +0x0000DDB1 0x8616 # 0 +0x0000DDB2 0x6AFA # 0 +0x0000DDB3 0x6B12 # 0 +0x0000DDB4 0x6B16 # 0 +0x0000DDB5 0x9B31 # 0 +0x0000DDB6 0x6B1F # 0 +0x0000DDB7 0x6B38 # 0 +0x0000DDB8 0x6B37 # 0 +0x0000DDB9 0x76DC # 0 +0x0000DDBA 0x6B39 # 0 +0x0000DDBB 0x98EE # 0 +0x0000DDBC 0x6B47 # 0 +0x0000DDBD 0x6B43 # 0 +0x0000DDBE 0x6B49 # 0 +0x0000DDBF 0x6B50 # 0 +0x0000DDC0 0x6B59 # 0 +0x0000DDC1 0x6B54 # 0 +0x0000DDC2 0x6B5B # 0 +0x0000DDC3 0x6B5F # 0 +0x0000DDC4 0x6B61 # 0 +0x0000DDC5 0x6B78 # 0 +0x0000DDC6 0x6B79 # 0 +0x0000DDC7 0x6B7F # 0 +0x0000DDC8 0x6B80 # 0 +0x0000DDC9 0x6B84 # 0 +0x0000DDCA 0x6B83 # 0 +0x0000DDCB 0x6B8D # 0 +0x0000DDCC 0x6B98 # 0 +0x0000DDCD 0x6B95 # 0 +0x0000DDCE 0x6B9E # 0 +0x0000DDCF 0x6BA4 # 0 +0x0000DDD0 0x6BAA # 0 +0x0000DDD1 0x6BAB # 0 +0x0000DDD2 0x6BAF # 0 +0x0000DDD3 0x6BB2 # 0 +0x0000DDD4 0x6BB1 # 0 +0x0000DDD5 0x6BB3 # 0 +0x0000DDD6 0x6BB7 # 0 +0x0000DDD7 0x6BBC # 0 +0x0000DDD8 0x6BC6 # 0 +0x0000DDD9 0x6BCB # 0 +0x0000DDDA 0x6BD3 # 0 +0x0000DDDB 0x6BDF # 0 +0x0000DDDC 0x6BEC # 0 +0x0000DDDD 0x6BEB # 0 +0x0000DDDE 0x6BF3 # 0 +0x0000DDDF 0x6BEF # 0 +0x0000DDE0 0x9EBE # 0 +0x0000DDE1 0x6C08 # 0 +0x0000DDE2 0x6C13 # 0 +0x0000DDE3 0x6C14 # 0 +0x0000DDE4 0x6C1B # 0 +0x0000DDE5 0x6C24 # 0 +0x0000DDE6 0x6C23 # 0 +0x0000DDE7 0x6C5E # 0 +0x0000DDE8 0x6C55 # 0 +0x0000DDE9 0x6C62 # 0 +0x0000DDEA 0x6C6A # 0 +0x0000DDEB 0x6C82 # 0 +0x0000DDEC 0x6C8D # 0 +0x0000DDED 0x6C9A # 0 +0x0000DDEE 0x6C81 # 0 +0x0000DDEF 0x6C9B # 0 +0x0000DDF0 0x6C7E # 0 +0x0000DDF1 0x6C68 # 0 +0x0000DDF2 0x6C73 # 0 +0x0000DDF3 0x6C92 # 0 +0x0000DDF4 0x6C90 # 0 +0x0000DDF5 0x6CC4 # 0 +0x0000DDF6 0x6CF1 # 0 +0x0000DDF7 0x6CD3 # 0 +0x0000DDF8 0x6CBD # 0 +0x0000DDF9 0x6CD7 # 0 +0x0000DDFA 0x6CC5 # 0 +0x0000DDFB 0x6CDD # 0 +0x0000DDFC 0x6CAE # 0 +0x0000DDFD 0x6CB1 # 0 +0x0000DDFE 0x6CBE # 0 +0x0000DEA1 0x6CBA # 0 +0x0000DEA2 0x6CDB # 0 +0x0000DEA3 0x6CEF # 0 +0x0000DEA4 0x6CD9 # 0 +0x0000DEA5 0x6CEA # 0 +0x0000DEA6 0x6D1F # 0 +0x0000DEA7 0x884D # 0 +0x0000DEA8 0x6D36 # 0 +0x0000DEA9 0x6D2B # 0 +0x0000DEAA 0x6D3D # 0 +0x0000DEAB 0x6D38 # 0 +0x0000DEAC 0x6D19 # 0 +0x0000DEAD 0x6D35 # 0 +0x0000DEAE 0x6D33 # 0 +0x0000DEAF 0x6D12 # 0 +0x0000DEB0 0x6D0C # 0 +0x0000DEB1 0x6D63 # 0 +0x0000DEB2 0x6D93 # 0 +0x0000DEB3 0x6D64 # 0 +0x0000DEB4 0x6D5A # 0 +0x0000DEB5 0x6D79 # 0 +0x0000DEB6 0x6D59 # 0 +0x0000DEB7 0x6D8E # 0 +0x0000DEB8 0x6D95 # 0 +0x0000DEB9 0x6FE4 # 0 +0x0000DEBA 0x6D85 # 0 +0x0000DEBB 0x6DF9 # 0 +0x0000DEBC 0x6E15 # 0 +0x0000DEBD 0x6E0A # 0 +0x0000DEBE 0x6DB5 # 0 +0x0000DEBF 0x6DC7 # 0 +0x0000DEC0 0x6DE6 # 0 +0x0000DEC1 0x6DB8 # 0 +0x0000DEC2 0x6DC6 # 0 +0x0000DEC3 0x6DEC # 0 +0x0000DEC4 0x6DDE # 0 +0x0000DEC5 0x6DCC # 0 +0x0000DEC6 0x6DE8 # 0 +0x0000DEC7 0x6DD2 # 0 +0x0000DEC8 0x6DC5 # 0 +0x0000DEC9 0x6DFA # 0 +0x0000DECA 0x6DD9 # 0 +0x0000DECB 0x6DE4 # 0 +0x0000DECC 0x6DD5 # 0 +0x0000DECD 0x6DEA # 0 +0x0000DECE 0x6DEE # 0 +0x0000DECF 0x6E2D # 0 +0x0000DED0 0x6E6E # 0 +0x0000DED1 0x6E2E # 0 +0x0000DED2 0x6E19 # 0 +0x0000DED3 0x6E72 # 0 +0x0000DED4 0x6E5F # 0 +0x0000DED5 0x6E3E # 0 +0x0000DED6 0x6E23 # 0 +0x0000DED7 0x6E6B # 0 +0x0000DED8 0x6E2B # 0 +0x0000DED9 0x6E76 # 0 +0x0000DEDA 0x6E4D # 0 +0x0000DEDB 0x6E1F # 0 +0x0000DEDC 0x6E43 # 0 +0x0000DEDD 0x6E3A # 0 +0x0000DEDE 0x6E4E # 0 +0x0000DEDF 0x6E24 # 0 +0x0000DEE0 0x6EFF # 0 +0x0000DEE1 0x6E1D # 0 +0x0000DEE2 0x6E38 # 0 +0x0000DEE3 0x6E82 # 0 +0x0000DEE4 0x6EAA # 0 +0x0000DEE5 0x6E98 # 0 +0x0000DEE6 0x6EC9 # 0 +0x0000DEE7 0x6EB7 # 0 +0x0000DEE8 0x6ED3 # 0 +0x0000DEE9 0x6EBD # 0 +0x0000DEEA 0x6EAF # 0 +0x0000DEEB 0x6EC4 # 0 +0x0000DEEC 0x6EB2 # 0 +0x0000DEED 0x6ED4 # 0 +0x0000DEEE 0x6ED5 # 0 +0x0000DEEF 0x6E8F # 0 +0x0000DEF0 0x6EA5 # 0 +0x0000DEF1 0x6EC2 # 0 +0x0000DEF2 0x6E9F # 0 +0x0000DEF3 0x6F41 # 0 +0x0000DEF4 0x6F11 # 0 +0x0000DEF5 0x704C # 0 +0x0000DEF6 0x6EEC # 0 +0x0000DEF7 0x6EF8 # 0 +0x0000DEF8 0x6EFE # 0 +0x0000DEF9 0x6F3F # 0 +0x0000DEFA 0x6EF2 # 0 +0x0000DEFB 0x6F31 # 0 +0x0000DEFC 0x6EEF # 0 +0x0000DEFD 0x6F32 # 0 +0x0000DEFE 0x6ECC # 0 +0x0000DFA1 0x6F3E # 0 +0x0000DFA2 0x6F13 # 0 +0x0000DFA3 0x6EF7 # 0 +0x0000DFA4 0x6F86 # 0 +0x0000DFA5 0x6F7A # 0 +0x0000DFA6 0x6F78 # 0 +0x0000DFA7 0x6F81 # 0 +0x0000DFA8 0x6F80 # 0 +0x0000DFA9 0x6F6F # 0 +0x0000DFAA 0x6F5B # 0 +0x0000DFAB 0x6FF3 # 0 +0x0000DFAC 0x6F6D # 0 +0x0000DFAD 0x6F82 # 0 +0x0000DFAE 0x6F7C # 0 +0x0000DFAF 0x6F58 # 0 +0x0000DFB0 0x6F8E # 0 +0x0000DFB1 0x6F91 # 0 +0x0000DFB2 0x6FC2 # 0 +0x0000DFB3 0x6F66 # 0 +0x0000DFB4 0x6FB3 # 0 +0x0000DFB5 0x6FA3 # 0 +0x0000DFB6 0x6FA1 # 0 +0x0000DFB7 0x6FA4 # 0 +0x0000DFB8 0x6FB9 # 0 +0x0000DFB9 0x6FC6 # 0 +0x0000DFBA 0x6FAA # 0 +0x0000DFBB 0x6FDF # 0 +0x0000DFBC 0x6FD5 # 0 +0x0000DFBD 0x6FEC # 0 +0x0000DFBE 0x6FD4 # 0 +0x0000DFBF 0x6FD8 # 0 +0x0000DFC0 0x6FF1 # 0 +0x0000DFC1 0x6FEE # 0 +0x0000DFC2 0x6FDB # 0 +0x0000DFC3 0x7009 # 0 +0x0000DFC4 0x700B # 0 +0x0000DFC5 0x6FFA # 0 +0x0000DFC6 0x7011 # 0 +0x0000DFC7 0x7001 # 0 +0x0000DFC8 0x700F # 0 +0x0000DFC9 0x6FFE # 0 +0x0000DFCA 0x701B # 0 +0x0000DFCB 0x701A # 0 +0x0000DFCC 0x6F74 # 0 +0x0000DFCD 0x701D # 0 +0x0000DFCE 0x7018 # 0 +0x0000DFCF 0x701F # 0 +0x0000DFD0 0x7030 # 0 +0x0000DFD1 0x703E # 0 +0x0000DFD2 0x7032 # 0 +0x0000DFD3 0x7051 # 0 +0x0000DFD4 0x7063 # 0 +0x0000DFD5 0x7099 # 0 +0x0000DFD6 0x7092 # 0 +0x0000DFD7 0x70AF # 0 +0x0000DFD8 0x70F1 # 0 +0x0000DFD9 0x70AC # 0 +0x0000DFDA 0x70B8 # 0 +0x0000DFDB 0x70B3 # 0 +0x0000DFDC 0x70AE # 0 +0x0000DFDD 0x70DF # 0 +0x0000DFDE 0x70CB # 0 +0x0000DFDF 0x70DD # 0 +0x0000DFE0 0x70D9 # 0 +0x0000DFE1 0x7109 # 0 +0x0000DFE2 0x70FD # 0 +0x0000DFE3 0x711C # 0 +0x0000DFE4 0x7119 # 0 +0x0000DFE5 0x7165 # 0 +0x0000DFE6 0x7155 # 0 +0x0000DFE7 0x7188 # 0 +0x0000DFE8 0x7166 # 0 +0x0000DFE9 0x7162 # 0 +0x0000DFEA 0x714C # 0 +0x0000DFEB 0x7156 # 0 +0x0000DFEC 0x716C # 0 +0x0000DFED 0x718F # 0 +0x0000DFEE 0x71FB # 0 +0x0000DFEF 0x7184 # 0 +0x0000DFF0 0x7195 # 0 +0x0000DFF1 0x71A8 # 0 +0x0000DFF2 0x71AC # 0 +0x0000DFF3 0x71D7 # 0 +0x0000DFF4 0x71B9 # 0 +0x0000DFF5 0x71BE # 0 +0x0000DFF6 0x71D2 # 0 +0x0000DFF7 0x71C9 # 0 +0x0000DFF8 0x71D4 # 0 +0x0000DFF9 0x71CE # 0 +0x0000DFFA 0x71E0 # 0 +0x0000DFFB 0x71EC # 0 +0x0000DFFC 0x71E7 # 0 +0x0000DFFD 0x71F5 # 0 +0x0000DFFE 0x71FC # 0 +0x0000E0A1 0x71F9 # 0 +0x0000E0A2 0x71FF # 0 +0x0000E0A3 0x720D # 0 +0x0000E0A4 0x7210 # 0 +0x0000E0A5 0x721B # 0 +0x0000E0A6 0x7228 # 0 +0x0000E0A7 0x722D # 0 +0x0000E0A8 0x722C # 0 +0x0000E0A9 0x7230 # 0 +0x0000E0AA 0x7232 # 0 +0x0000E0AB 0x723B # 0 +0x0000E0AC 0x723C # 0 +0x0000E0AD 0x723F # 0 +0x0000E0AE 0x7240 # 0 +0x0000E0AF 0x7246 # 0 +0x0000E0B0 0x724B # 0 +0x0000E0B1 0x7258 # 0 +0x0000E0B2 0x7274 # 0 +0x0000E0B3 0x727E # 0 +0x0000E0B4 0x7282 # 0 +0x0000E0B5 0x7281 # 0 +0x0000E0B6 0x7287 # 0 +0x0000E0B7 0x7292 # 0 +0x0000E0B8 0x7296 # 0 +0x0000E0B9 0x72A2 # 0 +0x0000E0BA 0x72A7 # 0 +0x0000E0BB 0x72B9 # 0 +0x0000E0BC 0x72B2 # 0 +0x0000E0BD 0x72C3 # 0 +0x0000E0BE 0x72C6 # 0 +0x0000E0BF 0x72C4 # 0 +0x0000E0C0 0x72CE # 0 +0x0000E0C1 0x72D2 # 0 +0x0000E0C2 0x72E2 # 0 +0x0000E0C3 0x72E0 # 0 +0x0000E0C4 0x72E1 # 0 +0x0000E0C5 0x72F9 # 0 +0x0000E0C6 0x72F7 # 0 +0x0000E0C7 0x500F # 0 +0x0000E0C8 0x7317 # 0 +0x0000E0C9 0x730A # 0 +0x0000E0CA 0x731C # 0 +0x0000E0CB 0x7316 # 0 +0x0000E0CC 0x731D # 0 +0x0000E0CD 0x7334 # 0 +0x0000E0CE 0x732F # 0 +0x0000E0CF 0x7329 # 0 +0x0000E0D0 0x7325 # 0 +0x0000E0D1 0x733E # 0 +0x0000E0D2 0x734E # 0 +0x0000E0D3 0x734F # 0 +0x0000E0D4 0x9ED8 # 0 +0x0000E0D5 0x7357 # 0 +0x0000E0D6 0x736A # 0 +0x0000E0D7 0x7368 # 0 +0x0000E0D8 0x7370 # 0 +0x0000E0D9 0x7378 # 0 +0x0000E0DA 0x7375 # 0 +0x0000E0DB 0x737B # 0 +0x0000E0DC 0x737A # 0 +0x0000E0DD 0x73C8 # 0 +0x0000E0DE 0x73B3 # 0 +0x0000E0DF 0x73CE # 0 +0x0000E0E0 0x73BB # 0 +0x0000E0E1 0x73C0 # 0 +0x0000E0E2 0x73E5 # 0 +0x0000E0E3 0x73EE # 0 +0x0000E0E4 0x73DE # 0 +0x0000E0E5 0x74A2 # 0 +0x0000E0E6 0x7405 # 0 +0x0000E0E7 0x746F # 0 +0x0000E0E8 0x7425 # 0 +0x0000E0E9 0x73F8 # 0 +0x0000E0EA 0x7432 # 0 +0x0000E0EB 0x743A # 0 +0x0000E0EC 0x7455 # 0 +0x0000E0ED 0x743F # 0 +0x0000E0EE 0x745F # 0 +0x0000E0EF 0x7459 # 0 +0x0000E0F0 0x7441 # 0 +0x0000E0F1 0x745C # 0 +0x0000E0F2 0x7469 # 0 +0x0000E0F3 0x7470 # 0 +0x0000E0F4 0x7463 # 0 +0x0000E0F5 0x746A # 0 +0x0000E0F6 0x7476 # 0 +0x0000E0F7 0x747E # 0 +0x0000E0F8 0x748B # 0 +0x0000E0F9 0x749E # 0 +0x0000E0FA 0x74A7 # 0 +0x0000E0FB 0x74CA # 0 +0x0000E0FC 0x74CF # 0 +0x0000E0FD 0x74D4 # 0 +0x0000E0FE 0x73F1 # 0 +0x0000E1A1 0x74E0 # 0 +0x0000E1A2 0x74E3 # 0 +0x0000E1A3 0x74E7 # 0 +0x0000E1A4 0x74E9 # 0 +0x0000E1A5 0x74EE # 0 +0x0000E1A6 0x74F2 # 0 +0x0000E1A7 0x74F0 # 0 +0x0000E1A8 0x74F1 # 0 +0x0000E1A9 0x74F8 # 0 +0x0000E1AA 0x74F7 # 0 +0x0000E1AB 0x7504 # 0 +0x0000E1AC 0x7503 # 0 +0x0000E1AD 0x7505 # 0 +0x0000E1AE 0x750C # 0 +0x0000E1AF 0x750E # 0 +0x0000E1B0 0x750D # 0 +0x0000E1B1 0x7515 # 0 +0x0000E1B2 0x7513 # 0 +0x0000E1B3 0x751E # 0 +0x0000E1B4 0x7526 # 0 +0x0000E1B5 0x752C # 0 +0x0000E1B6 0x753C # 0 +0x0000E1B7 0x7544 # 0 +0x0000E1B8 0x754D # 0 +0x0000E1B9 0x754A # 0 +0x0000E1BA 0x7549 # 0 +0x0000E1BB 0x755B # 0 +0x0000E1BC 0x7546 # 0 +0x0000E1BD 0x755A # 0 +0x0000E1BE 0x7569 # 0 +0x0000E1BF 0x7564 # 0 +0x0000E1C0 0x7567 # 0 +0x0000E1C1 0x756B # 0 +0x0000E1C2 0x756D # 0 +0x0000E1C3 0x7578 # 0 +0x0000E1C4 0x7576 # 0 +0x0000E1C5 0x7586 # 0 +0x0000E1C6 0x7587 # 0 +0x0000E1C7 0x7574 # 0 +0x0000E1C8 0x758A # 0 +0x0000E1C9 0x7589 # 0 +0x0000E1CA 0x7582 # 0 +0x0000E1CB 0x7594 # 0 +0x0000E1CC 0x759A # 0 +0x0000E1CD 0x759D # 0 +0x0000E1CE 0x75A5 # 0 +0x0000E1CF 0x75A3 # 0 +0x0000E1D0 0x75C2 # 0 +0x0000E1D1 0x75B3 # 0 +0x0000E1D2 0x75C3 # 0 +0x0000E1D3 0x75B5 # 0 +0x0000E1D4 0x75BD # 0 +0x0000E1D5 0x75B8 # 0 +0x0000E1D6 0x75BC # 0 +0x0000E1D7 0x75B1 # 0 +0x0000E1D8 0x75CD # 0 +0x0000E1D9 0x75CA # 0 +0x0000E1DA 0x75D2 # 0 +0x0000E1DB 0x75D9 # 0 +0x0000E1DC 0x75E3 # 0 +0x0000E1DD 0x75DE # 0 +0x0000E1DE 0x75FE # 0 +0x0000E1DF 0x75FF # 0 +0x0000E1E0 0x75FC # 0 +0x0000E1E1 0x7601 # 0 +0x0000E1E2 0x75F0 # 0 +0x0000E1E3 0x75FA # 0 +0x0000E1E4 0x75F2 # 0 +0x0000E1E5 0x75F3 # 0 +0x0000E1E6 0x760B # 0 +0x0000E1E7 0x760D # 0 +0x0000E1E8 0x7609 # 0 +0x0000E1E9 0x761F # 0 +0x0000E1EA 0x7627 # 0 +0x0000E1EB 0x7620 # 0 +0x0000E1EC 0x7621 # 0 +0x0000E1ED 0x7622 # 0 +0x0000E1EE 0x7624 # 0 +0x0000E1EF 0x7634 # 0 +0x0000E1F0 0x7630 # 0 +0x0000E1F1 0x763B # 0 +0x0000E1F2 0x7647 # 0 +0x0000E1F3 0x7648 # 0 +0x0000E1F4 0x7646 # 0 +0x0000E1F5 0x765C # 0 +0x0000E1F6 0x7658 # 0 +0x0000E1F7 0x7661 # 0 +0x0000E1F8 0x7662 # 0 +0x0000E1F9 0x7668 # 0 +0x0000E1FA 0x7669 # 0 +0x0000E1FB 0x766A # 0 +0x0000E1FC 0x7667 # 0 +0x0000E1FD 0x766C # 0 +0x0000E1FE 0x7670 # 0 +0x0000E2A1 0x7672 # 0 +0x0000E2A2 0x7676 # 0 +0x0000E2A3 0x7678 # 0 +0x0000E2A4 0x767C # 0 +0x0000E2A5 0x7680 # 0 +0x0000E2A6 0x7683 # 0 +0x0000E2A7 0x7688 # 0 +0x0000E2A8 0x768B # 0 +0x0000E2A9 0x768E # 0 +0x0000E2AA 0x7696 # 0 +0x0000E2AB 0x7693 # 0 +0x0000E2AC 0x7699 # 0 +0x0000E2AD 0x769A # 0 +0x0000E2AE 0x76B0 # 0 +0x0000E2AF 0x76B4 # 0 +0x0000E2B0 0x76B8 # 0 +0x0000E2B1 0x76B9 # 0 +0x0000E2B2 0x76BA # 0 +0x0000E2B3 0x76C2 # 0 +0x0000E2B4 0x76CD # 0 +0x0000E2B5 0x76D6 # 0 +0x0000E2B6 0x76D2 # 0 +0x0000E2B7 0x76DE # 0 +0x0000E2B8 0x76E1 # 0 +0x0000E2B9 0x76E5 # 0 +0x0000E2BA 0x76E7 # 0 +0x0000E2BB 0x76EA # 0 +0x0000E2BC 0x862F # 0 +0x0000E2BD 0x76FB # 0 +0x0000E2BE 0x7708 # 0 +0x0000E2BF 0x7707 # 0 +0x0000E2C0 0x7704 # 0 +0x0000E2C1 0x7729 # 0 +0x0000E2C2 0x7724 # 0 +0x0000E2C3 0x771E # 0 +0x0000E2C4 0x7725 # 0 +0x0000E2C5 0x7726 # 0 +0x0000E2C6 0x771B # 0 +0x0000E2C7 0x7737 # 0 +0x0000E2C8 0x7738 # 0 +0x0000E2C9 0x7747 # 0 +0x0000E2CA 0x775A # 0 +0x0000E2CB 0x7768 # 0 +0x0000E2CC 0x776B # 0 +0x0000E2CD 0x775B # 0 +0x0000E2CE 0x7765 # 0 +0x0000E2CF 0x777F # 0 +0x0000E2D0 0x777E # 0 +0x0000E2D1 0x7779 # 0 +0x0000E2D2 0x778E # 0 +0x0000E2D3 0x778B # 0 +0x0000E2D4 0x7791 # 0 +0x0000E2D5 0x77A0 # 0 +0x0000E2D6 0x779E # 0 +0x0000E2D7 0x77B0 # 0 +0x0000E2D8 0x77B6 # 0 +0x0000E2D9 0x77B9 # 0 +0x0000E2DA 0x77BF # 0 +0x0000E2DB 0x77BC # 0 +0x0000E2DC 0x77BD # 0 +0x0000E2DD 0x77BB # 0 +0x0000E2DE 0x77C7 # 0 +0x0000E2DF 0x77CD # 0 +0x0000E2E0 0x77D7 # 0 +0x0000E2E1 0x77DA # 0 +0x0000E2E2 0x77DC # 0 +0x0000E2E3 0x77E3 # 0 +0x0000E2E4 0x77EE # 0 +0x0000E2E5 0x77FC # 0 +0x0000E2E6 0x780C # 0 +0x0000E2E7 0x7812 # 0 +0x0000E2E8 0x7926 # 0 +0x0000E2E9 0x7820 # 0 +0x0000E2EA 0x792A # 0 +0x0000E2EB 0x7845 # 0 +0x0000E2EC 0x788E # 0 +0x0000E2ED 0x7874 # 0 +0x0000E2EE 0x7886 # 0 +0x0000E2EF 0x787C # 0 +0x0000E2F0 0x789A # 0 +0x0000E2F1 0x788C # 0 +0x0000E2F2 0x78A3 # 0 +0x0000E2F3 0x78B5 # 0 +0x0000E2F4 0x78AA # 0 +0x0000E2F5 0x78AF # 0 +0x0000E2F6 0x78D1 # 0 +0x0000E2F7 0x78C6 # 0 +0x0000E2F8 0x78CB # 0 +0x0000E2F9 0x78D4 # 0 +0x0000E2FA 0x78BE # 0 +0x0000E2FB 0x78BC # 0 +0x0000E2FC 0x78C5 # 0 +0x0000E2FD 0x78CA # 0 +0x0000E2FE 0x78EC # 0 +0x0000E3A1 0x78E7 # 0 +0x0000E3A2 0x78DA # 0 +0x0000E3A3 0x78FD # 0 +0x0000E3A4 0x78F4 # 0 +0x0000E3A5 0x7907 # 0 +0x0000E3A6 0x7912 # 0 +0x0000E3A7 0x7911 # 0 +0x0000E3A8 0x7919 # 0 +0x0000E3A9 0x792C # 0 +0x0000E3AA 0x792B # 0 +0x0000E3AB 0x7940 # 0 +0x0000E3AC 0x7960 # 0 +0x0000E3AD 0x7957 # 0 +0x0000E3AE 0x795F # 0 +0x0000E3AF 0x795A # 0 +0x0000E3B0 0x7955 # 0 +0x0000E3B1 0x7953 # 0 +0x0000E3B2 0x797A # 0 +0x0000E3B3 0x797F # 0 +0x0000E3B4 0x798A # 0 +0x0000E3B5 0x799D # 0 +0x0000E3B6 0x79A7 # 0 +0x0000E3B7 0x9F4B # 0 +0x0000E3B8 0x79AA # 0 +0x0000E3B9 0x79AE # 0 +0x0000E3BA 0x79B3 # 0 +0x0000E3BB 0x79B9 # 0 +0x0000E3BC 0x79BA # 0 +0x0000E3BD 0x79C9 # 0 +0x0000E3BE 0x79D5 # 0 +0x0000E3BF 0x79E7 # 0 +0x0000E3C0 0x79EC # 0 +0x0000E3C1 0x79E1 # 0 +0x0000E3C2 0x79E3 # 0 +0x0000E3C3 0x7A08 # 0 +0x0000E3C4 0x7A0D # 0 +0x0000E3C5 0x7A18 # 0 +0x0000E3C6 0x7A19 # 0 +0x0000E3C7 0x7A20 # 0 +0x0000E3C8 0x7A1F # 0 +0x0000E3C9 0x7980 # 0 +0x0000E3CA 0x7A31 # 0 +0x0000E3CB 0x7A3B # 0 +0x0000E3CC 0x7A3E # 0 +0x0000E3CD 0x7A37 # 0 +0x0000E3CE 0x7A43 # 0 +0x0000E3CF 0x7A57 # 0 +0x0000E3D0 0x7A49 # 0 +0x0000E3D1 0x7A61 # 0 +0x0000E3D2 0x7A62 # 0 +0x0000E3D3 0x7A69 # 0 +0x0000E3D4 0x9F9D # 0 +0x0000E3D5 0x7A70 # 0 +0x0000E3D6 0x7A79 # 0 +0x0000E3D7 0x7A7D # 0 +0x0000E3D8 0x7A88 # 0 +0x0000E3D9 0x7A97 # 0 +0x0000E3DA 0x7A95 # 0 +0x0000E3DB 0x7A98 # 0 +0x0000E3DC 0x7A96 # 0 +0x0000E3DD 0x7AA9 # 0 +0x0000E3DE 0x7AC8 # 0 +0x0000E3DF 0x7AB0 # 0 +0x0000E3E0 0x7AB6 # 0 +0x0000E3E1 0x7AC5 # 0 +0x0000E3E2 0x7AC4 # 0 +0x0000E3E3 0x7ABF # 0 +0x0000E3E4 0x9083 # 0 +0x0000E3E5 0x7AC7 # 0 +0x0000E3E6 0x7ACA # 0 +0x0000E3E7 0x7ACD # 0 +0x0000E3E8 0x7ACF # 0 +0x0000E3E9 0x7AD5 # 0 +0x0000E3EA 0x7AD3 # 0 +0x0000E3EB 0x7AD9 # 0 +0x0000E3EC 0x7ADA # 0 +0x0000E3ED 0x7ADD # 0 +0x0000E3EE 0x7AE1 # 0 +0x0000E3EF 0x7AE2 # 0 +0x0000E3F0 0x7AE6 # 0 +0x0000E3F1 0x7AED # 0 +0x0000E3F2 0x7AF0 # 0 +0x0000E3F3 0x7B02 # 0 +0x0000E3F4 0x7B0F # 0 +0x0000E3F5 0x7B0A # 0 +0x0000E3F6 0x7B06 # 0 +0x0000E3F7 0x7B33 # 0 +0x0000E3F8 0x7B18 # 0 +0x0000E3F9 0x7B19 # 0 +0x0000E3FA 0x7B1E # 0 +0x0000E3FB 0x7B35 # 0 +0x0000E3FC 0x7B28 # 0 +0x0000E3FD 0x7B36 # 0 +0x0000E3FE 0x7B50 # 0 +0x0000E4A1 0x7B7A # 0 +0x0000E4A2 0x7B04 # 0 +0x0000E4A3 0x7B4D # 0 +0x0000E4A4 0x7B0B # 0 +0x0000E4A5 0x7B4C # 0 +0x0000E4A6 0x7B45 # 0 +0x0000E4A7 0x7B75 # 0 +0x0000E4A8 0x7B65 # 0 +0x0000E4A9 0x7B74 # 0 +0x0000E4AA 0x7B67 # 0 +0x0000E4AB 0x7B70 # 0 +0x0000E4AC 0x7B71 # 0 +0x0000E4AD 0x7B6C # 0 +0x0000E4AE 0x7B6E # 0 +0x0000E4AF 0x7B9D # 0 +0x0000E4B0 0x7B98 # 0 +0x0000E4B1 0x7B9F # 0 +0x0000E4B2 0x7B8D # 0 +0x0000E4B3 0x7B9C # 0 +0x0000E4B4 0x7B9A # 0 +0x0000E4B5 0x7B8B # 0 +0x0000E4B6 0x7B92 # 0 +0x0000E4B7 0x7B8F # 0 +0x0000E4B8 0x7B5D # 0 +0x0000E4B9 0x7B99 # 0 +0x0000E4BA 0x7BCB # 0 +0x0000E4BB 0x7BC1 # 0 +0x0000E4BC 0x7BCC # 0 +0x0000E4BD 0x7BCF # 0 +0x0000E4BE 0x7BB4 # 0 +0x0000E4BF 0x7BC6 # 0 +0x0000E4C0 0x7BDD # 0 +0x0000E4C1 0x7BE9 # 0 +0x0000E4C2 0x7C11 # 0 +0x0000E4C3 0x7C14 # 0 +0x0000E4C4 0x7BE6 # 0 +0x0000E4C5 0x7BE5 # 0 +0x0000E4C6 0x7C60 # 0 +0x0000E4C7 0x7C00 # 0 +0x0000E4C8 0x7C07 # 0 +0x0000E4C9 0x7C13 # 0 +0x0000E4CA 0x7BF3 # 0 +0x0000E4CB 0x7BF7 # 0 +0x0000E4CC 0x7C17 # 0 +0x0000E4CD 0x7C0D # 0 +0x0000E4CE 0x7BF6 # 0 +0x0000E4CF 0x7C23 # 0 +0x0000E4D0 0x7C27 # 0 +0x0000E4D1 0x7C2A # 0 +0x0000E4D2 0x7C1F # 0 +0x0000E4D3 0x7C37 # 0 +0x0000E4D4 0x7C2B # 0 +0x0000E4D5 0x7C3D # 0 +0x0000E4D6 0x7C4C # 0 +0x0000E4D7 0x7C43 # 0 +0x0000E4D8 0x7C54 # 0 +0x0000E4D9 0x7C4F # 0 +0x0000E4DA 0x7C40 # 0 +0x0000E4DB 0x7C50 # 0 +0x0000E4DC 0x7C58 # 0 +0x0000E4DD 0x7C5F # 0 +0x0000E4DE 0x7C64 # 0 +0x0000E4DF 0x7C56 # 0 +0x0000E4E0 0x7C65 # 0 +0x0000E4E1 0x7C6C # 0 +0x0000E4E2 0x7C75 # 0 +0x0000E4E3 0x7C83 # 0 +0x0000E4E4 0x7C90 # 0 +0x0000E4E5 0x7CA4 # 0 +0x0000E4E6 0x7CAD # 0 +0x0000E4E7 0x7CA2 # 0 +0x0000E4E8 0x7CAB # 0 +0x0000E4E9 0x7CA1 # 0 +0x0000E4EA 0x7CA8 # 0 +0x0000E4EB 0x7CB3 # 0 +0x0000E4EC 0x7CB2 # 0 +0x0000E4ED 0x7CB1 # 0 +0x0000E4EE 0x7CAE # 0 +0x0000E4EF 0x7CB9 # 0 +0x0000E4F0 0x7CBD # 0 +0x0000E4F1 0x7CC0 # 0 +0x0000E4F2 0x7CC5 # 0 +0x0000E4F3 0x7CC2 # 0 +0x0000E4F4 0x7CD8 # 0 +0x0000E4F5 0x7CD2 # 0 +0x0000E4F6 0x7CDC # 0 +0x0000E4F7 0x7CE2 # 0 +0x0000E4F8 0x9B3B # 0 +0x0000E4F9 0x7CEF # 0 +0x0000E4FA 0x7CF2 # 0 +0x0000E4FB 0x7CF4 # 0 +0x0000E4FC 0x7CF6 # 0 +0x0000E4FD 0x7CFA # 0 +0x0000E4FE 0x7D06 # 0 +0x0000E5A1 0x7D02 # 0 +0x0000E5A2 0x7D1C # 0 +0x0000E5A3 0x7D15 # 0 +0x0000E5A4 0x7D0A # 0 +0x0000E5A5 0x7D45 # 0 +0x0000E5A6 0x7D4B # 0 +0x0000E5A7 0x7D2E # 0 +0x0000E5A8 0x7D32 # 0 +0x0000E5A9 0x7D3F # 0 +0x0000E5AA 0x7D35 # 0 +0x0000E5AB 0x7D46 # 0 +0x0000E5AC 0x7D73 # 0 +0x0000E5AD 0x7D56 # 0 +0x0000E5AE 0x7D4E # 0 +0x0000E5AF 0x7D72 # 0 +0x0000E5B0 0x7D68 # 0 +0x0000E5B1 0x7D6E # 0 +0x0000E5B2 0x7D4F # 0 +0x0000E5B3 0x7D63 # 0 +0x0000E5B4 0x7D93 # 0 +0x0000E5B5 0x7D89 # 0 +0x0000E5B6 0x7D5B # 0 +0x0000E5B7 0x7D8F # 0 +0x0000E5B8 0x7D7D # 0 +0x0000E5B9 0x7D9B # 0 +0x0000E5BA 0x7DBA # 0 +0x0000E5BB 0x7DAE # 0 +0x0000E5BC 0x7DA3 # 0 +0x0000E5BD 0x7DB5 # 0 +0x0000E5BE 0x7DC7 # 0 +0x0000E5BF 0x7DBD # 0 +0x0000E5C0 0x7DAB # 0 +0x0000E5C1 0x7E3D # 0 +0x0000E5C2 0x7DA2 # 0 +0x0000E5C3 0x7DAF # 0 +0x0000E5C4 0x7DDC # 0 +0x0000E5C5 0x7DB8 # 0 +0x0000E5C6 0x7D9F # 0 +0x0000E5C7 0x7DB0 # 0 +0x0000E5C8 0x7DD8 # 0 +0x0000E5C9 0x7DDD # 0 +0x0000E5CA 0x7DE4 # 0 +0x0000E5CB 0x7DDE # 0 +0x0000E5CC 0x7DFB # 0 +0x0000E5CD 0x7DF2 # 0 +0x0000E5CE 0x7DE1 # 0 +0x0000E5CF 0x7E05 # 0 +0x0000E5D0 0x7E0A # 0 +0x0000E5D1 0x7E23 # 0 +0x0000E5D2 0x7E21 # 0 +0x0000E5D3 0x7E12 # 0 +0x0000E5D4 0x7E31 # 0 +0x0000E5D5 0x7E1F # 0 +0x0000E5D6 0x7E09 # 0 +0x0000E5D7 0x7E0B # 0 +0x0000E5D8 0x7E22 # 0 +0x0000E5D9 0x7E46 # 0 +0x0000E5DA 0x7E66 # 0 +0x0000E5DB 0x7E3B # 0 +0x0000E5DC 0x7E35 # 0 +0x0000E5DD 0x7E39 # 0 +0x0000E5DE 0x7E43 # 0 +0x0000E5DF 0x7E37 # 0 +0x0000E5E0 0x7E32 # 0 +0x0000E5E1 0x7E3A # 0 +0x0000E5E2 0x7E67 # 0 +0x0000E5E3 0x7E5D # 0 +0x0000E5E4 0x7E56 # 0 +0x0000E5E5 0x7E5E # 0 +0x0000E5E6 0x7E59 # 0 +0x0000E5E7 0x7E5A # 0 +0x0000E5E8 0x7E79 # 0 +0x0000E5E9 0x7E6A # 0 +0x0000E5EA 0x7E69 # 0 +0x0000E5EB 0x7E7C # 0 +0x0000E5EC 0x7E7B # 0 +0x0000E5ED 0x7E83 # 0 +0x0000E5EE 0x7DD5 # 0 +0x0000E5EF 0x7E7D # 0 +0x0000E5F0 0x8FAE # 0 +0x0000E5F1 0x7E7F # 0 +0x0000E5F2 0x7E88 # 0 +0x0000E5F3 0x7E89 # 0 +0x0000E5F4 0x7E8C # 0 +0x0000E5F5 0x7E92 # 0 +0x0000E5F6 0x7E90 # 0 +0x0000E5F7 0x7E93 # 0 +0x0000E5F8 0x7E94 # 0 +0x0000E5F9 0x7E96 # 0 +0x0000E5FA 0x7E8E # 0 +0x0000E5FB 0x7E9B # 0 +0x0000E5FC 0x7E9C # 0 +0x0000E5FD 0x7F38 # 0 +0x0000E5FE 0x7F3A # 0 +0x0000E6A1 0x7F45 # 0 +0x0000E6A2 0x7F4C # 0 +0x0000E6A3 0x7F4D # 0 +0x0000E6A4 0x7F4E # 0 +0x0000E6A5 0x7F50 # 0 +0x0000E6A6 0x7F51 # 0 +0x0000E6A7 0x7F55 # 0 +0x0000E6A8 0x7F54 # 0 +0x0000E6A9 0x7F58 # 0 +0x0000E6AA 0x7F5F # 0 +0x0000E6AB 0x7F60 # 0 +0x0000E6AC 0x7F68 # 0 +0x0000E6AD 0x7F69 # 0 +0x0000E6AE 0x7F67 # 0 +0x0000E6AF 0x7F78 # 0 +0x0000E6B0 0x7F82 # 0 +0x0000E6B1 0x7F86 # 0 +0x0000E6B2 0x7F83 # 0 +0x0000E6B3 0x7F88 # 0 +0x0000E6B4 0x7F87 # 0 +0x0000E6B5 0x7F8C # 0 +0x0000E6B6 0x7F94 # 0 +0x0000E6B7 0x7F9E # 0 +0x0000E6B8 0x7F9D # 0 +0x0000E6B9 0x7F9A # 0 +0x0000E6BA 0x7FA3 # 0 +0x0000E6BB 0x7FAF # 0 +0x0000E6BC 0x7FB2 # 0 +0x0000E6BD 0x7FB9 # 0 +0x0000E6BE 0x7FAE # 0 +0x0000E6BF 0x7FB6 # 0 +0x0000E6C0 0x7FB8 # 0 +0x0000E6C1 0x8B71 # 0 +0x0000E6C2 0x7FC5 # 0 +0x0000E6C3 0x7FC6 # 0 +0x0000E6C4 0x7FCA # 0 +0x0000E6C5 0x7FD5 # 0 +0x0000E6C6 0x7FD4 # 0 +0x0000E6C7 0x7FE1 # 0 +0x0000E6C8 0x7FE6 # 0 +0x0000E6C9 0x7FE9 # 0 +0x0000E6CA 0x7FF3 # 0 +0x0000E6CB 0x7FF9 # 0 +0x0000E6CC 0x98DC # 0 +0x0000E6CD 0x8006 # 0 +0x0000E6CE 0x8004 # 0 +0x0000E6CF 0x800B # 0 +0x0000E6D0 0x8012 # 0 +0x0000E6D1 0x8018 # 0 +0x0000E6D2 0x8019 # 0 +0x0000E6D3 0x801C # 0 +0x0000E6D4 0x8021 # 0 +0x0000E6D5 0x8028 # 0 +0x0000E6D6 0x803F # 0 +0x0000E6D7 0x803B # 0 +0x0000E6D8 0x804A # 0 +0x0000E6D9 0x8046 # 0 +0x0000E6DA 0x8052 # 0 +0x0000E6DB 0x8058 # 0 +0x0000E6DC 0x805A # 0 +0x0000E6DD 0x805F # 0 +0x0000E6DE 0x8062 # 0 +0x0000E6DF 0x8068 # 0 +0x0000E6E0 0x8073 # 0 +0x0000E6E1 0x8072 # 0 +0x0000E6E2 0x8070 # 0 +0x0000E6E3 0x8076 # 0 +0x0000E6E4 0x8079 # 0 +0x0000E6E5 0x807D # 0 +0x0000E6E6 0x807F # 0 +0x0000E6E7 0x8084 # 0 +0x0000E6E8 0x8086 # 0 +0x0000E6E9 0x8085 # 0 +0x0000E6EA 0x809B # 0 +0x0000E6EB 0x8093 # 0 +0x0000E6EC 0x809A # 0 +0x0000E6ED 0x80AD # 0 +0x0000E6EE 0x5190 # 0 +0x0000E6EF 0x80AC # 0 +0x0000E6F0 0x80DB # 0 +0x0000E6F1 0x80E5 # 0 +0x0000E6F2 0x80D9 # 0 +0x0000E6F3 0x80DD # 0 +0x0000E6F4 0x80C4 # 0 +0x0000E6F5 0x80DA # 0 +0x0000E6F6 0x80D6 # 0 +0x0000E6F7 0x8109 # 0 +0x0000E6F8 0x80EF # 0 +0x0000E6F9 0x80F1 # 0 +0x0000E6FA 0x811B # 0 +0x0000E6FB 0x8129 # 0 +0x0000E6FC 0x8123 # 0 +0x0000E6FD 0x812F # 0 +0x0000E6FE 0x814B # 0 +0x0000E7A1 0x968B # 0 +0x0000E7A2 0x8146 # 0 +0x0000E7A3 0x813E # 0 +0x0000E7A4 0x8153 # 0 +0x0000E7A5 0x8151 # 0 +0x0000E7A6 0x80FC # 0 +0x0000E7A7 0x8171 # 0 +0x0000E7A8 0x816E # 0 +0x0000E7A9 0x8165 # 0 +0x0000E7AA 0x8166 # 0 +0x0000E7AB 0x8174 # 0 +0x0000E7AC 0x8183 # 0 +0x0000E7AD 0x8188 # 0 +0x0000E7AE 0x818A # 0 +0x0000E7AF 0x8180 # 0 +0x0000E7B0 0x8182 # 0 +0x0000E7B1 0x81A0 # 0 +0x0000E7B2 0x8195 # 0 +0x0000E7B3 0x81A4 # 0 +0x0000E7B4 0x81A3 # 0 +0x0000E7B5 0x815F # 0 +0x0000E7B6 0x8193 # 0 +0x0000E7B7 0x81A9 # 0 +0x0000E7B8 0x81B0 # 0 +0x0000E7B9 0x81B5 # 0 +0x0000E7BA 0x81BE # 0 +0x0000E7BB 0x81B8 # 0 +0x0000E7BC 0x81BD # 0 +0x0000E7BD 0x81C0 # 0 +0x0000E7BE 0x81C2 # 0 +0x0000E7BF 0x81BA # 0 +0x0000E7C0 0x81C9 # 0 +0x0000E7C1 0x81CD # 0 +0x0000E7C2 0x81D1 # 0 +0x0000E7C3 0x81D9 # 0 +0x0000E7C4 0x81D8 # 0 +0x0000E7C5 0x81C8 # 0 +0x0000E7C6 0x81DA # 0 +0x0000E7C7 0x81DF # 0 +0x0000E7C8 0x81E0 # 0 +0x0000E7C9 0x81E7 # 0 +0x0000E7CA 0x81FA # 0 +0x0000E7CB 0x81FB # 0 +0x0000E7CC 0x81FE # 0 +0x0000E7CD 0x8201 # 0 +0x0000E7CE 0x8202 # 0 +0x0000E7CF 0x8205 # 0 +0x0000E7D0 0x8207 # 0 +0x0000E7D1 0x820A # 0 +0x0000E7D2 0x820D # 0 +0x0000E7D3 0x8210 # 0 +0x0000E7D4 0x8216 # 0 +0x0000E7D5 0x8229 # 0 +0x0000E7D6 0x822B # 0 +0x0000E7D7 0x8238 # 0 +0x0000E7D8 0x8233 # 0 +0x0000E7D9 0x8240 # 0 +0x0000E7DA 0x8259 # 0 +0x0000E7DB 0x8258 # 0 +0x0000E7DC 0x825D # 0 +0x0000E7DD 0x825A # 0 +0x0000E7DE 0x825F # 0 +0x0000E7DF 0x8264 # 0 +0x0000E7E0 0x8262 # 0 +0x0000E7E1 0x8268 # 0 +0x0000E7E2 0x826A # 0 +0x0000E7E3 0x826B # 0 +0x0000E7E4 0x822E # 0 +0x0000E7E5 0x8271 # 0 +0x0000E7E6 0x8277 # 0 +0x0000E7E7 0x8278 # 0 +0x0000E7E8 0x827E # 0 +0x0000E7E9 0x828D # 0 +0x0000E7EA 0x8292 # 0 +0x0000E7EB 0x82AB # 0 +0x0000E7EC 0x829F # 0 +0x0000E7ED 0x82BB # 0 +0x0000E7EE 0x82AC # 0 +0x0000E7EF 0x82E1 # 0 +0x0000E7F0 0x82E3 # 0 +0x0000E7F1 0x82DF # 0 +0x0000E7F2 0x82D2 # 0 +0x0000E7F3 0x82F4 # 0 +0x0000E7F4 0x82F3 # 0 +0x0000E7F5 0x82FA # 0 +0x0000E7F6 0x8393 # 0 +0x0000E7F7 0x8303 # 0 +0x0000E7F8 0x82FB # 0 +0x0000E7F9 0x82F9 # 0 +0x0000E7FA 0x82DE # 0 +0x0000E7FB 0x8306 # 0 +0x0000E7FC 0x82DC # 0 +0x0000E7FD 0x8309 # 0 +0x0000E7FE 0x82D9 # 0 +0x0000E8A1 0x8335 # 0 +0x0000E8A2 0x8334 # 0 +0x0000E8A3 0x8316 # 0 +0x0000E8A4 0x8332 # 0 +0x0000E8A5 0x8331 # 0 +0x0000E8A6 0x8340 # 0 +0x0000E8A7 0x8339 # 0 +0x0000E8A8 0x8350 # 0 +0x0000E8A9 0x8345 # 0 +0x0000E8AA 0x832F # 0 +0x0000E8AB 0x832B # 0 +0x0000E8AC 0x8317 # 0 +0x0000E8AD 0x8318 # 0 +0x0000E8AE 0x8385 # 0 +0x0000E8AF 0x839A # 0 +0x0000E8B0 0x83AA # 0 +0x0000E8B1 0x839F # 0 +0x0000E8B2 0x83A2 # 0 +0x0000E8B3 0x8396 # 0 +0x0000E8B4 0x8323 # 0 +0x0000E8B5 0x838E # 0 +0x0000E8B6 0x8387 # 0 +0x0000E8B7 0x838A # 0 +0x0000E8B8 0x837C # 0 +0x0000E8B9 0x83B5 # 0 +0x0000E8BA 0x8373 # 0 +0x0000E8BB 0x8375 # 0 +0x0000E8BC 0x83A0 # 0 +0x0000E8BD 0x8389 # 0 +0x0000E8BE 0x83A8 # 0 +0x0000E8BF 0x83F4 # 0 +0x0000E8C0 0x8413 # 0 +0x0000E8C1 0x83EB # 0 +0x0000E8C2 0x83CE # 0 +0x0000E8C3 0x83FD # 0 +0x0000E8C4 0x8403 # 0 +0x0000E8C5 0x83D8 # 0 +0x0000E8C6 0x840B # 0 +0x0000E8C7 0x83C1 # 0 +0x0000E8C8 0x83F7 # 0 +0x0000E8C9 0x8407 # 0 +0x0000E8CA 0x83E0 # 0 +0x0000E8CB 0x83F2 # 0 +0x0000E8CC 0x840D # 0 +0x0000E8CD 0x8422 # 0 +0x0000E8CE 0x8420 # 0 +0x0000E8CF 0x83BD # 0 +0x0000E8D0 0x8438 # 0 +0x0000E8D1 0x8506 # 0 +0x0000E8D2 0x83FB # 0 +0x0000E8D3 0x846D # 0 +0x0000E8D4 0x842A # 0 +0x0000E8D5 0x843C # 0 +0x0000E8D6 0x855A # 0 +0x0000E8D7 0x8484 # 0 +0x0000E8D8 0x8477 # 0 +0x0000E8D9 0x846B # 0 +0x0000E8DA 0x84AD # 0 +0x0000E8DB 0x846E # 0 +0x0000E8DC 0x8482 # 0 +0x0000E8DD 0x8469 # 0 +0x0000E8DE 0x8446 # 0 +0x0000E8DF 0x842C # 0 +0x0000E8E0 0x846F # 0 +0x0000E8E1 0x8479 # 0 +0x0000E8E2 0x8435 # 0 +0x0000E8E3 0x84CA # 0 +0x0000E8E4 0x8462 # 0 +0x0000E8E5 0x84B9 # 0 +0x0000E8E6 0x84BF # 0 +0x0000E8E7 0x849F # 0 +0x0000E8E8 0x84D9 # 0 +0x0000E8E9 0x84CD # 0 +0x0000E8EA 0x84BB # 0 +0x0000E8EB 0x84DA # 0 +0x0000E8EC 0x84D0 # 0 +0x0000E8ED 0x84C1 # 0 +0x0000E8EE 0x84C6 # 0 +0x0000E8EF 0x84D6 # 0 +0x0000E8F0 0x84A1 # 0 +0x0000E8F1 0x8521 # 0 +0x0000E8F2 0x84FF # 0 +0x0000E8F3 0x84F4 # 0 +0x0000E8F4 0x8517 # 0 +0x0000E8F5 0x8518 # 0 +0x0000E8F6 0x852C # 0 +0x0000E8F7 0x851F # 0 +0x0000E8F8 0x8515 # 0 +0x0000E8F9 0x8514 # 0 +0x0000E8FA 0x84FC # 0 +0x0000E8FB 0x8540 # 0 +0x0000E8FC 0x8563 # 0 +0x0000E8FD 0x8558 # 0 +0x0000E8FE 0x8548 # 0 +0x0000E9A1 0x8541 # 0 +0x0000E9A2 0x8602 # 0 +0x0000E9A3 0x854B # 0 +0x0000E9A4 0x8555 # 0 +0x0000E9A5 0x8580 # 0 +0x0000E9A6 0x85A4 # 0 +0x0000E9A7 0x8588 # 0 +0x0000E9A8 0x8591 # 0 +0x0000E9A9 0x858A # 0 +0x0000E9AA 0x85A8 # 0 +0x0000E9AB 0x856D # 0 +0x0000E9AC 0x8594 # 0 +0x0000E9AD 0x859B # 0 +0x0000E9AE 0x85EA # 0 +0x0000E9AF 0x8587 # 0 +0x0000E9B0 0x859C # 0 +0x0000E9B1 0x8577 # 0 +0x0000E9B2 0x857E # 0 +0x0000E9B3 0x8590 # 0 +0x0000E9B4 0x85C9 # 0 +0x0000E9B5 0x85BA # 0 +0x0000E9B6 0x85CF # 0 +0x0000E9B7 0x85B9 # 0 +0x0000E9B8 0x85D0 # 0 +0x0000E9B9 0x85D5 # 0 +0x0000E9BA 0x85DD # 0 +0x0000E9BB 0x85E5 # 0 +0x0000E9BC 0x85DC # 0 +0x0000E9BD 0x85F9 # 0 +0x0000E9BE 0x860A # 0 +0x0000E9BF 0x8613 # 0 +0x0000E9C0 0x860B # 0 +0x0000E9C1 0x85FE # 0 +0x0000E9C2 0x85FA # 0 +0x0000E9C3 0x8606 # 0 +0x0000E9C4 0x8622 # 0 +0x0000E9C5 0x861A # 0 +0x0000E9C6 0x8630 # 0 +0x0000E9C7 0x863F # 0 +0x0000E9C8 0x864D # 0 +0x0000E9C9 0x4E55 # 0 +0x0000E9CA 0x8654 # 0 +0x0000E9CB 0x865F # 0 +0x0000E9CC 0x8667 # 0 +0x0000E9CD 0x8671 # 0 +0x0000E9CE 0x8693 # 0 +0x0000E9CF 0x86A3 # 0 +0x0000E9D0 0x86A9 # 0 +0x0000E9D1 0x86AA # 0 +0x0000E9D2 0x868B # 0 +0x0000E9D3 0x868C # 0 +0x0000E9D4 0x86B6 # 0 +0x0000E9D5 0x86AF # 0 +0x0000E9D6 0x86C4 # 0 +0x0000E9D7 0x86C6 # 0 +0x0000E9D8 0x86B0 # 0 +0x0000E9D9 0x86C9 # 0 +0x0000E9DA 0x8823 # 0 +0x0000E9DB 0x86AB # 0 +0x0000E9DC 0x86D4 # 0 +0x0000E9DD 0x86DE # 0 +0x0000E9DE 0x86E9 # 0 +0x0000E9DF 0x86EC # 0 +0x0000E9E0 0x86DF # 0 +0x0000E9E1 0x86DB # 0 +0x0000E9E2 0x86EF # 0 +0x0000E9E3 0x8712 # 0 +0x0000E9E4 0x8706 # 0 +0x0000E9E5 0x8708 # 0 +0x0000E9E6 0x8700 # 0 +0x0000E9E7 0x8703 # 0 +0x0000E9E8 0x86FB # 0 +0x0000E9E9 0x8711 # 0 +0x0000E9EA 0x8709 # 0 +0x0000E9EB 0x870D # 0 +0x0000E9EC 0x86F9 # 0 +0x0000E9ED 0x870A # 0 +0x0000E9EE 0x8734 # 0 +0x0000E9EF 0x873F # 0 +0x0000E9F0 0x8737 # 0 +0x0000E9F1 0x873B # 0 +0x0000E9F2 0x8725 # 0 +0x0000E9F3 0x8729 # 0 +0x0000E9F4 0x871A # 0 +0x0000E9F5 0x8760 # 0 +0x0000E9F6 0x875F # 0 +0x0000E9F7 0x8778 # 0 +0x0000E9F8 0x874C # 0 +0x0000E9F9 0x874E # 0 +0x0000E9FA 0x8774 # 0 +0x0000E9FB 0x8757 # 0 +0x0000E9FC 0x8768 # 0 +0x0000E9FD 0x876E # 0 +0x0000E9FE 0x8759 # 0 +0x0000EAA1 0x8753 # 0 +0x0000EAA2 0x8763 # 0 +0x0000EAA3 0x876A # 0 +0x0000EAA4 0x8805 # 0 +0x0000EAA5 0x87A2 # 0 +0x0000EAA6 0x879F # 0 +0x0000EAA7 0x8782 # 0 +0x0000EAA8 0x87AF # 0 +0x0000EAA9 0x87CB # 0 +0x0000EAAA 0x87BD # 0 +0x0000EAAB 0x87C0 # 0 +0x0000EAAC 0x87D0 # 0 +0x0000EAAD 0x96D6 # 0 +0x0000EAAE 0x87AB # 0 +0x0000EAAF 0x87C4 # 0 +0x0000EAB0 0x87B3 # 0 +0x0000EAB1 0x87C7 # 0 +0x0000EAB2 0x87C6 # 0 +0x0000EAB3 0x87BB # 0 +0x0000EAB4 0x87EF # 0 +0x0000EAB5 0x87F2 # 0 +0x0000EAB6 0x87E0 # 0 +0x0000EAB7 0x880F # 0 +0x0000EAB8 0x880D # 0 +0x0000EAB9 0x87FE # 0 +0x0000EABA 0x87F6 # 0 +0x0000EABB 0x87F7 # 0 +0x0000EABC 0x880E # 0 +0x0000EABD 0x87D2 # 0 +0x0000EABE 0x8811 # 0 +0x0000EABF 0x8816 # 0 +0x0000EAC0 0x8815 # 0 +0x0000EAC1 0x8822 # 0 +0x0000EAC2 0x8821 # 0 +0x0000EAC3 0x8831 # 0 +0x0000EAC4 0x8836 # 0 +0x0000EAC5 0x8839 # 0 +0x0000EAC6 0x8827 # 0 +0x0000EAC7 0x883B # 0 +0x0000EAC8 0x8844 # 0 +0x0000EAC9 0x8842 # 0 +0x0000EACA 0x8852 # 0 +0x0000EACB 0x8859 # 0 +0x0000EACC 0x885E # 0 +0x0000EACD 0x8862 # 0 +0x0000EACE 0x886B # 0 +0x0000EACF 0x8881 # 0 +0x0000EAD0 0x887E # 0 +0x0000EAD1 0x889E # 0 +0x0000EAD2 0x8875 # 0 +0x0000EAD3 0x887D # 0 +0x0000EAD4 0x88B5 # 0 +0x0000EAD5 0x8872 # 0 +0x0000EAD6 0x8882 # 0 +0x0000EAD7 0x8897 # 0 +0x0000EAD8 0x8892 # 0 +0x0000EAD9 0x88AE # 0 +0x0000EADA 0x8899 # 0 +0x0000EADB 0x88A2 # 0 +0x0000EADC 0x888D # 0 +0x0000EADD 0x88A4 # 0 +0x0000EADE 0x88B0 # 0 +0x0000EADF 0x88BF # 0 +0x0000EAE0 0x88B1 # 0 +0x0000EAE1 0x88C3 # 0 +0x0000EAE2 0x88C4 # 0 +0x0000EAE3 0x88D4 # 0 +0x0000EAE4 0x88D8 # 0 +0x0000EAE5 0x88D9 # 0 +0x0000EAE6 0x88DD # 0 +0x0000EAE7 0x88F9 # 0 +0x0000EAE8 0x8902 # 0 +0x0000EAE9 0x88FC # 0 +0x0000EAEA 0x88F4 # 0 +0x0000EAEB 0x88E8 # 0 +0x0000EAEC 0x88F2 # 0 +0x0000EAED 0x8904 # 0 +0x0000EAEE 0x890C # 0 +0x0000EAEF 0x890A # 0 +0x0000EAF0 0x8913 # 0 +0x0000EAF1 0x8943 # 0 +0x0000EAF2 0x891E # 0 +0x0000EAF3 0x8925 # 0 +0x0000EAF4 0x892A # 0 +0x0000EAF5 0x892B # 0 +0x0000EAF6 0x8941 # 0 +0x0000EAF7 0x8944 # 0 +0x0000EAF8 0x893B # 0 +0x0000EAF9 0x8936 # 0 +0x0000EAFA 0x8938 # 0 +0x0000EAFB 0x894C # 0 +0x0000EAFC 0x891D # 0 +0x0000EAFD 0x8960 # 0 +0x0000EAFE 0x895E # 0 +0x0000EBA1 0x8966 # 0 +0x0000EBA2 0x8964 # 0 +0x0000EBA3 0x896D # 0 +0x0000EBA4 0x896A # 0 +0x0000EBA5 0x896F # 0 +0x0000EBA6 0x8974 # 0 +0x0000EBA7 0x8977 # 0 +0x0000EBA8 0x897E # 0 +0x0000EBA9 0x8983 # 0 +0x0000EBAA 0x8988 # 0 +0x0000EBAB 0x898A # 0 +0x0000EBAC 0x8993 # 0 +0x0000EBAD 0x8998 # 0 +0x0000EBAE 0x89A1 # 0 +0x0000EBAF 0x89A9 # 0 +0x0000EBB0 0x89A6 # 0 +0x0000EBB1 0x89AC # 0 +0x0000EBB2 0x89AF # 0 +0x0000EBB3 0x89B2 # 0 +0x0000EBB4 0x89BA # 0 +0x0000EBB5 0x89BD # 0 +0x0000EBB6 0x89BF # 0 +0x0000EBB7 0x89C0 # 0 +0x0000EBB8 0x89DA # 0 +0x0000EBB9 0x89DC # 0 +0x0000EBBA 0x89DD # 0 +0x0000EBBB 0x89E7 # 0 +0x0000EBBC 0x89F4 # 0 +0x0000EBBD 0x89F8 # 0 +0x0000EBBE 0x8A03 # 0 +0x0000EBBF 0x8A16 # 0 +0x0000EBC0 0x8A10 # 0 +0x0000EBC1 0x8A0C # 0 +0x0000EBC2 0x8A1B # 0 +0x0000EBC3 0x8A1D # 0 +0x0000EBC4 0x8A25 # 0 +0x0000EBC5 0x8A36 # 0 +0x0000EBC6 0x8A41 # 0 +0x0000EBC7 0x8A5B # 0 +0x0000EBC8 0x8A52 # 0 +0x0000EBC9 0x8A46 # 0 +0x0000EBCA 0x8A48 # 0 +0x0000EBCB 0x8A7C # 0 +0x0000EBCC 0x8A6D # 0 +0x0000EBCD 0x8A6C # 0 +0x0000EBCE 0x8A62 # 0 +0x0000EBCF 0x8A85 # 0 +0x0000EBD0 0x8A82 # 0 +0x0000EBD1 0x8A84 # 0 +0x0000EBD2 0x8AA8 # 0 +0x0000EBD3 0x8AA1 # 0 +0x0000EBD4 0x8A91 # 0 +0x0000EBD5 0x8AA5 # 0 +0x0000EBD6 0x8AA6 # 0 +0x0000EBD7 0x8A9A # 0 +0x0000EBD8 0x8AA3 # 0 +0x0000EBD9 0x8AC4 # 0 +0x0000EBDA 0x8ACD # 0 +0x0000EBDB 0x8AC2 # 0 +0x0000EBDC 0x8ADA # 0 +0x0000EBDD 0x8AEB # 0 +0x0000EBDE 0x8AF3 # 0 +0x0000EBDF 0x8AE7 # 0 +0x0000EBE0 0x8AE4 # 0 +0x0000EBE1 0x8AF1 # 0 +0x0000EBE2 0x8B14 # 0 +0x0000EBE3 0x8AE0 # 0 +0x0000EBE4 0x8AE2 # 0 +0x0000EBE5 0x8AF7 # 0 +0x0000EBE6 0x8ADE # 0 +0x0000EBE7 0x8ADB # 0 +0x0000EBE8 0x8B0C # 0 +0x0000EBE9 0x8B07 # 0 +0x0000EBEA 0x8B1A # 0 +0x0000EBEB 0x8AE1 # 0 +0x0000EBEC 0x8B16 # 0 +0x0000EBED 0x8B10 # 0 +0x0000EBEE 0x8B17 # 0 +0x0000EBEF 0x8B20 # 0 +0x0000EBF0 0x8B33 # 0 +0x0000EBF1 0x97AB # 0 +0x0000EBF2 0x8B26 # 0 +0x0000EBF3 0x8B2B # 0 +0x0000EBF4 0x8B3E # 0 +0x0000EBF5 0x8B28 # 0 +0x0000EBF6 0x8B41 # 0 +0x0000EBF7 0x8B4C # 0 +0x0000EBF8 0x8B4F # 0 +0x0000EBF9 0x8B4E # 0 +0x0000EBFA 0x8B49 # 0 +0x0000EBFB 0x8B56 # 0 +0x0000EBFC 0x8B5B # 0 +0x0000EBFD 0x8B5A # 0 +0x0000EBFE 0x8B6B # 0 +0x0000ECA1 0x8B5F # 0 +0x0000ECA2 0x8B6C # 0 +0x0000ECA3 0x8B6F # 0 +0x0000ECA4 0x8B74 # 0 +0x0000ECA5 0x8B7D # 0 +0x0000ECA6 0x8B80 # 0 +0x0000ECA7 0x8B8C # 0 +0x0000ECA8 0x8B8E # 0 +0x0000ECA9 0x8B92 # 0 +0x0000ECAA 0x8B93 # 0 +0x0000ECAB 0x8B96 # 0 +0x0000ECAC 0x8B99 # 0 +0x0000ECAD 0x8B9A # 0 +0x0000ECAE 0x8C3A # 0 +0x0000ECAF 0x8C41 # 0 +0x0000ECB0 0x8C3F # 0 +0x0000ECB1 0x8C48 # 0 +0x0000ECB2 0x8C4C # 0 +0x0000ECB3 0x8C4E # 0 +0x0000ECB4 0x8C50 # 0 +0x0000ECB5 0x8C55 # 0 +0x0000ECB6 0x8C62 # 0 +0x0000ECB7 0x8C6C # 0 +0x0000ECB8 0x8C78 # 0 +0x0000ECB9 0x8C7A # 0 +0x0000ECBA 0x8C82 # 0 +0x0000ECBB 0x8C89 # 0 +0x0000ECBC 0x8C85 # 0 +0x0000ECBD 0x8C8A # 0 +0x0000ECBE 0x8C8D # 0 +0x0000ECBF 0x8C8E # 0 +0x0000ECC0 0x8C94 # 0 +0x0000ECC1 0x8C7C # 0 +0x0000ECC2 0x8C98 # 0 +0x0000ECC3 0x621D # 0 +0x0000ECC4 0x8CAD # 0 +0x0000ECC5 0x8CAA # 0 +0x0000ECC6 0x8CBD # 0 +0x0000ECC7 0x8CB2 # 0 +0x0000ECC8 0x8CB3 # 0 +0x0000ECC9 0x8CAE # 0 +0x0000ECCA 0x8CB6 # 0 +0x0000ECCB 0x8CC8 # 0 +0x0000ECCC 0x8CC1 # 0 +0x0000ECCD 0x8CE4 # 0 +0x0000ECCE 0x8CE3 # 0 +0x0000ECCF 0x8CDA # 0 +0x0000ECD0 0x8CFD # 0 +0x0000ECD1 0x8CFA # 0 +0x0000ECD2 0x8CFB # 0 +0x0000ECD3 0x8D04 # 0 +0x0000ECD4 0x8D05 # 0 +0x0000ECD5 0x8D0A # 0 +0x0000ECD6 0x8D07 # 0 +0x0000ECD7 0x8D0F # 0 +0x0000ECD8 0x8D0D # 0 +0x0000ECD9 0x8D10 # 0 +0x0000ECDA 0x9F4E # 0 +0x0000ECDB 0x8D13 # 0 +0x0000ECDC 0x8CCD # 0 +0x0000ECDD 0x8D14 # 0 +0x0000ECDE 0x8D16 # 0 +0x0000ECDF 0x8D67 # 0 +0x0000ECE0 0x8D6D # 0 +0x0000ECE1 0x8D71 # 0 +0x0000ECE2 0x8D73 # 0 +0x0000ECE3 0x8D81 # 0 +0x0000ECE4 0x8D99 # 0 +0x0000ECE5 0x8DC2 # 0 +0x0000ECE6 0x8DBE # 0 +0x0000ECE7 0x8DBA # 0 +0x0000ECE8 0x8DCF # 0 +0x0000ECE9 0x8DDA # 0 +0x0000ECEA 0x8DD6 # 0 +0x0000ECEB 0x8DCC # 0 +0x0000ECEC 0x8DDB # 0 +0x0000ECED 0x8DCB # 0 +0x0000ECEE 0x8DEA # 0 +0x0000ECEF 0x8DEB # 0 +0x0000ECF0 0x8DDF # 0 +0x0000ECF1 0x8DE3 # 0 +0x0000ECF2 0x8DFC # 0 +0x0000ECF3 0x8E08 # 0 +0x0000ECF4 0x8E09 # 0 +0x0000ECF5 0x8DFF # 0 +0x0000ECF6 0x8E1D # 0 +0x0000ECF7 0x8E1E # 0 +0x0000ECF8 0x8E10 # 0 +0x0000ECF9 0x8E1F # 0 +0x0000ECFA 0x8E42 # 0 +0x0000ECFB 0x8E35 # 0 +0x0000ECFC 0x8E30 # 0 +0x0000ECFD 0x8E34 # 0 +0x0000ECFE 0x8E4A # 0 +0x0000EDA1 0x8E47 # 0 +0x0000EDA2 0x8E49 # 0 +0x0000EDA3 0x8E4C # 0 +0x0000EDA4 0x8E50 # 0 +0x0000EDA5 0x8E48 # 0 +0x0000EDA6 0x8E59 # 0 +0x0000EDA7 0x8E64 # 0 +0x0000EDA8 0x8E60 # 0 +0x0000EDA9 0x8E2A # 0 +0x0000EDAA 0x8E63 # 0 +0x0000EDAB 0x8E55 # 0 +0x0000EDAC 0x8E76 # 0 +0x0000EDAD 0x8E72 # 0 +0x0000EDAE 0x8E7C # 0 +0x0000EDAF 0x8E81 # 0 +0x0000EDB0 0x8E87 # 0 +0x0000EDB1 0x8E85 # 0 +0x0000EDB2 0x8E84 # 0 +0x0000EDB3 0x8E8B # 0 +0x0000EDB4 0x8E8A # 0 +0x0000EDB5 0x8E93 # 0 +0x0000EDB6 0x8E91 # 0 +0x0000EDB7 0x8E94 # 0 +0x0000EDB8 0x8E99 # 0 +0x0000EDB9 0x8EAA # 0 +0x0000EDBA 0x8EA1 # 0 +0x0000EDBB 0x8EAC # 0 +0x0000EDBC 0x8EB0 # 0 +0x0000EDBD 0x8EC6 # 0 +0x0000EDBE 0x8EB1 # 0 +0x0000EDBF 0x8EBE # 0 +0x0000EDC0 0x8EC5 # 0 +0x0000EDC1 0x8EC8 # 0 +0x0000EDC2 0x8ECB # 0 +0x0000EDC3 0x8EDB # 0 +0x0000EDC4 0x8EE3 # 0 +0x0000EDC5 0x8EFC # 0 +0x0000EDC6 0x8EFB # 0 +0x0000EDC7 0x8EEB # 0 +0x0000EDC8 0x8EFE # 0 +0x0000EDC9 0x8F0A # 0 +0x0000EDCA 0x8F05 # 0 +0x0000EDCB 0x8F15 # 0 +0x0000EDCC 0x8F12 # 0 +0x0000EDCD 0x8F19 # 0 +0x0000EDCE 0x8F13 # 0 +0x0000EDCF 0x8F1C # 0 +0x0000EDD0 0x8F1F # 0 +0x0000EDD1 0x8F1B # 0 +0x0000EDD2 0x8F0C # 0 +0x0000EDD3 0x8F26 # 0 +0x0000EDD4 0x8F33 # 0 +0x0000EDD5 0x8F3B # 0 +0x0000EDD6 0x8F39 # 0 +0x0000EDD7 0x8F45 # 0 +0x0000EDD8 0x8F42 # 0 +0x0000EDD9 0x8F3E # 0 +0x0000EDDA 0x8F4C # 0 +0x0000EDDB 0x8F49 # 0 +0x0000EDDC 0x8F46 # 0 +0x0000EDDD 0x8F4E # 0 +0x0000EDDE 0x8F57 # 0 +0x0000EDDF 0x8F5C # 0 +0x0000EDE0 0x8F62 # 0 +0x0000EDE1 0x8F63 # 0 +0x0000EDE2 0x8F64 # 0 +0x0000EDE3 0x8F9C # 0 +0x0000EDE4 0x8F9F # 0 +0x0000EDE5 0x8FA3 # 0 +0x0000EDE6 0x8FAD # 0 +0x0000EDE7 0x8FAF # 0 +0x0000EDE8 0x8FB7 # 0 +0x0000EDE9 0x8FDA # 0 +0x0000EDEA 0x8FE5 # 0 +0x0000EDEB 0x8FE2 # 0 +0x0000EDEC 0x8FEA # 0 +0x0000EDED 0x8FEF # 0 +0x0000EDEE 0x9087 # 0 +0x0000EDEF 0x8FF4 # 0 +0x0000EDF0 0x9005 # 0 +0x0000EDF1 0x8FF9 # 0 +0x0000EDF2 0x8FFA # 0 +0x0000EDF3 0x9011 # 0 +0x0000EDF4 0x9015 # 0 +0x0000EDF5 0x9021 # 0 +0x0000EDF6 0x900D # 0 +0x0000EDF7 0x901E # 0 +0x0000EDF8 0x9016 # 0 +0x0000EDF9 0x900B # 0 +0x0000EDFA 0x9027 # 0 +0x0000EDFB 0x9036 # 0 +0x0000EDFC 0x9035 # 0 +0x0000EDFD 0x9039 # 0 +0x0000EDFE 0x8FF8 # 0 +0x0000EEA1 0x904F # 0 +0x0000EEA2 0x9050 # 0 +0x0000EEA3 0x9051 # 0 +0x0000EEA4 0x9052 # 0 +0x0000EEA5 0x900E # 0 +0x0000EEA6 0x9049 # 0 +0x0000EEA7 0x903E # 0 +0x0000EEA8 0x9056 # 0 +0x0000EEA9 0x9058 # 0 +0x0000EEAA 0x905E # 0 +0x0000EEAB 0x9068 # 0 +0x0000EEAC 0x906F # 0 +0x0000EEAD 0x9076 # 0 +0x0000EEAE 0x96A8 # 0 +0x0000EEAF 0x9072 # 0 +0x0000EEB0 0x9082 # 0 +0x0000EEB1 0x907D # 0 +0x0000EEB2 0x9081 # 0 +0x0000EEB3 0x9080 # 0 +0x0000EEB4 0x908A # 0 +0x0000EEB5 0x9089 # 0 +0x0000EEB6 0x908F # 0 +0x0000EEB7 0x90A8 # 0 +0x0000EEB8 0x90AF # 0 +0x0000EEB9 0x90B1 # 0 +0x0000EEBA 0x90B5 # 0 +0x0000EEBB 0x90E2 # 0 +0x0000EEBC 0x90E4 # 0 +0x0000EEBD 0x6248 # 0 +0x0000EEBE 0x90DB # 0 +0x0000EEBF 0x9102 # 0 +0x0000EEC0 0x9112 # 0 +0x0000EEC1 0x9119 # 0 +0x0000EEC2 0x9132 # 0 +0x0000EEC3 0x9130 # 0 +0x0000EEC4 0x914A # 0 +0x0000EEC5 0x9156 # 0 +0x0000EEC6 0x9158 # 0 +0x0000EEC7 0x9163 # 0 +0x0000EEC8 0x9165 # 0 +0x0000EEC9 0x9169 # 0 +0x0000EECA 0x9173 # 0 +0x0000EECB 0x9172 # 0 +0x0000EECC 0x918B # 0 +0x0000EECD 0x9189 # 0 +0x0000EECE 0x9182 # 0 +0x0000EECF 0x91A2 # 0 +0x0000EED0 0x91AB # 0 +0x0000EED1 0x91AF # 0 +0x0000EED2 0x91AA # 0 +0x0000EED3 0x91B5 # 0 +0x0000EED4 0x91B4 # 0 +0x0000EED5 0x91BA # 0 +0x0000EED6 0x91C0 # 0 +0x0000EED7 0x91C1 # 0 +0x0000EED8 0x91C9 # 0 +0x0000EED9 0x91CB # 0 +0x0000EEDA 0x91D0 # 0 +0x0000EEDB 0x91D6 # 0 +0x0000EEDC 0x91DF # 0 +0x0000EEDD 0x91E1 # 0 +0x0000EEDE 0x91DB # 0 +0x0000EEDF 0x91FC # 0 +0x0000EEE0 0x91F5 # 0 +0x0000EEE1 0x91F6 # 0 +0x0000EEE2 0x921E # 0 +0x0000EEE3 0x91FF # 0 +0x0000EEE4 0x9214 # 0 +0x0000EEE5 0x922C # 0 +0x0000EEE6 0x9215 # 0 +0x0000EEE7 0x9211 # 0 +0x0000EEE8 0x925E # 0 +0x0000EEE9 0x9257 # 0 +0x0000EEEA 0x9245 # 0 +0x0000EEEB 0x9249 # 0 +0x0000EEEC 0x9264 # 0 +0x0000EEED 0x9248 # 0 +0x0000EEEE 0x9295 # 0 +0x0000EEEF 0x923F # 0 +0x0000EEF0 0x924B # 0 +0x0000EEF1 0x9250 # 0 +0x0000EEF2 0x929C # 0 +0x0000EEF3 0x9296 # 0 +0x0000EEF4 0x9293 # 0 +0x0000EEF5 0x929B # 0 +0x0000EEF6 0x925A # 0 +0x0000EEF7 0x92CF # 0 +0x0000EEF8 0x92B9 # 0 +0x0000EEF9 0x92B7 # 0 +0x0000EEFA 0x92E9 # 0 +0x0000EEFB 0x930F # 0 +0x0000EEFC 0x92FA # 0 +0x0000EEFD 0x9344 # 0 +0x0000EEFE 0x932E # 0 +0x0000EFA1 0x9319 # 0 +0x0000EFA2 0x9322 # 0 +0x0000EFA3 0x931A # 0 +0x0000EFA4 0x9323 # 0 +0x0000EFA5 0x933A # 0 +0x0000EFA6 0x9335 # 0 +0x0000EFA7 0x933B # 0 +0x0000EFA8 0x935C # 0 +0x0000EFA9 0x9360 # 0 +0x0000EFAA 0x937C # 0 +0x0000EFAB 0x936E # 0 +0x0000EFAC 0x9356 # 0 +0x0000EFAD 0x93B0 # 0 +0x0000EFAE 0x93AC # 0 +0x0000EFAF 0x93AD # 0 +0x0000EFB0 0x9394 # 0 +0x0000EFB1 0x93B9 # 0 +0x0000EFB2 0x93D6 # 0 +0x0000EFB3 0x93D7 # 0 +0x0000EFB4 0x93E8 # 0 +0x0000EFB5 0x93E5 # 0 +0x0000EFB6 0x93D8 # 0 +0x0000EFB7 0x93C3 # 0 +0x0000EFB8 0x93DD # 0 +0x0000EFB9 0x93D0 # 0 +0x0000EFBA 0x93C8 # 0 +0x0000EFBB 0x93E4 # 0 +0x0000EFBC 0x941A # 0 +0x0000EFBD 0x9414 # 0 +0x0000EFBE 0x9413 # 0 +0x0000EFBF 0x9403 # 0 +0x0000EFC0 0x9407 # 0 +0x0000EFC1 0x9410 # 0 +0x0000EFC2 0x9436 # 0 +0x0000EFC3 0x942B # 0 +0x0000EFC4 0x9435 # 0 +0x0000EFC5 0x9421 # 0 +0x0000EFC6 0x943A # 0 +0x0000EFC7 0x9441 # 0 +0x0000EFC8 0x9452 # 0 +0x0000EFC9 0x9444 # 0 +0x0000EFCA 0x945B # 0 +0x0000EFCB 0x9460 # 0 +0x0000EFCC 0x9462 # 0 +0x0000EFCD 0x945E # 0 +0x0000EFCE 0x946A # 0 +0x0000EFCF 0x9229 # 0 +0x0000EFD0 0x9470 # 0 +0x0000EFD1 0x9475 # 0 +0x0000EFD2 0x9477 # 0 +0x0000EFD3 0x947D # 0 +0x0000EFD4 0x945A # 0 +0x0000EFD5 0x947C # 0 +0x0000EFD6 0x947E # 0 +0x0000EFD7 0x9481 # 0 +0x0000EFD8 0x947F # 0 +0x0000EFD9 0x9582 # 0 +0x0000EFDA 0x9587 # 0 +0x0000EFDB 0x958A # 0 +0x0000EFDC 0x9594 # 0 +0x0000EFDD 0x9596 # 0 +0x0000EFDE 0x9598 # 0 +0x0000EFDF 0x9599 # 0 +0x0000EFE0 0x95A0 # 0 +0x0000EFE1 0x95A8 # 0 +0x0000EFE2 0x95A7 # 0 +0x0000EFE3 0x95AD # 0 +0x0000EFE4 0x95BC # 0 +0x0000EFE5 0x95BB # 0 +0x0000EFE6 0x95B9 # 0 +0x0000EFE7 0x95BE # 0 +0x0000EFE8 0x95CA # 0 +0x0000EFE9 0x6FF6 # 0 +0x0000EFEA 0x95C3 # 0 +0x0000EFEB 0x95CD # 0 +0x0000EFEC 0x95CC # 0 +0x0000EFED 0x95D5 # 0 +0x0000EFEE 0x95D4 # 0 +0x0000EFEF 0x95D6 # 0 +0x0000EFF0 0x95DC # 0 +0x0000EFF1 0x95E1 # 0 +0x0000EFF2 0x95E5 # 0 +0x0000EFF3 0x95E2 # 0 +0x0000EFF4 0x9621 # 0 +0x0000EFF5 0x9628 # 0 +0x0000EFF6 0x962E # 0 +0x0000EFF7 0x962F # 0 +0x0000EFF8 0x9642 # 0 +0x0000EFF9 0x964C # 0 +0x0000EFFA 0x964F # 0 +0x0000EFFB 0x964B # 0 +0x0000EFFC 0x9677 # 0 +0x0000EFFD 0x965C # 0 +0x0000EFFE 0x965E # 0 +0x0000F0A1 0x965D # 0 +0x0000F0A2 0x965F # 0 +0x0000F0A3 0x9666 # 0 +0x0000F0A4 0x9672 # 0 +0x0000F0A5 0x966C # 0 +0x0000F0A6 0x968D # 0 +0x0000F0A7 0x9698 # 0 +0x0000F0A8 0x9695 # 0 +0x0000F0A9 0x9697 # 0 +0x0000F0AA 0x96AA # 0 +0x0000F0AB 0x96A7 # 0 +0x0000F0AC 0x96B1 # 0 +0x0000F0AD 0x96B2 # 0 +0x0000F0AE 0x96B0 # 0 +0x0000F0AF 0x96B4 # 0 +0x0000F0B0 0x96B6 # 0 +0x0000F0B1 0x96B8 # 0 +0x0000F0B2 0x96B9 # 0 +0x0000F0B3 0x96CE # 0 +0x0000F0B4 0x96CB # 0 +0x0000F0B5 0x96C9 # 0 +0x0000F0B6 0x96CD # 0 +0x0000F0B7 0x894D # 0 +0x0000F0B8 0x96DC # 0 +0x0000F0B9 0x970D # 0 +0x0000F0BA 0x96D5 # 0 +0x0000F0BB 0x96F9 # 0 +0x0000F0BC 0x9704 # 0 +0x0000F0BD 0x9706 # 0 +0x0000F0BE 0x9708 # 0 +0x0000F0BF 0x9713 # 0 +0x0000F0C0 0x970E # 0 +0x0000F0C1 0x9711 # 0 +0x0000F0C2 0x970F # 0 +0x0000F0C3 0x9716 # 0 +0x0000F0C4 0x9719 # 0 +0x0000F0C5 0x9724 # 0 +0x0000F0C6 0x972A # 0 +0x0000F0C7 0x9730 # 0 +0x0000F0C8 0x9739 # 0 +0x0000F0C9 0x973D # 0 +0x0000F0CA 0x973E # 0 +0x0000F0CB 0x9744 # 0 +0x0000F0CC 0x9746 # 0 +0x0000F0CD 0x9748 # 0 +0x0000F0CE 0x9742 # 0 +0x0000F0CF 0x9749 # 0 +0x0000F0D0 0x975C # 0 +0x0000F0D1 0x9760 # 0 +0x0000F0D2 0x9764 # 0 +0x0000F0D3 0x9766 # 0 +0x0000F0D4 0x9768 # 0 +0x0000F0D5 0x52D2 # 0 +0x0000F0D6 0x976B # 0 +0x0000F0D7 0x9771 # 0 +0x0000F0D8 0x9779 # 0 +0x0000F0D9 0x9785 # 0 +0x0000F0DA 0x977C # 0 +0x0000F0DB 0x9781 # 0 +0x0000F0DC 0x977A # 0 +0x0000F0DD 0x9786 # 0 +0x0000F0DE 0x978B # 0 +0x0000F0DF 0x978F # 0 +0x0000F0E0 0x9790 # 0 +0x0000F0E1 0x979C # 0 +0x0000F0E2 0x97A8 # 0 +0x0000F0E3 0x97A6 # 0 +0x0000F0E4 0x97A3 # 0 +0x0000F0E5 0x97B3 # 0 +0x0000F0E6 0x97B4 # 0 +0x0000F0E7 0x97C3 # 0 +0x0000F0E8 0x97C6 # 0 +0x0000F0E9 0x97C8 # 0 +0x0000F0EA 0x97CB # 0 +0x0000F0EB 0x97DC # 0 +0x0000F0EC 0x97ED # 0 +0x0000F0ED 0x9F4F # 0 +0x0000F0EE 0x97F2 # 0 +0x0000F0EF 0x7ADF # 0 +0x0000F0F0 0x97F6 # 0 +0x0000F0F1 0x97F5 # 0 +0x0000F0F2 0x980F # 0 +0x0000F0F3 0x980C # 0 +0x0000F0F4 0x9838 # 0 +0x0000F0F5 0x9824 # 0 +0x0000F0F6 0x9821 # 0 +0x0000F0F7 0x9837 # 0 +0x0000F0F8 0x983D # 0 +0x0000F0F9 0x9846 # 0 +0x0000F0FA 0x984F # 0 +0x0000F0FB 0x984B # 0 +0x0000F0FC 0x986B # 0 +0x0000F0FD 0x986F # 0 +0x0000F0FE 0x9870 # 0 +0x0000F1A1 0x9871 # 0 +0x0000F1A2 0x9874 # 0 +0x0000F1A3 0x9873 # 0 +0x0000F1A4 0x98AA # 0 +0x0000F1A5 0x98AF # 0 +0x0000F1A6 0x98B1 # 0 +0x0000F1A7 0x98B6 # 0 +0x0000F1A8 0x98C4 # 0 +0x0000F1A9 0x98C3 # 0 +0x0000F1AA 0x98C6 # 0 +0x0000F1AB 0x98E9 # 0 +0x0000F1AC 0x98EB # 0 +0x0000F1AD 0x9903 # 0 +0x0000F1AE 0x9909 # 0 +0x0000F1AF 0x9912 # 0 +0x0000F1B0 0x9914 # 0 +0x0000F1B1 0x9918 # 0 +0x0000F1B2 0x9921 # 0 +0x0000F1B3 0x991D # 0 +0x0000F1B4 0x991E # 0 +0x0000F1B5 0x9924 # 0 +0x0000F1B6 0x9920 # 0 +0x0000F1B7 0x992C # 0 +0x0000F1B8 0x992E # 0 +0x0000F1B9 0x993D # 0 +0x0000F1BA 0x993E # 0 +0x0000F1BB 0x9942 # 0 +0x0000F1BC 0x9949 # 0 +0x0000F1BD 0x9945 # 0 +0x0000F1BE 0x9950 # 0 +0x0000F1BF 0x994B # 0 +0x0000F1C0 0x9951 # 0 +0x0000F1C1 0x9952 # 0 +0x0000F1C2 0x994C # 0 +0x0000F1C3 0x9955 # 0 +0x0000F1C4 0x9997 # 0 +0x0000F1C5 0x9998 # 0 +0x0000F1C6 0x99A5 # 0 +0x0000F1C7 0x99AD # 0 +0x0000F1C8 0x99AE # 0 +0x0000F1C9 0x99BC # 0 +0x0000F1CA 0x99DF # 0 +0x0000F1CB 0x99DB # 0 +0x0000F1CC 0x99DD # 0 +0x0000F1CD 0x99D8 # 0 +0x0000F1CE 0x99D1 # 0 +0x0000F1CF 0x99ED # 0 +0x0000F1D0 0x99EE # 0 +0x0000F1D1 0x99F1 # 0 +0x0000F1D2 0x99F2 # 0 +0x0000F1D3 0x99FB # 0 +0x0000F1D4 0x99F8 # 0 +0x0000F1D5 0x9A01 # 0 +0x0000F1D6 0x9A0F # 0 +0x0000F1D7 0x9A05 # 0 +0x0000F1D8 0x99E2 # 0 +0x0000F1D9 0x9A19 # 0 +0x0000F1DA 0x9A2B # 0 +0x0000F1DB 0x9A37 # 0 +0x0000F1DC 0x9A45 # 0 +0x0000F1DD 0x9A42 # 0 +0x0000F1DE 0x9A40 # 0 +0x0000F1DF 0x9A43 # 0 +0x0000F1E0 0x9A3E # 0 +0x0000F1E1 0x9A55 # 0 +0x0000F1E2 0x9A4D # 0 +0x0000F1E3 0x9A5B # 0 +0x0000F1E4 0x9A57 # 0 +0x0000F1E5 0x9A5F # 0 +0x0000F1E6 0x9A62 # 0 +0x0000F1E7 0x9A65 # 0 +0x0000F1E8 0x9A64 # 0 +0x0000F1E9 0x9A69 # 0 +0x0000F1EA 0x9A6B # 0 +0x0000F1EB 0x9A6A # 0 +0x0000F1EC 0x9AAD # 0 +0x0000F1ED 0x9AB0 # 0 +0x0000F1EE 0x9ABC # 0 +0x0000F1EF 0x9AC0 # 0 +0x0000F1F0 0x9ACF # 0 +0x0000F1F1 0x9AD1 # 0 +0x0000F1F2 0x9AD3 # 0 +0x0000F1F3 0x9AD4 # 0 +0x0000F1F4 0x9ADE # 0 +0x0000F1F5 0x9ADF # 0 +0x0000F1F6 0x9AE2 # 0 +0x0000F1F7 0x9AE3 # 0 +0x0000F1F8 0x9AE6 # 0 +0x0000F1F9 0x9AEF # 0 +0x0000F1FA 0x9AEB # 0 +0x0000F1FB 0x9AEE # 0 +0x0000F1FC 0x9AF4 # 0 +0x0000F1FD 0x9AF1 # 0 +0x0000F1FE 0x9AF7 # 0 +0x0000F2A1 0x9AFB # 0 +0x0000F2A2 0x9B06 # 0 +0x0000F2A3 0x9B18 # 0 +0x0000F2A4 0x9B1A # 0 +0x0000F2A5 0x9B1F # 0 +0x0000F2A6 0x9B22 # 0 +0x0000F2A7 0x9B23 # 0 +0x0000F2A8 0x9B25 # 0 +0x0000F2A9 0x9B27 # 0 +0x0000F2AA 0x9B28 # 0 +0x0000F2AB 0x9B29 # 0 +0x0000F2AC 0x9B2A # 0 +0x0000F2AD 0x9B2E # 0 +0x0000F2AE 0x9B2F # 0 +0x0000F2AF 0x9B32 # 0 +0x0000F2B0 0x9B44 # 0 +0x0000F2B1 0x9B43 # 0 +0x0000F2B2 0x9B4F # 0 +0x0000F2B3 0x9B4D # 0 +0x0000F2B4 0x9B4E # 0 +0x0000F2B5 0x9B51 # 0 +0x0000F2B6 0x9B58 # 0 +0x0000F2B7 0x9B74 # 0 +0x0000F2B8 0x9B93 # 0 +0x0000F2B9 0x9B83 # 0 +0x0000F2BA 0x9B91 # 0 +0x0000F2BB 0x9B96 # 0 +0x0000F2BC 0x9B97 # 0 +0x0000F2BD 0x9B9F # 0 +0x0000F2BE 0x9BA0 # 0 +0x0000F2BF 0x9BA8 # 0 +0x0000F2C0 0x9BB4 # 0 +0x0000F2C1 0x9BC0 # 0 +0x0000F2C2 0x9BCA # 0 +0x0000F2C3 0x9BB9 # 0 +0x0000F2C4 0x9BC6 # 0 +0x0000F2C5 0x9BCF # 0 +0x0000F2C6 0x9BD1 # 0 +0x0000F2C7 0x9BD2 # 0 +0x0000F2C8 0x9BE3 # 0 +0x0000F2C9 0x9BE2 # 0 +0x0000F2CA 0x9BE4 # 0 +0x0000F2CB 0x9BD4 # 0 +0x0000F2CC 0x9BE1 # 0 +0x0000F2CD 0x9C3A # 0 +0x0000F2CE 0x9BF2 # 0 +0x0000F2CF 0x9BF1 # 0 +0x0000F2D0 0x9BF0 # 0 +0x0000F2D1 0x9C15 # 0 +0x0000F2D2 0x9C14 # 0 +0x0000F2D3 0x9C09 # 0 +0x0000F2D4 0x9C13 # 0 +0x0000F2D5 0x9C0C # 0 +0x0000F2D6 0x9C06 # 0 +0x0000F2D7 0x9C08 # 0 +0x0000F2D8 0x9C12 # 0 +0x0000F2D9 0x9C0A # 0 +0x0000F2DA 0x9C04 # 0 +0x0000F2DB 0x9C2E # 0 +0x0000F2DC 0x9C1B # 0 +0x0000F2DD 0x9C25 # 0 +0x0000F2DE 0x9C24 # 0 +0x0000F2DF 0x9C21 # 0 +0x0000F2E0 0x9C30 # 0 +0x0000F2E1 0x9C47 # 0 +0x0000F2E2 0x9C32 # 0 +0x0000F2E3 0x9C46 # 0 +0x0000F2E4 0x9C3E # 0 +0x0000F2E5 0x9C5A # 0 +0x0000F2E6 0x9C60 # 0 +0x0000F2E7 0x9C67 # 0 +0x0000F2E8 0x9C76 # 0 +0x0000F2E9 0x9C78 # 0 +0x0000F2EA 0x9CE7 # 0 +0x0000F2EB 0x9CEC # 0 +0x0000F2EC 0x9CF0 # 0 +0x0000F2ED 0x9D09 # 0 +0x0000F2EE 0x9D08 # 0 +0x0000F2EF 0x9CEB # 0 +0x0000F2F0 0x9D03 # 0 +0x0000F2F1 0x9D06 # 0 +0x0000F2F2 0x9D2A # 0 +0x0000F2F3 0x9D26 # 0 +0x0000F2F4 0x9DAF # 0 +0x0000F2F5 0x9D23 # 0 +0x0000F2F6 0x9D1F # 0 +0x0000F2F7 0x9D44 # 0 +0x0000F2F8 0x9D15 # 0 +0x0000F2F9 0x9D12 # 0 +0x0000F2FA 0x9D41 # 0 +0x0000F2FB 0x9D3F # 0 +0x0000F2FC 0x9D3E # 0 +0x0000F2FD 0x9D46 # 0 +0x0000F2FE 0x9D48 # 0 +0x0000F3A1 0x9D5D # 0 +0x0000F3A2 0x9D5E # 0 +0x0000F3A3 0x9D64 # 0 +0x0000F3A4 0x9D51 # 0 +0x0000F3A5 0x9D50 # 0 +0x0000F3A6 0x9D59 # 0 +0x0000F3A7 0x9D72 # 0 +0x0000F3A8 0x9D89 # 0 +0x0000F3A9 0x9D87 # 0 +0x0000F3AA 0x9DAB # 0 +0x0000F3AB 0x9D6F # 0 +0x0000F3AC 0x9D7A # 0 +0x0000F3AD 0x9D9A # 0 +0x0000F3AE 0x9DA4 # 0 +0x0000F3AF 0x9DA9 # 0 +0x0000F3B0 0x9DB2 # 0 +0x0000F3B1 0x9DC4 # 0 +0x0000F3B2 0x9DC1 # 0 +0x0000F3B3 0x9DBB # 0 +0x0000F3B4 0x9DB8 # 0 +0x0000F3B5 0x9DBA # 0 +0x0000F3B6 0x9DC6 # 0 +0x0000F3B7 0x9DCF # 0 +0x0000F3B8 0x9DC2 # 0 +0x0000F3B9 0x9DD9 # 0 +0x0000F3BA 0x9DD3 # 0 +0x0000F3BB 0x9DF8 # 0 +0x0000F3BC 0x9DE6 # 0 +0x0000F3BD 0x9DED # 0 +0x0000F3BE 0x9DEF # 0 +0x0000F3BF 0x9DFD # 0 +0x0000F3C0 0x9E1A # 0 +0x0000F3C1 0x9E1B # 0 +0x0000F3C2 0x9E1E # 0 +0x0000F3C3 0x9E75 # 0 +0x0000F3C4 0x9E79 # 0 +0x0000F3C5 0x9E7D # 0 +0x0000F3C6 0x9E81 # 0 +0x0000F3C7 0x9E88 # 0 +0x0000F3C8 0x9E8B # 0 +0x0000F3C9 0x9E8C # 0 +0x0000F3CA 0x9E92 # 0 +0x0000F3CB 0x9E95 # 0 +0x0000F3CC 0x9E91 # 0 +0x0000F3CD 0x9E9D # 0 +0x0000F3CE 0x9EA5 # 0 +0x0000F3CF 0x9EA9 # 0 +0x0000F3D0 0x9EB8 # 0 +0x0000F3D1 0x9EAA # 0 +0x0000F3D2 0x9EAD # 0 +0x0000F3D3 0x9761 # 0 +0x0000F3D4 0x9ECC # 0 +0x0000F3D5 0x9ECE # 0 +0x0000F3D6 0x9ECF # 0 +0x0000F3D7 0x9ED0 # 0 +0x0000F3D8 0x9ED4 # 0 +0x0000F3D9 0x9EDC # 0 +0x0000F3DA 0x9EDE # 0 +0x0000F3DB 0x9EDD # 0 +0x0000F3DC 0x9EE0 # 0 +0x0000F3DD 0x9EE5 # 0 +0x0000F3DE 0x9EE8 # 0 +0x0000F3DF 0x9EEF # 0 +0x0000F3E0 0x9EF4 # 0 +0x0000F3E1 0x9EF6 # 0 +0x0000F3E2 0x9EF7 # 0 +0x0000F3E3 0x9EF9 # 0 +0x0000F3E4 0x9EFB # 0 +0x0000F3E5 0x9EFC # 0 +0x0000F3E6 0x9EFD # 0 +0x0000F3E7 0x9F07 # 0 +0x0000F3E8 0x9F08 # 0 +0x0000F3E9 0x76B7 # 0 +0x0000F3EA 0x9F15 # 0 +0x0000F3EB 0x9F21 # 0 +0x0000F3EC 0x9F2C # 0 +0x0000F3ED 0x9F3E # 0 +0x0000F3EE 0x9F4A # 0 +0x0000F3EF 0x9F52 # 0 +0x0000F3F0 0x9F54 # 0 +0x0000F3F1 0x9F63 # 0 +0x0000F3F2 0x9F5F # 0 +0x0000F3F3 0x9F60 # 0 +0x0000F3F4 0x9F61 # 0 +0x0000F3F5 0x9F66 # 0 +0x0000F3F6 0x9F67 # 0 +0x0000F3F7 0x9F6C # 0 +0x0000F3F8 0x9F6A # 0 +0x0000F3F9 0x9F77 # 0 +0x0000F3FA 0x9F72 # 0 +0x0000F3FB 0x9F76 # 0 +0x0000F3FC 0x9F95 # 0 +0x0000F3FD 0x9F9C # 0 +0x0000F3FE 0x9FA0 # 0 +0x0000F4A1 0x582F # 0 +0x0000F4A2 0x69C7 # 0 +0x0000F4A3 0x9059 # 0 +0x0000F4A4 0x7464 # 0 +0x0000F4A5 0x51DC # 0 +0x0000F4A6 0x7199 # 0 +0x0000F5A1 0xE000 # 0 +0x0000F5A2 0xE001 # 0 +0x0000F5A3 0xE002 # 0 +0x0000F5A4 0xE003 # 0 +0x0000F5A5 0xE004 # 0 +0x0000F5A6 0xE005 # 0 +0x0000F5A7 0xE006 # 0 +0x0000F5A8 0xE007 # 0 +0x0000F5A9 0xE008 # 0 +0x0000F5AA 0xE009 # 0 +0x0000F5AB 0xE00A # 0 +0x0000F5AC 0xE00B # 0 +0x0000F5AD 0xE00C # 0 +0x0000F5AE 0xE00D # 0 +0x0000F5AF 0xE00E # 0 +0x0000F5B0 0xE00F # 0 +0x0000F5B1 0xE010 # 0 +0x0000F5B2 0xE011 # 0 +0x0000F5B3 0xE012 # 0 +0x0000F5B4 0xE013 # 0 +0x0000F5B5 0xE014 # 0 +0x0000F5B6 0xE015 # 0 +0x0000F5B7 0xE016 # 0 +0x0000F5B8 0xE017 # 0 +0x0000F5B9 0xE018 # 0 +0x0000F5BA 0xE019 # 0 +0x0000F5BB 0xE01A # 0 +0x0000F5BC 0xE01B # 0 +0x0000F5BD 0xE01C # 0 +0x0000F5BE 0xE01D # 0 +0x0000F5BF 0xE01E # 0 +0x0000F5C0 0xE01F # 0 +0x0000F5C1 0xE020 # 0 +0x0000F5C2 0xE021 # 0 +0x0000F5C3 0xE022 # 0 +0x0000F5C4 0xE023 # 0 +0x0000F5C5 0xE024 # 0 +0x0000F5C6 0xE025 # 0 +0x0000F5C7 0xE026 # 0 +0x0000F5C8 0xE027 # 0 +0x0000F5C9 0xE028 # 0 +0x0000F5CA 0xE029 # 0 +0x0000F5CB 0xE02A # 0 +0x0000F5CC 0xE02B # 0 +0x0000F5CD 0xE02C # 0 +0x0000F5CE 0xE02D # 0 +0x0000F5CF 0xE02E # 0 +0x0000F5D0 0xE02F # 0 +0x0000F5D1 0xE030 # 0 +0x0000F5D2 0xE031 # 0 +0x0000F5D3 0xE032 # 0 +0x0000F5D4 0xE033 # 0 +0x0000F5D5 0xE034 # 0 +0x0000F5D6 0xE035 # 0 +0x0000F5D7 0xE036 # 0 +0x0000F5D8 0xE037 # 0 +0x0000F5D9 0xE038 # 0 +0x0000F5DA 0xE039 # 0 +0x0000F5DB 0xE03A # 0 +0x0000F5DC 0xE03B # 0 +0x0000F5DD 0xE03C # 0 +0x0000F5DE 0xE03D # 0 +0x0000F5DF 0xE03E # 0 +0x0000F5E0 0xE03F # 0 +0x0000F5E1 0xE040 # 0 +0x0000F5E2 0xE041 # 0 +0x0000F5E3 0xE042 # 0 +0x0000F5E4 0xE043 # 0 +0x0000F5E5 0xE044 # 0 +0x0000F5E6 0xE045 # 0 +0x0000F5E7 0xE046 # 0 +0x0000F5E8 0xE047 # 0 +0x0000F5E9 0xE048 # 0 +0x0000F5EA 0xE049 # 0 +0x0000F5EB 0xE04A # 0 +0x0000F5EC 0xE04B # 0 +0x0000F5ED 0xE04C # 0 +0x0000F5EE 0xE04D # 0 +0x0000F5EF 0xE04E # 0 +0x0000F5F0 0xE04F # 0 +0x0000F5F1 0xE050 # 0 +0x0000F5F2 0xE051 # 0 +0x0000F5F3 0xE052 # 0 +0x0000F5F4 0xE053 # 0 +0x0000F5F5 0xE054 # 0 +0x0000F5F6 0xE055 # 0 +0x0000F5F7 0xE056 # 0 +0x0000F5F8 0xE057 # 0 +0x0000F5F9 0xE058 # 0 +0x0000F5FA 0xE059 # 0 +0x0000F5FB 0xE05A # 0 +0x0000F5FC 0xE05B # 0 +0x0000F5FD 0xE05C # 0 +0x0000F5FE 0xE05D # 0 +0x0000F6A1 0xE05E # 0 +0x0000F6A2 0xE05F # 0 +0x0000F6A3 0xE060 # 0 +0x0000F6A4 0xE061 # 0 +0x0000F6A5 0xE062 # 0 +0x0000F6A6 0xE063 # 0 +0x0000F6A7 0xE064 # 0 +0x0000F6A8 0xE065 # 0 +0x0000F6A9 0xE066 # 0 +0x0000F6AA 0xE067 # 0 +0x0000F6AB 0xE068 # 0 +0x0000F6AC 0xE069 # 0 +0x0000F6AD 0xE06A # 0 +0x0000F6AE 0xE06B # 0 +0x0000F6AF 0xE06C # 0 +0x0000F6B0 0xE06D # 0 +0x0000F6B1 0xE06E # 0 +0x0000F6B2 0xE06F # 0 +0x0000F6B3 0xE070 # 0 +0x0000F6B4 0xE071 # 0 +0x0000F6B5 0xE072 # 0 +0x0000F6B6 0xE073 # 0 +0x0000F6B7 0xE074 # 0 +0x0000F6B8 0xE075 # 0 +0x0000F6B9 0xE076 # 0 +0x0000F6BA 0xE077 # 0 +0x0000F6BB 0xE078 # 0 +0x0000F6BC 0xE079 # 0 +0x0000F6BD 0xE07A # 0 +0x0000F6BE 0xE07B # 0 +0x0000F6BF 0xE07C # 0 +0x0000F6C0 0xE07D # 0 +0x0000F6C1 0xE07E # 0 +0x0000F6C2 0xE07F # 0 +0x0000F6C3 0xE080 # 0 +0x0000F6C4 0xE081 # 0 +0x0000F6C5 0xE082 # 0 +0x0000F6C6 0xE083 # 0 +0x0000F6C7 0xE084 # 0 +0x0000F6C8 0xE085 # 0 +0x0000F6C9 0xE086 # 0 +0x0000F6CA 0xE087 # 0 +0x0000F6CB 0xE088 # 0 +0x0000F6CC 0xE089 # 0 +0x0000F6CD 0xE08A # 0 +0x0000F6CE 0xE08B # 0 +0x0000F6CF 0xE08C # 0 +0x0000F6D0 0xE08D # 0 +0x0000F6D1 0xE08E # 0 +0x0000F6D2 0xE08F # 0 +0x0000F6D3 0xE090 # 0 +0x0000F6D4 0xE091 # 0 +0x0000F6D5 0xE092 # 0 +0x0000F6D6 0xE093 # 0 +0x0000F6D7 0xE094 # 0 +0x0000F6D8 0xE095 # 0 +0x0000F6D9 0xE096 # 0 +0x0000F6DA 0xE097 # 0 +0x0000F6DB 0xE098 # 0 +0x0000F6DC 0xE099 # 0 +0x0000F6DD 0xE09A # 0 +0x0000F6DE 0xE09B # 0 +0x0000F6DF 0xE09C # 0 +0x0000F6E0 0xE09D # 0 +0x0000F6E1 0xE09E # 0 +0x0000F6E2 0xE09F # 0 +0x0000F6E3 0xE0A0 # 0 +0x0000F6E4 0xE0A1 # 0 +0x0000F6E5 0xE0A2 # 0 +0x0000F6E6 0xE0A3 # 0 +0x0000F6E7 0xE0A4 # 0 +0x0000F6E8 0xE0A5 # 0 +0x0000F6E9 0xE0A6 # 0 +0x0000F6EA 0xE0A7 # 0 +0x0000F6EB 0xE0A8 # 0 +0x0000F6EC 0xE0A9 # 0 +0x0000F6ED 0xE0AA # 0 +0x0000F6EE 0xE0AB # 0 +0x0000F6EF 0xE0AC # 0 +0x0000F6F0 0xE0AD # 0 +0x0000F6F1 0xE0AE # 0 +0x0000F6F2 0xE0AF # 0 +0x0000F6F3 0xE0B0 # 0 +0x0000F6F4 0xE0B1 # 0 +0x0000F6F5 0xE0B2 # 0 +0x0000F6F6 0xE0B3 # 0 +0x0000F6F7 0xE0B4 # 0 +0x0000F6F8 0xE0B5 # 0 +0x0000F6F9 0xE0B6 # 0 +0x0000F6FA 0xE0B7 # 0 +0x0000F6FB 0xE0B8 # 0 +0x0000F6FC 0xE0B9 # 0 +0x0000F6FD 0xE0BA # 0 +0x0000F6FE 0xE0BB # 0 +0x0000F7A1 0xE0BC # 0 +0x0000F7A2 0xE0BD # 0 +0x0000F7A3 0xE0BE # 0 +0x0000F7A4 0xE0BF # 0 +0x0000F7A5 0xE0C0 # 0 +0x0000F7A6 0xE0C1 # 0 +0x0000F7A7 0xE0C2 # 0 +0x0000F7A8 0xE0C3 # 0 +0x0000F7A9 0xE0C4 # 0 +0x0000F7AA 0xE0C5 # 0 +0x0000F7AB 0xE0C6 # 0 +0x0000F7AC 0xE0C7 # 0 +0x0000F7AD 0xE0C8 # 0 +0x0000F7AE 0xE0C9 # 0 +0x0000F7AF 0xE0CA # 0 +0x0000F7B0 0xE0CB # 0 +0x0000F7B1 0xE0CC # 0 +0x0000F7B2 0xE0CD # 0 +0x0000F7B3 0xE0CE # 0 +0x0000F7B4 0xE0CF # 0 +0x0000F7B5 0xE0D0 # 0 +0x0000F7B6 0xE0D1 # 0 +0x0000F7B7 0xE0D2 # 0 +0x0000F7B8 0xE0D3 # 0 +0x0000F7B9 0xE0D4 # 0 +0x0000F7BA 0xE0D5 # 0 +0x0000F7BB 0xE0D6 # 0 +0x0000F7BC 0xE0D7 # 0 +0x0000F7BD 0xE0D8 # 0 +0x0000F7BE 0xE0D9 # 0 +0x0000F7BF 0xE0DA # 0 +0x0000F7C0 0xE0DB # 0 +0x0000F7C1 0xE0DC # 0 +0x0000F7C2 0xE0DD # 0 +0x0000F7C3 0xE0DE # 0 +0x0000F7C4 0xE0DF # 0 +0x0000F7C5 0xE0E0 # 0 +0x0000F7C6 0xE0E1 # 0 +0x0000F7C7 0xE0E2 # 0 +0x0000F7C8 0xE0E3 # 0 +0x0000F7C9 0xE0E4 # 0 +0x0000F7CA 0xE0E5 # 0 +0x0000F7CB 0xE0E6 # 0 +0x0000F7CC 0xE0E7 # 0 +0x0000F7CD 0xE0E8 # 0 +0x0000F7CE 0xE0E9 # 0 +0x0000F7CF 0xE0EA # 0 +0x0000F7D0 0xE0EB # 0 +0x0000F7D1 0xE0EC # 0 +0x0000F7D2 0xE0ED # 0 +0x0000F7D3 0xE0EE # 0 +0x0000F7D4 0xE0EF # 0 +0x0000F7D5 0xE0F0 # 0 +0x0000F7D6 0xE0F1 # 0 +0x0000F7D7 0xE0F2 # 0 +0x0000F7D8 0xE0F3 # 0 +0x0000F7D9 0xE0F4 # 0 +0x0000F7DA 0xE0F5 # 0 +0x0000F7DB 0xE0F6 # 0 +0x0000F7DC 0xE0F7 # 0 +0x0000F7DD 0xE0F8 # 0 +0x0000F7DE 0xE0F9 # 0 +0x0000F7DF 0xE0FA # 0 +0x0000F7E0 0xE0FB # 0 +0x0000F7E1 0xE0FC # 0 +0x0000F7E2 0xE0FD # 0 +0x0000F7E3 0xE0FE # 0 +0x0000F7E4 0xE0FF # 0 +0x0000F7E5 0xE100 # 0 +0x0000F7E6 0xE101 # 0 +0x0000F7E7 0xE102 # 0 +0x0000F7E8 0xE103 # 0 +0x0000F7E9 0xE104 # 0 +0x0000F7EA 0xE105 # 0 +0x0000F7EB 0xE106 # 0 +0x0000F7EC 0xE107 # 0 +0x0000F7ED 0xE108 # 0 +0x0000F7EE 0xE109 # 0 +0x0000F7EF 0xE10A # 0 +0x0000F7F0 0xE10B # 0 +0x0000F7F1 0xE10C # 0 +0x0000F7F2 0xE10D # 0 +0x0000F7F3 0xE10E # 0 +0x0000F7F4 0xE10F # 0 +0x0000F7F5 0xE110 # 0 +0x0000F7F6 0xE111 # 0 +0x0000F7F7 0xE112 # 0 +0x0000F7F8 0xE113 # 0 +0x0000F7F9 0xE114 # 0 +0x0000F7FA 0xE115 # 0 +0x0000F7FB 0xE116 # 0 +0x0000F7FC 0xE117 # 0 +0x0000F7FD 0xE118 # 0 +0x0000F7FE 0xE119 # 0 +0x0000F8A1 0xE11A # 0 +0x0000F8A2 0xE11B # 0 +0x0000F8A3 0xE11C # 0 +0x0000F8A4 0xE11D # 0 +0x0000F8A5 0xE11E # 0 +0x0000F8A6 0xE11F # 0 +0x0000F8A7 0xE120 # 0 +0x0000F8A8 0xE121 # 0 +0x0000F8A9 0xE122 # 0 +0x0000F8AA 0xE123 # 0 +0x0000F8AB 0xE124 # 0 +0x0000F8AC 0xE125 # 0 +0x0000F8AD 0xE126 # 0 +0x0000F8AE 0xE127 # 0 +0x0000F8AF 0xE128 # 0 +0x0000F8B0 0xE129 # 0 +0x0000F8B1 0xE12A # 0 +0x0000F8B2 0xE12B # 0 +0x0000F8B3 0xE12C # 0 +0x0000F8B4 0xE12D # 0 +0x0000F8B5 0xE12E # 0 +0x0000F8B6 0xE12F # 0 +0x0000F8B7 0xE130 # 0 +0x0000F8B8 0xE131 # 0 +0x0000F8B9 0xE132 # 0 +0x0000F8BA 0xE133 # 0 +0x0000F8BB 0xE134 # 0 +0x0000F8BC 0xE135 # 0 +0x0000F8BD 0xE136 # 0 +0x0000F8BE 0xE137 # 0 +0x0000F8BF 0xE138 # 0 +0x0000F8C0 0xE139 # 0 +0x0000F8C1 0xE13A # 0 +0x0000F8C2 0xE13B # 0 +0x0000F8C3 0xE13C # 0 +0x0000F8C4 0xE13D # 0 +0x0000F8C5 0xE13E # 0 +0x0000F8C6 0xE13F # 0 +0x0000F8C7 0xE140 # 0 +0x0000F8C8 0xE141 # 0 +0x0000F8C9 0xE142 # 0 +0x0000F8CA 0xE143 # 0 +0x0000F8CB 0xE144 # 0 +0x0000F8CC 0xE145 # 0 +0x0000F8CD 0xE146 # 0 +0x0000F8CE 0xE147 # 0 +0x0000F8CF 0xE148 # 0 +0x0000F8D0 0xE149 # 0 +0x0000F8D1 0xE14A # 0 +0x0000F8D2 0xE14B # 0 +0x0000F8D3 0xE14C # 0 +0x0000F8D4 0xE14D # 0 +0x0000F8D5 0xE14E # 0 +0x0000F8D6 0xE14F # 0 +0x0000F8D7 0xE150 # 0 +0x0000F8D8 0xE151 # 0 +0x0000F8D9 0xE152 # 0 +0x0000F8DA 0xE153 # 0 +0x0000F8DB 0xE154 # 0 +0x0000F8DC 0xE155 # 0 +0x0000F8DD 0xE156 # 0 +0x0000F8DE 0xE157 # 0 +0x0000F8DF 0xE158 # 0 +0x0000F8E0 0xE159 # 0 +0x0000F8E1 0xE15A # 0 +0x0000F8E2 0xE15B # 0 +0x0000F8E3 0xE15C # 0 +0x0000F8E4 0xE15D # 0 +0x0000F8E5 0xE15E # 0 +0x0000F8E6 0xE15F # 0 +0x0000F8E7 0xE160 # 0 +0x0000F8E8 0xE161 # 0 +0x0000F8E9 0xE162 # 0 +0x0000F8EA 0xE163 # 0 +0x0000F8EB 0xE164 # 0 +0x0000F8EC 0xE165 # 0 +0x0000F8ED 0xE166 # 0 +0x0000F8EE 0xE167 # 0 +0x0000F8EF 0xE168 # 0 +0x0000F8F0 0xE169 # 0 +0x0000F8F1 0xE16A # 0 +0x0000F8F2 0xE16B # 0 +0x0000F8F3 0xE16C # 0 +0x0000F8F4 0xE16D # 0 +0x0000F8F5 0xE16E # 0 +0x0000F8F6 0xE16F # 0 +0x0000F8F7 0xE170 # 0 +0x0000F8F8 0xE171 # 0 +0x0000F8F9 0xE172 # 0 +0x0000F8FA 0xE173 # 0 +0x0000F8FB 0xE174 # 0 +0x0000F8FC 0xE175 # 0 +0x0000F8FD 0xE176 # 0 +0x0000F8FE 0xE177 # 0 +0x0000F9A1 0xE178 # 0 +0x0000F9A2 0xE179 # 0 +0x0000F9A3 0xE17A # 0 +0x0000F9A4 0xE17B # 0 +0x0000F9A5 0xE17C # 0 +0x0000F9A6 0xE17D # 0 +0x0000F9A7 0xE17E # 0 +0x0000F9A8 0xE17F # 0 +0x0000F9A9 0xE180 # 0 +0x0000F9AA 0xE181 # 0 +0x0000F9AB 0xE182 # 0 +0x0000F9AC 0xE183 # 0 +0x0000F9AD 0xE184 # 0 +0x0000F9AE 0xE185 # 0 +0x0000F9AF 0xE186 # 0 +0x0000F9B0 0xE187 # 0 +0x0000F9B1 0xE188 # 0 +0x0000F9B2 0xE189 # 0 +0x0000F9B3 0xE18A # 0 +0x0000F9B4 0xE18B # 0 +0x0000F9B5 0xE18C # 0 +0x0000F9B6 0xE18D # 0 +0x0000F9B7 0xE18E # 0 +0x0000F9B8 0xE18F # 0 +0x0000F9B9 0xE190 # 0 +0x0000F9BA 0xE191 # 0 +0x0000F9BB 0xE192 # 0 +0x0000F9BC 0xE193 # 0 +0x0000F9BD 0xE194 # 0 +0x0000F9BE 0xE195 # 0 +0x0000F9BF 0xE196 # 0 +0x0000F9C0 0xE197 # 0 +0x0000F9C1 0xE198 # 0 +0x0000F9C2 0xE199 # 0 +0x0000F9C3 0xE19A # 0 +0x0000F9C4 0xE19B # 0 +0x0000F9C5 0xE19C # 0 +0x0000F9C6 0xE19D # 0 +0x0000F9C7 0xE19E # 0 +0x0000F9C8 0xE19F # 0 +0x0000F9C9 0xE1A0 # 0 +0x0000F9CA 0xE1A1 # 0 +0x0000F9CB 0xE1A2 # 0 +0x0000F9CC 0xE1A3 # 0 +0x0000F9CD 0xE1A4 # 0 +0x0000F9CE 0xE1A5 # 0 +0x0000F9CF 0xE1A6 # 0 +0x0000F9D0 0xE1A7 # 0 +0x0000F9D1 0xE1A8 # 0 +0x0000F9D2 0xE1A9 # 0 +0x0000F9D3 0xE1AA # 0 +0x0000F9D4 0xE1AB # 0 +0x0000F9D5 0xE1AC # 0 +0x0000F9D6 0xE1AD # 0 +0x0000F9D7 0xE1AE # 0 +0x0000F9D8 0xE1AF # 0 +0x0000F9D9 0xE1B0 # 0 +0x0000F9DA 0xE1B1 # 0 +0x0000F9DB 0xE1B2 # 0 +0x0000F9DC 0xE1B3 # 0 +0x0000F9DD 0xE1B4 # 0 +0x0000F9DE 0xE1B5 # 0 +0x0000F9DF 0xE1B6 # 0 +0x0000F9E0 0xE1B7 # 0 +0x0000F9E1 0xE1B8 # 0 +0x0000F9E2 0xE1B9 # 0 +0x0000F9E3 0xE1BA # 0 +0x0000F9E4 0xE1BB # 0 +0x0000F9E5 0xE1BC # 0 +0x0000F9E6 0xE1BD # 0 +0x0000F9E7 0xE1BE # 0 +0x0000F9E8 0xE1BF # 0 +0x0000F9E9 0xE1C0 # 0 +0x0000F9EA 0xE1C1 # 0 +0x0000F9EB 0xE1C2 # 0 +0x0000F9EC 0xE1C3 # 0 +0x0000F9ED 0xE1C4 # 0 +0x0000F9EE 0xE1C5 # 0 +0x0000F9EF 0xE1C6 # 0 +0x0000F9F0 0xE1C7 # 0 +0x0000F9F1 0xE1C8 # 0 +0x0000F9F2 0xE1C9 # 0 +0x0000F9F3 0xE1CA # 0 +0x0000F9F4 0xE1CB # 0 +0x0000F9F5 0xE1CC # 0 +0x0000F9F6 0xE1CD # 0 +0x0000F9F7 0xE1CE # 0 +0x0000F9F8 0xE1CF # 0 +0x0000F9F9 0xE1D0 # 0 +0x0000F9FA 0xE1D1 # 0 +0x0000F9FB 0xE1D2 # 0 +0x0000F9FC 0xE1D3 # 0 +0x0000F9FD 0xE1D4 # 0 +0x0000F9FE 0xE1D5 # 0 +0x0000FAA1 0xE1D6 # 0 +0x0000FAA2 0xE1D7 # 0 +0x0000FAA3 0xE1D8 # 0 +0x0000FAA4 0xE1D9 # 0 +0x0000FAA5 0xE1DA # 0 +0x0000FAA6 0xE1DB # 0 +0x0000FAA7 0xE1DC # 0 +0x0000FAA8 0xE1DD # 0 +0x0000FAA9 0xE1DE # 0 +0x0000FAAA 0xE1DF # 0 +0x0000FAAB 0xE1E0 # 0 +0x0000FAAC 0xE1E1 # 0 +0x0000FAAD 0xE1E2 # 0 +0x0000FAAE 0xE1E3 # 0 +0x0000FAAF 0xE1E4 # 0 +0x0000FAB0 0xE1E5 # 0 +0x0000FAB1 0xE1E6 # 0 +0x0000FAB2 0xE1E7 # 0 +0x0000FAB3 0xE1E8 # 0 +0x0000FAB4 0xE1E9 # 0 +0x0000FAB5 0xE1EA # 0 +0x0000FAB6 0xE1EB # 0 +0x0000FAB7 0xE1EC # 0 +0x0000FAB8 0xE1ED # 0 +0x0000FAB9 0xE1EE # 0 +0x0000FABA 0xE1EF # 0 +0x0000FABB 0xE1F0 # 0 +0x0000FABC 0xE1F1 # 0 +0x0000FABD 0xE1F2 # 0 +0x0000FABE 0xE1F3 # 0 +0x0000FABF 0xE1F4 # 0 +0x0000FAC0 0xE1F5 # 0 +0x0000FAC1 0xE1F6 # 0 +0x0000FAC2 0xE1F7 # 0 +0x0000FAC3 0xE1F8 # 0 +0x0000FAC4 0xE1F9 # 0 +0x0000FAC5 0xE1FA # 0 +0x0000FAC6 0xE1FB # 0 +0x0000FAC7 0xE1FC # 0 +0x0000FAC8 0xE1FD # 0 +0x0000FAC9 0xE1FE # 0 +0x0000FACA 0xE1FF # 0 +0x0000FACB 0xE200 # 0 +0x0000FACC 0xE201 # 0 +0x0000FACD 0xE202 # 0 +0x0000FACE 0xE203 # 0 +0x0000FACF 0xE204 # 0 +0x0000FAD0 0xE205 # 0 +0x0000FAD1 0xE206 # 0 +0x0000FAD2 0xE207 # 0 +0x0000FAD3 0xE208 # 0 +0x0000FAD4 0xE209 # 0 +0x0000FAD5 0xE20A # 0 +0x0000FAD6 0xE20B # 0 +0x0000FAD7 0xE20C # 0 +0x0000FAD8 0xE20D # 0 +0x0000FAD9 0xE20E # 0 +0x0000FADA 0xE20F # 0 +0x0000FADB 0xE210 # 0 +0x0000FADC 0xE211 # 0 +0x0000FADD 0xE212 # 0 +0x0000FADE 0xE213 # 0 +0x0000FADF 0xE214 # 0 +0x0000FAE0 0xE215 # 0 +0x0000FAE1 0xE216 # 0 +0x0000FAE2 0xE217 # 0 +0x0000FAE3 0xE218 # 0 +0x0000FAE4 0xE219 # 0 +0x0000FAE5 0xE21A # 0 +0x0000FAE6 0xE21B # 0 +0x0000FAE7 0xE21C # 0 +0x0000FAE8 0xE21D # 0 +0x0000FAE9 0xE21E # 0 +0x0000FAEA 0xE21F # 0 +0x0000FAEB 0xE220 # 0 +0x0000FAEC 0xE221 # 0 +0x0000FAED 0xE222 # 0 +0x0000FAEE 0xE223 # 0 +0x0000FAEF 0xE224 # 0 +0x0000FAF0 0xE225 # 0 +0x0000FAF1 0xE226 # 0 +0x0000FAF2 0xE227 # 0 +0x0000FAF3 0xE228 # 0 +0x0000FAF4 0xE229 # 0 +0x0000FAF5 0xE22A # 0 +0x0000FAF6 0xE22B # 0 +0x0000FAF7 0xE22C # 0 +0x0000FAF8 0xE22D # 0 +0x0000FAF9 0xE22E # 0 +0x0000FAFA 0xE22F # 0 +0x0000FAFB 0xE230 # 0 +0x0000FAFC 0xE231 # 0 +0x0000FAFD 0xE232 # 0 +0x0000FAFE 0xE233 # 0 +0x0000FBA1 0xE234 # 0 +0x0000FBA2 0xE235 # 0 +0x0000FBA3 0xE236 # 0 +0x0000FBA4 0xE237 # 0 +0x0000FBA5 0xE238 # 0 +0x0000FBA6 0xE239 # 0 +0x0000FBA7 0xE23A # 0 +0x0000FBA8 0xE23B # 0 +0x0000FBA9 0xE23C # 0 +0x0000FBAA 0xE23D # 0 +0x0000FBAB 0xE23E # 0 +0x0000FBAC 0xE23F # 0 +0x0000FBAD 0xE240 # 0 +0x0000FBAE 0xE241 # 0 +0x0000FBAF 0xE242 # 0 +0x0000FBB0 0xE243 # 0 +0x0000FBB1 0xE244 # 0 +0x0000FBB2 0xE245 # 0 +0x0000FBB3 0xE246 # 0 +0x0000FBB4 0xE247 # 0 +0x0000FBB5 0xE248 # 0 +0x0000FBB6 0xE249 # 0 +0x0000FBB7 0xE24A # 0 +0x0000FBB8 0xE24B # 0 +0x0000FBB9 0xE24C # 0 +0x0000FBBA 0xE24D # 0 +0x0000FBBB 0xE24E # 0 +0x0000FBBC 0xE24F # 0 +0x0000FBBD 0xE250 # 0 +0x0000FBBE 0xE251 # 0 +0x0000FBBF 0xE252 # 0 +0x0000FBC0 0xE253 # 0 +0x0000FBC1 0xE254 # 0 +0x0000FBC2 0xE255 # 0 +0x0000FBC3 0xE256 # 0 +0x0000FBC4 0xE257 # 0 +0x0000FBC5 0xE258 # 0 +0x0000FBC6 0xE259 # 0 +0x0000FBC7 0xE25A # 0 +0x0000FBC8 0xE25B # 0 +0x0000FBC9 0xE25C # 0 +0x0000FBCA 0xE25D # 0 +0x0000FBCB 0xE25E # 0 +0x0000FBCC 0xE25F # 0 +0x0000FBCD 0xE260 # 0 +0x0000FBCE 0xE261 # 0 +0x0000FBCF 0xE262 # 0 +0x0000FBD0 0xE263 # 0 +0x0000FBD1 0xE264 # 0 +0x0000FBD2 0xE265 # 0 +0x0000FBD3 0xE266 # 0 +0x0000FBD4 0xE267 # 0 +0x0000FBD5 0xE268 # 0 +0x0000FBD6 0xE269 # 0 +0x0000FBD7 0xE26A # 0 +0x0000FBD8 0xE26B # 0 +0x0000FBD9 0xE26C # 0 +0x0000FBDA 0xE26D # 0 +0x0000FBDB 0xE26E # 0 +0x0000FBDC 0xE26F # 0 +0x0000FBDD 0xE270 # 0 +0x0000FBDE 0xE271 # 0 +0x0000FBDF 0xE272 # 0 +0x0000FBE0 0xE273 # 0 +0x0000FBE1 0xE274 # 0 +0x0000FBE2 0xE275 # 0 +0x0000FBE3 0xE276 # 0 +0x0000FBE4 0xE277 # 0 +0x0000FBE5 0xE278 # 0 +0x0000FBE6 0xE279 # 0 +0x0000FBE7 0xE27A # 0 +0x0000FBE8 0xE27B # 0 +0x0000FBE9 0xE27C # 0 +0x0000FBEA 0xE27D # 0 +0x0000FBEB 0xE27E # 0 +0x0000FBEC 0xE27F # 0 +0x0000FBED 0xE280 # 0 +0x0000FBEE 0xE281 # 0 +0x0000FBEF 0xE282 # 0 +0x0000FBF0 0xE283 # 0 +0x0000FBF1 0xE284 # 0 +0x0000FBF2 0xE285 # 0 +0x0000FBF3 0xE286 # 0 +0x0000FBF4 0xE287 # 0 +0x0000FBF5 0xE288 # 0 +0x0000FBF6 0xE289 # 0 +0x0000FBF7 0xE28A # 0 +0x0000FBF8 0xE28B # 0 +0x0000FBF9 0xE28C # 0 +0x0000FBFA 0xE28D # 0 +0x0000FBFB 0xE28E # 0 +0x0000FBFC 0xE28F # 0 +0x0000FBFD 0xE290 # 0 +0x0000FBFE 0xE291 # 0 +0x0000FCA1 0xE292 # 0 +0x0000FCA2 0xE293 # 0 +0x0000FCA3 0xE294 # 0 +0x0000FCA4 0xE295 # 0 +0x0000FCA5 0xE296 # 0 +0x0000FCA6 0xE297 # 0 +0x0000FCA7 0xE298 # 0 +0x0000FCA8 0xE299 # 0 +0x0000FCA9 0xE29A # 0 +0x0000FCAA 0xE29B # 0 +0x0000FCAB 0xE29C # 0 +0x0000FCAC 0xE29D # 0 +0x0000FCAD 0xE29E # 0 +0x0000FCAE 0xE29F # 0 +0x0000FCAF 0xE2A0 # 0 +0x0000FCB0 0xE2A1 # 0 +0x0000FCB1 0xE2A2 # 0 +0x0000FCB2 0xE2A3 # 0 +0x0000FCB3 0xE2A4 # 0 +0x0000FCB4 0xE2A5 # 0 +0x0000FCB5 0xE2A6 # 0 +0x0000FCB6 0xE2A7 # 0 +0x0000FCB7 0xE2A8 # 0 +0x0000FCB8 0xE2A9 # 0 +0x0000FCB9 0xE2AA # 0 +0x0000FCBA 0xE2AB # 0 +0x0000FCBB 0xE2AC # 0 +0x0000FCBC 0xE2AD # 0 +0x0000FCBD 0xE2AE # 0 +0x0000FCBE 0xE2AF # 0 +0x0000FCBF 0xE2B0 # 0 +0x0000FCC0 0xE2B1 # 0 +0x0000FCC1 0xE2B2 # 0 +0x0000FCC2 0xE2B3 # 0 +0x0000FCC3 0xE2B4 # 0 +0x0000FCC4 0xE2B5 # 0 +0x0000FCC5 0xE2B6 # 0 +0x0000FCC6 0xE2B7 # 0 +0x0000FCC7 0xE2B8 # 0 +0x0000FCC8 0xE2B9 # 0 +0x0000FCC9 0xE2BA # 0 +0x0000FCCA 0xE2BB # 0 +0x0000FCCB 0xE2BC # 0 +0x0000FCCC 0xE2BD # 0 +0x0000FCCD 0xE2BE # 0 +0x0000FCCE 0xE2BF # 0 +0x0000FCCF 0xE2C0 # 0 +0x0000FCD0 0xE2C1 # 0 +0x0000FCD1 0xE2C2 # 0 +0x0000FCD2 0xE2C3 # 0 +0x0000FCD3 0xE2C4 # 0 +0x0000FCD4 0xE2C5 # 0 +0x0000FCD5 0xE2C6 # 0 +0x0000FCD6 0xE2C7 # 0 +0x0000FCD7 0xE2C8 # 0 +0x0000FCD8 0xE2C9 # 0 +0x0000FCD9 0xE2CA # 0 +0x0000FCDA 0xE2CB # 0 +0x0000FCDB 0xE2CC # 0 +0x0000FCDC 0xE2CD # 0 +0x0000FCDD 0xE2CE # 0 +0x0000FCDE 0xE2CF # 0 +0x0000FCDF 0xE2D0 # 0 +0x0000FCE0 0xE2D1 # 0 +0x0000FCE1 0xE2D2 # 0 +0x0000FCE2 0xE2D3 # 0 +0x0000FCE3 0xE2D4 # 0 +0x0000FCE4 0xE2D5 # 0 +0x0000FCE5 0xE2D6 # 0 +0x0000FCE6 0xE2D7 # 0 +0x0000FCE7 0xE2D8 # 0 +0x0000FCE8 0xE2D9 # 0 +0x0000FCE9 0xE2DA # 0 +0x0000FCEA 0xE2DB # 0 +0x0000FCEB 0xE2DC # 0 +0x0000FCEC 0xE2DD # 0 +0x0000FCED 0xE2DE # 0 +0x0000FCEE 0xE2DF # 0 +0x0000FCEF 0xE2E0 # 0 +0x0000FCF0 0xE2E1 # 0 +0x0000FCF1 0xE2E2 # 0 +0x0000FCF2 0xE2E3 # 0 +0x0000FCF3 0xE2E4 # 0 +0x0000FCF4 0xE2E5 # 0 +0x0000FCF5 0xE2E6 # 0 +0x0000FCF6 0xE2E7 # 0 +0x0000FCF7 0xE2E8 # 0 +0x0000FCF8 0xE2E9 # 0 +0x0000FCF9 0xE2EA # 0 +0x0000FCFA 0xE2EB # 0 +0x0000FCFB 0xE2EC # 0 +0x0000FCFC 0xE2ED # 0 +0x0000FCFD 0xE2EE # 0 +0x0000FCFE 0xE2EF # 0 +0x0000FDA1 0xE2F0 # 0 +0x0000FDA2 0xE2F1 # 0 +0x0000FDA3 0xE2F2 # 0 +0x0000FDA4 0xE2F3 # 0 +0x0000FDA5 0xE2F4 # 0 +0x0000FDA6 0xE2F5 # 0 +0x0000FDA7 0xE2F6 # 0 +0x0000FDA8 0xE2F7 # 0 +0x0000FDA9 0xE2F8 # 0 +0x0000FDAA 0xE2F9 # 0 +0x0000FDAB 0xE2FA # 0 +0x0000FDAC 0xE2FB # 0 +0x0000FDAD 0xE2FC # 0 +0x0000FDAE 0xE2FD # 0 +0x0000FDAF 0xE2FE # 0 +0x0000FDB0 0xE2FF # 0 +0x0000FDB1 0xE300 # 0 +0x0000FDB2 0xE301 # 0 +0x0000FDB3 0xE302 # 0 +0x0000FDB4 0xE303 # 0 +0x0000FDB5 0xE304 # 0 +0x0000FDB6 0xE305 # 0 +0x0000FDB7 0xE306 # 0 +0x0000FDB8 0xE307 # 0 +0x0000FDB9 0xE308 # 0 +0x0000FDBA 0xE309 # 0 +0x0000FDBB 0xE30A # 0 +0x0000FDBC 0xE30B # 0 +0x0000FDBD 0xE30C # 0 +0x0000FDBE 0xE30D # 0 +0x0000FDBF 0xE30E # 0 +0x0000FDC0 0xE30F # 0 +0x0000FDC1 0xE310 # 0 +0x0000FDC2 0xE311 # 0 +0x0000FDC3 0xE312 # 0 +0x0000FDC4 0xE313 # 0 +0x0000FDC5 0xE314 # 0 +0x0000FDC6 0xE315 # 0 +0x0000FDC7 0xE316 # 0 +0x0000FDC8 0xE317 # 0 +0x0000FDC9 0xE318 # 0 +0x0000FDCA 0xE319 # 0 +0x0000FDCB 0xE31A # 0 +0x0000FDCC 0xE31B # 0 +0x0000FDCD 0xE31C # 0 +0x0000FDCE 0xE31D # 0 +0x0000FDCF 0xE31E # 0 +0x0000FDD0 0xE31F # 0 +0x0000FDD1 0xE320 # 0 +0x0000FDD2 0xE321 # 0 +0x0000FDD3 0xE322 # 0 +0x0000FDD4 0xE323 # 0 +0x0000FDD5 0xE324 # 0 +0x0000FDD6 0xE325 # 0 +0x0000FDD7 0xE326 # 0 +0x0000FDD8 0xE327 # 0 +0x0000FDD9 0xE328 # 0 +0x0000FDDA 0xE329 # 0 +0x0000FDDB 0xE32A # 0 +0x0000FDDC 0xE32B # 0 +0x0000FDDD 0xE32C # 0 +0x0000FDDE 0xE32D # 0 +0x0000FDDF 0xE32E # 0 +0x0000FDE0 0xE32F # 0 +0x0000FDE1 0xE330 # 0 +0x0000FDE2 0xE331 # 0 +0x0000FDE3 0xE332 # 0 +0x0000FDE4 0xE333 # 0 +0x0000FDE5 0xE334 # 0 +0x0000FDE6 0xE335 # 0 +0x0000FDE7 0xE336 # 0 +0x0000FDE8 0xE337 # 0 +0x0000FDE9 0xE338 # 0 +0x0000FDEA 0xE339 # 0 +0x0000FDEB 0xE33A # 0 +0x0000FDEC 0xE33B # 0 +0x0000FDED 0xE33C # 0 +0x0000FDEE 0xE33D # 0 +0x0000FDEF 0xE33E # 0 +0x0000FDF0 0xE33F # 0 +0x0000FDF1 0xE340 # 0 +0x0000FDF2 0xE341 # 0 +0x0000FDF3 0xE342 # 0 +0x0000FDF4 0xE343 # 0 +0x0000FDF5 0xE344 # 0 +0x0000FDF6 0xE345 # 0 +0x0000FDF7 0xE346 # 0 +0x0000FDF8 0xE347 # 0 +0x0000FDF9 0xE348 # 0 +0x0000FDFA 0xE349 # 0 +0x0000FDFB 0xE34A # 0 +0x0000FDFC 0xE34B # 0 +0x0000FDFD 0xE34C # 0 +0x0000FDFE 0xE34D # 0 +0x0000FEA1 0xE34E # 0 +0x0000FEA2 0xE34F # 0 +0x0000FEA3 0xE350 # 0 +0x0000FEA4 0xE351 # 0 +0x0000FEA5 0xE352 # 0 +0x0000FEA6 0xE353 # 0 +0x0000FEA7 0xE354 # 0 +0x0000FEA8 0xE355 # 0 +0x0000FEA9 0xE356 # 0 +0x0000FEAA 0xE357 # 0 +0x0000FEAB 0xE358 # 0 +0x0000FEAC 0xE359 # 0 +0x0000FEAD 0xE35A # 0 +0x0000FEAE 0xE35B # 0 +0x0000FEAF 0xE35C # 0 +0x0000FEB0 0xE35D # 0 +0x0000FEB1 0xE35E # 0 +0x0000FEB2 0xE35F # 0 +0x0000FEB3 0xE360 # 0 +0x0000FEB4 0xE361 # 0 +0x0000FEB5 0xE362 # 0 +0x0000FEB6 0xE363 # 0 +0x0000FEB7 0xE364 # 0 +0x0000FEB8 0xE365 # 0 +0x0000FEB9 0xE366 # 0 +0x0000FEBA 0xE367 # 0 +0x0000FEBB 0xE368 # 0 +0x0000FEBC 0xE369 # 0 +0x0000FEBD 0xE36A # 0 +0x0000FEBE 0xE36B # 0 +0x0000FEBF 0xE36C # 0 +0x0000FEC0 0xE36D # 0 +0x0000FEC1 0xE36E # 0 +0x0000FEC2 0xE36F # 0 +0x0000FEC3 0xE370 # 0 +0x0000FEC4 0xE371 # 0 +0x0000FEC5 0xE372 # 0 +0x0000FEC6 0xE373 # 0 +0x0000FEC7 0xE374 # 0 +0x0000FEC8 0xE375 # 0 +0x0000FEC9 0xE376 # 0 +0x0000FECA 0xE377 # 0 +0x0000FECB 0xE378 # 0 +0x0000FECC 0xE379 # 0 +0x0000FECD 0xE37A # 0 +0x0000FECE 0xE37B # 0 +0x0000FECF 0xE37C # 0 +0x0000FED0 0xE37D # 0 +0x0000FED1 0xE37E # 0 +0x0000FED2 0xE37F # 0 +0x0000FED3 0xE380 # 0 +0x0000FED4 0xE381 # 0 +0x0000FED5 0xE382 # 0 +0x0000FED6 0xE383 # 0 +0x0000FED7 0xE384 # 0 +0x0000FED8 0xE385 # 0 +0x0000FED9 0xE386 # 0 +0x0000FEDA 0xE387 # 0 +0x0000FEDB 0xE388 # 0 +0x0000FEDC 0xE389 # 0 +0x0000FEDD 0xE38A # 0 +0x0000FEDE 0xE38B # 0 +0x0000FEDF 0xE38C # 0 +0x0000FEE0 0xE38D # 0 +0x0000FEE1 0xE38E # 0 +0x0000FEE2 0xE38F # 0 +0x0000FEE3 0xE390 # 0 +0x0000FEE4 0xE391 # 0 +0x0000FEE5 0xE392 # 0 +0x0000FEE6 0xE393 # 0 +0x0000FEE7 0xE394 # 0 +0x0000FEE8 0xE395 # 0 +0x0000FEE9 0xE396 # 0 +0x0000FEEA 0xE397 # 0 +0x0000FEEB 0xE398 # 0 +0x0000FEEC 0xE399 # 0 +0x0000FEED 0xE39A # 0 +0x0000FEEE 0xE39B # 0 +0x0000FEEF 0xE39C # 0 +0x0000FEF0 0xE39D # 0 +0x0000FEF1 0xE39E # 0 +0x0000FEF2 0xE39F # 0 +0x0000FEF3 0xE3A0 # 0 +0x0000FEF4 0xE3A1 # 0 +0x0000FEF5 0xE3A2 # 0 +0x0000FEF6 0xE3A3 # 0 +0x0000FEF7 0xE3A4 # 0 +0x0000FEF8 0xE3A5 # 0 +0x0000FEF9 0xE3A6 # 0 +0x0000FEFA 0xE3A7 # 0 +0x0000FEFB 0xE3A8 # 0 +0x0000FEFC 0xE3A9 # 0 +0x0000FEFD 0xE3AA # 0 +0x0000FEFE 0xE3AB # 0 +0x008FA2AF 0x02D8 # 0 +0x008FA2B0 0x02C7 # 0 +0x008FA2B1 0x00B8 # 0 +0x008FA2B2 0x02D9 # 0 +0x008FA2B3 0x02DD # 0 +0x008FA2B4 0x00AF # 0 +0x008FA2B5 0x02DB # 0 +0x008FA2B6 0x02DA # 0 +0x008FA2B7 0xFF5E # 0 +0x008FA2B8 0x0384 # 0 +0x008FA2B9 0x0385 # 0 +0x008FA2C2 0x00A1 # 0 +0x008FA2C3 0x00A6 # 0 +0x008FA2C4 0x00BF # 0 +0x008FA2EB 0x00BA # 0 +0x008FA2EC 0x00AA # 0 +0x008FA2ED 0x00A9 # 0 +0x008FA2EE 0x00AE # 0 +0x008FA2EF 0x2122 # 0 +0x008FA2F0 0x00A4 # 0 +0x008FA2F1 0x2116 # 0 +0x008FA6E1 0x0386 # 0 +0x008FA6E2 0x0388 # 0 +0x008FA6E3 0x0389 # 0 +0x008FA6E4 0x038A # 0 +0x008FA6E5 0x03AA # 0 +0x008FA6E7 0x038C # 0 +0x008FA6E9 0x038E # 0 +0x008FA6EA 0x03AB # 0 +0x008FA6EC 0x038F # 0 +0x008FA6F1 0x03AC # 0 +0x008FA6F2 0x03AD # 0 +0x008FA6F3 0x03AE # 0 +0x008FA6F4 0x03AF # 0 +0x008FA6F5 0x03CA # 0 +0x008FA6F6 0x0390 # 0 +0x008FA6F7 0x03CC # 0 +0x008FA6F8 0x03C2 # 0 +0x008FA6F9 0x03CD # 0 +0x008FA6FA 0x03CB # 0 +0x008FA6FB 0x03B0 # 0 +0x008FA6FC 0x03CE # 0 +0x008FA7C2 0x0402 # 0 +0x008FA7C3 0x0403 # 0 +0x008FA7C4 0x0404 # 0 +0x008FA7C5 0x0405 # 0 +0x008FA7C6 0x0406 # 0 +0x008FA7C7 0x0407 # 0 +0x008FA7C8 0x0408 # 0 +0x008FA7C9 0x0409 # 0 +0x008FA7CA 0x040A # 0 +0x008FA7CB 0x040B # 0 +0x008FA7CC 0x040C # 0 +0x008FA7CD 0x040E # 0 +0x008FA7CE 0x040F # 0 +0x008FA7F2 0x0452 # 0 +0x008FA7F3 0x0453 # 0 +0x008FA7F4 0x0454 # 0 +0x008FA7F5 0x0455 # 0 +0x008FA7F6 0x0456 # 0 +0x008FA7F7 0x0457 # 0 +0x008FA7F8 0x0458 # 0 +0x008FA7F9 0x0459 # 0 +0x008FA7FA 0x045A # 0 +0x008FA7FB 0x045B # 0 +0x008FA7FC 0x045C # 0 +0x008FA7FD 0x045E # 0 +0x008FA7FE 0x045F # 0 +0x008FA9A1 0x00C6 # 0 +0x008FA9A2 0x0110 # 0 +0x008FA9A4 0x0126 # 0 +0x008FA9A6 0x0132 # 0 +0x008FA9A8 0x0141 # 0 +0x008FA9A9 0x013F # 0 +0x008FA9AB 0x014A # 0 +0x008FA9AC 0x00D8 # 0 +0x008FA9AD 0x0152 # 0 +0x008FA9AF 0x0166 # 0 +0x008FA9B0 0x00DE # 0 +0x008FA9C1 0x00E6 # 0 +0x008FA9C2 0x0111 # 0 +0x008FA9C3 0x00F0 # 0 +0x008FA9C4 0x0127 # 0 +0x008FA9C5 0x0131 # 0 +0x008FA9C6 0x0133 # 0 +0x008FA9C7 0x0138 # 0 +0x008FA9C8 0x0142 # 0 +0x008FA9C9 0x0140 # 0 +0x008FA9CA 0x0149 # 0 +0x008FA9CB 0x014B # 0 +0x008FA9CC 0x00F8 # 0 +0x008FA9CD 0x0153 # 0 +0x008FA9CE 0x00DF # 0 +0x008FA9CF 0x0167 # 0 +0x008FA9D0 0x00FE # 0 +0x008FAAA1 0x00C1 # 0 +0x008FAAA2 0x00C0 # 0 +0x008FAAA3 0x00C4 # 0 +0x008FAAA4 0x00C2 # 0 +0x008FAAA5 0x0102 # 0 +0x008FAAA6 0x01CD # 0 +0x008FAAA7 0x0100 # 0 +0x008FAAA8 0x0104 # 0 +0x008FAAA9 0x00C5 # 0 +0x008FAAAA 0x00C3 # 0 +0x008FAAAB 0x0106 # 0 +0x008FAAAC 0x0108 # 0 +0x008FAAAD 0x010C # 0 +0x008FAAAE 0x00C7 # 0 +0x008FAAAF 0x010A # 0 +0x008FAAB0 0x010E # 0 +0x008FAAB1 0x00C9 # 0 +0x008FAAB2 0x00C8 # 0 +0x008FAAB3 0x00CB # 0 +0x008FAAB4 0x00CA # 0 +0x008FAAB5 0x011A # 0 +0x008FAAB6 0x0116 # 0 +0x008FAAB7 0x0112 # 0 +0x008FAAB8 0x0118 # 0 +0x008FAABA 0x011C # 0 +0x008FAABB 0x011E # 0 +0x008FAABC 0x0122 # 0 +0x008FAABD 0x0120 # 0 +0x008FAABE 0x0124 # 0 +0x008FAABF 0x00CD # 0 +0x008FAAC0 0x00CC # 0 +0x008FAAC1 0x00CF # 0 +0x008FAAC2 0x00CE # 0 +0x008FAAC3 0x01CF # 0 +0x008FAAC4 0x0130 # 0 +0x008FAAC5 0x012A # 0 +0x008FAAC6 0x012E # 0 +0x008FAAC7 0x0128 # 0 +0x008FAAC8 0x0134 # 0 +0x008FAAC9 0x0136 # 0 +0x008FAACA 0x0139 # 0 +0x008FAACB 0x013D # 0 +0x008FAACC 0x013B # 0 +0x008FAACD 0x0143 # 0 +0x008FAACE 0x0147 # 0 +0x008FAACF 0x0145 # 0 +0x008FAAD0 0x00D1 # 0 +0x008FAAD1 0x00D3 # 0 +0x008FAAD2 0x00D2 # 0 +0x008FAAD3 0x00D6 # 0 +0x008FAAD4 0x00D4 # 0 +0x008FAAD5 0x01D1 # 0 +0x008FAAD6 0x0150 # 0 +0x008FAAD7 0x014C # 0 +0x008FAAD8 0x00D5 # 0 +0x008FAAD9 0x0154 # 0 +0x008FAADA 0x0158 # 0 +0x008FAADB 0x0156 # 0 +0x008FAADC 0x015A # 0 +0x008FAADD 0x015C # 0 +0x008FAADE 0x0160 # 0 +0x008FAADF 0x015E # 0 +0x008FAAE0 0x0164 # 0 +0x008FAAE1 0x0162 # 0 +0x008FAAE2 0x00DA # 0 +0x008FAAE3 0x00D9 # 0 +0x008FAAE4 0x00DC # 0 +0x008FAAE5 0x00DB # 0 +0x008FAAE6 0x016C # 0 +0x008FAAE7 0x01D3 # 0 +0x008FAAE8 0x0170 # 0 +0x008FAAE9 0x016A # 0 +0x008FAAEA 0x0172 # 0 +0x008FAAEB 0x016E # 0 +0x008FAAEC 0x0168 # 0 +0x008FAAED 0x01D7 # 0 +0x008FAAEE 0x01DB # 0 +0x008FAAEF 0x01D9 # 0 +0x008FAAF0 0x01D5 # 0 +0x008FAAF1 0x0174 # 0 +0x008FAAF2 0x00DD # 0 +0x008FAAF3 0x0178 # 0 +0x008FAAF4 0x0176 # 0 +0x008FAAF5 0x0179 # 0 +0x008FAAF6 0x017D # 0 +0x008FAAF7 0x017B # 0 +0x008FABA1 0x00E1 # 0 +0x008FABA2 0x00E0 # 0 +0x008FABA3 0x00E4 # 0 +0x008FABA4 0x00E2 # 0 +0x008FABA5 0x0103 # 0 +0x008FABA6 0x01CE # 0 +0x008FABA7 0x0101 # 0 +0x008FABA8 0x0105 # 0 +0x008FABA9 0x00E5 # 0 +0x008FABAA 0x00E3 # 0 +0x008FABAB 0x0107 # 0 +0x008FABAC 0x0109 # 0 +0x008FABAD 0x010D # 0 +0x008FABAE 0x00E7 # 0 +0x008FABAF 0x010B # 0 +0x008FABB0 0x010F # 0 +0x008FABB1 0x00E9 # 0 +0x008FABB2 0x00E8 # 0 +0x008FABB3 0x00EB # 0 +0x008FABB4 0x00EA # 0 +0x008FABB5 0x011B # 0 +0x008FABB6 0x0117 # 0 +0x008FABB7 0x0113 # 0 +0x008FABB8 0x0119 # 0 +0x008FABB9 0x01F5 # 0 +0x008FABBA 0x011D # 0 +0x008FABBB 0x011F # 0 +0x008FABBD 0x0121 # 0 +0x008FABBE 0x0125 # 0 +0x008FABBF 0x00ED # 0 +0x008FABC0 0x00EC # 0 +0x008FABC1 0x00EF # 0 +0x008FABC2 0x00EE # 0 +0x008FABC3 0x01D0 # 0 +0x008FABC5 0x012B # 0 +0x008FABC6 0x012F # 0 +0x008FABC7 0x0129 # 0 +0x008FABC8 0x0135 # 0 +0x008FABC9 0x0137 # 0 +0x008FABCA 0x013A # 0 +0x008FABCB 0x013E # 0 +0x008FABCC 0x013C # 0 +0x008FABCD 0x0144 # 0 +0x008FABCE 0x0148 # 0 +0x008FABCF 0x0146 # 0 +0x008FABD0 0x00F1 # 0 +0x008FABD1 0x00F3 # 0 +0x008FABD2 0x00F2 # 0 +0x008FABD3 0x00F6 # 0 +0x008FABD4 0x00F4 # 0 +0x008FABD5 0x01D2 # 0 +0x008FABD6 0x0151 # 0 +0x008FABD7 0x014D # 0 +0x008FABD8 0x00F5 # 0 +0x008FABD9 0x0155 # 0 +0x008FABDA 0x0159 # 0 +0x008FABDB 0x0157 # 0 +0x008FABDC 0x015B # 0 +0x008FABDD 0x015D # 0 +0x008FABDE 0x0161 # 0 +0x008FABDF 0x015F # 0 +0x008FABE0 0x0165 # 0 +0x008FABE1 0x0163 # 0 +0x008FABE2 0x00FA # 0 +0x008FABE3 0x00F9 # 0 +0x008FABE4 0x00FC # 0 +0x008FABE5 0x00FB # 0 +0x008FABE6 0x016D # 0 +0x008FABE7 0x01D4 # 0 +0x008FABE8 0x0171 # 0 +0x008FABE9 0x016B # 0 +0x008FABEA 0x0173 # 0 +0x008FABEB 0x016F # 0 +0x008FABEC 0x0169 # 0 +0x008FABED 0x01D8 # 0 +0x008FABEE 0x01DC # 0 +0x008FABEF 0x01DA # 0 +0x008FABF0 0x01D6 # 0 +0x008FABF1 0x0175 # 0 +0x008FABF2 0x00FD # 0 +0x008FABF3 0x00FF # 0 +0x008FABF4 0x0177 # 0 +0x008FABF5 0x017A # 0 +0x008FABF6 0x017E # 0 +0x008FABF7 0x017C # 0 +0x008FB0A1 0x4E02 # 0 +0x008FB0A2 0x4E04 # 0 +0x008FB0A3 0x4E05 # 0 +0x008FB0A4 0x4E0C # 0 +0x008FB0A5 0x4E12 # 0 +0x008FB0A6 0x4E1F # 0 +0x008FB0A7 0x4E23 # 0 +0x008FB0A8 0x4E24 # 0 +0x008FB0A9 0x4E28 # 0 +0x008FB0AA 0x4E2B # 0 +0x008FB0AB 0x4E2E # 0 +0x008FB0AC 0x4E2F # 0 +0x008FB0AD 0x4E30 # 0 +0x008FB0AE 0x4E35 # 0 +0x008FB0AF 0x4E40 # 0 +0x008FB0B0 0x4E41 # 0 +0x008FB0B1 0x4E44 # 0 +0x008FB0B2 0x4E47 # 0 +0x008FB0B3 0x4E51 # 0 +0x008FB0B4 0x4E5A # 0 +0x008FB0B5 0x4E5C # 0 +0x008FB0B6 0x4E63 # 0 +0x008FB0B7 0x4E68 # 0 +0x008FB0B8 0x4E69 # 0 +0x008FB0B9 0x4E74 # 0 +0x008FB0BA 0x4E75 # 0 +0x008FB0BB 0x4E79 # 0 +0x008FB0BC 0x4E7F # 0 +0x008FB0BD 0x4E8D # 0 +0x008FB0BE 0x4E96 # 0 +0x008FB0BF 0x4E97 # 0 +0x008FB0C0 0x4E9D # 0 +0x008FB0C1 0x4EAF # 0 +0x008FB0C2 0x4EB9 # 0 +0x008FB0C3 0x4EC3 # 0 +0x008FB0C4 0x4ED0 # 0 +0x008FB0C5 0x4EDA # 0 +0x008FB0C6 0x4EDB # 0 +0x008FB0C7 0x4EE0 # 0 +0x008FB0C8 0x4EE1 # 0 +0x008FB0C9 0x4EE2 # 0 +0x008FB0CA 0x4EE8 # 0 +0x008FB0CB 0x4EEF # 0 +0x008FB0CC 0x4EF1 # 0 +0x008FB0CD 0x4EF3 # 0 +0x008FB0CE 0x4EF5 # 0 +0x008FB0CF 0x4EFD # 0 +0x008FB0D0 0x4EFE # 0 +0x008FB0D1 0x4EFF # 0 +0x008FB0D2 0x4F00 # 0 +0x008FB0D3 0x4F02 # 0 +0x008FB0D4 0x4F03 # 0 +0x008FB0D5 0x4F08 # 0 +0x008FB0D6 0x4F0B # 0 +0x008FB0D7 0x4F0C # 0 +0x008FB0D8 0x4F12 # 0 +0x008FB0D9 0x4F15 # 0 +0x008FB0DA 0x4F16 # 0 +0x008FB0DB 0x4F17 # 0 +0x008FB0DC 0x4F19 # 0 +0x008FB0DD 0x4F2E # 0 +0x008FB0DE 0x4F31 # 0 +0x008FB0DF 0x4F60 # 0 +0x008FB0E0 0x4F33 # 0 +0x008FB0E1 0x4F35 # 0 +0x008FB0E2 0x4F37 # 0 +0x008FB0E3 0x4F39 # 0 +0x008FB0E4 0x4F3B # 0 +0x008FB0E5 0x4F3E # 0 +0x008FB0E6 0x4F40 # 0 +0x008FB0E7 0x4F42 # 0 +0x008FB0E8 0x4F48 # 0 +0x008FB0E9 0x4F49 # 0 +0x008FB0EA 0x4F4B # 0 +0x008FB0EB 0x4F4C # 0 +0x008FB0EC 0x4F52 # 0 +0x008FB0ED 0x4F54 # 0 +0x008FB0EE 0x4F56 # 0 +0x008FB0EF 0x4F58 # 0 +0x008FB0F0 0x4F5F # 0 +0x008FB0F1 0x4F63 # 0 +0x008FB0F2 0x4F6A # 0 +0x008FB0F3 0x4F6C # 0 +0x008FB0F4 0x4F6E # 0 +0x008FB0F5 0x4F71 # 0 +0x008FB0F6 0x4F77 # 0 +0x008FB0F7 0x4F78 # 0 +0x008FB0F8 0x4F79 # 0 +0x008FB0F9 0x4F7A # 0 +0x008FB0FA 0x4F7D # 0 +0x008FB0FB 0x4F7E # 0 +0x008FB0FC 0x4F81 # 0 +0x008FB0FD 0x4F82 # 0 +0x008FB0FE 0x4F84 # 0 +0x008FB1A1 0x4F85 # 0 +0x008FB1A2 0x4F89 # 0 +0x008FB1A3 0x4F8A # 0 +0x008FB1A4 0x4F8C # 0 +0x008FB1A5 0x4F8E # 0 +0x008FB1A6 0x4F90 # 0 +0x008FB1A7 0x4F92 # 0 +0x008FB1A8 0x4F93 # 0 +0x008FB1A9 0x4F94 # 0 +0x008FB1AA 0x4F97 # 0 +0x008FB1AB 0x4F99 # 0 +0x008FB1AC 0x4F9A # 0 +0x008FB1AD 0x4F9E # 0 +0x008FB1AE 0x4F9F # 0 +0x008FB1AF 0x4FB2 # 0 +0x008FB1B0 0x4FB7 # 0 +0x008FB1B1 0x4FB9 # 0 +0x008FB1B2 0x4FBB # 0 +0x008FB1B3 0x4FBC # 0 +0x008FB1B4 0x4FBD # 0 +0x008FB1B5 0x4FBE # 0 +0x008FB1B6 0x4FC0 # 0 +0x008FB1B7 0x4FC1 # 0 +0x008FB1B8 0x4FC5 # 0 +0x008FB1B9 0x4FC6 # 0 +0x008FB1BA 0x4FC8 # 0 +0x008FB1BB 0x4FC9 # 0 +0x008FB1BC 0x4FCB # 0 +0x008FB1BD 0x4FCC # 0 +0x008FB1BE 0x4FCD # 0 +0x008FB1BF 0x4FCF # 0 +0x008FB1C0 0x4FD2 # 0 +0x008FB1C1 0x4FDC # 0 +0x008FB1C2 0x4FE0 # 0 +0x008FB1C3 0x4FE2 # 0 +0x008FB1C4 0x4FF0 # 0 +0x008FB1C5 0x4FF2 # 0 +0x008FB1C6 0x4FFC # 0 +0x008FB1C7 0x4FFD # 0 +0x008FB1C8 0x4FFF # 0 +0x008FB1C9 0x5000 # 0 +0x008FB1CA 0x5001 # 0 +0x008FB1CB 0x5004 # 0 +0x008FB1CC 0x5007 # 0 +0x008FB1CD 0x500A # 0 +0x008FB1CE 0x500C # 0 +0x008FB1CF 0x500E # 0 +0x008FB1D0 0x5010 # 0 +0x008FB1D1 0x5013 # 0 +0x008FB1D2 0x5017 # 0 +0x008FB1D3 0x5018 # 0 +0x008FB1D4 0x501B # 0 +0x008FB1D5 0x501C # 0 +0x008FB1D6 0x501D # 0 +0x008FB1D7 0x501E # 0 +0x008FB1D8 0x5022 # 0 +0x008FB1D9 0x5027 # 0 +0x008FB1DA 0x502E # 0 +0x008FB1DB 0x5030 # 0 +0x008FB1DC 0x5032 # 0 +0x008FB1DD 0x5033 # 0 +0x008FB1DE 0x5035 # 0 +0x008FB1DF 0x5040 # 0 +0x008FB1E0 0x5041 # 0 +0x008FB1E1 0x5042 # 0 +0x008FB1E2 0x5045 # 0 +0x008FB1E3 0x5046 # 0 +0x008FB1E4 0x504A # 0 +0x008FB1E5 0x504C # 0 +0x008FB1E6 0x504E # 0 +0x008FB1E7 0x5051 # 0 +0x008FB1E8 0x5052 # 0 +0x008FB1E9 0x5053 # 0 +0x008FB1EA 0x5057 # 0 +0x008FB1EB 0x5059 # 0 +0x008FB1EC 0x505F # 0 +0x008FB1ED 0x5060 # 0 +0x008FB1EE 0x5062 # 0 +0x008FB1EF 0x5063 # 0 +0x008FB1F0 0x5066 # 0 +0x008FB1F1 0x5067 # 0 +0x008FB1F2 0x506A # 0 +0x008FB1F3 0x506D # 0 +0x008FB1F4 0x5070 # 0 +0x008FB1F5 0x5071 # 0 +0x008FB1F6 0x503B # 0 +0x008FB1F7 0x5081 # 0 +0x008FB1F8 0x5083 # 0 +0x008FB1F9 0x5084 # 0 +0x008FB1FA 0x5086 # 0 +0x008FB1FB 0x508A # 0 +0x008FB1FC 0x508E # 0 +0x008FB1FD 0x508F # 0 +0x008FB1FE 0x5090 # 0 +0x008FB2A1 0x5092 # 0 +0x008FB2A2 0x5093 # 0 +0x008FB2A3 0x5094 # 0 +0x008FB2A4 0x5096 # 0 +0x008FB2A5 0x509B # 0 +0x008FB2A6 0x509C # 0 +0x008FB2A7 0x509E # 0 +0x008FB2A8 0x509F # 0 +0x008FB2A9 0x50A0 # 0 +0x008FB2AA 0x50A1 # 0 +0x008FB2AB 0x50A2 # 0 +0x008FB2AC 0x50AA # 0 +0x008FB2AD 0x50AF # 0 +0x008FB2AE 0x50B0 # 0 +0x008FB2AF 0x50B9 # 0 +0x008FB2B0 0x50BA # 0 +0x008FB2B1 0x50BD # 0 +0x008FB2B2 0x50C0 # 0 +0x008FB2B3 0x50C3 # 0 +0x008FB2B4 0x50C4 # 0 +0x008FB2B5 0x50C7 # 0 +0x008FB2B6 0x50CC # 0 +0x008FB2B7 0x50CE # 0 +0x008FB2B8 0x50D0 # 0 +0x008FB2B9 0x50D3 # 0 +0x008FB2BA 0x50D4 # 0 +0x008FB2BB 0x50D8 # 0 +0x008FB2BC 0x50DC # 0 +0x008FB2BD 0x50DD # 0 +0x008FB2BE 0x50DF # 0 +0x008FB2BF 0x50E2 # 0 +0x008FB2C0 0x50E4 # 0 +0x008FB2C1 0x50E6 # 0 +0x008FB2C2 0x50E8 # 0 +0x008FB2C3 0x50E9 # 0 +0x008FB2C4 0x50EF # 0 +0x008FB2C5 0x50F1 # 0 +0x008FB2C6 0x50F6 # 0 +0x008FB2C7 0x50FA # 0 +0x008FB2C8 0x50FE # 0 +0x008FB2C9 0x5103 # 0 +0x008FB2CA 0x5106 # 0 +0x008FB2CB 0x5107 # 0 +0x008FB2CC 0x5108 # 0 +0x008FB2CD 0x510B # 0 +0x008FB2CE 0x510C # 0 +0x008FB2CF 0x510D # 0 +0x008FB2D0 0x510E # 0 +0x008FB2D1 0x50F2 # 0 +0x008FB2D2 0x5110 # 0 +0x008FB2D3 0x5117 # 0 +0x008FB2D4 0x5119 # 0 +0x008FB2D5 0x511B # 0 +0x008FB2D6 0x511C # 0 +0x008FB2D7 0x511D # 0 +0x008FB2D8 0x511E # 0 +0x008FB2D9 0x5123 # 0 +0x008FB2DA 0x5127 # 0 +0x008FB2DB 0x5128 # 0 +0x008FB2DC 0x512C # 0 +0x008FB2DD 0x512D # 0 +0x008FB2DE 0x512F # 0 +0x008FB2DF 0x5131 # 0 +0x008FB2E0 0x5133 # 0 +0x008FB2E1 0x5134 # 0 +0x008FB2E2 0x5135 # 0 +0x008FB2E3 0x5138 # 0 +0x008FB2E4 0x5139 # 0 +0x008FB2E5 0x5142 # 0 +0x008FB2E6 0x514A # 0 +0x008FB2E7 0x514F # 0 +0x008FB2E8 0x5153 # 0 +0x008FB2E9 0x5155 # 0 +0x008FB2EA 0x5157 # 0 +0x008FB2EB 0x5158 # 0 +0x008FB2EC 0x515F # 0 +0x008FB2ED 0x5164 # 0 +0x008FB2EE 0x5166 # 0 +0x008FB2EF 0x517E # 0 +0x008FB2F0 0x5183 # 0 +0x008FB2F1 0x5184 # 0 +0x008FB2F2 0x518B # 0 +0x008FB2F3 0x518E # 0 +0x008FB2F4 0x5198 # 0 +0x008FB2F5 0x519D # 0 +0x008FB2F6 0x51A1 # 0 +0x008FB2F7 0x51A3 # 0 +0x008FB2F8 0x51AD # 0 +0x008FB2F9 0x51B8 # 0 +0x008FB2FA 0x51BA # 0 +0x008FB2FB 0x51BC # 0 +0x008FB2FC 0x51BE # 0 +0x008FB2FD 0x51BF # 0 +0x008FB2FE 0x51C2 # 0 +0x008FB3A1 0x51C8 # 0 +0x008FB3A2 0x51CF # 0 +0x008FB3A3 0x51D1 # 0 +0x008FB3A4 0x51D2 # 0 +0x008FB3A5 0x51D3 # 0 +0x008FB3A6 0x51D5 # 0 +0x008FB3A7 0x51D8 # 0 +0x008FB3A8 0x51DE # 0 +0x008FB3A9 0x51E2 # 0 +0x008FB3AA 0x51E5 # 0 +0x008FB3AB 0x51EE # 0 +0x008FB3AC 0x51F2 # 0 +0x008FB3AD 0x51F3 # 0 +0x008FB3AE 0x51F4 # 0 +0x008FB3AF 0x51F7 # 0 +0x008FB3B0 0x5201 # 0 +0x008FB3B1 0x5202 # 0 +0x008FB3B2 0x5205 # 0 +0x008FB3B3 0x5212 # 0 +0x008FB3B4 0x5213 # 0 +0x008FB3B5 0x5215 # 0 +0x008FB3B6 0x5216 # 0 +0x008FB3B7 0x5218 # 0 +0x008FB3B8 0x5222 # 0 +0x008FB3B9 0x5228 # 0 +0x008FB3BA 0x5231 # 0 +0x008FB3BB 0x5232 # 0 +0x008FB3BC 0x5235 # 0 +0x008FB3BD 0x523C # 0 +0x008FB3BE 0x5245 # 0 +0x008FB3BF 0x5249 # 0 +0x008FB3C0 0x5255 # 0 +0x008FB3C1 0x5257 # 0 +0x008FB3C2 0x5258 # 0 +0x008FB3C3 0x525A # 0 +0x008FB3C4 0x525C # 0 +0x008FB3C5 0x525F # 0 +0x008FB3C6 0x5260 # 0 +0x008FB3C7 0x5261 # 0 +0x008FB3C8 0x5266 # 0 +0x008FB3C9 0x526E # 0 +0x008FB3CA 0x5277 # 0 +0x008FB3CB 0x5278 # 0 +0x008FB3CC 0x5279 # 0 +0x008FB3CD 0x5280 # 0 +0x008FB3CE 0x5282 # 0 +0x008FB3CF 0x5285 # 0 +0x008FB3D0 0x528A # 0 +0x008FB3D1 0x528C # 0 +0x008FB3D2 0x5293 # 0 +0x008FB3D3 0x5295 # 0 +0x008FB3D4 0x5296 # 0 +0x008FB3D5 0x5297 # 0 +0x008FB3D6 0x5298 # 0 +0x008FB3D7 0x529A # 0 +0x008FB3D8 0x529C # 0 +0x008FB3D9 0x52A4 # 0 +0x008FB3DA 0x52A5 # 0 +0x008FB3DB 0x52A6 # 0 +0x008FB3DC 0x52A7 # 0 +0x008FB3DD 0x52AF # 0 +0x008FB3DE 0x52B0 # 0 +0x008FB3DF 0x52B6 # 0 +0x008FB3E0 0x52B7 # 0 +0x008FB3E1 0x52B8 # 0 +0x008FB3E2 0x52BA # 0 +0x008FB3E3 0x52BB # 0 +0x008FB3E4 0x52BD # 0 +0x008FB3E5 0x52C0 # 0 +0x008FB3E6 0x52C4 # 0 +0x008FB3E7 0x52C6 # 0 +0x008FB3E8 0x52C8 # 0 +0x008FB3E9 0x52CC # 0 +0x008FB3EA 0x52CF # 0 +0x008FB3EB 0x52D1 # 0 +0x008FB3EC 0x52D4 # 0 +0x008FB3ED 0x52D6 # 0 +0x008FB3EE 0x52DB # 0 +0x008FB3EF 0x52DC # 0 +0x008FB3F0 0x52E1 # 0 +0x008FB3F1 0x52E5 # 0 +0x008FB3F2 0x52E8 # 0 +0x008FB3F3 0x52E9 # 0 +0x008FB3F4 0x52EA # 0 +0x008FB3F5 0x52EC # 0 +0x008FB3F6 0x52F0 # 0 +0x008FB3F7 0x52F1 # 0 +0x008FB3F8 0x52F4 # 0 +0x008FB3F9 0x52F6 # 0 +0x008FB3FA 0x52F7 # 0 +0x008FB3FB 0x5300 # 0 +0x008FB3FC 0x5303 # 0 +0x008FB3FD 0x530A # 0 +0x008FB3FE 0x530B # 0 +0x008FB4A1 0x530C # 0 +0x008FB4A2 0x5311 # 0 +0x008FB4A3 0x5313 # 0 +0x008FB4A4 0x5318 # 0 +0x008FB4A5 0x531B # 0 +0x008FB4A6 0x531C # 0 +0x008FB4A7 0x531E # 0 +0x008FB4A8 0x531F # 0 +0x008FB4A9 0x5325 # 0 +0x008FB4AA 0x5327 # 0 +0x008FB4AB 0x5328 # 0 +0x008FB4AC 0x5329 # 0 +0x008FB4AD 0x532B # 0 +0x008FB4AE 0x532C # 0 +0x008FB4AF 0x532D # 0 +0x008FB4B0 0x5330 # 0 +0x008FB4B1 0x5332 # 0 +0x008FB4B2 0x5335 # 0 +0x008FB4B3 0x533C # 0 +0x008FB4B4 0x533D # 0 +0x008FB4B5 0x533E # 0 +0x008FB4B6 0x5342 # 0 +0x008FB4B7 0x534C # 0 +0x008FB4B8 0x534B # 0 +0x008FB4B9 0x5359 # 0 +0x008FB4BA 0x535B # 0 +0x008FB4BB 0x5361 # 0 +0x008FB4BC 0x5363 # 0 +0x008FB4BD 0x5365 # 0 +0x008FB4BE 0x536C # 0 +0x008FB4BF 0x536D # 0 +0x008FB4C0 0x5372 # 0 +0x008FB4C1 0x5379 # 0 +0x008FB4C2 0x537E # 0 +0x008FB4C3 0x5383 # 0 +0x008FB4C4 0x5387 # 0 +0x008FB4C5 0x5388 # 0 +0x008FB4C6 0x538E # 0 +0x008FB4C7 0x5393 # 0 +0x008FB4C8 0x5394 # 0 +0x008FB4C9 0x5399 # 0 +0x008FB4CA 0x539D # 0 +0x008FB4CB 0x53A1 # 0 +0x008FB4CC 0x53A4 # 0 +0x008FB4CD 0x53AA # 0 +0x008FB4CE 0x53AB # 0 +0x008FB4CF 0x53AF # 0 +0x008FB4D0 0x53B2 # 0 +0x008FB4D1 0x53B4 # 0 +0x008FB4D2 0x53B5 # 0 +0x008FB4D3 0x53B7 # 0 +0x008FB4D4 0x53B8 # 0 +0x008FB4D5 0x53BA # 0 +0x008FB4D6 0x53BD # 0 +0x008FB4D7 0x53C0 # 0 +0x008FB4D8 0x53C5 # 0 +0x008FB4D9 0x53CF # 0 +0x008FB4DA 0x53D2 # 0 +0x008FB4DB 0x53D3 # 0 +0x008FB4DC 0x53D5 # 0 +0x008FB4DD 0x53DA # 0 +0x008FB4DE 0x53DD # 0 +0x008FB4DF 0x53DE # 0 +0x008FB4E0 0x53E0 # 0 +0x008FB4E1 0x53E6 # 0 +0x008FB4E2 0x53E7 # 0 +0x008FB4E3 0x53F5 # 0 +0x008FB4E4 0x5402 # 0 +0x008FB4E5 0x5413 # 0 +0x008FB4E6 0x541A # 0 +0x008FB4E7 0x5421 # 0 +0x008FB4E8 0x5427 # 0 +0x008FB4E9 0x5428 # 0 +0x008FB4EA 0x542A # 0 +0x008FB4EB 0x542F # 0 +0x008FB4EC 0x5431 # 0 +0x008FB4ED 0x5434 # 0 +0x008FB4EE 0x5435 # 0 +0x008FB4EF 0x5443 # 0 +0x008FB4F0 0x5444 # 0 +0x008FB4F1 0x5447 # 0 +0x008FB4F2 0x544D # 0 +0x008FB4F3 0x544F # 0 +0x008FB4F4 0x545E # 0 +0x008FB4F5 0x5462 # 0 +0x008FB4F6 0x5464 # 0 +0x008FB4F7 0x5466 # 0 +0x008FB4F8 0x5467 # 0 +0x008FB4F9 0x5469 # 0 +0x008FB4FA 0x546B # 0 +0x008FB4FB 0x546D # 0 +0x008FB4FC 0x546E # 0 +0x008FB4FD 0x5474 # 0 +0x008FB4FE 0x547F # 0 +0x008FB5A1 0x5481 # 0 +0x008FB5A2 0x5483 # 0 +0x008FB5A3 0x5485 # 0 +0x008FB5A4 0x5488 # 0 +0x008FB5A5 0x5489 # 0 +0x008FB5A6 0x548D # 0 +0x008FB5A7 0x5491 # 0 +0x008FB5A8 0x5495 # 0 +0x008FB5A9 0x5496 # 0 +0x008FB5AA 0x549C # 0 +0x008FB5AB 0x549F # 0 +0x008FB5AC 0x54A1 # 0 +0x008FB5AD 0x54A6 # 0 +0x008FB5AE 0x54A7 # 0 +0x008FB5AF 0x54A9 # 0 +0x008FB5B0 0x54AA # 0 +0x008FB5B1 0x54AD # 0 +0x008FB5B2 0x54AE # 0 +0x008FB5B3 0x54B1 # 0 +0x008FB5B4 0x54B7 # 0 +0x008FB5B5 0x54B9 # 0 +0x008FB5B6 0x54BA # 0 +0x008FB5B7 0x54BB # 0 +0x008FB5B8 0x54BF # 0 +0x008FB5B9 0x54C6 # 0 +0x008FB5BA 0x54CA # 0 +0x008FB5BB 0x54CD # 0 +0x008FB5BC 0x54CE # 0 +0x008FB5BD 0x54E0 # 0 +0x008FB5BE 0x54EA # 0 +0x008FB5BF 0x54EC # 0 +0x008FB5C0 0x54EF # 0 +0x008FB5C1 0x54F6 # 0 +0x008FB5C2 0x54FC # 0 +0x008FB5C3 0x54FE # 0 +0x008FB5C4 0x54FF # 0 +0x008FB5C5 0x5500 # 0 +0x008FB5C6 0x5501 # 0 +0x008FB5C7 0x5505 # 0 +0x008FB5C8 0x5508 # 0 +0x008FB5C9 0x5509 # 0 +0x008FB5CA 0x550C # 0 +0x008FB5CB 0x550D # 0 +0x008FB5CC 0x550E # 0 +0x008FB5CD 0x5515 # 0 +0x008FB5CE 0x552A # 0 +0x008FB5CF 0x552B # 0 +0x008FB5D0 0x5532 # 0 +0x008FB5D1 0x5535 # 0 +0x008FB5D2 0x5536 # 0 +0x008FB5D3 0x553B # 0 +0x008FB5D4 0x553C # 0 +0x008FB5D5 0x553D # 0 +0x008FB5D6 0x5541 # 0 +0x008FB5D7 0x5547 # 0 +0x008FB5D8 0x5549 # 0 +0x008FB5D9 0x554A # 0 +0x008FB5DA 0x554D # 0 +0x008FB5DB 0x5550 # 0 +0x008FB5DC 0x5551 # 0 +0x008FB5DD 0x5558 # 0 +0x008FB5DE 0x555A # 0 +0x008FB5DF 0x555B # 0 +0x008FB5E0 0x555E # 0 +0x008FB5E1 0x5560 # 0 +0x008FB5E2 0x5561 # 0 +0x008FB5E3 0x5564 # 0 +0x008FB5E4 0x5566 # 0 +0x008FB5E5 0x557F # 0 +0x008FB5E6 0x5581 # 0 +0x008FB5E7 0x5582 # 0 +0x008FB5E8 0x5586 # 0 +0x008FB5E9 0x5588 # 0 +0x008FB5EA 0x558E # 0 +0x008FB5EB 0x558F # 0 +0x008FB5EC 0x5591 # 0 +0x008FB5ED 0x5592 # 0 +0x008FB5EE 0x5593 # 0 +0x008FB5EF 0x5594 # 0 +0x008FB5F0 0x5597 # 0 +0x008FB5F1 0x55A3 # 0 +0x008FB5F2 0x55A4 # 0 +0x008FB5F3 0x55AD # 0 +0x008FB5F4 0x55B2 # 0 +0x008FB5F5 0x55BF # 0 +0x008FB5F6 0x55C1 # 0 +0x008FB5F7 0x55C3 # 0 +0x008FB5F8 0x55C6 # 0 +0x008FB5F9 0x55C9 # 0 +0x008FB5FA 0x55CB # 0 +0x008FB5FB 0x55CC # 0 +0x008FB5FC 0x55CE # 0 +0x008FB5FD 0x55D1 # 0 +0x008FB5FE 0x55D2 # 0 +0x008FB6A1 0x55D3 # 0 +0x008FB6A2 0x55D7 # 0 +0x008FB6A3 0x55D8 # 0 +0x008FB6A4 0x55DB # 0 +0x008FB6A5 0x55DE # 0 +0x008FB6A6 0x55E2 # 0 +0x008FB6A7 0x55E9 # 0 +0x008FB6A8 0x55F6 # 0 +0x008FB6A9 0x55FF # 0 +0x008FB6AA 0x5605 # 0 +0x008FB6AB 0x5608 # 0 +0x008FB6AC 0x560A # 0 +0x008FB6AD 0x560D # 0 +0x008FB6AE 0x560E # 0 +0x008FB6AF 0x560F # 0 +0x008FB6B0 0x5610 # 0 +0x008FB6B1 0x5611 # 0 +0x008FB6B2 0x5612 # 0 +0x008FB6B3 0x5619 # 0 +0x008FB6B4 0x562C # 0 +0x008FB6B5 0x5630 # 0 +0x008FB6B6 0x5633 # 0 +0x008FB6B7 0x5635 # 0 +0x008FB6B8 0x5637 # 0 +0x008FB6B9 0x5639 # 0 +0x008FB6BA 0x563B # 0 +0x008FB6BB 0x563C # 0 +0x008FB6BC 0x563D # 0 +0x008FB6BD 0x563F # 0 +0x008FB6BE 0x5640 # 0 +0x008FB6BF 0x5641 # 0 +0x008FB6C0 0x5643 # 0 +0x008FB6C1 0x5644 # 0 +0x008FB6C2 0x5646 # 0 +0x008FB6C3 0x5649 # 0 +0x008FB6C4 0x564B # 0 +0x008FB6C5 0x564D # 0 +0x008FB6C6 0x564F # 0 +0x008FB6C7 0x5654 # 0 +0x008FB6C8 0x565E # 0 +0x008FB6C9 0x5660 # 0 +0x008FB6CA 0x5661 # 0 +0x008FB6CB 0x5662 # 0 +0x008FB6CC 0x5663 # 0 +0x008FB6CD 0x5666 # 0 +0x008FB6CE 0x5669 # 0 +0x008FB6CF 0x566D # 0 +0x008FB6D0 0x566F # 0 +0x008FB6D1 0x5671 # 0 +0x008FB6D2 0x5672 # 0 +0x008FB6D3 0x5675 # 0 +0x008FB6D4 0x5684 # 0 +0x008FB6D5 0x5685 # 0 +0x008FB6D6 0x5688 # 0 +0x008FB6D7 0x568B # 0 +0x008FB6D8 0x568C # 0 +0x008FB6D9 0x5695 # 0 +0x008FB6DA 0x5699 # 0 +0x008FB6DB 0x569A # 0 +0x008FB6DC 0x569D # 0 +0x008FB6DD 0x569E # 0 +0x008FB6DE 0x569F # 0 +0x008FB6DF 0x56A6 # 0 +0x008FB6E0 0x56A7 # 0 +0x008FB6E1 0x56A8 # 0 +0x008FB6E2 0x56A9 # 0 +0x008FB6E3 0x56AB # 0 +0x008FB6E4 0x56AC # 0 +0x008FB6E5 0x56AD # 0 +0x008FB6E6 0x56B1 # 0 +0x008FB6E7 0x56B3 # 0 +0x008FB6E8 0x56B7 # 0 +0x008FB6E9 0x56BE # 0 +0x008FB6EA 0x56C5 # 0 +0x008FB6EB 0x56C9 # 0 +0x008FB6EC 0x56CA # 0 +0x008FB6ED 0x56CB # 0 +0x008FB6EE 0x56CF # 0 +0x008FB6EF 0x56D0 # 0 +0x008FB6F0 0x56CC # 0 +0x008FB6F1 0x56CD # 0 +0x008FB6F2 0x56D9 # 0 +0x008FB6F3 0x56DC # 0 +0x008FB6F4 0x56DD # 0 +0x008FB6F5 0x56DF # 0 +0x008FB6F6 0x56E1 # 0 +0x008FB6F7 0x56E4 # 0 +0x008FB6F8 0x56E5 # 0 +0x008FB6F9 0x56E6 # 0 +0x008FB6FA 0x56E7 # 0 +0x008FB6FB 0x56E8 # 0 +0x008FB6FC 0x56F1 # 0 +0x008FB6FD 0x56EB # 0 +0x008FB6FE 0x56ED # 0 +0x008FB7A1 0x56F6 # 0 +0x008FB7A2 0x56F7 # 0 +0x008FB7A3 0x5701 # 0 +0x008FB7A4 0x5702 # 0 +0x008FB7A5 0x5707 # 0 +0x008FB7A6 0x570A # 0 +0x008FB7A7 0x570C # 0 +0x008FB7A8 0x5711 # 0 +0x008FB7A9 0x5715 # 0 +0x008FB7AA 0x571A # 0 +0x008FB7AB 0x571B # 0 +0x008FB7AC 0x571D # 0 +0x008FB7AD 0x5720 # 0 +0x008FB7AE 0x5722 # 0 +0x008FB7AF 0x5723 # 0 +0x008FB7B0 0x5724 # 0 +0x008FB7B1 0x5725 # 0 +0x008FB7B2 0x5729 # 0 +0x008FB7B3 0x572A # 0 +0x008FB7B4 0x572C # 0 +0x008FB7B5 0x572E # 0 +0x008FB7B6 0x572F # 0 +0x008FB7B7 0x5733 # 0 +0x008FB7B8 0x5734 # 0 +0x008FB7B9 0x573D # 0 +0x008FB7BA 0x573E # 0 +0x008FB7BB 0x573F # 0 +0x008FB7BC 0x5745 # 0 +0x008FB7BD 0x5746 # 0 +0x008FB7BE 0x574C # 0 +0x008FB7BF 0x574D # 0 +0x008FB7C0 0x5752 # 0 +0x008FB7C1 0x5762 # 0 +0x008FB7C2 0x5765 # 0 +0x008FB7C3 0x5767 # 0 +0x008FB7C4 0x5768 # 0 +0x008FB7C5 0x576B # 0 +0x008FB7C6 0x576D # 0 +0x008FB7C7 0x576E # 0 +0x008FB7C8 0x576F # 0 +0x008FB7C9 0x5770 # 0 +0x008FB7CA 0x5771 # 0 +0x008FB7CB 0x5773 # 0 +0x008FB7CC 0x5774 # 0 +0x008FB7CD 0x5775 # 0 +0x008FB7CE 0x5777 # 0 +0x008FB7CF 0x5779 # 0 +0x008FB7D0 0x577A # 0 +0x008FB7D1 0x577B # 0 +0x008FB7D2 0x577C # 0 +0x008FB7D3 0x577E # 0 +0x008FB7D4 0x5781 # 0 +0x008FB7D5 0x5783 # 0 +0x008FB7D6 0x578C # 0 +0x008FB7D7 0x5794 # 0 +0x008FB7D8 0x5797 # 0 +0x008FB7D9 0x5799 # 0 +0x008FB7DA 0x579A # 0 +0x008FB7DB 0x579C # 0 +0x008FB7DC 0x579D # 0 +0x008FB7DD 0x579E # 0 +0x008FB7DE 0x579F # 0 +0x008FB7DF 0x57A1 # 0 +0x008FB7E0 0x5795 # 0 +0x008FB7E1 0x57A7 # 0 +0x008FB7E2 0x57A8 # 0 +0x008FB7E3 0x57A9 # 0 +0x008FB7E4 0x57AC # 0 +0x008FB7E5 0x57B8 # 0 +0x008FB7E6 0x57BD # 0 +0x008FB7E7 0x57C7 # 0 +0x008FB7E8 0x57C8 # 0 +0x008FB7E9 0x57CC # 0 +0x008FB7EA 0x57CF # 0 +0x008FB7EB 0x57D5 # 0 +0x008FB7EC 0x57DD # 0 +0x008FB7ED 0x57DE # 0 +0x008FB7EE 0x57E4 # 0 +0x008FB7EF 0x57E6 # 0 +0x008FB7F0 0x57E7 # 0 +0x008FB7F1 0x57E9 # 0 +0x008FB7F2 0x57ED # 0 +0x008FB7F3 0x57F0 # 0 +0x008FB7F4 0x57F5 # 0 +0x008FB7F5 0x57F6 # 0 +0x008FB7F6 0x57F8 # 0 +0x008FB7F7 0x57FD # 0 +0x008FB7F8 0x57FE # 0 +0x008FB7F9 0x57FF # 0 +0x008FB7FA 0x5803 # 0 +0x008FB7FB 0x5804 # 0 +0x008FB7FC 0x5808 # 0 +0x008FB7FD 0x5809 # 0 +0x008FB7FE 0x57E1 # 0 +0x008FB8A1 0x580C # 0 +0x008FB8A2 0x580D # 0 +0x008FB8A3 0x581B # 0 +0x008FB8A4 0x581E # 0 +0x008FB8A5 0x581F # 0 +0x008FB8A6 0x5820 # 0 +0x008FB8A7 0x5826 # 0 +0x008FB8A8 0x5827 # 0 +0x008FB8A9 0x582D # 0 +0x008FB8AA 0x5832 # 0 +0x008FB8AB 0x5839 # 0 +0x008FB8AC 0x583F # 0 +0x008FB8AD 0x5849 # 0 +0x008FB8AE 0x584C # 0 +0x008FB8AF 0x584D # 0 +0x008FB8B0 0x584F # 0 +0x008FB8B1 0x5850 # 0 +0x008FB8B2 0x5855 # 0 +0x008FB8B3 0x585F # 0 +0x008FB8B4 0x5861 # 0 +0x008FB8B5 0x5864 # 0 +0x008FB8B6 0x5867 # 0 +0x008FB8B7 0x5868 # 0 +0x008FB8B8 0x5878 # 0 +0x008FB8B9 0x587C # 0 +0x008FB8BA 0x587F # 0 +0x008FB8BB 0x5880 # 0 +0x008FB8BC 0x5881 # 0 +0x008FB8BD 0x5887 # 0 +0x008FB8BE 0x5888 # 0 +0x008FB8BF 0x5889 # 0 +0x008FB8C0 0x588A # 0 +0x008FB8C1 0x588C # 0 +0x008FB8C2 0x588D # 0 +0x008FB8C3 0x588F # 0 +0x008FB8C4 0x5890 # 0 +0x008FB8C5 0x5894 # 0 +0x008FB8C6 0x5896 # 0 +0x008FB8C7 0x589D # 0 +0x008FB8C8 0x58A0 # 0 +0x008FB8C9 0x58A1 # 0 +0x008FB8CA 0x58A2 # 0 +0x008FB8CB 0x58A6 # 0 +0x008FB8CC 0x58A9 # 0 +0x008FB8CD 0x58B1 # 0 +0x008FB8CE 0x58B2 # 0 +0x008FB8CF 0x58C4 # 0 +0x008FB8D0 0x58BC # 0 +0x008FB8D1 0x58C2 # 0 +0x008FB8D2 0x58C8 # 0 +0x008FB8D3 0x58CD # 0 +0x008FB8D4 0x58CE # 0 +0x008FB8D5 0x58D0 # 0 +0x008FB8D6 0x58D2 # 0 +0x008FB8D7 0x58D4 # 0 +0x008FB8D8 0x58D6 # 0 +0x008FB8D9 0x58DA # 0 +0x008FB8DA 0x58DD # 0 +0x008FB8DB 0x58E1 # 0 +0x008FB8DC 0x58E2 # 0 +0x008FB8DD 0x58E9 # 0 +0x008FB8DE 0x58F3 # 0 +0x008FB8DF 0x5905 # 0 +0x008FB8E0 0x5906 # 0 +0x008FB8E1 0x590B # 0 +0x008FB8E2 0x590C # 0 +0x008FB8E3 0x5912 # 0 +0x008FB8E4 0x5913 # 0 +0x008FB8E5 0x5914 # 0 +0x008FB8E6 0x8641 # 0 +0x008FB8E7 0x591D # 0 +0x008FB8E8 0x5921 # 0 +0x008FB8E9 0x5923 # 0 +0x008FB8EA 0x5924 # 0 +0x008FB8EB 0x5928 # 0 +0x008FB8EC 0x592F # 0 +0x008FB8ED 0x5930 # 0 +0x008FB8EE 0x5933 # 0 +0x008FB8EF 0x5935 # 0 +0x008FB8F0 0x5936 # 0 +0x008FB8F1 0x593F # 0 +0x008FB8F2 0x5943 # 0 +0x008FB8F3 0x5946 # 0 +0x008FB8F4 0x5952 # 0 +0x008FB8F5 0x5953 # 0 +0x008FB8F6 0x5959 # 0 +0x008FB8F7 0x595B # 0 +0x008FB8F8 0x595D # 0 +0x008FB8F9 0x595E # 0 +0x008FB8FA 0x595F # 0 +0x008FB8FB 0x5961 # 0 +0x008FB8FC 0x5963 # 0 +0x008FB8FD 0x596B # 0 +0x008FB8FE 0x596D # 0 +0x008FB9A1 0x596F # 0 +0x008FB9A2 0x5972 # 0 +0x008FB9A3 0x5975 # 0 +0x008FB9A4 0x5976 # 0 +0x008FB9A5 0x5979 # 0 +0x008FB9A6 0x597B # 0 +0x008FB9A7 0x597C # 0 +0x008FB9A8 0x598B # 0 +0x008FB9A9 0x598C # 0 +0x008FB9AA 0x598E # 0 +0x008FB9AB 0x5992 # 0 +0x008FB9AC 0x5995 # 0 +0x008FB9AD 0x5997 # 0 +0x008FB9AE 0x599F # 0 +0x008FB9AF 0x59A4 # 0 +0x008FB9B0 0x59A7 # 0 +0x008FB9B1 0x59AD # 0 +0x008FB9B2 0x59AE # 0 +0x008FB9B3 0x59AF # 0 +0x008FB9B4 0x59B0 # 0 +0x008FB9B5 0x59B3 # 0 +0x008FB9B6 0x59B7 # 0 +0x008FB9B7 0x59BA # 0 +0x008FB9B8 0x59BC # 0 +0x008FB9B9 0x59C1 # 0 +0x008FB9BA 0x59C3 # 0 +0x008FB9BB 0x59C4 # 0 +0x008FB9BC 0x59C8 # 0 +0x008FB9BD 0x59CA # 0 +0x008FB9BE 0x59CD # 0 +0x008FB9BF 0x59D2 # 0 +0x008FB9C0 0x59DD # 0 +0x008FB9C1 0x59DE # 0 +0x008FB9C2 0x59DF # 0 +0x008FB9C3 0x59E3 # 0 +0x008FB9C4 0x59E4 # 0 +0x008FB9C5 0x59E7 # 0 +0x008FB9C6 0x59EE # 0 +0x008FB9C7 0x59EF # 0 +0x008FB9C8 0x59F1 # 0 +0x008FB9C9 0x59F2 # 0 +0x008FB9CA 0x59F4 # 0 +0x008FB9CB 0x59F7 # 0 +0x008FB9CC 0x5A00 # 0 +0x008FB9CD 0x5A04 # 0 +0x008FB9CE 0x5A0C # 0 +0x008FB9CF 0x5A0D # 0 +0x008FB9D0 0x5A0E # 0 +0x008FB9D1 0x5A12 # 0 +0x008FB9D2 0x5A13 # 0 +0x008FB9D3 0x5A1E # 0 +0x008FB9D4 0x5A23 # 0 +0x008FB9D5 0x5A24 # 0 +0x008FB9D6 0x5A27 # 0 +0x008FB9D7 0x5A28 # 0 +0x008FB9D8 0x5A2A # 0 +0x008FB9D9 0x5A2D # 0 +0x008FB9DA 0x5A30 # 0 +0x008FB9DB 0x5A44 # 0 +0x008FB9DC 0x5A45 # 0 +0x008FB9DD 0x5A47 # 0 +0x008FB9DE 0x5A48 # 0 +0x008FB9DF 0x5A4C # 0 +0x008FB9E0 0x5A50 # 0 +0x008FB9E1 0x5A55 # 0 +0x008FB9E2 0x5A5E # 0 +0x008FB9E3 0x5A63 # 0 +0x008FB9E4 0x5A65 # 0 +0x008FB9E5 0x5A67 # 0 +0x008FB9E6 0x5A6D # 0 +0x008FB9E7 0x5A77 # 0 +0x008FB9E8 0x5A7A # 0 +0x008FB9E9 0x5A7B # 0 +0x008FB9EA 0x5A7E # 0 +0x008FB9EB 0x5A8B # 0 +0x008FB9EC 0x5A90 # 0 +0x008FB9ED 0x5A93 # 0 +0x008FB9EE 0x5A96 # 0 +0x008FB9EF 0x5A99 # 0 +0x008FB9F0 0x5A9C # 0 +0x008FB9F1 0x5A9E # 0 +0x008FB9F2 0x5A9F # 0 +0x008FB9F3 0x5AA0 # 0 +0x008FB9F4 0x5AA2 # 0 +0x008FB9F5 0x5AA7 # 0 +0x008FB9F6 0x5AAC # 0 +0x008FB9F7 0x5AB1 # 0 +0x008FB9F8 0x5AB2 # 0 +0x008FB9F9 0x5AB3 # 0 +0x008FB9FA 0x5AB5 # 0 +0x008FB9FB 0x5AB8 # 0 +0x008FB9FC 0x5ABA # 0 +0x008FB9FD 0x5ABB # 0 +0x008FB9FE 0x5ABF # 0 +0x008FBAA1 0x5AC4 # 0 +0x008FBAA2 0x5AC6 # 0 +0x008FBAA3 0x5AC8 # 0 +0x008FBAA4 0x5ACF # 0 +0x008FBAA5 0x5ADA # 0 +0x008FBAA6 0x5ADC # 0 +0x008FBAA7 0x5AE0 # 0 +0x008FBAA8 0x5AE5 # 0 +0x008FBAA9 0x5AEA # 0 +0x008FBAAA 0x5AEE # 0 +0x008FBAAB 0x5AF5 # 0 +0x008FBAAC 0x5AF6 # 0 +0x008FBAAD 0x5AFD # 0 +0x008FBAAE 0x5B00 # 0 +0x008FBAAF 0x5B01 # 0 +0x008FBAB0 0x5B08 # 0 +0x008FBAB1 0x5B17 # 0 +0x008FBAB2 0x5B34 # 0 +0x008FBAB3 0x5B19 # 0 +0x008FBAB4 0x5B1B # 0 +0x008FBAB5 0x5B1D # 0 +0x008FBAB6 0x5B21 # 0 +0x008FBAB7 0x5B25 # 0 +0x008FBAB8 0x5B2D # 0 +0x008FBAB9 0x5B38 # 0 +0x008FBABA 0x5B41 # 0 +0x008FBABB 0x5B4B # 0 +0x008FBABC 0x5B4C # 0 +0x008FBABD 0x5B52 # 0 +0x008FBABE 0x5B56 # 0 +0x008FBABF 0x5B5E # 0 +0x008FBAC0 0x5B68 # 0 +0x008FBAC1 0x5B6E # 0 +0x008FBAC2 0x5B6F # 0 +0x008FBAC3 0x5B7C # 0 +0x008FBAC4 0x5B7D # 0 +0x008FBAC5 0x5B7E # 0 +0x008FBAC6 0x5B7F # 0 +0x008FBAC7 0x5B81 # 0 +0x008FBAC8 0x5B84 # 0 +0x008FBAC9 0x5B86 # 0 +0x008FBACA 0x5B8A # 0 +0x008FBACB 0x5B8E # 0 +0x008FBACC 0x5B90 # 0 +0x008FBACD 0x5B91 # 0 +0x008FBACE 0x5B93 # 0 +0x008FBACF 0x5B94 # 0 +0x008FBAD0 0x5B96 # 0 +0x008FBAD1 0x5BA8 # 0 +0x008FBAD2 0x5BA9 # 0 +0x008FBAD3 0x5BAC # 0 +0x008FBAD4 0x5BAD # 0 +0x008FBAD5 0x5BAF # 0 +0x008FBAD6 0x5BB1 # 0 +0x008FBAD7 0x5BB2 # 0 +0x008FBAD8 0x5BB7 # 0 +0x008FBAD9 0x5BBA # 0 +0x008FBADA 0x5BBC # 0 +0x008FBADB 0x5BC0 # 0 +0x008FBADC 0x5BC1 # 0 +0x008FBADD 0x5BCD # 0 +0x008FBADE 0x5BCF # 0 +0x008FBADF 0x5BD6 # 0 +0x008FBAE0 0x5BD7 # 0 +0x008FBAE1 0x5BD8 # 0 +0x008FBAE2 0x5BD9 # 0 +0x008FBAE3 0x5BDA # 0 +0x008FBAE4 0x5BE0 # 0 +0x008FBAE5 0x5BEF # 0 +0x008FBAE6 0x5BF1 # 0 +0x008FBAE7 0x5BF4 # 0 +0x008FBAE8 0x5BFD # 0 +0x008FBAE9 0x5C0C # 0 +0x008FBAEA 0x5C17 # 0 +0x008FBAEB 0x5C1E # 0 +0x008FBAEC 0x5C1F # 0 +0x008FBAED 0x5C23 # 0 +0x008FBAEE 0x5C26 # 0 +0x008FBAEF 0x5C29 # 0 +0x008FBAF0 0x5C2B # 0 +0x008FBAF1 0x5C2C # 0 +0x008FBAF2 0x5C2E # 0 +0x008FBAF3 0x5C30 # 0 +0x008FBAF4 0x5C32 # 0 +0x008FBAF5 0x5C35 # 0 +0x008FBAF6 0x5C36 # 0 +0x008FBAF7 0x5C59 # 0 +0x008FBAF8 0x5C5A # 0 +0x008FBAF9 0x5C5C # 0 +0x008FBAFA 0x5C62 # 0 +0x008FBAFB 0x5C63 # 0 +0x008FBAFC 0x5C67 # 0 +0x008FBAFD 0x5C68 # 0 +0x008FBAFE 0x5C69 # 0 +0x008FBBA1 0x5C6D # 0 +0x008FBBA2 0x5C70 # 0 +0x008FBBA3 0x5C74 # 0 +0x008FBBA4 0x5C75 # 0 +0x008FBBA5 0x5C7A # 0 +0x008FBBA6 0x5C7B # 0 +0x008FBBA7 0x5C7C # 0 +0x008FBBA8 0x5C7D # 0 +0x008FBBA9 0x5C87 # 0 +0x008FBBAA 0x5C88 # 0 +0x008FBBAB 0x5C8A # 0 +0x008FBBAC 0x5C8F # 0 +0x008FBBAD 0x5C92 # 0 +0x008FBBAE 0x5C9D # 0 +0x008FBBAF 0x5C9F # 0 +0x008FBBB0 0x5CA0 # 0 +0x008FBBB1 0x5CA2 # 0 +0x008FBBB2 0x5CA3 # 0 +0x008FBBB3 0x5CA6 # 0 +0x008FBBB4 0x5CAA # 0 +0x008FBBB5 0x5CB2 # 0 +0x008FBBB6 0x5CB4 # 0 +0x008FBBB7 0x5CB5 # 0 +0x008FBBB8 0x5CBA # 0 +0x008FBBB9 0x5CC9 # 0 +0x008FBBBA 0x5CCB # 0 +0x008FBBBB 0x5CD2 # 0 +0x008FBBBC 0x5CDD # 0 +0x008FBBBD 0x5CD7 # 0 +0x008FBBBE 0x5CEE # 0 +0x008FBBBF 0x5CF1 # 0 +0x008FBBC0 0x5CF2 # 0 +0x008FBBC1 0x5CF4 # 0 +0x008FBBC2 0x5D01 # 0 +0x008FBBC3 0x5D06 # 0 +0x008FBBC4 0x5D0D # 0 +0x008FBBC5 0x5D12 # 0 +0x008FBBC6 0x5D2B # 0 +0x008FBBC7 0x5D23 # 0 +0x008FBBC8 0x5D24 # 0 +0x008FBBC9 0x5D26 # 0 +0x008FBBCA 0x5D27 # 0 +0x008FBBCB 0x5D31 # 0 +0x008FBBCC 0x5D34 # 0 +0x008FBBCD 0x5D39 # 0 +0x008FBBCE 0x5D3D # 0 +0x008FBBCF 0x5D3F # 0 +0x008FBBD0 0x5D42 # 0 +0x008FBBD1 0x5D43 # 0 +0x008FBBD2 0x5D46 # 0 +0x008FBBD3 0x5D48 # 0 +0x008FBBD4 0x5D55 # 0 +0x008FBBD5 0x5D51 # 0 +0x008FBBD6 0x5D59 # 0 +0x008FBBD7 0x5D4A # 0 +0x008FBBD8 0x5D5F # 0 +0x008FBBD9 0x5D60 # 0 +0x008FBBDA 0x5D61 # 0 +0x008FBBDB 0x5D62 # 0 +0x008FBBDC 0x5D64 # 0 +0x008FBBDD 0x5D6A # 0 +0x008FBBDE 0x5D6D # 0 +0x008FBBDF 0x5D70 # 0 +0x008FBBE0 0x5D79 # 0 +0x008FBBE1 0x5D7A # 0 +0x008FBBE2 0x5D7E # 0 +0x008FBBE3 0x5D7F # 0 +0x008FBBE4 0x5D81 # 0 +0x008FBBE5 0x5D83 # 0 +0x008FBBE6 0x5D88 # 0 +0x008FBBE7 0x5D8A # 0 +0x008FBBE8 0x5D92 # 0 +0x008FBBE9 0x5D93 # 0 +0x008FBBEA 0x5D94 # 0 +0x008FBBEB 0x5D95 # 0 +0x008FBBEC 0x5D99 # 0 +0x008FBBED 0x5D9B # 0 +0x008FBBEE 0x5D9F # 0 +0x008FBBEF 0x5DA0 # 0 +0x008FBBF0 0x5DA7 # 0 +0x008FBBF1 0x5DAB # 0 +0x008FBBF2 0x5DB0 # 0 +0x008FBBF3 0x5DB4 # 0 +0x008FBBF4 0x5DB8 # 0 +0x008FBBF5 0x5DB9 # 0 +0x008FBBF6 0x5DC3 # 0 +0x008FBBF7 0x5DC7 # 0 +0x008FBBF8 0x5DCB # 0 +0x008FBBF9 0x5DD0 # 0 +0x008FBBFA 0x5DCE # 0 +0x008FBBFB 0x5DD8 # 0 +0x008FBBFC 0x5DD9 # 0 +0x008FBBFD 0x5DE0 # 0 +0x008FBBFE 0x5DE4 # 0 +0x008FBCA1 0x5DE9 # 0 +0x008FBCA2 0x5DF8 # 0 +0x008FBCA3 0x5DF9 # 0 +0x008FBCA4 0x5E00 # 0 +0x008FBCA5 0x5E07 # 0 +0x008FBCA6 0x5E0D # 0 +0x008FBCA7 0x5E12 # 0 +0x008FBCA8 0x5E14 # 0 +0x008FBCA9 0x5E15 # 0 +0x008FBCAA 0x5E18 # 0 +0x008FBCAB 0x5E1F # 0 +0x008FBCAC 0x5E20 # 0 +0x008FBCAD 0x5E2E # 0 +0x008FBCAE 0x5E28 # 0 +0x008FBCAF 0x5E32 # 0 +0x008FBCB0 0x5E35 # 0 +0x008FBCB1 0x5E3E # 0 +0x008FBCB2 0x5E4B # 0 +0x008FBCB3 0x5E50 # 0 +0x008FBCB4 0x5E49 # 0 +0x008FBCB5 0x5E51 # 0 +0x008FBCB6 0x5E56 # 0 +0x008FBCB7 0x5E58 # 0 +0x008FBCB8 0x5E5B # 0 +0x008FBCB9 0x5E5C # 0 +0x008FBCBA 0x5E5E # 0 +0x008FBCBB 0x5E68 # 0 +0x008FBCBC 0x5E6A # 0 +0x008FBCBD 0x5E6B # 0 +0x008FBCBE 0x5E6C # 0 +0x008FBCBF 0x5E6D # 0 +0x008FBCC0 0x5E6E # 0 +0x008FBCC1 0x5E70 # 0 +0x008FBCC2 0x5E80 # 0 +0x008FBCC3 0x5E8B # 0 +0x008FBCC4 0x5E8E # 0 +0x008FBCC5 0x5EA2 # 0 +0x008FBCC6 0x5EA4 # 0 +0x008FBCC7 0x5EA5 # 0 +0x008FBCC8 0x5EA8 # 0 +0x008FBCC9 0x5EAA # 0 +0x008FBCCA 0x5EAC # 0 +0x008FBCCB 0x5EB1 # 0 +0x008FBCCC 0x5EB3 # 0 +0x008FBCCD 0x5EBD # 0 +0x008FBCCE 0x5EBE # 0 +0x008FBCCF 0x5EBF # 0 +0x008FBCD0 0x5EC6 # 0 +0x008FBCD1 0x5ECC # 0 +0x008FBCD2 0x5ECB # 0 +0x008FBCD3 0x5ECE # 0 +0x008FBCD4 0x5ED1 # 0 +0x008FBCD5 0x5ED2 # 0 +0x008FBCD6 0x5ED4 # 0 +0x008FBCD7 0x5ED5 # 0 +0x008FBCD8 0x5EDC # 0 +0x008FBCD9 0x5EDE # 0 +0x008FBCDA 0x5EE5 # 0 +0x008FBCDB 0x5EEB # 0 +0x008FBCDC 0x5F02 # 0 +0x008FBCDD 0x5F06 # 0 +0x008FBCDE 0x5F07 # 0 +0x008FBCDF 0x5F08 # 0 +0x008FBCE0 0x5F0E # 0 +0x008FBCE1 0x5F19 # 0 +0x008FBCE2 0x5F1C # 0 +0x008FBCE3 0x5F1D # 0 +0x008FBCE4 0x5F21 # 0 +0x008FBCE5 0x5F22 # 0 +0x008FBCE6 0x5F23 # 0 +0x008FBCE7 0x5F24 # 0 +0x008FBCE8 0x5F28 # 0 +0x008FBCE9 0x5F2B # 0 +0x008FBCEA 0x5F2C # 0 +0x008FBCEB 0x5F2E # 0 +0x008FBCEC 0x5F30 # 0 +0x008FBCED 0x5F34 # 0 +0x008FBCEE 0x5F36 # 0 +0x008FBCEF 0x5F3B # 0 +0x008FBCF0 0x5F3D # 0 +0x008FBCF1 0x5F3F # 0 +0x008FBCF2 0x5F40 # 0 +0x008FBCF3 0x5F44 # 0 +0x008FBCF4 0x5F45 # 0 +0x008FBCF5 0x5F47 # 0 +0x008FBCF6 0x5F4D # 0 +0x008FBCF7 0x5F50 # 0 +0x008FBCF8 0x5F54 # 0 +0x008FBCF9 0x5F58 # 0 +0x008FBCFA 0x5F5B # 0 +0x008FBCFB 0x5F60 # 0 +0x008FBCFC 0x5F63 # 0 +0x008FBCFD 0x5F64 # 0 +0x008FBCFE 0x5F67 # 0 +0x008FBDA1 0x5F6F # 0 +0x008FBDA2 0x5F72 # 0 +0x008FBDA3 0x5F74 # 0 +0x008FBDA4 0x5F75 # 0 +0x008FBDA5 0x5F78 # 0 +0x008FBDA6 0x5F7A # 0 +0x008FBDA7 0x5F7D # 0 +0x008FBDA8 0x5F7E # 0 +0x008FBDA9 0x5F89 # 0 +0x008FBDAA 0x5F8D # 0 +0x008FBDAB 0x5F8F # 0 +0x008FBDAC 0x5F96 # 0 +0x008FBDAD 0x5F9C # 0 +0x008FBDAE 0x5F9D # 0 +0x008FBDAF 0x5FA2 # 0 +0x008FBDB0 0x5FA7 # 0 +0x008FBDB1 0x5FAB # 0 +0x008FBDB2 0x5FA4 # 0 +0x008FBDB3 0x5FAC # 0 +0x008FBDB4 0x5FAF # 0 +0x008FBDB5 0x5FB0 # 0 +0x008FBDB6 0x5FB1 # 0 +0x008FBDB7 0x5FB8 # 0 +0x008FBDB8 0x5FC4 # 0 +0x008FBDB9 0x5FC7 # 0 +0x008FBDBA 0x5FC8 # 0 +0x008FBDBB 0x5FC9 # 0 +0x008FBDBC 0x5FCB # 0 +0x008FBDBD 0x5FD0 # 0 +0x008FBDBE 0x5FD1 # 0 +0x008FBDBF 0x5FD2 # 0 +0x008FBDC0 0x5FD3 # 0 +0x008FBDC1 0x5FD4 # 0 +0x008FBDC2 0x5FDE # 0 +0x008FBDC3 0x5FE1 # 0 +0x008FBDC4 0x5FE2 # 0 +0x008FBDC5 0x5FE8 # 0 +0x008FBDC6 0x5FE9 # 0 +0x008FBDC7 0x5FEA # 0 +0x008FBDC8 0x5FEC # 0 +0x008FBDC9 0x5FED # 0 +0x008FBDCA 0x5FEE # 0 +0x008FBDCB 0x5FEF # 0 +0x008FBDCC 0x5FF2 # 0 +0x008FBDCD 0x5FF3 # 0 +0x008FBDCE 0x5FF6 # 0 +0x008FBDCF 0x5FFA # 0 +0x008FBDD0 0x5FFC # 0 +0x008FBDD1 0x6007 # 0 +0x008FBDD2 0x600A # 0 +0x008FBDD3 0x600D # 0 +0x008FBDD4 0x6013 # 0 +0x008FBDD5 0x6014 # 0 +0x008FBDD6 0x6017 # 0 +0x008FBDD7 0x6018 # 0 +0x008FBDD8 0x601A # 0 +0x008FBDD9 0x601F # 0 +0x008FBDDA 0x6024 # 0 +0x008FBDDB 0x602D # 0 +0x008FBDDC 0x6033 # 0 +0x008FBDDD 0x6035 # 0 +0x008FBDDE 0x6040 # 0 +0x008FBDDF 0x6047 # 0 +0x008FBDE0 0x6048 # 0 +0x008FBDE1 0x6049 # 0 +0x008FBDE2 0x604C # 0 +0x008FBDE3 0x6051 # 0 +0x008FBDE4 0x6054 # 0 +0x008FBDE5 0x6056 # 0 +0x008FBDE6 0x6057 # 0 +0x008FBDE7 0x605D # 0 +0x008FBDE8 0x6061 # 0 +0x008FBDE9 0x6067 # 0 +0x008FBDEA 0x6071 # 0 +0x008FBDEB 0x607E # 0 +0x008FBDEC 0x607F # 0 +0x008FBDED 0x6082 # 0 +0x008FBDEE 0x6086 # 0 +0x008FBDEF 0x6088 # 0 +0x008FBDF0 0x608A # 0 +0x008FBDF1 0x608E # 0 +0x008FBDF2 0x6091 # 0 +0x008FBDF3 0x6093 # 0 +0x008FBDF4 0x6095 # 0 +0x008FBDF5 0x6098 # 0 +0x008FBDF6 0x609D # 0 +0x008FBDF7 0x609E # 0 +0x008FBDF8 0x60A2 # 0 +0x008FBDF9 0x60A4 # 0 +0x008FBDFA 0x60A5 # 0 +0x008FBDFB 0x60A8 # 0 +0x008FBDFC 0x60B0 # 0 +0x008FBDFD 0x60B1 # 0 +0x008FBDFE 0x60B7 # 0 +0x008FBEA1 0x60BB # 0 +0x008FBEA2 0x60BE # 0 +0x008FBEA3 0x60C2 # 0 +0x008FBEA4 0x60C4 # 0 +0x008FBEA5 0x60C8 # 0 +0x008FBEA6 0x60C9 # 0 +0x008FBEA7 0x60CA # 0 +0x008FBEA8 0x60CB # 0 +0x008FBEA9 0x60CE # 0 +0x008FBEAA 0x60CF # 0 +0x008FBEAB 0x60D4 # 0 +0x008FBEAC 0x60D5 # 0 +0x008FBEAD 0x60D9 # 0 +0x008FBEAE 0x60DB # 0 +0x008FBEAF 0x60DD # 0 +0x008FBEB0 0x60DE # 0 +0x008FBEB1 0x60E2 # 0 +0x008FBEB2 0x60E5 # 0 +0x008FBEB3 0x60F2 # 0 +0x008FBEB4 0x60F5 # 0 +0x008FBEB5 0x60F8 # 0 +0x008FBEB6 0x60FC # 0 +0x008FBEB7 0x60FD # 0 +0x008FBEB8 0x6102 # 0 +0x008FBEB9 0x6107 # 0 +0x008FBEBA 0x610A # 0 +0x008FBEBB 0x610C # 0 +0x008FBEBC 0x6110 # 0 +0x008FBEBD 0x6111 # 0 +0x008FBEBE 0x6112 # 0 +0x008FBEBF 0x6113 # 0 +0x008FBEC0 0x6114 # 0 +0x008FBEC1 0x6116 # 0 +0x008FBEC2 0x6117 # 0 +0x008FBEC3 0x6119 # 0 +0x008FBEC4 0x611C # 0 +0x008FBEC5 0x611E # 0 +0x008FBEC6 0x6122 # 0 +0x008FBEC7 0x612A # 0 +0x008FBEC8 0x612B # 0 +0x008FBEC9 0x6130 # 0 +0x008FBECA 0x6131 # 0 +0x008FBECB 0x6135 # 0 +0x008FBECC 0x6136 # 0 +0x008FBECD 0x6137 # 0 +0x008FBECE 0x6139 # 0 +0x008FBECF 0x6141 # 0 +0x008FBED0 0x6145 # 0 +0x008FBED1 0x6146 # 0 +0x008FBED2 0x6149 # 0 +0x008FBED3 0x615E # 0 +0x008FBED4 0x6160 # 0 +0x008FBED5 0x616C # 0 +0x008FBED6 0x6172 # 0 +0x008FBED7 0x6178 # 0 +0x008FBED8 0x617B # 0 +0x008FBED9 0x617C # 0 +0x008FBEDA 0x617F # 0 +0x008FBEDB 0x6180 # 0 +0x008FBEDC 0x6181 # 0 +0x008FBEDD 0x6183 # 0 +0x008FBEDE 0x6184 # 0 +0x008FBEDF 0x618B # 0 +0x008FBEE0 0x618D # 0 +0x008FBEE1 0x6192 # 0 +0x008FBEE2 0x6193 # 0 +0x008FBEE3 0x6197 # 0 +0x008FBEE4 0x6198 # 0 +0x008FBEE5 0x619C # 0 +0x008FBEE6 0x619D # 0 +0x008FBEE7 0x619F # 0 +0x008FBEE8 0x61A0 # 0 +0x008FBEE9 0x61A5 # 0 +0x008FBEEA 0x61A8 # 0 +0x008FBEEB 0x61AA # 0 +0x008FBEEC 0x61AD # 0 +0x008FBEED 0x61B8 # 0 +0x008FBEEE 0x61B9 # 0 +0x008FBEEF 0x61BC # 0 +0x008FBEF0 0x61C0 # 0 +0x008FBEF1 0x61C1 # 0 +0x008FBEF2 0x61C2 # 0 +0x008FBEF3 0x61CE # 0 +0x008FBEF4 0x61CF # 0 +0x008FBEF5 0x61D5 # 0 +0x008FBEF6 0x61DC # 0 +0x008FBEF7 0x61DD # 0 +0x008FBEF8 0x61DE # 0 +0x008FBEF9 0x61DF # 0 +0x008FBEFA 0x61E1 # 0 +0x008FBEFB 0x61E2 # 0 +0x008FBEFC 0x61E7 # 0 +0x008FBEFD 0x61E9 # 0 +0x008FBEFE 0x61E5 # 0 +0x008FBFA1 0x61EC # 0 +0x008FBFA2 0x61ED # 0 +0x008FBFA3 0x61EF # 0 +0x008FBFA4 0x6201 # 0 +0x008FBFA5 0x6203 # 0 +0x008FBFA6 0x6204 # 0 +0x008FBFA7 0x6207 # 0 +0x008FBFA8 0x6213 # 0 +0x008FBFA9 0x6215 # 0 +0x008FBFAA 0x621C # 0 +0x008FBFAB 0x6220 # 0 +0x008FBFAC 0x6222 # 0 +0x008FBFAD 0x6223 # 0 +0x008FBFAE 0x6227 # 0 +0x008FBFAF 0x6229 # 0 +0x008FBFB0 0x622B # 0 +0x008FBFB1 0x6239 # 0 +0x008FBFB2 0x623D # 0 +0x008FBFB3 0x6242 # 0 +0x008FBFB4 0x6243 # 0 +0x008FBFB5 0x6244 # 0 +0x008FBFB6 0x6246 # 0 +0x008FBFB7 0x624C # 0 +0x008FBFB8 0x6250 # 0 +0x008FBFB9 0x6251 # 0 +0x008FBFBA 0x6252 # 0 +0x008FBFBB 0x6254 # 0 +0x008FBFBC 0x6256 # 0 +0x008FBFBD 0x625A # 0 +0x008FBFBE 0x625C # 0 +0x008FBFBF 0x6264 # 0 +0x008FBFC0 0x626D # 0 +0x008FBFC1 0x626F # 0 +0x008FBFC2 0x6273 # 0 +0x008FBFC3 0x627A # 0 +0x008FBFC4 0x627D # 0 +0x008FBFC5 0x628D # 0 +0x008FBFC6 0x628E # 0 +0x008FBFC7 0x628F # 0 +0x008FBFC8 0x6290 # 0 +0x008FBFC9 0x62A6 # 0 +0x008FBFCA 0x62A8 # 0 +0x008FBFCB 0x62B3 # 0 +0x008FBFCC 0x62B6 # 0 +0x008FBFCD 0x62B7 # 0 +0x008FBFCE 0x62BA # 0 +0x008FBFCF 0x62BE # 0 +0x008FBFD0 0x62BF # 0 +0x008FBFD1 0x62C4 # 0 +0x008FBFD2 0x62CE # 0 +0x008FBFD3 0x62D5 # 0 +0x008FBFD4 0x62D6 # 0 +0x008FBFD5 0x62DA # 0 +0x008FBFD6 0x62EA # 0 +0x008FBFD7 0x62F2 # 0 +0x008FBFD8 0x62F4 # 0 +0x008FBFD9 0x62FC # 0 +0x008FBFDA 0x62FD # 0 +0x008FBFDB 0x6303 # 0 +0x008FBFDC 0x6304 # 0 +0x008FBFDD 0x630A # 0 +0x008FBFDE 0x630B # 0 +0x008FBFDF 0x630D # 0 +0x008FBFE0 0x6310 # 0 +0x008FBFE1 0x6313 # 0 +0x008FBFE2 0x6316 # 0 +0x008FBFE3 0x6318 # 0 +0x008FBFE4 0x6329 # 0 +0x008FBFE5 0x632A # 0 +0x008FBFE6 0x632D # 0 +0x008FBFE7 0x6335 # 0 +0x008FBFE8 0x6336 # 0 +0x008FBFE9 0x6339 # 0 +0x008FBFEA 0x633C # 0 +0x008FBFEB 0x6341 # 0 +0x008FBFEC 0x6342 # 0 +0x008FBFED 0x6343 # 0 +0x008FBFEE 0x6344 # 0 +0x008FBFEF 0x6346 # 0 +0x008FBFF0 0x634A # 0 +0x008FBFF1 0x634B # 0 +0x008FBFF2 0x634E # 0 +0x008FBFF3 0x6352 # 0 +0x008FBFF4 0x6353 # 0 +0x008FBFF5 0x6354 # 0 +0x008FBFF6 0x6358 # 0 +0x008FBFF7 0x635B # 0 +0x008FBFF8 0x6365 # 0 +0x008FBFF9 0x6366 # 0 +0x008FBFFA 0x636C # 0 +0x008FBFFB 0x636D # 0 +0x008FBFFC 0x6371 # 0 +0x008FBFFD 0x6374 # 0 +0x008FBFFE 0x6375 # 0 +0x008FC0A1 0x6378 # 0 +0x008FC0A2 0x637C # 0 +0x008FC0A3 0x637D # 0 +0x008FC0A4 0x637F # 0 +0x008FC0A5 0x6382 # 0 +0x008FC0A6 0x6384 # 0 +0x008FC0A7 0x6387 # 0 +0x008FC0A8 0x638A # 0 +0x008FC0A9 0x6390 # 0 +0x008FC0AA 0x6394 # 0 +0x008FC0AB 0x6395 # 0 +0x008FC0AC 0x6399 # 0 +0x008FC0AD 0x639A # 0 +0x008FC0AE 0x639E # 0 +0x008FC0AF 0x63A4 # 0 +0x008FC0B0 0x63A6 # 0 +0x008FC0B1 0x63AD # 0 +0x008FC0B2 0x63AE # 0 +0x008FC0B3 0x63AF # 0 +0x008FC0B4 0x63BD # 0 +0x008FC0B5 0x63C1 # 0 +0x008FC0B6 0x63C5 # 0 +0x008FC0B7 0x63C8 # 0 +0x008FC0B8 0x63CE # 0 +0x008FC0B9 0x63D1 # 0 +0x008FC0BA 0x63D3 # 0 +0x008FC0BB 0x63D4 # 0 +0x008FC0BC 0x63D5 # 0 +0x008FC0BD 0x63DC # 0 +0x008FC0BE 0x63E0 # 0 +0x008FC0BF 0x63E5 # 0 +0x008FC0C0 0x63EA # 0 +0x008FC0C1 0x63EC # 0 +0x008FC0C2 0x63F2 # 0 +0x008FC0C3 0x63F3 # 0 +0x008FC0C4 0x63F5 # 0 +0x008FC0C5 0x63F8 # 0 +0x008FC0C6 0x63F9 # 0 +0x008FC0C7 0x6409 # 0 +0x008FC0C8 0x640A # 0 +0x008FC0C9 0x6410 # 0 +0x008FC0CA 0x6412 # 0 +0x008FC0CB 0x6414 # 0 +0x008FC0CC 0x6418 # 0 +0x008FC0CD 0x641E # 0 +0x008FC0CE 0x6420 # 0 +0x008FC0CF 0x6422 # 0 +0x008FC0D0 0x6424 # 0 +0x008FC0D1 0x6425 # 0 +0x008FC0D2 0x6429 # 0 +0x008FC0D3 0x642A # 0 +0x008FC0D4 0x642F # 0 +0x008FC0D5 0x6430 # 0 +0x008FC0D6 0x6435 # 0 +0x008FC0D7 0x643D # 0 +0x008FC0D8 0x643F # 0 +0x008FC0D9 0x644B # 0 +0x008FC0DA 0x644F # 0 +0x008FC0DB 0x6451 # 0 +0x008FC0DC 0x6452 # 0 +0x008FC0DD 0x6453 # 0 +0x008FC0DE 0x6454 # 0 +0x008FC0DF 0x645A # 0 +0x008FC0E0 0x645B # 0 +0x008FC0E1 0x645C # 0 +0x008FC0E2 0x645D # 0 +0x008FC0E3 0x645F # 0 +0x008FC0E4 0x6460 # 0 +0x008FC0E5 0x6461 # 0 +0x008FC0E6 0x6463 # 0 +0x008FC0E7 0x646D # 0 +0x008FC0E8 0x6473 # 0 +0x008FC0E9 0x6474 # 0 +0x008FC0EA 0x647B # 0 +0x008FC0EB 0x647D # 0 +0x008FC0EC 0x6485 # 0 +0x008FC0ED 0x6487 # 0 +0x008FC0EE 0x648F # 0 +0x008FC0EF 0x6490 # 0 +0x008FC0F0 0x6491 # 0 +0x008FC0F1 0x6498 # 0 +0x008FC0F2 0x6499 # 0 +0x008FC0F3 0x649B # 0 +0x008FC0F4 0x649D # 0 +0x008FC0F5 0x649F # 0 +0x008FC0F6 0x64A1 # 0 +0x008FC0F7 0x64A3 # 0 +0x008FC0F8 0x64A6 # 0 +0x008FC0F9 0x64A8 # 0 +0x008FC0FA 0x64AC # 0 +0x008FC0FB 0x64B3 # 0 +0x008FC0FC 0x64BD # 0 +0x008FC0FD 0x64BE # 0 +0x008FC0FE 0x64BF # 0 +0x008FC1A1 0x64C4 # 0 +0x008FC1A2 0x64C9 # 0 +0x008FC1A3 0x64CA # 0 +0x008FC1A4 0x64CB # 0 +0x008FC1A5 0x64CC # 0 +0x008FC1A6 0x64CE # 0 +0x008FC1A7 0x64D0 # 0 +0x008FC1A8 0x64D1 # 0 +0x008FC1A9 0x64D5 # 0 +0x008FC1AA 0x64D7 # 0 +0x008FC1AB 0x64E4 # 0 +0x008FC1AC 0x64E5 # 0 +0x008FC1AD 0x64E9 # 0 +0x008FC1AE 0x64EA # 0 +0x008FC1AF 0x64ED # 0 +0x008FC1B0 0x64F0 # 0 +0x008FC1B1 0x64F5 # 0 +0x008FC1B2 0x64F7 # 0 +0x008FC1B3 0x64FB # 0 +0x008FC1B4 0x64FF # 0 +0x008FC1B5 0x6501 # 0 +0x008FC1B6 0x6504 # 0 +0x008FC1B7 0x6508 # 0 +0x008FC1B8 0x6509 # 0 +0x008FC1B9 0x650A # 0 +0x008FC1BA 0x650F # 0 +0x008FC1BB 0x6513 # 0 +0x008FC1BC 0x6514 # 0 +0x008FC1BD 0x6516 # 0 +0x008FC1BE 0x6519 # 0 +0x008FC1BF 0x651B # 0 +0x008FC1C0 0x651E # 0 +0x008FC1C1 0x651F # 0 +0x008FC1C2 0x6522 # 0 +0x008FC1C3 0x6526 # 0 +0x008FC1C4 0x6529 # 0 +0x008FC1C5 0x652E # 0 +0x008FC1C6 0x6531 # 0 +0x008FC1C7 0x653A # 0 +0x008FC1C8 0x653C # 0 +0x008FC1C9 0x653D # 0 +0x008FC1CA 0x6543 # 0 +0x008FC1CB 0x6547 # 0 +0x008FC1CC 0x6549 # 0 +0x008FC1CD 0x6550 # 0 +0x008FC1CE 0x6552 # 0 +0x008FC1CF 0x6554 # 0 +0x008FC1D0 0x655F # 0 +0x008FC1D1 0x6560 # 0 +0x008FC1D2 0x6567 # 0 +0x008FC1D3 0x656B # 0 +0x008FC1D4 0x657A # 0 +0x008FC1D5 0x657D # 0 +0x008FC1D6 0x6581 # 0 +0x008FC1D7 0x6585 # 0 +0x008FC1D8 0x658A # 0 +0x008FC1D9 0x6592 # 0 +0x008FC1DA 0x6595 # 0 +0x008FC1DB 0x6598 # 0 +0x008FC1DC 0x659D # 0 +0x008FC1DD 0x65A0 # 0 +0x008FC1DE 0x65A3 # 0 +0x008FC1DF 0x65A6 # 0 +0x008FC1E0 0x65AE # 0 +0x008FC1E1 0x65B2 # 0 +0x008FC1E2 0x65B3 # 0 +0x008FC1E3 0x65B4 # 0 +0x008FC1E4 0x65BF # 0 +0x008FC1E5 0x65C2 # 0 +0x008FC1E6 0x65C8 # 0 +0x008FC1E7 0x65C9 # 0 +0x008FC1E8 0x65CE # 0 +0x008FC1E9 0x65D0 # 0 +0x008FC1EA 0x65D4 # 0 +0x008FC1EB 0x65D6 # 0 +0x008FC1EC 0x65D8 # 0 +0x008FC1ED 0x65DF # 0 +0x008FC1EE 0x65F0 # 0 +0x008FC1EF 0x65F2 # 0 +0x008FC1F0 0x65F4 # 0 +0x008FC1F1 0x65F5 # 0 +0x008FC1F2 0x65F9 # 0 +0x008FC1F3 0x65FE # 0 +0x008FC1F4 0x65FF # 0 +0x008FC1F5 0x6600 # 0 +0x008FC1F6 0x6604 # 0 +0x008FC1F7 0x6608 # 0 +0x008FC1F8 0x6609 # 0 +0x008FC1F9 0x660D # 0 +0x008FC1FA 0x6611 # 0 +0x008FC1FB 0x6612 # 0 +0x008FC1FC 0x6615 # 0 +0x008FC1FD 0x6616 # 0 +0x008FC1FE 0x661D # 0 +0x008FC2A1 0x661E # 0 +0x008FC2A2 0x6621 # 0 +0x008FC2A3 0x6622 # 0 +0x008FC2A4 0x6623 # 0 +0x008FC2A5 0x6624 # 0 +0x008FC2A6 0x6626 # 0 +0x008FC2A7 0x6629 # 0 +0x008FC2A8 0x662A # 0 +0x008FC2A9 0x662B # 0 +0x008FC2AA 0x662C # 0 +0x008FC2AB 0x662E # 0 +0x008FC2AC 0x6630 # 0 +0x008FC2AD 0x6631 # 0 +0x008FC2AE 0x6633 # 0 +0x008FC2AF 0x6639 # 0 +0x008FC2B0 0x6637 # 0 +0x008FC2B1 0x6640 # 0 +0x008FC2B2 0x6645 # 0 +0x008FC2B3 0x6646 # 0 +0x008FC2B4 0x664A # 0 +0x008FC2B5 0x664C # 0 +0x008FC2B6 0x6651 # 0 +0x008FC2B7 0x664E # 0 +0x008FC2B8 0x6657 # 0 +0x008FC2B9 0x6658 # 0 +0x008FC2BA 0x6659 # 0 +0x008FC2BB 0x665B # 0 +0x008FC2BC 0x665C # 0 +0x008FC2BD 0x6660 # 0 +0x008FC2BE 0x6661 # 0 +0x008FC2BF 0x66FB # 0 +0x008FC2C0 0x666A # 0 +0x008FC2C1 0x666B # 0 +0x008FC2C2 0x666C # 0 +0x008FC2C3 0x667E # 0 +0x008FC2C4 0x6673 # 0 +0x008FC2C5 0x6675 # 0 +0x008FC2C6 0x667F # 0 +0x008FC2C7 0x6677 # 0 +0x008FC2C8 0x6678 # 0 +0x008FC2C9 0x6679 # 0 +0x008FC2CA 0x667B # 0 +0x008FC2CB 0x6680 # 0 +0x008FC2CC 0x667C # 0 +0x008FC2CD 0x668B # 0 +0x008FC2CE 0x668C # 0 +0x008FC2CF 0x668D # 0 +0x008FC2D0 0x6690 # 0 +0x008FC2D1 0x6692 # 0 +0x008FC2D2 0x6699 # 0 +0x008FC2D3 0x669A # 0 +0x008FC2D4 0x669B # 0 +0x008FC2D5 0x669C # 0 +0x008FC2D6 0x669F # 0 +0x008FC2D7 0x66A0 # 0 +0x008FC2D8 0x66A4 # 0 +0x008FC2D9 0x66AD # 0 +0x008FC2DA 0x66B1 # 0 +0x008FC2DB 0x66B2 # 0 +0x008FC2DC 0x66B5 # 0 +0x008FC2DD 0x66BB # 0 +0x008FC2DE 0x66BF # 0 +0x008FC2DF 0x66C0 # 0 +0x008FC2E0 0x66C2 # 0 +0x008FC2E1 0x66C3 # 0 +0x008FC2E2 0x66C8 # 0 +0x008FC2E3 0x66CC # 0 +0x008FC2E4 0x66CE # 0 +0x008FC2E5 0x66CF # 0 +0x008FC2E6 0x66D4 # 0 +0x008FC2E7 0x66DB # 0 +0x008FC2E8 0x66DF # 0 +0x008FC2E9 0x66E8 # 0 +0x008FC2EA 0x66EB # 0 +0x008FC2EB 0x66EC # 0 +0x008FC2EC 0x66EE # 0 +0x008FC2ED 0x66FA # 0 +0x008FC2EE 0x6705 # 0 +0x008FC2EF 0x6707 # 0 +0x008FC2F0 0x670E # 0 +0x008FC2F1 0x6713 # 0 +0x008FC2F2 0x6719 # 0 +0x008FC2F3 0x671C # 0 +0x008FC2F4 0x6720 # 0 +0x008FC2F5 0x6722 # 0 +0x008FC2F6 0x6733 # 0 +0x008FC2F7 0x673E # 0 +0x008FC2F8 0x6745 # 0 +0x008FC2F9 0x6747 # 0 +0x008FC2FA 0x6748 # 0 +0x008FC2FB 0x674C # 0 +0x008FC2FC 0x6754 # 0 +0x008FC2FD 0x6755 # 0 +0x008FC2FE 0x675D # 0 +0x008FC3A1 0x6766 # 0 +0x008FC3A2 0x676C # 0 +0x008FC3A3 0x676E # 0 +0x008FC3A4 0x6774 # 0 +0x008FC3A5 0x6776 # 0 +0x008FC3A6 0x677B # 0 +0x008FC3A7 0x6781 # 0 +0x008FC3A8 0x6784 # 0 +0x008FC3A9 0x678E # 0 +0x008FC3AA 0x678F # 0 +0x008FC3AB 0x6791 # 0 +0x008FC3AC 0x6793 # 0 +0x008FC3AD 0x6796 # 0 +0x008FC3AE 0x6798 # 0 +0x008FC3AF 0x6799 # 0 +0x008FC3B0 0x679B # 0 +0x008FC3B1 0x67B0 # 0 +0x008FC3B2 0x67B1 # 0 +0x008FC3B3 0x67B2 # 0 +0x008FC3B4 0x67B5 # 0 +0x008FC3B5 0x67BB # 0 +0x008FC3B6 0x67BC # 0 +0x008FC3B7 0x67BD # 0 +0x008FC3B8 0x67F9 # 0 +0x008FC3B9 0x67C0 # 0 +0x008FC3BA 0x67C2 # 0 +0x008FC3BB 0x67C3 # 0 +0x008FC3BC 0x67C5 # 0 +0x008FC3BD 0x67C8 # 0 +0x008FC3BE 0x67C9 # 0 +0x008FC3BF 0x67D2 # 0 +0x008FC3C0 0x67D7 # 0 +0x008FC3C1 0x67D9 # 0 +0x008FC3C2 0x67DC # 0 +0x008FC3C3 0x67E1 # 0 +0x008FC3C4 0x67E6 # 0 +0x008FC3C5 0x67F0 # 0 +0x008FC3C6 0x67F2 # 0 +0x008FC3C7 0x67F6 # 0 +0x008FC3C8 0x67F7 # 0 +0x008FC3C9 0x6852 # 0 +0x008FC3CA 0x6814 # 0 +0x008FC3CB 0x6819 # 0 +0x008FC3CC 0x681D # 0 +0x008FC3CD 0x681F # 0 +0x008FC3CE 0x6828 # 0 +0x008FC3CF 0x6827 # 0 +0x008FC3D0 0x682C # 0 +0x008FC3D1 0x682D # 0 +0x008FC3D2 0x682F # 0 +0x008FC3D3 0x6830 # 0 +0x008FC3D4 0x6831 # 0 +0x008FC3D5 0x6833 # 0 +0x008FC3D6 0x683B # 0 +0x008FC3D7 0x683F # 0 +0x008FC3D8 0x6844 # 0 +0x008FC3D9 0x6845 # 0 +0x008FC3DA 0x684A # 0 +0x008FC3DB 0x684C # 0 +0x008FC3DC 0x6855 # 0 +0x008FC3DD 0x6857 # 0 +0x008FC3DE 0x6858 # 0 +0x008FC3DF 0x685B # 0 +0x008FC3E0 0x686B # 0 +0x008FC3E1 0x686E # 0 +0x008FC3E2 0x686F # 0 +0x008FC3E3 0x6870 # 0 +0x008FC3E4 0x6871 # 0 +0x008FC3E5 0x6872 # 0 +0x008FC3E6 0x6875 # 0 +0x008FC3E7 0x6879 # 0 +0x008FC3E8 0x687A # 0 +0x008FC3E9 0x687B # 0 +0x008FC3EA 0x687C # 0 +0x008FC3EB 0x6882 # 0 +0x008FC3EC 0x6884 # 0 +0x008FC3ED 0x6886 # 0 +0x008FC3EE 0x6888 # 0 +0x008FC3EF 0x6896 # 0 +0x008FC3F0 0x6898 # 0 +0x008FC3F1 0x689A # 0 +0x008FC3F2 0x689C # 0 +0x008FC3F3 0x68A1 # 0 +0x008FC3F4 0x68A3 # 0 +0x008FC3F5 0x68A5 # 0 +0x008FC3F6 0x68A9 # 0 +0x008FC3F7 0x68AA # 0 +0x008FC3F8 0x68AE # 0 +0x008FC3F9 0x68B2 # 0 +0x008FC3FA 0x68BB # 0 +0x008FC3FB 0x68C5 # 0 +0x008FC3FC 0x68C8 # 0 +0x008FC3FD 0x68CC # 0 +0x008FC3FE 0x68CF # 0 +0x008FC4A1 0x68D0 # 0 +0x008FC4A2 0x68D1 # 0 +0x008FC4A3 0x68D3 # 0 +0x008FC4A4 0x68D6 # 0 +0x008FC4A5 0x68D9 # 0 +0x008FC4A6 0x68DC # 0 +0x008FC4A7 0x68DD # 0 +0x008FC4A8 0x68E5 # 0 +0x008FC4A9 0x68E8 # 0 +0x008FC4AA 0x68EA # 0 +0x008FC4AB 0x68EB # 0 +0x008FC4AC 0x68EC # 0 +0x008FC4AD 0x68ED # 0 +0x008FC4AE 0x68F0 # 0 +0x008FC4AF 0x68F1 # 0 +0x008FC4B0 0x68F5 # 0 +0x008FC4B1 0x68F6 # 0 +0x008FC4B2 0x68FB # 0 +0x008FC4B3 0x68FC # 0 +0x008FC4B4 0x68FD # 0 +0x008FC4B5 0x6906 # 0 +0x008FC4B6 0x6909 # 0 +0x008FC4B7 0x690A # 0 +0x008FC4B8 0x6910 # 0 +0x008FC4B9 0x6911 # 0 +0x008FC4BA 0x6913 # 0 +0x008FC4BB 0x6916 # 0 +0x008FC4BC 0x6917 # 0 +0x008FC4BD 0x6931 # 0 +0x008FC4BE 0x6933 # 0 +0x008FC4BF 0x6935 # 0 +0x008FC4C0 0x6938 # 0 +0x008FC4C1 0x693B # 0 +0x008FC4C2 0x6942 # 0 +0x008FC4C3 0x6945 # 0 +0x008FC4C4 0x6949 # 0 +0x008FC4C5 0x694E # 0 +0x008FC4C6 0x6957 # 0 +0x008FC4C7 0x695B # 0 +0x008FC4C8 0x6963 # 0 +0x008FC4C9 0x6964 # 0 +0x008FC4CA 0x6965 # 0 +0x008FC4CB 0x6966 # 0 +0x008FC4CC 0x6968 # 0 +0x008FC4CD 0x6969 # 0 +0x008FC4CE 0x696C # 0 +0x008FC4CF 0x6970 # 0 +0x008FC4D0 0x6971 # 0 +0x008FC4D1 0x6972 # 0 +0x008FC4D2 0x697A # 0 +0x008FC4D3 0x697B # 0 +0x008FC4D4 0x697F # 0 +0x008FC4D5 0x6980 # 0 +0x008FC4D6 0x698D # 0 +0x008FC4D7 0x6992 # 0 +0x008FC4D8 0x6996 # 0 +0x008FC4D9 0x6998 # 0 +0x008FC4DA 0x69A1 # 0 +0x008FC4DB 0x69A5 # 0 +0x008FC4DC 0x69A6 # 0 +0x008FC4DD 0x69A8 # 0 +0x008FC4DE 0x69AB # 0 +0x008FC4DF 0x69AD # 0 +0x008FC4E0 0x69AF # 0 +0x008FC4E1 0x69B7 # 0 +0x008FC4E2 0x69B8 # 0 +0x008FC4E3 0x69BA # 0 +0x008FC4E4 0x69BC # 0 +0x008FC4E5 0x69C5 # 0 +0x008FC4E6 0x69C8 # 0 +0x008FC4E7 0x69D1 # 0 +0x008FC4E8 0x69D6 # 0 +0x008FC4E9 0x69D7 # 0 +0x008FC4EA 0x69E2 # 0 +0x008FC4EB 0x69E5 # 0 +0x008FC4EC 0x69EE # 0 +0x008FC4ED 0x69EF # 0 +0x008FC4EE 0x69F1 # 0 +0x008FC4EF 0x69F3 # 0 +0x008FC4F0 0x69F5 # 0 +0x008FC4F1 0x69FE # 0 +0x008FC4F2 0x6A00 # 0 +0x008FC4F3 0x6A01 # 0 +0x008FC4F4 0x6A03 # 0 +0x008FC4F5 0x6A0F # 0 +0x008FC4F6 0x6A11 # 0 +0x008FC4F7 0x6A15 # 0 +0x008FC4F8 0x6A1A # 0 +0x008FC4F9 0x6A1D # 0 +0x008FC4FA 0x6A20 # 0 +0x008FC4FB 0x6A24 # 0 +0x008FC4FC 0x6A28 # 0 +0x008FC4FD 0x6A30 # 0 +0x008FC4FE 0x6A32 # 0 +0x008FC5A1 0x6A34 # 0 +0x008FC5A2 0x6A37 # 0 +0x008FC5A3 0x6A3B # 0 +0x008FC5A4 0x6A3E # 0 +0x008FC5A5 0x6A3F # 0 +0x008FC5A6 0x6A45 # 0 +0x008FC5A7 0x6A46 # 0 +0x008FC5A8 0x6A49 # 0 +0x008FC5A9 0x6A4A # 0 +0x008FC5AA 0x6A4E # 0 +0x008FC5AB 0x6A50 # 0 +0x008FC5AC 0x6A51 # 0 +0x008FC5AD 0x6A52 # 0 +0x008FC5AE 0x6A55 # 0 +0x008FC5AF 0x6A56 # 0 +0x008FC5B0 0x6A5B # 0 +0x008FC5B1 0x6A64 # 0 +0x008FC5B2 0x6A67 # 0 +0x008FC5B3 0x6A6A # 0 +0x008FC5B4 0x6A71 # 0 +0x008FC5B5 0x6A73 # 0 +0x008FC5B6 0x6A7E # 0 +0x008FC5B7 0x6A81 # 0 +0x008FC5B8 0x6A83 # 0 +0x008FC5B9 0x6A86 # 0 +0x008FC5BA 0x6A87 # 0 +0x008FC5BB 0x6A89 # 0 +0x008FC5BC 0x6A8B # 0 +0x008FC5BD 0x6A91 # 0 +0x008FC5BE 0x6A9B # 0 +0x008FC5BF 0x6A9D # 0 +0x008FC5C0 0x6A9E # 0 +0x008FC5C1 0x6A9F # 0 +0x008FC5C2 0x6AA5 # 0 +0x008FC5C3 0x6AAB # 0 +0x008FC5C4 0x6AAF # 0 +0x008FC5C5 0x6AB0 # 0 +0x008FC5C6 0x6AB1 # 0 +0x008FC5C7 0x6AB4 # 0 +0x008FC5C8 0x6ABD # 0 +0x008FC5C9 0x6ABE # 0 +0x008FC5CA 0x6ABF # 0 +0x008FC5CB 0x6AC6 # 0 +0x008FC5CC 0x6AC9 # 0 +0x008FC5CD 0x6AC8 # 0 +0x008FC5CE 0x6ACC # 0 +0x008FC5CF 0x6AD0 # 0 +0x008FC5D0 0x6AD4 # 0 +0x008FC5D1 0x6AD5 # 0 +0x008FC5D2 0x6AD6 # 0 +0x008FC5D3 0x6ADC # 0 +0x008FC5D4 0x6ADD # 0 +0x008FC5D5 0x6AE4 # 0 +0x008FC5D6 0x6AE7 # 0 +0x008FC5D7 0x6AEC # 0 +0x008FC5D8 0x6AF0 # 0 +0x008FC5D9 0x6AF1 # 0 +0x008FC5DA 0x6AF2 # 0 +0x008FC5DB 0x6AFC # 0 +0x008FC5DC 0x6AFD # 0 +0x008FC5DD 0x6B02 # 0 +0x008FC5DE 0x6B03 # 0 +0x008FC5DF 0x6B06 # 0 +0x008FC5E0 0x6B07 # 0 +0x008FC5E1 0x6B09 # 0 +0x008FC5E2 0x6B0F # 0 +0x008FC5E3 0x6B10 # 0 +0x008FC5E4 0x6B11 # 0 +0x008FC5E5 0x6B17 # 0 +0x008FC5E6 0x6B1B # 0 +0x008FC5E7 0x6B1E # 0 +0x008FC5E8 0x6B24 # 0 +0x008FC5E9 0x6B28 # 0 +0x008FC5EA 0x6B2B # 0 +0x008FC5EB 0x6B2C # 0 +0x008FC5EC 0x6B2F # 0 +0x008FC5ED 0x6B35 # 0 +0x008FC5EE 0x6B36 # 0 +0x008FC5EF 0x6B3B # 0 +0x008FC5F0 0x6B3F # 0 +0x008FC5F1 0x6B46 # 0 +0x008FC5F2 0x6B4A # 0 +0x008FC5F3 0x6B4D # 0 +0x008FC5F4 0x6B52 # 0 +0x008FC5F5 0x6B56 # 0 +0x008FC5F6 0x6B58 # 0 +0x008FC5F7 0x6B5D # 0 +0x008FC5F8 0x6B60 # 0 +0x008FC5F9 0x6B67 # 0 +0x008FC5FA 0x6B6B # 0 +0x008FC5FB 0x6B6E # 0 +0x008FC5FC 0x6B70 # 0 +0x008FC5FD 0x6B75 # 0 +0x008FC5FE 0x6B7D # 0 +0x008FC6A1 0x6B7E # 0 +0x008FC6A2 0x6B82 # 0 +0x008FC6A3 0x6B85 # 0 +0x008FC6A4 0x6B97 # 0 +0x008FC6A5 0x6B9B # 0 +0x008FC6A6 0x6B9F # 0 +0x008FC6A7 0x6BA0 # 0 +0x008FC6A8 0x6BA2 # 0 +0x008FC6A9 0x6BA3 # 0 +0x008FC6AA 0x6BA8 # 0 +0x008FC6AB 0x6BA9 # 0 +0x008FC6AC 0x6BAC # 0 +0x008FC6AD 0x6BAD # 0 +0x008FC6AE 0x6BAE # 0 +0x008FC6AF 0x6BB0 # 0 +0x008FC6B0 0x6BB8 # 0 +0x008FC6B1 0x6BB9 # 0 +0x008FC6B2 0x6BBD # 0 +0x008FC6B3 0x6BBE # 0 +0x008FC6B4 0x6BC3 # 0 +0x008FC6B5 0x6BC4 # 0 +0x008FC6B6 0x6BC9 # 0 +0x008FC6B7 0x6BCC # 0 +0x008FC6B8 0x6BD6 # 0 +0x008FC6B9 0x6BDA # 0 +0x008FC6BA 0x6BE1 # 0 +0x008FC6BB 0x6BE3 # 0 +0x008FC6BC 0x6BE6 # 0 +0x008FC6BD 0x6BE7 # 0 +0x008FC6BE 0x6BEE # 0 +0x008FC6BF 0x6BF1 # 0 +0x008FC6C0 0x6BF7 # 0 +0x008FC6C1 0x6BF9 # 0 +0x008FC6C2 0x6BFF # 0 +0x008FC6C3 0x6C02 # 0 +0x008FC6C4 0x6C04 # 0 +0x008FC6C5 0x6C05 # 0 +0x008FC6C6 0x6C09 # 0 +0x008FC6C7 0x6C0D # 0 +0x008FC6C8 0x6C0E # 0 +0x008FC6C9 0x6C10 # 0 +0x008FC6CA 0x6C12 # 0 +0x008FC6CB 0x6C19 # 0 +0x008FC6CC 0x6C1F # 0 +0x008FC6CD 0x6C26 # 0 +0x008FC6CE 0x6C27 # 0 +0x008FC6CF 0x6C28 # 0 +0x008FC6D0 0x6C2C # 0 +0x008FC6D1 0x6C2E # 0 +0x008FC6D2 0x6C33 # 0 +0x008FC6D3 0x6C35 # 0 +0x008FC6D4 0x6C36 # 0 +0x008FC6D5 0x6C3A # 0 +0x008FC6D6 0x6C3B # 0 +0x008FC6D7 0x6C3F # 0 +0x008FC6D8 0x6C4A # 0 +0x008FC6D9 0x6C4B # 0 +0x008FC6DA 0x6C4D # 0 +0x008FC6DB 0x6C4F # 0 +0x008FC6DC 0x6C52 # 0 +0x008FC6DD 0x6C54 # 0 +0x008FC6DE 0x6C59 # 0 +0x008FC6DF 0x6C5B # 0 +0x008FC6E0 0x6C5C # 0 +0x008FC6E1 0x6C6B # 0 +0x008FC6E2 0x6C6D # 0 +0x008FC6E3 0x6C6F # 0 +0x008FC6E4 0x6C74 # 0 +0x008FC6E5 0x6C76 # 0 +0x008FC6E6 0x6C78 # 0 +0x008FC6E7 0x6C79 # 0 +0x008FC6E8 0x6C7B # 0 +0x008FC6E9 0x6C85 # 0 +0x008FC6EA 0x6C86 # 0 +0x008FC6EB 0x6C87 # 0 +0x008FC6EC 0x6C89 # 0 +0x008FC6ED 0x6C94 # 0 +0x008FC6EE 0x6C95 # 0 +0x008FC6EF 0x6C97 # 0 +0x008FC6F0 0x6C98 # 0 +0x008FC6F1 0x6C9C # 0 +0x008FC6F2 0x6C9F # 0 +0x008FC6F3 0x6CB0 # 0 +0x008FC6F4 0x6CB2 # 0 +0x008FC6F5 0x6CB4 # 0 +0x008FC6F6 0x6CC2 # 0 +0x008FC6F7 0x6CC6 # 0 +0x008FC6F8 0x6CCD # 0 +0x008FC6F9 0x6CCF # 0 +0x008FC6FA 0x6CD0 # 0 +0x008FC6FB 0x6CD1 # 0 +0x008FC6FC 0x6CD2 # 0 +0x008FC6FD 0x6CD4 # 0 +0x008FC6FE 0x6CD6 # 0 +0x008FC7A1 0x6CDA # 0 +0x008FC7A2 0x6CDC # 0 +0x008FC7A3 0x6CE0 # 0 +0x008FC7A4 0x6CE7 # 0 +0x008FC7A5 0x6CE9 # 0 +0x008FC7A6 0x6CEB # 0 +0x008FC7A7 0x6CEC # 0 +0x008FC7A8 0x6CEE # 0 +0x008FC7A9 0x6CF2 # 0 +0x008FC7AA 0x6CF4 # 0 +0x008FC7AB 0x6D04 # 0 +0x008FC7AC 0x6D07 # 0 +0x008FC7AD 0x6D0A # 0 +0x008FC7AE 0x6D0E # 0 +0x008FC7AF 0x6D0F # 0 +0x008FC7B0 0x6D11 # 0 +0x008FC7B1 0x6D13 # 0 +0x008FC7B2 0x6D1A # 0 +0x008FC7B3 0x6D26 # 0 +0x008FC7B4 0x6D27 # 0 +0x008FC7B5 0x6D28 # 0 +0x008FC7B6 0x6C67 # 0 +0x008FC7B7 0x6D2E # 0 +0x008FC7B8 0x6D2F # 0 +0x008FC7B9 0x6D31 # 0 +0x008FC7BA 0x6D39 # 0 +0x008FC7BB 0x6D3C # 0 +0x008FC7BC 0x6D3F # 0 +0x008FC7BD 0x6D57 # 0 +0x008FC7BE 0x6D5E # 0 +0x008FC7BF 0x6D5F # 0 +0x008FC7C0 0x6D61 # 0 +0x008FC7C1 0x6D65 # 0 +0x008FC7C2 0x6D67 # 0 +0x008FC7C3 0x6D6F # 0 +0x008FC7C4 0x6D70 # 0 +0x008FC7C5 0x6D7C # 0 +0x008FC7C6 0x6D82 # 0 +0x008FC7C7 0x6D87 # 0 +0x008FC7C8 0x6D91 # 0 +0x008FC7C9 0x6D92 # 0 +0x008FC7CA 0x6D94 # 0 +0x008FC7CB 0x6D96 # 0 +0x008FC7CC 0x6D97 # 0 +0x008FC7CD 0x6D98 # 0 +0x008FC7CE 0x6DAA # 0 +0x008FC7CF 0x6DAC # 0 +0x008FC7D0 0x6DB4 # 0 +0x008FC7D1 0x6DB7 # 0 +0x008FC7D2 0x6DB9 # 0 +0x008FC7D3 0x6DBD # 0 +0x008FC7D4 0x6DBF # 0 +0x008FC7D5 0x6DC4 # 0 +0x008FC7D6 0x6DC8 # 0 +0x008FC7D7 0x6DCA # 0 +0x008FC7D8 0x6DCE # 0 +0x008FC7D9 0x6DCF # 0 +0x008FC7DA 0x6DD6 # 0 +0x008FC7DB 0x6DDB # 0 +0x008FC7DC 0x6DDD # 0 +0x008FC7DD 0x6DDF # 0 +0x008FC7DE 0x6DE0 # 0 +0x008FC7DF 0x6DE2 # 0 +0x008FC7E0 0x6DE5 # 0 +0x008FC7E1 0x6DE9 # 0 +0x008FC7E2 0x6DEF # 0 +0x008FC7E3 0x6DF0 # 0 +0x008FC7E4 0x6DF4 # 0 +0x008FC7E5 0x6DF6 # 0 +0x008FC7E6 0x6DFC # 0 +0x008FC7E7 0x6E00 # 0 +0x008FC7E8 0x6E04 # 0 +0x008FC7E9 0x6E1E # 0 +0x008FC7EA 0x6E22 # 0 +0x008FC7EB 0x6E27 # 0 +0x008FC7EC 0x6E32 # 0 +0x008FC7ED 0x6E36 # 0 +0x008FC7EE 0x6E39 # 0 +0x008FC7EF 0x6E3B # 0 +0x008FC7F0 0x6E3C # 0 +0x008FC7F1 0x6E44 # 0 +0x008FC7F2 0x6E45 # 0 +0x008FC7F3 0x6E48 # 0 +0x008FC7F4 0x6E49 # 0 +0x008FC7F5 0x6E4B # 0 +0x008FC7F6 0x6E4F # 0 +0x008FC7F7 0x6E51 # 0 +0x008FC7F8 0x6E52 # 0 +0x008FC7F9 0x6E53 # 0 +0x008FC7FA 0x6E54 # 0 +0x008FC7FB 0x6E57 # 0 +0x008FC7FC 0x6E5C # 0 +0x008FC7FD 0x6E5D # 0 +0x008FC7FE 0x6E5E # 0 +0x008FC8A1 0x6E62 # 0 +0x008FC8A2 0x6E63 # 0 +0x008FC8A3 0x6E68 # 0 +0x008FC8A4 0x6E73 # 0 +0x008FC8A5 0x6E7B # 0 +0x008FC8A6 0x6E7D # 0 +0x008FC8A7 0x6E8D # 0 +0x008FC8A8 0x6E93 # 0 +0x008FC8A9 0x6E99 # 0 +0x008FC8AA 0x6EA0 # 0 +0x008FC8AB 0x6EA7 # 0 +0x008FC8AC 0x6EAD # 0 +0x008FC8AD 0x6EAE # 0 +0x008FC8AE 0x6EB1 # 0 +0x008FC8AF 0x6EB3 # 0 +0x008FC8B0 0x6EBB # 0 +0x008FC8B1 0x6EBF # 0 +0x008FC8B2 0x6EC0 # 0 +0x008FC8B3 0x6EC1 # 0 +0x008FC8B4 0x6EC3 # 0 +0x008FC8B5 0x6EC7 # 0 +0x008FC8B6 0x6EC8 # 0 +0x008FC8B7 0x6ECA # 0 +0x008FC8B8 0x6ECD # 0 +0x008FC8B9 0x6ECE # 0 +0x008FC8BA 0x6ECF # 0 +0x008FC8BB 0x6EEB # 0 +0x008FC8BC 0x6EED # 0 +0x008FC8BD 0x6EEE # 0 +0x008FC8BE 0x6EF9 # 0 +0x008FC8BF 0x6EFB # 0 +0x008FC8C0 0x6EFD # 0 +0x008FC8C1 0x6F04 # 0 +0x008FC8C2 0x6F08 # 0 +0x008FC8C3 0x6F0A # 0 +0x008FC8C4 0x6F0C # 0 +0x008FC8C5 0x6F0D # 0 +0x008FC8C6 0x6F16 # 0 +0x008FC8C7 0x6F18 # 0 +0x008FC8C8 0x6F1A # 0 +0x008FC8C9 0x6F1B # 0 +0x008FC8CA 0x6F26 # 0 +0x008FC8CB 0x6F29 # 0 +0x008FC8CC 0x6F2A # 0 +0x008FC8CD 0x6F2F # 0 +0x008FC8CE 0x6F30 # 0 +0x008FC8CF 0x6F33 # 0 +0x008FC8D0 0x6F36 # 0 +0x008FC8D1 0x6F3B # 0 +0x008FC8D2 0x6F3C # 0 +0x008FC8D3 0x6F2D # 0 +0x008FC8D4 0x6F4F # 0 +0x008FC8D5 0x6F51 # 0 +0x008FC8D6 0x6F52 # 0 +0x008FC8D7 0x6F53 # 0 +0x008FC8D8 0x6F57 # 0 +0x008FC8D9 0x6F59 # 0 +0x008FC8DA 0x6F5A # 0 +0x008FC8DB 0x6F5D # 0 +0x008FC8DC 0x6F5E # 0 +0x008FC8DD 0x6F61 # 0 +0x008FC8DE 0x6F62 # 0 +0x008FC8DF 0x6F68 # 0 +0x008FC8E0 0x6F6C # 0 +0x008FC8E1 0x6F7D # 0 +0x008FC8E2 0x6F7E # 0 +0x008FC8E3 0x6F83 # 0 +0x008FC8E4 0x6F87 # 0 +0x008FC8E5 0x6F88 # 0 +0x008FC8E6 0x6F8B # 0 +0x008FC8E7 0x6F8C # 0 +0x008FC8E8 0x6F8D # 0 +0x008FC8E9 0x6F90 # 0 +0x008FC8EA 0x6F92 # 0 +0x008FC8EB 0x6F93 # 0 +0x008FC8EC 0x6F94 # 0 +0x008FC8ED 0x6F96 # 0 +0x008FC8EE 0x6F9A # 0 +0x008FC8EF 0x6F9F # 0 +0x008FC8F0 0x6FA0 # 0 +0x008FC8F1 0x6FA5 # 0 +0x008FC8F2 0x6FA6 # 0 +0x008FC8F3 0x6FA7 # 0 +0x008FC8F4 0x6FA8 # 0 +0x008FC8F5 0x6FAE # 0 +0x008FC8F6 0x6FAF # 0 +0x008FC8F7 0x6FB0 # 0 +0x008FC8F8 0x6FB5 # 0 +0x008FC8F9 0x6FB6 # 0 +0x008FC8FA 0x6FBC # 0 +0x008FC8FB 0x6FC5 # 0 +0x008FC8FC 0x6FC7 # 0 +0x008FC8FD 0x6FC8 # 0 +0x008FC8FE 0x6FCA # 0 +0x008FC9A1 0x6FDA # 0 +0x008FC9A2 0x6FDE # 0 +0x008FC9A3 0x6FE8 # 0 +0x008FC9A4 0x6FE9 # 0 +0x008FC9A5 0x6FF0 # 0 +0x008FC9A6 0x6FF5 # 0 +0x008FC9A7 0x6FF9 # 0 +0x008FC9A8 0x6FFC # 0 +0x008FC9A9 0x6FFD # 0 +0x008FC9AA 0x7000 # 0 +0x008FC9AB 0x7005 # 0 +0x008FC9AC 0x7006 # 0 +0x008FC9AD 0x7007 # 0 +0x008FC9AE 0x700D # 0 +0x008FC9AF 0x7017 # 0 +0x008FC9B0 0x7020 # 0 +0x008FC9B1 0x7023 # 0 +0x008FC9B2 0x702F # 0 +0x008FC9B3 0x7034 # 0 +0x008FC9B4 0x7037 # 0 +0x008FC9B5 0x7039 # 0 +0x008FC9B6 0x703C # 0 +0x008FC9B7 0x7043 # 0 +0x008FC9B8 0x7044 # 0 +0x008FC9B9 0x7048 # 0 +0x008FC9BA 0x7049 # 0 +0x008FC9BB 0x704A # 0 +0x008FC9BC 0x704B # 0 +0x008FC9BD 0x7054 # 0 +0x008FC9BE 0x7055 # 0 +0x008FC9BF 0x705D # 0 +0x008FC9C0 0x705E # 0 +0x008FC9C1 0x704E # 0 +0x008FC9C2 0x7064 # 0 +0x008FC9C3 0x7065 # 0 +0x008FC9C4 0x706C # 0 +0x008FC9C5 0x706E # 0 +0x008FC9C6 0x7075 # 0 +0x008FC9C7 0x7076 # 0 +0x008FC9C8 0x707E # 0 +0x008FC9C9 0x7081 # 0 +0x008FC9CA 0x7085 # 0 +0x008FC9CB 0x7086 # 0 +0x008FC9CC 0x7094 # 0 +0x008FC9CD 0x7095 # 0 +0x008FC9CE 0x7096 # 0 +0x008FC9CF 0x7097 # 0 +0x008FC9D0 0x7098 # 0 +0x008FC9D1 0x709B # 0 +0x008FC9D2 0x70A4 # 0 +0x008FC9D3 0x70AB # 0 +0x008FC9D4 0x70B0 # 0 +0x008FC9D5 0x70B1 # 0 +0x008FC9D6 0x70B4 # 0 +0x008FC9D7 0x70B7 # 0 +0x008FC9D8 0x70CA # 0 +0x008FC9D9 0x70D1 # 0 +0x008FC9DA 0x70D3 # 0 +0x008FC9DB 0x70D4 # 0 +0x008FC9DC 0x70D5 # 0 +0x008FC9DD 0x70D6 # 0 +0x008FC9DE 0x70D8 # 0 +0x008FC9DF 0x70DC # 0 +0x008FC9E0 0x70E4 # 0 +0x008FC9E1 0x70FA # 0 +0x008FC9E2 0x7103 # 0 +0x008FC9E3 0x7104 # 0 +0x008FC9E4 0x7105 # 0 +0x008FC9E5 0x7106 # 0 +0x008FC9E6 0x7107 # 0 +0x008FC9E7 0x710B # 0 +0x008FC9E8 0x710C # 0 +0x008FC9E9 0x710F # 0 +0x008FC9EA 0x711E # 0 +0x008FC9EB 0x7120 # 0 +0x008FC9EC 0x712B # 0 +0x008FC9ED 0x712D # 0 +0x008FC9EE 0x712F # 0 +0x008FC9EF 0x7130 # 0 +0x008FC9F0 0x7131 # 0 +0x008FC9F1 0x7138 # 0 +0x008FC9F2 0x7141 # 0 +0x008FC9F3 0x7145 # 0 +0x008FC9F4 0x7146 # 0 +0x008FC9F5 0x7147 # 0 +0x008FC9F6 0x714A # 0 +0x008FC9F7 0x714B # 0 +0x008FC9F8 0x7150 # 0 +0x008FC9F9 0x7152 # 0 +0x008FC9FA 0x7157 # 0 +0x008FC9FB 0x715A # 0 +0x008FC9FC 0x715C # 0 +0x008FC9FD 0x715E # 0 +0x008FC9FE 0x7160 # 0 +0x008FCAA1 0x7168 # 0 +0x008FCAA2 0x7179 # 0 +0x008FCAA3 0x7180 # 0 +0x008FCAA4 0x7185 # 0 +0x008FCAA5 0x7187 # 0 +0x008FCAA6 0x718C # 0 +0x008FCAA7 0x7192 # 0 +0x008FCAA8 0x719A # 0 +0x008FCAA9 0x719B # 0 +0x008FCAAA 0x71A0 # 0 +0x008FCAAB 0x71A2 # 0 +0x008FCAAC 0x71AF # 0 +0x008FCAAD 0x71B0 # 0 +0x008FCAAE 0x71B2 # 0 +0x008FCAAF 0x71B3 # 0 +0x008FCAB0 0x71BA # 0 +0x008FCAB1 0x71BF # 0 +0x008FCAB2 0x71C0 # 0 +0x008FCAB3 0x71C1 # 0 +0x008FCAB4 0x71C4 # 0 +0x008FCAB5 0x71CB # 0 +0x008FCAB6 0x71CC # 0 +0x008FCAB7 0x71D3 # 0 +0x008FCAB8 0x71D6 # 0 +0x008FCAB9 0x71D9 # 0 +0x008FCABA 0x71DA # 0 +0x008FCABB 0x71DC # 0 +0x008FCABC 0x71F8 # 0 +0x008FCABD 0x71FE # 0 +0x008FCABE 0x7200 # 0 +0x008FCABF 0x7207 # 0 +0x008FCAC0 0x7208 # 0 +0x008FCAC1 0x7209 # 0 +0x008FCAC2 0x7213 # 0 +0x008FCAC3 0x7217 # 0 +0x008FCAC4 0x721A # 0 +0x008FCAC5 0x721D # 0 +0x008FCAC6 0x721F # 0 +0x008FCAC7 0x7224 # 0 +0x008FCAC8 0x722B # 0 +0x008FCAC9 0x722F # 0 +0x008FCACA 0x7234 # 0 +0x008FCACB 0x7238 # 0 +0x008FCACC 0x7239 # 0 +0x008FCACD 0x7241 # 0 +0x008FCACE 0x7242 # 0 +0x008FCACF 0x7243 # 0 +0x008FCAD0 0x7245 # 0 +0x008FCAD1 0x724E # 0 +0x008FCAD2 0x724F # 0 +0x008FCAD3 0x7250 # 0 +0x008FCAD4 0x7253 # 0 +0x008FCAD5 0x7255 # 0 +0x008FCAD6 0x7256 # 0 +0x008FCAD7 0x725A # 0 +0x008FCAD8 0x725C # 0 +0x008FCAD9 0x725E # 0 +0x008FCADA 0x7260 # 0 +0x008FCADB 0x7263 # 0 +0x008FCADC 0x7268 # 0 +0x008FCADD 0x726B # 0 +0x008FCADE 0x726E # 0 +0x008FCADF 0x726F # 0 +0x008FCAE0 0x7271 # 0 +0x008FCAE1 0x7277 # 0 +0x008FCAE2 0x7278 # 0 +0x008FCAE3 0x727B # 0 +0x008FCAE4 0x727C # 0 +0x008FCAE5 0x727F # 0 +0x008FCAE6 0x7284 # 0 +0x008FCAE7 0x7289 # 0 +0x008FCAE8 0x728D # 0 +0x008FCAE9 0x728E # 0 +0x008FCAEA 0x7293 # 0 +0x008FCAEB 0x729B # 0 +0x008FCAEC 0x72A8 # 0 +0x008FCAED 0x72AD # 0 +0x008FCAEE 0x72AE # 0 +0x008FCAEF 0x72B1 # 0 +0x008FCAF0 0x72B4 # 0 +0x008FCAF1 0x72BE # 0 +0x008FCAF2 0x72C1 # 0 +0x008FCAF3 0x72C7 # 0 +0x008FCAF4 0x72C9 # 0 +0x008FCAF5 0x72CC # 0 +0x008FCAF6 0x72D5 # 0 +0x008FCAF7 0x72D6 # 0 +0x008FCAF8 0x72D8 # 0 +0x008FCAF9 0x72DF # 0 +0x008FCAFA 0x72E5 # 0 +0x008FCAFB 0x72F3 # 0 +0x008FCAFC 0x72F4 # 0 +0x008FCAFD 0x72FA # 0 +0x008FCAFE 0x72FB # 0 +0x008FCBA1 0x72FE # 0 +0x008FCBA2 0x7302 # 0 +0x008FCBA3 0x7304 # 0 +0x008FCBA4 0x7305 # 0 +0x008FCBA5 0x7307 # 0 +0x008FCBA6 0x730B # 0 +0x008FCBA7 0x730D # 0 +0x008FCBA8 0x7312 # 0 +0x008FCBA9 0x7313 # 0 +0x008FCBAA 0x7318 # 0 +0x008FCBAB 0x7319 # 0 +0x008FCBAC 0x731E # 0 +0x008FCBAD 0x7322 # 0 +0x008FCBAE 0x7324 # 0 +0x008FCBAF 0x7327 # 0 +0x008FCBB0 0x7328 # 0 +0x008FCBB1 0x732C # 0 +0x008FCBB2 0x7331 # 0 +0x008FCBB3 0x7332 # 0 +0x008FCBB4 0x7335 # 0 +0x008FCBB5 0x733A # 0 +0x008FCBB6 0x733B # 0 +0x008FCBB7 0x733D # 0 +0x008FCBB8 0x7343 # 0 +0x008FCBB9 0x734D # 0 +0x008FCBBA 0x7350 # 0 +0x008FCBBB 0x7352 # 0 +0x008FCBBC 0x7356 # 0 +0x008FCBBD 0x7358 # 0 +0x008FCBBE 0x735D # 0 +0x008FCBBF 0x735E # 0 +0x008FCBC0 0x735F # 0 +0x008FCBC1 0x7360 # 0 +0x008FCBC2 0x7366 # 0 +0x008FCBC3 0x7367 # 0 +0x008FCBC4 0x7369 # 0 +0x008FCBC5 0x736B # 0 +0x008FCBC6 0x736C # 0 +0x008FCBC7 0x736E # 0 +0x008FCBC8 0x736F # 0 +0x008FCBC9 0x7371 # 0 +0x008FCBCA 0x7377 # 0 +0x008FCBCB 0x7379 # 0 +0x008FCBCC 0x737C # 0 +0x008FCBCD 0x7380 # 0 +0x008FCBCE 0x7381 # 0 +0x008FCBCF 0x7383 # 0 +0x008FCBD0 0x7385 # 0 +0x008FCBD1 0x7386 # 0 +0x008FCBD2 0x738E # 0 +0x008FCBD3 0x7390 # 0 +0x008FCBD4 0x7393 # 0 +0x008FCBD5 0x7395 # 0 +0x008FCBD6 0x7397 # 0 +0x008FCBD7 0x7398 # 0 +0x008FCBD8 0x739C # 0 +0x008FCBD9 0x739E # 0 +0x008FCBDA 0x739F # 0 +0x008FCBDB 0x73A0 # 0 +0x008FCBDC 0x73A2 # 0 +0x008FCBDD 0x73A5 # 0 +0x008FCBDE 0x73A6 # 0 +0x008FCBDF 0x73AA # 0 +0x008FCBE0 0x73AB # 0 +0x008FCBE1 0x73AD # 0 +0x008FCBE2 0x73B5 # 0 +0x008FCBE3 0x73B7 # 0 +0x008FCBE4 0x73B9 # 0 +0x008FCBE5 0x73BC # 0 +0x008FCBE6 0x73BD # 0 +0x008FCBE7 0x73BF # 0 +0x008FCBE8 0x73C5 # 0 +0x008FCBE9 0x73C6 # 0 +0x008FCBEA 0x73C9 # 0 +0x008FCBEB 0x73CB # 0 +0x008FCBEC 0x73CC # 0 +0x008FCBED 0x73CF # 0 +0x008FCBEE 0x73D2 # 0 +0x008FCBEF 0x73D3 # 0 +0x008FCBF0 0x73D6 # 0 +0x008FCBF1 0x73D9 # 0 +0x008FCBF2 0x73DD # 0 +0x008FCBF3 0x73E1 # 0 +0x008FCBF4 0x73E3 # 0 +0x008FCBF5 0x73E6 # 0 +0x008FCBF6 0x73E7 # 0 +0x008FCBF7 0x73E9 # 0 +0x008FCBF8 0x73F4 # 0 +0x008FCBF9 0x73F5 # 0 +0x008FCBFA 0x73F7 # 0 +0x008FCBFB 0x73F9 # 0 +0x008FCBFC 0x73FA # 0 +0x008FCBFD 0x73FB # 0 +0x008FCBFE 0x73FD # 0 +0x008FCCA1 0x73FF # 0 +0x008FCCA2 0x7400 # 0 +0x008FCCA3 0x7401 # 0 +0x008FCCA4 0x7404 # 0 +0x008FCCA5 0x7407 # 0 +0x008FCCA6 0x740A # 0 +0x008FCCA7 0x7411 # 0 +0x008FCCA8 0x741A # 0 +0x008FCCA9 0x741B # 0 +0x008FCCAA 0x7424 # 0 +0x008FCCAB 0x7426 # 0 +0x008FCCAC 0x7428 # 0 +0x008FCCAD 0x7429 # 0 +0x008FCCAE 0x742A # 0 +0x008FCCAF 0x742B # 0 +0x008FCCB0 0x742C # 0 +0x008FCCB1 0x742D # 0 +0x008FCCB2 0x742E # 0 +0x008FCCB3 0x742F # 0 +0x008FCCB4 0x7430 # 0 +0x008FCCB5 0x7431 # 0 +0x008FCCB6 0x7439 # 0 +0x008FCCB7 0x7440 # 0 +0x008FCCB8 0x7443 # 0 +0x008FCCB9 0x7444 # 0 +0x008FCCBA 0x7446 # 0 +0x008FCCBB 0x7447 # 0 +0x008FCCBC 0x744B # 0 +0x008FCCBD 0x744D # 0 +0x008FCCBE 0x7451 # 0 +0x008FCCBF 0x7452 # 0 +0x008FCCC0 0x7457 # 0 +0x008FCCC1 0x745D # 0 +0x008FCCC2 0x7462 # 0 +0x008FCCC3 0x7466 # 0 +0x008FCCC4 0x7467 # 0 +0x008FCCC5 0x7468 # 0 +0x008FCCC6 0x746B # 0 +0x008FCCC7 0x746D # 0 +0x008FCCC8 0x746E # 0 +0x008FCCC9 0x7471 # 0 +0x008FCCCA 0x7472 # 0 +0x008FCCCB 0x7480 # 0 +0x008FCCCC 0x7481 # 0 +0x008FCCCD 0x7485 # 0 +0x008FCCCE 0x7486 # 0 +0x008FCCCF 0x7487 # 0 +0x008FCCD0 0x7489 # 0 +0x008FCCD1 0x748F # 0 +0x008FCCD2 0x7490 # 0 +0x008FCCD3 0x7491 # 0 +0x008FCCD4 0x7492 # 0 +0x008FCCD5 0x7498 # 0 +0x008FCCD6 0x7499 # 0 +0x008FCCD7 0x749A # 0 +0x008FCCD8 0x749C # 0 +0x008FCCD9 0x749F # 0 +0x008FCCDA 0x74A0 # 0 +0x008FCCDB 0x74A1 # 0 +0x008FCCDC 0x74A3 # 0 +0x008FCCDD 0x74A6 # 0 +0x008FCCDE 0x74A8 # 0 +0x008FCCDF 0x74A9 # 0 +0x008FCCE0 0x74AA # 0 +0x008FCCE1 0x74AB # 0 +0x008FCCE2 0x74AE # 0 +0x008FCCE3 0x74AF # 0 +0x008FCCE4 0x74B1 # 0 +0x008FCCE5 0x74B2 # 0 +0x008FCCE6 0x74B5 # 0 +0x008FCCE7 0x74B9 # 0 +0x008FCCE8 0x74BB # 0 +0x008FCCE9 0x74BF # 0 +0x008FCCEA 0x74C8 # 0 +0x008FCCEB 0x74C9 # 0 +0x008FCCEC 0x74CC # 0 +0x008FCCED 0x74D0 # 0 +0x008FCCEE 0x74D3 # 0 +0x008FCCEF 0x74D8 # 0 +0x008FCCF0 0x74DA # 0 +0x008FCCF1 0x74DB # 0 +0x008FCCF2 0x74DE # 0 +0x008FCCF3 0x74DF # 0 +0x008FCCF4 0x74E4 # 0 +0x008FCCF5 0x74E8 # 0 +0x008FCCF6 0x74EA # 0 +0x008FCCF7 0x74EB # 0 +0x008FCCF8 0x74EF # 0 +0x008FCCF9 0x74F4 # 0 +0x008FCCFA 0x74FA # 0 +0x008FCCFB 0x74FB # 0 +0x008FCCFC 0x74FC # 0 +0x008FCCFD 0x74FF # 0 +0x008FCCFE 0x7506 # 0 +0x008FCDA1 0x7512 # 0 +0x008FCDA2 0x7516 # 0 +0x008FCDA3 0x7517 # 0 +0x008FCDA4 0x7520 # 0 +0x008FCDA5 0x7521 # 0 +0x008FCDA6 0x7524 # 0 +0x008FCDA7 0x7527 # 0 +0x008FCDA8 0x7529 # 0 +0x008FCDA9 0x752A # 0 +0x008FCDAA 0x752F # 0 +0x008FCDAB 0x7536 # 0 +0x008FCDAC 0x7539 # 0 +0x008FCDAD 0x753D # 0 +0x008FCDAE 0x753E # 0 +0x008FCDAF 0x753F # 0 +0x008FCDB0 0x7540 # 0 +0x008FCDB1 0x7543 # 0 +0x008FCDB2 0x7547 # 0 +0x008FCDB3 0x7548 # 0 +0x008FCDB4 0x754E # 0 +0x008FCDB5 0x7550 # 0 +0x008FCDB6 0x7552 # 0 +0x008FCDB7 0x7557 # 0 +0x008FCDB8 0x755E # 0 +0x008FCDB9 0x755F # 0 +0x008FCDBA 0x7561 # 0 +0x008FCDBB 0x756F # 0 +0x008FCDBC 0x7571 # 0 +0x008FCDBD 0x7579 # 0 +0x008FCDBE 0x757A # 0 +0x008FCDBF 0x757B # 0 +0x008FCDC0 0x757C # 0 +0x008FCDC1 0x757D # 0 +0x008FCDC2 0x757E # 0 +0x008FCDC3 0x7581 # 0 +0x008FCDC4 0x7585 # 0 +0x008FCDC5 0x7590 # 0 +0x008FCDC6 0x7592 # 0 +0x008FCDC7 0x7593 # 0 +0x008FCDC8 0x7595 # 0 +0x008FCDC9 0x7599 # 0 +0x008FCDCA 0x759C # 0 +0x008FCDCB 0x75A2 # 0 +0x008FCDCC 0x75A4 # 0 +0x008FCDCD 0x75B4 # 0 +0x008FCDCE 0x75BA # 0 +0x008FCDCF 0x75BF # 0 +0x008FCDD0 0x75C0 # 0 +0x008FCDD1 0x75C1 # 0 +0x008FCDD2 0x75C4 # 0 +0x008FCDD3 0x75C6 # 0 +0x008FCDD4 0x75CC # 0 +0x008FCDD5 0x75CE # 0 +0x008FCDD6 0x75CF # 0 +0x008FCDD7 0x75D7 # 0 +0x008FCDD8 0x75DC # 0 +0x008FCDD9 0x75DF # 0 +0x008FCDDA 0x75E0 # 0 +0x008FCDDB 0x75E1 # 0 +0x008FCDDC 0x75E4 # 0 +0x008FCDDD 0x75E7 # 0 +0x008FCDDE 0x75EC # 0 +0x008FCDDF 0x75EE # 0 +0x008FCDE0 0x75EF # 0 +0x008FCDE1 0x75F1 # 0 +0x008FCDE2 0x75F9 # 0 +0x008FCDE3 0x7600 # 0 +0x008FCDE4 0x7602 # 0 +0x008FCDE5 0x7603 # 0 +0x008FCDE6 0x7604 # 0 +0x008FCDE7 0x7607 # 0 +0x008FCDE8 0x7608 # 0 +0x008FCDE9 0x760A # 0 +0x008FCDEA 0x760C # 0 +0x008FCDEB 0x760F # 0 +0x008FCDEC 0x7612 # 0 +0x008FCDED 0x7613 # 0 +0x008FCDEE 0x7615 # 0 +0x008FCDEF 0x7616 # 0 +0x008FCDF0 0x7619 # 0 +0x008FCDF1 0x761B # 0 +0x008FCDF2 0x761C # 0 +0x008FCDF3 0x761D # 0 +0x008FCDF4 0x761E # 0 +0x008FCDF5 0x7623 # 0 +0x008FCDF6 0x7625 # 0 +0x008FCDF7 0x7626 # 0 +0x008FCDF8 0x7629 # 0 +0x008FCDF9 0x762D # 0 +0x008FCDFA 0x7632 # 0 +0x008FCDFB 0x7633 # 0 +0x008FCDFC 0x7635 # 0 +0x008FCDFD 0x7638 # 0 +0x008FCDFE 0x7639 # 0 +0x008FCEA1 0x763A # 0 +0x008FCEA2 0x763C # 0 +0x008FCEA3 0x764A # 0 +0x008FCEA4 0x7640 # 0 +0x008FCEA5 0x7641 # 0 +0x008FCEA6 0x7643 # 0 +0x008FCEA7 0x7644 # 0 +0x008FCEA8 0x7645 # 0 +0x008FCEA9 0x7649 # 0 +0x008FCEAA 0x764B # 0 +0x008FCEAB 0x7655 # 0 +0x008FCEAC 0x7659 # 0 +0x008FCEAD 0x765F # 0 +0x008FCEAE 0x7664 # 0 +0x008FCEAF 0x7665 # 0 +0x008FCEB0 0x766D # 0 +0x008FCEB1 0x766E # 0 +0x008FCEB2 0x766F # 0 +0x008FCEB3 0x7671 # 0 +0x008FCEB4 0x7674 # 0 +0x008FCEB5 0x7681 # 0 +0x008FCEB6 0x7685 # 0 +0x008FCEB7 0x768C # 0 +0x008FCEB8 0x768D # 0 +0x008FCEB9 0x7695 # 0 +0x008FCEBA 0x769B # 0 +0x008FCEBB 0x769C # 0 +0x008FCEBC 0x769D # 0 +0x008FCEBD 0x769F # 0 +0x008FCEBE 0x76A0 # 0 +0x008FCEBF 0x76A2 # 0 +0x008FCEC0 0x76A3 # 0 +0x008FCEC1 0x76A4 # 0 +0x008FCEC2 0x76A5 # 0 +0x008FCEC3 0x76A6 # 0 +0x008FCEC4 0x76A7 # 0 +0x008FCEC5 0x76A8 # 0 +0x008FCEC6 0x76AA # 0 +0x008FCEC7 0x76AD # 0 +0x008FCEC8 0x76BD # 0 +0x008FCEC9 0x76C1 # 0 +0x008FCECA 0x76C5 # 0 +0x008FCECB 0x76C9 # 0 +0x008FCECC 0x76CB # 0 +0x008FCECD 0x76CC # 0 +0x008FCECE 0x76CE # 0 +0x008FCECF 0x76D4 # 0 +0x008FCED0 0x76D9 # 0 +0x008FCED1 0x76E0 # 0 +0x008FCED2 0x76E6 # 0 +0x008FCED3 0x76E8 # 0 +0x008FCED4 0x76EC # 0 +0x008FCED5 0x76F0 # 0 +0x008FCED6 0x76F1 # 0 +0x008FCED7 0x76F6 # 0 +0x008FCED8 0x76F9 # 0 +0x008FCED9 0x76FC # 0 +0x008FCEDA 0x7700 # 0 +0x008FCEDB 0x7706 # 0 +0x008FCEDC 0x770A # 0 +0x008FCEDD 0x770E # 0 +0x008FCEDE 0x7712 # 0 +0x008FCEDF 0x7714 # 0 +0x008FCEE0 0x7715 # 0 +0x008FCEE1 0x7717 # 0 +0x008FCEE2 0x7719 # 0 +0x008FCEE3 0x771A # 0 +0x008FCEE4 0x771C # 0 +0x008FCEE5 0x7722 # 0 +0x008FCEE6 0x7728 # 0 +0x008FCEE7 0x772D # 0 +0x008FCEE8 0x772E # 0 +0x008FCEE9 0x772F # 0 +0x008FCEEA 0x7734 # 0 +0x008FCEEB 0x7735 # 0 +0x008FCEEC 0x7736 # 0 +0x008FCEED 0x7739 # 0 +0x008FCEEE 0x773D # 0 +0x008FCEEF 0x773E # 0 +0x008FCEF0 0x7742 # 0 +0x008FCEF1 0x7745 # 0 +0x008FCEF2 0x7746 # 0 +0x008FCEF3 0x774A # 0 +0x008FCEF4 0x774D # 0 +0x008FCEF5 0x774E # 0 +0x008FCEF6 0x774F # 0 +0x008FCEF7 0x7752 # 0 +0x008FCEF8 0x7756 # 0 +0x008FCEF9 0x7757 # 0 +0x008FCEFA 0x775C # 0 +0x008FCEFB 0x775E # 0 +0x008FCEFC 0x775F # 0 +0x008FCEFD 0x7760 # 0 +0x008FCEFE 0x7762 # 0 +0x008FCFA1 0x7764 # 0 +0x008FCFA2 0x7767 # 0 +0x008FCFA3 0x776A # 0 +0x008FCFA4 0x776C # 0 +0x008FCFA5 0x7770 # 0 +0x008FCFA6 0x7772 # 0 +0x008FCFA7 0x7773 # 0 +0x008FCFA8 0x7774 # 0 +0x008FCFA9 0x777A # 0 +0x008FCFAA 0x777D # 0 +0x008FCFAB 0x7780 # 0 +0x008FCFAC 0x7784 # 0 +0x008FCFAD 0x778C # 0 +0x008FCFAE 0x778D # 0 +0x008FCFAF 0x7794 # 0 +0x008FCFB0 0x7795 # 0 +0x008FCFB1 0x7796 # 0 +0x008FCFB2 0x779A # 0 +0x008FCFB3 0x779F # 0 +0x008FCFB4 0x77A2 # 0 +0x008FCFB5 0x77A7 # 0 +0x008FCFB6 0x77AA # 0 +0x008FCFB7 0x77AE # 0 +0x008FCFB8 0x77AF # 0 +0x008FCFB9 0x77B1 # 0 +0x008FCFBA 0x77B5 # 0 +0x008FCFBB 0x77BE # 0 +0x008FCFBC 0x77C3 # 0 +0x008FCFBD 0x77C9 # 0 +0x008FCFBE 0x77D1 # 0 +0x008FCFBF 0x77D2 # 0 +0x008FCFC0 0x77D5 # 0 +0x008FCFC1 0x77D9 # 0 +0x008FCFC2 0x77DE # 0 +0x008FCFC3 0x77DF # 0 +0x008FCFC4 0x77E0 # 0 +0x008FCFC5 0x77E4 # 0 +0x008FCFC6 0x77E6 # 0 +0x008FCFC7 0x77EA # 0 +0x008FCFC8 0x77EC # 0 +0x008FCFC9 0x77F0 # 0 +0x008FCFCA 0x77F1 # 0 +0x008FCFCB 0x77F4 # 0 +0x008FCFCC 0x77F8 # 0 +0x008FCFCD 0x77FB # 0 +0x008FCFCE 0x7805 # 0 +0x008FCFCF 0x7806 # 0 +0x008FCFD0 0x7809 # 0 +0x008FCFD1 0x780D # 0 +0x008FCFD2 0x780E # 0 +0x008FCFD3 0x7811 # 0 +0x008FCFD4 0x781D # 0 +0x008FCFD5 0x7821 # 0 +0x008FCFD6 0x7822 # 0 +0x008FCFD7 0x7823 # 0 +0x008FCFD8 0x782D # 0 +0x008FCFD9 0x782E # 0 +0x008FCFDA 0x7830 # 0 +0x008FCFDB 0x7835 # 0 +0x008FCFDC 0x7837 # 0 +0x008FCFDD 0x7843 # 0 +0x008FCFDE 0x7844 # 0 +0x008FCFDF 0x7847 # 0 +0x008FCFE0 0x7848 # 0 +0x008FCFE1 0x784C # 0 +0x008FCFE2 0x784E # 0 +0x008FCFE3 0x7852 # 0 +0x008FCFE4 0x785C # 0 +0x008FCFE5 0x785E # 0 +0x008FCFE6 0x7860 # 0 +0x008FCFE7 0x7861 # 0 +0x008FCFE8 0x7863 # 0 +0x008FCFE9 0x7864 # 0 +0x008FCFEA 0x7868 # 0 +0x008FCFEB 0x786A # 0 +0x008FCFEC 0x786E # 0 +0x008FCFED 0x787A # 0 +0x008FCFEE 0x787E # 0 +0x008FCFEF 0x788A # 0 +0x008FCFF0 0x788F # 0 +0x008FCFF1 0x7894 # 0 +0x008FCFF2 0x7898 # 0 +0x008FCFF3 0x78A1 # 0 +0x008FCFF4 0x789D # 0 +0x008FCFF5 0x789E # 0 +0x008FCFF6 0x789F # 0 +0x008FCFF7 0x78A4 # 0 +0x008FCFF8 0x78A8 # 0 +0x008FCFF9 0x78AC # 0 +0x008FCFFA 0x78AD # 0 +0x008FCFFB 0x78B0 # 0 +0x008FCFFC 0x78B1 # 0 +0x008FCFFD 0x78B2 # 0 +0x008FCFFE 0x78B3 # 0 +0x008FD0A1 0x78BB # 0 +0x008FD0A2 0x78BD # 0 +0x008FD0A3 0x78BF # 0 +0x008FD0A4 0x78C7 # 0 +0x008FD0A5 0x78C8 # 0 +0x008FD0A6 0x78C9 # 0 +0x008FD0A7 0x78CC # 0 +0x008FD0A8 0x78CE # 0 +0x008FD0A9 0x78D2 # 0 +0x008FD0AA 0x78D3 # 0 +0x008FD0AB 0x78D5 # 0 +0x008FD0AC 0x78D6 # 0 +0x008FD0AD 0x78E4 # 0 +0x008FD0AE 0x78DB # 0 +0x008FD0AF 0x78DF # 0 +0x008FD0B0 0x78E0 # 0 +0x008FD0B1 0x78E1 # 0 +0x008FD0B2 0x78E6 # 0 +0x008FD0B3 0x78EA # 0 +0x008FD0B4 0x78F2 # 0 +0x008FD0B5 0x78F3 # 0 +0x008FD0B6 0x7900 # 0 +0x008FD0B7 0x78F6 # 0 +0x008FD0B8 0x78F7 # 0 +0x008FD0B9 0x78FA # 0 +0x008FD0BA 0x78FB # 0 +0x008FD0BB 0x78FF # 0 +0x008FD0BC 0x7906 # 0 +0x008FD0BD 0x790C # 0 +0x008FD0BE 0x7910 # 0 +0x008FD0BF 0x791A # 0 +0x008FD0C0 0x791C # 0 +0x008FD0C1 0x791E # 0 +0x008FD0C2 0x791F # 0 +0x008FD0C3 0x7920 # 0 +0x008FD0C4 0x7925 # 0 +0x008FD0C5 0x7927 # 0 +0x008FD0C6 0x7929 # 0 +0x008FD0C7 0x792D # 0 +0x008FD0C8 0x7931 # 0 +0x008FD0C9 0x7934 # 0 +0x008FD0CA 0x7935 # 0 +0x008FD0CB 0x793B # 0 +0x008FD0CC 0x793D # 0 +0x008FD0CD 0x793F # 0 +0x008FD0CE 0x7944 # 0 +0x008FD0CF 0x7945 # 0 +0x008FD0D0 0x7946 # 0 +0x008FD0D1 0x794A # 0 +0x008FD0D2 0x794B # 0 +0x008FD0D3 0x794F # 0 +0x008FD0D4 0x7951 # 0 +0x008FD0D5 0x7954 # 0 +0x008FD0D6 0x7958 # 0 +0x008FD0D7 0x795B # 0 +0x008FD0D8 0x795C # 0 +0x008FD0D9 0x7967 # 0 +0x008FD0DA 0x7969 # 0 +0x008FD0DB 0x796B # 0 +0x008FD0DC 0x7972 # 0 +0x008FD0DD 0x7979 # 0 +0x008FD0DE 0x797B # 0 +0x008FD0DF 0x797C # 0 +0x008FD0E0 0x797E # 0 +0x008FD0E1 0x798B # 0 +0x008FD0E2 0x798C # 0 +0x008FD0E3 0x7991 # 0 +0x008FD0E4 0x7993 # 0 +0x008FD0E5 0x7994 # 0 +0x008FD0E6 0x7995 # 0 +0x008FD0E7 0x7996 # 0 +0x008FD0E8 0x7998 # 0 +0x008FD0E9 0x799B # 0 +0x008FD0EA 0x799C # 0 +0x008FD0EB 0x79A1 # 0 +0x008FD0EC 0x79A8 # 0 +0x008FD0ED 0x79A9 # 0 +0x008FD0EE 0x79AB # 0 +0x008FD0EF 0x79AF # 0 +0x008FD0F0 0x79B1 # 0 +0x008FD0F1 0x79B4 # 0 +0x008FD0F2 0x79B8 # 0 +0x008FD0F3 0x79BB # 0 +0x008FD0F4 0x79C2 # 0 +0x008FD0F5 0x79C4 # 0 +0x008FD0F6 0x79C7 # 0 +0x008FD0F7 0x79C8 # 0 +0x008FD0F8 0x79CA # 0 +0x008FD0F9 0x79CF # 0 +0x008FD0FA 0x79D4 # 0 +0x008FD0FB 0x79D6 # 0 +0x008FD0FC 0x79DA # 0 +0x008FD0FD 0x79DD # 0 +0x008FD0FE 0x79DE # 0 +0x008FD1A1 0x79E0 # 0 +0x008FD1A2 0x79E2 # 0 +0x008FD1A3 0x79E5 # 0 +0x008FD1A4 0x79EA # 0 +0x008FD1A5 0x79EB # 0 +0x008FD1A6 0x79ED # 0 +0x008FD1A7 0x79F1 # 0 +0x008FD1A8 0x79F8 # 0 +0x008FD1A9 0x79FC # 0 +0x008FD1AA 0x7A02 # 0 +0x008FD1AB 0x7A03 # 0 +0x008FD1AC 0x7A07 # 0 +0x008FD1AD 0x7A09 # 0 +0x008FD1AE 0x7A0A # 0 +0x008FD1AF 0x7A0C # 0 +0x008FD1B0 0x7A11 # 0 +0x008FD1B1 0x7A15 # 0 +0x008FD1B2 0x7A1B # 0 +0x008FD1B3 0x7A1E # 0 +0x008FD1B4 0x7A21 # 0 +0x008FD1B5 0x7A27 # 0 +0x008FD1B6 0x7A2B # 0 +0x008FD1B7 0x7A2D # 0 +0x008FD1B8 0x7A2F # 0 +0x008FD1B9 0x7A30 # 0 +0x008FD1BA 0x7A34 # 0 +0x008FD1BB 0x7A35 # 0 +0x008FD1BC 0x7A38 # 0 +0x008FD1BD 0x7A39 # 0 +0x008FD1BE 0x7A3A # 0 +0x008FD1BF 0x7A44 # 0 +0x008FD1C0 0x7A45 # 0 +0x008FD1C1 0x7A47 # 0 +0x008FD1C2 0x7A48 # 0 +0x008FD1C3 0x7A4C # 0 +0x008FD1C4 0x7A55 # 0 +0x008FD1C5 0x7A56 # 0 +0x008FD1C6 0x7A59 # 0 +0x008FD1C7 0x7A5C # 0 +0x008FD1C8 0x7A5D # 0 +0x008FD1C9 0x7A5F # 0 +0x008FD1CA 0x7A60 # 0 +0x008FD1CB 0x7A65 # 0 +0x008FD1CC 0x7A67 # 0 +0x008FD1CD 0x7A6A # 0 +0x008FD1CE 0x7A6D # 0 +0x008FD1CF 0x7A75 # 0 +0x008FD1D0 0x7A78 # 0 +0x008FD1D1 0x7A7E # 0 +0x008FD1D2 0x7A80 # 0 +0x008FD1D3 0x7A82 # 0 +0x008FD1D4 0x7A85 # 0 +0x008FD1D5 0x7A86 # 0 +0x008FD1D6 0x7A8A # 0 +0x008FD1D7 0x7A8B # 0 +0x008FD1D8 0x7A90 # 0 +0x008FD1D9 0x7A91 # 0 +0x008FD1DA 0x7A94 # 0 +0x008FD1DB 0x7A9E # 0 +0x008FD1DC 0x7AA0 # 0 +0x008FD1DD 0x7AA3 # 0 +0x008FD1DE 0x7AAC # 0 +0x008FD1DF 0x7AB3 # 0 +0x008FD1E0 0x7AB5 # 0 +0x008FD1E1 0x7AB9 # 0 +0x008FD1E2 0x7ABB # 0 +0x008FD1E3 0x7ABC # 0 +0x008FD1E4 0x7AC6 # 0 +0x008FD1E5 0x7AC9 # 0 +0x008FD1E6 0x7ACC # 0 +0x008FD1E7 0x7ACE # 0 +0x008FD1E8 0x7AD1 # 0 +0x008FD1E9 0x7ADB # 0 +0x008FD1EA 0x7AE8 # 0 +0x008FD1EB 0x7AE9 # 0 +0x008FD1EC 0x7AEB # 0 +0x008FD1ED 0x7AEC # 0 +0x008FD1EE 0x7AF1 # 0 +0x008FD1EF 0x7AF4 # 0 +0x008FD1F0 0x7AFB # 0 +0x008FD1F1 0x7AFD # 0 +0x008FD1F2 0x7AFE # 0 +0x008FD1F3 0x7B07 # 0 +0x008FD1F4 0x7B14 # 0 +0x008FD1F5 0x7B1F # 0 +0x008FD1F6 0x7B23 # 0 +0x008FD1F7 0x7B27 # 0 +0x008FD1F8 0x7B29 # 0 +0x008FD1F9 0x7B2A # 0 +0x008FD1FA 0x7B2B # 0 +0x008FD1FB 0x7B2D # 0 +0x008FD1FC 0x7B2E # 0 +0x008FD1FD 0x7B2F # 0 +0x008FD1FE 0x7B30 # 0 +0x008FD2A1 0x7B31 # 0 +0x008FD2A2 0x7B34 # 0 +0x008FD2A3 0x7B3D # 0 +0x008FD2A4 0x7B3F # 0 +0x008FD2A5 0x7B40 # 0 +0x008FD2A6 0x7B41 # 0 +0x008FD2A7 0x7B47 # 0 +0x008FD2A8 0x7B4E # 0 +0x008FD2A9 0x7B55 # 0 +0x008FD2AA 0x7B60 # 0 +0x008FD2AB 0x7B64 # 0 +0x008FD2AC 0x7B66 # 0 +0x008FD2AD 0x7B69 # 0 +0x008FD2AE 0x7B6A # 0 +0x008FD2AF 0x7B6D # 0 +0x008FD2B0 0x7B6F # 0 +0x008FD2B1 0x7B72 # 0 +0x008FD2B2 0x7B73 # 0 +0x008FD2B3 0x7B77 # 0 +0x008FD2B4 0x7B84 # 0 +0x008FD2B5 0x7B89 # 0 +0x008FD2B6 0x7B8E # 0 +0x008FD2B7 0x7B90 # 0 +0x008FD2B8 0x7B91 # 0 +0x008FD2B9 0x7B96 # 0 +0x008FD2BA 0x7B9B # 0 +0x008FD2BB 0x7B9E # 0 +0x008FD2BC 0x7BA0 # 0 +0x008FD2BD 0x7BA5 # 0 +0x008FD2BE 0x7BAC # 0 +0x008FD2BF 0x7BAF # 0 +0x008FD2C0 0x7BB0 # 0 +0x008FD2C1 0x7BB2 # 0 +0x008FD2C2 0x7BB5 # 0 +0x008FD2C3 0x7BB6 # 0 +0x008FD2C4 0x7BBA # 0 +0x008FD2C5 0x7BBB # 0 +0x008FD2C6 0x7BBC # 0 +0x008FD2C7 0x7BBD # 0 +0x008FD2C8 0x7BC2 # 0 +0x008FD2C9 0x7BC5 # 0 +0x008FD2CA 0x7BC8 # 0 +0x008FD2CB 0x7BCA # 0 +0x008FD2CC 0x7BD4 # 0 +0x008FD2CD 0x7BD6 # 0 +0x008FD2CE 0x7BD7 # 0 +0x008FD2CF 0x7BD9 # 0 +0x008FD2D0 0x7BDA # 0 +0x008FD2D1 0x7BDB # 0 +0x008FD2D2 0x7BE8 # 0 +0x008FD2D3 0x7BEA # 0 +0x008FD2D4 0x7BF2 # 0 +0x008FD2D5 0x7BF4 # 0 +0x008FD2D6 0x7BF5 # 0 +0x008FD2D7 0x7BF8 # 0 +0x008FD2D8 0x7BF9 # 0 +0x008FD2D9 0x7BFA # 0 +0x008FD2DA 0x7BFC # 0 +0x008FD2DB 0x7BFE # 0 +0x008FD2DC 0x7C01 # 0 +0x008FD2DD 0x7C02 # 0 +0x008FD2DE 0x7C03 # 0 +0x008FD2DF 0x7C04 # 0 +0x008FD2E0 0x7C06 # 0 +0x008FD2E1 0x7C09 # 0 +0x008FD2E2 0x7C0B # 0 +0x008FD2E3 0x7C0C # 0 +0x008FD2E4 0x7C0E # 0 +0x008FD2E5 0x7C0F # 0 +0x008FD2E6 0x7C19 # 0 +0x008FD2E7 0x7C1B # 0 +0x008FD2E8 0x7C20 # 0 +0x008FD2E9 0x7C25 # 0 +0x008FD2EA 0x7C26 # 0 +0x008FD2EB 0x7C28 # 0 +0x008FD2EC 0x7C2C # 0 +0x008FD2ED 0x7C31 # 0 +0x008FD2EE 0x7C33 # 0 +0x008FD2EF 0x7C34 # 0 +0x008FD2F0 0x7C36 # 0 +0x008FD2F1 0x7C39 # 0 +0x008FD2F2 0x7C3A # 0 +0x008FD2F3 0x7C46 # 0 +0x008FD2F4 0x7C4A # 0 +0x008FD2F5 0x7C55 # 0 +0x008FD2F6 0x7C51 # 0 +0x008FD2F7 0x7C52 # 0 +0x008FD2F8 0x7C53 # 0 +0x008FD2F9 0x7C59 # 0 +0x008FD2FA 0x7C5A # 0 +0x008FD2FB 0x7C5B # 0 +0x008FD2FC 0x7C5C # 0 +0x008FD2FD 0x7C5D # 0 +0x008FD2FE 0x7C5E # 0 +0x008FD3A1 0x7C61 # 0 +0x008FD3A2 0x7C63 # 0 +0x008FD3A3 0x7C67 # 0 +0x008FD3A4 0x7C69 # 0 +0x008FD3A5 0x7C6D # 0 +0x008FD3A6 0x7C6E # 0 +0x008FD3A7 0x7C70 # 0 +0x008FD3A8 0x7C72 # 0 +0x008FD3A9 0x7C79 # 0 +0x008FD3AA 0x7C7C # 0 +0x008FD3AB 0x7C7D # 0 +0x008FD3AC 0x7C86 # 0 +0x008FD3AD 0x7C87 # 0 +0x008FD3AE 0x7C8F # 0 +0x008FD3AF 0x7C94 # 0 +0x008FD3B0 0x7C9E # 0 +0x008FD3B1 0x7CA0 # 0 +0x008FD3B2 0x7CA6 # 0 +0x008FD3B3 0x7CB0 # 0 +0x008FD3B4 0x7CB6 # 0 +0x008FD3B5 0x7CB7 # 0 +0x008FD3B6 0x7CBA # 0 +0x008FD3B7 0x7CBB # 0 +0x008FD3B8 0x7CBC # 0 +0x008FD3B9 0x7CBF # 0 +0x008FD3BA 0x7CC4 # 0 +0x008FD3BB 0x7CC7 # 0 +0x008FD3BC 0x7CC8 # 0 +0x008FD3BD 0x7CC9 # 0 +0x008FD3BE 0x7CCD # 0 +0x008FD3BF 0x7CCF # 0 +0x008FD3C0 0x7CD3 # 0 +0x008FD3C1 0x7CD4 # 0 +0x008FD3C2 0x7CD5 # 0 +0x008FD3C3 0x7CD7 # 0 +0x008FD3C4 0x7CD9 # 0 +0x008FD3C5 0x7CDA # 0 +0x008FD3C6 0x7CDD # 0 +0x008FD3C7 0x7CE6 # 0 +0x008FD3C8 0x7CE9 # 0 +0x008FD3C9 0x7CEB # 0 +0x008FD3CA 0x7CF5 # 0 +0x008FD3CB 0x7D03 # 0 +0x008FD3CC 0x7D07 # 0 +0x008FD3CD 0x7D08 # 0 +0x008FD3CE 0x7D09 # 0 +0x008FD3CF 0x7D0F # 0 +0x008FD3D0 0x7D11 # 0 +0x008FD3D1 0x7D12 # 0 +0x008FD3D2 0x7D13 # 0 +0x008FD3D3 0x7D16 # 0 +0x008FD3D4 0x7D1D # 0 +0x008FD3D5 0x7D1E # 0 +0x008FD3D6 0x7D23 # 0 +0x008FD3D7 0x7D26 # 0 +0x008FD3D8 0x7D2A # 0 +0x008FD3D9 0x7D2D # 0 +0x008FD3DA 0x7D31 # 0 +0x008FD3DB 0x7D3C # 0 +0x008FD3DC 0x7D3D # 0 +0x008FD3DD 0x7D3E # 0 +0x008FD3DE 0x7D40 # 0 +0x008FD3DF 0x7D41 # 0 +0x008FD3E0 0x7D47 # 0 +0x008FD3E1 0x7D48 # 0 +0x008FD3E2 0x7D4D # 0 +0x008FD3E3 0x7D51 # 0 +0x008FD3E4 0x7D53 # 0 +0x008FD3E5 0x7D57 # 0 +0x008FD3E6 0x7D59 # 0 +0x008FD3E7 0x7D5A # 0 +0x008FD3E8 0x7D5C # 0 +0x008FD3E9 0x7D5D # 0 +0x008FD3EA 0x7D65 # 0 +0x008FD3EB 0x7D67 # 0 +0x008FD3EC 0x7D6A # 0 +0x008FD3ED 0x7D70 # 0 +0x008FD3EE 0x7D78 # 0 +0x008FD3EF 0x7D7A # 0 +0x008FD3F0 0x7D7B # 0 +0x008FD3F1 0x7D7F # 0 +0x008FD3F2 0x7D81 # 0 +0x008FD3F3 0x7D82 # 0 +0x008FD3F4 0x7D83 # 0 +0x008FD3F5 0x7D85 # 0 +0x008FD3F6 0x7D86 # 0 +0x008FD3F7 0x7D88 # 0 +0x008FD3F8 0x7D8B # 0 +0x008FD3F9 0x7D8C # 0 +0x008FD3FA 0x7D8D # 0 +0x008FD3FB 0x7D91 # 0 +0x008FD3FC 0x7D96 # 0 +0x008FD3FD 0x7D97 # 0 +0x008FD3FE 0x7D9D # 0 +0x008FD4A1 0x7D9E # 0 +0x008FD4A2 0x7DA6 # 0 +0x008FD4A3 0x7DA7 # 0 +0x008FD4A4 0x7DAA # 0 +0x008FD4A5 0x7DB3 # 0 +0x008FD4A6 0x7DB6 # 0 +0x008FD4A7 0x7DB7 # 0 +0x008FD4A8 0x7DB9 # 0 +0x008FD4A9 0x7DC2 # 0 +0x008FD4AA 0x7DC3 # 0 +0x008FD4AB 0x7DC4 # 0 +0x008FD4AC 0x7DC5 # 0 +0x008FD4AD 0x7DC6 # 0 +0x008FD4AE 0x7DCC # 0 +0x008FD4AF 0x7DCD # 0 +0x008FD4B0 0x7DCE # 0 +0x008FD4B1 0x7DD7 # 0 +0x008FD4B2 0x7DD9 # 0 +0x008FD4B3 0x7E00 # 0 +0x008FD4B4 0x7DE2 # 0 +0x008FD4B5 0x7DE5 # 0 +0x008FD4B6 0x7DE6 # 0 +0x008FD4B7 0x7DEA # 0 +0x008FD4B8 0x7DEB # 0 +0x008FD4B9 0x7DED # 0 +0x008FD4BA 0x7DF1 # 0 +0x008FD4BB 0x7DF5 # 0 +0x008FD4BC 0x7DF6 # 0 +0x008FD4BD 0x7DF9 # 0 +0x008FD4BE 0x7DFA # 0 +0x008FD4BF 0x7E08 # 0 +0x008FD4C0 0x7E10 # 0 +0x008FD4C1 0x7E11 # 0 +0x008FD4C2 0x7E15 # 0 +0x008FD4C3 0x7E17 # 0 +0x008FD4C4 0x7E1C # 0 +0x008FD4C5 0x7E1D # 0 +0x008FD4C6 0x7E20 # 0 +0x008FD4C7 0x7E27 # 0 +0x008FD4C8 0x7E28 # 0 +0x008FD4C9 0x7E2C # 0 +0x008FD4CA 0x7E2D # 0 +0x008FD4CB 0x7E2F # 0 +0x008FD4CC 0x7E33 # 0 +0x008FD4CD 0x7E36 # 0 +0x008FD4CE 0x7E3F # 0 +0x008FD4CF 0x7E44 # 0 +0x008FD4D0 0x7E45 # 0 +0x008FD4D1 0x7E47 # 0 +0x008FD4D2 0x7E4E # 0 +0x008FD4D3 0x7E50 # 0 +0x008FD4D4 0x7E52 # 0 +0x008FD4D5 0x7E58 # 0 +0x008FD4D6 0x7E5F # 0 +0x008FD4D7 0x7E61 # 0 +0x008FD4D8 0x7E62 # 0 +0x008FD4D9 0x7E65 # 0 +0x008FD4DA 0x7E6B # 0 +0x008FD4DB 0x7E6E # 0 +0x008FD4DC 0x7E6F # 0 +0x008FD4DD 0x7E73 # 0 +0x008FD4DE 0x7E78 # 0 +0x008FD4DF 0x7E7E # 0 +0x008FD4E0 0x7E81 # 0 +0x008FD4E1 0x7E86 # 0 +0x008FD4E2 0x7E87 # 0 +0x008FD4E3 0x7E8A # 0 +0x008FD4E4 0x7E8D # 0 +0x008FD4E5 0x7E91 # 0 +0x008FD4E6 0x7E95 # 0 +0x008FD4E7 0x7E98 # 0 +0x008FD4E8 0x7E9A # 0 +0x008FD4E9 0x7E9D # 0 +0x008FD4EA 0x7E9E # 0 +0x008FD4EB 0x7F3C # 0 +0x008FD4EC 0x7F3B # 0 +0x008FD4ED 0x7F3D # 0 +0x008FD4EE 0x7F3E # 0 +0x008FD4EF 0x7F3F # 0 +0x008FD4F0 0x7F43 # 0 +0x008FD4F1 0x7F44 # 0 +0x008FD4F2 0x7F47 # 0 +0x008FD4F3 0x7F4F # 0 +0x008FD4F4 0x7F52 # 0 +0x008FD4F5 0x7F53 # 0 +0x008FD4F6 0x7F5B # 0 +0x008FD4F7 0x7F5C # 0 +0x008FD4F8 0x7F5D # 0 +0x008FD4F9 0x7F61 # 0 +0x008FD4FA 0x7F63 # 0 +0x008FD4FB 0x7F64 # 0 +0x008FD4FC 0x7F65 # 0 +0x008FD4FD 0x7F66 # 0 +0x008FD4FE 0x7F6D # 0 +0x008FD5A1 0x7F71 # 0 +0x008FD5A2 0x7F7D # 0 +0x008FD5A3 0x7F7E # 0 +0x008FD5A4 0x7F7F # 0 +0x008FD5A5 0x7F80 # 0 +0x008FD5A6 0x7F8B # 0 +0x008FD5A7 0x7F8D # 0 +0x008FD5A8 0x7F8F # 0 +0x008FD5A9 0x7F90 # 0 +0x008FD5AA 0x7F91 # 0 +0x008FD5AB 0x7F96 # 0 +0x008FD5AC 0x7F97 # 0 +0x008FD5AD 0x7F9C # 0 +0x008FD5AE 0x7FA1 # 0 +0x008FD5AF 0x7FA2 # 0 +0x008FD5B0 0x7FA6 # 0 +0x008FD5B1 0x7FAA # 0 +0x008FD5B2 0x7FAD # 0 +0x008FD5B3 0x7FB4 # 0 +0x008FD5B4 0x7FBC # 0 +0x008FD5B5 0x7FBF # 0 +0x008FD5B6 0x7FC0 # 0 +0x008FD5B7 0x7FC3 # 0 +0x008FD5B8 0x7FC8 # 0 +0x008FD5B9 0x7FCE # 0 +0x008FD5BA 0x7FCF # 0 +0x008FD5BB 0x7FDB # 0 +0x008FD5BC 0x7FDF # 0 +0x008FD5BD 0x7FE3 # 0 +0x008FD5BE 0x7FE5 # 0 +0x008FD5BF 0x7FE8 # 0 +0x008FD5C0 0x7FEC # 0 +0x008FD5C1 0x7FEE # 0 +0x008FD5C2 0x7FEF # 0 +0x008FD5C3 0x7FF2 # 0 +0x008FD5C4 0x7FFA # 0 +0x008FD5C5 0x7FFD # 0 +0x008FD5C6 0x7FFE # 0 +0x008FD5C7 0x7FFF # 0 +0x008FD5C8 0x8007 # 0 +0x008FD5C9 0x8008 # 0 +0x008FD5CA 0x800A # 0 +0x008FD5CB 0x800D # 0 +0x008FD5CC 0x800E # 0 +0x008FD5CD 0x800F # 0 +0x008FD5CE 0x8011 # 0 +0x008FD5CF 0x8013 # 0 +0x008FD5D0 0x8014 # 0 +0x008FD5D1 0x8016 # 0 +0x008FD5D2 0x801D # 0 +0x008FD5D3 0x801E # 0 +0x008FD5D4 0x801F # 0 +0x008FD5D5 0x8020 # 0 +0x008FD5D6 0x8024 # 0 +0x008FD5D7 0x8026 # 0 +0x008FD5D8 0x802C # 0 +0x008FD5D9 0x802E # 0 +0x008FD5DA 0x8030 # 0 +0x008FD5DB 0x8034 # 0 +0x008FD5DC 0x8035 # 0 +0x008FD5DD 0x8037 # 0 +0x008FD5DE 0x8039 # 0 +0x008FD5DF 0x803A # 0 +0x008FD5E0 0x803C # 0 +0x008FD5E1 0x803E # 0 +0x008FD5E2 0x8040 # 0 +0x008FD5E3 0x8044 # 0 +0x008FD5E4 0x8060 # 0 +0x008FD5E5 0x8064 # 0 +0x008FD5E6 0x8066 # 0 +0x008FD5E7 0x806D # 0 +0x008FD5E8 0x8071 # 0 +0x008FD5E9 0x8075 # 0 +0x008FD5EA 0x8081 # 0 +0x008FD5EB 0x8088 # 0 +0x008FD5EC 0x808E # 0 +0x008FD5ED 0x809C # 0 +0x008FD5EE 0x809E # 0 +0x008FD5EF 0x80A6 # 0 +0x008FD5F0 0x80A7 # 0 +0x008FD5F1 0x80AB # 0 +0x008FD5F2 0x80B8 # 0 +0x008FD5F3 0x80B9 # 0 +0x008FD5F4 0x80C8 # 0 +0x008FD5F5 0x80CD # 0 +0x008FD5F6 0x80CF # 0 +0x008FD5F7 0x80D2 # 0 +0x008FD5F8 0x80D4 # 0 +0x008FD5F9 0x80D5 # 0 +0x008FD5FA 0x80D7 # 0 +0x008FD5FB 0x80D8 # 0 +0x008FD5FC 0x80E0 # 0 +0x008FD5FD 0x80ED # 0 +0x008FD5FE 0x80EE # 0 +0x008FD6A1 0x80F0 # 0 +0x008FD6A2 0x80F2 # 0 +0x008FD6A3 0x80F3 # 0 +0x008FD6A4 0x80F6 # 0 +0x008FD6A5 0x80F9 # 0 +0x008FD6A6 0x80FA # 0 +0x008FD6A7 0x80FE # 0 +0x008FD6A8 0x8103 # 0 +0x008FD6A9 0x810B # 0 +0x008FD6AA 0x8116 # 0 +0x008FD6AB 0x8117 # 0 +0x008FD6AC 0x8118 # 0 +0x008FD6AD 0x811C # 0 +0x008FD6AE 0x811E # 0 +0x008FD6AF 0x8120 # 0 +0x008FD6B0 0x8124 # 0 +0x008FD6B1 0x8127 # 0 +0x008FD6B2 0x812C # 0 +0x008FD6B3 0x8130 # 0 +0x008FD6B4 0x8135 # 0 +0x008FD6B5 0x813A # 0 +0x008FD6B6 0x813C # 0 +0x008FD6B7 0x8145 # 0 +0x008FD6B8 0x8147 # 0 +0x008FD6B9 0x814A # 0 +0x008FD6BA 0x814C # 0 +0x008FD6BB 0x8152 # 0 +0x008FD6BC 0x8157 # 0 +0x008FD6BD 0x8160 # 0 +0x008FD6BE 0x8161 # 0 +0x008FD6BF 0x8167 # 0 +0x008FD6C0 0x8168 # 0 +0x008FD6C1 0x8169 # 0 +0x008FD6C2 0x816D # 0 +0x008FD6C3 0x816F # 0 +0x008FD6C4 0x8177 # 0 +0x008FD6C5 0x8181 # 0 +0x008FD6C6 0x8190 # 0 +0x008FD6C7 0x8184 # 0 +0x008FD6C8 0x8185 # 0 +0x008FD6C9 0x8186 # 0 +0x008FD6CA 0x818B # 0 +0x008FD6CB 0x818E # 0 +0x008FD6CC 0x8196 # 0 +0x008FD6CD 0x8198 # 0 +0x008FD6CE 0x819B # 0 +0x008FD6CF 0x819E # 0 +0x008FD6D0 0x81A2 # 0 +0x008FD6D1 0x81AE # 0 +0x008FD6D2 0x81B2 # 0 +0x008FD6D3 0x81B4 # 0 +0x008FD6D4 0x81BB # 0 +0x008FD6D5 0x81CB # 0 +0x008FD6D6 0x81C3 # 0 +0x008FD6D7 0x81C5 # 0 +0x008FD6D8 0x81CA # 0 +0x008FD6D9 0x81CE # 0 +0x008FD6DA 0x81CF # 0 +0x008FD6DB 0x81D5 # 0 +0x008FD6DC 0x81D7 # 0 +0x008FD6DD 0x81DB # 0 +0x008FD6DE 0x81DD # 0 +0x008FD6DF 0x81DE # 0 +0x008FD6E0 0x81E1 # 0 +0x008FD6E1 0x81E4 # 0 +0x008FD6E2 0x81EB # 0 +0x008FD6E3 0x81EC # 0 +0x008FD6E4 0x81F0 # 0 +0x008FD6E5 0x81F1 # 0 +0x008FD6E6 0x81F2 # 0 +0x008FD6E7 0x81F5 # 0 +0x008FD6E8 0x81F6 # 0 +0x008FD6E9 0x81F8 # 0 +0x008FD6EA 0x81F9 # 0 +0x008FD6EB 0x81FD # 0 +0x008FD6EC 0x81FF # 0 +0x008FD6ED 0x8200 # 0 +0x008FD6EE 0x8203 # 0 +0x008FD6EF 0x820F # 0 +0x008FD6F0 0x8213 # 0 +0x008FD6F1 0x8214 # 0 +0x008FD6F2 0x8219 # 0 +0x008FD6F3 0x821A # 0 +0x008FD6F4 0x821D # 0 +0x008FD6F5 0x8221 # 0 +0x008FD6F6 0x8222 # 0 +0x008FD6F7 0x8228 # 0 +0x008FD6F8 0x8232 # 0 +0x008FD6F9 0x8234 # 0 +0x008FD6FA 0x823A # 0 +0x008FD6FB 0x8243 # 0 +0x008FD6FC 0x8244 # 0 +0x008FD6FD 0x8245 # 0 +0x008FD6FE 0x8246 # 0 +0x008FD7A1 0x824B # 0 +0x008FD7A2 0x824E # 0 +0x008FD7A3 0x824F # 0 +0x008FD7A4 0x8251 # 0 +0x008FD7A5 0x8256 # 0 +0x008FD7A6 0x825C # 0 +0x008FD7A7 0x8260 # 0 +0x008FD7A8 0x8263 # 0 +0x008FD7A9 0x8267 # 0 +0x008FD7AA 0x826D # 0 +0x008FD7AB 0x8274 # 0 +0x008FD7AC 0x827B # 0 +0x008FD7AD 0x827D # 0 +0x008FD7AE 0x827F # 0 +0x008FD7AF 0x8280 # 0 +0x008FD7B0 0x8281 # 0 +0x008FD7B1 0x8283 # 0 +0x008FD7B2 0x8284 # 0 +0x008FD7B3 0x8287 # 0 +0x008FD7B4 0x8289 # 0 +0x008FD7B5 0x828A # 0 +0x008FD7B6 0x828E # 0 +0x008FD7B7 0x8291 # 0 +0x008FD7B8 0x8294 # 0 +0x008FD7B9 0x8296 # 0 +0x008FD7BA 0x8298 # 0 +0x008FD7BB 0x829A # 0 +0x008FD7BC 0x829B # 0 +0x008FD7BD 0x82A0 # 0 +0x008FD7BE 0x82A1 # 0 +0x008FD7BF 0x82A3 # 0 +0x008FD7C0 0x82A4 # 0 +0x008FD7C1 0x82A7 # 0 +0x008FD7C2 0x82A8 # 0 +0x008FD7C3 0x82A9 # 0 +0x008FD7C4 0x82AA # 0 +0x008FD7C5 0x82AE # 0 +0x008FD7C6 0x82B0 # 0 +0x008FD7C7 0x82B2 # 0 +0x008FD7C8 0x82B4 # 0 +0x008FD7C9 0x82B7 # 0 +0x008FD7CA 0x82BA # 0 +0x008FD7CB 0x82BC # 0 +0x008FD7CC 0x82BE # 0 +0x008FD7CD 0x82BF # 0 +0x008FD7CE 0x82C6 # 0 +0x008FD7CF 0x82D0 # 0 +0x008FD7D0 0x82D5 # 0 +0x008FD7D1 0x82DA # 0 +0x008FD7D2 0x82E0 # 0 +0x008FD7D3 0x82E2 # 0 +0x008FD7D4 0x82E4 # 0 +0x008FD7D5 0x82E8 # 0 +0x008FD7D6 0x82EA # 0 +0x008FD7D7 0x82ED # 0 +0x008FD7D8 0x82EF # 0 +0x008FD7D9 0x82F6 # 0 +0x008FD7DA 0x82F7 # 0 +0x008FD7DB 0x82FD # 0 +0x008FD7DC 0x82FE # 0 +0x008FD7DD 0x8300 # 0 +0x008FD7DE 0x8301 # 0 +0x008FD7DF 0x8307 # 0 +0x008FD7E0 0x8308 # 0 +0x008FD7E1 0x830A # 0 +0x008FD7E2 0x830B # 0 +0x008FD7E3 0x8354 # 0 +0x008FD7E4 0x831B # 0 +0x008FD7E5 0x831D # 0 +0x008FD7E6 0x831E # 0 +0x008FD7E7 0x831F # 0 +0x008FD7E8 0x8321 # 0 +0x008FD7E9 0x8322 # 0 +0x008FD7EA 0x832C # 0 +0x008FD7EB 0x832D # 0 +0x008FD7EC 0x832E # 0 +0x008FD7ED 0x8330 # 0 +0x008FD7EE 0x8333 # 0 +0x008FD7EF 0x8337 # 0 +0x008FD7F0 0x833A # 0 +0x008FD7F1 0x833C # 0 +0x008FD7F2 0x833D # 0 +0x008FD7F3 0x8342 # 0 +0x008FD7F4 0x8343 # 0 +0x008FD7F5 0x8344 # 0 +0x008FD7F6 0x8347 # 0 +0x008FD7F7 0x834D # 0 +0x008FD7F8 0x834E # 0 +0x008FD7F9 0x8351 # 0 +0x008FD7FA 0x8355 # 0 +0x008FD7FB 0x8356 # 0 +0x008FD7FC 0x8357 # 0 +0x008FD7FD 0x8370 # 0 +0x008FD7FE 0x8378 # 0 +0x008FD8A1 0x837D # 0 +0x008FD8A2 0x837F # 0 +0x008FD8A3 0x8380 # 0 +0x008FD8A4 0x8382 # 0 +0x008FD8A5 0x8384 # 0 +0x008FD8A6 0x8386 # 0 +0x008FD8A7 0x838D # 0 +0x008FD8A8 0x8392 # 0 +0x008FD8A9 0x8394 # 0 +0x008FD8AA 0x8395 # 0 +0x008FD8AB 0x8398 # 0 +0x008FD8AC 0x8399 # 0 +0x008FD8AD 0x839B # 0 +0x008FD8AE 0x839C # 0 +0x008FD8AF 0x839D # 0 +0x008FD8B0 0x83A6 # 0 +0x008FD8B1 0x83A7 # 0 +0x008FD8B2 0x83A9 # 0 +0x008FD8B3 0x83AC # 0 +0x008FD8B4 0x83BE # 0 +0x008FD8B5 0x83BF # 0 +0x008FD8B6 0x83C0 # 0 +0x008FD8B7 0x83C7 # 0 +0x008FD8B8 0x83C9 # 0 +0x008FD8B9 0x83CF # 0 +0x008FD8BA 0x83D0 # 0 +0x008FD8BB 0x83D1 # 0 +0x008FD8BC 0x83D4 # 0 +0x008FD8BD 0x83DD # 0 +0x008FD8BE 0x8353 # 0 +0x008FD8BF 0x83E8 # 0 +0x008FD8C0 0x83EA # 0 +0x008FD8C1 0x83F6 # 0 +0x008FD8C2 0x83F8 # 0 +0x008FD8C3 0x83F9 # 0 +0x008FD8C4 0x83FC # 0 +0x008FD8C5 0x8401 # 0 +0x008FD8C6 0x8406 # 0 +0x008FD8C7 0x840A # 0 +0x008FD8C8 0x840F # 0 +0x008FD8C9 0x8411 # 0 +0x008FD8CA 0x8415 # 0 +0x008FD8CB 0x8419 # 0 +0x008FD8CC 0x83AD # 0 +0x008FD8CD 0x842F # 0 +0x008FD8CE 0x8439 # 0 +0x008FD8CF 0x8445 # 0 +0x008FD8D0 0x8447 # 0 +0x008FD8D1 0x8448 # 0 +0x008FD8D2 0x844A # 0 +0x008FD8D3 0x844D # 0 +0x008FD8D4 0x844F # 0 +0x008FD8D5 0x8451 # 0 +0x008FD8D6 0x8452 # 0 +0x008FD8D7 0x8456 # 0 +0x008FD8D8 0x8458 # 0 +0x008FD8D9 0x8459 # 0 +0x008FD8DA 0x845A # 0 +0x008FD8DB 0x845C # 0 +0x008FD8DC 0x8460 # 0 +0x008FD8DD 0x8464 # 0 +0x008FD8DE 0x8465 # 0 +0x008FD8DF 0x8467 # 0 +0x008FD8E0 0x846A # 0 +0x008FD8E1 0x8470 # 0 +0x008FD8E2 0x8473 # 0 +0x008FD8E3 0x8474 # 0 +0x008FD8E4 0x8476 # 0 +0x008FD8E5 0x8478 # 0 +0x008FD8E6 0x847C # 0 +0x008FD8E7 0x847D # 0 +0x008FD8E8 0x8481 # 0 +0x008FD8E9 0x8485 # 0 +0x008FD8EA 0x8492 # 0 +0x008FD8EB 0x8493 # 0 +0x008FD8EC 0x8495 # 0 +0x008FD8ED 0x849E # 0 +0x008FD8EE 0x84A6 # 0 +0x008FD8EF 0x84A8 # 0 +0x008FD8F0 0x84A9 # 0 +0x008FD8F1 0x84AA # 0 +0x008FD8F2 0x84AF # 0 +0x008FD8F3 0x84B1 # 0 +0x008FD8F4 0x84B4 # 0 +0x008FD8F5 0x84BA # 0 +0x008FD8F6 0x84BD # 0 +0x008FD8F7 0x84BE # 0 +0x008FD8F8 0x84C0 # 0 +0x008FD8F9 0x84C2 # 0 +0x008FD8FA 0x84C7 # 0 +0x008FD8FB 0x84C8 # 0 +0x008FD8FC 0x84CC # 0 +0x008FD8FD 0x84CF # 0 +0x008FD8FE 0x84D3 # 0 +0x008FD9A1 0x84DC # 0 +0x008FD9A2 0x84E7 # 0 +0x008FD9A3 0x84EA # 0 +0x008FD9A4 0x84EF # 0 +0x008FD9A5 0x84F0 # 0 +0x008FD9A6 0x84F1 # 0 +0x008FD9A7 0x84F2 # 0 +0x008FD9A8 0x84F7 # 0 +0x008FD9A9 0x8532 # 0 +0x008FD9AA 0x84FA # 0 +0x008FD9AB 0x84FB # 0 +0x008FD9AC 0x84FD # 0 +0x008FD9AD 0x8502 # 0 +0x008FD9AE 0x8503 # 0 +0x008FD9AF 0x8507 # 0 +0x008FD9B0 0x850C # 0 +0x008FD9B1 0x850E # 0 +0x008FD9B2 0x8510 # 0 +0x008FD9B3 0x851C # 0 +0x008FD9B4 0x851E # 0 +0x008FD9B5 0x8522 # 0 +0x008FD9B6 0x8523 # 0 +0x008FD9B7 0x8524 # 0 +0x008FD9B8 0x8525 # 0 +0x008FD9B9 0x8527 # 0 +0x008FD9BA 0x852A # 0 +0x008FD9BB 0x852B # 0 +0x008FD9BC 0x852F # 0 +0x008FD9BD 0x8533 # 0 +0x008FD9BE 0x8534 # 0 +0x008FD9BF 0x8536 # 0 +0x008FD9C0 0x853F # 0 +0x008FD9C1 0x8546 # 0 +0x008FD9C2 0x854F # 0 +0x008FD9C3 0x8550 # 0 +0x008FD9C4 0x8551 # 0 +0x008FD9C5 0x8552 # 0 +0x008FD9C6 0x8553 # 0 +0x008FD9C7 0x8556 # 0 +0x008FD9C8 0x8559 # 0 +0x008FD9C9 0x855C # 0 +0x008FD9CA 0x855D # 0 +0x008FD9CB 0x855E # 0 +0x008FD9CC 0x855F # 0 +0x008FD9CD 0x8560 # 0 +0x008FD9CE 0x8561 # 0 +0x008FD9CF 0x8562 # 0 +0x008FD9D0 0x8564 # 0 +0x008FD9D1 0x856B # 0 +0x008FD9D2 0x856F # 0 +0x008FD9D3 0x8579 # 0 +0x008FD9D4 0x857A # 0 +0x008FD9D5 0x857B # 0 +0x008FD9D6 0x857D # 0 +0x008FD9D7 0x857F # 0 +0x008FD9D8 0x8581 # 0 +0x008FD9D9 0x8585 # 0 +0x008FD9DA 0x8586 # 0 +0x008FD9DB 0x8589 # 0 +0x008FD9DC 0x858B # 0 +0x008FD9DD 0x858C # 0 +0x008FD9DE 0x858F # 0 +0x008FD9DF 0x8593 # 0 +0x008FD9E0 0x8598 # 0 +0x008FD9E1 0x859D # 0 +0x008FD9E2 0x859F # 0 +0x008FD9E3 0x85A0 # 0 +0x008FD9E4 0x85A2 # 0 +0x008FD9E5 0x85A5 # 0 +0x008FD9E6 0x85A7 # 0 +0x008FD9E7 0x85B4 # 0 +0x008FD9E8 0x85B6 # 0 +0x008FD9E9 0x85B7 # 0 +0x008FD9EA 0x85B8 # 0 +0x008FD9EB 0x85BC # 0 +0x008FD9EC 0x85BD # 0 +0x008FD9ED 0x85BE # 0 +0x008FD9EE 0x85BF # 0 +0x008FD9EF 0x85C2 # 0 +0x008FD9F0 0x85C7 # 0 +0x008FD9F1 0x85CA # 0 +0x008FD9F2 0x85CB # 0 +0x008FD9F3 0x85CE # 0 +0x008FD9F4 0x85AD # 0 +0x008FD9F5 0x85D8 # 0 +0x008FD9F6 0x85DA # 0 +0x008FD9F7 0x85DF # 0 +0x008FD9F8 0x85E0 # 0 +0x008FD9F9 0x85E6 # 0 +0x008FD9FA 0x85E8 # 0 +0x008FD9FB 0x85ED # 0 +0x008FD9FC 0x85F3 # 0 +0x008FD9FD 0x85F6 # 0 +0x008FD9FE 0x85FC # 0 +0x008FDAA1 0x85FF # 0 +0x008FDAA2 0x8600 # 0 +0x008FDAA3 0x8604 # 0 +0x008FDAA4 0x8605 # 0 +0x008FDAA5 0x860D # 0 +0x008FDAA6 0x860E # 0 +0x008FDAA7 0x8610 # 0 +0x008FDAA8 0x8611 # 0 +0x008FDAA9 0x8612 # 0 +0x008FDAAA 0x8618 # 0 +0x008FDAAB 0x8619 # 0 +0x008FDAAC 0x861B # 0 +0x008FDAAD 0x861E # 0 +0x008FDAAE 0x8621 # 0 +0x008FDAAF 0x8627 # 0 +0x008FDAB0 0x8629 # 0 +0x008FDAB1 0x8636 # 0 +0x008FDAB2 0x8638 # 0 +0x008FDAB3 0x863A # 0 +0x008FDAB4 0x863C # 0 +0x008FDAB5 0x863D # 0 +0x008FDAB6 0x8640 # 0 +0x008FDAB7 0x8642 # 0 +0x008FDAB8 0x8646 # 0 +0x008FDAB9 0x8652 # 0 +0x008FDABA 0x8653 # 0 +0x008FDABB 0x8656 # 0 +0x008FDABC 0x8657 # 0 +0x008FDABD 0x8658 # 0 +0x008FDABE 0x8659 # 0 +0x008FDABF 0x865D # 0 +0x008FDAC0 0x8660 # 0 +0x008FDAC1 0x8661 # 0 +0x008FDAC2 0x8662 # 0 +0x008FDAC3 0x8663 # 0 +0x008FDAC4 0x8664 # 0 +0x008FDAC5 0x8669 # 0 +0x008FDAC6 0x866C # 0 +0x008FDAC7 0x866F # 0 +0x008FDAC8 0x8675 # 0 +0x008FDAC9 0x8676 # 0 +0x008FDACA 0x8677 # 0 +0x008FDACB 0x867A # 0 +0x008FDACC 0x868D # 0 +0x008FDACD 0x8691 # 0 +0x008FDACE 0x8696 # 0 +0x008FDACF 0x8698 # 0 +0x008FDAD0 0x869A # 0 +0x008FDAD1 0x869C # 0 +0x008FDAD2 0x86A1 # 0 +0x008FDAD3 0x86A6 # 0 +0x008FDAD4 0x86A7 # 0 +0x008FDAD5 0x86A8 # 0 +0x008FDAD6 0x86AD # 0 +0x008FDAD7 0x86B1 # 0 +0x008FDAD8 0x86B3 # 0 +0x008FDAD9 0x86B4 # 0 +0x008FDADA 0x86B5 # 0 +0x008FDADB 0x86B7 # 0 +0x008FDADC 0x86B8 # 0 +0x008FDADD 0x86B9 # 0 +0x008FDADE 0x86BF # 0 +0x008FDADF 0x86C0 # 0 +0x008FDAE0 0x86C1 # 0 +0x008FDAE1 0x86C3 # 0 +0x008FDAE2 0x86C5 # 0 +0x008FDAE3 0x86D1 # 0 +0x008FDAE4 0x86D2 # 0 +0x008FDAE5 0x86D5 # 0 +0x008FDAE6 0x86D7 # 0 +0x008FDAE7 0x86DA # 0 +0x008FDAE8 0x86DC # 0 +0x008FDAE9 0x86E0 # 0 +0x008FDAEA 0x86E3 # 0 +0x008FDAEB 0x86E5 # 0 +0x008FDAEC 0x86E7 # 0 +0x008FDAED 0x8688 # 0 +0x008FDAEE 0x86FA # 0 +0x008FDAEF 0x86FC # 0 +0x008FDAF0 0x86FD # 0 +0x008FDAF1 0x8704 # 0 +0x008FDAF2 0x8705 # 0 +0x008FDAF3 0x8707 # 0 +0x008FDAF4 0x870B # 0 +0x008FDAF5 0x870E # 0 +0x008FDAF6 0x870F # 0 +0x008FDAF7 0x8710 # 0 +0x008FDAF8 0x8713 # 0 +0x008FDAF9 0x8714 # 0 +0x008FDAFA 0x8719 # 0 +0x008FDAFB 0x871E # 0 +0x008FDAFC 0x871F # 0 +0x008FDAFD 0x8721 # 0 +0x008FDAFE 0x8723 # 0 +0x008FDBA1 0x8728 # 0 +0x008FDBA2 0x872E # 0 +0x008FDBA3 0x872F # 0 +0x008FDBA4 0x8731 # 0 +0x008FDBA5 0x8732 # 0 +0x008FDBA6 0x8739 # 0 +0x008FDBA7 0x873A # 0 +0x008FDBA8 0x873C # 0 +0x008FDBA9 0x873D # 0 +0x008FDBAA 0x873E # 0 +0x008FDBAB 0x8740 # 0 +0x008FDBAC 0x8743 # 0 +0x008FDBAD 0x8745 # 0 +0x008FDBAE 0x874D # 0 +0x008FDBAF 0x8758 # 0 +0x008FDBB0 0x875D # 0 +0x008FDBB1 0x8761 # 0 +0x008FDBB2 0x8764 # 0 +0x008FDBB3 0x8765 # 0 +0x008FDBB4 0x876F # 0 +0x008FDBB5 0x8771 # 0 +0x008FDBB6 0x8772 # 0 +0x008FDBB7 0x877B # 0 +0x008FDBB8 0x8783 # 0 +0x008FDBB9 0x8784 # 0 +0x008FDBBA 0x8785 # 0 +0x008FDBBB 0x8786 # 0 +0x008FDBBC 0x8787 # 0 +0x008FDBBD 0x8788 # 0 +0x008FDBBE 0x8789 # 0 +0x008FDBBF 0x878B # 0 +0x008FDBC0 0x878C # 0 +0x008FDBC1 0x8790 # 0 +0x008FDBC2 0x8793 # 0 +0x008FDBC3 0x8795 # 0 +0x008FDBC4 0x8797 # 0 +0x008FDBC5 0x8798 # 0 +0x008FDBC6 0x8799 # 0 +0x008FDBC7 0x879E # 0 +0x008FDBC8 0x87A0 # 0 +0x008FDBC9 0x87A3 # 0 +0x008FDBCA 0x87A7 # 0 +0x008FDBCB 0x87AC # 0 +0x008FDBCC 0x87AD # 0 +0x008FDBCD 0x87AE # 0 +0x008FDBCE 0x87B1 # 0 +0x008FDBCF 0x87B5 # 0 +0x008FDBD0 0x87BE # 0 +0x008FDBD1 0x87BF # 0 +0x008FDBD2 0x87C1 # 0 +0x008FDBD3 0x87C8 # 0 +0x008FDBD4 0x87C9 # 0 +0x008FDBD5 0x87CA # 0 +0x008FDBD6 0x87CE # 0 +0x008FDBD7 0x87D5 # 0 +0x008FDBD8 0x87D6 # 0 +0x008FDBD9 0x87D9 # 0 +0x008FDBDA 0x87DA # 0 +0x008FDBDB 0x87DC # 0 +0x008FDBDC 0x87DF # 0 +0x008FDBDD 0x87E2 # 0 +0x008FDBDE 0x87E3 # 0 +0x008FDBDF 0x87E4 # 0 +0x008FDBE0 0x87EA # 0 +0x008FDBE1 0x87EB # 0 +0x008FDBE2 0x87ED # 0 +0x008FDBE3 0x87F1 # 0 +0x008FDBE4 0x87F3 # 0 +0x008FDBE5 0x87F8 # 0 +0x008FDBE6 0x87FA # 0 +0x008FDBE7 0x87FF # 0 +0x008FDBE8 0x8801 # 0 +0x008FDBE9 0x8803 # 0 +0x008FDBEA 0x8806 # 0 +0x008FDBEB 0x8809 # 0 +0x008FDBEC 0x880A # 0 +0x008FDBED 0x880B # 0 +0x008FDBEE 0x8810 # 0 +0x008FDBEF 0x8819 # 0 +0x008FDBF0 0x8812 # 0 +0x008FDBF1 0x8813 # 0 +0x008FDBF2 0x8814 # 0 +0x008FDBF3 0x8818 # 0 +0x008FDBF4 0x881A # 0 +0x008FDBF5 0x881B # 0 +0x008FDBF6 0x881C # 0 +0x008FDBF7 0x881E # 0 +0x008FDBF8 0x881F # 0 +0x008FDBF9 0x8828 # 0 +0x008FDBFA 0x882D # 0 +0x008FDBFB 0x882E # 0 +0x008FDBFC 0x8830 # 0 +0x008FDBFD 0x8832 # 0 +0x008FDBFE 0x8835 # 0 +0x008FDCA1 0x883A # 0 +0x008FDCA2 0x883C # 0 +0x008FDCA3 0x8841 # 0 +0x008FDCA4 0x8843 # 0 +0x008FDCA5 0x8845 # 0 +0x008FDCA6 0x8848 # 0 +0x008FDCA7 0x8849 # 0 +0x008FDCA8 0x884A # 0 +0x008FDCA9 0x884B # 0 +0x008FDCAA 0x884E # 0 +0x008FDCAB 0x8851 # 0 +0x008FDCAC 0x8855 # 0 +0x008FDCAD 0x8856 # 0 +0x008FDCAE 0x8858 # 0 +0x008FDCAF 0x885A # 0 +0x008FDCB0 0x885C # 0 +0x008FDCB1 0x885F # 0 +0x008FDCB2 0x8860 # 0 +0x008FDCB3 0x8864 # 0 +0x008FDCB4 0x8869 # 0 +0x008FDCB5 0x8871 # 0 +0x008FDCB6 0x8879 # 0 +0x008FDCB7 0x887B # 0 +0x008FDCB8 0x8880 # 0 +0x008FDCB9 0x8898 # 0 +0x008FDCBA 0x889A # 0 +0x008FDCBB 0x889B # 0 +0x008FDCBC 0x889C # 0 +0x008FDCBD 0x889F # 0 +0x008FDCBE 0x88A0 # 0 +0x008FDCBF 0x88A8 # 0 +0x008FDCC0 0x88AA # 0 +0x008FDCC1 0x88BA # 0 +0x008FDCC2 0x88BD # 0 +0x008FDCC3 0x88BE # 0 +0x008FDCC4 0x88C0 # 0 +0x008FDCC5 0x88CA # 0 +0x008FDCC6 0x88CB # 0 +0x008FDCC7 0x88CC # 0 +0x008FDCC8 0x88CD # 0 +0x008FDCC9 0x88CE # 0 +0x008FDCCA 0x88D1 # 0 +0x008FDCCB 0x88D2 # 0 +0x008FDCCC 0x88D3 # 0 +0x008FDCCD 0x88DB # 0 +0x008FDCCE 0x88DE # 0 +0x008FDCCF 0x88E7 # 0 +0x008FDCD0 0x88EF # 0 +0x008FDCD1 0x88F0 # 0 +0x008FDCD2 0x88F1 # 0 +0x008FDCD3 0x88F5 # 0 +0x008FDCD4 0x88F7 # 0 +0x008FDCD5 0x8901 # 0 +0x008FDCD6 0x8906 # 0 +0x008FDCD7 0x890D # 0 +0x008FDCD8 0x890E # 0 +0x008FDCD9 0x890F # 0 +0x008FDCDA 0x8915 # 0 +0x008FDCDB 0x8916 # 0 +0x008FDCDC 0x8918 # 0 +0x008FDCDD 0x8919 # 0 +0x008FDCDE 0x891A # 0 +0x008FDCDF 0x891C # 0 +0x008FDCE0 0x8920 # 0 +0x008FDCE1 0x8926 # 0 +0x008FDCE2 0x8927 # 0 +0x008FDCE3 0x8928 # 0 +0x008FDCE4 0x8930 # 0 +0x008FDCE5 0x8931 # 0 +0x008FDCE6 0x8932 # 0 +0x008FDCE7 0x8935 # 0 +0x008FDCE8 0x8939 # 0 +0x008FDCE9 0x893A # 0 +0x008FDCEA 0x893E # 0 +0x008FDCEB 0x8940 # 0 +0x008FDCEC 0x8942 # 0 +0x008FDCED 0x8945 # 0 +0x008FDCEE 0x8946 # 0 +0x008FDCEF 0x8949 # 0 +0x008FDCF0 0x894F # 0 +0x008FDCF1 0x8952 # 0 +0x008FDCF2 0x8957 # 0 +0x008FDCF3 0x895A # 0 +0x008FDCF4 0x895B # 0 +0x008FDCF5 0x895C # 0 +0x008FDCF6 0x8961 # 0 +0x008FDCF7 0x8962 # 0 +0x008FDCF8 0x8963 # 0 +0x008FDCF9 0x896B # 0 +0x008FDCFA 0x896E # 0 +0x008FDCFB 0x8970 # 0 +0x008FDCFC 0x8973 # 0 +0x008FDCFD 0x8975 # 0 +0x008FDCFE 0x897A # 0 +0x008FDDA1 0x897B # 0 +0x008FDDA2 0x897C # 0 +0x008FDDA3 0x897D # 0 +0x008FDDA4 0x8989 # 0 +0x008FDDA5 0x898D # 0 +0x008FDDA6 0x8990 # 0 +0x008FDDA7 0x8994 # 0 +0x008FDDA8 0x8995 # 0 +0x008FDDA9 0x899B # 0 +0x008FDDAA 0x899C # 0 +0x008FDDAB 0x899F # 0 +0x008FDDAC 0x89A0 # 0 +0x008FDDAD 0x89A5 # 0 +0x008FDDAE 0x89B0 # 0 +0x008FDDAF 0x89B4 # 0 +0x008FDDB0 0x89B5 # 0 +0x008FDDB1 0x89B6 # 0 +0x008FDDB2 0x89B7 # 0 +0x008FDDB3 0x89BC # 0 +0x008FDDB4 0x89D4 # 0 +0x008FDDB5 0x89D5 # 0 +0x008FDDB6 0x89D6 # 0 +0x008FDDB7 0x89D7 # 0 +0x008FDDB8 0x89D8 # 0 +0x008FDDB9 0x89E5 # 0 +0x008FDDBA 0x89E9 # 0 +0x008FDDBB 0x89EB # 0 +0x008FDDBC 0x89ED # 0 +0x008FDDBD 0x89F1 # 0 +0x008FDDBE 0x89F3 # 0 +0x008FDDBF 0x89F6 # 0 +0x008FDDC0 0x89F9 # 0 +0x008FDDC1 0x89FD # 0 +0x008FDDC2 0x89FF # 0 +0x008FDDC3 0x8A04 # 0 +0x008FDDC4 0x8A05 # 0 +0x008FDDC5 0x8A07 # 0 +0x008FDDC6 0x8A0F # 0 +0x008FDDC7 0x8A11 # 0 +0x008FDDC8 0x8A12 # 0 +0x008FDDC9 0x8A14 # 0 +0x008FDDCA 0x8A15 # 0 +0x008FDDCB 0x8A1E # 0 +0x008FDDCC 0x8A20 # 0 +0x008FDDCD 0x8A22 # 0 +0x008FDDCE 0x8A24 # 0 +0x008FDDCF 0x8A26 # 0 +0x008FDDD0 0x8A2B # 0 +0x008FDDD1 0x8A2C # 0 +0x008FDDD2 0x8A2F # 0 +0x008FDDD3 0x8A35 # 0 +0x008FDDD4 0x8A37 # 0 +0x008FDDD5 0x8A3D # 0 +0x008FDDD6 0x8A3E # 0 +0x008FDDD7 0x8A40 # 0 +0x008FDDD8 0x8A43 # 0 +0x008FDDD9 0x8A45 # 0 +0x008FDDDA 0x8A47 # 0 +0x008FDDDB 0x8A49 # 0 +0x008FDDDC 0x8A4D # 0 +0x008FDDDD 0x8A4E # 0 +0x008FDDDE 0x8A53 # 0 +0x008FDDDF 0x8A56 # 0 +0x008FDDE0 0x8A57 # 0 +0x008FDDE1 0x8A58 # 0 +0x008FDDE2 0x8A5C # 0 +0x008FDDE3 0x8A5D # 0 +0x008FDDE4 0x8A61 # 0 +0x008FDDE5 0x8A65 # 0 +0x008FDDE6 0x8A67 # 0 +0x008FDDE7 0x8A75 # 0 +0x008FDDE8 0x8A76 # 0 +0x008FDDE9 0x8A77 # 0 +0x008FDDEA 0x8A79 # 0 +0x008FDDEB 0x8A7A # 0 +0x008FDDEC 0x8A7B # 0 +0x008FDDED 0x8A7E # 0 +0x008FDDEE 0x8A7F # 0 +0x008FDDEF 0x8A80 # 0 +0x008FDDF0 0x8A83 # 0 +0x008FDDF1 0x8A86 # 0 +0x008FDDF2 0x8A8B # 0 +0x008FDDF3 0x8A8F # 0 +0x008FDDF4 0x8A90 # 0 +0x008FDDF5 0x8A92 # 0 +0x008FDDF6 0x8A96 # 0 +0x008FDDF7 0x8A97 # 0 +0x008FDDF8 0x8A99 # 0 +0x008FDDF9 0x8A9F # 0 +0x008FDDFA 0x8AA7 # 0 +0x008FDDFB 0x8AA9 # 0 +0x008FDDFC 0x8AAE # 0 +0x008FDDFD 0x8AAF # 0 +0x008FDDFE 0x8AB3 # 0 +0x008FDEA1 0x8AB6 # 0 +0x008FDEA2 0x8AB7 # 0 +0x008FDEA3 0x8ABB # 0 +0x008FDEA4 0x8ABE # 0 +0x008FDEA5 0x8AC3 # 0 +0x008FDEA6 0x8AC6 # 0 +0x008FDEA7 0x8AC8 # 0 +0x008FDEA8 0x8AC9 # 0 +0x008FDEA9 0x8ACA # 0 +0x008FDEAA 0x8AD1 # 0 +0x008FDEAB 0x8AD3 # 0 +0x008FDEAC 0x8AD4 # 0 +0x008FDEAD 0x8AD5 # 0 +0x008FDEAE 0x8AD7 # 0 +0x008FDEAF 0x8ADD # 0 +0x008FDEB0 0x8ADF # 0 +0x008FDEB1 0x8AEC # 0 +0x008FDEB2 0x8AF0 # 0 +0x008FDEB3 0x8AF4 # 0 +0x008FDEB4 0x8AF5 # 0 +0x008FDEB5 0x8AF6 # 0 +0x008FDEB6 0x8AFC # 0 +0x008FDEB7 0x8AFF # 0 +0x008FDEB8 0x8B05 # 0 +0x008FDEB9 0x8B06 # 0 +0x008FDEBA 0x8B0B # 0 +0x008FDEBB 0x8B11 # 0 +0x008FDEBC 0x8B1C # 0 +0x008FDEBD 0x8B1E # 0 +0x008FDEBE 0x8B1F # 0 +0x008FDEBF 0x8B0A # 0 +0x008FDEC0 0x8B2D # 0 +0x008FDEC1 0x8B30 # 0 +0x008FDEC2 0x8B37 # 0 +0x008FDEC3 0x8B3C # 0 +0x008FDEC4 0x8B42 # 0 +0x008FDEC5 0x8B43 # 0 +0x008FDEC6 0x8B44 # 0 +0x008FDEC7 0x8B45 # 0 +0x008FDEC8 0x8B46 # 0 +0x008FDEC9 0x8B48 # 0 +0x008FDECA 0x8B52 # 0 +0x008FDECB 0x8B53 # 0 +0x008FDECC 0x8B54 # 0 +0x008FDECD 0x8B59 # 0 +0x008FDECE 0x8B4D # 0 +0x008FDECF 0x8B5E # 0 +0x008FDED0 0x8B63 # 0 +0x008FDED1 0x8B6D # 0 +0x008FDED2 0x8B76 # 0 +0x008FDED3 0x8B78 # 0 +0x008FDED4 0x8B79 # 0 +0x008FDED5 0x8B7C # 0 +0x008FDED6 0x8B7E # 0 +0x008FDED7 0x8B81 # 0 +0x008FDED8 0x8B84 # 0 +0x008FDED9 0x8B85 # 0 +0x008FDEDA 0x8B8B # 0 +0x008FDEDB 0x8B8D # 0 +0x008FDEDC 0x8B8F # 0 +0x008FDEDD 0x8B94 # 0 +0x008FDEDE 0x8B95 # 0 +0x008FDEDF 0x8B9C # 0 +0x008FDEE0 0x8B9E # 0 +0x008FDEE1 0x8B9F # 0 +0x008FDEE2 0x8C38 # 0 +0x008FDEE3 0x8C39 # 0 +0x008FDEE4 0x8C3D # 0 +0x008FDEE5 0x8C3E # 0 +0x008FDEE6 0x8C45 # 0 +0x008FDEE7 0x8C47 # 0 +0x008FDEE8 0x8C49 # 0 +0x008FDEE9 0x8C4B # 0 +0x008FDEEA 0x8C4F # 0 +0x008FDEEB 0x8C51 # 0 +0x008FDEEC 0x8C53 # 0 +0x008FDEED 0x8C54 # 0 +0x008FDEEE 0x8C57 # 0 +0x008FDEEF 0x8C58 # 0 +0x008FDEF0 0x8C5B # 0 +0x008FDEF1 0x8C5D # 0 +0x008FDEF2 0x8C59 # 0 +0x008FDEF3 0x8C63 # 0 +0x008FDEF4 0x8C64 # 0 +0x008FDEF5 0x8C66 # 0 +0x008FDEF6 0x8C68 # 0 +0x008FDEF7 0x8C69 # 0 +0x008FDEF8 0x8C6D # 0 +0x008FDEF9 0x8C73 # 0 +0x008FDEFA 0x8C75 # 0 +0x008FDEFB 0x8C76 # 0 +0x008FDEFC 0x8C7B # 0 +0x008FDEFD 0x8C7E # 0 +0x008FDEFE 0x8C86 # 0 +0x008FDFA1 0x8C87 # 0 +0x008FDFA2 0x8C8B # 0 +0x008FDFA3 0x8C90 # 0 +0x008FDFA4 0x8C92 # 0 +0x008FDFA5 0x8C93 # 0 +0x008FDFA6 0x8C99 # 0 +0x008FDFA7 0x8C9B # 0 +0x008FDFA8 0x8C9C # 0 +0x008FDFA9 0x8CA4 # 0 +0x008FDFAA 0x8CB9 # 0 +0x008FDFAB 0x8CBA # 0 +0x008FDFAC 0x8CC5 # 0 +0x008FDFAD 0x8CC6 # 0 +0x008FDFAE 0x8CC9 # 0 +0x008FDFAF 0x8CCB # 0 +0x008FDFB0 0x8CCF # 0 +0x008FDFB1 0x8CD6 # 0 +0x008FDFB2 0x8CD5 # 0 +0x008FDFB3 0x8CD9 # 0 +0x008FDFB4 0x8CDD # 0 +0x008FDFB5 0x8CE1 # 0 +0x008FDFB6 0x8CE8 # 0 +0x008FDFB7 0x8CEC # 0 +0x008FDFB8 0x8CEF # 0 +0x008FDFB9 0x8CF0 # 0 +0x008FDFBA 0x8CF2 # 0 +0x008FDFBB 0x8CF5 # 0 +0x008FDFBC 0x8CF7 # 0 +0x008FDFBD 0x8CF8 # 0 +0x008FDFBE 0x8CFE # 0 +0x008FDFBF 0x8CFF # 0 +0x008FDFC0 0x8D01 # 0 +0x008FDFC1 0x8D03 # 0 +0x008FDFC2 0x8D09 # 0 +0x008FDFC3 0x8D12 # 0 +0x008FDFC4 0x8D17 # 0 +0x008FDFC5 0x8D1B # 0 +0x008FDFC6 0x8D65 # 0 +0x008FDFC7 0x8D69 # 0 +0x008FDFC8 0x8D6C # 0 +0x008FDFC9 0x8D6E # 0 +0x008FDFCA 0x8D7F # 0 +0x008FDFCB 0x8D82 # 0 +0x008FDFCC 0x8D84 # 0 +0x008FDFCD 0x8D88 # 0 +0x008FDFCE 0x8D8D # 0 +0x008FDFCF 0x8D90 # 0 +0x008FDFD0 0x8D91 # 0 +0x008FDFD1 0x8D95 # 0 +0x008FDFD2 0x8D9E # 0 +0x008FDFD3 0x8D9F # 0 +0x008FDFD4 0x8DA0 # 0 +0x008FDFD5 0x8DA6 # 0 +0x008FDFD6 0x8DAB # 0 +0x008FDFD7 0x8DAC # 0 +0x008FDFD8 0x8DAF # 0 +0x008FDFD9 0x8DB2 # 0 +0x008FDFDA 0x8DB5 # 0 +0x008FDFDB 0x8DB7 # 0 +0x008FDFDC 0x8DB9 # 0 +0x008FDFDD 0x8DBB # 0 +0x008FDFDE 0x8DC0 # 0 +0x008FDFDF 0x8DC5 # 0 +0x008FDFE0 0x8DC6 # 0 +0x008FDFE1 0x8DC7 # 0 +0x008FDFE2 0x8DC8 # 0 +0x008FDFE3 0x8DCA # 0 +0x008FDFE4 0x8DCE # 0 +0x008FDFE5 0x8DD1 # 0 +0x008FDFE6 0x8DD4 # 0 +0x008FDFE7 0x8DD5 # 0 +0x008FDFE8 0x8DD7 # 0 +0x008FDFE9 0x8DD9 # 0 +0x008FDFEA 0x8DE4 # 0 +0x008FDFEB 0x8DE5 # 0 +0x008FDFEC 0x8DE7 # 0 +0x008FDFED 0x8DEC # 0 +0x008FDFEE 0x8DF0 # 0 +0x008FDFEF 0x8DBC # 0 +0x008FDFF0 0x8DF1 # 0 +0x008FDFF1 0x8DF2 # 0 +0x008FDFF2 0x8DF4 # 0 +0x008FDFF3 0x8DFD # 0 +0x008FDFF4 0x8E01 # 0 +0x008FDFF5 0x8E04 # 0 +0x008FDFF6 0x8E05 # 0 +0x008FDFF7 0x8E06 # 0 +0x008FDFF8 0x8E0B # 0 +0x008FDFF9 0x8E11 # 0 +0x008FDFFA 0x8E14 # 0 +0x008FDFFB 0x8E16 # 0 +0x008FDFFC 0x8E20 # 0 +0x008FDFFD 0x8E21 # 0 +0x008FDFFE 0x8E22 # 0 +0x008FE0A1 0x8E23 # 0 +0x008FE0A2 0x8E26 # 0 +0x008FE0A3 0x8E27 # 0 +0x008FE0A4 0x8E31 # 0 +0x008FE0A5 0x8E33 # 0 +0x008FE0A6 0x8E36 # 0 +0x008FE0A7 0x8E37 # 0 +0x008FE0A8 0x8E38 # 0 +0x008FE0A9 0x8E39 # 0 +0x008FE0AA 0x8E3D # 0 +0x008FE0AB 0x8E40 # 0 +0x008FE0AC 0x8E41 # 0 +0x008FE0AD 0x8E4B # 0 +0x008FE0AE 0x8E4D # 0 +0x008FE0AF 0x8E4E # 0 +0x008FE0B0 0x8E4F # 0 +0x008FE0B1 0x8E54 # 0 +0x008FE0B2 0x8E5B # 0 +0x008FE0B3 0x8E5C # 0 +0x008FE0B4 0x8E5D # 0 +0x008FE0B5 0x8E5E # 0 +0x008FE0B6 0x8E61 # 0 +0x008FE0B7 0x8E62 # 0 +0x008FE0B8 0x8E69 # 0 +0x008FE0B9 0x8E6C # 0 +0x008FE0BA 0x8E6D # 0 +0x008FE0BB 0x8E6F # 0 +0x008FE0BC 0x8E70 # 0 +0x008FE0BD 0x8E71 # 0 +0x008FE0BE 0x8E79 # 0 +0x008FE0BF 0x8E7A # 0 +0x008FE0C0 0x8E7B # 0 +0x008FE0C1 0x8E82 # 0 +0x008FE0C2 0x8E83 # 0 +0x008FE0C3 0x8E89 # 0 +0x008FE0C4 0x8E90 # 0 +0x008FE0C5 0x8E92 # 0 +0x008FE0C6 0x8E95 # 0 +0x008FE0C7 0x8E9A # 0 +0x008FE0C8 0x8E9B # 0 +0x008FE0C9 0x8E9D # 0 +0x008FE0CA 0x8E9E # 0 +0x008FE0CB 0x8EA2 # 0 +0x008FE0CC 0x8EA7 # 0 +0x008FE0CD 0x8EA9 # 0 +0x008FE0CE 0x8EAD # 0 +0x008FE0CF 0x8EAE # 0 +0x008FE0D0 0x8EB3 # 0 +0x008FE0D1 0x8EB5 # 0 +0x008FE0D2 0x8EBA # 0 +0x008FE0D3 0x8EBB # 0 +0x008FE0D4 0x8EC0 # 0 +0x008FE0D5 0x8EC1 # 0 +0x008FE0D6 0x8EC3 # 0 +0x008FE0D7 0x8EC4 # 0 +0x008FE0D8 0x8EC7 # 0 +0x008FE0D9 0x8ECF # 0 +0x008FE0DA 0x8ED1 # 0 +0x008FE0DB 0x8ED4 # 0 +0x008FE0DC 0x8EDC # 0 +0x008FE0DD 0x8EE8 # 0 +0x008FE0DE 0x8EEE # 0 +0x008FE0DF 0x8EF0 # 0 +0x008FE0E0 0x8EF1 # 0 +0x008FE0E1 0x8EF7 # 0 +0x008FE0E2 0x8EF9 # 0 +0x008FE0E3 0x8EFA # 0 +0x008FE0E4 0x8EED # 0 +0x008FE0E5 0x8F00 # 0 +0x008FE0E6 0x8F02 # 0 +0x008FE0E7 0x8F07 # 0 +0x008FE0E8 0x8F08 # 0 +0x008FE0E9 0x8F0F # 0 +0x008FE0EA 0x8F10 # 0 +0x008FE0EB 0x8F16 # 0 +0x008FE0EC 0x8F17 # 0 +0x008FE0ED 0x8F18 # 0 +0x008FE0EE 0x8F1E # 0 +0x008FE0EF 0x8F20 # 0 +0x008FE0F0 0x8F21 # 0 +0x008FE0F1 0x8F23 # 0 +0x008FE0F2 0x8F25 # 0 +0x008FE0F3 0x8F27 # 0 +0x008FE0F4 0x8F28 # 0 +0x008FE0F5 0x8F2C # 0 +0x008FE0F6 0x8F2D # 0 +0x008FE0F7 0x8F2E # 0 +0x008FE0F8 0x8F34 # 0 +0x008FE0F9 0x8F35 # 0 +0x008FE0FA 0x8F36 # 0 +0x008FE0FB 0x8F37 # 0 +0x008FE0FC 0x8F3A # 0 +0x008FE0FD 0x8F40 # 0 +0x008FE0FE 0x8F41 # 0 +0x008FE1A1 0x8F43 # 0 +0x008FE1A2 0x8F47 # 0 +0x008FE1A3 0x8F4F # 0 +0x008FE1A4 0x8F51 # 0 +0x008FE1A5 0x8F52 # 0 +0x008FE1A6 0x8F53 # 0 +0x008FE1A7 0x8F54 # 0 +0x008FE1A8 0x8F55 # 0 +0x008FE1A9 0x8F58 # 0 +0x008FE1AA 0x8F5D # 0 +0x008FE1AB 0x8F5E # 0 +0x008FE1AC 0x8F65 # 0 +0x008FE1AD 0x8F9D # 0 +0x008FE1AE 0x8FA0 # 0 +0x008FE1AF 0x8FA1 # 0 +0x008FE1B0 0x8FA4 # 0 +0x008FE1B1 0x8FA5 # 0 +0x008FE1B2 0x8FA6 # 0 +0x008FE1B3 0x8FB5 # 0 +0x008FE1B4 0x8FB6 # 0 +0x008FE1B5 0x8FB8 # 0 +0x008FE1B6 0x8FBE # 0 +0x008FE1B7 0x8FC0 # 0 +0x008FE1B8 0x8FC1 # 0 +0x008FE1B9 0x8FC6 # 0 +0x008FE1BA 0x8FCA # 0 +0x008FE1BB 0x8FCB # 0 +0x008FE1BC 0x8FCD # 0 +0x008FE1BD 0x8FD0 # 0 +0x008FE1BE 0x8FD2 # 0 +0x008FE1BF 0x8FD3 # 0 +0x008FE1C0 0x8FD5 # 0 +0x008FE1C1 0x8FE0 # 0 +0x008FE1C2 0x8FE3 # 0 +0x008FE1C3 0x8FE4 # 0 +0x008FE1C4 0x8FE8 # 0 +0x008FE1C5 0x8FEE # 0 +0x008FE1C6 0x8FF1 # 0 +0x008FE1C7 0x8FF5 # 0 +0x008FE1C8 0x8FF6 # 0 +0x008FE1C9 0x8FFB # 0 +0x008FE1CA 0x8FFE # 0 +0x008FE1CB 0x9002 # 0 +0x008FE1CC 0x9004 # 0 +0x008FE1CD 0x9008 # 0 +0x008FE1CE 0x900C # 0 +0x008FE1CF 0x9018 # 0 +0x008FE1D0 0x901B # 0 +0x008FE1D1 0x9028 # 0 +0x008FE1D2 0x9029 # 0 +0x008FE1D3 0x902F # 0 +0x008FE1D4 0x902A # 0 +0x008FE1D5 0x902C # 0 +0x008FE1D6 0x902D # 0 +0x008FE1D7 0x9033 # 0 +0x008FE1D8 0x9034 # 0 +0x008FE1D9 0x9037 # 0 +0x008FE1DA 0x903F # 0 +0x008FE1DB 0x9043 # 0 +0x008FE1DC 0x9044 # 0 +0x008FE1DD 0x904C # 0 +0x008FE1DE 0x905B # 0 +0x008FE1DF 0x905D # 0 +0x008FE1E0 0x9062 # 0 +0x008FE1E1 0x9066 # 0 +0x008FE1E2 0x9067 # 0 +0x008FE1E3 0x906C # 0 +0x008FE1E4 0x9070 # 0 +0x008FE1E5 0x9074 # 0 +0x008FE1E6 0x9079 # 0 +0x008FE1E7 0x9085 # 0 +0x008FE1E8 0x9088 # 0 +0x008FE1E9 0x908B # 0 +0x008FE1EA 0x908C # 0 +0x008FE1EB 0x908E # 0 +0x008FE1EC 0x9090 # 0 +0x008FE1ED 0x9095 # 0 +0x008FE1EE 0x9097 # 0 +0x008FE1EF 0x9098 # 0 +0x008FE1F0 0x9099 # 0 +0x008FE1F1 0x909B # 0 +0x008FE1F2 0x90A0 # 0 +0x008FE1F3 0x90A1 # 0 +0x008FE1F4 0x90A2 # 0 +0x008FE1F5 0x90A5 # 0 +0x008FE1F6 0x90B0 # 0 +0x008FE1F7 0x90B2 # 0 +0x008FE1F8 0x90B3 # 0 +0x008FE1F9 0x90B4 # 0 +0x008FE1FA 0x90B6 # 0 +0x008FE1FB 0x90BD # 0 +0x008FE1FC 0x90CC # 0 +0x008FE1FD 0x90BE # 0 +0x008FE1FE 0x90C3 # 0 +0x008FE2A1 0x90C4 # 0 +0x008FE2A2 0x90C5 # 0 +0x008FE2A3 0x90C7 # 0 +0x008FE2A4 0x90C8 # 0 +0x008FE2A5 0x90D5 # 0 +0x008FE2A6 0x90D7 # 0 +0x008FE2A7 0x90D8 # 0 +0x008FE2A8 0x90D9 # 0 +0x008FE2A9 0x90DC # 0 +0x008FE2AA 0x90DD # 0 +0x008FE2AB 0x90DF # 0 +0x008FE2AC 0x90E5 # 0 +0x008FE2AD 0x90D2 # 0 +0x008FE2AE 0x90F6 # 0 +0x008FE2AF 0x90EB # 0 +0x008FE2B0 0x90EF # 0 +0x008FE2B1 0x90F0 # 0 +0x008FE2B2 0x90F4 # 0 +0x008FE2B3 0x90FE # 0 +0x008FE2B4 0x90FF # 0 +0x008FE2B5 0x9100 # 0 +0x008FE2B6 0x9104 # 0 +0x008FE2B7 0x9105 # 0 +0x008FE2B8 0x9106 # 0 +0x008FE2B9 0x9108 # 0 +0x008FE2BA 0x910D # 0 +0x008FE2BB 0x9110 # 0 +0x008FE2BC 0x9114 # 0 +0x008FE2BD 0x9116 # 0 +0x008FE2BE 0x9117 # 0 +0x008FE2BF 0x9118 # 0 +0x008FE2C0 0x911A # 0 +0x008FE2C1 0x911C # 0 +0x008FE2C2 0x911E # 0 +0x008FE2C3 0x9120 # 0 +0x008FE2C4 0x9125 # 0 +0x008FE2C5 0x9122 # 0 +0x008FE2C6 0x9123 # 0 +0x008FE2C7 0x9127 # 0 +0x008FE2C8 0x9129 # 0 +0x008FE2C9 0x912E # 0 +0x008FE2CA 0x912F # 0 +0x008FE2CB 0x9131 # 0 +0x008FE2CC 0x9134 # 0 +0x008FE2CD 0x9136 # 0 +0x008FE2CE 0x9137 # 0 +0x008FE2CF 0x9139 # 0 +0x008FE2D0 0x913A # 0 +0x008FE2D1 0x913C # 0 +0x008FE2D2 0x913D # 0 +0x008FE2D3 0x9143 # 0 +0x008FE2D4 0x9147 # 0 +0x008FE2D5 0x9148 # 0 +0x008FE2D6 0x914F # 0 +0x008FE2D7 0x9153 # 0 +0x008FE2D8 0x9157 # 0 +0x008FE2D9 0x9159 # 0 +0x008FE2DA 0x915A # 0 +0x008FE2DB 0x915B # 0 +0x008FE2DC 0x9161 # 0 +0x008FE2DD 0x9164 # 0 +0x008FE2DE 0x9167 # 0 +0x008FE2DF 0x916D # 0 +0x008FE2E0 0x9174 # 0 +0x008FE2E1 0x9179 # 0 +0x008FE2E2 0x917A # 0 +0x008FE2E3 0x917B # 0 +0x008FE2E4 0x9181 # 0 +0x008FE2E5 0x9183 # 0 +0x008FE2E6 0x9185 # 0 +0x008FE2E7 0x9186 # 0 +0x008FE2E8 0x918A # 0 +0x008FE2E9 0x918E # 0 +0x008FE2EA 0x9191 # 0 +0x008FE2EB 0x9193 # 0 +0x008FE2EC 0x9194 # 0 +0x008FE2ED 0x9195 # 0 +0x008FE2EE 0x9198 # 0 +0x008FE2EF 0x919E # 0 +0x008FE2F0 0x91A1 # 0 +0x008FE2F1 0x91A6 # 0 +0x008FE2F2 0x91A8 # 0 +0x008FE2F3 0x91AC # 0 +0x008FE2F4 0x91AD # 0 +0x008FE2F5 0x91AE # 0 +0x008FE2F6 0x91B0 # 0 +0x008FE2F7 0x91B1 # 0 +0x008FE2F8 0x91B2 # 0 +0x008FE2F9 0x91B3 # 0 +0x008FE2FA 0x91B6 # 0 +0x008FE2FB 0x91BB # 0 +0x008FE2FC 0x91BC # 0 +0x008FE2FD 0x91BD # 0 +0x008FE2FE 0x91BF # 0 +0x008FE3A1 0x91C2 # 0 +0x008FE3A2 0x91C3 # 0 +0x008FE3A3 0x91C5 # 0 +0x008FE3A4 0x91D3 # 0 +0x008FE3A5 0x91D4 # 0 +0x008FE3A6 0x91D7 # 0 +0x008FE3A7 0x91D9 # 0 +0x008FE3A8 0x91DA # 0 +0x008FE3A9 0x91DE # 0 +0x008FE3AA 0x91E4 # 0 +0x008FE3AB 0x91E5 # 0 +0x008FE3AC 0x91E9 # 0 +0x008FE3AD 0x91EA # 0 +0x008FE3AE 0x91EC # 0 +0x008FE3AF 0x91ED # 0 +0x008FE3B0 0x91EE # 0 +0x008FE3B1 0x91EF # 0 +0x008FE3B2 0x91F0 # 0 +0x008FE3B3 0x91F1 # 0 +0x008FE3B4 0x91F7 # 0 +0x008FE3B5 0x91F9 # 0 +0x008FE3B6 0x91FB # 0 +0x008FE3B7 0x91FD # 0 +0x008FE3B8 0x9200 # 0 +0x008FE3B9 0x9201 # 0 +0x008FE3BA 0x9204 # 0 +0x008FE3BB 0x9205 # 0 +0x008FE3BC 0x9206 # 0 +0x008FE3BD 0x9207 # 0 +0x008FE3BE 0x9209 # 0 +0x008FE3BF 0x920A # 0 +0x008FE3C0 0x920C # 0 +0x008FE3C1 0x9210 # 0 +0x008FE3C2 0x9212 # 0 +0x008FE3C3 0x9213 # 0 +0x008FE3C4 0x9216 # 0 +0x008FE3C5 0x9218 # 0 +0x008FE3C6 0x921C # 0 +0x008FE3C7 0x921D # 0 +0x008FE3C8 0x9223 # 0 +0x008FE3C9 0x9224 # 0 +0x008FE3CA 0x9225 # 0 +0x008FE3CB 0x9226 # 0 +0x008FE3CC 0x9228 # 0 +0x008FE3CD 0x922E # 0 +0x008FE3CE 0x922F # 0 +0x008FE3CF 0x9230 # 0 +0x008FE3D0 0x9233 # 0 +0x008FE3D1 0x9235 # 0 +0x008FE3D2 0x9236 # 0 +0x008FE3D3 0x9238 # 0 +0x008FE3D4 0x9239 # 0 +0x008FE3D5 0x923A # 0 +0x008FE3D6 0x923C # 0 +0x008FE3D7 0x923E # 0 +0x008FE3D8 0x9240 # 0 +0x008FE3D9 0x9242 # 0 +0x008FE3DA 0x9243 # 0 +0x008FE3DB 0x9246 # 0 +0x008FE3DC 0x9247 # 0 +0x008FE3DD 0x924A # 0 +0x008FE3DE 0x924D # 0 +0x008FE3DF 0x924E # 0 +0x008FE3E0 0x924F # 0 +0x008FE3E1 0x9251 # 0 +0x008FE3E2 0x9258 # 0 +0x008FE3E3 0x9259 # 0 +0x008FE3E4 0x925C # 0 +0x008FE3E5 0x925D # 0 +0x008FE3E6 0x9260 # 0 +0x008FE3E7 0x9261 # 0 +0x008FE3E8 0x9265 # 0 +0x008FE3E9 0x9267 # 0 +0x008FE3EA 0x9268 # 0 +0x008FE3EB 0x9269 # 0 +0x008FE3EC 0x926E # 0 +0x008FE3ED 0x926F # 0 +0x008FE3EE 0x9270 # 0 +0x008FE3EF 0x9275 # 0 +0x008FE3F0 0x9276 # 0 +0x008FE3F1 0x9277 # 0 +0x008FE3F2 0x9278 # 0 +0x008FE3F3 0x9279 # 0 +0x008FE3F4 0x927B # 0 +0x008FE3F5 0x927C # 0 +0x008FE3F6 0x927D # 0 +0x008FE3F7 0x927F # 0 +0x008FE3F8 0x9288 # 0 +0x008FE3F9 0x9289 # 0 +0x008FE3FA 0x928A # 0 +0x008FE3FB 0x928D # 0 +0x008FE3FC 0x928E # 0 +0x008FE3FD 0x9292 # 0 +0x008FE3FE 0x9297 # 0 +0x008FE4A1 0x9299 # 0 +0x008FE4A2 0x929F # 0 +0x008FE4A3 0x92A0 # 0 +0x008FE4A4 0x92A4 # 0 +0x008FE4A5 0x92A5 # 0 +0x008FE4A6 0x92A7 # 0 +0x008FE4A7 0x92A8 # 0 +0x008FE4A8 0x92AB # 0 +0x008FE4A9 0x92AF # 0 +0x008FE4AA 0x92B2 # 0 +0x008FE4AB 0x92B6 # 0 +0x008FE4AC 0x92B8 # 0 +0x008FE4AD 0x92BA # 0 +0x008FE4AE 0x92BB # 0 +0x008FE4AF 0x92BC # 0 +0x008FE4B0 0x92BD # 0 +0x008FE4B1 0x92BF # 0 +0x008FE4B2 0x92C0 # 0 +0x008FE4B3 0x92C1 # 0 +0x008FE4B4 0x92C2 # 0 +0x008FE4B5 0x92C3 # 0 +0x008FE4B6 0x92C5 # 0 +0x008FE4B7 0x92C6 # 0 +0x008FE4B8 0x92C7 # 0 +0x008FE4B9 0x92C8 # 0 +0x008FE4BA 0x92CB # 0 +0x008FE4BB 0x92CC # 0 +0x008FE4BC 0x92CD # 0 +0x008FE4BD 0x92CE # 0 +0x008FE4BE 0x92D0 # 0 +0x008FE4BF 0x92D3 # 0 +0x008FE4C0 0x92D5 # 0 +0x008FE4C1 0x92D7 # 0 +0x008FE4C2 0x92D8 # 0 +0x008FE4C3 0x92D9 # 0 +0x008FE4C4 0x92DC # 0 +0x008FE4C5 0x92DD # 0 +0x008FE4C6 0x92DF # 0 +0x008FE4C7 0x92E0 # 0 +0x008FE4C8 0x92E1 # 0 +0x008FE4C9 0x92E3 # 0 +0x008FE4CA 0x92E5 # 0 +0x008FE4CB 0x92E7 # 0 +0x008FE4CC 0x92E8 # 0 +0x008FE4CD 0x92EC # 0 +0x008FE4CE 0x92EE # 0 +0x008FE4CF 0x92F0 # 0 +0x008FE4D0 0x92F9 # 0 +0x008FE4D1 0x92FB # 0 +0x008FE4D2 0x92FF # 0 +0x008FE4D3 0x9300 # 0 +0x008FE4D4 0x9302 # 0 +0x008FE4D5 0x9308 # 0 +0x008FE4D6 0x930D # 0 +0x008FE4D7 0x9311 # 0 +0x008FE4D8 0x9314 # 0 +0x008FE4D9 0x9315 # 0 +0x008FE4DA 0x931C # 0 +0x008FE4DB 0x931D # 0 +0x008FE4DC 0x931E # 0 +0x008FE4DD 0x931F # 0 +0x008FE4DE 0x9321 # 0 +0x008FE4DF 0x9324 # 0 +0x008FE4E0 0x9325 # 0 +0x008FE4E1 0x9327 # 0 +0x008FE4E2 0x9329 # 0 +0x008FE4E3 0x932A # 0 +0x008FE4E4 0x9333 # 0 +0x008FE4E5 0x9334 # 0 +0x008FE4E6 0x9336 # 0 +0x008FE4E7 0x9337 # 0 +0x008FE4E8 0x9347 # 0 +0x008FE4E9 0x9348 # 0 +0x008FE4EA 0x9349 # 0 +0x008FE4EB 0x9350 # 0 +0x008FE4EC 0x9351 # 0 +0x008FE4ED 0x9352 # 0 +0x008FE4EE 0x9355 # 0 +0x008FE4EF 0x9357 # 0 +0x008FE4F0 0x9358 # 0 +0x008FE4F1 0x935A # 0 +0x008FE4F2 0x935E # 0 +0x008FE4F3 0x9364 # 0 +0x008FE4F4 0x9365 # 0 +0x008FE4F5 0x9367 # 0 +0x008FE4F6 0x9369 # 0 +0x008FE4F7 0x936A # 0 +0x008FE4F8 0x936D # 0 +0x008FE4F9 0x936F # 0 +0x008FE4FA 0x9370 # 0 +0x008FE4FB 0x9371 # 0 +0x008FE4FC 0x9373 # 0 +0x008FE4FD 0x9374 # 0 +0x008FE4FE 0x9376 # 0 +0x008FE5A1 0x937A # 0 +0x008FE5A2 0x937D # 0 +0x008FE5A3 0x937F # 0 +0x008FE5A4 0x9380 # 0 +0x008FE5A5 0x9381 # 0 +0x008FE5A6 0x9382 # 0 +0x008FE5A7 0x9388 # 0 +0x008FE5A8 0x938A # 0 +0x008FE5A9 0x938B # 0 +0x008FE5AA 0x938D # 0 +0x008FE5AB 0x938F # 0 +0x008FE5AC 0x9392 # 0 +0x008FE5AD 0x9395 # 0 +0x008FE5AE 0x9398 # 0 +0x008FE5AF 0x939B # 0 +0x008FE5B0 0x939E # 0 +0x008FE5B1 0x93A1 # 0 +0x008FE5B2 0x93A3 # 0 +0x008FE5B3 0x93A4 # 0 +0x008FE5B4 0x93A6 # 0 +0x008FE5B5 0x93A8 # 0 +0x008FE5B6 0x93AB # 0 +0x008FE5B7 0x93B4 # 0 +0x008FE5B8 0x93B5 # 0 +0x008FE5B9 0x93B6 # 0 +0x008FE5BA 0x93BA # 0 +0x008FE5BB 0x93A9 # 0 +0x008FE5BC 0x93C1 # 0 +0x008FE5BD 0x93C4 # 0 +0x008FE5BE 0x93C5 # 0 +0x008FE5BF 0x93C6 # 0 +0x008FE5C0 0x93C7 # 0 +0x008FE5C1 0x93C9 # 0 +0x008FE5C2 0x93CA # 0 +0x008FE5C3 0x93CB # 0 +0x008FE5C4 0x93CC # 0 +0x008FE5C5 0x93CD # 0 +0x008FE5C6 0x93D3 # 0 +0x008FE5C7 0x93D9 # 0 +0x008FE5C8 0x93DC # 0 +0x008FE5C9 0x93DE # 0 +0x008FE5CA 0x93DF # 0 +0x008FE5CB 0x93E2 # 0 +0x008FE5CC 0x93E6 # 0 +0x008FE5CD 0x93E7 # 0 +0x008FE5CE 0x93F9 # 0 +0x008FE5CF 0x93F7 # 0 +0x008FE5D0 0x93F8 # 0 +0x008FE5D1 0x93FA # 0 +0x008FE5D2 0x93FB # 0 +0x008FE5D3 0x93FD # 0 +0x008FE5D4 0x9401 # 0 +0x008FE5D5 0x9402 # 0 +0x008FE5D6 0x9404 # 0 +0x008FE5D7 0x9408 # 0 +0x008FE5D8 0x9409 # 0 +0x008FE5D9 0x940D # 0 +0x008FE5DA 0x940E # 0 +0x008FE5DB 0x940F # 0 +0x008FE5DC 0x9415 # 0 +0x008FE5DD 0x9416 # 0 +0x008FE5DE 0x9417 # 0 +0x008FE5DF 0x941F # 0 +0x008FE5E0 0x942E # 0 +0x008FE5E1 0x942F # 0 +0x008FE5E2 0x9431 # 0 +0x008FE5E3 0x9432 # 0 +0x008FE5E4 0x9433 # 0 +0x008FE5E5 0x9434 # 0 +0x008FE5E6 0x943B # 0 +0x008FE5E7 0x943F # 0 +0x008FE5E8 0x943D # 0 +0x008FE5E9 0x9443 # 0 +0x008FE5EA 0x9445 # 0 +0x008FE5EB 0x9448 # 0 +0x008FE5EC 0x944A # 0 +0x008FE5ED 0x944C # 0 +0x008FE5EE 0x9455 # 0 +0x008FE5EF 0x9459 # 0 +0x008FE5F0 0x945C # 0 +0x008FE5F1 0x945F # 0 +0x008FE5F2 0x9461 # 0 +0x008FE5F3 0x9463 # 0 +0x008FE5F4 0x9468 # 0 +0x008FE5F5 0x946B # 0 +0x008FE5F6 0x946D # 0 +0x008FE5F7 0x946E # 0 +0x008FE5F8 0x946F # 0 +0x008FE5F9 0x9471 # 0 +0x008FE5FA 0x9472 # 0 +0x008FE5FB 0x9484 # 0 +0x008FE5FC 0x9483 # 0 +0x008FE5FD 0x9578 # 0 +0x008FE5FE 0x9579 # 0 +0x008FE6A1 0x957E # 0 +0x008FE6A2 0x9584 # 0 +0x008FE6A3 0x9588 # 0 +0x008FE6A4 0x958C # 0 +0x008FE6A5 0x958D # 0 +0x008FE6A6 0x958E # 0 +0x008FE6A7 0x959D # 0 +0x008FE6A8 0x959E # 0 +0x008FE6A9 0x959F # 0 +0x008FE6AA 0x95A1 # 0 +0x008FE6AB 0x95A6 # 0 +0x008FE6AC 0x95A9 # 0 +0x008FE6AD 0x95AB # 0 +0x008FE6AE 0x95AC # 0 +0x008FE6AF 0x95B4 # 0 +0x008FE6B0 0x95B6 # 0 +0x008FE6B1 0x95BA # 0 +0x008FE6B2 0x95BD # 0 +0x008FE6B3 0x95BF # 0 +0x008FE6B4 0x95C6 # 0 +0x008FE6B5 0x95C8 # 0 +0x008FE6B6 0x95C9 # 0 +0x008FE6B7 0x95CB # 0 +0x008FE6B8 0x95D0 # 0 +0x008FE6B9 0x95D1 # 0 +0x008FE6BA 0x95D2 # 0 +0x008FE6BB 0x95D3 # 0 +0x008FE6BC 0x95D9 # 0 +0x008FE6BD 0x95DA # 0 +0x008FE6BE 0x95DD # 0 +0x008FE6BF 0x95DE # 0 +0x008FE6C0 0x95DF # 0 +0x008FE6C1 0x95E0 # 0 +0x008FE6C2 0x95E4 # 0 +0x008FE6C3 0x95E6 # 0 +0x008FE6C4 0x961D # 0 +0x008FE6C5 0x961E # 0 +0x008FE6C6 0x9622 # 0 +0x008FE6C7 0x9624 # 0 +0x008FE6C8 0x9625 # 0 +0x008FE6C9 0x9626 # 0 +0x008FE6CA 0x962C # 0 +0x008FE6CB 0x9631 # 0 +0x008FE6CC 0x9633 # 0 +0x008FE6CD 0x9637 # 0 +0x008FE6CE 0x9638 # 0 +0x008FE6CF 0x9639 # 0 +0x008FE6D0 0x963A # 0 +0x008FE6D1 0x963C # 0 +0x008FE6D2 0x963D # 0 +0x008FE6D3 0x9641 # 0 +0x008FE6D4 0x9652 # 0 +0x008FE6D5 0x9654 # 0 +0x008FE6D6 0x9656 # 0 +0x008FE6D7 0x9657 # 0 +0x008FE6D8 0x9658 # 0 +0x008FE6D9 0x9661 # 0 +0x008FE6DA 0x966E # 0 +0x008FE6DB 0x9674 # 0 +0x008FE6DC 0x967B # 0 +0x008FE6DD 0x967C # 0 +0x008FE6DE 0x967E # 0 +0x008FE6DF 0x967F # 0 +0x008FE6E0 0x9681 # 0 +0x008FE6E1 0x9682 # 0 +0x008FE6E2 0x9683 # 0 +0x008FE6E3 0x9684 # 0 +0x008FE6E4 0x9689 # 0 +0x008FE6E5 0x9691 # 0 +0x008FE6E6 0x9696 # 0 +0x008FE6E7 0x969A # 0 +0x008FE6E8 0x969D # 0 +0x008FE6E9 0x969F # 0 +0x008FE6EA 0x96A4 # 0 +0x008FE6EB 0x96A5 # 0 +0x008FE6EC 0x96A6 # 0 +0x008FE6ED 0x96A9 # 0 +0x008FE6EE 0x96AE # 0 +0x008FE6EF 0x96AF # 0 +0x008FE6F0 0x96B3 # 0 +0x008FE6F1 0x96BA # 0 +0x008FE6F2 0x96CA # 0 +0x008FE6F3 0x96D2 # 0 +0x008FE6F4 0x5DB2 # 0 +0x008FE6F5 0x96D8 # 0 +0x008FE6F6 0x96DA # 0 +0x008FE6F7 0x96DD # 0 +0x008FE6F8 0x96DE # 0 +0x008FE6F9 0x96DF # 0 +0x008FE6FA 0x96E9 # 0 +0x008FE6FB 0x96EF # 0 +0x008FE6FC 0x96F1 # 0 +0x008FE6FD 0x96FA # 0 +0x008FE6FE 0x9702 # 0 +0x008FE7A1 0x9703 # 0 +0x008FE7A2 0x9705 # 0 +0x008FE7A3 0x9709 # 0 +0x008FE7A4 0x971A # 0 +0x008FE7A5 0x971B # 0 +0x008FE7A6 0x971D # 0 +0x008FE7A7 0x9721 # 0 +0x008FE7A8 0x9722 # 0 +0x008FE7A9 0x9723 # 0 +0x008FE7AA 0x9728 # 0 +0x008FE7AB 0x9731 # 0 +0x008FE7AC 0x9733 # 0 +0x008FE7AD 0x9741 # 0 +0x008FE7AE 0x9743 # 0 +0x008FE7AF 0x974A # 0 +0x008FE7B0 0x974E # 0 +0x008FE7B1 0x974F # 0 +0x008FE7B2 0x9755 # 0 +0x008FE7B3 0x9757 # 0 +0x008FE7B4 0x9758 # 0 +0x008FE7B5 0x975A # 0 +0x008FE7B6 0x975B # 0 +0x008FE7B7 0x9763 # 0 +0x008FE7B8 0x9767 # 0 +0x008FE7B9 0x976A # 0 +0x008FE7BA 0x976E # 0 +0x008FE7BB 0x9773 # 0 +0x008FE7BC 0x9776 # 0 +0x008FE7BD 0x9777 # 0 +0x008FE7BE 0x9778 # 0 +0x008FE7BF 0x977B # 0 +0x008FE7C0 0x977D # 0 +0x008FE7C1 0x977F # 0 +0x008FE7C2 0x9780 # 0 +0x008FE7C3 0x9789 # 0 +0x008FE7C4 0x9795 # 0 +0x008FE7C5 0x9796 # 0 +0x008FE7C6 0x9797 # 0 +0x008FE7C7 0x9799 # 0 +0x008FE7C8 0x979A # 0 +0x008FE7C9 0x979E # 0 +0x008FE7CA 0x979F # 0 +0x008FE7CB 0x97A2 # 0 +0x008FE7CC 0x97AC # 0 +0x008FE7CD 0x97AE # 0 +0x008FE7CE 0x97B1 # 0 +0x008FE7CF 0x97B2 # 0 +0x008FE7D0 0x97B5 # 0 +0x008FE7D1 0x97B6 # 0 +0x008FE7D2 0x97B8 # 0 +0x008FE7D3 0x97B9 # 0 +0x008FE7D4 0x97BA # 0 +0x008FE7D5 0x97BC # 0 +0x008FE7D6 0x97BE # 0 +0x008FE7D7 0x97BF # 0 +0x008FE7D8 0x97C1 # 0 +0x008FE7D9 0x97C4 # 0 +0x008FE7DA 0x97C5 # 0 +0x008FE7DB 0x97C7 # 0 +0x008FE7DC 0x97C9 # 0 +0x008FE7DD 0x97CA # 0 +0x008FE7DE 0x97CC # 0 +0x008FE7DF 0x97CD # 0 +0x008FE7E0 0x97CE # 0 +0x008FE7E1 0x97D0 # 0 +0x008FE7E2 0x97D1 # 0 +0x008FE7E3 0x97D4 # 0 +0x008FE7E4 0x97D7 # 0 +0x008FE7E5 0x97D8 # 0 +0x008FE7E6 0x97D9 # 0 +0x008FE7E7 0x97DD # 0 +0x008FE7E8 0x97DE # 0 +0x008FE7E9 0x97E0 # 0 +0x008FE7EA 0x97DB # 0 +0x008FE7EB 0x97E1 # 0 +0x008FE7EC 0x97E4 # 0 +0x008FE7ED 0x97EF # 0 +0x008FE7EE 0x97F1 # 0 +0x008FE7EF 0x97F4 # 0 +0x008FE7F0 0x97F7 # 0 +0x008FE7F1 0x97F8 # 0 +0x008FE7F2 0x97FA # 0 +0x008FE7F3 0x9807 # 0 +0x008FE7F4 0x980A # 0 +0x008FE7F5 0x9819 # 0 +0x008FE7F6 0x980D # 0 +0x008FE7F7 0x980E # 0 +0x008FE7F8 0x9814 # 0 +0x008FE7F9 0x9816 # 0 +0x008FE7FA 0x981C # 0 +0x008FE7FB 0x981E # 0 +0x008FE7FC 0x9820 # 0 +0x008FE7FD 0x9823 # 0 +0x008FE7FE 0x9826 # 0 +0x008FE8A1 0x982B # 0 +0x008FE8A2 0x982E # 0 +0x008FE8A3 0x982F # 0 +0x008FE8A4 0x9830 # 0 +0x008FE8A5 0x9832 # 0 +0x008FE8A6 0x9833 # 0 +0x008FE8A7 0x9835 # 0 +0x008FE8A8 0x9825 # 0 +0x008FE8A9 0x983E # 0 +0x008FE8AA 0x9844 # 0 +0x008FE8AB 0x9847 # 0 +0x008FE8AC 0x984A # 0 +0x008FE8AD 0x9851 # 0 +0x008FE8AE 0x9852 # 0 +0x008FE8AF 0x9853 # 0 +0x008FE8B0 0x9856 # 0 +0x008FE8B1 0x9857 # 0 +0x008FE8B2 0x9859 # 0 +0x008FE8B3 0x985A # 0 +0x008FE8B4 0x9862 # 0 +0x008FE8B5 0x9863 # 0 +0x008FE8B6 0x9865 # 0 +0x008FE8B7 0x9866 # 0 +0x008FE8B8 0x986A # 0 +0x008FE8B9 0x986C # 0 +0x008FE8BA 0x98AB # 0 +0x008FE8BB 0x98AD # 0 +0x008FE8BC 0x98AE # 0 +0x008FE8BD 0x98B0 # 0 +0x008FE8BE 0x98B4 # 0 +0x008FE8BF 0x98B7 # 0 +0x008FE8C0 0x98B8 # 0 +0x008FE8C1 0x98BA # 0 +0x008FE8C2 0x98BB # 0 +0x008FE8C3 0x98BF # 0 +0x008FE8C4 0x98C2 # 0 +0x008FE8C5 0x98C5 # 0 +0x008FE8C6 0x98C8 # 0 +0x008FE8C7 0x98CC # 0 +0x008FE8C8 0x98E1 # 0 +0x008FE8C9 0x98E3 # 0 +0x008FE8CA 0x98E5 # 0 +0x008FE8CB 0x98E6 # 0 +0x008FE8CC 0x98E7 # 0 +0x008FE8CD 0x98EA # 0 +0x008FE8CE 0x98F3 # 0 +0x008FE8CF 0x98F6 # 0 +0x008FE8D0 0x9902 # 0 +0x008FE8D1 0x9907 # 0 +0x008FE8D2 0x9908 # 0 +0x008FE8D3 0x9911 # 0 +0x008FE8D4 0x9915 # 0 +0x008FE8D5 0x9916 # 0 +0x008FE8D6 0x9917 # 0 +0x008FE8D7 0x991A # 0 +0x008FE8D8 0x991B # 0 +0x008FE8D9 0x991C # 0 +0x008FE8DA 0x991F # 0 +0x008FE8DB 0x9922 # 0 +0x008FE8DC 0x9926 # 0 +0x008FE8DD 0x9927 # 0 +0x008FE8DE 0x992B # 0 +0x008FE8DF 0x9931 # 0 +0x008FE8E0 0x9932 # 0 +0x008FE8E1 0x9933 # 0 +0x008FE8E2 0x9934 # 0 +0x008FE8E3 0x9935 # 0 +0x008FE8E4 0x9939 # 0 +0x008FE8E5 0x993A # 0 +0x008FE8E6 0x993B # 0 +0x008FE8E7 0x993C # 0 +0x008FE8E8 0x9940 # 0 +0x008FE8E9 0x9941 # 0 +0x008FE8EA 0x9946 # 0 +0x008FE8EB 0x9947 # 0 +0x008FE8EC 0x9948 # 0 +0x008FE8ED 0x994D # 0 +0x008FE8EE 0x994E # 0 +0x008FE8EF 0x9954 # 0 +0x008FE8F0 0x9958 # 0 +0x008FE8F1 0x9959 # 0 +0x008FE8F2 0x995B # 0 +0x008FE8F3 0x995C # 0 +0x008FE8F4 0x995E # 0 +0x008FE8F5 0x995F # 0 +0x008FE8F6 0x9960 # 0 +0x008FE8F7 0x999B # 0 +0x008FE8F8 0x999D # 0 +0x008FE8F9 0x999F # 0 +0x008FE8FA 0x99A6 # 0 +0x008FE8FB 0x99B0 # 0 +0x008FE8FC 0x99B1 # 0 +0x008FE8FD 0x99B2 # 0 +0x008FE8FE 0x99B5 # 0 +0x008FE9A1 0x99B9 # 0 +0x008FE9A2 0x99BA # 0 +0x008FE9A3 0x99BD # 0 +0x008FE9A4 0x99BF # 0 +0x008FE9A5 0x99C3 # 0 +0x008FE9A6 0x99C9 # 0 +0x008FE9A7 0x99D3 # 0 +0x008FE9A8 0x99D4 # 0 +0x008FE9A9 0x99D9 # 0 +0x008FE9AA 0x99DA # 0 +0x008FE9AB 0x99DC # 0 +0x008FE9AC 0x99DE # 0 +0x008FE9AD 0x99E7 # 0 +0x008FE9AE 0x99EA # 0 +0x008FE9AF 0x99EB # 0 +0x008FE9B0 0x99EC # 0 +0x008FE9B1 0x99F0 # 0 +0x008FE9B2 0x99F4 # 0 +0x008FE9B3 0x99F5 # 0 +0x008FE9B4 0x99F9 # 0 +0x008FE9B5 0x99FD # 0 +0x008FE9B6 0x99FE # 0 +0x008FE9B7 0x9A02 # 0 +0x008FE9B8 0x9A03 # 0 +0x008FE9B9 0x9A04 # 0 +0x008FE9BA 0x9A0B # 0 +0x008FE9BB 0x9A0C # 0 +0x008FE9BC 0x9A10 # 0 +0x008FE9BD 0x9A11 # 0 +0x008FE9BE 0x9A16 # 0 +0x008FE9BF 0x9A1E # 0 +0x008FE9C0 0x9A20 # 0 +0x008FE9C1 0x9A22 # 0 +0x008FE9C2 0x9A23 # 0 +0x008FE9C3 0x9A24 # 0 +0x008FE9C4 0x9A27 # 0 +0x008FE9C5 0x9A2D # 0 +0x008FE9C6 0x9A2E # 0 +0x008FE9C7 0x9A33 # 0 +0x008FE9C8 0x9A35 # 0 +0x008FE9C9 0x9A36 # 0 +0x008FE9CA 0x9A38 # 0 +0x008FE9CB 0x9A47 # 0 +0x008FE9CC 0x9A41 # 0 +0x008FE9CD 0x9A44 # 0 +0x008FE9CE 0x9A4A # 0 +0x008FE9CF 0x9A4B # 0 +0x008FE9D0 0x9A4C # 0 +0x008FE9D1 0x9A4E # 0 +0x008FE9D2 0x9A51 # 0 +0x008FE9D3 0x9A54 # 0 +0x008FE9D4 0x9A56 # 0 +0x008FE9D5 0x9A5D # 0 +0x008FE9D6 0x9AAA # 0 +0x008FE9D7 0x9AAC # 0 +0x008FE9D8 0x9AAE # 0 +0x008FE9D9 0x9AAF # 0 +0x008FE9DA 0x9AB2 # 0 +0x008FE9DB 0x9AB4 # 0 +0x008FE9DC 0x9AB5 # 0 +0x008FE9DD 0x9AB6 # 0 +0x008FE9DE 0x9AB9 # 0 +0x008FE9DF 0x9ABB # 0 +0x008FE9E0 0x9ABE # 0 +0x008FE9E1 0x9ABF # 0 +0x008FE9E2 0x9AC1 # 0 +0x008FE9E3 0x9AC3 # 0 +0x008FE9E4 0x9AC6 # 0 +0x008FE9E5 0x9AC8 # 0 +0x008FE9E6 0x9ACE # 0 +0x008FE9E7 0x9AD0 # 0 +0x008FE9E8 0x9AD2 # 0 +0x008FE9E9 0x9AD5 # 0 +0x008FE9EA 0x9AD6 # 0 +0x008FE9EB 0x9AD7 # 0 +0x008FE9EC 0x9ADB # 0 +0x008FE9ED 0x9ADC # 0 +0x008FE9EE 0x9AE0 # 0 +0x008FE9EF 0x9AE4 # 0 +0x008FE9F0 0x9AE5 # 0 +0x008FE9F1 0x9AE7 # 0 +0x008FE9F2 0x9AE9 # 0 +0x008FE9F3 0x9AEC # 0 +0x008FE9F4 0x9AF2 # 0 +0x008FE9F5 0x9AF3 # 0 +0x008FE9F6 0x9AF5 # 0 +0x008FE9F7 0x9AF9 # 0 +0x008FE9F8 0x9AFA # 0 +0x008FE9F9 0x9AFD # 0 +0x008FE9FA 0x9AFF # 0 +0x008FE9FB 0x9B00 # 0 +0x008FE9FC 0x9B01 # 0 +0x008FE9FD 0x9B02 # 0 +0x008FE9FE 0x9B03 # 0 +0x008FEAA1 0x9B04 # 0 +0x008FEAA2 0x9B05 # 0 +0x008FEAA3 0x9B08 # 0 +0x008FEAA4 0x9B09 # 0 +0x008FEAA5 0x9B0B # 0 +0x008FEAA6 0x9B0C # 0 +0x008FEAA7 0x9B0D # 0 +0x008FEAA8 0x9B0E # 0 +0x008FEAA9 0x9B10 # 0 +0x008FEAAA 0x9B12 # 0 +0x008FEAAB 0x9B16 # 0 +0x008FEAAC 0x9B19 # 0 +0x008FEAAD 0x9B1B # 0 +0x008FEAAE 0x9B1C # 0 +0x008FEAAF 0x9B20 # 0 +0x008FEAB0 0x9B26 # 0 +0x008FEAB1 0x9B2B # 0 +0x008FEAB2 0x9B2D # 0 +0x008FEAB3 0x9B33 # 0 +0x008FEAB4 0x9B34 # 0 +0x008FEAB5 0x9B35 # 0 +0x008FEAB6 0x9B37 # 0 +0x008FEAB7 0x9B39 # 0 +0x008FEAB8 0x9B3A # 0 +0x008FEAB9 0x9B3D # 0 +0x008FEABA 0x9B48 # 0 +0x008FEABB 0x9B4B # 0 +0x008FEABC 0x9B4C # 0 +0x008FEABD 0x9B55 # 0 +0x008FEABE 0x9B56 # 0 +0x008FEABF 0x9B57 # 0 +0x008FEAC0 0x9B5B # 0 +0x008FEAC1 0x9B5E # 0 +0x008FEAC2 0x9B61 # 0 +0x008FEAC3 0x9B63 # 0 +0x008FEAC4 0x9B65 # 0 +0x008FEAC5 0x9B66 # 0 +0x008FEAC6 0x9B68 # 0 +0x008FEAC7 0x9B6A # 0 +0x008FEAC8 0x9B6B # 0 +0x008FEAC9 0x9B6C # 0 +0x008FEACA 0x9B6D # 0 +0x008FEACB 0x9B6E # 0 +0x008FEACC 0x9B73 # 0 +0x008FEACD 0x9B75 # 0 +0x008FEACE 0x9B77 # 0 +0x008FEACF 0x9B78 # 0 +0x008FEAD0 0x9B79 # 0 +0x008FEAD1 0x9B7F # 0 +0x008FEAD2 0x9B80 # 0 +0x008FEAD3 0x9B84 # 0 +0x008FEAD4 0x9B85 # 0 +0x008FEAD5 0x9B86 # 0 +0x008FEAD6 0x9B87 # 0 +0x008FEAD7 0x9B89 # 0 +0x008FEAD8 0x9B8A # 0 +0x008FEAD9 0x9B8B # 0 +0x008FEADA 0x9B8D # 0 +0x008FEADB 0x9B8F # 0 +0x008FEADC 0x9B90 # 0 +0x008FEADD 0x9B94 # 0 +0x008FEADE 0x9B9A # 0 +0x008FEADF 0x9B9D # 0 +0x008FEAE0 0x9B9E # 0 +0x008FEAE1 0x9BA6 # 0 +0x008FEAE2 0x9BA7 # 0 +0x008FEAE3 0x9BA9 # 0 +0x008FEAE4 0x9BAC # 0 +0x008FEAE5 0x9BB0 # 0 +0x008FEAE6 0x9BB1 # 0 +0x008FEAE7 0x9BB2 # 0 +0x008FEAE8 0x9BB7 # 0 +0x008FEAE9 0x9BB8 # 0 +0x008FEAEA 0x9BBB # 0 +0x008FEAEB 0x9BBC # 0 +0x008FEAEC 0x9BBE # 0 +0x008FEAED 0x9BBF # 0 +0x008FEAEE 0x9BC1 # 0 +0x008FEAEF 0x9BC7 # 0 +0x008FEAF0 0x9BC8 # 0 +0x008FEAF1 0x9BCE # 0 +0x008FEAF2 0x9BD0 # 0 +0x008FEAF3 0x9BD7 # 0 +0x008FEAF4 0x9BD8 # 0 +0x008FEAF5 0x9BDD # 0 +0x008FEAF6 0x9BDF # 0 +0x008FEAF7 0x9BE5 # 0 +0x008FEAF8 0x9BE7 # 0 +0x008FEAF9 0x9BEA # 0 +0x008FEAFA 0x9BEB # 0 +0x008FEAFB 0x9BEF # 0 +0x008FEAFC 0x9BF3 # 0 +0x008FEAFD 0x9BF7 # 0 +0x008FEAFE 0x9BF8 # 0 +0x008FEBA1 0x9BF9 # 0 +0x008FEBA2 0x9BFA # 0 +0x008FEBA3 0x9BFD # 0 +0x008FEBA4 0x9BFF # 0 +0x008FEBA5 0x9C00 # 0 +0x008FEBA6 0x9C02 # 0 +0x008FEBA7 0x9C0B # 0 +0x008FEBA8 0x9C0F # 0 +0x008FEBA9 0x9C11 # 0 +0x008FEBAA 0x9C16 # 0 +0x008FEBAB 0x9C18 # 0 +0x008FEBAC 0x9C19 # 0 +0x008FEBAD 0x9C1A # 0 +0x008FEBAE 0x9C1C # 0 +0x008FEBAF 0x9C1E # 0 +0x008FEBB0 0x9C22 # 0 +0x008FEBB1 0x9C23 # 0 +0x008FEBB2 0x9C26 # 0 +0x008FEBB3 0x9C27 # 0 +0x008FEBB4 0x9C28 # 0 +0x008FEBB5 0x9C29 # 0 +0x008FEBB6 0x9C2A # 0 +0x008FEBB7 0x9C31 # 0 +0x008FEBB8 0x9C35 # 0 +0x008FEBB9 0x9C36 # 0 +0x008FEBBA 0x9C37 # 0 +0x008FEBBB 0x9C3D # 0 +0x008FEBBC 0x9C41 # 0 +0x008FEBBD 0x9C43 # 0 +0x008FEBBE 0x9C44 # 0 +0x008FEBBF 0x9C45 # 0 +0x008FEBC0 0x9C49 # 0 +0x008FEBC1 0x9C4A # 0 +0x008FEBC2 0x9C4E # 0 +0x008FEBC3 0x9C4F # 0 +0x008FEBC4 0x9C50 # 0 +0x008FEBC5 0x9C53 # 0 +0x008FEBC6 0x9C54 # 0 +0x008FEBC7 0x9C56 # 0 +0x008FEBC8 0x9C58 # 0 +0x008FEBC9 0x9C5B # 0 +0x008FEBCA 0x9C5D # 0 +0x008FEBCB 0x9C5E # 0 +0x008FEBCC 0x9C5F # 0 +0x008FEBCD 0x9C63 # 0 +0x008FEBCE 0x9C69 # 0 +0x008FEBCF 0x9C6A # 0 +0x008FEBD0 0x9C5C # 0 +0x008FEBD1 0x9C6B # 0 +0x008FEBD2 0x9C68 # 0 +0x008FEBD3 0x9C6E # 0 +0x008FEBD4 0x9C70 # 0 +0x008FEBD5 0x9C72 # 0 +0x008FEBD6 0x9C75 # 0 +0x008FEBD7 0x9C77 # 0 +0x008FEBD8 0x9C7B # 0 +0x008FEBD9 0x9CE6 # 0 +0x008FEBDA 0x9CF2 # 0 +0x008FEBDB 0x9CF7 # 0 +0x008FEBDC 0x9CF9 # 0 +0x008FEBDD 0x9D0B # 0 +0x008FEBDE 0x9D02 # 0 +0x008FEBDF 0x9D11 # 0 +0x008FEBE0 0x9D17 # 0 +0x008FEBE1 0x9D18 # 0 +0x008FEBE2 0x9D1C # 0 +0x008FEBE3 0x9D1D # 0 +0x008FEBE4 0x9D1E # 0 +0x008FEBE5 0x9D2F # 0 +0x008FEBE6 0x9D30 # 0 +0x008FEBE7 0x9D32 # 0 +0x008FEBE8 0x9D33 # 0 +0x008FEBE9 0x9D34 # 0 +0x008FEBEA 0x9D3A # 0 +0x008FEBEB 0x9D3C # 0 +0x008FEBEC 0x9D45 # 0 +0x008FEBED 0x9D3D # 0 +0x008FEBEE 0x9D42 # 0 +0x008FEBEF 0x9D43 # 0 +0x008FEBF0 0x9D47 # 0 +0x008FEBF1 0x9D4A # 0 +0x008FEBF2 0x9D53 # 0 +0x008FEBF3 0x9D54 # 0 +0x008FEBF4 0x9D5F # 0 +0x008FEBF5 0x9D63 # 0 +0x008FEBF6 0x9D62 # 0 +0x008FEBF7 0x9D65 # 0 +0x008FEBF8 0x9D69 # 0 +0x008FEBF9 0x9D6A # 0 +0x008FEBFA 0x9D6B # 0 +0x008FEBFB 0x9D70 # 0 +0x008FEBFC 0x9D76 # 0 +0x008FEBFD 0x9D77 # 0 +0x008FEBFE 0x9D7B # 0 +0x008FECA1 0x9D7C # 0 +0x008FECA2 0x9D7E # 0 +0x008FECA3 0x9D83 # 0 +0x008FECA4 0x9D84 # 0 +0x008FECA5 0x9D86 # 0 +0x008FECA6 0x9D8A # 0 +0x008FECA7 0x9D8D # 0 +0x008FECA8 0x9D8E # 0 +0x008FECA9 0x9D92 # 0 +0x008FECAA 0x9D93 # 0 +0x008FECAB 0x9D95 # 0 +0x008FECAC 0x9D96 # 0 +0x008FECAD 0x9D97 # 0 +0x008FECAE 0x9D98 # 0 +0x008FECAF 0x9DA1 # 0 +0x008FECB0 0x9DAA # 0 +0x008FECB1 0x9DAC # 0 +0x008FECB2 0x9DAE # 0 +0x008FECB3 0x9DB1 # 0 +0x008FECB4 0x9DB5 # 0 +0x008FECB5 0x9DB9 # 0 +0x008FECB6 0x9DBC # 0 +0x008FECB7 0x9DBF # 0 +0x008FECB8 0x9DC3 # 0 +0x008FECB9 0x9DC7 # 0 +0x008FECBA 0x9DC9 # 0 +0x008FECBB 0x9DCA # 0 +0x008FECBC 0x9DD4 # 0 +0x008FECBD 0x9DD5 # 0 +0x008FECBE 0x9DD6 # 0 +0x008FECBF 0x9DD7 # 0 +0x008FECC0 0x9DDA # 0 +0x008FECC1 0x9DDE # 0 +0x008FECC2 0x9DDF # 0 +0x008FECC3 0x9DE0 # 0 +0x008FECC4 0x9DE5 # 0 +0x008FECC5 0x9DE7 # 0 +0x008FECC6 0x9DE9 # 0 +0x008FECC7 0x9DEB # 0 +0x008FECC8 0x9DEE # 0 +0x008FECC9 0x9DF0 # 0 +0x008FECCA 0x9DF3 # 0 +0x008FECCB 0x9DF4 # 0 +0x008FECCC 0x9DFE # 0 +0x008FECCD 0x9E0A # 0 +0x008FECCE 0x9E02 # 0 +0x008FECCF 0x9E07 # 0 +0x008FECD0 0x9E0E # 0 +0x008FECD1 0x9E10 # 0 +0x008FECD2 0x9E11 # 0 +0x008FECD3 0x9E12 # 0 +0x008FECD4 0x9E15 # 0 +0x008FECD5 0x9E16 # 0 +0x008FECD6 0x9E19 # 0 +0x008FECD7 0x9E1C # 0 +0x008FECD8 0x9E1D # 0 +0x008FECD9 0x9E7A # 0 +0x008FECDA 0x9E7B # 0 +0x008FECDB 0x9E7C # 0 +0x008FECDC 0x9E80 # 0 +0x008FECDD 0x9E82 # 0 +0x008FECDE 0x9E83 # 0 +0x008FECDF 0x9E84 # 0 +0x008FECE0 0x9E85 # 0 +0x008FECE1 0x9E87 # 0 +0x008FECE2 0x9E8E # 0 +0x008FECE3 0x9E8F # 0 +0x008FECE4 0x9E96 # 0 +0x008FECE5 0x9E98 # 0 +0x008FECE6 0x9E9B # 0 +0x008FECE7 0x9E9E # 0 +0x008FECE8 0x9EA4 # 0 +0x008FECE9 0x9EA8 # 0 +0x008FECEA 0x9EAC # 0 +0x008FECEB 0x9EAE # 0 +0x008FECEC 0x9EAF # 0 +0x008FECED 0x9EB0 # 0 +0x008FECEE 0x9EB3 # 0 +0x008FECEF 0x9EB4 # 0 +0x008FECF0 0x9EB5 # 0 +0x008FECF1 0x9EC6 # 0 +0x008FECF2 0x9EC8 # 0 +0x008FECF3 0x9ECB # 0 +0x008FECF4 0x9ED5 # 0 +0x008FECF5 0x9EDF # 0 +0x008FECF6 0x9EE4 # 0 +0x008FECF7 0x9EE7 # 0 +0x008FECF8 0x9EEC # 0 +0x008FECF9 0x9EED # 0 +0x008FECFA 0x9EEE # 0 +0x008FECFB 0x9EF0 # 0 +0x008FECFC 0x9EF1 # 0 +0x008FECFD 0x9EF2 # 0 +0x008FECFE 0x9EF5 # 0 +0x008FEDA1 0x9EF8 # 0 +0x008FEDA2 0x9EFF # 0 +0x008FEDA3 0x9F02 # 0 +0x008FEDA4 0x9F03 # 0 +0x008FEDA5 0x9F09 # 0 +0x008FEDA6 0x9F0F # 0 +0x008FEDA7 0x9F10 # 0 +0x008FEDA8 0x9F11 # 0 +0x008FEDA9 0x9F12 # 0 +0x008FEDAA 0x9F14 # 0 +0x008FEDAB 0x9F16 # 0 +0x008FEDAC 0x9F17 # 0 +0x008FEDAD 0x9F19 # 0 +0x008FEDAE 0x9F1A # 0 +0x008FEDAF 0x9F1B # 0 +0x008FEDB0 0x9F1F # 0 +0x008FEDB1 0x9F22 # 0 +0x008FEDB2 0x9F26 # 0 +0x008FEDB3 0x9F2A # 0 +0x008FEDB4 0x9F2B # 0 +0x008FEDB5 0x9F2F # 0 +0x008FEDB6 0x9F31 # 0 +0x008FEDB7 0x9F32 # 0 +0x008FEDB8 0x9F34 # 0 +0x008FEDB9 0x9F37 # 0 +0x008FEDBA 0x9F39 # 0 +0x008FEDBB 0x9F3A # 0 +0x008FEDBC 0x9F3C # 0 +0x008FEDBD 0x9F3D # 0 +0x008FEDBE 0x9F3F # 0 +0x008FEDBF 0x9F41 # 0 +0x008FEDC0 0x9F43 # 0 +0x008FEDC1 0x9F44 # 0 +0x008FEDC2 0x9F45 # 0 +0x008FEDC3 0x9F46 # 0 +0x008FEDC4 0x9F47 # 0 +0x008FEDC5 0x9F53 # 0 +0x008FEDC6 0x9F55 # 0 +0x008FEDC7 0x9F56 # 0 +0x008FEDC8 0x9F57 # 0 +0x008FEDC9 0x9F58 # 0 +0x008FEDCA 0x9F5A # 0 +0x008FEDCB 0x9F5D # 0 +0x008FEDCC 0x9F5E # 0 +0x008FEDCD 0x9F68 # 0 +0x008FEDCE 0x9F69 # 0 +0x008FEDCF 0x9F6D # 0 +0x008FEDD0 0x9F6E # 0 +0x008FEDD1 0x9F6F # 0 +0x008FEDD2 0x9F70 # 0 +0x008FEDD3 0x9F71 # 0 +0x008FEDD4 0x9F73 # 0 +0x008FEDD5 0x9F75 # 0 +0x008FEDD6 0x9F7A # 0 +0x008FEDD7 0x9F7D # 0 +0x008FEDD8 0x9F8F # 0 +0x008FEDD9 0x9F90 # 0 +0x008FEDDA 0x9F91 # 0 +0x008FEDDB 0x9F92 # 0 +0x008FEDDC 0x9F94 # 0 +0x008FEDDD 0x9F96 # 0 +0x008FEDDE 0x9F97 # 0 +0x008FEDDF 0x9F9E # 0 +0x008FEDE0 0x9FA1 # 0 +0x008FEDE1 0x9FA2 # 0 +0x008FEDE2 0x9FA3 # 0 +0x008FEDE3 0x9FA5 # 0 +0x008FF3F3 0x2170 # 0 +0x008FF3F4 0x2171 # 0 +0x008FF3F5 0x2172 # 0 +0x008FF3F6 0x2173 # 0 +0x008FF3F7 0x2174 # 0 +0x008FF3F8 0x2175 # 0 +0x008FF3F9 0x2176 # 0 +0x008FF3FA 0x2177 # 0 +0x008FF3FB 0x2178 # 0 +0x008FF3FC 0x2179 # 0 +0x008FF4A9 0xFF07 # 0 +0x008FF4AA 0xFF02 # 0 +0x008FF4AE 0x70BB # 0 +0x008FF4AF 0x4EFC # 0 +0x008FF4B0 0x50F4 # 0 +0x008FF4B1 0x51EC # 0 +0x008FF4B2 0x5307 # 0 +0x008FF4B3 0x5324 # 0 +0x008FF4B4 0xFA0E # 0 +0x008FF4B5 0x548A # 0 +0x008FF4B6 0x5759 # 0 +0x008FF4B7 0xFA0F # 0 +0x008FF4B8 0xFA10 # 0 +0x008FF4B9 0x589E # 0 +0x008FF4BA 0x5BEC # 0 +0x008FF4BB 0x5CF5 # 0 +0x008FF4BC 0x5D53 # 0 +0x008FF4BD 0xFA11 # 0 +0x008FF4BE 0x5FB7 # 0 +0x008FF4BF 0x6085 # 0 +0x008FF4C0 0x6120 # 0 +0x008FF4C1 0x654E # 0 +0x008FF4C2 0x663B # 0 +0x008FF4C3 0x6665 # 0 +0x008FF4C4 0xFA12 # 0 +0x008FF4C5 0xF929 # 0 +0x008FF4C6 0x6801 # 0 +0x008FF4C7 0xFA13 # 0 +0x008FF4C8 0xFA14 # 0 +0x008FF4C9 0x6A6B # 0 +0x008FF4CA 0x6AE2 # 0 +0x008FF4CB 0x6DF8 # 0 +0x008FF4CC 0x6DF2 # 0 +0x008FF4CD 0x7028 # 0 +0x008FF4CE 0xFA15 # 0 +0x008FF4CF 0xFA16 # 0 +0x008FF4D0 0x7501 # 0 +0x008FF4D1 0x7682 # 0 +0x008FF4D2 0x769E # 0 +0x008FF4D3 0xFA17 # 0 +0x008FF4D4 0x7930 # 0 +0x008FF4D5 0xFA18 # 0 +0x008FF4D6 0xFA19 # 0 +0x008FF4D7 0xFA1A # 0 +0x008FF4D8 0xFA1B # 0 +0x008FF4D9 0x7AE7 # 0 +0x008FF4DA 0xFA1C # 0 +0x008FF4DB 0xFA1D # 0 +0x008FF4DC 0x7DA0 # 0 +0x008FF4DD 0x7DD6 # 0 +0x008FF4DE 0xFA1E # 0 +0x008FF4DF 0x8362 # 0 +0x008FF4E0 0xFA1F # 0 +0x008FF4E1 0x85B0 # 0 +0x008FF4E2 0xFA20 # 0 +0x008FF4E3 0xFA21 # 0 +0x008FF4E4 0x8807 # 0 +0x008FF4E5 0xFA22 # 0 +0x008FF4E6 0x8B7F # 0 +0x008FF4E7 0x8CF4 # 0 +0x008FF4E8 0x8D76 # 0 +0x008FF4E9 0xFA23 # 0 +0x008FF4EA 0xFA24 # 0 +0x008FF4EB 0xFA25 # 0 +0x008FF4EC 0x90DE # 0 +0x008FF4ED 0xFA26 # 0 +0x008FF4EE 0x9115 # 0 +0x008FF4EF 0xFA27 # 0 +0x008FF4F0 0xFA28 # 0 +0x008FF4F1 0x9592 # 0 +0x008FF4F2 0xF9DC # 0 +0x008FF4F3 0xFA29 # 0 +0x008FF4F4 0x973B # 0 +0x008FF4F5 0x974D # 0 +0x008FF4F6 0x9751 # 0 +0x008FF4F7 0xFA2A # 0 +0x008FF4F8 0xFA2B # 0 +0x008FF4F9 0xFA2C # 0 +0x008FF4FA 0x999E # 0 +0x008FF4FB 0x9AD9 # 0 +0x008FF4FC 0x9B72 # 0 +0x008FF4FD 0xFA2D # 0 +0x008FF4FE 0x9ED1 # 0 +0x008FF5A1 0xE3AC # 0 +0x008FF5A2 0xE3AD # 0 +0x008FF5A3 0xE3AE # 0 +0x008FF5A4 0xE3AF # 0 +0x008FF5A5 0xE3B0 # 0 +0x008FF5A6 0xE3B1 # 0 +0x008FF5A7 0xE3B2 # 0 +0x008FF5A8 0xE3B3 # 0 +0x008FF5A9 0xE3B4 # 0 +0x008FF5AA 0xE3B5 # 0 +0x008FF5AB 0xE3B6 # 0 +0x008FF5AC 0xE3B7 # 0 +0x008FF5AD 0xE3B8 # 0 +0x008FF5AE 0xE3B9 # 0 +0x008FF5AF 0xE3BA # 0 +0x008FF5B0 0xE3BB # 0 +0x008FF5B1 0xE3BC # 0 +0x008FF5B2 0xE3BD # 0 +0x008FF5B3 0xE3BE # 0 +0x008FF5B4 0xE3BF # 0 +0x008FF5B5 0xE3C0 # 0 +0x008FF5B6 0xE3C1 # 0 +0x008FF5B7 0xE3C2 # 0 +0x008FF5B8 0xE3C3 # 0 +0x008FF5B9 0xE3C4 # 0 +0x008FF5BA 0xE3C5 # 0 +0x008FF5BB 0xE3C6 # 0 +0x008FF5BC 0xE3C7 # 0 +0x008FF5BD 0xE3C8 # 0 +0x008FF5BE 0xE3C9 # 0 +0x008FF5BF 0xE3CA # 0 +0x008FF5C0 0xE3CB # 0 +0x008FF5C1 0xE3CC # 0 +0x008FF5C2 0xE3CD # 0 +0x008FF5C3 0xE3CE # 0 +0x008FF5C4 0xE3CF # 0 +0x008FF5C5 0xE3D0 # 0 +0x008FF5C6 0xE3D1 # 0 +0x008FF5C7 0xE3D2 # 0 +0x008FF5C8 0xE3D3 # 0 +0x008FF5C9 0xE3D4 # 0 +0x008FF5CA 0xE3D5 # 0 +0x008FF5CB 0xE3D6 # 0 +0x008FF5CC 0xE3D7 # 0 +0x008FF5CD 0xE3D8 # 0 +0x008FF5CE 0xE3D9 # 0 +0x008FF5CF 0xE3DA # 0 +0x008FF5D0 0xE3DB # 0 +0x008FF5D1 0xE3DC # 0 +0x008FF5D2 0xE3DD # 0 +0x008FF5D3 0xE3DE # 0 +0x008FF5D4 0xE3DF # 0 +0x008FF5D5 0xE3E0 # 0 +0x008FF5D6 0xE3E1 # 0 +0x008FF5D7 0xE3E2 # 0 +0x008FF5D8 0xE3E3 # 0 +0x008FF5D9 0xE3E4 # 0 +0x008FF5DA 0xE3E5 # 0 +0x008FF5DB 0xE3E6 # 0 +0x008FF5DC 0xE3E7 # 0 +0x008FF5DD 0xE3E8 # 0 +0x008FF5DE 0xE3E9 # 0 +0x008FF5DF 0xE3EA # 0 +0x008FF5E0 0xE3EB # 0 +0x008FF5E1 0xE3EC # 0 +0x008FF5E2 0xE3ED # 0 +0x008FF5E3 0xE3EE # 0 +0x008FF5E4 0xE3EF # 0 +0x008FF5E5 0xE3F0 # 0 +0x008FF5E6 0xE3F1 # 0 +0x008FF5E7 0xE3F2 # 0 +0x008FF5E8 0xE3F3 # 0 +0x008FF5E9 0xE3F4 # 0 +0x008FF5EA 0xE3F5 # 0 +0x008FF5EB 0xE3F6 # 0 +0x008FF5EC 0xE3F7 # 0 +0x008FF5ED 0xE3F8 # 0 +0x008FF5EE 0xE3F9 # 0 +0x008FF5EF 0xE3FA # 0 +0x008FF5F0 0xE3FB # 0 +0x008FF5F1 0xE3FC # 0 +0x008FF5F2 0xE3FD # 0 +0x008FF5F3 0xE3FE # 0 +0x008FF5F4 0xE3FF # 0 +0x008FF5F5 0xE400 # 0 +0x008FF5F6 0xE401 # 0 +0x008FF5F7 0xE402 # 0 +0x008FF5F8 0xE403 # 0 +0x008FF5F9 0xE404 # 0 +0x008FF5FA 0xE405 # 0 +0x008FF5FB 0xE406 # 0 +0x008FF5FC 0xE407 # 0 +0x008FF5FD 0xE408 # 0 +0x008FF5FE 0xE409 # 0 +0x008FF6A1 0xE40A # 0 +0x008FF6A2 0xE40B # 0 +0x008FF6A3 0xE40C # 0 +0x008FF6A4 0xE40D # 0 +0x008FF6A5 0xE40E # 0 +0x008FF6A6 0xE40F # 0 +0x008FF6A7 0xE410 # 0 +0x008FF6A8 0xE411 # 0 +0x008FF6A9 0xE412 # 0 +0x008FF6AA 0xE413 # 0 +0x008FF6AB 0xE414 # 0 +0x008FF6AC 0xE415 # 0 +0x008FF6AD 0xE416 # 0 +0x008FF6AE 0xE417 # 0 +0x008FF6AF 0xE418 # 0 +0x008FF6B0 0xE419 # 0 +0x008FF6B1 0xE41A # 0 +0x008FF6B2 0xE41B # 0 +0x008FF6B3 0xE41C # 0 +0x008FF6B4 0xE41D # 0 +0x008FF6B5 0xE41E # 0 +0x008FF6B6 0xE41F # 0 +0x008FF6B7 0xE420 # 0 +0x008FF6B8 0xE421 # 0 +0x008FF6B9 0xE422 # 0 +0x008FF6BA 0xE423 # 0 +0x008FF6BB 0xE424 # 0 +0x008FF6BC 0xE425 # 0 +0x008FF6BD 0xE426 # 0 +0x008FF6BE 0xE427 # 0 +0x008FF6BF 0xE428 # 0 +0x008FF6C0 0xE429 # 0 +0x008FF6C1 0xE42A # 0 +0x008FF6C2 0xE42B # 0 +0x008FF6C3 0xE42C # 0 +0x008FF6C4 0xE42D # 0 +0x008FF6C5 0xE42E # 0 +0x008FF6C6 0xE42F # 0 +0x008FF6C7 0xE430 # 0 +0x008FF6C8 0xE431 # 0 +0x008FF6C9 0xE432 # 0 +0x008FF6CA 0xE433 # 0 +0x008FF6CB 0xE434 # 0 +0x008FF6CC 0xE435 # 0 +0x008FF6CD 0xE436 # 0 +0x008FF6CE 0xE437 # 0 +0x008FF6CF 0xE438 # 0 +0x008FF6D0 0xE439 # 0 +0x008FF6D1 0xE43A # 0 +0x008FF6D2 0xE43B # 0 +0x008FF6D3 0xE43C # 0 +0x008FF6D4 0xE43D # 0 +0x008FF6D5 0xE43E # 0 +0x008FF6D6 0xE43F # 0 +0x008FF6D7 0xE440 # 0 +0x008FF6D8 0xE441 # 0 +0x008FF6D9 0xE442 # 0 +0x008FF6DA 0xE443 # 0 +0x008FF6DB 0xE444 # 0 +0x008FF6DC 0xE445 # 0 +0x008FF6DD 0xE446 # 0 +0x008FF6DE 0xE447 # 0 +0x008FF6DF 0xE448 # 0 +0x008FF6E0 0xE449 # 0 +0x008FF6E1 0xE44A # 0 +0x008FF6E2 0xE44B # 0 +0x008FF6E3 0xE44C # 0 +0x008FF6E4 0xE44D # 0 +0x008FF6E5 0xE44E # 0 +0x008FF6E6 0xE44F # 0 +0x008FF6E7 0xE450 # 0 +0x008FF6E8 0xE451 # 0 +0x008FF6E9 0xE452 # 0 +0x008FF6EA 0xE453 # 0 +0x008FF6EB 0xE454 # 0 +0x008FF6EC 0xE455 # 0 +0x008FF6ED 0xE456 # 0 +0x008FF6EE 0xE457 # 0 +0x008FF6EF 0xE458 # 0 +0x008FF6F0 0xE459 # 0 +0x008FF6F1 0xE45A # 0 +0x008FF6F2 0xE45B # 0 +0x008FF6F3 0xE45C # 0 +0x008FF6F4 0xE45D # 0 +0x008FF6F5 0xE45E # 0 +0x008FF6F6 0xE45F # 0 +0x008FF6F7 0xE460 # 0 +0x008FF6F8 0xE461 # 0 +0x008FF6F9 0xE462 # 0 +0x008FF6FA 0xE463 # 0 +0x008FF6FB 0xE464 # 0 +0x008FF6FC 0xE465 # 0 +0x008FF6FD 0xE466 # 0 +0x008FF6FE 0xE467 # 0 +0x008FF7A1 0xE468 # 0 +0x008FF7A2 0xE469 # 0 +0x008FF7A3 0xE46A # 0 +0x008FF7A4 0xE46B # 0 +0x008FF7A5 0xE46C # 0 +0x008FF7A6 0xE46D # 0 +0x008FF7A7 0xE46E # 0 +0x008FF7A8 0xE46F # 0 +0x008FF7A9 0xE470 # 0 +0x008FF7AA 0xE471 # 0 +0x008FF7AB 0xE472 # 0 +0x008FF7AC 0xE473 # 0 +0x008FF7AD 0xE474 # 0 +0x008FF7AE 0xE475 # 0 +0x008FF7AF 0xE476 # 0 +0x008FF7B0 0xE477 # 0 +0x008FF7B1 0xE478 # 0 +0x008FF7B2 0xE479 # 0 +0x008FF7B3 0xE47A # 0 +0x008FF7B4 0xE47B # 0 +0x008FF7B5 0xE47C # 0 +0x008FF7B6 0xE47D # 0 +0x008FF7B7 0xE47E # 0 +0x008FF7B8 0xE47F # 0 +0x008FF7B9 0xE480 # 0 +0x008FF7BA 0xE481 # 0 +0x008FF7BB 0xE482 # 0 +0x008FF7BC 0xE483 # 0 +0x008FF7BD 0xE484 # 0 +0x008FF7BE 0xE485 # 0 +0x008FF7BF 0xE486 # 0 +0x008FF7C0 0xE487 # 0 +0x008FF7C1 0xE488 # 0 +0x008FF7C2 0xE489 # 0 +0x008FF7C3 0xE48A # 0 +0x008FF7C4 0xE48B # 0 +0x008FF7C5 0xE48C # 0 +0x008FF7C6 0xE48D # 0 +0x008FF7C7 0xE48E # 0 +0x008FF7C8 0xE48F # 0 +0x008FF7C9 0xE490 # 0 +0x008FF7CA 0xE491 # 0 +0x008FF7CB 0xE492 # 0 +0x008FF7CC 0xE493 # 0 +0x008FF7CD 0xE494 # 0 +0x008FF7CE 0xE495 # 0 +0x008FF7CF 0xE496 # 0 +0x008FF7D0 0xE497 # 0 +0x008FF7D1 0xE498 # 0 +0x008FF7D2 0xE499 # 0 +0x008FF7D3 0xE49A # 0 +0x008FF7D4 0xE49B # 0 +0x008FF7D5 0xE49C # 0 +0x008FF7D6 0xE49D # 0 +0x008FF7D7 0xE49E # 0 +0x008FF7D8 0xE49F # 0 +0x008FF7D9 0xE4A0 # 0 +0x008FF7DA 0xE4A1 # 0 +0x008FF7DB 0xE4A2 # 0 +0x008FF7DC 0xE4A3 # 0 +0x008FF7DD 0xE4A4 # 0 +0x008FF7DE 0xE4A5 # 0 +0x008FF7DF 0xE4A6 # 0 +0x008FF7E0 0xE4A7 # 0 +0x008FF7E1 0xE4A8 # 0 +0x008FF7E2 0xE4A9 # 0 +0x008FF7E3 0xE4AA # 0 +0x008FF7E4 0xE4AB # 0 +0x008FF7E5 0xE4AC # 0 +0x008FF7E6 0xE4AD # 0 +0x008FF7E7 0xE4AE # 0 +0x008FF7E8 0xE4AF # 0 +0x008FF7E9 0xE4B0 # 0 +0x008FF7EA 0xE4B1 # 0 +0x008FF7EB 0xE4B2 # 0 +0x008FF7EC 0xE4B3 # 0 +0x008FF7ED 0xE4B4 # 0 +0x008FF7EE 0xE4B5 # 0 +0x008FF7EF 0xE4B6 # 0 +0x008FF7F0 0xE4B7 # 0 +0x008FF7F1 0xE4B8 # 0 +0x008FF7F2 0xE4B9 # 0 +0x008FF7F3 0xE4BA # 0 +0x008FF7F4 0xE4BB # 0 +0x008FF7F5 0xE4BC # 0 +0x008FF7F6 0xE4BD # 0 +0x008FF7F7 0xE4BE # 0 +0x008FF7F8 0xE4BF # 0 +0x008FF7F9 0xE4C0 # 0 +0x008FF7FA 0xE4C1 # 0 +0x008FF7FB 0xE4C2 # 0 +0x008FF7FC 0xE4C3 # 0 +0x008FF7FD 0xE4C4 # 0 +0x008FF7FE 0xE4C5 # 0 +0x008FF8A1 0xE4C6 # 0 +0x008FF8A2 0xE4C7 # 0 +0x008FF8A3 0xE4C8 # 0 +0x008FF8A4 0xE4C9 # 0 +0x008FF8A5 0xE4CA # 0 +0x008FF8A6 0xE4CB # 0 +0x008FF8A7 0xE4CC # 0 +0x008FF8A8 0xE4CD # 0 +0x008FF8A9 0xE4CE # 0 +0x008FF8AA 0xE4CF # 0 +0x008FF8AB 0xE4D0 # 0 +0x008FF8AC 0xE4D1 # 0 +0x008FF8AD 0xE4D2 # 0 +0x008FF8AE 0xE4D3 # 0 +0x008FF8AF 0xE4D4 # 0 +0x008FF8B0 0xE4D5 # 0 +0x008FF8B1 0xE4D6 # 0 +0x008FF8B2 0xE4D7 # 0 +0x008FF8B3 0xE4D8 # 0 +0x008FF8B4 0xE4D9 # 0 +0x008FF8B5 0xE4DA # 0 +0x008FF8B6 0xE4DB # 0 +0x008FF8B7 0xE4DC # 0 +0x008FF8B8 0xE4DD # 0 +0x008FF8B9 0xE4DE # 0 +0x008FF8BA 0xE4DF # 0 +0x008FF8BB 0xE4E0 # 0 +0x008FF8BC 0xE4E1 # 0 +0x008FF8BD 0xE4E2 # 0 +0x008FF8BE 0xE4E3 # 0 +0x008FF8BF 0xE4E4 # 0 +0x008FF8C0 0xE4E5 # 0 +0x008FF8C1 0xE4E6 # 0 +0x008FF8C2 0xE4E7 # 0 +0x008FF8C3 0xE4E8 # 0 +0x008FF8C4 0xE4E9 # 0 +0x008FF8C5 0xE4EA # 0 +0x008FF8C6 0xE4EB # 0 +0x008FF8C7 0xE4EC # 0 +0x008FF8C8 0xE4ED # 0 +0x008FF8C9 0xE4EE # 0 +0x008FF8CA 0xE4EF # 0 +0x008FF8CB 0xE4F0 # 0 +0x008FF8CC 0xE4F1 # 0 +0x008FF8CD 0xE4F2 # 0 +0x008FF8CE 0xE4F3 # 0 +0x008FF8CF 0xE4F4 # 0 +0x008FF8D0 0xE4F5 # 0 +0x008FF8D1 0xE4F6 # 0 +0x008FF8D2 0xE4F7 # 0 +0x008FF8D3 0xE4F8 # 0 +0x008FF8D4 0xE4F9 # 0 +0x008FF8D5 0xE4FA # 0 +0x008FF8D6 0xE4FB # 0 +0x008FF8D7 0xE4FC # 0 +0x008FF8D8 0xE4FD # 0 +0x008FF8D9 0xE4FE # 0 +0x008FF8DA 0xE4FF # 0 +0x008FF8DB 0xE500 # 0 +0x008FF8DC 0xE501 # 0 +0x008FF8DD 0xE502 # 0 +0x008FF8DE 0xE503 # 0 +0x008FF8DF 0xE504 # 0 +0x008FF8E0 0xE505 # 0 +0x008FF8E1 0xE506 # 0 +0x008FF8E2 0xE507 # 0 +0x008FF8E3 0xE508 # 0 +0x008FF8E4 0xE509 # 0 +0x008FF8E5 0xE50A # 0 +0x008FF8E6 0xE50B # 0 +0x008FF8E7 0xE50C # 0 +0x008FF8E8 0xE50D # 0 +0x008FF8E9 0xE50E # 0 +0x008FF8EA 0xE50F # 0 +0x008FF8EB 0xE510 # 0 +0x008FF8EC 0xE511 # 0 +0x008FF8ED 0xE512 # 0 +0x008FF8EE 0xE513 # 0 +0x008FF8EF 0xE514 # 0 +0x008FF8F0 0xE515 # 0 +0x008FF8F1 0xE516 # 0 +0x008FF8F2 0xE517 # 0 +0x008FF8F3 0xE518 # 0 +0x008FF8F4 0xE519 # 0 +0x008FF8F5 0xE51A # 0 +0x008FF8F6 0xE51B # 0 +0x008FF8F7 0xE51C # 0 +0x008FF8F8 0xE51D # 0 +0x008FF8F9 0xE51E # 0 +0x008FF8FA 0xE51F # 0 +0x008FF8FB 0xE520 # 0 +0x008FF8FC 0xE521 # 0 +0x008FF8FD 0xE522 # 0 +0x008FF8FE 0xE523 # 0 +0x008FF9A1 0xE524 # 0 +0x008FF9A2 0xE525 # 0 +0x008FF9A3 0xE526 # 0 +0x008FF9A4 0xE527 # 0 +0x008FF9A5 0xE528 # 0 +0x008FF9A6 0xE529 # 0 +0x008FF9A7 0xE52A # 0 +0x008FF9A8 0xE52B # 0 +0x008FF9A9 0xE52C # 0 +0x008FF9AA 0xE52D # 0 +0x008FF9AB 0xE52E # 0 +0x008FF9AC 0xE52F # 0 +0x008FF9AD 0xE530 # 0 +0x008FF9AE 0xE531 # 0 +0x008FF9AF 0xE532 # 0 +0x008FF9B0 0xE533 # 0 +0x008FF9B1 0xE534 # 0 +0x008FF9B2 0xE535 # 0 +0x008FF9B3 0xE536 # 0 +0x008FF9B4 0xE537 # 0 +0x008FF9B5 0xE538 # 0 +0x008FF9B6 0xE539 # 0 +0x008FF9B7 0xE53A # 0 +0x008FF9B8 0xE53B # 0 +0x008FF9B9 0xE53C # 0 +0x008FF9BA 0xE53D # 0 +0x008FF9BB 0xE53E # 0 +0x008FF9BC 0xE53F # 0 +0x008FF9BD 0xE540 # 0 +0x008FF9BE 0xE541 # 0 +0x008FF9BF 0xE542 # 0 +0x008FF9C0 0xE543 # 0 +0x008FF9C1 0xE544 # 0 +0x008FF9C2 0xE545 # 0 +0x008FF9C3 0xE546 # 0 +0x008FF9C4 0xE547 # 0 +0x008FF9C5 0xE548 # 0 +0x008FF9C6 0xE549 # 0 +0x008FF9C7 0xE54A # 0 +0x008FF9C8 0xE54B # 0 +0x008FF9C9 0xE54C # 0 +0x008FF9CA 0xE54D # 0 +0x008FF9CB 0xE54E # 0 +0x008FF9CC 0xE54F # 0 +0x008FF9CD 0xE550 # 0 +0x008FF9CE 0xE551 # 0 +0x008FF9CF 0xE552 # 0 +0x008FF9D0 0xE553 # 0 +0x008FF9D1 0xE554 # 0 +0x008FF9D2 0xE555 # 0 +0x008FF9D3 0xE556 # 0 +0x008FF9D4 0xE557 # 0 +0x008FF9D5 0xE558 # 0 +0x008FF9D6 0xE559 # 0 +0x008FF9D7 0xE55A # 0 +0x008FF9D8 0xE55B # 0 +0x008FF9D9 0xE55C # 0 +0x008FF9DA 0xE55D # 0 +0x008FF9DB 0xE55E # 0 +0x008FF9DC 0xE55F # 0 +0x008FF9DD 0xE560 # 0 +0x008FF9DE 0xE561 # 0 +0x008FF9DF 0xE562 # 0 +0x008FF9E0 0xE563 # 0 +0x008FF9E1 0xE564 # 0 +0x008FF9E2 0xE565 # 0 +0x008FF9E3 0xE566 # 0 +0x008FF9E4 0xE567 # 0 +0x008FF9E5 0xE568 # 0 +0x008FF9E6 0xE569 # 0 +0x008FF9E7 0xE56A # 0 +0x008FF9E8 0xE56B # 0 +0x008FF9E9 0xE56C # 0 +0x008FF9EA 0xE56D # 0 +0x008FF9EB 0xE56E # 0 +0x008FF9EC 0xE56F # 0 +0x008FF9ED 0xE570 # 0 +0x008FF9EE 0xE571 # 0 +0x008FF9EF 0xE572 # 0 +0x008FF9F0 0xE573 # 0 +0x008FF9F1 0xE574 # 0 +0x008FF9F2 0xE575 # 0 +0x008FF9F3 0xE576 # 0 +0x008FF9F4 0xE577 # 0 +0x008FF9F5 0xE578 # 0 +0x008FF9F6 0xE579 # 0 +0x008FF9F7 0xE57A # 0 +0x008FF9F8 0xE57B # 0 +0x008FF9F9 0xE57C # 0 +0x008FF9FA 0xE57D # 0 +0x008FF9FB 0xE57E # 0 +0x008FF9FC 0xE57F # 0 +0x008FF9FD 0xE580 # 0 +0x008FF9FE 0xE581 # 0 +0x008FFAA1 0xE582 # 0 +0x008FFAA2 0xE583 # 0 +0x008FFAA3 0xE584 # 0 +0x008FFAA4 0xE585 # 0 +0x008FFAA5 0xE586 # 0 +0x008FFAA6 0xE587 # 0 +0x008FFAA7 0xE588 # 0 +0x008FFAA8 0xE589 # 0 +0x008FFAA9 0xE58A # 0 +0x008FFAAA 0xE58B # 0 +0x008FFAAB 0xE58C # 0 +0x008FFAAC 0xE58D # 0 +0x008FFAAD 0xE58E # 0 +0x008FFAAE 0xE58F # 0 +0x008FFAAF 0xE590 # 0 +0x008FFAB0 0xE591 # 0 +0x008FFAB1 0xE592 # 0 +0x008FFAB2 0xE593 # 0 +0x008FFAB3 0xE594 # 0 +0x008FFAB4 0xE595 # 0 +0x008FFAB5 0xE596 # 0 +0x008FFAB6 0xE597 # 0 +0x008FFAB7 0xE598 # 0 +0x008FFAB8 0xE599 # 0 +0x008FFAB9 0xE59A # 0 +0x008FFABA 0xE59B # 0 +0x008FFABB 0xE59C # 0 +0x008FFABC 0xE59D # 0 +0x008FFABD 0xE59E # 0 +0x008FFABE 0xE59F # 0 +0x008FFABF 0xE5A0 # 0 +0x008FFAC0 0xE5A1 # 0 +0x008FFAC1 0xE5A2 # 0 +0x008FFAC2 0xE5A3 # 0 +0x008FFAC3 0xE5A4 # 0 +0x008FFAC4 0xE5A5 # 0 +0x008FFAC5 0xE5A6 # 0 +0x008FFAC6 0xE5A7 # 0 +0x008FFAC7 0xE5A8 # 0 +0x008FFAC8 0xE5A9 # 0 +0x008FFAC9 0xE5AA # 0 +0x008FFACA 0xE5AB # 0 +0x008FFACB 0xE5AC # 0 +0x008FFACC 0xE5AD # 0 +0x008FFACD 0xE5AE # 0 +0x008FFACE 0xE5AF # 0 +0x008FFACF 0xE5B0 # 0 +0x008FFAD0 0xE5B1 # 0 +0x008FFAD1 0xE5B2 # 0 +0x008FFAD2 0xE5B3 # 0 +0x008FFAD3 0xE5B4 # 0 +0x008FFAD4 0xE5B5 # 0 +0x008FFAD5 0xE5B6 # 0 +0x008FFAD6 0xE5B7 # 0 +0x008FFAD7 0xE5B8 # 0 +0x008FFAD8 0xE5B9 # 0 +0x008FFAD9 0xE5BA # 0 +0x008FFADA 0xE5BB # 0 +0x008FFADB 0xE5BC # 0 +0x008FFADC 0xE5BD # 0 +0x008FFADD 0xE5BE # 0 +0x008FFADE 0xE5BF # 0 +0x008FFADF 0xE5C0 # 0 +0x008FFAE0 0xE5C1 # 0 +0x008FFAE1 0xE5C2 # 0 +0x008FFAE2 0xE5C3 # 0 +0x008FFAE3 0xE5C4 # 0 +0x008FFAE4 0xE5C5 # 0 +0x008FFAE5 0xE5C6 # 0 +0x008FFAE6 0xE5C7 # 0 +0x008FFAE7 0xE5C8 # 0 +0x008FFAE8 0xE5C9 # 0 +0x008FFAE9 0xE5CA # 0 +0x008FFAEA 0xE5CB # 0 +0x008FFAEB 0xE5CC # 0 +0x008FFAEC 0xE5CD # 0 +0x008FFAED 0xE5CE # 0 +0x008FFAEE 0xE5CF # 0 +0x008FFAEF 0xE5D0 # 0 +0x008FFAF0 0xE5D1 # 0 +0x008FFAF1 0xE5D2 # 0 +0x008FFAF2 0xE5D3 # 0 +0x008FFAF3 0xE5D4 # 0 +0x008FFAF4 0xE5D5 # 0 +0x008FFAF5 0xE5D6 # 0 +0x008FFAF6 0xE5D7 # 0 +0x008FFAF7 0xE5D8 # 0 +0x008FFAF8 0xE5D9 # 0 +0x008FFAF9 0xE5DA # 0 +0x008FFAFA 0xE5DB # 0 +0x008FFAFB 0xE5DC # 0 +0x008FFAFC 0xE5DD # 0 +0x008FFAFD 0xE5DE # 0 +0x008FFAFE 0xE5DF # 0 +0x008FFBA1 0xE5E0 # 0 +0x008FFBA2 0xE5E1 # 0 +0x008FFBA3 0xE5E2 # 0 +0x008FFBA4 0xE5E3 # 0 +0x008FFBA5 0xE5E4 # 0 +0x008FFBA6 0xE5E5 # 0 +0x008FFBA7 0xE5E6 # 0 +0x008FFBA8 0xE5E7 # 0 +0x008FFBA9 0xE5E8 # 0 +0x008FFBAA 0xE5E9 # 0 +0x008FFBAB 0xE5EA # 0 +0x008FFBAC 0xE5EB # 0 +0x008FFBAD 0xE5EC # 0 +0x008FFBAE 0xE5ED # 0 +0x008FFBAF 0xE5EE # 0 +0x008FFBB0 0xE5EF # 0 +0x008FFBB1 0xE5F0 # 0 +0x008FFBB2 0xE5F1 # 0 +0x008FFBB3 0xE5F2 # 0 +0x008FFBB4 0xE5F3 # 0 +0x008FFBB5 0xE5F4 # 0 +0x008FFBB6 0xE5F5 # 0 +0x008FFBB7 0xE5F6 # 0 +0x008FFBB8 0xE5F7 # 0 +0x008FFBB9 0xE5F8 # 0 +0x008FFBBA 0xE5F9 # 0 +0x008FFBBB 0xE5FA # 0 +0x008FFBBC 0xE5FB # 0 +0x008FFBBD 0xE5FC # 0 +0x008FFBBE 0xE5FD # 0 +0x008FFBBF 0xE5FE # 0 +0x008FFBC0 0xE5FF # 0 +0x008FFBC1 0xE600 # 0 +0x008FFBC2 0xE601 # 0 +0x008FFBC3 0xE602 # 0 +0x008FFBC4 0xE603 # 0 +0x008FFBC5 0xE604 # 0 +0x008FFBC6 0xE605 # 0 +0x008FFBC7 0xE606 # 0 +0x008FFBC8 0xE607 # 0 +0x008FFBC9 0xE608 # 0 +0x008FFBCA 0xE609 # 0 +0x008FFBCB 0xE60A # 0 +0x008FFBCC 0xE60B # 0 +0x008FFBCD 0xE60C # 0 +0x008FFBCE 0xE60D # 0 +0x008FFBCF 0xE60E # 0 +0x008FFBD0 0xE60F # 0 +0x008FFBD1 0xE610 # 0 +0x008FFBD2 0xE611 # 0 +0x008FFBD3 0xE612 # 0 +0x008FFBD4 0xE613 # 0 +0x008FFBD5 0xE614 # 0 +0x008FFBD6 0xE615 # 0 +0x008FFBD7 0xE616 # 0 +0x008FFBD8 0xE617 # 0 +0x008FFBD9 0xE618 # 0 +0x008FFBDA 0xE619 # 0 +0x008FFBDB 0xE61A # 0 +0x008FFBDC 0xE61B # 0 +0x008FFBDD 0xE61C # 0 +0x008FFBDE 0xE61D # 0 +0x008FFBDF 0xE61E # 0 +0x008FFBE0 0xE61F # 0 +0x008FFBE1 0xE620 # 0 +0x008FFBE2 0xE621 # 0 +0x008FFBE3 0xE622 # 0 +0x008FFBE4 0xE623 # 0 +0x008FFBE5 0xE624 # 0 +0x008FFBE6 0xE625 # 0 +0x008FFBE7 0xE626 # 0 +0x008FFBE8 0xE627 # 0 +0x008FFBE9 0xE628 # 0 +0x008FFBEA 0xE629 # 0 +0x008FFBEB 0xE62A # 0 +0x008FFBEC 0xE62B # 0 +0x008FFBED 0xE62C # 0 +0x008FFBEE 0xE62D # 0 +0x008FFBEF 0xE62E # 0 +0x008FFBF0 0xE62F # 0 +0x008FFBF1 0xE630 # 0 +0x008FFBF2 0xE631 # 0 +0x008FFBF3 0xE632 # 0 +0x008FFBF4 0xE633 # 0 +0x008FFBF5 0xE634 # 0 +0x008FFBF6 0xE635 # 0 +0x008FFBF7 0xE636 # 0 +0x008FFBF8 0xE637 # 0 +0x008FFBF9 0xE638 # 0 +0x008FFBFA 0xE639 # 0 +0x008FFBFB 0xE63A # 0 +0x008FFBFC 0xE63B # 0 +0x008FFBFD 0xE63C # 0 +0x008FFBFE 0xE63D # 0 +0x008FFCA1 0xE63E # 0 +0x008FFCA2 0xE63F # 0 +0x008FFCA3 0xE640 # 0 +0x008FFCA4 0xE641 # 0 +0x008FFCA5 0xE642 # 0 +0x008FFCA6 0xE643 # 0 +0x008FFCA7 0xE644 # 0 +0x008FFCA8 0xE645 # 0 +0x008FFCA9 0xE646 # 0 +0x008FFCAA 0xE647 # 0 +0x008FFCAB 0xE648 # 0 +0x008FFCAC 0xE649 # 0 +0x008FFCAD 0xE64A # 0 +0x008FFCAE 0xE64B # 0 +0x008FFCAF 0xE64C # 0 +0x008FFCB0 0xE64D # 0 +0x008FFCB1 0xE64E # 0 +0x008FFCB2 0xE64F # 0 +0x008FFCB3 0xE650 # 0 +0x008FFCB4 0xE651 # 0 +0x008FFCB5 0xE652 # 0 +0x008FFCB6 0xE653 # 0 +0x008FFCB7 0xE654 # 0 +0x008FFCB8 0xE655 # 0 +0x008FFCB9 0xE656 # 0 +0x008FFCBA 0xE657 # 0 +0x008FFCBB 0xE658 # 0 +0x008FFCBC 0xE659 # 0 +0x008FFCBD 0xE65A # 0 +0x008FFCBE 0xE65B # 0 +0x008FFCBF 0xE65C # 0 +0x008FFCC0 0xE65D # 0 +0x008FFCC1 0xE65E # 0 +0x008FFCC2 0xE65F # 0 +0x008FFCC3 0xE660 # 0 +0x008FFCC4 0xE661 # 0 +0x008FFCC5 0xE662 # 0 +0x008FFCC6 0xE663 # 0 +0x008FFCC7 0xE664 # 0 +0x008FFCC8 0xE665 # 0 +0x008FFCC9 0xE666 # 0 +0x008FFCCA 0xE667 # 0 +0x008FFCCB 0xE668 # 0 +0x008FFCCC 0xE669 # 0 +0x008FFCCD 0xE66A # 0 +0x008FFCCE 0xE66B # 0 +0x008FFCCF 0xE66C # 0 +0x008FFCD0 0xE66D # 0 +0x008FFCD1 0xE66E # 0 +0x008FFCD2 0xE66F # 0 +0x008FFCD3 0xE670 # 0 +0x008FFCD4 0xE671 # 0 +0x008FFCD5 0xE672 # 0 +0x008FFCD6 0xE673 # 0 +0x008FFCD7 0xE674 # 0 +0x008FFCD8 0xE675 # 0 +0x008FFCD9 0xE676 # 0 +0x008FFCDA 0xE677 # 0 +0x008FFCDB 0xE678 # 0 +0x008FFCDC 0xE679 # 0 +0x008FFCDD 0xE67A # 0 +0x008FFCDE 0xE67B # 0 +0x008FFCDF 0xE67C # 0 +0x008FFCE0 0xE67D # 0 +0x008FFCE1 0xE67E # 0 +0x008FFCE2 0xE67F # 0 +0x008FFCE3 0xE680 # 0 +0x008FFCE4 0xE681 # 0 +0x008FFCE5 0xE682 # 0 +0x008FFCE6 0xE683 # 0 +0x008FFCE7 0xE684 # 0 +0x008FFCE8 0xE685 # 0 +0x008FFCE9 0xE686 # 0 +0x008FFCEA 0xE687 # 0 +0x008FFCEB 0xE688 # 0 +0x008FFCEC 0xE689 # 0 +0x008FFCED 0xE68A # 0 +0x008FFCEE 0xE68B # 0 +0x008FFCEF 0xE68C # 0 +0x008FFCF0 0xE68D # 0 +0x008FFCF1 0xE68E # 0 +0x008FFCF2 0xE68F # 0 +0x008FFCF3 0xE690 # 0 +0x008FFCF4 0xE691 # 0 +0x008FFCF5 0xE692 # 0 +0x008FFCF6 0xE693 # 0 +0x008FFCF7 0xE694 # 0 +0x008FFCF8 0xE695 # 0 +0x008FFCF9 0xE696 # 0 +0x008FFCFA 0xE697 # 0 +0x008FFCFB 0xE698 # 0 +0x008FFCFC 0xE699 # 0 +0x008FFCFD 0xE69A # 0 +0x008FFCFE 0xE69B # 0 +0x008FFDA1 0xE69C # 0 +0x008FFDA2 0xE69D # 0 +0x008FFDA3 0xE69E # 0 +0x008FFDA4 0xE69F # 0 +0x008FFDA5 0xE6A0 # 0 +0x008FFDA6 0xE6A1 # 0 +0x008FFDA7 0xE6A2 # 0 +0x008FFDA8 0xE6A3 # 0 +0x008FFDA9 0xE6A4 # 0 +0x008FFDAA 0xE6A5 # 0 +0x008FFDAB 0xE6A6 # 0 +0x008FFDAC 0xE6A7 # 0 +0x008FFDAD 0xE6A8 # 0 +0x008FFDAE 0xE6A9 # 0 +0x008FFDAF 0xE6AA # 0 +0x008FFDB0 0xE6AB # 0 +0x008FFDB1 0xE6AC # 0 +0x008FFDB2 0xE6AD # 0 +0x008FFDB3 0xE6AE # 0 +0x008FFDB4 0xE6AF # 0 +0x008FFDB5 0xE6B0 # 0 +0x008FFDB6 0xE6B1 # 0 +0x008FFDB7 0xE6B2 # 0 +0x008FFDB8 0xE6B3 # 0 +0x008FFDB9 0xE6B4 # 0 +0x008FFDBA 0xE6B5 # 0 +0x008FFDBB 0xE6B6 # 0 +0x008FFDBC 0xE6B7 # 0 +0x008FFDBD 0xE6B8 # 0 +0x008FFDBE 0xE6B9 # 0 +0x008FFDBF 0xE6BA # 0 +0x008FFDC0 0xE6BB # 0 +0x008FFDC1 0xE6BC # 0 +0x008FFDC2 0xE6BD # 0 +0x008FFDC3 0xE6BE # 0 +0x008FFDC4 0xE6BF # 0 +0x008FFDC5 0xE6C0 # 0 +0x008FFDC6 0xE6C1 # 0 +0x008FFDC7 0xE6C2 # 0 +0x008FFDC8 0xE6C3 # 0 +0x008FFDC9 0xE6C4 # 0 +0x008FFDCA 0xE6C5 # 0 +0x008FFDCB 0xE6C6 # 0 +0x008FFDCC 0xE6C7 # 0 +0x008FFDCD 0xE6C8 # 0 +0x008FFDCE 0xE6C9 # 0 +0x008FFDCF 0xE6CA # 0 +0x008FFDD0 0xE6CB # 0 +0x008FFDD1 0xE6CC # 0 +0x008FFDD2 0xE6CD # 0 +0x008FFDD3 0xE6CE # 0 +0x008FFDD4 0xE6CF # 0 +0x008FFDD5 0xE6D0 # 0 +0x008FFDD6 0xE6D1 # 0 +0x008FFDD7 0xE6D2 # 0 +0x008FFDD8 0xE6D3 # 0 +0x008FFDD9 0xE6D4 # 0 +0x008FFDDA 0xE6D5 # 0 +0x008FFDDB 0xE6D6 # 0 +0x008FFDDC 0xE6D7 # 0 +0x008FFDDD 0xE6D8 # 0 +0x008FFDDE 0xE6D9 # 0 +0x008FFDDF 0xE6DA # 0 +0x008FFDE0 0xE6DB # 0 +0x008FFDE1 0xE6DC # 0 +0x008FFDE2 0xE6DD # 0 +0x008FFDE3 0xE6DE # 0 +0x008FFDE4 0xE6DF # 0 +0x008FFDE5 0xE6E0 # 0 +0x008FFDE6 0xE6E1 # 0 +0x008FFDE7 0xE6E2 # 0 +0x008FFDE8 0xE6E3 # 0 +0x008FFDE9 0xE6E4 # 0 +0x008FFDEA 0xE6E5 # 0 +0x008FFDEB 0xE6E6 # 0 +0x008FFDEC 0xE6E7 # 0 +0x008FFDED 0xE6E8 # 0 +0x008FFDEE 0xE6E9 # 0 +0x008FFDEF 0xE6EA # 0 +0x008FFDF0 0xE6EB # 0 +0x008FFDF1 0xE6EC # 0 +0x008FFDF2 0xE6ED # 0 +0x008FFDF3 0xE6EE # 0 +0x008FFDF4 0xE6EF # 0 +0x008FFDF5 0xE6F0 # 0 +0x008FFDF6 0xE6F1 # 0 +0x008FFDF7 0xE6F2 # 0 +0x008FFDF8 0xE6F3 # 0 +0x008FFDF9 0xE6F4 # 0 +0x008FFDFA 0xE6F5 # 0 +0x008FFDFB 0xE6F6 # 0 +0x008FFDFC 0xE6F7 # 0 +0x008FFDFD 0xE6F8 # 0 +0x008FFDFE 0xE6F9 # 0 +0x008FFEA1 0xE6FA # 0 +0x008FFEA2 0xE6FB # 0 +0x008FFEA3 0xE6FC # 0 +0x008FFEA4 0xE6FD # 0 +0x008FFEA5 0xE6FE # 0 +0x008FFEA6 0xE6FF # 0 +0x008FFEA7 0xE700 # 0 +0x008FFEA8 0xE701 # 0 +0x008FFEA9 0xE702 # 0 +0x008FFEAA 0xE703 # 0 +0x008FFEAB 0xE704 # 0 +0x008FFEAC 0xE705 # 0 +0x008FFEAD 0xE706 # 0 +0x008FFEAE 0xE707 # 0 +0x008FFEAF 0xE708 # 0 +0x008FFEB0 0xE709 # 0 +0x008FFEB1 0xE70A # 0 +0x008FFEB2 0xE70B # 0 +0x008FFEB3 0xE70C # 0 +0x008FFEB4 0xE70D # 0 +0x008FFEB5 0xE70E # 0 +0x008FFEB6 0xE70F # 0 +0x008FFEB7 0xE710 # 0 +0x008FFEB8 0xE711 # 0 +0x008FFEB9 0xE712 # 0 +0x008FFEBA 0xE713 # 0 +0x008FFEBB 0xE714 # 0 +0x008FFEBC 0xE715 # 0 +0x008FFEBD 0xE716 # 0 +0x008FFEBE 0xE717 # 0 +0x008FFEBF 0xE718 # 0 +0x008FFEC0 0xE719 # 0 +0x008FFEC1 0xE71A # 0 +0x008FFEC2 0xE71B # 0 +0x008FFEC3 0xE71C # 0 +0x008FFEC4 0xE71D # 0 +0x008FFEC5 0xE71E # 0 +0x008FFEC6 0xE71F # 0 +0x008FFEC7 0xE720 # 0 +0x008FFEC8 0xE721 # 0 +0x008FFEC9 0xE722 # 0 +0x008FFECA 0xE723 # 0 +0x008FFECB 0xE724 # 0 +0x008FFECC 0xE725 # 0 +0x008FFECD 0xE726 # 0 +0x008FFECE 0xE727 # 0 +0x008FFECF 0xE728 # 0 +0x008FFED0 0xE729 # 0 +0x008FFED1 0xE72A # 0 +0x008FFED2 0xE72B # 0 +0x008FFED3 0xE72C # 0 +0x008FFED4 0xE72D # 0 +0x008FFED5 0xE72E # 0 +0x008FFED6 0xE72F # 0 +0x008FFED7 0xE730 # 0 +0x008FFED8 0xE731 # 0 +0x008FFED9 0xE732 # 0 +0x008FFEDA 0xE733 # 0 +0x008FFEDB 0xE734 # 0 +0x008FFEDC 0xE735 # 0 +0x008FFEDD 0xE736 # 0 +0x008FFEDE 0xE737 # 0 +0x008FFEDF 0xE738 # 0 +0x008FFEE0 0xE739 # 0 +0x008FFEE1 0xE73A # 0 +0x008FFEE2 0xE73B # 0 +0x008FFEE3 0xE73C # 0 +0x008FFEE4 0xE73D # 0 +0x008FFEE5 0xE73E # 0 +0x008FFEE6 0xE73F # 0 +0x008FFEE7 0xE740 # 0 +0x008FFEE8 0xE741 # 0 +0x008FFEE9 0xE742 # 0 +0x008FFEEA 0xE743 # 0 +0x008FFEEB 0xE744 # 0 +0x008FFEEC 0xE745 # 0 +0x008FFEED 0xE746 # 0 +0x008FFEEE 0xE747 # 0 +0x008FFEEF 0xE748 # 0 +0x008FFEF0 0xE749 # 0 +0x008FFEF1 0xE74A # 0 +0x008FFEF2 0xE74B # 0 +0x008FFEF3 0xE74C # 0 +0x008FFEF4 0xE74D # 0 +0x008FFEF5 0xE74E # 0 +0x008FFEF6 0xE74F # 0 +0x008FFEF7 0xE750 # 0 +0x008FFEF8 0xE751 # 0 +0x008FFEF9 0xE752 # 0 +0x008FFEFA 0xE753 # 0 +0x008FFEFB 0xE754 # 0 +0x008FFEFC 0xE755 # 0 +0x008FFEFD 0xE756 # 0 +0x008FFEFE 0xE757 # 0 diff --git a/data/euc-kr.txt b/data/euc-kr.txt new file mode 100644 index 000000000..7ea550360 --- /dev/null +++ b/data/euc-kr.txt @@ -0,0 +1,8371 @@ +# euc-kr.txt - EUC to Unicode charmap +0x00000000 0x0000 # 0 +0x00000001 0x0001 # 0 +0x00000002 0x0002 # 0 +0x00000003 0x0003 # 0 +0x00000004 0x0004 # 0 +0x00000005 0x0005 # 0 +0x00000006 0x0006 # 0 +0x00000007 0x0007 # 0 +0x00000008 0x0008 # 0 +0x00000009 0x0009 # 0 +0x0000000A 0x000A # 0 +0x0000000B 0x000B # 0 +0x0000000C 0x000C # 0 +0x0000000D 0x000D # 0 +0x0000000E 0x000E # 0 +0x0000000F 0x000F # 0 +0x00000010 0x0010 # 0 +0x00000011 0x0011 # 0 +0x00000012 0x0012 # 0 +0x00000013 0x0013 # 0 +0x00000014 0x0014 # 0 +0x00000015 0x0015 # 0 +0x00000016 0x0016 # 0 +0x00000017 0x0017 # 0 +0x00000018 0x0018 # 0 +0x00000019 0x0019 # 0 +0x0000001A 0x001A # 0 +0x0000001B 0x001B # 0 +0x0000001C 0x001C # 0 +0x0000001D 0x001D # 0 +0x0000001E 0x001E # 0 +0x0000001F 0x001F # 0 +0x00000020 0x0020 # 0 +0x00000021 0x0021 # 0 +0x00000022 0x0022 # 0 +0x00000023 0x0023 # 0 +0x00000024 0x0024 # 0 +0x00000025 0x0025 # 0 +0x00000026 0x0026 # 0 +0x00000027 0x0027 # 0 +0x00000028 0x0028 # 0 +0x00000029 0x0029 # 0 +0x0000002A 0x002A # 0 +0x0000002B 0x002B # 0 +0x0000002C 0x002C # 0 +0x0000002D 0x002D # 0 +0x0000002E 0x002E # 0 +0x0000002F 0x002F # 0 +0x00000030 0x0030 # 0 +0x00000031 0x0031 # 0 +0x00000032 0x0032 # 0 +0x00000033 0x0033 # 0 +0x00000034 0x0034 # 0 +0x00000035 0x0035 # 0 +0x00000036 0x0036 # 0 +0x00000037 0x0037 # 0 +0x00000038 0x0038 # 0 +0x00000039 0x0039 # 0 +0x0000003A 0x003A # 0 +0x0000003B 0x003B # 0 +0x0000003C 0x003C # 0 +0x0000003D 0x003D # 0 +0x0000003E 0x003E # 0 +0x0000003F 0x003F # 0 +0x00000040 0x0040 # 0 +0x00000041 0x0041 # 0 +0x00000042 0x0042 # 0 +0x00000043 0x0043 # 0 +0x00000044 0x0044 # 0 +0x00000045 0x0045 # 0 +0x00000046 0x0046 # 0 +0x00000047 0x0047 # 0 +0x00000048 0x0048 # 0 +0x00000049 0x0049 # 0 +0x0000004A 0x004A # 0 +0x0000004B 0x004B # 0 +0x0000004C 0x004C # 0 +0x0000004D 0x004D # 0 +0x0000004E 0x004E # 0 +0x0000004F 0x004F # 0 +0x00000050 0x0050 # 0 +0x00000051 0x0051 # 0 +0x00000052 0x0052 # 0 +0x00000053 0x0053 # 0 +0x00000054 0x0054 # 0 +0x00000055 0x0055 # 0 +0x00000056 0x0056 # 0 +0x00000057 0x0057 # 0 +0x00000058 0x0058 # 0 +0x00000059 0x0059 # 0 +0x0000005A 0x005A # 0 +0x0000005B 0x005B # 0 +0x0000005C 0x005C # 0 +0x0000005D 0x005D # 0 +0x0000005E 0x005E # 0 +0x0000005F 0x005F # 0 +0x00000060 0x0060 # 0 +0x00000061 0x0061 # 0 +0x00000062 0x0062 # 0 +0x00000063 0x0063 # 0 +0x00000064 0x0064 # 0 +0x00000065 0x0065 # 0 +0x00000066 0x0066 # 0 +0x00000067 0x0067 # 0 +0x00000068 0x0068 # 0 +0x00000069 0x0069 # 0 +0x0000006A 0x006A # 0 +0x0000006B 0x006B # 0 +0x0000006C 0x006C # 0 +0x0000006D 0x006D # 0 +0x0000006E 0x006E # 0 +0x0000006F 0x006F # 0 +0x00000070 0x0070 # 0 +0x00000071 0x0071 # 0 +0x00000072 0x0072 # 0 +0x00000073 0x0073 # 0 +0x00000074 0x0074 # 0 +0x00000075 0x0075 # 0 +0x00000076 0x0076 # 0 +0x00000077 0x0077 # 0 +0x00000078 0x0078 # 0 +0x00000079 0x0079 # 0 +0x0000007A 0x007A # 0 +0x0000007B 0x007B # 0 +0x0000007C 0x007C # 0 +0x0000007D 0x007D # 0 +0x0000007E 0x007E # 0 +0x0000007F 0x007F # 0 +0x0000A1A1 0x3000 # 0 +0x0000A1A2 0x3001 # 0 +0x0000A1A3 0x3002 # 0 +0x0000A1A4 0x30FB # 0 +0x0000A1A5 0x2025 # 0 +0x0000A1A6 0x2026 # 0 +0x0000A1A8 0x3003 # 0 +0x0000A1A9 0x2013 # 0 +0x0000A1AA 0x2014 # 0 +0x0000A1AB 0x2016 # 0 +0x0000A1AC 0xFF3C # 0 +0x0000A1AD 0xFF5E # 0 +0x0000A1AE 0x2018 # 0 +0x0000A1AF 0x2019 # 0 +0x0000A1B0 0x201C # 0 +0x0000A1B1 0x201D # 0 +0x0000A1B2 0x3014 # 0 +0x0000A1B3 0x3015 # 0 +0x0000A1B4 0x3008 # 0 +0x0000A1B5 0x3009 # 0 +0x0000A1B6 0x300A # 0 +0x0000A1B7 0x300B # 0 +0x0000A1B8 0x300C # 0 +0x0000A1B9 0x300D # 0 +0x0000A1BA 0x300E # 0 +0x0000A1BB 0x300F # 0 +0x0000A1BC 0x3010 # 0 +0x0000A1BD 0x3011 # 0 +0x0000A1C1 0x2260 # 0 +0x0000A1C2 0x2264 # 0 +0x0000A1C3 0x2265 # 0 +0x0000A1C4 0x221E # 0 +0x0000A1C5 0x2234 # 0 +0x0000A1C7 0x2032 # 0 +0x0000A1C8 0x2033 # 0 +0x0000A1C9 0x2103 # 0 +0x0000A1CA 0x212B # 0 +0x0000A1CB 0xFFE0 # 0 +0x0000A1CC 0xFFE1 # 0 +0x0000A1CD 0xFFE5 # 0 +0x0000A1CE 0x2642 # 0 +0x0000A1CF 0x2640 # 0 +0x0000A1D0 0x2220 # 0 +0x0000A1D1 0x22A5 # 0 +0x0000A1D2 0x2312 # 0 +0x0000A1D3 0x2202 # 0 +0x0000A1D4 0x2207 # 0 +0x0000A1D5 0x2261 # 0 +0x0000A1D6 0x2252 # 0 +0x0000A1D8 0x203B # 0 +0x0000A1D9 0x2606 # 0 +0x0000A1DA 0x2605 # 0 +0x0000A1DB 0x25CB # 0 +0x0000A1DC 0x25CF # 0 +0x0000A1DD 0x25CE # 0 +0x0000A1DE 0x25C7 # 0 +0x0000A1DF 0x25C6 # 0 +0x0000A1E0 0x25A1 # 0 +0x0000A1E1 0x25A0 # 0 +0x0000A1E2 0x25B3 # 0 +0x0000A1E3 0x25B2 # 0 +0x0000A1E4 0x25BD # 0 +0x0000A1E5 0x25BC # 0 +0x0000A1E6 0x2192 # 0 +0x0000A1E7 0x2190 # 0 +0x0000A1E8 0x2191 # 0 +0x0000A1E9 0x2193 # 0 +0x0000A1EA 0x2194 # 0 +0x0000A1EB 0x3013 # 0 +0x0000A1EE 0x221A # 0 +0x0000A1EF 0x223D # 0 +0x0000A1F0 0x221D # 0 +0x0000A1F1 0x2235 # 0 +0x0000A1F2 0x222B # 0 +0x0000A1F3 0x222C # 0 +0x0000A1F4 0x2208 # 0 +0x0000A1F5 0x220B # 0 +0x0000A1F6 0x2286 # 0 +0x0000A1F7 0x2287 # 0 +0x0000A1F8 0x2282 # 0 +0x0000A1F9 0x2283 # 0 +0x0000A1FA 0x222A # 0 +0x0000A1FB 0x2229 # 0 +0x0000A1FC 0x2227 # 0 +0x0000A1FD 0x2228 # 0 +0x0000A1FE 0xFFE2 # 0 +0x0000A2A1 0x21D2 # 0 +0x0000A2A2 0x21D4 # 0 +0x0000A2A3 0x2200 # 0 +0x0000A2A4 0x2203 # 0 +0x0000A2B0 0x2236 # 0 +0x0000A2B1 0x222E # 0 +0x0000A2B2 0x2211 # 0 +0x0000A2B3 0x220F # 0 +0x0000A2B5 0x2109 # 0 +0x0000A2B6 0x2030 # 0 +0x0000A2B7 0x25C1 # 0 +0x0000A2B8 0x25C0 # 0 +0x0000A2B9 0x25B7 # 0 +0x0000A2BA 0x25B6 # 0 +0x0000A2BB 0x2664 # 0 +0x0000A2BC 0x2660 # 0 +0x0000A2BD 0x2661 # 0 +0x0000A2BE 0x2665 # 0 +0x0000A2BF 0x2667 # 0 +0x0000A2C0 0x2663 # 0 +0x0000A2C1 0x25C9 # 0 +0x0000A2C2 0x25C8 # 0 +0x0000A2C3 0x25A3 # 0 +0x0000A2C4 0x25D0 # 0 +0x0000A2C5 0x25D1 # 0 +0x0000A2C6 0x2592 # 0 +0x0000A2C7 0x25A4 # 0 +0x0000A2C8 0x25A5 # 0 +0x0000A2C9 0x25A8 # 0 +0x0000A2CA 0x25A7 # 0 +0x0000A2CB 0x25A6 # 0 +0x0000A2CC 0x25A9 # 0 +0x0000A2CD 0x2668 # 0 +0x0000A2CE 0x260F # 0 +0x0000A2CF 0x260E # 0 +0x0000A2D0 0x261C # 0 +0x0000A2D1 0x261E # 0 +0x0000A2D3 0x2020 # 0 +0x0000A2D4 0x2021 # 0 +0x0000A2D5 0x2195 # 0 +0x0000A2D6 0x2197 # 0 +0x0000A2D7 0x2199 # 0 +0x0000A2D8 0x2196 # 0 +0x0000A2D9 0x2198 # 0 +0x0000A2DA 0x266D # 0 +0x0000A2DB 0x2669 # 0 +0x0000A2DC 0x266A # 0 +0x0000A2DD 0x266C # 0 +0x0000A2DE 0x327F # 0 +0x0000A2DF 0x321C # 0 +0x0000A2E0 0x2116 # 0 +0x0000A2E1 0x33C7 # 0 +0x0000A2E2 0x2122 # 0 +0x0000A2E3 0x33C2 # 0 +0x0000A2E4 0x33D8 # 0 +0x0000A2E5 0x2121 # 0 +0x0000A3A1 0xFF01 # 0 +0x0000A3A2 0xFF02 # 0 +0x0000A3A3 0xFF03 # 0 +0x0000A3A4 0xFF04 # 0 +0x0000A3A5 0xFF05 # 0 +0x0000A3A6 0xFF06 # 0 +0x0000A3A7 0xFF07 # 0 +0x0000A3A8 0xFF08 # 0 +0x0000A3A9 0xFF09 # 0 +0x0000A3AA 0xFF0A # 0 +0x0000A3AB 0xFF0B # 0 +0x0000A3AC 0xFF0C # 0 +0x0000A3AD 0xFF0D # 0 +0x0000A3AE 0xFF0E # 0 +0x0000A3AF 0xFF0F # 0 +0x0000A3B0 0xFF10 # 0 +0x0000A3B1 0xFF11 # 0 +0x0000A3B2 0xFF12 # 0 +0x0000A3B3 0xFF13 # 0 +0x0000A3B4 0xFF14 # 0 +0x0000A3B5 0xFF15 # 0 +0x0000A3B6 0xFF16 # 0 +0x0000A3B7 0xFF17 # 0 +0x0000A3B8 0xFF18 # 0 +0x0000A3B9 0xFF19 # 0 +0x0000A3BA 0xFF1A # 0 +0x0000A3BB 0xFF1B # 0 +0x0000A3BC 0xFF1C # 0 +0x0000A3BD 0xFF1D # 0 +0x0000A3BE 0xFF1E # 0 +0x0000A3BF 0xFF1F # 0 +0x0000A3C0 0xFF20 # 0 +0x0000A3C1 0xFF21 # 0 +0x0000A3C2 0xFF22 # 0 +0x0000A3C3 0xFF23 # 0 +0x0000A3C4 0xFF24 # 0 +0x0000A3C5 0xFF25 # 0 +0x0000A3C6 0xFF26 # 0 +0x0000A3C7 0xFF27 # 0 +0x0000A3C8 0xFF28 # 0 +0x0000A3C9 0xFF29 # 0 +0x0000A3CA 0xFF2A # 0 +0x0000A3CB 0xFF2B # 0 +0x0000A3CC 0xFF2C # 0 +0x0000A3CD 0xFF2D # 0 +0x0000A3CE 0xFF2E # 0 +0x0000A3CF 0xFF2F # 0 +0x0000A3D0 0xFF30 # 0 +0x0000A3D1 0xFF31 # 0 +0x0000A3D2 0xFF32 # 0 +0x0000A3D3 0xFF33 # 0 +0x0000A3D4 0xFF34 # 0 +0x0000A3D5 0xFF35 # 0 +0x0000A3D6 0xFF36 # 0 +0x0000A3D7 0xFF37 # 0 +0x0000A3D8 0xFF38 # 0 +0x0000A3D9 0xFF39 # 0 +0x0000A3DA 0xFF3A # 0 +0x0000A3DB 0xFF3B # 0 +0x0000A3DC 0xFFE6 # 0 +0x0000A3DD 0xFF3D # 0 +0x0000A3DE 0xFF3E # 0 +0x0000A3DF 0xFF3F # 0 +0x0000A3E0 0xFF40 # 0 +0x0000A3E1 0xFF41 # 0 +0x0000A3E2 0xFF42 # 0 +0x0000A3E3 0xFF43 # 0 +0x0000A3E4 0xFF44 # 0 +0x0000A3E5 0xFF45 # 0 +0x0000A3E6 0xFF46 # 0 +0x0000A3E7 0xFF47 # 0 +0x0000A3E8 0xFF48 # 0 +0x0000A3E9 0xFF49 # 0 +0x0000A3EA 0xFF4A # 0 +0x0000A3EB 0xFF4B # 0 +0x0000A3EC 0xFF4C # 0 +0x0000A3ED 0xFF4D # 0 +0x0000A3EE 0xFF4E # 0 +0x0000A3EF 0xFF4F # 0 +0x0000A3F0 0xFF50 # 0 +0x0000A3F1 0xFF51 # 0 +0x0000A3F2 0xFF52 # 0 +0x0000A3F3 0xFF53 # 0 +0x0000A3F4 0xFF54 # 0 +0x0000A3F5 0xFF55 # 0 +0x0000A3F6 0xFF56 # 0 +0x0000A3F7 0xFF57 # 0 +0x0000A3F8 0xFF58 # 0 +0x0000A3F9 0xFF59 # 0 +0x0000A3FA 0xFF5A # 0 +0x0000A3FB 0xFF5B # 0 +0x0000A3FC 0xFF5C # 0 +0x0000A3FD 0xFF5D # 0 +0x0000A3FE 0xFFE3 # 0 +0x0000A4A1 0x3131 # 0 +0x0000A4A2 0x3132 # 0 +0x0000A4A3 0x3133 # 0 +0x0000A4A4 0x3134 # 0 +0x0000A4A5 0x3135 # 0 +0x0000A4A6 0x3136 # 0 +0x0000A4A7 0x3137 # 0 +0x0000A4A8 0x3138 # 0 +0x0000A4A9 0x3139 # 0 +0x0000A4AA 0x313A # 0 +0x0000A4AB 0x313B # 0 +0x0000A4AC 0x313C # 0 +0x0000A4AD 0x313D # 0 +0x0000A4AE 0x313E # 0 +0x0000A4AF 0x313F # 0 +0x0000A4B0 0x3140 # 0 +0x0000A4B1 0x3141 # 0 +0x0000A4B2 0x3142 # 0 +0x0000A4B3 0x3143 # 0 +0x0000A4B4 0x3144 # 0 +0x0000A4B5 0x3145 # 0 +0x0000A4B6 0x3146 # 0 +0x0000A4B7 0x3147 # 0 +0x0000A4B8 0x3148 # 0 +0x0000A4B9 0x3149 # 0 +0x0000A4BA 0x314A # 0 +0x0000A4BB 0x314B # 0 +0x0000A4BC 0x314C # 0 +0x0000A4BD 0x314D # 0 +0x0000A4BE 0x314E # 0 +0x0000A4BF 0x314F # 0 +0x0000A4C0 0x3150 # 0 +0x0000A4C1 0x3151 # 0 +0x0000A4C2 0x3152 # 0 +0x0000A4C3 0x3153 # 0 +0x0000A4C4 0x3154 # 0 +0x0000A4C5 0x3155 # 0 +0x0000A4C6 0x3156 # 0 +0x0000A4C7 0x3157 # 0 +0x0000A4C8 0x3158 # 0 +0x0000A4C9 0x3159 # 0 +0x0000A4CA 0x315A # 0 +0x0000A4CB 0x315B # 0 +0x0000A4CC 0x315C # 0 +0x0000A4CD 0x315D # 0 +0x0000A4CE 0x315E # 0 +0x0000A4CF 0x315F # 0 +0x0000A4D0 0x3160 # 0 +0x0000A4D1 0x3161 # 0 +0x0000A4D2 0x3162 # 0 +0x0000A4D3 0x3163 # 0 +0x0000A4D4 0x3164 # 0 +0x0000A4D5 0x3165 # 0 +0x0000A4D6 0x3166 # 0 +0x0000A4D7 0x3167 # 0 +0x0000A4D8 0x3168 # 0 +0x0000A4D9 0x3169 # 0 +0x0000A4DA 0x316A # 0 +0x0000A4DB 0x316B # 0 +0x0000A4DC 0x316C # 0 +0x0000A4DD 0x316D # 0 +0x0000A4DE 0x316E # 0 +0x0000A4DF 0x316F # 0 +0x0000A4E0 0x3170 # 0 +0x0000A4E1 0x3171 # 0 +0x0000A4E2 0x3172 # 0 +0x0000A4E3 0x3173 # 0 +0x0000A4E4 0x3174 # 0 +0x0000A4E5 0x3175 # 0 +0x0000A4E6 0x3176 # 0 +0x0000A4E7 0x3177 # 0 +0x0000A4E8 0x3178 # 0 +0x0000A4E9 0x3179 # 0 +0x0000A4EA 0x317A # 0 +0x0000A4EB 0x317B # 0 +0x0000A4EC 0x317C # 0 +0x0000A4ED 0x317D # 0 +0x0000A4EE 0x317E # 0 +0x0000A4EF 0x317F # 0 +0x0000A4F0 0x3180 # 0 +0x0000A4F1 0x3181 # 0 +0x0000A4F2 0x3182 # 0 +0x0000A4F3 0x3183 # 0 +0x0000A4F4 0x3184 # 0 +0x0000A4F5 0x3185 # 0 +0x0000A4F6 0x3186 # 0 +0x0000A4F7 0x3187 # 0 +0x0000A4F8 0x3188 # 0 +0x0000A4F9 0x3189 # 0 +0x0000A4FA 0x318A # 0 +0x0000A4FB 0x318B # 0 +0x0000A4FC 0x318C # 0 +0x0000A4FD 0x318D # 0 +0x0000A4FE 0x318E # 0 +0x0000A5A1 0x2170 # 0 +0x0000A5A2 0x2171 # 0 +0x0000A5A3 0x2172 # 0 +0x0000A5A4 0x2173 # 0 +0x0000A5A5 0x2174 # 0 +0x0000A5A6 0x2175 # 0 +0x0000A5A7 0x2176 # 0 +0x0000A5A8 0x2177 # 0 +0x0000A5A9 0x2178 # 0 +0x0000A5AA 0x2179 # 0 +0x0000A5B0 0x2160 # 0 +0x0000A5B1 0x2161 # 0 +0x0000A5B2 0x2162 # 0 +0x0000A5B3 0x2163 # 0 +0x0000A5B4 0x2164 # 0 +0x0000A5B5 0x2165 # 0 +0x0000A5B6 0x2166 # 0 +0x0000A5B7 0x2167 # 0 +0x0000A5B8 0x2168 # 0 +0x0000A5B9 0x2169 # 0 +0x0000A6A1 0x2500 # 0 +0x0000A6A2 0x2502 # 0 +0x0000A6A3 0x250C # 0 +0x0000A6A4 0x2510 # 0 +0x0000A6A5 0x2518 # 0 +0x0000A6A6 0x2514 # 0 +0x0000A6A7 0x251C # 0 +0x0000A6A8 0x252C # 0 +0x0000A6A9 0x2524 # 0 +0x0000A6AA 0x2534 # 0 +0x0000A6AB 0x253C # 0 +0x0000A6AC 0x2501 # 0 +0x0000A6AD 0x2503 # 0 +0x0000A6AE 0x250F # 0 +0x0000A6AF 0x2513 # 0 +0x0000A6B0 0x251B # 0 +0x0000A6B1 0x2517 # 0 +0x0000A6B2 0x2523 # 0 +0x0000A6B3 0x2533 # 0 +0x0000A6B4 0x252B # 0 +0x0000A6B5 0x253B # 0 +0x0000A6B6 0x254B # 0 +0x0000A6B7 0x2520 # 0 +0x0000A6B8 0x252F # 0 +0x0000A6B9 0x2528 # 0 +0x0000A6BA 0x2537 # 0 +0x0000A6BB 0x253F # 0 +0x0000A6BC 0x251D # 0 +0x0000A6BD 0x2530 # 0 +0x0000A6BE 0x2525 # 0 +0x0000A6BF 0x2538 # 0 +0x0000A6C0 0x2542 # 0 +0x0000A6C1 0x2512 # 0 +0x0000A6C2 0x2511 # 0 +0x0000A6C3 0x251A # 0 +0x0000A6C4 0x2519 # 0 +0x0000A6C5 0x2516 # 0 +0x0000A6C6 0x2515 # 0 +0x0000A6C7 0x250E # 0 +0x0000A6C8 0x250D # 0 +0x0000A6C9 0x251E # 0 +0x0000A6CA 0x251F # 0 +0x0000A6CB 0x2521 # 0 +0x0000A6CC 0x2522 # 0 +0x0000A6CD 0x2526 # 0 +0x0000A6CE 0x2527 # 0 +0x0000A6CF 0x2529 # 0 +0x0000A6D0 0x252A # 0 +0x0000A6D1 0x252D # 0 +0x0000A6D2 0x252E # 0 +0x0000A6D3 0x2531 # 0 +0x0000A6D4 0x2532 # 0 +0x0000A6D5 0x2535 # 0 +0x0000A6D6 0x2536 # 0 +0x0000A6D7 0x2539 # 0 +0x0000A6D8 0x253A # 0 +0x0000A6D9 0x253D # 0 +0x0000A6DA 0x253E # 0 +0x0000A6DB 0x2540 # 0 +0x0000A6DC 0x2541 # 0 +0x0000A6DD 0x2543 # 0 +0x0000A6DE 0x2544 # 0 +0x0000A6DF 0x2545 # 0 +0x0000A6E0 0x2546 # 0 +0x0000A6E1 0x2547 # 0 +0x0000A6E2 0x2548 # 0 +0x0000A6E3 0x2549 # 0 +0x0000A6E4 0x254A # 0 +0x0000A7A1 0x3395 # 0 +0x0000A7A2 0x3396 # 0 +0x0000A7A3 0x3397 # 0 +0x0000A7A4 0x2113 # 0 +0x0000A7A5 0x3398 # 0 +0x0000A7A6 0x33C4 # 0 +0x0000A7A7 0x33A3 # 0 +0x0000A7A8 0x33A4 # 0 +0x0000A7A9 0x33A5 # 0 +0x0000A7AA 0x33A6 # 0 +0x0000A7AB 0x3399 # 0 +0x0000A7AC 0x339A # 0 +0x0000A7AD 0x339B # 0 +0x0000A7AE 0x339C # 0 +0x0000A7AF 0x339D # 0 +0x0000A7B0 0x339E # 0 +0x0000A7B1 0x339F # 0 +0x0000A7B2 0x33A0 # 0 +0x0000A7B3 0x33A1 # 0 +0x0000A7B4 0x33A2 # 0 +0x0000A7B5 0x33CA # 0 +0x0000A7B6 0x338D # 0 +0x0000A7B7 0x338E # 0 +0x0000A7B8 0x338F # 0 +0x0000A7B9 0x33CF # 0 +0x0000A7BA 0x3388 # 0 +0x0000A7BB 0x3389 # 0 +0x0000A7BC 0x33C8 # 0 +0x0000A7BD 0x33A7 # 0 +0x0000A7BE 0x33A8 # 0 +0x0000A7BF 0x33B0 # 0 +0x0000A7C0 0x33B1 # 0 +0x0000A7C1 0x33B2 # 0 +0x0000A7C2 0x33B3 # 0 +0x0000A7C3 0x33B4 # 0 +0x0000A7C4 0x33B5 # 0 +0x0000A7C5 0x33B6 # 0 +0x0000A7C6 0x33B7 # 0 +0x0000A7C7 0x33B8 # 0 +0x0000A7C8 0x33B9 # 0 +0x0000A7C9 0x3380 # 0 +0x0000A7CA 0x3381 # 0 +0x0000A7CB 0x3382 # 0 +0x0000A7CC 0x3383 # 0 +0x0000A7CD 0x3384 # 0 +0x0000A7CE 0x33BA # 0 +0x0000A7CF 0x33BB # 0 +0x0000A7D0 0x33BC # 0 +0x0000A7D1 0x33BD # 0 +0x0000A7D2 0x33BE # 0 +0x0000A7D3 0x33BF # 0 +0x0000A7D4 0x3390 # 0 +0x0000A7D5 0x3391 # 0 +0x0000A7D6 0x3392 # 0 +0x0000A7D7 0x3393 # 0 +0x0000A7D8 0x3394 # 0 +0x0000A7D9 0x2126 # 0 +0x0000A7DA 0x33C0 # 0 +0x0000A7DB 0x33C1 # 0 +0x0000A7DC 0x338A # 0 +0x0000A7DD 0x338B # 0 +0x0000A7DE 0x338C # 0 +0x0000A7DF 0x33D6 # 0 +0x0000A7E0 0x33C5 # 0 +0x0000A7E1 0x33AD # 0 +0x0000A7E2 0x33AE # 0 +0x0000A7E3 0x33AF # 0 +0x0000A7E4 0x33DB # 0 +0x0000A7E5 0x33A9 # 0 +0x0000A7E6 0x33AA # 0 +0x0000A7E7 0x33AB # 0 +0x0000A7E8 0x33AC # 0 +0x0000A7E9 0x33DD # 0 +0x0000A7EA 0x33D0 # 0 +0x0000A7EB 0x33D3 # 0 +0x0000A7EC 0x33C3 # 0 +0x0000A7ED 0x33C9 # 0 +0x0000A7EE 0x33DC # 0 +0x0000A7EF 0x33C6 # 0 +0x0000A8B1 0x3260 # 0 +0x0000A8B2 0x3261 # 0 +0x0000A8B3 0x3262 # 0 +0x0000A8B4 0x3263 # 0 +0x0000A8B5 0x3264 # 0 +0x0000A8B6 0x3265 # 0 +0x0000A8B7 0x3266 # 0 +0x0000A8B8 0x3267 # 0 +0x0000A8B9 0x3268 # 0 +0x0000A8BA 0x3269 # 0 +0x0000A8BB 0x326A # 0 +0x0000A8BC 0x326B # 0 +0x0000A8BD 0x326C # 0 +0x0000A8BE 0x326D # 0 +0x0000A8BF 0x326E # 0 +0x0000A8C0 0x326F # 0 +0x0000A8C1 0x3270 # 0 +0x0000A8C2 0x3271 # 0 +0x0000A8C3 0x3272 # 0 +0x0000A8C4 0x3273 # 0 +0x0000A8C5 0x3274 # 0 +0x0000A8C6 0x3275 # 0 +0x0000A8C7 0x3276 # 0 +0x0000A8C8 0x3277 # 0 +0x0000A8C9 0x3278 # 0 +0x0000A8CA 0x3279 # 0 +0x0000A8CB 0x327A # 0 +0x0000A8CC 0x327B # 0 +0x0000A8CD 0x24D0 # 0 +0x0000A8CE 0x24D1 # 0 +0x0000A8CF 0x24D2 # 0 +0x0000A8D0 0x24D3 # 0 +0x0000A8D1 0x24D4 # 0 +0x0000A8D2 0x24D5 # 0 +0x0000A8D3 0x24D6 # 0 +0x0000A8D4 0x24D7 # 0 +0x0000A8D5 0x24D8 # 0 +0x0000A8D6 0x24D9 # 0 +0x0000A8D7 0x24DA # 0 +0x0000A8D8 0x24DB # 0 +0x0000A8D9 0x24DC # 0 +0x0000A8DA 0x24DD # 0 +0x0000A8DB 0x24DE # 0 +0x0000A8DC 0x24DF # 0 +0x0000A8DD 0x24E0 # 0 +0x0000A8DE 0x24E1 # 0 +0x0000A8DF 0x24E2 # 0 +0x0000A8E0 0x24E3 # 0 +0x0000A8E1 0x24E4 # 0 +0x0000A8E2 0x24E5 # 0 +0x0000A8E3 0x24E6 # 0 +0x0000A8E4 0x24E7 # 0 +0x0000A8E5 0x24E8 # 0 +0x0000A8E6 0x24E9 # 0 +0x0000A8E7 0x2460 # 0 +0x0000A8E8 0x2461 # 0 +0x0000A8E9 0x2462 # 0 +0x0000A8EA 0x2463 # 0 +0x0000A8EB 0x2464 # 0 +0x0000A8EC 0x2465 # 0 +0x0000A8ED 0x2466 # 0 +0x0000A8EE 0x2467 # 0 +0x0000A8EF 0x2468 # 0 +0x0000A8F0 0x2469 # 0 +0x0000A8F1 0x246A # 0 +0x0000A8F2 0x246B # 0 +0x0000A8F3 0x246C # 0 +0x0000A8F4 0x246D # 0 +0x0000A8F5 0x246E # 0 +0x0000A8F7 0x2153 # 0 +0x0000A8F8 0x2154 # 0 +0x0000A8FB 0x215B # 0 +0x0000A8FC 0x215C # 0 +0x0000A8FD 0x215D # 0 +0x0000A8FE 0x215E # 0 +0x0000A9B1 0x3200 # 0 +0x0000A9B2 0x3201 # 0 +0x0000A9B3 0x3202 # 0 +0x0000A9B4 0x3203 # 0 +0x0000A9B5 0x3204 # 0 +0x0000A9B6 0x3205 # 0 +0x0000A9B7 0x3206 # 0 +0x0000A9B8 0x3207 # 0 +0x0000A9B9 0x3208 # 0 +0x0000A9BA 0x3209 # 0 +0x0000A9BB 0x320A # 0 +0x0000A9BC 0x320B # 0 +0x0000A9BD 0x320C # 0 +0x0000A9BE 0x320D # 0 +0x0000A9BF 0x320E # 0 +0x0000A9C0 0x320F # 0 +0x0000A9C1 0x3210 # 0 +0x0000A9C2 0x3211 # 0 +0x0000A9C3 0x3212 # 0 +0x0000A9C4 0x3213 # 0 +0x0000A9C5 0x3214 # 0 +0x0000A9C6 0x3215 # 0 +0x0000A9C7 0x3216 # 0 +0x0000A9C8 0x3217 # 0 +0x0000A9C9 0x3218 # 0 +0x0000A9CA 0x3219 # 0 +0x0000A9CB 0x321A # 0 +0x0000A9CC 0x321B # 0 +0x0000A9CD 0x249C # 0 +0x0000A9CE 0x249D # 0 +0x0000A9CF 0x249E # 0 +0x0000A9D0 0x249F # 0 +0x0000A9D1 0x24A0 # 0 +0x0000A9D2 0x24A1 # 0 +0x0000A9D3 0x24A2 # 0 +0x0000A9D4 0x24A3 # 0 +0x0000A9D5 0x24A4 # 0 +0x0000A9D6 0x24A5 # 0 +0x0000A9D7 0x24A6 # 0 +0x0000A9D8 0x24A7 # 0 +0x0000A9D9 0x24A8 # 0 +0x0000A9DA 0x24A9 # 0 +0x0000A9DB 0x24AA # 0 +0x0000A9DC 0x24AB # 0 +0x0000A9DD 0x24AC # 0 +0x0000A9DE 0x24AD # 0 +0x0000A9DF 0x24AE # 0 +0x0000A9E0 0x24AF # 0 +0x0000A9E1 0x24B0 # 0 +0x0000A9E2 0x24B1 # 0 +0x0000A9E3 0x24B2 # 0 +0x0000A9E4 0x24B3 # 0 +0x0000A9E5 0x24B4 # 0 +0x0000A9E6 0x24B5 # 0 +0x0000A9E7 0x2474 # 0 +0x0000A9E8 0x2475 # 0 +0x0000A9E9 0x2476 # 0 +0x0000A9EA 0x2477 # 0 +0x0000A9EB 0x2478 # 0 +0x0000A9EC 0x2479 # 0 +0x0000A9ED 0x247A # 0 +0x0000A9EE 0x247B # 0 +0x0000A9EF 0x247C # 0 +0x0000A9F0 0x247D # 0 +0x0000A9F1 0x247E # 0 +0x0000A9F2 0x247F # 0 +0x0000A9F3 0x2480 # 0 +0x0000A9F4 0x2481 # 0 +0x0000A9F5 0x2482 # 0 +0x0000A9F9 0x2074 # 0 +0x0000A9FA 0x207F # 0 +0x0000A9FB 0x2081 # 0 +0x0000A9FC 0x2082 # 0 +0x0000A9FD 0x2083 # 0 +0x0000A9FE 0x2084 # 0 +0x0000AAA1 0x3041 # 0 +0x0000AAA2 0x3042 # 0 +0x0000AAA3 0x3043 # 0 +0x0000AAA4 0x3044 # 0 +0x0000AAA5 0x3045 # 0 +0x0000AAA6 0x3046 # 0 +0x0000AAA7 0x3047 # 0 +0x0000AAA8 0x3048 # 0 +0x0000AAA9 0x3049 # 0 +0x0000AAAA 0x304A # 0 +0x0000AAAB 0x304B # 0 +0x0000AAAC 0x304C # 0 +0x0000AAAD 0x304D # 0 +0x0000AAAE 0x304E # 0 +0x0000AAAF 0x304F # 0 +0x0000AAB0 0x3050 # 0 +0x0000AAB1 0x3051 # 0 +0x0000AAB2 0x3052 # 0 +0x0000AAB3 0x3053 # 0 +0x0000AAB4 0x3054 # 0 +0x0000AAB5 0x3055 # 0 +0x0000AAB6 0x3056 # 0 +0x0000AAB7 0x3057 # 0 +0x0000AAB8 0x3058 # 0 +0x0000AAB9 0x3059 # 0 +0x0000AABA 0x305A # 0 +0x0000AABB 0x305B # 0 +0x0000AABC 0x305C # 0 +0x0000AABD 0x305D # 0 +0x0000AABE 0x305E # 0 +0x0000AABF 0x305F # 0 +0x0000AAC0 0x3060 # 0 +0x0000AAC1 0x3061 # 0 +0x0000AAC2 0x3062 # 0 +0x0000AAC3 0x3063 # 0 +0x0000AAC4 0x3064 # 0 +0x0000AAC5 0x3065 # 0 +0x0000AAC6 0x3066 # 0 +0x0000AAC7 0x3067 # 0 +0x0000AAC8 0x3068 # 0 +0x0000AAC9 0x3069 # 0 +0x0000AACA 0x306A # 0 +0x0000AACB 0x306B # 0 +0x0000AACC 0x306C # 0 +0x0000AACD 0x306D # 0 +0x0000AACE 0x306E # 0 +0x0000AACF 0x306F # 0 +0x0000AAD0 0x3070 # 0 +0x0000AAD1 0x3071 # 0 +0x0000AAD2 0x3072 # 0 +0x0000AAD3 0x3073 # 0 +0x0000AAD4 0x3074 # 0 +0x0000AAD5 0x3075 # 0 +0x0000AAD6 0x3076 # 0 +0x0000AAD7 0x3077 # 0 +0x0000AAD8 0x3078 # 0 +0x0000AAD9 0x3079 # 0 +0x0000AADA 0x307A # 0 +0x0000AADB 0x307B # 0 +0x0000AADC 0x307C # 0 +0x0000AADD 0x307D # 0 +0x0000AADE 0x307E # 0 +0x0000AADF 0x307F # 0 +0x0000AAE0 0x3080 # 0 +0x0000AAE1 0x3081 # 0 +0x0000AAE2 0x3082 # 0 +0x0000AAE3 0x3083 # 0 +0x0000AAE4 0x3084 # 0 +0x0000AAE5 0x3085 # 0 +0x0000AAE6 0x3086 # 0 +0x0000AAE7 0x3087 # 0 +0x0000AAE8 0x3088 # 0 +0x0000AAE9 0x3089 # 0 +0x0000AAEA 0x308A # 0 +0x0000AAEB 0x308B # 0 +0x0000AAEC 0x308C # 0 +0x0000AAED 0x308D # 0 +0x0000AAEE 0x308E # 0 +0x0000AAEF 0x308F # 0 +0x0000AAF0 0x3090 # 0 +0x0000AAF1 0x3091 # 0 +0x0000AAF2 0x3092 # 0 +0x0000AAF3 0x3093 # 0 +0x0000ABA1 0x30A1 # 0 +0x0000ABA2 0x30A2 # 0 +0x0000ABA3 0x30A3 # 0 +0x0000ABA4 0x30A4 # 0 +0x0000ABA5 0x30A5 # 0 +0x0000ABA6 0x30A6 # 0 +0x0000ABA7 0x30A7 # 0 +0x0000ABA8 0x30A8 # 0 +0x0000ABA9 0x30A9 # 0 +0x0000ABAA 0x30AA # 0 +0x0000ABAB 0x30AB # 0 +0x0000ABAC 0x30AC # 0 +0x0000ABAD 0x30AD # 0 +0x0000ABAE 0x30AE # 0 +0x0000ABAF 0x30AF # 0 +0x0000ABB0 0x30B0 # 0 +0x0000ABB1 0x30B1 # 0 +0x0000ABB2 0x30B2 # 0 +0x0000ABB3 0x30B3 # 0 +0x0000ABB4 0x30B4 # 0 +0x0000ABB5 0x30B5 # 0 +0x0000ABB6 0x30B6 # 0 +0x0000ABB7 0x30B7 # 0 +0x0000ABB8 0x30B8 # 0 +0x0000ABB9 0x30B9 # 0 +0x0000ABBA 0x30BA # 0 +0x0000ABBB 0x30BB # 0 +0x0000ABBC 0x30BC # 0 +0x0000ABBD 0x30BD # 0 +0x0000ABBE 0x30BE # 0 +0x0000ABBF 0x30BF # 0 +0x0000ABC0 0x30C0 # 0 +0x0000ABC1 0x30C1 # 0 +0x0000ABC2 0x30C2 # 0 +0x0000ABC3 0x30C3 # 0 +0x0000ABC4 0x30C4 # 0 +0x0000ABC5 0x30C5 # 0 +0x0000ABC6 0x30C6 # 0 +0x0000ABC7 0x30C7 # 0 +0x0000ABC8 0x30C8 # 0 +0x0000ABC9 0x30C9 # 0 +0x0000ABCA 0x30CA # 0 +0x0000ABCB 0x30CB # 0 +0x0000ABCC 0x30CC # 0 +0x0000ABCD 0x30CD # 0 +0x0000ABCE 0x30CE # 0 +0x0000ABCF 0x30CF # 0 +0x0000ABD0 0x30D0 # 0 +0x0000ABD1 0x30D1 # 0 +0x0000ABD2 0x30D2 # 0 +0x0000ABD3 0x30D3 # 0 +0x0000ABD4 0x30D4 # 0 +0x0000ABD5 0x30D5 # 0 +0x0000ABD6 0x30D6 # 0 +0x0000ABD7 0x30D7 # 0 +0x0000ABD8 0x30D8 # 0 +0x0000ABD9 0x30D9 # 0 +0x0000ABDA 0x30DA # 0 +0x0000ABDB 0x30DB # 0 +0x0000ABDC 0x30DC # 0 +0x0000ABDD 0x30DD # 0 +0x0000ABDE 0x30DE # 0 +0x0000ABDF 0x30DF # 0 +0x0000ABE0 0x30E0 # 0 +0x0000ABE1 0x30E1 # 0 +0x0000ABE2 0x30E2 # 0 +0x0000ABE3 0x30E3 # 0 +0x0000ABE4 0x30E4 # 0 +0x0000ABE5 0x30E5 # 0 +0x0000ABE6 0x30E6 # 0 +0x0000ABE7 0x30E7 # 0 +0x0000ABE8 0x30E8 # 0 +0x0000ABE9 0x30E9 # 0 +0x0000ABEA 0x30EA # 0 +0x0000ABEB 0x30EB # 0 +0x0000ABEC 0x30EC # 0 +0x0000ABED 0x30ED # 0 +0x0000ABEE 0x30EE # 0 +0x0000ABEF 0x30EF # 0 +0x0000ABF0 0x30F0 # 0 +0x0000ABF1 0x30F1 # 0 +0x0000ABF2 0x30F2 # 0 +0x0000ABF3 0x30F3 # 0 +0x0000ABF4 0x30F4 # 0 +0x0000ABF5 0x30F5 # 0 +0x0000ABF6 0x30F6 # 0 +0x0000B0A1 0xAC00 # 0 +0x0000B0A2 0xAC01 # 0 +0x0000B0A3 0xAC04 # 0 +0x0000B0A4 0xAC07 # 0 +0x0000B0A5 0xAC08 # 0 +0x0000B0A6 0xAC09 # 0 +0x0000B0A7 0xAC0A # 0 +0x0000B0A8 0xAC10 # 0 +0x0000B0A9 0xAC11 # 0 +0x0000B0AA 0xAC12 # 0 +0x0000B0AB 0xAC13 # 0 +0x0000B0AC 0xAC14 # 0 +0x0000B0AD 0xAC15 # 0 +0x0000B0AE 0xAC16 # 0 +0x0000B0AF 0xAC17 # 0 +0x0000B0B0 0xAC19 # 0 +0x0000B0B1 0xAC1A # 0 +0x0000B0B2 0xAC1B # 0 +0x0000B0B3 0xAC1C # 0 +0x0000B0B4 0xAC1D # 0 +0x0000B0B5 0xAC20 # 0 +0x0000B0B6 0xAC24 # 0 +0x0000B0B7 0xAC2C # 0 +0x0000B0B8 0xAC2D # 0 +0x0000B0B9 0xAC2F # 0 +0x0000B0BA 0xAC30 # 0 +0x0000B0BB 0xAC31 # 0 +0x0000B0BC 0xAC38 # 0 +0x0000B0BD 0xAC39 # 0 +0x0000B0BE 0xAC3C # 0 +0x0000B0BF 0xAC40 # 0 +0x0000B0C0 0xAC4B # 0 +0x0000B0C1 0xAC4D # 0 +0x0000B0C2 0xAC54 # 0 +0x0000B0C3 0xAC58 # 0 +0x0000B0C4 0xAC5C # 0 +0x0000B0C5 0xAC70 # 0 +0x0000B0C6 0xAC71 # 0 +0x0000B0C7 0xAC74 # 0 +0x0000B0C8 0xAC77 # 0 +0x0000B0C9 0xAC78 # 0 +0x0000B0CA 0xAC7A # 0 +0x0000B0CB 0xAC80 # 0 +0x0000B0CC 0xAC81 # 0 +0x0000B0CD 0xAC83 # 0 +0x0000B0CE 0xAC84 # 0 +0x0000B0CF 0xAC85 # 0 +0x0000B0D0 0xAC86 # 0 +0x0000B0D1 0xAC89 # 0 +0x0000B0D2 0xAC8A # 0 +0x0000B0D3 0xAC8B # 0 +0x0000B0D4 0xAC8C # 0 +0x0000B0D5 0xAC90 # 0 +0x0000B0D6 0xAC94 # 0 +0x0000B0D7 0xAC9C # 0 +0x0000B0D8 0xAC9D # 0 +0x0000B0D9 0xAC9F # 0 +0x0000B0DA 0xACA0 # 0 +0x0000B0DB 0xACA1 # 0 +0x0000B0DC 0xACA8 # 0 +0x0000B0DD 0xACA9 # 0 +0x0000B0DE 0xACAA # 0 +0x0000B0DF 0xACAC # 0 +0x0000B0E0 0xACAF # 0 +0x0000B0E1 0xACB0 # 0 +0x0000B0E2 0xACB8 # 0 +0x0000B0E3 0xACB9 # 0 +0x0000B0E4 0xACBB # 0 +0x0000B0E5 0xACBC # 0 +0x0000B0E6 0xACBD # 0 +0x0000B0E7 0xACC1 # 0 +0x0000B0E8 0xACC4 # 0 +0x0000B0E9 0xACC8 # 0 +0x0000B0EA 0xACCC # 0 +0x0000B0EB 0xACD5 # 0 +0x0000B0EC 0xACD7 # 0 +0x0000B0ED 0xACE0 # 0 +0x0000B0EE 0xACE1 # 0 +0x0000B0EF 0xACE4 # 0 +0x0000B0F0 0xACE7 # 0 +0x0000B0F1 0xACE8 # 0 +0x0000B0F2 0xACEA # 0 +0x0000B0F3 0xACEC # 0 +0x0000B0F4 0xACEF # 0 +0x0000B0F5 0xACF0 # 0 +0x0000B0F6 0xACF1 # 0 +0x0000B0F7 0xACF3 # 0 +0x0000B0F8 0xACF5 # 0 +0x0000B0F9 0xACF6 # 0 +0x0000B0FA 0xACFC # 0 +0x0000B0FB 0xACFD # 0 +0x0000B0FC 0xAD00 # 0 +0x0000B0FD 0xAD04 # 0 +0x0000B0FE 0xAD06 # 0 +0x0000B1A1 0xAD0C # 0 +0x0000B1A2 0xAD0D # 0 +0x0000B1A3 0xAD0F # 0 +0x0000B1A4 0xAD11 # 0 +0x0000B1A5 0xAD18 # 0 +0x0000B1A6 0xAD1C # 0 +0x0000B1A7 0xAD20 # 0 +0x0000B1A8 0xAD29 # 0 +0x0000B1A9 0xAD2C # 0 +0x0000B1AA 0xAD2D # 0 +0x0000B1AB 0xAD34 # 0 +0x0000B1AC 0xAD35 # 0 +0x0000B1AD 0xAD38 # 0 +0x0000B1AE 0xAD3C # 0 +0x0000B1AF 0xAD44 # 0 +0x0000B1B0 0xAD45 # 0 +0x0000B1B1 0xAD47 # 0 +0x0000B1B2 0xAD49 # 0 +0x0000B1B3 0xAD50 # 0 +0x0000B1B4 0xAD54 # 0 +0x0000B1B5 0xAD58 # 0 +0x0000B1B6 0xAD61 # 0 +0x0000B1B7 0xAD63 # 0 +0x0000B1B8 0xAD6C # 0 +0x0000B1B9 0xAD6D # 0 +0x0000B1BA 0xAD70 # 0 +0x0000B1BB 0xAD73 # 0 +0x0000B1BC 0xAD74 # 0 +0x0000B1BD 0xAD75 # 0 +0x0000B1BE 0xAD76 # 0 +0x0000B1BF 0xAD7B # 0 +0x0000B1C0 0xAD7C # 0 +0x0000B1C1 0xAD7D # 0 +0x0000B1C2 0xAD7F # 0 +0x0000B1C3 0xAD81 # 0 +0x0000B1C4 0xAD82 # 0 +0x0000B1C5 0xAD88 # 0 +0x0000B1C6 0xAD89 # 0 +0x0000B1C7 0xAD8C # 0 +0x0000B1C8 0xAD90 # 0 +0x0000B1C9 0xAD9C # 0 +0x0000B1CA 0xAD9D # 0 +0x0000B1CB 0xADA4 # 0 +0x0000B1CC 0xADB7 # 0 +0x0000B1CD 0xADC0 # 0 +0x0000B1CE 0xADC1 # 0 +0x0000B1CF 0xADC4 # 0 +0x0000B1D0 0xADC8 # 0 +0x0000B1D1 0xADD0 # 0 +0x0000B1D2 0xADD1 # 0 +0x0000B1D3 0xADD3 # 0 +0x0000B1D4 0xADDC # 0 +0x0000B1D5 0xADE0 # 0 +0x0000B1D6 0xADE4 # 0 +0x0000B1D7 0xADF8 # 0 +0x0000B1D8 0xADF9 # 0 +0x0000B1D9 0xADFC # 0 +0x0000B1DA 0xADFF # 0 +0x0000B1DB 0xAE00 # 0 +0x0000B1DC 0xAE01 # 0 +0x0000B1DD 0xAE08 # 0 +0x0000B1DE 0xAE09 # 0 +0x0000B1DF 0xAE0B # 0 +0x0000B1E0 0xAE0D # 0 +0x0000B1E1 0xAE14 # 0 +0x0000B1E2 0xAE30 # 0 +0x0000B1E3 0xAE31 # 0 +0x0000B1E4 0xAE34 # 0 +0x0000B1E5 0xAE37 # 0 +0x0000B1E6 0xAE38 # 0 +0x0000B1E7 0xAE3A # 0 +0x0000B1E8 0xAE40 # 0 +0x0000B1E9 0xAE41 # 0 +0x0000B1EA 0xAE43 # 0 +0x0000B1EB 0xAE45 # 0 +0x0000B1EC 0xAE46 # 0 +0x0000B1ED 0xAE4A # 0 +0x0000B1EE 0xAE4C # 0 +0x0000B1EF 0xAE4D # 0 +0x0000B1F0 0xAE4E # 0 +0x0000B1F1 0xAE50 # 0 +0x0000B1F2 0xAE54 # 0 +0x0000B1F3 0xAE56 # 0 +0x0000B1F4 0xAE5C # 0 +0x0000B1F5 0xAE5D # 0 +0x0000B1F6 0xAE5F # 0 +0x0000B1F7 0xAE60 # 0 +0x0000B1F8 0xAE61 # 0 +0x0000B1F9 0xAE65 # 0 +0x0000B1FA 0xAE68 # 0 +0x0000B1FB 0xAE69 # 0 +0x0000B1FC 0xAE6C # 0 +0x0000B1FD 0xAE70 # 0 +0x0000B1FE 0xAE78 # 0 +0x0000B2A1 0xAE79 # 0 +0x0000B2A2 0xAE7B # 0 +0x0000B2A3 0xAE7C # 0 +0x0000B2A4 0xAE7D # 0 +0x0000B2A5 0xAE84 # 0 +0x0000B2A6 0xAE85 # 0 +0x0000B2A7 0xAE8C # 0 +0x0000B2A8 0xAEBC # 0 +0x0000B2A9 0xAEBD # 0 +0x0000B2AA 0xAEBE # 0 +0x0000B2AB 0xAEC0 # 0 +0x0000B2AC 0xAEC4 # 0 +0x0000B2AD 0xAECC # 0 +0x0000B2AE 0xAECD # 0 +0x0000B2AF 0xAECF # 0 +0x0000B2B0 0xAED0 # 0 +0x0000B2B1 0xAED1 # 0 +0x0000B2B2 0xAED8 # 0 +0x0000B2B3 0xAED9 # 0 +0x0000B2B4 0xAEDC # 0 +0x0000B2B5 0xAEE8 # 0 +0x0000B2B6 0xAEEB # 0 +0x0000B2B7 0xAEED # 0 +0x0000B2B8 0xAEF4 # 0 +0x0000B2B9 0xAEF8 # 0 +0x0000B2BA 0xAEFC # 0 +0x0000B2BB 0xAF07 # 0 +0x0000B2BC 0xAF08 # 0 +0x0000B2BD 0xAF0D # 0 +0x0000B2BE 0xAF10 # 0 +0x0000B2BF 0xAF2C # 0 +0x0000B2C0 0xAF2D # 0 +0x0000B2C1 0xAF30 # 0 +0x0000B2C2 0xAF32 # 0 +0x0000B2C3 0xAF34 # 0 +0x0000B2C4 0xAF3C # 0 +0x0000B2C5 0xAF3D # 0 +0x0000B2C6 0xAF3F # 0 +0x0000B2C7 0xAF41 # 0 +0x0000B2C8 0xAF42 # 0 +0x0000B2C9 0xAF43 # 0 +0x0000B2CA 0xAF48 # 0 +0x0000B2CB 0xAF49 # 0 +0x0000B2CC 0xAF50 # 0 +0x0000B2CD 0xAF5C # 0 +0x0000B2CE 0xAF5D # 0 +0x0000B2CF 0xAF64 # 0 +0x0000B2D0 0xAF65 # 0 +0x0000B2D1 0xAF79 # 0 +0x0000B2D2 0xAF80 # 0 +0x0000B2D3 0xAF84 # 0 +0x0000B2D4 0xAF88 # 0 +0x0000B2D5 0xAF90 # 0 +0x0000B2D6 0xAF91 # 0 +0x0000B2D7 0xAF95 # 0 +0x0000B2D8 0xAF9C # 0 +0x0000B2D9 0xAFB8 # 0 +0x0000B2DA 0xAFB9 # 0 +0x0000B2DB 0xAFBC # 0 +0x0000B2DC 0xAFC0 # 0 +0x0000B2DD 0xAFC7 # 0 +0x0000B2DE 0xAFC8 # 0 +0x0000B2DF 0xAFC9 # 0 +0x0000B2E0 0xAFCB # 0 +0x0000B2E1 0xAFCD # 0 +0x0000B2E2 0xAFCE # 0 +0x0000B2E3 0xAFD4 # 0 +0x0000B2E4 0xAFDC # 0 +0x0000B2E5 0xAFE8 # 0 +0x0000B2E6 0xAFE9 # 0 +0x0000B2E7 0xAFF0 # 0 +0x0000B2E8 0xAFF1 # 0 +0x0000B2E9 0xAFF4 # 0 +0x0000B2EA 0xAFF8 # 0 +0x0000B2EB 0xB000 # 0 +0x0000B2EC 0xB001 # 0 +0x0000B2ED 0xB004 # 0 +0x0000B2EE 0xB00C # 0 +0x0000B2EF 0xB010 # 0 +0x0000B2F0 0xB014 # 0 +0x0000B2F1 0xB01C # 0 +0x0000B2F2 0xB01D # 0 +0x0000B2F3 0xB028 # 0 +0x0000B2F4 0xB044 # 0 +0x0000B2F5 0xB045 # 0 +0x0000B2F6 0xB048 # 0 +0x0000B2F7 0xB04A # 0 +0x0000B2F8 0xB04C # 0 +0x0000B2F9 0xB04E # 0 +0x0000B2FA 0xB053 # 0 +0x0000B2FB 0xB054 # 0 +0x0000B2FC 0xB055 # 0 +0x0000B2FD 0xB057 # 0 +0x0000B2FE 0xB059 # 0 +0x0000B3A1 0xB05D # 0 +0x0000B3A2 0xB07C # 0 +0x0000B3A3 0xB07D # 0 +0x0000B3A4 0xB080 # 0 +0x0000B3A5 0xB084 # 0 +0x0000B3A6 0xB08C # 0 +0x0000B3A7 0xB08D # 0 +0x0000B3A8 0xB08F # 0 +0x0000B3A9 0xB091 # 0 +0x0000B3AA 0xB098 # 0 +0x0000B3AB 0xB099 # 0 +0x0000B3AC 0xB09A # 0 +0x0000B3AD 0xB09C # 0 +0x0000B3AE 0xB09F # 0 +0x0000B3AF 0xB0A0 # 0 +0x0000B3B0 0xB0A1 # 0 +0x0000B3B1 0xB0A2 # 0 +0x0000B3B2 0xB0A8 # 0 +0x0000B3B3 0xB0A9 # 0 +0x0000B3B4 0xB0AB # 0 +0x0000B3B5 0xB0AC # 0 +0x0000B3B6 0xB0AD # 0 +0x0000B3B7 0xB0AE # 0 +0x0000B3B8 0xB0AF # 0 +0x0000B3B9 0xB0B1 # 0 +0x0000B3BA 0xB0B3 # 0 +0x0000B3BB 0xB0B4 # 0 +0x0000B3BC 0xB0B5 # 0 +0x0000B3BD 0xB0B8 # 0 +0x0000B3BE 0xB0BC # 0 +0x0000B3BF 0xB0C4 # 0 +0x0000B3C0 0xB0C5 # 0 +0x0000B3C1 0xB0C7 # 0 +0x0000B3C2 0xB0C8 # 0 +0x0000B3C3 0xB0C9 # 0 +0x0000B3C4 0xB0D0 # 0 +0x0000B3C5 0xB0D1 # 0 +0x0000B3C6 0xB0D4 # 0 +0x0000B3C7 0xB0D8 # 0 +0x0000B3C8 0xB0E0 # 0 +0x0000B3C9 0xB0E5 # 0 +0x0000B3CA 0xB108 # 0 +0x0000B3CB 0xB109 # 0 +0x0000B3CC 0xB10B # 0 +0x0000B3CD 0xB10C # 0 +0x0000B3CE 0xB110 # 0 +0x0000B3CF 0xB112 # 0 +0x0000B3D0 0xB113 # 0 +0x0000B3D1 0xB118 # 0 +0x0000B3D2 0xB119 # 0 +0x0000B3D3 0xB11B # 0 +0x0000B3D4 0xB11C # 0 +0x0000B3D5 0xB11D # 0 +0x0000B3D6 0xB123 # 0 +0x0000B3D7 0xB124 # 0 +0x0000B3D8 0xB125 # 0 +0x0000B3D9 0xB128 # 0 +0x0000B3DA 0xB12C # 0 +0x0000B3DB 0xB134 # 0 +0x0000B3DC 0xB135 # 0 +0x0000B3DD 0xB137 # 0 +0x0000B3DE 0xB138 # 0 +0x0000B3DF 0xB139 # 0 +0x0000B3E0 0xB140 # 0 +0x0000B3E1 0xB141 # 0 +0x0000B3E2 0xB144 # 0 +0x0000B3E3 0xB148 # 0 +0x0000B3E4 0xB150 # 0 +0x0000B3E5 0xB151 # 0 +0x0000B3E6 0xB154 # 0 +0x0000B3E7 0xB155 # 0 +0x0000B3E8 0xB158 # 0 +0x0000B3E9 0xB15C # 0 +0x0000B3EA 0xB160 # 0 +0x0000B3EB 0xB178 # 0 +0x0000B3EC 0xB179 # 0 +0x0000B3ED 0xB17C # 0 +0x0000B3EE 0xB180 # 0 +0x0000B3EF 0xB182 # 0 +0x0000B3F0 0xB188 # 0 +0x0000B3F1 0xB189 # 0 +0x0000B3F2 0xB18B # 0 +0x0000B3F3 0xB18D # 0 +0x0000B3F4 0xB192 # 0 +0x0000B3F5 0xB193 # 0 +0x0000B3F6 0xB194 # 0 +0x0000B3F7 0xB198 # 0 +0x0000B3F8 0xB19C # 0 +0x0000B3F9 0xB1A8 # 0 +0x0000B3FA 0xB1CC # 0 +0x0000B3FB 0xB1D0 # 0 +0x0000B3FC 0xB1D4 # 0 +0x0000B3FD 0xB1DC # 0 +0x0000B3FE 0xB1DD # 0 +0x0000B4A1 0xB1DF # 0 +0x0000B4A2 0xB1E8 # 0 +0x0000B4A3 0xB1E9 # 0 +0x0000B4A4 0xB1EC # 0 +0x0000B4A5 0xB1F0 # 0 +0x0000B4A6 0xB1F9 # 0 +0x0000B4A7 0xB1FB # 0 +0x0000B4A8 0xB1FD # 0 +0x0000B4A9 0xB204 # 0 +0x0000B4AA 0xB205 # 0 +0x0000B4AB 0xB208 # 0 +0x0000B4AC 0xB20B # 0 +0x0000B4AD 0xB20C # 0 +0x0000B4AE 0xB214 # 0 +0x0000B4AF 0xB215 # 0 +0x0000B4B0 0xB217 # 0 +0x0000B4B1 0xB219 # 0 +0x0000B4B2 0xB220 # 0 +0x0000B4B3 0xB234 # 0 +0x0000B4B4 0xB23C # 0 +0x0000B4B5 0xB258 # 0 +0x0000B4B6 0xB25C # 0 +0x0000B4B7 0xB260 # 0 +0x0000B4B8 0xB268 # 0 +0x0000B4B9 0xB269 # 0 +0x0000B4BA 0xB274 # 0 +0x0000B4BB 0xB275 # 0 +0x0000B4BC 0xB27C # 0 +0x0000B4BD 0xB284 # 0 +0x0000B4BE 0xB285 # 0 +0x0000B4BF 0xB289 # 0 +0x0000B4C0 0xB290 # 0 +0x0000B4C1 0xB291 # 0 +0x0000B4C2 0xB294 # 0 +0x0000B4C3 0xB298 # 0 +0x0000B4C4 0xB299 # 0 +0x0000B4C5 0xB29A # 0 +0x0000B4C6 0xB2A0 # 0 +0x0000B4C7 0xB2A1 # 0 +0x0000B4C8 0xB2A3 # 0 +0x0000B4C9 0xB2A5 # 0 +0x0000B4CA 0xB2A6 # 0 +0x0000B4CB 0xB2AA # 0 +0x0000B4CC 0xB2AC # 0 +0x0000B4CD 0xB2B0 # 0 +0x0000B4CE 0xB2B4 # 0 +0x0000B4CF 0xB2C8 # 0 +0x0000B4D0 0xB2C9 # 0 +0x0000B4D1 0xB2CC # 0 +0x0000B4D2 0xB2D0 # 0 +0x0000B4D3 0xB2D2 # 0 +0x0000B4D4 0xB2D8 # 0 +0x0000B4D5 0xB2D9 # 0 +0x0000B4D6 0xB2DB # 0 +0x0000B4D7 0xB2DD # 0 +0x0000B4D8 0xB2E2 # 0 +0x0000B4D9 0xB2E4 # 0 +0x0000B4DA 0xB2E5 # 0 +0x0000B4DB 0xB2E6 # 0 +0x0000B4DC 0xB2E8 # 0 +0x0000B4DD 0xB2EB # 0 +0x0000B4DE 0xB2EC # 0 +0x0000B4DF 0xB2ED # 0 +0x0000B4E0 0xB2EE # 0 +0x0000B4E1 0xB2EF # 0 +0x0000B4E2 0xB2F3 # 0 +0x0000B4E3 0xB2F4 # 0 +0x0000B4E4 0xB2F5 # 0 +0x0000B4E5 0xB2F7 # 0 +0x0000B4E6 0xB2F8 # 0 +0x0000B4E7 0xB2F9 # 0 +0x0000B4E8 0xB2FA # 0 +0x0000B4E9 0xB2FB # 0 +0x0000B4EA 0xB2FF # 0 +0x0000B4EB 0xB300 # 0 +0x0000B4EC 0xB301 # 0 +0x0000B4ED 0xB304 # 0 +0x0000B4EE 0xB308 # 0 +0x0000B4EF 0xB310 # 0 +0x0000B4F0 0xB311 # 0 +0x0000B4F1 0xB313 # 0 +0x0000B4F2 0xB314 # 0 +0x0000B4F3 0xB315 # 0 +0x0000B4F4 0xB31C # 0 +0x0000B4F5 0xB354 # 0 +0x0000B4F6 0xB355 # 0 +0x0000B4F7 0xB356 # 0 +0x0000B4F8 0xB358 # 0 +0x0000B4F9 0xB35B # 0 +0x0000B4FA 0xB35C # 0 +0x0000B4FB 0xB35E # 0 +0x0000B4FC 0xB35F # 0 +0x0000B4FD 0xB364 # 0 +0x0000B4FE 0xB365 # 0 +0x0000B5A1 0xB367 # 0 +0x0000B5A2 0xB369 # 0 +0x0000B5A3 0xB36B # 0 +0x0000B5A4 0xB36E # 0 +0x0000B5A5 0xB370 # 0 +0x0000B5A6 0xB371 # 0 +0x0000B5A7 0xB374 # 0 +0x0000B5A8 0xB378 # 0 +0x0000B5A9 0xB380 # 0 +0x0000B5AA 0xB381 # 0 +0x0000B5AB 0xB383 # 0 +0x0000B5AC 0xB384 # 0 +0x0000B5AD 0xB385 # 0 +0x0000B5AE 0xB38C # 0 +0x0000B5AF 0xB390 # 0 +0x0000B5B0 0xB394 # 0 +0x0000B5B1 0xB3A0 # 0 +0x0000B5B2 0xB3A1 # 0 +0x0000B5B3 0xB3A8 # 0 +0x0000B5B4 0xB3AC # 0 +0x0000B5B5 0xB3C4 # 0 +0x0000B5B6 0xB3C5 # 0 +0x0000B5B7 0xB3C8 # 0 +0x0000B5B8 0xB3CB # 0 +0x0000B5B9 0xB3CC # 0 +0x0000B5BA 0xB3CE # 0 +0x0000B5BB 0xB3D0 # 0 +0x0000B5BC 0xB3D4 # 0 +0x0000B5BD 0xB3D5 # 0 +0x0000B5BE 0xB3D7 # 0 +0x0000B5BF 0xB3D9 # 0 +0x0000B5C0 0xB3DB # 0 +0x0000B5C1 0xB3DD # 0 +0x0000B5C2 0xB3E0 # 0 +0x0000B5C3 0xB3E4 # 0 +0x0000B5C4 0xB3E8 # 0 +0x0000B5C5 0xB3FC # 0 +0x0000B5C6 0xB410 # 0 +0x0000B5C7 0xB418 # 0 +0x0000B5C8 0xB41C # 0 +0x0000B5C9 0xB420 # 0 +0x0000B5CA 0xB428 # 0 +0x0000B5CB 0xB429 # 0 +0x0000B5CC 0xB42B # 0 +0x0000B5CD 0xB434 # 0 +0x0000B5CE 0xB450 # 0 +0x0000B5CF 0xB451 # 0 +0x0000B5D0 0xB454 # 0 +0x0000B5D1 0xB458 # 0 +0x0000B5D2 0xB460 # 0 +0x0000B5D3 0xB461 # 0 +0x0000B5D4 0xB463 # 0 +0x0000B5D5 0xB465 # 0 +0x0000B5D6 0xB46C # 0 +0x0000B5D7 0xB480 # 0 +0x0000B5D8 0xB488 # 0 +0x0000B5D9 0xB49D # 0 +0x0000B5DA 0xB4A4 # 0 +0x0000B5DB 0xB4A8 # 0 +0x0000B5DC 0xB4AC # 0 +0x0000B5DD 0xB4B5 # 0 +0x0000B5DE 0xB4B7 # 0 +0x0000B5DF 0xB4B9 # 0 +0x0000B5E0 0xB4C0 # 0 +0x0000B5E1 0xB4C4 # 0 +0x0000B5E2 0xB4C8 # 0 +0x0000B5E3 0xB4D0 # 0 +0x0000B5E4 0xB4D5 # 0 +0x0000B5E5 0xB4DC # 0 +0x0000B5E6 0xB4DD # 0 +0x0000B5E7 0xB4E0 # 0 +0x0000B5E8 0xB4E3 # 0 +0x0000B5E9 0xB4E4 # 0 +0x0000B5EA 0xB4E6 # 0 +0x0000B5EB 0xB4EC # 0 +0x0000B5EC 0xB4ED # 0 +0x0000B5ED 0xB4EF # 0 +0x0000B5EE 0xB4F1 # 0 +0x0000B5EF 0xB4F8 # 0 +0x0000B5F0 0xB514 # 0 +0x0000B5F1 0xB515 # 0 +0x0000B5F2 0xB518 # 0 +0x0000B5F3 0xB51B # 0 +0x0000B5F4 0xB51C # 0 +0x0000B5F5 0xB524 # 0 +0x0000B5F6 0xB525 # 0 +0x0000B5F7 0xB527 # 0 +0x0000B5F8 0xB528 # 0 +0x0000B5F9 0xB529 # 0 +0x0000B5FA 0xB52A # 0 +0x0000B5FB 0xB530 # 0 +0x0000B5FC 0xB531 # 0 +0x0000B5FD 0xB534 # 0 +0x0000B5FE 0xB538 # 0 +0x0000B6A1 0xB540 # 0 +0x0000B6A2 0xB541 # 0 +0x0000B6A3 0xB543 # 0 +0x0000B6A4 0xB544 # 0 +0x0000B6A5 0xB545 # 0 +0x0000B6A6 0xB54B # 0 +0x0000B6A7 0xB54C # 0 +0x0000B6A8 0xB54D # 0 +0x0000B6A9 0xB550 # 0 +0x0000B6AA 0xB554 # 0 +0x0000B6AB 0xB55C # 0 +0x0000B6AC 0xB55D # 0 +0x0000B6AD 0xB55F # 0 +0x0000B6AE 0xB560 # 0 +0x0000B6AF 0xB561 # 0 +0x0000B6B0 0xB5A0 # 0 +0x0000B6B1 0xB5A1 # 0 +0x0000B6B2 0xB5A4 # 0 +0x0000B6B3 0xB5A8 # 0 +0x0000B6B4 0xB5AA # 0 +0x0000B6B5 0xB5AB # 0 +0x0000B6B6 0xB5B0 # 0 +0x0000B6B7 0xB5B1 # 0 +0x0000B6B8 0xB5B3 # 0 +0x0000B6B9 0xB5B4 # 0 +0x0000B6BA 0xB5B5 # 0 +0x0000B6BB 0xB5BB # 0 +0x0000B6BC 0xB5BC # 0 +0x0000B6BD 0xB5BD # 0 +0x0000B6BE 0xB5C0 # 0 +0x0000B6BF 0xB5C4 # 0 +0x0000B6C0 0xB5CC # 0 +0x0000B6C1 0xB5CD # 0 +0x0000B6C2 0xB5CF # 0 +0x0000B6C3 0xB5D0 # 0 +0x0000B6C4 0xB5D1 # 0 +0x0000B6C5 0xB5D8 # 0 +0x0000B6C6 0xB5EC # 0 +0x0000B6C7 0xB610 # 0 +0x0000B6C8 0xB611 # 0 +0x0000B6C9 0xB614 # 0 +0x0000B6CA 0xB618 # 0 +0x0000B6CB 0xB625 # 0 +0x0000B6CC 0xB62C # 0 +0x0000B6CD 0xB634 # 0 +0x0000B6CE 0xB648 # 0 +0x0000B6CF 0xB664 # 0 +0x0000B6D0 0xB668 # 0 +0x0000B6D1 0xB69C # 0 +0x0000B6D2 0xB69D # 0 +0x0000B6D3 0xB6A0 # 0 +0x0000B6D4 0xB6A4 # 0 +0x0000B6D5 0xB6AB # 0 +0x0000B6D6 0xB6AC # 0 +0x0000B6D7 0xB6B1 # 0 +0x0000B6D8 0xB6D4 # 0 +0x0000B6D9 0xB6F0 # 0 +0x0000B6DA 0xB6F4 # 0 +0x0000B6DB 0xB6F8 # 0 +0x0000B6DC 0xB700 # 0 +0x0000B6DD 0xB701 # 0 +0x0000B6DE 0xB705 # 0 +0x0000B6DF 0xB728 # 0 +0x0000B6E0 0xB729 # 0 +0x0000B6E1 0xB72C # 0 +0x0000B6E2 0xB72F # 0 +0x0000B6E3 0xB730 # 0 +0x0000B6E4 0xB738 # 0 +0x0000B6E5 0xB739 # 0 +0x0000B6E6 0xB73B # 0 +0x0000B6E7 0xB744 # 0 +0x0000B6E8 0xB748 # 0 +0x0000B6E9 0xB74C # 0 +0x0000B6EA 0xB754 # 0 +0x0000B6EB 0xB755 # 0 +0x0000B6EC 0xB760 # 0 +0x0000B6ED 0xB764 # 0 +0x0000B6EE 0xB768 # 0 +0x0000B6EF 0xB770 # 0 +0x0000B6F0 0xB771 # 0 +0x0000B6F1 0xB773 # 0 +0x0000B6F2 0xB775 # 0 +0x0000B6F3 0xB77C # 0 +0x0000B6F4 0xB77D # 0 +0x0000B6F5 0xB780 # 0 +0x0000B6F6 0xB784 # 0 +0x0000B6F7 0xB78C # 0 +0x0000B6F8 0xB78D # 0 +0x0000B6F9 0xB78F # 0 +0x0000B6FA 0xB790 # 0 +0x0000B6FB 0xB791 # 0 +0x0000B6FC 0xB792 # 0 +0x0000B6FD 0xB796 # 0 +0x0000B6FE 0xB797 # 0 +0x0000B7A1 0xB798 # 0 +0x0000B7A2 0xB799 # 0 +0x0000B7A3 0xB79C # 0 +0x0000B7A4 0xB7A0 # 0 +0x0000B7A5 0xB7A8 # 0 +0x0000B7A6 0xB7A9 # 0 +0x0000B7A7 0xB7AB # 0 +0x0000B7A8 0xB7AC # 0 +0x0000B7A9 0xB7AD # 0 +0x0000B7AA 0xB7B4 # 0 +0x0000B7AB 0xB7B5 # 0 +0x0000B7AC 0xB7B8 # 0 +0x0000B7AD 0xB7C7 # 0 +0x0000B7AE 0xB7C9 # 0 +0x0000B7AF 0xB7EC # 0 +0x0000B7B0 0xB7ED # 0 +0x0000B7B1 0xB7F0 # 0 +0x0000B7B2 0xB7F4 # 0 +0x0000B7B3 0xB7FC # 0 +0x0000B7B4 0xB7FD # 0 +0x0000B7B5 0xB7FF # 0 +0x0000B7B6 0xB800 # 0 +0x0000B7B7 0xB801 # 0 +0x0000B7B8 0xB807 # 0 +0x0000B7B9 0xB808 # 0 +0x0000B7BA 0xB809 # 0 +0x0000B7BB 0xB80C # 0 +0x0000B7BC 0xB810 # 0 +0x0000B7BD 0xB818 # 0 +0x0000B7BE 0xB819 # 0 +0x0000B7BF 0xB81B # 0 +0x0000B7C0 0xB81D # 0 +0x0000B7C1 0xB824 # 0 +0x0000B7C2 0xB825 # 0 +0x0000B7C3 0xB828 # 0 +0x0000B7C4 0xB82C # 0 +0x0000B7C5 0xB834 # 0 +0x0000B7C6 0xB835 # 0 +0x0000B7C7 0xB837 # 0 +0x0000B7C8 0xB838 # 0 +0x0000B7C9 0xB839 # 0 +0x0000B7CA 0xB840 # 0 +0x0000B7CB 0xB844 # 0 +0x0000B7CC 0xB851 # 0 +0x0000B7CD 0xB853 # 0 +0x0000B7CE 0xB85C # 0 +0x0000B7CF 0xB85D # 0 +0x0000B7D0 0xB860 # 0 +0x0000B7D1 0xB864 # 0 +0x0000B7D2 0xB86C # 0 +0x0000B7D3 0xB86D # 0 +0x0000B7D4 0xB86F # 0 +0x0000B7D5 0xB871 # 0 +0x0000B7D6 0xB878 # 0 +0x0000B7D7 0xB87C # 0 +0x0000B7D8 0xB88D # 0 +0x0000B7D9 0xB8A8 # 0 +0x0000B7DA 0xB8B0 # 0 +0x0000B7DB 0xB8B4 # 0 +0x0000B7DC 0xB8B8 # 0 +0x0000B7DD 0xB8C0 # 0 +0x0000B7DE 0xB8C1 # 0 +0x0000B7DF 0xB8C3 # 0 +0x0000B7E0 0xB8C5 # 0 +0x0000B7E1 0xB8CC # 0 +0x0000B7E2 0xB8D0 # 0 +0x0000B7E3 0xB8D4 # 0 +0x0000B7E4 0xB8DD # 0 +0x0000B7E5 0xB8DF # 0 +0x0000B7E6 0xB8E1 # 0 +0x0000B7E7 0xB8E8 # 0 +0x0000B7E8 0xB8E9 # 0 +0x0000B7E9 0xB8EC # 0 +0x0000B7EA 0xB8F0 # 0 +0x0000B7EB 0xB8F8 # 0 +0x0000B7EC 0xB8F9 # 0 +0x0000B7ED 0xB8FB # 0 +0x0000B7EE 0xB8FD # 0 +0x0000B7EF 0xB904 # 0 +0x0000B7F0 0xB918 # 0 +0x0000B7F1 0xB920 # 0 +0x0000B7F2 0xB93C # 0 +0x0000B7F3 0xB93D # 0 +0x0000B7F4 0xB940 # 0 +0x0000B7F5 0xB944 # 0 +0x0000B7F6 0xB94C # 0 +0x0000B7F7 0xB94F # 0 +0x0000B7F8 0xB951 # 0 +0x0000B7F9 0xB958 # 0 +0x0000B7FA 0xB959 # 0 +0x0000B7FB 0xB95C # 0 +0x0000B7FC 0xB960 # 0 +0x0000B7FD 0xB968 # 0 +0x0000B7FE 0xB969 # 0 +0x0000B8A1 0xB96B # 0 +0x0000B8A2 0xB96D # 0 +0x0000B8A3 0xB974 # 0 +0x0000B8A4 0xB975 # 0 +0x0000B8A5 0xB978 # 0 +0x0000B8A6 0xB97C # 0 +0x0000B8A7 0xB984 # 0 +0x0000B8A8 0xB985 # 0 +0x0000B8A9 0xB987 # 0 +0x0000B8AA 0xB989 # 0 +0x0000B8AB 0xB98A # 0 +0x0000B8AC 0xB98D # 0 +0x0000B8AD 0xB98E # 0 +0x0000B8AE 0xB9AC # 0 +0x0000B8AF 0xB9AD # 0 +0x0000B8B0 0xB9B0 # 0 +0x0000B8B1 0xB9B4 # 0 +0x0000B8B2 0xB9BC # 0 +0x0000B8B3 0xB9BD # 0 +0x0000B8B4 0xB9BF # 0 +0x0000B8B5 0xB9C1 # 0 +0x0000B8B6 0xB9C8 # 0 +0x0000B8B7 0xB9C9 # 0 +0x0000B8B8 0xB9CC # 0 +0x0000B8B9 0xB9CE # 0 +0x0000B8BA 0xB9CF # 0 +0x0000B8BB 0xB9D0 # 0 +0x0000B8BC 0xB9D1 # 0 +0x0000B8BD 0xB9D2 # 0 +0x0000B8BE 0xB9D8 # 0 +0x0000B8BF 0xB9D9 # 0 +0x0000B8C0 0xB9DB # 0 +0x0000B8C1 0xB9DD # 0 +0x0000B8C2 0xB9DE # 0 +0x0000B8C3 0xB9E1 # 0 +0x0000B8C4 0xB9E3 # 0 +0x0000B8C5 0xB9E4 # 0 +0x0000B8C6 0xB9E5 # 0 +0x0000B8C7 0xB9E8 # 0 +0x0000B8C8 0xB9EC # 0 +0x0000B8C9 0xB9F4 # 0 +0x0000B8CA 0xB9F5 # 0 +0x0000B8CB 0xB9F7 # 0 +0x0000B8CC 0xB9F8 # 0 +0x0000B8CD 0xB9F9 # 0 +0x0000B8CE 0xB9FA # 0 +0x0000B8CF 0xBA00 # 0 +0x0000B8D0 0xBA01 # 0 +0x0000B8D1 0xBA08 # 0 +0x0000B8D2 0xBA15 # 0 +0x0000B8D3 0xBA38 # 0 +0x0000B8D4 0xBA39 # 0 +0x0000B8D5 0xBA3C # 0 +0x0000B8D6 0xBA40 # 0 +0x0000B8D7 0xBA42 # 0 +0x0000B8D8 0xBA48 # 0 +0x0000B8D9 0xBA49 # 0 +0x0000B8DA 0xBA4B # 0 +0x0000B8DB 0xBA4D # 0 +0x0000B8DC 0xBA4E # 0 +0x0000B8DD 0xBA53 # 0 +0x0000B8DE 0xBA54 # 0 +0x0000B8DF 0xBA55 # 0 +0x0000B8E0 0xBA58 # 0 +0x0000B8E1 0xBA5C # 0 +0x0000B8E2 0xBA64 # 0 +0x0000B8E3 0xBA65 # 0 +0x0000B8E4 0xBA67 # 0 +0x0000B8E5 0xBA68 # 0 +0x0000B8E6 0xBA69 # 0 +0x0000B8E7 0xBA70 # 0 +0x0000B8E8 0xBA71 # 0 +0x0000B8E9 0xBA74 # 0 +0x0000B8EA 0xBA78 # 0 +0x0000B8EB 0xBA83 # 0 +0x0000B8EC 0xBA84 # 0 +0x0000B8ED 0xBA85 # 0 +0x0000B8EE 0xBA87 # 0 +0x0000B8EF 0xBA8C # 0 +0x0000B8F0 0xBAA8 # 0 +0x0000B8F1 0xBAA9 # 0 +0x0000B8F2 0xBAAB # 0 +0x0000B8F3 0xBAAC # 0 +0x0000B8F4 0xBAB0 # 0 +0x0000B8F5 0xBAB2 # 0 +0x0000B8F6 0xBAB8 # 0 +0x0000B8F7 0xBAB9 # 0 +0x0000B8F8 0xBABB # 0 +0x0000B8F9 0xBABD # 0 +0x0000B8FA 0xBAC4 # 0 +0x0000B8FB 0xBAC8 # 0 +0x0000B8FC 0xBAD8 # 0 +0x0000B8FD 0xBAD9 # 0 +0x0000B8FE 0xBAFC # 0 +0x0000B9A1 0xBB00 # 0 +0x0000B9A2 0xBB04 # 0 +0x0000B9A3 0xBB0D # 0 +0x0000B9A4 0xBB0F # 0 +0x0000B9A5 0xBB11 # 0 +0x0000B9A6 0xBB18 # 0 +0x0000B9A7 0xBB1C # 0 +0x0000B9A8 0xBB20 # 0 +0x0000B9A9 0xBB29 # 0 +0x0000B9AA 0xBB2B # 0 +0x0000B9AB 0xBB34 # 0 +0x0000B9AC 0xBB35 # 0 +0x0000B9AD 0xBB36 # 0 +0x0000B9AE 0xBB38 # 0 +0x0000B9AF 0xBB3B # 0 +0x0000B9B0 0xBB3C # 0 +0x0000B9B1 0xBB3D # 0 +0x0000B9B2 0xBB3E # 0 +0x0000B9B3 0xBB44 # 0 +0x0000B9B4 0xBB45 # 0 +0x0000B9B5 0xBB47 # 0 +0x0000B9B6 0xBB49 # 0 +0x0000B9B7 0xBB4D # 0 +0x0000B9B8 0xBB4F # 0 +0x0000B9B9 0xBB50 # 0 +0x0000B9BA 0xBB54 # 0 +0x0000B9BB 0xBB58 # 0 +0x0000B9BC 0xBB61 # 0 +0x0000B9BD 0xBB63 # 0 +0x0000B9BE 0xBB6C # 0 +0x0000B9BF 0xBB88 # 0 +0x0000B9C0 0xBB8C # 0 +0x0000B9C1 0xBB90 # 0 +0x0000B9C2 0xBBA4 # 0 +0x0000B9C3 0xBBA8 # 0 +0x0000B9C4 0xBBAC # 0 +0x0000B9C5 0xBBB4 # 0 +0x0000B9C6 0xBBB7 # 0 +0x0000B9C7 0xBBC0 # 0 +0x0000B9C8 0xBBC4 # 0 +0x0000B9C9 0xBBC8 # 0 +0x0000B9CA 0xBBD0 # 0 +0x0000B9CB 0xBBD3 # 0 +0x0000B9CC 0xBBF8 # 0 +0x0000B9CD 0xBBF9 # 0 +0x0000B9CE 0xBBFC # 0 +0x0000B9CF 0xBBFF # 0 +0x0000B9D0 0xBC00 # 0 +0x0000B9D1 0xBC02 # 0 +0x0000B9D2 0xBC08 # 0 +0x0000B9D3 0xBC09 # 0 +0x0000B9D4 0xBC0B # 0 +0x0000B9D5 0xBC0C # 0 +0x0000B9D6 0xBC0D # 0 +0x0000B9D7 0xBC0F # 0 +0x0000B9D8 0xBC11 # 0 +0x0000B9D9 0xBC14 # 0 +0x0000B9DA 0xBC15 # 0 +0x0000B9DB 0xBC16 # 0 +0x0000B9DC 0xBC17 # 0 +0x0000B9DD 0xBC18 # 0 +0x0000B9DE 0xBC1B # 0 +0x0000B9DF 0xBC1C # 0 +0x0000B9E0 0xBC1D # 0 +0x0000B9E1 0xBC1E # 0 +0x0000B9E2 0xBC1F # 0 +0x0000B9E3 0xBC24 # 0 +0x0000B9E4 0xBC25 # 0 +0x0000B9E5 0xBC27 # 0 +0x0000B9E6 0xBC29 # 0 +0x0000B9E7 0xBC2D # 0 +0x0000B9E8 0xBC30 # 0 +0x0000B9E9 0xBC31 # 0 +0x0000B9EA 0xBC34 # 0 +0x0000B9EB 0xBC38 # 0 +0x0000B9EC 0xBC40 # 0 +0x0000B9ED 0xBC41 # 0 +0x0000B9EE 0xBC43 # 0 +0x0000B9EF 0xBC44 # 0 +0x0000B9F0 0xBC45 # 0 +0x0000B9F1 0xBC49 # 0 +0x0000B9F2 0xBC4C # 0 +0x0000B9F3 0xBC4D # 0 +0x0000B9F4 0xBC50 # 0 +0x0000B9F5 0xBC5D # 0 +0x0000B9F6 0xBC84 # 0 +0x0000B9F7 0xBC85 # 0 +0x0000B9F8 0xBC88 # 0 +0x0000B9F9 0xBC8B # 0 +0x0000B9FA 0xBC8C # 0 +0x0000B9FB 0xBC8E # 0 +0x0000B9FC 0xBC94 # 0 +0x0000B9FD 0xBC95 # 0 +0x0000B9FE 0xBC97 # 0 +0x0000BAA1 0xBC99 # 0 +0x0000BAA2 0xBC9A # 0 +0x0000BAA3 0xBCA0 # 0 +0x0000BAA4 0xBCA1 # 0 +0x0000BAA5 0xBCA4 # 0 +0x0000BAA6 0xBCA7 # 0 +0x0000BAA7 0xBCA8 # 0 +0x0000BAA8 0xBCB0 # 0 +0x0000BAA9 0xBCB1 # 0 +0x0000BAAA 0xBCB3 # 0 +0x0000BAAB 0xBCB4 # 0 +0x0000BAAC 0xBCB5 # 0 +0x0000BAAD 0xBCBC # 0 +0x0000BAAE 0xBCBD # 0 +0x0000BAAF 0xBCC0 # 0 +0x0000BAB0 0xBCC4 # 0 +0x0000BAB1 0xBCCD # 0 +0x0000BAB2 0xBCCF # 0 +0x0000BAB3 0xBCD0 # 0 +0x0000BAB4 0xBCD1 # 0 +0x0000BAB5 0xBCD5 # 0 +0x0000BAB6 0xBCD8 # 0 +0x0000BAB7 0xBCDC # 0 +0x0000BAB8 0xBCF4 # 0 +0x0000BAB9 0xBCF5 # 0 +0x0000BABA 0xBCF6 # 0 +0x0000BABB 0xBCF8 # 0 +0x0000BABC 0xBCFC # 0 +0x0000BABD 0xBD04 # 0 +0x0000BABE 0xBD05 # 0 +0x0000BABF 0xBD07 # 0 +0x0000BAC0 0xBD09 # 0 +0x0000BAC1 0xBD10 # 0 +0x0000BAC2 0xBD14 # 0 +0x0000BAC3 0xBD24 # 0 +0x0000BAC4 0xBD2C # 0 +0x0000BAC5 0xBD40 # 0 +0x0000BAC6 0xBD48 # 0 +0x0000BAC7 0xBD49 # 0 +0x0000BAC8 0xBD4C # 0 +0x0000BAC9 0xBD50 # 0 +0x0000BACA 0xBD58 # 0 +0x0000BACB 0xBD59 # 0 +0x0000BACC 0xBD64 # 0 +0x0000BACD 0xBD68 # 0 +0x0000BACE 0xBD80 # 0 +0x0000BACF 0xBD81 # 0 +0x0000BAD0 0xBD84 # 0 +0x0000BAD1 0xBD87 # 0 +0x0000BAD2 0xBD88 # 0 +0x0000BAD3 0xBD89 # 0 +0x0000BAD4 0xBD8A # 0 +0x0000BAD5 0xBD90 # 0 +0x0000BAD6 0xBD91 # 0 +0x0000BAD7 0xBD93 # 0 +0x0000BAD8 0xBD95 # 0 +0x0000BAD9 0xBD99 # 0 +0x0000BADA 0xBD9A # 0 +0x0000BADB 0xBD9C # 0 +0x0000BADC 0xBDA4 # 0 +0x0000BADD 0xBDB0 # 0 +0x0000BADE 0xBDB8 # 0 +0x0000BADF 0xBDD4 # 0 +0x0000BAE0 0xBDD5 # 0 +0x0000BAE1 0xBDD8 # 0 +0x0000BAE2 0xBDDC # 0 +0x0000BAE3 0xBDE9 # 0 +0x0000BAE4 0xBDF0 # 0 +0x0000BAE5 0xBDF4 # 0 +0x0000BAE6 0xBDF8 # 0 +0x0000BAE7 0xBE00 # 0 +0x0000BAE8 0xBE03 # 0 +0x0000BAE9 0xBE05 # 0 +0x0000BAEA 0xBE0C # 0 +0x0000BAEB 0xBE0D # 0 +0x0000BAEC 0xBE10 # 0 +0x0000BAED 0xBE14 # 0 +0x0000BAEE 0xBE1C # 0 +0x0000BAEF 0xBE1D # 0 +0x0000BAF0 0xBE1F # 0 +0x0000BAF1 0xBE44 # 0 +0x0000BAF2 0xBE45 # 0 +0x0000BAF3 0xBE48 # 0 +0x0000BAF4 0xBE4C # 0 +0x0000BAF5 0xBE4E # 0 +0x0000BAF6 0xBE54 # 0 +0x0000BAF7 0xBE55 # 0 +0x0000BAF8 0xBE57 # 0 +0x0000BAF9 0xBE59 # 0 +0x0000BAFA 0xBE5A # 0 +0x0000BAFB 0xBE5B # 0 +0x0000BAFC 0xBE60 # 0 +0x0000BAFD 0xBE61 # 0 +0x0000BAFE 0xBE64 # 0 +0x0000BBA1 0xBE68 # 0 +0x0000BBA2 0xBE6A # 0 +0x0000BBA3 0xBE70 # 0 +0x0000BBA4 0xBE71 # 0 +0x0000BBA5 0xBE73 # 0 +0x0000BBA6 0xBE74 # 0 +0x0000BBA7 0xBE75 # 0 +0x0000BBA8 0xBE7B # 0 +0x0000BBA9 0xBE7C # 0 +0x0000BBAA 0xBE7D # 0 +0x0000BBAB 0xBE80 # 0 +0x0000BBAC 0xBE84 # 0 +0x0000BBAD 0xBE8C # 0 +0x0000BBAE 0xBE8D # 0 +0x0000BBAF 0xBE8F # 0 +0x0000BBB0 0xBE90 # 0 +0x0000BBB1 0xBE91 # 0 +0x0000BBB2 0xBE98 # 0 +0x0000BBB3 0xBE99 # 0 +0x0000BBB4 0xBEA8 # 0 +0x0000BBB5 0xBED0 # 0 +0x0000BBB6 0xBED1 # 0 +0x0000BBB7 0xBED4 # 0 +0x0000BBB8 0xBED7 # 0 +0x0000BBB9 0xBED8 # 0 +0x0000BBBA 0xBEE0 # 0 +0x0000BBBB 0xBEE3 # 0 +0x0000BBBC 0xBEE4 # 0 +0x0000BBBD 0xBEE5 # 0 +0x0000BBBE 0xBEEC # 0 +0x0000BBBF 0xBF01 # 0 +0x0000BBC0 0xBF08 # 0 +0x0000BBC1 0xBF09 # 0 +0x0000BBC2 0xBF18 # 0 +0x0000BBC3 0xBF19 # 0 +0x0000BBC4 0xBF1B # 0 +0x0000BBC5 0xBF1C # 0 +0x0000BBC6 0xBF1D # 0 +0x0000BBC7 0xBF40 # 0 +0x0000BBC8 0xBF41 # 0 +0x0000BBC9 0xBF44 # 0 +0x0000BBCA 0xBF48 # 0 +0x0000BBCB 0xBF50 # 0 +0x0000BBCC 0xBF51 # 0 +0x0000BBCD 0xBF55 # 0 +0x0000BBCE 0xBF94 # 0 +0x0000BBCF 0xBFB0 # 0 +0x0000BBD0 0xBFC5 # 0 +0x0000BBD1 0xBFCC # 0 +0x0000BBD2 0xBFCD # 0 +0x0000BBD3 0xBFD0 # 0 +0x0000BBD4 0xBFD4 # 0 +0x0000BBD5 0xBFDC # 0 +0x0000BBD6 0xBFDF # 0 +0x0000BBD7 0xBFE1 # 0 +0x0000BBD8 0xC03C # 0 +0x0000BBD9 0xC051 # 0 +0x0000BBDA 0xC058 # 0 +0x0000BBDB 0xC05C # 0 +0x0000BBDC 0xC060 # 0 +0x0000BBDD 0xC068 # 0 +0x0000BBDE 0xC069 # 0 +0x0000BBDF 0xC090 # 0 +0x0000BBE0 0xC091 # 0 +0x0000BBE1 0xC094 # 0 +0x0000BBE2 0xC098 # 0 +0x0000BBE3 0xC0A0 # 0 +0x0000BBE4 0xC0A1 # 0 +0x0000BBE5 0xC0A3 # 0 +0x0000BBE6 0xC0A5 # 0 +0x0000BBE7 0xC0AC # 0 +0x0000BBE8 0xC0AD # 0 +0x0000BBE9 0xC0AF # 0 +0x0000BBEA 0xC0B0 # 0 +0x0000BBEB 0xC0B3 # 0 +0x0000BBEC 0xC0B4 # 0 +0x0000BBED 0xC0B5 # 0 +0x0000BBEE 0xC0B6 # 0 +0x0000BBEF 0xC0BC # 0 +0x0000BBF0 0xC0BD # 0 +0x0000BBF1 0xC0BF # 0 +0x0000BBF2 0xC0C0 # 0 +0x0000BBF3 0xC0C1 # 0 +0x0000BBF4 0xC0C5 # 0 +0x0000BBF5 0xC0C8 # 0 +0x0000BBF6 0xC0C9 # 0 +0x0000BBF7 0xC0CC # 0 +0x0000BBF8 0xC0D0 # 0 +0x0000BBF9 0xC0D8 # 0 +0x0000BBFA 0xC0D9 # 0 +0x0000BBFB 0xC0DB # 0 +0x0000BBFC 0xC0DC # 0 +0x0000BBFD 0xC0DD # 0 +0x0000BBFE 0xC0E4 # 0 +0x0000BCA1 0xC0E5 # 0 +0x0000BCA2 0xC0E8 # 0 +0x0000BCA3 0xC0EC # 0 +0x0000BCA4 0xC0F4 # 0 +0x0000BCA5 0xC0F5 # 0 +0x0000BCA6 0xC0F7 # 0 +0x0000BCA7 0xC0F9 # 0 +0x0000BCA8 0xC100 # 0 +0x0000BCA9 0xC104 # 0 +0x0000BCAA 0xC108 # 0 +0x0000BCAB 0xC110 # 0 +0x0000BCAC 0xC115 # 0 +0x0000BCAD 0xC11C # 0 +0x0000BCAE 0xC11D # 0 +0x0000BCAF 0xC11E # 0 +0x0000BCB0 0xC11F # 0 +0x0000BCB1 0xC120 # 0 +0x0000BCB2 0xC123 # 0 +0x0000BCB3 0xC124 # 0 +0x0000BCB4 0xC126 # 0 +0x0000BCB5 0xC127 # 0 +0x0000BCB6 0xC12C # 0 +0x0000BCB7 0xC12D # 0 +0x0000BCB8 0xC12F # 0 +0x0000BCB9 0xC130 # 0 +0x0000BCBA 0xC131 # 0 +0x0000BCBB 0xC136 # 0 +0x0000BCBC 0xC138 # 0 +0x0000BCBD 0xC139 # 0 +0x0000BCBE 0xC13C # 0 +0x0000BCBF 0xC140 # 0 +0x0000BCC0 0xC148 # 0 +0x0000BCC1 0xC149 # 0 +0x0000BCC2 0xC14B # 0 +0x0000BCC3 0xC14C # 0 +0x0000BCC4 0xC14D # 0 +0x0000BCC5 0xC154 # 0 +0x0000BCC6 0xC155 # 0 +0x0000BCC7 0xC158 # 0 +0x0000BCC8 0xC15C # 0 +0x0000BCC9 0xC164 # 0 +0x0000BCCA 0xC165 # 0 +0x0000BCCB 0xC167 # 0 +0x0000BCCC 0xC168 # 0 +0x0000BCCD 0xC169 # 0 +0x0000BCCE 0xC170 # 0 +0x0000BCCF 0xC174 # 0 +0x0000BCD0 0xC178 # 0 +0x0000BCD1 0xC185 # 0 +0x0000BCD2 0xC18C # 0 +0x0000BCD3 0xC18D # 0 +0x0000BCD4 0xC18E # 0 +0x0000BCD5 0xC190 # 0 +0x0000BCD6 0xC194 # 0 +0x0000BCD7 0xC196 # 0 +0x0000BCD8 0xC19C # 0 +0x0000BCD9 0xC19D # 0 +0x0000BCDA 0xC19F # 0 +0x0000BCDB 0xC1A1 # 0 +0x0000BCDC 0xC1A5 # 0 +0x0000BCDD 0xC1A8 # 0 +0x0000BCDE 0xC1A9 # 0 +0x0000BCDF 0xC1AC # 0 +0x0000BCE0 0xC1B0 # 0 +0x0000BCE1 0xC1BD # 0 +0x0000BCE2 0xC1C4 # 0 +0x0000BCE3 0xC1C8 # 0 +0x0000BCE4 0xC1CC # 0 +0x0000BCE5 0xC1D4 # 0 +0x0000BCE6 0xC1D7 # 0 +0x0000BCE7 0xC1D8 # 0 +0x0000BCE8 0xC1E0 # 0 +0x0000BCE9 0xC1E4 # 0 +0x0000BCEA 0xC1E8 # 0 +0x0000BCEB 0xC1F0 # 0 +0x0000BCEC 0xC1F1 # 0 +0x0000BCED 0xC1F3 # 0 +0x0000BCEE 0xC1FC # 0 +0x0000BCEF 0xC1FD # 0 +0x0000BCF0 0xC200 # 0 +0x0000BCF1 0xC204 # 0 +0x0000BCF2 0xC20C # 0 +0x0000BCF3 0xC20D # 0 +0x0000BCF4 0xC20F # 0 +0x0000BCF5 0xC211 # 0 +0x0000BCF6 0xC218 # 0 +0x0000BCF7 0xC219 # 0 +0x0000BCF8 0xC21C # 0 +0x0000BCF9 0xC21F # 0 +0x0000BCFA 0xC220 # 0 +0x0000BCFB 0xC228 # 0 +0x0000BCFC 0xC229 # 0 +0x0000BCFD 0xC22B # 0 +0x0000BCFE 0xC22D # 0 +0x0000BDA1 0xC22F # 0 +0x0000BDA2 0xC231 # 0 +0x0000BDA3 0xC232 # 0 +0x0000BDA4 0xC234 # 0 +0x0000BDA5 0xC248 # 0 +0x0000BDA6 0xC250 # 0 +0x0000BDA7 0xC251 # 0 +0x0000BDA8 0xC254 # 0 +0x0000BDA9 0xC258 # 0 +0x0000BDAA 0xC260 # 0 +0x0000BDAB 0xC265 # 0 +0x0000BDAC 0xC26C # 0 +0x0000BDAD 0xC26D # 0 +0x0000BDAE 0xC270 # 0 +0x0000BDAF 0xC274 # 0 +0x0000BDB0 0xC27C # 0 +0x0000BDB1 0xC27D # 0 +0x0000BDB2 0xC27F # 0 +0x0000BDB3 0xC281 # 0 +0x0000BDB4 0xC288 # 0 +0x0000BDB5 0xC289 # 0 +0x0000BDB6 0xC290 # 0 +0x0000BDB7 0xC298 # 0 +0x0000BDB8 0xC29B # 0 +0x0000BDB9 0xC29D # 0 +0x0000BDBA 0xC2A4 # 0 +0x0000BDBB 0xC2A5 # 0 +0x0000BDBC 0xC2A8 # 0 +0x0000BDBD 0xC2AC # 0 +0x0000BDBE 0xC2AD # 0 +0x0000BDBF 0xC2B4 # 0 +0x0000BDC0 0xC2B5 # 0 +0x0000BDC1 0xC2B7 # 0 +0x0000BDC2 0xC2B9 # 0 +0x0000BDC3 0xC2DC # 0 +0x0000BDC4 0xC2DD # 0 +0x0000BDC5 0xC2E0 # 0 +0x0000BDC6 0xC2E3 # 0 +0x0000BDC7 0xC2E4 # 0 +0x0000BDC8 0xC2EB # 0 +0x0000BDC9 0xC2EC # 0 +0x0000BDCA 0xC2ED # 0 +0x0000BDCB 0xC2EF # 0 +0x0000BDCC 0xC2F1 # 0 +0x0000BDCD 0xC2F6 # 0 +0x0000BDCE 0xC2F8 # 0 +0x0000BDCF 0xC2F9 # 0 +0x0000BDD0 0xC2FB # 0 +0x0000BDD1 0xC2FC # 0 +0x0000BDD2 0xC300 # 0 +0x0000BDD3 0xC308 # 0 +0x0000BDD4 0xC309 # 0 +0x0000BDD5 0xC30C # 0 +0x0000BDD6 0xC30D # 0 +0x0000BDD7 0xC313 # 0 +0x0000BDD8 0xC314 # 0 +0x0000BDD9 0xC315 # 0 +0x0000BDDA 0xC318 # 0 +0x0000BDDB 0xC31C # 0 +0x0000BDDC 0xC324 # 0 +0x0000BDDD 0xC325 # 0 +0x0000BDDE 0xC328 # 0 +0x0000BDDF 0xC329 # 0 +0x0000BDE0 0xC345 # 0 +0x0000BDE1 0xC368 # 0 +0x0000BDE2 0xC369 # 0 +0x0000BDE3 0xC36C # 0 +0x0000BDE4 0xC370 # 0 +0x0000BDE5 0xC372 # 0 +0x0000BDE6 0xC378 # 0 +0x0000BDE7 0xC379 # 0 +0x0000BDE8 0xC37C # 0 +0x0000BDE9 0xC37D # 0 +0x0000BDEA 0xC384 # 0 +0x0000BDEB 0xC388 # 0 +0x0000BDEC 0xC38C # 0 +0x0000BDED 0xC3C0 # 0 +0x0000BDEE 0xC3D8 # 0 +0x0000BDEF 0xC3D9 # 0 +0x0000BDF0 0xC3DC # 0 +0x0000BDF1 0xC3DF # 0 +0x0000BDF2 0xC3E0 # 0 +0x0000BDF3 0xC3E2 # 0 +0x0000BDF4 0xC3E8 # 0 +0x0000BDF5 0xC3E9 # 0 +0x0000BDF6 0xC3ED # 0 +0x0000BDF7 0xC3F4 # 0 +0x0000BDF8 0xC3F5 # 0 +0x0000BDF9 0xC3F8 # 0 +0x0000BDFA 0xC408 # 0 +0x0000BDFB 0xC410 # 0 +0x0000BDFC 0xC424 # 0 +0x0000BDFD 0xC42C # 0 +0x0000BDFE 0xC430 # 0 +0x0000BEA1 0xC434 # 0 +0x0000BEA2 0xC43C # 0 +0x0000BEA3 0xC43D # 0 +0x0000BEA4 0xC448 # 0 +0x0000BEA5 0xC464 # 0 +0x0000BEA6 0xC465 # 0 +0x0000BEA7 0xC468 # 0 +0x0000BEA8 0xC46C # 0 +0x0000BEA9 0xC474 # 0 +0x0000BEAA 0xC475 # 0 +0x0000BEAB 0xC479 # 0 +0x0000BEAC 0xC480 # 0 +0x0000BEAD 0xC494 # 0 +0x0000BEAE 0xC49C # 0 +0x0000BEAF 0xC4B8 # 0 +0x0000BEB0 0xC4BC # 0 +0x0000BEB1 0xC4E9 # 0 +0x0000BEB2 0xC4F0 # 0 +0x0000BEB3 0xC4F1 # 0 +0x0000BEB4 0xC4F4 # 0 +0x0000BEB5 0xC4F8 # 0 +0x0000BEB6 0xC4FA # 0 +0x0000BEB7 0xC4FF # 0 +0x0000BEB8 0xC500 # 0 +0x0000BEB9 0xC501 # 0 +0x0000BEBA 0xC50C # 0 +0x0000BEBB 0xC510 # 0 +0x0000BEBC 0xC514 # 0 +0x0000BEBD 0xC51C # 0 +0x0000BEBE 0xC528 # 0 +0x0000BEBF 0xC529 # 0 +0x0000BEC0 0xC52C # 0 +0x0000BEC1 0xC530 # 0 +0x0000BEC2 0xC538 # 0 +0x0000BEC3 0xC539 # 0 +0x0000BEC4 0xC53B # 0 +0x0000BEC5 0xC53D # 0 +0x0000BEC6 0xC544 # 0 +0x0000BEC7 0xC545 # 0 +0x0000BEC8 0xC548 # 0 +0x0000BEC9 0xC549 # 0 +0x0000BECA 0xC54A # 0 +0x0000BECB 0xC54C # 0 +0x0000BECC 0xC54D # 0 +0x0000BECD 0xC54E # 0 +0x0000BECE 0xC553 # 0 +0x0000BECF 0xC554 # 0 +0x0000BED0 0xC555 # 0 +0x0000BED1 0xC557 # 0 +0x0000BED2 0xC558 # 0 +0x0000BED3 0xC559 # 0 +0x0000BED4 0xC55D # 0 +0x0000BED5 0xC55E # 0 +0x0000BED6 0xC560 # 0 +0x0000BED7 0xC561 # 0 +0x0000BED8 0xC564 # 0 +0x0000BED9 0xC568 # 0 +0x0000BEDA 0xC570 # 0 +0x0000BEDB 0xC571 # 0 +0x0000BEDC 0xC573 # 0 +0x0000BEDD 0xC574 # 0 +0x0000BEDE 0xC575 # 0 +0x0000BEDF 0xC57C # 0 +0x0000BEE0 0xC57D # 0 +0x0000BEE1 0xC580 # 0 +0x0000BEE2 0xC584 # 0 +0x0000BEE3 0xC587 # 0 +0x0000BEE4 0xC58C # 0 +0x0000BEE5 0xC58D # 0 +0x0000BEE6 0xC58F # 0 +0x0000BEE7 0xC591 # 0 +0x0000BEE8 0xC595 # 0 +0x0000BEE9 0xC597 # 0 +0x0000BEEA 0xC598 # 0 +0x0000BEEB 0xC59C # 0 +0x0000BEEC 0xC5A0 # 0 +0x0000BEED 0xC5A9 # 0 +0x0000BEEE 0xC5B4 # 0 +0x0000BEEF 0xC5B5 # 0 +0x0000BEF0 0xC5B8 # 0 +0x0000BEF1 0xC5B9 # 0 +0x0000BEF2 0xC5BB # 0 +0x0000BEF3 0xC5BC # 0 +0x0000BEF4 0xC5BD # 0 +0x0000BEF5 0xC5BE # 0 +0x0000BEF6 0xC5C4 # 0 +0x0000BEF7 0xC5C5 # 0 +0x0000BEF8 0xC5C6 # 0 +0x0000BEF9 0xC5C7 # 0 +0x0000BEFA 0xC5C8 # 0 +0x0000BEFB 0xC5C9 # 0 +0x0000BEFC 0xC5CA # 0 +0x0000BEFD 0xC5CC # 0 +0x0000BEFE 0xC5CE # 0 +0x0000BFA1 0xC5D0 # 0 +0x0000BFA2 0xC5D1 # 0 +0x0000BFA3 0xC5D4 # 0 +0x0000BFA4 0xC5D8 # 0 +0x0000BFA5 0xC5E0 # 0 +0x0000BFA6 0xC5E1 # 0 +0x0000BFA7 0xC5E3 # 0 +0x0000BFA8 0xC5E5 # 0 +0x0000BFA9 0xC5EC # 0 +0x0000BFAA 0xC5ED # 0 +0x0000BFAB 0xC5EE # 0 +0x0000BFAC 0xC5F0 # 0 +0x0000BFAD 0xC5F4 # 0 +0x0000BFAE 0xC5F6 # 0 +0x0000BFAF 0xC5F7 # 0 +0x0000BFB0 0xC5FC # 0 +0x0000BFB1 0xC5FD # 0 +0x0000BFB2 0xC5FE # 0 +0x0000BFB3 0xC5FF # 0 +0x0000BFB4 0xC600 # 0 +0x0000BFB5 0xC601 # 0 +0x0000BFB6 0xC605 # 0 +0x0000BFB7 0xC606 # 0 +0x0000BFB8 0xC607 # 0 +0x0000BFB9 0xC608 # 0 +0x0000BFBA 0xC60C # 0 +0x0000BFBB 0xC610 # 0 +0x0000BFBC 0xC618 # 0 +0x0000BFBD 0xC619 # 0 +0x0000BFBE 0xC61B # 0 +0x0000BFBF 0xC61C # 0 +0x0000BFC0 0xC624 # 0 +0x0000BFC1 0xC625 # 0 +0x0000BFC2 0xC628 # 0 +0x0000BFC3 0xC62C # 0 +0x0000BFC4 0xC62D # 0 +0x0000BFC5 0xC62E # 0 +0x0000BFC6 0xC630 # 0 +0x0000BFC7 0xC633 # 0 +0x0000BFC8 0xC634 # 0 +0x0000BFC9 0xC635 # 0 +0x0000BFCA 0xC637 # 0 +0x0000BFCB 0xC639 # 0 +0x0000BFCC 0xC63B # 0 +0x0000BFCD 0xC640 # 0 +0x0000BFCE 0xC641 # 0 +0x0000BFCF 0xC644 # 0 +0x0000BFD0 0xC648 # 0 +0x0000BFD1 0xC650 # 0 +0x0000BFD2 0xC651 # 0 +0x0000BFD3 0xC653 # 0 +0x0000BFD4 0xC654 # 0 +0x0000BFD5 0xC655 # 0 +0x0000BFD6 0xC65C # 0 +0x0000BFD7 0xC65D # 0 +0x0000BFD8 0xC660 # 0 +0x0000BFD9 0xC66C # 0 +0x0000BFDA 0xC66F # 0 +0x0000BFDB 0xC671 # 0 +0x0000BFDC 0xC678 # 0 +0x0000BFDD 0xC679 # 0 +0x0000BFDE 0xC67C # 0 +0x0000BFDF 0xC680 # 0 +0x0000BFE0 0xC688 # 0 +0x0000BFE1 0xC689 # 0 +0x0000BFE2 0xC68B # 0 +0x0000BFE3 0xC68D # 0 +0x0000BFE4 0xC694 # 0 +0x0000BFE5 0xC695 # 0 +0x0000BFE6 0xC698 # 0 +0x0000BFE7 0xC69C # 0 +0x0000BFE8 0xC6A4 # 0 +0x0000BFE9 0xC6A5 # 0 +0x0000BFEA 0xC6A7 # 0 +0x0000BFEB 0xC6A9 # 0 +0x0000BFEC 0xC6B0 # 0 +0x0000BFED 0xC6B1 # 0 +0x0000BFEE 0xC6B4 # 0 +0x0000BFEF 0xC6B8 # 0 +0x0000BFF0 0xC6B9 # 0 +0x0000BFF1 0xC6BA # 0 +0x0000BFF2 0xC6C0 # 0 +0x0000BFF3 0xC6C1 # 0 +0x0000BFF4 0xC6C3 # 0 +0x0000BFF5 0xC6C5 # 0 +0x0000BFF6 0xC6CC # 0 +0x0000BFF7 0xC6CD # 0 +0x0000BFF8 0xC6D0 # 0 +0x0000BFF9 0xC6D4 # 0 +0x0000BFFA 0xC6DC # 0 +0x0000BFFB 0xC6DD # 0 +0x0000BFFC 0xC6E0 # 0 +0x0000BFFD 0xC6E1 # 0 +0x0000BFFE 0xC6E8 # 0 +0x0000C0A1 0xC6E9 # 0 +0x0000C0A2 0xC6EC # 0 +0x0000C0A3 0xC6F0 # 0 +0x0000C0A4 0xC6F8 # 0 +0x0000C0A5 0xC6F9 # 0 +0x0000C0A6 0xC6FD # 0 +0x0000C0A7 0xC704 # 0 +0x0000C0A8 0xC705 # 0 +0x0000C0A9 0xC708 # 0 +0x0000C0AA 0xC70C # 0 +0x0000C0AB 0xC714 # 0 +0x0000C0AC 0xC715 # 0 +0x0000C0AD 0xC717 # 0 +0x0000C0AE 0xC719 # 0 +0x0000C0AF 0xC720 # 0 +0x0000C0B0 0xC721 # 0 +0x0000C0B1 0xC724 # 0 +0x0000C0B2 0xC728 # 0 +0x0000C0B3 0xC730 # 0 +0x0000C0B4 0xC731 # 0 +0x0000C0B5 0xC733 # 0 +0x0000C0B6 0xC735 # 0 +0x0000C0B7 0xC737 # 0 +0x0000C0B8 0xC73C # 0 +0x0000C0B9 0xC73D # 0 +0x0000C0BA 0xC740 # 0 +0x0000C0BB 0xC744 # 0 +0x0000C0BC 0xC74A # 0 +0x0000C0BD 0xC74C # 0 +0x0000C0BE 0xC74D # 0 +0x0000C0BF 0xC74F # 0 +0x0000C0C0 0xC751 # 0 +0x0000C0C1 0xC752 # 0 +0x0000C0C2 0xC753 # 0 +0x0000C0C3 0xC754 # 0 +0x0000C0C4 0xC755 # 0 +0x0000C0C5 0xC756 # 0 +0x0000C0C6 0xC757 # 0 +0x0000C0C7 0xC758 # 0 +0x0000C0C8 0xC75C # 0 +0x0000C0C9 0xC760 # 0 +0x0000C0CA 0xC768 # 0 +0x0000C0CB 0xC76B # 0 +0x0000C0CC 0xC774 # 0 +0x0000C0CD 0xC775 # 0 +0x0000C0CE 0xC778 # 0 +0x0000C0CF 0xC77C # 0 +0x0000C0D0 0xC77D # 0 +0x0000C0D1 0xC77E # 0 +0x0000C0D2 0xC783 # 0 +0x0000C0D3 0xC784 # 0 +0x0000C0D4 0xC785 # 0 +0x0000C0D5 0xC787 # 0 +0x0000C0D6 0xC788 # 0 +0x0000C0D7 0xC789 # 0 +0x0000C0D8 0xC78A # 0 +0x0000C0D9 0xC78E # 0 +0x0000C0DA 0xC790 # 0 +0x0000C0DB 0xC791 # 0 +0x0000C0DC 0xC794 # 0 +0x0000C0DD 0xC796 # 0 +0x0000C0DE 0xC797 # 0 +0x0000C0DF 0xC798 # 0 +0x0000C0E0 0xC79A # 0 +0x0000C0E1 0xC7A0 # 0 +0x0000C0E2 0xC7A1 # 0 +0x0000C0E3 0xC7A3 # 0 +0x0000C0E4 0xC7A4 # 0 +0x0000C0E5 0xC7A5 # 0 +0x0000C0E6 0xC7A6 # 0 +0x0000C0E7 0xC7AC # 0 +0x0000C0E8 0xC7AD # 0 +0x0000C0E9 0xC7B0 # 0 +0x0000C0EA 0xC7B4 # 0 +0x0000C0EB 0xC7BC # 0 +0x0000C0EC 0xC7BD # 0 +0x0000C0ED 0xC7BF # 0 +0x0000C0EE 0xC7C0 # 0 +0x0000C0EF 0xC7C1 # 0 +0x0000C0F0 0xC7C8 # 0 +0x0000C0F1 0xC7C9 # 0 +0x0000C0F2 0xC7CC # 0 +0x0000C0F3 0xC7CE # 0 +0x0000C0F4 0xC7D0 # 0 +0x0000C0F5 0xC7D8 # 0 +0x0000C0F6 0xC7DD # 0 +0x0000C0F7 0xC7E4 # 0 +0x0000C0F8 0xC7E8 # 0 +0x0000C0F9 0xC7EC # 0 +0x0000C0FA 0xC800 # 0 +0x0000C0FB 0xC801 # 0 +0x0000C0FC 0xC804 # 0 +0x0000C0FD 0xC808 # 0 +0x0000C0FE 0xC80A # 0 +0x0000C1A1 0xC810 # 0 +0x0000C1A2 0xC811 # 0 +0x0000C1A3 0xC813 # 0 +0x0000C1A4 0xC815 # 0 +0x0000C1A5 0xC816 # 0 +0x0000C1A6 0xC81C # 0 +0x0000C1A7 0xC81D # 0 +0x0000C1A8 0xC820 # 0 +0x0000C1A9 0xC824 # 0 +0x0000C1AA 0xC82C # 0 +0x0000C1AB 0xC82D # 0 +0x0000C1AC 0xC82F # 0 +0x0000C1AD 0xC831 # 0 +0x0000C1AE 0xC838 # 0 +0x0000C1AF 0xC83C # 0 +0x0000C1B0 0xC840 # 0 +0x0000C1B1 0xC848 # 0 +0x0000C1B2 0xC849 # 0 +0x0000C1B3 0xC84C # 0 +0x0000C1B4 0xC84D # 0 +0x0000C1B5 0xC854 # 0 +0x0000C1B6 0xC870 # 0 +0x0000C1B7 0xC871 # 0 +0x0000C1B8 0xC874 # 0 +0x0000C1B9 0xC878 # 0 +0x0000C1BA 0xC87A # 0 +0x0000C1BB 0xC880 # 0 +0x0000C1BC 0xC881 # 0 +0x0000C1BD 0xC883 # 0 +0x0000C1BE 0xC885 # 0 +0x0000C1BF 0xC886 # 0 +0x0000C1C0 0xC887 # 0 +0x0000C1C1 0xC88B # 0 +0x0000C1C2 0xC88C # 0 +0x0000C1C3 0xC88D # 0 +0x0000C1C4 0xC894 # 0 +0x0000C1C5 0xC89D # 0 +0x0000C1C6 0xC89F # 0 +0x0000C1C7 0xC8A1 # 0 +0x0000C1C8 0xC8A8 # 0 +0x0000C1C9 0xC8BC # 0 +0x0000C1CA 0xC8BD # 0 +0x0000C1CB 0xC8C4 # 0 +0x0000C1CC 0xC8C8 # 0 +0x0000C1CD 0xC8CC # 0 +0x0000C1CE 0xC8D4 # 0 +0x0000C1CF 0xC8D5 # 0 +0x0000C1D0 0xC8D7 # 0 +0x0000C1D1 0xC8D9 # 0 +0x0000C1D2 0xC8E0 # 0 +0x0000C1D3 0xC8E1 # 0 +0x0000C1D4 0xC8E4 # 0 +0x0000C1D5 0xC8F5 # 0 +0x0000C1D6 0xC8FC # 0 +0x0000C1D7 0xC8FD # 0 +0x0000C1D8 0xC900 # 0 +0x0000C1D9 0xC904 # 0 +0x0000C1DA 0xC905 # 0 +0x0000C1DB 0xC906 # 0 +0x0000C1DC 0xC90C # 0 +0x0000C1DD 0xC90D # 0 +0x0000C1DE 0xC90F # 0 +0x0000C1DF 0xC911 # 0 +0x0000C1E0 0xC918 # 0 +0x0000C1E1 0xC92C # 0 +0x0000C1E2 0xC934 # 0 +0x0000C1E3 0xC950 # 0 +0x0000C1E4 0xC951 # 0 +0x0000C1E5 0xC954 # 0 +0x0000C1E6 0xC958 # 0 +0x0000C1E7 0xC960 # 0 +0x0000C1E8 0xC961 # 0 +0x0000C1E9 0xC963 # 0 +0x0000C1EA 0xC96C # 0 +0x0000C1EB 0xC970 # 0 +0x0000C1EC 0xC974 # 0 +0x0000C1ED 0xC97C # 0 +0x0000C1EE 0xC988 # 0 +0x0000C1EF 0xC989 # 0 +0x0000C1F0 0xC98C # 0 +0x0000C1F1 0xC990 # 0 +0x0000C1F2 0xC998 # 0 +0x0000C1F3 0xC999 # 0 +0x0000C1F4 0xC99B # 0 +0x0000C1F5 0xC99D # 0 +0x0000C1F6 0xC9C0 # 0 +0x0000C1F7 0xC9C1 # 0 +0x0000C1F8 0xC9C4 # 0 +0x0000C1F9 0xC9C7 # 0 +0x0000C1FA 0xC9C8 # 0 +0x0000C1FB 0xC9CA # 0 +0x0000C1FC 0xC9D0 # 0 +0x0000C1FD 0xC9D1 # 0 +0x0000C1FE 0xC9D3 # 0 +0x0000C2A1 0xC9D5 # 0 +0x0000C2A2 0xC9D6 # 0 +0x0000C2A3 0xC9D9 # 0 +0x0000C2A4 0xC9DA # 0 +0x0000C2A5 0xC9DC # 0 +0x0000C2A6 0xC9DD # 0 +0x0000C2A7 0xC9E0 # 0 +0x0000C2A8 0xC9E2 # 0 +0x0000C2A9 0xC9E4 # 0 +0x0000C2AA 0xC9E7 # 0 +0x0000C2AB 0xC9EC # 0 +0x0000C2AC 0xC9ED # 0 +0x0000C2AD 0xC9EF # 0 +0x0000C2AE 0xC9F0 # 0 +0x0000C2AF 0xC9F1 # 0 +0x0000C2B0 0xC9F8 # 0 +0x0000C2B1 0xC9F9 # 0 +0x0000C2B2 0xC9FC # 0 +0x0000C2B3 0xCA00 # 0 +0x0000C2B4 0xCA08 # 0 +0x0000C2B5 0xCA09 # 0 +0x0000C2B6 0xCA0B # 0 +0x0000C2B7 0xCA0C # 0 +0x0000C2B8 0xCA0D # 0 +0x0000C2B9 0xCA14 # 0 +0x0000C2BA 0xCA18 # 0 +0x0000C2BB 0xCA29 # 0 +0x0000C2BC 0xCA4C # 0 +0x0000C2BD 0xCA4D # 0 +0x0000C2BE 0xCA50 # 0 +0x0000C2BF 0xCA54 # 0 +0x0000C2C0 0xCA5C # 0 +0x0000C2C1 0xCA5D # 0 +0x0000C2C2 0xCA5F # 0 +0x0000C2C3 0xCA60 # 0 +0x0000C2C4 0xCA61 # 0 +0x0000C2C5 0xCA68 # 0 +0x0000C2C6 0xCA7D # 0 +0x0000C2C7 0xCA84 # 0 +0x0000C2C8 0xCA98 # 0 +0x0000C2C9 0xCABC # 0 +0x0000C2CA 0xCABD # 0 +0x0000C2CB 0xCAC0 # 0 +0x0000C2CC 0xCAC4 # 0 +0x0000C2CD 0xCACC # 0 +0x0000C2CE 0xCACD # 0 +0x0000C2CF 0xCACF # 0 +0x0000C2D0 0xCAD1 # 0 +0x0000C2D1 0xCAD3 # 0 +0x0000C2D2 0xCAD8 # 0 +0x0000C2D3 0xCAD9 # 0 +0x0000C2D4 0xCAE0 # 0 +0x0000C2D5 0xCAEC # 0 +0x0000C2D6 0xCAF4 # 0 +0x0000C2D7 0xCB08 # 0 +0x0000C2D8 0xCB10 # 0 +0x0000C2D9 0xCB14 # 0 +0x0000C2DA 0xCB18 # 0 +0x0000C2DB 0xCB20 # 0 +0x0000C2DC 0xCB21 # 0 +0x0000C2DD 0xCB41 # 0 +0x0000C2DE 0xCB48 # 0 +0x0000C2DF 0xCB49 # 0 +0x0000C2E0 0xCB4C # 0 +0x0000C2E1 0xCB50 # 0 +0x0000C2E2 0xCB58 # 0 +0x0000C2E3 0xCB59 # 0 +0x0000C2E4 0xCB5D # 0 +0x0000C2E5 0xCB64 # 0 +0x0000C2E6 0xCB78 # 0 +0x0000C2E7 0xCB79 # 0 +0x0000C2E8 0xCB9C # 0 +0x0000C2E9 0xCBB8 # 0 +0x0000C2EA 0xCBD4 # 0 +0x0000C2EB 0xCBE4 # 0 +0x0000C2EC 0xCBE7 # 0 +0x0000C2ED 0xCBE9 # 0 +0x0000C2EE 0xCC0C # 0 +0x0000C2EF 0xCC0D # 0 +0x0000C2F0 0xCC10 # 0 +0x0000C2F1 0xCC14 # 0 +0x0000C2F2 0xCC1C # 0 +0x0000C2F3 0xCC1D # 0 +0x0000C2F4 0xCC21 # 0 +0x0000C2F5 0xCC22 # 0 +0x0000C2F6 0xCC27 # 0 +0x0000C2F7 0xCC28 # 0 +0x0000C2F8 0xCC29 # 0 +0x0000C2F9 0xCC2C # 0 +0x0000C2FA 0xCC2E # 0 +0x0000C2FB 0xCC30 # 0 +0x0000C2FC 0xCC38 # 0 +0x0000C2FD 0xCC39 # 0 +0x0000C2FE 0xCC3B # 0 +0x0000C3A1 0xCC3C # 0 +0x0000C3A2 0xCC3D # 0 +0x0000C3A3 0xCC3E # 0 +0x0000C3A4 0xCC44 # 0 +0x0000C3A5 0xCC45 # 0 +0x0000C3A6 0xCC48 # 0 +0x0000C3A7 0xCC4C # 0 +0x0000C3A8 0xCC54 # 0 +0x0000C3A9 0xCC55 # 0 +0x0000C3AA 0xCC57 # 0 +0x0000C3AB 0xCC58 # 0 +0x0000C3AC 0xCC59 # 0 +0x0000C3AD 0xCC60 # 0 +0x0000C3AE 0xCC64 # 0 +0x0000C3AF 0xCC66 # 0 +0x0000C3B0 0xCC68 # 0 +0x0000C3B1 0xCC70 # 0 +0x0000C3B2 0xCC75 # 0 +0x0000C3B3 0xCC98 # 0 +0x0000C3B4 0xCC99 # 0 +0x0000C3B5 0xCC9C # 0 +0x0000C3B6 0xCCA0 # 0 +0x0000C3B7 0xCCA8 # 0 +0x0000C3B8 0xCCA9 # 0 +0x0000C3B9 0xCCAB # 0 +0x0000C3BA 0xCCAC # 0 +0x0000C3BB 0xCCAD # 0 +0x0000C3BC 0xCCB4 # 0 +0x0000C3BD 0xCCB5 # 0 +0x0000C3BE 0xCCB8 # 0 +0x0000C3BF 0xCCBC # 0 +0x0000C3C0 0xCCC4 # 0 +0x0000C3C1 0xCCC5 # 0 +0x0000C3C2 0xCCC7 # 0 +0x0000C3C3 0xCCC9 # 0 +0x0000C3C4 0xCCD0 # 0 +0x0000C3C5 0xCCD4 # 0 +0x0000C3C6 0xCCE4 # 0 +0x0000C3C7 0xCCEC # 0 +0x0000C3C8 0xCCF0 # 0 +0x0000C3C9 0xCD01 # 0 +0x0000C3CA 0xCD08 # 0 +0x0000C3CB 0xCD09 # 0 +0x0000C3CC 0xCD0C # 0 +0x0000C3CD 0xCD10 # 0 +0x0000C3CE 0xCD18 # 0 +0x0000C3CF 0xCD19 # 0 +0x0000C3D0 0xCD1B # 0 +0x0000C3D1 0xCD1D # 0 +0x0000C3D2 0xCD24 # 0 +0x0000C3D3 0xCD28 # 0 +0x0000C3D4 0xCD2C # 0 +0x0000C3D5 0xCD39 # 0 +0x0000C3D6 0xCD5C # 0 +0x0000C3D7 0xCD60 # 0 +0x0000C3D8 0xCD64 # 0 +0x0000C3D9 0xCD6C # 0 +0x0000C3DA 0xCD6D # 0 +0x0000C3DB 0xCD6F # 0 +0x0000C3DC 0xCD71 # 0 +0x0000C3DD 0xCD78 # 0 +0x0000C3DE 0xCD88 # 0 +0x0000C3DF 0xCD94 # 0 +0x0000C3E0 0xCD95 # 0 +0x0000C3E1 0xCD98 # 0 +0x0000C3E2 0xCD9C # 0 +0x0000C3E3 0xCDA4 # 0 +0x0000C3E4 0xCDA5 # 0 +0x0000C3E5 0xCDA7 # 0 +0x0000C3E6 0xCDA9 # 0 +0x0000C3E7 0xCDB0 # 0 +0x0000C3E8 0xCDC4 # 0 +0x0000C3E9 0xCDCC # 0 +0x0000C3EA 0xCDD0 # 0 +0x0000C3EB 0xCDE8 # 0 +0x0000C3EC 0xCDEC # 0 +0x0000C3ED 0xCDF0 # 0 +0x0000C3EE 0xCDF8 # 0 +0x0000C3EF 0xCDF9 # 0 +0x0000C3F0 0xCDFB # 0 +0x0000C3F1 0xCDFD # 0 +0x0000C3F2 0xCE04 # 0 +0x0000C3F3 0xCE08 # 0 +0x0000C3F4 0xCE0C # 0 +0x0000C3F5 0xCE14 # 0 +0x0000C3F6 0xCE19 # 0 +0x0000C3F7 0xCE20 # 0 +0x0000C3F8 0xCE21 # 0 +0x0000C3F9 0xCE24 # 0 +0x0000C3FA 0xCE28 # 0 +0x0000C3FB 0xCE30 # 0 +0x0000C3FC 0xCE31 # 0 +0x0000C3FD 0xCE33 # 0 +0x0000C3FE 0xCE35 # 0 +0x0000C4A1 0xCE58 # 0 +0x0000C4A2 0xCE59 # 0 +0x0000C4A3 0xCE5C # 0 +0x0000C4A4 0xCE5F # 0 +0x0000C4A5 0xCE60 # 0 +0x0000C4A6 0xCE61 # 0 +0x0000C4A7 0xCE68 # 0 +0x0000C4A8 0xCE69 # 0 +0x0000C4A9 0xCE6B # 0 +0x0000C4AA 0xCE6D # 0 +0x0000C4AB 0xCE74 # 0 +0x0000C4AC 0xCE75 # 0 +0x0000C4AD 0xCE78 # 0 +0x0000C4AE 0xCE7C # 0 +0x0000C4AF 0xCE84 # 0 +0x0000C4B0 0xCE85 # 0 +0x0000C4B1 0xCE87 # 0 +0x0000C4B2 0xCE89 # 0 +0x0000C4B3 0xCE90 # 0 +0x0000C4B4 0xCE91 # 0 +0x0000C4B5 0xCE94 # 0 +0x0000C4B6 0xCE98 # 0 +0x0000C4B7 0xCEA0 # 0 +0x0000C4B8 0xCEA1 # 0 +0x0000C4B9 0xCEA3 # 0 +0x0000C4BA 0xCEA4 # 0 +0x0000C4BB 0xCEA5 # 0 +0x0000C4BC 0xCEAC # 0 +0x0000C4BD 0xCEAD # 0 +0x0000C4BE 0xCEC1 # 0 +0x0000C4BF 0xCEE4 # 0 +0x0000C4C0 0xCEE5 # 0 +0x0000C4C1 0xCEE8 # 0 +0x0000C4C2 0xCEEB # 0 +0x0000C4C3 0xCEEC # 0 +0x0000C4C4 0xCEF4 # 0 +0x0000C4C5 0xCEF5 # 0 +0x0000C4C6 0xCEF7 # 0 +0x0000C4C7 0xCEF8 # 0 +0x0000C4C8 0xCEF9 # 0 +0x0000C4C9 0xCF00 # 0 +0x0000C4CA 0xCF01 # 0 +0x0000C4CB 0xCF04 # 0 +0x0000C4CC 0xCF08 # 0 +0x0000C4CD 0xCF10 # 0 +0x0000C4CE 0xCF11 # 0 +0x0000C4CF 0xCF13 # 0 +0x0000C4D0 0xCF15 # 0 +0x0000C4D1 0xCF1C # 0 +0x0000C4D2 0xCF20 # 0 +0x0000C4D3 0xCF24 # 0 +0x0000C4D4 0xCF2C # 0 +0x0000C4D5 0xCF2D # 0 +0x0000C4D6 0xCF2F # 0 +0x0000C4D7 0xCF30 # 0 +0x0000C4D8 0xCF31 # 0 +0x0000C4D9 0xCF38 # 0 +0x0000C4DA 0xCF54 # 0 +0x0000C4DB 0xCF55 # 0 +0x0000C4DC 0xCF58 # 0 +0x0000C4DD 0xCF5C # 0 +0x0000C4DE 0xCF64 # 0 +0x0000C4DF 0xCF65 # 0 +0x0000C4E0 0xCF67 # 0 +0x0000C4E1 0xCF69 # 0 +0x0000C4E2 0xCF70 # 0 +0x0000C4E3 0xCF71 # 0 +0x0000C4E4 0xCF74 # 0 +0x0000C4E5 0xCF78 # 0 +0x0000C4E6 0xCF80 # 0 +0x0000C4E7 0xCF85 # 0 +0x0000C4E8 0xCF8C # 0 +0x0000C4E9 0xCFA1 # 0 +0x0000C4EA 0xCFA8 # 0 +0x0000C4EB 0xCFB0 # 0 +0x0000C4EC 0xCFC4 # 0 +0x0000C4ED 0xCFE0 # 0 +0x0000C4EE 0xCFE1 # 0 +0x0000C4EF 0xCFE4 # 0 +0x0000C4F0 0xCFE8 # 0 +0x0000C4F1 0xCFF0 # 0 +0x0000C4F2 0xCFF1 # 0 +0x0000C4F3 0xCFF3 # 0 +0x0000C4F4 0xCFF5 # 0 +0x0000C4F5 0xCFFC # 0 +0x0000C4F6 0xD000 # 0 +0x0000C4F7 0xD004 # 0 +0x0000C4F8 0xD011 # 0 +0x0000C4F9 0xD018 # 0 +0x0000C4FA 0xD02D # 0 +0x0000C4FB 0xD034 # 0 +0x0000C4FC 0xD035 # 0 +0x0000C4FD 0xD038 # 0 +0x0000C4FE 0xD03C # 0 +0x0000C5A1 0xD044 # 0 +0x0000C5A2 0xD045 # 0 +0x0000C5A3 0xD047 # 0 +0x0000C5A4 0xD049 # 0 +0x0000C5A5 0xD050 # 0 +0x0000C5A6 0xD054 # 0 +0x0000C5A7 0xD058 # 0 +0x0000C5A8 0xD060 # 0 +0x0000C5A9 0xD06C # 0 +0x0000C5AA 0xD06D # 0 +0x0000C5AB 0xD070 # 0 +0x0000C5AC 0xD074 # 0 +0x0000C5AD 0xD07C # 0 +0x0000C5AE 0xD07D # 0 +0x0000C5AF 0xD081 # 0 +0x0000C5B0 0xD0A4 # 0 +0x0000C5B1 0xD0A5 # 0 +0x0000C5B2 0xD0A8 # 0 +0x0000C5B3 0xD0AC # 0 +0x0000C5B4 0xD0B4 # 0 +0x0000C5B5 0xD0B5 # 0 +0x0000C5B6 0xD0B7 # 0 +0x0000C5B7 0xD0B9 # 0 +0x0000C5B8 0xD0C0 # 0 +0x0000C5B9 0xD0C1 # 0 +0x0000C5BA 0xD0C4 # 0 +0x0000C5BB 0xD0C8 # 0 +0x0000C5BC 0xD0C9 # 0 +0x0000C5BD 0xD0D0 # 0 +0x0000C5BE 0xD0D1 # 0 +0x0000C5BF 0xD0D3 # 0 +0x0000C5C0 0xD0D4 # 0 +0x0000C5C1 0xD0D5 # 0 +0x0000C5C2 0xD0DC # 0 +0x0000C5C3 0xD0DD # 0 +0x0000C5C4 0xD0E0 # 0 +0x0000C5C5 0xD0E4 # 0 +0x0000C5C6 0xD0EC # 0 +0x0000C5C7 0xD0ED # 0 +0x0000C5C8 0xD0EF # 0 +0x0000C5C9 0xD0F0 # 0 +0x0000C5CA 0xD0F1 # 0 +0x0000C5CB 0xD0F8 # 0 +0x0000C5CC 0xD10D # 0 +0x0000C5CD 0xD130 # 0 +0x0000C5CE 0xD131 # 0 +0x0000C5CF 0xD134 # 0 +0x0000C5D0 0xD138 # 0 +0x0000C5D1 0xD13A # 0 +0x0000C5D2 0xD140 # 0 +0x0000C5D3 0xD141 # 0 +0x0000C5D4 0xD143 # 0 +0x0000C5D5 0xD144 # 0 +0x0000C5D6 0xD145 # 0 +0x0000C5D7 0xD14C # 0 +0x0000C5D8 0xD14D # 0 +0x0000C5D9 0xD150 # 0 +0x0000C5DA 0xD154 # 0 +0x0000C5DB 0xD15C # 0 +0x0000C5DC 0xD15D # 0 +0x0000C5DD 0xD15F # 0 +0x0000C5DE 0xD161 # 0 +0x0000C5DF 0xD168 # 0 +0x0000C5E0 0xD16C # 0 +0x0000C5E1 0xD17C # 0 +0x0000C5E2 0xD184 # 0 +0x0000C5E3 0xD188 # 0 +0x0000C5E4 0xD1A0 # 0 +0x0000C5E5 0xD1A1 # 0 +0x0000C5E6 0xD1A4 # 0 +0x0000C5E7 0xD1A8 # 0 +0x0000C5E8 0xD1B0 # 0 +0x0000C5E9 0xD1B1 # 0 +0x0000C5EA 0xD1B3 # 0 +0x0000C5EB 0xD1B5 # 0 +0x0000C5EC 0xD1BA # 0 +0x0000C5ED 0xD1BC # 0 +0x0000C5EE 0xD1C0 # 0 +0x0000C5EF 0xD1D8 # 0 +0x0000C5F0 0xD1F4 # 0 +0x0000C5F1 0xD1F8 # 0 +0x0000C5F2 0xD207 # 0 +0x0000C5F3 0xD209 # 0 +0x0000C5F4 0xD210 # 0 +0x0000C5F5 0xD22C # 0 +0x0000C5F6 0xD22D # 0 +0x0000C5F7 0xD230 # 0 +0x0000C5F8 0xD234 # 0 +0x0000C5F9 0xD23C # 0 +0x0000C5FA 0xD23D # 0 +0x0000C5FB 0xD23F # 0 +0x0000C5FC 0xD241 # 0 +0x0000C5FD 0xD248 # 0 +0x0000C5FE 0xD25C # 0 +0x0000C6A1 0xD264 # 0 +0x0000C6A2 0xD280 # 0 +0x0000C6A3 0xD281 # 0 +0x0000C6A4 0xD284 # 0 +0x0000C6A5 0xD288 # 0 +0x0000C6A6 0xD290 # 0 +0x0000C6A7 0xD291 # 0 +0x0000C6A8 0xD295 # 0 +0x0000C6A9 0xD29C # 0 +0x0000C6AA 0xD2A0 # 0 +0x0000C6AB 0xD2A4 # 0 +0x0000C6AC 0xD2AC # 0 +0x0000C6AD 0xD2B1 # 0 +0x0000C6AE 0xD2B8 # 0 +0x0000C6AF 0xD2B9 # 0 +0x0000C6B0 0xD2BC # 0 +0x0000C6B1 0xD2BF # 0 +0x0000C6B2 0xD2C0 # 0 +0x0000C6B3 0xD2C2 # 0 +0x0000C6B4 0xD2C8 # 0 +0x0000C6B5 0xD2C9 # 0 +0x0000C6B6 0xD2CB # 0 +0x0000C6B7 0xD2D4 # 0 +0x0000C6B8 0xD2D8 # 0 +0x0000C6B9 0xD2DC # 0 +0x0000C6BA 0xD2E4 # 0 +0x0000C6BB 0xD2E5 # 0 +0x0000C6BC 0xD2F0 # 0 +0x0000C6BD 0xD2F1 # 0 +0x0000C6BE 0xD2F4 # 0 +0x0000C6BF 0xD2F8 # 0 +0x0000C6C0 0xD300 # 0 +0x0000C6C1 0xD301 # 0 +0x0000C6C2 0xD303 # 0 +0x0000C6C3 0xD305 # 0 +0x0000C6C4 0xD30C # 0 +0x0000C6C5 0xD30D # 0 +0x0000C6C6 0xD30E # 0 +0x0000C6C7 0xD310 # 0 +0x0000C6C8 0xD314 # 0 +0x0000C6C9 0xD316 # 0 +0x0000C6CA 0xD31C # 0 +0x0000C6CB 0xD31D # 0 +0x0000C6CC 0xD31F # 0 +0x0000C6CD 0xD320 # 0 +0x0000C6CE 0xD321 # 0 +0x0000C6CF 0xD325 # 0 +0x0000C6D0 0xD328 # 0 +0x0000C6D1 0xD329 # 0 +0x0000C6D2 0xD32C # 0 +0x0000C6D3 0xD330 # 0 +0x0000C6D4 0xD338 # 0 +0x0000C6D5 0xD339 # 0 +0x0000C6D6 0xD33B # 0 +0x0000C6D7 0xD33C # 0 +0x0000C6D8 0xD33D # 0 +0x0000C6D9 0xD344 # 0 +0x0000C6DA 0xD345 # 0 +0x0000C6DB 0xD37C # 0 +0x0000C6DC 0xD37D # 0 +0x0000C6DD 0xD380 # 0 +0x0000C6DE 0xD384 # 0 +0x0000C6DF 0xD38C # 0 +0x0000C6E0 0xD38D # 0 +0x0000C6E1 0xD38F # 0 +0x0000C6E2 0xD390 # 0 +0x0000C6E3 0xD391 # 0 +0x0000C6E4 0xD398 # 0 +0x0000C6E5 0xD399 # 0 +0x0000C6E6 0xD39C # 0 +0x0000C6E7 0xD3A0 # 0 +0x0000C6E8 0xD3A8 # 0 +0x0000C6E9 0xD3A9 # 0 +0x0000C6EA 0xD3AB # 0 +0x0000C6EB 0xD3AD # 0 +0x0000C6EC 0xD3B4 # 0 +0x0000C6ED 0xD3B8 # 0 +0x0000C6EE 0xD3BC # 0 +0x0000C6EF 0xD3C4 # 0 +0x0000C6F0 0xD3C5 # 0 +0x0000C6F1 0xD3C8 # 0 +0x0000C6F2 0xD3C9 # 0 +0x0000C6F3 0xD3D0 # 0 +0x0000C6F4 0xD3D8 # 0 +0x0000C6F5 0xD3E1 # 0 +0x0000C6F6 0xD3E3 # 0 +0x0000C6F7 0xD3EC # 0 +0x0000C6F8 0xD3ED # 0 +0x0000C6F9 0xD3F0 # 0 +0x0000C6FA 0xD3F4 # 0 +0x0000C6FB 0xD3FC # 0 +0x0000C6FC 0xD3FD # 0 +0x0000C6FD 0xD3FF # 0 +0x0000C6FE 0xD401 # 0 +0x0000C7A1 0xD408 # 0 +0x0000C7A2 0xD41D # 0 +0x0000C7A3 0xD440 # 0 +0x0000C7A4 0xD444 # 0 +0x0000C7A5 0xD45C # 0 +0x0000C7A6 0xD460 # 0 +0x0000C7A7 0xD464 # 0 +0x0000C7A8 0xD46D # 0 +0x0000C7A9 0xD46F # 0 +0x0000C7AA 0xD478 # 0 +0x0000C7AB 0xD479 # 0 +0x0000C7AC 0xD47C # 0 +0x0000C7AD 0xD47F # 0 +0x0000C7AE 0xD480 # 0 +0x0000C7AF 0xD482 # 0 +0x0000C7B0 0xD488 # 0 +0x0000C7B1 0xD489 # 0 +0x0000C7B2 0xD48B # 0 +0x0000C7B3 0xD48D # 0 +0x0000C7B4 0xD494 # 0 +0x0000C7B5 0xD4A9 # 0 +0x0000C7B6 0xD4CC # 0 +0x0000C7B7 0xD4D0 # 0 +0x0000C7B8 0xD4D4 # 0 +0x0000C7B9 0xD4DC # 0 +0x0000C7BA 0xD4DF # 0 +0x0000C7BB 0xD4E8 # 0 +0x0000C7BC 0xD4EC # 0 +0x0000C7BD 0xD4F0 # 0 +0x0000C7BE 0xD4F8 # 0 +0x0000C7BF 0xD4FB # 0 +0x0000C7C0 0xD4FD # 0 +0x0000C7C1 0xD504 # 0 +0x0000C7C2 0xD508 # 0 +0x0000C7C3 0xD50C # 0 +0x0000C7C4 0xD514 # 0 +0x0000C7C5 0xD515 # 0 +0x0000C7C6 0xD517 # 0 +0x0000C7C7 0xD53C # 0 +0x0000C7C8 0xD53D # 0 +0x0000C7C9 0xD540 # 0 +0x0000C7CA 0xD544 # 0 +0x0000C7CB 0xD54C # 0 +0x0000C7CC 0xD54D # 0 +0x0000C7CD 0xD54F # 0 +0x0000C7CE 0xD551 # 0 +0x0000C7CF 0xD558 # 0 +0x0000C7D0 0xD559 # 0 +0x0000C7D1 0xD55C # 0 +0x0000C7D2 0xD560 # 0 +0x0000C7D3 0xD565 # 0 +0x0000C7D4 0xD568 # 0 +0x0000C7D5 0xD569 # 0 +0x0000C7D6 0xD56B # 0 +0x0000C7D7 0xD56D # 0 +0x0000C7D8 0xD574 # 0 +0x0000C7D9 0xD575 # 0 +0x0000C7DA 0xD578 # 0 +0x0000C7DB 0xD57C # 0 +0x0000C7DC 0xD584 # 0 +0x0000C7DD 0xD585 # 0 +0x0000C7DE 0xD587 # 0 +0x0000C7DF 0xD588 # 0 +0x0000C7E0 0xD589 # 0 +0x0000C7E1 0xD590 # 0 +0x0000C7E2 0xD5A5 # 0 +0x0000C7E3 0xD5C8 # 0 +0x0000C7E4 0xD5C9 # 0 +0x0000C7E5 0xD5CC # 0 +0x0000C7E6 0xD5D0 # 0 +0x0000C7E7 0xD5D2 # 0 +0x0000C7E8 0xD5D8 # 0 +0x0000C7E9 0xD5D9 # 0 +0x0000C7EA 0xD5DB # 0 +0x0000C7EB 0xD5DD # 0 +0x0000C7EC 0xD5E4 # 0 +0x0000C7ED 0xD5E5 # 0 +0x0000C7EE 0xD5E8 # 0 +0x0000C7EF 0xD5EC # 0 +0x0000C7F0 0xD5F4 # 0 +0x0000C7F1 0xD5F5 # 0 +0x0000C7F2 0xD5F7 # 0 +0x0000C7F3 0xD5F9 # 0 +0x0000C7F4 0xD600 # 0 +0x0000C7F5 0xD601 # 0 +0x0000C7F6 0xD604 # 0 +0x0000C7F7 0xD608 # 0 +0x0000C7F8 0xD610 # 0 +0x0000C7F9 0xD611 # 0 +0x0000C7FA 0xD613 # 0 +0x0000C7FB 0xD614 # 0 +0x0000C7FC 0xD615 # 0 +0x0000C7FD 0xD61C # 0 +0x0000C7FE 0xD620 # 0 +0x0000C8A1 0xD624 # 0 +0x0000C8A2 0xD62D # 0 +0x0000C8A3 0xD638 # 0 +0x0000C8A4 0xD639 # 0 +0x0000C8A5 0xD63C # 0 +0x0000C8A6 0xD640 # 0 +0x0000C8A7 0xD645 # 0 +0x0000C8A8 0xD648 # 0 +0x0000C8A9 0xD649 # 0 +0x0000C8AA 0xD64B # 0 +0x0000C8AB 0xD64D # 0 +0x0000C8AC 0xD651 # 0 +0x0000C8AD 0xD654 # 0 +0x0000C8AE 0xD655 # 0 +0x0000C8AF 0xD658 # 0 +0x0000C8B0 0xD65C # 0 +0x0000C8B1 0xD667 # 0 +0x0000C8B2 0xD669 # 0 +0x0000C8B3 0xD670 # 0 +0x0000C8B4 0xD671 # 0 +0x0000C8B5 0xD674 # 0 +0x0000C8B6 0xD683 # 0 +0x0000C8B7 0xD685 # 0 +0x0000C8B8 0xD68C # 0 +0x0000C8B9 0xD68D # 0 +0x0000C8BA 0xD690 # 0 +0x0000C8BB 0xD694 # 0 +0x0000C8BC 0xD69D # 0 +0x0000C8BD 0xD69F # 0 +0x0000C8BE 0xD6A1 # 0 +0x0000C8BF 0xD6A8 # 0 +0x0000C8C0 0xD6AC # 0 +0x0000C8C1 0xD6B0 # 0 +0x0000C8C2 0xD6B9 # 0 +0x0000C8C3 0xD6BB # 0 +0x0000C8C4 0xD6C4 # 0 +0x0000C8C5 0xD6C5 # 0 +0x0000C8C6 0xD6C8 # 0 +0x0000C8C7 0xD6CC # 0 +0x0000C8C8 0xD6D1 # 0 +0x0000C8C9 0xD6D4 # 0 +0x0000C8CA 0xD6D7 # 0 +0x0000C8CB 0xD6D9 # 0 +0x0000C8CC 0xD6E0 # 0 +0x0000C8CD 0xD6E4 # 0 +0x0000C8CE 0xD6E8 # 0 +0x0000C8CF 0xD6F0 # 0 +0x0000C8D0 0xD6F5 # 0 +0x0000C8D1 0xD6FC # 0 +0x0000C8D2 0xD6FD # 0 +0x0000C8D3 0xD700 # 0 +0x0000C8D4 0xD704 # 0 +0x0000C8D5 0xD711 # 0 +0x0000C8D6 0xD718 # 0 +0x0000C8D7 0xD719 # 0 +0x0000C8D8 0xD71C # 0 +0x0000C8D9 0xD720 # 0 +0x0000C8DA 0xD728 # 0 +0x0000C8DB 0xD729 # 0 +0x0000C8DC 0xD72B # 0 +0x0000C8DD 0xD72D # 0 +0x0000C8DE 0xD734 # 0 +0x0000C8DF 0xD735 # 0 +0x0000C8E0 0xD738 # 0 +0x0000C8E1 0xD73C # 0 +0x0000C8E2 0xD744 # 0 +0x0000C8E3 0xD747 # 0 +0x0000C8E4 0xD749 # 0 +0x0000C8E5 0xD750 # 0 +0x0000C8E6 0xD751 # 0 +0x0000C8E7 0xD754 # 0 +0x0000C8E8 0xD756 # 0 +0x0000C8E9 0xD757 # 0 +0x0000C8EA 0xD758 # 0 +0x0000C8EB 0xD759 # 0 +0x0000C8EC 0xD760 # 0 +0x0000C8ED 0xD761 # 0 +0x0000C8EE 0xD763 # 0 +0x0000C8EF 0xD765 # 0 +0x0000C8F0 0xD769 # 0 +0x0000C8F1 0xD76C # 0 +0x0000C8F2 0xD770 # 0 +0x0000C8F3 0xD774 # 0 +0x0000C8F4 0xD77C # 0 +0x0000C8F5 0xD77D # 0 +0x0000C8F6 0xD781 # 0 +0x0000C8F7 0xD788 # 0 +0x0000C8F8 0xD789 # 0 +0x0000C8F9 0xD78C # 0 +0x0000C8FA 0xD790 # 0 +0x0000C8FB 0xD798 # 0 +0x0000C8FC 0xD799 # 0 +0x0000C8FD 0xD79B # 0 +0x0000C8FE 0xD79D # 0 +0x0000C9A1 0xF700 # 0 +0x0000C9A2 0xF701 # 0 +0x0000C9A3 0xF702 # 0 +0x0000C9A4 0xF703 # 0 +0x0000C9A5 0xF704 # 0 +0x0000C9A6 0xF705 # 0 +0x0000C9A7 0xF706 # 0 +0x0000C9A8 0xF707 # 0 +0x0000C9A9 0xF708 # 0 +0x0000C9AA 0xF709 # 0 +0x0000C9AB 0xF70A # 0 +0x0000C9AC 0xF70B # 0 +0x0000C9AD 0xF70C # 0 +0x0000C9AE 0xF70D # 0 +0x0000C9AF 0xF70E # 0 +0x0000C9B0 0xF70F # 0 +0x0000C9B1 0xF710 # 0 +0x0000C9B2 0xF711 # 0 +0x0000C9B3 0xF712 # 0 +0x0000C9B4 0xF713 # 0 +0x0000C9B5 0xF714 # 0 +0x0000C9B6 0xF715 # 0 +0x0000C9B7 0xF716 # 0 +0x0000C9B8 0xF717 # 0 +0x0000C9B9 0xF718 # 0 +0x0000C9BA 0xF719 # 0 +0x0000C9BB 0xF71A # 0 +0x0000C9BC 0xF71B # 0 +0x0000C9BD 0xF71C # 0 +0x0000C9BE 0xF71D # 0 +0x0000C9BF 0xF71E # 0 +0x0000C9C0 0xF71F # 0 +0x0000C9C1 0xF720 # 0 +0x0000C9C2 0xF721 # 0 +0x0000C9C3 0xF722 # 0 +0x0000C9C4 0xF723 # 0 +0x0000C9C5 0xF724 # 0 +0x0000C9C6 0xF725 # 0 +0x0000C9C7 0xF726 # 0 +0x0000C9C8 0xF727 # 0 +0x0000C9C9 0xF728 # 0 +0x0000C9CA 0xF729 # 0 +0x0000C9CB 0xF72A # 0 +0x0000C9CC 0xF72B # 0 +0x0000C9CD 0xF72C # 0 +0x0000C9CE 0xF72D # 0 +0x0000C9CF 0xF72E # 0 +0x0000C9D0 0xF72F # 0 +0x0000C9D1 0xF730 # 0 +0x0000C9D2 0xF731 # 0 +0x0000C9D3 0xF732 # 0 +0x0000C9D4 0xF733 # 0 +0x0000C9D5 0xF734 # 0 +0x0000C9D6 0xF735 # 0 +0x0000C9D7 0xF736 # 0 +0x0000C9D8 0xF737 # 0 +0x0000C9D9 0xF738 # 0 +0x0000C9DA 0xF739 # 0 +0x0000C9DB 0xF73A # 0 +0x0000C9DC 0xF73B # 0 +0x0000C9DD 0xF73C # 0 +0x0000C9DE 0xF73D # 0 +0x0000C9DF 0xF73E # 0 +0x0000C9E0 0xF73F # 0 +0x0000C9E1 0xF740 # 0 +0x0000C9E2 0xF741 # 0 +0x0000C9E3 0xF742 # 0 +0x0000C9E4 0xF743 # 0 +0x0000C9E5 0xF744 # 0 +0x0000C9E6 0xF745 # 0 +0x0000C9E7 0xF746 # 0 +0x0000C9E8 0xF747 # 0 +0x0000C9E9 0xF748 # 0 +0x0000C9EA 0xF749 # 0 +0x0000C9EB 0xF74A # 0 +0x0000C9EC 0xF74B # 0 +0x0000C9ED 0xF74C # 0 +0x0000C9EE 0xF74D # 0 +0x0000C9EF 0xF74E # 0 +0x0000C9F0 0xF74F # 0 +0x0000C9F1 0xF750 # 0 +0x0000C9F2 0xF751 # 0 +0x0000C9F3 0xF752 # 0 +0x0000C9F4 0xF753 # 0 +0x0000C9F5 0xF754 # 0 +0x0000C9F6 0xF755 # 0 +0x0000C9F7 0xF756 # 0 +0x0000C9F8 0xF757 # 0 +0x0000C9F9 0xF758 # 0 +0x0000C9FA 0xF759 # 0 +0x0000C9FB 0xF75A # 0 +0x0000C9FC 0xF75B # 0 +0x0000C9FD 0xF75C # 0 +0x0000C9FE 0xF75D # 0 +0x0000CAA1 0x4F3D # 0 +0x0000CAA2 0x4F73 # 0 +0x0000CAA3 0x5047 # 0 +0x0000CAA4 0x50F9 # 0 +0x0000CAA5 0x52A0 # 0 +0x0000CAA6 0x53EF # 0 +0x0000CAA7 0x5475 # 0 +0x0000CAA8 0x54E5 # 0 +0x0000CAA9 0x5609 # 0 +0x0000CAAA 0x5AC1 # 0 +0x0000CAAB 0x5BB6 # 0 +0x0000CAAC 0x6687 # 0 +0x0000CAAD 0x67B6 # 0 +0x0000CAAE 0x67B7 # 0 +0x0000CAAF 0x67EF # 0 +0x0000CAB0 0x6B4C # 0 +0x0000CAB1 0x73C2 # 0 +0x0000CAB2 0x75C2 # 0 +0x0000CAB3 0x7A3C # 0 +0x0000CAB4 0x82DB # 0 +0x0000CAB5 0x8304 # 0 +0x0000CAB6 0x8857 # 0 +0x0000CAB7 0x8888 # 0 +0x0000CAB8 0x8A36 # 0 +0x0000CAB9 0x8CC8 # 0 +0x0000CABA 0x8DCF # 0 +0x0000CABB 0x8EFB # 0 +0x0000CABC 0x8FE6 # 0 +0x0000CABD 0x99D5 # 0 +0x0000CABE 0x523B # 0 +0x0000CABF 0x5374 # 0 +0x0000CAC0 0x5404 # 0 +0x0000CAC1 0x606A # 0 +0x0000CAC2 0x6164 # 0 +0x0000CAC3 0x6BBC # 0 +0x0000CAC4 0x73CF # 0 +0x0000CAC5 0x811A # 0 +0x0000CAC6 0x89BA # 0 +0x0000CAC7 0x89D2 # 0 +0x0000CAC8 0x95A3 # 0 +0x0000CAC9 0x4F83 # 0 +0x0000CACA 0x520A # 0 +0x0000CACB 0x58BE # 0 +0x0000CACC 0x5978 # 0 +0x0000CACD 0x59E6 # 0 +0x0000CACE 0x5E72 # 0 +0x0000CACF 0x5E79 # 0 +0x0000CAD0 0x61C7 # 0 +0x0000CAD1 0x63C0 # 0 +0x0000CAD2 0x6746 # 0 +0x0000CAD3 0x67EC # 0 +0x0000CAD4 0x687F # 0 +0x0000CAD5 0x6F97 # 0 +0x0000CAD6 0x764E # 0 +0x0000CAD7 0x770B # 0 +0x0000CAD8 0x78F5 # 0 +0x0000CAD9 0x7A08 # 0 +0x0000CADA 0x7AFF # 0 +0x0000CADB 0x7C21 # 0 +0x0000CADC 0x809D # 0 +0x0000CADD 0x826E # 0 +0x0000CADE 0x8271 # 0 +0x0000CADF 0x8AEB # 0 +0x0000CAE0 0x9593 # 0 +0x0000CAE1 0x4E6B # 0 +0x0000CAE2 0x559D # 0 +0x0000CAE3 0x66F7 # 0 +0x0000CAE4 0x6E34 # 0 +0x0000CAE5 0x78A3 # 0 +0x0000CAE6 0x7AED # 0 +0x0000CAE7 0x845B # 0 +0x0000CAE8 0x8910 # 0 +0x0000CAE9 0x874E # 0 +0x0000CAEA 0x97A8 # 0 +0x0000CAEB 0x52D8 # 0 +0x0000CAEC 0x574E # 0 +0x0000CAED 0x582A # 0 +0x0000CAEE 0x5D4C # 0 +0x0000CAEF 0x611F # 0 +0x0000CAF0 0x61BE # 0 +0x0000CAF1 0x6221 # 0 +0x0000CAF2 0x6562 # 0 +0x0000CAF3 0x67D1 # 0 +0x0000CAF4 0x6A44 # 0 +0x0000CAF5 0x6E1B # 0 +0x0000CAF6 0x7518 # 0 +0x0000CAF7 0x75B3 # 0 +0x0000CAF8 0x76E3 # 0 +0x0000CAF9 0x77B0 # 0 +0x0000CAFA 0x7D3A # 0 +0x0000CAFB 0x90AF # 0 +0x0000CAFC 0x9451 # 0 +0x0000CAFD 0x9452 # 0 +0x0000CAFE 0x9F95 # 0 +0x0000CBA1 0x5323 # 0 +0x0000CBA2 0x5CAC # 0 +0x0000CBA3 0x7532 # 0 +0x0000CBA4 0x80DB # 0 +0x0000CBA5 0x9240 # 0 +0x0000CBA6 0x9598 # 0 +0x0000CBA7 0x525B # 0 +0x0000CBA8 0x5808 # 0 +0x0000CBA9 0x59DC # 0 +0x0000CBAA 0x5CA1 # 0 +0x0000CBAB 0x5D17 # 0 +0x0000CBAC 0x5EB7 # 0 +0x0000CBAD 0x5F3A # 0 +0x0000CBAE 0x5F4A # 0 +0x0000CBAF 0x6177 # 0 +0x0000CBB0 0x6C5F # 0 +0x0000CBB1 0x757A # 0 +0x0000CBB2 0x7586 # 0 +0x0000CBB3 0x7CE0 # 0 +0x0000CBB4 0x7D73 # 0 +0x0000CBB5 0x7DB1 # 0 +0x0000CBB6 0x7F8C # 0 +0x0000CBB7 0x8154 # 0 +0x0000CBB8 0x8221 # 0 +0x0000CBB9 0x8591 # 0 +0x0000CBBA 0x8941 # 0 +0x0000CBBB 0x8B1B # 0 +0x0000CBBC 0x92FC # 0 +0x0000CBBD 0x964D # 0 +0x0000CBBE 0x9C47 # 0 +0x0000CBBF 0x4ECB # 0 +0x0000CBC0 0x4EF7 # 0 +0x0000CBC1 0x500B # 0 +0x0000CBC2 0x51F1 # 0 +0x0000CBC3 0x584F # 0 +0x0000CBC4 0x6137 # 0 +0x0000CBC5 0x613E # 0 +0x0000CBC6 0x6168 # 0 +0x0000CBC7 0x6539 # 0 +0x0000CBC8 0x69EA # 0 +0x0000CBC9 0x6F11 # 0 +0x0000CBCA 0x75A5 # 0 +0x0000CBCB 0x7686 # 0 +0x0000CBCC 0x76D6 # 0 +0x0000CBCD 0x7B87 # 0 +0x0000CBCE 0x82A5 # 0 +0x0000CBCF 0x84CB # 0 +0x0000CBD0 0xF900 # 0 +0x0000CBD1 0x93A7 # 0 +0x0000CBD2 0x958B # 0 +0x0000CBD3 0x5580 # 0 +0x0000CBD4 0x5BA2 # 0 +0x0000CBD5 0x5751 # 0 +0x0000CBD6 0xF901 # 0 +0x0000CBD7 0x7CB3 # 0 +0x0000CBD8 0x7FB9 # 0 +0x0000CBD9 0x91B5 # 0 +0x0000CBDA 0x5028 # 0 +0x0000CBDB 0x53BB # 0 +0x0000CBDC 0x5C45 # 0 +0x0000CBDD 0x5DE8 # 0 +0x0000CBDE 0x62D2 # 0 +0x0000CBDF 0x636E # 0 +0x0000CBE0 0x64DA # 0 +0x0000CBE1 0x64E7 # 0 +0x0000CBE2 0x6E20 # 0 +0x0000CBE3 0x70AC # 0 +0x0000CBE4 0x795B # 0 +0x0000CBE5 0x8DDD # 0 +0x0000CBE6 0x8E1E # 0 +0x0000CBE7 0xF902 # 0 +0x0000CBE8 0x907D # 0 +0x0000CBE9 0x9245 # 0 +0x0000CBEA 0x92F8 # 0 +0x0000CBEB 0x4E7E # 0 +0x0000CBEC 0x4EF6 # 0 +0x0000CBED 0x5065 # 0 +0x0000CBEE 0x5DFE # 0 +0x0000CBEF 0x5EFA # 0 +0x0000CBF0 0x6106 # 0 +0x0000CBF1 0x6957 # 0 +0x0000CBF2 0x8171 # 0 +0x0000CBF3 0x8654 # 0 +0x0000CBF4 0x8E47 # 0 +0x0000CBF5 0x9375 # 0 +0x0000CBF6 0x9A2B # 0 +0x0000CBF7 0x4E5E # 0 +0x0000CBF8 0x5091 # 0 +0x0000CBF9 0x6770 # 0 +0x0000CBFA 0x6840 # 0 +0x0000CBFB 0x5109 # 0 +0x0000CBFC 0x528D # 0 +0x0000CBFD 0x5292 # 0 +0x0000CBFE 0x6AA2 # 0 +0x0000CCA1 0x77BC # 0 +0x0000CCA2 0x9210 # 0 +0x0000CCA3 0x9ED4 # 0 +0x0000CCA4 0x52AB # 0 +0x0000CCA5 0x602F # 0 +0x0000CCA6 0x8FF2 # 0 +0x0000CCA7 0x5048 # 0 +0x0000CCA8 0x61A9 # 0 +0x0000CCA9 0x63ED # 0 +0x0000CCAA 0x64CA # 0 +0x0000CCAB 0x683C # 0 +0x0000CCAC 0x6A84 # 0 +0x0000CCAD 0x6FC0 # 0 +0x0000CCAE 0x8188 # 0 +0x0000CCAF 0x89A1 # 0 +0x0000CCB0 0x9694 # 0 +0x0000CCB1 0x5805 # 0 +0x0000CCB2 0x727D # 0 +0x0000CCB3 0x72AC # 0 +0x0000CCB4 0x7504 # 0 +0x0000CCB5 0x7D79 # 0 +0x0000CCB6 0x7E6D # 0 +0x0000CCB7 0x80A9 # 0 +0x0000CCB8 0x898B # 0 +0x0000CCB9 0x8B74 # 0 +0x0000CCBA 0x9063 # 0 +0x0000CCBB 0x9D51 # 0 +0x0000CCBC 0x6289 # 0 +0x0000CCBD 0x6C7A # 0 +0x0000CCBE 0x6F54 # 0 +0x0000CCBF 0x7D50 # 0 +0x0000CCC0 0x7F3A # 0 +0x0000CCC1 0x8A23 # 0 +0x0000CCC2 0x517C # 0 +0x0000CCC3 0x614A # 0 +0x0000CCC4 0x7B9D # 0 +0x0000CCC5 0x8B19 # 0 +0x0000CCC6 0x9257 # 0 +0x0000CCC7 0x938C # 0 +0x0000CCC8 0x4EAC # 0 +0x0000CCC9 0x4FD3 # 0 +0x0000CCCA 0x501E # 0 +0x0000CCCB 0x50BE # 0 +0x0000CCCC 0x5106 # 0 +0x0000CCCD 0x52C1 # 0 +0x0000CCCE 0x52CD # 0 +0x0000CCCF 0x537F # 0 +0x0000CCD0 0x5770 # 0 +0x0000CCD1 0x5883 # 0 +0x0000CCD2 0x5E9A # 0 +0x0000CCD3 0x5F91 # 0 +0x0000CCD4 0x6176 # 0 +0x0000CCD5 0x61AC # 0 +0x0000CCD6 0x64CE # 0 +0x0000CCD7 0x656C # 0 +0x0000CCD8 0x666F # 0 +0x0000CCD9 0x66BB # 0 +0x0000CCDA 0x66F4 # 0 +0x0000CCDB 0x6897 # 0 +0x0000CCDC 0x6D87 # 0 +0x0000CCDD 0x7085 # 0 +0x0000CCDE 0x70F1 # 0 +0x0000CCDF 0x749F # 0 +0x0000CCE0 0x74A5 # 0 +0x0000CCE1 0x74CA # 0 +0x0000CCE2 0x75D9 # 0 +0x0000CCE3 0x786C # 0 +0x0000CCE4 0x78EC # 0 +0x0000CCE5 0x7ADF # 0 +0x0000CCE6 0x7AF6 # 0 +0x0000CCE7 0x7D45 # 0 +0x0000CCE8 0x7D93 # 0 +0x0000CCE9 0x8015 # 0 +0x0000CCEA 0x803F # 0 +0x0000CCEB 0x811B # 0 +0x0000CCEC 0x8396 # 0 +0x0000CCED 0x8B66 # 0 +0x0000CCEE 0x8F15 # 0 +0x0000CCEF 0x9015 # 0 +0x0000CCF0 0x93E1 # 0 +0x0000CCF1 0x9803 # 0 +0x0000CCF2 0x9838 # 0 +0x0000CCF3 0x9A5A # 0 +0x0000CCF4 0x9BE8 # 0 +0x0000CCF5 0x4FC2 # 0 +0x0000CCF6 0x5553 # 0 +0x0000CCF7 0x583A # 0 +0x0000CCF8 0x5951 # 0 +0x0000CCF9 0x5B63 # 0 +0x0000CCFA 0x5C46 # 0 +0x0000CCFB 0x60B8 # 0 +0x0000CCFC 0x6212 # 0 +0x0000CCFD 0x6842 # 0 +0x0000CCFE 0x68B0 # 0 +0x0000CDA1 0x68E8 # 0 +0x0000CDA2 0x6EAA # 0 +0x0000CDA3 0x754C # 0 +0x0000CDA4 0x7678 # 0 +0x0000CDA5 0x78CE # 0 +0x0000CDA6 0x7A3D # 0 +0x0000CDA7 0x7CFB # 0 +0x0000CDA8 0x7E6B # 0 +0x0000CDA9 0x7E7C # 0 +0x0000CDAA 0x8A08 # 0 +0x0000CDAB 0x8AA1 # 0 +0x0000CDAC 0x8C3F # 0 +0x0000CDAD 0x968E # 0 +0x0000CDAE 0x9DC4 # 0 +0x0000CDAF 0x53E4 # 0 +0x0000CDB0 0x53E9 # 0 +0x0000CDB1 0x544A # 0 +0x0000CDB2 0x5471 # 0 +0x0000CDB3 0x56FA # 0 +0x0000CDB4 0x59D1 # 0 +0x0000CDB5 0x5B64 # 0 +0x0000CDB6 0x5C3B # 0 +0x0000CDB7 0x5EAB # 0 +0x0000CDB8 0x62F7 # 0 +0x0000CDB9 0x6537 # 0 +0x0000CDBA 0x6545 # 0 +0x0000CDBB 0x6572 # 0 +0x0000CDBC 0x66A0 # 0 +0x0000CDBD 0x67AF # 0 +0x0000CDBE 0x69C1 # 0 +0x0000CDBF 0x6CBD # 0 +0x0000CDC0 0x75FC # 0 +0x0000CDC1 0x7690 # 0 +0x0000CDC2 0x777E # 0 +0x0000CDC3 0x7A3F # 0 +0x0000CDC4 0x7F94 # 0 +0x0000CDC5 0x8003 # 0 +0x0000CDC6 0x80A1 # 0 +0x0000CDC7 0x818F # 0 +0x0000CDC8 0x82E6 # 0 +0x0000CDC9 0x82FD # 0 +0x0000CDCA 0x83F0 # 0 +0x0000CDCB 0x85C1 # 0 +0x0000CDCC 0x8831 # 0 +0x0000CDCD 0x88B4 # 0 +0x0000CDCE 0x8AA5 # 0 +0x0000CDCF 0xF903 # 0 +0x0000CDD0 0x8F9C # 0 +0x0000CDD1 0x932E # 0 +0x0000CDD2 0x96C7 # 0 +0x0000CDD3 0x9867 # 0 +0x0000CDD4 0x9AD8 # 0 +0x0000CDD5 0x9F13 # 0 +0x0000CDD6 0x54ED # 0 +0x0000CDD7 0x659B # 0 +0x0000CDD8 0x66F2 # 0 +0x0000CDD9 0x688F # 0 +0x0000CDDA 0x7A40 # 0 +0x0000CDDB 0x8C37 # 0 +0x0000CDDC 0x9D60 # 0 +0x0000CDDD 0x56F0 # 0 +0x0000CDDE 0x5764 # 0 +0x0000CDDF 0x5D11 # 0 +0x0000CDE0 0x6606 # 0 +0x0000CDE1 0x68B1 # 0 +0x0000CDE2 0x68CD # 0 +0x0000CDE3 0x6EFE # 0 +0x0000CDE4 0x7428 # 0 +0x0000CDE5 0x889E # 0 +0x0000CDE6 0x9BE4 # 0 +0x0000CDE7 0x6C68 # 0 +0x0000CDE8 0xF904 # 0 +0x0000CDE9 0x9AA8 # 0 +0x0000CDEA 0x4F9B # 0 +0x0000CDEB 0x516C # 0 +0x0000CDEC 0x5171 # 0 +0x0000CDED 0x529F # 0 +0x0000CDEE 0x5B54 # 0 +0x0000CDEF 0x5DE5 # 0 +0x0000CDF0 0x6050 # 0 +0x0000CDF1 0x606D # 0 +0x0000CDF2 0x62F1 # 0 +0x0000CDF3 0x63A7 # 0 +0x0000CDF4 0x653B # 0 +0x0000CDF5 0x73D9 # 0 +0x0000CDF6 0x7A7A # 0 +0x0000CDF7 0x86A3 # 0 +0x0000CDF8 0x8CA2 # 0 +0x0000CDF9 0x978F # 0 +0x0000CDFA 0x4E32 # 0 +0x0000CDFB 0x5BE1 # 0 +0x0000CDFC 0x6208 # 0 +0x0000CDFD 0x679C # 0 +0x0000CDFE 0x74DC # 0 +0x0000CEA1 0x79D1 # 0 +0x0000CEA2 0x83D3 # 0 +0x0000CEA3 0x8A87 # 0 +0x0000CEA4 0x8AB2 # 0 +0x0000CEA5 0x8DE8 # 0 +0x0000CEA6 0x904E # 0 +0x0000CEA7 0x934B # 0 +0x0000CEA8 0x9846 # 0 +0x0000CEA9 0x5ED3 # 0 +0x0000CEAA 0x69E8 # 0 +0x0000CEAB 0x85FF # 0 +0x0000CEAC 0x90ED # 0 +0x0000CEAD 0xF905 # 0 +0x0000CEAE 0x51A0 # 0 +0x0000CEAF 0x5B98 # 0 +0x0000CEB0 0x5BEC # 0 +0x0000CEB1 0x6163 # 0 +0x0000CEB2 0x68FA # 0 +0x0000CEB3 0x6B3E # 0 +0x0000CEB4 0x704C # 0 +0x0000CEB5 0x742F # 0 +0x0000CEB6 0x74D8 # 0 +0x0000CEB7 0x7BA1 # 0 +0x0000CEB8 0x7F50 # 0 +0x0000CEB9 0x83C5 # 0 +0x0000CEBA 0x89C0 # 0 +0x0000CEBB 0x8CAB # 0 +0x0000CEBC 0x95DC # 0 +0x0000CEBD 0x9928 # 0 +0x0000CEBE 0x522E # 0 +0x0000CEBF 0x605D # 0 +0x0000CEC0 0x62EC # 0 +0x0000CEC1 0x9002 # 0 +0x0000CEC2 0x4F8A # 0 +0x0000CEC3 0x5149 # 0 +0x0000CEC4 0x5321 # 0 +0x0000CEC5 0x58D9 # 0 +0x0000CEC6 0x5EE3 # 0 +0x0000CEC7 0x66E0 # 0 +0x0000CEC8 0x6D38 # 0 +0x0000CEC9 0x709A # 0 +0x0000CECA 0x72C2 # 0 +0x0000CECB 0x73D6 # 0 +0x0000CECC 0x7B50 # 0 +0x0000CECD 0x80F1 # 0 +0x0000CECE 0x945B # 0 +0x0000CECF 0x5366 # 0 +0x0000CED0 0x639B # 0 +0x0000CED1 0x7F6B # 0 +0x0000CED2 0x4E56 # 0 +0x0000CED3 0x5080 # 0 +0x0000CED4 0x584A # 0 +0x0000CED5 0x58DE # 0 +0x0000CED6 0x602A # 0 +0x0000CED7 0x6127 # 0 +0x0000CED8 0x62D0 # 0 +0x0000CED9 0x69D0 # 0 +0x0000CEDA 0x9B41 # 0 +0x0000CEDB 0x5B8F # 0 +0x0000CEDC 0x7D18 # 0 +0x0000CEDD 0x80B1 # 0 +0x0000CEDE 0x8F5F # 0 +0x0000CEDF 0x4EA4 # 0 +0x0000CEE0 0x50D1 # 0 +0x0000CEE1 0x54AC # 0 +0x0000CEE2 0x55AC # 0 +0x0000CEE3 0x5B0C # 0 +0x0000CEE4 0x5DA0 # 0 +0x0000CEE5 0x5DE7 # 0 +0x0000CEE6 0x652A # 0 +0x0000CEE7 0x654E # 0 +0x0000CEE8 0x6821 # 0 +0x0000CEE9 0x6A4B # 0 +0x0000CEEA 0x72E1 # 0 +0x0000CEEB 0x768E # 0 +0x0000CEEC 0x77EF # 0 +0x0000CEED 0x7D5E # 0 +0x0000CEEE 0x7FF9 # 0 +0x0000CEEF 0x81A0 # 0 +0x0000CEF0 0x854E # 0 +0x0000CEF1 0x86DF # 0 +0x0000CEF2 0x8F03 # 0 +0x0000CEF3 0x8F4E # 0 +0x0000CEF4 0x90CA # 0 +0x0000CEF5 0x9903 # 0 +0x0000CEF6 0x9A55 # 0 +0x0000CEF7 0x9BAB # 0 +0x0000CEF8 0x4E18 # 0 +0x0000CEF9 0x4E45 # 0 +0x0000CEFA 0x4E5D # 0 +0x0000CEFB 0x4EC7 # 0 +0x0000CEFC 0x4FF1 # 0 +0x0000CEFD 0x5177 # 0 +0x0000CEFE 0x52FE # 0 +0x0000CFA1 0x5340 # 0 +0x0000CFA2 0x53E3 # 0 +0x0000CFA3 0x53E5 # 0 +0x0000CFA4 0x548E # 0 +0x0000CFA5 0x5614 # 0 +0x0000CFA6 0x5775 # 0 +0x0000CFA7 0x57A2 # 0 +0x0000CFA8 0x5BC7 # 0 +0x0000CFA9 0x5D87 # 0 +0x0000CFAA 0x5ED0 # 0 +0x0000CFAB 0x61FC # 0 +0x0000CFAC 0x62D8 # 0 +0x0000CFAD 0x6551 # 0 +0x0000CFAE 0x67B8 # 0 +0x0000CFAF 0x67E9 # 0 +0x0000CFB0 0x69CB # 0 +0x0000CFB1 0x6B50 # 0 +0x0000CFB2 0x6BC6 # 0 +0x0000CFB3 0x6BEC # 0 +0x0000CFB4 0x6C42 # 0 +0x0000CFB5 0x6E9D # 0 +0x0000CFB6 0x7078 # 0 +0x0000CFB7 0x72D7 # 0 +0x0000CFB8 0x7396 # 0 +0x0000CFB9 0x7403 # 0 +0x0000CFBA 0x77BF # 0 +0x0000CFBB 0x77E9 # 0 +0x0000CFBC 0x7A76 # 0 +0x0000CFBD 0x7D7F # 0 +0x0000CFBE 0x8009 # 0 +0x0000CFBF 0x81FC # 0 +0x0000CFC0 0x8205 # 0 +0x0000CFC1 0x820A # 0 +0x0000CFC2 0x82DF # 0 +0x0000CFC3 0x8862 # 0 +0x0000CFC4 0x8B33 # 0 +0x0000CFC5 0x8CFC # 0 +0x0000CFC6 0x8EC0 # 0 +0x0000CFC7 0x9011 # 0 +0x0000CFC8 0x90B1 # 0 +0x0000CFC9 0x9264 # 0 +0x0000CFCA 0x92B6 # 0 +0x0000CFCB 0x99D2 # 0 +0x0000CFCC 0x9A45 # 0 +0x0000CFCD 0x9CE9 # 0 +0x0000CFCE 0x9DD7 # 0 +0x0000CFCF 0x9F9C # 0 +0x0000CFD0 0x570B # 0 +0x0000CFD1 0x5C40 # 0 +0x0000CFD2 0x83CA # 0 +0x0000CFD3 0x97A0 # 0 +0x0000CFD4 0x97AB # 0 +0x0000CFD5 0x9EB4 # 0 +0x0000CFD6 0x541B # 0 +0x0000CFD7 0x7A98 # 0 +0x0000CFD8 0x7FA4 # 0 +0x0000CFD9 0x88D9 # 0 +0x0000CFDA 0x8ECD # 0 +0x0000CFDB 0x90E1 # 0 +0x0000CFDC 0x5800 # 0 +0x0000CFDD 0x5C48 # 0 +0x0000CFDE 0x6398 # 0 +0x0000CFDF 0x7A9F # 0 +0x0000CFE0 0x5BAE # 0 +0x0000CFE1 0x5F13 # 0 +0x0000CFE2 0x7A79 # 0 +0x0000CFE3 0x7AAE # 0 +0x0000CFE4 0x828E # 0 +0x0000CFE5 0x8EAC # 0 +0x0000CFE6 0x5026 # 0 +0x0000CFE7 0x5238 # 0 +0x0000CFE8 0x52F8 # 0 +0x0000CFE9 0x5377 # 0 +0x0000CFEA 0x5708 # 0 +0x0000CFEB 0x62F3 # 0 +0x0000CFEC 0x6372 # 0 +0x0000CFED 0x6B0A # 0 +0x0000CFEE 0x6DC3 # 0 +0x0000CFEF 0x7737 # 0 +0x0000CFF0 0x53A5 # 0 +0x0000CFF1 0x7357 # 0 +0x0000CFF2 0x8568 # 0 +0x0000CFF3 0x8E76 # 0 +0x0000CFF4 0x95D5 # 0 +0x0000CFF5 0x673A # 0 +0x0000CFF6 0x6AC3 # 0 +0x0000CFF7 0x6F70 # 0 +0x0000CFF8 0x8A6D # 0 +0x0000CFF9 0x8ECC # 0 +0x0000CFFA 0x994B # 0 +0x0000CFFB 0xF906 # 0 +0x0000CFFC 0x6677 # 0 +0x0000CFFD 0x6B78 # 0 +0x0000CFFE 0x8CB4 # 0 +0x0000D0A1 0x9B3C # 0 +0x0000D0A2 0xF907 # 0 +0x0000D0A3 0x53EB # 0 +0x0000D0A4 0x572D # 0 +0x0000D0A5 0x594E # 0 +0x0000D0A6 0x63C6 # 0 +0x0000D0A7 0x69FB # 0 +0x0000D0A8 0x73EA # 0 +0x0000D0A9 0x7845 # 0 +0x0000D0AA 0x7ABA # 0 +0x0000D0AB 0x7AC5 # 0 +0x0000D0AC 0x7CFE # 0 +0x0000D0AD 0x8475 # 0 +0x0000D0AE 0x898F # 0 +0x0000D0AF 0x8D73 # 0 +0x0000D0B0 0x9035 # 0 +0x0000D0B1 0x95A8 # 0 +0x0000D0B2 0x52FB # 0 +0x0000D0B3 0x5747 # 0 +0x0000D0B4 0x7547 # 0 +0x0000D0B5 0x7B60 # 0 +0x0000D0B6 0x83CC # 0 +0x0000D0B7 0x921E # 0 +0x0000D0B8 0xF908 # 0 +0x0000D0B9 0x6A58 # 0 +0x0000D0BA 0x514B # 0 +0x0000D0BB 0x524B # 0 +0x0000D0BC 0x5287 # 0 +0x0000D0BD 0x621F # 0 +0x0000D0BE 0x68D8 # 0 +0x0000D0BF 0x6975 # 0 +0x0000D0C0 0x9699 # 0 +0x0000D0C1 0x50C5 # 0 +0x0000D0C2 0x52A4 # 0 +0x0000D0C3 0x52E4 # 0 +0x0000D0C4 0x61C3 # 0 +0x0000D0C5 0x65A4 # 0 +0x0000D0C6 0x6839 # 0 +0x0000D0C7 0x69FF # 0 +0x0000D0C8 0x747E # 0 +0x0000D0C9 0x7B4B # 0 +0x0000D0CA 0x82B9 # 0 +0x0000D0CB 0x83EB # 0 +0x0000D0CC 0x89B2 # 0 +0x0000D0CD 0x8B39 # 0 +0x0000D0CE 0x8FD1 # 0 +0x0000D0CF 0x9949 # 0 +0x0000D0D0 0xF909 # 0 +0x0000D0D1 0x4ECA # 0 +0x0000D0D2 0x5997 # 0 +0x0000D0D3 0x64D2 # 0 +0x0000D0D4 0x6611 # 0 +0x0000D0D5 0x6A8E # 0 +0x0000D0D6 0x7434 # 0 +0x0000D0D7 0x7981 # 0 +0x0000D0D8 0x79BD # 0 +0x0000D0D9 0x82A9 # 0 +0x0000D0DA 0x887E # 0 +0x0000D0DB 0x887F # 0 +0x0000D0DC 0x895F # 0 +0x0000D0DD 0xF90A # 0 +0x0000D0DE 0x9326 # 0 +0x0000D0DF 0x4F0B # 0 +0x0000D0E0 0x53CA # 0 +0x0000D0E1 0x6025 # 0 +0x0000D0E2 0x6271 # 0 +0x0000D0E3 0x6C72 # 0 +0x0000D0E4 0x7D1A # 0 +0x0000D0E5 0x7D66 # 0 +0x0000D0E6 0x4E98 # 0 +0x0000D0E7 0x5162 # 0 +0x0000D0E8 0x77DC # 0 +0x0000D0E9 0x80AF # 0 +0x0000D0EA 0x4F01 # 0 +0x0000D0EB 0x4F0E # 0 +0x0000D0EC 0x5176 # 0 +0x0000D0ED 0x5180 # 0 +0x0000D0EE 0x55DC # 0 +0x0000D0EF 0x5668 # 0 +0x0000D0F0 0x573B # 0 +0x0000D0F1 0x57FA # 0 +0x0000D0F2 0x57FC # 0 +0x0000D0F3 0x5914 # 0 +0x0000D0F4 0x5947 # 0 +0x0000D0F5 0x5993 # 0 +0x0000D0F6 0x5BC4 # 0 +0x0000D0F7 0x5C90 # 0 +0x0000D0F8 0x5D0E # 0 +0x0000D0F9 0x5DF1 # 0 +0x0000D0FA 0x5E7E # 0 +0x0000D0FB 0x5FCC # 0 +0x0000D0FC 0x6280 # 0 +0x0000D0FD 0x65D7 # 0 +0x0000D0FE 0x65E3 # 0 +0x0000D1A1 0x671E # 0 +0x0000D1A2 0x671F # 0 +0x0000D1A3 0x675E # 0 +0x0000D1A4 0x68CB # 0 +0x0000D1A5 0x68C4 # 0 +0x0000D1A6 0x6A5F # 0 +0x0000D1A7 0x6B3A # 0 +0x0000D1A8 0x6C23 # 0 +0x0000D1A9 0x6C7D # 0 +0x0000D1AA 0x6C82 # 0 +0x0000D1AB 0x6DC7 # 0 +0x0000D1AC 0x7398 # 0 +0x0000D1AD 0x7426 # 0 +0x0000D1AE 0x742A # 0 +0x0000D1AF 0x7482 # 0 +0x0000D1B0 0x74A3 # 0 +0x0000D1B1 0x7578 # 0 +0x0000D1B2 0x757F # 0 +0x0000D1B3 0x7881 # 0 +0x0000D1B4 0x78EF # 0 +0x0000D1B5 0x7941 # 0 +0x0000D1B6 0x7947 # 0 +0x0000D1B7 0x7948 # 0 +0x0000D1B8 0x797A # 0 +0x0000D1B9 0x7B95 # 0 +0x0000D1BA 0x7D00 # 0 +0x0000D1BB 0x7DBA # 0 +0x0000D1BC 0x7F88 # 0 +0x0000D1BD 0x8006 # 0 +0x0000D1BE 0x802D # 0 +0x0000D1BF 0x808C # 0 +0x0000D1C0 0x8A18 # 0 +0x0000D1C1 0x8B4F # 0 +0x0000D1C2 0x8C48 # 0 +0x0000D1C3 0x8D77 # 0 +0x0000D1C4 0x9321 # 0 +0x0000D1C5 0x9324 # 0 +0x0000D1C6 0x98E2 # 0 +0x0000D1C7 0x9951 # 0 +0x0000D1C8 0x9A0E # 0 +0x0000D1C9 0x9A0F # 0 +0x0000D1CA 0x9A65 # 0 +0x0000D1CB 0x9E92 # 0 +0x0000D1CC 0x7DCA # 0 +0x0000D1CD 0x4F76 # 0 +0x0000D1CE 0x5409 # 0 +0x0000D1CF 0x62EE # 0 +0x0000D1D0 0x6854 # 0 +0x0000D1D1 0x91D1 # 0 +0x0000D1D2 0x55AB # 0 +0x0000D1D3 0x513A # 0 +0x0000D1D4 0xF90B # 0 +0x0000D1D5 0xF90C # 0 +0x0000D1D6 0x5A1C # 0 +0x0000D1D7 0x61E6 # 0 +0x0000D1D8 0xF90D # 0 +0x0000D1D9 0x62CF # 0 +0x0000D1DA 0x62FF # 0 +0x0000D1DB 0xF90E # 0 +0x0000D1DC 0xF90F # 0 +0x0000D1DD 0xF910 # 0 +0x0000D1DE 0xF911 # 0 +0x0000D1DF 0xF912 # 0 +0x0000D1E0 0xF913 # 0 +0x0000D1E1 0x90A3 # 0 +0x0000D1E2 0xF914 # 0 +0x0000D1E3 0xF915 # 0 +0x0000D1E4 0xF916 # 0 +0x0000D1E5 0xF917 # 0 +0x0000D1E6 0xF918 # 0 +0x0000D1E7 0x8AFE # 0 +0x0000D1E8 0xF919 # 0 +0x0000D1E9 0xF91A # 0 +0x0000D1EA 0xF91B # 0 +0x0000D1EB 0xF91C # 0 +0x0000D1EC 0x6696 # 0 +0x0000D1ED 0xF91D # 0 +0x0000D1EE 0x7156 # 0 +0x0000D1EF 0xF91E # 0 +0x0000D1F0 0xF91F # 0 +0x0000D1F1 0x96E3 # 0 +0x0000D1F2 0xF920 # 0 +0x0000D1F3 0x634F # 0 +0x0000D1F4 0x637A # 0 +0x0000D1F5 0x5357 # 0 +0x0000D1F6 0xF921 # 0 +0x0000D1F7 0x678F # 0 +0x0000D1F8 0x6960 # 0 +0x0000D1F9 0x6E73 # 0 +0x0000D1FA 0xF922 # 0 +0x0000D1FB 0x7537 # 0 +0x0000D1FC 0xF923 # 0 +0x0000D1FD 0xF924 # 0 +0x0000D1FE 0xF925 # 0 +0x0000D2A1 0x7D0D # 0 +0x0000D2A2 0xF926 # 0 +0x0000D2A3 0xF927 # 0 +0x0000D2A4 0x8872 # 0 +0x0000D2A5 0x56CA # 0 +0x0000D2A6 0x5A18 # 0 +0x0000D2A7 0xF928 # 0 +0x0000D2A8 0xF929 # 0 +0x0000D2A9 0xF92A # 0 +0x0000D2AA 0xF92B # 0 +0x0000D2AB 0xF92C # 0 +0x0000D2AC 0x4E43 # 0 +0x0000D2AD 0xF92D # 0 +0x0000D2AE 0x5167 # 0 +0x0000D2AF 0x5948 # 0 +0x0000D2B0 0x67F0 # 0 +0x0000D2B1 0x8010 # 0 +0x0000D2B2 0xF92E # 0 +0x0000D2B3 0x5973 # 0 +0x0000D2B4 0x5E74 # 0 +0x0000D2B5 0x649A # 0 +0x0000D2B6 0x79CA # 0 +0x0000D2B7 0x5FF5 # 0 +0x0000D2B8 0x606C # 0 +0x0000D2B9 0x62C8 # 0 +0x0000D2BA 0x637B # 0 +0x0000D2BB 0x5BE7 # 0 +0x0000D2BC 0x5BD7 # 0 +0x0000D2BD 0x52AA # 0 +0x0000D2BE 0xF92F # 0 +0x0000D2BF 0x5974 # 0 +0x0000D2C0 0x5F29 # 0 +0x0000D2C1 0x6012 # 0 +0x0000D2C2 0xF930 # 0 +0x0000D2C3 0xF931 # 0 +0x0000D2C4 0xF932 # 0 +0x0000D2C5 0x7459 # 0 +0x0000D2C6 0xF933 # 0 +0x0000D2C7 0xF934 # 0 +0x0000D2C8 0xF935 # 0 +0x0000D2C9 0xF936 # 0 +0x0000D2CA 0xF937 # 0 +0x0000D2CB 0xF938 # 0 +0x0000D2CC 0x99D1 # 0 +0x0000D2CD 0xF939 # 0 +0x0000D2CE 0xF93A # 0 +0x0000D2CF 0xF93B # 0 +0x0000D2D0 0xF93C # 0 +0x0000D2D1 0xF93D # 0 +0x0000D2D2 0xF93E # 0 +0x0000D2D3 0xF93F # 0 +0x0000D2D4 0xF940 # 0 +0x0000D2D5 0xF941 # 0 +0x0000D2D6 0xF942 # 0 +0x0000D2D7 0xF943 # 0 +0x0000D2D8 0x6FC3 # 0 +0x0000D2D9 0xF944 # 0 +0x0000D2DA 0xF945 # 0 +0x0000D2DB 0x81BF # 0 +0x0000D2DC 0x8FB2 # 0 +0x0000D2DD 0x60F1 # 0 +0x0000D2DE 0xF946 # 0 +0x0000D2DF 0xF947 # 0 +0x0000D2E0 0x8166 # 0 +0x0000D2E1 0xF948 # 0 +0x0000D2E2 0xF949 # 0 +0x0000D2E3 0x5C3F # 0 +0x0000D2E4 0xF94A # 0 +0x0000D2E5 0xF94B # 0 +0x0000D2E6 0xF94C # 0 +0x0000D2E7 0xF94D # 0 +0x0000D2E8 0xF94E # 0 +0x0000D2E9 0xF94F # 0 +0x0000D2EA 0xF950 # 0 +0x0000D2EB 0xF951 # 0 +0x0000D2EC 0x5AE9 # 0 +0x0000D2ED 0x8A25 # 0 +0x0000D2EE 0x677B # 0 +0x0000D2EF 0x7D10 # 0 +0x0000D2F0 0xF952 # 0 +0x0000D2F1 0xF953 # 0 +0x0000D2F2 0xF954 # 0 +0x0000D2F3 0xF955 # 0 +0x0000D2F4 0xF956 # 0 +0x0000D2F5 0xF957 # 0 +0x0000D2F6 0x80FD # 0 +0x0000D2F7 0xF958 # 0 +0x0000D2F8 0xF959 # 0 +0x0000D2F9 0x5C3C # 0 +0x0000D2FA 0x6CE5 # 0 +0x0000D2FB 0x533F # 0 +0x0000D2FC 0x6EBA # 0 +0x0000D2FD 0x591A # 0 +0x0000D2FE 0x8336 # 0 +0x0000D3A1 0x4E39 # 0 +0x0000D3A2 0x4EB6 # 0 +0x0000D3A3 0x4F46 # 0 +0x0000D3A4 0x55AE # 0 +0x0000D3A5 0x5718 # 0 +0x0000D3A6 0x58C7 # 0 +0x0000D3A7 0x5F56 # 0 +0x0000D3A8 0x65B7 # 0 +0x0000D3A9 0x65E6 # 0 +0x0000D3AA 0x6A80 # 0 +0x0000D3AB 0x6BB5 # 0 +0x0000D3AC 0x6E4D # 0 +0x0000D3AD 0x77ED # 0 +0x0000D3AE 0x7AEF # 0 +0x0000D3AF 0x7C1E # 0 +0x0000D3B0 0x7DDE # 0 +0x0000D3B1 0x86CB # 0 +0x0000D3B2 0x8892 # 0 +0x0000D3B3 0x9132 # 0 +0x0000D3B4 0x935B # 0 +0x0000D3B5 0x64BB # 0 +0x0000D3B6 0x6FBE # 0 +0x0000D3B7 0x737A # 0 +0x0000D3B8 0x75B8 # 0 +0x0000D3B9 0x9054 # 0 +0x0000D3BA 0x5556 # 0 +0x0000D3BB 0x574D # 0 +0x0000D3BC 0x61BA # 0 +0x0000D3BD 0x64D4 # 0 +0x0000D3BE 0x66C7 # 0 +0x0000D3BF 0x6DE1 # 0 +0x0000D3C0 0x6E5B # 0 +0x0000D3C1 0x6F6D # 0 +0x0000D3C2 0x6FB9 # 0 +0x0000D3C3 0x75F0 # 0 +0x0000D3C4 0x8043 # 0 +0x0000D3C5 0x81BD # 0 +0x0000D3C6 0x8541 # 0 +0x0000D3C7 0x8983 # 0 +0x0000D3C8 0x8AC7 # 0 +0x0000D3C9 0x8B5A # 0 +0x0000D3CA 0x931F # 0 +0x0000D3CB 0x6C93 # 0 +0x0000D3CC 0x7553 # 0 +0x0000D3CD 0x7B54 # 0 +0x0000D3CE 0x8E0F # 0 +0x0000D3CF 0x905D # 0 +0x0000D3D0 0x5510 # 0 +0x0000D3D1 0x5802 # 0 +0x0000D3D2 0x5858 # 0 +0x0000D3D3 0x5E62 # 0 +0x0000D3D4 0x6207 # 0 +0x0000D3D5 0x649E # 0 +0x0000D3D6 0x68E0 # 0 +0x0000D3D7 0x7576 # 0 +0x0000D3D8 0x7CD6 # 0 +0x0000D3D9 0x87B3 # 0 +0x0000D3DA 0x9EE8 # 0 +0x0000D3DB 0x4EE3 # 0 +0x0000D3DC 0x5788 # 0 +0x0000D3DD 0x576E # 0 +0x0000D3DE 0x5927 # 0 +0x0000D3DF 0x5C0D # 0 +0x0000D3E0 0x5CB1 # 0 +0x0000D3E1 0x5E36 # 0 +0x0000D3E2 0x5F85 # 0 +0x0000D3E3 0x6234 # 0 +0x0000D3E4 0x64E1 # 0 +0x0000D3E5 0x73B3 # 0 +0x0000D3E6 0x81FA # 0 +0x0000D3E7 0x888B # 0 +0x0000D3E8 0x8CB8 # 0 +0x0000D3E9 0x968A # 0 +0x0000D3EA 0x9EDB # 0 +0x0000D3EB 0x5B85 # 0 +0x0000D3EC 0x5FB7 # 0 +0x0000D3ED 0x60B3 # 0 +0x0000D3EE 0x5012 # 0 +0x0000D3EF 0x5200 # 0 +0x0000D3F0 0x5230 # 0 +0x0000D3F1 0x5716 # 0 +0x0000D3F2 0x5835 # 0 +0x0000D3F3 0x5857 # 0 +0x0000D3F4 0x5C0E # 0 +0x0000D3F5 0x5C60 # 0 +0x0000D3F6 0x5CF6 # 0 +0x0000D3F7 0x5D8B # 0 +0x0000D3F8 0x5EA6 # 0 +0x0000D3F9 0x5F92 # 0 +0x0000D3FA 0x60BC # 0 +0x0000D3FB 0x6311 # 0 +0x0000D3FC 0x6389 # 0 +0x0000D3FD 0x6417 # 0 +0x0000D3FE 0x6843 # 0 +0x0000D4A1 0x68F9 # 0 +0x0000D4A2 0x6AC2 # 0 +0x0000D4A3 0x6DD8 # 0 +0x0000D4A4 0x6E21 # 0 +0x0000D4A5 0x6ED4 # 0 +0x0000D4A6 0x6FE4 # 0 +0x0000D4A7 0x71FE # 0 +0x0000D4A8 0x76DC # 0 +0x0000D4A9 0x7779 # 0 +0x0000D4AA 0x79B1 # 0 +0x0000D4AB 0x7A3B # 0 +0x0000D4AC 0x8404 # 0 +0x0000D4AD 0x89A9 # 0 +0x0000D4AE 0x8CED # 0 +0x0000D4AF 0x8DF3 # 0 +0x0000D4B0 0x8E48 # 0 +0x0000D4B1 0x9003 # 0 +0x0000D4B2 0x9014 # 0 +0x0000D4B3 0x9053 # 0 +0x0000D4B4 0x90FD # 0 +0x0000D4B5 0x934D # 0 +0x0000D4B6 0x9676 # 0 +0x0000D4B7 0x97DC # 0 +0x0000D4B8 0x6BD2 # 0 +0x0000D4B9 0x7006 # 0 +0x0000D4BA 0x7258 # 0 +0x0000D4BB 0x72A2 # 0 +0x0000D4BC 0x7368 # 0 +0x0000D4BD 0x7763 # 0 +0x0000D4BE 0x79BF # 0 +0x0000D4BF 0x7BE4 # 0 +0x0000D4C0 0x7E9B # 0 +0x0000D4C1 0x8B80 # 0 +0x0000D4C2 0x58A9 # 0 +0x0000D4C3 0x60C7 # 0 +0x0000D4C4 0x6566 # 0 +0x0000D4C5 0x65FD # 0 +0x0000D4C6 0x66BE # 0 +0x0000D4C7 0x6C8C # 0 +0x0000D4C8 0x711E # 0 +0x0000D4C9 0x71C9 # 0 +0x0000D4CA 0x8C5A # 0 +0x0000D4CB 0x9813 # 0 +0x0000D4CC 0x4E6D # 0 +0x0000D4CD 0x7A81 # 0 +0x0000D4CE 0x4EDD # 0 +0x0000D4CF 0x51AC # 0 +0x0000D4D0 0x51CD # 0 +0x0000D4D1 0x52D5 # 0 +0x0000D4D2 0x540C # 0 +0x0000D4D3 0x61A7 # 0 +0x0000D4D4 0x6771 # 0 +0x0000D4D5 0x6850 # 0 +0x0000D4D6 0x68DF # 0 +0x0000D4D7 0x6D1E # 0 +0x0000D4D8 0x6F7C # 0 +0x0000D4D9 0x75BC # 0 +0x0000D4DA 0x77B3 # 0 +0x0000D4DB 0x7AE5 # 0 +0x0000D4DC 0x80F4 # 0 +0x0000D4DD 0x8463 # 0 +0x0000D4DE 0x9285 # 0 +0x0000D4DF 0x515C # 0 +0x0000D4E0 0x6597 # 0 +0x0000D4E1 0x675C # 0 +0x0000D4E2 0x6793 # 0 +0x0000D4E3 0x75D8 # 0 +0x0000D4E4 0x7AC7 # 0 +0x0000D4E5 0x8373 # 0 +0x0000D4E6 0xF95A # 0 +0x0000D4E7 0x8C46 # 0 +0x0000D4E8 0x9017 # 0 +0x0000D4E9 0x982D # 0 +0x0000D4EA 0x5C6F # 0 +0x0000D4EB 0x81C0 # 0 +0x0000D4EC 0x829A # 0 +0x0000D4ED 0x9041 # 0 +0x0000D4EE 0x906F # 0 +0x0000D4EF 0x920D # 0 +0x0000D4F0 0x5F97 # 0 +0x0000D4F1 0x5D9D # 0 +0x0000D4F2 0x6A59 # 0 +0x0000D4F3 0x71C8 # 0 +0x0000D4F4 0x767B # 0 +0x0000D4F5 0x7B49 # 0 +0x0000D4F6 0x85E4 # 0 +0x0000D4F7 0x8B04 # 0 +0x0000D4F8 0x9127 # 0 +0x0000D4F9 0x9A30 # 0 +0x0000D4FA 0x5587 # 0 +0x0000D4FB 0x61F6 # 0 +0x0000D4FC 0xF95B # 0 +0x0000D4FD 0x7669 # 0 +0x0000D4FE 0x7F85 # 0 +0x0000D5A1 0x863F # 0 +0x0000D5A2 0x87BA # 0 +0x0000D5A3 0x88F8 # 0 +0x0000D5A4 0x908F # 0 +0x0000D5A5 0xF95C # 0 +0x0000D5A6 0x6D1B # 0 +0x0000D5A7 0x70D9 # 0 +0x0000D5A8 0x73DE # 0 +0x0000D5A9 0x7D61 # 0 +0x0000D5AA 0x843D # 0 +0x0000D5AB 0xF95D # 0 +0x0000D5AC 0x916A # 0 +0x0000D5AD 0x99F1 # 0 +0x0000D5AE 0xF95E # 0 +0x0000D5AF 0x4E82 # 0 +0x0000D5B0 0x5375 # 0 +0x0000D5B1 0x6B04 # 0 +0x0000D5B2 0x6B12 # 0 +0x0000D5B3 0x703E # 0 +0x0000D5B4 0x721B # 0 +0x0000D5B5 0x862D # 0 +0x0000D5B6 0x9E1E # 0 +0x0000D5B7 0x524C # 0 +0x0000D5B8 0x8FA3 # 0 +0x0000D5B9 0x5D50 # 0 +0x0000D5BA 0x64E5 # 0 +0x0000D5BB 0x652C # 0 +0x0000D5BC 0x6B16 # 0 +0x0000D5BD 0x6FEB # 0 +0x0000D5BE 0x7C43 # 0 +0x0000D5BF 0x7E9C # 0 +0x0000D5C0 0x85CD # 0 +0x0000D5C1 0x8964 # 0 +0x0000D5C2 0x89BD # 0 +0x0000D5C3 0x62C9 # 0 +0x0000D5C4 0x81D8 # 0 +0x0000D5C5 0x881F # 0 +0x0000D5C6 0x5ECA # 0 +0x0000D5C7 0x6717 # 0 +0x0000D5C8 0x6D6A # 0 +0x0000D5C9 0x72FC # 0 +0x0000D5CA 0x7405 # 0 +0x0000D5CB 0x746F # 0 +0x0000D5CC 0x8782 # 0 +0x0000D5CD 0x90DE # 0 +0x0000D5CE 0x4F86 # 0 +0x0000D5CF 0x5D0D # 0 +0x0000D5D0 0x5FA0 # 0 +0x0000D5D1 0x840A # 0 +0x0000D5D2 0x51B7 # 0 +0x0000D5D3 0x63A0 # 0 +0x0000D5D4 0x7565 # 0 +0x0000D5D5 0x4EAE # 0 +0x0000D5D6 0x5006 # 0 +0x0000D5D7 0x5169 # 0 +0x0000D5D8 0x51C9 # 0 +0x0000D5D9 0x6881 # 0 +0x0000D5DA 0x6A11 # 0 +0x0000D5DB 0x7CAE # 0 +0x0000D5DC 0x7CB1 # 0 +0x0000D5DD 0x7CE7 # 0 +0x0000D5DE 0x826F # 0 +0x0000D5DF 0x8AD2 # 0 +0x0000D5E0 0x8F1B # 0 +0x0000D5E1 0x91CF # 0 +0x0000D5E2 0x4FB6 # 0 +0x0000D5E3 0x5137 # 0 +0x0000D5E4 0x52F5 # 0 +0x0000D5E5 0x5442 # 0 +0x0000D5E6 0x5EEC # 0 +0x0000D5E7 0x616E # 0 +0x0000D5E8 0x623E # 0 +0x0000D5E9 0x65C5 # 0 +0x0000D5EA 0x6ADA # 0 +0x0000D5EB 0x6FFE # 0 +0x0000D5EC 0x792A # 0 +0x0000D5ED 0x85DC # 0 +0x0000D5EE 0x8823 # 0 +0x0000D5EF 0x95AD # 0 +0x0000D5F0 0x9A62 # 0 +0x0000D5F1 0x9A6A # 0 +0x0000D5F2 0x9E97 # 0 +0x0000D5F3 0x9ECE # 0 +0x0000D5F4 0x529B # 0 +0x0000D5F5 0x66C6 # 0 +0x0000D5F6 0x6B77 # 0 +0x0000D5F7 0x701D # 0 +0x0000D5F8 0x792B # 0 +0x0000D5F9 0x8F62 # 0 +0x0000D5FA 0x9742 # 0 +0x0000D5FB 0x6190 # 0 +0x0000D5FC 0x6200 # 0 +0x0000D5FD 0x6523 # 0 +0x0000D5FE 0x6F23 # 0 +0x0000D6A1 0x7149 # 0 +0x0000D6A2 0x7489 # 0 +0x0000D6A3 0x7DF4 # 0 +0x0000D6A4 0x806F # 0 +0x0000D6A5 0x84EE # 0 +0x0000D6A6 0x8F26 # 0 +0x0000D6A7 0x9023 # 0 +0x0000D6A8 0x934A # 0 +0x0000D6A9 0x51BD # 0 +0x0000D6AA 0x5217 # 0 +0x0000D6AB 0x52A3 # 0 +0x0000D6AC 0x6D0C # 0 +0x0000D6AD 0x70C8 # 0 +0x0000D6AE 0x88C2 # 0 +0x0000D6AF 0x5EC9 # 0 +0x0000D6B0 0x6582 # 0 +0x0000D6B1 0x6BAE # 0 +0x0000D6B2 0x6FC2 # 0 +0x0000D6B3 0x7C3E # 0 +0x0000D6B4 0x7375 # 0 +0x0000D6B5 0x4EE4 # 0 +0x0000D6B6 0x4F36 # 0 +0x0000D6B7 0x56F9 # 0 +0x0000D6B8 0xF95F # 0 +0x0000D6B9 0x5CBA # 0 +0x0000D6BA 0x5DBA # 0 +0x0000D6BB 0x601C # 0 +0x0000D6BC 0x73B2 # 0 +0x0000D6BD 0x7B2D # 0 +0x0000D6BE 0x7F9A # 0 +0x0000D6BF 0x7FCE # 0 +0x0000D6C0 0x8046 # 0 +0x0000D6C1 0x901E # 0 +0x0000D6C2 0x9234 # 0 +0x0000D6C3 0x96F6 # 0 +0x0000D6C4 0x9748 # 0 +0x0000D6C5 0x9818 # 0 +0x0000D6C6 0x9F61 # 0 +0x0000D6C7 0x4F8B # 0 +0x0000D6C8 0x6FA7 # 0 +0x0000D6C9 0x79AE # 0 +0x0000D6CA 0x91B4 # 0 +0x0000D6CB 0x96B7 # 0 +0x0000D6CC 0x52DE # 0 +0x0000D6CD 0xF960 # 0 +0x0000D6CE 0x6488 # 0 +0x0000D6CF 0x64C4 # 0 +0x0000D6D0 0x6AD3 # 0 +0x0000D6D1 0x6F5E # 0 +0x0000D6D2 0x7018 # 0 +0x0000D6D3 0x7210 # 0 +0x0000D6D4 0x76E7 # 0 +0x0000D6D5 0x8001 # 0 +0x0000D6D6 0x8606 # 0 +0x0000D6D7 0x865C # 0 +0x0000D6D8 0x8DEF # 0 +0x0000D6D9 0x8F05 # 0 +0x0000D6DA 0x9732 # 0 +0x0000D6DB 0x9B6F # 0 +0x0000D6DC 0x9DFA # 0 +0x0000D6DD 0x9E75 # 0 +0x0000D6DE 0x788C # 0 +0x0000D6DF 0x797F # 0 +0x0000D6E0 0x7DA0 # 0 +0x0000D6E1 0x83C9 # 0 +0x0000D6E2 0x9304 # 0 +0x0000D6E3 0x9E7F # 0 +0x0000D6E4 0x9E93 # 0 +0x0000D6E5 0x8AD6 # 0 +0x0000D6E6 0x58DF # 0 +0x0000D6E7 0x5F04 # 0 +0x0000D6E8 0x6727 # 0 +0x0000D6E9 0x7027 # 0 +0x0000D6EA 0x74CF # 0 +0x0000D6EB 0x7C60 # 0 +0x0000D6EC 0x807E # 0 +0x0000D6ED 0x5121 # 0 +0x0000D6EE 0x7028 # 0 +0x0000D6EF 0x7262 # 0 +0x0000D6F0 0x78CA # 0 +0x0000D6F1 0x8CC2 # 0 +0x0000D6F2 0x8CDA # 0 +0x0000D6F3 0x8CF4 # 0 +0x0000D6F4 0x96F7 # 0 +0x0000D6F5 0x4E86 # 0 +0x0000D6F6 0x50DA # 0 +0x0000D6F7 0x5BEE # 0 +0x0000D6F8 0x5ED6 # 0 +0x0000D6F9 0x6599 # 0 +0x0000D6FA 0x71CE # 0 +0x0000D6FB 0x7642 # 0 +0x0000D6FC 0x77AD # 0 +0x0000D6FD 0x804A # 0 +0x0000D6FE 0x84FC # 0 +0x0000D7A1 0x907C # 0 +0x0000D7A2 0x9B27 # 0 +0x0000D7A3 0x9F8D # 0 +0x0000D7A4 0x58D8 # 0 +0x0000D7A5 0x5A41 # 0 +0x0000D7A6 0x5C62 # 0 +0x0000D7A7 0x6A13 # 0 +0x0000D7A8 0x6DDA # 0 +0x0000D7A9 0x6F0F # 0 +0x0000D7AA 0x763B # 0 +0x0000D7AB 0x7D2F # 0 +0x0000D7AC 0x7E37 # 0 +0x0000D7AD 0x851E # 0 +0x0000D7AE 0x8938 # 0 +0x0000D7AF 0x93E4 # 0 +0x0000D7B0 0x964B # 0 +0x0000D7B1 0x5289 # 0 +0x0000D7B2 0x65D2 # 0 +0x0000D7B3 0x67F3 # 0 +0x0000D7B4 0x69B4 # 0 +0x0000D7B5 0x6D41 # 0 +0x0000D7B6 0x6E9C # 0 +0x0000D7B7 0x700F # 0 +0x0000D7B8 0x7409 # 0 +0x0000D7B9 0x7460 # 0 +0x0000D7BA 0x7559 # 0 +0x0000D7BB 0x7624 # 0 +0x0000D7BC 0x786B # 0 +0x0000D7BD 0x8B2C # 0 +0x0000D7BE 0x985E # 0 +0x0000D7BF 0x516D # 0 +0x0000D7C0 0x622E # 0 +0x0000D7C1 0x9678 # 0 +0x0000D7C2 0x4F96 # 0 +0x0000D7C3 0x502B # 0 +0x0000D7C4 0x5D19 # 0 +0x0000D7C5 0x6DEA # 0 +0x0000D7C6 0x7DB8 # 0 +0x0000D7C7 0x8F2A # 0 +0x0000D7C8 0x5F8B # 0 +0x0000D7C9 0x6144 # 0 +0x0000D7CA 0x6817 # 0 +0x0000D7CB 0xF961 # 0 +0x0000D7CC 0x9686 # 0 +0x0000D7CD 0x52D2 # 0 +0x0000D7CE 0x808B # 0 +0x0000D7CF 0x51DC # 0 +0x0000D7D0 0x51CC # 0 +0x0000D7D1 0x695E # 0 +0x0000D7D2 0x7A1C # 0 +0x0000D7D3 0x7DBE # 0 +0x0000D7D4 0x83F1 # 0 +0x0000D7D5 0x9675 # 0 +0x0000D7D6 0x4FDA # 0 +0x0000D7D7 0x5229 # 0 +0x0000D7D8 0x5398 # 0 +0x0000D7D9 0x540F # 0 +0x0000D7DA 0x550E # 0 +0x0000D7DB 0x5C65 # 0 +0x0000D7DC 0x60A7 # 0 +0x0000D7DD 0x674E # 0 +0x0000D7DE 0x68A8 # 0 +0x0000D7DF 0x6D6C # 0 +0x0000D7E0 0x7281 # 0 +0x0000D7E1 0x72F8 # 0 +0x0000D7E2 0x7406 # 0 +0x0000D7E3 0x7483 # 0 +0x0000D7E4 0xF962 # 0 +0x0000D7E5 0x75E2 # 0 +0x0000D7E6 0x7C6C # 0 +0x0000D7E7 0x7F79 # 0 +0x0000D7E8 0x7FB8 # 0 +0x0000D7E9 0x8389 # 0 +0x0000D7EA 0x88CF # 0 +0x0000D7EB 0x88E1 # 0 +0x0000D7EC 0x91CC # 0 +0x0000D7ED 0x91D0 # 0 +0x0000D7EE 0x96E2 # 0 +0x0000D7EF 0x9BC9 # 0 +0x0000D7F0 0x541D # 0 +0x0000D7F1 0x6F7E # 0 +0x0000D7F2 0x71D0 # 0 +0x0000D7F3 0x7498 # 0 +0x0000D7F4 0x85FA # 0 +0x0000D7F5 0x8EAA # 0 +0x0000D7F6 0x96A3 # 0 +0x0000D7F7 0x9C57 # 0 +0x0000D7F8 0x9E9F # 0 +0x0000D7F9 0x6797 # 0 +0x0000D7FA 0x6DCB # 0 +0x0000D7FB 0x7433 # 0 +0x0000D7FC 0x81E8 # 0 +0x0000D7FD 0x9716 # 0 +0x0000D7FE 0x782C # 0 +0x0000D8A1 0x7ACB # 0 +0x0000D8A2 0x7B20 # 0 +0x0000D8A3 0x7C92 # 0 +0x0000D8A4 0x6469 # 0 +0x0000D8A5 0x746A # 0 +0x0000D8A6 0x75F2 # 0 +0x0000D8A7 0x78BC # 0 +0x0000D8A8 0x78E8 # 0 +0x0000D8A9 0x99AC # 0 +0x0000D8AA 0x9B54 # 0 +0x0000D8AB 0x9EBB # 0 +0x0000D8AC 0x5BDE # 0 +0x0000D8AD 0x5E55 # 0 +0x0000D8AE 0x6F20 # 0 +0x0000D8AF 0x819C # 0 +0x0000D8B0 0x83AB # 0 +0x0000D8B1 0x9088 # 0 +0x0000D8B2 0x4E07 # 0 +0x0000D8B3 0x534D # 0 +0x0000D8B4 0x5A29 # 0 +0x0000D8B5 0x5DD2 # 0 +0x0000D8B6 0x5F4E # 0 +0x0000D8B7 0x6162 # 0 +0x0000D8B8 0x633D # 0 +0x0000D8B9 0x6669 # 0 +0x0000D8BA 0x66FC # 0 +0x0000D8BB 0x6EFF # 0 +0x0000D8BC 0x6F2B # 0 +0x0000D8BD 0x7063 # 0 +0x0000D8BE 0x779E # 0 +0x0000D8BF 0x842C # 0 +0x0000D8C0 0x8513 # 0 +0x0000D8C1 0x883B # 0 +0x0000D8C2 0x8F13 # 0 +0x0000D8C3 0x9945 # 0 +0x0000D8C4 0x9C3B # 0 +0x0000D8C5 0x551C # 0 +0x0000D8C6 0x62B9 # 0 +0x0000D8C7 0x672B # 0 +0x0000D8C8 0x6CAB # 0 +0x0000D8C9 0x8309 # 0 +0x0000D8CA 0x896A # 0 +0x0000D8CB 0x977A # 0 +0x0000D8CC 0x4EA1 # 0 +0x0000D8CD 0x5984 # 0 +0x0000D8CE 0x5FD8 # 0 +0x0000D8CF 0x5FD9 # 0 +0x0000D8D0 0x671B # 0 +0x0000D8D1 0x7DB2 # 0 +0x0000D8D2 0x7F54 # 0 +0x0000D8D3 0x8292 # 0 +0x0000D8D4 0x832B # 0 +0x0000D8D5 0x83BD # 0 +0x0000D8D6 0x8F1E # 0 +0x0000D8D7 0x9099 # 0 +0x0000D8D8 0x57CB # 0 +0x0000D8D9 0x59B9 # 0 +0x0000D8DA 0x5A92 # 0 +0x0000D8DB 0x5BD0 # 0 +0x0000D8DC 0x6627 # 0 +0x0000D8DD 0x679A # 0 +0x0000D8DE 0x6885 # 0 +0x0000D8DF 0x6BCF # 0 +0x0000D8E0 0x7164 # 0 +0x0000D8E1 0x7F75 # 0 +0x0000D8E2 0x8CB7 # 0 +0x0000D8E3 0x8CE3 # 0 +0x0000D8E4 0x9081 # 0 +0x0000D8E5 0x9B45 # 0 +0x0000D8E6 0x8108 # 0 +0x0000D8E7 0x8C8A # 0 +0x0000D8E8 0x964C # 0 +0x0000D8E9 0x9A40 # 0 +0x0000D8EA 0x9EA5 # 0 +0x0000D8EB 0x5B5F # 0 +0x0000D8EC 0x6C13 # 0 +0x0000D8ED 0x731B # 0 +0x0000D8EE 0x76F2 # 0 +0x0000D8EF 0x76DF # 0 +0x0000D8F0 0x840C # 0 +0x0000D8F1 0x51AA # 0 +0x0000D8F2 0x8993 # 0 +0x0000D8F3 0x514D # 0 +0x0000D8F4 0x5195 # 0 +0x0000D8F5 0x52C9 # 0 +0x0000D8F6 0x68C9 # 0 +0x0000D8F7 0x6C94 # 0 +0x0000D8F8 0x7704 # 0 +0x0000D8F9 0x7720 # 0 +0x0000D8FA 0x7DBF # 0 +0x0000D8FB 0x7DEC # 0 +0x0000D8FC 0x9762 # 0 +0x0000D8FD 0x9EB5 # 0 +0x0000D8FE 0x6EC5 # 0 +0x0000D9A1 0x8511 # 0 +0x0000D9A2 0x51A5 # 0 +0x0000D9A3 0x540D # 0 +0x0000D9A4 0x547D # 0 +0x0000D9A5 0x660E # 0 +0x0000D9A6 0x669D # 0 +0x0000D9A7 0x6927 # 0 +0x0000D9A8 0x6E9F # 0 +0x0000D9A9 0x76BF # 0 +0x0000D9AA 0x7791 # 0 +0x0000D9AB 0x8317 # 0 +0x0000D9AC 0x84C2 # 0 +0x0000D9AD 0x879F # 0 +0x0000D9AE 0x9169 # 0 +0x0000D9AF 0x9298 # 0 +0x0000D9B0 0x9CF4 # 0 +0x0000D9B1 0x8882 # 0 +0x0000D9B2 0x4FAE # 0 +0x0000D9B3 0x5192 # 0 +0x0000D9B4 0x52DF # 0 +0x0000D9B5 0x59C6 # 0 +0x0000D9B6 0x5E3D # 0 +0x0000D9B7 0x6155 # 0 +0x0000D9B8 0x6478 # 0 +0x0000D9B9 0x6479 # 0 +0x0000D9BA 0x66AE # 0 +0x0000D9BB 0x67D0 # 0 +0x0000D9BC 0x6A21 # 0 +0x0000D9BD 0x6BCD # 0 +0x0000D9BE 0x6BDB # 0 +0x0000D9BF 0x725F # 0 +0x0000D9C0 0x7261 # 0 +0x0000D9C1 0x7441 # 0 +0x0000D9C2 0x7738 # 0 +0x0000D9C3 0x77DB # 0 +0x0000D9C4 0x8017 # 0 +0x0000D9C5 0x82BC # 0 +0x0000D9C6 0x8305 # 0 +0x0000D9C7 0x8B00 # 0 +0x0000D9C8 0x8B28 # 0 +0x0000D9C9 0x8C8C # 0 +0x0000D9CA 0x6728 # 0 +0x0000D9CB 0x6C90 # 0 +0x0000D9CC 0x7267 # 0 +0x0000D9CD 0x76EE # 0 +0x0000D9CE 0x7766 # 0 +0x0000D9CF 0x7A46 # 0 +0x0000D9D0 0x9DA9 # 0 +0x0000D9D1 0x6B7F # 0 +0x0000D9D2 0x6C92 # 0 +0x0000D9D3 0x5922 # 0 +0x0000D9D4 0x6726 # 0 +0x0000D9D5 0x8499 # 0 +0x0000D9D6 0x536F # 0 +0x0000D9D7 0x5893 # 0 +0x0000D9D8 0x5999 # 0 +0x0000D9D9 0x5EDF # 0 +0x0000D9DA 0x63CF # 0 +0x0000D9DB 0x6634 # 0 +0x0000D9DC 0x6773 # 0 +0x0000D9DD 0x6E3A # 0 +0x0000D9DE 0x732B # 0 +0x0000D9DF 0x7AD7 # 0 +0x0000D9E0 0x82D7 # 0 +0x0000D9E1 0x9328 # 0 +0x0000D9E2 0x52D9 # 0 +0x0000D9E3 0x5DEB # 0 +0x0000D9E4 0x61AE # 0 +0x0000D9E5 0x61CB # 0 +0x0000D9E6 0x620A # 0 +0x0000D9E7 0x62C7 # 0 +0x0000D9E8 0x64AB # 0 +0x0000D9E9 0x65E0 # 0 +0x0000D9EA 0x6959 # 0 +0x0000D9EB 0x6B66 # 0 +0x0000D9EC 0x6BCB # 0 +0x0000D9ED 0x7121 # 0 +0x0000D9EE 0x73F7 # 0 +0x0000D9EF 0x755D # 0 +0x0000D9F0 0x7E46 # 0 +0x0000D9F1 0x821E # 0 +0x0000D9F2 0x8302 # 0 +0x0000D9F3 0x856A # 0 +0x0000D9F4 0x8AA3 # 0 +0x0000D9F5 0x8CBF # 0 +0x0000D9F6 0x9727 # 0 +0x0000D9F7 0x9D61 # 0 +0x0000D9F8 0x58A8 # 0 +0x0000D9F9 0x9ED8 # 0 +0x0000D9FA 0x5011 # 0 +0x0000D9FB 0x520E # 0 +0x0000D9FC 0x543B # 0 +0x0000D9FD 0x554F # 0 +0x0000D9FE 0x6587 # 0 +0x0000DAA1 0x6C76 # 0 +0x0000DAA2 0x7D0A # 0 +0x0000DAA3 0x7D0B # 0 +0x0000DAA4 0x805E # 0 +0x0000DAA5 0x868A # 0 +0x0000DAA6 0x9580 # 0 +0x0000DAA7 0x96EF # 0 +0x0000DAA8 0x52FF # 0 +0x0000DAA9 0x6C95 # 0 +0x0000DAAA 0x7269 # 0 +0x0000DAAB 0x5473 # 0 +0x0000DAAC 0x5A9A # 0 +0x0000DAAD 0x5C3E # 0 +0x0000DAAE 0x5D4B # 0 +0x0000DAAF 0x5F4C # 0 +0x0000DAB0 0x5FAE # 0 +0x0000DAB1 0x672A # 0 +0x0000DAB2 0x68B6 # 0 +0x0000DAB3 0x6963 # 0 +0x0000DAB4 0x6E3C # 0 +0x0000DAB5 0x6E44 # 0 +0x0000DAB6 0x7709 # 0 +0x0000DAB7 0x7C73 # 0 +0x0000DAB8 0x7F8E # 0 +0x0000DAB9 0x8587 # 0 +0x0000DABA 0x8B0E # 0 +0x0000DABB 0x8FF7 # 0 +0x0000DABC 0x9761 # 0 +0x0000DABD 0x9EF4 # 0 +0x0000DABE 0x5CB7 # 0 +0x0000DABF 0x60B6 # 0 +0x0000DAC0 0x610D # 0 +0x0000DAC1 0x61AB # 0 +0x0000DAC2 0x654F # 0 +0x0000DAC3 0x65FB # 0 +0x0000DAC4 0x65FC # 0 +0x0000DAC5 0x6C11 # 0 +0x0000DAC6 0x6CEF # 0 +0x0000DAC7 0x739F # 0 +0x0000DAC8 0x73C9 # 0 +0x0000DAC9 0x7DE1 # 0 +0x0000DACA 0x9594 # 0 +0x0000DACB 0x5BC6 # 0 +0x0000DACC 0x871C # 0 +0x0000DACD 0x8B10 # 0 +0x0000DACE 0x525D # 0 +0x0000DACF 0x535A # 0 +0x0000DAD0 0x62CD # 0 +0x0000DAD1 0x640F # 0 +0x0000DAD2 0x64B2 # 0 +0x0000DAD3 0x6734 # 0 +0x0000DAD4 0x6A38 # 0 +0x0000DAD5 0x6CCA # 0 +0x0000DAD6 0x73C0 # 0 +0x0000DAD7 0x749E # 0 +0x0000DAD8 0x7B94 # 0 +0x0000DAD9 0x7C95 # 0 +0x0000DADA 0x7E1B # 0 +0x0000DADB 0x818A # 0 +0x0000DADC 0x8236 # 0 +0x0000DADD 0x8584 # 0 +0x0000DADE 0x8FEB # 0 +0x0000DADF 0x96F9 # 0 +0x0000DAE0 0x99C1 # 0 +0x0000DAE1 0x4F34 # 0 +0x0000DAE2 0x534A # 0 +0x0000DAE3 0x53CD # 0 +0x0000DAE4 0x53DB # 0 +0x0000DAE5 0x62CC # 0 +0x0000DAE6 0x642C # 0 +0x0000DAE7 0x6500 # 0 +0x0000DAE8 0x6591 # 0 +0x0000DAE9 0x69C3 # 0 +0x0000DAEA 0x6CEE # 0 +0x0000DAEB 0x6F58 # 0 +0x0000DAEC 0x73ED # 0 +0x0000DAED 0x7554 # 0 +0x0000DAEE 0x7622 # 0 +0x0000DAEF 0x76E4 # 0 +0x0000DAF0 0x76FC # 0 +0x0000DAF1 0x78D0 # 0 +0x0000DAF2 0x78FB # 0 +0x0000DAF3 0x792C # 0 +0x0000DAF4 0x7D46 # 0 +0x0000DAF5 0x822C # 0 +0x0000DAF6 0x87E0 # 0 +0x0000DAF7 0x8FD4 # 0 +0x0000DAF8 0x9812 # 0 +0x0000DAF9 0x98EF # 0 +0x0000DAFA 0x52C3 # 0 +0x0000DAFB 0x62D4 # 0 +0x0000DAFC 0x64A5 # 0 +0x0000DAFD 0x6E24 # 0 +0x0000DAFE 0x6F51 # 0 +0x0000DBA1 0x767C # 0 +0x0000DBA2 0x8DCB # 0 +0x0000DBA3 0x91B1 # 0 +0x0000DBA4 0x9262 # 0 +0x0000DBA5 0x9AEE # 0 +0x0000DBA6 0x9B43 # 0 +0x0000DBA7 0x5023 # 0 +0x0000DBA8 0x508D # 0 +0x0000DBA9 0x574A # 0 +0x0000DBAA 0x59A8 # 0 +0x0000DBAB 0x5C28 # 0 +0x0000DBAC 0x5E47 # 0 +0x0000DBAD 0x5F77 # 0 +0x0000DBAE 0x623F # 0 +0x0000DBAF 0x653E # 0 +0x0000DBB0 0x65B9 # 0 +0x0000DBB1 0x65C1 # 0 +0x0000DBB2 0x6609 # 0 +0x0000DBB3 0x678B # 0 +0x0000DBB4 0x699C # 0 +0x0000DBB5 0x6EC2 # 0 +0x0000DBB6 0x78C5 # 0 +0x0000DBB7 0x7D21 # 0 +0x0000DBB8 0x80AA # 0 +0x0000DBB9 0x8180 # 0 +0x0000DBBA 0x822B # 0 +0x0000DBBB 0x82B3 # 0 +0x0000DBBC 0x84A1 # 0 +0x0000DBBD 0x868C # 0 +0x0000DBBE 0x8A2A # 0 +0x0000DBBF 0x8B17 # 0 +0x0000DBC0 0x90A6 # 0 +0x0000DBC1 0x9632 # 0 +0x0000DBC2 0x9F90 # 0 +0x0000DBC3 0x500D # 0 +0x0000DBC4 0x4FF3 # 0 +0x0000DBC5 0xF963 # 0 +0x0000DBC6 0x57F9 # 0 +0x0000DBC7 0x5F98 # 0 +0x0000DBC8 0x62DC # 0 +0x0000DBC9 0x6392 # 0 +0x0000DBCA 0x676F # 0 +0x0000DBCB 0x6E43 # 0 +0x0000DBCC 0x7119 # 0 +0x0000DBCD 0x76C3 # 0 +0x0000DBCE 0x80CC # 0 +0x0000DBCF 0x80DA # 0 +0x0000DBD0 0x88F4 # 0 +0x0000DBD1 0x88F5 # 0 +0x0000DBD2 0x8919 # 0 +0x0000DBD3 0x8CE0 # 0 +0x0000DBD4 0x8F29 # 0 +0x0000DBD5 0x914D # 0 +0x0000DBD6 0x966A # 0 +0x0000DBD7 0x4F2F # 0 +0x0000DBD8 0x4F70 # 0 +0x0000DBD9 0x5E1B # 0 +0x0000DBDA 0x67CF # 0 +0x0000DBDB 0x6822 # 0 +0x0000DBDC 0x767D # 0 +0x0000DBDD 0x767E # 0 +0x0000DBDE 0x9B44 # 0 +0x0000DBDF 0x5E61 # 0 +0x0000DBE0 0x6A0A # 0 +0x0000DBE1 0x7169 # 0 +0x0000DBE2 0x71D4 # 0 +0x0000DBE3 0x756A # 0 +0x0000DBE4 0xF964 # 0 +0x0000DBE5 0x7E41 # 0 +0x0000DBE6 0x8543 # 0 +0x0000DBE7 0x85E9 # 0 +0x0000DBE8 0x98DC # 0 +0x0000DBE9 0x4F10 # 0 +0x0000DBEA 0x7B4F # 0 +0x0000DBEB 0x7F70 # 0 +0x0000DBEC 0x95A5 # 0 +0x0000DBED 0x51E1 # 0 +0x0000DBEE 0x5E06 # 0 +0x0000DBEF 0x68B5 # 0 +0x0000DBF0 0x6C3E # 0 +0x0000DBF1 0x6C4E # 0 +0x0000DBF2 0x6CDB # 0 +0x0000DBF3 0x72AF # 0 +0x0000DBF4 0x7BC4 # 0 +0x0000DBF5 0x8303 # 0 +0x0000DBF6 0x6CD5 # 0 +0x0000DBF7 0x743A # 0 +0x0000DBF8 0x50FB # 0 +0x0000DBF9 0x5288 # 0 +0x0000DBFA 0x58C1 # 0 +0x0000DBFB 0x64D8 # 0 +0x0000DBFC 0x6A97 # 0 +0x0000DBFD 0x74A7 # 0 +0x0000DBFE 0x7656 # 0 +0x0000DCA1 0x78A7 # 0 +0x0000DCA2 0x8617 # 0 +0x0000DCA3 0x95E2 # 0 +0x0000DCA4 0x9739 # 0 +0x0000DCA5 0xF965 # 0 +0x0000DCA6 0x535E # 0 +0x0000DCA7 0x5F01 # 0 +0x0000DCA8 0x8B8A # 0 +0x0000DCA9 0x8FA8 # 0 +0x0000DCAA 0x8FAF # 0 +0x0000DCAB 0x908A # 0 +0x0000DCAC 0x5225 # 0 +0x0000DCAD 0x77A5 # 0 +0x0000DCAE 0x9C49 # 0 +0x0000DCAF 0x9F08 # 0 +0x0000DCB0 0x4E19 # 0 +0x0000DCB1 0x5002 # 0 +0x0000DCB2 0x5175 # 0 +0x0000DCB3 0x5C5B # 0 +0x0000DCB4 0x5E77 # 0 +0x0000DCB5 0x661E # 0 +0x0000DCB6 0x663A # 0 +0x0000DCB7 0x67C4 # 0 +0x0000DCB8 0x68C5 # 0 +0x0000DCB9 0x70B3 # 0 +0x0000DCBA 0x7501 # 0 +0x0000DCBB 0x75C5 # 0 +0x0000DCBC 0x79C9 # 0 +0x0000DCBD 0x7ADD # 0 +0x0000DCBE 0x8F27 # 0 +0x0000DCBF 0x9920 # 0 +0x0000DCC0 0x9A08 # 0 +0x0000DCC1 0x4FDD # 0 +0x0000DCC2 0x5821 # 0 +0x0000DCC3 0x5831 # 0 +0x0000DCC4 0x5BF6 # 0 +0x0000DCC5 0x666E # 0 +0x0000DCC6 0x6B65 # 0 +0x0000DCC7 0x6D11 # 0 +0x0000DCC8 0x6E7A # 0 +0x0000DCC9 0x6F7D # 0 +0x0000DCCA 0x73E4 # 0 +0x0000DCCB 0x752B # 0 +0x0000DCCC 0x83E9 # 0 +0x0000DCCD 0x88DC # 0 +0x0000DCCE 0x8913 # 0 +0x0000DCCF 0x8B5C # 0 +0x0000DCD0 0x8F14 # 0 +0x0000DCD1 0x4F0F # 0 +0x0000DCD2 0x50D5 # 0 +0x0000DCD3 0x5310 # 0 +0x0000DCD4 0x535C # 0 +0x0000DCD5 0x5B93 # 0 +0x0000DCD6 0x5FA9 # 0 +0x0000DCD7 0x670D # 0 +0x0000DCD8 0x798F # 0 +0x0000DCD9 0x8179 # 0 +0x0000DCDA 0x832F # 0 +0x0000DCDB 0x8514 # 0 +0x0000DCDC 0x8907 # 0 +0x0000DCDD 0x8986 # 0 +0x0000DCDE 0x8F39 # 0 +0x0000DCDF 0x8F3B # 0 +0x0000DCE0 0x99A5 # 0 +0x0000DCE1 0x9C12 # 0 +0x0000DCE2 0x672C # 0 +0x0000DCE3 0x4E76 # 0 +0x0000DCE4 0x4FF8 # 0 +0x0000DCE5 0x5949 # 0 +0x0000DCE6 0x5C01 # 0 +0x0000DCE7 0x5CEF # 0 +0x0000DCE8 0x5CF0 # 0 +0x0000DCE9 0x6367 # 0 +0x0000DCEA 0x68D2 # 0 +0x0000DCEB 0x70FD # 0 +0x0000DCEC 0x71A2 # 0 +0x0000DCED 0x742B # 0 +0x0000DCEE 0x7E2B # 0 +0x0000DCEF 0x84EC # 0 +0x0000DCF0 0x8702 # 0 +0x0000DCF1 0x9022 # 0 +0x0000DCF2 0x92D2 # 0 +0x0000DCF3 0x9CF3 # 0 +0x0000DCF4 0x4E0D # 0 +0x0000DCF5 0x4ED8 # 0 +0x0000DCF6 0x4FEF # 0 +0x0000DCF7 0x5085 # 0 +0x0000DCF8 0x5256 # 0 +0x0000DCF9 0x526F # 0 +0x0000DCFA 0x5426 # 0 +0x0000DCFB 0x5490 # 0 +0x0000DCFC 0x57E0 # 0 +0x0000DCFD 0x592B # 0 +0x0000DCFE 0x5A66 # 0 +0x0000DDA1 0x5B5A # 0 +0x0000DDA2 0x5B75 # 0 +0x0000DDA3 0x5BCC # 0 +0x0000DDA4 0x5E9C # 0 +0x0000DDA5 0xF966 # 0 +0x0000DDA6 0x6276 # 0 +0x0000DDA7 0x6577 # 0 +0x0000DDA8 0x65A7 # 0 +0x0000DDA9 0x6D6E # 0 +0x0000DDAA 0x6EA5 # 0 +0x0000DDAB 0x7236 # 0 +0x0000DDAC 0x7B26 # 0 +0x0000DDAD 0x7C3F # 0 +0x0000DDAE 0x7F36 # 0 +0x0000DDAF 0x8150 # 0 +0x0000DDB0 0x8151 # 0 +0x0000DDB1 0x819A # 0 +0x0000DDB2 0x8240 # 0 +0x0000DDB3 0x8299 # 0 +0x0000DDB4 0x83A9 # 0 +0x0000DDB5 0x8A03 # 0 +0x0000DDB6 0x8CA0 # 0 +0x0000DDB7 0x8CE6 # 0 +0x0000DDB8 0x8CFB # 0 +0x0000DDB9 0x8D74 # 0 +0x0000DDBA 0x8DBA # 0 +0x0000DDBB 0x90E8 # 0 +0x0000DDBC 0x91DC # 0 +0x0000DDBD 0x961C # 0 +0x0000DDBE 0x9644 # 0 +0x0000DDBF 0x99D9 # 0 +0x0000DDC0 0x9CE7 # 0 +0x0000DDC1 0x5317 # 0 +0x0000DDC2 0x5206 # 0 +0x0000DDC3 0x5429 # 0 +0x0000DDC4 0x5674 # 0 +0x0000DDC5 0x58B3 # 0 +0x0000DDC6 0x5954 # 0 +0x0000DDC7 0x596E # 0 +0x0000DDC8 0x5FFF # 0 +0x0000DDC9 0x61A4 # 0 +0x0000DDCA 0x626E # 0 +0x0000DDCB 0x6610 # 0 +0x0000DDCC 0x6C7E # 0 +0x0000DDCD 0x711A # 0 +0x0000DDCE 0x76C6 # 0 +0x0000DDCF 0x7C89 # 0 +0x0000DDD0 0x7CDE # 0 +0x0000DDD1 0x7D1B # 0 +0x0000DDD2 0x82AC # 0 +0x0000DDD3 0x8CC1 # 0 +0x0000DDD4 0x96F0 # 0 +0x0000DDD5 0xF967 # 0 +0x0000DDD6 0x4F5B # 0 +0x0000DDD7 0x5F17 # 0 +0x0000DDD8 0x5F7F # 0 +0x0000DDD9 0x62C2 # 0 +0x0000DDDA 0x5D29 # 0 +0x0000DDDB 0x670B # 0 +0x0000DDDC 0x68DA # 0 +0x0000DDDD 0x787C # 0 +0x0000DDDE 0x7E43 # 0 +0x0000DDDF 0x9D6C # 0 +0x0000DDE0 0x4E15 # 0 +0x0000DDE1 0x5099 # 0 +0x0000DDE2 0x5315 # 0 +0x0000DDE3 0x532A # 0 +0x0000DDE4 0x5351 # 0 +0x0000DDE5 0x5983 # 0 +0x0000DDE6 0x5A62 # 0 +0x0000DDE7 0x5E87 # 0 +0x0000DDE8 0x60B2 # 0 +0x0000DDE9 0x618A # 0 +0x0000DDEA 0x6249 # 0 +0x0000DDEB 0x6279 # 0 +0x0000DDEC 0x6590 # 0 +0x0000DDED 0x6787 # 0 +0x0000DDEE 0x69A7 # 0 +0x0000DDEF 0x6BD4 # 0 +0x0000DDF0 0x6BD6 # 0 +0x0000DDF1 0x6BD7 # 0 +0x0000DDF2 0x6BD8 # 0 +0x0000DDF3 0x6CB8 # 0 +0x0000DDF4 0xF968 # 0 +0x0000DDF5 0x7435 # 0 +0x0000DDF6 0x75FA # 0 +0x0000DDF7 0x7812 # 0 +0x0000DDF8 0x7891 # 0 +0x0000DDF9 0x79D5 # 0 +0x0000DDFA 0x79D8 # 0 +0x0000DDFB 0x7C83 # 0 +0x0000DDFC 0x7DCB # 0 +0x0000DDFD 0x7FE1 # 0 +0x0000DDFE 0x80A5 # 0 +0x0000DEA1 0x813E # 0 +0x0000DEA2 0x81C2 # 0 +0x0000DEA3 0x83F2 # 0 +0x0000DEA4 0x871A # 0 +0x0000DEA5 0x88E8 # 0 +0x0000DEA6 0x8AB9 # 0 +0x0000DEA7 0x8B6C # 0 +0x0000DEA8 0x8CBB # 0 +0x0000DEA9 0x9119 # 0 +0x0000DEAA 0x975E # 0 +0x0000DEAB 0x98DB # 0 +0x0000DEAC 0x9F3B # 0 +0x0000DEAD 0x56AC # 0 +0x0000DEAE 0x5B2A # 0 +0x0000DEAF 0x5F6C # 0 +0x0000DEB0 0x658C # 0 +0x0000DEB1 0x6AB3 # 0 +0x0000DEB2 0x6BAF # 0 +0x0000DEB3 0x6D5C # 0 +0x0000DEB4 0x6FF1 # 0 +0x0000DEB5 0x7015 # 0 +0x0000DEB6 0x725D # 0 +0x0000DEB7 0x73AD # 0 +0x0000DEB8 0x8CA7 # 0 +0x0000DEB9 0x8CD3 # 0 +0x0000DEBA 0x983B # 0 +0x0000DEBB 0x6191 # 0 +0x0000DEBC 0x6C37 # 0 +0x0000DEBD 0x8058 # 0 +0x0000DEBE 0x9A01 # 0 +0x0000DEBF 0x4E4D # 0 +0x0000DEC0 0x4E8B # 0 +0x0000DEC1 0x4E9B # 0 +0x0000DEC2 0x4ED5 # 0 +0x0000DEC3 0x4F3A # 0 +0x0000DEC4 0x4F3C # 0 +0x0000DEC5 0x4F7F # 0 +0x0000DEC6 0x4FDF # 0 +0x0000DEC7 0x50FF # 0 +0x0000DEC8 0x53F2 # 0 +0x0000DEC9 0x53F8 # 0 +0x0000DECA 0x5506 # 0 +0x0000DECB 0x55E3 # 0 +0x0000DECC 0x56DB # 0 +0x0000DECD 0x58EB # 0 +0x0000DECE 0x5962 # 0 +0x0000DECF 0x5A11 # 0 +0x0000DED0 0x5BEB # 0 +0x0000DED1 0x5BFA # 0 +0x0000DED2 0x5C04 # 0 +0x0000DED3 0x5DF3 # 0 +0x0000DED4 0x5E2B # 0 +0x0000DED5 0x5F99 # 0 +0x0000DED6 0x601D # 0 +0x0000DED7 0x6368 # 0 +0x0000DED8 0x659C # 0 +0x0000DED9 0x65AF # 0 +0x0000DEDA 0x67F6 # 0 +0x0000DEDB 0x67FB # 0 +0x0000DEDC 0x68AD # 0 +0x0000DEDD 0x6B7B # 0 +0x0000DEDE 0x6C99 # 0 +0x0000DEDF 0x6CD7 # 0 +0x0000DEE0 0x6E23 # 0 +0x0000DEE1 0x7009 # 0 +0x0000DEE2 0x7345 # 0 +0x0000DEE3 0x7802 # 0 +0x0000DEE4 0x793E # 0 +0x0000DEE5 0x7940 # 0 +0x0000DEE6 0x7960 # 0 +0x0000DEE7 0x79C1 # 0 +0x0000DEE8 0x7BE9 # 0 +0x0000DEE9 0x7D17 # 0 +0x0000DEEA 0x7D72 # 0 +0x0000DEEB 0x8086 # 0 +0x0000DEEC 0x820D # 0 +0x0000DEED 0x838E # 0 +0x0000DEEE 0x84D1 # 0 +0x0000DEEF 0x86C7 # 0 +0x0000DEF0 0x88DF # 0 +0x0000DEF1 0x8A50 # 0 +0x0000DEF2 0x8A5E # 0 +0x0000DEF3 0x8B1D # 0 +0x0000DEF4 0x8CDC # 0 +0x0000DEF5 0x8D66 # 0 +0x0000DEF6 0x8FAD # 0 +0x0000DEF7 0x90AA # 0 +0x0000DEF8 0x98FC # 0 +0x0000DEF9 0x99DF # 0 +0x0000DEFA 0x9E9D # 0 +0x0000DEFB 0x524A # 0 +0x0000DEFC 0xF969 # 0 +0x0000DEFD 0x6714 # 0 +0x0000DEFE 0xF96A # 0 +0x0000DFA1 0x5098 # 0 +0x0000DFA2 0x522A # 0 +0x0000DFA3 0x5C71 # 0 +0x0000DFA4 0x6563 # 0 +0x0000DFA5 0x6C55 # 0 +0x0000DFA6 0x73CA # 0 +0x0000DFA7 0x7523 # 0 +0x0000DFA8 0x759D # 0 +0x0000DFA9 0x7B97 # 0 +0x0000DFAA 0x849C # 0 +0x0000DFAB 0x9178 # 0 +0x0000DFAC 0x9730 # 0 +0x0000DFAD 0x4E77 # 0 +0x0000DFAE 0x6492 # 0 +0x0000DFAF 0x6BBA # 0 +0x0000DFB0 0x715E # 0 +0x0000DFB1 0x85A9 # 0 +0x0000DFB2 0x4E09 # 0 +0x0000DFB3 0xF96B # 0 +0x0000DFB4 0x6749 # 0 +0x0000DFB5 0x68EE # 0 +0x0000DFB6 0x6E17 # 0 +0x0000DFB7 0x829F # 0 +0x0000DFB8 0x8518 # 0 +0x0000DFB9 0x886B # 0 +0x0000DFBA 0x63F7 # 0 +0x0000DFBB 0x6F81 # 0 +0x0000DFBC 0x9212 # 0 +0x0000DFBD 0x98AF # 0 +0x0000DFBE 0x4E0A # 0 +0x0000DFBF 0x50B7 # 0 +0x0000DFC0 0x50CF # 0 +0x0000DFC1 0x511F # 0 +0x0000DFC2 0x5546 # 0 +0x0000DFC3 0x55AA # 0 +0x0000DFC4 0x5617 # 0 +0x0000DFC5 0x5B40 # 0 +0x0000DFC6 0x5C19 # 0 +0x0000DFC7 0x5CE0 # 0 +0x0000DFC8 0x5E38 # 0 +0x0000DFC9 0x5E8A # 0 +0x0000DFCA 0x5EA0 # 0 +0x0000DFCB 0x5EC2 # 0 +0x0000DFCC 0x60F3 # 0 +0x0000DFCD 0x6851 # 0 +0x0000DFCE 0x6A61 # 0 +0x0000DFCF 0x6E58 # 0 +0x0000DFD0 0x723D # 0 +0x0000DFD1 0x7240 # 0 +0x0000DFD2 0x72C0 # 0 +0x0000DFD3 0x76F8 # 0 +0x0000DFD4 0x7965 # 0 +0x0000DFD5 0x7BB1 # 0 +0x0000DFD6 0x7FD4 # 0 +0x0000DFD7 0x88F3 # 0 +0x0000DFD8 0x89F4 # 0 +0x0000DFD9 0x8A73 # 0 +0x0000DFDA 0x8C61 # 0 +0x0000DFDB 0x8CDE # 0 +0x0000DFDC 0x971C # 0 +0x0000DFDD 0x585E # 0 +0x0000DFDE 0x74BD # 0 +0x0000DFDF 0x8CFD # 0 +0x0000DFE0 0x55C7 # 0 +0x0000DFE1 0xF96C # 0 +0x0000DFE2 0x7A61 # 0 +0x0000DFE3 0x7D22 # 0 +0x0000DFE4 0x8272 # 0 +0x0000DFE5 0x7272 # 0 +0x0000DFE6 0x751F # 0 +0x0000DFE7 0x7525 # 0 +0x0000DFE8 0xF96D # 0 +0x0000DFE9 0x7B19 # 0 +0x0000DFEA 0x5885 # 0 +0x0000DFEB 0x58FB # 0 +0x0000DFEC 0x5DBC # 0 +0x0000DFED 0x5E8F # 0 +0x0000DFEE 0x5EB6 # 0 +0x0000DFEF 0x5F90 # 0 +0x0000DFF0 0x6055 # 0 +0x0000DFF1 0x6292 # 0 +0x0000DFF2 0x637F # 0 +0x0000DFF3 0x654D # 0 +0x0000DFF4 0x6691 # 0 +0x0000DFF5 0x66D9 # 0 +0x0000DFF6 0x66F8 # 0 +0x0000DFF7 0x6816 # 0 +0x0000DFF8 0x68F2 # 0 +0x0000DFF9 0x7280 # 0 +0x0000DFFA 0x745E # 0 +0x0000DFFB 0x7B6E # 0 +0x0000DFFC 0x7D6E # 0 +0x0000DFFD 0x7DD6 # 0 +0x0000DFFE 0x7F72 # 0 +0x0000E0A1 0x80E5 # 0 +0x0000E0A2 0x8212 # 0 +0x0000E0A3 0x85AF # 0 +0x0000E0A4 0x897F # 0 +0x0000E0A5 0x8A93 # 0 +0x0000E0A6 0x901D # 0 +0x0000E0A7 0x92E4 # 0 +0x0000E0A8 0x9ECD # 0 +0x0000E0A9 0x9F20 # 0 +0x0000E0AA 0x5915 # 0 +0x0000E0AB 0x596D # 0 +0x0000E0AC 0x5E2D # 0 +0x0000E0AD 0x60DC # 0 +0x0000E0AE 0x6614 # 0 +0x0000E0AF 0x6673 # 0 +0x0000E0B0 0x6790 # 0 +0x0000E0B1 0x6C50 # 0 +0x0000E0B2 0x6DC5 # 0 +0x0000E0B3 0x6F5F # 0 +0x0000E0B4 0x77F3 # 0 +0x0000E0B5 0x78A9 # 0 +0x0000E0B6 0x84C6 # 0 +0x0000E0B7 0x91CB # 0 +0x0000E0B8 0x932B # 0 +0x0000E0B9 0x4ED9 # 0 +0x0000E0BA 0x50CA # 0 +0x0000E0BB 0x5148 # 0 +0x0000E0BC 0x5584 # 0 +0x0000E0BD 0x5B0B # 0 +0x0000E0BE 0x5BA3 # 0 +0x0000E0BF 0x6247 # 0 +0x0000E0C0 0x657E # 0 +0x0000E0C1 0x65CB # 0 +0x0000E0C2 0x6E32 # 0 +0x0000E0C3 0x717D # 0 +0x0000E0C4 0x7401 # 0 +0x0000E0C5 0x7444 # 0 +0x0000E0C6 0x7487 # 0 +0x0000E0C7 0x74BF # 0 +0x0000E0C8 0x766C # 0 +0x0000E0C9 0x79AA # 0 +0x0000E0CA 0x7DDA # 0 +0x0000E0CB 0x7E55 # 0 +0x0000E0CC 0x7FA8 # 0 +0x0000E0CD 0x817A # 0 +0x0000E0CE 0x81B3 # 0 +0x0000E0CF 0x8239 # 0 +0x0000E0D0 0x861A # 0 +0x0000E0D1 0x87EC # 0 +0x0000E0D2 0x8A75 # 0 +0x0000E0D3 0x8DE3 # 0 +0x0000E0D4 0x9078 # 0 +0x0000E0D5 0x9291 # 0 +0x0000E0D6 0x9425 # 0 +0x0000E0D7 0x994D # 0 +0x0000E0D8 0x9BAE # 0 +0x0000E0D9 0x5368 # 0 +0x0000E0DA 0x5C51 # 0 +0x0000E0DB 0x6954 # 0 +0x0000E0DC 0x6CC4 # 0 +0x0000E0DD 0x6D29 # 0 +0x0000E0DE 0x6E2B # 0 +0x0000E0DF 0x820C # 0 +0x0000E0E0 0x859B # 0 +0x0000E0E1 0x893B # 0 +0x0000E0E2 0x8A2D # 0 +0x0000E0E3 0x8AAA # 0 +0x0000E0E4 0x96EA # 0 +0x0000E0E5 0x9F67 # 0 +0x0000E0E6 0x5261 # 0 +0x0000E0E7 0x66B9 # 0 +0x0000E0E8 0x6BB2 # 0 +0x0000E0E9 0x7E96 # 0 +0x0000E0EA 0x87FE # 0 +0x0000E0EB 0x8D0D # 0 +0x0000E0EC 0x9583 # 0 +0x0000E0ED 0x965D # 0 +0x0000E0EE 0x651D # 0 +0x0000E0EF 0x6D89 # 0 +0x0000E0F0 0x71EE # 0 +0x0000E0F1 0xF96E # 0 +0x0000E0F2 0x57CE # 0 +0x0000E0F3 0x59D3 # 0 +0x0000E0F4 0x5BAC # 0 +0x0000E0F5 0x6027 # 0 +0x0000E0F6 0x60FA # 0 +0x0000E0F7 0x6210 # 0 +0x0000E0F8 0x661F # 0 +0x0000E0F9 0x665F # 0 +0x0000E0FA 0x7329 # 0 +0x0000E0FB 0x73F9 # 0 +0x0000E0FC 0x76DB # 0 +0x0000E0FD 0x7701 # 0 +0x0000E0FE 0x7B6C # 0 +0x0000E1A1 0x8056 # 0 +0x0000E1A2 0x8072 # 0 +0x0000E1A3 0x8165 # 0 +0x0000E1A4 0x8AA0 # 0 +0x0000E1A5 0x9192 # 0 +0x0000E1A6 0x4E16 # 0 +0x0000E1A7 0x52E2 # 0 +0x0000E1A8 0x6B72 # 0 +0x0000E1A9 0x6D17 # 0 +0x0000E1AA 0x7A05 # 0 +0x0000E1AB 0x7B39 # 0 +0x0000E1AC 0x7D30 # 0 +0x0000E1AD 0xF96F # 0 +0x0000E1AE 0x8CB0 # 0 +0x0000E1AF 0x53EC # 0 +0x0000E1B0 0x562F # 0 +0x0000E1B1 0x5851 # 0 +0x0000E1B2 0x5BB5 # 0 +0x0000E1B3 0x5C0F # 0 +0x0000E1B4 0x5C11 # 0 +0x0000E1B5 0x5DE2 # 0 +0x0000E1B6 0x6240 # 0 +0x0000E1B7 0x6383 # 0 +0x0000E1B8 0x6414 # 0 +0x0000E1B9 0x662D # 0 +0x0000E1BA 0x68B3 # 0 +0x0000E1BB 0x6CBC # 0 +0x0000E1BC 0x6D88 # 0 +0x0000E1BD 0x6EAF # 0 +0x0000E1BE 0x701F # 0 +0x0000E1BF 0x70A4 # 0 +0x0000E1C0 0x71D2 # 0 +0x0000E1C1 0x7526 # 0 +0x0000E1C2 0x758F # 0 +0x0000E1C3 0x758E # 0 +0x0000E1C4 0x7619 # 0 +0x0000E1C5 0x7B11 # 0 +0x0000E1C6 0x7BE0 # 0 +0x0000E1C7 0x7C2B # 0 +0x0000E1C8 0x7D20 # 0 +0x0000E1C9 0x7D39 # 0 +0x0000E1CA 0x852C # 0 +0x0000E1CB 0x856D # 0 +0x0000E1CC 0x8607 # 0 +0x0000E1CD 0x8A34 # 0 +0x0000E1CE 0x900D # 0 +0x0000E1CF 0x9061 # 0 +0x0000E1D0 0x90B5 # 0 +0x0000E1D1 0x92B7 # 0 +0x0000E1D2 0x97F6 # 0 +0x0000E1D3 0x9A37 # 0 +0x0000E1D4 0x4FD7 # 0 +0x0000E1D5 0x5C6C # 0 +0x0000E1D6 0x675F # 0 +0x0000E1D7 0x6D91 # 0 +0x0000E1D8 0x7C9F # 0 +0x0000E1D9 0x7E8C # 0 +0x0000E1DA 0x8B16 # 0 +0x0000E1DB 0x8D16 # 0 +0x0000E1DC 0x901F # 0 +0x0000E1DD 0x5B6B # 0 +0x0000E1DE 0x5DFD # 0 +0x0000E1DF 0x640D # 0 +0x0000E1E0 0x84C0 # 0 +0x0000E1E1 0x905C # 0 +0x0000E1E2 0x98E1 # 0 +0x0000E1E3 0x7387 # 0 +0x0000E1E4 0x5B8B # 0 +0x0000E1E5 0x609A # 0 +0x0000E1E6 0x677E # 0 +0x0000E1E7 0x6DDE # 0 +0x0000E1E8 0x8A1F # 0 +0x0000E1E9 0x8AA6 # 0 +0x0000E1EA 0x9001 # 0 +0x0000E1EB 0x980C # 0 +0x0000E1EC 0x5237 # 0 +0x0000E1ED 0xF970 # 0 +0x0000E1EE 0x7051 # 0 +0x0000E1EF 0x788E # 0 +0x0000E1F0 0x9396 # 0 +0x0000E1F1 0x8870 # 0 +0x0000E1F2 0x91D7 # 0 +0x0000E1F3 0x4FEE # 0 +0x0000E1F4 0x53D7 # 0 +0x0000E1F5 0x55FD # 0 +0x0000E1F6 0x56DA # 0 +0x0000E1F7 0x5782 # 0 +0x0000E1F8 0x58FD # 0 +0x0000E1F9 0x5AC2 # 0 +0x0000E1FA 0x5B88 # 0 +0x0000E1FB 0x5CAB # 0 +0x0000E1FC 0x5CC0 # 0 +0x0000E1FD 0x5E25 # 0 +0x0000E1FE 0x6101 # 0 +0x0000E2A1 0x620D # 0 +0x0000E2A2 0x624B # 0 +0x0000E2A3 0x6388 # 0 +0x0000E2A4 0x641C # 0 +0x0000E2A5 0x6536 # 0 +0x0000E2A6 0x6578 # 0 +0x0000E2A7 0x6A39 # 0 +0x0000E2A8 0x6B8A # 0 +0x0000E2A9 0x6C34 # 0 +0x0000E2AA 0x6D19 # 0 +0x0000E2AB 0x6F31 # 0 +0x0000E2AC 0x71E7 # 0 +0x0000E2AD 0x72E9 # 0 +0x0000E2AE 0x7378 # 0 +0x0000E2AF 0x7407 # 0 +0x0000E2B0 0x74B2 # 0 +0x0000E2B1 0x7626 # 0 +0x0000E2B2 0x7761 # 0 +0x0000E2B3 0x79C0 # 0 +0x0000E2B4 0x7A57 # 0 +0x0000E2B5 0x7AEA # 0 +0x0000E2B6 0x7CB9 # 0 +0x0000E2B7 0x7D8F # 0 +0x0000E2B8 0x7DAC # 0 +0x0000E2B9 0x7E61 # 0 +0x0000E2BA 0x7F9E # 0 +0x0000E2BB 0x8129 # 0 +0x0000E2BC 0x8331 # 0 +0x0000E2BD 0x8490 # 0 +0x0000E2BE 0x84DA # 0 +0x0000E2BF 0x85EA # 0 +0x0000E2C0 0x8896 # 0 +0x0000E2C1 0x8AB0 # 0 +0x0000E2C2 0x8B90 # 0 +0x0000E2C3 0x8F38 # 0 +0x0000E2C4 0x9042 # 0 +0x0000E2C5 0x9083 # 0 +0x0000E2C6 0x916C # 0 +0x0000E2C7 0x9296 # 0 +0x0000E2C8 0x92B9 # 0 +0x0000E2C9 0x968B # 0 +0x0000E2CA 0x96A7 # 0 +0x0000E2CB 0x96A8 # 0 +0x0000E2CC 0x96D6 # 0 +0x0000E2CD 0x9700 # 0 +0x0000E2CE 0x9808 # 0 +0x0000E2CF 0x9996 # 0 +0x0000E2D0 0x9AD3 # 0 +0x0000E2D1 0x9B1A # 0 +0x0000E2D2 0x53D4 # 0 +0x0000E2D3 0x587E # 0 +0x0000E2D4 0x5919 # 0 +0x0000E2D5 0x5B70 # 0 +0x0000E2D6 0x5BBF # 0 +0x0000E2D7 0x6DD1 # 0 +0x0000E2D8 0x6F5A # 0 +0x0000E2D9 0x719F # 0 +0x0000E2DA 0x7421 # 0 +0x0000E2DB 0x74B9 # 0 +0x0000E2DC 0x8085 # 0 +0x0000E2DD 0x83FD # 0 +0x0000E2DE 0x5DE1 # 0 +0x0000E2DF 0x5F87 # 0 +0x0000E2E0 0x5FAA # 0 +0x0000E2E1 0x6042 # 0 +0x0000E2E2 0x65EC # 0 +0x0000E2E3 0x6812 # 0 +0x0000E2E4 0x696F # 0 +0x0000E2E5 0x6A53 # 0 +0x0000E2E6 0x6B89 # 0 +0x0000E2E7 0x6D35 # 0 +0x0000E2E8 0x6DF3 # 0 +0x0000E2E9 0x73E3 # 0 +0x0000E2EA 0x76FE # 0 +0x0000E2EB 0x77AC # 0 +0x0000E2EC 0x7B4D # 0 +0x0000E2ED 0x7D14 # 0 +0x0000E2EE 0x8123 # 0 +0x0000E2EF 0x821C # 0 +0x0000E2F0 0x8340 # 0 +0x0000E2F1 0x84F4 # 0 +0x0000E2F2 0x8563 # 0 +0x0000E2F3 0x8A62 # 0 +0x0000E2F4 0x8AC4 # 0 +0x0000E2F5 0x9187 # 0 +0x0000E2F6 0x931E # 0 +0x0000E2F7 0x9806 # 0 +0x0000E2F8 0x99B4 # 0 +0x0000E2F9 0x620C # 0 +0x0000E2FA 0x8853 # 0 +0x0000E2FB 0x8FF0 # 0 +0x0000E2FC 0x9265 # 0 +0x0000E2FD 0x5D07 # 0 +0x0000E2FE 0x5D27 # 0 +0x0000E3A1 0x5D69 # 0 +0x0000E3A2 0x745F # 0 +0x0000E3A3 0x819D # 0 +0x0000E3A4 0x8768 # 0 +0x0000E3A5 0x6FD5 # 0 +0x0000E3A6 0x62FE # 0 +0x0000E3A7 0x7FD2 # 0 +0x0000E3A8 0x8936 # 0 +0x0000E3A9 0x8972 # 0 +0x0000E3AA 0x4E1E # 0 +0x0000E3AB 0x4E58 # 0 +0x0000E3AC 0x50E7 # 0 +0x0000E3AD 0x52DD # 0 +0x0000E3AE 0x5347 # 0 +0x0000E3AF 0x627F # 0 +0x0000E3B0 0x6607 # 0 +0x0000E3B1 0x7E69 # 0 +0x0000E3B2 0x8805 # 0 +0x0000E3B3 0x965E # 0 +0x0000E3B4 0x4F8D # 0 +0x0000E3B5 0x5319 # 0 +0x0000E3B6 0x5636 # 0 +0x0000E3B7 0x59CB # 0 +0x0000E3B8 0x5AA4 # 0 +0x0000E3B9 0x5C38 # 0 +0x0000E3BA 0x5C4E # 0 +0x0000E3BB 0x5C4D # 0 +0x0000E3BC 0x5E02 # 0 +0x0000E3BD 0x5F11 # 0 +0x0000E3BE 0x6043 # 0 +0x0000E3BF 0x65BD # 0 +0x0000E3C0 0x662F # 0 +0x0000E3C1 0x6642 # 0 +0x0000E3C2 0x67BE # 0 +0x0000E3C3 0x67F4 # 0 +0x0000E3C4 0x731C # 0 +0x0000E3C5 0x77E2 # 0 +0x0000E3C6 0x793A # 0 +0x0000E3C7 0x7FC5 # 0 +0x0000E3C8 0x8494 # 0 +0x0000E3C9 0x84CD # 0 +0x0000E3CA 0x8996 # 0 +0x0000E3CB 0x8A66 # 0 +0x0000E3CC 0x8A69 # 0 +0x0000E3CD 0x8AE1 # 0 +0x0000E3CE 0x8C55 # 0 +0x0000E3CF 0x8C7A # 0 +0x0000E3D0 0x57F4 # 0 +0x0000E3D1 0x5BD4 # 0 +0x0000E3D2 0x5F0F # 0 +0x0000E3D3 0x606F # 0 +0x0000E3D4 0x62ED # 0 +0x0000E3D5 0x690D # 0 +0x0000E3D6 0x6B96 # 0 +0x0000E3D7 0x6E5C # 0 +0x0000E3D8 0x7184 # 0 +0x0000E3D9 0x7BD2 # 0 +0x0000E3DA 0x8755 # 0 +0x0000E3DB 0x8B58 # 0 +0x0000E3DC 0x8EFE # 0 +0x0000E3DD 0x98DF # 0 +0x0000E3DE 0x98FE # 0 +0x0000E3DF 0x4F38 # 0 +0x0000E3E0 0x4F81 # 0 +0x0000E3E1 0x4FE1 # 0 +0x0000E3E2 0x547B # 0 +0x0000E3E3 0x5A20 # 0 +0x0000E3E4 0x5BB8 # 0 +0x0000E3E5 0x613C # 0 +0x0000E3E6 0x65B0 # 0 +0x0000E3E7 0x6668 # 0 +0x0000E3E8 0x71FC # 0 +0x0000E3E9 0x7533 # 0 +0x0000E3EA 0x795E # 0 +0x0000E3EB 0x7D33 # 0 +0x0000E3EC 0x814E # 0 +0x0000E3ED 0x81E3 # 0 +0x0000E3EE 0x8398 # 0 +0x0000E3EF 0x85AA # 0 +0x0000E3F0 0x85CE # 0 +0x0000E3F1 0x8703 # 0 +0x0000E3F2 0x8A0A # 0 +0x0000E3F3 0x8EAB # 0 +0x0000E3F4 0x8F9B # 0 +0x0000E3F5 0xF971 # 0 +0x0000E3F6 0x8FC5 # 0 +0x0000E3F7 0x5931 # 0 +0x0000E3F8 0x5BA4 # 0 +0x0000E3F9 0x5BE6 # 0 +0x0000E3FA 0x6089 # 0 +0x0000E3FB 0x5BE9 # 0 +0x0000E3FC 0x5C0B # 0 +0x0000E3FD 0x5FC3 # 0 +0x0000E3FE 0x6C81 # 0 +0x0000E4A1 0xF972 # 0 +0x0000E4A2 0x6DF1 # 0 +0x0000E4A3 0x700B # 0 +0x0000E4A4 0x751A # 0 +0x0000E4A5 0x82AF # 0 +0x0000E4A6 0x8AF6 # 0 +0x0000E4A7 0x4EC0 # 0 +0x0000E4A8 0x5341 # 0 +0x0000E4A9 0xF973 # 0 +0x0000E4AA 0x96D9 # 0 +0x0000E4AB 0x6C0F # 0 +0x0000E4AC 0x4E9E # 0 +0x0000E4AD 0x4FC4 # 0 +0x0000E4AE 0x5152 # 0 +0x0000E4AF 0x555E # 0 +0x0000E4B0 0x5A25 # 0 +0x0000E4B1 0x5CE8 # 0 +0x0000E4B2 0x6211 # 0 +0x0000E4B3 0x7259 # 0 +0x0000E4B4 0x82BD # 0 +0x0000E4B5 0x83AA # 0 +0x0000E4B6 0x86FE # 0 +0x0000E4B7 0x8859 # 0 +0x0000E4B8 0x8A1D # 0 +0x0000E4B9 0x963F # 0 +0x0000E4BA 0x96C5 # 0 +0x0000E4BB 0x9913 # 0 +0x0000E4BC 0x9D09 # 0 +0x0000E4BD 0x9D5D # 0 +0x0000E4BE 0x580A # 0 +0x0000E4BF 0x5CB3 # 0 +0x0000E4C0 0x5DBD # 0 +0x0000E4C1 0x5E44 # 0 +0x0000E4C2 0x60E1 # 0 +0x0000E4C3 0x6115 # 0 +0x0000E4C4 0x63E1 # 0 +0x0000E4C5 0x6A02 # 0 +0x0000E4C6 0x6E25 # 0 +0x0000E4C7 0x9102 # 0 +0x0000E4C8 0x9354 # 0 +0x0000E4C9 0x984E # 0 +0x0000E4CA 0x9C10 # 0 +0x0000E4CB 0x9F77 # 0 +0x0000E4CC 0x5B89 # 0 +0x0000E4CD 0x5CB8 # 0 +0x0000E4CE 0x6309 # 0 +0x0000E4CF 0x664F # 0 +0x0000E4D0 0x6848 # 0 +0x0000E4D1 0x773C # 0 +0x0000E4D2 0x96C1 # 0 +0x0000E4D3 0x978D # 0 +0x0000E4D4 0x9854 # 0 +0x0000E4D5 0x9B9F # 0 +0x0000E4D6 0x65A1 # 0 +0x0000E4D7 0x8B01 # 0 +0x0000E4D8 0x8ECB # 0 +0x0000E4D9 0x95BC # 0 +0x0000E4DA 0x5535 # 0 +0x0000E4DB 0x5CA9 # 0 +0x0000E4DC 0x5DD6 # 0 +0x0000E4DD 0x5EB5 # 0 +0x0000E4DE 0x6697 # 0 +0x0000E4DF 0x764C # 0 +0x0000E4E0 0x83F4 # 0 +0x0000E4E1 0x95C7 # 0 +0x0000E4E2 0x58D3 # 0 +0x0000E4E3 0x62BC # 0 +0x0000E4E4 0x72CE # 0 +0x0000E4E5 0x9D28 # 0 +0x0000E4E6 0x4EF0 # 0 +0x0000E4E7 0x592E # 0 +0x0000E4E8 0x600F # 0 +0x0000E4E9 0x663B # 0 +0x0000E4EA 0x6B83 # 0 +0x0000E4EB 0x79E7 # 0 +0x0000E4EC 0x9D26 # 0 +0x0000E4ED 0x5393 # 0 +0x0000E4EE 0x54C0 # 0 +0x0000E4EF 0x57C3 # 0 +0x0000E4F0 0x5D16 # 0 +0x0000E4F1 0x611B # 0 +0x0000E4F2 0x66D6 # 0 +0x0000E4F3 0x6DAF # 0 +0x0000E4F4 0x788D # 0 +0x0000E4F5 0x827E # 0 +0x0000E4F6 0x9698 # 0 +0x0000E4F7 0x9744 # 0 +0x0000E4F8 0x5384 # 0 +0x0000E4F9 0x627C # 0 +0x0000E4FA 0x6396 # 0 +0x0000E4FB 0x6DB2 # 0 +0x0000E4FC 0x7E0A # 0 +0x0000E4FD 0x814B # 0 +0x0000E4FE 0x984D # 0 +0x0000E5A1 0x6AFB # 0 +0x0000E5A2 0x7F4C # 0 +0x0000E5A3 0x9DAF # 0 +0x0000E5A4 0x9E1A # 0 +0x0000E5A5 0x4E5F # 0 +0x0000E5A6 0x503B # 0 +0x0000E5A7 0x51B6 # 0 +0x0000E5A8 0x591C # 0 +0x0000E5A9 0x60F9 # 0 +0x0000E5AA 0x63F6 # 0 +0x0000E5AB 0x6930 # 0 +0x0000E5AC 0x723A # 0 +0x0000E5AD 0x8036 # 0 +0x0000E5AE 0xF974 # 0 +0x0000E5AF 0x91CE # 0 +0x0000E5B0 0x5F31 # 0 +0x0000E5B1 0xF975 # 0 +0x0000E5B2 0xF976 # 0 +0x0000E5B3 0x7D04 # 0 +0x0000E5B4 0x82E5 # 0 +0x0000E5B5 0x846F # 0 +0x0000E5B6 0x84BB # 0 +0x0000E5B7 0x85E5 # 0 +0x0000E5B8 0x8E8D # 0 +0x0000E5B9 0xF977 # 0 +0x0000E5BA 0x4F6F # 0 +0x0000E5BB 0xF978 # 0 +0x0000E5BC 0xF979 # 0 +0x0000E5BD 0x58E4 # 0 +0x0000E5BE 0x5B43 # 0 +0x0000E5BF 0x6059 # 0 +0x0000E5C0 0x63DA # 0 +0x0000E5C1 0x6518 # 0 +0x0000E5C2 0x656D # 0 +0x0000E5C3 0x6698 # 0 +0x0000E5C4 0xF97A # 0 +0x0000E5C5 0x694A # 0 +0x0000E5C6 0x6A23 # 0 +0x0000E5C7 0x6D0B # 0 +0x0000E5C8 0x7001 # 0 +0x0000E5C9 0x716C # 0 +0x0000E5CA 0x75D2 # 0 +0x0000E5CB 0x760D # 0 +0x0000E5CC 0x79B3 # 0 +0x0000E5CD 0x7A70 # 0 +0x0000E5CE 0xF97B # 0 +0x0000E5CF 0x7F8A # 0 +0x0000E5D0 0xF97C # 0 +0x0000E5D1 0x8944 # 0 +0x0000E5D2 0xF97D # 0 +0x0000E5D3 0x8B93 # 0 +0x0000E5D4 0x91C0 # 0 +0x0000E5D5 0x967D # 0 +0x0000E5D6 0xF97E # 0 +0x0000E5D7 0x990A # 0 +0x0000E5D8 0x5704 # 0 +0x0000E5D9 0x5FA1 # 0 +0x0000E5DA 0x65BC # 0 +0x0000E5DB 0x6F01 # 0 +0x0000E5DC 0x7600 # 0 +0x0000E5DD 0x79A6 # 0 +0x0000E5DE 0x8A9E # 0 +0x0000E5DF 0x99AD # 0 +0x0000E5E0 0x9B5A # 0 +0x0000E5E1 0x9F6C # 0 +0x0000E5E2 0x5104 # 0 +0x0000E5E3 0x61B6 # 0 +0x0000E5E4 0x6291 # 0 +0x0000E5E5 0x6A8D # 0 +0x0000E5E6 0x81C6 # 0 +0x0000E5E7 0x5043 # 0 +0x0000E5E8 0x5830 # 0 +0x0000E5E9 0x5F66 # 0 +0x0000E5EA 0x7109 # 0 +0x0000E5EB 0x8A00 # 0 +0x0000E5EC 0x8AFA # 0 +0x0000E5ED 0x5B7C # 0 +0x0000E5EE 0x8616 # 0 +0x0000E5EF 0x4FFA # 0 +0x0000E5F0 0x513C # 0 +0x0000E5F1 0x56B4 # 0 +0x0000E5F2 0x5944 # 0 +0x0000E5F3 0x63A9 # 0 +0x0000E5F4 0x6DF9 # 0 +0x0000E5F5 0x5DAA # 0 +0x0000E5F6 0x696D # 0 +0x0000E5F7 0x5186 # 0 +0x0000E5F8 0x4E88 # 0 +0x0000E5F9 0x4F59 # 0 +0x0000E5FA 0xF97F # 0 +0x0000E5FB 0xF980 # 0 +0x0000E5FC 0xF981 # 0 +0x0000E5FD 0x5982 # 0 +0x0000E5FE 0xF982 # 0 +0x0000E6A1 0xF983 # 0 +0x0000E6A2 0x6B5F # 0 +0x0000E6A3 0x6C5D # 0 +0x0000E6A4 0xF984 # 0 +0x0000E6A5 0x74B5 # 0 +0x0000E6A6 0x7916 # 0 +0x0000E6A7 0xF985 # 0 +0x0000E6A8 0x8207 # 0 +0x0000E6A9 0x8245 # 0 +0x0000E6AA 0x8339 # 0 +0x0000E6AB 0x8F3F # 0 +0x0000E6AC 0x8F5D # 0 +0x0000E6AD 0xF986 # 0 +0x0000E6AE 0x9918 # 0 +0x0000E6AF 0xF987 # 0 +0x0000E6B0 0xF988 # 0 +0x0000E6B1 0xF989 # 0 +0x0000E6B2 0x4EA6 # 0 +0x0000E6B3 0xF98A # 0 +0x0000E6B4 0x57DF # 0 +0x0000E6B5 0x5F79 # 0 +0x0000E6B6 0x6613 # 0 +0x0000E6B7 0xF98B # 0 +0x0000E6B8 0xF98C # 0 +0x0000E6B9 0x75AB # 0 +0x0000E6BA 0x7E79 # 0 +0x0000E6BB 0x8B6F # 0 +0x0000E6BC 0xF98D # 0 +0x0000E6BD 0x9006 # 0 +0x0000E6BE 0x9A5B # 0 +0x0000E6BF 0x56A5 # 0 +0x0000E6C0 0x5827 # 0 +0x0000E6C1 0x59F8 # 0 +0x0000E6C2 0x5A1F # 0 +0x0000E6C3 0x5BB4 # 0 +0x0000E6C4 0xF98E # 0 +0x0000E6C5 0x5EF6 # 0 +0x0000E6C6 0xF98F # 0 +0x0000E6C7 0xF990 # 0 +0x0000E6C8 0x6350 # 0 +0x0000E6C9 0x633B # 0 +0x0000E6CA 0xF991 # 0 +0x0000E6CB 0x693D # 0 +0x0000E6CC 0x6C87 # 0 +0x0000E6CD 0x6CBF # 0 +0x0000E6CE 0x6D8E # 0 +0x0000E6CF 0x6D93 # 0 +0x0000E6D0 0x6DF5 # 0 +0x0000E6D1 0x6F14 # 0 +0x0000E6D2 0xF992 # 0 +0x0000E6D3 0x70DF # 0 +0x0000E6D4 0x7136 # 0 +0x0000E6D5 0x7159 # 0 +0x0000E6D6 0xF993 # 0 +0x0000E6D7 0x71C3 # 0 +0x0000E6D8 0x71D5 # 0 +0x0000E6D9 0xF994 # 0 +0x0000E6DA 0x784F # 0 +0x0000E6DB 0x786F # 0 +0x0000E6DC 0xF995 # 0 +0x0000E6DD 0x7B75 # 0 +0x0000E6DE 0x7DE3 # 0 +0x0000E6DF 0xF996 # 0 +0x0000E6E0 0x7E2F # 0 +0x0000E6E1 0xF997 # 0 +0x0000E6E2 0x884D # 0 +0x0000E6E3 0x8EDF # 0 +0x0000E6E4 0xF998 # 0 +0x0000E6E5 0xF999 # 0 +0x0000E6E6 0xF99A # 0 +0x0000E6E7 0x925B # 0 +0x0000E6E8 0xF99B # 0 +0x0000E6E9 0x9CF6 # 0 +0x0000E6EA 0xF99C # 0 +0x0000E6EB 0xF99D # 0 +0x0000E6EC 0xF99E # 0 +0x0000E6ED 0x6085 # 0 +0x0000E6EE 0x6D85 # 0 +0x0000E6EF 0xF99F # 0 +0x0000E6F0 0x71B1 # 0 +0x0000E6F1 0xF9A0 # 0 +0x0000E6F2 0xF9A1 # 0 +0x0000E6F3 0x95B1 # 0 +0x0000E6F4 0x53AD # 0 +0x0000E6F5 0xF9A2 # 0 +0x0000E6F6 0xF9A3 # 0 +0x0000E6F7 0xF9A4 # 0 +0x0000E6F8 0x67D3 # 0 +0x0000E6F9 0xF9A5 # 0 +0x0000E6FA 0x708E # 0 +0x0000E6FB 0x7130 # 0 +0x0000E6FC 0x7430 # 0 +0x0000E6FD 0x8276 # 0 +0x0000E6FE 0x82D2 # 0 +0x0000E7A1 0xF9A6 # 0 +0x0000E7A2 0x95BB # 0 +0x0000E7A3 0x9AE5 # 0 +0x0000E7A4 0x9E7D # 0 +0x0000E7A5 0x66C4 # 0 +0x0000E7A6 0xF9A7 # 0 +0x0000E7A7 0x71C1 # 0 +0x0000E7A8 0x8449 # 0 +0x0000E7A9 0xF9A8 # 0 +0x0000E7AA 0xF9A9 # 0 +0x0000E7AB 0x584B # 0 +0x0000E7AC 0xF9AA # 0 +0x0000E7AD 0xF9AB # 0 +0x0000E7AE 0x5DB8 # 0 +0x0000E7AF 0x5F71 # 0 +0x0000E7B0 0xF9AC # 0 +0x0000E7B1 0x6620 # 0 +0x0000E7B2 0x668E # 0 +0x0000E7B3 0x6979 # 0 +0x0000E7B4 0x69AE # 0 +0x0000E7B5 0x6C38 # 0 +0x0000E7B6 0x6CF3 # 0 +0x0000E7B7 0x6E36 # 0 +0x0000E7B8 0x6F41 # 0 +0x0000E7B9 0x6FDA # 0 +0x0000E7BA 0x701B # 0 +0x0000E7BB 0x702F # 0 +0x0000E7BC 0x7150 # 0 +0x0000E7BD 0x71DF # 0 +0x0000E7BE 0x7370 # 0 +0x0000E7BF 0xF9AD # 0 +0x0000E7C0 0x745B # 0 +0x0000E7C1 0xF9AE # 0 +0x0000E7C2 0x74D4 # 0 +0x0000E7C3 0x76C8 # 0 +0x0000E7C4 0x7A4E # 0 +0x0000E7C5 0x7E93 # 0 +0x0000E7C6 0xF9AF # 0 +0x0000E7C7 0xF9B0 # 0 +0x0000E7C8 0x82F1 # 0 +0x0000E7C9 0x8A60 # 0 +0x0000E7CA 0x8FCE # 0 +0x0000E7CB 0xF9B1 # 0 +0x0000E7CC 0x9348 # 0 +0x0000E7CD 0xF9B2 # 0 +0x0000E7CE 0x9719 # 0 +0x0000E7CF 0xF9B3 # 0 +0x0000E7D0 0xF9B4 # 0 +0x0000E7D1 0x4E42 # 0 +0x0000E7D2 0x502A # 0 +0x0000E7D3 0xF9B5 # 0 +0x0000E7D4 0x5208 # 0 +0x0000E7D5 0x53E1 # 0 +0x0000E7D6 0x66F3 # 0 +0x0000E7D7 0x6C6D # 0 +0x0000E7D8 0x6FCA # 0 +0x0000E7D9 0x730A # 0 +0x0000E7DA 0x777F # 0 +0x0000E7DB 0x7A62 # 0 +0x0000E7DC 0x82AE # 0 +0x0000E7DD 0x85DD # 0 +0x0000E7DE 0x8602 # 0 +0x0000E7DF 0xF9B6 # 0 +0x0000E7E0 0x88D4 # 0 +0x0000E7E1 0x8A63 # 0 +0x0000E7E2 0x8B7D # 0 +0x0000E7E3 0x8C6B # 0 +0x0000E7E4 0xF9B7 # 0 +0x0000E7E5 0x92B3 # 0 +0x0000E7E6 0xF9B8 # 0 +0x0000E7E7 0x9713 # 0 +0x0000E7E8 0x9810 # 0 +0x0000E7E9 0x4E94 # 0 +0x0000E7EA 0x4F0D # 0 +0x0000E7EB 0x4FC9 # 0 +0x0000E7EC 0x50B2 # 0 +0x0000E7ED 0x5348 # 0 +0x0000E7EE 0x543E # 0 +0x0000E7EF 0x5433 # 0 +0x0000E7F0 0x55DA # 0 +0x0000E7F1 0x5862 # 0 +0x0000E7F2 0x58BA # 0 +0x0000E7F3 0x5967 # 0 +0x0000E7F4 0x5A1B # 0 +0x0000E7F5 0x5BE4 # 0 +0x0000E7F6 0x609F # 0 +0x0000E7F7 0xF9B9 # 0 +0x0000E7F8 0x61CA # 0 +0x0000E7F9 0x6556 # 0 +0x0000E7FA 0x65FF # 0 +0x0000E7FB 0x6664 # 0 +0x0000E7FC 0x68A7 # 0 +0x0000E7FD 0x6C5A # 0 +0x0000E7FE 0x6FB3 # 0 +0x0000E8A1 0x70CF # 0 +0x0000E8A2 0x71AC # 0 +0x0000E8A3 0x7352 # 0 +0x0000E8A4 0x7B7D # 0 +0x0000E8A5 0x8708 # 0 +0x0000E8A6 0x8AA4 # 0 +0x0000E8A7 0x9C32 # 0 +0x0000E8A8 0x9F07 # 0 +0x0000E8A9 0x5C4B # 0 +0x0000E8AA 0x6C83 # 0 +0x0000E8AB 0x7344 # 0 +0x0000E8AC 0x7389 # 0 +0x0000E8AD 0x923A # 0 +0x0000E8AE 0x6EAB # 0 +0x0000E8AF 0x7465 # 0 +0x0000E8B0 0x761F # 0 +0x0000E8B1 0x7A69 # 0 +0x0000E8B2 0x7E15 # 0 +0x0000E8B3 0x860A # 0 +0x0000E8B4 0x5140 # 0 +0x0000E8B5 0x58C5 # 0 +0x0000E8B6 0x64C1 # 0 +0x0000E8B7 0x74EE # 0 +0x0000E8B8 0x7515 # 0 +0x0000E8B9 0x7670 # 0 +0x0000E8BA 0x7FC1 # 0 +0x0000E8BB 0x9095 # 0 +0x0000E8BC 0x96CD # 0 +0x0000E8BD 0x9954 # 0 +0x0000E8BE 0x6E26 # 0 +0x0000E8BF 0x74E6 # 0 +0x0000E8C0 0x7AA9 # 0 +0x0000E8C1 0x7AAA # 0 +0x0000E8C2 0x81E5 # 0 +0x0000E8C3 0x86D9 # 0 +0x0000E8C4 0x8778 # 0 +0x0000E8C5 0x8A1B # 0 +0x0000E8C6 0x5A49 # 0 +0x0000E8C7 0x5B8C # 0 +0x0000E8C8 0x5B9B # 0 +0x0000E8C9 0x68A1 # 0 +0x0000E8CA 0x6900 # 0 +0x0000E8CB 0x6D63 # 0 +0x0000E8CC 0x73A9 # 0 +0x0000E8CD 0x7413 # 0 +0x0000E8CE 0x742C # 0 +0x0000E8CF 0x7897 # 0 +0x0000E8D0 0x7DE9 # 0 +0x0000E8D1 0x7FEB # 0 +0x0000E8D2 0x8118 # 0 +0x0000E8D3 0x8155 # 0 +0x0000E8D4 0x839E # 0 +0x0000E8D5 0x8C4C # 0 +0x0000E8D6 0x962E # 0 +0x0000E8D7 0x9811 # 0 +0x0000E8D8 0x66F0 # 0 +0x0000E8D9 0x5F80 # 0 +0x0000E8DA 0x65FA # 0 +0x0000E8DB 0x6789 # 0 +0x0000E8DC 0x6C6A # 0 +0x0000E8DD 0x738B # 0 +0x0000E8DE 0x502D # 0 +0x0000E8DF 0x5A03 # 0 +0x0000E8E0 0x6B6A # 0 +0x0000E8E1 0x77EE # 0 +0x0000E8E2 0x5916 # 0 +0x0000E8E3 0x5D6C # 0 +0x0000E8E4 0x5DCD # 0 +0x0000E8E5 0x7325 # 0 +0x0000E8E6 0x754F # 0 +0x0000E8E7 0xF9BA # 0 +0x0000E8E8 0xF9BB # 0 +0x0000E8E9 0x50E5 # 0 +0x0000E8EA 0x51F9 # 0 +0x0000E8EB 0x582F # 0 +0x0000E8EC 0x592D # 0 +0x0000E8ED 0x5996 # 0 +0x0000E8EE 0x59DA # 0 +0x0000E8EF 0x5BE5 # 0 +0x0000E8F0 0xF9BC # 0 +0x0000E8F1 0xF9BD # 0 +0x0000E8F2 0x5DA2 # 0 +0x0000E8F3 0x62D7 # 0 +0x0000E8F4 0x6416 # 0 +0x0000E8F5 0x6493 # 0 +0x0000E8F6 0x64FE # 0 +0x0000E8F7 0xF9BE # 0 +0x0000E8F8 0x66DC # 0 +0x0000E8F9 0xF9BF # 0 +0x0000E8FA 0x6A48 # 0 +0x0000E8FB 0xF9C0 # 0 +0x0000E8FC 0x71FF # 0 +0x0000E8FD 0x7464 # 0 +0x0000E8FE 0xF9C1 # 0 +0x0000E9A1 0x7A88 # 0 +0x0000E9A2 0x7AAF # 0 +0x0000E9A3 0x7E47 # 0 +0x0000E9A4 0x7E5E # 0 +0x0000E9A5 0x8000 # 0 +0x0000E9A6 0x8170 # 0 +0x0000E9A7 0xF9C2 # 0 +0x0000E9A8 0x87EF # 0 +0x0000E9A9 0x8981 # 0 +0x0000E9AA 0x8B20 # 0 +0x0000E9AB 0x9059 # 0 +0x0000E9AC 0xF9C3 # 0 +0x0000E9AD 0x9080 # 0 +0x0000E9AE 0x9952 # 0 +0x0000E9AF 0x617E # 0 +0x0000E9B0 0x6B32 # 0 +0x0000E9B1 0x6D74 # 0 +0x0000E9B2 0x7E1F # 0 +0x0000E9B3 0x8925 # 0 +0x0000E9B4 0x8FB1 # 0 +0x0000E9B5 0x4FD1 # 0 +0x0000E9B6 0x50AD # 0 +0x0000E9B7 0x5197 # 0 +0x0000E9B8 0x52C7 # 0 +0x0000E9B9 0x57C7 # 0 +0x0000E9BA 0x5889 # 0 +0x0000E9BB 0x5BB9 # 0 +0x0000E9BC 0x5EB8 # 0 +0x0000E9BD 0x6142 # 0 +0x0000E9BE 0x6995 # 0 +0x0000E9BF 0x6D8C # 0 +0x0000E9C0 0x6E67 # 0 +0x0000E9C1 0x6EB6 # 0 +0x0000E9C2 0x7194 # 0 +0x0000E9C3 0x7462 # 0 +0x0000E9C4 0x7528 # 0 +0x0000E9C5 0x752C # 0 +0x0000E9C6 0x8073 # 0 +0x0000E9C7 0x8338 # 0 +0x0000E9C8 0x84C9 # 0 +0x0000E9C9 0x8E0A # 0 +0x0000E9CA 0x9394 # 0 +0x0000E9CB 0x93DE # 0 +0x0000E9CC 0xF9C4 # 0 +0x0000E9CD 0x4E8E # 0 +0x0000E9CE 0x4F51 # 0 +0x0000E9CF 0x5076 # 0 +0x0000E9D0 0x512A # 0 +0x0000E9D1 0x53C8 # 0 +0x0000E9D2 0x53CB # 0 +0x0000E9D3 0x53F3 # 0 +0x0000E9D4 0x5B87 # 0 +0x0000E9D5 0x5BD3 # 0 +0x0000E9D6 0x5C24 # 0 +0x0000E9D7 0x611A # 0 +0x0000E9D8 0x6182 # 0 +0x0000E9D9 0x65F4 # 0 +0x0000E9DA 0x725B # 0 +0x0000E9DB 0x7397 # 0 +0x0000E9DC 0x7440 # 0 +0x0000E9DD 0x76C2 # 0 +0x0000E9DE 0x7950 # 0 +0x0000E9DF 0x7991 # 0 +0x0000E9E0 0x79B9 # 0 +0x0000E9E1 0x7D06 # 0 +0x0000E9E2 0x7FBD # 0 +0x0000E9E3 0x828B # 0 +0x0000E9E4 0x85D5 # 0 +0x0000E9E5 0x865E # 0 +0x0000E9E6 0x8FC2 # 0 +0x0000E9E7 0x9047 # 0 +0x0000E9E8 0x90F5 # 0 +0x0000E9E9 0x91EA # 0 +0x0000E9EA 0x9685 # 0 +0x0000E9EB 0x96E8 # 0 +0x0000E9EC 0x96E9 # 0 +0x0000E9ED 0x52D6 # 0 +0x0000E9EE 0x5F67 # 0 +0x0000E9EF 0x65ED # 0 +0x0000E9F0 0x6631 # 0 +0x0000E9F1 0x682F # 0 +0x0000E9F2 0x715C # 0 +0x0000E9F3 0x7A36 # 0 +0x0000E9F4 0x90C1 # 0 +0x0000E9F5 0x980A # 0 +0x0000E9F6 0x4E91 # 0 +0x0000E9F7 0xF9C5 # 0 +0x0000E9F8 0x6A52 # 0 +0x0000E9F9 0x6B9E # 0 +0x0000E9FA 0x6F90 # 0 +0x0000E9FB 0x7189 # 0 +0x0000E9FC 0x8018 # 0 +0x0000E9FD 0x82B8 # 0 +0x0000E9FE 0x8553 # 0 +0x0000EAA1 0x904B # 0 +0x0000EAA2 0x9695 # 0 +0x0000EAA3 0x96F2 # 0 +0x0000EAA4 0x97FB # 0 +0x0000EAA5 0x851A # 0 +0x0000EAA6 0x9B31 # 0 +0x0000EAA7 0x4E90 # 0 +0x0000EAA8 0x718A # 0 +0x0000EAA9 0x96C4 # 0 +0x0000EAAA 0x5143 # 0 +0x0000EAAB 0x539F # 0 +0x0000EAAC 0x54E1 # 0 +0x0000EAAD 0x5713 # 0 +0x0000EAAE 0x5712 # 0 +0x0000EAAF 0x57A3 # 0 +0x0000EAB0 0x5A9B # 0 +0x0000EAB1 0x5AC4 # 0 +0x0000EAB2 0x5BC3 # 0 +0x0000EAB3 0x6028 # 0 +0x0000EAB4 0x613F # 0 +0x0000EAB5 0x63F4 # 0 +0x0000EAB6 0x6C85 # 0 +0x0000EAB7 0x6D39 # 0 +0x0000EAB8 0x6E72 # 0 +0x0000EAB9 0x6E90 # 0 +0x0000EABA 0x7230 # 0 +0x0000EABB 0x733F # 0 +0x0000EABC 0x7457 # 0 +0x0000EABD 0x82D1 # 0 +0x0000EABE 0x8881 # 0 +0x0000EABF 0x8F45 # 0 +0x0000EAC0 0x9060 # 0 +0x0000EAC1 0xF9C6 # 0 +0x0000EAC2 0x9662 # 0 +0x0000EAC3 0x9858 # 0 +0x0000EAC4 0x9D1B # 0 +0x0000EAC5 0x6708 # 0 +0x0000EAC6 0x8D8A # 0 +0x0000EAC7 0x925E # 0 +0x0000EAC8 0x4F4D # 0 +0x0000EAC9 0x5049 # 0 +0x0000EACA 0x50DE # 0 +0x0000EACB 0x5371 # 0 +0x0000EACC 0x570D # 0 +0x0000EACD 0x59D4 # 0 +0x0000EACE 0x5A01 # 0 +0x0000EACF 0x5C09 # 0 +0x0000EAD0 0x6170 # 0 +0x0000EAD1 0x6690 # 0 +0x0000EAD2 0x6E2D # 0 +0x0000EAD3 0x7232 # 0 +0x0000EAD4 0x744B # 0 +0x0000EAD5 0x7DEF # 0 +0x0000EAD6 0x80C3 # 0 +0x0000EAD7 0x840E # 0 +0x0000EAD8 0x8466 # 0 +0x0000EAD9 0x853F # 0 +0x0000EADA 0x875F # 0 +0x0000EADB 0x885B # 0 +0x0000EADC 0x8918 # 0 +0x0000EADD 0x8B02 # 0 +0x0000EADE 0x9055 # 0 +0x0000EADF 0x97CB # 0 +0x0000EAE0 0x9B4F # 0 +0x0000EAE1 0x4E73 # 0 +0x0000EAE2 0x4F91 # 0 +0x0000EAE3 0x5112 # 0 +0x0000EAE4 0x516A # 0 +0x0000EAE5 0xF9C7 # 0 +0x0000EAE6 0x552F # 0 +0x0000EAE7 0x55A9 # 0 +0x0000EAE8 0x5B7A # 0 +0x0000EAE9 0x5BA5 # 0 +0x0000EAEA 0x5E7C # 0 +0x0000EAEB 0x5E7D # 0 +0x0000EAEC 0x5EBE # 0 +0x0000EAED 0x60A0 # 0 +0x0000EAEE 0x60DF # 0 +0x0000EAEF 0x6108 # 0 +0x0000EAF0 0x6109 # 0 +0x0000EAF1 0x63C4 # 0 +0x0000EAF2 0x6538 # 0 +0x0000EAF3 0x6709 # 0 +0x0000EAF4 0xF9C8 # 0 +0x0000EAF5 0x67D4 # 0 +0x0000EAF6 0x67DA # 0 +0x0000EAF7 0xF9C9 # 0 +0x0000EAF8 0x6961 # 0 +0x0000EAF9 0x6962 # 0 +0x0000EAFA 0x6CB9 # 0 +0x0000EAFB 0x6D27 # 0 +0x0000EAFC 0xF9CA # 0 +0x0000EAFD 0x6E38 # 0 +0x0000EAFE 0xF9CB # 0 +0x0000EBA1 0x6FE1 # 0 +0x0000EBA2 0x7336 # 0 +0x0000EBA3 0x7337 # 0 +0x0000EBA4 0xF9CC # 0 +0x0000EBA5 0x745C # 0 +0x0000EBA6 0x7531 # 0 +0x0000EBA7 0xF9CD # 0 +0x0000EBA8 0x7652 # 0 +0x0000EBA9 0xF9CE # 0 +0x0000EBAA 0xF9CF # 0 +0x0000EBAB 0x7DAD # 0 +0x0000EBAC 0x81FE # 0 +0x0000EBAD 0x8438 # 0 +0x0000EBAE 0x88D5 # 0 +0x0000EBAF 0x8A98 # 0 +0x0000EBB0 0x8ADB # 0 +0x0000EBB1 0x8AED # 0 +0x0000EBB2 0x8E30 # 0 +0x0000EBB3 0x8E42 # 0 +0x0000EBB4 0x904A # 0 +0x0000EBB5 0x903E # 0 +0x0000EBB6 0x907A # 0 +0x0000EBB7 0x9149 # 0 +0x0000EBB8 0x91C9 # 0 +0x0000EBB9 0x936E # 0 +0x0000EBBA 0xF9D0 # 0 +0x0000EBBB 0xF9D1 # 0 +0x0000EBBC 0x5809 # 0 +0x0000EBBD 0xF9D2 # 0 +0x0000EBBE 0x6BD3 # 0 +0x0000EBBF 0x8089 # 0 +0x0000EBC0 0x80B2 # 0 +0x0000EBC1 0xF9D3 # 0 +0x0000EBC2 0xF9D4 # 0 +0x0000EBC3 0x5141 # 0 +0x0000EBC4 0x596B # 0 +0x0000EBC5 0x5C39 # 0 +0x0000EBC6 0xF9D5 # 0 +0x0000EBC7 0xF9D6 # 0 +0x0000EBC8 0x6F64 # 0 +0x0000EBC9 0x73A7 # 0 +0x0000EBCA 0x80E4 # 0 +0x0000EBCB 0x8D07 # 0 +0x0000EBCC 0xF9D7 # 0 +0x0000EBCD 0x9217 # 0 +0x0000EBCE 0x958F # 0 +0x0000EBCF 0xF9D8 # 0 +0x0000EBD0 0xF9D9 # 0 +0x0000EBD1 0xF9DA # 0 +0x0000EBD2 0xF9DB # 0 +0x0000EBD3 0x807F # 0 +0x0000EBD4 0x620E # 0 +0x0000EBD5 0x701C # 0 +0x0000EBD6 0x7D68 # 0 +0x0000EBD7 0x878D # 0 +0x0000EBD8 0xF9DC # 0 +0x0000EBD9 0x57A0 # 0 +0x0000EBDA 0x6069 # 0 +0x0000EBDB 0x6147 # 0 +0x0000EBDC 0x6BB7 # 0 +0x0000EBDD 0x8ABE # 0 +0x0000EBDE 0x9280 # 0 +0x0000EBDF 0x96B1 # 0 +0x0000EBE0 0x4E59 # 0 +0x0000EBE1 0x541F # 0 +0x0000EBE2 0x6DEB # 0 +0x0000EBE3 0x852D # 0 +0x0000EBE4 0x9670 # 0 +0x0000EBE5 0x97F3 # 0 +0x0000EBE6 0x98EE # 0 +0x0000EBE7 0x63D6 # 0 +0x0000EBE8 0x6CE3 # 0 +0x0000EBE9 0x9091 # 0 +0x0000EBEA 0x51DD # 0 +0x0000EBEB 0x61C9 # 0 +0x0000EBEC 0x81BA # 0 +0x0000EBED 0x9DF9 # 0 +0x0000EBEE 0x4F9D # 0 +0x0000EBEF 0x501A # 0 +0x0000EBF0 0x5100 # 0 +0x0000EBF1 0x5B9C # 0 +0x0000EBF2 0x610F # 0 +0x0000EBF3 0x61FF # 0 +0x0000EBF4 0x64EC # 0 +0x0000EBF5 0x6905 # 0 +0x0000EBF6 0x6BC5 # 0 +0x0000EBF7 0x7591 # 0 +0x0000EBF8 0x77E3 # 0 +0x0000EBF9 0x7FA9 # 0 +0x0000EBFA 0x8264 # 0 +0x0000EBFB 0x858F # 0 +0x0000EBFC 0x87FB # 0 +0x0000EBFD 0x8863 # 0 +0x0000EBFE 0x8ABC # 0 +0x0000ECA1 0x8B70 # 0 +0x0000ECA2 0x91AB # 0 +0x0000ECA3 0x4E8C # 0 +0x0000ECA4 0x4EE5 # 0 +0x0000ECA5 0x4F0A # 0 +0x0000ECA6 0xF9DD # 0 +0x0000ECA7 0xF9DE # 0 +0x0000ECA8 0x5937 # 0 +0x0000ECA9 0x59E8 # 0 +0x0000ECAA 0xF9DF # 0 +0x0000ECAB 0x5DF2 # 0 +0x0000ECAC 0x5F1B # 0 +0x0000ECAD 0x5F5B # 0 +0x0000ECAE 0x6021 # 0 +0x0000ECAF 0xF9E0 # 0 +0x0000ECB0 0xF9E1 # 0 +0x0000ECB1 0xF9E2 # 0 +0x0000ECB2 0xF9E3 # 0 +0x0000ECB3 0x723E # 0 +0x0000ECB4 0x73E5 # 0 +0x0000ECB5 0xF9E4 # 0 +0x0000ECB6 0x7570 # 0 +0x0000ECB7 0x75CD # 0 +0x0000ECB8 0xF9E5 # 0 +0x0000ECB9 0x79FB # 0 +0x0000ECBA 0xF9E6 # 0 +0x0000ECBB 0x800C # 0 +0x0000ECBC 0x8033 # 0 +0x0000ECBD 0x8084 # 0 +0x0000ECBE 0x82E1 # 0 +0x0000ECBF 0x8351 # 0 +0x0000ECC0 0xF9E7 # 0 +0x0000ECC1 0xF9E8 # 0 +0x0000ECC2 0x8CBD # 0 +0x0000ECC3 0x8CB3 # 0 +0x0000ECC4 0x9087 # 0 +0x0000ECC5 0xF9E9 # 0 +0x0000ECC6 0xF9EA # 0 +0x0000ECC7 0x98F4 # 0 +0x0000ECC8 0x990C # 0 +0x0000ECC9 0xF9EB # 0 +0x0000ECCA 0xF9EC # 0 +0x0000ECCB 0x7037 # 0 +0x0000ECCC 0x76CA # 0 +0x0000ECCD 0x7FCA # 0 +0x0000ECCE 0x7FCC # 0 +0x0000ECCF 0x7FFC # 0 +0x0000ECD0 0x8B1A # 0 +0x0000ECD1 0x4EBA # 0 +0x0000ECD2 0x4EC1 # 0 +0x0000ECD3 0x5203 # 0 +0x0000ECD4 0x5370 # 0 +0x0000ECD5 0xF9ED # 0 +0x0000ECD6 0x54BD # 0 +0x0000ECD7 0x56E0 # 0 +0x0000ECD8 0x59FB # 0 +0x0000ECD9 0x5BC5 # 0 +0x0000ECDA 0x5F15 # 0 +0x0000ECDB 0x5FCD # 0 +0x0000ECDC 0x6E6E # 0 +0x0000ECDD 0xF9EE # 0 +0x0000ECDE 0xF9EF # 0 +0x0000ECDF 0x7D6A # 0 +0x0000ECE0 0x8335 # 0 +0x0000ECE1 0xF9F0 # 0 +0x0000ECE2 0x8693 # 0 +0x0000ECE3 0x8A8D # 0 +0x0000ECE4 0xF9F1 # 0 +0x0000ECE5 0x976D # 0 +0x0000ECE6 0x9777 # 0 +0x0000ECE7 0xF9F2 # 0 +0x0000ECE8 0xF9F3 # 0 +0x0000ECE9 0x4E00 # 0 +0x0000ECEA 0x4F5A # 0 +0x0000ECEB 0x4F7E # 0 +0x0000ECEC 0x58F9 # 0 +0x0000ECED 0x65E5 # 0 +0x0000ECEE 0x6EA2 # 0 +0x0000ECEF 0x9038 # 0 +0x0000ECF0 0x93B0 # 0 +0x0000ECF1 0x99B9 # 0 +0x0000ECF2 0x4EFB # 0 +0x0000ECF3 0x58EC # 0 +0x0000ECF4 0x598A # 0 +0x0000ECF5 0x59D9 # 0 +0x0000ECF6 0x6041 # 0 +0x0000ECF7 0xF9F4 # 0 +0x0000ECF8 0xF9F5 # 0 +0x0000ECF9 0x7A14 # 0 +0x0000ECFA 0xF9F6 # 0 +0x0000ECFB 0x834F # 0 +0x0000ECFC 0x8CC3 # 0 +0x0000ECFD 0x5165 # 0 +0x0000ECFE 0x5344 # 0 +0x0000EDA1 0xF9F7 # 0 +0x0000EDA2 0xF9F8 # 0 +0x0000EDA3 0xF9F9 # 0 +0x0000EDA4 0x4ECD # 0 +0x0000EDA5 0x5269 # 0 +0x0000EDA6 0x5B55 # 0 +0x0000EDA7 0x82BF # 0 +0x0000EDA8 0x4ED4 # 0 +0x0000EDA9 0x523A # 0 +0x0000EDAA 0x54A8 # 0 +0x0000EDAB 0x59C9 # 0 +0x0000EDAC 0x59FF # 0 +0x0000EDAD 0x5B50 # 0 +0x0000EDAE 0x5B57 # 0 +0x0000EDAF 0x5B5C # 0 +0x0000EDB0 0x6063 # 0 +0x0000EDB1 0x6148 # 0 +0x0000EDB2 0x6ECB # 0 +0x0000EDB3 0x7099 # 0 +0x0000EDB4 0x716E # 0 +0x0000EDB5 0x7386 # 0 +0x0000EDB6 0x74F7 # 0 +0x0000EDB7 0x75B5 # 0 +0x0000EDB8 0x78C1 # 0 +0x0000EDB9 0x7D2B # 0 +0x0000EDBA 0x8005 # 0 +0x0000EDBB 0x81EA # 0 +0x0000EDBC 0x8328 # 0 +0x0000EDBD 0x8517 # 0 +0x0000EDBE 0x85C9 # 0 +0x0000EDBF 0x8AEE # 0 +0x0000EDC0 0x8CC7 # 0 +0x0000EDC1 0x96CC # 0 +0x0000EDC2 0x4F5C # 0 +0x0000EDC3 0x52FA # 0 +0x0000EDC4 0x56BC # 0 +0x0000EDC5 0x65AB # 0 +0x0000EDC6 0x6628 # 0 +0x0000EDC7 0x707C # 0 +0x0000EDC8 0x70B8 # 0 +0x0000EDC9 0x7235 # 0 +0x0000EDCA 0x7DBD # 0 +0x0000EDCB 0x828D # 0 +0x0000EDCC 0x914C # 0 +0x0000EDCD 0x96C0 # 0 +0x0000EDCE 0x9D72 # 0 +0x0000EDCF 0x5B71 # 0 +0x0000EDD0 0x68E7 # 0 +0x0000EDD1 0x6B98 # 0 +0x0000EDD2 0x6F7A # 0 +0x0000EDD3 0x76DE # 0 +0x0000EDD4 0x5C91 # 0 +0x0000EDD5 0x66AB # 0 +0x0000EDD6 0x6F5B # 0 +0x0000EDD7 0x7BB4 # 0 +0x0000EDD8 0x7C2A # 0 +0x0000EDD9 0x8836 # 0 +0x0000EDDA 0x96DC # 0 +0x0000EDDB 0x4E08 # 0 +0x0000EDDC 0x4ED7 # 0 +0x0000EDDD 0x5320 # 0 +0x0000EDDE 0x5834 # 0 +0x0000EDDF 0x58BB # 0 +0x0000EDE0 0x58EF # 0 +0x0000EDE1 0x596C # 0 +0x0000EDE2 0x5C07 # 0 +0x0000EDE3 0x5E33 # 0 +0x0000EDE4 0x5E84 # 0 +0x0000EDE5 0x5F35 # 0 +0x0000EDE6 0x638C # 0 +0x0000EDE7 0x66B2 # 0 +0x0000EDE8 0x6756 # 0 +0x0000EDE9 0x6A1F # 0 +0x0000EDEA 0x6AA3 # 0 +0x0000EDEB 0x6B0C # 0 +0x0000EDEC 0x6F3F # 0 +0x0000EDED 0x7246 # 0 +0x0000EDEE 0xF9FA # 0 +0x0000EDEF 0x7350 # 0 +0x0000EDF0 0x748B # 0 +0x0000EDF1 0x7AE0 # 0 +0x0000EDF2 0x7CA7 # 0 +0x0000EDF3 0x8178 # 0 +0x0000EDF4 0x81DF # 0 +0x0000EDF5 0x81E7 # 0 +0x0000EDF6 0x838A # 0 +0x0000EDF7 0x846C # 0 +0x0000EDF8 0x8523 # 0 +0x0000EDF9 0x8594 # 0 +0x0000EDFA 0x85CF # 0 +0x0000EDFB 0x88DD # 0 +0x0000EDFC 0x8D13 # 0 +0x0000EDFD 0x91AC # 0 +0x0000EDFE 0x9577 # 0 +0x0000EEA1 0x969C # 0 +0x0000EEA2 0x518D # 0 +0x0000EEA3 0x54C9 # 0 +0x0000EEA4 0x5728 # 0 +0x0000EEA5 0x5BB0 # 0 +0x0000EEA6 0x624D # 0 +0x0000EEA7 0x6750 # 0 +0x0000EEA8 0x683D # 0 +0x0000EEA9 0x6893 # 0 +0x0000EEAA 0x6E3D # 0 +0x0000EEAB 0x6ED3 # 0 +0x0000EEAC 0x707D # 0 +0x0000EEAD 0x7E21 # 0 +0x0000EEAE 0x88C1 # 0 +0x0000EEAF 0x8CA1 # 0 +0x0000EEB0 0x8F09 # 0 +0x0000EEB1 0x9F4B # 0 +0x0000EEB2 0x9F4E # 0 +0x0000EEB3 0x722D # 0 +0x0000EEB4 0x7B8F # 0 +0x0000EEB5 0x8ACD # 0 +0x0000EEB6 0x931A # 0 +0x0000EEB7 0x4F47 # 0 +0x0000EEB8 0x4F4E # 0 +0x0000EEB9 0x5132 # 0 +0x0000EEBA 0x5480 # 0 +0x0000EEBB 0x59D0 # 0 +0x0000EEBC 0x5E95 # 0 +0x0000EEBD 0x62B5 # 0 +0x0000EEBE 0x6775 # 0 +0x0000EEBF 0x696E # 0 +0x0000EEC0 0x6A17 # 0 +0x0000EEC1 0x6CAE # 0 +0x0000EEC2 0x6E1A # 0 +0x0000EEC3 0x72D9 # 0 +0x0000EEC4 0x732A # 0 +0x0000EEC5 0x75BD # 0 +0x0000EEC6 0x7BB8 # 0 +0x0000EEC7 0x7D35 # 0 +0x0000EEC8 0x82E7 # 0 +0x0000EEC9 0x83F9 # 0 +0x0000EECA 0x8457 # 0 +0x0000EECB 0x85F7 # 0 +0x0000EECC 0x8A5B # 0 +0x0000EECD 0x8CAF # 0 +0x0000EECE 0x8E87 # 0 +0x0000EECF 0x9019 # 0 +0x0000EED0 0x90B8 # 0 +0x0000EED1 0x96CE # 0 +0x0000EED2 0x9F5F # 0 +0x0000EED3 0x52E3 # 0 +0x0000EED4 0x540A # 0 +0x0000EED5 0x5AE1 # 0 +0x0000EED6 0x5BC2 # 0 +0x0000EED7 0x6458 # 0 +0x0000EED8 0x6575 # 0 +0x0000EED9 0x6EF4 # 0 +0x0000EEDA 0x72C4 # 0 +0x0000EEDB 0xF9FB # 0 +0x0000EEDC 0x7684 # 0 +0x0000EEDD 0x7A4D # 0 +0x0000EEDE 0x7B1B # 0 +0x0000EEDF 0x7C4D # 0 +0x0000EEE0 0x7E3E # 0 +0x0000EEE1 0x7FDF # 0 +0x0000EEE2 0x837B # 0 +0x0000EEE3 0x8B2B # 0 +0x0000EEE4 0x8CCA # 0 +0x0000EEE5 0x8D64 # 0 +0x0000EEE6 0x8DE1 # 0 +0x0000EEE7 0x8E5F # 0 +0x0000EEE8 0x8FEA # 0 +0x0000EEE9 0x8FF9 # 0 +0x0000EEEA 0x9069 # 0 +0x0000EEEB 0x93D1 # 0 +0x0000EEEC 0x4F43 # 0 +0x0000EEED 0x4F7A # 0 +0x0000EEEE 0x50B3 # 0 +0x0000EEEF 0x5168 # 0 +0x0000EEF0 0x5178 # 0 +0x0000EEF1 0x524D # 0 +0x0000EEF2 0x526A # 0 +0x0000EEF3 0x5861 # 0 +0x0000EEF4 0x587C # 0 +0x0000EEF5 0x5960 # 0 +0x0000EEF6 0x5C08 # 0 +0x0000EEF7 0x5C55 # 0 +0x0000EEF8 0x5EDB # 0 +0x0000EEF9 0x609B # 0 +0x0000EEFA 0x6230 # 0 +0x0000EEFB 0x6813 # 0 +0x0000EEFC 0x6BBF # 0 +0x0000EEFD 0x6C08 # 0 +0x0000EEFE 0x6FB1 # 0 +0x0000EFA1 0x714E # 0 +0x0000EFA2 0x7420 # 0 +0x0000EFA3 0x7530 # 0 +0x0000EFA4 0x7538 # 0 +0x0000EFA5 0x7551 # 0 +0x0000EFA6 0x7672 # 0 +0x0000EFA7 0x7B4C # 0 +0x0000EFA8 0x7B8B # 0 +0x0000EFA9 0x7BAD # 0 +0x0000EFAA 0x7BC6 # 0 +0x0000EFAB 0x7E8F # 0 +0x0000EFAC 0x8A6E # 0 +0x0000EFAD 0x8F3E # 0 +0x0000EFAE 0x8F49 # 0 +0x0000EFAF 0x923F # 0 +0x0000EFB0 0x9293 # 0 +0x0000EFB1 0x9322 # 0 +0x0000EFB2 0x942B # 0 +0x0000EFB3 0x96FB # 0 +0x0000EFB4 0x985A # 0 +0x0000EFB5 0x986B # 0 +0x0000EFB6 0x991E # 0 +0x0000EFB7 0x5207 # 0 +0x0000EFB8 0x622A # 0 +0x0000EFB9 0x6298 # 0 +0x0000EFBA 0x6D59 # 0 +0x0000EFBB 0x7664 # 0 +0x0000EFBC 0x7ACA # 0 +0x0000EFBD 0x7BC0 # 0 +0x0000EFBE 0x7D76 # 0 +0x0000EFBF 0x5360 # 0 +0x0000EFC0 0x5CBE # 0 +0x0000EFC1 0x5E97 # 0 +0x0000EFC2 0x6F38 # 0 +0x0000EFC3 0x70B9 # 0 +0x0000EFC4 0x7C98 # 0 +0x0000EFC5 0x9711 # 0 +0x0000EFC6 0x9B8E # 0 +0x0000EFC7 0x9EDE # 0 +0x0000EFC8 0x63A5 # 0 +0x0000EFC9 0x647A # 0 +0x0000EFCA 0x8776 # 0 +0x0000EFCB 0x4E01 # 0 +0x0000EFCC 0x4E95 # 0 +0x0000EFCD 0x4EAD # 0 +0x0000EFCE 0x505C # 0 +0x0000EFCF 0x5075 # 0 +0x0000EFD0 0x5448 # 0 +0x0000EFD1 0x59C3 # 0 +0x0000EFD2 0x5B9A # 0 +0x0000EFD3 0x5E40 # 0 +0x0000EFD4 0x5EAD # 0 +0x0000EFD5 0x5EF7 # 0 +0x0000EFD6 0x5F81 # 0 +0x0000EFD7 0x60C5 # 0 +0x0000EFD8 0x633A # 0 +0x0000EFD9 0x653F # 0 +0x0000EFDA 0x6574 # 0 +0x0000EFDB 0x65CC # 0 +0x0000EFDC 0x6676 # 0 +0x0000EFDD 0x6678 # 0 +0x0000EFDE 0x67FE # 0 +0x0000EFDF 0x6968 # 0 +0x0000EFE0 0x6A89 # 0 +0x0000EFE1 0x6B63 # 0 +0x0000EFE2 0x6C40 # 0 +0x0000EFE3 0x6DC0 # 0 +0x0000EFE4 0x6DE8 # 0 +0x0000EFE5 0x6E1F # 0 +0x0000EFE6 0x6E5E # 0 +0x0000EFE7 0x701E # 0 +0x0000EFE8 0x70A1 # 0 +0x0000EFE9 0x738E # 0 +0x0000EFEA 0x73FD # 0 +0x0000EFEB 0x753A # 0 +0x0000EFEC 0x775B # 0 +0x0000EFED 0x7887 # 0 +0x0000EFEE 0x798E # 0 +0x0000EFEF 0x7A0B # 0 +0x0000EFF0 0x7A7D # 0 +0x0000EFF1 0x7CBE # 0 +0x0000EFF2 0x7D8E # 0 +0x0000EFF3 0x8247 # 0 +0x0000EFF4 0x8A02 # 0 +0x0000EFF5 0x8AEA # 0 +0x0000EFF6 0x8C9E # 0 +0x0000EFF7 0x912D # 0 +0x0000EFF8 0x914A # 0 +0x0000EFF9 0x91D8 # 0 +0x0000EFFA 0x9266 # 0 +0x0000EFFB 0x92CC # 0 +0x0000EFFC 0x9320 # 0 +0x0000EFFD 0x9706 # 0 +0x0000EFFE 0x9756 # 0 +0x0000F0A1 0x975C # 0 +0x0000F0A2 0x9802 # 0 +0x0000F0A3 0x9F0E # 0 +0x0000F0A4 0x5236 # 0 +0x0000F0A5 0x5291 # 0 +0x0000F0A6 0x557C # 0 +0x0000F0A7 0x5824 # 0 +0x0000F0A8 0x5E1D # 0 +0x0000F0A9 0x5F1F # 0 +0x0000F0AA 0x608C # 0 +0x0000F0AB 0x63D0 # 0 +0x0000F0AC 0x68AF # 0 +0x0000F0AD 0x6FDF # 0 +0x0000F0AE 0x796D # 0 +0x0000F0AF 0x7B2C # 0 +0x0000F0B0 0x81CD # 0 +0x0000F0B1 0x85BA # 0 +0x0000F0B2 0x88FD # 0 +0x0000F0B3 0x8AF8 # 0 +0x0000F0B4 0x8E44 # 0 +0x0000F0B5 0x918D # 0 +0x0000F0B6 0x9664 # 0 +0x0000F0B7 0x969B # 0 +0x0000F0B8 0x973D # 0 +0x0000F0B9 0x984C # 0 +0x0000F0BA 0x9F4A # 0 +0x0000F0BB 0x4FCE # 0 +0x0000F0BC 0x5146 # 0 +0x0000F0BD 0x51CB # 0 +0x0000F0BE 0x52A9 # 0 +0x0000F0BF 0x5632 # 0 +0x0000F0C0 0x5F14 # 0 +0x0000F0C1 0x5F6B # 0 +0x0000F0C2 0x63AA # 0 +0x0000F0C3 0x64CD # 0 +0x0000F0C4 0x65E9 # 0 +0x0000F0C5 0x6641 # 0 +0x0000F0C6 0x66FA # 0 +0x0000F0C7 0x66F9 # 0 +0x0000F0C8 0x671D # 0 +0x0000F0C9 0x689D # 0 +0x0000F0CA 0x68D7 # 0 +0x0000F0CB 0x69FD # 0 +0x0000F0CC 0x6F15 # 0 +0x0000F0CD 0x6F6E # 0 +0x0000F0CE 0x7167 # 0 +0x0000F0CF 0x71E5 # 0 +0x0000F0D0 0x722A # 0 +0x0000F0D1 0x74AA # 0 +0x0000F0D2 0x773A # 0 +0x0000F0D3 0x7956 # 0 +0x0000F0D4 0x795A # 0 +0x0000F0D5 0x79DF # 0 +0x0000F0D6 0x7A20 # 0 +0x0000F0D7 0x7A95 # 0 +0x0000F0D8 0x7C97 # 0 +0x0000F0D9 0x7CDF # 0 +0x0000F0DA 0x7D44 # 0 +0x0000F0DB 0x7E70 # 0 +0x0000F0DC 0x8087 # 0 +0x0000F0DD 0x85FB # 0 +0x0000F0DE 0x86A4 # 0 +0x0000F0DF 0x8A54 # 0 +0x0000F0E0 0x8ABF # 0 +0x0000F0E1 0x8D99 # 0 +0x0000F0E2 0x8E81 # 0 +0x0000F0E3 0x9020 # 0 +0x0000F0E4 0x906D # 0 +0x0000F0E5 0x91E3 # 0 +0x0000F0E6 0x963B # 0 +0x0000F0E7 0x96D5 # 0 +0x0000F0E8 0x9CE5 # 0 +0x0000F0E9 0x65CF # 0 +0x0000F0EA 0x7C07 # 0 +0x0000F0EB 0x8DB3 # 0 +0x0000F0EC 0x93C3 # 0 +0x0000F0ED 0x5B58 # 0 +0x0000F0EE 0x5C0A # 0 +0x0000F0EF 0x5352 # 0 +0x0000F0F0 0x62D9 # 0 +0x0000F0F1 0x731D # 0 +0x0000F0F2 0x5027 # 0 +0x0000F0F3 0x5B97 # 0 +0x0000F0F4 0x5F9E # 0 +0x0000F0F5 0x60B0 # 0 +0x0000F0F6 0x616B # 0 +0x0000F0F7 0x68D5 # 0 +0x0000F0F8 0x6DD9 # 0 +0x0000F0F9 0x742E # 0 +0x0000F0FA 0x7A2E # 0 +0x0000F0FB 0x7D42 # 0 +0x0000F0FC 0x7D9C # 0 +0x0000F0FD 0x7E31 # 0 +0x0000F0FE 0x816B # 0 +0x0000F1A1 0x8E2A # 0 +0x0000F1A2 0x8E35 # 0 +0x0000F1A3 0x937E # 0 +0x0000F1A4 0x9418 # 0 +0x0000F1A5 0x4F50 # 0 +0x0000F1A6 0x5750 # 0 +0x0000F1A7 0x5DE6 # 0 +0x0000F1A8 0x5EA7 # 0 +0x0000F1A9 0x632B # 0 +0x0000F1AA 0x7F6A # 0 +0x0000F1AB 0x4E3B # 0 +0x0000F1AC 0x4F4F # 0 +0x0000F1AD 0x4F8F # 0 +0x0000F1AE 0x505A # 0 +0x0000F1AF 0x59DD # 0 +0x0000F1B0 0x80C4 # 0 +0x0000F1B1 0x546A # 0 +0x0000F1B2 0x5468 # 0 +0x0000F1B3 0x55FE # 0 +0x0000F1B4 0x594F # 0 +0x0000F1B5 0x5B99 # 0 +0x0000F1B6 0x5DDE # 0 +0x0000F1B7 0x5EDA # 0 +0x0000F1B8 0x665D # 0 +0x0000F1B9 0x6731 # 0 +0x0000F1BA 0x67F1 # 0 +0x0000F1BB 0x682A # 0 +0x0000F1BC 0x6CE8 # 0 +0x0000F1BD 0x6D32 # 0 +0x0000F1BE 0x6E4A # 0 +0x0000F1BF 0x6F8D # 0 +0x0000F1C0 0x70B7 # 0 +0x0000F1C1 0x73E0 # 0 +0x0000F1C2 0x7587 # 0 +0x0000F1C3 0x7C4C # 0 +0x0000F1C4 0x7D02 # 0 +0x0000F1C5 0x7D2C # 0 +0x0000F1C6 0x7DA2 # 0 +0x0000F1C7 0x821F # 0 +0x0000F1C8 0x86DB # 0 +0x0000F1C9 0x8A3B # 0 +0x0000F1CA 0x8A85 # 0 +0x0000F1CB 0x8D70 # 0 +0x0000F1CC 0x8E8A # 0 +0x0000F1CD 0x8F33 # 0 +0x0000F1CE 0x9031 # 0 +0x0000F1CF 0x914E # 0 +0x0000F1D0 0x9152 # 0 +0x0000F1D1 0x9444 # 0 +0x0000F1D2 0x99D0 # 0 +0x0000F1D3 0x7AF9 # 0 +0x0000F1D4 0x7CA5 # 0 +0x0000F1D5 0x4FCA # 0 +0x0000F1D6 0x5101 # 0 +0x0000F1D7 0x51C6 # 0 +0x0000F1D8 0x57C8 # 0 +0x0000F1D9 0x5BEF # 0 +0x0000F1DA 0x5CFB # 0 +0x0000F1DB 0x6659 # 0 +0x0000F1DC 0x6A3D # 0 +0x0000F1DD 0x6D5A # 0 +0x0000F1DE 0x6E96 # 0 +0x0000F1DF 0x6FEC # 0 +0x0000F1E0 0x710C # 0 +0x0000F1E1 0x756F # 0 +0x0000F1E2 0x7AE3 # 0 +0x0000F1E3 0x8822 # 0 +0x0000F1E4 0x9021 # 0 +0x0000F1E5 0x9075 # 0 +0x0000F1E6 0x96CB # 0 +0x0000F1E7 0x99FF # 0 +0x0000F1E8 0x8301 # 0 +0x0000F1E9 0x4E2D # 0 +0x0000F1EA 0x4EF2 # 0 +0x0000F1EB 0x8846 # 0 +0x0000F1EC 0x91CD # 0 +0x0000F1ED 0x537D # 0 +0x0000F1EE 0x6ADB # 0 +0x0000F1EF 0x696B # 0 +0x0000F1F0 0x6C41 # 0 +0x0000F1F1 0x847A # 0 +0x0000F1F2 0x589E # 0 +0x0000F1F3 0x618E # 0 +0x0000F1F4 0x66FE # 0 +0x0000F1F5 0x62EF # 0 +0x0000F1F6 0x70DD # 0 +0x0000F1F7 0x7511 # 0 +0x0000F1F8 0x75C7 # 0 +0x0000F1F9 0x7E52 # 0 +0x0000F1FA 0x84B8 # 0 +0x0000F1FB 0x8B49 # 0 +0x0000F1FC 0x8D08 # 0 +0x0000F1FD 0x4E4B # 0 +0x0000F1FE 0x53EA # 0 +0x0000F2A1 0x54AB # 0 +0x0000F2A2 0x5730 # 0 +0x0000F2A3 0x5740 # 0 +0x0000F2A4 0x5FD7 # 0 +0x0000F2A5 0x6301 # 0 +0x0000F2A6 0x6307 # 0 +0x0000F2A7 0x646F # 0 +0x0000F2A8 0x652F # 0 +0x0000F2A9 0x65E8 # 0 +0x0000F2AA 0x667A # 0 +0x0000F2AB 0x679D # 0 +0x0000F2AC 0x67B3 # 0 +0x0000F2AD 0x6B62 # 0 +0x0000F2AE 0x6C60 # 0 +0x0000F2AF 0x6C9A # 0 +0x0000F2B0 0x6F2C # 0 +0x0000F2B1 0x77E5 # 0 +0x0000F2B2 0x7825 # 0 +0x0000F2B3 0x7949 # 0 +0x0000F2B4 0x7957 # 0 +0x0000F2B5 0x7D19 # 0 +0x0000F2B6 0x80A2 # 0 +0x0000F2B7 0x8102 # 0 +0x0000F2B8 0x81F3 # 0 +0x0000F2B9 0x829D # 0 +0x0000F2BA 0x82B7 # 0 +0x0000F2BB 0x8718 # 0 +0x0000F2BC 0x8A8C # 0 +0x0000F2BD 0xF9FC # 0 +0x0000F2BE 0x8D04 # 0 +0x0000F2BF 0x8DBE # 0 +0x0000F2C0 0x9072 # 0 +0x0000F2C1 0x76F4 # 0 +0x0000F2C2 0x7A19 # 0 +0x0000F2C3 0x7A37 # 0 +0x0000F2C4 0x7E54 # 0 +0x0000F2C5 0x8077 # 0 +0x0000F2C6 0x5507 # 0 +0x0000F2C7 0x55D4 # 0 +0x0000F2C8 0x5875 # 0 +0x0000F2C9 0x632F # 0 +0x0000F2CA 0x6422 # 0 +0x0000F2CB 0x6649 # 0 +0x0000F2CC 0x664B # 0 +0x0000F2CD 0x686D # 0 +0x0000F2CE 0x699B # 0 +0x0000F2CF 0x6B84 # 0 +0x0000F2D0 0x6D25 # 0 +0x0000F2D1 0x6EB1 # 0 +0x0000F2D2 0x73CD # 0 +0x0000F2D3 0x7468 # 0 +0x0000F2D4 0x74A1 # 0 +0x0000F2D5 0x755B # 0 +0x0000F2D6 0x75B9 # 0 +0x0000F2D7 0x76E1 # 0 +0x0000F2D8 0x771E # 0 +0x0000F2D9 0x778B # 0 +0x0000F2DA 0x79E6 # 0 +0x0000F2DB 0x7E09 # 0 +0x0000F2DC 0x7E1D # 0 +0x0000F2DD 0x81FB # 0 +0x0000F2DE 0x852F # 0 +0x0000F2DF 0x8897 # 0 +0x0000F2E0 0x8A3A # 0 +0x0000F2E1 0x8CD1 # 0 +0x0000F2E2 0x8EEB # 0 +0x0000F2E3 0x8FB0 # 0 +0x0000F2E4 0x9032 # 0 +0x0000F2E5 0x93AD # 0 +0x0000F2E6 0x9663 # 0 +0x0000F2E7 0x9673 # 0 +0x0000F2E8 0x9707 # 0 +0x0000F2E9 0x4F84 # 0 +0x0000F2EA 0x53F1 # 0 +0x0000F2EB 0x59EA # 0 +0x0000F2EC 0x5AC9 # 0 +0x0000F2ED 0x5E19 # 0 +0x0000F2EE 0x684E # 0 +0x0000F2EF 0x74C6 # 0 +0x0000F2F0 0x75BE # 0 +0x0000F2F1 0x79E9 # 0 +0x0000F2F2 0x7A92 # 0 +0x0000F2F3 0x81A3 # 0 +0x0000F2F4 0x86ED # 0 +0x0000F2F5 0x8CEA # 0 +0x0000F2F6 0x8DCC # 0 +0x0000F2F7 0x8FED # 0 +0x0000F2F8 0x659F # 0 +0x0000F2F9 0x6715 # 0 +0x0000F2FA 0xF9FD # 0 +0x0000F2FB 0x57F7 # 0 +0x0000F2FC 0x6F57 # 0 +0x0000F2FD 0x7DDD # 0 +0x0000F2FE 0x8F2F # 0 +0x0000F3A1 0x93F6 # 0 +0x0000F3A2 0x96C6 # 0 +0x0000F3A3 0x5FB5 # 0 +0x0000F3A4 0x61F2 # 0 +0x0000F3A5 0x6F84 # 0 +0x0000F3A6 0x4E14 # 0 +0x0000F3A7 0x4F98 # 0 +0x0000F3A8 0x501F # 0 +0x0000F3A9 0x53C9 # 0 +0x0000F3AA 0x55DF # 0 +0x0000F3AB 0x5D6F # 0 +0x0000F3AC 0x5DEE # 0 +0x0000F3AD 0x6B21 # 0 +0x0000F3AE 0x6B64 # 0 +0x0000F3AF 0x78CB # 0 +0x0000F3B0 0x7B9A # 0 +0x0000F3B1 0xF9FE # 0 +0x0000F3B2 0x8E49 # 0 +0x0000F3B3 0x8ECA # 0 +0x0000F3B4 0x906E # 0 +0x0000F3B5 0x6349 # 0 +0x0000F3B6 0x643E # 0 +0x0000F3B7 0x7740 # 0 +0x0000F3B8 0x7A84 # 0 +0x0000F3B9 0x932F # 0 +0x0000F3BA 0x947F # 0 +0x0000F3BB 0x9F6A # 0 +0x0000F3BC 0x64B0 # 0 +0x0000F3BD 0x6FAF # 0 +0x0000F3BE 0x71E6 # 0 +0x0000F3BF 0x74A8 # 0 +0x0000F3C0 0x74DA # 0 +0x0000F3C1 0x7AC4 # 0 +0x0000F3C2 0x7C12 # 0 +0x0000F3C3 0x7E82 # 0 +0x0000F3C4 0x7CB2 # 0 +0x0000F3C5 0x7E98 # 0 +0x0000F3C6 0x8B9A # 0 +0x0000F3C7 0x8D0A # 0 +0x0000F3C8 0x947D # 0 +0x0000F3C9 0x9910 # 0 +0x0000F3CA 0x994C # 0 +0x0000F3CB 0x5239 # 0 +0x0000F3CC 0x5BDF # 0 +0x0000F3CD 0x64E6 # 0 +0x0000F3CE 0x672D # 0 +0x0000F3CF 0x7D2E # 0 +0x0000F3D0 0x50ED # 0 +0x0000F3D1 0x53C3 # 0 +0x0000F3D2 0x5879 # 0 +0x0000F3D3 0x6158 # 0 +0x0000F3D4 0x6159 # 0 +0x0000F3D5 0x61FA # 0 +0x0000F3D6 0x65AC # 0 +0x0000F3D7 0x7AD9 # 0 +0x0000F3D8 0x8B92 # 0 +0x0000F3D9 0x8B96 # 0 +0x0000F3DA 0x5009 # 0 +0x0000F3DB 0x5021 # 0 +0x0000F3DC 0x5275 # 0 +0x0000F3DD 0x5531 # 0 +0x0000F3DE 0x5A3C # 0 +0x0000F3DF 0x5EE0 # 0 +0x0000F3E0 0x5F70 # 0 +0x0000F3E1 0x6134 # 0 +0x0000F3E2 0x655E # 0 +0x0000F3E3 0x660C # 0 +0x0000F3E4 0x6636 # 0 +0x0000F3E5 0x66A2 # 0 +0x0000F3E6 0x69CD # 0 +0x0000F3E7 0x6EC4 # 0 +0x0000F3E8 0x6F32 # 0 +0x0000F3E9 0x7316 # 0 +0x0000F3EA 0x7621 # 0 +0x0000F3EB 0x7A93 # 0 +0x0000F3EC 0x8139 # 0 +0x0000F3ED 0x8259 # 0 +0x0000F3EE 0x83D6 # 0 +0x0000F3EF 0x84BC # 0 +0x0000F3F0 0x50B5 # 0 +0x0000F3F1 0x57F0 # 0 +0x0000F3F2 0x5BC0 # 0 +0x0000F3F3 0x5BE8 # 0 +0x0000F3F4 0x5F69 # 0 +0x0000F3F5 0x63A1 # 0 +0x0000F3F6 0x7826 # 0 +0x0000F3F7 0x7DB5 # 0 +0x0000F3F8 0x83DC # 0 +0x0000F3F9 0x8521 # 0 +0x0000F3FA 0x91C7 # 0 +0x0000F3FB 0x91F5 # 0 +0x0000F3FC 0x518A # 0 +0x0000F3FD 0x67F5 # 0 +0x0000F3FE 0x7B56 # 0 +0x0000F4A1 0x8CAC # 0 +0x0000F4A2 0x51C4 # 0 +0x0000F4A3 0x59BB # 0 +0x0000F4A4 0x60BD # 0 +0x0000F4A5 0x8655 # 0 +0x0000F4A6 0x501C # 0 +0x0000F4A7 0xF9FF # 0 +0x0000F4A8 0x5254 # 0 +0x0000F4A9 0x5C3A # 0 +0x0000F4AA 0x617D # 0 +0x0000F4AB 0x621A # 0 +0x0000F4AC 0x62D3 # 0 +0x0000F4AD 0x64F2 # 0 +0x0000F4AE 0x65A5 # 0 +0x0000F4AF 0x6ECC # 0 +0x0000F4B0 0x7620 # 0 +0x0000F4B1 0x810A # 0 +0x0000F4B2 0x8E60 # 0 +0x0000F4B3 0x965F # 0 +0x0000F4B4 0x96BB # 0 +0x0000F4B5 0x4EDF # 0 +0x0000F4B6 0x5343 # 0 +0x0000F4B7 0x5598 # 0 +0x0000F4B8 0x5929 # 0 +0x0000F4B9 0x5DDD # 0 +0x0000F4BA 0x64C5 # 0 +0x0000F4BB 0x6CC9 # 0 +0x0000F4BC 0x6DFA # 0 +0x0000F4BD 0x7394 # 0 +0x0000F4BE 0x7A7F # 0 +0x0000F4BF 0x821B # 0 +0x0000F4C0 0x85A6 # 0 +0x0000F4C1 0x8CE4 # 0 +0x0000F4C2 0x8E10 # 0 +0x0000F4C3 0x9077 # 0 +0x0000F4C4 0x91E7 # 0 +0x0000F4C5 0x95E1 # 0 +0x0000F4C6 0x9621 # 0 +0x0000F4C7 0x97C6 # 0 +0x0000F4C8 0x51F8 # 0 +0x0000F4C9 0x54F2 # 0 +0x0000F4CA 0x5586 # 0 +0x0000F4CB 0x5FB9 # 0 +0x0000F4CC 0x64A4 # 0 +0x0000F4CD 0x6F88 # 0 +0x0000F4CE 0x7DB4 # 0 +0x0000F4CF 0x8F1F # 0 +0x0000F4D0 0x8F4D # 0 +0x0000F4D1 0x9435 # 0 +0x0000F4D2 0x50C9 # 0 +0x0000F4D3 0x5C16 # 0 +0x0000F4D4 0x6CBE # 0 +0x0000F4D5 0x6DFB # 0 +0x0000F4D6 0x751B # 0 +0x0000F4D7 0x77BB # 0 +0x0000F4D8 0x7C3D # 0 +0x0000F4D9 0x7C64 # 0 +0x0000F4DA 0x8A79 # 0 +0x0000F4DB 0x8AC2 # 0 +0x0000F4DC 0x581E # 0 +0x0000F4DD 0x59BE # 0 +0x0000F4DE 0x5E16 # 0 +0x0000F4DF 0x6377 # 0 +0x0000F4E0 0x7252 # 0 +0x0000F4E1 0x758A # 0 +0x0000F4E2 0x776B # 0 +0x0000F4E3 0x8ADC # 0 +0x0000F4E4 0x8CBC # 0 +0x0000F4E5 0x8F12 # 0 +0x0000F4E6 0x5EF3 # 0 +0x0000F4E7 0x6674 # 0 +0x0000F4E8 0x6DF8 # 0 +0x0000F4E9 0x807D # 0 +0x0000F4EA 0x83C1 # 0 +0x0000F4EB 0x8ACB # 0 +0x0000F4EC 0x9751 # 0 +0x0000F4ED 0x9BD6 # 0 +0x0000F4EE 0xFA00 # 0 +0x0000F4EF 0x5243 # 0 +0x0000F4F0 0x66FF # 0 +0x0000F4F1 0x6D95 # 0 +0x0000F4F2 0x6EEF # 0 +0x0000F4F3 0x7DE0 # 0 +0x0000F4F4 0x8AE6 # 0 +0x0000F4F5 0x902E # 0 +0x0000F4F6 0x905E # 0 +0x0000F4F7 0x9AD4 # 0 +0x0000F4F8 0x521D # 0 +0x0000F4F9 0x527F # 0 +0x0000F4FA 0x54E8 # 0 +0x0000F4FB 0x6194 # 0 +0x0000F4FC 0x6284 # 0 +0x0000F4FD 0x62DB # 0 +0x0000F4FE 0x68A2 # 0 +0x0000F5A1 0x6912 # 0 +0x0000F5A2 0x695A # 0 +0x0000F5A3 0x6A35 # 0 +0x0000F5A4 0x7092 # 0 +0x0000F5A5 0x7126 # 0 +0x0000F5A6 0x785D # 0 +0x0000F5A7 0x7901 # 0 +0x0000F5A8 0x790E # 0 +0x0000F5A9 0x79D2 # 0 +0x0000F5AA 0x7A0D # 0 +0x0000F5AB 0x8096 # 0 +0x0000F5AC 0x8278 # 0 +0x0000F5AD 0x82D5 # 0 +0x0000F5AE 0x8349 # 0 +0x0000F5AF 0x8549 # 0 +0x0000F5B0 0x8C82 # 0 +0x0000F5B1 0x8D85 # 0 +0x0000F5B2 0x9162 # 0 +0x0000F5B3 0x918B # 0 +0x0000F5B4 0x91AE # 0 +0x0000F5B5 0x4FC3 # 0 +0x0000F5B6 0x56D1 # 0 +0x0000F5B7 0x71ED # 0 +0x0000F5B8 0x77D7 # 0 +0x0000F5B9 0x8700 # 0 +0x0000F5BA 0x89F8 # 0 +0x0000F5BB 0x5BF8 # 0 +0x0000F5BC 0x5FD6 # 0 +0x0000F5BD 0x6751 # 0 +0x0000F5BE 0x90A8 # 0 +0x0000F5BF 0x53E2 # 0 +0x0000F5C0 0x585A # 0 +0x0000F5C1 0x5BF5 # 0 +0x0000F5C2 0x60A4 # 0 +0x0000F5C3 0x6181 # 0 +0x0000F5C4 0x6460 # 0 +0x0000F5C5 0x7E3D # 0 +0x0000F5C6 0x8070 # 0 +0x0000F5C7 0x8525 # 0 +0x0000F5C8 0x9283 # 0 +0x0000F5C9 0x64AE # 0 +0x0000F5CA 0x50AC # 0 +0x0000F5CB 0x5D14 # 0 +0x0000F5CC 0x6700 # 0 +0x0000F5CD 0x589C # 0 +0x0000F5CE 0x62BD # 0 +0x0000F5CF 0x63A8 # 0 +0x0000F5D0 0x690E # 0 +0x0000F5D1 0x6978 # 0 +0x0000F5D2 0x6A1E # 0 +0x0000F5D3 0x6E6B # 0 +0x0000F5D4 0x76BA # 0 +0x0000F5D5 0x79CB # 0 +0x0000F5D6 0x82BB # 0 +0x0000F5D7 0x8429 # 0 +0x0000F5D8 0x8ACF # 0 +0x0000F5D9 0x8DA8 # 0 +0x0000F5DA 0x8FFD # 0 +0x0000F5DB 0x9112 # 0 +0x0000F5DC 0x914B # 0 +0x0000F5DD 0x919C # 0 +0x0000F5DE 0x9310 # 0 +0x0000F5DF 0x9318 # 0 +0x0000F5E0 0x939A # 0 +0x0000F5E1 0x96DB # 0 +0x0000F5E2 0x9A36 # 0 +0x0000F5E3 0x9C0D # 0 +0x0000F5E4 0x4E11 # 0 +0x0000F5E5 0x755C # 0 +0x0000F5E6 0x795D # 0 +0x0000F5E7 0x7AFA # 0 +0x0000F5E8 0x7B51 # 0 +0x0000F5E9 0x7BC9 # 0 +0x0000F5EA 0x7E2E # 0 +0x0000F5EB 0x84C4 # 0 +0x0000F5EC 0x8E59 # 0 +0x0000F5ED 0x8E74 # 0 +0x0000F5EE 0x8EF8 # 0 +0x0000F5EF 0x9010 # 0 +0x0000F5F0 0x6625 # 0 +0x0000F5F1 0x693F # 0 +0x0000F5F2 0x7443 # 0 +0x0000F5F3 0x51FA # 0 +0x0000F5F4 0x672E # 0 +0x0000F5F5 0x9EDC # 0 +0x0000F5F6 0x5145 # 0 +0x0000F5F7 0x5FE0 # 0 +0x0000F5F8 0x6C96 # 0 +0x0000F5F9 0x87F2 # 0 +0x0000F5FA 0x885D # 0 +0x0000F5FB 0x8877 # 0 +0x0000F5FC 0x60B4 # 0 +0x0000F5FD 0x81B5 # 0 +0x0000F5FE 0x8403 # 0 +0x0000F6A1 0x8D05 # 0 +0x0000F6A2 0x53D6 # 0 +0x0000F6A3 0x5439 # 0 +0x0000F6A4 0x5634 # 0 +0x0000F6A5 0x5A36 # 0 +0x0000F6A6 0x5C31 # 0 +0x0000F6A7 0x708A # 0 +0x0000F6A8 0x7FE0 # 0 +0x0000F6A9 0x805A # 0 +0x0000F6AA 0x8106 # 0 +0x0000F6AB 0x81ED # 0 +0x0000F6AC 0x8DA3 # 0 +0x0000F6AD 0x9189 # 0 +0x0000F6AE 0x9A5F # 0 +0x0000F6AF 0x9DF2 # 0 +0x0000F6B0 0x5074 # 0 +0x0000F6B1 0x4EC4 # 0 +0x0000F6B2 0x53A0 # 0 +0x0000F6B3 0x60FB # 0 +0x0000F6B4 0x6E2C # 0 +0x0000F6B5 0x5C64 # 0 +0x0000F6B6 0x4F88 # 0 +0x0000F6B7 0x5024 # 0 +0x0000F6B8 0x55E4 # 0 +0x0000F6B9 0x5CD9 # 0 +0x0000F6BA 0x5E5F # 0 +0x0000F6BB 0x6065 # 0 +0x0000F6BC 0x6894 # 0 +0x0000F6BD 0x6CBB # 0 +0x0000F6BE 0x6DC4 # 0 +0x0000F6BF 0x71BE # 0 +0x0000F6C0 0x75D4 # 0 +0x0000F6C1 0x75F4 # 0 +0x0000F6C2 0x7661 # 0 +0x0000F6C3 0x7A1A # 0 +0x0000F6C4 0x7A49 # 0 +0x0000F6C5 0x7DC7 # 0 +0x0000F6C6 0x7DFB # 0 +0x0000F6C7 0x7F6E # 0 +0x0000F6C8 0x81F4 # 0 +0x0000F6C9 0x86A9 # 0 +0x0000F6CA 0x8F1C # 0 +0x0000F6CB 0x96C9 # 0 +0x0000F6CC 0x99B3 # 0 +0x0000F6CD 0x9F52 # 0 +0x0000F6CE 0x5247 # 0 +0x0000F6CF 0x52C5 # 0 +0x0000F6D0 0x98ED # 0 +0x0000F6D1 0x89AA # 0 +0x0000F6D2 0x4E03 # 0 +0x0000F6D3 0x67D2 # 0 +0x0000F6D4 0x6F06 # 0 +0x0000F6D5 0x4FB5 # 0 +0x0000F6D6 0x5BE2 # 0 +0x0000F6D7 0x6795 # 0 +0x0000F6D8 0x6C88 # 0 +0x0000F6D9 0x6D78 # 0 +0x0000F6DA 0x741B # 0 +0x0000F6DB 0x7827 # 0 +0x0000F6DC 0x91DD # 0 +0x0000F6DD 0x937C # 0 +0x0000F6DE 0x87C4 # 0 +0x0000F6DF 0x79E4 # 0 +0x0000F6E0 0x7A31 # 0 +0x0000F6E1 0x5FEB # 0 +0x0000F6E2 0x4ED6 # 0 +0x0000F6E3 0x54A4 # 0 +0x0000F6E4 0x553E # 0 +0x0000F6E5 0x58AE # 0 +0x0000F6E6 0x59A5 # 0 +0x0000F6E7 0x60F0 # 0 +0x0000F6E8 0x6253 # 0 +0x0000F6E9 0x62D6 # 0 +0x0000F6EA 0x6736 # 0 +0x0000F6EB 0x6955 # 0 +0x0000F6EC 0x8235 # 0 +0x0000F6ED 0x9640 # 0 +0x0000F6EE 0x99B1 # 0 +0x0000F6EF 0x99DD # 0 +0x0000F6F0 0x502C # 0 +0x0000F6F1 0x5353 # 0 +0x0000F6F2 0x5544 # 0 +0x0000F6F3 0x577C # 0 +0x0000F6F4 0xFA01 # 0 +0x0000F6F5 0x6258 # 0 +0x0000F6F6 0xFA02 # 0 +0x0000F6F7 0x64E2 # 0 +0x0000F6F8 0x666B # 0 +0x0000F6F9 0x67DD # 0 +0x0000F6FA 0x6FC1 # 0 +0x0000F6FB 0x6FEF # 0 +0x0000F6FC 0x7422 # 0 +0x0000F6FD 0x7438 # 0 +0x0000F6FE 0x8A17 # 0 +0x0000F7A1 0x9438 # 0 +0x0000F7A2 0x5451 # 0 +0x0000F7A3 0x5606 # 0 +0x0000F7A4 0x5766 # 0 +0x0000F7A5 0x5F48 # 0 +0x0000F7A6 0x619A # 0 +0x0000F7A7 0x6B4E # 0 +0x0000F7A8 0x7058 # 0 +0x0000F7A9 0x70AD # 0 +0x0000F7AA 0x7DBB # 0 +0x0000F7AB 0x8A95 # 0 +0x0000F7AC 0x596A # 0 +0x0000F7AD 0x812B # 0 +0x0000F7AE 0x63A2 # 0 +0x0000F7AF 0x7708 # 0 +0x0000F7B0 0x803D # 0 +0x0000F7B1 0x8CAA # 0 +0x0000F7B2 0x5854 # 0 +0x0000F7B3 0x642D # 0 +0x0000F7B4 0x69BB # 0 +0x0000F7B5 0x5B95 # 0 +0x0000F7B6 0x5E11 # 0 +0x0000F7B7 0x6E6F # 0 +0x0000F7B8 0xFA03 # 0 +0x0000F7B9 0x8569 # 0 +0x0000F7BA 0x514C # 0 +0x0000F7BB 0x53F0 # 0 +0x0000F7BC 0x592A # 0 +0x0000F7BD 0x6020 # 0 +0x0000F7BE 0x614B # 0 +0x0000F7BF 0x6B86 # 0 +0x0000F7C0 0x6C70 # 0 +0x0000F7C1 0x6CF0 # 0 +0x0000F7C2 0x7B1E # 0 +0x0000F7C3 0x80CE # 0 +0x0000F7C4 0x82D4 # 0 +0x0000F7C5 0x8DC6 # 0 +0x0000F7C6 0x90B0 # 0 +0x0000F7C7 0x98B1 # 0 +0x0000F7C8 0xFA04 # 0 +0x0000F7C9 0x64C7 # 0 +0x0000F7CA 0x6FA4 # 0 +0x0000F7CB 0x6491 # 0 +0x0000F7CC 0x6504 # 0 +0x0000F7CD 0x514E # 0 +0x0000F7CE 0x5410 # 0 +0x0000F7CF 0x571F # 0 +0x0000F7D0 0x8A0E # 0 +0x0000F7D1 0x615F # 0 +0x0000F7D2 0x6876 # 0 +0x0000F7D3 0xFA05 # 0 +0x0000F7D4 0x75DB # 0 +0x0000F7D5 0x7B52 # 0 +0x0000F7D6 0x7D71 # 0 +0x0000F7D7 0x901A # 0 +0x0000F7D8 0x5806 # 0 +0x0000F7D9 0x69CC # 0 +0x0000F7DA 0x817F # 0 +0x0000F7DB 0x892A # 0 +0x0000F7DC 0x9000 # 0 +0x0000F7DD 0x9839 # 0 +0x0000F7DE 0x5078 # 0 +0x0000F7DF 0x5957 # 0 +0x0000F7E0 0x59AC # 0 +0x0000F7E1 0x6295 # 0 +0x0000F7E2 0x900F # 0 +0x0000F7E3 0x9B2A # 0 +0x0000F7E4 0x615D # 0 +0x0000F7E5 0x7279 # 0 +0x0000F7E6 0x95D6 # 0 +0x0000F7E7 0x5761 # 0 +0x0000F7E8 0x5A46 # 0 +0x0000F7E9 0x5DF4 # 0 +0x0000F7EA 0x628A # 0 +0x0000F7EB 0x64AD # 0 +0x0000F7EC 0x64FA # 0 +0x0000F7ED 0x6777 # 0 +0x0000F7EE 0x6CE2 # 0 +0x0000F7EF 0x6D3E # 0 +0x0000F7F0 0x722C # 0 +0x0000F7F1 0x7436 # 0 +0x0000F7F2 0x7834 # 0 +0x0000F7F3 0x7F77 # 0 +0x0000F7F4 0x82AD # 0 +0x0000F7F5 0x8DDB # 0 +0x0000F7F6 0x9817 # 0 +0x0000F7F7 0x5224 # 0 +0x0000F7F8 0x5742 # 0 +0x0000F7F9 0x677F # 0 +0x0000F7FA 0x7248 # 0 +0x0000F7FB 0x74E3 # 0 +0x0000F7FC 0x8CA9 # 0 +0x0000F7FD 0x8FA6 # 0 +0x0000F7FE 0x9211 # 0 +0x0000F8A1 0x962A # 0 +0x0000F8A2 0x516B # 0 +0x0000F8A3 0x53ED # 0 +0x0000F8A4 0x634C # 0 +0x0000F8A5 0x4F69 # 0 +0x0000F8A6 0x5504 # 0 +0x0000F8A7 0x6096 # 0 +0x0000F8A8 0x6557 # 0 +0x0000F8A9 0x6C9B # 0 +0x0000F8AA 0x6D7F # 0 +0x0000F8AB 0x724C # 0 +0x0000F8AC 0x72FD # 0 +0x0000F8AD 0x7A17 # 0 +0x0000F8AE 0x8987 # 0 +0x0000F8AF 0x8C9D # 0 +0x0000F8B0 0x5F6D # 0 +0x0000F8B1 0x6F8E # 0 +0x0000F8B2 0x70F9 # 0 +0x0000F8B3 0x81A8 # 0 +0x0000F8B4 0x610E # 0 +0x0000F8B5 0x4FBF # 0 +0x0000F8B6 0x504F # 0 +0x0000F8B7 0x6241 # 0 +0x0000F8B8 0x7247 # 0 +0x0000F8B9 0x7BC7 # 0 +0x0000F8BA 0x7DE8 # 0 +0x0000F8BB 0x7FE9 # 0 +0x0000F8BC 0x904D # 0 +0x0000F8BD 0x97AD # 0 +0x0000F8BE 0x9A19 # 0 +0x0000F8BF 0x8CB6 # 0 +0x0000F8C0 0x576A # 0 +0x0000F8C1 0x5E73 # 0 +0x0000F8C2 0x67B0 # 0 +0x0000F8C3 0x840D # 0 +0x0000F8C4 0x8A55 # 0 +0x0000F8C5 0x5420 # 0 +0x0000F8C6 0x5B16 # 0 +0x0000F8C7 0x5E63 # 0 +0x0000F8C8 0x5EE2 # 0 +0x0000F8C9 0x5F0A # 0 +0x0000F8CA 0x6583 # 0 +0x0000F8CB 0x80BA # 0 +0x0000F8CC 0x853D # 0 +0x0000F8CD 0x9589 # 0 +0x0000F8CE 0x965B # 0 +0x0000F8CF 0x4F48 # 0 +0x0000F8D0 0x5305 # 0 +0x0000F8D1 0x530D # 0 +0x0000F8D2 0x530F # 0 +0x0000F8D3 0x5486 # 0 +0x0000F8D4 0x54FA # 0 +0x0000F8D5 0x5703 # 0 +0x0000F8D6 0x5E03 # 0 +0x0000F8D7 0x6016 # 0 +0x0000F8D8 0x629B # 0 +0x0000F8D9 0x62B1 # 0 +0x0000F8DA 0x6355 # 0 +0x0000F8DB 0xFA06 # 0 +0x0000F8DC 0x6CE1 # 0 +0x0000F8DD 0x6D66 # 0 +0x0000F8DE 0x75B1 # 0 +0x0000F8DF 0x7832 # 0 +0x0000F8E0 0x80DE # 0 +0x0000F8E1 0x812F # 0 +0x0000F8E2 0x82DE # 0 +0x0000F8E3 0x8461 # 0 +0x0000F8E4 0x84B2 # 0 +0x0000F8E5 0x888D # 0 +0x0000F8E6 0x8912 # 0 +0x0000F8E7 0x900B # 0 +0x0000F8E8 0x92EA # 0 +0x0000F8E9 0x98FD # 0 +0x0000F8EA 0x9B91 # 0 +0x0000F8EB 0x5E45 # 0 +0x0000F8EC 0x66B4 # 0 +0x0000F8ED 0x66DD # 0 +0x0000F8EE 0x7011 # 0 +0x0000F8EF 0x7206 # 0 +0x0000F8F0 0xFA07 # 0 +0x0000F8F1 0x4FF5 # 0 +0x0000F8F2 0x527D # 0 +0x0000F8F3 0x5F6A # 0 +0x0000F8F4 0x6153 # 0 +0x0000F8F5 0x6753 # 0 +0x0000F8F6 0x6A19 # 0 +0x0000F8F7 0x6F02 # 0 +0x0000F8F8 0x74E2 # 0 +0x0000F8F9 0x7968 # 0 +0x0000F8FA 0x8868 # 0 +0x0000F8FB 0x8C79 # 0 +0x0000F8FC 0x98C7 # 0 +0x0000F8FD 0x98C4 # 0 +0x0000F8FE 0x9A43 # 0 +0x0000F9A1 0x54C1 # 0 +0x0000F9A2 0x7A1F # 0 +0x0000F9A3 0x6953 # 0 +0x0000F9A4 0x8AF7 # 0 +0x0000F9A5 0x8C4A # 0 +0x0000F9A6 0x98A8 # 0 +0x0000F9A7 0x99AE # 0 +0x0000F9A8 0x5F7C # 0 +0x0000F9A9 0x62AB # 0 +0x0000F9AA 0x75B2 # 0 +0x0000F9AB 0x76AE # 0 +0x0000F9AC 0x88AB # 0 +0x0000F9AD 0x907F # 0 +0x0000F9AE 0x9642 # 0 +0x0000F9AF 0x5339 # 0 +0x0000F9B0 0x5F3C # 0 +0x0000F9B1 0x5FC5 # 0 +0x0000F9B2 0x6CCC # 0 +0x0000F9B3 0x73CC # 0 +0x0000F9B4 0x7562 # 0 +0x0000F9B5 0x758B # 0 +0x0000F9B6 0x7B46 # 0 +0x0000F9B7 0x82FE # 0 +0x0000F9B8 0x999D # 0 +0x0000F9B9 0x4E4F # 0 +0x0000F9BA 0x903C # 0 +0x0000F9BB 0x4E0B # 0 +0x0000F9BC 0x4F55 # 0 +0x0000F9BD 0x53A6 # 0 +0x0000F9BE 0x590F # 0 +0x0000F9BF 0x5EC8 # 0 +0x0000F9C0 0x6630 # 0 +0x0000F9C1 0x6CB3 # 0 +0x0000F9C2 0x7455 # 0 +0x0000F9C3 0x8377 # 0 +0x0000F9C4 0x8766 # 0 +0x0000F9C5 0x8CC0 # 0 +0x0000F9C6 0x9050 # 0 +0x0000F9C7 0x971E # 0 +0x0000F9C8 0x9C15 # 0 +0x0000F9C9 0x58D1 # 0 +0x0000F9CA 0x5B78 # 0 +0x0000F9CB 0x8650 # 0 +0x0000F9CC 0x8B14 # 0 +0x0000F9CD 0x9DB4 # 0 +0x0000F9CE 0x5BD2 # 0 +0x0000F9CF 0x6068 # 0 +0x0000F9D0 0x608D # 0 +0x0000F9D1 0x65F1 # 0 +0x0000F9D2 0x6C57 # 0 +0x0000F9D3 0x6F22 # 0 +0x0000F9D4 0x6FA3 # 0 +0x0000F9D5 0x701A # 0 +0x0000F9D6 0x7F55 # 0 +0x0000F9D7 0x7FF0 # 0 +0x0000F9D8 0x9591 # 0 +0x0000F9D9 0x9592 # 0 +0x0000F9DA 0x9650 # 0 +0x0000F9DB 0x97D3 # 0 +0x0000F9DC 0x5272 # 0 +0x0000F9DD 0x8F44 # 0 +0x0000F9DE 0x51FD # 0 +0x0000F9DF 0x542B # 0 +0x0000F9E0 0x54B8 # 0 +0x0000F9E1 0x5563 # 0 +0x0000F9E2 0x558A # 0 +0x0000F9E3 0x6ABB # 0 +0x0000F9E4 0x6DB5 # 0 +0x0000F9E5 0x7DD8 # 0 +0x0000F9E6 0x8266 # 0 +0x0000F9E7 0x929C # 0 +0x0000F9E8 0x9677 # 0 +0x0000F9E9 0x9E79 # 0 +0x0000F9EA 0x5408 # 0 +0x0000F9EB 0x54C8 # 0 +0x0000F9EC 0x76D2 # 0 +0x0000F9ED 0x86E4 # 0 +0x0000F9EE 0x95A4 # 0 +0x0000F9EF 0x95D4 # 0 +0x0000F9F0 0x965C # 0 +0x0000F9F1 0x4EA2 # 0 +0x0000F9F2 0x4F09 # 0 +0x0000F9F3 0x59EE # 0 +0x0000F9F4 0x5AE6 # 0 +0x0000F9F5 0x5DF7 # 0 +0x0000F9F6 0x6052 # 0 +0x0000F9F7 0x6297 # 0 +0x0000F9F8 0x676D # 0 +0x0000F9F9 0x6841 # 0 +0x0000F9FA 0x6C86 # 0 +0x0000F9FB 0x6E2F # 0 +0x0000F9FC 0x7F38 # 0 +0x0000F9FD 0x809B # 0 +0x0000F9FE 0x822A # 0 +0x0000FAA1 0xFA08 # 0 +0x0000FAA2 0xFA09 # 0 +0x0000FAA3 0x9805 # 0 +0x0000FAA4 0x4EA5 # 0 +0x0000FAA5 0x5055 # 0 +0x0000FAA6 0x54B3 # 0 +0x0000FAA7 0x5793 # 0 +0x0000FAA8 0x595A # 0 +0x0000FAA9 0x5B69 # 0 +0x0000FAAA 0x5BB3 # 0 +0x0000FAAB 0x61C8 # 0 +0x0000FAAC 0x6977 # 0 +0x0000FAAD 0x6D77 # 0 +0x0000FAAE 0x7023 # 0 +0x0000FAAF 0x87F9 # 0 +0x0000FAB0 0x89E3 # 0 +0x0000FAB1 0x8A72 # 0 +0x0000FAB2 0x8AE7 # 0 +0x0000FAB3 0x9082 # 0 +0x0000FAB4 0x99ED # 0 +0x0000FAB5 0x9AB8 # 0 +0x0000FAB6 0x52BE # 0 +0x0000FAB7 0x6838 # 0 +0x0000FAB8 0x5016 # 0 +0x0000FAB9 0x5E78 # 0 +0x0000FABA 0x674F # 0 +0x0000FABB 0x8347 # 0 +0x0000FABC 0x884C # 0 +0x0000FABD 0x4EAB # 0 +0x0000FABE 0x5411 # 0 +0x0000FABF 0x56AE # 0 +0x0000FAC0 0x73E6 # 0 +0x0000FAC1 0x9115 # 0 +0x0000FAC2 0x97FF # 0 +0x0000FAC3 0x9909 # 0 +0x0000FAC4 0x9957 # 0 +0x0000FAC5 0x9999 # 0 +0x0000FAC6 0x5653 # 0 +0x0000FAC7 0x589F # 0 +0x0000FAC8 0x865B # 0 +0x0000FAC9 0x8A31 # 0 +0x0000FACA 0x61B2 # 0 +0x0000FACB 0x6AF6 # 0 +0x0000FACC 0x737B # 0 +0x0000FACD 0x8ED2 # 0 +0x0000FACE 0x6B47 # 0 +0x0000FACF 0x96AA # 0 +0x0000FAD0 0x9A57 # 0 +0x0000FAD1 0x5955 # 0 +0x0000FAD2 0x7200 # 0 +0x0000FAD3 0x8D6B # 0 +0x0000FAD4 0x9769 # 0 +0x0000FAD5 0x4FD4 # 0 +0x0000FAD6 0x5CF4 # 0 +0x0000FAD7 0x5F26 # 0 +0x0000FAD8 0x61F8 # 0 +0x0000FAD9 0x665B # 0 +0x0000FADA 0x6CEB # 0 +0x0000FADB 0x70AB # 0 +0x0000FADC 0x7384 # 0 +0x0000FADD 0x73B9 # 0 +0x0000FADE 0x73FE # 0 +0x0000FADF 0x7729 # 0 +0x0000FAE0 0x774D # 0 +0x0000FAE1 0x7D43 # 0 +0x0000FAE2 0x7D62 # 0 +0x0000FAE3 0x7E23 # 0 +0x0000FAE4 0x8237 # 0 +0x0000FAE5 0x8852 # 0 +0x0000FAE6 0xFA0A # 0 +0x0000FAE7 0x8CE2 # 0 +0x0000FAE8 0x9249 # 0 +0x0000FAE9 0x986F # 0 +0x0000FAEA 0x5B51 # 0 +0x0000FAEB 0x7A74 # 0 +0x0000FAEC 0x8840 # 0 +0x0000FAED 0x9801 # 0 +0x0000FAEE 0x5ACC # 0 +0x0000FAEF 0x4FE0 # 0 +0x0000FAF0 0x5354 # 0 +0x0000FAF1 0x593E # 0 +0x0000FAF2 0x5CFD # 0 +0x0000FAF3 0x633E # 0 +0x0000FAF4 0x6D79 # 0 +0x0000FAF5 0x72F9 # 0 +0x0000FAF6 0x8105 # 0 +0x0000FAF7 0x8107 # 0 +0x0000FAF8 0x83A2 # 0 +0x0000FAF9 0x92CF # 0 +0x0000FAFA 0x9830 # 0 +0x0000FAFB 0x4EA8 # 0 +0x0000FAFC 0x5144 # 0 +0x0000FAFD 0x5211 # 0 +0x0000FAFE 0x578B # 0 +0x0000FBA1 0x5F62 # 0 +0x0000FBA2 0x6CC2 # 0 +0x0000FBA3 0x6ECE # 0 +0x0000FBA4 0x7005 # 0 +0x0000FBA5 0x7050 # 0 +0x0000FBA6 0x70AF # 0 +0x0000FBA7 0x7192 # 0 +0x0000FBA8 0x73E9 # 0 +0x0000FBA9 0x7469 # 0 +0x0000FBAA 0x834A # 0 +0x0000FBAB 0x87A2 # 0 +0x0000FBAC 0x8861 # 0 +0x0000FBAD 0x9008 # 0 +0x0000FBAE 0x90A2 # 0 +0x0000FBAF 0x93A3 # 0 +0x0000FBB0 0x99A8 # 0 +0x0000FBB1 0x516E # 0 +0x0000FBB2 0x5F57 # 0 +0x0000FBB3 0x60E0 # 0 +0x0000FBB4 0x6167 # 0 +0x0000FBB5 0x66B3 # 0 +0x0000FBB6 0x8559 # 0 +0x0000FBB7 0x8E4A # 0 +0x0000FBB8 0x91AF # 0 +0x0000FBB9 0x978B # 0 +0x0000FBBA 0x4E4E # 0 +0x0000FBBB 0x4E92 # 0 +0x0000FBBC 0x547C # 0 +0x0000FBBD 0x58D5 # 0 +0x0000FBBE 0x58FA # 0 +0x0000FBBF 0x597D # 0 +0x0000FBC0 0x5CB5 # 0 +0x0000FBC1 0x5F27 # 0 +0x0000FBC2 0x6236 # 0 +0x0000FBC3 0x6248 # 0 +0x0000FBC4 0x660A # 0 +0x0000FBC5 0x6667 # 0 +0x0000FBC6 0x6BEB # 0 +0x0000FBC7 0x6D69 # 0 +0x0000FBC8 0x6DCF # 0 +0x0000FBC9 0x6E56 # 0 +0x0000FBCA 0x6EF8 # 0 +0x0000FBCB 0x6F94 # 0 +0x0000FBCC 0x6FE0 # 0 +0x0000FBCD 0x6FE9 # 0 +0x0000FBCE 0x705D # 0 +0x0000FBCF 0x72D0 # 0 +0x0000FBD0 0x7425 # 0 +0x0000FBD1 0x745A # 0 +0x0000FBD2 0x74E0 # 0 +0x0000FBD3 0x7693 # 0 +0x0000FBD4 0x795C # 0 +0x0000FBD5 0x7CCA # 0 +0x0000FBD6 0x7E1E # 0 +0x0000FBD7 0x80E1 # 0 +0x0000FBD8 0x82A6 # 0 +0x0000FBD9 0x846B # 0 +0x0000FBDA 0x84BF # 0 +0x0000FBDB 0x864E # 0 +0x0000FBDC 0x865F # 0 +0x0000FBDD 0x8774 # 0 +0x0000FBDE 0x8B77 # 0 +0x0000FBDF 0x8C6A # 0 +0x0000FBE0 0x93AC # 0 +0x0000FBE1 0x9800 # 0 +0x0000FBE2 0x9865 # 0 +0x0000FBE3 0x60D1 # 0 +0x0000FBE4 0x6216 # 0 +0x0000FBE5 0x9177 # 0 +0x0000FBE6 0x5A5A # 0 +0x0000FBE7 0x660F # 0 +0x0000FBE8 0x6DF7 # 0 +0x0000FBE9 0x6E3E # 0 +0x0000FBEA 0x743F # 0 +0x0000FBEB 0x9B42 # 0 +0x0000FBEC 0x5FFD # 0 +0x0000FBED 0x60DA # 0 +0x0000FBEE 0x7B0F # 0 +0x0000FBEF 0x54C4 # 0 +0x0000FBF0 0x5F18 # 0 +0x0000FBF1 0x6C5E # 0 +0x0000FBF2 0x6CD3 # 0 +0x0000FBF3 0x6D2A # 0 +0x0000FBF4 0x70D8 # 0 +0x0000FBF5 0x7D05 # 0 +0x0000FBF6 0x8679 # 0 +0x0000FBF7 0x8A0C # 0 +0x0000FBF8 0x9D3B # 0 +0x0000FBF9 0x5316 # 0 +0x0000FBFA 0x548C # 0 +0x0000FBFB 0x5B05 # 0 +0x0000FBFC 0x6A3A # 0 +0x0000FBFD 0x706B # 0 +0x0000FBFE 0x7575 # 0 +0x0000FCA1 0x798D # 0 +0x0000FCA2 0x79BE # 0 +0x0000FCA3 0x82B1 # 0 +0x0000FCA4 0x83EF # 0 +0x0000FCA5 0x8A71 # 0 +0x0000FCA6 0x8B41 # 0 +0x0000FCA7 0x8CA8 # 0 +0x0000FCA8 0x9774 # 0 +0x0000FCA9 0xFA0B # 0 +0x0000FCAA 0x64F4 # 0 +0x0000FCAB 0x652B # 0 +0x0000FCAC 0x78BA # 0 +0x0000FCAD 0x78BB # 0 +0x0000FCAE 0x7A6B # 0 +0x0000FCAF 0x4E38 # 0 +0x0000FCB0 0x559A # 0 +0x0000FCB1 0x5950 # 0 +0x0000FCB2 0x5BA6 # 0 +0x0000FCB3 0x5E7B # 0 +0x0000FCB4 0x60A3 # 0 +0x0000FCB5 0x63DB # 0 +0x0000FCB6 0x6B61 # 0 +0x0000FCB7 0x6665 # 0 +0x0000FCB8 0x6853 # 0 +0x0000FCB9 0x6E19 # 0 +0x0000FCBA 0x7165 # 0 +0x0000FCBB 0x74B0 # 0 +0x0000FCBC 0x7D08 # 0 +0x0000FCBD 0x9084 # 0 +0x0000FCBE 0x9A69 # 0 +0x0000FCBF 0x9C25 # 0 +0x0000FCC0 0x6D3B # 0 +0x0000FCC1 0x6ED1 # 0 +0x0000FCC2 0x733E # 0 +0x0000FCC3 0x8C41 # 0 +0x0000FCC4 0x95CA # 0 +0x0000FCC5 0x51F0 # 0 +0x0000FCC6 0x5E4C # 0 +0x0000FCC7 0x5FA8 # 0 +0x0000FCC8 0x604D # 0 +0x0000FCC9 0x60F6 # 0 +0x0000FCCA 0x6130 # 0 +0x0000FCCB 0x614C # 0 +0x0000FCCC 0x6643 # 0 +0x0000FCCD 0x6644 # 0 +0x0000FCCE 0x69A5 # 0 +0x0000FCCF 0x6CC1 # 0 +0x0000FCD0 0x6E5F # 0 +0x0000FCD1 0x6EC9 # 0 +0x0000FCD2 0x6F62 # 0 +0x0000FCD3 0x714C # 0 +0x0000FCD4 0x749C # 0 +0x0000FCD5 0x7687 # 0 +0x0000FCD6 0x7BC1 # 0 +0x0000FCD7 0x7C27 # 0 +0x0000FCD8 0x8352 # 0 +0x0000FCD9 0x8757 # 0 +0x0000FCDA 0x9051 # 0 +0x0000FCDB 0x968D # 0 +0x0000FCDC 0x9EC3 # 0 +0x0000FCDD 0x532F # 0 +0x0000FCDE 0x56DE # 0 +0x0000FCDF 0x5EFB # 0 +0x0000FCE0 0x5F8A # 0 +0x0000FCE1 0x6062 # 0 +0x0000FCE2 0x6094 # 0 +0x0000FCE3 0x61F7 # 0 +0x0000FCE4 0x6666 # 0 +0x0000FCE5 0x6703 # 0 +0x0000FCE6 0x6A9C # 0 +0x0000FCE7 0x6DEE # 0 +0x0000FCE8 0x6FAE # 0 +0x0000FCE9 0x7070 # 0 +0x0000FCEA 0x736A # 0 +0x0000FCEB 0x7E6A # 0 +0x0000FCEC 0x81BE # 0 +0x0000FCED 0x8334 # 0 +0x0000FCEE 0x86D4 # 0 +0x0000FCEF 0x8AA8 # 0 +0x0000FCF0 0x8CC4 # 0 +0x0000FCF1 0x5283 # 0 +0x0000FCF2 0x7372 # 0 +0x0000FCF3 0x5B96 # 0 +0x0000FCF4 0x6A6B # 0 +0x0000FCF5 0x9404 # 0 +0x0000FCF6 0x54EE # 0 +0x0000FCF7 0x5686 # 0 +0x0000FCF8 0x5B5D # 0 +0x0000FCF9 0x6548 # 0 +0x0000FCFA 0x6585 # 0 +0x0000FCFB 0x66C9 # 0 +0x0000FCFC 0x689F # 0 +0x0000FCFD 0x6D8D # 0 +0x0000FCFE 0x6DC6 # 0 +0x0000FDA1 0x723B # 0 +0x0000FDA2 0x80B4 # 0 +0x0000FDA3 0x9175 # 0 +0x0000FDA4 0x9A4D # 0 +0x0000FDA5 0x4FAF # 0 +0x0000FDA6 0x5019 # 0 +0x0000FDA7 0x539A # 0 +0x0000FDA8 0x540E # 0 +0x0000FDA9 0x543C # 0 +0x0000FDAA 0x5589 # 0 +0x0000FDAB 0x55C5 # 0 +0x0000FDAC 0x5E3F # 0 +0x0000FDAD 0x5F8C # 0 +0x0000FDAE 0x673D # 0 +0x0000FDAF 0x7166 # 0 +0x0000FDB0 0x73DD # 0 +0x0000FDB1 0x9005 # 0 +0x0000FDB2 0x52DB # 0 +0x0000FDB3 0x52F3 # 0 +0x0000FDB4 0x5864 # 0 +0x0000FDB5 0x58CE # 0 +0x0000FDB6 0x7104 # 0 +0x0000FDB7 0x718F # 0 +0x0000FDB8 0x71FB # 0 +0x0000FDB9 0x85B0 # 0 +0x0000FDBA 0x8A13 # 0 +0x0000FDBB 0x6688 # 0 +0x0000FDBC 0x85A8 # 0 +0x0000FDBD 0x55A7 # 0 +0x0000FDBE 0x6684 # 0 +0x0000FDBF 0x714A # 0 +0x0000FDC0 0x8431 # 0 +0x0000FDC1 0x5349 # 0 +0x0000FDC2 0x5599 # 0 +0x0000FDC3 0x6BC1 # 0 +0x0000FDC4 0x5F59 # 0 +0x0000FDC5 0x5FBD # 0 +0x0000FDC6 0x63EE # 0 +0x0000FDC7 0x6689 # 0 +0x0000FDC8 0x7147 # 0 +0x0000FDC9 0x8AF1 # 0 +0x0000FDCA 0x8F1D # 0 +0x0000FDCB 0x9EBE # 0 +0x0000FDCC 0x4F11 # 0 +0x0000FDCD 0x643A # 0 +0x0000FDCE 0x70CB # 0 +0x0000FDCF 0x7566 # 0 +0x0000FDD0 0x8667 # 0 +0x0000FDD1 0x6064 # 0 +0x0000FDD2 0x8B4E # 0 +0x0000FDD3 0x9DF8 # 0 +0x0000FDD4 0x5147 # 0 +0x0000FDD5 0x51F6 # 0 +0x0000FDD6 0x5308 # 0 +0x0000FDD7 0x6D36 # 0 +0x0000FDD8 0x80F8 # 0 +0x0000FDD9 0x9ED1 # 0 +0x0000FDDA 0x6615 # 0 +0x0000FDDB 0x6B23 # 0 +0x0000FDDC 0x7098 # 0 +0x0000FDDD 0x75D5 # 0 +0x0000FDDE 0x5403 # 0 +0x0000FDDF 0x5C79 # 0 +0x0000FDE0 0x7D07 # 0 +0x0000FDE1 0x8A16 # 0 +0x0000FDE2 0x6B20 # 0 +0x0000FDE3 0x6B3D # 0 +0x0000FDE4 0x6B46 # 0 +0x0000FDE5 0x5438 # 0 +0x0000FDE6 0x6070 # 0 +0x0000FDE7 0x6D3D # 0 +0x0000FDE8 0x7FD5 # 0 +0x0000FDE9 0x8208 # 0 +0x0000FDEA 0x50D6 # 0 +0x0000FDEB 0x51DE # 0 +0x0000FDEC 0x559C # 0 +0x0000FDED 0x566B # 0 +0x0000FDEE 0x56CD # 0 +0x0000FDEF 0x59EC # 0 +0x0000FDF0 0x5B09 # 0 +0x0000FDF1 0x5E0C # 0 +0x0000FDF2 0x6199 # 0 +0x0000FDF3 0x6198 # 0 +0x0000FDF4 0x6231 # 0 +0x0000FDF5 0x665E # 0 +0x0000FDF6 0x66E6 # 0 +0x0000FDF7 0x7199 # 0 +0x0000FDF8 0x71B9 # 0 +0x0000FDF9 0x71BA # 0 +0x0000FDFA 0x72A7 # 0 +0x0000FDFB 0x79A7 # 0 +0x0000FDFC 0x7A00 # 0 +0x0000FDFD 0x7FB2 # 0 +0x0000FDFE 0x8A70 # 0 +0x0000FEA1 0xF75E # 0 +0x0000FEA2 0xF75F # 0 +0x0000FEA3 0xF760 # 0 +0x0000FEA4 0xF761 # 0 +0x0000FEA5 0xF762 # 0 +0x0000FEA6 0xF763 # 0 +0x0000FEA7 0xF764 # 0 +0x0000FEA8 0xF765 # 0 +0x0000FEA9 0xF766 # 0 +0x0000FEAA 0xF767 # 0 +0x0000FEAB 0xF768 # 0 +0x0000FEAC 0xF769 # 0 +0x0000FEAD 0xF76A # 0 +0x0000FEAE 0xF76B # 0 +0x0000FEAF 0xF76C # 0 +0x0000FEB0 0xF76D # 0 +0x0000FEB1 0xF76E # 0 +0x0000FEB2 0xF76F # 0 +0x0000FEB3 0xF770 # 0 +0x0000FEB4 0xF771 # 0 +0x0000FEB5 0xF772 # 0 +0x0000FEB6 0xF773 # 0 +0x0000FEB7 0xF774 # 0 +0x0000FEB8 0xF775 # 0 +0x0000FEB9 0xF776 # 0 +0x0000FEBA 0xF777 # 0 +0x0000FEBB 0xF778 # 0 +0x0000FEBC 0xF779 # 0 +0x0000FEBD 0xF77A # 0 +0x0000FEBE 0xF77B # 0 +0x0000FEBF 0xF77C # 0 +0x0000FEC0 0xF77D # 0 +0x0000FEC1 0xF77E # 0 +0x0000FEC2 0xF77F # 0 +0x0000FEC3 0xF780 # 0 +0x0000FEC4 0xF781 # 0 +0x0000FEC5 0xF782 # 0 +0x0000FEC6 0xF783 # 0 +0x0000FEC7 0xF784 # 0 +0x0000FEC8 0xF785 # 0 +0x0000FEC9 0xF786 # 0 +0x0000FECA 0xF787 # 0 +0x0000FECB 0xF788 # 0 +0x0000FECC 0xF789 # 0 +0x0000FECD 0xF78A # 0 +0x0000FECE 0xF78B # 0 +0x0000FECF 0xF78C # 0 +0x0000FED0 0xF78D # 0 +0x0000FED1 0xF78E # 0 +0x0000FED2 0xF78F # 0 +0x0000FED3 0xF790 # 0 +0x0000FED4 0xF791 # 0 +0x0000FED5 0xF792 # 0 +0x0000FED6 0xF793 # 0 +0x0000FED7 0xF794 # 0 +0x0000FED8 0xF795 # 0 +0x0000FED9 0xF796 # 0 +0x0000FEDA 0xF797 # 0 +0x0000FEDB 0xF798 # 0 +0x0000FEDC 0xF799 # 0 +0x0000FEDD 0xF79A # 0 +0x0000FEDE 0xF79B # 0 +0x0000FEDF 0xF79C # 0 +0x0000FEE0 0xF79D # 0 +0x0000FEE1 0xF79E # 0 +0x0000FEE2 0xF79F # 0 +0x0000FEE3 0xF7A0 # 0 +0x0000FEE4 0xF7A1 # 0 +0x0000FEE5 0xF7A2 # 0 +0x0000FEE6 0xF7A3 # 0 +0x0000FEE7 0xF7A4 # 0 +0x0000FEE8 0xF7A5 # 0 +0x0000FEE9 0xF7A6 # 0 +0x0000FEEA 0xF7A7 # 0 +0x0000FEEB 0xF7A8 # 0 +0x0000FEEC 0xF7A9 # 0 +0x0000FEED 0xF7AA # 0 +0x0000FEEE 0xF7AB # 0 +0x0000FEEF 0xF7AC # 0 +0x0000FEF0 0xF7AD # 0 +0x0000FEF1 0xF7AE # 0 +0x0000FEF2 0xF7AF # 0 +0x0000FEF3 0xF7B0 # 0 +0x0000FEF4 0xF7B1 # 0 +0x0000FEF5 0xF7B2 # 0 +0x0000FEF6 0xF7B3 # 0 +0x0000FEF7 0xF7B4 # 0 +0x0000FEF8 0xF7B5 # 0 +0x0000FEF9 0xF7B6 # 0 +0x0000FEFA 0xF7B7 # 0 +0x0000FEFB 0xF7B8 # 0 +0x0000FEFC 0xF7B9 # 0 +0x0000FEFD 0xF7BA # 0 +0x0000FEFE 0xF7BB # 0 diff --git a/data/euc-tw.txt b/data/euc-tw.txt new file mode 100644 index 000000000..98a2ab5d8 --- /dev/null +++ b/data/euc-tw.txt @@ -0,0 +1,17840 @@ +# euc-tw.txt - EUC to Unicode charmap +0x00000000 0x0000 # 0 +0x00000001 0x0001 # 0 +0x00000002 0x0002 # 0 +0x00000003 0x0003 # 0 +0x00000004 0x0004 # 0 +0x00000005 0x0005 # 0 +0x00000006 0x0006 # 0 +0x00000007 0x0007 # 0 +0x00000008 0x0008 # 0 +0x00000009 0x0009 # 0 +0x0000000A 0x000A # 0 +0x0000000B 0x000B # 0 +0x0000000C 0x000C # 0 +0x0000000D 0x000D # 0 +0x0000000E 0x000E # 0 +0x0000000F 0x000F # 0 +0x00000010 0x0010 # 0 +0x00000011 0x0011 # 0 +0x00000012 0x0012 # 0 +0x00000013 0x0013 # 0 +0x00000014 0x0014 # 0 +0x00000015 0x0015 # 0 +0x00000016 0x0016 # 0 +0x00000017 0x0017 # 0 +0x00000018 0x0018 # 0 +0x00000019 0x0019 # 0 +0x0000001A 0x001A # 0 +0x0000001B 0x001B # 0 +0x0000001C 0x001C # 0 +0x0000001D 0x001D # 0 +0x0000001E 0x001E # 0 +0x0000001F 0x001F # 0 +0x00000020 0x0020 # 0 +0x00000021 0x0021 # 0 +0x00000022 0x0022 # 0 +0x00000023 0x0023 # 0 +0x00000024 0x0024 # 0 +0x00000025 0x0025 # 0 +0x00000026 0x0026 # 0 +0x00000027 0x0027 # 0 +0x00000028 0x0028 # 0 +0x00000029 0x0029 # 0 +0x0000002A 0x002A # 0 +0x0000002B 0x002B # 0 +0x0000002C 0x002C # 0 +0x0000002D 0x002D # 0 +0x0000002E 0x002E # 0 +0x0000002F 0x002F # 0 +0x00000030 0x0030 # 0 +0x00000031 0x0031 # 0 +0x00000032 0x0032 # 0 +0x00000033 0x0033 # 0 +0x00000034 0x0034 # 0 +0x00000035 0x0035 # 0 +0x00000036 0x0036 # 0 +0x00000037 0x0037 # 0 +0x00000038 0x0038 # 0 +0x00000039 0x0039 # 0 +0x0000003A 0x003A # 0 +0x0000003B 0x003B # 0 +0x0000003C 0x003C # 0 +0x0000003D 0x003D # 0 +0x0000003E 0x003E # 0 +0x0000003F 0x003F # 0 +0x00000040 0x0040 # 0 +0x00000041 0x0041 # 0 +0x00000042 0x0042 # 0 +0x00000043 0x0043 # 0 +0x00000044 0x0044 # 0 +0x00000045 0x0045 # 0 +0x00000046 0x0046 # 0 +0x00000047 0x0047 # 0 +0x00000048 0x0048 # 0 +0x00000049 0x0049 # 0 +0x0000004A 0x004A # 0 +0x0000004B 0x004B # 0 +0x0000004C 0x004C # 0 +0x0000004D 0x004D # 0 +0x0000004E 0x004E # 0 +0x0000004F 0x004F # 0 +0x00000050 0x0050 # 0 +0x00000051 0x0051 # 0 +0x00000052 0x0052 # 0 +0x00000053 0x0053 # 0 +0x00000054 0x0054 # 0 +0x00000055 0x0055 # 0 +0x00000056 0x0056 # 0 +0x00000057 0x0057 # 0 +0x00000058 0x0058 # 0 +0x00000059 0x0059 # 0 +0x0000005A 0x005A # 0 +0x0000005B 0x005B # 0 +0x0000005C 0x005C # 0 +0x0000005D 0x005D # 0 +0x0000005E 0x005E # 0 +0x0000005F 0x005F # 0 +0x00000060 0x0060 # 0 +0x00000061 0x0061 # 0 +0x00000062 0x0062 # 0 +0x00000063 0x0063 # 0 +0x00000064 0x0064 # 0 +0x00000065 0x0065 # 0 +0x00000066 0x0066 # 0 +0x00000067 0x0067 # 0 +0x00000068 0x0068 # 0 +0x00000069 0x0069 # 0 +0x0000006A 0x006A # 0 +0x0000006B 0x006B # 0 +0x0000006C 0x006C # 0 +0x0000006D 0x006D # 0 +0x0000006E 0x006E # 0 +0x0000006F 0x006F # 0 +0x00000070 0x0070 # 0 +0x00000071 0x0071 # 0 +0x00000072 0x0072 # 0 +0x00000073 0x0073 # 0 +0x00000074 0x0074 # 0 +0x00000075 0x0075 # 0 +0x00000076 0x0076 # 0 +0x00000077 0x0077 # 0 +0x00000078 0x0078 # 0 +0x00000079 0x0079 # 0 +0x0000007A 0x007A # 0 +0x0000007B 0x007B # 0 +0x0000007C 0x007C # 0 +0x0000007D 0x007D # 0 +0x0000007E 0x007E # 0 +0x0000007F 0x007F # 0 +0x0000A1A1 0x3000 # 0 +0x0000A1A2 0xFF0C # 0 +0x0000A1A3 0x3001 # 0 +0x0000A1A4 0x3002 # 0 +0x0000A1A5 0xFF0E # 0 +0x0000A1A6 0x30FB # 0 +0x0000A1A7 0xFF1B # 0 +0x0000A1A8 0xFF1A # 0 +0x0000A1A9 0xFF1F # 0 +0x0000A1AA 0xFF01 # 0 +0x0000A1AB 0xFE30 # 0 +0x0000A1AC 0x2026 # 0 +0x0000A1AD 0x2025 # 0 +0x0000A1AE 0xFE50 # 0 +0x0000A1AF 0xFE51 # 0 +0x0000A1B0 0xFE52 # 0 +0x0000A1B1 0x00B7 # 0 +0x0000A1B2 0xFE54 # 0 +0x0000A1B3 0xFE55 # 0 +0x0000A1B4 0xFE56 # 0 +0x0000A1B5 0xFE57 # 0 +0x0000A1B6 0xFE31 # 0 +0x0000A1B7 0x2014 # 0 +0x0000A1B8 0xFE32 # 0 +0x0000A1B9 0x2013 # 0 +0x0000A1BE 0xFF08 # 0 +0x0000A1BF 0xFF09 # 0 +0x0000A1C0 0xFE35 # 0 +0x0000A1C1 0xFE36 # 0 +0x0000A1C2 0xFF5B # 0 +0x0000A1C3 0xFF5D # 0 +0x0000A1C4 0xFE37 # 0 +0x0000A1C5 0xFE38 # 0 +0x0000A1C6 0x3014 # 0 +0x0000A1C7 0x3015 # 0 +0x0000A1C8 0xFE39 # 0 +0x0000A1C9 0xFE3A # 0 +0x0000A1CA 0x3010 # 0 +0x0000A1CB 0x3011 # 0 +0x0000A1CC 0xFE3B # 0 +0x0000A1CD 0xFE3C # 0 +0x0000A1CE 0x300A # 0 +0x0000A1CF 0x300B # 0 +0x0000A1D0 0xFE3D # 0 +0x0000A1D1 0xFE3E # 0 +0x0000A1D2 0x3008 # 0 +0x0000A1D3 0x3009 # 0 +0x0000A1D4 0xFE3F # 0 +0x0000A1D5 0xFE40 # 0 +0x0000A1D6 0x300C # 0 +0x0000A1D7 0x300D # 0 +0x0000A1D8 0xFE41 # 0 +0x0000A1D9 0xFE42 # 0 +0x0000A1DA 0x300E # 0 +0x0000A1DB 0x300F # 0 +0x0000A1DC 0xFE43 # 0 +0x0000A1DD 0xFE44 # 0 +0x0000A1DE 0xFE59 # 0 +0x0000A1DF 0xFE5A # 0 +0x0000A1E0 0xFE5B # 0 +0x0000A1E1 0xFE5C # 0 +0x0000A1E2 0xFE5D # 0 +0x0000A1E3 0xFE5E # 0 +0x0000A1E4 0x2018 # 0 +0x0000A1E5 0x2019 # 0 +0x0000A1E6 0x201C # 0 +0x0000A1E7 0x201D # 0 +0x0000A1E8 0x301D # 0 +0x0000A1E9 0x301E # 0 +0x0000A1EA 0x2032 # 0 +0x0000A1EB 0x2035 # 0 +0x0000A1EC 0xFF03 # 0 +0x0000A1ED 0xFF06 # 0 +0x0000A1EE 0xFF0A # 0 +0x0000A1EF 0x203B # 0 +0x0000A1F0 0x00A7 # 0 +0x0000A1F1 0x3003 # 0 +0x0000A1F2 0x25CB # 0 +0x0000A1F3 0x25CF # 0 +0x0000A1F4 0x25B3 # 0 +0x0000A1F5 0x25B2 # 0 +0x0000A1F6 0x25CE # 0 +0x0000A1F7 0x2606 # 0 +0x0000A1F8 0x2605 # 0 +0x0000A1F9 0x25C7 # 0 +0x0000A1FA 0x25C6 # 0 +0x0000A1FB 0x25A1 # 0 +0x0000A1FC 0x25A0 # 0 +0x0000A1FD 0x25BD # 0 +0x0000A1FE 0x25BC # 0 +0x0000A2A1 0x32A3 # 0 +0x0000A2A2 0x2105 # 0 +0x0000A2A3 0x203E # 0 +0x0000A2A5 0xFF3F # 0 +0x0000A2A7 0xFE49 # 0 +0x0000A2A8 0xFE4A # 0 +0x0000A2A9 0xFE4D # 0 +0x0000A2AA 0xFE4E # 0 +0x0000A2AB 0xFE4B # 0 +0x0000A2AC 0xFE4C # 0 +0x0000A2AD 0xFE5F # 0 +0x0000A2AE 0xFE60 # 0 +0x0000A2AF 0xFE61 # 0 +0x0000A2B0 0xFF0B # 0 +0x0000A2B1 0xFF0D # 0 +0x0000A2B2 0x00D7 # 0 +0x0000A2B3 0x00F7 # 0 +0x0000A2B4 0x00B1 # 0 +0x0000A2B5 0x221A # 0 +0x0000A2B6 0xFF1C # 0 +0x0000A2B7 0xFF1E # 0 +0x0000A2B8 0xFF1D # 0 +0x0000A2B9 0x2266 # 0 +0x0000A2BA 0x2267 # 0 +0x0000A2BB 0x2260 # 0 +0x0000A2BC 0x221E # 0 +0x0000A2BD 0x2252 # 0 +0x0000A2BE 0x2261 # 0 +0x0000A2BF 0xFE62 # 0 +0x0000A2C0 0xFE63 # 0 +0x0000A2C1 0xFE64 # 0 +0x0000A2C2 0xFE66 # 0 +0x0000A2C3 0xFE65 # 0 +0x0000A2C4 0x223C # 0 +0x0000A2C5 0x2229 # 0 +0x0000A2C6 0x222A # 0 +0x0000A2C7 0x22A5 # 0 +0x0000A2C8 0x2220 # 0 +0x0000A2C9 0x221F # 0 +0x0000A2CA 0x22BF # 0 +0x0000A2CB 0x33D2 # 0 +0x0000A2CC 0x33D1 # 0 +0x0000A2CD 0x222B # 0 +0x0000A2CE 0x222E # 0 +0x0000A2CF 0x2235 # 0 +0x0000A2D0 0x2234 # 0 +0x0000A2D1 0x2640 # 0 +0x0000A2D2 0x2642 # 0 +0x0000A2D3 0x2641 # 0 +0x0000A2D4 0x2609 # 0 +0x0000A2D5 0x2191 # 0 +0x0000A2D6 0x2193 # 0 +0x0000A2D7 0x2192 # 0 +0x0000A2D8 0x2190 # 0 +0x0000A2D9 0x2196 # 0 +0x0000A2DA 0x2197 # 0 +0x0000A2DB 0x2199 # 0 +0x0000A2DC 0x2198 # 0 +0x0000A2DD 0x2016 # 0 +0x0000A2DE 0xFF5C # 0 +0x0000A2DF 0xFF0F # 0 +0x0000A2E0 0xFF3C # 0 +0x0000A2E1 0x2215 # 0 +0x0000A2E2 0xFE68 # 0 +0x0000A2E3 0xFF04 # 0 +0x0000A2E4 0xFFE5 # 0 +0x0000A2E5 0x3012 # 0 +0x0000A2E6 0xFFE0 # 0 +0x0000A2E7 0xFFE1 # 0 +0x0000A2E8 0xFF05 # 0 +0x0000A2E9 0xFF20 # 0 +0x0000A2EA 0x2103 # 0 +0x0000A2EB 0x2109 # 0 +0x0000A2EC 0xFE69 # 0 +0x0000A2ED 0xFE6A # 0 +0x0000A2EE 0xFE6B # 0 +0x0000A2EF 0x33D5 # 0 +0x0000A2F0 0x339C # 0 +0x0000A2F1 0x339D # 0 +0x0000A2F2 0x339E # 0 +0x0000A2F3 0x33CE # 0 +0x0000A2F4 0x33A1 # 0 +0x0000A2F5 0x338E # 0 +0x0000A2F6 0x338F # 0 +0x0000A2F7 0x33C4 # 0 +0x0000A2F8 0x00B0 # 0 +0x0000A2F9 0x5159 # 0 +0x0000A2FA 0x515B # 0 +0x0000A2FB 0x515E # 0 +0x0000A2FC 0x515D # 0 +0x0000A2FD 0x5161 # 0 +0x0000A2FE 0x5163 # 0 +0x0000A3A1 0x55E7 # 0 +0x0000A3A2 0x74E9 # 0 +0x0000A3A3 0x7CCE # 0 +0x0000A3A4 0x2581 # 0 +0x0000A3A5 0x2582 # 0 +0x0000A3A6 0x2583 # 0 +0x0000A3A7 0x2584 # 0 +0x0000A3A8 0x2585 # 0 +0x0000A3A9 0x2586 # 0 +0x0000A3AA 0x2587 # 0 +0x0000A3AB 0x2588 # 0 +0x0000A3AC 0x258F # 0 +0x0000A3AD 0x258E # 0 +0x0000A3AE 0x258D # 0 +0x0000A3AF 0x258C # 0 +0x0000A3B0 0x258B # 0 +0x0000A3B1 0x258A # 0 +0x0000A3B2 0x2589 # 0 +0x0000A3B3 0x253C # 0 +0x0000A3B4 0x2534 # 0 +0x0000A3B5 0x252C # 0 +0x0000A3B6 0x2524 # 0 +0x0000A3B7 0x251C # 0 +0x0000A3B8 0x2594 # 0 +0x0000A3B9 0x2500 # 0 +0x0000A3BA 0x2502 # 0 +0x0000A3BB 0x2595 # 0 +0x0000A3BC 0x250C # 0 +0x0000A3BD 0x2510 # 0 +0x0000A3BE 0x2514 # 0 +0x0000A3BF 0x2518 # 0 +0x0000A3C0 0x256D # 0 +0x0000A3C1 0x256E # 0 +0x0000A3C2 0x2570 # 0 +0x0000A3C3 0x256F # 0 +0x0000A3C4 0x2550 # 0 +0x0000A3C5 0x255E # 0 +0x0000A3C6 0x256A # 0 +0x0000A3C7 0x2561 # 0 +0x0000A3C8 0x25E2 # 0 +0x0000A3C9 0x25E3 # 0 +0x0000A3CA 0x25E5 # 0 +0x0000A3CB 0x25E4 # 0 +0x0000A3CC 0x2571 # 0 +0x0000A3CD 0x2572 # 0 +0x0000A3CE 0x2573 # 0 +0x0000A4A1 0xFF10 # 0 +0x0000A4A2 0xFF11 # 0 +0x0000A4A3 0xFF12 # 0 +0x0000A4A4 0xFF13 # 0 +0x0000A4A5 0xFF14 # 0 +0x0000A4A6 0xFF15 # 0 +0x0000A4A7 0xFF16 # 0 +0x0000A4A8 0xFF17 # 0 +0x0000A4A9 0xFF18 # 0 +0x0000A4AA 0xFF19 # 0 +0x0000A4AB 0x2160 # 0 +0x0000A4AC 0x2161 # 0 +0x0000A4AD 0x2162 # 0 +0x0000A4AE 0x2163 # 0 +0x0000A4AF 0x2164 # 0 +0x0000A4B0 0x2165 # 0 +0x0000A4B1 0x2166 # 0 +0x0000A4B2 0x2167 # 0 +0x0000A4B3 0x2168 # 0 +0x0000A4B4 0x2169 # 0 +0x0000A4B5 0x3021 # 0 +0x0000A4B6 0x3022 # 0 +0x0000A4B7 0x3023 # 0 +0x0000A4B8 0x3024 # 0 +0x0000A4B9 0x3025 # 0 +0x0000A4BA 0x3026 # 0 +0x0000A4BB 0x3027 # 0 +0x0000A4BC 0x3028 # 0 +0x0000A4BD 0x3029 # 0 +0x0000A4BF 0x5344 # 0 +0x0000A4C1 0xFF21 # 0 +0x0000A4C2 0xFF22 # 0 +0x0000A4C3 0xFF23 # 0 +0x0000A4C4 0xFF24 # 0 +0x0000A4C5 0xFF25 # 0 +0x0000A4C6 0xFF26 # 0 +0x0000A4C7 0xFF27 # 0 +0x0000A4C8 0xFF28 # 0 +0x0000A4C9 0xFF29 # 0 +0x0000A4CA 0xFF2A # 0 +0x0000A4CB 0xFF2B # 0 +0x0000A4CC 0xFF2C # 0 +0x0000A4CD 0xFF2D # 0 +0x0000A4CE 0xFF2E # 0 +0x0000A4CF 0xFF2F # 0 +0x0000A4D0 0xFF30 # 0 +0x0000A4D1 0xFF31 # 0 +0x0000A4D2 0xFF32 # 0 +0x0000A4D3 0xFF33 # 0 +0x0000A4D4 0xFF34 # 0 +0x0000A4D5 0xFF35 # 0 +0x0000A4D6 0xFF36 # 0 +0x0000A4D7 0xFF37 # 0 +0x0000A4D8 0xFF38 # 0 +0x0000A4D9 0xFF39 # 0 +0x0000A4DA 0xFF3A # 0 +0x0000A4DB 0xFF41 # 0 +0x0000A4DC 0xFF42 # 0 +0x0000A4DD 0xFF43 # 0 +0x0000A4DE 0xFF44 # 0 +0x0000A4DF 0xFF45 # 0 +0x0000A4E0 0xFF46 # 0 +0x0000A4E1 0xFF47 # 0 +0x0000A4E2 0xFF48 # 0 +0x0000A4E3 0xFF49 # 0 +0x0000A4E4 0xFF4A # 0 +0x0000A4E5 0xFF4B # 0 +0x0000A4E6 0xFF4C # 0 +0x0000A4E7 0xFF4D # 0 +0x0000A4E8 0xFF4E # 0 +0x0000A4E9 0xFF4F # 0 +0x0000A4EA 0xFF50 # 0 +0x0000A4EB 0xFF51 # 0 +0x0000A4EC 0xFF52 # 0 +0x0000A4ED 0xFF53 # 0 +0x0000A4EE 0xFF54 # 0 +0x0000A4EF 0xFF55 # 0 +0x0000A4F0 0xFF56 # 0 +0x0000A4F1 0xFF57 # 0 +0x0000A4F2 0xFF58 # 0 +0x0000A4F3 0xFF59 # 0 +0x0000A4F4 0xFF5A # 0 +0x0000A4F5 0x0391 # 0 +0x0000A4F6 0x0392 # 0 +0x0000A4F7 0x0393 # 0 +0x0000A4F8 0x0394 # 0 +0x0000A4F9 0x0395 # 0 +0x0000A4FA 0x0396 # 0 +0x0000A4FB 0x0397 # 0 +0x0000A4FC 0x0398 # 0 +0x0000A4FD 0x0399 # 0 +0x0000A4FE 0x039A # 0 +0x0000A5A1 0x039B # 0 +0x0000A5A2 0x039C # 0 +0x0000A5A3 0x039D # 0 +0x0000A5A4 0x039E # 0 +0x0000A5A5 0x039F # 0 +0x0000A5A6 0x03A0 # 0 +0x0000A5A7 0x03A1 # 0 +0x0000A5A8 0x03A3 # 0 +0x0000A5A9 0x03A4 # 0 +0x0000A5AA 0x03A5 # 0 +0x0000A5AB 0x03A6 # 0 +0x0000A5AC 0x03A7 # 0 +0x0000A5AD 0x03A8 # 0 +0x0000A5AE 0x03A9 # 0 +0x0000A5AF 0x03B1 # 0 +0x0000A5B0 0x03B2 # 0 +0x0000A5B1 0x03B3 # 0 +0x0000A5B2 0x03B4 # 0 +0x0000A5B3 0x03B5 # 0 +0x0000A5B4 0x03B6 # 0 +0x0000A5B5 0x03B7 # 0 +0x0000A5B6 0x03B8 # 0 +0x0000A5B7 0x03B9 # 0 +0x0000A5B8 0x03BA # 0 +0x0000A5B9 0x03BB # 0 +0x0000A5BA 0x03BC # 0 +0x0000A5BB 0x03BD # 0 +0x0000A5BC 0x03BE # 0 +0x0000A5BD 0x03BF # 0 +0x0000A5BE 0x03C0 # 0 +0x0000A5BF 0x03C1 # 0 +0x0000A5C0 0x03C3 # 0 +0x0000A5C1 0x03C4 # 0 +0x0000A5C2 0x03C5 # 0 +0x0000A5C3 0x03C6 # 0 +0x0000A5C4 0x03C7 # 0 +0x0000A5C5 0x03C8 # 0 +0x0000A5C6 0x03C9 # 0 +0x0000A5C7 0x3105 # 0 +0x0000A5C8 0x3106 # 0 +0x0000A5C9 0x3107 # 0 +0x0000A5CA 0x3108 # 0 +0x0000A5CB 0x3109 # 0 +0x0000A5CC 0x310A # 0 +0x0000A5CD 0x310B # 0 +0x0000A5CE 0x310C # 0 +0x0000A5CF 0x310D # 0 +0x0000A5D0 0x310E # 0 +0x0000A5D1 0x310F # 0 +0x0000A5D2 0x3110 # 0 +0x0000A5D3 0x3111 # 0 +0x0000A5D4 0x3112 # 0 +0x0000A5D5 0x3113 # 0 +0x0000A5D6 0x3114 # 0 +0x0000A5D7 0x3115 # 0 +0x0000A5D8 0x3116 # 0 +0x0000A5D9 0x3117 # 0 +0x0000A5DA 0x3118 # 0 +0x0000A5DB 0x3119 # 0 +0x0000A5DC 0x311A # 0 +0x0000A5DD 0x311B # 0 +0x0000A5DE 0x311C # 0 +0x0000A5DF 0x311D # 0 +0x0000A5E0 0x311E # 0 +0x0000A5E1 0x311F # 0 +0x0000A5E2 0x3120 # 0 +0x0000A5E3 0x3121 # 0 +0x0000A5E4 0x3122 # 0 +0x0000A5E5 0x3123 # 0 +0x0000A5E6 0x3124 # 0 +0x0000A5E7 0x3125 # 0 +0x0000A5E8 0x3126 # 0 +0x0000A5E9 0x3127 # 0 +0x0000A5EA 0x3128 # 0 +0x0000A5EB 0x3129 # 0 +0x0000A5EC 0x02D9 # 0 +0x0000A5ED 0x02C9 # 0 +0x0000A5EE 0x02CA # 0 +0x0000A5EF 0x02C7 # 0 +0x0000A5F0 0x02CB # 0 +0x0000A6A1 0x2460 # 0 +0x0000A6A2 0x2461 # 0 +0x0000A6A3 0x2462 # 0 +0x0000A6A4 0x2463 # 0 +0x0000A6A5 0x2464 # 0 +0x0000A6A6 0x2465 # 0 +0x0000A6A7 0x2466 # 0 +0x0000A6A8 0x2467 # 0 +0x0000A6A9 0x2468 # 0 +0x0000A6AA 0x2469 # 0 +0x0000A6AB 0x2474 # 0 +0x0000A6AC 0x2475 # 0 +0x0000A6AD 0x2476 # 0 +0x0000A6AE 0x2477 # 0 +0x0000A6AF 0x2478 # 0 +0x0000A6B0 0x2479 # 0 +0x0000A6B1 0x247A # 0 +0x0000A6B2 0x247B # 0 +0x0000A6B3 0x247C # 0 +0x0000A6B4 0x247D # 0 +0x0000A6B5 0x2170 # 0 +0x0000A6B6 0x2171 # 0 +0x0000A6B7 0x2172 # 0 +0x0000A6B8 0x2173 # 0 +0x0000A6B9 0x2174 # 0 +0x0000A6BA 0x2175 # 0 +0x0000A6BB 0x2176 # 0 +0x0000A6BC 0x2177 # 0 +0x0000A6BD 0x2178 # 0 +0x0000A6BE 0x2179 # 0 +0x0000C2A1 0x2400 # 0 +0x0000C2A2 0x2401 # 0 +0x0000C2A3 0x2402 # 0 +0x0000C2A4 0x2403 # 0 +0x0000C2A5 0x2404 # 0 +0x0000C2A6 0x2405 # 0 +0x0000C2A7 0x2406 # 0 +0x0000C2A8 0x2407 # 0 +0x0000C2A9 0x2408 # 0 +0x0000C2AA 0x2409 # 0 +0x0000C2AB 0x240A # 0 +0x0000C2AC 0x240B # 0 +0x0000C2AD 0x240C # 0 +0x0000C2AE 0x240D # 0 +0x0000C2AF 0x240E # 0 +0x0000C2B0 0x240F # 0 +0x0000C2B1 0x2410 # 0 +0x0000C2B2 0x2411 # 0 +0x0000C2B3 0x2412 # 0 +0x0000C2B4 0x2413 # 0 +0x0000C2B5 0x2414 # 0 +0x0000C2B6 0x2415 # 0 +0x0000C2B7 0x2416 # 0 +0x0000C2B8 0x2417 # 0 +0x0000C2B9 0x2418 # 0 +0x0000C2BA 0x2419 # 0 +0x0000C2BB 0x241A # 0 +0x0000C2BC 0x241B # 0 +0x0000C2BD 0x241C # 0 +0x0000C2BE 0x241D # 0 +0x0000C2BF 0x241E # 0 +0x0000C2C0 0x241F # 0 +0x0000C2C1 0x2421 # 0 +0x0000C4A1 0x4E00 # 0 +0x0000C4A2 0x4E59 # 0 +0x0000C4A3 0x4E01 # 0 +0x0000C4A4 0x4E03 # 0 +0x0000C4A5 0x4E43 # 0 +0x0000C4A6 0x4E5D # 0 +0x0000C4A7 0x4E86 # 0 +0x0000C4A8 0x4E8C # 0 +0x0000C4A9 0x4EBA # 0 +0x0000C4AA 0x513F # 0 +0x0000C4AB 0x5165 # 0 +0x0000C4AC 0x516B # 0 +0x0000C4AD 0x51E0 # 0 +0x0000C4AE 0x5200 # 0 +0x0000C4AF 0x5201 # 0 +0x0000C4B0 0x529B # 0 +0x0000C4B1 0x5315 # 0 +0x0000C4B2 0x5341 # 0 +0x0000C4B3 0x535C # 0 +0x0000C4B4 0x53C8 # 0 +0x0000C4B5 0x4E09 # 0 +0x0000C4B6 0x4E0B # 0 +0x0000C4B7 0x4E08 # 0 +0x0000C4B8 0x4E0A # 0 +0x0000C4B9 0x4E2B # 0 +0x0000C4BA 0x4E38 # 0 +0x0000C4BB 0x51E1 # 0 +0x0000C4BC 0x4E45 # 0 +0x0000C4BD 0x4E48 # 0 +0x0000C4BE 0x4E5F # 0 +0x0000C4BF 0x4E5E # 0 +0x0000C4C0 0x4E8E # 0 +0x0000C4C1 0x4EA1 # 0 +0x0000C4C2 0x5140 # 0 +0x0000C4C3 0x5203 # 0 +0x0000C4C4 0x52FA # 0 +0x0000C4C5 0x5343 # 0 +0x0000C4C6 0x53C9 # 0 +0x0000C4C7 0x53E3 # 0 +0x0000C4C8 0x571F # 0 +0x0000C4C9 0x58EB # 0 +0x0000C4CA 0x5915 # 0 +0x0000C4CB 0x5927 # 0 +0x0000C4CC 0x5973 # 0 +0x0000C4CD 0x5B50 # 0 +0x0000C4CE 0x5B51 # 0 +0x0000C4CF 0x5B53 # 0 +0x0000C4D0 0x5BF8 # 0 +0x0000C4D1 0x5C0F # 0 +0x0000C4D2 0x5C22 # 0 +0x0000C4D3 0x5C38 # 0 +0x0000C4D4 0x5C71 # 0 +0x0000C4D5 0x5DDD # 0 +0x0000C4D6 0x5DE5 # 0 +0x0000C4D7 0x5DF1 # 0 +0x0000C4D8 0x5DF2 # 0 +0x0000C4D9 0x5DF3 # 0 +0x0000C4DA 0x5DFE # 0 +0x0000C4DB 0x5E72 # 0 +0x0000C4DC 0x5EFE # 0 +0x0000C4DD 0x5F0B # 0 +0x0000C4DE 0x5F13 # 0 +0x0000C4DF 0x624D # 0 +0x0000C4E0 0x4E11 # 0 +0x0000C4E1 0x4E10 # 0 +0x0000C4E2 0x4E0D # 0 +0x0000C4E3 0x4E2D # 0 +0x0000C4E4 0x4E30 # 0 +0x0000C4E5 0x4E39 # 0 +0x0000C4E6 0x4E4B # 0 +0x0000C4E7 0x5C39 # 0 +0x0000C4E8 0x4E88 # 0 +0x0000C4E9 0x4E91 # 0 +0x0000C4EA 0x4E95 # 0 +0x0000C4EB 0x4E92 # 0 +0x0000C4EC 0x4E94 # 0 +0x0000C4ED 0x4EA2 # 0 +0x0000C4EE 0x4EC1 # 0 +0x0000C4EF 0x4EC0 # 0 +0x0000C4F0 0x4EC3 # 0 +0x0000C4F1 0x4EC6 # 0 +0x0000C4F2 0x4EC7 # 0 +0x0000C4F3 0x4ECD # 0 +0x0000C4F4 0x4ECA # 0 +0x0000C4F5 0x4ECB # 0 +0x0000C4F6 0x4EC4 # 0 +0x0000C4F7 0x5143 # 0 +0x0000C4F8 0x5141 # 0 +0x0000C4F9 0x5167 # 0 +0x0000C4FA 0x516D # 0 +0x0000C4FB 0x516E # 0 +0x0000C4FC 0x516C # 0 +0x0000C4FD 0x5197 # 0 +0x0000C4FE 0x51F6 # 0 +0x0000C5A1 0x5206 # 0 +0x0000C5A2 0x5207 # 0 +0x0000C5A3 0x5208 # 0 +0x0000C5A4 0x52FB # 0 +0x0000C5A5 0x52FE # 0 +0x0000C5A6 0x52FF # 0 +0x0000C5A7 0x5316 # 0 +0x0000C5A8 0x5339 # 0 +0x0000C5A9 0x5348 # 0 +0x0000C5AA 0x5347 # 0 +0x0000C5AB 0x5345 # 0 +0x0000C5AC 0x535E # 0 +0x0000C5AD 0x5384 # 0 +0x0000C5AE 0x53CB # 0 +0x0000C5AF 0x53CA # 0 +0x0000C5B0 0x53CD # 0 +0x0000C5B1 0x58EC # 0 +0x0000C5B2 0x5929 # 0 +0x0000C5B3 0x592B # 0 +0x0000C5B4 0x592A # 0 +0x0000C5B5 0x592D # 0 +0x0000C5B6 0x5B54 # 0 +0x0000C5B7 0x5C11 # 0 +0x0000C5B8 0x5C24 # 0 +0x0000C5B9 0x5C3A # 0 +0x0000C5BA 0x5C6F # 0 +0x0000C5BB 0x5DF4 # 0 +0x0000C5BC 0x5E7B # 0 +0x0000C5BD 0x5EFF # 0 +0x0000C5BE 0x5F14 # 0 +0x0000C5BF 0x5F15 # 0 +0x0000C5C0 0x5FC3 # 0 +0x0000C5C1 0x6208 # 0 +0x0000C5C2 0x6236 # 0 +0x0000C5C3 0x624B # 0 +0x0000C5C4 0x624E # 0 +0x0000C5C5 0x652F # 0 +0x0000C5C6 0x6587 # 0 +0x0000C5C7 0x6597 # 0 +0x0000C5C8 0x65A4 # 0 +0x0000C5C9 0x65B9 # 0 +0x0000C5CA 0x65E5 # 0 +0x0000C5CB 0x66F0 # 0 +0x0000C5CC 0x6708 # 0 +0x0000C5CD 0x6728 # 0 +0x0000C5CE 0x6B20 # 0 +0x0000C5CF 0x6B62 # 0 +0x0000C5D0 0x6B79 # 0 +0x0000C5D1 0x6BCB # 0 +0x0000C5D2 0x6BD4 # 0 +0x0000C5D3 0x6BDB # 0 +0x0000C5D4 0x6C0F # 0 +0x0000C5D5 0x6C34 # 0 +0x0000C5D6 0x706B # 0 +0x0000C5D7 0x722A # 0 +0x0000C5D8 0x7236 # 0 +0x0000C5D9 0x723B # 0 +0x0000C5DA 0x7247 # 0 +0x0000C5DB 0x7259 # 0 +0x0000C5DC 0x725B # 0 +0x0000C5DD 0x72AC # 0 +0x0000C5DE 0x738B # 0 +0x0000C5DF 0x4E19 # 0 +0x0000C5E0 0x4E16 # 0 +0x0000C5E1 0x4E15 # 0 +0x0000C5E2 0x4E14 # 0 +0x0000C5E3 0x4E18 # 0 +0x0000C5E4 0x4E3B # 0 +0x0000C5E5 0x4E4D # 0 +0x0000C5E6 0x4E4F # 0 +0x0000C5E7 0x4E4E # 0 +0x0000C5E8 0x4EE5 # 0 +0x0000C5E9 0x4ED8 # 0 +0x0000C5EA 0x4ED4 # 0 +0x0000C5EB 0x4ED5 # 0 +0x0000C5EC 0x4ED6 # 0 +0x0000C5ED 0x4ED7 # 0 +0x0000C5EE 0x4EE3 # 0 +0x0000C5EF 0x4EE4 # 0 +0x0000C5F0 0x4ED9 # 0 +0x0000C5F1 0x4EDE # 0 +0x0000C5F2 0x5145 # 0 +0x0000C5F3 0x5144 # 0 +0x0000C5F4 0x5189 # 0 +0x0000C5F5 0x518A # 0 +0x0000C5F6 0x51AC # 0 +0x0000C5F7 0x51F9 # 0 +0x0000C5F8 0x51FA # 0 +0x0000C5F9 0x51F8 # 0 +0x0000C5FA 0x520A # 0 +0x0000C5FB 0x52A0 # 0 +0x0000C5FC 0x529F # 0 +0x0000C5FD 0x5305 # 0 +0x0000C5FE 0x5306 # 0 +0x0000C6A1 0x5317 # 0 +0x0000C6A2 0x531D # 0 +0x0000C6A3 0x4EDF # 0 +0x0000C6A4 0x534A # 0 +0x0000C6A5 0x5349 # 0 +0x0000C6A6 0x5361 # 0 +0x0000C6A7 0x5360 # 0 +0x0000C6A8 0x536F # 0 +0x0000C6A9 0x536E # 0 +0x0000C6AA 0x53BB # 0 +0x0000C6AB 0x53EF # 0 +0x0000C6AC 0x53E4 # 0 +0x0000C6AD 0x53F3 # 0 +0x0000C6AE 0x53EC # 0 +0x0000C6AF 0x53EE # 0 +0x0000C6B0 0x53E9 # 0 +0x0000C6B1 0x53E8 # 0 +0x0000C6B2 0x53FC # 0 +0x0000C6B3 0x53F8 # 0 +0x0000C6B4 0x53F5 # 0 +0x0000C6B5 0x53EB # 0 +0x0000C6B6 0x53E6 # 0 +0x0000C6B7 0x53EA # 0 +0x0000C6B8 0x53F2 # 0 +0x0000C6B9 0x53F1 # 0 +0x0000C6BA 0x53F0 # 0 +0x0000C6BB 0x53E5 # 0 +0x0000C6BC 0x53ED # 0 +0x0000C6BD 0x53FB # 0 +0x0000C6BE 0x56DB # 0 +0x0000C6BF 0x56DA # 0 +0x0000C6C0 0x5916 # 0 +0x0000C6C1 0x592E # 0 +0x0000C6C2 0x5931 # 0 +0x0000C6C3 0x5974 # 0 +0x0000C6C4 0x5976 # 0 +0x0000C6C5 0x5B55 # 0 +0x0000C6C6 0x5B83 # 0 +0x0000C6C7 0x5C3C # 0 +0x0000C6C8 0x5DE8 # 0 +0x0000C6C9 0x5DE7 # 0 +0x0000C6CA 0x5DE6 # 0 +0x0000C6CB 0x5E02 # 0 +0x0000C6CC 0x5E03 # 0 +0x0000C6CD 0x5E73 # 0 +0x0000C6CE 0x5E7C # 0 +0x0000C6CF 0x5F01 # 0 +0x0000C6D0 0x5F18 # 0 +0x0000C6D1 0x5F17 # 0 +0x0000C6D2 0x5FC5 # 0 +0x0000C6D3 0x620A # 0 +0x0000C6D4 0x6253 # 0 +0x0000C6D5 0x6254 # 0 +0x0000C6D6 0x6252 # 0 +0x0000C6D7 0x6251 # 0 +0x0000C6D8 0x65A5 # 0 +0x0000C6D9 0x65E6 # 0 +0x0000C6DA 0x672E # 0 +0x0000C6DB 0x672C # 0 +0x0000C6DC 0x672A # 0 +0x0000C6DD 0x672B # 0 +0x0000C6DE 0x672D # 0 +0x0000C6DF 0x6B63 # 0 +0x0000C6E0 0x6BCD # 0 +0x0000C6E1 0x6C11 # 0 +0x0000C6E2 0x6C10 # 0 +0x0000C6E3 0x6C38 # 0 +0x0000C6E4 0x6C41 # 0 +0x0000C6E5 0x6C40 # 0 +0x0000C6E6 0x6C3E # 0 +0x0000C6E7 0x72AF # 0 +0x0000C6E8 0x7384 # 0 +0x0000C6E9 0x7389 # 0 +0x0000C6EA 0x74DC # 0 +0x0000C6EB 0x74E6 # 0 +0x0000C6EC 0x7518 # 0 +0x0000C6ED 0x751F # 0 +0x0000C6EE 0x7528 # 0 +0x0000C6EF 0x7529 # 0 +0x0000C6F0 0x7530 # 0 +0x0000C6F1 0x7531 # 0 +0x0000C6F2 0x7532 # 0 +0x0000C6F3 0x7533 # 0 +0x0000C6F4 0x758B # 0 +0x0000C6F5 0x767D # 0 +0x0000C6F6 0x76AE # 0 +0x0000C6F7 0x76BF # 0 +0x0000C6F8 0x76EE # 0 +0x0000C6F9 0x77DB # 0 +0x0000C6FA 0x77E2 # 0 +0x0000C6FB 0x77F3 # 0 +0x0000C6FC 0x793A # 0 +0x0000C6FD 0x79BE # 0 +0x0000C6FE 0x7A74 # 0 +0x0000C7A1 0x7ACB # 0 +0x0000C7A2 0x4E1E # 0 +0x0000C7A3 0x4E1F # 0 +0x0000C7A4 0x4E52 # 0 +0x0000C7A5 0x4E53 # 0 +0x0000C7A6 0x4E69 # 0 +0x0000C7A7 0x4E99 # 0 +0x0000C7A8 0x4EA4 # 0 +0x0000C7A9 0x4EA6 # 0 +0x0000C7AA 0x4EA5 # 0 +0x0000C7AB 0x4EFF # 0 +0x0000C7AC 0x4F09 # 0 +0x0000C7AD 0x4F19 # 0 +0x0000C7AE 0x4F0A # 0 +0x0000C7AF 0x4F15 # 0 +0x0000C7B0 0x4F0D # 0 +0x0000C7B1 0x4F10 # 0 +0x0000C7B2 0x4F11 # 0 +0x0000C7B3 0x4F0F # 0 +0x0000C7B4 0x4EF2 # 0 +0x0000C7B5 0x4EF6 # 0 +0x0000C7B6 0x4EFB # 0 +0x0000C7B7 0x4EF0 # 0 +0x0000C7B8 0x4EF3 # 0 +0x0000C7B9 0x4EFD # 0 +0x0000C7BA 0x4F01 # 0 +0x0000C7BB 0x4F0B # 0 +0x0000C7BC 0x5149 # 0 +0x0000C7BD 0x5147 # 0 +0x0000C7BE 0x5146 # 0 +0x0000C7BF 0x5148 # 0 +0x0000C7C0 0x5168 # 0 +0x0000C7C1 0x5171 # 0 +0x0000C7C2 0x518D # 0 +0x0000C7C3 0x51B0 # 0 +0x0000C7C4 0x5217 # 0 +0x0000C7C5 0x5211 # 0 +0x0000C7C6 0x5212 # 0 +0x0000C7C7 0x520E # 0 +0x0000C7C8 0x5216 # 0 +0x0000C7C9 0x52A3 # 0 +0x0000C7CA 0x5308 # 0 +0x0000C7CB 0x5321 # 0 +0x0000C7CC 0x5320 # 0 +0x0000C7CD 0x5370 # 0 +0x0000C7CE 0x5371 # 0 +0x0000C7CF 0x5409 # 0 +0x0000C7D0 0x540F # 0 +0x0000C7D1 0x540C # 0 +0x0000C7D2 0x540A # 0 +0x0000C7D3 0x5410 # 0 +0x0000C7D4 0x5401 # 0 +0x0000C7D5 0x540B # 0 +0x0000C7D6 0x5404 # 0 +0x0000C7D7 0x5411 # 0 +0x0000C7D8 0x540D # 0 +0x0000C7D9 0x5408 # 0 +0x0000C7DA 0x5403 # 0 +0x0000C7DB 0x540E # 0 +0x0000C7DC 0x5406 # 0 +0x0000C7DD 0x5412 # 0 +0x0000C7DE 0x56E0 # 0 +0x0000C7DF 0x56DE # 0 +0x0000C7E0 0x56DD # 0 +0x0000C7E1 0x5733 # 0 +0x0000C7E2 0x5730 # 0 +0x0000C7E3 0x5728 # 0 +0x0000C7E4 0x572D # 0 +0x0000C7E5 0x572C # 0 +0x0000C7E6 0x572F # 0 +0x0000C7E7 0x5729 # 0 +0x0000C7E8 0x5919 # 0 +0x0000C7E9 0x591A # 0 +0x0000C7EA 0x5937 # 0 +0x0000C7EB 0x5938 # 0 +0x0000C7EC 0x5984 # 0 +0x0000C7ED 0x5978 # 0 +0x0000C7EE 0x5983 # 0 +0x0000C7EF 0x597D # 0 +0x0000C7F0 0x5979 # 0 +0x0000C7F1 0x5982 # 0 +0x0000C7F2 0x5981 # 0 +0x0000C7F3 0x5B57 # 0 +0x0000C7F4 0x5B58 # 0 +0x0000C7F5 0x5B87 # 0 +0x0000C7F6 0x5B88 # 0 +0x0000C7F7 0x5B85 # 0 +0x0000C7F8 0x5B89 # 0 +0x0000C7F9 0x5BFA # 0 +0x0000C7FA 0x5C16 # 0 +0x0000C7FB 0x5C79 # 0 +0x0000C7FC 0x5DDE # 0 +0x0000C7FD 0x5E06 # 0 +0x0000C7FE 0x5E76 # 0 +0x0000C8A1 0x5E74 # 0 +0x0000C8A2 0x5F0F # 0 +0x0000C8A3 0x5F1B # 0 +0x0000C8A4 0x5FD9 # 0 +0x0000C8A5 0x5FD6 # 0 +0x0000C8A6 0x620E # 0 +0x0000C8A7 0x620C # 0 +0x0000C8A8 0x620D # 0 +0x0000C8A9 0x6210 # 0 +0x0000C8AA 0x6263 # 0 +0x0000C8AB 0x625B # 0 +0x0000C8AC 0x6258 # 0 +0x0000C8AD 0x6536 # 0 +0x0000C8AE 0x65E9 # 0 +0x0000C8AF 0x65E8 # 0 +0x0000C8B0 0x65EC # 0 +0x0000C8B1 0x65ED # 0 +0x0000C8B2 0x66F2 # 0 +0x0000C8B3 0x66F3 # 0 +0x0000C8B4 0x6709 # 0 +0x0000C8B5 0x673D # 0 +0x0000C8B6 0x6734 # 0 +0x0000C8B7 0x6731 # 0 +0x0000C8B8 0x6735 # 0 +0x0000C8B9 0x6B21 # 0 +0x0000C8BA 0x6B64 # 0 +0x0000C8BB 0x6B7B # 0 +0x0000C8BC 0x6C16 # 0 +0x0000C8BD 0x6C5D # 0 +0x0000C8BE 0x6C57 # 0 +0x0000C8BF 0x6C59 # 0 +0x0000C8C0 0x6C5F # 0 +0x0000C8C1 0x6C60 # 0 +0x0000C8C2 0x6C50 # 0 +0x0000C8C3 0x6C55 # 0 +0x0000C8C4 0x6C61 # 0 +0x0000C8C5 0x6C5B # 0 +0x0000C8C6 0x6C4D # 0 +0x0000C8C7 0x6C4E # 0 +0x0000C8C8 0x7070 # 0 +0x0000C8C9 0x725F # 0 +0x0000C8CA 0x725D # 0 +0x0000C8CB 0x767E # 0 +0x0000C8CC 0x7AF9 # 0 +0x0000C8CD 0x7C73 # 0 +0x0000C8CE 0x7CF8 # 0 +0x0000C8CF 0x7F36 # 0 +0x0000C8D0 0x7F8A # 0 +0x0000C8D1 0x7FBD # 0 +0x0000C8D2 0x8001 # 0 +0x0000C8D3 0x8003 # 0 +0x0000C8D4 0x800C # 0 +0x0000C8D5 0x8012 # 0 +0x0000C8D6 0x8033 # 0 +0x0000C8D7 0x807F # 0 +0x0000C8D8 0x8089 # 0 +0x0000C8D9 0x808B # 0 +0x0000C8DA 0x808C # 0 +0x0000C8DB 0x81E3 # 0 +0x0000C8DC 0x81EA # 0 +0x0000C8DD 0x81F3 # 0 +0x0000C8DE 0x81FC # 0 +0x0000C8DF 0x820C # 0 +0x0000C8E0 0x821B # 0 +0x0000C8E1 0x821F # 0 +0x0000C8E2 0x826E # 0 +0x0000C8E3 0x8272 # 0 +0x0000C8E4 0x827E # 0 +0x0000C8E5 0x866B # 0 +0x0000C8E6 0x8840 # 0 +0x0000C8E7 0x884C # 0 +0x0000C8E8 0x8863 # 0 +0x0000C8E9 0x897F # 0 +0x0000C8EA 0x9621 # 0 +0x0000C8EB 0x4E32 # 0 +0x0000C8EC 0x4EA8 # 0 +0x0000C8ED 0x4F4D # 0 +0x0000C8EE 0x4F4F # 0 +0x0000C8EF 0x4F47 # 0 +0x0000C8F0 0x4F57 # 0 +0x0000C8F1 0x4F5E # 0 +0x0000C8F2 0x4F34 # 0 +0x0000C8F3 0x4F5B # 0 +0x0000C8F4 0x4F55 # 0 +0x0000C8F5 0x4F30 # 0 +0x0000C8F6 0x4F50 # 0 +0x0000C8F7 0x4F51 # 0 +0x0000C8F8 0x4F3D # 0 +0x0000C8F9 0x4F3A # 0 +0x0000C8FA 0x4F38 # 0 +0x0000C8FB 0x4F43 # 0 +0x0000C8FC 0x4F54 # 0 +0x0000C8FD 0x4F3C # 0 +0x0000C8FE 0x4F46 # 0 +0x0000C9A1 0x4F63 # 0 +0x0000C9A2 0x4F5C # 0 +0x0000C9A3 0x4F60 # 0 +0x0000C9A4 0x4F2F # 0 +0x0000C9A5 0x4F4E # 0 +0x0000C9A6 0x4F36 # 0 +0x0000C9A7 0x4F59 # 0 +0x0000C9A8 0x4F5D # 0 +0x0000C9A9 0x4F48 # 0 +0x0000C9AA 0x4F5A # 0 +0x0000C9AB 0x514C # 0 +0x0000C9AC 0x514B # 0 +0x0000C9AD 0x514D # 0 +0x0000C9AE 0x5175 # 0 +0x0000C9AF 0x51B6 # 0 +0x0000C9B0 0x51B7 # 0 +0x0000C9B1 0x5225 # 0 +0x0000C9B2 0x5224 # 0 +0x0000C9B3 0x5229 # 0 +0x0000C9B4 0x522A # 0 +0x0000C9B5 0x5228 # 0 +0x0000C9B6 0x52AB # 0 +0x0000C9B7 0x52A9 # 0 +0x0000C9B8 0x52AA # 0 +0x0000C9B9 0x52AC # 0 +0x0000C9BA 0x5323 # 0 +0x0000C9BB 0x5373 # 0 +0x0000C9BC 0x5375 # 0 +0x0000C9BD 0x541D # 0 +0x0000C9BE 0x542D # 0 +0x0000C9BF 0x541E # 0 +0x0000C9C0 0x543E # 0 +0x0000C9C1 0x5426 # 0 +0x0000C9C2 0x544E # 0 +0x0000C9C3 0x5427 # 0 +0x0000C9C4 0x5446 # 0 +0x0000C9C5 0x5443 # 0 +0x0000C9C6 0x5433 # 0 +0x0000C9C7 0x5448 # 0 +0x0000C9C8 0x5442 # 0 +0x0000C9C9 0x541B # 0 +0x0000C9CA 0x5429 # 0 +0x0000C9CB 0x544A # 0 +0x0000C9CC 0x5439 # 0 +0x0000C9CD 0x543B # 0 +0x0000C9CE 0x5438 # 0 +0x0000C9CF 0x542E # 0 +0x0000C9D0 0x5435 # 0 +0x0000C9D1 0x5436 # 0 +0x0000C9D2 0x5420 # 0 +0x0000C9D3 0x543C # 0 +0x0000C9D4 0x5440 # 0 +0x0000C9D5 0x5431 # 0 +0x0000C9D6 0x542B # 0 +0x0000C9D7 0x541F # 0 +0x0000C9D8 0x542C # 0 +0x0000C9D9 0x56EA # 0 +0x0000C9DA 0x56F0 # 0 +0x0000C9DB 0x56E4 # 0 +0x0000C9DC 0x56EB # 0 +0x0000C9DD 0x574A # 0 +0x0000C9DE 0x5751 # 0 +0x0000C9DF 0x5740 # 0 +0x0000C9E0 0x574D # 0 +0x0000C9E1 0x5747 # 0 +0x0000C9E2 0x574E # 0 +0x0000C9E3 0x573E # 0 +0x0000C9E4 0x5750 # 0 +0x0000C9E5 0x574F # 0 +0x0000C9E6 0x573B # 0 +0x0000C9E7 0x58EF # 0 +0x0000C9E8 0x593E # 0 +0x0000C9E9 0x599D # 0 +0x0000C9EA 0x5992 # 0 +0x0000C9EB 0x59A8 # 0 +0x0000C9EC 0x599E # 0 +0x0000C9ED 0x59A3 # 0 +0x0000C9EE 0x5999 # 0 +0x0000C9EF 0x5996 # 0 +0x0000C9F0 0x598D # 0 +0x0000C9F1 0x59A4 # 0 +0x0000C9F2 0x5993 # 0 +0x0000C9F3 0x598A # 0 +0x0000C9F4 0x59A5 # 0 +0x0000C9F5 0x5B5D # 0 +0x0000C9F6 0x5B5C # 0 +0x0000C9F7 0x5B5A # 0 +0x0000C9F8 0x5B5B # 0 +0x0000C9F9 0x5B8C # 0 +0x0000C9FA 0x5B8B # 0 +0x0000C9FB 0x5B8F # 0 +0x0000C9FC 0x5C2C # 0 +0x0000C9FD 0x5C40 # 0 +0x0000C9FE 0x5C41 # 0 +0x0000CAA1 0x5C3F # 0 +0x0000CAA2 0x5C3E # 0 +0x0000CAA3 0x5C90 # 0 +0x0000CAA4 0x5C91 # 0 +0x0000CAA5 0x5C94 # 0 +0x0000CAA6 0x5C8C # 0 +0x0000CAA7 0x5DEB # 0 +0x0000CAA8 0x5E0C # 0 +0x0000CAA9 0x5E8F # 0 +0x0000CAAA 0x5E87 # 0 +0x0000CAAB 0x5E8A # 0 +0x0000CAAC 0x5EF7 # 0 +0x0000CAAD 0x5F04 # 0 +0x0000CAAE 0x5F1F # 0 +0x0000CAAF 0x5F64 # 0 +0x0000CAB0 0x5F62 # 0 +0x0000CAB1 0x5F77 # 0 +0x0000CAB2 0x5F79 # 0 +0x0000CAB3 0x5FD8 # 0 +0x0000CAB4 0x5FCC # 0 +0x0000CAB5 0x5FD7 # 0 +0x0000CAB6 0x5FCD # 0 +0x0000CAB7 0x5FF1 # 0 +0x0000CAB8 0x5FEB # 0 +0x0000CAB9 0x5FF8 # 0 +0x0000CABA 0x5FEA # 0 +0x0000CABB 0x6212 # 0 +0x0000CABC 0x6211 # 0 +0x0000CABD 0x6284 # 0 +0x0000CABE 0x6297 # 0 +0x0000CABF 0x6296 # 0 +0x0000CAC0 0x6280 # 0 +0x0000CAC1 0x6276 # 0 +0x0000CAC2 0x6289 # 0 +0x0000CAC3 0x626D # 0 +0x0000CAC4 0x628A # 0 +0x0000CAC5 0x627C # 0 +0x0000CAC6 0x627E # 0 +0x0000CAC7 0x6279 # 0 +0x0000CAC8 0x6273 # 0 +0x0000CAC9 0x6292 # 0 +0x0000CACA 0x626F # 0 +0x0000CACB 0x6298 # 0 +0x0000CACC 0x626E # 0 +0x0000CACD 0x6295 # 0 +0x0000CACE 0x6293 # 0 +0x0000CACF 0x6291 # 0 +0x0000CAD0 0x6286 # 0 +0x0000CAD1 0x6539 # 0 +0x0000CAD2 0x653B # 0 +0x0000CAD3 0x6538 # 0 +0x0000CAD4 0x65F1 # 0 +0x0000CAD5 0x66F4 # 0 +0x0000CAD6 0x675F # 0 +0x0000CAD7 0x674E # 0 +0x0000CAD8 0x674F # 0 +0x0000CAD9 0x6750 # 0 +0x0000CADA 0x6751 # 0 +0x0000CADB 0x675C # 0 +0x0000CADC 0x6756 # 0 +0x0000CADD 0x675E # 0 +0x0000CADE 0x6749 # 0 +0x0000CADF 0x6746 # 0 +0x0000CAE0 0x6760 # 0 +0x0000CAE1 0x6753 # 0 +0x0000CAE2 0x6757 # 0 +0x0000CAE3 0x6B65 # 0 +0x0000CAE4 0x6BCF # 0 +0x0000CAE5 0x6C42 # 0 +0x0000CAE6 0x6C5E # 0 +0x0000CAE7 0x6C99 # 0 +0x0000CAE8 0x6C81 # 0 +0x0000CAE9 0x6C88 # 0 +0x0000CAEA 0x6C89 # 0 +0x0000CAEB 0x6C85 # 0 +0x0000CAEC 0x6C9B # 0 +0x0000CAED 0x6C6A # 0 +0x0000CAEE 0x6C7A # 0 +0x0000CAEF 0x6C90 # 0 +0x0000CAF0 0x6C70 # 0 +0x0000CAF1 0x6C8C # 0 +0x0000CAF2 0x6C68 # 0 +0x0000CAF3 0x6C96 # 0 +0x0000CAF4 0x6C92 # 0 +0x0000CAF5 0x6C7D # 0 +0x0000CAF6 0x6C83 # 0 +0x0000CAF7 0x6C72 # 0 +0x0000CAF8 0x6C7E # 0 +0x0000CAF9 0x6C74 # 0 +0x0000CAFA 0x6C86 # 0 +0x0000CAFB 0x6C76 # 0 +0x0000CAFC 0x6C8D # 0 +0x0000CAFD 0x6C94 # 0 +0x0000CAFE 0x6C98 # 0 +0x0000CBA1 0x6C82 # 0 +0x0000CBA2 0x7076 # 0 +0x0000CBA3 0x707C # 0 +0x0000CBA4 0x707D # 0 +0x0000CBA5 0x7078 # 0 +0x0000CBA6 0x7262 # 0 +0x0000CBA7 0x7261 # 0 +0x0000CBA8 0x7260 # 0 +0x0000CBA9 0x72C4 # 0 +0x0000CBAA 0x72C2 # 0 +0x0000CBAB 0x7396 # 0 +0x0000CBAC 0x752C # 0 +0x0000CBAD 0x752B # 0 +0x0000CBAE 0x7537 # 0 +0x0000CBAF 0x7538 # 0 +0x0000CBB0 0x7682 # 0 +0x0000CBB1 0x76EF # 0 +0x0000CBB2 0x77E3 # 0 +0x0000CBB3 0x79C1 # 0 +0x0000CBB4 0x79C0 # 0 +0x0000CBB5 0x79BF # 0 +0x0000CBB6 0x7A76 # 0 +0x0000CBB7 0x7CFB # 0 +0x0000CBB8 0x7F55 # 0 +0x0000CBB9 0x8096 # 0 +0x0000CBBA 0x8093 # 0 +0x0000CBBB 0x809D # 0 +0x0000CBBC 0x8098 # 0 +0x0000CBBD 0x809B # 0 +0x0000CBBE 0x809A # 0 +0x0000CBBF 0x80B2 # 0 +0x0000CBC0 0x826F # 0 +0x0000CBC1 0x8292 # 0 +0x0000CBC2 0x828B # 0 +0x0000CBC3 0x828D # 0 +0x0000CBC4 0x898B # 0 +0x0000CBC5 0x89D2 # 0 +0x0000CBC6 0x8A00 # 0 +0x0000CBC7 0x8C37 # 0 +0x0000CBC8 0x8C46 # 0 +0x0000CBC9 0x8C55 # 0 +0x0000CBCA 0x8C9D # 0 +0x0000CBCB 0x8D64 # 0 +0x0000CBCC 0x8D70 # 0 +0x0000CBCD 0x8DB3 # 0 +0x0000CBCE 0x8EAB # 0 +0x0000CBCF 0x8ECA # 0 +0x0000CBD0 0x8F9B # 0 +0x0000CBD1 0x8FB0 # 0 +0x0000CBD2 0x8FC2 # 0 +0x0000CBD3 0x8FC6 # 0 +0x0000CBD4 0x8FC5 # 0 +0x0000CBD5 0x8FC4 # 0 +0x0000CBD6 0x5DE1 # 0 +0x0000CBD7 0x9091 # 0 +0x0000CBD8 0x90A2 # 0 +0x0000CBD9 0x90AA # 0 +0x0000CBDA 0x90A6 # 0 +0x0000CBDB 0x90A3 # 0 +0x0000CBDC 0x9149 # 0 +0x0000CBDD 0x91C6 # 0 +0x0000CBDE 0x91CC # 0 +0x0000CBDF 0x9632 # 0 +0x0000CBE0 0x962E # 0 +0x0000CBE1 0x9631 # 0 +0x0000CBE2 0x962A # 0 +0x0000CBE3 0x962C # 0 +0x0000CBE4 0x4E26 # 0 +0x0000CBE5 0x4E56 # 0 +0x0000CBE6 0x4E73 # 0 +0x0000CBE7 0x4E8B # 0 +0x0000CBE8 0x4E9B # 0 +0x0000CBE9 0x4E9E # 0 +0x0000CBEA 0x4EAB # 0 +0x0000CBEB 0x4EAC # 0 +0x0000CBEC 0x4F6F # 0 +0x0000CBED 0x4F9D # 0 +0x0000CBEE 0x4F8D # 0 +0x0000CBEF 0x4F73 # 0 +0x0000CBF0 0x4F7F # 0 +0x0000CBF1 0x4F6C # 0 +0x0000CBF2 0x4F9B # 0 +0x0000CBF3 0x4F8B # 0 +0x0000CBF4 0x4F86 # 0 +0x0000CBF5 0x4F83 # 0 +0x0000CBF6 0x4F70 # 0 +0x0000CBF7 0x4F75 # 0 +0x0000CBF8 0x4F88 # 0 +0x0000CBF9 0x4F69 # 0 +0x0000CBFA 0x4F7B # 0 +0x0000CBFB 0x4F96 # 0 +0x0000CBFC 0x4F7E # 0 +0x0000CBFD 0x4F8F # 0 +0x0000CBFE 0x4F91 # 0 +0x0000CCA1 0x4F7A # 0 +0x0000CCA2 0x5154 # 0 +0x0000CCA3 0x5152 # 0 +0x0000CCA4 0x5155 # 0 +0x0000CCA5 0x5169 # 0 +0x0000CCA6 0x5177 # 0 +0x0000CCA7 0x5176 # 0 +0x0000CCA8 0x5178 # 0 +0x0000CCA9 0x51BD # 0 +0x0000CCAA 0x51FD # 0 +0x0000CCAB 0x523B # 0 +0x0000CCAC 0x5238 # 0 +0x0000CCAD 0x5237 # 0 +0x0000CCAE 0x523A # 0 +0x0000CCAF 0x5230 # 0 +0x0000CCB0 0x522E # 0 +0x0000CCB1 0x5236 # 0 +0x0000CCB2 0x5241 # 0 +0x0000CCB3 0x52BE # 0 +0x0000CCB4 0x52BB # 0 +0x0000CCB5 0x5352 # 0 +0x0000CCB6 0x5354 # 0 +0x0000CCB7 0x5353 # 0 +0x0000CCB8 0x5351 # 0 +0x0000CCB9 0x5366 # 0 +0x0000CCBA 0x5377 # 0 +0x0000CCBB 0x5378 # 0 +0x0000CCBC 0x5379 # 0 +0x0000CCBD 0x53D6 # 0 +0x0000CCBE 0x53D4 # 0 +0x0000CCBF 0x53D7 # 0 +0x0000CCC0 0x5473 # 0 +0x0000CCC1 0x5475 # 0 +0x0000CCC2 0x5496 # 0 +0x0000CCC3 0x5478 # 0 +0x0000CCC4 0x5495 # 0 +0x0000CCC5 0x5480 # 0 +0x0000CCC6 0x547B # 0 +0x0000CCC7 0x5477 # 0 +0x0000CCC8 0x5484 # 0 +0x0000CCC9 0x5492 # 0 +0x0000CCCA 0x5486 # 0 +0x0000CCCB 0x547C # 0 +0x0000CCCC 0x5490 # 0 +0x0000CCCD 0x5471 # 0 +0x0000CCCE 0x5476 # 0 +0x0000CCCF 0x548C # 0 +0x0000CCD0 0x549A # 0 +0x0000CCD1 0x5462 # 0 +0x0000CCD2 0x5468 # 0 +0x0000CCD3 0x548B # 0 +0x0000CCD4 0x547D # 0 +0x0000CCD5 0x548E # 0 +0x0000CCD6 0x56FA # 0 +0x0000CCD7 0x5783 # 0 +0x0000CCD8 0x5777 # 0 +0x0000CCD9 0x576A # 0 +0x0000CCDA 0x5769 # 0 +0x0000CCDB 0x5761 # 0 +0x0000CCDC 0x5766 # 0 +0x0000CCDD 0x5764 # 0 +0x0000CCDE 0x577C # 0 +0x0000CCDF 0x591C # 0 +0x0000CCE0 0x5949 # 0 +0x0000CCE1 0x5947 # 0 +0x0000CCE2 0x5948 # 0 +0x0000CCE3 0x5944 # 0 +0x0000CCE4 0x5954 # 0 +0x0000CCE5 0x59BE # 0 +0x0000CCE6 0x59BB # 0 +0x0000CCE7 0x59D4 # 0 +0x0000CCE8 0x59B9 # 0 +0x0000CCE9 0x59AE # 0 +0x0000CCEA 0x59D1 # 0 +0x0000CCEB 0x59C6 # 0 +0x0000CCEC 0x59D0 # 0 +0x0000CCED 0x59CD # 0 +0x0000CCEE 0x59CB # 0 +0x0000CCEF 0x59D3 # 0 +0x0000CCF0 0x59CA # 0 +0x0000CCF1 0x59AF # 0 +0x0000CCF2 0x59B3 # 0 +0x0000CCF3 0x59D2 # 0 +0x0000CCF4 0x59C5 # 0 +0x0000CCF5 0x5B5F # 0 +0x0000CCF6 0x5B64 # 0 +0x0000CCF7 0x5B63 # 0 +0x0000CCF8 0x5B97 # 0 +0x0000CCF9 0x5B9A # 0 +0x0000CCFA 0x5B98 # 0 +0x0000CCFB 0x5B9C # 0 +0x0000CCFC 0x5B99 # 0 +0x0000CCFD 0x5B9B # 0 +0x0000CCFE 0x5C1A # 0 +0x0000CDA1 0x5C48 # 0 +0x0000CDA2 0x5C45 # 0 +0x0000CDA3 0x5C46 # 0 +0x0000CDA4 0x5CB7 # 0 +0x0000CDA5 0x5CA1 # 0 +0x0000CDA6 0x5CB8 # 0 +0x0000CDA7 0x5CA9 # 0 +0x0000CDA8 0x5CAB # 0 +0x0000CDA9 0x5CB1 # 0 +0x0000CDAA 0x5CB3 # 0 +0x0000CDAB 0x5E18 # 0 +0x0000CDAC 0x5E1A # 0 +0x0000CDAD 0x5E16 # 0 +0x0000CDAE 0x5E15 # 0 +0x0000CDAF 0x5E1B # 0 +0x0000CDB0 0x5E11 # 0 +0x0000CDB1 0x5E78 # 0 +0x0000CDB2 0x5E9A # 0 +0x0000CDB3 0x5E97 # 0 +0x0000CDB4 0x5E9C # 0 +0x0000CDB5 0x5E95 # 0 +0x0000CDB6 0x5E96 # 0 +0x0000CDB7 0x5EF6 # 0 +0x0000CDB8 0x5F26 # 0 +0x0000CDB9 0x5F27 # 0 +0x0000CDBA 0x5F29 # 0 +0x0000CDBB 0x5F80 # 0 +0x0000CDBC 0x5F81 # 0 +0x0000CDBD 0x5F7F # 0 +0x0000CDBE 0x5F7C # 0 +0x0000CDBF 0x5FDD # 0 +0x0000CDC0 0x5FE0 # 0 +0x0000CDC1 0x5FFD # 0 +0x0000CDC2 0x5FF5 # 0 +0x0000CDC3 0x5FFF # 0 +0x0000CDC4 0x600F # 0 +0x0000CDC5 0x6014 # 0 +0x0000CDC6 0x602F # 0 +0x0000CDC7 0x6035 # 0 +0x0000CDC8 0x6016 # 0 +0x0000CDC9 0x602A # 0 +0x0000CDCA 0x6015 # 0 +0x0000CDCB 0x6021 # 0 +0x0000CDCC 0x6027 # 0 +0x0000CDCD 0x6029 # 0 +0x0000CDCE 0x602B # 0 +0x0000CDCF 0x601B # 0 +0x0000CDD0 0x6216 # 0 +0x0000CDD1 0x6215 # 0 +0x0000CDD2 0x623F # 0 +0x0000CDD3 0x623E # 0 +0x0000CDD4 0x6240 # 0 +0x0000CDD5 0x627F # 0 +0x0000CDD6 0x62C9 # 0 +0x0000CDD7 0x62CC # 0 +0x0000CDD8 0x62C4 # 0 +0x0000CDD9 0x62BF # 0 +0x0000CDDA 0x62C2 # 0 +0x0000CDDB 0x62B9 # 0 +0x0000CDDC 0x62D2 # 0 +0x0000CDDD 0x62DB # 0 +0x0000CDDE 0x62AB # 0 +0x0000CDDF 0x62D3 # 0 +0x0000CDE0 0x62D4 # 0 +0x0000CDE1 0x62CB # 0 +0x0000CDE2 0x62C8 # 0 +0x0000CDE3 0x62A8 # 0 +0x0000CDE4 0x62BD # 0 +0x0000CDE5 0x62BC # 0 +0x0000CDE6 0x62D0 # 0 +0x0000CDE7 0x62D9 # 0 +0x0000CDE8 0x62C7 # 0 +0x0000CDE9 0x62CD # 0 +0x0000CDEA 0x62B5 # 0 +0x0000CDEB 0x62DA # 0 +0x0000CDEC 0x62B1 # 0 +0x0000CDED 0x62D8 # 0 +0x0000CDEE 0x62D6 # 0 +0x0000CDEF 0x62D7 # 0 +0x0000CDF0 0x62C6 # 0 +0x0000CDF1 0x62AC # 0 +0x0000CDF2 0x62CE # 0 +0x0000CDF3 0x653E # 0 +0x0000CDF4 0x65A7 # 0 +0x0000CDF5 0x65BC # 0 +0x0000CDF6 0x65FA # 0 +0x0000CDF7 0x6614 # 0 +0x0000CDF8 0x6613 # 0 +0x0000CDF9 0x660C # 0 +0x0000CDFA 0x6606 # 0 +0x0000CDFB 0x6602 # 0 +0x0000CDFC 0x660E # 0 +0x0000CDFD 0x6600 # 0 +0x0000CDFE 0x660F # 0 +0x0000CEA1 0x6615 # 0 +0x0000CEA2 0x660A # 0 +0x0000CEA3 0x6607 # 0 +0x0000CEA4 0x670D # 0 +0x0000CEA5 0x670B # 0 +0x0000CEA6 0x676D # 0 +0x0000CEA7 0x678B # 0 +0x0000CEA8 0x6795 # 0 +0x0000CEA9 0x6771 # 0 +0x0000CEAA 0x679C # 0 +0x0000CEAB 0x6773 # 0 +0x0000CEAC 0x6777 # 0 +0x0000CEAD 0x6787 # 0 +0x0000CEAE 0x679D # 0 +0x0000CEAF 0x6797 # 0 +0x0000CEB0 0x676F # 0 +0x0000CEB1 0x6770 # 0 +0x0000CEB2 0x677F # 0 +0x0000CEB3 0x6789 # 0 +0x0000CEB4 0x677E # 0 +0x0000CEB5 0x6790 # 0 +0x0000CEB6 0x6775 # 0 +0x0000CEB7 0x679A # 0 +0x0000CEB8 0x6793 # 0 +0x0000CEB9 0x677C # 0 +0x0000CEBA 0x676A # 0 +0x0000CEBB 0x6772 # 0 +0x0000CEBC 0x6B23 # 0 +0x0000CEBD 0x6B66 # 0 +0x0000CEBE 0x6B67 # 0 +0x0000CEBF 0x6B7F # 0 +0x0000CEC0 0x6C13 # 0 +0x0000CEC1 0x6C1B # 0 +0x0000CEC2 0x6CE3 # 0 +0x0000CEC3 0x6CE8 # 0 +0x0000CEC4 0x6CF3 # 0 +0x0000CEC5 0x6CB1 # 0 +0x0000CEC6 0x6CCC # 0 +0x0000CEC7 0x6CE5 # 0 +0x0000CEC8 0x6CB3 # 0 +0x0000CEC9 0x6CBD # 0 +0x0000CECA 0x6CBE # 0 +0x0000CECB 0x6CBC # 0 +0x0000CECC 0x6CE2 # 0 +0x0000CECD 0x6CAB # 0 +0x0000CECE 0x6CD5 # 0 +0x0000CECF 0x6CD3 # 0 +0x0000CED0 0x6CB8 # 0 +0x0000CED1 0x6CC4 # 0 +0x0000CED2 0x6CB9 # 0 +0x0000CED3 0x6CC1 # 0 +0x0000CED4 0x6CAE # 0 +0x0000CED5 0x6CD7 # 0 +0x0000CED6 0x6CC5 # 0 +0x0000CED7 0x6CF1 # 0 +0x0000CED8 0x6CBF # 0 +0x0000CED9 0x6CBB # 0 +0x0000CEDA 0x6CE1 # 0 +0x0000CEDB 0x6CDB # 0 +0x0000CEDC 0x6CCA # 0 +0x0000CEDD 0x6CAC # 0 +0x0000CEDE 0x6CEF # 0 +0x0000CEDF 0x6CDC # 0 +0x0000CEE0 0x6CD6 # 0 +0x0000CEE1 0x6CE0 # 0 +0x0000CEE2 0x7095 # 0 +0x0000CEE3 0x708E # 0 +0x0000CEE4 0x7092 # 0 +0x0000CEE5 0x708A # 0 +0x0000CEE6 0x7099 # 0 +0x0000CEE7 0x722C # 0 +0x0000CEE8 0x722D # 0 +0x0000CEE9 0x7238 # 0 +0x0000CEEA 0x7248 # 0 +0x0000CEEB 0x7267 # 0 +0x0000CEEC 0x7269 # 0 +0x0000CEED 0x72C0 # 0 +0x0000CEEE 0x72CE # 0 +0x0000CEEF 0x72D9 # 0 +0x0000CEF0 0x72D7 # 0 +0x0000CEF1 0x72D0 # 0 +0x0000CEF2 0x73A9 # 0 +0x0000CEF3 0x73A8 # 0 +0x0000CEF4 0x739F # 0 +0x0000CEF5 0x73AB # 0 +0x0000CEF6 0x73A5 # 0 +0x0000CEF7 0x753D # 0 +0x0000CEF8 0x759D # 0 +0x0000CEF9 0x7599 # 0 +0x0000CEFA 0x759A # 0 +0x0000CEFB 0x7684 # 0 +0x0000CEFC 0x76C2 # 0 +0x0000CEFD 0x76F2 # 0 +0x0000CEFE 0x76F4 # 0 +0x0000CFA1 0x77E5 # 0 +0x0000CFA2 0x77FD # 0 +0x0000CFA3 0x793E # 0 +0x0000CFA4 0x7940 # 0 +0x0000CFA5 0x7941 # 0 +0x0000CFA6 0x79C9 # 0 +0x0000CFA7 0x79C8 # 0 +0x0000CFA8 0x7A7A # 0 +0x0000CFA9 0x7A79 # 0 +0x0000CFAA 0x7AFA # 0 +0x0000CFAB 0x7CFE # 0 +0x0000CFAC 0x7F54 # 0 +0x0000CFAD 0x7F8C # 0 +0x0000CFAE 0x7F8B # 0 +0x0000CFAF 0x8005 # 0 +0x0000CFB0 0x80BA # 0 +0x0000CFB1 0x80A5 # 0 +0x0000CFB2 0x80A2 # 0 +0x0000CFB3 0x80B1 # 0 +0x0000CFB4 0x80A1 # 0 +0x0000CFB5 0x80AB # 0 +0x0000CFB6 0x80A9 # 0 +0x0000CFB7 0x80B4 # 0 +0x0000CFB8 0x80AA # 0 +0x0000CFB9 0x80AF # 0 +0x0000CFBA 0x81E5 # 0 +0x0000CFBB 0x81FE # 0 +0x0000CFBC 0x820D # 0 +0x0000CFBD 0x82B3 # 0 +0x0000CFBE 0x829D # 0 +0x0000CFBF 0x8299 # 0 +0x0000CFC0 0x82AD # 0 +0x0000CFC1 0x82BD # 0 +0x0000CFC2 0x829F # 0 +0x0000CFC3 0x82B9 # 0 +0x0000CFC4 0x82B1 # 0 +0x0000CFC5 0x82AC # 0 +0x0000CFC6 0x82A5 # 0 +0x0000CFC7 0x82AF # 0 +0x0000CFC8 0x82B8 # 0 +0x0000CFC9 0x82A3 # 0 +0x0000CFCA 0x82B0 # 0 +0x0000CFCB 0x82BE # 0 +0x0000CFCC 0x82B7 # 0 +0x0000CFCD 0x864E # 0 +0x0000CFCE 0x8671 # 0 +0x0000CFCF 0x521D # 0 +0x0000CFD0 0x8868 # 0 +0x0000CFD1 0x8ECB # 0 +0x0000CFD2 0x8FCE # 0 +0x0000CFD3 0x8FD4 # 0 +0x0000CFD4 0x8FD1 # 0 +0x0000CFD5 0x90B5 # 0 +0x0000CFD6 0x90B8 # 0 +0x0000CFD7 0x90B1 # 0 +0x0000CFD8 0x90B6 # 0 +0x0000CFD9 0x91C7 # 0 +0x0000CFDA 0x91D1 # 0 +0x0000CFDB 0x9577 # 0 +0x0000CFDC 0x9580 # 0 +0x0000CFDD 0x961C # 0 +0x0000CFDE 0x9640 # 0 +0x0000CFDF 0x963F # 0 +0x0000CFE0 0x963B # 0 +0x0000CFE1 0x9644 # 0 +0x0000CFE2 0x9642 # 0 +0x0000CFE3 0x96B9 # 0 +0x0000CFE4 0x96E8 # 0 +0x0000CFE5 0x9752 # 0 +0x0000CFE6 0x975E # 0 +0x0000CFE7 0x4E9F # 0 +0x0000CFE8 0x4EAD # 0 +0x0000CFE9 0x4EAE # 0 +0x0000CFEA 0x4FE1 # 0 +0x0000CFEB 0x4FB5 # 0 +0x0000CFEC 0x4FAF # 0 +0x0000CFED 0x4FBF # 0 +0x0000CFEE 0x4FE0 # 0 +0x0000CFEF 0x4FD1 # 0 +0x0000CFF0 0x4FCF # 0 +0x0000CFF1 0x4FDD # 0 +0x0000CFF2 0x4FC3 # 0 +0x0000CFF3 0x4FB6 # 0 +0x0000CFF4 0x4FD8 # 0 +0x0000CFF5 0x4FDF # 0 +0x0000CFF6 0x4FCA # 0 +0x0000CFF7 0x4FD7 # 0 +0x0000CFF8 0x4FAE # 0 +0x0000CFF9 0x4FD0 # 0 +0x0000CFFA 0x4FC4 # 0 +0x0000CFFB 0x4FC2 # 0 +0x0000CFFC 0x4FDA # 0 +0x0000CFFD 0x4FCE # 0 +0x0000CFFE 0x4FDE # 0 +0x0000D0A1 0x4FB7 # 0 +0x0000D0A2 0x5157 # 0 +0x0000D0A3 0x5192 # 0 +0x0000D0A4 0x5191 # 0 +0x0000D0A5 0x51A0 # 0 +0x0000D0A6 0x524E # 0 +0x0000D0A7 0x5243 # 0 +0x0000D0A8 0x524A # 0 +0x0000D0A9 0x524D # 0 +0x0000D0AA 0x524C # 0 +0x0000D0AB 0x524B # 0 +0x0000D0AC 0x5247 # 0 +0x0000D0AD 0x52C7 # 0 +0x0000D0AE 0x52C9 # 0 +0x0000D0AF 0x52C3 # 0 +0x0000D0B0 0x52C1 # 0 +0x0000D0B1 0x530D # 0 +0x0000D0B2 0x5357 # 0 +0x0000D0B3 0x537B # 0 +0x0000D0B4 0x539A # 0 +0x0000D0B5 0x53DB # 0 +0x0000D0B6 0x54AC # 0 +0x0000D0B7 0x54C0 # 0 +0x0000D0B8 0x54A8 # 0 +0x0000D0B9 0x54CE # 0 +0x0000D0BA 0x54C9 # 0 +0x0000D0BB 0x54B8 # 0 +0x0000D0BC 0x54A6 # 0 +0x0000D0BD 0x54B3 # 0 +0x0000D0BE 0x54C7 # 0 +0x0000D0BF 0x54C2 # 0 +0x0000D0C0 0x54BD # 0 +0x0000D0C1 0x54AA # 0 +0x0000D0C2 0x54C1 # 0 +0x0000D0C3 0x54C4 # 0 +0x0000D0C4 0x54C8 # 0 +0x0000D0C5 0x54AF # 0 +0x0000D0C6 0x54AB # 0 +0x0000D0C7 0x54B1 # 0 +0x0000D0C8 0x54BB # 0 +0x0000D0C9 0x54A9 # 0 +0x0000D0CA 0x54A7 # 0 +0x0000D0CB 0x54BF # 0 +0x0000D0CC 0x56FF # 0 +0x0000D0CD 0x5782 # 0 +0x0000D0CE 0x578B # 0 +0x0000D0CF 0x57A0 # 0 +0x0000D0D0 0x57A3 # 0 +0x0000D0D1 0x57A2 # 0 +0x0000D0D2 0x57CE # 0 +0x0000D0D3 0x57AE # 0 +0x0000D0D4 0x5793 # 0 +0x0000D0D5 0x5955 # 0 +0x0000D0D6 0x5951 # 0 +0x0000D0D7 0x594F # 0 +0x0000D0D8 0x594E # 0 +0x0000D0D9 0x5950 # 0 +0x0000D0DA 0x59DC # 0 +0x0000D0DB 0x59D8 # 0 +0x0000D0DC 0x59FF # 0 +0x0000D0DD 0x59E3 # 0 +0x0000D0DE 0x59E8 # 0 +0x0000D0DF 0x5A03 # 0 +0x0000D0E0 0x59E5 # 0 +0x0000D0E1 0x59EA # 0 +0x0000D0E2 0x59DA # 0 +0x0000D0E3 0x59E6 # 0 +0x0000D0E4 0x5A01 # 0 +0x0000D0E5 0x59FB # 0 +0x0000D0E6 0x5B69 # 0 +0x0000D0E7 0x5BA3 # 0 +0x0000D0E8 0x5BA6 # 0 +0x0000D0E9 0x5BA4 # 0 +0x0000D0EA 0x5BA2 # 0 +0x0000D0EB 0x5BA5 # 0 +0x0000D0EC 0x5C01 # 0 +0x0000D0ED 0x5C4E # 0 +0x0000D0EE 0x5C4F # 0 +0x0000D0EF 0x5C4D # 0 +0x0000D0F0 0x5C4B # 0 +0x0000D0F1 0x5CD9 # 0 +0x0000D0F2 0x5CD2 # 0 +0x0000D0F3 0x5DF7 # 0 +0x0000D0F4 0x5E1D # 0 +0x0000D0F5 0x5E25 # 0 +0x0000D0F6 0x5E1F # 0 +0x0000D0F7 0x5E7D # 0 +0x0000D0F8 0x5EA0 # 0 +0x0000D0F9 0x5EA6 # 0 +0x0000D0FA 0x5EFA # 0 +0x0000D0FB 0x5F08 # 0 +0x0000D0FC 0x5F2D # 0 +0x0000D0FD 0x5F65 # 0 +0x0000D0FE 0x5F88 # 0 +0x0000D1A1 0x5F85 # 0 +0x0000D1A2 0x5F8A # 0 +0x0000D1A3 0x5F8B # 0 +0x0000D1A4 0x5F87 # 0 +0x0000D1A5 0x5F8C # 0 +0x0000D1A6 0x5F89 # 0 +0x0000D1A7 0x6012 # 0 +0x0000D1A8 0x601D # 0 +0x0000D1A9 0x6020 # 0 +0x0000D1AA 0x6025 # 0 +0x0000D1AB 0x600E # 0 +0x0000D1AC 0x6028 # 0 +0x0000D1AD 0x604D # 0 +0x0000D1AE 0x6070 # 0 +0x0000D1AF 0x6068 # 0 +0x0000D1B0 0x6062 # 0 +0x0000D1B1 0x6046 # 0 +0x0000D1B2 0x6043 # 0 +0x0000D1B3 0x606C # 0 +0x0000D1B4 0x606B # 0 +0x0000D1B5 0x606A # 0 +0x0000D1B6 0x6064 # 0 +0x0000D1B7 0x6241 # 0 +0x0000D1B8 0x62DC # 0 +0x0000D1B9 0x6316 # 0 +0x0000D1BA 0x6309 # 0 +0x0000D1BB 0x62FC # 0 +0x0000D1BC 0x62ED # 0 +0x0000D1BD 0x6301 # 0 +0x0000D1BE 0x62EE # 0 +0x0000D1BF 0x62FD # 0 +0x0000D1C0 0x6307 # 0 +0x0000D1C1 0x62F1 # 0 +0x0000D1C2 0x62F7 # 0 +0x0000D1C3 0x62EF # 0 +0x0000D1C4 0x62EC # 0 +0x0000D1C5 0x62FE # 0 +0x0000D1C6 0x62F4 # 0 +0x0000D1C7 0x6311 # 0 +0x0000D1C8 0x6302 # 0 +0x0000D1C9 0x653F # 0 +0x0000D1CA 0x6545 # 0 +0x0000D1CB 0x65AB # 0 +0x0000D1CC 0x65BD # 0 +0x0000D1CD 0x65E2 # 0 +0x0000D1CE 0x6625 # 0 +0x0000D1CF 0x662D # 0 +0x0000D1D0 0x6620 # 0 +0x0000D1D1 0x6627 # 0 +0x0000D1D2 0x662F # 0 +0x0000D1D3 0x661F # 0 +0x0000D1D4 0x6628 # 0 +0x0000D1D5 0x6631 # 0 +0x0000D1D6 0x6624 # 0 +0x0000D1D7 0x66F7 # 0 +0x0000D1D8 0x67FF # 0 +0x0000D1D9 0x67D3 # 0 +0x0000D1DA 0x67F1 # 0 +0x0000D1DB 0x67D4 # 0 +0x0000D1DC 0x67D0 # 0 +0x0000D1DD 0x67EC # 0 +0x0000D1DE 0x67B6 # 0 +0x0000D1DF 0x67AF # 0 +0x0000D1E0 0x67F5 # 0 +0x0000D1E1 0x67E9 # 0 +0x0000D1E2 0x67EF # 0 +0x0000D1E3 0x67C4 # 0 +0x0000D1E4 0x67D1 # 0 +0x0000D1E5 0x67B4 # 0 +0x0000D1E6 0x67DA # 0 +0x0000D1E7 0x67E5 # 0 +0x0000D1E8 0x67B8 # 0 +0x0000D1E9 0x67CF # 0 +0x0000D1EA 0x67DE # 0 +0x0000D1EB 0x67F3 # 0 +0x0000D1EC 0x67B0 # 0 +0x0000D1ED 0x67D9 # 0 +0x0000D1EE 0x67E2 # 0 +0x0000D1EF 0x67DD # 0 +0x0000D1F0 0x67D2 # 0 +0x0000D1F1 0x6B6A # 0 +0x0000D1F2 0x6B83 # 0 +0x0000D1F3 0x6B86 # 0 +0x0000D1F4 0x6BB5 # 0 +0x0000D1F5 0x6BD2 # 0 +0x0000D1F6 0x6BD7 # 0 +0x0000D1F7 0x6C1F # 0 +0x0000D1F8 0x6CC9 # 0 +0x0000D1F9 0x6D0B # 0 +0x0000D1FA 0x6D32 # 0 +0x0000D1FB 0x6D2A # 0 +0x0000D1FC 0x6D41 # 0 +0x0000D1FD 0x6D25 # 0 +0x0000D1FE 0x6D0C # 0 +0x0000D2A1 0x6D31 # 0 +0x0000D2A2 0x6D1E # 0 +0x0000D2A3 0x6D17 # 0 +0x0000D2A4 0x6D3B # 0 +0x0000D2A5 0x6D3D # 0 +0x0000D2A6 0x6D3E # 0 +0x0000D2A7 0x6D36 # 0 +0x0000D2A8 0x6D1B # 0 +0x0000D2A9 0x6CF5 # 0 +0x0000D2AA 0x6D39 # 0 +0x0000D2AB 0x6D27 # 0 +0x0000D2AC 0x6D38 # 0 +0x0000D2AD 0x6D29 # 0 +0x0000D2AE 0x6D2E # 0 +0x0000D2AF 0x6D35 # 0 +0x0000D2B0 0x6D0E # 0 +0x0000D2B1 0x6D2B # 0 +0x0000D2B2 0x70AB # 0 +0x0000D2B3 0x70BA # 0 +0x0000D2B4 0x70B3 # 0 +0x0000D2B5 0x70AC # 0 +0x0000D2B6 0x70AF # 0 +0x0000D2B7 0x70AD # 0 +0x0000D2B8 0x70B8 # 0 +0x0000D2B9 0x70AE # 0 +0x0000D2BA 0x70A4 # 0 +0x0000D2BB 0x7230 # 0 +0x0000D2BC 0x7272 # 0 +0x0000D2BD 0x726F # 0 +0x0000D2BE 0x7274 # 0 +0x0000D2BF 0x72E9 # 0 +0x0000D2C0 0x72E0 # 0 +0x0000D2C1 0x72E1 # 0 +0x0000D2C2 0x73B7 # 0 +0x0000D2C3 0x73CA # 0 +0x0000D2C4 0x73BB # 0 +0x0000D2C5 0x73B2 # 0 +0x0000D2C6 0x73CD # 0 +0x0000D2C7 0x73C0 # 0 +0x0000D2C8 0x73B3 # 0 +0x0000D2C9 0x751A # 0 +0x0000D2CA 0x752D # 0 +0x0000D2CB 0x754F # 0 +0x0000D2CC 0x754C # 0 +0x0000D2CD 0x754E # 0 +0x0000D2CE 0x754B # 0 +0x0000D2CF 0x75AB # 0 +0x0000D2D0 0x75A4 # 0 +0x0000D2D1 0x75A5 # 0 +0x0000D2D2 0x75A2 # 0 +0x0000D2D3 0x75A3 # 0 +0x0000D2D4 0x7678 # 0 +0x0000D2D5 0x7686 # 0 +0x0000D2D6 0x7687 # 0 +0x0000D2D7 0x7688 # 0 +0x0000D2D8 0x76C8 # 0 +0x0000D2D9 0x76C6 # 0 +0x0000D2DA 0x76C3 # 0 +0x0000D2DB 0x76C5 # 0 +0x0000D2DC 0x7701 # 0 +0x0000D2DD 0x76F9 # 0 +0x0000D2DE 0x76F8 # 0 +0x0000D2DF 0x7709 # 0 +0x0000D2E0 0x770B # 0 +0x0000D2E1 0x76FE # 0 +0x0000D2E2 0x76FC # 0 +0x0000D2E3 0x7707 # 0 +0x0000D2E4 0x77DC # 0 +0x0000D2E5 0x7802 # 0 +0x0000D2E6 0x7814 # 0 +0x0000D2E7 0x780C # 0 +0x0000D2E8 0x780D # 0 +0x0000D2E9 0x7946 # 0 +0x0000D2EA 0x7949 # 0 +0x0000D2EB 0x7948 # 0 +0x0000D2EC 0x7947 # 0 +0x0000D2ED 0x79B9 # 0 +0x0000D2EE 0x79BA # 0 +0x0000D2EF 0x79D1 # 0 +0x0000D2F0 0x79D2 # 0 +0x0000D2F1 0x79CB # 0 +0x0000D2F2 0x7A7F # 0 +0x0000D2F3 0x7A81 # 0 +0x0000D2F4 0x7AFF # 0 +0x0000D2F5 0x7AFD # 0 +0x0000D2F6 0x7C7D # 0 +0x0000D2F7 0x7D02 # 0 +0x0000D2F8 0x7D05 # 0 +0x0000D2F9 0x7D00 # 0 +0x0000D2FA 0x7D09 # 0 +0x0000D2FB 0x7D07 # 0 +0x0000D2FC 0x7D04 # 0 +0x0000D2FD 0x7D06 # 0 +0x0000D2FE 0x7F38 # 0 +0x0000D3A1 0x7F8E # 0 +0x0000D3A2 0x7FBF # 0 +0x0000D3A3 0x8010 # 0 +0x0000D3A4 0x800D # 0 +0x0000D3A5 0x8011 # 0 +0x0000D3A6 0x8036 # 0 +0x0000D3A7 0x80D6 # 0 +0x0000D3A8 0x80E5 # 0 +0x0000D3A9 0x80DA # 0 +0x0000D3AA 0x80C3 # 0 +0x0000D3AB 0x80C4 # 0 +0x0000D3AC 0x80CC # 0 +0x0000D3AD 0x80E1 # 0 +0x0000D3AE 0x80DB # 0 +0x0000D3AF 0x80CE # 0 +0x0000D3B0 0x80DE # 0 +0x0000D3B1 0x80E4 # 0 +0x0000D3B2 0x80DD # 0 +0x0000D3B3 0x81F4 # 0 +0x0000D3B4 0x8222 # 0 +0x0000D3B5 0x82E7 # 0 +0x0000D3B6 0x8303 # 0 +0x0000D3B7 0x8305 # 0 +0x0000D3B8 0x82E3 # 0 +0x0000D3B9 0x82DB # 0 +0x0000D3BA 0x82E6 # 0 +0x0000D3BB 0x8304 # 0 +0x0000D3BC 0x82E5 # 0 +0x0000D3BD 0x8302 # 0 +0x0000D3BE 0x8309 # 0 +0x0000D3BF 0x82D2 # 0 +0x0000D3C0 0x82D7 # 0 +0x0000D3C1 0x82F1 # 0 +0x0000D3C2 0x8301 # 0 +0x0000D3C3 0x82DC # 0 +0x0000D3C4 0x82D4 # 0 +0x0000D3C5 0x82D1 # 0 +0x0000D3C6 0x82DE # 0 +0x0000D3C7 0x82D3 # 0 +0x0000D3C8 0x82DF # 0 +0x0000D3C9 0x82EF # 0 +0x0000D3CA 0x8306 # 0 +0x0000D3CB 0x8650 # 0 +0x0000D3CC 0x8679 # 0 +0x0000D3CD 0x867B # 0 +0x0000D3CE 0x867A # 0 +0x0000D3CF 0x884D # 0 +0x0000D3D0 0x886B # 0 +0x0000D3D1 0x8981 # 0 +0x0000D3D2 0x89D4 # 0 +0x0000D3D3 0x8A08 # 0 +0x0000D3D4 0x8A02 # 0 +0x0000D3D5 0x8A03 # 0 +0x0000D3D6 0x8C9E # 0 +0x0000D3D7 0x8CA0 # 0 +0x0000D3D8 0x8D74 # 0 +0x0000D3D9 0x8D73 # 0 +0x0000D3DA 0x8DB4 # 0 +0x0000D3DB 0x8ECD # 0 +0x0000D3DC 0x8ECC # 0 +0x0000D3DD 0x8FF0 # 0 +0x0000D3DE 0x8FE6 # 0 +0x0000D3DF 0x8FE2 # 0 +0x0000D3E0 0x8FEA # 0 +0x0000D3E1 0x8FE5 # 0 +0x0000D3E2 0x8FED # 0 +0x0000D3E3 0x8FEB # 0 +0x0000D3E4 0x8FE4 # 0 +0x0000D3E5 0x8FE8 # 0 +0x0000D3E6 0x90CA # 0 +0x0000D3E7 0x90CE # 0 +0x0000D3E8 0x90C1 # 0 +0x0000D3E9 0x90C3 # 0 +0x0000D3EA 0x914B # 0 +0x0000D3EB 0x914A # 0 +0x0000D3EC 0x91CD # 0 +0x0000D3ED 0x9582 # 0 +0x0000D3EE 0x9650 # 0 +0x0000D3EF 0x964B # 0 +0x0000D3F0 0x964C # 0 +0x0000D3F1 0x964D # 0 +0x0000D3F2 0x9762 # 0 +0x0000D3F3 0x9769 # 0 +0x0000D3F4 0x97CB # 0 +0x0000D3F5 0x97ED # 0 +0x0000D3F6 0x97F3 # 0 +0x0000D3F7 0x9801 # 0 +0x0000D3F8 0x98A8 # 0 +0x0000D3F9 0x98DB # 0 +0x0000D3FA 0x98DF # 0 +0x0000D3FB 0x9996 # 0 +0x0000D3FC 0x9999 # 0 +0x0000D3FD 0x4E58 # 0 +0x0000D3FE 0x4EB3 # 0 +0x0000D4A1 0x500C # 0 +0x0000D4A2 0x500D # 0 +0x0000D4A3 0x5023 # 0 +0x0000D4A4 0x4FEF # 0 +0x0000D4A5 0x5026 # 0 +0x0000D4A6 0x5025 # 0 +0x0000D4A7 0x4FF8 # 0 +0x0000D4A8 0x5029 # 0 +0x0000D4A9 0x5016 # 0 +0x0000D4AA 0x5006 # 0 +0x0000D4AB 0x503C # 0 +0x0000D4AC 0x501F # 0 +0x0000D4AD 0x501A # 0 +0x0000D4AE 0x5012 # 0 +0x0000D4AF 0x5011 # 0 +0x0000D4B0 0x4FFA # 0 +0x0000D4B1 0x5000 # 0 +0x0000D4B2 0x5014 # 0 +0x0000D4B3 0x5028 # 0 +0x0000D4B4 0x4FF1 # 0 +0x0000D4B5 0x5021 # 0 +0x0000D4B6 0x500B # 0 +0x0000D4B7 0x5019 # 0 +0x0000D4B8 0x5018 # 0 +0x0000D4B9 0x4FF3 # 0 +0x0000D4BA 0x4FEE # 0 +0x0000D4BB 0x502D # 0 +0x0000D4BC 0x502A # 0 +0x0000D4BD 0x4FFE # 0 +0x0000D4BE 0x502B # 0 +0x0000D4BF 0x5009 # 0 +0x0000D4C0 0x517C # 0 +0x0000D4C1 0x51A4 # 0 +0x0000D4C2 0x51A5 # 0 +0x0000D4C3 0x51A2 # 0 +0x0000D4C4 0x51CD # 0 +0x0000D4C5 0x51CC # 0 +0x0000D4C6 0x51C6 # 0 +0x0000D4C7 0x51CB # 0 +0x0000D4C8 0x5256 # 0 +0x0000D4C9 0x525C # 0 +0x0000D4CA 0x5254 # 0 +0x0000D4CB 0x525B # 0 +0x0000D4CC 0x525D # 0 +0x0000D4CD 0x532A # 0 +0x0000D4CE 0x537F # 0 +0x0000D4CF 0x539F # 0 +0x0000D4D0 0x539D # 0 +0x0000D4D1 0x53DF # 0 +0x0000D4D2 0x54E8 # 0 +0x0000D4D3 0x5510 # 0 +0x0000D4D4 0x5501 # 0 +0x0000D4D5 0x5537 # 0 +0x0000D4D6 0x54FC # 0 +0x0000D4D7 0x54E5 # 0 +0x0000D4D8 0x54F2 # 0 +0x0000D4D9 0x5506 # 0 +0x0000D4DA 0x54FA # 0 +0x0000D4DB 0x5514 # 0 +0x0000D4DC 0x54E9 # 0 +0x0000D4DD 0x54ED # 0 +0x0000D4DE 0x54E1 # 0 +0x0000D4DF 0x5509 # 0 +0x0000D4E0 0x54EE # 0 +0x0000D4E1 0x54EA # 0 +0x0000D4E2 0x54E6 # 0 +0x0000D4E3 0x5527 # 0 +0x0000D4E4 0x5507 # 0 +0x0000D4E5 0x54FD # 0 +0x0000D4E6 0x550F # 0 +0x0000D4E7 0x5703 # 0 +0x0000D4E8 0x5704 # 0 +0x0000D4E9 0x57C2 # 0 +0x0000D4EA 0x57D4 # 0 +0x0000D4EB 0x57CB # 0 +0x0000D4EC 0x57C3 # 0 +0x0000D4ED 0x5809 # 0 +0x0000D4EE 0x590F # 0 +0x0000D4EF 0x5957 # 0 +0x0000D4F0 0x5958 # 0 +0x0000D4F1 0x595A # 0 +0x0000D4F2 0x5A11 # 0 +0x0000D4F3 0x5A18 # 0 +0x0000D4F4 0x5A1C # 0 +0x0000D4F5 0x5A1F # 0 +0x0000D4F6 0x5A1B # 0 +0x0000D4F7 0x5A13 # 0 +0x0000D4F8 0x59EC # 0 +0x0000D4F9 0x5A20 # 0 +0x0000D4FA 0x5A23 # 0 +0x0000D4FB 0x5A29 # 0 +0x0000D4FC 0x5A25 # 0 +0x0000D4FD 0x5A0C # 0 +0x0000D4FE 0x5A09 # 0 +0x0000D5A1 0x5B6B # 0 +0x0000D5A2 0x5C58 # 0 +0x0000D5A3 0x5BB0 # 0 +0x0000D5A4 0x5BB3 # 0 +0x0000D5A5 0x5BB6 # 0 +0x0000D5A6 0x5BB4 # 0 +0x0000D5A7 0x5BAE # 0 +0x0000D5A8 0x5BB5 # 0 +0x0000D5A9 0x5BB9 # 0 +0x0000D5AA 0x5BB8 # 0 +0x0000D5AB 0x5C04 # 0 +0x0000D5AC 0x5C51 # 0 +0x0000D5AD 0x5C55 # 0 +0x0000D5AE 0x5C50 # 0 +0x0000D5AF 0x5CED # 0 +0x0000D5B0 0x5CFD # 0 +0x0000D5B1 0x5CFB # 0 +0x0000D5B2 0x5CEA # 0 +0x0000D5B3 0x5CE8 # 0 +0x0000D5B4 0x5CF0 # 0 +0x0000D5B5 0x5CF6 # 0 +0x0000D5B6 0x5D01 # 0 +0x0000D5B7 0x5CF4 # 0 +0x0000D5B8 0x5DEE # 0 +0x0000D5B9 0x5E2D # 0 +0x0000D5BA 0x5E2B # 0 +0x0000D5BB 0x5EAB # 0 +0x0000D5BC 0x5EAD # 0 +0x0000D5BD 0x5EA7 # 0 +0x0000D5BE 0x5F31 # 0 +0x0000D5BF 0x5F92 # 0 +0x0000D5C0 0x5F91 # 0 +0x0000D5C1 0x5F90 # 0 +0x0000D5C2 0x6059 # 0 +0x0000D5C3 0x6063 # 0 +0x0000D5C4 0x6065 # 0 +0x0000D5C5 0x6050 # 0 +0x0000D5C6 0x6055 # 0 +0x0000D5C7 0x606D # 0 +0x0000D5C8 0x6069 # 0 +0x0000D5C9 0x606F # 0 +0x0000D5CA 0x6084 # 0 +0x0000D5CB 0x609F # 0 +0x0000D5CC 0x609A # 0 +0x0000D5CD 0x608D # 0 +0x0000D5CE 0x6094 # 0 +0x0000D5CF 0x608C # 0 +0x0000D5D0 0x6085 # 0 +0x0000D5D1 0x6096 # 0 +0x0000D5D2 0x6247 # 0 +0x0000D5D3 0x62F3 # 0 +0x0000D5D4 0x6308 # 0 +0x0000D5D5 0x62FF # 0 +0x0000D5D6 0x634E # 0 +0x0000D5D7 0x633E # 0 +0x0000D5D8 0x632F # 0 +0x0000D5D9 0x6355 # 0 +0x0000D5DA 0x6342 # 0 +0x0000D5DB 0x6346 # 0 +0x0000D5DC 0x634F # 0 +0x0000D5DD 0x6349 # 0 +0x0000D5DE 0x633A # 0 +0x0000D5DF 0x6350 # 0 +0x0000D5E0 0x633D # 0 +0x0000D5E1 0x632A # 0 +0x0000D5E2 0x632B # 0 +0x0000D5E3 0x6328 # 0 +0x0000D5E4 0x634D # 0 +0x0000D5E5 0x634C # 0 +0x0000D5E6 0x6548 # 0 +0x0000D5E7 0x6549 # 0 +0x0000D5E8 0x6599 # 0 +0x0000D5E9 0x65C1 # 0 +0x0000D5EA 0x65C5 # 0 +0x0000D5EB 0x6642 # 0 +0x0000D5EC 0x6649 # 0 +0x0000D5ED 0x664F # 0 +0x0000D5EE 0x6643 # 0 +0x0000D5EF 0x6652 # 0 +0x0000D5F0 0x664C # 0 +0x0000D5F1 0x6645 # 0 +0x0000D5F2 0x6641 # 0 +0x0000D5F3 0x66F8 # 0 +0x0000D5F4 0x6714 # 0 +0x0000D5F5 0x6715 # 0 +0x0000D5F6 0x6717 # 0 +0x0000D5F7 0x6821 # 0 +0x0000D5F8 0x6838 # 0 +0x0000D5F9 0x6848 # 0 +0x0000D5FA 0x6846 # 0 +0x0000D5FB 0x6853 # 0 +0x0000D5FC 0x6839 # 0 +0x0000D5FD 0x6842 # 0 +0x0000D5FE 0x6854 # 0 +0x0000D6A1 0x6829 # 0 +0x0000D6A2 0x68B3 # 0 +0x0000D6A3 0x6817 # 0 +0x0000D6A4 0x684C # 0 +0x0000D6A5 0x6851 # 0 +0x0000D6A6 0x683D # 0 +0x0000D6A7 0x67F4 # 0 +0x0000D6A8 0x6850 # 0 +0x0000D6A9 0x6840 # 0 +0x0000D6AA 0x683C # 0 +0x0000D6AB 0x6843 # 0 +0x0000D6AC 0x682A # 0 +0x0000D6AD 0x6845 # 0 +0x0000D6AE 0x6813 # 0 +0x0000D6AF 0x6818 # 0 +0x0000D6B0 0x6841 # 0 +0x0000D6B1 0x6B8A # 0 +0x0000D6B2 0x6B89 # 0 +0x0000D6B3 0x6BB7 # 0 +0x0000D6B4 0x6C23 # 0 +0x0000D6B5 0x6C27 # 0 +0x0000D6B6 0x6C28 # 0 +0x0000D6B7 0x6C26 # 0 +0x0000D6B8 0x6C24 # 0 +0x0000D6B9 0x6CF0 # 0 +0x0000D6BA 0x6D6A # 0 +0x0000D6BB 0x6D95 # 0 +0x0000D6BC 0x6D88 # 0 +0x0000D6BD 0x6D87 # 0 +0x0000D6BE 0x6D66 # 0 +0x0000D6BF 0x6D78 # 0 +0x0000D6C0 0x6D77 # 0 +0x0000D6C1 0x6D59 # 0 +0x0000D6C2 0x6D93 # 0 +0x0000D6C3 0x6D6C # 0 +0x0000D6C4 0x6D89 # 0 +0x0000D6C5 0x6D6E # 0 +0x0000D6C6 0x6D5A # 0 +0x0000D6C7 0x6D74 # 0 +0x0000D6C8 0x6D69 # 0 +0x0000D6C9 0x6D8C # 0 +0x0000D6CA 0x6D8A # 0 +0x0000D6CB 0x6D79 # 0 +0x0000D6CC 0x6D85 # 0 +0x0000D6CD 0x6D65 # 0 +0x0000D6CE 0x6D94 # 0 +0x0000D6CF 0x70CA # 0 +0x0000D6D0 0x70D8 # 0 +0x0000D6D1 0x70E4 # 0 +0x0000D6D2 0x70D9 # 0 +0x0000D6D3 0x70C8 # 0 +0x0000D6D4 0x70CF # 0 +0x0000D6D5 0x7239 # 0 +0x0000D6D6 0x7279 # 0 +0x0000D6D7 0x72FC # 0 +0x0000D6D8 0x72F9 # 0 +0x0000D6D9 0x72FD # 0 +0x0000D6DA 0x72F8 # 0 +0x0000D6DB 0x72F7 # 0 +0x0000D6DC 0x7386 # 0 +0x0000D6DD 0x73ED # 0 +0x0000D6DE 0x7409 # 0 +0x0000D6DF 0x73EE # 0 +0x0000D6E0 0x73E0 # 0 +0x0000D6E1 0x73EA # 0 +0x0000D6E2 0x73DE # 0 +0x0000D6E3 0x7554 # 0 +0x0000D6E4 0x755D # 0 +0x0000D6E5 0x755C # 0 +0x0000D6E6 0x755A # 0 +0x0000D6E7 0x7559 # 0 +0x0000D6E8 0x75BE # 0 +0x0000D6E9 0x75C5 # 0 +0x0000D6EA 0x75C7 # 0 +0x0000D6EB 0x75B2 # 0 +0x0000D6EC 0x75B3 # 0 +0x0000D6ED 0x75BD # 0 +0x0000D6EE 0x75BC # 0 +0x0000D6EF 0x75B9 # 0 +0x0000D6F0 0x75C2 # 0 +0x0000D6F1 0x75B8 # 0 +0x0000D6F2 0x768B # 0 +0x0000D6F3 0x76B0 # 0 +0x0000D6F4 0x76CA # 0 +0x0000D6F5 0x76CD # 0 +0x0000D6F6 0x76CE # 0 +0x0000D6F7 0x7729 # 0 +0x0000D6F8 0x771F # 0 +0x0000D6F9 0x7720 # 0 +0x0000D6FA 0x7728 # 0 +0x0000D6FB 0x77E9 # 0 +0x0000D6FC 0x7830 # 0 +0x0000D6FD 0x7827 # 0 +0x0000D6FE 0x7838 # 0 +0x0000D7A1 0x781D # 0 +0x0000D7A2 0x7834 # 0 +0x0000D7A3 0x7837 # 0 +0x0000D7A4 0x7825 # 0 +0x0000D7A5 0x782D # 0 +0x0000D7A6 0x7820 # 0 +0x0000D7A7 0x781F # 0 +0x0000D7A8 0x7832 # 0 +0x0000D7A9 0x7955 # 0 +0x0000D7AA 0x7950 # 0 +0x0000D7AB 0x7960 # 0 +0x0000D7AC 0x795F # 0 +0x0000D7AD 0x7956 # 0 +0x0000D7AE 0x795E # 0 +0x0000D7AF 0x795D # 0 +0x0000D7B0 0x7957 # 0 +0x0000D7B1 0x795A # 0 +0x0000D7B2 0x79E4 # 0 +0x0000D7B3 0x79E3 # 0 +0x0000D7B4 0x79E7 # 0 +0x0000D7B5 0x79DF # 0 +0x0000D7B6 0x79E6 # 0 +0x0000D7B7 0x79E9 # 0 +0x0000D7B8 0x79D8 # 0 +0x0000D7B9 0x7A84 # 0 +0x0000D7BA 0x7A88 # 0 +0x0000D7BB 0x7AD9 # 0 +0x0000D7BC 0x7B06 # 0 +0x0000D7BD 0x7B11 # 0 +0x0000D7BE 0x7C89 # 0 +0x0000D7BF 0x7D21 # 0 +0x0000D7C0 0x7D17 # 0 +0x0000D7C1 0x7D0B # 0 +0x0000D7C2 0x7D0A # 0 +0x0000D7C3 0x7D20 # 0 +0x0000D7C4 0x7D22 # 0 +0x0000D7C5 0x7D14 # 0 +0x0000D7C6 0x7D10 # 0 +0x0000D7C7 0x7D15 # 0 +0x0000D7C8 0x7D1A # 0 +0x0000D7C9 0x7D1C # 0 +0x0000D7CA 0x7D0D # 0 +0x0000D7CB 0x7D19 # 0 +0x0000D7CC 0x7D1B # 0 +0x0000D7CD 0x7F3A # 0 +0x0000D7CE 0x7F5F # 0 +0x0000D7CF 0x7F94 # 0 +0x0000D7D0 0x7FC5 # 0 +0x0000D7D1 0x7FC1 # 0 +0x0000D7D2 0x8006 # 0 +0x0000D7D3 0x8004 # 0 +0x0000D7D4 0x8018 # 0 +0x0000D7D5 0x8015 # 0 +0x0000D7D6 0x8019 # 0 +0x0000D7D7 0x8017 # 0 +0x0000D7D8 0x803D # 0 +0x0000D7D9 0x803F # 0 +0x0000D7DA 0x80F1 # 0 +0x0000D7DB 0x8102 # 0 +0x0000D7DC 0x80F0 # 0 +0x0000D7DD 0x8105 # 0 +0x0000D7DE 0x80ED # 0 +0x0000D7DF 0x80F4 # 0 +0x0000D7E0 0x8106 # 0 +0x0000D7E1 0x80F8 # 0 +0x0000D7E2 0x80F3 # 0 +0x0000D7E3 0x8108 # 0 +0x0000D7E4 0x80FD # 0 +0x0000D7E5 0x810A # 0 +0x0000D7E6 0x80FC # 0 +0x0000D7E7 0x80EF # 0 +0x0000D7E8 0x81ED # 0 +0x0000D7E9 0x81EC # 0 +0x0000D7EA 0x8200 # 0 +0x0000D7EB 0x8210 # 0 +0x0000D7EC 0x822A # 0 +0x0000D7ED 0x822B # 0 +0x0000D7EE 0x8228 # 0 +0x0000D7EF 0x822C # 0 +0x0000D7F0 0x82BB # 0 +0x0000D7F1 0x832B # 0 +0x0000D7F2 0x8352 # 0 +0x0000D7F3 0x8354 # 0 +0x0000D7F4 0x834A # 0 +0x0000D7F5 0x8338 # 0 +0x0000D7F6 0x8350 # 0 +0x0000D7F7 0x8349 # 0 +0x0000D7F8 0x8335 # 0 +0x0000D7F9 0x8334 # 0 +0x0000D7FA 0x834F # 0 +0x0000D7FB 0x8332 # 0 +0x0000D7FC 0x8339 # 0 +0x0000D7FD 0x8336 # 0 +0x0000D7FE 0x8317 # 0 +0x0000D8A1 0x8340 # 0 +0x0000D8A2 0x8331 # 0 +0x0000D8A3 0x8328 # 0 +0x0000D8A4 0x8343 # 0 +0x0000D8A5 0x8654 # 0 +0x0000D8A6 0x868A # 0 +0x0000D8A7 0x86AA # 0 +0x0000D8A8 0x8693 # 0 +0x0000D8A9 0x86A4 # 0 +0x0000D8AA 0x86A9 # 0 +0x0000D8AB 0x868C # 0 +0x0000D8AC 0x86A3 # 0 +0x0000D8AD 0x869C # 0 +0x0000D8AE 0x8870 # 0 +0x0000D8AF 0x8877 # 0 +0x0000D8B0 0x8881 # 0 +0x0000D8B1 0x8882 # 0 +0x0000D8B2 0x887D # 0 +0x0000D8B3 0x8879 # 0 +0x0000D8B4 0x8A18 # 0 +0x0000D8B5 0x8A10 # 0 +0x0000D8B6 0x8A0E # 0 +0x0000D8B7 0x8A0C # 0 +0x0000D8B8 0x8A15 # 0 +0x0000D8B9 0x8A0A # 0 +0x0000D8BA 0x8A17 # 0 +0x0000D8BB 0x8A13 # 0 +0x0000D8BC 0x8A16 # 0 +0x0000D8BD 0x8A0F # 0 +0x0000D8BE 0x8A11 # 0 +0x0000D8BF 0x8C48 # 0 +0x0000D8C0 0x8C7A # 0 +0x0000D8C1 0x8C79 # 0 +0x0000D8C2 0x8CA1 # 0 +0x0000D8C3 0x8CA2 # 0 +0x0000D8C4 0x8D77 # 0 +0x0000D8C5 0x8EAC # 0 +0x0000D8C6 0x8ED2 # 0 +0x0000D8C7 0x8ED4 # 0 +0x0000D8C8 0x8ECF # 0 +0x0000D8C9 0x8FB1 # 0 +0x0000D8CA 0x9001 # 0 +0x0000D8CB 0x9006 # 0 +0x0000D8CC 0x8FF7 # 0 +0x0000D8CD 0x9000 # 0 +0x0000D8CE 0x8FFA # 0 +0x0000D8CF 0x8FF4 # 0 +0x0000D8D0 0x9003 # 0 +0x0000D8D1 0x8FFD # 0 +0x0000D8D2 0x9005 # 0 +0x0000D8D3 0x8FF8 # 0 +0x0000D8D4 0x9095 # 0 +0x0000D8D5 0x90E1 # 0 +0x0000D8D6 0x90DD # 0 +0x0000D8D7 0x90E2 # 0 +0x0000D8D8 0x9152 # 0 +0x0000D8D9 0x914D # 0 +0x0000D8DA 0x914C # 0 +0x0000D8DB 0x91D8 # 0 +0x0000D8DC 0x91DD # 0 +0x0000D8DD 0x91D7 # 0 +0x0000D8DE 0x91DC # 0 +0x0000D8DF 0x91D9 # 0 +0x0000D8E0 0x9583 # 0 +0x0000D8E1 0x9662 # 0 +0x0000D8E2 0x9663 # 0 +0x0000D8E3 0x9661 # 0 +0x0000D8E4 0x965B # 0 +0x0000D8E5 0x965D # 0 +0x0000D8E6 0x9664 # 0 +0x0000D8E7 0x9658 # 0 +0x0000D8E8 0x965E # 0 +0x0000D8E9 0x96BB # 0 +0x0000D8EA 0x98E2 # 0 +0x0000D8EB 0x99AC # 0 +0x0000D8EC 0x9AA8 # 0 +0x0000D8ED 0x9AD8 # 0 +0x0000D8EE 0x9B25 # 0 +0x0000D8EF 0x9B32 # 0 +0x0000D8F0 0x9B3C # 0 +0x0000D8F1 0x4E7E # 0 +0x0000D8F2 0x507A # 0 +0x0000D8F3 0x507D # 0 +0x0000D8F4 0x505C # 0 +0x0000D8F5 0x5047 # 0 +0x0000D8F6 0x5043 # 0 +0x0000D8F7 0x504C # 0 +0x0000D8F8 0x505A # 0 +0x0000D8F9 0x5049 # 0 +0x0000D8FA 0x5065 # 0 +0x0000D8FB 0x5076 # 0 +0x0000D8FC 0x504E # 0 +0x0000D8FD 0x5055 # 0 +0x0000D8FE 0x5075 # 0 +0x0000D9A1 0x5074 # 0 +0x0000D9A2 0x5077 # 0 +0x0000D9A3 0x504F # 0 +0x0000D9A4 0x500F # 0 +0x0000D9A5 0x506F # 0 +0x0000D9A6 0x506D # 0 +0x0000D9A7 0x515C # 0 +0x0000D9A8 0x5195 # 0 +0x0000D9A9 0x51F0 # 0 +0x0000D9AA 0x526A # 0 +0x0000D9AB 0x526F # 0 +0x0000D9AC 0x52D2 # 0 +0x0000D9AD 0x52D9 # 0 +0x0000D9AE 0x52D8 # 0 +0x0000D9AF 0x52D5 # 0 +0x0000D9B0 0x5310 # 0 +0x0000D9B1 0x530F # 0 +0x0000D9B2 0x5319 # 0 +0x0000D9B3 0x533F # 0 +0x0000D9B4 0x5340 # 0 +0x0000D9B5 0x533E # 0 +0x0000D9B6 0x53C3 # 0 +0x0000D9B7 0x66FC # 0 +0x0000D9B8 0x5546 # 0 +0x0000D9B9 0x556A # 0 +0x0000D9BA 0x5566 # 0 +0x0000D9BB 0x5544 # 0 +0x0000D9BC 0x555E # 0 +0x0000D9BD 0x5561 # 0 +0x0000D9BE 0x5543 # 0 +0x0000D9BF 0x554A # 0 +0x0000D9C0 0x5531 # 0 +0x0000D9C1 0x5556 # 0 +0x0000D9C2 0x554F # 0 +0x0000D9C3 0x5555 # 0 +0x0000D9C4 0x552F # 0 +0x0000D9C5 0x5564 # 0 +0x0000D9C6 0x5538 # 0 +0x0000D9C7 0x552E # 0 +0x0000D9C8 0x555C # 0 +0x0000D9C9 0x552C # 0 +0x0000D9CA 0x5563 # 0 +0x0000D9CB 0x5533 # 0 +0x0000D9CC 0x5541 # 0 +0x0000D9CD 0x5557 # 0 +0x0000D9CE 0x5708 # 0 +0x0000D9CF 0x570B # 0 +0x0000D9D0 0x5709 # 0 +0x0000D9D1 0x57DF # 0 +0x0000D9D2 0x5805 # 0 +0x0000D9D3 0x580A # 0 +0x0000D9D4 0x5806 # 0 +0x0000D9D5 0x57E0 # 0 +0x0000D9D6 0x57E4 # 0 +0x0000D9D7 0x57FA # 0 +0x0000D9D8 0x5802 # 0 +0x0000D9D9 0x5835 # 0 +0x0000D9DA 0x57F7 # 0 +0x0000D9DB 0x57F9 # 0 +0x0000D9DC 0x5920 # 0 +0x0000D9DD 0x5962 # 0 +0x0000D9DE 0x5A36 # 0 +0x0000D9DF 0x5A41 # 0 +0x0000D9E0 0x5A49 # 0 +0x0000D9E1 0x5A66 # 0 +0x0000D9E2 0x5A6A # 0 +0x0000D9E3 0x5A40 # 0 +0x0000D9E4 0x5A3C # 0 +0x0000D9E5 0x5A62 # 0 +0x0000D9E6 0x5A5A # 0 +0x0000D9E7 0x5A46 # 0 +0x0000D9E8 0x5A4A # 0 +0x0000D9E9 0x5B70 # 0 +0x0000D9EA 0x5BC7 # 0 +0x0000D9EB 0x5BC5 # 0 +0x0000D9EC 0x5BC4 # 0 +0x0000D9ED 0x5BC2 # 0 +0x0000D9EE 0x5BBF # 0 +0x0000D9EF 0x5BC6 # 0 +0x0000D9F0 0x5C09 # 0 +0x0000D9F1 0x5C08 # 0 +0x0000D9F2 0x5C07 # 0 +0x0000D9F3 0x5C60 # 0 +0x0000D9F4 0x5C5C # 0 +0x0000D9F5 0x5C5D # 0 +0x0000D9F6 0x5D07 # 0 +0x0000D9F7 0x5D06 # 0 +0x0000D9F8 0x5D0E # 0 +0x0000D9F9 0x5D1B # 0 +0x0000D9FA 0x5D16 # 0 +0x0000D9FB 0x5D22 # 0 +0x0000D9FC 0x5D11 # 0 +0x0000D9FD 0x5D29 # 0 +0x0000D9FE 0x5D14 # 0 +0x0000DAA1 0x5D19 # 0 +0x0000DAA2 0x5D24 # 0 +0x0000DAA3 0x5D27 # 0 +0x0000DAA4 0x5D17 # 0 +0x0000DAA5 0x5DE2 # 0 +0x0000DAA6 0x5E38 # 0 +0x0000DAA7 0x5E36 # 0 +0x0000DAA8 0x5E33 # 0 +0x0000DAA9 0x5E37 # 0 +0x0000DAAA 0x5EB7 # 0 +0x0000DAAB 0x5EB8 # 0 +0x0000DAAC 0x5EB6 # 0 +0x0000DAAD 0x5EB5 # 0 +0x0000DAAE 0x5EBE # 0 +0x0000DAAF 0x5F35 # 0 +0x0000DAB0 0x5F37 # 0 +0x0000DAB1 0x5F57 # 0 +0x0000DAB2 0x5F6C # 0 +0x0000DAB3 0x5F69 # 0 +0x0000DAB4 0x5F6B # 0 +0x0000DAB5 0x5F97 # 0 +0x0000DAB6 0x5F99 # 0 +0x0000DAB7 0x5F9E # 0 +0x0000DAB8 0x5F98 # 0 +0x0000DAB9 0x5FA1 # 0 +0x0000DABA 0x5FA0 # 0 +0x0000DABB 0x5F9C # 0 +0x0000DABC 0x607F # 0 +0x0000DABD 0x60A3 # 0 +0x0000DABE 0x6089 # 0 +0x0000DABF 0x60A0 # 0 +0x0000DAC0 0x60A8 # 0 +0x0000DAC1 0x60CB # 0 +0x0000DAC2 0x60B4 # 0 +0x0000DAC3 0x60E6 # 0 +0x0000DAC4 0x60BD # 0 +0x0000DAC5 0x60C5 # 0 +0x0000DAC6 0x60BB # 0 +0x0000DAC7 0x60B5 # 0 +0x0000DAC8 0x60DC # 0 +0x0000DAC9 0x60BC # 0 +0x0000DACA 0x60D8 # 0 +0x0000DACB 0x60D5 # 0 +0x0000DACC 0x60C6 # 0 +0x0000DACD 0x60DF # 0 +0x0000DACE 0x60B8 # 0 +0x0000DACF 0x60DA # 0 +0x0000DAD0 0x60C7 # 0 +0x0000DAD1 0x621A # 0 +0x0000DAD2 0x621B # 0 +0x0000DAD3 0x6248 # 0 +0x0000DAD4 0x63A0 # 0 +0x0000DAD5 0x63A7 # 0 +0x0000DAD6 0x6372 # 0 +0x0000DAD7 0x6396 # 0 +0x0000DAD8 0x63A2 # 0 +0x0000DAD9 0x63A5 # 0 +0x0000DADA 0x6377 # 0 +0x0000DADB 0x6367 # 0 +0x0000DADC 0x6398 # 0 +0x0000DADD 0x63AA # 0 +0x0000DADE 0x6371 # 0 +0x0000DADF 0x63A9 # 0 +0x0000DAE0 0x6389 # 0 +0x0000DAE1 0x6383 # 0 +0x0000DAE2 0x639B # 0 +0x0000DAE3 0x636B # 0 +0x0000DAE4 0x63A8 # 0 +0x0000DAE5 0x6384 # 0 +0x0000DAE6 0x6388 # 0 +0x0000DAE7 0x6399 # 0 +0x0000DAE8 0x63A1 # 0 +0x0000DAE9 0x63AC # 0 +0x0000DAEA 0x6392 # 0 +0x0000DAEB 0x638F # 0 +0x0000DAEC 0x6380 # 0 +0x0000DAED 0x637B # 0 +0x0000DAEE 0x6369 # 0 +0x0000DAEF 0x6368 # 0 +0x0000DAF0 0x637A # 0 +0x0000DAF1 0x655D # 0 +0x0000DAF2 0x6556 # 0 +0x0000DAF3 0x6551 # 0 +0x0000DAF4 0x6559 # 0 +0x0000DAF5 0x6557 # 0 +0x0000DAF6 0x555F # 0 +0x0000DAF7 0x654F # 0 +0x0000DAF8 0x6558 # 0 +0x0000DAF9 0x6555 # 0 +0x0000DAFA 0x6554 # 0 +0x0000DAFB 0x659C # 0 +0x0000DAFC 0x659B # 0 +0x0000DAFD 0x65AC # 0 +0x0000DAFE 0x65CF # 0 +0x0000DBA1 0x65CB # 0 +0x0000DBA2 0x65CC # 0 +0x0000DBA3 0x65CE # 0 +0x0000DBA4 0x665D # 0 +0x0000DBA5 0x665A # 0 +0x0000DBA6 0x6664 # 0 +0x0000DBA7 0x6668 # 0 +0x0000DBA8 0x6666 # 0 +0x0000DBA9 0x665E # 0 +0x0000DBAA 0x66F9 # 0 +0x0000DBAB 0x52D7 # 0 +0x0000DBAC 0x671B # 0 +0x0000DBAD 0x6881 # 0 +0x0000DBAE 0x68AF # 0 +0x0000DBAF 0x68A2 # 0 +0x0000DBB0 0x6893 # 0 +0x0000DBB1 0x68B5 # 0 +0x0000DBB2 0x687F # 0 +0x0000DBB3 0x6876 # 0 +0x0000DBB4 0x68B1 # 0 +0x0000DBB5 0x68A7 # 0 +0x0000DBB6 0x6897 # 0 +0x0000DBB7 0x68B0 # 0 +0x0000DBB8 0x6883 # 0 +0x0000DBB9 0x68C4 # 0 +0x0000DBBA 0x68AD # 0 +0x0000DBBB 0x6886 # 0 +0x0000DBBC 0x6885 # 0 +0x0000DBBD 0x6894 # 0 +0x0000DBBE 0x689D # 0 +0x0000DBBF 0x68A8 # 0 +0x0000DBC0 0x689F # 0 +0x0000DBC1 0x68A1 # 0 +0x0000DBC2 0x6882 # 0 +0x0000DBC3 0x6B32 # 0 +0x0000DBC4 0x6BBA # 0 +0x0000DBC5 0x6BEB # 0 +0x0000DBC6 0x6BEC # 0 +0x0000DBC7 0x6C2B # 0 +0x0000DBC8 0x6D8E # 0 +0x0000DBC9 0x6DBC # 0 +0x0000DBCA 0x6DF3 # 0 +0x0000DBCB 0x6DD9 # 0 +0x0000DBCC 0x6DB2 # 0 +0x0000DBCD 0x6DE1 # 0 +0x0000DBCE 0x6DCC # 0 +0x0000DBCF 0x6DE4 # 0 +0x0000DBD0 0x6DFB # 0 +0x0000DBD1 0x6DFA # 0 +0x0000DBD2 0x6E05 # 0 +0x0000DBD3 0x6DC7 # 0 +0x0000DBD4 0x6DCB # 0 +0x0000DBD5 0x6DAF # 0 +0x0000DBD6 0x6DD1 # 0 +0x0000DBD7 0x6DAE # 0 +0x0000DBD8 0x6DDE # 0 +0x0000DBD9 0x6DF9 # 0 +0x0000DBDA 0x6DB8 # 0 +0x0000DBDB 0x6DF7 # 0 +0x0000DBDC 0x6DF5 # 0 +0x0000DBDD 0x6DC5 # 0 +0x0000DBDE 0x6DD2 # 0 +0x0000DBDF 0x6E1A # 0 +0x0000DBE0 0x6DB5 # 0 +0x0000DBE1 0x6DDA # 0 +0x0000DBE2 0x6DEB # 0 +0x0000DBE3 0x6DD8 # 0 +0x0000DBE4 0x6DEA # 0 +0x0000DBE5 0x6DF1 # 0 +0x0000DBE6 0x6DEE # 0 +0x0000DBE7 0x6DE8 # 0 +0x0000DBE8 0x6DC6 # 0 +0x0000DBE9 0x6DC4 # 0 +0x0000DBEA 0x6DAA # 0 +0x0000DBEB 0x6DEC # 0 +0x0000DBEC 0x6DBF # 0 +0x0000DBED 0x6DE6 # 0 +0x0000DBEE 0x70F9 # 0 +0x0000DBEF 0x7109 # 0 +0x0000DBF0 0x710A # 0 +0x0000DBF1 0x70FD # 0 +0x0000DBF2 0x70EF # 0 +0x0000DBF3 0x723D # 0 +0x0000DBF4 0x727D # 0 +0x0000DBF5 0x7281 # 0 +0x0000DBF6 0x731C # 0 +0x0000DBF7 0x731B # 0 +0x0000DBF8 0x7316 # 0 +0x0000DBF9 0x7313 # 0 +0x0000DBFA 0x7319 # 0 +0x0000DBFB 0x7387 # 0 +0x0000DBFC 0x7405 # 0 +0x0000DBFD 0x740A # 0 +0x0000DBFE 0x7403 # 0 +0x0000DCA1 0x7406 # 0 +0x0000DCA2 0x73FE # 0 +0x0000DCA3 0x740D # 0 +0x0000DCA4 0x74E0 # 0 +0x0000DCA5 0x74F6 # 0 +0x0000DCA6 0x74F7 # 0 +0x0000DCA7 0x751C # 0 +0x0000DCA8 0x7522 # 0 +0x0000DCA9 0x7565 # 0 +0x0000DCAA 0x7566 # 0 +0x0000DCAB 0x7562 # 0 +0x0000DCAC 0x7570 # 0 +0x0000DCAD 0x758F # 0 +0x0000DCAE 0x75D4 # 0 +0x0000DCAF 0x75D5 # 0 +0x0000DCB0 0x75B5 # 0 +0x0000DCB1 0x75CA # 0 +0x0000DCB2 0x75CD # 0 +0x0000DCB3 0x768E # 0 +0x0000DCB4 0x76D4 # 0 +0x0000DCB5 0x76D2 # 0 +0x0000DCB6 0x76DB # 0 +0x0000DCB7 0x7737 # 0 +0x0000DCB8 0x773E # 0 +0x0000DCB9 0x773C # 0 +0x0000DCBA 0x7736 # 0 +0x0000DCBB 0x7738 # 0 +0x0000DCBC 0x773A # 0 +0x0000DCBD 0x786B # 0 +0x0000DCBE 0x7843 # 0 +0x0000DCBF 0x784E # 0 +0x0000DCC0 0x7965 # 0 +0x0000DCC1 0x7968 # 0 +0x0000DCC2 0x796D # 0 +0x0000DCC3 0x79FB # 0 +0x0000DCC4 0x7A92 # 0 +0x0000DCC5 0x7A95 # 0 +0x0000DCC6 0x7B20 # 0 +0x0000DCC7 0x7B28 # 0 +0x0000DCC8 0x7B1B # 0 +0x0000DCC9 0x7B2C # 0 +0x0000DCCA 0x7B26 # 0 +0x0000DCCB 0x7B19 # 0 +0x0000DCCC 0x7B1E # 0 +0x0000DCCD 0x7B2E # 0 +0x0000DCCE 0x7C92 # 0 +0x0000DCCF 0x7C97 # 0 +0x0000DCD0 0x7C95 # 0 +0x0000DCD1 0x7D46 # 0 +0x0000DCD2 0x7D43 # 0 +0x0000DCD3 0x7D71 # 0 +0x0000DCD4 0x7D2E # 0 +0x0000DCD5 0x7D39 # 0 +0x0000DCD6 0x7D3C # 0 +0x0000DCD7 0x7D40 # 0 +0x0000DCD8 0x7D30 # 0 +0x0000DCD9 0x7D33 # 0 +0x0000DCDA 0x7D44 # 0 +0x0000DCDB 0x7D2F # 0 +0x0000DCDC 0x7D42 # 0 +0x0000DCDD 0x7D32 # 0 +0x0000DCDE 0x7D31 # 0 +0x0000DCDF 0x7F3D # 0 +0x0000DCE0 0x7F9E # 0 +0x0000DCE1 0x7F9A # 0 +0x0000DCE2 0x7FCC # 0 +0x0000DCE3 0x7FCE # 0 +0x0000DCE4 0x7FD2 # 0 +0x0000DCE5 0x801C # 0 +0x0000DCE6 0x804A # 0 +0x0000DCE7 0x8046 # 0 +0x0000DCE8 0x812F # 0 +0x0000DCE9 0x8116 # 0 +0x0000DCEA 0x8123 # 0 +0x0000DCEB 0x812B # 0 +0x0000DCEC 0x8129 # 0 +0x0000DCED 0x8130 # 0 +0x0000DCEE 0x8124 # 0 +0x0000DCEF 0x8202 # 0 +0x0000DCF0 0x8235 # 0 +0x0000DCF1 0x8237 # 0 +0x0000DCF2 0x8236 # 0 +0x0000DCF3 0x8239 # 0 +0x0000DCF4 0x838E # 0 +0x0000DCF5 0x839E # 0 +0x0000DCF6 0x8398 # 0 +0x0000DCF7 0x8378 # 0 +0x0000DCF8 0x83A2 # 0 +0x0000DCF9 0x8396 # 0 +0x0000DCFA 0x83BD # 0 +0x0000DCFB 0x83AB # 0 +0x0000DCFC 0x8392 # 0 +0x0000DCFD 0x838A # 0 +0x0000DCFE 0x8393 # 0 +0x0000DDA1 0x8389 # 0 +0x0000DDA2 0x83A0 # 0 +0x0000DDA3 0x8377 # 0 +0x0000DDA4 0x837B # 0 +0x0000DDA5 0x837C # 0 +0x0000DDA6 0x8386 # 0 +0x0000DDA7 0x83A7 # 0 +0x0000DDA8 0x8655 # 0 +0x0000DDA9 0x5F6A # 0 +0x0000DDAA 0x86C7 # 0 +0x0000DDAB 0x86C0 # 0 +0x0000DDAC 0x86B6 # 0 +0x0000DDAD 0x86C4 # 0 +0x0000DDAE 0x86B5 # 0 +0x0000DDAF 0x86C6 # 0 +0x0000DDB0 0x86CB # 0 +0x0000DDB1 0x86B1 # 0 +0x0000DDB2 0x86AF # 0 +0x0000DDB3 0x86C9 # 0 +0x0000DDB4 0x8853 # 0 +0x0000DDB5 0x889E # 0 +0x0000DDB6 0x8888 # 0 +0x0000DDB7 0x88AB # 0 +0x0000DDB8 0x8892 # 0 +0x0000DDB9 0x8896 # 0 +0x0000DDBA 0x888D # 0 +0x0000DDBB 0x888B # 0 +0x0000DDBC 0x8993 # 0 +0x0000DDBD 0x898F # 0 +0x0000DDBE 0x8A2A # 0 +0x0000DDBF 0x8A1D # 0 +0x0000DDC0 0x8A23 # 0 +0x0000DDC1 0x8A25 # 0 +0x0000DDC2 0x8A31 # 0 +0x0000DDC3 0x8A2D # 0 +0x0000DDC4 0x8A1F # 0 +0x0000DDC5 0x8A1B # 0 +0x0000DDC6 0x8A22 # 0 +0x0000DDC7 0x8C49 # 0 +0x0000DDC8 0x8C5A # 0 +0x0000DDC9 0x8CA9 # 0 +0x0000DDCA 0x8CAC # 0 +0x0000DDCB 0x8CAB # 0 +0x0000DDCC 0x8CA8 # 0 +0x0000DDCD 0x8CAA # 0 +0x0000DDCE 0x8CA7 # 0 +0x0000DDCF 0x8D67 # 0 +0x0000DDD0 0x8D66 # 0 +0x0000DDD1 0x8DBE # 0 +0x0000DDD2 0x8DBA # 0 +0x0000DDD3 0x8EDB # 0 +0x0000DDD4 0x8EDF # 0 +0x0000DDD5 0x9019 # 0 +0x0000DDD6 0x900D # 0 +0x0000DDD7 0x901A # 0 +0x0000DDD8 0x9017 # 0 +0x0000DDD9 0x9023 # 0 +0x0000DDDA 0x901F # 0 +0x0000DDDB 0x901D # 0 +0x0000DDDC 0x9010 # 0 +0x0000DDDD 0x9015 # 0 +0x0000DDDE 0x901E # 0 +0x0000DDDF 0x9020 # 0 +0x0000DDE0 0x900F # 0 +0x0000DDE1 0x9022 # 0 +0x0000DDE2 0x9016 # 0 +0x0000DDE3 0x901B # 0 +0x0000DDE4 0x9014 # 0 +0x0000DDE5 0x90E8 # 0 +0x0000DDE6 0x90ED # 0 +0x0000DDE7 0x90FD # 0 +0x0000DDE8 0x9157 # 0 +0x0000DDE9 0x91CE # 0 +0x0000DDEA 0x91F5 # 0 +0x0000DDEB 0x91E6 # 0 +0x0000DDEC 0x91E3 # 0 +0x0000DDED 0x91E7 # 0 +0x0000DDEE 0x91ED # 0 +0x0000DDEF 0x91E9 # 0 +0x0000DDF0 0x9589 # 0 +0x0000DDF1 0x966A # 0 +0x0000DDF2 0x9675 # 0 +0x0000DDF3 0x9673 # 0 +0x0000DDF4 0x9678 # 0 +0x0000DDF5 0x9670 # 0 +0x0000DDF6 0x9674 # 0 +0x0000DDF7 0x9676 # 0 +0x0000DDF8 0x9677 # 0 +0x0000DDF9 0x966C # 0 +0x0000DDFA 0x96C0 # 0 +0x0000DDFB 0x96EA # 0 +0x0000DDFC 0x96E9 # 0 +0x0000DDFD 0x7AE0 # 0 +0x0000DDFE 0x7ADF # 0 +0x0000DEA1 0x9802 # 0 +0x0000DEA2 0x9803 # 0 +0x0000DEA3 0x9B5A # 0 +0x0000DEA4 0x9CE5 # 0 +0x0000DEA5 0x9E75 # 0 +0x0000DEA6 0x9E7F # 0 +0x0000DEA7 0x9EA5 # 0 +0x0000DEA8 0x9EBB # 0 +0x0000DEA9 0x50A2 # 0 +0x0000DEAA 0x508D # 0 +0x0000DEAB 0x5085 # 0 +0x0000DEAC 0x5099 # 0 +0x0000DEAD 0x5091 # 0 +0x0000DEAE 0x5080 # 0 +0x0000DEAF 0x5096 # 0 +0x0000DEB0 0x5098 # 0 +0x0000DEB1 0x509A # 0 +0x0000DEB2 0x6700 # 0 +0x0000DEB3 0x51F1 # 0 +0x0000DEB4 0x5272 # 0 +0x0000DEB5 0x5274 # 0 +0x0000DEB6 0x5275 # 0 +0x0000DEB7 0x5269 # 0 +0x0000DEB8 0x52DE # 0 +0x0000DEB9 0x52DD # 0 +0x0000DEBA 0x52DB # 0 +0x0000DEBB 0x535A # 0 +0x0000DEBC 0x53A5 # 0 +0x0000DEBD 0x557B # 0 +0x0000DEBE 0x5580 # 0 +0x0000DEBF 0x55A7 # 0 +0x0000DEC0 0x557C # 0 +0x0000DEC1 0x558A # 0 +0x0000DEC2 0x559D # 0 +0x0000DEC3 0x5598 # 0 +0x0000DEC4 0x5582 # 0 +0x0000DEC5 0x559C # 0 +0x0000DEC6 0x55AA # 0 +0x0000DEC7 0x5594 # 0 +0x0000DEC8 0x5587 # 0 +0x0000DEC9 0x558B # 0 +0x0000DECA 0x5583 # 0 +0x0000DECB 0x55B3 # 0 +0x0000DECC 0x55AE # 0 +0x0000DECD 0x559F # 0 +0x0000DECE 0x553E # 0 +0x0000DECF 0x55B2 # 0 +0x0000DED0 0x559A # 0 +0x0000DED1 0x55BB # 0 +0x0000DED2 0x55AC # 0 +0x0000DED3 0x55B1 # 0 +0x0000DED4 0x557E # 0 +0x0000DED5 0x5589 # 0 +0x0000DED6 0x55AB # 0 +0x0000DED7 0x5599 # 0 +0x0000DED8 0x570D # 0 +0x0000DED9 0x582F # 0 +0x0000DEDA 0x582A # 0 +0x0000DEDB 0x5834 # 0 +0x0000DEDC 0x5824 # 0 +0x0000DEDD 0x5830 # 0 +0x0000DEDE 0x5831 # 0 +0x0000DEDF 0x5821 # 0 +0x0000DEE0 0x581D # 0 +0x0000DEE1 0x5820 # 0 +0x0000DEE2 0x58F9 # 0 +0x0000DEE3 0x58FA # 0 +0x0000DEE4 0x5960 # 0 +0x0000DEE5 0x5A77 # 0 +0x0000DEE6 0x5A9A # 0 +0x0000DEE7 0x5A7F # 0 +0x0000DEE8 0x5A92 # 0 +0x0000DEE9 0x5A9B # 0 +0x0000DEEA 0x5AA7 # 0 +0x0000DEEB 0x5B73 # 0 +0x0000DEEC 0x5B71 # 0 +0x0000DEED 0x5BD2 # 0 +0x0000DEEE 0x5BCC # 0 +0x0000DEEF 0x5BD3 # 0 +0x0000DEF0 0x5BD0 # 0 +0x0000DEF1 0x5C0A # 0 +0x0000DEF2 0x5C0B # 0 +0x0000DEF3 0x5C31 # 0 +0x0000DEF4 0x5D4C # 0 +0x0000DEF5 0x5D50 # 0 +0x0000DEF6 0x5D34 # 0 +0x0000DEF7 0x5D47 # 0 +0x0000DEF8 0x5DFD # 0 +0x0000DEF9 0x5E45 # 0 +0x0000DEFA 0x5E3D # 0 +0x0000DEFB 0x5E40 # 0 +0x0000DEFC 0x5E43 # 0 +0x0000DEFD 0x5E7E # 0 +0x0000DEFE 0x5ECA # 0 +0x0000DFA1 0x5EC1 # 0 +0x0000DFA2 0x5EC2 # 0 +0x0000DFA3 0x5EC4 # 0 +0x0000DFA4 0x5F3C # 0 +0x0000DFA5 0x5F6D # 0 +0x0000DFA6 0x5FA9 # 0 +0x0000DFA7 0x5FAA # 0 +0x0000DFA8 0x5FA8 # 0 +0x0000DFA9 0x60D1 # 0 +0x0000DFAA 0x60E1 # 0 +0x0000DFAB 0x60B2 # 0 +0x0000DFAC 0x60B6 # 0 +0x0000DFAD 0x60E0 # 0 +0x0000DFAE 0x611C # 0 +0x0000DFAF 0x6123 # 0 +0x0000DFB0 0x60FA # 0 +0x0000DFB1 0x6115 # 0 +0x0000DFB2 0x60F0 # 0 +0x0000DFB3 0x60FB # 0 +0x0000DFB4 0x60F4 # 0 +0x0000DFB5 0x6168 # 0 +0x0000DFB6 0x60F1 # 0 +0x0000DFB7 0x610E # 0 +0x0000DFB8 0x60F6 # 0 +0x0000DFB9 0x6109 # 0 +0x0000DFBA 0x6100 # 0 +0x0000DFBB 0x6112 # 0 +0x0000DFBC 0x621F # 0 +0x0000DFBD 0x6249 # 0 +0x0000DFBE 0x63A3 # 0 +0x0000DFBF 0x638C # 0 +0x0000DFC0 0x63CF # 0 +0x0000DFC1 0x63C0 # 0 +0x0000DFC2 0x63E9 # 0 +0x0000DFC3 0x63C9 # 0 +0x0000DFC4 0x63C6 # 0 +0x0000DFC5 0x63CD # 0 +0x0000DFC6 0x63D2 # 0 +0x0000DFC7 0x63E3 # 0 +0x0000DFC8 0x63D0 # 0 +0x0000DFC9 0x63E1 # 0 +0x0000DFCA 0x63D6 # 0 +0x0000DFCB 0x63ED # 0 +0x0000DFCC 0x63EE # 0 +0x0000DFCD 0x6376 # 0 +0x0000DFCE 0x63F4 # 0 +0x0000DFCF 0x63EA # 0 +0x0000DFD0 0x63DB # 0 +0x0000DFD1 0x6452 # 0 +0x0000DFD2 0x63DA # 0 +0x0000DFD3 0x63F9 # 0 +0x0000DFD4 0x655E # 0 +0x0000DFD5 0x6566 # 0 +0x0000DFD6 0x6562 # 0 +0x0000DFD7 0x6563 # 0 +0x0000DFD8 0x6591 # 0 +0x0000DFD9 0x6590 # 0 +0x0000DFDA 0x65AF # 0 +0x0000DFDB 0x666E # 0 +0x0000DFDC 0x6670 # 0 +0x0000DFDD 0x6674 # 0 +0x0000DFDE 0x6676 # 0 +0x0000DFDF 0x666F # 0 +0x0000DFE0 0x6691 # 0 +0x0000DFE1 0x667A # 0 +0x0000DFE2 0x667E # 0 +0x0000DFE3 0x6677 # 0 +0x0000DFE4 0x66FE # 0 +0x0000DFE5 0x66FF # 0 +0x0000DFE6 0x671F # 0 +0x0000DFE7 0x671D # 0 +0x0000DFE8 0x68FA # 0 +0x0000DFE9 0x68D5 # 0 +0x0000DFEA 0x68E0 # 0 +0x0000DFEB 0x68D8 # 0 +0x0000DFEC 0x68D7 # 0 +0x0000DFED 0x6905 # 0 +0x0000DFEE 0x68DF # 0 +0x0000DFEF 0x68F5 # 0 +0x0000DFF0 0x68EE # 0 +0x0000DFF1 0x68E7 # 0 +0x0000DFF2 0x68F9 # 0 +0x0000DFF3 0x68D2 # 0 +0x0000DFF4 0x68F2 # 0 +0x0000DFF5 0x68E3 # 0 +0x0000DFF6 0x68CB # 0 +0x0000DFF7 0x68CD # 0 +0x0000DFF8 0x690D # 0 +0x0000DFF9 0x6912 # 0 +0x0000DFFA 0x690E # 0 +0x0000DFFB 0x68C9 # 0 +0x0000DFFC 0x68DA # 0 +0x0000DFFD 0x696E # 0 +0x0000DFFE 0x68FB # 0 +0x0000E0A1 0x6B3E # 0 +0x0000E0A2 0x6B3A # 0 +0x0000E0A3 0x6B3D # 0 +0x0000E0A4 0x6B98 # 0 +0x0000E0A5 0x6B96 # 0 +0x0000E0A6 0x6BBC # 0 +0x0000E0A7 0x6BEF # 0 +0x0000E0A8 0x6C2E # 0 +0x0000E0A9 0x6C2F # 0 +0x0000E0AA 0x6C2C # 0 +0x0000E0AB 0x6E2F # 0 +0x0000E0AC 0x6E38 # 0 +0x0000E0AD 0x6E54 # 0 +0x0000E0AE 0x6E21 # 0 +0x0000E0AF 0x6E32 # 0 +0x0000E0B0 0x6E67 # 0 +0x0000E0B1 0x6E4A # 0 +0x0000E0B2 0x6E20 # 0 +0x0000E0B3 0x6E25 # 0 +0x0000E0B4 0x6E23 # 0 +0x0000E0B5 0x6E1B # 0 +0x0000E0B6 0x6E5B # 0 +0x0000E0B7 0x6E58 # 0 +0x0000E0B8 0x6E24 # 0 +0x0000E0B9 0x6E56 # 0 +0x0000E0BA 0x6E6E # 0 +0x0000E0BB 0x6E2D # 0 +0x0000E0BC 0x6E26 # 0 +0x0000E0BD 0x6E6F # 0 +0x0000E0BE 0x6E34 # 0 +0x0000E0BF 0x6E4D # 0 +0x0000E0C0 0x6E3A # 0 +0x0000E0C1 0x6E2C # 0 +0x0000E0C2 0x6E43 # 0 +0x0000E0C3 0x6E1D # 0 +0x0000E0C4 0x6E3E # 0 +0x0000E0C5 0x6ECB # 0 +0x0000E0C6 0x6E89 # 0 +0x0000E0C7 0x6E19 # 0 +0x0000E0C8 0x6E4E # 0 +0x0000E0C9 0x6E63 # 0 +0x0000E0CA 0x6E44 # 0 +0x0000E0CB 0x6E72 # 0 +0x0000E0CC 0x6E69 # 0 +0x0000E0CD 0x6E5F # 0 +0x0000E0CE 0x7119 # 0 +0x0000E0CF 0x711A # 0 +0x0000E0D0 0x7126 # 0 +0x0000E0D1 0x7130 # 0 +0x0000E0D2 0x7121 # 0 +0x0000E0D3 0x7136 # 0 +0x0000E0D4 0x716E # 0 +0x0000E0D5 0x711C # 0 +0x0000E0D6 0x724C # 0 +0x0000E0D7 0x7284 # 0 +0x0000E0D8 0x7280 # 0 +0x0000E0D9 0x7336 # 0 +0x0000E0DA 0x7325 # 0 +0x0000E0DB 0x7334 # 0 +0x0000E0DC 0x7329 # 0 +0x0000E0DD 0x743A # 0 +0x0000E0DE 0x742A # 0 +0x0000E0DF 0x7433 # 0 +0x0000E0E0 0x7422 # 0 +0x0000E0E1 0x7425 # 0 +0x0000E0E2 0x7435 # 0 +0x0000E0E3 0x7436 # 0 +0x0000E0E4 0x7434 # 0 +0x0000E0E5 0x742F # 0 +0x0000E0E6 0x741B # 0 +0x0000E0E7 0x7426 # 0 +0x0000E0E8 0x7428 # 0 +0x0000E0E9 0x7525 # 0 +0x0000E0EA 0x7526 # 0 +0x0000E0EB 0x756B # 0 +0x0000E0EC 0x756A # 0 +0x0000E0ED 0x75E2 # 0 +0x0000E0EE 0x75DB # 0 +0x0000E0EF 0x75E3 # 0 +0x0000E0F0 0x75D9 # 0 +0x0000E0F1 0x75D8 # 0 +0x0000E0F2 0x75DE # 0 +0x0000E0F3 0x75E0 # 0 +0x0000E0F4 0x767B # 0 +0x0000E0F5 0x767C # 0 +0x0000E0F6 0x7696 # 0 +0x0000E0F7 0x7693 # 0 +0x0000E0F8 0x76B4 # 0 +0x0000E0F9 0x76DC # 0 +0x0000E0FA 0x774F # 0 +0x0000E0FB 0x77ED # 0 +0x0000E0FC 0x785D # 0 +0x0000E0FD 0x786C # 0 +0x0000E0FE 0x786F # 0 +0x0000E1A1 0x7A0D # 0 +0x0000E1A2 0x7A08 # 0 +0x0000E1A3 0x7A0B # 0 +0x0000E1A4 0x7A05 # 0 +0x0000E1A5 0x7A00 # 0 +0x0000E1A6 0x7A98 # 0 +0x0000E1A7 0x7A97 # 0 +0x0000E1A8 0x7A96 # 0 +0x0000E1A9 0x7AE5 # 0 +0x0000E1AA 0x7AE3 # 0 +0x0000E1AB 0x7B49 # 0 +0x0000E1AC 0x7B56 # 0 +0x0000E1AD 0x7B46 # 0 +0x0000E1AE 0x7B50 # 0 +0x0000E1AF 0x7B52 # 0 +0x0000E1B0 0x7B54 # 0 +0x0000E1B1 0x7B4D # 0 +0x0000E1B2 0x7B4B # 0 +0x0000E1B3 0x7B4F # 0 +0x0000E1B4 0x7B51 # 0 +0x0000E1B5 0x7C9F # 0 +0x0000E1B6 0x7CA5 # 0 +0x0000E1B7 0x7D5E # 0 +0x0000E1B8 0x7D50 # 0 +0x0000E1B9 0x7D68 # 0 +0x0000E1BA 0x7D55 # 0 +0x0000E1BB 0x7D2B # 0 +0x0000E1BC 0x7D6E # 0 +0x0000E1BD 0x7D72 # 0 +0x0000E1BE 0x7D61 # 0 +0x0000E1BF 0x7D66 # 0 +0x0000E1C0 0x7D62 # 0 +0x0000E1C1 0x7D70 # 0 +0x0000E1C2 0x7D73 # 0 +0x0000E1C3 0x5584 # 0 +0x0000E1C4 0x7FD4 # 0 +0x0000E1C5 0x7FD5 # 0 +0x0000E1C6 0x800B # 0 +0x0000E1C7 0x8052 # 0 +0x0000E1C8 0x8085 # 0 +0x0000E1C9 0x8155 # 0 +0x0000E1CA 0x8154 # 0 +0x0000E1CB 0x814B # 0 +0x0000E1CC 0x8151 # 0 +0x0000E1CD 0x814E # 0 +0x0000E1CE 0x8139 # 0 +0x0000E1CF 0x8146 # 0 +0x0000E1D0 0x813E # 0 +0x0000E1D1 0x814C # 0 +0x0000E1D2 0x8153 # 0 +0x0000E1D3 0x8174 # 0 +0x0000E1D4 0x8212 # 0 +0x0000E1D5 0x821C # 0 +0x0000E1D6 0x83E9 # 0 +0x0000E1D7 0x8403 # 0 +0x0000E1D8 0x83F8 # 0 +0x0000E1D9 0x840D # 0 +0x0000E1DA 0x83E0 # 0 +0x0000E1DB 0x83C5 # 0 +0x0000E1DC 0x840B # 0 +0x0000E1DD 0x83C1 # 0 +0x0000E1DE 0x83EF # 0 +0x0000E1DF 0x83F1 # 0 +0x0000E1E0 0x83F4 # 0 +0x0000E1E1 0x8457 # 0 +0x0000E1E2 0x840A # 0 +0x0000E1E3 0x83F0 # 0 +0x0000E1E4 0x840C # 0 +0x0000E1E5 0x83CC # 0 +0x0000E1E6 0x83FD # 0 +0x0000E1E7 0x83F2 # 0 +0x0000E1E8 0x83CA # 0 +0x0000E1E9 0x8438 # 0 +0x0000E1EA 0x840E # 0 +0x0000E1EB 0x8404 # 0 +0x0000E1EC 0x83DC # 0 +0x0000E1ED 0x8407 # 0 +0x0000E1EE 0x83D4 # 0 +0x0000E1EF 0x83DF # 0 +0x0000E1F0 0x865B # 0 +0x0000E1F1 0x86DF # 0 +0x0000E1F2 0x86D9 # 0 +0x0000E1F3 0x86ED # 0 +0x0000E1F4 0x86D4 # 0 +0x0000E1F5 0x86DB # 0 +0x0000E1F6 0x86E4 # 0 +0x0000E1F7 0x86D0 # 0 +0x0000E1F8 0x86DE # 0 +0x0000E1F9 0x8857 # 0 +0x0000E1FA 0x88C1 # 0 +0x0000E1FB 0x88C2 # 0 +0x0000E1FC 0x88B1 # 0 +0x0000E1FD 0x8983 # 0 +0x0000E1FE 0x8996 # 0 +0x0000E2A1 0x8A3B # 0 +0x0000E2A2 0x8A60 # 0 +0x0000E2A3 0x8A55 # 0 +0x0000E2A4 0x8A5E # 0 +0x0000E2A5 0x8A3C # 0 +0x0000E2A6 0x8A41 # 0 +0x0000E2A7 0x8A54 # 0 +0x0000E2A8 0x8A5B # 0 +0x0000E2A9 0x8A50 # 0 +0x0000E2AA 0x8A46 # 0 +0x0000E2AB 0x8A34 # 0 +0x0000E2AC 0x8A3A # 0 +0x0000E2AD 0x8A36 # 0 +0x0000E2AE 0x8A56 # 0 +0x0000E2AF 0x8C61 # 0 +0x0000E2B0 0x8C82 # 0 +0x0000E2B1 0x8CAF # 0 +0x0000E2B2 0x8CBC # 0 +0x0000E2B3 0x8CB3 # 0 +0x0000E2B4 0x8CBD # 0 +0x0000E2B5 0x8CC1 # 0 +0x0000E2B6 0x8CBB # 0 +0x0000E2B7 0x8CC0 # 0 +0x0000E2B8 0x8CB4 # 0 +0x0000E2B9 0x8CB7 # 0 +0x0000E2BA 0x8CB6 # 0 +0x0000E2BB 0x8CBF # 0 +0x0000E2BC 0x8CB8 # 0 +0x0000E2BD 0x8D8A # 0 +0x0000E2BE 0x8D85 # 0 +0x0000E2BF 0x8D81 # 0 +0x0000E2C0 0x8DCE # 0 +0x0000E2C1 0x8DDD # 0 +0x0000E2C2 0x8DCB # 0 +0x0000E2C3 0x8DDA # 0 +0x0000E2C4 0x8DD1 # 0 +0x0000E2C5 0x8DCC # 0 +0x0000E2C6 0x8DDB # 0 +0x0000E2C7 0x8DC6 # 0 +0x0000E2C8 0x8EFB # 0 +0x0000E2C9 0x8EF8 # 0 +0x0000E2CA 0x8EFC # 0 +0x0000E2CB 0x8F9C # 0 +0x0000E2CC 0x902E # 0 +0x0000E2CD 0x9035 # 0 +0x0000E2CE 0x9031 # 0 +0x0000E2CF 0x9038 # 0 +0x0000E2D0 0x9032 # 0 +0x0000E2D1 0x9036 # 0 +0x0000E2D2 0x9102 # 0 +0x0000E2D3 0x90F5 # 0 +0x0000E2D4 0x9109 # 0 +0x0000E2D5 0x90FE # 0 +0x0000E2D6 0x9163 # 0 +0x0000E2D7 0x9165 # 0 +0x0000E2D8 0x91CF # 0 +0x0000E2D9 0x9214 # 0 +0x0000E2DA 0x9215 # 0 +0x0000E2DB 0x9223 # 0 +0x0000E2DC 0x9209 # 0 +0x0000E2DD 0x921E # 0 +0x0000E2DE 0x920D # 0 +0x0000E2DF 0x9210 # 0 +0x0000E2E0 0x9207 # 0 +0x0000E2E1 0x9211 # 0 +0x0000E2E2 0x9594 # 0 +0x0000E2E3 0x958F # 0 +0x0000E2E4 0x958B # 0 +0x0000E2E5 0x9591 # 0 +0x0000E2E6 0x9593 # 0 +0x0000E2E7 0x9592 # 0 +0x0000E2E8 0x958E # 0 +0x0000E2E9 0x968A # 0 +0x0000E2EA 0x968E # 0 +0x0000E2EB 0x968B # 0 +0x0000E2EC 0x967D # 0 +0x0000E2ED 0x9685 # 0 +0x0000E2EE 0x9686 # 0 +0x0000E2EF 0x968D # 0 +0x0000E2F0 0x9672 # 0 +0x0000E2F1 0x9684 # 0 +0x0000E2F2 0x96C1 # 0 +0x0000E2F3 0x96C5 # 0 +0x0000E2F4 0x96C4 # 0 +0x0000E2F5 0x96C6 # 0 +0x0000E2F6 0x96C7 # 0 +0x0000E2F7 0x96EF # 0 +0x0000E2F8 0x96F2 # 0 +0x0000E2F9 0x97CC # 0 +0x0000E2FA 0x9805 # 0 +0x0000E2FB 0x9806 # 0 +0x0000E2FC 0x9808 # 0 +0x0000E2FD 0x98E7 # 0 +0x0000E2FE 0x98EA # 0 +0x0000E3A1 0x98EF # 0 +0x0000E3A2 0x98E9 # 0 +0x0000E3A3 0x98F2 # 0 +0x0000E3A4 0x98ED # 0 +0x0000E3A5 0x99AE # 0 +0x0000E3A6 0x99AD # 0 +0x0000E3A7 0x9EC3 # 0 +0x0000E3A8 0x9ECD # 0 +0x0000E3A9 0x9ED1 # 0 +0x0000E3AA 0x4E82 # 0 +0x0000E3AB 0x50AD # 0 +0x0000E3AC 0x50B5 # 0 +0x0000E3AD 0x50B2 # 0 +0x0000E3AE 0x50B3 # 0 +0x0000E3AF 0x50C5 # 0 +0x0000E3B0 0x50BE # 0 +0x0000E3B1 0x50AC # 0 +0x0000E3B2 0x50B7 # 0 +0x0000E3B3 0x50BB # 0 +0x0000E3B4 0x50AF # 0 +0x0000E3B5 0x50C7 # 0 +0x0000E3B6 0x527F # 0 +0x0000E3B7 0x5277 # 0 +0x0000E3B8 0x527D # 0 +0x0000E3B9 0x52DF # 0 +0x0000E3BA 0x52E6 # 0 +0x0000E3BB 0x52E4 # 0 +0x0000E3BC 0x52E2 # 0 +0x0000E3BD 0x52E3 # 0 +0x0000E3BE 0x532F # 0 +0x0000E3BF 0x55DF # 0 +0x0000E3C0 0x55E8 # 0 +0x0000E3C1 0x55D3 # 0 +0x0000E3C2 0x55E6 # 0 +0x0000E3C3 0x55CE # 0 +0x0000E3C4 0x55DC # 0 +0x0000E3C5 0x55C7 # 0 +0x0000E3C6 0x55D1 # 0 +0x0000E3C7 0x55E3 # 0 +0x0000E3C8 0x55E4 # 0 +0x0000E3C9 0x55EF # 0 +0x0000E3CA 0x55DA # 0 +0x0000E3CB 0x55E1 # 0 +0x0000E3CC 0x55C5 # 0 +0x0000E3CD 0x55C6 # 0 +0x0000E3CE 0x55E5 # 0 +0x0000E3CF 0x55C9 # 0 +0x0000E3D0 0x5712 # 0 +0x0000E3D1 0x5713 # 0 +0x0000E3D2 0x585E # 0 +0x0000E3D3 0x5851 # 0 +0x0000E3D4 0x5858 # 0 +0x0000E3D5 0x5857 # 0 +0x0000E3D6 0x585A # 0 +0x0000E3D7 0x5854 # 0 +0x0000E3D8 0x586B # 0 +0x0000E3D9 0x584C # 0 +0x0000E3DA 0x586D # 0 +0x0000E3DB 0x584A # 0 +0x0000E3DC 0x5862 # 0 +0x0000E3DD 0x5852 # 0 +0x0000E3DE 0x584B # 0 +0x0000E3DF 0x5967 # 0 +0x0000E3E0 0x5AC1 # 0 +0x0000E3E1 0x5AC9 # 0 +0x0000E3E2 0x5ACC # 0 +0x0000E3E3 0x5ABE # 0 +0x0000E3E4 0x5ABD # 0 +0x0000E3E5 0x5ABC # 0 +0x0000E3E6 0x5AB3 # 0 +0x0000E3E7 0x5AC2 # 0 +0x0000E3E8 0x5AB2 # 0 +0x0000E3E9 0x5D69 # 0 +0x0000E3EA 0x5D6F # 0 +0x0000E3EB 0x5E4C # 0 +0x0000E3EC 0x5E79 # 0 +0x0000E3ED 0x5EC9 # 0 +0x0000E3EE 0x5EC8 # 0 +0x0000E3EF 0x5F12 # 0 +0x0000E3F0 0x5F59 # 0 +0x0000E3F1 0x5FAC # 0 +0x0000E3F2 0x5FAE # 0 +0x0000E3F3 0x611A # 0 +0x0000E3F4 0x610F # 0 +0x0000E3F5 0x6148 # 0 +0x0000E3F6 0x611F # 0 +0x0000E3F7 0x60F3 # 0 +0x0000E3F8 0x611B # 0 +0x0000E3F9 0x60F9 # 0 +0x0000E3FA 0x6101 # 0 +0x0000E3FB 0x6108 # 0 +0x0000E3FC 0x614E # 0 +0x0000E3FD 0x614C # 0 +0x0000E3FE 0x6144 # 0 +0x0000E4A1 0x614D # 0 +0x0000E4A2 0x613E # 0 +0x0000E4A3 0x6134 # 0 +0x0000E4A4 0x6127 # 0 +0x0000E4A5 0x610D # 0 +0x0000E4A6 0x6106 # 0 +0x0000E4A7 0x6137 # 0 +0x0000E4A8 0x6221 # 0 +0x0000E4A9 0x6222 # 0 +0x0000E4AA 0x6413 # 0 +0x0000E4AB 0x643E # 0 +0x0000E4AC 0x641E # 0 +0x0000E4AD 0x642A # 0 +0x0000E4AE 0x642D # 0 +0x0000E4AF 0x643D # 0 +0x0000E4B0 0x642C # 0 +0x0000E4B1 0x640F # 0 +0x0000E4B2 0x641C # 0 +0x0000E4B3 0x6414 # 0 +0x0000E4B4 0x640D # 0 +0x0000E4B5 0x6436 # 0 +0x0000E4B6 0x6416 # 0 +0x0000E4B7 0x6417 # 0 +0x0000E4B8 0x6406 # 0 +0x0000E4B9 0x656C # 0 +0x0000E4BA 0x659F # 0 +0x0000E4BB 0x65B0 # 0 +0x0000E4BC 0x6697 # 0 +0x0000E4BD 0x6689 # 0 +0x0000E4BE 0x6687 # 0 +0x0000E4BF 0x6688 # 0 +0x0000E4C0 0x6696 # 0 +0x0000E4C1 0x6684 # 0 +0x0000E4C2 0x6698 # 0 +0x0000E4C3 0x668D # 0 +0x0000E4C4 0x6703 # 0 +0x0000E4C5 0x6994 # 0 +0x0000E4C6 0x696D # 0 +0x0000E4C7 0x695A # 0 +0x0000E4C8 0x6977 # 0 +0x0000E4C9 0x6960 # 0 +0x0000E4CA 0x6954 # 0 +0x0000E4CB 0x6975 # 0 +0x0000E4CC 0x6930 # 0 +0x0000E4CD 0x6982 # 0 +0x0000E4CE 0x694A # 0 +0x0000E4CF 0x6968 # 0 +0x0000E4D0 0x696B # 0 +0x0000E4D1 0x695E # 0 +0x0000E4D2 0x6953 # 0 +0x0000E4D3 0x6979 # 0 +0x0000E4D4 0x6986 # 0 +0x0000E4D5 0x695D # 0 +0x0000E4D6 0x6963 # 0 +0x0000E4D7 0x695B # 0 +0x0000E4D8 0x6B47 # 0 +0x0000E4D9 0x6B72 # 0 +0x0000E4DA 0x6BC0 # 0 +0x0000E4DB 0x6BBF # 0 +0x0000E4DC 0x6BD3 # 0 +0x0000E4DD 0x6BFD # 0 +0x0000E4DE 0x6EA2 # 0 +0x0000E4DF 0x6EAF # 0 +0x0000E4E0 0x6ED3 # 0 +0x0000E4E1 0x6EB6 # 0 +0x0000E4E2 0x6EC2 # 0 +0x0000E4E3 0x6E90 # 0 +0x0000E4E4 0x6E9D # 0 +0x0000E4E5 0x6EC7 # 0 +0x0000E4E6 0x6EC5 # 0 +0x0000E4E7 0x6EA5 # 0 +0x0000E4E8 0x6E98 # 0 +0x0000E4E9 0x6EBC # 0 +0x0000E4EA 0x6EBA # 0 +0x0000E4EB 0x6EAB # 0 +0x0000E4EC 0x6ED1 # 0 +0x0000E4ED 0x6E96 # 0 +0x0000E4EE 0x6E9C # 0 +0x0000E4EF 0x6EC4 # 0 +0x0000E4F0 0x6ED4 # 0 +0x0000E4F1 0x6EAA # 0 +0x0000E4F2 0x6EA7 # 0 +0x0000E4F3 0x6EB4 # 0 +0x0000E4F4 0x714E # 0 +0x0000E4F5 0x7159 # 0 +0x0000E4F6 0x7169 # 0 +0x0000E4F7 0x7164 # 0 +0x0000E4F8 0x7149 # 0 +0x0000E4F9 0x7167 # 0 +0x0000E4FA 0x715C # 0 +0x0000E4FB 0x716C # 0 +0x0000E4FC 0x7166 # 0 +0x0000E4FD 0x714C # 0 +0x0000E4FE 0x7165 # 0 +0x0000E5A1 0x715E # 0 +0x0000E5A2 0x7146 # 0 +0x0000E5A3 0x7168 # 0 +0x0000E5A4 0x7156 # 0 +0x0000E5A5 0x723A # 0 +0x0000E5A6 0x7252 # 0 +0x0000E5A7 0x7337 # 0 +0x0000E5A8 0x7345 # 0 +0x0000E5A9 0x733F # 0 +0x0000E5AA 0x733E # 0 +0x0000E5AB 0x746F # 0 +0x0000E5AC 0x745A # 0 +0x0000E5AD 0x7455 # 0 +0x0000E5AE 0x745F # 0 +0x0000E5AF 0x745E # 0 +0x0000E5B0 0x7441 # 0 +0x0000E5B1 0x743F # 0 +0x0000E5B2 0x7459 # 0 +0x0000E5B3 0x745B # 0 +0x0000E5B4 0x745C # 0 +0x0000E5B5 0x7576 # 0 +0x0000E5B6 0x7578 # 0 +0x0000E5B7 0x7600 # 0 +0x0000E5B8 0x75F0 # 0 +0x0000E5B9 0x7601 # 0 +0x0000E5BA 0x75F2 # 0 +0x0000E5BB 0x75F1 # 0 +0x0000E5BC 0x75FA # 0 +0x0000E5BD 0x75FF # 0 +0x0000E5BE 0x75F4 # 0 +0x0000E5BF 0x75F3 # 0 +0x0000E5C0 0x76DE # 0 +0x0000E5C1 0x76DF # 0 +0x0000E5C2 0x775B # 0 +0x0000E5C3 0x776B # 0 +0x0000E5C4 0x7766 # 0 +0x0000E5C5 0x775E # 0 +0x0000E5C6 0x7763 # 0 +0x0000E5C7 0x7779 # 0 +0x0000E5C8 0x776A # 0 +0x0000E5C9 0x776C # 0 +0x0000E5CA 0x775C # 0 +0x0000E5CB 0x7765 # 0 +0x0000E5CC 0x7768 # 0 +0x0000E5CD 0x7762 # 0 +0x0000E5CE 0x77EE # 0 +0x0000E5CF 0x788E # 0 +0x0000E5D0 0x78B0 # 0 +0x0000E5D1 0x7897 # 0 +0x0000E5D2 0x7898 # 0 +0x0000E5D3 0x788C # 0 +0x0000E5D4 0x7889 # 0 +0x0000E5D5 0x787C # 0 +0x0000E5D6 0x7891 # 0 +0x0000E5D7 0x7893 # 0 +0x0000E5D8 0x787F # 0 +0x0000E5D9 0x797A # 0 +0x0000E5DA 0x797F # 0 +0x0000E5DB 0x7981 # 0 +0x0000E5DC 0x842C # 0 +0x0000E5DD 0x79BD # 0 +0x0000E5DE 0x7A1C # 0 +0x0000E5DF 0x7A1A # 0 +0x0000E5E0 0x7A20 # 0 +0x0000E5E1 0x7A14 # 0 +0x0000E5E2 0x7A1F # 0 +0x0000E5E3 0x7A1E # 0 +0x0000E5E4 0x7A9F # 0 +0x0000E5E5 0x7AA0 # 0 +0x0000E5E6 0x7B77 # 0 +0x0000E5E7 0x7BC0 # 0 +0x0000E5E8 0x7B60 # 0 +0x0000E5E9 0x7B6E # 0 +0x0000E5EA 0x7B67 # 0 +0x0000E5EB 0x7CB1 # 0 +0x0000E5EC 0x7CB3 # 0 +0x0000E5ED 0x7CB5 # 0 +0x0000E5EE 0x7D93 # 0 +0x0000E5EF 0x7D79 # 0 +0x0000E5F0 0x7D91 # 0 +0x0000E5F1 0x7D81 # 0 +0x0000E5F2 0x7D8F # 0 +0x0000E5F3 0x7D5B # 0 +0x0000E5F4 0x7F6E # 0 +0x0000E5F5 0x7F69 # 0 +0x0000E5F6 0x7F6A # 0 +0x0000E5F7 0x7F72 # 0 +0x0000E5F8 0x7FA9 # 0 +0x0000E5F9 0x7FA8 # 0 +0x0000E5FA 0x7FA4 # 0 +0x0000E5FB 0x8056 # 0 +0x0000E5FC 0x8058 # 0 +0x0000E5FD 0x8086 # 0 +0x0000E5FE 0x8084 # 0 +0x0000E6A1 0x8171 # 0 +0x0000E6A2 0x8170 # 0 +0x0000E6A3 0x8178 # 0 +0x0000E6A4 0x8165 # 0 +0x0000E6A5 0x816E # 0 +0x0000E6A6 0x8173 # 0 +0x0000E6A7 0x816B # 0 +0x0000E6A8 0x8179 # 0 +0x0000E6A9 0x817A # 0 +0x0000E6AA 0x8166 # 0 +0x0000E6AB 0x8205 # 0 +0x0000E6AC 0x8247 # 0 +0x0000E6AD 0x8482 # 0 +0x0000E6AE 0x8477 # 0 +0x0000E6AF 0x843D # 0 +0x0000E6B0 0x8431 # 0 +0x0000E6B1 0x8475 # 0 +0x0000E6B2 0x8466 # 0 +0x0000E6B3 0x846B # 0 +0x0000E6B4 0x8449 # 0 +0x0000E6B5 0x846C # 0 +0x0000E6B6 0x845B # 0 +0x0000E6B7 0x843C # 0 +0x0000E6B8 0x8435 # 0 +0x0000E6B9 0x8461 # 0 +0x0000E6BA 0x8463 # 0 +0x0000E6BB 0x8469 # 0 +0x0000E6BC 0x846D # 0 +0x0000E6BD 0x8446 # 0 +0x0000E6BE 0x865E # 0 +0x0000E6BF 0x865C # 0 +0x0000E6C0 0x865F # 0 +0x0000E6C1 0x86F9 # 0 +0x0000E6C2 0x8713 # 0 +0x0000E6C3 0x8708 # 0 +0x0000E6C4 0x8707 # 0 +0x0000E6C5 0x8700 # 0 +0x0000E6C6 0x86FE # 0 +0x0000E6C7 0x86FB # 0 +0x0000E6C8 0x8702 # 0 +0x0000E6C9 0x8703 # 0 +0x0000E6CA 0x8706 # 0 +0x0000E6CB 0x870A # 0 +0x0000E6CC 0x8859 # 0 +0x0000E6CD 0x88DF # 0 +0x0000E6CE 0x88D4 # 0 +0x0000E6CF 0x88D9 # 0 +0x0000E6D0 0x88DC # 0 +0x0000E6D1 0x88D8 # 0 +0x0000E6D2 0x88DD # 0 +0x0000E6D3 0x88E1 # 0 +0x0000E6D4 0x88CA # 0 +0x0000E6D5 0x88D5 # 0 +0x0000E6D6 0x88D2 # 0 +0x0000E6D7 0x899C # 0 +0x0000E6D8 0x89E3 # 0 +0x0000E6D9 0x8A6B # 0 +0x0000E6DA 0x8A72 # 0 +0x0000E6DB 0x8A73 # 0 +0x0000E6DC 0x8A66 # 0 +0x0000E6DD 0x8A69 # 0 +0x0000E6DE 0x8A70 # 0 +0x0000E6DF 0x8A87 # 0 +0x0000E6E0 0x8A7C # 0 +0x0000E6E1 0x8A63 # 0 +0x0000E6E2 0x8AA0 # 0 +0x0000E6E3 0x8A71 # 0 +0x0000E6E4 0x8A85 # 0 +0x0000E6E5 0x8A6D # 0 +0x0000E6E6 0x8A62 # 0 +0x0000E6E7 0x8A6E # 0 +0x0000E6E8 0x8A6C # 0 +0x0000E6E9 0x8A79 # 0 +0x0000E6EA 0x8A7B # 0 +0x0000E6EB 0x8A3E # 0 +0x0000E6EC 0x8A68 # 0 +0x0000E6ED 0x8C62 # 0 +0x0000E6EE 0x8C8A # 0 +0x0000E6EF 0x8C89 # 0 +0x0000E6F0 0x8CCA # 0 +0x0000E6F1 0x8CC7 # 0 +0x0000E6F2 0x8CC8 # 0 +0x0000E6F3 0x8CC4 # 0 +0x0000E6F4 0x8CB2 # 0 +0x0000E6F5 0x8CC3 # 0 +0x0000E6F6 0x8CC2 # 0 +0x0000E6F7 0x8CC5 # 0 +0x0000E6F8 0x8DE1 # 0 +0x0000E6F9 0x8DDF # 0 +0x0000E6FA 0x8DE8 # 0 +0x0000E6FB 0x8DEF # 0 +0x0000E6FC 0x8DF3 # 0 +0x0000E6FD 0x8DFA # 0 +0x0000E6FE 0x8DEA # 0 +0x0000E7A1 0x8DE4 # 0 +0x0000E7A2 0x8DE6 # 0 +0x0000E7A3 0x8EB2 # 0 +0x0000E7A4 0x8F03 # 0 +0x0000E7A5 0x8F09 # 0 +0x0000E7A6 0x8EFE # 0 +0x0000E7A7 0x8F0A # 0 +0x0000E7A8 0x8F9F # 0 +0x0000E7A9 0x8FB2 # 0 +0x0000E7AA 0x904B # 0 +0x0000E7AB 0x904A # 0 +0x0000E7AC 0x9053 # 0 +0x0000E7AD 0x9042 # 0 +0x0000E7AE 0x9054 # 0 +0x0000E7AF 0x903C # 0 +0x0000E7B0 0x9055 # 0 +0x0000E7B1 0x9050 # 0 +0x0000E7B2 0x9047 # 0 +0x0000E7B3 0x904F # 0 +0x0000E7B4 0x904E # 0 +0x0000E7B5 0x904D # 0 +0x0000E7B6 0x9051 # 0 +0x0000E7B7 0x903E # 0 +0x0000E7B8 0x9041 # 0 +0x0000E7B9 0x9112 # 0 +0x0000E7BA 0x9117 # 0 +0x0000E7BB 0x916C # 0 +0x0000E7BC 0x916A # 0 +0x0000E7BD 0x9169 # 0 +0x0000E7BE 0x91C9 # 0 +0x0000E7BF 0x9237 # 0 +0x0000E7C0 0x9257 # 0 +0x0000E7C1 0x9238 # 0 +0x0000E7C2 0x923D # 0 +0x0000E7C3 0x9240 # 0 +0x0000E7C4 0x923E # 0 +0x0000E7C5 0x925B # 0 +0x0000E7C6 0x924B # 0 +0x0000E7C7 0x9264 # 0 +0x0000E7C8 0x9251 # 0 +0x0000E7C9 0x9234 # 0 +0x0000E7CA 0x9249 # 0 +0x0000E7CB 0x924D # 0 +0x0000E7CC 0x9245 # 0 +0x0000E7CD 0x9239 # 0 +0x0000E7CE 0x923F # 0 +0x0000E7CF 0x925A # 0 +0x0000E7D0 0x9598 # 0 +0x0000E7D1 0x9698 # 0 +0x0000E7D2 0x9694 # 0 +0x0000E7D3 0x9695 # 0 +0x0000E7D4 0x96CD # 0 +0x0000E7D5 0x96CB # 0 +0x0000E7D6 0x96C9 # 0 +0x0000E7D7 0x96CA # 0 +0x0000E7D8 0x96F7 # 0 +0x0000E7D9 0x96FB # 0 +0x0000E7DA 0x96F9 # 0 +0x0000E7DB 0x96F6 # 0 +0x0000E7DC 0x9756 # 0 +0x0000E7DD 0x9774 # 0 +0x0000E7DE 0x9776 # 0 +0x0000E7DF 0x9810 # 0 +0x0000E7E0 0x9811 # 0 +0x0000E7E1 0x9813 # 0 +0x0000E7E2 0x980A # 0 +0x0000E7E3 0x9812 # 0 +0x0000E7E4 0x980C # 0 +0x0000E7E5 0x98FC # 0 +0x0000E7E6 0x98F4 # 0 +0x0000E7E7 0x98FD # 0 +0x0000E7E8 0x98FE # 0 +0x0000E7E9 0x99B3 # 0 +0x0000E7EA 0x99B1 # 0 +0x0000E7EB 0x99B4 # 0 +0x0000E7EC 0x9AE1 # 0 +0x0000E7ED 0x9CE9 # 0 +0x0000E7EE 0x9E82 # 0 +0x0000E7EF 0x9F0E # 0 +0x0000E7F0 0x9F13 # 0 +0x0000E7F1 0x9F20 # 0 +0x0000E7F2 0x50E7 # 0 +0x0000E7F3 0x50EE # 0 +0x0000E7F4 0x50E5 # 0 +0x0000E7F5 0x50D6 # 0 +0x0000E7F6 0x50ED # 0 +0x0000E7F7 0x50DA # 0 +0x0000E7F8 0x50D5 # 0 +0x0000E7F9 0x50CF # 0 +0x0000E7FA 0x50D1 # 0 +0x0000E7FB 0x50F1 # 0 +0x0000E7FC 0x50CE # 0 +0x0000E7FD 0x50E9 # 0 +0x0000E7FE 0x5162 # 0 +0x0000E8A1 0x51F3 # 0 +0x0000E8A2 0x5283 # 0 +0x0000E8A3 0x5282 # 0 +0x0000E8A4 0x5331 # 0 +0x0000E8A5 0x53AD # 0 +0x0000E8A6 0x55FE # 0 +0x0000E8A7 0x5600 # 0 +0x0000E8A8 0x561B # 0 +0x0000E8A9 0x5617 # 0 +0x0000E8AA 0x55FD # 0 +0x0000E8AB 0x5614 # 0 +0x0000E8AC 0x5606 # 0 +0x0000E8AD 0x5609 # 0 +0x0000E8AE 0x560D # 0 +0x0000E8AF 0x560E # 0 +0x0000E8B0 0x55F7 # 0 +0x0000E8B1 0x5616 # 0 +0x0000E8B2 0x561F # 0 +0x0000E8B3 0x5608 # 0 +0x0000E8B4 0x5610 # 0 +0x0000E8B5 0x55F6 # 0 +0x0000E8B6 0x5718 # 0 +0x0000E8B7 0x5716 # 0 +0x0000E8B8 0x5875 # 0 +0x0000E8B9 0x587E # 0 +0x0000E8BA 0x5883 # 0 +0x0000E8BB 0x5893 # 0 +0x0000E8BC 0x588A # 0 +0x0000E8BD 0x5879 # 0 +0x0000E8BE 0x5885 # 0 +0x0000E8BF 0x587D # 0 +0x0000E8C0 0x58FD # 0 +0x0000E8C1 0x5925 # 0 +0x0000E8C2 0x5922 # 0 +0x0000E8C3 0x5924 # 0 +0x0000E8C4 0x596A # 0 +0x0000E8C5 0x5969 # 0 +0x0000E8C6 0x5AE1 # 0 +0x0000E8C7 0x5AE6 # 0 +0x0000E8C8 0x5AE9 # 0 +0x0000E8C9 0x5AD7 # 0 +0x0000E8CA 0x5AD6 # 0 +0x0000E8CB 0x5AD8 # 0 +0x0000E8CC 0x5AE3 # 0 +0x0000E8CD 0x5B75 # 0 +0x0000E8CE 0x5BDE # 0 +0x0000E8CF 0x5BE7 # 0 +0x0000E8D0 0x5BE1 # 0 +0x0000E8D1 0x5BE5 # 0 +0x0000E8D2 0x5BE6 # 0 +0x0000E8D3 0x5BE8 # 0 +0x0000E8D4 0x5BE2 # 0 +0x0000E8D5 0x5BE4 # 0 +0x0000E8D6 0x5BDF # 0 +0x0000E8D7 0x5C0D # 0 +0x0000E8D8 0x5C62 # 0 +0x0000E8D9 0x5D84 # 0 +0x0000E8DA 0x5D87 # 0 +0x0000E8DB 0x5E5B # 0 +0x0000E8DC 0x5E63 # 0 +0x0000E8DD 0x5E55 # 0 +0x0000E8DE 0x5E57 # 0 +0x0000E8DF 0x5E54 # 0 +0x0000E8E0 0x5ED3 # 0 +0x0000E8E1 0x5ED6 # 0 +0x0000E8E2 0x5F0A # 0 +0x0000E8E3 0x5F46 # 0 +0x0000E8E4 0x5F70 # 0 +0x0000E8E5 0x5FB9 # 0 +0x0000E8E6 0x6147 # 0 +0x0000E8E7 0x613F # 0 +0x0000E8E8 0x614B # 0 +0x0000E8E9 0x6177 # 0 +0x0000E8EA 0x6162 # 0 +0x0000E8EB 0x6163 # 0 +0x0000E8EC 0x615F # 0 +0x0000E8ED 0x615A # 0 +0x0000E8EE 0x6158 # 0 +0x0000E8EF 0x6175 # 0 +0x0000E8F0 0x622A # 0 +0x0000E8F1 0x6487 # 0 +0x0000E8F2 0x6458 # 0 +0x0000E8F3 0x6454 # 0 +0x0000E8F4 0x64A4 # 0 +0x0000E8F5 0x6478 # 0 +0x0000E8F6 0x645F # 0 +0x0000E8F7 0x647A # 0 +0x0000E8F8 0x6451 # 0 +0x0000E8F9 0x6467 # 0 +0x0000E8FA 0x6434 # 0 +0x0000E8FB 0x646D # 0 +0x0000E8FC 0x647B # 0 +0x0000E8FD 0x6572 # 0 +0x0000E8FE 0x65A1 # 0 +0x0000E9A1 0x65D7 # 0 +0x0000E9A2 0x65D6 # 0 +0x0000E9A3 0x66A2 # 0 +0x0000E9A4 0x66A8 # 0 +0x0000E9A5 0x669D # 0 +0x0000E9A6 0x699C # 0 +0x0000E9A7 0x69A8 # 0 +0x0000E9A8 0x6995 # 0 +0x0000E9A9 0x69C1 # 0 +0x0000E9AA 0x69AE # 0 +0x0000E9AB 0x69D3 # 0 +0x0000E9AC 0x69CB # 0 +0x0000E9AD 0x699B # 0 +0x0000E9AE 0x69B7 # 0 +0x0000E9AF 0x69BB # 0 +0x0000E9B0 0x69AB # 0 +0x0000E9B1 0x69B4 # 0 +0x0000E9B2 0x69D0 # 0 +0x0000E9B3 0x69CD # 0 +0x0000E9B4 0x69AD # 0 +0x0000E9B5 0x69CC # 0 +0x0000E9B6 0x69A6 # 0 +0x0000E9B7 0x69C3 # 0 +0x0000E9B8 0x69A3 # 0 +0x0000E9B9 0x6B49 # 0 +0x0000E9BA 0x6B4C # 0 +0x0000E9BB 0x6C33 # 0 +0x0000E9BC 0x6F33 # 0 +0x0000E9BD 0x6F14 # 0 +0x0000E9BE 0x6EFE # 0 +0x0000E9BF 0x6F13 # 0 +0x0000E9C0 0x6EF4 # 0 +0x0000E9C1 0x6F29 # 0 +0x0000E9C2 0x6F3E # 0 +0x0000E9C3 0x6F20 # 0 +0x0000E9C4 0x6F2C # 0 +0x0000E9C5 0x6F0F # 0 +0x0000E9C6 0x6F02 # 0 +0x0000E9C7 0x6F22 # 0 +0x0000E9C8 0x6EFF # 0 +0x0000E9C9 0x6EEF # 0 +0x0000E9CA 0x6F06 # 0 +0x0000E9CB 0x6F31 # 0 +0x0000E9CC 0x6F38 # 0 +0x0000E9CD 0x6F32 # 0 +0x0000E9CE 0x6F23 # 0 +0x0000E9CF 0x6F15 # 0 +0x0000E9D0 0x6F2B # 0 +0x0000E9D1 0x6F2F # 0 +0x0000E9D2 0x6F88 # 0 +0x0000E9D3 0x6F2A # 0 +0x0000E9D4 0x6EEC # 0 +0x0000E9D5 0x6F01 # 0 +0x0000E9D6 0x6EF2 # 0 +0x0000E9D7 0x6ECC # 0 +0x0000E9D8 0x6EF7 # 0 +0x0000E9D9 0x7194 # 0 +0x0000E9DA 0x7199 # 0 +0x0000E9DB 0x717D # 0 +0x0000E9DC 0x718A # 0 +0x0000E9DD 0x7184 # 0 +0x0000E9DE 0x7192 # 0 +0x0000E9DF 0x723E # 0 +0x0000E9E0 0x7292 # 0 +0x0000E9E1 0x7296 # 0 +0x0000E9E2 0x7344 # 0 +0x0000E9E3 0x7350 # 0 +0x0000E9E4 0x7464 # 0 +0x0000E9E5 0x7463 # 0 +0x0000E9E6 0x746A # 0 +0x0000E9E7 0x7470 # 0 +0x0000E9E8 0x746D # 0 +0x0000E9E9 0x7504 # 0 +0x0000E9EA 0x7591 # 0 +0x0000E9EB 0x7627 # 0 +0x0000E9EC 0x760D # 0 +0x0000E9ED 0x760B # 0 +0x0000E9EE 0x7609 # 0 +0x0000E9EF 0x7613 # 0 +0x0000E9F0 0x76E1 # 0 +0x0000E9F1 0x76E3 # 0 +0x0000E9F2 0x7784 # 0 +0x0000E9F3 0x777D # 0 +0x0000E9F4 0x777F # 0 +0x0000E9F5 0x7761 # 0 +0x0000E9F6 0x78C1 # 0 +0x0000E9F7 0x789F # 0 +0x0000E9F8 0x78A7 # 0 +0x0000E9F9 0x78B3 # 0 +0x0000E9FA 0x78A9 # 0 +0x0000E9FB 0x78A3 # 0 +0x0000E9FC 0x798E # 0 +0x0000E9FD 0x798F # 0 +0x0000E9FE 0x798D # 0 +0x0000EAA1 0x7A2E # 0 +0x0000EAA2 0x7A31 # 0 +0x0000EAA3 0x7AAA # 0 +0x0000EAA4 0x7AA9 # 0 +0x0000EAA5 0x7AED # 0 +0x0000EAA6 0x7AEF # 0 +0x0000EAA7 0x7BA1 # 0 +0x0000EAA8 0x7B95 # 0 +0x0000EAA9 0x7B8B # 0 +0x0000EAAA 0x7B75 # 0 +0x0000EAAB 0x7B97 # 0 +0x0000EAAC 0x7B9D # 0 +0x0000EAAD 0x7B94 # 0 +0x0000EAAE 0x7B8F # 0 +0x0000EAAF 0x7BB8 # 0 +0x0000EAB0 0x7B87 # 0 +0x0000EAB1 0x7B84 # 0 +0x0000EAB2 0x7CB9 # 0 +0x0000EAB3 0x7CBD # 0 +0x0000EAB4 0x7CBE # 0 +0x0000EAB5 0x7DBB # 0 +0x0000EAB6 0x7DB0 # 0 +0x0000EAB7 0x7D9C # 0 +0x0000EAB8 0x7DBD # 0 +0x0000EAB9 0x7DBE # 0 +0x0000EABA 0x7DA0 # 0 +0x0000EABB 0x7DCA # 0 +0x0000EABC 0x7DB4 # 0 +0x0000EABD 0x7DB2 # 0 +0x0000EABE 0x7DB1 # 0 +0x0000EABF 0x7DBA # 0 +0x0000EAC0 0x7DA2 # 0 +0x0000EAC1 0x7DBF # 0 +0x0000EAC2 0x7DB5 # 0 +0x0000EAC3 0x7DB8 # 0 +0x0000EAC4 0x7DAD # 0 +0x0000EAC5 0x7DD2 # 0 +0x0000EAC6 0x7DC7 # 0 +0x0000EAC7 0x7DAC # 0 +0x0000EAC8 0x7F70 # 0 +0x0000EAC9 0x7FE0 # 0 +0x0000EACA 0x7FE1 # 0 +0x0000EACB 0x7FDF # 0 +0x0000EACC 0x805E # 0 +0x0000EACD 0x805A # 0 +0x0000EACE 0x8087 # 0 +0x0000EACF 0x8150 # 0 +0x0000EAD0 0x8180 # 0 +0x0000EAD1 0x818F # 0 +0x0000EAD2 0x8188 # 0 +0x0000EAD3 0x818A # 0 +0x0000EAD4 0x817F # 0 +0x0000EAD5 0x8182 # 0 +0x0000EAD6 0x81E7 # 0 +0x0000EAD7 0x81FA # 0 +0x0000EAD8 0x8207 # 0 +0x0000EAD9 0x8214 # 0 +0x0000EADA 0x821E # 0 +0x0000EADB 0x824B # 0 +0x0000EADC 0x84C9 # 0 +0x0000EADD 0x84BF # 0 +0x0000EADE 0x84C6 # 0 +0x0000EADF 0x84C4 # 0 +0x0000EAE0 0x8499 # 0 +0x0000EAE1 0x849E # 0 +0x0000EAE2 0x84B2 # 0 +0x0000EAE3 0x849C # 0 +0x0000EAE4 0x84CB # 0 +0x0000EAE5 0x84B8 # 0 +0x0000EAE6 0x84C0 # 0 +0x0000EAE7 0x84D3 # 0 +0x0000EAE8 0x8490 # 0 +0x0000EAE9 0x84BC # 0 +0x0000EAEA 0x84D1 # 0 +0x0000EAEB 0x84CA # 0 +0x0000EAEC 0x873F # 0 +0x0000EAED 0x871C # 0 +0x0000EAEE 0x873B # 0 +0x0000EAEF 0x8722 # 0 +0x0000EAF0 0x8725 # 0 +0x0000EAF1 0x8734 # 0 +0x0000EAF2 0x8718 # 0 +0x0000EAF3 0x8755 # 0 +0x0000EAF4 0x8737 # 0 +0x0000EAF5 0x8729 # 0 +0x0000EAF6 0x88F3 # 0 +0x0000EAF7 0x8902 # 0 +0x0000EAF8 0x88F4 # 0 +0x0000EAF9 0x88F9 # 0 +0x0000EAFA 0x88F8 # 0 +0x0000EAFB 0x88FD # 0 +0x0000EAFC 0x88E8 # 0 +0x0000EAFD 0x891A # 0 +0x0000EAFE 0x88EF # 0 +0x0000EBA1 0x8AA6 # 0 +0x0000EBA2 0x8A8C # 0 +0x0000EBA3 0x8A9E # 0 +0x0000EBA4 0x8AA3 # 0 +0x0000EBA5 0x8A8D # 0 +0x0000EBA6 0x8AA1 # 0 +0x0000EBA7 0x8A93 # 0 +0x0000EBA8 0x8AA4 # 0 +0x0000EBA9 0x8AAA # 0 +0x0000EBAA 0x8AA5 # 0 +0x0000EBAB 0x8AA8 # 0 +0x0000EBAC 0x8A98 # 0 +0x0000EBAD 0x8A91 # 0 +0x0000EBAE 0x8A9A # 0 +0x0000EBAF 0x8AA7 # 0 +0x0000EBB0 0x8C6A # 0 +0x0000EBB1 0x8C8D # 0 +0x0000EBB2 0x8C8C # 0 +0x0000EBB3 0x8CD3 # 0 +0x0000EBB4 0x8CD1 # 0 +0x0000EBB5 0x8CD2 # 0 +0x0000EBB6 0x8D6B # 0 +0x0000EBB7 0x8D99 # 0 +0x0000EBB8 0x8D95 # 0 +0x0000EBB9 0x8DFC # 0 +0x0000EBBA 0x8F14 # 0 +0x0000EBBB 0x8F12 # 0 +0x0000EBBC 0x8F15 # 0 +0x0000EBBD 0x8F13 # 0 +0x0000EBBE 0x8FA3 # 0 +0x0000EBBF 0x9060 # 0 +0x0000EBC0 0x9058 # 0 +0x0000EBC1 0x905C # 0 +0x0000EBC2 0x9063 # 0 +0x0000EBC3 0x9059 # 0 +0x0000EBC4 0x905E # 0 +0x0000EBC5 0x9062 # 0 +0x0000EBC6 0x905D # 0 +0x0000EBC7 0x905B # 0 +0x0000EBC8 0x9119 # 0 +0x0000EBC9 0x9118 # 0 +0x0000EBCA 0x911E # 0 +0x0000EBCB 0x9175 # 0 +0x0000EBCC 0x9178 # 0 +0x0000EBCD 0x9177 # 0 +0x0000EBCE 0x9174 # 0 +0x0000EBCF 0x9278 # 0 +0x0000EBD0 0x92AC # 0 +0x0000EBD1 0x9280 # 0 +0x0000EBD2 0x9285 # 0 +0x0000EBD3 0x9298 # 0 +0x0000EBD4 0x9296 # 0 +0x0000EBD5 0x927B # 0 +0x0000EBD6 0x9293 # 0 +0x0000EBD7 0x929C # 0 +0x0000EBD8 0x92A8 # 0 +0x0000EBD9 0x927C # 0 +0x0000EBDA 0x9291 # 0 +0x0000EBDB 0x95A1 # 0 +0x0000EBDC 0x95A8 # 0 +0x0000EBDD 0x95A9 # 0 +0x0000EBDE 0x95A3 # 0 +0x0000EBDF 0x95A5 # 0 +0x0000EBE0 0x95A4 # 0 +0x0000EBE1 0x9699 # 0 +0x0000EBE2 0x969C # 0 +0x0000EBE3 0x969B # 0 +0x0000EBE4 0x96CC # 0 +0x0000EBE5 0x96D2 # 0 +0x0000EBE6 0x9700 # 0 +0x0000EBE7 0x977C # 0 +0x0000EBE8 0x9785 # 0 +0x0000EBE9 0x97F6 # 0 +0x0000EBEA 0x9817 # 0 +0x0000EBEB 0x9818 # 0 +0x0000EBEC 0x98AF # 0 +0x0000EBED 0x98B1 # 0 +0x0000EBEE 0x9903 # 0 +0x0000EBEF 0x9905 # 0 +0x0000EBF0 0x990C # 0 +0x0000EBF1 0x9909 # 0 +0x0000EBF2 0x99C1 # 0 +0x0000EBF3 0x9AAF # 0 +0x0000EBF4 0x9AB0 # 0 +0x0000EBF5 0x9AE6 # 0 +0x0000EBF6 0x9B41 # 0 +0x0000EBF7 0x9B42 # 0 +0x0000EBF8 0x9CF4 # 0 +0x0000EBF9 0x9CF6 # 0 +0x0000EBFA 0x9CF3 # 0 +0x0000EBFB 0x9EBC # 0 +0x0000EBFC 0x9F3B # 0 +0x0000EBFD 0x9F4A # 0 +0x0000EBFE 0x5104 # 0 +0x0000ECA1 0x5100 # 0 +0x0000ECA2 0x50FB # 0 +0x0000ECA3 0x50F5 # 0 +0x0000ECA4 0x50F9 # 0 +0x0000ECA5 0x5102 # 0 +0x0000ECA6 0x5108 # 0 +0x0000ECA7 0x5109 # 0 +0x0000ECA8 0x5105 # 0 +0x0000ECA9 0x51DC # 0 +0x0000ECAA 0x5287 # 0 +0x0000ECAB 0x5288 # 0 +0x0000ECAC 0x5289 # 0 +0x0000ECAD 0x528D # 0 +0x0000ECAE 0x528A # 0 +0x0000ECAF 0x52F0 # 0 +0x0000ECB0 0x53B2 # 0 +0x0000ECB1 0x562E # 0 +0x0000ECB2 0x563B # 0 +0x0000ECB3 0x5639 # 0 +0x0000ECB4 0x5632 # 0 +0x0000ECB5 0x563F # 0 +0x0000ECB6 0x5634 # 0 +0x0000ECB7 0x5629 # 0 +0x0000ECB8 0x5653 # 0 +0x0000ECB9 0x564E # 0 +0x0000ECBA 0x5657 # 0 +0x0000ECBB 0x5674 # 0 +0x0000ECBC 0x5636 # 0 +0x0000ECBD 0x562F # 0 +0x0000ECBE 0x5630 # 0 +0x0000ECBF 0x5880 # 0 +0x0000ECC0 0x589F # 0 +0x0000ECC1 0x589E # 0 +0x0000ECC2 0x58B3 # 0 +0x0000ECC3 0x589C # 0 +0x0000ECC4 0x58AE # 0 +0x0000ECC5 0x58A9 # 0 +0x0000ECC6 0x58A6 # 0 +0x0000ECC7 0x596D # 0 +0x0000ECC8 0x5B09 # 0 +0x0000ECC9 0x5AFB # 0 +0x0000ECCA 0x5B0B # 0 +0x0000ECCB 0x5AF5 # 0 +0x0000ECCC 0x5B0C # 0 +0x0000ECCD 0x5B08 # 0 +0x0000ECCE 0x5BEE # 0 +0x0000ECCF 0x5BEC # 0 +0x0000ECD0 0x5BE9 # 0 +0x0000ECD1 0x5BEB # 0 +0x0000ECD2 0x5C64 # 0 +0x0000ECD3 0x5C65 # 0 +0x0000ECD4 0x5D9D # 0 +0x0000ECD5 0x5D94 # 0 +0x0000ECD6 0x5E62 # 0 +0x0000ECD7 0x5E5F # 0 +0x0000ECD8 0x5E61 # 0 +0x0000ECD9 0x5EE2 # 0 +0x0000ECDA 0x5EDA # 0 +0x0000ECDB 0x5EDF # 0 +0x0000ECDC 0x5EDD # 0 +0x0000ECDD 0x5EE3 # 0 +0x0000ECDE 0x5EE0 # 0 +0x0000ECDF 0x5F48 # 0 +0x0000ECE0 0x5F71 # 0 +0x0000ECE1 0x5FB7 # 0 +0x0000ECE2 0x5FB5 # 0 +0x0000ECE3 0x6176 # 0 +0x0000ECE4 0x6167 # 0 +0x0000ECE5 0x616E # 0 +0x0000ECE6 0x615D # 0 +0x0000ECE7 0x6155 # 0 +0x0000ECE8 0x6182 # 0 +0x0000ECE9 0x617C # 0 +0x0000ECEA 0x6170 # 0 +0x0000ECEB 0x616B # 0 +0x0000ECEC 0x617E # 0 +0x0000ECED 0x61A7 # 0 +0x0000ECEE 0x6190 # 0 +0x0000ECEF 0x61AB # 0 +0x0000ECF0 0x618E # 0 +0x0000ECF1 0x61AC # 0 +0x0000ECF2 0x619A # 0 +0x0000ECF3 0x61A4 # 0 +0x0000ECF4 0x6194 # 0 +0x0000ECF5 0x61AE # 0 +0x0000ECF6 0x622E # 0 +0x0000ECF7 0x6469 # 0 +0x0000ECF8 0x646F # 0 +0x0000ECF9 0x6479 # 0 +0x0000ECFA 0x649E # 0 +0x0000ECFB 0x64B2 # 0 +0x0000ECFC 0x6488 # 0 +0x0000ECFD 0x6490 # 0 +0x0000ECFE 0x64B0 # 0 +0x0000EDA1 0x64A5 # 0 +0x0000EDA2 0x6493 # 0 +0x0000EDA3 0x6495 # 0 +0x0000EDA4 0x64A9 # 0 +0x0000EDA5 0x6492 # 0 +0x0000EDA6 0x64AE # 0 +0x0000EDA7 0x64AD # 0 +0x0000EDA8 0x64AB # 0 +0x0000EDA9 0x649A # 0 +0x0000EDAA 0x64AC # 0 +0x0000EDAB 0x6499 # 0 +0x0000EDAC 0x64A2 # 0 +0x0000EDAD 0x64B3 # 0 +0x0000EDAE 0x6575 # 0 +0x0000EDAF 0x6577 # 0 +0x0000EDB0 0x6578 # 0 +0x0000EDB1 0x66AE # 0 +0x0000EDB2 0x66AB # 0 +0x0000EDB3 0x66B4 # 0 +0x0000EDB4 0x66B1 # 0 +0x0000EDB5 0x6A23 # 0 +0x0000EDB6 0x6A1F # 0 +0x0000EDB7 0x69E8 # 0 +0x0000EDB8 0x6A01 # 0 +0x0000EDB9 0x6A1E # 0 +0x0000EDBA 0x6A19 # 0 +0x0000EDBB 0x69FD # 0 +0x0000EDBC 0x6A21 # 0 +0x0000EDBD 0x6A13 # 0 +0x0000EDBE 0x6A0A # 0 +0x0000EDBF 0x69F3 # 0 +0x0000EDC0 0x6A02 # 0 +0x0000EDC1 0x6A05 # 0 +0x0000EDC2 0x69ED # 0 +0x0000EDC3 0x6A11 # 0 +0x0000EDC4 0x6B50 # 0 +0x0000EDC5 0x6B4E # 0 +0x0000EDC6 0x6BA4 # 0 +0x0000EDC7 0x6BC5 # 0 +0x0000EDC8 0x6BC6 # 0 +0x0000EDC9 0x6F3F # 0 +0x0000EDCA 0x6F7C # 0 +0x0000EDCB 0x6F84 # 0 +0x0000EDCC 0x6F51 # 0 +0x0000EDCD 0x6F66 # 0 +0x0000EDCE 0x6F54 # 0 +0x0000EDCF 0x6F86 # 0 +0x0000EDD0 0x6F6D # 0 +0x0000EDD1 0x6F5B # 0 +0x0000EDD2 0x6F78 # 0 +0x0000EDD3 0x6F6E # 0 +0x0000EDD4 0x6F8E # 0 +0x0000EDD5 0x6F7A # 0 +0x0000EDD6 0x6F70 # 0 +0x0000EDD7 0x6F64 # 0 +0x0000EDD8 0x6F97 # 0 +0x0000EDD9 0x6F58 # 0 +0x0000EDDA 0x6ED5 # 0 +0x0000EDDB 0x6F6F # 0 +0x0000EDDC 0x6F60 # 0 +0x0000EDDD 0x6F5F # 0 +0x0000EDDE 0x719F # 0 +0x0000EDDF 0x71AC # 0 +0x0000EDE0 0x71B1 # 0 +0x0000EDE1 0x71A8 # 0 +0x0000EDE2 0x7256 # 0 +0x0000EDE3 0x729B # 0 +0x0000EDE4 0x734E # 0 +0x0000EDE5 0x7357 # 0 +0x0000EDE6 0x7469 # 0 +0x0000EDE7 0x748B # 0 +0x0000EDE8 0x7483 # 0 +0x0000EDE9 0x747E # 0 +0x0000EDEA 0x7480 # 0 +0x0000EDEB 0x757F # 0 +0x0000EDEC 0x7620 # 0 +0x0000EDED 0x7629 # 0 +0x0000EDEE 0x761F # 0 +0x0000EDEF 0x7624 # 0 +0x0000EDF0 0x7626 # 0 +0x0000EDF1 0x7621 # 0 +0x0000EDF2 0x7622 # 0 +0x0000EDF3 0x769A # 0 +0x0000EDF4 0x76BA # 0 +0x0000EDF5 0x76E4 # 0 +0x0000EDF6 0x778E # 0 +0x0000EDF7 0x7787 # 0 +0x0000EDF8 0x778C # 0 +0x0000EDF9 0x7791 # 0 +0x0000EDFA 0x778B # 0 +0x0000EDFB 0x78CB # 0 +0x0000EDFC 0x78C5 # 0 +0x0000EDFD 0x78BA # 0 +0x0000EDFE 0x78CA # 0 +0x0000EEA1 0x78BE # 0 +0x0000EEA2 0x78D5 # 0 +0x0000EEA3 0x78BC # 0 +0x0000EEA4 0x78D0 # 0 +0x0000EEA5 0x7A3F # 0 +0x0000EEA6 0x7A3C # 0 +0x0000EEA7 0x7A40 # 0 +0x0000EEA8 0x7A3D # 0 +0x0000EEA9 0x7A37 # 0 +0x0000EEAA 0x7A3B # 0 +0x0000EEAB 0x7AAF # 0 +0x0000EEAC 0x7AAE # 0 +0x0000EEAD 0x7BAD # 0 +0x0000EEAE 0x7BB1 # 0 +0x0000EEAF 0x7BC4 # 0 +0x0000EEB0 0x7BB4 # 0 +0x0000EEB1 0x7BC6 # 0 +0x0000EEB2 0x7BC7 # 0 +0x0000EEB3 0x7BC1 # 0 +0x0000EEB4 0x7BA0 # 0 +0x0000EEB5 0x7BCC # 0 +0x0000EEB6 0x7CCA # 0 +0x0000EEB7 0x7DE0 # 0 +0x0000EEB8 0x7DF4 # 0 +0x0000EEB9 0x7DEF # 0 +0x0000EEBA 0x7DFB # 0 +0x0000EEBB 0x7DD8 # 0 +0x0000EEBC 0x7DEC # 0 +0x0000EEBD 0x7DDD # 0 +0x0000EEBE 0x7DE8 # 0 +0x0000EEBF 0x7DE3 # 0 +0x0000EEC0 0x7DDA # 0 +0x0000EEC1 0x7DDE # 0 +0x0000EEC2 0x7DE9 # 0 +0x0000EEC3 0x7D9E # 0 +0x0000EEC4 0x7DD9 # 0 +0x0000EEC5 0x7DF2 # 0 +0x0000EEC6 0x7DF9 # 0 +0x0000EEC7 0x7F75 # 0 +0x0000EEC8 0x7F77 # 0 +0x0000EEC9 0x7FAF # 0 +0x0000EECA 0x7FE9 # 0 +0x0000EECB 0x8026 # 0 +0x0000EECC 0x819B # 0 +0x0000EECD 0x819C # 0 +0x0000EECE 0x819D # 0 +0x0000EECF 0x81A0 # 0 +0x0000EED0 0x819A # 0 +0x0000EED1 0x8198 # 0 +0x0000EED2 0x8517 # 0 +0x0000EED3 0x853D # 0 +0x0000EED4 0x851A # 0 +0x0000EED5 0x84EE # 0 +0x0000EED6 0x852C # 0 +0x0000EED7 0x852D # 0 +0x0000EED8 0x8513 # 0 +0x0000EED9 0x8511 # 0 +0x0000EEDA 0x8523 # 0 +0x0000EEDB 0x8521 # 0 +0x0000EEDC 0x8514 # 0 +0x0000EEDD 0x84EC # 0 +0x0000EEDE 0x8525 # 0 +0x0000EEDF 0x84FF # 0 +0x0000EEE0 0x8506 # 0 +0x0000EEE1 0x8782 # 0 +0x0000EEE2 0x8774 # 0 +0x0000EEE3 0x8776 # 0 +0x0000EEE4 0x8760 # 0 +0x0000EEE5 0x8766 # 0 +0x0000EEE6 0x8778 # 0 +0x0000EEE7 0x8768 # 0 +0x0000EEE8 0x8759 # 0 +0x0000EEE9 0x8757 # 0 +0x0000EEEA 0x874C # 0 +0x0000EEEB 0x8753 # 0 +0x0000EEEC 0x885B # 0 +0x0000EEED 0x885D # 0 +0x0000EEEE 0x8910 # 0 +0x0000EEEF 0x8907 # 0 +0x0000EEF0 0x8912 # 0 +0x0000EEF1 0x8913 # 0 +0x0000EEF2 0x8915 # 0 +0x0000EEF3 0x890A # 0 +0x0000EEF4 0x8ABC # 0 +0x0000EEF5 0x8AD2 # 0 +0x0000EEF6 0x8AC7 # 0 +0x0000EEF7 0x8AC4 # 0 +0x0000EEF8 0x8A95 # 0 +0x0000EEF9 0x8ACB # 0 +0x0000EEFA 0x8AF8 # 0 +0x0000EEFB 0x8AB2 # 0 +0x0000EEFC 0x8AC9 # 0 +0x0000EEFD 0x8AC2 # 0 +0x0000EEFE 0x8ABF # 0 +0x0000EFA1 0x8AB0 # 0 +0x0000EFA2 0x8AD6 # 0 +0x0000EFA3 0x8ACD # 0 +0x0000EFA4 0x8AB6 # 0 +0x0000EFA5 0x8AB9 # 0 +0x0000EFA6 0x8ADB # 0 +0x0000EFA7 0x8C4C # 0 +0x0000EFA8 0x8C4E # 0 +0x0000EFA9 0x8C6C # 0 +0x0000EFAA 0x8CE0 # 0 +0x0000EFAB 0x8CDE # 0 +0x0000EFAC 0x8CE6 # 0 +0x0000EFAD 0x8CE4 # 0 +0x0000EFAE 0x8CEC # 0 +0x0000EFAF 0x8CED # 0 +0x0000EFB0 0x8CE2 # 0 +0x0000EFB1 0x8CE3 # 0 +0x0000EFB2 0x8CDC # 0 +0x0000EFB3 0x8CEA # 0 +0x0000EFB4 0x8CE1 # 0 +0x0000EFB5 0x8D6D # 0 +0x0000EFB6 0x8D9F # 0 +0x0000EFB7 0x8DA3 # 0 +0x0000EFB8 0x8E2B # 0 +0x0000EFB9 0x8E10 # 0 +0x0000EFBA 0x8E1D # 0 +0x0000EFBB 0x8E22 # 0 +0x0000EFBC 0x8E0F # 0 +0x0000EFBD 0x8E29 # 0 +0x0000EFBE 0x8E1F # 0 +0x0000EFBF 0x8E21 # 0 +0x0000EFC0 0x8E1E # 0 +0x0000EFC1 0x8EBA # 0 +0x0000EFC2 0x8F1D # 0 +0x0000EFC3 0x8F1B # 0 +0x0000EFC4 0x8F1F # 0 +0x0000EFC5 0x8F29 # 0 +0x0000EFC6 0x8F26 # 0 +0x0000EFC7 0x8F2A # 0 +0x0000EFC8 0x8F1C # 0 +0x0000EFC9 0x8F1E # 0 +0x0000EFCA 0x8F25 # 0 +0x0000EFCB 0x9069 # 0 +0x0000EFCC 0x906E # 0 +0x0000EFCD 0x9068 # 0 +0x0000EFCE 0x906D # 0 +0x0000EFCF 0x9077 # 0 +0x0000EFD0 0x9130 # 0 +0x0000EFD1 0x912D # 0 +0x0000EFD2 0x9127 # 0 +0x0000EFD3 0x9131 # 0 +0x0000EFD4 0x9187 # 0 +0x0000EFD5 0x9189 # 0 +0x0000EFD6 0x918B # 0 +0x0000EFD7 0x9183 # 0 +0x0000EFD8 0x92C5 # 0 +0x0000EFD9 0x92BB # 0 +0x0000EFDA 0x92B7 # 0 +0x0000EFDB 0x92EA # 0 +0x0000EFDC 0x92E4 # 0 +0x0000EFDD 0x92C1 # 0 +0x0000EFDE 0x92B3 # 0 +0x0000EFDF 0x92BC # 0 +0x0000EFE0 0x92D2 # 0 +0x0000EFE1 0x92C7 # 0 +0x0000EFE2 0x92F0 # 0 +0x0000EFE3 0x92B2 # 0 +0x0000EFE4 0x95AD # 0 +0x0000EFE5 0x95B1 # 0 +0x0000EFE6 0x9704 # 0 +0x0000EFE7 0x9706 # 0 +0x0000EFE8 0x9707 # 0 +0x0000EFE9 0x9709 # 0 +0x0000EFEA 0x9760 # 0 +0x0000EFEB 0x978D # 0 +0x0000EFEC 0x978B # 0 +0x0000EFED 0x978F # 0 +0x0000EFEE 0x9821 # 0 +0x0000EFEF 0x982B # 0 +0x0000EFF0 0x981C # 0 +0x0000EFF1 0x98B3 # 0 +0x0000EFF2 0x990A # 0 +0x0000EFF3 0x9913 # 0 +0x0000EFF4 0x9912 # 0 +0x0000EFF5 0x9918 # 0 +0x0000EFF6 0x99DD # 0 +0x0000EFF7 0x99D0 # 0 +0x0000EFF8 0x99DF # 0 +0x0000EFF9 0x99DB # 0 +0x0000EFFA 0x99D1 # 0 +0x0000EFFB 0x99D5 # 0 +0x0000EFFC 0x99D2 # 0 +0x0000EFFD 0x99D9 # 0 +0x0000EFFE 0x9AB7 # 0 +0x0000F0A1 0x9AEE # 0 +0x0000F0A2 0x9AEF # 0 +0x0000F0A3 0x9B27 # 0 +0x0000F0A4 0x9B45 # 0 +0x0000F0A5 0x9B44 # 0 +0x0000F0A6 0x9B77 # 0 +0x0000F0A7 0x9B6F # 0 +0x0000F0A8 0x9D06 # 0 +0x0000F0A9 0x9D09 # 0 +0x0000F0AA 0x9D03 # 0 +0x0000F0AB 0x9EA9 # 0 +0x0000F0AC 0x9EBE # 0 +0x0000F0AD 0x9ECE # 0 +0x0000F0AE 0x58A8 # 0 +0x0000F0AF 0x9F52 # 0 +0x0000F0B0 0x5112 # 0 +0x0000F0B1 0x5118 # 0 +0x0000F0B2 0x5114 # 0 +0x0000F0B3 0x5110 # 0 +0x0000F0B4 0x5115 # 0 +0x0000F0B5 0x5180 # 0 +0x0000F0B6 0x51AA # 0 +0x0000F0B7 0x51DD # 0 +0x0000F0B8 0x5291 # 0 +0x0000F0B9 0x5293 # 0 +0x0000F0BA 0x52F3 # 0 +0x0000F0BB 0x5659 # 0 +0x0000F0BC 0x566B # 0 +0x0000F0BD 0x5679 # 0 +0x0000F0BE 0x5669 # 0 +0x0000F0BF 0x5664 # 0 +0x0000F0C0 0x5678 # 0 +0x0000F0C1 0x566A # 0 +0x0000F0C2 0x5668 # 0 +0x0000F0C3 0x5665 # 0 +0x0000F0C4 0x5671 # 0 +0x0000F0C5 0x566F # 0 +0x0000F0C6 0x566C # 0 +0x0000F0C7 0x5662 # 0 +0x0000F0C8 0x5676 # 0 +0x0000F0C9 0x58C1 # 0 +0x0000F0CA 0x58BE # 0 +0x0000F0CB 0x58C7 # 0 +0x0000F0CC 0x58C5 # 0 +0x0000F0CD 0x596E # 0 +0x0000F0CE 0x5B1D # 0 +0x0000F0CF 0x5B34 # 0 +0x0000F0D0 0x5B78 # 0 +0x0000F0D1 0x5BF0 # 0 +0x0000F0D2 0x5C0E # 0 +0x0000F0D3 0x5F4A # 0 +0x0000F0D4 0x61B2 # 0 +0x0000F0D5 0x6191 # 0 +0x0000F0D6 0x61A9 # 0 +0x0000F0D7 0x618A # 0 +0x0000F0D8 0x61CD # 0 +0x0000F0D9 0x61B6 # 0 +0x0000F0DA 0x61BE # 0 +0x0000F0DB 0x61CA # 0 +0x0000F0DC 0x61C8 # 0 +0x0000F0DD 0x6230 # 0 +0x0000F0DE 0x64C5 # 0 +0x0000F0DF 0x64C1 # 0 +0x0000F0E0 0x64CB # 0 +0x0000F0E1 0x64BB # 0 +0x0000F0E2 0x64BC # 0 +0x0000F0E3 0x64DA # 0 +0x0000F0E4 0x64C4 # 0 +0x0000F0E5 0x64C7 # 0 +0x0000F0E6 0x64C2 # 0 +0x0000F0E7 0x64CD # 0 +0x0000F0E8 0x64BF # 0 +0x0000F0E9 0x64D2 # 0 +0x0000F0EA 0x64D4 # 0 +0x0000F0EB 0x64BE # 0 +0x0000F0EC 0x6574 # 0 +0x0000F0ED 0x66C6 # 0 +0x0000F0EE 0x66C9 # 0 +0x0000F0EF 0x66B9 # 0 +0x0000F0F0 0x66C4 # 0 +0x0000F0F1 0x66C7 # 0 +0x0000F0F2 0x66B8 # 0 +0x0000F0F3 0x6A3D # 0 +0x0000F0F4 0x6A38 # 0 +0x0000F0F5 0x6A3A # 0 +0x0000F0F6 0x6A59 # 0 +0x0000F0F7 0x6A6B # 0 +0x0000F0F8 0x6A58 # 0 +0x0000F0F9 0x6A39 # 0 +0x0000F0FA 0x6A44 # 0 +0x0000F0FB 0x6A62 # 0 +0x0000F0FC 0x6A61 # 0 +0x0000F0FD 0x6A4B # 0 +0x0000F0FE 0x6A47 # 0 +0x0000F1A1 0x6A35 # 0 +0x0000F1A2 0x6A5F # 0 +0x0000F1A3 0x6A48 # 0 +0x0000F1A4 0x6B59 # 0 +0x0000F1A5 0x6B77 # 0 +0x0000F1A6 0x6C05 # 0 +0x0000F1A7 0x6FC2 # 0 +0x0000F1A8 0x6FB1 # 0 +0x0000F1A9 0x6FA1 # 0 +0x0000F1AA 0x6FC3 # 0 +0x0000F1AB 0x6FA4 # 0 +0x0000F1AC 0x6FC1 # 0 +0x0000F1AD 0x6FA7 # 0 +0x0000F1AE 0x6FB3 # 0 +0x0000F1AF 0x6FC0 # 0 +0x0000F1B0 0x6FB9 # 0 +0x0000F1B1 0x6FB6 # 0 +0x0000F1B2 0x6FA6 # 0 +0x0000F1B3 0x6FA0 # 0 +0x0000F1B4 0x6FB4 # 0 +0x0000F1B5 0x71BE # 0 +0x0000F1B6 0x71C9 # 0 +0x0000F1B7 0x71D0 # 0 +0x0000F1B8 0x71D2 # 0 +0x0000F1B9 0x71C8 # 0 +0x0000F1BA 0x71D5 # 0 +0x0000F1BB 0x71B9 # 0 +0x0000F1BC 0x71CE # 0 +0x0000F1BD 0x71D9 # 0 +0x0000F1BE 0x71DC # 0 +0x0000F1BF 0x71C3 # 0 +0x0000F1C0 0x71C4 # 0 +0x0000F1C1 0x7368 # 0 +0x0000F1C2 0x749C # 0 +0x0000F1C3 0x74A3 # 0 +0x0000F1C4 0x7498 # 0 +0x0000F1C5 0x749F # 0 +0x0000F1C6 0x749E # 0 +0x0000F1C7 0x74E2 # 0 +0x0000F1C8 0x750C # 0 +0x0000F1C9 0x750D # 0 +0x0000F1CA 0x7634 # 0 +0x0000F1CB 0x7638 # 0 +0x0000F1CC 0x763A # 0 +0x0000F1CD 0x76E7 # 0 +0x0000F1CE 0x76E5 # 0 +0x0000F1CF 0x77A0 # 0 +0x0000F1D0 0x779E # 0 +0x0000F1D1 0x779F # 0 +0x0000F1D2 0x77A5 # 0 +0x0000F1D3 0x78E8 # 0 +0x0000F1D4 0x78DA # 0 +0x0000F1D5 0x78EC # 0 +0x0000F1D6 0x78E7 # 0 +0x0000F1D7 0x79A6 # 0 +0x0000F1D8 0x7A4D # 0 +0x0000F1D9 0x7A4E # 0 +0x0000F1DA 0x7A46 # 0 +0x0000F1DB 0x7A4C # 0 +0x0000F1DC 0x7A4B # 0 +0x0000F1DD 0x7ABA # 0 +0x0000F1DE 0x7BD9 # 0 +0x0000F1DF 0x7C11 # 0 +0x0000F1E0 0x7BC9 # 0 +0x0000F1E1 0x7BE4 # 0 +0x0000F1E2 0x7BDB # 0 +0x0000F1E3 0x7BE1 # 0 +0x0000F1E4 0x7BE9 # 0 +0x0000F1E5 0x7BE6 # 0 +0x0000F1E6 0x7CD5 # 0 +0x0000F1E7 0x7CD6 # 0 +0x0000F1E8 0x7E0A # 0 +0x0000F1E9 0x7E11 # 0 +0x0000F1EA 0x7E08 # 0 +0x0000F1EB 0x7E1B # 0 +0x0000F1EC 0x7E23 # 0 +0x0000F1ED 0x7E1E # 0 +0x0000F1EE 0x7E1D # 0 +0x0000F1EF 0x7E09 # 0 +0x0000F1F0 0x7E10 # 0 +0x0000F1F1 0x7F79 # 0 +0x0000F1F2 0x7FB2 # 0 +0x0000F1F3 0x7FF0 # 0 +0x0000F1F4 0x7FF1 # 0 +0x0000F1F5 0x7FEE # 0 +0x0000F1F6 0x8028 # 0 +0x0000F1F7 0x81B3 # 0 +0x0000F1F8 0x81A9 # 0 +0x0000F1F9 0x81A8 # 0 +0x0000F1FA 0x81FB # 0 +0x0000F1FB 0x8208 # 0 +0x0000F1FC 0x8258 # 0 +0x0000F1FD 0x8259 # 0 +0x0000F1FE 0x854A # 0 +0x0000F2A1 0x8559 # 0 +0x0000F2A2 0x8548 # 0 +0x0000F2A3 0x8568 # 0 +0x0000F2A4 0x8569 # 0 +0x0000F2A5 0x8543 # 0 +0x0000F2A6 0x8549 # 0 +0x0000F2A7 0x856D # 0 +0x0000F2A8 0x856A # 0 +0x0000F2A9 0x855E # 0 +0x0000F2AA 0x8783 # 0 +0x0000F2AB 0x879F # 0 +0x0000F2AC 0x879E # 0 +0x0000F2AD 0x87A2 # 0 +0x0000F2AE 0x878D # 0 +0x0000F2AF 0x8861 # 0 +0x0000F2B0 0x892A # 0 +0x0000F2B1 0x8932 # 0 +0x0000F2B2 0x8925 # 0 +0x0000F2B3 0x892B # 0 +0x0000F2B4 0x8921 # 0 +0x0000F2B5 0x89AA # 0 +0x0000F2B6 0x89A6 # 0 +0x0000F2B7 0x8AE6 # 0 +0x0000F2B8 0x8AFA # 0 +0x0000F2B9 0x8AEB # 0 +0x0000F2BA 0x8AF1 # 0 +0x0000F2BB 0x8B00 # 0 +0x0000F2BC 0x8ADC # 0 +0x0000F2BD 0x8AE7 # 0 +0x0000F2BE 0x8AEE # 0 +0x0000F2BF 0x8AFE # 0 +0x0000F2C0 0x8B01 # 0 +0x0000F2C1 0x8B02 # 0 +0x0000F2C2 0x8AF7 # 0 +0x0000F2C3 0x8AED # 0 +0x0000F2C4 0x8AF3 # 0 +0x0000F2C5 0x8AF6 # 0 +0x0000F2C6 0x8AFC # 0 +0x0000F2C7 0x8C6B # 0 +0x0000F2C8 0x8C6D # 0 +0x0000F2C9 0x8C93 # 0 +0x0000F2CA 0x8CF4 # 0 +0x0000F2CB 0x8E44 # 0 +0x0000F2CC 0x8E31 # 0 +0x0000F2CD 0x8E34 # 0 +0x0000F2CE 0x8E42 # 0 +0x0000F2CF 0x8E39 # 0 +0x0000F2D0 0x8E35 # 0 +0x0000F2D1 0x8F3B # 0 +0x0000F2D2 0x8F2F # 0 +0x0000F2D3 0x8F38 # 0 +0x0000F2D4 0x8F33 # 0 +0x0000F2D5 0x8FA8 # 0 +0x0000F2D6 0x8FA6 # 0 +0x0000F2D7 0x9075 # 0 +0x0000F2D8 0x9074 # 0 +0x0000F2D9 0x9078 # 0 +0x0000F2DA 0x9072 # 0 +0x0000F2DB 0x907C # 0 +0x0000F2DC 0x907A # 0 +0x0000F2DD 0x9134 # 0 +0x0000F2DE 0x9192 # 0 +0x0000F2DF 0x9320 # 0 +0x0000F2E0 0x9336 # 0 +0x0000F2E1 0x92F8 # 0 +0x0000F2E2 0x9333 # 0 +0x0000F2E3 0x932F # 0 +0x0000F2E4 0x9322 # 0 +0x0000F2E5 0x92FC # 0 +0x0000F2E6 0x932B # 0 +0x0000F2E7 0x9304 # 0 +0x0000F2E8 0x931A # 0 +0x0000F2E9 0x9310 # 0 +0x0000F2EA 0x9326 # 0 +0x0000F2EB 0x9321 # 0 +0x0000F2EC 0x9315 # 0 +0x0000F2ED 0x932E # 0 +0x0000F2EE 0x9319 # 0 +0x0000F2EF 0x95BB # 0 +0x0000F2F0 0x96A7 # 0 +0x0000F2F1 0x96A8 # 0 +0x0000F2F2 0x96AA # 0 +0x0000F2F3 0x96D5 # 0 +0x0000F2F4 0x970E # 0 +0x0000F2F5 0x9711 # 0 +0x0000F2F6 0x9716 # 0 +0x0000F2F7 0x970D # 0 +0x0000F2F8 0x9713 # 0 +0x0000F2F9 0x970F # 0 +0x0000F2FA 0x975B # 0 +0x0000F2FB 0x975C # 0 +0x0000F2FC 0x9766 # 0 +0x0000F2FD 0x9798 # 0 +0x0000F2FE 0x9830 # 0 +0x0000F3A1 0x9838 # 0 +0x0000F3A2 0x983B # 0 +0x0000F3A3 0x9837 # 0 +0x0000F3A4 0x982D # 0 +0x0000F3A5 0x9839 # 0 +0x0000F3A6 0x9824 # 0 +0x0000F3A7 0x9910 # 0 +0x0000F3A8 0x9928 # 0 +0x0000F3A9 0x991E # 0 +0x0000F3AA 0x991B # 0 +0x0000F3AB 0x9921 # 0 +0x0000F3AC 0x991A # 0 +0x0000F3AD 0x99ED # 0 +0x0000F3AE 0x99E2 # 0 +0x0000F3AF 0x99F1 # 0 +0x0000F3B0 0x9AB8 # 0 +0x0000F3B1 0x9ABC # 0 +0x0000F3B2 0x9AFB # 0 +0x0000F3B3 0x9AED # 0 +0x0000F3B4 0x9B28 # 0 +0x0000F3B5 0x9B91 # 0 +0x0000F3B6 0x9D15 # 0 +0x0000F3B7 0x9D23 # 0 +0x0000F3B8 0x9D26 # 0 +0x0000F3B9 0x9D28 # 0 +0x0000F3BA 0x9D12 # 0 +0x0000F3BB 0x9D1B # 0 +0x0000F3BC 0x9ED8 # 0 +0x0000F3BD 0x9ED4 # 0 +0x0000F3BE 0x9F8D # 0 +0x0000F3BF 0x9F9C # 0 +0x0000F3C0 0x512A # 0 +0x0000F3C1 0x511F # 0 +0x0000F3C2 0x5121 # 0 +0x0000F3C3 0x5132 # 0 +0x0000F3C4 0x52F5 # 0 +0x0000F3C5 0x568E # 0 +0x0000F3C6 0x5680 # 0 +0x0000F3C7 0x5690 # 0 +0x0000F3C8 0x5685 # 0 +0x0000F3C9 0x5687 # 0 +0x0000F3CA 0x568F # 0 +0x0000F3CB 0x58D5 # 0 +0x0000F3CC 0x58D3 # 0 +0x0000F3CD 0x58D1 # 0 +0x0000F3CE 0x58CE # 0 +0x0000F3CF 0x5B30 # 0 +0x0000F3D0 0x5B2A # 0 +0x0000F3D1 0x5B24 # 0 +0x0000F3D2 0x5B7A # 0 +0x0000F3D3 0x5C37 # 0 +0x0000F3D4 0x5C68 # 0 +0x0000F3D5 0x5DBC # 0 +0x0000F3D6 0x5DBA # 0 +0x0000F3D7 0x5DBD # 0 +0x0000F3D8 0x5DB8 # 0 +0x0000F3D9 0x5E6B # 0 +0x0000F3DA 0x5F4C # 0 +0x0000F3DB 0x5FBD # 0 +0x0000F3DC 0x61C9 # 0 +0x0000F3DD 0x61C2 # 0 +0x0000F3DE 0x61C7 # 0 +0x0000F3DF 0x61E6 # 0 +0x0000F3E0 0x61CB # 0 +0x0000F3E1 0x6232 # 0 +0x0000F3E2 0x6234 # 0 +0x0000F3E3 0x64CE # 0 +0x0000F3E4 0x64CA # 0 +0x0000F3E5 0x64D8 # 0 +0x0000F3E6 0x64E0 # 0 +0x0000F3E7 0x64F0 # 0 +0x0000F3E8 0x64E6 # 0 +0x0000F3E9 0x64EC # 0 +0x0000F3EA 0x64F1 # 0 +0x0000F3EB 0x64E2 # 0 +0x0000F3EC 0x64ED # 0 +0x0000F3ED 0x6582 # 0 +0x0000F3EE 0x6583 # 0 +0x0000F3EF 0x66D9 # 0 +0x0000F3F0 0x66D6 # 0 +0x0000F3F1 0x6A80 # 0 +0x0000F3F2 0x6A94 # 0 +0x0000F3F3 0x6A84 # 0 +0x0000F3F4 0x6AA2 # 0 +0x0000F3F5 0x6A9C # 0 +0x0000F3F6 0x6ADB # 0 +0x0000F3F7 0x6AA3 # 0 +0x0000F3F8 0x6A7E # 0 +0x0000F3F9 0x6A97 # 0 +0x0000F3FA 0x6A90 # 0 +0x0000F3FB 0x6AA0 # 0 +0x0000F3FC 0x6B5C # 0 +0x0000F3FD 0x6BAE # 0 +0x0000F3FE 0x6BDA # 0 +0x0000F4A1 0x6C08 # 0 +0x0000F4A2 0x6FD8 # 0 +0x0000F4A3 0x6FF1 # 0 +0x0000F4A4 0x6FDF # 0 +0x0000F4A5 0x6FE0 # 0 +0x0000F4A6 0x6FDB # 0 +0x0000F4A7 0x6FE4 # 0 +0x0000F4A8 0x6FEB # 0 +0x0000F4A9 0x6FEF # 0 +0x0000F4AA 0x6F80 # 0 +0x0000F4AB 0x6FEC # 0 +0x0000F4AC 0x6FE1 # 0 +0x0000F4AD 0x6FE9 # 0 +0x0000F4AE 0x6FD5 # 0 +0x0000F4AF 0x6FEE # 0 +0x0000F4B0 0x6FF0 # 0 +0x0000F4B1 0x71E7 # 0 +0x0000F4B2 0x71DF # 0 +0x0000F4B3 0x71EE # 0 +0x0000F4B4 0x71E6 # 0 +0x0000F4B5 0x71E5 # 0 +0x0000F4B6 0x71ED # 0 +0x0000F4B7 0x71EC # 0 +0x0000F4B8 0x71F4 # 0 +0x0000F4B9 0x71E0 # 0 +0x0000F4BA 0x7235 # 0 +0x0000F4BB 0x7246 # 0 +0x0000F4BC 0x7370 # 0 +0x0000F4BD 0x7372 # 0 +0x0000F4BE 0x74A9 # 0 +0x0000F4BF 0x74B0 # 0 +0x0000F4C0 0x74A6 # 0 +0x0000F4C1 0x74A8 # 0 +0x0000F4C2 0x7646 # 0 +0x0000F4C3 0x7642 # 0 +0x0000F4C4 0x764C # 0 +0x0000F4C5 0x76EA # 0 +0x0000F4C6 0x77B3 # 0 +0x0000F4C7 0x77AA # 0 +0x0000F4C8 0x77B0 # 0 +0x0000F4C9 0x77AC # 0 +0x0000F4CA 0x77A7 # 0 +0x0000F4CB 0x77AD # 0 +0x0000F4CC 0x77EF # 0 +0x0000F4CD 0x78F7 # 0 +0x0000F4CE 0x78FA # 0 +0x0000F4CF 0x78F4 # 0 +0x0000F4D0 0x78EF # 0 +0x0000F4D1 0x7901 # 0 +0x0000F4D2 0x79A7 # 0 +0x0000F4D3 0x79AA # 0 +0x0000F4D4 0x7A57 # 0 +0x0000F4D5 0x7ABF # 0 +0x0000F4D6 0x7C07 # 0 +0x0000F4D7 0x7C0D # 0 +0x0000F4D8 0x7BFE # 0 +0x0000F4D9 0x7BF7 # 0 +0x0000F4DA 0x7C0C # 0 +0x0000F4DB 0x7BE0 # 0 +0x0000F4DC 0x7CE0 # 0 +0x0000F4DD 0x7CDC # 0 +0x0000F4DE 0x7CDE # 0 +0x0000F4DF 0x7CE2 # 0 +0x0000F4E0 0x7CDF # 0 +0x0000F4E1 0x7CD9 # 0 +0x0000F4E2 0x7CDD # 0 +0x0000F4E3 0x7E2E # 0 +0x0000F4E4 0x7E3E # 0 +0x0000F4E5 0x7E46 # 0 +0x0000F4E6 0x7E37 # 0 +0x0000F4E7 0x7E32 # 0 +0x0000F4E8 0x7E43 # 0 +0x0000F4E9 0x7E2B # 0 +0x0000F4EA 0x7E3D # 0 +0x0000F4EB 0x7E31 # 0 +0x0000F4EC 0x7E45 # 0 +0x0000F4ED 0x7E41 # 0 +0x0000F4EE 0x7E34 # 0 +0x0000F4EF 0x7E39 # 0 +0x0000F4F0 0x7E48 # 0 +0x0000F4F1 0x7E35 # 0 +0x0000F4F2 0x7E3F # 0 +0x0000F4F3 0x7E2F # 0 +0x0000F4F4 0x7F44 # 0 +0x0000F4F5 0x7FF3 # 0 +0x0000F4F6 0x7FFC # 0 +0x0000F4F7 0x8071 # 0 +0x0000F4F8 0x8072 # 0 +0x0000F4F9 0x8070 # 0 +0x0000F4FA 0x806F # 0 +0x0000F4FB 0x8073 # 0 +0x0000F4FC 0x81C6 # 0 +0x0000F4FD 0x81C3 # 0 +0x0000F4FE 0x81BA # 0 +0x0000F5A1 0x81C2 # 0 +0x0000F5A2 0x81C0 # 0 +0x0000F5A3 0x81BF # 0 +0x0000F5A4 0x81BD # 0 +0x0000F5A5 0x81C9 # 0 +0x0000F5A6 0x81BE # 0 +0x0000F5A7 0x81E8 # 0 +0x0000F5A8 0x8209 # 0 +0x0000F5A9 0x8271 # 0 +0x0000F5AA 0x85AA # 0 +0x0000F5AB 0x8584 # 0 +0x0000F5AC 0x857E # 0 +0x0000F5AD 0x859C # 0 +0x0000F5AE 0x8591 # 0 +0x0000F5AF 0x8594 # 0 +0x0000F5B0 0x85AF # 0 +0x0000F5B1 0x859B # 0 +0x0000F5B2 0x8587 # 0 +0x0000F5B3 0x85A8 # 0 +0x0000F5B4 0x858A # 0 +0x0000F5B5 0x85A6 # 0 +0x0000F5B6 0x8667 # 0 +0x0000F5B7 0x87C0 # 0 +0x0000F5B8 0x87D1 # 0 +0x0000F5B9 0x87B3 # 0 +0x0000F5BA 0x87D2 # 0 +0x0000F5BB 0x87C6 # 0 +0x0000F5BC 0x87AB # 0 +0x0000F5BD 0x87BB # 0 +0x0000F5BE 0x87BA # 0 +0x0000F5BF 0x87C8 # 0 +0x0000F5C0 0x87CB # 0 +0x0000F5C1 0x893B # 0 +0x0000F5C2 0x8936 # 0 +0x0000F5C3 0x8944 # 0 +0x0000F5C4 0x8938 # 0 +0x0000F5C5 0x893D # 0 +0x0000F5C6 0x89AC # 0 +0x0000F5C7 0x8B0E # 0 +0x0000F5C8 0x8B17 # 0 +0x0000F5C9 0x8B19 # 0 +0x0000F5CA 0x8B1B # 0 +0x0000F5CB 0x8B0A # 0 +0x0000F5CC 0x8B20 # 0 +0x0000F5CD 0x8B1D # 0 +0x0000F5CE 0x8B04 # 0 +0x0000F5CF 0x8B10 # 0 +0x0000F5D0 0x8C41 # 0 +0x0000F5D1 0x8C3F # 0 +0x0000F5D2 0x8C73 # 0 +0x0000F5D3 0x8CFA # 0 +0x0000F5D4 0x8CFD # 0 +0x0000F5D5 0x8CFC # 0 +0x0000F5D6 0x8CF8 # 0 +0x0000F5D7 0x8CFB # 0 +0x0000F5D8 0x8DA8 # 0 +0x0000F5D9 0x8E49 # 0 +0x0000F5DA 0x8E4B # 0 +0x0000F5DB 0x8E48 # 0 +0x0000F5DC 0x8E4A # 0 +0x0000F5DD 0x8F44 # 0 +0x0000F5DE 0x8F3E # 0 +0x0000F5DF 0x8F42 # 0 +0x0000F5E0 0x8F45 # 0 +0x0000F5E1 0x8F3F # 0 +0x0000F5E2 0x907F # 0 +0x0000F5E3 0x907D # 0 +0x0000F5E4 0x9084 # 0 +0x0000F5E5 0x9081 # 0 +0x0000F5E6 0x9082 # 0 +0x0000F5E7 0x9080 # 0 +0x0000F5E8 0x9139 # 0 +0x0000F5E9 0x91A3 # 0 +0x0000F5EA 0x919E # 0 +0x0000F5EB 0x919C # 0 +0x0000F5EC 0x934D # 0 +0x0000F5ED 0x9382 # 0 +0x0000F5EE 0x9328 # 0 +0x0000F5EF 0x9375 # 0 +0x0000F5F0 0x934A # 0 +0x0000F5F1 0x9365 # 0 +0x0000F5F2 0x934B # 0 +0x0000F5F3 0x9318 # 0 +0x0000F5F4 0x937E # 0 +0x0000F5F5 0x936C # 0 +0x0000F5F6 0x935B # 0 +0x0000F5F7 0x9370 # 0 +0x0000F5F8 0x935A # 0 +0x0000F5F9 0x9354 # 0 +0x0000F5FA 0x95CA # 0 +0x0000F5FB 0x95CB # 0 +0x0000F5FC 0x95CC # 0 +0x0000F5FD 0x95C8 # 0 +0x0000F5FE 0x95C6 # 0 +0x0000F6A1 0x96B1 # 0 +0x0000F6A2 0x96B8 # 0 +0x0000F6A3 0x96D6 # 0 +0x0000F6A4 0x971C # 0 +0x0000F6A5 0x971E # 0 +0x0000F6A6 0x97A0 # 0 +0x0000F6A7 0x97D3 # 0 +0x0000F6A8 0x9846 # 0 +0x0000F6A9 0x98B6 # 0 +0x0000F6AA 0x9935 # 0 +0x0000F6AB 0x9A01 # 0 +0x0000F6AC 0x99FF # 0 +0x0000F6AD 0x9BAE # 0 +0x0000F6AE 0x9BAB # 0 +0x0000F6AF 0x9BAA # 0 +0x0000F6B0 0x9BAD # 0 +0x0000F6B1 0x9D3B # 0 +0x0000F6B2 0x9D3F # 0 +0x0000F6B3 0x9E8B # 0 +0x0000F6B4 0x9ECF # 0 +0x0000F6B5 0x9EDE # 0 +0x0000F6B6 0x9EDC # 0 +0x0000F6B7 0x9EDD # 0 +0x0000F6B8 0x9EDB # 0 +0x0000F6B9 0x9F3E # 0 +0x0000F6BA 0x9F4B # 0 +0x0000F6BB 0x53E2 # 0 +0x0000F6BC 0x5695 # 0 +0x0000F6BD 0x56AE # 0 +0x0000F6BE 0x58D9 # 0 +0x0000F6BF 0x58D8 # 0 +0x0000F6C0 0x5B38 # 0 +0x0000F6C1 0x5F5E # 0 +0x0000F6C2 0x61E3 # 0 +0x0000F6C3 0x6233 # 0 +0x0000F6C4 0x64F4 # 0 +0x0000F6C5 0x64F2 # 0 +0x0000F6C6 0x64FE # 0 +0x0000F6C7 0x6506 # 0 +0x0000F6C8 0x64FA # 0 +0x0000F6C9 0x64FB # 0 +0x0000F6CA 0x64F7 # 0 +0x0000F6CB 0x65B7 # 0 +0x0000F6CC 0x66DC # 0 +0x0000F6CD 0x6726 # 0 +0x0000F6CE 0x6AB3 # 0 +0x0000F6CF 0x6AAC # 0 +0x0000F6D0 0x6AC3 # 0 +0x0000F6D1 0x6ABB # 0 +0x0000F6D2 0x6AB8 # 0 +0x0000F6D3 0x6AC2 # 0 +0x0000F6D4 0x6AAE # 0 +0x0000F6D5 0x6AAF # 0 +0x0000F6D6 0x6B5F # 0 +0x0000F6D7 0x6B78 # 0 +0x0000F6D8 0x6BAF # 0 +0x0000F6D9 0x7009 # 0 +0x0000F6DA 0x700B # 0 +0x0000F6DB 0x6FFE # 0 +0x0000F6DC 0x7006 # 0 +0x0000F6DD 0x6FFA # 0 +0x0000F6DE 0x7011 # 0 +0x0000F6DF 0x700F # 0 +0x0000F6E0 0x71FB # 0 +0x0000F6E1 0x71FC # 0 +0x0000F6E2 0x71FE # 0 +0x0000F6E3 0x71F8 # 0 +0x0000F6E4 0x7377 # 0 +0x0000F6E5 0x7375 # 0 +0x0000F6E6 0x74A7 # 0 +0x0000F6E7 0x74BF # 0 +0x0000F6E8 0x7515 # 0 +0x0000F6E9 0x7656 # 0 +0x0000F6EA 0x7658 # 0 +0x0000F6EB 0x7652 # 0 +0x0000F6EC 0x77BD # 0 +0x0000F6ED 0x77BF # 0 +0x0000F6EE 0x77BB # 0 +0x0000F6EF 0x77BC # 0 +0x0000F6F0 0x790E # 0 +0x0000F6F1 0x79AE # 0 +0x0000F6F2 0x7A61 # 0 +0x0000F6F3 0x7A62 # 0 +0x0000F6F4 0x7A60 # 0 +0x0000F6F5 0x7AC4 # 0 +0x0000F6F6 0x7AC5 # 0 +0x0000F6F7 0x7C2B # 0 +0x0000F6F8 0x7C27 # 0 +0x0000F6F9 0x7C2A # 0 +0x0000F6FA 0x7C1E # 0 +0x0000F6FB 0x7C23 # 0 +0x0000F6FC 0x7C21 # 0 +0x0000F6FD 0x7CE7 # 0 +0x0000F6FE 0x7E54 # 0 +0x0000F7A1 0x7E55 # 0 +0x0000F7A2 0x7E5E # 0 +0x0000F7A3 0x7E5A # 0 +0x0000F7A4 0x7E61 # 0 +0x0000F7A5 0x7E52 # 0 +0x0000F7A6 0x7E59 # 0 +0x0000F7A7 0x7F48 # 0 +0x0000F7A8 0x7FF9 # 0 +0x0000F7A9 0x7FFB # 0 +0x0000F7AA 0x8077 # 0 +0x0000F7AB 0x8076 # 0 +0x0000F7AC 0x81CD # 0 +0x0000F7AD 0x81CF # 0 +0x0000F7AE 0x820A # 0 +0x0000F7AF 0x85CF # 0 +0x0000F7B0 0x85A9 # 0 +0x0000F7B1 0x85CD # 0 +0x0000F7B2 0x85D0 # 0 +0x0000F7B3 0x85C9 # 0 +0x0000F7B4 0x85B0 # 0 +0x0000F7B5 0x85BA # 0 +0x0000F7B6 0x85B9 # 0 +0x0000F7B7 0x87EF # 0 +0x0000F7B8 0x87EC # 0 +0x0000F7B9 0x87F2 # 0 +0x0000F7BA 0x87E0 # 0 +0x0000F7BB 0x8986 # 0 +0x0000F7BC 0x89B2 # 0 +0x0000F7BD 0x89F4 # 0 +0x0000F7BE 0x8B28 # 0 +0x0000F7BF 0x8B39 # 0 +0x0000F7C0 0x8B2C # 0 +0x0000F7C1 0x8B2B # 0 +0x0000F7C2 0x8C50 # 0 +0x0000F7C3 0x8D05 # 0 +0x0000F7C4 0x8E59 # 0 +0x0000F7C5 0x8E63 # 0 +0x0000F7C6 0x8E66 # 0 +0x0000F7C7 0x8E64 # 0 +0x0000F7C8 0x8E5F # 0 +0x0000F7C9 0x8E55 # 0 +0x0000F7CA 0x8EC0 # 0 +0x0000F7CB 0x8F49 # 0 +0x0000F7CC 0x8F4D # 0 +0x0000F7CD 0x9087 # 0 +0x0000F7CE 0x9083 # 0 +0x0000F7CF 0x9088 # 0 +0x0000F7D0 0x91AB # 0 +0x0000F7D1 0x91AC # 0 +0x0000F7D2 0x91D0 # 0 +0x0000F7D3 0x9394 # 0 +0x0000F7D4 0x938A # 0 +0x0000F7D5 0x9396 # 0 +0x0000F7D6 0x93A2 # 0 +0x0000F7D7 0x93B3 # 0 +0x0000F7D8 0x93AE # 0 +0x0000F7D9 0x93AC # 0 +0x0000F7DA 0x93B0 # 0 +0x0000F7DB 0x9398 # 0 +0x0000F7DC 0x939A # 0 +0x0000F7DD 0x9397 # 0 +0x0000F7DE 0x95D4 # 0 +0x0000F7DF 0x95D6 # 0 +0x0000F7E0 0x95D0 # 0 +0x0000F7E1 0x95D5 # 0 +0x0000F7E2 0x96E2 # 0 +0x0000F7E3 0x96DC # 0 +0x0000F7E4 0x96D9 # 0 +0x0000F7E5 0x96DB # 0 +0x0000F7E6 0x96DE # 0 +0x0000F7E7 0x9724 # 0 +0x0000F7E8 0x97A3 # 0 +0x0000F7E9 0x97A6 # 0 +0x0000F7EA 0x97AD # 0 +0x0000F7EB 0x97F9 # 0 +0x0000F7EC 0x984D # 0 +0x0000F7ED 0x984F # 0 +0x0000F7EE 0x984C # 0 +0x0000F7EF 0x984E # 0 +0x0000F7F0 0x9853 # 0 +0x0000F7F1 0x98BA # 0 +0x0000F7F2 0x993E # 0 +0x0000F7F3 0x993F # 0 +0x0000F7F4 0x993D # 0 +0x0000F7F5 0x992E # 0 +0x0000F7F6 0x99A5 # 0 +0x0000F7F7 0x9A0E # 0 +0x0000F7F8 0x9AC1 # 0 +0x0000F7F9 0x9B03 # 0 +0x0000F7FA 0x9B06 # 0 +0x0000F7FB 0x9B4F # 0 +0x0000F7FC 0x9B4E # 0 +0x0000F7FD 0x9B4D # 0 +0x0000F7FE 0x9BCA # 0 +0x0000F8A1 0x9BC9 # 0 +0x0000F8A2 0x9BFD # 0 +0x0000F8A3 0x9BC8 # 0 +0x0000F8A4 0x9BC0 # 0 +0x0000F8A5 0x9D51 # 0 +0x0000F8A6 0x9D5D # 0 +0x0000F8A7 0x9D60 # 0 +0x0000F8A8 0x9EE0 # 0 +0x0000F8A9 0x9F15 # 0 +0x0000F8AA 0x9F2C # 0 +0x0000F8AB 0x5133 # 0 +0x0000F8AC 0x56A5 # 0 +0x0000F8AD 0x56A8 # 0 +0x0000F8AE 0x58DE # 0 +0x0000F8AF 0x58DF # 0 +0x0000F8B0 0x58E2 # 0 +0x0000F8B1 0x5BF5 # 0 +0x0000F8B2 0x9F90 # 0 +0x0000F8B3 0x5EEC # 0 +0x0000F8B4 0x61F2 # 0 +0x0000F8B5 0x61F7 # 0 +0x0000F8B6 0x61F6 # 0 +0x0000F8B7 0x61F5 # 0 +0x0000F8B8 0x6500 # 0 +0x0000F8B9 0x650F # 0 +0x0000F8BA 0x66E0 # 0 +0x0000F8BB 0x66DD # 0 +0x0000F8BC 0x6AE5 # 0 +0x0000F8BD 0x6ADD # 0 +0x0000F8BE 0x6ADA # 0 +0x0000F8BF 0x6AD3 # 0 +0x0000F8C0 0x701B # 0 +0x0000F8C1 0x701F # 0 +0x0000F8C2 0x7028 # 0 +0x0000F8C3 0x701A # 0 +0x0000F8C4 0x701D # 0 +0x0000F8C5 0x7015 # 0 +0x0000F8C6 0x7018 # 0 +0x0000F8C7 0x7206 # 0 +0x0000F8C8 0x720D # 0 +0x0000F8C9 0x7258 # 0 +0x0000F8CA 0x72A2 # 0 +0x0000F8CB 0x7378 # 0 +0x0000F8CC 0x737A # 0 +0x0000F8CD 0x74BD # 0 +0x0000F8CE 0x74CA # 0 +0x0000F8CF 0x74E3 # 0 +0x0000F8D0 0x7587 # 0 +0x0000F8D1 0x7586 # 0 +0x0000F8D2 0x765F # 0 +0x0000F8D3 0x7661 # 0 +0x0000F8D4 0x77C7 # 0 +0x0000F8D5 0x7919 # 0 +0x0000F8D6 0x79B1 # 0 +0x0000F8D7 0x7A6B # 0 +0x0000F8D8 0x7A69 # 0 +0x0000F8D9 0x7C3E # 0 +0x0000F8DA 0x7C3F # 0 +0x0000F8DB 0x7C38 # 0 +0x0000F8DC 0x7C3D # 0 +0x0000F8DD 0x7C37 # 0 +0x0000F8DE 0x7C40 # 0 +0x0000F8DF 0x7E6B # 0 +0x0000F8E0 0x7E6D # 0 +0x0000F8E1 0x7E79 # 0 +0x0000F8E2 0x7E69 # 0 +0x0000F8E3 0x7E6A # 0 +0x0000F8E4 0x7E73 # 0 +0x0000F8E5 0x7F85 # 0 +0x0000F8E6 0x7FB6 # 0 +0x0000F8E7 0x7FB9 # 0 +0x0000F8E8 0x7FB8 # 0 +0x0000F8E9 0x81D8 # 0 +0x0000F8EA 0x85E9 # 0 +0x0000F8EB 0x85DD # 0 +0x0000F8EC 0x85EA # 0 +0x0000F8ED 0x85D5 # 0 +0x0000F8EE 0x85E4 # 0 +0x0000F8EF 0x85E5 # 0 +0x0000F8F0 0x85F7 # 0 +0x0000F8F1 0x87FB # 0 +0x0000F8F2 0x8805 # 0 +0x0000F8F3 0x880D # 0 +0x0000F8F4 0x87F9 # 0 +0x0000F8F5 0x87FE # 0 +0x0000F8F6 0x8960 # 0 +0x0000F8F7 0x895F # 0 +0x0000F8F8 0x8956 # 0 +0x0000F8F9 0x895E # 0 +0x0000F8FA 0x8B41 # 0 +0x0000F8FB 0x8B5C # 0 +0x0000F8FC 0x8B58 # 0 +0x0000F8FD 0x8B49 # 0 +0x0000F8FE 0x8B5A # 0 +0x0000F9A1 0x8B4E # 0 +0x0000F9A2 0x8B4F # 0 +0x0000F9A3 0x8B46 # 0 +0x0000F9A4 0x8B59 # 0 +0x0000F9A5 0x8D08 # 0 +0x0000F9A6 0x8D0A # 0 +0x0000F9A7 0x8E7C # 0 +0x0000F9A8 0x8E72 # 0 +0x0000F9A9 0x8E87 # 0 +0x0000F9AA 0x8E76 # 0 +0x0000F9AB 0x8E6C # 0 +0x0000F9AC 0x8E7A # 0 +0x0000F9AD 0x8E74 # 0 +0x0000F9AE 0x8F54 # 0 +0x0000F9AF 0x8F4E # 0 +0x0000F9B0 0x8FAD # 0 +0x0000F9B1 0x908A # 0 +0x0000F9B2 0x908B # 0 +0x0000F9B3 0x91B1 # 0 +0x0000F9B4 0x91AE # 0 +0x0000F9B5 0x93E1 # 0 +0x0000F9B6 0x93D1 # 0 +0x0000F9B7 0x93DF # 0 +0x0000F9B8 0x93C3 # 0 +0x0000F9B9 0x93C8 # 0 +0x0000F9BA 0x93DC # 0 +0x0000F9BB 0x93DD # 0 +0x0000F9BC 0x93D6 # 0 +0x0000F9BD 0x93E2 # 0 +0x0000F9BE 0x93CD # 0 +0x0000F9BF 0x93D8 # 0 +0x0000F9C0 0x93E4 # 0 +0x0000F9C1 0x93D7 # 0 +0x0000F9C2 0x93E8 # 0 +0x0000F9C3 0x95DC # 0 +0x0000F9C4 0x96B4 # 0 +0x0000F9C5 0x96E3 # 0 +0x0000F9C6 0x972A # 0 +0x0000F9C7 0x9727 # 0 +0x0000F9C8 0x9761 # 0 +0x0000F9C9 0x97DC # 0 +0x0000F9CA 0x97FB # 0 +0x0000F9CB 0x985E # 0 +0x0000F9CC 0x9858 # 0 +0x0000F9CD 0x985B # 0 +0x0000F9CE 0x98BC # 0 +0x0000F9CF 0x9945 # 0 +0x0000F9D0 0x9949 # 0 +0x0000F9D1 0x9A16 # 0 +0x0000F9D2 0x9A19 # 0 +0x0000F9D3 0x9B0D # 0 +0x0000F9D4 0x9BE8 # 0 +0x0000F9D5 0x9BE7 # 0 +0x0000F9D6 0x9BD6 # 0 +0x0000F9D7 0x9BDB # 0 +0x0000F9D8 0x9D89 # 0 +0x0000F9D9 0x9D61 # 0 +0x0000F9DA 0x9D72 # 0 +0x0000F9DB 0x9D6A # 0 +0x0000F9DC 0x9D6C # 0 +0x0000F9DD 0x9E92 # 0 +0x0000F9DE 0x9E97 # 0 +0x0000F9DF 0x9E93 # 0 +0x0000F9E0 0x9EB4 # 0 +0x0000F9E1 0x52F8 # 0 +0x0000F9E2 0x56B7 # 0 +0x0000F9E3 0x56B6 # 0 +0x0000F9E4 0x56B4 # 0 +0x0000F9E5 0x56BC # 0 +0x0000F9E6 0x58E4 # 0 +0x0000F9E7 0x5B40 # 0 +0x0000F9E8 0x5B43 # 0 +0x0000F9E9 0x5B7D # 0 +0x0000F9EA 0x5BF6 # 0 +0x0000F9EB 0x5DC9 # 0 +0x0000F9EC 0x61F8 # 0 +0x0000F9ED 0x61FA # 0 +0x0000F9EE 0x6518 # 0 +0x0000F9EF 0x6514 # 0 +0x0000F9F0 0x6519 # 0 +0x0000F9F1 0x66E6 # 0 +0x0000F9F2 0x6727 # 0 +0x0000F9F3 0x6AEC # 0 +0x0000F9F4 0x703E # 0 +0x0000F9F5 0x7030 # 0 +0x0000F9F6 0x7032 # 0 +0x0000F9F7 0x7210 # 0 +0x0000F9F8 0x737B # 0 +0x0000F9F9 0x74CF # 0 +0x0000F9FA 0x7662 # 0 +0x0000F9FB 0x7665 # 0 +0x0000F9FC 0x7926 # 0 +0x0000F9FD 0x792A # 0 +0x0000F9FE 0x792C # 0 +0x0000FAA1 0x792B # 0 +0x0000FAA2 0x7AC7 # 0 +0x0000FAA3 0x7AF6 # 0 +0x0000FAA4 0x7C4C # 0 +0x0000FAA5 0x7C43 # 0 +0x0000FAA6 0x7C4D # 0 +0x0000FAA7 0x7CEF # 0 +0x0000FAA8 0x7CF0 # 0 +0x0000FAA9 0x8FAE # 0 +0x0000FAAA 0x7E7D # 0 +0x0000FAAB 0x7E7C # 0 +0x0000FAAC 0x7E82 # 0 +0x0000FAAD 0x7F4C # 0 +0x0000FAAE 0x8000 # 0 +0x0000FAAF 0x81DA # 0 +0x0000FAB0 0x8266 # 0 +0x0000FAB1 0x85FB # 0 +0x0000FAB2 0x85F9 # 0 +0x0000FAB3 0x8611 # 0 +0x0000FAB4 0x85FA # 0 +0x0000FAB5 0x8606 # 0 +0x0000FAB6 0x860B # 0 +0x0000FAB7 0x8607 # 0 +0x0000FAB8 0x860A # 0 +0x0000FAB9 0x8814 # 0 +0x0000FABA 0x8815 # 0 +0x0000FABB 0x8964 # 0 +0x0000FABC 0x89BA # 0 +0x0000FABD 0x89F8 # 0 +0x0000FABE 0x8B70 # 0 +0x0000FABF 0x8B6C # 0 +0x0000FAC0 0x8B66 # 0 +0x0000FAC1 0x8B6F # 0 +0x0000FAC2 0x8B5F # 0 +0x0000FAC3 0x8B6B # 0 +0x0000FAC4 0x8D0F # 0 +0x0000FAC5 0x8D0D # 0 +0x0000FAC6 0x8E89 # 0 +0x0000FAC7 0x8E81 # 0 +0x0000FAC8 0x8E85 # 0 +0x0000FAC9 0x8E82 # 0 +0x0000FACA 0x91B4 # 0 +0x0000FACB 0x91CB # 0 +0x0000FACC 0x9418 # 0 +0x0000FACD 0x9403 # 0 +0x0000FACE 0x93FD # 0 +0x0000FACF 0x95E1 # 0 +0x0000FAD0 0x9730 # 0 +0x0000FAD1 0x98C4 # 0 +0x0000FAD2 0x9952 # 0 +0x0000FAD3 0x9951 # 0 +0x0000FAD4 0x99A8 # 0 +0x0000FAD5 0x9A2B # 0 +0x0000FAD6 0x9A30 # 0 +0x0000FAD7 0x9A37 # 0 +0x0000FAD8 0x9A35 # 0 +0x0000FAD9 0x9C13 # 0 +0x0000FADA 0x9C0D # 0 +0x0000FADB 0x9E79 # 0 +0x0000FADC 0x9EB5 # 0 +0x0000FADD 0x9EE8 # 0 +0x0000FADE 0x9F2F # 0 +0x0000FADF 0x9F5F # 0 +0x0000FAE0 0x9F63 # 0 +0x0000FAE1 0x9F61 # 0 +0x0000FAE2 0x5137 # 0 +0x0000FAE3 0x5138 # 0 +0x0000FAE4 0x56C1 # 0 +0x0000FAE5 0x56C0 # 0 +0x0000FAE6 0x56C2 # 0 +0x0000FAE7 0x5914 # 0 +0x0000FAE8 0x5C6C # 0 +0x0000FAE9 0x5DCD # 0 +0x0000FAEA 0x61FC # 0 +0x0000FAEB 0x61FE # 0 +0x0000FAEC 0x651D # 0 +0x0000FAED 0x651C # 0 +0x0000FAEE 0x6595 # 0 +0x0000FAEF 0x66E9 # 0 +0x0000FAF0 0x6AFB # 0 +0x0000FAF1 0x6B04 # 0 +0x0000FAF2 0x6AFA # 0 +0x0000FAF3 0x6BB2 # 0 +0x0000FAF4 0x704C # 0 +0x0000FAF5 0x721B # 0 +0x0000FAF6 0x72A7 # 0 +0x0000FAF7 0x74D6 # 0 +0x0000FAF8 0x74D4 # 0 +0x0000FAF9 0x7669 # 0 +0x0000FAFA 0x77D3 # 0 +0x0000FAFB 0x7C50 # 0 +0x0000FAFC 0x7E8F # 0 +0x0000FAFD 0x7E8C # 0 +0x0000FAFE 0x7FBC # 0 +0x0000FBA1 0x8617 # 0 +0x0000FBA2 0x862D # 0 +0x0000FBA3 0x861A # 0 +0x0000FBA4 0x8823 # 0 +0x0000FBA5 0x8822 # 0 +0x0000FBA6 0x8821 # 0 +0x0000FBA7 0x881F # 0 +0x0000FBA8 0x896A # 0 +0x0000FBA9 0x896C # 0 +0x0000FBAA 0x89BD # 0 +0x0000FBAB 0x8B74 # 0 +0x0000FBAC 0x8B77 # 0 +0x0000FBAD 0x8B7D # 0 +0x0000FBAE 0x8D13 # 0 +0x0000FBAF 0x8E8A # 0 +0x0000FBB0 0x8E8D # 0 +0x0000FBB1 0x8E8B # 0 +0x0000FBB2 0x8F5F # 0 +0x0000FBB3 0x8FAF # 0 +0x0000FBB4 0x91BA # 0 +0x0000FBB5 0x942E # 0 +0x0000FBB6 0x9433 # 0 +0x0000FBB7 0x9435 # 0 +0x0000FBB8 0x943A # 0 +0x0000FBB9 0x9438 # 0 +0x0000FBBA 0x9432 # 0 +0x0000FBBB 0x942B # 0 +0x0000FBBC 0x95E2 # 0 +0x0000FBBD 0x9738 # 0 +0x0000FBBE 0x9739 # 0 +0x0000FBBF 0x9732 # 0 +0x0000FBC0 0x97FF # 0 +0x0000FBC1 0x9867 # 0 +0x0000FBC2 0x9865 # 0 +0x0000FBC3 0x9957 # 0 +0x0000FBC4 0x9A45 # 0 +0x0000FBC5 0x9A43 # 0 +0x0000FBC6 0x9A40 # 0 +0x0000FBC7 0x9A3E # 0 +0x0000FBC8 0x9ACF # 0 +0x0000FBC9 0x9B54 # 0 +0x0000FBCA 0x9B51 # 0 +0x0000FBCB 0x9C2D # 0 +0x0000FBCC 0x9C25 # 0 +0x0000FBCD 0x9DAF # 0 +0x0000FBCE 0x9DB4 # 0 +0x0000FBCF 0x9DC2 # 0 +0x0000FBD0 0x9DB8 # 0 +0x0000FBD1 0x9E9D # 0 +0x0000FBD2 0x9EEF # 0 +0x0000FBD3 0x9F19 # 0 +0x0000FBD4 0x9F5C # 0 +0x0000FBD5 0x9F66 # 0 +0x0000FBD6 0x9F67 # 0 +0x0000FBD7 0x513C # 0 +0x0000FBD8 0x513B # 0 +0x0000FBD9 0x56C8 # 0 +0x0000FBDA 0x56CA # 0 +0x0000FBDB 0x56C9 # 0 +0x0000FBDC 0x5B7F # 0 +0x0000FBDD 0x5DD4 # 0 +0x0000FBDE 0x5DD2 # 0 +0x0000FBDF 0x5F4E # 0 +0x0000FBE0 0x61FF # 0 +0x0000FBE1 0x6524 # 0 +0x0000FBE2 0x6B0A # 0 +0x0000FBE3 0x6B61 # 0 +0x0000FBE4 0x7051 # 0 +0x0000FBE5 0x7058 # 0 +0x0000FBE6 0x7380 # 0 +0x0000FBE7 0x74E4 # 0 +0x0000FBE8 0x758A # 0 +0x0000FBE9 0x766E # 0 +0x0000FBEA 0x766C # 0 +0x0000FBEB 0x79B3 # 0 +0x0000FBEC 0x7C60 # 0 +0x0000FBED 0x7C5F # 0 +0x0000FBEE 0x807E # 0 +0x0000FBEF 0x807D # 0 +0x0000FBF0 0x81DF # 0 +0x0000FBF1 0x8972 # 0 +0x0000FBF2 0x896F # 0 +0x0000FBF3 0x89FC # 0 +0x0000FBF4 0x8B80 # 0 +0x0000FBF5 0x8D16 # 0 +0x0000FBF6 0x8D17 # 0 +0x0000FBF7 0x8E91 # 0 +0x0000FBF8 0x8E93 # 0 +0x0000FBF9 0x8F61 # 0 +0x0000FBFA 0x9148 # 0 +0x0000FBFB 0x9444 # 0 +0x0000FBFC 0x9451 # 0 +0x0000FBFD 0x9452 # 0 +0x0000FBFE 0x973D # 0 +0x0000FCA1 0x973E # 0 +0x0000FCA2 0x97C3 # 0 +0x0000FCA3 0x97C1 # 0 +0x0000FCA4 0x986B # 0 +0x0000FCA5 0x9955 # 0 +0x0000FCA6 0x9A55 # 0 +0x0000FCA7 0x9A4D # 0 +0x0000FCA8 0x9AD2 # 0 +0x0000FCA9 0x9B1A # 0 +0x0000FCAA 0x9C49 # 0 +0x0000FCAB 0x9C31 # 0 +0x0000FCAC 0x9C3E # 0 +0x0000FCAD 0x9C3B # 0 +0x0000FCAE 0x9DD3 # 0 +0x0000FCAF 0x9DD7 # 0 +0x0000FCB0 0x9F34 # 0 +0x0000FCB1 0x9F6C # 0 +0x0000FCB2 0x9F6A # 0 +0x0000FCB3 0x9F94 # 0 +0x0000FCB4 0x56CC # 0 +0x0000FCB5 0x5DD6 # 0 +0x0000FCB6 0x6200 # 0 +0x0000FCB7 0x6523 # 0 +0x0000FCB8 0x652B # 0 +0x0000FCB9 0x652A # 0 +0x0000FCBA 0x66EC # 0 +0x0000FCBB 0x6B10 # 0 +0x0000FCBC 0x74DA # 0 +0x0000FCBD 0x7ACA # 0 +0x0000FCBE 0x7C64 # 0 +0x0000FCBF 0x7C63 # 0 +0x0000FCC0 0x7C65 # 0 +0x0000FCC1 0x7E93 # 0 +0x0000FCC2 0x7E96 # 0 +0x0000FCC3 0x7E94 # 0 +0x0000FCC4 0x81E2 # 0 +0x0000FCC5 0x8638 # 0 +0x0000FCC6 0x863F # 0 +0x0000FCC7 0x8831 # 0 +0x0000FCC8 0x8B8A # 0 +0x0000FCC9 0x9090 # 0 +0x0000FCCA 0x908F # 0 +0x0000FCCB 0x9463 # 0 +0x0000FCCC 0x9460 # 0 +0x0000FCCD 0x9464 # 0 +0x0000FCCE 0x9768 # 0 +0x0000FCCF 0x986F # 0 +0x0000FCD0 0x995C # 0 +0x0000FCD1 0x9A5A # 0 +0x0000FCD2 0x9A5B # 0 +0x0000FCD3 0x9A57 # 0 +0x0000FCD4 0x9AD3 # 0 +0x0000FCD5 0x9AD4 # 0 +0x0000FCD6 0x9AD1 # 0 +0x0000FCD7 0x9C54 # 0 +0x0000FCD8 0x9C57 # 0 +0x0000FCD9 0x9C56 # 0 +0x0000FCDA 0x9DE5 # 0 +0x0000FCDB 0x9E9F # 0 +0x0000FCDC 0x9EF4 # 0 +0x0000FCDD 0x56D1 # 0 +0x0000FCDE 0x58E9 # 0 +0x0000FCDF 0x652C # 0 +0x0000FCE0 0x705E # 0 +0x0000FCE1 0x7671 # 0 +0x0000FCE2 0x7672 # 0 +0x0000FCE3 0x77D7 # 0 +0x0000FCE4 0x7F50 # 0 +0x0000FCE5 0x7F88 # 0 +0x0000FCE6 0x8836 # 0 +0x0000FCE7 0x8839 # 0 +0x0000FCE8 0x8862 # 0 +0x0000FCE9 0x8B93 # 0 +0x0000FCEA 0x8B92 # 0 +0x0000FCEB 0x8B96 # 0 +0x0000FCEC 0x8277 # 0 +0x0000FCED 0x8D1B # 0 +0x0000FCEE 0x91C0 # 0 +0x0000FCEF 0x946A # 0 +0x0000FCF0 0x9742 # 0 +0x0000FCF1 0x9748 # 0 +0x0000FCF2 0x9744 # 0 +0x0000FCF3 0x97C6 # 0 +0x0000FCF4 0x9870 # 0 +0x0000FCF5 0x9A5F # 0 +0x0000FCF6 0x9B22 # 0 +0x0000FCF7 0x9B58 # 0 +0x0000FCF8 0x9C5F # 0 +0x0000FCF9 0x9DF9 # 0 +0x0000FCFA 0x9DFA # 0 +0x0000FCFB 0x9E7C # 0 +0x0000FCFC 0x9E7D # 0 +0x0000FCFD 0x9F07 # 0 +0x0000FCFE 0x9F77 # 0 +0x0000FDA1 0x9F72 # 0 +0x0000FDA2 0x5EF3 # 0 +0x0000FDA3 0x6B16 # 0 +0x0000FDA4 0x7063 # 0 +0x0000FDA5 0x7C6C # 0 +0x0000FDA6 0x7C6E # 0 +0x0000FDA7 0x883B # 0 +0x0000FDA8 0x89C0 # 0 +0x0000FDA9 0x8EA1 # 0 +0x0000FDAA 0x91C1 # 0 +0x0000FDAB 0x9472 # 0 +0x0000FDAC 0x9470 # 0 +0x0000FDAD 0x9871 # 0 +0x0000FDAE 0x995E # 0 +0x0000FDAF 0x9AD6 # 0 +0x0000FDB0 0x9B23 # 0 +0x0000FDB1 0x9ECC # 0 +0x0000FDB2 0x7064 # 0 +0x0000FDB3 0x77DA # 0 +0x0000FDB4 0x8B9A # 0 +0x0000FDB5 0x9477 # 0 +0x0000FDB6 0x97C9 # 0 +0x0000FDB7 0x9A62 # 0 +0x0000FDB8 0x9A65 # 0 +0x0000FDB9 0x7E9C # 0 +0x0000FDBA 0x8B9C # 0 +0x0000FDBB 0x8EAA # 0 +0x0000FDBC 0x91C5 # 0 +0x0000FDBD 0x947D # 0 +0x0000FDBE 0x947E # 0 +0x0000FDBF 0x947C # 0 +0x0000FDC0 0x9C77 # 0 +0x0000FDC1 0x9C78 # 0 +0x0000FDC2 0x9EF7 # 0 +0x0000FDC3 0x8C54 # 0 +0x0000FDC4 0x947F # 0 +0x0000FDC5 0x9E1A # 0 +0x0000FDC6 0x7228 # 0 +0x0000FDC7 0x9A6A # 0 +0x0000FDC8 0x9B31 # 0 +0x0000FDC9 0x9E1B # 0 +0x0000FDCA 0x9E1E # 0 +0x0000FDCB 0x7C72 # 0 +0x8EA2A1A1 0x4E42 # 0 +0x8EA2A1A2 0x4E5C # 0 +0x8EA2A1A3 0x51F5 # 0 +0x8EA2A1A4 0x531A # 0 +0x8EA2A1A5 0x5382 # 0 +0x8EA2A1A6 0x4E07 # 0 +0x8EA2A1A7 0x4E0C # 0 +0x8EA2A1A8 0x4E47 # 0 +0x8EA2A1A9 0x4E8D # 0 +0x8EA2A1AA 0x56D7 # 0 +0x8EA2A1AB 0x5C6E # 0 +0x8EA2A1AC 0x5F73 # 0 +0x8EA2A1AD 0x4E0F # 0 +0x8EA2A1AE 0x5187 # 0 +0x8EA2A1AF 0x4E0E # 0 +0x8EA2A1B0 0x4E2E # 0 +0x8EA2A1B1 0x4E93 # 0 +0x8EA2A1B2 0x4EC2 # 0 +0x8EA2A1B3 0x4EC9 # 0 +0x8EA2A1B4 0x4EC8 # 0 +0x8EA2A1B5 0x5198 # 0 +0x8EA2A1B6 0x52FC # 0 +0x8EA2A1B7 0x536C # 0 +0x8EA2A1B8 0x53B9 # 0 +0x8EA2A1B9 0x5720 # 0 +0x8EA2A1BA 0x5903 # 0 +0x8EA2A1BB 0x592C # 0 +0x8EA2A1BC 0x5C10 # 0 +0x8EA2A1BD 0x5DFF # 0 +0x8EA2A1BE 0x65E1 # 0 +0x8EA2A1BF 0x6BB3 # 0 +0x8EA2A1C0 0x6BCC # 0 +0x8EA2A1C1 0x6C14 # 0 +0x8EA2A1C2 0x723F # 0 +0x8EA2A1C3 0x4E31 # 0 +0x8EA2A1C4 0x4E3C # 0 +0x8EA2A1C5 0x4EE8 # 0 +0x8EA2A1C6 0x4EDC # 0 +0x8EA2A1C7 0x4EE9 # 0 +0x8EA2A1C8 0x4EE1 # 0 +0x8EA2A1C9 0x4EDD # 0 +0x8EA2A1CA 0x4EDA # 0 +0x8EA2A1CB 0x520C # 0 +0x8EA2A1CC 0x5209 # 0 +0x8EA2A1CD 0x531C # 0 +0x8EA2A1CE 0x534C # 0 +0x8EA2A1CF 0x5722 # 0 +0x8EA2A1D0 0x5723 # 0 +0x8EA2A1D1 0x5917 # 0 +0x8EA2A1D2 0x592F # 0 +0x8EA2A1D3 0x5B81 # 0 +0x8EA2A1D4 0x5B84 # 0 +0x8EA2A1D5 0x5C12 # 0 +0x8EA2A1D6 0x5C3B # 0 +0x8EA2A1D7 0x5C74 # 0 +0x8EA2A1D8 0x5C73 # 0 +0x8EA2A1D9 0x5E04 # 0 +0x8EA2A1DA 0x5E80 # 0 +0x8EA2A1DB 0x5E82 # 0 +0x8EA2A1DC 0x5FC9 # 0 +0x8EA2A1DD 0x6209 # 0 +0x8EA2A1DE 0x6250 # 0 +0x8EA2A1DF 0x6C15 # 0 +0x8EA2A1E0 0x6C36 # 0 +0x8EA2A1E1 0x6C43 # 0 +0x8EA2A1E2 0x6C3F # 0 +0x8EA2A1E3 0x6C3B # 0 +0x8EA2A1E4 0x72AE # 0 +0x8EA2A1E5 0x72B0 # 0 +0x8EA2A1E6 0x738A # 0 +0x8EA2A1E7 0x79B8 # 0 +0x8EA2A1E8 0x808A # 0 +0x8EA2A1E9 0x961E # 0 +0x8EA2A1EA 0x4F0E # 0 +0x8EA2A1EB 0x4F18 # 0 +0x8EA2A1EC 0x4F2C # 0 +0x8EA2A1ED 0x4EF5 # 0 +0x8EA2A1EE 0x4F14 # 0 +0x8EA2A1EF 0x4EF1 # 0 +0x8EA2A1F0 0x4F00 # 0 +0x8EA2A1F1 0x4EF7 # 0 +0x8EA2A1F2 0x4F08 # 0 +0x8EA2A1F3 0x4F1D # 0 +0x8EA2A1F4 0x4F02 # 0 +0x8EA2A1F5 0x4F05 # 0 +0x8EA2A1F6 0x4F22 # 0 +0x8EA2A1F7 0x4F13 # 0 +0x8EA2A1F8 0x4F04 # 0 +0x8EA2A1F9 0x4EF4 # 0 +0x8EA2A1FA 0x4F12 # 0 +0x8EA2A1FB 0x51B1 # 0 +0x8EA2A1FC 0x5213 # 0 +0x8EA2A1FD 0x5210 # 0 +0x8EA2A1FE 0x52A6 # 0 +0x8EA2A2A1 0x5322 # 0 +0x8EA2A2A2 0x531F # 0 +0x8EA2A2A3 0x534D # 0 +0x8EA2A2A4 0x538A # 0 +0x8EA2A2A5 0x5407 # 0 +0x8EA2A2A6 0x56E1 # 0 +0x8EA2A2A7 0x56DF # 0 +0x8EA2A2A8 0x572E # 0 +0x8EA2A2A9 0x572A # 0 +0x8EA2A2AA 0x5734 # 0 +0x8EA2A2AB 0x593C # 0 +0x8EA2A2AC 0x5980 # 0 +0x8EA2A2AD 0x597C # 0 +0x8EA2A2AE 0x5985 # 0 +0x8EA2A2AF 0x597B # 0 +0x8EA2A2B0 0x597E # 0 +0x8EA2A2B1 0x5977 # 0 +0x8EA2A2B2 0x597F # 0 +0x8EA2A2B3 0x5B56 # 0 +0x8EA2A2B4 0x5C15 # 0 +0x8EA2A2B5 0x5C25 # 0 +0x8EA2A2B6 0x5C7C # 0 +0x8EA2A2B7 0x5C7A # 0 +0x8EA2A2B8 0x5C7B # 0 +0x8EA2A2B9 0x5C7E # 0 +0x8EA2A2BA 0x5DDF # 0 +0x8EA2A2BB 0x5E75 # 0 +0x8EA2A2BC 0x5E84 # 0 +0x8EA2A2BD 0x5F02 # 0 +0x8EA2A2BE 0x5F1A # 0 +0x8EA2A2BF 0x5F74 # 0 +0x8EA2A2C0 0x5FD5 # 0 +0x8EA2A2C1 0x5FD4 # 0 +0x8EA2A2C2 0x5FCF # 0 +0x8EA2A2C3 0x625C # 0 +0x8EA2A2C4 0x625E # 0 +0x8EA2A2C5 0x6264 # 0 +0x8EA2A2C6 0x6261 # 0 +0x8EA2A2C7 0x6266 # 0 +0x8EA2A2C8 0x6262 # 0 +0x8EA2A2C9 0x6259 # 0 +0x8EA2A2CA 0x6260 # 0 +0x8EA2A2CB 0x625A # 0 +0x8EA2A2CC 0x6265 # 0 +0x8EA2A2CD 0x6537 # 0 +0x8EA2A2CE 0x65EF # 0 +0x8EA2A2CF 0x65EE # 0 +0x8EA2A2D0 0x673E # 0 +0x8EA2A2D1 0x6739 # 0 +0x8EA2A2D2 0x6738 # 0 +0x8EA2A2D3 0x673B # 0 +0x8EA2A2D4 0x673A # 0 +0x8EA2A2D5 0x673F # 0 +0x8EA2A2D6 0x673C # 0 +0x8EA2A2D7 0x6733 # 0 +0x8EA2A2D8 0x6C18 # 0 +0x8EA2A2D9 0x6C46 # 0 +0x8EA2A2DA 0x6C52 # 0 +0x8EA2A2DB 0x6C5C # 0 +0x8EA2A2DC 0x6C4F # 0 +0x8EA2A2DD 0x6C4A # 0 +0x8EA2A2DE 0x6C54 # 0 +0x8EA2A2DF 0x6C4B # 0 +0x8EA2A2E0 0x6C4C # 0 +0x8EA2A2E1 0x7071 # 0 +0x8EA2A2E2 0x725E # 0 +0x8EA2A2E3 0x72B4 # 0 +0x8EA2A2E4 0x72B5 # 0 +0x8EA2A2E5 0x738E # 0 +0x8EA2A2E6 0x752A # 0 +0x8EA2A2E7 0x767F # 0 +0x8EA2A2E8 0x7A75 # 0 +0x8EA2A2E9 0x7F51 # 0 +0x8EA2A2EA 0x8278 # 0 +0x8EA2A2EB 0x827C # 0 +0x8EA2A2EC 0x8280 # 0 +0x8EA2A2ED 0x827D # 0 +0x8EA2A2EE 0x827F # 0 +0x8EA2A2EF 0x864D # 0 +0x8EA2A2F0 0x897E # 0 +0x8EA2A2F1 0x9099 # 0 +0x8EA2A2F2 0x9097 # 0 +0x8EA2A2F3 0x9098 # 0 +0x8EA2A2F4 0x909B # 0 +0x8EA2A2F5 0x9094 # 0 +0x8EA2A2F6 0x9622 # 0 +0x8EA2A2F7 0x9624 # 0 +0x8EA2A2F8 0x9620 # 0 +0x8EA2A2F9 0x9623 # 0 +0x8EA2A2FA 0x4F56 # 0 +0x8EA2A2FB 0x4F3B # 0 +0x8EA2A2FC 0x4F62 # 0 +0x8EA2A2FD 0x4F49 # 0 +0x8EA2A2FE 0x4F53 # 0 +0x8EA2A3A1 0x4F64 # 0 +0x8EA2A3A2 0x4F3E # 0 +0x8EA2A3A3 0x4F67 # 0 +0x8EA2A3A4 0x4F52 # 0 +0x8EA2A3A5 0x4F5F # 0 +0x8EA2A3A6 0x4F41 # 0 +0x8EA2A3A7 0x4F58 # 0 +0x8EA2A3A8 0x4F2D # 0 +0x8EA2A3A9 0x4F33 # 0 +0x8EA2A3AA 0x4F3F # 0 +0x8EA2A3AB 0x4F61 # 0 +0x8EA2A3AC 0x518F # 0 +0x8EA2A3AD 0x51B9 # 0 +0x8EA2A3AE 0x521C # 0 +0x8EA2A3AF 0x521E # 0 +0x8EA2A3B0 0x5221 # 0 +0x8EA2A3B1 0x52AD # 0 +0x8EA2A3B2 0x52AE # 0 +0x8EA2A3B3 0x5309 # 0 +0x8EA2A3B4 0x5363 # 0 +0x8EA2A3B5 0x5372 # 0 +0x8EA2A3B6 0x538E # 0 +0x8EA2A3B7 0x538F # 0 +0x8EA2A3B8 0x5430 # 0 +0x8EA2A3B9 0x5437 # 0 +0x8EA2A3BA 0x542A # 0 +0x8EA2A3BB 0x5454 # 0 +0x8EA2A3BC 0x5445 # 0 +0x8EA2A3BD 0x5419 # 0 +0x8EA2A3BE 0x541C # 0 +0x8EA2A3BF 0x5425 # 0 +0x8EA2A3C0 0x5418 # 0 +0x8EA2A3C1 0x543D # 0 +0x8EA2A3C2 0x544F # 0 +0x8EA2A3C3 0x5441 # 0 +0x8EA2A3C4 0x5428 # 0 +0x8EA2A3C5 0x5424 # 0 +0x8EA2A3C6 0x5447 # 0 +0x8EA2A3C7 0x56EE # 0 +0x8EA2A3C8 0x56E7 # 0 +0x8EA2A3C9 0x56E5 # 0 +0x8EA2A3CA 0x5741 # 0 +0x8EA2A3CB 0x5745 # 0 +0x8EA2A3CC 0x574C # 0 +0x8EA2A3CD 0x5749 # 0 +0x8EA2A3CE 0x574B # 0 +0x8EA2A3CF 0x5752 # 0 +0x8EA2A3D0 0x5906 # 0 +0x8EA2A3D1 0x5940 # 0 +0x8EA2A3D2 0x59A6 # 0 +0x8EA2A3D3 0x5998 # 0 +0x8EA2A3D4 0x59A0 # 0 +0x8EA2A3D5 0x5997 # 0 +0x8EA2A3D6 0x598E # 0 +0x8EA2A3D7 0x59A2 # 0 +0x8EA2A3D8 0x5990 # 0 +0x8EA2A3D9 0x598F # 0 +0x8EA2A3DA 0x59A7 # 0 +0x8EA2A3DB 0x59A1 # 0 +0x8EA2A3DC 0x5B8E # 0 +0x8EA2A3DD 0x5B92 # 0 +0x8EA2A3DE 0x5C28 # 0 +0x8EA2A3DF 0x5C2A # 0 +0x8EA2A3E0 0x5C8D # 0 +0x8EA2A3E1 0x5C8F # 0 +0x8EA2A3E2 0x5C88 # 0 +0x8EA2A3E3 0x5C8B # 0 +0x8EA2A3E4 0x5C89 # 0 +0x8EA2A3E5 0x5C92 # 0 +0x8EA2A3E6 0x5C8A # 0 +0x8EA2A3E7 0x5C86 # 0 +0x8EA2A3E8 0x5C93 # 0 +0x8EA2A3E9 0x5C95 # 0 +0x8EA2A3EA 0x5DE0 # 0 +0x8EA2A3EB 0x5E0A # 0 +0x8EA2A3EC 0x5E0E # 0 +0x8EA2A3ED 0x5E8B # 0 +0x8EA2A3EE 0x5E89 # 0 +0x8EA2A3EF 0x5E8C # 0 +0x8EA2A3F0 0x5E88 # 0 +0x8EA2A3F1 0x5E8D # 0 +0x8EA2A3F2 0x5F05 # 0 +0x8EA2A3F3 0x5F1D # 0 +0x8EA2A3F4 0x5F78 # 0 +0x8EA2A3F5 0x5F76 # 0 +0x8EA2A3F6 0x5FD2 # 0 +0x8EA2A3F7 0x5FD1 # 0 +0x8EA2A3F8 0x5FD0 # 0 +0x8EA2A3F9 0x5FED # 0 +0x8EA2A3FA 0x5FE8 # 0 +0x8EA2A3FB 0x5FEE # 0 +0x8EA2A3FC 0x5FF3 # 0 +0x8EA2A3FD 0x5FE1 # 0 +0x8EA2A3FE 0x5FE4 # 0 +0x8EA2A4A1 0x5FE3 # 0 +0x8EA2A4A2 0x5FFA # 0 +0x8EA2A4A3 0x5FEF # 0 +0x8EA2A4A4 0x5FF7 # 0 +0x8EA2A4A5 0x5FFB # 0 +0x8EA2A4A6 0x6000 # 0 +0x8EA2A4A7 0x5FF4 # 0 +0x8EA2A4A8 0x623A # 0 +0x8EA2A4A9 0x6283 # 0 +0x8EA2A4AA 0x628C # 0 +0x8EA2A4AB 0x628E # 0 +0x8EA2A4AC 0x628F # 0 +0x8EA2A4AD 0x6294 # 0 +0x8EA2A4AE 0x6287 # 0 +0x8EA2A4AF 0x6271 # 0 +0x8EA2A4B0 0x627B # 0 +0x8EA2A4B1 0x627A # 0 +0x8EA2A4B2 0x6270 # 0 +0x8EA2A4B3 0x6281 # 0 +0x8EA2A4B4 0x6288 # 0 +0x8EA2A4B5 0x6277 # 0 +0x8EA2A4B6 0x627D # 0 +0x8EA2A4B7 0x6272 # 0 +0x8EA2A4B8 0x6274 # 0 +0x8EA2A4B9 0x65F0 # 0 +0x8EA2A4BA 0x65F4 # 0 +0x8EA2A4BB 0x65F3 # 0 +0x8EA2A4BC 0x65F2 # 0 +0x8EA2A4BD 0x65F5 # 0 +0x8EA2A4BE 0x6745 # 0 +0x8EA2A4BF 0x6747 # 0 +0x8EA2A4C0 0x6759 # 0 +0x8EA2A4C1 0x6755 # 0 +0x8EA2A4C2 0x674C # 0 +0x8EA2A4C3 0x6748 # 0 +0x8EA2A4C4 0x675D # 0 +0x8EA2A4C5 0x674D # 0 +0x8EA2A4C6 0x675A # 0 +0x8EA2A4C7 0x674B # 0 +0x8EA2A4C8 0x6BD0 # 0 +0x8EA2A4C9 0x6C19 # 0 +0x8EA2A4CA 0x6C1A # 0 +0x8EA2A4CB 0x6C78 # 0 +0x8EA2A4CC 0x6C67 # 0 +0x8EA2A4CD 0x6C6B # 0 +0x8EA2A4CE 0x6C84 # 0 +0x8EA2A4CF 0x6C8B # 0 +0x8EA2A4D0 0x6C8F # 0 +0x8EA2A4D1 0x6C71 # 0 +0x8EA2A4D2 0x6C6F # 0 +0x8EA2A4D3 0x6C69 # 0 +0x8EA2A4D4 0x6C9A # 0 +0x8EA2A4D5 0x6C6D # 0 +0x8EA2A4D6 0x6C87 # 0 +0x8EA2A4D7 0x6C95 # 0 +0x8EA2A4D8 0x6C9C # 0 +0x8EA2A4D9 0x6C66 # 0 +0x8EA2A4DA 0x6C73 # 0 +0x8EA2A4DB 0x6C65 # 0 +0x8EA2A4DC 0x6C7B # 0 +0x8EA2A4DD 0x6C8E # 0 +0x8EA2A4DE 0x7074 # 0 +0x8EA2A4DF 0x707A # 0 +0x8EA2A4E0 0x7263 # 0 +0x8EA2A4E1 0x72BF # 0 +0x8EA2A4E2 0x72BD # 0 +0x8EA2A4E3 0x72C3 # 0 +0x8EA2A4E4 0x72C6 # 0 +0x8EA2A4E5 0x72C1 # 0 +0x8EA2A4E6 0x72BA # 0 +0x8EA2A4E7 0x72C5 # 0 +0x8EA2A4E8 0x7395 # 0 +0x8EA2A4E9 0x7397 # 0 +0x8EA2A4EA 0x7393 # 0 +0x8EA2A4EB 0x7394 # 0 +0x8EA2A4EC 0x7392 # 0 +0x8EA2A4ED 0x753A # 0 +0x8EA2A4EE 0x7539 # 0 +0x8EA2A4EF 0x7594 # 0 +0x8EA2A4F0 0x7595 # 0 +0x8EA2A4F1 0x7681 # 0 +0x8EA2A4F2 0x793D # 0 +0x8EA2A4F3 0x8034 # 0 +0x8EA2A4F4 0x8095 # 0 +0x8EA2A4F5 0x8099 # 0 +0x8EA2A4F6 0x8090 # 0 +0x8EA2A4F7 0x8092 # 0 +0x8EA2A4F8 0x809C # 0 +0x8EA2A4F9 0x8290 # 0 +0x8EA2A4FA 0x828F # 0 +0x8EA2A4FB 0x8285 # 0 +0x8EA2A4FC 0x828E # 0 +0x8EA2A4FD 0x8291 # 0 +0x8EA2A4FE 0x8293 # 0 +0x8EA2A5A1 0x828A # 0 +0x8EA2A5A2 0x8283 # 0 +0x8EA2A5A3 0x8284 # 0 +0x8EA2A5A4 0x8C78 # 0 +0x8EA2A5A5 0x8FC9 # 0 +0x8EA2A5A6 0x8FBF # 0 +0x8EA2A5A7 0x909F # 0 +0x8EA2A5A8 0x90A1 # 0 +0x8EA2A5A9 0x90A5 # 0 +0x8EA2A5AA 0x909E # 0 +0x8EA2A5AB 0x90A7 # 0 +0x8EA2A5AC 0x90A0 # 0 +0x8EA2A5AD 0x9630 # 0 +0x8EA2A5AE 0x9628 # 0 +0x8EA2A5AF 0x962F # 0 +0x8EA2A5B0 0x962D # 0 +0x8EA2A5B1 0x4E33 # 0 +0x8EA2A5B2 0x4F98 # 0 +0x8EA2A5B3 0x4F7C # 0 +0x8EA2A5B4 0x4F85 # 0 +0x8EA2A5B5 0x4F7D # 0 +0x8EA2A5B6 0x4F80 # 0 +0x8EA2A5B7 0x4F87 # 0 +0x8EA2A5B8 0x4F76 # 0 +0x8EA2A5B9 0x4F74 # 0 +0x8EA2A5BA 0x4F89 # 0 +0x8EA2A5BB 0x4F84 # 0 +0x8EA2A5BC 0x4F77 # 0 +0x8EA2A5BD 0x4F4C # 0 +0x8EA2A5BE 0x4F97 # 0 +0x8EA2A5BF 0x4F6A # 0 +0x8EA2A5C0 0x4F9A # 0 +0x8EA2A5C1 0x4F79 # 0 +0x8EA2A5C2 0x4F81 # 0 +0x8EA2A5C3 0x4F78 # 0 +0x8EA2A5C4 0x4F90 # 0 +0x8EA2A5C5 0x4F9C # 0 +0x8EA2A5C6 0x4F94 # 0 +0x8EA2A5C7 0x4F9E # 0 +0x8EA2A5C8 0x4F92 # 0 +0x8EA2A5C9 0x4F82 # 0 +0x8EA2A5CA 0x4F95 # 0 +0x8EA2A5CB 0x4F6B # 0 +0x8EA2A5CC 0x4F6E # 0 +0x8EA2A5CD 0x519E # 0 +0x8EA2A5CE 0x51BC # 0 +0x8EA2A5CF 0x51BE # 0 +0x8EA2A5D0 0x5235 # 0 +0x8EA2A5D1 0x5232 # 0 +0x8EA2A5D2 0x5233 # 0 +0x8EA2A5D3 0x5246 # 0 +0x8EA2A5D4 0x5231 # 0 +0x8EA2A5D5 0x52BC # 0 +0x8EA2A5D6 0x530A # 0 +0x8EA2A5D7 0x530B # 0 +0x8EA2A5D8 0x533C # 0 +0x8EA2A5D9 0x5392 # 0 +0x8EA2A5DA 0x5394 # 0 +0x8EA2A5DB 0x5487 # 0 +0x8EA2A5DC 0x547F # 0 +0x8EA2A5DD 0x5481 # 0 +0x8EA2A5DE 0x5491 # 0 +0x8EA2A5DF 0x5482 # 0 +0x8EA2A5E0 0x5488 # 0 +0x8EA2A5E1 0x546B # 0 +0x8EA2A5E2 0x547A # 0 +0x8EA2A5E3 0x547E # 0 +0x8EA2A5E4 0x5465 # 0 +0x8EA2A5E5 0x546C # 0 +0x8EA2A5E6 0x5474 # 0 +0x8EA2A5E7 0x5466 # 0 +0x8EA2A5E8 0x548D # 0 +0x8EA2A5E9 0x546F # 0 +0x8EA2A5EA 0x5461 # 0 +0x8EA2A5EB 0x5460 # 0 +0x8EA2A5EC 0x5498 # 0 +0x8EA2A5ED 0x5463 # 0 +0x8EA2A5EE 0x5467 # 0 +0x8EA2A5EF 0x5464 # 0 +0x8EA2A5F0 0x56F7 # 0 +0x8EA2A5F1 0x56F9 # 0 +0x8EA2A5F2 0x576F # 0 +0x8EA2A5F3 0x5772 # 0 +0x8EA2A5F4 0x576D # 0 +0x8EA2A5F5 0x576B # 0 +0x8EA2A5F6 0x5771 # 0 +0x8EA2A5F7 0x5770 # 0 +0x8EA2A5F8 0x5776 # 0 +0x8EA2A5F9 0x5780 # 0 +0x8EA2A5FA 0x5775 # 0 +0x8EA2A5FB 0x577B # 0 +0x8EA2A5FC 0x5773 # 0 +0x8EA2A5FD 0x5774 # 0 +0x8EA2A5FE 0x5762 # 0 +0x8EA2A6A1 0x5768 # 0 +0x8EA2A6A2 0x577D # 0 +0x8EA2A6A3 0x590C # 0 +0x8EA2A6A4 0x5945 # 0 +0x8EA2A6A5 0x59B5 # 0 +0x8EA2A6A6 0x59BA # 0 +0x8EA2A6A7 0x59CF # 0 +0x8EA2A6A8 0x59CE # 0 +0x8EA2A6A9 0x59B2 # 0 +0x8EA2A6AA 0x59CC # 0 +0x8EA2A6AB 0x59C1 # 0 +0x8EA2A6AC 0x59B6 # 0 +0x8EA2A6AD 0x59BC # 0 +0x8EA2A6AE 0x59C3 # 0 +0x8EA2A6AF 0x59D6 # 0 +0x8EA2A6B0 0x59B1 # 0 +0x8EA2A6B1 0x59BD # 0 +0x8EA2A6B2 0x59C0 # 0 +0x8EA2A6B3 0x59C8 # 0 +0x8EA2A6B4 0x59B4 # 0 +0x8EA2A6B5 0x59C7 # 0 +0x8EA2A6B6 0x5B62 # 0 +0x8EA2A6B7 0x5B65 # 0 +0x8EA2A6B8 0x5B93 # 0 +0x8EA2A6B9 0x5B95 # 0 +0x8EA2A6BA 0x5C44 # 0 +0x8EA2A6BB 0x5C47 # 0 +0x8EA2A6BC 0x5CAE # 0 +0x8EA2A6BD 0x5CA4 # 0 +0x8EA2A6BE 0x5CA0 # 0 +0x8EA2A6BF 0x5CB5 # 0 +0x8EA2A6C0 0x5CAF # 0 +0x8EA2A6C1 0x5CA8 # 0 +0x8EA2A6C2 0x5CAC # 0 +0x8EA2A6C3 0x5C9F # 0 +0x8EA2A6C4 0x5CA3 # 0 +0x8EA2A6C5 0x5CAD # 0 +0x8EA2A6C6 0x5CA2 # 0 +0x8EA2A6C7 0x5CAA # 0 +0x8EA2A6C8 0x5CA7 # 0 +0x8EA2A6C9 0x5C9D # 0 +0x8EA2A6CA 0x5CA5 # 0 +0x8EA2A6CB 0x5CB6 # 0 +0x8EA2A6CC 0x5CB0 # 0 +0x8EA2A6CD 0x5CA6 # 0 +0x8EA2A6CE 0x5E17 # 0 +0x8EA2A6CF 0x5E14 # 0 +0x8EA2A6D0 0x5E19 # 0 +0x8EA2A6D1 0x5F28 # 0 +0x8EA2A6D2 0x5F22 # 0 +0x8EA2A6D3 0x5F23 # 0 +0x8EA2A6D4 0x5F24 # 0 +0x8EA2A6D5 0x5F54 # 0 +0x8EA2A6D6 0x5F82 # 0 +0x8EA2A6D7 0x5F7E # 0 +0x8EA2A6D8 0x5F7D # 0 +0x8EA2A6D9 0x5FDE # 0 +0x8EA2A6DA 0x5FE5 # 0 +0x8EA2A6DB 0x602D # 0 +0x8EA2A6DC 0x6026 # 0 +0x8EA2A6DD 0x6019 # 0 +0x8EA2A6DE 0x6032 # 0 +0x8EA2A6DF 0x600B # 0 +0x8EA2A6E0 0x6034 # 0 +0x8EA2A6E1 0x600A # 0 +0x8EA2A6E2 0x6017 # 0 +0x8EA2A6E3 0x6033 # 0 +0x8EA2A6E4 0x601A # 0 +0x8EA2A6E5 0x601E # 0 +0x8EA2A6E6 0x602C # 0 +0x8EA2A6E7 0x6022 # 0 +0x8EA2A6E8 0x600D # 0 +0x8EA2A6E9 0x6010 # 0 +0x8EA2A6EA 0x602E # 0 +0x8EA2A6EB 0x6013 # 0 +0x8EA2A6EC 0x6011 # 0 +0x8EA2A6ED 0x600C # 0 +0x8EA2A6EE 0x6009 # 0 +0x8EA2A6EF 0x601C # 0 +0x8EA2A6F0 0x6214 # 0 +0x8EA2A6F1 0x623D # 0 +0x8EA2A6F2 0x62AD # 0 +0x8EA2A6F3 0x62B4 # 0 +0x8EA2A6F4 0x62D1 # 0 +0x8EA2A6F5 0x62BE # 0 +0x8EA2A6F6 0x62AA # 0 +0x8EA2A6F7 0x62B6 # 0 +0x8EA2A6F8 0x62CA # 0 +0x8EA2A6F9 0x62AE # 0 +0x8EA2A6FA 0x62B3 # 0 +0x8EA2A6FB 0x62AF # 0 +0x8EA2A6FC 0x62BB # 0 +0x8EA2A6FD 0x62A9 # 0 +0x8EA2A6FE 0x62B0 # 0 +0x8EA2A7A1 0x62B8 # 0 +0x8EA2A7A2 0x653D # 0 +0x8EA2A7A3 0x65A8 # 0 +0x8EA2A7A4 0x65BB # 0 +0x8EA2A7A5 0x6609 # 0 +0x8EA2A7A6 0x65FC # 0 +0x8EA2A7A7 0x6604 # 0 +0x8EA2A7A8 0x6612 # 0 +0x8EA2A7A9 0x6608 # 0 +0x8EA2A7AA 0x65FB # 0 +0x8EA2A7AB 0x6603 # 0 +0x8EA2A7AC 0x660B # 0 +0x8EA2A7AD 0x660D # 0 +0x8EA2A7AE 0x6605 # 0 +0x8EA2A7AF 0x65FD # 0 +0x8EA2A7B0 0x6611 # 0 +0x8EA2A7B1 0x6610 # 0 +0x8EA2A7B2 0x66F6 # 0 +0x8EA2A7B3 0x670A # 0 +0x8EA2A7B4 0x6785 # 0 +0x8EA2A7B5 0x676C # 0 +0x8EA2A7B6 0x678E # 0 +0x8EA2A7B7 0x6792 # 0 +0x8EA2A7B8 0x6776 # 0 +0x8EA2A7B9 0x677B # 0 +0x8EA2A7BA 0x6798 # 0 +0x8EA2A7BB 0x6786 # 0 +0x8EA2A7BC 0x6784 # 0 +0x8EA2A7BD 0x6774 # 0 +0x8EA2A7BE 0x678D # 0 +0x8EA2A7BF 0x678C # 0 +0x8EA2A7C0 0x677A # 0 +0x8EA2A7C1 0x679F # 0 +0x8EA2A7C2 0x6791 # 0 +0x8EA2A7C3 0x6799 # 0 +0x8EA2A7C4 0x6783 # 0 +0x8EA2A7C5 0x677D # 0 +0x8EA2A7C6 0x6781 # 0 +0x8EA2A7C7 0x6778 # 0 +0x8EA2A7C8 0x6779 # 0 +0x8EA2A7C9 0x6794 # 0 +0x8EA2A7CA 0x6B25 # 0 +0x8EA2A7CB 0x6B80 # 0 +0x8EA2A7CC 0x6B7E # 0 +0x8EA2A7CD 0x6BDE # 0 +0x8EA2A7CE 0x6C1D # 0 +0x8EA2A7CF 0x6C93 # 0 +0x8EA2A7D0 0x6CEC # 0 +0x8EA2A7D1 0x6CEB # 0 +0x8EA2A7D2 0x6CEE # 0 +0x8EA2A7D3 0x6CD9 # 0 +0x8EA2A7D4 0x6CB6 # 0 +0x8EA2A7D5 0x6CD4 # 0 +0x8EA2A7D6 0x6CAD # 0 +0x8EA2A7D7 0x6CE7 # 0 +0x8EA2A7D8 0x6CB7 # 0 +0x8EA2A7D9 0x6CD0 # 0 +0x8EA2A7DA 0x6CC2 # 0 +0x8EA2A7DB 0x6CBA # 0 +0x8EA2A7DC 0x6CC3 # 0 +0x8EA2A7DD 0x6CC6 # 0 +0x8EA2A7DE 0x6CED # 0 +0x8EA2A7DF 0x6CF2 # 0 +0x8EA2A7E0 0x6CD2 # 0 +0x8EA2A7E1 0x6CDD # 0 +0x8EA2A7E2 0x6CB4 # 0 +0x8EA2A7E3 0x6C8A # 0 +0x8EA2A7E4 0x6C9D # 0 +0x8EA2A7E5 0x6C80 # 0 +0x8EA2A7E6 0x6CDE # 0 +0x8EA2A7E7 0x6CC0 # 0 +0x8EA2A7E8 0x6D30 # 0 +0x8EA2A7E9 0x6CCD # 0 +0x8EA2A7EA 0x6CC7 # 0 +0x8EA2A7EB 0x6CB0 # 0 +0x8EA2A7EC 0x6CF9 # 0 +0x8EA2A7ED 0x6CCF # 0 +0x8EA2A7EE 0x6CE9 # 0 +0x8EA2A7EF 0x6CD1 # 0 +0x8EA2A7F0 0x7094 # 0 +0x8EA2A7F1 0x7098 # 0 +0x8EA2A7F2 0x7085 # 0 +0x8EA2A7F3 0x7093 # 0 +0x8EA2A7F4 0x7086 # 0 +0x8EA2A7F5 0x7084 # 0 +0x8EA2A7F6 0x7091 # 0 +0x8EA2A7F7 0x7096 # 0 +0x8EA2A7F8 0x7082 # 0 +0x8EA2A7F9 0x709A # 0 +0x8EA2A7FA 0x7083 # 0 +0x8EA2A7FB 0x726A # 0 +0x8EA2A7FC 0x72D6 # 0 +0x8EA2A7FD 0x72CB # 0 +0x8EA2A7FE 0x72D8 # 0 +0x8EA2A8A1 0x72C9 # 0 +0x8EA2A8A2 0x72DC # 0 +0x8EA2A8A3 0x72D2 # 0 +0x8EA2A8A4 0x72D4 # 0 +0x8EA2A8A5 0x72DA # 0 +0x8EA2A8A6 0x72CC # 0 +0x8EA2A8A7 0x72D1 # 0 +0x8EA2A8A8 0x73A4 # 0 +0x8EA2A8A9 0x73A1 # 0 +0x8EA2A8AA 0x73AD # 0 +0x8EA2A8AB 0x73A6 # 0 +0x8EA2A8AC 0x73A2 # 0 +0x8EA2A8AD 0x73A0 # 0 +0x8EA2A8AE 0x73AC # 0 +0x8EA2A8AF 0x739D # 0 +0x8EA2A8B0 0x74DD # 0 +0x8EA2A8B1 0x74E8 # 0 +0x8EA2A8B2 0x753F # 0 +0x8EA2A8B3 0x7540 # 0 +0x8EA2A8B4 0x753E # 0 +0x8EA2A8B5 0x758C # 0 +0x8EA2A8B6 0x7598 # 0 +0x8EA2A8B7 0x76AF # 0 +0x8EA2A8B8 0x76F3 # 0 +0x8EA2A8B9 0x76F1 # 0 +0x8EA2A8BA 0x76F0 # 0 +0x8EA2A8BB 0x76F5 # 0 +0x8EA2A8BC 0x77F8 # 0 +0x8EA2A8BD 0x77FC # 0 +0x8EA2A8BE 0x77F9 # 0 +0x8EA2A8BF 0x77FB # 0 +0x8EA2A8C0 0x77FA # 0 +0x8EA2A8C1 0x77F7 # 0 +0x8EA2A8C2 0x7942 # 0 +0x8EA2A8C3 0x793F # 0 +0x8EA2A8C4 0x79C5 # 0 +0x8EA2A8C5 0x7A78 # 0 +0x8EA2A8C6 0x7A7B # 0 +0x8EA2A8C7 0x7AFB # 0 +0x8EA2A8C8 0x7C75 # 0 +0x8EA2A8C9 0x7CFD # 0 +0x8EA2A8CA 0x8035 # 0 +0x8EA2A8CB 0x808F # 0 +0x8EA2A8CC 0x80AE # 0 +0x8EA2A8CD 0x80A3 # 0 +0x8EA2A8CE 0x80B8 # 0 +0x8EA2A8CF 0x80B5 # 0 +0x8EA2A8D0 0x80AD # 0 +0x8EA2A8D1 0x8220 # 0 +0x8EA2A8D2 0x82A0 # 0 +0x8EA2A8D3 0x82C0 # 0 +0x8EA2A8D4 0x82AB # 0 +0x8EA2A8D5 0x829A # 0 +0x8EA2A8D6 0x8298 # 0 +0x8EA2A8D7 0x829B # 0 +0x8EA2A8D8 0x82B5 # 0 +0x8EA2A8D9 0x82A7 # 0 +0x8EA2A8DA 0x82AE # 0 +0x8EA2A8DB 0x82BC # 0 +0x8EA2A8DC 0x829E # 0 +0x8EA2A8DD 0x82BA # 0 +0x8EA2A8DE 0x82B4 # 0 +0x8EA2A8DF 0x82A8 # 0 +0x8EA2A8E0 0x82A1 # 0 +0x8EA2A8E1 0x82A9 # 0 +0x8EA2A8E2 0x82C2 # 0 +0x8EA2A8E3 0x82A4 # 0 +0x8EA2A8E4 0x82C3 # 0 +0x8EA2A8E5 0x82B6 # 0 +0x8EA2A8E6 0x82A2 # 0 +0x8EA2A8E7 0x8670 # 0 +0x8EA2A8E8 0x866F # 0 +0x8EA2A8E9 0x866D # 0 +0x8EA2A8EA 0x866E # 0 +0x8EA2A8EB 0x8C56 # 0 +0x8EA2A8EC 0x8FD2 # 0 +0x8EA2A8ED 0x8FCB # 0 +0x8EA2A8EE 0x8FD3 # 0 +0x8EA2A8EF 0x8FCD # 0 +0x8EA2A8F0 0x8FD6 # 0 +0x8EA2A8F1 0x8FD5 # 0 +0x8EA2A8F2 0x8FD7 # 0 +0x8EA2A8F3 0x90B2 # 0 +0x8EA2A8F4 0x90B4 # 0 +0x8EA2A8F5 0x90AF # 0 +0x8EA2A8F6 0x90B3 # 0 +0x8EA2A8F7 0x90B0 # 0 +0x8EA2A8F8 0x9639 # 0 +0x8EA2A8F9 0x963D # 0 +0x8EA2A8FA 0x963C # 0 +0x8EA2A8FB 0x963A # 0 +0x8EA2A8FC 0x9643 # 0 +0x8EA2A8FD 0x4FCD # 0 +0x8EA2A8FE 0x4FC5 # 0 +0x8EA2A9A1 0x4FD3 # 0 +0x8EA2A9A2 0x4FB2 # 0 +0x8EA2A9A3 0x4FC9 # 0 +0x8EA2A9A4 0x4FCB # 0 +0x8EA2A9A5 0x4FC1 # 0 +0x8EA2A9A6 0x4FD4 # 0 +0x8EA2A9A7 0x4FDC # 0 +0x8EA2A9A8 0x4FD9 # 0 +0x8EA2A9A9 0x4FBB # 0 +0x8EA2A9AA 0x4FB3 # 0 +0x8EA2A9AB 0x4FDB # 0 +0x8EA2A9AC 0x4FC7 # 0 +0x8EA2A9AD 0x4FD6 # 0 +0x8EA2A9AE 0x4FBA # 0 +0x8EA2A9AF 0x4FC0 # 0 +0x8EA2A9B0 0x4FB9 # 0 +0x8EA2A9B1 0x4FEC # 0 +0x8EA2A9B2 0x5244 # 0 +0x8EA2A9B3 0x5249 # 0 +0x8EA2A9B4 0x52C0 # 0 +0x8EA2A9B5 0x52C2 # 0 +0x8EA2A9B6 0x533D # 0 +0x8EA2A9B7 0x537C # 0 +0x8EA2A9B8 0x5397 # 0 +0x8EA2A9B9 0x5396 # 0 +0x8EA2A9BA 0x5399 # 0 +0x8EA2A9BB 0x5398 # 0 +0x8EA2A9BC 0x54BA # 0 +0x8EA2A9BD 0x54A1 # 0 +0x8EA2A9BE 0x54AD # 0 +0x8EA2A9BF 0x54A5 # 0 +0x8EA2A9C0 0x54CF # 0 +0x8EA2A9C1 0x54C3 # 0 +0x8EA2A9C2 0x830D # 0 +0x8EA2A9C3 0x54B7 # 0 +0x8EA2A9C4 0x54AE # 0 +0x8EA2A9C5 0x54D6 # 0 +0x8EA2A9C6 0x54B6 # 0 +0x8EA2A9C7 0x54C5 # 0 +0x8EA2A9C8 0x54C6 # 0 +0x8EA2A9C9 0x54A0 # 0 +0x8EA2A9CA 0x5470 # 0 +0x8EA2A9CB 0x54BC # 0 +0x8EA2A9CC 0x54A2 # 0 +0x8EA2A9CD 0x54BE # 0 +0x8EA2A9CE 0x5472 # 0 +0x8EA2A9CF 0x54DE # 0 +0x8EA2A9D0 0x54B0 # 0 +0x8EA2A9D1 0x57B5 # 0 +0x8EA2A9D2 0x579E # 0 +0x8EA2A9D3 0x579F # 0 +0x8EA2A9D4 0x57A4 # 0 +0x8EA2A9D5 0x578C # 0 +0x8EA2A9D6 0x5797 # 0 +0x8EA2A9D7 0x579D # 0 +0x8EA2A9D8 0x579B # 0 +0x8EA2A9D9 0x5794 # 0 +0x8EA2A9DA 0x5798 # 0 +0x8EA2A9DB 0x578F # 0 +0x8EA2A9DC 0x5799 # 0 +0x8EA2A9DD 0x57A5 # 0 +0x8EA2A9DE 0x579A # 0 +0x8EA2A9DF 0x5795 # 0 +0x8EA2A9E0 0x58F4 # 0 +0x8EA2A9E1 0x590D # 0 +0x8EA2A9E2 0x5953 # 0 +0x8EA2A9E3 0x59E1 # 0 +0x8EA2A9E4 0x59DE # 0 +0x8EA2A9E5 0x59EE # 0 +0x8EA2A9E6 0x5A00 # 0 +0x8EA2A9E7 0x59F1 # 0 +0x8EA2A9E8 0x59DD # 0 +0x8EA2A9E9 0x59FA # 0 +0x8EA2A9EA 0x59FD # 0 +0x8EA2A9EB 0x59FC # 0 +0x8EA2A9EC 0x59F6 # 0 +0x8EA2A9ED 0x59E4 # 0 +0x8EA2A9EE 0x59F2 # 0 +0x8EA2A9EF 0x59F7 # 0 +0x8EA2A9F0 0x59DB # 0 +0x8EA2A9F1 0x59E9 # 0 +0x8EA2A9F2 0x59F3 # 0 +0x8EA2A9F3 0x59F5 # 0 +0x8EA2A9F4 0x59E0 # 0 +0x8EA2A9F5 0x59FE # 0 +0x8EA2A9F6 0x59F4 # 0 +0x8EA2A9F7 0x59ED # 0 +0x8EA2A9F8 0x5BA8 # 0 +0x8EA2A9F9 0x5C4C # 0 +0x8EA2A9FA 0x5CD0 # 0 +0x8EA2A9FB 0x5CD8 # 0 +0x8EA2A9FC 0x5CCC # 0 +0x8EA2A9FD 0x5CD7 # 0 +0x8EA2A9FE 0x5CCB # 0 +0x8EA2AAA1 0x5CDB # 0 +0x8EA2AAA2 0x5CDE # 0 +0x8EA2AAA3 0x5CDA # 0 +0x8EA2AAA4 0x5CC9 # 0 +0x8EA2AAA5 0x5CC7 # 0 +0x8EA2AAA6 0x5CCA # 0 +0x8EA2AAA7 0x5CD6 # 0 +0x8EA2AAA8 0x5CD3 # 0 +0x8EA2AAA9 0x5CD4 # 0 +0x8EA2AAAA 0x5CCF # 0 +0x8EA2AAAB 0x5CC8 # 0 +0x8EA2AAAC 0x5CC6 # 0 +0x8EA2AAAD 0x5CCE # 0 +0x8EA2AAAE 0x5CDF # 0 +0x8EA2AAAF 0x5CF8 # 0 +0x8EA2AAB0 0x5DF9 # 0 +0x8EA2AAB1 0x5E21 # 0 +0x8EA2AAB2 0x5E22 # 0 +0x8EA2AAB3 0x5E23 # 0 +0x8EA2AAB4 0x5E20 # 0 +0x8EA2AAB5 0x5E24 # 0 +0x8EA2AAB6 0x5EB0 # 0 +0x8EA2AAB7 0x5EA4 # 0 +0x8EA2AAB8 0x5EA2 # 0 +0x8EA2AAB9 0x5E9B # 0 +0x8EA2AABA 0x5EA3 # 0 +0x8EA2AABB 0x5EA5 # 0 +0x8EA2AABC 0x5F07 # 0 +0x8EA2AABD 0x5F2E # 0 +0x8EA2AABE 0x5F56 # 0 +0x8EA2AABF 0x5F86 # 0 +0x8EA2AAC0 0x6037 # 0 +0x8EA2AAC1 0x6039 # 0 +0x8EA2AAC2 0x6054 # 0 +0x8EA2AAC3 0x6072 # 0 +0x8EA2AAC4 0x605E # 0 +0x8EA2AAC5 0x6045 # 0 +0x8EA2AAC6 0x6053 # 0 +0x8EA2AAC7 0x6047 # 0 +0x8EA2AAC8 0x6049 # 0 +0x8EA2AAC9 0x605B # 0 +0x8EA2AACA 0x604C # 0 +0x8EA2AACB 0x6040 # 0 +0x8EA2AACC 0x6042 # 0 +0x8EA2AACD 0x605F # 0 +0x8EA2AACE 0x6024 # 0 +0x8EA2AACF 0x6044 # 0 +0x8EA2AAD0 0x6058 # 0 +0x8EA2AAD1 0x6066 # 0 +0x8EA2AAD2 0x606E # 0 +0x8EA2AAD3 0x6242 # 0 +0x8EA2AAD4 0x6243 # 0 +0x8EA2AAD5 0x62CF # 0 +0x8EA2AAD6 0x630D # 0 +0x8EA2AAD7 0x630B # 0 +0x8EA2AAD8 0x62F5 # 0 +0x8EA2AAD9 0x630E # 0 +0x8EA2AADA 0x6303 # 0 +0x8EA2AADB 0x62EB # 0 +0x8EA2AADC 0x62F9 # 0 +0x8EA2AADD 0x630F # 0 +0x8EA2AADE 0x630C # 0 +0x8EA2AADF 0x62F8 # 0 +0x8EA2AAE0 0x62F6 # 0 +0x8EA2AAE1 0x6300 # 0 +0x8EA2AAE2 0x6313 # 0 +0x8EA2AAE3 0x6314 # 0 +0x8EA2AAE4 0x62FA # 0 +0x8EA2AAE5 0x6315 # 0 +0x8EA2AAE6 0x62FB # 0 +0x8EA2AAE7 0x62F0 # 0 +0x8EA2AAE8 0x6541 # 0 +0x8EA2AAE9 0x6543 # 0 +0x8EA2AAEA 0x65AA # 0 +0x8EA2AAEB 0x65BF # 0 +0x8EA2AAEC 0x6636 # 0 +0x8EA2AAED 0x6621 # 0 +0x8EA2AAEE 0x6632 # 0 +0x8EA2AAEF 0x6635 # 0 +0x8EA2AAF0 0x661C # 0 +0x8EA2AAF1 0x6626 # 0 +0x8EA2AAF2 0x6622 # 0 +0x8EA2AAF3 0x6633 # 0 +0x8EA2AAF4 0x662B # 0 +0x8EA2AAF5 0x663A # 0 +0x8EA2AAF6 0x661D # 0 +0x8EA2AAF7 0x6634 # 0 +0x8EA2AAF8 0x6639 # 0 +0x8EA2AAF9 0x662E # 0 +0x8EA2AAFA 0x670F # 0 +0x8EA2AAFB 0x6710 # 0 +0x8EA2AAFC 0x67C1 # 0 +0x8EA2AAFD 0x67F2 # 0 +0x8EA2AAFE 0x67C8 # 0 +0x8EA2ABA1 0x67BA # 0 +0x8EA2ABA2 0x67DC # 0 +0x8EA2ABA3 0x67BB # 0 +0x8EA2ABA4 0x67F8 # 0 +0x8EA2ABA5 0x67D8 # 0 +0x8EA2ABA6 0x67C0 # 0 +0x8EA2ABA7 0x67B7 # 0 +0x8EA2ABA8 0x67C5 # 0 +0x8EA2ABA9 0x67EB # 0 +0x8EA2ABAA 0x67E4 # 0 +0x8EA2ABAB 0x67DF # 0 +0x8EA2ABAC 0x67B5 # 0 +0x8EA2ABAD 0x67CD # 0 +0x8EA2ABAE 0x67B3 # 0 +0x8EA2ABAF 0x67F7 # 0 +0x8EA2ABB0 0x67F6 # 0 +0x8EA2ABB1 0x67EE # 0 +0x8EA2ABB2 0x67E3 # 0 +0x8EA2ABB3 0x67C2 # 0 +0x8EA2ABB4 0x67B9 # 0 +0x8EA2ABB5 0x67CE # 0 +0x8EA2ABB6 0x67E7 # 0 +0x8EA2ABB7 0x67F0 # 0 +0x8EA2ABB8 0x67B2 # 0 +0x8EA2ABB9 0x67FC # 0 +0x8EA2ABBA 0x67C6 # 0 +0x8EA2ABBB 0x67ED # 0 +0x8EA2ABBC 0x67CC # 0 +0x8EA2ABBD 0x67AE # 0 +0x8EA2ABBE 0x67E6 # 0 +0x8EA2ABBF 0x67DB # 0 +0x8EA2ABC0 0x67FA # 0 +0x8EA2ABC1 0x67C9 # 0 +0x8EA2ABC2 0x67CA # 0 +0x8EA2ABC3 0x67C3 # 0 +0x8EA2ABC4 0x67EA # 0 +0x8EA2ABC5 0x67CB # 0 +0x8EA2ABC6 0x6B28 # 0 +0x8EA2ABC7 0x6B82 # 0 +0x8EA2ABC8 0x6B84 # 0 +0x8EA2ABC9 0x6BB6 # 0 +0x8EA2ABCA 0x6BD6 # 0 +0x8EA2ABCB 0x6BD8 # 0 +0x8EA2ABCC 0x6BE0 # 0 +0x8EA2ABCD 0x6C20 # 0 +0x8EA2ABCE 0x6C21 # 0 +0x8EA2ABCF 0x6D28 # 0 +0x8EA2ABD0 0x6D34 # 0 +0x8EA2ABD1 0x6D2D # 0 +0x8EA2ABD2 0x6D1F # 0 +0x8EA2ABD3 0x6D3C # 0 +0x8EA2ABD4 0x6D3F # 0 +0x8EA2ABD5 0x6D12 # 0 +0x8EA2ABD6 0x6D0A # 0 +0x8EA2ABD7 0x6CDA # 0 +0x8EA2ABD8 0x6D33 # 0 +0x8EA2ABD9 0x6D04 # 0 +0x8EA2ABDA 0x6D19 # 0 +0x8EA2ABDB 0x6D3A # 0 +0x8EA2ABDC 0x6D1A # 0 +0x8EA2ABDD 0x6D11 # 0 +0x8EA2ABDE 0x6D00 # 0 +0x8EA2ABDF 0x6D1D # 0 +0x8EA2ABE0 0x6D42 # 0 +0x8EA2ABE1 0x6D01 # 0 +0x8EA2ABE2 0x6D18 # 0 +0x8EA2ABE3 0x6D37 # 0 +0x8EA2ABE4 0x6D03 # 0 +0x8EA2ABE5 0x6D0F # 0 +0x8EA2ABE6 0x6D40 # 0 +0x8EA2ABE7 0x6D07 # 0 +0x8EA2ABE8 0x6D20 # 0 +0x8EA2ABE9 0x6D2C # 0 +0x8EA2ABEA 0x6D08 # 0 +0x8EA2ABEB 0x6D22 # 0 +0x8EA2ABEC 0x6D09 # 0 +0x8EA2ABED 0x6D10 # 0 +0x8EA2ABEE 0x70B7 # 0 +0x8EA2ABEF 0x709F # 0 +0x8EA2ABF0 0x70BE # 0 +0x8EA2ABF1 0x70B1 # 0 +0x8EA2ABF2 0x70B0 # 0 +0x8EA2ABF3 0x70A1 # 0 +0x8EA2ABF4 0x70B4 # 0 +0x8EA2ABF5 0x70B5 # 0 +0x8EA2ABF6 0x70A9 # 0 +0x8EA2ABF7 0x7241 # 0 +0x8EA2ABF8 0x7249 # 0 +0x8EA2ABF9 0x724A # 0 +0x8EA2ABFA 0x726C # 0 +0x8EA2ABFB 0x7270 # 0 +0x8EA2ABFC 0x7273 # 0 +0x8EA2ABFD 0x726E # 0 +0x8EA2ABFE 0x72CA # 0 +0x8EA2ACA1 0x72E4 # 0 +0x8EA2ACA2 0x72E8 # 0 +0x8EA2ACA3 0x72EB # 0 +0x8EA2ACA4 0x72DF # 0 +0x8EA2ACA5 0x72EA # 0 +0x8EA2ACA6 0x72E6 # 0 +0x8EA2ACA7 0x72E3 # 0 +0x8EA2ACA8 0x7385 # 0 +0x8EA2ACA9 0x73CC # 0 +0x8EA2ACAA 0x73C2 # 0 +0x8EA2ACAB 0x73C8 # 0 +0x8EA2ACAC 0x73C5 # 0 +0x8EA2ACAD 0x73B9 # 0 +0x8EA2ACAE 0x73B6 # 0 +0x8EA2ACAF 0x73B5 # 0 +0x8EA2ACB0 0x73B4 # 0 +0x8EA2ACB1 0x73EB # 0 +0x8EA2ACB2 0x73BF # 0 +0x8EA2ACB3 0x73C7 # 0 +0x8EA2ACB4 0x73BE # 0 +0x8EA2ACB5 0x73C3 # 0 +0x8EA2ACB6 0x73C6 # 0 +0x8EA2ACB7 0x73B8 # 0 +0x8EA2ACB8 0x73CB # 0 +0x8EA2ACB9 0x74EC # 0 +0x8EA2ACBA 0x74EE # 0 +0x8EA2ACBB 0x752E # 0 +0x8EA2ACBC 0x7547 # 0 +0x8EA2ACBD 0x7548 # 0 +0x8EA2ACBE 0x75A7 # 0 +0x8EA2ACBF 0x75AA # 0 +0x8EA2ACC0 0x7679 # 0 +0x8EA2ACC1 0x76C4 # 0 +0x8EA2ACC2 0x7708 # 0 +0x8EA2ACC3 0x7703 # 0 +0x8EA2ACC4 0x7704 # 0 +0x8EA2ACC5 0x7705 # 0 +0x8EA2ACC6 0x770A # 0 +0x8EA2ACC7 0x76F7 # 0 +0x8EA2ACC8 0x76FB # 0 +0x8EA2ACC9 0x76FA # 0 +0x8EA2ACCA 0x77E7 # 0 +0x8EA2ACCB 0x77E8 # 0 +0x8EA2ACCC 0x7806 # 0 +0x8EA2ACCD 0x7811 # 0 +0x8EA2ACCE 0x7812 # 0 +0x8EA2ACCF 0x7805 # 0 +0x8EA2ACD0 0x7810 # 0 +0x8EA2ACD1 0x780F # 0 +0x8EA2ACD2 0x780E # 0 +0x8EA2ACD3 0x7809 # 0 +0x8EA2ACD4 0x7803 # 0 +0x8EA2ACD5 0x7813 # 0 +0x8EA2ACD6 0x794A # 0 +0x8EA2ACD7 0x794C # 0 +0x8EA2ACD8 0x794B # 0 +0x8EA2ACD9 0x7945 # 0 +0x8EA2ACDA 0x7944 # 0 +0x8EA2ACDB 0x79D5 # 0 +0x8EA2ACDC 0x79CD # 0 +0x8EA2ACDD 0x79CF # 0 +0x8EA2ACDE 0x79D6 # 0 +0x8EA2ACDF 0x79CE # 0 +0x8EA2ACE0 0x7A80 # 0 +0x8EA2ACE1 0x7A7E # 0 +0x8EA2ACE2 0x7AD1 # 0 +0x8EA2ACE3 0x7B00 # 0 +0x8EA2ACE4 0x7B01 # 0 +0x8EA2ACE5 0x7C7A # 0 +0x8EA2ACE6 0x7C78 # 0 +0x8EA2ACE7 0x7C79 # 0 +0x8EA2ACE8 0x7C7F # 0 +0x8EA2ACE9 0x7C80 # 0 +0x8EA2ACEA 0x7C81 # 0 +0x8EA2ACEB 0x7D03 # 0 +0x8EA2ACEC 0x7D08 # 0 +0x8EA2ACED 0x7D01 # 0 +0x8EA2ACEE 0x7F58 # 0 +0x8EA2ACEF 0x7F91 # 0 +0x8EA2ACF0 0x7F8D # 0 +0x8EA2ACF1 0x7FBE # 0 +0x8EA2ACF2 0x8007 # 0 +0x8EA2ACF3 0x800E # 0 +0x8EA2ACF4 0x800F # 0 +0x8EA2ACF5 0x8014 # 0 +0x8EA2ACF6 0x8037 # 0 +0x8EA2ACF7 0x80D8 # 0 +0x8EA2ACF8 0x80C7 # 0 +0x8EA2ACF9 0x80E0 # 0 +0x8EA2ACFA 0x80D1 # 0 +0x8EA2ACFB 0x80C8 # 0 +0x8EA2ACFC 0x80C2 # 0 +0x8EA2ACFD 0x80D0 # 0 +0x8EA2ACFE 0x80C5 # 0 +0x8EA2ADA1 0x80E3 # 0 +0x8EA2ADA2 0x80D9 # 0 +0x8EA2ADA3 0x80DC # 0 +0x8EA2ADA4 0x80CA # 0 +0x8EA2ADA5 0x80D5 # 0 +0x8EA2ADA6 0x80C9 # 0 +0x8EA2ADA7 0x80CF # 0 +0x8EA2ADA8 0x80D7 # 0 +0x8EA2ADA9 0x80E6 # 0 +0x8EA2ADAA 0x80CD # 0 +0x8EA2ADAB 0x81FF # 0 +0x8EA2ADAC 0x8221 # 0 +0x8EA2ADAD 0x8294 # 0 +0x8EA2ADAE 0x82D9 # 0 +0x8EA2ADAF 0x82FE # 0 +0x8EA2ADB0 0x82F9 # 0 +0x8EA2ADB1 0x8307 # 0 +0x8EA2ADB2 0x82E8 # 0 +0x8EA2ADB3 0x8300 # 0 +0x8EA2ADB4 0x82D5 # 0 +0x8EA2ADB5 0x833A # 0 +0x8EA2ADB6 0x82EB # 0 +0x8EA2ADB7 0x82D6 # 0 +0x8EA2ADB8 0x82F4 # 0 +0x8EA2ADB9 0x82EC # 0 +0x8EA2ADBA 0x82E1 # 0 +0x8EA2ADBB 0x82F2 # 0 +0x8EA2ADBC 0x82F5 # 0 +0x8EA2ADBD 0x830C # 0 +0x8EA2ADBE 0x82FB # 0 +0x8EA2ADBF 0x82F6 # 0 +0x8EA2ADC0 0x82F0 # 0 +0x8EA2ADC1 0x82EA # 0 +0x8EA2ADC2 0x82E4 # 0 +0x8EA2ADC3 0x82E0 # 0 +0x8EA2ADC4 0x82FA # 0 +0x8EA2ADC5 0x82F3 # 0 +0x8EA2ADC6 0x82ED # 0 +0x8EA2ADC7 0x8677 # 0 +0x8EA2ADC8 0x8674 # 0 +0x8EA2ADC9 0x867C # 0 +0x8EA2ADCA 0x8673 # 0 +0x8EA2ADCB 0x8841 # 0 +0x8EA2ADCC 0x884E # 0 +0x8EA2ADCD 0x8867 # 0 +0x8EA2ADCE 0x886A # 0 +0x8EA2ADCF 0x8869 # 0 +0x8EA2ADD0 0x89D3 # 0 +0x8EA2ADD1 0x8A04 # 0 +0x8EA2ADD2 0x8A07 # 0 +0x8EA2ADD3 0x8D72 # 0 +0x8EA2ADD4 0x8FE3 # 0 +0x8EA2ADD5 0x8FE1 # 0 +0x8EA2ADD6 0x8FEE # 0 +0x8EA2ADD7 0x8FE0 # 0 +0x8EA2ADD8 0x90F1 # 0 +0x8EA2ADD9 0x90BD # 0 +0x8EA2ADDA 0x90BF # 0 +0x8EA2ADDB 0x90D5 # 0 +0x8EA2ADDC 0x90C5 # 0 +0x8EA2ADDD 0x90BE # 0 +0x8EA2ADDE 0x90C7 # 0 +0x8EA2ADDF 0x90CB # 0 +0x8EA2ADE0 0x90C8 # 0 +0x8EA2ADE1 0x91D4 # 0 +0x8EA2ADE2 0x91D3 # 0 +0x8EA2ADE3 0x9654 # 0 +0x8EA2ADE4 0x964F # 0 +0x8EA2ADE5 0x9651 # 0 +0x8EA2ADE6 0x9653 # 0 +0x8EA2ADE7 0x964A # 0 +0x8EA2ADE8 0x964E # 0 +0x8EA2ADE9 0x501E # 0 +0x8EA2ADEA 0x5005 # 0 +0x8EA2ADEB 0x5007 # 0 +0x8EA2ADEC 0x5013 # 0 +0x8EA2ADED 0x5022 # 0 +0x8EA2ADEE 0x5030 # 0 +0x8EA2ADEF 0x501B # 0 +0x8EA2ADF0 0x4FF5 # 0 +0x8EA2ADF1 0x4FF4 # 0 +0x8EA2ADF2 0x5033 # 0 +0x8EA2ADF3 0x5037 # 0 +0x8EA2ADF4 0x502C # 0 +0x8EA2ADF5 0x4FF6 # 0 +0x8EA2ADF6 0x4FF7 # 0 +0x8EA2ADF7 0x5017 # 0 +0x8EA2ADF8 0x501C # 0 +0x8EA2ADF9 0x5020 # 0 +0x8EA2ADFA 0x5027 # 0 +0x8EA2ADFB 0x5035 # 0 +0x8EA2ADFC 0x502F # 0 +0x8EA2ADFD 0x5031 # 0 +0x8EA2ADFE 0x500E # 0 +0x8EA2AEA1 0x515A # 0 +0x8EA2AEA2 0x5194 # 0 +0x8EA2AEA3 0x5193 # 0 +0x8EA2AEA4 0x51CA # 0 +0x8EA2AEA5 0x51C4 # 0 +0x8EA2AEA6 0x51C5 # 0 +0x8EA2AEA7 0x51C8 # 0 +0x8EA2AEA8 0x51CE # 0 +0x8EA2AEA9 0x5261 # 0 +0x8EA2AEAA 0x525A # 0 +0x8EA2AEAB 0x5252 # 0 +0x8EA2AEAC 0x525E # 0 +0x8EA2AEAD 0x525F # 0 +0x8EA2AEAE 0x5255 # 0 +0x8EA2AEAF 0x5262 # 0 +0x8EA2AEB0 0x52CD # 0 +0x8EA2AEB1 0x530E # 0 +0x8EA2AEB2 0x539E # 0 +0x8EA2AEB3 0x5526 # 0 +0x8EA2AEB4 0x54E2 # 0 +0x8EA2AEB5 0x5517 # 0 +0x8EA2AEB6 0x5512 # 0 +0x8EA2AEB7 0x54E7 # 0 +0x8EA2AEB8 0x54F3 # 0 +0x8EA2AEB9 0x54E4 # 0 +0x8EA2AEBA 0x551A # 0 +0x8EA2AEBB 0x54FF # 0 +0x8EA2AEBC 0x5504 # 0 +0x8EA2AEBD 0x5508 # 0 +0x8EA2AEBE 0x54EB # 0 +0x8EA2AEBF 0x5511 # 0 +0x8EA2AEC0 0x5505 # 0 +0x8EA2AEC1 0x54F1 # 0 +0x8EA2AEC2 0x550A # 0 +0x8EA2AEC3 0x54FB # 0 +0x8EA2AEC4 0x54F7 # 0 +0x8EA2AEC5 0x54F8 # 0 +0x8EA2AEC6 0x54E0 # 0 +0x8EA2AEC7 0x550E # 0 +0x8EA2AEC8 0x5503 # 0 +0x8EA2AEC9 0x550B # 0 +0x8EA2AECA 0x5701 # 0 +0x8EA2AECB 0x5702 # 0 +0x8EA2AECC 0x57CC # 0 +0x8EA2AECD 0x5832 # 0 +0x8EA2AECE 0x57D5 # 0 +0x8EA2AECF 0x57D2 # 0 +0x8EA2AED0 0x57BA # 0 +0x8EA2AED1 0x57C6 # 0 +0x8EA2AED2 0x57BD # 0 +0x8EA2AED3 0x57BC # 0 +0x8EA2AED4 0x57B8 # 0 +0x8EA2AED5 0x57B6 # 0 +0x8EA2AED6 0x57BF # 0 +0x8EA2AED7 0x57C7 # 0 +0x8EA2AED8 0x57D0 # 0 +0x8EA2AED9 0x57B9 # 0 +0x8EA2AEDA 0x57C1 # 0 +0x8EA2AEDB 0x590E # 0 +0x8EA2AEDC 0x594A # 0 +0x8EA2AEDD 0x5A19 # 0 +0x8EA2AEDE 0x5A16 # 0 +0x8EA2AEDF 0x5A2D # 0 +0x8EA2AEE0 0x5A2E # 0 +0x8EA2AEE1 0x5A15 # 0 +0x8EA2AEE2 0x5A0F # 0 +0x8EA2AEE3 0x5A17 # 0 +0x8EA2AEE4 0x5A0A # 0 +0x8EA2AEE5 0x5A1E # 0 +0x8EA2AEE6 0x5A33 # 0 +0x8EA2AEE7 0x5B6C # 0 +0x8EA2AEE8 0x5BA7 # 0 +0x8EA2AEE9 0x5BAD # 0 +0x8EA2AEEA 0x5BAC # 0 +0x8EA2AEEB 0x5C03 # 0 +0x8EA2AEEC 0x5C56 # 0 +0x8EA2AEED 0x5C54 # 0 +0x8EA2AEEE 0x5CEC # 0 +0x8EA2AEEF 0x5CFF # 0 +0x8EA2AEF0 0x5CEE # 0 +0x8EA2AEF1 0x5CF1 # 0 +0x8EA2AEF2 0x5CF7 # 0 +0x8EA2AEF3 0x5D00 # 0 +0x8EA2AEF4 0x5CF9 # 0 +0x8EA2AEF5 0x5E29 # 0 +0x8EA2AEF6 0x5E28 # 0 +0x8EA2AEF7 0x5EA8 # 0 +0x8EA2AEF8 0x5EAE # 0 +0x8EA2AEF9 0x5EAA # 0 +0x8EA2AEFA 0x5EAC # 0 +0x8EA2AEFB 0x5F33 # 0 +0x8EA2AEFC 0x5F30 # 0 +0x8EA2AEFD 0x5F67 # 0 +0x8EA2AEFE 0x605D # 0 +0x8EA2AFA1 0x605A # 0 +0x8EA2AFA2 0x6067 # 0 +0x8EA2AFA3 0x6041 # 0 +0x8EA2AFA4 0x60A2 # 0 +0x8EA2AFA5 0x6088 # 0 +0x8EA2AFA6 0x6080 # 0 +0x8EA2AFA7 0x6092 # 0 +0x8EA2AFA8 0x6081 # 0 +0x8EA2AFA9 0x609D # 0 +0x8EA2AFAA 0x6083 # 0 +0x8EA2AFAB 0x6095 # 0 +0x8EA2AFAC 0x609B # 0 +0x8EA2AFAD 0x6097 # 0 +0x8EA2AFAE 0x6087 # 0 +0x8EA2AFAF 0x609C # 0 +0x8EA2AFB0 0x608E # 0 +0x8EA2AFB1 0x6219 # 0 +0x8EA2AFB2 0x6246 # 0 +0x8EA2AFB3 0x62F2 # 0 +0x8EA2AFB4 0x6310 # 0 +0x8EA2AFB5 0x6356 # 0 +0x8EA2AFB6 0x632C # 0 +0x8EA2AFB7 0x6344 # 0 +0x8EA2AFB8 0x6345 # 0 +0x8EA2AFB9 0x6336 # 0 +0x8EA2AFBA 0x6343 # 0 +0x8EA2AFBB 0x63E4 # 0 +0x8EA2AFBC 0x6339 # 0 +0x8EA2AFBD 0x634B # 0 +0x8EA2AFBE 0x634A # 0 +0x8EA2AFBF 0x633C # 0 +0x8EA2AFC0 0x6329 # 0 +0x8EA2AFC1 0x6341 # 0 +0x8EA2AFC2 0x6334 # 0 +0x8EA2AFC3 0x6358 # 0 +0x8EA2AFC4 0x6354 # 0 +0x8EA2AFC5 0x6359 # 0 +0x8EA2AFC6 0x632D # 0 +0x8EA2AFC7 0x6347 # 0 +0x8EA2AFC8 0x6333 # 0 +0x8EA2AFC9 0x635A # 0 +0x8EA2AFCA 0x6351 # 0 +0x8EA2AFCB 0x6338 # 0 +0x8EA2AFCC 0x6357 # 0 +0x8EA2AFCD 0x6340 # 0 +0x8EA2AFCE 0x6348 # 0 +0x8EA2AFCF 0x654A # 0 +0x8EA2AFD0 0x6546 # 0 +0x8EA2AFD1 0x65C6 # 0 +0x8EA2AFD2 0x65C3 # 0 +0x8EA2AFD3 0x65C4 # 0 +0x8EA2AFD4 0x65C2 # 0 +0x8EA2AFD5 0x664A # 0 +0x8EA2AFD6 0x665F # 0 +0x8EA2AFD7 0x6647 # 0 +0x8EA2AFD8 0x6651 # 0 +0x8EA2AFD9 0x6712 # 0 +0x8EA2AFDA 0x6713 # 0 +0x8EA2AFDB 0x681F # 0 +0x8EA2AFDC 0x681A # 0 +0x8EA2AFDD 0x6849 # 0 +0x8EA2AFDE 0x6832 # 0 +0x8EA2AFDF 0x6833 # 0 +0x8EA2AFE0 0x683B # 0 +0x8EA2AFE1 0x684B # 0 +0x8EA2AFE2 0x684F # 0 +0x8EA2AFE3 0x6816 # 0 +0x8EA2AFE4 0x6831 # 0 +0x8EA2AFE5 0x681C # 0 +0x8EA2AFE6 0x6835 # 0 +0x8EA2AFE7 0x682B # 0 +0x8EA2AFE8 0x682D # 0 +0x8EA2AFE9 0x682F # 0 +0x8EA2AFEA 0x684E # 0 +0x8EA2AFEB 0x6844 # 0 +0x8EA2AFEC 0x6834 # 0 +0x8EA2AFED 0x681D # 0 +0x8EA2AFEE 0x6812 # 0 +0x8EA2AFEF 0x6814 # 0 +0x8EA2AFF0 0x6826 # 0 +0x8EA2AFF1 0x6828 # 0 +0x8EA2AFF2 0x682E # 0 +0x8EA2AFF3 0x684D # 0 +0x8EA2AFF4 0x683A # 0 +0x8EA2AFF5 0x6825 # 0 +0x8EA2AFF6 0x6820 # 0 +0x8EA2AFF7 0x6B2C # 0 +0x8EA2AFF8 0x6B2F # 0 +0x8EA2AFF9 0x6B2D # 0 +0x8EA2AFFA 0x6B31 # 0 +0x8EA2AFFB 0x6B34 # 0 +0x8EA2AFFC 0x6B6D # 0 +0x8EA2AFFD 0x8082 # 0 +0x8EA2AFFE 0x6B88 # 0 +0x8EA2B0A1 0x6BE6 # 0 +0x8EA2B0A2 0x6BE4 # 0 +0x8EA2B0A3 0x6BE8 # 0 +0x8EA2B0A4 0x6BE3 # 0 +0x8EA2B0A5 0x6BE2 # 0 +0x8EA2B0A6 0x6BE7 # 0 +0x8EA2B0A7 0x6C25 # 0 +0x8EA2B0A8 0x6D7A # 0 +0x8EA2B0A9 0x6D63 # 0 +0x8EA2B0AA 0x6D64 # 0 +0x8EA2B0AB 0x6D76 # 0 +0x8EA2B0AC 0x6D0D # 0 +0x8EA2B0AD 0x6D61 # 0 +0x8EA2B0AE 0x6D92 # 0 +0x8EA2B0AF 0x6D58 # 0 +0x8EA2B0B0 0x6D62 # 0 +0x8EA2B0B1 0x6D6D # 0 +0x8EA2B0B2 0x6D6F # 0 +0x8EA2B0B3 0x6D91 # 0 +0x8EA2B0B4 0x6D8D # 0 +0x8EA2B0B5 0x6DEF # 0 +0x8EA2B0B6 0x6D7F # 0 +0x8EA2B0B7 0x6D86 # 0 +0x8EA2B0B8 0x6D5E # 0 +0x8EA2B0B9 0x6D67 # 0 +0x8EA2B0BA 0x6D60 # 0 +0x8EA2B0BB 0x6D97 # 0 +0x8EA2B0BC 0x6D70 # 0 +0x8EA2B0BD 0x6D7C # 0 +0x8EA2B0BE 0x6D5F # 0 +0x8EA2B0BF 0x6D82 # 0 +0x8EA2B0C0 0x6D98 # 0 +0x8EA2B0C1 0x6D2F # 0 +0x8EA2B0C2 0x6D68 # 0 +0x8EA2B0C3 0x6D8B # 0 +0x8EA2B0C4 0x6D7E # 0 +0x8EA2B0C5 0x6D80 # 0 +0x8EA2B0C6 0x6D84 # 0 +0x8EA2B0C7 0x6D16 # 0 +0x8EA2B0C8 0x6D83 # 0 +0x8EA2B0C9 0x6D7B # 0 +0x8EA2B0CA 0x6D7D # 0 +0x8EA2B0CB 0x6D75 # 0 +0x8EA2B0CC 0x6D90 # 0 +0x8EA2B0CD 0x70DC # 0 +0x8EA2B0CE 0x70D3 # 0 +0x8EA2B0CF 0x70D1 # 0 +0x8EA2B0D0 0x70DD # 0 +0x8EA2B0D1 0x70CB # 0 +0x8EA2B0D2 0x7F39 # 0 +0x8EA2B0D3 0x70E2 # 0 +0x8EA2B0D4 0x70D7 # 0 +0x8EA2B0D5 0x70D2 # 0 +0x8EA2B0D6 0x70DE # 0 +0x8EA2B0D7 0x70E0 # 0 +0x8EA2B0D8 0x70D4 # 0 +0x8EA2B0D9 0x70CD # 0 +0x8EA2B0DA 0x70C5 # 0 +0x8EA2B0DB 0x70C6 # 0 +0x8EA2B0DC 0x70C7 # 0 +0x8EA2B0DD 0x70DA # 0 +0x8EA2B0DE 0x70CE # 0 +0x8EA2B0DF 0x70E1 # 0 +0x8EA2B0E0 0x7242 # 0 +0x8EA2B0E1 0x7278 # 0 +0x8EA2B0E2 0x7277 # 0 +0x8EA2B0E3 0x7276 # 0 +0x8EA2B0E4 0x7300 # 0 +0x8EA2B0E5 0x72FA # 0 +0x8EA2B0E6 0x72F4 # 0 +0x8EA2B0E7 0x72FE # 0 +0x8EA2B0E8 0x72F6 # 0 +0x8EA2B0E9 0x72F3 # 0 +0x8EA2B0EA 0x72FB # 0 +0x8EA2B0EB 0x7301 # 0 +0x8EA2B0EC 0x73D3 # 0 +0x8EA2B0ED 0x73D9 # 0 +0x8EA2B0EE 0x73E5 # 0 +0x8EA2B0EF 0x73D6 # 0 +0x8EA2B0F0 0x73BC # 0 +0x8EA2B0F1 0x73E7 # 0 +0x8EA2B0F2 0x73E3 # 0 +0x8EA2B0F3 0x73E9 # 0 +0x8EA2B0F4 0x73DC # 0 +0x8EA2B0F5 0x73D2 # 0 +0x8EA2B0F6 0x73DB # 0 +0x8EA2B0F7 0x73D4 # 0 +0x8EA2B0F8 0x73DD # 0 +0x8EA2B0F9 0x73DA # 0 +0x8EA2B0FA 0x73D7 # 0 +0x8EA2B0FB 0x73D8 # 0 +0x8EA2B0FC 0x73E8 # 0 +0x8EA2B0FD 0x74DE # 0 +0x8EA2B0FE 0x74DF # 0 +0x8EA2B1A1 0x74F4 # 0 +0x8EA2B1A2 0x74F5 # 0 +0x8EA2B1A3 0x7521 # 0 +0x8EA2B1A4 0x755B # 0 +0x8EA2B1A5 0x755F # 0 +0x8EA2B1A6 0x75B0 # 0 +0x8EA2B1A7 0x75C1 # 0 +0x8EA2B1A8 0x75BB # 0 +0x8EA2B1A9 0x75C4 # 0 +0x8EA2B1AA 0x75C0 # 0 +0x8EA2B1AB 0x75BF # 0 +0x8EA2B1AC 0x75B6 # 0 +0x8EA2B1AD 0x75BA # 0 +0x8EA2B1AE 0x768A # 0 +0x8EA2B1AF 0x76C9 # 0 +0x8EA2B1B0 0x771D # 0 +0x8EA2B1B1 0x771B # 0 +0x8EA2B1B2 0x7710 # 0 +0x8EA2B1B3 0x7713 # 0 +0x8EA2B1B4 0x7712 # 0 +0x8EA2B1B5 0x7723 # 0 +0x8EA2B1B6 0x7711 # 0 +0x8EA2B1B7 0x7715 # 0 +0x8EA2B1B8 0x7719 # 0 +0x8EA2B1B9 0x771A # 0 +0x8EA2B1BA 0x7722 # 0 +0x8EA2B1BB 0x7727 # 0 +0x8EA2B1BC 0x7823 # 0 +0x8EA2B1BD 0x782C # 0 +0x8EA2B1BE 0x7822 # 0 +0x8EA2B1BF 0x7835 # 0 +0x8EA2B1C0 0x782F # 0 +0x8EA2B1C1 0x7828 # 0 +0x8EA2B1C2 0x782E # 0 +0x8EA2B1C3 0x782B # 0 +0x8EA2B1C4 0x7821 # 0 +0x8EA2B1C5 0x7829 # 0 +0x8EA2B1C6 0x7833 # 0 +0x8EA2B1C7 0x782A # 0 +0x8EA2B1C8 0x7831 # 0 +0x8EA2B1C9 0x7954 # 0 +0x8EA2B1CA 0x795B # 0 +0x8EA2B1CB 0x794F # 0 +0x8EA2B1CC 0x795C # 0 +0x8EA2B1CD 0x7953 # 0 +0x8EA2B1CE 0x7952 # 0 +0x8EA2B1CF 0x7951 # 0 +0x8EA2B1D0 0x79EB # 0 +0x8EA2B1D1 0x79EC # 0 +0x8EA2B1D2 0x79E0 # 0 +0x8EA2B1D3 0x79EE # 0 +0x8EA2B1D4 0x79ED # 0 +0x8EA2B1D5 0x79EA # 0 +0x8EA2B1D6 0x79DC # 0 +0x8EA2B1D7 0x79DE # 0 +0x8EA2B1D8 0x79DD # 0 +0x8EA2B1D9 0x7A86 # 0 +0x8EA2B1DA 0x7A89 # 0 +0x8EA2B1DB 0x7A85 # 0 +0x8EA2B1DC 0x7A8B # 0 +0x8EA2B1DD 0x7A8C # 0 +0x8EA2B1DE 0x7A8A # 0 +0x8EA2B1DF 0x7A87 # 0 +0x8EA2B1E0 0x7AD8 # 0 +0x8EA2B1E1 0x7B10 # 0 +0x8EA2B1E2 0x7B04 # 0 +0x8EA2B1E3 0x7B13 # 0 +0x8EA2B1E4 0x7B05 # 0 +0x8EA2B1E5 0x7B0F # 0 +0x8EA2B1E6 0x7B08 # 0 +0x8EA2B1E7 0x7B0A # 0 +0x8EA2B1E8 0x7B0E # 0 +0x8EA2B1E9 0x7B09 # 0 +0x8EA2B1EA 0x7B12 # 0 +0x8EA2B1EB 0x7C84 # 0 +0x8EA2B1EC 0x7C91 # 0 +0x8EA2B1ED 0x7C8A # 0 +0x8EA2B1EE 0x7C8C # 0 +0x8EA2B1EF 0x7C88 # 0 +0x8EA2B1F0 0x7C8D # 0 +0x8EA2B1F1 0x7C85 # 0 +0x8EA2B1F2 0x7D1E # 0 +0x8EA2B1F3 0x7D1D # 0 +0x8EA2B1F4 0x7D11 # 0 +0x8EA2B1F5 0x7D0E # 0 +0x8EA2B1F6 0x7D18 # 0 +0x8EA2B1F7 0x7D16 # 0 +0x8EA2B1F8 0x7D13 # 0 +0x8EA2B1F9 0x7D1F # 0 +0x8EA2B1FA 0x7D12 # 0 +0x8EA2B1FB 0x7D0F # 0 +0x8EA2B1FC 0x7D0C # 0 +0x8EA2B1FD 0x7F5C # 0 +0x8EA2B1FE 0x7F61 # 0 +0x8EA2B2A1 0x7F5E # 0 +0x8EA2B2A2 0x7F60 # 0 +0x8EA2B2A3 0x7F5D # 0 +0x8EA2B2A4 0x7F5B # 0 +0x8EA2B2A5 0x7F96 # 0 +0x8EA2B2A6 0x7F92 # 0 +0x8EA2B2A7 0x7FC3 # 0 +0x8EA2B2A8 0x7FC2 # 0 +0x8EA2B2A9 0x7FC0 # 0 +0x8EA2B2AA 0x8016 # 0 +0x8EA2B2AB 0x803E # 0 +0x8EA2B2AC 0x8039 # 0 +0x8EA2B2AD 0x80FA # 0 +0x8EA2B2AE 0x80F2 # 0 +0x8EA2B2AF 0x80F9 # 0 +0x8EA2B2B0 0x80F5 # 0 +0x8EA2B2B1 0x8101 # 0 +0x8EA2B2B2 0x80FB # 0 +0x8EA2B2B3 0x8100 # 0 +0x8EA2B2B4 0x8201 # 0 +0x8EA2B2B5 0x822F # 0 +0x8EA2B2B6 0x8225 # 0 +0x8EA2B2B7 0x8333 # 0 +0x8EA2B2B8 0x832D # 0 +0x8EA2B2B9 0x8344 # 0 +0x8EA2B2BA 0x8319 # 0 +0x8EA2B2BB 0x8351 # 0 +0x8EA2B2BC 0x8325 # 0 +0x8EA2B2BD 0x8356 # 0 +0x8EA2B2BE 0x833F # 0 +0x8EA2B2BF 0x8341 # 0 +0x8EA2B2C0 0x8326 # 0 +0x8EA2B2C1 0x831C # 0 +0x8EA2B2C2 0x8322 # 0 +0x8EA2B2C3 0x8342 # 0 +0x8EA2B2C4 0x834E # 0 +0x8EA2B2C5 0x831B # 0 +0x8EA2B2C6 0x832A # 0 +0x8EA2B2C7 0x8308 # 0 +0x8EA2B2C8 0x833C # 0 +0x8EA2B2C9 0x834D # 0 +0x8EA2B2CA 0x8316 # 0 +0x8EA2B2CB 0x8324 # 0 +0x8EA2B2CC 0x8320 # 0 +0x8EA2B2CD 0x8337 # 0 +0x8EA2B2CE 0x832F # 0 +0x8EA2B2CF 0x8329 # 0 +0x8EA2B2D0 0x8347 # 0 +0x8EA2B2D1 0x8345 # 0 +0x8EA2B2D2 0x834C # 0 +0x8EA2B2D3 0x8353 # 0 +0x8EA2B2D4 0x831E # 0 +0x8EA2B2D5 0x832C # 0 +0x8EA2B2D6 0x834B # 0 +0x8EA2B2D7 0x8327 # 0 +0x8EA2B2D8 0x8348 # 0 +0x8EA2B2D9 0x8653 # 0 +0x8EA2B2DA 0x8652 # 0 +0x8EA2B2DB 0x86A2 # 0 +0x8EA2B2DC 0x86A8 # 0 +0x8EA2B2DD 0x8696 # 0 +0x8EA2B2DE 0x868D # 0 +0x8EA2B2DF 0x8691 # 0 +0x8EA2B2E0 0x869E # 0 +0x8EA2B2E1 0x8687 # 0 +0x8EA2B2E2 0x8697 # 0 +0x8EA2B2E3 0x8686 # 0 +0x8EA2B2E4 0x868B # 0 +0x8EA2B2E5 0x869A # 0 +0x8EA2B2E6 0x8685 # 0 +0x8EA2B2E7 0x86A5 # 0 +0x8EA2B2E8 0x8699 # 0 +0x8EA2B2E9 0x86A1 # 0 +0x8EA2B2EA 0x86A7 # 0 +0x8EA2B2EB 0x8695 # 0 +0x8EA2B2EC 0x8698 # 0 +0x8EA2B2ED 0x868E # 0 +0x8EA2B2EE 0x869D # 0 +0x8EA2B2EF 0x8690 # 0 +0x8EA2B2F0 0x8694 # 0 +0x8EA2B2F1 0x8843 # 0 +0x8EA2B2F2 0x8844 # 0 +0x8EA2B2F3 0x886D # 0 +0x8EA2B2F4 0x8875 # 0 +0x8EA2B2F5 0x8876 # 0 +0x8EA2B2F6 0x8872 # 0 +0x8EA2B2F7 0x8880 # 0 +0x8EA2B2F8 0x8871 # 0 +0x8EA2B2F9 0x887F # 0 +0x8EA2B2FA 0x886F # 0 +0x8EA2B2FB 0x8883 # 0 +0x8EA2B2FC 0x887E # 0 +0x8EA2B2FD 0x8874 # 0 +0x8EA2B2FE 0x887C # 0 +0x8EA2B3A1 0x8A12 # 0 +0x8EA2B3A2 0x8C47 # 0 +0x8EA2B3A3 0x8C57 # 0 +0x8EA2B3A4 0x8C7B # 0 +0x8EA2B3A5 0x8CA4 # 0 +0x8EA2B3A6 0x8CA3 # 0 +0x8EA2B3A7 0x8D76 # 0 +0x8EA2B3A8 0x8D78 # 0 +0x8EA2B3A9 0x8DB5 # 0 +0x8EA2B3AA 0x8DB7 # 0 +0x8EA2B3AB 0x8DB6 # 0 +0x8EA2B3AC 0x8ED1 # 0 +0x8EA2B3AD 0x8ED3 # 0 +0x8EA2B3AE 0x8FFE # 0 +0x8EA2B3AF 0x8FF5 # 0 +0x8EA2B3B0 0x9002 # 0 +0x8EA2B3B1 0x8FFF # 0 +0x8EA2B3B2 0x8FFB # 0 +0x8EA2B3B3 0x9004 # 0 +0x8EA2B3B4 0x8FFC # 0 +0x8EA2B3B5 0x8FF6 # 0 +0x8EA2B3B6 0x90D6 # 0 +0x8EA2B3B7 0x90E0 # 0 +0x8EA2B3B8 0x90D9 # 0 +0x8EA2B3B9 0x90DA # 0 +0x8EA2B3BA 0x90E3 # 0 +0x8EA2B3BB 0x90DF # 0 +0x8EA2B3BC 0x90E5 # 0 +0x8EA2B3BD 0x90D8 # 0 +0x8EA2B3BE 0x90DB # 0 +0x8EA2B3BF 0x90D7 # 0 +0x8EA2B3C0 0x90DC # 0 +0x8EA2B3C1 0x90E4 # 0 +0x8EA2B3C2 0x9150 # 0 +0x8EA2B3C3 0x914E # 0 +0x8EA2B3C4 0x914F # 0 +0x8EA2B3C5 0x91D5 # 0 +0x8EA2B3C6 0x91E2 # 0 +0x8EA2B3C7 0x91DA # 0 +0x8EA2B3C8 0x965C # 0 +0x8EA2B3C9 0x965F # 0 +0x8EA2B3CA 0x96BC # 0 +0x8EA2B3CB 0x98E3 # 0 +0x8EA2B3CC 0x9ADF # 0 +0x8EA2B3CD 0x9B2F # 0 +0x8EA2B3CE 0x4E7F # 0 +0x8EA2B3CF 0x5070 # 0 +0x8EA2B3D0 0x506A # 0 +0x8EA2B3D1 0x5061 # 0 +0x8EA2B3D2 0x505E # 0 +0x8EA2B3D3 0x5060 # 0 +0x8EA2B3D4 0x5053 # 0 +0x8EA2B3D5 0x504B # 0 +0x8EA2B3D6 0x505D # 0 +0x8EA2B3D7 0x5072 # 0 +0x8EA2B3D8 0x5048 # 0 +0x8EA2B3D9 0x504D # 0 +0x8EA2B3DA 0x5041 # 0 +0x8EA2B3DB 0x505B # 0 +0x8EA2B3DC 0x504A # 0 +0x8EA2B3DD 0x5062 # 0 +0x8EA2B3DE 0x5015 # 0 +0x8EA2B3DF 0x5045 # 0 +0x8EA2B3E0 0x505F # 0 +0x8EA2B3E1 0x5069 # 0 +0x8EA2B3E2 0x506B # 0 +0x8EA2B3E3 0x5063 # 0 +0x8EA2B3E4 0x5064 # 0 +0x8EA2B3E5 0x5046 # 0 +0x8EA2B3E6 0x5040 # 0 +0x8EA2B3E7 0x506E # 0 +0x8EA2B3E8 0x5073 # 0 +0x8EA2B3E9 0x5057 # 0 +0x8EA2B3EA 0x5051 # 0 +0x8EA2B3EB 0x51D0 # 0 +0x8EA2B3EC 0x526B # 0 +0x8EA2B3ED 0x526D # 0 +0x8EA2B3EE 0x526C # 0 +0x8EA2B3EF 0x526E # 0 +0x8EA2B3F0 0x52D6 # 0 +0x8EA2B3F1 0x52D3 # 0 +0x8EA2B3F2 0x532D # 0 +0x8EA2B3F3 0x539C # 0 +0x8EA2B3F4 0x5575 # 0 +0x8EA2B3F5 0x5576 # 0 +0x8EA2B3F6 0x553C # 0 +0x8EA2B3F7 0x554D # 0 +0x8EA2B3F8 0x5550 # 0 +0x8EA2B3F9 0x5534 # 0 +0x8EA2B3FA 0x552A # 0 +0x8EA2B3FB 0x5551 # 0 +0x8EA2B3FC 0x5562 # 0 +0x8EA2B3FD 0x5536 # 0 +0x8EA2B3FE 0x5535 # 0 +0x8EA2B4A1 0x5530 # 0 +0x8EA2B4A2 0x5552 # 0 +0x8EA2B4A3 0x5545 # 0 +0x8EA2B4A4 0x550C # 0 +0x8EA2B4A5 0x5532 # 0 +0x8EA2B4A6 0x5565 # 0 +0x8EA2B4A7 0x554E # 0 +0x8EA2B4A8 0x5539 # 0 +0x8EA2B4A9 0x5548 # 0 +0x8EA2B4AA 0x552D # 0 +0x8EA2B4AB 0x553B # 0 +0x8EA2B4AC 0x5540 # 0 +0x8EA2B4AD 0x554B # 0 +0x8EA2B4AE 0x570A # 0 +0x8EA2B4AF 0x5707 # 0 +0x8EA2B4B0 0x57FB # 0 +0x8EA2B4B1 0x5814 # 0 +0x8EA2B4B2 0x57E2 # 0 +0x8EA2B4B3 0x57F6 # 0 +0x8EA2B4B4 0x57DC # 0 +0x8EA2B4B5 0x57F4 # 0 +0x8EA2B4B6 0x5800 # 0 +0x8EA2B4B7 0x57ED # 0 +0x8EA2B4B8 0x57FD # 0 +0x8EA2B4B9 0x5808 # 0 +0x8EA2B4BA 0x57F8 # 0 +0x8EA2B4BB 0x580B # 0 +0x8EA2B4BC 0x57F3 # 0 +0x8EA2B4BD 0x57CF # 0 +0x8EA2B4BE 0x5807 # 0 +0x8EA2B4BF 0x57EE # 0 +0x8EA2B4C0 0x57E3 # 0 +0x8EA2B4C1 0x57F2 # 0 +0x8EA2B4C2 0x57E5 # 0 +0x8EA2B4C3 0x57EC # 0 +0x8EA2B4C4 0x57E1 # 0 +0x8EA2B4C5 0x580E # 0 +0x8EA2B4C6 0x57FC # 0 +0x8EA2B4C7 0x5810 # 0 +0x8EA2B4C8 0x57E7 # 0 +0x8EA2B4C9 0x5801 # 0 +0x8EA2B4CA 0x580C # 0 +0x8EA2B4CB 0x57F1 # 0 +0x8EA2B4CC 0x57E9 # 0 +0x8EA2B4CD 0x57F0 # 0 +0x8EA2B4CE 0x580D # 0 +0x8EA2B4CF 0x5804 # 0 +0x8EA2B4D0 0x595C # 0 +0x8EA2B4D1 0x5A60 # 0 +0x8EA2B4D2 0x5A58 # 0 +0x8EA2B4D3 0x5A55 # 0 +0x8EA2B4D4 0x5A67 # 0 +0x8EA2B4D5 0x5A5E # 0 +0x8EA2B4D6 0x5A38 # 0 +0x8EA2B4D7 0x5A35 # 0 +0x8EA2B4D8 0x5A6D # 0 +0x8EA2B4D9 0x5A50 # 0 +0x8EA2B4DA 0x5A5F # 0 +0x8EA2B4DB 0x5A65 # 0 +0x8EA2B4DC 0x5A6C # 0 +0x8EA2B4DD 0x5A53 # 0 +0x8EA2B4DE 0x5A64 # 0 +0x8EA2B4DF 0x5A57 # 0 +0x8EA2B4E0 0x5A43 # 0 +0x8EA2B4E1 0x5A5D # 0 +0x8EA2B4E2 0x5A52 # 0 +0x8EA2B4E3 0x5A44 # 0 +0x8EA2B4E4 0x5A5B # 0 +0x8EA2B4E5 0x5A48 # 0 +0x8EA2B4E6 0x5A8E # 0 +0x8EA2B4E7 0x5A3E # 0 +0x8EA2B4E8 0x5A4D # 0 +0x8EA2B4E9 0x5A39 # 0 +0x8EA2B4EA 0x5A4C # 0 +0x8EA2B4EB 0x5A70 # 0 +0x8EA2B4EC 0x5A69 # 0 +0x8EA2B4ED 0x5A47 # 0 +0x8EA2B4EE 0x5A51 # 0 +0x8EA2B4EF 0x5A56 # 0 +0x8EA2B4F0 0x5A42 # 0 +0x8EA2B4F1 0x5A5C # 0 +0x8EA2B4F2 0x5B72 # 0 +0x8EA2B4F3 0x5B6E # 0 +0x8EA2B4F4 0x5BC1 # 0 +0x8EA2B4F5 0x5BC0 # 0 +0x8EA2B4F6 0x5C59 # 0 +0x8EA2B4F7 0x5D1E # 0 +0x8EA2B4F8 0x5D0B # 0 +0x8EA2B4F9 0x5D1D # 0 +0x8EA2B4FA 0x5D1A # 0 +0x8EA2B4FB 0x5D20 # 0 +0x8EA2B4FC 0x5D0C # 0 +0x8EA2B4FD 0x5D28 # 0 +0x8EA2B4FE 0x5D0D # 0 +0x8EA2B5A1 0x5D26 # 0 +0x8EA2B5A2 0x5D25 # 0 +0x8EA2B5A3 0x5D0F # 0 +0x8EA2B5A4 0x5D30 # 0 +0x8EA2B5A5 0x5D12 # 0 +0x8EA2B5A6 0x5D23 # 0 +0x8EA2B5A7 0x5D1F # 0 +0x8EA2B5A8 0x5D2E # 0 +0x8EA2B5A9 0x5E3E # 0 +0x8EA2B5AA 0x5E34 # 0 +0x8EA2B5AB 0x5EB1 # 0 +0x8EA2B5AC 0x5EB4 # 0 +0x8EA2B5AD 0x5EB9 # 0 +0x8EA2B5AE 0x5EB2 # 0 +0x8EA2B5AF 0x5EB3 # 0 +0x8EA2B5B0 0x5F36 # 0 +0x8EA2B5B1 0x5F38 # 0 +0x8EA2B5B2 0x5F9B # 0 +0x8EA2B5B3 0x5F96 # 0 +0x8EA2B5B4 0x5F9F # 0 +0x8EA2B5B5 0x608A # 0 +0x8EA2B5B6 0x6090 # 0 +0x8EA2B5B7 0x6086 # 0 +0x8EA2B5B8 0x60BE # 0 +0x8EA2B5B9 0x60B0 # 0 +0x8EA2B5BA 0x60BA # 0 +0x8EA2B5BB 0x60D3 # 0 +0x8EA2B5BC 0x60D4 # 0 +0x8EA2B5BD 0x60CF # 0 +0x8EA2B5BE 0x60E4 # 0 +0x8EA2B5BF 0x60D9 # 0 +0x8EA2B5C0 0x60DD # 0 +0x8EA2B5C1 0x60C8 # 0 +0x8EA2B5C2 0x60B1 # 0 +0x8EA2B5C3 0x60DB # 0 +0x8EA2B5C4 0x60B7 # 0 +0x8EA2B5C5 0x60CA # 0 +0x8EA2B5C6 0x60BF # 0 +0x8EA2B5C7 0x60C3 # 0 +0x8EA2B5C8 0x60CD # 0 +0x8EA2B5C9 0x60C0 # 0 +0x8EA2B5CA 0x6332 # 0 +0x8EA2B5CB 0x6365 # 0 +0x8EA2B5CC 0x638A # 0 +0x8EA2B5CD 0x6382 # 0 +0x8EA2B5CE 0x637D # 0 +0x8EA2B5CF 0x63BD # 0 +0x8EA2B5D0 0x639E # 0 +0x8EA2B5D1 0x63AD # 0 +0x8EA2B5D2 0x639D # 0 +0x8EA2B5D3 0x6397 # 0 +0x8EA2B5D4 0x63AB # 0 +0x8EA2B5D5 0x638E # 0 +0x8EA2B5D6 0x636F # 0 +0x8EA2B5D7 0x6387 # 0 +0x8EA2B5D8 0x6390 # 0 +0x8EA2B5D9 0x636E # 0 +0x8EA2B5DA 0x63AF # 0 +0x8EA2B5DB 0x6375 # 0 +0x8EA2B5DC 0x639C # 0 +0x8EA2B5DD 0x636D # 0 +0x8EA2B5DE 0x63AE # 0 +0x8EA2B5DF 0x637C # 0 +0x8EA2B5E0 0x63A4 # 0 +0x8EA2B5E1 0x633B # 0 +0x8EA2B5E2 0x639F # 0 +0x8EA2B5E3 0x6378 # 0 +0x8EA2B5E4 0x6385 # 0 +0x8EA2B5E5 0x6381 # 0 +0x8EA2B5E6 0x6391 # 0 +0x8EA2B5E7 0x638D # 0 +0x8EA2B5E8 0x6370 # 0 +0x8EA2B5E9 0x6553 # 0 +0x8EA2B5EA 0x65CD # 0 +0x8EA2B5EB 0x6665 # 0 +0x8EA2B5EC 0x6661 # 0 +0x8EA2B5ED 0x665B # 0 +0x8EA2B5EE 0x6659 # 0 +0x8EA2B5EF 0x665C # 0 +0x8EA2B5F0 0x6662 # 0 +0x8EA2B5F1 0x6718 # 0 +0x8EA2B5F2 0x6879 # 0 +0x8EA2B5F3 0x6887 # 0 +0x8EA2B5F4 0x6890 # 0 +0x8EA2B5F5 0x689C # 0 +0x8EA2B5F6 0x686D # 0 +0x8EA2B5F7 0x686E # 0 +0x8EA2B5F8 0x68AE # 0 +0x8EA2B5F9 0x68AB # 0 +0x8EA2B5FA 0x6956 # 0 +0x8EA2B5FB 0x686F # 0 +0x8EA2B5FC 0x68A3 # 0 +0x8EA2B5FD 0x68AC # 0 +0x8EA2B5FE 0x68A9 # 0 +0x8EA2B6A1 0x6875 # 0 +0x8EA2B6A2 0x6874 # 0 +0x8EA2B6A3 0x68B2 # 0 +0x8EA2B6A4 0x688F # 0 +0x8EA2B6A5 0x6877 # 0 +0x8EA2B6A6 0x6892 # 0 +0x8EA2B6A7 0x687C # 0 +0x8EA2B6A8 0x686B # 0 +0x8EA2B6A9 0x6872 # 0 +0x8EA2B6AA 0x68AA # 0 +0x8EA2B6AB 0x6880 # 0 +0x8EA2B6AC 0x6871 # 0 +0x8EA2B6AD 0x687E # 0 +0x8EA2B6AE 0x689B # 0 +0x8EA2B6AF 0x6896 # 0 +0x8EA2B6B0 0x688B # 0 +0x8EA2B6B1 0x68A0 # 0 +0x8EA2B6B2 0x6889 # 0 +0x8EA2B6B3 0x68A4 # 0 +0x8EA2B6B4 0x6878 # 0 +0x8EA2B6B5 0x687B # 0 +0x8EA2B6B6 0x6891 # 0 +0x8EA2B6B7 0x688C # 0 +0x8EA2B6B8 0x688A # 0 +0x8EA2B6B9 0x687D # 0 +0x8EA2B6BA 0x6B36 # 0 +0x8EA2B6BB 0x6B33 # 0 +0x8EA2B6BC 0x6B37 # 0 +0x8EA2B6BD 0x6B38 # 0 +0x8EA2B6BE 0x6B91 # 0 +0x8EA2B6BF 0x6B8F # 0 +0x8EA2B6C0 0x6B8D # 0 +0x8EA2B6C1 0x6B8E # 0 +0x8EA2B6C2 0x6B8C # 0 +0x8EA2B6C3 0x6C2A # 0 +0x8EA2B6C4 0x6DC0 # 0 +0x8EA2B6C5 0x6DAB # 0 +0x8EA2B6C6 0x6DB4 # 0 +0x8EA2B6C7 0x6DB3 # 0 +0x8EA2B6C8 0x6E74 # 0 +0x8EA2B6C9 0x6DAC # 0 +0x8EA2B6CA 0x6DE9 # 0 +0x8EA2B6CB 0x6DE2 # 0 +0x8EA2B6CC 0x6DB7 # 0 +0x8EA2B6CD 0x6DF6 # 0 +0x8EA2B6CE 0x6DD4 # 0 +0x8EA2B6CF 0x6E00 # 0 +0x8EA2B6D0 0x6DC8 # 0 +0x8EA2B6D1 0x6DE0 # 0 +0x8EA2B6D2 0x6DDF # 0 +0x8EA2B6D3 0x6DD6 # 0 +0x8EA2B6D4 0x6DBE # 0 +0x8EA2B6D5 0x6DE5 # 0 +0x8EA2B6D6 0x6DDC # 0 +0x8EA2B6D7 0x6DDD # 0 +0x8EA2B6D8 0x6DDB # 0 +0x8EA2B6D9 0x6DF4 # 0 +0x8EA2B6DA 0x6DCA # 0 +0x8EA2B6DB 0x6DBD # 0 +0x8EA2B6DC 0x6DED # 0 +0x8EA2B6DD 0x6DF0 # 0 +0x8EA2B6DE 0x6DBA # 0 +0x8EA2B6DF 0x6DD5 # 0 +0x8EA2B6E0 0x6DC2 # 0 +0x8EA2B6E1 0x6DCF # 0 +0x8EA2B6E2 0x6DC9 # 0 +0x8EA2B6E3 0x6DD0 # 0 +0x8EA2B6E4 0x6DF2 # 0 +0x8EA2B6E5 0x6DD3 # 0 +0x8EA2B6E6 0x6DFD # 0 +0x8EA2B6E7 0x6DD7 # 0 +0x8EA2B6E8 0x6DCD # 0 +0x8EA2B6E9 0x6DE3 # 0 +0x8EA2B6EA 0x6DBB # 0 +0x8EA2B6EB 0x70FA # 0 +0x8EA2B6EC 0x710D # 0 +0x8EA2B6ED 0x70F7 # 0 +0x8EA2B6EE 0x7117 # 0 +0x8EA2B6EF 0x70F4 # 0 +0x8EA2B6F0 0x710C # 0 +0x8EA2B6F1 0x70F0 # 0 +0x8EA2B6F2 0x7104 # 0 +0x8EA2B6F3 0x70F3 # 0 +0x8EA2B6F4 0x7110 # 0 +0x8EA2B6F5 0x70FC # 0 +0x8EA2B6F6 0x70FF # 0 +0x8EA2B6F7 0x7106 # 0 +0x8EA2B6F8 0x7113 # 0 +0x8EA2B6F9 0x7100 # 0 +0x8EA2B6FA 0x70F8 # 0 +0x8EA2B6FB 0x70F6 # 0 +0x8EA2B6FC 0x710B # 0 +0x8EA2B6FD 0x7102 # 0 +0x8EA2B6FE 0x710E # 0 +0x8EA2B7A1 0x727E # 0 +0x8EA2B7A2 0x727B # 0 +0x8EA2B7A3 0x727C # 0 +0x8EA2B7A4 0x727F # 0 +0x8EA2B7A5 0x731D # 0 +0x8EA2B7A6 0x7317 # 0 +0x8EA2B7A7 0x7307 # 0 +0x8EA2B7A8 0x7311 # 0 +0x8EA2B7A9 0x7318 # 0 +0x8EA2B7AA 0x730A # 0 +0x8EA2B7AB 0x7308 # 0 +0x8EA2B7AC 0x72FF # 0 +0x8EA2B7AD 0x730F # 0 +0x8EA2B7AE 0x731E # 0 +0x8EA2B7AF 0x7388 # 0 +0x8EA2B7B0 0x73F6 # 0 +0x8EA2B7B1 0x73F8 # 0 +0x8EA2B7B2 0x73F5 # 0 +0x8EA2B7B3 0x7404 # 0 +0x8EA2B7B4 0x7401 # 0 +0x8EA2B7B5 0x73FD # 0 +0x8EA2B7B6 0x7407 # 0 +0x8EA2B7B7 0x7400 # 0 +0x8EA2B7B8 0x73FA # 0 +0x8EA2B7B9 0x73FC # 0 +0x8EA2B7BA 0x73FF # 0 +0x8EA2B7BB 0x740C # 0 +0x8EA2B7BC 0x740B # 0 +0x8EA2B7BD 0x73F4 # 0 +0x8EA2B7BE 0x7408 # 0 +0x8EA2B7BF 0x7564 # 0 +0x8EA2B7C0 0x7563 # 0 +0x8EA2B7C1 0x75CE # 0 +0x8EA2B7C2 0x75D2 # 0 +0x8EA2B7C3 0x75CF # 0 +0x8EA2B7C4 0x75CB # 0 +0x8EA2B7C5 0x75CC # 0 +0x8EA2B7C6 0x75D1 # 0 +0x8EA2B7C7 0x75D0 # 0 +0x8EA2B7C8 0x768F # 0 +0x8EA2B7C9 0x7689 # 0 +0x8EA2B7CA 0x76D3 # 0 +0x8EA2B7CB 0x7739 # 0 +0x8EA2B7CC 0x772F # 0 +0x8EA2B7CD 0x772D # 0 +0x8EA2B7CE 0x7731 # 0 +0x8EA2B7CF 0x7732 # 0 +0x8EA2B7D0 0x7734 # 0 +0x8EA2B7D1 0x7733 # 0 +0x8EA2B7D2 0x773D # 0 +0x8EA2B7D3 0x7725 # 0 +0x8EA2B7D4 0x773B # 0 +0x8EA2B7D5 0x7735 # 0 +0x8EA2B7D6 0x7848 # 0 +0x8EA2B7D7 0x7852 # 0 +0x8EA2B7D8 0x7849 # 0 +0x8EA2B7D9 0x784D # 0 +0x8EA2B7DA 0x784A # 0 +0x8EA2B7DB 0x784C # 0 +0x8EA2B7DC 0x7826 # 0 +0x8EA2B7DD 0x7845 # 0 +0x8EA2B7DE 0x7850 # 0 +0x8EA2B7DF 0x7964 # 0 +0x8EA2B7E0 0x7967 # 0 +0x8EA2B7E1 0x7969 # 0 +0x8EA2B7E2 0x796A # 0 +0x8EA2B7E3 0x7963 # 0 +0x8EA2B7E4 0x796B # 0 +0x8EA2B7E5 0x7961 # 0 +0x8EA2B7E6 0x79BB # 0 +0x8EA2B7E7 0x79FA # 0 +0x8EA2B7E8 0x79F8 # 0 +0x8EA2B7E9 0x79F6 # 0 +0x8EA2B7EA 0x79F7 # 0 +0x8EA2B7EB 0x7A8F # 0 +0x8EA2B7EC 0x7A94 # 0 +0x8EA2B7ED 0x7A90 # 0 +0x8EA2B7EE 0x7B35 # 0 +0x8EA2B7EF 0x7B3B # 0 +0x8EA2B7F0 0x7B34 # 0 +0x8EA2B7F1 0x7B25 # 0 +0x8EA2B7F2 0x7B30 # 0 +0x8EA2B7F3 0x7B22 # 0 +0x8EA2B7F4 0x7B24 # 0 +0x8EA2B7F5 0x7B33 # 0 +0x8EA2B7F6 0x7B18 # 0 +0x8EA2B7F7 0x7B2A # 0 +0x8EA2B7F8 0x7B1D # 0 +0x8EA2B7F9 0x7B31 # 0 +0x8EA2B7FA 0x7B2B # 0 +0x8EA2B7FB 0x7B2D # 0 +0x8EA2B7FC 0x7B2F # 0 +0x8EA2B7FD 0x7B32 # 0 +0x8EA2B7FE 0x7B38 # 0 +0x8EA2B8A1 0x7B1A # 0 +0x8EA2B8A2 0x7B23 # 0 +0x8EA2B8A3 0x7C94 # 0 +0x8EA2B8A4 0x7C98 # 0 +0x8EA2B8A5 0x7C96 # 0 +0x8EA2B8A6 0x7CA3 # 0 +0x8EA2B8A7 0x7D35 # 0 +0x8EA2B8A8 0x7D3D # 0 +0x8EA2B8A9 0x7D38 # 0 +0x8EA2B8AA 0x7D36 # 0 +0x8EA2B8AB 0x7D3A # 0 +0x8EA2B8AC 0x7D45 # 0 +0x8EA2B8AD 0x7D2C # 0 +0x8EA2B8AE 0x7D29 # 0 +0x8EA2B8AF 0x7D41 # 0 +0x8EA2B8B0 0x7D47 # 0 +0x8EA2B8B1 0x7D3E # 0 +0x8EA2B8B2 0x7D3F # 0 +0x8EA2B8B3 0x7D4A # 0 +0x8EA2B8B4 0x7D3B # 0 +0x8EA2B8B5 0x7D28 # 0 +0x8EA2B8B6 0x7F63 # 0 +0x8EA2B8B7 0x7F95 # 0 +0x8EA2B8B8 0x7F9C # 0 +0x8EA2B8B9 0x7F9D # 0 +0x8EA2B8BA 0x7F9B # 0 +0x8EA2B8BB 0x7FCA # 0 +0x8EA2B8BC 0x7FCB # 0 +0x8EA2B8BD 0x7FCD # 0 +0x8EA2B8BE 0x7FD0 # 0 +0x8EA2B8BF 0x7FD1 # 0 +0x8EA2B8C0 0x7FC7 # 0 +0x8EA2B8C1 0x7FCF # 0 +0x8EA2B8C2 0x7FC9 # 0 +0x8EA2B8C3 0x801F # 0 +0x8EA2B8C4 0x801E # 0 +0x8EA2B8C5 0x801B # 0 +0x8EA2B8C6 0x8047 # 0 +0x8EA2B8C7 0x8043 # 0 +0x8EA2B8C8 0x8048 # 0 +0x8EA2B8C9 0x8118 # 0 +0x8EA2B8CA 0x8125 # 0 +0x8EA2B8CB 0x8119 # 0 +0x8EA2B8CC 0x811B # 0 +0x8EA2B8CD 0x812D # 0 +0x8EA2B8CE 0x811F # 0 +0x8EA2B8CF 0x812C # 0 +0x8EA2B8D0 0x811E # 0 +0x8EA2B8D1 0x8121 # 0 +0x8EA2B8D2 0x8115 # 0 +0x8EA2B8D3 0x8127 # 0 +0x8EA2B8D4 0x811D # 0 +0x8EA2B8D5 0x8122 # 0 +0x8EA2B8D6 0x8211 # 0 +0x8EA2B8D7 0x8238 # 0 +0x8EA2B8D8 0x8233 # 0 +0x8EA2B8D9 0x823A # 0 +0x8EA2B8DA 0x8234 # 0 +0x8EA2B8DB 0x8232 # 0 +0x8EA2B8DC 0x8274 # 0 +0x8EA2B8DD 0x8390 # 0 +0x8EA2B8DE 0x83A3 # 0 +0x8EA2B8DF 0x83A8 # 0 +0x8EA2B8E0 0x838D # 0 +0x8EA2B8E1 0x837A # 0 +0x8EA2B8E2 0x8373 # 0 +0x8EA2B8E3 0x83A4 # 0 +0x8EA2B8E4 0x8374 # 0 +0x8EA2B8E5 0x838F # 0 +0x8EA2B8E6 0x8381 # 0 +0x8EA2B8E7 0x8395 # 0 +0x8EA2B8E8 0x8399 # 0 +0x8EA2B8E9 0x8375 # 0 +0x8EA2B8EA 0x8394 # 0 +0x8EA2B8EB 0x83A9 # 0 +0x8EA2B8EC 0x837D # 0 +0x8EA2B8ED 0x8383 # 0 +0x8EA2B8EE 0x838C # 0 +0x8EA2B8EF 0x839D # 0 +0x8EA2B8F0 0x839B # 0 +0x8EA2B8F1 0x83AA # 0 +0x8EA2B8F2 0x838B # 0 +0x8EA2B8F3 0x837E # 0 +0x8EA2B8F4 0x83A5 # 0 +0x8EA2B8F5 0x83AF # 0 +0x8EA2B8F6 0x8388 # 0 +0x8EA2B8F7 0x8397 # 0 +0x8EA2B8F8 0x83B0 # 0 +0x8EA2B8F9 0x837F # 0 +0x8EA2B8FA 0x83A6 # 0 +0x8EA2B8FB 0x8387 # 0 +0x8EA2B8FC 0x83AE # 0 +0x8EA2B8FD 0x8376 # 0 +0x8EA2B8FE 0x8659 # 0 +0x8EA2B9A1 0x8656 # 0 +0x8EA2B9A2 0x86BF # 0 +0x8EA2B9A3 0x86B7 # 0 +0x8EA2B9A4 0x86C2 # 0 +0x8EA2B9A5 0x86C1 # 0 +0x8EA2B9A6 0x86C5 # 0 +0x8EA2B9A7 0x86BA # 0 +0x8EA2B9A8 0x86B0 # 0 +0x8EA2B9A9 0x86C8 # 0 +0x8EA2B9AA 0x86B9 # 0 +0x8EA2B9AB 0x86B3 # 0 +0x8EA2B9AC 0x86B8 # 0 +0x8EA2B9AD 0x86CC # 0 +0x8EA2B9AE 0x86B4 # 0 +0x8EA2B9AF 0x86BB # 0 +0x8EA2B9B0 0x86BC # 0 +0x8EA2B9B1 0x86C3 # 0 +0x8EA2B9B2 0x86BD # 0 +0x8EA2B9B3 0x86BE # 0 +0x8EA2B9B4 0x8852 # 0 +0x8EA2B9B5 0x8889 # 0 +0x8EA2B9B6 0x8895 # 0 +0x8EA2B9B7 0x88A8 # 0 +0x8EA2B9B8 0x88A2 # 0 +0x8EA2B9B9 0x88AA # 0 +0x8EA2B9BA 0x889A # 0 +0x8EA2B9BB 0x8891 # 0 +0x8EA2B9BC 0x88A1 # 0 +0x8EA2B9BD 0x889F # 0 +0x8EA2B9BE 0x8898 # 0 +0x8EA2B9BF 0x88A7 # 0 +0x8EA2B9C0 0x8899 # 0 +0x8EA2B9C1 0x889B # 0 +0x8EA2B9C2 0x8897 # 0 +0x8EA2B9C3 0x88A4 # 0 +0x8EA2B9C4 0x88AC # 0 +0x8EA2B9C5 0x888C # 0 +0x8EA2B9C6 0x8893 # 0 +0x8EA2B9C7 0x888E # 0 +0x8EA2B9C8 0x8982 # 0 +0x8EA2B9C9 0x89D6 # 0 +0x8EA2B9CA 0x89D9 # 0 +0x8EA2B9CB 0x89D5 # 0 +0x8EA2B9CC 0x8A30 # 0 +0x8EA2B9CD 0x8A27 # 0 +0x8EA2B9CE 0x8A2C # 0 +0x8EA2B9CF 0x8A1E # 0 +0x8EA2B9D0 0x8C39 # 0 +0x8EA2B9D1 0x8C3B # 0 +0x8EA2B9D2 0x8C5C # 0 +0x8EA2B9D3 0x8C5D # 0 +0x8EA2B9D4 0x8C7D # 0 +0x8EA2B9D5 0x8CA5 # 0 +0x8EA2B9D6 0x8D7D # 0 +0x8EA2B9D7 0x8D7B # 0 +0x8EA2B9D8 0x8D79 # 0 +0x8EA2B9D9 0x8DBC # 0 +0x8EA2B9DA 0x8DC2 # 0 +0x8EA2B9DB 0x8DB9 # 0 +0x8EA2B9DC 0x8DBF # 0 +0x8EA2B9DD 0x8DC1 # 0 +0x8EA2B9DE 0x8ED8 # 0 +0x8EA2B9DF 0x8EDE # 0 +0x8EA2B9E0 0x8EDD # 0 +0x8EA2B9E1 0x8EDC # 0 +0x8EA2B9E2 0x8ED7 # 0 +0x8EA2B9E3 0x8EE0 # 0 +0x8EA2B9E4 0x8EE1 # 0 +0x8EA2B9E5 0x9024 # 0 +0x8EA2B9E6 0x900B # 0 +0x8EA2B9E7 0x9011 # 0 +0x8EA2B9E8 0x901C # 0 +0x8EA2B9E9 0x900C # 0 +0x8EA2B9EA 0x9021 # 0 +0x8EA2B9EB 0x90EF # 0 +0x8EA2B9EC 0x90EA # 0 +0x8EA2B9ED 0x90F0 # 0 +0x8EA2B9EE 0x90F4 # 0 +0x8EA2B9EF 0x90F2 # 0 +0x8EA2B9F0 0x90F3 # 0 +0x8EA2B9F1 0x90D4 # 0 +0x8EA2B9F2 0x90EB # 0 +0x8EA2B9F3 0x90EC # 0 +0x8EA2B9F4 0x90E9 # 0 +0x8EA2B9F5 0x9156 # 0 +0x8EA2B9F6 0x9158 # 0 +0x8EA2B9F7 0x915A # 0 +0x8EA2B9F8 0x9153 # 0 +0x8EA2B9F9 0x9155 # 0 +0x8EA2B9FA 0x91EC # 0 +0x8EA2B9FB 0x91F4 # 0 +0x8EA2B9FC 0x91F1 # 0 +0x8EA2B9FD 0x91F3 # 0 +0x8EA2B9FE 0x91F8 # 0 +0x8EA2BAA1 0x91E4 # 0 +0x8EA2BAA2 0x91F9 # 0 +0x8EA2BAA3 0x91EA # 0 +0x8EA2BAA4 0x91EB # 0 +0x8EA2BAA5 0x91F7 # 0 +0x8EA2BAA6 0x91E8 # 0 +0x8EA2BAA7 0x91EE # 0 +0x8EA2BAA8 0x957A # 0 +0x8EA2BAA9 0x9586 # 0 +0x8EA2BAAA 0x9588 # 0 +0x8EA2BAAB 0x967C # 0 +0x8EA2BAAC 0x966D # 0 +0x8EA2BAAD 0x966B # 0 +0x8EA2BAAE 0x9671 # 0 +0x8EA2BAAF 0x966F # 0 +0x8EA2BAB0 0x96BF # 0 +0x8EA2BAB1 0x976A # 0 +0x8EA2BAB2 0x9804 # 0 +0x8EA2BAB3 0x98E5 # 0 +0x8EA2BAB4 0x9997 # 0 +0x8EA2BAB5 0x509B # 0 +0x8EA2BAB6 0x5095 # 0 +0x8EA2BAB7 0x5094 # 0 +0x8EA2BAB8 0x509E # 0 +0x8EA2BAB9 0x508B # 0 +0x8EA2BABA 0x50A3 # 0 +0x8EA2BABB 0x5083 # 0 +0x8EA2BABC 0x508C # 0 +0x8EA2BABD 0x508E # 0 +0x8EA2BABE 0x509D # 0 +0x8EA2BABF 0x5068 # 0 +0x8EA2BAC0 0x509C # 0 +0x8EA2BAC1 0x5092 # 0 +0x8EA2BAC2 0x5082 # 0 +0x8EA2BAC3 0x5087 # 0 +0x8EA2BAC4 0x515F # 0 +0x8EA2BAC5 0x51D4 # 0 +0x8EA2BAC6 0x5312 # 0 +0x8EA2BAC7 0x5311 # 0 +0x8EA2BAC8 0x53A4 # 0 +0x8EA2BAC9 0x53A7 # 0 +0x8EA2BACA 0x5591 # 0 +0x8EA2BACB 0x55A8 # 0 +0x8EA2BACC 0x55A5 # 0 +0x8EA2BACD 0x55AD # 0 +0x8EA2BACE 0x5577 # 0 +0x8EA2BACF 0x5645 # 0 +0x8EA2BAD0 0x55A2 # 0 +0x8EA2BAD1 0x5593 # 0 +0x8EA2BAD2 0x5588 # 0 +0x8EA2BAD3 0x558F # 0 +0x8EA2BAD4 0x55B5 # 0 +0x8EA2BAD5 0x5581 # 0 +0x8EA2BAD6 0x55A3 # 0 +0x8EA2BAD7 0x5592 # 0 +0x8EA2BAD8 0x55A4 # 0 +0x8EA2BAD9 0x557D # 0 +0x8EA2BADA 0x558C # 0 +0x8EA2BADB 0x55A6 # 0 +0x8EA2BADC 0x557F # 0 +0x8EA2BADD 0x5595 # 0 +0x8EA2BADE 0x55A1 # 0 +0x8EA2BADF 0x558E # 0 +0x8EA2BAE0 0x570C # 0 +0x8EA2BAE1 0x5829 # 0 +0x8EA2BAE2 0x5837 # 0 +0x8EA2BAE3 0x5819 # 0 +0x8EA2BAE4 0x581E # 0 +0x8EA2BAE5 0x5827 # 0 +0x8EA2BAE6 0x5823 # 0 +0x8EA2BAE7 0x5828 # 0 +0x8EA2BAE8 0x57F5 # 0 +0x8EA2BAE9 0x5848 # 0 +0x8EA2BAEA 0x5825 # 0 +0x8EA2BAEB 0x581C # 0 +0x8EA2BAEC 0x581B # 0 +0x8EA2BAED 0x5833 # 0 +0x8EA2BAEE 0x583F # 0 +0x8EA2BAEF 0x5836 # 0 +0x8EA2BAF0 0x582E # 0 +0x8EA2BAF1 0x5839 # 0 +0x8EA2BAF2 0x5838 # 0 +0x8EA2BAF3 0x582D # 0 +0x8EA2BAF4 0x582C # 0 +0x8EA2BAF5 0x583B # 0 +0x8EA2BAF6 0x5961 # 0 +0x8EA2BAF7 0x5AAF # 0 +0x8EA2BAF8 0x5A94 # 0 +0x8EA2BAF9 0x5A9F # 0 +0x8EA2BAFA 0x5A7A # 0 +0x8EA2BAFB 0x5AA2 # 0 +0x8EA2BAFC 0x5A9E # 0 +0x8EA2BAFD 0x5A78 # 0 +0x8EA2BAFE 0x5AA6 # 0 +0x8EA2BBA1 0x5A7C # 0 +0x8EA2BBA2 0x5AA5 # 0 +0x8EA2BBA3 0x5AAC # 0 +0x8EA2BBA4 0x5A95 # 0 +0x8EA2BBA5 0x5AAE # 0 +0x8EA2BBA6 0x5A37 # 0 +0x8EA2BBA7 0x5A84 # 0 +0x8EA2BBA8 0x5A8A # 0 +0x8EA2BBA9 0x5A97 # 0 +0x8EA2BBAA 0x5A83 # 0 +0x8EA2BBAB 0x5A8B # 0 +0x8EA2BBAC 0x5AA9 # 0 +0x8EA2BBAD 0x5A7B # 0 +0x8EA2BBAE 0x5A7D # 0 +0x8EA2BBAF 0x5A8C # 0 +0x8EA2BBB0 0x5A9C # 0 +0x8EA2BBB1 0x5A8F # 0 +0x8EA2BBB2 0x5A93 # 0 +0x8EA2BBB3 0x5A9D # 0 +0x8EA2BBB4 0x5BEA # 0 +0x8EA2BBB5 0x5BCD # 0 +0x8EA2BBB6 0x5BCB # 0 +0x8EA2BBB7 0x5BD4 # 0 +0x8EA2BBB8 0x5BD1 # 0 +0x8EA2BBB9 0x5BCA # 0 +0x8EA2BBBA 0x5BCE # 0 +0x8EA2BBBB 0x5C0C # 0 +0x8EA2BBBC 0x5C30 # 0 +0x8EA2BBBD 0x5D37 # 0 +0x8EA2BBBE 0x5D43 # 0 +0x8EA2BBBF 0x5D6B # 0 +0x8EA2BBC0 0x5D41 # 0 +0x8EA2BBC1 0x5D4B # 0 +0x8EA2BBC2 0x5D3F # 0 +0x8EA2BBC3 0x5D35 # 0 +0x8EA2BBC4 0x5D51 # 0 +0x8EA2BBC5 0x5D4E # 0 +0x8EA2BBC6 0x5D55 # 0 +0x8EA2BBC7 0x5D33 # 0 +0x8EA2BBC8 0x5D3A # 0 +0x8EA2BBC9 0x5D52 # 0 +0x8EA2BBCA 0x5D3D # 0 +0x8EA2BBCB 0x5D31 # 0 +0x8EA2BBCC 0x5D59 # 0 +0x8EA2BBCD 0x5D42 # 0 +0x8EA2BBCE 0x5D39 # 0 +0x8EA2BBCF 0x5D49 # 0 +0x8EA2BBD0 0x5D38 # 0 +0x8EA2BBD1 0x5D3C # 0 +0x8EA2BBD2 0x5D32 # 0 +0x8EA2BBD3 0x5D36 # 0 +0x8EA2BBD4 0x5D40 # 0 +0x8EA2BBD5 0x5D45 # 0 +0x8EA2BBD6 0x5E44 # 0 +0x8EA2BBD7 0x5E41 # 0 +0x8EA2BBD8 0x5F58 # 0 +0x8EA2BBD9 0x5FA6 # 0 +0x8EA2BBDA 0x5FA5 # 0 +0x8EA2BBDB 0x5FAB # 0 +0x8EA2BBDC 0x60C9 # 0 +0x8EA2BBDD 0x60B9 # 0 +0x8EA2BBDE 0x60CC # 0 +0x8EA2BBDF 0x60E2 # 0 +0x8EA2BBE0 0x60CE # 0 +0x8EA2BBE1 0x60C4 # 0 +0x8EA2BBE2 0x6114 # 0 +0x8EA2BBE3 0x60F2 # 0 +0x8EA2BBE4 0x610A # 0 +0x8EA2BBE5 0x6116 # 0 +0x8EA2BBE6 0x6105 # 0 +0x8EA2BBE7 0x60F5 # 0 +0x8EA2BBE8 0x6113 # 0 +0x8EA2BBE9 0x60F8 # 0 +0x8EA2BBEA 0x60FC # 0 +0x8EA2BBEB 0x60FE # 0 +0x8EA2BBEC 0x60C1 # 0 +0x8EA2BBED 0x6103 # 0 +0x8EA2BBEE 0x6118 # 0 +0x8EA2BBEF 0x611D # 0 +0x8EA2BBF0 0x6110 # 0 +0x8EA2BBF1 0x60FF # 0 +0x8EA2BBF2 0x6104 # 0 +0x8EA2BBF3 0x610B # 0 +0x8EA2BBF4 0x624A # 0 +0x8EA2BBF5 0x6394 # 0 +0x8EA2BBF6 0x63B1 # 0 +0x8EA2BBF7 0x63B0 # 0 +0x8EA2BBF8 0x63CE # 0 +0x8EA2BBF9 0x63E5 # 0 +0x8EA2BBFA 0x63E8 # 0 +0x8EA2BBFB 0x63EF # 0 +0x8EA2BBFC 0x63C3 # 0 +0x8EA2BBFD 0x649D # 0 +0x8EA2BBFE 0x63F3 # 0 +0x8EA2BCA1 0x63CA # 0 +0x8EA2BCA2 0x63E0 # 0 +0x8EA2BCA3 0x63F6 # 0 +0x8EA2BCA4 0x63D5 # 0 +0x8EA2BCA5 0x63F2 # 0 +0x8EA2BCA6 0x63F5 # 0 +0x8EA2BCA7 0x6461 # 0 +0x8EA2BCA8 0x63DF # 0 +0x8EA2BCA9 0x63BE # 0 +0x8EA2BCAA 0x63DD # 0 +0x8EA2BCAB 0x63DC # 0 +0x8EA2BCAC 0x63C4 # 0 +0x8EA2BCAD 0x63D8 # 0 +0x8EA2BCAE 0x63D3 # 0 +0x8EA2BCAF 0x63C2 # 0 +0x8EA2BCB0 0x63C7 # 0 +0x8EA2BCB1 0x63CC # 0 +0x8EA2BCB2 0x63CB # 0 +0x8EA2BCB3 0x63C8 # 0 +0x8EA2BCB4 0x63F0 # 0 +0x8EA2BCB5 0x63D7 # 0 +0x8EA2BCB6 0x63D9 # 0 +0x8EA2BCB7 0x6532 # 0 +0x8EA2BCB8 0x6567 # 0 +0x8EA2BCB9 0x656A # 0 +0x8EA2BCBA 0x6564 # 0 +0x8EA2BCBB 0x655C # 0 +0x8EA2BCBC 0x6568 # 0 +0x8EA2BCBD 0x6565 # 0 +0x8EA2BCBE 0x658C # 0 +0x8EA2BCBF 0x659D # 0 +0x8EA2BCC0 0x659E # 0 +0x8EA2BCC1 0x65AE # 0 +0x8EA2BCC2 0x65D0 # 0 +0x8EA2BCC3 0x65D2 # 0 +0x8EA2BCC4 0x667C # 0 +0x8EA2BCC5 0x666C # 0 +0x8EA2BCC6 0x667B # 0 +0x8EA2BCC7 0x6680 # 0 +0x8EA2BCC8 0x6671 # 0 +0x8EA2BCC9 0x6679 # 0 +0x8EA2BCCA 0x666A # 0 +0x8EA2BCCB 0x6672 # 0 +0x8EA2BCCC 0x6701 # 0 +0x8EA2BCCD 0x690C # 0 +0x8EA2BCCE 0x68D3 # 0 +0x8EA2BCCF 0x6904 # 0 +0x8EA2BCD0 0x68DC # 0 +0x8EA2BCD1 0x692A # 0 +0x8EA2BCD2 0x68EC # 0 +0x8EA2BCD3 0x68EA # 0 +0x8EA2BCD4 0x68F1 # 0 +0x8EA2BCD5 0x690F # 0 +0x8EA2BCD6 0x68D6 # 0 +0x8EA2BCD7 0x68F7 # 0 +0x8EA2BCD8 0x68EB # 0 +0x8EA2BCD9 0x68E4 # 0 +0x8EA2BCDA 0x68F6 # 0 +0x8EA2BCDB 0x6913 # 0 +0x8EA2BCDC 0x6910 # 0 +0x8EA2BCDD 0x68F3 # 0 +0x8EA2BCDE 0x68E1 # 0 +0x8EA2BCDF 0x6907 # 0 +0x8EA2BCE0 0x68CC # 0 +0x8EA2BCE1 0x6908 # 0 +0x8EA2BCE2 0x6970 # 0 +0x8EA2BCE3 0x68B4 # 0 +0x8EA2BCE4 0x6911 # 0 +0x8EA2BCE5 0x68EF # 0 +0x8EA2BCE6 0x68C6 # 0 +0x8EA2BCE7 0x6914 # 0 +0x8EA2BCE8 0x68F8 # 0 +0x8EA2BCE9 0x68D0 # 0 +0x8EA2BCEA 0x68FD # 0 +0x8EA2BCEB 0x68FC # 0 +0x8EA2BCEC 0x68E8 # 0 +0x8EA2BCED 0x690B # 0 +0x8EA2BCEE 0x690A # 0 +0x8EA2BCEF 0x6917 # 0 +0x8EA2BCF0 0x68CE # 0 +0x8EA2BCF1 0x68C8 # 0 +0x8EA2BCF2 0x68DD # 0 +0x8EA2BCF3 0x68DE # 0 +0x8EA2BCF4 0x68E6 # 0 +0x8EA2BCF5 0x68F4 # 0 +0x8EA2BCF6 0x68D1 # 0 +0x8EA2BCF7 0x6906 # 0 +0x8EA2BCF8 0x68D4 # 0 +0x8EA2BCF9 0x68E9 # 0 +0x8EA2BCFA 0x6915 # 0 +0x8EA2BCFB 0x6925 # 0 +0x8EA2BCFC 0x68C7 # 0 +0x8EA2BCFD 0x6B39 # 0 +0x8EA2BCFE 0x6B3B # 0 +0x8EA2BDA1 0x6B3F # 0 +0x8EA2BDA2 0x6B3C # 0 +0x8EA2BDA3 0x6B94 # 0 +0x8EA2BDA4 0x6B97 # 0 +0x8EA2BDA5 0x6B99 # 0 +0x8EA2BDA6 0x6B95 # 0 +0x8EA2BDA7 0x6BBD # 0 +0x8EA2BDA8 0x6BF0 # 0 +0x8EA2BDA9 0x6BF2 # 0 +0x8EA2BDAA 0x6BF3 # 0 +0x8EA2BDAB 0x6C30 # 0 +0x8EA2BDAC 0x6DFC # 0 +0x8EA2BDAD 0x6E46 # 0 +0x8EA2BDAE 0x6E47 # 0 +0x8EA2BDAF 0x6E1F # 0 +0x8EA2BDB0 0x6E49 # 0 +0x8EA2BDB1 0x6E88 # 0 +0x8EA2BDB2 0x6E3C # 0 +0x8EA2BDB3 0x6E3D # 0 +0x8EA2BDB4 0x6E45 # 0 +0x8EA2BDB5 0x6E62 # 0 +0x8EA2BDB6 0x6E2B # 0 +0x8EA2BDB7 0x6E3F # 0 +0x8EA2BDB8 0x6E41 # 0 +0x8EA2BDB9 0x6E5D # 0 +0x8EA2BDBA 0x6E73 # 0 +0x8EA2BDBB 0x6E1C # 0 +0x8EA2BDBC 0x6E33 # 0 +0x8EA2BDBD 0x6E4B # 0 +0x8EA2BDBE 0x6E40 # 0 +0x8EA2BDBF 0x6E51 # 0 +0x8EA2BDC0 0x6E3B # 0 +0x8EA2BDC1 0x6E03 # 0 +0x8EA2BDC2 0x6E2E # 0 +0x8EA2BDC3 0x6E5E # 0 +0x8EA2BDC4 0x6E68 # 0 +0x8EA2BDC5 0x6E5C # 0 +0x8EA2BDC6 0x6E61 # 0 +0x8EA2BDC7 0x6E31 # 0 +0x8EA2BDC8 0x6E28 # 0 +0x8EA2BDC9 0x6E60 # 0 +0x8EA2BDCA 0x6E71 # 0 +0x8EA2BDCB 0x6E6B # 0 +0x8EA2BDCC 0x6E39 # 0 +0x8EA2BDCD 0x6E22 # 0 +0x8EA2BDCE 0x6E30 # 0 +0x8EA2BDCF 0x6E53 # 0 +0x8EA2BDD0 0x6E65 # 0 +0x8EA2BDD1 0x6E27 # 0 +0x8EA2BDD2 0x6E78 # 0 +0x8EA2BDD3 0x6E64 # 0 +0x8EA2BDD4 0x6E77 # 0 +0x8EA2BDD5 0x6E55 # 0 +0x8EA2BDD6 0x6E79 # 0 +0x8EA2BDD7 0x6E52 # 0 +0x8EA2BDD8 0x6E66 # 0 +0x8EA2BDD9 0x6E35 # 0 +0x8EA2BDDA 0x6E36 # 0 +0x8EA2BDDB 0x6E5A # 0 +0x8EA2BDDC 0x7120 # 0 +0x8EA2BDDD 0x711E # 0 +0x8EA2BDDE 0x712F # 0 +0x8EA2BDDF 0x70FB # 0 +0x8EA2BDE0 0x712E # 0 +0x8EA2BDE1 0x7131 # 0 +0x8EA2BDE2 0x7123 # 0 +0x8EA2BDE3 0x7125 # 0 +0x8EA2BDE4 0x7122 # 0 +0x8EA2BDE5 0x7132 # 0 +0x8EA2BDE6 0x711F # 0 +0x8EA2BDE7 0x7128 # 0 +0x8EA2BDE8 0x713A # 0 +0x8EA2BDE9 0x711B # 0 +0x8EA2BDEA 0x724B # 0 +0x8EA2BDEB 0x725A # 0 +0x8EA2BDEC 0x7288 # 0 +0x8EA2BDED 0x7289 # 0 +0x8EA2BDEE 0x7286 # 0 +0x8EA2BDEF 0x7285 # 0 +0x8EA2BDF0 0x728B # 0 +0x8EA2BDF1 0x7312 # 0 +0x8EA2BDF2 0x730B # 0 +0x8EA2BDF3 0x7330 # 0 +0x8EA2BDF4 0x7322 # 0 +0x8EA2BDF5 0x7331 # 0 +0x8EA2BDF6 0x7333 # 0 +0x8EA2BDF7 0x7327 # 0 +0x8EA2BDF8 0x7332 # 0 +0x8EA2BDF9 0x732D # 0 +0x8EA2BDFA 0x7326 # 0 +0x8EA2BDFB 0x7323 # 0 +0x8EA2BDFC 0x7335 # 0 +0x8EA2BDFD 0x730C # 0 +0x8EA2BDFE 0x742E # 0 +0x8EA2BEA1 0x742C # 0 +0x8EA2BEA2 0x7430 # 0 +0x8EA2BEA3 0x742B # 0 +0x8EA2BEA4 0x7416 # 0 +0x8EA2BEA5 0x741A # 0 +0x8EA2BEA6 0x7421 # 0 +0x8EA2BEA7 0x742D # 0 +0x8EA2BEA8 0x7431 # 0 +0x8EA2BEA9 0x7424 # 0 +0x8EA2BEAA 0x7423 # 0 +0x8EA2BEAB 0x741D # 0 +0x8EA2BEAC 0x7429 # 0 +0x8EA2BEAD 0x7420 # 0 +0x8EA2BEAE 0x7432 # 0 +0x8EA2BEAF 0x74FB # 0 +0x8EA2BEB0 0x752F # 0 +0x8EA2BEB1 0x756F # 0 +0x8EA2BEB2 0x756C # 0 +0x8EA2BEB3 0x75E7 # 0 +0x8EA2BEB4 0x75DA # 0 +0x8EA2BEB5 0x75E1 # 0 +0x8EA2BEB6 0x75E6 # 0 +0x8EA2BEB7 0x75DD # 0 +0x8EA2BEB8 0x75DF # 0 +0x8EA2BEB9 0x75E4 # 0 +0x8EA2BEBA 0x75D7 # 0 +0x8EA2BEBB 0x7695 # 0 +0x8EA2BEBC 0x7692 # 0 +0x8EA2BEBD 0x76DA # 0 +0x8EA2BEBE 0x7746 # 0 +0x8EA2BEBF 0x7747 # 0 +0x8EA2BEC0 0x7744 # 0 +0x8EA2BEC1 0x774D # 0 +0x8EA2BEC2 0x7745 # 0 +0x8EA2BEC3 0x774A # 0 +0x8EA2BEC4 0x774E # 0 +0x8EA2BEC5 0x774B # 0 +0x8EA2BEC6 0x774C # 0 +0x8EA2BEC7 0x77DE # 0 +0x8EA2BEC8 0x77EC # 0 +0x8EA2BEC9 0x7860 # 0 +0x8EA2BECA 0x7864 # 0 +0x8EA2BECB 0x7865 # 0 +0x8EA2BECC 0x785C # 0 +0x8EA2BECD 0x786D # 0 +0x8EA2BECE 0x7871 # 0 +0x8EA2BECF 0x786A # 0 +0x8EA2BED0 0x786E # 0 +0x8EA2BED1 0x7870 # 0 +0x8EA2BED2 0x7869 # 0 +0x8EA2BED3 0x7868 # 0 +0x8EA2BED4 0x785E # 0 +0x8EA2BED5 0x7862 # 0 +0x8EA2BED6 0x7974 # 0 +0x8EA2BED7 0x7973 # 0 +0x8EA2BED8 0x7972 # 0 +0x8EA2BED9 0x7970 # 0 +0x8EA2BEDA 0x7A02 # 0 +0x8EA2BEDB 0x7A0A # 0 +0x8EA2BEDC 0x7A03 # 0 +0x8EA2BEDD 0x7A0C # 0 +0x8EA2BEDE 0x7A04 # 0 +0x8EA2BEDF 0x7A99 # 0 +0x8EA2BEE0 0x7AE6 # 0 +0x8EA2BEE1 0x7AE4 # 0 +0x8EA2BEE2 0x7B4A # 0 +0x8EA2BEE3 0x7B47 # 0 +0x8EA2BEE4 0x7B44 # 0 +0x8EA2BEE5 0x7B48 # 0 +0x8EA2BEE6 0x7B4C # 0 +0x8EA2BEE7 0x7B4E # 0 +0x8EA2BEE8 0x7B40 # 0 +0x8EA2BEE9 0x7B58 # 0 +0x8EA2BEEA 0x7B45 # 0 +0x8EA2BEEB 0x7CA2 # 0 +0x8EA2BEEC 0x7C9E # 0 +0x8EA2BEED 0x7CA8 # 0 +0x8EA2BEEE 0x7CA1 # 0 +0x8EA2BEEF 0x7D58 # 0 +0x8EA2BEF0 0x7D6F # 0 +0x8EA2BEF1 0x7D63 # 0 +0x8EA2BEF2 0x7D53 # 0 +0x8EA2BEF3 0x7D56 # 0 +0x8EA2BEF4 0x7D67 # 0 +0x8EA2BEF5 0x7D6A # 0 +0x8EA2BEF6 0x7D4F # 0 +0x8EA2BEF7 0x7D6D # 0 +0x8EA2BEF8 0x7D5C # 0 +0x8EA2BEF9 0x7D6B # 0 +0x8EA2BEFA 0x7D52 # 0 +0x8EA2BEFB 0x7D54 # 0 +0x8EA2BEFC 0x7D69 # 0 +0x8EA2BEFD 0x7D51 # 0 +0x8EA2BEFE 0x7D5F # 0 +0x8EA2BFA1 0x7D4E # 0 +0x8EA2BFA2 0x7F3E # 0 +0x8EA2BFA3 0x7F3F # 0 +0x8EA2BFA4 0x7F65 # 0 +0x8EA2BFA5 0x7F66 # 0 +0x8EA2BFA6 0x7FA2 # 0 +0x8EA2BFA7 0x7FA0 # 0 +0x8EA2BFA8 0x7FA1 # 0 +0x8EA2BFA9 0x7FD7 # 0 +0x8EA2BFAA 0x8051 # 0 +0x8EA2BFAB 0x804F # 0 +0x8EA2BFAC 0x8050 # 0 +0x8EA2BFAD 0x80FE # 0 +0x8EA2BFAE 0x80D4 # 0 +0x8EA2BFAF 0x8143 # 0 +0x8EA2BFB0 0x814A # 0 +0x8EA2BFB1 0x8152 # 0 +0x8EA2BFB2 0x814F # 0 +0x8EA2BFB3 0x8147 # 0 +0x8EA2BFB4 0x813D # 0 +0x8EA2BFB5 0x814D # 0 +0x8EA2BFB6 0x813A # 0 +0x8EA2BFB7 0x81E6 # 0 +0x8EA2BFB8 0x81EE # 0 +0x8EA2BFB9 0x81F7 # 0 +0x8EA2BFBA 0x81F8 # 0 +0x8EA2BFBB 0x81F9 # 0 +0x8EA2BFBC 0x8204 # 0 +0x8EA2BFBD 0x823C # 0 +0x8EA2BFBE 0x823D # 0 +0x8EA2BFBF 0x823F # 0 +0x8EA2BFC0 0x8275 # 0 +0x8EA2BFC1 0x833B # 0 +0x8EA2BFC2 0x83CF # 0 +0x8EA2BFC3 0x83F9 # 0 +0x8EA2BFC4 0x8423 # 0 +0x8EA2BFC5 0x83C0 # 0 +0x8EA2BFC6 0x83E8 # 0 +0x8EA2BFC7 0x8412 # 0 +0x8EA2BFC8 0x83E7 # 0 +0x8EA2BFC9 0x83E4 # 0 +0x8EA2BFCA 0x83FC # 0 +0x8EA2BFCB 0x83F6 # 0 +0x8EA2BFCC 0x8410 # 0 +0x8EA2BFCD 0x83C6 # 0 +0x8EA2BFCE 0x83C8 # 0 +0x8EA2BFCF 0x83EB # 0 +0x8EA2BFD0 0x83E3 # 0 +0x8EA2BFD1 0x83BF # 0 +0x8EA2BFD2 0x8401 # 0 +0x8EA2BFD3 0x83DD # 0 +0x8EA2BFD4 0x83E5 # 0 +0x8EA2BFD5 0x83D8 # 0 +0x8EA2BFD6 0x83FF # 0 +0x8EA2BFD7 0x83E1 # 0 +0x8EA2BFD8 0x83CB # 0 +0x8EA2BFD9 0x83CE # 0 +0x8EA2BFDA 0x83D6 # 0 +0x8EA2BFDB 0x83F5 # 0 +0x8EA2BFDC 0x83C9 # 0 +0x8EA2BFDD 0x8409 # 0 +0x8EA2BFDE 0x840F # 0 +0x8EA2BFDF 0x83DE # 0 +0x8EA2BFE0 0x8411 # 0 +0x8EA2BFE1 0x8406 # 0 +0x8EA2BFE2 0x83C2 # 0 +0x8EA2BFE3 0x83F3 # 0 +0x8EA2BFE4 0x83D5 # 0 +0x8EA2BFE5 0x83FA # 0 +0x8EA2BFE6 0x83C7 # 0 +0x8EA2BFE7 0x83D1 # 0 +0x8EA2BFE8 0x83EA # 0 +0x8EA2BFE9 0x8413 # 0 +0x8EA2BFEA 0x839A # 0 +0x8EA2BFEB 0x83C3 # 0 +0x8EA2BFEC 0x83EC # 0 +0x8EA2BFED 0x83EE # 0 +0x8EA2BFEE 0x83C4 # 0 +0x8EA2BFEF 0x83FB # 0 +0x8EA2BFF0 0x83D7 # 0 +0x8EA2BFF1 0x83E2 # 0 +0x8EA2BFF2 0x841B # 0 +0x8EA2BFF3 0x83DB # 0 +0x8EA2BFF4 0x83FE # 0 +0x8EA2BFF5 0x86D8 # 0 +0x8EA2BFF6 0x86E2 # 0 +0x8EA2BFF7 0x86E6 # 0 +0x8EA2BFF8 0x86D3 # 0 +0x8EA2BFF9 0x86E3 # 0 +0x8EA2BFFA 0x86DA # 0 +0x8EA2BFFB 0x86EA # 0 +0x8EA2BFFC 0x86DD # 0 +0x8EA2BFFD 0x86EB # 0 +0x8EA2BFFE 0x86DC # 0 +0x8EA2C0A1 0x86EC # 0 +0x8EA2C0A2 0x86E9 # 0 +0x8EA2C0A3 0x86D7 # 0 +0x8EA2C0A4 0x86E8 # 0 +0x8EA2C0A5 0x86D1 # 0 +0x8EA2C0A6 0x8848 # 0 +0x8EA2C0A7 0x8856 # 0 +0x8EA2C0A8 0x8855 # 0 +0x8EA2C0A9 0x88BA # 0 +0x8EA2C0AA 0x88D7 # 0 +0x8EA2C0AB 0x88B9 # 0 +0x8EA2C0AC 0x88B8 # 0 +0x8EA2C0AD 0x88C0 # 0 +0x8EA2C0AE 0x88BE # 0 +0x8EA2C0AF 0x88B6 # 0 +0x8EA2C0B0 0x88BC # 0 +0x8EA2C0B1 0x88B7 # 0 +0x8EA2C0B2 0x88BD # 0 +0x8EA2C0B3 0x88B2 # 0 +0x8EA2C0B4 0x8901 # 0 +0x8EA2C0B5 0x88C9 # 0 +0x8EA2C0B6 0x8995 # 0 +0x8EA2C0B7 0x8998 # 0 +0x8EA2C0B8 0x8997 # 0 +0x8EA2C0B9 0x89DD # 0 +0x8EA2C0BA 0x89DA # 0 +0x8EA2C0BB 0x89DB # 0 +0x8EA2C0BC 0x8A4E # 0 +0x8EA2C0BD 0x8A4D # 0 +0x8EA2C0BE 0x8A39 # 0 +0x8EA2C0BF 0x8A59 # 0 +0x8EA2C0C0 0x8A40 # 0 +0x8EA2C0C1 0x8A57 # 0 +0x8EA2C0C2 0x8A58 # 0 +0x8EA2C0C3 0x8A44 # 0 +0x8EA2C0C4 0x8A45 # 0 +0x8EA2C0C5 0x8A52 # 0 +0x8EA2C0C6 0x8A48 # 0 +0x8EA2C0C7 0x8A51 # 0 +0x8EA2C0C8 0x8A4A # 0 +0x8EA2C0C9 0x8A4C # 0 +0x8EA2C0CA 0x8A4F # 0 +0x8EA2C0CB 0x8C5F # 0 +0x8EA2C0CC 0x8C81 # 0 +0x8EA2C0CD 0x8C80 # 0 +0x8EA2C0CE 0x8CBA # 0 +0x8EA2C0CF 0x8CBE # 0 +0x8EA2C0D0 0x8CB0 # 0 +0x8EA2C0D1 0x8CB9 # 0 +0x8EA2C0D2 0x8CB5 # 0 +0x8EA2C0D3 0x8D84 # 0 +0x8EA2C0D4 0x8D80 # 0 +0x8EA2C0D5 0x8D89 # 0 +0x8EA2C0D6 0x8DD8 # 0 +0x8EA2C0D7 0x8DD3 # 0 +0x8EA2C0D8 0x8DCD # 0 +0x8EA2C0D9 0x8DC7 # 0 +0x8EA2C0DA 0x8DD6 # 0 +0x8EA2C0DB 0x8DDC # 0 +0x8EA2C0DC 0x8DCF # 0 +0x8EA2C0DD 0x8DD5 # 0 +0x8EA2C0DE 0x8DD9 # 0 +0x8EA2C0DF 0x8DC8 # 0 +0x8EA2C0E0 0x8DD7 # 0 +0x8EA2C0E1 0x8DC5 # 0 +0x8EA2C0E2 0x8EEF # 0 +0x8EA2C0E3 0x8EF7 # 0 +0x8EA2C0E4 0x8EFA # 0 +0x8EA2C0E5 0x8EF9 # 0 +0x8EA2C0E6 0x8EE6 # 0 +0x8EA2C0E7 0x8EEE # 0 +0x8EA2C0E8 0x8EE5 # 0 +0x8EA2C0E9 0x8EF5 # 0 +0x8EA2C0EA 0x8EE7 # 0 +0x8EA2C0EB 0x8EE8 # 0 +0x8EA2C0EC 0x8EF6 # 0 +0x8EA2C0ED 0x8EEB # 0 +0x8EA2C0EE 0x8EF1 # 0 +0x8EA2C0EF 0x8EEC # 0 +0x8EA2C0F0 0x8EF4 # 0 +0x8EA2C0F1 0x8EE9 # 0 +0x8EA2C0F2 0x902D # 0 +0x8EA2C0F3 0x9034 # 0 +0x8EA2C0F4 0x902F # 0 +0x8EA2C0F5 0x9106 # 0 +0x8EA2C0F6 0x912C # 0 +0x8EA2C0F7 0x9104 # 0 +0x8EA2C0F8 0x90FF # 0 +0x8EA2C0F9 0x90FC # 0 +0x8EA2C0FA 0x9108 # 0 +0x8EA2C0FB 0x90F9 # 0 +0x8EA2C0FC 0x90FB # 0 +0x8EA2C0FD 0x9101 # 0 +0x8EA2C0FE 0x9100 # 0 +0x8EA2C1A1 0x9107 # 0 +0x8EA2C1A2 0x9105 # 0 +0x8EA2C1A3 0x9103 # 0 +0x8EA2C1A4 0x9161 # 0 +0x8EA2C1A5 0x9164 # 0 +0x8EA2C1A6 0x915F # 0 +0x8EA2C1A7 0x9162 # 0 +0x8EA2C1A8 0x9160 # 0 +0x8EA2C1A9 0x9201 # 0 +0x8EA2C1AA 0x920A # 0 +0x8EA2C1AB 0x9225 # 0 +0x8EA2C1AC 0x9203 # 0 +0x8EA2C1AD 0x921A # 0 +0x8EA2C1AE 0x9226 # 0 +0x8EA2C1AF 0x920F # 0 +0x8EA2C1B0 0x920C # 0 +0x8EA2C1B1 0x9200 # 0 +0x8EA2C1B2 0x9212 # 0 +0x8EA2C1B3 0x91FF # 0 +0x8EA2C1B4 0x91FD # 0 +0x8EA2C1B5 0x9206 # 0 +0x8EA2C1B6 0x9204 # 0 +0x8EA2C1B7 0x9227 # 0 +0x8EA2C1B8 0x9202 # 0 +0x8EA2C1B9 0x921C # 0 +0x8EA2C1BA 0x9224 # 0 +0x8EA2C1BB 0x9219 # 0 +0x8EA2C1BC 0x9217 # 0 +0x8EA2C1BD 0x9205 # 0 +0x8EA2C1BE 0x9216 # 0 +0x8EA2C1BF 0x957B # 0 +0x8EA2C1C0 0x958D # 0 +0x8EA2C1C1 0x958C # 0 +0x8EA2C1C2 0x9590 # 0 +0x8EA2C1C3 0x9687 # 0 +0x8EA2C1C4 0x967E # 0 +0x8EA2C1C5 0x9688 # 0 +0x8EA2C1C6 0x9689 # 0 +0x8EA2C1C7 0x9683 # 0 +0x8EA2C1C8 0x9680 # 0 +0x8EA2C1C9 0x96C2 # 0 +0x8EA2C1CA 0x96C8 # 0 +0x8EA2C1CB 0x96C3 # 0 +0x8EA2C1CC 0x96F1 # 0 +0x8EA2C1CD 0x96F0 # 0 +0x8EA2C1CE 0x976C # 0 +0x8EA2C1CF 0x9770 # 0 +0x8EA2C1D0 0x976E # 0 +0x8EA2C1D1 0x9807 # 0 +0x8EA2C1D2 0x98A9 # 0 +0x8EA2C1D3 0x98EB # 0 +0x8EA2C1D4 0x9CE6 # 0 +0x8EA2C1D5 0x9EF9 # 0 +0x8EA2C1D6 0x4E83 # 0 +0x8EA2C1D7 0x4E84 # 0 +0x8EA2C1D8 0x4EB6 # 0 +0x8EA2C1D9 0x50BD # 0 +0x8EA2C1DA 0x50BF # 0 +0x8EA2C1DB 0x50C6 # 0 +0x8EA2C1DC 0x50AE # 0 +0x8EA2C1DD 0x50C4 # 0 +0x8EA2C1DE 0x50CA # 0 +0x8EA2C1DF 0x50B4 # 0 +0x8EA2C1E0 0x50C8 # 0 +0x8EA2C1E1 0x50C2 # 0 +0x8EA2C1E2 0x50B0 # 0 +0x8EA2C1E3 0x50C1 # 0 +0x8EA2C1E4 0x50BA # 0 +0x8EA2C1E5 0x50B1 # 0 +0x8EA2C1E6 0x50CB # 0 +0x8EA2C1E7 0x50C9 # 0 +0x8EA2C1E8 0x50B6 # 0 +0x8EA2C1E9 0x50B8 # 0 +0x8EA2C1EA 0x51D7 # 0 +0x8EA2C1EB 0x527A # 0 +0x8EA2C1EC 0x5278 # 0 +0x8EA2C1ED 0x527B # 0 +0x8EA2C1EE 0x527C # 0 +0x8EA2C1EF 0x55C3 # 0 +0x8EA2C1F0 0x55DB # 0 +0x8EA2C1F1 0x55CC # 0 +0x8EA2C1F2 0x55D0 # 0 +0x8EA2C1F3 0x55CB # 0 +0x8EA2C1F4 0x55CA # 0 +0x8EA2C1F5 0x55DD # 0 +0x8EA2C1F6 0x55C0 # 0 +0x8EA2C1F7 0x55D4 # 0 +0x8EA2C1F8 0x55C4 # 0 +0x8EA2C1F9 0x55E9 # 0 +0x8EA2C1FA 0x55BF # 0 +0x8EA2C1FB 0x55D2 # 0 +0x8EA2C1FC 0x558D # 0 +0x8EA2C1FD 0x55CF # 0 +0x8EA2C1FE 0x55D5 # 0 +0x8EA2C2A1 0x55E2 # 0 +0x8EA2C2A2 0x55D6 # 0 +0x8EA2C2A3 0x55C8 # 0 +0x8EA2C2A4 0x55F2 # 0 +0x8EA2C2A5 0x55CD # 0 +0x8EA2C2A6 0x55D9 # 0 +0x8EA2C2A7 0x55C2 # 0 +0x8EA2C2A8 0x5714 # 0 +0x8EA2C2A9 0x5853 # 0 +0x8EA2C2AA 0x5868 # 0 +0x8EA2C2AB 0x5864 # 0 +0x8EA2C2AC 0x584F # 0 +0x8EA2C2AD 0x584D # 0 +0x8EA2C2AE 0x5849 # 0 +0x8EA2C2AF 0x586F # 0 +0x8EA2C2B0 0x5855 # 0 +0x8EA2C2B1 0x584E # 0 +0x8EA2C2B2 0x585D # 0 +0x8EA2C2B3 0x5859 # 0 +0x8EA2C2B4 0x5865 # 0 +0x8EA2C2B5 0x585B # 0 +0x8EA2C2B6 0x583D # 0 +0x8EA2C2B7 0x5863 # 0 +0x8EA2C2B8 0x5871 # 0 +0x8EA2C2B9 0x58FC # 0 +0x8EA2C2BA 0x5AC7 # 0 +0x8EA2C2BB 0x5AC4 # 0 +0x8EA2C2BC 0x5ACB # 0 +0x8EA2C2BD 0x5ABA # 0 +0x8EA2C2BE 0x5AB8 # 0 +0x8EA2C2BF 0x5AB1 # 0 +0x8EA2C2C0 0x5AB5 # 0 +0x8EA2C2C1 0x5AB0 # 0 +0x8EA2C2C2 0x5ABF # 0 +0x8EA2C2C3 0x5AC8 # 0 +0x8EA2C2C4 0x5ABB # 0 +0x8EA2C2C5 0x5AC6 # 0 +0x8EA2C2C6 0x5AB7 # 0 +0x8EA2C2C7 0x5AC0 # 0 +0x8EA2C2C8 0x5ACA # 0 +0x8EA2C2C9 0x5AB4 # 0 +0x8EA2C2CA 0x5AB6 # 0 +0x8EA2C2CB 0x5ACD # 0 +0x8EA2C2CC 0x5AB9 # 0 +0x8EA2C2CD 0x5A90 # 0 +0x8EA2C2CE 0x5BD6 # 0 +0x8EA2C2CF 0x5BD8 # 0 +0x8EA2C2D0 0x5BD9 # 0 +0x8EA2C2D1 0x5C1F # 0 +0x8EA2C2D2 0x5C33 # 0 +0x8EA2C2D3 0x5D71 # 0 +0x8EA2C2D4 0x5D63 # 0 +0x8EA2C2D5 0x5D4A # 0 +0x8EA2C2D6 0x5D65 # 0 +0x8EA2C2D7 0x5D72 # 0 +0x8EA2C2D8 0x5D6C # 0 +0x8EA2C2D9 0x5D5E # 0 +0x8EA2C2DA 0x5D68 # 0 +0x8EA2C2DB 0x5D67 # 0 +0x8EA2C2DC 0x5D62 # 0 +0x8EA2C2DD 0x5DF0 # 0 +0x8EA2C2DE 0x5E4F # 0 +0x8EA2C2DF 0x5E4E # 0 +0x8EA2C2E0 0x5E4A # 0 +0x8EA2C2E1 0x5E4D # 0 +0x8EA2C2E2 0x5E4B # 0 +0x8EA2C2E3 0x5EC5 # 0 +0x8EA2C2E4 0x5ECC # 0 +0x8EA2C2E5 0x5EC6 # 0 +0x8EA2C2E6 0x5ECB # 0 +0x8EA2C2E7 0x5EC7 # 0 +0x8EA2C2E8 0x5F40 # 0 +0x8EA2C2E9 0x5FAF # 0 +0x8EA2C2EA 0x5FAD # 0 +0x8EA2C2EB 0x60F7 # 0 +0x8EA2C2EC 0x6149 # 0 +0x8EA2C2ED 0x614A # 0 +0x8EA2C2EE 0x612B # 0 +0x8EA2C2EF 0x6145 # 0 +0x8EA2C2F0 0x6136 # 0 +0x8EA2C2F1 0x6132 # 0 +0x8EA2C2F2 0x612E # 0 +0x8EA2C2F3 0x6146 # 0 +0x8EA2C2F4 0x612F # 0 +0x8EA2C2F5 0x614F # 0 +0x8EA2C2F6 0x6129 # 0 +0x8EA2C2F7 0x6140 # 0 +0x8EA2C2F8 0x6220 # 0 +0x8EA2C2F9 0x9168 # 0 +0x8EA2C2FA 0x6223 # 0 +0x8EA2C2FB 0x6225 # 0 +0x8EA2C2FC 0x6224 # 0 +0x8EA2C2FD 0x63C5 # 0 +0x8EA2C2FE 0x63F1 # 0 +0x8EA2C3A1 0x63EB # 0 +0x8EA2C3A2 0x6410 # 0 +0x8EA2C3A3 0x6412 # 0 +0x8EA2C3A4 0x6409 # 0 +0x8EA2C3A5 0x6420 # 0 +0x8EA2C3A6 0x6424 # 0 +0x8EA2C3A7 0x6433 # 0 +0x8EA2C3A8 0x6443 # 0 +0x8EA2C3A9 0x641F # 0 +0x8EA2C3AA 0x6415 # 0 +0x8EA2C3AB 0x6418 # 0 +0x8EA2C3AC 0x6439 # 0 +0x8EA2C3AD 0x6437 # 0 +0x8EA2C3AE 0x6422 # 0 +0x8EA2C3AF 0x6423 # 0 +0x8EA2C3B0 0x640C # 0 +0x8EA2C3B1 0x6426 # 0 +0x8EA2C3B2 0x6430 # 0 +0x8EA2C3B3 0x6428 # 0 +0x8EA2C3B4 0x6441 # 0 +0x8EA2C3B5 0x6435 # 0 +0x8EA2C3B6 0x642F # 0 +0x8EA2C3B7 0x640A # 0 +0x8EA2C3B8 0x641A # 0 +0x8EA2C3B9 0x6440 # 0 +0x8EA2C3BA 0x6425 # 0 +0x8EA2C3BB 0x6427 # 0 +0x8EA2C3BC 0x640B # 0 +0x8EA2C3BD 0x63E7 # 0 +0x8EA2C3BE 0x641B # 0 +0x8EA2C3BF 0x642E # 0 +0x8EA2C3C0 0x6421 # 0 +0x8EA2C3C1 0x640E # 0 +0x8EA2C3C2 0x656F # 0 +0x8EA2C3C3 0x6592 # 0 +0x8EA2C3C4 0x65D3 # 0 +0x8EA2C3C5 0x6686 # 0 +0x8EA2C3C6 0x668C # 0 +0x8EA2C3C7 0x6695 # 0 +0x8EA2C3C8 0x6690 # 0 +0x8EA2C3C9 0x668B # 0 +0x8EA2C3CA 0x668A # 0 +0x8EA2C3CB 0x6699 # 0 +0x8EA2C3CC 0x6694 # 0 +0x8EA2C3CD 0x6678 # 0 +0x8EA2C3CE 0x6720 # 0 +0x8EA2C3CF 0x6966 # 0 +0x8EA2C3D0 0x695F # 0 +0x8EA2C3D1 0x6938 # 0 +0x8EA2C3D2 0x694E # 0 +0x8EA2C3D3 0x6962 # 0 +0x8EA2C3D4 0x6971 # 0 +0x8EA2C3D5 0x693F # 0 +0x8EA2C3D6 0x6945 # 0 +0x8EA2C3D7 0x696A # 0 +0x8EA2C3D8 0x6939 # 0 +0x8EA2C3D9 0x6942 # 0 +0x8EA2C3DA 0x6957 # 0 +0x8EA2C3DB 0x6959 # 0 +0x8EA2C3DC 0x697A # 0 +0x8EA2C3DD 0x6948 # 0 +0x8EA2C3DE 0x6949 # 0 +0x8EA2C3DF 0x6935 # 0 +0x8EA2C3E0 0x696C # 0 +0x8EA2C3E1 0x6933 # 0 +0x8EA2C3E2 0x693D # 0 +0x8EA2C3E3 0x6965 # 0 +0x8EA2C3E4 0x68F0 # 0 +0x8EA2C3E5 0x6978 # 0 +0x8EA2C3E6 0x6934 # 0 +0x8EA2C3E7 0x6969 # 0 +0x8EA2C3E8 0x6940 # 0 +0x8EA2C3E9 0x696F # 0 +0x8EA2C3EA 0x6944 # 0 +0x8EA2C3EB 0x6976 # 0 +0x8EA2C3EC 0x6958 # 0 +0x8EA2C3ED 0x6941 # 0 +0x8EA2C3EE 0x6974 # 0 +0x8EA2C3EF 0x694C # 0 +0x8EA2C3F0 0x693B # 0 +0x8EA2C3F1 0x694B # 0 +0x8EA2C3F2 0x6937 # 0 +0x8EA2C3F3 0x695C # 0 +0x8EA2C3F4 0x694F # 0 +0x8EA2C3F5 0x6951 # 0 +0x8EA2C3F6 0x6932 # 0 +0x8EA2C3F7 0x6952 # 0 +0x8EA2C3F8 0x692F # 0 +0x8EA2C3F9 0x697B # 0 +0x8EA2C3FA 0x693C # 0 +0x8EA2C3FB 0x6B46 # 0 +0x8EA2C3FC 0x6B45 # 0 +0x8EA2C3FD 0x6B43 # 0 +0x8EA2C3FE 0x6B42 # 0 +0x8EA2C4A1 0x6B48 # 0 +0x8EA2C4A2 0x6B41 # 0 +0x8EA2C4A3 0x6B9B # 0 +0x8EA2C4A4 0x6BFB # 0 +0x8EA2C4A5 0x6BFC # 0 +0x8EA2C4A6 0x6BF9 # 0 +0x8EA2C4A7 0x6BF7 # 0 +0x8EA2C4A8 0x6BF8 # 0 +0x8EA2C4A9 0x6E9B # 0 +0x8EA2C4AA 0x6ED6 # 0 +0x8EA2C4AB 0x6EC8 # 0 +0x8EA2C4AC 0x6E8F # 0 +0x8EA2C4AD 0x6EC0 # 0 +0x8EA2C4AE 0x6E9F # 0 +0x8EA2C4AF 0x6E93 # 0 +0x8EA2C4B0 0x6E94 # 0 +0x8EA2C4B1 0x6EA0 # 0 +0x8EA2C4B2 0x6EB1 # 0 +0x8EA2C4B3 0x6EB9 # 0 +0x8EA2C4B4 0x6EC6 # 0 +0x8EA2C4B5 0x6ED2 # 0 +0x8EA2C4B6 0x6EBD # 0 +0x8EA2C4B7 0x6EC1 # 0 +0x8EA2C4B8 0x6E9E # 0 +0x8EA2C4B9 0x6EC9 # 0 +0x8EA2C4BA 0x6EB7 # 0 +0x8EA2C4BB 0x6EB0 # 0 +0x8EA2C4BC 0x6ECD # 0 +0x8EA2C4BD 0x6EA6 # 0 +0x8EA2C4BE 0x6ECF # 0 +0x8EA2C4BF 0x6EB2 # 0 +0x8EA2C4C0 0x6EBE # 0 +0x8EA2C4C1 0x6EC3 # 0 +0x8EA2C4C2 0x6EDC # 0 +0x8EA2C4C3 0x6ED8 # 0 +0x8EA2C4C4 0x6E99 # 0 +0x8EA2C4C5 0x6E92 # 0 +0x8EA2C4C6 0x6E8E # 0 +0x8EA2C4C7 0x6E8D # 0 +0x8EA2C4C8 0x6EA4 # 0 +0x8EA2C4C9 0x6EA1 # 0 +0x8EA2C4CA 0x6EBF # 0 +0x8EA2C4CB 0x6EB3 # 0 +0x8EA2C4CC 0x6ED0 # 0 +0x8EA2C4CD 0x6ECA # 0 +0x8EA2C4CE 0x6E97 # 0 +0x8EA2C4CF 0x6EAE # 0 +0x8EA2C4D0 0x6EA3 # 0 +0x8EA2C4D1 0x7147 # 0 +0x8EA2C4D2 0x7154 # 0 +0x8EA2C4D3 0x7152 # 0 +0x8EA2C4D4 0x7163 # 0 +0x8EA2C4D5 0x7160 # 0 +0x8EA2C4D6 0x7141 # 0 +0x8EA2C4D7 0x715D # 0 +0x8EA2C4D8 0x7162 # 0 +0x8EA2C4D9 0x7172 # 0 +0x8EA2C4DA 0x7178 # 0 +0x8EA2C4DB 0x716A # 0 +0x8EA2C4DC 0x7161 # 0 +0x8EA2C4DD 0x7142 # 0 +0x8EA2C4DE 0x7158 # 0 +0x8EA2C4DF 0x7143 # 0 +0x8EA2C4E0 0x714B # 0 +0x8EA2C4E1 0x7170 # 0 +0x8EA2C4E2 0x715F # 0 +0x8EA2C4E3 0x7150 # 0 +0x8EA2C4E4 0x7153 # 0 +0x8EA2C4E5 0x7144 # 0 +0x8EA2C4E6 0x714D # 0 +0x8EA2C4E7 0x715A # 0 +0x8EA2C4E8 0x724F # 0 +0x8EA2C4E9 0x728D # 0 +0x8EA2C4EA 0x728C # 0 +0x8EA2C4EB 0x7291 # 0 +0x8EA2C4EC 0x7290 # 0 +0x8EA2C4ED 0x728E # 0 +0x8EA2C4EE 0x733C # 0 +0x8EA2C4EF 0x7342 # 0 +0x8EA2C4F0 0x733B # 0 +0x8EA2C4F1 0x733A # 0 +0x8EA2C4F2 0x7340 # 0 +0x8EA2C4F3 0x734A # 0 +0x8EA2C4F4 0x7349 # 0 +0x8EA2C4F5 0x7444 # 0 +0x8EA2C4F6 0x744A # 0 +0x8EA2C4F7 0x744B # 0 +0x8EA2C4F8 0x7452 # 0 +0x8EA2C4F9 0x7451 # 0 +0x8EA2C4FA 0x7457 # 0 +0x8EA2C4FB 0x7440 # 0 +0x8EA2C4FC 0x744F # 0 +0x8EA2C4FD 0x7450 # 0 +0x8EA2C4FE 0x744E # 0 +0x8EA2C5A1 0x7442 # 0 +0x8EA2C5A2 0x7446 # 0 +0x8EA2C5A3 0x744D # 0 +0x8EA2C5A4 0x7454 # 0 +0x8EA2C5A5 0x74E1 # 0 +0x8EA2C5A6 0x74FF # 0 +0x8EA2C5A7 0x74FE # 0 +0x8EA2C5A8 0x74FD # 0 +0x8EA2C5A9 0x751D # 0 +0x8EA2C5AA 0x7579 # 0 +0x8EA2C5AB 0x7577 # 0 +0x8EA2C5AC 0x6983 # 0 +0x8EA2C5AD 0x75EF # 0 +0x8EA2C5AE 0x760F # 0 +0x8EA2C5AF 0x7603 # 0 +0x8EA2C5B0 0x75F7 # 0 +0x8EA2C5B1 0x75FE # 0 +0x8EA2C5B2 0x75FC # 0 +0x8EA2C5B3 0x75F9 # 0 +0x8EA2C5B4 0x75F8 # 0 +0x8EA2C5B5 0x7610 # 0 +0x8EA2C5B6 0x75FB # 0 +0x8EA2C5B7 0x75F6 # 0 +0x8EA2C5B8 0x75ED # 0 +0x8EA2C5B9 0x75F5 # 0 +0x8EA2C5BA 0x75FD # 0 +0x8EA2C5BB 0x7699 # 0 +0x8EA2C5BC 0x76B5 # 0 +0x8EA2C5BD 0x76DD # 0 +0x8EA2C5BE 0x7755 # 0 +0x8EA2C5BF 0x775F # 0 +0x8EA2C5C0 0x7760 # 0 +0x8EA2C5C1 0x7752 # 0 +0x8EA2C5C2 0x7756 # 0 +0x8EA2C5C3 0x775A # 0 +0x8EA2C5C4 0x7769 # 0 +0x8EA2C5C5 0x7767 # 0 +0x8EA2C5C6 0x7754 # 0 +0x8EA2C5C7 0x7759 # 0 +0x8EA2C5C8 0x776D # 0 +0x8EA2C5C9 0x77E0 # 0 +0x8EA2C5CA 0x7887 # 0 +0x8EA2C5CB 0x789A # 0 +0x8EA2C5CC 0x7894 # 0 +0x8EA2C5CD 0x788F # 0 +0x8EA2C5CE 0x7884 # 0 +0x8EA2C5CF 0x7895 # 0 +0x8EA2C5D0 0x7885 # 0 +0x8EA2C5D1 0x7886 # 0 +0x8EA2C5D2 0x78A1 # 0 +0x8EA2C5D3 0x7883 # 0 +0x8EA2C5D4 0x7879 # 0 +0x8EA2C5D5 0x7899 # 0 +0x8EA2C5D6 0x7880 # 0 +0x8EA2C5D7 0x7896 # 0 +0x8EA2C5D8 0x787B # 0 +0x8EA2C5D9 0x797C # 0 +0x8EA2C5DA 0x7982 # 0 +0x8EA2C5DB 0x797D # 0 +0x8EA2C5DC 0x7979 # 0 +0x8EA2C5DD 0x7A11 # 0 +0x8EA2C5DE 0x7A18 # 0 +0x8EA2C5DF 0x7A19 # 0 +0x8EA2C5E0 0x7A12 # 0 +0x8EA2C5E1 0x7A17 # 0 +0x8EA2C5E2 0x7A15 # 0 +0x8EA2C5E3 0x7A22 # 0 +0x8EA2C5E4 0x7A13 # 0 +0x8EA2C5E5 0x7A1B # 0 +0x8EA2C5E6 0x7A10 # 0 +0x8EA2C5E7 0x7AA3 # 0 +0x8EA2C5E8 0x7AA2 # 0 +0x8EA2C5E9 0x7A9E # 0 +0x8EA2C5EA 0x7AEB # 0 +0x8EA2C5EB 0x7B66 # 0 +0x8EA2C5EC 0x7B64 # 0 +0x8EA2C5ED 0x7B6D # 0 +0x8EA2C5EE 0x7B74 # 0 +0x8EA2C5EF 0x7B69 # 0 +0x8EA2C5F0 0x7B72 # 0 +0x8EA2C5F1 0x7B65 # 0 +0x8EA2C5F2 0x7B73 # 0 +0x8EA2C5F3 0x7B71 # 0 +0x8EA2C5F4 0x7B70 # 0 +0x8EA2C5F5 0x7B61 # 0 +0x8EA2C5F6 0x7B78 # 0 +0x8EA2C5F7 0x7B76 # 0 +0x8EA2C5F8 0x7B63 # 0 +0x8EA2C5F9 0x7CB2 # 0 +0x8EA2C5FA 0x7CB4 # 0 +0x8EA2C5FB 0x7CAF # 0 +0x8EA2C5FC 0x7D88 # 0 +0x8EA2C5FD 0x7D86 # 0 +0x8EA2C5FE 0x7D80 # 0 +0x8EA2C6A1 0x7D8D # 0 +0x8EA2C6A2 0x7D7F # 0 +0x8EA2C6A3 0x7D85 # 0 +0x8EA2C6A4 0x7D7A # 0 +0x8EA2C6A5 0x7D8E # 0 +0x8EA2C6A6 0x7D7B # 0 +0x8EA2C6A7 0x7D83 # 0 +0x8EA2C6A8 0x7D7C # 0 +0x8EA2C6A9 0x7D8C # 0 +0x8EA2C6AA 0x7D94 # 0 +0x8EA2C6AB 0x7D84 # 0 +0x8EA2C6AC 0x7D7D # 0 +0x8EA2C6AD 0x7D92 # 0 +0x8EA2C6AE 0x7F6D # 0 +0x8EA2C6AF 0x7F6B # 0 +0x8EA2C6B0 0x7F67 # 0 +0x8EA2C6B1 0x7F68 # 0 +0x8EA2C6B2 0x7F6C # 0 +0x8EA2C6B3 0x7FA6 # 0 +0x8EA2C6B4 0x7FA5 # 0 +0x8EA2C6B5 0x7FA7 # 0 +0x8EA2C6B6 0x7FDB # 0 +0x8EA2C6B7 0x7FDC # 0 +0x8EA2C6B8 0x8021 # 0 +0x8EA2C6B9 0x8164 # 0 +0x8EA2C6BA 0x8160 # 0 +0x8EA2C6BB 0x8177 # 0 +0x8EA2C6BC 0x815C # 0 +0x8EA2C6BD 0x8169 # 0 +0x8EA2C6BE 0x815B # 0 +0x8EA2C6BF 0x8162 # 0 +0x8EA2C6C0 0x8172 # 0 +0x8EA2C6C1 0x6721 # 0 +0x8EA2C6C2 0x815E # 0 +0x8EA2C6C3 0x8176 # 0 +0x8EA2C6C4 0x8167 # 0 +0x8EA2C6C5 0x816F # 0 +0x8EA2C6C6 0x8144 # 0 +0x8EA2C6C7 0x8161 # 0 +0x8EA2C6C8 0x821D # 0 +0x8EA2C6C9 0x8249 # 0 +0x8EA2C6CA 0x8244 # 0 +0x8EA2C6CB 0x8240 # 0 +0x8EA2C6CC 0x8242 # 0 +0x8EA2C6CD 0x8245 # 0 +0x8EA2C6CE 0x84F1 # 0 +0x8EA2C6CF 0x843F # 0 +0x8EA2C6D0 0x8456 # 0 +0x8EA2C6D1 0x8476 # 0 +0x8EA2C6D2 0x8479 # 0 +0x8EA2C6D3 0x848F # 0 +0x8EA2C6D4 0x848D # 0 +0x8EA2C6D5 0x8465 # 0 +0x8EA2C6D6 0x8451 # 0 +0x8EA2C6D7 0x8440 # 0 +0x8EA2C6D8 0x8486 # 0 +0x8EA2C6D9 0x8467 # 0 +0x8EA2C6DA 0x8430 # 0 +0x8EA2C6DB 0x844D # 0 +0x8EA2C6DC 0x847D # 0 +0x8EA2C6DD 0x845A # 0 +0x8EA2C6DE 0x8459 # 0 +0x8EA2C6DF 0x8474 # 0 +0x8EA2C6E0 0x8473 # 0 +0x8EA2C6E1 0x845D # 0 +0x8EA2C6E2 0x8507 # 0 +0x8EA2C6E3 0x845E # 0 +0x8EA2C6E4 0x8437 # 0 +0x8EA2C6E5 0x843A # 0 +0x8EA2C6E6 0x8434 # 0 +0x8EA2C6E7 0x847A # 0 +0x8EA2C6E8 0x8443 # 0 +0x8EA2C6E9 0x8478 # 0 +0x8EA2C6EA 0x8432 # 0 +0x8EA2C6EB 0x8445 # 0 +0x8EA2C6EC 0x8429 # 0 +0x8EA2C6ED 0x83D9 # 0 +0x8EA2C6EE 0x844B # 0 +0x8EA2C6EF 0x842F # 0 +0x8EA2C6F0 0x8442 # 0 +0x8EA2C6F1 0x842D # 0 +0x8EA2C6F2 0x845F # 0 +0x8EA2C6F3 0x8470 # 0 +0x8EA2C6F4 0x8439 # 0 +0x8EA2C6F5 0x844E # 0 +0x8EA2C6F6 0x844C # 0 +0x8EA2C6F7 0x8452 # 0 +0x8EA2C6F8 0x846F # 0 +0x8EA2C6F9 0x84C5 # 0 +0x8EA2C6FA 0x848E # 0 +0x8EA2C6FB 0x843B # 0 +0x8EA2C6FC 0x8447 # 0 +0x8EA2C6FD 0x8436 # 0 +0x8EA2C6FE 0x8433 # 0 +0x8EA2C7A1 0x8468 # 0 +0x8EA2C7A2 0x847E # 0 +0x8EA2C7A3 0x8444 # 0 +0x8EA2C7A4 0x842B # 0 +0x8EA2C7A5 0x8460 # 0 +0x8EA2C7A6 0x8454 # 0 +0x8EA2C7A7 0x846E # 0 +0x8EA2C7A8 0x8450 # 0 +0x8EA2C7A9 0x870B # 0 +0x8EA2C7AA 0x8704 # 0 +0x8EA2C7AB 0x86F7 # 0 +0x8EA2C7AC 0x870C # 0 +0x8EA2C7AD 0x86FA # 0 +0x8EA2C7AE 0x86D6 # 0 +0x8EA2C7AF 0x86F5 # 0 +0x8EA2C7B0 0x874D # 0 +0x8EA2C7B1 0x86F8 # 0 +0x8EA2C7B2 0x870E # 0 +0x8EA2C7B3 0x8709 # 0 +0x8EA2C7B4 0x8701 # 0 +0x8EA2C7B5 0x86F6 # 0 +0x8EA2C7B6 0x870D # 0 +0x8EA2C7B7 0x8705 # 0 +0x8EA2C7B8 0x88D6 # 0 +0x8EA2C7B9 0x88CB # 0 +0x8EA2C7BA 0x88CD # 0 +0x8EA2C7BB 0x88CE # 0 +0x8EA2C7BC 0x88DE # 0 +0x8EA2C7BD 0x88DB # 0 +0x8EA2C7BE 0x88DA # 0 +0x8EA2C7BF 0x88CC # 0 +0x8EA2C7C0 0x88D0 # 0 +0x8EA2C7C1 0x8985 # 0 +0x8EA2C7C2 0x899B # 0 +0x8EA2C7C3 0x89DF # 0 +0x8EA2C7C4 0x89E5 # 0 +0x8EA2C7C5 0x89E4 # 0 +0x8EA2C7C6 0x89E1 # 0 +0x8EA2C7C7 0x89E0 # 0 +0x8EA2C7C8 0x89E2 # 0 +0x8EA2C7C9 0x89DC # 0 +0x8EA2C7CA 0x89E6 # 0 +0x8EA2C7CB 0x8A76 # 0 +0x8EA2C7CC 0x8A86 # 0 +0x8EA2C7CD 0x8A7F # 0 +0x8EA2C7CE 0x8A61 # 0 +0x8EA2C7CF 0x8A3F # 0 +0x8EA2C7D0 0x8A77 # 0 +0x8EA2C7D1 0x8A82 # 0 +0x8EA2C7D2 0x8A84 # 0 +0x8EA2C7D3 0x8A75 # 0 +0x8EA2C7D4 0x8A83 # 0 +0x8EA2C7D5 0x8A81 # 0 +0x8EA2C7D6 0x8A74 # 0 +0x8EA2C7D7 0x8A7A # 0 +0x8EA2C7D8 0x8C3C # 0 +0x8EA2C7D9 0x8C4B # 0 +0x8EA2C7DA 0x8C4A # 0 +0x8EA2C7DB 0x8C65 # 0 +0x8EA2C7DC 0x8C64 # 0 +0x8EA2C7DD 0x8C66 # 0 +0x8EA2C7DE 0x8C86 # 0 +0x8EA2C7DF 0x8C84 # 0 +0x8EA2C7E0 0x8C85 # 0 +0x8EA2C7E1 0x8CCC # 0 +0x8EA2C7E2 0x8D68 # 0 +0x8EA2C7E3 0x8D69 # 0 +0x8EA2C7E4 0x8D91 # 0 +0x8EA2C7E5 0x8D8C # 0 +0x8EA2C7E6 0x8D8E # 0 +0x8EA2C7E7 0x8D8F # 0 +0x8EA2C7E8 0x8D8D # 0 +0x8EA2C7E9 0x8D93 # 0 +0x8EA2C7EA 0x8D94 # 0 +0x8EA2C7EB 0x8D90 # 0 +0x8EA2C7EC 0x8D92 # 0 +0x8EA2C7ED 0x8DF0 # 0 +0x8EA2C7EE 0x8DE0 # 0 +0x8EA2C7EF 0x8DEC # 0 +0x8EA2C7F0 0x8DF1 # 0 +0x8EA2C7F1 0x8DEE # 0 +0x8EA2C7F2 0x8DD0 # 0 +0x8EA2C7F3 0x8DE9 # 0 +0x8EA2C7F4 0x8DE3 # 0 +0x8EA2C7F5 0x8DE2 # 0 +0x8EA2C7F6 0x8DE7 # 0 +0x8EA2C7F7 0x8DF2 # 0 +0x8EA2C7F8 0x8DEB # 0 +0x8EA2C7F9 0x8DF4 # 0 +0x8EA2C7FA 0x8F06 # 0 +0x8EA2C7FB 0x8EFF # 0 +0x8EA2C7FC 0x8F01 # 0 +0x8EA2C7FD 0x8F00 # 0 +0x8EA2C7FE 0x8F05 # 0 +0x8EA2C8A1 0x8F07 # 0 +0x8EA2C8A2 0x8F08 # 0 +0x8EA2C8A3 0x8F02 # 0 +0x8EA2C8A4 0x8F0B # 0 +0x8EA2C8A5 0x9052 # 0 +0x8EA2C8A6 0x903F # 0 +0x8EA2C8A7 0x9044 # 0 +0x8EA2C8A8 0x9049 # 0 +0x8EA2C8A9 0x903D # 0 +0x8EA2C8AA 0x9110 # 0 +0x8EA2C8AB 0x910D # 0 +0x8EA2C8AC 0x910F # 0 +0x8EA2C8AD 0x9111 # 0 +0x8EA2C8AE 0x9116 # 0 +0x8EA2C8AF 0x9114 # 0 +0x8EA2C8B0 0x910B # 0 +0x8EA2C8B1 0x910E # 0 +0x8EA2C8B2 0x916E # 0 +0x8EA2C8B3 0x916F # 0 +0x8EA2C8B4 0x9248 # 0 +0x8EA2C8B5 0x9252 # 0 +0x8EA2C8B6 0x9230 # 0 +0x8EA2C8B7 0x923A # 0 +0x8EA2C8B8 0x9266 # 0 +0x8EA2C8B9 0x9233 # 0 +0x8EA2C8BA 0x9265 # 0 +0x8EA2C8BB 0x925E # 0 +0x8EA2C8BC 0x9283 # 0 +0x8EA2C8BD 0x922E # 0 +0x8EA2C8BE 0x924A # 0 +0x8EA2C8BF 0x9246 # 0 +0x8EA2C8C0 0x926D # 0 +0x8EA2C8C1 0x926C # 0 +0x8EA2C8C2 0x924F # 0 +0x8EA2C8C3 0x9260 # 0 +0x8EA2C8C4 0x9267 # 0 +0x8EA2C8C5 0x926F # 0 +0x8EA2C8C6 0x9236 # 0 +0x8EA2C8C7 0x9261 # 0 +0x8EA2C8C8 0x9270 # 0 +0x8EA2C8C9 0x9231 # 0 +0x8EA2C8CA 0x9254 # 0 +0x8EA2C8CB 0x9263 # 0 +0x8EA2C8CC 0x9250 # 0 +0x8EA2C8CD 0x9272 # 0 +0x8EA2C8CE 0x924E # 0 +0x8EA2C8CF 0x9253 # 0 +0x8EA2C8D0 0x924C # 0 +0x8EA2C8D1 0x9256 # 0 +0x8EA2C8D2 0x9232 # 0 +0x8EA2C8D3 0x959F # 0 +0x8EA2C8D4 0x959C # 0 +0x8EA2C8D5 0x959E # 0 +0x8EA2C8D6 0x959B # 0 +0x8EA2C8D7 0x9692 # 0 +0x8EA2C8D8 0x9693 # 0 +0x8EA2C8D9 0x9691 # 0 +0x8EA2C8DA 0x9697 # 0 +0x8EA2C8DB 0x96CE # 0 +0x8EA2C8DC 0x96FA # 0 +0x8EA2C8DD 0x96FD # 0 +0x8EA2C8DE 0x96F8 # 0 +0x8EA2C8DF 0x96F5 # 0 +0x8EA2C8E0 0x9773 # 0 +0x8EA2C8E1 0x9777 # 0 +0x8EA2C8E2 0x9778 # 0 +0x8EA2C8E3 0x9772 # 0 +0x8EA2C8E4 0x980F # 0 +0x8EA2C8E5 0x980D # 0 +0x8EA2C8E6 0x980E # 0 +0x8EA2C8E7 0x98AC # 0 +0x8EA2C8E8 0x98F6 # 0 +0x8EA2C8E9 0x98F9 # 0 +0x8EA2C8EA 0x99AF # 0 +0x8EA2C8EB 0x99B2 # 0 +0x8EA2C8EC 0x99B0 # 0 +0x8EA2C8ED 0x99B5 # 0 +0x8EA2C8EE 0x9AAD # 0 +0x8EA2C8EF 0x9AAB # 0 +0x8EA2C8F0 0x9B5B # 0 +0x8EA2C8F1 0x9CEA # 0 +0x8EA2C8F2 0x9CED # 0 +0x8EA2C8F3 0x9CE7 # 0 +0x8EA2C8F4 0x9E80 # 0 +0x8EA2C8F5 0x9EFD # 0 +0x8EA2C8F6 0x50E6 # 0 +0x8EA2C8F7 0x50D4 # 0 +0x8EA2C8F8 0x50D7 # 0 +0x8EA2C8F9 0x50E8 # 0 +0x8EA2C8FA 0x50F3 # 0 +0x8EA2C8FB 0x50DB # 0 +0x8EA2C8FC 0x50EA # 0 +0x8EA2C8FD 0x50DD # 0 +0x8EA2C8FE 0x50E4 # 0 +0x8EA2C9A1 0x50D3 # 0 +0x8EA2C9A2 0x50EC # 0 +0x8EA2C9A3 0x50F0 # 0 +0x8EA2C9A4 0x50EF # 0 +0x8EA2C9A5 0x50E3 # 0 +0x8EA2C9A6 0x50E0 # 0 +0x8EA2C9A7 0x51D8 # 0 +0x8EA2C9A8 0x5280 # 0 +0x8EA2C9A9 0x5281 # 0 +0x8EA2C9AA 0x52E9 # 0 +0x8EA2C9AB 0x52EB # 0 +0x8EA2C9AC 0x5330 # 0 +0x8EA2C9AD 0x53AC # 0 +0x8EA2C9AE 0x5627 # 0 +0x8EA2C9AF 0x5615 # 0 +0x8EA2C9B0 0x560C # 0 +0x8EA2C9B1 0x5612 # 0 +0x8EA2C9B2 0x55FC # 0 +0x8EA2C9B3 0x560F # 0 +0x8EA2C9B4 0x561C # 0 +0x8EA2C9B5 0x5601 # 0 +0x8EA2C9B6 0x5613 # 0 +0x8EA2C9B7 0x5602 # 0 +0x8EA2C9B8 0x55FA # 0 +0x8EA2C9B9 0x561D # 0 +0x8EA2C9BA 0x5604 # 0 +0x8EA2C9BB 0x55FF # 0 +0x8EA2C9BC 0x55F9 # 0 +0x8EA2C9BD 0x5889 # 0 +0x8EA2C9BE 0x587C # 0 +0x8EA2C9BF 0x5890 # 0 +0x8EA2C9C0 0x5898 # 0 +0x8EA2C9C1 0x5886 # 0 +0x8EA2C9C2 0x5881 # 0 +0x8EA2C9C3 0x587F # 0 +0x8EA2C9C4 0x5874 # 0 +0x8EA2C9C5 0x588B # 0 +0x8EA2C9C6 0x587A # 0 +0x8EA2C9C7 0x5887 # 0 +0x8EA2C9C8 0x5891 # 0 +0x8EA2C9C9 0x588E # 0 +0x8EA2C9CA 0x5876 # 0 +0x8EA2C9CB 0x5882 # 0 +0x8EA2C9CC 0x5888 # 0 +0x8EA2C9CD 0x587B # 0 +0x8EA2C9CE 0x5894 # 0 +0x8EA2C9CF 0x588F # 0 +0x8EA2C9D0 0x58FE # 0 +0x8EA2C9D1 0x596B # 0 +0x8EA2C9D2 0x5ADC # 0 +0x8EA2C9D3 0x5AEE # 0 +0x8EA2C9D4 0x5AE5 # 0 +0x8EA2C9D5 0x5AD5 # 0 +0x8EA2C9D6 0x5AEA # 0 +0x8EA2C9D7 0x5ADA # 0 +0x8EA2C9D8 0x5AED # 0 +0x8EA2C9D9 0x5AEB # 0 +0x8EA2C9DA 0x5AF3 # 0 +0x8EA2C9DB 0x5AE2 # 0 +0x8EA2C9DC 0x5AE0 # 0 +0x8EA2C9DD 0x5ADB # 0 +0x8EA2C9DE 0x5AEC # 0 +0x8EA2C9DF 0x5ADE # 0 +0x8EA2C9E0 0x5ADD # 0 +0x8EA2C9E1 0x5AD9 # 0 +0x8EA2C9E2 0x5AE8 # 0 +0x8EA2C9E3 0x5ADF # 0 +0x8EA2C9E4 0x5B77 # 0 +0x8EA2C9E5 0x5BE0 # 0 +0x8EA2C9E6 0x5BE3 # 0 +0x8EA2C9E7 0x5C63 # 0 +0x8EA2C9E8 0x5D82 # 0 +0x8EA2C9E9 0x5D80 # 0 +0x8EA2C9EA 0x5D7D # 0 +0x8EA2C9EB 0x5D86 # 0 +0x8EA2C9EC 0x5D7A # 0 +0x8EA2C9ED 0x5D81 # 0 +0x8EA2C9EE 0x5D77 # 0 +0x8EA2C9EF 0x5D8A # 0 +0x8EA2C9F0 0x5D89 # 0 +0x8EA2C9F1 0x5D88 # 0 +0x8EA2C9F2 0x5D7E # 0 +0x8EA2C9F3 0x5D7C # 0 +0x8EA2C9F4 0x5D8D # 0 +0x8EA2C9F5 0x5D79 # 0 +0x8EA2C9F6 0x5D7F # 0 +0x8EA2C9F7 0x5E58 # 0 +0x8EA2C9F8 0x5E59 # 0 +0x8EA2C9F9 0x5E53 # 0 +0x8EA2C9FA 0x5ED8 # 0 +0x8EA2C9FB 0x5ED1 # 0 +0x8EA2C9FC 0x5ED7 # 0 +0x8EA2C9FD 0x5ECE # 0 +0x8EA2C9FE 0x5EDC # 0 +0x8EA2CAA1 0x5ED5 # 0 +0x8EA2CAA2 0x5ED9 # 0 +0x8EA2CAA3 0x5ED2 # 0 +0x8EA2CAA4 0x5ED4 # 0 +0x8EA2CAA5 0x5F44 # 0 +0x8EA2CAA6 0x5F43 # 0 +0x8EA2CAA7 0x5F6F # 0 +0x8EA2CAA8 0x5FB6 # 0 +0x8EA2CAA9 0x612C # 0 +0x8EA2CAAA 0x6128 # 0 +0x8EA2CAAB 0x6141 # 0 +0x8EA2CAAC 0x615E # 0 +0x8EA2CAAD 0x6171 # 0 +0x8EA2CAAE 0x6173 # 0 +0x8EA2CAAF 0x6152 # 0 +0x8EA2CAB0 0x6153 # 0 +0x8EA2CAB1 0x6172 # 0 +0x8EA2CAB2 0x616C # 0 +0x8EA2CAB3 0x6180 # 0 +0x8EA2CAB4 0x6174 # 0 +0x8EA2CAB5 0x6154 # 0 +0x8EA2CAB6 0x617A # 0 +0x8EA2CAB7 0x615B # 0 +0x8EA2CAB8 0x6165 # 0 +0x8EA2CAB9 0x613B # 0 +0x8EA2CABA 0x616A # 0 +0x8EA2CABB 0x6161 # 0 +0x8EA2CABC 0x6156 # 0 +0x8EA2CABD 0x6229 # 0 +0x8EA2CABE 0x6227 # 0 +0x8EA2CABF 0x622B # 0 +0x8EA2CAC0 0x642B # 0 +0x8EA2CAC1 0x644D # 0 +0x8EA2CAC2 0x645B # 0 +0x8EA2CAC3 0x645D # 0 +0x8EA2CAC4 0x6474 # 0 +0x8EA2CAC5 0x6476 # 0 +0x8EA2CAC6 0x6472 # 0 +0x8EA2CAC7 0x6473 # 0 +0x8EA2CAC8 0x647D # 0 +0x8EA2CAC9 0x6475 # 0 +0x8EA2CACA 0x6466 # 0 +0x8EA2CACB 0x64A6 # 0 +0x8EA2CACC 0x644E # 0 +0x8EA2CACD 0x6482 # 0 +0x8EA2CACE 0x645E # 0 +0x8EA2CACF 0x645C # 0 +0x8EA2CAD0 0x644B # 0 +0x8EA2CAD1 0x6453 # 0 +0x8EA2CAD2 0x6460 # 0 +0x8EA2CAD3 0x6450 # 0 +0x8EA2CAD4 0x647F # 0 +0x8EA2CAD5 0x643F # 0 +0x8EA2CAD6 0x646C # 0 +0x8EA2CAD7 0x646B # 0 +0x8EA2CAD8 0x6459 # 0 +0x8EA2CAD9 0x6465 # 0 +0x8EA2CADA 0x6477 # 0 +0x8EA2CADB 0x6573 # 0 +0x8EA2CADC 0x65A0 # 0 +0x8EA2CADD 0x66A1 # 0 +0x8EA2CADE 0x66A0 # 0 +0x8EA2CADF 0x669F # 0 +0x8EA2CAE0 0x6705 # 0 +0x8EA2CAE1 0x6704 # 0 +0x8EA2CAE2 0x6722 # 0 +0x8EA2CAE3 0x69B1 # 0 +0x8EA2CAE4 0x69B6 # 0 +0x8EA2CAE5 0x69C9 # 0 +0x8EA2CAE6 0x69A0 # 0 +0x8EA2CAE7 0x69CE # 0 +0x8EA2CAE8 0x6996 # 0 +0x8EA2CAE9 0x69B0 # 0 +0x8EA2CAEA 0x69AC # 0 +0x8EA2CAEB 0x69BC # 0 +0x8EA2CAEC 0x6991 # 0 +0x8EA2CAED 0x6999 # 0 +0x8EA2CAEE 0x698E # 0 +0x8EA2CAEF 0x69A7 # 0 +0x8EA2CAF0 0x698D # 0 +0x8EA2CAF1 0x69A9 # 0 +0x8EA2CAF2 0x69BE # 0 +0x8EA2CAF3 0x69AF # 0 +0x8EA2CAF4 0x69BF # 0 +0x8EA2CAF5 0x69C4 # 0 +0x8EA2CAF6 0x69BD # 0 +0x8EA2CAF7 0x69A4 # 0 +0x8EA2CAF8 0x69D4 # 0 +0x8EA2CAF9 0x69B9 # 0 +0x8EA2CAFA 0x69CA # 0 +0x8EA2CAFB 0x699A # 0 +0x8EA2CAFC 0x69CF # 0 +0x8EA2CAFD 0x69B3 # 0 +0x8EA2CAFE 0x6993 # 0 +0x8EA2CBA1 0x69AA # 0 +0x8EA2CBA2 0x69A1 # 0 +0x8EA2CBA3 0x699E # 0 +0x8EA2CBA4 0x69D9 # 0 +0x8EA2CBA5 0x6997 # 0 +0x8EA2CBA6 0x6990 # 0 +0x8EA2CBA7 0x69C2 # 0 +0x8EA2CBA8 0x69B5 # 0 +0x8EA2CBA9 0x69A5 # 0 +0x8EA2CBAA 0x69C6 # 0 +0x8EA2CBAB 0x6B4A # 0 +0x8EA2CBAC 0x6B4D # 0 +0x8EA2CBAD 0x6B4B # 0 +0x8EA2CBAE 0x6B9E # 0 +0x8EA2CBAF 0x6B9F # 0 +0x8EA2CBB0 0x6BA0 # 0 +0x8EA2CBB1 0x6BC3 # 0 +0x8EA2CBB2 0x6BC4 # 0 +0x8EA2CBB3 0x6BFE # 0 +0x8EA2CBB4 0x6ECE # 0 +0x8EA2CBB5 0x6EF5 # 0 +0x8EA2CBB6 0x6EF1 # 0 +0x8EA2CBB7 0x6F03 # 0 +0x8EA2CBB8 0x6F25 # 0 +0x8EA2CBB9 0x6EF8 # 0 +0x8EA2CBBA 0x6F37 # 0 +0x8EA2CBBB 0x6EFB # 0 +0x8EA2CBBC 0x6F2E # 0 +0x8EA2CBBD 0x6F09 # 0 +0x8EA2CBBE 0x6F4E # 0 +0x8EA2CBBF 0x6F19 # 0 +0x8EA2CBC0 0x6F1A # 0 +0x8EA2CBC1 0x6F27 # 0 +0x8EA2CBC2 0x6F18 # 0 +0x8EA2CBC3 0x6F3B # 0 +0x8EA2CBC4 0x6F12 # 0 +0x8EA2CBC5 0x6EED # 0 +0x8EA2CBC6 0x6F0A # 0 +0x8EA2CBC7 0x6F36 # 0 +0x8EA2CBC8 0x6F73 # 0 +0x8EA2CBC9 0x6EF9 # 0 +0x8EA2CBCA 0x6EEE # 0 +0x8EA2CBCB 0x6F2D # 0 +0x8EA2CBCC 0x6F40 # 0 +0x8EA2CBCD 0x6F30 # 0 +0x8EA2CBCE 0x6F3C # 0 +0x8EA2CBCF 0x6F35 # 0 +0x8EA2CBD0 0x6EEB # 0 +0x8EA2CBD1 0x6F07 # 0 +0x8EA2CBD2 0x6F0E # 0 +0x8EA2CBD3 0x6F43 # 0 +0x8EA2CBD4 0x6F05 # 0 +0x8EA2CBD5 0x6EFD # 0 +0x8EA2CBD6 0x6EF6 # 0 +0x8EA2CBD7 0x6F39 # 0 +0x8EA2CBD8 0x6F1C # 0 +0x8EA2CBD9 0x6EFC # 0 +0x8EA2CBDA 0x6F3A # 0 +0x8EA2CBDB 0x6F1F # 0 +0x8EA2CBDC 0x6F0D # 0 +0x8EA2CBDD 0x6F1E # 0 +0x8EA2CBDE 0x6F08 # 0 +0x8EA2CBDF 0x6F21 # 0 +0x8EA2CBE0 0x7187 # 0 +0x8EA2CBE1 0x7190 # 0 +0x8EA2CBE2 0x7189 # 0 +0x8EA2CBE3 0x7180 # 0 +0x8EA2CBE4 0x7185 # 0 +0x8EA2CBE5 0x7182 # 0 +0x8EA2CBE6 0x718F # 0 +0x8EA2CBE7 0x717B # 0 +0x8EA2CBE8 0x7186 # 0 +0x8EA2CBE9 0x7181 # 0 +0x8EA2CBEA 0x7197 # 0 +0x8EA2CBEB 0x7244 # 0 +0x8EA2CBEC 0x7253 # 0 +0x8EA2CBED 0x7297 # 0 +0x8EA2CBEE 0x7295 # 0 +0x8EA2CBEF 0x7293 # 0 +0x8EA2CBF0 0x7343 # 0 +0x8EA2CBF1 0x734D # 0 +0x8EA2CBF2 0x7351 # 0 +0x8EA2CBF3 0x734C # 0 +0x8EA2CBF4 0x7462 # 0 +0x8EA2CBF5 0x7473 # 0 +0x8EA2CBF6 0x7471 # 0 +0x8EA2CBF7 0x7475 # 0 +0x8EA2CBF8 0x7472 # 0 +0x8EA2CBF9 0x7467 # 0 +0x8EA2CBFA 0x746E # 0 +0x8EA2CBFB 0x7500 # 0 +0x8EA2CBFC 0x7502 # 0 +0x8EA2CBFD 0x7503 # 0 +0x8EA2CBFE 0x757D # 0 +0x8EA2CCA1 0x7590 # 0 +0x8EA2CCA2 0x7616 # 0 +0x8EA2CCA3 0x7608 # 0 +0x8EA2CCA4 0x760C # 0 +0x8EA2CCA5 0x7615 # 0 +0x8EA2CCA6 0x7611 # 0 +0x8EA2CCA7 0x760A # 0 +0x8EA2CCA8 0x7614 # 0 +0x8EA2CCA9 0x76B8 # 0 +0x8EA2CCAA 0x7781 # 0 +0x8EA2CCAB 0x777C # 0 +0x8EA2CCAC 0x7785 # 0 +0x8EA2CCAD 0x7782 # 0 +0x8EA2CCAE 0x776E # 0 +0x8EA2CCAF 0x7780 # 0 +0x8EA2CCB0 0x776F # 0 +0x8EA2CCB1 0x777E # 0 +0x8EA2CCB2 0x7783 # 0 +0x8EA2CCB3 0x78B2 # 0 +0x8EA2CCB4 0x78AA # 0 +0x8EA2CCB5 0x78B4 # 0 +0x8EA2CCB6 0x78AD # 0 +0x8EA2CCB7 0x78A8 # 0 +0x8EA2CCB8 0x787E # 0 +0x8EA2CCB9 0x78AB # 0 +0x8EA2CCBA 0x789E # 0 +0x8EA2CCBB 0x78A5 # 0 +0x8EA2CCBC 0x78A0 # 0 +0x8EA2CCBD 0x78AC # 0 +0x8EA2CCBE 0x78A2 # 0 +0x8EA2CCBF 0x78A4 # 0 +0x8EA2CCC0 0x7998 # 0 +0x8EA2CCC1 0x798A # 0 +0x8EA2CCC2 0x798B # 0 +0x8EA2CCC3 0x7996 # 0 +0x8EA2CCC4 0x7995 # 0 +0x8EA2CCC5 0x7994 # 0 +0x8EA2CCC6 0x7993 # 0 +0x8EA2CCC7 0x7997 # 0 +0x8EA2CCC8 0x7988 # 0 +0x8EA2CCC9 0x7992 # 0 +0x8EA2CCCA 0x7990 # 0 +0x8EA2CCCB 0x7A2B # 0 +0x8EA2CCCC 0x7A4A # 0 +0x8EA2CCCD 0x7A30 # 0 +0x8EA2CCCE 0x7A2F # 0 +0x8EA2CCCF 0x7A28 # 0 +0x8EA2CCD0 0x7A26 # 0 +0x8EA2CCD1 0x7AA8 # 0 +0x8EA2CCD2 0x7AAB # 0 +0x8EA2CCD3 0x7AAC # 0 +0x8EA2CCD4 0x7AEE # 0 +0x8EA2CCD5 0x7B88 # 0 +0x8EA2CCD6 0x7B9C # 0 +0x8EA2CCD7 0x7B8A # 0 +0x8EA2CCD8 0x7B91 # 0 +0x8EA2CCD9 0x7B90 # 0 +0x8EA2CCDA 0x7B96 # 0 +0x8EA2CCDB 0x7B8D # 0 +0x8EA2CCDC 0x7B8C # 0 +0x8EA2CCDD 0x7B9B # 0 +0x8EA2CCDE 0x7B8E # 0 +0x8EA2CCDF 0x7B85 # 0 +0x8EA2CCE0 0x7B98 # 0 +0x8EA2CCE1 0x5284 # 0 +0x8EA2CCE2 0x7B99 # 0 +0x8EA2CCE3 0x7BA4 # 0 +0x8EA2CCE4 0x7B82 # 0 +0x8EA2CCE5 0x7CBB # 0 +0x8EA2CCE6 0x7CBF # 0 +0x8EA2CCE7 0x7CBC # 0 +0x8EA2CCE8 0x7CBA # 0 +0x8EA2CCE9 0x7DA7 # 0 +0x8EA2CCEA 0x7DB7 # 0 +0x8EA2CCEB 0x7DC2 # 0 +0x8EA2CCEC 0x7DA3 # 0 +0x8EA2CCED 0x7DAA # 0 +0x8EA2CCEE 0x7DC1 # 0 +0x8EA2CCEF 0x7DC0 # 0 +0x8EA2CCF0 0x7DC5 # 0 +0x8EA2CCF1 0x7D9D # 0 +0x8EA2CCF2 0x7DCE # 0 +0x8EA2CCF3 0x7DC4 # 0 +0x8EA2CCF4 0x7DC6 # 0 +0x8EA2CCF5 0x7DCB # 0 +0x8EA2CCF6 0x7DCC # 0 +0x8EA2CCF7 0x7DAF # 0 +0x8EA2CCF8 0x7DB9 # 0 +0x8EA2CCF9 0x7D96 # 0 +0x8EA2CCFA 0x7DBC # 0 +0x8EA2CCFB 0x7D9F # 0 +0x8EA2CCFC 0x7DA6 # 0 +0x8EA2CCFD 0x7DAE # 0 +0x8EA2CCFE 0x7DA9 # 0 +0x8EA2CDA1 0x7DA1 # 0 +0x8EA2CDA2 0x7DC9 # 0 +0x8EA2CDA3 0x7F73 # 0 +0x8EA2CDA4 0x7FE2 # 0 +0x8EA2CDA5 0x7FE3 # 0 +0x8EA2CDA6 0x7FE5 # 0 +0x8EA2CDA7 0x7FDE # 0 +0x8EA2CDA8 0x8024 # 0 +0x8EA2CDA9 0x805D # 0 +0x8EA2CDAA 0x805C # 0 +0x8EA2CDAB 0x8189 # 0 +0x8EA2CDAC 0x8186 # 0 +0x8EA2CDAD 0x8183 # 0 +0x8EA2CDAE 0x8187 # 0 +0x8EA2CDAF 0x818D # 0 +0x8EA2CDB0 0x818C # 0 +0x8EA2CDB1 0x818B # 0 +0x8EA2CDB2 0x8215 # 0 +0x8EA2CDB3 0x8497 # 0 +0x8EA2CDB4 0x84A4 # 0 +0x8EA2CDB5 0x84A1 # 0 +0x8EA2CDB6 0x849F # 0 +0x8EA2CDB7 0x84BA # 0 +0x8EA2CDB8 0x84CE # 0 +0x8EA2CDB9 0x84C2 # 0 +0x8EA2CDBA 0x84AC # 0 +0x8EA2CDBB 0x84AE # 0 +0x8EA2CDBC 0x84AB # 0 +0x8EA2CDBD 0x84B9 # 0 +0x8EA2CDBE 0x84B4 # 0 +0x8EA2CDBF 0x84C1 # 0 +0x8EA2CDC0 0x84CD # 0 +0x8EA2CDC1 0x84AA # 0 +0x8EA2CDC2 0x849A # 0 +0x8EA2CDC3 0x84B1 # 0 +0x8EA2CDC4 0x84D0 # 0 +0x8EA2CDC5 0x849D # 0 +0x8EA2CDC6 0x84A7 # 0 +0x8EA2CDC7 0x84BB # 0 +0x8EA2CDC8 0x84A2 # 0 +0x8EA2CDC9 0x8494 # 0 +0x8EA2CDCA 0x84C7 # 0 +0x8EA2CDCB 0x84CC # 0 +0x8EA2CDCC 0x849B # 0 +0x8EA2CDCD 0x84A9 # 0 +0x8EA2CDCE 0x84AF # 0 +0x8EA2CDCF 0x84A8 # 0 +0x8EA2CDD0 0x84D6 # 0 +0x8EA2CDD1 0x8498 # 0 +0x8EA2CDD2 0x84B6 # 0 +0x8EA2CDD3 0x84CF # 0 +0x8EA2CDD4 0x84A0 # 0 +0x8EA2CDD5 0x84D7 # 0 +0x8EA2CDD6 0x84D4 # 0 +0x8EA2CDD7 0x84D2 # 0 +0x8EA2CDD8 0x84DB # 0 +0x8EA2CDD9 0x84B0 # 0 +0x8EA2CDDA 0x8491 # 0 +0x8EA2CDDB 0x8661 # 0 +0x8EA2CDDC 0x8733 # 0 +0x8EA2CDDD 0x8723 # 0 +0x8EA2CDDE 0x8728 # 0 +0x8EA2CDDF 0x876B # 0 +0x8EA2CDE0 0x8740 # 0 +0x8EA2CDE1 0x872E # 0 +0x8EA2CDE2 0x871E # 0 +0x8EA2CDE3 0x8721 # 0 +0x8EA2CDE4 0x8719 # 0 +0x8EA2CDE5 0x871B # 0 +0x8EA2CDE6 0x8743 # 0 +0x8EA2CDE7 0x872C # 0 +0x8EA2CDE8 0x8741 # 0 +0x8EA2CDE9 0x873E # 0 +0x8EA2CDEA 0x8746 # 0 +0x8EA2CDEB 0x8720 # 0 +0x8EA2CDEC 0x8732 # 0 +0x8EA2CDED 0x872A # 0 +0x8EA2CDEE 0x872D # 0 +0x8EA2CDEF 0x873C # 0 +0x8EA2CDF0 0x8712 # 0 +0x8EA2CDF1 0x873A # 0 +0x8EA2CDF2 0x8731 # 0 +0x8EA2CDF3 0x8735 # 0 +0x8EA2CDF4 0x8742 # 0 +0x8EA2CDF5 0x8726 # 0 +0x8EA2CDF6 0x8727 # 0 +0x8EA2CDF7 0x8738 # 0 +0x8EA2CDF8 0x8724 # 0 +0x8EA2CDF9 0x871A # 0 +0x8EA2CDFA 0x8730 # 0 +0x8EA2CDFB 0x8711 # 0 +0x8EA2CDFC 0x88F7 # 0 +0x8EA2CDFD 0x88E7 # 0 +0x8EA2CDFE 0x88F1 # 0 +0x8EA2CEA1 0x88F2 # 0 +0x8EA2CEA2 0x88FA # 0 +0x8EA2CEA3 0x88FE # 0 +0x8EA2CEA4 0x88EE # 0 +0x8EA2CEA5 0x88FC # 0 +0x8EA2CEA6 0x88F6 # 0 +0x8EA2CEA7 0x88FB # 0 +0x8EA2CEA8 0x88F0 # 0 +0x8EA2CEA9 0x88EC # 0 +0x8EA2CEAA 0x88EB # 0 +0x8EA2CEAB 0x899D # 0 +0x8EA2CEAC 0x89A1 # 0 +0x8EA2CEAD 0x899F # 0 +0x8EA2CEAE 0x899E # 0 +0x8EA2CEAF 0x89E9 # 0 +0x8EA2CEB0 0x89EB # 0 +0x8EA2CEB1 0x89E8 # 0 +0x8EA2CEB2 0x8AAB # 0 +0x8EA2CEB3 0x8A99 # 0 +0x8EA2CEB4 0x8A8B # 0 +0x8EA2CEB5 0x8A92 # 0 +0x8EA2CEB6 0x8A8F # 0 +0x8EA2CEB7 0x8A96 # 0 +0x8EA2CEB8 0x8C3D # 0 +0x8EA2CEB9 0x8C68 # 0 +0x8EA2CEBA 0x8C69 # 0 +0x8EA2CEBB 0x8CD5 # 0 +0x8EA2CEBC 0x8CCF # 0 +0x8EA2CEBD 0x8CD7 # 0 +0x8EA2CEBE 0x8D96 # 0 +0x8EA2CEBF 0x8E09 # 0 +0x8EA2CEC0 0x8E02 # 0 +0x8EA2CEC1 0x8DFF # 0 +0x8EA2CEC2 0x8E0D # 0 +0x8EA2CEC3 0x8DFD # 0 +0x8EA2CEC4 0x8E0A # 0 +0x8EA2CEC5 0x8E03 # 0 +0x8EA2CEC6 0x8E07 # 0 +0x8EA2CEC7 0x8E06 # 0 +0x8EA2CEC8 0x8E05 # 0 +0x8EA2CEC9 0x8DFE # 0 +0x8EA2CECA 0x8E00 # 0 +0x8EA2CECB 0x8E04 # 0 +0x8EA2CECC 0x8F10 # 0 +0x8EA2CECD 0x8F11 # 0 +0x8EA2CECE 0x8F0E # 0 +0x8EA2CECF 0x8F0D # 0 +0x8EA2CED0 0x9123 # 0 +0x8EA2CED1 0x911C # 0 +0x8EA2CED2 0x9120 # 0 +0x8EA2CED3 0x9122 # 0 +0x8EA2CED4 0x911F # 0 +0x8EA2CED5 0x911D # 0 +0x8EA2CED6 0x911A # 0 +0x8EA2CED7 0x9124 # 0 +0x8EA2CED8 0x9121 # 0 +0x8EA2CED9 0x911B # 0 +0x8EA2CEDA 0x917A # 0 +0x8EA2CEDB 0x9172 # 0 +0x8EA2CEDC 0x9179 # 0 +0x8EA2CEDD 0x9173 # 0 +0x8EA2CEDE 0x92A5 # 0 +0x8EA2CEDF 0x92A4 # 0 +0x8EA2CEE0 0x9276 # 0 +0x8EA2CEE1 0x929B # 0 +0x8EA2CEE2 0x927A # 0 +0x8EA2CEE3 0x92A0 # 0 +0x8EA2CEE4 0x9294 # 0 +0x8EA2CEE5 0x92AA # 0 +0x8EA2CEE6 0x928D # 0 +0x8EA2CEE7 0x92A6 # 0 +0x8EA2CEE8 0x929A # 0 +0x8EA2CEE9 0x92AB # 0 +0x8EA2CEEA 0x9279 # 0 +0x8EA2CEEB 0x9297 # 0 +0x8EA2CEEC 0x927F # 0 +0x8EA2CEED 0x92A3 # 0 +0x8EA2CEEE 0x92EE # 0 +0x8EA2CEEF 0x928E # 0 +0x8EA2CEF0 0x9282 # 0 +0x8EA2CEF1 0x9295 # 0 +0x8EA2CEF2 0x92A2 # 0 +0x8EA2CEF3 0x927D # 0 +0x8EA2CEF4 0x9288 # 0 +0x8EA2CEF5 0x92A1 # 0 +0x8EA2CEF6 0x928A # 0 +0x8EA2CEF7 0x9286 # 0 +0x8EA2CEF8 0x928C # 0 +0x8EA2CEF9 0x9299 # 0 +0x8EA2CEFA 0x92A7 # 0 +0x8EA2CEFB 0x927E # 0 +0x8EA2CEFC 0x9287 # 0 +0x8EA2CEFD 0x92A9 # 0 +0x8EA2CEFE 0x929D # 0 +0x8EA2CFA1 0x928B # 0 +0x8EA2CFA2 0x922D # 0 +0x8EA2CFA3 0x969E # 0 +0x8EA2CFA4 0x96A1 # 0 +0x8EA2CFA5 0x96FF # 0 +0x8EA2CFA6 0x9758 # 0 +0x8EA2CFA7 0x977D # 0 +0x8EA2CFA8 0x977A # 0 +0x8EA2CFA9 0x977E # 0 +0x8EA2CFAA 0x9783 # 0 +0x8EA2CFAB 0x9780 # 0 +0x8EA2CFAC 0x9782 # 0 +0x8EA2CFAD 0x977B # 0 +0x8EA2CFAE 0x9784 # 0 +0x8EA2CFAF 0x9781 # 0 +0x8EA2CFB0 0x977F # 0 +0x8EA2CFB1 0x97CE # 0 +0x8EA2CFB2 0x97CD # 0 +0x8EA2CFB3 0x9816 # 0 +0x8EA2CFB4 0x98AD # 0 +0x8EA2CFB5 0x98AE # 0 +0x8EA2CFB6 0x9902 # 0 +0x8EA2CFB7 0x9900 # 0 +0x8EA2CFB8 0x9907 # 0 +0x8EA2CFB9 0x999D # 0 +0x8EA2CFBA 0x999C # 0 +0x8EA2CFBB 0x99C3 # 0 +0x8EA2CFBC 0x99B9 # 0 +0x8EA2CFBD 0x99BB # 0 +0x8EA2CFBE 0x99BA # 0 +0x8EA2CFBF 0x99C2 # 0 +0x8EA2CFC0 0x99BD # 0 +0x8EA2CFC1 0x99C7 # 0 +0x8EA2CFC2 0x9AB1 # 0 +0x8EA2CFC3 0x9AE3 # 0 +0x8EA2CFC4 0x9AE7 # 0 +0x8EA2CFC5 0x9B3E # 0 +0x8EA2CFC6 0x9B3F # 0 +0x8EA2CFC7 0x9B60 # 0 +0x8EA2CFC8 0x9B61 # 0 +0x8EA2CFC9 0x9B5F # 0 +0x8EA2CFCA 0x9CF1 # 0 +0x8EA2CFCB 0x9CF2 # 0 +0x8EA2CFCC 0x9CF5 # 0 +0x8EA2CFCD 0x9EA7 # 0 +0x8EA2CFCE 0x50FF # 0 +0x8EA2CFCF 0x5103 # 0 +0x8EA2CFD0 0x5130 # 0 +0x8EA2CFD1 0x50F8 # 0 +0x8EA2CFD2 0x5106 # 0 +0x8EA2CFD3 0x5107 # 0 +0x8EA2CFD4 0x50F6 # 0 +0x8EA2CFD5 0x50FE # 0 +0x8EA2CFD6 0x510B # 0 +0x8EA2CFD7 0x510C # 0 +0x8EA2CFD8 0x50FD # 0 +0x8EA2CFD9 0x510A # 0 +0x8EA2CFDA 0x528B # 0 +0x8EA2CFDB 0x528C # 0 +0x8EA2CFDC 0x52F1 # 0 +0x8EA2CFDD 0x52EF # 0 +0x8EA2CFDE 0x5648 # 0 +0x8EA2CFDF 0x5642 # 0 +0x8EA2CFE0 0x564C # 0 +0x8EA2CFE1 0x5635 # 0 +0x8EA2CFE2 0x5641 # 0 +0x8EA2CFE3 0x564A # 0 +0x8EA2CFE4 0x5649 # 0 +0x8EA2CFE5 0x5646 # 0 +0x8EA2CFE6 0x5658 # 0 +0x8EA2CFE7 0x565A # 0 +0x8EA2CFE8 0x5640 # 0 +0x8EA2CFE9 0x5633 # 0 +0x8EA2CFEA 0x563D # 0 +0x8EA2CFEB 0x562C # 0 +0x8EA2CFEC 0x563E # 0 +0x8EA2CFED 0x5638 # 0 +0x8EA2CFEE 0x562A # 0 +0x8EA2CFEF 0x563A # 0 +0x8EA2CFF0 0x571A # 0 +0x8EA2CFF1 0x58AB # 0 +0x8EA2CFF2 0x589D # 0 +0x8EA2CFF3 0x58B1 # 0 +0x8EA2CFF4 0x58A0 # 0 +0x8EA2CFF5 0x58A3 # 0 +0x8EA2CFF6 0x58AF # 0 +0x8EA2CFF7 0x58AC # 0 +0x8EA2CFF8 0x58A5 # 0 +0x8EA2CFF9 0x58A1 # 0 +0x8EA2CFFA 0x58FF # 0 +0x8EA2CFFB 0x5AFF # 0 +0x8EA2CFFC 0x5AF4 # 0 +0x8EA2CFFD 0x5AFD # 0 +0x8EA2CFFE 0x5AF7 # 0 +0x8EA2D0A1 0x5AF6 # 0 +0x8EA2D0A2 0x5B03 # 0 +0x8EA2D0A3 0x5AF8 # 0 +0x8EA2D0A4 0x5B02 # 0 +0x8EA2D0A5 0x5AF9 # 0 +0x8EA2D0A6 0x5B01 # 0 +0x8EA2D0A7 0x5B07 # 0 +0x8EA2D0A8 0x5B05 # 0 +0x8EA2D0A9 0x5B0F # 0 +0x8EA2D0AA 0x5C67 # 0 +0x8EA2D0AB 0x5D99 # 0 +0x8EA2D0AC 0x5D97 # 0 +0x8EA2D0AD 0x5D9F # 0 +0x8EA2D0AE 0x5D92 # 0 +0x8EA2D0AF 0x5DA2 # 0 +0x8EA2D0B0 0x5D93 # 0 +0x8EA2D0B1 0x5D95 # 0 +0x8EA2D0B2 0x5DA0 # 0 +0x8EA2D0B3 0x5D9C # 0 +0x8EA2D0B4 0x5DA1 # 0 +0x8EA2D0B5 0x5D9A # 0 +0x8EA2D0B6 0x5D9E # 0 +0x8EA2D0B7 0x5E69 # 0 +0x8EA2D0B8 0x5E5D # 0 +0x8EA2D0B9 0x5E60 # 0 +0x8EA2D0BA 0x5E5C # 0 +0x8EA2D0BB 0x7DF3 # 0 +0x8EA2D0BC 0x5EDB # 0 +0x8EA2D0BD 0x5EDE # 0 +0x8EA2D0BE 0x5EE1 # 0 +0x8EA2D0BF 0x5F49 # 0 +0x8EA2D0C0 0x5FB2 # 0 +0x8EA2D0C1 0x618B # 0 +0x8EA2D0C2 0x6183 # 0 +0x8EA2D0C3 0x6179 # 0 +0x8EA2D0C4 0x61B1 # 0 +0x8EA2D0C5 0x61B0 # 0 +0x8EA2D0C6 0x61A2 # 0 +0x8EA2D0C7 0x6189 # 0 +0x8EA2D0C8 0x619B # 0 +0x8EA2D0C9 0x6193 # 0 +0x8EA2D0CA 0x61AF # 0 +0x8EA2D0CB 0x61AD # 0 +0x8EA2D0CC 0x619F # 0 +0x8EA2D0CD 0x6192 # 0 +0x8EA2D0CE 0x61AA # 0 +0x8EA2D0CF 0x61A1 # 0 +0x8EA2D0D0 0x618D # 0 +0x8EA2D0D1 0x6166 # 0 +0x8EA2D0D2 0x61B3 # 0 +0x8EA2D0D3 0x622D # 0 +0x8EA2D0D4 0x646E # 0 +0x8EA2D0D5 0x6470 # 0 +0x8EA2D0D6 0x6496 # 0 +0x8EA2D0D7 0x64A0 # 0 +0x8EA2D0D8 0x6485 # 0 +0x8EA2D0D9 0x6497 # 0 +0x8EA2D0DA 0x649C # 0 +0x8EA2D0DB 0x648F # 0 +0x8EA2D0DC 0x648B # 0 +0x8EA2D0DD 0x648A # 0 +0x8EA2D0DE 0x648C # 0 +0x8EA2D0DF 0x64A3 # 0 +0x8EA2D0E0 0x649F # 0 +0x8EA2D0E1 0x6468 # 0 +0x8EA2D0E2 0x64B1 # 0 +0x8EA2D0E3 0x6498 # 0 +0x8EA2D0E4 0x6576 # 0 +0x8EA2D0E5 0x657A # 0 +0x8EA2D0E6 0x6579 # 0 +0x8EA2D0E7 0x657B # 0 +0x8EA2D0E8 0x65B2 # 0 +0x8EA2D0E9 0x65B3 # 0 +0x8EA2D0EA 0x66B5 # 0 +0x8EA2D0EB 0x66B0 # 0 +0x8EA2D0EC 0x66A9 # 0 +0x8EA2D0ED 0x66B2 # 0 +0x8EA2D0EE 0x66B7 # 0 +0x8EA2D0EF 0x66AA # 0 +0x8EA2D0F0 0x66AF # 0 +0x8EA2D0F1 0x6A00 # 0 +0x8EA2D0F2 0x6A06 # 0 +0x8EA2D0F3 0x6A17 # 0 +0x8EA2D0F4 0x69E5 # 0 +0x8EA2D0F5 0x69F8 # 0 +0x8EA2D0F6 0x6A15 # 0 +0x8EA2D0F7 0x69F1 # 0 +0x8EA2D0F8 0x69E4 # 0 +0x8EA2D0F9 0x6A20 # 0 +0x8EA2D0FA 0x69FF # 0 +0x8EA2D0FB 0x69EC # 0 +0x8EA2D0FC 0x69E2 # 0 +0x8EA2D0FD 0x6A1B # 0 +0x8EA2D0FE 0x6A1D # 0 +0x8EA2D1A1 0x69FE # 0 +0x8EA2D1A2 0x6A27 # 0 +0x8EA2D1A3 0x69F2 # 0 +0x8EA2D1A4 0x69EE # 0 +0x8EA2D1A5 0x6A14 # 0 +0x8EA2D1A6 0x69F7 # 0 +0x8EA2D1A7 0x69E7 # 0 +0x8EA2D1A8 0x6A40 # 0 +0x8EA2D1A9 0x6A08 # 0 +0x8EA2D1AA 0x69E6 # 0 +0x8EA2D1AB 0x69FB # 0 +0x8EA2D1AC 0x6A0D # 0 +0x8EA2D1AD 0x69FC # 0 +0x8EA2D1AE 0x69EB # 0 +0x8EA2D1AF 0x6A09 # 0 +0x8EA2D1B0 0x6A04 # 0 +0x8EA2D1B1 0x6A18 # 0 +0x8EA2D1B2 0x6A25 # 0 +0x8EA2D1B3 0x6A0F # 0 +0x8EA2D1B4 0x69F6 # 0 +0x8EA2D1B5 0x6A26 # 0 +0x8EA2D1B6 0x6A07 # 0 +0x8EA2D1B7 0x69F4 # 0 +0x8EA2D1B8 0x6A16 # 0 +0x8EA2D1B9 0x6B51 # 0 +0x8EA2D1BA 0x6BA5 # 0 +0x8EA2D1BB 0x6BA3 # 0 +0x8EA2D1BC 0x6BA2 # 0 +0x8EA2D1BD 0x6BA6 # 0 +0x8EA2D1BE 0x6C01 # 0 +0x8EA2D1BF 0x6C00 # 0 +0x8EA2D1C0 0x6BFF # 0 +0x8EA2D1C1 0x6C02 # 0 +0x8EA2D1C2 0x6F41 # 0 +0x8EA2D1C3 0x6F26 # 0 +0x8EA2D1C4 0x6F7E # 0 +0x8EA2D1C5 0x6F87 # 0 +0x8EA2D1C6 0x6FC6 # 0 +0x8EA2D1C7 0x6F92 # 0 +0x8EA2D1C8 0x6F8D # 0 +0x8EA2D1C9 0x6F89 # 0 +0x8EA2D1CA 0x6F8C # 0 +0x8EA2D1CB 0x6F62 # 0 +0x8EA2D1CC 0x6F4F # 0 +0x8EA2D1CD 0x6F85 # 0 +0x8EA2D1CE 0x6F5A # 0 +0x8EA2D1CF 0x6F96 # 0 +0x8EA2D1D0 0x6F76 # 0 +0x8EA2D1D1 0x6F6C # 0 +0x8EA2D1D2 0x6F82 # 0 +0x8EA2D1D3 0x6F55 # 0 +0x8EA2D1D4 0x6F72 # 0 +0x8EA2D1D5 0x6F52 # 0 +0x8EA2D1D6 0x6F50 # 0 +0x8EA2D1D7 0x6F57 # 0 +0x8EA2D1D8 0x6F94 # 0 +0x8EA2D1D9 0x6F93 # 0 +0x8EA2D1DA 0x6F5D # 0 +0x8EA2D1DB 0x6F00 # 0 +0x8EA2D1DC 0x6F61 # 0 +0x8EA2D1DD 0x6F6B # 0 +0x8EA2D1DE 0x6F7D # 0 +0x8EA2D1DF 0x6F67 # 0 +0x8EA2D1E0 0x6F90 # 0 +0x8EA2D1E1 0x6F53 # 0 +0x8EA2D1E2 0x6F8B # 0 +0x8EA2D1E3 0x6F69 # 0 +0x8EA2D1E4 0x6F7F # 0 +0x8EA2D1E5 0x6F95 # 0 +0x8EA2D1E6 0x6F63 # 0 +0x8EA2D1E7 0x6F77 # 0 +0x8EA2D1E8 0x6F6A # 0 +0x8EA2D1E9 0x6F7B # 0 +0x8EA2D1EA 0x71B2 # 0 +0x8EA2D1EB 0x71AF # 0 +0x8EA2D1EC 0x719B # 0 +0x8EA2D1ED 0x71B0 # 0 +0x8EA2D1EE 0x71A0 # 0 +0x8EA2D1EF 0x719A # 0 +0x8EA2D1F0 0x71A9 # 0 +0x8EA2D1F1 0x71B5 # 0 +0x8EA2D1F2 0x719D # 0 +0x8EA2D1F3 0x71A5 # 0 +0x8EA2D1F4 0x719E # 0 +0x8EA2D1F5 0x71A4 # 0 +0x8EA2D1F6 0x71A1 # 0 +0x8EA2D1F7 0x71AA # 0 +0x8EA2D1F8 0x719C # 0 +0x8EA2D1F9 0x71A7 # 0 +0x8EA2D1FA 0x71B3 # 0 +0x8EA2D1FB 0x7298 # 0 +0x8EA2D1FC 0x729A # 0 +0x8EA2D1FD 0x7358 # 0 +0x8EA2D1FE 0x7352 # 0 +0x8EA2D2A1 0x735E # 0 +0x8EA2D2A2 0x735F # 0 +0x8EA2D2A3 0x7360 # 0 +0x8EA2D2A4 0x735D # 0 +0x8EA2D2A5 0x735B # 0 +0x8EA2D2A6 0x7361 # 0 +0x8EA2D2A7 0x735A # 0 +0x8EA2D2A8 0x7359 # 0 +0x8EA2D2A9 0x7362 # 0 +0x8EA2D2AA 0x7487 # 0 +0x8EA2D2AB 0x7489 # 0 +0x8EA2D2AC 0x748A # 0 +0x8EA2D2AD 0x7486 # 0 +0x8EA2D2AE 0x7481 # 0 +0x8EA2D2AF 0x747D # 0 +0x8EA2D2B0 0x7485 # 0 +0x8EA2D2B1 0x7488 # 0 +0x8EA2D2B2 0x747C # 0 +0x8EA2D2B3 0x7479 # 0 +0x8EA2D2B4 0x7508 # 0 +0x8EA2D2B5 0x7507 # 0 +0x8EA2D2B6 0x757E # 0 +0x8EA2D2B7 0x7625 # 0 +0x8EA2D2B8 0x761E # 0 +0x8EA2D2B9 0x7619 # 0 +0x8EA2D2BA 0x761D # 0 +0x8EA2D2BB 0x761C # 0 +0x8EA2D2BC 0x7623 # 0 +0x8EA2D2BD 0x761A # 0 +0x8EA2D2BE 0x7628 # 0 +0x8EA2D2BF 0x761B # 0 +0x8EA2D2C0 0x769C # 0 +0x8EA2D2C1 0x769D # 0 +0x8EA2D2C2 0x769E # 0 +0x8EA2D2C3 0x769B # 0 +0x8EA2D2C4 0x778D # 0 +0x8EA2D2C5 0x778F # 0 +0x8EA2D2C6 0x7789 # 0 +0x8EA2D2C7 0x7788 # 0 +0x8EA2D2C8 0x78CD # 0 +0x8EA2D2C9 0x78BB # 0 +0x8EA2D2CA 0x78CF # 0 +0x8EA2D2CB 0x78CC # 0 +0x8EA2D2CC 0x78D1 # 0 +0x8EA2D2CD 0x78CE # 0 +0x8EA2D2CE 0x78D4 # 0 +0x8EA2D2CF 0x78C8 # 0 +0x8EA2D2D0 0x78C3 # 0 +0x8EA2D2D1 0x78C4 # 0 +0x8EA2D2D2 0x78C9 # 0 +0x8EA2D2D3 0x799A # 0 +0x8EA2D2D4 0x79A1 # 0 +0x8EA2D2D5 0x79A0 # 0 +0x8EA2D2D6 0x799C # 0 +0x8EA2D2D7 0x79A2 # 0 +0x8EA2D2D8 0x799B # 0 +0x8EA2D2D9 0x6B76 # 0 +0x8EA2D2DA 0x7A39 # 0 +0x8EA2D2DB 0x7AB2 # 0 +0x8EA2D2DC 0x7AB4 # 0 +0x8EA2D2DD 0x7AB3 # 0 +0x8EA2D2DE 0x7BB7 # 0 +0x8EA2D2DF 0x7BCB # 0 +0x8EA2D2E0 0x7BBE # 0 +0x8EA2D2E1 0x7BAC # 0 +0x8EA2D2E2 0x7BCE # 0 +0x8EA2D2E3 0x7BAF # 0 +0x8EA2D2E4 0x7BB9 # 0 +0x8EA2D2E5 0x7BCA # 0 +0x8EA2D2E6 0x7BB5 # 0 +0x8EA2D2E7 0x7CC5 # 0 +0x8EA2D2E8 0x7CC8 # 0 +0x8EA2D2E9 0x7CCC # 0 +0x8EA2D2EA 0x7CCB # 0 +0x8EA2D2EB 0x7DF7 # 0 +0x8EA2D2EC 0x7DDB # 0 +0x8EA2D2ED 0x7DEA # 0 +0x8EA2D2EE 0x7DE7 # 0 +0x8EA2D2EF 0x7DD7 # 0 +0x8EA2D2F0 0x7DE1 # 0 +0x8EA2D2F1 0x7E03 # 0 +0x8EA2D2F2 0x7DFA # 0 +0x8EA2D2F3 0x7DE6 # 0 +0x8EA2D2F4 0x7DF6 # 0 +0x8EA2D2F5 0x7DF1 # 0 +0x8EA2D2F6 0x7DF0 # 0 +0x8EA2D2F7 0x7DEE # 0 +0x8EA2D2F8 0x7DDF # 0 +0x8EA2D2F9 0x7F76 # 0 +0x8EA2D2FA 0x7FAC # 0 +0x8EA2D2FB 0x7FB0 # 0 +0x8EA2D2FC 0x7FAD # 0 +0x8EA2D2FD 0x7FED # 0 +0x8EA2D2FE 0x7FEB # 0 +0x8EA2D3A1 0x7FEA # 0 +0x8EA2D3A2 0x7FEC # 0 +0x8EA2D3A3 0x7FE6 # 0 +0x8EA2D3A4 0x7FE8 # 0 +0x8EA2D3A5 0x8064 # 0 +0x8EA2D3A6 0x8067 # 0 +0x8EA2D3A7 0x81A3 # 0 +0x8EA2D3A8 0x819F # 0 +0x8EA2D3A9 0x819E # 0 +0x8EA2D3AA 0x8195 # 0 +0x8EA2D3AB 0x81A2 # 0 +0x8EA2D3AC 0x8199 # 0 +0x8EA2D3AD 0x8197 # 0 +0x8EA2D3AE 0x8216 # 0 +0x8EA2D3AF 0x824F # 0 +0x8EA2D3B0 0x8253 # 0 +0x8EA2D3B1 0x8252 # 0 +0x8EA2D3B2 0x8250 # 0 +0x8EA2D3B3 0x824E # 0 +0x8EA2D3B4 0x8251 # 0 +0x8EA2D3B5 0x8524 # 0 +0x8EA2D3B6 0x853B # 0 +0x8EA2D3B7 0x850F # 0 +0x8EA2D3B8 0x8500 # 0 +0x8EA2D3B9 0x8529 # 0 +0x8EA2D3BA 0x850E # 0 +0x8EA2D3BB 0x8509 # 0 +0x8EA2D3BC 0x850D # 0 +0x8EA2D3BD 0x851F # 0 +0x8EA2D3BE 0x850A # 0 +0x8EA2D3BF 0x8527 # 0 +0x8EA2D3C0 0x851C # 0 +0x8EA2D3C1 0x84FB # 0 +0x8EA2D3C2 0x852B # 0 +0x8EA2D3C3 0x84FA # 0 +0x8EA2D3C4 0x8508 # 0 +0x8EA2D3C5 0x850C # 0 +0x8EA2D3C6 0x84F4 # 0 +0x8EA2D3C7 0x852A # 0 +0x8EA2D3C8 0x84F2 # 0 +0x8EA2D3C9 0x8515 # 0 +0x8EA2D3CA 0x84F7 # 0 +0x8EA2D3CB 0x84EB # 0 +0x8EA2D3CC 0x84F3 # 0 +0x8EA2D3CD 0x84FC # 0 +0x8EA2D3CE 0x8512 # 0 +0x8EA2D3CF 0x84EA # 0 +0x8EA2D3D0 0x84E9 # 0 +0x8EA2D3D1 0x8516 # 0 +0x8EA2D3D2 0x84FE # 0 +0x8EA2D3D3 0x8528 # 0 +0x8EA2D3D4 0x851D # 0 +0x8EA2D3D5 0x852E # 0 +0x8EA2D3D6 0x8502 # 0 +0x8EA2D3D7 0x84FD # 0 +0x8EA2D3D8 0x851E # 0 +0x8EA2D3D9 0x84F6 # 0 +0x8EA2D3DA 0x8531 # 0 +0x8EA2D3DB 0x8526 # 0 +0x8EA2D3DC 0x84E7 # 0 +0x8EA2D3DD 0x84E8 # 0 +0x8EA2D3DE 0x84F0 # 0 +0x8EA2D3DF 0x84EF # 0 +0x8EA2D3E0 0x84F9 # 0 +0x8EA2D3E1 0x8518 # 0 +0x8EA2D3E2 0x8520 # 0 +0x8EA2D3E3 0x8530 # 0 +0x8EA2D3E4 0x850B # 0 +0x8EA2D3E5 0x8519 # 0 +0x8EA2D3E6 0x852F # 0 +0x8EA2D3E7 0x8662 # 0 +0x8EA2D3E8 0x8756 # 0 +0x8EA2D3E9 0x8763 # 0 +0x8EA2D3EA 0x8764 # 0 +0x8EA2D3EB 0x8777 # 0 +0x8EA2D3EC 0x87E1 # 0 +0x8EA2D3ED 0x8773 # 0 +0x8EA2D3EE 0x8758 # 0 +0x8EA2D3EF 0x8754 # 0 +0x8EA2D3F0 0x875B # 0 +0x8EA2D3F1 0x8752 # 0 +0x8EA2D3F2 0x8761 # 0 +0x8EA2D3F3 0x875A # 0 +0x8EA2D3F4 0x8751 # 0 +0x8EA2D3F5 0x875E # 0 +0x8EA2D3F6 0x876D # 0 +0x8EA2D3F7 0x876A # 0 +0x8EA2D3F8 0x8750 # 0 +0x8EA2D3F9 0x874E # 0 +0x8EA2D3FA 0x875F # 0 +0x8EA2D3FB 0x875D # 0 +0x8EA2D3FC 0x876F # 0 +0x8EA2D3FD 0x876C # 0 +0x8EA2D3FE 0x877A # 0 +0x8EA2D4A1 0x876E # 0 +0x8EA2D4A2 0x875C # 0 +0x8EA2D4A3 0x8765 # 0 +0x8EA2D4A4 0x874F # 0 +0x8EA2D4A5 0x877B # 0 +0x8EA2D4A6 0x8775 # 0 +0x8EA2D4A7 0x8762 # 0 +0x8EA2D4A8 0x8767 # 0 +0x8EA2D4A9 0x8769 # 0 +0x8EA2D4AA 0x885A # 0 +0x8EA2D4AB 0x8905 # 0 +0x8EA2D4AC 0x890C # 0 +0x8EA2D4AD 0x8914 # 0 +0x8EA2D4AE 0x890B # 0 +0x8EA2D4AF 0x8917 # 0 +0x8EA2D4B0 0x8918 # 0 +0x8EA2D4B1 0x8919 # 0 +0x8EA2D4B2 0x8906 # 0 +0x8EA2D4B3 0x8916 # 0 +0x8EA2D4B4 0x8911 # 0 +0x8EA2D4B5 0x890E # 0 +0x8EA2D4B6 0x8909 # 0 +0x8EA2D4B7 0x89A2 # 0 +0x8EA2D4B8 0x89A4 # 0 +0x8EA2D4B9 0x89A3 # 0 +0x8EA2D4BA 0x89ED # 0 +0x8EA2D4BB 0x89F0 # 0 +0x8EA2D4BC 0x89EC # 0 +0x8EA2D4BD 0x8ACF # 0 +0x8EA2D4BE 0x8AC6 # 0 +0x8EA2D4BF 0x8AB8 # 0 +0x8EA2D4C0 0x8AD3 # 0 +0x8EA2D4C1 0x8AD1 # 0 +0x8EA2D4C2 0x8AD4 # 0 +0x8EA2D4C3 0x8AD5 # 0 +0x8EA2D4C4 0x8ABB # 0 +0x8EA2D4C5 0x8AD7 # 0 +0x8EA2D4C6 0x8ABE # 0 +0x8EA2D4C7 0x8AC0 # 0 +0x8EA2D4C8 0x8AC5 # 0 +0x8EA2D4C9 0x8AD8 # 0 +0x8EA2D4CA 0x8AC3 # 0 +0x8EA2D4CB 0x8ABA # 0 +0x8EA2D4CC 0x8ABD # 0 +0x8EA2D4CD 0x8AD9 # 0 +0x8EA2D4CE 0x8C3E # 0 +0x8EA2D4CF 0x8C4D # 0 +0x8EA2D4D0 0x8C8F # 0 +0x8EA2D4D1 0x8CE5 # 0 +0x8EA2D4D2 0x8CDF # 0 +0x8EA2D4D3 0x8CD9 # 0 +0x8EA2D4D4 0x8CE8 # 0 +0x8EA2D4D5 0x8CDA # 0 +0x8EA2D4D6 0x8CDD # 0 +0x8EA2D4D7 0x8CE7 # 0 +0x8EA2D4D8 0x8DA0 # 0 +0x8EA2D4D9 0x8D9C # 0 +0x8EA2D4DA 0x8DA1 # 0 +0x8EA2D4DB 0x8D9B # 0 +0x8EA2D4DC 0x8E20 # 0 +0x8EA2D4DD 0x8E23 # 0 +0x8EA2D4DE 0x8E25 # 0 +0x8EA2D4DF 0x8E24 # 0 +0x8EA2D4E0 0x8E2E # 0 +0x8EA2D4E1 0x8E15 # 0 +0x8EA2D4E2 0x8E1B # 0 +0x8EA2D4E3 0x8E16 # 0 +0x8EA2D4E4 0x8E11 # 0 +0x8EA2D4E5 0x8E19 # 0 +0x8EA2D4E6 0x8E26 # 0 +0x8EA2D4E7 0x8E27 # 0 +0x8EA2D4E8 0x8E14 # 0 +0x8EA2D4E9 0x8E12 # 0 +0x8EA2D4EA 0x8E18 # 0 +0x8EA2D4EB 0x8E13 # 0 +0x8EA2D4EC 0x8E1C # 0 +0x8EA2D4ED 0x8E17 # 0 +0x8EA2D4EE 0x8E1A # 0 +0x8EA2D4EF 0x8F2C # 0 +0x8EA2D4F0 0x8F24 # 0 +0x8EA2D4F1 0x8F18 # 0 +0x8EA2D4F2 0x8F1A # 0 +0x8EA2D4F3 0x8F20 # 0 +0x8EA2D4F4 0x8F23 # 0 +0x8EA2D4F5 0x8F16 # 0 +0x8EA2D4F6 0x8F17 # 0 +0x8EA2D4F7 0x9073 # 0 +0x8EA2D4F8 0x9070 # 0 +0x8EA2D4F9 0x906F # 0 +0x8EA2D4FA 0x9067 # 0 +0x8EA2D4FB 0x906B # 0 +0x8EA2D4FC 0x912F # 0 +0x8EA2D4FD 0x912B # 0 +0x8EA2D4FE 0x9129 # 0 +0x8EA2D5A1 0x912A # 0 +0x8EA2D5A2 0x9132 # 0 +0x8EA2D5A3 0x9126 # 0 +0x8EA2D5A4 0x912E # 0 +0x8EA2D5A5 0x9185 # 0 +0x8EA2D5A6 0x9186 # 0 +0x8EA2D5A7 0x918A # 0 +0x8EA2D5A8 0x9181 # 0 +0x8EA2D5A9 0x9182 # 0 +0x8EA2D5AA 0x9184 # 0 +0x8EA2D5AB 0x9180 # 0 +0x8EA2D5AC 0x92D0 # 0 +0x8EA2D5AD 0x92C3 # 0 +0x8EA2D5AE 0x92C4 # 0 +0x8EA2D5AF 0x92C0 # 0 +0x8EA2D5B0 0x92D9 # 0 +0x8EA2D5B1 0x92B6 # 0 +0x8EA2D5B2 0x92CF # 0 +0x8EA2D5B3 0x92F1 # 0 +0x8EA2D5B4 0x92DF # 0 +0x8EA2D5B5 0x92D8 # 0 +0x8EA2D5B6 0x92E9 # 0 +0x8EA2D5B7 0x92D7 # 0 +0x8EA2D5B8 0x92DD # 0 +0x8EA2D5B9 0x92CC # 0 +0x8EA2D5BA 0x92EF # 0 +0x8EA2D5BB 0x92C2 # 0 +0x8EA2D5BC 0x92E8 # 0 +0x8EA2D5BD 0x92CA # 0 +0x8EA2D5BE 0x92C8 # 0 +0x8EA2D5BF 0x92CE # 0 +0x8EA2D5C0 0x92E6 # 0 +0x8EA2D5C1 0x92CD # 0 +0x8EA2D5C2 0x92D5 # 0 +0x8EA2D5C3 0x92C9 # 0 +0x8EA2D5C4 0x92E0 # 0 +0x8EA2D5C5 0x92DE # 0 +0x8EA2D5C6 0x92E7 # 0 +0x8EA2D5C7 0x92D1 # 0 +0x8EA2D5C8 0x92D3 # 0 +0x8EA2D5C9 0x92B5 # 0 +0x8EA2D5CA 0x92E1 # 0 +0x8EA2D5CB 0x9325 # 0 +0x8EA2D5CC 0x92C6 # 0 +0x8EA2D5CD 0x92B4 # 0 +0x8EA2D5CE 0x957C # 0 +0x8EA2D5CF 0x95AC # 0 +0x8EA2D5D0 0x95AB # 0 +0x8EA2D5D1 0x95AE # 0 +0x8EA2D5D2 0x95B0 # 0 +0x8EA2D5D3 0x96A4 # 0 +0x8EA2D5D4 0x96A2 # 0 +0x8EA2D5D5 0x96D3 # 0 +0x8EA2D5D6 0x9705 # 0 +0x8EA2D5D7 0x9708 # 0 +0x8EA2D5D8 0x9702 # 0 +0x8EA2D5D9 0x975A # 0 +0x8EA2D5DA 0x978A # 0 +0x8EA2D5DB 0x978E # 0 +0x8EA2D5DC 0x9788 # 0 +0x8EA2D5DD 0x97D0 # 0 +0x8EA2D5DE 0x97CF # 0 +0x8EA2D5DF 0x981E # 0 +0x8EA2D5E0 0x981D # 0 +0x8EA2D5E1 0x9826 # 0 +0x8EA2D5E2 0x9829 # 0 +0x8EA2D5E3 0x9828 # 0 +0x8EA2D5E4 0x9820 # 0 +0x8EA2D5E5 0x981B # 0 +0x8EA2D5E6 0x9827 # 0 +0x8EA2D5E7 0x98B2 # 0 +0x8EA2D5E8 0x9908 # 0 +0x8EA2D5E9 0x98FA # 0 +0x8EA2D5EA 0x9911 # 0 +0x8EA2D5EB 0x9914 # 0 +0x8EA2D5EC 0x9916 # 0 +0x8EA2D5ED 0x9917 # 0 +0x8EA2D5EE 0x9915 # 0 +0x8EA2D5EF 0x99DC # 0 +0x8EA2D5F0 0x99CD # 0 +0x8EA2D5F1 0x99CF # 0 +0x8EA2D5F2 0x99D3 # 0 +0x8EA2D5F3 0x99D4 # 0 +0x8EA2D5F4 0x99CE # 0 +0x8EA2D5F5 0x99C9 # 0 +0x8EA2D5F6 0x99D6 # 0 +0x8EA2D5F7 0x99D8 # 0 +0x8EA2D5F8 0x99CB # 0 +0x8EA2D5F9 0x99D7 # 0 +0x8EA2D5FA 0x99CC # 0 +0x8EA2D5FB 0x9AB3 # 0 +0x8EA2D5FC 0x9AEC # 0 +0x8EA2D5FD 0x9AEB # 0 +0x8EA2D5FE 0x9AF3 # 0 +0x8EA2D6A1 0x9AF2 # 0 +0x8EA2D6A2 0x9AF1 # 0 +0x8EA2D6A3 0x9B46 # 0 +0x8EA2D6A4 0x9B43 # 0 +0x8EA2D6A5 0x9B67 # 0 +0x8EA2D6A6 0x9B74 # 0 +0x8EA2D6A7 0x9B71 # 0 +0x8EA2D6A8 0x9B66 # 0 +0x8EA2D6A9 0x9B76 # 0 +0x8EA2D6AA 0x9B75 # 0 +0x8EA2D6AB 0x9B70 # 0 +0x8EA2D6AC 0x9B68 # 0 +0x8EA2D6AD 0x9B64 # 0 +0x8EA2D6AE 0x9B6C # 0 +0x8EA2D6AF 0x9CFC # 0 +0x8EA2D6B0 0x9CFA # 0 +0x8EA2D6B1 0x9CFD # 0 +0x8EA2D6B2 0x9CFF # 0 +0x8EA2D6B3 0x9CF7 # 0 +0x8EA2D6B4 0x9D07 # 0 +0x8EA2D6B5 0x9D00 # 0 +0x8EA2D6B6 0x9CF9 # 0 +0x8EA2D6B7 0x9CFB # 0 +0x8EA2D6B8 0x9D08 # 0 +0x8EA2D6B9 0x9D05 # 0 +0x8EA2D6BA 0x9D04 # 0 +0x8EA2D6BB 0x9E83 # 0 +0x8EA2D6BC 0x9ED3 # 0 +0x8EA2D6BD 0x9F0F # 0 +0x8EA2D6BE 0x9F10 # 0 +0x8EA2D6BF 0x511C # 0 +0x8EA2D6C0 0x5113 # 0 +0x8EA2D6C1 0x5117 # 0 +0x8EA2D6C2 0x511A # 0 +0x8EA2D6C3 0x5111 # 0 +0x8EA2D6C4 0x51DE # 0 +0x8EA2D6C5 0x5334 # 0 +0x8EA2D6C6 0x53E1 # 0 +0x8EA2D6C7 0x5670 # 0 +0x8EA2D6C8 0x5660 # 0 +0x8EA2D6C9 0x566E # 0 +0x8EA2D6CA 0x5673 # 0 +0x8EA2D6CB 0x5666 # 0 +0x8EA2D6CC 0x5663 # 0 +0x8EA2D6CD 0x566D # 0 +0x8EA2D6CE 0x5672 # 0 +0x8EA2D6CF 0x565E # 0 +0x8EA2D6D0 0x5677 # 0 +0x8EA2D6D1 0x571C # 0 +0x8EA2D6D2 0x571B # 0 +0x8EA2D6D3 0x58C8 # 0 +0x8EA2D6D4 0x58BD # 0 +0x8EA2D6D5 0x58C9 # 0 +0x8EA2D6D6 0x58BF # 0 +0x8EA2D6D7 0x58BA # 0 +0x8EA2D6D8 0x58C2 # 0 +0x8EA2D6D9 0x58BC # 0 +0x8EA2D6DA 0x58C6 # 0 +0x8EA2D6DB 0x5B17 # 0 +0x8EA2D6DC 0x5B19 # 0 +0x8EA2D6DD 0x5B1B # 0 +0x8EA2D6DE 0x5B21 # 0 +0x8EA2D6DF 0x5B14 # 0 +0x8EA2D6E0 0x5B13 # 0 +0x8EA2D6E1 0x5B10 # 0 +0x8EA2D6E2 0x5B16 # 0 +0x8EA2D6E3 0x5B28 # 0 +0x8EA2D6E4 0x5B1A # 0 +0x8EA2D6E5 0x5B20 # 0 +0x8EA2D6E6 0x5B1E # 0 +0x8EA2D6E7 0x5BEF # 0 +0x8EA2D6E8 0x5DAC # 0 +0x8EA2D6E9 0x5DB1 # 0 +0x8EA2D6EA 0x5DA9 # 0 +0x8EA2D6EB 0x5DA7 # 0 +0x8EA2D6EC 0x5DB5 # 0 +0x8EA2D6ED 0x5DB0 # 0 +0x8EA2D6EE 0x5DAE # 0 +0x8EA2D6EF 0x5DAA # 0 +0x8EA2D6F0 0x5DA8 # 0 +0x8EA2D6F1 0x5DB2 # 0 +0x8EA2D6F2 0x5DAD # 0 +0x8EA2D6F3 0x5DAF # 0 +0x8EA2D6F4 0x5DB4 # 0 +0x8EA2D6F5 0x5E67 # 0 +0x8EA2D6F6 0x5E68 # 0 +0x8EA2D6F7 0x5E66 # 0 +0x8EA2D6F8 0x5E6F # 0 +0x8EA2D6F9 0x5EE9 # 0 +0x8EA2D6FA 0x5EE7 # 0 +0x8EA2D6FB 0x5EE6 # 0 +0x8EA2D6FC 0x5EE8 # 0 +0x8EA2D6FD 0x5EE5 # 0 +0x8EA2D6FE 0x5F4B # 0 +0x8EA2D7A1 0x5FBC # 0 +0x8EA2D7A2 0x5FBB # 0 +0x8EA2D7A3 0x619D # 0 +0x8EA2D7A4 0x61A8 # 0 +0x8EA2D7A5 0x6196 # 0 +0x8EA2D7A6 0x61C5 # 0 +0x8EA2D7A7 0x61B4 # 0 +0x8EA2D7A8 0x61C6 # 0 +0x8EA2D7A9 0x61C1 # 0 +0x8EA2D7AA 0x61CC # 0 +0x8EA2D7AB 0x61BA # 0 +0x8EA2D7AC 0x61BF # 0 +0x8EA2D7AD 0x61B8 # 0 +0x8EA2D7AE 0x618C # 0 +0x8EA2D7AF 0x64D7 # 0 +0x8EA2D7B0 0x64D6 # 0 +0x8EA2D7B1 0x64D0 # 0 +0x8EA2D7B2 0x64CF # 0 +0x8EA2D7B3 0x64C9 # 0 +0x8EA2D7B4 0x64BD # 0 +0x8EA2D7B5 0x6489 # 0 +0x8EA2D7B6 0x64C3 # 0 +0x8EA2D7B7 0x64DB # 0 +0x8EA2D7B8 0x64F3 # 0 +0x8EA2D7B9 0x64D9 # 0 +0x8EA2D7BA 0x6533 # 0 +0x8EA2D7BB 0x657F # 0 +0x8EA2D7BC 0x657C # 0 +0x8EA2D7BD 0x65A2 # 0 +0x8EA2D7BE 0x66C8 # 0 +0x8EA2D7BF 0x66BE # 0 +0x8EA2D7C0 0x66C0 # 0 +0x8EA2D7C1 0x66CA # 0 +0x8EA2D7C2 0x66CB # 0 +0x8EA2D7C3 0x66CF # 0 +0x8EA2D7C4 0x66BD # 0 +0x8EA2D7C5 0x66BB # 0 +0x8EA2D7C6 0x66BA # 0 +0x8EA2D7C7 0x66CC # 0 +0x8EA2D7C8 0x6723 # 0 +0x8EA2D7C9 0x6A34 # 0 +0x8EA2D7CA 0x6A66 # 0 +0x8EA2D7CB 0x6A49 # 0 +0x8EA2D7CC 0x6A67 # 0 +0x8EA2D7CD 0x6A32 # 0 +0x8EA2D7CE 0x6A68 # 0 +0x8EA2D7CF 0x6A3E # 0 +0x8EA2D7D0 0x6A5D # 0 +0x8EA2D7D1 0x6A6D # 0 +0x8EA2D7D2 0x6A76 # 0 +0x8EA2D7D3 0x6A5B # 0 +0x8EA2D7D4 0x6A51 # 0 +0x8EA2D7D5 0x6A28 # 0 +0x8EA2D7D6 0x6A5A # 0 +0x8EA2D7D7 0x6A3B # 0 +0x8EA2D7D8 0x6A3F # 0 +0x8EA2D7D9 0x6A41 # 0 +0x8EA2D7DA 0x6A6A # 0 +0x8EA2D7DB 0x6A64 # 0 +0x8EA2D7DC 0x6A50 # 0 +0x8EA2D7DD 0x6A4F # 0 +0x8EA2D7DE 0x6A54 # 0 +0x8EA2D7DF 0x6A6F # 0 +0x8EA2D7E0 0x6A69 # 0 +0x8EA2D7E1 0x6A60 # 0 +0x8EA2D7E2 0x6A3C # 0 +0x8EA2D7E3 0x6A5E # 0 +0x8EA2D7E4 0x6A56 # 0 +0x8EA2D7E5 0x6A55 # 0 +0x8EA2D7E6 0x6A4D # 0 +0x8EA2D7E7 0x6A4E # 0 +0x8EA2D7E8 0x6A46 # 0 +0x8EA2D7E9 0x6B55 # 0 +0x8EA2D7EA 0x6B54 # 0 +0x8EA2D7EB 0x6B56 # 0 +0x8EA2D7EC 0x6BA7 # 0 +0x8EA2D7ED 0x6BAA # 0 +0x8EA2D7EE 0x6BAB # 0 +0x8EA2D7EF 0x6BC8 # 0 +0x8EA2D7F0 0x6BC7 # 0 +0x8EA2D7F1 0x6C04 # 0 +0x8EA2D7F2 0x6C03 # 0 +0x8EA2D7F3 0x6C06 # 0 +0x8EA2D7F4 0x6FAD # 0 +0x8EA2D7F5 0x6FCB # 0 +0x8EA2D7F6 0x6FA3 # 0 +0x8EA2D7F7 0x6FC7 # 0 +0x8EA2D7F8 0x6FBC # 0 +0x8EA2D7F9 0x6FCE # 0 +0x8EA2D7FA 0x6FC8 # 0 +0x8EA2D7FB 0x6F5E # 0 +0x8EA2D7FC 0x6FC4 # 0 +0x8EA2D7FD 0x6FBD # 0 +0x8EA2D7FE 0x6F9E # 0 +0x8EA2D8A1 0x6FCA # 0 +0x8EA2D8A2 0x6FA8 # 0 +0x8EA2D8A3 0x7004 # 0 +0x8EA2D8A4 0x6FA5 # 0 +0x8EA2D8A5 0x6FAE # 0 +0x8EA2D8A6 0x6FBA # 0 +0x8EA2D8A7 0x6FAC # 0 +0x8EA2D8A8 0x6FAA # 0 +0x8EA2D8A9 0x6FCF # 0 +0x8EA2D8AA 0x6FBF # 0 +0x8EA2D8AB 0x6FB8 # 0 +0x8EA2D8AC 0x6FA2 # 0 +0x8EA2D8AD 0x6FC9 # 0 +0x8EA2D8AE 0x6FAB # 0 +0x8EA2D8AF 0x6FCD # 0 +0x8EA2D8B0 0x6FAF # 0 +0x8EA2D8B1 0x6FB2 # 0 +0x8EA2D8B2 0x6FB0 # 0 +0x8EA2D8B3 0x71C5 # 0 +0x8EA2D8B4 0x71C2 # 0 +0x8EA2D8B5 0x71BF # 0 +0x8EA2D8B6 0x71B8 # 0 +0x8EA2D8B7 0x71D6 # 0 +0x8EA2D8B8 0x71C0 # 0 +0x8EA2D8B9 0x71C1 # 0 +0x8EA2D8BA 0x71CB # 0 +0x8EA2D8BB 0x71D4 # 0 +0x8EA2D8BC 0x71CA # 0 +0x8EA2D8BD 0x71C7 # 0 +0x8EA2D8BE 0x71CF # 0 +0x8EA2D8BF 0x71BD # 0 +0x8EA2D8C0 0x71D8 # 0 +0x8EA2D8C1 0x71BC # 0 +0x8EA2D8C2 0x71C6 # 0 +0x8EA2D8C3 0x71DA # 0 +0x8EA2D8C4 0x71DB # 0 +0x8EA2D8C5 0x729D # 0 +0x8EA2D8C6 0x729E # 0 +0x8EA2D8C7 0x7369 # 0 +0x8EA2D8C8 0x7366 # 0 +0x8EA2D8C9 0x7367 # 0 +0x8EA2D8CA 0x736C # 0 +0x8EA2D8CB 0x7365 # 0 +0x8EA2D8CC 0x736B # 0 +0x8EA2D8CD 0x736A # 0 +0x8EA2D8CE 0x747F # 0 +0x8EA2D8CF 0x749A # 0 +0x8EA2D8D0 0x74A0 # 0 +0x8EA2D8D1 0x7494 # 0 +0x8EA2D8D2 0x7492 # 0 +0x8EA2D8D3 0x7495 # 0 +0x8EA2D8D4 0x74A1 # 0 +0x8EA2D8D5 0x750B # 0 +0x8EA2D8D6 0x7580 # 0 +0x8EA2D8D7 0x762F # 0 +0x8EA2D8D8 0x762D # 0 +0x8EA2D8D9 0x7631 # 0 +0x8EA2D8DA 0x763D # 0 +0x8EA2D8DB 0x7633 # 0 +0x8EA2D8DC 0x763C # 0 +0x8EA2D8DD 0x7635 # 0 +0x8EA2D8DE 0x7632 # 0 +0x8EA2D8DF 0x7630 # 0 +0x8EA2D8E0 0x76BB # 0 +0x8EA2D8E1 0x76E6 # 0 +0x8EA2D8E2 0x779A # 0 +0x8EA2D8E3 0x779D # 0 +0x8EA2D8E4 0x77A1 # 0 +0x8EA2D8E5 0x779C # 0 +0x8EA2D8E6 0x779B # 0 +0x8EA2D8E7 0x77A2 # 0 +0x8EA2D8E8 0x77A3 # 0 +0x8EA2D8E9 0x7795 # 0 +0x8EA2D8EA 0x7799 # 0 +0x8EA2D8EB 0x7797 # 0 +0x8EA2D8EC 0x78DD # 0 +0x8EA2D8ED 0x78E9 # 0 +0x8EA2D8EE 0x78E5 # 0 +0x8EA2D8EF 0x78EA # 0 +0x8EA2D8F0 0x78DE # 0 +0x8EA2D8F1 0x78E3 # 0 +0x8EA2D8F2 0x78DB # 0 +0x8EA2D8F3 0x78E1 # 0 +0x8EA2D8F4 0x78E2 # 0 +0x8EA2D8F5 0x78ED # 0 +0x8EA2D8F6 0x78DF # 0 +0x8EA2D8F7 0x78E0 # 0 +0x8EA2D8F8 0x79A4 # 0 +0x8EA2D8F9 0x7A44 # 0 +0x8EA2D8FA 0x7A48 # 0 +0x8EA2D8FB 0x7A47 # 0 +0x8EA2D8FC 0x7AB6 # 0 +0x8EA2D8FD 0x7AB8 # 0 +0x8EA2D8FE 0x7AB5 # 0 +0x8EA2D9A1 0x7AB1 # 0 +0x8EA2D9A2 0x7AB7 # 0 +0x8EA2D9A3 0x7BDE # 0 +0x8EA2D9A4 0x7BE3 # 0 +0x8EA2D9A5 0x7BE7 # 0 +0x8EA2D9A6 0x7BDD # 0 +0x8EA2D9A7 0x7BD5 # 0 +0x8EA2D9A8 0x7BE5 # 0 +0x8EA2D9A9 0x7BDA # 0 +0x8EA2D9AA 0x7BE8 # 0 +0x8EA2D9AB 0x7BF9 # 0 +0x8EA2D9AC 0x7BD4 # 0 +0x8EA2D9AD 0x7BEA # 0 +0x8EA2D9AE 0x7BE2 # 0 +0x8EA2D9AF 0x7BDC # 0 +0x8EA2D9B0 0x7BEB # 0 +0x8EA2D9B1 0x7BD8 # 0 +0x8EA2D9B2 0x7BDF # 0 +0x8EA2D9B3 0x7CD2 # 0 +0x8EA2D9B4 0x7CD4 # 0 +0x8EA2D9B5 0x7CD7 # 0 +0x8EA2D9B6 0x7CD0 # 0 +0x8EA2D9B7 0x7CD1 # 0 +0x8EA2D9B8 0x7E12 # 0 +0x8EA2D9B9 0x7E21 # 0 +0x8EA2D9BA 0x7E17 # 0 +0x8EA2D9BB 0x7E0C # 0 +0x8EA2D9BC 0x7E1F # 0 +0x8EA2D9BD 0x7E20 # 0 +0x8EA2D9BE 0x7E13 # 0 +0x8EA2D9BF 0x7E0E # 0 +0x8EA2D9C0 0x7E1C # 0 +0x8EA2D9C1 0x7E15 # 0 +0x8EA2D9C2 0x7E1A # 0 +0x8EA2D9C3 0x7E22 # 0 +0x8EA2D9C4 0x7E0B # 0 +0x8EA2D9C5 0x7E0F # 0 +0x8EA2D9C6 0x7E16 # 0 +0x8EA2D9C7 0x7E0D # 0 +0x8EA2D9C8 0x7E14 # 0 +0x8EA2D9C9 0x7E25 # 0 +0x8EA2D9CA 0x7E24 # 0 +0x8EA2D9CB 0x7F43 # 0 +0x8EA2D9CC 0x7F7B # 0 +0x8EA2D9CD 0x7F7C # 0 +0x8EA2D9CE 0x7F7A # 0 +0x8EA2D9CF 0x7FB1 # 0 +0x8EA2D9D0 0x7FEF # 0 +0x8EA2D9D1 0x802A # 0 +0x8EA2D9D2 0x8029 # 0 +0x8EA2D9D3 0x806C # 0 +0x8EA2D9D4 0x81B1 # 0 +0x8EA2D9D5 0x81A6 # 0 +0x8EA2D9D6 0x81AE # 0 +0x8EA2D9D7 0x81B9 # 0 +0x8EA2D9D8 0x81B5 # 0 +0x8EA2D9D9 0x81AB # 0 +0x8EA2D9DA 0x81B0 # 0 +0x8EA2D9DB 0x81AC # 0 +0x8EA2D9DC 0x81B4 # 0 +0x8EA2D9DD 0x81B2 # 0 +0x8EA2D9DE 0x81B7 # 0 +0x8EA2D9DF 0x81A7 # 0 +0x8EA2D9E0 0x81F2 # 0 +0x8EA2D9E1 0x8255 # 0 +0x8EA2D9E2 0x8256 # 0 +0x8EA2D9E3 0x8257 # 0 +0x8EA2D9E4 0x8556 # 0 +0x8EA2D9E5 0x8545 # 0 +0x8EA2D9E6 0x856B # 0 +0x8EA2D9E7 0x854D # 0 +0x8EA2D9E8 0x8553 # 0 +0x8EA2D9E9 0x8561 # 0 +0x8EA2D9EA 0x8558 # 0 +0x8EA2D9EB 0x8540 # 0 +0x8EA2D9EC 0x8546 # 0 +0x8EA2D9ED 0x8564 # 0 +0x8EA2D9EE 0x8541 # 0 +0x8EA2D9EF 0x8562 # 0 +0x8EA2D9F0 0x8544 # 0 +0x8EA2D9F1 0x8551 # 0 +0x8EA2D9F2 0x8547 # 0 +0x8EA2D9F3 0x8563 # 0 +0x8EA2D9F4 0x853E # 0 +0x8EA2D9F5 0x855B # 0 +0x8EA2D9F6 0x8571 # 0 +0x8EA2D9F7 0x854E # 0 +0x8EA2D9F8 0x856E # 0 +0x8EA2D9F9 0x8575 # 0 +0x8EA2D9FA 0x8555 # 0 +0x8EA2D9FB 0x8567 # 0 +0x8EA2D9FC 0x8560 # 0 +0x8EA2D9FD 0x858C # 0 +0x8EA2D9FE 0x8566 # 0 +0x8EA2DAA1 0x855D # 0 +0x8EA2DAA2 0x8554 # 0 +0x8EA2DAA3 0x8565 # 0 +0x8EA2DAA4 0x856C # 0 +0x8EA2DAA5 0x8663 # 0 +0x8EA2DAA6 0x8665 # 0 +0x8EA2DAA7 0x8664 # 0 +0x8EA2DAA8 0x87A4 # 0 +0x8EA2DAA9 0x879B # 0 +0x8EA2DAAA 0x878F # 0 +0x8EA2DAAB 0x8797 # 0 +0x8EA2DAAC 0x8793 # 0 +0x8EA2DAAD 0x8792 # 0 +0x8EA2DAAE 0x8788 # 0 +0x8EA2DAAF 0x8781 # 0 +0x8EA2DAB0 0x8796 # 0 +0x8EA2DAB1 0x8798 # 0 +0x8EA2DAB2 0x8779 # 0 +0x8EA2DAB3 0x8787 # 0 +0x8EA2DAB4 0x87A3 # 0 +0x8EA2DAB5 0x8785 # 0 +0x8EA2DAB6 0x8790 # 0 +0x8EA2DAB7 0x8791 # 0 +0x8EA2DAB8 0x879D # 0 +0x8EA2DAB9 0x8784 # 0 +0x8EA2DABA 0x8794 # 0 +0x8EA2DABB 0x879C # 0 +0x8EA2DABC 0x879A # 0 +0x8EA2DABD 0x8789 # 0 +0x8EA2DABE 0x891E # 0 +0x8EA2DABF 0x8926 # 0 +0x8EA2DAC0 0x8930 # 0 +0x8EA2DAC1 0x892D # 0 +0x8EA2DAC2 0x892E # 0 +0x8EA2DAC3 0x8927 # 0 +0x8EA2DAC4 0x8931 # 0 +0x8EA2DAC5 0x8922 # 0 +0x8EA2DAC6 0x8929 # 0 +0x8EA2DAC7 0x8923 # 0 +0x8EA2DAC8 0x892F # 0 +0x8EA2DAC9 0x892C # 0 +0x8EA2DACA 0x891F # 0 +0x8EA2DACB 0x89F1 # 0 +0x8EA2DACC 0x8AE0 # 0 +0x8EA2DACD 0x8AE2 # 0 +0x8EA2DACE 0x8AF2 # 0 +0x8EA2DACF 0x8AF4 # 0 +0x8EA2DAD0 0x8AF5 # 0 +0x8EA2DAD1 0x8ADD # 0 +0x8EA2DAD2 0x8B14 # 0 +0x8EA2DAD3 0x8AE4 # 0 +0x8EA2DAD4 0x8ADF # 0 +0x8EA2DAD5 0x8AF0 # 0 +0x8EA2DAD6 0x8AC8 # 0 +0x8EA2DAD7 0x8ADE # 0 +0x8EA2DAD8 0x8AE1 # 0 +0x8EA2DAD9 0x8AE8 # 0 +0x8EA2DADA 0x8AFF # 0 +0x8EA2DADB 0x8AEF # 0 +0x8EA2DADC 0x8AFB # 0 +0x8EA2DADD 0x8C91 # 0 +0x8EA2DADE 0x8C92 # 0 +0x8EA2DADF 0x8C90 # 0 +0x8EA2DAE0 0x8CF5 # 0 +0x8EA2DAE1 0x8CEE # 0 +0x8EA2DAE2 0x8CF1 # 0 +0x8EA2DAE3 0x8CF0 # 0 +0x8EA2DAE4 0x8CF3 # 0 +0x8EA2DAE5 0x8D6C # 0 +0x8EA2DAE6 0x8D6E # 0 +0x8EA2DAE7 0x8DA5 # 0 +0x8EA2DAE8 0x8DA7 # 0 +0x8EA2DAE9 0x8E33 # 0 +0x8EA2DAEA 0x8E3E # 0 +0x8EA2DAEB 0x8E38 # 0 +0x8EA2DAEC 0x8E40 # 0 +0x8EA2DAED 0x8E45 # 0 +0x8EA2DAEE 0x8E36 # 0 +0x8EA2DAEF 0x8E3C # 0 +0x8EA2DAF0 0x8E3D # 0 +0x8EA2DAF1 0x8E41 # 0 +0x8EA2DAF2 0x8E30 # 0 +0x8EA2DAF3 0x8E3F # 0 +0x8EA2DAF4 0x8EBD # 0 +0x8EA2DAF5 0x8F36 # 0 +0x8EA2DAF6 0x8F2E # 0 +0x8EA2DAF7 0x8F35 # 0 +0x8EA2DAF8 0x8F32 # 0 +0x8EA2DAF9 0x8F39 # 0 +0x8EA2DAFA 0x8F37 # 0 +0x8EA2DAFB 0x8F34 # 0 +0x8EA2DAFC 0x9076 # 0 +0x8EA2DAFD 0x9079 # 0 +0x8EA2DAFE 0x907B # 0 +0x8EA2DBA1 0x9086 # 0 +0x8EA2DBA2 0x90FA # 0 +0x8EA2DBA3 0x9133 # 0 +0x8EA2DBA4 0x9135 # 0 +0x8EA2DBA5 0x9136 # 0 +0x8EA2DBA6 0x9193 # 0 +0x8EA2DBA7 0x9190 # 0 +0x8EA2DBA8 0x9191 # 0 +0x8EA2DBA9 0x918D # 0 +0x8EA2DBAA 0x918F # 0 +0x8EA2DBAB 0x9327 # 0 +0x8EA2DBAC 0x931E # 0 +0x8EA2DBAD 0x9308 # 0 +0x8EA2DBAE 0x931F # 0 +0x8EA2DBAF 0x9306 # 0 +0x8EA2DBB0 0x930F # 0 +0x8EA2DBB1 0x937A # 0 +0x8EA2DBB2 0x9338 # 0 +0x8EA2DBB3 0x933C # 0 +0x8EA2DBB4 0x931B # 0 +0x8EA2DBB5 0x9323 # 0 +0x8EA2DBB6 0x9312 # 0 +0x8EA2DBB7 0x9301 # 0 +0x8EA2DBB8 0x9346 # 0 +0x8EA2DBB9 0x932D # 0 +0x8EA2DBBA 0x930E # 0 +0x8EA2DBBB 0x930D # 0 +0x8EA2DBBC 0x92CB # 0 +0x8EA2DBBD 0x931D # 0 +0x8EA2DBBE 0x92FA # 0 +0x8EA2DBBF 0x9313 # 0 +0x8EA2DBC0 0x92F9 # 0 +0x8EA2DBC1 0x92F7 # 0 +0x8EA2DBC2 0x9334 # 0 +0x8EA2DBC3 0x9302 # 0 +0x8EA2DBC4 0x9324 # 0 +0x8EA2DBC5 0x92FF # 0 +0x8EA2DBC6 0x9329 # 0 +0x8EA2DBC7 0x9339 # 0 +0x8EA2DBC8 0x9335 # 0 +0x8EA2DBC9 0x932A # 0 +0x8EA2DBCA 0x9314 # 0 +0x8EA2DBCB 0x930C # 0 +0x8EA2DBCC 0x930B # 0 +0x8EA2DBCD 0x92FE # 0 +0x8EA2DBCE 0x9309 # 0 +0x8EA2DBCF 0x9300 # 0 +0x8EA2DBD0 0x92FB # 0 +0x8EA2DBD1 0x9316 # 0 +0x8EA2DBD2 0x95BC # 0 +0x8EA2DBD3 0x95CD # 0 +0x8EA2DBD4 0x95BE # 0 +0x8EA2DBD5 0x95B9 # 0 +0x8EA2DBD6 0x95BA # 0 +0x8EA2DBD7 0x95B6 # 0 +0x8EA2DBD8 0x95BF # 0 +0x8EA2DBD9 0x95B5 # 0 +0x8EA2DBDA 0x95BD # 0 +0x8EA2DBDB 0x96A9 # 0 +0x8EA2DBDC 0x96D4 # 0 +0x8EA2DBDD 0x970B # 0 +0x8EA2DBDE 0x9712 # 0 +0x8EA2DBDF 0x9710 # 0 +0x8EA2DBE0 0x9799 # 0 +0x8EA2DBE1 0x9797 # 0 +0x8EA2DBE2 0x9794 # 0 +0x8EA2DBE3 0x97F0 # 0 +0x8EA2DBE4 0x97F8 # 0 +0x8EA2DBE5 0x9835 # 0 +0x8EA2DBE6 0x982F # 0 +0x8EA2DBE7 0x9832 # 0 +0x8EA2DBE8 0x9924 # 0 +0x8EA2DBE9 0x991F # 0 +0x8EA2DBEA 0x9927 # 0 +0x8EA2DBEB 0x9929 # 0 +0x8EA2DBEC 0x999E # 0 +0x8EA2DBED 0x99EE # 0 +0x8EA2DBEE 0x99EC # 0 +0x8EA2DBEF 0x99E5 # 0 +0x8EA2DBF0 0x99E4 # 0 +0x8EA2DBF1 0x99F0 # 0 +0x8EA2DBF2 0x99E3 # 0 +0x8EA2DBF3 0x99EA # 0 +0x8EA2DBF4 0x99E9 # 0 +0x8EA2DBF5 0x99E7 # 0 +0x8EA2DBF6 0x9AB9 # 0 +0x8EA2DBF7 0x9ABF # 0 +0x8EA2DBF8 0x9AB4 # 0 +0x8EA2DBF9 0x9ABB # 0 +0x8EA2DBFA 0x9AF6 # 0 +0x8EA2DBFB 0x9AFA # 0 +0x8EA2DBFC 0x9AF9 # 0 +0x8EA2DBFD 0x9AF7 # 0 +0x8EA2DBFE 0x9B33 # 0 +0x8EA2DCA1 0x9B80 # 0 +0x8EA2DCA2 0x9B85 # 0 +0x8EA2DCA3 0x9B87 # 0 +0x8EA2DCA4 0x9B7C # 0 +0x8EA2DCA5 0x9B7E # 0 +0x8EA2DCA6 0x9B7B # 0 +0x8EA2DCA7 0x9B82 # 0 +0x8EA2DCA8 0x9B93 # 0 +0x8EA2DCA9 0x9B92 # 0 +0x8EA2DCAA 0x9B90 # 0 +0x8EA2DCAB 0x9B7A # 0 +0x8EA2DCAC 0x9B95 # 0 +0x8EA2DCAD 0x9B7D # 0 +0x8EA2DCAE 0x9B88 # 0 +0x8EA2DCAF 0x9D25 # 0 +0x8EA2DCB0 0x9D17 # 0 +0x8EA2DCB1 0x9D20 # 0 +0x8EA2DCB2 0x9D1E # 0 +0x8EA2DCB3 0x9D14 # 0 +0x8EA2DCB4 0x9D29 # 0 +0x8EA2DCB5 0x9D1D # 0 +0x8EA2DCB6 0x9D18 # 0 +0x8EA2DCB7 0x9D22 # 0 +0x8EA2DCB8 0x9D10 # 0 +0x8EA2DCB9 0x9D19 # 0 +0x8EA2DCBA 0x9D1F # 0 +0x8EA2DCBB 0x9E88 # 0 +0x8EA2DCBC 0x9E86 # 0 +0x8EA2DCBD 0x9E87 # 0 +0x8EA2DCBE 0x9EAE # 0 +0x8EA2DCBF 0x9EAD # 0 +0x8EA2DCC0 0x9ED5 # 0 +0x8EA2DCC1 0x9ED6 # 0 +0x8EA2DCC2 0x9EFA # 0 +0x8EA2DCC3 0x9F12 # 0 +0x8EA2DCC4 0x9F3D # 0 +0x8EA2DCC5 0x5126 # 0 +0x8EA2DCC6 0x5125 # 0 +0x8EA2DCC7 0x5122 # 0 +0x8EA2DCC8 0x5124 # 0 +0x8EA2DCC9 0x5120 # 0 +0x8EA2DCCA 0x5129 # 0 +0x8EA2DCCB 0x52F4 # 0 +0x8EA2DCCC 0x5693 # 0 +0x8EA2DCCD 0x568C # 0 +0x8EA2DCCE 0x568D # 0 +0x8EA2DCCF 0x5686 # 0 +0x8EA2DCD0 0x5684 # 0 +0x8EA2DCD1 0x5683 # 0 +0x8EA2DCD2 0x567E # 0 +0x8EA2DCD3 0x5682 # 0 +0x8EA2DCD4 0x567F # 0 +0x8EA2DCD5 0x5681 # 0 +0x8EA2DCD6 0x58D6 # 0 +0x8EA2DCD7 0x58D4 # 0 +0x8EA2DCD8 0x58CF # 0 +0x8EA2DCD9 0x58D2 # 0 +0x8EA2DCDA 0x5B2D # 0 +0x8EA2DCDB 0x5B25 # 0 +0x8EA2DCDC 0x5B32 # 0 +0x8EA2DCDD 0x5B23 # 0 +0x8EA2DCDE 0x5B2C # 0 +0x8EA2DCDF 0x5B27 # 0 +0x8EA2DCE0 0x5B26 # 0 +0x8EA2DCE1 0x5B2F # 0 +0x8EA2DCE2 0x5B2E # 0 +0x8EA2DCE3 0x5B7B # 0 +0x8EA2DCE4 0x5BF1 # 0 +0x8EA2DCE5 0x5BF2 # 0 +0x8EA2DCE6 0x5DB7 # 0 +0x8EA2DCE7 0x5E6C # 0 +0x8EA2DCE8 0x5E6A # 0 +0x8EA2DCE9 0x5FBE # 0 +0x8EA2DCEA 0x61C3 # 0 +0x8EA2DCEB 0x61B5 # 0 +0x8EA2DCEC 0x61BC # 0 +0x8EA2DCED 0x61E7 # 0 +0x8EA2DCEE 0x61E0 # 0 +0x8EA2DCEF 0x61E5 # 0 +0x8EA2DCF0 0x61E4 # 0 +0x8EA2DCF1 0x61E8 # 0 +0x8EA2DCF2 0x61DE # 0 +0x8EA2DCF3 0x64EF # 0 +0x8EA2DCF4 0x64E9 # 0 +0x8EA2DCF5 0x64E3 # 0 +0x8EA2DCF6 0x64EB # 0 +0x8EA2DCF7 0x64E4 # 0 +0x8EA2DCF8 0x64E8 # 0 +0x8EA2DCF9 0x6581 # 0 +0x8EA2DCFA 0x6580 # 0 +0x8EA2DCFB 0x65B6 # 0 +0x8EA2DCFC 0x65DA # 0 +0x8EA2DCFD 0x66D2 # 0 +0x8EA2DCFE 0x6A8D # 0 +0x8EA2DDA1 0x6A96 # 0 +0x8EA2DDA2 0x6A81 # 0 +0x8EA2DDA3 0x6AA5 # 0 +0x8EA2DDA4 0x6A89 # 0 +0x8EA2DDA5 0x6A9F # 0 +0x8EA2DDA6 0x6A9B # 0 +0x8EA2DDA7 0x6AA1 # 0 +0x8EA2DDA8 0x6A9E # 0 +0x8EA2DDA9 0x6A87 # 0 +0x8EA2DDAA 0x6A93 # 0 +0x8EA2DDAB 0x6A8E # 0 +0x8EA2DDAC 0x6A95 # 0 +0x8EA2DDAD 0x6A83 # 0 +0x8EA2DDAE 0x6AA8 # 0 +0x8EA2DDAF 0x6AA4 # 0 +0x8EA2DDB0 0x6A91 # 0 +0x8EA2DDB1 0x6A7F # 0 +0x8EA2DDB2 0x6AA6 # 0 +0x8EA2DDB3 0x6A9A # 0 +0x8EA2DDB4 0x6A85 # 0 +0x8EA2DDB5 0x6A8C # 0 +0x8EA2DDB6 0x6A92 # 0 +0x8EA2DDB7 0x6B5B # 0 +0x8EA2DDB8 0x6BAD # 0 +0x8EA2DDB9 0x6C09 # 0 +0x8EA2DDBA 0x6FCC # 0 +0x8EA2DDBB 0x6FA9 # 0 +0x8EA2DDBC 0x6FF4 # 0 +0x8EA2DDBD 0x6FD4 # 0 +0x8EA2DDBE 0x6FE3 # 0 +0x8EA2DDBF 0x6FDC # 0 +0x8EA2DDC0 0x6FED # 0 +0x8EA2DDC1 0x6FE7 # 0 +0x8EA2DDC2 0x6FE6 # 0 +0x8EA2DDC3 0x6FDE # 0 +0x8EA2DDC4 0x6FF2 # 0 +0x8EA2DDC5 0x6FDD # 0 +0x8EA2DDC6 0x6FE2 # 0 +0x8EA2DDC7 0x6FE8 # 0 +0x8EA2DDC8 0x71E1 # 0 +0x8EA2DDC9 0x71F1 # 0 +0x8EA2DDCA 0x71E8 # 0 +0x8EA2DDCB 0x71F2 # 0 +0x8EA2DDCC 0x71E4 # 0 +0x8EA2DDCD 0x71F0 # 0 +0x8EA2DDCE 0x71E2 # 0 +0x8EA2DDCF 0x7373 # 0 +0x8EA2DDD0 0x736E # 0 +0x8EA2DDD1 0x736F # 0 +0x8EA2DDD2 0x7497 # 0 +0x8EA2DDD3 0x74B2 # 0 +0x8EA2DDD4 0x74AB # 0 +0x8EA2DDD5 0x7490 # 0 +0x8EA2DDD6 0x74AA # 0 +0x8EA2DDD7 0x74AD # 0 +0x8EA2DDD8 0x74B1 # 0 +0x8EA2DDD9 0x74A5 # 0 +0x8EA2DDDA 0x74AF # 0 +0x8EA2DDDB 0x7510 # 0 +0x8EA2DDDC 0x7511 # 0 +0x8EA2DDDD 0x7512 # 0 +0x8EA2DDDE 0x750F # 0 +0x8EA2DDDF 0x7584 # 0 +0x8EA2DDE0 0x7643 # 0 +0x8EA2DDE1 0x7648 # 0 +0x8EA2DDE2 0x7649 # 0 +0x8EA2DDE3 0x7647 # 0 +0x8EA2DDE4 0x76A4 # 0 +0x8EA2DDE5 0x76E9 # 0 +0x8EA2DDE6 0x77B5 # 0 +0x8EA2DDE7 0x77AB # 0 +0x8EA2DDE8 0x77B2 # 0 +0x8EA2DDE9 0x77B7 # 0 +0x8EA2DDEA 0x77B6 # 0 +0x8EA2DDEB 0x77B4 # 0 +0x8EA2DDEC 0x77B1 # 0 +0x8EA2DDED 0x77A8 # 0 +0x8EA2DDEE 0x77F0 # 0 +0x8EA2DDEF 0x78F3 # 0 +0x8EA2DDF0 0x78FD # 0 +0x8EA2DDF1 0x7902 # 0 +0x8EA2DDF2 0x78FB # 0 +0x8EA2DDF3 0x78FC # 0 +0x8EA2DDF4 0x78FF # 0 +0x8EA2DDF5 0x78F2 # 0 +0x8EA2DDF6 0x7905 # 0 +0x8EA2DDF7 0x78F9 # 0 +0x8EA2DDF8 0x78FE # 0 +0x8EA2DDF9 0x7904 # 0 +0x8EA2DDFA 0x79AB # 0 +0x8EA2DDFB 0x79A8 # 0 +0x8EA2DDFC 0x7A5C # 0 +0x8EA2DDFD 0x7A5B # 0 +0x8EA2DDFE 0x7A56 # 0 +0x8EA2DEA1 0x7A58 # 0 +0x8EA2DEA2 0x7A54 # 0 +0x8EA2DEA3 0x7A5A # 0 +0x8EA2DEA4 0x7ABE # 0 +0x8EA2DEA5 0x7AC0 # 0 +0x8EA2DEA6 0x7AC1 # 0 +0x8EA2DEA7 0x7C05 # 0 +0x8EA2DEA8 0x7C0F # 0 +0x8EA2DEA9 0x7BF2 # 0 +0x8EA2DEAA 0x7C00 # 0 +0x8EA2DEAB 0x7BFF # 0 +0x8EA2DEAC 0x7BFB # 0 +0x8EA2DEAD 0x7C0E # 0 +0x8EA2DEAE 0x7BF4 # 0 +0x8EA2DEAF 0x7C0B # 0 +0x8EA2DEB0 0x7BF3 # 0 +0x8EA2DEB1 0x7C02 # 0 +0x8EA2DEB2 0x7C09 # 0 +0x8EA2DEB3 0x7C03 # 0 +0x8EA2DEB4 0x7C01 # 0 +0x8EA2DEB5 0x7BF8 # 0 +0x8EA2DEB6 0x7BFD # 0 +0x8EA2DEB7 0x7C06 # 0 +0x8EA2DEB8 0x7BF0 # 0 +0x8EA2DEB9 0x7BF1 # 0 +0x8EA2DEBA 0x7C10 # 0 +0x8EA2DEBB 0x7C0A # 0 +0x8EA2DEBC 0x7CE8 # 0 +0x8EA2DEBD 0x7E2D # 0 +0x8EA2DEBE 0x7E3C # 0 +0x8EA2DEBF 0x7E42 # 0 +0x8EA2DEC0 0x7E33 # 0 +0x8EA2DEC1 0x9848 # 0 +0x8EA2DEC2 0x7E38 # 0 +0x8EA2DEC3 0x7E2A # 0 +0x8EA2DEC4 0x7E49 # 0 +0x8EA2DEC5 0x7E40 # 0 +0x8EA2DEC6 0x7E47 # 0 +0x8EA2DEC7 0x7E29 # 0 +0x8EA2DEC8 0x7E4C # 0 +0x8EA2DEC9 0x7E30 # 0 +0x8EA2DECA 0x7E3B # 0 +0x8EA2DECB 0x7E36 # 0 +0x8EA2DECC 0x7E44 # 0 +0x8EA2DECD 0x7E3A # 0 +0x8EA2DECE 0x7F45 # 0 +0x8EA2DECF 0x7F7F # 0 +0x8EA2DED0 0x7F7E # 0 +0x8EA2DED1 0x7F7D # 0 +0x8EA2DED2 0x7FF4 # 0 +0x8EA2DED3 0x7FF2 # 0 +0x8EA2DED4 0x802C # 0 +0x8EA2DED5 0x81BB # 0 +0x8EA2DED6 0x81C4 # 0 +0x8EA2DED7 0x81CC # 0 +0x8EA2DED8 0x81CA # 0 +0x8EA2DED9 0x81C5 # 0 +0x8EA2DEDA 0x81C7 # 0 +0x8EA2DEDB 0x81BC # 0 +0x8EA2DEDC 0x81E9 # 0 +0x8EA2DEDD 0x825B # 0 +0x8EA2DEDE 0x825A # 0 +0x8EA2DEDF 0x825C # 0 +0x8EA2DEE0 0x8583 # 0 +0x8EA2DEE1 0x8580 # 0 +0x8EA2DEE2 0x858F # 0 +0x8EA2DEE3 0x85A7 # 0 +0x8EA2DEE4 0x8595 # 0 +0x8EA2DEE5 0x85A0 # 0 +0x8EA2DEE6 0x858B # 0 +0x8EA2DEE7 0x85A3 # 0 +0x8EA2DEE8 0x857B # 0 +0x8EA2DEE9 0x85A4 # 0 +0x8EA2DEEA 0x859A # 0 +0x8EA2DEEB 0x859E # 0 +0x8EA2DEEC 0x8577 # 0 +0x8EA2DEED 0x857C # 0 +0x8EA2DEEE 0x8589 # 0 +0x8EA2DEEF 0x85A1 # 0 +0x8EA2DEF0 0x857A # 0 +0x8EA2DEF1 0x8578 # 0 +0x8EA2DEF2 0x8557 # 0 +0x8EA2DEF3 0x858E # 0 +0x8EA2DEF4 0x8596 # 0 +0x8EA2DEF5 0x8586 # 0 +0x8EA2DEF6 0x858D # 0 +0x8EA2DEF7 0x8599 # 0 +0x8EA2DEF8 0x859D # 0 +0x8EA2DEF9 0x8581 # 0 +0x8EA2DEFA 0x85A2 # 0 +0x8EA2DEFB 0x8582 # 0 +0x8EA2DEFC 0x8588 # 0 +0x8EA2DEFD 0x8585 # 0 +0x8EA2DEFE 0x8579 # 0 +0x8EA2DFA1 0x8576 # 0 +0x8EA2DFA2 0x8598 # 0 +0x8EA2DFA3 0x8590 # 0 +0x8EA2DFA4 0x859F # 0 +0x8EA2DFA5 0x8668 # 0 +0x8EA2DFA6 0x87BE # 0 +0x8EA2DFA7 0x87AA # 0 +0x8EA2DFA8 0x87AD # 0 +0x8EA2DFA9 0x87C5 # 0 +0x8EA2DFAA 0x87B0 # 0 +0x8EA2DFAB 0x87AC # 0 +0x8EA2DFAC 0x87B9 # 0 +0x8EA2DFAD 0x87B5 # 0 +0x8EA2DFAE 0x87BC # 0 +0x8EA2DFAF 0x87AE # 0 +0x8EA2DFB0 0x87C9 # 0 +0x8EA2DFB1 0x87C3 # 0 +0x8EA2DFB2 0x87C2 # 0 +0x8EA2DFB3 0x87CC # 0 +0x8EA2DFB4 0x87B7 # 0 +0x8EA2DFB5 0x87AF # 0 +0x8EA2DFB6 0x87C4 # 0 +0x8EA2DFB7 0x87CA # 0 +0x8EA2DFB8 0x87B4 # 0 +0x8EA2DFB9 0x87B6 # 0 +0x8EA2DFBA 0x87BF # 0 +0x8EA2DFBB 0x87B8 # 0 +0x8EA2DFBC 0x87BD # 0 +0x8EA2DFBD 0x87DE # 0 +0x8EA2DFBE 0x87B2 # 0 +0x8EA2DFBF 0x8935 # 0 +0x8EA2DFC0 0x8933 # 0 +0x8EA2DFC1 0x893C # 0 +0x8EA2DFC2 0x893E # 0 +0x8EA2DFC3 0x8941 # 0 +0x8EA2DFC4 0x8952 # 0 +0x8EA2DFC5 0x8937 # 0 +0x8EA2DFC6 0x8942 # 0 +0x8EA2DFC7 0x89AD # 0 +0x8EA2DFC8 0x89AF # 0 +0x8EA2DFC9 0x89AE # 0 +0x8EA2DFCA 0x89F2 # 0 +0x8EA2DFCB 0x89F3 # 0 +0x8EA2DFCC 0x8B1E # 0 +0x8EA2DFCD 0x8B18 # 0 +0x8EA2DFCE 0x8B16 # 0 +0x8EA2DFCF 0x8B11 # 0 +0x8EA2DFD0 0x8B05 # 0 +0x8EA2DFD1 0x8B0B # 0 +0x8EA2DFD2 0x8B22 # 0 +0x8EA2DFD3 0x8B0F # 0 +0x8EA2DFD4 0x8B12 # 0 +0x8EA2DFD5 0x8B15 # 0 +0x8EA2DFD6 0x8B07 # 0 +0x8EA2DFD7 0x8B0D # 0 +0x8EA2DFD8 0x8B08 # 0 +0x8EA2DFD9 0x8B06 # 0 +0x8EA2DFDA 0x8B1C # 0 +0x8EA2DFDB 0x8B13 # 0 +0x8EA2DFDC 0x8B1A # 0 +0x8EA2DFDD 0x8C4F # 0 +0x8EA2DFDE 0x8C70 # 0 +0x8EA2DFDF 0x8C72 # 0 +0x8EA2DFE0 0x8C71 # 0 +0x8EA2DFE1 0x8C6F # 0 +0x8EA2DFE2 0x8C95 # 0 +0x8EA2DFE3 0x8C94 # 0 +0x8EA2DFE4 0x8CF9 # 0 +0x8EA2DFE5 0x8D6F # 0 +0x8EA2DFE6 0x8E4E # 0 +0x8EA2DFE7 0x8E4D # 0 +0x8EA2DFE8 0x8E53 # 0 +0x8EA2DFE9 0x8E50 # 0 +0x8EA2DFEA 0x8E4C # 0 +0x8EA2DFEB 0x8E47 # 0 +0x8EA2DFEC 0x8F43 # 0 +0x8EA2DFED 0x8F40 # 0 +0x8EA2DFEE 0x9085 # 0 +0x8EA2DFEF 0x907E # 0 +0x8EA2DFF0 0x9138 # 0 +0x8EA2DFF1 0x919A # 0 +0x8EA2DFF2 0x91A2 # 0 +0x8EA2DFF3 0x919B # 0 +0x8EA2DFF4 0x9199 # 0 +0x8EA2DFF5 0x919F # 0 +0x8EA2DFF6 0x91A1 # 0 +0x8EA2DFF7 0x919D # 0 +0x8EA2DFF8 0x91A0 # 0 +0x8EA2DFF9 0x93A1 # 0 +0x8EA2DFFA 0x9383 # 0 +0x8EA2DFFB 0x93AF # 0 +0x8EA2DFFC 0x9364 # 0 +0x8EA2DFFD 0x9356 # 0 +0x8EA2DFFE 0x9347 # 0 +0x8EA2E0A1 0x937C # 0 +0x8EA2E0A2 0x9358 # 0 +0x8EA2E0A3 0x935C # 0 +0x8EA2E0A4 0x9376 # 0 +0x8EA2E0A5 0x9349 # 0 +0x8EA2E0A6 0x9350 # 0 +0x8EA2E0A7 0x9351 # 0 +0x8EA2E0A8 0x9360 # 0 +0x8EA2E0A9 0x936D # 0 +0x8EA2E0AA 0x938F # 0 +0x8EA2E0AB 0x934C # 0 +0x8EA2E0AC 0x936A # 0 +0x8EA2E0AD 0x9379 # 0 +0x8EA2E0AE 0x9357 # 0 +0x8EA2E0AF 0x9355 # 0 +0x8EA2E0B0 0x9352 # 0 +0x8EA2E0B1 0x934F # 0 +0x8EA2E0B2 0x9371 # 0 +0x8EA2E0B3 0x9377 # 0 +0x8EA2E0B4 0x937B # 0 +0x8EA2E0B5 0x9361 # 0 +0x8EA2E0B6 0x935E # 0 +0x8EA2E0B7 0x9363 # 0 +0x8EA2E0B8 0x9367 # 0 +0x8EA2E0B9 0x934E # 0 +0x8EA2E0BA 0x9359 # 0 +0x8EA2E0BB 0x95C7 # 0 +0x8EA2E0BC 0x95C0 # 0 +0x8EA2E0BD 0x95C9 # 0 +0x8EA2E0BE 0x95C3 # 0 +0x8EA2E0BF 0x95C5 # 0 +0x8EA2E0C0 0x95B7 # 0 +0x8EA2E0C1 0x96AE # 0 +0x8EA2E0C2 0x96B0 # 0 +0x8EA2E0C3 0x96AC # 0 +0x8EA2E0C4 0x9720 # 0 +0x8EA2E0C5 0x971F # 0 +0x8EA2E0C6 0x9718 # 0 +0x8EA2E0C7 0x971D # 0 +0x8EA2E0C8 0x9719 # 0 +0x8EA2E0C9 0x979A # 0 +0x8EA2E0CA 0x97A1 # 0 +0x8EA2E0CB 0x979C # 0 +0x8EA2E0CC 0x979E # 0 +0x8EA2E0CD 0x979D # 0 +0x8EA2E0CE 0x97D5 # 0 +0x8EA2E0CF 0x97D4 # 0 +0x8EA2E0D0 0x97F1 # 0 +0x8EA2E0D1 0x9841 # 0 +0x8EA2E0D2 0x9844 # 0 +0x8EA2E0D3 0x984A # 0 +0x8EA2E0D4 0x9849 # 0 +0x8EA2E0D5 0x9845 # 0 +0x8EA2E0D6 0x9843 # 0 +0x8EA2E0D7 0x9925 # 0 +0x8EA2E0D8 0x992B # 0 +0x8EA2E0D9 0x992C # 0 +0x8EA2E0DA 0x992A # 0 +0x8EA2E0DB 0x9933 # 0 +0x8EA2E0DC 0x9932 # 0 +0x8EA2E0DD 0x992F # 0 +0x8EA2E0DE 0x992D # 0 +0x8EA2E0DF 0x9931 # 0 +0x8EA2E0E0 0x9930 # 0 +0x8EA2E0E1 0x9998 # 0 +0x8EA2E0E2 0x99A3 # 0 +0x8EA2E0E3 0x99A1 # 0 +0x8EA2E0E4 0x9A02 # 0 +0x8EA2E0E5 0x99FA # 0 +0x8EA2E0E6 0x99F4 # 0 +0x8EA2E0E7 0x99F7 # 0 +0x8EA2E0E8 0x99F9 # 0 +0x8EA2E0E9 0x99F8 # 0 +0x8EA2E0EA 0x99F6 # 0 +0x8EA2E0EB 0x99FB # 0 +0x8EA2E0EC 0x99FD # 0 +0x8EA2E0ED 0x99FE # 0 +0x8EA2E0EE 0x99FC # 0 +0x8EA2E0EF 0x9A03 # 0 +0x8EA2E0F0 0x9ABE # 0 +0x8EA2E0F1 0x9AFE # 0 +0x8EA2E0F2 0x9AFD # 0 +0x8EA2E0F3 0x9B01 # 0 +0x8EA2E0F4 0x9AFC # 0 +0x8EA2E0F5 0x9B48 # 0 +0x8EA2E0F6 0x9B9A # 0 +0x8EA2E0F7 0x9BA8 # 0 +0x8EA2E0F8 0x9B9E # 0 +0x8EA2E0F9 0x9B9B # 0 +0x8EA2E0FA 0x9BA6 # 0 +0x8EA2E0FB 0x9BA1 # 0 +0x8EA2E0FC 0x9BA5 # 0 +0x8EA2E0FD 0x9BA4 # 0 +0x8EA2E0FE 0x9B86 # 0 +0x8EA2E1A1 0x9BA2 # 0 +0x8EA2E1A2 0x9BA0 # 0 +0x8EA2E1A3 0x9BAF # 0 +0x8EA2E1A4 0x9D33 # 0 +0x8EA2E1A5 0x9D41 # 0 +0x8EA2E1A6 0x9D67 # 0 +0x8EA2E1A7 0x9D36 # 0 +0x8EA2E1A8 0x9D2E # 0 +0x8EA2E1A9 0x9D2F # 0 +0x8EA2E1AA 0x9D31 # 0 +0x8EA2E1AB 0x9D38 # 0 +0x8EA2E1AC 0x9D30 # 0 +0x8EA2E1AD 0x9D45 # 0 +0x8EA2E1AE 0x9D42 # 0 +0x8EA2E1AF 0x9D43 # 0 +0x8EA2E1B0 0x9D3E # 0 +0x8EA2E1B1 0x9D37 # 0 +0x8EA2E1B2 0x9D40 # 0 +0x8EA2E1B3 0x9D3D # 0 +0x8EA2E1B4 0x7FF5 # 0 +0x8EA2E1B5 0x9D2D # 0 +0x8EA2E1B6 0x9E8A # 0 +0x8EA2E1B7 0x9E89 # 0 +0x8EA2E1B8 0x9E8D # 0 +0x8EA2E1B9 0x9EB0 # 0 +0x8EA2E1BA 0x9EC8 # 0 +0x8EA2E1BB 0x9EDA # 0 +0x8EA2E1BC 0x9EFB # 0 +0x8EA2E1BD 0x9EFF # 0 +0x8EA2E1BE 0x9F24 # 0 +0x8EA2E1BF 0x9F23 # 0 +0x8EA2E1C0 0x9F22 # 0 +0x8EA2E1C1 0x9F54 # 0 +0x8EA2E1C2 0x9FA0 # 0 +0x8EA2E1C3 0x5131 # 0 +0x8EA2E1C4 0x512D # 0 +0x8EA2E1C5 0x512E # 0 +0x8EA2E1C6 0x5698 # 0 +0x8EA2E1C7 0x569C # 0 +0x8EA2E1C8 0x5697 # 0 +0x8EA2E1C9 0x569A # 0 +0x8EA2E1CA 0x569D # 0 +0x8EA2E1CB 0x5699 # 0 +0x8EA2E1CC 0x5970 # 0 +0x8EA2E1CD 0x5B3C # 0 +0x8EA2E1CE 0x5C69 # 0 +0x8EA2E1CF 0x5C6A # 0 +0x8EA2E1D0 0x5DC0 # 0 +0x8EA2E1D1 0x5E6D # 0 +0x8EA2E1D2 0x5E6E # 0 +0x8EA2E1D3 0x61D8 # 0 +0x8EA2E1D4 0x61DF # 0 +0x8EA2E1D5 0x61ED # 0 +0x8EA2E1D6 0x61EE # 0 +0x8EA2E1D7 0x61F1 # 0 +0x8EA2E1D8 0x61EA # 0 +0x8EA2E1D9 0x61F0 # 0 +0x8EA2E1DA 0x61EB # 0 +0x8EA2E1DB 0x61D6 # 0 +0x8EA2E1DC 0x61E9 # 0 +0x8EA2E1DD 0x64FF # 0 +0x8EA2E1DE 0x6504 # 0 +0x8EA2E1DF 0x64FD # 0 +0x8EA2E1E0 0x64F8 # 0 +0x8EA2E1E1 0x6501 # 0 +0x8EA2E1E2 0x6503 # 0 +0x8EA2E1E3 0x64FC # 0 +0x8EA2E1E4 0x6594 # 0 +0x8EA2E1E5 0x65DB # 0 +0x8EA2E1E6 0x66DA # 0 +0x8EA2E1E7 0x66DB # 0 +0x8EA2E1E8 0x66D8 # 0 +0x8EA2E1E9 0x6AC5 # 0 +0x8EA2E1EA 0x6AB9 # 0 +0x8EA2E1EB 0x6ABD # 0 +0x8EA2E1EC 0x6AE1 # 0 +0x8EA2E1ED 0x6AC6 # 0 +0x8EA2E1EE 0x6ABA # 0 +0x8EA2E1EF 0x6AB6 # 0 +0x8EA2E1F0 0x6AB7 # 0 +0x8EA2E1F1 0x6AC7 # 0 +0x8EA2E1F2 0x6AB4 # 0 +0x8EA2E1F3 0x6AAD # 0 +0x8EA2E1F4 0x6B5E # 0 +0x8EA2E1F5 0x6BC9 # 0 +0x8EA2E1F6 0x6C0B # 0 +0x8EA2E1F7 0x7007 # 0 +0x8EA2E1F8 0x700C # 0 +0x8EA2E1F9 0x700D # 0 +0x8EA2E1FA 0x7001 # 0 +0x8EA2E1FB 0x7005 # 0 +0x8EA2E1FC 0x7014 # 0 +0x8EA2E1FD 0x700E # 0 +0x8EA2E1FE 0x6FFF # 0 +0x8EA2E2A1 0x7000 # 0 +0x8EA2E2A2 0x6FFB # 0 +0x8EA2E2A3 0x7026 # 0 +0x8EA2E2A4 0x6FFC # 0 +0x8EA2E2A5 0x6FF7 # 0 +0x8EA2E2A6 0x700A # 0 +0x8EA2E2A7 0x7201 # 0 +0x8EA2E2A8 0x71FF # 0 +0x8EA2E2A9 0x71F9 # 0 +0x8EA2E2AA 0x7203 # 0 +0x8EA2E2AB 0x71FD # 0 +0x8EA2E2AC 0x7376 # 0 +0x8EA2E2AD 0x74B8 # 0 +0x8EA2E2AE 0x74C0 # 0 +0x8EA2E2AF 0x74B5 # 0 +0x8EA2E2B0 0x74C1 # 0 +0x8EA2E2B1 0x74BE # 0 +0x8EA2E2B2 0x74B6 # 0 +0x8EA2E2B3 0x74BB # 0 +0x8EA2E2B4 0x74C2 # 0 +0x8EA2E2B5 0x7514 # 0 +0x8EA2E2B6 0x7513 # 0 +0x8EA2E2B7 0x765C # 0 +0x8EA2E2B8 0x7664 # 0 +0x8EA2E2B9 0x7659 # 0 +0x8EA2E2BA 0x7650 # 0 +0x8EA2E2BB 0x7653 # 0 +0x8EA2E2BC 0x7657 # 0 +0x8EA2E2BD 0x765A # 0 +0x8EA2E2BE 0x76A6 # 0 +0x8EA2E2BF 0x76BD # 0 +0x8EA2E2C0 0x76EC # 0 +0x8EA2E2C1 0x77C2 # 0 +0x8EA2E2C2 0x77BA # 0 +0x8EA2E2C3 0x790C # 0 +0x8EA2E2C4 0x7913 # 0 +0x8EA2E2C5 0x7914 # 0 +0x8EA2E2C6 0x7909 # 0 +0x8EA2E2C7 0x7910 # 0 +0x8EA2E2C8 0x7912 # 0 +0x8EA2E2C9 0x7911 # 0 +0x8EA2E2CA 0x79AD # 0 +0x8EA2E2CB 0x79AC # 0 +0x8EA2E2CC 0x7A5F # 0 +0x8EA2E2CD 0x7C1C # 0 +0x8EA2E2CE 0x7C29 # 0 +0x8EA2E2CF 0x7C19 # 0 +0x8EA2E2D0 0x7C20 # 0 +0x8EA2E2D1 0x7C1F # 0 +0x8EA2E2D2 0x7C2D # 0 +0x8EA2E2D3 0x7C1D # 0 +0x8EA2E2D4 0x7C26 # 0 +0x8EA2E2D5 0x7C28 # 0 +0x8EA2E2D6 0x7C22 # 0 +0x8EA2E2D7 0x7C25 # 0 +0x8EA2E2D8 0x7C30 # 0 +0x8EA2E2D9 0x7E5C # 0 +0x8EA2E2DA 0x7E50 # 0 +0x8EA2E2DB 0x7E56 # 0 +0x8EA2E2DC 0x7E63 # 0 +0x8EA2E2DD 0x7E58 # 0 +0x8EA2E2DE 0x7E62 # 0 +0x8EA2E2DF 0x7E5F # 0 +0x8EA2E2E0 0x7E51 # 0 +0x8EA2E2E1 0x7E60 # 0 +0x8EA2E2E2 0x7E57 # 0 +0x8EA2E2E3 0x7E53 # 0 +0x8EA2E2E4 0x7FB5 # 0 +0x8EA2E2E5 0x7FB3 # 0 +0x8EA2E2E6 0x7FF7 # 0 +0x8EA2E2E7 0x7FF8 # 0 +0x8EA2E2E8 0x8075 # 0 +0x8EA2E2E9 0x81D1 # 0 +0x8EA2E2EA 0x81D2 # 0 +0x8EA2E2EB 0x81D0 # 0 +0x8EA2E2EC 0x825F # 0 +0x8EA2E2ED 0x825E # 0 +0x8EA2E2EE 0x85B4 # 0 +0x8EA2E2EF 0x85C6 # 0 +0x8EA2E2F0 0x85C0 # 0 +0x8EA2E2F1 0x85C3 # 0 +0x8EA2E2F2 0x85C2 # 0 +0x8EA2E2F3 0x85B3 # 0 +0x8EA2E2F4 0x85B5 # 0 +0x8EA2E2F5 0x85BD # 0 +0x8EA2E2F6 0x85C7 # 0 +0x8EA2E2F7 0x85C4 # 0 +0x8EA2E2F8 0x85BF # 0 +0x8EA2E2F9 0x85CB # 0 +0x8EA2E2FA 0x85CE # 0 +0x8EA2E2FB 0x85C8 # 0 +0x8EA2E2FC 0x85C5 # 0 +0x8EA2E2FD 0x85B1 # 0 +0x8EA2E2FE 0x85B6 # 0 +0x8EA2E3A1 0x85D2 # 0 +0x8EA2E3A2 0x8624 # 0 +0x8EA2E3A3 0x85B8 # 0 +0x8EA2E3A4 0x85B7 # 0 +0x8EA2E3A5 0x85BE # 0 +0x8EA2E3A6 0x8669 # 0 +0x8EA2E3A7 0x87E7 # 0 +0x8EA2E3A8 0x87E6 # 0 +0x8EA2E3A9 0x87E2 # 0 +0x8EA2E3AA 0x87DB # 0 +0x8EA2E3AB 0x87EB # 0 +0x8EA2E3AC 0x87EA # 0 +0x8EA2E3AD 0x87E5 # 0 +0x8EA2E3AE 0x87DF # 0 +0x8EA2E3AF 0x87F3 # 0 +0x8EA2E3B0 0x87E4 # 0 +0x8EA2E3B1 0x87D4 # 0 +0x8EA2E3B2 0x87DC # 0 +0x8EA2E3B3 0x87D3 # 0 +0x8EA2E3B4 0x87ED # 0 +0x8EA2E3B5 0x87D8 # 0 +0x8EA2E3B6 0x87E3 # 0 +0x8EA2E3B7 0x87D7 # 0 +0x8EA2E3B8 0x87D9 # 0 +0x8EA2E3B9 0x8801 # 0 +0x8EA2E3BA 0x87F4 # 0 +0x8EA2E3BB 0x87E8 # 0 +0x8EA2E3BC 0x87DD # 0 +0x8EA2E3BD 0x8953 # 0 +0x8EA2E3BE 0x894B # 0 +0x8EA2E3BF 0x894F # 0 +0x8EA2E3C0 0x894C # 0 +0x8EA2E3C1 0x8946 # 0 +0x8EA2E3C2 0x8950 # 0 +0x8EA2E3C3 0x8951 # 0 +0x8EA2E3C4 0x8949 # 0 +0x8EA2E3C5 0x8B2A # 0 +0x8EA2E3C6 0x8B27 # 0 +0x8EA2E3C7 0x8B23 # 0 +0x8EA2E3C8 0x8B33 # 0 +0x8EA2E3C9 0x8B30 # 0 +0x8EA2E3CA 0x8B35 # 0 +0x8EA2E3CB 0x8B47 # 0 +0x8EA2E3CC 0x8B2F # 0 +0x8EA2E3CD 0x8B3C # 0 +0x8EA2E3CE 0x8B3E # 0 +0x8EA2E3CF 0x8B31 # 0 +0x8EA2E3D0 0x8B25 # 0 +0x8EA2E3D1 0x8B37 # 0 +0x8EA2E3D2 0x8B26 # 0 +0x8EA2E3D3 0x8B36 # 0 +0x8EA2E3D4 0x8B2E # 0 +0x8EA2E3D5 0x8B24 # 0 +0x8EA2E3D6 0x8B3B # 0 +0x8EA2E3D7 0x8B3D # 0 +0x8EA2E3D8 0x8B3A # 0 +0x8EA2E3D9 0x8C42 # 0 +0x8EA2E3DA 0x8C75 # 0 +0x8EA2E3DB 0x8C99 # 0 +0x8EA2E3DC 0x8C98 # 0 +0x8EA2E3DD 0x8C97 # 0 +0x8EA2E3DE 0x8CFE # 0 +0x8EA2E3DF 0x8D04 # 0 +0x8EA2E3E0 0x8D02 # 0 +0x8EA2E3E1 0x8D00 # 0 +0x8EA2E3E2 0x8E5C # 0 +0x8EA2E3E3 0x8E62 # 0 +0x8EA2E3E4 0x8E60 # 0 +0x8EA2E3E5 0x8E57 # 0 +0x8EA2E3E6 0x8E56 # 0 +0x8EA2E3E7 0x8E5E # 0 +0x8EA2E3E8 0x8E65 # 0 +0x8EA2E3E9 0x8E67 # 0 +0x8EA2E3EA 0x8E5B # 0 +0x8EA2E3EB 0x8E5A # 0 +0x8EA2E3EC 0x8E61 # 0 +0x8EA2E3ED 0x8E5D # 0 +0x8EA2E3EE 0x8E69 # 0 +0x8EA2E3EF 0x8E54 # 0 +0x8EA2E3F0 0x8F46 # 0 +0x8EA2E3F1 0x8F47 # 0 +0x8EA2E3F2 0x8F48 # 0 +0x8EA2E3F3 0x8F4B # 0 +0x8EA2E3F4 0x9128 # 0 +0x8EA2E3F5 0x913A # 0 +0x8EA2E3F6 0x913B # 0 +0x8EA2E3F7 0x913E # 0 +0x8EA2E3F8 0x91A8 # 0 +0x8EA2E3F9 0x91A5 # 0 +0x8EA2E3FA 0x91A7 # 0 +0x8EA2E3FB 0x91AF # 0 +0x8EA2E3FC 0x91AA # 0 +0x8EA2E3FD 0x93B5 # 0 +0x8EA2E3FE 0x938C # 0 +0x8EA2E4A1 0x9392 # 0 +0x8EA2E4A2 0x93B7 # 0 +0x8EA2E4A3 0x939B # 0 +0x8EA2E4A4 0x939D # 0 +0x8EA2E4A5 0x9389 # 0 +0x8EA2E4A6 0x93A7 # 0 +0x8EA2E4A7 0x938E # 0 +0x8EA2E4A8 0x93AA # 0 +0x8EA2E4A9 0x939E # 0 +0x8EA2E4AA 0x93A6 # 0 +0x8EA2E4AB 0x9395 # 0 +0x8EA2E4AC 0x9388 # 0 +0x8EA2E4AD 0x9399 # 0 +0x8EA2E4AE 0x939F # 0 +0x8EA2E4AF 0x9380 # 0 +0x8EA2E4B0 0x938D # 0 +0x8EA2E4B1 0x93B1 # 0 +0x8EA2E4B2 0x9391 # 0 +0x8EA2E4B3 0x93B2 # 0 +0x8EA2E4B4 0x93A4 # 0 +0x8EA2E4B5 0x93A8 # 0 +0x8EA2E4B6 0x93B4 # 0 +0x8EA2E4B7 0x93A3 # 0 +0x8EA2E4B8 0x95D2 # 0 +0x8EA2E4B9 0x95D3 # 0 +0x8EA2E4BA 0x95D1 # 0 +0x8EA2E4BB 0x96B3 # 0 +0x8EA2E4BC 0x96D7 # 0 +0x8EA2E4BD 0x96DA # 0 +0x8EA2E4BE 0x5DC2 # 0 +0x8EA2E4BF 0x96DF # 0 +0x8EA2E4C0 0x96D8 # 0 +0x8EA2E4C1 0x96DD # 0 +0x8EA2E4C2 0x9723 # 0 +0x8EA2E4C3 0x9722 # 0 +0x8EA2E4C4 0x9725 # 0 +0x8EA2E4C5 0x97AC # 0 +0x8EA2E4C6 0x97AE # 0 +0x8EA2E4C7 0x97A8 # 0 +0x8EA2E4C8 0x97AB # 0 +0x8EA2E4C9 0x97A4 # 0 +0x8EA2E4CA 0x97AA # 0 +0x8EA2E4CB 0x97A2 # 0 +0x8EA2E4CC 0x97A5 # 0 +0x8EA2E4CD 0x97D7 # 0 +0x8EA2E4CE 0x97D9 # 0 +0x8EA2E4CF 0x97D6 # 0 +0x8EA2E4D0 0x97D8 # 0 +0x8EA2E4D1 0x97FA # 0 +0x8EA2E4D2 0x9850 # 0 +0x8EA2E4D3 0x9851 # 0 +0x8EA2E4D4 0x9852 # 0 +0x8EA2E4D5 0x98B8 # 0 +0x8EA2E4D6 0x9941 # 0 +0x8EA2E4D7 0x993C # 0 +0x8EA2E4D8 0x993A # 0 +0x8EA2E4D9 0x9A0F # 0 +0x8EA2E4DA 0x9A0B # 0 +0x8EA2E4DB 0x9A09 # 0 +0x8EA2E4DC 0x9A0D # 0 +0x8EA2E4DD 0x9A04 # 0 +0x8EA2E4DE 0x9A11 # 0 +0x8EA2E4DF 0x9A0A # 0 +0x8EA2E4E0 0x9A05 # 0 +0x8EA2E4E1 0x9A07 # 0 +0x8EA2E4E2 0x9A06 # 0 +0x8EA2E4E3 0x9AC0 # 0 +0x8EA2E4E4 0x9ADC # 0 +0x8EA2E4E5 0x9B08 # 0 +0x8EA2E4E6 0x9B04 # 0 +0x8EA2E4E7 0x9B05 # 0 +0x8EA2E4E8 0x9B29 # 0 +0x8EA2E4E9 0x9B35 # 0 +0x8EA2E4EA 0x9B4A # 0 +0x8EA2E4EB 0x9B4C # 0 +0x8EA2E4EC 0x9B4B # 0 +0x8EA2E4ED 0x9BC7 # 0 +0x8EA2E4EE 0x9BC6 # 0 +0x8EA2E4EF 0x9BC3 # 0 +0x8EA2E4F0 0x9BBF # 0 +0x8EA2E4F1 0x9BC1 # 0 +0x8EA2E4F2 0x9BB5 # 0 +0x8EA2E4F3 0x9BB8 # 0 +0x8EA2E4F4 0x9BD3 # 0 +0x8EA2E4F5 0x9BB6 # 0 +0x8EA2E4F6 0x9BC4 # 0 +0x8EA2E4F7 0x9BB9 # 0 +0x8EA2E4F8 0x9BBD # 0 +0x8EA2E4F9 0x9D5C # 0 +0x8EA2E4FA 0x9D53 # 0 +0x8EA2E4FB 0x9D4F # 0 +0x8EA2E4FC 0x9D4A # 0 +0x8EA2E4FD 0x9D5B # 0 +0x8EA2E4FE 0x9D4B # 0 +0x8EA2E5A1 0x9D59 # 0 +0x8EA2E5A2 0x9D56 # 0 +0x8EA2E5A3 0x9D4C # 0 +0x8EA2E5A4 0x9D57 # 0 +0x8EA2E5A5 0x9D52 # 0 +0x8EA2E5A6 0x9D54 # 0 +0x8EA2E5A7 0x9D5F # 0 +0x8EA2E5A8 0x9D58 # 0 +0x8EA2E5A9 0x9D5A # 0 +0x8EA2E5AA 0x9E8E # 0 +0x8EA2E5AB 0x9E8C # 0 +0x8EA2E5AC 0x9EDF # 0 +0x8EA2E5AD 0x9F01 # 0 +0x8EA2E5AE 0x9F00 # 0 +0x8EA2E5AF 0x9F16 # 0 +0x8EA2E5B0 0x9F25 # 0 +0x8EA2E5B1 0x9F2B # 0 +0x8EA2E5B2 0x9F2A # 0 +0x8EA2E5B3 0x9F29 # 0 +0x8EA2E5B4 0x9F28 # 0 +0x8EA2E5B5 0x9F4C # 0 +0x8EA2E5B6 0x9F55 # 0 +0x8EA2E5B7 0x5134 # 0 +0x8EA2E5B8 0x5135 # 0 +0x8EA2E5B9 0x5296 # 0 +0x8EA2E5BA 0x52F7 # 0 +0x8EA2E5BB 0x53B4 # 0 +0x8EA2E5BC 0x56AB # 0 +0x8EA2E5BD 0x56AD # 0 +0x8EA2E5BE 0x56A6 # 0 +0x8EA2E5BF 0x56A7 # 0 +0x8EA2E5C0 0x56AA # 0 +0x8EA2E5C1 0x56AC # 0 +0x8EA2E5C2 0x58DA # 0 +0x8EA2E5C3 0x58DD # 0 +0x8EA2E5C4 0x58DB # 0 +0x8EA2E5C5 0x5912 # 0 +0x8EA2E5C6 0x5B3D # 0 +0x8EA2E5C7 0x5B3E # 0 +0x8EA2E5C8 0x5B3F # 0 +0x8EA2E5C9 0x5DC3 # 0 +0x8EA2E5CA 0x5E70 # 0 +0x8EA2E5CB 0x5FBF # 0 +0x8EA2E5CC 0x61FB # 0 +0x8EA2E5CD 0x6507 # 0 +0x8EA2E5CE 0x6510 # 0 +0x8EA2E5CF 0x650D # 0 +0x8EA2E5D0 0x6509 # 0 +0x8EA2E5D1 0x650C # 0 +0x8EA2E5D2 0x650E # 0 +0x8EA2E5D3 0x6584 # 0 +0x8EA2E5D4 0x65DE # 0 +0x8EA2E5D5 0x65DD # 0 +0x8EA2E5D6 0x66DE # 0 +0x8EA2E5D7 0x6AE7 # 0 +0x8EA2E5D8 0x6AE0 # 0 +0x8EA2E5D9 0x6ACC # 0 +0x8EA2E5DA 0x6AD1 # 0 +0x8EA2E5DB 0x6AD9 # 0 +0x8EA2E5DC 0x6ACB # 0 +0x8EA2E5DD 0x6ADF # 0 +0x8EA2E5DE 0x6ADC # 0 +0x8EA2E5DF 0x6AD0 # 0 +0x8EA2E5E0 0x6AEB # 0 +0x8EA2E5E1 0x6ACF # 0 +0x8EA2E5E2 0x6ACD # 0 +0x8EA2E5E3 0x6ADE # 0 +0x8EA2E5E4 0x6B60 # 0 +0x8EA2E5E5 0x6BB0 # 0 +0x8EA2E5E6 0x6C0C # 0 +0x8EA2E5E7 0x7019 # 0 +0x8EA2E5E8 0x7027 # 0 +0x8EA2E5E9 0x7020 # 0 +0x8EA2E5EA 0x7016 # 0 +0x8EA2E5EB 0x702B # 0 +0x8EA2E5EC 0x7021 # 0 +0x8EA2E5ED 0x7022 # 0 +0x8EA2E5EE 0x7023 # 0 +0x8EA2E5EF 0x7029 # 0 +0x8EA2E5F0 0x7017 # 0 +0x8EA2E5F1 0x7024 # 0 +0x8EA2E5F2 0x701C # 0 +0x8EA2E5F3 0x720C # 0 +0x8EA2E5F4 0x720A # 0 +0x8EA2E5F5 0x7207 # 0 +0x8EA2E5F6 0x7202 # 0 +0x8EA2E5F7 0x7205 # 0 +0x8EA2E5F8 0x72A5 # 0 +0x8EA2E5F9 0x72A6 # 0 +0x8EA2E5FA 0x72A4 # 0 +0x8EA2E5FB 0x72A3 # 0 +0x8EA2E5FC 0x72A1 # 0 +0x8EA2E5FD 0x74CB # 0 +0x8EA2E5FE 0x74C5 # 0 +0x8EA2E6A1 0x74B7 # 0 +0x8EA2E6A2 0x74C3 # 0 +0x8EA2E6A3 0x7516 # 0 +0x8EA2E6A4 0x7660 # 0 +0x8EA2E6A5 0x77C9 # 0 +0x8EA2E6A6 0x77CA # 0 +0x8EA2E6A7 0x77C4 # 0 +0x8EA2E6A8 0x77F1 # 0 +0x8EA2E6A9 0x791D # 0 +0x8EA2E6AA 0x791B # 0 +0x8EA2E6AB 0x7921 # 0 +0x8EA2E6AC 0x791C # 0 +0x8EA2E6AD 0x7917 # 0 +0x8EA2E6AE 0x791E # 0 +0x8EA2E6AF 0x79B0 # 0 +0x8EA2E6B0 0x7A67 # 0 +0x8EA2E6B1 0x7A68 # 0 +0x8EA2E6B2 0x7C33 # 0 +0x8EA2E6B3 0x7C3C # 0 +0x8EA2E6B4 0x7C39 # 0 +0x8EA2E6B5 0x7C2C # 0 +0x8EA2E6B6 0x7C3B # 0 +0x8EA2E6B7 0x7CEC # 0 +0x8EA2E6B8 0x7CEA # 0 +0x8EA2E6B9 0x7E76 # 0 +0x8EA2E6BA 0x7E75 # 0 +0x8EA2E6BB 0x7E78 # 0 +0x8EA2E6BC 0x7E70 # 0 +0x8EA2E6BD 0x7E77 # 0 +0x8EA2E6BE 0x7E6F # 0 +0x8EA2E6BF 0x7E7A # 0 +0x8EA2E6C0 0x7E72 # 0 +0x8EA2E6C1 0x7E74 # 0 +0x8EA2E6C2 0x7E68 # 0 +0x8EA2E6C3 0x7F4B # 0 +0x8EA2E6C4 0x7F4A # 0 +0x8EA2E6C5 0x7F83 # 0 +0x8EA2E6C6 0x7F86 # 0 +0x8EA2E6C7 0x7FB7 # 0 +0x8EA2E6C8 0x7FFD # 0 +0x8EA2E6C9 0x7FFE # 0 +0x8EA2E6CA 0x8078 # 0 +0x8EA2E6CB 0x81D7 # 0 +0x8EA2E6CC 0x81D5 # 0 +0x8EA2E6CD 0x820B # 0 +0x8EA2E6CE 0x8264 # 0 +0x8EA2E6CF 0x8261 # 0 +0x8EA2E6D0 0x8263 # 0 +0x8EA2E6D1 0x85EB # 0 +0x8EA2E6D2 0x85F1 # 0 +0x8EA2E6D3 0x85ED # 0 +0x8EA2E6D4 0x85D9 # 0 +0x8EA2E6D5 0x85E1 # 0 +0x8EA2E6D6 0x85E8 # 0 +0x8EA2E6D7 0x85DA # 0 +0x8EA2E6D8 0x85D7 # 0 +0x8EA2E6D9 0x85EC # 0 +0x8EA2E6DA 0x85F2 # 0 +0x8EA2E6DB 0x85F8 # 0 +0x8EA2E6DC 0x85D8 # 0 +0x8EA2E6DD 0x85DF # 0 +0x8EA2E6DE 0x85E3 # 0 +0x8EA2E6DF 0x85DC # 0 +0x8EA2E6E0 0x85D1 # 0 +0x8EA2E6E1 0x85F0 # 0 +0x8EA2E6E2 0x85E6 # 0 +0x8EA2E6E3 0x85EF # 0 +0x8EA2E6E4 0x85DE # 0 +0x8EA2E6E5 0x85E2 # 0 +0x8EA2E6E6 0x8800 # 0 +0x8EA2E6E7 0x87FA # 0 +0x8EA2E6E8 0x8803 # 0 +0x8EA2E6E9 0x87F6 # 0 +0x8EA2E6EA 0x87F7 # 0 +0x8EA2E6EB 0x8809 # 0 +0x8EA2E6EC 0x880C # 0 +0x8EA2E6ED 0x880B # 0 +0x8EA2E6EE 0x8806 # 0 +0x8EA2E6EF 0x87FC # 0 +0x8EA2E6F0 0x8808 # 0 +0x8EA2E6F1 0x87FF # 0 +0x8EA2E6F2 0x880A # 0 +0x8EA2E6F3 0x8802 # 0 +0x8EA2E6F4 0x8962 # 0 +0x8EA2E6F5 0x895A # 0 +0x8EA2E6F6 0x895B # 0 +0x8EA2E6F7 0x8957 # 0 +0x8EA2E6F8 0x8961 # 0 +0x8EA2E6F9 0x895C # 0 +0x8EA2E6FA 0x8958 # 0 +0x8EA2E6FB 0x895D # 0 +0x8EA2E6FC 0x8959 # 0 +0x8EA2E6FD 0x8988 # 0 +0x8EA2E6FE 0x89B7 # 0 +0x8EA2E7A1 0x89B6 # 0 +0x8EA2E7A2 0x89F6 # 0 +0x8EA2E7A3 0x8B50 # 0 +0x8EA2E7A4 0x8B48 # 0 +0x8EA2E7A5 0x8B4A # 0 +0x8EA2E7A6 0x8B40 # 0 +0x8EA2E7A7 0x8B53 # 0 +0x8EA2E7A8 0x8B56 # 0 +0x8EA2E7A9 0x8B54 # 0 +0x8EA2E7AA 0x8B4B # 0 +0x8EA2E7AB 0x8B55 # 0 +0x8EA2E7AC 0x8B51 # 0 +0x8EA2E7AD 0x8B42 # 0 +0x8EA2E7AE 0x8B52 # 0 +0x8EA2E7AF 0x8B57 # 0 +0x8EA2E7B0 0x8C43 # 0 +0x8EA2E7B1 0x8C77 # 0 +0x8EA2E7B2 0x8C76 # 0 +0x8EA2E7B3 0x8C9A # 0 +0x8EA2E7B4 0x8D06 # 0 +0x8EA2E7B5 0x8D07 # 0 +0x8EA2E7B6 0x8D09 # 0 +0x8EA2E7B7 0x8DAC # 0 +0x8EA2E7B8 0x8DAA # 0 +0x8EA2E7B9 0x8DAD # 0 +0x8EA2E7BA 0x8DAB # 0 +0x8EA2E7BB 0x8E6D # 0 +0x8EA2E7BC 0x8E78 # 0 +0x8EA2E7BD 0x8E73 # 0 +0x8EA2E7BE 0x8E6A # 0 +0x8EA2E7BF 0x8E6F # 0 +0x8EA2E7C0 0x8E7B # 0 +0x8EA2E7C1 0x8EC2 # 0 +0x8EA2E7C2 0x8F52 # 0 +0x8EA2E7C3 0x8F51 # 0 +0x8EA2E7C4 0x8F4F # 0 +0x8EA2E7C5 0x8F50 # 0 +0x8EA2E7C6 0x8F53 # 0 +0x8EA2E7C7 0x8FB4 # 0 +0x8EA2E7C8 0x9140 # 0 +0x8EA2E7C9 0x913F # 0 +0x8EA2E7CA 0x91B0 # 0 +0x8EA2E7CB 0x91AD # 0 +0x8EA2E7CC 0x93DE # 0 +0x8EA2E7CD 0x93C7 # 0 +0x8EA2E7CE 0x93CF # 0 +0x8EA2E7CF 0x93C2 # 0 +0x8EA2E7D0 0x93DA # 0 +0x8EA2E7D1 0x93D0 # 0 +0x8EA2E7D2 0x93F9 # 0 +0x8EA2E7D3 0x93EC # 0 +0x8EA2E7D4 0x93CC # 0 +0x8EA2E7D5 0x93D9 # 0 +0x8EA2E7D6 0x93A9 # 0 +0x8EA2E7D7 0x93E6 # 0 +0x8EA2E7D8 0x93CA # 0 +0x8EA2E7D9 0x93D4 # 0 +0x8EA2E7DA 0x93EE # 0 +0x8EA2E7DB 0x93E3 # 0 +0x8EA2E7DC 0x93D5 # 0 +0x8EA2E7DD 0x93C4 # 0 +0x8EA2E7DE 0x93CE # 0 +0x8EA2E7DF 0x93C0 # 0 +0x8EA2E7E0 0x93D2 # 0 +0x8EA2E7E1 0x93A5 # 0 +0x8EA2E7E2 0x93E7 # 0 +0x8EA2E7E3 0x957D # 0 +0x8EA2E7E4 0x95DA # 0 +0x8EA2E7E5 0x95DB # 0 +0x8EA2E7E6 0x96E1 # 0 +0x8EA2E7E7 0x9729 # 0 +0x8EA2E7E8 0x972B # 0 +0x8EA2E7E9 0x972C # 0 +0x8EA2E7EA 0x9728 # 0 +0x8EA2E7EB 0x9726 # 0 +0x8EA2E7EC 0x97B3 # 0 +0x8EA2E7ED 0x97B7 # 0 +0x8EA2E7EE 0x97B6 # 0 +0x8EA2E7EF 0x97DD # 0 +0x8EA2E7F0 0x97DE # 0 +0x8EA2E7F1 0x97DF # 0 +0x8EA2E7F2 0x985C # 0 +0x8EA2E7F3 0x9859 # 0 +0x8EA2E7F4 0x985D # 0 +0x8EA2E7F5 0x9857 # 0 +0x8EA2E7F6 0x98BF # 0 +0x8EA2E7F7 0x98BD # 0 +0x8EA2E7F8 0x98BB # 0 +0x8EA2E7F9 0x98BE # 0 +0x8EA2E7FA 0x9948 # 0 +0x8EA2E7FB 0x9947 # 0 +0x8EA2E7FC 0x9943 # 0 +0x8EA2E7FD 0x99A6 # 0 +0x8EA2E7FE 0x99A7 # 0 +0x8EA2E8A1 0x9A1A # 0 +0x8EA2E8A2 0x9A15 # 0 +0x8EA2E8A3 0x9A25 # 0 +0x8EA2E8A4 0x9A1D # 0 +0x8EA2E8A5 0x9A24 # 0 +0x8EA2E8A6 0x9A1B # 0 +0x8EA2E8A7 0x9A22 # 0 +0x8EA2E8A8 0x9A20 # 0 +0x8EA2E8A9 0x9A27 # 0 +0x8EA2E8AA 0x9A23 # 0 +0x8EA2E8AB 0x9A1E # 0 +0x8EA2E8AC 0x9A1C # 0 +0x8EA2E8AD 0x9A14 # 0 +0x8EA2E8AE 0x9AC2 # 0 +0x8EA2E8AF 0x9B0B # 0 +0x8EA2E8B0 0x9B0A # 0 +0x8EA2E8B1 0x9B0E # 0 +0x8EA2E8B2 0x9B0C # 0 +0x8EA2E8B3 0x9B37 # 0 +0x8EA2E8B4 0x9BEA # 0 +0x8EA2E8B5 0x9BEB # 0 +0x8EA2E8B6 0x9BE0 # 0 +0x8EA2E8B7 0x9BDE # 0 +0x8EA2E8B8 0x9BE4 # 0 +0x8EA2E8B9 0x9BE6 # 0 +0x8EA2E8BA 0x9BE2 # 0 +0x8EA2E8BB 0x9BF0 # 0 +0x8EA2E8BC 0x9BD4 # 0 +0x8EA2E8BD 0x9BD7 # 0 +0x8EA2E8BE 0x9BEC # 0 +0x8EA2E8BF 0x9BDC # 0 +0x8EA2E8C0 0x9BD9 # 0 +0x8EA2E8C1 0x9BE5 # 0 +0x8EA2E8C2 0x9BD5 # 0 +0x8EA2E8C3 0x9BE1 # 0 +0x8EA2E8C4 0x9BDA # 0 +0x8EA2E8C5 0x9D77 # 0 +0x8EA2E8C6 0x9D81 # 0 +0x8EA2E8C7 0x9D8A # 0 +0x8EA2E8C8 0x9D84 # 0 +0x8EA2E8C9 0x9D88 # 0 +0x8EA2E8CA 0x9D71 # 0 +0x8EA2E8CB 0x9D80 # 0 +0x8EA2E8CC 0x9D78 # 0 +0x8EA2E8CD 0x9D86 # 0 +0x8EA2E8CE 0x9D8B # 0 +0x8EA2E8CF 0x9D8C # 0 +0x8EA2E8D0 0x9D7D # 0 +0x8EA2E8D1 0x9D6B # 0 +0x8EA2E8D2 0x9D74 # 0 +0x8EA2E8D3 0x9D75 # 0 +0x8EA2E8D4 0x9D70 # 0 +0x8EA2E8D5 0x9D69 # 0 +0x8EA2E8D6 0x9D85 # 0 +0x8EA2E8D7 0x9D73 # 0 +0x8EA2E8D8 0x9D7B # 0 +0x8EA2E8D9 0x9D82 # 0 +0x8EA2E8DA 0x9D6F # 0 +0x8EA2E8DB 0x9D79 # 0 +0x8EA2E8DC 0x9D7F # 0 +0x8EA2E8DD 0x9D87 # 0 +0x8EA2E8DE 0x9D68 # 0 +0x8EA2E8DF 0x9E94 # 0 +0x8EA2E8E0 0x9E91 # 0 +0x8EA2E8E1 0x9EC0 # 0 +0x8EA2E8E2 0x9EFC # 0 +0x8EA2E8E3 0x9F2D # 0 +0x8EA2E8E4 0x9F40 # 0 +0x8EA2E8E5 0x9F41 # 0 +0x8EA2E8E6 0x9F4D # 0 +0x8EA2E8E7 0x9F56 # 0 +0x8EA2E8E8 0x9F57 # 0 +0x8EA2E8E9 0x9F58 # 0 +0x8EA2E8EA 0x5337 # 0 +0x8EA2E8EB 0x56B2 # 0 +0x8EA2E8EC 0x56B5 # 0 +0x8EA2E8ED 0x56B3 # 0 +0x8EA2E8EE 0x58E3 # 0 +0x8EA2E8EF 0x5B45 # 0 +0x8EA2E8F0 0x5DC6 # 0 +0x8EA2E8F1 0x5DC7 # 0 +0x8EA2E8F2 0x5EEE # 0 +0x8EA2E8F3 0x5EEF # 0 +0x8EA2E8F4 0x5FC0 # 0 +0x8EA2E8F5 0x5FC1 # 0 +0x8EA2E8F6 0x61F9 # 0 +0x8EA2E8F7 0x6517 # 0 +0x8EA2E8F8 0x6516 # 0 +0x8EA2E8F9 0x6515 # 0 +0x8EA2E8FA 0x6513 # 0 +0x8EA2E8FB 0x65DF # 0 +0x8EA2E8FC 0x66E8 # 0 +0x8EA2E8FD 0x66E3 # 0 +0x8EA2E8FE 0x66E4 # 0 +0x8EA2E9A1 0x6AF3 # 0 +0x8EA2E9A2 0x6AF0 # 0 +0x8EA2E9A3 0x6AEA # 0 +0x8EA2E9A4 0x6AE8 # 0 +0x8EA2E9A5 0x6AF9 # 0 +0x8EA2E9A6 0x6AF1 # 0 +0x8EA2E9A7 0x6AEE # 0 +0x8EA2E9A8 0x6AEF # 0 +0x8EA2E9A9 0x703C # 0 +0x8EA2E9AA 0x7035 # 0 +0x8EA2E9AB 0x702F # 0 +0x8EA2E9AC 0x7037 # 0 +0x8EA2E9AD 0x7034 # 0 +0x8EA2E9AE 0x7031 # 0 +0x8EA2E9AF 0x7042 # 0 +0x8EA2E9B0 0x7038 # 0 +0x8EA2E9B1 0x703F # 0 +0x8EA2E9B2 0x703A # 0 +0x8EA2E9B3 0x7039 # 0 +0x8EA2E9B4 0x702A # 0 +0x8EA2E9B5 0x7040 # 0 +0x8EA2E9B6 0x703B # 0 +0x8EA2E9B7 0x7033 # 0 +0x8EA2E9B8 0x7041 # 0 +0x8EA2E9B9 0x7213 # 0 +0x8EA2E9BA 0x7214 # 0 +0x8EA2E9BB 0x72A8 # 0 +0x8EA2E9BC 0x737D # 0 +0x8EA2E9BD 0x737C # 0 +0x8EA2E9BE 0x74BA # 0 +0x8EA2E9BF 0x76AB # 0 +0x8EA2E9C0 0x76AA # 0 +0x8EA2E9C1 0x76BE # 0 +0x8EA2E9C2 0x76ED # 0 +0x8EA2E9C3 0x77CC # 0 +0x8EA2E9C4 0x77CE # 0 +0x8EA2E9C5 0x77CF # 0 +0x8EA2E9C6 0x77CD # 0 +0x8EA2E9C7 0x77F2 # 0 +0x8EA2E9C8 0x7925 # 0 +0x8EA2E9C9 0x7923 # 0 +0x8EA2E9CA 0x7927 # 0 +0x8EA2E9CB 0x7928 # 0 +0x8EA2E9CC 0x7924 # 0 +0x8EA2E9CD 0x7929 # 0 +0x8EA2E9CE 0x79B2 # 0 +0x8EA2E9CF 0x7A6E # 0 +0x8EA2E9D0 0x7A6C # 0 +0x8EA2E9D1 0x7A6D # 0 +0x8EA2E9D2 0x7AF7 # 0 +0x8EA2E9D3 0x7C49 # 0 +0x8EA2E9D4 0x7C48 # 0 +0x8EA2E9D5 0x7C4A # 0 +0x8EA2E9D6 0x7C47 # 0 +0x8EA2E9D7 0x7C45 # 0 +0x8EA2E9D8 0x7CEE # 0 +0x8EA2E9D9 0x7E7B # 0 +0x8EA2E9DA 0x7E7E # 0 +0x8EA2E9DB 0x7E81 # 0 +0x8EA2E9DC 0x7E80 # 0 +0x8EA2E9DD 0x7FBA # 0 +0x8EA2E9DE 0x7FFF # 0 +0x8EA2E9DF 0x8079 # 0 +0x8EA2E9E0 0x81DB # 0 +0x8EA2E9E1 0x81D9 # 0 +0x8EA2E9E2 0x8268 # 0 +0x8EA2E9E3 0x8269 # 0 +0x8EA2E9E4 0x8622 # 0 +0x8EA2E9E5 0x85FF # 0 +0x8EA2E9E6 0x8601 # 0 +0x8EA2E9E7 0x85FE # 0 +0x8EA2E9E8 0x861B # 0 +0x8EA2E9E9 0x8600 # 0 +0x8EA2E9EA 0x85F6 # 0 +0x8EA2E9EB 0x8604 # 0 +0x8EA2E9EC 0x8609 # 0 +0x8EA2E9ED 0x8605 # 0 +0x8EA2E9EE 0x860C # 0 +0x8EA2E9EF 0x85FD # 0 +0x8EA2E9F0 0x8819 # 0 +0x8EA2E9F1 0x8810 # 0 +0x8EA2E9F2 0x8811 # 0 +0x8EA2E9F3 0x8817 # 0 +0x8EA2E9F4 0x8813 # 0 +0x8EA2E9F5 0x8816 # 0 +0x8EA2E9F6 0x8963 # 0 +0x8EA2E9F7 0x8966 # 0 +0x8EA2E9F8 0x89B9 # 0 +0x8EA2E9F9 0x89F7 # 0 +0x8EA2E9FA 0x8B60 # 0 +0x8EA2E9FB 0x8B6A # 0 +0x8EA2E9FC 0x8B5D # 0 +0x8EA2E9FD 0x8B68 # 0 +0x8EA2E9FE 0x8B63 # 0 +0x8EA2EAA1 0x8B65 # 0 +0x8EA2EAA2 0x8B67 # 0 +0x8EA2EAA3 0x8B6D # 0 +0x8EA2EAA4 0x8DAE # 0 +0x8EA2EAA5 0x8E86 # 0 +0x8EA2EAA6 0x8E88 # 0 +0x8EA2EAA7 0x8E84 # 0 +0x8EA2EAA8 0x8F59 # 0 +0x8EA2EAA9 0x8F56 # 0 +0x8EA2EAAA 0x8F57 # 0 +0x8EA2EAAB 0x8F55 # 0 +0x8EA2EAAC 0x8F58 # 0 +0x8EA2EAAD 0x8F5A # 0 +0x8EA2EAAE 0x908D # 0 +0x8EA2EAAF 0x9143 # 0 +0x8EA2EAB0 0x9141 # 0 +0x8EA2EAB1 0x91B7 # 0 +0x8EA2EAB2 0x91B5 # 0 +0x8EA2EAB3 0x91B2 # 0 +0x8EA2EAB4 0x91B3 # 0 +0x8EA2EAB5 0x940B # 0 +0x8EA2EAB6 0x9413 # 0 +0x8EA2EAB7 0x93FB # 0 +0x8EA2EAB8 0x9420 # 0 +0x8EA2EAB9 0x940F # 0 +0x8EA2EABA 0x9414 # 0 +0x8EA2EABB 0x93FE # 0 +0x8EA2EABC 0x9415 # 0 +0x8EA2EABD 0x9410 # 0 +0x8EA2EABE 0x9428 # 0 +0x8EA2EABF 0x9419 # 0 +0x8EA2EAC0 0x940D # 0 +0x8EA2EAC1 0x93F5 # 0 +0x8EA2EAC2 0x9400 # 0 +0x8EA2EAC3 0x93F7 # 0 +0x8EA2EAC4 0x9407 # 0 +0x8EA2EAC5 0x940E # 0 +0x8EA2EAC6 0x9416 # 0 +0x8EA2EAC7 0x9412 # 0 +0x8EA2EAC8 0x93FA # 0 +0x8EA2EAC9 0x9409 # 0 +0x8EA2EACA 0x93F8 # 0 +0x8EA2EACB 0x943C # 0 +0x8EA2EACC 0x940A # 0 +0x8EA2EACD 0x93FF # 0 +0x8EA2EACE 0x93FC # 0 +0x8EA2EACF 0x940C # 0 +0x8EA2EAD0 0x93F6 # 0 +0x8EA2EAD1 0x9411 # 0 +0x8EA2EAD2 0x9406 # 0 +0x8EA2EAD3 0x95DE # 0 +0x8EA2EAD4 0x95E0 # 0 +0x8EA2EAD5 0x95DF # 0 +0x8EA2EAD6 0x972E # 0 +0x8EA2EAD7 0x972F # 0 +0x8EA2EAD8 0x97B9 # 0 +0x8EA2EAD9 0x97BB # 0 +0x8EA2EADA 0x97FD # 0 +0x8EA2EADB 0x97FE # 0 +0x8EA2EADC 0x9860 # 0 +0x8EA2EADD 0x9862 # 0 +0x8EA2EADE 0x9863 # 0 +0x8EA2EADF 0x985F # 0 +0x8EA2EAE0 0x98C1 # 0 +0x8EA2EAE1 0x98C2 # 0 +0x8EA2EAE2 0x9950 # 0 +0x8EA2EAE3 0x994E # 0 +0x8EA2EAE4 0x9959 # 0 +0x8EA2EAE5 0x994C # 0 +0x8EA2EAE6 0x994B # 0 +0x8EA2EAE7 0x9953 # 0 +0x8EA2EAE8 0x9A32 # 0 +0x8EA2EAE9 0x9A34 # 0 +0x8EA2EAEA 0x9A31 # 0 +0x8EA2EAEB 0x9A2C # 0 +0x8EA2EAEC 0x9A2A # 0 +0x8EA2EAED 0x9A36 # 0 +0x8EA2EAEE 0x9A29 # 0 +0x8EA2EAEF 0x9A2E # 0 +0x8EA2EAF0 0x9A38 # 0 +0x8EA2EAF1 0x9A2D # 0 +0x8EA2EAF2 0x9AC7 # 0 +0x8EA2EAF3 0x9ACA # 0 +0x8EA2EAF4 0x9AC6 # 0 +0x8EA2EAF5 0x9B10 # 0 +0x8EA2EAF6 0x9B12 # 0 +0x8EA2EAF7 0x9B11 # 0 +0x8EA2EAF8 0x9C0B # 0 +0x8EA2EAF9 0x9C08 # 0 +0x8EA2EAFA 0x9BF7 # 0 +0x8EA2EAFB 0x9C05 # 0 +0x8EA2EAFC 0x9C12 # 0 +0x8EA2EAFD 0x9BF8 # 0 +0x8EA2EAFE 0x9C40 # 0 +0x8EA2EBA1 0x9C07 # 0 +0x8EA2EBA2 0x9C0E # 0 +0x8EA2EBA3 0x9C06 # 0 +0x8EA2EBA4 0x9C17 # 0 +0x8EA2EBA5 0x9C14 # 0 +0x8EA2EBA6 0x9C09 # 0 +0x8EA2EBA7 0x9D9F # 0 +0x8EA2EBA8 0x9D99 # 0 +0x8EA2EBA9 0x9DA4 # 0 +0x8EA2EBAA 0x9D9D # 0 +0x8EA2EBAB 0x9D92 # 0 +0x8EA2EBAC 0x9D98 # 0 +0x8EA2EBAD 0x9D90 # 0 +0x8EA2EBAE 0x9D9B # 0 +0x8EA2EBAF 0x9DA0 # 0 +0x8EA2EBB0 0x9D94 # 0 +0x8EA2EBB1 0x9D9C # 0 +0x8EA2EBB2 0x9DAA # 0 +0x8EA2EBB3 0x9D97 # 0 +0x8EA2EBB4 0x9DA1 # 0 +0x8EA2EBB5 0x9D9A # 0 +0x8EA2EBB6 0x9DA2 # 0 +0x8EA2EBB7 0x9DA8 # 0 +0x8EA2EBB8 0x9D9E # 0 +0x8EA2EBB9 0x9DA3 # 0 +0x8EA2EBBA 0x9DBF # 0 +0x8EA2EBBB 0x9DA9 # 0 +0x8EA2EBBC 0x9D96 # 0 +0x8EA2EBBD 0x9DA6 # 0 +0x8EA2EBBE 0x9DA7 # 0 +0x8EA2EBBF 0x9E99 # 0 +0x8EA2EBC0 0x9E9B # 0 +0x8EA2EBC1 0x9E9A # 0 +0x8EA2EBC2 0x9EE5 # 0 +0x8EA2EBC3 0x9EE4 # 0 +0x8EA2EBC4 0x9EE7 # 0 +0x8EA2EBC5 0x9EE6 # 0 +0x8EA2EBC6 0x9F30 # 0 +0x8EA2EBC7 0x9F2E # 0 +0x8EA2EBC8 0x9F5B # 0 +0x8EA2EBC9 0x9F60 # 0 +0x8EA2EBCA 0x9F5E # 0 +0x8EA2EBCB 0x9F5D # 0 +0x8EA2EBCC 0x9F59 # 0 +0x8EA2EBCD 0x9F91 # 0 +0x8EA2EBCE 0x513A # 0 +0x8EA2EBCF 0x5139 # 0 +0x8EA2EBD0 0x5298 # 0 +0x8EA2EBD1 0x5297 # 0 +0x8EA2EBD2 0x56C3 # 0 +0x8EA2EBD3 0x56BD # 0 +0x8EA2EBD4 0x56BE # 0 +0x8EA2EBD5 0x5B48 # 0 +0x8EA2EBD6 0x5B47 # 0 +0x8EA2EBD7 0x5DCB # 0 +0x8EA2EBD8 0x5DCF # 0 +0x8EA2EBD9 0x5EF1 # 0 +0x8EA2EBDA 0x61FD # 0 +0x8EA2EBDB 0x651B # 0 +0x8EA2EBDC 0x6B02 # 0 +0x8EA2EBDD 0x6AFC # 0 +0x8EA2EBDE 0x6B03 # 0 +0x8EA2EBDF 0x6AF8 # 0 +0x8EA2EBE0 0x6B00 # 0 +0x8EA2EBE1 0x7043 # 0 +0x8EA2EBE2 0x7044 # 0 +0x8EA2EBE3 0x704A # 0 +0x8EA2EBE4 0x7048 # 0 +0x8EA2EBE5 0x7049 # 0 +0x8EA2EBE6 0x7045 # 0 +0x8EA2EBE7 0x7046 # 0 +0x8EA2EBE8 0x721D # 0 +0x8EA2EBE9 0x721A # 0 +0x8EA2EBEA 0x7219 # 0 +0x8EA2EBEB 0x737E # 0 +0x8EA2EBEC 0x7517 # 0 +0x8EA2EBED 0x766A # 0 +0x8EA2EBEE 0x77D0 # 0 +0x8EA2EBEF 0x792D # 0 +0x8EA2EBF0 0x7931 # 0 +0x8EA2EBF1 0x792F # 0 +0x8EA2EBF2 0x7C54 # 0 +0x8EA2EBF3 0x7C53 # 0 +0x8EA2EBF4 0x7CF2 # 0 +0x8EA2EBF5 0x7E8A # 0 +0x8EA2EBF6 0x7E87 # 0 +0x8EA2EBF7 0x7E88 # 0 +0x8EA2EBF8 0x7E8B # 0 +0x8EA2EBF9 0x7E86 # 0 +0x8EA2EBFA 0x7E8D # 0 +0x8EA2EBFB 0x7F4D # 0 +0x8EA2EBFC 0x7FBB # 0 +0x8EA2EBFD 0x8030 # 0 +0x8EA2EBFE 0x81DD # 0 +0x8EA2ECA1 0x8618 # 0 +0x8EA2ECA2 0x862A # 0 +0x8EA2ECA3 0x8626 # 0 +0x8EA2ECA4 0x861F # 0 +0x8EA2ECA5 0x8623 # 0 +0x8EA2ECA6 0x861C # 0 +0x8EA2ECA7 0x8619 # 0 +0x8EA2ECA8 0x8627 # 0 +0x8EA2ECA9 0x862E # 0 +0x8EA2ECAA 0x8621 # 0 +0x8EA2ECAB 0x8620 # 0 +0x8EA2ECAC 0x8629 # 0 +0x8EA2ECAD 0x861E # 0 +0x8EA2ECAE 0x8625 # 0 +0x8EA2ECAF 0x8829 # 0 +0x8EA2ECB0 0x881D # 0 +0x8EA2ECB1 0x881B # 0 +0x8EA2ECB2 0x8820 # 0 +0x8EA2ECB3 0x8824 # 0 +0x8EA2ECB4 0x881C # 0 +0x8EA2ECB5 0x882B # 0 +0x8EA2ECB6 0x884A # 0 +0x8EA2ECB7 0x896D # 0 +0x8EA2ECB8 0x8969 # 0 +0x8EA2ECB9 0x896E # 0 +0x8EA2ECBA 0x896B # 0 +0x8EA2ECBB 0x89FA # 0 +0x8EA2ECBC 0x8B79 # 0 +0x8EA2ECBD 0x8B78 # 0 +0x8EA2ECBE 0x8B45 # 0 +0x8EA2ECBF 0x8B7A # 0 +0x8EA2ECC0 0x8B7B # 0 +0x8EA2ECC1 0x8D10 # 0 +0x8EA2ECC2 0x8D14 # 0 +0x8EA2ECC3 0x8DAF # 0 +0x8EA2ECC4 0x8E8E # 0 +0x8EA2ECC5 0x8E8C # 0 +0x8EA2ECC6 0x8F5E # 0 +0x8EA2ECC7 0x8F5B # 0 +0x8EA2ECC8 0x8F5D # 0 +0x8EA2ECC9 0x9146 # 0 +0x8EA2ECCA 0x9144 # 0 +0x8EA2ECCB 0x9145 # 0 +0x8EA2ECCC 0x91B9 # 0 +0x8EA2ECCD 0x943F # 0 +0x8EA2ECCE 0x943B # 0 +0x8EA2ECCF 0x9436 # 0 +0x8EA2ECD0 0x9429 # 0 +0x8EA2ECD1 0x943D # 0 +0x8EA2ECD2 0x9430 # 0 +0x8EA2ECD3 0x9439 # 0 +0x8EA2ECD4 0x942A # 0 +0x8EA2ECD5 0x9437 # 0 +0x8EA2ECD6 0x942C # 0 +0x8EA2ECD7 0x9440 # 0 +0x8EA2ECD8 0x9431 # 0 +0x8EA2ECD9 0x95E5 # 0 +0x8EA2ECDA 0x95E4 # 0 +0x8EA2ECDB 0x95E3 # 0 +0x8EA2ECDC 0x9735 # 0 +0x8EA2ECDD 0x973A # 0 +0x8EA2ECDE 0x97BF # 0 +0x8EA2ECDF 0x97E1 # 0 +0x8EA2ECE0 0x9864 # 0 +0x8EA2ECE1 0x98C9 # 0 +0x8EA2ECE2 0x98C6 # 0 +0x8EA2ECE3 0x98C0 # 0 +0x8EA2ECE4 0x9958 # 0 +0x8EA2ECE5 0x9956 # 0 +0x8EA2ECE6 0x9A39 # 0 +0x8EA2ECE7 0x9A3D # 0 +0x8EA2ECE8 0x9A46 # 0 +0x8EA2ECE9 0x9A44 # 0 +0x8EA2ECEA 0x9A42 # 0 +0x8EA2ECEB 0x9A41 # 0 +0x8EA2ECEC 0x9A3A # 0 +0x8EA2ECED 0x9A3F # 0 +0x8EA2ECEE 0x9ACD # 0 +0x8EA2ECEF 0x9B15 # 0 +0x8EA2ECF0 0x9B17 # 0 +0x8EA2ECF1 0x9B18 # 0 +0x8EA2ECF2 0x9B16 # 0 +0x8EA2ECF3 0x9B3A # 0 +0x8EA2ECF4 0x9B52 # 0 +0x8EA2ECF5 0x9C2B # 0 +0x8EA2ECF6 0x9C1D # 0 +0x8EA2ECF7 0x9C1C # 0 +0x8EA2ECF8 0x9C2C # 0 +0x8EA2ECF9 0x9C23 # 0 +0x8EA2ECFA 0x9C28 # 0 +0x8EA2ECFB 0x9C29 # 0 +0x8EA2ECFC 0x9C24 # 0 +0x8EA2ECFD 0x9C21 # 0 +0x8EA2ECFE 0x9DB7 # 0 +0x8EA2EDA1 0x9DB6 # 0 +0x8EA2EDA2 0x9DBC # 0 +0x8EA2EDA3 0x9DC1 # 0 +0x8EA2EDA4 0x9DC7 # 0 +0x8EA2EDA5 0x9DCA # 0 +0x8EA2EDA6 0x9DCF # 0 +0x8EA2EDA7 0x9DBE # 0 +0x8EA2EDA8 0x9DC5 # 0 +0x8EA2EDA9 0x9DC3 # 0 +0x8EA2EDAA 0x9DBB # 0 +0x8EA2EDAB 0x9DB5 # 0 +0x8EA2EDAC 0x9DCE # 0 +0x8EA2EDAD 0x9DB9 # 0 +0x8EA2EDAE 0x9DBA # 0 +0x8EA2EDAF 0x9DAC # 0 +0x8EA2EDB0 0x9DC8 # 0 +0x8EA2EDB1 0x9DB1 # 0 +0x8EA2EDB2 0x9DAD # 0 +0x8EA2EDB3 0x9DCC # 0 +0x8EA2EDB4 0x9DB3 # 0 +0x8EA2EDB5 0x9DCD # 0 +0x8EA2EDB6 0x9DB2 # 0 +0x8EA2EDB7 0x9E7A # 0 +0x8EA2EDB8 0x9E9C # 0 +0x8EA2EDB9 0x9EEB # 0 +0x8EA2EDBA 0x9EEE # 0 +0x8EA2EDBB 0x9EED # 0 +0x8EA2EDBC 0x9F1B # 0 +0x8EA2EDBD 0x9F18 # 0 +0x8EA2EDBE 0x9F1A # 0 +0x8EA2EDBF 0x9F31 # 0 +0x8EA2EDC0 0x9F4E # 0 +0x8EA2EDC1 0x9F65 # 0 +0x8EA2EDC2 0x9F64 # 0 +0x8EA2EDC3 0x9F92 # 0 +0x8EA2EDC4 0x4EB9 # 0 +0x8EA2EDC5 0x56C6 # 0 +0x8EA2EDC6 0x56C5 # 0 +0x8EA2EDC7 0x56CB # 0 +0x8EA2EDC8 0x5971 # 0 +0x8EA2EDC9 0x5B4B # 0 +0x8EA2EDCA 0x5B4C # 0 +0x8EA2EDCB 0x5DD5 # 0 +0x8EA2EDCC 0x5DD1 # 0 +0x8EA2EDCD 0x5EF2 # 0 +0x8EA2EDCE 0x6521 # 0 +0x8EA2EDCF 0x6520 # 0 +0x8EA2EDD0 0x6526 # 0 +0x8EA2EDD1 0x6522 # 0 +0x8EA2EDD2 0x6B0B # 0 +0x8EA2EDD3 0x6B08 # 0 +0x8EA2EDD4 0x6B09 # 0 +0x8EA2EDD5 0x6C0D # 0 +0x8EA2EDD6 0x7055 # 0 +0x8EA2EDD7 0x7056 # 0 +0x8EA2EDD8 0x7057 # 0 +0x8EA2EDD9 0x7052 # 0 +0x8EA2EDDA 0x721E # 0 +0x8EA2EDDB 0x721F # 0 +0x8EA2EDDC 0x72A9 # 0 +0x8EA2EDDD 0x737F # 0 +0x8EA2EDDE 0x74D8 # 0 +0x8EA2EDDF 0x74D5 # 0 +0x8EA2EDE0 0x74D9 # 0 +0x8EA2EDE1 0x74D7 # 0 +0x8EA2EDE2 0x766D # 0 +0x8EA2EDE3 0x76AD # 0 +0x8EA2EDE4 0x7935 # 0 +0x8EA2EDE5 0x79B4 # 0 +0x8EA2EDE6 0x7A70 # 0 +0x8EA2EDE7 0x7A71 # 0 +0x8EA2EDE8 0x7C57 # 0 +0x8EA2EDE9 0x7C5C # 0 +0x8EA2EDEA 0x7C59 # 0 +0x8EA2EDEB 0x7C5B # 0 +0x8EA2EDEC 0x7C5A # 0 +0x8EA2EDED 0x7CF4 # 0 +0x8EA2EDEE 0x7CF1 # 0 +0x8EA2EDEF 0x7E91 # 0 +0x8EA2EDF0 0x7F4F # 0 +0x8EA2EDF1 0x7F87 # 0 +0x8EA2EDF2 0x81DE # 0 +0x8EA2EDF3 0x826B # 0 +0x8EA2EDF4 0x8634 # 0 +0x8EA2EDF5 0x8635 # 0 +0x8EA2EDF6 0x8633 # 0 +0x8EA2EDF7 0x862C # 0 +0x8EA2EDF8 0x8632 # 0 +0x8EA2EDF9 0x8636 # 0 +0x8EA2EDFA 0x882C # 0 +0x8EA2EDFB 0x8828 # 0 +0x8EA2EDFC 0x8826 # 0 +0x8EA2EDFD 0x882A # 0 +0x8EA2EDFE 0x8825 # 0 +0x8EA2EEA1 0x8971 # 0 +0x8EA2EEA2 0x89BF # 0 +0x8EA2EEA3 0x89BE # 0 +0x8EA2EEA4 0x89FB # 0 +0x8EA2EEA5 0x8B7E # 0 +0x8EA2EEA6 0x8B84 # 0 +0x8EA2EEA7 0x8B82 # 0 +0x8EA2EEA8 0x8B86 # 0 +0x8EA2EEA9 0x8B85 # 0 +0x8EA2EEAA 0x8B7F # 0 +0x8EA2EEAB 0x8D15 # 0 +0x8EA2EEAC 0x8E95 # 0 +0x8EA2EEAD 0x8E94 # 0 +0x8EA2EEAE 0x8E9A # 0 +0x8EA2EEAF 0x8E92 # 0 +0x8EA2EEB0 0x8E90 # 0 +0x8EA2EEB1 0x8E96 # 0 +0x8EA2EEB2 0x8E97 # 0 +0x8EA2EEB3 0x8F60 # 0 +0x8EA2EEB4 0x8F62 # 0 +0x8EA2EEB5 0x9147 # 0 +0x8EA2EEB6 0x944C # 0 +0x8EA2EEB7 0x9450 # 0 +0x8EA2EEB8 0x944A # 0 +0x8EA2EEB9 0x944B # 0 +0x8EA2EEBA 0x944F # 0 +0x8EA2EEBB 0x9447 # 0 +0x8EA2EEBC 0x9445 # 0 +0x8EA2EEBD 0x9448 # 0 +0x8EA2EEBE 0x9449 # 0 +0x8EA2EEBF 0x9446 # 0 +0x8EA2EEC0 0x973F # 0 +0x8EA2EEC1 0x97E3 # 0 +0x8EA2EEC2 0x986A # 0 +0x8EA2EEC3 0x9869 # 0 +0x8EA2EEC4 0x98CB # 0 +0x8EA2EEC5 0x9954 # 0 +0x8EA2EEC6 0x995B # 0 +0x8EA2EEC7 0x9A4E # 0 +0x8EA2EEC8 0x9A53 # 0 +0x8EA2EEC9 0x9A54 # 0 +0x8EA2EECA 0x9A4C # 0 +0x8EA2EECB 0x9A4F # 0 +0x8EA2EECC 0x9A48 # 0 +0x8EA2EECD 0x9A4A # 0 +0x8EA2EECE 0x9A49 # 0 +0x8EA2EECF 0x9A52 # 0 +0x8EA2EED0 0x9A50 # 0 +0x8EA2EED1 0x9AD0 # 0 +0x8EA2EED2 0x9B19 # 0 +0x8EA2EED3 0x9B2B # 0 +0x8EA2EED4 0x9B3B # 0 +0x8EA2EED5 0x9B56 # 0 +0x8EA2EED6 0x9B55 # 0 +0x8EA2EED7 0x9C46 # 0 +0x8EA2EED8 0x9C48 # 0 +0x8EA2EED9 0x9C3F # 0 +0x8EA2EEDA 0x9C44 # 0 +0x8EA2EEDB 0x9C39 # 0 +0x8EA2EEDC 0x9C33 # 0 +0x8EA2EEDD 0x9C41 # 0 +0x8EA2EEDE 0x9C3C # 0 +0x8EA2EEDF 0x9C37 # 0 +0x8EA2EEE0 0x9C34 # 0 +0x8EA2EEE1 0x9C32 # 0 +0x8EA2EEE2 0x9C3D # 0 +0x8EA2EEE3 0x9C36 # 0 +0x8EA2EEE4 0x9DDB # 0 +0x8EA2EEE5 0x9DD2 # 0 +0x8EA2EEE6 0x9DDE # 0 +0x8EA2EEE7 0x9DDA # 0 +0x8EA2EEE8 0x9DCB # 0 +0x8EA2EEE9 0x9DD0 # 0 +0x8EA2EEEA 0x9DDC # 0 +0x8EA2EEEB 0x9DD1 # 0 +0x8EA2EEEC 0x9DDF # 0 +0x8EA2EEED 0x9DE9 # 0 +0x8EA2EEEE 0x9DD9 # 0 +0x8EA2EEEF 0x9DD8 # 0 +0x8EA2EEF0 0x9DD6 # 0 +0x8EA2EEF1 0x9DF5 # 0 +0x8EA2EEF2 0x9DD5 # 0 +0x8EA2EEF3 0x9DDD # 0 +0x8EA2EEF4 0x9EB6 # 0 +0x8EA2EEF5 0x9EF0 # 0 +0x8EA2EEF6 0x9F35 # 0 +0x8EA2EEF7 0x9F33 # 0 +0x8EA2EEF8 0x9F32 # 0 +0x8EA2EEF9 0x9F42 # 0 +0x8EA2EEFA 0x9F6B # 0 +0x8EA2EEFB 0x9F95 # 0 +0x8EA2EEFC 0x9FA2 # 0 +0x8EA2EEFD 0x513D # 0 +0x8EA2EEFE 0x5299 # 0 +0x8EA2EFA1 0x58E8 # 0 +0x8EA2EFA2 0x58E7 # 0 +0x8EA2EFA3 0x5972 # 0 +0x8EA2EFA4 0x5B4D # 0 +0x8EA2EFA5 0x5DD8 # 0 +0x8EA2EFA6 0x882F # 0 +0x8EA2EFA7 0x5F4F # 0 +0x8EA2EFA8 0x6201 # 0 +0x8EA2EFA9 0x6203 # 0 +0x8EA2EFAA 0x6204 # 0 +0x8EA2EFAB 0x6529 # 0 +0x8EA2EFAC 0x6525 # 0 +0x8EA2EFAD 0x6596 # 0 +0x8EA2EFAE 0x66EB # 0 +0x8EA2EFAF 0x6B11 # 0 +0x8EA2EFB0 0x6B12 # 0 +0x8EA2EFB1 0x6B0F # 0 +0x8EA2EFB2 0x6BCA # 0 +0x8EA2EFB3 0x705B # 0 +0x8EA2EFB4 0x705A # 0 +0x8EA2EFB5 0x7222 # 0 +0x8EA2EFB6 0x7382 # 0 +0x8EA2EFB7 0x7381 # 0 +0x8EA2EFB8 0x7383 # 0 +0x8EA2EFB9 0x7670 # 0 +0x8EA2EFBA 0x77D4 # 0 +0x8EA2EFBB 0x7C67 # 0 +0x8EA2EFBC 0x7C66 # 0 +0x8EA2EFBD 0x7E95 # 0 +0x8EA2EFBE 0x826C # 0 +0x8EA2EFBF 0x863A # 0 +0x8EA2EFC0 0x8640 # 0 +0x8EA2EFC1 0x8639 # 0 +0x8EA2EFC2 0x863C # 0 +0x8EA2EFC3 0x8631 # 0 +0x8EA2EFC4 0x863B # 0 +0x8EA2EFC5 0x863E # 0 +0x8EA2EFC6 0x8830 # 0 +0x8EA2EFC7 0x8832 # 0 +0x8EA2EFC8 0x882E # 0 +0x8EA2EFC9 0x8833 # 0 +0x8EA2EFCA 0x8976 # 0 +0x8EA2EFCB 0x8974 # 0 +0x8EA2EFCC 0x8973 # 0 +0x8EA2EFCD 0x89FE # 0 +0x8EA2EFCE 0x8B8C # 0 +0x8EA2EFCF 0x8B8E # 0 +0x8EA2EFD0 0x8B8B # 0 +0x8EA2EFD1 0x8B88 # 0 +0x8EA2EFD2 0x8C45 # 0 +0x8EA2EFD3 0x8D19 # 0 +0x8EA2EFD4 0x8E98 # 0 +0x8EA2EFD5 0x8F64 # 0 +0x8EA2EFD6 0x8F63 # 0 +0x8EA2EFD7 0x91BC # 0 +0x8EA2EFD8 0x9462 # 0 +0x8EA2EFD9 0x9455 # 0 +0x8EA2EFDA 0x945D # 0 +0x8EA2EFDB 0x9457 # 0 +0x8EA2EFDC 0x945E # 0 +0x8EA2EFDD 0x97C4 # 0 +0x8EA2EFDE 0x97C5 # 0 +0x8EA2EFDF 0x9800 # 0 +0x8EA2EFE0 0x9A56 # 0 +0x8EA2EFE1 0x9A59 # 0 +0x8EA2EFE2 0x9B1E # 0 +0x8EA2EFE3 0x9B1F # 0 +0x8EA2EFE4 0x9B20 # 0 +0x8EA2EFE5 0x9C52 # 0 +0x8EA2EFE6 0x9C58 # 0 +0x8EA2EFE7 0x9C50 # 0 +0x8EA2EFE8 0x9C4A # 0 +0x8EA2EFE9 0x9C4D # 0 +0x8EA2EFEA 0x9C4B # 0 +0x8EA2EFEB 0x9C55 # 0 +0x8EA2EFEC 0x9C59 # 0 +0x8EA2EFED 0x9C4C # 0 +0x8EA2EFEE 0x9C4E # 0 +0x8EA2EFEF 0x9DFB # 0 +0x8EA2EFF0 0x9DF7 # 0 +0x8EA2EFF1 0x9DEF # 0 +0x8EA2EFF2 0x9DE3 # 0 +0x8EA2EFF3 0x9DEB # 0 +0x8EA2EFF4 0x9DF8 # 0 +0x8EA2EFF5 0x9DE4 # 0 +0x8EA2EFF6 0x9DF6 # 0 +0x8EA2EFF7 0x9DE1 # 0 +0x8EA2EFF8 0x9DEE # 0 +0x8EA2EFF9 0x9DE6 # 0 +0x8EA2EFFA 0x9DF2 # 0 +0x8EA2EFFB 0x9DF0 # 0 +0x8EA2EFFC 0x9DE2 # 0 +0x8EA2EFFD 0x9DEC # 0 +0x8EA2EFFE 0x9DF4 # 0 +0x8EA2F0A1 0x9DF3 # 0 +0x8EA2F0A2 0x9DE8 # 0 +0x8EA2F0A3 0x9DED # 0 +0x8EA2F0A4 0x9EC2 # 0 +0x8EA2F0A5 0x9ED0 # 0 +0x8EA2F0A6 0x9EF2 # 0 +0x8EA2F0A7 0x9EF3 # 0 +0x8EA2F0A8 0x9F06 # 0 +0x8EA2F0A9 0x9F1C # 0 +0x8EA2F0AA 0x9F38 # 0 +0x8EA2F0AB 0x9F37 # 0 +0x8EA2F0AC 0x9F36 # 0 +0x8EA2F0AD 0x9F43 # 0 +0x8EA2F0AE 0x9F4F # 0 +0x8EA2F0AF 0x9F71 # 0 +0x8EA2F0B0 0x9F70 # 0 +0x8EA2F0B1 0x9F6E # 0 +0x8EA2F0B2 0x9F6F # 0 +0x8EA2F0B3 0x56D3 # 0 +0x8EA2F0B4 0x56CD # 0 +0x8EA2F0B5 0x5B4E # 0 +0x8EA2F0B6 0x5C6D # 0 +0x8EA2F0B7 0x652D # 0 +0x8EA2F0B8 0x66ED # 0 +0x8EA2F0B9 0x66EE # 0 +0x8EA2F0BA 0x6B13 # 0 +0x8EA2F0BB 0x705F # 0 +0x8EA2F0BC 0x7061 # 0 +0x8EA2F0BD 0x705D # 0 +0x8EA2F0BE 0x7060 # 0 +0x8EA2F0BF 0x7223 # 0 +0x8EA2F0C0 0x74DB # 0 +0x8EA2F0C1 0x74E5 # 0 +0x8EA2F0C2 0x77D5 # 0 +0x8EA2F0C3 0x7938 # 0 +0x8EA2F0C4 0x79B7 # 0 +0x8EA2F0C5 0x79B6 # 0 +0x8EA2F0C6 0x7C6A # 0 +0x8EA2F0C7 0x7E97 # 0 +0x8EA2F0C8 0x7F89 # 0 +0x8EA2F0C9 0x826D # 0 +0x8EA2F0CA 0x8643 # 0 +0x8EA2F0CB 0x8838 # 0 +0x8EA2F0CC 0x8837 # 0 +0x8EA2F0CD 0x8835 # 0 +0x8EA2F0CE 0x884B # 0 +0x8EA2F0CF 0x8B94 # 0 +0x8EA2F0D0 0x8B95 # 0 +0x8EA2F0D1 0x8E9E # 0 +0x8EA2F0D2 0x8E9F # 0 +0x8EA2F0D3 0x8EA0 # 0 +0x8EA2F0D4 0x8E9D # 0 +0x8EA2F0D5 0x91BE # 0 +0x8EA2F0D6 0x91BD # 0 +0x8EA2F0D7 0x91C2 # 0 +0x8EA2F0D8 0x946B # 0 +0x8EA2F0D9 0x9468 # 0 +0x8EA2F0DA 0x9469 # 0 +0x8EA2F0DB 0x96E5 # 0 +0x8EA2F0DC 0x9746 # 0 +0x8EA2F0DD 0x9743 # 0 +0x8EA2F0DE 0x9747 # 0 +0x8EA2F0DF 0x97C7 # 0 +0x8EA2F0E0 0x97E5 # 0 +0x8EA2F0E1 0x9A5E # 0 +0x8EA2F0E2 0x9AD5 # 0 +0x8EA2F0E3 0x9B59 # 0 +0x8EA2F0E4 0x9C63 # 0 +0x8EA2F0E5 0x9C67 # 0 +0x8EA2F0E6 0x9C66 # 0 +0x8EA2F0E7 0x9C62 # 0 +0x8EA2F0E8 0x9C5E # 0 +0x8EA2F0E9 0x9C60 # 0 +0x8EA2F0EA 0x9E02 # 0 +0x8EA2F0EB 0x9DFE # 0 +0x8EA2F0EC 0x9E07 # 0 +0x8EA2F0ED 0x9E03 # 0 +0x8EA2F0EE 0x9E06 # 0 +0x8EA2F0EF 0x9E05 # 0 +0x8EA2F0F0 0x9E00 # 0 +0x8EA2F0F1 0x9E01 # 0 +0x8EA2F0F2 0x9E09 # 0 +0x8EA2F0F3 0x9DFF # 0 +0x8EA2F0F4 0x9DFD # 0 +0x8EA2F0F5 0x9E04 # 0 +0x8EA2F0F6 0x9EA0 # 0 +0x8EA2F0F7 0x9F1E # 0 +0x8EA2F0F8 0x9F46 # 0 +0x8EA2F0F9 0x9F74 # 0 +0x8EA2F0FA 0x9F75 # 0 +0x8EA2F0FB 0x9F76 # 0 +0x8EA2F0FC 0x56D4 # 0 +0x8EA2F0FD 0x652E # 0 +0x8EA2F0FE 0x65B8 # 0 +0x8EA2F1A1 0x6B18 # 0 +0x8EA2F1A2 0x6B19 # 0 +0x8EA2F1A3 0x6B17 # 0 +0x8EA2F1A4 0x6B1A # 0 +0x8EA2F1A5 0x7062 # 0 +0x8EA2F1A6 0x7226 # 0 +0x8EA2F1A7 0x72AA # 0 +0x8EA2F1A8 0x77D8 # 0 +0x8EA2F1A9 0x77D9 # 0 +0x8EA2F1AA 0x7939 # 0 +0x8EA2F1AB 0x7C69 # 0 +0x8EA2F1AC 0x7C6B # 0 +0x8EA2F1AD 0x7CF6 # 0 +0x8EA2F1AE 0x7E9A # 0 +0x8EA2F1AF 0x7E98 # 0 +0x8EA2F1B0 0x7E9B # 0 +0x8EA2F1B1 0x7E99 # 0 +0x8EA2F1B2 0x81E0 # 0 +0x8EA2F1B3 0x81E1 # 0 +0x8EA2F1B4 0x8646 # 0 +0x8EA2F1B5 0x8647 # 0 +0x8EA2F1B6 0x8648 # 0 +0x8EA2F1B7 0x8979 # 0 +0x8EA2F1B8 0x897A # 0 +0x8EA2F1B9 0x897C # 0 +0x8EA2F1BA 0x897B # 0 +0x8EA2F1BB 0x89FF # 0 +0x8EA2F1BC 0x8B98 # 0 +0x8EA2F1BD 0x8B99 # 0 +0x8EA2F1BE 0x8EA5 # 0 +0x8EA2F1BF 0x8EA4 # 0 +0x8EA2F1C0 0x8EA3 # 0 +0x8EA2F1C1 0x946E # 0 +0x8EA2F1C2 0x946D # 0 +0x8EA2F1C3 0x946F # 0 +0x8EA2F1C4 0x9471 # 0 +0x8EA2F1C5 0x9473 # 0 +0x8EA2F1C6 0x9749 # 0 +0x8EA2F1C7 0x9872 # 0 +0x8EA2F1C8 0x995F # 0 +0x8EA2F1C9 0x9C68 # 0 +0x8EA2F1CA 0x9C6E # 0 +0x8EA2F1CB 0x9C6D # 0 +0x8EA2F1CC 0x9E0B # 0 +0x8EA2F1CD 0x9E0D # 0 +0x8EA2F1CE 0x9E10 # 0 +0x8EA2F1CF 0x9E0F # 0 +0x8EA2F1D0 0x9E12 # 0 +0x8EA2F1D1 0x9E11 # 0 +0x8EA2F1D2 0x9EA1 # 0 +0x8EA2F1D3 0x9EF5 # 0 +0x8EA2F1D4 0x9F09 # 0 +0x8EA2F1D5 0x9F47 # 0 +0x8EA2F1D6 0x9F78 # 0 +0x8EA2F1D7 0x9F7B # 0 +0x8EA2F1D8 0x9F7A # 0 +0x8EA2F1D9 0x9F79 # 0 +0x8EA2F1DA 0x571E # 0 +0x8EA2F1DB 0x7066 # 0 +0x8EA2F1DC 0x7C6F # 0 +0x8EA2F1DD 0x883C # 0 +0x8EA2F1DE 0x8DB2 # 0 +0x8EA2F1DF 0x8EA6 # 0 +0x8EA2F1E0 0x91C3 # 0 +0x8EA2F1E1 0x9474 # 0 +0x8EA2F1E2 0x9478 # 0 +0x8EA2F1E3 0x9476 # 0 +0x8EA2F1E4 0x9475 # 0 +0x8EA2F1E5 0x9A60 # 0 +0x8EA2F1E6 0x9B2E # 0 +0x8EA2F1E7 0x9C74 # 0 +0x8EA2F1E8 0x9C73 # 0 +0x8EA2F1E9 0x9C71 # 0 +0x8EA2F1EA 0x9C75 # 0 +0x8EA2F1EB 0x9E14 # 0 +0x8EA2F1EC 0x9E13 # 0 +0x8EA2F1ED 0x9EF6 # 0 +0x8EA2F1EE 0x9F0A # 0 +0x8EA2F1EF 0x9FA4 # 0 +0x8EA2F1F0 0x7068 # 0 +0x8EA2F1F1 0x7065 # 0 +0x8EA2F1F2 0x7CF7 # 0 +0x8EA2F1F3 0x866A # 0 +0x8EA2F1F4 0x883E # 0 +0x8EA2F1F5 0x883D # 0 +0x8EA2F1F6 0x883F # 0 +0x8EA2F1F7 0x8B9E # 0 +0x8EA2F1F8 0x8C9C # 0 +0x8EA2F1F9 0x8EA9 # 0 +0x8EA2F1FA 0x8EC9 # 0 +0x8EA2F1FB 0x974B # 0 +0x8EA2F1FC 0x9873 # 0 +0x8EA2F1FD 0x9874 # 0 +0x8EA2F1FE 0x98CC # 0 +0x8EA2F2A1 0x9961 # 0 +0x8EA2F2A2 0x99AB # 0 +0x8EA2F2A3 0x9A64 # 0 +0x8EA2F2A4 0x9A66 # 0 +0x8EA2F2A5 0x9A67 # 0 +0x8EA2F2A6 0x9B24 # 0 +0x8EA2F2A7 0x9E15 # 0 +0x8EA2F2A8 0x9E17 # 0 +0x8EA2F2A9 0x9F48 # 0 +0x8EA2F2AA 0x6207 # 0 +0x8EA2F2AB 0x6B1E # 0 +0x8EA2F2AC 0x7227 # 0 +0x8EA2F2AD 0x864C # 0 +0x8EA2F2AE 0x8EA8 # 0 +0x8EA2F2AF 0x9482 # 0 +0x8EA2F2B0 0x9480 # 0 +0x8EA2F2B1 0x9481 # 0 +0x8EA2F2B2 0x9A69 # 0 +0x8EA2F2B3 0x9A68 # 0 +0x8EA2F2B4 0x9E19 # 0 +0x8EA2F2B5 0x864B # 0 +0x8EA2F2B6 0x8B9F # 0 +0x8EA2F2B7 0x9483 # 0 +0x8EA2F2B8 0x9C79 # 0 +0x8EA2F2B9 0x9EB7 # 0 +0x8EA2F2BA 0x7675 # 0 +0x8EA2F2BB 0x9A6B # 0 +0x8EA2F2BC 0x9C7A # 0 +0x8EA2F2BD 0x9E1D # 0 +0x8EA2F2BE 0x7069 # 0 +0x8EA2F2BF 0x706A # 0 +0x8EA2F2C0 0x7229 # 0 +0x8EA2F2C1 0x9EA4 # 0 +0x8EA2F2C2 0x9F7E # 0 +0x8EA2F2C3 0x9F49 # 0 +0x8EA2F2C4 0x9F98 # 0 +0x8EA3A1A1 0x4E28 # 0 +0x8EA3A1A2 0x4E36 # 0 +0x8EA3A1A3 0x4E3F # 0 +0x8EA3A1A4 0x4E85 # 0 +0x8EA3A1A5 0x4E05 # 0 +0x8EA3A1A6 0x4E04 # 0 +0x8EA3A1A7 0x5182 # 0 +0x8EA3A1A8 0x5196 # 0 +0x8EA3A1A9 0x5338 # 0 +0x8EA3A1AA 0x5369 # 0 +0x8EA3A1AB 0x53B6 # 0 +0x8EA3A1AC 0x4E2A # 0 +0x8EA3A1AD 0x4E87 # 0 +0x8EA3A1AE 0x4E49 # 0 +0x8EA3A1AF 0x51E2 # 0 +0x8EA3A1B0 0x4E46 # 0 +0x8EA3A1B1 0x4E8F # 0 +0x8EA3A1B2 0x4EBC # 0 +0x8EA3A1B3 0x4EBE # 0 +0x8EA3A1B4 0x5166 # 0 +0x8EA3A1B5 0x51E3 # 0 +0x8EA3A1B6 0x5204 # 0 +0x8EA3A1B7 0x529C # 0 +0x8EA3A1B9 0x5902 # 0 +0x8EA3A1BA 0x590A # 0 +0x8EA3A1BB 0x5B80 # 0 +0x8EA3A1BC 0x5DDB # 0 +0x8EA3A1BD 0x5E7A # 0 +0x8EA3A1BE 0x5E7F # 0 +0x8EA3A1BF 0x5EF4 # 0 +0x8EA3A1C0 0x5F50 # 0 +0x8EA3A1C1 0x5F51 # 0 +0x8EA3A1C2 0x5F61 # 0 +0x8EA3A1C3 0x961D # 0 +0x8EA3A1C5 0x4E63 # 0 +0x8EA3A1C6 0x4E62 # 0 +0x8EA3A1C7 0x4EA3 # 0 +0x8EA3A1C8 0x5185 # 0 +0x8EA3A1C9 0x4EC5 # 0 +0x8EA3A1CA 0x4ECF # 0 +0x8EA3A1CB 0x4ECE # 0 +0x8EA3A1CC 0x4ECC # 0 +0x8EA3A1CD 0x5184 # 0 +0x8EA3A1CE 0x5186 # 0 +0x8EA3A1D1 0x51E4 # 0 +0x8EA3A1D2 0x5205 # 0 +0x8EA3A1D3 0x529E # 0 +0x8EA3A1D4 0x529D # 0 +0x8EA3A1D5 0x52FD # 0 +0x8EA3A1D6 0x5300 # 0 +0x8EA3A1D7 0x533A # 0 +0x8EA3A1D9 0x5346 # 0 +0x8EA3A1DA 0x535D # 0 +0x8EA3A1DB 0x5386 # 0 +0x8EA3A1DC 0x53B7 # 0 +0x8EA3A1DE 0x53CC # 0 +0x8EA3A1E0 0x53CE # 0 +0x8EA3A1E1 0x5721 # 0 +0x8EA3A1E3 0x5E00 # 0 +0x8EA3A1E4 0x5F0C # 0 +0x8EA3A1E5 0x6237 # 0 +0x8EA3A1E6 0x6238 # 0 +0x8EA3A1E7 0x6534 # 0 +0x8EA3A1E8 0x6535 # 0 +0x8EA3A1E9 0x65E0 # 0 +0x8EA3A1EB 0x738D # 0 +0x8EA3A1EC 0x4E97 # 0 +0x8EA3A1ED 0x4EE0 # 0 +0x8EA3A1F0 0x4EE7 # 0 +0x8EA3A1F2 0x4EE6 # 0 +0x8EA3A1F7 0x56D8 # 0 +0x8EA3A1F8 0x518B # 0 +0x8EA3A1F9 0x518C # 0 +0x8EA3A1FA 0x5199 # 0 +0x8EA3A1FB 0x51E5 # 0 +0x8EA3A1FD 0x520B # 0 +0x8EA3A2A2 0x5304 # 0 +0x8EA3A2A3 0x5303 # 0 +0x8EA3A2A4 0x5307 # 0 +0x8EA3A2A6 0x531E # 0 +0x8EA3A2A7 0x535F # 0 +0x8EA3A2A8 0x536D # 0 +0x8EA3A2A9 0x5389 # 0 +0x8EA3A2AA 0x53BA # 0 +0x8EA3A2AB 0x53D0 # 0 +0x8EA3A2AD 0x53F6 # 0 +0x8EA3A2AE 0x53F7 # 0 +0x8EA3A2AF 0x53F9 # 0 +0x8EA3A2B1 0x53F4 # 0 +0x8EA3A2B4 0x5724 # 0 +0x8EA3A2B5 0x5904 # 0 +0x8EA3A2B6 0x5918 # 0 +0x8EA3A2B7 0x5932 # 0 +0x8EA3A2B8 0x5930 # 0 +0x8EA3A2B9 0x5934 # 0 +0x8EA3A2BB 0x5975 # 0 +0x8EA3A2BD 0x5B82 # 0 +0x8EA3A2BE 0x5BF9 # 0 +0x8EA3A2BF 0x5C14 # 0 +0x8EA3A2C7 0x5E81 # 0 +0x8EA3A2C8 0x5E83 # 0 +0x8EA3A2C9 0x5F0D # 0 +0x8EA3A2CA 0x5F52 # 0 +0x8EA3A2CC 0x5FCA # 0 +0x8EA3A2CD 0x5FC7 # 0 +0x8EA3A2CE 0x6239 # 0 +0x8EA3A2D0 0x624F # 0 +0x8EA3A2D1 0x65E7 # 0 +0x8EA3A2D2 0x672F # 0 +0x8EA3A2D3 0x6B7A # 0 +0x8EA3A2D4 0x6C39 # 0 +0x8EA3A2D7 0x6C37 # 0 +0x8EA3A2D8 0x6C44 # 0 +0x8EA3A2D9 0x6C45 # 0 +0x8EA3A2DA 0x738C # 0 +0x8EA3A2DB 0x7592 # 0 +0x8EA3A2DC 0x7676 # 0 +0x8EA3A2DD 0x9093 # 0 +0x8EA3A2DE 0x9092 # 0 +0x8EA3A2E1 0x4E21 # 0 +0x8EA3A2E2 0x4E20 # 0 +0x8EA3A2E3 0x4E22 # 0 +0x8EA3A2E4 0x4E68 # 0 +0x8EA3A2E5 0x4E89 # 0 +0x8EA3A2E6 0x4E98 # 0 +0x8EA3A2E7 0x4EF9 # 0 +0x8EA3A2E8 0x4EEF # 0 +0x8EA3A2EB 0x4EF8 # 0 +0x8EA3A2EC 0x4F06 # 0 +0x8EA3A2ED 0x4F03 # 0 +0x8EA3A2EE 0x4EFC # 0 +0x8EA3A2EF 0x4EEE # 0 +0x8EA3A2F0 0x4F16 # 0 +0x8EA3A2F2 0x4F28 # 0 +0x8EA3A2F3 0x4F1C # 0 +0x8EA3A2F4 0x4F07 # 0 +0x8EA3A2F5 0x4F1A # 0 +0x8EA3A2F6 0x4EFA # 0 +0x8EA3A2F7 0x4F17 # 0 +0x8EA3A2F8 0x514A # 0 +0x8EA3A2FA 0x5172 # 0 +0x8EA3A2FC 0x51B4 # 0 +0x8EA3A2FD 0x51B3 # 0 +0x8EA3A2FE 0x51B2 # 0 +0x8EA3A3A2 0x51E8 # 0 +0x8EA3A3A4 0x5214 # 0 +0x8EA3A3A5 0x520F # 0 +0x8EA3A3A6 0x5215 # 0 +0x8EA3A3A7 0x5218 # 0 +0x8EA3A3A8 0x52A8 # 0 +0x8EA3A3AA 0x534B # 0 +0x8EA3A3AB 0x534F # 0 +0x8EA3A3AD 0x5350 # 0 +0x8EA3A3AF 0x538B # 0 +0x8EA3A3B1 0x53BE # 0 +0x8EA3A3B3 0x53D2 # 0 +0x8EA3A3B4 0x5416 # 0 +0x8EA3A3B5 0x53FF # 0 +0x8EA3A3B7 0x5400 # 0 +0x8EA3A3B9 0x5405 # 0 +0x8EA3A3BA 0x5413 # 0 +0x8EA3A3BB 0x5415 # 0 +0x8EA3A3BE 0x56E3 # 0 +0x8EA3A3BF 0x5735 # 0 +0x8EA3A3C0 0x5736 # 0 +0x8EA3A3C1 0x5731 # 0 +0x8EA3A3C2 0x5732 # 0 +0x8EA3A3C3 0x58EE # 0 +0x8EA3A3C4 0x5905 # 0 +0x8EA3A3C5 0x4E54 # 0 +0x8EA3A3C7 0x5936 # 0 +0x8EA3A3CB 0x597A # 0 +0x8EA3A3CD 0x5986 # 0 +0x8EA3A3D0 0x5B86 # 0 +0x8EA3A3D1 0x5F53 # 0 +0x8EA3A3D2 0x5C18 # 0 +0x8EA3A3D4 0x5C3D # 0 +0x8EA3A3D5 0x5C78 # 0 +0x8EA3A3DA 0x5C80 # 0 +0x8EA3A3DC 0x5E08 # 0 +0x8EA3A3E1 0x5EF5 # 0 +0x8EA3A3E2 0x5F0E # 0 +0x8EA3A3E6 0x5FD3 # 0 +0x8EA3A3E7 0x5FDA # 0 +0x8EA3A3E9 0x5FDB # 0 +0x8EA3A3EB 0x620F # 0 +0x8EA3A3EC 0x625D # 0 +0x8EA3A3ED 0x625F # 0 +0x8EA3A3EE 0x6267 # 0 +0x8EA3A3EF 0x6257 # 0 +0x8EA3A3F0 0x9F50 # 0 +0x8EA3A3F2 0x65EB # 0 +0x8EA3A3F3 0x65EA # 0 +0x8EA3A3F5 0x6737 # 0 +0x8EA3A3F7 0x6732 # 0 +0x8EA3A3F8 0x6736 # 0 +0x8EA3A3F9 0x6B22 # 0 +0x8EA3A3FA 0x6BCE # 0 +0x8EA3A3FC 0x6C58 # 0 +0x8EA3A3FD 0x6C51 # 0 +0x8EA3A3FE 0x6C77 # 0 +0x8EA3A4A1 0x6C3C # 0 +0x8EA3A4A3 0x6C5A # 0 +0x8EA3A4A5 0x6C53 # 0 +0x8EA3A4A6 0x706F # 0 +0x8EA3A4A7 0x7072 # 0 +0x8EA3A4A8 0x706E # 0 +0x8EA3A4AB 0x7073 # 0 +0x8EA3A4AC 0x72B1 # 0 +0x8EA3A4AD 0x72B2 # 0 +0x8EA3A4AF 0x738F # 0 +0x8EA3A4B3 0x793C # 0 +0x8EA3A4B5 0x808D # 0 +0x8EA3A4B6 0x808E # 0 +0x8EA3A4B8 0x827B # 0 +0x8EA3A4BA 0x8D71 # 0 +0x8EA3A4BB 0x8FB9 # 0 +0x8EA3A4BC 0x9096 # 0 +0x8EA3A4BD 0x909A # 0 +0x8EA3A4BF 0x4E24 # 0 +0x8EA3A4C0 0x4E71 # 0 +0x8EA3A4C2 0x4E9C # 0 +0x8EA3A4C3 0x4F45 # 0 +0x8EA3A4C4 0x4F4A # 0 +0x8EA3A4C5 0x4F39 # 0 +0x8EA3A4C6 0x4F37 # 0 +0x8EA3A4C8 0x4F32 # 0 +0x8EA3A4C9 0x4F42 # 0 +0x8EA3A4CB 0x4F44 # 0 +0x8EA3A4CC 0x4F4B # 0 +0x8EA3A4CE 0x4F40 # 0 +0x8EA3A4CF 0x4F35 # 0 +0x8EA3A4D0 0x4F31 # 0 +0x8EA3A4D1 0x5151 # 0 +0x8EA3A4D3 0x5150 # 0 +0x8EA3A4D4 0x514E # 0 +0x8EA3A4D7 0x519D # 0 +0x8EA3A4D9 0x51B5 # 0 +0x8EA3A4DA 0x51B8 # 0 +0x8EA3A4DB 0x51EC # 0 +0x8EA3A4DC 0x5223 # 0 +0x8EA3A4DD 0x5227 # 0 +0x8EA3A4DE 0x5226 # 0 +0x8EA3A4DF 0x521F # 0 +0x8EA3A4E0 0x522B # 0 +0x8EA3A4E1 0x5220 # 0 +0x8EA3A4E2 0x52B4 # 0 +0x8EA3A4E3 0x52B3 # 0 +0x8EA3A4E5 0x5325 # 0 +0x8EA3A4E6 0x533B # 0 +0x8EA3A4E7 0x5374 # 0 +0x8EA3A4ED 0x544D # 0 +0x8EA3A4F0 0x543A # 0 +0x8EA3A4F3 0x5444 # 0 +0x8EA3A4F4 0x544C # 0 +0x8EA3A4F5 0x5423 # 0 +0x8EA3A4F6 0x541A # 0 +0x8EA3A4F7 0x5432 # 0 +0x8EA3A4F8 0x544B # 0 +0x8EA3A4F9 0x5421 # 0 +0x8EA3A4FB 0x5434 # 0 +0x8EA3A4FC 0x5449 # 0 +0x8EA3A4FD 0x5450 # 0 +0x8EA3A4FE 0x5422 # 0 +0x8EA3A5A1 0x543F # 0 +0x8EA3A5A2 0x5451 # 0 +0x8EA3A5A3 0x545A # 0 +0x8EA3A5A4 0x542F # 0 +0x8EA3A5A6 0x56E9 # 0 +0x8EA3A5A7 0x56F2 # 0 +0x8EA3A5A8 0x56F3 # 0 +0x8EA3A5A9 0x56EF # 0 +0x8EA3A5AA 0x56ED # 0 +0x8EA3A5AB 0x56EC # 0 +0x8EA3A5AC 0x56E6 # 0 +0x8EA3A5AD 0x5748 # 0 +0x8EA3A5AF 0x5744 # 0 +0x8EA3A5B0 0x573F # 0 +0x8EA3A5B1 0x573C # 0 +0x8EA3A5B2 0x5753 # 0 +0x8EA3A5B3 0x5756 # 0 +0x8EA3A5B5 0x575F # 0 +0x8EA3A5B6 0x5743 # 0 +0x8EA3A5B7 0x5758 # 0 +0x8EA3A5B8 0x5757 # 0 +0x8EA3A5BC 0x5746 # 0 +0x8EA3A5BE 0x573D # 0 +0x8EA3A5C0 0x5742 # 0 +0x8EA3A5C1 0x5754 # 0 +0x8EA3A5C2 0x5755 # 0 +0x8EA3A5C3 0x58F1 # 0 +0x8EA3A5C4 0x58F2 # 0 +0x8EA3A5C5 0x58F0 # 0 +0x8EA3A5C6 0x590B # 0 +0x8EA3A5C7 0x9EA6 # 0 +0x8EA3A5C8 0x56F1 # 0 +0x8EA3A5C9 0x593D # 0 +0x8EA3A5CB 0x5994 # 0 +0x8EA3A5CC 0x598C # 0 +0x8EA3A5CE 0x599C # 0 +0x8EA3A5D1 0x599F # 0 +0x8EA3A5D3 0x599B # 0 +0x8EA3A5D5 0x5989 # 0 +0x8EA3A5D6 0x599A # 0 +0x8EA3A5D8 0x6588 # 0 +0x8EA3A5DA 0x5B8D # 0 +0x8EA3A5DC 0x5BFE # 0 +0x8EA3A5DD 0x5BFF # 0 +0x8EA3A5DE 0x5BFD # 0 +0x8EA3A5DF 0x5C2B # 0 +0x8EA3A5E1 0x5C84 # 0 +0x8EA3A5E2 0x5C8E # 0 +0x8EA3A5E3 0x5C9C # 0 +0x8EA3A5E6 0x5C85 # 0 +0x8EA3A5E7 0x5DF5 # 0 +0x8EA3A5E8 0x5E09 # 0 +0x8EA3A5EB 0x5E0B # 0 +0x8EA3A5ED 0x5E92 # 0 +0x8EA3A5EE 0x5E90 # 0 +0x8EA3A5EF 0x5F03 # 0 +0x8EA3A5F1 0x5F1E # 0 +0x8EA3A5F2 0x5F63 # 0 +0x8EA3A5F4 0x5FE7 # 0 +0x8EA3A5F5 0x5FFE # 0 +0x8EA3A5F6 0x5FE6 # 0 +0x8EA3A5F7 0x5FDC # 0 +0x8EA3A5F8 0x5FCE # 0 +0x8EA3A5FA 0x5FFC # 0 +0x8EA3A5FB 0x5FDF # 0 +0x8EA3A5FC 0x5FEC # 0 +0x8EA3A5FD 0x5FF6 # 0 +0x8EA3A6A1 0x5FF2 # 0 +0x8EA3A6A2 0x5FF0 # 0 +0x8EA3A6A3 0x5FF9 # 0 +0x8EA3A6A5 0x6213 # 0 +0x8EA3A6A8 0x623B # 0 +0x8EA3A6A9 0x623C # 0 +0x8EA3A6AA 0x6282 # 0 +0x8EA3A6AE 0x6278 # 0 +0x8EA3A6AF 0x628B # 0 +0x8EA3A6B1 0x629E # 0 +0x8EA3A6B2 0x62A5 # 0 +0x8EA3A6B3 0x629B # 0 +0x8EA3A6B4 0x629C # 0 +0x8EA3A6B5 0x6299 # 0 +0x8EA3A6B6 0x628D # 0 +0x8EA3A6B7 0x6285 # 0 +0x8EA3A6B8 0x629D # 0 +0x8EA3A6B9 0x6275 # 0 +0x8EA3A6BD 0x65F6 # 0 +0x8EA3A6C1 0x66F5 # 0 +0x8EA3A6C2 0x675B # 0 +0x8EA3A6C4 0x6754 # 0 +0x8EA3A6C5 0x6752 # 0 +0x8EA3A6C7 0x6758 # 0 +0x8EA3A6C8 0x6744 # 0 +0x8EA3A6C9 0x674A # 0 +0x8EA3A6CA 0x6761 # 0 +0x8EA3A6CC 0x6C7F # 0 +0x8EA3A6CD 0x6C91 # 0 +0x8EA3A6CE 0x6C9E # 0 +0x8EA3A6D0 0x6C6E # 0 +0x8EA3A6D1 0x6C7C # 0 +0x8EA3A6D2 0x6C9F # 0 +0x8EA3A6D3 0x6C75 # 0 +0x8EA3A6D5 0x6C56 # 0 +0x8EA3A6D6 0x6CA2 # 0 +0x8EA3A6D7 0x6C79 # 0 +0x8EA3A6D9 0x6CA1 # 0 +0x8EA3A6DB 0x6CAA # 0 +0x8EA3A6DC 0x6CA0 # 0 +0x8EA3A6DE 0x7079 # 0 +0x8EA3A6DF 0x7077 # 0 +0x8EA3A6E0 0x707E # 0 +0x8EA3A6E2 0x7075 # 0 +0x8EA3A6E3 0x707B # 0 +0x8EA3A6E4 0x7264 # 0 +0x8EA3A6E6 0x72BB # 0 +0x8EA3A6E7 0x72BC # 0 +0x8EA3A6E8 0x72C7 # 0 +0x8EA3A6E9 0x72B9 # 0 +0x8EA3A6EA 0x72BE # 0 +0x8EA3A6EB 0x72B6 # 0 +0x8EA3A6EE 0x7398 # 0 +0x8EA3A6F3 0x7593 # 0 +0x8EA3A6F4 0x7680 # 0 +0x8EA3A6F6 0x7683 # 0 +0x8EA3A6F7 0x76C0 # 0 +0x8EA3A6F8 0x76C1 # 0 +0x8EA3A6FB 0x77F4 # 0 +0x8EA3A6FC 0x77F5 # 0 +0x8EA3A6FE 0x7ACC # 0 +0x8EA3A7A1 0x7ACD # 0 +0x8EA3A7A2 0x7CFA # 0 +0x8EA3A7A3 0x809F # 0 +0x8EA3A7A4 0x8091 # 0 +0x8EA3A7A5 0x8097 # 0 +0x8EA3A7A6 0x8094 # 0 +0x8EA3A7A8 0x8286 # 0 +0x8EA3A7A9 0x828C # 0 +0x8EA3A7AB 0x8295 # 0 +0x8EA3A7AD 0x866C # 0 +0x8EA3A7AF 0x8FB5 # 0 +0x8EA3A7B0 0x8FBE # 0 +0x8EA3A7B1 0x8FC7 # 0 +0x8EA3A7B3 0x8FC1 # 0 +0x8EA3A7B4 0x90A9 # 0 +0x8EA3A7B5 0x90A4 # 0 +0x8EA3A7B9 0x90A8 # 0 +0x8EA3A7BA 0x9627 # 0 +0x8EA3A7BB 0x9626 # 0 +0x8EA3A7BC 0x962B # 0 +0x8EA3A7BD 0x9633 # 0 +0x8EA3A7BE 0x9634 # 0 +0x8EA3A7BF 0x9629 # 0 +0x8EA3A7C0 0x4E3D # 0 +0x8EA3A7C2 0x4E9D # 0 +0x8EA3A7C3 0x4F93 # 0 +0x8EA3A7C4 0x4F8A # 0 +0x8EA3A7C7 0x4F6D # 0 +0x8EA3A7C8 0x4F8E # 0 +0x8EA3A7C9 0x4FA0 # 0 +0x8EA3A7CA 0x4FA2 # 0 +0x8EA3A7CB 0x4FA1 # 0 +0x8EA3A7CC 0x4F9F # 0 +0x8EA3A7CD 0x4FA3 # 0 +0x8EA3A7CF 0x4F72 # 0 +0x8EA3A7D1 0x4F8C # 0 +0x8EA3A7D2 0x5156 # 0 +0x8EA3A7D5 0x5190 # 0 +0x8EA3A7D9 0x51ED # 0 +0x8EA3A7DA 0x51FE # 0 +0x8EA3A7DB 0x522F # 0 +0x8EA3A7DD 0x523C # 0 +0x8EA3A7DE 0x5234 # 0 +0x8EA3A7DF 0x5239 # 0 +0x8EA3A7E0 0x52B9 # 0 +0x8EA3A7E1 0x52B5 # 0 +0x8EA3A7E2 0x52BF # 0 +0x8EA3A7E3 0x5355 # 0 +0x8EA3A7E5 0x5376 # 0 +0x8EA3A7E6 0x537A # 0 +0x8EA3A7E7 0x5393 # 0 +0x8EA3A7E9 0x53C1 # 0 +0x8EA3A7EA 0x53C2 # 0 +0x8EA3A7EB 0x53D5 # 0 +0x8EA3A7EC 0x5485 # 0 +0x8EA3A7EE 0x545F # 0 +0x8EA3A7EF 0x5493 # 0 +0x8EA3A7F0 0x5489 # 0 +0x8EA3A7F1 0x5479 # 0 +0x8EA3A7F2 0x9EFE # 0 +0x8EA3A7F3 0x548F # 0 +0x8EA3A7F4 0x5469 # 0 +0x8EA3A7F5 0x546D # 0 +0x8EA3A7F7 0x5494 # 0 +0x8EA3A7F8 0x546A # 0 +0x8EA3A7F9 0x548A # 0 +0x8EA3A7FB 0x56FD # 0 +0x8EA3A7FC 0x56FB # 0 +0x8EA3A7FD 0x56F8 # 0 +0x8EA3A8A1 0x56FC # 0 +0x8EA3A8A2 0x56F6 # 0 +0x8EA3A8A3 0x5765 # 0 +0x8EA3A8A4 0x5781 # 0 +0x8EA3A8A5 0x5763 # 0 +0x8EA3A8A6 0x5767 # 0 +0x8EA3A8A8 0x576E # 0 +0x8EA3A8A9 0x5778 # 0 +0x8EA3A8AA 0x577F # 0 +0x8EA3A8AD 0x58F3 # 0 +0x8EA3A8AE 0x594B # 0 +0x8EA3A8AF 0x594C # 0 +0x8EA3A8B3 0x59AD # 0 +0x8EA3A8B5 0x59C4 # 0 +0x8EA3A8B7 0x59C2 # 0 +0x8EA3A8B8 0x59B0 # 0 +0x8EA3A8BD 0x59BF # 0 +0x8EA3A8BF 0x59C9 # 0 +0x8EA3A8C0 0x59B8 # 0 +0x8EA3A8C1 0x59AC # 0 +0x8EA3A8C5 0x59B7 # 0 +0x8EA3A8C6 0x59D7 # 0 +0x8EA3A8C8 0x5B60 # 0 +0x8EA3A8CA 0x5B96 # 0 +0x8EA3A8CB 0x5B9E # 0 +0x8EA3A8CC 0x5B94 # 0 +0x8EA3A8CD 0x5B9F # 0 +0x8EA3A8CE 0x5B9D # 0 +0x8EA3A8D0 0x5C00 # 0 +0x8EA3A8D1 0x5C19 # 0 +0x8EA3A8D4 0x5C49 # 0 +0x8EA3A8D5 0x5C4A # 0 +0x8EA3A8D7 0x5CBB # 0 +0x8EA3A8D8 0x5CC1 # 0 +0x8EA3A8DC 0x5CB9 # 0 +0x8EA3A8DD 0x5C9E # 0 +0x8EA3A8DE 0x5CB4 # 0 +0x8EA3A8DF 0x5CBA # 0 +0x8EA3A8E0 0x5DF6 # 0 +0x8EA3A8E1 0x5E13 # 0 +0x8EA3A8E2 0x5E12 # 0 +0x8EA3A8E3 0x5E77 # 0 +0x8EA3A8E5 0x5E98 # 0 +0x8EA3A8E7 0x5E99 # 0 +0x8EA3A8E8 0x5E9D # 0 +0x8EA3A8E9 0x5EF8 # 0 +0x8EA3A8EB 0x5EF9 # 0 +0x8EA3A8ED 0x5F06 # 0 +0x8EA3A8EE 0x5F21 # 0 +0x8EA3A8F0 0x5F25 # 0 +0x8EA3A8F1 0x5F55 # 0 +0x8EA3A8F5 0x5F84 # 0 +0x8EA3A8F6 0x5F83 # 0 +0x8EA3A8F7 0x6030 # 0 +0x8EA3A8F8 0x6007 # 0 +0x8EA3A8FA 0x6036 # 0 +0x8EA3A8FE 0x5FE9 # 0 +0x8EA3A9A1 0x603D # 0 +0x8EA3A9A2 0x6008 # 0 +0x8EA3A9A5 0x62BA # 0 +0x8EA3A9A6 0x62B2 # 0 +0x8EA3A9A8 0x62B7 # 0 +0x8EA3A9A9 0x62E4 # 0 +0x8EA3A9AA 0x62A7 # 0 +0x8EA3A9AE 0x62D5 # 0 +0x8EA3A9AF 0x62E1 # 0 +0x8EA3A9B0 0x62DD # 0 +0x8EA3A9B1 0x62A6 # 0 +0x8EA3A9B2 0x62C1 # 0 +0x8EA3A9B3 0x62C5 # 0 +0x8EA3A9B4 0x62C0 # 0 +0x8EA3A9B5 0x62DF # 0 +0x8EA3A9B6 0x62E0 # 0 +0x8EA3A9B7 0x62DE # 0 +0x8EA3A9B9 0x6589 # 0 +0x8EA3A9BB 0x65A6 # 0 +0x8EA3A9BC 0x65BA # 0 +0x8EA3A9BE 0x65FF # 0 +0x8EA3A9C0 0x6617 # 0 +0x8EA3A9C1 0x6618 # 0 +0x8EA3A9C2 0x6601 # 0 +0x8EA3A9C3 0x65FE # 0 +0x8EA3A9C5 0x670C # 0 +0x8EA3A9C7 0x676B # 0 +0x8EA3A9C8 0x6796 # 0 +0x8EA3A9C9 0x6782 # 0 +0x8EA3A9CA 0x678A # 0 +0x8EA3A9CC 0x67A3 # 0 +0x8EA3A9CE 0x67A2 # 0 +0x8EA3A9CF 0x678F # 0 +0x8EA3A9D1 0x67F9 # 0 +0x8EA3A9D2 0x6780 # 0 +0x8EA3A9D3 0x6B26 # 0 +0x8EA3A9D4 0x6B27 # 0 +0x8EA3A9D5 0x6B68 # 0 +0x8EA3A9D6 0x6B69 # 0 +0x8EA3A9D8 0x6B81 # 0 +0x8EA3A9D9 0x6BB4 # 0 +0x8EA3A9DA 0x6BD1 # 0 +0x8EA3A9DD 0x6C1C # 0 +0x8EA3A9E3 0x6C97 # 0 +0x8EA3A9E4 0x6C6C # 0 +0x8EA3A9E5 0x6CDF # 0 +0x8EA3A9E7 0x6CEA # 0 +0x8EA3A9E9 0x6CE4 # 0 +0x8EA3A9EA 0x6CD8 # 0 +0x8EA3A9EB 0x6CB2 # 0 +0x8EA3A9EC 0x6CCE # 0 +0x8EA3A9ED 0x6CC8 # 0 +0x8EA3A9EF 0x708B # 0 +0x8EA3A9F0 0x7088 # 0 +0x8EA3A9F1 0x7090 # 0 +0x8EA3A9F2 0x708F # 0 +0x8EA3A9F4 0x7087 # 0 +0x8EA3A9F5 0x7089 # 0 +0x8EA3A9F6 0x708D # 0 +0x8EA3A9F7 0x7081 # 0 +0x8EA3A9F9 0x708C # 0 +0x8EA3A9FC 0x7240 # 0 +0x8EA3AAA1 0x7265 # 0 +0x8EA3AAA2 0x7266 # 0 +0x8EA3AAA3 0x7268 # 0 +0x8EA3AAA6 0x72CD # 0 +0x8EA3AAA7 0x72D3 # 0 +0x8EA3AAA8 0x72DB # 0 +0x8EA3AAAA 0x72CF # 0 +0x8EA3AAAB 0x73A7 # 0 +0x8EA3AAAC 0x73A3 # 0 +0x8EA3AAAD 0x739E # 0 +0x8EA3AAAF 0x73AF # 0 +0x8EA3AAB2 0x73AA # 0 +0x8EA3AAB3 0x739C # 0 +0x8EA3AAB5 0x7542 # 0 +0x8EA3AAB6 0x7544 # 0 +0x8EA3AAB7 0x753B # 0 +0x8EA3AAB8 0x7541 # 0 +0x8EA3AABA 0x759B # 0 +0x8EA3AABB 0x759E # 0 +0x8EA3AABD 0x79C4 # 0 +0x8EA3AABE 0x79C3 # 0 +0x8EA3AABF 0x79C6 # 0 +0x8EA3AAC2 0x79C7 # 0 +0x8EA3AAC4 0x79CA # 0 +0x8EA3AAC7 0x7ACF # 0 +0x8EA3AAC8 0x7C76 # 0 +0x8EA3AAC9 0x7C74 # 0 +0x8EA3AACA 0x7CFF # 0 +0x8EA3AACB 0x7CFC # 0 +0x8EA3AACE 0x7F59 # 0 +0x8EA3AACF 0x80A8 # 0 +0x8EA3AAD2 0x80B0 # 0 +0x8EA3AAD4 0x80B3 # 0 +0x8EA3AAD6 0x80A4 # 0 +0x8EA3AAD7 0x80B6 # 0 +0x8EA3AAD8 0x80A7 # 0 +0x8EA3AAD9 0x80AC # 0 +0x8EA3AADB 0x80A6 # 0 +0x8EA3AADC 0x5367 # 0 +0x8EA3AADD 0x820E # 0 +0x8EA3AADE 0x82C4 # 0 +0x8EA3AADF 0x833E # 0 +0x8EA3AAE0 0x829C # 0 +0x8EA3AAE6 0x82AA # 0 +0x8EA3AAE8 0x82C9 # 0 +0x8EA3AAEB 0x82A6 # 0 +0x8EA3AAEC 0x82B2 # 0 +0x8EA3AAF0 0x8FCC # 0 +0x8EA3AAF1 0x8FD9 # 0 +0x8EA3AAF2 0x8FCA # 0 +0x8EA3AAF3 0x8FD8 # 0 +0x8EA3AAF4 0x8FCF # 0 +0x8EA3AAF5 0x90B7 # 0 +0x8EA3AAF7 0x90AD # 0 +0x8EA3AAF8 0x90B9 # 0 +0x8EA3AAF9 0x9637 # 0 +0x8EA3AAFB 0x9641 # 0 +0x8EA3AAFC 0x963E # 0 +0x8EA3AAFD 0x96B6 # 0 +0x8EA3AAFE 0x9751 # 0 +0x8EA3ABA1 0x9763 # 0 +0x8EA3ABA2 0x4E57 # 0 +0x8EA3ABA3 0x4E79 # 0 +0x8EA3ABA4 0x4EB2 # 0 +0x8EA3ABA5 0x4EB0 # 0 +0x8EA3ABA6 0x4EAF # 0 +0x8EA3ABA7 0x4EB1 # 0 +0x8EA3ABA8 0x4FD2 # 0 +0x8EA3ABA9 0x4FD5 # 0 +0x8EA3ABAB 0x4FBE # 0 +0x8EA3ABAC 0x4FB8 # 0 +0x8EA3ABAD 0x4FB0 # 0 +0x8EA3ABAE 0x4FB1 # 0 +0x8EA3ABAF 0x4FC8 # 0 +0x8EA3ABB2 0x4FC6 # 0 +0x8EA3ABB3 0x4FCC # 0 +0x8EA3ABB4 0x4FE5 # 0 +0x8EA3ABB5 0x4FE3 # 0 +0x8EA3ABB6 0x4FB4 # 0 +0x8EA3ABB7 0x516A # 0 +0x8EA3ABB9 0x519F # 0 +0x8EA3ABBB 0x51C1 # 0 +0x8EA3ABBD 0x51C2 # 0 +0x8EA3ABBE 0x51C3 # 0 +0x8EA3ABBF 0x5245 # 0 +0x8EA3ABC0 0x5248 # 0 +0x8EA3ABC3 0x524F # 0 +0x8EA3ABC6 0x52C5 # 0 +0x8EA3ABC7 0x52CA # 0 +0x8EA3ABC8 0x52C4 # 0 +0x8EA3ABC9 0x5327 # 0 +0x8EA3ABCA 0x5358 # 0 +0x8EA3ABCB 0x537D # 0 +0x8EA3ABCD 0x53DD # 0 +0x8EA3ABCE 0x53DC # 0 +0x8EA3ABCF 0x53DA # 0 +0x8EA3ABD0 0x53D9 # 0 +0x8EA3ABD1 0x54B9 # 0 +0x8EA3ABD3 0x54D0 # 0 +0x8EA3ABD4 0x54B4 # 0 +0x8EA3ABD5 0x54CA # 0 +0x8EA3ABD7 0x54A3 # 0 +0x8EA3ABD8 0x54DA # 0 +0x8EA3ABD9 0x54A4 # 0 +0x8EA3ABDB 0x54B2 # 0 +0x8EA3ABDC 0x549E # 0 +0x8EA3ABDD 0x549F # 0 +0x8EA3ABDE 0x54B5 # 0 +0x8EA3ABE1 0x54CD # 0 +0x8EA3ABE3 0x54CC # 0 +0x8EA3ABE5 0x5700 # 0 +0x8EA3ABE6 0x57AC # 0 +0x8EA3ABE7 0x5791 # 0 +0x8EA3ABE8 0x578E # 0 +0x8EA3ABE9 0x578D # 0 +0x8EA3ABEA 0x5792 # 0 +0x8EA3ABEB 0x57A1 # 0 +0x8EA3ABEC 0x5790 # 0 +0x8EA3ABED 0x57A6 # 0 +0x8EA3ABEE 0x57A8 # 0 +0x8EA3ABF0 0x579C # 0 +0x8EA3ABF1 0x5796 # 0 +0x8EA3ABF2 0x57A7 # 0 +0x8EA3ABF7 0x58F5 # 0 +0x8EA3ABF9 0x5909 # 0 +0x8EA3ABFA 0x5908 # 0 +0x8EA3ABFC 0x5952 # 0 +0x8EA3ACA1 0x59DF # 0 +0x8EA3ACA3 0x59EB # 0 +0x8EA3ACA4 0x59EF # 0 +0x8EA3ACA5 0x59F0 # 0 +0x8EA3ACA6 0x59D5 # 0 +0x8EA3ACA7 0x5A0D # 0 +0x8EA3ACA8 0x5A04 # 0 +0x8EA3ACA9 0x59F9 # 0 +0x8EA3ACAA 0x5A02 # 0 +0x8EA3ACAB 0x59F8 # 0 +0x8EA3ACAC 0x59E2 # 0 +0x8EA3ACAD 0x59D9 # 0 +0x8EA3ACAE 0x59E7 # 0 +0x8EA3ACAF 0x5B6A # 0 +0x8EA3ACB2 0x5BAB # 0 +0x8EA3ACB4 0x5C1B # 0 +0x8EA3ACB5 0x5C2F # 0 +0x8EA3ACB7 0x663C # 0 +0x8EA3ACBB 0x5CD1 # 0 +0x8EA3ACBC 0x5CDC # 0 +0x8EA3ACBD 0x5CE6 # 0 +0x8EA3ACBE 0x5CE1 # 0 +0x8EA3ACBF 0x5CCD # 0 +0x8EA3ACC1 0x5CE2 # 0 +0x8EA3ACC2 0x5CDD # 0 +0x8EA3ACC3 0x5CE5 # 0 +0x8EA3ACC4 0x5DFB # 0 +0x8EA3ACC5 0x5DFA # 0 +0x8EA3ACC6 0x5E1E # 0 +0x8EA3ACC8 0x5EA1 # 0 +0x8EA3ACCB 0x5EFC # 0 +0x8EA3ACCC 0x5EFB # 0 +0x8EA3ACCD 0x5F2F # 0 +0x8EA3ACD0 0x5F66 # 0 +0x8EA3ACD4 0x605C # 0 +0x8EA3ACD6 0x604E # 0 +0x8EA3ACD7 0x6051 # 0 +0x8EA3ACDA 0x6023 # 0 +0x8EA3ACDB 0x6031 # 0 +0x8EA3ACDC 0x607C # 0 +0x8EA3ACDD 0x6052 # 0 +0x8EA3ACDF 0x6060 # 0 +0x8EA3ACE0 0x604A # 0 +0x8EA3ACE1 0x6061 # 0 +0x8EA3ACE3 0x6218 # 0 +0x8EA3ACEB 0x631F # 0 +0x8EA3ACEC 0x6317 # 0 +0x8EA3ACED 0x62EA # 0 +0x8EA3ACEE 0x6321 # 0 +0x8EA3ACEF 0x6304 # 0 +0x8EA3ACF0 0x6305 # 0 +0x8EA3ACF2 0x6531 # 0 +0x8EA3ACF3 0x6544 # 0 +0x8EA3ACF4 0x6540 # 0 +0x8EA3ACF6 0x6542 # 0 +0x8EA3ACF7 0x65BE # 0 +0x8EA3ACF9 0x6629 # 0 +0x8EA3ACFA 0x661B # 0 +0x8EA3ACFC 0x6623 # 0 +0x8EA3ACFD 0x662C # 0 +0x8EA3ACFE 0x661A # 0 +0x8EA3ADA1 0x6630 # 0 +0x8EA3ADA2 0x663B # 0 +0x8EA3ADA3 0x661E # 0 +0x8EA3ADA4 0x6637 # 0 +0x8EA3ADA5 0x6638 # 0 +0x8EA3ADA7 0x670E # 0 +0x8EA3ADAA 0x67E8 # 0 +0x8EA3ADAB 0x67D6 # 0 +0x8EA3ADAD 0x67C7 # 0 +0x8EA3ADAE 0x67BC # 0 +0x8EA3ADAF 0x6852 # 0 +0x8EA3ADB0 0x67BF # 0 +0x8EA3ADB1 0x67D5 # 0 +0x8EA3ADB2 0x67FE # 0 +0x8EA3ADB3 0x8363 # 0 +0x8EA3ADB4 0x67FB # 0 +0x8EA3ADB6 0x67B1 # 0 +0x8EA3ADB7 0x6801 # 0 +0x8EA3ADB8 0x6805 # 0 +0x8EA3ADB9 0x6800 # 0 +0x8EA3ADBA 0x67D7 # 0 +0x8EA3ADBC 0x6B2A # 0 +0x8EA3ADBD 0x6B6B # 0 +0x8EA3ADC2 0x6BE1 # 0 +0x8EA3ADC5 0x6D23 # 0 +0x8EA3ADC6 0x6CFF # 0 +0x8EA3ADC7 0x6D14 # 0 +0x8EA3ADC8 0x6D05 # 0 +0x8EA3ADC9 0x6D13 # 0 +0x8EA3ADCA 0x6D06 # 0 +0x8EA3ADCB 0x6D21 # 0 +0x8EA3ADCD 0x6D15 # 0 +0x8EA3ADCE 0x6CAF # 0 +0x8EA3ADCF 0x6CF4 # 0 +0x8EA3ADD0 0x6D02 # 0 +0x8EA3ADD1 0x6D45 # 0 +0x8EA3ADD3 0x6D26 # 0 +0x8EA3ADD5 0x6D44 # 0 +0x8EA3ADD7 0x6D24 # 0 +0x8EA3ADD8 0x70A5 # 0 +0x8EA3ADDA 0x70A3 # 0 +0x8EA3ADDC 0x70A2 # 0 +0x8EA3ADDD 0x70BB # 0 +0x8EA3ADDE 0x70A0 # 0 +0x8EA3ADDF 0x70AA # 0 +0x8EA3ADE2 0x70A8 # 0 +0x8EA3ADE3 0x70B6 # 0 +0x8EA3ADE4 0x70B2 # 0 +0x8EA3ADE5 0x70A7 # 0 +0x8EA3ADE8 0x70B9 # 0 +0x8EA3ADE9 0x722E # 0 +0x8EA3ADEB 0x723C # 0 +0x8EA3ADED 0x726D # 0 +0x8EA3ADF0 0x72E7 # 0 +0x8EA3ADF1 0x72ED # 0 +0x8EA3ADF3 0x72EC # 0 +0x8EA3ADF4 0x72E5 # 0 +0x8EA3ADF5 0x72E2 # 0 +0x8EA3ADF7 0x73C4 # 0 +0x8EA3ADF8 0x73BD # 0 +0x8EA3ADF9 0x73CF # 0 +0x8EA3ADFA 0x73C9 # 0 +0x8EA3ADFB 0x73C1 # 0 +0x8EA3ADFC 0x73D0 # 0 +0x8EA3ADFE 0x73CE # 0 +0x8EA3AEA1 0x74ED # 0 +0x8EA3AEA2 0x74EB # 0 +0x8EA3AEA4 0x74EF # 0 +0x8EA3AEA5 0x7549 # 0 +0x8EA3AEA6 0x7550 # 0 +0x8EA3AEA7 0x7546 # 0 +0x8EA3AEA8 0x754A # 0 +0x8EA3AEAA 0x754D # 0 +0x8EA3AEAB 0x75A6 # 0 +0x8EA3AEAF 0x75A8 # 0 +0x8EA3AEB2 0x76C7 # 0 +0x8EA3AEB3 0x76FF # 0 +0x8EA3AEB5 0x76FD # 0 +0x8EA3AEB6 0x77E6 # 0 +0x8EA3AEB7 0x780A # 0 +0x8EA3AEB9 0x7804 # 0 +0x8EA3AEBA 0x780B # 0 +0x8EA3AEBB 0x7807 # 0 +0x8EA3AEBD 0x7815 # 0 +0x8EA3AEBE 0x7808 # 0 +0x8EA3AEC0 0x79D3 # 0 +0x8EA3AEC1 0x79D4 # 0 +0x8EA3AEC2 0x79D0 # 0 +0x8EA3AEC3 0x79D7 # 0 +0x8EA3AEC4 0x7A7C # 0 +0x8EA3AEC7 0x7A7D # 0 +0x8EA3AEC8 0x7A83 # 0 +0x8EA3AEC9 0x7A82 # 0 +0x8EA3AECB 0x7AD4 # 0 +0x8EA3AECC 0x7AD5 # 0 +0x8EA3AECD 0x7AD3 # 0 +0x8EA3AECE 0x7AD0 # 0 +0x8EA3AECF 0x7AD2 # 0 +0x8EA3AED0 0x7AFE # 0 +0x8EA3AED1 0x7AFC # 0 +0x8EA3AED2 0x7C77 # 0 +0x8EA3AED3 0x7C7C # 0 +0x8EA3AED4 0x7C7B # 0 +0x8EA3AEDD 0x7F8F # 0 +0x8EA3AEDE 0x80D3 # 0 +0x8EA3AEE0 0x80CB # 0 +0x8EA3AEE1 0x80D2 # 0 +0x8EA3AEE3 0x8109 # 0 +0x8EA3AEE4 0x80E2 # 0 +0x8EA3AEE5 0x80DF # 0 +0x8EA3AEE6 0x80C6 # 0 +0x8EA3AEE8 0x8224 # 0 +0x8EA3AEE9 0x82F7 # 0 +0x8EA3AEEA 0x82D8 # 0 +0x8EA3AEEB 0x82DD # 0 +0x8EA3AEEE 0x82F8 # 0 +0x8EA3AEEF 0x82FC # 0 +0x8EA3AEF2 0x82E9 # 0 +0x8EA3AEF4 0x82EE # 0 +0x8EA3AEF6 0x82D0 # 0 +0x8EA3AEF7 0x830E # 0 +0x8EA3AEF8 0x82E2 # 0 +0x8EA3AEF9 0x830B # 0 +0x8EA3AEFA 0x82FD # 0 +0x8EA3AEFB 0x5179 # 0 +0x8EA3AEFC 0x8676 # 0 +0x8EA3AEFE 0x8678 # 0 +0x8EA3AFA3 0x8675 # 0 +0x8EA3AFA4 0x867D # 0 +0x8EA3AFA6 0x8842 # 0 +0x8EA3AFA7 0x8866 # 0 +0x8EA3AFA9 0x898C # 0 +0x8EA3AFAA 0x8A05 # 0 +0x8EA3AFAC 0x8A06 # 0 +0x8EA3AFAE 0x8C9F # 0 +0x8EA3AFB0 0x8FF1 # 0 +0x8EA3AFB1 0x8FE7 # 0 +0x8EA3AFB2 0x8FE9 # 0 +0x8EA3AFB3 0x8FEF # 0 +0x8EA3AFB4 0x90C2 # 0 +0x8EA3AFB5 0x90BC # 0 +0x8EA3AFB7 0x90C6 # 0 +0x8EA3AFB8 0x90C0 # 0 +0x8EA3AFBB 0x90CD # 0 +0x8EA3AFBC 0x90C9 # 0 +0x8EA3AFBE 0x90C4 # 0 +0x8EA3AFC0 0x9581 # 0 +0x8EA3AFC2 0x9CEC # 0 +0x8EA3AFC3 0x5032 # 0 +0x8EA3AFC4 0x4FF9 # 0 +0x8EA3AFC5 0x501D # 0 +0x8EA3AFC6 0x4FFF # 0 +0x8EA3AFC7 0x5004 # 0 +0x8EA3AFC8 0x4FF0 # 0 +0x8EA3AFC9 0x5003 # 0 +0x8EA3AFCB 0x5002 # 0 +0x8EA3AFCC 0x4FFC # 0 +0x8EA3AFCD 0x4FF2 # 0 +0x8EA3AFCE 0x5024 # 0 +0x8EA3AFCF 0x5008 # 0 +0x8EA3AFD0 0x5036 # 0 +0x8EA3AFD1 0x502E # 0 +0x8EA3AFD3 0x5010 # 0 +0x8EA3AFD4 0x5038 # 0 +0x8EA3AFD5 0x5039 # 0 +0x8EA3AFD6 0x4FFD # 0 +0x8EA3AFD7 0x5056 # 0 +0x8EA3AFD8 0x4FFB # 0 +0x8EA3AFD9 0x51A3 # 0 +0x8EA3AFDA 0x51A6 # 0 +0x8EA3AFDB 0x51A1 # 0 +0x8EA3AFDE 0x51C7 # 0 +0x8EA3AFDF 0x51C9 # 0 +0x8EA3AFE0 0x5260 # 0 +0x8EA3AFE1 0x5264 # 0 +0x8EA3AFE2 0x5259 # 0 +0x8EA3AFE3 0x5265 # 0 +0x8EA3AFE4 0x5267 # 0 +0x8EA3AFE5 0x5257 # 0 +0x8EA3AFE6 0x5263 # 0 +0x8EA3AFE8 0x5253 # 0 +0x8EA3AFEA 0x52CF # 0 +0x8EA3AFEC 0x52CE # 0 +0x8EA3AFED 0x52D0 # 0 +0x8EA3AFEE 0x52D1 # 0 +0x8EA3AFEF 0x52CC # 0 +0x8EA3AFF3 0x550D # 0 +0x8EA3AFF4 0x54F4 # 0 +0x8EA3AFF6 0x5513 # 0 +0x8EA3AFF7 0x54EF # 0 +0x8EA3AFF8 0x54F5 # 0 +0x8EA3AFF9 0x54F9 # 0 +0x8EA3AFFA 0x5502 # 0 +0x8EA3AFFB 0x5500 # 0 +0x8EA3AFFE 0x5518 # 0 +0x8EA3B0A1 0x54F0 # 0 +0x8EA3B0A2 0x54F6 # 0 +0x8EA3B0A5 0x5519 # 0 +0x8EA3B0A7 0x5705 # 0 +0x8EA3B0A8 0x57C9 # 0 +0x8EA3B0AA 0x57B7 # 0 +0x8EA3B0AB 0x57CD # 0 +0x8EA3B0AF 0x57BE # 0 +0x8EA3B0B0 0x57BB # 0 +0x8EA3B0B2 0x57DB # 0 +0x8EA3B0B3 0x57C8 # 0 +0x8EA3B0B4 0x57C4 # 0 +0x8EA3B0B5 0x57C5 # 0 +0x8EA3B0B6 0x57D1 # 0 +0x8EA3B0B7 0x57CA # 0 +0x8EA3B0B8 0x57C0 # 0 +0x8EA3B0BB 0x5A21 # 0 +0x8EA3B0BC 0x5A2A # 0 +0x8EA3B0BE 0x5A1D # 0 +0x8EA3B0C0 0x5A0B # 0 +0x8EA3B0C5 0x5A22 # 0 +0x8EA3B0C8 0x5A24 # 0 +0x8EA3B0CA 0x5A14 # 0 +0x8EA3B0CB 0x5A31 # 0 +0x8EA3B0CD 0x5A2F # 0 +0x8EA3B0CE 0x5A1A # 0 +0x8EA3B0CF 0x5A12 # 0 +0x8EA3B0D2 0x5A26 # 0 +0x8EA3B0D5 0x5BBC # 0 +0x8EA3B0D6 0x5BBB # 0 +0x8EA3B0D7 0x5BB7 # 0 +0x8EA3B0D8 0x5C05 # 0 +0x8EA3B0D9 0x5C06 # 0 +0x8EA3B0DA 0x5C52 # 0 +0x8EA3B0DB 0x5C53 # 0 +0x8EA3B0DE 0x5CFA # 0 +0x8EA3B0DF 0x5CEB # 0 +0x8EA3B0E1 0x5CF3 # 0 +0x8EA3B0E2 0x5CF5 # 0 +0x8EA3B0E3 0x5CE9 # 0 +0x8EA3B0E4 0x5CEF # 0 +0x8EA3B0E6 0x5E2A # 0 +0x8EA3B0E7 0x5E30 # 0 +0x8EA3B0E8 0x5E2E # 0 +0x8EA3B0E9 0x5E2C # 0 +0x8EA3B0EA 0x5E2F # 0 +0x8EA3B0EB 0x5EAF # 0 +0x8EA3B0EC 0x5EA9 # 0 +0x8EA3B0EE 0x5EFD # 0 +0x8EA3B0EF 0x5F32 # 0 +0x8EA3B0F0 0x5F8E # 0 +0x8EA3B0F1 0x5F93 # 0 +0x8EA3B0F2 0x5F8F # 0 +0x8EA3B0F3 0x604F # 0 +0x8EA3B0F4 0x6099 # 0 +0x8EA3B0F6 0x607E # 0 +0x8EA3B0F8 0x6074 # 0 +0x8EA3B0F9 0x604B # 0 +0x8EA3B0FA 0x6073 # 0 +0x8EA3B0FB 0x6075 # 0 +0x8EA3B0FE 0x6056 # 0 +0x8EA3B1A1 0x60A9 # 0 +0x8EA3B1A2 0x608B # 0 +0x8EA3B1A3 0x60A6 # 0 +0x8EA3B1A5 0x6093 # 0 +0x8EA3B1A6 0x60AE # 0 +0x8EA3B1A7 0x609E # 0 +0x8EA3B1A8 0x60A7 # 0 +0x8EA3B1A9 0x6245 # 0 +0x8EA3B1AC 0x632E # 0 +0x8EA3B1AE 0x6352 # 0 +0x8EA3B1AF 0x6330 # 0 +0x8EA3B1B0 0x635B # 0 +0x8EA3B1B2 0x6319 # 0 +0x8EA3B1B3 0x631B # 0 +0x8EA3B1B5 0x6331 # 0 +0x8EA3B1B6 0x635D # 0 +0x8EA3B1B7 0x6337 # 0 +0x8EA3B1B8 0x6335 # 0 +0x8EA3B1B9 0x6353 # 0 +0x8EA3B1BB 0x635C # 0 +0x8EA3B1BC 0x633F # 0 +0x8EA3B1BD 0x654B # 0 +0x8EA3B1C0 0x658B # 0 +0x8EA3B1C2 0x659A # 0 +0x8EA3B1C3 0x6650 # 0 +0x8EA3B1C4 0x6646 # 0 +0x8EA3B1C5 0x664E # 0 +0x8EA3B1C6 0x6640 # 0 +0x8EA3B1C8 0x664B # 0 +0x8EA3B1C9 0x6648 # 0 +0x8EA3B1CB 0x6660 # 0 +0x8EA3B1CC 0x6644 # 0 +0x8EA3B1CD 0x664D # 0 +0x8EA3B1CF 0x6837 # 0 +0x8EA3B1D0 0x6824 # 0 +0x8EA3B1D3 0x681B # 0 +0x8EA3B1D4 0x6836 # 0 +0x8EA3B1D6 0x682C # 0 +0x8EA3B1D7 0x6819 # 0 +0x8EA3B1D8 0x6856 # 0 +0x8EA3B1D9 0x6847 # 0 +0x8EA3B1DA 0x683E # 0 +0x8EA3B1DB 0x681E # 0 +0x8EA3B1DD 0x6815 # 0 +0x8EA3B1DE 0x6822 # 0 +0x8EA3B1DF 0x6827 # 0 +0x8EA3B1E0 0x6859 # 0 +0x8EA3B1E1 0x6858 # 0 +0x8EA3B1E2 0x6855 # 0 +0x8EA3B1E3 0x6830 # 0 +0x8EA3B1E4 0x6823 # 0 +0x8EA3B1E5 0x6B2E # 0 +0x8EA3B1E6 0x6B2B # 0 +0x8EA3B1E7 0x6B30 # 0 +0x8EA3B1E8 0x6B6C # 0 +0x8EA3B1EA 0x6B8B # 0 +0x8EA3B1EC 0x6BE9 # 0 +0x8EA3B1ED 0x6BEA # 0 +0x8EA3B1EE 0x6BE5 # 0 +0x8EA3B1EF 0x6D6B # 0 +0x8EA3B1F2 0x6D73 # 0 +0x8EA3B1F3 0x6D57 # 0 +0x8EA3B1F6 0x6D5D # 0 +0x8EA3B1F7 0x6D56 # 0 +0x8EA3B1F8 0x6D8F # 0 +0x8EA3B1F9 0x6D5B # 0 +0x8EA3B1FA 0x6D1C # 0 +0x8EA3B1FB 0x6D9A # 0 +0x8EA3B1FC 0x6D9B # 0 +0x8EA3B1FD 0x6D99 # 0 +0x8EA3B2A1 0x6D81 # 0 +0x8EA3B2A2 0x6D71 # 0 +0x8EA3B2A5 0x6D72 # 0 +0x8EA3B2A6 0x6D5C # 0 +0x8EA3B2A7 0x6D96 # 0 +0x8EA3B2A8 0x70C4 # 0 +0x8EA3B2A9 0x70DB # 0 +0x8EA3B2AA 0x70CC # 0 +0x8EA3B2AB 0x70D0 # 0 +0x8EA3B2AC 0x70E3 # 0 +0x8EA3B2AD 0x70DF # 0 +0x8EA3B2AF 0x70D6 # 0 +0x8EA3B2B0 0x70EE # 0 +0x8EA3B2B1 0x70D5 # 0 +0x8EA3B2B6 0x727A # 0 +0x8EA3B2B8 0x72F5 # 0 +0x8EA3B2B9 0x7302 # 0 +0x8EA3B2BC 0x73E2 # 0 +0x8EA3B2BD 0x73EC # 0 +0x8EA3B2BE 0x73D5 # 0 +0x8EA3B2BF 0x73F9 # 0 +0x8EA3B2C0 0x73DF # 0 +0x8EA3B2C1 0x73E6 # 0 +0x8EA3B2C6 0x73E4 # 0 +0x8EA3B2C7 0x73E1 # 0 +0x8EA3B2C8 0x74F3 # 0 +0x8EA3B2CD 0x7556 # 0 +0x8EA3B2CE 0x7555 # 0 +0x8EA3B2CF 0x7558 # 0 +0x8EA3B2D0 0x7557 # 0 +0x8EA3B2D1 0x755E # 0 +0x8EA3B2D2 0x75C3 # 0 +0x8EA3B2D5 0x75B4 # 0 +0x8EA3B2D7 0x75B1 # 0 +0x8EA3B2DA 0x76CB # 0 +0x8EA3B2DB 0x76CC # 0 +0x8EA3B2DC 0x772A # 0 +0x8EA3B2DE 0x7716 # 0 +0x8EA3B2DF 0x770F # 0 +0x8EA3B2E2 0x773F # 0 +0x8EA3B2E3 0x772B # 0 +0x8EA3B2E4 0x770E # 0 +0x8EA3B2E5 0x7724 # 0 +0x8EA3B2E7 0x7721 # 0 +0x8EA3B2E8 0x7718 # 0 +0x8EA3B2E9 0x77DD # 0 +0x8EA3B2EC 0x7824 # 0 +0x8EA3B2ED 0x7836 # 0 +0x8EA3B2EF 0x7958 # 0 +0x8EA3B2F0 0x7959 # 0 +0x8EA3B2F2 0x7962 # 0 +0x8EA3B2F3 0x79DA # 0 +0x8EA3B2F4 0x79D9 # 0 +0x8EA3B2F6 0x79E1 # 0 +0x8EA3B2F7 0x79E5 # 0 +0x8EA3B2F8 0x79E8 # 0 +0x8EA3B2F9 0x79DB # 0 +0x8EA3B2FB 0x79E2 # 0 +0x8EA3B2FC 0x79F0 # 0 +0x8EA3B3A3 0x7ADA # 0 +0x8EA3B3A4 0x7ADD # 0 +0x8EA3B3A6 0x7ADB # 0 +0x8EA3B3A7 0x7ADC # 0 +0x8EA3B3AA 0x7B0D # 0 +0x8EA3B3AB 0x7B0B # 0 +0x8EA3B3AC 0x7B14 # 0 +0x8EA3B3AD 0x7C8E # 0 +0x8EA3B3AE 0x7C86 # 0 +0x8EA3B3B0 0x7C87 # 0 +0x8EA3B3B1 0x7C83 # 0 +0x8EA3B3B2 0x7C8B # 0 +0x8EA3B3B7 0x7D24 # 0 +0x8EA3B3BB 0x7D25 # 0 +0x8EA3B3BC 0x7F62 # 0 +0x8EA3B3BD 0x7F93 # 0 +0x8EA3B3BE 0x7F99 # 0 +0x8EA3B3BF 0x7F97 # 0 +0x8EA3B3C2 0x7FC4 # 0 +0x8EA3B3C3 0x7FC6 # 0 +0x8EA3B3C4 0x800A # 0 +0x8EA3B3C7 0x8040 # 0 +0x8EA3B3C8 0x803C # 0 +0x8EA3B3C9 0x803B # 0 +0x8EA3B3CA 0x80F6 # 0 +0x8EA3B3CB 0x80FF # 0 +0x8EA3B3CC 0x80EE # 0 +0x8EA3B3CD 0x8104 # 0 +0x8EA3B3CE 0x8103 # 0 +0x8EA3B3CF 0x8107 # 0 +0x8EA3B3D2 0x80F7 # 0 +0x8EA3B3D5 0x822D # 0 +0x8EA3B3D7 0x8227 # 0 +0x8EA3B3D8 0x8229 # 0 +0x8EA3B3D9 0x831F # 0 +0x8EA3B3DA 0x8357 # 0 +0x8EA3B3DF 0x8321 # 0 +0x8EA3B3E2 0x8318 # 0 +0x8EA3B3E3 0x8358 # 0 +0x8EA3B3E9 0x8684 # 0 +0x8EA3B3EA 0x869F # 0 +0x8EA3B3EB 0x869B # 0 +0x8EA3B3EC 0x8689 # 0 +0x8EA3B3ED 0x86A6 # 0 +0x8EA3B3EE 0x8692 # 0 +0x8EA3B3EF 0x868F # 0 +0x8EA3B3F0 0x86A0 # 0 +0x8EA3B3F1 0x884F # 0 +0x8EA3B3F2 0x8878 # 0 +0x8EA3B3F3 0x887A # 0 +0x8EA3B3F4 0x886E # 0 +0x8EA3B3F5 0x887B # 0 +0x8EA3B3F6 0x8884 # 0 +0x8EA3B3F7 0x8873 # 0 +0x8EA3B3FA 0x8A0D # 0 +0x8EA3B3FB 0x8A0B # 0 +0x8EA3B3FC 0x8A19 # 0 +0x8EA3B4A5 0x8FF9 # 0 +0x8EA3B4A6 0x9009 # 0 +0x8EA3B4A7 0x9008 # 0 +0x8EA3B4A9 0x90DE # 0 +0x8EA3B4AA 0x9151 # 0 +0x8EA3B4AD 0x91DB # 0 +0x8EA3B4AE 0x91DF # 0 +0x8EA3B4AF 0x91DE # 0 +0x8EA3B4B0 0x91D6 # 0 +0x8EA3B4B1 0x91E0 # 0 +0x8EA3B4B2 0x9585 # 0 +0x8EA3B4B3 0x9660 # 0 +0x8EA3B4B4 0x9659 # 0 +0x8EA3B4B6 0x9656 # 0 +0x8EA3B4B9 0x96BD # 0 +0x8EA3B4BC 0x5042 # 0 +0x8EA3B4BD 0x5059 # 0 +0x8EA3B4BF 0x5044 # 0 +0x8EA3B4C0 0x5066 # 0 +0x8EA3B4C1 0x5052 # 0 +0x8EA3B4C2 0x5054 # 0 +0x8EA3B4C3 0x5071 # 0 +0x8EA3B4C4 0x5050 # 0 +0x8EA3B4C5 0x507B # 0 +0x8EA3B4C6 0x507C # 0 +0x8EA3B4C7 0x5058 # 0 +0x8EA3B4CA 0x5079 # 0 +0x8EA3B4CB 0x506C # 0 +0x8EA3B4CC 0x5078 # 0 +0x8EA3B4CD 0x51A8 # 0 +0x8EA3B4CE 0x51D1 # 0 +0x8EA3B4CF 0x51CF # 0 +0x8EA3B4D0 0x5268 # 0 +0x8EA3B4D1 0x5276 # 0 +0x8EA3B4D2 0x52D4 # 0 +0x8EA3B4D4 0x53A0 # 0 +0x8EA3B4D5 0x53C4 # 0 +0x8EA3B4D7 0x5558 # 0 +0x8EA3B4D8 0x554C # 0 +0x8EA3B4D9 0x5568 # 0 +0x8EA3B4DB 0x5549 # 0 +0x8EA3B4DE 0x555D # 0 +0x8EA3B4DF 0x5529 # 0 +0x8EA3B4E1 0x5554 # 0 +0x8EA3B4E2 0x5553 # 0 +0x8EA3B4E4 0x555A # 0 +0x8EA3B4E6 0x553A # 0 +0x8EA3B4E7 0x553F # 0 +0x8EA3B4E8 0x552B # 0 +0x8EA3B4E9 0x57EA # 0 +0x8EA3B4EB 0x57EF # 0 +0x8EA3B4EE 0x57DD # 0 +0x8EA3B4EF 0x57FE # 0 +0x8EA3B4F1 0x57DE # 0 +0x8EA3B4F2 0x57E6 # 0 +0x8EA3B4F4 0x57E8 # 0 +0x8EA3B4F5 0x57FF # 0 +0x8EA3B4F6 0x5803 # 0 +0x8EA3B4F7 0x58F7 # 0 +0x8EA3B4F8 0x68A6 # 0 +0x8EA3B4F9 0x591F # 0 +0x8EA3B4FB 0x595B # 0 +0x8EA3B4FC 0x595D # 0 +0x8EA3B4FD 0x595E # 0 +0x8EA3B5A2 0x5A2B # 0 +0x8EA3B5A4 0x5A3B # 0 +0x8EA3B5A7 0x5A61 # 0 +0x8EA3B5A8 0x5A3A # 0 +0x8EA3B5A9 0x5A6E # 0 +0x8EA3B5AA 0x5A4B # 0 +0x8EA3B5AB 0x5A6B # 0 +0x8EA3B5AE 0x5A45 # 0 +0x8EA3B5AF 0x5A4E # 0 +0x8EA3B5B0 0x5A68 # 0 +0x8EA3B5B1 0x5A3D # 0 +0x8EA3B5B2 0x5A71 # 0 +0x8EA3B5B3 0x5A3F # 0 +0x8EA3B5B4 0x5A6F # 0 +0x8EA3B5B5 0x5A75 # 0 +0x8EA3B5B7 0x5A73 # 0 +0x8EA3B5B8 0x5A2C # 0 +0x8EA3B5B9 0x5A59 # 0 +0x8EA3B5BA 0x5A54 # 0 +0x8EA3B5BB 0x5A4F # 0 +0x8EA3B5BC 0x5A63 # 0 +0x8EA3B5BF 0x5BC8 # 0 +0x8EA3B5C1 0x5BC3 # 0 +0x8EA3B5C3 0x5C5B # 0 +0x8EA3B5C4 0x5C61 # 0 +0x8EA3B5C6 0x5D21 # 0 +0x8EA3B5C7 0x5D0A # 0 +0x8EA3B5C8 0x5D09 # 0 +0x8EA3B5CA 0x5D2C # 0 +0x8EA3B5CB 0x5D08 # 0 +0x8EA3B5CE 0x5D2A # 0 +0x8EA3B5CF 0x5D15 # 0 +0x8EA3B5D1 0x5D10 # 0 +0x8EA3B5D2 0x5D13 # 0 +0x8EA3B5D4 0x5D2F # 0 +0x8EA3B5D5 0x5D18 # 0 +0x8EA3B5D7 0x5DE3 # 0 +0x8EA3B5D8 0x5E39 # 0 +0x8EA3B5D9 0x5E35 # 0 +0x8EA3B5DA 0x5E3A # 0 +0x8EA3B5DB 0x5E32 # 0 +0x8EA3B5E0 0x5EBB # 0 +0x8EA3B5E1 0x5EBA # 0 +0x8EA3B5E2 0x5F34 # 0 +0x8EA3B5E3 0x5F39 # 0 +0x8EA3B5E8 0x6098 # 0 +0x8EA3B5EA 0x60D0 # 0 +0x8EA3B5EE 0x60D7 # 0 +0x8EA3B5EF 0x60AA # 0 +0x8EA3B5F1 0x60A1 # 0 +0x8EA3B5F2 0x60A4 # 0 +0x8EA3B5F4 0x60EE # 0 +0x8EA3B5F6 0x60E7 # 0 +0x8EA3B5F9 0x60DE # 0 +0x8EA3B5FC 0x637E # 0 +0x8EA3B5FD 0x638B # 0 +0x8EA3B6A2 0x6379 # 0 +0x8EA3B6A3 0x6386 # 0 +0x8EA3B6A4 0x6393 # 0 +0x8EA3B6A6 0x6373 # 0 +0x8EA3B6A7 0x636A # 0 +0x8EA3B6A9 0x636C # 0 +0x8EA3B6AB 0x637F # 0 +0x8EA3B6AD 0x63B2 # 0 +0x8EA3B6AE 0x63BA # 0 +0x8EA3B6B1 0x6366 # 0 +0x8EA3B6B2 0x6374 # 0 +0x8EA3B6B4 0x655A # 0 +0x8EA3B6B6 0x654E # 0 +0x8EA3B6B7 0x654D # 0 +0x8EA3B6B8 0x658D # 0 +0x8EA3B6B9 0x658E # 0 +0x8EA3B6BA 0x65AD # 0 +0x8EA3B6BC 0x65C7 # 0 +0x8EA3B6BD 0x65CA # 0 +0x8EA3B6BF 0x65C9 # 0 +0x8EA3B6C1 0x65E3 # 0 +0x8EA3B6C2 0x6657 # 0 +0x8EA3B6C4 0x6663 # 0 +0x8EA3B6C5 0x6667 # 0 +0x8EA3B6C6 0x671A # 0 +0x8EA3B6C7 0x6719 # 0 +0x8EA3B6C8 0x6716 # 0 +0x8EA3B6CB 0x689E # 0 +0x8EA3B6CC 0x68B6 # 0 +0x8EA3B6CD 0x6898 # 0 +0x8EA3B6CE 0x6873 # 0 +0x8EA3B6D0 0x689A # 0 +0x8EA3B6D1 0x688E # 0 +0x8EA3B6D2 0x68B7 # 0 +0x8EA3B6D3 0x68DB # 0 +0x8EA3B6D4 0x68A5 # 0 +0x8EA3B6D5 0x686C # 0 +0x8EA3B6D6 0x68C1 # 0 +0x8EA3B6D7 0x6884 # 0 +0x8EA3B6DA 0x6895 # 0 +0x8EA3B6DB 0x687A # 0 +0x8EA3B6DC 0x6899 # 0 +0x8EA3B6DE 0x68B8 # 0 +0x8EA3B6DF 0x68B9 # 0 +0x8EA3B6E0 0x6870 # 0 +0x8EA3B6E2 0x6B35 # 0 +0x8EA3B6E4 0x6B90 # 0 +0x8EA3B6E5 0x6BBB # 0 +0x8EA3B6E6 0x6BED # 0 +0x8EA3B6EA 0x6DC1 # 0 +0x8EA3B6EB 0x6DC3 # 0 +0x8EA3B6EC 0x6DCE # 0 +0x8EA3B6EF 0x6DAD # 0 +0x8EA3B6F0 0x6E04 # 0 +0x8EA3B6F2 0x6DB9 # 0 +0x8EA3B6F4 0x6DE7 # 0 +0x8EA3B6F6 0x6E08 # 0 +0x8EA3B6F7 0x6E06 # 0 +0x8EA3B6F9 0x6E0A # 0 +0x8EA3B6FA 0x6DB0 # 0 +0x8EA3B6FC 0x6DF8 # 0 +0x8EA3B6FD 0x6E0C # 0 +0x8EA3B7A1 0x6DB1 # 0 +0x8EA3B7A3 0x6E02 # 0 +0x8EA3B7A4 0x6E07 # 0 +0x8EA3B7A5 0x6E09 # 0 +0x8EA3B7A6 0x6E01 # 0 +0x8EA3B7A7 0x6E17 # 0 +0x8EA3B7A8 0x6DFF # 0 +0x8EA3B7A9 0x6E12 # 0 +0x8EA3B7AC 0x7103 # 0 +0x8EA3B7AD 0x7107 # 0 +0x8EA3B7AE 0x7101 # 0 +0x8EA3B7AF 0x70F5 # 0 +0x8EA3B7B0 0x70F1 # 0 +0x8EA3B7B1 0x7108 # 0 +0x8EA3B7B2 0x70F2 # 0 +0x8EA3B7B3 0x710F # 0 +0x8EA3B7B5 0x70FE # 0 +0x8EA3B7B9 0x731A # 0 +0x8EA3B7BA 0x7310 # 0 +0x8EA3B7BB 0x730E # 0 +0x8EA3B7BC 0x7402 # 0 +0x8EA3B7BD 0x73F3 # 0 +0x8EA3B7C0 0x73FB # 0 +0x8EA3B7C4 0x751B # 0 +0x8EA3B7C5 0x7523 # 0 +0x8EA3B7C6 0x7561 # 0 +0x8EA3B7C7 0x7568 # 0 +0x8EA3B7C9 0x7567 # 0 +0x8EA3B7CA 0x75D3 # 0 +0x8EA3B7CD 0x7690 # 0 +0x8EA3B7D0 0x76D5 # 0 +0x8EA3B7D1 0x76D7 # 0 +0x8EA3B7D2 0x76D6 # 0 +0x8EA3B7D3 0x7730 # 0 +0x8EA3B7D5 0x7726 # 0 +0x8EA3B7D7 0x7740 # 0 +0x8EA3B7D9 0x771E # 0 +0x8EA3B7DD 0x7847 # 0 +0x8EA3B7DF 0x784B # 0 +0x8EA3B7E0 0x7851 # 0 +0x8EA3B7E1 0x784F # 0 +0x8EA3B7E2 0x7842 # 0 +0x8EA3B7E3 0x7846 # 0 +0x8EA3B7E5 0x796E # 0 +0x8EA3B7E6 0x796C # 0 +0x8EA3B7E7 0x79F2 # 0 +0x8EA3B7E9 0x79F1 # 0 +0x8EA3B7EA 0x79F5 # 0 +0x8EA3B7EB 0x79F3 # 0 +0x8EA3B7EC 0x79F9 # 0 +0x8EA3B7F0 0x7A9A # 0 +0x8EA3B7F1 0x7A93 # 0 +0x8EA3B7F2 0x7A91 # 0 +0x8EA3B7F3 0x7AE1 # 0 +0x8EA3B7F6 0x7B21 # 0 +0x8EA3B7F7 0x7B1C # 0 +0x8EA3B7F8 0x7B16 # 0 +0x8EA3B7F9 0x7B17 # 0 +0x8EA3B7FA 0x7B36 # 0 +0x8EA3B7FB 0x7B1F # 0 +0x8EA3B7FD 0x7C93 # 0 +0x8EA3B7FE 0x7C99 # 0 +0x8EA3B8A1 0x7C9A # 0 +0x8EA3B8A2 0x7C9C # 0 +0x8EA3B8A4 0x7D49 # 0 +0x8EA3B8A6 0x7D34 # 0 +0x8EA3B8A7 0x7D37 # 0 +0x8EA3B8A9 0x7D2D # 0 +0x8EA3B8AB 0x7D4C # 0 +0x8EA3B8AE 0x7D48 # 0 +0x8EA3B8B1 0x7F3B # 0 +0x8EA3B8B6 0x8008 # 0 +0x8EA3B8B7 0x801A # 0 +0x8EA3B8B9 0x801D # 0 +0x8EA3B8BB 0x8049 # 0 +0x8EA3B8BC 0x8045 # 0 +0x8EA3B8BD 0x8044 # 0 +0x8EA3B8BE 0x7C9B # 0 +0x8EA3B8C1 0x812A # 0 +0x8EA3B8C2 0x812E # 0 +0x8EA3B8C5 0x8131 # 0 +0x8EA3B8C7 0x811A # 0 +0x8EA3B8C8 0x8134 # 0 +0x8EA3B8C9 0x8117 # 0 +0x8EA3B8CD 0x831D # 0 +0x8EA3B8CE 0x8371 # 0 +0x8EA3B8CF 0x8384 # 0 +0x8EA3B8D0 0x8380 # 0 +0x8EA3B8D1 0x8372 # 0 +0x8EA3B8D2 0x83A1 # 0 +0x8EA3B8D4 0x8379 # 0 +0x8EA3B8D5 0x8391 # 0 +0x8EA3B8D7 0x839F # 0 +0x8EA3B8D8 0x83AD # 0 +0x8EA3B8DB 0x8323 # 0 +0x8EA3B8DD 0x8385 # 0 +0x8EA3B8DE 0x839C # 0 +0x8EA3B8DF 0x83B7 # 0 +0x8EA3B8E0 0x8658 # 0 +0x8EA3B8E1 0x865A # 0 +0x8EA3B8E3 0x8657 # 0 +0x8EA3B8E4 0x86B2 # 0 +0x8EA3B8E6 0x86AE # 0 +0x8EA3B8EA 0x8845 # 0 +0x8EA3B8EB 0x889C # 0 +0x8EA3B8EC 0x8894 # 0 +0x8EA3B8ED 0x88A3 # 0 +0x8EA3B8EE 0x888F # 0 +0x8EA3B8EF 0x88A5 # 0 +0x8EA3B8F0 0x88A9 # 0 +0x8EA3B8F1 0x88A6 # 0 +0x8EA3B8F2 0x888A # 0 +0x8EA3B8F3 0x88A0 # 0 +0x8EA3B8F4 0x8890 # 0 +0x8EA3B8F5 0x8992 # 0 +0x8EA3B8F6 0x8991 # 0 +0x8EA3B8F7 0x8994 # 0 +0x8EA3B8F9 0x8A26 # 0 +0x8EA3B8FA 0x8A32 # 0 +0x8EA3B8FB 0x8A28 # 0 +0x8EA3B8FE 0x8A1C # 0 +0x8EA3B9A2 0x8A2B # 0 +0x8EA3B9A3 0x8A20 # 0 +0x8EA3B9A5 0x8A29 # 0 +0x8EA3B9A9 0x8A21 # 0 +0x8EA3B9AA 0x8C3A # 0 +0x8EA3B9AC 0x8C5B # 0 +0x8EA3B9AD 0x8C58 # 0 +0x8EA3B9AE 0x8C7C # 0 +0x8EA3B9B0 0x8CA6 # 0 +0x8EA3B9B1 0x8CAE # 0 +0x8EA3B9B2 0x8CAD # 0 +0x8EA3B9B3 0x8D65 # 0 +0x8EA3B9B5 0x8D7E # 0 +0x8EA3B9B7 0x8D7C # 0 +0x8EA3B9B8 0x8D7F # 0 +0x8EA3B9B9 0x8D7A # 0 +0x8EA3B9BA 0x8DBD # 0 +0x8EA3B9BD 0x8DC0 # 0 +0x8EA3B9BE 0x8DBB # 0 +0x8EA3B9BF 0x8EAD # 0 +0x8EA3B9C0 0x8EAF # 0 +0x8EA3B9C1 0x8ED6 # 0 +0x8EA3B9C7 0x8ED9 # 0 +0x8EA3B9CA 0x9012 # 0 +0x8EA3B9CB 0x900E # 0 +0x8EA3B9CC 0x9025 # 0 +0x8EA3B9CE 0x9013 # 0 +0x8EA3B9CF 0x90EE # 0 +0x8EA3B9D1 0x90AB # 0 +0x8EA3B9D2 0x90F7 # 0 +0x8EA3B9D4 0x9159 # 0 +0x8EA3B9D5 0x9154 # 0 +0x8EA3B9D6 0x91F2 # 0 +0x8EA3B9D7 0x91F0 # 0 +0x8EA3B9D8 0x91E5 # 0 +0x8EA3B9D9 0x91F6 # 0 +0x8EA3B9DC 0x9587 # 0 +0x8EA3B9DE 0x965A # 0 +0x8EA3B9E1 0x966E # 0 +0x8EA3B9E5 0x9679 # 0 +0x8EA3B9E7 0x98E1 # 0 +0x8EA3B9E8 0x98E6 # 0 +0x8EA3B9EA 0x9EC4 # 0 +0x8EA3B9EB 0x9ED2 # 0 +0x8EA3B9EC 0x4E80 # 0 +0x8EA3B9EE 0x4E81 # 0 +0x8EA3B9EF 0x508F # 0 +0x8EA3B9F0 0x5097 # 0 +0x8EA3B9F1 0x5088 # 0 +0x8EA3B9F2 0x5089 # 0 +0x8EA3B9F5 0x5081 # 0 +0x8EA3B9F6 0x5160 # 0 +0x8EA3B9F9 0x5E42 # 0 +0x8EA3B9FA 0x51D3 # 0 +0x8EA3B9FD 0x51D2 # 0 +0x8EA3B9FE 0x51D6 # 0 +0x8EA3BAA1 0x5273 # 0 +0x8EA3BAA3 0x5270 # 0 +0x8EA3BAA7 0x53A8 # 0 +0x8EA3BAA8 0x53A6 # 0 +0x8EA3BAA9 0x53C5 # 0 +0x8EA3BAAA 0x5597 # 0 +0x8EA3BAAB 0x55DE # 0 +0x8EA3BAAE 0x5596 # 0 +0x8EA3BAAF 0x55B4 # 0 +0x8EA3BAB1 0x5585 # 0 +0x8EA3BAB3 0x559B # 0 +0x8EA3BAB4 0x55A0 # 0 +0x8EA3BAB6 0x5559 # 0 +0x8EA3BAB8 0x5586 # 0 +0x8EA3BABB 0x55AF # 0 +0x8EA3BABC 0x557A # 0 +0x8EA3BAC0 0x559E # 0 +0x8EA3BAC2 0x55A9 # 0 +0x8EA3BAC3 0x570F # 0 +0x8EA3BAC4 0x570E # 0 +0x8EA3BAC5 0x581A # 0 +0x8EA3BAC7 0x581F # 0 +0x8EA3BAC9 0x583C # 0 +0x8EA3BACA 0x5818 # 0 +0x8EA3BACB 0x583E # 0 +0x8EA3BACC 0x5826 # 0 +0x8EA3BACE 0x583A # 0 +0x8EA3BAD0 0x5822 # 0 +0x8EA3BAD2 0x58FB # 0 +0x8EA3BAD3 0x5963 # 0 +0x8EA3BAD4 0x5964 # 0 +0x8EA3BAD6 0x5AA8 # 0 +0x8EA3BAD7 0x5AA3 # 0 +0x8EA3BAD8 0x5A82 # 0 +0x8EA3BAD9 0x5A88 # 0 +0x8EA3BADA 0x5AA1 # 0 +0x8EA3BADB 0x5A85 # 0 +0x8EA3BADC 0x5A98 # 0 +0x8EA3BADE 0x5A99 # 0 +0x8EA3BAE0 0x5A89 # 0 +0x8EA3BAE1 0x5A81 # 0 +0x8EA3BAE2 0x5A96 # 0 +0x8EA3BAE3 0x5A80 # 0 +0x8EA3BAE6 0x5A91 # 0 +0x8EA3BAEB 0x5ACF # 0 +0x8EA3BAF2 0x5A87 # 0 +0x8EA3BAF3 0x5AA0 # 0 +0x8EA3BAF5 0x5A79 # 0 +0x8EA3BAF7 0x5A86 # 0 +0x8EA3BAF8 0x5AAB # 0 +0x8EA3BAF9 0x5AAA # 0 +0x8EA3BAFA 0x5AA4 # 0 +0x8EA3BAFB 0x5A8D # 0 +0x8EA3BAFC 0x5A7E # 0 +0x8EA3BAFE 0x5BD5 # 0 +0x8EA3BBA4 0x5C1E # 0 +0x8EA3BBA5 0x5C5F # 0 +0x8EA3BBA6 0x5C5E # 0 +0x8EA3BBA7 0x5D44 # 0 +0x8EA3BBA8 0x5D3E # 0 +0x8EA3BBAA 0x5D48 # 0 +0x8EA3BBAB 0x5D1C # 0 +0x8EA3BBAD 0x5D5B # 0 +0x8EA3BBAE 0x5D4D # 0 +0x8EA3BBB1 0x5D57 # 0 +0x8EA3BBB3 0x5D53 # 0 +0x8EA3BBB4 0x5D4F # 0 +0x8EA3BBB6 0x5D3B # 0 +0x8EA3BBB7 0x5D46 # 0 +0x8EA3BBBA 0x5E46 # 0 +0x8EA3BBBB 0x5E47 # 0 +0x8EA3BBBD 0x5E48 # 0 +0x8EA3BBBE 0x5EC0 # 0 +0x8EA3BBBF 0x5EBD # 0 +0x8EA3BBC0 0x5EBF # 0 +0x8EA3BBC2 0x5F11 # 0 +0x8EA3BBC4 0x5F3E # 0 +0x8EA3BBC5 0x5F3B # 0 +0x8EA3BBC7 0x5F3A # 0 +0x8EA3BBCB 0x5FA7 # 0 +0x8EA3BBCD 0x60EA # 0 +0x8EA3BBCF 0x6107 # 0 +0x8EA3BBD0 0x6122 # 0 +0x8EA3BBD1 0x610C # 0 +0x8EA3BBD4 0x60B3 # 0 +0x8EA3BBD5 0x60D6 # 0 +0x8EA3BBD6 0x60D2 # 0 +0x8EA3BBD8 0x60E3 # 0 +0x8EA3BBD9 0x60E5 # 0 +0x8EA3BBDA 0x60E9 # 0 +0x8EA3BBDD 0x6111 # 0 +0x8EA3BBDE 0x60FD # 0 +0x8EA3BBE1 0x611E # 0 +0x8EA3BBE2 0x6120 # 0 +0x8EA3BBE3 0x6121 # 0 +0x8EA3BBE4 0x621E # 0 +0x8EA3BBE6 0x63E2 # 0 +0x8EA3BBE7 0x63DE # 0 +0x8EA3BBE8 0x63E6 # 0 +0x8EA3BBED 0x63F8 # 0 +0x8EA3BBEF 0x63FE # 0 +0x8EA3BBF0 0x63C1 # 0 +0x8EA3BBF1 0x63BF # 0 +0x8EA3BBF2 0x63F7 # 0 +0x8EA3BBF3 0x63D1 # 0 +0x8EA3BBF4 0x655F # 0 +0x8EA3BBF5 0x6560 # 0 +0x8EA3BBF6 0x6561 # 0 +0x8EA3BBF9 0x65D1 # 0 +0x8EA3BBFC 0x667D # 0 +0x8EA3BBFD 0x666B # 0 +0x8EA3BBFE 0x667F # 0 +0x8EA3BCA3 0x6673 # 0 +0x8EA3BCA4 0x6681 # 0 +0x8EA3BCA5 0x666D # 0 +0x8EA3BCA6 0x6669 # 0 +0x8EA3BCA9 0x671E # 0 +0x8EA3BCAA 0x68ED # 0 +0x8EA3BCAF 0x6903 # 0 +0x8EA3BCB1 0x68FE # 0 +0x8EA3BCB2 0x68E5 # 0 +0x8EA3BCB3 0x691E # 0 +0x8EA3BCB4 0x6902 # 0 +0x8EA3BCB7 0x6909 # 0 +0x8EA3BCB8 0x68CA # 0 +0x8EA3BCB9 0x6900 # 0 +0x8EA3BCBB 0x6901 # 0 +0x8EA3BCBC 0x6918 # 0 +0x8EA3BCBD 0x68E2 # 0 +0x8EA3BCBE 0x68CF # 0 +0x8EA3BCC0 0x692E # 0 +0x8EA3BCC1 0x68C5 # 0 +0x8EA3BCC2 0x68FF # 0 +0x8EA3BCC4 0x691C # 0 +0x8EA3BCC5 0x68C3 # 0 +0x8EA3BCC7 0x6B6F # 0 +0x8EA3BCC9 0x6B6E # 0 +0x8EA3BCCB 0x6BBE # 0 +0x8EA3BCCD 0x6BF4 # 0 +0x8EA3BCCE 0x6C2D # 0 +0x8EA3BCD0 0x6DB6 # 0 +0x8EA3BCD1 0x6E75 # 0 +0x8EA3BCD2 0x6E1E # 0 +0x8EA3BCD4 0x6E18 # 0 +0x8EA3BCD6 0x6E48 # 0 +0x8EA3BCD8 0x6E4F # 0 +0x8EA3BCDA 0x6E42 # 0 +0x8EA3BCDB 0x6E6A # 0 +0x8EA3BCDC 0x6E70 # 0 +0x8EA3BCDD 0x6DFE # 0 +0x8EA3BCE0 0x6E6D # 0 +0x8EA3BCE2 0x6E7B # 0 +0x8EA3BCE3 0x6E7E # 0 +0x8EA3BCE4 0x6E59 # 0 +0x8EA3BCE6 0x6E57 # 0 +0x8EA3BCE8 0x6E80 # 0 +0x8EA3BCE9 0x6E50 # 0 +0x8EA3BCEB 0x6E29 # 0 +0x8EA3BCEC 0x6E76 # 0 +0x8EA3BCED 0x6E2A # 0 +0x8EA3BCEE 0x6E4C # 0 +0x8EA3BCEF 0x712A # 0 +0x8EA3BCF1 0x7135 # 0 +0x8EA3BCF2 0x712C # 0 +0x8EA3BCF3 0x7137 # 0 +0x8EA3BCF4 0x711D # 0 +0x8EA3BCF7 0x7138 # 0 +0x8EA3BCF9 0x7134 # 0 +0x8EA3BCFA 0x712B # 0 +0x8EA3BCFB 0x7133 # 0 +0x8EA3BCFC 0x7127 # 0 +0x8EA3BCFD 0x7124 # 0 +0x8EA3BDA1 0x712D # 0 +0x8EA3BDA2 0x7232 # 0 +0x8EA3BDA3 0x7283 # 0 +0x8EA3BDA4 0x7282 # 0 +0x8EA3BDA5 0x7287 # 0 +0x8EA3BDA6 0x7306 # 0 +0x8EA3BDA7 0x7324 # 0 +0x8EA3BDA8 0x7338 # 0 +0x8EA3BDA9 0x732A # 0 +0x8EA3BDAA 0x732C # 0 +0x8EA3BDAB 0x732B # 0 +0x8EA3BDAD 0x732F # 0 +0x8EA3BDAE 0x7328 # 0 +0x8EA3BDAF 0x7417 # 0 +0x8EA3BDB2 0x7419 # 0 +0x8EA3BDB3 0x7438 # 0 +0x8EA3BDB5 0x741F # 0 +0x8EA3BDB6 0x7414 # 0 +0x8EA3BDB7 0x743C # 0 +0x8EA3BDB8 0x73F7 # 0 +0x8EA3BDB9 0x741C # 0 +0x8EA3BDBA 0x7415 # 0 +0x8EA3BDBB 0x7418 # 0 +0x8EA3BDBC 0x7439 # 0 +0x8EA3BDBD 0x74F9 # 0 +0x8EA3BDBE 0x7524 # 0 +0x8EA3BDC2 0x756E # 0 +0x8EA3BDC3 0x756D # 0 +0x8EA3BDC4 0x7571 # 0 +0x8EA3BDC5 0x758E # 0 +0x8EA3BDC7 0x75E5 # 0 +0x8EA3BDCC 0x7694 # 0 +0x8EA3BDCD 0x76B3 # 0 +0x8EA3BDCF 0x76D9 # 0 +0x8EA3BDD1 0x7748 # 0 +0x8EA3BDD2 0x7749 # 0 +0x8EA3BDD3 0x7743 # 0 +0x8EA3BDD6 0x7742 # 0 +0x8EA3BDD7 0x77DF # 0 +0x8EA3BDD9 0x7863 # 0 +0x8EA3BDDA 0x7876 # 0 +0x8EA3BDDC 0x785F # 0 +0x8EA3BDDD 0x7866 # 0 +0x8EA3BDDE 0x7966 # 0 +0x8EA3BDDF 0x7971 # 0 +0x8EA3BDE2 0x7976 # 0 +0x8EA3BDE3 0x7984 # 0 +0x8EA3BDE4 0x7975 # 0 +0x8EA3BDE5 0x79FF # 0 +0x8EA3BDE6 0x7A07 # 0 +0x8EA3BDE8 0x7A0E # 0 +0x8EA3BDE9 0x7A09 # 0 +0x8EA3BDF0 0x7AE7 # 0 +0x8EA3BDF1 0x7AE2 # 0 +0x8EA3BDF2 0x7B55 # 0 +0x8EA3BDF5 0x7B43 # 0 +0x8EA3BDF6 0x7B57 # 0 +0x8EA3BDF7 0x7B6C # 0 +0x8EA3BDF8 0x7B42 # 0 +0x8EA3BDF9 0x7B53 # 0 +0x8EA3BDFB 0x7B41 # 0 +0x8EA3BDFE 0x7CA7 # 0 +0x8EA3BEA1 0x7CA0 # 0 +0x8EA3BEA2 0x7CA6 # 0 +0x8EA3BEA3 0x7CA4 # 0 +0x8EA3BEA4 0x7D74 # 0 +0x8EA3BEA6 0x7D59 # 0 +0x8EA3BEA8 0x7D60 # 0 +0x8EA3BEA9 0x7D57 # 0 +0x8EA3BEAA 0x7D6C # 0 +0x8EA3BEAB 0x7D7E # 0 +0x8EA3BEAC 0x7D64 # 0 +0x8EA3BEAE 0x7D5A # 0 +0x8EA3BEAF 0x7D5D # 0 +0x8EA3BEB3 0x7D76 # 0 +0x8EA3BEB4 0x7D4D # 0 +0x8EA3BEB5 0x7D75 # 0 +0x8EA3BEB7 0x7FD3 # 0 +0x8EA3BEB8 0x7FD6 # 0 +0x8EA3BEBB 0x8060 # 0 +0x8EA3BEBC 0x804E # 0 +0x8EA3BEBD 0x8145 # 0 +0x8EA3BEBE 0x813B # 0 +0x8EA3BEC0 0x8148 # 0 +0x8EA3BEC1 0x8142 # 0 +0x8EA3BEC2 0x8149 # 0 +0x8EA3BEC3 0x8140 # 0 +0x8EA3BEC4 0x8114 # 0 +0x8EA3BEC5 0x8141 # 0 +0x8EA3BEC7 0x81EF # 0 +0x8EA3BEC8 0x81F6 # 0 +0x8EA3BEC9 0x8203 # 0 +0x8EA3BECB 0x83ED # 0 +0x8EA3BECD 0x83DA # 0 +0x8EA3BECE 0x8418 # 0 +0x8EA3BECF 0x83D2 # 0 +0x8EA3BED0 0x8408 # 0 +0x8EA3BED2 0x8400 # 0 +0x8EA3BED6 0x8417 # 0 +0x8EA3BED7 0x8346 # 0 +0x8EA3BED8 0x8414 # 0 +0x8EA3BED9 0x83D3 # 0 +0x8EA3BEDA 0x8405 # 0 +0x8EA3BEDB 0x841F # 0 +0x8EA3BEDC 0x8402 # 0 +0x8EA3BEDD 0x8416 # 0 +0x8EA3BEDE 0x83CD # 0 +0x8EA3BEDF 0x83E6 # 0 +0x8EA3BEE1 0x865D # 0 +0x8EA3BEE2 0x86D5 # 0 +0x8EA3BEE3 0x86E1 # 0 +0x8EA3BEE8 0x86EE # 0 +0x8EA3BEE9 0x8847 # 0 +0x8EA3BEEA 0x8846 # 0 +0x8EA3BEED 0x88BB # 0 +0x8EA3BEEF 0x88BF # 0 +0x8EA3BEF0 0x88B4 # 0 +0x8EA3BEF2 0x88B5 # 0 +0x8EA3BEF4 0x899A # 0 +0x8EA3BEF5 0x8A43 # 0 +0x8EA3BEF8 0x8A5A # 0 +0x8EA3BEFC 0x8A35 # 0 +0x8EA3BEFD 0x8A38 # 0 +0x8EA3BEFE 0x8A42 # 0 +0x8EA3BFA1 0x8A49 # 0 +0x8EA3BFA2 0x8A5D # 0 +0x8EA3BFA3 0x8A4B # 0 +0x8EA3BFA4 0x8A3D # 0 +0x8EA3BFA9 0x8C60 # 0 +0x8EA3BFAA 0x8C5E # 0 +0x8EA3BFAB 0x8C7F # 0 +0x8EA3BFAC 0x8C7E # 0 +0x8EA3BFAD 0x8C83 # 0 +0x8EA3BFAF 0x8CB1 # 0 +0x8EA3BFB0 0x8D87 # 0 +0x8EA3BFB3 0x8D88 # 0 +0x8EA3BFB4 0x8D83 # 0 +0x8EA3BFB7 0x8D86 # 0 +0x8EA3BFB8 0x8D8B # 0 +0x8EA3BFB9 0x8D82 # 0 +0x8EA3BFBA 0x8DCA # 0 +0x8EA3BFBB 0x8DD2 # 0 +0x8EA3BFBE 0x8DD4 # 0 +0x8EA3BFBF 0x8DC9 # 0 +0x8EA3BFC0 0x8EB0 # 0 +0x8EA3BFC4 0x8EF2 # 0 +0x8EA3BFC5 0x8EE4 # 0 +0x8EA3BFC6 0x8EF3 # 0 +0x8EA3BFC7 0x8EEA # 0 +0x8EA3BFC9 0x8EFD # 0 +0x8EA3BFCB 0x8F9D # 0 +0x8EA3BFCC 0x902B # 0 +0x8EA3BFCD 0x902A # 0 +0x8EA3BFCF 0x9028 # 0 +0x8EA3BFD0 0x9029 # 0 +0x8EA3BFD1 0x902C # 0 +0x8EA3BFD4 0x903A # 0 +0x8EA3BFD5 0x9030 # 0 +0x8EA3BFD6 0x9037 # 0 +0x8EA3BFD7 0x903B # 0 +0x8EA3BFD9 0x910A # 0 +0x8EA3BFDD 0x91FE # 0 +0x8EA3BFDE 0x9220 # 0 +0x8EA3BFE0 0x920B # 0 +0x8EA3BFE2 0x9218 # 0 +0x8EA3BFE3 0x9222 # 0 +0x8EA3BFE5 0x921B # 0 +0x8EA3BFE6 0x9208 # 0 +0x8EA3BFE8 0x920E # 0 +0x8EA3BFE9 0x9213 # 0 +0x8EA3BFEC 0x9595 # 0 +0x8EA3BFF0 0x968C # 0 +0x8EA3BFF1 0x967B # 0 +0x8EA3BFF2 0x967F # 0 +0x8EA3BFF3 0x9681 # 0 +0x8EA3BFF5 0x9682 # 0 +0x8EA3BFFB 0x96EE # 0 +0x8EA3BFFC 0x96ED # 0 +0x8EA3BFFE 0x96EC # 0 +0x8EA3C0A1 0x975F # 0 +0x8EA3C0A2 0x976F # 0 +0x8EA3C0A4 0x976D # 0 +0x8EA3C0AB 0x98F0 # 0 +0x8EA3C0AF 0x9AA9 # 0 +0x8EA3C0B2 0x9AE0 # 0 +0x8EA3C0B3 0x4EB7 # 0 +0x8EA3C0B6 0x50CC # 0 +0x8EA3C0B7 0x50BC # 0 +0x8EA3C0B9 0x50AA # 0 +0x8EA3C0BA 0x50B9 # 0 +0x8EA3C0BC 0x50AB # 0 +0x8EA3C0BD 0x50C3 # 0 +0x8EA3C0BE 0x50CD # 0 +0x8EA3C0BF 0x517E # 0 +0x8EA3C0C0 0x527E # 0 +0x8EA3C0C1 0x5279 # 0 +0x8EA3C0C4 0x52E1 # 0 +0x8EA3C0C5 0x52E0 # 0 +0x8EA3C0C6 0x52E7 # 0 +0x8EA3C0C7 0x5380 # 0 +0x8EA3C0C8 0x53AB # 0 +0x8EA3C0C9 0x53AA # 0 +0x8EA3C0CA 0x53A9 # 0 +0x8EA3C0CB 0x53E0 # 0 +0x8EA3C0CC 0x55EA # 0 +0x8EA3C0CE 0x55D7 # 0 +0x8EA3C0D1 0x55C1 # 0 +0x8EA3C0D2 0x5715 # 0 +0x8EA3C0D4 0x586C # 0 +0x8EA3C0D6 0x585C # 0 +0x8EA3C0D7 0x5850 # 0 +0x8EA3C0D8 0x5861 # 0 +0x8EA3C0D9 0x586A # 0 +0x8EA3C0DA 0x5869 # 0 +0x8EA3C0DB 0x5856 # 0 +0x8EA3C0DC 0x5860 # 0 +0x8EA3C0DD 0x5866 # 0 +0x8EA3C0DE 0x585F # 0 +0x8EA3C0DF 0x5923 # 0 +0x8EA3C0E0 0x5966 # 0 +0x8EA3C0E1 0x5968 # 0 +0x8EA3C0E4 0x5ACE # 0 +0x8EA3C0E6 0x5AC5 # 0 +0x8EA3C0E7 0x5AC3 # 0 +0x8EA3C0EA 0x5AD0 # 0 +0x8EA3C0F1 0x5B74 # 0 +0x8EA3C0F2 0x5B76 # 0 +0x8EA3C0F3 0x5BDC # 0 +0x8EA3C0F4 0x5BD7 # 0 +0x8EA3C0F5 0x5BDA # 0 +0x8EA3C0F6 0x5BDB # 0 +0x8EA3C0F8 0x5C20 # 0 +0x8EA3C0F9 0x5D6D # 0 +0x8EA3C0FA 0x5D66 # 0 +0x8EA3C0FC 0x5D64 # 0 +0x8EA3C0FD 0x5D6E # 0 +0x8EA3C1A1 0x5D60 # 0 +0x8EA3C1A2 0x5F42 # 0 +0x8EA3C1A3 0x5F5A # 0 +0x8EA3C1A4 0x5F6E # 0 +0x8EA3C1A7 0x6130 # 0 +0x8EA3C1A8 0x613A # 0 +0x8EA3C1A9 0x612A # 0 +0x8EA3C1AA 0x6143 # 0 +0x8EA3C1AB 0x6119 # 0 +0x8EA3C1AC 0x6131 # 0 +0x8EA3C1AE 0x613D # 0 +0x8EA3C1B2 0x6408 # 0 +0x8EA3C1B3 0x6432 # 0 +0x8EA3C1B4 0x6438 # 0 +0x8EA3C1B6 0x6431 # 0 +0x8EA3C1B8 0x6419 # 0 +0x8EA3C1BA 0x6411 # 0 +0x8EA3C1BD 0x6429 # 0 +0x8EA3C1BE 0x641D # 0 +0x8EA3C1C2 0x643C # 0 +0x8EA3C1C4 0x6446 # 0 +0x8EA3C1C5 0x6447 # 0 +0x8EA3C1C8 0x643A # 0 +0x8EA3C1C9 0x6407 # 0 +0x8EA3C1CB 0x656B # 0 +0x8EA3C1CD 0x6570 # 0 +0x8EA3C1CE 0x656D # 0 +0x8EA3C1D0 0x65E4 # 0 +0x8EA3C1D1 0x6693 # 0 +0x8EA3C1D6 0x668F # 0 +0x8EA3C1D9 0x6692 # 0 +0x8EA3C1DB 0x668E # 0 +0x8EA3C1DD 0x6946 # 0 +0x8EA3C1E5 0x6931 # 0 +0x8EA3C1E8 0x693E # 0 +0x8EA3C1EA 0x697C # 0 +0x8EA3C1EB 0x6943 # 0 +0x8EA3C1ED 0x6973 # 0 +0x8EA3C1EF 0x6955 # 0 +0x8EA3C1F2 0x6985 # 0 +0x8EA3C1F3 0x694D # 0 +0x8EA3C1F4 0x6950 # 0 +0x8EA3C1F5 0x6947 # 0 +0x8EA3C1F6 0x6967 # 0 +0x8EA3C1F7 0x6936 # 0 +0x8EA3C1F8 0x6964 # 0 +0x8EA3C1F9 0x6961 # 0 +0x8EA3C1FB 0x697D # 0 +0x8EA3C1FC 0x6B44 # 0 +0x8EA3C1FD 0x6B40 # 0 +0x8EA3C1FE 0x6B71 # 0 +0x8EA3C2A1 0x6B73 # 0 +0x8EA3C2A2 0x6B9C # 0 +0x8EA3C2A6 0x6BC1 # 0 +0x8EA3C2A8 0x6BFA # 0 +0x8EA3C2A9 0x6C31 # 0 +0x8EA3C2AA 0x6C32 # 0 +0x8EA3C2AD 0x6EB8 # 0 +0x8EA3C2AE 0x6EA8 # 0 +0x8EA3C2B0 0x6E91 # 0 +0x8EA3C2B1 0x6EBB # 0 +0x8EA3C2B3 0x6E9A # 0 +0x8EA3C2B6 0x6EA9 # 0 +0x8EA3C2B9 0x6EB5 # 0 +0x8EA3C2BA 0x6E6C # 0 +0x8EA3C2BB 0x6EE8 # 0 +0x8EA3C2BD 0x6EDD # 0 +0x8EA3C2BE 0x6EDA # 0 +0x8EA3C2BF 0x6EE6 # 0 +0x8EA3C2C0 0x6EAC # 0 +0x8EA3C2C4 0x6ED9 # 0 +0x8EA3C2C5 0x6EE3 # 0 +0x8EA3C2C6 0x6EE9 # 0 +0x8EA3C2C7 0x6EDB # 0 +0x8EA3C2C9 0x716F # 0 +0x8EA3C2CC 0x7148 # 0 +0x8EA3C2CE 0x714A # 0 +0x8EA3C2CF 0x716B # 0 +0x8EA3C2D1 0x714F # 0 +0x8EA3C2D2 0x7157 # 0 +0x8EA3C2D3 0x7174 # 0 +0x8EA3C2D7 0x7145 # 0 +0x8EA3C2D8 0x7151 # 0 +0x8EA3C2D9 0x716D # 0 +0x8EA3C2DB 0x7251 # 0 +0x8EA3C2DC 0x7250 # 0 +0x8EA3C2DD 0x724E # 0 +0x8EA3C2DF 0x7341 # 0 +0x8EA3C2E1 0x732E # 0 +0x8EA3C2E2 0x7346 # 0 +0x8EA3C2E4 0x7427 # 0 +0x8EA3C2E6 0x7448 # 0 +0x8EA3C2E7 0x7453 # 0 +0x8EA3C2E8 0x743D # 0 +0x8EA3C2EA 0x745D # 0 +0x8EA3C2EB 0x7456 # 0 +0x8EA3C2ED 0x741E # 0 +0x8EA3C2EE 0x7447 # 0 +0x8EA3C2EF 0x7443 # 0 +0x8EA3C2F0 0x7458 # 0 +0x8EA3C2F1 0x7449 # 0 +0x8EA3C2F3 0x744C # 0 +0x8EA3C2F4 0x7445 # 0 +0x8EA3C2F5 0x743E # 0 +0x8EA3C2F7 0x7501 # 0 +0x8EA3C2F8 0x751E # 0 +0x8EA3C2FB 0x757A # 0 +0x8EA3C2FC 0x75EE # 0 +0x8EA3C2FD 0x7602 # 0 +0x8EA3C2FE 0x7697 # 0 +0x8EA3C3A1 0x7698 # 0 +0x8EA3C3A5 0x775D # 0 +0x8EA3C3A6 0x7764 # 0 +0x8EA3C3A7 0x7753 # 0 +0x8EA3C3A8 0x7758 # 0 +0x8EA3C3A9 0x7882 # 0 +0x8EA3C3AA 0x7890 # 0 +0x8EA3C3AB 0x788A # 0 +0x8EA3C3AD 0x787A # 0 +0x8EA3C3AE 0x787D # 0 +0x8EA3C3B0 0x788B # 0 +0x8EA3C3B1 0x7878 # 0 +0x8EA3C3B4 0x788D # 0 +0x8EA3C3B5 0x7888 # 0 +0x8EA3C3B6 0x7892 # 0 +0x8EA3C3B7 0x7881 # 0 +0x8EA3C3B8 0x797E # 0 +0x8EA3C3B9 0x7983 # 0 +0x8EA3C3BD 0x7980 # 0 +0x8EA3C3C1 0x7A0F # 0 +0x8EA3C3C4 0x7A1D # 0 +0x8EA3C3C6 0x7AA1 # 0 +0x8EA3C3C7 0x7AA4 # 0 +0x8EA3C3C9 0x7AE9 # 0 +0x8EA3C3CA 0x7AEA # 0 +0x8EA3C3CC 0x7B62 # 0 +0x8EA3C3CD 0x7B6B # 0 +0x8EA3C3CF 0x7B5E # 0 +0x8EA3C3D1 0x7B79 # 0 +0x8EA3C3D4 0x7B6F # 0 +0x8EA3C3D5 0x7B68 # 0 +0x8EA3C3D8 0x7CAE # 0 +0x8EA3C3DC 0x7CB0 # 0 +0x8EA3C3DE 0x7D90 # 0 +0x8EA3C3E0 0x7D8A # 0 +0x8EA3C3E2 0x7D8B # 0 +0x8EA3C3E3 0x7D99 # 0 +0x8EA3C3E4 0x7D95 # 0 +0x8EA3C3E6 0x7D87 # 0 +0x8EA3C3E7 0x7D78 # 0 +0x8EA3C3E8 0x7D97 # 0 +0x8EA3C3E9 0x7D89 # 0 +0x8EA3C3EA 0x7D98 # 0 +0x8EA3C3EE 0x7FA3 # 0 +0x8EA3C3F2 0x7FDD # 0 +0x8EA3C3F3 0x8057 # 0 +0x8EA3C3F5 0x8163 # 0 +0x8EA3C3F6 0x816A # 0 +0x8EA3C3F7 0x816C # 0 +0x8EA3C3FB 0x815D # 0 +0x8EA3C3FC 0x8175 # 0 +0x8EA3C3FE 0x815F # 0 +0x8EA3C4A2 0x817D # 0 +0x8EA3C4A3 0x816D # 0 +0x8EA3C4A6 0x8241 # 0 +0x8EA3C4A7 0x844F # 0 +0x8EA3C4A8 0x8484 # 0 +0x8EA3C4AA 0x847F # 0 +0x8EA3C4AC 0x8448 # 0 +0x8EA3C4AD 0x842A # 0 +0x8EA3C4AE 0x847B # 0 +0x8EA3C4AF 0x8472 # 0 +0x8EA3C4B0 0x8464 # 0 +0x8EA3C4B1 0x842E # 0 +0x8EA3C4B2 0x845C # 0 +0x8EA3C4B3 0x8453 # 0 +0x8EA3C4B5 0x8441 # 0 +0x8EA3C4B6 0x84C8 # 0 +0x8EA3C4B8 0x8462 # 0 +0x8EA3C4B9 0x8480 # 0 +0x8EA3C4BA 0x843E # 0 +0x8EA3C4BB 0x8483 # 0 +0x8EA3C4BC 0x8471 # 0 +0x8EA3C4BE 0x844A # 0 +0x8EA3C4BF 0x8455 # 0 +0x8EA3C4C0 0x8458 # 0 +0x8EA3C4C4 0x86FC # 0 +0x8EA3C4C5 0x86FD # 0 +0x8EA3C4C6 0x8715 # 0 +0x8EA3C4C8 0x8716 # 0 +0x8EA3C4C9 0x86FF # 0 +0x8EA3C4CD 0x8858 # 0 +0x8EA3C4CE 0x88CF # 0 +0x8EA3C4CF 0x88E0 # 0 +0x8EA3C4D4 0x89E7 # 0 +0x8EA3C4D5 0x8A6A # 0 +0x8EA3C4D6 0x8A80 # 0 +0x8EA3C4D8 0x8A6F # 0 +0x8EA3C4D9 0x8A65 # 0 +0x8EA3C4DB 0x8A78 # 0 +0x8EA3C4DC 0x8A7D # 0 +0x8EA3C4DD 0x8A88 # 0 +0x8EA3C4E0 0x8A64 # 0 +0x8EA3C4E1 0x8A7E # 0 +0x8EA3C4E3 0x8A67 # 0 +0x8EA3C4E4 0x8C63 # 0 +0x8EA3C4E5 0x8C88 # 0 +0x8EA3C4E7 0x8CCD # 0 +0x8EA3C4E9 0x8CC9 # 0 +0x8EA3C4EB 0x8DED # 0 +0x8EA3C4F3 0x8EB1 # 0 +0x8EA3C4F6 0x8F04 # 0 +0x8EA3C4F7 0x8F9E # 0 +0x8EA3C4F8 0x8FA0 # 0 +0x8EA3C4F9 0x9043 # 0 +0x8EA3C4FA 0x9046 # 0 +0x8EA3C4FB 0x9048 # 0 +0x8EA3C4FC 0x9045 # 0 +0x8EA3C4FD 0x9040 # 0 +0x8EA3C4FE 0x904C # 0 +0x8EA3C5A3 0x910C # 0 +0x8EA3C5A4 0x9113 # 0 +0x8EA3C5A5 0x9115 # 0 +0x8EA3C5A7 0x916B # 0 +0x8EA3C5A8 0x9167 # 0 +0x8EA3C5A9 0x925D # 0 +0x8EA3C5AA 0x9255 # 0 +0x8EA3C5AB 0x9235 # 0 +0x8EA3C5AD 0x9259 # 0 +0x8EA3C5AE 0x922F # 0 +0x8EA3C5AF 0x923C # 0 +0x8EA3C5B0 0x928F # 0 +0x8EA3C5B1 0x925C # 0 +0x8EA3C5B2 0x926A # 0 +0x8EA3C5B3 0x9262 # 0 +0x8EA3C5B4 0x925F # 0 +0x8EA3C5B5 0x926B # 0 +0x8EA3C5B6 0x926E # 0 +0x8EA3C5B7 0x923B # 0 +0x8EA3C5B8 0x9244 # 0 +0x8EA3C5B9 0x9241 # 0 +0x8EA3C5BA 0x959A # 0 +0x8EA3C5BC 0x9599 # 0 +0x8EA3C5C0 0x968F # 0 +0x8EA3C5C2 0x9696 # 0 +0x8EA3C5C6 0x96F4 # 0 +0x8EA3C5C7 0x96FC # 0 +0x8EA3C5C9 0x9755 # 0 +0x8EA3C5CB 0x9779 # 0 +0x8EA3C5CF 0x97EE # 0 +0x8EA3C5D0 0x97F5 # 0 +0x8EA3C5D2 0x980B # 0 +0x8EA3C5D4 0x98F3 # 0 +0x8EA3C5D7 0x98F7 # 0 +0x8EA3C5D8 0x98FF # 0 +0x8EA3C5D9 0x98F5 # 0 +0x8EA3C5DB 0x98EC # 0 +0x8EA3C5DC 0x98F1 # 0 +0x8EA3C5DF 0x999A # 0 +0x8EA3C5E1 0x9AE2 # 0 +0x8EA3C5E2 0x9B3D # 0 +0x8EA3C5E3 0x9B5D # 0 +0x8EA3C5E4 0x9CE8 # 0 +0x8EA3C5E6 0x9CEB # 0 +0x8EA3C5E7 0x9CEF # 0 +0x8EA3C5E8 0x9CEE # 0 +0x8EA3C5E9 0x9E81 # 0 +0x8EA3C5EA 0x9F14 # 0 +0x8EA3C5EB 0x50D0 # 0 +0x8EA3C5EC 0x50D9 # 0 +0x8EA3C5ED 0x50DC # 0 +0x8EA3C5EE 0x50D8 # 0 +0x8EA3C5F0 0x50E1 # 0 +0x8EA3C5F1 0x50EB # 0 +0x8EA3C5F4 0x50F4 # 0 +0x8EA3C5F5 0x50E2 # 0 +0x8EA3C5F6 0x50DE # 0 +0x8EA3C5FA 0x51F4 # 0 +0x8EA3C5FE 0x52ED # 0 +0x8EA3C6A1 0x52EA # 0 +0x8EA3C6A3 0x5332 # 0 +0x8EA3C6A5 0x53AE # 0 +0x8EA3C6A6 0x53B0 # 0 +0x8EA3C6A8 0x55FB # 0 +0x8EA3C6A9 0x5603 # 0 +0x8EA3C6AA 0x560B # 0 +0x8EA3C6AC 0x5607 # 0 +0x8EA3C6AE 0x55F8 # 0 +0x8EA3C6B0 0x5628 # 0 +0x8EA3C6B1 0x561E # 0 +0x8EA3C6B3 0x5618 # 0 +0x8EA3C6B4 0x5611 # 0 +0x8EA3C6B5 0x5651 # 0 +0x8EA3C6B6 0x5605 # 0 +0x8EA3C6B7 0x5717 # 0 +0x8EA3C6B8 0x5892 # 0 +0x8EA3C6BA 0x588C # 0 +0x8EA3C6BC 0x5878 # 0 +0x8EA3C6BD 0x5884 # 0 +0x8EA3C6BE 0x5873 # 0 +0x8EA3C6BF 0x58AD # 0 +0x8EA3C6C0 0x5897 # 0 +0x8EA3C6C1 0x5895 # 0 +0x8EA3C6C2 0x5877 # 0 +0x8EA3C6C3 0x5872 # 0 +0x8EA3C6C4 0x5896 # 0 +0x8EA3C6C5 0x588D # 0 +0x8EA3C6C6 0x5910 # 0 +0x8EA3C6C8 0x596C # 0 +0x8EA3C6CA 0x5AE7 # 0 +0x8EA3C6CC 0x5AE4 # 0 +0x8EA3C6CF 0x5AEF # 0 +0x8EA3C6D0 0x5626 # 0 +0x8EA3C6D3 0x5AF0 # 0 +0x8EA3C6D4 0x5D7B # 0 +0x8EA3C6D6 0x5D83 # 0 +0x8EA3C6D9 0x5D8B # 0 +0x8EA3C6DA 0x5D8C # 0 +0x8EA3C6DC 0x5D78 # 0 +0x8EA3C6DD 0x5E52 # 0 +0x8EA3C6E0 0x5ED0 # 0 +0x8EA3C6E1 0x5ECF # 0 +0x8EA3C6E3 0x5FB3 # 0 +0x8EA3C6E4 0x5FB4 # 0 +0x8EA3C6E8 0x617B # 0 +0x8EA3C6EA 0x616F # 0 +0x8EA3C6EB 0x6181 # 0 +0x8EA3C6EC 0x613C # 0 +0x8EA3C6ED 0x6142 # 0 +0x8EA3C6EE 0x6138 # 0 +0x8EA3C6EF 0x6133 # 0 +0x8EA3C6F1 0x6160 # 0 +0x8EA3C6F2 0x6169 # 0 +0x8EA3C6F3 0x617D # 0 +0x8EA3C6F4 0x6186 # 0 +0x8EA3C6F5 0x622C # 0 +0x8EA3C6F6 0x6228 # 0 +0x8EA3C6F8 0x644C # 0 +0x8EA3C6FA 0x6457 # 0 +0x8EA3C6FB 0x647C # 0 +0x8EA3C6FE 0x6455 # 0 +0x8EA3C7A1 0x6462 # 0 +0x8EA3C7A2 0x6471 # 0 +0x8EA3C7A3 0x646A # 0 +0x8EA3C7A4 0x6456 # 0 +0x8EA3C7A5 0x643B # 0 +0x8EA3C7A6 0x6481 # 0 +0x8EA3C7A8 0x644F # 0 +0x8EA3C7A9 0x647E # 0 +0x8EA3C7AA 0x6464 # 0 +0x8EA3C7B0 0x6571 # 0 +0x8EA3C7B3 0x66A5 # 0 +0x8EA3C7B4 0x669A # 0 +0x8EA3C7B5 0x669C # 0 +0x8EA3C7B7 0x66A6 # 0 +0x8EA3C7B9 0x66A4 # 0 +0x8EA3C7BA 0x698F # 0 +0x8EA3C7BB 0x69C5 # 0 +0x8EA3C7BC 0x69C8 # 0 +0x8EA3C7BD 0x6992 # 0 +0x8EA3C7BE 0x69B2 # 0 +0x8EA3C7C2 0x69E3 # 0 +0x8EA3C7C3 0x69C0 # 0 +0x8EA3C7C4 0x69D6 # 0 +0x8EA3C7C5 0x69D1 # 0 +0x8EA3C7C6 0x699F # 0 +0x8EA3C7C7 0x69A2 # 0 +0x8EA3C7C8 0x69D2 # 0 +0x8EA3C7CC 0x69E1 # 0 +0x8EA3C7CD 0x69D5 # 0 +0x8EA3C7CE 0x699D # 0 +0x8EA3C7D1 0x6998 # 0 +0x8EA3C7D3 0x6B74 # 0 +0x8EA3C7D4 0x6BA1 # 0 +0x8EA3C7D6 0x6EF0 # 0 +0x8EA3C7D7 0x6EF3 # 0 +0x8EA3C7DA 0x6F1B # 0 +0x8EA3C7DB 0x6F0C # 0 +0x8EA3C7DC 0x6F1D # 0 +0x8EA3C7DD 0x6F34 # 0 +0x8EA3C7DE 0x6F28 # 0 +0x8EA3C7DF 0x6F17 # 0 +0x8EA3C7E1 0x6F44 # 0 +0x8EA3C7E2 0x6F42 # 0 +0x8EA3C7E3 0x6F04 # 0 +0x8EA3C7E4 0x6F11 # 0 +0x8EA3C7E5 0x6EFA # 0 +0x8EA3C7E6 0x6F4A # 0 +0x8EA3C7E7 0x7191 # 0 +0x8EA3C7E8 0x718E # 0 +0x8EA3C7EA 0x718B # 0 +0x8EA3C7EB 0x718D # 0 +0x8EA3C7EC 0x717F # 0 +0x8EA3C7ED 0x718C # 0 +0x8EA3C7EE 0x717E # 0 +0x8EA3C7EF 0x717C # 0 +0x8EA3C7F0 0x7183 # 0 +0x8EA3C7F2 0x7188 # 0 +0x8EA3C7F5 0x7294 # 0 +0x8EA3C7F7 0x7355 # 0 +0x8EA3C7F8 0x7353 # 0 +0x8EA3C7F9 0x734F # 0 +0x8EA3C7FA 0x7354 # 0 +0x8EA3C7FB 0x746C # 0 +0x8EA3C7FC 0x7465 # 0 +0x8EA3C7FD 0x7466 # 0 +0x8EA3C7FE 0x7461 # 0 +0x8EA3C8A1 0x746B # 0 +0x8EA3C8A2 0x7468 # 0 +0x8EA3C8A3 0x7476 # 0 +0x8EA3C8A5 0x7460 # 0 +0x8EA3C8A7 0x7474 # 0 +0x8EA3C8A8 0x7506 # 0 +0x8EA3C8A9 0x760E # 0 +0x8EA3C8AB 0x7607 # 0 +0x8EA3C8AE 0x76B9 # 0 +0x8EA3C8B0 0x76B7 # 0 +0x8EA3C8B1 0x76E2 # 0 +0x8EA3C8B3 0x7774 # 0 +0x8EA3C8B4 0x7777 # 0 +0x8EA3C8B5 0x7776 # 0 +0x8EA3C8B6 0x7775 # 0 +0x8EA3C8B8 0x7778 # 0 +0x8EA3C8B9 0x7771 # 0 +0x8EA3C8BB 0x777A # 0 +0x8EA3C8BC 0x715B # 0 +0x8EA3C8BD 0x777B # 0 +0x8EA3C8BE 0x78A6 # 0 +0x8EA3C8BF 0x78AE # 0 +0x8EA3C8C0 0x78B8 # 0 +0x8EA3C8C4 0x78B1 # 0 +0x8EA3C8C5 0x78AF # 0 +0x8EA3C8C7 0x7989 # 0 +0x8EA3C8C8 0x7987 # 0 +0x8EA3C8CB 0x7A29 # 0 +0x8EA3C8CD 0x7A2A # 0 +0x8EA3C8CF 0x7A2D # 0 +0x8EA3C8D0 0x7A2C # 0 +0x8EA3C8D2 0x7A32 # 0 +0x8EA3C8D4 0x7AEC # 0 +0x8EA3C8D5 0x7AF0 # 0 +0x8EA3C8D6 0x7B81 # 0 +0x8EA3C8D7 0x7B9E # 0 +0x8EA3C8D8 0x7B83 # 0 +0x8EA3C8DA 0x7B92 # 0 +0x8EA3C8DC 0x7BA3 # 0 +0x8EA3C8DD 0x7B9F # 0 +0x8EA3C8DE 0x7B93 # 0 +0x8EA3C8E0 0x7B86 # 0 +0x8EA3C8E1 0x7CB8 # 0 +0x8EA3C8E2 0x7CB7 # 0 +0x8EA3C8E8 0x7DC8 # 0 +0x8EA3C8E9 0x7DB6 # 0 +0x8EA3C8EB 0x7DD1 # 0 +0x8EA3C8ED 0x7DA8 # 0 +0x8EA3C8EE 0x7DAB # 0 +0x8EA3C8F0 0x7DB3 # 0 +0x8EA3C8F1 0x7DCD # 0 +0x8EA3C8F3 0x7DCF # 0 +0x8EA3C8F4 0x7DA4 # 0 +0x8EA3C8F7 0x7F41 # 0 +0x8EA3C8F8 0x7F6F # 0 +0x8EA3C8F9 0x7F71 # 0 +0x8EA3C9A2 0x8023 # 0 +0x8EA3C9A3 0x805B # 0 +0x8EA3C9A5 0x8061 # 0 +0x8EA3C9A6 0x805F # 0 +0x8EA3C9A7 0x8181 # 0 +0x8EA3C9AA 0x8184 # 0 +0x8EA3C9AB 0x8213 # 0 +0x8EA3C9AD 0x824A # 0 +0x8EA3C9AE 0x824C # 0 +0x8EA3C9B2 0x84BD # 0 +0x8EA3C9B3 0x8495 # 0 +0x8EA3C9B5 0x8492 # 0 +0x8EA3C9B6 0x84C3 # 0 +0x8EA3C9B8 0x8496 # 0 +0x8EA3C9B9 0x84A5 # 0 +0x8EA3C9BA 0x84B5 # 0 +0x8EA3C9BB 0x84B3 # 0 +0x8EA3C9BC 0x84A3 # 0 +0x8EA3C9BD 0x84E4 # 0 +0x8EA3C9BE 0x84D8 # 0 +0x8EA3C9BF 0x84D5 # 0 +0x8EA3C9C1 0x84B7 # 0 +0x8EA3C9C2 0x84AD # 0 +0x8EA3C9C3 0x84DA # 0 +0x8EA3C9C4 0x8493 # 0 +0x8EA3C9C5 0x8736 # 0 +0x8EA3C9C9 0x873D # 0 +0x8EA3C9CA 0x872B # 0 +0x8EA3C9CB 0x8747 # 0 +0x8EA3C9CC 0x8739 # 0 +0x8EA3C9CE 0x8745 # 0 +0x8EA3C9CF 0x871D # 0 +0x8EA3C9D1 0x88FF # 0 +0x8EA3C9D2 0x88EA # 0 +0x8EA3C9D4 0x88F5 # 0 +0x8EA3C9D6 0x8900 # 0 +0x8EA3C9D7 0x88ED # 0 +0x8EA3C9D8 0x8903 # 0 +0x8EA3C9D9 0x88E9 # 0 +0x8EA3C9DC 0x89EA # 0 +0x8EA3C9DE 0x8A9B # 0 +0x8EA3C9DF 0x8A8E # 0 +0x8EA3C9E0 0x8AA2 # 0 +0x8EA3C9E2 0x8A9C # 0 +0x8EA3C9E3 0x8A94 # 0 +0x8EA3C9E4 0x8A90 # 0 +0x8EA3C9E5 0x8AA9 # 0 +0x8EA3C9E6 0x8AAC # 0 +0x8EA3C9E8 0x8A9F # 0 +0x8EA3C9EB 0x8A9D # 0 +0x8EA3C9ED 0x8C67 # 0 +0x8EA3C9F0 0x8CD0 # 0 +0x8EA3C9F1 0x8CD6 # 0 +0x8EA3C9F2 0x8CD4 # 0 +0x8EA3C9F3 0x8D98 # 0 +0x8EA3C9F4 0x8D9A # 0 +0x8EA3C9F5 0x8D97 # 0 +0x8EA3C9F9 0x8E0B # 0 +0x8EA3C9FA 0x8E08 # 0 +0x8EA3C9FB 0x8E01 # 0 +0x8EA3C9FC 0x8EB4 # 0 +0x8EA3C9FD 0x8EB3 # 0 +0x8EA3CAA1 0x8FA1 # 0 +0x8EA3CAA2 0x8FA2 # 0 +0x8EA3CAA4 0x905A # 0 +0x8EA3CAA6 0x9061 # 0 +0x8EA3CAA7 0x905F # 0 +0x8EA3CAAA 0x9125 # 0 +0x8EA3CAAB 0x917B # 0 +0x8EA3CAAC 0x9176 # 0 +0x8EA3CAAD 0x917C # 0 +0x8EA3CAAF 0x9289 # 0 +0x8EA3CAB0 0x92F6 # 0 +0x8EA3CAB1 0x92B1 # 0 +0x8EA3CAB2 0x92AD # 0 +0x8EA3CAB3 0x9292 # 0 +0x8EA3CAB4 0x9281 # 0 +0x8EA3CAB5 0x9284 # 0 +0x8EA3CAB7 0x92AE # 0 +0x8EA3CAB8 0x9290 # 0 +0x8EA3CAB9 0x929E # 0 +0x8EA3CABD 0x95A2 # 0 +0x8EA3CABE 0x95A7 # 0 +0x8EA3CAC4 0x96A0 # 0 +0x8EA3CAC5 0x969D # 0 +0x8EA3CAC6 0x969F # 0 +0x8EA3CAC7 0x96D0 # 0 +0x8EA3CAC9 0x96D1 # 0 +0x8EA3CACC 0x9759 # 0 +0x8EA3CACE 0x9764 # 0 +0x8EA3CAD2 0x9819 # 0 +0x8EA3CAD4 0x9814 # 0 +0x8EA3CAD5 0x9815 # 0 +0x8EA3CAD6 0x981A # 0 +0x8EA3CADB 0x9906 # 0 +0x8EA3CADD 0x98F8 # 0 +0x8EA3CADE 0x9901 # 0 +0x8EA3CAE0 0x99BE # 0 +0x8EA3CAE1 0x99BC # 0 +0x8EA3CAE2 0x99B7 # 0 +0x8EA3CAE3 0x99B6 # 0 +0x8EA3CAE4 0x99C0 # 0 +0x8EA3CAE6 0x99B8 # 0 +0x8EA3CAEA 0x99C4 # 0 +0x8EA3CAEC 0x99BF # 0 +0x8EA3CAEE 0x9ADA # 0 +0x8EA3CAEF 0x9AE4 # 0 +0x8EA3CAF0 0x9AE9 # 0 +0x8EA3CAF1 0x9AE8 # 0 +0x8EA3CAF2 0x9AEA # 0 +0x8EA3CAF3 0x9AE5 # 0 +0x8EA3CAF5 0x9B26 # 0 +0x8EA3CAF8 0x9B40 # 0 +0x8EA3CBA2 0x9EBD # 0 +0x8EA3CBA7 0x510E # 0 +0x8EA3CBA9 0x50F7 # 0 +0x8EA3CBAB 0x50FC # 0 +0x8EA3CBAC 0x510D # 0 +0x8EA3CBAD 0x5101 # 0 +0x8EA3CBAE 0x51DA # 0 +0x8EA3CBAF 0x51D9 # 0 +0x8EA3CBB0 0x51DB # 0 +0x8EA3CBB1 0x5286 # 0 +0x8EA3CBB2 0x528E # 0 +0x8EA3CBB3 0x52EE # 0 +0x8EA3CBB4 0x5333 # 0 +0x8EA3CBB5 0x53B1 # 0 +0x8EA3CBB7 0x5647 # 0 +0x8EA3CBB8 0x562D # 0 +0x8EA3CBB9 0x5654 # 0 +0x8EA3CBBB 0x564B # 0 +0x8EA3CBBC 0x5652 # 0 +0x8EA3CBBD 0x5631 # 0 +0x8EA3CBBE 0x5644 # 0 +0x8EA3CBBF 0x5656 # 0 +0x8EA3CBC0 0x5650 # 0 +0x8EA3CBC1 0x562B # 0 +0x8EA3CBC3 0x564D # 0 +0x8EA3CBC4 0x5637 # 0 +0x8EA3CBC5 0x564F # 0 +0x8EA3CBC6 0x58A2 # 0 +0x8EA3CBC7 0x58B7 # 0 +0x8EA3CBC9 0x58B2 # 0 +0x8EA3CBCB 0x58AA # 0 +0x8EA3CBCC 0x58B5 # 0 +0x8EA3CBCD 0x58B0 # 0 +0x8EA3CBCF 0x58B4 # 0 +0x8EA3CBD0 0x58A4 # 0 +0x8EA3CBD1 0x58A7 # 0 +0x8EA3CBD3 0x5926 # 0 +0x8EA3CBD4 0x5AFE # 0 +0x8EA3CBD6 0x5B04 # 0 +0x8EA3CBD8 0x5AFC # 0 +0x8EA3CBDA 0x5B06 # 0 +0x8EA3CBDB 0x5B0A # 0 +0x8EA3CBDC 0x5AFA # 0 +0x8EA3CBDD 0x5B0D # 0 +0x8EA3CBDE 0x5B00 # 0 +0x8EA3CBDF 0x5B0E # 0 +0x8EA3CBE3 0x5D91 # 0 +0x8EA3CBE5 0x5D8F # 0 +0x8EA3CBE6 0x5D90 # 0 +0x8EA3CBE7 0x5D98 # 0 +0x8EA3CBE8 0x5DA4 # 0 +0x8EA3CBE9 0x5D9B # 0 +0x8EA3CBEA 0x5DA3 # 0 +0x8EA3CBEB 0x5D96 # 0 +0x8EA3CBEC 0x5DE4 # 0 +0x8EA3CBED 0x5E5A # 0 +0x8EA3CBF0 0x5E5E # 0 +0x8EA3CBF2 0x5FB8 # 0 +0x8EA3CBF3 0x6157 # 0 +0x8EA3CBF4 0x615C # 0 +0x8EA3CBF5 0x61A6 # 0 +0x8EA3CBF6 0x6195 # 0 +0x8EA3CBF7 0x6188 # 0 +0x8EA3CBF9 0x61A3 # 0 +0x8EA3CBFA 0x618F # 0 +0x8EA3CBFC 0x6164 # 0 +0x8EA3CBFE 0x6159 # 0 +0x8EA3CCA1 0x6178 # 0 +0x8EA3CCA3 0x6185 # 0 +0x8EA3CCA4 0x6187 # 0 +0x8EA3CCA5 0x619E # 0 +0x8EA3CCA8 0x6198 # 0 +0x8EA3CCA9 0x619C # 0 +0x8EA3CCAC 0x622F # 0 +0x8EA3CCAD 0x6480 # 0 +0x8EA3CCAE 0x649B # 0 +0x8EA3CCAF 0x648E # 0 +0x8EA3CCB0 0x648D # 0 +0x8EA3CCB1 0x6494 # 0 +0x8EA3CCB2 0x64C6 # 0 +0x8EA3CCB4 0x64A8 # 0 +0x8EA3CCB5 0x6483 # 0 +0x8EA3CCB7 0x64B9 # 0 +0x8EA3CCB8 0x6486 # 0 +0x8EA3CCB9 0x64B4 # 0 +0x8EA3CCBA 0x64AF # 0 +0x8EA3CCBB 0x6491 # 0 +0x8EA3CCBD 0x64AA # 0 +0x8EA3CCBE 0x64A1 # 0 +0x8EA3CCBF 0x64A7 # 0 +0x8EA3CCC0 0x66B6 # 0 +0x8EA3CCC1 0x66B3 # 0 +0x8EA3CCC3 0x66BC # 0 +0x8EA3CCC4 0x66AC # 0 +0x8EA3CCC6 0x66AD # 0 +0x8EA3CCC7 0x6A0E # 0 +0x8EA3CCC9 0x6A1C # 0 +0x8EA3CCCA 0x6A1A # 0 +0x8EA3CCCD 0x6A0B # 0 +0x8EA3CCCF 0x69EF # 0 +0x8EA3CCD0 0x6A0C # 0 +0x8EA3CCD1 0x69F0 # 0 +0x8EA3CCD2 0x6A22 # 0 +0x8EA3CCD4 0x69D8 # 0 +0x8EA3CCD6 0x6A12 # 0 +0x8EA3CCD7 0x69FA # 0 +0x8EA3CCD9 0x6A2A # 0 +0x8EA3CCDB 0x6A10 # 0 +0x8EA3CCDE 0x6A29 # 0 +0x8EA3CCDF 0x69F9 # 0 +0x8EA3CCE0 0x69EA # 0 +0x8EA3CCE1 0x6A2C # 0 +0x8EA3CCE2 0x6A24 # 0 +0x8EA3CCE4 0x69E9 # 0 +0x8EA3CCE5 0x6B52 # 0 +0x8EA3CCE6 0x6B4F # 0 +0x8EA3CCE7 0x6B53 # 0 +0x8EA3CCEA 0x6F10 # 0 +0x8EA3CCEB 0x6F65 # 0 +0x8EA3CCEC 0x6F75 # 0 +0x8EA3CCF1 0x6FD0 # 0 +0x8EA3CCF3 0x6F5C # 0 +0x8EA3CCF4 0x6F3D # 0 +0x8EA3CCF5 0x6F71 # 0 +0x8EA3CCF7 0x6F91 # 0 +0x8EA3CCF8 0x6F0B # 0 +0x8EA3CCF9 0x6F79 # 0 +0x8EA3CCFA 0x6F81 # 0 +0x8EA3CCFB 0x6F8F # 0 +0x8EA3CCFD 0x6F59 # 0 +0x8EA3CCFE 0x6F74 # 0 +0x8EA3CDA2 0x71AE # 0 +0x8EA3CDA4 0x71A3 # 0 +0x8EA3CDA5 0x71AD # 0 +0x8EA3CDA8 0x71AB # 0 +0x8EA3CDA9 0x71A6 # 0 +0x8EA3CDAA 0x71A2 # 0 +0x8EA3CDAC 0x52F2 # 0 +0x8EA3CDAD 0x7257 # 0 +0x8EA3CDAE 0x7255 # 0 +0x8EA3CDAF 0x7299 # 0 +0x8EA3CDB0 0x734B # 0 +0x8EA3CDB1 0x747A # 0 +0x8EA3CDB5 0x748C # 0 +0x8EA3CDB6 0x7484 # 0 +0x8EA3CDB9 0x7482 # 0 +0x8EA3CDBA 0x7493 # 0 +0x8EA3CDBB 0x747B # 0 +0x8EA3CDBD 0x7509 # 0 +0x8EA3CDC4 0x778A # 0 +0x8EA3CDC6 0x7790 # 0 +0x8EA3CDC8 0x78C6 # 0 +0x8EA3CDC9 0x78D3 # 0 +0x8EA3CDCA 0x78C0 # 0 +0x8EA3CDCB 0x78D2 # 0 +0x8EA3CDCC 0x78C7 # 0 +0x8EA3CDCD 0x78C2 # 0 +0x8EA3CDCF 0x799F # 0 +0x8EA3CDD0 0x799D # 0 +0x8EA3CDD1 0x799E # 0 +0x8EA3CDD3 0x7A41 # 0 +0x8EA3CDD5 0x7A38 # 0 +0x8EA3CDD6 0x7A3A # 0 +0x8EA3CDD7 0x7A42 # 0 +0x8EA3CDDA 0x7A3E # 0 +0x8EA3CDDB 0x7AB0 # 0 +0x8EA3CDDC 0x7BAE # 0 +0x8EA3CDDD 0x7BB3 # 0 +0x8EA3CDE0 0x7BBF # 0 +0x8EA3CDE3 0x7BCD # 0 +0x8EA3CDE5 0x7BB2 # 0 +0x8EA3CDED 0x7CC4 # 0 +0x8EA3CDEE 0x7CCD # 0 +0x8EA3CDEF 0x7CC2 # 0 +0x8EA3CDF0 0x7CC6 # 0 +0x8EA3CDF1 0x7CC3 # 0 +0x8EA3CDF2 0x7CC9 # 0 +0x8EA3CDF3 0x7CC7 # 0 +0x8EA3CDF5 0x7DF8 # 0 +0x8EA3CDF7 0x7DED # 0 +0x8EA3CDF8 0x7DE2 # 0 +0x8EA3CDFC 0x7DDC # 0 +0x8EA3CDFD 0x7E02 # 0 +0x8EA3CDFE 0x7E01 # 0 +0x8EA3CEA2 0x7DD6 # 0 +0x8EA3CEA4 0x7DE4 # 0 +0x8EA3CEA5 0x7DFE # 0 +0x8EA3CEA7 0x7E00 # 0 +0x8EA3CEA8 0x7DFC # 0 +0x8EA3CEA9 0x7DFD # 0 +0x8EA3CEAB 0x7DF5 # 0 +0x8EA3CEAC 0x7DFF # 0 +0x8EA3CEAE 0x7DEB # 0 +0x8EA3CEAF 0x7DE5 # 0 +0x8EA3CEB0 0x7F78 # 0 +0x8EA3CEB1 0x7FAE # 0 +0x8EA3CEB2 0x7FE7 # 0 +0x8EA3CEB4 0x8065 # 0 +0x8EA3CEB5 0x806A # 0 +0x8EA3CEB6 0x8066 # 0 +0x8EA3CEB7 0x8068 # 0 +0x8EA3CEB8 0x806B # 0 +0x8EA3CEB9 0x8194 # 0 +0x8EA3CEBA 0x81A1 # 0 +0x8EA3CEBB 0x8192 # 0 +0x8EA3CEBC 0x8196 # 0 +0x8EA3CEBD 0x8193 # 0 +0x8EA3CEC0 0x8501 # 0 +0x8EA3CEC2 0x84F8 # 0 +0x8EA3CEC4 0x84F5 # 0 +0x8EA3CEC6 0x8504 # 0 +0x8EA3CECB 0x851B # 0 +0x8EA3CECC 0x8503 # 0 +0x8EA3CECD 0x8533 # 0 +0x8EA3CECE 0x8534 # 0 +0x8EA3CECF 0x84ED # 0 +0x8EA3CED2 0x8535 # 0 +0x8EA3CED4 0x8505 # 0 +0x8EA3CED9 0x877D # 0 +0x8EA3CEDD 0x8771 # 0 +0x8EA3CEDF 0x885C # 0 +0x8EA3CEE0 0x88E6 # 0 +0x8EA3CEE1 0x890F # 0 +0x8EA3CEE2 0x891B # 0 +0x8EA3CEE4 0x89A9 # 0 +0x8EA3CEE5 0x89A5 # 0 +0x8EA3CEE6 0x89EE # 0 +0x8EA3CEE7 0x8AB1 # 0 +0x8EA3CEE9 0x8ACC # 0 +0x8EA3CEEA 0x8ACE # 0 +0x8EA3CEEC 0x8AB7 # 0 +0x8EA3CEEE 0x8AB5 # 0 +0x8EA3CEEF 0x8AE9 # 0 +0x8EA3CEF0 0x8AB4 # 0 +0x8EA3CEF2 0x8AB3 # 0 +0x8EA3CEF3 0x8AC1 # 0 +0x8EA3CEF4 0x8AAF # 0 +0x8EA3CEF5 0x8ACA # 0 +0x8EA3CEF6 0x8AD0 # 0 +0x8EA3CEFA 0x8C8E # 0 +0x8EA3CEFD 0x8CE9 # 0 +0x8EA3CEFE 0x8CDB # 0 +0x8EA3CFA2 0x8CEB # 0 +0x8EA3CFA3 0x8DA4 # 0 +0x8EA3CFA5 0x8DA2 # 0 +0x8EA3CFA6 0x8D9D # 0 +0x8EA3CFAB 0x8E2A # 0 +0x8EA3CFAC 0x8E28 # 0 +0x8EA3CFAF 0x8EB8 # 0 +0x8EA3CFB0 0x8EB6 # 0 +0x8EA3CFB1 0x8EB9 # 0 +0x8EA3CFB2 0x8EB7 # 0 +0x8EA3CFB3 0x8F22 # 0 +0x8EA3CFB4 0x8F2B # 0 +0x8EA3CFB5 0x8F27 # 0 +0x8EA3CFB6 0x8F19 # 0 +0x8EA3CFB7 0x8FA4 # 0 +0x8EA3CFB9 0x8FB3 # 0 +0x8EA3CFBB 0x9071 # 0 +0x8EA3CFBC 0x906A # 0 +0x8EA3CFBF 0x9188 # 0 +0x8EA3CFC0 0x918C # 0 +0x8EA3CFC1 0x92BF # 0 +0x8EA3CFC2 0x92B8 # 0 +0x8EA3CFC3 0x92BE # 0 +0x8EA3CFC4 0x92DC # 0 +0x8EA3CFC5 0x92E5 # 0 +0x8EA3CFC8 0x92D4 # 0 +0x8EA3CFC9 0x92D6 # 0 +0x8EA3CFCB 0x92DA # 0 +0x8EA3CFCC 0x92ED # 0 +0x8EA3CFCD 0x92F3 # 0 +0x8EA3CFCE 0x92DB # 0 +0x8EA3CFD0 0x92B9 # 0 +0x8EA3CFD1 0x92E2 # 0 +0x8EA3CFD2 0x92EB # 0 +0x8EA3CFD3 0x95AF # 0 +0x8EA3CFD5 0x95B2 # 0 +0x8EA3CFD6 0x95B3 # 0 +0x8EA3CFDA 0x96A3 # 0 +0x8EA3CFDB 0x96A5 # 0 +0x8EA3CFE0 0x970A # 0 +0x8EA3CFE2 0x9787 # 0 +0x8EA3CFE3 0x9789 # 0 +0x8EA3CFE4 0x978C # 0 +0x8EA3CFE5 0x97EF # 0 +0x8EA3CFE6 0x982A # 0 +0x8EA3CFE7 0x9822 # 0 +0x8EA3CFE9 0x981F # 0 +0x8EA3CFEB 0x9919 # 0 +0x8EA3CFED 0x99CA # 0 +0x8EA3CFEE 0x99DA # 0 +0x8EA3CFF2 0x99DE # 0 +0x8EA3CFF3 0x99C8 # 0 +0x8EA3CFF4 0x99E0 # 0 +0x8EA3CFF6 0x9AB6 # 0 +0x8EA3CFF7 0x9AB5 # 0 +0x8EA3CFF9 0x9AF4 # 0 +0x8EA3CFFB 0x9B6B # 0 +0x8EA3CFFC 0x9B69 # 0 +0x8EA3CFFD 0x9B72 # 0 +0x8EA3CFFE 0x9B63 # 0 +0x8EA3D0A2 0x9D0D # 0 +0x8EA3D0A4 0x9D01 # 0 +0x8EA3D0A5 0x9D0C # 0 +0x8EA3D0A7 0x9CF8 # 0 +0x8EA3D0AA 0x9CFE # 0 +0x8EA3D0AB 0x9D02 # 0 +0x8EA3D0AC 0x9E84 # 0 +0x8EA3D0AE 0x9EAB # 0 +0x8EA3D0AF 0x9EAA # 0 +0x8EA3D0B0 0x511D # 0 +0x8EA3D0B1 0x5116 # 0 +0x8EA3D0B3 0x512B # 0 +0x8EA3D0B4 0x511E # 0 +0x8EA3D0B5 0x511B # 0 +0x8EA3D0B6 0x5290 # 0 +0x8EA3D0B7 0x5294 # 0 +0x8EA3D0B8 0x5314 # 0 +0x8EA3D0BB 0x5667 # 0 +0x8EA3D0BD 0x567B # 0 +0x8EA3D0BF 0x565F # 0 +0x8EA3D0C0 0x5661 # 0 +0x8EA3D0C8 0x58C3 # 0 +0x8EA3D0C9 0x58CA # 0 +0x8EA3D0CA 0x58BB # 0 +0x8EA3D0CB 0x58C0 # 0 +0x8EA3D0CC 0x58C4 # 0 +0x8EA3D0CD 0x5901 # 0 +0x8EA3D0CE 0x5B1F # 0 +0x8EA3D0CF 0x5B18 # 0 +0x8EA3D0D0 0x5B11 # 0 +0x8EA3D0D1 0x5B15 # 0 +0x8EA3D0D3 0x5B12 # 0 +0x8EA3D0D4 0x5B1C # 0 +0x8EA3D0D6 0x5B22 # 0 +0x8EA3D0D7 0x5B79 # 0 +0x8EA3D0D8 0x5DA6 # 0 +0x8EA3D0DA 0x5DB3 # 0 +0x8EA3D0DB 0x5DAB # 0 +0x8EA3D0DC 0x5EEA # 0 +0x8EA3D0DE 0x5F5B # 0 +0x8EA3D0E1 0x61B7 # 0 +0x8EA3D0E2 0x61CE # 0 +0x8EA3D0E3 0x61B9 # 0 +0x8EA3D0E4 0x61BD # 0 +0x8EA3D0E5 0x61CF # 0 +0x8EA3D0E6 0x61C0 # 0 +0x8EA3D0E7 0x6199 # 0 +0x8EA3D0E8 0x6197 # 0 +0x8EA3D0EA 0x61BB # 0 +0x8EA3D0EB 0x61D0 # 0 +0x8EA3D0EC 0x61C4 # 0 +0x8EA3D0ED 0x6231 # 0 +0x8EA3D0EF 0x64D3 # 0 +0x8EA3D0F0 0x64C0 # 0 +0x8EA3D0F5 0x64DC # 0 +0x8EA3D0F6 0x64D1 # 0 +0x8EA3D0F7 0x64C8 # 0 +0x8EA3D0F9 0x64D5 # 0 +0x8EA3D0FA 0x66C3 # 0 +0x8EA3D0FD 0x66BF # 0 +0x8EA3D0FE 0x66C5 # 0 +0x8EA3D1A2 0x66CD # 0 +0x8EA3D1A3 0x66C1 # 0 +0x8EA3D1A4 0x6706 # 0 +0x8EA3D1A6 0x6724 # 0 +0x8EA3D1A7 0x6A63 # 0 +0x8EA3D1A8 0x6A42 # 0 +0x8EA3D1A9 0x6A52 # 0 +0x8EA3D1AB 0x6A43 # 0 +0x8EA3D1AC 0x6A33 # 0 +0x8EA3D1AE 0x6A6C # 0 +0x8EA3D1AF 0x6A57 # 0 +0x8EA3D1B1 0x6A4C # 0 +0x8EA3D1B2 0x6A6E # 0 +0x8EA3D1B8 0x6A37 # 0 +0x8EA3D1BA 0x6A71 # 0 +0x8EA3D1BB 0x6A4A # 0 +0x8EA3D1BC 0x6A36 # 0 +0x8EA3D1BE 0x6A53 # 0 +0x8EA3D1C0 0x6A45 # 0 +0x8EA3D1C1 0x6A70 # 0 +0x8EA3D1C4 0x6A5C # 0 +0x8EA3D1C5 0x6B58 # 0 +0x8EA3D1C6 0x6B57 # 0 +0x8EA3D1CD 0x6FBB # 0 +0x8EA3D1D0 0x6FBE # 0 +0x8EA3D1D4 0x6FB5 # 0 +0x8EA3D1D5 0x6FD3 # 0 +0x8EA3D1D6 0x6F9F # 0 +0x8EA3D1D8 0x6FB7 # 0 +0x8EA3D1D9 0x6FF5 # 0 +0x8EA3D1DA 0x71B7 # 0 +0x8EA3D1DC 0x71BB # 0 +0x8EA3D1DE 0x71D1 # 0 +0x8EA3D1E0 0x71BA # 0 +0x8EA3D1E2 0x71B6 # 0 +0x8EA3D1E3 0x71CC # 0 +0x8EA3D1E6 0x71D3 # 0 +0x8EA3D1E7 0x749B # 0 +0x8EA3D1EA 0x7496 # 0 +0x8EA3D1EB 0x74A2 # 0 +0x8EA3D1EC 0x749D # 0 +0x8EA3D1ED 0x750A # 0 +0x8EA3D1EE 0x750E # 0 +0x8EA3D1F0 0x7581 # 0 +0x8EA3D1F1 0x762C # 0 +0x8EA3D1F2 0x7637 # 0 +0x8EA3D1F3 0x7636 # 0 +0x8EA3D1F4 0x763B # 0 +0x8EA3D1F6 0x76A1 # 0 +0x8EA3D1F9 0x7798 # 0 +0x8EA3D1FB 0x7796 # 0 +0x8EA3D2A1 0x78D6 # 0 +0x8EA3D2A2 0x78EB # 0 +0x8EA3D2A4 0x78DC # 0 +0x8EA3D2A6 0x79A5 # 0 +0x8EA3D2A7 0x79A9 # 0 +0x8EA3D2A8 0x9834 # 0 +0x8EA3D2A9 0x7A53 # 0 +0x8EA3D2AA 0x7A45 # 0 +0x8EA3D2AC 0x7A4F # 0 +0x8EA3D2AE 0x7ABD # 0 +0x8EA3D2AF 0x7ABB # 0 +0x8EA3D2B0 0x7AF1 # 0 +0x8EA3D2B3 0x7BEC # 0 +0x8EA3D2B4 0x7BED # 0 +0x8EA3D2B7 0x7CD3 # 0 +0x8EA3D2B9 0x7CE1 # 0 +0x8EA3D2BB 0x7E19 # 0 +0x8EA3D2BF 0x7E27 # 0 +0x8EA3D2C0 0x7E26 # 0 +0x8EA3D2C3 0x806E # 0 +0x8EA3D2C4 0x81AF # 0 +0x8EA3D2C7 0x81AD # 0 +0x8EA3D2C9 0x81AA # 0 +0x8EA3D2CA 0x8218 # 0 +0x8EA3D2CF 0x856F # 0 +0x8EA3D2D0 0x854C # 0 +0x8EA3D2D2 0x8542 # 0 +0x8EA3D2D4 0x855C # 0 +0x8EA3D2D5 0x8570 # 0 +0x8EA3D2D6 0x855F # 0 +0x8EA3D2D8 0x855A # 0 +0x8EA3D2D9 0x854B # 0 +0x8EA3D2DA 0x853F # 0 +0x8EA3D2DB 0x878A # 0 +0x8EA3D2DD 0x878B # 0 +0x8EA3D2DE 0x87A1 # 0 +0x8EA3D2DF 0x878E # 0 +0x8EA3D2E2 0x8799 # 0 +0x8EA3D2E3 0x885E # 0 +0x8EA3D2E4 0x885F # 0 +0x8EA3D2E5 0x8924 # 0 +0x8EA3D2E6 0x89A7 # 0 +0x8EA3D2E7 0x8AEA # 0 +0x8EA3D2E8 0x8AFD # 0 +0x8EA3D2E9 0x8AF9 # 0 +0x8EA3D2EA 0x8AE3 # 0 +0x8EA3D2EB 0x8AE5 # 0 +0x8EA3D2EE 0x8AEC # 0 +0x8EA3D2F3 0x8CF2 # 0 +0x8EA3D2F5 0x8CEF # 0 +0x8EA3D2F7 0x8DA6 # 0 +0x8EA3D2FB 0x8E3B # 0 +0x8EA3D2FC 0x8E43 # 0 +0x8EA3D2FE 0x8E32 # 0 +0x8EA3D3A1 0x8F31 # 0 +0x8EA3D3A2 0x8F30 # 0 +0x8EA3D3A4 0x8F2D # 0 +0x8EA3D3A5 0x8F3C # 0 +0x8EA3D3A6 0x8FA7 # 0 +0x8EA3D3A7 0x8FA5 # 0 +0x8EA3D3AB 0x9137 # 0 +0x8EA3D3AC 0x9195 # 0 +0x8EA3D3AD 0x918E # 0 +0x8EA3D3AF 0x9196 # 0 +0x8EA3D3B1 0x9345 # 0 +0x8EA3D3B2 0x930A # 0 +0x8EA3D3B5 0x92FD # 0 +0x8EA3D3B6 0x9317 # 0 +0x8EA3D3B7 0x931C # 0 +0x8EA3D3B8 0x9307 # 0 +0x8EA3D3B9 0x9331 # 0 +0x8EA3D3BA 0x9332 # 0 +0x8EA3D3BB 0x932C # 0 +0x8EA3D3BC 0x9330 # 0 +0x8EA3D3BD 0x9303 # 0 +0x8EA3D3BE 0x9305 # 0 +0x8EA3D3C0 0x95C2 # 0 +0x8EA3D3C2 0x95B8 # 0 +0x8EA3D3C4 0x95C1 # 0 +0x8EA3D3C8 0x96AB # 0 +0x8EA3D3C9 0x96B7 # 0 +0x8EA3D3CC 0x9715 # 0 +0x8EA3D3CD 0x9714 # 0 +0x8EA3D3D0 0x970C # 0 +0x8EA3D3D1 0x9717 # 0 +0x8EA3D3D3 0x9793 # 0 +0x8EA3D3D5 0x97D2 # 0 +0x8EA3D3D8 0x9836 # 0 +0x8EA3D3D9 0x9831 # 0 +0x8EA3D3DA 0x9833 # 0 +0x8EA3D3DB 0x983C # 0 +0x8EA3D3DC 0x982E # 0 +0x8EA3D3DD 0x983A # 0 +0x8EA3D3DF 0x983D # 0 +0x8EA3D3E1 0x98B5 # 0 +0x8EA3D3E2 0x9922 # 0 +0x8EA3D3E3 0x9923 # 0 +0x8EA3D3E4 0x9920 # 0 +0x8EA3D3E5 0x991C # 0 +0x8EA3D3E6 0x991D # 0 +0x8EA3D3E8 0x99A0 # 0 +0x8EA3D3EA 0x99EF # 0 +0x8EA3D3EB 0x99E8 # 0 +0x8EA3D3EC 0x99EB # 0 +0x8EA3D3F0 0x99E1 # 0 +0x8EA3D3F1 0x99E6 # 0 +0x8EA3D3F4 0x9AF8 # 0 +0x8EA3D3F5 0x9AF5 # 0 +0x8EA3D3F8 0x9B83 # 0 +0x8EA3D3F9 0x9B94 # 0 +0x8EA3D3FA 0x9B84 # 0 +0x8EA3D3FC 0x9B8B # 0 +0x8EA3D3FD 0x9B8F # 0 +0x8EA3D4A1 0x9B8C # 0 +0x8EA3D4A3 0x9B89 # 0 +0x8EA3D4A5 0x9B8E # 0 +0x8EA3D4A9 0x9D24 # 0 +0x8EA3D4AA 0x9D0F # 0 +0x8EA3D4AC 0x9D13 # 0 +0x8EA3D4AD 0x9D0A # 0 +0x8EA3D4B2 0x9D2A # 0 +0x8EA3D4B3 0x9D1A # 0 +0x8EA3D4B5 0x9D27 # 0 +0x8EA3D4B6 0x9D16 # 0 +0x8EA3D4B7 0x9D21 # 0 +0x8EA3D4B9 0x9E85 # 0 +0x8EA3D4BA 0x9EAC # 0 +0x8EA3D4BB 0x9EC6 # 0 +0x8EA3D4BC 0x9EC5 # 0 +0x8EA3D4BD 0x9ED7 # 0 +0x8EA3D4BE 0x9F53 # 0 +0x8EA3D4C0 0x5128 # 0 +0x8EA3D4C1 0x5127 # 0 +0x8EA3D4C2 0x51DF # 0 +0x8EA3D4C4 0x5335 # 0 +0x8EA3D4C5 0x53B3 # 0 +0x8EA3D4C7 0x568A # 0 +0x8EA3D4C8 0x567D # 0 +0x8EA3D4C9 0x5689 # 0 +0x8EA3D4CB 0x58CD # 0 +0x8EA3D4CC 0x58D0 # 0 +0x8EA3D4CE 0x5B2B # 0 +0x8EA3D4CF 0x5B33 # 0 +0x8EA3D4D0 0x5B29 # 0 +0x8EA3D4D1 0x5B35 # 0 +0x8EA3D4D2 0x5B31 # 0 +0x8EA3D4D3 0x5B37 # 0 +0x8EA3D4D4 0x5C36 # 0 +0x8EA3D4D5 0x5DBE # 0 +0x8EA3D4D7 0x5DB9 # 0 +0x8EA3D4D9 0x5DBB # 0 +0x8EA3D4DB 0x61E2 # 0 +0x8EA3D4DC 0x61DB # 0 +0x8EA3D4DD 0x61DD # 0 +0x8EA3D4DE 0x61DC # 0 +0x8EA3D4DF 0x61DA # 0 +0x8EA3D4E1 0x61D9 # 0 +0x8EA3D4E4 0x64DF # 0 +0x8EA3D4E7 0x64E1 # 0 +0x8EA3D4E9 0x64EE # 0 +0x8EA3D4EB 0x65B5 # 0 +0x8EA3D4EC 0x66D4 # 0 +0x8EA3D4ED 0x66D5 # 0 +0x8EA3D4EF 0x66D0 # 0 +0x8EA3D4F0 0x66D1 # 0 +0x8EA3D4F1 0x66CE # 0 +0x8EA3D4F2 0x66D7 # 0 +0x8EA3D4F5 0x6A7D # 0 +0x8EA3D4F6 0x6A8A # 0 +0x8EA3D4F8 0x6AA7 # 0 +0x8EA3D4FA 0x6A99 # 0 +0x8EA3D4FB 0x6A82 # 0 +0x8EA3D4FC 0x6A88 # 0 +0x8EA3D5A1 0x6A86 # 0 +0x8EA3D5A3 0x6A98 # 0 +0x8EA3D5A4 0x6A9D # 0 +0x8EA3D5A7 0x6A8F # 0 +0x8EA3D5A9 0x6AAA # 0 +0x8EA3D5AB 0x6B5D # 0 +0x8EA3D5AD 0x6C0A # 0 +0x8EA3D5AF 0x6FD7 # 0 +0x8EA3D5B0 0x6FD6 # 0 +0x8EA3D5B1 0x6FE5 # 0 +0x8EA3D5B5 0x6FD9 # 0 +0x8EA3D5B6 0x6FDA # 0 +0x8EA3D5B7 0x6FEA # 0 +0x8EA3D5B9 0x6FF6 # 0 +0x8EA3D5BC 0x71E3 # 0 +0x8EA3D5BE 0x71E9 # 0 +0x8EA3D5C0 0x71EB # 0 +0x8EA3D5C1 0x71EF # 0 +0x8EA3D5C2 0x71F3 # 0 +0x8EA3D5C3 0x71EA # 0 +0x8EA3D5C9 0x7371 # 0 +0x8EA3D5CB 0x74AE # 0 +0x8EA3D5CD 0x74B3 # 0 +0x8EA3D5CF 0x74AC # 0 +0x8EA3D5D2 0x7583 # 0 +0x8EA3D5D3 0x7645 # 0 +0x8EA3D5D4 0x764E # 0 +0x8EA3D5D5 0x7644 # 0 +0x8EA3D5D6 0x76A3 # 0 +0x8EA3D5D7 0x76A5 # 0 +0x8EA3D5D8 0x77A6 # 0 +0x8EA3D5D9 0x77A4 # 0 +0x8EA3D5DB 0x77A9 # 0 +0x8EA3D5DC 0x77AF # 0 +0x8EA3D5E0 0x78F0 # 0 +0x8EA3D5E1 0x78F8 # 0 +0x8EA3D5E2 0x78F1 # 0 +0x8EA3D5E4 0x7A49 # 0 +0x8EA3D5E8 0x7AC2 # 0 +0x8EA3D5E9 0x7AF2 # 0 +0x8EA3D5EA 0x7AF3 # 0 +0x8EA3D5EB 0x7BFA # 0 +0x8EA3D5ED 0x7BF6 # 0 +0x8EA3D5EE 0x7BFC # 0 +0x8EA3D5EF 0x7C18 # 0 +0x8EA3D5F0 0x7C08 # 0 +0x8EA3D5F1 0x7C12 # 0 +0x8EA3D5F4 0x7CDB # 0 +0x8EA3D5F5 0x7CDA # 0 +0x8EA3D5F9 0x7E2C # 0 +0x8EA3D5FA 0x7E4D # 0 +0x8EA3D5FD 0x7F46 # 0 +0x8EA3D5FE 0x7FF6 # 0 +0x8EA3D6A1 0x802B # 0 +0x8EA3D6A2 0x8074 # 0 +0x8EA3D6A3 0x81B8 # 0 +0x8EA3D6A4 0x81C8 # 0 +0x8EA3D6A8 0x8592 # 0 +0x8EA3D6A9 0x8593 # 0 +0x8EA3D6AB 0x857F # 0 +0x8EA3D6AC 0x85AB # 0 +0x8EA3D6AD 0x8597 # 0 +0x8EA3D6B0 0x85AC # 0 +0x8EA3D6B4 0x87CE # 0 +0x8EA3D6B6 0x87CD # 0 +0x8EA3D6B9 0x87C1 # 0 +0x8EA3D6BA 0x87B1 # 0 +0x8EA3D6BB 0x87C7 # 0 +0x8EA3D6BD 0x8940 # 0 +0x8EA3D6BF 0x893F # 0 +0x8EA3D6C0 0x8939 # 0 +0x8EA3D6C2 0x8943 # 0 +0x8EA3D6C6 0x89AB # 0 +0x8EA3D6C8 0x8B1F # 0 +0x8EA3D6C9 0x8B09 # 0 +0x8EA3D6CA 0x8B0C # 0 +0x8EA3D6CD 0x8C40 # 0 +0x8EA3D6CF 0x8C96 # 0 +0x8EA3D6D1 0x8CF6 # 0 +0x8EA3D6D2 0x8CF7 # 0 +0x8EA3D6D4 0x8E46 # 0 +0x8EA3D6D5 0x8E4F # 0 +0x8EA3D6D9 0x8F3D # 0 +0x8EA3D6DA 0x8F41 # 0 +0x8EA3D6DB 0x9366 # 0 +0x8EA3D6DC 0x9378 # 0 +0x8EA3D6DD 0x935D # 0 +0x8EA3D6DE 0x9369 # 0 +0x8EA3D6DF 0x9374 # 0 +0x8EA3D6E0 0x937D # 0 +0x8EA3D6E1 0x936E # 0 +0x8EA3D6E2 0x9372 # 0 +0x8EA3D6E3 0x9373 # 0 +0x8EA3D6E4 0x9362 # 0 +0x8EA3D6E5 0x9348 # 0 +0x8EA3D6E6 0x9353 # 0 +0x8EA3D6E7 0x935F # 0 +0x8EA3D6E8 0x9368 # 0 +0x8EA3D6EA 0x937F # 0 +0x8EA3D6EB 0x936B # 0 +0x8EA3D6ED 0x95C4 # 0 +0x8EA3D6EF 0x96AF # 0 +0x8EA3D6F0 0x96AD # 0 +0x8EA3D6F1 0x96B2 # 0 +0x8EA3D6F4 0x971A # 0 +0x8EA3D6F5 0x971B # 0 +0x8EA3D6FA 0x979B # 0 +0x8EA3D6FB 0x979F # 0 +0x8EA3D7A6 0x9840 # 0 +0x8EA3D7A8 0x9847 # 0 +0x8EA3D7AA 0x98B7 # 0 +0x8EA3D7B0 0x99A2 # 0 +0x8EA3D7B3 0x9A00 # 0 +0x8EA3D7B4 0x99F3 # 0 +0x8EA3D7B7 0x99F5 # 0 +0x8EA3D7BA 0x9ABD # 0 +0x8EA3D7BB 0x9B00 # 0 +0x8EA3D7BC 0x9B02 # 0 +0x8EA3D7BE 0x9B34 # 0 +0x8EA3D7BF 0x9B49 # 0 +0x8EA3D7C0 0x9B9F # 0 +0x8EA3D7C2 0x9BA3 # 0 +0x8EA3D7C3 0x9BCD # 0 +0x8EA3D7C4 0x9B99 # 0 +0x8EA3D7C5 0x9B9D # 0 +0x8EA3D7C8 0x9D39 # 0 +0x8EA3D7CA 0x9D44 # 0 +0x8EA3D7CD 0x9D35 # 0 +0x8EA3D7D0 0x9EAF # 0 +0x8EA3D7D2 0x512F # 0 +0x8EA3D7D5 0x9F8E # 0 +0x8EA3D7D7 0x569F # 0 +0x8EA3D7D8 0x569B # 0 +0x8EA3D7D9 0x569E # 0 +0x8EA3D7DA 0x5696 # 0 +0x8EA3D7DB 0x5694 # 0 +0x8EA3D7DC 0x56A0 # 0 +0x8EA3D7DE 0x5B3B # 0 +0x8EA3D7E1 0x5B3A # 0 +0x8EA3D7E2 0x5DC1 # 0 +0x8EA3D7E3 0x5F4D # 0 +0x8EA3D7E4 0x5F5D # 0 +0x8EA3D7E5 0x61F3 # 0 +0x8EA3D7EA 0x64F6 # 0 +0x8EA3D7EB 0x64E5 # 0 +0x8EA3D7EC 0x64EA # 0 +0x8EA3D7ED 0x64E7 # 0 +0x8EA3D7EE 0x6505 # 0 +0x8EA3D7F0 0x64F9 # 0 +0x8EA3D7F4 0x6AAB # 0 +0x8EA3D7F5 0x6AED # 0 +0x8EA3D7F6 0x6AB2 # 0 +0x8EA3D7F7 0x6AB0 # 0 +0x8EA3D7F8 0x6AB5 # 0 +0x8EA3D7F9 0x6ABE # 0 +0x8EA3D7FA 0x6AC1 # 0 +0x8EA3D7FB 0x6AC8 # 0 +0x8EA3D7FD 0x6AC0 # 0 +0x8EA3D7FE 0x6ABC # 0 +0x8EA3D8A1 0x6AB1 # 0 +0x8EA3D8A2 0x6AC4 # 0 +0x8EA3D8A3 0x6ABF # 0 +0x8EA3D8A6 0x7008 # 0 +0x8EA3D8A7 0x7003 # 0 +0x8EA3D8A8 0x6FFD # 0 +0x8EA3D8A9 0x7010 # 0 +0x8EA3D8AA 0x7002 # 0 +0x8EA3D8AB 0x7013 # 0 +0x8EA3D8AD 0x71FA # 0 +0x8EA3D8AE 0x7200 # 0 +0x8EA3D8AF 0x74B9 # 0 +0x8EA3D8B0 0x74BC # 0 +0x8EA3D8B2 0x765B # 0 +0x8EA3D8B3 0x7651 # 0 +0x8EA3D8B4 0x764F # 0 +0x8EA3D8B5 0x76EB # 0 +0x8EA3D8B6 0x77B8 # 0 +0x8EA3D8B8 0x77B9 # 0 +0x8EA3D8B9 0x77C1 # 0 +0x8EA3D8BA 0x77C0 # 0 +0x8EA3D8BB 0x77BE # 0 +0x8EA3D8BC 0x790B # 0 +0x8EA3D8BE 0x7907 # 0 +0x8EA3D8BF 0x790A # 0 +0x8EA3D8C0 0x7908 # 0 +0x8EA3D8C2 0x790D # 0 +0x8EA3D8C3 0x7906 # 0 +0x8EA3D8C4 0x7915 # 0 +0x8EA3D8C5 0x79AF # 0 +0x8EA3D8C9 0x7AF5 # 0 +0x8EA3D8CC 0x7C2E # 0 +0x8EA3D8CE 0x7C1B # 0 +0x8EA3D8D0 0x7C1A # 0 +0x8EA3D8D1 0x7C24 # 0 +0x8EA3D8D4 0x7CE6 # 0 +0x8EA3D8D5 0x7CE3 # 0 +0x8EA3D8D8 0x7E5D # 0 +0x8EA3D8D9 0x7E4F # 0 +0x8EA3D8DA 0x7E66 # 0 +0x8EA3D8DB 0x7E5B # 0 +0x8EA3D8DC 0x7F47 # 0 +0x8EA3D8DD 0x7FB4 # 0 +0x8EA3D8E1 0x7FFA # 0 +0x8EA3D8E2 0x802E # 0 +0x8EA3D8E5 0x81CE # 0 +0x8EA3D8E8 0x8219 # 0 +0x8EA3D8EB 0x85CC # 0 +0x8EA3D8EC 0x85B2 # 0 +0x8EA3D8EE 0x85BB # 0 +0x8EA3D8EF 0x85C1 # 0 +0x8EA3D8F3 0x87E9 # 0 +0x8EA3D8F4 0x87EE # 0 +0x8EA3D8F5 0x87F0 # 0 +0x8EA3D8F6 0x87D6 # 0 +0x8EA3D8F7 0x880E # 0 +0x8EA3D8F8 0x87DA # 0 +0x8EA3D8F9 0x8948 # 0 +0x8EA3D8FA 0x894A # 0 +0x8EA3D8FB 0x894E # 0 +0x8EA3D8FC 0x894D # 0 +0x8EA3D8FD 0x89B1 # 0 +0x8EA3D8FE 0x89B0 # 0 +0x8EA3D9A1 0x89B3 # 0 +0x8EA3D9A3 0x8B38 # 0 +0x8EA3D9A4 0x8B32 # 0 +0x8EA3D9A6 0x8B2D # 0 +0x8EA3D9A8 0x8B34 # 0 +0x8EA3D9AA 0x8B29 # 0 +0x8EA3D9AB 0x8C74 # 0 +0x8EA3D9AE 0x8D03 # 0 +0x8EA3D9B1 0x8DA9 # 0 +0x8EA3D9B2 0x8E58 # 0 +0x8EA3D9B5 0x8EBF # 0 +0x8EA3D9B6 0x8EC1 # 0 +0x8EA3D9B7 0x8F4A # 0 +0x8EA3D9B8 0x8FAC # 0 +0x8EA3D9BA 0x9089 # 0 +0x8EA3D9BB 0x913D # 0 +0x8EA3D9BC 0x913C # 0 +0x8EA3D9BD 0x91A9 # 0 +0x8EA3D9BE 0x93A0 # 0 +0x8EA3D9C0 0x9390 # 0 +0x8EA3D9C2 0x9393 # 0 +0x8EA3D9C3 0x938B # 0 +0x8EA3D9C4 0x93AD # 0 +0x8EA3D9C5 0x93BB # 0 +0x8EA3D9C6 0x93B8 # 0 +0x8EA3D9C9 0x939C # 0 +0x8EA3D9CA 0x95D8 # 0 +0x8EA3D9CB 0x95D7 # 0 +0x8EA3D9CF 0x975D # 0 +0x8EA3D9D0 0x97A9 # 0 +0x8EA3D9D1 0x97DA # 0 +0x8EA3D9D6 0x9854 # 0 +0x8EA3D9D8 0x9855 # 0 +0x8EA3D9D9 0x984B # 0 +0x8EA3D9DB 0x983F # 0 +0x8EA3D9DC 0x98B9 # 0 +0x8EA3D9E1 0x9938 # 0 +0x8EA3D9E2 0x9936 # 0 +0x8EA3D9E3 0x9940 # 0 +0x8EA3D9E5 0x993B # 0 +0x8EA3D9E6 0x9939 # 0 +0x8EA3D9E7 0x99A4 # 0 +0x8EA3D9EA 0x9A08 # 0 +0x8EA3D9EB 0x9A0C # 0 +0x8EA3D9ED 0x9A10 # 0 +0x8EA3D9EF 0x9B07 # 0 +0x8EA3D9F1 0x9BD2 # 0 +0x8EA3D9F3 0x9BC2 # 0 +0x8EA3D9F4 0x9BBB # 0 +0x8EA3D9F5 0x9BCC # 0 +0x8EA3D9F6 0x9BCB # 0 +0x8EA3D9F9 0x9D4D # 0 +0x8EA3D9FA 0x9D63 # 0 +0x8EA3D9FB 0x9D4E # 0 +0x8EA3D9FD 0x9D50 # 0 +0x8EA3D9FE 0x9D55 # 0 +0x8EA3DAA2 0x9D5E # 0 +0x8EA3DAA4 0x9E90 # 0 +0x8EA3DAA5 0x9EB2 # 0 +0x8EA3DAA6 0x9EB1 # 0 +0x8EA3DAA8 0x9ECA # 0 +0x8EA3DAA9 0x9F02 # 0 +0x8EA3DAAA 0x9F27 # 0 +0x8EA3DAAB 0x9F26 # 0 +0x8EA3DAAD 0x56AF # 0 +0x8EA3DAAE 0x58E0 # 0 +0x8EA3DAAF 0x58DC # 0 +0x8EA3DAB1 0x5B39 # 0 +0x8EA3DAB4 0x5B7C # 0 +0x8EA3DAB5 0x5BF3 # 0 +0x8EA3DAB8 0x5C6B # 0 +0x8EA3DAB9 0x5DC4 # 0 +0x8EA3DABA 0x650B # 0 +0x8EA3DABB 0x6508 # 0 +0x8EA3DABC 0x650A # 0 +0x8EA3DABF 0x65DC # 0 +0x8EA3DAC2 0x66E1 # 0 +0x8EA3DAC3 0x66DF # 0 +0x8EA3DAC4 0x6ACE # 0 +0x8EA3DAC5 0x6AD4 # 0 +0x8EA3DAC6 0x6AE3 # 0 +0x8EA3DAC7 0x6AD7 # 0 +0x8EA3DAC8 0x6AE2 # 0 +0x8EA3DACD 0x6AD8 # 0 +0x8EA3DACE 0x6AD5 # 0 +0x8EA3DACF 0x6AD2 # 0 +0x8EA3DAD2 0x701E # 0 +0x8EA3DAD3 0x702C # 0 +0x8EA3DAD4 0x7025 # 0 +0x8EA3DAD5 0x6FF3 # 0 +0x8EA3DAD6 0x7204 # 0 +0x8EA3DAD7 0x7208 # 0 +0x8EA3DAD8 0x7215 # 0 +0x8EA3DADA 0x74C4 # 0 +0x8EA3DADB 0x74C9 # 0 +0x8EA3DADC 0x74C7 # 0 +0x8EA3DADD 0x74C8 # 0 +0x8EA3DADE 0x76A9 # 0 +0x8EA3DADF 0x77C6 # 0 +0x8EA3DAE0 0x77C5 # 0 +0x8EA3DAE1 0x7918 # 0 +0x8EA3DAE2 0x791A # 0 +0x8EA3DAE3 0x7920 # 0 +0x8EA3DAE5 0x7A66 # 0 +0x8EA3DAE6 0x7A64 # 0 +0x8EA3DAE7 0x7A6A # 0 +0x8EA3DAEE 0x7C35 # 0 +0x8EA3DAEF 0x7C34 # 0 +0x8EA3DAF2 0x7E6C # 0 +0x8EA3DAF4 0x7E6E # 0 +0x8EA3DAF5 0x7E71 # 0 +0x8EA3DAF7 0x81D4 # 0 +0x8EA3DAF8 0x81D6 # 0 +0x8EA3DAF9 0x821A # 0 +0x8EA3DAFA 0x8262 # 0 +0x8EA3DAFB 0x8265 # 0 +0x8EA3DAFC 0x8276 # 0 +0x8EA3DAFD 0x85DB # 0 +0x8EA3DAFE 0x85D6 # 0 +0x8EA3DBA2 0x85E7 # 0 +0x8EA3DBA5 0x85F4 # 0 +0x8EA3DBA7 0x87FD # 0 +0x8EA3DBA8 0x87D5 # 0 +0x8EA3DBA9 0x8807 # 0 +0x8EA3DBAB 0x880F # 0 +0x8EA3DBAC 0x87F8 # 0 +0x8EA3DBAF 0x8987 # 0 +0x8EA3DBB1 0x89B5 # 0 +0x8EA3DBB2 0x89F5 # 0 +0x8EA3DBB4 0x8B3F # 0 +0x8EA3DBB5 0x8B43 # 0 +0x8EA3DBB6 0x8B4C # 0 +0x8EA3DBB8 0x8D0B # 0 +0x8EA3DBB9 0x8E6B # 0 +0x8EA3DBBA 0x8E68 # 0 +0x8EA3DBBB 0x8E70 # 0 +0x8EA3DBBC 0x8E75 # 0 +0x8EA3DBBD 0x8E77 # 0 +0x8EA3DBBF 0x8EC3 # 0 +0x8EA3DBC1 0x93E9 # 0 +0x8EA3DBC2 0x93EA # 0 +0x8EA3DBC3 0x93CB # 0 +0x8EA3DBC4 0x93C5 # 0 +0x8EA3DBC5 0x93C6 # 0 +0x8EA3DBC7 0x93ED # 0 +0x8EA3DBC8 0x93D3 # 0 +0x8EA3DBCA 0x93E5 # 0 +0x8EA3DBCD 0x93DB # 0 +0x8EA3DBCE 0x93EB # 0 +0x8EA3DBCF 0x93E0 # 0 +0x8EA3DBD0 0x93C1 # 0 +0x8EA3DBD3 0x95DD # 0 +0x8EA3DBDD 0x97B2 # 0 +0x8EA3DBDE 0x97B4 # 0 +0x8EA3DBDF 0x97B1 # 0 +0x8EA3DBE0 0x97B5 # 0 +0x8EA3DBE1 0x97F2 # 0 +0x8EA3DBE5 0x9856 # 0 +0x8EA3DBE9 0x9944 # 0 +0x8EA3DBEB 0x9A26 # 0 +0x8EA3DBEC 0x9A1F # 0 +0x8EA3DBED 0x9A18 # 0 +0x8EA3DBEE 0x9A21 # 0 +0x8EA3DBEF 0x9A17 # 0 +0x8EA3DBF1 0x9B09 # 0 +0x8EA3DBF4 0x9BC5 # 0 +0x8EA3DBF5 0x9BDF # 0 +0x8EA3DBF7 0x9BE3 # 0 +0x8EA3DBF9 0x9BE9 # 0 +0x8EA3DBFA 0x9BEE # 0 +0x8EA3DBFD 0x9D66 # 0 +0x8EA3DBFE 0x9D7A # 0 +0x8EA3DCA2 0x9D6E # 0 +0x8EA3DCA3 0x9D91 # 0 +0x8EA3DCA4 0x9D83 # 0 +0x8EA3DCA5 0x9D76 # 0 +0x8EA3DCA6 0x9D7E # 0 +0x8EA3DCA7 0x9D6D # 0 +0x8EA3DCA9 0x9E95 # 0 +0x8EA3DCAA 0x9EE3 # 0 +0x8EA3DCAD 0x9F03 # 0 +0x8EA3DCAE 0x9F04 # 0 +0x8EA3DCB0 0x9F17 # 0 +0x8EA3DCB2 0x5136 # 0 +0x8EA3DCB4 0x5336 # 0 +0x8EA3DCB6 0x5B42 # 0 +0x8EA3DCB9 0x5B44 # 0 +0x8EA3DCBA 0x5B46 # 0 +0x8EA3DCBB 0x5B7E # 0 +0x8EA3DCBC 0x5DCA # 0 +0x8EA3DCBD 0x5DC8 # 0 +0x8EA3DCBE 0x5DCC # 0 +0x8EA3DCBF 0x5EF0 # 0 +0x8EA3DCC1 0x6585 # 0 +0x8EA3DCC2 0x66E5 # 0 +0x8EA3DCC3 0x66E7 # 0 +0x8EA3DCC7 0x6AF4 # 0 +0x8EA3DCC9 0x6AE9 # 0 +0x8EA3DCCF 0x703D # 0 +0x8EA3DCD1 0x7036 # 0 +0x8EA3DCD3 0x7216 # 0 +0x8EA3DCD5 0x7212 # 0 +0x8EA3DCD6 0x720F # 0 +0x8EA3DCD7 0x7217 # 0 +0x8EA3DCD8 0x7211 # 0 +0x8EA3DCD9 0x720B # 0 +0x8EA3DCDC 0x74CD # 0 +0x8EA3DCDD 0x74D0 # 0 +0x8EA3DCDE 0x74CC # 0 +0x8EA3DCDF 0x74CE # 0 +0x8EA3DCE0 0x74D1 # 0 +0x8EA3DCE2 0x7589 # 0 +0x8EA3DCE4 0x7A6F # 0 +0x8EA3DCE5 0x7C4B # 0 +0x8EA3DCE6 0x7C44 # 0 +0x8EA3DCEC 0x7E7F # 0 +0x8EA3DCED 0x8B71 # 0 +0x8EA3DCEF 0x802F # 0 +0x8EA3DCF0 0x807A # 0 +0x8EA3DCF1 0x807B # 0 +0x8EA3DCF2 0x807C # 0 +0x8EA3DCF6 0x85FC # 0 +0x8EA3DCF7 0x8610 # 0 +0x8EA3DCF8 0x8602 # 0 +0x8EA3DCFB 0x85EE # 0 +0x8EA3DCFC 0x8603 # 0 +0x8EA3DCFE 0x860D # 0 +0x8EA3DDA1 0x8613 # 0 +0x8EA3DDA2 0x8608 # 0 +0x8EA3DDA3 0x860F # 0 +0x8EA3DDA4 0x8818 # 0 +0x8EA3DDA5 0x8812 # 0 +0x8EA3DDA8 0x8967 # 0 +0x8EA3DDA9 0x8965 # 0 +0x8EA3DDAA 0x89BB # 0 +0x8EA3DDAB 0x8B69 # 0 +0x8EA3DDAC 0x8B62 # 0 +0x8EA3DDAE 0x8B6E # 0 +0x8EA3DDB0 0x8B61 # 0 +0x8EA3DDB2 0x8B64 # 0 +0x8EA3DDB3 0x8B4D # 0 +0x8EA3DDB4 0x8C51 # 0 +0x8EA3DDB7 0x8E83 # 0 +0x8EA3DDB8 0x8EC6 # 0 +0x8EA3DDBA 0x941F # 0 +0x8EA3DDBC 0x9404 # 0 +0x8EA3DDBD 0x9417 # 0 +0x8EA3DDBE 0x9408 # 0 +0x8EA3DDBF 0x9405 # 0 +0x8EA3DDC1 0x93F3 # 0 +0x8EA3DDC2 0x941E # 0 +0x8EA3DDC3 0x9402 # 0 +0x8EA3DDC4 0x941A # 0 +0x8EA3DDC5 0x941B # 0 +0x8EA3DDC6 0x9427 # 0 +0x8EA3DDC7 0x941C # 0 +0x8EA3DDC9 0x96B5 # 0 +0x8EA3DDCC 0x9733 # 0 +0x8EA3DDCE 0x9734 # 0 +0x8EA3DDCF 0x9731 # 0 +0x8EA3DDD0 0x97B8 # 0 +0x8EA3DDD1 0x97BA # 0 +0x8EA3DDD3 0x97FC # 0 +0x8EA3DDD6 0x98C3 # 0 +0x8EA3DDD8 0x994D # 0 +0x8EA3DDDA 0x9A2F # 0 +0x8EA3DDDE 0x9AC9 # 0 +0x8EA3DDE0 0x9AC8 # 0 +0x8EA3DDE1 0x9AC4 # 0 +0x8EA3DDE2 0x9B2A # 0 +0x8EA3DDE3 0x9B38 # 0 +0x8EA3DDE4 0x9B50 # 0 +0x8EA3DDE6 0x9C0A # 0 +0x8EA3DDE7 0x9BFB # 0 +0x8EA3DDE8 0x9C04 # 0 +0x8EA3DDE9 0x9BFC # 0 +0x8EA3DDEA 0x9BFE # 0 +0x8EA3DDEE 0x9C02 # 0 +0x8EA3DDEF 0x9BF6 # 0 +0x8EA3DDF0 0x9C1B # 0 +0x8EA3DDF1 0x9BF9 # 0 +0x8EA3DDF2 0x9C15 # 0 +0x8EA3DDF3 0x9C10 # 0 +0x8EA3DDF4 0x9BFF # 0 +0x8EA3DDF5 0x9C00 # 0 +0x8EA3DDF6 0x9C0C # 0 +0x8EA3DDF9 0x9D95 # 0 +0x8EA3DDFA 0x9DA5 # 0 +0x8EA3DEA1 0x9E98 # 0 +0x8EA3DEA2 0x9EC1 # 0 +0x8EA3DEA4 0x9F5A # 0 +0x8EA3DEA5 0x5164 # 0 +0x8EA3DEA6 0x56BB # 0 +0x8EA3DEA8 0x58E6 # 0 +0x8EA3DEA9 0x5B49 # 0 +0x8EA3DEAA 0x5BF7 # 0 +0x8EA3DEAD 0x5DD0 # 0 +0x8EA3DEAF 0x5FC2 # 0 +0x8EA3DEB1 0x6511 # 0 +0x8EA3DEB3 0x6AFF # 0 +0x8EA3DEB4 0x6AFE # 0 +0x8EA3DEB5 0x6AFD # 0 +0x8EA3DEB7 0x6B01 # 0 +0x8EA3DEBA 0x704B # 0 +0x8EA3DEBB 0x704D # 0 +0x8EA3DEBC 0x7047 # 0 +0x8EA3DEBD 0x74D3 # 0 +0x8EA3DEBE 0x7668 # 0 +0x8EA3DEBF 0x7667 # 0 +0x8EA3DEC2 0x77D1 # 0 +0x8EA3DEC3 0x7930 # 0 +0x8EA3DEC4 0x7932 # 0 +0x8EA3DEC5 0x792E # 0 +0x8EA3DEC7 0x9F9D # 0 +0x8EA3DEC8 0x7AC9 # 0 +0x8EA3DEC9 0x7AC8 # 0 +0x8EA3DECB 0x7C56 # 0 +0x8EA3DECC 0x7C51 # 0 +0x8EA3DED0 0x7E85 # 0 +0x8EA3DED1 0x7E89 # 0 +0x8EA3DED2 0x7E8E # 0 +0x8EA3DED3 0x7E84 # 0 +0x8EA3DED5 0x826A # 0 +0x8EA3DED6 0x862B # 0 +0x8EA3DED7 0x862F # 0 +0x8EA3DED8 0x8628 # 0 +0x8EA3DEDA 0x8616 # 0 +0x8EA3DEDB 0x8615 # 0 +0x8EA3DEDC 0x861D # 0 +0x8EA3DEDD 0x881A # 0 +0x8EA3DEE1 0x89BC # 0 +0x8EA3DEE2 0x8B75 # 0 +0x8EA3DEE3 0x8B7C # 0 +0x8EA3DEE5 0x8D11 # 0 +0x8EA3DEE6 0x8D12 # 0 +0x8EA3DEE7 0x8F5C # 0 +0x8EA3DEE8 0x91BB # 0 +0x8EA3DEEA 0x93F4 # 0 +0x8EA3DEED 0x942D # 0 +0x8EA3DEF0 0x96E4 # 0 +0x8EA3DEF1 0x9737 # 0 +0x8EA3DEF2 0x9736 # 0 +0x8EA3DEF3 0x9767 # 0 +0x8EA3DEF4 0x97BE # 0 +0x8EA3DEF5 0x97BD # 0 +0x8EA3DEF6 0x97E2 # 0 +0x8EA3DEF7 0x9868 # 0 +0x8EA3DEF8 0x9866 # 0 +0x8EA3DEF9 0x98C8 # 0 +0x8EA3DEFA 0x98CA # 0 +0x8EA3DEFB 0x98C7 # 0 +0x8EA3DEFC 0x98DC # 0 +0x8EA3DEFE 0x994F # 0 +0x8EA3DFA1 0x99A9 # 0 +0x8EA3DFA2 0x9A3C # 0 +0x8EA3DFA4 0x9A3B # 0 +0x8EA3DFA5 0x9ACE # 0 +0x8EA3DFA7 0x9B14 # 0 +0x8EA3DFA8 0x9B53 # 0 +0x8EA3DFAA 0x9C2E # 0 +0x8EA3DFAC 0x9C1F # 0 +0x8EA3DFB1 0x9DB0 # 0 +0x8EA3DFB2 0x9DBD # 0 +0x8EA3DFB5 0x9DAE # 0 +0x8EA3DFB6 0x9DC4 # 0 +0x8EA3DFB7 0x9E7B # 0 +0x8EA3DFBA 0x9E9E # 0 +0x8EA3DFBC 0x9F05 # 0 +0x8EA3DFBE 0x9F69 # 0 +0x8EA3DFBF 0x9FA1 # 0 +0x8EA3DFC0 0x56C7 # 0 +0x8EA3DFC1 0x571D # 0 +0x8EA3DFC2 0x5B4A # 0 +0x8EA3DFC3 0x5DD3 # 0 +0x8EA3DFC5 0x5F72 # 0 +0x8EA3DFC6 0x6202 # 0 +0x8EA3DFC8 0x6235 # 0 +0x8EA3DFC9 0x6527 # 0 +0x8EA3DFCA 0x651E # 0 +0x8EA3DFCB 0x651F # 0 +0x8EA3DFCE 0x6B07 # 0 +0x8EA3DFCF 0x6B06 # 0 +0x8EA3DFD2 0x7054 # 0 +0x8EA3DFD3 0x721C # 0 +0x8EA3DFD4 0x7220 # 0 +0x8EA3DFD5 0x7AF8 # 0 +0x8EA3DFD7 0x7C5D # 0 +0x8EA3DFD8 0x7C58 # 0 +0x8EA3DFDA 0x7E92 # 0 +0x8EA3DFDB 0x7F4E # 0 +0x8EA3DFDF 0x8827 # 0 +0x8EA3DFE1 0x8B81 # 0 +0x8EA3DFE2 0x8B83 # 0 +0x8EA3DFE4 0x8C44 # 0 +0x8EA3DFE9 0x9442 # 0 +0x8EA3DFEA 0x944D # 0 +0x8EA3DFEB 0x9454 # 0 +0x8EA3DFEC 0x944E # 0 +0x8EA3DFEE 0x9443 # 0 +0x8EA3DFF1 0x973C # 0 +0x8EA3DFF2 0x9740 # 0 +0x8EA3DFF3 0x97C0 # 0 +0x8EA3DFF8 0x995A # 0 +0x8EA3DFF9 0x9A51 # 0 +0x8EA3DFFB 0x9ADD # 0 +0x8EA3DFFE 0x9C38 # 0 +0x8EA3E0A2 0x9C45 # 0 +0x8EA3E0A3 0x9C3A # 0 +0x8EA3E0A5 0x9C35 # 0 +0x8EA3E0A9 0x9EF1 # 0 +0x8EA3E0AB 0x9F93 # 0 +0x8EA3E0AC 0x529A # 0 +0x8EA3E0AF 0x8641 # 0 +0x8EA3E0B0 0x5DD7 # 0 +0x8EA3E0B2 0x6528 # 0 +0x8EA3E0B6 0x7053 # 0 +0x8EA3E0B7 0x7059 # 0 +0x8EA3E0B9 0x7221 # 0 +0x8EA3E0BB 0x766F # 0 +0x8EA3E0BC 0x7937 # 0 +0x8EA3E0BD 0x79B5 # 0 +0x8EA3E0BE 0x7C62 # 0 +0x8EA3E0BF 0x7C5E # 0 +0x8EA3E0C0 0x7CF5 # 0 +0x8EA3E0C3 0x863D # 0 +0x8EA3E0C5 0x882D # 0 +0x8EA3E0C6 0x8989 # 0 +0x8EA3E0C7 0x8B8D # 0 +0x8EA3E0C8 0x8B87 # 0 +0x8EA3E0C9 0x8B90 # 0 +0x8EA3E0CA 0x8D1A # 0 +0x8EA3E0CB 0x8E99 # 0 +0x8EA3E0CF 0x945F # 0 +0x8EA3E0D2 0x9456 # 0 +0x8EA3E0D3 0x9461 # 0 +0x8EA3E0D4 0x945B # 0 +0x8EA3E0D5 0x945A # 0 +0x8EA3E0D6 0x945C # 0 +0x8EA3E0D7 0x9465 # 0 +0x8EA3E0D9 0x9741 # 0 +0x8EA3E0DC 0x986E # 0 +0x8EA3E0DD 0x986C # 0 +0x8EA3E0DE 0x986D # 0 +0x8EA3E0E0 0x99AA # 0 +0x8EA3E0E1 0x9A5C # 0 +0x8EA3E0E2 0x9A58 # 0 +0x8EA3E0E3 0x9ADE # 0 +0x8EA3E0E5 0x9C4F # 0 +0x8EA3E0E6 0x9C51 # 0 +0x8EA3E0E8 0x9C53 # 0 +0x8EA3E0EC 0x9DFC # 0 +0x8EA3E0ED 0x9F39 # 0 +0x8EA3E0EF 0x513E # 0 +0x8EA3E0F1 0x56D2 # 0 +0x8EA3E0F3 0x5B4F # 0 +0x8EA3E0F4 0x6B14 # 0 +0x8EA3E0F6 0x7A72 # 0 +0x8EA3E0F7 0x7A73 # 0 +0x8EA3E0FB 0x8B91 # 0 +0x8EA3E0FE 0x91BF # 0 +0x8EA3E1A2 0x946C # 0 +0x8EA3E1A5 0x96E6 # 0 +0x8EA3E1A6 0x9745 # 0 +0x8EA3E1A8 0x97C8 # 0 +0x8EA3E1A9 0x97E4 # 0 +0x8EA3E1AA 0x995D # 0 +0x8EA3E1AC 0x9B21 # 0 +0x8EA3E1AE 0x9B2C # 0 +0x8EA3E1AF 0x9B57 # 0 +0x8EA3E1B2 0x9C5D # 0 +0x8EA3E1B3 0x9C61 # 0 +0x8EA3E1B4 0x9C65 # 0 +0x8EA3E1B5 0x9E08 # 0 +0x8EA3E1BB 0x9F45 # 0 +0x8EA3E1BE 0x6205 # 0 +0x8EA3E1BF 0x66EF # 0 +0x8EA3E1C0 0x6B1B # 0 +0x8EA3E1C1 0x6B1D # 0 +0x8EA3E1C2 0x7225 # 0 +0x8EA3E1C3 0x7224 # 0 +0x8EA3E1C4 0x7C6D # 0 +0x8EA3E1C6 0x8642 # 0 +0x8EA3E1C7 0x8649 # 0 +0x8EA3E1C9 0x8978 # 0 +0x8EA3E1CA 0x898A # 0 +0x8EA3E1CB 0x8B97 # 0 +0x8EA3E1CD 0x8C9B # 0 +0x8EA3E1CE 0x8D1C # 0 +0x8EA3E1D0 0x8EA2 # 0 +0x8EA3E1D9 0x9C6C # 0 +0x8EA3E1DB 0x9C6F # 0 +0x8EA3E1DD 0x9E0E # 0 +0x8EA3E1DF 0x9F08 # 0 +0x8EA3E1E0 0x9F1D # 0 +0x8EA3E1E1 0x9FA3 # 0 +0x8EA3E1E4 0x5F60 # 0 +0x8EA3E1E5 0x6B1C # 0 +0x8EA3E1E9 0x7CF3 # 0 +0x8EA3E1EB 0x8B9B # 0 +0x8EA3E1EC 0x8EA7 # 0 +0x8EA3E1ED 0x91C4 # 0 +0x8EA3E1EF 0x947A # 0 +0x8EA3E1F2 0x9A61 # 0 +0x8EA3E1F3 0x9A63 # 0 +0x8EA3E1F4 0x9AD7 # 0 +0x8EA3E1F5 0x9C76 # 0 +0x8EA3E1F7 0x9FA5 # 0 +0x8EA3E1F9 0x7067 # 0 +0x8EA3E1FB 0x72AB # 0 +0x8EA3E1FC 0x864A # 0 +0x8EA3E1FD 0x897D # 0 +0x8EA3E1FE 0x8B9D # 0 +0x8EA3E2A1 0x8C53 # 0 +0x8EA3E2A2 0x8F65 # 0 +0x8EA3E2A3 0x947B # 0 +0x8EA3E2A5 0x98CD # 0 +0x8EA3E2A6 0x98DD # 0 +0x8EA3E2A8 0x9B30 # 0 +0x8EA3E2A9 0x9E16 # 0 +0x8EA3E2AF 0x96E7 # 0 +0x8EA3E2B0 0x9E18 # 0 +0x8EA3E2B1 0x9EA2 # 0 +0x8EA3E2B3 0x9F7C # 0 +0x8EA3E2B5 0x7E9E # 0 +0x8EA3E2B6 0x9484 # 0 +0x8EA3E2B8 0x9E1C # 0 +0x8EA3E2BA 0x7C71 # 0 +0x8EA3E2BB 0x97CA # 0 +0x8EA3E2BF 0x9EA3 # 0 +0x8EA3E2C1 0x9C7B # 0 +0x8EA3E2C2 0x9F97 # 0 +0x8EA3E2C5 0x9750 # 0 +0x8EA3E2C9 0x5727 # 0 +0x8EA3E2CA 0x5C13 # 0 +0x8EA3E2D1 0x5FC8 # 0 +0x8EA3E2D7 0x6765 # 0 +0x8EA3E2DA 0x52BD # 0 +0x8EA3E2DC 0x5B66 # 0 +0x8EA3E2DE 0x65F9 # 0 +0x8EA3E2DF 0x6788 # 0 +0x8EA3E2E0 0x6CE6 # 0 +0x8EA3E2E1 0x6CCB # 0 +0x8EA3E2E3 0x4FBD # 0 +0x8EA3E2E4 0x5F8D # 0 +0x8EA3E2E6 0x6018 # 0 +0x8EA3E2E7 0x6048 # 0 +0x8EA3E2E9 0x6B29 # 0 +0x8EA3E2EA 0x70A6 # 0 +0x8EA3E2EC 0x7706 # 0 +0x8EA3E2F0 0x5A10 # 0 +0x8EA3E2F1 0x5CFC # 0 +0x8EA3E2F2 0x5CFE # 0 +0x8EA3E2F9 0x70C9 # 0 +0x8EA3E3A3 0x9579 # 0 +0x8EA3E3A5 0x96BA # 0 +0x8EA3E3AD 0x7B29 # 0 +0x8EA3E3AE 0x8128 # 0 +0x8EA3E3B0 0x8A2E # 0 +0x8EA3E3B4 0x9AD9 # 0 +0x8EA3E3B6 0x582B # 0 +0x8EA3E3B7 0x5845 # 0 +0x8EA3E3B9 0x63FA # 0 +0x8EA3E3BD 0x6E86 # 0 +0x8EA3E3C3 0x5867 # 0 +0x8EA3E3C5 0x5BDD # 0 +0x8EA3E3C6 0x656E # 0 +0x8EA3E3CA 0x8C87 # 0 +0x8EA3E3CC 0x50D2 # 0 +0x8EA3E3CD 0x50DF # 0 +0x8EA3E3D2 0x69BA # 0 +0x8EA3E3D4 0x6B9D # 0 +0x8EA3E3D6 0x8059 # 0 +0x8EA3E3E3 0x6F8A # 0 +0x8EA3E3E6 0x7BC3 # 0 +0x8EA3E3E7 0x7BC2 # 0 +0x8EA3E3EC 0x90F6 # 0 +0x8EA3E3EE 0x9823 # 0 +0x8EA3E3F4 0x71CD # 0 +0x8EA3E3F5 0x7499 # 0 +0x8EA3E3FB 0x9842 # 0 +0x8EA3E4A2 0x7F84 # 0 +0x8EA3E4A8 0x8D0E # 0 +0x8EA3E4AA 0x9861 # 0 +0x8EA3E4AD 0x8B73 # 0 +0x8EA3E4AF 0x9C27 # 0 +0x8EA3E4B1 0x9458 # 0 +0x8EA3E4B2 0x77D6 # 0 +0x8EA3E4B3 0x9B2D # 0 +0x8EA3E4C8 0x4F66 # 0 +0x8EA3E4C9 0x4F68 # 0 +0x8EA3E4CA 0x4FE7 # 0 +0x8EA3E4CB 0x503F # 0 +0x8EA3E4CD 0x50A6 # 0 +0x8EA3E4CE 0x510F # 0 +0x8EA3E4CF 0x523E # 0 +0x8EA3E4D0 0x5324 # 0 +0x8EA3E4D1 0x5365 # 0 +0x8EA3E4D2 0x539B # 0 +0x8EA3E4D3 0x517F # 0 +0x8EA3E4D4 0x54CB # 0 +0x8EA3E4D5 0x5573 # 0 +0x8EA3E4D6 0x5571 # 0 +0x8EA3E4D7 0x556B # 0 +0x8EA3E4D8 0x55F4 # 0 +0x8EA3E4D9 0x5622 # 0 +0x8EA3E4DA 0x5620 # 0 +0x8EA3E4DB 0x5692 # 0 +0x8EA3E4DC 0x56BA # 0 +0x8EA3E4DD 0x5691 # 0 +0x8EA3E4DE 0x56B0 # 0 +0x8EA3E4DF 0x5759 # 0 +0x8EA3E4E0 0x578A # 0 +0x8EA3E4E1 0x580F # 0 +0x8EA3E4E2 0x5812 # 0 +0x8EA3E4E3 0x5813 # 0 +0x8EA3E4E4 0x5847 # 0 +0x8EA3E4E5 0x589B # 0 +0x8EA3E4E6 0x5900 # 0 +0x8EA3E4E7 0x594D # 0 +0x8EA3E4E8 0x5AD1 # 0 +0x8EA3E4E9 0x5AD3 # 0 +0x8EA3E4EA 0x5B67 # 0 +0x8EA3E4EB 0x5C57 # 0 +0x8EA3E4EC 0x5C77 # 0 +0x8EA3E4ED 0x5CD5 # 0 +0x8EA3E4EE 0x5D75 # 0 +0x8EA3E4EF 0x5D8E # 0 +0x8EA3E4F0 0x5DA5 # 0 +0x8EA3E4F1 0x5DB6 # 0 +0x8EA3E4F2 0x5DBF # 0 +0x8EA3E4F3 0x5E65 # 0 +0x8EA3E4F4 0x5ECD # 0 +0x8EA3E4F5 0x5EED # 0 +0x8EA3E4F6 0x5F94 # 0 +0x8EA3E4F7 0x5F9A # 0 +0x8EA3E4F8 0x5FBA # 0 +0x8EA3E4F9 0x6125 # 0 +0x8EA3E4FA 0x6150 # 0 +0x8EA3E4FB 0x62A3 # 0 +0x8EA3E4FC 0x6360 # 0 +0x8EA3E4FD 0x6364 # 0 +0x8EA3E4FE 0x63B6 # 0 +0x8EA3E5A1 0x6403 # 0 +0x8EA3E5A2 0x64B6 # 0 +0x8EA3E5A3 0x651A # 0 +0x8EA3E5A4 0x7A25 # 0 +0x8EA3E5A5 0x5C21 # 0 +0x8EA3E5A6 0x66E2 # 0 +0x8EA3E5A7 0x6702 # 0 +0x8EA3E5A8 0x67A4 # 0 +0x8EA3E5A9 0x67AC # 0 +0x8EA3E5AA 0x6810 # 0 +0x8EA3E5AB 0x6806 # 0 +0x8EA3E5AC 0x685E # 0 +0x8EA3E5AD 0x685A # 0 +0x8EA3E5AE 0x692C # 0 +0x8EA3E5AF 0x6929 # 0 +0x8EA3E5B0 0x6A2D # 0 +0x8EA3E5B1 0x6A77 # 0 +0x8EA3E5B2 0x6A7A # 0 +0x8EA3E5B3 0x6ACA # 0 +0x8EA3E5B4 0x6AE6 # 0 +0x8EA3E5B5 0x6AF5 # 0 +0x8EA3E5B6 0x6B0D # 0 +0x8EA3E5B7 0x6B0E # 0 +0x8EA3E5B8 0x6BDC # 0 +0x8EA3E5B9 0x6BDD # 0 +0x8EA3E5BA 0x6BF6 # 0 +0x8EA3E5BB 0x6C1E # 0 +0x8EA3E5BC 0x6C63 # 0 +0x8EA3E5BD 0x6DA5 # 0 +0x8EA3E5BE 0x6E0F # 0 +0x8EA3E5BF 0x6E8A # 0 +0x8EA3E5C0 0x6E84 # 0 +0x8EA3E5C1 0x6E8B # 0 +0x8EA3E5C2 0x6E7C # 0 +0x8EA3E5C3 0x6F4C # 0 +0x8EA3E5C4 0x6F48 # 0 +0x8EA3E5C5 0x6F49 # 0 +0x8EA3E5C6 0x6F9D # 0 +0x8EA3E5C7 0x6F99 # 0 +0x8EA3E5C8 0x6FF8 # 0 +0x8EA3E5C9 0x702E # 0 +0x8EA3E5CA 0x702D # 0 +0x8EA3E5CB 0x705C # 0 +0x8EA3E5CC 0x79CC # 0 +0x8EA3E5CD 0x70BF # 0 +0x8EA3E5CE 0x70EA # 0 +0x8EA3E5CF 0x70E5 # 0 +0x8EA3E5D0 0x7111 # 0 +0x8EA3E5D1 0x7112 # 0 +0x8EA3E5D2 0x713F # 0 +0x8EA3E5D3 0x7139 # 0 +0x8EA3E5D4 0x713B # 0 +0x8EA3E5D5 0x713D # 0 +0x8EA3E5D6 0x7177 # 0 +0x8EA3E5D7 0x7175 # 0 +0x8EA3E5D8 0x7176 # 0 +0x8EA3E5D9 0x7171 # 0 +0x8EA3E5DA 0x7196 # 0 +0x8EA3E5DB 0x7193 # 0 +0x8EA3E5DC 0x71B4 # 0 +0x8EA3E5DD 0x71DD # 0 +0x8EA3E5DE 0x71DE # 0 +0x8EA3E5DF 0x720E # 0 +0x8EA3E5E0 0x5911 # 0 +0x8EA3E5E1 0x7218 # 0 +0x8EA3E5E2 0x7347 # 0 +0x8EA3E5E3 0x7348 # 0 +0x8EA3E5E4 0x73EF # 0 +0x8EA3E5E5 0x7412 # 0 +0x8EA3E5E6 0x743B # 0 +0x8EA3E5E7 0x74A4 # 0 +0x8EA3E5E8 0x748D # 0 +0x8EA3E5E9 0x74B4 # 0 +0x8EA3E5EA 0x7673 # 0 +0x8EA3E5EB 0x7677 # 0 +0x8EA3E5EC 0x76BC # 0 +0x8EA3E5ED 0x7819 # 0 +0x8EA3E5EE 0x781B # 0 +0x8EA3E5EF 0x783D # 0 +0x8EA3E5F0 0x7853 # 0 +0x8EA3E5F1 0x7854 # 0 +0x8EA3E5F2 0x7858 # 0 +0x8EA3E5F3 0x78B7 # 0 +0x8EA3E5F4 0x78D8 # 0 +0x8EA3E5F5 0x78EE # 0 +0x8EA3E5F6 0x7922 # 0 +0x8EA3E5F7 0x794D # 0 +0x8EA3E5F8 0x7986 # 0 +0x8EA3E5F9 0x7999 # 0 +0x8EA3E5FA 0x79A3 # 0 +0x8EA3E5FB 0x79BC # 0 +0x8EA3E5FC 0x7AA7 # 0 +0x8EA3E5FD 0x7B37 # 0 +0x8EA3E5FE 0x7B59 # 0 +0x8EA3E6A1 0x7BD0 # 0 +0x8EA3E6A2 0x7C2F # 0 +0x8EA3E6A3 0x7C32 # 0 +0x8EA3E6A4 0x7C42 # 0 +0x8EA3E6A5 0x7C4E # 0 +0x8EA3E6A6 0x7C68 # 0 +0x8EA3E6A7 0x7CA9 # 0 +0x8EA3E6A8 0x7CED # 0 +0x8EA3E6A9 0x7DD0 # 0 +0x8EA3E6AA 0x7E07 # 0 +0x8EA3E6AB 0x7DD3 # 0 +0x8EA3E6AC 0x7E64 # 0 +0x8EA3E6AD 0x7F40 # 0 +0x8EA3E6AF 0x8041 # 0 +0x8EA3E6B0 0x8063 # 0 +0x8EA3E6B1 0x80BB # 0 +0x8EA3E6B2 0x6711 # 0 +0x8EA3E6B3 0x6725 # 0 +0x8EA3E6B4 0x8248 # 0 +0x8EA3E6B5 0x8310 # 0 +0x8EA3E6B6 0x8362 # 0 +0x8EA3E6B7 0x8312 # 0 +0x8EA3E6B8 0x8421 # 0 +0x8EA3E6B9 0x841E # 0 +0x8EA3E6BA 0x84E2 # 0 +0x8EA3E6BB 0x84DE # 0 +0x8EA3E6BC 0x84E1 # 0 +0x8EA3E6BD 0x8573 # 0 +0x8EA3E6BE 0x85D4 # 0 +0x8EA3E6BF 0x85F5 # 0 +0x8EA3E6C0 0x8637 # 0 +0x8EA3E6C1 0x8645 # 0 +0x8EA3E6C2 0x8672 # 0 +0x8EA3E6C3 0x874A # 0 +0x8EA3E6C4 0x87A9 # 0 +0x8EA3E6C5 0x87A5 # 0 +0x8EA3E6C6 0x87F5 # 0 +0x8EA3E6C7 0x8834 # 0 +0x8EA3E6C8 0x8850 # 0 +0x8EA3E6C9 0x8887 # 0 +0x8EA3E6CA 0x8954 # 0 +0x8EA3E6CB 0x8984 # 0 +0x8EA3E6CC 0x8B03 # 0 +0x8EA3E6CD 0x8C52 # 0 +0x8EA3E6CE 0x8CD8 # 0 +0x8EA3E6CF 0x8D0C # 0 +0x8EA3E6D0 0x8D18 # 0 +0x8EA3E6D1 0x8DB0 # 0 +0x8EA3E6D2 0x8EBC # 0 +0x8EA3E6D3 0x8ED5 # 0 +0x8EA3E6D4 0x8FAA # 0 +0x8EA3E6D5 0x909C # 0 +0x8EA3E6D7 0x915C # 0 +0x8EA3E6D8 0x922B # 0 +0x8EA3E6D9 0x9221 # 0 +0x8EA3E6DA 0x9273 # 0 +0x8EA3E6DB 0x92F4 # 0 +0x8EA3E6DC 0x92F5 # 0 +0x8EA3E6DD 0x933F # 0 +0x8EA3E6DE 0x9342 # 0 +0x8EA3E6DF 0x9386 # 0 +0x8EA3E6E0 0x93BE # 0 +0x8EA3E6E1 0x93BC # 0 +0x8EA3E6E2 0x93BD # 0 +0x8EA3E6E3 0x93F1 # 0 +0x8EA3E6E4 0x93F2 # 0 +0x8EA3E6E5 0x93EF # 0 +0x8EA3E6E6 0x9422 # 0 +0x8EA3E6E7 0x9423 # 0 +0x8EA3E6E8 0x9424 # 0 +0x8EA3E6E9 0x9467 # 0 +0x8EA3E6EA 0x9466 # 0 +0x8EA3E6EB 0x9597 # 0 +0x8EA3E6EC 0x95CE # 0 +0x8EA3E6ED 0x95E7 # 0 +0x8EA3E6EE 0x973B # 0 +0x8EA3E6EF 0x974D # 0 +0x8EA3E6F0 0x98E4 # 0 +0x8EA3E6F1 0x9942 # 0 +0x8EA3E6F2 0x9B1D # 0 +0x8EA3E6F3 0x9B98 # 0 +0x8EA3E6F5 0x9D49 # 0 +0x8EA3E6F6 0x6449 # 0 +0x8EA3E6F7 0x5E71 # 0 +0x8EA3E6F8 0x5E85 # 0 +0x8EA3E6F9 0x61D3 # 0 +0x8EA3E6FA 0x990E # 0 +0x8EA3E6FB 0x8002 # 0 +0x8EA3E6FC 0x781E # 0 +0x8EA3E7A1 0x5528 # 0 +0x8EA3E7A2 0x5572 # 0 +0x8EA3E7A3 0x55BA # 0 +0x8EA3E7A4 0x55F0 # 0 +0x8EA3E7A5 0x55EE # 0 +0x8EA3E7A6 0x56B8 # 0 +0x8EA3E7A7 0x56B9 # 0 +0x8EA3E7A8 0x56C4 # 0 +0x8EA3E7A9 0x8053 # 0 +0x8EA3E7AA 0x92B0 # 0 diff --git a/data/i18n_sdd.txt b/data/i18n_sdd.txt new file mode 100644 index 000000000..5c6cbcedc --- /dev/null +++ b/data/i18n_sdd.txt @@ -0,0 +1,2337 @@ + + + WORKING DRAFT Ira McDonald + High North Inc + + Common UNIX Printing System ("CUPS") + Internationalization Software Design Description v0.3 + + Copyright (C) Easy Software Products (2002) - All Rights Reserved + + + Status of this Document + + This document is an unapproved working draft and is incomplete in some + sections (see 'Ed Note:' comments). + + + Abstract + + This document provides general information and high-level design for the + Internationalization extensions for the Common UNIX Printing System + ("CUPS") Version 1.2. This document also provides C language header + files and high-level pseudo-code for all new modules and external + functions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + McDonald June 20, 2002 [Page 1] + + CUPS Internationalization Software Design Description v0.3 + + Table of Contents + + 1. Scope ...................................................... 4 + 1.1. Identification ......................................... 4 + 1.2. System Overview ........................................ 4 + 1.3. Document Overview ...................................... 4 + 2. References ................................................. 5 + 2.1. CUPS References ........................................ 5 + 2.2. Other Documents ........................................ 5 + 3. Design Overview ............................................ 7 + 3.1. Transcoding - New ...................................... 7 + 3.1.1. transcode.h - Transcoding header ................... 7 + 3.1.1.1. cups_cmap_t - SBCS Charmap Structure ........... 10 + 3.1.1.2. cups_dmap_t - DBCS Charmap Structure ........... 11 + 3.1.2. transcode.c - Transcoding module ................... 11 + 3.1.2.1. cupsUtf8ToCharset() ............................ 11 + 3.1.2.2. cupsCharsetToUtf8() ............................ 12 + 3.1.2.3. cupsUtf8ToUtf16() .............................. 12 + 3.1.2.4. cupsUtf16ToUtf8() .............................. 12 + 3.1.2.5. cupsUtf8ToUtf32() .............................. 12 + 3.1.2.6. cupsUtf32ToUtf8() .............................. 13 + 3.1.2.7. cupsUtf16ToUtf32() ............................. 13 + 3.1.2.8. cupsUtf32ToUtf16() ............................. 13 + 3.1.2.9. Transcoding Utility Functions .................. 13 + 3.1.2.9.1. cupsCharmapGet() ........................... 14 + 3.1.2.9.2. cupsCharmapFree() .......................... 14 + 3.1.2.9.3. cupsCharmapFlush() ......................... 14 + 3.2. Normalization - New .................................... 15 + 3.2.1. normalize.h - Normalization header ................. 15 + 3.2.1.1. cups_normmap_t - Normalize Map Structure ....... 22 + 3.2.1.2. cups_foldmap_t - Case Fold Map Structure ....... 22 + 3.2.1.3. cups_propmap_t - Char Property Map Structure ... 23 + 3.2.1.4. cups_prop_t - Char Property Structure .......... 23 + 3.2.1.5. cups_breakmap_t - Line Break Map Structure ..... 23 + 3.2.1.6. cups_combmap_t - Combining Class Map Structure . 24 + 3.2.1.7. cups_comb_t - Combining Class Structure ........ 24 + 3.2.2. normalize.c - Normalization module ................. 24 + 3.2.2.1. cupsUtf8Normalize() ............................ 24 + 3.2.2.2. cupsUtf32Normalize() ........................... 25 + 3.2.2.3. cupsUtf8CaseFold() ............................. 25 + 3.2.2.4. cupsUtf32CaseFold() ............................ 26 + 3.2.2.5. cupsUtf8CompareCaseless() ...................... 26 + 3.2.2.6. cupsUtf32CompareCaseless() ..................... 26 + 3.2.2.7. cupsUtf8CompareIdentifier() .................... 27 + 3.2.2.8. cupsUtf32CompareIdentifier() ................... 27 + 3.2.2.9. cupsUtf32CharacterProperty() ................... 27 + 3.2.2.10. Normalization Utility Functions ............... 28 + 3.2.2.10.1. cupsNormalizeMapsGet() .................... 28 + 3.2.2.10.2. cupsNormalizeMapsFree() ................... 28 + 3.2.2.10.3. cupsNormalizeMapsFlush() .................. 28 + 3.3. Language - Existing .................................... 29 + 3.3.1. language.h - Language header ....................... 29 + + McDonald June 20, 2002 [Page 2] + + CUPS Internationalization Software Design Description v0.3 + + 3.3.2. language.c - Language module ....................... 29 + 3.3.2.1. cupsLangEncoding() - Existing .................. 29 + 3.3.2.2. cupsLangFlush() - Existing ..................... 29 + 3.3.2.3. cupsLangFree() - Existing ...................... 29 + 3.3.2.4. cupsLangGet() - Existing ....................... 30 + 3.3.2.5. cupsLangPrintf() - New ......................... 30 + 3.3.2.6. cupsLangPuts() - New ........................... 30 + 3.3.2.7. cupsEncodingName() - New ....................... 31 + 3.4. Common Text Filter - Existing .......................... 31 + 3.4.1. textcommon.h - Common text filter header ........... 31 + 3.4.1.1. lchar_t - Character/Attribute Structure ........ 31 + 3.4.2. textcommon.c - Common text filter .................. 32 + 3.4.2.1. TextMain() - Existing .......................... 32 + 3.4.2.2. compare_keywords() - Existing .................. 33 + 3.4.2.3. getutf8() - Existing ........................... 33 + 3.5. Text to PostScript Filter - Existing ................... 33 + 3.5.1. texttops.c - Text to PostScript filter ............. 33 + 3.5.1.1. main() - Existing .............................. 33 + 3.5.1.2. WriteEpilogue () - Existing .................... 34 + 3.5.1.3. WritePage () - Existing ........................ 34 + 3.5.1.4. WriteProlog () - Existing ...................... 34 + 3.5.1.5. write_line() - Existing ........................ 34 + 3.5.1.6. write_string() - Existing ...................... 34 + 3.5.1.7. write_text() - Existing ........................ 35 + A. Glossary ................................................... A-1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + McDonald June 20, 2002 [Page 3] + + CUPS Internationalization Software Design Description v0.3 + + + + 1. Scope + + + + 1.1. Identification + + This document provides general information and high-level design for the + Internationalization extensions for the Common UNIX Printing System + ("CUPS") Version 1.2. This document also provides C language header + files and high-level pseudo-code for all new modules and external + functions. + + + 1.2. System Overview + + The CUPS Internationalization extensions provide multilingual support + via Unicode 3.2:2002 [UNICODE3.2] / ISO-10646-1:2000 [ISO10646-1] and a + suite of local character sets (including all adopted parts of ISO-8859 + and many MS Windows code pages) for CUPS 1.2. + + The CUPS Internationalization extensions support UTF-8 [RFC2279] as the + common stream-oriented representation of all character data. UTF-8 is + defined in [ISO10646-1] and is further constrained (for integrity and + security) by [UNICODE3.2]. + + UTF-8 is the native character set of LDAPv3 [RFC2251], SLPv2 [RFC2608], + IPP/1.1 [RFC2910] [RFC2911], and many other Internet protocols. + + + 1.3. Document Overview + + + This software design description document is organized into the + following sections: + + o 1 - Scope + o 2 - References + o 3 - Design Overview + o A - Glossary + + + + + + + + + + + + + McDonald June 20, 2002 [Page 4] + + CUPS Internationalization Software Design Description v0.3 + + + + 2. References + + + + 2.1. CUPS References + + See: Section 2.1 'CUPS Documentation' of CUPS Software Design + Description. + + + 2.2. Other Documents + + The following non-CUPS documents are referenced by this document. + + [ANSI-X3.4] ANSI Coded Character Set - 7-bit American National Standard + Code for Information Interchange, ANSI X3.4, 1986 (aka US-ASCII). + + [GB2312] Code of Chinese Graphic Character Set for Information + Interchange, Primary Set, GB 2312, 1980. + + [ISO639-1] Codes for the Representation of Names of Languages -- Part 1: + Alpha-2 Code, ISO/IEC 639-1, 2000. + + [ISO639-2] Codes for the Representation of Names of Languages -- Part 2: + Alpha-3 Code, ISO/IEC 639-2, 1998. + + [ISO646] Information Technology - ISO 7-bit Coded Character Set for + Information Interchange, ISO/IEC 646, 1991. + + [ISO2022] Information Processing - ISO 7-bit and 8-bit Coded Character + Sets - Code Extension Techniques, ISO/IEC 2022, 1994. (Technically + identical to ECMA-35.) + + [ISO3166-1] Codes for the Representation of Names of Countries and their + Subdivisions, Part 1: Country Codes, ISO/ISO 3166-1, 1997. + + [ISO8859] Information Processing - 8-bit Single-Byte Code Graphic + Character Sets, ISO/IEC 8859-n, 1987-2001. + + [ISO10646-1] Information Technology - Universal Multiple-Octet Code + Character Set (UCS) - Part 1: Architecture and Basic Multilingual + Plane, ISO/IEC 10646-1, September 2000. + + [ISO10646-2] Information Technology - Universal Multiple-Octet Code + Character Set (UCS) - Part 2: Supplemental Planes, ISO/IEC 10646-2, + January 2001. + + [RFC2119] Bradner. Key words for use in RFCs to Indicate Requirement + Levels, RFC 2119, March 1997. + + + McDonald June 20, 2002 [Page 5] + + CUPS Internationalization Software Design Description v0.3 + + + [RFC2251] Whal, Howes, Kille. Lightweight Directory Access Protocol + Version 3 (LDAPv3), RFC 2251, December 1997. + + [RFC2277] Alvestrand. IETF Policy on Character Sets and Languages, RFC + 2277, January 1998. + + [RFC2279] Yergeau. UTF-8, a Transformation Format of ISO 10646, RFC + 2279, January 1998. + + [RFC2608] Guttman, Perkins, Veizades, Day. Service Location Protocol + Version 2 (SLPv2), RFC 2608, June 1999. + + [RFC2910] Herriot, Butler, Moore, Turner, Wenn. Internet Printing + Protocol/1.1: Encoding and Transport, RFC 2910, September 2000. + + [RFC2911] Hastings, Herriot, deBry, Isaacson, Powell. Internet Printing + Protocol/1.1: Model and Semantics, RFC 2911, September 2000. + + [UNICODE3.0] Unicode Consortium, Unicode Standard Version 3.0, + Addison-Wesley Developers Press, ISBN 0-201-61633-5, 2000. + + [UNICODE3.1] Unicode Consortium, Unicode Standard Version 3.1 (UAX-27), + May 2001. + + [UNICODE3.2] Unicode Consortium, Unicode Standard Version 3.2 (UAX-28), + March 2002. + + [US-ASCII] See [ANSI-X3.4] above. + + + + + + + + + + + + + + + + + + + + + + + + + McDonald June 20, 2002 [Page 6] + + CUPS Internationalization Software Design Description v0.3 + + + + 3. Design Overview + + The CUPS Internationalization extensions are composed of several header + files and modules which extend the Language functions in the existing + CUPS Application Programmers Interface (API). + + + 3.1. Transcoding - New + + Initially, the CUPS Internationalization extensions will only support + SBCS (single-byte character set) transcoding. But the design allows + future support for DBCS (double-byte character set) transcoding for CJK + (Chinese/Japanese/Korean) languages and the MBCS (multiple-byte + character set) compound sets that use escapes for charset switching. + + In order to reduce code size and increase performance all conventional + 'mapping files' (tables of values in legacy characters sets with their + corresponding Unicode scalar values) will ALSO be sorted and stored in + memory as reverse maps (for efficient conversion from Unicode scalar + values to their corresponding legacy character set values). Transcoding + will be done directly by 2-level lookup (without any searching or + sorting). + + [Ed Note: CJK languages will be fairly costly in mapping table sizes, + because they have thousands (or tens of thousands) of codepoints.] + + + + 3.1.1. transcode.h - Transcoding header + + /* + * "$Id: i18n_sdd.txt 2678 2002-08-19 01:15:26Z mike $" + * + * Transcoding 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 + + McDonald June 20, 2002 [Page 7] + + CUPS Internationalization Software Design Description v0.3 + + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + + #ifndef _CUPS_TRANSCODE_H_ + # define _CUPS_TRANSCODE_H_ + + /* + * Include necessary headers... + */ + + # include "cups/language.h" + + # ifdef __cplusplus + extern "C" { + # endif /* __cplusplus */ + + /* + * Types... + */ + + typedef unsigned char utf8_t; /* UTF-8 Unicode/ISO-10646 code unit */ + typedef unsigned short utf16_t; /* UTF-16 Unicode/ISO-10646 code unit */ + typedef unsigned long utf32_t; /* UTF-32 Unicode/ISO-10646 code unit */ + typedef unsigned short ucs2_t; /* UCS-2 Unicode/ISO-10646 code unit */ + typedef unsigned long ucs4_t; /* UCS-4 Unicode/ISO-10646 code unit */ + typedef unsigned char sbcs_t; /* SBCS Legacy 8-bit code unit */ + typedef unsigned short dbcs_t; /* DBCS Legacy 16-bit code unit */ + + /* + * Structures... + */ + + typedef struct cups_cmap_str /**** SBCS Charmap Cache Structure ****/ + { + struct cups_cmap_str *next; /* Next charmap in cache */ + int used; /* Number of times entry used */ + cups_encoding_t encoding; /* Legacy charset encoding */ + ucs2_t char2uni[256]; /* Map Legacy SBCS -> UCS-2 */ + sbcs_t *uni2char[256]; /* Map UCS-2 -> Legacy SBCS */ + } cups_cmap_t; + + #if 0 + typedef struct cups_dmap_str /**** DBCS Charmap Cache Structure ****/ + { + struct cups_dmap_str *next; /* Next charmap in cache */ + int used; /* Number of times entry used */ + cups_encoding_t encoding; /* Legacy charset encoding */ + ucs2_t *char2uni[256]; /* Map Legacy DBCS -> UCS-2 */ + dbcs_t *uni2char[256]; /* Map UCS-2 -> Legacy DBCS */ + } cups_dmap_t; + #endif + + McDonald June 20, 2002 [Page 8] + + CUPS Internationalization Software Design Description v0.3 + + + /* + * Constants... + */ + #define CUPS_MAX_USTRING 1024 /* Maximum size of Unicode string */ + + /* + * Globals... + */ + + extern int TcFixMapNames; /* Fix map names to Unicode names */ + extern int TcStrictUtf8; /* Non-shortest-form is illegal */ + extern int TcStrictUtf16; /* Invalid surrogate pair is illegal */ + extern int TcStrictUtf32; /* Greater than 0x10FFFF is illegal */ + extern int TcRequireBOM; /* Require BOM for little/big-endian */ + extern int TcSupportBOM; /* Support BOM for little/big-endian */ + extern int TcSupport8859; /* Support ISO 8859-x repertoires */ + extern int TcSupportWin; /* Support Windows-x repertoires */ + extern int TcSupportCJK; /* Support CJK (Asian) repertoires */ + + /* + * Prototypes... + */ + + /* + * Utility functions for character set maps + */ + extern void *cupsCharmapGet(const cups_encoding_t encoding); + /* I - Encoding */ + extern void cupsCharmapFree(const cups_encoding_t encoding); + /* I - Encoding */ + extern void cupsCharmapFlush(void); + + /* + * Convert UTF-8 to and from legacy character set + */ + extern int cupsUtf8ToCharset(char *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + cups_encoding_t encoding); /* I - Encoding */ + extern int cupsCharsetToUtf8(utf8_t *dest, /* O - Target string */ + const char *src, /* I - Source string */ + const int maxout, /* I - Max output */ + cups_encoding_t encoding); /* I - Encoding */ + + /* + * Convert UTF-8 to and from UTF-16 + */ + extern int cupsUtf8ToUtf16(utf16_t *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + extern int cupsUtf16ToUtf8(utf8_t *dest, /* O - Target string */ + + McDonald June 20, 2002 [Page 9] + + CUPS Internationalization Software Design Description v0.3 + + const utf16_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + /* + * Convert UTF-8 to and from UTF-32 + */ + extern int cupsUtf8ToUtf32(utf32_t *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + extern int cupsUtf32ToUtf8(utf8_t *dest, /* O - Target string */ + const utf32_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + /* + * Convert UTF-16 to and from UTF-32 + */ + extern int cupsUtf16ToUtf32(utf32_t *dest, /* O - Target string */ + const utf16_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + extern int cupsUtf32ToUtf16(utf16_t *dest, /* O - Target string */ + const utf32_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + # ifdef __cplusplus + } + # endif /* __cplusplus */ + + #endif /* !_CUPS_TRANSCODE_H_ */ + + /* + * End of "$Id: i18n_sdd.txt 2678 2002-08-19 01:15:26Z mike $" + */ + + + + 3.1.1.1. cups_cmap_t - SBCS Charmap Structure + + typedef struct cups_cmap_str /**** SBCS Charmap Cache Structure ****/ + { + struct cups_cmap_str *next; /* Next charset map in cache */ + int used; /* Number of times entry used */ + cups_encoding_t encoding; /* Legacy charset encoding */ + ucs2_t char2uni[256]; /* Map Legacy SBCS -> UCS-2 */ + sbcs_t *uni2char[256]; /* Map UCS-2 -> Legacy SBCS */ + } cups_cmap_t; + + 'char2uni[]' is a (complete) array of UCS-2 values that supports direct + one-level lookup from an input SBCS legacy charset code point, for use + by 'cupsCharsetToUtf8()'. + + 'uni2char[]' is a (sparse) array of pointers to arrays of (256 each) + SBCS values, that supports direct two-level lookup from an input UCS-2 + + McDonald June 20, 2002 [Page 10] + + CUPS Internationalization Software Design Description v0.3 + + code point, for use by 'cupsUtf8ToCharset()'. + + + + 3.1.1.2. cups_dmap_t - DBCS Charmap Structure + + typedef struct cups_dmap_str /**** DBCS Charmap Cache Structure ****/ + { + struct cups_dmap_str *next; /* Next charset map in cache */ + int used; /* Number of times entry used */ + cups_encoding_t encoding; /* Legacy charset encoding */ + ucs2_t *char2uni[256]; /* Map Legacy DBCS -> UCS-2 */ + dbcs_t *uni2char[256]; /* Map UCS-2 -> Legacy DBCS */ + } cups_dmap_t; + + 'char2uni[]' is a (sparse) array of pointers to arrays of (256 each) + UCS-2 values that supports direct two-level lookup from an input DBCS + legacy charset code point, for (future) use by 'cupsCharsetToUtf8()'. + + 'uni2char[]' is a (sparse) array of pointers to arrays of (256 each) + DBCS values, that supports direct two-level lookup from an input UCS-2 + code point, for (future) use by 'cupsUtf8ToCharset()'. + + + + 3.1.2. transcode.c - Transcoding module + + All of the transcoding functions are modelled on the C standard library + function 'strncpy()', except that they return the count of output, like + 'strlen()', rather than the (redundant) pointer to the output. + + If the transcoding functions detect invalid input parameters or they + detect an encoding error in their input, then they return '-1', rather + than the count of output. + + All of the transcoding functions take an input parameter indicating the + maximum output units (for safe operation). The functions that return + 16-bit (UTF-16) or 32-bit (UTF-32/UCS-4) output always return the output + string count (not including the final null) and NOT the memory size in + bytes. + + + + 3.1.2.1. cupsUtf8ToCharset() + + extern int cupsUtf8ToCharset(char *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + cups_encoding_t encoding); /* I - Encoding */ + + + + + McDonald June 20, 2002 [Page 11] + + CUPS Internationalization Software Design Description v0.3 + + + + + + + + 3.1.2.2. cupsCharsetToUtf8() + + extern int cupsCharsetToUtf8(utf8_t *dest, /* O - Target string */ + const char *src, /* I - Source string */ + const int maxout, /* I - Max output */ + cups_encoding_t encoding); /* I - Encoding */ + + + + + + + + + + 3.1.2.3. cupsUtf8ToUtf16() + + extern int cupsUtf8ToUtf16(utf16_t *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + <...to avoid duplicate code to handle surrogate pairs...> + + + + + + + 3.1.2.4. cupsUtf16ToUtf8() + + extern int cupsUtf16ToUtf8(utf8_t *dest, /* O - Target string */ + const utf16_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + <...to avoid duplicate code to handle surrogate pairs...> + + + + + + + 3.1.2.5. cupsUtf8ToUtf32() + + extern int cupsUtf8ToUtf32(utf32_t *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + McDonald June 20, 2002 [Page 12] + + CUPS Internationalization Software Design Description v0.3 + + + + <...checking for valid range, shortest-form, etc.> + + + + + 3.1.2.6. cupsUtf32ToUtf8() + + extern int cupsUtf32ToUtf8(utf8_t *dest, /* O - Target string */ + const utf32_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + + <...checking for valid range, etc.> + + + + + 3.1.2.7. cupsUtf16ToUtf32() + + extern int cupsUtf16ToUtf32(utf32_t *dest, /* O - Target string */ + const utf16_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + + <...handling surrogate pairs decoding from UTF-16> + + + + + 3.1.2.8. cupsUtf32ToUtf16() + + extern int cupsUtf32ToUtf16(utf16_t *dest, /* O - Target string */ + const utf32_t *src, /* I - Source string */ + const int maxout); /* I - Max output */ + + + <...handling surrogate pairs encoding to UTF-16> + + + + + 3.1.2.9. Transcoding Utility Functions + + The transcoding utility functions are used to load (from a file into + memory), free (logically, without freeing memory), and flush (actually + free memory) character maps for SBCS (single-byte character set) and + (future) DBCS (double-byte character set) transcoding to and from UTF-8. + + + + + McDonald June 20, 2002 [Page 13] + + CUPS Internationalization Software Design Description v0.3 + + + + 3.1.2.9.1. cupsCharmapGet() + + extern void *cupsCharmapGet(const cups_encoding_t encoding); + /* I - Encoding */ + + + <...If found, increment 'used'> + <...and return pointer to SBCS or DBCS charset map> + + + <...If not found, return void> + + <...If no memory, return void> + + + + + + <...and 'uni2char[]' is an array of pointers to 'sbcs_t' arrays> + + <...and 'uni2char[]' is an array of pointers to 'dbcs_t' arrays> + + + + + + 3.1.2.9.2. cupsCharmapFree() + + extern void cupsCharmapFree(const cups_encoding_t encoding); + /* I - Encoding */ + + + <...If found, decrement 'used'> + + + + + 3.1.2.9.3. cupsCharmapFlush() + + extern void cupsCharmapFlush(void); + + + <...Free 'uni2char[]' memory> + <...Free SBCS charset map memory> + + <...Free 'char2uni[]' memory> + <...Free 'uni2char[]' memory> + <...Free DBCS charset map memory> + + + + McDonald June 20, 2002 [Page 14] + + CUPS Internationalization Software Design Description v0.3 + + + + + 3.2. Normalization - New + + + + 3.2.1. normalize.h - Normalization header + + /* + * "$Id: i18n_sdd.txt 2678 2002-08-19 01:15:26Z mike $" + * + * Unicode normalization 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_NORMALIZE_H_ + # define _CUPS_NORMALIZE_H_ + + /* + * Include necessary headers... + */ + + # include "transcod.h" + + # ifdef __cplusplus + extern "C" { + # endif /* __cplusplus */ + + /* + * Types... + */ + + typedef enum /**** Normalizataion Types ****/ + { + + McDonald June 20, 2002 [Page 15] + + CUPS Internationalization Software Design Description v0.3 + + CUPS_NORM_NFD, /* Canonical Decomposition */ + CUPS_NORM_NFKD, /* Compatibility Decomposition */ + CUPS_NORM_NFC, /* NFD, them Canonical Composition */ + CUPS_NORM_NFKC /* NFKD, them Canonical Composition */ + } cups_normalize_t; + + typedef enum /**** Case Folding Types ****/ + { + CUPS_FOLD_SIMPLE, /* Simple - no expansion in size */ + CUPS_FOLD_FULL /* Full - possible expansion in size */ + } cups_folding_t; + + typedef enum /**** Unicode Char Property Types ****/ + { + CUPS_PROP_GENERAL_CATEGORY, /* See 'cups_gencat_t' enum */ + CUPS_PROP_BIDI_CATEGORY, /* See 'cups_bidicat_t' enum */ + CUPS_PROP_COMBINING_CLASS, /* See 'cups_combclass_t' type */ + CUPS_PROP_BREAK_CLASS /* See 'cups_breakclass_t' enum */ + } cups_property_t; + + /* + * Note - parse Unicode char general category from 'UnicodeData.txt' + * into sparse local table in 'normalize.c'. + * Use major classes for logic optimizations throughout (by mask). + */ + + typedef enum /**** Unicode General Category ****/ + { + CUPS_GENCAT_L = 0x10, /* Letter major class */ + CUPS_GENCAT_LU = 0x11, /* Lu Letter, Uppercase */ + CUPS_GENCAT_LL = 0x12, /* Ll Letter, Lowercase */ + CUPS_GENCAT_LT = 0x13, /* Lt Letter, Titlecase */ + CUPS_GENCAT_LM = 0x14, /* Lm Letter, Modifier */ + CUPS_GENCAT_LO = 0x15, /* Lo Letter, Other */ + CUPS_GENCAT_M = 0x20, /* Mark major class */ + CUPS_GENCAT_MN = 0x21, /* Mn Mark, Non-Spacing */ + CUPS_GENCAT_MC = 0x22, /* Mc Mark, Spacing Combining */ + CUPS_GENCAT_ME = 0x23, /* Me Mark, Enclosing */ + CUPS_GENCAT_N = 0x30, /* Number major class */ + CUPS_GENCAT_ND = 0x31, /* Nd Number, Decimal Digit */ + CUPS_GENCAT_NL = 0x32, /* Nl Number, Letter */ + CUPS_GENCAT_NO = 0x33, /* No Number, Other */ + CUPS_GENCAT_P = 0x40, /* Punctuation major class */ + CUPS_GENCAT_PC = 0x41, /* Pc Punctuation, Connector */ + CUPS_GENCAT_PD = 0x42, /* Pd Punctuation, Dash */ + CUPS_GENCAT_PS = 0x43, /* Ps Punctuation, Open (start) */ + CUPS_GENCAT_PE = 0x44, /* Pe Punctuation, Close (end) */ + CUPS_GENCAT_PI = 0x45, /* Pi Punctuation, Initial Quote */ + CUPS_GENCAT_PF = 0x46, /* Pf Punctuation, Final Quote */ + CUPS_GENCAT_PO = 0x47, /* Po Punctuation, Other */ + CUPS_GENCAT_S = 0x50, /* Symbol major class */ + CUPS_GENCAT_SM = 0x51, /* Sm Symbol, Math */ + + McDonald June 20, 2002 [Page 16] + + CUPS Internationalization Software Design Description v0.3 + + CUPS_GENCAT_SC = 0x52, /* Sc Symbol, Currency */ + CUPS_GENCAT_SK = 0x53, /* Sk Symbol, Modifier */ + CUPS_GENCAT_SO = 0x54, /* So Symbol, Other */ + CUPS_GENCAT_Z = 0x60, /* Separator major class */ + CUPS_GENCAT_ZS = 0x61, /* Zs Separator, Space */ + CUPS_GENCAT_ZL = 0x62, /* Zl Separator, Line */ + CUPS_GENCAT_ZP = 0x63, /* Zp Separator, Paragraph */ + CUPS_GENCAT_C = 0x70, /* Other (miscellaneous) major class */ + CUPS_GENCAT_CC = 0x71, /* Cc Other, Control */ + CUPS_GENCAT_CF = 0x72, /* Cf Other, Format */ + CUPS_GENCAT_CS = 0x73, /* Cs Other, Surrogate */ + CUPS_GENCAT_CO = 0x74, /* Co Other, Private Use */ + CUPS_GENCAT_CN = 0x75 /* Cn Other, Not Assigned */ + } cups_gencat_t; + + /* + * Note - parse Unicode char bidi category from 'UnicodeData.txt' + * into sparse local table in 'normalize.c'. + * Add bidirectional support to 'textcommon.c' - per Mike + */ + + typedef enum /**** Unicode Bidi Category ****/ + { + CUPS_BIDI_L, /* Left-to-Right (Alpha, Syllabic, Ideographic) */ + CUPS_BIDI_LRE, /* Left-to-Right Embedding (explicit) */ + CUPS_BIDI_LRO, /* Left-to-Right Override (explicit) */ + CUPS_BIDI_R, /* Right-to-Left (Hebrew alphabet and most punct) */ + CUPS_BIDI_AL, /* Right-to-Left Arabic (Arabic, Thaana, Syriac) */ + CUPS_BIDI_RLE, /* Right-to-Left Embedding (explicit) */ + CUPS_BIDI_RLO, /* Right-to-Left Override (explicit) */ + CUPS_BIDI_PDF, /* Pop Directional Format */ + CUPS_BIDI_EN, /* Euro Number (Euro and East Arabic-Indic digits) */ + CUPS_BIDI_ES, /* Euro Number Separator (Slash) */ + CUPS_BIDI_ET, /* Euro Number Termintor (Plus, Minus, Degree, etc) */ + CUPS_BIDI_AN, /* Arabic Number (Arabic-Indic digits, separators) */ + CUPS_BIDI_CS, /* Common Number Separator (Colon, Comma, Dot, etc) */ + CUPS_BIDI_NSM, /* Non-Spacing Mark (category Mn / Me in UCD) */ + CUPS_BIDI_BN, /* Boundary Neutral (Formatting / Control chars) */ + CUPS_BIDI_B, /* Paragraph Separator */ + CUPS_BIDI_S, /* Segment Separator (Tab) */ + CUPS_BIDI_WS, /* Whitespace Space (Space, Line Separator, etc) */ + CUPS_BIDI_ON /* Other Neutrals */ + } cups_bidicat_t; + + /* + * Note - parse Unicode line break class from 'DerivedLineBreak.txt' + * into sparse local table (list of class ranges) in 'normalize.c'. + * Note - add state table from UAX-14, section 7.3 - Ira + * Remember to do BK and SP in outer loop (not in state table). + * Consider optimization for CM (combining mark). + * See 'LineBreak.txt' (12,875) and 'DerivedLineBreak.txt' (1,350). + */ + + McDonald June 20, 2002 [Page 17] + + CUPS Internationalization Software Design Description v0.3 + + + typedef enum /**** Unicode Line Break Class ****/ + { + /* + * (A) - Allow Break AFTER + * (XA) - Prevent Break AFTER + * (B) - Allow Break BEFORE + * (XB) - Prevent Break BEFORE + * (P) - Allow Break For Pair + * (XP) - Prevent Break For Pair + */ + CUPS_BREAK_AI, /* Ambiguous (Alphabetic or Ideograph) */ + CUPS_BREAK_AL, /* Ordinary Alphabetic / Symbol Chars (XP) */ + CUPS_BREAK_BA, /* Break Opportunity After Chars (A) */ + CUPS_BREAK_BB, /* Break Opportunities Before Chars (B) */ + CUPS_BREAK_B2, /* Break Opportunity Before / After (B/A/XP) */ + CUPS_BREAK_BK, /* Mandatory Break (A) (normative) */ + CUPS_BREAK_CB, /* Contingent Break (B/A) (normative) */ + CUPS_BREAK_CL, /* Closing Punctuation (XB) */ + CUPS_BREAK_CM, /* Attached Chars / Combining (XB) (normative) */ + CUPS_BREAK_CR, /* Carriage Return (A) (normative) */ + CUPS_BREAK_EX, /* Exclamation / Interrogation (XB) */ + CUPS_BREAK_GL, /* Non-breaking ("Glue") (XB/XA) (normative) */ + CUPS_BREAK_HY, /* Hyphen (XA) */ + CUPS_BREAK_ID, /* Ideographic (B/A) */ + CUPS_BREAK_IN, /* Inseparable chars (XP) */ + CUPS_BREAK_IS, /* Numeric Separator (Infix) (XB) */ + CUPS_BREAK_LF, /* Line Feed (A) (normative) */ + CUPS_BREAK_NS, /* Non-starters (XB) */ + CUPS_BREAK_NU, /* Numeric (XP) */ + CUPS_BREAK_OP, /* Opening Punctuation (XA) */ + CUPS_BREAK_PO, /* Postfix (Numeric) (XB) */ + CUPS_BREAK_PR, /* Prefix (Numeric) (XA) */ + CUPS_BREAK_QU, /* Ambiguous Quotation (XB/XA) */ + CUPS_BREAK_SA, /* Context Dependent (South East Asian) (P) */ + CUPS_BREAK_SG, /* Surrogates (XP) (normative) */ + CUPS_BREAK_SP, /* Space (A) (normative) */ + CUPS_BREAK_SY, /* Symbols Allowing Break After (A) */ + CUPS_BREAK_XX, /* Unknown (XP) */ + CUPS_BREAK_ZW /* Zero Width Space (A) (normative) */ + } cups_breakclass_t; + + typedef int cups_combclass_t; /**** Unicode Combining Class ****/ + /* 0=base / 1..254=combining char */ + + /* + * Structures... + */ + + typedef struct cups_normmap_str /**** Normalize Map Cache Struct ****/ + { + struct cups_normmap_str *next; /* Next normalize in cache */ + + McDonald June 20, 2002 [Page 18] + + CUPS Internationalization Software Design Description v0.3 + + int used; /* Number of times entry used */ + cups_normalize_t normalize; /* Normalization type */ + int normcount; /* Count of Source Chars */ + ucs2_t *uni2norm; /* Char -> Normalization */ + /* ...only supports UCS-2 */ + } cups_normmap_t; + + typedef struct cups_foldmap_str /**** Case Fold Map Cache Struct ****/ + { + struct cups_foldmap_str *next; /* Next case fold in cache */ + int used; /* Number of times entry used */ + cups_folding_t fold; /* Case folding type */ + int foldcount; /* Count of Source Chars */ + ucs2_t *uni2fold; /* Char -> Folded Char(s) */ + /* ...only supports UCS-2 */ + } cups_foldmap_t; + + typedef struct cups_prop_str /**** Char Property Struct ****/ + { + ucs2_t ch; /* Unicode Char as UCS-2 */ + unsigned char gencat; /* General Category */ + unsigned char bidicat; /* Bidirectional Category */ + } cups_prop_t; + + typedef struct /**** Char Property Map Struct ****/ + { + int used; /* Number of times entry used */ + int propcount; /* Count of Source Chars */ + cups_prop_t *uni2prop; /* Char -> Properties */ + } cups_propmap_t; + + typedef struct /**** Line Break Class Map Struct ****/ + { + int used; /* Number of times entry used */ + int breakcount; /* Count of Source Chars */ + ucs2_t *uni2break; /* Char -> Line Break Class */ + } cups_breakmap_t; + + typedef struct cups_comb_str /**** Char Combining Class Struct ****/ + { + ucs2_t ch; /* Unicode Char as UCS-2 */ + unsigned char combclass; /* Combining Class */ + unsigned char reserved; /* Reserved for alignment */ + } cups_comb_t; + + typedef struct /**** Combining Class Map Struct ****/ + { + int used; /* Number of times entry used */ + int combcount; /* Count of Source Chars */ + cups_comb_t *uni2comb; /* Char -> Combining Class */ + } cups_combmap_t; + + + McDonald June 20, 2002 [Page 19] + + CUPS Internationalization Software Design Description v0.3 + + + /* + * Globals... + */ + + extern int NzSupportUcs2; /* Support UCS-2 (16-bit) mapping */ + extern int NzSupportUcs4; /* Support UCS-4 (32-bit) mapping */ + + /* + * Prototypes... + */ + + /* + * Utility functions for normalization module + */ + extern int cupsNormalizeMapsGet(void); + extern int cupsNormalizeMapsFree(void); + extern void cupsNormalizeMapsFlush(void); + + /* + * Normalize UTF-8 string to Unicode UAX-15 Normalization Form + * Note - Compatibility Normalization Forms (NFKD/NFKC) are + * unsafe for subsequent transcoding to legacy charsets + */ + extern int cupsUtf8Normalize(utf8_t *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_normalize_t normalize); + /* I - Normalization */ + + /* + * Normalize UTF-32 string to Unicode UAX-15 Normalization Form + * Note - Compatibility Normalization Forms (NFKD/NFKC) are + * unsafe for subsequent transcoding to legacy charsets + */ + extern int cupsUtf32Normalize(utf32_t *dest, + /* O - Target string */ + const utf32_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_normalize_t normalize); + /* I - Normalization */ + + /* + * Case Fold UTF-8 string per Unicode UAX-21 Section 2.3 + * Note - Case folding output is + * unsafe for subsequent transcoding to legacy charsets + */ + extern int cupsUtf8CaseFold(utf8_t *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_folding_t fold); /* I - Fold Mode */ + + + McDonald June 20, 2002 [Page 20] + + CUPS Internationalization Software Design Description v0.3 + + + /* + * Case Fold UTF-32 string per Unicode UAX-21 Section 2.3 + * Note - Case folding output is + * unsafe for subsequent transcoding to legacy charsets + */ + extern int cupsUtf32CaseFold(utf32_t *dest,/* O - Target string */ + const utf32_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_folding_t fold); /* I - Fold Mode */ + + /* + * Compare UTF-8 strings after case folding + */ + extern int cupsUtf8CompareCaseless(const utf8_t *s1, + /* I - String1 */ + const utf8_t *s2); /* I - String2 */ + + /* + * Compare UTF-32 strings after case folding + */ + extern int cupsUtf32CompareCaseless(const utf32_t *s1, + /* I - String1 */ + const utf32_t *s2); /* I - String2 */ + + /* + * Compare UTF-8 strings after case folding and NFKC normalization + */ + extern int cupsUtf8CompareIdentifier(const utf8_t *s1, + /* I - String1 */ + const utf8_t *s2); /* I - String2 */ + + /* + * Compare UTF-32 strings after case folding and NFKC normalization + */ + extern int cupsUtf32CompareIdentifier(const utf32_t *s1, + /* I - String1 */ + const utf32_t *s2); /* I - String2 */ + + /* + * Get UTF-32 character property + */ + extern int cupsUtf32CharacterProperty(const utf32_t ch, + /* I - Source char */ + const cups_property_t property); + /* I - Char Property */ + + # ifdef __cplusplus + } + # endif /* __cplusplus */ + + #endif /* !_CUPS_NORMALIZE_H_ */ + + McDonald June 20, 2002 [Page 21] + + CUPS Internationalization Software Design Description v0.3 + + + /* + * End of "$Id: i18n_sdd.txt 2678 2002-08-19 01:15:26Z mike $" + */ + + + + 3.2.1.1. cups_normmap_t - Normalize Map Structure + + typedef struct cups_normmap_str /**** Normalize Map Cache Struct ****/ + { + struct cups_normmap_str *next; /* Next normalize in cache */ + int used; /* Number of times entry used */ + cups_normalize_t normalize; /* Normalization type */ + int normcount; /* Count of Source Chars */ + ucs2_t *uni2norm; /* Char -> Normalization */ + /* ...only supports UCS-2 */ + } cups_normmap_t; + + 'uni2norm' is a pointer to an array of _triplets_ of UCS-2 values. + 'normcount' is a count of _triplets_ in the 'uni2norm[]' array. + + For decompositions (NFD and NFKD), the triplets are: composed base + character, decomposed base character, and decomposed accent character. + These are used by 'cupsUtf8Normalize()' and 'cupsUtf32Normalize()' in + performing canonical (NFD) or compatibility (NFKD) decomposition. + + For compositions (NFC and NFKC), the triplets are: decomposed base + character, decomposed accent character, and composed base character. + These are used by 'cupsUtf8Normalize()' and 'cupsUtf32Normalize()' in + performing canonical composition (for NFC or NFKC). + + + + 3.2.1.2. cups_foldmap_t - Case Fold Map Structure + + typedef struct cups_foldmap_str /**** Case Fold Map Cache Struct ****/ + { + int used; /* Number of times entry used */ + cups_folding_t fold; /* Case folding type */ + int foldcount; /* Count of Source Chars */ + ucs2_t *uni2fold; /* Char -> Folded Char(s) */ + /* ...only supports UCS-2 */ + } cups_foldmap_t; + + 'uni2fold' is a pointer to an array of _quadruplets_ of UCS-2 values. + 'foldcount' is a count of _quadruplets_ in the 'uni2fold[]' array. + + For simple case folding (without expansion of the size of the output + string), the quadruplets are: input base character, output case folded + character, zero (unused), and zero (unused). + + + McDonald June 20, 2002 [Page 22] + + CUPS Internationalization Software Design Description v0.3 + + + For full case folding (with possible expansion of the size of the output + string), the quadruplets are: input base character, output case folded + character, second output character or zero, third output character or + zero. + + + + 3.2.1.3. cups_propmap_t - Char Property Map Structure + + typedef struct /**** Char Property Map Struct ****/ + { + int used; /* Number of times entry used */ + int propcount; /* Count of Source Chars */ + cups_prop_t *uni2prop; /* Char -> Properties */ + } cups_propmap_t; + + 'uni2prop' is a pointer to an array of 'cups_prop_t' (see below). + 'propcount' is a count of elements in the 'uni2prop[]' array. + + + + 3.2.1.4. cups_prop_t - Char Property Structure + + typedef struct cups_prop_str /**** Char Property Struct ****/ + { + ucs2_t ch; /* Unicode Char as UCS-2 */ + unsigned char gencat; /* General Category */ + unsigned char bidicat; /* Bidirectional Category */ + } cups_prop_t; + + + + 3.2.1.5. cups_breakmap_t - Line Break Map Structure + + typedef struct /**** Line Break Class Map Struct ****/ + { + int used; /* Number of times entry used */ + int breakcount; /* Count of Source Chars */ + ucs2_t *uni2break; /* Char -> Line Break Class */ + } cups_breakmap_t; + + 'uni2break' is a pointer to an array of _triplets_ of UCS-2 values. + 'breakcount' is a count of _triplets_ in the 'uni2break[]' array. + + The triplets in 'uni2break' are: first UCS-2 value in a range, last + UCS-2 value in a range, and line break class stored as UCS-2. + + + + + + + McDonald June 20, 2002 [Page 23] + + CUPS Internationalization Software Design Description v0.3 + + + + 3.2.1.6. cups_combmap_t - Combining Class Map Structure + + typedef struct /**** Combining Class Map Struct ****/ + { + int used; /* Number of times entry used */ + int combcount; /* Count of Source Chars */ + cups_comb_t *uni2comb; /* Char -> Combining Class */ + } cups_combmap_t; + + 'uni2comb' is a pointer to an array of 'cups_comb_t' (see below). + 'combcount' is a count of elements in the 'uni2comb[]' array. + + + + 3.2.1.7. cups_comb_t - Combining Class Structure + + typedef struct cups_comb_str /**** Char Combining Class Struct ****/ + { + unsigned short ch; /* Unicode Char as UCS-2 */ + unsigned char combclass; /* Combining Class */ + unsigned char reserved; /* Reserved for alignment */ + } cups_comb_t; + + + + 3.2.2. normalize.c - Normalization module + + The normalization function 'cupsUtf8Normalize()' and the case folding + function 'cupsUtf8CaseFold()' are modelled on the C standard library + function 'strncpy()', except that they return the count of the output, + like 'strlen()', rather than the (redundant) pointer to the output. + + If the normalization or case folding functions detect invalid input + parameters or they detect an encoding error in their input, then they + return '-1', rather than the count of output. + + The normalization and case folding functions take an input parameter + indicating the maximum output units (for safe operation). + + + + 3.2.2.1. cupsUtf8Normalize() + + /* + * Normalize UTF-8 string to Unicode UAX-15 Normalization Form + * Note - Compatibility Normalization Forms (NFKD/NFKC) are + * unsafe for subsequent transcoding to legacy charsets + */ + extern int cupsUtf8Normalize(utf8_t *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + + McDonald June 20, 2002 [Page 24] + + CUPS Internationalization Software Design Description v0.3 + + const int maxout, /* I - Max output */ + const cups_normalize_t normalize); + /* I - Normalization */ + + + + + + + + + 3.2.2.2. cupsUtf32Normalize() + + extern int cupsUtf32Normalize(utf32_t *dest, + /* O - Target string */ + const utf32_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_normalize_t normalize); + /* I - Normalization */ + + + <...if not found, return '-1'> + + <...with 'bsearch()' of 'uni2norm[]' using local 'compare_decompose()'> + <...until one pass yields no further decomposition> + + <...with 'bsearch()' of 'uni2comb[]' using local 'compare_combchar()'> + <...until one pass yields no further canonical reordering> + + <...repeatedly traverse internal UCS-4, composing (NFC or NFKC)...> + <...with 'bsearch()' of 'uni2norm[]' using local 'compare_compose()'> + <...until one pass yields no further composition> + + + + + + 3.2.2.3. cupsUtf8CaseFold() + + /* + * Case Fold UTF-8 string per Unicode UAX-21 Section 2.3 + * Note - Case folding output is + * unsafe for subsequent transcoding to legacy charsets + */ + extern int cupsUtf8CaseFold(utf8_t *dest, /* O - Target string */ + const utf8_t *src, /* I - Source string */ + const int maxout, /* I - Max output */ + const cups_folding_t fold); /* I - Fold Mode */ + + + <...if not found, return '-1'> + + + McDonald June 20, 2002 [Page 25] + + CUPS Internationalization Software Design Description v0.3 + + + + + + + + + 3.2.2.4. cupsUtf32CaseFold() + + /* + * Case Fold UTF-32 string per Unicode UAX-21 Section 2.3 + * Note - Case folding output is + * unsafe for subsequent transcoding to legacy charsets + */ + extern int cupsUtf32CaseFold(utf32_t *dest, /* Target string */ + const utf32_t *src, /* Source string */ + const int maxout); /* Max output units */ + + + <...if not found, return '-1'> + + <...with 'bsearch()' of 'uni2fold[]' using local 'compare_foldchar()'> + + + + + + + 3.2.2.5. cupsUtf8CompareCaseless() + + /* + * Compare UTF-8 strings after case folding + */ + extern int cupsUtf8CompareCaseless(const utf8_t *s1, + /* I - String1 */ + const utf8_t *s2); /* I - String2 */ + + + + + + + 3.2.2.6. cupsUtf32CompareCaseless() + + /* + * Compare UTF-32 strings after case folding + */ + extern int cupsUtf32CompareCaseless(const utf32_t *s1, + /* I - String1 */ + const utf32_t *s2); /* I - String2 */ + + + + McDonald June 20, 2002 [Page 26] + + CUPS Internationalization Software Design Description v0.3 + + + + + + 3.2.2.7. cupsUtf8CompareIdentifier() + + /* + * Compare UTF-8 strings after case folding and NFKC normalization + */ + extern int cupsUtf8CompareIdentifier(const utf8_t *s1, + /* I - String1 */ + const utf8_t *s2); /* I - String2 */ + + + + + + + + + 3.2.2.8. cupsUtf32CompareIdentifier() + + /* + * Compare UTF-32 strings after case folding and NFKC normalization + */ + extern int cupsUtf32CompareIdentifier(const utf32_t *s1, + /* I - String1 */ + const utf32_t *s2); /* I - String2 */ + + + + + + + + 3.2.2.9. cupsUtf32CharacterProperty() + + /* + * Get UTF-32 character property + */ + extern int cupsUtf32CharacterProperty(const utf32_t ch, + /* I - Source char */ + const cups_property_t property); + /* I - Char Property */ + + <...internal + functions for each different map lookup> + + + + + + + McDonald June 20, 2002 [Page 27] + + CUPS Internationalization Software Design Description v0.3 + + + + 3.2.2.10. Normalization Utility Functions + + + + + 3.2.2.10.1. cupsNormalizeMapsGet() + + extern void cupsNormalizeMapsMapsGet(void); + + + <...If found, increment 'used'> + <...and return void> + + + <...If not found, return void> + + <...Close (preprocessed form of) Unicode data file> + + <...If not found, return void> + + <...If no memory, return void> + + + + + <...Add values to 'uni2xxx[]' array> + + + + + + 3.2.2.10.2. cupsNormalizeMapsFree() + + extern void cupsNormalizeMapsFree(void); + + + <...If found, decrement 'used'> + + + + + 3.2.2.10.3. cupsNormalizeMapsFlush() + + extern void cupsNormalizeMapsFlush(void); + + + <...Free 'uni2norm[]' memory> + <...Free normalize map memory> + + <...Free 'uni2fold[]' memory> + + McDonald June 20, 2002 [Page 28] + + CUPS Internationalization Software Design Description v0.3 + + <...Free case folding memory> + + <...Free 'uni2prop[]' memory> + <...Free char property map memory> + + <...Free 'uni2break[]' memory> + <...Free line break class map memory> + + <...Free 'uni2comb[]' memory> + <...Free combining class map memory> + + + + + 3.3. Language - Existing + + + + 3.3.1. language.h - Language header + + Required Changes: + + (1) Change definition of 'cups_lang_t' to correct length of 'language[]' + to 32 characters per [RFC3066] and [ISO639-2] and [ISO3166-1]. + + + + 3.3.2. language.c - Language module + + + + 3.3.2.1. cupsLangEncoding() - Existing + + [No Change] + + + + 3.3.2.2. cupsLangFlush() - Existing + + [No Change] + + + + 3.3.2.3. cupsLangFree() - Existing + + [No Change] + + + + + + + + McDonald June 20, 2002 [Page 29] + + CUPS Internationalization Software Design Description v0.3 + + + + 3.3.2.4. cupsLangGet() - Existing + + Required Changes: + + (1) Change length of 'langname[]' and 'real[]' to 64 characters per + [RFC3066] and potential length of encoding (charset) names; + (2) Change language string normalization to support: + (a) 8-character language codes per [RFC3066] and 3-character + language codes per [ISO639-2]; + (b) 8-character country codes per [RFC3066] and 3-character country + codes per [ISO3166-1]; + (c) Support for 'i' (IANA registered) and 'x' (private) language + prefixes per [RFC3066]; + (d) Invariant use of 'utf-8' for encoding in message catalog, but + save actual requested encoding name for later use. + (3) Correct broken do/while statement for message catalog lookup (while + condition is _never_ satisfied). + + + + 3.3.2.5. cupsLangPrintf() - New + + extern int cupsLangPrintf(FILE *fp, /* I - File to write */ + const cups_lang_t *lang, /* I - Language/locale*/ + const cups_msg_t msg, /* I - Msg to format */ + ...); /* I - Args to format */ + + + + + + + + + + + 3.3.2.6. cupsLangPuts() - New + + extern int cupsLangPuts(FILE *fp, /* I - File to write */ + const cups_lang_t *lang, /* I - Language/locale*/ + const cups_msg_t msg); /* I - Msg to write */ + + + + + + + + + + + McDonald June 20, 2002 [Page 30] + + CUPS Internationalization Software Design Description v0.3 + + + + 3.3.2.7. cupsEncodingName() - New + + extern char *cupsEncodingName(cups_encoding_t encoding); + + + + + + + 3.4. Common Text Filter - Existing + + + + 3.4.1. textcommon.h - Common text filter header + + Required changes: + + (1) Revise 'lchar_t' as specified below, adding 'attrx' bit-mask for + selected Unicode character properties; + (2) Revise 'lchar_t' as specified below, adding 'comblen' and 'combch[]' + for Unicode combining/attached chars (accents); + (3) Add 'COMBLEN_MAX' limit as specified below; + (4) Add 'ATTRX_...' selected Unicode character properties as specified + below. + + + + 3.4.1.1. lchar_t - Character/Attribute Structure + + typedef struct lchar_str /**** Character / Attribute Structure ****/ + { + unsigned short ch; /* Unicode Char as UCS-2 */ + /* or 8/16-bit Legacy Char */ + unsigned short attr; /* Attributes of Char */ + unsigned short attrx; /* Extended Attributes */ + unsigned short comblen; /* Combining Char Count */ + unsigned short combch[8]; /* Combining Chars as UCS-2 */ + } lchar_t; + + 'ch' is a 16-bit UCS-2 character or a 8/16-bit legacy char. 'attr' is + the character attributes defined for the existing 'lchar_t' structure + (defined in 'textcommon.h'). 'attrx' is the extended character + attributes defined for future selected Unicode character properties (see + below). 'comblen' is the number of attached/combining characters. + 'combch' is an array of 16-bit UCS-2 attached/combining characters. + + Add to 'textcommon.h' constants: + + COMBLEN_MAX 8 + + + McDonald June 20, 2002 [Page 31] + + CUPS Internationalization Software Design Description v0.3 + + + ATTRX_RIGHT2LEFT 0x0001 + + + + 3.4.2. textcommon.c - Common text filter + + Required Changes: + + (1) Revise 'TextMain()' function as described below. + + + + 3.4.2.1. TextMain() - Existing + + Required Changes: + + [Ed Note: Pseudo code below needs more work on bidi handling.] + + (1) In main loop at the _beginning_ of the 'default' clause, add the + following code for combining marks: + lchar_t *cp; + + cp = Page[line]; + cp += column; + /* + * Check for Unicode combining mark (accent) + */ + if (UTF-8 && cupsUtf32CombiningClass(ch) > 0) + { + + /* + * Save Unicode combining mark in SAME character + */ + if (cp->comblen > COMBLEN_MAX) + break; + cp->combch[cp->comblen] = ch; + cp->comblen ++; + break; + } + + (2) In main loop _after_ combining chars section in 'default' clause, + add the following code for Unicode bidi control characters + cups_bidicat_t bidicat; + + /* + * Check for Unicode bidi control character + */ + if (UTF-8) + { + bidicat = (cups_bidicat_t) + cupsUtf32CharacterProperty(ch, CUPS_PROP_BIDI_CATEGORY); + + McDonald June 20, 2002 [Page 32] + + CUPS Internationalization Software Design Description v0.3 + + if ((bidicat == CUPS_BIDI_LRE) /* Left-to-Right Embedding * + || (bidicat == CUPS_BIDI_LRO) /* Left-to-Right Override */ + || (bidicat == CUPS_BIDI_RLE) /* Right-to-Left Embedding * + || (bidicat == CUPS_BIDI_RLO) /* Right-to-Left Override */ + || (bidicat == CUPS_BIDI_PDF)) /* Pop Directional Format */ + { + /* Do bidi stuff here with memory for NEXT char's direction + /* Discard bidi control character and break */ + } + if ((bidicat == CUPS_BIDI_R) /* Right-to-Left Hebrew */ + || (bidicat == CUPS_BIDI_AL)) /* Right-to-Left Arabic */ + { + /* Set attrx for right-to-left */ + cp->attrx |= ATTRX_RIGHT2LEFT + } + } + + + + 3.4.2.2. compare_keywords() - Existing + + [No Change] + + + + 3.4.2.3. getutf8() - Existing + + [No Change] + + [Ed Note: Future - allow 20-bit UTF-32 code points - requires updates + in both 'textcommon.c' and 'texttops.c' for extended PostScript.] + + + + 3.5. Text to PostScript Filter - Existing + + + + 3.5.1. texttops.c - Text to PostScript filter + + Required Changes: + + (1) Revise local 'write_string()' function as described below. + + + + 3.5.1.1. main() - Existing + + [No Change] + + + + + McDonald June 20, 2002 [Page 33] + + CUPS Internationalization Software Design Description v0.3 + + + + 3.5.1.2. WriteEpilogue () - Existing + + [No Change] + + + + 3.5.1.3. WritePage () - Existing + + [No Change] + + + + 3.5.1.4. WriteProlog () - Existing + + [No Change] + + + + 3.5.1.5. write_line() - Existing + + [No Change] + + + + 3.5.1.6. write_string() - Existing + + Required Changes: + + (1) At the _beginning_ of Multiple Fonts section, _replace_ the while() + loop and surrounding 'putchar()' calls with the following code: + + for (; len > 0; len --, s ++) + { + utf32_t decstr[COMBLEN_MAX * 2]; + utf32_t cmpstr[COMBLEN_MAX * 2]; + int cmplen; + int i; + + if (s->comblen == 0) + { + printf("<%04x>", Chars[s->ch]); + continue; + } + + /* + * Normalize decomposed Unicode character to NFKC + * (compatibility decomposition, then canonical composition) + */ + decstr[0] = (utf32_t) s->ch; + for (i = 0; i < s->comblen; i ++) + + McDonald June 20, 2002 [Page 34] + + CUPS Internationalization Software Design Description v0.3 + + decstr[i + 1] = (utf32_t) s->combch[i]; + decstr[i] = 0; + cmplen = cupsUtf32Normalize (&cmpstr[0], + &decstr[0], COMBLEN_MAX * 2, CUPS_NORM_NFKC); + if (cmplen < 1) + continue; + + /* + * Write combining chars, then composed base, to same location + */ + for (i = 1; i < cmplen; i ++) + { + printf("<%04x>", Chars[(int) cmpstr[i]); + /* + * Superimpose glyphs by backing up one column width + */ + printf (" -%.3f ", (72.0f / (float) CharsPerInch)); + } + printf("<%04x>", Chars[(int) cmpstr[0]); + } + + [Ed Note: Future - Bidi support - When writing Unicode characters + (checking for explicit bidi) convert input string (lchar_t) to display + order???] + + + + 3.5.1.7. write_text() - Existing + + [No Change] + + + + + + + + + + + + + + + + + + + + + + + + McDonald June 20, 2002 [Page 35] + + CUPS Internationalization Software Design Description v0.3 + APPENDIX A + Glossary + + + + A. Glossary + + Abstract Character: A unit of information used for the organization, + control, or representation of textual data. + + Accent Mark: A mark placed above, below, or to the side of a character + to alter its phonetic value (also 'diacritic'). + + Alphabet: A collection of symbols that, in the context of a particular + written language, represent the sounds of that language. + + Base Character: A character that does not graphically combine with + preceding characters, and that is neither a control nor a format + character. + + Basic Multilingual Plane: The Unicode (or UCS) code values 0x0000 + through 0xFFFF, specified by [ISO10646] (also 'Plane 0'). + + BIDI: Abbreviation for Bidirectional, in reference to mixed + left-to-right and right-to-left text. + + Bidirectional Display: The process or result of mixing left-to-right + oriented text and right-to-left oriented text in a single line. + + Big-endian: A computer architecture that stores multiple-byte numerical + values with the most significant byte (MSB) values first. + + BMP: Abbreviation for Basic Multilingual Plane. + + BOM: Acronym for byte order mark (also 'ZWNBSP'). + + Byte Order Mark: The Unicode character U+FEFF Zero Width No-Break Space + (ZWNBSP) when used to indicate the byte order of text. + + Canonical: (1) Conforming to the general rules for encoding -- that is, + not compressed, compacted, or in any other form specified by a higher + protocol. (2) Characteristic of a normative mapping and form of + equivalence. + + Canonical Decomposition: The decomposition of a character that results + from recursively applying the canonical mappings defined in the Unicode + Character Database until no characters can be further decomposed, then + reordering nonspacing marks according to section 3.10 of [UNICODE3.2]. + + Canonical Equivalent: Two characters are canonical equivalents if their + full canonical decompositions are identical. + + Case: (1) Feature of certain alphabets wheere the letters have two + + McDonald June 20, 2002 [Page A-1] + + CUPS Internationalization Software Design Description v0.3 + APPENDIX A + Glossary + + distinct forms. These variants are called the 'uppercase' letter (also + known as 'capital' or 'majuscule') and the 'lowercase' letter (also + known as 'small' or 'minuscule'). (2) Normative property of Unicode + characters, consisting of uppercase, lowercase, and titlecase. + + Character: (1) The smallest component of written language that has + semantic value; refers to the abstract meaning and/or shape, rather than + a specific shape (see also 'glyph'). (2) Synonym for 'abstract + character'. (3) The basic unit of encoding for the Unicode character + encoding. (4) The English name for the ideographic written elements of + Chinese origin (see 'ideograph'). + + Character Encoding Form (CEF): Mapping from a character set definition + to the actual bits used to represent the data. + + Character Encoding Scheme (CES): A 'character encoding form' plus byte + serialization. [UNICODE3.2] defines seven character encoding schemes: + UTF-8, UTF-16, UTF-16BE, UTF-16LE, UTF-32, UTF-32BE, and UTF32-LE. + + Character Properties: A set of property names and property values + associated with individual characters defined in [UNICODE3.2]. + + Character Repertoire: (1) The collection of characters included in a + character set. (2) The SUBSET of characters included in a large + character set, e.g., [UNICODE3.2], that are necessary to support a + complete mapping to another smaller character set, e.g., ISO8859-1 (also + called 'Latin-1'). + + Character Set: A collection of elements used to represent textual + information. + + Coded Character Set: A character set in which each character is + assigned a numeric code value. Frequently abbreviated as 'character + set', 'charset', or 'code set'. + + Code Point: (1) A numerical index (or position) in an encoding table + used for encoding characters. (2) Synonym for 'Unicode scalar value'. + + Collation: The process of ordering units of textual information. + Collation is usually specific to a particular language. Also known as + 'alphabetizing' or 'alphabetic sorting'. + + Combining Character: A character that graphically combines with a + preceding 'base character'. The combining character is said to 'apply' + to that base character. (See also 'nonspacing mark'.) + + Compatibility: (1) Consistency with existing practice or preexisting + character encoding standards. (2) Characterisitic of a normative + mapping and form of equivalence (see 'compatibility decomposition'). + + + McDonald June 20, 2002 [Page A-2] + + CUPS Internationalization Software Design Description v0.3 + APPENDIX A + Glossary + + + Compatibility Character: A character that has a compatibility + decomposition. + + Compatibility Decomposition: The decomposition of a character that + results from recursively applying BOTH the compatibility mappings AND + the canonical mappings found in the Unicode Character Database until no + characters can be further decomposed, then reordering nonspacing marks + according to section 3.10 of [UNICODE3.2]. + + Compatibility Equivalent: Two characters are compatibility equivalents + if their full compatibility decompositions are identical. + + Composed Character: (See 'descomposable character'.) + + DBCS: Acronym for 'double-byte character set'. + + Decomposable Character: A character that is equivalent to a sequence of + one or more other characters, according to the decomposition mappings + found in [UNICODE3.2]. It may also be known as a 'precomposed + character' or a 'composite character'. + + Decomposition: (1) The process of separating or analyzing a text + element into component units. (2) A sequence of one or more characters + that is equivalent to a 'decomposable character'. + + Diacritic: (See 'accent mark'.) + + Double-Byte Character Set (DBCS): One of a number of character sets + defined for representing Chinese, Japanese, or Korean text (for example, + JIS X 0208-1990). These character sets are often encoded in such a way + as to allow double-byte character encodings to be mixed with single-byte + character encodings. (See also 'multiple-byte character set'.) + + Font: A collection of glyphs used for visual depication of character + data. + + FSS-UTF: Abbreviation for 'File System Safe UCS Transformation Format', + originally published by X/Open. Now called 'UTF-8'. + + Fullwidth: Characters of East Asian character sets whose glyph image + extends across the entire character display cell. In legacy character + sets, fullwidth characters are normally encoded in two or three bytes. + + Glyph: (1) An abstract form that represents one or more glyph images. + (2) A synonym for 'glyph image'. + + Glyph Image: The actual, concrete image of a glyph representation + having been rasterized or otherwise images onto some display surface. + + + McDonald June 20, 2002 [Page A-3] + + CUPS Internationalization Software Design Description v0.3 + APPENDIX A + Glossary + + + Halfwidth: Characters of East Asian character sets whose glyph image + occupies half of the character display cell. In legacy character sets, + halfwidth characters are normally encoded in a single byte. + + Han Characters: Ideographic characters of Chinese origin. + + Hangul: The name of the script used to write the Korean language. + + High-Surrogate: A Unicode code value in the range U+D800 to U+DBFF. + + Hiragana: One of two standard syllabaries associated with the Japanese + writing system. Use to write particles, grammatical affixes, and words + that have no 'kanji' form. + + IANA: Internet Assigned Numbers Authority. + + Ideograph: (1) Any symbol that denotes an idea (or meaning) in contrast + to a sound or pronunciation (for example, a 'smiley face'). (2) A + common term used to refer to Han characters. + + IPA: International Phonetic Alphabet. + + IRG: Abbreviation for Ideographic Rapporteur Group, a subgroup of + ISO/IEC JTC1/SC2/WG2 (who work on Han unification and submission of new + Han characters for inclusion in revised versions of Unicode/ISO 10646). + + Jamo: The Korean name for a single letter of the Hangul script. Jamos + are used to form Hangul syllables. + + Joiner: An invisible character that affects the joining behavior of + surrounding characters. + + JTC1: Abbreviation for Joint Technical Committee 1 of ISO/IEC, + responsible for information technology standardization. + + Kana: The name of a primarily syllabic script used by the Japanese + writing system, composed of 'hiragana' and 'katakana'. + + Kanji: The Japanese name for Han characters; derived from the Chinese + word 'hanzi'. Also romanized as 'kanzi'. + + Katakana: One of two standard syllabaries associated with the Japanese + writing system, typically used in representation of borrowed vocabulary. + + Ligature: A glyph representing a combination of two or more characters, + for example in the Latin script the ligature between 'f' and 'i' as + 'fi'. + + Logical Order: The order in which text is typed on a keyboard. For the + + McDonald June 20, 2002 [Page A-4] + + CUPS Internationalization Software Design Description v0.3 + APPENDIX A + Glossary + + most part, logical order corresponds to phonetic order. + + Lowercase: (See 'case'.) + + Low-Surrogate: A Unicode code value in the range U+DC00 to U+DFFF. + + MBCS: Acronym for 'multiple-byte character set'. + + Multiple-Byte Character Set (MBCS): A character set encoded with a + variable number of bytes per character. Many large character sets have + been defined as MBCS so as to keep strict compatibility with the + US-ASCII subset and/or [ISO2022]. + + Normalization: Transformation of data to a normal form. + + Plain Text: Computer-encoded text that consists ONLY of a sequence of + code values from a given standard, with no other formatting or + structural information. + + Precomposed Character: (See 'decomposable character'.) + + Rendering: (1) The process of selecting and laying out glyphs for the + purpose of depicting characters. (2) The process of making glyphs + visible on a display device. + + Repertoire: (See 'character repertoire'.) + + Replacement Character: A character used as a substitute for an + uninterpretable character from another encoding. [UNICODE3.2] defines + U+FFFD REPLACEMENT CHARACTER for this function. + + Rich Text: The result of adding information such as font data, color, + formatting, phonetic annotations, etc. to 'plain text' (e.g., HTML). + + SBCS: Acronym for 'single-byte character set'. + + Scalar Value: (See 'Unicode scalar value'.) + + Script: A collection of symbols used to represent textual information + in one or more writing systems. + + Single-Byte Character Set (SBCS): One of a number of one-byte character + sets defined for representing (mostly) Western languages (for example, + ISO 8859-1 'Latin-1'). These character sets are often encoded in such a + way as to be strict supersets of 7-bit [US-ASCII]. + + Sorting: (See 'collation'.) + + Transcoding: Conversion of character data between different character + sets. + + McDonald June 20, 2002 [Page A-5] + + CUPS Internationalization Software Design Description v0.3 + APPENDIX A + Glossary + + + Transformation Format: A mapping from a coded character sequence to a + unique sequence of code values (typically octets). + + UCS: Abbreviation for Universal Character Set, specified by [ISO10646]. + + UCS-2: UCS encoded in 2 octets, specified by [ISO10646]. + + UCS-4: UCS encoded in 4 octets, specified by [ISO10646]. + + Unicode Scalar Value: A number between 0 to 0x10FFFF. + + Uppercase: (See 'case'.) + + UTF: Abbreviation for Unicode (or UCS) Transformation Format. + + UTF-8: Unicode (or UCS) Transformation Format, 8-bit encoding form. + Serializes a Unicode (or UCS) scalar value (code point) as a sequence of + one to four octets. Does NOT suffer from byte-ordering ambiguities. + + UTF-16: Unicode (or UCS) Transformation Format, 16-bit encoding form. + Serializes a Unicode (or UCS) scalar value (code point) as a sequence of + two octets, in either big-endian or little-endian format. Uses an + (optional) prefix of BOM to disambiguate byte-ordering. + + UTF-32: Unicode (or UCS) Transformation Format, 32-bit encoding form. + Serializes a Unicode (or UCS) scalar value (code point) as a sequence of + four octets, in either big-endian or little-endian format. Uses an + (optional) prefix of BOM to disambiguate byte-ordering. + + Zero Width: Characteristic of some spaces or format control characters + that do not advance text along the horizontal baseline. + + + + + + + + + + + + + + + + + + + + McDonald June 20, 2002 [Page A-6] 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-1.txt b/data/iso-8859-1.txt new file mode 100644 index 000000000..473ecabc1 --- /dev/null +++ b/data/iso-8859-1.txt @@ -0,0 +1,303 @@ +# +# Name: ISO/IEC 8859-1:1998 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-1:1998 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-1 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-1 order. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x00A1 # INVERTED EXCLAMATION MARK +0xA2 0x00A2 # CENT SIGN +0xA3 0x00A3 # POUND SIGN +0xA4 0x00A4 # CURRENCY SIGN +0xA5 0x00A5 # YEN SIGN +0xA6 0x00A6 # BROKEN BAR +0xA7 0x00A7 # SECTION SIGN +0xA8 0x00A8 # DIAERESIS +0xA9 0x00A9 # COPYRIGHT SIGN +0xAA 0x00AA # FEMININE ORDINAL INDICATOR +0xAB 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC # NOT SIGN +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x00AE # REGISTERED SIGN +0xAF 0x00AF # MACRON +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x00B1 # PLUS-MINUS SIGN +0xB2 0x00B2 # SUPERSCRIPT TWO +0xB3 0x00B3 # SUPERSCRIPT THREE +0xB4 0x00B4 # ACUTE ACCENT +0xB5 0x00B5 # MICRO SIGN +0xB6 0x00B6 # PILCROW SIGN +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x00B8 # CEDILLA +0xB9 0x00B9 # SUPERSCRIPT ONE +0xBA 0x00BA # MASCULINE ORDINAL INDICATOR +0xBB 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC # VULGAR FRACTION ONE QUARTER +0xBD 0x00BD # VULGAR FRACTION ONE HALF +0xBE 0x00BE # VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF # INVERTED QUESTION MARK +0xC0 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 # LATIN CAPITAL LETTER AE +0xC7 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x00D0 # LATIN CAPITAL LETTER ETH (Icelandic) +0xD1 0x00D1 # LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 # MULTIPLICATION SIGN +0xD8 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x00DD # LATIN CAPITAL LETTER Y WITH ACUTE +0xDE 0x00DE # LATIN CAPITAL LETTER THORN (Icelandic) +0xDF 0x00DF # LATIN SMALL LETTER SHARP S (German) +0xE0 0x00E0 # LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 # LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 # LATIN SMALL LETTER AE +0xE7 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 # LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC # LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x00F0 # LATIN SMALL LETTER ETH (Icelandic) +0xF1 0x00F1 # LATIN SMALL LETTER N WITH TILDE +0xF2 0x00F2 # LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 # LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 # DIVISION SIGN +0xF8 0x00F8 # LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 # LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x00FD # LATIN SMALL LETTER Y WITH ACUTE +0xFE 0x00FE # LATIN SMALL LETTER THORN (Icelandic) +0xFF 0x00FF # LATIN SMALL LETTER Y WITH DIAERESIS 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-10.txt b/data/iso-8859-10.txt new file mode 100644 index 000000000..374a42b1a --- /dev/null +++ b/data/iso-8859-10.txt @@ -0,0 +1,303 @@ +# +# Name: ISO/IEC 8859-10:1998 to Unicode +# Unicode version: 3.0 +# Table version: 1.1 +# Table format: Format A +# Date: 1999 October 11 +# Authors: Ken Whistler +# +# Copyright (c) 1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-10:1998 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-10 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-10 order. +# +# Version history +# 1.0 version new. +# 1.1 corrected mistake in mapping of 0xA4 +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x0104 # LATIN CAPITAL LETTER A WITH OGONEK +0xA2 0x0112 # LATIN CAPITAL LETTER E WITH MACRON +0xA3 0x0122 # LATIN CAPITAL LETTER G WITH CEDILLA +0xA4 0x012A # LATIN CAPITAL LETTER I WITH MACRON +0xA5 0x0128 # LATIN CAPITAL LETTER I WITH TILDE +0xA6 0x0136 # LATIN CAPITAL LETTER K WITH CEDILLA +0xA7 0x00A7 # SECTION SIGN +0xA8 0x013B # LATIN CAPITAL LETTER L WITH CEDILLA +0xA9 0x0110 # LATIN CAPITAL LETTER D WITH STROKE +0xAA 0x0160 # LATIN CAPITAL LETTER S WITH CARON +0xAB 0x0166 # LATIN CAPITAL LETTER T WITH STROKE +0xAC 0x017D # LATIN CAPITAL LETTER Z WITH CARON +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x016A # LATIN CAPITAL LETTER U WITH MACRON +0xAF 0x014A # LATIN CAPITAL LETTER ENG +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x0105 # LATIN SMALL LETTER A WITH OGONEK +0xB2 0x0113 # LATIN SMALL LETTER E WITH MACRON +0xB3 0x0123 # LATIN SMALL LETTER G WITH CEDILLA +0xB4 0x012B # LATIN SMALL LETTER I WITH MACRON +0xB5 0x0129 # LATIN SMALL LETTER I WITH TILDE +0xB6 0x0137 # LATIN SMALL LETTER K WITH CEDILLA +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x013C # LATIN SMALL LETTER L WITH CEDILLA +0xB9 0x0111 # LATIN SMALL LETTER D WITH STROKE +0xBA 0x0161 # LATIN SMALL LETTER S WITH CARON +0xBB 0x0167 # LATIN SMALL LETTER T WITH STROKE +0xBC 0x017E # LATIN SMALL LETTER Z WITH CARON +0xBD 0x2015 # HORIZONTAL BAR +0xBE 0x016B # LATIN SMALL LETTER U WITH MACRON +0xBF 0x014B # LATIN SMALL LETTER ENG +0xC0 0x0100 # LATIN CAPITAL LETTER A WITH MACRON +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 # LATIN CAPITAL LETTER AE +0xC7 0x012E # LATIN CAPITAL LETTER I WITH OGONEK +0xC8 0x010C # LATIN CAPITAL LETTER C WITH CARON +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x0118 # LATIN CAPITAL LETTER E WITH OGONEK +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x0116 # LATIN CAPITAL LETTER E WITH DOT ABOVE +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x00D0 # LATIN CAPITAL LETTER ETH (Icelandic) +0xD1 0x0145 # LATIN CAPITAL LETTER N WITH CEDILLA +0xD2 0x014C # LATIN CAPITAL LETTER O WITH MACRON +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x0168 # LATIN CAPITAL LETTER U WITH TILDE +0xD8 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x0172 # LATIN CAPITAL LETTER U WITH OGONEK +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x00DD # LATIN CAPITAL LETTER Y WITH ACUTE +0xDE 0x00DE # LATIN CAPITAL LETTER THORN (Icelandic) +0xDF 0x00DF # LATIN SMALL LETTER SHARP S (German) +0xE0 0x0101 # LATIN SMALL LETTER A WITH MACRON +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 # LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 # LATIN SMALL LETTER AE +0xE7 0x012F # LATIN SMALL LETTER I WITH OGONEK +0xE8 0x010D # LATIN SMALL LETTER C WITH CARON +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x0119 # LATIN SMALL LETTER E WITH OGONEK +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x0117 # LATIN SMALL LETTER E WITH DOT ABOVE +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x00F0 # LATIN SMALL LETTER ETH (Icelandic) +0xF1 0x0146 # LATIN SMALL LETTER N WITH CEDILLA +0xF2 0x014D # LATIN SMALL LETTER O WITH MACRON +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 # LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x0169 # LATIN SMALL LETTER U WITH TILDE +0xF8 0x00F8 # LATIN SMALL LETTER O WITH STROKE +0xF9 0x0173 # LATIN SMALL LETTER U WITH OGONEK +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x00FD # LATIN SMALL LETTER Y WITH ACUTE +0xFE 0x00FE # LATIN SMALL LETTER THORN (Icelandic) +0xFF 0x0138 # LATIN SMALL LETTER KRA diff --git a/data/iso-8859-11.txt b/data/iso-8859-11.txt new file mode 100644 index 000000000..cfbcc5fdf --- /dev/null +++ b/data/iso-8859-11.txt @@ -0,0 +1,249 @@ +# 8859-11.txt - Legacy SBCS to Unicode charmap +0x00 0x0000 # 0 +0x01 0x0001 # 0 +0x02 0x0002 # 0 +0x03 0x0003 # 0 +0x04 0x0004 # 0 +0x05 0x0005 # 0 +0x06 0x0006 # 0 +0x07 0x0007 # 0 +0x08 0x0008 # 0 +0x09 0x0009 # 0 +0x0A 0x000A # 0 +0x0B 0x000B # 0 +0x0C 0x000C # 0 +0x0D 0x000D # 0 +0x0E 0x000E # 0 +0x0F 0x000F # 0 +0x10 0x0010 # 0 +0x11 0x0011 # 0 +0x12 0x0012 # 0 +0x13 0x0013 # 0 +0x14 0x0014 # 0 +0x15 0x0015 # 0 +0x16 0x0016 # 0 +0x17 0x0017 # 0 +0x18 0x0018 # 0 +0x19 0x0019 # 0 +0x1A 0x001A # 0 +0x1B 0x001B # 0 +0x1C 0x001C # 0 +0x1D 0x001D # 0 +0x1E 0x001E # 0 +0x1F 0x001F # 0 +0x20 0x0020 # 0 +0x21 0x0021 # 0 +0x22 0x0022 # 0 +0x23 0x0023 # 0 +0x24 0x0024 # 0 +0x25 0x0025 # 0 +0x26 0x0026 # 0 +0x27 0x0027 # 0 +0x28 0x0028 # 0 +0x29 0x0029 # 0 +0x2A 0x002A # 0 +0x2B 0x002B # 0 +0x2C 0x002C # 0 +0x2D 0x002D # 0 +0x2E 0x002E # 0 +0x2F 0x002F # 0 +0x30 0x0030 # 0 +0x31 0x0031 # 0 +0x32 0x0032 # 0 +0x33 0x0033 # 0 +0x34 0x0034 # 0 +0x35 0x0035 # 0 +0x36 0x0036 # 0 +0x37 0x0037 # 0 +0x38 0x0038 # 0 +0x39 0x0039 # 0 +0x3A 0x003A # 0 +0x3B 0x003B # 0 +0x3C 0x003C # 0 +0x3D 0x003D # 0 +0x3E 0x003E # 0 +0x3F 0x003F # 0 +0x40 0x0040 # 0 +0x41 0x0041 # 0 +0x42 0x0042 # 0 +0x43 0x0043 # 0 +0x44 0x0044 # 0 +0x45 0x0045 # 0 +0x46 0x0046 # 0 +0x47 0x0047 # 0 +0x48 0x0048 # 0 +0x49 0x0049 # 0 +0x4A 0x004A # 0 +0x4B 0x004B # 0 +0x4C 0x004C # 0 +0x4D 0x004D # 0 +0x4E 0x004E # 0 +0x4F 0x004F # 0 +0x50 0x0050 # 0 +0x51 0x0051 # 0 +0x52 0x0052 # 0 +0x53 0x0053 # 0 +0x54 0x0054 # 0 +0x55 0x0055 # 0 +0x56 0x0056 # 0 +0x57 0x0057 # 0 +0x58 0x0058 # 0 +0x59 0x0059 # 0 +0x5A 0x005A # 0 +0x5B 0x005B # 0 +0x5C 0x005C # 0 +0x5D 0x005D # 0 +0x5E 0x005E # 0 +0x5F 0x005F # 0 +0x60 0x0060 # 0 +0x61 0x0061 # 0 +0x62 0x0062 # 0 +0x63 0x0063 # 0 +0x64 0x0064 # 0 +0x65 0x0065 # 0 +0x66 0x0066 # 0 +0x67 0x0067 # 0 +0x68 0x0068 # 0 +0x69 0x0069 # 0 +0x6A 0x006A # 0 +0x6B 0x006B # 0 +0x6C 0x006C # 0 +0x6D 0x006D # 0 +0x6E 0x006E # 0 +0x6F 0x006F # 0 +0x70 0x0070 # 0 +0x71 0x0071 # 0 +0x72 0x0072 # 0 +0x73 0x0073 # 0 +0x74 0x0074 # 0 +0x75 0x0075 # 0 +0x76 0x0076 # 0 +0x77 0x0077 # 0 +0x78 0x0078 # 0 +0x79 0x0079 # 0 +0x7A 0x007A # 0 +0x7B 0x007B # 0 +0x7C 0x007C # 0 +0x7D 0x007D # 0 +0x7E 0x007E # 0 +0x7F 0x007F # 0 +0x80 0x0080 # 0 +0x81 0x0081 # 0 +0x82 0x0082 # 0 +0x83 0x0083 # 0 +0x84 0x0084 # 0 +0x85 0x0085 # 0 +0x86 0x0086 # 0 +0x87 0x0087 # 0 +0x88 0x0088 # 0 +0x89 0x0089 # 0 +0x8A 0x008A # 0 +0x8B 0x008B # 0 +0x8C 0x008C # 0 +0x8D 0x008D # 0 +0x8E 0x008E # 0 +0x8F 0x008F # 0 +0x90 0x0090 # 0 +0x91 0x0091 # 0 +0x92 0x0092 # 0 +0x93 0x0093 # 0 +0x94 0x0094 # 0 +0x95 0x0095 # 0 +0x96 0x0096 # 0 +0x97 0x0097 # 0 +0x98 0x0098 # 0 +0x99 0x0099 # 0 +0x9A 0x009A # 0 +0x9B 0x009B # 0 +0x9C 0x009C # 0 +0x9D 0x009D # 0 +0x9E 0x009E # 0 +0x9F 0x009F # 0 +0xA0 0x00A0 # 0 +0xA1 0x0E01 # 0 +0xA2 0x0E02 # 0 +0xA3 0x0E03 # 0 +0xA4 0x0E04 # 0 +0xA5 0x0E05 # 0 +0xA6 0x0E06 # 0 +0xA7 0x0E07 # 0 +0xA8 0x0E08 # 0 +0xA9 0x0E09 # 0 +0xAA 0x0E0A # 0 +0xAB 0x0E0B # 0 +0xAC 0x0E0C # 0 +0xAD 0x0E0D # 0 +0xAE 0x0E0E # 0 +0xAF 0x0E0F # 0 +0xB0 0x0E10 # 0 +0xB1 0x0E11 # 0 +0xB2 0x0E12 # 0 +0xB3 0x0E13 # 0 +0xB4 0x0E14 # 0 +0xB5 0x0E15 # 0 +0xB6 0x0E16 # 0 +0xB7 0x0E17 # 0 +0xB8 0x0E18 # 0 +0xB9 0x0E19 # 0 +0xBA 0x0E1A # 0 +0xBB 0x0E1B # 0 +0xBC 0x0E1C # 0 +0xBD 0x0E1D # 0 +0xBE 0x0E1E # 0 +0xBF 0x0E1F # 0 +0xC0 0x0E20 # 0 +0xC1 0x0E21 # 0 +0xC2 0x0E22 # 0 +0xC3 0x0E23 # 0 +0xC4 0x0E24 # 0 +0xC5 0x0E25 # 0 +0xC6 0x0E26 # 0 +0xC7 0x0E27 # 0 +0xC8 0x0E28 # 0 +0xC9 0x0E29 # 0 +0xCA 0x0E2A # 0 +0xCB 0x0E2B # 0 +0xCC 0x0E2C # 0 +0xCD 0x0E2D # 0 +0xCE 0x0E2E # 0 +0xCF 0x0E2F # 0 +0xD0 0x0E30 # 0 +0xD1 0x0E31 # 0 +0xD2 0x0E32 # 0 +0xD3 0x0E33 # 0 +0xD4 0x0E34 # 0 +0xD5 0x0E35 # 0 +0xD6 0x0E36 # 0 +0xD7 0x0E37 # 0 +0xD8 0x0E38 # 0 +0xD9 0x0E39 # 0 +0xDA 0x0E3A # 0 +0xDF 0x0E3F # 0 +0xE0 0x0E40 # 0 +0xE1 0x0E41 # 0 +0xE2 0x0E42 # 0 +0xE3 0x0E43 # 0 +0xE4 0x0E44 # 0 +0xE5 0x0E45 # 0 +0xE6 0x0E46 # 0 +0xE7 0x0E47 # 0 +0xE8 0x0E48 # 0 +0xE9 0x0E49 # 0 +0xEA 0x0E4A # 0 +0xEB 0x0E4B # 0 +0xEC 0x0E4C # 0 +0xED 0x0E4D # 0 +0xEE 0x0E4E # 0 +0xEF 0x0E4F # 0 +0xF0 0x0E50 # 0 +0xF1 0x0E51 # 0 +0xF2 0x0E52 # 0 +0xF3 0x0E53 # 0 +0xF4 0x0E54 # 0 +0xF5 0x0E55 # 0 +0xF6 0x0E56 # 0 +0xF7 0x0E57 # 0 +0xF8 0x0E58 # 0 +0xF9 0x0E59 # 0 +0xFA 0x0E5A # 0 +0xFB 0x0E5B # 0 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-13.txt b/data/iso-8859-13.txt new file mode 100644 index 000000000..cd11b53fd --- /dev/null +++ b/data/iso-8859-13.txt @@ -0,0 +1,299 @@ +# +# Name: ISO/IEC 8859-13:1998 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1998 - 1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-13:1998 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-13 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-13 order. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x201D # RIGHT DOUBLE QUOTATION MARK +0xA2 0x00A2 # CENT SIGN +0xA3 0x00A3 # POUND SIGN +0xA4 0x00A4 # CURRENCY SIGN +0xA5 0x201E # DOUBLE LOW-9 QUOTATION MARK +0xA6 0x00A6 # BROKEN BAR +0xA7 0x00A7 # SECTION SIGN +0xA8 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE +0xA9 0x00A9 # COPYRIGHT SIGN +0xAA 0x0156 # LATIN CAPITAL LETTER R WITH CEDILLA +0xAB 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC # NOT SIGN +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x00AE # REGISTERED SIGN +0xAF 0x00C6 # LATIN CAPITAL LETTER AE +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x00B1 # PLUS-MINUS SIGN +0xB2 0x00B2 # SUPERSCRIPT TWO +0xB3 0x00B3 # SUPERSCRIPT THREE +0xB4 0x201C # LEFT DOUBLE QUOTATION MARK +0xB5 0x00B5 # MICRO SIGN +0xB6 0x00B6 # PILCROW SIGN +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x00F8 # LATIN SMALL LETTER O WITH STROKE +0xB9 0x00B9 # SUPERSCRIPT ONE +0xBA 0x0157 # LATIN SMALL LETTER R WITH CEDILLA +0xBB 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC # VULGAR FRACTION ONE QUARTER +0xBD 0x00BD # VULGAR FRACTION ONE HALF +0xBE 0x00BE # VULGAR FRACTION THREE QUARTERS +0xBF 0x00E6 # LATIN SMALL LETTER AE +0xC0 0x0104 # LATIN CAPITAL LETTER A WITH OGONEK +0xC1 0x012E # LATIN CAPITAL LETTER I WITH OGONEK +0xC2 0x0100 # LATIN CAPITAL LETTER A WITH MACRON +0xC3 0x0106 # LATIN CAPITAL LETTER C WITH ACUTE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x0118 # LATIN CAPITAL LETTER E WITH OGONEK +0xC7 0x0112 # LATIN CAPITAL LETTER E WITH MACRON +0xC8 0x010C # LATIN CAPITAL LETTER C WITH CARON +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x0179 # LATIN CAPITAL LETTER Z WITH ACUTE +0xCB 0x0116 # LATIN CAPITAL LETTER E WITH DOT ABOVE +0xCC 0x0122 # LATIN CAPITAL LETTER G WITH CEDILLA +0xCD 0x0136 # LATIN CAPITAL LETTER K WITH CEDILLA +0xCE 0x012A # LATIN CAPITAL LETTER I WITH MACRON +0xCF 0x013B # LATIN CAPITAL LETTER L WITH CEDILLA +0xD0 0x0160 # LATIN CAPITAL LETTER S WITH CARON +0xD1 0x0143 # LATIN CAPITAL LETTER N WITH ACUTE +0xD2 0x0145 # LATIN CAPITAL LETTER N WITH CEDILLA +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x014C # LATIN CAPITAL LETTER O WITH MACRON +0xD5 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 # MULTIPLICATION SIGN +0xD8 0x0172 # LATIN CAPITAL LETTER U WITH OGONEK +0xD9 0x0141 # LATIN CAPITAL LETTER L WITH STROKE +0xDA 0x015A # LATIN CAPITAL LETTER S WITH ACUTE +0xDB 0x016A # LATIN CAPITAL LETTER U WITH MACRON +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x017B # LATIN CAPITAL LETTER Z WITH DOT ABOVE +0xDE 0x017D # LATIN CAPITAL LETTER Z WITH CARON +0xDF 0x00DF # LATIN SMALL LETTER SHARP S (German) +0xE0 0x0105 # LATIN SMALL LETTER A WITH OGONEK +0xE1 0x012F # LATIN SMALL LETTER I WITH OGONEK +0xE2 0x0101 # LATIN SMALL LETTER A WITH MACRON +0xE3 0x0107 # LATIN SMALL LETTER C WITH ACUTE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x0119 # LATIN SMALL LETTER E WITH OGONEK +0xE7 0x0113 # LATIN SMALL LETTER E WITH MACRON +0xE8 0x010D # LATIN SMALL LETTER C WITH CARON +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x017A # LATIN SMALL LETTER Z WITH ACUTE +0xEB 0x0117 # LATIN SMALL LETTER E WITH DOT ABOVE +0xEC 0x0123 # LATIN SMALL LETTER G WITH CEDILLA +0xED 0x0137 # LATIN SMALL LETTER K WITH CEDILLA +0xEE 0x012B # LATIN SMALL LETTER I WITH MACRON +0xEF 0x013C # LATIN SMALL LETTER L WITH CEDILLA +0xF0 0x0161 # LATIN SMALL LETTER S WITH CARON +0xF1 0x0144 # LATIN SMALL LETTER N WITH ACUTE +0xF2 0x0146 # LATIN SMALL LETTER N WITH CEDILLA +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x014D # LATIN SMALL LETTER O WITH MACRON +0xF5 0x00F5 # LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 # DIVISION SIGN +0xF8 0x0173 # LATIN SMALL LETTER U WITH OGONEK +0xF9 0x0142 # LATIN SMALL LETTER L WITH STROKE +0xFA 0x015B # LATIN SMALL LETTER S WITH ACUTE +0xFB 0x016B # LATIN SMALL LETTER U WITH MACRON +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x017C # LATIN SMALL LETTER Z WITH DOT ABOVE +0xFE 0x017E # LATIN SMALL LETTER Z WITH CARON +0xFF 0x2019 # RIGHT SINGLE QUOTATION MARK 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-14.txt b/data/iso-8859-14.txt new file mode 100644 index 000000000..36038f413 --- /dev/null +++ b/data/iso-8859-14.txt @@ -0,0 +1,301 @@ +# +# Name: ISO/IEC 8859-14:1998 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Markus Kuhn +# Ken Whistler +# +# Copyright (c) 1998 - 1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-14:1998 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-14 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-14 order. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x1E02 # LATIN CAPITAL LETTER B WITH DOT ABOVE +0xA2 0x1E03 # LATIN SMALL LETTER B WITH DOT ABOVE +0xA3 0x00A3 # POUND SIGN +0xA4 0x010A # LATIN CAPITAL LETTER C WITH DOT ABOVE +0xA5 0x010B # LATIN SMALL LETTER C WITH DOT ABOVE +0xA6 0x1E0A # LATIN CAPITAL LETTER D WITH DOT ABOVE +0xA7 0x00A7 # SECTION SIGN +0xA8 0x1E80 # LATIN CAPITAL LETTER W WITH GRAVE +0xA9 0x00A9 # COPYRIGHT SIGN +0xAA 0x1E82 # LATIN CAPITAL LETTER W WITH ACUTE +0xAB 0x1E0B # LATIN SMALL LETTER D WITH DOT ABOVE +0xAC 0x1EF2 # LATIN CAPITAL LETTER Y WITH GRAVE +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x00AE # REGISTERED SIGN +0xAF 0x0178 # LATIN CAPITAL LETTER Y WITH DIAERESIS +0xB0 0x1E1E # LATIN CAPITAL LETTER F WITH DOT ABOVE +0xB1 0x1E1F # LATIN SMALL LETTER F WITH DOT ABOVE +0xB2 0x0120 # LATIN CAPITAL LETTER G WITH DOT ABOVE +0xB3 0x0121 # LATIN SMALL LETTER G WITH DOT ABOVE +0xB4 0x1E40 # LATIN CAPITAL LETTER M WITH DOT ABOVE +0xB5 0x1E41 # LATIN SMALL LETTER M WITH DOT ABOVE +0xB6 0x00B6 # PILCROW SIGN +0xB7 0x1E56 # LATIN CAPITAL LETTER P WITH DOT ABOVE +0xB8 0x1E81 # LATIN SMALL LETTER W WITH GRAVE +0xB9 0x1E57 # LATIN SMALL LETTER P WITH DOT ABOVE +0xBA 0x1E83 # LATIN SMALL LETTER W WITH ACUTE +0xBB 0x1E60 # LATIN CAPITAL LETTER S WITH DOT ABOVE +0xBC 0x1EF3 # LATIN SMALL LETTER Y WITH GRAVE +0xBD 0x1E84 # LATIN CAPITAL LETTER W WITH DIAERESIS +0xBE 0x1E85 # LATIN SMALL LETTER W WITH DIAERESIS +0xBF 0x1E61 # LATIN SMALL LETTER S WITH DOT ABOVE +0xC0 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 # LATIN CAPITAL LETTER AE +0xC7 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x0174 # LATIN CAPITAL LETTER W WITH CIRCUMFLEX +0xD1 0x00D1 # LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x1E6A # LATIN CAPITAL LETTER T WITH DOT ABOVE +0xD8 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x00DD # LATIN CAPITAL LETTER Y WITH ACUTE +0xDE 0x0176 # LATIN CAPITAL LETTER Y WITH CIRCUMFLEX +0xDF 0x00DF # LATIN SMALL LETTER SHARP S +0xE0 0x00E0 # LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 # LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 # LATIN SMALL LETTER AE +0xE7 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 # LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC # LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x0175 # LATIN SMALL LETTER W WITH CIRCUMFLEX +0xF1 0x00F1 # LATIN SMALL LETTER N WITH TILDE +0xF2 0x00F2 # LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 # LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x1E6B # LATIN SMALL LETTER T WITH DOT ABOVE +0xF8 0x00F8 # LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 # LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x00FD # LATIN SMALL LETTER Y WITH ACUTE +0xFE 0x0177 # LATIN SMALL LETTER Y WITH CIRCUMFLEX +0xFF 0x00FF # LATIN SMALL LETTER Y WITH DIAERESIS + 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-15.txt b/data/iso-8859-15.txt new file mode 100644 index 000000000..1e319707d --- /dev/null +++ b/data/iso-8859-15.txt @@ -0,0 +1,303 @@ +# +# Name: ISO/IEC 8859-15:1999 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Markus Kuhn +# Ken Whistler +# +# Copyright (c) 1998 - 1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-15:1999 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-15 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-15 order. +# +# Version history +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x00A1 # INVERTED EXCLAMATION MARK +0xA2 0x00A2 # CENT SIGN +0xA3 0x00A3 # POUND SIGN +0xA4 0x20AC # EURO SIGN +0xA5 0x00A5 # YEN SIGN +0xA6 0x0160 # LATIN CAPITAL LETTER S WITH CARON +0xA7 0x00A7 # SECTION SIGN +0xA8 0x0161 # LATIN SMALL LETTER S WITH CARON +0xA9 0x00A9 # COPYRIGHT SIGN +0xAA 0x00AA # FEMININE ORDINAL INDICATOR +0xAB 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC # NOT SIGN +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x00AE # REGISTERED SIGN +0xAF 0x00AF # MACRON +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x00B1 # PLUS-MINUS SIGN +0xB2 0x00B2 # SUPERSCRIPT TWO +0xB3 0x00B3 # SUPERSCRIPT THREE +0xB4 0x017D # LATIN CAPITAL LETTER Z WITH CARON +0xB5 0x00B5 # MICRO SIGN +0xB6 0x00B6 # PILCROW SIGN +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x017E # LATIN SMALL LETTER Z WITH CARON +0xB9 0x00B9 # SUPERSCRIPT ONE +0xBA 0x00BA # MASCULINE ORDINAL INDICATOR +0xBB 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x0152 # LATIN CAPITAL LIGATURE OE +0xBD 0x0153 # LATIN SMALL LIGATURE OE +0xBE 0x0178 # LATIN CAPITAL LETTER Y WITH DIAERESIS +0xBF 0x00BF # INVERTED QUESTION MARK +0xC0 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 # LATIN CAPITAL LETTER AE +0xC7 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x00D0 # LATIN CAPITAL LETTER ETH +0xD1 0x00D1 # LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 # MULTIPLICATION SIGN +0xD8 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x00DD # LATIN CAPITAL LETTER Y WITH ACUTE +0xDE 0x00DE # LATIN CAPITAL LETTER THORN +0xDF 0x00DF # LATIN SMALL LETTER SHARP S +0xE0 0x00E0 # LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 # LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 # LATIN SMALL LETTER AE +0xE7 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 # LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC # LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x00F0 # LATIN SMALL LETTER ETH +0xF1 0x00F1 # LATIN SMALL LETTER N WITH TILDE +0xF2 0x00F2 # LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 # LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 # DIVISION SIGN +0xF8 0x00F8 # LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 # LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x00FD # LATIN SMALL LETTER Y WITH ACUTE +0xFE 0x00FE # LATIN SMALL LETTER THORN +0xFF 0x00FF # LATIN SMALL LETTER Y WITH DIAERESIS + diff --git a/data/iso-8859-16.txt b/data/iso-8859-16.txt new file mode 100644 index 000000000..5353d747b --- /dev/null +++ b/data/iso-8859-16.txt @@ -0,0 +1,299 @@ +# +# Name: ISO/IEC 8859-16:2001 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 2001 July 26 +# Authors: Markus Kuhn +# +# Copyright (c) 1999-2001 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-16:2001 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-16 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-16 order. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x0104 # LATIN CAPITAL LETTER A WITH OGONEK +0xA2 0x0105 # LATIN SMALL LETTER A WITH OGONEK +0xA3 0x0141 # LATIN CAPITAL LETTER L WITH STROKE +0xA4 0x20AC # EURO SIGN +0xA5 0x201E # DOUBLE LOW-9 QUOTATION MARK +0xA6 0x0160 # LATIN CAPITAL LETTER S WITH CARON +0xA7 0x00A7 # SECTION SIGN +0xA8 0x0161 # LATIN SMALL LETTER S WITH CARON +0xA9 0x00A9 # COPYRIGHT SIGN +0xAA 0x0218 # LATIN CAPITAL LETTER S WITH COMMA BELOW +0xAB 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x0179 # LATIN CAPITAL LETTER Z WITH ACUTE +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x017A # LATIN SMALL LETTER Z WITH ACUTE +0xAF 0x017B # LATIN CAPITAL LETTER Z WITH DOT ABOVE +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x00B1 # PLUS-MINUS SIGN +0xB2 0x010C # LATIN CAPITAL LETTER C WITH CARON +0xB3 0x0142 # LATIN SMALL LETTER L WITH STROKE +0xB4 0x017D # LATIN CAPITAL LETTER Z WITH CARON +0xB5 0x201D # RIGHT DOUBLE QUOTATION MARK +0xB6 0x00B6 # PILCROW SIGN +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x017E # LATIN SMALL LETTER Z WITH CARON +0xB9 0x010D # LATIN SMALL LETTER C WITH CARON +0xBA 0x0219 # LATIN SMALL LETTER S WITH COMMA BELOW +0xBB 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x0152 # LATIN CAPITAL LIGATURE OE +0xBD 0x0153 # LATIN SMALL LIGATURE OE +0xBE 0x0178 # LATIN CAPITAL LETTER Y WITH DIAERESIS +0xBF 0x017C # LATIN SMALL LETTER Z WITH DOT ABOVE +0xC0 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x0102 # LATIN CAPITAL LETTER A WITH BREVE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x0106 # LATIN CAPITAL LETTER C WITH ACUTE +0xC6 0x00C6 # LATIN CAPITAL LETTER AE +0xC7 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x0110 # LATIN CAPITAL LETTER D WITH STROKE +0xD1 0x0143 # LATIN CAPITAL LETTER N WITH ACUTE +0xD2 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x0150 # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x015A # LATIN CAPITAL LETTER S WITH ACUTE +0xD8 0x0170 # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0xD9 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x0118 # LATIN CAPITAL LETTER E WITH OGONEK +0xDE 0x021A # LATIN CAPITAL LETTER T WITH COMMA BELOW +0xDF 0x00DF # LATIN SMALL LETTER SHARP S +0xE0 0x00E0 # LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x0103 # LATIN SMALL LETTER A WITH BREVE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x0107 # LATIN SMALL LETTER C WITH ACUTE +0xE6 0x00E6 # LATIN SMALL LETTER AE +0xE7 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 # LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC # LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x0111 # LATIN SMALL LETTER D WITH STROKE +0xF1 0x0144 # LATIN SMALL LETTER N WITH ACUTE +0xF2 0x00F2 # LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x0151 # LATIN SMALL LETTER O WITH DOUBLE ACUTE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x015B # LATIN SMALL LETTER S WITH ACUTE +0xF8 0x0171 # LATIN SMALL LETTER U WITH DOUBLE ACUTE +0xF9 0x00F9 # LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x0119 # LATIN SMALL LETTER E WITH OGONEK +0xFE 0x021B # LATIN SMALL LETTER T WITH COMMA BELOW +0xFF 0x00FF # LATIN SMALL LETTER Y WITH DIAERESIS 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-2.txt b/data/iso-8859-2.txt new file mode 100644 index 000000000..e45df25eb --- /dev/null +++ b/data/iso-8859-2.txt @@ -0,0 +1,303 @@ +# +# Name: ISO 8859-2:1999 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-2:1999 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-2 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-2 order. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x0104 # LATIN CAPITAL LETTER A WITH OGONEK +0xA2 0x02D8 # BREVE +0xA3 0x0141 # LATIN CAPITAL LETTER L WITH STROKE +0xA4 0x00A4 # CURRENCY SIGN +0xA5 0x013D # LATIN CAPITAL LETTER L WITH CARON +0xA6 0x015A # LATIN CAPITAL LETTER S WITH ACUTE +0xA7 0x00A7 # SECTION SIGN +0xA8 0x00A8 # DIAERESIS +0xA9 0x0160 # LATIN CAPITAL LETTER S WITH CARON +0xAA 0x015E # LATIN CAPITAL LETTER S WITH CEDILLA +0xAB 0x0164 # LATIN CAPITAL LETTER T WITH CARON +0xAC 0x0179 # LATIN CAPITAL LETTER Z WITH ACUTE +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x017D # LATIN CAPITAL LETTER Z WITH CARON +0xAF 0x017B # LATIN CAPITAL LETTER Z WITH DOT ABOVE +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x0105 # LATIN SMALL LETTER A WITH OGONEK +0xB2 0x02DB # OGONEK +0xB3 0x0142 # LATIN SMALL LETTER L WITH STROKE +0xB4 0x00B4 # ACUTE ACCENT +0xB5 0x013E # LATIN SMALL LETTER L WITH CARON +0xB6 0x015B # LATIN SMALL LETTER S WITH ACUTE +0xB7 0x02C7 # CARON +0xB8 0x00B8 # CEDILLA +0xB9 0x0161 # LATIN SMALL LETTER S WITH CARON +0xBA 0x015F # LATIN SMALL LETTER S WITH CEDILLA +0xBB 0x0165 # LATIN SMALL LETTER T WITH CARON +0xBC 0x017A # LATIN SMALL LETTER Z WITH ACUTE +0xBD 0x02DD # DOUBLE ACUTE ACCENT +0xBE 0x017E # LATIN SMALL LETTER Z WITH CARON +0xBF 0x017C # LATIN SMALL LETTER Z WITH DOT ABOVE +0xC0 0x0154 # LATIN CAPITAL LETTER R WITH ACUTE +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x0102 # LATIN CAPITAL LETTER A WITH BREVE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x0139 # LATIN CAPITAL LETTER L WITH ACUTE +0xC6 0x0106 # LATIN CAPITAL LETTER C WITH ACUTE +0xC7 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x010C # LATIN CAPITAL LETTER C WITH CARON +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x0118 # LATIN CAPITAL LETTER E WITH OGONEK +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x011A # LATIN CAPITAL LETTER E WITH CARON +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x010E # LATIN CAPITAL LETTER D WITH CARON +0xD0 0x0110 # LATIN CAPITAL LETTER D WITH STROKE +0xD1 0x0143 # LATIN CAPITAL LETTER N WITH ACUTE +0xD2 0x0147 # LATIN CAPITAL LETTER N WITH CARON +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x0150 # LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 # MULTIPLICATION SIGN +0xD8 0x0158 # LATIN CAPITAL LETTER R WITH CARON +0xD9 0x016E # LATIN CAPITAL LETTER U WITH RING ABOVE +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x0170 # LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x00DD # LATIN CAPITAL LETTER Y WITH ACUTE +0xDE 0x0162 # LATIN CAPITAL LETTER T WITH CEDILLA +0xDF 0x00DF # LATIN SMALL LETTER SHARP S +0xE0 0x0155 # LATIN SMALL LETTER R WITH ACUTE +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x0103 # LATIN SMALL LETTER A WITH BREVE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x013A # LATIN SMALL LETTER L WITH ACUTE +0xE6 0x0107 # LATIN SMALL LETTER C WITH ACUTE +0xE7 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x010D # LATIN SMALL LETTER C WITH CARON +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x0119 # LATIN SMALL LETTER E WITH OGONEK +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x011B # LATIN SMALL LETTER E WITH CARON +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x010F # LATIN SMALL LETTER D WITH CARON +0xF0 0x0111 # LATIN SMALL LETTER D WITH STROKE +0xF1 0x0144 # LATIN SMALL LETTER N WITH ACUTE +0xF2 0x0148 # LATIN SMALL LETTER N WITH CARON +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x0151 # LATIN SMALL LETTER O WITH DOUBLE ACUTE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 # DIVISION SIGN +0xF8 0x0159 # LATIN SMALL LETTER R WITH CARON +0xF9 0x016F # LATIN SMALL LETTER U WITH RING ABOVE +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x0171 # LATIN SMALL LETTER U WITH DOUBLE ACUTE +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x00FD # LATIN SMALL LETTER Y WITH ACUTE +0xFE 0x0163 # LATIN SMALL LETTER T WITH CEDILLA +0xFF 0x02D9 # DOT ABOVE 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-3.txt b/data/iso-8859-3.txt new file mode 100644 index 000000000..9b6ac69dd --- /dev/null +++ b/data/iso-8859-3.txt @@ -0,0 +1,296 @@ +# +# Name: ISO/IEC 8859-3:1999 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-3:1999 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-3 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-3 order. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x0126 # LATIN CAPITAL LETTER H WITH STROKE +0xA2 0x02D8 # BREVE +0xA3 0x00A3 # POUND SIGN +0xA4 0x00A4 # CURRENCY SIGN +0xA6 0x0124 # LATIN CAPITAL LETTER H WITH CIRCUMFLEX +0xA7 0x00A7 # SECTION SIGN +0xA8 0x00A8 # DIAERESIS +0xA9 0x0130 # LATIN CAPITAL LETTER I WITH DOT ABOVE +0xAA 0x015E # LATIN CAPITAL LETTER S WITH CEDILLA +0xAB 0x011E # LATIN CAPITAL LETTER G WITH BREVE +0xAC 0x0134 # LATIN CAPITAL LETTER J WITH CIRCUMFLEX +0xAD 0x00AD # SOFT HYPHEN +0xAF 0x017B # LATIN CAPITAL LETTER Z WITH DOT ABOVE +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x0127 # LATIN SMALL LETTER H WITH STROKE +0xB2 0x00B2 # SUPERSCRIPT TWO +0xB3 0x00B3 # SUPERSCRIPT THREE +0xB4 0x00B4 # ACUTE ACCENT +0xB5 0x00B5 # MICRO SIGN +0xB6 0x0125 # LATIN SMALL LETTER H WITH CIRCUMFLEX +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x00B8 # CEDILLA +0xB9 0x0131 # LATIN SMALL LETTER DOTLESS I +0xBA 0x015F # LATIN SMALL LETTER S WITH CEDILLA +0xBB 0x011F # LATIN SMALL LETTER G WITH BREVE +0xBC 0x0135 # LATIN SMALL LETTER J WITH CIRCUMFLEX +0xBD 0x00BD # VULGAR FRACTION ONE HALF +0xBF 0x017C # LATIN SMALL LETTER Z WITH DOT ABOVE +0xC0 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x010A # LATIN CAPITAL LETTER C WITH DOT ABOVE +0xC6 0x0108 # LATIN CAPITAL LETTER C WITH CIRCUMFLEX +0xC7 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS +0xD1 0x00D1 # LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x0120 # LATIN CAPITAL LETTER G WITH DOT ABOVE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 # MULTIPLICATION SIGN +0xD8 0x011C # LATIN CAPITAL LETTER G WITH CIRCUMFLEX +0xD9 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x016C # LATIN CAPITAL LETTER U WITH BREVE +0xDE 0x015C # LATIN CAPITAL LETTER S WITH CIRCUMFLEX +0xDF 0x00DF # LATIN SMALL LETTER SHARP S +0xE0 0x00E0 # LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x010B # LATIN SMALL LETTER C WITH DOT ABOVE +0xE6 0x0109 # LATIN SMALL LETTER C WITH CIRCUMFLEX +0xE7 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 # LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC # LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS +0xF1 0x00F1 # LATIN SMALL LETTER N WITH TILDE +0xF2 0x00F2 # LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x0121 # LATIN SMALL LETTER G WITH DOT ABOVE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 # DIVISION SIGN +0xF8 0x011D # LATIN SMALL LETTER G WITH CIRCUMFLEX +0xF9 0x00F9 # LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x016D # LATIN SMALL LETTER U WITH BREVE +0xFE 0x015D # LATIN SMALL LETTER S WITH CIRCUMFLEX +0xFF 0x02D9 # DOT ABOVE 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-4.txt b/data/iso-8859-4.txt new file mode 100644 index 000000000..662e698ab --- /dev/null +++ b/data/iso-8859-4.txt @@ -0,0 +1,303 @@ +# +# Name: ISO/IEC 8859-4:1998 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-4:1998 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-4 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-4 order. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x0104 # LATIN CAPITAL LETTER A WITH OGONEK +0xA2 0x0138 # LATIN SMALL LETTER KRA +0xA3 0x0156 # LATIN CAPITAL LETTER R WITH CEDILLA +0xA4 0x00A4 # CURRENCY SIGN +0xA5 0x0128 # LATIN CAPITAL LETTER I WITH TILDE +0xA6 0x013B # LATIN CAPITAL LETTER L WITH CEDILLA +0xA7 0x00A7 # SECTION SIGN +0xA8 0x00A8 # DIAERESIS +0xA9 0x0160 # LATIN CAPITAL LETTER S WITH CARON +0xAA 0x0112 # LATIN CAPITAL LETTER E WITH MACRON +0xAB 0x0122 # LATIN CAPITAL LETTER G WITH CEDILLA +0xAC 0x0166 # LATIN CAPITAL LETTER T WITH STROKE +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x017D # LATIN CAPITAL LETTER Z WITH CARON +0xAF 0x00AF # MACRON +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x0105 # LATIN SMALL LETTER A WITH OGONEK +0xB2 0x02DB # OGONEK +0xB3 0x0157 # LATIN SMALL LETTER R WITH CEDILLA +0xB4 0x00B4 # ACUTE ACCENT +0xB5 0x0129 # LATIN SMALL LETTER I WITH TILDE +0xB6 0x013C # LATIN SMALL LETTER L WITH CEDILLA +0xB7 0x02C7 # CARON +0xB8 0x00B8 # CEDILLA +0xB9 0x0161 # LATIN SMALL LETTER S WITH CARON +0xBA 0x0113 # LATIN SMALL LETTER E WITH MACRON +0xBB 0x0123 # LATIN SMALL LETTER G WITH CEDILLA +0xBC 0x0167 # LATIN SMALL LETTER T WITH STROKE +0xBD 0x014A # LATIN CAPITAL LETTER ENG +0xBE 0x017E # LATIN SMALL LETTER Z WITH CARON +0xBF 0x014B # LATIN SMALL LETTER ENG +0xC0 0x0100 # LATIN CAPITAL LETTER A WITH MACRON +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 # LATIN CAPITAL LETTER AE +0xC7 0x012E # LATIN CAPITAL LETTER I WITH OGONEK +0xC8 0x010C # LATIN CAPITAL LETTER C WITH CARON +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x0118 # LATIN CAPITAL LETTER E WITH OGONEK +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x0116 # LATIN CAPITAL LETTER E WITH DOT ABOVE +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x012A # LATIN CAPITAL LETTER I WITH MACRON +0xD0 0x0110 # LATIN CAPITAL LETTER D WITH STROKE +0xD1 0x0145 # LATIN CAPITAL LETTER N WITH CEDILLA +0xD2 0x014C # LATIN CAPITAL LETTER O WITH MACRON +0xD3 0x0136 # LATIN CAPITAL LETTER K WITH CEDILLA +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 # MULTIPLICATION SIGN +0xD8 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x0172 # LATIN CAPITAL LETTER U WITH OGONEK +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x0168 # LATIN CAPITAL LETTER U WITH TILDE +0xDE 0x016A # LATIN CAPITAL LETTER U WITH MACRON +0xDF 0x00DF # LATIN SMALL LETTER SHARP S +0xE0 0x0101 # LATIN SMALL LETTER A WITH MACRON +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 # LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 # LATIN SMALL LETTER AE +0xE7 0x012F # LATIN SMALL LETTER I WITH OGONEK +0xE8 0x010D # LATIN SMALL LETTER C WITH CARON +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x0119 # LATIN SMALL LETTER E WITH OGONEK +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x0117 # LATIN SMALL LETTER E WITH DOT ABOVE +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x012B # LATIN SMALL LETTER I WITH MACRON +0xF0 0x0111 # LATIN SMALL LETTER D WITH STROKE +0xF1 0x0146 # LATIN SMALL LETTER N WITH CEDILLA +0xF2 0x014D # LATIN SMALL LETTER O WITH MACRON +0xF3 0x0137 # LATIN SMALL LETTER K WITH CEDILLA +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 # LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 # DIVISION SIGN +0xF8 0x00F8 # LATIN SMALL LETTER O WITH STROKE +0xF9 0x0173 # LATIN SMALL LETTER U WITH OGONEK +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x0169 # LATIN SMALL LETTER U WITH TILDE +0xFE 0x016B # LATIN SMALL LETTER U WITH MACRON +0xFF 0x02D9 # DOT ABOVE 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-5.txt b/data/iso-8859-5.txt new file mode 100644 index 000000000..a7ed1ce2a --- /dev/null +++ b/data/iso-8859-5.txt @@ -0,0 +1,303 @@ +# +# Name: ISO 8859-5:1999 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-5:1999 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-5 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-5 order. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x0401 # CYRILLIC CAPITAL LETTER IO +0xA2 0x0402 # CYRILLIC CAPITAL LETTER DJE +0xA3 0x0403 # CYRILLIC CAPITAL LETTER GJE +0xA4 0x0404 # CYRILLIC CAPITAL LETTER UKRAINIAN IE +0xA5 0x0405 # CYRILLIC CAPITAL LETTER DZE +0xA6 0x0406 # CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0xA7 0x0407 # CYRILLIC CAPITAL LETTER YI +0xA8 0x0408 # CYRILLIC CAPITAL LETTER JE +0xA9 0x0409 # CYRILLIC CAPITAL LETTER LJE +0xAA 0x040A # CYRILLIC CAPITAL LETTER NJE +0xAB 0x040B # CYRILLIC CAPITAL LETTER TSHE +0xAC 0x040C # CYRILLIC CAPITAL LETTER KJE +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x040E # CYRILLIC CAPITAL LETTER SHORT U +0xAF 0x040F # CYRILLIC CAPITAL LETTER DZHE +0xB0 0x0410 # CYRILLIC CAPITAL LETTER A +0xB1 0x0411 # CYRILLIC CAPITAL LETTER BE +0xB2 0x0412 # CYRILLIC CAPITAL LETTER VE +0xB3 0x0413 # CYRILLIC CAPITAL LETTER GHE +0xB4 0x0414 # CYRILLIC CAPITAL LETTER DE +0xB5 0x0415 # CYRILLIC CAPITAL LETTER IE +0xB6 0x0416 # CYRILLIC CAPITAL LETTER ZHE +0xB7 0x0417 # CYRILLIC CAPITAL LETTER ZE +0xB8 0x0418 # CYRILLIC CAPITAL LETTER I +0xB9 0x0419 # CYRILLIC CAPITAL LETTER SHORT I +0xBA 0x041A # CYRILLIC CAPITAL LETTER KA +0xBB 0x041B # CYRILLIC CAPITAL LETTER EL +0xBC 0x041C # CYRILLIC CAPITAL LETTER EM +0xBD 0x041D # CYRILLIC CAPITAL LETTER EN +0xBE 0x041E # CYRILLIC CAPITAL LETTER O +0xBF 0x041F # CYRILLIC CAPITAL LETTER PE +0xC0 0x0420 # CYRILLIC CAPITAL LETTER ER +0xC1 0x0421 # CYRILLIC CAPITAL LETTER ES +0xC2 0x0422 # CYRILLIC CAPITAL LETTER TE +0xC3 0x0423 # CYRILLIC CAPITAL LETTER U +0xC4 0x0424 # CYRILLIC CAPITAL LETTER EF +0xC5 0x0425 # CYRILLIC CAPITAL LETTER HA +0xC6 0x0426 # CYRILLIC CAPITAL LETTER TSE +0xC7 0x0427 # CYRILLIC CAPITAL LETTER CHE +0xC8 0x0428 # CYRILLIC CAPITAL LETTER SHA +0xC9 0x0429 # CYRILLIC CAPITAL LETTER SHCHA +0xCA 0x042A # CYRILLIC CAPITAL LETTER HARD SIGN +0xCB 0x042B # CYRILLIC CAPITAL LETTER YERU +0xCC 0x042C # CYRILLIC CAPITAL LETTER SOFT SIGN +0xCD 0x042D # CYRILLIC CAPITAL LETTER E +0xCE 0x042E # CYRILLIC CAPITAL LETTER YU +0xCF 0x042F # CYRILLIC CAPITAL LETTER YA +0xD0 0x0430 # CYRILLIC SMALL LETTER A +0xD1 0x0431 # CYRILLIC SMALL LETTER BE +0xD2 0x0432 # CYRILLIC SMALL LETTER VE +0xD3 0x0433 # CYRILLIC SMALL LETTER GHE +0xD4 0x0434 # CYRILLIC SMALL LETTER DE +0xD5 0x0435 # CYRILLIC SMALL LETTER IE +0xD6 0x0436 # CYRILLIC SMALL LETTER ZHE +0xD7 0x0437 # CYRILLIC SMALL LETTER ZE +0xD8 0x0438 # CYRILLIC SMALL LETTER I +0xD9 0x0439 # CYRILLIC SMALL LETTER SHORT I +0xDA 0x043A # CYRILLIC SMALL LETTER KA +0xDB 0x043B # CYRILLIC SMALL LETTER EL +0xDC 0x043C # CYRILLIC SMALL LETTER EM +0xDD 0x043D # CYRILLIC SMALL LETTER EN +0xDE 0x043E # CYRILLIC SMALL LETTER O +0xDF 0x043F # CYRILLIC SMALL LETTER PE +0xE0 0x0440 # CYRILLIC SMALL LETTER ER +0xE1 0x0441 # CYRILLIC SMALL LETTER ES +0xE2 0x0442 # CYRILLIC SMALL LETTER TE +0xE3 0x0443 # CYRILLIC SMALL LETTER U +0xE4 0x0444 # CYRILLIC SMALL LETTER EF +0xE5 0x0445 # CYRILLIC SMALL LETTER HA +0xE6 0x0446 # CYRILLIC SMALL LETTER TSE +0xE7 0x0447 # CYRILLIC SMALL LETTER CHE +0xE8 0x0448 # CYRILLIC SMALL LETTER SHA +0xE9 0x0449 # CYRILLIC SMALL LETTER SHCHA +0xEA 0x044A # CYRILLIC SMALL LETTER HARD SIGN +0xEB 0x044B # CYRILLIC SMALL LETTER YERU +0xEC 0x044C # CYRILLIC SMALL LETTER SOFT SIGN +0xED 0x044D # CYRILLIC SMALL LETTER E +0xEE 0x044E # CYRILLIC SMALL LETTER YU +0xEF 0x044F # CYRILLIC SMALL LETTER YA +0xF0 0x2116 # NUMERO SIGN +0xF1 0x0451 # CYRILLIC SMALL LETTER IO +0xF2 0x0452 # CYRILLIC SMALL LETTER DJE +0xF3 0x0453 # CYRILLIC SMALL LETTER GJE +0xF4 0x0454 # CYRILLIC SMALL LETTER UKRAINIAN IE +0xF5 0x0455 # CYRILLIC SMALL LETTER DZE +0xF6 0x0456 # CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +0xF7 0x0457 # CYRILLIC SMALL LETTER YI +0xF8 0x0458 # CYRILLIC SMALL LETTER JE +0xF9 0x0459 # CYRILLIC SMALL LETTER LJE +0xFA 0x045A # CYRILLIC SMALL LETTER NJE +0xFB 0x045B # CYRILLIC SMALL LETTER TSHE +0xFC 0x045C # CYRILLIC SMALL LETTER KJE +0xFD 0x00A7 # SECTION SIGN +0xFE 0x045E # CYRILLIC SMALL LETTER SHORT U +0xFF 0x045F # CYRILLIC SMALL LETTER DZHE 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-6.txt b/data/iso-8859-6.txt new file mode 100644 index 000000000..69ac7f589 --- /dev/null +++ b/data/iso-8859-6.txt @@ -0,0 +1,260 @@ +# +# Name: ISO 8859-6:1999 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-6:1999 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-6 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-6 order. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# 0x30..0x39 remapped to the ASCII digits (U+0030..U+0039) instead +# of the Arabic digits (U+0660..U+0669). +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA4 0x00A4 # CURRENCY SIGN +0xAC 0x060C # ARABIC COMMA +0xAD 0x00AD # SOFT HYPHEN +0xBB 0x061B # ARABIC SEMICOLON +0xBF 0x061F # ARABIC QUESTION MARK +0xC1 0x0621 # ARABIC LETTER HAMZA +0xC2 0x0622 # ARABIC LETTER ALEF WITH MADDA ABOVE +0xC3 0x0623 # ARABIC LETTER ALEF WITH HAMZA ABOVE +0xC4 0x0624 # ARABIC LETTER WAW WITH HAMZA ABOVE +0xC5 0x0625 # ARABIC LETTER ALEF WITH HAMZA BELOW +0xC6 0x0626 # ARABIC LETTER YEH WITH HAMZA ABOVE +0xC7 0x0627 # ARABIC LETTER ALEF +0xC8 0x0628 # ARABIC LETTER BEH +0xC9 0x0629 # ARABIC LETTER TEH MARBUTA +0xCA 0x062A # ARABIC LETTER TEH +0xCB 0x062B # ARABIC LETTER THEH +0xCC 0x062C # ARABIC LETTER JEEM +0xCD 0x062D # ARABIC LETTER HAH +0xCE 0x062E # ARABIC LETTER KHAH +0xCF 0x062F # ARABIC LETTER DAL +0xD0 0x0630 # ARABIC LETTER THAL +0xD1 0x0631 # ARABIC LETTER REH +0xD2 0x0632 # ARABIC LETTER ZAIN +0xD3 0x0633 # ARABIC LETTER SEEN +0xD4 0x0634 # ARABIC LETTER SHEEN +0xD5 0x0635 # ARABIC LETTER SAD +0xD6 0x0636 # ARABIC LETTER DAD +0xD7 0x0637 # ARABIC LETTER TAH +0xD8 0x0638 # ARABIC LETTER ZAH +0xD9 0x0639 # ARABIC LETTER AIN +0xDA 0x063A # ARABIC LETTER GHAIN +0xE0 0x0640 # ARABIC TATWEEL +0xE1 0x0641 # ARABIC LETTER FEH +0xE2 0x0642 # ARABIC LETTER QAF +0xE3 0x0643 # ARABIC LETTER KAF +0xE4 0x0644 # ARABIC LETTER LAM +0xE5 0x0645 # ARABIC LETTER MEEM +0xE6 0x0646 # ARABIC LETTER NOON +0xE7 0x0647 # ARABIC LETTER HEH +0xE8 0x0648 # ARABIC LETTER WAW +0xE9 0x0649 # ARABIC LETTER ALEF MAKSURA +0xEA 0x064A # ARABIC LETTER YEH +0xEB 0x064B # ARABIC FATHATAN +0xEC 0x064C # ARABIC DAMMATAN +0xED 0x064D # ARABIC KASRATAN +0xEE 0x064E # ARABIC FATHA +0xEF 0x064F # ARABIC DAMMA +0xF0 0x0650 # ARABIC KASRA +0xF1 0x0651 # ARABIC SHADDA +0xF2 0x0652 # ARABIC SUKUN 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-7.txt b/data/iso-8859-7.txt new file mode 100644 index 000000000..52c42d08a --- /dev/null +++ b/data/iso-8859-7.txt @@ -0,0 +1,302 @@ +# +# Name: ISO 8859-7:1987 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO 8859-7:1987 characters map into Unicode. +# +# ISO 8859-7:1987 is equivalent to ISO-IR-126, ELOT 928, +# and ECMA 118. +# +# Format: Three tab-separated columns +# Column #1 is the ISO 8859-7 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO 8859-7 order. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# Remap 0xA1 to U+2018 (instead of 0x02BD) to match text of 8859-7 +# Remap 0xA2 to U+2019 (instead of 0x02BC) to match text of 8859-7 +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x2018 # LEFT SINGLE QUOTATION MARK +0xA2 0x2019 # RIGHT SINGLE QUOTATION MARK +0xA3 0x00A3 # POUND SIGN +0xA6 0x00A6 # BROKEN BAR +0xA7 0x00A7 # SECTION SIGN +0xA8 0x00A8 # DIAERESIS +0xA9 0x00A9 # COPYRIGHT SIGN +0xAB 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC # NOT SIGN +0xAD 0x00AD # SOFT HYPHEN +0xAF 0x2015 # HORIZONTAL BAR +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x00B1 # PLUS-MINUS SIGN +0xB2 0x00B2 # SUPERSCRIPT TWO +0xB3 0x00B3 # SUPERSCRIPT THREE +0xB4 0x0384 # GREEK TONOS +0xB5 0x0385 # GREEK DIALYTIKA TONOS +0xB6 0x0386 # GREEK CAPITAL LETTER ALPHA WITH TONOS +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x0388 # GREEK CAPITAL LETTER EPSILON WITH TONOS +0xB9 0x0389 # GREEK CAPITAL LETTER ETA WITH TONOS +0xBA 0x038A # GREEK CAPITAL LETTER IOTA WITH TONOS +0xBB 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x038C # GREEK CAPITAL LETTER OMICRON WITH TONOS +0xBD 0x00BD # VULGAR FRACTION ONE HALF +0xBE 0x038E # GREEK CAPITAL LETTER UPSILON WITH TONOS +0xBF 0x038F # GREEK CAPITAL LETTER OMEGA WITH TONOS +0xC0 0x0390 # GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +0xC1 0x0391 # GREEK CAPITAL LETTER ALPHA +0xC2 0x0392 # GREEK CAPITAL LETTER BETA +0xC3 0x0393 # GREEK CAPITAL LETTER GAMMA +0xC4 0x0394 # GREEK CAPITAL LETTER DELTA +0xC5 0x0395 # GREEK CAPITAL LETTER EPSILON +0xC6 0x0396 # GREEK CAPITAL LETTER ZETA +0xC7 0x0397 # GREEK CAPITAL LETTER ETA +0xC8 0x0398 # GREEK CAPITAL LETTER THETA +0xC9 0x0399 # GREEK CAPITAL LETTER IOTA +0xCA 0x039A # GREEK CAPITAL LETTER KAPPA +0xCB 0x039B # GREEK CAPITAL LETTER LAMDA +0xCC 0x039C # GREEK CAPITAL LETTER MU +0xCD 0x039D # GREEK CAPITAL LETTER NU +0xCE 0x039E # GREEK CAPITAL LETTER XI +0xCF 0x039F # GREEK CAPITAL LETTER OMICRON +0xD0 0x03A0 # GREEK CAPITAL LETTER PI +0xD1 0x03A1 # GREEK CAPITAL LETTER RHO +0xD3 0x03A3 # GREEK CAPITAL LETTER SIGMA +0xD4 0x03A4 # GREEK CAPITAL LETTER TAU +0xD5 0x03A5 # GREEK CAPITAL LETTER UPSILON +0xD6 0x03A6 # GREEK CAPITAL LETTER PHI +0xD7 0x03A7 # GREEK CAPITAL LETTER CHI +0xD8 0x03A8 # GREEK CAPITAL LETTER PSI +0xD9 0x03A9 # GREEK CAPITAL LETTER OMEGA +0xDA 0x03AA # GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +0xDB 0x03AB # GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +0xDC 0x03AC # GREEK SMALL LETTER ALPHA WITH TONOS +0xDD 0x03AD # GREEK SMALL LETTER EPSILON WITH TONOS +0xDE 0x03AE # GREEK SMALL LETTER ETA WITH TONOS +0xDF 0x03AF # GREEK SMALL LETTER IOTA WITH TONOS +0xE0 0x03B0 # GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +0xE1 0x03B1 # GREEK SMALL LETTER ALPHA +0xE2 0x03B2 # GREEK SMALL LETTER BETA +0xE3 0x03B3 # GREEK SMALL LETTER GAMMA +0xE4 0x03B4 # GREEK SMALL LETTER DELTA +0xE5 0x03B5 # GREEK SMALL LETTER EPSILON +0xE6 0x03B6 # GREEK SMALL LETTER ZETA +0xE7 0x03B7 # GREEK SMALL LETTER ETA +0xE8 0x03B8 # GREEK SMALL LETTER THETA +0xE9 0x03B9 # GREEK SMALL LETTER IOTA +0xEA 0x03BA # GREEK SMALL LETTER KAPPA +0xEB 0x03BB # GREEK SMALL LETTER LAMDA +0xEC 0x03BC # GREEK SMALL LETTER MU +0xED 0x03BD # GREEK SMALL LETTER NU +0xEE 0x03BE # GREEK SMALL LETTER XI +0xEF 0x03BF # GREEK SMALL LETTER OMICRON +0xF0 0x03C0 # GREEK SMALL LETTER PI +0xF1 0x03C1 # GREEK SMALL LETTER RHO +0xF2 0x03C2 # GREEK SMALL LETTER FINAL SIGMA +0xF3 0x03C3 # GREEK SMALL LETTER SIGMA +0xF4 0x03C4 # GREEK SMALL LETTER TAU +0xF5 0x03C5 # GREEK SMALL LETTER UPSILON +0xF6 0x03C6 # GREEK SMALL LETTER PHI +0xF7 0x03C7 # GREEK SMALL LETTER CHI +0xF8 0x03C8 # GREEK SMALL LETTER PSI +0xF9 0x03C9 # GREEK SMALL LETTER OMEGA +0xFA 0x03CA # GREEK SMALL LETTER IOTA WITH DIALYTIKA +0xFB 0x03CB # GREEK SMALL LETTER UPSILON WITH DIALYTIKA +0xFC 0x03CC # GREEK SMALL LETTER OMICRON WITH TONOS +0xFD 0x03CD # GREEK SMALL LETTER UPSILON WITH TONOS +0xFE 0x03CE # GREEK SMALL LETTER OMEGA WITH TONOS 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-8.txt b/data/iso-8859-8.txt new file mode 100644 index 000000000..bc8da4c7f --- /dev/null +++ b/data/iso-8859-8.txt @@ -0,0 +1,270 @@ +# +# Name: ISO/IEC 8859-8:1999 to Unicode +# Unicode version: 3.0 +# Table version: 1.1 +# Table format: Format A +# Date: 2000-Jan-03 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on optical media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-8:1999 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-8 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-8 order. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# 1.1 version updates to the published 8859-8:1999, correcting +# the mapping of 0xAF and adding mappings for LRM and RLM. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA2 0x00A2 # CENT SIGN +0xA3 0x00A3 # POUND SIGN +0xA4 0x00A4 # CURRENCY SIGN +0xA5 0x00A5 # YEN SIGN +0xA6 0x00A6 # BROKEN BAR +0xA7 0x00A7 # SECTION SIGN +0xA8 0x00A8 # DIAERESIS +0xA9 0x00A9 # COPYRIGHT SIGN +0xAA 0x00D7 # MULTIPLICATION SIGN +0xAB 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC # NOT SIGN +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x00AE # REGISTERED SIGN +0xAF 0x00AF # MACRON +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x00B1 # PLUS-MINUS SIGN +0xB2 0x00B2 # SUPERSCRIPT TWO +0xB3 0x00B3 # SUPERSCRIPT THREE +0xB4 0x00B4 # ACUTE ACCENT +0xB5 0x00B5 # MICRO SIGN +0xB6 0x00B6 # PILCROW SIGN +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x00B8 # CEDILLA +0xB9 0x00B9 # SUPERSCRIPT ONE +0xBA 0x00F7 # DIVISION SIGN +0xBB 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC # VULGAR FRACTION ONE QUARTER +0xBD 0x00BD # VULGAR FRACTION ONE HALF +0xBE 0x00BE # VULGAR FRACTION THREE QUARTERS +0xDF 0x2017 # DOUBLE LOW LINE +0xE0 0x05D0 # HEBREW LETTER ALEF +0xE1 0x05D1 # HEBREW LETTER BET +0xE2 0x05D2 # HEBREW LETTER GIMEL +0xE3 0x05D3 # HEBREW LETTER DALET +0xE4 0x05D4 # HEBREW LETTER HE +0xE5 0x05D5 # HEBREW LETTER VAV +0xE6 0x05D6 # HEBREW LETTER ZAYIN +0xE7 0x05D7 # HEBREW LETTER HET +0xE8 0x05D8 # HEBREW LETTER TET +0xE9 0x05D9 # HEBREW LETTER YOD +0xEA 0x05DA # HEBREW LETTER FINAL KAF +0xEB 0x05DB # HEBREW LETTER KAF +0xEC 0x05DC # HEBREW LETTER LAMED +0xED 0x05DD # HEBREW LETTER FINAL MEM +0xEE 0x05DE # HEBREW LETTER MEM +0xEF 0x05DF # HEBREW LETTER FINAL NUN +0xF0 0x05E0 # HEBREW LETTER NUN +0xF1 0x05E1 # HEBREW LETTER SAMEKH +0xF2 0x05E2 # HEBREW LETTER AYIN +0xF3 0x05E3 # HEBREW LETTER FINAL PE +0xF4 0x05E4 # HEBREW LETTER PE +0xF5 0x05E5 # HEBREW LETTER FINAL TSADI +0xF6 0x05E6 # HEBREW LETTER TSADI +0xF7 0x05E7 # HEBREW LETTER QOF +0xF8 0x05E8 # HEBREW LETTER RESH +0xF9 0x05E9 # HEBREW LETTER SHIN +0xFA 0x05EA # HEBREW LETTER TAV +0xFD 0x200E # LEFT-TO-RIGHT MARK +0xFE 0x200F # RIGHT-TO-LEFT MARK + 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/iso-8859-9.txt b/data/iso-8859-9.txt new file mode 100644 index 000000000..22901f107 --- /dev/null +++ b/data/iso-8859-9.txt @@ -0,0 +1,307 @@ +# +# Name: ISO/IEC 8859-9:1999 to Unicode +# Unicode version: 3.0 +# Table version: 1.0 +# Table format: Format A +# Date: 1999 July 27 +# Authors: Ken Whistler +# +# Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. +# +# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). +# No claims are made as to fitness for any particular purpose. No +# warranties of any kind are expressed or implied. The recipient +# agrees to determine applicability of information provided. If this +# file has been provided on magnetic media by Unicode, Inc., the sole +# remedy for any claim will be exchange of defective media within 90 +# days of receipt. +# +# Unicode, Inc. hereby grants the right to freely use the information +# supplied in this file in the creation of products supporting the +# Unicode Standard, and to make copies of this file in any form for +# internal or external distribution as long as this notice remains +# attached. +# +# General notes: +# +# This table contains the data the Unicode Consortium has on how +# ISO/IEC 8859-9:1999 characters map into Unicode. +# +# Format: Three tab-separated columns +# Column #1 is the ISO/IEC 8859-9 code (in hex as 0xXX) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 the Unicode name (follows a comment sign, '#') +# +# The entries are in ISO/IEC 8859-9 order. +# +# ISO/IEC 8859-9 is also equivalent to ISO-IR-148. +# +# Version history +# 1.0 version updates 0.1 version by adding mappings for all +# control characters. +# +# Updated versions of this file may be found in: +# +# +# Any comments or problems, contact +# Please note that is an archival address; +# notices will be checked, but do not expect an immediate response. +# +0x00 0x0000 # NULL +0x01 0x0001 # START OF HEADING +0x02 0x0002 # START OF TEXT +0x03 0x0003 # END OF TEXT +0x04 0x0004 # END OF TRANSMISSION +0x05 0x0005 # ENQUIRY +0x06 0x0006 # ACKNOWLEDGE +0x07 0x0007 # BELL +0x08 0x0008 # BACKSPACE +0x09 0x0009 # HORIZONTAL TABULATION +0x0A 0x000A # LINE FEED +0x0B 0x000B # VERTICAL TABULATION +0x0C 0x000C # FORM FEED +0x0D 0x000D # CARRIAGE RETURN +0x0E 0x000E # SHIFT OUT +0x0F 0x000F # SHIFT IN +0x10 0x0010 # DATA LINK ESCAPE +0x11 0x0011 # DEVICE CONTROL ONE +0x12 0x0012 # DEVICE CONTROL TWO +0x13 0x0013 # DEVICE CONTROL THREE +0x14 0x0014 # DEVICE CONTROL FOUR +0x15 0x0015 # NEGATIVE ACKNOWLEDGE +0x16 0x0016 # SYNCHRONOUS IDLE +0x17 0x0017 # END OF TRANSMISSION BLOCK +0x18 0x0018 # CANCEL +0x19 0x0019 # END OF MEDIUM +0x1A 0x001A # SUBSTITUTE +0x1B 0x001B # ESCAPE +0x1C 0x001C # FILE SEPARATOR +0x1D 0x001D # GROUP SEPARATOR +0x1E 0x001E # RECORD SEPARATOR +0x1F 0x001F # UNIT SEPARATOR +0x20 0x0020 # SPACE +0x21 0x0021 # EXCLAMATION MARK +0x22 0x0022 # QUOTATION MARK +0x23 0x0023 # NUMBER SIGN +0x24 0x0024 # DOLLAR SIGN +0x25 0x0025 # PERCENT SIGN +0x26 0x0026 # AMPERSAND +0x27 0x0027 # APOSTROPHE +0x28 0x0028 # LEFT PARENTHESIS +0x29 0x0029 # RIGHT PARENTHESIS +0x2A 0x002A # ASTERISK +0x2B 0x002B # PLUS SIGN +0x2C 0x002C # COMMA +0x2D 0x002D # HYPHEN-MINUS +0x2E 0x002E # FULL STOP +0x2F 0x002F # SOLIDUS +0x30 0x0030 # DIGIT ZERO +0x31 0x0031 # DIGIT ONE +0x32 0x0032 # DIGIT TWO +0x33 0x0033 # DIGIT THREE +0x34 0x0034 # DIGIT FOUR +0x35 0x0035 # DIGIT FIVE +0x36 0x0036 # DIGIT SIX +0x37 0x0037 # DIGIT SEVEN +0x38 0x0038 # DIGIT EIGHT +0x39 0x0039 # DIGIT NINE +0x3A 0x003A # COLON +0x3B 0x003B # SEMICOLON +0x3C 0x003C # LESS-THAN SIGN +0x3D 0x003D # EQUALS SIGN +0x3E 0x003E # GREATER-THAN SIGN +0x3F 0x003F # QUESTION MARK +0x40 0x0040 # COMMERCIAL AT +0x41 0x0041 # LATIN CAPITAL LETTER A +0x42 0x0042 # LATIN CAPITAL LETTER B +0x43 0x0043 # LATIN CAPITAL LETTER C +0x44 0x0044 # LATIN CAPITAL LETTER D +0x45 0x0045 # LATIN CAPITAL LETTER E +0x46 0x0046 # LATIN CAPITAL LETTER F +0x47 0x0047 # LATIN CAPITAL LETTER G +0x48 0x0048 # LATIN CAPITAL LETTER H +0x49 0x0049 # LATIN CAPITAL LETTER I +0x4A 0x004A # LATIN CAPITAL LETTER J +0x4B 0x004B # LATIN CAPITAL LETTER K +0x4C 0x004C # LATIN CAPITAL LETTER L +0x4D 0x004D # LATIN CAPITAL LETTER M +0x4E 0x004E # LATIN CAPITAL LETTER N +0x4F 0x004F # LATIN CAPITAL LETTER O +0x50 0x0050 # LATIN CAPITAL LETTER P +0x51 0x0051 # LATIN CAPITAL LETTER Q +0x52 0x0052 # LATIN CAPITAL LETTER R +0x53 0x0053 # LATIN CAPITAL LETTER S +0x54 0x0054 # LATIN CAPITAL LETTER T +0x55 0x0055 # LATIN CAPITAL LETTER U +0x56 0x0056 # LATIN CAPITAL LETTER V +0x57 0x0057 # LATIN CAPITAL LETTER W +0x58 0x0058 # LATIN CAPITAL LETTER X +0x59 0x0059 # LATIN CAPITAL LETTER Y +0x5A 0x005A # LATIN CAPITAL LETTER Z +0x5B 0x005B # LEFT SQUARE BRACKET +0x5C 0x005C # REVERSE SOLIDUS +0x5D 0x005D # RIGHT SQUARE BRACKET +0x5E 0x005E # CIRCUMFLEX ACCENT +0x5F 0x005F # LOW LINE +0x60 0x0060 # GRAVE ACCENT +0x61 0x0061 # LATIN SMALL LETTER A +0x62 0x0062 # LATIN SMALL LETTER B +0x63 0x0063 # LATIN SMALL LETTER C +0x64 0x0064 # LATIN SMALL LETTER D +0x65 0x0065 # LATIN SMALL LETTER E +0x66 0x0066 # LATIN SMALL LETTER F +0x67 0x0067 # LATIN SMALL LETTER G +0x68 0x0068 # LATIN SMALL LETTER H +0x69 0x0069 # LATIN SMALL LETTER I +0x6A 0x006A # LATIN SMALL LETTER J +0x6B 0x006B # LATIN SMALL LETTER K +0x6C 0x006C # LATIN SMALL LETTER L +0x6D 0x006D # LATIN SMALL LETTER M +0x6E 0x006E # LATIN SMALL LETTER N +0x6F 0x006F # LATIN SMALL LETTER O +0x70 0x0070 # LATIN SMALL LETTER P +0x71 0x0071 # LATIN SMALL LETTER Q +0x72 0x0072 # LATIN SMALL LETTER R +0x73 0x0073 # LATIN SMALL LETTER S +0x74 0x0074 # LATIN SMALL LETTER T +0x75 0x0075 # LATIN SMALL LETTER U +0x76 0x0076 # LATIN SMALL LETTER V +0x77 0x0077 # LATIN SMALL LETTER W +0x78 0x0078 # LATIN SMALL LETTER X +0x79 0x0079 # LATIN SMALL LETTER Y +0x7A 0x007A # LATIN SMALL LETTER Z +0x7B 0x007B # LEFT CURLY BRACKET +0x7C 0x007C # VERTICAL LINE +0x7D 0x007D # RIGHT CURLY BRACKET +0x7E 0x007E # TILDE +0x7F 0x007F # DELETE +0x80 0x0080 # +0x81 0x0081 # +0x82 0x0082 # +0x83 0x0083 # +0x84 0x0084 # +0x85 0x0085 # +0x86 0x0086 # +0x87 0x0087 # +0x88 0x0088 # +0x89 0x0089 # +0x8A 0x008A # +0x8B 0x008B # +0x8C 0x008C # +0x8D 0x008D # +0x8E 0x008E # +0x8F 0x008F # +0x90 0x0090 # +0x91 0x0091 # +0x92 0x0092 # +0x93 0x0093 # +0x94 0x0094 # +0x95 0x0095 # +0x96 0x0096 # +0x97 0x0097 # +0x98 0x0098 # +0x99 0x0099 # +0x9A 0x009A # +0x9B 0x009B # +0x9C 0x009C # +0x9D 0x009D # +0x9E 0x009E # +0x9F 0x009F # +0xA0 0x00A0 # NO-BREAK SPACE +0xA1 0x00A1 # INVERTED EXCLAMATION MARK +0xA2 0x00A2 # CENT SIGN +0xA3 0x00A3 # POUND SIGN +0xA4 0x00A4 # CURRENCY SIGN +0xA5 0x00A5 # YEN SIGN +0xA6 0x00A6 # BROKEN BAR +0xA7 0x00A7 # SECTION SIGN +0xA8 0x00A8 # DIAERESIS +0xA9 0x00A9 # COPYRIGHT SIGN +0xAA 0x00AA # FEMININE ORDINAL INDICATOR +0xAB 0x00AB # LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC # NOT SIGN +0xAD 0x00AD # SOFT HYPHEN +0xAE 0x00AE # REGISTERED SIGN +0xAF 0x00AF # MACRON +0xB0 0x00B0 # DEGREE SIGN +0xB1 0x00B1 # PLUS-MINUS SIGN +0xB2 0x00B2 # SUPERSCRIPT TWO +0xB3 0x00B3 # SUPERSCRIPT THREE +0xB4 0x00B4 # ACUTE ACCENT +0xB5 0x00B5 # MICRO SIGN +0xB6 0x00B6 # PILCROW SIGN +0xB7 0x00B7 # MIDDLE DOT +0xB8 0x00B8 # CEDILLA +0xB9 0x00B9 # SUPERSCRIPT ONE +0xBA 0x00BA # MASCULINE ORDINAL INDICATOR +0xBB 0x00BB # RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC # VULGAR FRACTION ONE QUARTER +0xBD 0x00BD # VULGAR FRACTION ONE HALF +0xBE 0x00BE # VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF # INVERTED QUESTION MARK +0xC0 0x00C0 # LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 # LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 # LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 # LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 # LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 # LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 # LATIN CAPITAL LETTER AE +0xC7 0x00C7 # LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 # LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 # LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA # LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB # LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC # LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD # LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE # LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF # LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x011E # LATIN CAPITAL LETTER G WITH BREVE +0xD1 0x00D1 # LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x00D2 # LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 # LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 # LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 # LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 # LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 # MULTIPLICATION SIGN +0xD8 0x00D8 # LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 # LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA # LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB # LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC # LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x0130 # LATIN CAPITAL LETTER I WITH DOT ABOVE +0xDE 0x015E # LATIN CAPITAL LETTER S WITH CEDILLA +0xDF 0x00DF # LATIN SMALL LETTER SHARP S +0xE0 0x00E0 # LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 # LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 # LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 # LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 # LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 # LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 # LATIN SMALL LETTER AE +0xE7 0x00E7 # LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 # LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 # LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA # LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB # LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC # LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED # LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE # LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF # LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x011F # LATIN SMALL LETTER G WITH BREVE +0xF1 0x00F1 # LATIN SMALL LETTER N WITH TILDE +0xF2 0x00F2 # LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 # LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 # LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 # LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 # LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 # DIVISION SIGN +0xF8 0x00F8 # LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 # LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA # LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB # LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC # LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x0131 # LATIN SMALL LETTER DOTLESS I +0xFE 0x015F # LATIN SMALL LETTER S WITH CEDILLA +0xFF 0x00FF # LATIN SMALL LETTER Y WITH DIAERESIS + + 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-r.txt b/data/koi8-r.txt new file mode 100644 index 000000000..173f520a1 --- /dev/null +++ b/data/koi8-r.txt @@ -0,0 +1,257 @@ +# koi8-r.txt - Legacy SBCS to Unicode charmap +0x00 0x0000 # 0 +0x01 0x0001 # 0 +0x02 0x0002 # 0 +0x03 0x0003 # 0 +0x04 0x0004 # 0 +0x05 0x0005 # 0 +0x06 0x0006 # 0 +0x07 0x0007 # 0 +0x08 0x0008 # 0 +0x09 0x0009 # 0 +0x0A 0x000A # 0 +0x0B 0x000B # 0 +0x0C 0x000C # 0 +0x0D 0x000D # 0 +0x0E 0x000E # 0 +0x0F 0x000F # 0 +0x10 0x0010 # 0 +0x11 0x0011 # 0 +0x12 0x0012 # 0 +0x13 0x0013 # 0 +0x14 0x0014 # 0 +0x15 0x0015 # 0 +0x16 0x0016 # 0 +0x17 0x0017 # 0 +0x18 0x0018 # 0 +0x19 0x0019 # 0 +0x1A 0x001A # 0 +0x1B 0x001B # 0 +0x1C 0x001C # 0 +0x1D 0x001D # 0 +0x1E 0x001E # 0 +0x1F 0x001F # 0 +0x20 0x0020 # 0 +0x21 0x0021 # 0 +0x22 0x0022 # 0 +0x23 0x0023 # 0 +0x24 0x0024 # 0 +0x25 0x0025 # 0 +0x26 0x0026 # 0 +0x27 0x0027 # 0 +0x28 0x0028 # 0 +0x29 0x0029 # 0 +0x2A 0x002A # 0 +0x2B 0x002B # 0 +0x2C 0x002C # 0 +0x2D 0x002D # 0 +0x2E 0x002E # 0 +0x2F 0x002F # 0 +0x30 0x0030 # 0 +0x31 0x0031 # 0 +0x32 0x0032 # 0 +0x33 0x0033 # 0 +0x34 0x0034 # 0 +0x35 0x0035 # 0 +0x36 0x0036 # 0 +0x37 0x0037 # 0 +0x38 0x0038 # 0 +0x39 0x0039 # 0 +0x3A 0x003A # 0 +0x3B 0x003B # 0 +0x3C 0x003C # 0 +0x3D 0x003D # 0 +0x3E 0x003E # 0 +0x3F 0x003F # 0 +0x40 0x0040 # 0 +0x41 0x0041 # 0 +0x42 0x0042 # 0 +0x43 0x0043 # 0 +0x44 0x0044 # 0 +0x45 0x0045 # 0 +0x46 0x0046 # 0 +0x47 0x0047 # 0 +0x48 0x0048 # 0 +0x49 0x0049 # 0 +0x4A 0x004A # 0 +0x4B 0x004B # 0 +0x4C 0x004C # 0 +0x4D 0x004D # 0 +0x4E 0x004E # 0 +0x4F 0x004F # 0 +0x50 0x0050 # 0 +0x51 0x0051 # 0 +0x52 0x0052 # 0 +0x53 0x0053 # 0 +0x54 0x0054 # 0 +0x55 0x0055 # 0 +0x56 0x0056 # 0 +0x57 0x0057 # 0 +0x58 0x0058 # 0 +0x59 0x0059 # 0 +0x5A 0x005A # 0 +0x5B 0x005B # 0 +0x5C 0x005C # 0 +0x5D 0x005D # 0 +0x5E 0x005E # 0 +0x5F 0x005F # 0 +0x60 0x0060 # 0 +0x61 0x0061 # 0 +0x62 0x0062 # 0 +0x63 0x0063 # 0 +0x64 0x0064 # 0 +0x65 0x0065 # 0 +0x66 0x0066 # 0 +0x67 0x0067 # 0 +0x68 0x0068 # 0 +0x69 0x0069 # 0 +0x6A 0x006A # 0 +0x6B 0x006B # 0 +0x6C 0x006C # 0 +0x6D 0x006D # 0 +0x6E 0x006E # 0 +0x6F 0x006F # 0 +0x70 0x0070 # 0 +0x71 0x0071 # 0 +0x72 0x0072 # 0 +0x73 0x0073 # 0 +0x74 0x0074 # 0 +0x75 0x0075 # 0 +0x76 0x0076 # 0 +0x77 0x0077 # 0 +0x78 0x0078 # 0 +0x79 0x0079 # 0 +0x7A 0x007A # 0 +0x7B 0x007B # 0 +0x7C 0x007C # 0 +0x7D 0x007D # 0 +0x7E 0x007E # 0 +0x7F 0x007F # 0 +0x80 0x2500 # 0 +0x81 0x2502 # 0 +0x82 0x250C # 0 +0x83 0x2510 # 0 +0x84 0x2514 # 0 +0x85 0x2518 # 0 +0x86 0x251C # 0 +0x87 0x2524 # 0 +0x88 0x252C # 0 +0x89 0x2534 # 0 +0x8A 0x253C # 0 +0x8B 0x2580 # 0 +0x8C 0x2584 # 0 +0x8D 0x2588 # 0 +0x8E 0x258C # 0 +0x8F 0x2590 # 0 +0x90 0x2591 # 0 +0x91 0x2592 # 0 +0x92 0x2593 # 0 +0x93 0x2320 # 0 +0x94 0x25A0 # 0 +0x95 0x2022 # 0 +0x96 0x221A # 0 +0x97 0x2248 # 0 +0x98 0x2264 # 0 +0x99 0x2265 # 0 +0x9A 0x00A0 # 0 +0x9B 0x2321 # 0 +0x9C 0x00B0 # 0 +0x9D 0x00B2 # 0 +0x9E 0x00B7 # 0 +0x9F 0x00F7 # 0 +0xA0 0x2550 # 0 +0xA1 0x2551 # 0 +0xA2 0x2552 # 0 +0xA3 0x0451 # 0 +0xA4 0x2553 # 0 +0xA5 0x2554 # 0 +0xA6 0x2555 # 0 +0xA7 0x2556 # 0 +0xA8 0x2557 # 0 +0xA9 0x2558 # 0 +0xAA 0x2559 # 0 +0xAB 0x255A # 0 +0xAC 0x255B # 0 +0xAD 0x255C # 0 +0xAE 0x255D # 0 +0xAF 0x255E # 0 +0xB0 0x255F # 0 +0xB1 0x2560 # 0 +0xB2 0x2561 # 0 +0xB3 0x0401 # 0 +0xB4 0x2562 # 0 +0xB5 0x2563 # 0 +0xB6 0x2564 # 0 +0xB7 0x2565 # 0 +0xB8 0x2566 # 0 +0xB9 0x2567 # 0 +0xBA 0x2568 # 0 +0xBB 0x2569 # 0 +0xBC 0x256A # 0 +0xBD 0x256B # 0 +0xBE 0x256C # 0 +0xBF 0x00A9 # 0 +0xC0 0x044E # 0 +0xC1 0x0430 # 0 +0xC2 0x0431 # 0 +0xC3 0x0446 # 0 +0xC4 0x0434 # 0 +0xC5 0x0435 # 0 +0xC6 0x0444 # 0 +0xC7 0x0433 # 0 +0xC8 0x0445 # 0 +0xC9 0x0438 # 0 +0xCA 0x0439 # 0 +0xCB 0x043A # 0 +0xCC 0x043B # 0 +0xCD 0x043C # 0 +0xCE 0x043D # 0 +0xCF 0x043E # 0 +0xD0 0x043F # 0 +0xD1 0x044F # 0 +0xD2 0x0440 # 0 +0xD3 0x0441 # 0 +0xD4 0x0442 # 0 +0xD5 0x0443 # 0 +0xD6 0x0436 # 0 +0xD7 0x0432 # 0 +0xD8 0x044C # 0 +0xD9 0x044B # 0 +0xDA 0x0437 # 0 +0xDB 0x0448 # 0 +0xDC 0x044D # 0 +0xDD 0x0449 # 0 +0xDE 0x0447 # 0 +0xDF 0x044A # 0 +0xE0 0x042E # 0 +0xE1 0x0410 # 0 +0xE2 0x0411 # 0 +0xE3 0x0426 # 0 +0xE4 0x0414 # 0 +0xE5 0x0415 # 0 +0xE6 0x0424 # 0 +0xE7 0x0413 # 0 +0xE8 0x0425 # 0 +0xE9 0x0418 # 0 +0xEA 0x0419 # 0 +0xEB 0x041A # 0 +0xEC 0x041B # 0 +0xED 0x041C # 0 +0xEE 0x041D # 0 +0xEF 0x041E # 0 +0xF0 0x041F # 0 +0xF1 0x042F # 0 +0xF2 0x0420 # 0 +0xF3 0x0421 # 0 +0xF4 0x0422 # 0 +0xF5 0x0423 # 0 +0xF6 0x0416 # 0 +0xF7 0x0412 # 0 +0xF8 0x042C # 0 +0xF9 0x042B # 0 +0xFA 0x0417 # 0 +0xFB 0x0428 # 0 +0xFC 0x042D # 0 +0xFD 0x0429 # 0 +0xFE 0x0427 # 0 +0xFF 0x042A # 0 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/koi8-u.txt b/data/koi8-u.txt new file mode 100644 index 000000000..9942e2192 --- /dev/null +++ b/data/koi8-u.txt @@ -0,0 +1,257 @@ +# koi8-u.txt - Legacy SBCS to Unicode charmap +0x00 0x0000 # 0 +0x01 0x0001 # 0 +0x02 0x0002 # 0 +0x03 0x0003 # 0 +0x04 0x0004 # 0 +0x05 0x0005 # 0 +0x06 0x0006 # 0 +0x07 0x0007 # 0 +0x08 0x0008 # 0 +0x09 0x0009 # 0 +0x0A 0x000A # 0 +0x0B 0x000B # 0 +0x0C 0x000C # 0 +0x0D 0x000D # 0 +0x0E 0x000E # 0 +0x0F 0x000F # 0 +0x10 0x0010 # 0 +0x11 0x0011 # 0 +0x12 0x0012 # 0 +0x13 0x0013 # 0 +0x14 0x0014 # 0 +0x15 0x0015 # 0 +0x16 0x0016 # 0 +0x17 0x0017 # 0 +0x18 0x0018 # 0 +0x19 0x0019 # 0 +0x1A 0x001A # 0 +0x1B 0x001B # 0 +0x1C 0x001C # 0 +0x1D 0x001D # 0 +0x1E 0x001E # 0 +0x1F 0x001F # 0 +0x20 0x0020 # 0 +0x21 0x0021 # 0 +0x22 0x0022 # 0 +0x23 0x0023 # 0 +0x24 0x0024 # 0 +0x25 0x0025 # 0 +0x26 0x0026 # 0 +0x27 0x0027 # 0 +0x28 0x0028 # 0 +0x29 0x0029 # 0 +0x2A 0x002A # 0 +0x2B 0x002B # 0 +0x2C 0x002C # 0 +0x2D 0x002D # 0 +0x2E 0x002E # 0 +0x2F 0x002F # 0 +0x30 0x0030 # 0 +0x31 0x0031 # 0 +0x32 0x0032 # 0 +0x33 0x0033 # 0 +0x34 0x0034 # 0 +0x35 0x0035 # 0 +0x36 0x0036 # 0 +0x37 0x0037 # 0 +0x38 0x0038 # 0 +0x39 0x0039 # 0 +0x3A 0x003A # 0 +0x3B 0x003B # 0 +0x3C 0x003C # 0 +0x3D 0x003D # 0 +0x3E 0x003E # 0 +0x3F 0x003F # 0 +0x40 0x0040 # 0 +0x41 0x0041 # 0 +0x42 0x0042 # 0 +0x43 0x0043 # 0 +0x44 0x0044 # 0 +0x45 0x0045 # 0 +0x46 0x0046 # 0 +0x47 0x0047 # 0 +0x48 0x0048 # 0 +0x49 0x0049 # 0 +0x4A 0x004A # 0 +0x4B 0x004B # 0 +0x4C 0x004C # 0 +0x4D 0x004D # 0 +0x4E 0x004E # 0 +0x4F 0x004F # 0 +0x50 0x0050 # 0 +0x51 0x0051 # 0 +0x52 0x0052 # 0 +0x53 0x0053 # 0 +0x54 0x0054 # 0 +0x55 0x0055 # 0 +0x56 0x0056 # 0 +0x57 0x0057 # 0 +0x58 0x0058 # 0 +0x59 0x0059 # 0 +0x5A 0x005A # 0 +0x5B 0x005B # 0 +0x5C 0x005C # 0 +0x5D 0x005D # 0 +0x5E 0x005E # 0 +0x5F 0x005F # 0 +0x60 0x0060 # 0 +0x61 0x0061 # 0 +0x62 0x0062 # 0 +0x63 0x0063 # 0 +0x64 0x0064 # 0 +0x65 0x0065 # 0 +0x66 0x0066 # 0 +0x67 0x0067 # 0 +0x68 0x0068 # 0 +0x69 0x0069 # 0 +0x6A 0x006A # 0 +0x6B 0x006B # 0 +0x6C 0x006C # 0 +0x6D 0x006D # 0 +0x6E 0x006E # 0 +0x6F 0x006F # 0 +0x70 0x0070 # 0 +0x71 0x0071 # 0 +0x72 0x0072 # 0 +0x73 0x0073 # 0 +0x74 0x0074 # 0 +0x75 0x0075 # 0 +0x76 0x0076 # 0 +0x77 0x0077 # 0 +0x78 0x0078 # 0 +0x79 0x0079 # 0 +0x7A 0x007A # 0 +0x7B 0x007B # 0 +0x7C 0x007C # 0 +0x7D 0x007D # 0 +0x7E 0x007E # 0 +0x7F 0x007F # 0 +0x80 0x2500 # 0 +0x81 0x2502 # 0 +0x82 0x250C # 0 +0x83 0x2510 # 0 +0x84 0x2514 # 0 +0x85 0x2518 # 0 +0x86 0x251C # 0 +0x87 0x2524 # 0 +0x88 0x252C # 0 +0x89 0x2534 # 0 +0x8A 0x253C # 0 +0x8B 0x2580 # 0 +0x8C 0x2584 # 0 +0x8D 0x2588 # 0 +0x8E 0x258C # 0 +0x8F 0x2590 # 0 +0x90 0x2591 # 0 +0x91 0x2592 # 0 +0x92 0x2593 # 0 +0x93 0x2320 # 0 +0x94 0x25A0 # 0 +0x95 0x2019 # 0 +0x96 0x221A # 0 +0x97 0x2248 # 0 +0x98 0x2264 # 0 +0x99 0x2265 # 0 +0x9A 0x00A0 # 0 +0x9B 0x2321 # 0 +0x9C 0x00B0 # 0 +0x9D 0x00B2 # 0 +0x9E 0x00B7 # 0 +0x9F 0x00F7 # 0 +0xA0 0x2550 # 0 +0xA1 0x2551 # 0 +0xA2 0x2552 # 0 +0xA3 0x0451 # 0 +0xA4 0x0454 # 0 +0xA5 0x2554 # 0 +0xA6 0x0456 # 0 +0xA7 0x0457 # 0 +0xA8 0x2557 # 0 +0xA9 0x2558 # 0 +0xAA 0x2559 # 0 +0xAB 0x255A # 0 +0xAC 0x255B # 0 +0xAD 0x0491 # 0 +0xAE 0x255D # 0 +0xAF 0x255E # 0 +0xB0 0x255F # 0 +0xB1 0x2560 # 0 +0xB2 0x2561 # 0 +0xB3 0x0401 # 0 +0xB4 0x0404 # 0 +0xB5 0x2563 # 0 +0xB6 0x0406 # 0 +0xB7 0x0407 # 0 +0xB8 0x2566 # 0 +0xB9 0x2567 # 0 +0xBA 0x2568 # 0 +0xBB 0x2569 # 0 +0xBC 0x256A # 0 +0xBD 0x0490 # 0 +0xBE 0x256C # 0 +0xBF 0x00A9 # 0 +0xC0 0x044E # 0 +0xC1 0x0430 # 0 +0xC2 0x0431 # 0 +0xC3 0x0446 # 0 +0xC4 0x0434 # 0 +0xC5 0x0435 # 0 +0xC6 0x0444 # 0 +0xC7 0x0433 # 0 +0xC8 0x0445 # 0 +0xC9 0x0438 # 0 +0xCA 0x0439 # 0 +0xCB 0x043A # 0 +0xCC 0x043B # 0 +0xCD 0x043C # 0 +0xCE 0x043D # 0 +0xCF 0x043E # 0 +0xD0 0x043F # 0 +0xD1 0x044F # 0 +0xD2 0x0440 # 0 +0xD3 0x0441 # 0 +0xD4 0x0442 # 0 +0xD5 0x0443 # 0 +0xD6 0x0436 # 0 +0xD7 0x0432 # 0 +0xD8 0x044C # 0 +0xD9 0x044B # 0 +0xDA 0x0437 # 0 +0xDB 0x0448 # 0 +0xDC 0x044D # 0 +0xDD 0x0449 # 0 +0xDE 0x0447 # 0 +0xDF 0x044A # 0 +0xE0 0x042E # 0 +0xE1 0x0410 # 0 +0xE2 0x0411 # 0 +0xE3 0x0426 # 0 +0xE4 0x0414 # 0 +0xE5 0x0415 # 0 +0xE6 0x0424 # 0 +0xE7 0x0413 # 0 +0xE8 0x0425 # 0 +0xE9 0x0418 # 0 +0xEA 0x0419 # 0 +0xEB 0x041A # 0 +0xEC 0x041B # 0 +0xED 0x041C # 0 +0xEE 0x041D # 0 +0xEF 0x041E # 0 +0xF0 0x041F # 0 +0xF1 0x042F # 0 +0xF2 0x0420 # 0 +0xF3 0x0421 # 0 +0xF4 0x0422 # 0 +0xF5 0x0423 # 0 +0xF6 0x0416 # 0 +0xF7 0x0412 # 0 +0xF8 0x042C # 0 +0xF9 0x042B # 0 +0xFA 0x0417 # 0 +0xFB 0x0428 # 0 +0xFC 0x042D # 0 +0xFD 0x0429 # 0 +0xFE 0x0427 # 0 +0xFF 0x042A # 0 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..998f59a92 --- /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-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/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 4494 2005-02-18 02:18:11Z mike $". +% +%%EOF diff --git a/data/standard b/data/standard new file mode 100644 index 000000000..8fac59e5f --- /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-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/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 4494 2005-02-18 02:18:11Z mike $". +% +%%EOF diff --git a/data/testprint.ps b/data/testprint.ps new file mode 100644 index 000000000..69a2406e3 --- /dev/null +++ b/data/testprint.ps @@ -0,0 +1,636 @@ +%!PS-Adobe-3.0 +%%BoundingBox: 0 0 612 792 +%%Pages: 1 +%%LanguageLevel: 1 +%%DocumentData: Clean7Bit +%%DocumentSuppliedResources: procset testprint/1.2 +%%DocumentNeededResources: font Helvetica Helvetica-Bold Times-Roman +%%Creator: Michael Sweet, Easy Software Products +%%CreationDate: D:20051002193000+0500 +%%Title: Test Page +%%EndComments +%%BeginProlog +%%BeginResource procset testprint 1.2 0 +% +% PostScript test page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/SEXTANT { % Draw a color wheel sextant... + % (name) white radius r g b SEXTANT - + % Loop through 100 shades... + 0 0.010101 0.98 { + % Set the color... + dup 0.75 le { % Get "white" value + % Start from black + dup 0.75 div % val2 = val / 0.75 + + 0 index 5 index mul % R = R * val2 + 1 index 5 index mul % G = G * val2 + 2 index 5 index mul % B = B * val2 + + 4 -1 roll pop % Discard val2 + } { + % Fade to white + dup neg 1 add 4 mul % val2 = (1 - val) * 4 + + 0 index 5 index mul % R = R * val2 + 1 index neg 1 add add % + (1 - val2) + 1 index 5 index mul % G = G * val2 + 2 index neg 1 add add % + (1 - val2) + 2 index 5 index mul % B = B * val2 + 3 index neg 1 add add % + (1 - val2) + + 4 -1 roll pop % Discard val2 + } ifelse + setrgbcolor % Set the color... + + % Draw the polygon... + newpath % Start a new path... + dup 5 index mul % r1 = radius * val + 0 0 3 -1 roll 0 60 arc % Draw the inner arc + + dup 0.010101 add 5 index mul% r2 = (radius + 0.010101) * val + 0 0 3 -1 roll 60 0 arcn % Draw the outer arc + + closepath % Close the path + fill % Fill it... + + pop % Pop value... + } for + + % Draw a line around the polygons... + pop pop pop dup % Pop R, G, B, start + 0 setgray % Black + newpath + 0 0 moveto % Center + 0 0 3 -1 roll 0 60 arc % Arc around octant + closepath % Back to center + stroke % Stroke it... + + % Draw the label... + dup % Save radius + dup 30 cos mul % X = radius * cos(30) + exch 30 sin mul % Y = radius * sin(30) + moveto % Position label + + gsave + 30 rotate % Rotate label + dup 0.05 mul % Offset to the right + exch -0.05 mul % and down... + 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 + gsave + 48 div dup scale + + /Helvetica-Bold findfont 38.2 scalefont setfont + 0 setgray + -3 19.5 moveto (ESP) show + + /Helvetica-Narrow-Oblique findfont 8.2 scalefont setfont + 0 2 moveto (Easy Software Products) show + + 1 -0.01 0 { dup neg 1.0 add setgray 0 11 3 -1 roll 68 mul 4.5 rectfill } for + + 1 0 0 setrgbcolor + 67.5 11 4.5 4.5 rectfill + grestore +} 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 + + /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) + + % Draw rulers along the edges... + /CENTIMETER 72 2.54 div def + /MILLIMETER 72 25.4 div def + + smallFont setfont % Font + + gsave % Left side inches + pageLeft 72 mul 0 translate % Offset left edge + + 1 setlinewidth % Draw normal lines + 72 72 pageTop 72 mul { % Height inches + dup dup + 0 exch moveto 24 0 rlineto stroke % Draw tic mark + 24 exch pageHeight sub moveto % Draw number + 72 div cvi 10 string cvs RIGHT + } for + + 0.5 setlinewidth % Draw thin lines + 18 18 pageTop 72 mul { % 1/4 inches + 0 exch moveto 15 0 rlineto stroke % Draw tic mark + } for + + 9 9 pageTop 72 mul { % 1/8 inches + 0 exch moveto 6 0 rlineto stroke % Draw tic mark + } for + grestore + + gsave % Bottom inches + 0 pageBottom 72 mul translate % Offset bottom edge + + 1 setlinewidth % Draw normal lines + 72 72 pageRight 72 mul { % Width inches + dup dup + 0 moveto 0 24 rlineto stroke % Draw tic mark + 3 add 27 pageHeight sub moveto % Draw number + 72 div cvi 10 string cvs show + } for + + 0.5 setlinewidth % Draw thin lines + 18 18 pageRight 72 mul { % 1/4 inches + 0 moveto 0 15 rlineto stroke % Draw tic mark + } for + + 9 9 pageRight 72 mul { % 1/8 inches + 0 moveto 0 6 rlineto stroke % Draw tic mark + } for + grestore + + gsave % Right side centimeters + pageRight 72 mul 0 translate % Offset right edge + + 1 setlinewidth % Draw normal lines + CENTIMETER CENTIMETER + pageTop 72 mul { % Height centimeters + 0 exch moveto -24 0 rlineto stroke% Draw tic mark + } for + 1 1 pageTop 2.54 mul { % Height labels + dup + -24 exch CENTIMETER mul + pageHeight sub moveto % Draw number + cvi 10 string cvs show + } for + + 0.5 setlinewidth % Draw thin lines + 0 0.5 CENTIMETER mul + pageTop 72 mul { % 1/2 centimeters + 0 exch moveto -15 0 rlineto stroke% Draw tic mark + } for + 0 MILLIMETER pageTop 72 mul { % Millimeters + 0 exch moveto -6 0 rlineto stroke % Draw tic mark + } for + grestore + + gsave % Top centimeters + 0 pageTop 72 mul translate % Offset top edge + + 1 setlinewidth % Draw normal lines + CENTIMETER CENTIMETER + pageRight 72 mul { % Width centimeters + 0 moveto 0 -24 rlineto stroke % Draw tic mark + } for + 1 1 pageRight 2.54 mul { % Width labels + dup + CENTIMETER mul 3 add -24 moveto % Draw number + cvi 10 string cvs show + } for + + 0.5 setlinewidth % Draw thin lines + 0 0.5 CENTIMETER mul + pageRight 72 mul { % 1/2 centimeters + 0 moveto 0 -15 rlineto stroke % Draw tic mark + } for + 0 MILLIMETER pageRight 72 mul { % Millimeters + 0 moveto 0 -6 rlineto stroke % Draw tic mark + } for + grestore + + % Offset page to account for lower-left margin... + pageLeft 72 mul + pageBottom 72 mul + translate + + % Set text font and color... + mediumFont setfont % Font + 0 setgray % Color + 1 setlinewidth % Draw normal lines + + % Draw the color wheel... + 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) 3 -1 roll 0 1 1 SEXTANT 60 rotate + dup (M) 3 -1 roll 1 0 1 SEXTANT 60 rotate + dup (Y) 3 -1 roll 1 1 0 SEXTANT 60 rotate + dup (R) 3 -1 roll 1 0 0 SEXTANT 60 rotate + dup (G) 3 -1 roll 0 1 0 SEXTANT 60 rotate + dup (B) 3 -1 roll 0 0 1 SEXTANT 60 rotate + + pop + grestore + + % Label the color wheel... + pageWidth 18 mul % x = pageWidth * 1/4 * 72 + pageHeight 43 mul % y = pageHeight * 19/32 * 72 + moveto % Position the text + (Color Wheel) CENTER % Show the text centered + + % Draw the gray ramp... + gsave + % Position the gray ramp in the center... + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 54 mul % y = pageHeight * 3/4 * 72 + wheelSize sub % - wheelSize + translate + + % Loop through 100 shades... + 0 0.010101 0.98 { + % Set the color... + dup setgray % Set the grayscale... + + % Draw the polygon... + newpath % Start a new path... + + wheelSize -0.2 mul % X = -wheelSize / 5 + 1 index 2 mul wheelSize mul % Y = val * 2 * wheelSize + moveto % Move there... + + wheelSize 0.4 mul 0 rlineto % Right side... + + wheelSize 0.2 mul % X = wheelSize / 5 + 1 index 0.010101 add 2 mul wheelSize mul + % Y = (val + 0.010101) * 2 * wheelSize + lineto % Move there... + + wheelSize -0.4 mul 0 rlineto % Left side... + + closepath % Close the path + fill % Fill it... + + pop % Pop value... + } for + + 0 setgray % Black + + newpath % Start a new path + wheelSize -0.2 mul 0 moveto % Bottom left + wheelSize 0.4 mul 0 rlineto % Bottom right + 0 wheelSize 2 mul rlineto % Upper right + wheelSize -0.4 mul 0 rlineto % Upper left + closepath % Close the path + stroke % Stroke it... + + 0 wheelSize -0.2 mul moveto % Center bottom for label + (K) CENTER % Center K at bottom + + 0 wheelSize 2.05 mul moveto % Center top for label + (W) CENTER % Center W at top + grestore + + % Label the gray ramp... + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 43 mul % y = pageHeight * 19/32 * 72 + moveto % Position the text + (Gray Ramp) 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 43 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... + 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 66 mul % Top of page (11/12ths) + 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 12 mul % Bottom of page + moveto % Position text + (Printed Using CUPS v1.2.x) CENTER % Show text centered + + pageWidth 34 mul % Left-center of page + pageHeight 8 mul % Move down... + 2 copy moveto % Position text + smallFont setfont % Font + (Copyright 1993-2005 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 Easy Software Products,) CENTER + pageHeight sub % Move down... + 2 copy moveto % Position text + (44141 Airport View Drive, Suite 204, Hollywood, Maryland, 20636, USA.) CENTER + pageHeight sub % Move down... + pageHeight sub % Move down... + moveto % Position text + (Need help? Contact your operating system vendor or visit "http://www.cups.org/".) CENTER + + % Then the CUPS logo.... + gsave + pageWidth 4 mul + pageHeight 4 mul + translate + pageWidth 9 mul CUPSLOGO + grestore + + % And the ESP logo.... + gsave + pageWidth 58 mul + pageHeight 4 mul + translate + pageWidth 6 mul ESPLOGO + grestore +% Show the page... +grestore +showpage +% +% End of "$Id: testprint.ps 4743 2005-10-02 23:29:44Z mike $". +% +%%EOF diff --git a/data/topsecret b/data/topsecret new file mode 100644 index 000000000..389cbf105 --- /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-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/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 4494 2005-02-18 02:18:11Z mike $". +% +%%EOF diff --git a/data/unclassified b/data/unclassified new file mode 100644 index 000000000..804773e6e --- /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-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/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 4494 2005-02-18 02:18:11Z mike $". +% +%%EOF diff --git a/data/uni-comb.txt b/data/uni-comb.txt new file mode 100644 index 000000000..1e2021738 --- /dev/null +++ b/data/uni-comb.txt @@ -0,0 +1,299 @@ +# uni-comb.txt - Unicode combining class +0300;230;NSM; +0301;230;NSM; +0302;230;NSM; +0303;230;NSM; +0304;230;NSM; +0305;230;NSM; +0306;230;NSM; +0307;230;NSM; +0308;230;NSM; +0309;230;NSM; +030A;230;NSM; +030B;230;NSM; +030C;230;NSM; +030D;230;NSM; +030E;230;NSM; +030F;230;NSM; +0310;230;NSM; +0311;230;NSM; +0312;230;NSM; +0313;230;NSM; +0314;230;NSM; +0315;232;NSM; +0316;220;NSM; +0317;220;NSM; +0318;220;NSM; +0319;220;NSM; +031A;232;NSM; +031B;216;NSM; +031C;220;NSM; +031D;220;NSM; +031E;220;NSM; +031F;220;NSM; +0320;220;NSM; +0321;202;NSM; +0322;202;NSM; +0323;220;NSM; +0324;220;NSM; +0325;220;NSM; +0326;220;NSM; +0327;202;NSM; +0328;202;NSM; +0329;220;NSM; +032A;220;NSM; +032B;220;NSM; +032C;220;NSM; +032D;220;NSM; +032E;220;NSM; +032F;220;NSM; +0330;220;NSM; +0331;220;NSM; +0332;220;NSM; +0333;220;NSM; +0334;1;NSM; +0335;1;NSM; +0336;1;NSM; +0337;1;NSM; +0338;1;NSM; +0339;220;NSM; +033A;220;NSM; +033B;220;NSM; +033C;220;NSM; +033D;230;NSM; +033E;230;NSM; +033F;230;NSM; +0340;230;NSM; +0341;230;NSM; +0342;230;NSM; +0343;230;NSM; +0344;230;NSM; +0345;240;NSM; +0346;230;NSM; +0347;220;NSM; +0348;220;NSM; +0349;220;NSM; +034A;230;NSM; +034B;230;NSM; +034C;230;NSM; +034D;220;NSM; +034E;220;NSM; +0360;234;NSM; +0361;234;NSM; +0362;233;NSM; +0483;230;NSM; +0484;230;NSM; +0485;230;NSM; +0486;230;NSM; +0591;220;NSM; +0592;230;NSM; +0593;230;NSM; +0594;230;NSM; +0595;230;NSM; +0596;220;NSM; +0597;230;NSM; +0598;230;NSM; +0599;230;NSM; +059A;222;NSM; +059B;220;NSM; +059C;230;NSM; +059D;230;NSM; +059E;230;NSM; +059F;230;NSM; +05A0;230;NSM; +05A1;230;NSM; +05A3;220;NSM; +05A4;220;NSM; +05A5;220;NSM; +05A6;220;NSM; +05A7;220;NSM; +05A8;230;NSM; +05A9;230;NSM; +05AA;220;NSM; +05AB;230;NSM; +05AC;230;NSM; +05AD;222;NSM; +05AE;228;NSM; +05AF;230;NSM; +05B0;10;NSM; +05B1;11;NSM; +05B2;12;NSM; +05B3;13;NSM; +05B4;14;NSM; +05B5;15;NSM; +05B6;16;NSM; +05B7;17;NSM; +05B8;18;NSM; +05B9;19;NSM; +05BB;20;NSM; +05BC;21;NSM; +05BD;22;NSM; +05BF;23;NSM; +05C1;24;NSM; +05C2;25;NSM; +05C4;230;NSM; +064B;27;NSM; +064C;28;NSM; +064D;29;NSM; +064E;30;NSM; +064F;31;NSM; +0650;32;NSM; +0651;33;NSM; +0652;34;NSM; +0653;230;NSM; +0654;230;NSM; +0655;220;NSM; +0670;35;NSM; +06D6;230;NSM; +06D7;230;NSM; +06D8;230;NSM; +06D9;230;NSM; +06DA;230;NSM; +06DB;230;NSM; +06DC;230;NSM; +06DF;230;NSM; +06E0;230;NSM; +06E1;230;NSM; +06E2;230;NSM; +06E3;220;NSM; +06E4;230;NSM; +06E7;230;NSM; +06E8;230;NSM; +06EA;220;NSM; +06EB;230;NSM; +06EC;230;NSM; +06ED;220;NSM; +0711;36;NSM; +0730;230;NSM; +0731;220;NSM; +0732;230;NSM; +0733;230;NSM; +0734;220;NSM; +0735;230;NSM; +0736;230;NSM; +0737;220;NSM; +0738;220;NSM; +0739;220;NSM; +073A;230;NSM; +073B;220;NSM; +073C;220;NSM; +073D;230;NSM; +073E;220;NSM; +073F;230;NSM; +0740;230;NSM; +0741;230;NSM; +0742;220;NSM; +0743;230;NSM; +0744;220;NSM; +0745;230;NSM; +0746;220;NSM; +0747;230;NSM; +0748;220;NSM; +0749;230;NSM; +074A;230;NSM; +093C;7;NSM; +094D;9;NSM; +0951;230;NSM; +0952;220;NSM; +0953;230;NSM; +0954;230;NSM; +09BC;7;NSM; +09CD;9;NSM; +0A3C;7;NSM; +0A4D;9;NSM; +0ABC;7;NSM; +0ACD;9;NSM; +0B3C;7;NSM; +0B4D;9;NSM; +0BCD;9;NSM; +0C4D;9;NSM; +0C55;84;NSM; +0C56;91;NSM; +0CCD;9;NSM; +0D4D;9;NSM; +0DCA;9;NSM; +0E38;103;NSM; +0E39;103;NSM; +0E3A;9;NSM; +0E48;107;NSM; +0E49;107;NSM; +0E4A;107;NSM; +0E4B;107;NSM; +0EB8;118;NSM; +0EB9;118;NSM; +0EC8;122;NSM; +0EC9;122;NSM; +0ECA;122;NSM; +0ECB;122;NSM; +0F18;220;NSM; +0F19;220;NSM; +0F35;220;NSM; +0F37;220;NSM; +0F39;216;NSM; +0F71;129;NSM; +0F72;130;NSM; +0F74;132;NSM; +0F7A;130;NSM; +0F7B;130;NSM; +0F7C;130;NSM; +0F7D;130;NSM; +0F80;130;NSM; +0F82;230;NSM; +0F83;230;NSM; +0F84;9;NSM; +0F86;230;NSM; +0F87;230;NSM; +0FC6;220;NSM; +1037;7;NSM; +1039;9;NSM; +17D2;9;NSM; +18A9;228;NSM; +20D0;230;NSM; +20D1;230;NSM; +20D2;1;NSM; +20D3;1;NSM; +20D4;230;NSM; +20D5;230;NSM; +20D6;230;NSM; +20D7;230;NSM; +20D8;1;NSM; +20D9;1;NSM; +20DA;1;NSM; +20DB;230;NSM; +20DC;230;NSM; +20E1;230;NSM; +302A;218;NSM; +302B;228;NSM; +302C;232;NSM; +302D;222;NSM; +302E;224;NSM; +302F;224;NSM; +3099;8;NSM; +309A;8;NSM; +FB1E;26;NSM; +FE20;230;NSM; +FE21;230;NSM; +FE22;230;NSM; +FE23;230;NSM; +1D167;1;NSM; +1D168;1;NSM; +1D169;1;NSM; +1D17B;220;NSM; +1D17C;220;NSM; +1D17D;220;NSM; +1D17E;220;NSM; +1D17F;220;NSM; +1D180;220;NSM; +1D181;220;NSM; +1D182;220;NSM; +1D185;230;NSM; +1D186;230;NSM; +1D187;230;NSM; +1D188;230;NSM; +1D189;230;NSM; +1D18A;220;NSM; +1D18B;220;NSM; +1D1AA;230;NSM; +1D1AB;230;NSM; +1D1AC;230;NSM; +1D1AD;230;NSM; diff --git a/data/uni-fold.txt b/data/uni-fold.txt new file mode 100644 index 000000000..df75af841 --- /dev/null +++ b/data/uni-fold.txt @@ -0,0 +1,713 @@ +# uni-fold.txt - Unicode simple case folding +0041 0061;C; +0042 0062;C; +0043 0063;C; +0044 0064;C; +0045 0065;C; +0046 0066;C; +0047 0067;C; +0048 0068;C; +0049 0069;C; +004A 006A;C; +004B 006B;C; +004C 006C;C; +004D 006D;C; +004E 006E;C; +004F 006F;C; +0050 0070;C; +0051 0071;C; +0052 0072;C; +0053 0073;C; +0054 0074;C; +0055 0075;C; +0056 0076;C; +0057 0077;C; +0058 0078;C; +0059 0079;C; +005A 007A;C; +00B5 03BC;C; +00C0 00E0;C; +00C1 00E1;C; +00C2 00E2;C; +00C3 00E3;C; +00C4 00E4;C; +00C5 00E5;C; +00C6 00E6;C; +00C7 00E7;C; +00C8 00E8;C; +00C9 00E9;C; +00CA 00EA;C; +00CB 00EB;C; +00CC 00EC;C; +00CD 00ED;C; +00CE 00EE;C; +00CF 00EF;C; +00D0 00F0;C; +00D1 00F1;C; +00D2 00F2;C; +00D3 00F3;C; +00D4 00F4;C; +00D5 00F5;C; +00D6 00F6;C; +00D8 00F8;C; +00D9 00F9;C; +00DA 00FA;C; +00DB 00FB;C; +00DC 00FC;C; +00DD 00FD;C; +00DE 00FE;C; +0100 0101;C; +0102 0103;C; +0104 0105;C; +0106 0107;C; +0108 0109;C; +010A 010B;C; +010C 010D;C; +010E 010F;C; +0110 0111;C; +0112 0113;C; +0114 0115;C; +0116 0117;C; +0118 0119;C; +011A 011B;C; +011C 011D;C; +011E 011F;C; +0120 0121;C; +0122 0123;C; +0124 0125;C; +0126 0127;C; +0128 0129;C; +012A 012B;C; +012C 012D;C; +012E 012F;C; +0130 0069;I; +0131 0069;I; +0132 0133;C; +0134 0135;C; +0136 0137;C; +0139 013A;C; +013B 013C;C; +013D 013E;C; +013F 0140;C; +0141 0142;C; +0143 0144;C; +0145 0146;C; +0147 0148;C; +014A 014B;C; +014C 014D;C; +014E 014F;C; +0150 0151;C; +0152 0153;C; +0154 0155;C; +0156 0157;C; +0158 0159;C; +015A 015B;C; +015C 015D;C; +015E 015F;C; +0160 0161;C; +0162 0163;C; +0164 0165;C; +0166 0167;C; +0168 0169;C; +016A 016B;C; +016C 016D;C; +016E 016F;C; +0170 0171;C; +0172 0173;C; +0174 0175;C; +0176 0177;C; +0178 00FF;C; +0179 017A;C; +017B 017C;C; +017D 017E;C; +017F 0073;C; +0181 0253;C; +0182 0183;C; +0184 0185;C; +0186 0254;C; +0187 0188;C; +0189 0256;C; +018A 0257;C; +018B 018C;C; +018E 01DD;C; +018F 0259;C; +0190 025B;C; +0191 0192;C; +0193 0260;C; +0194 0263;C; +0196 0269;C; +0197 0268;C; +0198 0199;C; +019C 026F;C; +019D 0272;C; +019F 0275;C; +01A0 01A1;C; +01A2 01A3;C; +01A4 01A5;C; +01A6 0280;C; +01A7 01A8;C; +01A9 0283;C; +01AC 01AD;C; +01AE 0288;C; +01AF 01B0;C; +01B1 028A;C; +01B2 028B;C; +01B3 01B4;C; +01B5 01B6;C; +01B7 0292;C; +01B8 01B9;C; +01BC 01BD;C; +01C4 01C6;C; +01C5 01C6;C; +01C7 01C9;C; +01C8 01C9;C; +01CA 01CC;C; +01CB 01CC;C; +01CD 01CE;C; +01CF 01D0;C; +01D1 01D2;C; +01D3 01D4;C; +01D5 01D6;C; +01D7 01D8;C; +01D9 01DA;C; +01DB 01DC;C; +01DE 01DF;C; +01E0 01E1;C; +01E2 01E3;C; +01E4 01E5;C; +01E6 01E7;C; +01E8 01E9;C; +01EA 01EB;C; +01EC 01ED;C; +01EE 01EF;C; +01F1 01F3;C; +01F2 01F3;C; +01F4 01F5;C; +01F6 0195;C; +01F7 01BF;C; +01F8 01F9;C; +01FA 01FB;C; +01FC 01FD;C; +01FE 01FF;C; +0200 0201;C; +0202 0203;C; +0204 0205;C; +0206 0207;C; +0208 0209;C; +020A 020B;C; +020C 020D;C; +020E 020F;C; +0210 0211;C; +0212 0213;C; +0214 0215;C; +0216 0217;C; +0218 0219;C; +021A 021B;C; +021C 021D;C; +021E 021F;C; +0222 0223;C; +0224 0225;C; +0226 0227;C; +0228 0229;C; +022A 022B;C; +022C 022D;C; +022E 022F;C; +0230 0231;C; +0232 0233;C; +0345 03B9;C; +0386 03AC;C; +0388 03AD;C; +0389 03AE;C; +038A 03AF;C; +038C 03CC;C; +038E 03CD;C; +038F 03CE;C; +0391 03B1;C; +0392 03B2;C; +0393 03B3;C; +0394 03B4;C; +0395 03B5;C; +0396 03B6;C; +0397 03B7;C; +0398 03B8;C; +0399 03B9;C; +039A 03BA;C; +039B 03BB;C; +039C 03BC;C; +039D 03BD;C; +039E 03BE;C; +039F 03BF;C; +03A0 03C0;C; +03A1 03C1;C; +03A3 03C3;C; +03A4 03C4;C; +03A5 03C5;C; +03A6 03C6;C; +03A7 03C7;C; +03A8 03C8;C; +03A9 03C9;C; +03AA 03CA;C; +03AB 03CB;C; +03C2 03C3;C; +03D0 03B2;C; +03D1 03B8;C; +03D5 03C6;C; +03D6 03C0;C; +03DA 03DB;C; +03DC 03DD;C; +03DE 03DF;C; +03E0 03E1;C; +03E2 03E3;C; +03E4 03E5;C; +03E6 03E7;C; +03E8 03E9;C; +03EA 03EB;C; +03EC 03ED;C; +03EE 03EF;C; +03F0 03BA;C; +03F1 03C1;C; +03F2 03C3;C; +03F4 03B8;C; +03F5 03B5;C; +0400 0450;C; +0401 0451;C; +0402 0452;C; +0403 0453;C; +0404 0454;C; +0405 0455;C; +0406 0456;C; +0407 0457;C; +0408 0458;C; +0409 0459;C; +040A 045A;C; +040B 045B;C; +040C 045C;C; +040D 045D;C; +040E 045E;C; +040F 045F;C; +0410 0430;C; +0411 0431;C; +0412 0432;C; +0413 0433;C; +0414 0434;C; +0415 0435;C; +0416 0436;C; +0417 0437;C; +0418 0438;C; +0419 0439;C; +041A 043A;C; +041B 043B;C; +041C 043C;C; +041D 043D;C; +041E 043E;C; +041F 043F;C; +0420 0440;C; +0421 0441;C; +0422 0442;C; +0423 0443;C; +0424 0444;C; +0425 0445;C; +0426 0446;C; +0427 0447;C; +0428 0448;C; +0429 0449;C; +042A 044A;C; +042B 044B;C; +042C 044C;C; +042D 044D;C; +042E 044E;C; +042F 044F;C; +0460 0461;C; +0462 0463;C; +0464 0465;C; +0466 0467;C; +0468 0469;C; +046A 046B;C; +046C 046D;C; +046E 046F;C; +0470 0471;C; +0472 0473;C; +0474 0475;C; +0476 0477;C; +0478 0479;C; +047A 047B;C; +047C 047D;C; +047E 047F;C; +0480 0481;C; +048C 048D;C; +048E 048F;C; +0490 0491;C; +0492 0493;C; +0494 0495;C; +0496 0497;C; +0498 0499;C; +049A 049B;C; +049C 049D;C; +049E 049F;C; +04A0 04A1;C; +04A2 04A3;C; +04A4 04A5;C; +04A6 04A7;C; +04A8 04A9;C; +04AA 04AB;C; +04AC 04AD;C; +04AE 04AF;C; +04B0 04B1;C; +04B2 04B3;C; +04B4 04B5;C; +04B6 04B7;C; +04B8 04B9;C; +04BA 04BB;C; +04BC 04BD;C; +04BE 04BF;C; +04C1 04C2;C; +04C3 04C4;C; +04C7 04C8;C; +04CB 04CC;C; +04D0 04D1;C; +04D2 04D3;C; +04D4 04D5;C; +04D6 04D7;C; +04D8 04D9;C; +04DA 04DB;C; +04DC 04DD;C; +04DE 04DF;C; +04E0 04E1;C; +04E2 04E3;C; +04E4 04E5;C; +04E6 04E7;C; +04E8 04E9;C; +04EA 04EB;C; +04EC 04ED;C; +04EE 04EF;C; +04F0 04F1;C; +04F2 04F3;C; +04F4 04F5;C; +04F8 04F9;C; +0531 0561;C; +0532 0562;C; +0533 0563;C; +0534 0564;C; +0535 0565;C; +0536 0566;C; +0537 0567;C; +0538 0568;C; +0539 0569;C; +053A 056A;C; +053B 056B;C; +053C 056C;C; +053D 056D;C; +053E 056E;C; +053F 056F;C; +0540 0570;C; +0541 0571;C; +0542 0572;C; +0543 0573;C; +0544 0574;C; +0545 0575;C; +0546 0576;C; +0547 0577;C; +0548 0578;C; +0549 0579;C; +054A 057A;C; +054B 057B;C; +054C 057C;C; +054D 057D;C; +054E 057E;C; +054F 057F;C; +0550 0580;C; +0551 0581;C; +0552 0582;C; +0553 0583;C; +0554 0584;C; +0555 0585;C; +0556 0586;C; +1E00 1E01;C; +1E02 1E03;C; +1E04 1E05;C; +1E06 1E07;C; +1E08 1E09;C; +1E0A 1E0B;C; +1E0C 1E0D;C; +1E0E 1E0F;C; +1E10 1E11;C; +1E12 1E13;C; +1E14 1E15;C; +1E16 1E17;C; +1E18 1E19;C; +1E1A 1E1B;C; +1E1C 1E1D;C; +1E1E 1E1F;C; +1E20 1E21;C; +1E22 1E23;C; +1E24 1E25;C; +1E26 1E27;C; +1E28 1E29;C; +1E2A 1E2B;C; +1E2C 1E2D;C; +1E2E 1E2F;C; +1E30 1E31;C; +1E32 1E33;C; +1E34 1E35;C; +1E36 1E37;C; +1E38 1E39;C; +1E3A 1E3B;C; +1E3C 1E3D;C; +1E3E 1E3F;C; +1E40 1E41;C; +1E42 1E43;C; +1E44 1E45;C; +1E46 1E47;C; +1E48 1E49;C; +1E4A 1E4B;C; +1E4C 1E4D;C; +1E4E 1E4F;C; +1E50 1E51;C; +1E52 1E53;C; +1E54 1E55;C; +1E56 1E57;C; +1E58 1E59;C; +1E5A 1E5B;C; +1E5C 1E5D;C; +1E5E 1E5F;C; +1E60 1E61;C; +1E62 1E63;C; +1E64 1E65;C; +1E66 1E67;C; +1E68 1E69;C; +1E6A 1E6B;C; +1E6C 1E6D;C; +1E6E 1E6F;C; +1E70 1E71;C; +1E72 1E73;C; +1E74 1E75;C; +1E76 1E77;C; +1E78 1E79;C; +1E7A 1E7B;C; +1E7C 1E7D;C; +1E7E 1E7F;C; +1E80 1E81;C; +1E82 1E83;C; +1E84 1E85;C; +1E86 1E87;C; +1E88 1E89;C; +1E8A 1E8B;C; +1E8C 1E8D;C; +1E8E 1E8F;C; +1E90 1E91;C; +1E92 1E93;C; +1E94 1E95;C; +1E9B 1E61;C; +1EA0 1EA1;C; +1EA2 1EA3;C; +1EA4 1EA5;C; +1EA6 1EA7;C; +1EA8 1EA9;C; +1EAA 1EAB;C; +1EAC 1EAD;C; +1EAE 1EAF;C; +1EB0 1EB1;C; +1EB2 1EB3;C; +1EB4 1EB5;C; +1EB6 1EB7;C; +1EB8 1EB9;C; +1EBA 1EBB;C; +1EBC 1EBD;C; +1EBE 1EBF;C; +1EC0 1EC1;C; +1EC2 1EC3;C; +1EC4 1EC5;C; +1EC6 1EC7;C; +1EC8 1EC9;C; +1ECA 1ECB;C; +1ECC 1ECD;C; +1ECE 1ECF;C; +1ED0 1ED1;C; +1ED2 1ED3;C; +1ED4 1ED5;C; +1ED6 1ED7;C; +1ED8 1ED9;C; +1EDA 1EDB;C; +1EDC 1EDD;C; +1EDE 1EDF;C; +1EE0 1EE1;C; +1EE2 1EE3;C; +1EE4 1EE5;C; +1EE6 1EE7;C; +1EE8 1EE9;C; +1EEA 1EEB;C; +1EEC 1EED;C; +1EEE 1EEF;C; +1EF0 1EF1;C; +1EF2 1EF3;C; +1EF4 1EF5;C; +1EF6 1EF7;C; +1EF8 1EF9;C; +1F08 1F00;C; +1F09 1F01;C; +1F0A 1F02;C; +1F0B 1F03;C; +1F0C 1F04;C; +1F0D 1F05;C; +1F0E 1F06;C; +1F0F 1F07;C; +1F18 1F10;C; +1F19 1F11;C; +1F1A 1F12;C; +1F1B 1F13;C; +1F1C 1F14;C; +1F1D 1F15;C; +1F28 1F20;C; +1F29 1F21;C; +1F2A 1F22;C; +1F2B 1F23;C; +1F2C 1F24;C; +1F2D 1F25;C; +1F2E 1F26;C; +1F2F 1F27;C; +1F38 1F30;C; +1F39 1F31;C; +1F3A 1F32;C; +1F3B 1F33;C; +1F3C 1F34;C; +1F3D 1F35;C; +1F3E 1F36;C; +1F3F 1F37;C; +1F48 1F40;C; +1F49 1F41;C; +1F4A 1F42;C; +1F4B 1F43;C; +1F4C 1F44;C; +1F4D 1F45;C; +1F59 1F51;C; +1F5B 1F53;C; +1F5D 1F55;C; +1F5F 1F57;C; +1F68 1F60;C; +1F69 1F61;C; +1F6A 1F62;C; +1F6B 1F63;C; +1F6C 1F64;C; +1F6D 1F65;C; +1F6E 1F66;C; +1F6F 1F67;C; +1F88 1F80;S; +1F89 1F81;S; +1F8A 1F82;S; +1F8B 1F83;S; +1F8C 1F84;S; +1F8D 1F85;S; +1F8E 1F86;S; +1F8F 1F87;S; +1F98 1F90;S; +1F99 1F91;S; +1F9A 1F92;S; +1F9B 1F93;S; +1F9C 1F94;S; +1F9D 1F95;S; +1F9E 1F96;S; +1F9F 1F97;S; +1FA8 1FA0;S; +1FA9 1FA1;S; +1FAA 1FA2;S; +1FAB 1FA3;S; +1FAC 1FA4;S; +1FAD 1FA5;S; +1FAE 1FA6;S; +1FAF 1FA7;S; +1FB8 1FB0;C; +1FB9 1FB1;C; +1FBA 1F70;C; +1FBB 1F71;C; +1FBC 1FB3;S; +1FBE 03B9;C; +1FC8 1F72;C; +1FC9 1F73;C; +1FCA 1F74;C; +1FCB 1F75;C; +1FCC 1FC3;S; +1FD8 1FD0;C; +1FD9 1FD1;C; +1FDA 1F76;C; +1FDB 1F77;C; +1FE8 1FE0;C; +1FE9 1FE1;C; +1FEA 1F7A;C; +1FEB 1F7B;C; +1FEC 1FE5;C; +1FF8 1F78;C; +1FF9 1F79;C; +1FFA 1F7C;C; +1FFB 1F7D;C; +1FFC 1FF3;S; +2126 03C9;C; +212A 006B;C; +212B 00E5;C; +2160 2170;C; +2161 2171;C; +2162 2172;C; +2163 2173;C; +2164 2174;C; +2165 2175;C; +2166 2176;C; +2167 2177;C; +2168 2178;C; +2169 2179;C; +216A 217A;C; +216B 217B;C; +216C 217C;C; +216D 217D;C; +216E 217E;C; +216F 217F;C; +24B6 24D0;C; +24B7 24D1;C; +24B8 24D2;C; +24B9 24D3;C; +24BA 24D4;C; +24BB 24D5;C; +24BC 24D6;C; +24BD 24D7;C; +24BE 24D8;C; +24BF 24D9;C; +24C0 24DA;C; +24C1 24DB;C; +24C2 24DC;C; +24C3 24DD;C; +24C4 24DE;C; +24C5 24DF;C; +24C6 24E0;C; +24C7 24E1;C; +24C8 24E2;C; +24C9 24E3;C; +24CA 24E4;C; +24CB 24E5;C; +24CC 24E6;C; +24CD 24E7;C; +24CE 24E8;C; +24CF 24E9;C; +FF21 FF41;C; +FF22 FF42;C; +FF23 FF43;C; +FF24 FF44;C; +FF25 FF45;C; +FF26 FF46;C; +FF27 FF47;C; +FF28 FF48;C; +FF29 FF49;C; +FF2A FF4A;C; +FF2B FF4B;C; +FF2C FF4C;C; +FF2D FF4D;C; +FF2E FF4E;C; +FF2F FF4F;C; +FF30 FF50;C; +FF31 FF51;C; +FF32 FF52;C; +FF33 FF53;C; +FF34 FF54;C; +FF35 FF55;C; +FF36 FF56;C; +FF37 FF57;C; +FF38 FF58;C; +FF39 FF59;C; +FF3A FF5A;C; diff --git a/data/uni-full.txt b/data/uni-full.txt new file mode 100644 index 000000000..30e57ee35 --- /dev/null +++ b/data/uni-full.txt @@ -0,0 +1,788 @@ +# uni-full.txt - Unicode full case folding +0041 0061 0000 0000;C; +0042 0062 0000 0000;C; +0043 0063 0000 0000;C; +0044 0064 0000 0000;C; +0045 0065 0000 0000;C; +0046 0066 0000 0000;C; +0047 0067 0000 0000;C; +0048 0068 0000 0000;C; +0049 0069 0000 0000;C; +004A 006A 0000 0000;C; +004B 006B 0000 0000;C; +004C 006C 0000 0000;C; +004D 006D 0000 0000;C; +004E 006E 0000 0000;C; +004F 006F 0000 0000;C; +0050 0070 0000 0000;C; +0051 0071 0000 0000;C; +0052 0072 0000 0000;C; +0053 0073 0000 0000;C; +0054 0074 0000 0000;C; +0055 0075 0000 0000;C; +0056 0076 0000 0000;C; +0057 0077 0000 0000;C; +0058 0078 0000 0000;C; +0059 0079 0000 0000;C; +005A 007A 0000 0000;C; +00B5 03BC 0000 0000;C; +00C0 00E0 0000 0000;C; +00C1 00E1 0000 0000;C; +00C2 00E2 0000 0000;C; +00C3 00E3 0000 0000;C; +00C4 00E4 0000 0000;C; +00C5 00E5 0000 0000;C; +00C6 00E6 0000 0000;C; +00C7 00E7 0000 0000;C; +00C8 00E8 0000 0000;C; +00C9 00E9 0000 0000;C; +00CA 00EA 0000 0000;C; +00CB 00EB 0000 0000;C; +00CC 00EC 0000 0000;C; +00CD 00ED 0000 0000;C; +00CE 00EE 0000 0000;C; +00CF 00EF 0000 0000;C; +00D0 00F0 0000 0000;C; +00D1 00F1 0000 0000;C; +00D2 00F2 0000 0000;C; +00D3 00F3 0000 0000;C; +00D4 00F4 0000 0000;C; +00D5 00F5 0000 0000;C; +00D6 00F6 0000 0000;C; +00D8 00F8 0000 0000;C; +00D9 00F9 0000 0000;C; +00DA 00FA 0000 0000;C; +00DB 00FB 0000 0000;C; +00DC 00FC 0000 0000;C; +00DD 00FD 0000 0000;C; +00DE 00FE 0000 0000;C; +00DF 0073 0073 0000;F; +0100 0101 0000 0000;C; +0102 0103 0000 0000;C; +0104 0105 0000 0000;C; +0106 0107 0000 0000;C; +0108 0109 0000 0000;C; +010A 010B 0000 0000;C; +010C 010D 0000 0000;C; +010E 010F 0000 0000;C; +0110 0111 0000 0000;C; +0112 0113 0000 0000;C; +0114 0115 0000 0000;C; +0116 0117 0000 0000;C; +0118 0119 0000 0000;C; +011A 011B 0000 0000;C; +011C 011D 0000 0000;C; +011E 011F 0000 0000;C; +0120 0121 0000 0000;C; +0122 0123 0000 0000;C; +0124 0125 0000 0000;C; +0126 0127 0000 0000;C; +0128 0129 0000 0000;C; +012A 012B 0000 0000;C; +012C 012D 0000 0000;C; +012E 012F 0000 0000;C; +0130 0069 0000 0000;I; +0131 0069 0000 0000;I; +0132 0133 0000 0000;C; +0134 0135 0000 0000;C; +0136 0137 0000 0000;C; +0139 013A 0000 0000;C; +013B 013C 0000 0000;C; +013D 013E 0000 0000;C; +013F 0140 0000 0000;C; +0141 0142 0000 0000;C; +0143 0144 0000 0000;C; +0145 0146 0000 0000;C; +0147 0148 0000 0000;C; +0149 02BC 006E 0000;F; +014A 014B 0000 0000;C; +014C 014D 0000 0000;C; +014E 014F 0000 0000;C; +0150 0151 0000 0000;C; +0152 0153 0000 0000;C; +0154 0155 0000 0000;C; +0156 0157 0000 0000;C; +0158 0159 0000 0000;C; +015A 015B 0000 0000;C; +015C 015D 0000 0000;C; +015E 015F 0000 0000;C; +0160 0161 0000 0000;C; +0162 0163 0000 0000;C; +0164 0165 0000 0000;C; +0166 0167 0000 0000;C; +0168 0169 0000 0000;C; +016A 016B 0000 0000;C; +016C 016D 0000 0000;C; +016E 016F 0000 0000;C; +0170 0171 0000 0000;C; +0172 0173 0000 0000;C; +0174 0175 0000 0000;C; +0176 0177 0000 0000;C; +0178 00FF 0000 0000;C; +0179 017A 0000 0000;C; +017B 017C 0000 0000;C; +017D 017E 0000 0000;C; +017F 0073 0000 0000;C; +0181 0253 0000 0000;C; +0182 0183 0000 0000;C; +0184 0185 0000 0000;C; +0186 0254 0000 0000;C; +0187 0188 0000 0000;C; +0189 0256 0000 0000;C; +018A 0257 0000 0000;C; +018B 018C 0000 0000;C; +018E 01DD 0000 0000;C; +018F 0259 0000 0000;C; +0190 025B 0000 0000;C; +0191 0192 0000 0000;C; +0193 0260 0000 0000;C; +0194 0263 0000 0000;C; +0196 0269 0000 0000;C; +0197 0268 0000 0000;C; +0198 0199 0000 0000;C; +019C 026F 0000 0000;C; +019D 0272 0000 0000;C; +019F 0275 0000 0000;C; +01A0 01A1 0000 0000;C; +01A2 01A3 0000 0000;C; +01A4 01A5 0000 0000;C; +01A6 0280 0000 0000;C; +01A7 01A8 0000 0000;C; +01A9 0283 0000 0000;C; +01AC 01AD 0000 0000;C; +01AE 0288 0000 0000;C; +01AF 01B0 0000 0000;C; +01B1 028A 0000 0000;C; +01B2 028B 0000 0000;C; +01B3 01B4 0000 0000;C; +01B5 01B6 0000 0000;C; +01B7 0292 0000 0000;C; +01B8 01B9 0000 0000;C; +01BC 01BD 0000 0000;C; +01C4 01C6 0000 0000;C; +01C5 01C6 0000 0000;C; +01C7 01C9 0000 0000;C; +01C8 01C9 0000 0000;C; +01CA 01CC 0000 0000;C; +01CB 01CC 0000 0000;C; +01CD 01CE 0000 0000;C; +01CF 01D0 0000 0000;C; +01D1 01D2 0000 0000;C; +01D3 01D4 0000 0000;C; +01D5 01D6 0000 0000;C; +01D7 01D8 0000 0000;C; +01D9 01DA 0000 0000;C; +01DB 01DC 0000 0000;C; +01DE 01DF 0000 0000;C; +01E0 01E1 0000 0000;C; +01E2 01E3 0000 0000;C; +01E4 01E5 0000 0000;C; +01E6 01E7 0000 0000;C; +01E8 01E9 0000 0000;C; +01EA 01EB 0000 0000;C; +01EC 01ED 0000 0000;C; +01EE 01EF 0000 0000;C; +01F0 006A 030C 0000;F; +01F1 01F3 0000 0000;C; +01F2 01F3 0000 0000;C; +01F4 01F5 0000 0000;C; +01F6 0195 0000 0000;C; +01F7 01BF 0000 0000;C; +01F8 01F9 0000 0000;C; +01FA 01FB 0000 0000;C; +01FC 01FD 0000 0000;C; +01FE 01FF 0000 0000;C; +0200 0201 0000 0000;C; +0202 0203 0000 0000;C; +0204 0205 0000 0000;C; +0206 0207 0000 0000;C; +0208 0209 0000 0000;C; +020A 020B 0000 0000;C; +020C 020D 0000 0000;C; +020E 020F 0000 0000;C; +0210 0211 0000 0000;C; +0212 0213 0000 0000;C; +0214 0215 0000 0000;C; +0216 0217 0000 0000;C; +0218 0219 0000 0000;C; +021A 021B 0000 0000;C; +021C 021D 0000 0000;C; +021E 021F 0000 0000;C; +0222 0223 0000 0000;C; +0224 0225 0000 0000;C; +0226 0227 0000 0000;C; +0228 0229 0000 0000;C; +022A 022B 0000 0000;C; +022C 022D 0000 0000;C; +022E 022F 0000 0000;C; +0230 0231 0000 0000;C; +0232 0233 0000 0000;C; +0345 03B9 0000 0000;C; +0386 03AC 0000 0000;C; +0388 03AD 0000 0000;C; +0389 03AE 0000 0000;C; +038A 03AF 0000 0000;C; +038C 03CC 0000 0000;C; +038E 03CD 0000 0000;C; +038F 03CE 0000 0000;C; +0390 03B9 0308 0301;F; +0391 03B1 0000 0000;C; +0392 03B2 0000 0000;C; +0393 03B3 0000 0000;C; +0394 03B4 0000 0000;C; +0395 03B5 0000 0000;C; +0396 03B6 0000 0000;C; +0397 03B7 0000 0000;C; +0398 03B8 0000 0000;C; +0399 03B9 0000 0000;C; +039A 03BA 0000 0000;C; +039B 03BB 0000 0000;C; +039C 03BC 0000 0000;C; +039D 03BD 0000 0000;C; +039E 03BE 0000 0000;C; +039F 03BF 0000 0000;C; +03A0 03C0 0000 0000;C; +03A1 03C1 0000 0000;C; +03A3 03C3 0000 0000;C; +03A4 03C4 0000 0000;C; +03A5 03C5 0000 0000;C; +03A6 03C6 0000 0000;C; +03A7 03C7 0000 0000;C; +03A8 03C8 0000 0000;C; +03A9 03C9 0000 0000;C; +03AA 03CA 0000 0000;C; +03AB 03CB 0000 0000;C; +03B0 03C5 0308 0301;F; +03C2 03C3 0000 0000;C; +03D0 03B2 0000 0000;C; +03D1 03B8 0000 0000;C; +03D5 03C6 0000 0000;C; +03D6 03C0 0000 0000;C; +03DA 03DB 0000 0000;C; +03DC 03DD 0000 0000;C; +03DE 03DF 0000 0000;C; +03E0 03E1 0000 0000;C; +03E2 03E3 0000 0000;C; +03E4 03E5 0000 0000;C; +03E6 03E7 0000 0000;C; +03E8 03E9 0000 0000;C; +03EA 03EB 0000 0000;C; +03EC 03ED 0000 0000;C; +03EE 03EF 0000 0000;C; +03F0 03BA 0000 0000;C; +03F1 03C1 0000 0000;C; +03F2 03C3 0000 0000;C; +03F4 03B8 0000 0000;C; +03F5 03B5 0000 0000;C; +0400 0450 0000 0000;C; +0401 0451 0000 0000;C; +0402 0452 0000 0000;C; +0403 0453 0000 0000;C; +0404 0454 0000 0000;C; +0405 0455 0000 0000;C; +0406 0456 0000 0000;C; +0407 0457 0000 0000;C; +0408 0458 0000 0000;C; +0409 0459 0000 0000;C; +040A 045A 0000 0000;C; +040B 045B 0000 0000;C; +040C 045C 0000 0000;C; +040D 045D 0000 0000;C; +040E 045E 0000 0000;C; +040F 045F 0000 0000;C; +0410 0430 0000 0000;C; +0411 0431 0000 0000;C; +0412 0432 0000 0000;C; +0413 0433 0000 0000;C; +0414 0434 0000 0000;C; +0415 0435 0000 0000;C; +0416 0436 0000 0000;C; +0417 0437 0000 0000;C; +0418 0438 0000 0000;C; +0419 0439 0000 0000;C; +041A 043A 0000 0000;C; +041B 043B 0000 0000;C; +041C 043C 0000 0000;C; +041D 043D 0000 0000;C; +041E 043E 0000 0000;C; +041F 043F 0000 0000;C; +0420 0440 0000 0000;C; +0421 0441 0000 0000;C; +0422 0442 0000 0000;C; +0423 0443 0000 0000;C; +0424 0444 0000 0000;C; +0425 0445 0000 0000;C; +0426 0446 0000 0000;C; +0427 0447 0000 0000;C; +0428 0448 0000 0000;C; +0429 0449 0000 0000;C; +042A 044A 0000 0000;C; +042B 044B 0000 0000;C; +042C 044C 0000 0000;C; +042D 044D 0000 0000;C; +042E 044E 0000 0000;C; +042F 044F 0000 0000;C; +0460 0461 0000 0000;C; +0462 0463 0000 0000;C; +0464 0465 0000 0000;C; +0466 0467 0000 0000;C; +0468 0469 0000 0000;C; +046A 046B 0000 0000;C; +046C 046D 0000 0000;C; +046E 046F 0000 0000;C; +0470 0471 0000 0000;C; +0472 0473 0000 0000;C; +0474 0475 0000 0000;C; +0476 0477 0000 0000;C; +0478 0479 0000 0000;C; +047A 047B 0000 0000;C; +047C 047D 0000 0000;C; +047E 047F 0000 0000;C; +0480 0481 0000 0000;C; +048C 048D 0000 0000;C; +048E 048F 0000 0000;C; +0490 0491 0000 0000;C; +0492 0493 0000 0000;C; +0494 0495 0000 0000;C; +0496 0497 0000 0000;C; +0498 0499 0000 0000;C; +049A 049B 0000 0000;C; +049C 049D 0000 0000;C; +049E 049F 0000 0000;C; +04A0 04A1 0000 0000;C; +04A2 04A3 0000 0000;C; +04A4 04A5 0000 0000;C; +04A6 04A7 0000 0000;C; +04A8 04A9 0000 0000;C; +04AA 04AB 0000 0000;C; +04AC 04AD 0000 0000;C; +04AE 04AF 0000 0000;C; +04B0 04B1 0000 0000;C; +04B2 04B3 0000 0000;C; +04B4 04B5 0000 0000;C; +04B6 04B7 0000 0000;C; +04B8 04B9 0000 0000;C; +04BA 04BB 0000 0000;C; +04BC 04BD 0000 0000;C; +04BE 04BF 0000 0000;C; +04C1 04C2 0000 0000;C; +04C3 04C4 0000 0000;C; +04C7 04C8 0000 0000;C; +04CB 04CC 0000 0000;C; +04D0 04D1 0000 0000;C; +04D2 04D3 0000 0000;C; +04D4 04D5 0000 0000;C; +04D6 04D7 0000 0000;C; +04D8 04D9 0000 0000;C; +04DA 04DB 0000 0000;C; +04DC 04DD 0000 0000;C; +04DE 04DF 0000 0000;C; +04E0 04E1 0000 0000;C; +04E2 04E3 0000 0000;C; +04E4 04E5 0000 0000;C; +04E6 04E7 0000 0000;C; +04E8 04E9 0000 0000;C; +04EA 04EB 0000 0000;C; +04EC 04ED 0000 0000;C; +04EE 04EF 0000 0000;C; +04F0 04F1 0000 0000;C; +04F2 04F3 0000 0000;C; +04F4 04F5 0000 0000;C; +04F8 04F9 0000 0000;C; +0531 0561 0000 0000;C; +0532 0562 0000 0000;C; +0533 0563 0000 0000;C; +0534 0564 0000 0000;C; +0535 0565 0000 0000;C; +0536 0566 0000 0000;C; +0537 0567 0000 0000;C; +0538 0568 0000 0000;C; +0539 0569 0000 0000;C; +053A 056A 0000 0000;C; +053B 056B 0000 0000;C; +053C 056C 0000 0000;C; +053D 056D 0000 0000;C; +053E 056E 0000 0000;C; +053F 056F 0000 0000;C; +0540 0570 0000 0000;C; +0541 0571 0000 0000;C; +0542 0572 0000 0000;C; +0543 0573 0000 0000;C; +0544 0574 0000 0000;C; +0545 0575 0000 0000;C; +0546 0576 0000 0000;C; +0547 0577 0000 0000;C; +0548 0578 0000 0000;C; +0549 0579 0000 0000;C; +054A 057A 0000 0000;C; +054B 057B 0000 0000;C; +054C 057C 0000 0000;C; +054D 057D 0000 0000;C; +054E 057E 0000 0000;C; +054F 057F 0000 0000;C; +0550 0580 0000 0000;C; +0551 0581 0000 0000;C; +0552 0582 0000 0000;C; +0553 0583 0000 0000;C; +0554 0584 0000 0000;C; +0555 0585 0000 0000;C; +0556 0586 0000 0000;C; +0587 0565 0582 0000;F; +1E00 1E01 0000 0000;C; +1E02 1E03 0000 0000;C; +1E04 1E05 0000 0000;C; +1E06 1E07 0000 0000;C; +1E08 1E09 0000 0000;C; +1E0A 1E0B 0000 0000;C; +1E0C 1E0D 0000 0000;C; +1E0E 1E0F 0000 0000;C; +1E10 1E11 0000 0000;C; +1E12 1E13 0000 0000;C; +1E14 1E15 0000 0000;C; +1E16 1E17 0000 0000;C; +1E18 1E19 0000 0000;C; +1E1A 1E1B 0000 0000;C; +1E1C 1E1D 0000 0000;C; +1E1E 1E1F 0000 0000;C; +1E20 1E21 0000 0000;C; +1E22 1E23 0000 0000;C; +1E24 1E25 0000 0000;C; +1E26 1E27 0000 0000;C; +1E28 1E29 0000 0000;C; +1E2A 1E2B 0000 0000;C; +1E2C 1E2D 0000 0000;C; +1E2E 1E2F 0000 0000;C; +1E30 1E31 0000 0000;C; +1E32 1E33 0000 0000;C; +1E34 1E35 0000 0000;C; +1E36 1E37 0000 0000;C; +1E38 1E39 0000 0000;C; +1E3A 1E3B 0000 0000;C; +1E3C 1E3D 0000 0000;C; +1E3E 1E3F 0000 0000;C; +1E40 1E41 0000 0000;C; +1E42 1E43 0000 0000;C; +1E44 1E45 0000 0000;C; +1E46 1E47 0000 0000;C; +1E48 1E49 0000 0000;C; +1E4A 1E4B 0000 0000;C; +1E4C 1E4D 0000 0000;C; +1E4E 1E4F 0000 0000;C; +1E50 1E51 0000 0000;C; +1E52 1E53 0000 0000;C; +1E54 1E55 0000 0000;C; +1E56 1E57 0000 0000;C; +1E58 1E59 0000 0000;C; +1E5A 1E5B 0000 0000;C; +1E5C 1E5D 0000 0000;C; +1E5E 1E5F 0000 0000;C; +1E60 1E61 0000 0000;C; +1E62 1E63 0000 0000;C; +1E64 1E65 0000 0000;C; +1E66 1E67 0000 0000;C; +1E68 1E69 0000 0000;C; +1E6A 1E6B 0000 0000;C; +1E6C 1E6D 0000 0000;C; +1E6E 1E6F 0000 0000;C; +1E70 1E71 0000 0000;C; +1E72 1E73 0000 0000;C; +1E74 1E75 0000 0000;C; +1E76 1E77 0000 0000;C; +1E78 1E79 0000 0000;C; +1E7A 1E7B 0000 0000;C; +1E7C 1E7D 0000 0000;C; +1E7E 1E7F 0000 0000;C; +1E80 1E81 0000 0000;C; +1E82 1E83 0000 0000;C; +1E84 1E85 0000 0000;C; +1E86 1E87 0000 0000;C; +1E88 1E89 0000 0000;C; +1E8A 1E8B 0000 0000;C; +1E8C 1E8D 0000 0000;C; +1E8E 1E8F 0000 0000;C; +1E90 1E91 0000 0000;C; +1E92 1E93 0000 0000;C; +1E94 1E95 0000 0000;C; +1E96 0068 0331 0000;F; +1E97 0074 0308 0000;F; +1E98 0077 030A 0000;F; +1E99 0079 030A 0000;F; +1E9A 0061 02BE 0000;F; +1E9B 1E61 0000 0000;C; +1EA0 1EA1 0000 0000;C; +1EA2 1EA3 0000 0000;C; +1EA4 1EA5 0000 0000;C; +1EA6 1EA7 0000 0000;C; +1EA8 1EA9 0000 0000;C; +1EAA 1EAB 0000 0000;C; +1EAC 1EAD 0000 0000;C; +1EAE 1EAF 0000 0000;C; +1EB0 1EB1 0000 0000;C; +1EB2 1EB3 0000 0000;C; +1EB4 1EB5 0000 0000;C; +1EB6 1EB7 0000 0000;C; +1EB8 1EB9 0000 0000;C; +1EBA 1EBB 0000 0000;C; +1EBC 1EBD 0000 0000;C; +1EBE 1EBF 0000 0000;C; +1EC0 1EC1 0000 0000;C; +1EC2 1EC3 0000 0000;C; +1EC4 1EC5 0000 0000;C; +1EC6 1EC7 0000 0000;C; +1EC8 1EC9 0000 0000;C; +1ECA 1ECB 0000 0000;C; +1ECC 1ECD 0000 0000;C; +1ECE 1ECF 0000 0000;C; +1ED0 1ED1 0000 0000;C; +1ED2 1ED3 0000 0000;C; +1ED4 1ED5 0000 0000;C; +1ED6 1ED7 0000 0000;C; +1ED8 1ED9 0000 0000;C; +1EDA 1EDB 0000 0000;C; +1EDC 1EDD 0000 0000;C; +1EDE 1EDF 0000 0000;C; +1EE0 1EE1 0000 0000;C; +1EE2 1EE3 0000 0000;C; +1EE4 1EE5 0000 0000;C; +1EE6 1EE7 0000 0000;C; +1EE8 1EE9 0000 0000;C; +1EEA 1EEB 0000 0000;C; +1EEC 1EED 0000 0000;C; +1EEE 1EEF 0000 0000;C; +1EF0 1EF1 0000 0000;C; +1EF2 1EF3 0000 0000;C; +1EF4 1EF5 0000 0000;C; +1EF6 1EF7 0000 0000;C; +1EF8 1EF9 0000 0000;C; +1F08 1F00 0000 0000;C; +1F09 1F01 0000 0000;C; +1F0A 1F02 0000 0000;C; +1F0B 1F03 0000 0000;C; +1F0C 1F04 0000 0000;C; +1F0D 1F05 0000 0000;C; +1F0E 1F06 0000 0000;C; +1F0F 1F07 0000 0000;C; +1F18 1F10 0000 0000;C; +1F19 1F11 0000 0000;C; +1F1A 1F12 0000 0000;C; +1F1B 1F13 0000 0000;C; +1F1C 1F14 0000 0000;C; +1F1D 1F15 0000 0000;C; +1F28 1F20 0000 0000;C; +1F29 1F21 0000 0000;C; +1F2A 1F22 0000 0000;C; +1F2B 1F23 0000 0000;C; +1F2C 1F24 0000 0000;C; +1F2D 1F25 0000 0000;C; +1F2E 1F26 0000 0000;C; +1F2F 1F27 0000 0000;C; +1F38 1F30 0000 0000;C; +1F39 1F31 0000 0000;C; +1F3A 1F32 0000 0000;C; +1F3B 1F33 0000 0000;C; +1F3C 1F34 0000 0000;C; +1F3D 1F35 0000 0000;C; +1F3E 1F36 0000 0000;C; +1F3F 1F37 0000 0000;C; +1F48 1F40 0000 0000;C; +1F49 1F41 0000 0000;C; +1F4A 1F42 0000 0000;C; +1F4B 1F43 0000 0000;C; +1F4C 1F44 0000 0000;C; +1F4D 1F45 0000 0000;C; +1F50 03C5 0313 0000;F; +1F52 03C5 0313 0300;F; +1F54 03C5 0313 0301;F; +1F56 03C5 0313 0342;F; +1F59 1F51 0000 0000;C; +1F5B 1F53 0000 0000;C; +1F5D 1F55 0000 0000;C; +1F5F 1F57 0000 0000;C; +1F68 1F60 0000 0000;C; +1F69 1F61 0000 0000;C; +1F6A 1F62 0000 0000;C; +1F6B 1F63 0000 0000;C; +1F6C 1F64 0000 0000;C; +1F6D 1F65 0000 0000;C; +1F6E 1F66 0000 0000;C; +1F6F 1F67 0000 0000;C; +1F80 1F00 03B9 0000;F; +1F81 1F01 03B9 0000;F; +1F82 1F02 03B9 0000;F; +1F83 1F03 03B9 0000;F; +1F84 1F04 03B9 0000;F; +1F85 1F05 03B9 0000;F; +1F86 1F06 03B9 0000;F; +1F87 1F07 03B9 0000;F; +1F88 1F00 03B9 0000;F; +1F89 1F01 03B9 0000;F; +1F8A 1F02 03B9 0000;F; +1F8B 1F03 03B9 0000;F; +1F8C 1F04 03B9 0000;F; +1F8D 1F05 03B9 0000;F; +1F8E 1F06 03B9 0000;F; +1F8F 1F07 03B9 0000;F; +1F90 1F20 03B9 0000;F; +1F91 1F21 03B9 0000;F; +1F92 1F22 03B9 0000;F; +1F93 1F23 03B9 0000;F; +1F94 1F24 03B9 0000;F; +1F95 1F25 03B9 0000;F; +1F96 1F26 03B9 0000;F; +1F97 1F27 03B9 0000;F; +1F98 1F20 03B9 0000;F; +1F99 1F21 03B9 0000;F; +1F9A 1F22 03B9 0000;F; +1F9B 1F23 03B9 0000;F; +1F9C 1F24 03B9 0000;F; +1F9D 1F25 03B9 0000;F; +1F9E 1F26 03B9 0000;F; +1F9F 1F27 03B9 0000;F; +1FA0 1F60 03B9 0000;F; +1FA1 1F61 03B9 0000;F; +1FA2 1F62 03B9 0000;F; +1FA3 1F63 03B9 0000;F; +1FA4 1F64 03B9 0000;F; +1FA5 1F65 03B9 0000;F; +1FA6 1F66 03B9 0000;F; +1FA7 1F67 03B9 0000;F; +1FA8 1F60 03B9 0000;F; +1FA9 1F61 03B9 0000;F; +1FAA 1F62 03B9 0000;F; +1FAB 1F63 03B9 0000;F; +1FAC 1F64 03B9 0000;F; +1FAD 1F65 03B9 0000;F; +1FAE 1F66 03B9 0000;F; +1FAF 1F67 03B9 0000;F; +1FB2 1F70 03B9 0000;F; +1FB3 03B1 03B9 0000;F; +1FB4 03AC 03B9 0000;F; +1FB6 03B1 0342 0000;F; +1FB7 03B1 0342 03B9;F; +1FB8 1FB0 0000 0000;C; +1FB9 1FB1 0000 0000;C; +1FBA 1F70 0000 0000;C; +1FBB 1F71 0000 0000;C; +1FBC 03B1 03B9 0000;F; +1FBE 03B9 0000 0000;C; +1FC2 1F74 03B9 0000;F; +1FC3 03B7 03B9 0000;F; +1FC4 03AE 03B9 0000;F; +1FC6 03B7 0342 0000;F; +1FC7 03B7 0342 03B9;F; +1FC8 1F72 0000 0000;C; +1FC9 1F73 0000 0000;C; +1FCA 1F74 0000 0000;C; +1FCB 1F75 0000 0000;C; +1FCC 03B7 03B9 0000;F; +1FD2 03B9 0308 0300;F; +1FD3 03B9 0308 0301;F; +1FD6 03B9 0342 0000;F; +1FD7 03B9 0308 0342;F; +1FD8 1FD0 0000 0000;C; +1FD9 1FD1 0000 0000;C; +1FDA 1F76 0000 0000;C; +1FDB 1F77 0000 0000;C; +1FE2 03C5 0308 0300;F; +1FE3 03C5 0308 0301;F; +1FE4 03C1 0313 0000;F; +1FE6 03C5 0342 0000;F; +1FE7 03C5 0308 0342;F; +1FE8 1FE0 0000 0000;C; +1FE9 1FE1 0000 0000;C; +1FEA 1F7A 0000 0000;C; +1FEB 1F7B 0000 0000;C; +1FEC 1FE5 0000 0000;C; +1FF2 1F7C 03B9 0000;F; +1FF3 03C9 03B9 0000;F; +1FF4 03CE 03B9 0000;F; +1FF6 03C9 0342 0000;F; +1FF7 03C9 0342 03B9;F; +1FF8 1F78 0000 0000;C; +1FF9 1F79 0000 0000;C; +1FFA 1F7C 0000 0000;C; +1FFB 1F7D 0000 0000;C; +1FFC 03C9 03B9 0000;F; +2126 03C9 0000 0000;C; +212A 006B 0000 0000;C; +212B 00E5 0000 0000;C; +2160 2170 0000 0000;C; +2161 2171 0000 0000;C; +2162 2172 0000 0000;C; +2163 2173 0000 0000;C; +2164 2174 0000 0000;C; +2165 2175 0000 0000;C; +2166 2176 0000 0000;C; +2167 2177 0000 0000;C; +2168 2178 0000 0000;C; +2169 2179 0000 0000;C; +216A 217A 0000 0000;C; +216B 217B 0000 0000;C; +216C 217C 0000 0000;C; +216D 217D 0000 0000;C; +216E 217E 0000 0000;C; +216F 217F 0000 0000;C; +24B6 24D0 0000 0000;C; +24B7 24D1 0000 0000;C; +24B8 24D2 0000 0000;C; +24B9 24D3 0000 0000;C; +24BA 24D4 0000 0000;C; +24BB 24D5 0000 0000;C; +24BC 24D6 0000 0000;C; +24BD 24D7 0000 0000;C; +24BE 24D8 0000 0000;C; +24BF 24D9 0000 0000;C; +24C0 24DA 0000 0000;C; +24C1 24DB 0000 0000;C; +24C2 24DC 0000 0000;C; +24C3 24DD 0000 0000;C; +24C4 24DE 0000 0000;C; +24C5 24DF 0000 0000;C; +24C6 24E0 0000 0000;C; +24C7 24E1 0000 0000;C; +24C8 24E2 0000 0000;C; +24C9 24E3 0000 0000;C; +24CA 24E4 0000 0000;C; +24CB 24E5 0000 0000;C; +24CC 24E6 0000 0000;C; +24CD 24E7 0000 0000;C; +24CE 24E8 0000 0000;C; +24CF 24E9 0000 0000;C; +FB00 0066 0066 0000;F; +FB01 0066 0069 0000;F; +FB02 0066 006C 0000;F; +FB03 0066 0066 0069;F; +FB04 0066 0066 006C;F; +FB05 0073 0074 0000;F; +FB06 0073 0074 0000;F; +FB13 0574 0576 0000;F; +FB14 0574 0565 0000;F; +FB15 0574 056B 0000;F; +FB16 057E 0576 0000;F; +FB17 0574 056D 0000;F; +FF21 FF41 0000 0000;C; +FF22 FF42 0000 0000;C; +FF23 FF43 0000 0000;C; +FF24 FF44 0000 0000;C; +FF25 FF45 0000 0000;C; +FF26 FF46 0000 0000;C; +FF27 FF47 0000 0000;C; +FF28 FF48 0000 0000;C; +FF29 FF49 0000 0000;C; +FF2A FF4A 0000 0000;C; +FF2B FF4B 0000 0000;C; +FF2C FF4C 0000 0000;C; +FF2D FF4D 0000 0000;C; +FF2E FF4E 0000 0000;C; +FF2F FF4F 0000 0000;C; +FF30 FF50 0000 0000;C; +FF31 FF51 0000 0000;C; +FF32 FF52 0000 0000;C; +FF33 FF53 0000 0000;C; +FF34 FF54 0000 0000;C; +FF35 FF55 0000 0000;C; +FF36 FF56 0000 0000;C; +FF37 FF57 0000 0000;C; +FF38 FF58 0000 0000;C; +FF39 FF59 0000 0000;C; +FF3A FF5A 0000 0000;C; diff --git a/data/uni-line.txt b/data/uni-line.txt new file mode 100644 index 000000000..47230ccbb --- /dev/null +++ b/data/uni-line.txt @@ -0,0 +1,1126 @@ +# uni-line.txt - Unicode line break class +0000 0008;CM +0009 0009;BA +000A 000A;LF +000B 000B;CM +000C 000C;BK +000D 000D;CR +000E 001F;CM +0020 0020;SP +0021 0021;EX +0022 0022;QU +0023 0023;AL +0024 0024;PR +0025 0025;PO +0026 0026;AL +0027 0027;QU +0028 0028;OP +0029 0029;CL +002A 002A;AL +002B 002B;PR +002C 002C;IS +002D 002D;HY +002E 002E;IS +002F 002F;SY +0030 0039;NU +003A 003B;IS +003C 003E;AL +003F 003F;EX +0040 0040;AL +0041 005A;AL +005B 005B;OP +005C 005C;PR +005D 005D;CL +005E 005E;AL +005F 005F;AL +0060 0060;AL +0061 007A;AL +007B 007B;OP +007C 007C;BA +007D 007D;CL +007E 007E;AL +007F 009F;CM +00A0 00A0;GL +00A1 00A1;AI +00A2 00A2;PO +00A3 00A5;PR +00A6 00A6;AL +00A7 00A7;AI +00A8 00A8;AI +00A9 00A9;AL +00AA 00AA;AI +00AB 00AB;QU +00AC 00AC;AL +00AD 00AD;BA +00AE 00AE;AL +00AF 00AF;AL +00B0 00B0;PO +00B1 00B1;PR +00B2 00B3;AI +00B4 00B4;BB +00B5 00B5;AL +00B6 00B6;AI +00B7 00B7;AI +00B8 00B8;AI +00B9 00B9;AI +00BA 00BA;AI +00BB 00BB;QU +00BC 00BE;AI +00BF 00BF;AI +00C0 00C5;AL +00C6 00C6;AI +00C7 00CF;AL +00D0 00D0;AI +00D1 00D6;AL +00D7 00D7;AI +00D8 00D8;AI +00D9 00DD;AL +00DE 00E1;AI +00E2 00E5;AL +00E6 00E6;AI +00E7 00E7;AL +00E8 00EA;AI +00EB 00EB;AL +00EC 00ED;AI +00EE 00EF;AL +00F0 00F0;AI +00F1 00F1;AL +00F2 00F3;AI +00F4 00F6;AL +00F7 00F7;AI +00F8 00FA;AI +00FB 00FB;AL +00FC 00FC;AI +00FD 00FD;AL +00FE 00FE;AI +00FF 0100;AL +0101 0101;AI +0102 0110;AL +0111 0111;AI +0112 0112;AL +0113 0113;AI +0114 011A;AL +011B 011B;AI +011C 0125;AL +0126 0127;AI +0128 012A;AL +012B 012B;AI +012C 0130;AL +0131 0133;AI +0134 0137;AL +0138 0138;AI +0139 013E;AL +013F 0142;AI +0143 0143;AL +0144 0144;AI +0145 0147;AL +0148 014A;AI +014B 014C;AL +014D 014D;AI +014E 0151;AL +0152 0153;AI +0154 0165;AL +0166 0167;AI +0168 016A;AL +016B 016B;AI +016C 01BA;AL +01BB 01BB;AL +01BC 01BF;AL +01C0 01C3;AL +01C4 01CD;AL +01CE 01CE;AI +01CF 01CF;AL +01D0 01D0;AI +01D1 01D1;AL +01D2 01D2;AI +01D3 01D3;AL +01D4 01D4;AI +01D5 01D5;AL +01D6 01D6;AI +01D7 01D7;AL +01D8 01D8;AI +01D9 01D9;AL +01DA 01DA;AI +01DB 01DB;AL +01DC 01DC;AI +01DD 021F;AL +0222 0233;AL +0250 0250;AL +0251 0251;AI +0252 0260;AL +0261 0261;AI +0262 02AD;AL +02B0 02B8;AL +02B9 02BA;AL +02BB 02C1;AL +02C2 02C6;AL +02C7 02C7;AI +02C8 02C8;BB +02C9 02CB;AI +02CC 02CC;BB +02CD 02CD;AI +02CE 02CF;AL +02D0 02D0;AI +02D1 02D1;AL +02D2 02D7;AL +02D8 02DB;AI +02DC 02DC;AL +02DD 02DD;AI +02DE 02DF;AL +02E0 02E4;AL +02E5 02ED;AL +02EE 02EE;AL +0300 034E;CM +0360 0362;CM +0374 0375;AL +037A 037A;AL +037E 037E;AL +0384 0385;AL +0386 0386;AL +0387 0387;AL +0388 038A;AL +038C 038C;AL +038E 0390;AL +0391 03A1;AI +03A3 03A9;AI +03AA 03B0;AL +03B1 03C1;AI +03C2 03C2;AL +03C3 03C9;AI +03CA 03CE;AL +03D0 03D7;AL +03DA 03F5;AL +0400 0400;AL +0401 0401;AI +0402 040F;AL +0410 044F;AI +0450 0450;AL +0451 0451;AI +0452 0481;AL +0482 0482;AL +0483 0486;CM +0488 0489;CM +048C 04C4;AL +04C7 04C8;AL +04CB 04CC;AL +04D0 04F5;AL +04F8 04F9;AL +0531 0556;AL +0559 0559;AL +055A 055F;AL +0561 0587;AL +0589 0589;IS +058A 058A;BA +0591 05A1;CM +05A3 05B9;CM +05BB 05BD;CM +05BE 05BE;AL +05BF 05BF;CM +05C0 05C0;AL +05C1 05C2;CM +05C3 05C3;AL +05C4 05C4;CM +05D0 05EA;AL +05F0 05F2;AL +05F3 05F4;AL +060C 060C;AL +061B 061B;AL +061F 061F;AL +0621 063A;AL +0640 0640;AL +0641 064A;AL +064B 0655;CM +0660 0669;NU +066A 066D;AL +0670 0670;CM +0671 06D3;AL +06D4 06D4;AL +06D5 06D5;AL +06D6 06DC;CM +06DD 06DE;CM +06DF 06E4;CM +06E5 06E6;AL +06E7 06E8;CM +06E9 06E9;AL +06EA 06ED;CM +06F0 06F9;NU +06FA 06FC;AL +06FD 06FE;AL +0700 070D;AL +070F 070F;CM +0710 0710;AL +0711 0711;CM +0712 072C;AL +0730 074A;CM +0780 07A5;AL +07A6 07B0;CM +0901 0902;CM +0903 0903;CM +0905 0939;AL +093C 093C;CM +093D 093D;AL +093E 0940;CM +0941 0948;CM +0949 094C;CM +094D 094D;CM +0950 0950;AL +0951 0954;CM +0958 0961;AL +0962 0963;CM +0964 0965;AL +0966 096F;NU +0970 0970;AL +0981 0981;CM +0982 0983;CM +0985 098C;AL +098F 0990;AL +0993 09A8;AL +09AA 09B0;AL +09B2 09B2;AL +09B6 09B9;AL +09BC 09BC;CM +09BE 09C0;CM +09C1 09C4;CM +09C7 09C8;CM +09CB 09CC;CM +09CD 09CD;CM +09D7 09D7;CM +09DC 09DD;AL +09DF 09E1;AL +09E2 09E3;CM +09E6 09EF;NU +09F0 09F1;AL +09F2 09F3;PR +09F4 09F9;AL +09FA 09FA;AL +0A02 0A02;CM +0A05 0A0A;AL +0A0F 0A10;AL +0A13 0A28;AL +0A2A 0A30;AL +0A32 0A33;AL +0A35 0A36;AL +0A38 0A39;AL +0A3C 0A3C;CM +0A3E 0A40;CM +0A41 0A42;CM +0A47 0A48;CM +0A4B 0A4D;CM +0A59 0A5C;AL +0A5E 0A5E;AL +0A66 0A6F;NU +0A70 0A71;CM +0A72 0A74;AL +0A81 0A82;CM +0A83 0A83;CM +0A85 0A8B;AL +0A8D 0A8D;AL +0A8F 0A91;AL +0A93 0AA8;AL +0AAA 0AB0;AL +0AB2 0AB3;AL +0AB5 0AB9;AL +0ABC 0ABC;CM +0ABD 0ABD;AL +0ABE 0AC0;CM +0AC1 0AC5;CM +0AC7 0AC8;CM +0AC9 0AC9;CM +0ACB 0ACC;CM +0ACD 0ACD;CM +0AD0 0AD0;AL +0AE0 0AE0;AL +0AE6 0AEF;NU +0B01 0B01;CM +0B02 0B03;CM +0B05 0B0C;AL +0B0F 0B10;AL +0B13 0B28;AL +0B2A 0B30;AL +0B32 0B33;AL +0B36 0B39;AL +0B3C 0B3C;CM +0B3D 0B3D;AL +0B3E 0B3E;CM +0B3F 0B3F;CM +0B40 0B40;CM +0B41 0B43;CM +0B47 0B48;CM +0B4B 0B4C;CM +0B4D 0B4D;CM +0B56 0B56;CM +0B57 0B57;CM +0B5C 0B5D;AL +0B5F 0B61;AL +0B66 0B6F;NU +0B70 0B70;AL +0B82 0B82;CM +0B83 0B83;CM +0B85 0B8A;AL +0B8E 0B90;AL +0B92 0B95;AL +0B99 0B9A;AL +0B9C 0B9C;AL +0B9E 0B9F;AL +0BA3 0BA4;AL +0BA8 0BAA;AL +0BAE 0BB5;AL +0BB7 0BB9;AL +0BBE 0BBF;CM +0BC0 0BC0;CM +0BC1 0BC2;CM +0BC6 0BC8;CM +0BCA 0BCC;CM +0BCD 0BCD;CM +0BD7 0BD7;CM +0BE7 0BEF;NU +0BF0 0BF2;AL +0C01 0C03;CM +0C05 0C0C;AL +0C0E 0C10;AL +0C12 0C28;AL +0C2A 0C33;AL +0C35 0C39;AL +0C3E 0C40;CM +0C41 0C44;CM +0C46 0C48;CM +0C4A 0C4D;CM +0C55 0C56;CM +0C60 0C61;AL +0C66 0C6F;NU +0C82 0C83;CM +0C85 0C8C;AL +0C8E 0C90;AL +0C92 0CA8;AL +0CAA 0CB3;AL +0CB5 0CB9;AL +0CBE 0CBE;CM +0CBF 0CBF;CM +0CC0 0CC4;CM +0CC6 0CC6;CM +0CC7 0CC8;CM +0CCA 0CCB;CM +0CCC 0CCD;CM +0CD5 0CD6;CM +0CDE 0CDE;AL +0CE0 0CE1;AL +0CE6 0CEF;NU +0D02 0D03;CM +0D05 0D0C;AL +0D0E 0D10;AL +0D12 0D28;AL +0D2A 0D39;AL +0D3E 0D40;CM +0D41 0D43;CM +0D46 0D48;CM +0D4A 0D4C;CM +0D4D 0D4D;CM +0D57 0D57;CM +0D60 0D61;AL +0D66 0D6F;NU +0D82 0D83;CM +0D85 0D96;AL +0D9A 0DB1;AL +0DB3 0DBB;AL +0DBD 0DBD;AL +0DC0 0DC6;AL +0DCA 0DCA;CM +0DCF 0DD1;CM +0DD2 0DD4;CM +0DD6 0DD6;CM +0DD8 0DDF;CM +0DF2 0DF3;CM +0DF4 0DF4;AL +0E01 0E30;SA +0E31 0E31;CM +0E32 0E33;SA +0E34 0E3A;CM +0E3F 0E3F;PR +0E40 0E45;SA +0E46 0E46;SA +0E47 0E4E;CM +0E4F 0E4F;AL +0E50 0E59;NU +0E5A 0E5B;NS +0E81 0E82;SA +0E84 0E84;SA +0E87 0E88;SA +0E8A 0E8A;SA +0E8D 0E8D;SA +0E94 0E97;SA +0E99 0E9F;SA +0EA1 0EA3;SA +0EA5 0EA5;SA +0EA7 0EA7;SA +0EAA 0EAB;SA +0EAD 0EB0;SA +0EB1 0EB1;CM +0EB2 0EB3;SA +0EB4 0EB9;CM +0EBB 0EBC;CM +0EBD 0EBD;SA +0EC0 0EC4;SA +0EC6 0EC6;SA +0EC8 0ECD;CM +0ED0 0ED9;NU +0EDC 0EDD;SA +0F00 0F00;AL +0F01 0F03;AL +0F04 0F0A;AL +0F0B 0F0B;BA +0F0C 0F0C;GL +0F0D 0F12;AL +0F13 0F17;AL +0F18 0F19;CM +0F1A 0F1F;AL +0F20 0F29;NU +0F2A 0F33;AL +0F34 0F34;AL +0F35 0F35;CM +0F36 0F36;AL +0F37 0F37;CM +0F38 0F38;AL +0F39 0F39;CM +0F3A 0F3A;OP +0F3B 0F3B;CL +0F3C 0F3C;OP +0F3D 0F3D;CL +0F3E 0F3F;CM +0F40 0F47;AL +0F49 0F6A;AL +0F71 0F7E;CM +0F7F 0F7F;CM +0F80 0F84;CM +0F85 0F85;AL +0F86 0F87;CM +0F88 0F8B;AL +0F90 0F97;CM +0F99 0FBC;CM +0FBE 0FC5;AL +0FC6 0FC6;CM +0FC7 0FCC;AL +0FCF 0FCF;AL +1000 1021;SA +1023 1027;SA +1029 102A;SA +102C 102C;CM +102D 1030;CM +1031 1031;CM +1032 1032;CM +1036 1037;CM +1038 1038;CM +1039 1039;CM +1040 1049;NU +104A 104F;AL +1050 1055;SA +1056 1057;CM +1058 1059;CM +10A0 10C5;AL +10D0 10F6;AL +10FB 10FB;AL +1100 1159;ID +115F 115F;ID +1160 11A2;CM +11A8 11F9;CM +1200 1206;AL +1208 1246;AL +1248 1248;AL +124A 124D;AL +1250 1256;AL +1258 1258;AL +125A 125D;AL +1260 1286;AL +1288 1288;AL +128A 128D;AL +1290 12AE;AL +12B0 12B0;AL +12B2 12B5;AL +12B8 12BE;AL +12C0 12C0;AL +12C2 12C5;AL +12C8 12CE;AL +12D0 12D6;AL +12D8 12EE;AL +12F0 130E;AL +1310 1310;AL +1312 1315;AL +1318 131E;AL +1320 1346;AL +1348 135A;AL +1361 1361;BA +1362 1368;AL +1369 1371;NU +1372 137C;AL +13A0 13F4;AL +1401 166C;AL +166D 166E;AL +166F 1676;AL +1680 1680;BA +1681 169A;AL +169B 169B;OP +169C 169C;CL +16A0 16EA;AL +16EB 16ED;AL +16EE 16F0;AL +1780 17B3;SA +17B4 17B6;CM +17B7 17BD;CM +17BE 17C5;CM +17C6 17C6;CM +17C7 17C8;CM +17C9 17D3;CM +17D4 17D4;NS +17D5 17D5;BA +17D6 17DA;NS +17DB 17DB;PR +17DC 17DC;AL +17E0 17E9;NU +1800 1805;AL +1806 1806;BB +1807 180A;AL +180B 180E;CM +1810 1819;NU +1820 1842;AL +1843 1843;AL +1844 1877;AL +1880 18A8;AL +18A9 18A9;CM +1E00 1E9B;AL +1EA0 1EF9;AL +1F00 1F15;AL +1F18 1F1D;AL +1F20 1F45;AL +1F48 1F4D;AL +1F50 1F57;AL +1F59 1F59;AL +1F5B 1F5B;AL +1F5D 1F5D;AL +1F5F 1F7D;AL +1F80 1FB4;AL +1FB6 1FBC;AL +1FBD 1FBD;AL +1FBE 1FBE;AL +1FBF 1FC1;AL +1FC2 1FC4;AL +1FC6 1FCC;AL +1FCD 1FCF;AL +1FD0 1FD3;AL +1FD6 1FDB;AL +1FDD 1FDF;AL +1FE0 1FEC;AL +1FED 1FEF;AL +1FF2 1FF4;AL +1FF6 1FFC;AL +1FFD 1FFE;AL +2000 2006;BA +2007 2007;GL +2008 200A;BA +200B 200B;ZW +200C 200F;CM +2010 2010;BA +2011 2011;GL +2012 2013;BA +2014 2014;B2 +2015 2015;AI +2016 2016;AI +2017 2017;AL +2018 2018;QU +2019 2019;QU +201A 201A;OP +201B 201C;QU +201D 201D;QU +201E 201E;OP +201F 201F;QU +2020 2021;AI +2022 2023;AL +2024 2026;IN +2027 2027;BA +2028 2028;BK +2029 2029;BK +202A 202E;CM +202F 202F;GL +2030 2037;PO +2038 2038;AL +2039 2039;QU +203A 203A;QU +203B 203B;AI +203C 203C;NS +203D 203E;AL +203F 2040;AL +2041 2043;AL +2044 2044;NS +2045 2045;OP +2046 2046;CL +2048 204D;AL +206A 206F;CM +2070 2070;AL +2074 2074;AI +2075 2079;AL +207A 207C;AL +207D 207D;OP +207E 207E;CL +207F 207F;AI +2080 2080;AL +2081 2084;AI +2085 2089;AL +208A 208C;AL +208D 208D;OP +208E 208E;CL +20A0 20A6;PR +20A7 20A7;PO +20A8 20AF;PR +20D0 20DC;CM +20DD 20E0;CM +20E1 20E1;CM +20E2 20E3;CM +2100 2101;AL +2102 2102;AL +2103 2103;PO +2104 2104;AL +2105 2105;AI +2106 2106;AL +2107 2107;AL +2108 2108;AL +2109 2109;PO +210A 2112;AL +2113 2113;AI +2114 2114;AL +2115 2115;AL +2116 2116;PR +2117 2118;AL +2119 211D;AL +211E 2120;AL +2121 2122;AI +2123 2123;AL +2124 2124;AL +2125 2125;AL +2126 2126;PO +2127 2127;AL +2128 2128;AL +2129 2129;AL +212A 212A;AL +212B 212B;AI +212C 212D;AL +212E 212E;AL +212F 2131;AL +2132 2132;AL +2133 2134;AL +2135 2138;AL +2139 2139;AL +213A 213A;AL +2153 2153;AL +2154 2155;AI +2156 215A;AL +215B 215B;AI +215C 215D;AL +215E 215E;AI +215F 215F;AL +2160 216B;AI +216C 216F;AL +2170 2179;AI +217A 2183;AL +2190 2194;AI +2195 2199;AI +219A 219B;AL +219C 219F;AL +21A0 21A0;AL +21A1 21A2;AL +21A3 21A3;AL +21A4 21A5;AL +21A6 21A6;AL +21A7 21AD;AL +21AE 21AE;AL +21AF 21CD;AL +21CE 21CF;AL +21D0 21D1;AL +21D2 21D2;AI +21D3 21D3;AL +21D4 21D4;AI +21D5 21F3;AL +2200 2200;AI +2201 2201;AL +2202 2203;AI +2204 2206;AL +2207 2208;AI +2209 220A;AL +220B 220B;AI +220C 220E;AL +220F 220F;AI +2210 2210;AL +2211 2211;AI +2212 2213;PR +2214 2214;AL +2215 2215;AI +2216 2219;AL +221A 221A;AI +221B 221C;AL +221D 2220;AI +2221 2222;AL +2223 2223;AI +2224 2224;AL +2225 2225;AI +2226 2226;AL +2227 222C;AI +222D 222D;AL +222E 222E;AI +222F 2233;AL +2234 2237;AI +2238 223B;AL +223C 223D;AI +223E 2247;AL +2248 2248;AI +2249 224B;AL +224C 224C;AI +224D 2251;AL +2252 2252;AI +2253 225F;AL +2260 2261;AI +2262 2263;AL +2264 2267;AI +2268 2269;AL +226A 226B;AI +226C 226D;AL +226E 226F;AI +2270 2281;AL +2282 2283;AI +2284 2285;AL +2286 2287;AI +2288 2294;AL +2295 2295;AI +2296 2298;AL +2299 2299;AI +229A 22A4;AL +22A5 22A5;AI +22A6 22BE;AL +22BF 22BF;AI +22C0 22F1;AL +2300 2307;AL +2308 230B;AL +230C 2311;AL +2312 2312;AI +2313 231F;AL +2320 2321;AL +2322 2328;AL +2329 2329;OP +232A 232A;CL +232B 237B;AL +237D 239A;AL +2400 2426;AL +2440 244A;AL +2460 249B;AI +249C 24BF;AI +24C0 24CF;AL +24D0 24E9;AI +24EA 24EA;AL +2500 254B;AI +254C 254F;AL +2550 2574;AI +2575 257F;AL +2580 258F;AI +2590 2591;AL +2592 2595;AI +25A0 25A1;AI +25A2 25A2;AL +25A3 25A9;AI +25AA 25B1;AL +25B2 25B3;AI +25B4 25B5;AL +25B6 25B6;AI +25B7 25B7;AI +25B8 25BB;AL +25BC 25BD;AI +25BE 25BF;AL +25C0 25C0;AI +25C1 25C1;AI +25C2 25C5;AL +25C6 25C8;AI +25C9 25CA;AL +25CB 25CB;AI +25CC 25CD;AL +25CE 25D1;AI +25D2 25E1;AL +25E2 25E5;AI +25E6 25EE;AL +25EF 25EF;AI +25F0 25F7;AL +2600 2604;AL +2605 2606;AI +2607 2608;AL +2609 2609;AI +260A 260D;AL +260E 260F;AI +2610 2613;AL +2619 261B;AL +261C 261C;AI +261D 261D;AL +261E 261E;AI +261F 263F;AL +2640 2640;AI +2641 2641;AL +2642 2642;AI +2643 265F;AL +2660 2661;AI +2662 2662;AL +2663 2665;AI +2666 2666;AL +2667 266A;AI +266B 266B;AL +266C 266D;AI +266E 266E;AL +266F 266F;AI +2670 2671;AL +2701 2704;AL +2706 2709;AL +270C 2727;AL +2729 274B;AL +274D 274D;AL +274F 2752;AL +2756 2756;AL +2758 275E;AL +2761 2767;AL +2776 2793;AL +2794 2794;AL +2798 27AF;AL +27B1 27BE;AL +2800 28FF;AL +2E80 2E99;ID +2E9B 2EF3;ID +2F00 2FD5;ID +2FF0 2FFB;ID +3000 3000;ID +3001 3002;CL +3003 3003;ID +3004 3004;ID +3005 3005;NS +3006 3006;ID +3007 3007;ID +3008 3008;OP +3009 3009;CL +300A 300A;OP +300B 300B;CL +300C 300C;OP +300D 300D;CL +300E 300E;OP +300F 300F;CL +3010 3010;OP +3011 3011;CL +3012 3013;ID +3014 3014;OP +3015 3015;CL +3016 3016;OP +3017 3017;CL +3018 3018;OP +3019 3019;CL +301A 301A;OP +301B 301B;CL +301C 301C;NS +301D 301D;OP +301E 301F;CL +3020 3020;ID +3021 3029;ID +302A 302F;CM +3030 3030;ID +3031 3035;ID +3036 3037;ID +3038 303A;ID +303E 303F;ID +3041 3041;NS +3042 3042;ID +3043 3043;NS +3044 3044;ID +3045 3045;NS +3046 3046;ID +3047 3047;NS +3048 3048;ID +3049 3049;NS +304A 3062;ID +3063 3063;NS +3064 3082;ID +3083 3083;NS +3084 3084;ID +3085 3085;NS +3086 3086;ID +3087 3087;NS +3088 308D;ID +308E 308E;NS +308F 3094;ID +3099 309A;CM +309B 309C;NS +309D 309E;NS +30A1 30A1;NS +30A2 30A2;ID +30A3 30A3;NS +30A4 30A4;ID +30A5 30A5;NS +30A6 30A6;ID +30A7 30A7;NS +30A8 30A8;ID +30A9 30A9;NS +30AA 30C2;ID +30C3 30C3;NS +30C4 30E2;ID +30E3 30E3;NS +30E4 30E4;ID +30E5 30E5;NS +30E6 30E6;ID +30E7 30E7;NS +30E8 30ED;ID +30EE 30EE;NS +30EF 30F4;ID +30F5 30F6;NS +30F7 30FA;ID +30FB 30FB;NS +30FC 30FC;ID +30FD 30FD;NS +30FE 30FE;ID +3105 312C;ID +3131 318E;ID +3190 3191;ID +3192 3195;ID +3196 319F;ID +31A0 31B7;ID +3200 321C;ID +3220 3229;ID +322A 3243;ID +3260 327B;ID +327F 327F;ID +3280 3289;ID +328A 32B0;ID +32C0 32CB;ID +32D0 32FE;ID +3300 3376;ID +337B 33DD;ID +33E0 33FE;ID +3400 4DB5;ID +4E00 9FA5;ID +A000 A48C;ID +A490 A4A1;ID +A4A4 A4B3;ID +A4B5 A4C0;ID +A4C2 A4C4;ID +A4C6 A4C6;ID +AC00 D7A3;ID +D800 DFFF;SG +E000 F8FF;XX +F900 FA2D;ID +FB00 FB06;AL +FB13 FB17;AL +FB1D FB1D;AL +FB1E FB1E;CM +FB1F FB28;AL +FB29 FB29;AL +FB2A FB36;AL +FB38 FB3C;AL +FB3E FB3E;AL +FB40 FB41;AL +FB43 FB44;AL +FB46 FBB1;AL +FBD3 FD3D;AL +FD3E FD3E;OP +FD3F FD3F;CL +FD50 FD8F;AL +FD92 FDC7;AL +FDF0 FDFB;AL +FE20 FE23;CM +FE30 FE30;ID +FE31 FE32;ID +FE33 FE34;ID +FE35 FE35;OP +FE36 FE36;CL +FE37 FE37;OP +FE38 FE38;CL +FE39 FE39;OP +FE3A FE3A;CL +FE3B FE3B;OP +FE3C FE3C;CL +FE3D FE3D;OP +FE3E FE3E;CL +FE3F FE3F;OP +FE40 FE40;CL +FE41 FE41;OP +FE42 FE42;CL +FE43 FE43;OP +FE44 FE44;CL +FE49 FE4C;ID +FE4D FE4F;ID +FE50 FE50;CL +FE51 FE51;ID +FE52 FE52;CL +FE54 FE55;NS +FE56 FE57;EX +FE58 FE58;ID +FE59 FE59;OP +FE5A FE5A;CL +FE5B FE5B;OP +FE5C FE5C;CL +FE5D FE5D;OP +FE5E FE5E;CL +FE5F FE61;ID +FE62 FE62;ID +FE63 FE63;ID +FE64 FE66;ID +FE68 FE68;ID +FE69 FE69;PR +FE6A FE6A;PO +FE6B FE6B;ID +FE70 FE72;AL +FE74 FE74;AL +FE76 FEFC;AL +FEFF FEFF;GL +FF01 FF01;EX +FF02 FF03;ID +FF04 FF04;PR +FF05 FF05;PO +FF06 FF07;ID +FF08 FF08;OP +FF09 FF09;CL +FF0A FF0A;ID +FF0B FF0B;ID +FF0C FF0C;CL +FF0D FF0D;ID +FF0E FF0E;CL +FF0F FF0F;ID +FF10 FF19;ID +FF1A FF1B;NS +FF1C FF1E;ID +FF1F FF1F;EX +FF20 FF20;ID +FF21 FF3A;ID +FF3B FF3B;OP +FF3C FF3C;ID +FF3D FF3D;CL +FF3E FF3E;ID +FF3F FF3F;ID +FF40 FF40;ID +FF41 FF5A;ID +FF5B FF5B;OP +FF5C FF5C;ID +FF5D FF5D;CL +FF5E FF5E;ID +FF61 FF61;CL +FF62 FF62;OP +FF63 FF63;CL +FF64 FF64;CL +FF65 FF65;NS +FF66 FF66;AL +FF67 FF6F;NS +FF70 FF70;NS +FF71 FF9D;AL +FF9E FF9F;NS +FFA0 FFBE;AL +FFC2 FFC7;AL +FFCA FFCF;AL +FFD2 FFD7;AL +FFDA FFDC;AL +FFE0 FFE0;PO +FFE1 FFE1;PR +FFE2 FFE2;ID +FFE3 FFE3;ID +FFE4 FFE4;ID +FFE5 FFE6;PR +FFE8 FFE8;AL +FFE9 FFEC;AL +FFED FFEE;AL +FFF9 FFFB;CM +FFFC FFFC;CB +FFFD FFFD;AI diff --git a/data/uni-nfc.txt b/data/uni-nfc.txt new file mode 100644 index 000000000..4ce77c52c --- /dev/null +++ b/data/uni-nfc.txt @@ -0,0 +1,989 @@ +# uni-nfc.txt - Unicode composition mapping +003C 0338 226E; +003D 0338 2260; +003E 0338 226F; +0041 0300 00C0; +0041 0301 00C1; +0041 0302 00C2; +0041 0303 00C3; +0041 0304 0100; +0041 0306 0102; +0041 0307 0226; +0041 0308 00C4; +0041 0309 1EA2; +0041 030A 00C5; +0041 030C 01CD; +0041 030F 0200; +0041 0311 0202; +0041 0323 1EA0; +0041 0325 1E00; +0041 0328 0104; +0042 0307 1E02; +0042 0323 1E04; +0042 0331 1E06; +0043 0301 0106; +0043 0302 0108; +0043 0307 010A; +0043 030C 010C; +0043 0327 00C7; +0044 0307 1E0A; +0044 030C 010E; +0044 0323 1E0C; +0044 0327 1E10; +0044 032D 1E12; +0044 0331 1E0E; +0045 0300 00C8; +0045 0301 00C9; +0045 0302 00CA; +0045 0303 1EBC; +0045 0304 0112; +0045 0306 0114; +0045 0307 0116; +0045 0308 00CB; +0045 0309 1EBA; +0045 030C 011A; +0045 030F 0204; +0045 0311 0206; +0045 0323 1EB8; +0045 0327 0228; +0045 0328 0118; +0045 032D 1E18; +0045 0330 1E1A; +0046 0307 1E1E; +0047 0301 01F4; +0047 0302 011C; +0047 0304 1E20; +0047 0306 011E; +0047 0307 0120; +0047 030C 01E6; +0047 0327 0122; +0048 0302 0124; +0048 0307 1E22; +0048 0308 1E26; +0048 030C 021E; +0048 0323 1E24; +0048 0327 1E28; +0048 032E 1E2A; +0049 0300 00CC; +0049 0301 00CD; +0049 0302 00CE; +0049 0303 0128; +0049 0304 012A; +0049 0306 012C; +0049 0307 0130; +0049 0308 00CF; +0049 0309 1EC8; +0049 030C 01CF; +0049 030F 0208; +0049 0311 020A; +0049 0323 1ECA; +0049 0328 012E; +0049 0330 1E2C; +004A 0302 0134; +004B 0301 1E30; +004B 030C 01E8; +004B 0323 1E32; +004B 0327 0136; +004B 0331 1E34; +004C 0301 0139; +004C 030C 013D; +004C 0323 1E36; +004C 0327 013B; +004C 032D 1E3C; +004C 0331 1E3A; +004D 0301 1E3E; +004D 0307 1E40; +004D 0323 1E42; +004E 0300 01F8; +004E 0301 0143; +004E 0303 00D1; +004E 0307 1E44; +004E 030C 0147; +004E 0323 1E46; +004E 0327 0145; +004E 032D 1E4A; +004E 0331 1E48; +004F 0300 00D2; +004F 0301 00D3; +004F 0302 00D4; +004F 0303 00D5; +004F 0304 014C; +004F 0306 014E; +004F 0307 022E; +004F 0308 00D6; +004F 0309 1ECE; +004F 030B 0150; +004F 030C 01D1; +004F 030F 020C; +004F 0311 020E; +004F 031B 01A0; +004F 0323 1ECC; +004F 0328 01EA; +0050 0301 1E54; +0050 0307 1E56; +0052 0301 0154; +0052 0307 1E58; +0052 030C 0158; +0052 030F 0210; +0052 0311 0212; +0052 0323 1E5A; +0052 0327 0156; +0052 0331 1E5E; +0053 0301 015A; +0053 0302 015C; +0053 0307 1E60; +0053 030C 0160; +0053 0323 1E62; +0053 0326 0218; +0053 0327 015E; +0054 0307 1E6A; +0054 030C 0164; +0054 0323 1E6C; +0054 0326 021A; +0054 0327 0162; +0054 032D 1E70; +0054 0331 1E6E; +0055 0300 00D9; +0055 0301 00DA; +0055 0302 00DB; +0055 0303 0168; +0055 0304 016A; +0055 0306 016C; +0055 0308 00DC; +0055 0309 1EE6; +0055 030A 016E; +0055 030B 0170; +0055 030C 01D3; +0055 030F 0214; +0055 0311 0216; +0055 031B 01AF; +0055 0323 1EE4; +0055 0324 1E72; +0055 0328 0172; +0055 032D 1E76; +0055 0330 1E74; +0056 0303 1E7C; +0056 0323 1E7E; +0057 0300 1E80; +0057 0301 1E82; +0057 0302 0174; +0057 0307 1E86; +0057 0308 1E84; +0057 0323 1E88; +0058 0307 1E8A; +0058 0308 1E8C; +0059 0300 1EF2; +0059 0301 00DD; +0059 0302 0176; +0059 0303 1EF8; +0059 0304 0232; +0059 0307 1E8E; +0059 0308 0178; +0059 0309 1EF6; +0059 0323 1EF4; +005A 0301 0179; +005A 0302 1E90; +005A 0307 017B; +005A 030C 017D; +005A 0323 1E92; +005A 0331 1E94; +0061 0300 00E0; +0061 0301 00E1; +0061 0302 00E2; +0061 0303 00E3; +0061 0304 0101; +0061 0306 0103; +0061 0307 0227; +0061 0308 00E4; +0061 0309 1EA3; +0061 030A 00E5; +0061 030C 01CE; +0061 030F 0201; +0061 0311 0203; +0061 0323 1EA1; +0061 0325 1E01; +0061 0328 0105; +0062 0307 1E03; +0062 0323 1E05; +0062 0331 1E07; +0063 0301 0107; +0063 0302 0109; +0063 0307 010B; +0063 030C 010D; +0063 0327 00E7; +0064 0307 1E0B; +0064 030C 010F; +0064 0323 1E0D; +0064 0327 1E11; +0064 032D 1E13; +0064 0331 1E0F; +0065 0300 00E8; +0065 0301 00E9; +0065 0302 00EA; +0065 0303 1EBD; +0065 0304 0113; +0065 0306 0115; +0065 0307 0117; +0065 0308 00EB; +0065 0309 1EBB; +0065 030C 011B; +0065 030F 0205; +0065 0311 0207; +0065 0323 1EB9; +0065 0327 0229; +0065 0328 0119; +0065 032D 1E19; +0065 0330 1E1B; +0066 0307 1E1F; +0067 0301 01F5; +0067 0302 011D; +0067 0304 1E21; +0067 0306 011F; +0067 0307 0121; +0067 030C 01E7; +0067 0327 0123; +0068 0302 0125; +0068 0307 1E23; +0068 0308 1E27; +0068 030C 021F; +0068 0323 1E25; +0068 0327 1E29; +0068 032E 1E2B; +0068 0331 1E96; +0069 0300 00EC; +0069 0301 00ED; +0069 0302 00EE; +0069 0303 0129; +0069 0304 012B; +0069 0306 012D; +0069 0308 00EF; +0069 0309 1EC9; +0069 030C 01D0; +0069 030F 0209; +0069 0311 020B; +0069 0323 1ECB; +0069 0328 012F; +0069 0330 1E2D; +006A 0302 0135; +006A 030C 01F0; +006B 0301 1E31; +006B 030C 01E9; +006B 0323 1E33; +006B 0327 0137; +006B 0331 1E35; +006C 0301 013A; +006C 030C 013E; +006C 0323 1E37; +006C 0327 013C; +006C 032D 1E3D; +006C 0331 1E3B; +006D 0301 1E3F; +006D 0307 1E41; +006D 0323 1E43; +006E 0300 01F9; +006E 0301 0144; +006E 0303 00F1; +006E 0307 1E45; +006E 030C 0148; +006E 0323 1E47; +006E 0327 0146; +006E 032D 1E4B; +006E 0331 1E49; +006F 0300 00F2; +006F 0301 00F3; +006F 0302 00F4; +006F 0303 00F5; +006F 0304 014D; +006F 0306 014F; +006F 0307 022F; +006F 0308 00F6; +006F 0309 1ECF; +006F 030B 0151; +006F 030C 01D2; +006F 030F 020D; +006F 0311 020F; +006F 031B 01A1; +006F 0323 1ECD; +006F 0328 01EB; +0070 0301 1E55; +0070 0307 1E57; +0072 0301 0155; +0072 0307 1E59; +0072 030C 0159; +0072 030F 0211; +0072 0311 0213; +0072 0323 1E5B; +0072 0327 0157; +0072 0331 1E5F; +0073 0301 015B; +0073 0302 015D; +0073 0307 1E61; +0073 030C 0161; +0073 0323 1E63; +0073 0326 0219; +0073 0327 015F; +0074 0307 1E6B; +0074 0308 1E97; +0074 030C 0165; +0074 0323 1E6D; +0074 0326 021B; +0074 0327 0163; +0074 032D 1E71; +0074 0331 1E6F; +0075 0300 00F9; +0075 0301 00FA; +0075 0302 00FB; +0075 0303 0169; +0075 0304 016B; +0075 0306 016D; +0075 0308 00FC; +0075 0309 1EE7; +0075 030A 016F; +0075 030B 0171; +0075 030C 01D4; +0075 030F 0215; +0075 0311 0217; +0075 031B 01B0; +0075 0323 1EE5; +0075 0324 1E73; +0075 0328 0173; +0075 032D 1E77; +0075 0330 1E75; +0076 0303 1E7D; +0076 0323 1E7F; +0077 0300 1E81; +0077 0301 1E83; +0077 0302 0175; +0077 0307 1E87; +0077 0308 1E85; +0077 030A 1E98; +0077 0323 1E89; +0078 0307 1E8B; +0078 0308 1E8D; +0079 0300 1EF3; +0079 0301 00FD; +0079 0302 0177; +0079 0303 1EF9; +0079 0304 0233; +0079 0307 1E8F; +0079 0308 00FF; +0079 0309 1EF7; +0079 030A 1E99; +0079 0323 1EF5; +007A 0301 017A; +007A 0302 1E91; +007A 0307 017C; +007A 030C 017E; +007A 0323 1E93; +007A 0331 1E95; +00A8 0300 1FED; +00A8 0301 0385; +00A8 0342 1FC1; +00C2 0300 1EA6; +00C2 0301 1EA4; +00C2 0303 1EAA; +00C2 0309 1EA8; +00C4 0304 01DE; +00C5 0301 01FA; +00C6 0301 01FC; +00C6 0304 01E2; +00C7 0301 1E08; +00CA 0300 1EC0; +00CA 0301 1EBE; +00CA 0303 1EC4; +00CA 0309 1EC2; +00CF 0301 1E2E; +00D4 0300 1ED2; +00D4 0301 1ED0; +00D4 0303 1ED6; +00D4 0309 1ED4; +00D5 0301 1E4C; +00D5 0304 022C; +00D5 0308 1E4E; +00D6 0304 022A; +00D8 0301 01FE; +00DC 0300 01DB; +00DC 0301 01D7; +00DC 0304 01D5; +00DC 030C 01D9; +00E2 0300 1EA7; +00E2 0301 1EA5; +00E2 0303 1EAB; +00E2 0309 1EA9; +00E4 0304 01DF; +00E5 0301 01FB; +00E6 0301 01FD; +00E6 0304 01E3; +00E7 0301 1E09; +00EA 0300 1EC1; +00EA 0301 1EBF; +00EA 0303 1EC5; +00EA 0309 1EC3; +00EF 0301 1E2F; +00F4 0300 1ED3; +00F4 0301 1ED1; +00F4 0303 1ED7; +00F4 0309 1ED5; +00F5 0301 1E4D; +00F5 0304 022D; +00F5 0308 1E4F; +00F6 0304 022B; +00F8 0301 01FF; +00FC 0300 01DC; +00FC 0301 01D8; +00FC 0304 01D6; +00FC 030C 01DA; +0102 0300 1EB0; +0102 0301 1EAE; +0102 0303 1EB4; +0102 0309 1EB2; +0103 0300 1EB1; +0103 0301 1EAF; +0103 0303 1EB5; +0103 0309 1EB3; +0112 0300 1E14; +0112 0301 1E16; +0113 0300 1E15; +0113 0301 1E17; +014C 0300 1E50; +014C 0301 1E52; +014D 0300 1E51; +014D 0301 1E53; +015A 0307 1E64; +015B 0307 1E65; +0160 0307 1E66; +0161 0307 1E67; +0168 0301 1E78; +0169 0301 1E79; +016A 0308 1E7A; +016B 0308 1E7B; +017F 0307 1E9B; +01A0 0300 1EDC; +01A0 0301 1EDA; +01A0 0303 1EE0; +01A0 0309 1EDE; +01A0 0323 1EE2; +01A1 0300 1EDD; +01A1 0301 1EDB; +01A1 0303 1EE1; +01A1 0309 1EDF; +01A1 0323 1EE3; +01AF 0300 1EEA; +01AF 0301 1EE8; +01AF 0303 1EEE; +01AF 0309 1EEC; +01AF 0323 1EF0; +01B0 0300 1EEB; +01B0 0301 1EE9; +01B0 0303 1EEF; +01B0 0309 1EED; +01B0 0323 1EF1; +01B7 030C 01EE; +01EA 0304 01EC; +01EB 0304 01ED; +0226 0304 01E0; +0227 0304 01E1; +0228 0306 1E1C; +0229 0306 1E1D; +022E 0304 0230; +022F 0304 0231; +0292 030C 01EF; +0308 0301 0344; +0391 0300 1FBA; +0391 0301 0386; +0391 0304 1FB9; +0391 0306 1FB8; +0391 0313 1F08; +0391 0314 1F09; +0391 0345 1FBC; +0395 0300 1FC8; +0395 0301 0388; +0395 0313 1F18; +0395 0314 1F19; +0397 0300 1FCA; +0397 0301 0389; +0397 0313 1F28; +0397 0314 1F29; +0397 0345 1FCC; +0399 0300 1FDA; +0399 0301 038A; +0399 0304 1FD9; +0399 0306 1FD8; +0399 0308 03AA; +0399 0313 1F38; +0399 0314 1F39; +039F 0300 1FF8; +039F 0301 038C; +039F 0313 1F48; +039F 0314 1F49; +03A1 0314 1FEC; +03A5 0300 1FEA; +03A5 0301 038E; +03A5 0304 1FE9; +03A5 0306 1FE8; +03A5 0308 03AB; +03A5 0314 1F59; +03A9 0300 1FFA; +03A9 0301 038F; +03A9 0313 1F68; +03A9 0314 1F69; +03A9 0345 1FFC; +03AC 0345 1FB4; +03AE 0345 1FC4; +03B1 0300 1F70; +03B1 0301 03AC; +03B1 0304 1FB1; +03B1 0306 1FB0; +03B1 0313 1F00; +03B1 0314 1F01; +03B1 0342 1FB6; +03B1 0345 1FB3; +03B5 0300 1F72; +03B5 0301 03AD; +03B5 0313 1F10; +03B5 0314 1F11; +03B7 0300 1F74; +03B7 0301 03AE; +03B7 0313 1F20; +03B7 0314 1F21; +03B7 0342 1FC6; +03B7 0345 1FC3; +03B9 0300 1F76; +03B9 0301 03AF; +03B9 0304 1FD1; +03B9 0306 1FD0; +03B9 0308 03CA; +03B9 0313 1F30; +03B9 0314 1F31; +03B9 0342 1FD6; +03BF 0300 1F78; +03BF 0301 03CC; +03BF 0313 1F40; +03BF 0314 1F41; +03C1 0313 1FE4; +03C1 0314 1FE5; +03C5 0300 1F7A; +03C5 0301 03CD; +03C5 0304 1FE1; +03C5 0306 1FE0; +03C5 0308 03CB; +03C5 0313 1F50; +03C5 0314 1F51; +03C5 0342 1FE6; +03C9 0300 1F7C; +03C9 0301 03CE; +03C9 0313 1F60; +03C9 0314 1F61; +03C9 0342 1FF6; +03C9 0345 1FF3; +03CA 0300 1FD2; +03CA 0301 0390; +03CA 0342 1FD7; +03CB 0300 1FE2; +03CB 0301 03B0; +03CB 0342 1FE7; +03CE 0345 1FF4; +03D2 0301 03D3; +03D2 0308 03D4; +0406 0308 0407; +0410 0306 04D0; +0410 0308 04D2; +0413 0301 0403; +0415 0300 0400; +0415 0306 04D6; +0415 0308 0401; +0416 0306 04C1; +0416 0308 04DC; +0417 0308 04DE; +0418 0300 040D; +0418 0304 04E2; +0418 0306 0419; +0418 0308 04E4; +041A 0301 040C; +041E 0308 04E6; +0423 0304 04EE; +0423 0306 040E; +0423 0308 04F0; +0423 030B 04F2; +0427 0308 04F4; +042B 0308 04F8; +042D 0308 04EC; +0430 0306 04D1; +0430 0308 04D3; +0433 0301 0453; +0435 0300 0450; +0435 0306 04D7; +0435 0308 0451; +0436 0306 04C2; +0436 0308 04DD; +0437 0308 04DF; +0438 0300 045D; +0438 0304 04E3; +0438 0306 0439; +0438 0308 04E5; +043A 0301 045C; +043E 0308 04E7; +0443 0304 04EF; +0443 0306 045E; +0443 0308 04F1; +0443 030B 04F3; +0447 0308 04F5; +044B 0308 04F9; +044D 0308 04ED; +0456 0308 0457; +0474 030F 0476; +0475 030F 0477; +04D8 0308 04DA; +04D9 0308 04DB; +04E8 0308 04EA; +04E9 0308 04EB; +05D0 05B7 FB2E; +05D0 05B8 FB2F; +05D0 05BC FB30; +05D1 05BC FB31; +05D1 05BF FB4C; +05D2 05BC FB32; +05D3 05BC FB33; +05D4 05BC FB34; +05D5 05B9 FB4B; +05D5 05BC FB35; +05D6 05BC FB36; +05D8 05BC FB38; +05D9 05B4 FB1D; +05D9 05BC FB39; +05DA 05BC FB3A; +05DB 05BC FB3B; +05DB 05BF FB4D; +05DC 05BC FB3C; +05DE 05BC FB3E; +05E0 05BC FB40; +05E1 05BC FB41; +05E3 05BC FB43; +05E4 05BC FB44; +05E4 05BF FB4E; +05E6 05BC FB46; +05E7 05BC FB47; +05E8 05BC FB48; +05E9 05BC FB49; +05E9 05C1 FB2A; +05E9 05C2 FB2B; +05EA 05BC FB4A; +05F2 05B7 FB1F; +0627 0653 0622; +0627 0654 0623; +0627 0655 0625; +0648 0654 0624; +064A 0654 0626; +06C1 0654 06C2; +06D2 0654 06D3; +06D5 0654 06C0; +0915 093C 0958; +0916 093C 0959; +0917 093C 095A; +091C 093C 095B; +0921 093C 095C; +0922 093C 095D; +0928 093C 0929; +092B 093C 095E; +092F 093C 095F; +0930 093C 0931; +0933 093C 0934; +09A1 09BC 09DC; +09A2 09BC 09DD; +09AF 09BC 09DF; +09C7 09BE 09CB; +09C7 09D7 09CC; +0A16 0A3C 0A59; +0A17 0A3C 0A5A; +0A1C 0A3C 0A5B; +0A2B 0A3C 0A5E; +0A32 0A3C 0A33; +0A38 0A3C 0A36; +0B21 0B3C 0B5C; +0B22 0B3C 0B5D; +0B47 0B3E 0B4B; +0B47 0B56 0B48; +0B47 0B57 0B4C; +0B92 0BD7 0B94; +0BC6 0BBE 0BCA; +0BC6 0BD7 0BCC; +0BC7 0BBE 0BCB; +0C46 0C56 0C48; +0CBF 0CD5 0CC0; +0CC6 0CC2 0CCA; +0CC6 0CD5 0CC7; +0CC6 0CD6 0CC8; +0CCA 0CD5 0CCB; +0D46 0D3E 0D4A; +0D46 0D57 0D4C; +0D47 0D3E 0D4B; +0DD9 0DCA 0DDA; +0DD9 0DCF 0DDC; +0DD9 0DDF 0DDE; +0DDC 0DCA 0DDD; +0F40 0FB5 0F69; +0F42 0FB7 0F43; +0F4C 0FB7 0F4D; +0F51 0FB7 0F52; +0F56 0FB7 0F57; +0F5B 0FB7 0F5C; +0F71 0F72 0F73; +0F71 0F74 0F75; +0F71 0F80 0F81; +0F90 0FB5 0FB9; +0F92 0FB7 0F93; +0F9C 0FB7 0F9D; +0FA1 0FB7 0FA2; +0FA6 0FB7 0FA7; +0FAB 0FB7 0FAC; +0FB2 0F80 0F76; +0FB3 0F80 0F78; +1025 102E 1026; +1E36 0304 1E38; +1E37 0304 1E39; +1E5A 0304 1E5C; +1E5B 0304 1E5D; +1E62 0307 1E68; +1E63 0307 1E69; +1EA0 0302 1EAC; +1EA0 0306 1EB6; +1EA1 0302 1EAD; +1EA1 0306 1EB7; +1EB8 0302 1EC6; +1EB9 0302 1EC7; +1ECC 0302 1ED8; +1ECD 0302 1ED9; +1F00 0300 1F02; +1F00 0301 1F04; +1F00 0342 1F06; +1F00 0345 1F80; +1F01 0300 1F03; +1F01 0301 1F05; +1F01 0342 1F07; +1F01 0345 1F81; +1F02 0345 1F82; +1F03 0345 1F83; +1F04 0345 1F84; +1F05 0345 1F85; +1F06 0345 1F86; +1F07 0345 1F87; +1F08 0300 1F0A; +1F08 0301 1F0C; +1F08 0342 1F0E; +1F08 0345 1F88; +1F09 0300 1F0B; +1F09 0301 1F0D; +1F09 0342 1F0F; +1F09 0345 1F89; +1F0A 0345 1F8A; +1F0B 0345 1F8B; +1F0C 0345 1F8C; +1F0D 0345 1F8D; +1F0E 0345 1F8E; +1F0F 0345 1F8F; +1F10 0300 1F12; +1F10 0301 1F14; +1F11 0300 1F13; +1F11 0301 1F15; +1F18 0300 1F1A; +1F18 0301 1F1C; +1F19 0300 1F1B; +1F19 0301 1F1D; +1F20 0300 1F22; +1F20 0301 1F24; +1F20 0342 1F26; +1F20 0345 1F90; +1F21 0300 1F23; +1F21 0301 1F25; +1F21 0342 1F27; +1F21 0345 1F91; +1F22 0345 1F92; +1F23 0345 1F93; +1F24 0345 1F94; +1F25 0345 1F95; +1F26 0345 1F96; +1F27 0345 1F97; +1F28 0300 1F2A; +1F28 0301 1F2C; +1F28 0342 1F2E; +1F28 0345 1F98; +1F29 0300 1F2B; +1F29 0301 1F2D; +1F29 0342 1F2F; +1F29 0345 1F99; +1F2A 0345 1F9A; +1F2B 0345 1F9B; +1F2C 0345 1F9C; +1F2D 0345 1F9D; +1F2E 0345 1F9E; +1F2F 0345 1F9F; +1F30 0300 1F32; +1F30 0301 1F34; +1F30 0342 1F36; +1F31 0300 1F33; +1F31 0301 1F35; +1F31 0342 1F37; +1F38 0300 1F3A; +1F38 0301 1F3C; +1F38 0342 1F3E; +1F39 0300 1F3B; +1F39 0301 1F3D; +1F39 0342 1F3F; +1F40 0300 1F42; +1F40 0301 1F44; +1F41 0300 1F43; +1F41 0301 1F45; +1F48 0300 1F4A; +1F48 0301 1F4C; +1F49 0300 1F4B; +1F49 0301 1F4D; +1F50 0300 1F52; +1F50 0301 1F54; +1F50 0342 1F56; +1F51 0300 1F53; +1F51 0301 1F55; +1F51 0342 1F57; +1F59 0300 1F5B; +1F59 0301 1F5D; +1F59 0342 1F5F; +1F60 0300 1F62; +1F60 0301 1F64; +1F60 0342 1F66; +1F60 0345 1FA0; +1F61 0300 1F63; +1F61 0301 1F65; +1F61 0342 1F67; +1F61 0345 1FA1; +1F62 0345 1FA2; +1F63 0345 1FA3; +1F64 0345 1FA4; +1F65 0345 1FA5; +1F66 0345 1FA6; +1F67 0345 1FA7; +1F68 0300 1F6A; +1F68 0301 1F6C; +1F68 0342 1F6E; +1F68 0345 1FA8; +1F69 0300 1F6B; +1F69 0301 1F6D; +1F69 0342 1F6F; +1F69 0345 1FA9; +1F6A 0345 1FAA; +1F6B 0345 1FAB; +1F6C 0345 1FAC; +1F6D 0345 1FAD; +1F6E 0345 1FAE; +1F6F 0345 1FAF; +1F70 0345 1FB2; +1F74 0345 1FC2; +1F7C 0345 1FF2; +1FB6 0345 1FB7; +1FBF 0300 1FCD; +1FBF 0301 1FCE; +1FBF 0342 1FCF; +1FC6 0345 1FC7; +1FF6 0345 1FF7; +1FFE 0300 1FDD; +1FFE 0301 1FDE; +1FFE 0342 1FDF; +2190 0338 219A; +2192 0338 219B; +2194 0338 21AE; +21D0 0338 21CD; +21D2 0338 21CF; +21D4 0338 21CE; +2203 0338 2204; +2208 0338 2209; +220B 0338 220C; +2223 0338 2224; +2225 0338 2226; +223C 0338 2241; +2243 0338 2244; +2245 0338 2247; +2248 0338 2249; +224D 0338 226D; +2261 0338 2262; +2264 0338 2270; +2265 0338 2271; +2272 0338 2274; +2273 0338 2275; +2276 0338 2278; +2277 0338 2279; +227A 0338 2280; +227B 0338 2281; +227C 0338 22E0; +227D 0338 22E1; +2282 0338 2284; +2283 0338 2285; +2286 0338 2288; +2287 0338 2289; +2291 0338 22E2; +2292 0338 22E3; +22A2 0338 22AC; +22A8 0338 22AD; +22A9 0338 22AE; +22AB 0338 22AF; +22B2 0338 22EA; +22B3 0338 22EB; +22B4 0338 22EC; +22B5 0338 22ED; +3046 3099 3094; +304B 3099 304C; +304D 3099 304E; +304F 3099 3050; +3051 3099 3052; +3053 3099 3054; +3055 3099 3056; +3057 3099 3058; +3059 3099 305A; +305B 3099 305C; +305D 3099 305E; +305F 3099 3060; +3061 3099 3062; +3064 3099 3065; +3066 3099 3067; +3068 3099 3069; +306F 3099 3070; +306F 309A 3071; +3072 3099 3073; +3072 309A 3074; +3075 3099 3076; +3075 309A 3077; +3078 3099 3079; +3078 309A 307A; +307B 3099 307C; +307B 309A 307D; +309D 3099 309E; +30A6 3099 30F4; +30AB 3099 30AC; +30AD 3099 30AE; +30AF 3099 30B0; +30B1 3099 30B2; +30B3 3099 30B4; +30B5 3099 30B6; +30B7 3099 30B8; +30B9 3099 30BA; +30BB 3099 30BC; +30BD 3099 30BE; +30BF 3099 30C0; +30C1 3099 30C2; +30C4 3099 30C5; +30C6 3099 30C7; +30C8 3099 30C9; +30CF 3099 30D0; +30CF 309A 30D1; +30D2 3099 30D3; +30D2 309A 30D4; +30D5 3099 30D6; +30D5 309A 30D7; +30D8 3099 30D9; +30D8 309A 30DA; +30DB 3099 30DC; +30DB 309A 30DD; +30EF 3099 30F7; +30F0 3099 30F8; +30F1 3099 30F9; +30F2 3099 30FA; +30FD 3099 30FE; +FB49 05C1 FB2C; +FB49 05C2 FB2D; diff --git a/data/uni-nfd.txt b/data/uni-nfd.txt new file mode 100644 index 000000000..80cef2770 --- /dev/null +++ b/data/uni-nfd.txt @@ -0,0 +1,1312 @@ +# uni-nfd.txt - Unicode decomposition mapping +00C0 0041 0300; +00C1 0041 0301; +00C2 0041 0302; +00C3 0041 0303; +00C4 0041 0308; +00C5 0041 030A; +00C7 0043 0327; +00C8 0045 0300; +00C9 0045 0301; +00CA 0045 0302; +00CB 0045 0308; +00CC 0049 0300; +00CD 0049 0301; +00CE 0049 0302; +00CF 0049 0308; +00D1 004E 0303; +00D2 004F 0300; +00D3 004F 0301; +00D4 004F 0302; +00D5 004F 0303; +00D6 004F 0308; +00D9 0055 0300; +00DA 0055 0301; +00DB 0055 0302; +00DC 0055 0308; +00DD 0059 0301; +00E0 0061 0300; +00E1 0061 0301; +00E2 0061 0302; +00E3 0061 0303; +00E4 0061 0308; +00E5 0061 030A; +00E7 0063 0327; +00E8 0065 0300; +00E9 0065 0301; +00EA 0065 0302; +00EB 0065 0308; +00EC 0069 0300; +00ED 0069 0301; +00EE 0069 0302; +00EF 0069 0308; +00F1 006E 0303; +00F2 006F 0300; +00F3 006F 0301; +00F4 006F 0302; +00F5 006F 0303; +00F6 006F 0308; +00F9 0075 0300; +00FA 0075 0301; +00FB 0075 0302; +00FC 0075 0308; +00FD 0079 0301; +00FF 0079 0308; +0100 0041 0304; +0101 0061 0304; +0102 0041 0306; +0103 0061 0306; +0104 0041 0328; +0105 0061 0328; +0106 0043 0301; +0107 0063 0301; +0108 0043 0302; +0109 0063 0302; +010A 0043 0307; +010B 0063 0307; +010C 0043 030C; +010D 0063 030C; +010E 0044 030C; +010F 0064 030C; +0112 0045 0304; +0113 0065 0304; +0114 0045 0306; +0115 0065 0306; +0116 0045 0307; +0117 0065 0307; +0118 0045 0328; +0119 0065 0328; +011A 0045 030C; +011B 0065 030C; +011C 0047 0302; +011D 0067 0302; +011E 0047 0306; +011F 0067 0306; +0120 0047 0307; +0121 0067 0307; +0122 0047 0327; +0123 0067 0327; +0124 0048 0302; +0125 0068 0302; +0128 0049 0303; +0129 0069 0303; +012A 0049 0304; +012B 0069 0304; +012C 0049 0306; +012D 0069 0306; +012E 0049 0328; +012F 0069 0328; +0130 0049 0307; +0134 004A 0302; +0135 006A 0302; +0136 004B 0327; +0137 006B 0327; +0139 004C 0301; +013A 006C 0301; +013B 004C 0327; +013C 006C 0327; +013D 004C 030C; +013E 006C 030C; +0143 004E 0301; +0144 006E 0301; +0145 004E 0327; +0146 006E 0327; +0147 004E 030C; +0148 006E 030C; +014C 004F 0304; +014D 006F 0304; +014E 004F 0306; +014F 006F 0306; +0150 004F 030B; +0151 006F 030B; +0154 0052 0301; +0155 0072 0301; +0156 0052 0327; +0157 0072 0327; +0158 0052 030C; +0159 0072 030C; +015A 0053 0301; +015B 0073 0301; +015C 0053 0302; +015D 0073 0302; +015E 0053 0327; +015F 0073 0327; +0160 0053 030C; +0161 0073 030C; +0162 0054 0327; +0163 0074 0327; +0164 0054 030C; +0165 0074 030C; +0168 0055 0303; +0169 0075 0303; +016A 0055 0304; +016B 0075 0304; +016C 0055 0306; +016D 0075 0306; +016E 0055 030A; +016F 0075 030A; +0170 0055 030B; +0171 0075 030B; +0172 0055 0328; +0173 0075 0328; +0174 0057 0302; +0175 0077 0302; +0176 0059 0302; +0177 0079 0302; +0178 0059 0308; +0179 005A 0301; +017A 007A 0301; +017B 005A 0307; +017C 007A 0307; +017D 005A 030C; +017E 007A 030C; +01A0 004F 031B; +01A1 006F 031B; +01AF 0055 031B; +01B0 0075 031B; +01CD 0041 030C; +01CE 0061 030C; +01CF 0049 030C; +01D0 0069 030C; +01D1 004F 030C; +01D2 006F 030C; +01D3 0055 030C; +01D4 0075 030C; +01D5 00DC 0304; +01D6 00FC 0304; +01D7 00DC 0301; +01D8 00FC 0301; +01D9 00DC 030C; +01DA 00FC 030C; +01DB 00DC 0300; +01DC 00FC 0300; +01DE 00C4 0304; +01DF 00E4 0304; +01E0 0226 0304; +01E1 0227 0304; +01E2 00C6 0304; +01E3 00E6 0304; +01E6 0047 030C; +01E7 0067 030C; +01E8 004B 030C; +01E9 006B 030C; +01EA 004F 0328; +01EB 006F 0328; +01EC 01EA 0304; +01ED 01EB 0304; +01EE 01B7 030C; +01EF 0292 030C; +01F0 006A 030C; +01F4 0047 0301; +01F5 0067 0301; +01F8 004E 0300; +01F9 006E 0300; +01FA 00C5 0301; +01FB 00E5 0301; +01FC 00C6 0301; +01FD 00E6 0301; +01FE 00D8 0301; +01FF 00F8 0301; +0200 0041 030F; +0201 0061 030F; +0202 0041 0311; +0203 0061 0311; +0204 0045 030F; +0205 0065 030F; +0206 0045 0311; +0207 0065 0311; +0208 0049 030F; +0209 0069 030F; +020A 0049 0311; +020B 0069 0311; +020C 004F 030F; +020D 006F 030F; +020E 004F 0311; +020F 006F 0311; +0210 0052 030F; +0211 0072 030F; +0212 0052 0311; +0213 0072 0311; +0214 0055 030F; +0215 0075 030F; +0216 0055 0311; +0217 0075 0311; +0218 0053 0326; +0219 0073 0326; +021A 0054 0326; +021B 0074 0326; +021E 0048 030C; +021F 0068 030C; +0226 0041 0307; +0227 0061 0307; +0228 0045 0327; +0229 0065 0327; +022A 00D6 0304; +022B 00F6 0304; +022C 00D5 0304; +022D 00F5 0304; +022E 004F 0307; +022F 006F 0307; +0230 022E 0304; +0231 022F 0304; +0232 0059 0304; +0233 0079 0304; +0340 0300 0000; +0341 0301 0000; +0343 0313 0000; +0344 0308 0301; +0374 02B9 0000; +037E 003B 0000; +0385 00A8 0301; +0386 0391 0301; +0387 00B7 0000; +0388 0395 0301; +0389 0397 0301; +038A 0399 0301; +038C 039F 0301; +038E 03A5 0301; +038F 03A9 0301; +0390 03CA 0301; +03AA 0399 0308; +03AB 03A5 0308; +03AC 03B1 0301; +03AD 03B5 0301; +03AE 03B7 0301; +03AF 03B9 0301; +03B0 03CB 0301; +03CA 03B9 0308; +03CB 03C5 0308; +03CC 03BF 0301; +03CD 03C5 0301; +03CE 03C9 0301; +03D3 03D2 0301; +03D4 03D2 0308; +0400 0415 0300; +0401 0415 0308; +0403 0413 0301; +0407 0406 0308; +040C 041A 0301; +040D 0418 0300; +040E 0423 0306; +0419 0418 0306; +0439 0438 0306; +0450 0435 0300; +0451 0435 0308; +0453 0433 0301; +0457 0456 0308; +045C 043A 0301; +045D 0438 0300; +045E 0443 0306; +0476 0474 030F; +0477 0475 030F; +04C1 0416 0306; +04C2 0436 0306; +04D0 0410 0306; +04D1 0430 0306; +04D2 0410 0308; +04D3 0430 0308; +04D6 0415 0306; +04D7 0435 0306; +04DA 04D8 0308; +04DB 04D9 0308; +04DC 0416 0308; +04DD 0436 0308; +04DE 0417 0308; +04DF 0437 0308; +04E2 0418 0304; +04E3 0438 0304; +04E4 0418 0308; +04E5 0438 0308; +04E6 041E 0308; +04E7 043E 0308; +04EA 04E8 0308; +04EB 04E9 0308; +04EC 042D 0308; +04ED 044D 0308; +04EE 0423 0304; +04EF 0443 0304; +04F0 0423 0308; +04F1 0443 0308; +04F2 0423 030B; +04F3 0443 030B; +04F4 0427 0308; +04F5 0447 0308; +04F8 042B 0308; +04F9 044B 0308; +0622 0627 0653; +0623 0627 0654; +0624 0648 0654; +0625 0627 0655; +0626 064A 0654; +06C0 06D5 0654; +06C2 06C1 0654; +06D3 06D2 0654; +0929 0928 093C; +0931 0930 093C; +0934 0933 093C; +0958 0915 093C; +0959 0916 093C; +095A 0917 093C; +095B 091C 093C; +095C 0921 093C; +095D 0922 093C; +095E 092B 093C; +095F 092F 093C; +09CB 09C7 09BE; +09CC 09C7 09D7; +09DC 09A1 09BC; +09DD 09A2 09BC; +09DF 09AF 09BC; +0A33 0A32 0A3C; +0A36 0A38 0A3C; +0A59 0A16 0A3C; +0A5A 0A17 0A3C; +0A5B 0A1C 0A3C; +0A5E 0A2B 0A3C; +0B48 0B47 0B56; +0B4B 0B47 0B3E; +0B4C 0B47 0B57; +0B5C 0B21 0B3C; +0B5D 0B22 0B3C; +0B94 0B92 0BD7; +0BCA 0BC6 0BBE; +0BCB 0BC7 0BBE; +0BCC 0BC6 0BD7; +0C48 0C46 0C56; +0CC0 0CBF 0CD5; +0CC7 0CC6 0CD5; +0CC8 0CC6 0CD6; +0CCA 0CC6 0CC2; +0CCB 0CCA 0CD5; +0D4A 0D46 0D3E; +0D4B 0D47 0D3E; +0D4C 0D46 0D57; +0DDA 0DD9 0DCA; +0DDC 0DD9 0DCF; +0DDD 0DDC 0DCA; +0DDE 0DD9 0DDF; +0F43 0F42 0FB7; +0F4D 0F4C 0FB7; +0F52 0F51 0FB7; +0F57 0F56 0FB7; +0F5C 0F5B 0FB7; +0F69 0F40 0FB5; +0F73 0F71 0F72; +0F75 0F71 0F74; +0F76 0FB2 0F80; +0F78 0FB3 0F80; +0F81 0F71 0F80; +0F93 0F92 0FB7; +0F9D 0F9C 0FB7; +0FA2 0FA1 0FB7; +0FA7 0FA6 0FB7; +0FAC 0FAB 0FB7; +0FB9 0F90 0FB5; +1026 1025 102E; +1E00 0041 0325; +1E01 0061 0325; +1E02 0042 0307; +1E03 0062 0307; +1E04 0042 0323; +1E05 0062 0323; +1E06 0042 0331; +1E07 0062 0331; +1E08 00C7 0301; +1E09 00E7 0301; +1E0A 0044 0307; +1E0B 0064 0307; +1E0C 0044 0323; +1E0D 0064 0323; +1E0E 0044 0331; +1E0F 0064 0331; +1E10 0044 0327; +1E11 0064 0327; +1E12 0044 032D; +1E13 0064 032D; +1E14 0112 0300; +1E15 0113 0300; +1E16 0112 0301; +1E17 0113 0301; +1E18 0045 032D; +1E19 0065 032D; +1E1A 0045 0330; +1E1B 0065 0330; +1E1C 0228 0306; +1E1D 0229 0306; +1E1E 0046 0307; +1E1F 0066 0307; +1E20 0047 0304; +1E21 0067 0304; +1E22 0048 0307; +1E23 0068 0307; +1E24 0048 0323; +1E25 0068 0323; +1E26 0048 0308; +1E27 0068 0308; +1E28 0048 0327; +1E29 0068 0327; +1E2A 0048 032E; +1E2B 0068 032E; +1E2C 0049 0330; +1E2D 0069 0330; +1E2E 00CF 0301; +1E2F 00EF 0301; +1E30 004B 0301; +1E31 006B 0301; +1E32 004B 0323; +1E33 006B 0323; +1E34 004B 0331; +1E35 006B 0331; +1E36 004C 0323; +1E37 006C 0323; +1E38 1E36 0304; +1E39 1E37 0304; +1E3A 004C 0331; +1E3B 006C 0331; +1E3C 004C 032D; +1E3D 006C 032D; +1E3E 004D 0301; +1E3F 006D 0301; +1E40 004D 0307; +1E41 006D 0307; +1E42 004D 0323; +1E43 006D 0323; +1E44 004E 0307; +1E45 006E 0307; +1E46 004E 0323; +1E47 006E 0323; +1E48 004E 0331; +1E49 006E 0331; +1E4A 004E 032D; +1E4B 006E 032D; +1E4C 00D5 0301; +1E4D 00F5 0301; +1E4E 00D5 0308; +1E4F 00F5 0308; +1E50 014C 0300; +1E51 014D 0300; +1E52 014C 0301; +1E53 014D 0301; +1E54 0050 0301; +1E55 0070 0301; +1E56 0050 0307; +1E57 0070 0307; +1E58 0052 0307; +1E59 0072 0307; +1E5A 0052 0323; +1E5B 0072 0323; +1E5C 1E5A 0304; +1E5D 1E5B 0304; +1E5E 0052 0331; +1E5F 0072 0331; +1E60 0053 0307; +1E61 0073 0307; +1E62 0053 0323; +1E63 0073 0323; +1E64 015A 0307; +1E65 015B 0307; +1E66 0160 0307; +1E67 0161 0307; +1E68 1E62 0307; +1E69 1E63 0307; +1E6A 0054 0307; +1E6B 0074 0307; +1E6C 0054 0323; +1E6D 0074 0323; +1E6E 0054 0331; +1E6F 0074 0331; +1E70 0054 032D; +1E71 0074 032D; +1E72 0055 0324; +1E73 0075 0324; +1E74 0055 0330; +1E75 0075 0330; +1E76 0055 032D; +1E77 0075 032D; +1E78 0168 0301; +1E79 0169 0301; +1E7A 016A 0308; +1E7B 016B 0308; +1E7C 0056 0303; +1E7D 0076 0303; +1E7E 0056 0323; +1E7F 0076 0323; +1E80 0057 0300; +1E81 0077 0300; +1E82 0057 0301; +1E83 0077 0301; +1E84 0057 0308; +1E85 0077 0308; +1E86 0057 0307; +1E87 0077 0307; +1E88 0057 0323; +1E89 0077 0323; +1E8A 0058 0307; +1E8B 0078 0307; +1E8C 0058 0308; +1E8D 0078 0308; +1E8E 0059 0307; +1E8F 0079 0307; +1E90 005A 0302; +1E91 007A 0302; +1E92 005A 0323; +1E93 007A 0323; +1E94 005A 0331; +1E95 007A 0331; +1E96 0068 0331; +1E97 0074 0308; +1E98 0077 030A; +1E99 0079 030A; +1E9B 017F 0307; +1EA0 0041 0323; +1EA1 0061 0323; +1EA2 0041 0309; +1EA3 0061 0309; +1EA4 00C2 0301; +1EA5 00E2 0301; +1EA6 00C2 0300; +1EA7 00E2 0300; +1EA8 00C2 0309; +1EA9 00E2 0309; +1EAA 00C2 0303; +1EAB 00E2 0303; +1EAC 1EA0 0302; +1EAD 1EA1 0302; +1EAE 0102 0301; +1EAF 0103 0301; +1EB0 0102 0300; +1EB1 0103 0300; +1EB2 0102 0309; +1EB3 0103 0309; +1EB4 0102 0303; +1EB5 0103 0303; +1EB6 1EA0 0306; +1EB7 1EA1 0306; +1EB8 0045 0323; +1EB9 0065 0323; +1EBA 0045 0309; +1EBB 0065 0309; +1EBC 0045 0303; +1EBD 0065 0303; +1EBE 00CA 0301; +1EBF 00EA 0301; +1EC0 00CA 0300; +1EC1 00EA 0300; +1EC2 00CA 0309; +1EC3 00EA 0309; +1EC4 00CA 0303; +1EC5 00EA 0303; +1EC6 1EB8 0302; +1EC7 1EB9 0302; +1EC8 0049 0309; +1EC9 0069 0309; +1ECA 0049 0323; +1ECB 0069 0323; +1ECC 004F 0323; +1ECD 006F 0323; +1ECE 004F 0309; +1ECF 006F 0309; +1ED0 00D4 0301; +1ED1 00F4 0301; +1ED2 00D4 0300; +1ED3 00F4 0300; +1ED4 00D4 0309; +1ED5 00F4 0309; +1ED6 00D4 0303; +1ED7 00F4 0303; +1ED8 1ECC 0302; +1ED9 1ECD 0302; +1EDA 01A0 0301; +1EDB 01A1 0301; +1EDC 01A0 0300; +1EDD 01A1 0300; +1EDE 01A0 0309; +1EDF 01A1 0309; +1EE0 01A0 0303; +1EE1 01A1 0303; +1EE2 01A0 0323; +1EE3 01A1 0323; +1EE4 0055 0323; +1EE5 0075 0323; +1EE6 0055 0309; +1EE7 0075 0309; +1EE8 01AF 0301; +1EE9 01B0 0301; +1EEA 01AF 0300; +1EEB 01B0 0300; +1EEC 01AF 0309; +1EED 01B0 0309; +1EEE 01AF 0303; +1EEF 01B0 0303; +1EF0 01AF 0323; +1EF1 01B0 0323; +1EF2 0059 0300; +1EF3 0079 0300; +1EF4 0059 0323; +1EF5 0079 0323; +1EF6 0059 0309; +1EF7 0079 0309; +1EF8 0059 0303; +1EF9 0079 0303; +1F00 03B1 0313; +1F01 03B1 0314; +1F02 1F00 0300; +1F03 1F01 0300; +1F04 1F00 0301; +1F05 1F01 0301; +1F06 1F00 0342; +1F07 1F01 0342; +1F08 0391 0313; +1F09 0391 0314; +1F0A 1F08 0300; +1F0B 1F09 0300; +1F0C 1F08 0301; +1F0D 1F09 0301; +1F0E 1F08 0342; +1F0F 1F09 0342; +1F10 03B5 0313; +1F11 03B5 0314; +1F12 1F10 0300; +1F13 1F11 0300; +1F14 1F10 0301; +1F15 1F11 0301; +1F18 0395 0313; +1F19 0395 0314; +1F1A 1F18 0300; +1F1B 1F19 0300; +1F1C 1F18 0301; +1F1D 1F19 0301; +1F20 03B7 0313; +1F21 03B7 0314; +1F22 1F20 0300; +1F23 1F21 0300; +1F24 1F20 0301; +1F25 1F21 0301; +1F26 1F20 0342; +1F27 1F21 0342; +1F28 0397 0313; +1F29 0397 0314; +1F2A 1F28 0300; +1F2B 1F29 0300; +1F2C 1F28 0301; +1F2D 1F29 0301; +1F2E 1F28 0342; +1F2F 1F29 0342; +1F30 03B9 0313; +1F31 03B9 0314; +1F32 1F30 0300; +1F33 1F31 0300; +1F34 1F30 0301; +1F35 1F31 0301; +1F36 1F30 0342; +1F37 1F31 0342; +1F38 0399 0313; +1F39 0399 0314; +1F3A 1F38 0300; +1F3B 1F39 0300; +1F3C 1F38 0301; +1F3D 1F39 0301; +1F3E 1F38 0342; +1F3F 1F39 0342; +1F40 03BF 0313; +1F41 03BF 0314; +1F42 1F40 0300; +1F43 1F41 0300; +1F44 1F40 0301; +1F45 1F41 0301; +1F48 039F 0313; +1F49 039F 0314; +1F4A 1F48 0300; +1F4B 1F49 0300; +1F4C 1F48 0301; +1F4D 1F49 0301; +1F50 03C5 0313; +1F51 03C5 0314; +1F52 1F50 0300; +1F53 1F51 0300; +1F54 1F50 0301; +1F55 1F51 0301; +1F56 1F50 0342; +1F57 1F51 0342; +1F59 03A5 0314; +1F5B 1F59 0300; +1F5D 1F59 0301; +1F5F 1F59 0342; +1F60 03C9 0313; +1F61 03C9 0314; +1F62 1F60 0300; +1F63 1F61 0300; +1F64 1F60 0301; +1F65 1F61 0301; +1F66 1F60 0342; +1F67 1F61 0342; +1F68 03A9 0313; +1F69 03A9 0314; +1F6A 1F68 0300; +1F6B 1F69 0300; +1F6C 1F68 0301; +1F6D 1F69 0301; +1F6E 1F68 0342; +1F6F 1F69 0342; +1F70 03B1 0300; +1F71 03AC 0000; +1F72 03B5 0300; +1F73 03AD 0000; +1F74 03B7 0300; +1F75 03AE 0000; +1F76 03B9 0300; +1F77 03AF 0000; +1F78 03BF 0300; +1F79 03CC 0000; +1F7A 03C5 0300; +1F7B 03CD 0000; +1F7C 03C9 0300; +1F7D 03CE 0000; +1F80 1F00 0345; +1F81 1F01 0345; +1F82 1F02 0345; +1F83 1F03 0345; +1F84 1F04 0345; +1F85 1F05 0345; +1F86 1F06 0345; +1F87 1F07 0345; +1F88 1F08 0345; +1F89 1F09 0345; +1F8A 1F0A 0345; +1F8B 1F0B 0345; +1F8C 1F0C 0345; +1F8D 1F0D 0345; +1F8E 1F0E 0345; +1F8F 1F0F 0345; +1F90 1F20 0345; +1F91 1F21 0345; +1F92 1F22 0345; +1F93 1F23 0345; +1F94 1F24 0345; +1F95 1F25 0345; +1F96 1F26 0345; +1F97 1F27 0345; +1F98 1F28 0345; +1F99 1F29 0345; +1F9A 1F2A 0345; +1F9B 1F2B 0345; +1F9C 1F2C 0345; +1F9D 1F2D 0345; +1F9E 1F2E 0345; +1F9F 1F2F 0345; +1FA0 1F60 0345; +1FA1 1F61 0345; +1FA2 1F62 0345; +1FA3 1F63 0345; +1FA4 1F64 0345; +1FA5 1F65 0345; +1FA6 1F66 0345; +1FA7 1F67 0345; +1FA8 1F68 0345; +1FA9 1F69 0345; +1FAA 1F6A 0345; +1FAB 1F6B 0345; +1FAC 1F6C 0345; +1FAD 1F6D 0345; +1FAE 1F6E 0345; +1FAF 1F6F 0345; +1FB0 03B1 0306; +1FB1 03B1 0304; +1FB2 1F70 0345; +1FB3 03B1 0345; +1FB4 03AC 0345; +1FB6 03B1 0342; +1FB7 1FB6 0345; +1FB8 0391 0306; +1FB9 0391 0304; +1FBA 0391 0300; +1FBB 0386 0000; +1FBC 0391 0345; +1FBE 03B9 0000; +1FC1 00A8 0342; +1FC2 1F74 0345; +1FC3 03B7 0345; +1FC4 03AE 0345; +1FC6 03B7 0342; +1FC7 1FC6 0345; +1FC8 0395 0300; +1FC9 0388 0000; +1FCA 0397 0300; +1FCB 0389 0000; +1FCC 0397 0345; +1FCD 1FBF 0300; +1FCE 1FBF 0301; +1FCF 1FBF 0342; +1FD0 03B9 0306; +1FD1 03B9 0304; +1FD2 03CA 0300; +1FD3 0390 0000; +1FD6 03B9 0342; +1FD7 03CA 0342; +1FD8 0399 0306; +1FD9 0399 0304; +1FDA 0399 0300; +1FDB 038A 0000; +1FDD 1FFE 0300; +1FDE 1FFE 0301; +1FDF 1FFE 0342; +1FE0 03C5 0306; +1FE1 03C5 0304; +1FE2 03CB 0300; +1FE3 03B0 0000; +1FE4 03C1 0313; +1FE5 03C1 0314; +1FE6 03C5 0342; +1FE7 03CB 0342; +1FE8 03A5 0306; +1FE9 03A5 0304; +1FEA 03A5 0300; +1FEB 038E 0000; +1FEC 03A1 0314; +1FED 00A8 0300; +1FEE 0385 0000; +1FEF 0060 0000; +1FF2 1F7C 0345; +1FF3 03C9 0345; +1FF4 03CE 0345; +1FF6 03C9 0342; +1FF7 1FF6 0345; +1FF8 039F 0300; +1FF9 038C 0000; +1FFA 03A9 0300; +1FFB 038F 0000; +1FFC 03A9 0345; +1FFD 00B4 0000; +2000 2002 0000; +2001 2003 0000; +2126 03A9 0000; +212A 004B 0000; +212B 00C5 0000; +219A 2190 0338; +219B 2192 0338; +21AE 2194 0338; +21CD 21D0 0338; +21CE 21D4 0338; +21CF 21D2 0338; +2204 2203 0338; +2209 2208 0338; +220C 220B 0338; +2224 2223 0338; +2226 2225 0338; +2241 223C 0338; +2244 2243 0338; +2247 2245 0338; +2249 2248 0338; +2260 003D 0338; +2262 2261 0338; +226D 224D 0338; +226E 003C 0338; +226F 003E 0338; +2270 2264 0338; +2271 2265 0338; +2274 2272 0338; +2275 2273 0338; +2278 2276 0338; +2279 2277 0338; +2280 227A 0338; +2281 227B 0338; +2284 2282 0338; +2285 2283 0338; +2288 2286 0338; +2289 2287 0338; +22AC 22A2 0338; +22AD 22A8 0338; +22AE 22A9 0338; +22AF 22AB 0338; +22E0 227C 0338; +22E1 227D 0338; +22E2 2291 0338; +22E3 2292 0338; +22EA 22B2 0338; +22EB 22B3 0338; +22EC 22B4 0338; +22ED 22B5 0338; +2329 3008 0000; +232A 3009 0000; +304C 304B 3099; +304E 304D 3099; +3050 304F 3099; +3052 3051 3099; +3054 3053 3099; +3056 3055 3099; +3058 3057 3099; +305A 3059 3099; +305C 305B 3099; +305E 305D 3099; +3060 305F 3099; +3062 3061 3099; +3065 3064 3099; +3067 3066 3099; +3069 3068 3099; +3070 306F 3099; +3071 306F 309A; +3073 3072 3099; +3074 3072 309A; +3076 3075 3099; +3077 3075 309A; +3079 3078 3099; +307A 3078 309A; +307C 307B 3099; +307D 307B 309A; +3094 3046 3099; +309E 309D 3099; +30AC 30AB 3099; +30AE 30AD 3099; +30B0 30AF 3099; +30B2 30B1 3099; +30B4 30B3 3099; +30B6 30B5 3099; +30B8 30B7 3099; +30BA 30B9 3099; +30BC 30BB 3099; +30BE 30BD 3099; +30C0 30BF 3099; +30C2 30C1 3099; +30C5 30C4 3099; +30C7 30C6 3099; +30C9 30C8 3099; +30D0 30CF 3099; +30D1 30CF 309A; +30D3 30D2 3099; +30D4 30D2 309A; +30D6 30D5 3099; +30D7 30D5 309A; +30D9 30D8 3099; +30DA 30D8 309A; +30DC 30DB 3099; +30DD 30DB 309A; +30F4 30A6 3099; +30F7 30EF 3099; +30F8 30F0 3099; +30F9 30F1 3099; +30FA 30F2 3099; +30FE 30FD 3099; +F900 8C48 0000; +F901 66F4 0000; +F902 8ECA 0000; +F903 8CC8 0000; +F904 6ED1 0000; +F905 4E32 0000; +F906 53E5 0000; +F907 9F9C 0000; +F908 9F9C 0000; +F909 5951 0000; +F90A 91D1 0000; +F90B 5587 0000; +F90C 5948 0000; +F90D 61F6 0000; +F90E 7669 0000; +F90F 7F85 0000; +F910 863F 0000; +F911 87BA 0000; +F912 88F8 0000; +F913 908F 0000; +F914 6A02 0000; +F915 6D1B 0000; +F916 70D9 0000; +F917 73DE 0000; +F918 843D 0000; +F919 916A 0000; +F91A 99F1 0000; +F91B 4E82 0000; +F91C 5375 0000; +F91D 6B04 0000; +F91E 721B 0000; +F91F 862D 0000; +F920 9E1E 0000; +F921 5D50 0000; +F922 6FEB 0000; +F923 85CD 0000; +F924 8964 0000; +F925 62C9 0000; +F926 81D8 0000; +F927 881F 0000; +F928 5ECA 0000; +F929 6717 0000; +F92A 6D6A 0000; +F92B 72FC 0000; +F92C 90CE 0000; +F92D 4F86 0000; +F92E 51B7 0000; +F92F 52DE 0000; +F930 64C4 0000; +F931 6AD3 0000; +F932 7210 0000; +F933 76E7 0000; +F934 8001 0000; +F935 8606 0000; +F936 865C 0000; +F937 8DEF 0000; +F938 9732 0000; +F939 9B6F 0000; +F93A 9DFA 0000; +F93B 788C 0000; +F93C 797F 0000; +F93D 7DA0 0000; +F93E 83C9 0000; +F93F 9304 0000; +F940 9E7F 0000; +F941 8AD6 0000; +F942 58DF 0000; +F943 5F04 0000; +F944 7C60 0000; +F945 807E 0000; +F946 7262 0000; +F947 78CA 0000; +F948 8CC2 0000; +F949 96F7 0000; +F94A 58D8 0000; +F94B 5C62 0000; +F94C 6A13 0000; +F94D 6DDA 0000; +F94E 6F0F 0000; +F94F 7D2F 0000; +F950 7E37 0000; +F951 96FB 0000; +F952 52D2 0000; +F953 808B 0000; +F954 51DC 0000; +F955 51CC 0000; +F956 7A1C 0000; +F957 7DBE 0000; +F958 83F1 0000; +F959 9675 0000; +F95A 8B80 0000; +F95B 62CF 0000; +F95C 6A02 0000; +F95D 8AFE 0000; +F95E 4E39 0000; +F95F 5BE7 0000; +F960 6012 0000; +F961 7387 0000; +F962 7570 0000; +F963 5317 0000; +F964 78FB 0000; +F965 4FBF 0000; +F966 5FA9 0000; +F967 4E0D 0000; +F968 6CCC 0000; +F969 6578 0000; +F96A 7D22 0000; +F96B 53C3 0000; +F96C 585E 0000; +F96D 7701 0000; +F96E 8449 0000; +F96F 8AAA 0000; +F970 6BBA 0000; +F971 8FB0 0000; +F972 6C88 0000; +F973 62FE 0000; +F974 82E5 0000; +F975 63A0 0000; +F976 7565 0000; +F977 4EAE 0000; +F978 5169 0000; +F979 51C9 0000; +F97A 6881 0000; +F97B 7CE7 0000; +F97C 826F 0000; +F97D 8AD2 0000; +F97E 91CF 0000; +F97F 52F5 0000; +F980 5442 0000; +F981 5973 0000; +F982 5EEC 0000; +F983 65C5 0000; +F984 6FFE 0000; +F985 792A 0000; +F986 95AD 0000; +F987 9A6A 0000; +F988 9E97 0000; +F989 9ECE 0000; +F98A 529B 0000; +F98B 66C6 0000; +F98C 6B77 0000; +F98D 8F62 0000; +F98E 5E74 0000; +F98F 6190 0000; +F990 6200 0000; +F991 649A 0000; +F992 6F23 0000; +F993 7149 0000; +F994 7489 0000; +F995 79CA 0000; +F996 7DF4 0000; +F997 806F 0000; +F998 8F26 0000; +F999 84EE 0000; +F99A 9023 0000; +F99B 934A 0000; +F99C 5217 0000; +F99D 52A3 0000; +F99E 54BD 0000; +F99F 70C8 0000; +F9A0 88C2 0000; +F9A1 8AAA 0000; +F9A2 5EC9 0000; +F9A3 5FF5 0000; +F9A4 637B 0000; +F9A5 6BAE 0000; +F9A6 7C3E 0000; +F9A7 7375 0000; +F9A8 4EE4 0000; +F9A9 56F9 0000; +F9AA 5BE7 0000; +F9AB 5DBA 0000; +F9AC 601C 0000; +F9AD 73B2 0000; +F9AE 7469 0000; +F9AF 7F9A 0000; +F9B0 8046 0000; +F9B1 9234 0000; +F9B2 96F6 0000; +F9B3 9748 0000; +F9B4 9818 0000; +F9B5 4F8B 0000; +F9B6 79AE 0000; +F9B7 91B4 0000; +F9B8 96B8 0000; +F9B9 60E1 0000; +F9BA 4E86 0000; +F9BB 50DA 0000; +F9BC 5BEE 0000; +F9BD 5C3F 0000; +F9BE 6599 0000; +F9BF 6A02 0000; +F9C0 71CE 0000; +F9C1 7642 0000; +F9C2 84FC 0000; +F9C3 907C 0000; +F9C4 9F8D 0000; +F9C5 6688 0000; +F9C6 962E 0000; +F9C7 5289 0000; +F9C8 677B 0000; +F9C9 67F3 0000; +F9CA 6D41 0000; +F9CB 6E9C 0000; +F9CC 7409 0000; +F9CD 7559 0000; +F9CE 786B 0000; +F9CF 7D10 0000; +F9D0 985E 0000; +F9D1 516D 0000; +F9D2 622E 0000; +F9D3 9678 0000; +F9D4 502B 0000; +F9D5 5D19 0000; +F9D6 6DEA 0000; +F9D7 8F2A 0000; +F9D8 5F8B 0000; +F9D9 6144 0000; +F9DA 6817 0000; +F9DB 7387 0000; +F9DC 9686 0000; +F9DD 5229 0000; +F9DE 540F 0000; +F9DF 5C65 0000; +F9E0 6613 0000; +F9E1 674E 0000; +F9E2 68A8 0000; +F9E3 6CE5 0000; +F9E4 7406 0000; +F9E5 75E2 0000; +F9E6 7F79 0000; +F9E7 88CF 0000; +F9E8 88E1 0000; +F9E9 91CC 0000; +F9EA 96E2 0000; +F9EB 533F 0000; +F9EC 6EBA 0000; +F9ED 541D 0000; +F9EE 71D0 0000; +F9EF 7498 0000; +F9F0 85FA 0000; +F9F1 96A3 0000; +F9F2 9C57 0000; +F9F3 9E9F 0000; +F9F4 6797 0000; +F9F5 6DCB 0000; +F9F6 81E8 0000; +F9F7 7ACB 0000; +F9F8 7B20 0000; +F9F9 7C92 0000; +F9FA 72C0 0000; +F9FB 7099 0000; +F9FC 8B58 0000; +F9FD 4EC0 0000; +F9FE 8336 0000; +F9FF 523A 0000; +FA00 5207 0000; +FA01 5EA6 0000; +FA02 62D3 0000; +FA03 7CD6 0000; +FA04 5B85 0000; +FA05 6D1E 0000; +FA06 66B4 0000; +FA07 8F3B 0000; +FA08 884C 0000; +FA09 964D 0000; +FA0A 898B 0000; +FA0B 5ED3 0000; +FA0C 5140 0000; +FA0D 55C0 0000; +FA10 585A 0000; +FA12 6674 0000; +FA15 51DE 0000; +FA16 732A 0000; +FA17 76CA 0000; +FA18 793C 0000; +FA19 795E 0000; +FA1A 7965 0000; +FA1B 798F 0000; +FA1C 9756 0000; +FA1D 7CBE 0000; +FA1E 7FBD 0000; +FA20 8612 0000; +FA22 8AF8 0000; +FA25 9038 0000; +FA26 90FD 0000; +FA2A 98EF 0000; +FA2B 98FC 0000; +FA2C 9928 0000; +FA2D 9DB4 0000; +FB1D 05D9 05B4; +FB1F 05F2 05B7; +FB2A 05E9 05C1; +FB2B 05E9 05C2; +FB2C FB49 05C1; +FB2D FB49 05C2; +FB2E 05D0 05B7; +FB2F 05D0 05B8; +FB30 05D0 05BC; +FB31 05D1 05BC; +FB32 05D2 05BC; +FB33 05D3 05BC; +FB34 05D4 05BC; +FB35 05D5 05BC; +FB36 05D6 05BC; +FB38 05D8 05BC; +FB39 05D9 05BC; +FB3A 05DA 05BC; +FB3B 05DB 05BC; +FB3C 05DC 05BC; +FB3E 05DE 05BC; +FB40 05E0 05BC; +FB41 05E1 05BC; +FB43 05E3 05BC; +FB44 05E4 05BC; +FB46 05E6 05BC; +FB47 05E7 05BC; +FB48 05E8 05BC; +FB49 05E9 05BC; +FB4A 05EA 05BC; +FB4B 05D5 05B9; +FB4C 05D1 05BF; +FB4D 05DB 05BF; +FB4E 05E4 05BF; diff --git a/data/uni-nfkd.txt b/data/uni-nfkd.txt new file mode 100644 index 000000000..8dc828e45 --- /dev/null +++ b/data/uni-nfkd.txt @@ -0,0 +1,3486 @@ +# uni-nfkd.txt - Unicode decomposition mapping +00A0 0020 0000;; +00A8 0020 0308;; +00AA 0061 0000;; +00AF 0020 0304;; +00B2 0032 0000;; +00B3 0033 0000;; +00B4 0020 0301;; +00B5 03BC 0000;; +00B8 0020 0327;; +00B9 0031 0000;; +00BA 006F 0000;; +00BC 0031 2044;; +00BD 0031 2044;; +00BE 0033 2044;; +00C0 0041 0300; +00C1 0041 0301; +00C2 0041 0302; +00C3 0041 0303; +00C4 0041 0308; +00C5 0041 030A; +00C7 0043 0327; +00C8 0045 0300; +00C9 0045 0301; +00CA 0045 0302; +00CB 0045 0308; +00CC 0049 0300; +00CD 0049 0301; +00CE 0049 0302; +00CF 0049 0308; +00D1 004E 0303; +00D2 004F 0300; +00D3 004F 0301; +00D4 004F 0302; +00D5 004F 0303; +00D6 004F 0308; +00D9 0055 0300; +00DA 0055 0301; +00DB 0055 0302; +00DC 0055 0308; +00DD 0059 0301; +00E0 0061 0300; +00E1 0061 0301; +00E2 0061 0302; +00E3 0061 0303; +00E4 0061 0308; +00E5 0061 030A; +00E7 0063 0327; +00E8 0065 0300; +00E9 0065 0301; +00EA 0065 0302; +00EB 0065 0308; +00EC 0069 0300; +00ED 0069 0301; +00EE 0069 0302; +00EF 0069 0308; +00F1 006E 0303; +00F2 006F 0300; +00F3 006F 0301; +00F4 006F 0302; +00F5 006F 0303; +00F6 006F 0308; +00F9 0075 0300; +00FA 0075 0301; +00FB 0075 0302; +00FC 0075 0308; +00FD 0079 0301; +00FF 0079 0308; +0100 0041 0304; +0101 0061 0304; +0102 0041 0306; +0103 0061 0306; +0104 0041 0328; +0105 0061 0328; +0106 0043 0301; +0107 0063 0301; +0108 0043 0302; +0109 0063 0302; +010A 0043 0307; +010B 0063 0307; +010C 0043 030C; +010D 0063 030C; +010E 0044 030C; +010F 0064 030C; +0112 0045 0304; +0113 0065 0304; +0114 0045 0306; +0115 0065 0306; +0116 0045 0307; +0117 0065 0307; +0118 0045 0328; +0119 0065 0328; +011A 0045 030C; +011B 0065 030C; +011C 0047 0302; +011D 0067 0302; +011E 0047 0306; +011F 0067 0306; +0120 0047 0307; +0121 0067 0307; +0122 0047 0327; +0123 0067 0327; +0124 0048 0302; +0125 0068 0302; +0128 0049 0303; +0129 0069 0303; +012A 0049 0304; +012B 0069 0304; +012C 0049 0306; +012D 0069 0306; +012E 0049 0328; +012F 0069 0328; +0130 0049 0307; +0132 0049 004A;; +0133 0069 006A;; +0134 004A 0302; +0135 006A 0302; +0136 004B 0327; +0137 006B 0327; +0139 004C 0301; +013A 006C 0301; +013B 004C 0327; +013C 006C 0327; +013D 004C 030C; +013E 006C 030C; +013F 004C 00B7;; +0140 006C 00B7;; +0143 004E 0301; +0144 006E 0301; +0145 004E 0327; +0146 006E 0327; +0147 004E 030C; +0148 006E 030C; +0149 02BC 006E;; +014C 004F 0304; +014D 006F 0304; +014E 004F 0306; +014F 006F 0306; +0150 004F 030B; +0151 006F 030B; +0154 0052 0301; +0155 0072 0301; +0156 0052 0327; +0157 0072 0327; +0158 0052 030C; +0159 0072 030C; +015A 0053 0301; +015B 0073 0301; +015C 0053 0302; +015D 0073 0302; +015E 0053 0327; +015F 0073 0327; +0160 0053 030C; +0161 0073 030C; +0162 0054 0327; +0163 0074 0327; +0164 0054 030C; +0165 0074 030C; +0168 0055 0303; +0169 0075 0303; +016A 0055 0304; +016B 0075 0304; +016C 0055 0306; +016D 0075 0306; +016E 0055 030A; +016F 0075 030A; +0170 0055 030B; +0171 0075 030B; +0172 0055 0328; +0173 0075 0328; +0174 0057 0302; +0175 0077 0302; +0176 0059 0302; +0177 0079 0302; +0178 0059 0308; +0179 005A 0301; +017A 007A 0301; +017B 005A 0307; +017C 007A 0307; +017D 005A 030C; +017E 007A 030C; +017F 0073 0000;; +01A0 004F 031B; +01A1 006F 031B; +01AF 0055 031B; +01B0 0075 031B; +01C4 0044 017D;; +01C5 0044 017E;; +01C6 0064 017E;; +01C7 004C 004A;; +01C8 004C 006A;; +01C9 006C 006A;; +01CA 004E 004A;; +01CB 004E 006A;; +01CC 006E 006A;; +01CD 0041 030C; +01CE 0061 030C; +01CF 0049 030C; +01D0 0069 030C; +01D1 004F 030C; +01D2 006F 030C; +01D3 0055 030C; +01D4 0075 030C; +01D5 00DC 0304; +01D6 00FC 0304; +01D7 00DC 0301; +01D8 00FC 0301; +01D9 00DC 030C; +01DA 00FC 030C; +01DB 00DC 0300; +01DC 00FC 0300; +01DE 00C4 0304; +01DF 00E4 0304; +01E0 0226 0304; +01E1 0227 0304; +01E2 00C6 0304; +01E3 00E6 0304; +01E6 0047 030C; +01E7 0067 030C; +01E8 004B 030C; +01E9 006B 030C; +01EA 004F 0328; +01EB 006F 0328; +01EC 01EA 0304; +01ED 01EB 0304; +01EE 01B7 030C; +01EF 0292 030C; +01F0 006A 030C; +01F1 0044 005A;; +01F2 0044 007A;; +01F3 0064 007A;; +01F4 0047 0301; +01F5 0067 0301; +01F8 004E 0300; +01F9 006E 0300; +01FA 00C5 0301; +01FB 00E5 0301; +01FC 00C6 0301; +01FD 00E6 0301; +01FE 00D8 0301; +01FF 00F8 0301; +0200 0041 030F; +0201 0061 030F; +0202 0041 0311; +0203 0061 0311; +0204 0045 030F; +0205 0065 030F; +0206 0045 0311; +0207 0065 0311; +0208 0049 030F; +0209 0069 030F; +020A 0049 0311; +020B 0069 0311; +020C 004F 030F; +020D 006F 030F; +020E 004F 0311; +020F 006F 0311; +0210 0052 030F; +0211 0072 030F; +0212 0052 0311; +0213 0072 0311; +0214 0055 030F; +0215 0075 030F; +0216 0055 0311; +0217 0075 0311; +0218 0053 0326; +0219 0073 0326; +021A 0054 0326; +021B 0074 0326; +021E 0048 030C; +021F 0068 030C; +0226 0041 0307; +0227 0061 0307; +0228 0045 0327; +0229 0065 0327; +022A 00D6 0304; +022B 00F6 0304; +022C 00D5 0304; +022D 00F5 0304; +022E 004F 0307; +022F 006F 0307; +0230 022E 0304; +0231 022F 0304; +0232 0059 0304; +0233 0079 0304; +02B0 0068 0000;; +02B1 0266 0000;; +02B2 006A 0000;; +02B3 0072 0000;; +02B4 0279 0000;; +02B5 027B 0000;; +02B6 0281 0000;; +02B7 0077 0000;; +02B8 0079 0000;; +02D8 0020 0306;; +02D9 0020 0307;; +02DA 0020 030A;; +02DB 0020 0328;; +02DC 0020 0303;; +02DD 0020 030B;; +02E0 0263 0000;; +02E1 006C 0000;; +02E2 0073 0000;; +02E3 0078 0000;; +02E4 0295 0000;; +0340 0300 0000; +0341 0301 0000; +0343 0313 0000; +0344 0308 0301; +0374 02B9 0000; +037A 0020 0345;; +037E 003B 0000; +0384 0020 0301;; +0385 00A8 0301; +0386 0391 0301; +0387 00B7 0000; +0388 0395 0301; +0389 0397 0301; +038A 0399 0301; +038C 039F 0301; +038E 03A5 0301; +038F 03A9 0301; +0390 03CA 0301; +03AA 0399 0308; +03AB 03A5 0308; +03AC 03B1 0301; +03AD 03B5 0301; +03AE 03B7 0301; +03AF 03B9 0301; +03B0 03CB 0301; +03CA 03B9 0308; +03CB 03C5 0308; +03CC 03BF 0301; +03CD 03C5 0301; +03CE 03C9 0301; +03D0 03B2 0000;; +03D1 03B8 0000;; +03D2 03A5 0000;; +03D3 03D2 0301; +03D4 03D2 0308; +03D5 03C6 0000;; +03D6 03C0 0000;; +03F0 03BA 0000;; +03F1 03C1 0000;; +03F2 03C2 0000;; +03F4 0398 0000;; +03F5 03B5 0000;; +0400 0415 0300; +0401 0415 0308; +0403 0413 0301; +0407 0406 0308; +040C 041A 0301; +040D 0418 0300; +040E 0423 0306; +0419 0418 0306; +0439 0438 0306; +0450 0435 0300; +0451 0435 0308; +0453 0433 0301; +0457 0456 0308; +045C 043A 0301; +045D 0438 0300; +045E 0443 0306; +0476 0474 030F; +0477 0475 030F; +04C1 0416 0306; +04C2 0436 0306; +04D0 0410 0306; +04D1 0430 0306; +04D2 0410 0308; +04D3 0430 0308; +04D6 0415 0306; +04D7 0435 0306; +04DA 04D8 0308; +04DB 04D9 0308; +04DC 0416 0308; +04DD 0436 0308; +04DE 0417 0308; +04DF 0437 0308; +04E2 0418 0304; +04E3 0438 0304; +04E4 0418 0308; +04E5 0438 0308; +04E6 041E 0308; +04E7 043E 0308; +04EA 04E8 0308; +04EB 04E9 0308; +04EC 042D 0308; +04ED 044D 0308; +04EE 0423 0304; +04EF 0443 0304; +04F0 0423 0308; +04F1 0443 0308; +04F2 0423 030B; +04F3 0443 030B; +04F4 0427 0308; +04F5 0447 0308; +04F8 042B 0308; +04F9 044B 0308; +0587 0565 0582;; +0622 0627 0653; +0623 0627 0654; +0624 0648 0654; +0625 0627 0655; +0626 064A 0654; +0675 0627 0674;; +0676 0648 0674;; +0677 06C7 0674;; +0678 064A 0674;; +06C0 06D5 0654; +06C2 06C1 0654; +06D3 06D2 0654; +0929 0928 093C; +0931 0930 093C; +0934 0933 093C; +0958 0915 093C; +0959 0916 093C; +095A 0917 093C; +095B 091C 093C; +095C 0921 093C; +095D 0922 093C; +095E 092B 093C; +095F 092F 093C; +09CB 09C7 09BE; +09CC 09C7 09D7; +09DC 09A1 09BC; +09DD 09A2 09BC; +09DF 09AF 09BC; +0A33 0A32 0A3C; +0A36 0A38 0A3C; +0A59 0A16 0A3C; +0A5A 0A17 0A3C; +0A5B 0A1C 0A3C; +0A5E 0A2B 0A3C; +0B48 0B47 0B56; +0B4B 0B47 0B3E; +0B4C 0B47 0B57; +0B5C 0B21 0B3C; +0B5D 0B22 0B3C; +0B94 0B92 0BD7; +0BCA 0BC6 0BBE; +0BCB 0BC7 0BBE; +0BCC 0BC6 0BD7; +0C48 0C46 0C56; +0CC0 0CBF 0CD5; +0CC7 0CC6 0CD5; +0CC8 0CC6 0CD6; +0CCA 0CC6 0CC2; +0CCB 0CCA 0CD5; +0D4A 0D46 0D3E; +0D4B 0D47 0D3E; +0D4C 0D46 0D57; +0DDA 0DD9 0DCA; +0DDC 0DD9 0DCF; +0DDD 0DDC 0DCA; +0DDE 0DD9 0DDF; +0E33 0E4D 0E32;; +0EB3 0ECD 0EB2;; +0EDC 0EAB 0E99;; +0EDD 0EAB 0EA1;; +0F0C 0F0B 0000;; +0F43 0F42 0FB7; +0F4D 0F4C 0FB7; +0F52 0F51 0FB7; +0F57 0F56 0FB7; +0F5C 0F5B 0FB7; +0F69 0F40 0FB5; +0F73 0F71 0F72; +0F75 0F71 0F74; +0F76 0FB2 0F80; +0F77 0FB2 0F81;; +0F78 0FB3 0F80; +0F79 0FB3 0F81;; +0F81 0F71 0F80; +0F93 0F92 0FB7; +0F9D 0F9C 0FB7; +0FA2 0FA1 0FB7; +0FA7 0FA6 0FB7; +0FAC 0FAB 0FB7; +0FB9 0F90 0FB5; +1026 1025 102E; +1E00 0041 0325; +1E01 0061 0325; +1E02 0042 0307; +1E03 0062 0307; +1E04 0042 0323; +1E05 0062 0323; +1E06 0042 0331; +1E07 0062 0331; +1E08 00C7 0301; +1E09 00E7 0301; +1E0A 0044 0307; +1E0B 0064 0307; +1E0C 0044 0323; +1E0D 0064 0323; +1E0E 0044 0331; +1E0F 0064 0331; +1E10 0044 0327; +1E11 0064 0327; +1E12 0044 032D; +1E13 0064 032D; +1E14 0112 0300; +1E15 0113 0300; +1E16 0112 0301; +1E17 0113 0301; +1E18 0045 032D; +1E19 0065 032D; +1E1A 0045 0330; +1E1B 0065 0330; +1E1C 0228 0306; +1E1D 0229 0306; +1E1E 0046 0307; +1E1F 0066 0307; +1E20 0047 0304; +1E21 0067 0304; +1E22 0048 0307; +1E23 0068 0307; +1E24 0048 0323; +1E25 0068 0323; +1E26 0048 0308; +1E27 0068 0308; +1E28 0048 0327; +1E29 0068 0327; +1E2A 0048 032E; +1E2B 0068 032E; +1E2C 0049 0330; +1E2D 0069 0330; +1E2E 00CF 0301; +1E2F 00EF 0301; +1E30 004B 0301; +1E31 006B 0301; +1E32 004B 0323; +1E33 006B 0323; +1E34 004B 0331; +1E35 006B 0331; +1E36 004C 0323; +1E37 006C 0323; +1E38 1E36 0304; +1E39 1E37 0304; +1E3A 004C 0331; +1E3B 006C 0331; +1E3C 004C 032D; +1E3D 006C 032D; +1E3E 004D 0301; +1E3F 006D 0301; +1E40 004D 0307; +1E41 006D 0307; +1E42 004D 0323; +1E43 006D 0323; +1E44 004E 0307; +1E45 006E 0307; +1E46 004E 0323; +1E47 006E 0323; +1E48 004E 0331; +1E49 006E 0331; +1E4A 004E 032D; +1E4B 006E 032D; +1E4C 00D5 0301; +1E4D 00F5 0301; +1E4E 00D5 0308; +1E4F 00F5 0308; +1E50 014C 0300; +1E51 014D 0300; +1E52 014C 0301; +1E53 014D 0301; +1E54 0050 0301; +1E55 0070 0301; +1E56 0050 0307; +1E57 0070 0307; +1E58 0052 0307; +1E59 0072 0307; +1E5A 0052 0323; +1E5B 0072 0323; +1E5C 1E5A 0304; +1E5D 1E5B 0304; +1E5E 0052 0331; +1E5F 0072 0331; +1E60 0053 0307; +1E61 0073 0307; +1E62 0053 0323; +1E63 0073 0323; +1E64 015A 0307; +1E65 015B 0307; +1E66 0160 0307; +1E67 0161 0307; +1E68 1E62 0307; +1E69 1E63 0307; +1E6A 0054 0307; +1E6B 0074 0307; +1E6C 0054 0323; +1E6D 0074 0323; +1E6E 0054 0331; +1E6F 0074 0331; +1E70 0054 032D; +1E71 0074 032D; +1E72 0055 0324; +1E73 0075 0324; +1E74 0055 0330; +1E75 0075 0330; +1E76 0055 032D; +1E77 0075 032D; +1E78 0168 0301; +1E79 0169 0301; +1E7A 016A 0308; +1E7B 016B 0308; +1E7C 0056 0303; +1E7D 0076 0303; +1E7E 0056 0323; +1E7F 0076 0323; +1E80 0057 0300; +1E81 0077 0300; +1E82 0057 0301; +1E83 0077 0301; +1E84 0057 0308; +1E85 0077 0308; +1E86 0057 0307; +1E87 0077 0307; +1E88 0057 0323; +1E89 0077 0323; +1E8A 0058 0307; +1E8B 0078 0307; +1E8C 0058 0308; +1E8D 0078 0308; +1E8E 0059 0307; +1E8F 0079 0307; +1E90 005A 0302; +1E91 007A 0302; +1E92 005A 0323; +1E93 007A 0323; +1E94 005A 0331; +1E95 007A 0331; +1E96 0068 0331; +1E97 0074 0308; +1E98 0077 030A; +1E99 0079 030A; +1E9A 0061 02BE;; +1E9B 017F 0307; +1EA0 0041 0323; +1EA1 0061 0323; +1EA2 0041 0309; +1EA3 0061 0309; +1EA4 00C2 0301; +1EA5 00E2 0301; +1EA6 00C2 0300; +1EA7 00E2 0300; +1EA8 00C2 0309; +1EA9 00E2 0309; +1EAA 00C2 0303; +1EAB 00E2 0303; +1EAC 1EA0 0302; +1EAD 1EA1 0302; +1EAE 0102 0301; +1EAF 0103 0301; +1EB0 0102 0300; +1EB1 0103 0300; +1EB2 0102 0309; +1EB3 0103 0309; +1EB4 0102 0303; +1EB5 0103 0303; +1EB6 1EA0 0306; +1EB7 1EA1 0306; +1EB8 0045 0323; +1EB9 0065 0323; +1EBA 0045 0309; +1EBB 0065 0309; +1EBC 0045 0303; +1EBD 0065 0303; +1EBE 00CA 0301; +1EBF 00EA 0301; +1EC0 00CA 0300; +1EC1 00EA 0300; +1EC2 00CA 0309; +1EC3 00EA 0309; +1EC4 00CA 0303; +1EC5 00EA 0303; +1EC6 1EB8 0302; +1EC7 1EB9 0302; +1EC8 0049 0309; +1EC9 0069 0309; +1ECA 0049 0323; +1ECB 0069 0323; +1ECC 004F 0323; +1ECD 006F 0323; +1ECE 004F 0309; +1ECF 006F 0309; +1ED0 00D4 0301; +1ED1 00F4 0301; +1ED2 00D4 0300; +1ED3 00F4 0300; +1ED4 00D4 0309; +1ED5 00F4 0309; +1ED6 00D4 0303; +1ED7 00F4 0303; +1ED8 1ECC 0302; +1ED9 1ECD 0302; +1EDA 01A0 0301; +1EDB 01A1 0301; +1EDC 01A0 0300; +1EDD 01A1 0300; +1EDE 01A0 0309; +1EDF 01A1 0309; +1EE0 01A0 0303; +1EE1 01A1 0303; +1EE2 01A0 0323; +1EE3 01A1 0323; +1EE4 0055 0323; +1EE5 0075 0323; +1EE6 0055 0309; +1EE7 0075 0309; +1EE8 01AF 0301; +1EE9 01B0 0301; +1EEA 01AF 0300; +1EEB 01B0 0300; +1EEC 01AF 0309; +1EED 01B0 0309; +1EEE 01AF 0303; +1EEF 01B0 0303; +1EF0 01AF 0323; +1EF1 01B0 0323; +1EF2 0059 0300; +1EF3 0079 0300; +1EF4 0059 0323; +1EF5 0079 0323; +1EF6 0059 0309; +1EF7 0079 0309; +1EF8 0059 0303; +1EF9 0079 0303; +1F00 03B1 0313; +1F01 03B1 0314; +1F02 1F00 0300; +1F03 1F01 0300; +1F04 1F00 0301; +1F05 1F01 0301; +1F06 1F00 0342; +1F07 1F01 0342; +1F08 0391 0313; +1F09 0391 0314; +1F0A 1F08 0300; +1F0B 1F09 0300; +1F0C 1F08 0301; +1F0D 1F09 0301; +1F0E 1F08 0342; +1F0F 1F09 0342; +1F10 03B5 0313; +1F11 03B5 0314; +1F12 1F10 0300; +1F13 1F11 0300; +1F14 1F10 0301; +1F15 1F11 0301; +1F18 0395 0313; +1F19 0395 0314; +1F1A 1F18 0300; +1F1B 1F19 0300; +1F1C 1F18 0301; +1F1D 1F19 0301; +1F20 03B7 0313; +1F21 03B7 0314; +1F22 1F20 0300; +1F23 1F21 0300; +1F24 1F20 0301; +1F25 1F21 0301; +1F26 1F20 0342; +1F27 1F21 0342; +1F28 0397 0313; +1F29 0397 0314; +1F2A 1F28 0300; +1F2B 1F29 0300; +1F2C 1F28 0301; +1F2D 1F29 0301; +1F2E 1F28 0342; +1F2F 1F29 0342; +1F30 03B9 0313; +1F31 03B9 0314; +1F32 1F30 0300; +1F33 1F31 0300; +1F34 1F30 0301; +1F35 1F31 0301; +1F36 1F30 0342; +1F37 1F31 0342; +1F38 0399 0313; +1F39 0399 0314; +1F3A 1F38 0300; +1F3B 1F39 0300; +1F3C 1F38 0301; +1F3D 1F39 0301; +1F3E 1F38 0342; +1F3F 1F39 0342; +1F40 03BF 0313; +1F41 03BF 0314; +1F42 1F40 0300; +1F43 1F41 0300; +1F44 1F40 0301; +1F45 1F41 0301; +1F48 039F 0313; +1F49 039F 0314; +1F4A 1F48 0300; +1F4B 1F49 0300; +1F4C 1F48 0301; +1F4D 1F49 0301; +1F50 03C5 0313; +1F51 03C5 0314; +1F52 1F50 0300; +1F53 1F51 0300; +1F54 1F50 0301; +1F55 1F51 0301; +1F56 1F50 0342; +1F57 1F51 0342; +1F59 03A5 0314; +1F5B 1F59 0300; +1F5D 1F59 0301; +1F5F 1F59 0342; +1F60 03C9 0313; +1F61 03C9 0314; +1F62 1F60 0300; +1F63 1F61 0300; +1F64 1F60 0301; +1F65 1F61 0301; +1F66 1F60 0342; +1F67 1F61 0342; +1F68 03A9 0313; +1F69 03A9 0314; +1F6A 1F68 0300; +1F6B 1F69 0300; +1F6C 1F68 0301; +1F6D 1F69 0301; +1F6E 1F68 0342; +1F6F 1F69 0342; +1F70 03B1 0300; +1F71 03AC 0000; +1F72 03B5 0300; +1F73 03AD 0000; +1F74 03B7 0300; +1F75 03AE 0000; +1F76 03B9 0300; +1F77 03AF 0000; +1F78 03BF 0300; +1F79 03CC 0000; +1F7A 03C5 0300; +1F7B 03CD 0000; +1F7C 03C9 0300; +1F7D 03CE 0000; +1F80 1F00 0345; +1F81 1F01 0345; +1F82 1F02 0345; +1F83 1F03 0345; +1F84 1F04 0345; +1F85 1F05 0345; +1F86 1F06 0345; +1F87 1F07 0345; +1F88 1F08 0345; +1F89 1F09 0345; +1F8A 1F0A 0345; +1F8B 1F0B 0345; +1F8C 1F0C 0345; +1F8D 1F0D 0345; +1F8E 1F0E 0345; +1F8F 1F0F 0345; +1F90 1F20 0345; +1F91 1F21 0345; +1F92 1F22 0345; +1F93 1F23 0345; +1F94 1F24 0345; +1F95 1F25 0345; +1F96 1F26 0345; +1F97 1F27 0345; +1F98 1F28 0345; +1F99 1F29 0345; +1F9A 1F2A 0345; +1F9B 1F2B 0345; +1F9C 1F2C 0345; +1F9D 1F2D 0345; +1F9E 1F2E 0345; +1F9F 1F2F 0345; +1FA0 1F60 0345; +1FA1 1F61 0345; +1FA2 1F62 0345; +1FA3 1F63 0345; +1FA4 1F64 0345; +1FA5 1F65 0345; +1FA6 1F66 0345; +1FA7 1F67 0345; +1FA8 1F68 0345; +1FA9 1F69 0345; +1FAA 1F6A 0345; +1FAB 1F6B 0345; +1FAC 1F6C 0345; +1FAD 1F6D 0345; +1FAE 1F6E 0345; +1FAF 1F6F 0345; +1FB0 03B1 0306; +1FB1 03B1 0304; +1FB2 1F70 0345; +1FB3 03B1 0345; +1FB4 03AC 0345; +1FB6 03B1 0342; +1FB7 1FB6 0345; +1FB8 0391 0306; +1FB9 0391 0304; +1FBA 0391 0300; +1FBB 0386 0000; +1FBC 0391 0345; +1FBD 0020 0313;; +1FBE 03B9 0000; +1FBF 0020 0313;; +1FC0 0020 0342;; +1FC1 00A8 0342; +1FC2 1F74 0345; +1FC3 03B7 0345; +1FC4 03AE 0345; +1FC6 03B7 0342; +1FC7 1FC6 0345; +1FC8 0395 0300; +1FC9 0388 0000; +1FCA 0397 0300; +1FCB 0389 0000; +1FCC 0397 0345; +1FCD 1FBF 0300; +1FCE 1FBF 0301; +1FCF 1FBF 0342; +1FD0 03B9 0306; +1FD1 03B9 0304; +1FD2 03CA 0300; +1FD3 0390 0000; +1FD6 03B9 0342; +1FD7 03CA 0342; +1FD8 0399 0306; +1FD9 0399 0304; +1FDA 0399 0300; +1FDB 038A 0000; +1FDD 1FFE 0300; +1FDE 1FFE 0301; +1FDF 1FFE 0342; +1FE0 03C5 0306; +1FE1 03C5 0304; +1FE2 03CB 0300; +1FE3 03B0 0000; +1FE4 03C1 0313; +1FE5 03C1 0314; +1FE6 03C5 0342; +1FE7 03CB 0342; +1FE8 03A5 0306; +1FE9 03A5 0304; +1FEA 03A5 0300; +1FEB 038E 0000; +1FEC 03A1 0314; +1FED 00A8 0300; +1FEE 0385 0000; +1FEF 0060 0000; +1FF2 1F7C 0345; +1FF3 03C9 0345; +1FF4 03CE 0345; +1FF6 03C9 0342; +1FF7 1FF6 0345; +1FF8 039F 0300; +1FF9 038C 0000; +1FFA 03A9 0300; +1FFB 038F 0000; +1FFC 03A9 0345; +1FFD 00B4 0000; +1FFE 0020 0314;; +2000 2002 0000; +2001 2003 0000; +2002 0020 0000;; +2003 0020 0000;; +2004 0020 0000;; +2005 0020 0000;; +2006 0020 0000;; +2007 0020 0000;; +2008 0020 0000;; +2009 0020 0000;; +200A 0020 0000;; +2011 2010 0000;; +2017 0020 0333;; +2024 002E 0000;; +2025 002E 002E;; +2026 002E 002E;; +202F 0020 0000;; +2033 2032 2032;; +2034 2032 2032;; +2036 2035 2035;; +2037 2035 2035;; +203C 0021 0021;; +203E 0020 0305;; +2048 003F 0021;; +2049 0021 003F;; +2070 0030 0000;; +2074 0034 0000;; +2075 0035 0000;; +2076 0036 0000;; +2077 0037 0000;; +2078 0038 0000;; +2079 0039 0000;; +207A 002B 0000;; +207B 2212 0000;; +207C 003D 0000;; +207D 0028 0000;; +207E 0029 0000;; +207F 006E 0000;; +2080 0030 0000;; +2081 0031 0000;; +2082 0032 0000;; +2083 0033 0000;; +2084 0034 0000;; +2085 0035 0000;; +2086 0036 0000;; +2087 0037 0000;; +2088 0038 0000;; +2089 0039 0000;; +208A 002B 0000;; +208B 2212 0000;; +208C 003D 0000;; +208D 0028 0000;; +208E 0029 0000;; +20A8 0052 0073;; +2100 0061 002F;; +2101 0061 002F;; +2102 0043 0000;; +2103 00B0 0043;; +2105 0063 002F;; +2106 0063 002F;; +2107 0190 0000;; +2109 00B0 0046;; +210A 0067 0000;; +210B 0048 0000;; +210C 0048 0000;; +210D 0048 0000;; +210E 0068 0000;; +210F 0127 0000;; +2110 0049 0000;; +2111 0049 0000;; +2112 004C 0000;; +2113 006C 0000;; +2115 004E 0000;; +2116 004E 006F;; +2119 0050 0000;; +211A 0051 0000;; +211B 0052 0000;; +211C 0052 0000;; +211D 0052 0000;; +2120 0053 004D;; +2121 0054 0045;; +2122 0054 004D;; +2124 005A 0000;; +2126 03A9 0000; +2128 005A 0000;; +212A 004B 0000; +212B 00C5 0000; +212C 0042 0000;; +212D 0043 0000;; +212F 0065 0000;; +2130 0045 0000;; +2131 0046 0000;; +2133 004D 0000;; +2134 006F 0000;; +2135 05D0 0000;; +2136 05D1 0000;; +2137 05D2 0000;; +2138 05D3 0000;; +2139 0069 0000;; +2153 0031 2044;; +2154 0032 2044;; +2155 0031 2044;; +2156 0032 2044;; +2157 0033 2044;; +2158 0034 2044;; +2159 0031 2044;; +215A 0035 2044;; +215B 0031 2044;; +215C 0033 2044;; +215D 0035 2044;; +215E 0037 2044;; +215F 0031 2044;; +2160 0049 0000;; +2161 0049 0049;; +2162 0049 0049;; +2163 0049 0056;; +2164 0056 0000;; +2165 0056 0049;; +2166 0056 0049;; +2167 0056 0049;; +2168 0049 0058;; +2169 0058 0000;; +216A 0058 0049;; +216B 0058 0049;; +216C 004C 0000;; +216D 0043 0000;; +216E 0044 0000;; +216F 004D 0000;; +2170 0069 0000;; +2171 0069 0069;; +2172 0069 0069;; +2173 0069 0076;; +2174 0076 0000;; +2175 0076 0069;; +2176 0076 0069;; +2177 0076 0069;; +2178 0069 0078;; +2179 0078 0000;; +217A 0078 0069;; +217B 0078 0069;; +217C 006C 0000;; +217D 0063 0000;; +217E 0064 0000;; +217F 006D 0000;; +219A 2190 0338; +219B 2192 0338; +21AE 2194 0338; +21CD 21D0 0338; +21CE 21D4 0338; +21CF 21D2 0338; +2204 2203 0338; +2209 2208 0338; +220C 220B 0338; +2224 2223 0338; +2226 2225 0338; +222C 222B 222B;; +222D 222B 222B;; +222F 222E 222E;; +2230 222E 222E;; +2241 223C 0338; +2244 2243 0338; +2247 2245 0338; +2249 2248 0338; +2260 003D 0338; +2262 2261 0338; +226D 224D 0338; +226E 003C 0338; +226F 003E 0338; +2270 2264 0338; +2271 2265 0338; +2274 2272 0338; +2275 2273 0338; +2278 2276 0338; +2279 2277 0338; +2280 227A 0338; +2281 227B 0338; +2284 2282 0338; +2285 2283 0338; +2288 2286 0338; +2289 2287 0338; +22AC 22A2 0338; +22AD 22A8 0338; +22AE 22A9 0338; +22AF 22AB 0338; +22E0 227C 0338; +22E1 227D 0338; +22E2 2291 0338; +22E3 2292 0338; +22EA 22B2 0338; +22EB 22B3 0338; +22EC 22B4 0338; +22ED 22B5 0338; +2329 3008 0000; +232A 3009 0000; +2460 0031 0000;; +2461 0032 0000;; +2462 0033 0000;; +2463 0034 0000;; +2464 0035 0000;; +2465 0036 0000;; +2466 0037 0000;; +2467 0038 0000;; +2468 0039 0000;; +2469 0031 0030;; +246A 0031 0031;; +246B 0031 0032;; +246C 0031 0033;; +246D 0031 0034;; +246E 0031 0035;; +246F 0031 0036;; +2470 0031 0037;; +2471 0031 0038;; +2472 0031 0039;; +2473 0032 0030;; +2474 0028 0031;; +2475 0028 0032;; +2476 0028 0033;; +2477 0028 0034;; +2478 0028 0035;; +2479 0028 0036;; +247A 0028 0037;; +247B 0028 0038;; +247C 0028 0039;; +247D 0028 0031;; +247E 0028 0031;; +247F 0028 0031;; +2480 0028 0031;; +2481 0028 0031;; +2482 0028 0031;; +2483 0028 0031;; +2484 0028 0031;; +2485 0028 0031;; +2486 0028 0031;; +2487 0028 0032;; +2488 0031 002E;; +2489 0032 002E;; +248A 0033 002E;; +248B 0034 002E;; +248C 0035 002E;; +248D 0036 002E;; +248E 0037 002E;; +248F 0038 002E;; +2490 0039 002E;; +2491 0031 0030;; +2492 0031 0031;; +2493 0031 0032;; +2494 0031 0033;; +2495 0031 0034;; +2496 0031 0035;; +2497 0031 0036;; +2498 0031 0037;; +2499 0031 0038;; +249A 0031 0039;; +249B 0032 0030;; +249C 0028 0061;; +249D 0028 0062;; +249E 0028 0063;; +249F 0028 0064;; +24A0 0028 0065;; +24A1 0028 0066;; +24A2 0028 0067;; +24A3 0028 0068;; +24A4 0028 0069;; +24A5 0028 006A;; +24A6 0028 006B;; +24A7 0028 006C;; +24A8 0028 006D;; +24A9 0028 006E;; +24AA 0028 006F;; +24AB 0028 0070;; +24AC 0028 0071;; +24AD 0028 0072;; +24AE 0028 0073;; +24AF 0028 0074;; +24B0 0028 0075;; +24B1 0028 0076;; +24B2 0028 0077;; +24B3 0028 0078;; +24B4 0028 0079;; +24B5 0028 007A;; +24B6 0041 0000;; +24B7 0042 0000;; +24B8 0043 0000;; +24B9 0044 0000;; +24BA 0045 0000;; +24BB 0046 0000;; +24BC 0047 0000;; +24BD 0048 0000;; +24BE 0049 0000;; +24BF 004A 0000;; +24C0 004B 0000;; +24C1 004C 0000;; +24C2 004D 0000;; +24C3 004E 0000;; +24C4 004F 0000;; +24C5 0050 0000;; +24C6 0051 0000;; +24C7 0052 0000;; +24C8 0053 0000;; +24C9 0054 0000;; +24CA 0055 0000;; +24CB 0056 0000;; +24CC 0057 0000;; +24CD 0058 0000;; +24CE 0059 0000;; +24CF 005A 0000;; +24D0 0061 0000;; +24D1 0062 0000;; +24D2 0063 0000;; +24D3 0064 0000;; +24D4 0065 0000;; +24D5 0066 0000;; +24D6 0067 0000;; +24D7 0068 0000;; +24D8 0069 0000;; +24D9 006A 0000;; +24DA 006B 0000;; +24DB 006C 0000;; +24DC 006D 0000;; +24DD 006E 0000;; +24DE 006F 0000;; +24DF 0070 0000;; +24E0 0071 0000;; +24E1 0072 0000;; +24E2 0073 0000;; +24E3 0074 0000;; +24E4 0075 0000;; +24E5 0076 0000;; +24E6 0077 0000;; +24E7 0078 0000;; +24E8 0079 0000;; +24E9 007A 0000;; +24EA 0030 0000;; +2E9F 6BCD 0000;; +2EF3 9F9F 0000;; +2F00 4E00 0000;; +2F01 4E28 0000;; +2F02 4E36 0000;; +2F03 4E3F 0000;; +2F04 4E59 0000;; +2F05 4E85 0000;; +2F06 4E8C 0000;; +2F07 4EA0 0000;; +2F08 4EBA 0000;; +2F09 513F 0000;; +2F0A 5165 0000;; +2F0B 516B 0000;; +2F0C 5182 0000;; +2F0D 5196 0000;; +2F0E 51AB 0000;; +2F0F 51E0 0000;; +2F10 51F5 0000;; +2F11 5200 0000;; +2F12 529B 0000;; +2F13 52F9 0000;; +2F14 5315 0000;; +2F15 531A 0000;; +2F16 5338 0000;; +2F17 5341 0000;; +2F18 535C 0000;; +2F19 5369 0000;; +2F1A 5382 0000;; +2F1B 53B6 0000;; +2F1C 53C8 0000;; +2F1D 53E3 0000;; +2F1E 56D7 0000;; +2F1F 571F 0000;; +2F20 58EB 0000;; +2F21 5902 0000;; +2F22 590A 0000;; +2F23 5915 0000;; +2F24 5927 0000;; +2F25 5973 0000;; +2F26 5B50 0000;; +2F27 5B80 0000;; +2F28 5BF8 0000;; +2F29 5C0F 0000;; +2F2A 5C22 0000;; +2F2B 5C38 0000;; +2F2C 5C6E 0000;; +2F2D 5C71 0000;; +2F2E 5DDB 0000;; +2F2F 5DE5 0000;; +2F30 5DF1 0000;; +2F31 5DFE 0000;; +2F32 5E72 0000;; +2F33 5E7A 0000;; +2F34 5E7F 0000;; +2F35 5EF4 0000;; +2F36 5EFE 0000;; +2F37 5F0B 0000;; +2F38 5F13 0000;; +2F39 5F50 0000;; +2F3A 5F61 0000;; +2F3B 5F73 0000;; +2F3C 5FC3 0000;; +2F3D 6208 0000;; +2F3E 6236 0000;; +2F3F 624B 0000;; +2F40 652F 0000;; +2F41 6534 0000;; +2F42 6587 0000;; +2F43 6597 0000;; +2F44 65A4 0000;; +2F45 65B9 0000;; +2F46 65E0 0000;; +2F47 65E5 0000;; +2F48 66F0 0000;; +2F49 6708 0000;; +2F4A 6728 0000;; +2F4B 6B20 0000;; +2F4C 6B62 0000;; +2F4D 6B79 0000;; +2F4E 6BB3 0000;; +2F4F 6BCB 0000;; +2F50 6BD4 0000;; +2F51 6BDB 0000;; +2F52 6C0F 0000;; +2F53 6C14 0000;; +2F54 6C34 0000;; +2F55 706B 0000;; +2F56 722A 0000;; +2F57 7236 0000;; +2F58 723B 0000;; +2F59 723F 0000;; +2F5A 7247 0000;; +2F5B 7259 0000;; +2F5C 725B 0000;; +2F5D 72AC 0000;; +2F5E 7384 0000;; +2F5F 7389 0000;; +2F60 74DC 0000;; +2F61 74E6 0000;; +2F62 7518 0000;; +2F63 751F 0000;; +2F64 7528 0000;; +2F65 7530 0000;; +2F66 758B 0000;; +2F67 7592 0000;; +2F68 7676 0000;; +2F69 767D 0000;; +2F6A 76AE 0000;; +2F6B 76BF 0000;; +2F6C 76EE 0000;; +2F6D 77DB 0000;; +2F6E 77E2 0000;; +2F6F 77F3 0000;; +2F70 793A 0000;; +2F71 79B8 0000;; +2F72 79BE 0000;; +2F73 7A74 0000;; +2F74 7ACB 0000;; +2F75 7AF9 0000;; +2F76 7C73 0000;; +2F77 7CF8 0000;; +2F78 7F36 0000;; +2F79 7F51 0000;; +2F7A 7F8A 0000;; +2F7B 7FBD 0000;; +2F7C 8001 0000;; +2F7D 800C 0000;; +2F7E 8012 0000;; +2F7F 8033 0000;; +2F80 807F 0000;; +2F81 8089 0000;; +2F82 81E3 0000;; +2F83 81EA 0000;; +2F84 81F3 0000;; +2F85 81FC 0000;; +2F86 820C 0000;; +2F87 821B 0000;; +2F88 821F 0000;; +2F89 826E 0000;; +2F8A 8272 0000;; +2F8B 8278 0000;; +2F8C 864D 0000;; +2F8D 866B 0000;; +2F8E 8840 0000;; +2F8F 884C 0000;; +2F90 8863 0000;; +2F91 897E 0000;; +2F92 898B 0000;; +2F93 89D2 0000;; +2F94 8A00 0000;; +2F95 8C37 0000;; +2F96 8C46 0000;; +2F97 8C55 0000;; +2F98 8C78 0000;; +2F99 8C9D 0000;; +2F9A 8D64 0000;; +2F9B 8D70 0000;; +2F9C 8DB3 0000;; +2F9D 8EAB 0000;; +2F9E 8ECA 0000;; +2F9F 8F9B 0000;; +2FA0 8FB0 0000;; +2FA1 8FB5 0000;; +2FA2 9091 0000;; +2FA3 9149 0000;; +2FA4 91C6 0000;; +2FA5 91CC 0000;; +2FA6 91D1 0000;; +2FA7 9577 0000;; +2FA8 9580 0000;; +2FA9 961C 0000;; +2FAA 96B6 0000;; +2FAB 96B9 0000;; +2FAC 96E8 0000;; +2FAD 9751 0000;; +2FAE 975E 0000;; +2FAF 9762 0000;; +2FB0 9769 0000;; +2FB1 97CB 0000;; +2FB2 97ED 0000;; +2FB3 97F3 0000;; +2FB4 9801 0000;; +2FB5 98A8 0000;; +2FB6 98DB 0000;; +2FB7 98DF 0000;; +2FB8 9996 0000;; +2FB9 9999 0000;; +2FBA 99AC 0000;; +2FBB 9AA8 0000;; +2FBC 9AD8 0000;; +2FBD 9ADF 0000;; +2FBE 9B25 0000;; +2FBF 9B2F 0000;; +2FC0 9B32 0000;; +2FC1 9B3C 0000;; +2FC2 9B5A 0000;; +2FC3 9CE5 0000;; +2FC4 9E75 0000;; +2FC5 9E7F 0000;; +2FC6 9EA5 0000;; +2FC7 9EBB 0000;; +2FC8 9EC3 0000;; +2FC9 9ECD 0000;; +2FCA 9ED1 0000;; +2FCB 9EF9 0000;; +2FCC 9EFD 0000;; +2FCD 9F0E 0000;; +2FCE 9F13 0000;; +2FCF 9F20 0000;; +2FD0 9F3B 0000;; +2FD1 9F4A 0000;; +2FD2 9F52 0000;; +2FD3 9F8D 0000;; +2FD4 9F9C 0000;; +2FD5 9FA0 0000;; +3000 0020 0000;; +3036 3012 0000;; +3038 5341 0000;; +3039 5344 0000;; +303A 5345 0000;; +304C 304B 3099; +304E 304D 3099; +3050 304F 3099; +3052 3051 3099; +3054 3053 3099; +3056 3055 3099; +3058 3057 3099; +305A 3059 3099; +305C 305B 3099; +305E 305D 3099; +3060 305F 3099; +3062 3061 3099; +3065 3064 3099; +3067 3066 3099; +3069 3068 3099; +3070 306F 3099; +3071 306F 309A; +3073 3072 3099; +3074 3072 309A; +3076 3075 3099; +3077 3075 309A; +3079 3078 3099; +307A 3078 309A; +307C 307B 3099; +307D 307B 309A; +3094 3046 3099; +309B 0020 3099;; +309C 0020 309A;; +309E 309D 3099; +30AC 30AB 3099; +30AE 30AD 3099; +30B0 30AF 3099; +30B2 30B1 3099; +30B4 30B3 3099; +30B6 30B5 3099; +30B8 30B7 3099; +30BA 30B9 3099; +30BC 30BB 3099; +30BE 30BD 3099; +30C0 30BF 3099; +30C2 30C1 3099; +30C5 30C4 3099; +30C7 30C6 3099; +30C9 30C8 3099; +30D0 30CF 3099; +30D1 30CF 309A; +30D3 30D2 3099; +30D4 30D2 309A; +30D6 30D5 3099; +30D7 30D5 309A; +30D9 30D8 3099; +30DA 30D8 309A; +30DC 30DB 3099; +30DD 30DB 309A; +30F4 30A6 3099; +30F7 30EF 3099; +30F8 30F0 3099; +30F9 30F1 3099; +30FA 30F2 3099; +30FE 30FD 3099; +3131 1100 0000;; +3132 1101 0000;; +3133 11AA 0000;; +3134 1102 0000;; +3135 11AC 0000;; +3136 11AD 0000;; +3137 1103 0000;; +3138 1104 0000;; +3139 1105 0000;; +313A 11B0 0000;; +313B 11B1 0000;; +313C 11B2 0000;; +313D 11B3 0000;; +313E 11B4 0000;; +313F 11B5 0000;; +3140 111A 0000;; +3141 1106 0000;; +3142 1107 0000;; +3143 1108 0000;; +3144 1121 0000;; +3145 1109 0000;; +3146 110A 0000;; +3147 110B 0000;; +3148 110C 0000;; +3149 110D 0000;; +314A 110E 0000;; +314B 110F 0000;; +314C 1110 0000;; +314D 1111 0000;; +314E 1112 0000;; +314F 1161 0000;; +3150 1162 0000;; +3151 1163 0000;; +3152 1164 0000;; +3153 1165 0000;; +3154 1166 0000;; +3155 1167 0000;; +3156 1168 0000;; +3157 1169 0000;; +3158 116A 0000;; +3159 116B 0000;; +315A 116C 0000;; +315B 116D 0000;; +315C 116E 0000;; +315D 116F 0000;; +315E 1170 0000;; +315F 1171 0000;; +3160 1172 0000;; +3161 1173 0000;; +3162 1174 0000;; +3163 1175 0000;; +3164 1160 0000;; +3165 1114 0000;; +3166 1115 0000;; +3167 11C7 0000;; +3168 11C8 0000;; +3169 11CC 0000;; +316A 11CE 0000;; +316B 11D3 0000;; +316C 11D7 0000;; +316D 11D9 0000;; +316E 111C 0000;; +316F 11DD 0000;; +3170 11DF 0000;; +3171 111D 0000;; +3172 111E 0000;; +3173 1120 0000;; +3174 1122 0000;; +3175 1123 0000;; +3176 1127 0000;; +3177 1129 0000;; +3178 112B 0000;; +3179 112C 0000;; +317A 112D 0000;; +317B 112E 0000;; +317C 112F 0000;; +317D 1132 0000;; +317E 1136 0000;; +317F 1140 0000;; +3180 1147 0000;; +3181 114C 0000;; +3182 11F1 0000;; +3183 11F2 0000;; +3184 1157 0000;; +3185 1158 0000;; +3186 1159 0000;; +3187 1184 0000;; +3188 1185 0000;; +3189 1188 0000;; +318A 1191 0000;; +318B 1192 0000;; +318C 1194 0000;; +318D 119E 0000;; +318E 11A1 0000;; +3192 4E00 0000;; +3193 4E8C 0000;; +3194 4E09 0000;; +3195 56DB 0000;; +3196 4E0A 0000;; +3197 4E2D 0000;; +3198 4E0B 0000;; +3199 7532 0000;; +319A 4E59 0000;; +319B 4E19 0000;; +319C 4E01 0000;; +319D 5929 0000;; +319E 5730 0000;; +319F 4EBA 0000;; +3200 0028 1100;; +3201 0028 1102;; +3202 0028 1103;; +3203 0028 1105;; +3204 0028 1106;; +3205 0028 1107;; +3206 0028 1109;; +3207 0028 110B;; +3208 0028 110C;; +3209 0028 110E;; +320A 0028 110F;; +320B 0028 1110;; +320C 0028 1111;; +320D 0028 1112;; +320E 0028 1100;; +320F 0028 1102;; +3210 0028 1103;; +3211 0028 1105;; +3212 0028 1106;; +3213 0028 1107;; +3214 0028 1109;; +3215 0028 110B;; +3216 0028 110C;; +3217 0028 110E;; +3218 0028 110F;; +3219 0028 1110;; +321A 0028 1111;; +321B 0028 1112;; +321C 0028 110C;; +3220 0028 4E00;; +3221 0028 4E8C;; +3222 0028 4E09;; +3223 0028 56DB;; +3224 0028 4E94;; +3225 0028 516D;; +3226 0028 4E03;; +3227 0028 516B;; +3228 0028 4E5D;; +3229 0028 5341;; +322A 0028 6708;; +322B 0028 706B;; +322C 0028 6C34;; +322D 0028 6728;; +322E 0028 91D1;; +322F 0028 571F;; +3230 0028 65E5;; +3231 0028 682A;; +3232 0028 6709;; +3233 0028 793E;; +3234 0028 540D;; +3235 0028 7279;; +3236 0028 8CA1;; +3237 0028 795D;; +3238 0028 52B4;; +3239 0028 4EE3;; +323A 0028 547C;; +323B 0028 5B66;; +323C 0028 76E3;; +323D 0028 4F01;; +323E 0028 8CC7;; +323F 0028 5354;; +3240 0028 796D;; +3241 0028 4F11;; +3242 0028 81EA;; +3243 0028 81F3;; +3260 1100 0000;; +3261 1102 0000;; +3262 1103 0000;; +3263 1105 0000;; +3264 1106 0000;; +3265 1107 0000;; +3266 1109 0000;; +3267 110B 0000;; +3268 110C 0000;; +3269 110E 0000;; +326A 110F 0000;; +326B 1110 0000;; +326C 1111 0000;; +326D 1112 0000;; +326E 1100 1161;; +326F 1102 1161;; +3270 1103 1161;; +3271 1105 1161;; +3272 1106 1161;; +3273 1107 1161;; +3274 1109 1161;; +3275 110B 1161;; +3276 110C 1161;; +3277 110E 1161;; +3278 110F 1161;; +3279 1110 1161;; +327A 1111 1161;; +327B 1112 1161;; +3280 4E00 0000;; +3281 4E8C 0000;; +3282 4E09 0000;; +3283 56DB 0000;; +3284 4E94 0000;; +3285 516D 0000;; +3286 4E03 0000;; +3287 516B 0000;; +3288 4E5D 0000;; +3289 5341 0000;; +328A 6708 0000;; +328B 706B 0000;; +328C 6C34 0000;; +328D 6728 0000;; +328E 91D1 0000;; +328F 571F 0000;; +3290 65E5 0000;; +3291 682A 0000;; +3292 6709 0000;; +3293 793E 0000;; +3294 540D 0000;; +3295 7279 0000;; +3296 8CA1 0000;; +3297 795D 0000;; +3298 52B4 0000;; +3299 79D8 0000;; +329A 7537 0000;; +329B 5973 0000;; +329C 9069 0000;; +329D 512A 0000;; +329E 5370 0000;; +329F 6CE8 0000;; +32A0 9805 0000;; +32A1 4F11 0000;; +32A2 5199 0000;; +32A3 6B63 0000;; +32A4 4E0A 0000;; +32A5 4E2D 0000;; +32A6 4E0B 0000;; +32A7 5DE6 0000;; +32A8 53F3 0000;; +32A9 533B 0000;; +32AA 5B97 0000;; +32AB 5B66 0000;; +32AC 76E3 0000;; +32AD 4F01 0000;; +32AE 8CC7 0000;; +32AF 5354 0000;; +32B0 591C 0000;; +32C0 0031 6708;; +32C1 0032 6708;; +32C2 0033 6708;; +32C3 0034 6708;; +32C4 0035 6708;; +32C5 0036 6708;; +32C6 0037 6708;; +32C7 0038 6708;; +32C8 0039 6708;; +32C9 0031 0030;; +32CA 0031 0031;; +32CB 0031 0032;; +32D0 30A2 0000;; +32D1 30A4 0000;; +32D2 30A6 0000;; +32D3 30A8 0000;; +32D4 30AA 0000;; +32D5 30AB 0000;; +32D6 30AD 0000;; +32D7 30AF 0000;; +32D8 30B1 0000;; +32D9 30B3 0000;; +32DA 30B5 0000;; +32DB 30B7 0000;; +32DC 30B9 0000;; +32DD 30BB 0000;; +32DE 30BD 0000;; +32DF 30BF 0000;; +32E0 30C1 0000;; +32E1 30C4 0000;; +32E2 30C6 0000;; +32E3 30C8 0000;; +32E4 30CA 0000;; +32E5 30CB 0000;; +32E6 30CC 0000;; +32E7 30CD 0000;; +32E8 30CE 0000;; +32E9 30CF 0000;; +32EA 30D2 0000;; +32EB 30D5 0000;; +32EC 30D8 0000;; +32ED 30DB 0000;; +32EE 30DE 0000;; +32EF 30DF 0000;; +32F0 30E0 0000;; +32F1 30E1 0000;; +32F2 30E2 0000;; +32F3 30E4 0000;; +32F4 30E6 0000;; +32F5 30E8 0000;; +32F6 30E9 0000;; +32F7 30EA 0000;; +32F8 30EB 0000;; +32F9 30EC 0000;; +32FA 30ED 0000;; +32FB 30EF 0000;; +32FC 30F0 0000;; +32FD 30F1 0000;; +32FE 30F2 0000;; +3300 30A2 30D1;; +3301 30A2 30EB;; +3302 30A2 30F3;; +3303 30A2 30FC;; +3304 30A4 30CB;; +3305 30A4 30F3;; +3306 30A6 30A9;; +3307 30A8 30B9;; +3308 30A8 30FC;; +3309 30AA 30F3;; +330A 30AA 30FC;; +330B 30AB 30A4;; +330C 30AB 30E9;; +330D 30AB 30ED;; +330E 30AC 30ED;; +330F 30AC 30F3;; +3310 30AE 30AC;; +3311 30AE 30CB;; +3312 30AD 30E5;; +3313 30AE 30EB;; +3314 30AD 30ED;; +3315 30AD 30ED;; +3316 30AD 30ED;; +3317 30AD 30ED;; +3318 30B0 30E9;; +3319 30B0 30E9;; +331A 30AF 30EB;; +331B 30AF 30ED;; +331C 30B1 30FC;; +331D 30B3 30EB;; +331E 30B3 30FC;; +331F 30B5 30A4;; +3320 30B5 30F3;; +3321 30B7 30EA;; +3322 30BB 30F3;; +3323 30BB 30F3;; +3324 30C0 30FC;; +3325 30C7 30B7;; +3326 30C9 30EB;; +3327 30C8 30F3;; +3328 30CA 30CE;; +3329 30CE 30C3;; +332A 30CF 30A4;; +332B 30D1 30FC;; +332C 30D1 30FC;; +332D 30D0 30FC;; +332E 30D4 30A2;; +332F 30D4 30AF;; +3330 30D4 30B3;; +3331 30D3 30EB;; +3332 30D5 30A1;; +3333 30D5 30A3;; +3334 30D6 30C3;; +3335 30D5 30E9;; +3336 30D8 30AF;; +3337 30DA 30BD;; +3338 30DA 30CB;; +3339 30D8 30EB;; +333A 30DA 30F3;; +333B 30DA 30FC;; +333C 30D9 30FC;; +333D 30DD 30A4;; +333E 30DC 30EB;; +333F 30DB 30F3;; +3340 30DD 30F3;; +3341 30DB 30FC;; +3342 30DB 30FC;; +3343 30DE 30A4;; +3344 30DE 30A4;; +3345 30DE 30C3;; +3346 30DE 30EB;; +3347 30DE 30F3;; +3348 30DF 30AF;; +3349 30DF 30EA;; +334A 30DF 30EA;; +334B 30E1 30AC;; +334C 30E1 30AC;; +334D 30E1 30FC;; +334E 30E4 30FC;; +334F 30E4 30FC;; +3350 30E6 30A2;; +3351 30EA 30C3;; +3352 30EA 30E9;; +3353 30EB 30D4;; +3354 30EB 30FC;; +3355 30EC 30E0;; +3356 30EC 30F3;; +3357 30EF 30C3;; +3358 0030 70B9;; +3359 0031 70B9;; +335A 0032 70B9;; +335B 0033 70B9;; +335C 0034 70B9;; +335D 0035 70B9;; +335E 0036 70B9;; +335F 0037 70B9;; +3360 0038 70B9;; +3361 0039 70B9;; +3362 0031 0030;; +3363 0031 0031;; +3364 0031 0032;; +3365 0031 0033;; +3366 0031 0034;; +3367 0031 0035;; +3368 0031 0036;; +3369 0031 0037;; +336A 0031 0038;; +336B 0031 0039;; +336C 0032 0030;; +336D 0032 0031;; +336E 0032 0032;; +336F 0032 0033;; +3370 0032 0034;; +3371 0068 0050;; +3372 0064 0061;; +3373 0041 0055;; +3374 0062 0061;; +3375 006F 0056;; +3376 0070 0063;; +337B 5E73 6210;; +337C 662D 548C;; +337D 5927 6B63;; +337E 660E 6CBB;; +337F 682A 5F0F;; +3380 0070 0041;; +3381 006E 0041;; +3382 03BC 0041;; +3383 006D 0041;; +3384 006B 0041;; +3385 004B 0042;; +3386 004D 0042;; +3387 0047 0042;; +3388 0063 0061;; +3389 006B 0063;; +338A 0070 0046;; +338B 006E 0046;; +338C 03BC 0046;; +338D 03BC 0067;; +338E 006D 0067;; +338F 006B 0067;; +3390 0048 007A;; +3391 006B 0048;; +3392 004D 0048;; +3393 0047 0048;; +3394 0054 0048;; +3395 03BC 2113;; +3396 006D 2113;; +3397 0064 2113;; +3398 006B 2113;; +3399 0066 006D;; +339A 006E 006D;; +339B 03BC 006D;; +339C 006D 006D;; +339D 0063 006D;; +339E 006B 006D;; +339F 006D 006D;; +33A0 0063 006D;; +33A1 006D 00B2;; +33A2 006B 006D;; +33A3 006D 006D;; +33A4 0063 006D;; +33A5 006D 00B3;; +33A6 006B 006D;; +33A7 006D 2215;; +33A8 006D 2215;; +33A9 0050 0061;; +33AA 006B 0050;; +33AB 004D 0050;; +33AC 0047 0050;; +33AD 0072 0061;; +33AE 0072 0061;; +33AF 0072 0061;; +33B0 0070 0073;; +33B1 006E 0073;; +33B2 03BC 0073;; +33B3 006D 0073;; +33B4 0070 0056;; +33B5 006E 0056;; +33B6 03BC 0056;; +33B7 006D 0056;; +33B8 006B 0056;; +33B9 004D 0056;; +33BA 0070 0057;; +33BB 006E 0057;; +33BC 03BC 0057;; +33BD 006D 0057;; +33BE 006B 0057;; +33BF 004D 0057;; +33C0 006B 03A9;; +33C1 004D 03A9;; +33C2 0061 002E;; +33C3 0042 0071;; +33C4 0063 0063;; +33C5 0063 0064;; +33C6 0043 2215;; +33C7 0043 006F;; +33C8 0064 0042;; +33C9 0047 0079;; +33CA 0068 0061;; +33CB 0048 0050;; +33CC 0069 006E;; +33CD 004B 004B;; +33CE 004B 004D;; +33CF 006B 0074;; +33D0 006C 006D;; +33D1 006C 006E;; +33D2 006C 006F;; +33D3 006C 0078;; +33D4 006D 0062;; +33D5 006D 0069;; +33D6 006D 006F;; +33D7 0050 0048;; +33D8 0070 002E;; +33D9 0050 0050;; +33DA 0050 0052;; +33DB 0073 0072;; +33DC 0053 0076;; +33DD 0057 0062;; +33E0 0031 65E5;; +33E1 0032 65E5;; +33E2 0033 65E5;; +33E3 0034 65E5;; +33E4 0035 65E5;; +33E5 0036 65E5;; +33E6 0037 65E5;; +33E7 0038 65E5;; +33E8 0039 65E5;; +33E9 0031 0030;; +33EA 0031 0031;; +33EB 0031 0032;; +33EC 0031 0033;; +33ED 0031 0034;; +33EE 0031 0035;; +33EF 0031 0036;; +33F0 0031 0037;; +33F1 0031 0038;; +33F2 0031 0039;; +33F3 0032 0030;; +33F4 0032 0031;; +33F5 0032 0032;; +33F6 0032 0033;; +33F7 0032 0034;; +33F8 0032 0035;; +33F9 0032 0036;; +33FA 0032 0037;; +33FB 0032 0038;; +33FC 0032 0039;; +33FD 0033 0030;; +33FE 0033 0031;; +F900 8C48 0000; +F901 66F4 0000; +F902 8ECA 0000; +F903 8CC8 0000; +F904 6ED1 0000; +F905 4E32 0000; +F906 53E5 0000; +F907 9F9C 0000; +F908 9F9C 0000; +F909 5951 0000; +F90A 91D1 0000; +F90B 5587 0000; +F90C 5948 0000; +F90D 61F6 0000; +F90E 7669 0000; +F90F 7F85 0000; +F910 863F 0000; +F911 87BA 0000; +F912 88F8 0000; +F913 908F 0000; +F914 6A02 0000; +F915 6D1B 0000; +F916 70D9 0000; +F917 73DE 0000; +F918 843D 0000; +F919 916A 0000; +F91A 99F1 0000; +F91B 4E82 0000; +F91C 5375 0000; +F91D 6B04 0000; +F91E 721B 0000; +F91F 862D 0000; +F920 9E1E 0000; +F921 5D50 0000; +F922 6FEB 0000; +F923 85CD 0000; +F924 8964 0000; +F925 62C9 0000; +F926 81D8 0000; +F927 881F 0000; +F928 5ECA 0000; +F929 6717 0000; +F92A 6D6A 0000; +F92B 72FC 0000; +F92C 90CE 0000; +F92D 4F86 0000; +F92E 51B7 0000; +F92F 52DE 0000; +F930 64C4 0000; +F931 6AD3 0000; +F932 7210 0000; +F933 76E7 0000; +F934 8001 0000; +F935 8606 0000; +F936 865C 0000; +F937 8DEF 0000; +F938 9732 0000; +F939 9B6F 0000; +F93A 9DFA 0000; +F93B 788C 0000; +F93C 797F 0000; +F93D 7DA0 0000; +F93E 83C9 0000; +F93F 9304 0000; +F940 9E7F 0000; +F941 8AD6 0000; +F942 58DF 0000; +F943 5F04 0000; +F944 7C60 0000; +F945 807E 0000; +F946 7262 0000; +F947 78CA 0000; +F948 8CC2 0000; +F949 96F7 0000; +F94A 58D8 0000; +F94B 5C62 0000; +F94C 6A13 0000; +F94D 6DDA 0000; +F94E 6F0F 0000; +F94F 7D2F 0000; +F950 7E37 0000; +F951 96FB 0000; +F952 52D2 0000; +F953 808B 0000; +F954 51DC 0000; +F955 51CC 0000; +F956 7A1C 0000; +F957 7DBE 0000; +F958 83F1 0000; +F959 9675 0000; +F95A 8B80 0000; +F95B 62CF 0000; +F95C 6A02 0000; +F95D 8AFE 0000; +F95E 4E39 0000; +F95F 5BE7 0000; +F960 6012 0000; +F961 7387 0000; +F962 7570 0000; +F963 5317 0000; +F964 78FB 0000; +F965 4FBF 0000; +F966 5FA9 0000; +F967 4E0D 0000; +F968 6CCC 0000; +F969 6578 0000; +F96A 7D22 0000; +F96B 53C3 0000; +F96C 585E 0000; +F96D 7701 0000; +F96E 8449 0000; +F96F 8AAA 0000; +F970 6BBA 0000; +F971 8FB0 0000; +F972 6C88 0000; +F973 62FE 0000; +F974 82E5 0000; +F975 63A0 0000; +F976 7565 0000; +F977 4EAE 0000; +F978 5169 0000; +F979 51C9 0000; +F97A 6881 0000; +F97B 7CE7 0000; +F97C 826F 0000; +F97D 8AD2 0000; +F97E 91CF 0000; +F97F 52F5 0000; +F980 5442 0000; +F981 5973 0000; +F982 5EEC 0000; +F983 65C5 0000; +F984 6FFE 0000; +F985 792A 0000; +F986 95AD 0000; +F987 9A6A 0000; +F988 9E97 0000; +F989 9ECE 0000; +F98A 529B 0000; +F98B 66C6 0000; +F98C 6B77 0000; +F98D 8F62 0000; +F98E 5E74 0000; +F98F 6190 0000; +F990 6200 0000; +F991 649A 0000; +F992 6F23 0000; +F993 7149 0000; +F994 7489 0000; +F995 79CA 0000; +F996 7DF4 0000; +F997 806F 0000; +F998 8F26 0000; +F999 84EE 0000; +F99A 9023 0000; +F99B 934A 0000; +F99C 5217 0000; +F99D 52A3 0000; +F99E 54BD 0000; +F99F 70C8 0000; +F9A0 88C2 0000; +F9A1 8AAA 0000; +F9A2 5EC9 0000; +F9A3 5FF5 0000; +F9A4 637B 0000; +F9A5 6BAE 0000; +F9A6 7C3E 0000; +F9A7 7375 0000; +F9A8 4EE4 0000; +F9A9 56F9 0000; +F9AA 5BE7 0000; +F9AB 5DBA 0000; +F9AC 601C 0000; +F9AD 73B2 0000; +F9AE 7469 0000; +F9AF 7F9A 0000; +F9B0 8046 0000; +F9B1 9234 0000; +F9B2 96F6 0000; +F9B3 9748 0000; +F9B4 9818 0000; +F9B5 4F8B 0000; +F9B6 79AE 0000; +F9B7 91B4 0000; +F9B8 96B8 0000; +F9B9 60E1 0000; +F9BA 4E86 0000; +F9BB 50DA 0000; +F9BC 5BEE 0000; +F9BD 5C3F 0000; +F9BE 6599 0000; +F9BF 6A02 0000; +F9C0 71CE 0000; +F9C1 7642 0000; +F9C2 84FC 0000; +F9C3 907C 0000; +F9C4 9F8D 0000; +F9C5 6688 0000; +F9C6 962E 0000; +F9C7 5289 0000; +F9C8 677B 0000; +F9C9 67F3 0000; +F9CA 6D41 0000; +F9CB 6E9C 0000; +F9CC 7409 0000; +F9CD 7559 0000; +F9CE 786B 0000; +F9CF 7D10 0000; +F9D0 985E 0000; +F9D1 516D 0000; +F9D2 622E 0000; +F9D3 9678 0000; +F9D4 502B 0000; +F9D5 5D19 0000; +F9D6 6DEA 0000; +F9D7 8F2A 0000; +F9D8 5F8B 0000; +F9D9 6144 0000; +F9DA 6817 0000; +F9DB 7387 0000; +F9DC 9686 0000; +F9DD 5229 0000; +F9DE 540F 0000; +F9DF 5C65 0000; +F9E0 6613 0000; +F9E1 674E 0000; +F9E2 68A8 0000; +F9E3 6CE5 0000; +F9E4 7406 0000; +F9E5 75E2 0000; +F9E6 7F79 0000; +F9E7 88CF 0000; +F9E8 88E1 0000; +F9E9 91CC 0000; +F9EA 96E2 0000; +F9EB 533F 0000; +F9EC 6EBA 0000; +F9ED 541D 0000; +F9EE 71D0 0000; +F9EF 7498 0000; +F9F0 85FA 0000; +F9F1 96A3 0000; +F9F2 9C57 0000; +F9F3 9E9F 0000; +F9F4 6797 0000; +F9F5 6DCB 0000; +F9F6 81E8 0000; +F9F7 7ACB 0000; +F9F8 7B20 0000; +F9F9 7C92 0000; +F9FA 72C0 0000; +F9FB 7099 0000; +F9FC 8B58 0000; +F9FD 4EC0 0000; +F9FE 8336 0000; +F9FF 523A 0000; +FA00 5207 0000; +FA01 5EA6 0000; +FA02 62D3 0000; +FA03 7CD6 0000; +FA04 5B85 0000; +FA05 6D1E 0000; +FA06 66B4 0000; +FA07 8F3B 0000; +FA08 884C 0000; +FA09 964D 0000; +FA0A 898B 0000; +FA0B 5ED3 0000; +FA0C 5140 0000; +FA0D 55C0 0000; +FA10 585A 0000; +FA12 6674 0000; +FA15 51DE 0000; +FA16 732A 0000; +FA17 76CA 0000; +FA18 793C 0000; +FA19 795E 0000; +FA1A 7965 0000; +FA1B 798F 0000; +FA1C 9756 0000; +FA1D 7CBE 0000; +FA1E 7FBD 0000; +FA20 8612 0000; +FA22 8AF8 0000; +FA25 9038 0000; +FA26 90FD 0000; +FA2A 98EF 0000; +FA2B 98FC 0000; +FA2C 9928 0000; +FA2D 9DB4 0000; +FB00 0066 0066;; +FB01 0066 0069;; +FB02 0066 006C;; +FB03 0066 0066;; +FB04 0066 0066;; +FB05 017F 0074;; +FB06 0073 0074;; +FB13 0574 0576;; +FB14 0574 0565;; +FB15 0574 056B;; +FB16 057E 0576;; +FB17 0574 056D;; +FB1D 05D9 05B4; +FB1F 05F2 05B7; +FB20 05E2 0000;; +FB21 05D0 0000;; +FB22 05D3 0000;; +FB23 05D4 0000;; +FB24 05DB 0000;; +FB25 05DC 0000;; +FB26 05DD 0000;; +FB27 05E8 0000;; +FB28 05EA 0000;; +FB29 002B 0000;; +FB2A 05E9 05C1; +FB2B 05E9 05C2; +FB2C FB49 05C1; +FB2D FB49 05C2; +FB2E 05D0 05B7; +FB2F 05D0 05B8; +FB30 05D0 05BC; +FB31 05D1 05BC; +FB32 05D2 05BC; +FB33 05D3 05BC; +FB34 05D4 05BC; +FB35 05D5 05BC; +FB36 05D6 05BC; +FB38 05D8 05BC; +FB39 05D9 05BC; +FB3A 05DA 05BC; +FB3B 05DB 05BC; +FB3C 05DC 05BC; +FB3E 05DE 05BC; +FB40 05E0 05BC; +FB41 05E1 05BC; +FB43 05E3 05BC; +FB44 05E4 05BC; +FB46 05E6 05BC; +FB47 05E7 05BC; +FB48 05E8 05BC; +FB49 05E9 05BC; +FB4A 05EA 05BC; +FB4B 05D5 05B9; +FB4C 05D1 05BF; +FB4D 05DB 05BF; +FB4E 05E4 05BF; +FB4F 05D0 05DC;; +FB50 0671 0000;; +FB51 0671 0000;; +FB52 067B 0000;; +FB53 067B 0000;; +FB54 067B 0000;; +FB55 067B 0000;; +FB56 067E 0000;; +FB57 067E 0000;; +FB58 067E 0000;; +FB59 067E 0000;; +FB5A 0680 0000;; +FB5B 0680 0000;; +FB5C 0680 0000;; +FB5D 0680 0000;; +FB5E 067A 0000;; +FB5F 067A 0000;; +FB60 067A 0000;; +FB61 067A 0000;; +FB62 067F 0000;; +FB63 067F 0000;; +FB64 067F 0000;; +FB65 067F 0000;; +FB66 0679 0000;; +FB67 0679 0000;; +FB68 0679 0000;; +FB69 0679 0000;; +FB6A 06A4 0000;; +FB6B 06A4 0000;; +FB6C 06A4 0000;; +FB6D 06A4 0000;; +FB6E 06A6 0000;; +FB6F 06A6 0000;; +FB70 06A6 0000;; +FB71 06A6 0000;; +FB72 0684 0000;; +FB73 0684 0000;; +FB74 0684 0000;; +FB75 0684 0000;; +FB76 0683 0000;; +FB77 0683 0000;; +FB78 0683 0000;; +FB79 0683 0000;; +FB7A 0686 0000;; +FB7B 0686 0000;; +FB7C 0686 0000;; +FB7D 0686 0000;; +FB7E 0687 0000;; +FB7F 0687 0000;; +FB80 0687 0000;; +FB81 0687 0000;; +FB82 068D 0000;; +FB83 068D 0000;; +FB84 068C 0000;; +FB85 068C 0000;; +FB86 068E 0000;; +FB87 068E 0000;; +FB88 0688 0000;; +FB89 0688 0000;; +FB8A 0698 0000;; +FB8B 0698 0000;; +FB8C 0691 0000;; +FB8D 0691 0000;; +FB8E 06A9 0000;; +FB8F 06A9 0000;; +FB90 06A9 0000;; +FB91 06A9 0000;; +FB92 06AF 0000;; +FB93 06AF 0000;; +FB94 06AF 0000;; +FB95 06AF 0000;; +FB96 06B3 0000;; +FB97 06B3 0000;; +FB98 06B3 0000;; +FB99 06B3 0000;; +FB9A 06B1 0000;; +FB9B 06B1 0000;; +FB9C 06B1 0000;; +FB9D 06B1 0000;; +FB9E 06BA 0000;; +FB9F 06BA 0000;; +FBA0 06BB 0000;; +FBA1 06BB 0000;; +FBA2 06BB 0000;; +FBA3 06BB 0000;; +FBA4 06C0 0000;; +FBA5 06C0 0000;; +FBA6 06C1 0000;; +FBA7 06C1 0000;; +FBA8 06C1 0000;; +FBA9 06C1 0000;; +FBAA 06BE 0000;; +FBAB 06BE 0000;; +FBAC 06BE 0000;; +FBAD 06BE 0000;; +FBAE 06D2 0000;; +FBAF 06D2 0000;; +FBB0 06D3 0000;; +FBB1 06D3 0000;; +FBD3 06AD 0000;; +FBD4 06AD 0000;; +FBD5 06AD 0000;; +FBD6 06AD 0000;; +FBD7 06C7 0000;; +FBD8 06C7 0000;; +FBD9 06C6 0000;; +FBDA 06C6 0000;; +FBDB 06C8 0000;; +FBDC 06C8 0000;; +FBDD 0677 0000;; +FBDE 06CB 0000;; +FBDF 06CB 0000;; +FBE0 06C5 0000;; +FBE1 06C5 0000;; +FBE2 06C9 0000;; +FBE3 06C9 0000;; +FBE4 06D0 0000;; +FBE5 06D0 0000;; +FBE6 06D0 0000;; +FBE7 06D0 0000;; +FBE8 0649 0000;; +FBE9 0649 0000;; +FBEA 0626 0627;; +FBEB 0626 0627;; +FBEC 0626 06D5;; +FBED 0626 06D5;; +FBEE 0626 0648;; +FBEF 0626 0648;; +FBF0 0626 06C7;; +FBF1 0626 06C7;; +FBF2 0626 06C6;; +FBF3 0626 06C6;; +FBF4 0626 06C8;; +FBF5 0626 06C8;; +FBF6 0626 06D0;; +FBF7 0626 06D0;; +FBF8 0626 06D0;; +FBF9 0626 0649;; +FBFA 0626 0649;; +FBFB 0626 0649;; +FBFC 06CC 0000;; +FBFD 06CC 0000;; +FBFE 06CC 0000;; +FBFF 06CC 0000;; +FC00 0626 062C;; +FC01 0626 062D;; +FC02 0626 0645;; +FC03 0626 0649;; +FC04 0626 064A;; +FC05 0628 062C;; +FC06 0628 062D;; +FC07 0628 062E;; +FC08 0628 0645;; +FC09 0628 0649;; +FC0A 0628 064A;; +FC0B 062A 062C;; +FC0C 062A 062D;; +FC0D 062A 062E;; +FC0E 062A 0645;; +FC0F 062A 0649;; +FC10 062A 064A;; +FC11 062B 062C;; +FC12 062B 0645;; +FC13 062B 0649;; +FC14 062B 064A;; +FC15 062C 062D;; +FC16 062C 0645;; +FC17 062D 062C;; +FC18 062D 0645;; +FC19 062E 062C;; +FC1A 062E 062D;; +FC1B 062E 0645;; +FC1C 0633 062C;; +FC1D 0633 062D;; +FC1E 0633 062E;; +FC1F 0633 0645;; +FC20 0635 062D;; +FC21 0635 0645;; +FC22 0636 062C;; +FC23 0636 062D;; +FC24 0636 062E;; +FC25 0636 0645;; +FC26 0637 062D;; +FC27 0637 0645;; +FC28 0638 0645;; +FC29 0639 062C;; +FC2A 0639 0645;; +FC2B 063A 062C;; +FC2C 063A 0645;; +FC2D 0641 062C;; +FC2E 0641 062D;; +FC2F 0641 062E;; +FC30 0641 0645;; +FC31 0641 0649;; +FC32 0641 064A;; +FC33 0642 062D;; +FC34 0642 0645;; +FC35 0642 0649;; +FC36 0642 064A;; +FC37 0643 0627;; +FC38 0643 062C;; +FC39 0643 062D;; +FC3A 0643 062E;; +FC3B 0643 0644;; +FC3C 0643 0645;; +FC3D 0643 0649;; +FC3E 0643 064A;; +FC3F 0644 062C;; +FC40 0644 062D;; +FC41 0644 062E;; +FC42 0644 0645;; +FC43 0644 0649;; +FC44 0644 064A;; +FC45 0645 062C;; +FC46 0645 062D;; +FC47 0645 062E;; +FC48 0645 0645;; +FC49 0645 0649;; +FC4A 0645 064A;; +FC4B 0646 062C;; +FC4C 0646 062D;; +FC4D 0646 062E;; +FC4E 0646 0645;; +FC4F 0646 0649;; +FC50 0646 064A;; +FC51 0647 062C;; +FC52 0647 0645;; +FC53 0647 0649;; +FC54 0647 064A;; +FC55 064A 062C;; +FC56 064A 062D;; +FC57 064A 062E;; +FC58 064A 0645;; +FC59 064A 0649;; +FC5A 064A 064A;; +FC5B 0630 0670;; +FC5C 0631 0670;; +FC5D 0649 0670;; +FC5E 0020 064C;; +FC5F 0020 064D;; +FC60 0020 064E;; +FC61 0020 064F;; +FC62 0020 0650;; +FC63 0020 0651;; +FC64 0626 0631;; +FC65 0626 0632;; +FC66 0626 0645;; +FC67 0626 0646;; +FC68 0626 0649;; +FC69 0626 064A;; +FC6A 0628 0631;; +FC6B 0628 0632;; +FC6C 0628 0645;; +FC6D 0628 0646;; +FC6E 0628 0649;; +FC6F 0628 064A;; +FC70 062A 0631;; +FC71 062A 0632;; +FC72 062A 0645;; +FC73 062A 0646;; +FC74 062A 0649;; +FC75 062A 064A;; +FC76 062B 0631;; +FC77 062B 0632;; +FC78 062B 0645;; +FC79 062B 0646;; +FC7A 062B 0649;; +FC7B 062B 064A;; +FC7C 0641 0649;; +FC7D 0641 064A;; +FC7E 0642 0649;; +FC7F 0642 064A;; +FC80 0643 0627;; +FC81 0643 0644;; +FC82 0643 0645;; +FC83 0643 0649;; +FC84 0643 064A;; +FC85 0644 0645;; +FC86 0644 0649;; +FC87 0644 064A;; +FC88 0645 0627;; +FC89 0645 0645;; +FC8A 0646 0631;; +FC8B 0646 0632;; +FC8C 0646 0645;; +FC8D 0646 0646;; +FC8E 0646 0649;; +FC8F 0646 064A;; +FC90 0649 0670;; +FC91 064A 0631;; +FC92 064A 0632;; +FC93 064A 0645;; +FC94 064A 0646;; +FC95 064A 0649;; +FC96 064A 064A;; +FC97 0626 062C;; +FC98 0626 062D;; +FC99 0626 062E;; +FC9A 0626 0645;; +FC9B 0626 0647;; +FC9C 0628 062C;; +FC9D 0628 062D;; +FC9E 0628 062E;; +FC9F 0628 0645;; +FCA0 0628 0647;; +FCA1 062A 062C;; +FCA2 062A 062D;; +FCA3 062A 062E;; +FCA4 062A 0645;; +FCA5 062A 0647;; +FCA6 062B 0645;; +FCA7 062C 062D;; +FCA8 062C 0645;; +FCA9 062D 062C;; +FCAA 062D 0645;; +FCAB 062E 062C;; +FCAC 062E 0645;; +FCAD 0633 062C;; +FCAE 0633 062D;; +FCAF 0633 062E;; +FCB0 0633 0645;; +FCB1 0635 062D;; +FCB2 0635 062E;; +FCB3 0635 0645;; +FCB4 0636 062C;; +FCB5 0636 062D;; +FCB6 0636 062E;; +FCB7 0636 0645;; +FCB8 0637 062D;; +FCB9 0638 0645;; +FCBA 0639 062C;; +FCBB 0639 0645;; +FCBC 063A 062C;; +FCBD 063A 0645;; +FCBE 0641 062C;; +FCBF 0641 062D;; +FCC0 0641 062E;; +FCC1 0641 0645;; +FCC2 0642 062D;; +FCC3 0642 0645;; +FCC4 0643 062C;; +FCC5 0643 062D;; +FCC6 0643 062E;; +FCC7 0643 0644;; +FCC8 0643 0645;; +FCC9 0644 062C;; +FCCA 0644 062D;; +FCCB 0644 062E;; +FCCC 0644 0645;; +FCCD 0644 0647;; +FCCE 0645 062C;; +FCCF 0645 062D;; +FCD0 0645 062E;; +FCD1 0645 0645;; +FCD2 0646 062C;; +FCD3 0646 062D;; +FCD4 0646 062E;; +FCD5 0646 0645;; +FCD6 0646 0647;; +FCD7 0647 062C;; +FCD8 0647 0645;; +FCD9 0647 0670;; +FCDA 064A 062C;; +FCDB 064A 062D;; +FCDC 064A 062E;; +FCDD 064A 0645;; +FCDE 064A 0647;; +FCDF 0626 0645;; +FCE0 0626 0647;; +FCE1 0628 0645;; +FCE2 0628 0647;; +FCE3 062A 0645;; +FCE4 062A 0647;; +FCE5 062B 0645;; +FCE6 062B 0647;; +FCE7 0633 0645;; +FCE8 0633 0647;; +FCE9 0634 0645;; +FCEA 0634 0647;; +FCEB 0643 0644;; +FCEC 0643 0645;; +FCED 0644 0645;; +FCEE 0646 0645;; +FCEF 0646 0647;; +FCF0 064A 0645;; +FCF1 064A 0647;; +FCF2 0640 064E;; +FCF3 0640 064F;; +FCF4 0640 0650;; +FCF5 0637 0649;; +FCF6 0637 064A;; +FCF7 0639 0649;; +FCF8 0639 064A;; +FCF9 063A 0649;; +FCFA 063A 064A;; +FCFB 0633 0649;; +FCFC 0633 064A;; +FCFD 0634 0649;; +FCFE 0634 064A;; +FCFF 062D 0649;; +FD00 062D 064A;; +FD01 062C 0649;; +FD02 062C 064A;; +FD03 062E 0649;; +FD04 062E 064A;; +FD05 0635 0649;; +FD06 0635 064A;; +FD07 0636 0649;; +FD08 0636 064A;; +FD09 0634 062C;; +FD0A 0634 062D;; +FD0B 0634 062E;; +FD0C 0634 0645;; +FD0D 0634 0631;; +FD0E 0633 0631;; +FD0F 0635 0631;; +FD10 0636 0631;; +FD11 0637 0649;; +FD12 0637 064A;; +FD13 0639 0649;; +FD14 0639 064A;; +FD15 063A 0649;; +FD16 063A 064A;; +FD17 0633 0649;; +FD18 0633 064A;; +FD19 0634 0649;; +FD1A 0634 064A;; +FD1B 062D 0649;; +FD1C 062D 064A;; +FD1D 062C 0649;; +FD1E 062C 064A;; +FD1F 062E 0649;; +FD20 062E 064A;; +FD21 0635 0649;; +FD22 0635 064A;; +FD23 0636 0649;; +FD24 0636 064A;; +FD25 0634 062C;; +FD26 0634 062D;; +FD27 0634 062E;; +FD28 0634 0645;; +FD29 0634 0631;; +FD2A 0633 0631;; +FD2B 0635 0631;; +FD2C 0636 0631;; +FD2D 0634 062C;; +FD2E 0634 062D;; +FD2F 0634 062E;; +FD30 0634 0645;; +FD31 0633 0647;; +FD32 0634 0647;; +FD33 0637 0645;; +FD34 0633 062C;; +FD35 0633 062D;; +FD36 0633 062E;; +FD37 0634 062C;; +FD38 0634 062D;; +FD39 0634 062E;; +FD3A 0637 0645;; +FD3B 0638 0645;; +FD3C 0627 064B;; +FD3D 0627 064B;; +FD50 062A 062C;; +FD51 062A 062D;; +FD52 062A 062D;; +FD53 062A 062D;; +FD54 062A 062E;; +FD55 062A 0645;; +FD56 062A 0645;; +FD57 062A 0645;; +FD58 062C 0645;; +FD59 062C 0645;; +FD5A 062D 0645;; +FD5B 062D 0645;; +FD5C 0633 062D;; +FD5D 0633 062C;; +FD5E 0633 062C;; +FD5F 0633 0645;; +FD60 0633 0645;; +FD61 0633 0645;; +FD62 0633 0645;; +FD63 0633 0645;; +FD64 0635 062D;; +FD65 0635 062D;; +FD66 0635 0645;; +FD67 0634 062D;; +FD68 0634 062D;; +FD69 0634 062C;; +FD6A 0634 0645;; +FD6B 0634 0645;; +FD6C 0634 0645;; +FD6D 0634 0645;; +FD6E 0636 062D;; +FD6F 0636 062E;; +FD70 0636 062E;; +FD71 0637 0645;; +FD72 0637 0645;; +FD73 0637 0645;; +FD74 0637 0645;; +FD75 0639 062C;; +FD76 0639 0645;; +FD77 0639 0645;; +FD78 0639 0645;; +FD79 063A 0645;; +FD7A 063A 0645;; +FD7B 063A 0645;; +FD7C 0641 062E;; +FD7D 0641 062E;; +FD7E 0642 0645;; +FD7F 0642 0645;; +FD80 0644 062D;; +FD81 0644 062D;; +FD82 0644 062D;; +FD83 0644 062C;; +FD84 0644 062C;; +FD85 0644 062E;; +FD86 0644 062E;; +FD87 0644 0645;; +FD88 0644 0645;; +FD89 0645 062D;; +FD8A 0645 062D;; +FD8B 0645 062D;; +FD8C 0645 062C;; +FD8D 0645 062C;; +FD8E 0645 062E;; +FD8F 0645 062E;; +FD92 0645 062C;; +FD93 0647 0645;; +FD94 0647 0645;; +FD95 0646 062D;; +FD96 0646 062D;; +FD97 0646 062C;; +FD98 0646 062C;; +FD99 0646 062C;; +FD9A 0646 0645;; +FD9B 0646 0645;; +FD9C 064A 0645;; +FD9D 064A 0645;; +FD9E 0628 062E;; +FD9F 062A 062C;; +FDA0 062A 062C;; +FDA1 062A 062E;; +FDA2 062A 062E;; +FDA3 062A 0645;; +FDA4 062A 0645;; +FDA5 062C 0645;; +FDA6 062C 062D;; +FDA7 062C 0645;; +FDA8 0633 062E;; +FDA9 0635 062D;; +FDAA 0634 062D;; +FDAB 0636 062D;; +FDAC 0644 062C;; +FDAD 0644 0645;; +FDAE 064A 062D;; +FDAF 064A 062C;; +FDB0 064A 0645;; +FDB1 0645 0645;; +FDB2 0642 0645;; +FDB3 0646 062D;; +FDB4 0642 0645;; +FDB5 0644 062D;; +FDB6 0639 0645;; +FDB7 0643 0645;; +FDB8 0646 062C;; +FDB9 0645 062E;; +FDBA 0644 062C;; +FDBB 0643 0645;; +FDBC 0644 062C;; +FDBD 0646 062C;; +FDBE 062C 062D;; +FDBF 062D 062C;; +FDC0 0645 062C;; +FDC1 0641 0645;; +FDC2 0628 062D;; +FDC3 0643 0645;; +FDC4 0639 062C;; +FDC5 0635 0645;; +FDC6 0633 062E;; +FDC7 0646 062C;; +FDF0 0635 0644;; +FDF1 0642 0644;; +FDF2 0627 0644;; +FDF3 0627 0643;; +FDF4 0645 062D;; +FDF5 0635 0644;; +FDF6 0631 0633;; +FDF7 0639 0644;; +FDF8 0648 0633;; +FDF9 0635 0644;; +FDFA 0635 0644;; +FDFB 062C 0644;; +FE30 2025 0000;; +FE31 2014 0000;; +FE32 2013 0000;; +FE33 005F 0000;; +FE34 005F 0000;; +FE35 0028 0000;; +FE36 0029 0000;; +FE37 007B 0000;; +FE38 007D 0000;; +FE39 3014 0000;; +FE3A 3015 0000;; +FE3B 3010 0000;; +FE3C 3011 0000;; +FE3D 300A 0000;; +FE3E 300B 0000;; +FE3F 3008 0000;; +FE40 3009 0000;; +FE41 300C 0000;; +FE42 300D 0000;; +FE43 300E 0000;; +FE44 300F 0000;; +FE49 203E 0000;; +FE4A 203E 0000;; +FE4B 203E 0000;; +FE4C 203E 0000;; +FE4D 005F 0000;; +FE4E 005F 0000;; +FE4F 005F 0000;; +FE50 002C 0000;; +FE51 3001 0000;; +FE52 002E 0000;; +FE54 003B 0000;; +FE55 003A 0000;; +FE56 003F 0000;; +FE57 0021 0000;; +FE58 2014 0000;; +FE59 0028 0000;; +FE5A 0029 0000;; +FE5B 007B 0000;; +FE5C 007D 0000;; +FE5D 3014 0000;; +FE5E 3015 0000;; +FE5F 0023 0000;; +FE60 0026 0000;; +FE61 002A 0000;; +FE62 002B 0000;; +FE63 002D 0000;; +FE64 003C 0000;; +FE65 003E 0000;; +FE66 003D 0000;; +FE68 005C 0000;; +FE69 0024 0000;; +FE6A 0025 0000;; +FE6B 0040 0000;; +FE70 0020 064B;; +FE71 0640 064B;; +FE72 0020 064C;; +FE74 0020 064D;; +FE76 0020 064E;; +FE77 0640 064E;; +FE78 0020 064F;; +FE79 0640 064F;; +FE7A 0020 0650;; +FE7B 0640 0650;; +FE7C 0020 0651;; +FE7D 0640 0651;; +FE7E 0020 0652;; +FE7F 0640 0652;; +FE80 0621 0000;; +FE81 0622 0000;; +FE82 0622 0000;; +FE83 0623 0000;; +FE84 0623 0000;; +FE85 0624 0000;; +FE86 0624 0000;; +FE87 0625 0000;; +FE88 0625 0000;; +FE89 0626 0000;; +FE8A 0626 0000;; +FE8B 0626 0000;; +FE8C 0626 0000;; +FE8D 0627 0000;; +FE8E 0627 0000;; +FE8F 0628 0000;; +FE90 0628 0000;; +FE91 0628 0000;; +FE92 0628 0000;; +FE93 0629 0000;; +FE94 0629 0000;; +FE95 062A 0000;; +FE96 062A 0000;; +FE97 062A 0000;; +FE98 062A 0000;; +FE99 062B 0000;; +FE9A 062B 0000;; +FE9B 062B 0000;; +FE9C 062B 0000;; +FE9D 062C 0000;; +FE9E 062C 0000;; +FE9F 062C 0000;; +FEA0 062C 0000;; +FEA1 062D 0000;; +FEA2 062D 0000;; +FEA3 062D 0000;; +FEA4 062D 0000;; +FEA5 062E 0000;; +FEA6 062E 0000;; +FEA7 062E 0000;; +FEA8 062E 0000;; +FEA9 062F 0000;; +FEAA 062F 0000;; +FEAB 0630 0000;; +FEAC 0630 0000;; +FEAD 0631 0000;; +FEAE 0631 0000;; +FEAF 0632 0000;; +FEB0 0632 0000;; +FEB1 0633 0000;; +FEB2 0633 0000;; +FEB3 0633 0000;; +FEB4 0633 0000;; +FEB5 0634 0000;; +FEB6 0634 0000;; +FEB7 0634 0000;; +FEB8 0634 0000;; +FEB9 0635 0000;; +FEBA 0635 0000;; +FEBB 0635 0000;; +FEBC 0635 0000;; +FEBD 0636 0000;; +FEBE 0636 0000;; +FEBF 0636 0000;; +FEC0 0636 0000;; +FEC1 0637 0000;; +FEC2 0637 0000;; +FEC3 0637 0000;; +FEC4 0637 0000;; +FEC5 0638 0000;; +FEC6 0638 0000;; +FEC7 0638 0000;; +FEC8 0638 0000;; +FEC9 0639 0000;; +FECA 0639 0000;; +FECB 0639 0000;; +FECC 0639 0000;; +FECD 063A 0000;; +FECE 063A 0000;; +FECF 063A 0000;; +FED0 063A 0000;; +FED1 0641 0000;; +FED2 0641 0000;; +FED3 0641 0000;; +FED4 0641 0000;; +FED5 0642 0000;; +FED6 0642 0000;; +FED7 0642 0000;; +FED8 0642 0000;; +FED9 0643 0000;; +FEDA 0643 0000;; +FEDB 0643 0000;; +FEDC 0643 0000;; +FEDD 0644 0000;; +FEDE 0644 0000;; +FEDF 0644 0000;; +FEE0 0644 0000;; +FEE1 0645 0000;; +FEE2 0645 0000;; +FEE3 0645 0000;; +FEE4 0645 0000;; +FEE5 0646 0000;; +FEE6 0646 0000;; +FEE7 0646 0000;; +FEE8 0646 0000;; +FEE9 0647 0000;; +FEEA 0647 0000;; +FEEB 0647 0000;; +FEEC 0647 0000;; +FEED 0648 0000;; +FEEE 0648 0000;; +FEEF 0649 0000;; +FEF0 0649 0000;; +FEF1 064A 0000;; +FEF2 064A 0000;; +FEF3 064A 0000;; +FEF4 064A 0000;; +FEF5 0644 0622;; +FEF6 0644 0622;; +FEF7 0644 0623;; +FEF8 0644 0623;; +FEF9 0644 0625;; +FEFA 0644 0625;; +FEFB 0644 0627;; +FEFC 0644 0627;; +FF01 0021 0000;; +FF02 0022 0000;; +FF03 0023 0000;; +FF04 0024 0000;; +FF05 0025 0000;; +FF06 0026 0000;; +FF07 0027 0000;; +FF08 0028 0000;; +FF09 0029 0000;; +FF0A 002A 0000;; +FF0B 002B 0000;; +FF0C 002C 0000;; +FF0D 002D 0000;; +FF0E 002E 0000;; +FF0F 002F 0000;; +FF10 0030 0000;; +FF11 0031 0000;; +FF12 0032 0000;; +FF13 0033 0000;; +FF14 0034 0000;; +FF15 0035 0000;; +FF16 0036 0000;; +FF17 0037 0000;; +FF18 0038 0000;; +FF19 0039 0000;; +FF1A 003A 0000;; +FF1B 003B 0000;; +FF1C 003C 0000;; +FF1D 003D 0000;; +FF1E 003E 0000;; +FF1F 003F 0000;; +FF20 0040 0000;; +FF21 0041 0000;; +FF22 0042 0000;; +FF23 0043 0000;; +FF24 0044 0000;; +FF25 0045 0000;; +FF26 0046 0000;; +FF27 0047 0000;; +FF28 0048 0000;; +FF29 0049 0000;; +FF2A 004A 0000;; +FF2B 004B 0000;; +FF2C 004C 0000;; +FF2D 004D 0000;; +FF2E 004E 0000;; +FF2F 004F 0000;; +FF30 0050 0000;; +FF31 0051 0000;; +FF32 0052 0000;; +FF33 0053 0000;; +FF34 0054 0000;; +FF35 0055 0000;; +FF36 0056 0000;; +FF37 0057 0000;; +FF38 0058 0000;; +FF39 0059 0000;; +FF3A 005A 0000;; +FF3B 005B 0000;; +FF3C 005C 0000;; +FF3D 005D 0000;; +FF3E 005E 0000;; +FF3F 005F 0000;; +FF40 0060 0000;; +FF41 0061 0000;; +FF42 0062 0000;; +FF43 0063 0000;; +FF44 0064 0000;; +FF45 0065 0000;; +FF46 0066 0000;; +FF47 0067 0000;; +FF48 0068 0000;; +FF49 0069 0000;; +FF4A 006A 0000;; +FF4B 006B 0000;; +FF4C 006C 0000;; +FF4D 006D 0000;; +FF4E 006E 0000;; +FF4F 006F 0000;; +FF50 0070 0000;; +FF51 0071 0000;; +FF52 0072 0000;; +FF53 0073 0000;; +FF54 0074 0000;; +FF55 0075 0000;; +FF56 0076 0000;; +FF57 0077 0000;; +FF58 0078 0000;; +FF59 0079 0000;; +FF5A 007A 0000;; +FF5B 007B 0000;; +FF5C 007C 0000;; +FF5D 007D 0000;; +FF5E 007E 0000;; +FF61 3002 0000;; +FF62 300C 0000;; +FF63 300D 0000;; +FF64 3001 0000;; +FF65 30FB 0000;; +FF66 30F2 0000;; +FF67 30A1 0000;; +FF68 30A3 0000;; +FF69 30A5 0000;; +FF6A 30A7 0000;; +FF6B 30A9 0000;; +FF6C 30E3 0000;; +FF6D 30E5 0000;; +FF6E 30E7 0000;; +FF6F 30C3 0000;; +FF70 30FC 0000;; +FF71 30A2 0000;; +FF72 30A4 0000;; +FF73 30A6 0000;; +FF74 30A8 0000;; +FF75 30AA 0000;; +FF76 30AB 0000;; +FF77 30AD 0000;; +FF78 30AF 0000;; +FF79 30B1 0000;; +FF7A 30B3 0000;; +FF7B 30B5 0000;; +FF7C 30B7 0000;; +FF7D 30B9 0000;; +FF7E 30BB 0000;; +FF7F 30BD 0000;; +FF80 30BF 0000;; +FF81 30C1 0000;; +FF82 30C4 0000;; +FF83 30C6 0000;; +FF84 30C8 0000;; +FF85 30CA 0000;; +FF86 30CB 0000;; +FF87 30CC 0000;; +FF88 30CD 0000;; +FF89 30CE 0000;; +FF8A 30CF 0000;; +FF8B 30D2 0000;; +FF8C 30D5 0000;; +FF8D 30D8 0000;; +FF8E 30DB 0000;; +FF8F 30DE 0000;; +FF90 30DF 0000;; +FF91 30E0 0000;; +FF92 30E1 0000;; +FF93 30E2 0000;; +FF94 30E4 0000;; +FF95 30E6 0000;; +FF96 30E8 0000;; +FF97 30E9 0000;; +FF98 30EA 0000;; +FF99 30EB 0000;; +FF9A 30EC 0000;; +FF9B 30ED 0000;; +FF9C 30EF 0000;; +FF9D 30F3 0000;; +FF9E 3099 0000;; +FF9F 309A 0000;; +FFA0 3164 0000;; +FFA1 3131 0000;; +FFA2 3132 0000;; +FFA3 3133 0000;; +FFA4 3134 0000;; +FFA5 3135 0000;; +FFA6 3136 0000;; +FFA7 3137 0000;; +FFA8 3138 0000;; +FFA9 3139 0000;; +FFAA 313A 0000;; +FFAB 313B 0000;; +FFAC 313C 0000;; +FFAD 313D 0000;; +FFAE 313E 0000;; +FFAF 313F 0000;; +FFB0 3140 0000;; +FFB1 3141 0000;; +FFB2 3142 0000;; +FFB3 3143 0000;; +FFB4 3144 0000;; +FFB5 3145 0000;; +FFB6 3146 0000;; +FFB7 3147 0000;; +FFB8 3148 0000;; +FFB9 3149 0000;; +FFBA 314A 0000;; +FFBB 314B 0000;; +FFBC 314C 0000;; +FFBD 314D 0000;; +FFBE 314E 0000;; +FFC2 314F 0000;; +FFC3 3150 0000;; +FFC4 3151 0000;; +FFC5 3152 0000;; +FFC6 3153 0000;; +FFC7 3154 0000;; +FFCA 3155 0000;; +FFCB 3156 0000;; +FFCC 3157 0000;; +FFCD 3158 0000;; +FFCE 3159 0000;; +FFCF 315A 0000;; +FFD2 315B 0000;; +FFD3 315C 0000;; +FFD4 315D 0000;; +FFD5 315E 0000;; +FFD6 315F 0000;; +FFD7 3160 0000;; +FFDA 3161 0000;; +FFDB 3162 0000;; +FFDC 3163 0000;; +FFE0 00A2 0000;; +FFE1 00A3 0000;; +FFE2 00AC 0000;; +FFE3 00AF 0000;; +FFE4 00A6 0000;; +FFE5 00A5 0000;; +FFE6 20A9 0000;; +FFE8 2502 0000;; +FFE9 2190 0000;; +FFEA 2191 0000;; +FFEB 2192 0000;; +FFEC 2193 0000;; +FFED 25A0 0000;; +FFEE 25CB 0000;; diff --git a/data/uni-prop.txt b/data/uni-prop.txt new file mode 100644 index 000000000..cffd7b9d3 --- /dev/null +++ b/data/uni-prop.txt @@ -0,0 +1,10620 @@ +# uni-prop.txt - Unicode character properties +0000;Cc;BN; +0001;Cc;BN; +0002;Cc;BN; +0003;Cc;BN; +0004;Cc;BN; +0005;Cc;BN; +0006;Cc;BN; +0007;Cc;BN; +0008;Cc;BN; +0009;Cc;S; +000A;Cc;B; +000B;Cc;S; +000C;Cc;WS; +000D;Cc;B; +000E;Cc;BN; +000F;Cc;BN; +0010;Cc;BN; +0011;Cc;BN; +0012;Cc;BN; +0013;Cc;BN; +0014;Cc;BN; +0015;Cc;BN; +0016;Cc;BN; +0017;Cc;BN; +0018;Cc;BN; +0019;Cc;BN; +001A;Cc;BN; +001B;Cc;BN; +001C;Cc;B; +001D;Cc;B; +001E;Cc;B; +001F;Cc;S; +0020;Zs;WS; +0021;Po;ON; +0022;Po;ON; +0023;Po;ET; +0024;Sc;ET; +0025;Po;ET; +0026;Po;ON; +0027;Po;ON; +0028;Ps;ON; +0029;Pe;ON; +002A;Po;ON; +002B;Sm;ET; +002C;Po;CS; +002D;Pd;ET; +002E;Po;CS; +002F;Po;ES; +0030;Nd;EN; +0031;Nd;EN; +0032;Nd;EN; +0033;Nd;EN; +0034;Nd;EN; +0035;Nd;EN; +0036;Nd;EN; +0037;Nd;EN; +0038;Nd;EN; +0039;Nd;EN; +003A;Po;CS; +003B;Po;ON; +003C;Sm;ON; +003D;Sm;ON; +003E;Sm;ON; +003F;Po;ON; +0040;Po;ON; +0041;Lu;L; +0042;Lu;L; +0043;Lu;L; +0044;Lu;L; +0045;Lu;L; +0046;Lu;L; +0047;Lu;L; +0048;Lu;L; +0049;Lu;L; +004A;Lu;L; +004B;Lu;L; +004C;Lu;L; +004D;Lu;L; +004E;Lu;L; +004F;Lu;L; +0050;Lu;L; +0051;Lu;L; +0052;Lu;L; +0053;Lu;L; +0054;Lu;L; +0055;Lu;L; +0056;Lu;L; +0057;Lu;L; +0058;Lu;L; +0059;Lu;L; +005A;Lu;L; +005B;Ps;ON; +005C;Po;ON; +005D;Pe;ON; +005E;Sk;ON; +005F;Pc;ON; +0060;Sk;ON; +0061;Ll;L; +0062;Ll;L; +0063;Ll;L; +0064;Ll;L; +0065;Ll;L; +0066;Ll;L; +0067;Ll;L; +0068;Ll;L; +0069;Ll;L; +006A;Ll;L; +006B;Ll;L; +006C;Ll;L; +006D;Ll;L; +006E;Ll;L; +006F;Ll;L; +0070;Ll;L; +0071;Ll;L; +0072;Ll;L; +0073;Ll;L; +0074;Ll;L; +0075;Ll;L; +0076;Ll;L; +0077;Ll;L; +0078;Ll;L; +0079;Ll;L; +007A;Ll;L; +007B;Ps;ON; +007C;Sm;ON; +007D;Pe;ON; +007E;Sm;ON; +007F;Cc;BN; +0080;Cc;BN; +0081;Cc;BN; +0082;Cc;BN; +0083;Cc;BN; +0084;Cc;BN; +0085;Cc;B; +0086;Cc;BN; +0087;Cc;BN; +0088;Cc;BN; +0089;Cc;BN; +008A;Cc;BN; +008B;Cc;BN; +008C;Cc;BN; +008D;Cc;BN; +008E;Cc;BN; +008F;Cc;BN; +0090;Cc;BN; +0091;Cc;BN; +0092;Cc;BN; +0093;Cc;BN; +0094;Cc;BN; +0095;Cc;BN; +0096;Cc;BN; +0097;Cc;BN; +0098;Cc;BN; +0099;Cc;BN; +009A;Cc;BN; +009B;Cc;BN; +009C;Cc;BN; +009D;Cc;BN; +009E;Cc;BN; +009F;Cc;BN; +00A0;Zs;CS; +00A1;Po;ON; +00A2;Sc;ET; +00A3;Sc;ET; +00A4;Sc;ET; +00A5;Sc;ET; +00A6;So;ON; +00A7;So;ON; +00A8;Sk;ON; +00A9;So;ON; +00AA;Ll;L; +00AB;Pi;ON; +00AC;Sm;ON; +00AD;Pd;ON; +00AE;So;ON; +00AF;Sk;ON; +00B0;So;ET; +00B1;Sm;ET; +00B2;No;EN; +00B3;No;EN; +00B4;Sk;ON; +00B5;Ll;L; +00B6;So;ON; +00B7;Po;ON; +00B8;Sk;ON; +00B9;No;EN; +00BA;Ll;L; +00BB;Pf;ON; +00BC;No;ON; +00BD;No;ON; +00BE;No;ON; +00BF;Po;ON; +00C0;Lu;L; +00C1;Lu;L; +00C2;Lu;L; +00C3;Lu;L; +00C4;Lu;L; +00C5;Lu;L; +00C6;Lu;L; +00C7;Lu;L; +00C8;Lu;L; +00C9;Lu;L; +00CA;Lu;L; +00CB;Lu;L; +00CC;Lu;L; +00CD;Lu;L; +00CE;Lu;L; +00CF;Lu;L; +00D0;Lu;L; +00D1;Lu;L; +00D2;Lu;L; +00D3;Lu;L; +00D4;Lu;L; +00D5;Lu;L; +00D6;Lu;L; +00D7;Sm;ON; +00D8;Lu;L; +00D9;Lu;L; +00DA;Lu;L; +00DB;Lu;L; +00DC;Lu;L; +00DD;Lu;L; +00DE;Lu;L; +00DF;Ll;L; +00E0;Ll;L; +00E1;Ll;L; +00E2;Ll;L; +00E3;Ll;L; +00E4;Ll;L; +00E5;Ll;L; +00E6;Ll;L; +00E7;Ll;L; +00E8;Ll;L; +00E9;Ll;L; +00EA;Ll;L; +00EB;Ll;L; +00EC;Ll;L; +00ED;Ll;L; +00EE;Ll;L; +00EF;Ll;L; +00F0;Ll;L; +00F1;Ll;L; +00F2;Ll;L; +00F3;Ll;L; +00F4;Ll;L; +00F5;Ll;L; +00F6;Ll;L; +00F7;Sm;ON; +00F8;Ll;L; +00F9;Ll;L; +00FA;Ll;L; +00FB;Ll;L; +00FC;Ll;L; +00FD;Ll;L; +00FE;Ll;L; +00FF;Ll;L; +0100;Lu;L; +0101;Ll;L; +0102;Lu;L; +0103;Ll;L; +0104;Lu;L; +0105;Ll;L; +0106;Lu;L; +0107;Ll;L; +0108;Lu;L; +0109;Ll;L; +010A;Lu;L; +010B;Ll;L; +010C;Lu;L; +010D;Ll;L; +010E;Lu;L; +010F;Ll;L; +0110;Lu;L; +0111;Ll;L; +0112;Lu;L; +0113;Ll;L; +0114;Lu;L; +0115;Ll;L; +0116;Lu;L; +0117;Ll;L; +0118;Lu;L; +0119;Ll;L; +011A;Lu;L; +011B;Ll;L; +011C;Lu;L; +011D;Ll;L; +011E;Lu;L; +011F;Ll;L; +0120;Lu;L; +0121;Ll;L; +0122;Lu;L; +0123;Ll;L; +0124;Lu;L; +0125;Ll;L; +0126;Lu;L; +0127;Ll;L; +0128;Lu;L; +0129;Ll;L; +012A;Lu;L; +012B;Ll;L; +012C;Lu;L; +012D;Ll;L; +012E;Lu;L; +012F;Ll;L; +0130;Lu;L; +0131;Ll;L; +0132;Lu;L; +0133;Ll;L; +0134;Lu;L; +0135;Ll;L; +0136;Lu;L; +0137;Ll;L; +0138;Ll;L; +0139;Lu;L; +013A;Ll;L; +013B;Lu;L; +013C;Ll;L; +013D;Lu;L; +013E;Ll;L; +013F;Lu;L; +0140;Ll;L; +0141;Lu;L; +0142;Ll;L; +0143;Lu;L; +0144;Ll;L; +0145;Lu;L; +0146;Ll;L; +0147;Lu;L; +0148;Ll;L; +0149;Ll;L; +014A;Lu;L; +014B;Ll;L; +014C;Lu;L; +014D;Ll;L; +014E;Lu;L; +014F;Ll;L; +0150;Lu;L; +0151;Ll;L; +0152;Lu;L; +0153;Ll;L; +0154;Lu;L; +0155;Ll;L; +0156;Lu;L; +0157;Ll;L; +0158;Lu;L; +0159;Ll;L; +015A;Lu;L; +015B;Ll;L; +015C;Lu;L; +015D;Ll;L; +015E;Lu;L; +015F;Ll;L; +0160;Lu;L; +0161;Ll;L; +0162;Lu;L; +0163;Ll;L; +0164;Lu;L; +0165;Ll;L; +0166;Lu;L; +0167;Ll;L; +0168;Lu;L; +0169;Ll;L; +016A;Lu;L; +016B;Ll;L; +016C;Lu;L; +016D;Ll;L; +016E;Lu;L; +016F;Ll;L; +0170;Lu;L; +0171;Ll;L; +0172;Lu;L; +0173;Ll;L; +0174;Lu;L; +0175;Ll;L; +0176;Lu;L; +0177;Ll;L; +0178;Lu;L; +0179;Lu;L; +017A;Ll;L; +017B;Lu;L; +017C;Ll;L; +017D;Lu;L; +017E;Ll;L; +017F;Ll;L; +0180;Ll;L; +0181;Lu;L; +0182;Lu;L; +0183;Ll;L; +0184;Lu;L; +0185;Ll;L; +0186;Lu;L; +0187;Lu;L; +0188;Ll;L; +0189;Lu;L; +018A;Lu;L; +018B;Lu;L; +018C;Ll;L; +018D;Ll;L; +018E;Lu;L; +018F;Lu;L; +0190;Lu;L; +0191;Lu;L; +0192;Ll;L; +0193;Lu;L; +0194;Lu;L; +0195;Ll;L; +0196;Lu;L; +0197;Lu;L; +0198;Lu;L; +0199;Ll;L; +019A;Ll;L; +019B;Ll;L; +019C;Lu;L; +019D;Lu;L; +019E;Ll;L; +019F;Lu;L; +01A0;Lu;L; +01A1;Ll;L; +01A2;Lu;L; +01A3;Ll;L; +01A4;Lu;L; +01A5;Ll;L; +01A6;Lu;L; +01A7;Lu;L; +01A8;Ll;L; +01A9;Lu;L; +01AA;Ll;L; +01AB;Ll;L; +01AC;Lu;L; +01AD;Ll;L; +01AE;Lu;L; +01AF;Lu;L; +01B0;Ll;L; +01B1;Lu;L; +01B2;Lu;L; +01B3;Lu;L; +01B4;Ll;L; +01B5;Lu;L; +01B6;Ll;L; +01B7;Lu;L; +01B8;Lu;L; +01B9;Ll;L; +01BA;Ll;L; +01BB;Lo;L; +01BC;Lu;L; +01BD;Ll;L; +01BE;Ll;L; +01BF;Ll;L; +01C0;Lo;L; +01C1;Lo;L; +01C2;Lo;L; +01C3;Lo;L; +01C4;Lu;L; +01C5;Lt;L; +01C6;Ll;L; +01C7;Lu;L; +01C8;Lt;L; +01C9;Ll;L; +01CA;Lu;L; +01CB;Lt;L; +01CC;Ll;L; +01CD;Lu;L; +01CE;Ll;L; +01CF;Lu;L; +01D0;Ll;L; +01D1;Lu;L; +01D2;Ll;L; +01D3;Lu;L; +01D4;Ll;L; +01D5;Lu;L; +01D6;Ll;L; +01D7;Lu;L; +01D8;Ll;L; +01D9;Lu;L; +01DA;Ll;L; +01DB;Lu;L; +01DC;Ll;L; +01DD;Ll;L; +01DE;Lu;L; +01DF;Ll;L; +01E0;Lu;L; +01E1;Ll;L; +01E2;Lu;L; +01E3;Ll;L; +01E4;Lu;L; +01E5;Ll;L; +01E6;Lu;L; +01E7;Ll;L; +01E8;Lu;L; +01E9;Ll;L; +01EA;Lu;L; +01EB;Ll;L; +01EC;Lu;L; +01ED;Ll;L; +01EE;Lu;L; +01EF;Ll;L; +01F0;Ll;L; +01F1;Lu;L; +01F2;Lt;L; +01F3;Ll;L; +01F4;Lu;L; +01F5;Ll;L; +01F6;Lu;L; +01F7;Lu;L; +01F8;Lu;L; +01F9;Ll;L; +01FA;Lu;L; +01FB;Ll;L; +01FC;Lu;L; +01FD;Ll;L; +01FE;Lu;L; +01FF;Ll;L; +0200;Lu;L; +0201;Ll;L; +0202;Lu;L; +0203;Ll;L; +0204;Lu;L; +0205;Ll;L; +0206;Lu;L; +0207;Ll;L; +0208;Lu;L; +0209;Ll;L; +020A;Lu;L; +020B;Ll;L; +020C;Lu;L; +020D;Ll;L; +020E;Lu;L; +020F;Ll;L; +0210;Lu;L; +0211;Ll;L; +0212;Lu;L; +0213;Ll;L; +0214;Lu;L; +0215;Ll;L; +0216;Lu;L; +0217;Ll;L; +0218;Lu;L; +0219;Ll;L; +021A;Lu;L; +021B;Ll;L; +021C;Lu;L; +021D;Ll;L; +021E;Lu;L; +021F;Ll;L; +0222;Lu;L; +0223;Ll;L; +0224;Lu;L; +0225;Ll;L; +0226;Lu;L; +0227;Ll;L; +0228;Lu;L; +0229;Ll;L; +022A;Lu;L; +022B;Ll;L; +022C;Lu;L; +022D;Ll;L; +022E;Lu;L; +022F;Ll;L; +0230;Lu;L; +0231;Ll;L; +0232;Lu;L; +0233;Ll;L; +0250;Ll;L; +0251;Ll;L; +0252;Ll;L; +0253;Ll;L; +0254;Ll;L; +0255;Ll;L; +0256;Ll;L; +0257;Ll;L; +0258;Ll;L; +0259;Ll;L; +025A;Ll;L; +025B;Ll;L; +025C;Ll;L; +025D;Ll;L; +025E;Ll;L; +025F;Ll;L; +0260;Ll;L; +0261;Ll;L; +0262;Ll;L; +0263;Ll;L; +0264;Ll;L; +0265;Ll;L; +0266;Ll;L; +0267;Ll;L; +0268;Ll;L; +0269;Ll;L; +026A;Ll;L; +026B;Ll;L; +026C;Ll;L; +026D;Ll;L; +026E;Ll;L; +026F;Ll;L; +0270;Ll;L; +0271;Ll;L; +0272;Ll;L; +0273;Ll;L; +0274;Ll;L; +0275;Ll;L; +0276;Ll;L; +0277;Ll;L; +0278;Ll;L; +0279;Ll;L; +027A;Ll;L; +027B;Ll;L; +027C;Ll;L; +027D;Ll;L; +027E;Ll;L; +027F;Ll;L; +0280;Ll;L; +0281;Ll;L; +0282;Ll;L; +0283;Ll;L; +0284;Ll;L; +0285;Ll;L; +0286;Ll;L; +0287;Ll;L; +0288;Ll;L; +0289;Ll;L; +028A;Ll;L; +028B;Ll;L; +028C;Ll;L; +028D;Ll;L; +028E;Ll;L; +028F;Ll;L; +0290;Ll;L; +0291;Ll;L; +0292;Ll;L; +0293;Ll;L; +0294;Ll;L; +0295;Ll;L; +0296;Ll;L; +0297;Ll;L; +0298;Ll;L; +0299;Ll;L; +029A;Ll;L; +029B;Ll;L; +029C;Ll;L; +029D;Ll;L; +029E;Ll;L; +029F;Ll;L; +02A0;Ll;L; +02A1;Ll;L; +02A2;Ll;L; +02A3;Ll;L; +02A4;Ll;L; +02A5;Ll;L; +02A6;Ll;L; +02A7;Ll;L; +02A8;Ll;L; +02A9;Ll;L; +02AA;Ll;L; +02AB;Ll;L; +02AC;Ll;L; +02AD;Ll;L; +02B0;Lm;L; +02B1;Lm;L; +02B2;Lm;L; +02B3;Lm;L; +02B4;Lm;L; +02B5;Lm;L; +02B6;Lm;L; +02B7;Lm;L; +02B8;Lm;L; +02B9;Sk;ON; +02BA;Sk;ON; +02BB;Lm;L; +02BC;Lm;L; +02BD;Lm;L; +02BE;Lm;L; +02BF;Lm;L; +02C0;Lm;L; +02C1;Lm;L; +02C2;Sk;ON; +02C3;Sk;ON; +02C4;Sk;ON; +02C5;Sk;ON; +02C6;Sk;ON; +02C7;Sk;ON; +02C8;Sk;ON; +02C9;Sk;ON; +02CA;Sk;ON; +02CB;Sk;ON; +02CC;Sk;ON; +02CD;Sk;ON; +02CE;Sk;ON; +02CF;Sk;ON; +02D0;Lm;L; +02D1;Lm;L; +02D2;Sk;ON; +02D3;Sk;ON; +02D4;Sk;ON; +02D5;Sk;ON; +02D6;Sk;ON; +02D7;Sk;ON; +02D8;Sk;ON; +02D9;Sk;ON; +02DA;Sk;ON; +02DB;Sk;ON; +02DC;Sk;ON; +02DD;Sk;ON; +02DE;Sk;ON; +02DF;Sk;ON; +02E0;Lm;L; +02E1;Lm;L; +02E2;Lm;L; +02E3;Lm;L; +02E4;Lm;L; +02E5;Sk;ON; +02E6;Sk;ON; +02E7;Sk;ON; +02E8;Sk;ON; +02E9;Sk;ON; +02EA;Sk;ON; +02EB;Sk;ON; +02EC;Sk;ON; +02ED;Sk;ON; +02EE;Lm;L; +0300;Mn;NSM; +0301;Mn;NSM; +0302;Mn;NSM; +0303;Mn;NSM; +0304;Mn;NSM; +0305;Mn;NSM; +0306;Mn;NSM; +0307;Mn;NSM; +0308;Mn;NSM; +0309;Mn;NSM; +030A;Mn;NSM; +030B;Mn;NSM; +030C;Mn;NSM; +030D;Mn;NSM; +030E;Mn;NSM; +030F;Mn;NSM; +0310;Mn;NSM; +0311;Mn;NSM; +0312;Mn;NSM; +0313;Mn;NSM; +0314;Mn;NSM; +0315;Mn;NSM; +0316;Mn;NSM; +0317;Mn;NSM; +0318;Mn;NSM; +0319;Mn;NSM; +031A;Mn;NSM; +031B;Mn;NSM; +031C;Mn;NSM; +031D;Mn;NSM; +031E;Mn;NSM; +031F;Mn;NSM; +0320;Mn;NSM; +0321;Mn;NSM; +0322;Mn;NSM; +0323;Mn;NSM; +0324;Mn;NSM; +0325;Mn;NSM; +0326;Mn;NSM; +0327;Mn;NSM; +0328;Mn;NSM; +0329;Mn;NSM; +032A;Mn;NSM; +032B;Mn;NSM; +032C;Mn;NSM; +032D;Mn;NSM; +032E;Mn;NSM; +032F;Mn;NSM; +0330;Mn;NSM; +0331;Mn;NSM; +0332;Mn;NSM; +0333;Mn;NSM; +0334;Mn;NSM; +0335;Mn;NSM; +0336;Mn;NSM; +0337;Mn;NSM; +0338;Mn;NSM; +0339;Mn;NSM; +033A;Mn;NSM; +033B;Mn;NSM; +033C;Mn;NSM; +033D;Mn;NSM; +033E;Mn;NSM; +033F;Mn;NSM; +0340;Mn;NSM; +0341;Mn;NSM; +0342;Mn;NSM; +0343;Mn;NSM; +0344;Mn;NSM; +0345;Mn;NSM; +0346;Mn;NSM; +0347;Mn;NSM; +0348;Mn;NSM; +0349;Mn;NSM; +034A;Mn;NSM; +034B;Mn;NSM; +034C;Mn;NSM; +034D;Mn;NSM; +034E;Mn;NSM; +0360;Mn;NSM; +0361;Mn;NSM; +0362;Mn;NSM; +0374;Sk;ON; +0375;Sk;ON; +037A;Lm;L; +037E;Po;ON; +0384;Sk;ON; +0385;Sk;ON; +0386;Lu;L; +0387;Po;ON; +0388;Lu;L; +0389;Lu;L; +038A;Lu;L; +038C;Lu;L; +038E;Lu;L; +038F;Lu;L; +0390;Ll;L; +0391;Lu;L; +0392;Lu;L; +0393;Lu;L; +0394;Lu;L; +0395;Lu;L; +0396;Lu;L; +0397;Lu;L; +0398;Lu;L; +0399;Lu;L; +039A;Lu;L; +039B;Lu;L; +039C;Lu;L; +039D;Lu;L; +039E;Lu;L; +039F;Lu;L; +03A0;Lu;L; +03A1;Lu;L; +03A3;Lu;L; +03A4;Lu;L; +03A5;Lu;L; +03A6;Lu;L; +03A7;Lu;L; +03A8;Lu;L; +03A9;Lu;L; +03AA;Lu;L; +03AB;Lu;L; +03AC;Ll;L; +03AD;Ll;L; +03AE;Ll;L; +03AF;Ll;L; +03B0;Ll;L; +03B1;Ll;L; +03B2;Ll;L; +03B3;Ll;L; +03B4;Ll;L; +03B5;Ll;L; +03B6;Ll;L; +03B7;Ll;L; +03B8;Ll;L; +03B9;Ll;L; +03BA;Ll;L; +03BB;Ll;L; +03BC;Ll;L; +03BD;Ll;L; +03BE;Ll;L; +03BF;Ll;L; +03C0;Ll;L; +03C1;Ll;L; +03C2;Ll;L; +03C3;Ll;L; +03C4;Ll;L; +03C5;Ll;L; +03C6;Ll;L; +03C7;Ll;L; +03C8;Ll;L; +03C9;Ll;L; +03CA;Ll;L; +03CB;Ll;L; +03CC;Ll;L; +03CD;Ll;L; +03CE;Ll;L; +03D0;Ll;L; +03D1;Ll;L; +03D2;Lu;L; +03D3;Lu;L; +03D4;Lu;L; +03D5;Ll;L; +03D6;Ll;L; +03D7;Ll;L; +03DA;Lu;L; +03DB;Ll;L; +03DC;Lu;L; +03DD;Ll;L; +03DE;Lu;L; +03DF;Ll;L; +03E0;Lu;L; +03E1;Ll;L; +03E2;Lu;L; +03E3;Ll;L; +03E4;Lu;L; +03E5;Ll;L; +03E6;Lu;L; +03E7;Ll;L; +03E8;Lu;L; +03E9;Ll;L; +03EA;Lu;L; +03EB;Ll;L; +03EC;Lu;L; +03ED;Ll;L; +03EE;Lu;L; +03EF;Ll;L; +03F0;Ll;L; +03F1;Ll;L; +03F2;Ll;L; +03F3;Ll;L; +03F4;Lu;L; +03F5;Ll;L; +0400;Lu;L; +0401;Lu;L; +0402;Lu;L; +0403;Lu;L; +0404;Lu;L; +0405;Lu;L; +0406;Lu;L; +0407;Lu;L; +0408;Lu;L; +0409;Lu;L; +040A;Lu;L; +040B;Lu;L; +040C;Lu;L; +040D;Lu;L; +040E;Lu;L; +040F;Lu;L; +0410;Lu;L; +0411;Lu;L; +0412;Lu;L; +0413;Lu;L; +0414;Lu;L; +0415;Lu;L; +0416;Lu;L; +0417;Lu;L; +0418;Lu;L; +0419;Lu;L; +041A;Lu;L; +041B;Lu;L; +041C;Lu;L; +041D;Lu;L; +041E;Lu;L; +041F;Lu;L; +0420;Lu;L; +0421;Lu;L; +0422;Lu;L; +0423;Lu;L; +0424;Lu;L; +0425;Lu;L; +0426;Lu;L; +0427;Lu;L; +0428;Lu;L; +0429;Lu;L; +042A;Lu;L; +042B;Lu;L; +042C;Lu;L; +042D;Lu;L; +042E;Lu;L; +042F;Lu;L; +0430;Ll;L; +0431;Ll;L; +0432;Ll;L; +0433;Ll;L; +0434;Ll;L; +0435;Ll;L; +0436;Ll;L; +0437;Ll;L; +0438;Ll;L; +0439;Ll;L; +043A;Ll;L; +043B;Ll;L; +043C;Ll;L; +043D;Ll;L; +043E;Ll;L; +043F;Ll;L; +0440;Ll;L; +0441;Ll;L; +0442;Ll;L; +0443;Ll;L; +0444;Ll;L; +0445;Ll;L; +0446;Ll;L; +0447;Ll;L; +0448;Ll;L; +0449;Ll;L; +044A;Ll;L; +044B;Ll;L; +044C;Ll;L; +044D;Ll;L; +044E;Ll;L; +044F;Ll;L; +0450;Ll;L; +0451;Ll;L; +0452;Ll;L; +0453;Ll;L; +0454;Ll;L; +0455;Ll;L; +0456;Ll;L; +0457;Ll;L; +0458;Ll;L; +0459;Ll;L; +045A;Ll;L; +045B;Ll;L; +045C;Ll;L; +045D;Ll;L; +045E;Ll;L; +045F;Ll;L; +0460;Lu;L; +0461;Ll;L; +0462;Lu;L; +0463;Ll;L; +0464;Lu;L; +0465;Ll;L; +0466;Lu;L; +0467;Ll;L; +0468;Lu;L; +0469;Ll;L; +046A;Lu;L; +046B;Ll;L; +046C;Lu;L; +046D;Ll;L; +046E;Lu;L; +046F;Ll;L; +0470;Lu;L; +0471;Ll;L; +0472;Lu;L; +0473;Ll;L; +0474;Lu;L; +0475;Ll;L; +0476;Lu;L; +0477;Ll;L; +0478;Lu;L; +0479;Ll;L; +047A;Lu;L; +047B;Ll;L; +047C;Lu;L; +047D;Ll;L; +047E;Lu;L; +047F;Ll;L; +0480;Lu;L; +0481;Ll;L; +0482;So;L; +0483;Mn;NSM; +0484;Mn;NSM; +0485;Mn;NSM; +0486;Mn;NSM; +0488;Me;NSM; +0489;Me;NSM; +048C;Lu;L; +048D;Ll;L; +048E;Lu;L; +048F;Ll;L; +0490;Lu;L; +0491;Ll;L; +0492;Lu;L; +0493;Ll;L; +0494;Lu;L; +0495;Ll;L; +0496;Lu;L; +0497;Ll;L; +0498;Lu;L; +0499;Ll;L; +049A;Lu;L; +049B;Ll;L; +049C;Lu;L; +049D;Ll;L; +049E;Lu;L; +049F;Ll;L; +04A0;Lu;L; +04A1;Ll;L; +04A2;Lu;L; +04A3;Ll;L; +04A4;Lu;L; +04A5;Ll;L; +04A6;Lu;L; +04A7;Ll;L; +04A8;Lu;L; +04A9;Ll;L; +04AA;Lu;L; +04AB;Ll;L; +04AC;Lu;L; +04AD;Ll;L; +04AE;Lu;L; +04AF;Ll;L; +04B0;Lu;L; +04B1;Ll;L; +04B2;Lu;L; +04B3;Ll;L; +04B4;Lu;L; +04B5;Ll;L; +04B6;Lu;L; +04B7;Ll;L; +04B8;Lu;L; +04B9;Ll;L; +04BA;Lu;L; +04BB;Ll;L; +04BC;Lu;L; +04BD;Ll;L; +04BE;Lu;L; +04BF;Ll;L; +04C0;Lu;L; +04C1;Lu;L; +04C2;Ll;L; +04C3;Lu;L; +04C4;Ll;L; +04C7;Lu;L; +04C8;Ll;L; +04CB;Lu;L; +04CC;Ll;L; +04D0;Lu;L; +04D1;Ll;L; +04D2;Lu;L; +04D3;Ll;L; +04D4;Lu;L; +04D5;Ll;L; +04D6;Lu;L; +04D7;Ll;L; +04D8;Lu;L; +04D9;Ll;L; +04DA;Lu;L; +04DB;Ll;L; +04DC;Lu;L; +04DD;Ll;L; +04DE;Lu;L; +04DF;Ll;L; +04E0;Lu;L; +04E1;Ll;L; +04E2;Lu;L; +04E3;Ll;L; +04E4;Lu;L; +04E5;Ll;L; +04E6;Lu;L; +04E7;Ll;L; +04E8;Lu;L; +04E9;Ll;L; +04EA;Lu;L; +04EB;Ll;L; +04EC;Lu;L; +04ED;Ll;L; +04EE;Lu;L; +04EF;Ll;L; +04F0;Lu;L; +04F1;Ll;L; +04F2;Lu;L; +04F3;Ll;L; +04F4;Lu;L; +04F5;Ll;L; +04F8;Lu;L; +04F9;Ll;L; +0531;Lu;L; +0532;Lu;L; +0533;Lu;L; +0534;Lu;L; +0535;Lu;L; +0536;Lu;L; +0537;Lu;L; +0538;Lu;L; +0539;Lu;L; +053A;Lu;L; +053B;Lu;L; +053C;Lu;L; +053D;Lu;L; +053E;Lu;L; +053F;Lu;L; +0540;Lu;L; +0541;Lu;L; +0542;Lu;L; +0543;Lu;L; +0544;Lu;L; +0545;Lu;L; +0546;Lu;L; +0547;Lu;L; +0548;Lu;L; +0549;Lu;L; +054A;Lu;L; +054B;Lu;L; +054C;Lu;L; +054D;Lu;L; +054E;Lu;L; +054F;Lu;L; +0550;Lu;L; +0551;Lu;L; +0552;Lu;L; +0553;Lu;L; +0554;Lu;L; +0555;Lu;L; +0556;Lu;L; +0559;Lm;L; +055A;Po;L; +055B;Po;L; +055C;Po;L; +055D;Po;L; +055E;Po;L; +055F;Po;L; +0561;Ll;L; +0562;Ll;L; +0563;Ll;L; +0564;Ll;L; +0565;Ll;L; +0566;Ll;L; +0567;Ll;L; +0568;Ll;L; +0569;Ll;L; +056A;Ll;L; +056B;Ll;L; +056C;Ll;L; +056D;Ll;L; +056E;Ll;L; +056F;Ll;L; +0570;Ll;L; +0571;Ll;L; +0572;Ll;L; +0573;Ll;L; +0574;Ll;L; +0575;Ll;L; +0576;Ll;L; +0577;Ll;L; +0578;Ll;L; +0579;Ll;L; +057A;Ll;L; +057B;Ll;L; +057C;Ll;L; +057D;Ll;L; +057E;Ll;L; +057F;Ll;L; +0580;Ll;L; +0581;Ll;L; +0582;Ll;L; +0583;Ll;L; +0584;Ll;L; +0585;Ll;L; +0586;Ll;L; +0587;Ll;L; +0589;Po;L; +058A;Pd;ON; +0591;Mn;NSM; +0592;Mn;NSM; +0593;Mn;NSM; +0594;Mn;NSM; +0595;Mn;NSM; +0596;Mn;NSM; +0597;Mn;NSM; +0598;Mn;NSM; +0599;Mn;NSM; +059A;Mn;NSM; +059B;Mn;NSM; +059C;Mn;NSM; +059D;Mn;NSM; +059E;Mn;NSM; +059F;Mn;NSM; +05A0;Mn;NSM; +05A1;Mn;NSM; +05A3;Mn;NSM; +05A4;Mn;NSM; +05A5;Mn;NSM; +05A6;Mn;NSM; +05A7;Mn;NSM; +05A8;Mn;NSM; +05A9;Mn;NSM; +05AA;Mn;NSM; +05AB;Mn;NSM; +05AC;Mn;NSM; +05AD;Mn;NSM; +05AE;Mn;NSM; +05AF;Mn;NSM; +05B0;Mn;NSM; +05B1;Mn;NSM; +05B2;Mn;NSM; +05B3;Mn;NSM; +05B4;Mn;NSM; +05B5;Mn;NSM; +05B6;Mn;NSM; +05B7;Mn;NSM; +05B8;Mn;NSM; +05B9;Mn;NSM; +05BB;Mn;NSM; +05BC;Mn;NSM; +05BD;Mn;NSM; +05BE;Po;R; +05BF;Mn;NSM; +05C0;Po;R; +05C1;Mn;NSM; +05C2;Mn;NSM; +05C3;Po;R; +05C4;Mn;NSM; +05D0;Lo;R; +05D1;Lo;R; +05D2;Lo;R; +05D3;Lo;R; +05D4;Lo;R; +05D5;Lo;R; +05D6;Lo;R; +05D7;Lo;R; +05D8;Lo;R; +05D9;Lo;R; +05DA;Lo;R; +05DB;Lo;R; +05DC;Lo;R; +05DD;Lo;R; +05DE;Lo;R; +05DF;Lo;R; +05E0;Lo;R; +05E1;Lo;R; +05E2;Lo;R; +05E3;Lo;R; +05E4;Lo;R; +05E5;Lo;R; +05E6;Lo;R; +05E7;Lo;R; +05E8;Lo;R; +05E9;Lo;R; +05EA;Lo;R; +05F0;Lo;R; +05F1;Lo;R; +05F2;Lo;R; +05F3;Po;R; +05F4;Po;R; +060C;Po;CS; +061B;Po;AL; +061F;Po;AL; +0621;Lo;AL; +0622;Lo;AL; +0623;Lo;AL; +0624;Lo;AL; +0625;Lo;AL; +0626;Lo;AL; +0627;Lo;AL; +0628;Lo;AL; +0629;Lo;AL; +062A;Lo;AL; +062B;Lo;AL; +062C;Lo;AL; +062D;Lo;AL; +062E;Lo;AL; +062F;Lo;AL; +0630;Lo;AL; +0631;Lo;AL; +0632;Lo;AL; +0633;Lo;AL; +0634;Lo;AL; +0635;Lo;AL; +0636;Lo;AL; +0637;Lo;AL; +0638;Lo;AL; +0639;Lo;AL; +063A;Lo;AL; +0640;Lm;AL; +0641;Lo;AL; +0642;Lo;AL; +0643;Lo;AL; +0644;Lo;AL; +0645;Lo;AL; +0646;Lo;AL; +0647;Lo;AL; +0648;Lo;AL; +0649;Lo;AL; +064A;Lo;AL; +064B;Mn;NSM; +064C;Mn;NSM; +064D;Mn;NSM; +064E;Mn;NSM; +064F;Mn;NSM; +0650;Mn;NSM; +0651;Mn;NSM; +0652;Mn;NSM; +0653;Mn;NSM; +0654;Mn;NSM; +0655;Mn;NSM; +0660;Nd;AN; +0661;Nd;AN; +0662;Nd;AN; +0663;Nd;AN; +0664;Nd;AN; +0665;Nd;AN; +0666;Nd;AN; +0667;Nd;AN; +0668;Nd;AN; +0669;Nd;AN; +066A;Po;ET; +066B;Po;AN; +066C;Po;AN; +066D;Po;AL; +0670;Mn;NSM; +0671;Lo;AL; +0672;Lo;AL; +0673;Lo;AL; +0674;Lo;AL; +0675;Lo;AL; +0676;Lo;AL; +0677;Lo;AL; +0678;Lo;AL; +0679;Lo;AL; +067A;Lo;AL; +067B;Lo;AL; +067C;Lo;AL; +067D;Lo;AL; +067E;Lo;AL; +067F;Lo;AL; +0680;Lo;AL; +0681;Lo;AL; +0682;Lo;AL; +0683;Lo;AL; +0684;Lo;AL; +0685;Lo;AL; +0686;Lo;AL; +0687;Lo;AL; +0688;Lo;AL; +0689;Lo;AL; +068A;Lo;AL; +068B;Lo;AL; +068C;Lo;AL; +068D;Lo;AL; +068E;Lo;AL; +068F;Lo;AL; +0690;Lo;AL; +0691;Lo;AL; +0692;Lo;AL; +0693;Lo;AL; +0694;Lo;AL; +0695;Lo;AL; +0696;Lo;AL; +0697;Lo;AL; +0698;Lo;AL; +0699;Lo;AL; +069A;Lo;AL; +069B;Lo;AL; +069C;Lo;AL; +069D;Lo;AL; +069E;Lo;AL; +069F;Lo;AL; +06A0;Lo;AL; +06A1;Lo;AL; +06A2;Lo;AL; +06A3;Lo;AL; +06A4;Lo;AL; +06A5;Lo;AL; +06A6;Lo;AL; +06A7;Lo;AL; +06A8;Lo;AL; +06A9;Lo;AL; +06AA;Lo;AL; +06AB;Lo;AL; +06AC;Lo;AL; +06AD;Lo;AL; +06AE;Lo;AL; +06AF;Lo;AL; +06B0;Lo;AL; +06B1;Lo;AL; +06B2;Lo;AL; +06B3;Lo;AL; +06B4;Lo;AL; +06B5;Lo;AL; +06B6;Lo;AL; +06B7;Lo;AL; +06B8;Lo;AL; +06B9;Lo;AL; +06BA;Lo;AL; +06BB;Lo;AL; +06BC;Lo;AL; +06BD;Lo;AL; +06BE;Lo;AL; +06BF;Lo;AL; +06C0;Lo;AL; +06C1;Lo;AL; +06C2;Lo;AL; +06C3;Lo;AL; +06C4;Lo;AL; +06C5;Lo;AL; +06C6;Lo;AL; +06C7;Lo;AL; +06C8;Lo;AL; +06C9;Lo;AL; +06CA;Lo;AL; +06CB;Lo;AL; +06CC;Lo;AL; +06CD;Lo;AL; +06CE;Lo;AL; +06CF;Lo;AL; +06D0;Lo;AL; +06D1;Lo;AL; +06D2;Lo;AL; +06D3;Lo;AL; +06D4;Po;AL; +06D5;Lo;AL; +06D6;Mn;NSM; +06D7;Mn;NSM; +06D8;Mn;NSM; +06D9;Mn;NSM; +06DA;Mn;NSM; +06DB;Mn;NSM; +06DC;Mn;NSM; +06DD;Me;NSM; +06DE;Me;NSM; +06DF;Mn;NSM; +06E0;Mn;NSM; +06E1;Mn;NSM; +06E2;Mn;NSM; +06E3;Mn;NSM; +06E4;Mn;NSM; +06E5;Lm;AL; +06E6;Lm;AL; +06E7;Mn;NSM; +06E8;Mn;NSM; +06E9;So;ON; +06EA;Mn;NSM; +06EB;Mn;NSM; +06EC;Mn;NSM; +06ED;Mn;NSM; +06F0;Nd;EN; +06F1;Nd;EN; +06F2;Nd;EN; +06F3;Nd;EN; +06F4;Nd;EN; +06F5;Nd;EN; +06F6;Nd;EN; +06F7;Nd;EN; +06F8;Nd;EN; +06F9;Nd;EN; +06FA;Lo;AL; +06FB;Lo;AL; +06FC;Lo;AL; +06FD;So;AL; +06FE;So;AL; +0700;Po;AL; +0701;Po;AL; +0702;Po;AL; +0703;Po;AL; +0704;Po;AL; +0705;Po;AL; +0706;Po;AL; +0707;Po;AL; +0708;Po;AL; +0709;Po;AL; +070A;Po;AL; +070B;Po;AL; +070C;Po;AL; +070D;Po;AL; +070F;Cf;BN; +0710;Lo;AL; +0711;Mn;NSM; +0712;Lo;AL; +0713;Lo;AL; +0714;Lo;AL; +0715;Lo;AL; +0716;Lo;AL; +0717;Lo;AL; +0718;Lo;AL; +0719;Lo;AL; +071A;Lo;AL; +071B;Lo;AL; +071C;Lo;AL; +071D;Lo;AL; +071E;Lo;AL; +071F;Lo;AL; +0720;Lo;AL; +0721;Lo;AL; +0722;Lo;AL; +0723;Lo;AL; +0724;Lo;AL; +0725;Lo;AL; +0726;Lo;AL; +0727;Lo;AL; +0728;Lo;AL; +0729;Lo;AL; +072A;Lo;AL; +072B;Lo;AL; +072C;Lo;AL; +0730;Mn;NSM; +0731;Mn;NSM; +0732;Mn;NSM; +0733;Mn;NSM; +0734;Mn;NSM; +0735;Mn;NSM; +0736;Mn;NSM; +0737;Mn;NSM; +0738;Mn;NSM; +0739;Mn;NSM; +073A;Mn;NSM; +073B;Mn;NSM; +073C;Mn;NSM; +073D;Mn;NSM; +073E;Mn;NSM; +073F;Mn;NSM; +0740;Mn;NSM; +0741;Mn;NSM; +0742;Mn;NSM; +0743;Mn;NSM; +0744;Mn;NSM; +0745;Mn;NSM; +0746;Mn;NSM; +0747;Mn;NSM; +0748;Mn;NSM; +0749;Mn;NSM; +074A;Mn;NSM; +0780;Lo;AL; +0781;Lo;AL; +0782;Lo;AL; +0783;Lo;AL; +0784;Lo;AL; +0785;Lo;AL; +0786;Lo;AL; +0787;Lo;AL; +0788;Lo;AL; +0789;Lo;AL; +078A;Lo;AL; +078B;Lo;AL; +078C;Lo;AL; +078D;Lo;AL; +078E;Lo;AL; +078F;Lo;AL; +0790;Lo;AL; +0791;Lo;AL; +0792;Lo;AL; +0793;Lo;AL; +0794;Lo;AL; +0795;Lo;AL; +0796;Lo;AL; +0797;Lo;AL; +0798;Lo;AL; +0799;Lo;AL; +079A;Lo;AL; +079B;Lo;AL; +079C;Lo;AL; +079D;Lo;AL; +079E;Lo;AL; +079F;Lo;AL; +07A0;Lo;AL; +07A1;Lo;AL; +07A2;Lo;AL; +07A3;Lo;AL; +07A4;Lo;AL; +07A5;Lo;AL; +07A6;Mn;NSM; +07A7;Mn;NSM; +07A8;Mn;NSM; +07A9;Mn;NSM; +07AA;Mn;NSM; +07AB;Mn;NSM; +07AC;Mn;NSM; +07AD;Mn;NSM; +07AE;Mn;NSM; +07AF;Mn;NSM; +07B0;Mn;NSM; +0901;Mn;NSM; +0902;Mn;NSM; +0903;Mc;L; +0905;Lo;L; +0906;Lo;L; +0907;Lo;L; +0908;Lo;L; +0909;Lo;L; +090A;Lo;L; +090B;Lo;L; +090C;Lo;L; +090D;Lo;L; +090E;Lo;L; +090F;Lo;L; +0910;Lo;L; +0911;Lo;L; +0912;Lo;L; +0913;Lo;L; +0914;Lo;L; +0915;Lo;L; +0916;Lo;L; +0917;Lo;L; +0918;Lo;L; +0919;Lo;L; +091A;Lo;L; +091B;Lo;L; +091C;Lo;L; +091D;Lo;L; +091E;Lo;L; +091F;Lo;L; +0920;Lo;L; +0921;Lo;L; +0922;Lo;L; +0923;Lo;L; +0924;Lo;L; +0925;Lo;L; +0926;Lo;L; +0927;Lo;L; +0928;Lo;L; +0929;Lo;L; +092A;Lo;L; +092B;Lo;L; +092C;Lo;L; +092D;Lo;L; +092E;Lo;L; +092F;Lo;L; +0930;Lo;L; +0931;Lo;L; +0932;Lo;L; +0933;Lo;L; +0934;Lo;L; +0935;Lo;L; +0936;Lo;L; +0937;Lo;L; +0938;Lo;L; +0939;Lo;L; +093C;Mn;NSM; +093D;Lo;L; +093E;Mc;L; +093F;Mc;L; +0940;Mc;L; +0941;Mn;NSM; +0942;Mn;NSM; +0943;Mn;NSM; +0944;Mn;NSM; +0945;Mn;NSM; +0946;Mn;NSM; +0947;Mn;NSM; +0948;Mn;NSM; +0949;Mc;L; +094A;Mc;L; +094B;Mc;L; +094C;Mc;L; +094D;Mn;NSM; +0950;Lo;L; +0951;Mn;NSM; +0952;Mn;NSM; +0953;Mn;NSM; +0954;Mn;NSM; +0958;Lo;L; +0959;Lo;L; +095A;Lo;L; +095B;Lo;L; +095C;Lo;L; +095D;Lo;L; +095E;Lo;L; +095F;Lo;L; +0960;Lo;L; +0961;Lo;L; +0962;Mn;NSM; +0963;Mn;NSM; +0964;Po;L; +0965;Po;L; +0966;Nd;L; +0967;Nd;L; +0968;Nd;L; +0969;Nd;L; +096A;Nd;L; +096B;Nd;L; +096C;Nd;L; +096D;Nd;L; +096E;Nd;L; +096F;Nd;L; +0970;Po;L; +0981;Mn;NSM; +0982;Mc;L; +0983;Mc;L; +0985;Lo;L; +0986;Lo;L; +0987;Lo;L; +0988;Lo;L; +0989;Lo;L; +098A;Lo;L; +098B;Lo;L; +098C;Lo;L; +098F;Lo;L; +0990;Lo;L; +0993;Lo;L; +0994;Lo;L; +0995;Lo;L; +0996;Lo;L; +0997;Lo;L; +0998;Lo;L; +0999;Lo;L; +099A;Lo;L; +099B;Lo;L; +099C;Lo;L; +099D;Lo;L; +099E;Lo;L; +099F;Lo;L; +09A0;Lo;L; +09A1;Lo;L; +09A2;Lo;L; +09A3;Lo;L; +09A4;Lo;L; +09A5;Lo;L; +09A6;Lo;L; +09A7;Lo;L; +09A8;Lo;L; +09AA;Lo;L; +09AB;Lo;L; +09AC;Lo;L; +09AD;Lo;L; +09AE;Lo;L; +09AF;Lo;L; +09B0;Lo;L; +09B2;Lo;L; +09B6;Lo;L; +09B7;Lo;L; +09B8;Lo;L; +09B9;Lo;L; +09BC;Mn;NSM; +09BE;Mc;L; +09BF;Mc;L; +09C0;Mc;L; +09C1;Mn;NSM; +09C2;Mn;NSM; +09C3;Mn;NSM; +09C4;Mn;NSM; +09C7;Mc;L; +09C8;Mc;L; +09CB;Mc;L; +09CC;Mc;L; +09CD;Mn;NSM; +09D7;Mc;L; +09DC;Lo;L; +09DD;Lo;L; +09DF;Lo;L; +09E0;Lo;L; +09E1;Lo;L; +09E2;Mn;NSM; +09E3;Mn;NSM; +09E6;Nd;L; +09E7;Nd;L; +09E8;Nd;L; +09E9;Nd;L; +09EA;Nd;L; +09EB;Nd;L; +09EC;Nd;L; +09ED;Nd;L; +09EE;Nd;L; +09EF;Nd;L; +09F0;Lo;L; +09F1;Lo;L; +09F2;Sc;ET; +09F3;Sc;ET; +09F4;No;L; +09F5;No;L; +09F6;No;L; +09F7;No;L; +09F8;No;L; +09F9;No;L; +09FA;So;L; +0A02;Mn;NSM; +0A05;Lo;L; +0A06;Lo;L; +0A07;Lo;L; +0A08;Lo;L; +0A09;Lo;L; +0A0A;Lo;L; +0A0F;Lo;L; +0A10;Lo;L; +0A13;Lo;L; +0A14;Lo;L; +0A15;Lo;L; +0A16;Lo;L; +0A17;Lo;L; +0A18;Lo;L; +0A19;Lo;L; +0A1A;Lo;L; +0A1B;Lo;L; +0A1C;Lo;L; +0A1D;Lo;L; +0A1E;Lo;L; +0A1F;Lo;L; +0A20;Lo;L; +0A21;Lo;L; +0A22;Lo;L; +0A23;Lo;L; +0A24;Lo;L; +0A25;Lo;L; +0A26;Lo;L; +0A27;Lo;L; +0A28;Lo;L; +0A2A;Lo;L; +0A2B;Lo;L; +0A2C;Lo;L; +0A2D;Lo;L; +0A2E;Lo;L; +0A2F;Lo;L; +0A30;Lo;L; +0A32;Lo;L; +0A33;Lo;L; +0A35;Lo;L; +0A36;Lo;L; +0A38;Lo;L; +0A39;Lo;L; +0A3C;Mn;NSM; +0A3E;Mc;L; +0A3F;Mc;L; +0A40;Mc;L; +0A41;Mn;NSM; +0A42;Mn;NSM; +0A47;Mn;NSM; +0A48;Mn;NSM; +0A4B;Mn;NSM; +0A4C;Mn;NSM; +0A4D;Mn;NSM; +0A59;Lo;L; +0A5A;Lo;L; +0A5B;Lo;L; +0A5C;Lo;L; +0A5E;Lo;L; +0A66;Nd;L; +0A67;Nd;L; +0A68;Nd;L; +0A69;Nd;L; +0A6A;Nd;L; +0A6B;Nd;L; +0A6C;Nd;L; +0A6D;Nd;L; +0A6E;Nd;L; +0A6F;Nd;L; +0A70;Mn;NSM; +0A71;Mn;NSM; +0A72;Lo;L; +0A73;Lo;L; +0A74;Lo;L; +0A81;Mn;NSM; +0A82;Mn;NSM; +0A83;Mc;L; +0A85;Lo;L; +0A86;Lo;L; +0A87;Lo;L; +0A88;Lo;L; +0A89;Lo;L; +0A8A;Lo;L; +0A8B;Lo;L; +0A8D;Lo;L; +0A8F;Lo;L; +0A90;Lo;L; +0A91;Lo;L; +0A93;Lo;L; +0A94;Lo;L; +0A95;Lo;L; +0A96;Lo;L; +0A97;Lo;L; +0A98;Lo;L; +0A99;Lo;L; +0A9A;Lo;L; +0A9B;Lo;L; +0A9C;Lo;L; +0A9D;Lo;L; +0A9E;Lo;L; +0A9F;Lo;L; +0AA0;Lo;L; +0AA1;Lo;L; +0AA2;Lo;L; +0AA3;Lo;L; +0AA4;Lo;L; +0AA5;Lo;L; +0AA6;Lo;L; +0AA7;Lo;L; +0AA8;Lo;L; +0AAA;Lo;L; +0AAB;Lo;L; +0AAC;Lo;L; +0AAD;Lo;L; +0AAE;Lo;L; +0AAF;Lo;L; +0AB0;Lo;L; +0AB2;Lo;L; +0AB3;Lo;L; +0AB5;Lo;L; +0AB6;Lo;L; +0AB7;Lo;L; +0AB8;Lo;L; +0AB9;Lo;L; +0ABC;Mn;NSM; +0ABD;Lo;L; +0ABE;Mc;L; +0ABF;Mc;L; +0AC0;Mc;L; +0AC1;Mn;NSM; +0AC2;Mn;NSM; +0AC3;Mn;NSM; +0AC4;Mn;NSM; +0AC5;Mn;NSM; +0AC7;Mn;NSM; +0AC8;Mn;NSM; +0AC9;Mc;L; +0ACB;Mc;L; +0ACC;Mc;L; +0ACD;Mn;NSM; +0AD0;Lo;L; +0AE0;Lo;L; +0AE6;Nd;L; +0AE7;Nd;L; +0AE8;Nd;L; +0AE9;Nd;L; +0AEA;Nd;L; +0AEB;Nd;L; +0AEC;Nd;L; +0AED;Nd;L; +0AEE;Nd;L; +0AEF;Nd;L; +0B01;Mn;NSM; +0B02;Mc;L; +0B03;Mc;L; +0B05;Lo;L; +0B06;Lo;L; +0B07;Lo;L; +0B08;Lo;L; +0B09;Lo;L; +0B0A;Lo;L; +0B0B;Lo;L; +0B0C;Lo;L; +0B0F;Lo;L; +0B10;Lo;L; +0B13;Lo;L; +0B14;Lo;L; +0B15;Lo;L; +0B16;Lo;L; +0B17;Lo;L; +0B18;Lo;L; +0B19;Lo;L; +0B1A;Lo;L; +0B1B;Lo;L; +0B1C;Lo;L; +0B1D;Lo;L; +0B1E;Lo;L; +0B1F;Lo;L; +0B20;Lo;L; +0B21;Lo;L; +0B22;Lo;L; +0B23;Lo;L; +0B24;Lo;L; +0B25;Lo;L; +0B26;Lo;L; +0B27;Lo;L; +0B28;Lo;L; +0B2A;Lo;L; +0B2B;Lo;L; +0B2C;Lo;L; +0B2D;Lo;L; +0B2E;Lo;L; +0B2F;Lo;L; +0B30;Lo;L; +0B32;Lo;L; +0B33;Lo;L; +0B36;Lo;L; +0B37;Lo;L; +0B38;Lo;L; +0B39;Lo;L; +0B3C;Mn;NSM; +0B3D;Lo;L; +0B3E;Mc;L; +0B3F;Mn;NSM; +0B40;Mc;L; +0B41;Mn;NSM; +0B42;Mn;NSM; +0B43;Mn;NSM; +0B47;Mc;L; +0B48;Mc;L; +0B4B;Mc;L; +0B4C;Mc;L; +0B4D;Mn;NSM; +0B56;Mn;NSM; +0B57;Mc;L; +0B5C;Lo;L; +0B5D;Lo;L; +0B5F;Lo;L; +0B60;Lo;L; +0B61;Lo;L; +0B66;Nd;L; +0B67;Nd;L; +0B68;Nd;L; +0B69;Nd;L; +0B6A;Nd;L; +0B6B;Nd;L; +0B6C;Nd;L; +0B6D;Nd;L; +0B6E;Nd;L; +0B6F;Nd;L; +0B70;So;L; +0B82;Mn;NSM; +0B83;Mc;L; +0B85;Lo;L; +0B86;Lo;L; +0B87;Lo;L; +0B88;Lo;L; +0B89;Lo;L; +0B8A;Lo;L; +0B8E;Lo;L; +0B8F;Lo;L; +0B90;Lo;L; +0B92;Lo;L; +0B93;Lo;L; +0B94;Lo;L; +0B95;Lo;L; +0B99;Lo;L; +0B9A;Lo;L; +0B9C;Lo;L; +0B9E;Lo;L; +0B9F;Lo;L; +0BA3;Lo;L; +0BA4;Lo;L; +0BA8;Lo;L; +0BA9;Lo;L; +0BAA;Lo;L; +0BAE;Lo;L; +0BAF;Lo;L; +0BB0;Lo;L; +0BB1;Lo;L; +0BB2;Lo;L; +0BB3;Lo;L; +0BB4;Lo;L; +0BB5;Lo;L; +0BB7;Lo;L; +0BB8;Lo;L; +0BB9;Lo;L; +0BBE;Mc;L; +0BBF;Mc;L; +0BC0;Mn;NSM; +0BC1;Mc;L; +0BC2;Mc;L; +0BC6;Mc;L; +0BC7;Mc;L; +0BC8;Mc;L; +0BCA;Mc;L; +0BCB;Mc;L; +0BCC;Mc;L; +0BCD;Mn;NSM; +0BD7;Mc;L; +0BE7;Nd;L; +0BE8;Nd;L; +0BE9;Nd;L; +0BEA;Nd;L; +0BEB;Nd;L; +0BEC;Nd;L; +0BED;Nd;L; +0BEE;Nd;L; +0BEF;Nd;L; +0BF0;No;L; +0BF1;No;L; +0BF2;No;L; +0C01;Mc;L; +0C02;Mc;L; +0C03;Mc;L; +0C05;Lo;L; +0C06;Lo;L; +0C07;Lo;L; +0C08;Lo;L; +0C09;Lo;L; +0C0A;Lo;L; +0C0B;Lo;L; +0C0C;Lo;L; +0C0E;Lo;L; +0C0F;Lo;L; +0C10;Lo;L; +0C12;Lo;L; +0C13;Lo;L; +0C14;Lo;L; +0C15;Lo;L; +0C16;Lo;L; +0C17;Lo;L; +0C18;Lo;L; +0C19;Lo;L; +0C1A;Lo;L; +0C1B;Lo;L; +0C1C;Lo;L; +0C1D;Lo;L; +0C1E;Lo;L; +0C1F;Lo;L; +0C20;Lo;L; +0C21;Lo;L; +0C22;Lo;L; +0C23;Lo;L; +0C24;Lo;L; +0C25;Lo;L; +0C26;Lo;L; +0C27;Lo;L; +0C28;Lo;L; +0C2A;Lo;L; +0C2B;Lo;L; +0C2C;Lo;L; +0C2D;Lo;L; +0C2E;Lo;L; +0C2F;Lo;L; +0C30;Lo;L; +0C31;Lo;L; +0C32;Lo;L; +0C33;Lo;L; +0C35;Lo;L; +0C36;Lo;L; +0C37;Lo;L; +0C38;Lo;L; +0C39;Lo;L; +0C3E;Mn;NSM; +0C3F;Mn;NSM; +0C40;Mn;NSM; +0C41;Mc;L; +0C42;Mc;L; +0C43;Mc;L; +0C44;Mc;L; +0C46;Mn;NSM; +0C47;Mn;NSM; +0C48;Mn;NSM; +0C4A;Mn;NSM; +0C4B;Mn;NSM; +0C4C;Mn;NSM; +0C4D;Mn;NSM; +0C55;Mn;NSM; +0C56;Mn;NSM; +0C60;Lo;L; +0C61;Lo;L; +0C66;Nd;L; +0C67;Nd;L; +0C68;Nd;L; +0C69;Nd;L; +0C6A;Nd;L; +0C6B;Nd;L; +0C6C;Nd;L; +0C6D;Nd;L; +0C6E;Nd;L; +0C6F;Nd;L; +0C82;Mc;L; +0C83;Mc;L; +0C85;Lo;L; +0C86;Lo;L; +0C87;Lo;L; +0C88;Lo;L; +0C89;Lo;L; +0C8A;Lo;L; +0C8B;Lo;L; +0C8C;Lo;L; +0C8E;Lo;L; +0C8F;Lo;L; +0C90;Lo;L; +0C92;Lo;L; +0C93;Lo;L; +0C94;Lo;L; +0C95;Lo;L; +0C96;Lo;L; +0C97;Lo;L; +0C98;Lo;L; +0C99;Lo;L; +0C9A;Lo;L; +0C9B;Lo;L; +0C9C;Lo;L; +0C9D;Lo;L; +0C9E;Lo;L; +0C9F;Lo;L; +0CA0;Lo;L; +0CA1;Lo;L; +0CA2;Lo;L; +0CA3;Lo;L; +0CA4;Lo;L; +0CA5;Lo;L; +0CA6;Lo;L; +0CA7;Lo;L; +0CA8;Lo;L; +0CAA;Lo;L; +0CAB;Lo;L; +0CAC;Lo;L; +0CAD;Lo;L; +0CAE;Lo;L; +0CAF;Lo;L; +0CB0;Lo;L; +0CB1;Lo;L; +0CB2;Lo;L; +0CB3;Lo;L; +0CB5;Lo;L; +0CB6;Lo;L; +0CB7;Lo;L; +0CB8;Lo;L; +0CB9;Lo;L; +0CBE;Mc;L; +0CBF;Mn;NSM; +0CC0;Mc;L; +0CC1;Mc;L; +0CC2;Mc;L; +0CC3;Mc;L; +0CC4;Mc;L; +0CC6;Mn;NSM; +0CC7;Mc;L; +0CC8;Mc;L; +0CCA;Mc;L; +0CCB;Mc;L; +0CCC;Mn;NSM; +0CCD;Mn;NSM; +0CD5;Mc;L; +0CD6;Mc;L; +0CDE;Lo;L; +0CE0;Lo;L; +0CE1;Lo;L; +0CE6;Nd;L; +0CE7;Nd;L; +0CE8;Nd;L; +0CE9;Nd;L; +0CEA;Nd;L; +0CEB;Nd;L; +0CEC;Nd;L; +0CED;Nd;L; +0CEE;Nd;L; +0CEF;Nd;L; +0D02;Mc;L; +0D03;Mc;L; +0D05;Lo;L; +0D06;Lo;L; +0D07;Lo;L; +0D08;Lo;L; +0D09;Lo;L; +0D0A;Lo;L; +0D0B;Lo;L; +0D0C;Lo;L; +0D0E;Lo;L; +0D0F;Lo;L; +0D10;Lo;L; +0D12;Lo;L; +0D13;Lo;L; +0D14;Lo;L; +0D15;Lo;L; +0D16;Lo;L; +0D17;Lo;L; +0D18;Lo;L; +0D19;Lo;L; +0D1A;Lo;L; +0D1B;Lo;L; +0D1C;Lo;L; +0D1D;Lo;L; +0D1E;Lo;L; +0D1F;Lo;L; +0D20;Lo;L; +0D21;Lo;L; +0D22;Lo;L; +0D23;Lo;L; +0D24;Lo;L; +0D25;Lo;L; +0D26;Lo;L; +0D27;Lo;L; +0D28;Lo;L; +0D2A;Lo;L; +0D2B;Lo;L; +0D2C;Lo;L; +0D2D;Lo;L; +0D2E;Lo;L; +0D2F;Lo;L; +0D30;Lo;L; +0D31;Lo;L; +0D32;Lo;L; +0D33;Lo;L; +0D34;Lo;L; +0D35;Lo;L; +0D36;Lo;L; +0D37;Lo;L; +0D38;Lo;L; +0D39;Lo;L; +0D3E;Mc;L; +0D3F;Mc;L; +0D40;Mc;L; +0D41;Mn;NSM; +0D42;Mn;NSM; +0D43;Mn;NSM; +0D46;Mc;L; +0D47;Mc;L; +0D48;Mc;L; +0D4A;Mc;L; +0D4B;Mc;L; +0D4C;Mc;L; +0D4D;Mn;NSM; +0D57;Mc;L; +0D60;Lo;L; +0D61;Lo;L; +0D66;Nd;L; +0D67;Nd;L; +0D68;Nd;L; +0D69;Nd;L; +0D6A;Nd;L; +0D6B;Nd;L; +0D6C;Nd;L; +0D6D;Nd;L; +0D6E;Nd;L; +0D6F;Nd;L; +0D82;Mc;L; +0D83;Mc;L; +0D85;Lo;L; +0D86;Lo;L; +0D87;Lo;L; +0D88;Lo;L; +0D89;Lo;L; +0D8A;Lo;L; +0D8B;Lo;L; +0D8C;Lo;L; +0D8D;Lo;L; +0D8E;Lo;L; +0D8F;Lo;L; +0D90;Lo;L; +0D91;Lo;L; +0D92;Lo;L; +0D93;Lo;L; +0D94;Lo;L; +0D95;Lo;L; +0D96;Lo;L; +0D9A;Lo;L; +0D9B;Lo;L; +0D9C;Lo;L; +0D9D;Lo;L; +0D9E;Lo;L; +0D9F;Lo;L; +0DA0;Lo;L; +0DA1;Lo;L; +0DA2;Lo;L; +0DA3;Lo;L; +0DA4;Lo;L; +0DA5;Lo;L; +0DA6;Lo;L; +0DA7;Lo;L; +0DA8;Lo;L; +0DA9;Lo;L; +0DAA;Lo;L; +0DAB;Lo;L; +0DAC;Lo;L; +0DAD;Lo;L; +0DAE;Lo;L; +0DAF;Lo;L; +0DB0;Lo;L; +0DB1;Lo;L; +0DB3;Lo;L; +0DB4;Lo;L; +0DB5;Lo;L; +0DB6;Lo;L; +0DB7;Lo;L; +0DB8;Lo;L; +0DB9;Lo;L; +0DBA;Lo;L; +0DBB;Lo;L; +0DBD;Lo;L; +0DC0;Lo;L; +0DC1;Lo;L; +0DC2;Lo;L; +0DC3;Lo;L; +0DC4;Lo;L; +0DC5;Lo;L; +0DC6;Lo;L; +0DCA;Mn;NSM; +0DCF;Mc;L; +0DD0;Mc;L; +0DD1;Mc;L; +0DD2;Mn;NSM; +0DD3;Mn;NSM; +0DD4;Mn;NSM; +0DD6;Mn;NSM; +0DD8;Mc;L; +0DD9;Mc;L; +0DDA;Mc;L; +0DDB;Mc;L; +0DDC;Mc;L; +0DDD;Mc;L; +0DDE;Mc;L; +0DDF;Mc;L; +0DF2;Mc;L; +0DF3;Mc;L; +0DF4;Po;L; +0E01;Lo;L; +0E02;Lo;L; +0E03;Lo;L; +0E04;Lo;L; +0E05;Lo;L; +0E06;Lo;L; +0E07;Lo;L; +0E08;Lo;L; +0E09;Lo;L; +0E0A;Lo;L; +0E0B;Lo;L; +0E0C;Lo;L; +0E0D;Lo;L; +0E0E;Lo;L; +0E0F;Lo;L; +0E10;Lo;L; +0E11;Lo;L; +0E12;Lo;L; +0E13;Lo;L; +0E14;Lo;L; +0E15;Lo;L; +0E16;Lo;L; +0E17;Lo;L; +0E18;Lo;L; +0E19;Lo;L; +0E1A;Lo;L; +0E1B;Lo;L; +0E1C;Lo;L; +0E1D;Lo;L; +0E1E;Lo;L; +0E1F;Lo;L; +0E20;Lo;L; +0E21;Lo;L; +0E22;Lo;L; +0E23;Lo;L; +0E24;Lo;L; +0E25;Lo;L; +0E26;Lo;L; +0E27;Lo;L; +0E28;Lo;L; +0E29;Lo;L; +0E2A;Lo;L; +0E2B;Lo;L; +0E2C;Lo;L; +0E2D;Lo;L; +0E2E;Lo;L; +0E2F;Lo;L; +0E30;Lo;L; +0E31;Mn;NSM; +0E32;Lo;L; +0E33;Lo;L; +0E34;Mn;NSM; +0E35;Mn;NSM; +0E36;Mn;NSM; +0E37;Mn;NSM; +0E38;Mn;NSM; +0E39;Mn;NSM; +0E3A;Mn;NSM; +0E3F;Sc;ET; +0E40;Lo;L; +0E41;Lo;L; +0E42;Lo;L; +0E43;Lo;L; +0E44;Lo;L; +0E45;Lo;L; +0E46;Lm;L; +0E47;Mn;NSM; +0E48;Mn;NSM; +0E49;Mn;NSM; +0E4A;Mn;NSM; +0E4B;Mn;NSM; +0E4C;Mn;NSM; +0E4D;Mn;NSM; +0E4E;Mn;NSM; +0E4F;Po;L; +0E50;Nd;L; +0E51;Nd;L; +0E52;Nd;L; +0E53;Nd;L; +0E54;Nd;L; +0E55;Nd;L; +0E56;Nd;L; +0E57;Nd;L; +0E58;Nd;L; +0E59;Nd;L; +0E5A;Po;L; +0E5B;Po;L; +0E81;Lo;L; +0E82;Lo;L; +0E84;Lo;L; +0E87;Lo;L; +0E88;Lo;L; +0E8A;Lo;L; +0E8D;Lo;L; +0E94;Lo;L; +0E95;Lo;L; +0E96;Lo;L; +0E97;Lo;L; +0E99;Lo;L; +0E9A;Lo;L; +0E9B;Lo;L; +0E9C;Lo;L; +0E9D;Lo;L; +0E9E;Lo;L; +0E9F;Lo;L; +0EA1;Lo;L; +0EA2;Lo;L; +0EA3;Lo;L; +0EA5;Lo;L; +0EA7;Lo;L; +0EAA;Lo;L; +0EAB;Lo;L; +0EAD;Lo;L; +0EAE;Lo;L; +0EAF;Lo;L; +0EB0;Lo;L; +0EB1;Mn;NSM; +0EB2;Lo;L; +0EB3;Lo;L; +0EB4;Mn;NSM; +0EB5;Mn;NSM; +0EB6;Mn;NSM; +0EB7;Mn;NSM; +0EB8;Mn;NSM; +0EB9;Mn;NSM; +0EBB;Mn;NSM; +0EBC;Mn;NSM; +0EBD;Lo;L; +0EC0;Lo;L; +0EC1;Lo;L; +0EC2;Lo;L; +0EC3;Lo;L; +0EC4;Lo;L; +0EC6;Lm;L; +0EC8;Mn;NSM; +0EC9;Mn;NSM; +0ECA;Mn;NSM; +0ECB;Mn;NSM; +0ECC;Mn;NSM; +0ECD;Mn;NSM; +0ED0;Nd;L; +0ED1;Nd;L; +0ED2;Nd;L; +0ED3;Nd;L; +0ED4;Nd;L; +0ED5;Nd;L; +0ED6;Nd;L; +0ED7;Nd;L; +0ED8;Nd;L; +0ED9;Nd;L; +0EDC;Lo;L; +0EDD;Lo;L; +0F00;Lo;L; +0F01;So;L; +0F02;So;L; +0F03;So;L; +0F04;Po;L; +0F05;Po;L; +0F06;Po;L; +0F07;Po;L; +0F08;Po;L; +0F09;Po;L; +0F0A;Po;L; +0F0B;Po;L; +0F0C;Po;L; +0F0D;Po;L; +0F0E;Po;L; +0F0F;Po;L; +0F10;Po;L; +0F11;Po;L; +0F12;Po;L; +0F13;So;L; +0F14;So;L; +0F15;So;L; +0F16;So;L; +0F17;So;L; +0F18;Mn;NSM; +0F19;Mn;NSM; +0F1A;So;L; +0F1B;So;L; +0F1C;So;L; +0F1D;So;L; +0F1E;So;L; +0F1F;So;L; +0F20;Nd;L; +0F21;Nd;L; +0F22;Nd;L; +0F23;Nd;L; +0F24;Nd;L; +0F25;Nd;L; +0F26;Nd;L; +0F27;Nd;L; +0F28;Nd;L; +0F29;Nd;L; +0F2A;No;L; +0F2B;No;L; +0F2C;No;L; +0F2D;No;L; +0F2E;No;L; +0F2F;No;L; +0F30;No;L; +0F31;No;L; +0F32;No;L; +0F33;No;L; +0F34;So;L; +0F35;Mn;NSM; +0F36;So;L; +0F37;Mn;NSM; +0F38;So;L; +0F39;Mn;NSM; +0F3A;Ps;ON; +0F3B;Pe;ON; +0F3C;Ps;ON; +0F3D;Pe;ON; +0F3E;Mc;L; +0F3F;Mc;L; +0F40;Lo;L; +0F41;Lo;L; +0F42;Lo;L; +0F43;Lo;L; +0F44;Lo;L; +0F45;Lo;L; +0F46;Lo;L; +0F47;Lo;L; +0F49;Lo;L; +0F4A;Lo;L; +0F4B;Lo;L; +0F4C;Lo;L; +0F4D;Lo;L; +0F4E;Lo;L; +0F4F;Lo;L; +0F50;Lo;L; +0F51;Lo;L; +0F52;Lo;L; +0F53;Lo;L; +0F54;Lo;L; +0F55;Lo;L; +0F56;Lo;L; +0F57;Lo;L; +0F58;Lo;L; +0F59;Lo;L; +0F5A;Lo;L; +0F5B;Lo;L; +0F5C;Lo;L; +0F5D;Lo;L; +0F5E;Lo;L; +0F5F;Lo;L; +0F60;Lo;L; +0F61;Lo;L; +0F62;Lo;L; +0F63;Lo;L; +0F64;Lo;L; +0F65;Lo;L; +0F66;Lo;L; +0F67;Lo;L; +0F68;Lo;L; +0F69;Lo;L; +0F6A;Lo;L; +0F71;Mn;NSM; +0F72;Mn;NSM; +0F73;Mn;NSM; +0F74;Mn;NSM; +0F75;Mn;NSM; +0F76;Mn;NSM; +0F77;Mn;NSM; +0F78;Mn;NSM; +0F79;Mn;NSM; +0F7A;Mn;NSM; +0F7B;Mn;NSM; +0F7C;Mn;NSM; +0F7D;Mn;NSM; +0F7E;Mn;NSM; +0F7F;Mc;L; +0F80;Mn;NSM; +0F81;Mn;NSM; +0F82;Mn;NSM; +0F83;Mn;NSM; +0F84;Mn;NSM; +0F85;Po;L; +0F86;Mn;NSM; +0F87;Mn;NSM; +0F88;Lo;L; +0F89;Lo;L; +0F8A;Lo;L; +0F8B;Lo;L; +0F90;Mn;NSM; +0F91;Mn;NSM; +0F92;Mn;NSM; +0F93;Mn;NSM; +0F94;Mn;NSM; +0F95;Mn;NSM; +0F96;Mn;NSM; +0F97;Mn;NSM; +0F99;Mn;NSM; +0F9A;Mn;NSM; +0F9B;Mn;NSM; +0F9C;Mn;NSM; +0F9D;Mn;NSM; +0F9E;Mn;NSM; +0F9F;Mn;NSM; +0FA0;Mn;NSM; +0FA1;Mn;NSM; +0FA2;Mn;NSM; +0FA3;Mn;NSM; +0FA4;Mn;NSM; +0FA5;Mn;NSM; +0FA6;Mn;NSM; +0FA7;Mn;NSM; +0FA8;Mn;NSM; +0FA9;Mn;NSM; +0FAA;Mn;NSM; +0FAB;Mn;NSM; +0FAC;Mn;NSM; +0FAD;Mn;NSM; +0FAE;Mn;NSM; +0FAF;Mn;NSM; +0FB0;Mn;NSM; +0FB1;Mn;NSM; +0FB2;Mn;NSM; +0FB3;Mn;NSM; +0FB4;Mn;NSM; +0FB5;Mn;NSM; +0FB6;Mn;NSM; +0FB7;Mn;NSM; +0FB8;Mn;NSM; +0FB9;Mn;NSM; +0FBA;Mn;NSM; +0FBB;Mn;NSM; +0FBC;Mn;NSM; +0FBE;So;L; +0FBF;So;L; +0FC0;So;L; +0FC1;So;L; +0FC2;So;L; +0FC3;So;L; +0FC4;So;L; +0FC5;So;L; +0FC6;Mn;NSM; +0FC7;So;L; +0FC8;So;L; +0FC9;So;L; +0FCA;So;L; +0FCB;So;L; +0FCC;So;L; +0FCF;So;L; +1000;Lo;L; +1001;Lo;L; +1002;Lo;L; +1003;Lo;L; +1004;Lo;L; +1005;Lo;L; +1006;Lo;L; +1007;Lo;L; +1008;Lo;L; +1009;Lo;L; +100A;Lo;L; +100B;Lo;L; +100C;Lo;L; +100D;Lo;L; +100E;Lo;L; +100F;Lo;L; +1010;Lo;L; +1011;Lo;L; +1012;Lo;L; +1013;Lo;L; +1014;Lo;L; +1015;Lo;L; +1016;Lo;L; +1017;Lo;L; +1018;Lo;L; +1019;Lo;L; +101A;Lo;L; +101B;Lo;L; +101C;Lo;L; +101D;Lo;L; +101E;Lo;L; +101F;Lo;L; +1020;Lo;L; +1021;Lo;L; +1023;Lo;L; +1024;Lo;L; +1025;Lo;L; +1026;Lo;L; +1027;Lo;L; +1029;Lo;L; +102A;Lo;L; +102C;Mc;L; +102D;Mn;NSM; +102E;Mn;NSM; +102F;Mn;NSM; +1030;Mn;NSM; +1031;Mc;L; +1032;Mn;NSM; +1036;Mn;NSM; +1037;Mn;NSM; +1038;Mc;L; +1039;Mn;NSM; +1040;Nd;L; +1041;Nd;L; +1042;Nd;L; +1043;Nd;L; +1044;Nd;L; +1045;Nd;L; +1046;Nd;L; +1047;Nd;L; +1048;Nd;L; +1049;Nd;L; +104A;Po;L; +104B;Po;L; +104C;Po;L; +104D;Po;L; +104E;Po;L; +104F;Po;L; +1050;Lo;L; +1051;Lo;L; +1052;Lo;L; +1053;Lo;L; +1054;Lo;L; +1055;Lo;L; +1056;Mc;L; +1057;Mc;L; +1058;Mn;NSM; +1059;Mn;NSM; +10A0;Lu;L; +10A1;Lu;L; +10A2;Lu;L; +10A3;Lu;L; +10A4;Lu;L; +10A5;Lu;L; +10A6;Lu;L; +10A7;Lu;L; +10A8;Lu;L; +10A9;Lu;L; +10AA;Lu;L; +10AB;Lu;L; +10AC;Lu;L; +10AD;Lu;L; +10AE;Lu;L; +10AF;Lu;L; +10B0;Lu;L; +10B1;Lu;L; +10B2;Lu;L; +10B3;Lu;L; +10B4;Lu;L; +10B5;Lu;L; +10B6;Lu;L; +10B7;Lu;L; +10B8;Lu;L; +10B9;Lu;L; +10BA;Lu;L; +10BB;Lu;L; +10BC;Lu;L; +10BD;Lu;L; +10BE;Lu;L; +10BF;Lu;L; +10C0;Lu;L; +10C1;Lu;L; +10C2;Lu;L; +10C3;Lu;L; +10C4;Lu;L; +10C5;Lu;L; +10D0;Lo;L; +10D1;Lo;L; +10D2;Lo;L; +10D3;Lo;L; +10D4;Lo;L; +10D5;Lo;L; +10D6;Lo;L; +10D7;Lo;L; +10D8;Lo;L; +10D9;Lo;L; +10DA;Lo;L; +10DB;Lo;L; +10DC;Lo;L; +10DD;Lo;L; +10DE;Lo;L; +10DF;Lo;L; +10E0;Lo;L; +10E1;Lo;L; +10E2;Lo;L; +10E3;Lo;L; +10E4;Lo;L; +10E5;Lo;L; +10E6;Lo;L; +10E7;Lo;L; +10E8;Lo;L; +10E9;Lo;L; +10EA;Lo;L; +10EB;Lo;L; +10EC;Lo;L; +10ED;Lo;L; +10EE;Lo;L; +10EF;Lo;L; +10F0;Lo;L; +10F1;Lo;L; +10F2;Lo;L; +10F3;Lo;L; +10F4;Lo;L; +10F5;Lo;L; +10F6;Lo;L; +10FB;Po;L; +1100;Lo;L; +1101;Lo;L; +1102;Lo;L; +1103;Lo;L; +1104;Lo;L; +1105;Lo;L; +1106;Lo;L; +1107;Lo;L; +1108;Lo;L; +1109;Lo;L; +110A;Lo;L; +110B;Lo;L; +110C;Lo;L; +110D;Lo;L; +110E;Lo;L; +110F;Lo;L; +1110;Lo;L; +1111;Lo;L; +1112;Lo;L; +1113;Lo;L; +1114;Lo;L; +1115;Lo;L; +1116;Lo;L; +1117;Lo;L; +1118;Lo;L; +1119;Lo;L; +111A;Lo;L; +111B;Lo;L; +111C;Lo;L; +111D;Lo;L; +111E;Lo;L; +111F;Lo;L; +1120;Lo;L; +1121;Lo;L; +1122;Lo;L; +1123;Lo;L; +1124;Lo;L; +1125;Lo;L; +1126;Lo;L; +1127;Lo;L; +1128;Lo;L; +1129;Lo;L; +112A;Lo;L; +112B;Lo;L; +112C;Lo;L; +112D;Lo;L; +112E;Lo;L; +112F;Lo;L; +1130;Lo;L; +1131;Lo;L; +1132;Lo;L; +1133;Lo;L; +1134;Lo;L; +1135;Lo;L; +1136;Lo;L; +1137;Lo;L; +1138;Lo;L; +1139;Lo;L; +113A;Lo;L; +113B;Lo;L; +113C;Lo;L; +113D;Lo;L; +113E;Lo;L; +113F;Lo;L; +1140;Lo;L; +1141;Lo;L; +1142;Lo;L; +1143;Lo;L; +1144;Lo;L; +1145;Lo;L; +1146;Lo;L; +1147;Lo;L; +1148;Lo;L; +1149;Lo;L; +114A;Lo;L; +114B;Lo;L; +114C;Lo;L; +114D;Lo;L; +114E;Lo;L; +114F;Lo;L; +1150;Lo;L; +1151;Lo;L; +1152;Lo;L; +1153;Lo;L; +1154;Lo;L; +1155;Lo;L; +1156;Lo;L; +1157;Lo;L; +1158;Lo;L; +1159;Lo;L; +115F;Lo;L; +1160;Lo;L; +1161;Lo;L; +1162;Lo;L; +1163;Lo;L; +1164;Lo;L; +1165;Lo;L; +1166;Lo;L; +1167;Lo;L; +1168;Lo;L; +1169;Lo;L; +116A;Lo;L; +116B;Lo;L; +116C;Lo;L; +116D;Lo;L; +116E;Lo;L; +116F;Lo;L; +1170;Lo;L; +1171;Lo;L; +1172;Lo;L; +1173;Lo;L; +1174;Lo;L; +1175;Lo;L; +1176;Lo;L; +1177;Lo;L; +1178;Lo;L; +1179;Lo;L; +117A;Lo;L; +117B;Lo;L; +117C;Lo;L; +117D;Lo;L; +117E;Lo;L; +117F;Lo;L; +1180;Lo;L; +1181;Lo;L; +1182;Lo;L; +1183;Lo;L; +1184;Lo;L; +1185;Lo;L; +1186;Lo;L; +1187;Lo;L; +1188;Lo;L; +1189;Lo;L; +118A;Lo;L; +118B;Lo;L; +118C;Lo;L; +118D;Lo;L; +118E;Lo;L; +118F;Lo;L; +1190;Lo;L; +1191;Lo;L; +1192;Lo;L; +1193;Lo;L; +1194;Lo;L; +1195;Lo;L; +1196;Lo;L; +1197;Lo;L; +1198;Lo;L; +1199;Lo;L; +119A;Lo;L; +119B;Lo;L; +119C;Lo;L; +119D;Lo;L; +119E;Lo;L; +119F;Lo;L; +11A0;Lo;L; +11A1;Lo;L; +11A2;Lo;L; +11A8;Lo;L; +11A9;Lo;L; +11AA;Lo;L; +11AB;Lo;L; +11AC;Lo;L; +11AD;Lo;L; +11AE;Lo;L; +11AF;Lo;L; +11B0;Lo;L; +11B1;Lo;L; +11B2;Lo;L; +11B3;Lo;L; +11B4;Lo;L; +11B5;Lo;L; +11B6;Lo;L; +11B7;Lo;L; +11B8;Lo;L; +11B9;Lo;L; +11BA;Lo;L; +11BB;Lo;L; +11BC;Lo;L; +11BD;Lo;L; +11BE;Lo;L; +11BF;Lo;L; +11C0;Lo;L; +11C1;Lo;L; +11C2;Lo;L; +11C3;Lo;L; +11C4;Lo;L; +11C5;Lo;L; +11C6;Lo;L; +11C7;Lo;L; +11C8;Lo;L; +11C9;Lo;L; +11CA;Lo;L; +11CB;Lo;L; +11CC;Lo;L; +11CD;Lo;L; +11CE;Lo;L; +11CF;Lo;L; +11D0;Lo;L; +11D1;Lo;L; +11D2;Lo;L; +11D3;Lo;L; +11D4;Lo;L; +11D5;Lo;L; +11D6;Lo;L; +11D7;Lo;L; +11D8;Lo;L; +11D9;Lo;L; +11DA;Lo;L; +11DB;Lo;L; +11DC;Lo;L; +11DD;Lo;L; +11DE;Lo;L; +11DF;Lo;L; +11E0;Lo;L; +11E1;Lo;L; +11E2;Lo;L; +11E3;Lo;L; +11E4;Lo;L; +11E5;Lo;L; +11E6;Lo;L; +11E7;Lo;L; +11E8;Lo;L; +11E9;Lo;L; +11EA;Lo;L; +11EB;Lo;L; +11EC;Lo;L; +11ED;Lo;L; +11EE;Lo;L; +11EF;Lo;L; +11F0;Lo;L; +11F1;Lo;L; +11F2;Lo;L; +11F3;Lo;L; +11F4;Lo;L; +11F5;Lo;L; +11F6;Lo;L; +11F7;Lo;L; +11F8;Lo;L; +11F9;Lo;L; +1200;Lo;L; +1201;Lo;L; +1202;Lo;L; +1203;Lo;L; +1204;Lo;L; +1205;Lo;L; +1206;Lo;L; +1208;Lo;L; +1209;Lo;L; +120A;Lo;L; +120B;Lo;L; +120C;Lo;L; +120D;Lo;L; +120E;Lo;L; +120F;Lo;L; +1210;Lo;L; +1211;Lo;L; +1212;Lo;L; +1213;Lo;L; +1214;Lo;L; +1215;Lo;L; +1216;Lo;L; +1217;Lo;L; +1218;Lo;L; +1219;Lo;L; +121A;Lo;L; +121B;Lo;L; +121C;Lo;L; +121D;Lo;L; +121E;Lo;L; +121F;Lo;L; +1220;Lo;L; +1221;Lo;L; +1222;Lo;L; +1223;Lo;L; +1224;Lo;L; +1225;Lo;L; +1226;Lo;L; +1227;Lo;L; +1228;Lo;L; +1229;Lo;L; +122A;Lo;L; +122B;Lo;L; +122C;Lo;L; +122D;Lo;L; +122E;Lo;L; +122F;Lo;L; +1230;Lo;L; +1231;Lo;L; +1232;Lo;L; +1233;Lo;L; +1234;Lo;L; +1235;Lo;L; +1236;Lo;L; +1237;Lo;L; +1238;Lo;L; +1239;Lo;L; +123A;Lo;L; +123B;Lo;L; +123C;Lo;L; +123D;Lo;L; +123E;Lo;L; +123F;Lo;L; +1240;Lo;L; +1241;Lo;L; +1242;Lo;L; +1243;Lo;L; +1244;Lo;L; +1245;Lo;L; +1246;Lo;L; +1248;Lo;L; +124A;Lo;L; +124B;Lo;L; +124C;Lo;L; +124D;Lo;L; +1250;Lo;L; +1251;Lo;L; +1252;Lo;L; +1253;Lo;L; +1254;Lo;L; +1255;Lo;L; +1256;Lo;L; +1258;Lo;L; +125A;Lo;L; +125B;Lo;L; +125C;Lo;L; +125D;Lo;L; +1260;Lo;L; +1261;Lo;L; +1262;Lo;L; +1263;Lo;L; +1264;Lo;L; +1265;Lo;L; +1266;Lo;L; +1267;Lo;L; +1268;Lo;L; +1269;Lo;L; +126A;Lo;L; +126B;Lo;L; +126C;Lo;L; +126D;Lo;L; +126E;Lo;L; +126F;Lo;L; +1270;Lo;L; +1271;Lo;L; +1272;Lo;L; +1273;Lo;L; +1274;Lo;L; +1275;Lo;L; +1276;Lo;L; +1277;Lo;L; +1278;Lo;L; +1279;Lo;L; +127A;Lo;L; +127B;Lo;L; +127C;Lo;L; +127D;Lo;L; +127E;Lo;L; +127F;Lo;L; +1280;Lo;L; +1281;Lo;L; +1282;Lo;L; +1283;Lo;L; +1284;Lo;L; +1285;Lo;L; +1286;Lo;L; +1288;Lo;L; +128A;Lo;L; +128B;Lo;L; +128C;Lo;L; +128D;Lo;L; +1290;Lo;L; +1291;Lo;L; +1292;Lo;L; +1293;Lo;L; +1294;Lo;L; +1295;Lo;L; +1296;Lo;L; +1297;Lo;L; +1298;Lo;L; +1299;Lo;L; +129A;Lo;L; +129B;Lo;L; +129C;Lo;L; +129D;Lo;L; +129E;Lo;L; +129F;Lo;L; +12A0;Lo;L; +12A1;Lo;L; +12A2;Lo;L; +12A3;Lo;L; +12A4;Lo;L; +12A5;Lo;L; +12A6;Lo;L; +12A7;Lo;L; +12A8;Lo;L; +12A9;Lo;L; +12AA;Lo;L; +12AB;Lo;L; +12AC;Lo;L; +12AD;Lo;L; +12AE;Lo;L; +12B0;Lo;L; +12B2;Lo;L; +12B3;Lo;L; +12B4;Lo;L; +12B5;Lo;L; +12B8;Lo;L; +12B9;Lo;L; +12BA;Lo;L; +12BB;Lo;L; +12BC;Lo;L; +12BD;Lo;L; +12BE;Lo;L; +12C0;Lo;L; +12C2;Lo;L; +12C3;Lo;L; +12C4;Lo;L; +12C5;Lo;L; +12C8;Lo;L; +12C9;Lo;L; +12CA;Lo;L; +12CB;Lo;L; +12CC;Lo;L; +12CD;Lo;L; +12CE;Lo;L; +12D0;Lo;L; +12D1;Lo;L; +12D2;Lo;L; +12D3;Lo;L; +12D4;Lo;L; +12D5;Lo;L; +12D6;Lo;L; +12D8;Lo;L; +12D9;Lo;L; +12DA;Lo;L; +12DB;Lo;L; +12DC;Lo;L; +12DD;Lo;L; +12DE;Lo;L; +12DF;Lo;L; +12E0;Lo;L; +12E1;Lo;L; +12E2;Lo;L; +12E3;Lo;L; +12E4;Lo;L; +12E5;Lo;L; +12E6;Lo;L; +12E7;Lo;L; +12E8;Lo;L; +12E9;Lo;L; +12EA;Lo;L; +12EB;Lo;L; +12EC;Lo;L; +12ED;Lo;L; +12EE;Lo;L; +12F0;Lo;L; +12F1;Lo;L; +12F2;Lo;L; +12F3;Lo;L; +12F4;Lo;L; +12F5;Lo;L; +12F6;Lo;L; +12F7;Lo;L; +12F8;Lo;L; +12F9;Lo;L; +12FA;Lo;L; +12FB;Lo;L; +12FC;Lo;L; +12FD;Lo;L; +12FE;Lo;L; +12FF;Lo;L; +1300;Lo;L; +1301;Lo;L; +1302;Lo;L; +1303;Lo;L; +1304;Lo;L; +1305;Lo;L; +1306;Lo;L; +1307;Lo;L; +1308;Lo;L; +1309;Lo;L; +130A;Lo;L; +130B;Lo;L; +130C;Lo;L; +130D;Lo;L; +130E;Lo;L; +1310;Lo;L; +1312;Lo;L; +1313;Lo;L; +1314;Lo;L; +1315;Lo;L; +1318;Lo;L; +1319;Lo;L; +131A;Lo;L; +131B;Lo;L; +131C;Lo;L; +131D;Lo;L; +131E;Lo;L; +1320;Lo;L; +1321;Lo;L; +1322;Lo;L; +1323;Lo;L; +1324;Lo;L; +1325;Lo;L; +1326;Lo;L; +1327;Lo;L; +1328;Lo;L; +1329;Lo;L; +132A;Lo;L; +132B;Lo;L; +132C;Lo;L; +132D;Lo;L; +132E;Lo;L; +132F;Lo;L; +1330;Lo;L; +1331;Lo;L; +1332;Lo;L; +1333;Lo;L; +1334;Lo;L; +1335;Lo;L; +1336;Lo;L; +1337;Lo;L; +1338;Lo;L; +1339;Lo;L; +133A;Lo;L; +133B;Lo;L; +133C;Lo;L; +133D;Lo;L; +133E;Lo;L; +133F;Lo;L; +1340;Lo;L; +1341;Lo;L; +1342;Lo;L; +1343;Lo;L; +1344;Lo;L; +1345;Lo;L; +1346;Lo;L; +1348;Lo;L; +1349;Lo;L; +134A;Lo;L; +134B;Lo;L; +134C;Lo;L; +134D;Lo;L; +134E;Lo;L; +134F;Lo;L; +1350;Lo;L; +1351;Lo;L; +1352;Lo;L; +1353;Lo;L; +1354;Lo;L; +1355;Lo;L; +1356;Lo;L; +1357;Lo;L; +1358;Lo;L; +1359;Lo;L; +135A;Lo;L; +1361;Po;L; +1362;Po;L; +1363;Po;L; +1364;Po;L; +1365;Po;L; +1366;Po;L; +1367;Po;L; +1368;Po;L; +1369;Nd;L; +136A;Nd;L; +136B;Nd;L; +136C;Nd;L; +136D;Nd;L; +136E;Nd;L; +136F;Nd;L; +1370;Nd;L; +1371;Nd;L; +1372;No;L; +1373;No;L; +1374;No;L; +1375;No;L; +1376;No;L; +1377;No;L; +1378;No;L; +1379;No;L; +137A;No;L; +137B;No;L; +137C;No;L; +13A0;Lo;L; +13A1;Lo;L; +13A2;Lo;L; +13A3;Lo;L; +13A4;Lo;L; +13A5;Lo;L; +13A6;Lo;L; +13A7;Lo;L; +13A8;Lo;L; +13A9;Lo;L; +13AA;Lo;L; +13AB;Lo;L; +13AC;Lo;L; +13AD;Lo;L; +13AE;Lo;L; +13AF;Lo;L; +13B0;Lo;L; +13B1;Lo;L; +13B2;Lo;L; +13B3;Lo;L; +13B4;Lo;L; +13B5;Lo;L; +13B6;Lo;L; +13B7;Lo;L; +13B8;Lo;L; +13B9;Lo;L; +13BA;Lo;L; +13BB;Lo;L; +13BC;Lo;L; +13BD;Lo;L; +13BE;Lo;L; +13BF;Lo;L; +13C0;Lo;L; +13C1;Lo;L; +13C2;Lo;L; +13C3;Lo;L; +13C4;Lo;L; +13C5;Lo;L; +13C6;Lo;L; +13C7;Lo;L; +13C8;Lo;L; +13C9;Lo;L; +13CA;Lo;L; +13CB;Lo;L; +13CC;Lo;L; +13CD;Lo;L; +13CE;Lo;L; +13CF;Lo;L; +13D0;Lo;L; +13D1;Lo;L; +13D2;Lo;L; +13D3;Lo;L; +13D4;Lo;L; +13D5;Lo;L; +13D6;Lo;L; +13D7;Lo;L; +13D8;Lo;L; +13D9;Lo;L; +13DA;Lo;L; +13DB;Lo;L; +13DC;Lo;L; +13DD;Lo;L; +13DE;Lo;L; +13DF;Lo;L; +13E0;Lo;L; +13E1;Lo;L; +13E2;Lo;L; +13E3;Lo;L; +13E4;Lo;L; +13E5;Lo;L; +13E6;Lo;L; +13E7;Lo;L; +13E8;Lo;L; +13E9;Lo;L; +13EA;Lo;L; +13EB;Lo;L; +13EC;Lo;L; +13ED;Lo;L; +13EE;Lo;L; +13EF;Lo;L; +13F0;Lo;L; +13F1;Lo;L; +13F2;Lo;L; +13F3;Lo;L; +13F4;Lo;L; +1401;Lo;L; +1402;Lo;L; +1403;Lo;L; +1404;Lo;L; +1405;Lo;L; +1406;Lo;L; +1407;Lo;L; +1408;Lo;L; +1409;Lo;L; +140A;Lo;L; +140B;Lo;L; +140C;Lo;L; +140D;Lo;L; +140E;Lo;L; +140F;Lo;L; +1410;Lo;L; +1411;Lo;L; +1412;Lo;L; +1413;Lo;L; +1414;Lo;L; +1415;Lo;L; +1416;Lo;L; +1417;Lo;L; +1418;Lo;L; +1419;Lo;L; +141A;Lo;L; +141B;Lo;L; +141C;Lo;L; +141D;Lo;L; +141E;Lo;L; +141F;Lo;L; +1420;Lo;L; +1421;Lo;L; +1422;Lo;L; +1423;Lo;L; +1424;Lo;L; +1425;Lo;L; +1426;Lo;L; +1427;Lo;L; +1428;Lo;L; +1429;Lo;L; +142A;Lo;L; +142B;Lo;L; +142C;Lo;L; +142D;Lo;L; +142E;Lo;L; +142F;Lo;L; +1430;Lo;L; +1431;Lo;L; +1432;Lo;L; +1433;Lo;L; +1434;Lo;L; +1435;Lo;L; +1436;Lo;L; +1437;Lo;L; +1438;Lo;L; +1439;Lo;L; +143A;Lo;L; +143B;Lo;L; +143C;Lo;L; +143D;Lo;L; +143E;Lo;L; +143F;Lo;L; +1440;Lo;L; +1441;Lo;L; +1442;Lo;L; +1443;Lo;L; +1444;Lo;L; +1445;Lo;L; +1446;Lo;L; +1447;Lo;L; +1448;Lo;L; +1449;Lo;L; +144A;Lo;L; +144B;Lo;L; +144C;Lo;L; +144D;Lo;L; +144E;Lo;L; +144F;Lo;L; +1450;Lo;L; +1451;Lo;L; +1452;Lo;L; +1453;Lo;L; +1454;Lo;L; +1455;Lo;L; +1456;Lo;L; +1457;Lo;L; +1458;Lo;L; +1459;Lo;L; +145A;Lo;L; +145B;Lo;L; +145C;Lo;L; +145D;Lo;L; +145E;Lo;L; +145F;Lo;L; +1460;Lo;L; +1461;Lo;L; +1462;Lo;L; +1463;Lo;L; +1464;Lo;L; +1465;Lo;L; +1466;Lo;L; +1467;Lo;L; +1468;Lo;L; +1469;Lo;L; +146A;Lo;L; +146B;Lo;L; +146C;Lo;L; +146D;Lo;L; +146E;Lo;L; +146F;Lo;L; +1470;Lo;L; +1471;Lo;L; +1472;Lo;L; +1473;Lo;L; +1474;Lo;L; +1475;Lo;L; +1476;Lo;L; +1477;Lo;L; +1478;Lo;L; +1479;Lo;L; +147A;Lo;L; +147B;Lo;L; +147C;Lo;L; +147D;Lo;L; +147E;Lo;L; +147F;Lo;L; +1480;Lo;L; +1481;Lo;L; +1482;Lo;L; +1483;Lo;L; +1484;Lo;L; +1485;Lo;L; +1486;Lo;L; +1487;Lo;L; +1488;Lo;L; +1489;Lo;L; +148A;Lo;L; +148B;Lo;L; +148C;Lo;L; +148D;Lo;L; +148E;Lo;L; +148F;Lo;L; +1490;Lo;L; +1491;Lo;L; +1492;Lo;L; +1493;Lo;L; +1494;Lo;L; +1495;Lo;L; +1496;Lo;L; +1497;Lo;L; +1498;Lo;L; +1499;Lo;L; +149A;Lo;L; +149B;Lo;L; +149C;Lo;L; +149D;Lo;L; +149E;Lo;L; +149F;Lo;L; +14A0;Lo;L; +14A1;Lo;L; +14A2;Lo;L; +14A3;Lo;L; +14A4;Lo;L; +14A5;Lo;L; +14A6;Lo;L; +14A7;Lo;L; +14A8;Lo;L; +14A9;Lo;L; +14AA;Lo;L; +14AB;Lo;L; +14AC;Lo;L; +14AD;Lo;L; +14AE;Lo;L; +14AF;Lo;L; +14B0;Lo;L; +14B1;Lo;L; +14B2;Lo;L; +14B3;Lo;L; +14B4;Lo;L; +14B5;Lo;L; +14B6;Lo;L; +14B7;Lo;L; +14B8;Lo;L; +14B9;Lo;L; +14BA;Lo;L; +14BB;Lo;L; +14BC;Lo;L; +14BD;Lo;L; +14BE;Lo;L; +14BF;Lo;L; +14C0;Lo;L; +14C1;Lo;L; +14C2;Lo;L; +14C3;Lo;L; +14C4;Lo;L; +14C5;Lo;L; +14C6;Lo;L; +14C7;Lo;L; +14C8;Lo;L; +14C9;Lo;L; +14CA;Lo;L; +14CB;Lo;L; +14CC;Lo;L; +14CD;Lo;L; +14CE;Lo;L; +14CF;Lo;L; +14D0;Lo;L; +14D1;Lo;L; +14D2;Lo;L; +14D3;Lo;L; +14D4;Lo;L; +14D5;Lo;L; +14D6;Lo;L; +14D7;Lo;L; +14D8;Lo;L; +14D9;Lo;L; +14DA;Lo;L; +14DB;Lo;L; +14DC;Lo;L; +14DD;Lo;L; +14DE;Lo;L; +14DF;Lo;L; +14E0;Lo;L; +14E1;Lo;L; +14E2;Lo;L; +14E3;Lo;L; +14E4;Lo;L; +14E5;Lo;L; +14E6;Lo;L; +14E7;Lo;L; +14E8;Lo;L; +14E9;Lo;L; +14EA;Lo;L; +14EB;Lo;L; +14EC;Lo;L; +14ED;Lo;L; +14EE;Lo;L; +14EF;Lo;L; +14F0;Lo;L; +14F1;Lo;L; +14F2;Lo;L; +14F3;Lo;L; +14F4;Lo;L; +14F5;Lo;L; +14F6;Lo;L; +14F7;Lo;L; +14F8;Lo;L; +14F9;Lo;L; +14FA;Lo;L; +14FB;Lo;L; +14FC;Lo;L; +14FD;Lo;L; +14FE;Lo;L; +14FF;Lo;L; +1500;Lo;L; +1501;Lo;L; +1502;Lo;L; +1503;Lo;L; +1504;Lo;L; +1505;Lo;L; +1506;Lo;L; +1507;Lo;L; +1508;Lo;L; +1509;Lo;L; +150A;Lo;L; +150B;Lo;L; +150C;Lo;L; +150D;Lo;L; +150E;Lo;L; +150F;Lo;L; +1510;Lo;L; +1511;Lo;L; +1512;Lo;L; +1513;Lo;L; +1514;Lo;L; +1515;Lo;L; +1516;Lo;L; +1517;Lo;L; +1518;Lo;L; +1519;Lo;L; +151A;Lo;L; +151B;Lo;L; +151C;Lo;L; +151D;Lo;L; +151E;Lo;L; +151F;Lo;L; +1520;Lo;L; +1521;Lo;L; +1522;Lo;L; +1523;Lo;L; +1524;Lo;L; +1525;Lo;L; +1526;Lo;L; +1527;Lo;L; +1528;Lo;L; +1529;Lo;L; +152A;Lo;L; +152B;Lo;L; +152C;Lo;L; +152D;Lo;L; +152E;Lo;L; +152F;Lo;L; +1530;Lo;L; +1531;Lo;L; +1532;Lo;L; +1533;Lo;L; +1534;Lo;L; +1535;Lo;L; +1536;Lo;L; +1537;Lo;L; +1538;Lo;L; +1539;Lo;L; +153A;Lo;L; +153B;Lo;L; +153C;Lo;L; +153D;Lo;L; +153E;Lo;L; +153F;Lo;L; +1540;Lo;L; +1541;Lo;L; +1542;Lo;L; +1543;Lo;L; +1544;Lo;L; +1545;Lo;L; +1546;Lo;L; +1547;Lo;L; +1548;Lo;L; +1549;Lo;L; +154A;Lo;L; +154B;Lo;L; +154C;Lo;L; +154D;Lo;L; +154E;Lo;L; +154F;Lo;L; +1550;Lo;L; +1551;Lo;L; +1552;Lo;L; +1553;Lo;L; +1554;Lo;L; +1555;Lo;L; +1556;Lo;L; +1557;Lo;L; +1558;Lo;L; +1559;Lo;L; +155A;Lo;L; +155B;Lo;L; +155C;Lo;L; +155D;Lo;L; +155E;Lo;L; +155F;Lo;L; +1560;Lo;L; +1561;Lo;L; +1562;Lo;L; +1563;Lo;L; +1564;Lo;L; +1565;Lo;L; +1566;Lo;L; +1567;Lo;L; +1568;Lo;L; +1569;Lo;L; +156A;Lo;L; +156B;Lo;L; +156C;Lo;L; +156D;Lo;L; +156E;Lo;L; +156F;Lo;L; +1570;Lo;L; +1571;Lo;L; +1572;Lo;L; +1573;Lo;L; +1574;Lo;L; +1575;Lo;L; +1576;Lo;L; +1577;Lo;L; +1578;Lo;L; +1579;Lo;L; +157A;Lo;L; +157B;Lo;L; +157C;Lo;L; +157D;Lo;L; +157E;Lo;L; +157F;Lo;L; +1580;Lo;L; +1581;Lo;L; +1582;Lo;L; +1583;Lo;L; +1584;Lo;L; +1585;Lo;L; +1586;Lo;L; +1587;Lo;L; +1588;Lo;L; +1589;Lo;L; +158A;Lo;L; +158B;Lo;L; +158C;Lo;L; +158D;Lo;L; +158E;Lo;L; +158F;Lo;L; +1590;Lo;L; +1591;Lo;L; +1592;Lo;L; +1593;Lo;L; +1594;Lo;L; +1595;Lo;L; +1596;Lo;L; +1597;Lo;L; +1598;Lo;L; +1599;Lo;L; +159A;Lo;L; +159B;Lo;L; +159C;Lo;L; +159D;Lo;L; +159E;Lo;L; +159F;Lo;L; +15A0;Lo;L; +15A1;Lo;L; +15A2;Lo;L; +15A3;Lo;L; +15A4;Lo;L; +15A5;Lo;L; +15A6;Lo;L; +15A7;Lo;L; +15A8;Lo;L; +15A9;Lo;L; +15AA;Lo;L; +15AB;Lo;L; +15AC;Lo;L; +15AD;Lo;L; +15AE;Lo;L; +15AF;Lo;L; +15B0;Lo;L; +15B1;Lo;L; +15B2;Lo;L; +15B3;Lo;L; +15B4;Lo;L; +15B5;Lo;L; +15B6;Lo;L; +15B7;Lo;L; +15B8;Lo;L; +15B9;Lo;L; +15BA;Lo;L; +15BB;Lo;L; +15BC;Lo;L; +15BD;Lo;L; +15BE;Lo;L; +15BF;Lo;L; +15C0;Lo;L; +15C1;Lo;L; +15C2;Lo;L; +15C3;Lo;L; +15C4;Lo;L; +15C5;Lo;L; +15C6;Lo;L; +15C7;Lo;L; +15C8;Lo;L; +15C9;Lo;L; +15CA;Lo;L; +15CB;Lo;L; +15CC;Lo;L; +15CD;Lo;L; +15CE;Lo;L; +15CF;Lo;L; +15D0;Lo;L; +15D1;Lo;L; +15D2;Lo;L; +15D3;Lo;L; +15D4;Lo;L; +15D5;Lo;L; +15D6;Lo;L; +15D7;Lo;L; +15D8;Lo;L; +15D9;Lo;L; +15DA;Lo;L; +15DB;Lo;L; +15DC;Lo;L; +15DD;Lo;L; +15DE;Lo;L; +15DF;Lo;L; +15E0;Lo;L; +15E1;Lo;L; +15E2;Lo;L; +15E3;Lo;L; +15E4;Lo;L; +15E5;Lo;L; +15E6;Lo;L; +15E7;Lo;L; +15E8;Lo;L; +15E9;Lo;L; +15EA;Lo;L; +15EB;Lo;L; +15EC;Lo;L; +15ED;Lo;L; +15EE;Lo;L; +15EF;Lo;L; +15F0;Lo;L; +15F1;Lo;L; +15F2;Lo;L; +15F3;Lo;L; +15F4;Lo;L; +15F5;Lo;L; +15F6;Lo;L; +15F7;Lo;L; +15F8;Lo;L; +15F9;Lo;L; +15FA;Lo;L; +15FB;Lo;L; +15FC;Lo;L; +15FD;Lo;L; +15FE;Lo;L; +15FF;Lo;L; +1600;Lo;L; +1601;Lo;L; +1602;Lo;L; +1603;Lo;L; +1604;Lo;L; +1605;Lo;L; +1606;Lo;L; +1607;Lo;L; +1608;Lo;L; +1609;Lo;L; +160A;Lo;L; +160B;Lo;L; +160C;Lo;L; +160D;Lo;L; +160E;Lo;L; +160F;Lo;L; +1610;Lo;L; +1611;Lo;L; +1612;Lo;L; +1613;Lo;L; +1614;Lo;L; +1615;Lo;L; +1616;Lo;L; +1617;Lo;L; +1618;Lo;L; +1619;Lo;L; +161A;Lo;L; +161B;Lo;L; +161C;Lo;L; +161D;Lo;L; +161E;Lo;L; +161F;Lo;L; +1620;Lo;L; +1621;Lo;L; +1622;Lo;L; +1623;Lo;L; +1624;Lo;L; +1625;Lo;L; +1626;Lo;L; +1627;Lo;L; +1628;Lo;L; +1629;Lo;L; +162A;Lo;L; +162B;Lo;L; +162C;Lo;L; +162D;Lo;L; +162E;Lo;L; +162F;Lo;L; +1630;Lo;L; +1631;Lo;L; +1632;Lo;L; +1633;Lo;L; +1634;Lo;L; +1635;Lo;L; +1636;Lo;L; +1637;Lo;L; +1638;Lo;L; +1639;Lo;L; +163A;Lo;L; +163B;Lo;L; +163C;Lo;L; +163D;Lo;L; +163E;Lo;L; +163F;Lo;L; +1640;Lo;L; +1641;Lo;L; +1642;Lo;L; +1643;Lo;L; +1644;Lo;L; +1645;Lo;L; +1646;Lo;L; +1647;Lo;L; +1648;Lo;L; +1649;Lo;L; +164A;Lo;L; +164B;Lo;L; +164C;Lo;L; +164D;Lo;L; +164E;Lo;L; +164F;Lo;L; +1650;Lo;L; +1651;Lo;L; +1652;Lo;L; +1653;Lo;L; +1654;Lo;L; +1655;Lo;L; +1656;Lo;L; +1657;Lo;L; +1658;Lo;L; +1659;Lo;L; +165A;Lo;L; +165B;Lo;L; +165C;Lo;L; +165D;Lo;L; +165E;Lo;L; +165F;Lo;L; +1660;Lo;L; +1661;Lo;L; +1662;Lo;L; +1663;Lo;L; +1664;Lo;L; +1665;Lo;L; +1666;Lo;L; +1667;Lo;L; +1668;Lo;L; +1669;Lo;L; +166A;Lo;L; +166B;Lo;L; +166C;Lo;L; +166D;Po;L; +166E;Po;L; +166F;Lo;L; +1670;Lo;L; +1671;Lo;L; +1672;Lo;L; +1673;Lo;L; +1674;Lo;L; +1675;Lo;L; +1676;Lo;L; +1680;Zs;WS; +1681;Lo;L; +1682;Lo;L; +1683;Lo;L; +1684;Lo;L; +1685;Lo;L; +1686;Lo;L; +1687;Lo;L; +1688;Lo;L; +1689;Lo;L; +168A;Lo;L; +168B;Lo;L; +168C;Lo;L; +168D;Lo;L; +168E;Lo;L; +168F;Lo;L; +1690;Lo;L; +1691;Lo;L; +1692;Lo;L; +1693;Lo;L; +1694;Lo;L; +1695;Lo;L; +1696;Lo;L; +1697;Lo;L; +1698;Lo;L; +1699;Lo;L; +169A;Lo;L; +169B;Ps;ON; +169C;Pe;ON; +16A0;Lo;L; +16A1;Lo;L; +16A2;Lo;L; +16A3;Lo;L; +16A4;Lo;L; +16A5;Lo;L; +16A6;Lo;L; +16A7;Lo;L; +16A8;Lo;L; +16A9;Lo;L; +16AA;Lo;L; +16AB;Lo;L; +16AC;Lo;L; +16AD;Lo;L; +16AE;Lo;L; +16AF;Lo;L; +16B0;Lo;L; +16B1;Lo;L; +16B2;Lo;L; +16B3;Lo;L; +16B4;Lo;L; +16B5;Lo;L; +16B6;Lo;L; +16B7;Lo;L; +16B8;Lo;L; +16B9;Lo;L; +16BA;Lo;L; +16BB;Lo;L; +16BC;Lo;L; +16BD;Lo;L; +16BE;Lo;L; +16BF;Lo;L; +16C0;Lo;L; +16C1;Lo;L; +16C2;Lo;L; +16C3;Lo;L; +16C4;Lo;L; +16C5;Lo;L; +16C6;Lo;L; +16C7;Lo;L; +16C8;Lo;L; +16C9;Lo;L; +16CA;Lo;L; +16CB;Lo;L; +16CC;Lo;L; +16CD;Lo;L; +16CE;Lo;L; +16CF;Lo;L; +16D0;Lo;L; +16D1;Lo;L; +16D2;Lo;L; +16D3;Lo;L; +16D4;Lo;L; +16D5;Lo;L; +16D6;Lo;L; +16D7;Lo;L; +16D8;Lo;L; +16D9;Lo;L; +16DA;Lo;L; +16DB;Lo;L; +16DC;Lo;L; +16DD;Lo;L; +16DE;Lo;L; +16DF;Lo;L; +16E0;Lo;L; +16E1;Lo;L; +16E2;Lo;L; +16E3;Lo;L; +16E4;Lo;L; +16E5;Lo;L; +16E6;Lo;L; +16E7;Lo;L; +16E8;Lo;L; +16E9;Lo;L; +16EA;Lo;L; +16EB;Po;L; +16EC;Po;L; +16ED;Po;L; +16EE;Nl;L; +16EF;Nl;L; +16F0;Nl;L; +1780;Lo;L; +1781;Lo;L; +1782;Lo;L; +1783;Lo;L; +1784;Lo;L; +1785;Lo;L; +1786;Lo;L; +1787;Lo;L; +1788;Lo;L; +1789;Lo;L; +178A;Lo;L; +178B;Lo;L; +178C;Lo;L; +178D;Lo;L; +178E;Lo;L; +178F;Lo;L; +1790;Lo;L; +1791;Lo;L; +1792;Lo;L; +1793;Lo;L; +1794;Lo;L; +1795;Lo;L; +1796;Lo;L; +1797;Lo;L; +1798;Lo;L; +1799;Lo;L; +179A;Lo;L; +179B;Lo;L; +179C;Lo;L; +179D;Lo;L; +179E;Lo;L; +179F;Lo;L; +17A0;Lo;L; +17A1;Lo;L; +17A2;Lo;L; +17A3;Lo;L; +17A4;Lo;L; +17A5;Lo;L; +17A6;Lo;L; +17A7;Lo;L; +17A8;Lo;L; +17A9;Lo;L; +17AA;Lo;L; +17AB;Lo;L; +17AC;Lo;L; +17AD;Lo;L; +17AE;Lo;L; +17AF;Lo;L; +17B0;Lo;L; +17B1;Lo;L; +17B2;Lo;L; +17B3;Lo;L; +17B4;Mc;L; +17B5;Mc;L; +17B6;Mc;L; +17B7;Mn;NSM; +17B8;Mn;NSM; +17B9;Mn;NSM; +17BA;Mn;NSM; +17BB;Mn;NSM; +17BC;Mn;NSM; +17BD;Mn;NSM; +17BE;Mc;L; +17BF;Mc;L; +17C0;Mc;L; +17C1;Mc;L; +17C2;Mc;L; +17C3;Mc;L; +17C4;Mc;L; +17C5;Mc;L; +17C6;Mn;NSM; +17C7;Mc;L; +17C8;Mc;L; +17C9;Mn;NSM; +17CA;Mn;NSM; +17CB;Mn;NSM; +17CC;Mn;NSM; +17CD;Mn;NSM; +17CE;Mn;NSM; +17CF;Mn;NSM; +17D0;Mn;NSM; +17D1;Mn;NSM; +17D2;Mn;NSM; +17D3;Mn;NSM; +17D4;Po;L; +17D5;Po;L; +17D6;Po;L; +17D7;Po;L; +17D8;Po;L; +17D9;Po;L; +17DA;Po;L; +17DB;Sc;ET; +17DC;Po;L; +17E0;Nd;L; +17E1;Nd;L; +17E2;Nd;L; +17E3;Nd;L; +17E4;Nd;L; +17E5;Nd;L; +17E6;Nd;L; +17E7;Nd;L; +17E8;Nd;L; +17E9;Nd;L; +1800;Po;ON; +1801;Po;ON; +1802;Po;ON; +1803;Po;ON; +1804;Po;ON; +1805;Po;ON; +1806;Pd;ON; +1807;Po;ON; +1808;Po;ON; +1809;Po;ON; +180A;Po;ON; +180B;Cf;BN; +180C;Cf;BN; +180D;Cf;BN; +180E;Cf;BN; +1810;Nd;L; +1811;Nd;L; +1812;Nd;L; +1813;Nd;L; +1814;Nd;L; +1815;Nd;L; +1816;Nd;L; +1817;Nd;L; +1818;Nd;L; +1819;Nd;L; +1820;Lo;L; +1821;Lo;L; +1822;Lo;L; +1823;Lo;L; +1824;Lo;L; +1825;Lo;L; +1826;Lo;L; +1827;Lo;L; +1828;Lo;L; +1829;Lo;L; +182A;Lo;L; +182B;Lo;L; +182C;Lo;L; +182D;Lo;L; +182E;Lo;L; +182F;Lo;L; +1830;Lo;L; +1831;Lo;L; +1832;Lo;L; +1833;Lo;L; +1834;Lo;L; +1835;Lo;L; +1836;Lo;L; +1837;Lo;L; +1838;Lo;L; +1839;Lo;L; +183A;Lo;L; +183B;Lo;L; +183C;Lo;L; +183D;Lo;L; +183E;Lo;L; +183F;Lo;L; +1840;Lo;L; +1841;Lo;L; +1842;Lo;L; +1843;Lm;L; +1844;Lo;L; +1845;Lo;L; +1846;Lo;L; +1847;Lo;L; +1848;Lo;L; +1849;Lo;L; +184A;Lo;L; +184B;Lo;L; +184C;Lo;L; +184D;Lo;L; +184E;Lo;L; +184F;Lo;L; +1850;Lo;L; +1851;Lo;L; +1852;Lo;L; +1853;Lo;L; +1854;Lo;L; +1855;Lo;L; +1856;Lo;L; +1857;Lo;L; +1858;Lo;L; +1859;Lo;L; +185A;Lo;L; +185B;Lo;L; +185C;Lo;L; +185D;Lo;L; +185E;Lo;L; +185F;Lo;L; +1860;Lo;L; +1861;Lo;L; +1862;Lo;L; +1863;Lo;L; +1864;Lo;L; +1865;Lo;L; +1866;Lo;L; +1867;Lo;L; +1868;Lo;L; +1869;Lo;L; +186A;Lo;L; +186B;Lo;L; +186C;Lo;L; +186D;Lo;L; +186E;Lo;L; +186F;Lo;L; +1870;Lo;L; +1871;Lo;L; +1872;Lo;L; +1873;Lo;L; +1874;Lo;L; +1875;Lo;L; +1876;Lo;L; +1877;Lo;L; +1880;Lo;L; +1881;Lo;L; +1882;Lo;L; +1883;Lo;L; +1884;Lo;L; +1885;Lo;L; +1886;Lo;L; +1887;Lo;L; +1888;Lo;L; +1889;Lo;L; +188A;Lo;L; +188B;Lo;L; +188C;Lo;L; +188D;Lo;L; +188E;Lo;L; +188F;Lo;L; +1890;Lo;L; +1891;Lo;L; +1892;Lo;L; +1893;Lo;L; +1894;Lo;L; +1895;Lo;L; +1896;Lo;L; +1897;Lo;L; +1898;Lo;L; +1899;Lo;L; +189A;Lo;L; +189B;Lo;L; +189C;Lo;L; +189D;Lo;L; +189E;Lo;L; +189F;Lo;L; +18A0;Lo;L; +18A1;Lo;L; +18A2;Lo;L; +18A3;Lo;L; +18A4;Lo;L; +18A5;Lo;L; +18A6;Lo;L; +18A7;Lo;L; +18A8;Lo;L; +18A9;Mn;NSM; +1E00;Lu;L; +1E01;Ll;L; +1E02;Lu;L; +1E03;Ll;L; +1E04;Lu;L; +1E05;Ll;L; +1E06;Lu;L; +1E07;Ll;L; +1E08;Lu;L; +1E09;Ll;L; +1E0A;Lu;L; +1E0B;Ll;L; +1E0C;Lu;L; +1E0D;Ll;L; +1E0E;Lu;L; +1E0F;Ll;L; +1E10;Lu;L; +1E11;Ll;L; +1E12;Lu;L; +1E13;Ll;L; +1E14;Lu;L; +1E15;Ll;L; +1E16;Lu;L; +1E17;Ll;L; +1E18;Lu;L; +1E19;Ll;L; +1E1A;Lu;L; +1E1B;Ll;L; +1E1C;Lu;L; +1E1D;Ll;L; +1E1E;Lu;L; +1E1F;Ll;L; +1E20;Lu;L; +1E21;Ll;L; +1E22;Lu;L; +1E23;Ll;L; +1E24;Lu;L; +1E25;Ll;L; +1E26;Lu;L; +1E27;Ll;L; +1E28;Lu;L; +1E29;Ll;L; +1E2A;Lu;L; +1E2B;Ll;L; +1E2C;Lu;L; +1E2D;Ll;L; +1E2E;Lu;L; +1E2F;Ll;L; +1E30;Lu;L; +1E31;Ll;L; +1E32;Lu;L; +1E33;Ll;L; +1E34;Lu;L; +1E35;Ll;L; +1E36;Lu;L; +1E37;Ll;L; +1E38;Lu;L; +1E39;Ll;L; +1E3A;Lu;L; +1E3B;Ll;L; +1E3C;Lu;L; +1E3D;Ll;L; +1E3E;Lu;L; +1E3F;Ll;L; +1E40;Lu;L; +1E41;Ll;L; +1E42;Lu;L; +1E43;Ll;L; +1E44;Lu;L; +1E45;Ll;L; +1E46;Lu;L; +1E47;Ll;L; +1E48;Lu;L; +1E49;Ll;L; +1E4A;Lu;L; +1E4B;Ll;L; +1E4C;Lu;L; +1E4D;Ll;L; +1E4E;Lu;L; +1E4F;Ll;L; +1E50;Lu;L; +1E51;Ll;L; +1E52;Lu;L; +1E53;Ll;L; +1E54;Lu;L; +1E55;Ll;L; +1E56;Lu;L; +1E57;Ll;L; +1E58;Lu;L; +1E59;Ll;L; +1E5A;Lu;L; +1E5B;Ll;L; +1E5C;Lu;L; +1E5D;Ll;L; +1E5E;Lu;L; +1E5F;Ll;L; +1E60;Lu;L; +1E61;Ll;L; +1E62;Lu;L; +1E63;Ll;L; +1E64;Lu;L; +1E65;Ll;L; +1E66;Lu;L; +1E67;Ll;L; +1E68;Lu;L; +1E69;Ll;L; +1E6A;Lu;L; +1E6B;Ll;L; +1E6C;Lu;L; +1E6D;Ll;L; +1E6E;Lu;L; +1E6F;Ll;L; +1E70;Lu;L; +1E71;Ll;L; +1E72;Lu;L; +1E73;Ll;L; +1E74;Lu;L; +1E75;Ll;L; +1E76;Lu;L; +1E77;Ll;L; +1E78;Lu;L; +1E79;Ll;L; +1E7A;Lu;L; +1E7B;Ll;L; +1E7C;Lu;L; +1E7D;Ll;L; +1E7E;Lu;L; +1E7F;Ll;L; +1E80;Lu;L; +1E81;Ll;L; +1E82;Lu;L; +1E83;Ll;L; +1E84;Lu;L; +1E85;Ll;L; +1E86;Lu;L; +1E87;Ll;L; +1E88;Lu;L; +1E89;Ll;L; +1E8A;Lu;L; +1E8B;Ll;L; +1E8C;Lu;L; +1E8D;Ll;L; +1E8E;Lu;L; +1E8F;Ll;L; +1E90;Lu;L; +1E91;Ll;L; +1E92;Lu;L; +1E93;Ll;L; +1E94;Lu;L; +1E95;Ll;L; +1E96;Ll;L; +1E97;Ll;L; +1E98;Ll;L; +1E99;Ll;L; +1E9A;Ll;L; +1E9B;Ll;L; +1EA0;Lu;L; +1EA1;Ll;L; +1EA2;Lu;L; +1EA3;Ll;L; +1EA4;Lu;L; +1EA5;Ll;L; +1EA6;Lu;L; +1EA7;Ll;L; +1EA8;Lu;L; +1EA9;Ll;L; +1EAA;Lu;L; +1EAB;Ll;L; +1EAC;Lu;L; +1EAD;Ll;L; +1EAE;Lu;L; +1EAF;Ll;L; +1EB0;Lu;L; +1EB1;Ll;L; +1EB2;Lu;L; +1EB3;Ll;L; +1EB4;Lu;L; +1EB5;Ll;L; +1EB6;Lu;L; +1EB7;Ll;L; +1EB8;Lu;L; +1EB9;Ll;L; +1EBA;Lu;L; +1EBB;Ll;L; +1EBC;Lu;L; +1EBD;Ll;L; +1EBE;Lu;L; +1EBF;Ll;L; +1EC0;Lu;L; +1EC1;Ll;L; +1EC2;Lu;L; +1EC3;Ll;L; +1EC4;Lu;L; +1EC5;Ll;L; +1EC6;Lu;L; +1EC7;Ll;L; +1EC8;Lu;L; +1EC9;Ll;L; +1ECA;Lu;L; +1ECB;Ll;L; +1ECC;Lu;L; +1ECD;Ll;L; +1ECE;Lu;L; +1ECF;Ll;L; +1ED0;Lu;L; +1ED1;Ll;L; +1ED2;Lu;L; +1ED3;Ll;L; +1ED4;Lu;L; +1ED5;Ll;L; +1ED6;Lu;L; +1ED7;Ll;L; +1ED8;Lu;L; +1ED9;Ll;L; +1EDA;Lu;L; +1EDB;Ll;L; +1EDC;Lu;L; +1EDD;Ll;L; +1EDE;Lu;L; +1EDF;Ll;L; +1EE0;Lu;L; +1EE1;Ll;L; +1EE2;Lu;L; +1EE3;Ll;L; +1EE4;Lu;L; +1EE5;Ll;L; +1EE6;Lu;L; +1EE7;Ll;L; +1EE8;Lu;L; +1EE9;Ll;L; +1EEA;Lu;L; +1EEB;Ll;L; +1EEC;Lu;L; +1EED;Ll;L; +1EEE;Lu;L; +1EEF;Ll;L; +1EF0;Lu;L; +1EF1;Ll;L; +1EF2;Lu;L; +1EF3;Ll;L; +1EF4;Lu;L; +1EF5;Ll;L; +1EF6;Lu;L; +1EF7;Ll;L; +1EF8;Lu;L; +1EF9;Ll;L; +1F00;Ll;L; +1F01;Ll;L; +1F02;Ll;L; +1F03;Ll;L; +1F04;Ll;L; +1F05;Ll;L; +1F06;Ll;L; +1F07;Ll;L; +1F08;Lu;L; +1F09;Lu;L; +1F0A;Lu;L; +1F0B;Lu;L; +1F0C;Lu;L; +1F0D;Lu;L; +1F0E;Lu;L; +1F0F;Lu;L; +1F10;Ll;L; +1F11;Ll;L; +1F12;Ll;L; +1F13;Ll;L; +1F14;Ll;L; +1F15;Ll;L; +1F18;Lu;L; +1F19;Lu;L; +1F1A;Lu;L; +1F1B;Lu;L; +1F1C;Lu;L; +1F1D;Lu;L; +1F20;Ll;L; +1F21;Ll;L; +1F22;Ll;L; +1F23;Ll;L; +1F24;Ll;L; +1F25;Ll;L; +1F26;Ll;L; +1F27;Ll;L; +1F28;Lu;L; +1F29;Lu;L; +1F2A;Lu;L; +1F2B;Lu;L; +1F2C;Lu;L; +1F2D;Lu;L; +1F2E;Lu;L; +1F2F;Lu;L; +1F30;Ll;L; +1F31;Ll;L; +1F32;Ll;L; +1F33;Ll;L; +1F34;Ll;L; +1F35;Ll;L; +1F36;Ll;L; +1F37;Ll;L; +1F38;Lu;L; +1F39;Lu;L; +1F3A;Lu;L; +1F3B;Lu;L; +1F3C;Lu;L; +1F3D;Lu;L; +1F3E;Lu;L; +1F3F;Lu;L; +1F40;Ll;L; +1F41;Ll;L; +1F42;Ll;L; +1F43;Ll;L; +1F44;Ll;L; +1F45;Ll;L; +1F48;Lu;L; +1F49;Lu;L; +1F4A;Lu;L; +1F4B;Lu;L; +1F4C;Lu;L; +1F4D;Lu;L; +1F50;Ll;L; +1F51;Ll;L; +1F52;Ll;L; +1F53;Ll;L; +1F54;Ll;L; +1F55;Ll;L; +1F56;Ll;L; +1F57;Ll;L; +1F59;Lu;L; +1F5B;Lu;L; +1F5D;Lu;L; +1F5F;Lu;L; +1F60;Ll;L; +1F61;Ll;L; +1F62;Ll;L; +1F63;Ll;L; +1F64;Ll;L; +1F65;Ll;L; +1F66;Ll;L; +1F67;Ll;L; +1F68;Lu;L; +1F69;Lu;L; +1F6A;Lu;L; +1F6B;Lu;L; +1F6C;Lu;L; +1F6D;Lu;L; +1F6E;Lu;L; +1F6F;Lu;L; +1F70;Ll;L; +1F71;Ll;L; +1F72;Ll;L; +1F73;Ll;L; +1F74;Ll;L; +1F75;Ll;L; +1F76;Ll;L; +1F77;Ll;L; +1F78;Ll;L; +1F79;Ll;L; +1F7A;Ll;L; +1F7B;Ll;L; +1F7C;Ll;L; +1F7D;Ll;L; +1F80;Ll;L; +1F81;Ll;L; +1F82;Ll;L; +1F83;Ll;L; +1F84;Ll;L; +1F85;Ll;L; +1F86;Ll;L; +1F87;Ll;L; +1F88;Lt;L; +1F89;Lt;L; +1F8A;Lt;L; +1F8B;Lt;L; +1F8C;Lt;L; +1F8D;Lt;L; +1F8E;Lt;L; +1F8F;Lt;L; +1F90;Ll;L; +1F91;Ll;L; +1F92;Ll;L; +1F93;Ll;L; +1F94;Ll;L; +1F95;Ll;L; +1F96;Ll;L; +1F97;Ll;L; +1F98;Lt;L; +1F99;Lt;L; +1F9A;Lt;L; +1F9B;Lt;L; +1F9C;Lt;L; +1F9D;Lt;L; +1F9E;Lt;L; +1F9F;Lt;L; +1FA0;Ll;L; +1FA1;Ll;L; +1FA2;Ll;L; +1FA3;Ll;L; +1FA4;Ll;L; +1FA5;Ll;L; +1FA6;Ll;L; +1FA7;Ll;L; +1FA8;Lt;L; +1FA9;Lt;L; +1FAA;Lt;L; +1FAB;Lt;L; +1FAC;Lt;L; +1FAD;Lt;L; +1FAE;Lt;L; +1FAF;Lt;L; +1FB0;Ll;L; +1FB1;Ll;L; +1FB2;Ll;L; +1FB3;Ll;L; +1FB4;Ll;L; +1FB6;Ll;L; +1FB7;Ll;L; +1FB8;Lu;L; +1FB9;Lu;L; +1FBA;Lu;L; +1FBB;Lu;L; +1FBC;Lt;L; +1FBD;Sk;ON; +1FBE;Ll;L; +1FBF;Sk;ON; +1FC0;Sk;ON; +1FC1;Sk;ON; +1FC2;Ll;L; +1FC3;Ll;L; +1FC4;Ll;L; +1FC6;Ll;L; +1FC7;Ll;L; +1FC8;Lu;L; +1FC9;Lu;L; +1FCA;Lu;L; +1FCB;Lu;L; +1FCC;Lt;L; +1FCD;Sk;ON; +1FCE;Sk;ON; +1FCF;Sk;ON; +1FD0;Ll;L; +1FD1;Ll;L; +1FD2;Ll;L; +1FD3;Ll;L; +1FD6;Ll;L; +1FD7;Ll;L; +1FD8;Lu;L; +1FD9;Lu;L; +1FDA;Lu;L; +1FDB;Lu;L; +1FDD;Sk;ON; +1FDE;Sk;ON; +1FDF;Sk;ON; +1FE0;Ll;L; +1FE1;Ll;L; +1FE2;Ll;L; +1FE3;Ll;L; +1FE4;Ll;L; +1FE5;Ll;L; +1FE6;Ll;L; +1FE7;Ll;L; +1FE8;Lu;L; +1FE9;Lu;L; +1FEA;Lu;L; +1FEB;Lu;L; +1FEC;Lu;L; +1FED;Sk;ON; +1FEE;Sk;ON; +1FEF;Sk;ON; +1FF2;Ll;L; +1FF3;Ll;L; +1FF4;Ll;L; +1FF6;Ll;L; +1FF7;Ll;L; +1FF8;Lu;L; +1FF9;Lu;L; +1FFA;Lu;L; +1FFB;Lu;L; +1FFC;Lt;L; +1FFD;Sk;ON; +1FFE;Sk;ON; +2000;Zs;WS; +2001;Zs;WS; +2002;Zs;WS; +2003;Zs;WS; +2004;Zs;WS; +2005;Zs;WS; +2006;Zs;WS; +2007;Zs;WS; +2008;Zs;WS; +2009;Zs;WS; +200A;Zs;WS; +200B;Zs;BN; +200C;Cf;BN; +200D;Cf;BN; +200E;Cf;L; +200F;Cf;R; +2010;Pd;ON; +2011;Pd;ON; +2012;Pd;ON; +2013;Pd;ON; +2014;Pd;ON; +2015;Pd;ON; +2016;Po;ON; +2017;Po;ON; +2018;Pi;ON; +2019;Pf;ON; +201A;Ps;ON; +201B;Pi;ON; +201C;Pi;ON; +201D;Pf;ON; +201E;Ps;ON; +201F;Pi;ON; +2020;Po;ON; +2021;Po;ON; +2022;Po;ON; +2023;Po;ON; +2024;Po;ON; +2025;Po;ON; +2026;Po;ON; +2027;Po;ON; +2028;Zl;WS; +2029;Zp;B; +202A;Cf;LRE; +202B;Cf;RLE; +202C;Cf;PDF; +202D;Cf;LRO; +202E;Cf;RLO; +202F;Zs;WS; +2030;Po;ET; +2031;Po;ET; +2032;Po;ET; +2033;Po;ET; +2034;Po;ET; +2035;Po;ON; +2036;Po;ON; +2037;Po;ON; +2038;Po;ON; +2039;Pi;ON; +203A;Pf;ON; +203B;Po;ON; +203C;Po;ON; +203D;Po;ON; +203E;Po;ON; +203F;Pc;ON; +2040;Pc;ON; +2041;Po;ON; +2042;Po;ON; +2043;Po;ON; +2044;Sm;ON; +2045;Ps;ON; +2046;Pe;ON; +2048;Po;ON; +2049;Po;ON; +204A;Po;ON; +204B;Po;ON; +204C;Po;ON; +204D;Po;ON; +206A;Cf;BN; +206B;Cf;BN; +206C;Cf;BN; +206D;Cf;BN; +206E;Cf;BN; +206F;Cf;BN; +2070;No;EN; +2074;No;EN; +2075;No;EN; +2076;No;EN; +2077;No;EN; +2078;No;EN; +2079;No;EN; +207A;Sm;ET; +207B;Sm;ET; +207C;Sm;ON; +207D;Ps;ON; +207E;Pe;ON; +207F;Ll;L; +2080;No;EN; +2081;No;EN; +2082;No;EN; +2083;No;EN; +2084;No;EN; +2085;No;EN; +2086;No;EN; +2087;No;EN; +2088;No;EN; +2089;No;EN; +208A;Sm;ET; +208B;Sm;ET; +208C;Sm;ON; +208D;Ps;ON; +208E;Pe;ON; +20A0;Sc;ET; +20A1;Sc;ET; +20A2;Sc;ET; +20A3;Sc;ET; +20A4;Sc;ET; +20A5;Sc;ET; +20A6;Sc;ET; +20A7;Sc;ET; +20A8;Sc;ET; +20A9;Sc;ET; +20AA;Sc;ET; +20AB;Sc;ET; +20AC;Sc;ET; +20AD;Sc;ET; +20AE;Sc;ET; +20AF;Sc;ET; +20D0;Mn;NSM; +20D1;Mn;NSM; +20D2;Mn;NSM; +20D3;Mn;NSM; +20D4;Mn;NSM; +20D5;Mn;NSM; +20D6;Mn;NSM; +20D7;Mn;NSM; +20D8;Mn;NSM; +20D9;Mn;NSM; +20DA;Mn;NSM; +20DB;Mn;NSM; +20DC;Mn;NSM; +20DD;Me;NSM; +20DE;Me;NSM; +20DF;Me;NSM; +20E0;Me;NSM; +20E1;Mn;NSM; +20E2;Me;NSM; +20E3;Me;NSM; +2100;So;ON; +2101;So;ON; +2102;Lu;L; +2103;So;ON; +2104;So;ON; +2105;So;ON; +2106;So;ON; +2107;Lu;L; +2108;So;ON; +2109;So;ON; +210A;Ll;L; +210B;Lu;L; +210C;Lu;L; +210D;Lu;L; +210E;Ll;L; +210F;Ll;L; +2110;Lu;L; +2111;Lu;L; +2112;Lu;L; +2113;Ll;L; +2114;So;ON; +2115;Lu;L; +2116;So;ON; +2117;So;ON; +2118;So;ON; +2119;Lu;L; +211A;Lu;L; +211B;Lu;L; +211C;Lu;L; +211D;Lu;L; +211E;So;ON; +211F;So;ON; +2120;So;ON; +2121;So;ON; +2122;So;ON; +2123;So;ON; +2124;Lu;L; +2125;So;ON; +2126;Lu;L; +2127;So;ON; +2128;Lu;L; +2129;So;ON; +212A;Lu;L; +212B;Lu;L; +212C;Lu;L; +212D;Lu;L; +212E;So;ET; +212F;Ll;L; +2130;Lu;L; +2131;Lu;L; +2132;So;ON; +2133;Lu;L; +2134;Ll;L; +2135;Lo;L; +2136;Lo;L; +2137;Lo;L; +2138;Lo;L; +2139;Ll;L; +213A;So;ON; +2153;No;ON; +2154;No;ON; +2155;No;ON; +2156;No;ON; +2157;No;ON; +2158;No;ON; +2159;No;ON; +215A;No;ON; +215B;No;ON; +215C;No;ON; +215D;No;ON; +215E;No;ON; +215F;No;ON; +2160;Nl;L; +2161;Nl;L; +2162;Nl;L; +2163;Nl;L; +2164;Nl;L; +2165;Nl;L; +2166;Nl;L; +2167;Nl;L; +2168;Nl;L; +2169;Nl;L; +216A;Nl;L; +216B;Nl;L; +216C;Nl;L; +216D;Nl;L; +216E;Nl;L; +216F;Nl;L; +2170;Nl;L; +2171;Nl;L; +2172;Nl;L; +2173;Nl;L; +2174;Nl;L; +2175;Nl;L; +2176;Nl;L; +2177;Nl;L; +2178;Nl;L; +2179;Nl;L; +217A;Nl;L; +217B;Nl;L; +217C;Nl;L; +217D;Nl;L; +217E;Nl;L; +217F;Nl;L; +2180;Nl;L; +2181;Nl;L; +2182;Nl;L; +2183;Nl;L; +2190;Sm;ON; +2191;Sm;ON; +2192;Sm;ON; +2193;Sm;ON; +2194;Sm;ON; +2195;So;ON; +2196;So;ON; +2197;So;ON; +2198;So;ON; +2199;So;ON; +219A;Sm;ON; +219B;Sm;ON; +219C;So;ON; +219D;So;ON; +219E;So;ON; +219F;So;ON; +21A0;Sm;ON; +21A1;So;ON; +21A2;So;ON; +21A3;Sm;ON; +21A4;So;ON; +21A5;So;ON; +21A6;Sm;ON; +21A7;So;ON; +21A8;So;ON; +21A9;So;ON; +21AA;So;ON; +21AB;So;ON; +21AC;So;ON; +21AD;So;ON; +21AE;Sm;ON; +21AF;So;ON; +21B0;So;ON; +21B1;So;ON; +21B2;So;ON; +21B3;So;ON; +21B4;So;ON; +21B5;So;ON; +21B6;So;ON; +21B7;So;ON; +21B8;So;ON; +21B9;So;ON; +21BA;So;ON; +21BB;So;ON; +21BC;So;ON; +21BD;So;ON; +21BE;So;ON; +21BF;So;ON; +21C0;So;ON; +21C1;So;ON; +21C2;So;ON; +21C3;So;ON; +21C4;So;ON; +21C5;So;ON; +21C6;So;ON; +21C7;So;ON; +21C8;So;ON; +21C9;So;ON; +21CA;So;ON; +21CB;So;ON; +21CC;So;ON; +21CD;So;ON; +21CE;Sm;ON; +21CF;Sm;ON; +21D0;So;ON; +21D1;So;ON; +21D2;Sm;ON; +21D3;So;ON; +21D4;Sm;ON; +21D5;So;ON; +21D6;So;ON; +21D7;So;ON; +21D8;So;ON; +21D9;So;ON; +21DA;So;ON; +21DB;So;ON; +21DC;So;ON; +21DD;So;ON; +21DE;So;ON; +21DF;So;ON; +21E0;So;ON; +21E1;So;ON; +21E2;So;ON; +21E3;So;ON; +21E4;So;ON; +21E5;So;ON; +21E6;So;ON; +21E7;So;ON; +21E8;So;ON; +21E9;So;ON; +21EA;So;ON; +21EB;So;ON; +21EC;So;ON; +21ED;So;ON; +21EE;So;ON; +21EF;So;ON; +21F0;So;ON; +21F1;So;ON; +21F2;So;ON; +21F3;So;ON; +2200;Sm;ON; +2201;Sm;ON; +2202;Sm;ON; +2203;Sm;ON; +2204;Sm;ON; +2205;Sm;ON; +2206;Sm;ON; +2207;Sm;ON; +2208;Sm;ON; +2209;Sm;ON; +220A;Sm;ON; +220B;Sm;ON; +220C;Sm;ON; +220D;Sm;ON; +220E;Sm;ON; +220F;Sm;ON; +2210;Sm;ON; +2211;Sm;ON; +2212;Sm;ET; +2213;Sm;ET; +2214;Sm;ON; +2215;Sm;ON; +2216;Sm;ON; +2217;Sm;ON; +2218;Sm;ON; +2219;Sm;ON; +221A;Sm;ON; +221B;Sm;ON; +221C;Sm;ON; +221D;Sm;ON; +221E;Sm;ON; +221F;Sm;ON; +2220;Sm;ON; +2221;Sm;ON; +2222;Sm;ON; +2223;Sm;ON; +2224;Sm;ON; +2225;Sm;ON; +2226;Sm;ON; +2227;Sm;ON; +2228;Sm;ON; +2229;Sm;ON; +222A;Sm;ON; +222B;Sm;ON; +222C;Sm;ON; +222D;Sm;ON; +222E;Sm;ON; +222F;Sm;ON; +2230;Sm;ON; +2231;Sm;ON; +2232;Sm;ON; +2233;Sm;ON; +2234;Sm;ON; +2235;Sm;ON; +2236;Sm;ON; +2237;Sm;ON; +2238;Sm;ON; +2239;Sm;ON; +223A;Sm;ON; +223B;Sm;ON; +223C;Sm;ON; +223D;Sm;ON; +223E;Sm;ON; +223F;Sm;ON; +2240;Sm;ON; +2241;Sm;ON; +2242;Sm;ON; +2243;Sm;ON; +2244;Sm;ON; +2245;Sm;ON; +2246;Sm;ON; +2247;Sm;ON; +2248;Sm;ON; +2249;Sm;ON; +224A;Sm;ON; +224B;Sm;ON; +224C;Sm;ON; +224D;Sm;ON; +224E;Sm;ON; +224F;Sm;ON; +2250;Sm;ON; +2251;Sm;ON; +2252;Sm;ON; +2253;Sm;ON; +2254;Sm;ON; +2255;Sm;ON; +2256;Sm;ON; +2257;Sm;ON; +2258;Sm;ON; +2259;Sm;ON; +225A;Sm;ON; +225B;Sm;ON; +225C;Sm;ON; +225D;Sm;ON; +225E;Sm;ON; +225F;Sm;ON; +2260;Sm;ON; +2261;Sm;ON; +2262;Sm;ON; +2263;Sm;ON; +2264;Sm;ON; +2265;Sm;ON; +2266;Sm;ON; +2267;Sm;ON; +2268;Sm;ON; +2269;Sm;ON; +226A;Sm;ON; +226B;Sm;ON; +226C;Sm;ON; +226D;Sm;ON; +226E;Sm;ON; +226F;Sm;ON; +2270;Sm;ON; +2271;Sm;ON; +2272;Sm;ON; +2273;Sm;ON; +2274;Sm;ON; +2275;Sm;ON; +2276;Sm;ON; +2277;Sm;ON; +2278;Sm;ON; +2279;Sm;ON; +227A;Sm;ON; +227B;Sm;ON; +227C;Sm;ON; +227D;Sm;ON; +227E;Sm;ON; +227F;Sm;ON; +2280;Sm;ON; +2281;Sm;ON; +2282;Sm;ON; +2283;Sm;ON; +2284;Sm;ON; +2285;Sm;ON; +2286;Sm;ON; +2287;Sm;ON; +2288;Sm;ON; +2289;Sm;ON; +228A;Sm;ON; +228B;Sm;ON; +228C;Sm;ON; +228D;Sm;ON; +228E;Sm;ON; +228F;Sm;ON; +2290;Sm;ON; +2291;Sm;ON; +2292;Sm;ON; +2293;Sm;ON; +2294;Sm;ON; +2295;Sm;ON; +2296;Sm;ON; +2297;Sm;ON; +2298;Sm;ON; +2299;Sm;ON; +229A;Sm;ON; +229B;Sm;ON; +229C;Sm;ON; +229D;Sm;ON; +229E;Sm;ON; +229F;Sm;ON; +22A0;Sm;ON; +22A1;Sm;ON; +22A2;Sm;ON; +22A3;Sm;ON; +22A4;Sm;ON; +22A5;Sm;ON; +22A6;Sm;ON; +22A7;Sm;ON; +22A8;Sm;ON; +22A9;Sm;ON; +22AA;Sm;ON; +22AB;Sm;ON; +22AC;Sm;ON; +22AD;Sm;ON; +22AE;Sm;ON; +22AF;Sm;ON; +22B0;Sm;ON; +22B1;Sm;ON; +22B2;Sm;ON; +22B3;Sm;ON; +22B4;Sm;ON; +22B5;Sm;ON; +22B6;Sm;ON; +22B7;Sm;ON; +22B8;Sm;ON; +22B9;Sm;ON; +22BA;Sm;ON; +22BB;Sm;ON; +22BC;Sm;ON; +22BD;Sm;ON; +22BE;Sm;ON; +22BF;Sm;ON; +22C0;Sm;ON; +22C1;Sm;ON; +22C2;Sm;ON; +22C3;Sm;ON; +22C4;Sm;ON; +22C5;Sm;ON; +22C6;Sm;ON; +22C7;Sm;ON; +22C8;Sm;ON; +22C9;Sm;ON; +22CA;Sm;ON; +22CB;Sm;ON; +22CC;Sm;ON; +22CD;Sm;ON; +22CE;Sm;ON; +22CF;Sm;ON; +22D0;Sm;ON; +22D1;Sm;ON; +22D2;Sm;ON; +22D3;Sm;ON; +22D4;Sm;ON; +22D5;Sm;ON; +22D6;Sm;ON; +22D7;Sm;ON; +22D8;Sm;ON; +22D9;Sm;ON; +22DA;Sm;ON; +22DB;Sm;ON; +22DC;Sm;ON; +22DD;Sm;ON; +22DE;Sm;ON; +22DF;Sm;ON; +22E0;Sm;ON; +22E1;Sm;ON; +22E2;Sm;ON; +22E3;Sm;ON; +22E4;Sm;ON; +22E5;Sm;ON; +22E6;Sm;ON; +22E7;Sm;ON; +22E8;Sm;ON; +22E9;Sm;ON; +22EA;Sm;ON; +22EB;Sm;ON; +22EC;Sm;ON; +22ED;Sm;ON; +22EE;Sm;ON; +22EF;Sm;ON; +22F0;Sm;ON; +22F1;Sm;ON; +2300;So;ON; +2301;So;ON; +2302;So;ON; +2303;So;ON; +2304;So;ON; +2305;So;ON; +2306;So;ON; +2307;So;ON; +2308;Sm;ON; +2309;Sm;ON; +230A;Sm;ON; +230B;Sm;ON; +230C;So;ON; +230D;So;ON; +230E;So;ON; +230F;So;ON; +2310;So;ON; +2311;So;ON; +2312;So;ON; +2313;So;ON; +2314;So;ON; +2315;So;ON; +2316;So;ON; +2317;So;ON; +2318;So;ON; +2319;So;ON; +231A;So;ON; +231B;So;ON; +231C;So;ON; +231D;So;ON; +231E;So;ON; +231F;So;ON; +2320;Sm;ON; +2321;Sm;ON; +2322;So;ON; +2323;So;ON; +2324;So;ON; +2325;So;ON; +2326;So;ON; +2327;So;ON; +2328;So;ON; +2329;Ps;ON; +232A;Pe;ON; +232B;So;ON; +232C;So;ON; +232D;So;ON; +232E;So;ON; +232F;So;ON; +2330;So;ON; +2331;So;ON; +2332;So;ON; +2333;So;ON; +2334;So;ON; +2335;So;ON; +2336;So;L; +2337;So;L; +2338;So;L; +2339;So;L; +233A;So;L; +233B;So;L; +233C;So;L; +233D;So;L; +233E;So;L; +233F;So;L; +2340;So;L; +2341;So;L; +2342;So;L; +2343;So;L; +2344;So;L; +2345;So;L; +2346;So;L; +2347;So;L; +2348;So;L; +2349;So;L; +234A;So;L; +234B;So;L; +234C;So;L; +234D;So;L; +234E;So;L; +234F;So;L; +2350;So;L; +2351;So;L; +2352;So;L; +2353;So;L; +2354;So;L; +2355;So;L; +2356;So;L; +2357;So;L; +2358;So;L; +2359;So;L; +235A;So;L; +235B;So;L; +235C;So;L; +235D;So;L; +235E;So;L; +235F;So;L; +2360;So;L; +2361;So;L; +2362;So;L; +2363;So;L; +2364;So;L; +2365;So;L; +2366;So;L; +2367;So;L; +2368;So;L; +2369;So;L; +236A;So;L; +236B;So;L; +236C;So;L; +236D;So;L; +236E;So;L; +236F;So;L; +2370;So;L; +2371;So;L; +2372;So;L; +2373;So;L; +2374;So;L; +2375;So;L; +2376;So;L; +2377;So;L; +2378;So;L; +2379;So;L; +237A;So;L; +237B;So;ON; +237D;So;ON; +237E;So;ON; +237F;So;ON; +2380;So;ON; +2381;So;ON; +2382;So;ON; +2383;So;ON; +2384;So;ON; +2385;So;ON; +2386;So;ON; +2387;So;ON; +2388;So;ON; +2389;So;ON; +238A;So;ON; +238B;So;ON; +238C;So;ON; +238D;So;ON; +238E;So;ON; +238F;So;ON; +2390;So;ON; +2391;So;ON; +2392;So;ON; +2393;So;ON; +2394;So;ON; +2395;So;L; +2396;So;ON; +2397;So;ON; +2398;So;ON; +2399;So;ON; +239A;So;ON; +2400;So;ON; +2401;So;ON; +2402;So;ON; +2403;So;ON; +2404;So;ON; +2405;So;ON; +2406;So;ON; +2407;So;ON; +2408;So;ON; +2409;So;ON; +240A;So;ON; +240B;So;ON; +240C;So;ON; +240D;So;ON; +240E;So;ON; +240F;So;ON; +2410;So;ON; +2411;So;ON; +2412;So;ON; +2413;So;ON; +2414;So;ON; +2415;So;ON; +2416;So;ON; +2417;So;ON; +2418;So;ON; +2419;So;ON; +241A;So;ON; +241B;So;ON; +241C;So;ON; +241D;So;ON; +241E;So;ON; +241F;So;ON; +2420;So;ON; +2421;So;ON; +2422;So;ON; +2423;So;ON; +2424;So;ON; +2425;So;ON; +2426;So;ON; +2440;So;ON; +2441;So;ON; +2442;So;ON; +2443;So;ON; +2444;So;ON; +2445;So;ON; +2446;So;ON; +2447;So;ON; +2448;So;ON; +2449;So;ON; +244A;So;ON; +2460;No;EN; +2461;No;EN; +2462;No;EN; +2463;No;EN; +2464;No;EN; +2465;No;EN; +2466;No;EN; +2467;No;EN; +2468;No;EN; +2469;No;EN; +246A;No;EN; +246B;No;EN; +246C;No;EN; +246D;No;EN; +246E;No;EN; +246F;No;EN; +2470;No;EN; +2471;No;EN; +2472;No;EN; +2473;No;EN; +2474;No;EN; +2475;No;EN; +2476;No;EN; +2477;No;EN; +2478;No;EN; +2479;No;EN; +247A;No;EN; +247B;No;EN; +247C;No;EN; +247D;No;EN; +247E;No;EN; +247F;No;EN; +2480;No;EN; +2481;No;EN; +2482;No;EN; +2483;No;EN; +2484;No;EN; +2485;No;EN; +2486;No;EN; +2487;No;EN; +2488;No;EN; +2489;No;EN; +248A;No;EN; +248B;No;EN; +248C;No;EN; +248D;No;EN; +248E;No;EN; +248F;No;EN; +2490;No;EN; +2491;No;EN; +2492;No;EN; +2493;No;EN; +2494;No;EN; +2495;No;EN; +2496;No;EN; +2497;No;EN; +2498;No;EN; +2499;No;EN; +249A;No;EN; +249B;No;EN; +249C;So;L; +249D;So;L; +249E;So;L; +249F;So;L; +24A0;So;L; +24A1;So;L; +24A2;So;L; +24A3;So;L; +24A4;So;L; +24A5;So;L; +24A6;So;L; +24A7;So;L; +24A8;So;L; +24A9;So;L; +24AA;So;L; +24AB;So;L; +24AC;So;L; +24AD;So;L; +24AE;So;L; +24AF;So;L; +24B0;So;L; +24B1;So;L; +24B2;So;L; +24B3;So;L; +24B4;So;L; +24B5;So;L; +24B6;So;L; +24B7;So;L; +24B8;So;L; +24B9;So;L; +24BA;So;L; +24BB;So;L; +24BC;So;L; +24BD;So;L; +24BE;So;L; +24BF;So;L; +24C0;So;L; +24C1;So;L; +24C2;So;L; +24C3;So;L; +24C4;So;L; +24C5;So;L; +24C6;So;L; +24C7;So;L; +24C8;So;L; +24C9;So;L; +24CA;So;L; +24CB;So;L; +24CC;So;L; +24CD;So;L; +24CE;So;L; +24CF;So;L; +24D0;So;L; +24D1;So;L; +24D2;So;L; +24D3;So;L; +24D4;So;L; +24D5;So;L; +24D6;So;L; +24D7;So;L; +24D8;So;L; +24D9;So;L; +24DA;So;L; +24DB;So;L; +24DC;So;L; +24DD;So;L; +24DE;So;L; +24DF;So;L; +24E0;So;L; +24E1;So;L; +24E2;So;L; +24E3;So;L; +24E4;So;L; +24E5;So;L; +24E6;So;L; +24E7;So;L; +24E8;So;L; +24E9;So;L; +24EA;No;EN; +2500;So;ON; +2501;So;ON; +2502;So;ON; +2503;So;ON; +2504;So;ON; +2505;So;ON; +2506;So;ON; +2507;So;ON; +2508;So;ON; +2509;So;ON; +250A;So;ON; +250B;So;ON; +250C;So;ON; +250D;So;ON; +250E;So;ON; +250F;So;ON; +2510;So;ON; +2511;So;ON; +2512;So;ON; +2513;So;ON; +2514;So;ON; +2515;So;ON; +2516;So;ON; +2517;So;ON; +2518;So;ON; +2519;So;ON; +251A;So;ON; +251B;So;ON; +251C;So;ON; +251D;So;ON; +251E;So;ON; +251F;So;ON; +2520;So;ON; +2521;So;ON; +2522;So;ON; +2523;So;ON; +2524;So;ON; +2525;So;ON; +2526;So;ON; +2527;So;ON; +2528;So;ON; +2529;So;ON; +252A;So;ON; +252B;So;ON; +252C;So;ON; +252D;So;ON; +252E;So;ON; +252F;So;ON; +2530;So;ON; +2531;So;ON; +2532;So;ON; +2533;So;ON; +2534;So;ON; +2535;So;ON; +2536;So;ON; +2537;So;ON; +2538;So;ON; +2539;So;ON; +253A;So;ON; +253B;So;ON; +253C;So;ON; +253D;So;ON; +253E;So;ON; +253F;So;ON; +2540;So;ON; +2541;So;ON; +2542;So;ON; +2543;So;ON; +2544;So;ON; +2545;So;ON; +2546;So;ON; +2547;So;ON; +2548;So;ON; +2549;So;ON; +254A;So;ON; +254B;So;ON; +254C;So;ON; +254D;So;ON; +254E;So;ON; +254F;So;ON; +2550;So;ON; +2551;So;ON; +2552;So;ON; +2553;So;ON; +2554;So;ON; +2555;So;ON; +2556;So;ON; +2557;So;ON; +2558;So;ON; +2559;So;ON; +255A;So;ON; +255B;So;ON; +255C;So;ON; +255D;So;ON; +255E;So;ON; +255F;So;ON; +2560;So;ON; +2561;So;ON; +2562;So;ON; +2563;So;ON; +2564;So;ON; +2565;So;ON; +2566;So;ON; +2567;So;ON; +2568;So;ON; +2569;So;ON; +256A;So;ON; +256B;So;ON; +256C;So;ON; +256D;So;ON; +256E;So;ON; +256F;So;ON; +2570;So;ON; +2571;So;ON; +2572;So;ON; +2573;So;ON; +2574;So;ON; +2575;So;ON; +2576;So;ON; +2577;So;ON; +2578;So;ON; +2579;So;ON; +257A;So;ON; +257B;So;ON; +257C;So;ON; +257D;So;ON; +257E;So;ON; +257F;So;ON; +2580;So;ON; +2581;So;ON; +2582;So;ON; +2583;So;ON; +2584;So;ON; +2585;So;ON; +2586;So;ON; +2587;So;ON; +2588;So;ON; +2589;So;ON; +258A;So;ON; +258B;So;ON; +258C;So;ON; +258D;So;ON; +258E;So;ON; +258F;So;ON; +2590;So;ON; +2591;So;ON; +2592;So;ON; +2593;So;ON; +2594;So;ON; +2595;So;ON; +25A0;So;ON; +25A1;So;ON; +25A2;So;ON; +25A3;So;ON; +25A4;So;ON; +25A5;So;ON; +25A6;So;ON; +25A7;So;ON; +25A8;So;ON; +25A9;So;ON; +25AA;So;ON; +25AB;So;ON; +25AC;So;ON; +25AD;So;ON; +25AE;So;ON; +25AF;So;ON; +25B0;So;ON; +25B1;So;ON; +25B2;So;ON; +25B3;So;ON; +25B4;So;ON; +25B5;So;ON; +25B6;So;ON; +25B7;Sm;ON; +25B8;So;ON; +25B9;So;ON; +25BA;So;ON; +25BB;So;ON; +25BC;So;ON; +25BD;So;ON; +25BE;So;ON; +25BF;So;ON; +25C0;So;ON; +25C1;Sm;ON; +25C2;So;ON; +25C3;So;ON; +25C4;So;ON; +25C5;So;ON; +25C6;So;ON; +25C7;So;ON; +25C8;So;ON; +25C9;So;ON; +25CA;So;ON; +25CB;So;ON; +25CC;So;ON; +25CD;So;ON; +25CE;So;ON; +25CF;So;ON; +25D0;So;ON; +25D1;So;ON; +25D2;So;ON; +25D3;So;ON; +25D4;So;ON; +25D5;So;ON; +25D6;So;ON; +25D7;So;ON; +25D8;So;ON; +25D9;So;ON; +25DA;So;ON; +25DB;So;ON; +25DC;So;ON; +25DD;So;ON; +25DE;So;ON; +25DF;So;ON; +25E0;So;ON; +25E1;So;ON; +25E2;So;ON; +25E3;So;ON; +25E4;So;ON; +25E5;So;ON; +25E6;So;ON; +25E7;So;ON; +25E8;So;ON; +25E9;So;ON; +25EA;So;ON; +25EB;So;ON; +25EC;So;ON; +25ED;So;ON; +25EE;So;ON; +25EF;So;ON; +25F0;So;ON; +25F1;So;ON; +25F2;So;ON; +25F3;So;ON; +25F4;So;ON; +25F5;So;ON; +25F6;So;ON; +25F7;So;ON; +2600;So;ON; +2601;So;ON; +2602;So;ON; +2603;So;ON; +2604;So;ON; +2605;So;ON; +2606;So;ON; +2607;So;ON; +2608;So;ON; +2609;So;ON; +260A;So;ON; +260B;So;ON; +260C;So;ON; +260D;So;ON; +260E;So;ON; +260F;So;ON; +2610;So;ON; +2611;So;ON; +2612;So;ON; +2613;So;ON; +2619;So;ON; +261A;So;ON; +261B;So;ON; +261C;So;ON; +261D;So;ON; +261E;So;ON; +261F;So;ON; +2620;So;ON; +2621;So;ON; +2622;So;ON; +2623;So;ON; +2624;So;ON; +2625;So;ON; +2626;So;ON; +2627;So;ON; +2628;So;ON; +2629;So;ON; +262A;So;ON; +262B;So;ON; +262C;So;ON; +262D;So;ON; +262E;So;ON; +262F;So;ON; +2630;So;ON; +2631;So;ON; +2632;So;ON; +2633;So;ON; +2634;So;ON; +2635;So;ON; +2636;So;ON; +2637;So;ON; +2638;So;ON; +2639;So;ON; +263A;So;ON; +263B;So;ON; +263C;So;ON; +263D;So;ON; +263E;So;ON; +263F;So;ON; +2640;So;ON; +2641;So;ON; +2642;So;ON; +2643;So;ON; +2644;So;ON; +2645;So;ON; +2646;So;ON; +2647;So;ON; +2648;So;ON; +2649;So;ON; +264A;So;ON; +264B;So;ON; +264C;So;ON; +264D;So;ON; +264E;So;ON; +264F;So;ON; +2650;So;ON; +2651;So;ON; +2652;So;ON; +2653;So;ON; +2654;So;ON; +2655;So;ON; +2656;So;ON; +2657;So;ON; +2658;So;ON; +2659;So;ON; +265A;So;ON; +265B;So;ON; +265C;So;ON; +265D;So;ON; +265E;So;ON; +265F;So;ON; +2660;So;ON; +2661;So;ON; +2662;So;ON; +2663;So;ON; +2664;So;ON; +2665;So;ON; +2666;So;ON; +2667;So;ON; +2668;So;ON; +2669;So;ON; +266A;So;ON; +266B;So;ON; +266C;So;ON; +266D;So;ON; +266E;So;ON; +266F;Sm;ON; +2670;So;ON; +2671;So;ON; +2701;So;ON; +2702;So;ON; +2703;So;ON; +2704;So;ON; +2706;So;ON; +2707;So;ON; +2708;So;ON; +2709;So;ON; +270C;So;ON; +270D;So;ON; +270E;So;ON; +270F;So;ON; +2710;So;ON; +2711;So;ON; +2712;So;ON; +2713;So;ON; +2714;So;ON; +2715;So;ON; +2716;So;ON; +2717;So;ON; +2718;So;ON; +2719;So;ON; +271A;So;ON; +271B;So;ON; +271C;So;ON; +271D;So;ON; +271E;So;ON; +271F;So;ON; +2720;So;ON; +2721;So;ON; +2722;So;ON; +2723;So;ON; +2724;So;ON; +2725;So;ON; +2726;So;ON; +2727;So;ON; +2729;So;ON; +272A;So;ON; +272B;So;ON; +272C;So;ON; +272D;So;ON; +272E;So;ON; +272F;So;ON; +2730;So;ON; +2731;So;ON; +2732;So;ON; +2733;So;ON; +2734;So;ON; +2735;So;ON; +2736;So;ON; +2737;So;ON; +2738;So;ON; +2739;So;ON; +273A;So;ON; +273B;So;ON; +273C;So;ON; +273D;So;ON; +273E;So;ON; +273F;So;ON; +2740;So;ON; +2741;So;ON; +2742;So;ON; +2743;So;ON; +2744;So;ON; +2745;So;ON; +2746;So;ON; +2747;So;ON; +2748;So;ON; +2749;So;ON; +274A;So;ON; +274B;So;ON; +274D;So;ON; +274F;So;ON; +2750;So;ON; +2751;So;ON; +2752;So;ON; +2756;So;ON; +2758;So;ON; +2759;So;ON; +275A;So;ON; +275B;So;ON; +275C;So;ON; +275D;So;ON; +275E;So;ON; +2761;So;ON; +2762;So;ON; +2763;So;ON; +2764;So;ON; +2765;So;ON; +2766;So;ON; +2767;So;ON; +2776;No;ON; +2777;No;ON; +2778;No;ON; +2779;No;ON; +277A;No;ON; +277B;No;ON; +277C;No;ON; +277D;No;ON; +277E;No;ON; +277F;No;ON; +2780;No;ON; +2781;No;ON; +2782;No;ON; +2783;No;ON; +2784;No;ON; +2785;No;ON; +2786;No;ON; +2787;No;ON; +2788;No;ON; +2789;No;ON; +278A;No;ON; +278B;No;ON; +278C;No;ON; +278D;No;ON; +278E;No;ON; +278F;No;ON; +2790;No;ON; +2791;No;ON; +2792;No;ON; +2793;No;ON; +2794;So;ON; +2798;So;ON; +2799;So;ON; +279A;So;ON; +279B;So;ON; +279C;So;ON; +279D;So;ON; +279E;So;ON; +279F;So;ON; +27A0;So;ON; +27A1;So;ON; +27A2;So;ON; +27A3;So;ON; +27A4;So;ON; +27A5;So;ON; +27A6;So;ON; +27A7;So;ON; +27A8;So;ON; +27A9;So;ON; +27AA;So;ON; +27AB;So;ON; +27AC;So;ON; +27AD;So;ON; +27AE;So;ON; +27AF;So;ON; +27B1;So;ON; +27B2;So;ON; +27B3;So;ON; +27B4;So;ON; +27B5;So;ON; +27B6;So;ON; +27B7;So;ON; +27B8;So;ON; +27B9;So;ON; +27BA;So;ON; +27BB;So;ON; +27BC;So;ON; +27BD;So;ON; +27BE;So;ON; +2800;So;ON; +2801;So;ON; +2802;So;ON; +2803;So;ON; +2804;So;ON; +2805;So;ON; +2806;So;ON; +2807;So;ON; +2808;So;ON; +2809;So;ON; +280A;So;ON; +280B;So;ON; +280C;So;ON; +280D;So;ON; +280E;So;ON; +280F;So;ON; +2810;So;ON; +2811;So;ON; +2812;So;ON; +2813;So;ON; +2814;So;ON; +2815;So;ON; +2816;So;ON; +2817;So;ON; +2818;So;ON; +2819;So;ON; +281A;So;ON; +281B;So;ON; +281C;So;ON; +281D;So;ON; +281E;So;ON; +281F;So;ON; +2820;So;ON; +2821;So;ON; +2822;So;ON; +2823;So;ON; +2824;So;ON; +2825;So;ON; +2826;So;ON; +2827;So;ON; +2828;So;ON; +2829;So;ON; +282A;So;ON; +282B;So;ON; +282C;So;ON; +282D;So;ON; +282E;So;ON; +282F;So;ON; +2830;So;ON; +2831;So;ON; +2832;So;ON; +2833;So;ON; +2834;So;ON; +2835;So;ON; +2836;So;ON; +2837;So;ON; +2838;So;ON; +2839;So;ON; +283A;So;ON; +283B;So;ON; +283C;So;ON; +283D;So;ON; +283E;So;ON; +283F;So;ON; +2840;So;ON; +2841;So;ON; +2842;So;ON; +2843;So;ON; +2844;So;ON; +2845;So;ON; +2846;So;ON; +2847;So;ON; +2848;So;ON; +2849;So;ON; +284A;So;ON; +284B;So;ON; +284C;So;ON; +284D;So;ON; +284E;So;ON; +284F;So;ON; +2850;So;ON; +2851;So;ON; +2852;So;ON; +2853;So;ON; +2854;So;ON; +2855;So;ON; +2856;So;ON; +2857;So;ON; +2858;So;ON; +2859;So;ON; +285A;So;ON; +285B;So;ON; +285C;So;ON; +285D;So;ON; +285E;So;ON; +285F;So;ON; +2860;So;ON; +2861;So;ON; +2862;So;ON; +2863;So;ON; +2864;So;ON; +2865;So;ON; +2866;So;ON; +2867;So;ON; +2868;So;ON; +2869;So;ON; +286A;So;ON; +286B;So;ON; +286C;So;ON; +286D;So;ON; +286E;So;ON; +286F;So;ON; +2870;So;ON; +2871;So;ON; +2872;So;ON; +2873;So;ON; +2874;So;ON; +2875;So;ON; +2876;So;ON; +2877;So;ON; +2878;So;ON; +2879;So;ON; +287A;So;ON; +287B;So;ON; +287C;So;ON; +287D;So;ON; +287E;So;ON; +287F;So;ON; +2880;So;ON; +2881;So;ON; +2882;So;ON; +2883;So;ON; +2884;So;ON; +2885;So;ON; +2886;So;ON; +2887;So;ON; +2888;So;ON; +2889;So;ON; +288A;So;ON; +288B;So;ON; +288C;So;ON; +288D;So;ON; +288E;So;ON; +288F;So;ON; +2890;So;ON; +2891;So;ON; +2892;So;ON; +2893;So;ON; +2894;So;ON; +2895;So;ON; +2896;So;ON; +2897;So;ON; +2898;So;ON; +2899;So;ON; +289A;So;ON; +289B;So;ON; +289C;So;ON; +289D;So;ON; +289E;So;ON; +289F;So;ON; +28A0;So;ON; +28A1;So;ON; +28A2;So;ON; +28A3;So;ON; +28A4;So;ON; +28A5;So;ON; +28A6;So;ON; +28A7;So;ON; +28A8;So;ON; +28A9;So;ON; +28AA;So;ON; +28AB;So;ON; +28AC;So;ON; +28AD;So;ON; +28AE;So;ON; +28AF;So;ON; +28B0;So;ON; +28B1;So;ON; +28B2;So;ON; +28B3;So;ON; +28B4;So;ON; +28B5;So;ON; +28B6;So;ON; +28B7;So;ON; +28B8;So;ON; +28B9;So;ON; +28BA;So;ON; +28BB;So;ON; +28BC;So;ON; +28BD;So;ON; +28BE;So;ON; +28BF;So;ON; +28C0;So;ON; +28C1;So;ON; +28C2;So;ON; +28C3;So;ON; +28C4;So;ON; +28C5;So;ON; +28C6;So;ON; +28C7;So;ON; +28C8;So;ON; +28C9;So;ON; +28CA;So;ON; +28CB;So;ON; +28CC;So;ON; +28CD;So;ON; +28CE;So;ON; +28CF;So;ON; +28D0;So;ON; +28D1;So;ON; +28D2;So;ON; +28D3;So;ON; +28D4;So;ON; +28D5;So;ON; +28D6;So;ON; +28D7;So;ON; +28D8;So;ON; +28D9;So;ON; +28DA;So;ON; +28DB;So;ON; +28DC;So;ON; +28DD;So;ON; +28DE;So;ON; +28DF;So;ON; +28E0;So;ON; +28E1;So;ON; +28E2;So;ON; +28E3;So;ON; +28E4;So;ON; +28E5;So;ON; +28E6;So;ON; +28E7;So;ON; +28E8;So;ON; +28E9;So;ON; +28EA;So;ON; +28EB;So;ON; +28EC;So;ON; +28ED;So;ON; +28EE;So;ON; +28EF;So;ON; +28F0;So;ON; +28F1;So;ON; +28F2;So;ON; +28F3;So;ON; +28F4;So;ON; +28F5;So;ON; +28F6;So;ON; +28F7;So;ON; +28F8;So;ON; +28F9;So;ON; +28FA;So;ON; +28FB;So;ON; +28FC;So;ON; +28FD;So;ON; +28FE;So;ON; +28FF;So;ON; +2E80;So;ON; +2E81;So;ON; +2E82;So;ON; +2E83;So;ON; +2E84;So;ON; +2E85;So;ON; +2E86;So;ON; +2E87;So;ON; +2E88;So;ON; +2E89;So;ON; +2E8A;So;ON; +2E8B;So;ON; +2E8C;So;ON; +2E8D;So;ON; +2E8E;So;ON; +2E8F;So;ON; +2E90;So;ON; +2E91;So;ON; +2E92;So;ON; +2E93;So;ON; +2E94;So;ON; +2E95;So;ON; +2E96;So;ON; +2E97;So;ON; +2E98;So;ON; +2E99;So;ON; +2E9B;So;ON; +2E9C;So;ON; +2E9D;So;ON; +2E9E;So;ON; +2E9F;So;ON; +2EA0;So;ON; +2EA1;So;ON; +2EA2;So;ON; +2EA3;So;ON; +2EA4;So;ON; +2EA5;So;ON; +2EA6;So;ON; +2EA7;So;ON; +2EA8;So;ON; +2EA9;So;ON; +2EAA;So;ON; +2EAB;So;ON; +2EAC;So;ON; +2EAD;So;ON; +2EAE;So;ON; +2EAF;So;ON; +2EB0;So;ON; +2EB1;So;ON; +2EB2;So;ON; +2EB3;So;ON; +2EB4;So;ON; +2EB5;So;ON; +2EB6;So;ON; +2EB7;So;ON; +2EB8;So;ON; +2EB9;So;ON; +2EBA;So;ON; +2EBB;So;ON; +2EBC;So;ON; +2EBD;So;ON; +2EBE;So;ON; +2EBF;So;ON; +2EC0;So;ON; +2EC1;So;ON; +2EC2;So;ON; +2EC3;So;ON; +2EC4;So;ON; +2EC5;So;ON; +2EC6;So;ON; +2EC7;So;ON; +2EC8;So;ON; +2EC9;So;ON; +2ECA;So;ON; +2ECB;So;ON; +2ECC;So;ON; +2ECD;So;ON; +2ECE;So;ON; +2ECF;So;ON; +2ED0;So;ON; +2ED1;So;ON; +2ED2;So;ON; +2ED3;So;ON; +2ED4;So;ON; +2ED5;So;ON; +2ED6;So;ON; +2ED7;So;ON; +2ED8;So;ON; +2ED9;So;ON; +2EDA;So;ON; +2EDB;So;ON; +2EDC;So;ON; +2EDD;So;ON; +2EDE;So;ON; +2EDF;So;ON; +2EE0;So;ON; +2EE1;So;ON; +2EE2;So;ON; +2EE3;So;ON; +2EE4;So;ON; +2EE5;So;ON; +2EE6;So;ON; +2EE7;So;ON; +2EE8;So;ON; +2EE9;So;ON; +2EEA;So;ON; +2EEB;So;ON; +2EEC;So;ON; +2EED;So;ON; +2EEE;So;ON; +2EEF;So;ON; +2EF0;So;ON; +2EF1;So;ON; +2EF2;So;ON; +2EF3;So;ON; +2F00;So;ON; +2F01;So;ON; +2F02;So;ON; +2F03;So;ON; +2F04;So;ON; +2F05;So;ON; +2F06;So;ON; +2F07;So;ON; +2F08;So;ON; +2F09;So;ON; +2F0A;So;ON; +2F0B;So;ON; +2F0C;So;ON; +2F0D;So;ON; +2F0E;So;ON; +2F0F;So;ON; +2F10;So;ON; +2F11;So;ON; +2F12;So;ON; +2F13;So;ON; +2F14;So;ON; +2F15;So;ON; +2F16;So;ON; +2F17;So;ON; +2F18;So;ON; +2F19;So;ON; +2F1A;So;ON; +2F1B;So;ON; +2F1C;So;ON; +2F1D;So;ON; +2F1E;So;ON; +2F1F;So;ON; +2F20;So;ON; +2F21;So;ON; +2F22;So;ON; +2F23;So;ON; +2F24;So;ON; +2F25;So;ON; +2F26;So;ON; +2F27;So;ON; +2F28;So;ON; +2F29;So;ON; +2F2A;So;ON; +2F2B;So;ON; +2F2C;So;ON; +2F2D;So;ON; +2F2E;So;ON; +2F2F;So;ON; +2F30;So;ON; +2F31;So;ON; +2F32;So;ON; +2F33;So;ON; +2F34;So;ON; +2F35;So;ON; +2F36;So;ON; +2F37;So;ON; +2F38;So;ON; +2F39;So;ON; +2F3A;So;ON; +2F3B;So;ON; +2F3C;So;ON; +2F3D;So;ON; +2F3E;So;ON; +2F3F;So;ON; +2F40;So;ON; +2F41;So;ON; +2F42;So;ON; +2F43;So;ON; +2F44;So;ON; +2F45;So;ON; +2F46;So;ON; +2F47;So;ON; +2F48;So;ON; +2F49;So;ON; +2F4A;So;ON; +2F4B;So;ON; +2F4C;So;ON; +2F4D;So;ON; +2F4E;So;ON; +2F4F;So;ON; +2F50;So;ON; +2F51;So;ON; +2F52;So;ON; +2F53;So;ON; +2F54;So;ON; +2F55;So;ON; +2F56;So;ON; +2F57;So;ON; +2F58;So;ON; +2F59;So;ON; +2F5A;So;ON; +2F5B;So;ON; +2F5C;So;ON; +2F5D;So;ON; +2F5E;So;ON; +2F5F;So;ON; +2F60;So;ON; +2F61;So;ON; +2F62;So;ON; +2F63;So;ON; +2F64;So;ON; +2F65;So;ON; +2F66;So;ON; +2F67;So;ON; +2F68;So;ON; +2F69;So;ON; +2F6A;So;ON; +2F6B;So;ON; +2F6C;So;ON; +2F6D;So;ON; +2F6E;So;ON; +2F6F;So;ON; +2F70;So;ON; +2F71;So;ON; +2F72;So;ON; +2F73;So;ON; +2F74;So;ON; +2F75;So;ON; +2F76;So;ON; +2F77;So;ON; +2F78;So;ON; +2F79;So;ON; +2F7A;So;ON; +2F7B;So;ON; +2F7C;So;ON; +2F7D;So;ON; +2F7E;So;ON; +2F7F;So;ON; +2F80;So;ON; +2F81;So;ON; +2F82;So;ON; +2F83;So;ON; +2F84;So;ON; +2F85;So;ON; +2F86;So;ON; +2F87;So;ON; +2F88;So;ON; +2F89;So;ON; +2F8A;So;ON; +2F8B;So;ON; +2F8C;So;ON; +2F8D;So;ON; +2F8E;So;ON; +2F8F;So;ON; +2F90;So;ON; +2F91;So;ON; +2F92;So;ON; +2F93;So;ON; +2F94;So;ON; +2F95;So;ON; +2F96;So;ON; +2F97;So;ON; +2F98;So;ON; +2F99;So;ON; +2F9A;So;ON; +2F9B;So;ON; +2F9C;So;ON; +2F9D;So;ON; +2F9E;So;ON; +2F9F;So;ON; +2FA0;So;ON; +2FA1;So;ON; +2FA2;So;ON; +2FA3;So;ON; +2FA4;So;ON; +2FA5;So;ON; +2FA6;So;ON; +2FA7;So;ON; +2FA8;So;ON; +2FA9;So;ON; +2FAA;So;ON; +2FAB;So;ON; +2FAC;So;ON; +2FAD;So;ON; +2FAE;So;ON; +2FAF;So;ON; +2FB0;So;ON; +2FB1;So;ON; +2FB2;So;ON; +2FB3;So;ON; +2FB4;So;ON; +2FB5;So;ON; +2FB6;So;ON; +2FB7;So;ON; +2FB8;So;ON; +2FB9;So;ON; +2FBA;So;ON; +2FBB;So;ON; +2FBC;So;ON; +2FBD;So;ON; +2FBE;So;ON; +2FBF;So;ON; +2FC0;So;ON; +2FC1;So;ON; +2FC2;So;ON; +2FC3;So;ON; +2FC4;So;ON; +2FC5;So;ON; +2FC6;So;ON; +2FC7;So;ON; +2FC8;So;ON; +2FC9;So;ON; +2FCA;So;ON; +2FCB;So;ON; +2FCC;So;ON; +2FCD;So;ON; +2FCE;So;ON; +2FCF;So;ON; +2FD0;So;ON; +2FD1;So;ON; +2FD2;So;ON; +2FD3;So;ON; +2FD4;So;ON; +2FD5;So;ON; +2FF0;So;ON; +2FF1;So;ON; +2FF2;So;ON; +2FF3;So;ON; +2FF4;So;ON; +2FF5;So;ON; +2FF6;So;ON; +2FF7;So;ON; +2FF8;So;ON; +2FF9;So;ON; +2FFA;So;ON; +2FFB;So;ON; +3000;Zs;WS; +3001;Po;ON; +3002;Po;ON; +3003;Po;ON; +3004;So;ON; +3005;Lm;L; +3006;Lo;L; +3007;Nl;L; +3008;Ps;ON; +3009;Pe;ON; +300A;Ps;ON; +300B;Pe;ON; +300C;Ps;ON; +300D;Pe;ON; +300E;Ps;ON; +300F;Pe;ON; +3010;Ps;ON; +3011;Pe;ON; +3012;So;ON; +3013;So;ON; +3014;Ps;ON; +3015;Pe;ON; +3016;Ps;ON; +3017;Pe;ON; +3018;Ps;ON; +3019;Pe;ON; +301A;Ps;ON; +301B;Pe;ON; +301C;Pd;ON; +301D;Ps;ON; +301E;Pe;ON; +301F;Pe;ON; +3020;So;ON; +3021;Nl;L; +3022;Nl;L; +3023;Nl;L; +3024;Nl;L; +3025;Nl;L; +3026;Nl;L; +3027;Nl;L; +3028;Nl;L; +3029;Nl;L; +302A;Mn;NSM; +302B;Mn;NSM; +302C;Mn;NSM; +302D;Mn;NSM; +302E;Mn;NSM; +302F;Mn;NSM; +3030;Pd;ON; +3031;Lm;L; +3032;Lm;L; +3033;Lm;L; +3034;Lm;L; +3035;Lm;L; +3036;So;ON; +3037;So;ON; +3038;Nl;L; +3039;Nl;L; +303A;Nl;L; +303E;So;ON; +303F;So;ON; +3041;Lo;L; +3042;Lo;L; +3043;Lo;L; +3044;Lo;L; +3045;Lo;L; +3046;Lo;L; +3047;Lo;L; +3048;Lo;L; +3049;Lo;L; +304A;Lo;L; +304B;Lo;L; +304C;Lo;L; +304D;Lo;L; +304E;Lo;L; +304F;Lo;L; +3050;Lo;L; +3051;Lo;L; +3052;Lo;L; +3053;Lo;L; +3054;Lo;L; +3055;Lo;L; +3056;Lo;L; +3057;Lo;L; +3058;Lo;L; +3059;Lo;L; +305A;Lo;L; +305B;Lo;L; +305C;Lo;L; +305D;Lo;L; +305E;Lo;L; +305F;Lo;L; +3060;Lo;L; +3061;Lo;L; +3062;Lo;L; +3063;Lo;L; +3064;Lo;L; +3065;Lo;L; +3066;Lo;L; +3067;Lo;L; +3068;Lo;L; +3069;Lo;L; +306A;Lo;L; +306B;Lo;L; +306C;Lo;L; +306D;Lo;L; +306E;Lo;L; +306F;Lo;L; +3070;Lo;L; +3071;Lo;L; +3072;Lo;L; +3073;Lo;L; +3074;Lo;L; +3075;Lo;L; +3076;Lo;L; +3077;Lo;L; +3078;Lo;L; +3079;Lo;L; +307A;Lo;L; +307B;Lo;L; +307C;Lo;L; +307D;Lo;L; +307E;Lo;L; +307F;Lo;L; +3080;Lo;L; +3081;Lo;L; +3082;Lo;L; +3083;Lo;L; +3084;Lo;L; +3085;Lo;L; +3086;Lo;L; +3087;Lo;L; +3088;Lo;L; +3089;Lo;L; +308A;Lo;L; +308B;Lo;L; +308C;Lo;L; +308D;Lo;L; +308E;Lo;L; +308F;Lo;L; +3090;Lo;L; +3091;Lo;L; +3092;Lo;L; +3093;Lo;L; +3094;Lo;L; +3099;Mn;NSM; +309A;Mn;NSM; +309B;Sk;ON; +309C;Sk;ON; +309D;Lm;L; +309E;Lm;L; +30A1;Lo;L; +30A2;Lo;L; +30A3;Lo;L; +30A4;Lo;L; +30A5;Lo;L; +30A6;Lo;L; +30A7;Lo;L; +30A8;Lo;L; +30A9;Lo;L; +30AA;Lo;L; +30AB;Lo;L; +30AC;Lo;L; +30AD;Lo;L; +30AE;Lo;L; +30AF;Lo;L; +30B0;Lo;L; +30B1;Lo;L; +30B2;Lo;L; +30B3;Lo;L; +30B4;Lo;L; +30B5;Lo;L; +30B6;Lo;L; +30B7;Lo;L; +30B8;Lo;L; +30B9;Lo;L; +30BA;Lo;L; +30BB;Lo;L; +30BC;Lo;L; +30BD;Lo;L; +30BE;Lo;L; +30BF;Lo;L; +30C0;Lo;L; +30C1;Lo;L; +30C2;Lo;L; +30C3;Lo;L; +30C4;Lo;L; +30C5;Lo;L; +30C6;Lo;L; +30C7;Lo;L; +30C8;Lo;L; +30C9;Lo;L; +30CA;Lo;L; +30CB;Lo;L; +30CC;Lo;L; +30CD;Lo;L; +30CE;Lo;L; +30CF;Lo;L; +30D0;Lo;L; +30D1;Lo;L; +30D2;Lo;L; +30D3;Lo;L; +30D4;Lo;L; +30D5;Lo;L; +30D6;Lo;L; +30D7;Lo;L; +30D8;Lo;L; +30D9;Lo;L; +30DA;Lo;L; +30DB;Lo;L; +30DC;Lo;L; +30DD;Lo;L; +30DE;Lo;L; +30DF;Lo;L; +30E0;Lo;L; +30E1;Lo;L; +30E2;Lo;L; +30E3;Lo;L; +30E4;Lo;L; +30E5;Lo;L; +30E6;Lo;L; +30E7;Lo;L; +30E8;Lo;L; +30E9;Lo;L; +30EA;Lo;L; +30EB;Lo;L; +30EC;Lo;L; +30ED;Lo;L; +30EE;Lo;L; +30EF;Lo;L; +30F0;Lo;L; +30F1;Lo;L; +30F2;Lo;L; +30F3;Lo;L; +30F4;Lo;L; +30F5;Lo;L; +30F6;Lo;L; +30F7;Lo;L; +30F8;Lo;L; +30F9;Lo;L; +30FA;Lo;L; +30FB;Pc;ON; +30FC;Lm;L; +30FD;Lm;L; +30FE;Lm;L; +3105;Lo;L; +3106;Lo;L; +3107;Lo;L; +3108;Lo;L; +3109;Lo;L; +310A;Lo;L; +310B;Lo;L; +310C;Lo;L; +310D;Lo;L; +310E;Lo;L; +310F;Lo;L; +3110;Lo;L; +3111;Lo;L; +3112;Lo;L; +3113;Lo;L; +3114;Lo;L; +3115;Lo;L; +3116;Lo;L; +3117;Lo;L; +3118;Lo;L; +3119;Lo;L; +311A;Lo;L; +311B;Lo;L; +311C;Lo;L; +311D;Lo;L; +311E;Lo;L; +311F;Lo;L; +3120;Lo;L; +3121;Lo;L; +3122;Lo;L; +3123;Lo;L; +3124;Lo;L; +3125;Lo;L; +3126;Lo;L; +3127;Lo;L; +3128;Lo;L; +3129;Lo;L; +312A;Lo;L; +312B;Lo;L; +312C;Lo;L; +3131;Lo;L; +3132;Lo;L; +3133;Lo;L; +3134;Lo;L; +3135;Lo;L; +3136;Lo;L; +3137;Lo;L; +3138;Lo;L; +3139;Lo;L; +313A;Lo;L; +313B;Lo;L; +313C;Lo;L; +313D;Lo;L; +313E;Lo;L; +313F;Lo;L; +3140;Lo;L; +3141;Lo;L; +3142;Lo;L; +3143;Lo;L; +3144;Lo;L; +3145;Lo;L; +3146;Lo;L; +3147;Lo;L; +3148;Lo;L; +3149;Lo;L; +314A;Lo;L; +314B;Lo;L; +314C;Lo;L; +314D;Lo;L; +314E;Lo;L; +314F;Lo;L; +3150;Lo;L; +3151;Lo;L; +3152;Lo;L; +3153;Lo;L; +3154;Lo;L; +3155;Lo;L; +3156;Lo;L; +3157;Lo;L; +3158;Lo;L; +3159;Lo;L; +315A;Lo;L; +315B;Lo;L; +315C;Lo;L; +315D;Lo;L; +315E;Lo;L; +315F;Lo;L; +3160;Lo;L; +3161;Lo;L; +3162;Lo;L; +3163;Lo;L; +3164;Lo;L; +3165;Lo;L; +3166;Lo;L; +3167;Lo;L; +3168;Lo;L; +3169;Lo;L; +316A;Lo;L; +316B;Lo;L; +316C;Lo;L; +316D;Lo;L; +316E;Lo;L; +316F;Lo;L; +3170;Lo;L; +3171;Lo;L; +3172;Lo;L; +3173;Lo;L; +3174;Lo;L; +3175;Lo;L; +3176;Lo;L; +3177;Lo;L; +3178;Lo;L; +3179;Lo;L; +317A;Lo;L; +317B;Lo;L; +317C;Lo;L; +317D;Lo;L; +317E;Lo;L; +317F;Lo;L; +3180;Lo;L; +3181;Lo;L; +3182;Lo;L; +3183;Lo;L; +3184;Lo;L; +3185;Lo;L; +3186;Lo;L; +3187;Lo;L; +3188;Lo;L; +3189;Lo;L; +318A;Lo;L; +318B;Lo;L; +318C;Lo;L; +318D;Lo;L; +318E;Lo;L; +3190;So;L; +3191;So;L; +3192;No;L; +3193;No;L; +3194;No;L; +3195;No;L; +3196;So;L; +3197;So;L; +3198;So;L; +3199;So;L; +319A;So;L; +319B;So;L; +319C;So;L; +319D;So;L; +319E;So;L; +319F;So;L; +31A0;Lo;L; +31A1;Lo;L; +31A2;Lo;L; +31A3;Lo;L; +31A4;Lo;L; +31A5;Lo;L; +31A6;Lo;L; +31A7;Lo;L; +31A8;Lo;L; +31A9;Lo;L; +31AA;Lo;L; +31AB;Lo;L; +31AC;Lo;L; +31AD;Lo;L; +31AE;Lo;L; +31AF;Lo;L; +31B0;Lo;L; +31B1;Lo;L; +31B2;Lo;L; +31B3;Lo;L; +31B4;Lo;L; +31B5;Lo;L; +31B6;Lo;L; +31B7;Lo;L; +3200;So;L; +3201;So;L; +3202;So;L; +3203;So;L; +3204;So;L; +3205;So;L; +3206;So;L; +3207;So;L; +3208;So;L; +3209;So;L; +320A;So;L; +320B;So;L; +320C;So;L; +320D;So;L; +320E;So;L; +320F;So;L; +3210;So;L; +3211;So;L; +3212;So;L; +3213;So;L; +3214;So;L; +3215;So;L; +3216;So;L; +3217;So;L; +3218;So;L; +3219;So;L; +321A;So;L; +321B;So;L; +321C;So;L; +3220;No;L; +3221;No;L; +3222;No;L; +3223;No;L; +3224;No;L; +3225;No;L; +3226;No;L; +3227;No;L; +3228;No;L; +3229;No;L; +322A;So;L; +322B;So;L; +322C;So;L; +322D;So;L; +322E;So;L; +322F;So;L; +3230;So;L; +3231;So;L; +3232;So;L; +3233;So;L; +3234;So;L; +3235;So;L; +3236;So;L; +3237;So;L; +3238;So;L; +3239;So;L; +323A;So;L; +323B;So;L; +323C;So;L; +323D;So;L; +323E;So;L; +323F;So;L; +3240;So;L; +3241;So;L; +3242;So;L; +3243;So;L; +3260;So;L; +3261;So;L; +3262;So;L; +3263;So;L; +3264;So;L; +3265;So;L; +3266;So;L; +3267;So;L; +3268;So;L; +3269;So;L; +326A;So;L; +326B;So;L; +326C;So;L; +326D;So;L; +326E;So;L; +326F;So;L; +3270;So;L; +3271;So;L; +3272;So;L; +3273;So;L; +3274;So;L; +3275;So;L; +3276;So;L; +3277;So;L; +3278;So;L; +3279;So;L; +327A;So;L; +327B;So;L; +327F;So;L; +3280;No;L; +3281;No;L; +3282;No;L; +3283;No;L; +3284;No;L; +3285;No;L; +3286;No;L; +3287;No;L; +3288;No;L; +3289;No;L; +328A;So;L; +328B;So;L; +328C;So;L; +328D;So;L; +328E;So;L; +328F;So;L; +3290;So;L; +3291;So;L; +3292;So;L; +3293;So;L; +3294;So;L; +3295;So;L; +3296;So;L; +3297;So;L; +3298;So;L; +3299;So;L; +329A;So;L; +329B;So;L; +329C;So;L; +329D;So;L; +329E;So;L; +329F;So;L; +32A0;So;L; +32A1;So;L; +32A2;So;L; +32A3;So;L; +32A4;So;L; +32A5;So;L; +32A6;So;L; +32A7;So;L; +32A8;So;L; +32A9;So;L; +32AA;So;L; +32AB;So;L; +32AC;So;L; +32AD;So;L; +32AE;So;L; +32AF;So;L; +32B0;So;L; +32C0;So;L; +32C1;So;L; +32C2;So;L; +32C3;So;L; +32C4;So;L; +32C5;So;L; +32C6;So;L; +32C7;So;L; +32C8;So;L; +32C9;So;L; +32CA;So;L; +32CB;So;L; +32D0;So;L; +32D1;So;L; +32D2;So;L; +32D3;So;L; +32D4;So;L; +32D5;So;L; +32D6;So;L; +32D7;So;L; +32D8;So;L; +32D9;So;L; +32DA;So;L; +32DB;So;L; +32DC;So;L; +32DD;So;L; +32DE;So;L; +32DF;So;L; +32E0;So;L; +32E1;So;L; +32E2;So;L; +32E3;So;L; +32E4;So;L; +32E5;So;L; +32E6;So;L; +32E7;So;L; +32E8;So;L; +32E9;So;L; +32EA;So;L; +32EB;So;L; +32EC;So;L; +32ED;So;L; +32EE;So;L; +32EF;So;L; +32F0;So;L; +32F1;So;L; +32F2;So;L; +32F3;So;L; +32F4;So;L; +32F5;So;L; +32F6;So;L; +32F7;So;L; +32F8;So;L; +32F9;So;L; +32FA;So;L; +32FB;So;L; +32FC;So;L; +32FD;So;L; +32FE;So;L; +3300;So;L; +3301;So;L; +3302;So;L; +3303;So;L; +3304;So;L; +3305;So;L; +3306;So;L; +3307;So;L; +3308;So;L; +3309;So;L; +330A;So;L; +330B;So;L; +330C;So;L; +330D;So;L; +330E;So;L; +330F;So;L; +3310;So;L; +3311;So;L; +3312;So;L; +3313;So;L; +3314;So;L; +3315;So;L; +3316;So;L; +3317;So;L; +3318;So;L; +3319;So;L; +331A;So;L; +331B;So;L; +331C;So;L; +331D;So;L; +331E;So;L; +331F;So;L; +3320;So;L; +3321;So;L; +3322;So;L; +3323;So;L; +3324;So;L; +3325;So;L; +3326;So;L; +3327;So;L; +3328;So;L; +3329;So;L; +332A;So;L; +332B;So;L; +332C;So;L; +332D;So;L; +332E;So;L; +332F;So;L; +3330;So;L; +3331;So;L; +3332;So;L; +3333;So;L; +3334;So;L; +3335;So;L; +3336;So;L; +3337;So;L; +3338;So;L; +3339;So;L; +333A;So;L; +333B;So;L; +333C;So;L; +333D;So;L; +333E;So;L; +333F;So;L; +3340;So;L; +3341;So;L; +3342;So;L; +3343;So;L; +3344;So;L; +3345;So;L; +3346;So;L; +3347;So;L; +3348;So;L; +3349;So;L; +334A;So;L; +334B;So;L; +334C;So;L; +334D;So;L; +334E;So;L; +334F;So;L; +3350;So;L; +3351;So;L; +3352;So;L; +3353;So;L; +3354;So;L; +3355;So;L; +3356;So;L; +3357;So;L; +3358;So;L; +3359;So;L; +335A;So;L; +335B;So;L; +335C;So;L; +335D;So;L; +335E;So;L; +335F;So;L; +3360;So;L; +3361;So;L; +3362;So;L; +3363;So;L; +3364;So;L; +3365;So;L; +3366;So;L; +3367;So;L; +3368;So;L; +3369;So;L; +336A;So;L; +336B;So;L; +336C;So;L; +336D;So;L; +336E;So;L; +336F;So;L; +3370;So;L; +3371;So;L; +3372;So;L; +3373;So;L; +3374;So;L; +3375;So;L; +3376;So;L; +337B;So;L; +337C;So;L; +337D;So;L; +337E;So;L; +337F;So;L; +3380;So;L; +3381;So;L; +3382;So;L; +3383;So;L; +3384;So;L; +3385;So;L; +3386;So;L; +3387;So;L; +3388;So;L; +3389;So;L; +338A;So;L; +338B;So;L; +338C;So;L; +338D;So;L; +338E;So;L; +338F;So;L; +3390;So;L; +3391;So;L; +3392;So;L; +3393;So;L; +3394;So;L; +3395;So;L; +3396;So;L; +3397;So;L; +3398;So;L; +3399;So;L; +339A;So;L; +339B;So;L; +339C;So;L; +339D;So;L; +339E;So;L; +339F;So;L; +33A0;So;L; +33A1;So;L; +33A2;So;L; +33A3;So;L; +33A4;So;L; +33A5;So;L; +33A6;So;L; +33A7;So;L; +33A8;So;L; +33A9;So;L; +33AA;So;L; +33AB;So;L; +33AC;So;L; +33AD;So;L; +33AE;So;L; +33AF;So;L; +33B0;So;L; +33B1;So;L; +33B2;So;L; +33B3;So;L; +33B4;So;L; +33B5;So;L; +33B6;So;L; +33B7;So;L; +33B8;So;L; +33B9;So;L; +33BA;So;L; +33BB;So;L; +33BC;So;L; +33BD;So;L; +33BE;So;L; +33BF;So;L; +33C0;So;L; +33C1;So;L; +33C2;So;L; +33C3;So;L; +33C4;So;L; +33C5;So;L; +33C6;So;L; +33C7;So;L; +33C8;So;L; +33C9;So;L; +33CA;So;L; +33CB;So;L; +33CC;So;L; +33CD;So;L; +33CE;So;L; +33CF;So;L; +33D0;So;L; +33D1;So;L; +33D2;So;L; +33D3;So;L; +33D4;So;L; +33D5;So;L; +33D6;So;L; +33D7;So;L; +33D8;So;L; +33D9;So;L; +33DA;So;L; +33DB;So;L; +33DC;So;L; +33DD;So;L; +33E0;So;L; +33E1;So;L; +33E2;So;L; +33E3;So;L; +33E4;So;L; +33E5;So;L; +33E6;So;L; +33E7;So;L; +33E8;So;L; +33E9;So;L; +33EA;So;L; +33EB;So;L; +33EC;So;L; +33ED;So;L; +33EE;So;L; +33EF;So;L; +33F0;So;L; +33F1;So;L; +33F2;So;L; +33F3;So;L; +33F4;So;L; +33F5;So;L; +33F6;So;L; +33F7;So;L; +33F8;So;L; +33F9;So;L; +33FA;So;L; +33FB;So;L; +33FC;So;L; +33FD;So;L; +33FE;So;L; +3400;Lo;L; +4DB5;Lo;L; +4E00;Lo;L; +9FA5;Lo;L; +A000;Lo;L; +A001;Lo;L; +A002;Lo;L; +A003;Lo;L; +A004;Lo;L; +A005;Lo;L; +A006;Lo;L; +A007;Lo;L; +A008;Lo;L; +A009;Lo;L; +A00A;Lo;L; +A00B;Lo;L; +A00C;Lo;L; +A00D;Lo;L; +A00E;Lo;L; +A00F;Lo;L; +A010;Lo;L; +A011;Lo;L; +A012;Lo;L; +A013;Lo;L; +A014;Lo;L; +A015;Lo;L; +A016;Lo;L; +A017;Lo;L; +A018;Lo;L; +A019;Lo;L; +A01A;Lo;L; +A01B;Lo;L; +A01C;Lo;L; +A01D;Lo;L; +A01E;Lo;L; +A01F;Lo;L; +A020;Lo;L; +A021;Lo;L; +A022;Lo;L; +A023;Lo;L; +A024;Lo;L; +A025;Lo;L; +A026;Lo;L; +A027;Lo;L; +A028;Lo;L; +A029;Lo;L; +A02A;Lo;L; +A02B;Lo;L; +A02C;Lo;L; +A02D;Lo;L; +A02E;Lo;L; +A02F;Lo;L; +A030;Lo;L; +A031;Lo;L; +A032;Lo;L; +A033;Lo;L; +A034;Lo;L; +A035;Lo;L; +A036;Lo;L; +A037;Lo;L; +A038;Lo;L; +A039;Lo;L; +A03A;Lo;L; +A03B;Lo;L; +A03C;Lo;L; +A03D;Lo;L; +A03E;Lo;L; +A03F;Lo;L; +A040;Lo;L; +A041;Lo;L; +A042;Lo;L; +A043;Lo;L; +A044;Lo;L; +A045;Lo;L; +A046;Lo;L; +A047;Lo;L; +A048;Lo;L; +A049;Lo;L; +A04A;Lo;L; +A04B;Lo;L; +A04C;Lo;L; +A04D;Lo;L; +A04E;Lo;L; +A04F;Lo;L; +A050;Lo;L; +A051;Lo;L; +A052;Lo;L; +A053;Lo;L; +A054;Lo;L; +A055;Lo;L; +A056;Lo;L; +A057;Lo;L; +A058;Lo;L; +A059;Lo;L; +A05A;Lo;L; +A05B;Lo;L; +A05C;Lo;L; +A05D;Lo;L; +A05E;Lo;L; +A05F;Lo;L; +A060;Lo;L; +A061;Lo;L; +A062;Lo;L; +A063;Lo;L; +A064;Lo;L; +A065;Lo;L; +A066;Lo;L; +A067;Lo;L; +A068;Lo;L; +A069;Lo;L; +A06A;Lo;L; +A06B;Lo;L; +A06C;Lo;L; +A06D;Lo;L; +A06E;Lo;L; +A06F;Lo;L; +A070;Lo;L; +A071;Lo;L; +A072;Lo;L; +A073;Lo;L; +A074;Lo;L; +A075;Lo;L; +A076;Lo;L; +A077;Lo;L; +A078;Lo;L; +A079;Lo;L; +A07A;Lo;L; +A07B;Lo;L; +A07C;Lo;L; +A07D;Lo;L; +A07E;Lo;L; +A07F;Lo;L; +A080;Lo;L; +A081;Lo;L; +A082;Lo;L; +A083;Lo;L; +A084;Lo;L; +A085;Lo;L; +A086;Lo;L; +A087;Lo;L; +A088;Lo;L; +A089;Lo;L; +A08A;Lo;L; +A08B;Lo;L; +A08C;Lo;L; +A08D;Lo;L; +A08E;Lo;L; +A08F;Lo;L; +A090;Lo;L; +A091;Lo;L; +A092;Lo;L; +A093;Lo;L; +A094;Lo;L; +A095;Lo;L; +A096;Lo;L; +A097;Lo;L; +A098;Lo;L; +A099;Lo;L; +A09A;Lo;L; +A09B;Lo;L; +A09C;Lo;L; +A09D;Lo;L; +A09E;Lo;L; +A09F;Lo;L; +A0A0;Lo;L; +A0A1;Lo;L; +A0A2;Lo;L; +A0A3;Lo;L; +A0A4;Lo;L; +A0A5;Lo;L; +A0A6;Lo;L; +A0A7;Lo;L; +A0A8;Lo;L; +A0A9;Lo;L; +A0AA;Lo;L; +A0AB;Lo;L; +A0AC;Lo;L; +A0AD;Lo;L; +A0AE;Lo;L; +A0AF;Lo;L; +A0B0;Lo;L; +A0B1;Lo;L; +A0B2;Lo;L; +A0B3;Lo;L; +A0B4;Lo;L; +A0B5;Lo;L; +A0B6;Lo;L; +A0B7;Lo;L; +A0B8;Lo;L; +A0B9;Lo;L; +A0BA;Lo;L; +A0BB;Lo;L; +A0BC;Lo;L; +A0BD;Lo;L; +A0BE;Lo;L; +A0BF;Lo;L; +A0C0;Lo;L; +A0C1;Lo;L; +A0C2;Lo;L; +A0C3;Lo;L; +A0C4;Lo;L; +A0C5;Lo;L; +A0C6;Lo;L; +A0C7;Lo;L; +A0C8;Lo;L; +A0C9;Lo;L; +A0CA;Lo;L; +A0CB;Lo;L; +A0CC;Lo;L; +A0CD;Lo;L; +A0CE;Lo;L; +A0CF;Lo;L; +A0D0;Lo;L; +A0D1;Lo;L; +A0D2;Lo;L; +A0D3;Lo;L; +A0D4;Lo;L; +A0D5;Lo;L; +A0D6;Lo;L; +A0D7;Lo;L; +A0D8;Lo;L; +A0D9;Lo;L; +A0DA;Lo;L; +A0DB;Lo;L; +A0DC;Lo;L; +A0DD;Lo;L; +A0DE;Lo;L; +A0DF;Lo;L; +A0E0;Lo;L; +A0E1;Lo;L; +A0E2;Lo;L; +A0E3;Lo;L; +A0E4;Lo;L; +A0E5;Lo;L; +A0E6;Lo;L; +A0E7;Lo;L; +A0E8;Lo;L; +A0E9;Lo;L; +A0EA;Lo;L; +A0EB;Lo;L; +A0EC;Lo;L; +A0ED;Lo;L; +A0EE;Lo;L; +A0EF;Lo;L; +A0F0;Lo;L; +A0F1;Lo;L; +A0F2;Lo;L; +A0F3;Lo;L; +A0F4;Lo;L; +A0F5;Lo;L; +A0F6;Lo;L; +A0F7;Lo;L; +A0F8;Lo;L; +A0F9;Lo;L; +A0FA;Lo;L; +A0FB;Lo;L; +A0FC;Lo;L; +A0FD;Lo;L; +A0FE;Lo;L; +A0FF;Lo;L; +A100;Lo;L; +A101;Lo;L; +A102;Lo;L; +A103;Lo;L; +A104;Lo;L; +A105;Lo;L; +A106;Lo;L; +A107;Lo;L; +A108;Lo;L; +A109;Lo;L; +A10A;Lo;L; +A10B;Lo;L; +A10C;Lo;L; +A10D;Lo;L; +A10E;Lo;L; +A10F;Lo;L; +A110;Lo;L; +A111;Lo;L; +A112;Lo;L; +A113;Lo;L; +A114;Lo;L; +A115;Lo;L; +A116;Lo;L; +A117;Lo;L; +A118;Lo;L; +A119;Lo;L; +A11A;Lo;L; +A11B;Lo;L; +A11C;Lo;L; +A11D;Lo;L; +A11E;Lo;L; +A11F;Lo;L; +A120;Lo;L; +A121;Lo;L; +A122;Lo;L; +A123;Lo;L; +A124;Lo;L; +A125;Lo;L; +A126;Lo;L; +A127;Lo;L; +A128;Lo;L; +A129;Lo;L; +A12A;Lo;L; +A12B;Lo;L; +A12C;Lo;L; +A12D;Lo;L; +A12E;Lo;L; +A12F;Lo;L; +A130;Lo;L; +A131;Lo;L; +A132;Lo;L; +A133;Lo;L; +A134;Lo;L; +A135;Lo;L; +A136;Lo;L; +A137;Lo;L; +A138;Lo;L; +A139;Lo;L; +A13A;Lo;L; +A13B;Lo;L; +A13C;Lo;L; +A13D;Lo;L; +A13E;Lo;L; +A13F;Lo;L; +A140;Lo;L; +A141;Lo;L; +A142;Lo;L; +A143;Lo;L; +A144;Lo;L; +A145;Lo;L; +A146;Lo;L; +A147;Lo;L; +A148;Lo;L; +A149;Lo;L; +A14A;Lo;L; +A14B;Lo;L; +A14C;Lo;L; +A14D;Lo;L; +A14E;Lo;L; +A14F;Lo;L; +A150;Lo;L; +A151;Lo;L; +A152;Lo;L; +A153;Lo;L; +A154;Lo;L; +A155;Lo;L; +A156;Lo;L; +A157;Lo;L; +A158;Lo;L; +A159;Lo;L; +A15A;Lo;L; +A15B;Lo;L; +A15C;Lo;L; +A15D;Lo;L; +A15E;Lo;L; +A15F;Lo;L; +A160;Lo;L; +A161;Lo;L; +A162;Lo;L; +A163;Lo;L; +A164;Lo;L; +A165;Lo;L; +A166;Lo;L; +A167;Lo;L; +A168;Lo;L; +A169;Lo;L; +A16A;Lo;L; +A16B;Lo;L; +A16C;Lo;L; +A16D;Lo;L; +A16E;Lo;L; +A16F;Lo;L; +A170;Lo;L; +A171;Lo;L; +A172;Lo;L; +A173;Lo;L; +A174;Lo;L; +A175;Lo;L; +A176;Lo;L; +A177;Lo;L; +A178;Lo;L; +A179;Lo;L; +A17A;Lo;L; +A17B;Lo;L; +A17C;Lo;L; +A17D;Lo;L; +A17E;Lo;L; +A17F;Lo;L; +A180;Lo;L; +A181;Lo;L; +A182;Lo;L; +A183;Lo;L; +A184;Lo;L; +A185;Lo;L; +A186;Lo;L; +A187;Lo;L; +A188;Lo;L; +A189;Lo;L; +A18A;Lo;L; +A18B;Lo;L; +A18C;Lo;L; +A18D;Lo;L; +A18E;Lo;L; +A18F;Lo;L; +A190;Lo;L; +A191;Lo;L; +A192;Lo;L; +A193;Lo;L; +A194;Lo;L; +A195;Lo;L; +A196;Lo;L; +A197;Lo;L; +A198;Lo;L; +A199;Lo;L; +A19A;Lo;L; +A19B;Lo;L; +A19C;Lo;L; +A19D;Lo;L; +A19E;Lo;L; +A19F;Lo;L; +A1A0;Lo;L; +A1A1;Lo;L; +A1A2;Lo;L; +A1A3;Lo;L; +A1A4;Lo;L; +A1A5;Lo;L; +A1A6;Lo;L; +A1A7;Lo;L; +A1A8;Lo;L; +A1A9;Lo;L; +A1AA;Lo;L; +A1AB;Lo;L; +A1AC;Lo;L; +A1AD;Lo;L; +A1AE;Lo;L; +A1AF;Lo;L; +A1B0;Lo;L; +A1B1;Lo;L; +A1B2;Lo;L; +A1B3;Lo;L; +A1B4;Lo;L; +A1B5;Lo;L; +A1B6;Lo;L; +A1B7;Lo;L; +A1B8;Lo;L; +A1B9;Lo;L; +A1BA;Lo;L; +A1BB;Lo;L; +A1BC;Lo;L; +A1BD;Lo;L; +A1BE;Lo;L; +A1BF;Lo;L; +A1C0;Lo;L; +A1C1;Lo;L; +A1C2;Lo;L; +A1C3;Lo;L; +A1C4;Lo;L; +A1C5;Lo;L; +A1C6;Lo;L; +A1C7;Lo;L; +A1C8;Lo;L; +A1C9;Lo;L; +A1CA;Lo;L; +A1CB;Lo;L; +A1CC;Lo;L; +A1CD;Lo;L; +A1CE;Lo;L; +A1CF;Lo;L; +A1D0;Lo;L; +A1D1;Lo;L; +A1D2;Lo;L; +A1D3;Lo;L; +A1D4;Lo;L; +A1D5;Lo;L; +A1D6;Lo;L; +A1D7;Lo;L; +A1D8;Lo;L; +A1D9;Lo;L; +A1DA;Lo;L; +A1DB;Lo;L; +A1DC;Lo;L; +A1DD;Lo;L; +A1DE;Lo;L; +A1DF;Lo;L; +A1E0;Lo;L; +A1E1;Lo;L; +A1E2;Lo;L; +A1E3;Lo;L; +A1E4;Lo;L; +A1E5;Lo;L; +A1E6;Lo;L; +A1E7;Lo;L; +A1E8;Lo;L; +A1E9;Lo;L; +A1EA;Lo;L; +A1EB;Lo;L; +A1EC;Lo;L; +A1ED;Lo;L; +A1EE;Lo;L; +A1EF;Lo;L; +A1F0;Lo;L; +A1F1;Lo;L; +A1F2;Lo;L; +A1F3;Lo;L; +A1F4;Lo;L; +A1F5;Lo;L; +A1F6;Lo;L; +A1F7;Lo;L; +A1F8;Lo;L; +A1F9;Lo;L; +A1FA;Lo;L; +A1FB;Lo;L; +A1FC;Lo;L; +A1FD;Lo;L; +A1FE;Lo;L; +A1FF;Lo;L; +A200;Lo;L; +A201;Lo;L; +A202;Lo;L; +A203;Lo;L; +A204;Lo;L; +A205;Lo;L; +A206;Lo;L; +A207;Lo;L; +A208;Lo;L; +A209;Lo;L; +A20A;Lo;L; +A20B;Lo;L; +A20C;Lo;L; +A20D;Lo;L; +A20E;Lo;L; +A20F;Lo;L; +A210;Lo;L; +A211;Lo;L; +A212;Lo;L; +A213;Lo;L; +A214;Lo;L; +A215;Lo;L; +A216;Lo;L; +A217;Lo;L; +A218;Lo;L; +A219;Lo;L; +A21A;Lo;L; +A21B;Lo;L; +A21C;Lo;L; +A21D;Lo;L; +A21E;Lo;L; +A21F;Lo;L; +A220;Lo;L; +A221;Lo;L; +A222;Lo;L; +A223;Lo;L; +A224;Lo;L; +A225;Lo;L; +A226;Lo;L; +A227;Lo;L; +A228;Lo;L; +A229;Lo;L; +A22A;Lo;L; +A22B;Lo;L; +A22C;Lo;L; +A22D;Lo;L; +A22E;Lo;L; +A22F;Lo;L; +A230;Lo;L; +A231;Lo;L; +A232;Lo;L; +A233;Lo;L; +A234;Lo;L; +A235;Lo;L; +A236;Lo;L; +A237;Lo;L; +A238;Lo;L; +A239;Lo;L; +A23A;Lo;L; +A23B;Lo;L; +A23C;Lo;L; +A23D;Lo;L; +A23E;Lo;L; +A23F;Lo;L; +A240;Lo;L; +A241;Lo;L; +A242;Lo;L; +A243;Lo;L; +A244;Lo;L; +A245;Lo;L; +A246;Lo;L; +A247;Lo;L; +A248;Lo;L; +A249;Lo;L; +A24A;Lo;L; +A24B;Lo;L; +A24C;Lo;L; +A24D;Lo;L; +A24E;Lo;L; +A24F;Lo;L; +A250;Lo;L; +A251;Lo;L; +A252;Lo;L; +A253;Lo;L; +A254;Lo;L; +A255;Lo;L; +A256;Lo;L; +A257;Lo;L; +A258;Lo;L; +A259;Lo;L; +A25A;Lo;L; +A25B;Lo;L; +A25C;Lo;L; +A25D;Lo;L; +A25E;Lo;L; +A25F;Lo;L; +A260;Lo;L; +A261;Lo;L; +A262;Lo;L; +A263;Lo;L; +A264;Lo;L; +A265;Lo;L; +A266;Lo;L; +A267;Lo;L; +A268;Lo;L; +A269;Lo;L; +A26A;Lo;L; +A26B;Lo;L; +A26C;Lo;L; +A26D;Lo;L; +A26E;Lo;L; +A26F;Lo;L; +A270;Lo;L; +A271;Lo;L; +A272;Lo;L; +A273;Lo;L; +A274;Lo;L; +A275;Lo;L; +A276;Lo;L; +A277;Lo;L; +A278;Lo;L; +A279;Lo;L; +A27A;Lo;L; +A27B;Lo;L; +A27C;Lo;L; +A27D;Lo;L; +A27E;Lo;L; +A27F;Lo;L; +A280;Lo;L; +A281;Lo;L; +A282;Lo;L; +A283;Lo;L; +A284;Lo;L; +A285;Lo;L; +A286;Lo;L; +A287;Lo;L; +A288;Lo;L; +A289;Lo;L; +A28A;Lo;L; +A28B;Lo;L; +A28C;Lo;L; +A28D;Lo;L; +A28E;Lo;L; +A28F;Lo;L; +A290;Lo;L; +A291;Lo;L; +A292;Lo;L; +A293;Lo;L; +A294;Lo;L; +A295;Lo;L; +A296;Lo;L; +A297;Lo;L; +A298;Lo;L; +A299;Lo;L; +A29A;Lo;L; +A29B;Lo;L; +A29C;Lo;L; +A29D;Lo;L; +A29E;Lo;L; +A29F;Lo;L; +A2A0;Lo;L; +A2A1;Lo;L; +A2A2;Lo;L; +A2A3;Lo;L; +A2A4;Lo;L; +A2A5;Lo;L; +A2A6;Lo;L; +A2A7;Lo;L; +A2A8;Lo;L; +A2A9;Lo;L; +A2AA;Lo;L; +A2AB;Lo;L; +A2AC;Lo;L; +A2AD;Lo;L; +A2AE;Lo;L; +A2AF;Lo;L; +A2B0;Lo;L; +A2B1;Lo;L; +A2B2;Lo;L; +A2B3;Lo;L; +A2B4;Lo;L; +A2B5;Lo;L; +A2B6;Lo;L; +A2B7;Lo;L; +A2B8;Lo;L; +A2B9;Lo;L; +A2BA;Lo;L; +A2BB;Lo;L; +A2BC;Lo;L; +A2BD;Lo;L; +A2BE;Lo;L; +A2BF;Lo;L; +A2C0;Lo;L; +A2C1;Lo;L; +A2C2;Lo;L; +A2C3;Lo;L; +A2C4;Lo;L; +A2C5;Lo;L; +A2C6;Lo;L; +A2C7;Lo;L; +A2C8;Lo;L; +A2C9;Lo;L; +A2CA;Lo;L; +A2CB;Lo;L; +A2CC;Lo;L; +A2CD;Lo;L; +A2CE;Lo;L; +A2CF;Lo;L; +A2D0;Lo;L; +A2D1;Lo;L; +A2D2;Lo;L; +A2D3;Lo;L; +A2D4;Lo;L; +A2D5;Lo;L; +A2D6;Lo;L; +A2D7;Lo;L; +A2D8;Lo;L; +A2D9;Lo;L; +A2DA;Lo;L; +A2DB;Lo;L; +A2DC;Lo;L; +A2DD;Lo;L; +A2DE;Lo;L; +A2DF;Lo;L; +A2E0;Lo;L; +A2E1;Lo;L; +A2E2;Lo;L; +A2E3;Lo;L; +A2E4;Lo;L; +A2E5;Lo;L; +A2E6;Lo;L; +A2E7;Lo;L; +A2E8;Lo;L; +A2E9;Lo;L; +A2EA;Lo;L; +A2EB;Lo;L; +A2EC;Lo;L; +A2ED;Lo;L; +A2EE;Lo;L; +A2EF;Lo;L; +A2F0;Lo;L; +A2F1;Lo;L; +A2F2;Lo;L; +A2F3;Lo;L; +A2F4;Lo;L; +A2F5;Lo;L; +A2F6;Lo;L; +A2F7;Lo;L; +A2F8;Lo;L; +A2F9;Lo;L; +A2FA;Lo;L; +A2FB;Lo;L; +A2FC;Lo;L; +A2FD;Lo;L; +A2FE;Lo;L; +A2FF;Lo;L; +A300;Lo;L; +A301;Lo;L; +A302;Lo;L; +A303;Lo;L; +A304;Lo;L; +A305;Lo;L; +A306;Lo;L; +A307;Lo;L; +A308;Lo;L; +A309;Lo;L; +A30A;Lo;L; +A30B;Lo;L; +A30C;Lo;L; +A30D;Lo;L; +A30E;Lo;L; +A30F;Lo;L; +A310;Lo;L; +A311;Lo;L; +A312;Lo;L; +A313;Lo;L; +A314;Lo;L; +A315;Lo;L; +A316;Lo;L; +A317;Lo;L; +A318;Lo;L; +A319;Lo;L; +A31A;Lo;L; +A31B;Lo;L; +A31C;Lo;L; +A31D;Lo;L; +A31E;Lo;L; +A31F;Lo;L; +A320;Lo;L; +A321;Lo;L; +A322;Lo;L; +A323;Lo;L; +A324;Lo;L; +A325;Lo;L; +A326;Lo;L; +A327;Lo;L; +A328;Lo;L; +A329;Lo;L; +A32A;Lo;L; +A32B;Lo;L; +A32C;Lo;L; +A32D;Lo;L; +A32E;Lo;L; +A32F;Lo;L; +A330;Lo;L; +A331;Lo;L; +A332;Lo;L; +A333;Lo;L; +A334;Lo;L; +A335;Lo;L; +A336;Lo;L; +A337;Lo;L; +A338;Lo;L; +A339;Lo;L; +A33A;Lo;L; +A33B;Lo;L; +A33C;Lo;L; +A33D;Lo;L; +A33E;Lo;L; +A33F;Lo;L; +A340;Lo;L; +A341;Lo;L; +A342;Lo;L; +A343;Lo;L; +A344;Lo;L; +A345;Lo;L; +A346;Lo;L; +A347;Lo;L; +A348;Lo;L; +A349;Lo;L; +A34A;Lo;L; +A34B;Lo;L; +A34C;Lo;L; +A34D;Lo;L; +A34E;Lo;L; +A34F;Lo;L; +A350;Lo;L; +A351;Lo;L; +A352;Lo;L; +A353;Lo;L; +A354;Lo;L; +A355;Lo;L; +A356;Lo;L; +A357;Lo;L; +A358;Lo;L; +A359;Lo;L; +A35A;Lo;L; +A35B;Lo;L; +A35C;Lo;L; +A35D;Lo;L; +A35E;Lo;L; +A35F;Lo;L; +A360;Lo;L; +A361;Lo;L; +A362;Lo;L; +A363;Lo;L; +A364;Lo;L; +A365;Lo;L; +A366;Lo;L; +A367;Lo;L; +A368;Lo;L; +A369;Lo;L; +A36A;Lo;L; +A36B;Lo;L; +A36C;Lo;L; +A36D;Lo;L; +A36E;Lo;L; +A36F;Lo;L; +A370;Lo;L; +A371;Lo;L; +A372;Lo;L; +A373;Lo;L; +A374;Lo;L; +A375;Lo;L; +A376;Lo;L; +A377;Lo;L; +A378;Lo;L; +A379;Lo;L; +A37A;Lo;L; +A37B;Lo;L; +A37C;Lo;L; +A37D;Lo;L; +A37E;Lo;L; +A37F;Lo;L; +A380;Lo;L; +A381;Lo;L; +A382;Lo;L; +A383;Lo;L; +A384;Lo;L; +A385;Lo;L; +A386;Lo;L; +A387;Lo;L; +A388;Lo;L; +A389;Lo;L; +A38A;Lo;L; +A38B;Lo;L; +A38C;Lo;L; +A38D;Lo;L; +A38E;Lo;L; +A38F;Lo;L; +A390;Lo;L; +A391;Lo;L; +A392;Lo;L; +A393;Lo;L; +A394;Lo;L; +A395;Lo;L; +A396;Lo;L; +A397;Lo;L; +A398;Lo;L; +A399;Lo;L; +A39A;Lo;L; +A39B;Lo;L; +A39C;Lo;L; +A39D;Lo;L; +A39E;Lo;L; +A39F;Lo;L; +A3A0;Lo;L; +A3A1;Lo;L; +A3A2;Lo;L; +A3A3;Lo;L; +A3A4;Lo;L; +A3A5;Lo;L; +A3A6;Lo;L; +A3A7;Lo;L; +A3A8;Lo;L; +A3A9;Lo;L; +A3AA;Lo;L; +A3AB;Lo;L; +A3AC;Lo;L; +A3AD;Lo;L; +A3AE;Lo;L; +A3AF;Lo;L; +A3B0;Lo;L; +A3B1;Lo;L; +A3B2;Lo;L; +A3B3;Lo;L; +A3B4;Lo;L; +A3B5;Lo;L; +A3B6;Lo;L; +A3B7;Lo;L; +A3B8;Lo;L; +A3B9;Lo;L; +A3BA;Lo;L; +A3BB;Lo;L; +A3BC;Lo;L; +A3BD;Lo;L; +A3BE;Lo;L; +A3BF;Lo;L; +A3C0;Lo;L; +A3C1;Lo;L; +A3C2;Lo;L; +A3C3;Lo;L; +A3C4;Lo;L; +A3C5;Lo;L; +A3C6;Lo;L; +A3C7;Lo;L; +A3C8;Lo;L; +A3C9;Lo;L; +A3CA;Lo;L; +A3CB;Lo;L; +A3CC;Lo;L; +A3CD;Lo;L; +A3CE;Lo;L; +A3CF;Lo;L; +A3D0;Lo;L; +A3D1;Lo;L; +A3D2;Lo;L; +A3D3;Lo;L; +A3D4;Lo;L; +A3D5;Lo;L; +A3D6;Lo;L; +A3D7;Lo;L; +A3D8;Lo;L; +A3D9;Lo;L; +A3DA;Lo;L; +A3DB;Lo;L; +A3DC;Lo;L; +A3DD;Lo;L; +A3DE;Lo;L; +A3DF;Lo;L; +A3E0;Lo;L; +A3E1;Lo;L; +A3E2;Lo;L; +A3E3;Lo;L; +A3E4;Lo;L; +A3E5;Lo;L; +A3E6;Lo;L; +A3E7;Lo;L; +A3E8;Lo;L; +A3E9;Lo;L; +A3EA;Lo;L; +A3EB;Lo;L; +A3EC;Lo;L; +A3ED;Lo;L; +A3EE;Lo;L; +A3EF;Lo;L; +A3F0;Lo;L; +A3F1;Lo;L; +A3F2;Lo;L; +A3F3;Lo;L; +A3F4;Lo;L; +A3F5;Lo;L; +A3F6;Lo;L; +A3F7;Lo;L; +A3F8;Lo;L; +A3F9;Lo;L; +A3FA;Lo;L; +A3FB;Lo;L; +A3FC;Lo;L; +A3FD;Lo;L; +A3FE;Lo;L; +A3FF;Lo;L; +A400;Lo;L; +A401;Lo;L; +A402;Lo;L; +A403;Lo;L; +A404;Lo;L; +A405;Lo;L; +A406;Lo;L; +A407;Lo;L; +A408;Lo;L; +A409;Lo;L; +A40A;Lo;L; +A40B;Lo;L; +A40C;Lo;L; +A40D;Lo;L; +A40E;Lo;L; +A40F;Lo;L; +A410;Lo;L; +A411;Lo;L; +A412;Lo;L; +A413;Lo;L; +A414;Lo;L; +A415;Lo;L; +A416;Lo;L; +A417;Lo;L; +A418;Lo;L; +A419;Lo;L; +A41A;Lo;L; +A41B;Lo;L; +A41C;Lo;L; +A41D;Lo;L; +A41E;Lo;L; +A41F;Lo;L; +A420;Lo;L; +A421;Lo;L; +A422;Lo;L; +A423;Lo;L; +A424;Lo;L; +A425;Lo;L; +A426;Lo;L; +A427;Lo;L; +A428;Lo;L; +A429;Lo;L; +A42A;Lo;L; +A42B;Lo;L; +A42C;Lo;L; +A42D;Lo;L; +A42E;Lo;L; +A42F;Lo;L; +A430;Lo;L; +A431;Lo;L; +A432;Lo;L; +A433;Lo;L; +A434;Lo;L; +A435;Lo;L; +A436;Lo;L; +A437;Lo;L; +A438;Lo;L; +A439;Lo;L; +A43A;Lo;L; +A43B;Lo;L; +A43C;Lo;L; +A43D;Lo;L; +A43E;Lo;L; +A43F;Lo;L; +A440;Lo;L; +A441;Lo;L; +A442;Lo;L; +A443;Lo;L; +A444;Lo;L; +A445;Lo;L; +A446;Lo;L; +A447;Lo;L; +A448;Lo;L; +A449;Lo;L; +A44A;Lo;L; +A44B;Lo;L; +A44C;Lo;L; +A44D;Lo;L; +A44E;Lo;L; +A44F;Lo;L; +A450;Lo;L; +A451;Lo;L; +A452;Lo;L; +A453;Lo;L; +A454;Lo;L; +A455;Lo;L; +A456;Lo;L; +A457;Lo;L; +A458;Lo;L; +A459;Lo;L; +A45A;Lo;L; +A45B;Lo;L; +A45C;Lo;L; +A45D;Lo;L; +A45E;Lo;L; +A45F;Lo;L; +A460;Lo;L; +A461;Lo;L; +A462;Lo;L; +A463;Lo;L; +A464;Lo;L; +A465;Lo;L; +A466;Lo;L; +A467;Lo;L; +A468;Lo;L; +A469;Lo;L; +A46A;Lo;L; +A46B;Lo;L; +A46C;Lo;L; +A46D;Lo;L; +A46E;Lo;L; +A46F;Lo;L; +A470;Lo;L; +A471;Lo;L; +A472;Lo;L; +A473;Lo;L; +A474;Lo;L; +A475;Lo;L; +A476;Lo;L; +A477;Lo;L; +A478;Lo;L; +A479;Lo;L; +A47A;Lo;L; +A47B;Lo;L; +A47C;Lo;L; +A47D;Lo;L; +A47E;Lo;L; +A47F;Lo;L; +A480;Lo;L; +A481;Lo;L; +A482;Lo;L; +A483;Lo;L; +A484;Lo;L; +A485;Lo;L; +A486;Lo;L; +A487;Lo;L; +A488;Lo;L; +A489;Lo;L; +A48A;Lo;L; +A48B;Lo;L; +A48C;Lo;L; +A490;So;ON; +A491;So;ON; +A492;So;ON; +A493;So;ON; +A494;So;ON; +A495;So;ON; +A496;So;ON; +A497;So;ON; +A498;So;ON; +A499;So;ON; +A49A;So;ON; +A49B;So;ON; +A49C;So;ON; +A49D;So;ON; +A49E;So;ON; +A49F;So;ON; +A4A0;So;ON; +A4A1;So;ON; +A4A4;So;ON; +A4A5;So;ON; +A4A6;So;ON; +A4A7;So;ON; +A4A8;So;ON; +A4A9;So;ON; +A4AA;So;ON; +A4AB;So;ON; +A4AC;So;ON; +A4AD;So;ON; +A4AE;So;ON; +A4AF;So;ON; +A4B0;So;ON; +A4B1;So;ON; +A4B2;So;ON; +A4B3;So;ON; +A4B5;So;ON; +A4B6;So;ON; +A4B7;So;ON; +A4B8;So;ON; +A4B9;So;ON; +A4BA;So;ON; +A4BB;So;ON; +A4BC;So;ON; +A4BD;So;ON; +A4BE;So;ON; +A4BF;So;ON; +A4C0;So;ON; +A4C2;So;ON; +A4C3;So;ON; +A4C4;So;ON; +A4C6;So;ON; +AC00;Lo;L; +D7A3;Lo;L; +D800;Cs;L; +DB7F;Cs;L; +DB80;Cs;L; +DBFF;Cs;L; +DC00;Cs;L; +DFFF;Cs;L; +E000;Co;L; +F8FF;Co;L; +F900;Lo;L; +F901;Lo;L; +F902;Lo;L; +F903;Lo;L; +F904;Lo;L; +F905;Lo;L; +F906;Lo;L; +F907;Lo;L; +F908;Lo;L; +F909;Lo;L; +F90A;Lo;L; +F90B;Lo;L; +F90C;Lo;L; +F90D;Lo;L; +F90E;Lo;L; +F90F;Lo;L; +F910;Lo;L; +F911;Lo;L; +F912;Lo;L; +F913;Lo;L; +F914;Lo;L; +F915;Lo;L; +F916;Lo;L; +F917;Lo;L; +F918;Lo;L; +F919;Lo;L; +F91A;Lo;L; +F91B;Lo;L; +F91C;Lo;L; +F91D;Lo;L; +F91E;Lo;L; +F91F;Lo;L; +F920;Lo;L; +F921;Lo;L; +F922;Lo;L; +F923;Lo;L; +F924;Lo;L; +F925;Lo;L; +F926;Lo;L; +F927;Lo;L; +F928;Lo;L; +F929;Lo;L; +F92A;Lo;L; +F92B;Lo;L; +F92C;Lo;L; +F92D;Lo;L; +F92E;Lo;L; +F92F;Lo;L; +F930;Lo;L; +F931;Lo;L; +F932;Lo;L; +F933;Lo;L; +F934;Lo;L; +F935;Lo;L; +F936;Lo;L; +F937;Lo;L; +F938;Lo;L; +F939;Lo;L; +F93A;Lo;L; +F93B;Lo;L; +F93C;Lo;L; +F93D;Lo;L; +F93E;Lo;L; +F93F;Lo;L; +F940;Lo;L; +F941;Lo;L; +F942;Lo;L; +F943;Lo;L; +F944;Lo;L; +F945;Lo;L; +F946;Lo;L; +F947;Lo;L; +F948;Lo;L; +F949;Lo;L; +F94A;Lo;L; +F94B;Lo;L; +F94C;Lo;L; +F94D;Lo;L; +F94E;Lo;L; +F94F;Lo;L; +F950;Lo;L; +F951;Lo;L; +F952;Lo;L; +F953;Lo;L; +F954;Lo;L; +F955;Lo;L; +F956;Lo;L; +F957;Lo;L; +F958;Lo;L; +F959;Lo;L; +F95A;Lo;L; +F95B;Lo;L; +F95C;Lo;L; +F95D;Lo;L; +F95E;Lo;L; +F95F;Lo;L; +F960;Lo;L; +F961;Lo;L; +F962;Lo;L; +F963;Lo;L; +F964;Lo;L; +F965;Lo;L; +F966;Lo;L; +F967;Lo;L; +F968;Lo;L; +F969;Lo;L; +F96A;Lo;L; +F96B;Lo;L; +F96C;Lo;L; +F96D;Lo;L; +F96E;Lo;L; +F96F;Lo;L; +F970;Lo;L; +F971;Lo;L; +F972;Lo;L; +F973;Lo;L; +F974;Lo;L; +F975;Lo;L; +F976;Lo;L; +F977;Lo;L; +F978;Lo;L; +F979;Lo;L; +F97A;Lo;L; +F97B;Lo;L; +F97C;Lo;L; +F97D;Lo;L; +F97E;Lo;L; +F97F;Lo;L; +F980;Lo;L; +F981;Lo;L; +F982;Lo;L; +F983;Lo;L; +F984;Lo;L; +F985;Lo;L; +F986;Lo;L; +F987;Lo;L; +F988;Lo;L; +F989;Lo;L; +F98A;Lo;L; +F98B;Lo;L; +F98C;Lo;L; +F98D;Lo;L; +F98E;Lo;L; +F98F;Lo;L; +F990;Lo;L; +F991;Lo;L; +F992;Lo;L; +F993;Lo;L; +F994;Lo;L; +F995;Lo;L; +F996;Lo;L; +F997;Lo;L; +F998;Lo;L; +F999;Lo;L; +F99A;Lo;L; +F99B;Lo;L; +F99C;Lo;L; +F99D;Lo;L; +F99E;Lo;L; +F99F;Lo;L; +F9A0;Lo;L; +F9A1;Lo;L; +F9A2;Lo;L; +F9A3;Lo;L; +F9A4;Lo;L; +F9A5;Lo;L; +F9A6;Lo;L; +F9A7;Lo;L; +F9A8;Lo;L; +F9A9;Lo;L; +F9AA;Lo;L; +F9AB;Lo;L; +F9AC;Lo;L; +F9AD;Lo;L; +F9AE;Lo;L; +F9AF;Lo;L; +F9B0;Lo;L; +F9B1;Lo;L; +F9B2;Lo;L; +F9B3;Lo;L; +F9B4;Lo;L; +F9B5;Lo;L; +F9B6;Lo;L; +F9B7;Lo;L; +F9B8;Lo;L; +F9B9;Lo;L; +F9BA;Lo;L; +F9BB;Lo;L; +F9BC;Lo;L; +F9BD;Lo;L; +F9BE;Lo;L; +F9BF;Lo;L; +F9C0;Lo;L; +F9C1;Lo;L; +F9C2;Lo;L; +F9C3;Lo;L; +F9C4;Lo;L; +F9C5;Lo;L; +F9C6;Lo;L; +F9C7;Lo;L; +F9C8;Lo;L; +F9C9;Lo;L; +F9CA;Lo;L; +F9CB;Lo;L; +F9CC;Lo;L; +F9CD;Lo;L; +F9CE;Lo;L; +F9CF;Lo;L; +F9D0;Lo;L; +F9D1;Lo;L; +F9D2;Lo;L; +F9D3;Lo;L; +F9D4;Lo;L; +F9D5;Lo;L; +F9D6;Lo;L; +F9D7;Lo;L; +F9D8;Lo;L; +F9D9;Lo;L; +F9DA;Lo;L; +F9DB;Lo;L; +F9DC;Lo;L; +F9DD;Lo;L; +F9DE;Lo;L; +F9DF;Lo;L; +F9E0;Lo;L; +F9E1;Lo;L; +F9E2;Lo;L; +F9E3;Lo;L; +F9E4;Lo;L; +F9E5;Lo;L; +F9E6;Lo;L; +F9E7;Lo;L; +F9E8;Lo;L; +F9E9;Lo;L; +F9EA;Lo;L; +F9EB;Lo;L; +F9EC;Lo;L; +F9ED;Lo;L; +F9EE;Lo;L; +F9EF;Lo;L; +F9F0;Lo;L; +F9F1;Lo;L; +F9F2;Lo;L; +F9F3;Lo;L; +F9F4;Lo;L; +F9F5;Lo;L; +F9F6;Lo;L; +F9F7;Lo;L; +F9F8;Lo;L; +F9F9;Lo;L; +F9FA;Lo;L; +F9FB;Lo;L; +F9FC;Lo;L; +F9FD;Lo;L; +F9FE;Lo;L; +F9FF;Lo;L; +FA00;Lo;L; +FA01;Lo;L; +FA02;Lo;L; +FA03;Lo;L; +FA04;Lo;L; +FA05;Lo;L; +FA06;Lo;L; +FA07;Lo;L; +FA08;Lo;L; +FA09;Lo;L; +FA0A;Lo;L; +FA0B;Lo;L; +FA0C;Lo;L; +FA0D;Lo;L; +FA0E;Lo;L; +FA0F;Lo;L; +FA10;Lo;L; +FA11;Lo;L; +FA12;Lo;L; +FA13;Lo;L; +FA14;Lo;L; +FA15;Lo;L; +FA16;Lo;L; +FA17;Lo;L; +FA18;Lo;L; +FA19;Lo;L; +FA1A;Lo;L; +FA1B;Lo;L; +FA1C;Lo;L; +FA1D;Lo;L; +FA1E;Lo;L; +FA1F;Lo;L; +FA20;Lo;L; +FA21;Lo;L; +FA22;Lo;L; +FA23;Lo;L; +FA24;Lo;L; +FA25;Lo;L; +FA26;Lo;L; +FA27;Lo;L; +FA28;Lo;L; +FA29;Lo;L; +FA2A;Lo;L; +FA2B;Lo;L; +FA2C;Lo;L; +FA2D;Lo;L; +FB00;Ll;L; +FB01;Ll;L; +FB02;Ll;L; +FB03;Ll;L; +FB04;Ll;L; +FB05;Ll;L; +FB06;Ll;L; +FB13;Ll;L; +FB14;Ll;L; +FB15;Ll;L; +FB16;Ll;L; +FB17;Ll;L; +FB1D;Lo;R; +FB1E;Mn;NSM; +FB1F;Lo;R; +FB20;Lo;R; +FB21;Lo;R; +FB22;Lo;R; +FB23;Lo;R; +FB24;Lo;R; +FB25;Lo;R; +FB26;Lo;R; +FB27;Lo;R; +FB28;Lo;R; +FB29;Sm;ET; +FB2A;Lo;R; +FB2B;Lo;R; +FB2C;Lo;R; +FB2D;Lo;R; +FB2E;Lo;R; +FB2F;Lo;R; +FB30;Lo;R; +FB31;Lo;R; +FB32;Lo;R; +FB33;Lo;R; +FB34;Lo;R; +FB35;Lo;R; +FB36;Lo;R; +FB38;Lo;R; +FB39;Lo;R; +FB3A;Lo;R; +FB3B;Lo;R; +FB3C;Lo;R; +FB3E;Lo;R; +FB40;Lo;R; +FB41;Lo;R; +FB43;Lo;R; +FB44;Lo;R; +FB46;Lo;R; +FB47;Lo;R; +FB48;Lo;R; +FB49;Lo;R; +FB4A;Lo;R; +FB4B;Lo;R; +FB4C;Lo;R; +FB4D;Lo;R; +FB4E;Lo;R; +FB4F;Lo;R; +FB50;Lo;AL; +FB51;Lo;AL; +FB52;Lo;AL; +FB53;Lo;AL; +FB54;Lo;AL; +FB55;Lo;AL; +FB56;Lo;AL; +FB57;Lo;AL; +FB58;Lo;AL; +FB59;Lo;AL; +FB5A;Lo;AL; +FB5B;Lo;AL; +FB5C;Lo;AL; +FB5D;Lo;AL; +FB5E;Lo;AL; +FB5F;Lo;AL; +FB60;Lo;AL; +FB61;Lo;AL; +FB62;Lo;AL; +FB63;Lo;AL; +FB64;Lo;AL; +FB65;Lo;AL; +FB66;Lo;AL; +FB67;Lo;AL; +FB68;Lo;AL; +FB69;Lo;AL; +FB6A;Lo;AL; +FB6B;Lo;AL; +FB6C;Lo;AL; +FB6D;Lo;AL; +FB6E;Lo;AL; +FB6F;Lo;AL; +FB70;Lo;AL; +FB71;Lo;AL; +FB72;Lo;AL; +FB73;Lo;AL; +FB74;Lo;AL; +FB75;Lo;AL; +FB76;Lo;AL; +FB77;Lo;AL; +FB78;Lo;AL; +FB79;Lo;AL; +FB7A;Lo;AL; +FB7B;Lo;AL; +FB7C;Lo;AL; +FB7D;Lo;AL; +FB7E;Lo;AL; +FB7F;Lo;AL; +FB80;Lo;AL; +FB81;Lo;AL; +FB82;Lo;AL; +FB83;Lo;AL; +FB84;Lo;AL; +FB85;Lo;AL; +FB86;Lo;AL; +FB87;Lo;AL; +FB88;Lo;AL; +FB89;Lo;AL; +FB8A;Lo;AL; +FB8B;Lo;AL; +FB8C;Lo;AL; +FB8D;Lo;AL; +FB8E;Lo;AL; +FB8F;Lo;AL; +FB90;Lo;AL; +FB91;Lo;AL; +FB92;Lo;AL; +FB93;Lo;AL; +FB94;Lo;AL; +FB95;Lo;AL; +FB96;Lo;AL; +FB97;Lo;AL; +FB98;Lo;AL; +FB99;Lo;AL; +FB9A;Lo;AL; +FB9B;Lo;AL; +FB9C;Lo;AL; +FB9D;Lo;AL; +FB9E;Lo;AL; +FB9F;Lo;AL; +FBA0;Lo;AL; +FBA1;Lo;AL; +FBA2;Lo;AL; +FBA3;Lo;AL; +FBA4;Lo;AL; +FBA5;Lo;AL; +FBA6;Lo;AL; +FBA7;Lo;AL; +FBA8;Lo;AL; +FBA9;Lo;AL; +FBAA;Lo;AL; +FBAB;Lo;AL; +FBAC;Lo;AL; +FBAD;Lo;AL; +FBAE;Lo;AL; +FBAF;Lo;AL; +FBB0;Lo;AL; +FBB1;Lo;AL; +FBD3;Lo;AL; +FBD4;Lo;AL; +FBD5;Lo;AL; +FBD6;Lo;AL; +FBD7;Lo;AL; +FBD8;Lo;AL; +FBD9;Lo;AL; +FBDA;Lo;AL; +FBDB;Lo;AL; +FBDC;Lo;AL; +FBDD;Lo;AL; +FBDE;Lo;AL; +FBDF;Lo;AL; +FBE0;Lo;AL; +FBE1;Lo;AL; +FBE2;Lo;AL; +FBE3;Lo;AL; +FBE4;Lo;AL; +FBE5;Lo;AL; +FBE6;Lo;AL; +FBE7;Lo;AL; +FBE8;Lo;AL; +FBE9;Lo;AL; +FBEA;Lo;AL; +FBEB;Lo;AL; +FBEC;Lo;AL; +FBED;Lo;AL; +FBEE;Lo;AL; +FBEF;Lo;AL; +FBF0;Lo;AL; +FBF1;Lo;AL; +FBF2;Lo;AL; +FBF3;Lo;AL; +FBF4;Lo;AL; +FBF5;Lo;AL; +FBF6;Lo;AL; +FBF7;Lo;AL; +FBF8;Lo;AL; +FBF9;Lo;AL; +FBFA;Lo;AL; +FBFB;Lo;AL; +FBFC;Lo;AL; +FBFD;Lo;AL; +FBFE;Lo;AL; +FBFF;Lo;AL; +FC00;Lo;AL; +FC01;Lo;AL; +FC02;Lo;AL; +FC03;Lo;AL; +FC04;Lo;AL; +FC05;Lo;AL; +FC06;Lo;AL; +FC07;Lo;AL; +FC08;Lo;AL; +FC09;Lo;AL; +FC0A;Lo;AL; +FC0B;Lo;AL; +FC0C;Lo;AL; +FC0D;Lo;AL; +FC0E;Lo;AL; +FC0F;Lo;AL; +FC10;Lo;AL; +FC11;Lo;AL; +FC12;Lo;AL; +FC13;Lo;AL; +FC14;Lo;AL; +FC15;Lo;AL; +FC16;Lo;AL; +FC17;Lo;AL; +FC18;Lo;AL; +FC19;Lo;AL; +FC1A;Lo;AL; +FC1B;Lo;AL; +FC1C;Lo;AL; +FC1D;Lo;AL; +FC1E;Lo;AL; +FC1F;Lo;AL; +FC20;Lo;AL; +FC21;Lo;AL; +FC22;Lo;AL; +FC23;Lo;AL; +FC24;Lo;AL; +FC25;Lo;AL; +FC26;Lo;AL; +FC27;Lo;AL; +FC28;Lo;AL; +FC29;Lo;AL; +FC2A;Lo;AL; +FC2B;Lo;AL; +FC2C;Lo;AL; +FC2D;Lo;AL; +FC2E;Lo;AL; +FC2F;Lo;AL; +FC30;Lo;AL; +FC31;Lo;AL; +FC32;Lo;AL; +FC33;Lo;AL; +FC34;Lo;AL; +FC35;Lo;AL; +FC36;Lo;AL; +FC37;Lo;AL; +FC38;Lo;AL; +FC39;Lo;AL; +FC3A;Lo;AL; +FC3B;Lo;AL; +FC3C;Lo;AL; +FC3D;Lo;AL; +FC3E;Lo;AL; +FC3F;Lo;AL; +FC40;Lo;AL; +FC41;Lo;AL; +FC42;Lo;AL; +FC43;Lo;AL; +FC44;Lo;AL; +FC45;Lo;AL; +FC46;Lo;AL; +FC47;Lo;AL; +FC48;Lo;AL; +FC49;Lo;AL; +FC4A;Lo;AL; +FC4B;Lo;AL; +FC4C;Lo;AL; +FC4D;Lo;AL; +FC4E;Lo;AL; +FC4F;Lo;AL; +FC50;Lo;AL; +FC51;Lo;AL; +FC52;Lo;AL; +FC53;Lo;AL; +FC54;Lo;AL; +FC55;Lo;AL; +FC56;Lo;AL; +FC57;Lo;AL; +FC58;Lo;AL; +FC59;Lo;AL; +FC5A;Lo;AL; +FC5B;Lo;AL; +FC5C;Lo;AL; +FC5D;Lo;AL; +FC5E;Lo;AL; +FC5F;Lo;AL; +FC60;Lo;AL; +FC61;Lo;AL; +FC62;Lo;AL; +FC63;Lo;AL; +FC64;Lo;AL; +FC65;Lo;AL; +FC66;Lo;AL; +FC67;Lo;AL; +FC68;Lo;AL; +FC69;Lo;AL; +FC6A;Lo;AL; +FC6B;Lo;AL; +FC6C;Lo;AL; +FC6D;Lo;AL; +FC6E;Lo;AL; +FC6F;Lo;AL; +FC70;Lo;AL; +FC71;Lo;AL; +FC72;Lo;AL; +FC73;Lo;AL; +FC74;Lo;AL; +FC75;Lo;AL; +FC76;Lo;AL; +FC77;Lo;AL; +FC78;Lo;AL; +FC79;Lo;AL; +FC7A;Lo;AL; +FC7B;Lo;AL; +FC7C;Lo;AL; +FC7D;Lo;AL; +FC7E;Lo;AL; +FC7F;Lo;AL; +FC80;Lo;AL; +FC81;Lo;AL; +FC82;Lo;AL; +FC83;Lo;AL; +FC84;Lo;AL; +FC85;Lo;AL; +FC86;Lo;AL; +FC87;Lo;AL; +FC88;Lo;AL; +FC89;Lo;AL; +FC8A;Lo;AL; +FC8B;Lo;AL; +FC8C;Lo;AL; +FC8D;Lo;AL; +FC8E;Lo;AL; +FC8F;Lo;AL; +FC90;Lo;AL; +FC91;Lo;AL; +FC92;Lo;AL; +FC93;Lo;AL; +FC94;Lo;AL; +FC95;Lo;AL; +FC96;Lo;AL; +FC97;Lo;AL; +FC98;Lo;AL; +FC99;Lo;AL; +FC9A;Lo;AL; +FC9B;Lo;AL; +FC9C;Lo;AL; +FC9D;Lo;AL; +FC9E;Lo;AL; +FC9F;Lo;AL; +FCA0;Lo;AL; +FCA1;Lo;AL; +FCA2;Lo;AL; +FCA3;Lo;AL; +FCA4;Lo;AL; +FCA5;Lo;AL; +FCA6;Lo;AL; +FCA7;Lo;AL; +FCA8;Lo;AL; +FCA9;Lo;AL; +FCAA;Lo;AL; +FCAB;Lo;AL; +FCAC;Lo;AL; +FCAD;Lo;AL; +FCAE;Lo;AL; +FCAF;Lo;AL; +FCB0;Lo;AL; +FCB1;Lo;AL; +FCB2;Lo;AL; +FCB3;Lo;AL; +FCB4;Lo;AL; +FCB5;Lo;AL; +FCB6;Lo;AL; +FCB7;Lo;AL; +FCB8;Lo;AL; +FCB9;Lo;AL; +FCBA;Lo;AL; +FCBB;Lo;AL; +FCBC;Lo;AL; +FCBD;Lo;AL; +FCBE;Lo;AL; +FCBF;Lo;AL; +FCC0;Lo;AL; +FCC1;Lo;AL; +FCC2;Lo;AL; +FCC3;Lo;AL; +FCC4;Lo;AL; +FCC5;Lo;AL; +FCC6;Lo;AL; +FCC7;Lo;AL; +FCC8;Lo;AL; +FCC9;Lo;AL; +FCCA;Lo;AL; +FCCB;Lo;AL; +FCCC;Lo;AL; +FCCD;Lo;AL; +FCCE;Lo;AL; +FCCF;Lo;AL; +FCD0;Lo;AL; +FCD1;Lo;AL; +FCD2;Lo;AL; +FCD3;Lo;AL; +FCD4;Lo;AL; +FCD5;Lo;AL; +FCD6;Lo;AL; +FCD7;Lo;AL; +FCD8;Lo;AL; +FCD9;Lo;AL; +FCDA;Lo;AL; +FCDB;Lo;AL; +FCDC;Lo;AL; +FCDD;Lo;AL; +FCDE;Lo;AL; +FCDF;Lo;AL; +FCE0;Lo;AL; +FCE1;Lo;AL; +FCE2;Lo;AL; +FCE3;Lo;AL; +FCE4;Lo;AL; +FCE5;Lo;AL; +FCE6;Lo;AL; +FCE7;Lo;AL; +FCE8;Lo;AL; +FCE9;Lo;AL; +FCEA;Lo;AL; +FCEB;Lo;AL; +FCEC;Lo;AL; +FCED;Lo;AL; +FCEE;Lo;AL; +FCEF;Lo;AL; +FCF0;Lo;AL; +FCF1;Lo;AL; +FCF2;Lo;AL; +FCF3;Lo;AL; +FCF4;Lo;AL; +FCF5;Lo;AL; +FCF6;Lo;AL; +FCF7;Lo;AL; +FCF8;Lo;AL; +FCF9;Lo;AL; +FCFA;Lo;AL; +FCFB;Lo;AL; +FCFC;Lo;AL; +FCFD;Lo;AL; +FCFE;Lo;AL; +FCFF;Lo;AL; +FD00;Lo;AL; +FD01;Lo;AL; +FD02;Lo;AL; +FD03;Lo;AL; +FD04;Lo;AL; +FD05;Lo;AL; +FD06;Lo;AL; +FD07;Lo;AL; +FD08;Lo;AL; +FD09;Lo;AL; +FD0A;Lo;AL; +FD0B;Lo;AL; +FD0C;Lo;AL; +FD0D;Lo;AL; +FD0E;Lo;AL; +FD0F;Lo;AL; +FD10;Lo;AL; +FD11;Lo;AL; +FD12;Lo;AL; +FD13;Lo;AL; +FD14;Lo;AL; +FD15;Lo;AL; +FD16;Lo;AL; +FD17;Lo;AL; +FD18;Lo;AL; +FD19;Lo;AL; +FD1A;Lo;AL; +FD1B;Lo;AL; +FD1C;Lo;AL; +FD1D;Lo;AL; +FD1E;Lo;AL; +FD1F;Lo;AL; +FD20;Lo;AL; +FD21;Lo;AL; +FD22;Lo;AL; +FD23;Lo;AL; +FD24;Lo;AL; +FD25;Lo;AL; +FD26;Lo;AL; +FD27;Lo;AL; +FD28;Lo;AL; +FD29;Lo;AL; +FD2A;Lo;AL; +FD2B;Lo;AL; +FD2C;Lo;AL; +FD2D;Lo;AL; +FD2E;Lo;AL; +FD2F;Lo;AL; +FD30;Lo;AL; +FD31;Lo;AL; +FD32;Lo;AL; +FD33;Lo;AL; +FD34;Lo;AL; +FD35;Lo;AL; +FD36;Lo;AL; +FD37;Lo;AL; +FD38;Lo;AL; +FD39;Lo;AL; +FD3A;Lo;AL; +FD3B;Lo;AL; +FD3C;Lo;AL; +FD3D;Lo;AL; +FD3E;Ps;ON; +FD3F;Pe;ON; +FD50;Lo;AL; +FD51;Lo;AL; +FD52;Lo;AL; +FD53;Lo;AL; +FD54;Lo;AL; +FD55;Lo;AL; +FD56;Lo;AL; +FD57;Lo;AL; +FD58;Lo;AL; +FD59;Lo;AL; +FD5A;Lo;AL; +FD5B;Lo;AL; +FD5C;Lo;AL; +FD5D;Lo;AL; +FD5E;Lo;AL; +FD5F;Lo;AL; +FD60;Lo;AL; +FD61;Lo;AL; +FD62;Lo;AL; +FD63;Lo;AL; +FD64;Lo;AL; +FD65;Lo;AL; +FD66;Lo;AL; +FD67;Lo;AL; +FD68;Lo;AL; +FD69;Lo;AL; +FD6A;Lo;AL; +FD6B;Lo;AL; +FD6C;Lo;AL; +FD6D;Lo;AL; +FD6E;Lo;AL; +FD6F;Lo;AL; +FD70;Lo;AL; +FD71;Lo;AL; +FD72;Lo;AL; +FD73;Lo;AL; +FD74;Lo;AL; +FD75;Lo;AL; +FD76;Lo;AL; +FD77;Lo;AL; +FD78;Lo;AL; +FD79;Lo;AL; +FD7A;Lo;AL; +FD7B;Lo;AL; +FD7C;Lo;AL; +FD7D;Lo;AL; +FD7E;Lo;AL; +FD7F;Lo;AL; +FD80;Lo;AL; +FD81;Lo;AL; +FD82;Lo;AL; +FD83;Lo;AL; +FD84;Lo;AL; +FD85;Lo;AL; +FD86;Lo;AL; +FD87;Lo;AL; +FD88;Lo;AL; +FD89;Lo;AL; +FD8A;Lo;AL; +FD8B;Lo;AL; +FD8C;Lo;AL; +FD8D;Lo;AL; +FD8E;Lo;AL; +FD8F;Lo;AL; +FD92;Lo;AL; +FD93;Lo;AL; +FD94;Lo;AL; +FD95;Lo;AL; +FD96;Lo;AL; +FD97;Lo;AL; +FD98;Lo;AL; +FD99;Lo;AL; +FD9A;Lo;AL; +FD9B;Lo;AL; +FD9C;Lo;AL; +FD9D;Lo;AL; +FD9E;Lo;AL; +FD9F;Lo;AL; +FDA0;Lo;AL; +FDA1;Lo;AL; +FDA2;Lo;AL; +FDA3;Lo;AL; +FDA4;Lo;AL; +FDA5;Lo;AL; +FDA6;Lo;AL; +FDA7;Lo;AL; +FDA8;Lo;AL; +FDA9;Lo;AL; +FDAA;Lo;AL; +FDAB;Lo;AL; +FDAC;Lo;AL; +FDAD;Lo;AL; +FDAE;Lo;AL; +FDAF;Lo;AL; +FDB0;Lo;AL; +FDB1;Lo;AL; +FDB2;Lo;AL; +FDB3;Lo;AL; +FDB4;Lo;AL; +FDB5;Lo;AL; +FDB6;Lo;AL; +FDB7;Lo;AL; +FDB8;Lo;AL; +FDB9;Lo;AL; +FDBA;Lo;AL; +FDBB;Lo;AL; +FDBC;Lo;AL; +FDBD;Lo;AL; +FDBE;Lo;AL; +FDBF;Lo;AL; +FDC0;Lo;AL; +FDC1;Lo;AL; +FDC2;Lo;AL; +FDC3;Lo;AL; +FDC4;Lo;AL; +FDC5;Lo;AL; +FDC6;Lo;AL; +FDC7;Lo;AL; +FDF0;Lo;AL; +FDF1;Lo;AL; +FDF2;Lo;AL; +FDF3;Lo;AL; +FDF4;Lo;AL; +FDF5;Lo;AL; +FDF6;Lo;AL; +FDF7;Lo;AL; +FDF8;Lo;AL; +FDF9;Lo;AL; +FDFA;Lo;AL; +FDFB;Lo;AL; +FE20;Mn;NSM; +FE21;Mn;NSM; +FE22;Mn;NSM; +FE23;Mn;NSM; +FE30;Po;ON; +FE31;Pd;ON; +FE32;Pd;ON; +FE33;Pc;ON; +FE34;Pc;ON; +FE35;Ps;ON; +FE36;Pe;ON; +FE37;Ps;ON; +FE38;Pe;ON; +FE39;Ps;ON; +FE3A;Pe;ON; +FE3B;Ps;ON; +FE3C;Pe;ON; +FE3D;Ps;ON; +FE3E;Pe;ON; +FE3F;Ps;ON; +FE40;Pe;ON; +FE41;Ps;ON; +FE42;Pe;ON; +FE43;Ps;ON; +FE44;Pe;ON; +FE49;Po;ON; +FE4A;Po;ON; +FE4B;Po;ON; +FE4C;Po;ON; +FE4D;Pc;ON; +FE4E;Pc;ON; +FE4F;Pc;ON; +FE50;Po;CS; +FE51;Po;ON; +FE52;Po;CS; +FE54;Po;ON; +FE55;Po;CS; +FE56;Po;ON; +FE57;Po;ON; +FE58;Pd;ON; +FE59;Ps;ON; +FE5A;Pe;ON; +FE5B;Ps;ON; +FE5C;Pe;ON; +FE5D;Ps;ON; +FE5E;Pe;ON; +FE5F;Po;ET; +FE60;Po;ON; +FE61;Po;ON; +FE62;Sm;ET; +FE63;Pd;ET; +FE64;Sm;ON; +FE65;Sm;ON; +FE66;Sm;ON; +FE68;Po;ON; +FE69;Sc;ET; +FE6A;Po;ET; +FE6B;Po;ON; +FE70;Lo;AL; +FE71;Lo;AL; +FE72;Lo;AL; +FE74;Lo;AL; +FE76;Lo;AL; +FE77;Lo;AL; +FE78;Lo;AL; +FE79;Lo;AL; +FE7A;Lo;AL; +FE7B;Lo;AL; +FE7C;Lo;AL; +FE7D;Lo;AL; +FE7E;Lo;AL; +FE7F;Lo;AL; +FE80;Lo;AL; +FE81;Lo;AL; +FE82;Lo;AL; +FE83;Lo;AL; +FE84;Lo;AL; +FE85;Lo;AL; +FE86;Lo;AL; +FE87;Lo;AL; +FE88;Lo;AL; +FE89;Lo;AL; +FE8A;Lo;AL; +FE8B;Lo;AL; +FE8C;Lo;AL; +FE8D;Lo;AL; +FE8E;Lo;AL; +FE8F;Lo;AL; +FE90;Lo;AL; +FE91;Lo;AL; +FE92;Lo;AL; +FE93;Lo;AL; +FE94;Lo;AL; +FE95;Lo;AL; +FE96;Lo;AL; +FE97;Lo;AL; +FE98;Lo;AL; +FE99;Lo;AL; +FE9A;Lo;AL; +FE9B;Lo;AL; +FE9C;Lo;AL; +FE9D;Lo;AL; +FE9E;Lo;AL; +FE9F;Lo;AL; +FEA0;Lo;AL; +FEA1;Lo;AL; +FEA2;Lo;AL; +FEA3;Lo;AL; +FEA4;Lo;AL; +FEA5;Lo;AL; +FEA6;Lo;AL; +FEA7;Lo;AL; +FEA8;Lo;AL; +FEA9;Lo;AL; +FEAA;Lo;AL; +FEAB;Lo;AL; +FEAC;Lo;AL; +FEAD;Lo;AL; +FEAE;Lo;AL; +FEAF;Lo;AL; +FEB0;Lo;AL; +FEB1;Lo;AL; +FEB2;Lo;AL; +FEB3;Lo;AL; +FEB4;Lo;AL; +FEB5;Lo;AL; +FEB6;Lo;AL; +FEB7;Lo;AL; +FEB8;Lo;AL; +FEB9;Lo;AL; +FEBA;Lo;AL; +FEBB;Lo;AL; +FEBC;Lo;AL; +FEBD;Lo;AL; +FEBE;Lo;AL; +FEBF;Lo;AL; +FEC0;Lo;AL; +FEC1;Lo;AL; +FEC2;Lo;AL; +FEC3;Lo;AL; +FEC4;Lo;AL; +FEC5;Lo;AL; +FEC6;Lo;AL; +FEC7;Lo;AL; +FEC8;Lo;AL; +FEC9;Lo;AL; +FECA;Lo;AL; +FECB;Lo;AL; +FECC;Lo;AL; +FECD;Lo;AL; +FECE;Lo;AL; +FECF;Lo;AL; +FED0;Lo;AL; +FED1;Lo;AL; +FED2;Lo;AL; +FED3;Lo;AL; +FED4;Lo;AL; +FED5;Lo;AL; +FED6;Lo;AL; +FED7;Lo;AL; +FED8;Lo;AL; +FED9;Lo;AL; +FEDA;Lo;AL; +FEDB;Lo;AL; +FEDC;Lo;AL; +FEDD;Lo;AL; +FEDE;Lo;AL; +FEDF;Lo;AL; +FEE0;Lo;AL; +FEE1;Lo;AL; +FEE2;Lo;AL; +FEE3;Lo;AL; +FEE4;Lo;AL; +FEE5;Lo;AL; +FEE6;Lo;AL; +FEE7;Lo;AL; +FEE8;Lo;AL; +FEE9;Lo;AL; +FEEA;Lo;AL; +FEEB;Lo;AL; +FEEC;Lo;AL; +FEED;Lo;AL; +FEEE;Lo;AL; +FEEF;Lo;AL; +FEF0;Lo;AL; +FEF1;Lo;AL; +FEF2;Lo;AL; +FEF3;Lo;AL; +FEF4;Lo;AL; +FEF5;Lo;AL; +FEF6;Lo;AL; +FEF7;Lo;AL; +FEF8;Lo;AL; +FEF9;Lo;AL; +FEFA;Lo;AL; +FEFB;Lo;AL; +FEFC;Lo;AL; +FEFF;Cf;BN; +FF01;Po;ON; +FF02;Po;ON; +FF03;Po;ET; +FF04;Sc;ET; +FF05;Po;ET; +FF06;Po;ON; +FF07;Po;ON; +FF08;Ps;ON; +FF09;Pe;ON; +FF0A;Po;ON; +FF0B;Sm;ET; +FF0C;Po;CS; +FF0D;Pd;ET; +FF0E;Po;CS; +FF0F;Po;ES; +FF10;Nd;EN; +FF11;Nd;EN; +FF12;Nd;EN; +FF13;Nd;EN; +FF14;Nd;EN; +FF15;Nd;EN; +FF16;Nd;EN; +FF17;Nd;EN; +FF18;Nd;EN; +FF19;Nd;EN; +FF1A;Po;CS; +FF1B;Po;ON; +FF1C;Sm;ON; +FF1D;Sm;ON; +FF1E;Sm;ON; +FF1F;Po;ON; +FF20;Po;ON; +FF21;Lu;L; +FF22;Lu;L; +FF23;Lu;L; +FF24;Lu;L; +FF25;Lu;L; +FF26;Lu;L; +FF27;Lu;L; +FF28;Lu;L; +FF29;Lu;L; +FF2A;Lu;L; +FF2B;Lu;L; +FF2C;Lu;L; +FF2D;Lu;L; +FF2E;Lu;L; +FF2F;Lu;L; +FF30;Lu;L; +FF31;Lu;L; +FF32;Lu;L; +FF33;Lu;L; +FF34;Lu;L; +FF35;Lu;L; +FF36;Lu;L; +FF37;Lu;L; +FF38;Lu;L; +FF39;Lu;L; +FF3A;Lu;L; +FF3B;Ps;ON; +FF3C;Po;ON; +FF3D;Pe;ON; +FF3E;Sk;ON; +FF3F;Pc;ON; +FF40;Sk;ON; +FF41;Ll;L; +FF42;Ll;L; +FF43;Ll;L; +FF44;Ll;L; +FF45;Ll;L; +FF46;Ll;L; +FF47;Ll;L; +FF48;Ll;L; +FF49;Ll;L; +FF4A;Ll;L; +FF4B;Ll;L; +FF4C;Ll;L; +FF4D;Ll;L; +FF4E;Ll;L; +FF4F;Ll;L; +FF50;Ll;L; +FF51;Ll;L; +FF52;Ll;L; +FF53;Ll;L; +FF54;Ll;L; +FF55;Ll;L; +FF56;Ll;L; +FF57;Ll;L; +FF58;Ll;L; +FF59;Ll;L; +FF5A;Ll;L; +FF5B;Ps;ON; +FF5C;Sm;ON; +FF5D;Pe;ON; +FF5E;Sm;ON; +FF61;Po;ON; +FF62;Ps;ON; +FF63;Pe;ON; +FF64;Po;ON; +FF65;Pc;ON; +FF66;Lo;L; +FF67;Lo;L; +FF68;Lo;L; +FF69;Lo;L; +FF6A;Lo;L; +FF6B;Lo;L; +FF6C;Lo;L; +FF6D;Lo;L; +FF6E;Lo;L; +FF6F;Lo;L; +FF70;Lm;L; +FF71;Lo;L; +FF72;Lo;L; +FF73;Lo;L; +FF74;Lo;L; +FF75;Lo;L; +FF76;Lo;L; +FF77;Lo;L; +FF78;Lo;L; +FF79;Lo;L; +FF7A;Lo;L; +FF7B;Lo;L; +FF7C;Lo;L; +FF7D;Lo;L; +FF7E;Lo;L; +FF7F;Lo;L; +FF80;Lo;L; +FF81;Lo;L; +FF82;Lo;L; +FF83;Lo;L; +FF84;Lo;L; +FF85;Lo;L; +FF86;Lo;L; +FF87;Lo;L; +FF88;Lo;L; +FF89;Lo;L; +FF8A;Lo;L; +FF8B;Lo;L; +FF8C;Lo;L; +FF8D;Lo;L; +FF8E;Lo;L; +FF8F;Lo;L; +FF90;Lo;L; +FF91;Lo;L; +FF92;Lo;L; +FF93;Lo;L; +FF94;Lo;L; +FF95;Lo;L; +FF96;Lo;L; +FF97;Lo;L; +FF98;Lo;L; +FF99;Lo;L; +FF9A;Lo;L; +FF9B;Lo;L; +FF9C;Lo;L; +FF9D;Lo;L; +FF9E;Lm;L; +FF9F;Lm;L; +FFA0;Lo;L; +FFA1;Lo;L; +FFA2;Lo;L; +FFA3;Lo;L; +FFA4;Lo;L; +FFA5;Lo;L; +FFA6;Lo;L; +FFA7;Lo;L; +FFA8;Lo;L; +FFA9;Lo;L; +FFAA;Lo;L; +FFAB;Lo;L; +FFAC;Lo;L; +FFAD;Lo;L; +FFAE;Lo;L; +FFAF;Lo;L; +FFB0;Lo;L; +FFB1;Lo;L; +FFB2;Lo;L; +FFB3;Lo;L; +FFB4;Lo;L; +FFB5;Lo;L; +FFB6;Lo;L; +FFB7;Lo;L; +FFB8;Lo;L; +FFB9;Lo;L; +FFBA;Lo;L; +FFBB;Lo;L; +FFBC;Lo;L; +FFBD;Lo;L; +FFBE;Lo;L; +FFC2;Lo;L; +FFC3;Lo;L; +FFC4;Lo;L; +FFC5;Lo;L; +FFC6;Lo;L; +FFC7;Lo;L; +FFCA;Lo;L; +FFCB;Lo;L; +FFCC;Lo;L; +FFCD;Lo;L; +FFCE;Lo;L; +FFCF;Lo;L; +FFD2;Lo;L; +FFD3;Lo;L; +FFD4;Lo;L; +FFD5;Lo;L; +FFD6;Lo;L; +FFD7;Lo;L; +FFDA;Lo;L; +FFDB;Lo;L; +FFDC;Lo;L; +FFE0;Sc;ET; +FFE1;Sc;ET; +FFE2;Sm;ON; +FFE3;Sk;ON; +FFE4;So;ON; +FFE5;Sc;ET; +FFE6;Sc;ET; +FFE8;So;ON; +FFE9;Sm;ON; +FFEA;Sm;ON; +FFEB;Sm;ON; +FFEC;Sm;ON; +FFED;So;ON; +FFEE;So;ON; +FFF9;Cf;BN; +FFFA;Cf;BN; +FFFB;Cf;BN; +FFFC;So;ON; +FFFD;So;ON; diff --git a/data/unibreak.txt b/data/unibreak.txt new file mode 100644 index 000000000..512dad63b --- /dev/null +++ b/data/unibreak.txt @@ -0,0 +1,1354 @@ +# DerivedLineBreak-3.1.0.txt +# +# Unicode Character Database: Derived Property Data +# Generated algorithmically from the Unicode Character Database +# For documentation, see DerivedProperties.html +# Date: 2001-03-02 00:05:44.2 GMT [MD] +# Note: Unassigned and Noncharacter codepoints are omitted, +# except when listing Noncharacter or Cn. +# ================================================ + + +# ================================================ +# Line Break (listing LineBreak.txt, field 1) +# ================================================ + +E000..F8FF ; XX # Co [6400] +F0000..FFFFD ; XX # Co [65534] +100000..10FFFD; XX # Co [65534] + +# Total code points: 137468 + +# ================================================ + +0028 ; OP # Ps LEFT PARENTHESIS +005B ; OP # Ps LEFT SQUARE BRACKET +007B ; OP # Ps LEFT CURLY BRACKET +0F3A ; OP # Ps TIBETAN MARK GUG RTAGS GYON +0F3C ; OP # Ps TIBETAN MARK ANG KHANG GYON +169B ; OP # Ps OGHAM FEATHER MARK +201A ; OP # Ps SINGLE LOW-9 QUOTATION MARK +201E ; OP # Ps DOUBLE LOW-9 QUOTATION MARK +2045 ; OP # Ps LEFT SQUARE BRACKET WITH QUILL +207D ; OP # Ps SUPERSCRIPT LEFT PARENTHESIS +208D ; OP # Ps SUBSCRIPT LEFT PARENTHESIS +2329 ; OP # Ps LEFT-POINTING ANGLE BRACKET +3008 ; OP # Ps LEFT ANGLE BRACKET +300A ; OP # Ps LEFT DOUBLE ANGLE BRACKET +300C ; OP # Ps LEFT CORNER BRACKET +300E ; OP # Ps LEFT WHITE CORNER BRACKET +3010 ; OP # Ps LEFT BLACK LENTICULAR BRACKET +3014 ; OP # Ps LEFT TORTOISE SHELL BRACKET +3016 ; OP # Ps LEFT WHITE LENTICULAR BRACKET +3018 ; OP # Ps LEFT WHITE TORTOISE SHELL BRACKET +301A ; OP # Ps LEFT WHITE SQUARE BRACKET +301D ; OP # Ps REVERSED DOUBLE PRIME QUOTATION MARK +FD3E ; OP # Ps ORNATE LEFT PARENTHESIS +FE35 ; OP # Ps PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS +FE37 ; OP # Ps PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET +FE39 ; OP # Ps PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET +FE3B ; OP # Ps PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET +FE3D ; OP # Ps PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET +FE3F ; OP # Ps PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET +FE41 ; OP # Ps PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET +FE43 ; OP # Ps PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET +FE59 ; OP # Ps SMALL LEFT PARENTHESIS +FE5B ; OP # Ps SMALL LEFT CURLY BRACKET +FE5D ; OP # Ps SMALL LEFT TORTOISE SHELL BRACKET +FF08 ; OP # Ps FULLWIDTH LEFT PARENTHESIS +FF3B ; OP # Ps FULLWIDTH LEFT SQUARE BRACKET +FF5B ; OP # Ps FULLWIDTH LEFT CURLY BRACKET +FF62 ; OP # Ps HALFWIDTH LEFT CORNER BRACKET + +# Total code points: 38 + +# ================================================ + +0029 ; CL # Pe RIGHT PARENTHESIS +005D ; CL # Pe RIGHT SQUARE BRACKET +007D ; CL # Pe RIGHT CURLY BRACKET +0F3B ; CL # Pe TIBETAN MARK GUG RTAGS GYAS +0F3D ; CL # Pe TIBETAN MARK ANG KHANG GYAS +169C ; CL # Pe OGHAM REVERSED FEATHER MARK +2046 ; CL # Pe RIGHT SQUARE BRACKET WITH QUILL +207E ; CL # Pe SUPERSCRIPT RIGHT PARENTHESIS +208E ; CL # Pe SUBSCRIPT RIGHT PARENTHESIS +232A ; CL # Pe RIGHT-POINTING ANGLE BRACKET +3001..3002 ; CL # Po [2] IDEOGRAPHIC COMMA..IDEOGRAPHIC FULL STOP +3009 ; CL # Pe RIGHT ANGLE BRACKET +300B ; CL # Pe RIGHT DOUBLE ANGLE BRACKET +300D ; CL # Pe RIGHT CORNER BRACKET +300F ; CL # Pe RIGHT WHITE CORNER BRACKET +3011 ; CL # Pe RIGHT BLACK LENTICULAR BRACKET +3015 ; CL # Pe RIGHT TORTOISE SHELL BRACKET +3017 ; CL # Pe RIGHT WHITE LENTICULAR BRACKET +3019 ; CL # Pe RIGHT WHITE TORTOISE SHELL BRACKET +301B ; CL # Pe RIGHT WHITE SQUARE BRACKET +301E..301F ; CL # Pe [2] DOUBLE PRIME QUOTATION MARK..LOW DOUBLE PRIME QUOTATION MARK +FD3F ; CL # Pe ORNATE RIGHT PARENTHESIS +FE36 ; CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS +FE38 ; CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET +FE3A ; CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET +FE3C ; CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET +FE3E ; CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET +FE40 ; CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET +FE42 ; CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET +FE44 ; CL # Pe PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET +FE50 ; CL # Po SMALL COMMA +FE52 ; CL # Po SMALL FULL STOP +FE5A ; CL # Pe SMALL RIGHT PARENTHESIS +FE5C ; CL # Pe SMALL RIGHT CURLY BRACKET +FE5E ; CL # Pe SMALL RIGHT TORTOISE SHELL BRACKET +FF09 ; CL # Pe FULLWIDTH RIGHT PARENTHESIS +FF0C ; CL # Po FULLWIDTH COMMA +FF0E ; CL # Po FULLWIDTH FULL STOP +FF3D ; CL # Pe FULLWIDTH RIGHT SQUARE BRACKET +FF5D ; CL # Pe FULLWIDTH RIGHT CURLY BRACKET +FF61 ; CL # Po HALFWIDTH IDEOGRAPHIC FULL STOP +FF63 ; CL # Pe HALFWIDTH RIGHT CORNER BRACKET +FF64 ; CL # Po HALFWIDTH IDEOGRAPHIC COMMA + +# Total code points: 45 + +# ================================================ + +0022 ; QU # Po QUOTATION MARK +0027 ; QU # Po APOSTROPHE +00AB ; QU # Pi LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +00BB ; QU # Pf RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +2018 ; QU # Pi LEFT SINGLE QUOTATION MARK +2019 ; QU # Pf RIGHT SINGLE QUOTATION MARK +201B..201C ; QU # Pi [2] SINGLE HIGH-REVERSED-9 QUOTATION MARK..LEFT DOUBLE QUOTATION MARK +201D ; QU # Pf RIGHT DOUBLE QUOTATION MARK +201F ; QU # Pi DOUBLE HIGH-REVERSED-9 QUOTATION MARK +2039 ; QU # Pi SINGLE LEFT-POINTING ANGLE QUOTATION MARK +203A ; QU # Pf SINGLE RIGHT-POINTING ANGLE QUOTATION MARK + +# Total code points: 12 + +# ================================================ + +00A0 ; GL # Zs NO-BREAK SPACE +0F0C ; GL # Po TIBETAN MARK DELIMITER TSHEG BSTAR +2007 ; GL # Zs FIGURE SPACE +2011 ; GL # Pd NON-BREAKING HYPHEN +202F ; GL # Zs NARROW NO-BREAK SPACE +FEFF ; GL # Cf ZERO WIDTH NO-BREAK SPACE + +# Total code points: 6 + +# ================================================ + +0E5A..0E5B ; NS # Po [2] THAI CHARACTER ANGKHANKHU..THAI CHARACTER KHOMUT +17D4 ; NS # Po KHMER SIGN KHAN +17D6..17DA ; NS # Po [5] KHMER SIGN CAMNUC PII KUUH..KHMER SIGN KOOMUUT +203C ; NS # Po DOUBLE EXCLAMATION MARK +2044 ; NS # Sm FRACTION SLASH +3005 ; NS # Lm IDEOGRAPHIC ITERATION MARK +301C ; NS # Pd WAVE DASH +3041 ; NS # Lo HIRAGANA LETTER SMALL A +3043 ; NS # Lo HIRAGANA LETTER SMALL I +3045 ; NS # Lo HIRAGANA LETTER SMALL U +3047 ; NS # Lo HIRAGANA LETTER SMALL E +3049 ; NS # Lo HIRAGANA LETTER SMALL O +3063 ; NS # Lo HIRAGANA LETTER SMALL TU +3083 ; NS # Lo HIRAGANA LETTER SMALL YA +3085 ; NS # Lo HIRAGANA LETTER SMALL YU +3087 ; NS # Lo HIRAGANA LETTER SMALL YO +308E ; NS # Lo HIRAGANA LETTER SMALL WA +309B..309C ; NS # Sk [2] KATAKANA-HIRAGANA VOICED SOUND MARK..KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +309D..309E ; NS # Lm [2] HIRAGANA ITERATION MARK..HIRAGANA VOICED ITERATION MARK +30A1 ; NS # Lo KATAKANA LETTER SMALL A +30A3 ; NS # Lo KATAKANA LETTER SMALL I +30A5 ; NS # Lo KATAKANA LETTER SMALL U +30A7 ; NS # Lo KATAKANA LETTER SMALL E +30A9 ; NS # Lo KATAKANA LETTER SMALL O +30C3 ; NS # Lo KATAKANA LETTER SMALL TU +30E3 ; NS # Lo KATAKANA LETTER SMALL YA +30E5 ; NS # Lo KATAKANA LETTER SMALL YU +30E7 ; NS # Lo KATAKANA LETTER SMALL YO +30EE ; NS # Lo KATAKANA LETTER SMALL WA +30F5..30F6 ; NS # Lo [2] KATAKANA LETTER SMALL KA..KATAKANA LETTER SMALL KE +30FB ; NS # Pc KATAKANA MIDDLE DOT +30FD ; NS # Lm KATAKANA ITERATION MARK +FE54..FE55 ; NS # Po [2] SMALL SEMICOLON..SMALL COLON +FF1A..FF1B ; NS # Po [2] FULLWIDTH COLON..FULLWIDTH SEMICOLON +FF65 ; NS # Pc HALFWIDTH KATAKANA MIDDLE DOT +FF67..FF6F ; NS # Lo [9] HALFWIDTH KATAKANA LETTER SMALL A..HALFWIDTH KATAKANA LETTER SMALL TU +FF70 ; NS # Lm HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK +FF9E..FF9F ; NS # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK + +# Total code points: 57 + +# ================================================ + +0021 ; EX # Po EXCLAMATION MARK +003F ; EX # Po QUESTION MARK +FE56..FE57 ; EX # Po [2] SMALL QUESTION MARK..SMALL EXCLAMATION MARK +FF01 ; EX # Po FULLWIDTH EXCLAMATION MARK +FF1F ; EX # Po FULLWIDTH QUESTION MARK + +# Total code points: 6 + +# ================================================ + +002F ; SY # Po SOLIDUS + +# Total code points: 1 + +# ================================================ + +002C ; IS # Po COMMA +002E ; IS # Po FULL STOP +003A..003B ; IS # Po [2] COLON..SEMICOLON +0589 ; IS # Po ARMENIAN FULL STOP + +# Total code points: 5 + +# ================================================ + +0024 ; PR # Sc DOLLAR SIGN +002B ; PR # Sm PLUS SIGN +005C ; PR # Po REVERSE SOLIDUS +00A3..00A5 ; PR # Sc [3] POUND SIGN..YEN SIGN +00B1 ; PR # Sm PLUS-MINUS SIGN +09F2..09F3 ; PR # Sc [2] BENGALI RUPEE MARK..BENGALI RUPEE SIGN +0E3F ; PR # Sc THAI CURRENCY SYMBOL BAHT +17DB ; PR # Sc KHMER CURRENCY SYMBOL RIEL +20A0..20A6 ; PR # Sc [7] EURO-CURRENCY SIGN..NAIRA SIGN +20A8..20AF ; PR # Sc [8] RUPEE SIGN..DRACHMA SIGN +2116 ; PR # So NUMERO SIGN +2212..2213 ; PR # Sm [2] MINUS SIGN..MINUS-OR-PLUS SIGN +FE69 ; PR # Sc SMALL DOLLAR SIGN +FF04 ; PR # Sc FULLWIDTH DOLLAR SIGN +FFE1 ; PR # Sc FULLWIDTH POUND SIGN +FFE5..FFE6 ; PR # Sc [2] FULLWIDTH YEN SIGN..FULLWIDTH WON SIGN + +# Total code points: 34 + +# ================================================ + +0025 ; PO # Po PERCENT SIGN +00A2 ; PO # Sc CENT SIGN +00B0 ; PO # So DEGREE SIGN +2030..2037 ; PO # Po [8] PER MILLE SIGN..REVERSED TRIPLE PRIME +20A7 ; PO # Sc PESETA SIGN +2103 ; PO # So DEGREE CELSIUS +2109 ; PO # So DEGREE FAHRENHEIT +2126 ; PO # L& OHM SIGN +FE6A ; PO # Po SMALL PERCENT SIGN +FF05 ; PO # Po FULLWIDTH PERCENT SIGN +FFE0 ; PO # Sc FULLWIDTH CENT SIGN + +# Total code points: 18 + +# ================================================ + +0030..0039 ; NU # Nd [10] DIGIT ZERO..DIGIT NINE +0660..0669 ; NU # Nd [10] ARABIC-INDIC DIGIT ZERO..ARABIC-INDIC DIGIT NINE +06F0..06F9 ; NU # Nd [10] EXTENDED ARABIC-INDIC DIGIT ZERO..EXTENDED ARABIC-INDIC DIGIT NINE +0966..096F ; NU # Nd [10] DEVANAGARI DIGIT ZERO..DEVANAGARI DIGIT NINE +09E6..09EF ; NU # Nd [10] BENGALI DIGIT ZERO..BENGALI DIGIT NINE +0A66..0A6F ; NU # Nd [10] GURMUKHI DIGIT ZERO..GURMUKHI DIGIT NINE +0AE6..0AEF ; NU # Nd [10] GUJARATI DIGIT ZERO..GUJARATI DIGIT NINE +0B66..0B6F ; NU # Nd [10] ORIYA DIGIT ZERO..ORIYA DIGIT NINE +0BE7..0BEF ; NU # Nd [9] TAMIL DIGIT ONE..TAMIL DIGIT NINE +0C66..0C6F ; NU # Nd [10] TELUGU DIGIT ZERO..TELUGU DIGIT NINE +0CE6..0CEF ; NU # Nd [10] KANNADA DIGIT ZERO..KANNADA DIGIT NINE +0D66..0D6F ; NU # Nd [10] MALAYALAM DIGIT ZERO..MALAYALAM DIGIT NINE +0E50..0E59 ; NU # Nd [10] THAI DIGIT ZERO..THAI DIGIT NINE +0ED0..0ED9 ; NU # Nd [10] LAO DIGIT ZERO..LAO DIGIT NINE +0F20..0F29 ; NU # Nd [10] TIBETAN DIGIT ZERO..TIBETAN DIGIT NINE +1040..1049 ; NU # Nd [10] MYANMAR DIGIT ZERO..MYANMAR DIGIT NINE +1369..1371 ; NU # Nd [9] ETHIOPIC DIGIT ONE..ETHIOPIC DIGIT NINE +17E0..17E9 ; NU # Nd [10] KHMER DIGIT ZERO..KHMER DIGIT NINE +1810..1819 ; NU # Nd [10] MONGOLIAN DIGIT ZERO..MONGOLIAN DIGIT NINE +1D7CE..1D7FF ; NU # Nd [50] MATHEMATICAL BOLD DIGIT ZERO..MATHEMATICAL MONOSPACE DIGIT NINE + +# Total code points: 238 + +# ================================================ + +0023 ; AL # Po NUMBER SIGN +0026 ; AL # Po AMPERSAND +002A ; AL # Po ASTERISK +003C..003E ; AL # Sm [3] LESS-THAN SIGN..GREATER-THAN SIGN +0040 ; AL # Po COMMERCIAL AT +0041..005A ; AL # L& [26] LATIN CAPITAL LETTER A..LATIN CAPITAL LETTER Z +005E ; AL # Sk CIRCUMFLEX ACCENT +005F ; AL # Pc LOW LINE +0060 ; AL # Sk GRAVE ACCENT +0061..007A ; AL # L& [26] LATIN SMALL LETTER A..LATIN SMALL LETTER Z +007E ; AL # Sm TILDE +00A6 ; AL # So BROKEN BAR +00A9 ; AL # So COPYRIGHT SIGN +00AC ; AL # Sm NOT SIGN +00AE ; AL # So REGISTERED SIGN +00AF ; AL # Sk MACRON +00B5 ; AL # L& MICRO SIGN +00C0..00C5 ; AL # L& [6] LATIN CAPITAL LETTER A WITH GRAVE..LATIN CAPITAL LETTER A WITH RING ABOVE +00C7..00CF ; AL # L& [9] LATIN CAPITAL LETTER C WITH CEDILLA..LATIN CAPITAL LETTER I WITH DIAERESIS +00D1..00D6 ; AL # L& [6] LATIN CAPITAL LETTER N WITH TILDE..LATIN CAPITAL LETTER O WITH DIAERESIS +00D9..00DD ; AL # L& [5] LATIN CAPITAL LETTER U WITH GRAVE..LATIN CAPITAL LETTER Y WITH ACUTE +00E2..00E5 ; AL # L& [4] LATIN SMALL LETTER A WITH CIRCUMFLEX..LATIN SMALL LETTER A WITH RING ABOVE +00E7 ; AL # L& LATIN SMALL LETTER C WITH CEDILLA +00EB ; AL # L& LATIN SMALL LETTER E WITH DIAERESIS +00EE..00EF ; AL # L& [2] LATIN SMALL LETTER I WITH CIRCUMFLEX..LATIN SMALL LETTER I WITH DIAERESIS +00F1 ; AL # L& LATIN SMALL LETTER N WITH TILDE +00F4..00F6 ; AL # L& [3] LATIN SMALL LETTER O WITH CIRCUMFLEX..LATIN SMALL LETTER O WITH DIAERESIS +00FB ; AL # L& LATIN SMALL LETTER U WITH CIRCUMFLEX +00FD ; AL # L& LATIN SMALL LETTER Y WITH ACUTE +00FF..0100 ; AL # L& [2] LATIN SMALL LETTER Y WITH DIAERESIS..LATIN CAPITAL LETTER A WITH MACRON +0102..0110 ; AL # L& [15] LATIN CAPITAL LETTER A WITH BREVE..LATIN CAPITAL LETTER D WITH STROKE +0112 ; AL # L& LATIN CAPITAL LETTER E WITH MACRON +0114..011A ; AL # L& [7] LATIN CAPITAL LETTER E WITH BREVE..LATIN CAPITAL LETTER E WITH CARON +011C..0125 ; AL # L& [10] LATIN CAPITAL LETTER G WITH CIRCUMFLEX..LATIN SMALL LETTER H WITH CIRCUMFLEX +0128..012A ; AL # L& [3] LATIN CAPITAL LETTER I WITH TILDE..LATIN CAPITAL LETTER I WITH MACRON +012C..0130 ; AL # L& [5] LATIN CAPITAL LETTER I WITH BREVE..LATIN CAPITAL LETTER I WITH DOT ABOVE +0134..0137 ; AL # L& [4] LATIN CAPITAL LETTER J WITH CIRCUMFLEX..LATIN SMALL LETTER K WITH CEDILLA +0139..013E ; AL # L& [6] LATIN CAPITAL LETTER L WITH ACUTE..LATIN SMALL LETTER L WITH CARON +0143 ; AL # L& LATIN CAPITAL LETTER N WITH ACUTE +0145..0147 ; AL # L& [3] LATIN CAPITAL LETTER N WITH CEDILLA..LATIN CAPITAL LETTER N WITH CARON +014B..014C ; AL # L& [2] LATIN SMALL LETTER ENG..LATIN CAPITAL LETTER O WITH MACRON +014E..0151 ; AL # L& [4] LATIN CAPITAL LETTER O WITH BREVE..LATIN SMALL LETTER O WITH DOUBLE ACUTE +0154..0165 ; AL # L& [18] LATIN CAPITAL LETTER R WITH ACUTE..LATIN SMALL LETTER T WITH CARON +0168..016A ; AL # L& [3] LATIN CAPITAL LETTER U WITH TILDE..LATIN CAPITAL LETTER U WITH MACRON +016C..01BA ; AL # L& [79] LATIN CAPITAL LETTER U WITH BREVE..LATIN SMALL LETTER EZH WITH TAIL +01BB ; AL # Lo LATIN LETTER TWO WITH STROKE +01BC..01BF ; AL # L& [4] LATIN CAPITAL LETTER TONE FIVE..LATIN LETTER WYNN +01C0..01C3 ; AL # Lo [4] LATIN LETTER DENTAL CLICK..LATIN LETTER RETROFLEX CLICK +01C4..01CD ; AL # L& [10] LATIN CAPITAL LETTER DZ WITH CARON..LATIN CAPITAL LETTER A WITH CARON +01CF ; AL # L& LATIN CAPITAL LETTER I WITH CARON +01D1 ; AL # L& LATIN CAPITAL LETTER O WITH CARON +01D3 ; AL # L& LATIN CAPITAL LETTER U WITH CARON +01D5 ; AL # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON +01D7 ; AL # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE +01D9 ; AL # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON +01DB ; AL # L& LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE +01DD..021F ; AL # L& [67] LATIN SMALL LETTER TURNED E..LATIN SMALL LETTER H WITH CARON +0222..0233 ; AL # L& [18] LATIN CAPITAL LETTER OU..LATIN SMALL LETTER Y WITH MACRON +0250 ; AL # L& LATIN SMALL LETTER TURNED A +0252..0260 ; AL # L& [15] LATIN SMALL LETTER TURNED ALPHA..LATIN SMALL LETTER G WITH HOOK +0262..02AD ; AL # L& [76] LATIN LETTER SMALL CAPITAL G..LATIN LETTER BIDENTAL PERCUSSIVE +02B0..02B8 ; AL # Lm [9] MODIFIER LETTER SMALL H..MODIFIER LETTER SMALL Y +02B9..02BA ; AL # Sk [2] MODIFIER LETTER PRIME..MODIFIER LETTER DOUBLE PRIME +02BB..02C1 ; AL # Lm [7] MODIFIER LETTER TURNED COMMA..MODIFIER LETTER REVERSED GLOTTAL STOP +02C2..02C6 ; AL # Sk [5] MODIFIER LETTER LEFT ARROWHEAD..MODIFIER LETTER CIRCUMFLEX ACCENT +02CE..02CF ; AL # Sk [2] MODIFIER LETTER LOW GRAVE ACCENT..MODIFIER LETTER LOW ACUTE ACCENT +02D1 ; AL # Lm MODIFIER LETTER HALF TRIANGULAR COLON +02D2..02D7 ; AL # Sk [6] MODIFIER LETTER CENTRED RIGHT HALF RING..MODIFIER LETTER MINUS SIGN +02DC ; AL # Sk SMALL TILDE +02DE..02DF ; AL # Sk [2] MODIFIER LETTER RHOTIC HOOK..MODIFIER LETTER CROSS ACCENT +02E0..02E4 ; AL # Lm [5] MODIFIER LETTER SMALL GAMMA..MODIFIER LETTER SMALL REVERSED GLOTTAL STOP +02E5..02ED ; AL # Sk [9] MODIFIER LETTER EXTRA-HIGH TONE BAR..MODIFIER LETTER UNASPIRATED +02EE ; AL # Lm MODIFIER LETTER DOUBLE APOSTROPHE +0374..0375 ; AL # Sk [2] GREEK NUMERAL SIGN..GREEK LOWER NUMERAL SIGN +037A ; AL # Lm GREEK YPOGEGRAMMENI +037E ; AL # Po GREEK QUESTION MARK +0384..0385 ; AL # Sk [2] GREEK TONOS..GREEK DIALYTIKA TONOS +0386 ; AL # L& GREEK CAPITAL LETTER ALPHA WITH TONOS +0387 ; AL # Po GREEK ANO TELEIA +0388..038A ; AL # L& [3] GREEK CAPITAL LETTER EPSILON WITH TONOS..GREEK CAPITAL LETTER IOTA WITH TONOS +038C ; AL # L& GREEK CAPITAL LETTER OMICRON WITH TONOS +038E..0390 ; AL # L& [3] GREEK CAPITAL LETTER UPSILON WITH TONOS..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +03AA..03B0 ; AL # L& [7] GREEK CAPITAL LETTER IOTA WITH DIALYTIKA..GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +03C2 ; AL # L& GREEK SMALL LETTER FINAL SIGMA +03CA..03CE ; AL # L& [5] GREEK SMALL LETTER IOTA WITH DIALYTIKA..GREEK SMALL LETTER OMEGA WITH TONOS +03D0..03D7 ; AL # L& [8] GREEK BETA SYMBOL..GREEK KAI SYMBOL +03DA..03F5 ; AL # L& [28] GREEK LETTER STIGMA..GREEK LUNATE EPSILON SYMBOL +0400 ; AL # L& CYRILLIC CAPITAL LETTER IE WITH GRAVE +0402..040F ; AL # L& [14] CYRILLIC CAPITAL LETTER DJE..CYRILLIC CAPITAL LETTER DZHE +0450 ; AL # L& CYRILLIC SMALL LETTER IE WITH GRAVE +0452..0481 ; AL # L& [48] CYRILLIC SMALL LETTER DJE..CYRILLIC SMALL LETTER KOPPA +0482 ; AL # So CYRILLIC THOUSANDS SIGN +048C..04C4 ; AL # L& [57] CYRILLIC CAPITAL LETTER SEMISOFT SIGN..CYRILLIC SMALL LETTER KA WITH HOOK +04C7..04C8 ; AL # L& [2] CYRILLIC CAPITAL LETTER EN WITH HOOK..CYRILLIC SMALL LETTER EN WITH HOOK +04CB..04CC ; AL # L& [2] CYRILLIC CAPITAL LETTER KHAKASSIAN CHE..CYRILLIC SMALL LETTER KHAKASSIAN CHE +04D0..04F5 ; AL # L& [38] CYRILLIC CAPITAL LETTER A WITH BREVE..CYRILLIC SMALL LETTER CHE WITH DIAERESIS +04F8..04F9 ; AL # L& [2] CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS..CYRILLIC SMALL LETTER YERU WITH DIAERESIS +0531..0556 ; AL # L& [38] ARMENIAN CAPITAL LETTER AYB..ARMENIAN CAPITAL LETTER FEH +0559 ; AL # Lm ARMENIAN MODIFIER LETTER LEFT HALF RING +055A..055F ; AL # Po [6] ARMENIAN APOSTROPHE..ARMENIAN ABBREVIATION MARK +0561..0587 ; AL # L& [39] ARMENIAN SMALL LETTER AYB..ARMENIAN SMALL LIGATURE ECH YIWN +05BE ; AL # Po HEBREW PUNCTUATION MAQAF +05C0 ; AL # Po HEBREW PUNCTUATION PASEQ +05C3 ; AL # Po HEBREW PUNCTUATION SOF PASUQ +05D0..05EA ; AL # Lo [27] HEBREW LETTER ALEF..HEBREW LETTER TAV +05F0..05F2 ; AL # Lo [3] HEBREW LIGATURE YIDDISH DOUBLE VAV..HEBREW LIGATURE YIDDISH DOUBLE YOD +05F3..05F4 ; AL # Po [2] HEBREW PUNCTUATION GERESH..HEBREW PUNCTUATION GERSHAYIM +060C ; AL # Po ARABIC COMMA +061B ; AL # Po ARABIC SEMICOLON +061F ; AL # Po ARABIC QUESTION MARK +0621..063A ; AL # Lo [26] ARABIC LETTER HAMZA..ARABIC LETTER GHAIN +0640 ; AL # Lm ARABIC TATWEEL +0641..064A ; AL # Lo [10] ARABIC LETTER FEH..ARABIC LETTER YEH +066A..066D ; AL # Po [4] ARABIC PERCENT SIGN..ARABIC FIVE POINTED STAR +0671..06D3 ; AL # Lo [99] ARABIC LETTER ALEF WASLA..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE +06D4 ; AL # Po ARABIC FULL STOP +06D5 ; AL # Lo ARABIC LETTER AE +06E5..06E6 ; AL # Lm [2] ARABIC SMALL WAW..ARABIC SMALL YEH +06E9 ; AL # So ARABIC PLACE OF SAJDAH +06FA..06FC ; AL # Lo [3] ARABIC LETTER SHEEN WITH DOT BELOW..ARABIC LETTER GHAIN WITH DOT BELOW +06FD..06FE ; AL # So [2] ARABIC SIGN SINDHI AMPERSAND..ARABIC SIGN SINDHI POSTPOSITION MEN +0700..070D ; AL # Po [14] SYRIAC END OF PARAGRAPH..SYRIAC HARKLEAN ASTERISCUS +0710 ; AL # Lo SYRIAC LETTER ALAPH +0712..072C ; AL # Lo [27] SYRIAC LETTER BETH..SYRIAC LETTER TAW +0780..07A5 ; AL # Lo [38] THAANA LETTER HAA..THAANA LETTER WAAVU +0905..0939 ; AL # Lo [53] DEVANAGARI LETTER A..DEVANAGARI LETTER HA +093D ; AL # Lo DEVANAGARI SIGN AVAGRAHA +0950 ; AL # Lo DEVANAGARI OM +0958..0961 ; AL # Lo [10] DEVANAGARI LETTER QA..DEVANAGARI LETTER VOCALIC LL +0964..0965 ; AL # Po [2] DEVANAGARI DANDA..DEVANAGARI DOUBLE DANDA +0970 ; AL # Po DEVANAGARI ABBREVIATION SIGN +0985..098C ; AL # Lo [8] BENGALI LETTER A..BENGALI LETTER VOCALIC L +098F..0990 ; AL # Lo [2] BENGALI LETTER E..BENGALI LETTER AI +0993..09A8 ; AL # Lo [22] BENGALI LETTER O..BENGALI LETTER NA +09AA..09B0 ; AL # Lo [7] BENGALI LETTER PA..BENGALI LETTER RA +09B2 ; AL # Lo BENGALI LETTER LA +09B6..09B9 ; AL # Lo [4] BENGALI LETTER SHA..BENGALI LETTER HA +09DC..09DD ; AL # Lo [2] BENGALI LETTER RRA..BENGALI LETTER RHA +09DF..09E1 ; AL # Lo [3] BENGALI LETTER YYA..BENGALI LETTER VOCALIC LL +09F0..09F1 ; AL # Lo [2] BENGALI LETTER RA WITH MIDDLE DIAGONAL..BENGALI LETTER RA WITH LOWER DIAGONAL +09F4..09F9 ; AL # No [6] BENGALI CURRENCY NUMERATOR ONE..BENGALI CURRENCY DENOMINATOR SIXTEEN +09FA ; AL # So BENGALI ISSHAR +0A05..0A0A ; AL # Lo [6] GURMUKHI LETTER A..GURMUKHI LETTER UU +0A0F..0A10 ; AL # Lo [2] GURMUKHI LETTER EE..GURMUKHI LETTER AI +0A13..0A28 ; AL # Lo [22] GURMUKHI LETTER OO..GURMUKHI LETTER NA +0A2A..0A30 ; AL # Lo [7] GURMUKHI LETTER PA..GURMUKHI LETTER RA +0A32..0A33 ; AL # Lo [2] GURMUKHI LETTER LA..GURMUKHI LETTER LLA +0A35..0A36 ; AL # Lo [2] GURMUKHI LETTER VA..GURMUKHI LETTER SHA +0A38..0A39 ; AL # Lo [2] GURMUKHI LETTER SA..GURMUKHI LETTER HA +0A59..0A5C ; AL # Lo [4] GURMUKHI LETTER KHHA..GURMUKHI LETTER RRA +0A5E ; AL # Lo GURMUKHI LETTER FA +0A72..0A74 ; AL # Lo [3] GURMUKHI IRI..GURMUKHI EK ONKAR +0A85..0A8B ; AL # Lo [7] GUJARATI LETTER A..GUJARATI LETTER VOCALIC R +0A8D ; AL # Lo GUJARATI VOWEL CANDRA E +0A8F..0A91 ; AL # Lo [3] GUJARATI LETTER E..GUJARATI VOWEL CANDRA O +0A93..0AA8 ; AL # Lo [22] GUJARATI LETTER O..GUJARATI LETTER NA +0AAA..0AB0 ; AL # Lo [7] GUJARATI LETTER PA..GUJARATI LETTER RA +0AB2..0AB3 ; AL # Lo [2] GUJARATI LETTER LA..GUJARATI LETTER LLA +0AB5..0AB9 ; AL # Lo [5] GUJARATI LETTER VA..GUJARATI LETTER HA +0ABD ; AL # Lo GUJARATI SIGN AVAGRAHA +0AD0 ; AL # Lo GUJARATI OM +0AE0 ; AL # Lo GUJARATI LETTER VOCALIC RR +0B05..0B0C ; AL # Lo [8] ORIYA LETTER A..ORIYA LETTER VOCALIC L +0B0F..0B10 ; AL # Lo [2] ORIYA LETTER E..ORIYA LETTER AI +0B13..0B28 ; AL # Lo [22] ORIYA LETTER O..ORIYA LETTER NA +0B2A..0B30 ; AL # Lo [7] ORIYA LETTER PA..ORIYA LETTER RA +0B32..0B33 ; AL # Lo [2] ORIYA LETTER LA..ORIYA LETTER LLA +0B36..0B39 ; AL # Lo [4] ORIYA LETTER SHA..ORIYA LETTER HA +0B3D ; AL # Lo ORIYA SIGN AVAGRAHA +0B5C..0B5D ; AL # Lo [2] ORIYA LETTER RRA..ORIYA LETTER RHA +0B5F..0B61 ; AL # Lo [3] ORIYA LETTER YYA..ORIYA LETTER VOCALIC LL +0B70 ; AL # So ORIYA ISSHAR +0B85..0B8A ; AL # Lo [6] TAMIL LETTER A..TAMIL LETTER UU +0B8E..0B90 ; AL # Lo [3] TAMIL LETTER E..TAMIL LETTER AI +0B92..0B95 ; AL # Lo [4] TAMIL LETTER O..TAMIL LETTER KA +0B99..0B9A ; AL # Lo [2] TAMIL LETTER NGA..TAMIL LETTER CA +0B9C ; AL # Lo TAMIL LETTER JA +0B9E..0B9F ; AL # Lo [2] TAMIL LETTER NYA..TAMIL LETTER TTA +0BA3..0BA4 ; AL # Lo [2] TAMIL LETTER NNA..TAMIL LETTER TA +0BA8..0BAA ; AL # Lo [3] TAMIL LETTER NA..TAMIL LETTER PA +0BAE..0BB5 ; AL # Lo [8] TAMIL LETTER MA..TAMIL LETTER VA +0BB7..0BB9 ; AL # Lo [3] TAMIL LETTER SSA..TAMIL LETTER HA +0BF0..0BF2 ; AL # No [3] TAMIL NUMBER TEN..TAMIL NUMBER ONE THOUSAND +0C05..0C0C ; AL # Lo [8] TELUGU LETTER A..TELUGU LETTER VOCALIC L +0C0E..0C10 ; AL # Lo [3] TELUGU LETTER E..TELUGU LETTER AI +0C12..0C28 ; AL # Lo [23] TELUGU LETTER O..TELUGU LETTER NA +0C2A..0C33 ; AL # Lo [10] TELUGU LETTER PA..TELUGU LETTER LLA +0C35..0C39 ; AL # Lo [5] TELUGU LETTER VA..TELUGU LETTER HA +0C60..0C61 ; AL # Lo [2] TELUGU LETTER VOCALIC RR..TELUGU LETTER VOCALIC LL +0C85..0C8C ; AL # Lo [8] KANNADA LETTER A..KANNADA LETTER VOCALIC L +0C8E..0C90 ; AL # Lo [3] KANNADA LETTER E..KANNADA LETTER AI +0C92..0CA8 ; AL # Lo [23] KANNADA LETTER O..KANNADA LETTER NA +0CAA..0CB3 ; AL # Lo [10] KANNADA LETTER PA..KANNADA LETTER LLA +0CB5..0CB9 ; AL # Lo [5] KANNADA LETTER VA..KANNADA LETTER HA +0CDE ; AL # Lo KANNADA LETTER FA +0CE0..0CE1 ; AL # Lo [2] KANNADA LETTER VOCALIC RR..KANNADA LETTER VOCALIC LL +0D05..0D0C ; AL # Lo [8] MALAYALAM LETTER A..MALAYALAM LETTER VOCALIC L +0D0E..0D10 ; AL # Lo [3] MALAYALAM LETTER E..MALAYALAM LETTER AI +0D12..0D28 ; AL # Lo [23] MALAYALAM LETTER O..MALAYALAM LETTER NA +0D2A..0D39 ; AL # Lo [16] MALAYALAM LETTER PA..MALAYALAM LETTER HA +0D60..0D61 ; AL # Lo [2] MALAYALAM LETTER VOCALIC RR..MALAYALAM LETTER VOCALIC LL +0D85..0D96 ; AL # Lo [18] SINHALA LETTER AYANNA..SINHALA LETTER AUYANNA +0D9A..0DB1 ; AL # Lo [24] SINHALA LETTER ALPAPRAANA KAYANNA..SINHALA LETTER DANTAJA NAYANNA +0DB3..0DBB ; AL # Lo [9] SINHALA LETTER SANYAKA DAYANNA..SINHALA LETTER RAYANNA +0DBD ; AL # Lo SINHALA LETTER DANTAJA LAYANNA +0DC0..0DC6 ; AL # Lo [7] SINHALA LETTER VAYANNA..SINHALA LETTER FAYANNA +0DF4 ; AL # Po SINHALA PUNCTUATION KUNDDALIYA +0E4F ; AL # Po THAI CHARACTER FONGMAN +0F00 ; AL # Lo TIBETAN SYLLABLE OM +0F01..0F03 ; AL # So [3] TIBETAN MARK GTER YIG MGO TRUNCATED A..TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA +0F04..0F0A ; AL # Po [7] TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK BKA- SHOG YIG MGO +0F0D..0F12 ; AL # Po [6] TIBETAN MARK SHAD..TIBETAN MARK RGYA GRAM SHAD +0F13..0F17 ; AL # So [5] TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN..TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS +0F1A..0F1F ; AL # So [6] TIBETAN SIGN RDEL DKAR GCIG..TIBETAN SIGN RDEL DKAR RDEL NAG +0F2A..0F33 ; AL # No [10] TIBETAN DIGIT HALF ONE..TIBETAN DIGIT HALF ZERO +0F34 ; AL # So TIBETAN MARK BSDUS RTAGS +0F36 ; AL # So TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN +0F38 ; AL # So TIBETAN MARK CHE MGO +0F40..0F47 ; AL # Lo [8] TIBETAN LETTER KA..TIBETAN LETTER JA +0F49..0F6A ; AL # Lo [34] TIBETAN LETTER NYA..TIBETAN LETTER FIXED-FORM RA +0F85 ; AL # Po TIBETAN MARK PALUTA +0F88..0F8B ; AL # Lo [4] TIBETAN SIGN LCE TSA CAN..TIBETAN SIGN GRU MED RGYINGS +0FBE..0FC5 ; AL # So [8] TIBETAN KU RU KHA..TIBETAN SYMBOL RDO RJE +0FC7..0FCC ; AL # So [6] TIBETAN SYMBOL RDO RJE RGYA GRAM..TIBETAN SYMBOL NOR BU BZHI -KHYIL +0FCF ; AL # So TIBETAN SIGN RDEL NAG GSUM +104A..104F ; AL # Po [6] MYANMAR SIGN LITTLE SECTION..MYANMAR SYMBOL GENITIVE +10A0..10C5 ; AL # L& [38] GEORGIAN CAPITAL LETTER AN..GEORGIAN CAPITAL LETTER HOE +10D0..10F6 ; AL # Lo [39] GEORGIAN LETTER AN..GEORGIAN LETTER FI +10FB ; AL # Po GEORGIAN PARAGRAPH SEPARATOR +1200..1206 ; AL # Lo [7] ETHIOPIC SYLLABLE HA..ETHIOPIC SYLLABLE HO +1208..1246 ; AL # Lo [63] ETHIOPIC SYLLABLE LA..ETHIOPIC SYLLABLE QO +1248 ; AL # Lo ETHIOPIC SYLLABLE QWA +124A..124D ; AL # Lo [4] ETHIOPIC SYLLABLE QWI..ETHIOPIC SYLLABLE QWE +1250..1256 ; AL # Lo [7] ETHIOPIC SYLLABLE QHA..ETHIOPIC SYLLABLE QHO +1258 ; AL # Lo ETHIOPIC SYLLABLE QHWA +125A..125D ; AL # Lo [4] ETHIOPIC SYLLABLE QHWI..ETHIOPIC SYLLABLE QHWE +1260..1286 ; AL # Lo [39] ETHIOPIC SYLLABLE BA..ETHIOPIC SYLLABLE XO +1288 ; AL # Lo ETHIOPIC SYLLABLE XWA +128A..128D ; AL # Lo [4] ETHIOPIC SYLLABLE XWI..ETHIOPIC SYLLABLE XWE +1290..12AE ; AL # Lo [31] ETHIOPIC SYLLABLE NA..ETHIOPIC SYLLABLE KO +12B0 ; AL # Lo ETHIOPIC SYLLABLE KWA +12B2..12B5 ; AL # Lo [4] ETHIOPIC SYLLABLE KWI..ETHIOPIC SYLLABLE KWE +12B8..12BE ; AL # Lo [7] ETHIOPIC SYLLABLE KXA..ETHIOPIC SYLLABLE KXO +12C0 ; AL # Lo ETHIOPIC SYLLABLE KXWA +12C2..12C5 ; AL # Lo [4] ETHIOPIC SYLLABLE KXWI..ETHIOPIC SYLLABLE KXWE +12C8..12CE ; AL # Lo [7] ETHIOPIC SYLLABLE WA..ETHIOPIC SYLLABLE WO +12D0..12D6 ; AL # Lo [7] ETHIOPIC SYLLABLE PHARYNGEAL A..ETHIOPIC SYLLABLE PHARYNGEAL O +12D8..12EE ; AL # Lo [23] ETHIOPIC SYLLABLE ZA..ETHIOPIC SYLLABLE YO +12F0..130E ; AL # Lo [31] ETHIOPIC SYLLABLE DA..ETHIOPIC SYLLABLE GO +1310 ; AL # Lo ETHIOPIC SYLLABLE GWA +1312..1315 ; AL # Lo [4] ETHIOPIC SYLLABLE GWI..ETHIOPIC SYLLABLE GWE +1318..131E ; AL # Lo [7] ETHIOPIC SYLLABLE GGA..ETHIOPIC SYLLABLE GGO +1320..1346 ; AL # Lo [39] ETHIOPIC SYLLABLE THA..ETHIOPIC SYLLABLE TZO +1348..135A ; AL # Lo [19] ETHIOPIC SYLLABLE FA..ETHIOPIC SYLLABLE FYA +1362..1368 ; AL # Po [7] ETHIOPIC FULL STOP..ETHIOPIC PARAGRAPH SEPARATOR +1372..137C ; AL # No [11] ETHIOPIC NUMBER TEN..ETHIOPIC NUMBER TEN THOUSAND +13A0..13F4 ; AL # Lo [85] CHEROKEE LETTER A..CHEROKEE LETTER YV +1401..166C ; AL # Lo [620] CANADIAN SYLLABICS E..CANADIAN SYLLABICS CARRIER TTSA +166D..166E ; AL # Po [2] CANADIAN SYLLABICS CHI SIGN..CANADIAN SYLLABICS FULL STOP +166F..1676 ; AL # Lo [8] CANADIAN SYLLABICS QAI..CANADIAN SYLLABICS NNGAA +1681..169A ; AL # Lo [26] OGHAM LETTER BEITH..OGHAM LETTER PEITH +16A0..16EA ; AL # Lo [75] RUNIC LETTER FEHU FEOH FE F..RUNIC LETTER X +16EB..16ED ; AL # Po [3] RUNIC SINGLE PUNCTUATION..RUNIC CROSS PUNCTUATION +16EE..16F0 ; AL # Nl [3] RUNIC ARLAUG SYMBOL..RUNIC BELGTHOR SYMBOL +17DC ; AL # Po KHMER SIGN AVAKRAHASANYA +1800..1805 ; AL # Po [6] MONGOLIAN BIRGA..MONGOLIAN FOUR DOTS +1807..180A ; AL # Po [4] MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER..MONGOLIAN NIRUGU +1820..1842 ; AL # Lo [35] MONGOLIAN LETTER A..MONGOLIAN LETTER CHI +1843 ; AL # Lm MONGOLIAN LETTER TODO LONG VOWEL SIGN +1844..1877 ; AL # Lo [52] MONGOLIAN LETTER TODO E..MONGOLIAN LETTER MANCHU ZHA +1880..18A8 ; AL # Lo [41] MONGOLIAN LETTER ALI GALI ANUSVARA ONE..MONGOLIAN LETTER MANCHU ALI GALI BHA +1E00..1E9B ; AL # L& [156] LATIN CAPITAL LETTER A WITH RING BELOW..LATIN SMALL LETTER LONG S WITH DOT ABOVE +1EA0..1EF9 ; AL # L& [90] LATIN CAPITAL LETTER A WITH DOT BELOW..LATIN SMALL LETTER Y WITH TILDE +1F00..1F15 ; AL # L& [22] GREEK SMALL LETTER ALPHA WITH PSILI..GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA +1F18..1F1D ; AL # L& [6] GREEK CAPITAL LETTER EPSILON WITH PSILI..GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA +1F20..1F45 ; AL # L& [38] GREEK SMALL LETTER ETA WITH PSILI..GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA +1F48..1F4D ; AL # L& [6] GREEK CAPITAL LETTER OMICRON WITH PSILI..GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA +1F50..1F57 ; AL # L& [8] GREEK SMALL LETTER UPSILON WITH PSILI..GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI +1F59 ; AL # L& GREEK CAPITAL LETTER UPSILON WITH DASIA +1F5B ; AL # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA +1F5D ; AL # L& GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA +1F5F..1F7D ; AL # L& [31] GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI..GREEK SMALL LETTER OMEGA WITH OXIA +1F80..1FB4 ; AL # L& [53] GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI..GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI +1FB6..1FBC ; AL # L& [7] GREEK SMALL LETTER ALPHA WITH PERISPOMENI..GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI +1FBD ; AL # Sk GREEK KORONIS +1FBE ; AL # L& GREEK PROSGEGRAMMENI +1FBF..1FC1 ; AL # Sk [3] GREEK PSILI..GREEK DIALYTIKA AND PERISPOMENI +1FC2..1FC4 ; AL # L& [3] GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI +1FC6..1FCC ; AL # L& [7] GREEK SMALL LETTER ETA WITH PERISPOMENI..GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI +1FCD..1FCF ; AL # Sk [3] GREEK PSILI AND VARIA..GREEK PSILI AND PERISPOMENI +1FD0..1FD3 ; AL # L& [4] GREEK SMALL LETTER IOTA WITH VRACHY..GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA +1FD6..1FDB ; AL # L& [6] GREEK SMALL LETTER IOTA WITH PERISPOMENI..GREEK CAPITAL LETTER IOTA WITH OXIA +1FDD..1FDF ; AL # Sk [3] GREEK DASIA AND VARIA..GREEK DASIA AND PERISPOMENI +1FE0..1FEC ; AL # L& [13] GREEK SMALL LETTER UPSILON WITH VRACHY..GREEK CAPITAL LETTER RHO WITH DASIA +1FED..1FEF ; AL # Sk [3] GREEK DIALYTIKA AND VARIA..GREEK VARIA +1FF2..1FF4 ; AL # L& [3] GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI..GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI +1FF6..1FFC ; AL # L& [7] GREEK SMALL LETTER OMEGA WITH PERISPOMENI..GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI +1FFD..1FFE ; AL # Sk [2] GREEK OXIA..GREEK DASIA +2017 ; AL # Po DOUBLE LOW LINE +2022..2023 ; AL # Po [2] BULLET..TRIANGULAR BULLET +2038 ; AL # Po CARET +203D..203E ; AL # Po [2] INTERROBANG..OVERLINE +203F..2040 ; AL # Pc [2] UNDERTIE..CHARACTER TIE +2041..2043 ; AL # Po [3] CARET INSERTION POINT..HYPHEN BULLET +2048..204D ; AL # Po [6] QUESTION EXCLAMATION MARK..BLACK RIGHTWARDS BULLET +2070 ; AL # No SUPERSCRIPT ZERO +2075..2079 ; AL # No [5] SUPERSCRIPT FIVE..SUPERSCRIPT NINE +207A..207C ; AL # Sm [3] SUPERSCRIPT PLUS SIGN..SUPERSCRIPT EQUALS SIGN +2080 ; AL # No SUBSCRIPT ZERO +2085..2089 ; AL # No [5] SUBSCRIPT FIVE..SUBSCRIPT NINE +208A..208C ; AL # Sm [3] SUBSCRIPT PLUS SIGN..SUBSCRIPT EQUALS SIGN +2100..2101 ; AL # So [2] ACCOUNT OF..ADDRESSED TO THE SUBJECT +2102 ; AL # L& DOUBLE-STRUCK CAPITAL C +2104 ; AL # So CENTRE LINE SYMBOL +2106 ; AL # So CADA UNA +2107 ; AL # L& EULER CONSTANT +2108 ; AL # So SCRUPLE +210A..2112 ; AL # L& [9] SCRIPT SMALL G..SCRIPT CAPITAL L +2114 ; AL # So L B BAR SYMBOL +2115 ; AL # L& DOUBLE-STRUCK CAPITAL N +2117..2118 ; AL # So [2] SOUND RECORDING COPYRIGHT..SCRIPT CAPITAL P +2119..211D ; AL # L& [5] DOUBLE-STRUCK CAPITAL P..DOUBLE-STRUCK CAPITAL R +211E..2120 ; AL # So [3] PRESCRIPTION TAKE..SERVICE MARK +2123 ; AL # So VERSICLE +2124 ; AL # L& DOUBLE-STRUCK CAPITAL Z +2125 ; AL # So OUNCE SIGN +2127 ; AL # So INVERTED OHM SIGN +2128 ; AL # L& BLACK-LETTER CAPITAL Z +2129 ; AL # So TURNED GREEK SMALL LETTER IOTA +212A ; AL # L& KELVIN SIGN +212C..212D ; AL # L& [2] SCRIPT CAPITAL B..BLACK-LETTER CAPITAL C +212E ; AL # So ESTIMATED SYMBOL +212F..2131 ; AL # L& [3] SCRIPT SMALL E..SCRIPT CAPITAL F +2132 ; AL # So TURNED CAPITAL F +2133..2134 ; AL # L& [2] SCRIPT CAPITAL M..SCRIPT SMALL O +2135..2138 ; AL # Lo [4] ALEF SYMBOL..DALET SYMBOL +2139 ; AL # L& INFORMATION SOURCE +213A ; AL # So ROTATED CAPITAL Q +2153 ; AL # No VULGAR FRACTION ONE THIRD +2156..215A ; AL # No [5] VULGAR FRACTION TWO FIFTHS..VULGAR FRACTION FIVE SIXTHS +215C..215D ; AL # No [2] VULGAR FRACTION THREE EIGHTHS..VULGAR FRACTION FIVE EIGHTHS +215F ; AL # No FRACTION NUMERATOR ONE +216C..216F ; AL # Nl [4] ROMAN NUMERAL FIFTY..ROMAN NUMERAL ONE THOUSAND +217A..2183 ; AL # Nl [10] SMALL ROMAN NUMERAL ELEVEN..ROMAN NUMERAL REVERSED ONE HUNDRED +219A..219B ; AL # Sm [2] LEFTWARDS ARROW WITH STROKE..RIGHTWARDS ARROW WITH STROKE +219C..219F ; AL # So [4] LEFTWARDS WAVE ARROW..UPWARDS TWO HEADED ARROW +21A0 ; AL # Sm RIGHTWARDS TWO HEADED ARROW +21A1..21A2 ; AL # So [2] DOWNWARDS TWO HEADED ARROW..LEFTWARDS ARROW WITH TAIL +21A3 ; AL # Sm RIGHTWARDS ARROW WITH TAIL +21A4..21A5 ; AL # So [2] LEFTWARDS ARROW FROM BAR..UPWARDS ARROW FROM BAR +21A6 ; AL # Sm RIGHTWARDS ARROW FROM BAR +21A7..21AD ; AL # So [7] DOWNWARDS ARROW FROM BAR..LEFT RIGHT WAVE ARROW +21AE ; AL # Sm LEFT RIGHT ARROW WITH STROKE +21AF..21CD ; AL # So [31] DOWNWARDS ZIGZAG ARROW..LEFTWARDS DOUBLE ARROW WITH STROKE +21CE..21CF ; AL # Sm [2] LEFT RIGHT DOUBLE ARROW WITH STROKE..RIGHTWARDS DOUBLE ARROW WITH STROKE +21D0..21D1 ; AL # So [2] LEFTWARDS DOUBLE ARROW..UPWARDS DOUBLE ARROW +21D3 ; AL # So DOWNWARDS DOUBLE ARROW +21D5..21F3 ; AL # So [31] UP DOWN DOUBLE ARROW..UP DOWN WHITE ARROW +2201 ; AL # Sm COMPLEMENT +2204..2206 ; AL # Sm [3] THERE DOES NOT EXIST..INCREMENT +2209..220A ; AL # Sm [2] NOT AN ELEMENT OF..SMALL ELEMENT OF +220C..220E ; AL # Sm [3] DOES NOT CONTAIN AS MEMBER..END OF PROOF +2210 ; AL # Sm N-ARY COPRODUCT +2214 ; AL # Sm DOT PLUS +2216..2219 ; AL # Sm [4] SET MINUS..BULLET OPERATOR +221B..221C ; AL # Sm [2] CUBE ROOT..FOURTH ROOT +2221..2222 ; AL # Sm [2] MEASURED ANGLE..SPHERICAL ANGLE +2224 ; AL # Sm DOES NOT DIVIDE +2226 ; AL # Sm NOT PARALLEL TO +222D ; AL # Sm TRIPLE INTEGRAL +222F..2233 ; AL # Sm [5] SURFACE INTEGRAL..ANTICLOCKWISE CONTOUR INTEGRAL +2238..223B ; AL # Sm [4] DOT MINUS..HOMOTHETIC +223E..2247 ; AL # Sm [10] INVERTED LAZY S..NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO +2249..224B ; AL # Sm [3] NOT ALMOST EQUAL TO..TRIPLE TILDE +224D..2251 ; AL # Sm [5] EQUIVALENT TO..GEOMETRICALLY EQUAL TO +2253..225F ; AL # Sm [13] IMAGE OF OR APPROXIMATELY EQUAL TO..QUESTIONED EQUAL TO +2262..2263 ; AL # Sm [2] NOT IDENTICAL TO..STRICTLY EQUIVALENT TO +2268..2269 ; AL # Sm [2] LESS-THAN BUT NOT EQUAL TO..GREATER-THAN BUT NOT EQUAL TO +226C..226D ; AL # Sm [2] BETWEEN..NOT EQUIVALENT TO +2270..2281 ; AL # Sm [18] NEITHER LESS-THAN NOR EQUAL TO..DOES NOT SUCCEED +2284..2285 ; AL # Sm [2] NOT A SUBSET OF..NOT A SUPERSET OF +2288..2294 ; AL # Sm [13] NEITHER A SUBSET OF NOR EQUAL TO..SQUARE CUP +2296..2298 ; AL # Sm [3] CIRCLED MINUS..CIRCLED DIVISION SLASH +229A..22A4 ; AL # Sm [11] CIRCLED RING OPERATOR..DOWN TACK +22A6..22BE ; AL # Sm [25] ASSERTION..RIGHT ANGLE WITH ARC +22C0..22F1 ; AL # Sm [50] N-ARY LOGICAL AND..DOWN RIGHT DIAGONAL ELLIPSIS +2300..2307 ; AL # So [8] DIAMETER SIGN..WAVY LINE +2308..230B ; AL # Sm [4] LEFT CEILING..RIGHT FLOOR +230C..2311 ; AL # So [6] BOTTOM RIGHT CROP..SQUARE LOZENGE +2313..231F ; AL # So [13] SEGMENT..BOTTOM RIGHT CORNER +2320..2321 ; AL # Sm [2] TOP HALF INTEGRAL..BOTTOM HALF INTEGRAL +2322..2328 ; AL # So [7] FROWN..KEYBOARD +232B..237B ; AL # So [81] ERASE TO THE LEFT..NOT CHECK MARK +237D..239A ; AL # So [30] SHOULDERED OPEN BOX..CLEAR SCREEN SYMBOL +2400..2426 ; AL # So [39] SYMBOL FOR NULL..SYMBOL FOR SUBSTITUTE FORM TWO +2440..244A ; AL # So [11] OCR HOOK..OCR DOUBLE BACKSLASH +24C0..24CF ; AL # So [16] CIRCLED LATIN CAPITAL LETTER K..CIRCLED LATIN CAPITAL LETTER Z +24EA ; AL # No CIRCLED DIGIT ZERO +254C..254F ; AL # So [4] BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL..BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL +2575..257F ; AL # So [11] BOX DRAWINGS LIGHT UP..BOX DRAWINGS HEAVY UP AND LIGHT DOWN +2590..2591 ; AL # So [2] RIGHT HALF BLOCK..LIGHT SHADE +25A2 ; AL # So WHITE SQUARE WITH ROUNDED CORNERS +25AA..25B1 ; AL # So [8] BLACK SMALL SQUARE..WHITE PARALLELOGRAM +25B4..25B5 ; AL # So [2] BLACK UP-POINTING SMALL TRIANGLE..WHITE UP-POINTING SMALL TRIANGLE +25B8..25BB ; AL # So [4] BLACK RIGHT-POINTING SMALL TRIANGLE..WHITE RIGHT-POINTING POINTER +25BE..25BF ; AL # So [2] BLACK DOWN-POINTING SMALL TRIANGLE..WHITE DOWN-POINTING SMALL TRIANGLE +25C2..25C5 ; AL # So [4] BLACK LEFT-POINTING SMALL TRIANGLE..WHITE LEFT-POINTING POINTER +25C9..25CA ; AL # So [2] FISHEYE..LOZENGE +25CC..25CD ; AL # So [2] DOTTED CIRCLE..CIRCLE WITH VERTICAL FILL +25D2..25E1 ; AL # So [16] CIRCLE WITH LOWER HALF BLACK..LOWER HALF CIRCLE +25E6..25EE ; AL # So [9] WHITE BULLET..UP-POINTING TRIANGLE WITH RIGHT HALF BLACK +25F0..25F7 ; AL # So [8] WHITE SQUARE WITH UPPER LEFT QUADRANT..WHITE CIRCLE WITH UPPER RIGHT QUADRANT +2600..2604 ; AL # So [5] BLACK SUN WITH RAYS..COMET +2607..2608 ; AL # So [2] LIGHTNING..THUNDERSTORM +260A..260D ; AL # So [4] ASCENDING NODE..OPPOSITION +2610..2613 ; AL # So [4] BALLOT BOX..SALTIRE +2619..261B ; AL # So [3] REVERSED ROTATED FLORAL HEART BULLET..BLACK RIGHT POINTING INDEX +261D ; AL # So WHITE UP POINTING INDEX +261F..263F ; AL # So [33] WHITE DOWN POINTING INDEX..MERCURY +2641 ; AL # So EARTH +2643..265F ; AL # So [29] JUPITER..BLACK CHESS PAWN +2662 ; AL # So WHITE DIAMOND SUIT +2666 ; AL # So BLACK DIAMOND SUIT +266B ; AL # So BEAMED EIGHTH NOTES +266E ; AL # So MUSIC NATURAL SIGN +2670..2671 ; AL # So [2] WEST SYRIAC CROSS..EAST SYRIAC CROSS +2701..2704 ; AL # So [4] UPPER BLADE SCISSORS..WHITE SCISSORS +2706..2709 ; AL # So [4] TELEPHONE LOCATION SIGN..ENVELOPE +270C..2727 ; AL # So [28] VICTORY HAND..WHITE FOUR POINTED STAR +2729..274B ; AL # So [35] STRESS OUTLINED WHITE STAR..HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK +274D ; AL # So SHADOWED WHITE CIRCLE +274F..2752 ; AL # So [4] LOWER RIGHT DROP-SHADOWED WHITE SQUARE..UPPER RIGHT SHADOWED WHITE SQUARE +2756 ; AL # So BLACK DIAMOND MINUS WHITE X +2758..275E ; AL # So [7] LIGHT VERTICAL BAR..HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT +2761..2767 ; AL # So [7] CURVED STEM PARAGRAPH SIGN ORNAMENT..ROTATED FLORAL HEART BULLET +2776..2793 ; AL # No [30] DINGBAT NEGATIVE CIRCLED DIGIT ONE..DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN +2794 ; AL # So HEAVY WIDE-HEADED RIGHTWARDS ARROW +2798..27AF ; AL # So [24] HEAVY SOUTH EAST ARROW..NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW +27B1..27BE ; AL # So [14] NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW..OPEN-OUTLINED RIGHTWARDS ARROW +2800..28FF ; AL # So [256] BRAILLE PATTERN BLANK..BRAILLE PATTERN DOTS-12345678 +FB00..FB06 ; AL # L& [7] LATIN SMALL LIGATURE FF..LATIN SMALL LIGATURE ST +FB13..FB17 ; AL # L& [5] ARMENIAN SMALL LIGATURE MEN NOW..ARMENIAN SMALL LIGATURE MEN XEH +FB1D ; AL # Lo HEBREW LETTER YOD WITH HIRIQ +FB1F..FB28 ; AL # Lo [10] HEBREW LIGATURE YIDDISH YOD YOD PATAH..HEBREW LETTER WIDE TAV +FB29 ; AL # Sm HEBREW LETTER ALTERNATIVE PLUS SIGN +FB2A..FB36 ; AL # Lo [13] HEBREW LETTER SHIN WITH SHIN DOT..HEBREW LETTER ZAYIN WITH DAGESH +FB38..FB3C ; AL # Lo [5] HEBREW LETTER TET WITH DAGESH..HEBREW LETTER LAMED WITH DAGESH +FB3E ; AL # Lo HEBREW LETTER MEM WITH DAGESH +FB40..FB41 ; AL # Lo [2] HEBREW LETTER NUN WITH DAGESH..HEBREW LETTER SAMEKH WITH DAGESH +FB43..FB44 ; AL # Lo [2] HEBREW LETTER FINAL PE WITH DAGESH..HEBREW LETTER PE WITH DAGESH +FB46..FBB1 ; AL # Lo [108] HEBREW LETTER TSADI WITH DAGESH..ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM +FBD3..FD3D ; AL # Lo [363] ARABIC LETTER NG ISOLATED FORM..ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM +FD50..FD8F ; AL # Lo [64] ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM..ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM +FD92..FDC7 ; AL # Lo [54] ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM..ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM +FDF0..FDFB ; AL # Lo [12] ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM..ARABIC LIGATURE JALLAJALALOUHOU +FE70..FE72 ; AL # Lo [3] ARABIC FATHATAN ISOLATED FORM..ARABIC DAMMATAN ISOLATED FORM +FE74 ; AL # Lo ARABIC KASRATAN ISOLATED FORM +FE76..FEFC ; AL # Lo [135] ARABIC FATHA ISOLATED FORM..ARABIC LIGATURE LAM WITH ALEF FINAL FORM +FF66 ; AL # Lo HALFWIDTH KATAKANA LETTER WO +FF71..FF9D ; AL # Lo [45] HALFWIDTH KATAKANA LETTER A..HALFWIDTH KATAKANA LETTER N +FFA0..FFBE ; AL # Lo [31] HALFWIDTH HANGUL FILLER..HALFWIDTH HANGUL LETTER HIEUH +FFC2..FFC7 ; AL # Lo [6] HALFWIDTH HANGUL LETTER A..HALFWIDTH HANGUL LETTER E +FFCA..FFCF ; AL # Lo [6] HALFWIDTH HANGUL LETTER YEO..HALFWIDTH HANGUL LETTER OE +FFD2..FFD7 ; AL # Lo [6] HALFWIDTH HANGUL LETTER YO..HALFWIDTH HANGUL LETTER YU +FFDA..FFDC ; AL # Lo [3] HALFWIDTH HANGUL LETTER EU..HALFWIDTH HANGUL LETTER I +FFE8 ; AL # So HALFWIDTH FORMS LIGHT VERTICAL +FFE9..FFEC ; AL # Sm [4] HALFWIDTH LEFTWARDS ARROW..HALFWIDTH DOWNWARDS ARROW +FFED..FFEE ; AL # So [2] HALFWIDTH BLACK SQUARE..HALFWIDTH WHITE CIRCLE +10300..1031E ; AL # Lo [31] OLD ITALIC LETTER A..OLD ITALIC LETTER UU +10320..10323 ; AL # No [4] OLD ITALIC NUMERAL ONE..OLD ITALIC NUMERAL FIFTY +10330..10349 ; AL # Lo [26] GOTHIC LETTER AHSA..GOTHIC LETTER OTHAL +1034A ; AL # Nl GOTHIC LETTER NINE HUNDRED +10400..10425 ; AL # L& [38] DESERET CAPITAL LETTER LONG I..DESERET CAPITAL LETTER ENG +10428..1044D ; AL # L& [38] DESERET SMALL LETTER LONG I..DESERET SMALL LETTER ENG +1D000..1D0F5 ; AL # So [246] BYZANTINE MUSICAL SYMBOL PSILI..BYZANTINE MUSICAL SYMBOL GORGON NEO KATO +1D100..1D126 ; AL # So [39] MUSICAL SYMBOL SINGLE BARLINE..MUSICAL SYMBOL DRUM CLEF-2 +1D12A..1D164 ; AL # So [59] MUSICAL SYMBOL DOUBLE SHARP..MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE +1D16A..1D16C ; AL # So [3] MUSICAL SYMBOL FINGERED TREMOLO-1..MUSICAL SYMBOL FINGERED TREMOLO-3 +1D183..1D184 ; AL # So [2] MUSICAL SYMBOL ARPEGGIATO UP..MUSICAL SYMBOL ARPEGGIATO DOWN +1D18C..1D1A9 ; AL # So [30] MUSICAL SYMBOL RINFORZANDO..MUSICAL SYMBOL DEGREE SLASH +1D1AE..1D1DD ; AL # So [48] MUSICAL SYMBOL PEDAL MARK..MUSICAL SYMBOL PES SUBPUNCTIS +1D400..1D454 ; AL # L& [85] MATHEMATICAL BOLD CAPITAL A..MATHEMATICAL ITALIC SMALL G +1D456..1D49C ; AL # L& [71] MATHEMATICAL ITALIC SMALL I..MATHEMATICAL SCRIPT CAPITAL A +1D49E..1D49F ; AL # L& [2] MATHEMATICAL SCRIPT CAPITAL C..MATHEMATICAL SCRIPT CAPITAL D +1D4A2 ; AL # L& MATHEMATICAL SCRIPT CAPITAL G +1D4A5..1D4A6 ; AL # L& [2] MATHEMATICAL SCRIPT CAPITAL J..MATHEMATICAL SCRIPT CAPITAL K +1D4A9..1D4AC ; AL # L& [4] MATHEMATICAL SCRIPT CAPITAL N..MATHEMATICAL SCRIPT CAPITAL Q +1D4AE..1D4B9 ; AL # L& [12] MATHEMATICAL SCRIPT CAPITAL S..MATHEMATICAL SCRIPT SMALL D +1D4BB ; AL # L& MATHEMATICAL SCRIPT SMALL F +1D4BD..1D4C0 ; AL # L& [4] MATHEMATICAL SCRIPT SMALL H..MATHEMATICAL SCRIPT SMALL K +1D4C2..1D4C3 ; AL # L& [2] MATHEMATICAL SCRIPT SMALL M..MATHEMATICAL SCRIPT SMALL N +1D4C5..1D505 ; AL # L& [65] MATHEMATICAL SCRIPT SMALL P..MATHEMATICAL FRAKTUR CAPITAL B +1D507..1D50A ; AL # L& [4] MATHEMATICAL FRAKTUR CAPITAL D..MATHEMATICAL FRAKTUR CAPITAL G +1D50D..1D514 ; AL # L& [8] MATHEMATICAL FRAKTUR CAPITAL J..MATHEMATICAL FRAKTUR CAPITAL Q +1D516..1D51C ; AL # L& [7] MATHEMATICAL FRAKTUR CAPITAL S..MATHEMATICAL FRAKTUR CAPITAL Y +1D51E..1D539 ; AL # L& [28] MATHEMATICAL FRAKTUR SMALL A..MATHEMATICAL DOUBLE-STRUCK CAPITAL B +1D53B..1D53E ; AL # L& [4] MATHEMATICAL DOUBLE-STRUCK CAPITAL D..MATHEMATICAL DOUBLE-STRUCK CAPITAL G +1D540..1D544 ; AL # L& [5] MATHEMATICAL DOUBLE-STRUCK CAPITAL I..MATHEMATICAL DOUBLE-STRUCK CAPITAL M +1D546 ; AL # L& MATHEMATICAL DOUBLE-STRUCK CAPITAL O +1D54A..1D550 ; AL # L& [7] MATHEMATICAL DOUBLE-STRUCK CAPITAL S..MATHEMATICAL DOUBLE-STRUCK CAPITAL Y +1D552..1D6A3 ; AL # L& [338] MATHEMATICAL DOUBLE-STRUCK SMALL A..MATHEMATICAL MONOSPACE SMALL Z +1D6A8..1D6C0 ; AL # L& [25] MATHEMATICAL BOLD CAPITAL ALPHA..MATHEMATICAL BOLD CAPITAL OMEGA +1D6C1 ; AL # Sm MATHEMATICAL BOLD NABLA +1D6C2..1D6DA ; AL # L& [25] MATHEMATICAL BOLD SMALL ALPHA..MATHEMATICAL BOLD SMALL OMEGA +1D6DB ; AL # Sm MATHEMATICAL BOLD PARTIAL DIFFERENTIAL +1D6DC..1D6FA ; AL # L& [31] MATHEMATICAL BOLD EPSILON SYMBOL..MATHEMATICAL ITALIC CAPITAL OMEGA +1D6FB ; AL # Sm MATHEMATICAL ITALIC NABLA +1D6FC..1D714 ; AL # L& [25] MATHEMATICAL ITALIC SMALL ALPHA..MATHEMATICAL ITALIC SMALL OMEGA +1D715 ; AL # Sm MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL +1D716..1D734 ; AL # L& [31] MATHEMATICAL ITALIC EPSILON SYMBOL..MATHEMATICAL BOLD ITALIC CAPITAL OMEGA +1D735 ; AL # Sm MATHEMATICAL BOLD ITALIC NABLA +1D736..1D74E ; AL # L& [25] MATHEMATICAL BOLD ITALIC SMALL ALPHA..MATHEMATICAL BOLD ITALIC SMALL OMEGA +1D74F ; AL # Sm MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL +1D750..1D76E ; AL # L& [31] MATHEMATICAL BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA +1D76F ; AL # Sm MATHEMATICAL SANS-SERIF BOLD NABLA +1D770..1D788 ; AL # L& [25] MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA +1D789 ; AL # Sm MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL +1D78A..1D7A8 ; AL # L& [31] MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA +1D7A9 ; AL # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA +1D7AA..1D7C2 ; AL # L& [25] MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA..MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA +1D7C3 ; AL # Sm MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL +1D7C4..1D7C9 ; AL # L& [6] MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL..MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL + +# Total code points: 7183 + +# ================================================ + +1100..1159 ; ID # Lo [90] HANGUL CHOSEONG KIYEOK..HANGUL CHOSEONG YEORINHIEUH +115F ; ID # Lo HANGUL CHOSEONG FILLER +2E80..2E99 ; ID # So [26] CJK RADICAL REPEAT..CJK RADICAL RAP +2E9B..2EF3 ; ID # So [89] CJK RADICAL CHOKE..CJK RADICAL C-SIMPLIFIED TURTLE +2F00..2FD5 ; ID # So [214] KANGXI RADICAL ONE..KANGXI RADICAL FLUTE +2FF0..2FFB ; ID # So [12] IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT..IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID +3000 ; ID # Zs IDEOGRAPHIC SPACE +3003 ; ID # Po DITTO MARK +3004 ; ID # So JAPANESE INDUSTRIAL STANDARD SYMBOL +3006 ; ID # Lo IDEOGRAPHIC CLOSING MARK +3007 ; ID # Nl IDEOGRAPHIC NUMBER ZERO +3012..3013 ; ID # So [2] POSTAL MARK..GETA MARK +3020 ; ID # So POSTAL MARK FACE +3021..3029 ; ID # Nl [9] HANGZHOU NUMERAL ONE..HANGZHOU NUMERAL NINE +3030 ; ID # Pd WAVY DASH +3031..3035 ; ID # Lm [5] VERTICAL KANA REPEAT MARK..VERTICAL KANA REPEAT MARK LOWER HALF +3036..3037 ; ID # So [2] CIRCLED POSTAL MARK..IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL +3038..303A ; ID # Nl [3] HANGZHOU NUMERAL TEN..HANGZHOU NUMERAL THIRTY +303E..303F ; ID # So [2] IDEOGRAPHIC VARIATION INDICATOR..IDEOGRAPHIC HALF FILL SPACE +3042 ; ID # Lo HIRAGANA LETTER A +3044 ; ID # Lo HIRAGANA LETTER I +3046 ; ID # Lo HIRAGANA LETTER U +3048 ; ID # Lo HIRAGANA LETTER E +304A..3062 ; ID # Lo [25] HIRAGANA LETTER O..HIRAGANA LETTER DI +3064..3082 ; ID # Lo [31] HIRAGANA LETTER TU..HIRAGANA LETTER MO +3084 ; ID # Lo HIRAGANA LETTER YA +3086 ; ID # Lo HIRAGANA LETTER YU +3088..308D ; ID # Lo [6] HIRAGANA LETTER YO..HIRAGANA LETTER RO +308F..3094 ; ID # Lo [6] HIRAGANA LETTER WA..HIRAGANA LETTER VU +30A2 ; ID # Lo KATAKANA LETTER A +30A4 ; ID # Lo KATAKANA LETTER I +30A6 ; ID # Lo KATAKANA LETTER U +30A8 ; ID # Lo KATAKANA LETTER E +30AA..30C2 ; ID # Lo [25] KATAKANA LETTER O..KATAKANA LETTER DI +30C4..30E2 ; ID # Lo [31] KATAKANA LETTER TU..KATAKANA LETTER MO +30E4 ; ID # Lo KATAKANA LETTER YA +30E6 ; ID # Lo KATAKANA LETTER YU +30E8..30ED ; ID # Lo [6] KATAKANA LETTER YO..KATAKANA LETTER RO +30EF..30F4 ; ID # Lo [6] KATAKANA LETTER WA..KATAKANA LETTER VU +30F7..30FA ; ID # Lo [4] KATAKANA LETTER VA..KATAKANA LETTER VO +30FC ; ID # Lm KATAKANA-HIRAGANA PROLONGED SOUND MARK +30FE ; ID # Lm KATAKANA VOICED ITERATION MARK +3105..312C ; ID # Lo [40] BOPOMOFO LETTER B..BOPOMOFO LETTER GN +3131..318E ; ID # Lo [94] HANGUL LETTER KIYEOK..HANGUL LETTER ARAEAE +3190..3191 ; ID # So [2] IDEOGRAPHIC ANNOTATION LINKING MARK..IDEOGRAPHIC ANNOTATION REVERSE MARK +3192..3195 ; ID # No [4] IDEOGRAPHIC ANNOTATION ONE MARK..IDEOGRAPHIC ANNOTATION FOUR MARK +3196..319F ; ID # So [10] IDEOGRAPHIC ANNOTATION TOP MARK..IDEOGRAPHIC ANNOTATION MAN MARK +31A0..31B7 ; ID # Lo [24] BOPOMOFO LETTER BU..BOPOMOFO FINAL LETTER H +3200..321C ; ID # So [29] PARENTHESIZED HANGUL KIYEOK..PARENTHESIZED HANGUL CIEUC U +3220..3229 ; ID # No [10] PARENTHESIZED IDEOGRAPH ONE..PARENTHESIZED IDEOGRAPH TEN +322A..3243 ; ID # So [26] PARENTHESIZED IDEOGRAPH MOON..PARENTHESIZED IDEOGRAPH REACH +3260..327B ; ID # So [28] CIRCLED HANGUL KIYEOK..CIRCLED HANGUL HIEUH A +327F ; ID # So KOREAN STANDARD SYMBOL +3280..3289 ; ID # No [10] CIRCLED IDEOGRAPH ONE..CIRCLED IDEOGRAPH TEN +328A..32B0 ; ID # So [39] CIRCLED IDEOGRAPH MOON..CIRCLED IDEOGRAPH NIGHT +32C0..32CB ; ID # So [12] IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER +32D0..32FE ; ID # So [47] CIRCLED KATAKANA A..CIRCLED KATAKANA WO +3300..3376 ; ID # So [119] SQUARE APAATO..SQUARE PC +337B..33DD ; ID # So [99] SQUARE ERA NAME HEISEI..SQUARE WB +33E0..33FE ; ID # So [31] IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE..IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE +3400..4DB5 ; ID # Lo [6582] CJK UNIFIED IDEOGRAPH-3400..CJK UNIFIED IDEOGRAPH-4DB5 +4E00..9FA5 ; ID # Lo [20902] CJK UNIFIED IDEOGRAPH-4E00..CJK UNIFIED IDEOGRAPH-9FA5 +A000..A48C ; ID # Lo [1165] YI SYLLABLE IT..YI SYLLABLE YYR +A490..A4A1 ; ID # So [18] YI RADICAL QOT..YI RADICAL GA +A4A4..A4B3 ; ID # So [16] YI RADICAL DDUR..YI RADICAL JO +A4B5..A4C0 ; ID # So [12] YI RADICAL JJY..YI RADICAL SHAT +A4C2..A4C4 ; ID # So [3] YI RADICAL SHOP..YI RADICAL ZZIET +A4C6 ; ID # So YI RADICAL KE +AC00..D7A3 ; ID # Lo [11172] HANGUL SYLLABLE GA..HANGUL SYLLABLE HIH +F900..FA2D ; ID # Lo [302] CJK COMPATIBILITY IDEOGRAPH-F900..CJK COMPATIBILITY IDEOGRAPH-FA2D +FE30 ; ID # Po PRESENTATION FORM FOR VERTICAL TWO DOT LEADER +FE31..FE32 ; ID # Pd [2] PRESENTATION FORM FOR VERTICAL EM DASH..PRESENTATION FORM FOR VERTICAL EN DASH +FE33..FE34 ; ID # Pc [2] PRESENTATION FORM FOR VERTICAL LOW LINE..PRESENTATION FORM FOR VERTICAL WAVY LOW LINE +FE49..FE4C ; ID # Po [4] DASHED OVERLINE..DOUBLE WAVY OVERLINE +FE4D..FE4F ; ID # Pc [3] DASHED LOW LINE..WAVY LOW LINE +FE51 ; ID # Po SMALL IDEOGRAPHIC COMMA +FE58 ; ID # Pd SMALL EM DASH +FE5F..FE61 ; ID # Po [3] SMALL NUMBER SIGN..SMALL ASTERISK +FE62 ; ID # Sm SMALL PLUS SIGN +FE63 ; ID # Pd SMALL HYPHEN-MINUS +FE64..FE66 ; ID # Sm [3] SMALL LESS-THAN SIGN..SMALL EQUALS SIGN +FE68 ; ID # Po SMALL REVERSE SOLIDUS +FE6B ; ID # Po SMALL COMMERCIAL AT +FF02..FF03 ; ID # Po [2] FULLWIDTH QUOTATION MARK..FULLWIDTH NUMBER SIGN +FF06..FF07 ; ID # Po [2] FULLWIDTH AMPERSAND..FULLWIDTH APOSTROPHE +FF0A ; ID # Po FULLWIDTH ASTERISK +FF0B ; ID # Sm FULLWIDTH PLUS SIGN +FF0D ; ID # Pd FULLWIDTH HYPHEN-MINUS +FF0F ; ID # Po FULLWIDTH SOLIDUS +FF10..FF19 ; ID # Nd [10] FULLWIDTH DIGIT ZERO..FULLWIDTH DIGIT NINE +FF1C..FF1E ; ID # Sm [3] FULLWIDTH LESS-THAN SIGN..FULLWIDTH GREATER-THAN SIGN +FF20 ; ID # Po FULLWIDTH COMMERCIAL AT +FF21..FF3A ; ID # L& [26] FULLWIDTH LATIN CAPITAL LETTER A..FULLWIDTH LATIN CAPITAL LETTER Z +FF3C ; ID # Po FULLWIDTH REVERSE SOLIDUS +FF3E ; ID # Sk FULLWIDTH CIRCUMFLEX ACCENT +FF3F ; ID # Pc FULLWIDTH LOW LINE +FF40 ; ID # Sk FULLWIDTH GRAVE ACCENT +FF41..FF5A ; ID # L& [26] FULLWIDTH LATIN SMALL LETTER A..FULLWIDTH LATIN SMALL LETTER Z +FF5C ; ID # Sm FULLWIDTH VERTICAL LINE +FF5E ; ID # Sm FULLWIDTH TILDE +FFE2 ; ID # Sm FULLWIDTH NOT SIGN +FFE3 ; ID # Sk FULLWIDTH MACRON +FFE4 ; ID # So FULLWIDTH BROKEN BAR +20000..2A6D6 ; ID # Lo [42711] CJK UNIFIED IDEOGRAPH-20000..CJK UNIFIED IDEOGRAPH-2A6D6 +2F800..2FA1D ; ID # Lo [542] CJK COMPATIBILITY IDEOGRAPH-2F800..CJK COMPATIBILITY IDEOGRAPH-2FA1D + +# Total code points: 84774 + +# ================================================ + +2024..2026 ; IN # Po [3] ONE DOT LEADER..HORIZONTAL ELLIPSIS + +# Total code points: 3 + +# ================================================ + +002D ; HY # Pd HYPHEN-MINUS + +# Total code points: 1 + +# ================================================ + +0000..0008 ; CM # Cc [9] .. +000B ; CM # Cc +000E..001F ; CM # Cc [18] .. +007F..009F ; CM # Cc [33] .. +0300..034E ; CM # Mn [79] COMBINING GRAVE ACCENT..COMBINING UPWARDS ARROW BELOW +0360..0362 ; CM # Mn [3] COMBINING DOUBLE TILDE..COMBINING DOUBLE RIGHTWARDS ARROW BELOW +0483..0486 ; CM # Mn [4] COMBINING CYRILLIC TITLO..COMBINING CYRILLIC PSILI PNEUMATA +0488..0489 ; CM # Me [2] COMBINING CYRILLIC HUNDRED THOUSANDS SIGN..COMBINING CYRILLIC MILLIONS SIGN +0591..05A1 ; CM # Mn [17] HEBREW ACCENT ETNAHTA..HEBREW ACCENT PAZER +05A3..05B9 ; CM # Mn [23] HEBREW ACCENT MUNAH..HEBREW POINT HOLAM +05BB..05BD ; CM # Mn [3] HEBREW POINT QUBUTS..HEBREW POINT METEG +05BF ; CM # Mn HEBREW POINT RAFE +05C1..05C2 ; CM # Mn [2] HEBREW POINT SHIN DOT..HEBREW POINT SIN DOT +05C4 ; CM # Mn HEBREW MARK UPPER DOT +064B..0655 ; CM # Mn [11] ARABIC FATHATAN..ARABIC HAMZA BELOW +0670 ; CM # Mn ARABIC LETTER SUPERSCRIPT ALEF +06D6..06DC ; CM # Mn [7] ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA..ARABIC SMALL HIGH SEEN +06DD..06DE ; CM # Me [2] ARABIC END OF AYAH..ARABIC START OF RUB EL HIZB +06DF..06E4 ; CM # Mn [6] ARABIC SMALL HIGH ROUNDED ZERO..ARABIC SMALL HIGH MADDA +06E7..06E8 ; CM # Mn [2] ARABIC SMALL HIGH YEH..ARABIC SMALL HIGH NOON +06EA..06ED ; CM # Mn [4] ARABIC EMPTY CENTRE LOW STOP..ARABIC SMALL LOW MEEM +070F ; CM # Cf SYRIAC ABBREVIATION MARK +0711 ; CM # Mn SYRIAC LETTER SUPERSCRIPT ALAPH +0730..074A ; CM # Mn [27] SYRIAC PTHAHA ABOVE..SYRIAC BARREKH +07A6..07B0 ; CM # Mn [11] THAANA ABAFILI..THAANA SUKUN +0901..0902 ; CM # Mn [2] DEVANAGARI SIGN CANDRABINDU..DEVANAGARI SIGN ANUSVARA +0903 ; CM # Mc DEVANAGARI SIGN VISARGA +093C ; CM # Mn DEVANAGARI SIGN NUKTA +093E..0940 ; CM # Mc [3] DEVANAGARI VOWEL SIGN AA..DEVANAGARI VOWEL SIGN II +0941..0948 ; CM # Mn [8] DEVANAGARI VOWEL SIGN U..DEVANAGARI VOWEL SIGN AI +0949..094C ; CM # Mc [4] DEVANAGARI VOWEL SIGN CANDRA O..DEVANAGARI VOWEL SIGN AU +094D ; CM # Mn DEVANAGARI SIGN VIRAMA +0951..0954 ; CM # Mn [4] DEVANAGARI STRESS SIGN UDATTA..DEVANAGARI ACUTE ACCENT +0962..0963 ; CM # Mn [2] DEVANAGARI VOWEL SIGN VOCALIC L..DEVANAGARI VOWEL SIGN VOCALIC LL +0981 ; CM # Mn BENGALI SIGN CANDRABINDU +0982..0983 ; CM # Mc [2] BENGALI SIGN ANUSVARA..BENGALI SIGN VISARGA +09BC ; CM # Mn BENGALI SIGN NUKTA +09BE..09C0 ; CM # Mc [3] BENGALI VOWEL SIGN AA..BENGALI VOWEL SIGN II +09C1..09C4 ; CM # Mn [4] BENGALI VOWEL SIGN U..BENGALI VOWEL SIGN VOCALIC RR +09C7..09C8 ; CM # Mc [2] BENGALI VOWEL SIGN E..BENGALI VOWEL SIGN AI +09CB..09CC ; CM # Mc [2] BENGALI VOWEL SIGN O..BENGALI VOWEL SIGN AU +09CD ; CM # Mn BENGALI SIGN VIRAMA +09D7 ; CM # Mc BENGALI AU LENGTH MARK +09E2..09E3 ; CM # Mn [2] BENGALI VOWEL SIGN VOCALIC L..BENGALI VOWEL SIGN VOCALIC LL +0A02 ; CM # Mn GURMUKHI SIGN BINDI +0A3C ; CM # Mn GURMUKHI SIGN NUKTA +0A3E..0A40 ; CM # Mc [3] GURMUKHI VOWEL SIGN AA..GURMUKHI VOWEL SIGN II +0A41..0A42 ; CM # Mn [2] GURMUKHI VOWEL SIGN U..GURMUKHI VOWEL SIGN UU +0A47..0A48 ; CM # Mn [2] GURMUKHI VOWEL SIGN EE..GURMUKHI VOWEL SIGN AI +0A4B..0A4D ; CM # Mn [3] GURMUKHI VOWEL SIGN OO..GURMUKHI SIGN VIRAMA +0A70..0A71 ; CM # Mn [2] GURMUKHI TIPPI..GURMUKHI ADDAK +0A81..0A82 ; CM # Mn [2] GUJARATI SIGN CANDRABINDU..GUJARATI SIGN ANUSVARA +0A83 ; CM # Mc GUJARATI SIGN VISARGA +0ABC ; CM # Mn GUJARATI SIGN NUKTA +0ABE..0AC0 ; CM # Mc [3] GUJARATI VOWEL SIGN AA..GUJARATI VOWEL SIGN II +0AC1..0AC5 ; CM # Mn [5] GUJARATI VOWEL SIGN U..GUJARATI VOWEL SIGN CANDRA E +0AC7..0AC8 ; CM # Mn [2] GUJARATI VOWEL SIGN E..GUJARATI VOWEL SIGN AI +0AC9 ; CM # Mc GUJARATI VOWEL SIGN CANDRA O +0ACB..0ACC ; CM # Mc [2] GUJARATI VOWEL SIGN O..GUJARATI VOWEL SIGN AU +0ACD ; CM # Mn GUJARATI SIGN VIRAMA +0B01 ; CM # Mn ORIYA SIGN CANDRABINDU +0B02..0B03 ; CM # Mc [2] ORIYA SIGN ANUSVARA..ORIYA SIGN VISARGA +0B3C ; CM # Mn ORIYA SIGN NUKTA +0B3E ; CM # Mc ORIYA VOWEL SIGN AA +0B3F ; CM # Mn ORIYA VOWEL SIGN I +0B40 ; CM # Mc ORIYA VOWEL SIGN II +0B41..0B43 ; CM # Mn [3] ORIYA VOWEL SIGN U..ORIYA VOWEL SIGN VOCALIC R +0B47..0B48 ; CM # Mc [2] ORIYA VOWEL SIGN E..ORIYA VOWEL SIGN AI +0B4B..0B4C ; CM # Mc [2] ORIYA VOWEL SIGN O..ORIYA VOWEL SIGN AU +0B4D ; CM # Mn ORIYA SIGN VIRAMA +0B56 ; CM # Mn ORIYA AI LENGTH MARK +0B57 ; CM # Mc ORIYA AU LENGTH MARK +0B82 ; CM # Mn TAMIL SIGN ANUSVARA +0B83 ; CM # Mc TAMIL SIGN VISARGA +0BBE..0BBF ; CM # Mc [2] TAMIL VOWEL SIGN AA..TAMIL VOWEL SIGN I +0BC0 ; CM # Mn TAMIL VOWEL SIGN II +0BC1..0BC2 ; CM # Mc [2] TAMIL VOWEL SIGN U..TAMIL VOWEL SIGN UU +0BC6..0BC8 ; CM # Mc [3] TAMIL VOWEL SIGN E..TAMIL VOWEL SIGN AI +0BCA..0BCC ; CM # Mc [3] TAMIL VOWEL SIGN O..TAMIL VOWEL SIGN AU +0BCD ; CM # Mn TAMIL SIGN VIRAMA +0BD7 ; CM # Mc TAMIL AU LENGTH MARK +0C01..0C03 ; CM # Mc [3] TELUGU SIGN CANDRABINDU..TELUGU SIGN VISARGA +0C3E..0C40 ; CM # Mn [3] TELUGU VOWEL SIGN AA..TELUGU VOWEL SIGN II +0C41..0C44 ; CM # Mc [4] TELUGU VOWEL SIGN U..TELUGU VOWEL SIGN VOCALIC RR +0C46..0C48 ; CM # Mn [3] TELUGU VOWEL SIGN E..TELUGU VOWEL SIGN AI +0C4A..0C4D ; CM # Mn [4] TELUGU VOWEL SIGN O..TELUGU SIGN VIRAMA +0C55..0C56 ; CM # Mn [2] TELUGU LENGTH MARK..TELUGU AI LENGTH MARK +0C82..0C83 ; CM # Mc [2] KANNADA SIGN ANUSVARA..KANNADA SIGN VISARGA +0CBE ; CM # Mc KANNADA VOWEL SIGN AA +0CBF ; CM # Mn KANNADA VOWEL SIGN I +0CC0..0CC4 ; CM # Mc [5] KANNADA VOWEL SIGN II..KANNADA VOWEL SIGN VOCALIC RR +0CC6 ; CM # Mn KANNADA VOWEL SIGN E +0CC7..0CC8 ; CM # Mc [2] KANNADA VOWEL SIGN EE..KANNADA VOWEL SIGN AI +0CCA..0CCB ; CM # Mc [2] KANNADA VOWEL SIGN O..KANNADA VOWEL SIGN OO +0CCC..0CCD ; CM # Mn [2] KANNADA VOWEL SIGN AU..KANNADA SIGN VIRAMA +0CD5..0CD6 ; CM # Mc [2] KANNADA LENGTH MARK..KANNADA AI LENGTH MARK +0D02..0D03 ; CM # Mc [2] MALAYALAM SIGN ANUSVARA..MALAYALAM SIGN VISARGA +0D3E..0D40 ; CM # Mc [3] MALAYALAM VOWEL SIGN AA..MALAYALAM VOWEL SIGN II +0D41..0D43 ; CM # Mn [3] MALAYALAM VOWEL SIGN U..MALAYALAM VOWEL SIGN VOCALIC R +0D46..0D48 ; CM # Mc [3] MALAYALAM VOWEL SIGN E..MALAYALAM VOWEL SIGN AI +0D4A..0D4C ; CM # Mc [3] MALAYALAM VOWEL SIGN O..MALAYALAM VOWEL SIGN AU +0D4D ; CM # Mn MALAYALAM SIGN VIRAMA +0D57 ; CM # Mc MALAYALAM AU LENGTH MARK +0D82..0D83 ; CM # Mc [2] SINHALA SIGN ANUSVARAYA..SINHALA SIGN VISARGAYA +0DCA ; CM # Mn SINHALA SIGN AL-LAKUNA +0DCF..0DD1 ; CM # Mc [3] SINHALA VOWEL SIGN AELA-PILLA..SINHALA VOWEL SIGN DIGA AEDA-PILLA +0DD2..0DD4 ; CM # Mn [3] SINHALA VOWEL SIGN KETTI IS-PILLA..SINHALA VOWEL SIGN KETTI PAA-PILLA +0DD6 ; CM # Mn SINHALA VOWEL SIGN DIGA PAA-PILLA +0DD8..0DDF ; CM # Mc [8] SINHALA VOWEL SIGN GAETTA-PILLA..SINHALA VOWEL SIGN GAYANUKITTA +0DF2..0DF3 ; CM # Mc [2] SINHALA VOWEL SIGN DIGA GAETTA-PILLA..SINHALA VOWEL SIGN DIGA GAYANUKITTA +0E31 ; CM # Mn THAI CHARACTER MAI HAN-AKAT +0E34..0E3A ; CM # Mn [7] THAI CHARACTER SARA I..THAI CHARACTER PHINTHU +0E47..0E4E ; CM # Mn [8] THAI CHARACTER MAITAIKHU..THAI CHARACTER YAMAKKAN +0EB1 ; CM # Mn LAO VOWEL SIGN MAI KAN +0EB4..0EB9 ; CM # Mn [6] LAO VOWEL SIGN I..LAO VOWEL SIGN UU +0EBB..0EBC ; CM # Mn [2] LAO VOWEL SIGN MAI KON..LAO SEMIVOWEL SIGN LO +0EC8..0ECD ; CM # Mn [6] LAO TONE MAI EK..LAO NIGGAHITA +0F18..0F19 ; CM # Mn [2] TIBETAN ASTROLOGICAL SIGN -KHYUD PA..TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS +0F35 ; CM # Mn TIBETAN MARK NGAS BZUNG NYI ZLA +0F37 ; CM # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS +0F39 ; CM # Mn TIBETAN MARK TSA -PHRU +0F3E..0F3F ; CM # Mc [2] TIBETAN SIGN YAR TSHES..TIBETAN SIGN MAR TSHES +0F71..0F7E ; CM # Mn [14] TIBETAN VOWEL SIGN AA..TIBETAN SIGN RJES SU NGA RO +0F7F ; CM # Mc TIBETAN SIGN RNAM BCAD +0F80..0F84 ; CM # Mn [5] TIBETAN VOWEL SIGN REVERSED I..TIBETAN MARK HALANTA +0F86..0F87 ; CM # Mn [2] TIBETAN SIGN LCI RTAGS..TIBETAN SIGN YANG RTAGS +0F90..0F97 ; CM # Mn [8] TIBETAN SUBJOINED LETTER KA..TIBETAN SUBJOINED LETTER JA +0F99..0FBC ; CM # Mn [36] TIBETAN SUBJOINED LETTER NYA..TIBETAN SUBJOINED LETTER FIXED-FORM RA +0FC6 ; CM # Mn TIBETAN SYMBOL PADMA GDAN +102C ; CM # Mc MYANMAR VOWEL SIGN AA +102D..1030 ; CM # Mn [4] MYANMAR VOWEL SIGN I..MYANMAR VOWEL SIGN UU +1031 ; CM # Mc MYANMAR VOWEL SIGN E +1032 ; CM # Mn MYANMAR VOWEL SIGN AI +1036..1037 ; CM # Mn [2] MYANMAR SIGN ANUSVARA..MYANMAR SIGN DOT BELOW +1038 ; CM # Mc MYANMAR SIGN VISARGA +1039 ; CM # Mn MYANMAR SIGN VIRAMA +1056..1057 ; CM # Mc [2] MYANMAR VOWEL SIGN VOCALIC R..MYANMAR VOWEL SIGN VOCALIC RR +1058..1059 ; CM # Mn [2] MYANMAR VOWEL SIGN VOCALIC L..MYANMAR VOWEL SIGN VOCALIC LL +1160..11A2 ; CM # Lo [67] HANGUL JUNGSEONG FILLER..HANGUL JUNGSEONG SSANGARAEA +11A8..11F9 ; CM # Lo [82] HANGUL JONGSEONG KIYEOK..HANGUL JONGSEONG YEORINHIEUH +17B4..17B6 ; CM # Mc [3] KHMER VOWEL INHERENT AQ..KHMER VOWEL SIGN AA +17B7..17BD ; CM # Mn [7] KHMER VOWEL SIGN I..KHMER VOWEL SIGN UA +17BE..17C5 ; CM # Mc [8] KHMER VOWEL SIGN OE..KHMER VOWEL SIGN AU +17C6 ; CM # Mn KHMER SIGN NIKAHIT +17C7..17C8 ; CM # Mc [2] KHMER SIGN REAHMUK..KHMER SIGN YUUKALEAPINTU +17C9..17D3 ; CM # Mn [11] KHMER SIGN MUUSIKATOAN..KHMER SIGN BATHAMASAT +180B..180E ; CM # Cf [4] MONGOLIAN FREE VARIATION SELECTOR ONE..MONGOLIAN VOWEL SEPARATOR +18A9 ; CM # Mn MONGOLIAN LETTER ALI GALI DAGALGA +200C..200F ; CM # Cf [4] ZERO WIDTH NON-JOINER..RIGHT-TO-LEFT MARK +202A..202E ; CM # Cf [5] LEFT-TO-RIGHT EMBEDDING..RIGHT-TO-LEFT OVERRIDE +206A..206F ; CM # Cf [6] INHIBIT SYMMETRIC SWAPPING..NOMINAL DIGIT SHAPES +20D0..20DC ; CM # Mn [13] COMBINING LEFT HARPOON ABOVE..COMBINING FOUR DOTS ABOVE +20DD..20E0 ; CM # Me [4] COMBINING ENCLOSING CIRCLE..COMBINING ENCLOSING CIRCLE BACKSLASH +20E1 ; CM # Mn COMBINING LEFT RIGHT ARROW ABOVE +20E2..20E3 ; CM # Me [2] COMBINING ENCLOSING SCREEN..COMBINING ENCLOSING KEYCAP +302A..302F ; CM # Mn [6] IDEOGRAPHIC LEVEL TONE MARK..HANGUL DOUBLE DOT TONE MARK +3099..309A ; CM # Mn [2] COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK..COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK +FB1E ; CM # Mn HEBREW POINT JUDEO-SPANISH VARIKA +FE20..FE23 ; CM # Mn [4] COMBINING LIGATURE LEFT HALF..COMBINING DOUBLE TILDE RIGHT HALF +FFF9..FFFB ; CM # Cf [3] INTERLINEAR ANNOTATION ANCHOR..INTERLINEAR ANNOTATION TERMINATOR +1D165..1D166 ; CM # Mc [2] MUSICAL SYMBOL COMBINING STEM..MUSICAL SYMBOL COMBINING SPRECHGESANG STEM +1D167..1D169 ; CM # Mn [3] MUSICAL SYMBOL COMBINING TREMOLO-1..MUSICAL SYMBOL COMBINING TREMOLO-3 +1D16D..1D172 ; CM # Mc [6] MUSICAL SYMBOL COMBINING AUGMENTATION DOT..MUSICAL SYMBOL COMBINING FLAG-5 +1D173..1D17A ; CM # Cf [8] MUSICAL SYMBOL BEGIN BEAM..MUSICAL SYMBOL END PHRASE +1D17B..1D182 ; CM # Mn [8] MUSICAL SYMBOL COMBINING ACCENT..MUSICAL SYMBOL COMBINING LOURE +1D185..1D18B ; CM # Mn [7] MUSICAL SYMBOL COMBINING DOIT..MUSICAL SYMBOL COMBINING TRIPLE TONGUE +1D1AA..1D1AD ; CM # Mn [4] MUSICAL SYMBOL COMBINING DOWN BOW..MUSICAL SYMBOL COMBINING SNAP PIZZICATO +E0001 ; CM # Cf LANGUAGE TAG +E0020..E007F ; CM # Cf [96] TAG SPACE..CANCEL TAG + +# Total code points: 943 + +# ================================================ + +00B4 ; BB # Sk ACUTE ACCENT +02C8 ; BB # Sk MODIFIER LETTER VERTICAL LINE +02CC ; BB # Sk MODIFIER LETTER LOW VERTICAL LINE +1806 ; BB # Pd MONGOLIAN TODO SOFT HYPHEN + +# Total code points: 4 + +# ================================================ + +0009 ; BA # Cc +007C ; BA # Sm VERTICAL LINE +00AD ; BA # Pd SOFT HYPHEN +058A ; BA # Pd ARMENIAN HYPHEN +0F0B ; BA # Po TIBETAN MARK INTERSYLLABIC TSHEG +1361 ; BA # Po ETHIOPIC WORDSPACE +1680 ; BA # Zs OGHAM SPACE MARK +17D5 ; BA # Po KHMER SIGN BARIYOOSAN +2000..2006 ; BA # Zs [7] EN QUAD..SIX-PER-EM SPACE +2008..200A ; BA # Zs [3] PUNCTUATION SPACE..HAIR SPACE +2010 ; BA # Pd HYPHEN +2012..2013 ; BA # Pd [2] FIGURE DASH..EN DASH +2027 ; BA # Po HYPHENATION POINT + +# Total code points: 22 + +# ================================================ + +0020 ; SP # Zs SPACE + +# Total code points: 1 + +# ================================================ + +000C ; BK # Cc +2028 ; BK # Zl LINE SEPARATOR +2029 ; BK # Zp PARAGRAPH SEPARATOR + +# Total code points: 3 + +# ================================================ + +000D ; CR # Cc + +# Total code points: 1 + +# ================================================ + +000A ; LF # Cc + +# Total code points: 1 + +# ================================================ + +FFFC ; CB # So OBJECT REPLACEMENT CHARACTER + +# Total code points: 1 + +# ================================================ + +0E01..0E30 ; SA # Lo [48] THAI CHARACTER KO KAI..THAI CHARACTER SARA A +0E32..0E33 ; SA # Lo [2] THAI CHARACTER SARA AA..THAI CHARACTER SARA AM +0E40..0E45 ; SA # Lo [6] THAI CHARACTER SARA E..THAI CHARACTER LAKKHANGYAO +0E46 ; SA # Lm THAI CHARACTER MAIYAMOK +0E81..0E82 ; SA # Lo [2] LAO LETTER KO..LAO LETTER KHO SUNG +0E84 ; SA # Lo LAO LETTER KHO TAM +0E87..0E88 ; SA # Lo [2] LAO LETTER NGO..LAO LETTER CO +0E8A ; SA # Lo LAO LETTER SO TAM +0E8D ; SA # Lo LAO LETTER NYO +0E94..0E97 ; SA # Lo [4] LAO LETTER DO..LAO LETTER THO TAM +0E99..0E9F ; SA # Lo [7] LAO LETTER NO..LAO LETTER FO SUNG +0EA1..0EA3 ; SA # Lo [3] LAO LETTER MO..LAO LETTER LO LING +0EA5 ; SA # Lo LAO LETTER LO LOOT +0EA7 ; SA # Lo LAO LETTER WO +0EAA..0EAB ; SA # Lo [2] LAO LETTER SO SUNG..LAO LETTER HO SUNG +0EAD..0EB0 ; SA # Lo [4] LAO LETTER O..LAO VOWEL SIGN A +0EB2..0EB3 ; SA # Lo [2] LAO VOWEL SIGN AA..LAO VOWEL SIGN AM +0EBD ; SA # Lo LAO SEMIVOWEL SIGN NYO +0EC0..0EC4 ; SA # Lo [5] LAO VOWEL SIGN E..LAO VOWEL SIGN AI +0EC6 ; SA # Lm LAO KO LA +0EDC..0EDD ; SA # Lo [2] LAO HO NO..LAO HO MO +1000..1021 ; SA # Lo [34] MYANMAR LETTER KA..MYANMAR LETTER A +1023..1027 ; SA # Lo [5] MYANMAR LETTER I..MYANMAR LETTER E +1029..102A ; SA # Lo [2] MYANMAR LETTER O..MYANMAR LETTER AU +1050..1055 ; SA # Lo [6] MYANMAR LETTER SHA..MYANMAR LETTER VOCALIC LL +1780..17B3 ; SA # Lo [52] KHMER LETTER KA..KHMER INDEPENDENT VOWEL QAU + +# Total code points: 196 + +# ================================================ + +00A1 ; AI # Po INVERTED EXCLAMATION MARK +00A7 ; AI # So SECTION SIGN +00A8 ; AI # Sk DIAERESIS +00AA ; AI # L& FEMININE ORDINAL INDICATOR +00B2..00B3 ; AI # No [2] SUPERSCRIPT TWO..SUPERSCRIPT THREE +00B6 ; AI # So PILCROW SIGN +00B7 ; AI # Po MIDDLE DOT +00B8 ; AI # Sk CEDILLA +00B9 ; AI # No SUPERSCRIPT ONE +00BA ; AI # L& MASCULINE ORDINAL INDICATOR +00BC..00BE ; AI # No [3] VULGAR FRACTION ONE QUARTER..VULGAR FRACTION THREE QUARTERS +00BF ; AI # Po INVERTED QUESTION MARK +00C6 ; AI # L& LATIN CAPITAL LETTER AE +00D0 ; AI # L& LATIN CAPITAL LETTER ETH +00D7 ; AI # Sm MULTIPLICATION SIGN +00D8 ; AI # L& LATIN CAPITAL LETTER O WITH STROKE +00DE..00E1 ; AI # L& [4] LATIN CAPITAL LETTER THORN..LATIN SMALL LETTER A WITH ACUTE +00E6 ; AI # L& LATIN SMALL LETTER AE +00E8..00EA ; AI # L& [3] LATIN SMALL LETTER E WITH GRAVE..LATIN SMALL LETTER E WITH CIRCUMFLEX +00EC..00ED ; AI # L& [2] LATIN SMALL LETTER I WITH GRAVE..LATIN SMALL LETTER I WITH ACUTE +00F0 ; AI # L& LATIN SMALL LETTER ETH +00F2..00F3 ; AI # L& [2] LATIN SMALL LETTER O WITH GRAVE..LATIN SMALL LETTER O WITH ACUTE +00F7 ; AI # Sm DIVISION SIGN +00F8..00FA ; AI # L& [3] LATIN SMALL LETTER O WITH STROKE..LATIN SMALL LETTER U WITH ACUTE +00FC ; AI # L& LATIN SMALL LETTER U WITH DIAERESIS +00FE ; AI # L& LATIN SMALL LETTER THORN +0101 ; AI # L& LATIN SMALL LETTER A WITH MACRON +0111 ; AI # L& LATIN SMALL LETTER D WITH STROKE +0113 ; AI # L& LATIN SMALL LETTER E WITH MACRON +011B ; AI # L& LATIN SMALL LETTER E WITH CARON +0126..0127 ; AI # L& [2] LATIN CAPITAL LETTER H WITH STROKE..LATIN SMALL LETTER H WITH STROKE +012B ; AI # L& LATIN SMALL LETTER I WITH MACRON +0131..0133 ; AI # L& [3] LATIN SMALL LETTER DOTLESS I..LATIN SMALL LIGATURE IJ +0138 ; AI # L& LATIN SMALL LETTER KRA +013F..0142 ; AI # L& [4] LATIN CAPITAL LETTER L WITH MIDDLE DOT..LATIN SMALL LETTER L WITH STROKE +0144 ; AI # L& LATIN SMALL LETTER N WITH ACUTE +0148..014A ; AI # L& [3] LATIN SMALL LETTER N WITH CARON..LATIN CAPITAL LETTER ENG +014D ; AI # L& LATIN SMALL LETTER O WITH MACRON +0152..0153 ; AI # L& [2] LATIN CAPITAL LIGATURE OE..LATIN SMALL LIGATURE OE +0166..0167 ; AI # L& [2] LATIN CAPITAL LETTER T WITH STROKE..LATIN SMALL LETTER T WITH STROKE +016B ; AI # L& LATIN SMALL LETTER U WITH MACRON +01CE ; AI # L& LATIN SMALL LETTER A WITH CARON +01D0 ; AI # L& LATIN SMALL LETTER I WITH CARON +01D2 ; AI # L& LATIN SMALL LETTER O WITH CARON +01D4 ; AI # L& LATIN SMALL LETTER U WITH CARON +01D6 ; AI # L& LATIN SMALL LETTER U WITH DIAERESIS AND MACRON +01D8 ; AI # L& LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE +01DA ; AI # L& LATIN SMALL LETTER U WITH DIAERESIS AND CARON +01DC ; AI # L& LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE +0251 ; AI # L& LATIN SMALL LETTER ALPHA +0261 ; AI # L& LATIN SMALL LETTER SCRIPT G +02C7 ; AI # Sk CARON +02C9..02CB ; AI # Sk [3] MODIFIER LETTER MACRON..MODIFIER LETTER GRAVE ACCENT +02CD ; AI # Sk MODIFIER LETTER LOW MACRON +02D0 ; AI # Lm MODIFIER LETTER TRIANGULAR COLON +02D8..02DB ; AI # Sk [4] BREVE..OGONEK +02DD ; AI # Sk DOUBLE ACUTE ACCENT +0391..03A1 ; AI # L& [17] GREEK CAPITAL LETTER ALPHA..GREEK CAPITAL LETTER RHO +03A3..03A9 ; AI # L& [7] GREEK CAPITAL LETTER SIGMA..GREEK CAPITAL LETTER OMEGA +03B1..03C1 ; AI # L& [17] GREEK SMALL LETTER ALPHA..GREEK SMALL LETTER RHO +03C3..03C9 ; AI # L& [7] GREEK SMALL LETTER SIGMA..GREEK SMALL LETTER OMEGA +0401 ; AI # L& CYRILLIC CAPITAL LETTER IO +0410..044F ; AI # L& [64] CYRILLIC CAPITAL LETTER A..CYRILLIC SMALL LETTER YA +0451 ; AI # L& CYRILLIC SMALL LETTER IO +2015 ; AI # Pd HORIZONTAL BAR +2016 ; AI # Po DOUBLE VERTICAL LINE +2020..2021 ; AI # Po [2] DAGGER..DOUBLE DAGGER +203B ; AI # Po REFERENCE MARK +2074 ; AI # No SUPERSCRIPT FOUR +207F ; AI # L& SUPERSCRIPT LATIN SMALL LETTER N +2081..2084 ; AI # No [4] SUBSCRIPT ONE..SUBSCRIPT FOUR +2105 ; AI # So CARE OF +2113 ; AI # L& SCRIPT SMALL L +2121..2122 ; AI # So [2] TELEPHONE SIGN..TRADE MARK SIGN +212B ; AI # L& ANGSTROM SIGN +2154..2155 ; AI # No [2] VULGAR FRACTION TWO THIRDS..VULGAR FRACTION ONE FIFTH +215B ; AI # No VULGAR FRACTION ONE EIGHTH +215E ; AI # No VULGAR FRACTION SEVEN EIGHTHS +2160..216B ; AI # Nl [12] ROMAN NUMERAL ONE..ROMAN NUMERAL TWELVE +2170..2179 ; AI # Nl [10] SMALL ROMAN NUMERAL ONE..SMALL ROMAN NUMERAL TEN +2190..2194 ; AI # Sm [5] LEFTWARDS ARROW..LEFT RIGHT ARROW +2195..2199 ; AI # So [5] UP DOWN ARROW..SOUTH WEST ARROW +21D2 ; AI # Sm RIGHTWARDS DOUBLE ARROW +21D4 ; AI # Sm LEFT RIGHT DOUBLE ARROW +2200 ; AI # Sm FOR ALL +2202..2203 ; AI # Sm [2] PARTIAL DIFFERENTIAL..THERE EXISTS +2207..2208 ; AI # Sm [2] NABLA..ELEMENT OF +220B ; AI # Sm CONTAINS AS MEMBER +220F ; AI # Sm N-ARY PRODUCT +2211 ; AI # Sm N-ARY SUMMATION +2215 ; AI # Sm DIVISION SLASH +221A ; AI # Sm SQUARE ROOT +221D..2220 ; AI # Sm [4] PROPORTIONAL TO..ANGLE +2223 ; AI # Sm DIVIDES +2225 ; AI # Sm PARALLEL TO +2227..222C ; AI # Sm [6] LOGICAL AND..DOUBLE INTEGRAL +222E ; AI # Sm CONTOUR INTEGRAL +2234..2237 ; AI # Sm [4] THEREFORE..PROPORTION +223C..223D ; AI # Sm [2] TILDE OPERATOR..REVERSED TILDE +2248 ; AI # Sm ALMOST EQUAL TO +224C ; AI # Sm ALL EQUAL TO +2252 ; AI # Sm APPROXIMATELY EQUAL TO OR THE IMAGE OF +2260..2261 ; AI # Sm [2] NOT EQUAL TO..IDENTICAL TO +2264..2267 ; AI # Sm [4] LESS-THAN OR EQUAL TO..GREATER-THAN OVER EQUAL TO +226A..226B ; AI # Sm [2] MUCH LESS-THAN..MUCH GREATER-THAN +226E..226F ; AI # Sm [2] NOT LESS-THAN..NOT GREATER-THAN +2282..2283 ; AI # Sm [2] SUBSET OF..SUPERSET OF +2286..2287 ; AI # Sm [2] SUBSET OF OR EQUAL TO..SUPERSET OF OR EQUAL TO +2295 ; AI # Sm CIRCLED PLUS +2299 ; AI # Sm CIRCLED DOT OPERATOR +22A5 ; AI # Sm UP TACK +22BF ; AI # Sm RIGHT TRIANGLE +2312 ; AI # So ARC +2460..249B ; AI # No [60] CIRCLED DIGIT ONE..NUMBER TWENTY FULL STOP +249C..24BF ; AI # So [36] PARENTHESIZED LATIN SMALL LETTER A..CIRCLED LATIN CAPITAL LETTER J +24D0..24E9 ; AI # So [26] CIRCLED LATIN SMALL LETTER A..CIRCLED LATIN SMALL LETTER Z +2500..254B ; AI # So [76] BOX DRAWINGS LIGHT HORIZONTAL..BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL +2550..2574 ; AI # So [37] BOX DRAWINGS DOUBLE HORIZONTAL..BOX DRAWINGS LIGHT LEFT +2580..258F ; AI # So [16] UPPER HALF BLOCK..LEFT ONE EIGHTH BLOCK +2592..2595 ; AI # So [4] MEDIUM SHADE..RIGHT ONE EIGHTH BLOCK +25A0..25A1 ; AI # So [2] BLACK SQUARE..WHITE SQUARE +25A3..25A9 ; AI # So [7] WHITE SQUARE CONTAINING BLACK SMALL SQUARE..SQUARE WITH DIAGONAL CROSSHATCH FILL +25B2..25B3 ; AI # So [2] BLACK UP-POINTING TRIANGLE..WHITE UP-POINTING TRIANGLE +25B6 ; AI # So BLACK RIGHT-POINTING TRIANGLE +25B7 ; AI # Sm WHITE RIGHT-POINTING TRIANGLE +25BC..25BD ; AI # So [2] BLACK DOWN-POINTING TRIANGLE..WHITE DOWN-POINTING TRIANGLE +25C0 ; AI # So BLACK LEFT-POINTING TRIANGLE +25C1 ; AI # Sm WHITE LEFT-POINTING TRIANGLE +25C6..25C8 ; AI # So [3] BLACK DIAMOND..WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND +25CB ; AI # So WHITE CIRCLE +25CE..25D1 ; AI # So [4] BULLSEYE..CIRCLE WITH RIGHT HALF BLACK +25E2..25E5 ; AI # So [4] BLACK LOWER RIGHT TRIANGLE..BLACK UPPER RIGHT TRIANGLE +25EF ; AI # So LARGE CIRCLE +2605..2606 ; AI # So [2] BLACK STAR..WHITE STAR +2609 ; AI # So SUN +260E..260F ; AI # So [2] BLACK TELEPHONE..WHITE TELEPHONE +261C ; AI # So WHITE LEFT POINTING INDEX +261E ; AI # So WHITE RIGHT POINTING INDEX +2640 ; AI # So FEMALE SIGN +2642 ; AI # So MALE SIGN +2660..2661 ; AI # So [2] BLACK SPADE SUIT..WHITE HEART SUIT +2663..2665 ; AI # So [3] BLACK CLUB SUIT..BLACK HEART SUIT +2667..266A ; AI # So [4] WHITE CLUB SUIT..EIGHTH NOTE +266C..266D ; AI # So [2] BEAMED SIXTEENTH NOTES..MUSIC FLAT SIGN +266F ; AI # Sm MUSIC SHARP SIGN +FFFD ; AI # So REPLACEMENT CHARACTER + +# Total code points: 610 + +# ================================================ + +2014 ; B2 # Pd EM DASH + +# Total code points: 1 + +# ================================================ + +D800..DFFF ; SG # Cs [2048] + +# Total code points: 2048 + +# ================================================ + +200B ; ZW # Zs ZERO WIDTH SPACE + +# Total code points: 1 + + + + \ No newline at end of file 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-1250.txt b/data/windows-1250.txt new file mode 100644 index 000000000..081d7763b --- /dev/null +++ b/data/windows-1250.txt @@ -0,0 +1,274 @@ +# +# Name: cp1250 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1250 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1250 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 #UNDEFINED +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 #UNDEFINED +0x89 0x2030 #PER MILLE SIGN +0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x015A #LATIN CAPITAL LETTER S WITH ACUTE +0x8D 0x0164 #LATIN CAPITAL LETTER T WITH CARON +0x8E 0x017D #LATIN CAPITAL LETTER Z WITH CARON +0x8F 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 #UNDEFINED +0x99 0x2122 #TRADE MARK SIGN +0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x015B #LATIN SMALL LETTER S WITH ACUTE +0x9D 0x0165 #LATIN SMALL LETTER T WITH CARON +0x9E 0x017E #LATIN SMALL LETTER Z WITH CARON +0x9F 0x017A #LATIN SMALL LETTER Z WITH ACUTE +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x02C7 #CARON +0xA2 0x02D8 #BREVE +0xA3 0x0141 #LATIN CAPITAL LETTER L WITH STROKE +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x015E #LATIN CAPITAL LETTER S WITH CEDILLA +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x017B #LATIN CAPITAL LETTER Z WITH DOT ABOVE +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x02DB #OGONEK +0xB3 0x0142 #LATIN SMALL LETTER L WITH STROKE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x0105 #LATIN SMALL LETTER A WITH OGONEK +0xBA 0x015F #LATIN SMALL LETTER S WITH CEDILLA +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x013D #LATIN CAPITAL LETTER L WITH CARON +0xBD 0x02DD #DOUBLE ACUTE ACCENT +0xBE 0x013E #LATIN SMALL LETTER L WITH CARON +0xBF 0x017C #LATIN SMALL LETTER Z WITH DOT ABOVE +0xC0 0x0154 #LATIN CAPITAL LETTER R WITH ACUTE +0xC1 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x0102 #LATIN CAPITAL LETTER A WITH BREVE +0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x0139 #LATIN CAPITAL LETTER L WITH ACUTE +0xC6 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE +0xC7 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x010C #LATIN CAPITAL LETTER C WITH CARON +0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK +0xCB 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x011A #LATIN CAPITAL LETTER E WITH CARON +0xCD 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x010E #LATIN CAPITAL LETTER D WITH CARON +0xD0 0x0110 #LATIN CAPITAL LETTER D WITH STROKE +0xD1 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE +0xD2 0x0147 #LATIN CAPITAL LETTER N WITH CARON +0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x0150 #LATIN CAPITAL LETTER O WITH DOUBLE ACUTE +0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x0158 #LATIN CAPITAL LETTER R WITH CARON +0xD9 0x016E #LATIN CAPITAL LETTER U WITH RING ABOVE +0xDA 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x0170 #LATIN CAPITAL LETTER U WITH DOUBLE ACUTE +0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x00DD #LATIN CAPITAL LETTER Y WITH ACUTE +0xDE 0x0162 #LATIN CAPITAL LETTER T WITH CEDILLA +0xDF 0x00DF #LATIN SMALL LETTER SHARP S +0xE0 0x0155 #LATIN SMALL LETTER R WITH ACUTE +0xE1 0x00E1 #LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x0103 #LATIN SMALL LETTER A WITH BREVE +0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x013A #LATIN SMALL LETTER L WITH ACUTE +0xE6 0x0107 #LATIN SMALL LETTER C WITH ACUTE +0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x010D #LATIN SMALL LETTER C WITH CARON +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x0119 #LATIN SMALL LETTER E WITH OGONEK +0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x011B #LATIN SMALL LETTER E WITH CARON +0xED 0x00ED #LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x010F #LATIN SMALL LETTER D WITH CARON +0xF0 0x0111 #LATIN SMALL LETTER D WITH STROKE +0xF1 0x0144 #LATIN SMALL LETTER N WITH ACUTE +0xF2 0x0148 #LATIN SMALL LETTER N WITH CARON +0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x0151 #LATIN SMALL LETTER O WITH DOUBLE ACUTE +0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x0159 #LATIN SMALL LETTER R WITH CARON +0xF9 0x016F #LATIN SMALL LETTER U WITH RING ABOVE +0xFA 0x00FA #LATIN SMALL LETTER U WITH ACUTE +0xFB 0x0171 #LATIN SMALL LETTER U WITH DOUBLE ACUTE +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x00FD #LATIN SMALL LETTER Y WITH ACUTE +0xFE 0x0163 #LATIN SMALL LETTER T WITH CEDILLA +0xFF 0x02D9 #DOT ABOVE 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-1251.txt b/data/windows-1251.txt new file mode 100644 index 000000000..37eadbdbc --- /dev/null +++ b/data/windows-1251.txt @@ -0,0 +1,274 @@ +# +# Name: cp1251 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1251 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1251 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x0402 #CYRILLIC CAPITAL LETTER DJE +0x81 0x0403 #CYRILLIC CAPITAL LETTER GJE +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0453 #CYRILLIC SMALL LETTER GJE +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x20AC #EURO SIGN +0x89 0x2030 #PER MILLE SIGN +0x8A 0x0409 #CYRILLIC CAPITAL LETTER LJE +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x040A #CYRILLIC CAPITAL LETTER NJE +0x8D 0x040C #CYRILLIC CAPITAL LETTER KJE +0x8E 0x040B #CYRILLIC CAPITAL LETTER TSHE +0x8F 0x040F #CYRILLIC CAPITAL LETTER DZHE +0x90 0x0452 #CYRILLIC SMALL LETTER DJE +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 #UNDEFINED +0x99 0x2122 #TRADE MARK SIGN +0x9A 0x0459 #CYRILLIC SMALL LETTER LJE +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x045A #CYRILLIC SMALL LETTER NJE +0x9D 0x045C #CYRILLIC SMALL LETTER KJE +0x9E 0x045B #CYRILLIC SMALL LETTER TSHE +0x9F 0x045F #CYRILLIC SMALL LETTER DZHE +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x040E #CYRILLIC CAPITAL LETTER SHORT U +0xA2 0x045E #CYRILLIC SMALL LETTER SHORT U +0xA3 0x0408 #CYRILLIC CAPITAL LETTER JE +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x0490 #CYRILLIC CAPITAL LETTER GHE WITH UPTURN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x0401 #CYRILLIC CAPITAL LETTER IO +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x0404 #CYRILLIC CAPITAL LETTER UKRAINIAN IE +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x0407 #CYRILLIC CAPITAL LETTER YI +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x0406 #CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I +0xB3 0x0456 #CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I +0xB4 0x0491 #CYRILLIC SMALL LETTER GHE WITH UPTURN +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x0451 #CYRILLIC SMALL LETTER IO +0xB9 0x2116 #NUMERO SIGN +0xBA 0x0454 #CYRILLIC SMALL LETTER UKRAINIAN IE +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x0458 #CYRILLIC SMALL LETTER JE +0xBD 0x0405 #CYRILLIC CAPITAL LETTER DZE +0xBE 0x0455 #CYRILLIC SMALL LETTER DZE +0xBF 0x0457 #CYRILLIC SMALL LETTER YI +0xC0 0x0410 #CYRILLIC CAPITAL LETTER A +0xC1 0x0411 #CYRILLIC CAPITAL LETTER BE +0xC2 0x0412 #CYRILLIC CAPITAL LETTER VE +0xC3 0x0413 #CYRILLIC CAPITAL LETTER GHE +0xC4 0x0414 #CYRILLIC CAPITAL LETTER DE +0xC5 0x0415 #CYRILLIC CAPITAL LETTER IE +0xC6 0x0416 #CYRILLIC CAPITAL LETTER ZHE +0xC7 0x0417 #CYRILLIC CAPITAL LETTER ZE +0xC8 0x0418 #CYRILLIC CAPITAL LETTER I +0xC9 0x0419 #CYRILLIC CAPITAL LETTER SHORT I +0xCA 0x041A #CYRILLIC CAPITAL LETTER KA +0xCB 0x041B #CYRILLIC CAPITAL LETTER EL +0xCC 0x041C #CYRILLIC CAPITAL LETTER EM +0xCD 0x041D #CYRILLIC CAPITAL LETTER EN +0xCE 0x041E #CYRILLIC CAPITAL LETTER O +0xCF 0x041F #CYRILLIC CAPITAL LETTER PE +0xD0 0x0420 #CYRILLIC CAPITAL LETTER ER +0xD1 0x0421 #CYRILLIC CAPITAL LETTER ES +0xD2 0x0422 #CYRILLIC CAPITAL LETTER TE +0xD3 0x0423 #CYRILLIC CAPITAL LETTER U +0xD4 0x0424 #CYRILLIC CAPITAL LETTER EF +0xD5 0x0425 #CYRILLIC CAPITAL LETTER HA +0xD6 0x0426 #CYRILLIC CAPITAL LETTER TSE +0xD7 0x0427 #CYRILLIC CAPITAL LETTER CHE +0xD8 0x0428 #CYRILLIC CAPITAL LETTER SHA +0xD9 0x0429 #CYRILLIC CAPITAL LETTER SHCHA +0xDA 0x042A #CYRILLIC CAPITAL LETTER HARD SIGN +0xDB 0x042B #CYRILLIC CAPITAL LETTER YERU +0xDC 0x042C #CYRILLIC CAPITAL LETTER SOFT SIGN +0xDD 0x042D #CYRILLIC CAPITAL LETTER E +0xDE 0x042E #CYRILLIC CAPITAL LETTER YU +0xDF 0x042F #CYRILLIC CAPITAL LETTER YA +0xE0 0x0430 #CYRILLIC SMALL LETTER A +0xE1 0x0431 #CYRILLIC SMALL LETTER BE +0xE2 0x0432 #CYRILLIC SMALL LETTER VE +0xE3 0x0433 #CYRILLIC SMALL LETTER GHE +0xE4 0x0434 #CYRILLIC SMALL LETTER DE +0xE5 0x0435 #CYRILLIC SMALL LETTER IE +0xE6 0x0436 #CYRILLIC SMALL LETTER ZHE +0xE7 0x0437 #CYRILLIC SMALL LETTER ZE +0xE8 0x0438 #CYRILLIC SMALL LETTER I +0xE9 0x0439 #CYRILLIC SMALL LETTER SHORT I +0xEA 0x043A #CYRILLIC SMALL LETTER KA +0xEB 0x043B #CYRILLIC SMALL LETTER EL +0xEC 0x043C #CYRILLIC SMALL LETTER EM +0xED 0x043D #CYRILLIC SMALL LETTER EN +0xEE 0x043E #CYRILLIC SMALL LETTER O +0xEF 0x043F #CYRILLIC SMALL LETTER PE +0xF0 0x0440 #CYRILLIC SMALL LETTER ER +0xF1 0x0441 #CYRILLIC SMALL LETTER ES +0xF2 0x0442 #CYRILLIC SMALL LETTER TE +0xF3 0x0443 #CYRILLIC SMALL LETTER U +0xF4 0x0444 #CYRILLIC SMALL LETTER EF +0xF5 0x0445 #CYRILLIC SMALL LETTER HA +0xF6 0x0446 #CYRILLIC SMALL LETTER TSE +0xF7 0x0447 #CYRILLIC SMALL LETTER CHE +0xF8 0x0448 #CYRILLIC SMALL LETTER SHA +0xF9 0x0449 #CYRILLIC SMALL LETTER SHCHA +0xFA 0x044A #CYRILLIC SMALL LETTER HARD SIGN +0xFB 0x044B #CYRILLIC SMALL LETTER YERU +0xFC 0x044C #CYRILLIC SMALL LETTER SOFT SIGN +0xFD 0x044D #CYRILLIC SMALL LETTER E +0xFE 0x044E #CYRILLIC SMALL LETTER YU +0xFF 0x044F #CYRILLIC SMALL LETTER YA 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-1252.txt b/data/windows-1252.txt new file mode 100644 index 000000000..2ca4486eb --- /dev/null +++ b/data/windows-1252.txt @@ -0,0 +1,274 @@ +# +# Name: cp1252 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1252 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1252 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x0152 #LATIN CAPITAL LIGATURE OE +0x8D #UNDEFINED +0x8E 0x017D #LATIN CAPITAL LETTER Z WITH CARON +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x02DC #SMALL TILDE +0x99 0x2122 #TRADE MARK SIGN +0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x0153 #LATIN SMALL LIGATURE OE +0x9D #UNDEFINED +0x9E 0x017E #LATIN SMALL LETTER Z WITH CARON +0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x00A1 #INVERTED EXCLAMATION MARK +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x00AA #FEMININE ORDINAL INDICATOR +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x00BA #MASCULINE ORDINAL INDICATOR +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF #INVERTED QUESTION MARK +0xC0 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 #LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 #LATIN CAPITAL LETTER AE +0xC7 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC #LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x00D0 #LATIN CAPITAL LETTER ETH +0xD1 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x00D2 #LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 #LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x00DD #LATIN CAPITAL LETTER Y WITH ACUTE +0xDE 0x00DE #LATIN CAPITAL LETTER THORN +0xDF 0x00DF #LATIN SMALL LETTER SHARP S +0xE0 0x00E0 #LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 #LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 #LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 #LATIN SMALL LETTER AE +0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 #LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC #LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED #LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x00F0 #LATIN SMALL LETTER ETH +0xF1 0x00F1 #LATIN SMALL LETTER N WITH TILDE +0xF2 0x00F2 #LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 #LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x00F8 #LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 #LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA #LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x00FD #LATIN SMALL LETTER Y WITH ACUTE +0xFE 0x00FE #LATIN SMALL LETTER THORN +0xFF 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS 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-1253.txt b/data/windows-1253.txt new file mode 100644 index 000000000..2ba51a0c8 --- /dev/null +++ b/data/windows-1253.txt @@ -0,0 +1,274 @@ +# +# Name: cp1253 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1253 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1253 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 #UNDEFINED +0x89 0x2030 #PER MILLE SIGN +0x8A #UNDEFINED +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C #UNDEFINED +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 #UNDEFINED +0x99 0x2122 #TRADE MARK SIGN +0x9A #UNDEFINED +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C #UNDEFINED +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F #UNDEFINED +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x0385 #GREEK DIALYTIKA TONOS +0xA2 0x0386 #GREEK CAPITAL LETTER ALPHA WITH TONOS +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA #UNDEFINED +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x2015 #HORIZONTAL BAR +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x0384 #GREEK TONOS +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x0388 #GREEK CAPITAL LETTER EPSILON WITH TONOS +0xB9 0x0389 #GREEK CAPITAL LETTER ETA WITH TONOS +0xBA 0x038A #GREEK CAPITAL LETTER IOTA WITH TONOS +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x038C #GREEK CAPITAL LETTER OMICRON WITH TONOS +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x038E #GREEK CAPITAL LETTER UPSILON WITH TONOS +0xBF 0x038F #GREEK CAPITAL LETTER OMEGA WITH TONOS +0xC0 0x0390 #GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS +0xC1 0x0391 #GREEK CAPITAL LETTER ALPHA +0xC2 0x0392 #GREEK CAPITAL LETTER BETA +0xC3 0x0393 #GREEK CAPITAL LETTER GAMMA +0xC4 0x0394 #GREEK CAPITAL LETTER DELTA +0xC5 0x0395 #GREEK CAPITAL LETTER EPSILON +0xC6 0x0396 #GREEK CAPITAL LETTER ZETA +0xC7 0x0397 #GREEK CAPITAL LETTER ETA +0xC8 0x0398 #GREEK CAPITAL LETTER THETA +0xC9 0x0399 #GREEK CAPITAL LETTER IOTA +0xCA 0x039A #GREEK CAPITAL LETTER KAPPA +0xCB 0x039B #GREEK CAPITAL LETTER LAMDA +0xCC 0x039C #GREEK CAPITAL LETTER MU +0xCD 0x039D #GREEK CAPITAL LETTER NU +0xCE 0x039E #GREEK CAPITAL LETTER XI +0xCF 0x039F #GREEK CAPITAL LETTER OMICRON +0xD0 0x03A0 #GREEK CAPITAL LETTER PI +0xD1 0x03A1 #GREEK CAPITAL LETTER RHO +0xD2 #UNDEFINED +0xD3 0x03A3 #GREEK CAPITAL LETTER SIGMA +0xD4 0x03A4 #GREEK CAPITAL LETTER TAU +0xD5 0x03A5 #GREEK CAPITAL LETTER UPSILON +0xD6 0x03A6 #GREEK CAPITAL LETTER PHI +0xD7 0x03A7 #GREEK CAPITAL LETTER CHI +0xD8 0x03A8 #GREEK CAPITAL LETTER PSI +0xD9 0x03A9 #GREEK CAPITAL LETTER OMEGA +0xDA 0x03AA #GREEK CAPITAL LETTER IOTA WITH DIALYTIKA +0xDB 0x03AB #GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA +0xDC 0x03AC #GREEK SMALL LETTER ALPHA WITH TONOS +0xDD 0x03AD #GREEK SMALL LETTER EPSILON WITH TONOS +0xDE 0x03AE #GREEK SMALL LETTER ETA WITH TONOS +0xDF 0x03AF #GREEK SMALL LETTER IOTA WITH TONOS +0xE0 0x03B0 #GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS +0xE1 0x03B1 #GREEK SMALL LETTER ALPHA +0xE2 0x03B2 #GREEK SMALL LETTER BETA +0xE3 0x03B3 #GREEK SMALL LETTER GAMMA +0xE4 0x03B4 #GREEK SMALL LETTER DELTA +0xE5 0x03B5 #GREEK SMALL LETTER EPSILON +0xE6 0x03B6 #GREEK SMALL LETTER ZETA +0xE7 0x03B7 #GREEK SMALL LETTER ETA +0xE8 0x03B8 #GREEK SMALL LETTER THETA +0xE9 0x03B9 #GREEK SMALL LETTER IOTA +0xEA 0x03BA #GREEK SMALL LETTER KAPPA +0xEB 0x03BB #GREEK SMALL LETTER LAMDA +0xEC 0x03BC #GREEK SMALL LETTER MU +0xED 0x03BD #GREEK SMALL LETTER NU +0xEE 0x03BE #GREEK SMALL LETTER XI +0xEF 0x03BF #GREEK SMALL LETTER OMICRON +0xF0 0x03C0 #GREEK SMALL LETTER PI +0xF1 0x03C1 #GREEK SMALL LETTER RHO +0xF2 0x03C2 #GREEK SMALL LETTER FINAL SIGMA +0xF3 0x03C3 #GREEK SMALL LETTER SIGMA +0xF4 0x03C4 #GREEK SMALL LETTER TAU +0xF5 0x03C5 #GREEK SMALL LETTER UPSILON +0xF6 0x03C6 #GREEK SMALL LETTER PHI +0xF7 0x03C7 #GREEK SMALL LETTER CHI +0xF8 0x03C8 #GREEK SMALL LETTER PSI +0xF9 0x03C9 #GREEK SMALL LETTER OMEGA +0xFA 0x03CA #GREEK SMALL LETTER IOTA WITH DIALYTIKA +0xFB 0x03CB #GREEK SMALL LETTER UPSILON WITH DIALYTIKA +0xFC 0x03CC #GREEK SMALL LETTER OMICRON WITH TONOS +0xFD 0x03CD #GREEK SMALL LETTER UPSILON WITH TONOS +0xFE 0x03CE #GREEK SMALL LETTER OMEGA WITH TONOS +0xFF #UNDEFINED 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-1254.txt b/data/windows-1254.txt new file mode 100644 index 000000000..ca1a1ebdb --- /dev/null +++ b/data/windows-1254.txt @@ -0,0 +1,274 @@ +# +# Name: cp1254 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1254 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1254 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A 0x0160 #LATIN CAPITAL LETTER S WITH CARON +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x0152 #LATIN CAPITAL LIGATURE OE +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x02DC #SMALL TILDE +0x99 0x2122 #TRADE MARK SIGN +0x9A 0x0161 #LATIN SMALL LETTER S WITH CARON +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x0153 #LATIN SMALL LIGATURE OE +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x00A1 #INVERTED EXCLAMATION MARK +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x00AA #FEMININE ORDINAL INDICATOR +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x00BA #MASCULINE ORDINAL INDICATOR +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF #INVERTED QUESTION MARK +0xC0 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x00C3 #LATIN CAPITAL LETTER A WITH TILDE +0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 #LATIN CAPITAL LETTER AE +0xC7 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x00CC #LATIN CAPITAL LETTER I WITH GRAVE +0xCD 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x011E #LATIN CAPITAL LETTER G WITH BREVE +0xD1 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x00D2 #LATIN CAPITAL LETTER O WITH GRAVE +0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x00D5 #LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x0130 #LATIN CAPITAL LETTER I WITH DOT ABOVE +0xDE 0x015E #LATIN CAPITAL LETTER S WITH CEDILLA +0xDF 0x00DF #LATIN SMALL LETTER SHARP S +0xE0 0x00E0 #LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 #LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x00E3 #LATIN SMALL LETTER A WITH TILDE +0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 #LATIN SMALL LETTER AE +0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 #LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x00EC #LATIN SMALL LETTER I WITH GRAVE +0xED 0x00ED #LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x011F #LATIN SMALL LETTER G WITH BREVE +0xF1 0x00F1 #LATIN SMALL LETTER N WITH TILDE +0xF2 0x00F2 #LATIN SMALL LETTER O WITH GRAVE +0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x00F5 #LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x00F8 #LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 #LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA #LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x0131 #LATIN SMALL LETTER DOTLESS I +0xFE 0x015F #LATIN SMALL LETTER S WITH CEDILLA +0xFF 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS 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-1255.txt b/data/windows-1255.txt new file mode 100644 index 000000000..341517f11 --- /dev/null +++ b/data/windows-1255.txt @@ -0,0 +1,274 @@ +# +# Name: cp1255 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 1/7/2000 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1255 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1255 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A #UNDEFINED +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C #UNDEFINED +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x02DC #SMALL TILDE +0x99 0x2122 #TRADE MARK SIGN +0x9A #UNDEFINED +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C #UNDEFINED +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F #UNDEFINED +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x00A1 #INVERTED EXCLAMATION MARK +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x20AA #NEW SHEQEL SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x00D7 #MULTIPLICATION SIGN +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x00F7 #DIVISION SIGN +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF #INVERTED QUESTION MARK +0xC0 0x05B0 #HEBREW POINT SHEVA +0xC1 0x05B1 #HEBREW POINT HATAF SEGOL +0xC2 0x05B2 #HEBREW POINT HATAF PATAH +0xC3 0x05B3 #HEBREW POINT HATAF QAMATS +0xC4 0x05B4 #HEBREW POINT HIRIQ +0xC5 0x05B5 #HEBREW POINT TSERE +0xC6 0x05B6 #HEBREW POINT SEGOL +0xC7 0x05B7 #HEBREW POINT PATAH +0xC8 0x05B8 #HEBREW POINT QAMATS +0xC9 0x05B9 #HEBREW POINT HOLAM +0xCA #UNDEFINED +0xCB 0x05BB #HEBREW POINT QUBUTS +0xCC 0x05BC #HEBREW POINT DAGESH OR MAPIQ +0xCD 0x05BD #HEBREW POINT METEG +0xCE 0x05BE #HEBREW PUNCTUATION MAQAF +0xCF 0x05BF #HEBREW POINT RAFE +0xD0 0x05C0 #HEBREW PUNCTUATION PASEQ +0xD1 0x05C1 #HEBREW POINT SHIN DOT +0xD2 0x05C2 #HEBREW POINT SIN DOT +0xD3 0x05C3 #HEBREW PUNCTUATION SOF PASUQ +0xD4 0x05F0 #HEBREW LIGATURE YIDDISH DOUBLE VAV +0xD5 0x05F1 #HEBREW LIGATURE YIDDISH VAV YOD +0xD6 0x05F2 #HEBREW LIGATURE YIDDISH DOUBLE YOD +0xD7 0x05F3 #HEBREW PUNCTUATION GERESH +0xD8 0x05F4 #HEBREW PUNCTUATION GERSHAYIM +0xD9 #UNDEFINED +0xDA #UNDEFINED +0xDB #UNDEFINED +0xDC #UNDEFINED +0xDD #UNDEFINED +0xDE #UNDEFINED +0xDF #UNDEFINED +0xE0 0x05D0 #HEBREW LETTER ALEF +0xE1 0x05D1 #HEBREW LETTER BET +0xE2 0x05D2 #HEBREW LETTER GIMEL +0xE3 0x05D3 #HEBREW LETTER DALET +0xE4 0x05D4 #HEBREW LETTER HE +0xE5 0x05D5 #HEBREW LETTER VAV +0xE6 0x05D6 #HEBREW LETTER ZAYIN +0xE7 0x05D7 #HEBREW LETTER HET +0xE8 0x05D8 #HEBREW LETTER TET +0xE9 0x05D9 #HEBREW LETTER YOD +0xEA 0x05DA #HEBREW LETTER FINAL KAF +0xEB 0x05DB #HEBREW LETTER KAF +0xEC 0x05DC #HEBREW LETTER LAMED +0xED 0x05DD #HEBREW LETTER FINAL MEM +0xEE 0x05DE #HEBREW LETTER MEM +0xEF 0x05DF #HEBREW LETTER FINAL NUN +0xF0 0x05E0 #HEBREW LETTER NUN +0xF1 0x05E1 #HEBREW LETTER SAMEKH +0xF2 0x05E2 #HEBREW LETTER AYIN +0xF3 0x05E3 #HEBREW LETTER FINAL PE +0xF4 0x05E4 #HEBREW LETTER PE +0xF5 0x05E5 #HEBREW LETTER FINAL TSADI +0xF6 0x05E6 #HEBREW LETTER TSADI +0xF7 0x05E7 #HEBREW LETTER QOF +0xF8 0x05E8 #HEBREW LETTER RESH +0xF9 0x05E9 #HEBREW LETTER SHIN +0xFA 0x05EA #HEBREW LETTER TAV +0xFB #UNDEFINED +0xFC #UNDEFINED +0xFD 0x200E #LEFT-TO-RIGHT MARK +0xFE 0x200F #RIGHT-TO-LEFT MARK +0xFF #UNDEFINED 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-1256.txt b/data/windows-1256.txt new file mode 100644 index 000000000..0edd081b9 --- /dev/null +++ b/data/windows-1256.txt @@ -0,0 +1,274 @@ +# +# Name: cp1256 to Unicode table +# Unicode version: 2.1 +# Table version: 2.01 +# Table format: Format A +# Date: 01/5/99 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1256 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1256 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 0x067E #ARABIC LETTER PEH +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A 0x0679 #ARABIC LETTER TTEH +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x0152 #LATIN CAPITAL LIGATURE OE +0x8D 0x0686 #ARABIC LETTER TCHEH +0x8E 0x0698 #ARABIC LETTER JEH +0x8F 0x0688 #ARABIC LETTER DDAL +0x90 0x06AF #ARABIC LETTER GAF +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x06A9 #ARABIC LETTER KEHEH +0x99 0x2122 #TRADE MARK SIGN +0x9A 0x0691 #ARABIC LETTER RREH +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x0153 #LATIN SMALL LIGATURE OE +0x9D 0x200C #ZERO WIDTH NON-JOINER +0x9E 0x200D #ZERO WIDTH JOINER +0x9F 0x06BA #ARABIC LETTER NOON GHUNNA +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x060C #ARABIC COMMA +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x06BE #ARABIC LETTER HEH DOACHASHMEE +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x061B #ARABIC SEMICOLON +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x061F #ARABIC QUESTION MARK +0xC0 0x06C1 #ARABIC LETTER HEH GOAL +0xC1 0x0621 #ARABIC LETTER HAMZA +0xC2 0x0622 #ARABIC LETTER ALEF WITH MADDA ABOVE +0xC3 0x0623 #ARABIC LETTER ALEF WITH HAMZA ABOVE +0xC4 0x0624 #ARABIC LETTER WAW WITH HAMZA ABOVE +0xC5 0x0625 #ARABIC LETTER ALEF WITH HAMZA BELOW +0xC6 0x0626 #ARABIC LETTER YEH WITH HAMZA ABOVE +0xC7 0x0627 #ARABIC LETTER ALEF +0xC8 0x0628 #ARABIC LETTER BEH +0xC9 0x0629 #ARABIC LETTER TEH MARBUTA +0xCA 0x062A #ARABIC LETTER TEH +0xCB 0x062B #ARABIC LETTER THEH +0xCC 0x062C #ARABIC LETTER JEEM +0xCD 0x062D #ARABIC LETTER HAH +0xCE 0x062E #ARABIC LETTER KHAH +0xCF 0x062F #ARABIC LETTER DAL +0xD0 0x0630 #ARABIC LETTER THAL +0xD1 0x0631 #ARABIC LETTER REH +0xD2 0x0632 #ARABIC LETTER ZAIN +0xD3 0x0633 #ARABIC LETTER SEEN +0xD4 0x0634 #ARABIC LETTER SHEEN +0xD5 0x0635 #ARABIC LETTER SAD +0xD6 0x0636 #ARABIC LETTER DAD +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x0637 #ARABIC LETTER TAH +0xD9 0x0638 #ARABIC LETTER ZAH +0xDA 0x0639 #ARABIC LETTER AIN +0xDB 0x063A #ARABIC LETTER GHAIN +0xDC 0x0640 #ARABIC TATWEEL +0xDD 0x0641 #ARABIC LETTER FEH +0xDE 0x0642 #ARABIC LETTER QAF +0xDF 0x0643 #ARABIC LETTER KAF +0xE0 0x00E0 #LATIN SMALL LETTER A WITH GRAVE +0xE1 0x0644 #ARABIC LETTER LAM +0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x0645 #ARABIC LETTER MEEM +0xE4 0x0646 #ARABIC LETTER NOON +0xE5 0x0647 #ARABIC LETTER HEH +0xE6 0x0648 #ARABIC LETTER WAW +0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 #LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x0649 #ARABIC LETTER ALEF MAKSURA +0xED 0x064A #ARABIC LETTER YEH +0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x064B #ARABIC FATHATAN +0xF1 0x064C #ARABIC DAMMATAN +0xF2 0x064D #ARABIC KASRATAN +0xF3 0x064E #ARABIC FATHA +0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x064F #ARABIC DAMMA +0xF6 0x0650 #ARABIC KASRA +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x0651 #ARABIC SHADDA +0xF9 0x00F9 #LATIN SMALL LETTER U WITH GRAVE +0xFA 0x0652 #ARABIC SUKUN +0xFB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x200E #LEFT-TO-RIGHT MARK +0xFE 0x200F #RIGHT-TO-LEFT MARK +0xFF 0x06D2 #ARABIC LETTER YEH BARREE 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-1257.txt b/data/windows-1257.txt new file mode 100644 index 000000000..97979d931 --- /dev/null +++ b/data/windows-1257.txt @@ -0,0 +1,274 @@ +# +# Name: cp1257 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1257 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1257 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 #UNDEFINED +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 #UNDEFINED +0x89 0x2030 #PER MILLE SIGN +0x8A #UNDEFINED +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C #UNDEFINED +0x8D 0x00A8 #DIAERESIS +0x8E 0x02C7 #CARON +0x8F 0x00B8 #CEDILLA +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 #UNDEFINED +0x99 0x2122 #TRADE MARK SIGN +0x9A #UNDEFINED +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C #UNDEFINED +0x9D 0x00AF #MACRON +0x9E 0x02DB #OGONEK +0x9F #UNDEFINED +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 #UNDEFINED +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 #UNDEFINED +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x0156 #LATIN CAPITAL LETTER R WITH CEDILLA +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00C6 #LATIN CAPITAL LETTER AE +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00F8 #LATIN SMALL LETTER O WITH STROKE +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x0157 #LATIN SMALL LETTER R WITH CEDILLA +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00E6 #LATIN SMALL LETTER AE +0xC0 0x0104 #LATIN CAPITAL LETTER A WITH OGONEK +0xC1 0x012E #LATIN CAPITAL LETTER I WITH OGONEK +0xC2 0x0100 #LATIN CAPITAL LETTER A WITH MACRON +0xC3 0x0106 #LATIN CAPITAL LETTER C WITH ACUTE +0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x0118 #LATIN CAPITAL LETTER E WITH OGONEK +0xC7 0x0112 #LATIN CAPITAL LETTER E WITH MACRON +0xC8 0x010C #LATIN CAPITAL LETTER C WITH CARON +0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x0179 #LATIN CAPITAL LETTER Z WITH ACUTE +0xCB 0x0116 #LATIN CAPITAL LETTER E WITH DOT ABOVE +0xCC 0x0122 #LATIN CAPITAL LETTER G WITH CEDILLA +0xCD 0x0136 #LATIN CAPITAL LETTER K WITH CEDILLA +0xCE 0x012A #LATIN CAPITAL LETTER I WITH MACRON +0xCF 0x013B #LATIN CAPITAL LETTER L WITH CEDILLA +0xD0 0x0160 #LATIN CAPITAL LETTER S WITH CARON +0xD1 0x0143 #LATIN CAPITAL LETTER N WITH ACUTE +0xD2 0x0145 #LATIN CAPITAL LETTER N WITH CEDILLA +0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x014C #LATIN CAPITAL LETTER O WITH MACRON +0xD5 0x00D5 #LATIN CAPITAL LETTER O WITH TILDE +0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x0172 #LATIN CAPITAL LETTER U WITH OGONEK +0xD9 0x0141 #LATIN CAPITAL LETTER L WITH STROKE +0xDA 0x015A #LATIN CAPITAL LETTER S WITH ACUTE +0xDB 0x016A #LATIN CAPITAL LETTER U WITH MACRON +0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x017B #LATIN CAPITAL LETTER Z WITH DOT ABOVE +0xDE 0x017D #LATIN CAPITAL LETTER Z WITH CARON +0xDF 0x00DF #LATIN SMALL LETTER SHARP S +0xE0 0x0105 #LATIN SMALL LETTER A WITH OGONEK +0xE1 0x012F #LATIN SMALL LETTER I WITH OGONEK +0xE2 0x0101 #LATIN SMALL LETTER A WITH MACRON +0xE3 0x0107 #LATIN SMALL LETTER C WITH ACUTE +0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x0119 #LATIN SMALL LETTER E WITH OGONEK +0xE7 0x0113 #LATIN SMALL LETTER E WITH MACRON +0xE8 0x010D #LATIN SMALL LETTER C WITH CARON +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x017A #LATIN SMALL LETTER Z WITH ACUTE +0xEB 0x0117 #LATIN SMALL LETTER E WITH DOT ABOVE +0xEC 0x0123 #LATIN SMALL LETTER G WITH CEDILLA +0xED 0x0137 #LATIN SMALL LETTER K WITH CEDILLA +0xEE 0x012B #LATIN SMALL LETTER I WITH MACRON +0xEF 0x013C #LATIN SMALL LETTER L WITH CEDILLA +0xF0 0x0161 #LATIN SMALL LETTER S WITH CARON +0xF1 0x0144 #LATIN SMALL LETTER N WITH ACUTE +0xF2 0x0146 #LATIN SMALL LETTER N WITH CEDILLA +0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xF4 0x014D #LATIN SMALL LETTER O WITH MACRON +0xF5 0x00F5 #LATIN SMALL LETTER O WITH TILDE +0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x0173 #LATIN SMALL LETTER U WITH OGONEK +0xF9 0x0142 #LATIN SMALL LETTER L WITH STROKE +0xFA 0x015B #LATIN SMALL LETTER S WITH ACUTE +0xFB 0x016B #LATIN SMALL LETTER U WITH MACRON +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x017C #LATIN SMALL LETTER Z WITH DOT ABOVE +0xFE 0x017E #LATIN SMALL LETTER Z WITH CARON +0xFF 0x02D9 #DOT ABOVE 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-1258.txt b/data/windows-1258.txt new file mode 100644 index 000000000..392310a8c --- /dev/null +++ b/data/windows-1258.txt @@ -0,0 +1,274 @@ +# +# Name: cp1258 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 04/15/98 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp1258 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp1258 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 0x201A #SINGLE LOW-9 QUOTATION MARK +0x83 0x0192 #LATIN SMALL LETTER F WITH HOOK +0x84 0x201E #DOUBLE LOW-9 QUOTATION MARK +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 0x2020 #DAGGER +0x87 0x2021 #DOUBLE DAGGER +0x88 0x02C6 #MODIFIER LETTER CIRCUMFLEX ACCENT +0x89 0x2030 #PER MILLE SIGN +0x8A #UNDEFINED +0x8B 0x2039 #SINGLE LEFT-POINTING ANGLE QUOTATION MARK +0x8C 0x0152 #LATIN CAPITAL LIGATURE OE +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 0x02DC #SMALL TILDE +0x99 0x2122 #TRADE MARK SIGN +0x9A #UNDEFINED +0x9B 0x203A #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK +0x9C 0x0153 #LATIN SMALL LIGATURE OE +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F 0x0178 #LATIN CAPITAL LETTER Y WITH DIAERESIS +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x00A1 #INVERTED EXCLAMATION MARK +0xA2 0x00A2 #CENT SIGN +0xA3 0x00A3 #POUND SIGN +0xA4 0x00A4 #CURRENCY SIGN +0xA5 0x00A5 #YEN SIGN +0xA6 0x00A6 #BROKEN BAR +0xA7 0x00A7 #SECTION SIGN +0xA8 0x00A8 #DIAERESIS +0xA9 0x00A9 #COPYRIGHT SIGN +0xAA 0x00AA #FEMININE ORDINAL INDICATOR +0xAB 0x00AB #LEFT-POINTING DOUBLE ANGLE QUOTATION MARK +0xAC 0x00AC #NOT SIGN +0xAD 0x00AD #SOFT HYPHEN +0xAE 0x00AE #REGISTERED SIGN +0xAF 0x00AF #MACRON +0xB0 0x00B0 #DEGREE SIGN +0xB1 0x00B1 #PLUS-MINUS SIGN +0xB2 0x00B2 #SUPERSCRIPT TWO +0xB3 0x00B3 #SUPERSCRIPT THREE +0xB4 0x00B4 #ACUTE ACCENT +0xB5 0x00B5 #MICRO SIGN +0xB6 0x00B6 #PILCROW SIGN +0xB7 0x00B7 #MIDDLE DOT +0xB8 0x00B8 #CEDILLA +0xB9 0x00B9 #SUPERSCRIPT ONE +0xBA 0x00BA #MASCULINE ORDINAL INDICATOR +0xBB 0x00BB #RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK +0xBC 0x00BC #VULGAR FRACTION ONE QUARTER +0xBD 0x00BD #VULGAR FRACTION ONE HALF +0xBE 0x00BE #VULGAR FRACTION THREE QUARTERS +0xBF 0x00BF #INVERTED QUESTION MARK +0xC0 0x00C0 #LATIN CAPITAL LETTER A WITH GRAVE +0xC1 0x00C1 #LATIN CAPITAL LETTER A WITH ACUTE +0xC2 0x00C2 #LATIN CAPITAL LETTER A WITH CIRCUMFLEX +0xC3 0x0102 #LATIN CAPITAL LETTER A WITH BREVE +0xC4 0x00C4 #LATIN CAPITAL LETTER A WITH DIAERESIS +0xC5 0x00C5 #LATIN CAPITAL LETTER A WITH RING ABOVE +0xC6 0x00C6 #LATIN CAPITAL LETTER AE +0xC7 0x00C7 #LATIN CAPITAL LETTER C WITH CEDILLA +0xC8 0x00C8 #LATIN CAPITAL LETTER E WITH GRAVE +0xC9 0x00C9 #LATIN CAPITAL LETTER E WITH ACUTE +0xCA 0x00CA #LATIN CAPITAL LETTER E WITH CIRCUMFLEX +0xCB 0x00CB #LATIN CAPITAL LETTER E WITH DIAERESIS +0xCC 0x0300 #COMBINING GRAVE ACCENT +0xCD 0x00CD #LATIN CAPITAL LETTER I WITH ACUTE +0xCE 0x00CE #LATIN CAPITAL LETTER I WITH CIRCUMFLEX +0xCF 0x00CF #LATIN CAPITAL LETTER I WITH DIAERESIS +0xD0 0x0110 #LATIN CAPITAL LETTER D WITH STROKE +0xD1 0x00D1 #LATIN CAPITAL LETTER N WITH TILDE +0xD2 0x0309 #COMBINING HOOK ABOVE +0xD3 0x00D3 #LATIN CAPITAL LETTER O WITH ACUTE +0xD4 0x00D4 #LATIN CAPITAL LETTER O WITH CIRCUMFLEX +0xD5 0x01A0 #LATIN CAPITAL LETTER O WITH HORN +0xD6 0x00D6 #LATIN CAPITAL LETTER O WITH DIAERESIS +0xD7 0x00D7 #MULTIPLICATION SIGN +0xD8 0x00D8 #LATIN CAPITAL LETTER O WITH STROKE +0xD9 0x00D9 #LATIN CAPITAL LETTER U WITH GRAVE +0xDA 0x00DA #LATIN CAPITAL LETTER U WITH ACUTE +0xDB 0x00DB #LATIN CAPITAL LETTER U WITH CIRCUMFLEX +0xDC 0x00DC #LATIN CAPITAL LETTER U WITH DIAERESIS +0xDD 0x01AF #LATIN CAPITAL LETTER U WITH HORN +0xDE 0x0303 #COMBINING TILDE +0xDF 0x00DF #LATIN SMALL LETTER SHARP S +0xE0 0x00E0 #LATIN SMALL LETTER A WITH GRAVE +0xE1 0x00E1 #LATIN SMALL LETTER A WITH ACUTE +0xE2 0x00E2 #LATIN SMALL LETTER A WITH CIRCUMFLEX +0xE3 0x0103 #LATIN SMALL LETTER A WITH BREVE +0xE4 0x00E4 #LATIN SMALL LETTER A WITH DIAERESIS +0xE5 0x00E5 #LATIN SMALL LETTER A WITH RING ABOVE +0xE6 0x00E6 #LATIN SMALL LETTER AE +0xE7 0x00E7 #LATIN SMALL LETTER C WITH CEDILLA +0xE8 0x00E8 #LATIN SMALL LETTER E WITH GRAVE +0xE9 0x00E9 #LATIN SMALL LETTER E WITH ACUTE +0xEA 0x00EA #LATIN SMALL LETTER E WITH CIRCUMFLEX +0xEB 0x00EB #LATIN SMALL LETTER E WITH DIAERESIS +0xEC 0x0301 #COMBINING ACUTE ACCENT +0xED 0x00ED #LATIN SMALL LETTER I WITH ACUTE +0xEE 0x00EE #LATIN SMALL LETTER I WITH CIRCUMFLEX +0xEF 0x00EF #LATIN SMALL LETTER I WITH DIAERESIS +0xF0 0x0111 #LATIN SMALL LETTER D WITH STROKE +0xF1 0x00F1 #LATIN SMALL LETTER N WITH TILDE +0xF2 0x0323 #COMBINING DOT BELOW +0xF3 0x00F3 #LATIN SMALL LETTER O WITH ACUTE +0xF4 0x00F4 #LATIN SMALL LETTER O WITH CIRCUMFLEX +0xF5 0x01A1 #LATIN SMALL LETTER O WITH HORN +0xF6 0x00F6 #LATIN SMALL LETTER O WITH DIAERESIS +0xF7 0x00F7 #DIVISION SIGN +0xF8 0x00F8 #LATIN SMALL LETTER O WITH STROKE +0xF9 0x00F9 #LATIN SMALL LETTER U WITH GRAVE +0xFA 0x00FA #LATIN SMALL LETTER U WITH ACUTE +0xFB 0x00FB #LATIN SMALL LETTER U WITH CIRCUMFLEX +0xFC 0x00FC #LATIN SMALL LETTER U WITH DIAERESIS +0xFD 0x01B0 #LATIN SMALL LETTER U WITH HORN +0xFE 0x20AB #DONG SIGN +0xFF 0x00FF #LATIN SMALL LETTER Y WITH DIAERESIS diff --git a/data/windows-1361.txt b/data/windows-1361.txt new file mode 100644 index 000000000..3024f5870 --- /dev/null +++ b/data/windows-1361.txt @@ -0,0 +1,17396 @@ +# cp1361.txt - Legacy to Unicode charmap +0x0000 0x0000 # 0 +0x0001 0x0001 # 0 +0x0002 0x0002 # 0 +0x0003 0x0003 # 0 +0x0004 0x0004 # 0 +0x0005 0x0005 # 0 +0x0006 0x0006 # 0 +0x0007 0x0007 # 0 +0x0008 0x0008 # 0 +0x0009 0x0009 # 0 +0x000A 0x000A # 0 +0x000B 0x000B # 0 +0x000C 0x000C # 0 +0x000D 0x000D # 0 +0x000E 0x000E # 0 +0x000F 0x000F # 0 +0x0010 0x0010 # 0 +0x0011 0x0011 # 0 +0x0012 0x0012 # 0 +0x0013 0x0013 # 0 +0x0014 0x0014 # 0 +0x0015 0x0015 # 0 +0x0016 0x0016 # 0 +0x0017 0x0017 # 0 +0x0018 0x0018 # 0 +0x0019 0x0019 # 0 +0x001A 0x001A # 0 +0x001B 0x001B # 0 +0x001C 0x001C # 0 +0x001D 0x001D # 0 +0x001E 0x001E # 0 +0x001F 0x001F # 0 +0x0020 0x0020 # 0 +0x0021 0x0021 # 0 +0x0022 0x0022 # 0 +0x0023 0x0023 # 0 +0x0024 0x0024 # 0 +0x0025 0x0025 # 0 +0x0026 0x0026 # 0 +0x0027 0x0027 # 0 +0x0028 0x0028 # 0 +0x0029 0x0029 # 0 +0x002A 0x002A # 0 +0x002B 0x002B # 0 +0x002C 0x002C # 0 +0x002D 0x002D # 0 +0x002E 0x002E # 0 +0x002F 0x002F # 0 +0x0030 0x0030 # 0 +0x0031 0x0031 # 0 +0x0032 0x0032 # 0 +0x0033 0x0033 # 0 +0x0034 0x0034 # 0 +0x0035 0x0035 # 0 +0x0036 0x0036 # 0 +0x0037 0x0037 # 0 +0x0038 0x0038 # 0 +0x0039 0x0039 # 0 +0x003A 0x003A # 0 +0x003B 0x003B # 0 +0x003C 0x003C # 0 +0x003D 0x003D # 0 +0x003E 0x003E # 0 +0x003F 0x003F # 0 +0x0040 0x0040 # 0 +0x0041 0x0041 # 0 +0x0042 0x0042 # 0 +0x0043 0x0043 # 0 +0x0044 0x0044 # 0 +0x0045 0x0045 # 0 +0x0046 0x0046 # 0 +0x0047 0x0047 # 0 +0x0048 0x0048 # 0 +0x0049 0x0049 # 0 +0x004A 0x004A # 0 +0x004B 0x004B # 0 +0x004C 0x004C # 0 +0x004D 0x004D # 0 +0x004E 0x004E # 0 +0x004F 0x004F # 0 +0x0050 0x0050 # 0 +0x0051 0x0051 # 0 +0x0052 0x0052 # 0 +0x0053 0x0053 # 0 +0x0054 0x0054 # 0 +0x0055 0x0055 # 0 +0x0056 0x0056 # 0 +0x0057 0x0057 # 0 +0x0058 0x0058 # 0 +0x0059 0x0059 # 0 +0x005A 0x005A # 0 +0x005B 0x005B # 0 +0x005C 0x005C # 0 +0x005D 0x005D # 0 +0x005E 0x005E # 0 +0x005F 0x005F # 0 +0x0060 0x0060 # 0 +0x0061 0x0061 # 0 +0x0062 0x0062 # 0 +0x0063 0x0063 # 0 +0x0064 0x0064 # 0 +0x0065 0x0065 # 0 +0x0066 0x0066 # 0 +0x0067 0x0067 # 0 +0x0068 0x0068 # 0 +0x0069 0x0069 # 0 +0x006A 0x006A # 0 +0x006B 0x006B # 0 +0x006C 0x006C # 0 +0x006D 0x006D # 0 +0x006E 0x006E # 0 +0x006F 0x006F # 0 +0x0070 0x0070 # 0 +0x0071 0x0071 # 0 +0x0072 0x0072 # 0 +0x0073 0x0073 # 0 +0x0074 0x0074 # 0 +0x0075 0x0075 # 0 +0x0076 0x0076 # 0 +0x0077 0x0077 # 0 +0x0078 0x0078 # 0 +0x0079 0x0079 # 0 +0x007A 0x007A # 0 +0x007B 0x007B # 0 +0x007C 0x007C # 0 +0x007D 0x007D # 0 +0x007E 0x007E # 0 +0x007F 0x007F # 0 +0x0080 0x0080 # 0 +0x0081 0x0081 # 0 +0x0082 0x0082 # 0 +0x0083 0x0083 # 0 +0x00D4 0xF8EC # 0 +0x00D5 0xF8ED # 0 +0x00D6 0xF8EE # 0 +0x00D7 0xF8EF # 0 +0x00DF 0xF8F0 # 0 +0x00FA 0xF8F1 # 0 +0x00FB 0xF8F2 # 0 +0x00FC 0xF8F3 # 0 +0x00FD 0xF8F4 # 0 +0x00FE 0xF8F5 # 0 +0x00FF 0xF8F6 # 0 +0x8442 0x11A8 # 0 +0x8443 0x11A9 # 0 +0x8444 0x11AA # 0 +0x8445 0x11AB # 0 +0x8446 0x11AC # 0 +0x8447 0x11AD # 0 +0x8448 0x11AE # 0 +0x8449 0x11AF # 0 +0x844A 0x11B0 # 0 +0x844B 0x11B1 # 0 +0x844C 0x11B2 # 0 +0x844D 0x11B3 # 0 +0x844E 0x11B4 # 0 +0x844F 0x11B5 # 0 +0x8450 0x11B6 # 0 +0x8451 0x11B7 # 0 +0x8453 0x11B8 # 0 +0x8454 0x11B9 # 0 +0x8455 0x11BA # 0 +0x8456 0x11BB # 0 +0x8457 0x11BC # 0 +0x8458 0x11BD # 0 +0x8459 0x11BE # 0 +0x845A 0x11BF # 0 +0x845B 0x11C0 # 0 +0x845C 0x11C1 # 0 +0x845D 0x11C2 # 0 +0x8461 0x1161 # 0 +0x8481 0x1162 # 0 +0x84A1 0x1163 # 0 +0x84C1 0x1164 # 0 +0x84E1 0x1165 # 0 +0x8541 0x1166 # 0 +0x8561 0x1167 # 0 +0x8581 0x1168 # 0 +0x85A1 0x1169 # 0 +0x85C1 0x116A # 0 +0x85E1 0x116B # 0 +0x8641 0x116C # 0 +0x8661 0x116D # 0 +0x8681 0x116E # 0 +0x86A1 0x116F # 0 +0x86C1 0x1170 # 0 +0x86E1 0x1171 # 0 +0x8741 0x1172 # 0 +0x8761 0x1173 # 0 +0x8781 0x1174 # 0 +0x87A1 0x1175 # 0 +0x8841 0x1100 # 0 +0x8861 0xAC00 # 0 +0x8862 0xAC01 # 0 +0x8863 0xAC02 # 0 +0x8864 0xAC03 # 0 +0x8865 0xAC04 # 0 +0x8866 0xAC05 # 0 +0x8867 0xAC06 # 0 +0x8868 0xAC07 # 0 +0x8869 0xAC08 # 0 +0x886A 0xAC09 # 0 +0x886B 0xAC0A # 0 +0x886C 0xAC0B # 0 +0x886D 0xAC0C # 0 +0x886E 0xAC0D # 0 +0x886F 0xAC0E # 0 +0x8870 0xAC0F # 0 +0x8871 0xAC10 # 0 +0x8873 0xAC11 # 0 +0x8874 0xAC12 # 0 +0x8875 0xAC13 # 0 +0x8876 0xAC14 # 0 +0x8877 0xAC15 # 0 +0x8878 0xAC16 # 0 +0x8879 0xAC17 # 0 +0x887A 0xAC18 # 0 +0x887B 0xAC19 # 0 +0x887C 0xAC1A # 0 +0x887D 0xAC1B # 0 +0x8881 0xAC1C # 0 +0x8882 0xAC1D # 0 +0x8883 0xAC1E # 0 +0x8884 0xAC1F # 0 +0x8885 0xAC20 # 0 +0x8886 0xAC21 # 0 +0x8887 0xAC22 # 0 +0x8888 0xAC23 # 0 +0x8889 0xAC24 # 0 +0x888A 0xAC25 # 0 +0x888B 0xAC26 # 0 +0x888C 0xAC27 # 0 +0x888D 0xAC28 # 0 +0x888E 0xAC29 # 0 +0x888F 0xAC2A # 0 +0x8890 0xAC2B # 0 +0x8891 0xAC2C # 0 +0x8893 0xAC2D # 0 +0x8894 0xAC2E # 0 +0x8895 0xAC2F # 0 +0x8896 0xAC30 # 0 +0x8897 0xAC31 # 0 +0x8898 0xAC32 # 0 +0x8899 0xAC33 # 0 +0x889A 0xAC34 # 0 +0x889B 0xAC35 # 0 +0x889C 0xAC36 # 0 +0x889D 0xAC37 # 0 +0x88A1 0xAC38 # 0 +0x88A2 0xAC39 # 0 +0x88A3 0xAC3A # 0 +0x88A4 0xAC3B # 0 +0x88A5 0xAC3C # 0 +0x88A6 0xAC3D # 0 +0x88A7 0xAC3E # 0 +0x88A8 0xAC3F # 0 +0x88A9 0xAC40 # 0 +0x88AA 0xAC41 # 0 +0x88AB 0xAC42 # 0 +0x88AC 0xAC43 # 0 +0x88AD 0xAC44 # 0 +0x88AE 0xAC45 # 0 +0x88AF 0xAC46 # 0 +0x88B0 0xAC47 # 0 +0x88B1 0xAC48 # 0 +0x88B3 0xAC49 # 0 +0x88B4 0xAC4A # 0 +0x88B5 0xAC4B # 0 +0x88B6 0xAC4C # 0 +0x88B7 0xAC4D # 0 +0x88B8 0xAC4E # 0 +0x88B9 0xAC4F # 0 +0x88BA 0xAC50 # 0 +0x88BB 0xAC51 # 0 +0x88BC 0xAC52 # 0 +0x88BD 0xAC53 # 0 +0x88C1 0xAC54 # 0 +0x88C2 0xAC55 # 0 +0x88C3 0xAC56 # 0 +0x88C4 0xAC57 # 0 +0x88C5 0xAC58 # 0 +0x88C6 0xAC59 # 0 +0x88C7 0xAC5A # 0 +0x88C8 0xAC5B # 0 +0x88C9 0xAC5C # 0 +0x88CA 0xAC5D # 0 +0x88CB 0xAC5E # 0 +0x88CC 0xAC5F # 0 +0x88CD 0xAC60 # 0 +0x88CE 0xAC61 # 0 +0x88CF 0xAC62 # 0 +0x88D0 0xAC63 # 0 +0x88D1 0xAC64 # 0 +0x88D3 0xAC65 # 0 +0x88D4 0xAC66 # 0 +0x88D5 0xAC67 # 0 +0x88D6 0xAC68 # 0 +0x88D7 0xAC69 # 0 +0x88D8 0xAC6A # 0 +0x88D9 0xAC6B # 0 +0x88DA 0xAC6C # 0 +0x88DB 0xAC6D # 0 +0x88DC 0xAC6E # 0 +0x88DD 0xAC6F # 0 +0x88E1 0xAC70 # 0 +0x88E2 0xAC71 # 0 +0x88E3 0xAC72 # 0 +0x88E4 0xAC73 # 0 +0x88E5 0xAC74 # 0 +0x88E6 0xAC75 # 0 +0x88E7 0xAC76 # 0 +0x88E8 0xAC77 # 0 +0x88E9 0xAC78 # 0 +0x88EA 0xAC79 # 0 +0x88EB 0xAC7A # 0 +0x88EC 0xAC7B # 0 +0x88ED 0xAC7C # 0 +0x88EE 0xAC7D # 0 +0x88EF 0xAC7E # 0 +0x88F0 0xAC7F # 0 +0x88F1 0xAC80 # 0 +0x88F3 0xAC81 # 0 +0x88F4 0xAC82 # 0 +0x88F5 0xAC83 # 0 +0x88F6 0xAC84 # 0 +0x88F7 0xAC85 # 0 +0x88F8 0xAC86 # 0 +0x88F9 0xAC87 # 0 +0x88FA 0xAC88 # 0 +0x88FB 0xAC89 # 0 +0x88FC 0xAC8A # 0 +0x88FD 0xAC8B # 0 +0x8941 0xAC8C # 0 +0x8942 0xAC8D # 0 +0x8943 0xAC8E # 0 +0x8944 0xAC8F # 0 +0x8945 0xAC90 # 0 +0x8946 0xAC91 # 0 +0x8947 0xAC92 # 0 +0x8948 0xAC93 # 0 +0x8949 0xAC94 # 0 +0x894A 0xAC95 # 0 +0x894B 0xAC96 # 0 +0x894C 0xAC97 # 0 +0x894D 0xAC98 # 0 +0x894E 0xAC99 # 0 +0x894F 0xAC9A # 0 +0x8950 0xAC9B # 0 +0x8951 0xAC9C # 0 +0x8953 0xAC9D # 0 +0x8954 0xAC9E # 0 +0x8955 0xAC9F # 0 +0x8956 0xACA0 # 0 +0x8957 0xACA1 # 0 +0x8958 0xACA2 # 0 +0x8959 0xACA3 # 0 +0x895A 0xACA4 # 0 +0x895B 0xACA5 # 0 +0x895C 0xACA6 # 0 +0x895D 0xACA7 # 0 +0x8961 0xACA8 # 0 +0x8962 0xACA9 # 0 +0x8963 0xACAA # 0 +0x8964 0xACAB # 0 +0x8965 0xACAC # 0 +0x8966 0xACAD # 0 +0x8967 0xACAE # 0 +0x8968 0xACAF # 0 +0x8969 0xACB0 # 0 +0x896A 0xACB1 # 0 +0x896B 0xACB2 # 0 +0x896C 0xACB3 # 0 +0x896D 0xACB4 # 0 +0x896E 0xACB5 # 0 +0x896F 0xACB6 # 0 +0x8970 0xACB7 # 0 +0x8971 0xACB8 # 0 +0x8973 0xACB9 # 0 +0x8974 0xACBA # 0 +0x8975 0xACBB # 0 +0x8976 0xACBC # 0 +0x8977 0xACBD # 0 +0x8978 0xACBE # 0 +0x8979 0xACBF # 0 +0x897A 0xACC0 # 0 +0x897B 0xACC1 # 0 +0x897C 0xACC2 # 0 +0x897D 0xACC3 # 0 +0x8981 0xACC4 # 0 +0x8982 0xACC5 # 0 +0x8983 0xACC6 # 0 +0x8984 0xACC7 # 0 +0x8985 0xACC8 # 0 +0x8986 0xACC9 # 0 +0x8987 0xACCA # 0 +0x8988 0xACCB # 0 +0x8989 0xACCC # 0 +0x898A 0xACCD # 0 +0x898B 0xACCE # 0 +0x898C 0xACCF # 0 +0x898D 0xACD0 # 0 +0x898E 0xACD1 # 0 +0x898F 0xACD2 # 0 +0x8990 0xACD3 # 0 +0x8991 0xACD4 # 0 +0x8993 0xACD5 # 0 +0x8994 0xACD6 # 0 +0x8995 0xACD7 # 0 +0x8996 0xACD8 # 0 +0x8997 0xACD9 # 0 +0x8998 0xACDA # 0 +0x8999 0xACDB # 0 +0x899A 0xACDC # 0 +0x899B 0xACDD # 0 +0x899C 0xACDE # 0 +0x899D 0xACDF # 0 +0x89A1 0xACE0 # 0 +0x89A2 0xACE1 # 0 +0x89A3 0xACE2 # 0 +0x89A4 0xACE3 # 0 +0x89A5 0xACE4 # 0 +0x89A6 0xACE5 # 0 +0x89A7 0xACE6 # 0 +0x89A8 0xACE7 # 0 +0x89A9 0xACE8 # 0 +0x89AA 0xACE9 # 0 +0x89AB 0xACEA # 0 +0x89AC 0xACEB # 0 +0x89AD 0xACEC # 0 +0x89AE 0xACED # 0 +0x89AF 0xACEE # 0 +0x89B0 0xACEF # 0 +0x89B1 0xACF0 # 0 +0x89B3 0xACF1 # 0 +0x89B4 0xACF2 # 0 +0x89B5 0xACF3 # 0 +0x89B6 0xACF4 # 0 +0x89B7 0xACF5 # 0 +0x89B8 0xACF6 # 0 +0x89B9 0xACF7 # 0 +0x89BA 0xACF8 # 0 +0x89BB 0xACF9 # 0 +0x89BC 0xACFA # 0 +0x89BD 0xACFB # 0 +0x89C1 0xACFC # 0 +0x89C2 0xACFD # 0 +0x89C3 0xACFE # 0 +0x89C4 0xACFF # 0 +0x89C5 0xAD00 # 0 +0x89C6 0xAD01 # 0 +0x89C7 0xAD02 # 0 +0x89C8 0xAD03 # 0 +0x89C9 0xAD04 # 0 +0x89CA 0xAD05 # 0 +0x89CB 0xAD06 # 0 +0x89CC 0xAD07 # 0 +0x89CD 0xAD08 # 0 +0x89CE 0xAD09 # 0 +0x89CF 0xAD0A # 0 +0x89D0 0xAD0B # 0 +0x89D1 0xAD0C # 0 +0x89D3 0xAD0D # 0 +0x89D4 0xAD0E # 0 +0x89D5 0xAD0F # 0 +0x89D6 0xAD10 # 0 +0x89D7 0xAD11 # 0 +0x89D8 0xAD12 # 0 +0x89D9 0xAD13 # 0 +0x89DA 0xAD14 # 0 +0x89DB 0xAD15 # 0 +0x89DC 0xAD16 # 0 +0x89DD 0xAD17 # 0 +0x89E1 0xAD18 # 0 +0x89E2 0xAD19 # 0 +0x89E3 0xAD1A # 0 +0x89E4 0xAD1B # 0 +0x89E5 0xAD1C # 0 +0x89E6 0xAD1D # 0 +0x89E7 0xAD1E # 0 +0x89E8 0xAD1F # 0 +0x89E9 0xAD20 # 0 +0x89EA 0xAD21 # 0 +0x89EB 0xAD22 # 0 +0x89EC 0xAD23 # 0 +0x89ED 0xAD24 # 0 +0x89EE 0xAD25 # 0 +0x89EF 0xAD26 # 0 +0x89F0 0xAD27 # 0 +0x89F1 0xAD28 # 0 +0x89F3 0xAD29 # 0 +0x89F4 0xAD2A # 0 +0x89F5 0xAD2B # 0 +0x89F6 0xAD2C # 0 +0x89F7 0xAD2D # 0 +0x89F8 0xAD2E # 0 +0x89F9 0xAD2F # 0 +0x89FA 0xAD30 # 0 +0x89FB 0xAD31 # 0 +0x89FC 0xAD32 # 0 +0x89FD 0xAD33 # 0 +0x8A41 0xAD34 # 0 +0x8A42 0xAD35 # 0 +0x8A43 0xAD36 # 0 +0x8A44 0xAD37 # 0 +0x8A45 0xAD38 # 0 +0x8A46 0xAD39 # 0 +0x8A47 0xAD3A # 0 +0x8A48 0xAD3B # 0 +0x8A49 0xAD3C # 0 +0x8A4A 0xAD3D # 0 +0x8A4B 0xAD3E # 0 +0x8A4C 0xAD3F # 0 +0x8A4D 0xAD40 # 0 +0x8A4E 0xAD41 # 0 +0x8A4F 0xAD42 # 0 +0x8A50 0xAD43 # 0 +0x8A51 0xAD44 # 0 +0x8A53 0xAD45 # 0 +0x8A54 0xAD46 # 0 +0x8A55 0xAD47 # 0 +0x8A56 0xAD48 # 0 +0x8A57 0xAD49 # 0 +0x8A58 0xAD4A # 0 +0x8A59 0xAD4B # 0 +0x8A5A 0xAD4C # 0 +0x8A5B 0xAD4D # 0 +0x8A5C 0xAD4E # 0 +0x8A5D 0xAD4F # 0 +0x8A61 0xAD50 # 0 +0x8A62 0xAD51 # 0 +0x8A63 0xAD52 # 0 +0x8A64 0xAD53 # 0 +0x8A65 0xAD54 # 0 +0x8A66 0xAD55 # 0 +0x8A67 0xAD56 # 0 +0x8A68 0xAD57 # 0 +0x8A69 0xAD58 # 0 +0x8A6A 0xAD59 # 0 +0x8A6B 0xAD5A # 0 +0x8A6C 0xAD5B # 0 +0x8A6D 0xAD5C # 0 +0x8A6E 0xAD5D # 0 +0x8A6F 0xAD5E # 0 +0x8A70 0xAD5F # 0 +0x8A71 0xAD60 # 0 +0x8A73 0xAD61 # 0 +0x8A74 0xAD62 # 0 +0x8A75 0xAD63 # 0 +0x8A76 0xAD64 # 0 +0x8A77 0xAD65 # 0 +0x8A78 0xAD66 # 0 +0x8A79 0xAD67 # 0 +0x8A7A 0xAD68 # 0 +0x8A7B 0xAD69 # 0 +0x8A7C 0xAD6A # 0 +0x8A7D 0xAD6B # 0 +0x8A81 0xAD6C # 0 +0x8A82 0xAD6D # 0 +0x8A83 0xAD6E # 0 +0x8A84 0xAD6F # 0 +0x8A85 0xAD70 # 0 +0x8A86 0xAD71 # 0 +0x8A87 0xAD72 # 0 +0x8A88 0xAD73 # 0 +0x8A89 0xAD74 # 0 +0x8A8A 0xAD75 # 0 +0x8A8B 0xAD76 # 0 +0x8A8C 0xAD77 # 0 +0x8A8D 0xAD78 # 0 +0x8A8E 0xAD79 # 0 +0x8A8F 0xAD7A # 0 +0x8A90 0xAD7B # 0 +0x8A91 0xAD7C # 0 +0x8A93 0xAD7D # 0 +0x8A94 0xAD7E # 0 +0x8A95 0xAD7F # 0 +0x8A96 0xAD80 # 0 +0x8A97 0xAD81 # 0 +0x8A98 0xAD82 # 0 +0x8A99 0xAD83 # 0 +0x8A9A 0xAD84 # 0 +0x8A9B 0xAD85 # 0 +0x8A9C 0xAD86 # 0 +0x8A9D 0xAD87 # 0 +0x8AA1 0xAD88 # 0 +0x8AA2 0xAD89 # 0 +0x8AA3 0xAD8A # 0 +0x8AA4 0xAD8B # 0 +0x8AA5 0xAD8C # 0 +0x8AA6 0xAD8D # 0 +0x8AA7 0xAD8E # 0 +0x8AA8 0xAD8F # 0 +0x8AA9 0xAD90 # 0 +0x8AAA 0xAD91 # 0 +0x8AAB 0xAD92 # 0 +0x8AAC 0xAD93 # 0 +0x8AAD 0xAD94 # 0 +0x8AAE 0xAD95 # 0 +0x8AAF 0xAD96 # 0 +0x8AB0 0xAD97 # 0 +0x8AB1 0xAD98 # 0 +0x8AB3 0xAD99 # 0 +0x8AB4 0xAD9A # 0 +0x8AB5 0xAD9B # 0 +0x8AB6 0xAD9C # 0 +0x8AB7 0xAD9D # 0 +0x8AB8 0xAD9E # 0 +0x8AB9 0xAD9F # 0 +0x8ABA 0xADA0 # 0 +0x8ABB 0xADA1 # 0 +0x8ABC 0xADA2 # 0 +0x8ABD 0xADA3 # 0 +0x8AC1 0xADA4 # 0 +0x8AC2 0xADA5 # 0 +0x8AC3 0xADA6 # 0 +0x8AC4 0xADA7 # 0 +0x8AC5 0xADA8 # 0 +0x8AC6 0xADA9 # 0 +0x8AC7 0xADAA # 0 +0x8AC8 0xADAB # 0 +0x8AC9 0xADAC # 0 +0x8ACA 0xADAD # 0 +0x8ACB 0xADAE # 0 +0x8ACC 0xADAF # 0 +0x8ACD 0xADB0 # 0 +0x8ACE 0xADB1 # 0 +0x8ACF 0xADB2 # 0 +0x8AD0 0xADB3 # 0 +0x8AD1 0xADB4 # 0 +0x8AD3 0xADB5 # 0 +0x8AD4 0xADB6 # 0 +0x8AD5 0xADB7 # 0 +0x8AD6 0xADB8 # 0 +0x8AD7 0xADB9 # 0 +0x8AD8 0xADBA # 0 +0x8AD9 0xADBB # 0 +0x8ADA 0xADBC # 0 +0x8ADB 0xADBD # 0 +0x8ADC 0xADBE # 0 +0x8ADD 0xADBF # 0 +0x8AE1 0xADC0 # 0 +0x8AE2 0xADC1 # 0 +0x8AE3 0xADC2 # 0 +0x8AE4 0xADC3 # 0 +0x8AE5 0xADC4 # 0 +0x8AE6 0xADC5 # 0 +0x8AE7 0xADC6 # 0 +0x8AE8 0xADC7 # 0 +0x8AE9 0xADC8 # 0 +0x8AEA 0xADC9 # 0 +0x8AEB 0xADCA # 0 +0x8AEC 0xADCB # 0 +0x8AED 0xADCC # 0 +0x8AEE 0xADCD # 0 +0x8AEF 0xADCE # 0 +0x8AF0 0xADCF # 0 +0x8AF1 0xADD0 # 0 +0x8AF3 0xADD1 # 0 +0x8AF4 0xADD2 # 0 +0x8AF5 0xADD3 # 0 +0x8AF6 0xADD4 # 0 +0x8AF7 0xADD5 # 0 +0x8AF8 0xADD6 # 0 +0x8AF9 0xADD7 # 0 +0x8AFA 0xADD8 # 0 +0x8AFB 0xADD9 # 0 +0x8AFC 0xADDA # 0 +0x8AFD 0xADDB # 0 +0x8B41 0xADDC # 0 +0x8B42 0xADDD # 0 +0x8B43 0xADDE # 0 +0x8B44 0xADDF # 0 +0x8B45 0xADE0 # 0 +0x8B46 0xADE1 # 0 +0x8B47 0xADE2 # 0 +0x8B48 0xADE3 # 0 +0x8B49 0xADE4 # 0 +0x8B4A 0xADE5 # 0 +0x8B4B 0xADE6 # 0 +0x8B4C 0xADE7 # 0 +0x8B4D 0xADE8 # 0 +0x8B4E 0xADE9 # 0 +0x8B4F 0xADEA # 0 +0x8B50 0xADEB # 0 +0x8B51 0xADEC # 0 +0x8B53 0xADED # 0 +0x8B54 0xADEE # 0 +0x8B55 0xADEF # 0 +0x8B56 0xADF0 # 0 +0x8B57 0xADF1 # 0 +0x8B58 0xADF2 # 0 +0x8B59 0xADF3 # 0 +0x8B5A 0xADF4 # 0 +0x8B5B 0xADF5 # 0 +0x8B5C 0xADF6 # 0 +0x8B5D 0xADF7 # 0 +0x8B61 0xADF8 # 0 +0x8B62 0xADF9 # 0 +0x8B63 0xADFA # 0 +0x8B64 0xADFB # 0 +0x8B65 0xADFC # 0 +0x8B66 0xADFD # 0 +0x8B67 0xADFE # 0 +0x8B68 0xADFF # 0 +0x8B69 0xAE00 # 0 +0x8B6A 0xAE01 # 0 +0x8B6B 0xAE02 # 0 +0x8B6C 0xAE03 # 0 +0x8B6D 0xAE04 # 0 +0x8B6E 0xAE05 # 0 +0x8B6F 0xAE06 # 0 +0x8B70 0xAE07 # 0 +0x8B71 0xAE08 # 0 +0x8B73 0xAE09 # 0 +0x8B74 0xAE0A # 0 +0x8B75 0xAE0B # 0 +0x8B76 0xAE0C # 0 +0x8B77 0xAE0D # 0 +0x8B78 0xAE0E # 0 +0x8B79 0xAE0F # 0 +0x8B7A 0xAE10 # 0 +0x8B7B 0xAE11 # 0 +0x8B7C 0xAE12 # 0 +0x8B7D 0xAE13 # 0 +0x8B81 0xAE14 # 0 +0x8B82 0xAE15 # 0 +0x8B83 0xAE16 # 0 +0x8B84 0xAE17 # 0 +0x8B85 0xAE18 # 0 +0x8B86 0xAE19 # 0 +0x8B87 0xAE1A # 0 +0x8B88 0xAE1B # 0 +0x8B89 0xAE1C # 0 +0x8B8A 0xAE1D # 0 +0x8B8B 0xAE1E # 0 +0x8B8C 0xAE1F # 0 +0x8B8D 0xAE20 # 0 +0x8B8E 0xAE21 # 0 +0x8B8F 0xAE22 # 0 +0x8B90 0xAE23 # 0 +0x8B91 0xAE24 # 0 +0x8B93 0xAE25 # 0 +0x8B94 0xAE26 # 0 +0x8B95 0xAE27 # 0 +0x8B96 0xAE28 # 0 +0x8B97 0xAE29 # 0 +0x8B98 0xAE2A # 0 +0x8B99 0xAE2B # 0 +0x8B9A 0xAE2C # 0 +0x8B9B 0xAE2D # 0 +0x8B9C 0xAE2E # 0 +0x8B9D 0xAE2F # 0 +0x8BA1 0xAE30 # 0 +0x8BA2 0xAE31 # 0 +0x8BA3 0xAE32 # 0 +0x8BA4 0xAE33 # 0 +0x8BA5 0xAE34 # 0 +0x8BA6 0xAE35 # 0 +0x8BA7 0xAE36 # 0 +0x8BA8 0xAE37 # 0 +0x8BA9 0xAE38 # 0 +0x8BAA 0xAE39 # 0 +0x8BAB 0xAE3A # 0 +0x8BAC 0xAE3B # 0 +0x8BAD 0xAE3C # 0 +0x8BAE 0xAE3D # 0 +0x8BAF 0xAE3E # 0 +0x8BB0 0xAE3F # 0 +0x8BB1 0xAE40 # 0 +0x8BB3 0xAE41 # 0 +0x8BB4 0xAE42 # 0 +0x8BB5 0xAE43 # 0 +0x8BB6 0xAE44 # 0 +0x8BB7 0xAE45 # 0 +0x8BB8 0xAE46 # 0 +0x8BB9 0xAE47 # 0 +0x8BBA 0xAE48 # 0 +0x8BBB 0xAE49 # 0 +0x8BBC 0xAE4A # 0 +0x8BBD 0xAE4B # 0 +0x8C41 0x1101 # 0 +0x8C61 0xAE4C # 0 +0x8C62 0xAE4D # 0 +0x8C63 0xAE4E # 0 +0x8C64 0xAE4F # 0 +0x8C65 0xAE50 # 0 +0x8C66 0xAE51 # 0 +0x8C67 0xAE52 # 0 +0x8C68 0xAE53 # 0 +0x8C69 0xAE54 # 0 +0x8C6A 0xAE55 # 0 +0x8C6B 0xAE56 # 0 +0x8C6C 0xAE57 # 0 +0x8C6D 0xAE58 # 0 +0x8C6E 0xAE59 # 0 +0x8C6F 0xAE5A # 0 +0x8C70 0xAE5B # 0 +0x8C71 0xAE5C # 0 +0x8C73 0xAE5D # 0 +0x8C74 0xAE5E # 0 +0x8C75 0xAE5F # 0 +0x8C76 0xAE60 # 0 +0x8C77 0xAE61 # 0 +0x8C78 0xAE62 # 0 +0x8C79 0xAE63 # 0 +0x8C7A 0xAE64 # 0 +0x8C7B 0xAE65 # 0 +0x8C7C 0xAE66 # 0 +0x8C7D 0xAE67 # 0 +0x8C81 0xAE68 # 0 +0x8C82 0xAE69 # 0 +0x8C83 0xAE6A # 0 +0x8C84 0xAE6B # 0 +0x8C85 0xAE6C # 0 +0x8C86 0xAE6D # 0 +0x8C87 0xAE6E # 0 +0x8C88 0xAE6F # 0 +0x8C89 0xAE70 # 0 +0x8C8A 0xAE71 # 0 +0x8C8B 0xAE72 # 0 +0x8C8C 0xAE73 # 0 +0x8C8D 0xAE74 # 0 +0x8C8E 0xAE75 # 0 +0x8C8F 0xAE76 # 0 +0x8C90 0xAE77 # 0 +0x8C91 0xAE78 # 0 +0x8C93 0xAE79 # 0 +0x8C94 0xAE7A # 0 +0x8C95 0xAE7B # 0 +0x8C96 0xAE7C # 0 +0x8C97 0xAE7D # 0 +0x8C98 0xAE7E # 0 +0x8C99 0xAE7F # 0 +0x8C9A 0xAE80 # 0 +0x8C9B 0xAE81 # 0 +0x8C9C 0xAE82 # 0 +0x8C9D 0xAE83 # 0 +0x8CA1 0xAE84 # 0 +0x8CA2 0xAE85 # 0 +0x8CA3 0xAE86 # 0 +0x8CA4 0xAE87 # 0 +0x8CA5 0xAE88 # 0 +0x8CA6 0xAE89 # 0 +0x8CA7 0xAE8A # 0 +0x8CA8 0xAE8B # 0 +0x8CA9 0xAE8C # 0 +0x8CAA 0xAE8D # 0 +0x8CAB 0xAE8E # 0 +0x8CAC 0xAE8F # 0 +0x8CAD 0xAE90 # 0 +0x8CAE 0xAE91 # 0 +0x8CAF 0xAE92 # 0 +0x8CB0 0xAE93 # 0 +0x8CB1 0xAE94 # 0 +0x8CB3 0xAE95 # 0 +0x8CB4 0xAE96 # 0 +0x8CB5 0xAE97 # 0 +0x8CB6 0xAE98 # 0 +0x8CB7 0xAE99 # 0 +0x8CB8 0xAE9A # 0 +0x8CB9 0xAE9B # 0 +0x8CBA 0xAE9C # 0 +0x8CBB 0xAE9D # 0 +0x8CBC 0xAE9E # 0 +0x8CBD 0xAE9F # 0 +0x8CC1 0xAEA0 # 0 +0x8CC2 0xAEA1 # 0 +0x8CC3 0xAEA2 # 0 +0x8CC4 0xAEA3 # 0 +0x8CC5 0xAEA4 # 0 +0x8CC6 0xAEA5 # 0 +0x8CC7 0xAEA6 # 0 +0x8CC8 0xAEA7 # 0 +0x8CC9 0xAEA8 # 0 +0x8CCA 0xAEA9 # 0 +0x8CCB 0xAEAA # 0 +0x8CCC 0xAEAB # 0 +0x8CCD 0xAEAC # 0 +0x8CCE 0xAEAD # 0 +0x8CCF 0xAEAE # 0 +0x8CD0 0xAEAF # 0 +0x8CD1 0xAEB0 # 0 +0x8CD3 0xAEB1 # 0 +0x8CD4 0xAEB2 # 0 +0x8CD5 0xAEB3 # 0 +0x8CD6 0xAEB4 # 0 +0x8CD7 0xAEB5 # 0 +0x8CD8 0xAEB6 # 0 +0x8CD9 0xAEB7 # 0 +0x8CDA 0xAEB8 # 0 +0x8CDB 0xAEB9 # 0 +0x8CDC 0xAEBA # 0 +0x8CDD 0xAEBB # 0 +0x8CE1 0xAEBC # 0 +0x8CE2 0xAEBD # 0 +0x8CE3 0xAEBE # 0 +0x8CE4 0xAEBF # 0 +0x8CE5 0xAEC0 # 0 +0x8CE6 0xAEC1 # 0 +0x8CE7 0xAEC2 # 0 +0x8CE8 0xAEC3 # 0 +0x8CE9 0xAEC4 # 0 +0x8CEA 0xAEC5 # 0 +0x8CEB 0xAEC6 # 0 +0x8CEC 0xAEC7 # 0 +0x8CED 0xAEC8 # 0 +0x8CEE 0xAEC9 # 0 +0x8CEF 0xAECA # 0 +0x8CF0 0xAECB # 0 +0x8CF1 0xAECC # 0 +0x8CF3 0xAECD # 0 +0x8CF4 0xAECE # 0 +0x8CF5 0xAECF # 0 +0x8CF6 0xAED0 # 0 +0x8CF7 0xAED1 # 0 +0x8CF8 0xAED2 # 0 +0x8CF9 0xAED3 # 0 +0x8CFA 0xAED4 # 0 +0x8CFB 0xAED5 # 0 +0x8CFC 0xAED6 # 0 +0x8CFD 0xAED7 # 0 +0x8D41 0xAED8 # 0 +0x8D42 0xAED9 # 0 +0x8D43 0xAEDA # 0 +0x8D44 0xAEDB # 0 +0x8D45 0xAEDC # 0 +0x8D46 0xAEDD # 0 +0x8D47 0xAEDE # 0 +0x8D48 0xAEDF # 0 +0x8D49 0xAEE0 # 0 +0x8D4A 0xAEE1 # 0 +0x8D4B 0xAEE2 # 0 +0x8D4C 0xAEE3 # 0 +0x8D4D 0xAEE4 # 0 +0x8D4E 0xAEE5 # 0 +0x8D4F 0xAEE6 # 0 +0x8D50 0xAEE7 # 0 +0x8D51 0xAEE8 # 0 +0x8D53 0xAEE9 # 0 +0x8D54 0xAEEA # 0 +0x8D55 0xAEEB # 0 +0x8D56 0xAEEC # 0 +0x8D57 0xAEED # 0 +0x8D58 0xAEEE # 0 +0x8D59 0xAEEF # 0 +0x8D5A 0xAEF0 # 0 +0x8D5B 0xAEF1 # 0 +0x8D5C 0xAEF2 # 0 +0x8D5D 0xAEF3 # 0 +0x8D61 0xAEF4 # 0 +0x8D62 0xAEF5 # 0 +0x8D63 0xAEF6 # 0 +0x8D64 0xAEF7 # 0 +0x8D65 0xAEF8 # 0 +0x8D66 0xAEF9 # 0 +0x8D67 0xAEFA # 0 +0x8D68 0xAEFB # 0 +0x8D69 0xAEFC # 0 +0x8D6A 0xAEFD # 0 +0x8D6B 0xAEFE # 0 +0x8D6C 0xAEFF # 0 +0x8D6D 0xAF00 # 0 +0x8D6E 0xAF01 # 0 +0x8D6F 0xAF02 # 0 +0x8D70 0xAF03 # 0 +0x8D71 0xAF04 # 0 +0x8D73 0xAF05 # 0 +0x8D74 0xAF06 # 0 +0x8D75 0xAF07 # 0 +0x8D76 0xAF08 # 0 +0x8D77 0xAF09 # 0 +0x8D78 0xAF0A # 0 +0x8D79 0xAF0B # 0 +0x8D7A 0xAF0C # 0 +0x8D7B 0xAF0D # 0 +0x8D7C 0xAF0E # 0 +0x8D7D 0xAF0F # 0 +0x8D81 0xAF10 # 0 +0x8D82 0xAF11 # 0 +0x8D83 0xAF12 # 0 +0x8D84 0xAF13 # 0 +0x8D85 0xAF14 # 0 +0x8D86 0xAF15 # 0 +0x8D87 0xAF16 # 0 +0x8D88 0xAF17 # 0 +0x8D89 0xAF18 # 0 +0x8D8A 0xAF19 # 0 +0x8D8B 0xAF1A # 0 +0x8D8C 0xAF1B # 0 +0x8D8D 0xAF1C # 0 +0x8D8E 0xAF1D # 0 +0x8D8F 0xAF1E # 0 +0x8D90 0xAF1F # 0 +0x8D91 0xAF20 # 0 +0x8D93 0xAF21 # 0 +0x8D94 0xAF22 # 0 +0x8D95 0xAF23 # 0 +0x8D96 0xAF24 # 0 +0x8D97 0xAF25 # 0 +0x8D98 0xAF26 # 0 +0x8D99 0xAF27 # 0 +0x8D9A 0xAF28 # 0 +0x8D9B 0xAF29 # 0 +0x8D9C 0xAF2A # 0 +0x8D9D 0xAF2B # 0 +0x8DA1 0xAF2C # 0 +0x8DA2 0xAF2D # 0 +0x8DA3 0xAF2E # 0 +0x8DA4 0xAF2F # 0 +0x8DA5 0xAF30 # 0 +0x8DA6 0xAF31 # 0 +0x8DA7 0xAF32 # 0 +0x8DA8 0xAF33 # 0 +0x8DA9 0xAF34 # 0 +0x8DAA 0xAF35 # 0 +0x8DAB 0xAF36 # 0 +0x8DAC 0xAF37 # 0 +0x8DAD 0xAF38 # 0 +0x8DAE 0xAF39 # 0 +0x8DAF 0xAF3A # 0 +0x8DB0 0xAF3B # 0 +0x8DB1 0xAF3C # 0 +0x8DB3 0xAF3D # 0 +0x8DB4 0xAF3E # 0 +0x8DB5 0xAF3F # 0 +0x8DB6 0xAF40 # 0 +0x8DB7 0xAF41 # 0 +0x8DB8 0xAF42 # 0 +0x8DB9 0xAF43 # 0 +0x8DBA 0xAF44 # 0 +0x8DBB 0xAF45 # 0 +0x8DBC 0xAF46 # 0 +0x8DBD 0xAF47 # 0 +0x8DC1 0xAF48 # 0 +0x8DC2 0xAF49 # 0 +0x8DC3 0xAF4A # 0 +0x8DC4 0xAF4B # 0 +0x8DC5 0xAF4C # 0 +0x8DC6 0xAF4D # 0 +0x8DC7 0xAF4E # 0 +0x8DC8 0xAF4F # 0 +0x8DC9 0xAF50 # 0 +0x8DCA 0xAF51 # 0 +0x8DCB 0xAF52 # 0 +0x8DCC 0xAF53 # 0 +0x8DCD 0xAF54 # 0 +0x8DCE 0xAF55 # 0 +0x8DCF 0xAF56 # 0 +0x8DD0 0xAF57 # 0 +0x8DD1 0xAF58 # 0 +0x8DD3 0xAF59 # 0 +0x8DD4 0xAF5A # 0 +0x8DD5 0xAF5B # 0 +0x8DD6 0xAF5C # 0 +0x8DD7 0xAF5D # 0 +0x8DD8 0xAF5E # 0 +0x8DD9 0xAF5F # 0 +0x8DDA 0xAF60 # 0 +0x8DDB 0xAF61 # 0 +0x8DDC 0xAF62 # 0 +0x8DDD 0xAF63 # 0 +0x8DE1 0xAF64 # 0 +0x8DE2 0xAF65 # 0 +0x8DE3 0xAF66 # 0 +0x8DE4 0xAF67 # 0 +0x8DE5 0xAF68 # 0 +0x8DE6 0xAF69 # 0 +0x8DE7 0xAF6A # 0 +0x8DE8 0xAF6B # 0 +0x8DE9 0xAF6C # 0 +0x8DEA 0xAF6D # 0 +0x8DEB 0xAF6E # 0 +0x8DEC 0xAF6F # 0 +0x8DED 0xAF70 # 0 +0x8DEE 0xAF71 # 0 +0x8DEF 0xAF72 # 0 +0x8DF0 0xAF73 # 0 +0x8DF1 0xAF74 # 0 +0x8DF3 0xAF75 # 0 +0x8DF4 0xAF76 # 0 +0x8DF5 0xAF77 # 0 +0x8DF6 0xAF78 # 0 +0x8DF7 0xAF79 # 0 +0x8DF8 0xAF7A # 0 +0x8DF9 0xAF7B # 0 +0x8DFA 0xAF7C # 0 +0x8DFB 0xAF7D # 0 +0x8DFC 0xAF7E # 0 +0x8DFD 0xAF7F # 0 +0x8E41 0xAF80 # 0 +0x8E42 0xAF81 # 0 +0x8E43 0xAF82 # 0 +0x8E44 0xAF83 # 0 +0x8E45 0xAF84 # 0 +0x8E46 0xAF85 # 0 +0x8E47 0xAF86 # 0 +0x8E48 0xAF87 # 0 +0x8E49 0xAF88 # 0 +0x8E4A 0xAF89 # 0 +0x8E4B 0xAF8A # 0 +0x8E4C 0xAF8B # 0 +0x8E4D 0xAF8C # 0 +0x8E4E 0xAF8D # 0 +0x8E4F 0xAF8E # 0 +0x8E50 0xAF8F # 0 +0x8E51 0xAF90 # 0 +0x8E53 0xAF91 # 0 +0x8E54 0xAF92 # 0 +0x8E55 0xAF93 # 0 +0x8E56 0xAF94 # 0 +0x8E57 0xAF95 # 0 +0x8E58 0xAF96 # 0 +0x8E59 0xAF97 # 0 +0x8E5A 0xAF98 # 0 +0x8E5B 0xAF99 # 0 +0x8E5C 0xAF9A # 0 +0x8E5D 0xAF9B # 0 +0x8E61 0xAF9C # 0 +0x8E62 0xAF9D # 0 +0x8E63 0xAF9E # 0 +0x8E64 0xAF9F # 0 +0x8E65 0xAFA0 # 0 +0x8E66 0xAFA1 # 0 +0x8E67 0xAFA2 # 0 +0x8E68 0xAFA3 # 0 +0x8E69 0xAFA4 # 0 +0x8E6A 0xAFA5 # 0 +0x8E6B 0xAFA6 # 0 +0x8E6C 0xAFA7 # 0 +0x8E6D 0xAFA8 # 0 +0x8E6E 0xAFA9 # 0 +0x8E6F 0xAFAA # 0 +0x8E70 0xAFAB # 0 +0x8E71 0xAFAC # 0 +0x8E73 0xAFAD # 0 +0x8E74 0xAFAE # 0 +0x8E75 0xAFAF # 0 +0x8E76 0xAFB0 # 0 +0x8E77 0xAFB1 # 0 +0x8E78 0xAFB2 # 0 +0x8E79 0xAFB3 # 0 +0x8E7A 0xAFB4 # 0 +0x8E7B 0xAFB5 # 0 +0x8E7C 0xAFB6 # 0 +0x8E7D 0xAFB7 # 0 +0x8E81 0xAFB8 # 0 +0x8E82 0xAFB9 # 0 +0x8E83 0xAFBA # 0 +0x8E84 0xAFBB # 0 +0x8E85 0xAFBC # 0 +0x8E86 0xAFBD # 0 +0x8E87 0xAFBE # 0 +0x8E88 0xAFBF # 0 +0x8E89 0xAFC0 # 0 +0x8E8A 0xAFC1 # 0 +0x8E8B 0xAFC2 # 0 +0x8E8C 0xAFC3 # 0 +0x8E8D 0xAFC4 # 0 +0x8E8E 0xAFC5 # 0 +0x8E8F 0xAFC6 # 0 +0x8E90 0xAFC7 # 0 +0x8E91 0xAFC8 # 0 +0x8E93 0xAFC9 # 0 +0x8E94 0xAFCA # 0 +0x8E95 0xAFCB # 0 +0x8E96 0xAFCC # 0 +0x8E97 0xAFCD # 0 +0x8E98 0xAFCE # 0 +0x8E99 0xAFCF # 0 +0x8E9A 0xAFD0 # 0 +0x8E9B 0xAFD1 # 0 +0x8E9C 0xAFD2 # 0 +0x8E9D 0xAFD3 # 0 +0x8EA1 0xAFD4 # 0 +0x8EA2 0xAFD5 # 0 +0x8EA3 0xAFD6 # 0 +0x8EA4 0xAFD7 # 0 +0x8EA5 0xAFD8 # 0 +0x8EA6 0xAFD9 # 0 +0x8EA7 0xAFDA # 0 +0x8EA8 0xAFDB # 0 +0x8EA9 0xAFDC # 0 +0x8EAA 0xAFDD # 0 +0x8EAB 0xAFDE # 0 +0x8EAC 0xAFDF # 0 +0x8EAD 0xAFE0 # 0 +0x8EAE 0xAFE1 # 0 +0x8EAF 0xAFE2 # 0 +0x8EB0 0xAFE3 # 0 +0x8EB1 0xAFE4 # 0 +0x8EB3 0xAFE5 # 0 +0x8EB4 0xAFE6 # 0 +0x8EB5 0xAFE7 # 0 +0x8EB6 0xAFE8 # 0 +0x8EB7 0xAFE9 # 0 +0x8EB8 0xAFEA # 0 +0x8EB9 0xAFEB # 0 +0x8EBA 0xAFEC # 0 +0x8EBB 0xAFED # 0 +0x8EBC 0xAFEE # 0 +0x8EBD 0xAFEF # 0 +0x8EC1 0xAFF0 # 0 +0x8EC2 0xAFF1 # 0 +0x8EC3 0xAFF2 # 0 +0x8EC4 0xAFF3 # 0 +0x8EC5 0xAFF4 # 0 +0x8EC6 0xAFF5 # 0 +0x8EC7 0xAFF6 # 0 +0x8EC8 0xAFF7 # 0 +0x8EC9 0xAFF8 # 0 +0x8ECA 0xAFF9 # 0 +0x8ECB 0xAFFA # 0 +0x8ECC 0xAFFB # 0 +0x8ECD 0xAFFC # 0 +0x8ECE 0xAFFD # 0 +0x8ECF 0xAFFE # 0 +0x8ED0 0xAFFF # 0 +0x8ED1 0xB000 # 0 +0x8ED3 0xB001 # 0 +0x8ED4 0xB002 # 0 +0x8ED5 0xB003 # 0 +0x8ED6 0xB004 # 0 +0x8ED7 0xB005 # 0 +0x8ED8 0xB006 # 0 +0x8ED9 0xB007 # 0 +0x8EDA 0xB008 # 0 +0x8EDB 0xB009 # 0 +0x8EDC 0xB00A # 0 +0x8EDD 0xB00B # 0 +0x8EE1 0xB00C # 0 +0x8EE2 0xB00D # 0 +0x8EE3 0xB00E # 0 +0x8EE4 0xB00F # 0 +0x8EE5 0xB010 # 0 +0x8EE6 0xB011 # 0 +0x8EE7 0xB012 # 0 +0x8EE8 0xB013 # 0 +0x8EE9 0xB014 # 0 +0x8EEA 0xB015 # 0 +0x8EEB 0xB016 # 0 +0x8EEC 0xB017 # 0 +0x8EED 0xB018 # 0 +0x8EEE 0xB019 # 0 +0x8EEF 0xB01A # 0 +0x8EF0 0xB01B # 0 +0x8EF1 0xB01C # 0 +0x8EF3 0xB01D # 0 +0x8EF4 0xB01E # 0 +0x8EF5 0xB01F # 0 +0x8EF6 0xB020 # 0 +0x8EF7 0xB021 # 0 +0x8EF8 0xB022 # 0 +0x8EF9 0xB023 # 0 +0x8EFA 0xB024 # 0 +0x8EFB 0xB025 # 0 +0x8EFC 0xB026 # 0 +0x8EFD 0xB027 # 0 +0x8F41 0xB028 # 0 +0x8F42 0xB029 # 0 +0x8F43 0xB02A # 0 +0x8F44 0xB02B # 0 +0x8F45 0xB02C # 0 +0x8F46 0xB02D # 0 +0x8F47 0xB02E # 0 +0x8F48 0xB02F # 0 +0x8F49 0xB030 # 0 +0x8F4A 0xB031 # 0 +0x8F4B 0xB032 # 0 +0x8F4C 0xB033 # 0 +0x8F4D 0xB034 # 0 +0x8F4E 0xB035 # 0 +0x8F4F 0xB036 # 0 +0x8F50 0xB037 # 0 +0x8F51 0xB038 # 0 +0x8F53 0xB039 # 0 +0x8F54 0xB03A # 0 +0x8F55 0xB03B # 0 +0x8F56 0xB03C # 0 +0x8F57 0xB03D # 0 +0x8F58 0xB03E # 0 +0x8F59 0xB03F # 0 +0x8F5A 0xB040 # 0 +0x8F5B 0xB041 # 0 +0x8F5C 0xB042 # 0 +0x8F5D 0xB043 # 0 +0x8F61 0xB044 # 0 +0x8F62 0xB045 # 0 +0x8F63 0xB046 # 0 +0x8F64 0xB047 # 0 +0x8F65 0xB048 # 0 +0x8F66 0xB049 # 0 +0x8F67 0xB04A # 0 +0x8F68 0xB04B # 0 +0x8F69 0xB04C # 0 +0x8F6A 0xB04D # 0 +0x8F6B 0xB04E # 0 +0x8F6C 0xB04F # 0 +0x8F6D 0xB050 # 0 +0x8F6E 0xB051 # 0 +0x8F6F 0xB052 # 0 +0x8F70 0xB053 # 0 +0x8F71 0xB054 # 0 +0x8F73 0xB055 # 0 +0x8F74 0xB056 # 0 +0x8F75 0xB057 # 0 +0x8F76 0xB058 # 0 +0x8F77 0xB059 # 0 +0x8F78 0xB05A # 0 +0x8F79 0xB05B # 0 +0x8F7A 0xB05C # 0 +0x8F7B 0xB05D # 0 +0x8F7C 0xB05E # 0 +0x8F7D 0xB05F # 0 +0x8F81 0xB060 # 0 +0x8F82 0xB061 # 0 +0x8F83 0xB062 # 0 +0x8F84 0xB063 # 0 +0x8F85 0xB064 # 0 +0x8F86 0xB065 # 0 +0x8F87 0xB066 # 0 +0x8F88 0xB067 # 0 +0x8F89 0xB068 # 0 +0x8F8A 0xB069 # 0 +0x8F8B 0xB06A # 0 +0x8F8C 0xB06B # 0 +0x8F8D 0xB06C # 0 +0x8F8E 0xB06D # 0 +0x8F8F 0xB06E # 0 +0x8F90 0xB06F # 0 +0x8F91 0xB070 # 0 +0x8F93 0xB071 # 0 +0x8F94 0xB072 # 0 +0x8F95 0xB073 # 0 +0x8F96 0xB074 # 0 +0x8F97 0xB075 # 0 +0x8F98 0xB076 # 0 +0x8F99 0xB077 # 0 +0x8F9A 0xB078 # 0 +0x8F9B 0xB079 # 0 +0x8F9C 0xB07A # 0 +0x8F9D 0xB07B # 0 +0x8FA1 0xB07C # 0 +0x8FA2 0xB07D # 0 +0x8FA3 0xB07E # 0 +0x8FA4 0xB07F # 0 +0x8FA5 0xB080 # 0 +0x8FA6 0xB081 # 0 +0x8FA7 0xB082 # 0 +0x8FA8 0xB083 # 0 +0x8FA9 0xB084 # 0 +0x8FAA 0xB085 # 0 +0x8FAB 0xB086 # 0 +0x8FAC 0xB087 # 0 +0x8FAD 0xB088 # 0 +0x8FAE 0xB089 # 0 +0x8FAF 0xB08A # 0 +0x8FB0 0xB08B # 0 +0x8FB1 0xB08C # 0 +0x8FB3 0xB08D # 0 +0x8FB4 0xB08E # 0 +0x8FB5 0xB08F # 0 +0x8FB6 0xB090 # 0 +0x8FB7 0xB091 # 0 +0x8FB8 0xB092 # 0 +0x8FB9 0xB093 # 0 +0x8FBA 0xB094 # 0 +0x8FBB 0xB095 # 0 +0x8FBC 0xB096 # 0 +0x8FBD 0xB097 # 0 +0x9041 0x1102 # 0 +0x9061 0xB098 # 0 +0x9062 0xB099 # 0 +0x9063 0xB09A # 0 +0x9064 0xB09B # 0 +0x9065 0xB09C # 0 +0x9066 0xB09D # 0 +0x9067 0xB09E # 0 +0x9068 0xB09F # 0 +0x9069 0xB0A0 # 0 +0x906A 0xB0A1 # 0 +0x906B 0xB0A2 # 0 +0x906C 0xB0A3 # 0 +0x906D 0xB0A4 # 0 +0x906E 0xB0A5 # 0 +0x906F 0xB0A6 # 0 +0x9070 0xB0A7 # 0 +0x9071 0xB0A8 # 0 +0x9073 0xB0A9 # 0 +0x9074 0xB0AA # 0 +0x9075 0xB0AB # 0 +0x9076 0xB0AC # 0 +0x9077 0xB0AD # 0 +0x9078 0xB0AE # 0 +0x9079 0xB0AF # 0 +0x907A 0xB0B0 # 0 +0x907B 0xB0B1 # 0 +0x907C 0xB0B2 # 0 +0x907D 0xB0B3 # 0 +0x9081 0xB0B4 # 0 +0x9082 0xB0B5 # 0 +0x9083 0xB0B6 # 0 +0x9084 0xB0B7 # 0 +0x9085 0xB0B8 # 0 +0x9086 0xB0B9 # 0 +0x9087 0xB0BA # 0 +0x9088 0xB0BB # 0 +0x9089 0xB0BC # 0 +0x908A 0xB0BD # 0 +0x908B 0xB0BE # 0 +0x908C 0xB0BF # 0 +0x908D 0xB0C0 # 0 +0x908E 0xB0C1 # 0 +0x908F 0xB0C2 # 0 +0x9090 0xB0C3 # 0 +0x9091 0xB0C4 # 0 +0x9093 0xB0C5 # 0 +0x9094 0xB0C6 # 0 +0x9095 0xB0C7 # 0 +0x9096 0xB0C8 # 0 +0x9097 0xB0C9 # 0 +0x9098 0xB0CA # 0 +0x9099 0xB0CB # 0 +0x909A 0xB0CC # 0 +0x909B 0xB0CD # 0 +0x909C 0xB0CE # 0 +0x909D 0xB0CF # 0 +0x90A1 0xB0D0 # 0 +0x90A2 0xB0D1 # 0 +0x90A3 0xB0D2 # 0 +0x90A4 0xB0D3 # 0 +0x90A5 0xB0D4 # 0 +0x90A6 0xB0D5 # 0 +0x90A7 0xB0D6 # 0 +0x90A8 0xB0D7 # 0 +0x90A9 0xB0D8 # 0 +0x90AA 0xB0D9 # 0 +0x90AB 0xB0DA # 0 +0x90AC 0xB0DB # 0 +0x90AD 0xB0DC # 0 +0x90AE 0xB0DD # 0 +0x90AF 0xB0DE # 0 +0x90B0 0xB0DF # 0 +0x90B1 0xB0E0 # 0 +0x90B3 0xB0E1 # 0 +0x90B4 0xB0E2 # 0 +0x90B5 0xB0E3 # 0 +0x90B6 0xB0E4 # 0 +0x90B7 0xB0E5 # 0 +0x90B8 0xB0E6 # 0 +0x90B9 0xB0E7 # 0 +0x90BA 0xB0E8 # 0 +0x90BB 0xB0E9 # 0 +0x90BC 0xB0EA # 0 +0x90BD 0xB0EB # 0 +0x90C1 0xB0EC # 0 +0x90C2 0xB0ED # 0 +0x90C3 0xB0EE # 0 +0x90C4 0xB0EF # 0 +0x90C5 0xB0F0 # 0 +0x90C6 0xB0F1 # 0 +0x90C7 0xB0F2 # 0 +0x90C8 0xB0F3 # 0 +0x90C9 0xB0F4 # 0 +0x90CA 0xB0F5 # 0 +0x90CB 0xB0F6 # 0 +0x90CC 0xB0F7 # 0 +0x90CD 0xB0F8 # 0 +0x90CE 0xB0F9 # 0 +0x90CF 0xB0FA # 0 +0x90D0 0xB0FB # 0 +0x90D1 0xB0FC # 0 +0x90D3 0xB0FD # 0 +0x90D4 0xB0FE # 0 +0x90D5 0xB0FF # 0 +0x90D6 0xB100 # 0 +0x90D7 0xB101 # 0 +0x90D8 0xB102 # 0 +0x90D9 0xB103 # 0 +0x90DA 0xB104 # 0 +0x90DB 0xB105 # 0 +0x90DC 0xB106 # 0 +0x90DD 0xB107 # 0 +0x90E1 0xB108 # 0 +0x90E2 0xB109 # 0 +0x90E3 0xB10A # 0 +0x90E4 0xB10B # 0 +0x90E5 0xB10C # 0 +0x90E6 0xB10D # 0 +0x90E7 0xB10E # 0 +0x90E8 0xB10F # 0 +0x90E9 0xB110 # 0 +0x90EA 0xB111 # 0 +0x90EB 0xB112 # 0 +0x90EC 0xB113 # 0 +0x90ED 0xB114 # 0 +0x90EE 0xB115 # 0 +0x90EF 0xB116 # 0 +0x90F0 0xB117 # 0 +0x90F1 0xB118 # 0 +0x90F3 0xB119 # 0 +0x90F4 0xB11A # 0 +0x90F5 0xB11B # 0 +0x90F6 0xB11C # 0 +0x90F7 0xB11D # 0 +0x90F8 0xB11E # 0 +0x90F9 0xB11F # 0 +0x90FA 0xB120 # 0 +0x90FB 0xB121 # 0 +0x90FC 0xB122 # 0 +0x90FD 0xB123 # 0 +0x9141 0xB124 # 0 +0x9142 0xB125 # 0 +0x9143 0xB126 # 0 +0x9144 0xB127 # 0 +0x9145 0xB128 # 0 +0x9146 0xB129 # 0 +0x9147 0xB12A # 0 +0x9148 0xB12B # 0 +0x9149 0xB12C # 0 +0x914A 0xB12D # 0 +0x914B 0xB12E # 0 +0x914C 0xB12F # 0 +0x914D 0xB130 # 0 +0x914E 0xB131 # 0 +0x914F 0xB132 # 0 +0x9150 0xB133 # 0 +0x9151 0xB134 # 0 +0x9153 0xB135 # 0 +0x9154 0xB136 # 0 +0x9155 0xB137 # 0 +0x9156 0xB138 # 0 +0x9157 0xB139 # 0 +0x9158 0xB13A # 0 +0x9159 0xB13B # 0 +0x915A 0xB13C # 0 +0x915B 0xB13D # 0 +0x915C 0xB13E # 0 +0x915D 0xB13F # 0 +0x9161 0xB140 # 0 +0x9162 0xB141 # 0 +0x9163 0xB142 # 0 +0x9164 0xB143 # 0 +0x9165 0xB144 # 0 +0x9166 0xB145 # 0 +0x9167 0xB146 # 0 +0x9168 0xB147 # 0 +0x9169 0xB148 # 0 +0x916A 0xB149 # 0 +0x916B 0xB14A # 0 +0x916C 0xB14B # 0 +0x916D 0xB14C # 0 +0x916E 0xB14D # 0 +0x916F 0xB14E # 0 +0x9170 0xB14F # 0 +0x9171 0xB150 # 0 +0x9173 0xB151 # 0 +0x9174 0xB152 # 0 +0x9175 0xB153 # 0 +0x9176 0xB154 # 0 +0x9177 0xB155 # 0 +0x9178 0xB156 # 0 +0x9179 0xB157 # 0 +0x917A 0xB158 # 0 +0x917B 0xB159 # 0 +0x917C 0xB15A # 0 +0x917D 0xB15B # 0 +0x9181 0xB15C # 0 +0x9182 0xB15D # 0 +0x9183 0xB15E # 0 +0x9184 0xB15F # 0 +0x9185 0xB160 # 0 +0x9186 0xB161 # 0 +0x9187 0xB162 # 0 +0x9188 0xB163 # 0 +0x9189 0xB164 # 0 +0x918A 0xB165 # 0 +0x918B 0xB166 # 0 +0x918C 0xB167 # 0 +0x918D 0xB168 # 0 +0x918E 0xB169 # 0 +0x918F 0xB16A # 0 +0x9190 0xB16B # 0 +0x9191 0xB16C # 0 +0x9193 0xB16D # 0 +0x9194 0xB16E # 0 +0x9195 0xB16F # 0 +0x9196 0xB170 # 0 +0x9197 0xB171 # 0 +0x9198 0xB172 # 0 +0x9199 0xB173 # 0 +0x919A 0xB174 # 0 +0x919B 0xB175 # 0 +0x919C 0xB176 # 0 +0x919D 0xB177 # 0 +0x91A1 0xB178 # 0 +0x91A2 0xB179 # 0 +0x91A3 0xB17A # 0 +0x91A4 0xB17B # 0 +0x91A5 0xB17C # 0 +0x91A6 0xB17D # 0 +0x91A7 0xB17E # 0 +0x91A8 0xB17F # 0 +0x91A9 0xB180 # 0 +0x91AA 0xB181 # 0 +0x91AB 0xB182 # 0 +0x91AC 0xB183 # 0 +0x91AD 0xB184 # 0 +0x91AE 0xB185 # 0 +0x91AF 0xB186 # 0 +0x91B0 0xB187 # 0 +0x91B1 0xB188 # 0 +0x91B3 0xB189 # 0 +0x91B4 0xB18A # 0 +0x91B5 0xB18B # 0 +0x91B6 0xB18C # 0 +0x91B7 0xB18D # 0 +0x91B8 0xB18E # 0 +0x91B9 0xB18F # 0 +0x91BA 0xB190 # 0 +0x91BB 0xB191 # 0 +0x91BC 0xB192 # 0 +0x91BD 0xB193 # 0 +0x91C1 0xB194 # 0 +0x91C2 0xB195 # 0 +0x91C3 0xB196 # 0 +0x91C4 0xB197 # 0 +0x91C5 0xB198 # 0 +0x91C6 0xB199 # 0 +0x91C7 0xB19A # 0 +0x91C8 0xB19B # 0 +0x91C9 0xB19C # 0 +0x91CA 0xB19D # 0 +0x91CB 0xB19E # 0 +0x91CC 0xB19F # 0 +0x91CD 0xB1A0 # 0 +0x91CE 0xB1A1 # 0 +0x91CF 0xB1A2 # 0 +0x91D0 0xB1A3 # 0 +0x91D1 0xB1A4 # 0 +0x91D3 0xB1A5 # 0 +0x91D4 0xB1A6 # 0 +0x91D5 0xB1A7 # 0 +0x91D6 0xB1A8 # 0 +0x91D7 0xB1A9 # 0 +0x91D8 0xB1AA # 0 +0x91D9 0xB1AB # 0 +0x91DA 0xB1AC # 0 +0x91DB 0xB1AD # 0 +0x91DC 0xB1AE # 0 +0x91DD 0xB1AF # 0 +0x91E1 0xB1B0 # 0 +0x91E2 0xB1B1 # 0 +0x91E3 0xB1B2 # 0 +0x91E4 0xB1B3 # 0 +0x91E5 0xB1B4 # 0 +0x91E6 0xB1B5 # 0 +0x91E7 0xB1B6 # 0 +0x91E8 0xB1B7 # 0 +0x91E9 0xB1B8 # 0 +0x91EA 0xB1B9 # 0 +0x91EB 0xB1BA # 0 +0x91EC 0xB1BB # 0 +0x91ED 0xB1BC # 0 +0x91EE 0xB1BD # 0 +0x91EF 0xB1BE # 0 +0x91F0 0xB1BF # 0 +0x91F1 0xB1C0 # 0 +0x91F3 0xB1C1 # 0 +0x91F4 0xB1C2 # 0 +0x91F5 0xB1C3 # 0 +0x91F6 0xB1C4 # 0 +0x91F7 0xB1C5 # 0 +0x91F8 0xB1C6 # 0 +0x91F9 0xB1C7 # 0 +0x91FA 0xB1C8 # 0 +0x91FB 0xB1C9 # 0 +0x91FC 0xB1CA # 0 +0x91FD 0xB1CB # 0 +0x9241 0xB1CC # 0 +0x9242 0xB1CD # 0 +0x9243 0xB1CE # 0 +0x9244 0xB1CF # 0 +0x9245 0xB1D0 # 0 +0x9246 0xB1D1 # 0 +0x9247 0xB1D2 # 0 +0x9248 0xB1D3 # 0 +0x9249 0xB1D4 # 0 +0x924A 0xB1D5 # 0 +0x924B 0xB1D6 # 0 +0x924C 0xB1D7 # 0 +0x924D 0xB1D8 # 0 +0x924E 0xB1D9 # 0 +0x924F 0xB1DA # 0 +0x9250 0xB1DB # 0 +0x9251 0xB1DC # 0 +0x9253 0xB1DD # 0 +0x9254 0xB1DE # 0 +0x9255 0xB1DF # 0 +0x9256 0xB1E0 # 0 +0x9257 0xB1E1 # 0 +0x9258 0xB1E2 # 0 +0x9259 0xB1E3 # 0 +0x925A 0xB1E4 # 0 +0x925B 0xB1E5 # 0 +0x925C 0xB1E6 # 0 +0x925D 0xB1E7 # 0 +0x9261 0xB1E8 # 0 +0x9262 0xB1E9 # 0 +0x9263 0xB1EA # 0 +0x9264 0xB1EB # 0 +0x9265 0xB1EC # 0 +0x9266 0xB1ED # 0 +0x9267 0xB1EE # 0 +0x9268 0xB1EF # 0 +0x9269 0xB1F0 # 0 +0x926A 0xB1F1 # 0 +0x926B 0xB1F2 # 0 +0x926C 0xB1F3 # 0 +0x926D 0xB1F4 # 0 +0x926E 0xB1F5 # 0 +0x926F 0xB1F6 # 0 +0x9270 0xB1F7 # 0 +0x9271 0xB1F8 # 0 +0x9273 0xB1F9 # 0 +0x9274 0xB1FA # 0 +0x9275 0xB1FB # 0 +0x9276 0xB1FC # 0 +0x9277 0xB1FD # 0 +0x9278 0xB1FE # 0 +0x9279 0xB1FF # 0 +0x927A 0xB200 # 0 +0x927B 0xB201 # 0 +0x927C 0xB202 # 0 +0x927D 0xB203 # 0 +0x9281 0xB204 # 0 +0x9282 0xB205 # 0 +0x9283 0xB206 # 0 +0x9284 0xB207 # 0 +0x9285 0xB208 # 0 +0x9286 0xB209 # 0 +0x9287 0xB20A # 0 +0x9288 0xB20B # 0 +0x9289 0xB20C # 0 +0x928A 0xB20D # 0 +0x928B 0xB20E # 0 +0x928C 0xB20F # 0 +0x928D 0xB210 # 0 +0x928E 0xB211 # 0 +0x928F 0xB212 # 0 +0x9290 0xB213 # 0 +0x9291 0xB214 # 0 +0x9293 0xB215 # 0 +0x9294 0xB216 # 0 +0x9295 0xB217 # 0 +0x9296 0xB218 # 0 +0x9297 0xB219 # 0 +0x9298 0xB21A # 0 +0x9299 0xB21B # 0 +0x929A 0xB21C # 0 +0x929B 0xB21D # 0 +0x929C 0xB21E # 0 +0x929D 0xB21F # 0 +0x92A1 0xB220 # 0 +0x92A2 0xB221 # 0 +0x92A3 0xB222 # 0 +0x92A4 0xB223 # 0 +0x92A5 0xB224 # 0 +0x92A6 0xB225 # 0 +0x92A7 0xB226 # 0 +0x92A8 0xB227 # 0 +0x92A9 0xB228 # 0 +0x92AA 0xB229 # 0 +0x92AB 0xB22A # 0 +0x92AC 0xB22B # 0 +0x92AD 0xB22C # 0 +0x92AE 0xB22D # 0 +0x92AF 0xB22E # 0 +0x92B0 0xB22F # 0 +0x92B1 0xB230 # 0 +0x92B3 0xB231 # 0 +0x92B4 0xB232 # 0 +0x92B5 0xB233 # 0 +0x92B6 0xB234 # 0 +0x92B7 0xB235 # 0 +0x92B8 0xB236 # 0 +0x92B9 0xB237 # 0 +0x92BA 0xB238 # 0 +0x92BB 0xB239 # 0 +0x92BC 0xB23A # 0 +0x92BD 0xB23B # 0 +0x92C1 0xB23C # 0 +0x92C2 0xB23D # 0 +0x92C3 0xB23E # 0 +0x92C4 0xB23F # 0 +0x92C5 0xB240 # 0 +0x92C6 0xB241 # 0 +0x92C7 0xB242 # 0 +0x92C8 0xB243 # 0 +0x92C9 0xB244 # 0 +0x92CA 0xB245 # 0 +0x92CB 0xB246 # 0 +0x92CC 0xB247 # 0 +0x92CD 0xB248 # 0 +0x92CE 0xB249 # 0 +0x92CF 0xB24A # 0 +0x92D0 0xB24B # 0 +0x92D1 0xB24C # 0 +0x92D3 0xB24D # 0 +0x92D4 0xB24E # 0 +0x92D5 0xB24F # 0 +0x92D6 0xB250 # 0 +0x92D7 0xB251 # 0 +0x92D8 0xB252 # 0 +0x92D9 0xB253 # 0 +0x92DA 0xB254 # 0 +0x92DB 0xB255 # 0 +0x92DC 0xB256 # 0 +0x92DD 0xB257 # 0 +0x92E1 0xB258 # 0 +0x92E2 0xB259 # 0 +0x92E3 0xB25A # 0 +0x92E4 0xB25B # 0 +0x92E5 0xB25C # 0 +0x92E6 0xB25D # 0 +0x92E7 0xB25E # 0 +0x92E8 0xB25F # 0 +0x92E9 0xB260 # 0 +0x92EA 0xB261 # 0 +0x92EB 0xB262 # 0 +0x92EC 0xB263 # 0 +0x92ED 0xB264 # 0 +0x92EE 0xB265 # 0 +0x92EF 0xB266 # 0 +0x92F0 0xB267 # 0 +0x92F1 0xB268 # 0 +0x92F3 0xB269 # 0 +0x92F4 0xB26A # 0 +0x92F5 0xB26B # 0 +0x92F6 0xB26C # 0 +0x92F7 0xB26D # 0 +0x92F8 0xB26E # 0 +0x92F9 0xB26F # 0 +0x92FA 0xB270 # 0 +0x92FB 0xB271 # 0 +0x92FC 0xB272 # 0 +0x92FD 0xB273 # 0 +0x9341 0xB274 # 0 +0x9342 0xB275 # 0 +0x9343 0xB276 # 0 +0x9344 0xB277 # 0 +0x9345 0xB278 # 0 +0x9346 0xB279 # 0 +0x9347 0xB27A # 0 +0x9348 0xB27B # 0 +0x9349 0xB27C # 0 +0x934A 0xB27D # 0 +0x934B 0xB27E # 0 +0x934C 0xB27F # 0 +0x934D 0xB280 # 0 +0x934E 0xB281 # 0 +0x934F 0xB282 # 0 +0x9350 0xB283 # 0 +0x9351 0xB284 # 0 +0x9353 0xB285 # 0 +0x9354 0xB286 # 0 +0x9355 0xB287 # 0 +0x9356 0xB288 # 0 +0x9357 0xB289 # 0 +0x9358 0xB28A # 0 +0x9359 0xB28B # 0 +0x935A 0xB28C # 0 +0x935B 0xB28D # 0 +0x935C 0xB28E # 0 +0x935D 0xB28F # 0 +0x9361 0xB290 # 0 +0x9362 0xB291 # 0 +0x9363 0xB292 # 0 +0x9364 0xB293 # 0 +0x9365 0xB294 # 0 +0x9366 0xB295 # 0 +0x9367 0xB296 # 0 +0x9368 0xB297 # 0 +0x9369 0xB298 # 0 +0x936A 0xB299 # 0 +0x936B 0xB29A # 0 +0x936C 0xB29B # 0 +0x936D 0xB29C # 0 +0x936E 0xB29D # 0 +0x936F 0xB29E # 0 +0x9370 0xB29F # 0 +0x9371 0xB2A0 # 0 +0x9373 0xB2A1 # 0 +0x9374 0xB2A2 # 0 +0x9375 0xB2A3 # 0 +0x9376 0xB2A4 # 0 +0x9377 0xB2A5 # 0 +0x9378 0xB2A6 # 0 +0x9379 0xB2A7 # 0 +0x937A 0xB2A8 # 0 +0x937B 0xB2A9 # 0 +0x937C 0xB2AA # 0 +0x937D 0xB2AB # 0 +0x9381 0xB2AC # 0 +0x9382 0xB2AD # 0 +0x9383 0xB2AE # 0 +0x9384 0xB2AF # 0 +0x9385 0xB2B0 # 0 +0x9386 0xB2B1 # 0 +0x9387 0xB2B2 # 0 +0x9388 0xB2B3 # 0 +0x9389 0xB2B4 # 0 +0x938A 0xB2B5 # 0 +0x938B 0xB2B6 # 0 +0x938C 0xB2B7 # 0 +0x938D 0xB2B8 # 0 +0x938E 0xB2B9 # 0 +0x938F 0xB2BA # 0 +0x9390 0xB2BB # 0 +0x9391 0xB2BC # 0 +0x9393 0xB2BD # 0 +0x9394 0xB2BE # 0 +0x9395 0xB2BF # 0 +0x9396 0xB2C0 # 0 +0x9397 0xB2C1 # 0 +0x9398 0xB2C2 # 0 +0x9399 0xB2C3 # 0 +0x939A 0xB2C4 # 0 +0x939B 0xB2C5 # 0 +0x939C 0xB2C6 # 0 +0x939D 0xB2C7 # 0 +0x93A1 0xB2C8 # 0 +0x93A2 0xB2C9 # 0 +0x93A3 0xB2CA # 0 +0x93A4 0xB2CB # 0 +0x93A5 0xB2CC # 0 +0x93A6 0xB2CD # 0 +0x93A7 0xB2CE # 0 +0x93A8 0xB2CF # 0 +0x93A9 0xB2D0 # 0 +0x93AA 0xB2D1 # 0 +0x93AB 0xB2D2 # 0 +0x93AC 0xB2D3 # 0 +0x93AD 0xB2D4 # 0 +0x93AE 0xB2D5 # 0 +0x93AF 0xB2D6 # 0 +0x93B0 0xB2D7 # 0 +0x93B1 0xB2D8 # 0 +0x93B3 0xB2D9 # 0 +0x93B4 0xB2DA # 0 +0x93B5 0xB2DB # 0 +0x93B6 0xB2DC # 0 +0x93B7 0xB2DD # 0 +0x93B8 0xB2DE # 0 +0x93B9 0xB2DF # 0 +0x93BA 0xB2E0 # 0 +0x93BB 0xB2E1 # 0 +0x93BC 0xB2E2 # 0 +0x93BD 0xB2E3 # 0 +0x9441 0x1103 # 0 +0x9461 0xB2E4 # 0 +0x9462 0xB2E5 # 0 +0x9463 0xB2E6 # 0 +0x9464 0xB2E7 # 0 +0x9465 0xB2E8 # 0 +0x9466 0xB2E9 # 0 +0x9467 0xB2EA # 0 +0x9468 0xB2EB # 0 +0x9469 0xB2EC # 0 +0x946A 0xB2ED # 0 +0x946B 0xB2EE # 0 +0x946C 0xB2EF # 0 +0x946D 0xB2F0 # 0 +0x946E 0xB2F1 # 0 +0x946F 0xB2F2 # 0 +0x9470 0xB2F3 # 0 +0x9471 0xB2F4 # 0 +0x9473 0xB2F5 # 0 +0x9474 0xB2F6 # 0 +0x9475 0xB2F7 # 0 +0x9476 0xB2F8 # 0 +0x9477 0xB2F9 # 0 +0x9478 0xB2FA # 0 +0x9479 0xB2FB # 0 +0x947A 0xB2FC # 0 +0x947B 0xB2FD # 0 +0x947C 0xB2FE # 0 +0x947D 0xB2FF # 0 +0x9481 0xB300 # 0 +0x9482 0xB301 # 0 +0x9483 0xB302 # 0 +0x9484 0xB303 # 0 +0x9485 0xB304 # 0 +0x9486 0xB305 # 0 +0x9487 0xB306 # 0 +0x9488 0xB307 # 0 +0x9489 0xB308 # 0 +0x948A 0xB309 # 0 +0x948B 0xB30A # 0 +0x948C 0xB30B # 0 +0x948D 0xB30C # 0 +0x948E 0xB30D # 0 +0x948F 0xB30E # 0 +0x9490 0xB30F # 0 +0x9491 0xB310 # 0 +0x9493 0xB311 # 0 +0x9494 0xB312 # 0 +0x9495 0xB313 # 0 +0x9496 0xB314 # 0 +0x9497 0xB315 # 0 +0x9498 0xB316 # 0 +0x9499 0xB317 # 0 +0x949A 0xB318 # 0 +0x949B 0xB319 # 0 +0x949C 0xB31A # 0 +0x949D 0xB31B # 0 +0x94A1 0xB31C # 0 +0x94A2 0xB31D # 0 +0x94A3 0xB31E # 0 +0x94A4 0xB31F # 0 +0x94A5 0xB320 # 0 +0x94A6 0xB321 # 0 +0x94A7 0xB322 # 0 +0x94A8 0xB323 # 0 +0x94A9 0xB324 # 0 +0x94AA 0xB325 # 0 +0x94AB 0xB326 # 0 +0x94AC 0xB327 # 0 +0x94AD 0xB328 # 0 +0x94AE 0xB329 # 0 +0x94AF 0xB32A # 0 +0x94B0 0xB32B # 0 +0x94B1 0xB32C # 0 +0x94B3 0xB32D # 0 +0x94B4 0xB32E # 0 +0x94B5 0xB32F # 0 +0x94B6 0xB330 # 0 +0x94B7 0xB331 # 0 +0x94B8 0xB332 # 0 +0x94B9 0xB333 # 0 +0x94BA 0xB334 # 0 +0x94BB 0xB335 # 0 +0x94BC 0xB336 # 0 +0x94BD 0xB337 # 0 +0x94C1 0xB338 # 0 +0x94C2 0xB339 # 0 +0x94C3 0xB33A # 0 +0x94C4 0xB33B # 0 +0x94C5 0xB33C # 0 +0x94C6 0xB33D # 0 +0x94C7 0xB33E # 0 +0x94C8 0xB33F # 0 +0x94C9 0xB340 # 0 +0x94CA 0xB341 # 0 +0x94CB 0xB342 # 0 +0x94CC 0xB343 # 0 +0x94CD 0xB344 # 0 +0x94CE 0xB345 # 0 +0x94CF 0xB346 # 0 +0x94D0 0xB347 # 0 +0x94D1 0xB348 # 0 +0x94D3 0xB349 # 0 +0x94D4 0xB34A # 0 +0x94D5 0xB34B # 0 +0x94D6 0xB34C # 0 +0x94D7 0xB34D # 0 +0x94D8 0xB34E # 0 +0x94D9 0xB34F # 0 +0x94DA 0xB350 # 0 +0x94DB 0xB351 # 0 +0x94DC 0xB352 # 0 +0x94DD 0xB353 # 0 +0x94E1 0xB354 # 0 +0x94E2 0xB355 # 0 +0x94E3 0xB356 # 0 +0x94E4 0xB357 # 0 +0x94E5 0xB358 # 0 +0x94E6 0xB359 # 0 +0x94E7 0xB35A # 0 +0x94E8 0xB35B # 0 +0x94E9 0xB35C # 0 +0x94EA 0xB35D # 0 +0x94EB 0xB35E # 0 +0x94EC 0xB35F # 0 +0x94ED 0xB360 # 0 +0x94EE 0xB361 # 0 +0x94EF 0xB362 # 0 +0x94F0 0xB363 # 0 +0x94F1 0xB364 # 0 +0x94F3 0xB365 # 0 +0x94F4 0xB366 # 0 +0x94F5 0xB367 # 0 +0x94F6 0xB368 # 0 +0x94F7 0xB369 # 0 +0x94F8 0xB36A # 0 +0x94F9 0xB36B # 0 +0x94FA 0xB36C # 0 +0x94FB 0xB36D # 0 +0x94FC 0xB36E # 0 +0x94FD 0xB36F # 0 +0x9541 0xB370 # 0 +0x9542 0xB371 # 0 +0x9543 0xB372 # 0 +0x9544 0xB373 # 0 +0x9545 0xB374 # 0 +0x9546 0xB375 # 0 +0x9547 0xB376 # 0 +0x9548 0xB377 # 0 +0x9549 0xB378 # 0 +0x954A 0xB379 # 0 +0x954B 0xB37A # 0 +0x954C 0xB37B # 0 +0x954D 0xB37C # 0 +0x954E 0xB37D # 0 +0x954F 0xB37E # 0 +0x9550 0xB37F # 0 +0x9551 0xB380 # 0 +0x9553 0xB381 # 0 +0x9554 0xB382 # 0 +0x9555 0xB383 # 0 +0x9556 0xB384 # 0 +0x9557 0xB385 # 0 +0x9558 0xB386 # 0 +0x9559 0xB387 # 0 +0x955A 0xB388 # 0 +0x955B 0xB389 # 0 +0x955C 0xB38A # 0 +0x955D 0xB38B # 0 +0x9561 0xB38C # 0 +0x9562 0xB38D # 0 +0x9563 0xB38E # 0 +0x9564 0xB38F # 0 +0x9565 0xB390 # 0 +0x9566 0xB391 # 0 +0x9567 0xB392 # 0 +0x9568 0xB393 # 0 +0x9569 0xB394 # 0 +0x956A 0xB395 # 0 +0x956B 0xB396 # 0 +0x956C 0xB397 # 0 +0x956D 0xB398 # 0 +0x956E 0xB399 # 0 +0x956F 0xB39A # 0 +0x9570 0xB39B # 0 +0x9571 0xB39C # 0 +0x9573 0xB39D # 0 +0x9574 0xB39E # 0 +0x9575 0xB39F # 0 +0x9576 0xB3A0 # 0 +0x9577 0xB3A1 # 0 +0x9578 0xB3A2 # 0 +0x9579 0xB3A3 # 0 +0x957A 0xB3A4 # 0 +0x957B 0xB3A5 # 0 +0x957C 0xB3A6 # 0 +0x957D 0xB3A7 # 0 +0x9581 0xB3A8 # 0 +0x9582 0xB3A9 # 0 +0x9583 0xB3AA # 0 +0x9584 0xB3AB # 0 +0x9585 0xB3AC # 0 +0x9586 0xB3AD # 0 +0x9587 0xB3AE # 0 +0x9588 0xB3AF # 0 +0x9589 0xB3B0 # 0 +0x958A 0xB3B1 # 0 +0x958B 0xB3B2 # 0 +0x958C 0xB3B3 # 0 +0x958D 0xB3B4 # 0 +0x958E 0xB3B5 # 0 +0x958F 0xB3B6 # 0 +0x9590 0xB3B7 # 0 +0x9591 0xB3B8 # 0 +0x9593 0xB3B9 # 0 +0x9594 0xB3BA # 0 +0x9595 0xB3BB # 0 +0x9596 0xB3BC # 0 +0x9597 0xB3BD # 0 +0x9598 0xB3BE # 0 +0x9599 0xB3BF # 0 +0x959A 0xB3C0 # 0 +0x959B 0xB3C1 # 0 +0x959C 0xB3C2 # 0 +0x959D 0xB3C3 # 0 +0x95A1 0xB3C4 # 0 +0x95A2 0xB3C5 # 0 +0x95A3 0xB3C6 # 0 +0x95A4 0xB3C7 # 0 +0x95A5 0xB3C8 # 0 +0x95A6 0xB3C9 # 0 +0x95A7 0xB3CA # 0 +0x95A8 0xB3CB # 0 +0x95A9 0xB3CC # 0 +0x95AA 0xB3CD # 0 +0x95AB 0xB3CE # 0 +0x95AC 0xB3CF # 0 +0x95AD 0xB3D0 # 0 +0x95AE 0xB3D1 # 0 +0x95AF 0xB3D2 # 0 +0x95B0 0xB3D3 # 0 +0x95B1 0xB3D4 # 0 +0x95B3 0xB3D5 # 0 +0x95B4 0xB3D6 # 0 +0x95B5 0xB3D7 # 0 +0x95B6 0xB3D8 # 0 +0x95B7 0xB3D9 # 0 +0x95B8 0xB3DA # 0 +0x95B9 0xB3DB # 0 +0x95BA 0xB3DC # 0 +0x95BB 0xB3DD # 0 +0x95BC 0xB3DE # 0 +0x95BD 0xB3DF # 0 +0x95C1 0xB3E0 # 0 +0x95C2 0xB3E1 # 0 +0x95C3 0xB3E2 # 0 +0x95C4 0xB3E3 # 0 +0x95C5 0xB3E4 # 0 +0x95C6 0xB3E5 # 0 +0x95C7 0xB3E6 # 0 +0x95C8 0xB3E7 # 0 +0x95C9 0xB3E8 # 0 +0x95CA 0xB3E9 # 0 +0x95CB 0xB3EA # 0 +0x95CC 0xB3EB # 0 +0x95CD 0xB3EC # 0 +0x95CE 0xB3ED # 0 +0x95CF 0xB3EE # 0 +0x95D0 0xB3EF # 0 +0x95D1 0xB3F0 # 0 +0x95D3 0xB3F1 # 0 +0x95D4 0xB3F2 # 0 +0x95D5 0xB3F3 # 0 +0x95D6 0xB3F4 # 0 +0x95D7 0xB3F5 # 0 +0x95D8 0xB3F6 # 0 +0x95D9 0xB3F7 # 0 +0x95DA 0xB3F8 # 0 +0x95DB 0xB3F9 # 0 +0x95DC 0xB3FA # 0 +0x95DD 0xB3FB # 0 +0x95E1 0xB3FC # 0 +0x95E2 0xB3FD # 0 +0x95E3 0xB3FE # 0 +0x95E4 0xB3FF # 0 +0x95E5 0xB400 # 0 +0x95E6 0xB401 # 0 +0x95E7 0xB402 # 0 +0x95E8 0xB403 # 0 +0x95E9 0xB404 # 0 +0x95EA 0xB405 # 0 +0x95EB 0xB406 # 0 +0x95EC 0xB407 # 0 +0x95ED 0xB408 # 0 +0x95EE 0xB409 # 0 +0x95EF 0xB40A # 0 +0x95F0 0xB40B # 0 +0x95F1 0xB40C # 0 +0x95F3 0xB40D # 0 +0x95F4 0xB40E # 0 +0x95F5 0xB40F # 0 +0x95F6 0xB410 # 0 +0x95F7 0xB411 # 0 +0x95F8 0xB412 # 0 +0x95F9 0xB413 # 0 +0x95FA 0xB414 # 0 +0x95FB 0xB415 # 0 +0x95FC 0xB416 # 0 +0x95FD 0xB417 # 0 +0x9641 0xB418 # 0 +0x9642 0xB419 # 0 +0x9643 0xB41A # 0 +0x9644 0xB41B # 0 +0x9645 0xB41C # 0 +0x9646 0xB41D # 0 +0x9647 0xB41E # 0 +0x9648 0xB41F # 0 +0x9649 0xB420 # 0 +0x964A 0xB421 # 0 +0x964B 0xB422 # 0 +0x964C 0xB423 # 0 +0x964D 0xB424 # 0 +0x964E 0xB425 # 0 +0x964F 0xB426 # 0 +0x9650 0xB427 # 0 +0x9651 0xB428 # 0 +0x9653 0xB429 # 0 +0x9654 0xB42A # 0 +0x9655 0xB42B # 0 +0x9656 0xB42C # 0 +0x9657 0xB42D # 0 +0x9658 0xB42E # 0 +0x9659 0xB42F # 0 +0x965A 0xB430 # 0 +0x965B 0xB431 # 0 +0x965C 0xB432 # 0 +0x965D 0xB433 # 0 +0x9661 0xB434 # 0 +0x9662 0xB435 # 0 +0x9663 0xB436 # 0 +0x9664 0xB437 # 0 +0x9665 0xB438 # 0 +0x9666 0xB439 # 0 +0x9667 0xB43A # 0 +0x9668 0xB43B # 0 +0x9669 0xB43C # 0 +0x966A 0xB43D # 0 +0x966B 0xB43E # 0 +0x966C 0xB43F # 0 +0x966D 0xB440 # 0 +0x966E 0xB441 # 0 +0x966F 0xB442 # 0 +0x9670 0xB443 # 0 +0x9671 0xB444 # 0 +0x9673 0xB445 # 0 +0x9674 0xB446 # 0 +0x9675 0xB447 # 0 +0x9676 0xB448 # 0 +0x9677 0xB449 # 0 +0x9678 0xB44A # 0 +0x9679 0xB44B # 0 +0x967A 0xB44C # 0 +0x967B 0xB44D # 0 +0x967C 0xB44E # 0 +0x967D 0xB44F # 0 +0x9681 0xB450 # 0 +0x9682 0xB451 # 0 +0x9683 0xB452 # 0 +0x9684 0xB453 # 0 +0x9685 0xB454 # 0 +0x9686 0xB455 # 0 +0x9687 0xB456 # 0 +0x9688 0xB457 # 0 +0x9689 0xB458 # 0 +0x968A 0xB459 # 0 +0x968B 0xB45A # 0 +0x968C 0xB45B # 0 +0x968D 0xB45C # 0 +0x968E 0xB45D # 0 +0x968F 0xB45E # 0 +0x9690 0xB45F # 0 +0x9691 0xB460 # 0 +0x9693 0xB461 # 0 +0x9694 0xB462 # 0 +0x9695 0xB463 # 0 +0x9696 0xB464 # 0 +0x9697 0xB465 # 0 +0x9698 0xB466 # 0 +0x9699 0xB467 # 0 +0x969A 0xB468 # 0 +0x969B 0xB469 # 0 +0x969C 0xB46A # 0 +0x969D 0xB46B # 0 +0x96A1 0xB46C # 0 +0x96A2 0xB46D # 0 +0x96A3 0xB46E # 0 +0x96A4 0xB46F # 0 +0x96A5 0xB470 # 0 +0x96A6 0xB471 # 0 +0x96A7 0xB472 # 0 +0x96A8 0xB473 # 0 +0x96A9 0xB474 # 0 +0x96AA 0xB475 # 0 +0x96AB 0xB476 # 0 +0x96AC 0xB477 # 0 +0x96AD 0xB478 # 0 +0x96AE 0xB479 # 0 +0x96AF 0xB47A # 0 +0x96B0 0xB47B # 0 +0x96B1 0xB47C # 0 +0x96B3 0xB47D # 0 +0x96B4 0xB47E # 0 +0x96B5 0xB47F # 0 +0x96B6 0xB480 # 0 +0x96B7 0xB481 # 0 +0x96B8 0xB482 # 0 +0x96B9 0xB483 # 0 +0x96BA 0xB484 # 0 +0x96BB 0xB485 # 0 +0x96BC 0xB486 # 0 +0x96BD 0xB487 # 0 +0x96C1 0xB488 # 0 +0x96C2 0xB489 # 0 +0x96C3 0xB48A # 0 +0x96C4 0xB48B # 0 +0x96C5 0xB48C # 0 +0x96C6 0xB48D # 0 +0x96C7 0xB48E # 0 +0x96C8 0xB48F # 0 +0x96C9 0xB490 # 0 +0x96CA 0xB491 # 0 +0x96CB 0xB492 # 0 +0x96CC 0xB493 # 0 +0x96CD 0xB494 # 0 +0x96CE 0xB495 # 0 +0x96CF 0xB496 # 0 +0x96D0 0xB497 # 0 +0x96D1 0xB498 # 0 +0x96D3 0xB499 # 0 +0x96D4 0xB49A # 0 +0x96D5 0xB49B # 0 +0x96D6 0xB49C # 0 +0x96D7 0xB49D # 0 +0x96D8 0xB49E # 0 +0x96D9 0xB49F # 0 +0x96DA 0xB4A0 # 0 +0x96DB 0xB4A1 # 0 +0x96DC 0xB4A2 # 0 +0x96DD 0xB4A3 # 0 +0x96E1 0xB4A4 # 0 +0x96E2 0xB4A5 # 0 +0x96E3 0xB4A6 # 0 +0x96E4 0xB4A7 # 0 +0x96E5 0xB4A8 # 0 +0x96E6 0xB4A9 # 0 +0x96E7 0xB4AA # 0 +0x96E8 0xB4AB # 0 +0x96E9 0xB4AC # 0 +0x96EA 0xB4AD # 0 +0x96EB 0xB4AE # 0 +0x96EC 0xB4AF # 0 +0x96ED 0xB4B0 # 0 +0x96EE 0xB4B1 # 0 +0x96EF 0xB4B2 # 0 +0x96F0 0xB4B3 # 0 +0x96F1 0xB4B4 # 0 +0x96F3 0xB4B5 # 0 +0x96F4 0xB4B6 # 0 +0x96F5 0xB4B7 # 0 +0x96F6 0xB4B8 # 0 +0x96F7 0xB4B9 # 0 +0x96F8 0xB4BA # 0 +0x96F9 0xB4BB # 0 +0x96FA 0xB4BC # 0 +0x96FB 0xB4BD # 0 +0x96FC 0xB4BE # 0 +0x96FD 0xB4BF # 0 +0x9741 0xB4C0 # 0 +0x9742 0xB4C1 # 0 +0x9743 0xB4C2 # 0 +0x9744 0xB4C3 # 0 +0x9745 0xB4C4 # 0 +0x9746 0xB4C5 # 0 +0x9747 0xB4C6 # 0 +0x9748 0xB4C7 # 0 +0x9749 0xB4C8 # 0 +0x974A 0xB4C9 # 0 +0x974B 0xB4CA # 0 +0x974C 0xB4CB # 0 +0x974D 0xB4CC # 0 +0x974E 0xB4CD # 0 +0x974F 0xB4CE # 0 +0x9750 0xB4CF # 0 +0x9751 0xB4D0 # 0 +0x9753 0xB4D1 # 0 +0x9754 0xB4D2 # 0 +0x9755 0xB4D3 # 0 +0x9756 0xB4D4 # 0 +0x9757 0xB4D5 # 0 +0x9758 0xB4D6 # 0 +0x9759 0xB4D7 # 0 +0x975A 0xB4D8 # 0 +0x975B 0xB4D9 # 0 +0x975C 0xB4DA # 0 +0x975D 0xB4DB # 0 +0x9761 0xB4DC # 0 +0x9762 0xB4DD # 0 +0x9763 0xB4DE # 0 +0x9764 0xB4DF # 0 +0x9765 0xB4E0 # 0 +0x9766 0xB4E1 # 0 +0x9767 0xB4E2 # 0 +0x9768 0xB4E3 # 0 +0x9769 0xB4E4 # 0 +0x976A 0xB4E5 # 0 +0x976B 0xB4E6 # 0 +0x976C 0xB4E7 # 0 +0x976D 0xB4E8 # 0 +0x976E 0xB4E9 # 0 +0x976F 0xB4EA # 0 +0x9770 0xB4EB # 0 +0x9771 0xB4EC # 0 +0x9773 0xB4ED # 0 +0x9774 0xB4EE # 0 +0x9775 0xB4EF # 0 +0x9776 0xB4F0 # 0 +0x9777 0xB4F1 # 0 +0x9778 0xB4F2 # 0 +0x9779 0xB4F3 # 0 +0x977A 0xB4F4 # 0 +0x977B 0xB4F5 # 0 +0x977C 0xB4F6 # 0 +0x977D 0xB4F7 # 0 +0x9781 0xB4F8 # 0 +0x9782 0xB4F9 # 0 +0x9783 0xB4FA # 0 +0x9784 0xB4FB # 0 +0x9785 0xB4FC # 0 +0x9786 0xB4FD # 0 +0x9787 0xB4FE # 0 +0x9788 0xB4FF # 0 +0x9789 0xB500 # 0 +0x978A 0xB501 # 0 +0x978B 0xB502 # 0 +0x978C 0xB503 # 0 +0x978D 0xB504 # 0 +0x978E 0xB505 # 0 +0x978F 0xB506 # 0 +0x9790 0xB507 # 0 +0x9791 0xB508 # 0 +0x9793 0xB509 # 0 +0x9794 0xB50A # 0 +0x9795 0xB50B # 0 +0x9796 0xB50C # 0 +0x9797 0xB50D # 0 +0x9798 0xB50E # 0 +0x9799 0xB50F # 0 +0x979A 0xB510 # 0 +0x979B 0xB511 # 0 +0x979C 0xB512 # 0 +0x979D 0xB513 # 0 +0x97A1 0xB514 # 0 +0x97A2 0xB515 # 0 +0x97A3 0xB516 # 0 +0x97A4 0xB517 # 0 +0x97A5 0xB518 # 0 +0x97A6 0xB519 # 0 +0x97A7 0xB51A # 0 +0x97A8 0xB51B # 0 +0x97A9 0xB51C # 0 +0x97AA 0xB51D # 0 +0x97AB 0xB51E # 0 +0x97AC 0xB51F # 0 +0x97AD 0xB520 # 0 +0x97AE 0xB521 # 0 +0x97AF 0xB522 # 0 +0x97B0 0xB523 # 0 +0x97B1 0xB524 # 0 +0x97B3 0xB525 # 0 +0x97B4 0xB526 # 0 +0x97B5 0xB527 # 0 +0x97B6 0xB528 # 0 +0x97B7 0xB529 # 0 +0x97B8 0xB52A # 0 +0x97B9 0xB52B # 0 +0x97BA 0xB52C # 0 +0x97BB 0xB52D # 0 +0x97BC 0xB52E # 0 +0x97BD 0xB52F # 0 +0x9841 0x1104 # 0 +0x9861 0xB530 # 0 +0x9862 0xB531 # 0 +0x9863 0xB532 # 0 +0x9864 0xB533 # 0 +0x9865 0xB534 # 0 +0x9866 0xB535 # 0 +0x9867 0xB536 # 0 +0x9868 0xB537 # 0 +0x9869 0xB538 # 0 +0x986A 0xB539 # 0 +0x986B 0xB53A # 0 +0x986C 0xB53B # 0 +0x986D 0xB53C # 0 +0x986E 0xB53D # 0 +0x986F 0xB53E # 0 +0x9870 0xB53F # 0 +0x9871 0xB540 # 0 +0x9873 0xB541 # 0 +0x9874 0xB542 # 0 +0x9875 0xB543 # 0 +0x9876 0xB544 # 0 +0x9877 0xB545 # 0 +0x9878 0xB546 # 0 +0x9879 0xB547 # 0 +0x987A 0xB548 # 0 +0x987B 0xB549 # 0 +0x987C 0xB54A # 0 +0x987D 0xB54B # 0 +0x9881 0xB54C # 0 +0x9882 0xB54D # 0 +0x9883 0xB54E # 0 +0x9884 0xB54F # 0 +0x9885 0xB550 # 0 +0x9886 0xB551 # 0 +0x9887 0xB552 # 0 +0x9888 0xB553 # 0 +0x9889 0xB554 # 0 +0x988A 0xB555 # 0 +0x988B 0xB556 # 0 +0x988C 0xB557 # 0 +0x988D 0xB558 # 0 +0x988E 0xB559 # 0 +0x988F 0xB55A # 0 +0x9890 0xB55B # 0 +0x9891 0xB55C # 0 +0x9893 0xB55D # 0 +0x9894 0xB55E # 0 +0x9895 0xB55F # 0 +0x9896 0xB560 # 0 +0x9897 0xB561 # 0 +0x9898 0xB562 # 0 +0x9899 0xB563 # 0 +0x989A 0xB564 # 0 +0x989B 0xB565 # 0 +0x989C 0xB566 # 0 +0x989D 0xB567 # 0 +0x98A1 0xB568 # 0 +0x98A2 0xB569 # 0 +0x98A3 0xB56A # 0 +0x98A4 0xB56B # 0 +0x98A5 0xB56C # 0 +0x98A6 0xB56D # 0 +0x98A7 0xB56E # 0 +0x98A8 0xB56F # 0 +0x98A9 0xB570 # 0 +0x98AA 0xB571 # 0 +0x98AB 0xB572 # 0 +0x98AC 0xB573 # 0 +0x98AD 0xB574 # 0 +0x98AE 0xB575 # 0 +0x98AF 0xB576 # 0 +0x98B0 0xB577 # 0 +0x98B1 0xB578 # 0 +0x98B3 0xB579 # 0 +0x98B4 0xB57A # 0 +0x98B5 0xB57B # 0 +0x98B6 0xB57C # 0 +0x98B7 0xB57D # 0 +0x98B8 0xB57E # 0 +0x98B9 0xB57F # 0 +0x98BA 0xB580 # 0 +0x98BB 0xB581 # 0 +0x98BC 0xB582 # 0 +0x98BD 0xB583 # 0 +0x98C1 0xB584 # 0 +0x98C2 0xB585 # 0 +0x98C3 0xB586 # 0 +0x98C4 0xB587 # 0 +0x98C5 0xB588 # 0 +0x98C6 0xB589 # 0 +0x98C7 0xB58A # 0 +0x98C8 0xB58B # 0 +0x98C9 0xB58C # 0 +0x98CA 0xB58D # 0 +0x98CB 0xB58E # 0 +0x98CC 0xB58F # 0 +0x98CD 0xB590 # 0 +0x98CE 0xB591 # 0 +0x98CF 0xB592 # 0 +0x98D0 0xB593 # 0 +0x98D1 0xB594 # 0 +0x98D3 0xB595 # 0 +0x98D4 0xB596 # 0 +0x98D5 0xB597 # 0 +0x98D6 0xB598 # 0 +0x98D7 0xB599 # 0 +0x98D8 0xB59A # 0 +0x98D9 0xB59B # 0 +0x98DA 0xB59C # 0 +0x98DB 0xB59D # 0 +0x98DC 0xB59E # 0 +0x98DD 0xB59F # 0 +0x98E1 0xB5A0 # 0 +0x98E2 0xB5A1 # 0 +0x98E3 0xB5A2 # 0 +0x98E4 0xB5A3 # 0 +0x98E5 0xB5A4 # 0 +0x98E6 0xB5A5 # 0 +0x98E7 0xB5A6 # 0 +0x98E8 0xB5A7 # 0 +0x98E9 0xB5A8 # 0 +0x98EA 0xB5A9 # 0 +0x98EB 0xB5AA # 0 +0x98EC 0xB5AB # 0 +0x98ED 0xB5AC # 0 +0x98EE 0xB5AD # 0 +0x98EF 0xB5AE # 0 +0x98F0 0xB5AF # 0 +0x98F1 0xB5B0 # 0 +0x98F3 0xB5B1 # 0 +0x98F4 0xB5B2 # 0 +0x98F5 0xB5B3 # 0 +0x98F6 0xB5B4 # 0 +0x98F7 0xB5B5 # 0 +0x98F8 0xB5B6 # 0 +0x98F9 0xB5B7 # 0 +0x98FA 0xB5B8 # 0 +0x98FB 0xB5B9 # 0 +0x98FC 0xB5BA # 0 +0x98FD 0xB5BB # 0 +0x9941 0xB5BC # 0 +0x9942 0xB5BD # 0 +0x9943 0xB5BE # 0 +0x9944 0xB5BF # 0 +0x9945 0xB5C0 # 0 +0x9946 0xB5C1 # 0 +0x9947 0xB5C2 # 0 +0x9948 0xB5C3 # 0 +0x9949 0xB5C4 # 0 +0x994A 0xB5C5 # 0 +0x994B 0xB5C6 # 0 +0x994C 0xB5C7 # 0 +0x994D 0xB5C8 # 0 +0x994E 0xB5C9 # 0 +0x994F 0xB5CA # 0 +0x9950 0xB5CB # 0 +0x9951 0xB5CC # 0 +0x9953 0xB5CD # 0 +0x9954 0xB5CE # 0 +0x9955 0xB5CF # 0 +0x9956 0xB5D0 # 0 +0x9957 0xB5D1 # 0 +0x9958 0xB5D2 # 0 +0x9959 0xB5D3 # 0 +0x995A 0xB5D4 # 0 +0x995B 0xB5D5 # 0 +0x995C 0xB5D6 # 0 +0x995D 0xB5D7 # 0 +0x9961 0xB5D8 # 0 +0x9962 0xB5D9 # 0 +0x9963 0xB5DA # 0 +0x9964 0xB5DB # 0 +0x9965 0xB5DC # 0 +0x9966 0xB5DD # 0 +0x9967 0xB5DE # 0 +0x9968 0xB5DF # 0 +0x9969 0xB5E0 # 0 +0x996A 0xB5E1 # 0 +0x996B 0xB5E2 # 0 +0x996C 0xB5E3 # 0 +0x996D 0xB5E4 # 0 +0x996E 0xB5E5 # 0 +0x996F 0xB5E6 # 0 +0x9970 0xB5E7 # 0 +0x9971 0xB5E8 # 0 +0x9973 0xB5E9 # 0 +0x9974 0xB5EA # 0 +0x9975 0xB5EB # 0 +0x9976 0xB5EC # 0 +0x9977 0xB5ED # 0 +0x9978 0xB5EE # 0 +0x9979 0xB5EF # 0 +0x997A 0xB5F0 # 0 +0x997B 0xB5F1 # 0 +0x997C 0xB5F2 # 0 +0x997D 0xB5F3 # 0 +0x9981 0xB5F4 # 0 +0x9982 0xB5F5 # 0 +0x9983 0xB5F6 # 0 +0x9984 0xB5F7 # 0 +0x9985 0xB5F8 # 0 +0x9986 0xB5F9 # 0 +0x9987 0xB5FA # 0 +0x9988 0xB5FB # 0 +0x9989 0xB5FC # 0 +0x998A 0xB5FD # 0 +0x998B 0xB5FE # 0 +0x998C 0xB5FF # 0 +0x998D 0xB600 # 0 +0x998E 0xB601 # 0 +0x998F 0xB602 # 0 +0x9990 0xB603 # 0 +0x9991 0xB604 # 0 +0x9993 0xB605 # 0 +0x9994 0xB606 # 0 +0x9995 0xB607 # 0 +0x9996 0xB608 # 0 +0x9997 0xB609 # 0 +0x9998 0xB60A # 0 +0x9999 0xB60B # 0 +0x999A 0xB60C # 0 +0x999B 0xB60D # 0 +0x999C 0xB60E # 0 +0x999D 0xB60F # 0 +0x99A1 0xB610 # 0 +0x99A2 0xB611 # 0 +0x99A3 0xB612 # 0 +0x99A4 0xB613 # 0 +0x99A5 0xB614 # 0 +0x99A6 0xB615 # 0 +0x99A7 0xB616 # 0 +0x99A8 0xB617 # 0 +0x99A9 0xB618 # 0 +0x99AA 0xB619 # 0 +0x99AB 0xB61A # 0 +0x99AC 0xB61B # 0 +0x99AD 0xB61C # 0 +0x99AE 0xB61D # 0 +0x99AF 0xB61E # 0 +0x99B0 0xB61F # 0 +0x99B1 0xB620 # 0 +0x99B3 0xB621 # 0 +0x99B4 0xB622 # 0 +0x99B5 0xB623 # 0 +0x99B6 0xB624 # 0 +0x99B7 0xB625 # 0 +0x99B8 0xB626 # 0 +0x99B9 0xB627 # 0 +0x99BA 0xB628 # 0 +0x99BB 0xB629 # 0 +0x99BC 0xB62A # 0 +0x99BD 0xB62B # 0 +0x99C1 0xB62C # 0 +0x99C2 0xB62D # 0 +0x99C3 0xB62E # 0 +0x99C4 0xB62F # 0 +0x99C5 0xB630 # 0 +0x99C6 0xB631 # 0 +0x99C7 0xB632 # 0 +0x99C8 0xB633 # 0 +0x99C9 0xB634 # 0 +0x99CA 0xB635 # 0 +0x99CB 0xB636 # 0 +0x99CC 0xB637 # 0 +0x99CD 0xB638 # 0 +0x99CE 0xB639 # 0 +0x99CF 0xB63A # 0 +0x99D0 0xB63B # 0 +0x99D1 0xB63C # 0 +0x99D3 0xB63D # 0 +0x99D4 0xB63E # 0 +0x99D5 0xB63F # 0 +0x99D6 0xB640 # 0 +0x99D7 0xB641 # 0 +0x99D8 0xB642 # 0 +0x99D9 0xB643 # 0 +0x99DA 0xB644 # 0 +0x99DB 0xB645 # 0 +0x99DC 0xB646 # 0 +0x99DD 0xB647 # 0 +0x99E1 0xB648 # 0 +0x99E2 0xB649 # 0 +0x99E3 0xB64A # 0 +0x99E4 0xB64B # 0 +0x99E5 0xB64C # 0 +0x99E6 0xB64D # 0 +0x99E7 0xB64E # 0 +0x99E8 0xB64F # 0 +0x99E9 0xB650 # 0 +0x99EA 0xB651 # 0 +0x99EB 0xB652 # 0 +0x99EC 0xB653 # 0 +0x99ED 0xB654 # 0 +0x99EE 0xB655 # 0 +0x99EF 0xB656 # 0 +0x99F0 0xB657 # 0 +0x99F1 0xB658 # 0 +0x99F3 0xB659 # 0 +0x99F4 0xB65A # 0 +0x99F5 0xB65B # 0 +0x99F6 0xB65C # 0 +0x99F7 0xB65D # 0 +0x99F8 0xB65E # 0 +0x99F9 0xB65F # 0 +0x99FA 0xB660 # 0 +0x99FB 0xB661 # 0 +0x99FC 0xB662 # 0 +0x99FD 0xB663 # 0 +0x9A41 0xB664 # 0 +0x9A42 0xB665 # 0 +0x9A43 0xB666 # 0 +0x9A44 0xB667 # 0 +0x9A45 0xB668 # 0 +0x9A46 0xB669 # 0 +0x9A47 0xB66A # 0 +0x9A48 0xB66B # 0 +0x9A49 0xB66C # 0 +0x9A4A 0xB66D # 0 +0x9A4B 0xB66E # 0 +0x9A4C 0xB66F # 0 +0x9A4D 0xB670 # 0 +0x9A4E 0xB671 # 0 +0x9A4F 0xB672 # 0 +0x9A50 0xB673 # 0 +0x9A51 0xB674 # 0 +0x9A53 0xB675 # 0 +0x9A54 0xB676 # 0 +0x9A55 0xB677 # 0 +0x9A56 0xB678 # 0 +0x9A57 0xB679 # 0 +0x9A58 0xB67A # 0 +0x9A59 0xB67B # 0 +0x9A5A 0xB67C # 0 +0x9A5B 0xB67D # 0 +0x9A5C 0xB67E # 0 +0x9A5D 0xB67F # 0 +0x9A61 0xB680 # 0 +0x9A62 0xB681 # 0 +0x9A63 0xB682 # 0 +0x9A64 0xB683 # 0 +0x9A65 0xB684 # 0 +0x9A66 0xB685 # 0 +0x9A67 0xB686 # 0 +0x9A68 0xB687 # 0 +0x9A69 0xB688 # 0 +0x9A6A 0xB689 # 0 +0x9A6B 0xB68A # 0 +0x9A6C 0xB68B # 0 +0x9A6D 0xB68C # 0 +0x9A6E 0xB68D # 0 +0x9A6F 0xB68E # 0 +0x9A70 0xB68F # 0 +0x9A71 0xB690 # 0 +0x9A73 0xB691 # 0 +0x9A74 0xB692 # 0 +0x9A75 0xB693 # 0 +0x9A76 0xB694 # 0 +0x9A77 0xB695 # 0 +0x9A78 0xB696 # 0 +0x9A79 0xB697 # 0 +0x9A7A 0xB698 # 0 +0x9A7B 0xB699 # 0 +0x9A7C 0xB69A # 0 +0x9A7D 0xB69B # 0 +0x9A81 0xB69C # 0 +0x9A82 0xB69D # 0 +0x9A83 0xB69E # 0 +0x9A84 0xB69F # 0 +0x9A85 0xB6A0 # 0 +0x9A86 0xB6A1 # 0 +0x9A87 0xB6A2 # 0 +0x9A88 0xB6A3 # 0 +0x9A89 0xB6A4 # 0 +0x9A8A 0xB6A5 # 0 +0x9A8B 0xB6A6 # 0 +0x9A8C 0xB6A7 # 0 +0x9A8D 0xB6A8 # 0 +0x9A8E 0xB6A9 # 0 +0x9A8F 0xB6AA # 0 +0x9A90 0xB6AB # 0 +0x9A91 0xB6AC # 0 +0x9A93 0xB6AD # 0 +0x9A94 0xB6AE # 0 +0x9A95 0xB6AF # 0 +0x9A96 0xB6B0 # 0 +0x9A97 0xB6B1 # 0 +0x9A98 0xB6B2 # 0 +0x9A99 0xB6B3 # 0 +0x9A9A 0xB6B4 # 0 +0x9A9B 0xB6B5 # 0 +0x9A9C 0xB6B6 # 0 +0x9A9D 0xB6B7 # 0 +0x9AA1 0xB6B8 # 0 +0x9AA2 0xB6B9 # 0 +0x9AA3 0xB6BA # 0 +0x9AA4 0xB6BB # 0 +0x9AA5 0xB6BC # 0 +0x9AA6 0xB6BD # 0 +0x9AA7 0xB6BE # 0 +0x9AA8 0xB6BF # 0 +0x9AA9 0xB6C0 # 0 +0x9AAA 0xB6C1 # 0 +0x9AAB 0xB6C2 # 0 +0x9AAC 0xB6C3 # 0 +0x9AAD 0xB6C4 # 0 +0x9AAE 0xB6C5 # 0 +0x9AAF 0xB6C6 # 0 +0x9AB0 0xB6C7 # 0 +0x9AB1 0xB6C8 # 0 +0x9AB3 0xB6C9 # 0 +0x9AB4 0xB6CA # 0 +0x9AB5 0xB6CB # 0 +0x9AB6 0xB6CC # 0 +0x9AB7 0xB6CD # 0 +0x9AB8 0xB6CE # 0 +0x9AB9 0xB6CF # 0 +0x9ABA 0xB6D0 # 0 +0x9ABB 0xB6D1 # 0 +0x9ABC 0xB6D2 # 0 +0x9ABD 0xB6D3 # 0 +0x9AC1 0xB6D4 # 0 +0x9AC2 0xB6D5 # 0 +0x9AC3 0xB6D6 # 0 +0x9AC4 0xB6D7 # 0 +0x9AC5 0xB6D8 # 0 +0x9AC6 0xB6D9 # 0 +0x9AC7 0xB6DA # 0 +0x9AC8 0xB6DB # 0 +0x9AC9 0xB6DC # 0 +0x9ACA 0xB6DD # 0 +0x9ACB 0xB6DE # 0 +0x9ACC 0xB6DF # 0 +0x9ACD 0xB6E0 # 0 +0x9ACE 0xB6E1 # 0 +0x9ACF 0xB6E2 # 0 +0x9AD0 0xB6E3 # 0 +0x9AD1 0xB6E4 # 0 +0x9AD3 0xB6E5 # 0 +0x9AD4 0xB6E6 # 0 +0x9AD5 0xB6E7 # 0 +0x9AD6 0xB6E8 # 0 +0x9AD7 0xB6E9 # 0 +0x9AD8 0xB6EA # 0 +0x9AD9 0xB6EB # 0 +0x9ADA 0xB6EC # 0 +0x9ADB 0xB6ED # 0 +0x9ADC 0xB6EE # 0 +0x9ADD 0xB6EF # 0 +0x9AE1 0xB6F0 # 0 +0x9AE2 0xB6F1 # 0 +0x9AE3 0xB6F2 # 0 +0x9AE4 0xB6F3 # 0 +0x9AE5 0xB6F4 # 0 +0x9AE6 0xB6F5 # 0 +0x9AE7 0xB6F6 # 0 +0x9AE8 0xB6F7 # 0 +0x9AE9 0xB6F8 # 0 +0x9AEA 0xB6F9 # 0 +0x9AEB 0xB6FA # 0 +0x9AEC 0xB6FB # 0 +0x9AED 0xB6FC # 0 +0x9AEE 0xB6FD # 0 +0x9AEF 0xB6FE # 0 +0x9AF0 0xB6FF # 0 +0x9AF1 0xB700 # 0 +0x9AF3 0xB701 # 0 +0x9AF4 0xB702 # 0 +0x9AF5 0xB703 # 0 +0x9AF6 0xB704 # 0 +0x9AF7 0xB705 # 0 +0x9AF8 0xB706 # 0 +0x9AF9 0xB707 # 0 +0x9AFA 0xB708 # 0 +0x9AFB 0xB709 # 0 +0x9AFC 0xB70A # 0 +0x9AFD 0xB70B # 0 +0x9B41 0xB70C # 0 +0x9B42 0xB70D # 0 +0x9B43 0xB70E # 0 +0x9B44 0xB70F # 0 +0x9B45 0xB710 # 0 +0x9B46 0xB711 # 0 +0x9B47 0xB712 # 0 +0x9B48 0xB713 # 0 +0x9B49 0xB714 # 0 +0x9B4A 0xB715 # 0 +0x9B4B 0xB716 # 0 +0x9B4C 0xB717 # 0 +0x9B4D 0xB718 # 0 +0x9B4E 0xB719 # 0 +0x9B4F 0xB71A # 0 +0x9B50 0xB71B # 0 +0x9B51 0xB71C # 0 +0x9B53 0xB71D # 0 +0x9B54 0xB71E # 0 +0x9B55 0xB71F # 0 +0x9B56 0xB720 # 0 +0x9B57 0xB721 # 0 +0x9B58 0xB722 # 0 +0x9B59 0xB723 # 0 +0x9B5A 0xB724 # 0 +0x9B5B 0xB725 # 0 +0x9B5C 0xB726 # 0 +0x9B5D 0xB727 # 0 +0x9B61 0xB728 # 0 +0x9B62 0xB729 # 0 +0x9B63 0xB72A # 0 +0x9B64 0xB72B # 0 +0x9B65 0xB72C # 0 +0x9B66 0xB72D # 0 +0x9B67 0xB72E # 0 +0x9B68 0xB72F # 0 +0x9B69 0xB730 # 0 +0x9B6A 0xB731 # 0 +0x9B6B 0xB732 # 0 +0x9B6C 0xB733 # 0 +0x9B6D 0xB734 # 0 +0x9B6E 0xB735 # 0 +0x9B6F 0xB736 # 0 +0x9B70 0xB737 # 0 +0x9B71 0xB738 # 0 +0x9B73 0xB739 # 0 +0x9B74 0xB73A # 0 +0x9B75 0xB73B # 0 +0x9B76 0xB73C # 0 +0x9B77 0xB73D # 0 +0x9B78 0xB73E # 0 +0x9B79 0xB73F # 0 +0x9B7A 0xB740 # 0 +0x9B7B 0xB741 # 0 +0x9B7C 0xB742 # 0 +0x9B7D 0xB743 # 0 +0x9B81 0xB744 # 0 +0x9B82 0xB745 # 0 +0x9B83 0xB746 # 0 +0x9B84 0xB747 # 0 +0x9B85 0xB748 # 0 +0x9B86 0xB749 # 0 +0x9B87 0xB74A # 0 +0x9B88 0xB74B # 0 +0x9B89 0xB74C # 0 +0x9B8A 0xB74D # 0 +0x9B8B 0xB74E # 0 +0x9B8C 0xB74F # 0 +0x9B8D 0xB750 # 0 +0x9B8E 0xB751 # 0 +0x9B8F 0xB752 # 0 +0x9B90 0xB753 # 0 +0x9B91 0xB754 # 0 +0x9B93 0xB755 # 0 +0x9B94 0xB756 # 0 +0x9B95 0xB757 # 0 +0x9B96 0xB758 # 0 +0x9B97 0xB759 # 0 +0x9B98 0xB75A # 0 +0x9B99 0xB75B # 0 +0x9B9A 0xB75C # 0 +0x9B9B 0xB75D # 0 +0x9B9C 0xB75E # 0 +0x9B9D 0xB75F # 0 +0x9BA1 0xB760 # 0 +0x9BA2 0xB761 # 0 +0x9BA3 0xB762 # 0 +0x9BA4 0xB763 # 0 +0x9BA5 0xB764 # 0 +0x9BA6 0xB765 # 0 +0x9BA7 0xB766 # 0 +0x9BA8 0xB767 # 0 +0x9BA9 0xB768 # 0 +0x9BAA 0xB769 # 0 +0x9BAB 0xB76A # 0 +0x9BAC 0xB76B # 0 +0x9BAD 0xB76C # 0 +0x9BAE 0xB76D # 0 +0x9BAF 0xB76E # 0 +0x9BB0 0xB76F # 0 +0x9BB1 0xB770 # 0 +0x9BB3 0xB771 # 0 +0x9BB4 0xB772 # 0 +0x9BB5 0xB773 # 0 +0x9BB6 0xB774 # 0 +0x9BB7 0xB775 # 0 +0x9BB8 0xB776 # 0 +0x9BB9 0xB777 # 0 +0x9BBA 0xB778 # 0 +0x9BBB 0xB779 # 0 +0x9BBC 0xB77A # 0 +0x9BBD 0xB77B # 0 +0x9C41 0x1105 # 0 +0x9C61 0xB77C # 0 +0x9C62 0xB77D # 0 +0x9C63 0xB77E # 0 +0x9C64 0xB77F # 0 +0x9C65 0xB780 # 0 +0x9C66 0xB781 # 0 +0x9C67 0xB782 # 0 +0x9C68 0xB783 # 0 +0x9C69 0xB784 # 0 +0x9C6A 0xB785 # 0 +0x9C6B 0xB786 # 0 +0x9C6C 0xB787 # 0 +0x9C6D 0xB788 # 0 +0x9C6E 0xB789 # 0 +0x9C6F 0xB78A # 0 +0x9C70 0xB78B # 0 +0x9C71 0xB78C # 0 +0x9C73 0xB78D # 0 +0x9C74 0xB78E # 0 +0x9C75 0xB78F # 0 +0x9C76 0xB790 # 0 +0x9C77 0xB791 # 0 +0x9C78 0xB792 # 0 +0x9C79 0xB793 # 0 +0x9C7A 0xB794 # 0 +0x9C7B 0xB795 # 0 +0x9C7C 0xB796 # 0 +0x9C7D 0xB797 # 0 +0x9C81 0xB798 # 0 +0x9C82 0xB799 # 0 +0x9C83 0xB79A # 0 +0x9C84 0xB79B # 0 +0x9C85 0xB79C # 0 +0x9C86 0xB79D # 0 +0x9C87 0xB79E # 0 +0x9C88 0xB79F # 0 +0x9C89 0xB7A0 # 0 +0x9C8A 0xB7A1 # 0 +0x9C8B 0xB7A2 # 0 +0x9C8C 0xB7A3 # 0 +0x9C8D 0xB7A4 # 0 +0x9C8E 0xB7A5 # 0 +0x9C8F 0xB7A6 # 0 +0x9C90 0xB7A7 # 0 +0x9C91 0xB7A8 # 0 +0x9C93 0xB7A9 # 0 +0x9C94 0xB7AA # 0 +0x9C95 0xB7AB # 0 +0x9C96 0xB7AC # 0 +0x9C97 0xB7AD # 0 +0x9C98 0xB7AE # 0 +0x9C99 0xB7AF # 0 +0x9C9A 0xB7B0 # 0 +0x9C9B 0xB7B1 # 0 +0x9C9C 0xB7B2 # 0 +0x9C9D 0xB7B3 # 0 +0x9CA1 0xB7B4 # 0 +0x9CA2 0xB7B5 # 0 +0x9CA3 0xB7B6 # 0 +0x9CA4 0xB7B7 # 0 +0x9CA5 0xB7B8 # 0 +0x9CA6 0xB7B9 # 0 +0x9CA7 0xB7BA # 0 +0x9CA8 0xB7BB # 0 +0x9CA9 0xB7BC # 0 +0x9CAA 0xB7BD # 0 +0x9CAB 0xB7BE # 0 +0x9CAC 0xB7BF # 0 +0x9CAD 0xB7C0 # 0 +0x9CAE 0xB7C1 # 0 +0x9CAF 0xB7C2 # 0 +0x9CB0 0xB7C3 # 0 +0x9CB1 0xB7C4 # 0 +0x9CB3 0xB7C5 # 0 +0x9CB4 0xB7C6 # 0 +0x9CB5 0xB7C7 # 0 +0x9CB6 0xB7C8 # 0 +0x9CB7 0xB7C9 # 0 +0x9CB8 0xB7CA # 0 +0x9CB9 0xB7CB # 0 +0x9CBA 0xB7CC # 0 +0x9CBB 0xB7CD # 0 +0x9CBC 0xB7CE # 0 +0x9CBD 0xB7CF # 0 +0x9CC1 0xB7D0 # 0 +0x9CC2 0xB7D1 # 0 +0x9CC3 0xB7D2 # 0 +0x9CC4 0xB7D3 # 0 +0x9CC5 0xB7D4 # 0 +0x9CC6 0xB7D5 # 0 +0x9CC7 0xB7D6 # 0 +0x9CC8 0xB7D7 # 0 +0x9CC9 0xB7D8 # 0 +0x9CCA 0xB7D9 # 0 +0x9CCB 0xB7DA # 0 +0x9CCC 0xB7DB # 0 +0x9CCD 0xB7DC # 0 +0x9CCE 0xB7DD # 0 +0x9CCF 0xB7DE # 0 +0x9CD0 0xB7DF # 0 +0x9CD1 0xB7E0 # 0 +0x9CD3 0xB7E1 # 0 +0x9CD4 0xB7E2 # 0 +0x9CD5 0xB7E3 # 0 +0x9CD6 0xB7E4 # 0 +0x9CD7 0xB7E5 # 0 +0x9CD8 0xB7E6 # 0 +0x9CD9 0xB7E7 # 0 +0x9CDA 0xB7E8 # 0 +0x9CDB 0xB7E9 # 0 +0x9CDC 0xB7EA # 0 +0x9CDD 0xB7EB # 0 +0x9CE1 0xB7EC # 0 +0x9CE2 0xB7ED # 0 +0x9CE3 0xB7EE # 0 +0x9CE4 0xB7EF # 0 +0x9CE5 0xB7F0 # 0 +0x9CE6 0xB7F1 # 0 +0x9CE7 0xB7F2 # 0 +0x9CE8 0xB7F3 # 0 +0x9CE9 0xB7F4 # 0 +0x9CEA 0xB7F5 # 0 +0x9CEB 0xB7F6 # 0 +0x9CEC 0xB7F7 # 0 +0x9CED 0xB7F8 # 0 +0x9CEE 0xB7F9 # 0 +0x9CEF 0xB7FA # 0 +0x9CF0 0xB7FB # 0 +0x9CF1 0xB7FC # 0 +0x9CF3 0xB7FD # 0 +0x9CF4 0xB7FE # 0 +0x9CF5 0xB7FF # 0 +0x9CF6 0xB800 # 0 +0x9CF7 0xB801 # 0 +0x9CF8 0xB802 # 0 +0x9CF9 0xB803 # 0 +0x9CFA 0xB804 # 0 +0x9CFB 0xB805 # 0 +0x9CFC 0xB806 # 0 +0x9CFD 0xB807 # 0 +0x9D41 0xB808 # 0 +0x9D42 0xB809 # 0 +0x9D43 0xB80A # 0 +0x9D44 0xB80B # 0 +0x9D45 0xB80C # 0 +0x9D46 0xB80D # 0 +0x9D47 0xB80E # 0 +0x9D48 0xB80F # 0 +0x9D49 0xB810 # 0 +0x9D4A 0xB811 # 0 +0x9D4B 0xB812 # 0 +0x9D4C 0xB813 # 0 +0x9D4D 0xB814 # 0 +0x9D4E 0xB815 # 0 +0x9D4F 0xB816 # 0 +0x9D50 0xB817 # 0 +0x9D51 0xB818 # 0 +0x9D53 0xB819 # 0 +0x9D54 0xB81A # 0 +0x9D55 0xB81B # 0 +0x9D56 0xB81C # 0 +0x9D57 0xB81D # 0 +0x9D58 0xB81E # 0 +0x9D59 0xB81F # 0 +0x9D5A 0xB820 # 0 +0x9D5B 0xB821 # 0 +0x9D5C 0xB822 # 0 +0x9D5D 0xB823 # 0 +0x9D61 0xB824 # 0 +0x9D62 0xB825 # 0 +0x9D63 0xB826 # 0 +0x9D64 0xB827 # 0 +0x9D65 0xB828 # 0 +0x9D66 0xB829 # 0 +0x9D67 0xB82A # 0 +0x9D68 0xB82B # 0 +0x9D69 0xB82C # 0 +0x9D6A 0xB82D # 0 +0x9D6B 0xB82E # 0 +0x9D6C 0xB82F # 0 +0x9D6D 0xB830 # 0 +0x9D6E 0xB831 # 0 +0x9D6F 0xB832 # 0 +0x9D70 0xB833 # 0 +0x9D71 0xB834 # 0 +0x9D73 0xB835 # 0 +0x9D74 0xB836 # 0 +0x9D75 0xB837 # 0 +0x9D76 0xB838 # 0 +0x9D77 0xB839 # 0 +0x9D78 0xB83A # 0 +0x9D79 0xB83B # 0 +0x9D7A 0xB83C # 0 +0x9D7B 0xB83D # 0 +0x9D7C 0xB83E # 0 +0x9D7D 0xB83F # 0 +0x9D81 0xB840 # 0 +0x9D82 0xB841 # 0 +0x9D83 0xB842 # 0 +0x9D84 0xB843 # 0 +0x9D85 0xB844 # 0 +0x9D86 0xB845 # 0 +0x9D87 0xB846 # 0 +0x9D88 0xB847 # 0 +0x9D89 0xB848 # 0 +0x9D8A 0xB849 # 0 +0x9D8B 0xB84A # 0 +0x9D8C 0xB84B # 0 +0x9D8D 0xB84C # 0 +0x9D8E 0xB84D # 0 +0x9D8F 0xB84E # 0 +0x9D90 0xB84F # 0 +0x9D91 0xB850 # 0 +0x9D93 0xB851 # 0 +0x9D94 0xB852 # 0 +0x9D95 0xB853 # 0 +0x9D96 0xB854 # 0 +0x9D97 0xB855 # 0 +0x9D98 0xB856 # 0 +0x9D99 0xB857 # 0 +0x9D9A 0xB858 # 0 +0x9D9B 0xB859 # 0 +0x9D9C 0xB85A # 0 +0x9D9D 0xB85B # 0 +0x9DA1 0xB85C # 0 +0x9DA2 0xB85D # 0 +0x9DA3 0xB85E # 0 +0x9DA4 0xB85F # 0 +0x9DA5 0xB860 # 0 +0x9DA6 0xB861 # 0 +0x9DA7 0xB862 # 0 +0x9DA8 0xB863 # 0 +0x9DA9 0xB864 # 0 +0x9DAA 0xB865 # 0 +0x9DAB 0xB866 # 0 +0x9DAC 0xB867 # 0 +0x9DAD 0xB868 # 0 +0x9DAE 0xB869 # 0 +0x9DAF 0xB86A # 0 +0x9DB0 0xB86B # 0 +0x9DB1 0xB86C # 0 +0x9DB3 0xB86D # 0 +0x9DB4 0xB86E # 0 +0x9DB5 0xB86F # 0 +0x9DB6 0xB870 # 0 +0x9DB7 0xB871 # 0 +0x9DB8 0xB872 # 0 +0x9DB9 0xB873 # 0 +0x9DBA 0xB874 # 0 +0x9DBB 0xB875 # 0 +0x9DBC 0xB876 # 0 +0x9DBD 0xB877 # 0 +0x9DC1 0xB878 # 0 +0x9DC2 0xB879 # 0 +0x9DC3 0xB87A # 0 +0x9DC4 0xB87B # 0 +0x9DC5 0xB87C # 0 +0x9DC6 0xB87D # 0 +0x9DC7 0xB87E # 0 +0x9DC8 0xB87F # 0 +0x9DC9 0xB880 # 0 +0x9DCA 0xB881 # 0 +0x9DCB 0xB882 # 0 +0x9DCC 0xB883 # 0 +0x9DCD 0xB884 # 0 +0x9DCE 0xB885 # 0 +0x9DCF 0xB886 # 0 +0x9DD0 0xB887 # 0 +0x9DD1 0xB888 # 0 +0x9DD3 0xB889 # 0 +0x9DD4 0xB88A # 0 +0x9DD5 0xB88B # 0 +0x9DD6 0xB88C # 0 +0x9DD7 0xB88D # 0 +0x9DD8 0xB88E # 0 +0x9DD9 0xB88F # 0 +0x9DDA 0xB890 # 0 +0x9DDB 0xB891 # 0 +0x9DDC 0xB892 # 0 +0x9DDD 0xB893 # 0 +0x9DE1 0xB894 # 0 +0x9DE2 0xB895 # 0 +0x9DE3 0xB896 # 0 +0x9DE4 0xB897 # 0 +0x9DE5 0xB898 # 0 +0x9DE6 0xB899 # 0 +0x9DE7 0xB89A # 0 +0x9DE8 0xB89B # 0 +0x9DE9 0xB89C # 0 +0x9DEA 0xB89D # 0 +0x9DEB 0xB89E # 0 +0x9DEC 0xB89F # 0 +0x9DED 0xB8A0 # 0 +0x9DEE 0xB8A1 # 0 +0x9DEF 0xB8A2 # 0 +0x9DF0 0xB8A3 # 0 +0x9DF1 0xB8A4 # 0 +0x9DF3 0xB8A5 # 0 +0x9DF4 0xB8A6 # 0 +0x9DF5 0xB8A7 # 0 +0x9DF6 0xB8A8 # 0 +0x9DF7 0xB8A9 # 0 +0x9DF8 0xB8AA # 0 +0x9DF9 0xB8AB # 0 +0x9DFA 0xB8AC # 0 +0x9DFB 0xB8AD # 0 +0x9DFC 0xB8AE # 0 +0x9DFD 0xB8AF # 0 +0x9E41 0xB8B0 # 0 +0x9E42 0xB8B1 # 0 +0x9E43 0xB8B2 # 0 +0x9E44 0xB8B3 # 0 +0x9E45 0xB8B4 # 0 +0x9E46 0xB8B5 # 0 +0x9E47 0xB8B6 # 0 +0x9E48 0xB8B7 # 0 +0x9E49 0xB8B8 # 0 +0x9E4A 0xB8B9 # 0 +0x9E4B 0xB8BA # 0 +0x9E4C 0xB8BB # 0 +0x9E4D 0xB8BC # 0 +0x9E4E 0xB8BD # 0 +0x9E4F 0xB8BE # 0 +0x9E50 0xB8BF # 0 +0x9E51 0xB8C0 # 0 +0x9E53 0xB8C1 # 0 +0x9E54 0xB8C2 # 0 +0x9E55 0xB8C3 # 0 +0x9E56 0xB8C4 # 0 +0x9E57 0xB8C5 # 0 +0x9E58 0xB8C6 # 0 +0x9E59 0xB8C7 # 0 +0x9E5A 0xB8C8 # 0 +0x9E5B 0xB8C9 # 0 +0x9E5C 0xB8CA # 0 +0x9E5D 0xB8CB # 0 +0x9E61 0xB8CC # 0 +0x9E62 0xB8CD # 0 +0x9E63 0xB8CE # 0 +0x9E64 0xB8CF # 0 +0x9E65 0xB8D0 # 0 +0x9E66 0xB8D1 # 0 +0x9E67 0xB8D2 # 0 +0x9E68 0xB8D3 # 0 +0x9E69 0xB8D4 # 0 +0x9E6A 0xB8D5 # 0 +0x9E6B 0xB8D6 # 0 +0x9E6C 0xB8D7 # 0 +0x9E6D 0xB8D8 # 0 +0x9E6E 0xB8D9 # 0 +0x9E6F 0xB8DA # 0 +0x9E70 0xB8DB # 0 +0x9E71 0xB8DC # 0 +0x9E73 0xB8DD # 0 +0x9E74 0xB8DE # 0 +0x9E75 0xB8DF # 0 +0x9E76 0xB8E0 # 0 +0x9E77 0xB8E1 # 0 +0x9E78 0xB8E2 # 0 +0x9E79 0xB8E3 # 0 +0x9E7A 0xB8E4 # 0 +0x9E7B 0xB8E5 # 0 +0x9E7C 0xB8E6 # 0 +0x9E7D 0xB8E7 # 0 +0x9E81 0xB8E8 # 0 +0x9E82 0xB8E9 # 0 +0x9E83 0xB8EA # 0 +0x9E84 0xB8EB # 0 +0x9E85 0xB8EC # 0 +0x9E86 0xB8ED # 0 +0x9E87 0xB8EE # 0 +0x9E88 0xB8EF # 0 +0x9E89 0xB8F0 # 0 +0x9E8A 0xB8F1 # 0 +0x9E8B 0xB8F2 # 0 +0x9E8C 0xB8F3 # 0 +0x9E8D 0xB8F4 # 0 +0x9E8E 0xB8F5 # 0 +0x9E8F 0xB8F6 # 0 +0x9E90 0xB8F7 # 0 +0x9E91 0xB8F8 # 0 +0x9E93 0xB8F9 # 0 +0x9E94 0xB8FA # 0 +0x9E95 0xB8FB # 0 +0x9E96 0xB8FC # 0 +0x9E97 0xB8FD # 0 +0x9E98 0xB8FE # 0 +0x9E99 0xB8FF # 0 +0x9E9A 0xB900 # 0 +0x9E9B 0xB901 # 0 +0x9E9C 0xB902 # 0 +0x9E9D 0xB903 # 0 +0x9EA1 0xB904 # 0 +0x9EA2 0xB905 # 0 +0x9EA3 0xB906 # 0 +0x9EA4 0xB907 # 0 +0x9EA5 0xB908 # 0 +0x9EA6 0xB909 # 0 +0x9EA7 0xB90A # 0 +0x9EA8 0xB90B # 0 +0x9EA9 0xB90C # 0 +0x9EAA 0xB90D # 0 +0x9EAB 0xB90E # 0 +0x9EAC 0xB90F # 0 +0x9EAD 0xB910 # 0 +0x9EAE 0xB911 # 0 +0x9EAF 0xB912 # 0 +0x9EB0 0xB913 # 0 +0x9EB1 0xB914 # 0 +0x9EB3 0xB915 # 0 +0x9EB4 0xB916 # 0 +0x9EB5 0xB917 # 0 +0x9EB6 0xB918 # 0 +0x9EB7 0xB919 # 0 +0x9EB8 0xB91A # 0 +0x9EB9 0xB91B # 0 +0x9EBA 0xB91C # 0 +0x9EBB 0xB91D # 0 +0x9EBC 0xB91E # 0 +0x9EBD 0xB91F # 0 +0x9EC1 0xB920 # 0 +0x9EC2 0xB921 # 0 +0x9EC3 0xB922 # 0 +0x9EC4 0xB923 # 0 +0x9EC5 0xB924 # 0 +0x9EC6 0xB925 # 0 +0x9EC7 0xB926 # 0 +0x9EC8 0xB927 # 0 +0x9EC9 0xB928 # 0 +0x9ECA 0xB929 # 0 +0x9ECB 0xB92A # 0 +0x9ECC 0xB92B # 0 +0x9ECD 0xB92C # 0 +0x9ECE 0xB92D # 0 +0x9ECF 0xB92E # 0 +0x9ED0 0xB92F # 0 +0x9ED1 0xB930 # 0 +0x9ED3 0xB931 # 0 +0x9ED4 0xB932 # 0 +0x9ED5 0xB933 # 0 +0x9ED6 0xB934 # 0 +0x9ED7 0xB935 # 0 +0x9ED8 0xB936 # 0 +0x9ED9 0xB937 # 0 +0x9EDA 0xB938 # 0 +0x9EDB 0xB939 # 0 +0x9EDC 0xB93A # 0 +0x9EDD 0xB93B # 0 +0x9EE1 0xB93C # 0 +0x9EE2 0xB93D # 0 +0x9EE3 0xB93E # 0 +0x9EE4 0xB93F # 0 +0x9EE5 0xB940 # 0 +0x9EE6 0xB941 # 0 +0x9EE7 0xB942 # 0 +0x9EE8 0xB943 # 0 +0x9EE9 0xB944 # 0 +0x9EEA 0xB945 # 0 +0x9EEB 0xB946 # 0 +0x9EEC 0xB947 # 0 +0x9EED 0xB948 # 0 +0x9EEE 0xB949 # 0 +0x9EEF 0xB94A # 0 +0x9EF0 0xB94B # 0 +0x9EF1 0xB94C # 0 +0x9EF3 0xB94D # 0 +0x9EF4 0xB94E # 0 +0x9EF5 0xB94F # 0 +0x9EF6 0xB950 # 0 +0x9EF7 0xB951 # 0 +0x9EF8 0xB952 # 0 +0x9EF9 0xB953 # 0 +0x9EFA 0xB954 # 0 +0x9EFB 0xB955 # 0 +0x9EFC 0xB956 # 0 +0x9EFD 0xB957 # 0 +0x9F41 0xB958 # 0 +0x9F42 0xB959 # 0 +0x9F43 0xB95A # 0 +0x9F44 0xB95B # 0 +0x9F45 0xB95C # 0 +0x9F46 0xB95D # 0 +0x9F47 0xB95E # 0 +0x9F48 0xB95F # 0 +0x9F49 0xB960 # 0 +0x9F4A 0xB961 # 0 +0x9F4B 0xB962 # 0 +0x9F4C 0xB963 # 0 +0x9F4D 0xB964 # 0 +0x9F4E 0xB965 # 0 +0x9F4F 0xB966 # 0 +0x9F50 0xB967 # 0 +0x9F51 0xB968 # 0 +0x9F53 0xB969 # 0 +0x9F54 0xB96A # 0 +0x9F55 0xB96B # 0 +0x9F56 0xB96C # 0 +0x9F57 0xB96D # 0 +0x9F58 0xB96E # 0 +0x9F59 0xB96F # 0 +0x9F5A 0xB970 # 0 +0x9F5B 0xB971 # 0 +0x9F5C 0xB972 # 0 +0x9F5D 0xB973 # 0 +0x9F61 0xB974 # 0 +0x9F62 0xB975 # 0 +0x9F63 0xB976 # 0 +0x9F64 0xB977 # 0 +0x9F65 0xB978 # 0 +0x9F66 0xB979 # 0 +0x9F67 0xB97A # 0 +0x9F68 0xB97B # 0 +0x9F69 0xB97C # 0 +0x9F6A 0xB97D # 0 +0x9F6B 0xB97E # 0 +0x9F6C 0xB97F # 0 +0x9F6D 0xB980 # 0 +0x9F6E 0xB981 # 0 +0x9F6F 0xB982 # 0 +0x9F70 0xB983 # 0 +0x9F71 0xB984 # 0 +0x9F73 0xB985 # 0 +0x9F74 0xB986 # 0 +0x9F75 0xB987 # 0 +0x9F76 0xB988 # 0 +0x9F77 0xB989 # 0 +0x9F78 0xB98A # 0 +0x9F79 0xB98B # 0 +0x9F7A 0xB98C # 0 +0x9F7B 0xB98D # 0 +0x9F7C 0xB98E # 0 +0x9F7D 0xB98F # 0 +0x9F81 0xB990 # 0 +0x9F82 0xB991 # 0 +0x9F83 0xB992 # 0 +0x9F84 0xB993 # 0 +0x9F85 0xB994 # 0 +0x9F86 0xB995 # 0 +0x9F87 0xB996 # 0 +0x9F88 0xB997 # 0 +0x9F89 0xB998 # 0 +0x9F8A 0xB999 # 0 +0x9F8B 0xB99A # 0 +0x9F8C 0xB99B # 0 +0x9F8D 0xB99C # 0 +0x9F8E 0xB99D # 0 +0x9F8F 0xB99E # 0 +0x9F90 0xB99F # 0 +0x9F91 0xB9A0 # 0 +0x9F93 0xB9A1 # 0 +0x9F94 0xB9A2 # 0 +0x9F95 0xB9A3 # 0 +0x9F96 0xB9A4 # 0 +0x9F97 0xB9A5 # 0 +0x9F98 0xB9A6 # 0 +0x9F99 0xB9A7 # 0 +0x9F9A 0xB9A8 # 0 +0x9F9B 0xB9A9 # 0 +0x9F9C 0xB9AA # 0 +0x9F9D 0xB9AB # 0 +0x9FA1 0xB9AC # 0 +0x9FA2 0xB9AD # 0 +0x9FA3 0xB9AE # 0 +0x9FA4 0xB9AF # 0 +0x9FA5 0xB9B0 # 0 +0x9FA6 0xB9B1 # 0 +0x9FA7 0xB9B2 # 0 +0x9FA8 0xB9B3 # 0 +0x9FA9 0xB9B4 # 0 +0x9FAA 0xB9B5 # 0 +0x9FAB 0xB9B6 # 0 +0x9FAC 0xB9B7 # 0 +0x9FAD 0xB9B8 # 0 +0x9FAE 0xB9B9 # 0 +0x9FAF 0xB9BA # 0 +0x9FB0 0xB9BB # 0 +0x9FB1 0xB9BC # 0 +0x9FB3 0xB9BD # 0 +0x9FB4 0xB9BE # 0 +0x9FB5 0xB9BF # 0 +0x9FB6 0xB9C0 # 0 +0x9FB7 0xB9C1 # 0 +0x9FB8 0xB9C2 # 0 +0x9FB9 0xB9C3 # 0 +0x9FBA 0xB9C4 # 0 +0x9FBB 0xB9C5 # 0 +0x9FBC 0xB9C6 # 0 +0x9FBD 0xB9C7 # 0 +0xA041 0x1106 # 0 +0xA061 0xB9C8 # 0 +0xA062 0xB9C9 # 0 +0xA063 0xB9CA # 0 +0xA064 0xB9CB # 0 +0xA065 0xB9CC # 0 +0xA066 0xB9CD # 0 +0xA067 0xB9CE # 0 +0xA068 0xB9CF # 0 +0xA069 0xB9D0 # 0 +0xA06A 0xB9D1 # 0 +0xA06B 0xB9D2 # 0 +0xA06C 0xB9D3 # 0 +0xA06D 0xB9D4 # 0 +0xA06E 0xB9D5 # 0 +0xA06F 0xB9D6 # 0 +0xA070 0xB9D7 # 0 +0xA071 0xB9D8 # 0 +0xA073 0xB9D9 # 0 +0xA074 0xB9DA # 0 +0xA075 0xB9DB # 0 +0xA076 0xB9DC # 0 +0xA077 0xB9DD # 0 +0xA078 0xB9DE # 0 +0xA079 0xB9DF # 0 +0xA07A 0xB9E0 # 0 +0xA07B 0xB9E1 # 0 +0xA07C 0xB9E2 # 0 +0xA07D 0xB9E3 # 0 +0xA081 0xB9E4 # 0 +0xA082 0xB9E5 # 0 +0xA083 0xB9E6 # 0 +0xA084 0xB9E7 # 0 +0xA085 0xB9E8 # 0 +0xA086 0xB9E9 # 0 +0xA087 0xB9EA # 0 +0xA088 0xB9EB # 0 +0xA089 0xB9EC # 0 +0xA08A 0xB9ED # 0 +0xA08B 0xB9EE # 0 +0xA08C 0xB9EF # 0 +0xA08D 0xB9F0 # 0 +0xA08E 0xB9F1 # 0 +0xA08F 0xB9F2 # 0 +0xA090 0xB9F3 # 0 +0xA091 0xB9F4 # 0 +0xA093 0xB9F5 # 0 +0xA094 0xB9F6 # 0 +0xA095 0xB9F7 # 0 +0xA096 0xB9F8 # 0 +0xA097 0xB9F9 # 0 +0xA098 0xB9FA # 0 +0xA099 0xB9FB # 0 +0xA09A 0xB9FC # 0 +0xA09B 0xB9FD # 0 +0xA09C 0xB9FE # 0 +0xA09D 0xB9FF # 0 +0xA0A1 0xBA00 # 0 +0xA0A2 0xBA01 # 0 +0xA0A3 0xBA02 # 0 +0xA0A4 0xBA03 # 0 +0xA0A5 0xBA04 # 0 +0xA0A6 0xBA05 # 0 +0xA0A7 0xBA06 # 0 +0xA0A8 0xBA07 # 0 +0xA0A9 0xBA08 # 0 +0xA0AA 0xBA09 # 0 +0xA0AB 0xBA0A # 0 +0xA0AC 0xBA0B # 0 +0xA0AD 0xBA0C # 0 +0xA0AE 0xBA0D # 0 +0xA0AF 0xBA0E # 0 +0xA0B0 0xBA0F # 0 +0xA0B1 0xBA10 # 0 +0xA0B3 0xBA11 # 0 +0xA0B4 0xBA12 # 0 +0xA0B5 0xBA13 # 0 +0xA0B6 0xBA14 # 0 +0xA0B7 0xBA15 # 0 +0xA0B8 0xBA16 # 0 +0xA0B9 0xBA17 # 0 +0xA0BA 0xBA18 # 0 +0xA0BB 0xBA19 # 0 +0xA0BC 0xBA1A # 0 +0xA0BD 0xBA1B # 0 +0xA0C1 0xBA1C # 0 +0xA0C2 0xBA1D # 0 +0xA0C3 0xBA1E # 0 +0xA0C4 0xBA1F # 0 +0xA0C5 0xBA20 # 0 +0xA0C6 0xBA21 # 0 +0xA0C7 0xBA22 # 0 +0xA0C8 0xBA23 # 0 +0xA0C9 0xBA24 # 0 +0xA0CA 0xBA25 # 0 +0xA0CB 0xBA26 # 0 +0xA0CC 0xBA27 # 0 +0xA0CD 0xBA28 # 0 +0xA0CE 0xBA29 # 0 +0xA0CF 0xBA2A # 0 +0xA0D0 0xBA2B # 0 +0xA0D1 0xBA2C # 0 +0xA0D3 0xBA2D # 0 +0xA0D4 0xBA2E # 0 +0xA0D5 0xBA2F # 0 +0xA0D6 0xBA30 # 0 +0xA0D7 0xBA31 # 0 +0xA0D8 0xBA32 # 0 +0xA0D9 0xBA33 # 0 +0xA0DA 0xBA34 # 0 +0xA0DB 0xBA35 # 0 +0xA0DC 0xBA36 # 0 +0xA0DD 0xBA37 # 0 +0xA0E1 0xBA38 # 0 +0xA0E2 0xBA39 # 0 +0xA0E3 0xBA3A # 0 +0xA0E4 0xBA3B # 0 +0xA0E5 0xBA3C # 0 +0xA0E6 0xBA3D # 0 +0xA0E7 0xBA3E # 0 +0xA0E8 0xBA3F # 0 +0xA0E9 0xBA40 # 0 +0xA0EA 0xBA41 # 0 +0xA0EB 0xBA42 # 0 +0xA0EC 0xBA43 # 0 +0xA0ED 0xBA44 # 0 +0xA0EE 0xBA45 # 0 +0xA0EF 0xBA46 # 0 +0xA0F0 0xBA47 # 0 +0xA0F1 0xBA48 # 0 +0xA0F3 0xBA49 # 0 +0xA0F4 0xBA4A # 0 +0xA0F5 0xBA4B # 0 +0xA0F6 0xBA4C # 0 +0xA0F7 0xBA4D # 0 +0xA0F8 0xBA4E # 0 +0xA0F9 0xBA4F # 0 +0xA0FA 0xBA50 # 0 +0xA0FB 0xBA51 # 0 +0xA0FC 0xBA52 # 0 +0xA0FD 0xBA53 # 0 +0xA141 0xBA54 # 0 +0xA142 0xBA55 # 0 +0xA143 0xBA56 # 0 +0xA144 0xBA57 # 0 +0xA145 0xBA58 # 0 +0xA146 0xBA59 # 0 +0xA147 0xBA5A # 0 +0xA148 0xBA5B # 0 +0xA149 0xBA5C # 0 +0xA14A 0xBA5D # 0 +0xA14B 0xBA5E # 0 +0xA14C 0xBA5F # 0 +0xA14D 0xBA60 # 0 +0xA14E 0xBA61 # 0 +0xA14F 0xBA62 # 0 +0xA150 0xBA63 # 0 +0xA151 0xBA64 # 0 +0xA153 0xBA65 # 0 +0xA154 0xBA66 # 0 +0xA155 0xBA67 # 0 +0xA156 0xBA68 # 0 +0xA157 0xBA69 # 0 +0xA158 0xBA6A # 0 +0xA159 0xBA6B # 0 +0xA15A 0xBA6C # 0 +0xA15B 0xBA6D # 0 +0xA15C 0xBA6E # 0 +0xA15D 0xBA6F # 0 +0xA161 0xBA70 # 0 +0xA162 0xBA71 # 0 +0xA163 0xBA72 # 0 +0xA164 0xBA73 # 0 +0xA165 0xBA74 # 0 +0xA166 0xBA75 # 0 +0xA167 0xBA76 # 0 +0xA168 0xBA77 # 0 +0xA169 0xBA78 # 0 +0xA16A 0xBA79 # 0 +0xA16B 0xBA7A # 0 +0xA16C 0xBA7B # 0 +0xA16D 0xBA7C # 0 +0xA16E 0xBA7D # 0 +0xA16F 0xBA7E # 0 +0xA170 0xBA7F # 0 +0xA171 0xBA80 # 0 +0xA173 0xBA81 # 0 +0xA174 0xBA82 # 0 +0xA175 0xBA83 # 0 +0xA176 0xBA84 # 0 +0xA177 0xBA85 # 0 +0xA178 0xBA86 # 0 +0xA179 0xBA87 # 0 +0xA17A 0xBA88 # 0 +0xA17B 0xBA89 # 0 +0xA17C 0xBA8A # 0 +0xA17D 0xBA8B # 0 +0xA181 0xBA8C # 0 +0xA182 0xBA8D # 0 +0xA183 0xBA8E # 0 +0xA184 0xBA8F # 0 +0xA185 0xBA90 # 0 +0xA186 0xBA91 # 0 +0xA187 0xBA92 # 0 +0xA188 0xBA93 # 0 +0xA189 0xBA94 # 0 +0xA18A 0xBA95 # 0 +0xA18B 0xBA96 # 0 +0xA18C 0xBA97 # 0 +0xA18D 0xBA98 # 0 +0xA18E 0xBA99 # 0 +0xA18F 0xBA9A # 0 +0xA190 0xBA9B # 0 +0xA191 0xBA9C # 0 +0xA193 0xBA9D # 0 +0xA194 0xBA9E # 0 +0xA195 0xBA9F # 0 +0xA196 0xBAA0 # 0 +0xA197 0xBAA1 # 0 +0xA198 0xBAA2 # 0 +0xA199 0xBAA3 # 0 +0xA19A 0xBAA4 # 0 +0xA19B 0xBAA5 # 0 +0xA19C 0xBAA6 # 0 +0xA19D 0xBAA7 # 0 +0xA1A1 0xBAA8 # 0 +0xA1A2 0xBAA9 # 0 +0xA1A3 0xBAAA # 0 +0xA1A4 0xBAAB # 0 +0xA1A5 0xBAAC # 0 +0xA1A6 0xBAAD # 0 +0xA1A7 0xBAAE # 0 +0xA1A8 0xBAAF # 0 +0xA1A9 0xBAB0 # 0 +0xA1AA 0xBAB1 # 0 +0xA1AB 0xBAB2 # 0 +0xA1AC 0xBAB3 # 0 +0xA1AD 0xBAB4 # 0 +0xA1AE 0xBAB5 # 0 +0xA1AF 0xBAB6 # 0 +0xA1B0 0xBAB7 # 0 +0xA1B1 0xBAB8 # 0 +0xA1B3 0xBAB9 # 0 +0xA1B4 0xBABA # 0 +0xA1B5 0xBABB # 0 +0xA1B6 0xBABC # 0 +0xA1B7 0xBABD # 0 +0xA1B8 0xBABE # 0 +0xA1B9 0xBABF # 0 +0xA1BA 0xBAC0 # 0 +0xA1BB 0xBAC1 # 0 +0xA1BC 0xBAC2 # 0 +0xA1BD 0xBAC3 # 0 +0xA1C1 0xBAC4 # 0 +0xA1C2 0xBAC5 # 0 +0xA1C3 0xBAC6 # 0 +0xA1C4 0xBAC7 # 0 +0xA1C5 0xBAC8 # 0 +0xA1C6 0xBAC9 # 0 +0xA1C7 0xBACA # 0 +0xA1C8 0xBACB # 0 +0xA1C9 0xBACC # 0 +0xA1CA 0xBACD # 0 +0xA1CB 0xBACE # 0 +0xA1CC 0xBACF # 0 +0xA1CD 0xBAD0 # 0 +0xA1CE 0xBAD1 # 0 +0xA1CF 0xBAD2 # 0 +0xA1D0 0xBAD3 # 0 +0xA1D1 0xBAD4 # 0 +0xA1D3 0xBAD5 # 0 +0xA1D4 0xBAD6 # 0 +0xA1D5 0xBAD7 # 0 +0xA1D6 0xBAD8 # 0 +0xA1D7 0xBAD9 # 0 +0xA1D8 0xBADA # 0 +0xA1D9 0xBADB # 0 +0xA1DA 0xBADC # 0 +0xA1DB 0xBADD # 0 +0xA1DC 0xBADE # 0 +0xA1DD 0xBADF # 0 +0xA1E1 0xBAE0 # 0 +0xA1E2 0xBAE1 # 0 +0xA1E3 0xBAE2 # 0 +0xA1E4 0xBAE3 # 0 +0xA1E5 0xBAE4 # 0 +0xA1E6 0xBAE5 # 0 +0xA1E7 0xBAE6 # 0 +0xA1E8 0xBAE7 # 0 +0xA1E9 0xBAE8 # 0 +0xA1EA 0xBAE9 # 0 +0xA1EB 0xBAEA # 0 +0xA1EC 0xBAEB # 0 +0xA1ED 0xBAEC # 0 +0xA1EE 0xBAED # 0 +0xA1EF 0xBAEE # 0 +0xA1F0 0xBAEF # 0 +0xA1F1 0xBAF0 # 0 +0xA1F3 0xBAF1 # 0 +0xA1F4 0xBAF2 # 0 +0xA1F5 0xBAF3 # 0 +0xA1F6 0xBAF4 # 0 +0xA1F7 0xBAF5 # 0 +0xA1F8 0xBAF6 # 0 +0xA1F9 0xBAF7 # 0 +0xA1FA 0xBAF8 # 0 +0xA1FB 0xBAF9 # 0 +0xA1FC 0xBAFA # 0 +0xA1FD 0xBAFB # 0 +0xA241 0xBAFC # 0 +0xA242 0xBAFD # 0 +0xA243 0xBAFE # 0 +0xA244 0xBAFF # 0 +0xA245 0xBB00 # 0 +0xA246 0xBB01 # 0 +0xA247 0xBB02 # 0 +0xA248 0xBB03 # 0 +0xA249 0xBB04 # 0 +0xA24A 0xBB05 # 0 +0xA24B 0xBB06 # 0 +0xA24C 0xBB07 # 0 +0xA24D 0xBB08 # 0 +0xA24E 0xBB09 # 0 +0xA24F 0xBB0A # 0 +0xA250 0xBB0B # 0 +0xA251 0xBB0C # 0 +0xA253 0xBB0D # 0 +0xA254 0xBB0E # 0 +0xA255 0xBB0F # 0 +0xA256 0xBB10 # 0 +0xA257 0xBB11 # 0 +0xA258 0xBB12 # 0 +0xA259 0xBB13 # 0 +0xA25A 0xBB14 # 0 +0xA25B 0xBB15 # 0 +0xA25C 0xBB16 # 0 +0xA25D 0xBB17 # 0 +0xA261 0xBB18 # 0 +0xA262 0xBB19 # 0 +0xA263 0xBB1A # 0 +0xA264 0xBB1B # 0 +0xA265 0xBB1C # 0 +0xA266 0xBB1D # 0 +0xA267 0xBB1E # 0 +0xA268 0xBB1F # 0 +0xA269 0xBB20 # 0 +0xA26A 0xBB21 # 0 +0xA26B 0xBB22 # 0 +0xA26C 0xBB23 # 0 +0xA26D 0xBB24 # 0 +0xA26E 0xBB25 # 0 +0xA26F 0xBB26 # 0 +0xA270 0xBB27 # 0 +0xA271 0xBB28 # 0 +0xA273 0xBB29 # 0 +0xA274 0xBB2A # 0 +0xA275 0xBB2B # 0 +0xA276 0xBB2C # 0 +0xA277 0xBB2D # 0 +0xA278 0xBB2E # 0 +0xA279 0xBB2F # 0 +0xA27A 0xBB30 # 0 +0xA27B 0xBB31 # 0 +0xA27C 0xBB32 # 0 +0xA27D 0xBB33 # 0 +0xA281 0xBB34 # 0 +0xA282 0xBB35 # 0 +0xA283 0xBB36 # 0 +0xA284 0xBB37 # 0 +0xA285 0xBB38 # 0 +0xA286 0xBB39 # 0 +0xA287 0xBB3A # 0 +0xA288 0xBB3B # 0 +0xA289 0xBB3C # 0 +0xA28A 0xBB3D # 0 +0xA28B 0xBB3E # 0 +0xA28C 0xBB3F # 0 +0xA28D 0xBB40 # 0 +0xA28E 0xBB41 # 0 +0xA28F 0xBB42 # 0 +0xA290 0xBB43 # 0 +0xA291 0xBB44 # 0 +0xA293 0xBB45 # 0 +0xA294 0xBB46 # 0 +0xA295 0xBB47 # 0 +0xA296 0xBB48 # 0 +0xA297 0xBB49 # 0 +0xA298 0xBB4A # 0 +0xA299 0xBB4B # 0 +0xA29A 0xBB4C # 0 +0xA29B 0xBB4D # 0 +0xA29C 0xBB4E # 0 +0xA29D 0xBB4F # 0 +0xA2A1 0xBB50 # 0 +0xA2A2 0xBB51 # 0 +0xA2A3 0xBB52 # 0 +0xA2A4 0xBB53 # 0 +0xA2A5 0xBB54 # 0 +0xA2A6 0xBB55 # 0 +0xA2A7 0xBB56 # 0 +0xA2A8 0xBB57 # 0 +0xA2A9 0xBB58 # 0 +0xA2AA 0xBB59 # 0 +0xA2AB 0xBB5A # 0 +0xA2AC 0xBB5B # 0 +0xA2AD 0xBB5C # 0 +0xA2AE 0xBB5D # 0 +0xA2AF 0xBB5E # 0 +0xA2B0 0xBB5F # 0 +0xA2B1 0xBB60 # 0 +0xA2B3 0xBB61 # 0 +0xA2B4 0xBB62 # 0 +0xA2B5 0xBB63 # 0 +0xA2B6 0xBB64 # 0 +0xA2B7 0xBB65 # 0 +0xA2B8 0xBB66 # 0 +0xA2B9 0xBB67 # 0 +0xA2BA 0xBB68 # 0 +0xA2BB 0xBB69 # 0 +0xA2BC 0xBB6A # 0 +0xA2BD 0xBB6B # 0 +0xA2C1 0xBB6C # 0 +0xA2C2 0xBB6D # 0 +0xA2C3 0xBB6E # 0 +0xA2C4 0xBB6F # 0 +0xA2C5 0xBB70 # 0 +0xA2C6 0xBB71 # 0 +0xA2C7 0xBB72 # 0 +0xA2C8 0xBB73 # 0 +0xA2C9 0xBB74 # 0 +0xA2CA 0xBB75 # 0 +0xA2CB 0xBB76 # 0 +0xA2CC 0xBB77 # 0 +0xA2CD 0xBB78 # 0 +0xA2CE 0xBB79 # 0 +0xA2CF 0xBB7A # 0 +0xA2D0 0xBB7B # 0 +0xA2D1 0xBB7C # 0 +0xA2D3 0xBB7D # 0 +0xA2D4 0xBB7E # 0 +0xA2D5 0xBB7F # 0 +0xA2D6 0xBB80 # 0 +0xA2D7 0xBB81 # 0 +0xA2D8 0xBB82 # 0 +0xA2D9 0xBB83 # 0 +0xA2DA 0xBB84 # 0 +0xA2DB 0xBB85 # 0 +0xA2DC 0xBB86 # 0 +0xA2DD 0xBB87 # 0 +0xA2E1 0xBB88 # 0 +0xA2E2 0xBB89 # 0 +0xA2E3 0xBB8A # 0 +0xA2E4 0xBB8B # 0 +0xA2E5 0xBB8C # 0 +0xA2E6 0xBB8D # 0 +0xA2E7 0xBB8E # 0 +0xA2E8 0xBB8F # 0 +0xA2E9 0xBB90 # 0 +0xA2EA 0xBB91 # 0 +0xA2EB 0xBB92 # 0 +0xA2EC 0xBB93 # 0 +0xA2ED 0xBB94 # 0 +0xA2EE 0xBB95 # 0 +0xA2EF 0xBB96 # 0 +0xA2F0 0xBB97 # 0 +0xA2F1 0xBB98 # 0 +0xA2F3 0xBB99 # 0 +0xA2F4 0xBB9A # 0 +0xA2F5 0xBB9B # 0 +0xA2F6 0xBB9C # 0 +0xA2F7 0xBB9D # 0 +0xA2F8 0xBB9E # 0 +0xA2F9 0xBB9F # 0 +0xA2FA 0xBBA0 # 0 +0xA2FB 0xBBA1 # 0 +0xA2FC 0xBBA2 # 0 +0xA2FD 0xBBA3 # 0 +0xA341 0xBBA4 # 0 +0xA342 0xBBA5 # 0 +0xA343 0xBBA6 # 0 +0xA344 0xBBA7 # 0 +0xA345 0xBBA8 # 0 +0xA346 0xBBA9 # 0 +0xA347 0xBBAA # 0 +0xA348 0xBBAB # 0 +0xA349 0xBBAC # 0 +0xA34A 0xBBAD # 0 +0xA34B 0xBBAE # 0 +0xA34C 0xBBAF # 0 +0xA34D 0xBBB0 # 0 +0xA34E 0xBBB1 # 0 +0xA34F 0xBBB2 # 0 +0xA350 0xBBB3 # 0 +0xA351 0xBBB4 # 0 +0xA353 0xBBB5 # 0 +0xA354 0xBBB6 # 0 +0xA355 0xBBB7 # 0 +0xA356 0xBBB8 # 0 +0xA357 0xBBB9 # 0 +0xA358 0xBBBA # 0 +0xA359 0xBBBB # 0 +0xA35A 0xBBBC # 0 +0xA35B 0xBBBD # 0 +0xA35C 0xBBBE # 0 +0xA35D 0xBBBF # 0 +0xA361 0xBBC0 # 0 +0xA362 0xBBC1 # 0 +0xA363 0xBBC2 # 0 +0xA364 0xBBC3 # 0 +0xA365 0xBBC4 # 0 +0xA366 0xBBC5 # 0 +0xA367 0xBBC6 # 0 +0xA368 0xBBC7 # 0 +0xA369 0xBBC8 # 0 +0xA36A 0xBBC9 # 0 +0xA36B 0xBBCA # 0 +0xA36C 0xBBCB # 0 +0xA36D 0xBBCC # 0 +0xA36E 0xBBCD # 0 +0xA36F 0xBBCE # 0 +0xA370 0xBBCF # 0 +0xA371 0xBBD0 # 0 +0xA373 0xBBD1 # 0 +0xA374 0xBBD2 # 0 +0xA375 0xBBD3 # 0 +0xA376 0xBBD4 # 0 +0xA377 0xBBD5 # 0 +0xA378 0xBBD6 # 0 +0xA379 0xBBD7 # 0 +0xA37A 0xBBD8 # 0 +0xA37B 0xBBD9 # 0 +0xA37C 0xBBDA # 0 +0xA37D 0xBBDB # 0 +0xA381 0xBBDC # 0 +0xA382 0xBBDD # 0 +0xA383 0xBBDE # 0 +0xA384 0xBBDF # 0 +0xA385 0xBBE0 # 0 +0xA386 0xBBE1 # 0 +0xA387 0xBBE2 # 0 +0xA388 0xBBE3 # 0 +0xA389 0xBBE4 # 0 +0xA38A 0xBBE5 # 0 +0xA38B 0xBBE6 # 0 +0xA38C 0xBBE7 # 0 +0xA38D 0xBBE8 # 0 +0xA38E 0xBBE9 # 0 +0xA38F 0xBBEA # 0 +0xA390 0xBBEB # 0 +0xA391 0xBBEC # 0 +0xA393 0xBBED # 0 +0xA394 0xBBEE # 0 +0xA395 0xBBEF # 0 +0xA396 0xBBF0 # 0 +0xA397 0xBBF1 # 0 +0xA398 0xBBF2 # 0 +0xA399 0xBBF3 # 0 +0xA39A 0xBBF4 # 0 +0xA39B 0xBBF5 # 0 +0xA39C 0xBBF6 # 0 +0xA39D 0xBBF7 # 0 +0xA3A1 0xBBF8 # 0 +0xA3A2 0xBBF9 # 0 +0xA3A3 0xBBFA # 0 +0xA3A4 0xBBFB # 0 +0xA3A5 0xBBFC # 0 +0xA3A6 0xBBFD # 0 +0xA3A7 0xBBFE # 0 +0xA3A8 0xBBFF # 0 +0xA3A9 0xBC00 # 0 +0xA3AA 0xBC01 # 0 +0xA3AB 0xBC02 # 0 +0xA3AC 0xBC03 # 0 +0xA3AD 0xBC04 # 0 +0xA3AE 0xBC05 # 0 +0xA3AF 0xBC06 # 0 +0xA3B0 0xBC07 # 0 +0xA3B1 0xBC08 # 0 +0xA3B3 0xBC09 # 0 +0xA3B4 0xBC0A # 0 +0xA3B5 0xBC0B # 0 +0xA3B6 0xBC0C # 0 +0xA3B7 0xBC0D # 0 +0xA3B8 0xBC0E # 0 +0xA3B9 0xBC0F # 0 +0xA3BA 0xBC10 # 0 +0xA3BB 0xBC11 # 0 +0xA3BC 0xBC12 # 0 +0xA3BD 0xBC13 # 0 +0xA441 0x1107 # 0 +0xA461 0xBC14 # 0 +0xA462 0xBC15 # 0 +0xA463 0xBC16 # 0 +0xA464 0xBC17 # 0 +0xA465 0xBC18 # 0 +0xA466 0xBC19 # 0 +0xA467 0xBC1A # 0 +0xA468 0xBC1B # 0 +0xA469 0xBC1C # 0 +0xA46A 0xBC1D # 0 +0xA46B 0xBC1E # 0 +0xA46C 0xBC1F # 0 +0xA46D 0xBC20 # 0 +0xA46E 0xBC21 # 0 +0xA46F 0xBC22 # 0 +0xA470 0xBC23 # 0 +0xA471 0xBC24 # 0 +0xA473 0xBC25 # 0 +0xA474 0xBC26 # 0 +0xA475 0xBC27 # 0 +0xA476 0xBC28 # 0 +0xA477 0xBC29 # 0 +0xA478 0xBC2A # 0 +0xA479 0xBC2B # 0 +0xA47A 0xBC2C # 0 +0xA47B 0xBC2D # 0 +0xA47C 0xBC2E # 0 +0xA47D 0xBC2F # 0 +0xA481 0xBC30 # 0 +0xA482 0xBC31 # 0 +0xA483 0xBC32 # 0 +0xA484 0xBC33 # 0 +0xA485 0xBC34 # 0 +0xA486 0xBC35 # 0 +0xA487 0xBC36 # 0 +0xA488 0xBC37 # 0 +0xA489 0xBC38 # 0 +0xA48A 0xBC39 # 0 +0xA48B 0xBC3A # 0 +0xA48C 0xBC3B # 0 +0xA48D 0xBC3C # 0 +0xA48E 0xBC3D # 0 +0xA48F 0xBC3E # 0 +0xA490 0xBC3F # 0 +0xA491 0xBC40 # 0 +0xA493 0xBC41 # 0 +0xA494 0xBC42 # 0 +0xA495 0xBC43 # 0 +0xA496 0xBC44 # 0 +0xA497 0xBC45 # 0 +0xA498 0xBC46 # 0 +0xA499 0xBC47 # 0 +0xA49A 0xBC48 # 0 +0xA49B 0xBC49 # 0 +0xA49C 0xBC4A # 0 +0xA49D 0xBC4B # 0 +0xA4A1 0xBC4C # 0 +0xA4A2 0xBC4D # 0 +0xA4A3 0xBC4E # 0 +0xA4A4 0xBC4F # 0 +0xA4A5 0xBC50 # 0 +0xA4A6 0xBC51 # 0 +0xA4A7 0xBC52 # 0 +0xA4A8 0xBC53 # 0 +0xA4A9 0xBC54 # 0 +0xA4AA 0xBC55 # 0 +0xA4AB 0xBC56 # 0 +0xA4AC 0xBC57 # 0 +0xA4AD 0xBC58 # 0 +0xA4AE 0xBC59 # 0 +0xA4AF 0xBC5A # 0 +0xA4B0 0xBC5B # 0 +0xA4B1 0xBC5C # 0 +0xA4B3 0xBC5D # 0 +0xA4B4 0xBC5E # 0 +0xA4B5 0xBC5F # 0 +0xA4B6 0xBC60 # 0 +0xA4B7 0xBC61 # 0 +0xA4B8 0xBC62 # 0 +0xA4B9 0xBC63 # 0 +0xA4BA 0xBC64 # 0 +0xA4BB 0xBC65 # 0 +0xA4BC 0xBC66 # 0 +0xA4BD 0xBC67 # 0 +0xA4C1 0xBC68 # 0 +0xA4C2 0xBC69 # 0 +0xA4C3 0xBC6A # 0 +0xA4C4 0xBC6B # 0 +0xA4C5 0xBC6C # 0 +0xA4C6 0xBC6D # 0 +0xA4C7 0xBC6E # 0 +0xA4C8 0xBC6F # 0 +0xA4C9 0xBC70 # 0 +0xA4CA 0xBC71 # 0 +0xA4CB 0xBC72 # 0 +0xA4CC 0xBC73 # 0 +0xA4CD 0xBC74 # 0 +0xA4CE 0xBC75 # 0 +0xA4CF 0xBC76 # 0 +0xA4D0 0xBC77 # 0 +0xA4D1 0xBC78 # 0 +0xA4D3 0xBC79 # 0 +0xA4D4 0xBC7A # 0 +0xA4D5 0xBC7B # 0 +0xA4D6 0xBC7C # 0 +0xA4D7 0xBC7D # 0 +0xA4D8 0xBC7E # 0 +0xA4D9 0xBC7F # 0 +0xA4DA 0xBC80 # 0 +0xA4DB 0xBC81 # 0 +0xA4DC 0xBC82 # 0 +0xA4DD 0xBC83 # 0 +0xA4E1 0xBC84 # 0 +0xA4E2 0xBC85 # 0 +0xA4E3 0xBC86 # 0 +0xA4E4 0xBC87 # 0 +0xA4E5 0xBC88 # 0 +0xA4E6 0xBC89 # 0 +0xA4E7 0xBC8A # 0 +0xA4E8 0xBC8B # 0 +0xA4E9 0xBC8C # 0 +0xA4EA 0xBC8D # 0 +0xA4EB 0xBC8E # 0 +0xA4EC 0xBC8F # 0 +0xA4ED 0xBC90 # 0 +0xA4EE 0xBC91 # 0 +0xA4EF 0xBC92 # 0 +0xA4F0 0xBC93 # 0 +0xA4F1 0xBC94 # 0 +0xA4F3 0xBC95 # 0 +0xA4F4 0xBC96 # 0 +0xA4F5 0xBC97 # 0 +0xA4F6 0xBC98 # 0 +0xA4F7 0xBC99 # 0 +0xA4F8 0xBC9A # 0 +0xA4F9 0xBC9B # 0 +0xA4FA 0xBC9C # 0 +0xA4FB 0xBC9D # 0 +0xA4FC 0xBC9E # 0 +0xA4FD 0xBC9F # 0 +0xA541 0xBCA0 # 0 +0xA542 0xBCA1 # 0 +0xA543 0xBCA2 # 0 +0xA544 0xBCA3 # 0 +0xA545 0xBCA4 # 0 +0xA546 0xBCA5 # 0 +0xA547 0xBCA6 # 0 +0xA548 0xBCA7 # 0 +0xA549 0xBCA8 # 0 +0xA54A 0xBCA9 # 0 +0xA54B 0xBCAA # 0 +0xA54C 0xBCAB # 0 +0xA54D 0xBCAC # 0 +0xA54E 0xBCAD # 0 +0xA54F 0xBCAE # 0 +0xA550 0xBCAF # 0 +0xA551 0xBCB0 # 0 +0xA553 0xBCB1 # 0 +0xA554 0xBCB2 # 0 +0xA555 0xBCB3 # 0 +0xA556 0xBCB4 # 0 +0xA557 0xBCB5 # 0 +0xA558 0xBCB6 # 0 +0xA559 0xBCB7 # 0 +0xA55A 0xBCB8 # 0 +0xA55B 0xBCB9 # 0 +0xA55C 0xBCBA # 0 +0xA55D 0xBCBB # 0 +0xA561 0xBCBC # 0 +0xA562 0xBCBD # 0 +0xA563 0xBCBE # 0 +0xA564 0xBCBF # 0 +0xA565 0xBCC0 # 0 +0xA566 0xBCC1 # 0 +0xA567 0xBCC2 # 0 +0xA568 0xBCC3 # 0 +0xA569 0xBCC4 # 0 +0xA56A 0xBCC5 # 0 +0xA56B 0xBCC6 # 0 +0xA56C 0xBCC7 # 0 +0xA56D 0xBCC8 # 0 +0xA56E 0xBCC9 # 0 +0xA56F 0xBCCA # 0 +0xA570 0xBCCB # 0 +0xA571 0xBCCC # 0 +0xA573 0xBCCD # 0 +0xA574 0xBCCE # 0 +0xA575 0xBCCF # 0 +0xA576 0xBCD0 # 0 +0xA577 0xBCD1 # 0 +0xA578 0xBCD2 # 0 +0xA579 0xBCD3 # 0 +0xA57A 0xBCD4 # 0 +0xA57B 0xBCD5 # 0 +0xA57C 0xBCD6 # 0 +0xA57D 0xBCD7 # 0 +0xA581 0xBCD8 # 0 +0xA582 0xBCD9 # 0 +0xA583 0xBCDA # 0 +0xA584 0xBCDB # 0 +0xA585 0xBCDC # 0 +0xA586 0xBCDD # 0 +0xA587 0xBCDE # 0 +0xA588 0xBCDF # 0 +0xA589 0xBCE0 # 0 +0xA58A 0xBCE1 # 0 +0xA58B 0xBCE2 # 0 +0xA58C 0xBCE3 # 0 +0xA58D 0xBCE4 # 0 +0xA58E 0xBCE5 # 0 +0xA58F 0xBCE6 # 0 +0xA590 0xBCE7 # 0 +0xA591 0xBCE8 # 0 +0xA593 0xBCE9 # 0 +0xA594 0xBCEA # 0 +0xA595 0xBCEB # 0 +0xA596 0xBCEC # 0 +0xA597 0xBCED # 0 +0xA598 0xBCEE # 0 +0xA599 0xBCEF # 0 +0xA59A 0xBCF0 # 0 +0xA59B 0xBCF1 # 0 +0xA59C 0xBCF2 # 0 +0xA59D 0xBCF3 # 0 +0xA5A1 0xBCF4 # 0 +0xA5A2 0xBCF5 # 0 +0xA5A3 0xBCF6 # 0 +0xA5A4 0xBCF7 # 0 +0xA5A5 0xBCF8 # 0 +0xA5A6 0xBCF9 # 0 +0xA5A7 0xBCFA # 0 +0xA5A8 0xBCFB # 0 +0xA5A9 0xBCFC # 0 +0xA5AA 0xBCFD # 0 +0xA5AB 0xBCFE # 0 +0xA5AC 0xBCFF # 0 +0xA5AD 0xBD00 # 0 +0xA5AE 0xBD01 # 0 +0xA5AF 0xBD02 # 0 +0xA5B0 0xBD03 # 0 +0xA5B1 0xBD04 # 0 +0xA5B3 0xBD05 # 0 +0xA5B4 0xBD06 # 0 +0xA5B5 0xBD07 # 0 +0xA5B6 0xBD08 # 0 +0xA5B7 0xBD09 # 0 +0xA5B8 0xBD0A # 0 +0xA5B9 0xBD0B # 0 +0xA5BA 0xBD0C # 0 +0xA5BB 0xBD0D # 0 +0xA5BC 0xBD0E # 0 +0xA5BD 0xBD0F # 0 +0xA5C1 0xBD10 # 0 +0xA5C2 0xBD11 # 0 +0xA5C3 0xBD12 # 0 +0xA5C4 0xBD13 # 0 +0xA5C5 0xBD14 # 0 +0xA5C6 0xBD15 # 0 +0xA5C7 0xBD16 # 0 +0xA5C8 0xBD17 # 0 +0xA5C9 0xBD18 # 0 +0xA5CA 0xBD19 # 0 +0xA5CB 0xBD1A # 0 +0xA5CC 0xBD1B # 0 +0xA5CD 0xBD1C # 0 +0xA5CE 0xBD1D # 0 +0xA5CF 0xBD1E # 0 +0xA5D0 0xBD1F # 0 +0xA5D1 0xBD20 # 0 +0xA5D3 0xBD21 # 0 +0xA5D4 0xBD22 # 0 +0xA5D5 0xBD23 # 0 +0xA5D6 0xBD24 # 0 +0xA5D7 0xBD25 # 0 +0xA5D8 0xBD26 # 0 +0xA5D9 0xBD27 # 0 +0xA5DA 0xBD28 # 0 +0xA5DB 0xBD29 # 0 +0xA5DC 0xBD2A # 0 +0xA5DD 0xBD2B # 0 +0xA5E1 0xBD2C # 0 +0xA5E2 0xBD2D # 0 +0xA5E3 0xBD2E # 0 +0xA5E4 0xBD2F # 0 +0xA5E5 0xBD30 # 0 +0xA5E6 0xBD31 # 0 +0xA5E7 0xBD32 # 0 +0xA5E8 0xBD33 # 0 +0xA5E9 0xBD34 # 0 +0xA5EA 0xBD35 # 0 +0xA5EB 0xBD36 # 0 +0xA5EC 0xBD37 # 0 +0xA5ED 0xBD38 # 0 +0xA5EE 0xBD39 # 0 +0xA5EF 0xBD3A # 0 +0xA5F0 0xBD3B # 0 +0xA5F1 0xBD3C # 0 +0xA5F3 0xBD3D # 0 +0xA5F4 0xBD3E # 0 +0xA5F5 0xBD3F # 0 +0xA5F6 0xBD40 # 0 +0xA5F7 0xBD41 # 0 +0xA5F8 0xBD42 # 0 +0xA5F9 0xBD43 # 0 +0xA5FA 0xBD44 # 0 +0xA5FB 0xBD45 # 0 +0xA5FC 0xBD46 # 0 +0xA5FD 0xBD47 # 0 +0xA641 0xBD48 # 0 +0xA642 0xBD49 # 0 +0xA643 0xBD4A # 0 +0xA644 0xBD4B # 0 +0xA645 0xBD4C # 0 +0xA646 0xBD4D # 0 +0xA647 0xBD4E # 0 +0xA648 0xBD4F # 0 +0xA649 0xBD50 # 0 +0xA64A 0xBD51 # 0 +0xA64B 0xBD52 # 0 +0xA64C 0xBD53 # 0 +0xA64D 0xBD54 # 0 +0xA64E 0xBD55 # 0 +0xA64F 0xBD56 # 0 +0xA650 0xBD57 # 0 +0xA651 0xBD58 # 0 +0xA653 0xBD59 # 0 +0xA654 0xBD5A # 0 +0xA655 0xBD5B # 0 +0xA656 0xBD5C # 0 +0xA657 0xBD5D # 0 +0xA658 0xBD5E # 0 +0xA659 0xBD5F # 0 +0xA65A 0xBD60 # 0 +0xA65B 0xBD61 # 0 +0xA65C 0xBD62 # 0 +0xA65D 0xBD63 # 0 +0xA661 0xBD64 # 0 +0xA662 0xBD65 # 0 +0xA663 0xBD66 # 0 +0xA664 0xBD67 # 0 +0xA665 0xBD68 # 0 +0xA666 0xBD69 # 0 +0xA667 0xBD6A # 0 +0xA668 0xBD6B # 0 +0xA669 0xBD6C # 0 +0xA66A 0xBD6D # 0 +0xA66B 0xBD6E # 0 +0xA66C 0xBD6F # 0 +0xA66D 0xBD70 # 0 +0xA66E 0xBD71 # 0 +0xA66F 0xBD72 # 0 +0xA670 0xBD73 # 0 +0xA671 0xBD74 # 0 +0xA673 0xBD75 # 0 +0xA674 0xBD76 # 0 +0xA675 0xBD77 # 0 +0xA676 0xBD78 # 0 +0xA677 0xBD79 # 0 +0xA678 0xBD7A # 0 +0xA679 0xBD7B # 0 +0xA67A 0xBD7C # 0 +0xA67B 0xBD7D # 0 +0xA67C 0xBD7E # 0 +0xA67D 0xBD7F # 0 +0xA681 0xBD80 # 0 +0xA682 0xBD81 # 0 +0xA683 0xBD82 # 0 +0xA684 0xBD83 # 0 +0xA685 0xBD84 # 0 +0xA686 0xBD85 # 0 +0xA687 0xBD86 # 0 +0xA688 0xBD87 # 0 +0xA689 0xBD88 # 0 +0xA68A 0xBD89 # 0 +0xA68B 0xBD8A # 0 +0xA68C 0xBD8B # 0 +0xA68D 0xBD8C # 0 +0xA68E 0xBD8D # 0 +0xA68F 0xBD8E # 0 +0xA690 0xBD8F # 0 +0xA691 0xBD90 # 0 +0xA693 0xBD91 # 0 +0xA694 0xBD92 # 0 +0xA695 0xBD93 # 0 +0xA696 0xBD94 # 0 +0xA697 0xBD95 # 0 +0xA698 0xBD96 # 0 +0xA699 0xBD97 # 0 +0xA69A 0xBD98 # 0 +0xA69B 0xBD99 # 0 +0xA69C 0xBD9A # 0 +0xA69D 0xBD9B # 0 +0xA6A1 0xBD9C # 0 +0xA6A2 0xBD9D # 0 +0xA6A3 0xBD9E # 0 +0xA6A4 0xBD9F # 0 +0xA6A5 0xBDA0 # 0 +0xA6A6 0xBDA1 # 0 +0xA6A7 0xBDA2 # 0 +0xA6A8 0xBDA3 # 0 +0xA6A9 0xBDA4 # 0 +0xA6AA 0xBDA5 # 0 +0xA6AB 0xBDA6 # 0 +0xA6AC 0xBDA7 # 0 +0xA6AD 0xBDA8 # 0 +0xA6AE 0xBDA9 # 0 +0xA6AF 0xBDAA # 0 +0xA6B0 0xBDAB # 0 +0xA6B1 0xBDAC # 0 +0xA6B3 0xBDAD # 0 +0xA6B4 0xBDAE # 0 +0xA6B5 0xBDAF # 0 +0xA6B6 0xBDB0 # 0 +0xA6B7 0xBDB1 # 0 +0xA6B8 0xBDB2 # 0 +0xA6B9 0xBDB3 # 0 +0xA6BA 0xBDB4 # 0 +0xA6BB 0xBDB5 # 0 +0xA6BC 0xBDB6 # 0 +0xA6BD 0xBDB7 # 0 +0xA6C1 0xBDB8 # 0 +0xA6C2 0xBDB9 # 0 +0xA6C3 0xBDBA # 0 +0xA6C4 0xBDBB # 0 +0xA6C5 0xBDBC # 0 +0xA6C6 0xBDBD # 0 +0xA6C7 0xBDBE # 0 +0xA6C8 0xBDBF # 0 +0xA6C9 0xBDC0 # 0 +0xA6CA 0xBDC1 # 0 +0xA6CB 0xBDC2 # 0 +0xA6CC 0xBDC3 # 0 +0xA6CD 0xBDC4 # 0 +0xA6CE 0xBDC5 # 0 +0xA6CF 0xBDC6 # 0 +0xA6D0 0xBDC7 # 0 +0xA6D1 0xBDC8 # 0 +0xA6D3 0xBDC9 # 0 +0xA6D4 0xBDCA # 0 +0xA6D5 0xBDCB # 0 +0xA6D6 0xBDCC # 0 +0xA6D7 0xBDCD # 0 +0xA6D8 0xBDCE # 0 +0xA6D9 0xBDCF # 0 +0xA6DA 0xBDD0 # 0 +0xA6DB 0xBDD1 # 0 +0xA6DC 0xBDD2 # 0 +0xA6DD 0xBDD3 # 0 +0xA6E1 0xBDD4 # 0 +0xA6E2 0xBDD5 # 0 +0xA6E3 0xBDD6 # 0 +0xA6E4 0xBDD7 # 0 +0xA6E5 0xBDD8 # 0 +0xA6E6 0xBDD9 # 0 +0xA6E7 0xBDDA # 0 +0xA6E8 0xBDDB # 0 +0xA6E9 0xBDDC # 0 +0xA6EA 0xBDDD # 0 +0xA6EB 0xBDDE # 0 +0xA6EC 0xBDDF # 0 +0xA6ED 0xBDE0 # 0 +0xA6EE 0xBDE1 # 0 +0xA6EF 0xBDE2 # 0 +0xA6F0 0xBDE3 # 0 +0xA6F1 0xBDE4 # 0 +0xA6F3 0xBDE5 # 0 +0xA6F4 0xBDE6 # 0 +0xA6F5 0xBDE7 # 0 +0xA6F6 0xBDE8 # 0 +0xA6F7 0xBDE9 # 0 +0xA6F8 0xBDEA # 0 +0xA6F9 0xBDEB # 0 +0xA6FA 0xBDEC # 0 +0xA6FB 0xBDED # 0 +0xA6FC 0xBDEE # 0 +0xA6FD 0xBDEF # 0 +0xA741 0xBDF0 # 0 +0xA742 0xBDF1 # 0 +0xA743 0xBDF2 # 0 +0xA744 0xBDF3 # 0 +0xA745 0xBDF4 # 0 +0xA746 0xBDF5 # 0 +0xA747 0xBDF6 # 0 +0xA748 0xBDF7 # 0 +0xA749 0xBDF8 # 0 +0xA74A 0xBDF9 # 0 +0xA74B 0xBDFA # 0 +0xA74C 0xBDFB # 0 +0xA74D 0xBDFC # 0 +0xA74E 0xBDFD # 0 +0xA74F 0xBDFE # 0 +0xA750 0xBDFF # 0 +0xA751 0xBE00 # 0 +0xA753 0xBE01 # 0 +0xA754 0xBE02 # 0 +0xA755 0xBE03 # 0 +0xA756 0xBE04 # 0 +0xA757 0xBE05 # 0 +0xA758 0xBE06 # 0 +0xA759 0xBE07 # 0 +0xA75A 0xBE08 # 0 +0xA75B 0xBE09 # 0 +0xA75C 0xBE0A # 0 +0xA75D 0xBE0B # 0 +0xA761 0xBE0C # 0 +0xA762 0xBE0D # 0 +0xA763 0xBE0E # 0 +0xA764 0xBE0F # 0 +0xA765 0xBE10 # 0 +0xA766 0xBE11 # 0 +0xA767 0xBE12 # 0 +0xA768 0xBE13 # 0 +0xA769 0xBE14 # 0 +0xA76A 0xBE15 # 0 +0xA76B 0xBE16 # 0 +0xA76C 0xBE17 # 0 +0xA76D 0xBE18 # 0 +0xA76E 0xBE19 # 0 +0xA76F 0xBE1A # 0 +0xA770 0xBE1B # 0 +0xA771 0xBE1C # 0 +0xA773 0xBE1D # 0 +0xA774 0xBE1E # 0 +0xA775 0xBE1F # 0 +0xA776 0xBE20 # 0 +0xA777 0xBE21 # 0 +0xA778 0xBE22 # 0 +0xA779 0xBE23 # 0 +0xA77A 0xBE24 # 0 +0xA77B 0xBE25 # 0 +0xA77C 0xBE26 # 0 +0xA77D 0xBE27 # 0 +0xA781 0xBE28 # 0 +0xA782 0xBE29 # 0 +0xA783 0xBE2A # 0 +0xA784 0xBE2B # 0 +0xA785 0xBE2C # 0 +0xA786 0xBE2D # 0 +0xA787 0xBE2E # 0 +0xA788 0xBE2F # 0 +0xA789 0xBE30 # 0 +0xA78A 0xBE31 # 0 +0xA78B 0xBE32 # 0 +0xA78C 0xBE33 # 0 +0xA78D 0xBE34 # 0 +0xA78E 0xBE35 # 0 +0xA78F 0xBE36 # 0 +0xA790 0xBE37 # 0 +0xA791 0xBE38 # 0 +0xA793 0xBE39 # 0 +0xA794 0xBE3A # 0 +0xA795 0xBE3B # 0 +0xA796 0xBE3C # 0 +0xA797 0xBE3D # 0 +0xA798 0xBE3E # 0 +0xA799 0xBE3F # 0 +0xA79A 0xBE40 # 0 +0xA79B 0xBE41 # 0 +0xA79C 0xBE42 # 0 +0xA79D 0xBE43 # 0 +0xA7A1 0xBE44 # 0 +0xA7A2 0xBE45 # 0 +0xA7A3 0xBE46 # 0 +0xA7A4 0xBE47 # 0 +0xA7A5 0xBE48 # 0 +0xA7A6 0xBE49 # 0 +0xA7A7 0xBE4A # 0 +0xA7A8 0xBE4B # 0 +0xA7A9 0xBE4C # 0 +0xA7AA 0xBE4D # 0 +0xA7AB 0xBE4E # 0 +0xA7AC 0xBE4F # 0 +0xA7AD 0xBE50 # 0 +0xA7AE 0xBE51 # 0 +0xA7AF 0xBE52 # 0 +0xA7B0 0xBE53 # 0 +0xA7B1 0xBE54 # 0 +0xA7B3 0xBE55 # 0 +0xA7B4 0xBE56 # 0 +0xA7B5 0xBE57 # 0 +0xA7B6 0xBE58 # 0 +0xA7B7 0xBE59 # 0 +0xA7B8 0xBE5A # 0 +0xA7B9 0xBE5B # 0 +0xA7BA 0xBE5C # 0 +0xA7BB 0xBE5D # 0 +0xA7BC 0xBE5E # 0 +0xA7BD 0xBE5F # 0 +0xA841 0x1108 # 0 +0xA861 0xBE60 # 0 +0xA862 0xBE61 # 0 +0xA863 0xBE62 # 0 +0xA864 0xBE63 # 0 +0xA865 0xBE64 # 0 +0xA866 0xBE65 # 0 +0xA867 0xBE66 # 0 +0xA868 0xBE67 # 0 +0xA869 0xBE68 # 0 +0xA86A 0xBE69 # 0 +0xA86B 0xBE6A # 0 +0xA86C 0xBE6B # 0 +0xA86D 0xBE6C # 0 +0xA86E 0xBE6D # 0 +0xA86F 0xBE6E # 0 +0xA870 0xBE6F # 0 +0xA871 0xBE70 # 0 +0xA873 0xBE71 # 0 +0xA874 0xBE72 # 0 +0xA875 0xBE73 # 0 +0xA876 0xBE74 # 0 +0xA877 0xBE75 # 0 +0xA878 0xBE76 # 0 +0xA879 0xBE77 # 0 +0xA87A 0xBE78 # 0 +0xA87B 0xBE79 # 0 +0xA87C 0xBE7A # 0 +0xA87D 0xBE7B # 0 +0xA881 0xBE7C # 0 +0xA882 0xBE7D # 0 +0xA883 0xBE7E # 0 +0xA884 0xBE7F # 0 +0xA885 0xBE80 # 0 +0xA886 0xBE81 # 0 +0xA887 0xBE82 # 0 +0xA888 0xBE83 # 0 +0xA889 0xBE84 # 0 +0xA88A 0xBE85 # 0 +0xA88B 0xBE86 # 0 +0xA88C 0xBE87 # 0 +0xA88D 0xBE88 # 0 +0xA88E 0xBE89 # 0 +0xA88F 0xBE8A # 0 +0xA890 0xBE8B # 0 +0xA891 0xBE8C # 0 +0xA893 0xBE8D # 0 +0xA894 0xBE8E # 0 +0xA895 0xBE8F # 0 +0xA896 0xBE90 # 0 +0xA897 0xBE91 # 0 +0xA898 0xBE92 # 0 +0xA899 0xBE93 # 0 +0xA89A 0xBE94 # 0 +0xA89B 0xBE95 # 0 +0xA89C 0xBE96 # 0 +0xA89D 0xBE97 # 0 +0xA8A1 0xBE98 # 0 +0xA8A2 0xBE99 # 0 +0xA8A3 0xBE9A # 0 +0xA8A4 0xBE9B # 0 +0xA8A5 0xBE9C # 0 +0xA8A6 0xBE9D # 0 +0xA8A7 0xBE9E # 0 +0xA8A8 0xBE9F # 0 +0xA8A9 0xBEA0 # 0 +0xA8AA 0xBEA1 # 0 +0xA8AB 0xBEA2 # 0 +0xA8AC 0xBEA3 # 0 +0xA8AD 0xBEA4 # 0 +0xA8AE 0xBEA5 # 0 +0xA8AF 0xBEA6 # 0 +0xA8B0 0xBEA7 # 0 +0xA8B1 0xBEA8 # 0 +0xA8B3 0xBEA9 # 0 +0xA8B4 0xBEAA # 0 +0xA8B5 0xBEAB # 0 +0xA8B6 0xBEAC # 0 +0xA8B7 0xBEAD # 0 +0xA8B8 0xBEAE # 0 +0xA8B9 0xBEAF # 0 +0xA8BA 0xBEB0 # 0 +0xA8BB 0xBEB1 # 0 +0xA8BC 0xBEB2 # 0 +0xA8BD 0xBEB3 # 0 +0xA8C1 0xBEB4 # 0 +0xA8C2 0xBEB5 # 0 +0xA8C3 0xBEB6 # 0 +0xA8C4 0xBEB7 # 0 +0xA8C5 0xBEB8 # 0 +0xA8C6 0xBEB9 # 0 +0xA8C7 0xBEBA # 0 +0xA8C8 0xBEBB # 0 +0xA8C9 0xBEBC # 0 +0xA8CA 0xBEBD # 0 +0xA8CB 0xBEBE # 0 +0xA8CC 0xBEBF # 0 +0xA8CD 0xBEC0 # 0 +0xA8CE 0xBEC1 # 0 +0xA8CF 0xBEC2 # 0 +0xA8D0 0xBEC3 # 0 +0xA8D1 0xBEC4 # 0 +0xA8D3 0xBEC5 # 0 +0xA8D4 0xBEC6 # 0 +0xA8D5 0xBEC7 # 0 +0xA8D6 0xBEC8 # 0 +0xA8D7 0xBEC9 # 0 +0xA8D8 0xBECA # 0 +0xA8D9 0xBECB # 0 +0xA8DA 0xBECC # 0 +0xA8DB 0xBECD # 0 +0xA8DC 0xBECE # 0 +0xA8DD 0xBECF # 0 +0xA8E1 0xBED0 # 0 +0xA8E2 0xBED1 # 0 +0xA8E3 0xBED2 # 0 +0xA8E4 0xBED3 # 0 +0xA8E5 0xBED4 # 0 +0xA8E6 0xBED5 # 0 +0xA8E7 0xBED6 # 0 +0xA8E8 0xBED7 # 0 +0xA8E9 0xBED8 # 0 +0xA8EA 0xBED9 # 0 +0xA8EB 0xBEDA # 0 +0xA8EC 0xBEDB # 0 +0xA8ED 0xBEDC # 0 +0xA8EE 0xBEDD # 0 +0xA8EF 0xBEDE # 0 +0xA8F0 0xBEDF # 0 +0xA8F1 0xBEE0 # 0 +0xA8F3 0xBEE1 # 0 +0xA8F4 0xBEE2 # 0 +0xA8F5 0xBEE3 # 0 +0xA8F6 0xBEE4 # 0 +0xA8F7 0xBEE5 # 0 +0xA8F8 0xBEE6 # 0 +0xA8F9 0xBEE7 # 0 +0xA8FA 0xBEE8 # 0 +0xA8FB 0xBEE9 # 0 +0xA8FC 0xBEEA # 0 +0xA8FD 0xBEEB # 0 +0xA941 0xBEEC # 0 +0xA942 0xBEED # 0 +0xA943 0xBEEE # 0 +0xA944 0xBEEF # 0 +0xA945 0xBEF0 # 0 +0xA946 0xBEF1 # 0 +0xA947 0xBEF2 # 0 +0xA948 0xBEF3 # 0 +0xA949 0xBEF4 # 0 +0xA94A 0xBEF5 # 0 +0xA94B 0xBEF6 # 0 +0xA94C 0xBEF7 # 0 +0xA94D 0xBEF8 # 0 +0xA94E 0xBEF9 # 0 +0xA94F 0xBEFA # 0 +0xA950 0xBEFB # 0 +0xA951 0xBEFC # 0 +0xA953 0xBEFD # 0 +0xA954 0xBEFE # 0 +0xA955 0xBEFF # 0 +0xA956 0xBF00 # 0 +0xA957 0xBF01 # 0 +0xA958 0xBF02 # 0 +0xA959 0xBF03 # 0 +0xA95A 0xBF04 # 0 +0xA95B 0xBF05 # 0 +0xA95C 0xBF06 # 0 +0xA95D 0xBF07 # 0 +0xA961 0xBF08 # 0 +0xA962 0xBF09 # 0 +0xA963 0xBF0A # 0 +0xA964 0xBF0B # 0 +0xA965 0xBF0C # 0 +0xA966 0xBF0D # 0 +0xA967 0xBF0E # 0 +0xA968 0xBF0F # 0 +0xA969 0xBF10 # 0 +0xA96A 0xBF11 # 0 +0xA96B 0xBF12 # 0 +0xA96C 0xBF13 # 0 +0xA96D 0xBF14 # 0 +0xA96E 0xBF15 # 0 +0xA96F 0xBF16 # 0 +0xA970 0xBF17 # 0 +0xA971 0xBF18 # 0 +0xA973 0xBF19 # 0 +0xA974 0xBF1A # 0 +0xA975 0xBF1B # 0 +0xA976 0xBF1C # 0 +0xA977 0xBF1D # 0 +0xA978 0xBF1E # 0 +0xA979 0xBF1F # 0 +0xA97A 0xBF20 # 0 +0xA97B 0xBF21 # 0 +0xA97C 0xBF22 # 0 +0xA97D 0xBF23 # 0 +0xA981 0xBF24 # 0 +0xA982 0xBF25 # 0 +0xA983 0xBF26 # 0 +0xA984 0xBF27 # 0 +0xA985 0xBF28 # 0 +0xA986 0xBF29 # 0 +0xA987 0xBF2A # 0 +0xA988 0xBF2B # 0 +0xA989 0xBF2C # 0 +0xA98A 0xBF2D # 0 +0xA98B 0xBF2E # 0 +0xA98C 0xBF2F # 0 +0xA98D 0xBF30 # 0 +0xA98E 0xBF31 # 0 +0xA98F 0xBF32 # 0 +0xA990 0xBF33 # 0 +0xA991 0xBF34 # 0 +0xA993 0xBF35 # 0 +0xA994 0xBF36 # 0 +0xA995 0xBF37 # 0 +0xA996 0xBF38 # 0 +0xA997 0xBF39 # 0 +0xA998 0xBF3A # 0 +0xA999 0xBF3B # 0 +0xA99A 0xBF3C # 0 +0xA99B 0xBF3D # 0 +0xA99C 0xBF3E # 0 +0xA99D 0xBF3F # 0 +0xA9A1 0xBF40 # 0 +0xA9A2 0xBF41 # 0 +0xA9A3 0xBF42 # 0 +0xA9A4 0xBF43 # 0 +0xA9A5 0xBF44 # 0 +0xA9A6 0xBF45 # 0 +0xA9A7 0xBF46 # 0 +0xA9A8 0xBF47 # 0 +0xA9A9 0xBF48 # 0 +0xA9AA 0xBF49 # 0 +0xA9AB 0xBF4A # 0 +0xA9AC 0xBF4B # 0 +0xA9AD 0xBF4C # 0 +0xA9AE 0xBF4D # 0 +0xA9AF 0xBF4E # 0 +0xA9B0 0xBF4F # 0 +0xA9B1 0xBF50 # 0 +0xA9B3 0xBF51 # 0 +0xA9B4 0xBF52 # 0 +0xA9B5 0xBF53 # 0 +0xA9B6 0xBF54 # 0 +0xA9B7 0xBF55 # 0 +0xA9B8 0xBF56 # 0 +0xA9B9 0xBF57 # 0 +0xA9BA 0xBF58 # 0 +0xA9BB 0xBF59 # 0 +0xA9BC 0xBF5A # 0 +0xA9BD 0xBF5B # 0 +0xA9C1 0xBF5C # 0 +0xA9C2 0xBF5D # 0 +0xA9C3 0xBF5E # 0 +0xA9C4 0xBF5F # 0 +0xA9C5 0xBF60 # 0 +0xA9C6 0xBF61 # 0 +0xA9C7 0xBF62 # 0 +0xA9C8 0xBF63 # 0 +0xA9C9 0xBF64 # 0 +0xA9CA 0xBF65 # 0 +0xA9CB 0xBF66 # 0 +0xA9CC 0xBF67 # 0 +0xA9CD 0xBF68 # 0 +0xA9CE 0xBF69 # 0 +0xA9CF 0xBF6A # 0 +0xA9D0 0xBF6B # 0 +0xA9D1 0xBF6C # 0 +0xA9D3 0xBF6D # 0 +0xA9D4 0xBF6E # 0 +0xA9D5 0xBF6F # 0 +0xA9D6 0xBF70 # 0 +0xA9D7 0xBF71 # 0 +0xA9D8 0xBF72 # 0 +0xA9D9 0xBF73 # 0 +0xA9DA 0xBF74 # 0 +0xA9DB 0xBF75 # 0 +0xA9DC 0xBF76 # 0 +0xA9DD 0xBF77 # 0 +0xA9E1 0xBF78 # 0 +0xA9E2 0xBF79 # 0 +0xA9E3 0xBF7A # 0 +0xA9E4 0xBF7B # 0 +0xA9E5 0xBF7C # 0 +0xA9E6 0xBF7D # 0 +0xA9E7 0xBF7E # 0 +0xA9E8 0xBF7F # 0 +0xA9E9 0xBF80 # 0 +0xA9EA 0xBF81 # 0 +0xA9EB 0xBF82 # 0 +0xA9EC 0xBF83 # 0 +0xA9ED 0xBF84 # 0 +0xA9EE 0xBF85 # 0 +0xA9EF 0xBF86 # 0 +0xA9F0 0xBF87 # 0 +0xA9F1 0xBF88 # 0 +0xA9F3 0xBF89 # 0 +0xA9F4 0xBF8A # 0 +0xA9F5 0xBF8B # 0 +0xA9F6 0xBF8C # 0 +0xA9F7 0xBF8D # 0 +0xA9F8 0xBF8E # 0 +0xA9F9 0xBF8F # 0 +0xA9FA 0xBF90 # 0 +0xA9FB 0xBF91 # 0 +0xA9FC 0xBF92 # 0 +0xA9FD 0xBF93 # 0 +0xAA41 0xBF94 # 0 +0xAA42 0xBF95 # 0 +0xAA43 0xBF96 # 0 +0xAA44 0xBF97 # 0 +0xAA45 0xBF98 # 0 +0xAA46 0xBF99 # 0 +0xAA47 0xBF9A # 0 +0xAA48 0xBF9B # 0 +0xAA49 0xBF9C # 0 +0xAA4A 0xBF9D # 0 +0xAA4B 0xBF9E # 0 +0xAA4C 0xBF9F # 0 +0xAA4D 0xBFA0 # 0 +0xAA4E 0xBFA1 # 0 +0xAA4F 0xBFA2 # 0 +0xAA50 0xBFA3 # 0 +0xAA51 0xBFA4 # 0 +0xAA53 0xBFA5 # 0 +0xAA54 0xBFA6 # 0 +0xAA55 0xBFA7 # 0 +0xAA56 0xBFA8 # 0 +0xAA57 0xBFA9 # 0 +0xAA58 0xBFAA # 0 +0xAA59 0xBFAB # 0 +0xAA5A 0xBFAC # 0 +0xAA5B 0xBFAD # 0 +0xAA5C 0xBFAE # 0 +0xAA5D 0xBFAF # 0 +0xAA61 0xBFB0 # 0 +0xAA62 0xBFB1 # 0 +0xAA63 0xBFB2 # 0 +0xAA64 0xBFB3 # 0 +0xAA65 0xBFB4 # 0 +0xAA66 0xBFB5 # 0 +0xAA67 0xBFB6 # 0 +0xAA68 0xBFB7 # 0 +0xAA69 0xBFB8 # 0 +0xAA6A 0xBFB9 # 0 +0xAA6B 0xBFBA # 0 +0xAA6C 0xBFBB # 0 +0xAA6D 0xBFBC # 0 +0xAA6E 0xBFBD # 0 +0xAA6F 0xBFBE # 0 +0xAA70 0xBFBF # 0 +0xAA71 0xBFC0 # 0 +0xAA73 0xBFC1 # 0 +0xAA74 0xBFC2 # 0 +0xAA75 0xBFC3 # 0 +0xAA76 0xBFC4 # 0 +0xAA77 0xBFC5 # 0 +0xAA78 0xBFC6 # 0 +0xAA79 0xBFC7 # 0 +0xAA7A 0xBFC8 # 0 +0xAA7B 0xBFC9 # 0 +0xAA7C 0xBFCA # 0 +0xAA7D 0xBFCB # 0 +0xAA81 0xBFCC # 0 +0xAA82 0xBFCD # 0 +0xAA83 0xBFCE # 0 +0xAA84 0xBFCF # 0 +0xAA85 0xBFD0 # 0 +0xAA86 0xBFD1 # 0 +0xAA87 0xBFD2 # 0 +0xAA88 0xBFD3 # 0 +0xAA89 0xBFD4 # 0 +0xAA8A 0xBFD5 # 0 +0xAA8B 0xBFD6 # 0 +0xAA8C 0xBFD7 # 0 +0xAA8D 0xBFD8 # 0 +0xAA8E 0xBFD9 # 0 +0xAA8F 0xBFDA # 0 +0xAA90 0xBFDB # 0 +0xAA91 0xBFDC # 0 +0xAA93 0xBFDD # 0 +0xAA94 0xBFDE # 0 +0xAA95 0xBFDF # 0 +0xAA96 0xBFE0 # 0 +0xAA97 0xBFE1 # 0 +0xAA98 0xBFE2 # 0 +0xAA99 0xBFE3 # 0 +0xAA9A 0xBFE4 # 0 +0xAA9B 0xBFE5 # 0 +0xAA9C 0xBFE6 # 0 +0xAA9D 0xBFE7 # 0 +0xAAA1 0xBFE8 # 0 +0xAAA2 0xBFE9 # 0 +0xAAA3 0xBFEA # 0 +0xAAA4 0xBFEB # 0 +0xAAA5 0xBFEC # 0 +0xAAA6 0xBFED # 0 +0xAAA7 0xBFEE # 0 +0xAAA8 0xBFEF # 0 +0xAAA9 0xBFF0 # 0 +0xAAAA 0xBFF1 # 0 +0xAAAB 0xBFF2 # 0 +0xAAAC 0xBFF3 # 0 +0xAAAD 0xBFF4 # 0 +0xAAAE 0xBFF5 # 0 +0xAAAF 0xBFF6 # 0 +0xAAB0 0xBFF7 # 0 +0xAAB1 0xBFF8 # 0 +0xAAB3 0xBFF9 # 0 +0xAAB4 0xBFFA # 0 +0xAAB5 0xBFFB # 0 +0xAAB6 0xBFFC # 0 +0xAAB7 0xBFFD # 0 +0xAAB8 0xBFFE # 0 +0xAAB9 0xBFFF # 0 +0xAABA 0xC000 # 0 +0xAABB 0xC001 # 0 +0xAABC 0xC002 # 0 +0xAABD 0xC003 # 0 +0xAAC1 0xC004 # 0 +0xAAC2 0xC005 # 0 +0xAAC3 0xC006 # 0 +0xAAC4 0xC007 # 0 +0xAAC5 0xC008 # 0 +0xAAC6 0xC009 # 0 +0xAAC7 0xC00A # 0 +0xAAC8 0xC00B # 0 +0xAAC9 0xC00C # 0 +0xAACA 0xC00D # 0 +0xAACB 0xC00E # 0 +0xAACC 0xC00F # 0 +0xAACD 0xC010 # 0 +0xAACE 0xC011 # 0 +0xAACF 0xC012 # 0 +0xAAD0 0xC013 # 0 +0xAAD1 0xC014 # 0 +0xAAD3 0xC015 # 0 +0xAAD4 0xC016 # 0 +0xAAD5 0xC017 # 0 +0xAAD6 0xC018 # 0 +0xAAD7 0xC019 # 0 +0xAAD8 0xC01A # 0 +0xAAD9 0xC01B # 0 +0xAADA 0xC01C # 0 +0xAADB 0xC01D # 0 +0xAADC 0xC01E # 0 +0xAADD 0xC01F # 0 +0xAAE1 0xC020 # 0 +0xAAE2 0xC021 # 0 +0xAAE3 0xC022 # 0 +0xAAE4 0xC023 # 0 +0xAAE5 0xC024 # 0 +0xAAE6 0xC025 # 0 +0xAAE7 0xC026 # 0 +0xAAE8 0xC027 # 0 +0xAAE9 0xC028 # 0 +0xAAEA 0xC029 # 0 +0xAAEB 0xC02A # 0 +0xAAEC 0xC02B # 0 +0xAAED 0xC02C # 0 +0xAAEE 0xC02D # 0 +0xAAEF 0xC02E # 0 +0xAAF0 0xC02F # 0 +0xAAF1 0xC030 # 0 +0xAAF3 0xC031 # 0 +0xAAF4 0xC032 # 0 +0xAAF5 0xC033 # 0 +0xAAF6 0xC034 # 0 +0xAAF7 0xC035 # 0 +0xAAF8 0xC036 # 0 +0xAAF9 0xC037 # 0 +0xAAFA 0xC038 # 0 +0xAAFB 0xC039 # 0 +0xAAFC 0xC03A # 0 +0xAAFD 0xC03B # 0 +0xAB41 0xC03C # 0 +0xAB42 0xC03D # 0 +0xAB43 0xC03E # 0 +0xAB44 0xC03F # 0 +0xAB45 0xC040 # 0 +0xAB46 0xC041 # 0 +0xAB47 0xC042 # 0 +0xAB48 0xC043 # 0 +0xAB49 0xC044 # 0 +0xAB4A 0xC045 # 0 +0xAB4B 0xC046 # 0 +0xAB4C 0xC047 # 0 +0xAB4D 0xC048 # 0 +0xAB4E 0xC049 # 0 +0xAB4F 0xC04A # 0 +0xAB50 0xC04B # 0 +0xAB51 0xC04C # 0 +0xAB53 0xC04D # 0 +0xAB54 0xC04E # 0 +0xAB55 0xC04F # 0 +0xAB56 0xC050 # 0 +0xAB57 0xC051 # 0 +0xAB58 0xC052 # 0 +0xAB59 0xC053 # 0 +0xAB5A 0xC054 # 0 +0xAB5B 0xC055 # 0 +0xAB5C 0xC056 # 0 +0xAB5D 0xC057 # 0 +0xAB61 0xC058 # 0 +0xAB62 0xC059 # 0 +0xAB63 0xC05A # 0 +0xAB64 0xC05B # 0 +0xAB65 0xC05C # 0 +0xAB66 0xC05D # 0 +0xAB67 0xC05E # 0 +0xAB68 0xC05F # 0 +0xAB69 0xC060 # 0 +0xAB6A 0xC061 # 0 +0xAB6B 0xC062 # 0 +0xAB6C 0xC063 # 0 +0xAB6D 0xC064 # 0 +0xAB6E 0xC065 # 0 +0xAB6F 0xC066 # 0 +0xAB70 0xC067 # 0 +0xAB71 0xC068 # 0 +0xAB73 0xC069 # 0 +0xAB74 0xC06A # 0 +0xAB75 0xC06B # 0 +0xAB76 0xC06C # 0 +0xAB77 0xC06D # 0 +0xAB78 0xC06E # 0 +0xAB79 0xC06F # 0 +0xAB7A 0xC070 # 0 +0xAB7B 0xC071 # 0 +0xAB7C 0xC072 # 0 +0xAB7D 0xC073 # 0 +0xAB81 0xC074 # 0 +0xAB82 0xC075 # 0 +0xAB83 0xC076 # 0 +0xAB84 0xC077 # 0 +0xAB85 0xC078 # 0 +0xAB86 0xC079 # 0 +0xAB87 0xC07A # 0 +0xAB88 0xC07B # 0 +0xAB89 0xC07C # 0 +0xAB8A 0xC07D # 0 +0xAB8B 0xC07E # 0 +0xAB8C 0xC07F # 0 +0xAB8D 0xC080 # 0 +0xAB8E 0xC081 # 0 +0xAB8F 0xC082 # 0 +0xAB90 0xC083 # 0 +0xAB91 0xC084 # 0 +0xAB93 0xC085 # 0 +0xAB94 0xC086 # 0 +0xAB95 0xC087 # 0 +0xAB96 0xC088 # 0 +0xAB97 0xC089 # 0 +0xAB98 0xC08A # 0 +0xAB99 0xC08B # 0 +0xAB9A 0xC08C # 0 +0xAB9B 0xC08D # 0 +0xAB9C 0xC08E # 0 +0xAB9D 0xC08F # 0 +0xABA1 0xC090 # 0 +0xABA2 0xC091 # 0 +0xABA3 0xC092 # 0 +0xABA4 0xC093 # 0 +0xABA5 0xC094 # 0 +0xABA6 0xC095 # 0 +0xABA7 0xC096 # 0 +0xABA8 0xC097 # 0 +0xABA9 0xC098 # 0 +0xABAA 0xC099 # 0 +0xABAB 0xC09A # 0 +0xABAC 0xC09B # 0 +0xABAD 0xC09C # 0 +0xABAE 0xC09D # 0 +0xABAF 0xC09E # 0 +0xABB0 0xC09F # 0 +0xABB1 0xC0A0 # 0 +0xABB3 0xC0A1 # 0 +0xABB4 0xC0A2 # 0 +0xABB5 0xC0A3 # 0 +0xABB6 0xC0A4 # 0 +0xABB7 0xC0A5 # 0 +0xABB8 0xC0A6 # 0 +0xABB9 0xC0A7 # 0 +0xABBA 0xC0A8 # 0 +0xABBB 0xC0A9 # 0 +0xABBC 0xC0AA # 0 +0xABBD 0xC0AB # 0 +0xAC41 0x1109 # 0 +0xAC61 0xC0AC # 0 +0xAC62 0xC0AD # 0 +0xAC63 0xC0AE # 0 +0xAC64 0xC0AF # 0 +0xAC65 0xC0B0 # 0 +0xAC66 0xC0B1 # 0 +0xAC67 0xC0B2 # 0 +0xAC68 0xC0B3 # 0 +0xAC69 0xC0B4 # 0 +0xAC6A 0xC0B5 # 0 +0xAC6B 0xC0B6 # 0 +0xAC6C 0xC0B7 # 0 +0xAC6D 0xC0B8 # 0 +0xAC6E 0xC0B9 # 0 +0xAC6F 0xC0BA # 0 +0xAC70 0xC0BB # 0 +0xAC71 0xC0BC # 0 +0xAC73 0xC0BD # 0 +0xAC74 0xC0BE # 0 +0xAC75 0xC0BF # 0 +0xAC76 0xC0C0 # 0 +0xAC77 0xC0C1 # 0 +0xAC78 0xC0C2 # 0 +0xAC79 0xC0C3 # 0 +0xAC7A 0xC0C4 # 0 +0xAC7B 0xC0C5 # 0 +0xAC7C 0xC0C6 # 0 +0xAC7D 0xC0C7 # 0 +0xAC81 0xC0C8 # 0 +0xAC82 0xC0C9 # 0 +0xAC83 0xC0CA # 0 +0xAC84 0xC0CB # 0 +0xAC85 0xC0CC # 0 +0xAC86 0xC0CD # 0 +0xAC87 0xC0CE # 0 +0xAC88 0xC0CF # 0 +0xAC89 0xC0D0 # 0 +0xAC8A 0xC0D1 # 0 +0xAC8B 0xC0D2 # 0 +0xAC8C 0xC0D3 # 0 +0xAC8D 0xC0D4 # 0 +0xAC8E 0xC0D5 # 0 +0xAC8F 0xC0D6 # 0 +0xAC90 0xC0D7 # 0 +0xAC91 0xC0D8 # 0 +0xAC93 0xC0D9 # 0 +0xAC94 0xC0DA # 0 +0xAC95 0xC0DB # 0 +0xAC96 0xC0DC # 0 +0xAC97 0xC0DD # 0 +0xAC98 0xC0DE # 0 +0xAC99 0xC0DF # 0 +0xAC9A 0xC0E0 # 0 +0xAC9B 0xC0E1 # 0 +0xAC9C 0xC0E2 # 0 +0xAC9D 0xC0E3 # 0 +0xACA1 0xC0E4 # 0 +0xACA2 0xC0E5 # 0 +0xACA3 0xC0E6 # 0 +0xACA4 0xC0E7 # 0 +0xACA5 0xC0E8 # 0 +0xACA6 0xC0E9 # 0 +0xACA7 0xC0EA # 0 +0xACA8 0xC0EB # 0 +0xACA9 0xC0EC # 0 +0xACAA 0xC0ED # 0 +0xACAB 0xC0EE # 0 +0xACAC 0xC0EF # 0 +0xACAD 0xC0F0 # 0 +0xACAE 0xC0F1 # 0 +0xACAF 0xC0F2 # 0 +0xACB0 0xC0F3 # 0 +0xACB1 0xC0F4 # 0 +0xACB3 0xC0F5 # 0 +0xACB4 0xC0F6 # 0 +0xACB5 0xC0F7 # 0 +0xACB6 0xC0F8 # 0 +0xACB7 0xC0F9 # 0 +0xACB8 0xC0FA # 0 +0xACB9 0xC0FB # 0 +0xACBA 0xC0FC # 0 +0xACBB 0xC0FD # 0 +0xACBC 0xC0FE # 0 +0xACBD 0xC0FF # 0 +0xACC1 0xC100 # 0 +0xACC2 0xC101 # 0 +0xACC3 0xC102 # 0 +0xACC4 0xC103 # 0 +0xACC5 0xC104 # 0 +0xACC6 0xC105 # 0 +0xACC7 0xC106 # 0 +0xACC8 0xC107 # 0 +0xACC9 0xC108 # 0 +0xACCA 0xC109 # 0 +0xACCB 0xC10A # 0 +0xACCC 0xC10B # 0 +0xACCD 0xC10C # 0 +0xACCE 0xC10D # 0 +0xACCF 0xC10E # 0 +0xACD0 0xC10F # 0 +0xACD1 0xC110 # 0 +0xACD3 0xC111 # 0 +0xACD4 0xC112 # 0 +0xACD5 0xC113 # 0 +0xACD6 0xC114 # 0 +0xACD7 0xC115 # 0 +0xACD8 0xC116 # 0 +0xACD9 0xC117 # 0 +0xACDA 0xC118 # 0 +0xACDB 0xC119 # 0 +0xACDC 0xC11A # 0 +0xACDD 0xC11B # 0 +0xACE1 0xC11C # 0 +0xACE2 0xC11D # 0 +0xACE3 0xC11E # 0 +0xACE4 0xC11F # 0 +0xACE5 0xC120 # 0 +0xACE6 0xC121 # 0 +0xACE7 0xC122 # 0 +0xACE8 0xC123 # 0 +0xACE9 0xC124 # 0 +0xACEA 0xC125 # 0 +0xACEB 0xC126 # 0 +0xACEC 0xC127 # 0 +0xACED 0xC128 # 0 +0xACEE 0xC129 # 0 +0xACEF 0xC12A # 0 +0xACF0 0xC12B # 0 +0xACF1 0xC12C # 0 +0xACF3 0xC12D # 0 +0xACF4 0xC12E # 0 +0xACF5 0xC12F # 0 +0xACF6 0xC130 # 0 +0xACF7 0xC131 # 0 +0xACF8 0xC132 # 0 +0xACF9 0xC133 # 0 +0xACFA 0xC134 # 0 +0xACFB 0xC135 # 0 +0xACFC 0xC136 # 0 +0xACFD 0xC137 # 0 +0xAD41 0xC138 # 0 +0xAD42 0xC139 # 0 +0xAD43 0xC13A # 0 +0xAD44 0xC13B # 0 +0xAD45 0xC13C # 0 +0xAD46 0xC13D # 0 +0xAD47 0xC13E # 0 +0xAD48 0xC13F # 0 +0xAD49 0xC140 # 0 +0xAD4A 0xC141 # 0 +0xAD4B 0xC142 # 0 +0xAD4C 0xC143 # 0 +0xAD4D 0xC144 # 0 +0xAD4E 0xC145 # 0 +0xAD4F 0xC146 # 0 +0xAD50 0xC147 # 0 +0xAD51 0xC148 # 0 +0xAD53 0xC149 # 0 +0xAD54 0xC14A # 0 +0xAD55 0xC14B # 0 +0xAD56 0xC14C # 0 +0xAD57 0xC14D # 0 +0xAD58 0xC14E # 0 +0xAD59 0xC14F # 0 +0xAD5A 0xC150 # 0 +0xAD5B 0xC151 # 0 +0xAD5C 0xC152 # 0 +0xAD5D 0xC153 # 0 +0xAD61 0xC154 # 0 +0xAD62 0xC155 # 0 +0xAD63 0xC156 # 0 +0xAD64 0xC157 # 0 +0xAD65 0xC158 # 0 +0xAD66 0xC159 # 0 +0xAD67 0xC15A # 0 +0xAD68 0xC15B # 0 +0xAD69 0xC15C # 0 +0xAD6A 0xC15D # 0 +0xAD6B 0xC15E # 0 +0xAD6C 0xC15F # 0 +0xAD6D 0xC160 # 0 +0xAD6E 0xC161 # 0 +0xAD6F 0xC162 # 0 +0xAD70 0xC163 # 0 +0xAD71 0xC164 # 0 +0xAD73 0xC165 # 0 +0xAD74 0xC166 # 0 +0xAD75 0xC167 # 0 +0xAD76 0xC168 # 0 +0xAD77 0xC169 # 0 +0xAD78 0xC16A # 0 +0xAD79 0xC16B # 0 +0xAD7A 0xC16C # 0 +0xAD7B 0xC16D # 0 +0xAD7C 0xC16E # 0 +0xAD7D 0xC16F # 0 +0xAD81 0xC170 # 0 +0xAD82 0xC171 # 0 +0xAD83 0xC172 # 0 +0xAD84 0xC173 # 0 +0xAD85 0xC174 # 0 +0xAD86 0xC175 # 0 +0xAD87 0xC176 # 0 +0xAD88 0xC177 # 0 +0xAD89 0xC178 # 0 +0xAD8A 0xC179 # 0 +0xAD8B 0xC17A # 0 +0xAD8C 0xC17B # 0 +0xAD8D 0xC17C # 0 +0xAD8E 0xC17D # 0 +0xAD8F 0xC17E # 0 +0xAD90 0xC17F # 0 +0xAD91 0xC180 # 0 +0xAD93 0xC181 # 0 +0xAD94 0xC182 # 0 +0xAD95 0xC183 # 0 +0xAD96 0xC184 # 0 +0xAD97 0xC185 # 0 +0xAD98 0xC186 # 0 +0xAD99 0xC187 # 0 +0xAD9A 0xC188 # 0 +0xAD9B 0xC189 # 0 +0xAD9C 0xC18A # 0 +0xAD9D 0xC18B # 0 +0xADA1 0xC18C # 0 +0xADA2 0xC18D # 0 +0xADA3 0xC18E # 0 +0xADA4 0xC18F # 0 +0xADA5 0xC190 # 0 +0xADA6 0xC191 # 0 +0xADA7 0xC192 # 0 +0xADA8 0xC193 # 0 +0xADA9 0xC194 # 0 +0xADAA 0xC195 # 0 +0xADAB 0xC196 # 0 +0xADAC 0xC197 # 0 +0xADAD 0xC198 # 0 +0xADAE 0xC199 # 0 +0xADAF 0xC19A # 0 +0xADB0 0xC19B # 0 +0xADB1 0xC19C # 0 +0xADB3 0xC19D # 0 +0xADB4 0xC19E # 0 +0xADB5 0xC19F # 0 +0xADB6 0xC1A0 # 0 +0xADB7 0xC1A1 # 0 +0xADB8 0xC1A2 # 0 +0xADB9 0xC1A3 # 0 +0xADBA 0xC1A4 # 0 +0xADBB 0xC1A5 # 0 +0xADBC 0xC1A6 # 0 +0xADBD 0xC1A7 # 0 +0xADC1 0xC1A8 # 0 +0xADC2 0xC1A9 # 0 +0xADC3 0xC1AA # 0 +0xADC4 0xC1AB # 0 +0xADC5 0xC1AC # 0 +0xADC6 0xC1AD # 0 +0xADC7 0xC1AE # 0 +0xADC8 0xC1AF # 0 +0xADC9 0xC1B0 # 0 +0xADCA 0xC1B1 # 0 +0xADCB 0xC1B2 # 0 +0xADCC 0xC1B3 # 0 +0xADCD 0xC1B4 # 0 +0xADCE 0xC1B5 # 0 +0xADCF 0xC1B6 # 0 +0xADD0 0xC1B7 # 0 +0xADD1 0xC1B8 # 0 +0xADD3 0xC1B9 # 0 +0xADD4 0xC1BA # 0 +0xADD5 0xC1BB # 0 +0xADD6 0xC1BC # 0 +0xADD7 0xC1BD # 0 +0xADD8 0xC1BE # 0 +0xADD9 0xC1BF # 0 +0xADDA 0xC1C0 # 0 +0xADDB 0xC1C1 # 0 +0xADDC 0xC1C2 # 0 +0xADDD 0xC1C3 # 0 +0xADE1 0xC1C4 # 0 +0xADE2 0xC1C5 # 0 +0xADE3 0xC1C6 # 0 +0xADE4 0xC1C7 # 0 +0xADE5 0xC1C8 # 0 +0xADE6 0xC1C9 # 0 +0xADE7 0xC1CA # 0 +0xADE8 0xC1CB # 0 +0xADE9 0xC1CC # 0 +0xADEA 0xC1CD # 0 +0xADEB 0xC1CE # 0 +0xADEC 0xC1CF # 0 +0xADED 0xC1D0 # 0 +0xADEE 0xC1D1 # 0 +0xADEF 0xC1D2 # 0 +0xADF0 0xC1D3 # 0 +0xADF1 0xC1D4 # 0 +0xADF3 0xC1D5 # 0 +0xADF4 0xC1D6 # 0 +0xADF5 0xC1D7 # 0 +0xADF6 0xC1D8 # 0 +0xADF7 0xC1D9 # 0 +0xADF8 0xC1DA # 0 +0xADF9 0xC1DB # 0 +0xADFA 0xC1DC # 0 +0xADFB 0xC1DD # 0 +0xADFC 0xC1DE # 0 +0xADFD 0xC1DF # 0 +0xAE41 0xC1E0 # 0 +0xAE42 0xC1E1 # 0 +0xAE43 0xC1E2 # 0 +0xAE44 0xC1E3 # 0 +0xAE45 0xC1E4 # 0 +0xAE46 0xC1E5 # 0 +0xAE47 0xC1E6 # 0 +0xAE48 0xC1E7 # 0 +0xAE49 0xC1E8 # 0 +0xAE4A 0xC1E9 # 0 +0xAE4B 0xC1EA # 0 +0xAE4C 0xC1EB # 0 +0xAE4D 0xC1EC # 0 +0xAE4E 0xC1ED # 0 +0xAE4F 0xC1EE # 0 +0xAE50 0xC1EF # 0 +0xAE51 0xC1F0 # 0 +0xAE53 0xC1F1 # 0 +0xAE54 0xC1F2 # 0 +0xAE55 0xC1F3 # 0 +0xAE56 0xC1F4 # 0 +0xAE57 0xC1F5 # 0 +0xAE58 0xC1F6 # 0 +0xAE59 0xC1F7 # 0 +0xAE5A 0xC1F8 # 0 +0xAE5B 0xC1F9 # 0 +0xAE5C 0xC1FA # 0 +0xAE5D 0xC1FB # 0 +0xAE61 0xC1FC # 0 +0xAE62 0xC1FD # 0 +0xAE63 0xC1FE # 0 +0xAE64 0xC1FF # 0 +0xAE65 0xC200 # 0 +0xAE66 0xC201 # 0 +0xAE67 0xC202 # 0 +0xAE68 0xC203 # 0 +0xAE69 0xC204 # 0 +0xAE6A 0xC205 # 0 +0xAE6B 0xC206 # 0 +0xAE6C 0xC207 # 0 +0xAE6D 0xC208 # 0 +0xAE6E 0xC209 # 0 +0xAE6F 0xC20A # 0 +0xAE70 0xC20B # 0 +0xAE71 0xC20C # 0 +0xAE73 0xC20D # 0 +0xAE74 0xC20E # 0 +0xAE75 0xC20F # 0 +0xAE76 0xC210 # 0 +0xAE77 0xC211 # 0 +0xAE78 0xC212 # 0 +0xAE79 0xC213 # 0 +0xAE7A 0xC214 # 0 +0xAE7B 0xC215 # 0 +0xAE7C 0xC216 # 0 +0xAE7D 0xC217 # 0 +0xAE81 0xC218 # 0 +0xAE82 0xC219 # 0 +0xAE83 0xC21A # 0 +0xAE84 0xC21B # 0 +0xAE85 0xC21C # 0 +0xAE86 0xC21D # 0 +0xAE87 0xC21E # 0 +0xAE88 0xC21F # 0 +0xAE89 0xC220 # 0 +0xAE8A 0xC221 # 0 +0xAE8B 0xC222 # 0 +0xAE8C 0xC223 # 0 +0xAE8D 0xC224 # 0 +0xAE8E 0xC225 # 0 +0xAE8F 0xC226 # 0 +0xAE90 0xC227 # 0 +0xAE91 0xC228 # 0 +0xAE93 0xC229 # 0 +0xAE94 0xC22A # 0 +0xAE95 0xC22B # 0 +0xAE96 0xC22C # 0 +0xAE97 0xC22D # 0 +0xAE98 0xC22E # 0 +0xAE99 0xC22F # 0 +0xAE9A 0xC230 # 0 +0xAE9B 0xC231 # 0 +0xAE9C 0xC232 # 0 +0xAE9D 0xC233 # 0 +0xAEA1 0xC234 # 0 +0xAEA2 0xC235 # 0 +0xAEA3 0xC236 # 0 +0xAEA4 0xC237 # 0 +0xAEA5 0xC238 # 0 +0xAEA6 0xC239 # 0 +0xAEA7 0xC23A # 0 +0xAEA8 0xC23B # 0 +0xAEA9 0xC23C # 0 +0xAEAA 0xC23D # 0 +0xAEAB 0xC23E # 0 +0xAEAC 0xC23F # 0 +0xAEAD 0xC240 # 0 +0xAEAE 0xC241 # 0 +0xAEAF 0xC242 # 0 +0xAEB0 0xC243 # 0 +0xAEB1 0xC244 # 0 +0xAEB3 0xC245 # 0 +0xAEB4 0xC246 # 0 +0xAEB5 0xC247 # 0 +0xAEB6 0xC248 # 0 +0xAEB7 0xC249 # 0 +0xAEB8 0xC24A # 0 +0xAEB9 0xC24B # 0 +0xAEBA 0xC24C # 0 +0xAEBB 0xC24D # 0 +0xAEBC 0xC24E # 0 +0xAEBD 0xC24F # 0 +0xAEC1 0xC250 # 0 +0xAEC2 0xC251 # 0 +0xAEC3 0xC252 # 0 +0xAEC4 0xC253 # 0 +0xAEC5 0xC254 # 0 +0xAEC6 0xC255 # 0 +0xAEC7 0xC256 # 0 +0xAEC8 0xC257 # 0 +0xAEC9 0xC258 # 0 +0xAECA 0xC259 # 0 +0xAECB 0xC25A # 0 +0xAECC 0xC25B # 0 +0xAECD 0xC25C # 0 +0xAECE 0xC25D # 0 +0xAECF 0xC25E # 0 +0xAED0 0xC25F # 0 +0xAED1 0xC260 # 0 +0xAED3 0xC261 # 0 +0xAED4 0xC262 # 0 +0xAED5 0xC263 # 0 +0xAED6 0xC264 # 0 +0xAED7 0xC265 # 0 +0xAED8 0xC266 # 0 +0xAED9 0xC267 # 0 +0xAEDA 0xC268 # 0 +0xAEDB 0xC269 # 0 +0xAEDC 0xC26A # 0 +0xAEDD 0xC26B # 0 +0xAEE1 0xC26C # 0 +0xAEE2 0xC26D # 0 +0xAEE3 0xC26E # 0 +0xAEE4 0xC26F # 0 +0xAEE5 0xC270 # 0 +0xAEE6 0xC271 # 0 +0xAEE7 0xC272 # 0 +0xAEE8 0xC273 # 0 +0xAEE9 0xC274 # 0 +0xAEEA 0xC275 # 0 +0xAEEB 0xC276 # 0 +0xAEEC 0xC277 # 0 +0xAEED 0xC278 # 0 +0xAEEE 0xC279 # 0 +0xAEEF 0xC27A # 0 +0xAEF0 0xC27B # 0 +0xAEF1 0xC27C # 0 +0xAEF3 0xC27D # 0 +0xAEF4 0xC27E # 0 +0xAEF5 0xC27F # 0 +0xAEF6 0xC280 # 0 +0xAEF7 0xC281 # 0 +0xAEF8 0xC282 # 0 +0xAEF9 0xC283 # 0 +0xAEFA 0xC284 # 0 +0xAEFB 0xC285 # 0 +0xAEFC 0xC286 # 0 +0xAEFD 0xC287 # 0 +0xAF41 0xC288 # 0 +0xAF42 0xC289 # 0 +0xAF43 0xC28A # 0 +0xAF44 0xC28B # 0 +0xAF45 0xC28C # 0 +0xAF46 0xC28D # 0 +0xAF47 0xC28E # 0 +0xAF48 0xC28F # 0 +0xAF49 0xC290 # 0 +0xAF4A 0xC291 # 0 +0xAF4B 0xC292 # 0 +0xAF4C 0xC293 # 0 +0xAF4D 0xC294 # 0 +0xAF4E 0xC295 # 0 +0xAF4F 0xC296 # 0 +0xAF50 0xC297 # 0 +0xAF51 0xC298 # 0 +0xAF53 0xC299 # 0 +0xAF54 0xC29A # 0 +0xAF55 0xC29B # 0 +0xAF56 0xC29C # 0 +0xAF57 0xC29D # 0 +0xAF58 0xC29E # 0 +0xAF59 0xC29F # 0 +0xAF5A 0xC2A0 # 0 +0xAF5B 0xC2A1 # 0 +0xAF5C 0xC2A2 # 0 +0xAF5D 0xC2A3 # 0 +0xAF61 0xC2A4 # 0 +0xAF62 0xC2A5 # 0 +0xAF63 0xC2A6 # 0 +0xAF64 0xC2A7 # 0 +0xAF65 0xC2A8 # 0 +0xAF66 0xC2A9 # 0 +0xAF67 0xC2AA # 0 +0xAF68 0xC2AB # 0 +0xAF69 0xC2AC # 0 +0xAF6A 0xC2AD # 0 +0xAF6B 0xC2AE # 0 +0xAF6C 0xC2AF # 0 +0xAF6D 0xC2B0 # 0 +0xAF6E 0xC2B1 # 0 +0xAF6F 0xC2B2 # 0 +0xAF70 0xC2B3 # 0 +0xAF71 0xC2B4 # 0 +0xAF73 0xC2B5 # 0 +0xAF74 0xC2B6 # 0 +0xAF75 0xC2B7 # 0 +0xAF76 0xC2B8 # 0 +0xAF77 0xC2B9 # 0 +0xAF78 0xC2BA # 0 +0xAF79 0xC2BB # 0 +0xAF7A 0xC2BC # 0 +0xAF7B 0xC2BD # 0 +0xAF7C 0xC2BE # 0 +0xAF7D 0xC2BF # 0 +0xAF81 0xC2C0 # 0 +0xAF82 0xC2C1 # 0 +0xAF83 0xC2C2 # 0 +0xAF84 0xC2C3 # 0 +0xAF85 0xC2C4 # 0 +0xAF86 0xC2C5 # 0 +0xAF87 0xC2C6 # 0 +0xAF88 0xC2C7 # 0 +0xAF89 0xC2C8 # 0 +0xAF8A 0xC2C9 # 0 +0xAF8B 0xC2CA # 0 +0xAF8C 0xC2CB # 0 +0xAF8D 0xC2CC # 0 +0xAF8E 0xC2CD # 0 +0xAF8F 0xC2CE # 0 +0xAF90 0xC2CF # 0 +0xAF91 0xC2D0 # 0 +0xAF93 0xC2D1 # 0 +0xAF94 0xC2D2 # 0 +0xAF95 0xC2D3 # 0 +0xAF96 0xC2D4 # 0 +0xAF97 0xC2D5 # 0 +0xAF98 0xC2D6 # 0 +0xAF99 0xC2D7 # 0 +0xAF9A 0xC2D8 # 0 +0xAF9B 0xC2D9 # 0 +0xAF9C 0xC2DA # 0 +0xAF9D 0xC2DB # 0 +0xAFA1 0xC2DC # 0 +0xAFA2 0xC2DD # 0 +0xAFA3 0xC2DE # 0 +0xAFA4 0xC2DF # 0 +0xAFA5 0xC2E0 # 0 +0xAFA6 0xC2E1 # 0 +0xAFA7 0xC2E2 # 0 +0xAFA8 0xC2E3 # 0 +0xAFA9 0xC2E4 # 0 +0xAFAA 0xC2E5 # 0 +0xAFAB 0xC2E6 # 0 +0xAFAC 0xC2E7 # 0 +0xAFAD 0xC2E8 # 0 +0xAFAE 0xC2E9 # 0 +0xAFAF 0xC2EA # 0 +0xAFB0 0xC2EB # 0 +0xAFB1 0xC2EC # 0 +0xAFB3 0xC2ED # 0 +0xAFB4 0xC2EE # 0 +0xAFB5 0xC2EF # 0 +0xAFB6 0xC2F0 # 0 +0xAFB7 0xC2F1 # 0 +0xAFB8 0xC2F2 # 0 +0xAFB9 0xC2F3 # 0 +0xAFBA 0xC2F4 # 0 +0xAFBB 0xC2F5 # 0 +0xAFBC 0xC2F6 # 0 +0xAFBD 0xC2F7 # 0 +0xB041 0x110A # 0 +0xB061 0xC2F8 # 0 +0xB062 0xC2F9 # 0 +0xB063 0xC2FA # 0 +0xB064 0xC2FB # 0 +0xB065 0xC2FC # 0 +0xB066 0xC2FD # 0 +0xB067 0xC2FE # 0 +0xB068 0xC2FF # 0 +0xB069 0xC300 # 0 +0xB06A 0xC301 # 0 +0xB06B 0xC302 # 0 +0xB06C 0xC303 # 0 +0xB06D 0xC304 # 0 +0xB06E 0xC305 # 0 +0xB06F 0xC306 # 0 +0xB070 0xC307 # 0 +0xB071 0xC308 # 0 +0xB073 0xC309 # 0 +0xB074 0xC30A # 0 +0xB075 0xC30B # 0 +0xB076 0xC30C # 0 +0xB077 0xC30D # 0 +0xB078 0xC30E # 0 +0xB079 0xC30F # 0 +0xB07A 0xC310 # 0 +0xB07B 0xC311 # 0 +0xB07C 0xC312 # 0 +0xB07D 0xC313 # 0 +0xB081 0xC314 # 0 +0xB082 0xC315 # 0 +0xB083 0xC316 # 0 +0xB084 0xC317 # 0 +0xB085 0xC318 # 0 +0xB086 0xC319 # 0 +0xB087 0xC31A # 0 +0xB088 0xC31B # 0 +0xB089 0xC31C # 0 +0xB08A 0xC31D # 0 +0xB08B 0xC31E # 0 +0xB08C 0xC31F # 0 +0xB08D 0xC320 # 0 +0xB08E 0xC321 # 0 +0xB08F 0xC322 # 0 +0xB090 0xC323 # 0 +0xB091 0xC324 # 0 +0xB093 0xC325 # 0 +0xB094 0xC326 # 0 +0xB095 0xC327 # 0 +0xB096 0xC328 # 0 +0xB097 0xC329 # 0 +0xB098 0xC32A # 0 +0xB099 0xC32B # 0 +0xB09A 0xC32C # 0 +0xB09B 0xC32D # 0 +0xB09C 0xC32E # 0 +0xB09D 0xC32F # 0 +0xB0A1 0xC330 # 0 +0xB0A2 0xC331 # 0 +0xB0A3 0xC332 # 0 +0xB0A4 0xC333 # 0 +0xB0A5 0xC334 # 0 +0xB0A6 0xC335 # 0 +0xB0A7 0xC336 # 0 +0xB0A8 0xC337 # 0 +0xB0A9 0xC338 # 0 +0xB0AA 0xC339 # 0 +0xB0AB 0xC33A # 0 +0xB0AC 0xC33B # 0 +0xB0AD 0xC33C # 0 +0xB0AE 0xC33D # 0 +0xB0AF 0xC33E # 0 +0xB0B0 0xC33F # 0 +0xB0B1 0xC340 # 0 +0xB0B3 0xC341 # 0 +0xB0B4 0xC342 # 0 +0xB0B5 0xC343 # 0 +0xB0B6 0xC344 # 0 +0xB0B7 0xC345 # 0 +0xB0B8 0xC346 # 0 +0xB0B9 0xC347 # 0 +0xB0BA 0xC348 # 0 +0xB0BB 0xC349 # 0 +0xB0BC 0xC34A # 0 +0xB0BD 0xC34B # 0 +0xB0C1 0xC34C # 0 +0xB0C2 0xC34D # 0 +0xB0C3 0xC34E # 0 +0xB0C4 0xC34F # 0 +0xB0C5 0xC350 # 0 +0xB0C6 0xC351 # 0 +0xB0C7 0xC352 # 0 +0xB0C8 0xC353 # 0 +0xB0C9 0xC354 # 0 +0xB0CA 0xC355 # 0 +0xB0CB 0xC356 # 0 +0xB0CC 0xC357 # 0 +0xB0CD 0xC358 # 0 +0xB0CE 0xC359 # 0 +0xB0CF 0xC35A # 0 +0xB0D0 0xC35B # 0 +0xB0D1 0xC35C # 0 +0xB0D3 0xC35D # 0 +0xB0D4 0xC35E # 0 +0xB0D5 0xC35F # 0 +0xB0D6 0xC360 # 0 +0xB0D7 0xC361 # 0 +0xB0D8 0xC362 # 0 +0xB0D9 0xC363 # 0 +0xB0DA 0xC364 # 0 +0xB0DB 0xC365 # 0 +0xB0DC 0xC366 # 0 +0xB0DD 0xC367 # 0 +0xB0E1 0xC368 # 0 +0xB0E2 0xC369 # 0 +0xB0E3 0xC36A # 0 +0xB0E4 0xC36B # 0 +0xB0E5 0xC36C # 0 +0xB0E6 0xC36D # 0 +0xB0E7 0xC36E # 0 +0xB0E8 0xC36F # 0 +0xB0E9 0xC370 # 0 +0xB0EA 0xC371 # 0 +0xB0EB 0xC372 # 0 +0xB0EC 0xC373 # 0 +0xB0ED 0xC374 # 0 +0xB0EE 0xC375 # 0 +0xB0EF 0xC376 # 0 +0xB0F0 0xC377 # 0 +0xB0F1 0xC378 # 0 +0xB0F3 0xC379 # 0 +0xB0F4 0xC37A # 0 +0xB0F5 0xC37B # 0 +0xB0F6 0xC37C # 0 +0xB0F7 0xC37D # 0 +0xB0F8 0xC37E # 0 +0xB0F9 0xC37F # 0 +0xB0FA 0xC380 # 0 +0xB0FB 0xC381 # 0 +0xB0FC 0xC382 # 0 +0xB0FD 0xC383 # 0 +0xB141 0xC384 # 0 +0xB142 0xC385 # 0 +0xB143 0xC386 # 0 +0xB144 0xC387 # 0 +0xB145 0xC388 # 0 +0xB146 0xC389 # 0 +0xB147 0xC38A # 0 +0xB148 0xC38B # 0 +0xB149 0xC38C # 0 +0xB14A 0xC38D # 0 +0xB14B 0xC38E # 0 +0xB14C 0xC38F # 0 +0xB14D 0xC390 # 0 +0xB14E 0xC391 # 0 +0xB14F 0xC392 # 0 +0xB150 0xC393 # 0 +0xB151 0xC394 # 0 +0xB153 0xC395 # 0 +0xB154 0xC396 # 0 +0xB155 0xC397 # 0 +0xB156 0xC398 # 0 +0xB157 0xC399 # 0 +0xB158 0xC39A # 0 +0xB159 0xC39B # 0 +0xB15A 0xC39C # 0 +0xB15B 0xC39D # 0 +0xB15C 0xC39E # 0 +0xB15D 0xC39F # 0 +0xB161 0xC3A0 # 0 +0xB162 0xC3A1 # 0 +0xB163 0xC3A2 # 0 +0xB164 0xC3A3 # 0 +0xB165 0xC3A4 # 0 +0xB166 0xC3A5 # 0 +0xB167 0xC3A6 # 0 +0xB168 0xC3A7 # 0 +0xB169 0xC3A8 # 0 +0xB16A 0xC3A9 # 0 +0xB16B 0xC3AA # 0 +0xB16C 0xC3AB # 0 +0xB16D 0xC3AC # 0 +0xB16E 0xC3AD # 0 +0xB16F 0xC3AE # 0 +0xB170 0xC3AF # 0 +0xB171 0xC3B0 # 0 +0xB173 0xC3B1 # 0 +0xB174 0xC3B2 # 0 +0xB175 0xC3B3 # 0 +0xB176 0xC3B4 # 0 +0xB177 0xC3B5 # 0 +0xB178 0xC3B6 # 0 +0xB179 0xC3B7 # 0 +0xB17A 0xC3B8 # 0 +0xB17B 0xC3B9 # 0 +0xB17C 0xC3BA # 0 +0xB17D 0xC3BB # 0 +0xB181 0xC3BC # 0 +0xB182 0xC3BD # 0 +0xB183 0xC3BE # 0 +0xB184 0xC3BF # 0 +0xB185 0xC3C0 # 0 +0xB186 0xC3C1 # 0 +0xB187 0xC3C2 # 0 +0xB188 0xC3C3 # 0 +0xB189 0xC3C4 # 0 +0xB18A 0xC3C5 # 0 +0xB18B 0xC3C6 # 0 +0xB18C 0xC3C7 # 0 +0xB18D 0xC3C8 # 0 +0xB18E 0xC3C9 # 0 +0xB18F 0xC3CA # 0 +0xB190 0xC3CB # 0 +0xB191 0xC3CC # 0 +0xB193 0xC3CD # 0 +0xB194 0xC3CE # 0 +0xB195 0xC3CF # 0 +0xB196 0xC3D0 # 0 +0xB197 0xC3D1 # 0 +0xB198 0xC3D2 # 0 +0xB199 0xC3D3 # 0 +0xB19A 0xC3D4 # 0 +0xB19B 0xC3D5 # 0 +0xB19C 0xC3D6 # 0 +0xB19D 0xC3D7 # 0 +0xB1A1 0xC3D8 # 0 +0xB1A2 0xC3D9 # 0 +0xB1A3 0xC3DA # 0 +0xB1A4 0xC3DB # 0 +0xB1A5 0xC3DC # 0 +0xB1A6 0xC3DD # 0 +0xB1A7 0xC3DE # 0 +0xB1A8 0xC3DF # 0 +0xB1A9 0xC3E0 # 0 +0xB1AA 0xC3E1 # 0 +0xB1AB 0xC3E2 # 0 +0xB1AC 0xC3E3 # 0 +0xB1AD 0xC3E4 # 0 +0xB1AE 0xC3E5 # 0 +0xB1AF 0xC3E6 # 0 +0xB1B0 0xC3E7 # 0 +0xB1B1 0xC3E8 # 0 +0xB1B3 0xC3E9 # 0 +0xB1B4 0xC3EA # 0 +0xB1B5 0xC3EB # 0 +0xB1B6 0xC3EC # 0 +0xB1B7 0xC3ED # 0 +0xB1B8 0xC3EE # 0 +0xB1B9 0xC3EF # 0 +0xB1BA 0xC3F0 # 0 +0xB1BB 0xC3F1 # 0 +0xB1BC 0xC3F2 # 0 +0xB1BD 0xC3F3 # 0 +0xB1C1 0xC3F4 # 0 +0xB1C2 0xC3F5 # 0 +0xB1C3 0xC3F6 # 0 +0xB1C4 0xC3F7 # 0 +0xB1C5 0xC3F8 # 0 +0xB1C6 0xC3F9 # 0 +0xB1C7 0xC3FA # 0 +0xB1C8 0xC3FB # 0 +0xB1C9 0xC3FC # 0 +0xB1CA 0xC3FD # 0 +0xB1CB 0xC3FE # 0 +0xB1CC 0xC3FF # 0 +0xB1CD 0xC400 # 0 +0xB1CE 0xC401 # 0 +0xB1CF 0xC402 # 0 +0xB1D0 0xC403 # 0 +0xB1D1 0xC404 # 0 +0xB1D3 0xC405 # 0 +0xB1D4 0xC406 # 0 +0xB1D5 0xC407 # 0 +0xB1D6 0xC408 # 0 +0xB1D7 0xC409 # 0 +0xB1D8 0xC40A # 0 +0xB1D9 0xC40B # 0 +0xB1DA 0xC40C # 0 +0xB1DB 0xC40D # 0 +0xB1DC 0xC40E # 0 +0xB1DD 0xC40F # 0 +0xB1E1 0xC410 # 0 +0xB1E2 0xC411 # 0 +0xB1E3 0xC412 # 0 +0xB1E4 0xC413 # 0 +0xB1E5 0xC414 # 0 +0xB1E6 0xC415 # 0 +0xB1E7 0xC416 # 0 +0xB1E8 0xC417 # 0 +0xB1E9 0xC418 # 0 +0xB1EA 0xC419 # 0 +0xB1EB 0xC41A # 0 +0xB1EC 0xC41B # 0 +0xB1ED 0xC41C # 0 +0xB1EE 0xC41D # 0 +0xB1EF 0xC41E # 0 +0xB1F0 0xC41F # 0 +0xB1F1 0xC420 # 0 +0xB1F3 0xC421 # 0 +0xB1F4 0xC422 # 0 +0xB1F5 0xC423 # 0 +0xB1F6 0xC424 # 0 +0xB1F7 0xC425 # 0 +0xB1F8 0xC426 # 0 +0xB1F9 0xC427 # 0 +0xB1FA 0xC428 # 0 +0xB1FB 0xC429 # 0 +0xB1FC 0xC42A # 0 +0xB1FD 0xC42B # 0 +0xB241 0xC42C # 0 +0xB242 0xC42D # 0 +0xB243 0xC42E # 0 +0xB244 0xC42F # 0 +0xB245 0xC430 # 0 +0xB246 0xC431 # 0 +0xB247 0xC432 # 0 +0xB248 0xC433 # 0 +0xB249 0xC434 # 0 +0xB24A 0xC435 # 0 +0xB24B 0xC436 # 0 +0xB24C 0xC437 # 0 +0xB24D 0xC438 # 0 +0xB24E 0xC439 # 0 +0xB24F 0xC43A # 0 +0xB250 0xC43B # 0 +0xB251 0xC43C # 0 +0xB253 0xC43D # 0 +0xB254 0xC43E # 0 +0xB255 0xC43F # 0 +0xB256 0xC440 # 0 +0xB257 0xC441 # 0 +0xB258 0xC442 # 0 +0xB259 0xC443 # 0 +0xB25A 0xC444 # 0 +0xB25B 0xC445 # 0 +0xB25C 0xC446 # 0 +0xB25D 0xC447 # 0 +0xB261 0xC448 # 0 +0xB262 0xC449 # 0 +0xB263 0xC44A # 0 +0xB264 0xC44B # 0 +0xB265 0xC44C # 0 +0xB266 0xC44D # 0 +0xB267 0xC44E # 0 +0xB268 0xC44F # 0 +0xB269 0xC450 # 0 +0xB26A 0xC451 # 0 +0xB26B 0xC452 # 0 +0xB26C 0xC453 # 0 +0xB26D 0xC454 # 0 +0xB26E 0xC455 # 0 +0xB26F 0xC456 # 0 +0xB270 0xC457 # 0 +0xB271 0xC458 # 0 +0xB273 0xC459 # 0 +0xB274 0xC45A # 0 +0xB275 0xC45B # 0 +0xB276 0xC45C # 0 +0xB277 0xC45D # 0 +0xB278 0xC45E # 0 +0xB279 0xC45F # 0 +0xB27A 0xC460 # 0 +0xB27B 0xC461 # 0 +0xB27C 0xC462 # 0 +0xB27D 0xC463 # 0 +0xB281 0xC464 # 0 +0xB282 0xC465 # 0 +0xB283 0xC466 # 0 +0xB284 0xC467 # 0 +0xB285 0xC468 # 0 +0xB286 0xC469 # 0 +0xB287 0xC46A # 0 +0xB288 0xC46B # 0 +0xB289 0xC46C # 0 +0xB28A 0xC46D # 0 +0xB28B 0xC46E # 0 +0xB28C 0xC46F # 0 +0xB28D 0xC470 # 0 +0xB28E 0xC471 # 0 +0xB28F 0xC472 # 0 +0xB290 0xC473 # 0 +0xB291 0xC474 # 0 +0xB293 0xC475 # 0 +0xB294 0xC476 # 0 +0xB295 0xC477 # 0 +0xB296 0xC478 # 0 +0xB297 0xC479 # 0 +0xB298 0xC47A # 0 +0xB299 0xC47B # 0 +0xB29A 0xC47C # 0 +0xB29B 0xC47D # 0 +0xB29C 0xC47E # 0 +0xB29D 0xC47F # 0 +0xB2A1 0xC480 # 0 +0xB2A2 0xC481 # 0 +0xB2A3 0xC482 # 0 +0xB2A4 0xC483 # 0 +0xB2A5 0xC484 # 0 +0xB2A6 0xC485 # 0 +0xB2A7 0xC486 # 0 +0xB2A8 0xC487 # 0 +0xB2A9 0xC488 # 0 +0xB2AA 0xC489 # 0 +0xB2AB 0xC48A # 0 +0xB2AC 0xC48B # 0 +0xB2AD 0xC48C # 0 +0xB2AE 0xC48D # 0 +0xB2AF 0xC48E # 0 +0xB2B0 0xC48F # 0 +0xB2B1 0xC490 # 0 +0xB2B3 0xC491 # 0 +0xB2B4 0xC492 # 0 +0xB2B5 0xC493 # 0 +0xB2B6 0xC494 # 0 +0xB2B7 0xC495 # 0 +0xB2B8 0xC496 # 0 +0xB2B9 0xC497 # 0 +0xB2BA 0xC498 # 0 +0xB2BB 0xC499 # 0 +0xB2BC 0xC49A # 0 +0xB2BD 0xC49B # 0 +0xB2C1 0xC49C # 0 +0xB2C2 0xC49D # 0 +0xB2C3 0xC49E # 0 +0xB2C4 0xC49F # 0 +0xB2C5 0xC4A0 # 0 +0xB2C6 0xC4A1 # 0 +0xB2C7 0xC4A2 # 0 +0xB2C8 0xC4A3 # 0 +0xB2C9 0xC4A4 # 0 +0xB2CA 0xC4A5 # 0 +0xB2CB 0xC4A6 # 0 +0xB2CC 0xC4A7 # 0 +0xB2CD 0xC4A8 # 0 +0xB2CE 0xC4A9 # 0 +0xB2CF 0xC4AA # 0 +0xB2D0 0xC4AB # 0 +0xB2D1 0xC4AC # 0 +0xB2D3 0xC4AD # 0 +0xB2D4 0xC4AE # 0 +0xB2D5 0xC4AF # 0 +0xB2D6 0xC4B0 # 0 +0xB2D7 0xC4B1 # 0 +0xB2D8 0xC4B2 # 0 +0xB2D9 0xC4B3 # 0 +0xB2DA 0xC4B4 # 0 +0xB2DB 0xC4B5 # 0 +0xB2DC 0xC4B6 # 0 +0xB2DD 0xC4B7 # 0 +0xB2E1 0xC4B8 # 0 +0xB2E2 0xC4B9 # 0 +0xB2E3 0xC4BA # 0 +0xB2E4 0xC4BB # 0 +0xB2E5 0xC4BC # 0 +0xB2E6 0xC4BD # 0 +0xB2E7 0xC4BE # 0 +0xB2E8 0xC4BF # 0 +0xB2E9 0xC4C0 # 0 +0xB2EA 0xC4C1 # 0 +0xB2EB 0xC4C2 # 0 +0xB2EC 0xC4C3 # 0 +0xB2ED 0xC4C4 # 0 +0xB2EE 0xC4C5 # 0 +0xB2EF 0xC4C6 # 0 +0xB2F0 0xC4C7 # 0 +0xB2F1 0xC4C8 # 0 +0xB2F3 0xC4C9 # 0 +0xB2F4 0xC4CA # 0 +0xB2F5 0xC4CB # 0 +0xB2F6 0xC4CC # 0 +0xB2F7 0xC4CD # 0 +0xB2F8 0xC4CE # 0 +0xB2F9 0xC4CF # 0 +0xB2FA 0xC4D0 # 0 +0xB2FB 0xC4D1 # 0 +0xB2FC 0xC4D2 # 0 +0xB2FD 0xC4D3 # 0 +0xB341 0xC4D4 # 0 +0xB342 0xC4D5 # 0 +0xB343 0xC4D6 # 0 +0xB344 0xC4D7 # 0 +0xB345 0xC4D8 # 0 +0xB346 0xC4D9 # 0 +0xB347 0xC4DA # 0 +0xB348 0xC4DB # 0 +0xB349 0xC4DC # 0 +0xB34A 0xC4DD # 0 +0xB34B 0xC4DE # 0 +0xB34C 0xC4DF # 0 +0xB34D 0xC4E0 # 0 +0xB34E 0xC4E1 # 0 +0xB34F 0xC4E2 # 0 +0xB350 0xC4E3 # 0 +0xB351 0xC4E4 # 0 +0xB353 0xC4E5 # 0 +0xB354 0xC4E6 # 0 +0xB355 0xC4E7 # 0 +0xB356 0xC4E8 # 0 +0xB357 0xC4E9 # 0 +0xB358 0xC4EA # 0 +0xB359 0xC4EB # 0 +0xB35A 0xC4EC # 0 +0xB35B 0xC4ED # 0 +0xB35C 0xC4EE # 0 +0xB35D 0xC4EF # 0 +0xB361 0xC4F0 # 0 +0xB362 0xC4F1 # 0 +0xB363 0xC4F2 # 0 +0xB364 0xC4F3 # 0 +0xB365 0xC4F4 # 0 +0xB366 0xC4F5 # 0 +0xB367 0xC4F6 # 0 +0xB368 0xC4F7 # 0 +0xB369 0xC4F8 # 0 +0xB36A 0xC4F9 # 0 +0xB36B 0xC4FA # 0 +0xB36C 0xC4FB # 0 +0xB36D 0xC4FC # 0 +0xB36E 0xC4FD # 0 +0xB36F 0xC4FE # 0 +0xB370 0xC4FF # 0 +0xB371 0xC500 # 0 +0xB373 0xC501 # 0 +0xB374 0xC502 # 0 +0xB375 0xC503 # 0 +0xB376 0xC504 # 0 +0xB377 0xC505 # 0 +0xB378 0xC506 # 0 +0xB379 0xC507 # 0 +0xB37A 0xC508 # 0 +0xB37B 0xC509 # 0 +0xB37C 0xC50A # 0 +0xB37D 0xC50B # 0 +0xB381 0xC50C # 0 +0xB382 0xC50D # 0 +0xB383 0xC50E # 0 +0xB384 0xC50F # 0 +0xB385 0xC510 # 0 +0xB386 0xC511 # 0 +0xB387 0xC512 # 0 +0xB388 0xC513 # 0 +0xB389 0xC514 # 0 +0xB38A 0xC515 # 0 +0xB38B 0xC516 # 0 +0xB38C 0xC517 # 0 +0xB38D 0xC518 # 0 +0xB38E 0xC519 # 0 +0xB38F 0xC51A # 0 +0xB390 0xC51B # 0 +0xB391 0xC51C # 0 +0xB393 0xC51D # 0 +0xB394 0xC51E # 0 +0xB395 0xC51F # 0 +0xB396 0xC520 # 0 +0xB397 0xC521 # 0 +0xB398 0xC522 # 0 +0xB399 0xC523 # 0 +0xB39A 0xC524 # 0 +0xB39B 0xC525 # 0 +0xB39C 0xC526 # 0 +0xB39D 0xC527 # 0 +0xB3A1 0xC528 # 0 +0xB3A2 0xC529 # 0 +0xB3A3 0xC52A # 0 +0xB3A4 0xC52B # 0 +0xB3A5 0xC52C # 0 +0xB3A6 0xC52D # 0 +0xB3A7 0xC52E # 0 +0xB3A8 0xC52F # 0 +0xB3A9 0xC530 # 0 +0xB3AA 0xC531 # 0 +0xB3AB 0xC532 # 0 +0xB3AC 0xC533 # 0 +0xB3AD 0xC534 # 0 +0xB3AE 0xC535 # 0 +0xB3AF 0xC536 # 0 +0xB3B0 0xC537 # 0 +0xB3B1 0xC538 # 0 +0xB3B3 0xC539 # 0 +0xB3B4 0xC53A # 0 +0xB3B5 0xC53B # 0 +0xB3B6 0xC53C # 0 +0xB3B7 0xC53D # 0 +0xB3B8 0xC53E # 0 +0xB3B9 0xC53F # 0 +0xB3BA 0xC540 # 0 +0xB3BB 0xC541 # 0 +0xB3BC 0xC542 # 0 +0xB3BD 0xC543 # 0 +0xB441 0x110B # 0 +0xB461 0xC544 # 0 +0xB462 0xC545 # 0 +0xB463 0xC546 # 0 +0xB464 0xC547 # 0 +0xB465 0xC548 # 0 +0xB466 0xC549 # 0 +0xB467 0xC54A # 0 +0xB468 0xC54B # 0 +0xB469 0xC54C # 0 +0xB46A 0xC54D # 0 +0xB46B 0xC54E # 0 +0xB46C 0xC54F # 0 +0xB46D 0xC550 # 0 +0xB46E 0xC551 # 0 +0xB46F 0xC552 # 0 +0xB470 0xC553 # 0 +0xB471 0xC554 # 0 +0xB473 0xC555 # 0 +0xB474 0xC556 # 0 +0xB475 0xC557 # 0 +0xB476 0xC558 # 0 +0xB477 0xC559 # 0 +0xB478 0xC55A # 0 +0xB479 0xC55B # 0 +0xB47A 0xC55C # 0 +0xB47B 0xC55D # 0 +0xB47C 0xC55E # 0 +0xB47D 0xC55F # 0 +0xB481 0xC560 # 0 +0xB482 0xC561 # 0 +0xB483 0xC562 # 0 +0xB484 0xC563 # 0 +0xB485 0xC564 # 0 +0xB486 0xC565 # 0 +0xB487 0xC566 # 0 +0xB488 0xC567 # 0 +0xB489 0xC568 # 0 +0xB48A 0xC569 # 0 +0xB48B 0xC56A # 0 +0xB48C 0xC56B # 0 +0xB48D 0xC56C # 0 +0xB48E 0xC56D # 0 +0xB48F 0xC56E # 0 +0xB490 0xC56F # 0 +0xB491 0xC570 # 0 +0xB493 0xC571 # 0 +0xB494 0xC572 # 0 +0xB495 0xC573 # 0 +0xB496 0xC574 # 0 +0xB497 0xC575 # 0 +0xB498 0xC576 # 0 +0xB499 0xC577 # 0 +0xB49A 0xC578 # 0 +0xB49B 0xC579 # 0 +0xB49C 0xC57A # 0 +0xB49D 0xC57B # 0 +0xB4A1 0xC57C # 0 +0xB4A2 0xC57D # 0 +0xB4A3 0xC57E # 0 +0xB4A4 0xC57F # 0 +0xB4A5 0xC580 # 0 +0xB4A6 0xC581 # 0 +0xB4A7 0xC582 # 0 +0xB4A8 0xC583 # 0 +0xB4A9 0xC584 # 0 +0xB4AA 0xC585 # 0 +0xB4AB 0xC586 # 0 +0xB4AC 0xC587 # 0 +0xB4AD 0xC588 # 0 +0xB4AE 0xC589 # 0 +0xB4AF 0xC58A # 0 +0xB4B0 0xC58B # 0 +0xB4B1 0xC58C # 0 +0xB4B3 0xC58D # 0 +0xB4B4 0xC58E # 0 +0xB4B5 0xC58F # 0 +0xB4B6 0xC590 # 0 +0xB4B7 0xC591 # 0 +0xB4B8 0xC592 # 0 +0xB4B9 0xC593 # 0 +0xB4BA 0xC594 # 0 +0xB4BB 0xC595 # 0 +0xB4BC 0xC596 # 0 +0xB4BD 0xC597 # 0 +0xB4C1 0xC598 # 0 +0xB4C2 0xC599 # 0 +0xB4C3 0xC59A # 0 +0xB4C4 0xC59B # 0 +0xB4C5 0xC59C # 0 +0xB4C6 0xC59D # 0 +0xB4C7 0xC59E # 0 +0xB4C8 0xC59F # 0 +0xB4C9 0xC5A0 # 0 +0xB4CA 0xC5A1 # 0 +0xB4CB 0xC5A2 # 0 +0xB4CC 0xC5A3 # 0 +0xB4CD 0xC5A4 # 0 +0xB4CE 0xC5A5 # 0 +0xB4CF 0xC5A6 # 0 +0xB4D0 0xC5A7 # 0 +0xB4D1 0xC5A8 # 0 +0xB4D3 0xC5A9 # 0 +0xB4D4 0xC5AA # 0 +0xB4D5 0xC5AB # 0 +0xB4D6 0xC5AC # 0 +0xB4D7 0xC5AD # 0 +0xB4D8 0xC5AE # 0 +0xB4D9 0xC5AF # 0 +0xB4DA 0xC5B0 # 0 +0xB4DB 0xC5B1 # 0 +0xB4DC 0xC5B2 # 0 +0xB4DD 0xC5B3 # 0 +0xB4E1 0xC5B4 # 0 +0xB4E2 0xC5B5 # 0 +0xB4E3 0xC5B6 # 0 +0xB4E4 0xC5B7 # 0 +0xB4E5 0xC5B8 # 0 +0xB4E6 0xC5B9 # 0 +0xB4E7 0xC5BA # 0 +0xB4E8 0xC5BB # 0 +0xB4E9 0xC5BC # 0 +0xB4EA 0xC5BD # 0 +0xB4EB 0xC5BE # 0 +0xB4EC 0xC5BF # 0 +0xB4ED 0xC5C0 # 0 +0xB4EE 0xC5C1 # 0 +0xB4EF 0xC5C2 # 0 +0xB4F0 0xC5C3 # 0 +0xB4F1 0xC5C4 # 0 +0xB4F3 0xC5C5 # 0 +0xB4F4 0xC5C6 # 0 +0xB4F5 0xC5C7 # 0 +0xB4F6 0xC5C8 # 0 +0xB4F7 0xC5C9 # 0 +0xB4F8 0xC5CA # 0 +0xB4F9 0xC5CB # 0 +0xB4FA 0xC5CC # 0 +0xB4FB 0xC5CD # 0 +0xB4FC 0xC5CE # 0 +0xB4FD 0xC5CF # 0 +0xB541 0xC5D0 # 0 +0xB542 0xC5D1 # 0 +0xB543 0xC5D2 # 0 +0xB544 0xC5D3 # 0 +0xB545 0xC5D4 # 0 +0xB546 0xC5D5 # 0 +0xB547 0xC5D6 # 0 +0xB548 0xC5D7 # 0 +0xB549 0xC5D8 # 0 +0xB54A 0xC5D9 # 0 +0xB54B 0xC5DA # 0 +0xB54C 0xC5DB # 0 +0xB54D 0xC5DC # 0 +0xB54E 0xC5DD # 0 +0xB54F 0xC5DE # 0 +0xB550 0xC5DF # 0 +0xB551 0xC5E0 # 0 +0xB553 0xC5E1 # 0 +0xB554 0xC5E2 # 0 +0xB555 0xC5E3 # 0 +0xB556 0xC5E4 # 0 +0xB557 0xC5E5 # 0 +0xB558 0xC5E6 # 0 +0xB559 0xC5E7 # 0 +0xB55A 0xC5E8 # 0 +0xB55B 0xC5E9 # 0 +0xB55C 0xC5EA # 0 +0xB55D 0xC5EB # 0 +0xB561 0xC5EC # 0 +0xB562 0xC5ED # 0 +0xB563 0xC5EE # 0 +0xB564 0xC5EF # 0 +0xB565 0xC5F0 # 0 +0xB566 0xC5F1 # 0 +0xB567 0xC5F2 # 0 +0xB568 0xC5F3 # 0 +0xB569 0xC5F4 # 0 +0xB56A 0xC5F5 # 0 +0xB56B 0xC5F6 # 0 +0xB56C 0xC5F7 # 0 +0xB56D 0xC5F8 # 0 +0xB56E 0xC5F9 # 0 +0xB56F 0xC5FA # 0 +0xB570 0xC5FB # 0 +0xB571 0xC5FC # 0 +0xB573 0xC5FD # 0 +0xB574 0xC5FE # 0 +0xB575 0xC5FF # 0 +0xB576 0xC600 # 0 +0xB577 0xC601 # 0 +0xB578 0xC602 # 0 +0xB579 0xC603 # 0 +0xB57A 0xC604 # 0 +0xB57B 0xC605 # 0 +0xB57C 0xC606 # 0 +0xB57D 0xC607 # 0 +0xB581 0xC608 # 0 +0xB582 0xC609 # 0 +0xB583 0xC60A # 0 +0xB584 0xC60B # 0 +0xB585 0xC60C # 0 +0xB586 0xC60D # 0 +0xB587 0xC60E # 0 +0xB588 0xC60F # 0 +0xB589 0xC610 # 0 +0xB58A 0xC611 # 0 +0xB58B 0xC612 # 0 +0xB58C 0xC613 # 0 +0xB58D 0xC614 # 0 +0xB58E 0xC615 # 0 +0xB58F 0xC616 # 0 +0xB590 0xC617 # 0 +0xB591 0xC618 # 0 +0xB593 0xC619 # 0 +0xB594 0xC61A # 0 +0xB595 0xC61B # 0 +0xB596 0xC61C # 0 +0xB597 0xC61D # 0 +0xB598 0xC61E # 0 +0xB599 0xC61F # 0 +0xB59A 0xC620 # 0 +0xB59B 0xC621 # 0 +0xB59C 0xC622 # 0 +0xB59D 0xC623 # 0 +0xB5A1 0xC624 # 0 +0xB5A2 0xC625 # 0 +0xB5A3 0xC626 # 0 +0xB5A4 0xC627 # 0 +0xB5A5 0xC628 # 0 +0xB5A6 0xC629 # 0 +0xB5A7 0xC62A # 0 +0xB5A8 0xC62B # 0 +0xB5A9 0xC62C # 0 +0xB5AA 0xC62D # 0 +0xB5AB 0xC62E # 0 +0xB5AC 0xC62F # 0 +0xB5AD 0xC630 # 0 +0xB5AE 0xC631 # 0 +0xB5AF 0xC632 # 0 +0xB5B0 0xC633 # 0 +0xB5B1 0xC634 # 0 +0xB5B3 0xC635 # 0 +0xB5B4 0xC636 # 0 +0xB5B5 0xC637 # 0 +0xB5B6 0xC638 # 0 +0xB5B7 0xC639 # 0 +0xB5B8 0xC63A # 0 +0xB5B9 0xC63B # 0 +0xB5BA 0xC63C # 0 +0xB5BB 0xC63D # 0 +0xB5BC 0xC63E # 0 +0xB5BD 0xC63F # 0 +0xB5C1 0xC640 # 0 +0xB5C2 0xC641 # 0 +0xB5C3 0xC642 # 0 +0xB5C4 0xC643 # 0 +0xB5C5 0xC644 # 0 +0xB5C6 0xC645 # 0 +0xB5C7 0xC646 # 0 +0xB5C8 0xC647 # 0 +0xB5C9 0xC648 # 0 +0xB5CA 0xC649 # 0 +0xB5CB 0xC64A # 0 +0xB5CC 0xC64B # 0 +0xB5CD 0xC64C # 0 +0xB5CE 0xC64D # 0 +0xB5CF 0xC64E # 0 +0xB5D0 0xC64F # 0 +0xB5D1 0xC650 # 0 +0xB5D3 0xC651 # 0 +0xB5D4 0xC652 # 0 +0xB5D5 0xC653 # 0 +0xB5D6 0xC654 # 0 +0xB5D7 0xC655 # 0 +0xB5D8 0xC656 # 0 +0xB5D9 0xC657 # 0 +0xB5DA 0xC658 # 0 +0xB5DB 0xC659 # 0 +0xB5DC 0xC65A # 0 +0xB5DD 0xC65B # 0 +0xB5E1 0xC65C # 0 +0xB5E2 0xC65D # 0 +0xB5E3 0xC65E # 0 +0xB5E4 0xC65F # 0 +0xB5E5 0xC660 # 0 +0xB5E6 0xC661 # 0 +0xB5E7 0xC662 # 0 +0xB5E8 0xC663 # 0 +0xB5E9 0xC664 # 0 +0xB5EA 0xC665 # 0 +0xB5EB 0xC666 # 0 +0xB5EC 0xC667 # 0 +0xB5ED 0xC668 # 0 +0xB5EE 0xC669 # 0 +0xB5EF 0xC66A # 0 +0xB5F0 0xC66B # 0 +0xB5F1 0xC66C # 0 +0xB5F3 0xC66D # 0 +0xB5F4 0xC66E # 0 +0xB5F5 0xC66F # 0 +0xB5F6 0xC670 # 0 +0xB5F7 0xC671 # 0 +0xB5F8 0xC672 # 0 +0xB5F9 0xC673 # 0 +0xB5FA 0xC674 # 0 +0xB5FB 0xC675 # 0 +0xB5FC 0xC676 # 0 +0xB5FD 0xC677 # 0 +0xB641 0xC678 # 0 +0xB642 0xC679 # 0 +0xB643 0xC67A # 0 +0xB644 0xC67B # 0 +0xB645 0xC67C # 0 +0xB646 0xC67D # 0 +0xB647 0xC67E # 0 +0xB648 0xC67F # 0 +0xB649 0xC680 # 0 +0xB64A 0xC681 # 0 +0xB64B 0xC682 # 0 +0xB64C 0xC683 # 0 +0xB64D 0xC684 # 0 +0xB64E 0xC685 # 0 +0xB64F 0xC686 # 0 +0xB650 0xC687 # 0 +0xB651 0xC688 # 0 +0xB653 0xC689 # 0 +0xB654 0xC68A # 0 +0xB655 0xC68B # 0 +0xB656 0xC68C # 0 +0xB657 0xC68D # 0 +0xB658 0xC68E # 0 +0xB659 0xC68F # 0 +0xB65A 0xC690 # 0 +0xB65B 0xC691 # 0 +0xB65C 0xC692 # 0 +0xB65D 0xC693 # 0 +0xB661 0xC694 # 0 +0xB662 0xC695 # 0 +0xB663 0xC696 # 0 +0xB664 0xC697 # 0 +0xB665 0xC698 # 0 +0xB666 0xC699 # 0 +0xB667 0xC69A # 0 +0xB668 0xC69B # 0 +0xB669 0xC69C # 0 +0xB66A 0xC69D # 0 +0xB66B 0xC69E # 0 +0xB66C 0xC69F # 0 +0xB66D 0xC6A0 # 0 +0xB66E 0xC6A1 # 0 +0xB66F 0xC6A2 # 0 +0xB670 0xC6A3 # 0 +0xB671 0xC6A4 # 0 +0xB673 0xC6A5 # 0 +0xB674 0xC6A6 # 0 +0xB675 0xC6A7 # 0 +0xB676 0xC6A8 # 0 +0xB677 0xC6A9 # 0 +0xB678 0xC6AA # 0 +0xB679 0xC6AB # 0 +0xB67A 0xC6AC # 0 +0xB67B 0xC6AD # 0 +0xB67C 0xC6AE # 0 +0xB67D 0xC6AF # 0 +0xB681 0xC6B0 # 0 +0xB682 0xC6B1 # 0 +0xB683 0xC6B2 # 0 +0xB684 0xC6B3 # 0 +0xB685 0xC6B4 # 0 +0xB686 0xC6B5 # 0 +0xB687 0xC6B6 # 0 +0xB688 0xC6B7 # 0 +0xB689 0xC6B8 # 0 +0xB68A 0xC6B9 # 0 +0xB68B 0xC6BA # 0 +0xB68C 0xC6BB # 0 +0xB68D 0xC6BC # 0 +0xB68E 0xC6BD # 0 +0xB68F 0xC6BE # 0 +0xB690 0xC6BF # 0 +0xB691 0xC6C0 # 0 +0xB693 0xC6C1 # 0 +0xB694 0xC6C2 # 0 +0xB695 0xC6C3 # 0 +0xB696 0xC6C4 # 0 +0xB697 0xC6C5 # 0 +0xB698 0xC6C6 # 0 +0xB699 0xC6C7 # 0 +0xB69A 0xC6C8 # 0 +0xB69B 0xC6C9 # 0 +0xB69C 0xC6CA # 0 +0xB69D 0xC6CB # 0 +0xB6A1 0xC6CC # 0 +0xB6A2 0xC6CD # 0 +0xB6A3 0xC6CE # 0 +0xB6A4 0xC6CF # 0 +0xB6A5 0xC6D0 # 0 +0xB6A6 0xC6D1 # 0 +0xB6A7 0xC6D2 # 0 +0xB6A8 0xC6D3 # 0 +0xB6A9 0xC6D4 # 0 +0xB6AA 0xC6D5 # 0 +0xB6AB 0xC6D6 # 0 +0xB6AC 0xC6D7 # 0 +0xB6AD 0xC6D8 # 0 +0xB6AE 0xC6D9 # 0 +0xB6AF 0xC6DA # 0 +0xB6B0 0xC6DB # 0 +0xB6B1 0xC6DC # 0 +0xB6B3 0xC6DD # 0 +0xB6B4 0xC6DE # 0 +0xB6B5 0xC6DF # 0 +0xB6B6 0xC6E0 # 0 +0xB6B7 0xC6E1 # 0 +0xB6B8 0xC6E2 # 0 +0xB6B9 0xC6E3 # 0 +0xB6BA 0xC6E4 # 0 +0xB6BB 0xC6E5 # 0 +0xB6BC 0xC6E6 # 0 +0xB6BD 0xC6E7 # 0 +0xB6C1 0xC6E8 # 0 +0xB6C2 0xC6E9 # 0 +0xB6C3 0xC6EA # 0 +0xB6C4 0xC6EB # 0 +0xB6C5 0xC6EC # 0 +0xB6C6 0xC6ED # 0 +0xB6C7 0xC6EE # 0 +0xB6C8 0xC6EF # 0 +0xB6C9 0xC6F0 # 0 +0xB6CA 0xC6F1 # 0 +0xB6CB 0xC6F2 # 0 +0xB6CC 0xC6F3 # 0 +0xB6CD 0xC6F4 # 0 +0xB6CE 0xC6F5 # 0 +0xB6CF 0xC6F6 # 0 +0xB6D0 0xC6F7 # 0 +0xB6D1 0xC6F8 # 0 +0xB6D3 0xC6F9 # 0 +0xB6D4 0xC6FA # 0 +0xB6D5 0xC6FB # 0 +0xB6D6 0xC6FC # 0 +0xB6D7 0xC6FD # 0 +0xB6D8 0xC6FE # 0 +0xB6D9 0xC6FF # 0 +0xB6DA 0xC700 # 0 +0xB6DB 0xC701 # 0 +0xB6DC 0xC702 # 0 +0xB6DD 0xC703 # 0 +0xB6E1 0xC704 # 0 +0xB6E2 0xC705 # 0 +0xB6E3 0xC706 # 0 +0xB6E4 0xC707 # 0 +0xB6E5 0xC708 # 0 +0xB6E6 0xC709 # 0 +0xB6E7 0xC70A # 0 +0xB6E8 0xC70B # 0 +0xB6E9 0xC70C # 0 +0xB6EA 0xC70D # 0 +0xB6EB 0xC70E # 0 +0xB6EC 0xC70F # 0 +0xB6ED 0xC710 # 0 +0xB6EE 0xC711 # 0 +0xB6EF 0xC712 # 0 +0xB6F0 0xC713 # 0 +0xB6F1 0xC714 # 0 +0xB6F3 0xC715 # 0 +0xB6F4 0xC716 # 0 +0xB6F5 0xC717 # 0 +0xB6F6 0xC718 # 0 +0xB6F7 0xC719 # 0 +0xB6F8 0xC71A # 0 +0xB6F9 0xC71B # 0 +0xB6FA 0xC71C # 0 +0xB6FB 0xC71D # 0 +0xB6FC 0xC71E # 0 +0xB6FD 0xC71F # 0 +0xB741 0xC720 # 0 +0xB742 0xC721 # 0 +0xB743 0xC722 # 0 +0xB744 0xC723 # 0 +0xB745 0xC724 # 0 +0xB746 0xC725 # 0 +0xB747 0xC726 # 0 +0xB748 0xC727 # 0 +0xB749 0xC728 # 0 +0xB74A 0xC729 # 0 +0xB74B 0xC72A # 0 +0xB74C 0xC72B # 0 +0xB74D 0xC72C # 0 +0xB74E 0xC72D # 0 +0xB74F 0xC72E # 0 +0xB750 0xC72F # 0 +0xB751 0xC730 # 0 +0xB753 0xC731 # 0 +0xB754 0xC732 # 0 +0xB755 0xC733 # 0 +0xB756 0xC734 # 0 +0xB757 0xC735 # 0 +0xB758 0xC736 # 0 +0xB759 0xC737 # 0 +0xB75A 0xC738 # 0 +0xB75B 0xC739 # 0 +0xB75C 0xC73A # 0 +0xB75D 0xC73B # 0 +0xB761 0xC73C # 0 +0xB762 0xC73D # 0 +0xB763 0xC73E # 0 +0xB764 0xC73F # 0 +0xB765 0xC740 # 0 +0xB766 0xC741 # 0 +0xB767 0xC742 # 0 +0xB768 0xC743 # 0 +0xB769 0xC744 # 0 +0xB76A 0xC745 # 0 +0xB76B 0xC746 # 0 +0xB76C 0xC747 # 0 +0xB76D 0xC748 # 0 +0xB76E 0xC749 # 0 +0xB76F 0xC74A # 0 +0xB770 0xC74B # 0 +0xB771 0xC74C # 0 +0xB773 0xC74D # 0 +0xB774 0xC74E # 0 +0xB775 0xC74F # 0 +0xB776 0xC750 # 0 +0xB777 0xC751 # 0 +0xB778 0xC752 # 0 +0xB779 0xC753 # 0 +0xB77A 0xC754 # 0 +0xB77B 0xC755 # 0 +0xB77C 0xC756 # 0 +0xB77D 0xC757 # 0 +0xB781 0xC758 # 0 +0xB782 0xC759 # 0 +0xB783 0xC75A # 0 +0xB784 0xC75B # 0 +0xB785 0xC75C # 0 +0xB786 0xC75D # 0 +0xB787 0xC75E # 0 +0xB788 0xC75F # 0 +0xB789 0xC760 # 0 +0xB78A 0xC761 # 0 +0xB78B 0xC762 # 0 +0xB78C 0xC763 # 0 +0xB78D 0xC764 # 0 +0xB78E 0xC765 # 0 +0xB78F 0xC766 # 0 +0xB790 0xC767 # 0 +0xB791 0xC768 # 0 +0xB793 0xC769 # 0 +0xB794 0xC76A # 0 +0xB795 0xC76B # 0 +0xB796 0xC76C # 0 +0xB797 0xC76D # 0 +0xB798 0xC76E # 0 +0xB799 0xC76F # 0 +0xB79A 0xC770 # 0 +0xB79B 0xC771 # 0 +0xB79C 0xC772 # 0 +0xB79D 0xC773 # 0 +0xB7A1 0xC774 # 0 +0xB7A2 0xC775 # 0 +0xB7A3 0xC776 # 0 +0xB7A4 0xC777 # 0 +0xB7A5 0xC778 # 0 +0xB7A6 0xC779 # 0 +0xB7A7 0xC77A # 0 +0xB7A8 0xC77B # 0 +0xB7A9 0xC77C # 0 +0xB7AA 0xC77D # 0 +0xB7AB 0xC77E # 0 +0xB7AC 0xC77F # 0 +0xB7AD 0xC780 # 0 +0xB7AE 0xC781 # 0 +0xB7AF 0xC782 # 0 +0xB7B0 0xC783 # 0 +0xB7B1 0xC784 # 0 +0xB7B3 0xC785 # 0 +0xB7B4 0xC786 # 0 +0xB7B5 0xC787 # 0 +0xB7B6 0xC788 # 0 +0xB7B7 0xC789 # 0 +0xB7B8 0xC78A # 0 +0xB7B9 0xC78B # 0 +0xB7BA 0xC78C # 0 +0xB7BB 0xC78D # 0 +0xB7BC 0xC78E # 0 +0xB7BD 0xC78F # 0 +0xB841 0x110C # 0 +0xB861 0xC790 # 0 +0xB862 0xC791 # 0 +0xB863 0xC792 # 0 +0xB864 0xC793 # 0 +0xB865 0xC794 # 0 +0xB866 0xC795 # 0 +0xB867 0xC796 # 0 +0xB868 0xC797 # 0 +0xB869 0xC798 # 0 +0xB86A 0xC799 # 0 +0xB86B 0xC79A # 0 +0xB86C 0xC79B # 0 +0xB86D 0xC79C # 0 +0xB86E 0xC79D # 0 +0xB86F 0xC79E # 0 +0xB870 0xC79F # 0 +0xB871 0xC7A0 # 0 +0xB873 0xC7A1 # 0 +0xB874 0xC7A2 # 0 +0xB875 0xC7A3 # 0 +0xB876 0xC7A4 # 0 +0xB877 0xC7A5 # 0 +0xB878 0xC7A6 # 0 +0xB879 0xC7A7 # 0 +0xB87A 0xC7A8 # 0 +0xB87B 0xC7A9 # 0 +0xB87C 0xC7AA # 0 +0xB87D 0xC7AB # 0 +0xB881 0xC7AC # 0 +0xB882 0xC7AD # 0 +0xB883 0xC7AE # 0 +0xB884 0xC7AF # 0 +0xB885 0xC7B0 # 0 +0xB886 0xC7B1 # 0 +0xB887 0xC7B2 # 0 +0xB888 0xC7B3 # 0 +0xB889 0xC7B4 # 0 +0xB88A 0xC7B5 # 0 +0xB88B 0xC7B6 # 0 +0xB88C 0xC7B7 # 0 +0xB88D 0xC7B8 # 0 +0xB88E 0xC7B9 # 0 +0xB88F 0xC7BA # 0 +0xB890 0xC7BB # 0 +0xB891 0xC7BC # 0 +0xB893 0xC7BD # 0 +0xB894 0xC7BE # 0 +0xB895 0xC7BF # 0 +0xB896 0xC7C0 # 0 +0xB897 0xC7C1 # 0 +0xB898 0xC7C2 # 0 +0xB899 0xC7C3 # 0 +0xB89A 0xC7C4 # 0 +0xB89B 0xC7C5 # 0 +0xB89C 0xC7C6 # 0 +0xB89D 0xC7C7 # 0 +0xB8A1 0xC7C8 # 0 +0xB8A2 0xC7C9 # 0 +0xB8A3 0xC7CA # 0 +0xB8A4 0xC7CB # 0 +0xB8A5 0xC7CC # 0 +0xB8A6 0xC7CD # 0 +0xB8A7 0xC7CE # 0 +0xB8A8 0xC7CF # 0 +0xB8A9 0xC7D0 # 0 +0xB8AA 0xC7D1 # 0 +0xB8AB 0xC7D2 # 0 +0xB8AC 0xC7D3 # 0 +0xB8AD 0xC7D4 # 0 +0xB8AE 0xC7D5 # 0 +0xB8AF 0xC7D6 # 0 +0xB8B0 0xC7D7 # 0 +0xB8B1 0xC7D8 # 0 +0xB8B3 0xC7D9 # 0 +0xB8B4 0xC7DA # 0 +0xB8B5 0xC7DB # 0 +0xB8B6 0xC7DC # 0 +0xB8B7 0xC7DD # 0 +0xB8B8 0xC7DE # 0 +0xB8B9 0xC7DF # 0 +0xB8BA 0xC7E0 # 0 +0xB8BB 0xC7E1 # 0 +0xB8BC 0xC7E2 # 0 +0xB8BD 0xC7E3 # 0 +0xB8C1 0xC7E4 # 0 +0xB8C2 0xC7E5 # 0 +0xB8C3 0xC7E6 # 0 +0xB8C4 0xC7E7 # 0 +0xB8C5 0xC7E8 # 0 +0xB8C6 0xC7E9 # 0 +0xB8C7 0xC7EA # 0 +0xB8C8 0xC7EB # 0 +0xB8C9 0xC7EC # 0 +0xB8CA 0xC7ED # 0 +0xB8CB 0xC7EE # 0 +0xB8CC 0xC7EF # 0 +0xB8CD 0xC7F0 # 0 +0xB8CE 0xC7F1 # 0 +0xB8CF 0xC7F2 # 0 +0xB8D0 0xC7F3 # 0 +0xB8D1 0xC7F4 # 0 +0xB8D3 0xC7F5 # 0 +0xB8D4 0xC7F6 # 0 +0xB8D5 0xC7F7 # 0 +0xB8D6 0xC7F8 # 0 +0xB8D7 0xC7F9 # 0 +0xB8D8 0xC7FA # 0 +0xB8D9 0xC7FB # 0 +0xB8DA 0xC7FC # 0 +0xB8DB 0xC7FD # 0 +0xB8DC 0xC7FE # 0 +0xB8DD 0xC7FF # 0 +0xB8E1 0xC800 # 0 +0xB8E2 0xC801 # 0 +0xB8E3 0xC802 # 0 +0xB8E4 0xC803 # 0 +0xB8E5 0xC804 # 0 +0xB8E6 0xC805 # 0 +0xB8E7 0xC806 # 0 +0xB8E8 0xC807 # 0 +0xB8E9 0xC808 # 0 +0xB8EA 0xC809 # 0 +0xB8EB 0xC80A # 0 +0xB8EC 0xC80B # 0 +0xB8ED 0xC80C # 0 +0xB8EE 0xC80D # 0 +0xB8EF 0xC80E # 0 +0xB8F0 0xC80F # 0 +0xB8F1 0xC810 # 0 +0xB8F3 0xC811 # 0 +0xB8F4 0xC812 # 0 +0xB8F5 0xC813 # 0 +0xB8F6 0xC814 # 0 +0xB8F7 0xC815 # 0 +0xB8F8 0xC816 # 0 +0xB8F9 0xC817 # 0 +0xB8FA 0xC818 # 0 +0xB8FB 0xC819 # 0 +0xB8FC 0xC81A # 0 +0xB8FD 0xC81B # 0 +0xB941 0xC81C # 0 +0xB942 0xC81D # 0 +0xB943 0xC81E # 0 +0xB944 0xC81F # 0 +0xB945 0xC820 # 0 +0xB946 0xC821 # 0 +0xB947 0xC822 # 0 +0xB948 0xC823 # 0 +0xB949 0xC824 # 0 +0xB94A 0xC825 # 0 +0xB94B 0xC826 # 0 +0xB94C 0xC827 # 0 +0xB94D 0xC828 # 0 +0xB94E 0xC829 # 0 +0xB94F 0xC82A # 0 +0xB950 0xC82B # 0 +0xB951 0xC82C # 0 +0xB953 0xC82D # 0 +0xB954 0xC82E # 0 +0xB955 0xC82F # 0 +0xB956 0xC830 # 0 +0xB957 0xC831 # 0 +0xB958 0xC832 # 0 +0xB959 0xC833 # 0 +0xB95A 0xC834 # 0 +0xB95B 0xC835 # 0 +0xB95C 0xC836 # 0 +0xB95D 0xC837 # 0 +0xB961 0xC838 # 0 +0xB962 0xC839 # 0 +0xB963 0xC83A # 0 +0xB964 0xC83B # 0 +0xB965 0xC83C # 0 +0xB966 0xC83D # 0 +0xB967 0xC83E # 0 +0xB968 0xC83F # 0 +0xB969 0xC840 # 0 +0xB96A 0xC841 # 0 +0xB96B 0xC842 # 0 +0xB96C 0xC843 # 0 +0xB96D 0xC844 # 0 +0xB96E 0xC845 # 0 +0xB96F 0xC846 # 0 +0xB970 0xC847 # 0 +0xB971 0xC848 # 0 +0xB973 0xC849 # 0 +0xB974 0xC84A # 0 +0xB975 0xC84B # 0 +0xB976 0xC84C # 0 +0xB977 0xC84D # 0 +0xB978 0xC84E # 0 +0xB979 0xC84F # 0 +0xB97A 0xC850 # 0 +0xB97B 0xC851 # 0 +0xB97C 0xC852 # 0 +0xB97D 0xC853 # 0 +0xB981 0xC854 # 0 +0xB982 0xC855 # 0 +0xB983 0xC856 # 0 +0xB984 0xC857 # 0 +0xB985 0xC858 # 0 +0xB986 0xC859 # 0 +0xB987 0xC85A # 0 +0xB988 0xC85B # 0 +0xB989 0xC85C # 0 +0xB98A 0xC85D # 0 +0xB98B 0xC85E # 0 +0xB98C 0xC85F # 0 +0xB98D 0xC860 # 0 +0xB98E 0xC861 # 0 +0xB98F 0xC862 # 0 +0xB990 0xC863 # 0 +0xB991 0xC864 # 0 +0xB993 0xC865 # 0 +0xB994 0xC866 # 0 +0xB995 0xC867 # 0 +0xB996 0xC868 # 0 +0xB997 0xC869 # 0 +0xB998 0xC86A # 0 +0xB999 0xC86B # 0 +0xB99A 0xC86C # 0 +0xB99B 0xC86D # 0 +0xB99C 0xC86E # 0 +0xB99D 0xC86F # 0 +0xB9A1 0xC870 # 0 +0xB9A2 0xC871 # 0 +0xB9A3 0xC872 # 0 +0xB9A4 0xC873 # 0 +0xB9A5 0xC874 # 0 +0xB9A6 0xC875 # 0 +0xB9A7 0xC876 # 0 +0xB9A8 0xC877 # 0 +0xB9A9 0xC878 # 0 +0xB9AA 0xC879 # 0 +0xB9AB 0xC87A # 0 +0xB9AC 0xC87B # 0 +0xB9AD 0xC87C # 0 +0xB9AE 0xC87D # 0 +0xB9AF 0xC87E # 0 +0xB9B0 0xC87F # 0 +0xB9B1 0xC880 # 0 +0xB9B3 0xC881 # 0 +0xB9B4 0xC882 # 0 +0xB9B5 0xC883 # 0 +0xB9B6 0xC884 # 0 +0xB9B7 0xC885 # 0 +0xB9B8 0xC886 # 0 +0xB9B9 0xC887 # 0 +0xB9BA 0xC888 # 0 +0xB9BB 0xC889 # 0 +0xB9BC 0xC88A # 0 +0xB9BD 0xC88B # 0 +0xB9C1 0xC88C # 0 +0xB9C2 0xC88D # 0 +0xB9C3 0xC88E # 0 +0xB9C4 0xC88F # 0 +0xB9C5 0xC890 # 0 +0xB9C6 0xC891 # 0 +0xB9C7 0xC892 # 0 +0xB9C8 0xC893 # 0 +0xB9C9 0xC894 # 0 +0xB9CA 0xC895 # 0 +0xB9CB 0xC896 # 0 +0xB9CC 0xC897 # 0 +0xB9CD 0xC898 # 0 +0xB9CE 0xC899 # 0 +0xB9CF 0xC89A # 0 +0xB9D0 0xC89B # 0 +0xB9D1 0xC89C # 0 +0xB9D3 0xC89D # 0 +0xB9D4 0xC89E # 0 +0xB9D5 0xC89F # 0 +0xB9D6 0xC8A0 # 0 +0xB9D7 0xC8A1 # 0 +0xB9D8 0xC8A2 # 0 +0xB9D9 0xC8A3 # 0 +0xB9DA 0xC8A4 # 0 +0xB9DB 0xC8A5 # 0 +0xB9DC 0xC8A6 # 0 +0xB9DD 0xC8A7 # 0 +0xB9E1 0xC8A8 # 0 +0xB9E2 0xC8A9 # 0 +0xB9E3 0xC8AA # 0 +0xB9E4 0xC8AB # 0 +0xB9E5 0xC8AC # 0 +0xB9E6 0xC8AD # 0 +0xB9E7 0xC8AE # 0 +0xB9E8 0xC8AF # 0 +0xB9E9 0xC8B0 # 0 +0xB9EA 0xC8B1 # 0 +0xB9EB 0xC8B2 # 0 +0xB9EC 0xC8B3 # 0 +0xB9ED 0xC8B4 # 0 +0xB9EE 0xC8B5 # 0 +0xB9EF 0xC8B6 # 0 +0xB9F0 0xC8B7 # 0 +0xB9F1 0xC8B8 # 0 +0xB9F3 0xC8B9 # 0 +0xB9F4 0xC8BA # 0 +0xB9F5 0xC8BB # 0 +0xB9F6 0xC8BC # 0 +0xB9F7 0xC8BD # 0 +0xB9F8 0xC8BE # 0 +0xB9F9 0xC8BF # 0 +0xB9FA 0xC8C0 # 0 +0xB9FB 0xC8C1 # 0 +0xB9FC 0xC8C2 # 0 +0xB9FD 0xC8C3 # 0 +0xBA41 0xC8C4 # 0 +0xBA42 0xC8C5 # 0 +0xBA43 0xC8C6 # 0 +0xBA44 0xC8C7 # 0 +0xBA45 0xC8C8 # 0 +0xBA46 0xC8C9 # 0 +0xBA47 0xC8CA # 0 +0xBA48 0xC8CB # 0 +0xBA49 0xC8CC # 0 +0xBA4A 0xC8CD # 0 +0xBA4B 0xC8CE # 0 +0xBA4C 0xC8CF # 0 +0xBA4D 0xC8D0 # 0 +0xBA4E 0xC8D1 # 0 +0xBA4F 0xC8D2 # 0 +0xBA50 0xC8D3 # 0 +0xBA51 0xC8D4 # 0 +0xBA53 0xC8D5 # 0 +0xBA54 0xC8D6 # 0 +0xBA55 0xC8D7 # 0 +0xBA56 0xC8D8 # 0 +0xBA57 0xC8D9 # 0 +0xBA58 0xC8DA # 0 +0xBA59 0xC8DB # 0 +0xBA5A 0xC8DC # 0 +0xBA5B 0xC8DD # 0 +0xBA5C 0xC8DE # 0 +0xBA5D 0xC8DF # 0 +0xBA61 0xC8E0 # 0 +0xBA62 0xC8E1 # 0 +0xBA63 0xC8E2 # 0 +0xBA64 0xC8E3 # 0 +0xBA65 0xC8E4 # 0 +0xBA66 0xC8E5 # 0 +0xBA67 0xC8E6 # 0 +0xBA68 0xC8E7 # 0 +0xBA69 0xC8E8 # 0 +0xBA6A 0xC8E9 # 0 +0xBA6B 0xC8EA # 0 +0xBA6C 0xC8EB # 0 +0xBA6D 0xC8EC # 0 +0xBA6E 0xC8ED # 0 +0xBA6F 0xC8EE # 0 +0xBA70 0xC8EF # 0 +0xBA71 0xC8F0 # 0 +0xBA73 0xC8F1 # 0 +0xBA74 0xC8F2 # 0 +0xBA75 0xC8F3 # 0 +0xBA76 0xC8F4 # 0 +0xBA77 0xC8F5 # 0 +0xBA78 0xC8F6 # 0 +0xBA79 0xC8F7 # 0 +0xBA7A 0xC8F8 # 0 +0xBA7B 0xC8F9 # 0 +0xBA7C 0xC8FA # 0 +0xBA7D 0xC8FB # 0 +0xBA81 0xC8FC # 0 +0xBA82 0xC8FD # 0 +0xBA83 0xC8FE # 0 +0xBA84 0xC8FF # 0 +0xBA85 0xC900 # 0 +0xBA86 0xC901 # 0 +0xBA87 0xC902 # 0 +0xBA88 0xC903 # 0 +0xBA89 0xC904 # 0 +0xBA8A 0xC905 # 0 +0xBA8B 0xC906 # 0 +0xBA8C 0xC907 # 0 +0xBA8D 0xC908 # 0 +0xBA8E 0xC909 # 0 +0xBA8F 0xC90A # 0 +0xBA90 0xC90B # 0 +0xBA91 0xC90C # 0 +0xBA93 0xC90D # 0 +0xBA94 0xC90E # 0 +0xBA95 0xC90F # 0 +0xBA96 0xC910 # 0 +0xBA97 0xC911 # 0 +0xBA98 0xC912 # 0 +0xBA99 0xC913 # 0 +0xBA9A 0xC914 # 0 +0xBA9B 0xC915 # 0 +0xBA9C 0xC916 # 0 +0xBA9D 0xC917 # 0 +0xBAA1 0xC918 # 0 +0xBAA2 0xC919 # 0 +0xBAA3 0xC91A # 0 +0xBAA4 0xC91B # 0 +0xBAA5 0xC91C # 0 +0xBAA6 0xC91D # 0 +0xBAA7 0xC91E # 0 +0xBAA8 0xC91F # 0 +0xBAA9 0xC920 # 0 +0xBAAA 0xC921 # 0 +0xBAAB 0xC922 # 0 +0xBAAC 0xC923 # 0 +0xBAAD 0xC924 # 0 +0xBAAE 0xC925 # 0 +0xBAAF 0xC926 # 0 +0xBAB0 0xC927 # 0 +0xBAB1 0xC928 # 0 +0xBAB3 0xC929 # 0 +0xBAB4 0xC92A # 0 +0xBAB5 0xC92B # 0 +0xBAB6 0xC92C # 0 +0xBAB7 0xC92D # 0 +0xBAB8 0xC92E # 0 +0xBAB9 0xC92F # 0 +0xBABA 0xC930 # 0 +0xBABB 0xC931 # 0 +0xBABC 0xC932 # 0 +0xBABD 0xC933 # 0 +0xBAC1 0xC934 # 0 +0xBAC2 0xC935 # 0 +0xBAC3 0xC936 # 0 +0xBAC4 0xC937 # 0 +0xBAC5 0xC938 # 0 +0xBAC6 0xC939 # 0 +0xBAC7 0xC93A # 0 +0xBAC8 0xC93B # 0 +0xBAC9 0xC93C # 0 +0xBACA 0xC93D # 0 +0xBACB 0xC93E # 0 +0xBACC 0xC93F # 0 +0xBACD 0xC940 # 0 +0xBACE 0xC941 # 0 +0xBACF 0xC942 # 0 +0xBAD0 0xC943 # 0 +0xBAD1 0xC944 # 0 +0xBAD3 0xC945 # 0 +0xBAD4 0xC946 # 0 +0xBAD5 0xC947 # 0 +0xBAD6 0xC948 # 0 +0xBAD7 0xC949 # 0 +0xBAD8 0xC94A # 0 +0xBAD9 0xC94B # 0 +0xBADA 0xC94C # 0 +0xBADB 0xC94D # 0 +0xBADC 0xC94E # 0 +0xBADD 0xC94F # 0 +0xBAE1 0xC950 # 0 +0xBAE2 0xC951 # 0 +0xBAE3 0xC952 # 0 +0xBAE4 0xC953 # 0 +0xBAE5 0xC954 # 0 +0xBAE6 0xC955 # 0 +0xBAE7 0xC956 # 0 +0xBAE8 0xC957 # 0 +0xBAE9 0xC958 # 0 +0xBAEA 0xC959 # 0 +0xBAEB 0xC95A # 0 +0xBAEC 0xC95B # 0 +0xBAED 0xC95C # 0 +0xBAEE 0xC95D # 0 +0xBAEF 0xC95E # 0 +0xBAF0 0xC95F # 0 +0xBAF1 0xC960 # 0 +0xBAF3 0xC961 # 0 +0xBAF4 0xC962 # 0 +0xBAF5 0xC963 # 0 +0xBAF6 0xC964 # 0 +0xBAF7 0xC965 # 0 +0xBAF8 0xC966 # 0 +0xBAF9 0xC967 # 0 +0xBAFA 0xC968 # 0 +0xBAFB 0xC969 # 0 +0xBAFC 0xC96A # 0 +0xBAFD 0xC96B # 0 +0xBB41 0xC96C # 0 +0xBB42 0xC96D # 0 +0xBB43 0xC96E # 0 +0xBB44 0xC96F # 0 +0xBB45 0xC970 # 0 +0xBB46 0xC971 # 0 +0xBB47 0xC972 # 0 +0xBB48 0xC973 # 0 +0xBB49 0xC974 # 0 +0xBB4A 0xC975 # 0 +0xBB4B 0xC976 # 0 +0xBB4C 0xC977 # 0 +0xBB4D 0xC978 # 0 +0xBB4E 0xC979 # 0 +0xBB4F 0xC97A # 0 +0xBB50 0xC97B # 0 +0xBB51 0xC97C # 0 +0xBB53 0xC97D # 0 +0xBB54 0xC97E # 0 +0xBB55 0xC97F # 0 +0xBB56 0xC980 # 0 +0xBB57 0xC981 # 0 +0xBB58 0xC982 # 0 +0xBB59 0xC983 # 0 +0xBB5A 0xC984 # 0 +0xBB5B 0xC985 # 0 +0xBB5C 0xC986 # 0 +0xBB5D 0xC987 # 0 +0xBB61 0xC988 # 0 +0xBB62 0xC989 # 0 +0xBB63 0xC98A # 0 +0xBB64 0xC98B # 0 +0xBB65 0xC98C # 0 +0xBB66 0xC98D # 0 +0xBB67 0xC98E # 0 +0xBB68 0xC98F # 0 +0xBB69 0xC990 # 0 +0xBB6A 0xC991 # 0 +0xBB6B 0xC992 # 0 +0xBB6C 0xC993 # 0 +0xBB6D 0xC994 # 0 +0xBB6E 0xC995 # 0 +0xBB6F 0xC996 # 0 +0xBB70 0xC997 # 0 +0xBB71 0xC998 # 0 +0xBB73 0xC999 # 0 +0xBB74 0xC99A # 0 +0xBB75 0xC99B # 0 +0xBB76 0xC99C # 0 +0xBB77 0xC99D # 0 +0xBB78 0xC99E # 0 +0xBB79 0xC99F # 0 +0xBB7A 0xC9A0 # 0 +0xBB7B 0xC9A1 # 0 +0xBB7C 0xC9A2 # 0 +0xBB7D 0xC9A3 # 0 +0xBB81 0xC9A4 # 0 +0xBB82 0xC9A5 # 0 +0xBB83 0xC9A6 # 0 +0xBB84 0xC9A7 # 0 +0xBB85 0xC9A8 # 0 +0xBB86 0xC9A9 # 0 +0xBB87 0xC9AA # 0 +0xBB88 0xC9AB # 0 +0xBB89 0xC9AC # 0 +0xBB8A 0xC9AD # 0 +0xBB8B 0xC9AE # 0 +0xBB8C 0xC9AF # 0 +0xBB8D 0xC9B0 # 0 +0xBB8E 0xC9B1 # 0 +0xBB8F 0xC9B2 # 0 +0xBB90 0xC9B3 # 0 +0xBB91 0xC9B4 # 0 +0xBB93 0xC9B5 # 0 +0xBB94 0xC9B6 # 0 +0xBB95 0xC9B7 # 0 +0xBB96 0xC9B8 # 0 +0xBB97 0xC9B9 # 0 +0xBB98 0xC9BA # 0 +0xBB99 0xC9BB # 0 +0xBB9A 0xC9BC # 0 +0xBB9B 0xC9BD # 0 +0xBB9C 0xC9BE # 0 +0xBB9D 0xC9BF # 0 +0xBBA1 0xC9C0 # 0 +0xBBA2 0xC9C1 # 0 +0xBBA3 0xC9C2 # 0 +0xBBA4 0xC9C3 # 0 +0xBBA5 0xC9C4 # 0 +0xBBA6 0xC9C5 # 0 +0xBBA7 0xC9C6 # 0 +0xBBA8 0xC9C7 # 0 +0xBBA9 0xC9C8 # 0 +0xBBAA 0xC9C9 # 0 +0xBBAB 0xC9CA # 0 +0xBBAC 0xC9CB # 0 +0xBBAD 0xC9CC # 0 +0xBBAE 0xC9CD # 0 +0xBBAF 0xC9CE # 0 +0xBBB0 0xC9CF # 0 +0xBBB1 0xC9D0 # 0 +0xBBB3 0xC9D1 # 0 +0xBBB4 0xC9D2 # 0 +0xBBB5 0xC9D3 # 0 +0xBBB6 0xC9D4 # 0 +0xBBB7 0xC9D5 # 0 +0xBBB8 0xC9D6 # 0 +0xBBB9 0xC9D7 # 0 +0xBBBA 0xC9D8 # 0 +0xBBBB 0xC9D9 # 0 +0xBBBC 0xC9DA # 0 +0xBBBD 0xC9DB # 0 +0xBC41 0x110D # 0 +0xBC61 0xC9DC # 0 +0xBC62 0xC9DD # 0 +0xBC63 0xC9DE # 0 +0xBC64 0xC9DF # 0 +0xBC65 0xC9E0 # 0 +0xBC66 0xC9E1 # 0 +0xBC67 0xC9E2 # 0 +0xBC68 0xC9E3 # 0 +0xBC69 0xC9E4 # 0 +0xBC6A 0xC9E5 # 0 +0xBC6B 0xC9E6 # 0 +0xBC6C 0xC9E7 # 0 +0xBC6D 0xC9E8 # 0 +0xBC6E 0xC9E9 # 0 +0xBC6F 0xC9EA # 0 +0xBC70 0xC9EB # 0 +0xBC71 0xC9EC # 0 +0xBC73 0xC9ED # 0 +0xBC74 0xC9EE # 0 +0xBC75 0xC9EF # 0 +0xBC76 0xC9F0 # 0 +0xBC77 0xC9F1 # 0 +0xBC78 0xC9F2 # 0 +0xBC79 0xC9F3 # 0 +0xBC7A 0xC9F4 # 0 +0xBC7B 0xC9F5 # 0 +0xBC7C 0xC9F6 # 0 +0xBC7D 0xC9F7 # 0 +0xBC81 0xC9F8 # 0 +0xBC82 0xC9F9 # 0 +0xBC83 0xC9FA # 0 +0xBC84 0xC9FB # 0 +0xBC85 0xC9FC # 0 +0xBC86 0xC9FD # 0 +0xBC87 0xC9FE # 0 +0xBC88 0xC9FF # 0 +0xBC89 0xCA00 # 0 +0xBC8A 0xCA01 # 0 +0xBC8B 0xCA02 # 0 +0xBC8C 0xCA03 # 0 +0xBC8D 0xCA04 # 0 +0xBC8E 0xCA05 # 0 +0xBC8F 0xCA06 # 0 +0xBC90 0xCA07 # 0 +0xBC91 0xCA08 # 0 +0xBC93 0xCA09 # 0 +0xBC94 0xCA0A # 0 +0xBC95 0xCA0B # 0 +0xBC96 0xCA0C # 0 +0xBC97 0xCA0D # 0 +0xBC98 0xCA0E # 0 +0xBC99 0xCA0F # 0 +0xBC9A 0xCA10 # 0 +0xBC9B 0xCA11 # 0 +0xBC9C 0xCA12 # 0 +0xBC9D 0xCA13 # 0 +0xBCA1 0xCA14 # 0 +0xBCA2 0xCA15 # 0 +0xBCA3 0xCA16 # 0 +0xBCA4 0xCA17 # 0 +0xBCA5 0xCA18 # 0 +0xBCA6 0xCA19 # 0 +0xBCA7 0xCA1A # 0 +0xBCA8 0xCA1B # 0 +0xBCA9 0xCA1C # 0 +0xBCAA 0xCA1D # 0 +0xBCAB 0xCA1E # 0 +0xBCAC 0xCA1F # 0 +0xBCAD 0xCA20 # 0 +0xBCAE 0xCA21 # 0 +0xBCAF 0xCA22 # 0 +0xBCB0 0xCA23 # 0 +0xBCB1 0xCA24 # 0 +0xBCB3 0xCA25 # 0 +0xBCB4 0xCA26 # 0 +0xBCB5 0xCA27 # 0 +0xBCB6 0xCA28 # 0 +0xBCB7 0xCA29 # 0 +0xBCB8 0xCA2A # 0 +0xBCB9 0xCA2B # 0 +0xBCBA 0xCA2C # 0 +0xBCBB 0xCA2D # 0 +0xBCBC 0xCA2E # 0 +0xBCBD 0xCA2F # 0 +0xBCC1 0xCA30 # 0 +0xBCC2 0xCA31 # 0 +0xBCC3 0xCA32 # 0 +0xBCC4 0xCA33 # 0 +0xBCC5 0xCA34 # 0 +0xBCC6 0xCA35 # 0 +0xBCC7 0xCA36 # 0 +0xBCC8 0xCA37 # 0 +0xBCC9 0xCA38 # 0 +0xBCCA 0xCA39 # 0 +0xBCCB 0xCA3A # 0 +0xBCCC 0xCA3B # 0 +0xBCCD 0xCA3C # 0 +0xBCCE 0xCA3D # 0 +0xBCCF 0xCA3E # 0 +0xBCD0 0xCA3F # 0 +0xBCD1 0xCA40 # 0 +0xBCD3 0xCA41 # 0 +0xBCD4 0xCA42 # 0 +0xBCD5 0xCA43 # 0 +0xBCD6 0xCA44 # 0 +0xBCD7 0xCA45 # 0 +0xBCD8 0xCA46 # 0 +0xBCD9 0xCA47 # 0 +0xBCDA 0xCA48 # 0 +0xBCDB 0xCA49 # 0 +0xBCDC 0xCA4A # 0 +0xBCDD 0xCA4B # 0 +0xBCE1 0xCA4C # 0 +0xBCE2 0xCA4D # 0 +0xBCE3 0xCA4E # 0 +0xBCE4 0xCA4F # 0 +0xBCE5 0xCA50 # 0 +0xBCE6 0xCA51 # 0 +0xBCE7 0xCA52 # 0 +0xBCE8 0xCA53 # 0 +0xBCE9 0xCA54 # 0 +0xBCEA 0xCA55 # 0 +0xBCEB 0xCA56 # 0 +0xBCEC 0xCA57 # 0 +0xBCED 0xCA58 # 0 +0xBCEE 0xCA59 # 0 +0xBCEF 0xCA5A # 0 +0xBCF0 0xCA5B # 0 +0xBCF1 0xCA5C # 0 +0xBCF3 0xCA5D # 0 +0xBCF4 0xCA5E # 0 +0xBCF5 0xCA5F # 0 +0xBCF6 0xCA60 # 0 +0xBCF7 0xCA61 # 0 +0xBCF8 0xCA62 # 0 +0xBCF9 0xCA63 # 0 +0xBCFA 0xCA64 # 0 +0xBCFB 0xCA65 # 0 +0xBCFC 0xCA66 # 0 +0xBCFD 0xCA67 # 0 +0xBD41 0xCA68 # 0 +0xBD42 0xCA69 # 0 +0xBD43 0xCA6A # 0 +0xBD44 0xCA6B # 0 +0xBD45 0xCA6C # 0 +0xBD46 0xCA6D # 0 +0xBD47 0xCA6E # 0 +0xBD48 0xCA6F # 0 +0xBD49 0xCA70 # 0 +0xBD4A 0xCA71 # 0 +0xBD4B 0xCA72 # 0 +0xBD4C 0xCA73 # 0 +0xBD4D 0xCA74 # 0 +0xBD4E 0xCA75 # 0 +0xBD4F 0xCA76 # 0 +0xBD50 0xCA77 # 0 +0xBD51 0xCA78 # 0 +0xBD53 0xCA79 # 0 +0xBD54 0xCA7A # 0 +0xBD55 0xCA7B # 0 +0xBD56 0xCA7C # 0 +0xBD57 0xCA7D # 0 +0xBD58 0xCA7E # 0 +0xBD59 0xCA7F # 0 +0xBD5A 0xCA80 # 0 +0xBD5B 0xCA81 # 0 +0xBD5C 0xCA82 # 0 +0xBD5D 0xCA83 # 0 +0xBD61 0xCA84 # 0 +0xBD62 0xCA85 # 0 +0xBD63 0xCA86 # 0 +0xBD64 0xCA87 # 0 +0xBD65 0xCA88 # 0 +0xBD66 0xCA89 # 0 +0xBD67 0xCA8A # 0 +0xBD68 0xCA8B # 0 +0xBD69 0xCA8C # 0 +0xBD6A 0xCA8D # 0 +0xBD6B 0xCA8E # 0 +0xBD6C 0xCA8F # 0 +0xBD6D 0xCA90 # 0 +0xBD6E 0xCA91 # 0 +0xBD6F 0xCA92 # 0 +0xBD70 0xCA93 # 0 +0xBD71 0xCA94 # 0 +0xBD73 0xCA95 # 0 +0xBD74 0xCA96 # 0 +0xBD75 0xCA97 # 0 +0xBD76 0xCA98 # 0 +0xBD77 0xCA99 # 0 +0xBD78 0xCA9A # 0 +0xBD79 0xCA9B # 0 +0xBD7A 0xCA9C # 0 +0xBD7B 0xCA9D # 0 +0xBD7C 0xCA9E # 0 +0xBD7D 0xCA9F # 0 +0xBD81 0xCAA0 # 0 +0xBD82 0xCAA1 # 0 +0xBD83 0xCAA2 # 0 +0xBD84 0xCAA3 # 0 +0xBD85 0xCAA4 # 0 +0xBD86 0xCAA5 # 0 +0xBD87 0xCAA6 # 0 +0xBD88 0xCAA7 # 0 +0xBD89 0xCAA8 # 0 +0xBD8A 0xCAA9 # 0 +0xBD8B 0xCAAA # 0 +0xBD8C 0xCAAB # 0 +0xBD8D 0xCAAC # 0 +0xBD8E 0xCAAD # 0 +0xBD8F 0xCAAE # 0 +0xBD90 0xCAAF # 0 +0xBD91 0xCAB0 # 0 +0xBD93 0xCAB1 # 0 +0xBD94 0xCAB2 # 0 +0xBD95 0xCAB3 # 0 +0xBD96 0xCAB4 # 0 +0xBD97 0xCAB5 # 0 +0xBD98 0xCAB6 # 0 +0xBD99 0xCAB7 # 0 +0xBD9A 0xCAB8 # 0 +0xBD9B 0xCAB9 # 0 +0xBD9C 0xCABA # 0 +0xBD9D 0xCABB # 0 +0xBDA1 0xCABC # 0 +0xBDA2 0xCABD # 0 +0xBDA3 0xCABE # 0 +0xBDA4 0xCABF # 0 +0xBDA5 0xCAC0 # 0 +0xBDA6 0xCAC1 # 0 +0xBDA7 0xCAC2 # 0 +0xBDA8 0xCAC3 # 0 +0xBDA9 0xCAC4 # 0 +0xBDAA 0xCAC5 # 0 +0xBDAB 0xCAC6 # 0 +0xBDAC 0xCAC7 # 0 +0xBDAD 0xCAC8 # 0 +0xBDAE 0xCAC9 # 0 +0xBDAF 0xCACA # 0 +0xBDB0 0xCACB # 0 +0xBDB1 0xCACC # 0 +0xBDB3 0xCACD # 0 +0xBDB4 0xCACE # 0 +0xBDB5 0xCACF # 0 +0xBDB6 0xCAD0 # 0 +0xBDB7 0xCAD1 # 0 +0xBDB8 0xCAD2 # 0 +0xBDB9 0xCAD3 # 0 +0xBDBA 0xCAD4 # 0 +0xBDBB 0xCAD5 # 0 +0xBDBC 0xCAD6 # 0 +0xBDBD 0xCAD7 # 0 +0xBDC1 0xCAD8 # 0 +0xBDC2 0xCAD9 # 0 +0xBDC3 0xCADA # 0 +0xBDC4 0xCADB # 0 +0xBDC5 0xCADC # 0 +0xBDC6 0xCADD # 0 +0xBDC7 0xCADE # 0 +0xBDC8 0xCADF # 0 +0xBDC9 0xCAE0 # 0 +0xBDCA 0xCAE1 # 0 +0xBDCB 0xCAE2 # 0 +0xBDCC 0xCAE3 # 0 +0xBDCD 0xCAE4 # 0 +0xBDCE 0xCAE5 # 0 +0xBDCF 0xCAE6 # 0 +0xBDD0 0xCAE7 # 0 +0xBDD1 0xCAE8 # 0 +0xBDD3 0xCAE9 # 0 +0xBDD4 0xCAEA # 0 +0xBDD5 0xCAEB # 0 +0xBDD6 0xCAEC # 0 +0xBDD7 0xCAED # 0 +0xBDD8 0xCAEE # 0 +0xBDD9 0xCAEF # 0 +0xBDDA 0xCAF0 # 0 +0xBDDB 0xCAF1 # 0 +0xBDDC 0xCAF2 # 0 +0xBDDD 0xCAF3 # 0 +0xBDE1 0xCAF4 # 0 +0xBDE2 0xCAF5 # 0 +0xBDE3 0xCAF6 # 0 +0xBDE4 0xCAF7 # 0 +0xBDE5 0xCAF8 # 0 +0xBDE6 0xCAF9 # 0 +0xBDE7 0xCAFA # 0 +0xBDE8 0xCAFB # 0 +0xBDE9 0xCAFC # 0 +0xBDEA 0xCAFD # 0 +0xBDEB 0xCAFE # 0 +0xBDEC 0xCAFF # 0 +0xBDED 0xCB00 # 0 +0xBDEE 0xCB01 # 0 +0xBDEF 0xCB02 # 0 +0xBDF0 0xCB03 # 0 +0xBDF1 0xCB04 # 0 +0xBDF3 0xCB05 # 0 +0xBDF4 0xCB06 # 0 +0xBDF5 0xCB07 # 0 +0xBDF6 0xCB08 # 0 +0xBDF7 0xCB09 # 0 +0xBDF8 0xCB0A # 0 +0xBDF9 0xCB0B # 0 +0xBDFA 0xCB0C # 0 +0xBDFB 0xCB0D # 0 +0xBDFC 0xCB0E # 0 +0xBDFD 0xCB0F # 0 +0xBE41 0xCB10 # 0 +0xBE42 0xCB11 # 0 +0xBE43 0xCB12 # 0 +0xBE44 0xCB13 # 0 +0xBE45 0xCB14 # 0 +0xBE46 0xCB15 # 0 +0xBE47 0xCB16 # 0 +0xBE48 0xCB17 # 0 +0xBE49 0xCB18 # 0 +0xBE4A 0xCB19 # 0 +0xBE4B 0xCB1A # 0 +0xBE4C 0xCB1B # 0 +0xBE4D 0xCB1C # 0 +0xBE4E 0xCB1D # 0 +0xBE4F 0xCB1E # 0 +0xBE50 0xCB1F # 0 +0xBE51 0xCB20 # 0 +0xBE53 0xCB21 # 0 +0xBE54 0xCB22 # 0 +0xBE55 0xCB23 # 0 +0xBE56 0xCB24 # 0 +0xBE57 0xCB25 # 0 +0xBE58 0xCB26 # 0 +0xBE59 0xCB27 # 0 +0xBE5A 0xCB28 # 0 +0xBE5B 0xCB29 # 0 +0xBE5C 0xCB2A # 0 +0xBE5D 0xCB2B # 0 +0xBE61 0xCB2C # 0 +0xBE62 0xCB2D # 0 +0xBE63 0xCB2E # 0 +0xBE64 0xCB2F # 0 +0xBE65 0xCB30 # 0 +0xBE66 0xCB31 # 0 +0xBE67 0xCB32 # 0 +0xBE68 0xCB33 # 0 +0xBE69 0xCB34 # 0 +0xBE6A 0xCB35 # 0 +0xBE6B 0xCB36 # 0 +0xBE6C 0xCB37 # 0 +0xBE6D 0xCB38 # 0 +0xBE6E 0xCB39 # 0 +0xBE6F 0xCB3A # 0 +0xBE70 0xCB3B # 0 +0xBE71 0xCB3C # 0 +0xBE73 0xCB3D # 0 +0xBE74 0xCB3E # 0 +0xBE75 0xCB3F # 0 +0xBE76 0xCB40 # 0 +0xBE77 0xCB41 # 0 +0xBE78 0xCB42 # 0 +0xBE79 0xCB43 # 0 +0xBE7A 0xCB44 # 0 +0xBE7B 0xCB45 # 0 +0xBE7C 0xCB46 # 0 +0xBE7D 0xCB47 # 0 +0xBE81 0xCB48 # 0 +0xBE82 0xCB49 # 0 +0xBE83 0xCB4A # 0 +0xBE84 0xCB4B # 0 +0xBE85 0xCB4C # 0 +0xBE86 0xCB4D # 0 +0xBE87 0xCB4E # 0 +0xBE88 0xCB4F # 0 +0xBE89 0xCB50 # 0 +0xBE8A 0xCB51 # 0 +0xBE8B 0xCB52 # 0 +0xBE8C 0xCB53 # 0 +0xBE8D 0xCB54 # 0 +0xBE8E 0xCB55 # 0 +0xBE8F 0xCB56 # 0 +0xBE90 0xCB57 # 0 +0xBE91 0xCB58 # 0 +0xBE93 0xCB59 # 0 +0xBE94 0xCB5A # 0 +0xBE95 0xCB5B # 0 +0xBE96 0xCB5C # 0 +0xBE97 0xCB5D # 0 +0xBE98 0xCB5E # 0 +0xBE99 0xCB5F # 0 +0xBE9A 0xCB60 # 0 +0xBE9B 0xCB61 # 0 +0xBE9C 0xCB62 # 0 +0xBE9D 0xCB63 # 0 +0xBEA1 0xCB64 # 0 +0xBEA2 0xCB65 # 0 +0xBEA3 0xCB66 # 0 +0xBEA4 0xCB67 # 0 +0xBEA5 0xCB68 # 0 +0xBEA6 0xCB69 # 0 +0xBEA7 0xCB6A # 0 +0xBEA8 0xCB6B # 0 +0xBEA9 0xCB6C # 0 +0xBEAA 0xCB6D # 0 +0xBEAB 0xCB6E # 0 +0xBEAC 0xCB6F # 0 +0xBEAD 0xCB70 # 0 +0xBEAE 0xCB71 # 0 +0xBEAF 0xCB72 # 0 +0xBEB0 0xCB73 # 0 +0xBEB1 0xCB74 # 0 +0xBEB3 0xCB75 # 0 +0xBEB4 0xCB76 # 0 +0xBEB5 0xCB77 # 0 +0xBEB6 0xCB78 # 0 +0xBEB7 0xCB79 # 0 +0xBEB8 0xCB7A # 0 +0xBEB9 0xCB7B # 0 +0xBEBA 0xCB7C # 0 +0xBEBB 0xCB7D # 0 +0xBEBC 0xCB7E # 0 +0xBEBD 0xCB7F # 0 +0xBEC1 0xCB80 # 0 +0xBEC2 0xCB81 # 0 +0xBEC3 0xCB82 # 0 +0xBEC4 0xCB83 # 0 +0xBEC5 0xCB84 # 0 +0xBEC6 0xCB85 # 0 +0xBEC7 0xCB86 # 0 +0xBEC8 0xCB87 # 0 +0xBEC9 0xCB88 # 0 +0xBECA 0xCB89 # 0 +0xBECB 0xCB8A # 0 +0xBECC 0xCB8B # 0 +0xBECD 0xCB8C # 0 +0xBECE 0xCB8D # 0 +0xBECF 0xCB8E # 0 +0xBED0 0xCB8F # 0 +0xBED1 0xCB90 # 0 +0xBED3 0xCB91 # 0 +0xBED4 0xCB92 # 0 +0xBED5 0xCB93 # 0 +0xBED6 0xCB94 # 0 +0xBED7 0xCB95 # 0 +0xBED8 0xCB96 # 0 +0xBED9 0xCB97 # 0 +0xBEDA 0xCB98 # 0 +0xBEDB 0xCB99 # 0 +0xBEDC 0xCB9A # 0 +0xBEDD 0xCB9B # 0 +0xBEE1 0xCB9C # 0 +0xBEE2 0xCB9D # 0 +0xBEE3 0xCB9E # 0 +0xBEE4 0xCB9F # 0 +0xBEE5 0xCBA0 # 0 +0xBEE6 0xCBA1 # 0 +0xBEE7 0xCBA2 # 0 +0xBEE8 0xCBA3 # 0 +0xBEE9 0xCBA4 # 0 +0xBEEA 0xCBA5 # 0 +0xBEEB 0xCBA6 # 0 +0xBEEC 0xCBA7 # 0 +0xBEED 0xCBA8 # 0 +0xBEEE 0xCBA9 # 0 +0xBEEF 0xCBAA # 0 +0xBEF0 0xCBAB # 0 +0xBEF1 0xCBAC # 0 +0xBEF3 0xCBAD # 0 +0xBEF4 0xCBAE # 0 +0xBEF5 0xCBAF # 0 +0xBEF6 0xCBB0 # 0 +0xBEF7 0xCBB1 # 0 +0xBEF8 0xCBB2 # 0 +0xBEF9 0xCBB3 # 0 +0xBEFA 0xCBB4 # 0 +0xBEFB 0xCBB5 # 0 +0xBEFC 0xCBB6 # 0 +0xBEFD 0xCBB7 # 0 +0xBF41 0xCBB8 # 0 +0xBF42 0xCBB9 # 0 +0xBF43 0xCBBA # 0 +0xBF44 0xCBBB # 0 +0xBF45 0xCBBC # 0 +0xBF46 0xCBBD # 0 +0xBF47 0xCBBE # 0 +0xBF48 0xCBBF # 0 +0xBF49 0xCBC0 # 0 +0xBF4A 0xCBC1 # 0 +0xBF4B 0xCBC2 # 0 +0xBF4C 0xCBC3 # 0 +0xBF4D 0xCBC4 # 0 +0xBF4E 0xCBC5 # 0 +0xBF4F 0xCBC6 # 0 +0xBF50 0xCBC7 # 0 +0xBF51 0xCBC8 # 0 +0xBF53 0xCBC9 # 0 +0xBF54 0xCBCA # 0 +0xBF55 0xCBCB # 0 +0xBF56 0xCBCC # 0 +0xBF57 0xCBCD # 0 +0xBF58 0xCBCE # 0 +0xBF59 0xCBCF # 0 +0xBF5A 0xCBD0 # 0 +0xBF5B 0xCBD1 # 0 +0xBF5C 0xCBD2 # 0 +0xBF5D 0xCBD3 # 0 +0xBF61 0xCBD4 # 0 +0xBF62 0xCBD5 # 0 +0xBF63 0xCBD6 # 0 +0xBF64 0xCBD7 # 0 +0xBF65 0xCBD8 # 0 +0xBF66 0xCBD9 # 0 +0xBF67 0xCBDA # 0 +0xBF68 0xCBDB # 0 +0xBF69 0xCBDC # 0 +0xBF6A 0xCBDD # 0 +0xBF6B 0xCBDE # 0 +0xBF6C 0xCBDF # 0 +0xBF6D 0xCBE0 # 0 +0xBF6E 0xCBE1 # 0 +0xBF6F 0xCBE2 # 0 +0xBF70 0xCBE3 # 0 +0xBF71 0xCBE4 # 0 +0xBF73 0xCBE5 # 0 +0xBF74 0xCBE6 # 0 +0xBF75 0xCBE7 # 0 +0xBF76 0xCBE8 # 0 +0xBF77 0xCBE9 # 0 +0xBF78 0xCBEA # 0 +0xBF79 0xCBEB # 0 +0xBF7A 0xCBEC # 0 +0xBF7B 0xCBED # 0 +0xBF7C 0xCBEE # 0 +0xBF7D 0xCBEF # 0 +0xBF81 0xCBF0 # 0 +0xBF82 0xCBF1 # 0 +0xBF83 0xCBF2 # 0 +0xBF84 0xCBF3 # 0 +0xBF85 0xCBF4 # 0 +0xBF86 0xCBF5 # 0 +0xBF87 0xCBF6 # 0 +0xBF88 0xCBF7 # 0 +0xBF89 0xCBF8 # 0 +0xBF8A 0xCBF9 # 0 +0xBF8B 0xCBFA # 0 +0xBF8C 0xCBFB # 0 +0xBF8D 0xCBFC # 0 +0xBF8E 0xCBFD # 0 +0xBF8F 0xCBFE # 0 +0xBF90 0xCBFF # 0 +0xBF91 0xCC00 # 0 +0xBF93 0xCC01 # 0 +0xBF94 0xCC02 # 0 +0xBF95 0xCC03 # 0 +0xBF96 0xCC04 # 0 +0xBF97 0xCC05 # 0 +0xBF98 0xCC06 # 0 +0xBF99 0xCC07 # 0 +0xBF9A 0xCC08 # 0 +0xBF9B 0xCC09 # 0 +0xBF9C 0xCC0A # 0 +0xBF9D 0xCC0B # 0 +0xBFA1 0xCC0C # 0 +0xBFA2 0xCC0D # 0 +0xBFA3 0xCC0E # 0 +0xBFA4 0xCC0F # 0 +0xBFA5 0xCC10 # 0 +0xBFA6 0xCC11 # 0 +0xBFA7 0xCC12 # 0 +0xBFA8 0xCC13 # 0 +0xBFA9 0xCC14 # 0 +0xBFAA 0xCC15 # 0 +0xBFAB 0xCC16 # 0 +0xBFAC 0xCC17 # 0 +0xBFAD 0xCC18 # 0 +0xBFAE 0xCC19 # 0 +0xBFAF 0xCC1A # 0 +0xBFB0 0xCC1B # 0 +0xBFB1 0xCC1C # 0 +0xBFB3 0xCC1D # 0 +0xBFB4 0xCC1E # 0 +0xBFB5 0xCC1F # 0 +0xBFB6 0xCC20 # 0 +0xBFB7 0xCC21 # 0 +0xBFB8 0xCC22 # 0 +0xBFB9 0xCC23 # 0 +0xBFBA 0xCC24 # 0 +0xBFBB 0xCC25 # 0 +0xBFBC 0xCC26 # 0 +0xBFBD 0xCC27 # 0 +0xC041 0x110E # 0 +0xC061 0xCC28 # 0 +0xC062 0xCC29 # 0 +0xC063 0xCC2A # 0 +0xC064 0xCC2B # 0 +0xC065 0xCC2C # 0 +0xC066 0xCC2D # 0 +0xC067 0xCC2E # 0 +0xC068 0xCC2F # 0 +0xC069 0xCC30 # 0 +0xC06A 0xCC31 # 0 +0xC06B 0xCC32 # 0 +0xC06C 0xCC33 # 0 +0xC06D 0xCC34 # 0 +0xC06E 0xCC35 # 0 +0xC06F 0xCC36 # 0 +0xC070 0xCC37 # 0 +0xC071 0xCC38 # 0 +0xC073 0xCC39 # 0 +0xC074 0xCC3A # 0 +0xC075 0xCC3B # 0 +0xC076 0xCC3C # 0 +0xC077 0xCC3D # 0 +0xC078 0xCC3E # 0 +0xC079 0xCC3F # 0 +0xC07A 0xCC40 # 0 +0xC07B 0xCC41 # 0 +0xC07C 0xCC42 # 0 +0xC07D 0xCC43 # 0 +0xC081 0xCC44 # 0 +0xC082 0xCC45 # 0 +0xC083 0xCC46 # 0 +0xC084 0xCC47 # 0 +0xC085 0xCC48 # 0 +0xC086 0xCC49 # 0 +0xC087 0xCC4A # 0 +0xC088 0xCC4B # 0 +0xC089 0xCC4C # 0 +0xC08A 0xCC4D # 0 +0xC08B 0xCC4E # 0 +0xC08C 0xCC4F # 0 +0xC08D 0xCC50 # 0 +0xC08E 0xCC51 # 0 +0xC08F 0xCC52 # 0 +0xC090 0xCC53 # 0 +0xC091 0xCC54 # 0 +0xC093 0xCC55 # 0 +0xC094 0xCC56 # 0 +0xC095 0xCC57 # 0 +0xC096 0xCC58 # 0 +0xC097 0xCC59 # 0 +0xC098 0xCC5A # 0 +0xC099 0xCC5B # 0 +0xC09A 0xCC5C # 0 +0xC09B 0xCC5D # 0 +0xC09C 0xCC5E # 0 +0xC09D 0xCC5F # 0 +0xC0A1 0xCC60 # 0 +0xC0A2 0xCC61 # 0 +0xC0A3 0xCC62 # 0 +0xC0A4 0xCC63 # 0 +0xC0A5 0xCC64 # 0 +0xC0A6 0xCC65 # 0 +0xC0A7 0xCC66 # 0 +0xC0A8 0xCC67 # 0 +0xC0A9 0xCC68 # 0 +0xC0AA 0xCC69 # 0 +0xC0AB 0xCC6A # 0 +0xC0AC 0xCC6B # 0 +0xC0AD 0xCC6C # 0 +0xC0AE 0xCC6D # 0 +0xC0AF 0xCC6E # 0 +0xC0B0 0xCC6F # 0 +0xC0B1 0xCC70 # 0 +0xC0B3 0xCC71 # 0 +0xC0B4 0xCC72 # 0 +0xC0B5 0xCC73 # 0 +0xC0B6 0xCC74 # 0 +0xC0B7 0xCC75 # 0 +0xC0B8 0xCC76 # 0 +0xC0B9 0xCC77 # 0 +0xC0BA 0xCC78 # 0 +0xC0BB 0xCC79 # 0 +0xC0BC 0xCC7A # 0 +0xC0BD 0xCC7B # 0 +0xC0C1 0xCC7C # 0 +0xC0C2 0xCC7D # 0 +0xC0C3 0xCC7E # 0 +0xC0C4 0xCC7F # 0 +0xC0C5 0xCC80 # 0 +0xC0C6 0xCC81 # 0 +0xC0C7 0xCC82 # 0 +0xC0C8 0xCC83 # 0 +0xC0C9 0xCC84 # 0 +0xC0CA 0xCC85 # 0 +0xC0CB 0xCC86 # 0 +0xC0CC 0xCC87 # 0 +0xC0CD 0xCC88 # 0 +0xC0CE 0xCC89 # 0 +0xC0CF 0xCC8A # 0 +0xC0D0 0xCC8B # 0 +0xC0D1 0xCC8C # 0 +0xC0D3 0xCC8D # 0 +0xC0D4 0xCC8E # 0 +0xC0D5 0xCC8F # 0 +0xC0D6 0xCC90 # 0 +0xC0D7 0xCC91 # 0 +0xC0D8 0xCC92 # 0 +0xC0D9 0xCC93 # 0 +0xC0DA 0xCC94 # 0 +0xC0DB 0xCC95 # 0 +0xC0DC 0xCC96 # 0 +0xC0DD 0xCC97 # 0 +0xC0E1 0xCC98 # 0 +0xC0E2 0xCC99 # 0 +0xC0E3 0xCC9A # 0 +0xC0E4 0xCC9B # 0 +0xC0E5 0xCC9C # 0 +0xC0E6 0xCC9D # 0 +0xC0E7 0xCC9E # 0 +0xC0E8 0xCC9F # 0 +0xC0E9 0xCCA0 # 0 +0xC0EA 0xCCA1 # 0 +0xC0EB 0xCCA2 # 0 +0xC0EC 0xCCA3 # 0 +0xC0ED 0xCCA4 # 0 +0xC0EE 0xCCA5 # 0 +0xC0EF 0xCCA6 # 0 +0xC0F0 0xCCA7 # 0 +0xC0F1 0xCCA8 # 0 +0xC0F3 0xCCA9 # 0 +0xC0F4 0xCCAA # 0 +0xC0F5 0xCCAB # 0 +0xC0F6 0xCCAC # 0 +0xC0F7 0xCCAD # 0 +0xC0F8 0xCCAE # 0 +0xC0F9 0xCCAF # 0 +0xC0FA 0xCCB0 # 0 +0xC0FB 0xCCB1 # 0 +0xC0FC 0xCCB2 # 0 +0xC0FD 0xCCB3 # 0 +0xC141 0xCCB4 # 0 +0xC142 0xCCB5 # 0 +0xC143 0xCCB6 # 0 +0xC144 0xCCB7 # 0 +0xC145 0xCCB8 # 0 +0xC146 0xCCB9 # 0 +0xC147 0xCCBA # 0 +0xC148 0xCCBB # 0 +0xC149 0xCCBC # 0 +0xC14A 0xCCBD # 0 +0xC14B 0xCCBE # 0 +0xC14C 0xCCBF # 0 +0xC14D 0xCCC0 # 0 +0xC14E 0xCCC1 # 0 +0xC14F 0xCCC2 # 0 +0xC150 0xCCC3 # 0 +0xC151 0xCCC4 # 0 +0xC153 0xCCC5 # 0 +0xC154 0xCCC6 # 0 +0xC155 0xCCC7 # 0 +0xC156 0xCCC8 # 0 +0xC157 0xCCC9 # 0 +0xC158 0xCCCA # 0 +0xC159 0xCCCB # 0 +0xC15A 0xCCCC # 0 +0xC15B 0xCCCD # 0 +0xC15C 0xCCCE # 0 +0xC15D 0xCCCF # 0 +0xC161 0xCCD0 # 0 +0xC162 0xCCD1 # 0 +0xC163 0xCCD2 # 0 +0xC164 0xCCD3 # 0 +0xC165 0xCCD4 # 0 +0xC166 0xCCD5 # 0 +0xC167 0xCCD6 # 0 +0xC168 0xCCD7 # 0 +0xC169 0xCCD8 # 0 +0xC16A 0xCCD9 # 0 +0xC16B 0xCCDA # 0 +0xC16C 0xCCDB # 0 +0xC16D 0xCCDC # 0 +0xC16E 0xCCDD # 0 +0xC16F 0xCCDE # 0 +0xC170 0xCCDF # 0 +0xC171 0xCCE0 # 0 +0xC173 0xCCE1 # 0 +0xC174 0xCCE2 # 0 +0xC175 0xCCE3 # 0 +0xC176 0xCCE4 # 0 +0xC177 0xCCE5 # 0 +0xC178 0xCCE6 # 0 +0xC179 0xCCE7 # 0 +0xC17A 0xCCE8 # 0 +0xC17B 0xCCE9 # 0 +0xC17C 0xCCEA # 0 +0xC17D 0xCCEB # 0 +0xC181 0xCCEC # 0 +0xC182 0xCCED # 0 +0xC183 0xCCEE # 0 +0xC184 0xCCEF # 0 +0xC185 0xCCF0 # 0 +0xC186 0xCCF1 # 0 +0xC187 0xCCF2 # 0 +0xC188 0xCCF3 # 0 +0xC189 0xCCF4 # 0 +0xC18A 0xCCF5 # 0 +0xC18B 0xCCF6 # 0 +0xC18C 0xCCF7 # 0 +0xC18D 0xCCF8 # 0 +0xC18E 0xCCF9 # 0 +0xC18F 0xCCFA # 0 +0xC190 0xCCFB # 0 +0xC191 0xCCFC # 0 +0xC193 0xCCFD # 0 +0xC194 0xCCFE # 0 +0xC195 0xCCFF # 0 +0xC196 0xCD00 # 0 +0xC197 0xCD01 # 0 +0xC198 0xCD02 # 0 +0xC199 0xCD03 # 0 +0xC19A 0xCD04 # 0 +0xC19B 0xCD05 # 0 +0xC19C 0xCD06 # 0 +0xC19D 0xCD07 # 0 +0xC1A1 0xCD08 # 0 +0xC1A2 0xCD09 # 0 +0xC1A3 0xCD0A # 0 +0xC1A4 0xCD0B # 0 +0xC1A5 0xCD0C # 0 +0xC1A6 0xCD0D # 0 +0xC1A7 0xCD0E # 0 +0xC1A8 0xCD0F # 0 +0xC1A9 0xCD10 # 0 +0xC1AA 0xCD11 # 0 +0xC1AB 0xCD12 # 0 +0xC1AC 0xCD13 # 0 +0xC1AD 0xCD14 # 0 +0xC1AE 0xCD15 # 0 +0xC1AF 0xCD16 # 0 +0xC1B0 0xCD17 # 0 +0xC1B1 0xCD18 # 0 +0xC1B3 0xCD19 # 0 +0xC1B4 0xCD1A # 0 +0xC1B5 0xCD1B # 0 +0xC1B6 0xCD1C # 0 +0xC1B7 0xCD1D # 0 +0xC1B8 0xCD1E # 0 +0xC1B9 0xCD1F # 0 +0xC1BA 0xCD20 # 0 +0xC1BB 0xCD21 # 0 +0xC1BC 0xCD22 # 0 +0xC1BD 0xCD23 # 0 +0xC1C1 0xCD24 # 0 +0xC1C2 0xCD25 # 0 +0xC1C3 0xCD26 # 0 +0xC1C4 0xCD27 # 0 +0xC1C5 0xCD28 # 0 +0xC1C6 0xCD29 # 0 +0xC1C7 0xCD2A # 0 +0xC1C8 0xCD2B # 0 +0xC1C9 0xCD2C # 0 +0xC1CA 0xCD2D # 0 +0xC1CB 0xCD2E # 0 +0xC1CC 0xCD2F # 0 +0xC1CD 0xCD30 # 0 +0xC1CE 0xCD31 # 0 +0xC1CF 0xCD32 # 0 +0xC1D0 0xCD33 # 0 +0xC1D1 0xCD34 # 0 +0xC1D3 0xCD35 # 0 +0xC1D4 0xCD36 # 0 +0xC1D5 0xCD37 # 0 +0xC1D6 0xCD38 # 0 +0xC1D7 0xCD39 # 0 +0xC1D8 0xCD3A # 0 +0xC1D9 0xCD3B # 0 +0xC1DA 0xCD3C # 0 +0xC1DB 0xCD3D # 0 +0xC1DC 0xCD3E # 0 +0xC1DD 0xCD3F # 0 +0xC1E1 0xCD40 # 0 +0xC1E2 0xCD41 # 0 +0xC1E3 0xCD42 # 0 +0xC1E4 0xCD43 # 0 +0xC1E5 0xCD44 # 0 +0xC1E6 0xCD45 # 0 +0xC1E7 0xCD46 # 0 +0xC1E8 0xCD47 # 0 +0xC1E9 0xCD48 # 0 +0xC1EA 0xCD49 # 0 +0xC1EB 0xCD4A # 0 +0xC1EC 0xCD4B # 0 +0xC1ED 0xCD4C # 0 +0xC1EE 0xCD4D # 0 +0xC1EF 0xCD4E # 0 +0xC1F0 0xCD4F # 0 +0xC1F1 0xCD50 # 0 +0xC1F3 0xCD51 # 0 +0xC1F4 0xCD52 # 0 +0xC1F5 0xCD53 # 0 +0xC1F6 0xCD54 # 0 +0xC1F7 0xCD55 # 0 +0xC1F8 0xCD56 # 0 +0xC1F9 0xCD57 # 0 +0xC1FA 0xCD58 # 0 +0xC1FB 0xCD59 # 0 +0xC1FC 0xCD5A # 0 +0xC1FD 0xCD5B # 0 +0xC241 0xCD5C # 0 +0xC242 0xCD5D # 0 +0xC243 0xCD5E # 0 +0xC244 0xCD5F # 0 +0xC245 0xCD60 # 0 +0xC246 0xCD61 # 0 +0xC247 0xCD62 # 0 +0xC248 0xCD63 # 0 +0xC249 0xCD64 # 0 +0xC24A 0xCD65 # 0 +0xC24B 0xCD66 # 0 +0xC24C 0xCD67 # 0 +0xC24D 0xCD68 # 0 +0xC24E 0xCD69 # 0 +0xC24F 0xCD6A # 0 +0xC250 0xCD6B # 0 +0xC251 0xCD6C # 0 +0xC253 0xCD6D # 0 +0xC254 0xCD6E # 0 +0xC255 0xCD6F # 0 +0xC256 0xCD70 # 0 +0xC257 0xCD71 # 0 +0xC258 0xCD72 # 0 +0xC259 0xCD73 # 0 +0xC25A 0xCD74 # 0 +0xC25B 0xCD75 # 0 +0xC25C 0xCD76 # 0 +0xC25D 0xCD77 # 0 +0xC261 0xCD78 # 0 +0xC262 0xCD79 # 0 +0xC263 0xCD7A # 0 +0xC264 0xCD7B # 0 +0xC265 0xCD7C # 0 +0xC266 0xCD7D # 0 +0xC267 0xCD7E # 0 +0xC268 0xCD7F # 0 +0xC269 0xCD80 # 0 +0xC26A 0xCD81 # 0 +0xC26B 0xCD82 # 0 +0xC26C 0xCD83 # 0 +0xC26D 0xCD84 # 0 +0xC26E 0xCD85 # 0 +0xC26F 0xCD86 # 0 +0xC270 0xCD87 # 0 +0xC271 0xCD88 # 0 +0xC273 0xCD89 # 0 +0xC274 0xCD8A # 0 +0xC275 0xCD8B # 0 +0xC276 0xCD8C # 0 +0xC277 0xCD8D # 0 +0xC278 0xCD8E # 0 +0xC279 0xCD8F # 0 +0xC27A 0xCD90 # 0 +0xC27B 0xCD91 # 0 +0xC27C 0xCD92 # 0 +0xC27D 0xCD93 # 0 +0xC281 0xCD94 # 0 +0xC282 0xCD95 # 0 +0xC283 0xCD96 # 0 +0xC284 0xCD97 # 0 +0xC285 0xCD98 # 0 +0xC286 0xCD99 # 0 +0xC287 0xCD9A # 0 +0xC288 0xCD9B # 0 +0xC289 0xCD9C # 0 +0xC28A 0xCD9D # 0 +0xC28B 0xCD9E # 0 +0xC28C 0xCD9F # 0 +0xC28D 0xCDA0 # 0 +0xC28E 0xCDA1 # 0 +0xC28F 0xCDA2 # 0 +0xC290 0xCDA3 # 0 +0xC291 0xCDA4 # 0 +0xC293 0xCDA5 # 0 +0xC294 0xCDA6 # 0 +0xC295 0xCDA7 # 0 +0xC296 0xCDA8 # 0 +0xC297 0xCDA9 # 0 +0xC298 0xCDAA # 0 +0xC299 0xCDAB # 0 +0xC29A 0xCDAC # 0 +0xC29B 0xCDAD # 0 +0xC29C 0xCDAE # 0 +0xC29D 0xCDAF # 0 +0xC2A1 0xCDB0 # 0 +0xC2A2 0xCDB1 # 0 +0xC2A3 0xCDB2 # 0 +0xC2A4 0xCDB3 # 0 +0xC2A5 0xCDB4 # 0 +0xC2A6 0xCDB5 # 0 +0xC2A7 0xCDB6 # 0 +0xC2A8 0xCDB7 # 0 +0xC2A9 0xCDB8 # 0 +0xC2AA 0xCDB9 # 0 +0xC2AB 0xCDBA # 0 +0xC2AC 0xCDBB # 0 +0xC2AD 0xCDBC # 0 +0xC2AE 0xCDBD # 0 +0xC2AF 0xCDBE # 0 +0xC2B0 0xCDBF # 0 +0xC2B1 0xCDC0 # 0 +0xC2B3 0xCDC1 # 0 +0xC2B4 0xCDC2 # 0 +0xC2B5 0xCDC3 # 0 +0xC2B6 0xCDC4 # 0 +0xC2B7 0xCDC5 # 0 +0xC2B8 0xCDC6 # 0 +0xC2B9 0xCDC7 # 0 +0xC2BA 0xCDC8 # 0 +0xC2BB 0xCDC9 # 0 +0xC2BC 0xCDCA # 0 +0xC2BD 0xCDCB # 0 +0xC2C1 0xCDCC # 0 +0xC2C2 0xCDCD # 0 +0xC2C3 0xCDCE # 0 +0xC2C4 0xCDCF # 0 +0xC2C5 0xCDD0 # 0 +0xC2C6 0xCDD1 # 0 +0xC2C7 0xCDD2 # 0 +0xC2C8 0xCDD3 # 0 +0xC2C9 0xCDD4 # 0 +0xC2CA 0xCDD5 # 0 +0xC2CB 0xCDD6 # 0 +0xC2CC 0xCDD7 # 0 +0xC2CD 0xCDD8 # 0 +0xC2CE 0xCDD9 # 0 +0xC2CF 0xCDDA # 0 +0xC2D0 0xCDDB # 0 +0xC2D1 0xCDDC # 0 +0xC2D3 0xCDDD # 0 +0xC2D4 0xCDDE # 0 +0xC2D5 0xCDDF # 0 +0xC2D6 0xCDE0 # 0 +0xC2D7 0xCDE1 # 0 +0xC2D8 0xCDE2 # 0 +0xC2D9 0xCDE3 # 0 +0xC2DA 0xCDE4 # 0 +0xC2DB 0xCDE5 # 0 +0xC2DC 0xCDE6 # 0 +0xC2DD 0xCDE7 # 0 +0xC2E1 0xCDE8 # 0 +0xC2E2 0xCDE9 # 0 +0xC2E3 0xCDEA # 0 +0xC2E4 0xCDEB # 0 +0xC2E5 0xCDEC # 0 +0xC2E6 0xCDED # 0 +0xC2E7 0xCDEE # 0 +0xC2E8 0xCDEF # 0 +0xC2E9 0xCDF0 # 0 +0xC2EA 0xCDF1 # 0 +0xC2EB 0xCDF2 # 0 +0xC2EC 0xCDF3 # 0 +0xC2ED 0xCDF4 # 0 +0xC2EE 0xCDF5 # 0 +0xC2EF 0xCDF6 # 0 +0xC2F0 0xCDF7 # 0 +0xC2F1 0xCDF8 # 0 +0xC2F3 0xCDF9 # 0 +0xC2F4 0xCDFA # 0 +0xC2F5 0xCDFB # 0 +0xC2F6 0xCDFC # 0 +0xC2F7 0xCDFD # 0 +0xC2F8 0xCDFE # 0 +0xC2F9 0xCDFF # 0 +0xC2FA 0xCE00 # 0 +0xC2FB 0xCE01 # 0 +0xC2FC 0xCE02 # 0 +0xC2FD 0xCE03 # 0 +0xC341 0xCE04 # 0 +0xC342 0xCE05 # 0 +0xC343 0xCE06 # 0 +0xC344 0xCE07 # 0 +0xC345 0xCE08 # 0 +0xC346 0xCE09 # 0 +0xC347 0xCE0A # 0 +0xC348 0xCE0B # 0 +0xC349 0xCE0C # 0 +0xC34A 0xCE0D # 0 +0xC34B 0xCE0E # 0 +0xC34C 0xCE0F # 0 +0xC34D 0xCE10 # 0 +0xC34E 0xCE11 # 0 +0xC34F 0xCE12 # 0 +0xC350 0xCE13 # 0 +0xC351 0xCE14 # 0 +0xC353 0xCE15 # 0 +0xC354 0xCE16 # 0 +0xC355 0xCE17 # 0 +0xC356 0xCE18 # 0 +0xC357 0xCE19 # 0 +0xC358 0xCE1A # 0 +0xC359 0xCE1B # 0 +0xC35A 0xCE1C # 0 +0xC35B 0xCE1D # 0 +0xC35C 0xCE1E # 0 +0xC35D 0xCE1F # 0 +0xC361 0xCE20 # 0 +0xC362 0xCE21 # 0 +0xC363 0xCE22 # 0 +0xC364 0xCE23 # 0 +0xC365 0xCE24 # 0 +0xC366 0xCE25 # 0 +0xC367 0xCE26 # 0 +0xC368 0xCE27 # 0 +0xC369 0xCE28 # 0 +0xC36A 0xCE29 # 0 +0xC36B 0xCE2A # 0 +0xC36C 0xCE2B # 0 +0xC36D 0xCE2C # 0 +0xC36E 0xCE2D # 0 +0xC36F 0xCE2E # 0 +0xC370 0xCE2F # 0 +0xC371 0xCE30 # 0 +0xC373 0xCE31 # 0 +0xC374 0xCE32 # 0 +0xC375 0xCE33 # 0 +0xC376 0xCE34 # 0 +0xC377 0xCE35 # 0 +0xC378 0xCE36 # 0 +0xC379 0xCE37 # 0 +0xC37A 0xCE38 # 0 +0xC37B 0xCE39 # 0 +0xC37C 0xCE3A # 0 +0xC37D 0xCE3B # 0 +0xC381 0xCE3C # 0 +0xC382 0xCE3D # 0 +0xC383 0xCE3E # 0 +0xC384 0xCE3F # 0 +0xC385 0xCE40 # 0 +0xC386 0xCE41 # 0 +0xC387 0xCE42 # 0 +0xC388 0xCE43 # 0 +0xC389 0xCE44 # 0 +0xC38A 0xCE45 # 0 +0xC38B 0xCE46 # 0 +0xC38C 0xCE47 # 0 +0xC38D 0xCE48 # 0 +0xC38E 0xCE49 # 0 +0xC38F 0xCE4A # 0 +0xC390 0xCE4B # 0 +0xC391 0xCE4C # 0 +0xC393 0xCE4D # 0 +0xC394 0xCE4E # 0 +0xC395 0xCE4F # 0 +0xC396 0xCE50 # 0 +0xC397 0xCE51 # 0 +0xC398 0xCE52 # 0 +0xC399 0xCE53 # 0 +0xC39A 0xCE54 # 0 +0xC39B 0xCE55 # 0 +0xC39C 0xCE56 # 0 +0xC39D 0xCE57 # 0 +0xC3A1 0xCE58 # 0 +0xC3A2 0xCE59 # 0 +0xC3A3 0xCE5A # 0 +0xC3A4 0xCE5B # 0 +0xC3A5 0xCE5C # 0 +0xC3A6 0xCE5D # 0 +0xC3A7 0xCE5E # 0 +0xC3A8 0xCE5F # 0 +0xC3A9 0xCE60 # 0 +0xC3AA 0xCE61 # 0 +0xC3AB 0xCE62 # 0 +0xC3AC 0xCE63 # 0 +0xC3AD 0xCE64 # 0 +0xC3AE 0xCE65 # 0 +0xC3AF 0xCE66 # 0 +0xC3B0 0xCE67 # 0 +0xC3B1 0xCE68 # 0 +0xC3B3 0xCE69 # 0 +0xC3B4 0xCE6A # 0 +0xC3B5 0xCE6B # 0 +0xC3B6 0xCE6C # 0 +0xC3B7 0xCE6D # 0 +0xC3B8 0xCE6E # 0 +0xC3B9 0xCE6F # 0 +0xC3BA 0xCE70 # 0 +0xC3BB 0xCE71 # 0 +0xC3BC 0xCE72 # 0 +0xC3BD 0xCE73 # 0 +0xC441 0x110F # 0 +0xC461 0xCE74 # 0 +0xC462 0xCE75 # 0 +0xC463 0xCE76 # 0 +0xC464 0xCE77 # 0 +0xC465 0xCE78 # 0 +0xC466 0xCE79 # 0 +0xC467 0xCE7A # 0 +0xC468 0xCE7B # 0 +0xC469 0xCE7C # 0 +0xC46A 0xCE7D # 0 +0xC46B 0xCE7E # 0 +0xC46C 0xCE7F # 0 +0xC46D 0xCE80 # 0 +0xC46E 0xCE81 # 0 +0xC46F 0xCE82 # 0 +0xC470 0xCE83 # 0 +0xC471 0xCE84 # 0 +0xC473 0xCE85 # 0 +0xC474 0xCE86 # 0 +0xC475 0xCE87 # 0 +0xC476 0xCE88 # 0 +0xC477 0xCE89 # 0 +0xC478 0xCE8A # 0 +0xC479 0xCE8B # 0 +0xC47A 0xCE8C # 0 +0xC47B 0xCE8D # 0 +0xC47C 0xCE8E # 0 +0xC47D 0xCE8F # 0 +0xC481 0xCE90 # 0 +0xC482 0xCE91 # 0 +0xC483 0xCE92 # 0 +0xC484 0xCE93 # 0 +0xC485 0xCE94 # 0 +0xC486 0xCE95 # 0 +0xC487 0xCE96 # 0 +0xC488 0xCE97 # 0 +0xC489 0xCE98 # 0 +0xC48A 0xCE99 # 0 +0xC48B 0xCE9A # 0 +0xC48C 0xCE9B # 0 +0xC48D 0xCE9C # 0 +0xC48E 0xCE9D # 0 +0xC48F 0xCE9E # 0 +0xC490 0xCE9F # 0 +0xC491 0xCEA0 # 0 +0xC493 0xCEA1 # 0 +0xC494 0xCEA2 # 0 +0xC495 0xCEA3 # 0 +0xC496 0xCEA4 # 0 +0xC497 0xCEA5 # 0 +0xC498 0xCEA6 # 0 +0xC499 0xCEA7 # 0 +0xC49A 0xCEA8 # 0 +0xC49B 0xCEA9 # 0 +0xC49C 0xCEAA # 0 +0xC49D 0xCEAB # 0 +0xC4A1 0xCEAC # 0 +0xC4A2 0xCEAD # 0 +0xC4A3 0xCEAE # 0 +0xC4A4 0xCEAF # 0 +0xC4A5 0xCEB0 # 0 +0xC4A6 0xCEB1 # 0 +0xC4A7 0xCEB2 # 0 +0xC4A8 0xCEB3 # 0 +0xC4A9 0xCEB4 # 0 +0xC4AA 0xCEB5 # 0 +0xC4AB 0xCEB6 # 0 +0xC4AC 0xCEB7 # 0 +0xC4AD 0xCEB8 # 0 +0xC4AE 0xCEB9 # 0 +0xC4AF 0xCEBA # 0 +0xC4B0 0xCEBB # 0 +0xC4B1 0xCEBC # 0 +0xC4B3 0xCEBD # 0 +0xC4B4 0xCEBE # 0 +0xC4B5 0xCEBF # 0 +0xC4B6 0xCEC0 # 0 +0xC4B7 0xCEC1 # 0 +0xC4B8 0xCEC2 # 0 +0xC4B9 0xCEC3 # 0 +0xC4BA 0xCEC4 # 0 +0xC4BB 0xCEC5 # 0 +0xC4BC 0xCEC6 # 0 +0xC4BD 0xCEC7 # 0 +0xC4C1 0xCEC8 # 0 +0xC4C2 0xCEC9 # 0 +0xC4C3 0xCECA # 0 +0xC4C4 0xCECB # 0 +0xC4C5 0xCECC # 0 +0xC4C6 0xCECD # 0 +0xC4C7 0xCECE # 0 +0xC4C8 0xCECF # 0 +0xC4C9 0xCED0 # 0 +0xC4CA 0xCED1 # 0 +0xC4CB 0xCED2 # 0 +0xC4CC 0xCED3 # 0 +0xC4CD 0xCED4 # 0 +0xC4CE 0xCED5 # 0 +0xC4CF 0xCED6 # 0 +0xC4D0 0xCED7 # 0 +0xC4D1 0xCED8 # 0 +0xC4D3 0xCED9 # 0 +0xC4D4 0xCEDA # 0 +0xC4D5 0xCEDB # 0 +0xC4D6 0xCEDC # 0 +0xC4D7 0xCEDD # 0 +0xC4D8 0xCEDE # 0 +0xC4D9 0xCEDF # 0 +0xC4DA 0xCEE0 # 0 +0xC4DB 0xCEE1 # 0 +0xC4DC 0xCEE2 # 0 +0xC4DD 0xCEE3 # 0 +0xC4E1 0xCEE4 # 0 +0xC4E2 0xCEE5 # 0 +0xC4E3 0xCEE6 # 0 +0xC4E4 0xCEE7 # 0 +0xC4E5 0xCEE8 # 0 +0xC4E6 0xCEE9 # 0 +0xC4E7 0xCEEA # 0 +0xC4E8 0xCEEB # 0 +0xC4E9 0xCEEC # 0 +0xC4EA 0xCEED # 0 +0xC4EB 0xCEEE # 0 +0xC4EC 0xCEEF # 0 +0xC4ED 0xCEF0 # 0 +0xC4EE 0xCEF1 # 0 +0xC4EF 0xCEF2 # 0 +0xC4F0 0xCEF3 # 0 +0xC4F1 0xCEF4 # 0 +0xC4F3 0xCEF5 # 0 +0xC4F4 0xCEF6 # 0 +0xC4F5 0xCEF7 # 0 +0xC4F6 0xCEF8 # 0 +0xC4F7 0xCEF9 # 0 +0xC4F8 0xCEFA # 0 +0xC4F9 0xCEFB # 0 +0xC4FA 0xCEFC # 0 +0xC4FB 0xCEFD # 0 +0xC4FC 0xCEFE # 0 +0xC4FD 0xCEFF # 0 +0xC541 0xCF00 # 0 +0xC542 0xCF01 # 0 +0xC543 0xCF02 # 0 +0xC544 0xCF03 # 0 +0xC545 0xCF04 # 0 +0xC546 0xCF05 # 0 +0xC547 0xCF06 # 0 +0xC548 0xCF07 # 0 +0xC549 0xCF08 # 0 +0xC54A 0xCF09 # 0 +0xC54B 0xCF0A # 0 +0xC54C 0xCF0B # 0 +0xC54D 0xCF0C # 0 +0xC54E 0xCF0D # 0 +0xC54F 0xCF0E # 0 +0xC550 0xCF0F # 0 +0xC551 0xCF10 # 0 +0xC553 0xCF11 # 0 +0xC554 0xCF12 # 0 +0xC555 0xCF13 # 0 +0xC556 0xCF14 # 0 +0xC557 0xCF15 # 0 +0xC558 0xCF16 # 0 +0xC559 0xCF17 # 0 +0xC55A 0xCF18 # 0 +0xC55B 0xCF19 # 0 +0xC55C 0xCF1A # 0 +0xC55D 0xCF1B # 0 +0xC561 0xCF1C # 0 +0xC562 0xCF1D # 0 +0xC563 0xCF1E # 0 +0xC564 0xCF1F # 0 +0xC565 0xCF20 # 0 +0xC566 0xCF21 # 0 +0xC567 0xCF22 # 0 +0xC568 0xCF23 # 0 +0xC569 0xCF24 # 0 +0xC56A 0xCF25 # 0 +0xC56B 0xCF26 # 0 +0xC56C 0xCF27 # 0 +0xC56D 0xCF28 # 0 +0xC56E 0xCF29 # 0 +0xC56F 0xCF2A # 0 +0xC570 0xCF2B # 0 +0xC571 0xCF2C # 0 +0xC573 0xCF2D # 0 +0xC574 0xCF2E # 0 +0xC575 0xCF2F # 0 +0xC576 0xCF30 # 0 +0xC577 0xCF31 # 0 +0xC578 0xCF32 # 0 +0xC579 0xCF33 # 0 +0xC57A 0xCF34 # 0 +0xC57B 0xCF35 # 0 +0xC57C 0xCF36 # 0 +0xC57D 0xCF37 # 0 +0xC581 0xCF38 # 0 +0xC582 0xCF39 # 0 +0xC583 0xCF3A # 0 +0xC584 0xCF3B # 0 +0xC585 0xCF3C # 0 +0xC586 0xCF3D # 0 +0xC587 0xCF3E # 0 +0xC588 0xCF3F # 0 +0xC589 0xCF40 # 0 +0xC58A 0xCF41 # 0 +0xC58B 0xCF42 # 0 +0xC58C 0xCF43 # 0 +0xC58D 0xCF44 # 0 +0xC58E 0xCF45 # 0 +0xC58F 0xCF46 # 0 +0xC590 0xCF47 # 0 +0xC591 0xCF48 # 0 +0xC593 0xCF49 # 0 +0xC594 0xCF4A # 0 +0xC595 0xCF4B # 0 +0xC596 0xCF4C # 0 +0xC597 0xCF4D # 0 +0xC598 0xCF4E # 0 +0xC599 0xCF4F # 0 +0xC59A 0xCF50 # 0 +0xC59B 0xCF51 # 0 +0xC59C 0xCF52 # 0 +0xC59D 0xCF53 # 0 +0xC5A1 0xCF54 # 0 +0xC5A2 0xCF55 # 0 +0xC5A3 0xCF56 # 0 +0xC5A4 0xCF57 # 0 +0xC5A5 0xCF58 # 0 +0xC5A6 0xCF59 # 0 +0xC5A7 0xCF5A # 0 +0xC5A8 0xCF5B # 0 +0xC5A9 0xCF5C # 0 +0xC5AA 0xCF5D # 0 +0xC5AB 0xCF5E # 0 +0xC5AC 0xCF5F # 0 +0xC5AD 0xCF60 # 0 +0xC5AE 0xCF61 # 0 +0xC5AF 0xCF62 # 0 +0xC5B0 0xCF63 # 0 +0xC5B1 0xCF64 # 0 +0xC5B3 0xCF65 # 0 +0xC5B4 0xCF66 # 0 +0xC5B5 0xCF67 # 0 +0xC5B6 0xCF68 # 0 +0xC5B7 0xCF69 # 0 +0xC5B8 0xCF6A # 0 +0xC5B9 0xCF6B # 0 +0xC5BA 0xCF6C # 0 +0xC5BB 0xCF6D # 0 +0xC5BC 0xCF6E # 0 +0xC5BD 0xCF6F # 0 +0xC5C1 0xCF70 # 0 +0xC5C2 0xCF71 # 0 +0xC5C3 0xCF72 # 0 +0xC5C4 0xCF73 # 0 +0xC5C5 0xCF74 # 0 +0xC5C6 0xCF75 # 0 +0xC5C7 0xCF76 # 0 +0xC5C8 0xCF77 # 0 +0xC5C9 0xCF78 # 0 +0xC5CA 0xCF79 # 0 +0xC5CB 0xCF7A # 0 +0xC5CC 0xCF7B # 0 +0xC5CD 0xCF7C # 0 +0xC5CE 0xCF7D # 0 +0xC5CF 0xCF7E # 0 +0xC5D0 0xCF7F # 0 +0xC5D1 0xCF80 # 0 +0xC5D3 0xCF81 # 0 +0xC5D4 0xCF82 # 0 +0xC5D5 0xCF83 # 0 +0xC5D6 0xCF84 # 0 +0xC5D7 0xCF85 # 0 +0xC5D8 0xCF86 # 0 +0xC5D9 0xCF87 # 0 +0xC5DA 0xCF88 # 0 +0xC5DB 0xCF89 # 0 +0xC5DC 0xCF8A # 0 +0xC5DD 0xCF8B # 0 +0xC5E1 0xCF8C # 0 +0xC5E2 0xCF8D # 0 +0xC5E3 0xCF8E # 0 +0xC5E4 0xCF8F # 0 +0xC5E5 0xCF90 # 0 +0xC5E6 0xCF91 # 0 +0xC5E7 0xCF92 # 0 +0xC5E8 0xCF93 # 0 +0xC5E9 0xCF94 # 0 +0xC5EA 0xCF95 # 0 +0xC5EB 0xCF96 # 0 +0xC5EC 0xCF97 # 0 +0xC5ED 0xCF98 # 0 +0xC5EE 0xCF99 # 0 +0xC5EF 0xCF9A # 0 +0xC5F0 0xCF9B # 0 +0xC5F1 0xCF9C # 0 +0xC5F3 0xCF9D # 0 +0xC5F4 0xCF9E # 0 +0xC5F5 0xCF9F # 0 +0xC5F6 0xCFA0 # 0 +0xC5F7 0xCFA1 # 0 +0xC5F8 0xCFA2 # 0 +0xC5F9 0xCFA3 # 0 +0xC5FA 0xCFA4 # 0 +0xC5FB 0xCFA5 # 0 +0xC5FC 0xCFA6 # 0 +0xC5FD 0xCFA7 # 0 +0xC641 0xCFA8 # 0 +0xC642 0xCFA9 # 0 +0xC643 0xCFAA # 0 +0xC644 0xCFAB # 0 +0xC645 0xCFAC # 0 +0xC646 0xCFAD # 0 +0xC647 0xCFAE # 0 +0xC648 0xCFAF # 0 +0xC649 0xCFB0 # 0 +0xC64A 0xCFB1 # 0 +0xC64B 0xCFB2 # 0 +0xC64C 0xCFB3 # 0 +0xC64D 0xCFB4 # 0 +0xC64E 0xCFB5 # 0 +0xC64F 0xCFB6 # 0 +0xC650 0xCFB7 # 0 +0xC651 0xCFB8 # 0 +0xC653 0xCFB9 # 0 +0xC654 0xCFBA # 0 +0xC655 0xCFBB # 0 +0xC656 0xCFBC # 0 +0xC657 0xCFBD # 0 +0xC658 0xCFBE # 0 +0xC659 0xCFBF # 0 +0xC65A 0xCFC0 # 0 +0xC65B 0xCFC1 # 0 +0xC65C 0xCFC2 # 0 +0xC65D 0xCFC3 # 0 +0xC661 0xCFC4 # 0 +0xC662 0xCFC5 # 0 +0xC663 0xCFC6 # 0 +0xC664 0xCFC7 # 0 +0xC665 0xCFC8 # 0 +0xC666 0xCFC9 # 0 +0xC667 0xCFCA # 0 +0xC668 0xCFCB # 0 +0xC669 0xCFCC # 0 +0xC66A 0xCFCD # 0 +0xC66B 0xCFCE # 0 +0xC66C 0xCFCF # 0 +0xC66D 0xCFD0 # 0 +0xC66E 0xCFD1 # 0 +0xC66F 0xCFD2 # 0 +0xC670 0xCFD3 # 0 +0xC671 0xCFD4 # 0 +0xC673 0xCFD5 # 0 +0xC674 0xCFD6 # 0 +0xC675 0xCFD7 # 0 +0xC676 0xCFD8 # 0 +0xC677 0xCFD9 # 0 +0xC678 0xCFDA # 0 +0xC679 0xCFDB # 0 +0xC67A 0xCFDC # 0 +0xC67B 0xCFDD # 0 +0xC67C 0xCFDE # 0 +0xC67D 0xCFDF # 0 +0xC681 0xCFE0 # 0 +0xC682 0xCFE1 # 0 +0xC683 0xCFE2 # 0 +0xC684 0xCFE3 # 0 +0xC685 0xCFE4 # 0 +0xC686 0xCFE5 # 0 +0xC687 0xCFE6 # 0 +0xC688 0xCFE7 # 0 +0xC689 0xCFE8 # 0 +0xC68A 0xCFE9 # 0 +0xC68B 0xCFEA # 0 +0xC68C 0xCFEB # 0 +0xC68D 0xCFEC # 0 +0xC68E 0xCFED # 0 +0xC68F 0xCFEE # 0 +0xC690 0xCFEF # 0 +0xC691 0xCFF0 # 0 +0xC693 0xCFF1 # 0 +0xC694 0xCFF2 # 0 +0xC695 0xCFF3 # 0 +0xC696 0xCFF4 # 0 +0xC697 0xCFF5 # 0 +0xC698 0xCFF6 # 0 +0xC699 0xCFF7 # 0 +0xC69A 0xCFF8 # 0 +0xC69B 0xCFF9 # 0 +0xC69C 0xCFFA # 0 +0xC69D 0xCFFB # 0 +0xC6A1 0xCFFC # 0 +0xC6A2 0xCFFD # 0 +0xC6A3 0xCFFE # 0 +0xC6A4 0xCFFF # 0 +0xC6A5 0xD000 # 0 +0xC6A6 0xD001 # 0 +0xC6A7 0xD002 # 0 +0xC6A8 0xD003 # 0 +0xC6A9 0xD004 # 0 +0xC6AA 0xD005 # 0 +0xC6AB 0xD006 # 0 +0xC6AC 0xD007 # 0 +0xC6AD 0xD008 # 0 +0xC6AE 0xD009 # 0 +0xC6AF 0xD00A # 0 +0xC6B0 0xD00B # 0 +0xC6B1 0xD00C # 0 +0xC6B3 0xD00D # 0 +0xC6B4 0xD00E # 0 +0xC6B5 0xD00F # 0 +0xC6B6 0xD010 # 0 +0xC6B7 0xD011 # 0 +0xC6B8 0xD012 # 0 +0xC6B9 0xD013 # 0 +0xC6BA 0xD014 # 0 +0xC6BB 0xD015 # 0 +0xC6BC 0xD016 # 0 +0xC6BD 0xD017 # 0 +0xC6C1 0xD018 # 0 +0xC6C2 0xD019 # 0 +0xC6C3 0xD01A # 0 +0xC6C4 0xD01B # 0 +0xC6C5 0xD01C # 0 +0xC6C6 0xD01D # 0 +0xC6C7 0xD01E # 0 +0xC6C8 0xD01F # 0 +0xC6C9 0xD020 # 0 +0xC6CA 0xD021 # 0 +0xC6CB 0xD022 # 0 +0xC6CC 0xD023 # 0 +0xC6CD 0xD024 # 0 +0xC6CE 0xD025 # 0 +0xC6CF 0xD026 # 0 +0xC6D0 0xD027 # 0 +0xC6D1 0xD028 # 0 +0xC6D3 0xD029 # 0 +0xC6D4 0xD02A # 0 +0xC6D5 0xD02B # 0 +0xC6D6 0xD02C # 0 +0xC6D7 0xD02D # 0 +0xC6D8 0xD02E # 0 +0xC6D9 0xD02F # 0 +0xC6DA 0xD030 # 0 +0xC6DB 0xD031 # 0 +0xC6DC 0xD032 # 0 +0xC6DD 0xD033 # 0 +0xC6E1 0xD034 # 0 +0xC6E2 0xD035 # 0 +0xC6E3 0xD036 # 0 +0xC6E4 0xD037 # 0 +0xC6E5 0xD038 # 0 +0xC6E6 0xD039 # 0 +0xC6E7 0xD03A # 0 +0xC6E8 0xD03B # 0 +0xC6E9 0xD03C # 0 +0xC6EA 0xD03D # 0 +0xC6EB 0xD03E # 0 +0xC6EC 0xD03F # 0 +0xC6ED 0xD040 # 0 +0xC6EE 0xD041 # 0 +0xC6EF 0xD042 # 0 +0xC6F0 0xD043 # 0 +0xC6F1 0xD044 # 0 +0xC6F3 0xD045 # 0 +0xC6F4 0xD046 # 0 +0xC6F5 0xD047 # 0 +0xC6F6 0xD048 # 0 +0xC6F7 0xD049 # 0 +0xC6F8 0xD04A # 0 +0xC6F9 0xD04B # 0 +0xC6FA 0xD04C # 0 +0xC6FB 0xD04D # 0 +0xC6FC 0xD04E # 0 +0xC6FD 0xD04F # 0 +0xC741 0xD050 # 0 +0xC742 0xD051 # 0 +0xC743 0xD052 # 0 +0xC744 0xD053 # 0 +0xC745 0xD054 # 0 +0xC746 0xD055 # 0 +0xC747 0xD056 # 0 +0xC748 0xD057 # 0 +0xC749 0xD058 # 0 +0xC74A 0xD059 # 0 +0xC74B 0xD05A # 0 +0xC74C 0xD05B # 0 +0xC74D 0xD05C # 0 +0xC74E 0xD05D # 0 +0xC74F 0xD05E # 0 +0xC750 0xD05F # 0 +0xC751 0xD060 # 0 +0xC753 0xD061 # 0 +0xC754 0xD062 # 0 +0xC755 0xD063 # 0 +0xC756 0xD064 # 0 +0xC757 0xD065 # 0 +0xC758 0xD066 # 0 +0xC759 0xD067 # 0 +0xC75A 0xD068 # 0 +0xC75B 0xD069 # 0 +0xC75C 0xD06A # 0 +0xC75D 0xD06B # 0 +0xC761 0xD06C # 0 +0xC762 0xD06D # 0 +0xC763 0xD06E # 0 +0xC764 0xD06F # 0 +0xC765 0xD070 # 0 +0xC766 0xD071 # 0 +0xC767 0xD072 # 0 +0xC768 0xD073 # 0 +0xC769 0xD074 # 0 +0xC76A 0xD075 # 0 +0xC76B 0xD076 # 0 +0xC76C 0xD077 # 0 +0xC76D 0xD078 # 0 +0xC76E 0xD079 # 0 +0xC76F 0xD07A # 0 +0xC770 0xD07B # 0 +0xC771 0xD07C # 0 +0xC773 0xD07D # 0 +0xC774 0xD07E # 0 +0xC775 0xD07F # 0 +0xC776 0xD080 # 0 +0xC777 0xD081 # 0 +0xC778 0xD082 # 0 +0xC779 0xD083 # 0 +0xC77A 0xD084 # 0 +0xC77B 0xD085 # 0 +0xC77C 0xD086 # 0 +0xC77D 0xD087 # 0 +0xC781 0xD088 # 0 +0xC782 0xD089 # 0 +0xC783 0xD08A # 0 +0xC784 0xD08B # 0 +0xC785 0xD08C # 0 +0xC786 0xD08D # 0 +0xC787 0xD08E # 0 +0xC788 0xD08F # 0 +0xC789 0xD090 # 0 +0xC78A 0xD091 # 0 +0xC78B 0xD092 # 0 +0xC78C 0xD093 # 0 +0xC78D 0xD094 # 0 +0xC78E 0xD095 # 0 +0xC78F 0xD096 # 0 +0xC790 0xD097 # 0 +0xC791 0xD098 # 0 +0xC793 0xD099 # 0 +0xC794 0xD09A # 0 +0xC795 0xD09B # 0 +0xC796 0xD09C # 0 +0xC797 0xD09D # 0 +0xC798 0xD09E # 0 +0xC799 0xD09F # 0 +0xC79A 0xD0A0 # 0 +0xC79B 0xD0A1 # 0 +0xC79C 0xD0A2 # 0 +0xC79D 0xD0A3 # 0 +0xC7A1 0xD0A4 # 0 +0xC7A2 0xD0A5 # 0 +0xC7A3 0xD0A6 # 0 +0xC7A4 0xD0A7 # 0 +0xC7A5 0xD0A8 # 0 +0xC7A6 0xD0A9 # 0 +0xC7A7 0xD0AA # 0 +0xC7A8 0xD0AB # 0 +0xC7A9 0xD0AC # 0 +0xC7AA 0xD0AD # 0 +0xC7AB 0xD0AE # 0 +0xC7AC 0xD0AF # 0 +0xC7AD 0xD0B0 # 0 +0xC7AE 0xD0B1 # 0 +0xC7AF 0xD0B2 # 0 +0xC7B0 0xD0B3 # 0 +0xC7B1 0xD0B4 # 0 +0xC7B3 0xD0B5 # 0 +0xC7B4 0xD0B6 # 0 +0xC7B5 0xD0B7 # 0 +0xC7B6 0xD0B8 # 0 +0xC7B7 0xD0B9 # 0 +0xC7B8 0xD0BA # 0 +0xC7B9 0xD0BB # 0 +0xC7BA 0xD0BC # 0 +0xC7BB 0xD0BD # 0 +0xC7BC 0xD0BE # 0 +0xC7BD 0xD0BF # 0 +0xC841 0x1110 # 0 +0xC861 0xD0C0 # 0 +0xC862 0xD0C1 # 0 +0xC863 0xD0C2 # 0 +0xC864 0xD0C3 # 0 +0xC865 0xD0C4 # 0 +0xC866 0xD0C5 # 0 +0xC867 0xD0C6 # 0 +0xC868 0xD0C7 # 0 +0xC869 0xD0C8 # 0 +0xC86A 0xD0C9 # 0 +0xC86B 0xD0CA # 0 +0xC86C 0xD0CB # 0 +0xC86D 0xD0CC # 0 +0xC86E 0xD0CD # 0 +0xC86F 0xD0CE # 0 +0xC870 0xD0CF # 0 +0xC871 0xD0D0 # 0 +0xC873 0xD0D1 # 0 +0xC874 0xD0D2 # 0 +0xC875 0xD0D3 # 0 +0xC876 0xD0D4 # 0 +0xC877 0xD0D5 # 0 +0xC878 0xD0D6 # 0 +0xC879 0xD0D7 # 0 +0xC87A 0xD0D8 # 0 +0xC87B 0xD0D9 # 0 +0xC87C 0xD0DA # 0 +0xC87D 0xD0DB # 0 +0xC881 0xD0DC # 0 +0xC882 0xD0DD # 0 +0xC883 0xD0DE # 0 +0xC884 0xD0DF # 0 +0xC885 0xD0E0 # 0 +0xC886 0xD0E1 # 0 +0xC887 0xD0E2 # 0 +0xC888 0xD0E3 # 0 +0xC889 0xD0E4 # 0 +0xC88A 0xD0E5 # 0 +0xC88B 0xD0E6 # 0 +0xC88C 0xD0E7 # 0 +0xC88D 0xD0E8 # 0 +0xC88E 0xD0E9 # 0 +0xC88F 0xD0EA # 0 +0xC890 0xD0EB # 0 +0xC891 0xD0EC # 0 +0xC893 0xD0ED # 0 +0xC894 0xD0EE # 0 +0xC895 0xD0EF # 0 +0xC896 0xD0F0 # 0 +0xC897 0xD0F1 # 0 +0xC898 0xD0F2 # 0 +0xC899 0xD0F3 # 0 +0xC89A 0xD0F4 # 0 +0xC89B 0xD0F5 # 0 +0xC89C 0xD0F6 # 0 +0xC89D 0xD0F7 # 0 +0xC8A1 0xD0F8 # 0 +0xC8A2 0xD0F9 # 0 +0xC8A3 0xD0FA # 0 +0xC8A4 0xD0FB # 0 +0xC8A5 0xD0FC # 0 +0xC8A6 0xD0FD # 0 +0xC8A7 0xD0FE # 0 +0xC8A8 0xD0FF # 0 +0xC8A9 0xD100 # 0 +0xC8AA 0xD101 # 0 +0xC8AB 0xD102 # 0 +0xC8AC 0xD103 # 0 +0xC8AD 0xD104 # 0 +0xC8AE 0xD105 # 0 +0xC8AF 0xD106 # 0 +0xC8B0 0xD107 # 0 +0xC8B1 0xD108 # 0 +0xC8B3 0xD109 # 0 +0xC8B4 0xD10A # 0 +0xC8B5 0xD10B # 0 +0xC8B6 0xD10C # 0 +0xC8B7 0xD10D # 0 +0xC8B8 0xD10E # 0 +0xC8B9 0xD10F # 0 +0xC8BA 0xD110 # 0 +0xC8BB 0xD111 # 0 +0xC8BC 0xD112 # 0 +0xC8BD 0xD113 # 0 +0xC8C1 0xD114 # 0 +0xC8C2 0xD115 # 0 +0xC8C3 0xD116 # 0 +0xC8C4 0xD117 # 0 +0xC8C5 0xD118 # 0 +0xC8C6 0xD119 # 0 +0xC8C7 0xD11A # 0 +0xC8C8 0xD11B # 0 +0xC8C9 0xD11C # 0 +0xC8CA 0xD11D # 0 +0xC8CB 0xD11E # 0 +0xC8CC 0xD11F # 0 +0xC8CD 0xD120 # 0 +0xC8CE 0xD121 # 0 +0xC8CF 0xD122 # 0 +0xC8D0 0xD123 # 0 +0xC8D1 0xD124 # 0 +0xC8D3 0xD125 # 0 +0xC8D4 0xD126 # 0 +0xC8D5 0xD127 # 0 +0xC8D6 0xD128 # 0 +0xC8D7 0xD129 # 0 +0xC8D8 0xD12A # 0 +0xC8D9 0xD12B # 0 +0xC8DA 0xD12C # 0 +0xC8DB 0xD12D # 0 +0xC8DC 0xD12E # 0 +0xC8DD 0xD12F # 0 +0xC8E1 0xD130 # 0 +0xC8E2 0xD131 # 0 +0xC8E3 0xD132 # 0 +0xC8E4 0xD133 # 0 +0xC8E5 0xD134 # 0 +0xC8E6 0xD135 # 0 +0xC8E7 0xD136 # 0 +0xC8E8 0xD137 # 0 +0xC8E9 0xD138 # 0 +0xC8EA 0xD139 # 0 +0xC8EB 0xD13A # 0 +0xC8EC 0xD13B # 0 +0xC8ED 0xD13C # 0 +0xC8EE 0xD13D # 0 +0xC8EF 0xD13E # 0 +0xC8F0 0xD13F # 0 +0xC8F1 0xD140 # 0 +0xC8F3 0xD141 # 0 +0xC8F4 0xD142 # 0 +0xC8F5 0xD143 # 0 +0xC8F6 0xD144 # 0 +0xC8F7 0xD145 # 0 +0xC8F8 0xD146 # 0 +0xC8F9 0xD147 # 0 +0xC8FA 0xD148 # 0 +0xC8FB 0xD149 # 0 +0xC8FC 0xD14A # 0 +0xC8FD 0xD14B # 0 +0xC941 0xD14C # 0 +0xC942 0xD14D # 0 +0xC943 0xD14E # 0 +0xC944 0xD14F # 0 +0xC945 0xD150 # 0 +0xC946 0xD151 # 0 +0xC947 0xD152 # 0 +0xC948 0xD153 # 0 +0xC949 0xD154 # 0 +0xC94A 0xD155 # 0 +0xC94B 0xD156 # 0 +0xC94C 0xD157 # 0 +0xC94D 0xD158 # 0 +0xC94E 0xD159 # 0 +0xC94F 0xD15A # 0 +0xC950 0xD15B # 0 +0xC951 0xD15C # 0 +0xC953 0xD15D # 0 +0xC954 0xD15E # 0 +0xC955 0xD15F # 0 +0xC956 0xD160 # 0 +0xC957 0xD161 # 0 +0xC958 0xD162 # 0 +0xC959 0xD163 # 0 +0xC95A 0xD164 # 0 +0xC95B 0xD165 # 0 +0xC95C 0xD166 # 0 +0xC95D 0xD167 # 0 +0xC961 0xD168 # 0 +0xC962 0xD169 # 0 +0xC963 0xD16A # 0 +0xC964 0xD16B # 0 +0xC965 0xD16C # 0 +0xC966 0xD16D # 0 +0xC967 0xD16E # 0 +0xC968 0xD16F # 0 +0xC969 0xD170 # 0 +0xC96A 0xD171 # 0 +0xC96B 0xD172 # 0 +0xC96C 0xD173 # 0 +0xC96D 0xD174 # 0 +0xC96E 0xD175 # 0 +0xC96F 0xD176 # 0 +0xC970 0xD177 # 0 +0xC971 0xD178 # 0 +0xC973 0xD179 # 0 +0xC974 0xD17A # 0 +0xC975 0xD17B # 0 +0xC976 0xD17C # 0 +0xC977 0xD17D # 0 +0xC978 0xD17E # 0 +0xC979 0xD17F # 0 +0xC97A 0xD180 # 0 +0xC97B 0xD181 # 0 +0xC97C 0xD182 # 0 +0xC97D 0xD183 # 0 +0xC981 0xD184 # 0 +0xC982 0xD185 # 0 +0xC983 0xD186 # 0 +0xC984 0xD187 # 0 +0xC985 0xD188 # 0 +0xC986 0xD189 # 0 +0xC987 0xD18A # 0 +0xC988 0xD18B # 0 +0xC989 0xD18C # 0 +0xC98A 0xD18D # 0 +0xC98B 0xD18E # 0 +0xC98C 0xD18F # 0 +0xC98D 0xD190 # 0 +0xC98E 0xD191 # 0 +0xC98F 0xD192 # 0 +0xC990 0xD193 # 0 +0xC991 0xD194 # 0 +0xC993 0xD195 # 0 +0xC994 0xD196 # 0 +0xC995 0xD197 # 0 +0xC996 0xD198 # 0 +0xC997 0xD199 # 0 +0xC998 0xD19A # 0 +0xC999 0xD19B # 0 +0xC99A 0xD19C # 0 +0xC99B 0xD19D # 0 +0xC99C 0xD19E # 0 +0xC99D 0xD19F # 0 +0xC9A1 0xD1A0 # 0 +0xC9A2 0xD1A1 # 0 +0xC9A3 0xD1A2 # 0 +0xC9A4 0xD1A3 # 0 +0xC9A5 0xD1A4 # 0 +0xC9A6 0xD1A5 # 0 +0xC9A7 0xD1A6 # 0 +0xC9A8 0xD1A7 # 0 +0xC9A9 0xD1A8 # 0 +0xC9AA 0xD1A9 # 0 +0xC9AB 0xD1AA # 0 +0xC9AC 0xD1AB # 0 +0xC9AD 0xD1AC # 0 +0xC9AE 0xD1AD # 0 +0xC9AF 0xD1AE # 0 +0xC9B0 0xD1AF # 0 +0xC9B1 0xD1B0 # 0 +0xC9B3 0xD1B1 # 0 +0xC9B4 0xD1B2 # 0 +0xC9B5 0xD1B3 # 0 +0xC9B6 0xD1B4 # 0 +0xC9B7 0xD1B5 # 0 +0xC9B8 0xD1B6 # 0 +0xC9B9 0xD1B7 # 0 +0xC9BA 0xD1B8 # 0 +0xC9BB 0xD1B9 # 0 +0xC9BC 0xD1BA # 0 +0xC9BD 0xD1BB # 0 +0xC9C1 0xD1BC # 0 +0xC9C2 0xD1BD # 0 +0xC9C3 0xD1BE # 0 +0xC9C4 0xD1BF # 0 +0xC9C5 0xD1C0 # 0 +0xC9C6 0xD1C1 # 0 +0xC9C7 0xD1C2 # 0 +0xC9C8 0xD1C3 # 0 +0xC9C9 0xD1C4 # 0 +0xC9CA 0xD1C5 # 0 +0xC9CB 0xD1C6 # 0 +0xC9CC 0xD1C7 # 0 +0xC9CD 0xD1C8 # 0 +0xC9CE 0xD1C9 # 0 +0xC9CF 0xD1CA # 0 +0xC9D0 0xD1CB # 0 +0xC9D1 0xD1CC # 0 +0xC9D3 0xD1CD # 0 +0xC9D4 0xD1CE # 0 +0xC9D5 0xD1CF # 0 +0xC9D6 0xD1D0 # 0 +0xC9D7 0xD1D1 # 0 +0xC9D8 0xD1D2 # 0 +0xC9D9 0xD1D3 # 0 +0xC9DA 0xD1D4 # 0 +0xC9DB 0xD1D5 # 0 +0xC9DC 0xD1D6 # 0 +0xC9DD 0xD1D7 # 0 +0xC9E1 0xD1D8 # 0 +0xC9E2 0xD1D9 # 0 +0xC9E3 0xD1DA # 0 +0xC9E4 0xD1DB # 0 +0xC9E5 0xD1DC # 0 +0xC9E6 0xD1DD # 0 +0xC9E7 0xD1DE # 0 +0xC9E8 0xD1DF # 0 +0xC9E9 0xD1E0 # 0 +0xC9EA 0xD1E1 # 0 +0xC9EB 0xD1E2 # 0 +0xC9EC 0xD1E3 # 0 +0xC9ED 0xD1E4 # 0 +0xC9EE 0xD1E5 # 0 +0xC9EF 0xD1E6 # 0 +0xC9F0 0xD1E7 # 0 +0xC9F1 0xD1E8 # 0 +0xC9F3 0xD1E9 # 0 +0xC9F4 0xD1EA # 0 +0xC9F5 0xD1EB # 0 +0xC9F6 0xD1EC # 0 +0xC9F7 0xD1ED # 0 +0xC9F8 0xD1EE # 0 +0xC9F9 0xD1EF # 0 +0xC9FA 0xD1F0 # 0 +0xC9FB 0xD1F1 # 0 +0xC9FC 0xD1F2 # 0 +0xC9FD 0xD1F3 # 0 +0xCA41 0xD1F4 # 0 +0xCA42 0xD1F5 # 0 +0xCA43 0xD1F6 # 0 +0xCA44 0xD1F7 # 0 +0xCA45 0xD1F8 # 0 +0xCA46 0xD1F9 # 0 +0xCA47 0xD1FA # 0 +0xCA48 0xD1FB # 0 +0xCA49 0xD1FC # 0 +0xCA4A 0xD1FD # 0 +0xCA4B 0xD1FE # 0 +0xCA4C 0xD1FF # 0 +0xCA4D 0xD200 # 0 +0xCA4E 0xD201 # 0 +0xCA4F 0xD202 # 0 +0xCA50 0xD203 # 0 +0xCA51 0xD204 # 0 +0xCA53 0xD205 # 0 +0xCA54 0xD206 # 0 +0xCA55 0xD207 # 0 +0xCA56 0xD208 # 0 +0xCA57 0xD209 # 0 +0xCA58 0xD20A # 0 +0xCA59 0xD20B # 0 +0xCA5A 0xD20C # 0 +0xCA5B 0xD20D # 0 +0xCA5C 0xD20E # 0 +0xCA5D 0xD20F # 0 +0xCA61 0xD210 # 0 +0xCA62 0xD211 # 0 +0xCA63 0xD212 # 0 +0xCA64 0xD213 # 0 +0xCA65 0xD214 # 0 +0xCA66 0xD215 # 0 +0xCA67 0xD216 # 0 +0xCA68 0xD217 # 0 +0xCA69 0xD218 # 0 +0xCA6A 0xD219 # 0 +0xCA6B 0xD21A # 0 +0xCA6C 0xD21B # 0 +0xCA6D 0xD21C # 0 +0xCA6E 0xD21D # 0 +0xCA6F 0xD21E # 0 +0xCA70 0xD21F # 0 +0xCA71 0xD220 # 0 +0xCA73 0xD221 # 0 +0xCA74 0xD222 # 0 +0xCA75 0xD223 # 0 +0xCA76 0xD224 # 0 +0xCA77 0xD225 # 0 +0xCA78 0xD226 # 0 +0xCA79 0xD227 # 0 +0xCA7A 0xD228 # 0 +0xCA7B 0xD229 # 0 +0xCA7C 0xD22A # 0 +0xCA7D 0xD22B # 0 +0xCA81 0xD22C # 0 +0xCA82 0xD22D # 0 +0xCA83 0xD22E # 0 +0xCA84 0xD22F # 0 +0xCA85 0xD230 # 0 +0xCA86 0xD231 # 0 +0xCA87 0xD232 # 0 +0xCA88 0xD233 # 0 +0xCA89 0xD234 # 0 +0xCA8A 0xD235 # 0 +0xCA8B 0xD236 # 0 +0xCA8C 0xD237 # 0 +0xCA8D 0xD238 # 0 +0xCA8E 0xD239 # 0 +0xCA8F 0xD23A # 0 +0xCA90 0xD23B # 0 +0xCA91 0xD23C # 0 +0xCA93 0xD23D # 0 +0xCA94 0xD23E # 0 +0xCA95 0xD23F # 0 +0xCA96 0xD240 # 0 +0xCA97 0xD241 # 0 +0xCA98 0xD242 # 0 +0xCA99 0xD243 # 0 +0xCA9A 0xD244 # 0 +0xCA9B 0xD245 # 0 +0xCA9C 0xD246 # 0 +0xCA9D 0xD247 # 0 +0xCAA1 0xD248 # 0 +0xCAA2 0xD249 # 0 +0xCAA3 0xD24A # 0 +0xCAA4 0xD24B # 0 +0xCAA5 0xD24C # 0 +0xCAA6 0xD24D # 0 +0xCAA7 0xD24E # 0 +0xCAA8 0xD24F # 0 +0xCAA9 0xD250 # 0 +0xCAAA 0xD251 # 0 +0xCAAB 0xD252 # 0 +0xCAAC 0xD253 # 0 +0xCAAD 0xD254 # 0 +0xCAAE 0xD255 # 0 +0xCAAF 0xD256 # 0 +0xCAB0 0xD257 # 0 +0xCAB1 0xD258 # 0 +0xCAB3 0xD259 # 0 +0xCAB4 0xD25A # 0 +0xCAB5 0xD25B # 0 +0xCAB6 0xD25C # 0 +0xCAB7 0xD25D # 0 +0xCAB8 0xD25E # 0 +0xCAB9 0xD25F # 0 +0xCABA 0xD260 # 0 +0xCABB 0xD261 # 0 +0xCABC 0xD262 # 0 +0xCABD 0xD263 # 0 +0xCAC1 0xD264 # 0 +0xCAC2 0xD265 # 0 +0xCAC3 0xD266 # 0 +0xCAC4 0xD267 # 0 +0xCAC5 0xD268 # 0 +0xCAC6 0xD269 # 0 +0xCAC7 0xD26A # 0 +0xCAC8 0xD26B # 0 +0xCAC9 0xD26C # 0 +0xCACA 0xD26D # 0 +0xCACB 0xD26E # 0 +0xCACC 0xD26F # 0 +0xCACD 0xD270 # 0 +0xCACE 0xD271 # 0 +0xCACF 0xD272 # 0 +0xCAD0 0xD273 # 0 +0xCAD1 0xD274 # 0 +0xCAD3 0xD275 # 0 +0xCAD4 0xD276 # 0 +0xCAD5 0xD277 # 0 +0xCAD6 0xD278 # 0 +0xCAD7 0xD279 # 0 +0xCAD8 0xD27A # 0 +0xCAD9 0xD27B # 0 +0xCADA 0xD27C # 0 +0xCADB 0xD27D # 0 +0xCADC 0xD27E # 0 +0xCADD 0xD27F # 0 +0xCAE1 0xD280 # 0 +0xCAE2 0xD281 # 0 +0xCAE3 0xD282 # 0 +0xCAE4 0xD283 # 0 +0xCAE5 0xD284 # 0 +0xCAE6 0xD285 # 0 +0xCAE7 0xD286 # 0 +0xCAE8 0xD287 # 0 +0xCAE9 0xD288 # 0 +0xCAEA 0xD289 # 0 +0xCAEB 0xD28A # 0 +0xCAEC 0xD28B # 0 +0xCAED 0xD28C # 0 +0xCAEE 0xD28D # 0 +0xCAEF 0xD28E # 0 +0xCAF0 0xD28F # 0 +0xCAF1 0xD290 # 0 +0xCAF3 0xD291 # 0 +0xCAF4 0xD292 # 0 +0xCAF5 0xD293 # 0 +0xCAF6 0xD294 # 0 +0xCAF7 0xD295 # 0 +0xCAF8 0xD296 # 0 +0xCAF9 0xD297 # 0 +0xCAFA 0xD298 # 0 +0xCAFB 0xD299 # 0 +0xCAFC 0xD29A # 0 +0xCAFD 0xD29B # 0 +0xCB41 0xD29C # 0 +0xCB42 0xD29D # 0 +0xCB43 0xD29E # 0 +0xCB44 0xD29F # 0 +0xCB45 0xD2A0 # 0 +0xCB46 0xD2A1 # 0 +0xCB47 0xD2A2 # 0 +0xCB48 0xD2A3 # 0 +0xCB49 0xD2A4 # 0 +0xCB4A 0xD2A5 # 0 +0xCB4B 0xD2A6 # 0 +0xCB4C 0xD2A7 # 0 +0xCB4D 0xD2A8 # 0 +0xCB4E 0xD2A9 # 0 +0xCB4F 0xD2AA # 0 +0xCB50 0xD2AB # 0 +0xCB51 0xD2AC # 0 +0xCB53 0xD2AD # 0 +0xCB54 0xD2AE # 0 +0xCB55 0xD2AF # 0 +0xCB56 0xD2B0 # 0 +0xCB57 0xD2B1 # 0 +0xCB58 0xD2B2 # 0 +0xCB59 0xD2B3 # 0 +0xCB5A 0xD2B4 # 0 +0xCB5B 0xD2B5 # 0 +0xCB5C 0xD2B6 # 0 +0xCB5D 0xD2B7 # 0 +0xCB61 0xD2B8 # 0 +0xCB62 0xD2B9 # 0 +0xCB63 0xD2BA # 0 +0xCB64 0xD2BB # 0 +0xCB65 0xD2BC # 0 +0xCB66 0xD2BD # 0 +0xCB67 0xD2BE # 0 +0xCB68 0xD2BF # 0 +0xCB69 0xD2C0 # 0 +0xCB6A 0xD2C1 # 0 +0xCB6B 0xD2C2 # 0 +0xCB6C 0xD2C3 # 0 +0xCB6D 0xD2C4 # 0 +0xCB6E 0xD2C5 # 0 +0xCB6F 0xD2C6 # 0 +0xCB70 0xD2C7 # 0 +0xCB71 0xD2C8 # 0 +0xCB73 0xD2C9 # 0 +0xCB74 0xD2CA # 0 +0xCB75 0xD2CB # 0 +0xCB76 0xD2CC # 0 +0xCB77 0xD2CD # 0 +0xCB78 0xD2CE # 0 +0xCB79 0xD2CF # 0 +0xCB7A 0xD2D0 # 0 +0xCB7B 0xD2D1 # 0 +0xCB7C 0xD2D2 # 0 +0xCB7D 0xD2D3 # 0 +0xCB81 0xD2D4 # 0 +0xCB82 0xD2D5 # 0 +0xCB83 0xD2D6 # 0 +0xCB84 0xD2D7 # 0 +0xCB85 0xD2D8 # 0 +0xCB86 0xD2D9 # 0 +0xCB87 0xD2DA # 0 +0xCB88 0xD2DB # 0 +0xCB89 0xD2DC # 0 +0xCB8A 0xD2DD # 0 +0xCB8B 0xD2DE # 0 +0xCB8C 0xD2DF # 0 +0xCB8D 0xD2E0 # 0 +0xCB8E 0xD2E1 # 0 +0xCB8F 0xD2E2 # 0 +0xCB90 0xD2E3 # 0 +0xCB91 0xD2E4 # 0 +0xCB93 0xD2E5 # 0 +0xCB94 0xD2E6 # 0 +0xCB95 0xD2E7 # 0 +0xCB96 0xD2E8 # 0 +0xCB97 0xD2E9 # 0 +0xCB98 0xD2EA # 0 +0xCB99 0xD2EB # 0 +0xCB9A 0xD2EC # 0 +0xCB9B 0xD2ED # 0 +0xCB9C 0xD2EE # 0 +0xCB9D 0xD2EF # 0 +0xCBA1 0xD2F0 # 0 +0xCBA2 0xD2F1 # 0 +0xCBA3 0xD2F2 # 0 +0xCBA4 0xD2F3 # 0 +0xCBA5 0xD2F4 # 0 +0xCBA6 0xD2F5 # 0 +0xCBA7 0xD2F6 # 0 +0xCBA8 0xD2F7 # 0 +0xCBA9 0xD2F8 # 0 +0xCBAA 0xD2F9 # 0 +0xCBAB 0xD2FA # 0 +0xCBAC 0xD2FB # 0 +0xCBAD 0xD2FC # 0 +0xCBAE 0xD2FD # 0 +0xCBAF 0xD2FE # 0 +0xCBB0 0xD2FF # 0 +0xCBB1 0xD300 # 0 +0xCBB3 0xD301 # 0 +0xCBB4 0xD302 # 0 +0xCBB5 0xD303 # 0 +0xCBB6 0xD304 # 0 +0xCBB7 0xD305 # 0 +0xCBB8 0xD306 # 0 +0xCBB9 0xD307 # 0 +0xCBBA 0xD308 # 0 +0xCBBB 0xD309 # 0 +0xCBBC 0xD30A # 0 +0xCBBD 0xD30B # 0 +0xCC41 0x1111 # 0 +0xCC61 0xD30C # 0 +0xCC62 0xD30D # 0 +0xCC63 0xD30E # 0 +0xCC64 0xD30F # 0 +0xCC65 0xD310 # 0 +0xCC66 0xD311 # 0 +0xCC67 0xD312 # 0 +0xCC68 0xD313 # 0 +0xCC69 0xD314 # 0 +0xCC6A 0xD315 # 0 +0xCC6B 0xD316 # 0 +0xCC6C 0xD317 # 0 +0xCC6D 0xD318 # 0 +0xCC6E 0xD319 # 0 +0xCC6F 0xD31A # 0 +0xCC70 0xD31B # 0 +0xCC71 0xD31C # 0 +0xCC73 0xD31D # 0 +0xCC74 0xD31E # 0 +0xCC75 0xD31F # 0 +0xCC76 0xD320 # 0 +0xCC77 0xD321 # 0 +0xCC78 0xD322 # 0 +0xCC79 0xD323 # 0 +0xCC7A 0xD324 # 0 +0xCC7B 0xD325 # 0 +0xCC7C 0xD326 # 0 +0xCC7D 0xD327 # 0 +0xCC81 0xD328 # 0 +0xCC82 0xD329 # 0 +0xCC83 0xD32A # 0 +0xCC84 0xD32B # 0 +0xCC85 0xD32C # 0 +0xCC86 0xD32D # 0 +0xCC87 0xD32E # 0 +0xCC88 0xD32F # 0 +0xCC89 0xD330 # 0 +0xCC8A 0xD331 # 0 +0xCC8B 0xD332 # 0 +0xCC8C 0xD333 # 0 +0xCC8D 0xD334 # 0 +0xCC8E 0xD335 # 0 +0xCC8F 0xD336 # 0 +0xCC90 0xD337 # 0 +0xCC91 0xD338 # 0 +0xCC93 0xD339 # 0 +0xCC94 0xD33A # 0 +0xCC95 0xD33B # 0 +0xCC96 0xD33C # 0 +0xCC97 0xD33D # 0 +0xCC98 0xD33E # 0 +0xCC99 0xD33F # 0 +0xCC9A 0xD340 # 0 +0xCC9B 0xD341 # 0 +0xCC9C 0xD342 # 0 +0xCC9D 0xD343 # 0 +0xCCA1 0xD344 # 0 +0xCCA2 0xD345 # 0 +0xCCA3 0xD346 # 0 +0xCCA4 0xD347 # 0 +0xCCA5 0xD348 # 0 +0xCCA6 0xD349 # 0 +0xCCA7 0xD34A # 0 +0xCCA8 0xD34B # 0 +0xCCA9 0xD34C # 0 +0xCCAA 0xD34D # 0 +0xCCAB 0xD34E # 0 +0xCCAC 0xD34F # 0 +0xCCAD 0xD350 # 0 +0xCCAE 0xD351 # 0 +0xCCAF 0xD352 # 0 +0xCCB0 0xD353 # 0 +0xCCB1 0xD354 # 0 +0xCCB3 0xD355 # 0 +0xCCB4 0xD356 # 0 +0xCCB5 0xD357 # 0 +0xCCB6 0xD358 # 0 +0xCCB7 0xD359 # 0 +0xCCB8 0xD35A # 0 +0xCCB9 0xD35B # 0 +0xCCBA 0xD35C # 0 +0xCCBB 0xD35D # 0 +0xCCBC 0xD35E # 0 +0xCCBD 0xD35F # 0 +0xCCC1 0xD360 # 0 +0xCCC2 0xD361 # 0 +0xCCC3 0xD362 # 0 +0xCCC4 0xD363 # 0 +0xCCC5 0xD364 # 0 +0xCCC6 0xD365 # 0 +0xCCC7 0xD366 # 0 +0xCCC8 0xD367 # 0 +0xCCC9 0xD368 # 0 +0xCCCA 0xD369 # 0 +0xCCCB 0xD36A # 0 +0xCCCC 0xD36B # 0 +0xCCCD 0xD36C # 0 +0xCCCE 0xD36D # 0 +0xCCCF 0xD36E # 0 +0xCCD0 0xD36F # 0 +0xCCD1 0xD370 # 0 +0xCCD3 0xD371 # 0 +0xCCD4 0xD372 # 0 +0xCCD5 0xD373 # 0 +0xCCD6 0xD374 # 0 +0xCCD7 0xD375 # 0 +0xCCD8 0xD376 # 0 +0xCCD9 0xD377 # 0 +0xCCDA 0xD378 # 0 +0xCCDB 0xD379 # 0 +0xCCDC 0xD37A # 0 +0xCCDD 0xD37B # 0 +0xCCE1 0xD37C # 0 +0xCCE2 0xD37D # 0 +0xCCE3 0xD37E # 0 +0xCCE4 0xD37F # 0 +0xCCE5 0xD380 # 0 +0xCCE6 0xD381 # 0 +0xCCE7 0xD382 # 0 +0xCCE8 0xD383 # 0 +0xCCE9 0xD384 # 0 +0xCCEA 0xD385 # 0 +0xCCEB 0xD386 # 0 +0xCCEC 0xD387 # 0 +0xCCED 0xD388 # 0 +0xCCEE 0xD389 # 0 +0xCCEF 0xD38A # 0 +0xCCF0 0xD38B # 0 +0xCCF1 0xD38C # 0 +0xCCF3 0xD38D # 0 +0xCCF4 0xD38E # 0 +0xCCF5 0xD38F # 0 +0xCCF6 0xD390 # 0 +0xCCF7 0xD391 # 0 +0xCCF8 0xD392 # 0 +0xCCF9 0xD393 # 0 +0xCCFA 0xD394 # 0 +0xCCFB 0xD395 # 0 +0xCCFC 0xD396 # 0 +0xCCFD 0xD397 # 0 +0xCD41 0xD398 # 0 +0xCD42 0xD399 # 0 +0xCD43 0xD39A # 0 +0xCD44 0xD39B # 0 +0xCD45 0xD39C # 0 +0xCD46 0xD39D # 0 +0xCD47 0xD39E # 0 +0xCD48 0xD39F # 0 +0xCD49 0xD3A0 # 0 +0xCD4A 0xD3A1 # 0 +0xCD4B 0xD3A2 # 0 +0xCD4C 0xD3A3 # 0 +0xCD4D 0xD3A4 # 0 +0xCD4E 0xD3A5 # 0 +0xCD4F 0xD3A6 # 0 +0xCD50 0xD3A7 # 0 +0xCD51 0xD3A8 # 0 +0xCD53 0xD3A9 # 0 +0xCD54 0xD3AA # 0 +0xCD55 0xD3AB # 0 +0xCD56 0xD3AC # 0 +0xCD57 0xD3AD # 0 +0xCD58 0xD3AE # 0 +0xCD59 0xD3AF # 0 +0xCD5A 0xD3B0 # 0 +0xCD5B 0xD3B1 # 0 +0xCD5C 0xD3B2 # 0 +0xCD5D 0xD3B3 # 0 +0xCD61 0xD3B4 # 0 +0xCD62 0xD3B5 # 0 +0xCD63 0xD3B6 # 0 +0xCD64 0xD3B7 # 0 +0xCD65 0xD3B8 # 0 +0xCD66 0xD3B9 # 0 +0xCD67 0xD3BA # 0 +0xCD68 0xD3BB # 0 +0xCD69 0xD3BC # 0 +0xCD6A 0xD3BD # 0 +0xCD6B 0xD3BE # 0 +0xCD6C 0xD3BF # 0 +0xCD6D 0xD3C0 # 0 +0xCD6E 0xD3C1 # 0 +0xCD6F 0xD3C2 # 0 +0xCD70 0xD3C3 # 0 +0xCD71 0xD3C4 # 0 +0xCD73 0xD3C5 # 0 +0xCD74 0xD3C6 # 0 +0xCD75 0xD3C7 # 0 +0xCD76 0xD3C8 # 0 +0xCD77 0xD3C9 # 0 +0xCD78 0xD3CA # 0 +0xCD79 0xD3CB # 0 +0xCD7A 0xD3CC # 0 +0xCD7B 0xD3CD # 0 +0xCD7C 0xD3CE # 0 +0xCD7D 0xD3CF # 0 +0xCD81 0xD3D0 # 0 +0xCD82 0xD3D1 # 0 +0xCD83 0xD3D2 # 0 +0xCD84 0xD3D3 # 0 +0xCD85 0xD3D4 # 0 +0xCD86 0xD3D5 # 0 +0xCD87 0xD3D6 # 0 +0xCD88 0xD3D7 # 0 +0xCD89 0xD3D8 # 0 +0xCD8A 0xD3D9 # 0 +0xCD8B 0xD3DA # 0 +0xCD8C 0xD3DB # 0 +0xCD8D 0xD3DC # 0 +0xCD8E 0xD3DD # 0 +0xCD8F 0xD3DE # 0 +0xCD90 0xD3DF # 0 +0xCD91 0xD3E0 # 0 +0xCD93 0xD3E1 # 0 +0xCD94 0xD3E2 # 0 +0xCD95 0xD3E3 # 0 +0xCD96 0xD3E4 # 0 +0xCD97 0xD3E5 # 0 +0xCD98 0xD3E6 # 0 +0xCD99 0xD3E7 # 0 +0xCD9A 0xD3E8 # 0 +0xCD9B 0xD3E9 # 0 +0xCD9C 0xD3EA # 0 +0xCD9D 0xD3EB # 0 +0xCDA1 0xD3EC # 0 +0xCDA2 0xD3ED # 0 +0xCDA3 0xD3EE # 0 +0xCDA4 0xD3EF # 0 +0xCDA5 0xD3F0 # 0 +0xCDA6 0xD3F1 # 0 +0xCDA7 0xD3F2 # 0 +0xCDA8 0xD3F3 # 0 +0xCDA9 0xD3F4 # 0 +0xCDAA 0xD3F5 # 0 +0xCDAB 0xD3F6 # 0 +0xCDAC 0xD3F7 # 0 +0xCDAD 0xD3F8 # 0 +0xCDAE 0xD3F9 # 0 +0xCDAF 0xD3FA # 0 +0xCDB0 0xD3FB # 0 +0xCDB1 0xD3FC # 0 +0xCDB3 0xD3FD # 0 +0xCDB4 0xD3FE # 0 +0xCDB5 0xD3FF # 0 +0xCDB6 0xD400 # 0 +0xCDB7 0xD401 # 0 +0xCDB8 0xD402 # 0 +0xCDB9 0xD403 # 0 +0xCDBA 0xD404 # 0 +0xCDBB 0xD405 # 0 +0xCDBC 0xD406 # 0 +0xCDBD 0xD407 # 0 +0xCDC1 0xD408 # 0 +0xCDC2 0xD409 # 0 +0xCDC3 0xD40A # 0 +0xCDC4 0xD40B # 0 +0xCDC5 0xD40C # 0 +0xCDC6 0xD40D # 0 +0xCDC7 0xD40E # 0 +0xCDC8 0xD40F # 0 +0xCDC9 0xD410 # 0 +0xCDCA 0xD411 # 0 +0xCDCB 0xD412 # 0 +0xCDCC 0xD413 # 0 +0xCDCD 0xD414 # 0 +0xCDCE 0xD415 # 0 +0xCDCF 0xD416 # 0 +0xCDD0 0xD417 # 0 +0xCDD1 0xD418 # 0 +0xCDD3 0xD419 # 0 +0xCDD4 0xD41A # 0 +0xCDD5 0xD41B # 0 +0xCDD6 0xD41C # 0 +0xCDD7 0xD41D # 0 +0xCDD8 0xD41E # 0 +0xCDD9 0xD41F # 0 +0xCDDA 0xD420 # 0 +0xCDDB 0xD421 # 0 +0xCDDC 0xD422 # 0 +0xCDDD 0xD423 # 0 +0xCDE1 0xD424 # 0 +0xCDE2 0xD425 # 0 +0xCDE3 0xD426 # 0 +0xCDE4 0xD427 # 0 +0xCDE5 0xD428 # 0 +0xCDE6 0xD429 # 0 +0xCDE7 0xD42A # 0 +0xCDE8 0xD42B # 0 +0xCDE9 0xD42C # 0 +0xCDEA 0xD42D # 0 +0xCDEB 0xD42E # 0 +0xCDEC 0xD42F # 0 +0xCDED 0xD430 # 0 +0xCDEE 0xD431 # 0 +0xCDEF 0xD432 # 0 +0xCDF0 0xD433 # 0 +0xCDF1 0xD434 # 0 +0xCDF3 0xD435 # 0 +0xCDF4 0xD436 # 0 +0xCDF5 0xD437 # 0 +0xCDF6 0xD438 # 0 +0xCDF7 0xD439 # 0 +0xCDF8 0xD43A # 0 +0xCDF9 0xD43B # 0 +0xCDFA 0xD43C # 0 +0xCDFB 0xD43D # 0 +0xCDFC 0xD43E # 0 +0xCDFD 0xD43F # 0 +0xCE41 0xD440 # 0 +0xCE42 0xD441 # 0 +0xCE43 0xD442 # 0 +0xCE44 0xD443 # 0 +0xCE45 0xD444 # 0 +0xCE46 0xD445 # 0 +0xCE47 0xD446 # 0 +0xCE48 0xD447 # 0 +0xCE49 0xD448 # 0 +0xCE4A 0xD449 # 0 +0xCE4B 0xD44A # 0 +0xCE4C 0xD44B # 0 +0xCE4D 0xD44C # 0 +0xCE4E 0xD44D # 0 +0xCE4F 0xD44E # 0 +0xCE50 0xD44F # 0 +0xCE51 0xD450 # 0 +0xCE53 0xD451 # 0 +0xCE54 0xD452 # 0 +0xCE55 0xD453 # 0 +0xCE56 0xD454 # 0 +0xCE57 0xD455 # 0 +0xCE58 0xD456 # 0 +0xCE59 0xD457 # 0 +0xCE5A 0xD458 # 0 +0xCE5B 0xD459 # 0 +0xCE5C 0xD45A # 0 +0xCE5D 0xD45B # 0 +0xCE61 0xD45C # 0 +0xCE62 0xD45D # 0 +0xCE63 0xD45E # 0 +0xCE64 0xD45F # 0 +0xCE65 0xD460 # 0 +0xCE66 0xD461 # 0 +0xCE67 0xD462 # 0 +0xCE68 0xD463 # 0 +0xCE69 0xD464 # 0 +0xCE6A 0xD465 # 0 +0xCE6B 0xD466 # 0 +0xCE6C 0xD467 # 0 +0xCE6D 0xD468 # 0 +0xCE6E 0xD469 # 0 +0xCE6F 0xD46A # 0 +0xCE70 0xD46B # 0 +0xCE71 0xD46C # 0 +0xCE73 0xD46D # 0 +0xCE74 0xD46E # 0 +0xCE75 0xD46F # 0 +0xCE76 0xD470 # 0 +0xCE77 0xD471 # 0 +0xCE78 0xD472 # 0 +0xCE79 0xD473 # 0 +0xCE7A 0xD474 # 0 +0xCE7B 0xD475 # 0 +0xCE7C 0xD476 # 0 +0xCE7D 0xD477 # 0 +0xCE81 0xD478 # 0 +0xCE82 0xD479 # 0 +0xCE83 0xD47A # 0 +0xCE84 0xD47B # 0 +0xCE85 0xD47C # 0 +0xCE86 0xD47D # 0 +0xCE87 0xD47E # 0 +0xCE88 0xD47F # 0 +0xCE89 0xD480 # 0 +0xCE8A 0xD481 # 0 +0xCE8B 0xD482 # 0 +0xCE8C 0xD483 # 0 +0xCE8D 0xD484 # 0 +0xCE8E 0xD485 # 0 +0xCE8F 0xD486 # 0 +0xCE90 0xD487 # 0 +0xCE91 0xD488 # 0 +0xCE93 0xD489 # 0 +0xCE94 0xD48A # 0 +0xCE95 0xD48B # 0 +0xCE96 0xD48C # 0 +0xCE97 0xD48D # 0 +0xCE98 0xD48E # 0 +0xCE99 0xD48F # 0 +0xCE9A 0xD490 # 0 +0xCE9B 0xD491 # 0 +0xCE9C 0xD492 # 0 +0xCE9D 0xD493 # 0 +0xCEA1 0xD494 # 0 +0xCEA2 0xD495 # 0 +0xCEA3 0xD496 # 0 +0xCEA4 0xD497 # 0 +0xCEA5 0xD498 # 0 +0xCEA6 0xD499 # 0 +0xCEA7 0xD49A # 0 +0xCEA8 0xD49B # 0 +0xCEA9 0xD49C # 0 +0xCEAA 0xD49D # 0 +0xCEAB 0xD49E # 0 +0xCEAC 0xD49F # 0 +0xCEAD 0xD4A0 # 0 +0xCEAE 0xD4A1 # 0 +0xCEAF 0xD4A2 # 0 +0xCEB0 0xD4A3 # 0 +0xCEB1 0xD4A4 # 0 +0xCEB3 0xD4A5 # 0 +0xCEB4 0xD4A6 # 0 +0xCEB5 0xD4A7 # 0 +0xCEB6 0xD4A8 # 0 +0xCEB7 0xD4A9 # 0 +0xCEB8 0xD4AA # 0 +0xCEB9 0xD4AB # 0 +0xCEBA 0xD4AC # 0 +0xCEBB 0xD4AD # 0 +0xCEBC 0xD4AE # 0 +0xCEBD 0xD4AF # 0 +0xCEC1 0xD4B0 # 0 +0xCEC2 0xD4B1 # 0 +0xCEC3 0xD4B2 # 0 +0xCEC4 0xD4B3 # 0 +0xCEC5 0xD4B4 # 0 +0xCEC6 0xD4B5 # 0 +0xCEC7 0xD4B6 # 0 +0xCEC8 0xD4B7 # 0 +0xCEC9 0xD4B8 # 0 +0xCECA 0xD4B9 # 0 +0xCECB 0xD4BA # 0 +0xCECC 0xD4BB # 0 +0xCECD 0xD4BC # 0 +0xCECE 0xD4BD # 0 +0xCECF 0xD4BE # 0 +0xCED0 0xD4BF # 0 +0xCED1 0xD4C0 # 0 +0xCED3 0xD4C1 # 0 +0xCED4 0xD4C2 # 0 +0xCED5 0xD4C3 # 0 +0xCED6 0xD4C4 # 0 +0xCED7 0xD4C5 # 0 +0xCED8 0xD4C6 # 0 +0xCED9 0xD4C7 # 0 +0xCEDA 0xD4C8 # 0 +0xCEDB 0xD4C9 # 0 +0xCEDC 0xD4CA # 0 +0xCEDD 0xD4CB # 0 +0xCEE1 0xD4CC # 0 +0xCEE2 0xD4CD # 0 +0xCEE3 0xD4CE # 0 +0xCEE4 0xD4CF # 0 +0xCEE5 0xD4D0 # 0 +0xCEE6 0xD4D1 # 0 +0xCEE7 0xD4D2 # 0 +0xCEE8 0xD4D3 # 0 +0xCEE9 0xD4D4 # 0 +0xCEEA 0xD4D5 # 0 +0xCEEB 0xD4D6 # 0 +0xCEEC 0xD4D7 # 0 +0xCEED 0xD4D8 # 0 +0xCEEE 0xD4D9 # 0 +0xCEEF 0xD4DA # 0 +0xCEF0 0xD4DB # 0 +0xCEF1 0xD4DC # 0 +0xCEF3 0xD4DD # 0 +0xCEF4 0xD4DE # 0 +0xCEF5 0xD4DF # 0 +0xCEF6 0xD4E0 # 0 +0xCEF7 0xD4E1 # 0 +0xCEF8 0xD4E2 # 0 +0xCEF9 0xD4E3 # 0 +0xCEFA 0xD4E4 # 0 +0xCEFB 0xD4E5 # 0 +0xCEFC 0xD4E6 # 0 +0xCEFD 0xD4E7 # 0 +0xCF41 0xD4E8 # 0 +0xCF42 0xD4E9 # 0 +0xCF43 0xD4EA # 0 +0xCF44 0xD4EB # 0 +0xCF45 0xD4EC # 0 +0xCF46 0xD4ED # 0 +0xCF47 0xD4EE # 0 +0xCF48 0xD4EF # 0 +0xCF49 0xD4F0 # 0 +0xCF4A 0xD4F1 # 0 +0xCF4B 0xD4F2 # 0 +0xCF4C 0xD4F3 # 0 +0xCF4D 0xD4F4 # 0 +0xCF4E 0xD4F5 # 0 +0xCF4F 0xD4F6 # 0 +0xCF50 0xD4F7 # 0 +0xCF51 0xD4F8 # 0 +0xCF53 0xD4F9 # 0 +0xCF54 0xD4FA # 0 +0xCF55 0xD4FB # 0 +0xCF56 0xD4FC # 0 +0xCF57 0xD4FD # 0 +0xCF58 0xD4FE # 0 +0xCF59 0xD4FF # 0 +0xCF5A 0xD500 # 0 +0xCF5B 0xD501 # 0 +0xCF5C 0xD502 # 0 +0xCF5D 0xD503 # 0 +0xCF61 0xD504 # 0 +0xCF62 0xD505 # 0 +0xCF63 0xD506 # 0 +0xCF64 0xD507 # 0 +0xCF65 0xD508 # 0 +0xCF66 0xD509 # 0 +0xCF67 0xD50A # 0 +0xCF68 0xD50B # 0 +0xCF69 0xD50C # 0 +0xCF6A 0xD50D # 0 +0xCF6B 0xD50E # 0 +0xCF6C 0xD50F # 0 +0xCF6D 0xD510 # 0 +0xCF6E 0xD511 # 0 +0xCF6F 0xD512 # 0 +0xCF70 0xD513 # 0 +0xCF71 0xD514 # 0 +0xCF73 0xD515 # 0 +0xCF74 0xD516 # 0 +0xCF75 0xD517 # 0 +0xCF76 0xD518 # 0 +0xCF77 0xD519 # 0 +0xCF78 0xD51A # 0 +0xCF79 0xD51B # 0 +0xCF7A 0xD51C # 0 +0xCF7B 0xD51D # 0 +0xCF7C 0xD51E # 0 +0xCF7D 0xD51F # 0 +0xCF81 0xD520 # 0 +0xCF82 0xD521 # 0 +0xCF83 0xD522 # 0 +0xCF84 0xD523 # 0 +0xCF85 0xD524 # 0 +0xCF86 0xD525 # 0 +0xCF87 0xD526 # 0 +0xCF88 0xD527 # 0 +0xCF89 0xD528 # 0 +0xCF8A 0xD529 # 0 +0xCF8B 0xD52A # 0 +0xCF8C 0xD52B # 0 +0xCF8D 0xD52C # 0 +0xCF8E 0xD52D # 0 +0xCF8F 0xD52E # 0 +0xCF90 0xD52F # 0 +0xCF91 0xD530 # 0 +0xCF93 0xD531 # 0 +0xCF94 0xD532 # 0 +0xCF95 0xD533 # 0 +0xCF96 0xD534 # 0 +0xCF97 0xD535 # 0 +0xCF98 0xD536 # 0 +0xCF99 0xD537 # 0 +0xCF9A 0xD538 # 0 +0xCF9B 0xD539 # 0 +0xCF9C 0xD53A # 0 +0xCF9D 0xD53B # 0 +0xCFA1 0xD53C # 0 +0xCFA2 0xD53D # 0 +0xCFA3 0xD53E # 0 +0xCFA4 0xD53F # 0 +0xCFA5 0xD540 # 0 +0xCFA6 0xD541 # 0 +0xCFA7 0xD542 # 0 +0xCFA8 0xD543 # 0 +0xCFA9 0xD544 # 0 +0xCFAA 0xD545 # 0 +0xCFAB 0xD546 # 0 +0xCFAC 0xD547 # 0 +0xCFAD 0xD548 # 0 +0xCFAE 0xD549 # 0 +0xCFAF 0xD54A # 0 +0xCFB0 0xD54B # 0 +0xCFB1 0xD54C # 0 +0xCFB3 0xD54D # 0 +0xCFB4 0xD54E # 0 +0xCFB5 0xD54F # 0 +0xCFB6 0xD550 # 0 +0xCFB7 0xD551 # 0 +0xCFB8 0xD552 # 0 +0xCFB9 0xD553 # 0 +0xCFBA 0xD554 # 0 +0xCFBB 0xD555 # 0 +0xCFBC 0xD556 # 0 +0xCFBD 0xD557 # 0 +0xD041 0x1112 # 0 +0xD061 0xD558 # 0 +0xD062 0xD559 # 0 +0xD063 0xD55A # 0 +0xD064 0xD55B # 0 +0xD065 0xD55C # 0 +0xD066 0xD55D # 0 +0xD067 0xD55E # 0 +0xD068 0xD55F # 0 +0xD069 0xD560 # 0 +0xD06A 0xD561 # 0 +0xD06B 0xD562 # 0 +0xD06C 0xD563 # 0 +0xD06D 0xD564 # 0 +0xD06E 0xD565 # 0 +0xD06F 0xD566 # 0 +0xD070 0xD567 # 0 +0xD071 0xD568 # 0 +0xD073 0xD569 # 0 +0xD074 0xD56A # 0 +0xD075 0xD56B # 0 +0xD076 0xD56C # 0 +0xD077 0xD56D # 0 +0xD078 0xD56E # 0 +0xD079 0xD56F # 0 +0xD07A 0xD570 # 0 +0xD07B 0xD571 # 0 +0xD07C 0xD572 # 0 +0xD07D 0xD573 # 0 +0xD081 0xD574 # 0 +0xD082 0xD575 # 0 +0xD083 0xD576 # 0 +0xD084 0xD577 # 0 +0xD085 0xD578 # 0 +0xD086 0xD579 # 0 +0xD087 0xD57A # 0 +0xD088 0xD57B # 0 +0xD089 0xD57C # 0 +0xD08A 0xD57D # 0 +0xD08B 0xD57E # 0 +0xD08C 0xD57F # 0 +0xD08D 0xD580 # 0 +0xD08E 0xD581 # 0 +0xD08F 0xD582 # 0 +0xD090 0xD583 # 0 +0xD091 0xD584 # 0 +0xD093 0xD585 # 0 +0xD094 0xD586 # 0 +0xD095 0xD587 # 0 +0xD096 0xD588 # 0 +0xD097 0xD589 # 0 +0xD098 0xD58A # 0 +0xD099 0xD58B # 0 +0xD09A 0xD58C # 0 +0xD09B 0xD58D # 0 +0xD09C 0xD58E # 0 +0xD09D 0xD58F # 0 +0xD0A1 0xD590 # 0 +0xD0A2 0xD591 # 0 +0xD0A3 0xD592 # 0 +0xD0A4 0xD593 # 0 +0xD0A5 0xD594 # 0 +0xD0A6 0xD595 # 0 +0xD0A7 0xD596 # 0 +0xD0A8 0xD597 # 0 +0xD0A9 0xD598 # 0 +0xD0AA 0xD599 # 0 +0xD0AB 0xD59A # 0 +0xD0AC 0xD59B # 0 +0xD0AD 0xD59C # 0 +0xD0AE 0xD59D # 0 +0xD0AF 0xD59E # 0 +0xD0B0 0xD59F # 0 +0xD0B1 0xD5A0 # 0 +0xD0B3 0xD5A1 # 0 +0xD0B4 0xD5A2 # 0 +0xD0B5 0xD5A3 # 0 +0xD0B6 0xD5A4 # 0 +0xD0B7 0xD5A5 # 0 +0xD0B8 0xD5A6 # 0 +0xD0B9 0xD5A7 # 0 +0xD0BA 0xD5A8 # 0 +0xD0BB 0xD5A9 # 0 +0xD0BC 0xD5AA # 0 +0xD0BD 0xD5AB # 0 +0xD0C1 0xD5AC # 0 +0xD0C2 0xD5AD # 0 +0xD0C3 0xD5AE # 0 +0xD0C4 0xD5AF # 0 +0xD0C5 0xD5B0 # 0 +0xD0C6 0xD5B1 # 0 +0xD0C7 0xD5B2 # 0 +0xD0C8 0xD5B3 # 0 +0xD0C9 0xD5B4 # 0 +0xD0CA 0xD5B5 # 0 +0xD0CB 0xD5B6 # 0 +0xD0CC 0xD5B7 # 0 +0xD0CD 0xD5B8 # 0 +0xD0CE 0xD5B9 # 0 +0xD0CF 0xD5BA # 0 +0xD0D0 0xD5BB # 0 +0xD0D1 0xD5BC # 0 +0xD0D3 0xD5BD # 0 +0xD0D4 0xD5BE # 0 +0xD0D5 0xD5BF # 0 +0xD0D6 0xD5C0 # 0 +0xD0D7 0xD5C1 # 0 +0xD0D8 0xD5C2 # 0 +0xD0D9 0xD5C3 # 0 +0xD0DA 0xD5C4 # 0 +0xD0DB 0xD5C5 # 0 +0xD0DC 0xD5C6 # 0 +0xD0DD 0xD5C7 # 0 +0xD0E1 0xD5C8 # 0 +0xD0E2 0xD5C9 # 0 +0xD0E3 0xD5CA # 0 +0xD0E4 0xD5CB # 0 +0xD0E5 0xD5CC # 0 +0xD0E6 0xD5CD # 0 +0xD0E7 0xD5CE # 0 +0xD0E8 0xD5CF # 0 +0xD0E9 0xD5D0 # 0 +0xD0EA 0xD5D1 # 0 +0xD0EB 0xD5D2 # 0 +0xD0EC 0xD5D3 # 0 +0xD0ED 0xD5D4 # 0 +0xD0EE 0xD5D5 # 0 +0xD0EF 0xD5D6 # 0 +0xD0F0 0xD5D7 # 0 +0xD0F1 0xD5D8 # 0 +0xD0F3 0xD5D9 # 0 +0xD0F4 0xD5DA # 0 +0xD0F5 0xD5DB # 0 +0xD0F6 0xD5DC # 0 +0xD0F7 0xD5DD # 0 +0xD0F8 0xD5DE # 0 +0xD0F9 0xD5DF # 0 +0xD0FA 0xD5E0 # 0 +0xD0FB 0xD5E1 # 0 +0xD0FC 0xD5E2 # 0 +0xD0FD 0xD5E3 # 0 +0xD141 0xD5E4 # 0 +0xD142 0xD5E5 # 0 +0xD143 0xD5E6 # 0 +0xD144 0xD5E7 # 0 +0xD145 0xD5E8 # 0 +0xD146 0xD5E9 # 0 +0xD147 0xD5EA # 0 +0xD148 0xD5EB # 0 +0xD149 0xD5EC # 0 +0xD14A 0xD5ED # 0 +0xD14B 0xD5EE # 0 +0xD14C 0xD5EF # 0 +0xD14D 0xD5F0 # 0 +0xD14E 0xD5F1 # 0 +0xD14F 0xD5F2 # 0 +0xD150 0xD5F3 # 0 +0xD151 0xD5F4 # 0 +0xD153 0xD5F5 # 0 +0xD154 0xD5F6 # 0 +0xD155 0xD5F7 # 0 +0xD156 0xD5F8 # 0 +0xD157 0xD5F9 # 0 +0xD158 0xD5FA # 0 +0xD159 0xD5FB # 0 +0xD15A 0xD5FC # 0 +0xD15B 0xD5FD # 0 +0xD15C 0xD5FE # 0 +0xD15D 0xD5FF # 0 +0xD161 0xD600 # 0 +0xD162 0xD601 # 0 +0xD163 0xD602 # 0 +0xD164 0xD603 # 0 +0xD165 0xD604 # 0 +0xD166 0xD605 # 0 +0xD167 0xD606 # 0 +0xD168 0xD607 # 0 +0xD169 0xD608 # 0 +0xD16A 0xD609 # 0 +0xD16B 0xD60A # 0 +0xD16C 0xD60B # 0 +0xD16D 0xD60C # 0 +0xD16E 0xD60D # 0 +0xD16F 0xD60E # 0 +0xD170 0xD60F # 0 +0xD171 0xD610 # 0 +0xD173 0xD611 # 0 +0xD174 0xD612 # 0 +0xD175 0xD613 # 0 +0xD176 0xD614 # 0 +0xD177 0xD615 # 0 +0xD178 0xD616 # 0 +0xD179 0xD617 # 0 +0xD17A 0xD618 # 0 +0xD17B 0xD619 # 0 +0xD17C 0xD61A # 0 +0xD17D 0xD61B # 0 +0xD181 0xD61C # 0 +0xD182 0xD61D # 0 +0xD183 0xD61E # 0 +0xD184 0xD61F # 0 +0xD185 0xD620 # 0 +0xD186 0xD621 # 0 +0xD187 0xD622 # 0 +0xD188 0xD623 # 0 +0xD189 0xD624 # 0 +0xD18A 0xD625 # 0 +0xD18B 0xD626 # 0 +0xD18C 0xD627 # 0 +0xD18D 0xD628 # 0 +0xD18E 0xD629 # 0 +0xD18F 0xD62A # 0 +0xD190 0xD62B # 0 +0xD191 0xD62C # 0 +0xD193 0xD62D # 0 +0xD194 0xD62E # 0 +0xD195 0xD62F # 0 +0xD196 0xD630 # 0 +0xD197 0xD631 # 0 +0xD198 0xD632 # 0 +0xD199 0xD633 # 0 +0xD19A 0xD634 # 0 +0xD19B 0xD635 # 0 +0xD19C 0xD636 # 0 +0xD19D 0xD637 # 0 +0xD1A1 0xD638 # 0 +0xD1A2 0xD639 # 0 +0xD1A3 0xD63A # 0 +0xD1A4 0xD63B # 0 +0xD1A5 0xD63C # 0 +0xD1A6 0xD63D # 0 +0xD1A7 0xD63E # 0 +0xD1A8 0xD63F # 0 +0xD1A9 0xD640 # 0 +0xD1AA 0xD641 # 0 +0xD1AB 0xD642 # 0 +0xD1AC 0xD643 # 0 +0xD1AD 0xD644 # 0 +0xD1AE 0xD645 # 0 +0xD1AF 0xD646 # 0 +0xD1B0 0xD647 # 0 +0xD1B1 0xD648 # 0 +0xD1B3 0xD649 # 0 +0xD1B4 0xD64A # 0 +0xD1B5 0xD64B # 0 +0xD1B6 0xD64C # 0 +0xD1B7 0xD64D # 0 +0xD1B8 0xD64E # 0 +0xD1B9 0xD64F # 0 +0xD1BA 0xD650 # 0 +0xD1BB 0xD651 # 0 +0xD1BC 0xD652 # 0 +0xD1BD 0xD653 # 0 +0xD1C1 0xD654 # 0 +0xD1C2 0xD655 # 0 +0xD1C3 0xD656 # 0 +0xD1C4 0xD657 # 0 +0xD1C5 0xD658 # 0 +0xD1C6 0xD659 # 0 +0xD1C7 0xD65A # 0 +0xD1C8 0xD65B # 0 +0xD1C9 0xD65C # 0 +0xD1CA 0xD65D # 0 +0xD1CB 0xD65E # 0 +0xD1CC 0xD65F # 0 +0xD1CD 0xD660 # 0 +0xD1CE 0xD661 # 0 +0xD1CF 0xD662 # 0 +0xD1D0 0xD663 # 0 +0xD1D1 0xD664 # 0 +0xD1D3 0xD665 # 0 +0xD1D4 0xD666 # 0 +0xD1D5 0xD667 # 0 +0xD1D6 0xD668 # 0 +0xD1D7 0xD669 # 0 +0xD1D8 0xD66A # 0 +0xD1D9 0xD66B # 0 +0xD1DA 0xD66C # 0 +0xD1DB 0xD66D # 0 +0xD1DC 0xD66E # 0 +0xD1DD 0xD66F # 0 +0xD1E1 0xD670 # 0 +0xD1E2 0xD671 # 0 +0xD1E3 0xD672 # 0 +0xD1E4 0xD673 # 0 +0xD1E5 0xD674 # 0 +0xD1E6 0xD675 # 0 +0xD1E7 0xD676 # 0 +0xD1E8 0xD677 # 0 +0xD1E9 0xD678 # 0 +0xD1EA 0xD679 # 0 +0xD1EB 0xD67A # 0 +0xD1EC 0xD67B # 0 +0xD1ED 0xD67C # 0 +0xD1EE 0xD67D # 0 +0xD1EF 0xD67E # 0 +0xD1F0 0xD67F # 0 +0xD1F1 0xD680 # 0 +0xD1F3 0xD681 # 0 +0xD1F4 0xD682 # 0 +0xD1F5 0xD683 # 0 +0xD1F6 0xD684 # 0 +0xD1F7 0xD685 # 0 +0xD1F8 0xD686 # 0 +0xD1F9 0xD687 # 0 +0xD1FA 0xD688 # 0 +0xD1FB 0xD689 # 0 +0xD1FC 0xD68A # 0 +0xD1FD 0xD68B # 0 +0xD241 0xD68C # 0 +0xD242 0xD68D # 0 +0xD243 0xD68E # 0 +0xD244 0xD68F # 0 +0xD245 0xD690 # 0 +0xD246 0xD691 # 0 +0xD247 0xD692 # 0 +0xD248 0xD693 # 0 +0xD249 0xD694 # 0 +0xD24A 0xD695 # 0 +0xD24B 0xD696 # 0 +0xD24C 0xD697 # 0 +0xD24D 0xD698 # 0 +0xD24E 0xD699 # 0 +0xD24F 0xD69A # 0 +0xD250 0xD69B # 0 +0xD251 0xD69C # 0 +0xD253 0xD69D # 0 +0xD254 0xD69E # 0 +0xD255 0xD69F # 0 +0xD256 0xD6A0 # 0 +0xD257 0xD6A1 # 0 +0xD258 0xD6A2 # 0 +0xD259 0xD6A3 # 0 +0xD25A 0xD6A4 # 0 +0xD25B 0xD6A5 # 0 +0xD25C 0xD6A6 # 0 +0xD25D 0xD6A7 # 0 +0xD261 0xD6A8 # 0 +0xD262 0xD6A9 # 0 +0xD263 0xD6AA # 0 +0xD264 0xD6AB # 0 +0xD265 0xD6AC # 0 +0xD266 0xD6AD # 0 +0xD267 0xD6AE # 0 +0xD268 0xD6AF # 0 +0xD269 0xD6B0 # 0 +0xD26A 0xD6B1 # 0 +0xD26B 0xD6B2 # 0 +0xD26C 0xD6B3 # 0 +0xD26D 0xD6B4 # 0 +0xD26E 0xD6B5 # 0 +0xD26F 0xD6B6 # 0 +0xD270 0xD6B7 # 0 +0xD271 0xD6B8 # 0 +0xD273 0xD6B9 # 0 +0xD274 0xD6BA # 0 +0xD275 0xD6BB # 0 +0xD276 0xD6BC # 0 +0xD277 0xD6BD # 0 +0xD278 0xD6BE # 0 +0xD279 0xD6BF # 0 +0xD27A 0xD6C0 # 0 +0xD27B 0xD6C1 # 0 +0xD27C 0xD6C2 # 0 +0xD27D 0xD6C3 # 0 +0xD281 0xD6C4 # 0 +0xD282 0xD6C5 # 0 +0xD283 0xD6C6 # 0 +0xD284 0xD6C7 # 0 +0xD285 0xD6C8 # 0 +0xD286 0xD6C9 # 0 +0xD287 0xD6CA # 0 +0xD288 0xD6CB # 0 +0xD289 0xD6CC # 0 +0xD28A 0xD6CD # 0 +0xD28B 0xD6CE # 0 +0xD28C 0xD6CF # 0 +0xD28D 0xD6D0 # 0 +0xD28E 0xD6D1 # 0 +0xD28F 0xD6D2 # 0 +0xD290 0xD6D3 # 0 +0xD291 0xD6D4 # 0 +0xD293 0xD6D5 # 0 +0xD294 0xD6D6 # 0 +0xD295 0xD6D7 # 0 +0xD296 0xD6D8 # 0 +0xD297 0xD6D9 # 0 +0xD298 0xD6DA # 0 +0xD299 0xD6DB # 0 +0xD29A 0xD6DC # 0 +0xD29B 0xD6DD # 0 +0xD29C 0xD6DE # 0 +0xD29D 0xD6DF # 0 +0xD2A1 0xD6E0 # 0 +0xD2A2 0xD6E1 # 0 +0xD2A3 0xD6E2 # 0 +0xD2A4 0xD6E3 # 0 +0xD2A5 0xD6E4 # 0 +0xD2A6 0xD6E5 # 0 +0xD2A7 0xD6E6 # 0 +0xD2A8 0xD6E7 # 0 +0xD2A9 0xD6E8 # 0 +0xD2AA 0xD6E9 # 0 +0xD2AB 0xD6EA # 0 +0xD2AC 0xD6EB # 0 +0xD2AD 0xD6EC # 0 +0xD2AE 0xD6ED # 0 +0xD2AF 0xD6EE # 0 +0xD2B0 0xD6EF # 0 +0xD2B1 0xD6F0 # 0 +0xD2B3 0xD6F1 # 0 +0xD2B4 0xD6F2 # 0 +0xD2B5 0xD6F3 # 0 +0xD2B6 0xD6F4 # 0 +0xD2B7 0xD6F5 # 0 +0xD2B8 0xD6F6 # 0 +0xD2B9 0xD6F7 # 0 +0xD2BA 0xD6F8 # 0 +0xD2BB 0xD6F9 # 0 +0xD2BC 0xD6FA # 0 +0xD2BD 0xD6FB # 0 +0xD2C1 0xD6FC # 0 +0xD2C2 0xD6FD # 0 +0xD2C3 0xD6FE # 0 +0xD2C4 0xD6FF # 0 +0xD2C5 0xD700 # 0 +0xD2C6 0xD701 # 0 +0xD2C7 0xD702 # 0 +0xD2C8 0xD703 # 0 +0xD2C9 0xD704 # 0 +0xD2CA 0xD705 # 0 +0xD2CB 0xD706 # 0 +0xD2CC 0xD707 # 0 +0xD2CD 0xD708 # 0 +0xD2CE 0xD709 # 0 +0xD2CF 0xD70A # 0 +0xD2D0 0xD70B # 0 +0xD2D1 0xD70C # 0 +0xD2D3 0xD70D # 0 +0xD2D4 0xD70E # 0 +0xD2D5 0xD70F # 0 +0xD2D6 0xD710 # 0 +0xD2D7 0xD711 # 0 +0xD2D8 0xD712 # 0 +0xD2D9 0xD713 # 0 +0xD2DA 0xD714 # 0 +0xD2DB 0xD715 # 0 +0xD2DC 0xD716 # 0 +0xD2DD 0xD717 # 0 +0xD2E1 0xD718 # 0 +0xD2E2 0xD719 # 0 +0xD2E3 0xD71A # 0 +0xD2E4 0xD71B # 0 +0xD2E5 0xD71C # 0 +0xD2E6 0xD71D # 0 +0xD2E7 0xD71E # 0 +0xD2E8 0xD71F # 0 +0xD2E9 0xD720 # 0 +0xD2EA 0xD721 # 0 +0xD2EB 0xD722 # 0 +0xD2EC 0xD723 # 0 +0xD2ED 0xD724 # 0 +0xD2EE 0xD725 # 0 +0xD2EF 0xD726 # 0 +0xD2F0 0xD727 # 0 +0xD2F1 0xD728 # 0 +0xD2F3 0xD729 # 0 +0xD2F4 0xD72A # 0 +0xD2F5 0xD72B # 0 +0xD2F6 0xD72C # 0 +0xD2F7 0xD72D # 0 +0xD2F8 0xD72E # 0 +0xD2F9 0xD72F # 0 +0xD2FA 0xD730 # 0 +0xD2FB 0xD731 # 0 +0xD2FC 0xD732 # 0 +0xD2FD 0xD733 # 0 +0xD341 0xD734 # 0 +0xD342 0xD735 # 0 +0xD343 0xD736 # 0 +0xD344 0xD737 # 0 +0xD345 0xD738 # 0 +0xD346 0xD739 # 0 +0xD347 0xD73A # 0 +0xD348 0xD73B # 0 +0xD349 0xD73C # 0 +0xD34A 0xD73D # 0 +0xD34B 0xD73E # 0 +0xD34C 0xD73F # 0 +0xD34D 0xD740 # 0 +0xD34E 0xD741 # 0 +0xD34F 0xD742 # 0 +0xD350 0xD743 # 0 +0xD351 0xD744 # 0 +0xD353 0xD745 # 0 +0xD354 0xD746 # 0 +0xD355 0xD747 # 0 +0xD356 0xD748 # 0 +0xD357 0xD749 # 0 +0xD358 0xD74A # 0 +0xD359 0xD74B # 0 +0xD35A 0xD74C # 0 +0xD35B 0xD74D # 0 +0xD35C 0xD74E # 0 +0xD35D 0xD74F # 0 +0xD361 0xD750 # 0 +0xD362 0xD751 # 0 +0xD363 0xD752 # 0 +0xD364 0xD753 # 0 +0xD365 0xD754 # 0 +0xD366 0xD755 # 0 +0xD367 0xD756 # 0 +0xD368 0xD757 # 0 +0xD369 0xD758 # 0 +0xD36A 0xD759 # 0 +0xD36B 0xD75A # 0 +0xD36C 0xD75B # 0 +0xD36D 0xD75C # 0 +0xD36E 0xD75D # 0 +0xD36F 0xD75E # 0 +0xD370 0xD75F # 0 +0xD371 0xD760 # 0 +0xD373 0xD761 # 0 +0xD374 0xD762 # 0 +0xD375 0xD763 # 0 +0xD376 0xD764 # 0 +0xD377 0xD765 # 0 +0xD378 0xD766 # 0 +0xD379 0xD767 # 0 +0xD37A 0xD768 # 0 +0xD37B 0xD769 # 0 +0xD37C 0xD76A # 0 +0xD37D 0xD76B # 0 +0xD381 0xD76C # 0 +0xD382 0xD76D # 0 +0xD383 0xD76E # 0 +0xD384 0xD76F # 0 +0xD385 0xD770 # 0 +0xD386 0xD771 # 0 +0xD387 0xD772 # 0 +0xD388 0xD773 # 0 +0xD389 0xD774 # 0 +0xD38A 0xD775 # 0 +0xD38B 0xD776 # 0 +0xD38C 0xD777 # 0 +0xD38D 0xD778 # 0 +0xD38E 0xD779 # 0 +0xD38F 0xD77A # 0 +0xD390 0xD77B # 0 +0xD391 0xD77C # 0 +0xD393 0xD77D # 0 +0xD394 0xD77E # 0 +0xD395 0xD77F # 0 +0xD396 0xD780 # 0 +0xD397 0xD781 # 0 +0xD398 0xD782 # 0 +0xD399 0xD783 # 0 +0xD39A 0xD784 # 0 +0xD39B 0xD785 # 0 +0xD39C 0xD786 # 0 +0xD39D 0xD787 # 0 +0xD3A1 0xD788 # 0 +0xD3A2 0xD789 # 0 +0xD3A3 0xD78A # 0 +0xD3A4 0xD78B # 0 +0xD3A5 0xD78C # 0 +0xD3A6 0xD78D # 0 +0xD3A7 0xD78E # 0 +0xD3A8 0xD78F # 0 +0xD3A9 0xD790 # 0 +0xD3AA 0xD791 # 0 +0xD3AB 0xD792 # 0 +0xD3AC 0xD793 # 0 +0xD3AD 0xD794 # 0 +0xD3AE 0xD795 # 0 +0xD3AF 0xD796 # 0 +0xD3B0 0xD797 # 0 +0xD3B1 0xD798 # 0 +0xD3B3 0xD799 # 0 +0xD3B4 0xD79A # 0 +0xD3B5 0xD79B # 0 +0xD3B6 0xD79C # 0 +0xD3B7 0xD79D # 0 +0xD3B8 0xD79E # 0 +0xD3B9 0xD79F # 0 +0xD3BA 0xD7A0 # 0 +0xD3BB 0xD7A1 # 0 +0xD3BC 0xD7A2 # 0 +0xD3BD 0xD7A3 # 0 +0xD831 0xE000 # 0 +0xD832 0xE001 # 0 +0xD833 0xE002 # 0 +0xD834 0xE003 # 0 +0xD835 0xE004 # 0 +0xD836 0xE005 # 0 +0xD837 0xE006 # 0 +0xD838 0xE007 # 0 +0xD839 0xE008 # 0 +0xD83A 0xE009 # 0 +0xD83B 0xE00A # 0 +0xD83C 0xE00B # 0 +0xD83D 0xE00C # 0 +0xD83E 0xE00D # 0 +0xD83F 0xE00E # 0 +0xD840 0xE00F # 0 +0xD841 0xE010 # 0 +0xD842 0xE011 # 0 +0xD843 0xE012 # 0 +0xD844 0xE013 # 0 +0xD845 0xE014 # 0 +0xD846 0xE015 # 0 +0xD847 0xE016 # 0 +0xD848 0xE017 # 0 +0xD849 0xE018 # 0 +0xD84A 0xE019 # 0 +0xD84B 0xE01A # 0 +0xD84C 0xE01B # 0 +0xD84D 0xE01C # 0 +0xD84E 0xE01D # 0 +0xD84F 0xE01E # 0 +0xD850 0xE01F # 0 +0xD851 0xE020 # 0 +0xD852 0xE021 # 0 +0xD853 0xE022 # 0 +0xD854 0xE023 # 0 +0xD855 0xE024 # 0 +0xD856 0xE025 # 0 +0xD857 0xE026 # 0 +0xD858 0xE027 # 0 +0xD859 0xE028 # 0 +0xD85A 0xE029 # 0 +0xD85B 0xE02A # 0 +0xD85C 0xE02B # 0 +0xD85D 0xE02C # 0 +0xD85E 0xE02D # 0 +0xD85F 0xE02E # 0 +0xD860 0xE02F # 0 +0xD861 0xE030 # 0 +0xD862 0xE031 # 0 +0xD863 0xE032 # 0 +0xD864 0xE033 # 0 +0xD865 0xE034 # 0 +0xD866 0xE035 # 0 +0xD867 0xE036 # 0 +0xD868 0xE037 # 0 +0xD869 0xE038 # 0 +0xD86A 0xE039 # 0 +0xD86B 0xE03A # 0 +0xD86C 0xE03B # 0 +0xD86D 0xE03C # 0 +0xD86E 0xE03D # 0 +0xD86F 0xE03E # 0 +0xD870 0xE03F # 0 +0xD871 0xE040 # 0 +0xD872 0xE041 # 0 +0xD873 0xE042 # 0 +0xD874 0xE043 # 0 +0xD875 0xE044 # 0 +0xD876 0xE045 # 0 +0xD877 0xE046 # 0 +0xD878 0xE047 # 0 +0xD879 0xE048 # 0 +0xD87A 0xE049 # 0 +0xD87B 0xE04A # 0 +0xD87C 0xE04B # 0 +0xD87D 0xE04C # 0 +0xD87E 0xE04D # 0 +0xD891 0xE04E # 0 +0xD892 0xE04F # 0 +0xD893 0xE050 # 0 +0xD894 0xE051 # 0 +0xD895 0xE052 # 0 +0xD896 0xE053 # 0 +0xD897 0xE054 # 0 +0xD898 0xE055 # 0 +0xD899 0xE056 # 0 +0xD89A 0xE057 # 0 +0xD89B 0xE058 # 0 +0xD89C 0xE059 # 0 +0xD89D 0xE05A # 0 +0xD89E 0xE05B # 0 +0xD89F 0xE05C # 0 +0xD8A0 0xE05D # 0 +0xD8A1 0xE05E # 0 +0xD8A2 0xE05F # 0 +0xD8A3 0xE060 # 0 +0xD8A4 0xE061 # 0 +0xD8A5 0xE062 # 0 +0xD8A6 0xE063 # 0 +0xD8A7 0xE064 # 0 +0xD8A8 0xE065 # 0 +0xD8A9 0xE066 # 0 +0xD8AA 0xE067 # 0 +0xD8AB 0xE068 # 0 +0xD8AC 0xE069 # 0 +0xD8AD 0xE06A # 0 +0xD8AE 0xE06B # 0 +0xD8AF 0xE06C # 0 +0xD8B0 0xE06D # 0 +0xD8B1 0xE06E # 0 +0xD8B2 0xE06F # 0 +0xD8B3 0xE070 # 0 +0xD8B4 0xE071 # 0 +0xD8B5 0xE072 # 0 +0xD8B6 0xE073 # 0 +0xD8B7 0xE074 # 0 +0xD8B8 0xE075 # 0 +0xD8B9 0xE076 # 0 +0xD8BA 0xE077 # 0 +0xD8BB 0xE078 # 0 +0xD8BC 0xE079 # 0 +0xD8BD 0xE07A # 0 +0xD8BE 0xE07B # 0 +0xD8BF 0xE07C # 0 +0xD8C0 0xE07D # 0 +0xD8C1 0xE07E # 0 +0xD8C2 0xE07F # 0 +0xD8C3 0xE080 # 0 +0xD8C4 0xE081 # 0 +0xD8C5 0xE082 # 0 +0xD8C6 0xE083 # 0 +0xD8C7 0xE084 # 0 +0xD8C8 0xE085 # 0 +0xD8C9 0xE086 # 0 +0xD8CA 0xE087 # 0 +0xD8CB 0xE088 # 0 +0xD8CC 0xE089 # 0 +0xD8CD 0xE08A # 0 +0xD8CE 0xE08B # 0 +0xD8CF 0xE08C # 0 +0xD8D0 0xE08D # 0 +0xD8D1 0xE08E # 0 +0xD8D2 0xE08F # 0 +0xD8D3 0xE090 # 0 +0xD8D4 0xE091 # 0 +0xD8D5 0xE092 # 0 +0xD8D6 0xE093 # 0 +0xD8D7 0xE094 # 0 +0xD8D8 0xE095 # 0 +0xD8D9 0xE096 # 0 +0xD8DA 0xE097 # 0 +0xD8DB 0xE098 # 0 +0xD8DC 0xE099 # 0 +0xD8DD 0xE09A # 0 +0xD8DE 0xE09B # 0 +0xD8DF 0xE09C # 0 +0xD8E0 0xE09D # 0 +0xD8E1 0xE09E # 0 +0xD8E2 0xE09F # 0 +0xD8E3 0xE0A0 # 0 +0xD8E4 0xE0A1 # 0 +0xD8E5 0xE0A2 # 0 +0xD8E6 0xE0A3 # 0 +0xD8E7 0xE0A4 # 0 +0xD8E8 0xE0A5 # 0 +0xD8E9 0xE0A6 # 0 +0xD8EA 0xE0A7 # 0 +0xD8EB 0xE0A8 # 0 +0xD8EC 0xE0A9 # 0 +0xD8ED 0xE0AA # 0 +0xD8EE 0xE0AB # 0 +0xD8EF 0xE0AC # 0 +0xD8F0 0xE0AD # 0 +0xD8F1 0xE0AE # 0 +0xD8F2 0xE0AF # 0 +0xD8F3 0xE0B0 # 0 +0xD8F4 0xE0B1 # 0 +0xD8F5 0xE0B2 # 0 +0xD8F6 0xE0B3 # 0 +0xD8F7 0xE0B4 # 0 +0xD8F8 0xE0B5 # 0 +0xD8F9 0xE0B6 # 0 +0xD8FA 0xE0B7 # 0 +0xD8FB 0xE0B8 # 0 +0xD8FC 0xE0B9 # 0 +0xD8FD 0xE0BA # 0 +0xD8FE 0xE0BB # 0 +0xD931 0x3000 # 0 +0xD932 0x3001 # 0 +0xD933 0x3002 # 0 +0xD934 0x00B7 # 0 +0xD935 0x2025 # 0 +0xD936 0x2026 # 0 +0xD937 0x00A8 # 0 +0xD938 0x3003 # 0 +0xD939 0x00AD # 0 +0xD93A 0x2015 # 0 +0xD93B 0x2225 # 0 +0xD93C 0xFF3C # 0 +0xD93D 0x223C # 0 +0xD93E 0x2018 # 0 +0xD93F 0x2019 # 0 +0xD940 0x201C # 0 +0xD941 0x201D # 0 +0xD942 0x3014 # 0 +0xD943 0x3015 # 0 +0xD944 0x3008 # 0 +0xD945 0x3009 # 0 +0xD946 0x300A # 0 +0xD947 0x300B # 0 +0xD948 0x300C # 0 +0xD949 0x300D # 0 +0xD94A 0x300E # 0 +0xD94B 0x300F # 0 +0xD94C 0x3010 # 0 +0xD94D 0x3011 # 0 +0xD94E 0x00B1 # 0 +0xD94F 0x00D7 # 0 +0xD950 0x00F7 # 0 +0xD951 0x2260 # 0 +0xD952 0x2264 # 0 +0xD953 0x2265 # 0 +0xD954 0x221E # 0 +0xD955 0x2234 # 0 +0xD956 0x00B0 # 0 +0xD957 0x2032 # 0 +0xD958 0x2033 # 0 +0xD959 0x2103 # 0 +0xD95A 0x212B # 0 +0xD95B 0xFFE0 # 0 +0xD95C 0xFFE1 # 0 +0xD95D 0xFFE5 # 0 +0xD95E 0x2642 # 0 +0xD95F 0x2640 # 0 +0xD960 0x2220 # 0 +0xD961 0x22A5 # 0 +0xD962 0x2312 # 0 +0xD963 0x2202 # 0 +0xD964 0x2207 # 0 +0xD965 0x2261 # 0 +0xD966 0x2252 # 0 +0xD967 0x00A7 # 0 +0xD968 0x203B # 0 +0xD969 0x2606 # 0 +0xD96A 0x2605 # 0 +0xD96B 0x25CB # 0 +0xD96C 0x25CF # 0 +0xD96D 0x25CE # 0 +0xD96E 0x25C7 # 0 +0xD96F 0x25C6 # 0 +0xD970 0x25A1 # 0 +0xD971 0x25A0 # 0 +0xD972 0x25B3 # 0 +0xD973 0x25B2 # 0 +0xD974 0x25BD # 0 +0xD975 0x25BC # 0 +0xD976 0x2192 # 0 +0xD977 0x2190 # 0 +0xD978 0x2191 # 0 +0xD979 0x2193 # 0 +0xD97A 0x2194 # 0 +0xD97B 0x3013 # 0 +0xD97C 0x226A # 0 +0xD97D 0x226B # 0 +0xD97E 0x221A # 0 +0xD991 0x223D # 0 +0xD992 0x221D # 0 +0xD993 0x2235 # 0 +0xD994 0x222B # 0 +0xD995 0x222C # 0 +0xD996 0x2208 # 0 +0xD997 0x220B # 0 +0xD998 0x2286 # 0 +0xD999 0x2287 # 0 +0xD99A 0x2282 # 0 +0xD99B 0x2283 # 0 +0xD99C 0x222A # 0 +0xD99D 0x2229 # 0 +0xD99E 0x2227 # 0 +0xD99F 0x2228 # 0 +0xD9A0 0xFFE2 # 0 +0xD9A1 0x21D2 # 0 +0xD9A2 0x21D4 # 0 +0xD9A3 0x2200 # 0 +0xD9A4 0x2203 # 0 +0xD9A5 0x00B4 # 0 +0xD9A6 0xFF5E # 0 +0xD9A7 0x02C7 # 0 +0xD9A8 0x02D8 # 0 +0xD9A9 0x02DD # 0 +0xD9AA 0x02DA # 0 +0xD9AB 0x02D9 # 0 +0xD9AC 0x00B8 # 0 +0xD9AD 0x02DB # 0 +0xD9AE 0x00A1 # 0 +0xD9AF 0x00BF # 0 +0xD9B0 0x02D0 # 0 +0xD9B1 0x222E # 0 +0xD9B2 0x2211 # 0 +0xD9B3 0x220F # 0 +0xD9B4 0x00A4 # 0 +0xD9B5 0x2109 # 0 +0xD9B6 0x2030 # 0 +0xD9B7 0x25C1 # 0 +0xD9B8 0x25C0 # 0 +0xD9B9 0x25B7 # 0 +0xD9BA 0x25B6 # 0 +0xD9BB 0x2664 # 0 +0xD9BC 0x2660 # 0 +0xD9BD 0x2661 # 0 +0xD9BE 0x2665 # 0 +0xD9BF 0x2667 # 0 +0xD9C0 0x2663 # 0 +0xD9C1 0x2299 # 0 +0xD9C2 0x25C8 # 0 +0xD9C3 0x25A3 # 0 +0xD9C4 0x25D0 # 0 +0xD9C5 0x25D1 # 0 +0xD9C6 0x2592 # 0 +0xD9C7 0x25A4 # 0 +0xD9C8 0x25A5 # 0 +0xD9C9 0x25A8 # 0 +0xD9CA 0x25A7 # 0 +0xD9CB 0x25A6 # 0 +0xD9CC 0x25A9 # 0 +0xD9CD 0x2668 # 0 +0xD9CE 0x260F # 0 +0xD9CF 0x260E # 0 +0xD9D0 0x261C # 0 +0xD9D1 0x261E # 0 +0xD9D2 0x00B6 # 0 +0xD9D3 0x2020 # 0 +0xD9D4 0x2021 # 0 +0xD9D5 0x2195 # 0 +0xD9D6 0x2197 # 0 +0xD9D7 0x2199 # 0 +0xD9D8 0x2196 # 0 +0xD9D9 0x2198 # 0 +0xD9DA 0x266D # 0 +0xD9DB 0x2669 # 0 +0xD9DC 0x266A # 0 +0xD9DD 0x266C # 0 +0xD9DE 0x327F # 0 +0xD9DF 0x321C # 0 +0xD9E0 0x2116 # 0 +0xD9E1 0x33C7 # 0 +0xD9E2 0x2122 # 0 +0xD9E3 0x33C2 # 0 +0xD9E4 0x33D8 # 0 +0xD9E5 0x2121 # 0 +0xD9E6 0x20AC # 0 +0xD9E7 0x00AE # 0 +0xDA31 0xFF01 # 0 +0xDA32 0xFF02 # 0 +0xDA33 0xFF03 # 0 +0xDA34 0xFF04 # 0 +0xDA35 0xFF05 # 0 +0xDA36 0xFF06 # 0 +0xDA37 0xFF07 # 0 +0xDA38 0xFF08 # 0 +0xDA39 0xFF09 # 0 +0xDA3A 0xFF0A # 0 +0xDA3B 0xFF0B # 0 +0xDA3C 0xFF0C # 0 +0xDA3D 0xFF0D # 0 +0xDA3E 0xFF0E # 0 +0xDA3F 0xFF0F # 0 +0xDA40 0xFF10 # 0 +0xDA41 0xFF11 # 0 +0xDA42 0xFF12 # 0 +0xDA43 0xFF13 # 0 +0xDA44 0xFF14 # 0 +0xDA45 0xFF15 # 0 +0xDA46 0xFF16 # 0 +0xDA47 0xFF17 # 0 +0xDA48 0xFF18 # 0 +0xDA49 0xFF19 # 0 +0xDA4A 0xFF1A # 0 +0xDA4B 0xFF1B # 0 +0xDA4C 0xFF1C # 0 +0xDA4D 0xFF1D # 0 +0xDA4E 0xFF1E # 0 +0xDA4F 0xFF1F # 0 +0xDA50 0xFF20 # 0 +0xDA51 0xFF21 # 0 +0xDA52 0xFF22 # 0 +0xDA53 0xFF23 # 0 +0xDA54 0xFF24 # 0 +0xDA55 0xFF25 # 0 +0xDA56 0xFF26 # 0 +0xDA57 0xFF27 # 0 +0xDA58 0xFF28 # 0 +0xDA59 0xFF29 # 0 +0xDA5A 0xFF2A # 0 +0xDA5B 0xFF2B # 0 +0xDA5C 0xFF2C # 0 +0xDA5D 0xFF2D # 0 +0xDA5E 0xFF2E # 0 +0xDA5F 0xFF2F # 0 +0xDA60 0xFF30 # 0 +0xDA61 0xFF31 # 0 +0xDA62 0xFF32 # 0 +0xDA63 0xFF33 # 0 +0xDA64 0xFF34 # 0 +0xDA65 0xFF35 # 0 +0xDA66 0xFF36 # 0 +0xDA67 0xFF37 # 0 +0xDA68 0xFF38 # 0 +0xDA69 0xFF39 # 0 +0xDA6A 0xFF3A # 0 +0xDA6B 0xFF3B # 0 +0xDA6C 0xFFE6 # 0 +0xDA6D 0xFF3D # 0 +0xDA6E 0xFF3E # 0 +0xDA6F 0xFF3F # 0 +0xDA70 0xFF40 # 0 +0xDA71 0xFF41 # 0 +0xDA72 0xFF42 # 0 +0xDA73 0xFF43 # 0 +0xDA74 0xFF44 # 0 +0xDA75 0xFF45 # 0 +0xDA76 0xFF46 # 0 +0xDA77 0xFF47 # 0 +0xDA78 0xFF48 # 0 +0xDA79 0xFF49 # 0 +0xDA7A 0xFF4A # 0 +0xDA7B 0xFF4B # 0 +0xDA7C 0xFF4C # 0 +0xDA7D 0xFF4D # 0 +0xDA7E 0xFF4E # 0 +0xDA91 0xFF4F # 0 +0xDA92 0xFF50 # 0 +0xDA93 0xFF51 # 0 +0xDA94 0xFF52 # 0 +0xDA95 0xFF53 # 0 +0xDA96 0xFF54 # 0 +0xDA97 0xFF55 # 0 +0xDA98 0xFF56 # 0 +0xDA99 0xFF57 # 0 +0xDA9A 0xFF58 # 0 +0xDA9B 0xFF59 # 0 +0xDA9C 0xFF5A # 0 +0xDA9D 0xFF5B # 0 +0xDA9E 0xFF5C # 0 +0xDA9F 0xFF5D # 0 +0xDAA0 0xFFE3 # 0 +0xDAD4 0x115F # 0 +0xDAD5 0x1114 # 0 +0xDAD6 0x1115 # 0 +0xDAD7 0x11C7 # 0 +0xDAD8 0x11C8 # 0 +0xDAD9 0x11CC # 0 +0xDADA 0x11CE # 0 +0xDADB 0x11D3 # 0 +0xDADC 0x11D7 # 0 +0xDADD 0x11D9 # 0 +0xDADE 0x111C # 0 +0xDADF 0x11DD # 0 +0xDAE0 0x11DF # 0 +0xDAE1 0x111D # 0 +0xDAE2 0x111E # 0 +0xDAE3 0x1120 # 0 +0xDAE4 0x1122 # 0 +0xDAE5 0x1123 # 0 +0xDAE6 0x1127 # 0 +0xDAE7 0x1128 # 0 +0xDAE8 0x112B # 0 +0xDAE9 0x112C # 0 +0xDAEA 0x112D # 0 +0xDAEB 0x112E # 0 +0xDAEC 0x112F # 0 +0xDAED 0x1132 # 0 +0xDAEE 0x1136 # 0 +0xDAEF 0x1140 # 0 +0xDAF0 0x1147 # 0 +0xDAF1 0x114C # 0 +0xDAF2 0x1145 # 0 +0xDAF3 0x1146 # 0 +0xDAF4 0x1157 # 0 +0xDAF5 0x1158 # 0 +0xDAF6 0x1159 # 0 +0xDAF7 0x1184 # 0 +0xDAF8 0x1185 # 0 +0xDAF9 0x1188 # 0 +0xDAFA 0x1191 # 0 +0xDAFB 0x1192 # 0 +0xDAFC 0x1194 # 0 +0xDAFD 0x119E # 0 +0xDAFE 0x11A1 # 0 +0xDB31 0x2170 # 0 +0xDB32 0x2171 # 0 +0xDB33 0x2172 # 0 +0xDB34 0x2173 # 0 +0xDB35 0x2174 # 0 +0xDB36 0x2175 # 0 +0xDB37 0x2176 # 0 +0xDB38 0x2177 # 0 +0xDB39 0x2178 # 0 +0xDB3A 0x2179 # 0 +0xDB40 0x2160 # 0 +0xDB41 0x2161 # 0 +0xDB42 0x2162 # 0 +0xDB43 0x2163 # 0 +0xDB44 0x2164 # 0 +0xDB45 0x2165 # 0 +0xDB46 0x2166 # 0 +0xDB47 0x2167 # 0 +0xDB48 0x2168 # 0 +0xDB49 0x2169 # 0 +0xDB51 0x0391 # 0 +0xDB52 0x0392 # 0 +0xDB53 0x0393 # 0 +0xDB54 0x0394 # 0 +0xDB55 0x0395 # 0 +0xDB56 0x0396 # 0 +0xDB57 0x0397 # 0 +0xDB58 0x0398 # 0 +0xDB59 0x0399 # 0 +0xDB5A 0x039A # 0 +0xDB5B 0x039B # 0 +0xDB5C 0x039C # 0 +0xDB5D 0x039D # 0 +0xDB5E 0x039E # 0 +0xDB5F 0x039F # 0 +0xDB60 0x03A0 # 0 +0xDB61 0x03A1 # 0 +0xDB62 0x03A3 # 0 +0xDB63 0x03A4 # 0 +0xDB64 0x03A5 # 0 +0xDB65 0x03A6 # 0 +0xDB66 0x03A7 # 0 +0xDB67 0x03A8 # 0 +0xDB68 0x03A9 # 0 +0xDB71 0x03B1 # 0 +0xDB72 0x03B2 # 0 +0xDB73 0x03B3 # 0 +0xDB74 0x03B4 # 0 +0xDB75 0x03B5 # 0 +0xDB76 0x03B6 # 0 +0xDB77 0x03B7 # 0 +0xDB78 0x03B8 # 0 +0xDB79 0x03B9 # 0 +0xDB7A 0x03BA # 0 +0xDB7B 0x03BB # 0 +0xDB7C 0x03BC # 0 +0xDB7D 0x03BD # 0 +0xDB7E 0x03BE # 0 +0xDB91 0x03BF # 0 +0xDB92 0x03C0 # 0 +0xDB93 0x03C1 # 0 +0xDB94 0x03C3 # 0 +0xDB95 0x03C4 # 0 +0xDB96 0x03C5 # 0 +0xDB97 0x03C6 # 0 +0xDB98 0x03C7 # 0 +0xDB99 0x03C8 # 0 +0xDB9A 0x03C9 # 0 +0xDBA1 0x2500 # 0 +0xDBA2 0x2502 # 0 +0xDBA3 0x250C # 0 +0xDBA4 0x2510 # 0 +0xDBA5 0x2518 # 0 +0xDBA6 0x2514 # 0 +0xDBA7 0x251C # 0 +0xDBA8 0x252C # 0 +0xDBA9 0x2524 # 0 +0xDBAA 0x2534 # 0 +0xDBAB 0x253C # 0 +0xDBAC 0x2501 # 0 +0xDBAD 0x2503 # 0 +0xDBAE 0x250F # 0 +0xDBAF 0x2513 # 0 +0xDBB0 0x251B # 0 +0xDBB1 0x2517 # 0 +0xDBB2 0x2523 # 0 +0xDBB3 0x2533 # 0 +0xDBB4 0x252B # 0 +0xDBB5 0x253B # 0 +0xDBB6 0x254B # 0 +0xDBB7 0x2520 # 0 +0xDBB8 0x252F # 0 +0xDBB9 0x2528 # 0 +0xDBBA 0x2537 # 0 +0xDBBB 0x253F # 0 +0xDBBC 0x251D # 0 +0xDBBD 0x2530 # 0 +0xDBBE 0x2525 # 0 +0xDBBF 0x2538 # 0 +0xDBC0 0x2542 # 0 +0xDBC1 0x2512 # 0 +0xDBC2 0x2511 # 0 +0xDBC3 0x251A # 0 +0xDBC4 0x2519 # 0 +0xDBC5 0x2516 # 0 +0xDBC6 0x2515 # 0 +0xDBC7 0x250E # 0 +0xDBC8 0x250D # 0 +0xDBC9 0x251E # 0 +0xDBCA 0x251F # 0 +0xDBCB 0x2521 # 0 +0xDBCC 0x2522 # 0 +0xDBCD 0x2526 # 0 +0xDBCE 0x2527 # 0 +0xDBCF 0x2529 # 0 +0xDBD0 0x252A # 0 +0xDBD1 0x252D # 0 +0xDBD2 0x252E # 0 +0xDBD3 0x2531 # 0 +0xDBD4 0x2532 # 0 +0xDBD5 0x2535 # 0 +0xDBD6 0x2536 # 0 +0xDBD7 0x2539 # 0 +0xDBD8 0x253A # 0 +0xDBD9 0x253D # 0 +0xDBDA 0x253E # 0 +0xDBDB 0x2540 # 0 +0xDBDC 0x2541 # 0 +0xDBDD 0x2543 # 0 +0xDBDE 0x2544 # 0 +0xDBDF 0x2545 # 0 +0xDBE0 0x2546 # 0 +0xDBE1 0x2547 # 0 +0xDBE2 0x2548 # 0 +0xDBE3 0x2549 # 0 +0xDBE4 0x254A # 0 +0xDC31 0x3395 # 0 +0xDC32 0x3396 # 0 +0xDC33 0x3397 # 0 +0xDC34 0x2113 # 0 +0xDC35 0x3398 # 0 +0xDC36 0x33C4 # 0 +0xDC37 0x33A3 # 0 +0xDC38 0x33A4 # 0 +0xDC39 0x33A5 # 0 +0xDC3A 0x33A6 # 0 +0xDC3B 0x3399 # 0 +0xDC3C 0x339A # 0 +0xDC3D 0x339B # 0 +0xDC3E 0x339C # 0 +0xDC3F 0x339D # 0 +0xDC40 0x339E # 0 +0xDC41 0x339F # 0 +0xDC42 0x33A0 # 0 +0xDC43 0x33A1 # 0 +0xDC44 0x33A2 # 0 +0xDC45 0x33CA # 0 +0xDC46 0x338D # 0 +0xDC47 0x338E # 0 +0xDC48 0x338F # 0 +0xDC49 0x33CF # 0 +0xDC4A 0x3388 # 0 +0xDC4B 0x3389 # 0 +0xDC4C 0x33C8 # 0 +0xDC4D 0x33A7 # 0 +0xDC4E 0x33A8 # 0 +0xDC4F 0x33B0 # 0 +0xDC50 0x33B1 # 0 +0xDC51 0x33B2 # 0 +0xDC52 0x33B3 # 0 +0xDC53 0x33B4 # 0 +0xDC54 0x33B5 # 0 +0xDC55 0x33B6 # 0 +0xDC56 0x33B7 # 0 +0xDC57 0x33B8 # 0 +0xDC58 0x33B9 # 0 +0xDC59 0x3380 # 0 +0xDC5A 0x3381 # 0 +0xDC5B 0x3382 # 0 +0xDC5C 0x3383 # 0 +0xDC5D 0x3384 # 0 +0xDC5E 0x33BA # 0 +0xDC5F 0x33BB # 0 +0xDC60 0x33BC # 0 +0xDC61 0x33BD # 0 +0xDC62 0x33BE # 0 +0xDC63 0x33BF # 0 +0xDC64 0x3390 # 0 +0xDC65 0x3391 # 0 +0xDC66 0x3392 # 0 +0xDC67 0x3393 # 0 +0xDC68 0x3394 # 0 +0xDC69 0x2126 # 0 +0xDC6A 0x33C0 # 0 +0xDC6B 0x33C1 # 0 +0xDC6C 0x338A # 0 +0xDC6D 0x338B # 0 +0xDC6E 0x338C # 0 +0xDC6F 0x33D6 # 0 +0xDC70 0x33C5 # 0 +0xDC71 0x33AD # 0 +0xDC72 0x33AE # 0 +0xDC73 0x33AF # 0 +0xDC74 0x33DB # 0 +0xDC75 0x33A9 # 0 +0xDC76 0x33AA # 0 +0xDC77 0x33AB # 0 +0xDC78 0x33AC # 0 +0xDC79 0x33DD # 0 +0xDC7A 0x33D0 # 0 +0xDC7B 0x33D3 # 0 +0xDC7C 0x33C3 # 0 +0xDC7D 0x33C9 # 0 +0xDC7E 0x33DC # 0 +0xDC91 0x33C6 # 0 +0xDCA1 0x00C6 # 0 +0xDCA2 0x00D0 # 0 +0xDCA3 0x00AA # 0 +0xDCA4 0x0126 # 0 +0xDCA6 0x0132 # 0 +0xDCA8 0x013F # 0 +0xDCA9 0x0141 # 0 +0xDCAA 0x00D8 # 0 +0xDCAB 0x0152 # 0 +0xDCAC 0x00BA # 0 +0xDCAD 0x00DE # 0 +0xDCAE 0x0166 # 0 +0xDCAF 0x014A # 0 +0xDCB1 0x3260 # 0 +0xDCB2 0x3261 # 0 +0xDCB3 0x3262 # 0 +0xDCB4 0x3263 # 0 +0xDCB5 0x3264 # 0 +0xDCB6 0x3265 # 0 +0xDCB7 0x3266 # 0 +0xDCB8 0x3267 # 0 +0xDCB9 0x3268 # 0 +0xDCBA 0x3269 # 0 +0xDCBB 0x326A # 0 +0xDCBC 0x326B # 0 +0xDCBD 0x326C # 0 +0xDCBE 0x326D # 0 +0xDCBF 0x326E # 0 +0xDCC0 0x326F # 0 +0xDCC1 0x3270 # 0 +0xDCC2 0x3271 # 0 +0xDCC3 0x3272 # 0 +0xDCC4 0x3273 # 0 +0xDCC5 0x3274 # 0 +0xDCC6 0x3275 # 0 +0xDCC7 0x3276 # 0 +0xDCC8 0x3277 # 0 +0xDCC9 0x3278 # 0 +0xDCCA 0x3279 # 0 +0xDCCB 0x327A # 0 +0xDCCC 0x327B # 0 +0xDCCD 0x24D0 # 0 +0xDCCE 0x24D1 # 0 +0xDCCF 0x24D2 # 0 +0xDCD0 0x24D3 # 0 +0xDCD1 0x24D4 # 0 +0xDCD2 0x24D5 # 0 +0xDCD3 0x24D6 # 0 +0xDCD4 0x24D7 # 0 +0xDCD5 0x24D8 # 0 +0xDCD6 0x24D9 # 0 +0xDCD7 0x24DA # 0 +0xDCD8 0x24DB # 0 +0xDCD9 0x24DC # 0 +0xDCDA 0x24DD # 0 +0xDCDB 0x24DE # 0 +0xDCDC 0x24DF # 0 +0xDCDD 0x24E0 # 0 +0xDCDE 0x24E1 # 0 +0xDCDF 0x24E2 # 0 +0xDCE0 0x24E3 # 0 +0xDCE1 0x24E4 # 0 +0xDCE2 0x24E5 # 0 +0xDCE3 0x24E6 # 0 +0xDCE4 0x24E7 # 0 +0xDCE5 0x24E8 # 0 +0xDCE6 0x24E9 # 0 +0xDCE7 0x2460 # 0 +0xDCE8 0x2461 # 0 +0xDCE9 0x2462 # 0 +0xDCEA 0x2463 # 0 +0xDCEB 0x2464 # 0 +0xDCEC 0x2465 # 0 +0xDCED 0x2466 # 0 +0xDCEE 0x2467 # 0 +0xDCEF 0x2468 # 0 +0xDCF0 0x2469 # 0 +0xDCF1 0x246A # 0 +0xDCF2 0x246B # 0 +0xDCF3 0x246C # 0 +0xDCF4 0x246D # 0 +0xDCF5 0x246E # 0 +0xDCF6 0x00BD # 0 +0xDCF7 0x2153 # 0 +0xDCF8 0x2154 # 0 +0xDCF9 0x00BC # 0 +0xDCFA 0x00BE # 0 +0xDCFB 0x215B # 0 +0xDCFC 0x215C # 0 +0xDCFD 0x215D # 0 +0xDCFE 0x215E # 0 +0xDD31 0x00E6 # 0 +0xDD32 0x0111 # 0 +0xDD33 0x00F0 # 0 +0xDD34 0x0127 # 0 +0xDD35 0x0131 # 0 +0xDD36 0x0133 # 0 +0xDD37 0x0138 # 0 +0xDD38 0x0140 # 0 +0xDD39 0x0142 # 0 +0xDD3A 0x00F8 # 0 +0xDD3B 0x0153 # 0 +0xDD3C 0x00DF # 0 +0xDD3D 0x00FE # 0 +0xDD3E 0x0167 # 0 +0xDD3F 0x014B # 0 +0xDD40 0x0149 # 0 +0xDD41 0x3200 # 0 +0xDD42 0x3201 # 0 +0xDD43 0x3202 # 0 +0xDD44 0x3203 # 0 +0xDD45 0x3204 # 0 +0xDD46 0x3205 # 0 +0xDD47 0x3206 # 0 +0xDD48 0x3207 # 0 +0xDD49 0x3208 # 0 +0xDD4A 0x3209 # 0 +0xDD4B 0x320A # 0 +0xDD4C 0x320B # 0 +0xDD4D 0x320C # 0 +0xDD4E 0x320D # 0 +0xDD4F 0x320E # 0 +0xDD50 0x320F # 0 +0xDD51 0x3210 # 0 +0xDD52 0x3211 # 0 +0xDD53 0x3212 # 0 +0xDD54 0x3213 # 0 +0xDD55 0x3214 # 0 +0xDD56 0x3215 # 0 +0xDD57 0x3216 # 0 +0xDD58 0x3217 # 0 +0xDD59 0x3218 # 0 +0xDD5A 0x3219 # 0 +0xDD5B 0x321A # 0 +0xDD5C 0x321B # 0 +0xDD5D 0x249C # 0 +0xDD5E 0x249D # 0 +0xDD5F 0x249E # 0 +0xDD60 0x249F # 0 +0xDD61 0x24A0 # 0 +0xDD62 0x24A1 # 0 +0xDD63 0x24A2 # 0 +0xDD64 0x24A3 # 0 +0xDD65 0x24A4 # 0 +0xDD66 0x24A5 # 0 +0xDD67 0x24A6 # 0 +0xDD68 0x24A7 # 0 +0xDD69 0x24A8 # 0 +0xDD6A 0x24A9 # 0 +0xDD6B 0x24AA # 0 +0xDD6C 0x24AB # 0 +0xDD6D 0x24AC # 0 +0xDD6E 0x24AD # 0 +0xDD6F 0x24AE # 0 +0xDD70 0x24AF # 0 +0xDD71 0x24B0 # 0 +0xDD72 0x24B1 # 0 +0xDD73 0x24B2 # 0 +0xDD74 0x24B3 # 0 +0xDD75 0x24B4 # 0 +0xDD76 0x24B5 # 0 +0xDD77 0x2474 # 0 +0xDD78 0x2475 # 0 +0xDD79 0x2476 # 0 +0xDD7A 0x2477 # 0 +0xDD7B 0x2478 # 0 +0xDD7C 0x2479 # 0 +0xDD7D 0x247A # 0 +0xDD7E 0x247B # 0 +0xDD91 0x247C # 0 +0xDD92 0x247D # 0 +0xDD93 0x247E # 0 +0xDD94 0x247F # 0 +0xDD95 0x2480 # 0 +0xDD96 0x2481 # 0 +0xDD97 0x2482 # 0 +0xDD98 0x00B9 # 0 +0xDD99 0x00B2 # 0 +0xDD9A 0x00B3 # 0 +0xDD9B 0x2074 # 0 +0xDD9C 0x207F # 0 +0xDD9D 0x2081 # 0 +0xDD9E 0x2082 # 0 +0xDD9F 0x2083 # 0 +0xDDA0 0x2084 # 0 +0xDDA1 0x3041 # 0 +0xDDA2 0x3042 # 0 +0xDDA3 0x3043 # 0 +0xDDA4 0x3044 # 0 +0xDDA5 0x3045 # 0 +0xDDA6 0x3046 # 0 +0xDDA7 0x3047 # 0 +0xDDA8 0x3048 # 0 +0xDDA9 0x3049 # 0 +0xDDAA 0x304A # 0 +0xDDAB 0x304B # 0 +0xDDAC 0x304C # 0 +0xDDAD 0x304D # 0 +0xDDAE 0x304E # 0 +0xDDAF 0x304F # 0 +0xDDB0 0x3050 # 0 +0xDDB1 0x3051 # 0 +0xDDB2 0x3052 # 0 +0xDDB3 0x3053 # 0 +0xDDB4 0x3054 # 0 +0xDDB5 0x3055 # 0 +0xDDB6 0x3056 # 0 +0xDDB7 0x3057 # 0 +0xDDB8 0x3058 # 0 +0xDDB9 0x3059 # 0 +0xDDBA 0x305A # 0 +0xDDBB 0x305B # 0 +0xDDBC 0x305C # 0 +0xDDBD 0x305D # 0 +0xDDBE 0x305E # 0 +0xDDBF 0x305F # 0 +0xDDC0 0x3060 # 0 +0xDDC1 0x3061 # 0 +0xDDC2 0x3062 # 0 +0xDDC3 0x3063 # 0 +0xDDC4 0x3064 # 0 +0xDDC5 0x3065 # 0 +0xDDC6 0x3066 # 0 +0xDDC7 0x3067 # 0 +0xDDC8 0x3068 # 0 +0xDDC9 0x3069 # 0 +0xDDCA 0x306A # 0 +0xDDCB 0x306B # 0 +0xDDCC 0x306C # 0 +0xDDCD 0x306D # 0 +0xDDCE 0x306E # 0 +0xDDCF 0x306F # 0 +0xDDD0 0x3070 # 0 +0xDDD1 0x3071 # 0 +0xDDD2 0x3072 # 0 +0xDDD3 0x3073 # 0 +0xDDD4 0x3074 # 0 +0xDDD5 0x3075 # 0 +0xDDD6 0x3076 # 0 +0xDDD7 0x3077 # 0 +0xDDD8 0x3078 # 0 +0xDDD9 0x3079 # 0 +0xDDDA 0x307A # 0 +0xDDDB 0x307B # 0 +0xDDDC 0x307C # 0 +0xDDDD 0x307D # 0 +0xDDDE 0x307E # 0 +0xDDDF 0x307F # 0 +0xDDE0 0x3080 # 0 +0xDDE1 0x3081 # 0 +0xDDE2 0x3082 # 0 +0xDDE3 0x3083 # 0 +0xDDE4 0x3084 # 0 +0xDDE5 0x3085 # 0 +0xDDE6 0x3086 # 0 +0xDDE7 0x3087 # 0 +0xDDE8 0x3088 # 0 +0xDDE9 0x3089 # 0 +0xDDEA 0x308A # 0 +0xDDEB 0x308B # 0 +0xDDEC 0x308C # 0 +0xDDED 0x308D # 0 +0xDDEE 0x308E # 0 +0xDDEF 0x308F # 0 +0xDDF0 0x3090 # 0 +0xDDF1 0x3091 # 0 +0xDDF2 0x3092 # 0 +0xDDF3 0x3093 # 0 +0xDE31 0x30A1 # 0 +0xDE32 0x30A2 # 0 +0xDE33 0x30A3 # 0 +0xDE34 0x30A4 # 0 +0xDE35 0x30A5 # 0 +0xDE36 0x30A6 # 0 +0xDE37 0x30A7 # 0 +0xDE38 0x30A8 # 0 +0xDE39 0x30A9 # 0 +0xDE3A 0x30AA # 0 +0xDE3B 0x30AB # 0 +0xDE3C 0x30AC # 0 +0xDE3D 0x30AD # 0 +0xDE3E 0x30AE # 0 +0xDE3F 0x30AF # 0 +0xDE40 0x30B0 # 0 +0xDE41 0x30B1 # 0 +0xDE42 0x30B2 # 0 +0xDE43 0x30B3 # 0 +0xDE44 0x30B4 # 0 +0xDE45 0x30B5 # 0 +0xDE46 0x30B6 # 0 +0xDE47 0x30B7 # 0 +0xDE48 0x30B8 # 0 +0xDE49 0x30B9 # 0 +0xDE4A 0x30BA # 0 +0xDE4B 0x30BB # 0 +0xDE4C 0x30BC # 0 +0xDE4D 0x30BD # 0 +0xDE4E 0x30BE # 0 +0xDE4F 0x30BF # 0 +0xDE50 0x30C0 # 0 +0xDE51 0x30C1 # 0 +0xDE52 0x30C2 # 0 +0xDE53 0x30C3 # 0 +0xDE54 0x30C4 # 0 +0xDE55 0x30C5 # 0 +0xDE56 0x30C6 # 0 +0xDE57 0x30C7 # 0 +0xDE58 0x30C8 # 0 +0xDE59 0x30C9 # 0 +0xDE5A 0x30CA # 0 +0xDE5B 0x30CB # 0 +0xDE5C 0x30CC # 0 +0xDE5D 0x30CD # 0 +0xDE5E 0x30CE # 0 +0xDE5F 0x30CF # 0 +0xDE60 0x30D0 # 0 +0xDE61 0x30D1 # 0 +0xDE62 0x30D2 # 0 +0xDE63 0x30D3 # 0 +0xDE64 0x30D4 # 0 +0xDE65 0x30D5 # 0 +0xDE66 0x30D6 # 0 +0xDE67 0x30D7 # 0 +0xDE68 0x30D8 # 0 +0xDE69 0x30D9 # 0 +0xDE6A 0x30DA # 0 +0xDE6B 0x30DB # 0 +0xDE6C 0x30DC # 0 +0xDE6D 0x30DD # 0 +0xDE6E 0x30DE # 0 +0xDE6F 0x30DF # 0 +0xDE70 0x30E0 # 0 +0xDE71 0x30E1 # 0 +0xDE72 0x30E2 # 0 +0xDE73 0x30E3 # 0 +0xDE74 0x30E4 # 0 +0xDE75 0x30E5 # 0 +0xDE76 0x30E6 # 0 +0xDE77 0x30E7 # 0 +0xDE78 0x30E8 # 0 +0xDE79 0x30E9 # 0 +0xDE7A 0x30EA # 0 +0xDE7B 0x30EB # 0 +0xDE7C 0x30EC # 0 +0xDE7D 0x30ED # 0 +0xDE7E 0x30EE # 0 +0xDE91 0x30EF # 0 +0xDE92 0x30F0 # 0 +0xDE93 0x30F1 # 0 +0xDE94 0x30F2 # 0 +0xDE95 0x30F3 # 0 +0xDE96 0x30F4 # 0 +0xDE97 0x30F5 # 0 +0xDE98 0x30F6 # 0 +0xDEA1 0x0410 # 0 +0xDEA2 0x0411 # 0 +0xDEA3 0x0412 # 0 +0xDEA4 0x0413 # 0 +0xDEA5 0x0414 # 0 +0xDEA6 0x0415 # 0 +0xDEA7 0x0401 # 0 +0xDEA8 0x0416 # 0 +0xDEA9 0x0417 # 0 +0xDEAA 0x0418 # 0 +0xDEAB 0x0419 # 0 +0xDEAC 0x041A # 0 +0xDEAD 0x041B # 0 +0xDEAE 0x041C # 0 +0xDEAF 0x041D # 0 +0xDEB0 0x041E # 0 +0xDEB1 0x041F # 0 +0xDEB2 0x0420 # 0 +0xDEB3 0x0421 # 0 +0xDEB4 0x0422 # 0 +0xDEB5 0x0423 # 0 +0xDEB6 0x0424 # 0 +0xDEB7 0x0425 # 0 +0xDEB8 0x0426 # 0 +0xDEB9 0x0427 # 0 +0xDEBA 0x0428 # 0 +0xDEBB 0x0429 # 0 +0xDEBC 0x042A # 0 +0xDEBD 0x042B # 0 +0xDEBE 0x042C # 0 +0xDEBF 0x042D # 0 +0xDEC0 0x042E # 0 +0xDEC1 0x042F # 0 +0xDED1 0x0430 # 0 +0xDED2 0x0431 # 0 +0xDED3 0x0432 # 0 +0xDED4 0x0433 # 0 +0xDED5 0x0434 # 0 +0xDED6 0x0435 # 0 +0xDED7 0x0451 # 0 +0xDED8 0x0436 # 0 +0xDED9 0x0437 # 0 +0xDEDA 0x0438 # 0 +0xDEDB 0x0439 # 0 +0xDEDC 0x043A # 0 +0xDEDD 0x043B # 0 +0xDEDE 0x043C # 0 +0xDEDF 0x043D # 0 +0xDEE0 0x043E # 0 +0xDEE1 0x043F # 0 +0xDEE2 0x0440 # 0 +0xDEE3 0x0441 # 0 +0xDEE4 0x0442 # 0 +0xDEE5 0x0443 # 0 +0xDEE6 0x0444 # 0 +0xDEE7 0x0445 # 0 +0xDEE8 0x0446 # 0 +0xDEE9 0x0447 # 0 +0xDEEA 0x0448 # 0 +0xDEEB 0x0449 # 0 +0xDEEC 0x044A # 0 +0xDEED 0x044B # 0 +0xDEEE 0x044C # 0 +0xDEEF 0x044D # 0 +0xDEF0 0x044E # 0 +0xDEF1 0x044F # 0 +0xE031 0x4F3D # 0 +0xE032 0x4F73 # 0 +0xE033 0x5047 # 0 +0xE034 0x50F9 # 0 +0xE035 0x52A0 # 0 +0xE036 0x53EF # 0 +0xE037 0x5475 # 0 +0xE038 0x54E5 # 0 +0xE039 0x5609 # 0 +0xE03A 0x5AC1 # 0 +0xE03B 0x5BB6 # 0 +0xE03C 0x6687 # 0 +0xE03D 0x67B6 # 0 +0xE03E 0x67B7 # 0 +0xE03F 0x67EF # 0 +0xE040 0x6B4C # 0 +0xE041 0x73C2 # 0 +0xE042 0x75C2 # 0 +0xE043 0x7A3C # 0 +0xE044 0x82DB # 0 +0xE045 0x8304 # 0 +0xE046 0x8857 # 0 +0xE047 0x8888 # 0 +0xE048 0x8A36 # 0 +0xE049 0x8CC8 # 0 +0xE04A 0x8DCF # 0 +0xE04B 0x8EFB # 0 +0xE04C 0x8FE6 # 0 +0xE04D 0x99D5 # 0 +0xE04E 0x523B # 0 +0xE04F 0x5374 # 0 +0xE050 0x5404 # 0 +0xE051 0x606A # 0 +0xE052 0x6164 # 0 +0xE053 0x6BBC # 0 +0xE054 0x73CF # 0 +0xE055 0x811A # 0 +0xE056 0x89BA # 0 +0xE057 0x89D2 # 0 +0xE058 0x95A3 # 0 +0xE059 0x4F83 # 0 +0xE05A 0x520A # 0 +0xE05B 0x58BE # 0 +0xE05C 0x5978 # 0 +0xE05D 0x59E6 # 0 +0xE05E 0x5E72 # 0 +0xE05F 0x5E79 # 0 +0xE060 0x61C7 # 0 +0xE061 0x63C0 # 0 +0xE062 0x6746 # 0 +0xE063 0x67EC # 0 +0xE064 0x687F # 0 +0xE065 0x6F97 # 0 +0xE066 0x764E # 0 +0xE067 0x770B # 0 +0xE068 0x78F5 # 0 +0xE069 0x7A08 # 0 +0xE06A 0x7AFF # 0 +0xE06B 0x7C21 # 0 +0xE06C 0x809D # 0 +0xE06D 0x826E # 0 +0xE06E 0x8271 # 0 +0xE06F 0x8AEB # 0 +0xE070 0x9593 # 0 +0xE071 0x4E6B # 0 +0xE072 0x559D # 0 +0xE073 0x66F7 # 0 +0xE074 0x6E34 # 0 +0xE075 0x78A3 # 0 +0xE076 0x7AED # 0 +0xE077 0x845B # 0 +0xE078 0x8910 # 0 +0xE079 0x874E # 0 +0xE07A 0x97A8 # 0 +0xE07B 0x52D8 # 0 +0xE07C 0x574E # 0 +0xE07D 0x582A # 0 +0xE07E 0x5D4C # 0 +0xE091 0x611F # 0 +0xE092 0x61BE # 0 +0xE093 0x6221 # 0 +0xE094 0x6562 # 0 +0xE095 0x67D1 # 0 +0xE096 0x6A44 # 0 +0xE097 0x6E1B # 0 +0xE098 0x7518 # 0 +0xE099 0x75B3 # 0 +0xE09A 0x76E3 # 0 +0xE09B 0x77B0 # 0 +0xE09C 0x7D3A # 0 +0xE09D 0x90AF # 0 +0xE09E 0x9451 # 0 +0xE09F 0x9452 # 0 +0xE0A0 0x9F95 # 0 +0xE0A1 0x5323 # 0 +0xE0A2 0x5CAC # 0 +0xE0A3 0x7532 # 0 +0xE0A4 0x80DB # 0 +0xE0A5 0x9240 # 0 +0xE0A6 0x9598 # 0 +0xE0A7 0x525B # 0 +0xE0A8 0x5808 # 0 +0xE0A9 0x59DC # 0 +0xE0AA 0x5CA1 # 0 +0xE0AB 0x5D17 # 0 +0xE0AC 0x5EB7 # 0 +0xE0AD 0x5F3A # 0 +0xE0AE 0x5F4A # 0 +0xE0AF 0x6177 # 0 +0xE0B0 0x6C5F # 0 +0xE0B1 0x757A # 0 +0xE0B2 0x7586 # 0 +0xE0B3 0x7CE0 # 0 +0xE0B4 0x7D73 # 0 +0xE0B5 0x7DB1 # 0 +0xE0B6 0x7F8C # 0 +0xE0B7 0x8154 # 0 +0xE0B8 0x8221 # 0 +0xE0B9 0x8591 # 0 +0xE0BA 0x8941 # 0 +0xE0BB 0x8B1B # 0 +0xE0BC 0x92FC # 0 +0xE0BD 0x964D # 0 +0xE0BE 0x9C47 # 0 +0xE0BF 0x4ECB # 0 +0xE0C0 0x4EF7 # 0 +0xE0C1 0x500B # 0 +0xE0C2 0x51F1 # 0 +0xE0C3 0x584F # 0 +0xE0C4 0x6137 # 0 +0xE0C5 0x613E # 0 +0xE0C6 0x6168 # 0 +0xE0C7 0x6539 # 0 +0xE0C8 0x69EA # 0 +0xE0C9 0x6F11 # 0 +0xE0CA 0x75A5 # 0 +0xE0CB 0x7686 # 0 +0xE0CC 0x76D6 # 0 +0xE0CD 0x7B87 # 0 +0xE0CE 0x82A5 # 0 +0xE0CF 0x84CB # 0 +0xE0D0 0xF900 # 0 +0xE0D1 0x93A7 # 0 +0xE0D2 0x958B # 0 +0xE0D3 0x5580 # 0 +0xE0D4 0x5BA2 # 0 +0xE0D5 0x5751 # 0 +0xE0D6 0xF901 # 0 +0xE0D7 0x7CB3 # 0 +0xE0D8 0x7FB9 # 0 +0xE0D9 0x91B5 # 0 +0xE0DA 0x5028 # 0 +0xE0DB 0x53BB # 0 +0xE0DC 0x5C45 # 0 +0xE0DD 0x5DE8 # 0 +0xE0DE 0x62D2 # 0 +0xE0DF 0x636E # 0 +0xE0E0 0x64DA # 0 +0xE0E1 0x64E7 # 0 +0xE0E2 0x6E20 # 0 +0xE0E3 0x70AC # 0 +0xE0E4 0x795B # 0 +0xE0E5 0x8DDD # 0 +0xE0E6 0x8E1E # 0 +0xE0E7 0xF902 # 0 +0xE0E8 0x907D # 0 +0xE0E9 0x9245 # 0 +0xE0EA 0x92F8 # 0 +0xE0EB 0x4E7E # 0 +0xE0EC 0x4EF6 # 0 +0xE0ED 0x5065 # 0 +0xE0EE 0x5DFE # 0 +0xE0EF 0x5EFA # 0 +0xE0F0 0x6106 # 0 +0xE0F1 0x6957 # 0 +0xE0F2 0x8171 # 0 +0xE0F3 0x8654 # 0 +0xE0F4 0x8E47 # 0 +0xE0F5 0x9375 # 0 +0xE0F6 0x9A2B # 0 +0xE0F7 0x4E5E # 0 +0xE0F8 0x5091 # 0 +0xE0F9 0x6770 # 0 +0xE0FA 0x6840 # 0 +0xE0FB 0x5109 # 0 +0xE0FC 0x528D # 0 +0xE0FD 0x5292 # 0 +0xE0FE 0x6AA2 # 0 +0xE131 0x77BC # 0 +0xE132 0x9210 # 0 +0xE133 0x9ED4 # 0 +0xE134 0x52AB # 0 +0xE135 0x602F # 0 +0xE136 0x8FF2 # 0 +0xE137 0x5048 # 0 +0xE138 0x61A9 # 0 +0xE139 0x63ED # 0 +0xE13A 0x64CA # 0 +0xE13B 0x683C # 0 +0xE13C 0x6A84 # 0 +0xE13D 0x6FC0 # 0 +0xE13E 0x8188 # 0 +0xE13F 0x89A1 # 0 +0xE140 0x9694 # 0 +0xE141 0x5805 # 0 +0xE142 0x727D # 0 +0xE143 0x72AC # 0 +0xE144 0x7504 # 0 +0xE145 0x7D79 # 0 +0xE146 0x7E6D # 0 +0xE147 0x80A9 # 0 +0xE148 0x898B # 0 +0xE149 0x8B74 # 0 +0xE14A 0x9063 # 0 +0xE14B 0x9D51 # 0 +0xE14C 0x6289 # 0 +0xE14D 0x6C7A # 0 +0xE14E 0x6F54 # 0 +0xE14F 0x7D50 # 0 +0xE150 0x7F3A # 0 +0xE151 0x8A23 # 0 +0xE152 0x517C # 0 +0xE153 0x614A # 0 +0xE154 0x7B9D # 0 +0xE155 0x8B19 # 0 +0xE156 0x9257 # 0 +0xE157 0x938C # 0 +0xE158 0x4EAC # 0 +0xE159 0x4FD3 # 0 +0xE15A 0x501E # 0 +0xE15B 0x50BE # 0 +0xE15C 0x5106 # 0 +0xE15D 0x52C1 # 0 +0xE15E 0x52CD # 0 +0xE15F 0x537F # 0 +0xE160 0x5770 # 0 +0xE161 0x5883 # 0 +0xE162 0x5E9A # 0 +0xE163 0x5F91 # 0 +0xE164 0x6176 # 0 +0xE165 0x61AC # 0 +0xE166 0x64CE # 0 +0xE167 0x656C # 0 +0xE168 0x666F # 0 +0xE169 0x66BB # 0 +0xE16A 0x66F4 # 0 +0xE16B 0x6897 # 0 +0xE16C 0x6D87 # 0 +0xE16D 0x7085 # 0 +0xE16E 0x70F1 # 0 +0xE16F 0x749F # 0 +0xE170 0x74A5 # 0 +0xE171 0x74CA # 0 +0xE172 0x75D9 # 0 +0xE173 0x786C # 0 +0xE174 0x78EC # 0 +0xE175 0x7ADF # 0 +0xE176 0x7AF6 # 0 +0xE177 0x7D45 # 0 +0xE178 0x7D93 # 0 +0xE179 0x8015 # 0 +0xE17A 0x803F # 0 +0xE17B 0x811B # 0 +0xE17C 0x8396 # 0 +0xE17D 0x8B66 # 0 +0xE17E 0x8F15 # 0 +0xE191 0x9015 # 0 +0xE192 0x93E1 # 0 +0xE193 0x9803 # 0 +0xE194 0x9838 # 0 +0xE195 0x9A5A # 0 +0xE196 0x9BE8 # 0 +0xE197 0x4FC2 # 0 +0xE198 0x5553 # 0 +0xE199 0x583A # 0 +0xE19A 0x5951 # 0 +0xE19B 0x5B63 # 0 +0xE19C 0x5C46 # 0 +0xE19D 0x60B8 # 0 +0xE19E 0x6212 # 0 +0xE19F 0x6842 # 0 +0xE1A0 0x68B0 # 0 +0xE1A1 0x68E8 # 0 +0xE1A2 0x6EAA # 0 +0xE1A3 0x754C # 0 +0xE1A4 0x7678 # 0 +0xE1A5 0x78CE # 0 +0xE1A6 0x7A3D # 0 +0xE1A7 0x7CFB # 0 +0xE1A8 0x7E6B # 0 +0xE1A9 0x7E7C # 0 +0xE1AA 0x8A08 # 0 +0xE1AB 0x8AA1 # 0 +0xE1AC 0x8C3F # 0 +0xE1AD 0x968E # 0 +0xE1AE 0x9DC4 # 0 +0xE1AF 0x53E4 # 0 +0xE1B0 0x53E9 # 0 +0xE1B1 0x544A # 0 +0xE1B2 0x5471 # 0 +0xE1B3 0x56FA # 0 +0xE1B4 0x59D1 # 0 +0xE1B5 0x5B64 # 0 +0xE1B6 0x5C3B # 0 +0xE1B7 0x5EAB # 0 +0xE1B8 0x62F7 # 0 +0xE1B9 0x6537 # 0 +0xE1BA 0x6545 # 0 +0xE1BB 0x6572 # 0 +0xE1BC 0x66A0 # 0 +0xE1BD 0x67AF # 0 +0xE1BE 0x69C1 # 0 +0xE1BF 0x6CBD # 0 +0xE1C0 0x75FC # 0 +0xE1C1 0x7690 # 0 +0xE1C2 0x777E # 0 +0xE1C3 0x7A3F # 0 +0xE1C4 0x7F94 # 0 +0xE1C5 0x8003 # 0 +0xE1C6 0x80A1 # 0 +0xE1C7 0x818F # 0 +0xE1C8 0x82E6 # 0 +0xE1C9 0x82FD # 0 +0xE1CA 0x83F0 # 0 +0xE1CB 0x85C1 # 0 +0xE1CC 0x8831 # 0 +0xE1CD 0x88B4 # 0 +0xE1CE 0x8AA5 # 0 +0xE1CF 0xF903 # 0 +0xE1D0 0x8F9C # 0 +0xE1D1 0x932E # 0 +0xE1D2 0x96C7 # 0 +0xE1D3 0x9867 # 0 +0xE1D4 0x9AD8 # 0 +0xE1D5 0x9F13 # 0 +0xE1D6 0x54ED # 0 +0xE1D7 0x659B # 0 +0xE1D8 0x66F2 # 0 +0xE1D9 0x688F # 0 +0xE1DA 0x7A40 # 0 +0xE1DB 0x8C37 # 0 +0xE1DC 0x9D60 # 0 +0xE1DD 0x56F0 # 0 +0xE1DE 0x5764 # 0 +0xE1DF 0x5D11 # 0 +0xE1E0 0x6606 # 0 +0xE1E1 0x68B1 # 0 +0xE1E2 0x68CD # 0 +0xE1E3 0x6EFE # 0 +0xE1E4 0x7428 # 0 +0xE1E5 0x889E # 0 +0xE1E6 0x9BE4 # 0 +0xE1E7 0x6C68 # 0 +0xE1E8 0xF904 # 0 +0xE1E9 0x9AA8 # 0 +0xE1EA 0x4F9B # 0 +0xE1EB 0x516C # 0 +0xE1EC 0x5171 # 0 +0xE1ED 0x529F # 0 +0xE1EE 0x5B54 # 0 +0xE1EF 0x5DE5 # 0 +0xE1F0 0x6050 # 0 +0xE1F1 0x606D # 0 +0xE1F2 0x62F1 # 0 +0xE1F3 0x63A7 # 0 +0xE1F4 0x653B # 0 +0xE1F5 0x73D9 # 0 +0xE1F6 0x7A7A # 0 +0xE1F7 0x86A3 # 0 +0xE1F8 0x8CA2 # 0 +0xE1F9 0x978F # 0 +0xE1FA 0x4E32 # 0 +0xE1FB 0x5BE1 # 0 +0xE1FC 0x6208 # 0 +0xE1FD 0x679C # 0 +0xE1FE 0x74DC # 0 +0xE231 0x79D1 # 0 +0xE232 0x83D3 # 0 +0xE233 0x8A87 # 0 +0xE234 0x8AB2 # 0 +0xE235 0x8DE8 # 0 +0xE236 0x904E # 0 +0xE237 0x934B # 0 +0xE238 0x9846 # 0 +0xE239 0x5ED3 # 0 +0xE23A 0x69E8 # 0 +0xE23B 0x85FF # 0 +0xE23C 0x90ED # 0 +0xE23D 0xF905 # 0 +0xE23E 0x51A0 # 0 +0xE23F 0x5B98 # 0 +0xE240 0x5BEC # 0 +0xE241 0x6163 # 0 +0xE242 0x68FA # 0 +0xE243 0x6B3E # 0 +0xE244 0x704C # 0 +0xE245 0x742F # 0 +0xE246 0x74D8 # 0 +0xE247 0x7BA1 # 0 +0xE248 0x7F50 # 0 +0xE249 0x83C5 # 0 +0xE24A 0x89C0 # 0 +0xE24B 0x8CAB # 0 +0xE24C 0x95DC # 0 +0xE24D 0x9928 # 0 +0xE24E 0x522E # 0 +0xE24F 0x605D # 0 +0xE250 0x62EC # 0 +0xE251 0x9002 # 0 +0xE252 0x4F8A # 0 +0xE253 0x5149 # 0 +0xE254 0x5321 # 0 +0xE255 0x58D9 # 0 +0xE256 0x5EE3 # 0 +0xE257 0x66E0 # 0 +0xE258 0x6D38 # 0 +0xE259 0x709A # 0 +0xE25A 0x72C2 # 0 +0xE25B 0x73D6 # 0 +0xE25C 0x7B50 # 0 +0xE25D 0x80F1 # 0 +0xE25E 0x945B # 0 +0xE25F 0x5366 # 0 +0xE260 0x639B # 0 +0xE261 0x7F6B # 0 +0xE262 0x4E56 # 0 +0xE263 0x5080 # 0 +0xE264 0x584A # 0 +0xE265 0x58DE # 0 +0xE266 0x602A # 0 +0xE267 0x6127 # 0 +0xE268 0x62D0 # 0 +0xE269 0x69D0 # 0 +0xE26A 0x9B41 # 0 +0xE26B 0x5B8F # 0 +0xE26C 0x7D18 # 0 +0xE26D 0x80B1 # 0 +0xE26E 0x8F5F # 0 +0xE26F 0x4EA4 # 0 +0xE270 0x50D1 # 0 +0xE271 0x54AC # 0 +0xE272 0x55AC # 0 +0xE273 0x5B0C # 0 +0xE274 0x5DA0 # 0 +0xE275 0x5DE7 # 0 +0xE276 0x652A # 0 +0xE277 0x654E # 0 +0xE278 0x6821 # 0 +0xE279 0x6A4B # 0 +0xE27A 0x72E1 # 0 +0xE27B 0x768E # 0 +0xE27C 0x77EF # 0 +0xE27D 0x7D5E # 0 +0xE27E 0x7FF9 # 0 +0xE291 0x81A0 # 0 +0xE292 0x854E # 0 +0xE293 0x86DF # 0 +0xE294 0x8F03 # 0 +0xE295 0x8F4E # 0 +0xE296 0x90CA # 0 +0xE297 0x9903 # 0 +0xE298 0x9A55 # 0 +0xE299 0x9BAB # 0 +0xE29A 0x4E18 # 0 +0xE29B 0x4E45 # 0 +0xE29C 0x4E5D # 0 +0xE29D 0x4EC7 # 0 +0xE29E 0x4FF1 # 0 +0xE29F 0x5177 # 0 +0xE2A0 0x52FE # 0 +0xE2A1 0x5340 # 0 +0xE2A2 0x53E3 # 0 +0xE2A3 0x53E5 # 0 +0xE2A4 0x548E # 0 +0xE2A5 0x5614 # 0 +0xE2A6 0x5775 # 0 +0xE2A7 0x57A2 # 0 +0xE2A8 0x5BC7 # 0 +0xE2A9 0x5D87 # 0 +0xE2AA 0x5ED0 # 0 +0xE2AB 0x61FC # 0 +0xE2AC 0x62D8 # 0 +0xE2AD 0x6551 # 0 +0xE2AE 0x67B8 # 0 +0xE2AF 0x67E9 # 0 +0xE2B0 0x69CB # 0 +0xE2B1 0x6B50 # 0 +0xE2B2 0x6BC6 # 0 +0xE2B3 0x6BEC # 0 +0xE2B4 0x6C42 # 0 +0xE2B5 0x6E9D # 0 +0xE2B6 0x7078 # 0 +0xE2B7 0x72D7 # 0 +0xE2B8 0x7396 # 0 +0xE2B9 0x7403 # 0 +0xE2BA 0x77BF # 0 +0xE2BB 0x77E9 # 0 +0xE2BC 0x7A76 # 0 +0xE2BD 0x7D7F # 0 +0xE2BE 0x8009 # 0 +0xE2BF 0x81FC # 0 +0xE2C0 0x8205 # 0 +0xE2C1 0x820A # 0 +0xE2C2 0x82DF # 0 +0xE2C3 0x8862 # 0 +0xE2C4 0x8B33 # 0 +0xE2C5 0x8CFC # 0 +0xE2C6 0x8EC0 # 0 +0xE2C7 0x9011 # 0 +0xE2C8 0x90B1 # 0 +0xE2C9 0x9264 # 0 +0xE2CA 0x92B6 # 0 +0xE2CB 0x99D2 # 0 +0xE2CC 0x9A45 # 0 +0xE2CD 0x9CE9 # 0 +0xE2CE 0x9DD7 # 0 +0xE2CF 0x9F9C # 0 +0xE2D0 0x570B # 0 +0xE2D1 0x5C40 # 0 +0xE2D2 0x83CA # 0 +0xE2D3 0x97A0 # 0 +0xE2D4 0x97AB # 0 +0xE2D5 0x9EB4 # 0 +0xE2D6 0x541B # 0 +0xE2D7 0x7A98 # 0 +0xE2D8 0x7FA4 # 0 +0xE2D9 0x88D9 # 0 +0xE2DA 0x8ECD # 0 +0xE2DB 0x90E1 # 0 +0xE2DC 0x5800 # 0 +0xE2DD 0x5C48 # 0 +0xE2DE 0x6398 # 0 +0xE2DF 0x7A9F # 0 +0xE2E0 0x5BAE # 0 +0xE2E1 0x5F13 # 0 +0xE2E2 0x7A79 # 0 +0xE2E3 0x7AAE # 0 +0xE2E4 0x828E # 0 +0xE2E5 0x8EAC # 0 +0xE2E6 0x5026 # 0 +0xE2E7 0x5238 # 0 +0xE2E8 0x52F8 # 0 +0xE2E9 0x5377 # 0 +0xE2EA 0x5708 # 0 +0xE2EB 0x62F3 # 0 +0xE2EC 0x6372 # 0 +0xE2ED 0x6B0A # 0 +0xE2EE 0x6DC3 # 0 +0xE2EF 0x7737 # 0 +0xE2F0 0x53A5 # 0 +0xE2F1 0x7357 # 0 +0xE2F2 0x8568 # 0 +0xE2F3 0x8E76 # 0 +0xE2F4 0x95D5 # 0 +0xE2F5 0x673A # 0 +0xE2F6 0x6AC3 # 0 +0xE2F7 0x6F70 # 0 +0xE2F8 0x8A6D # 0 +0xE2F9 0x8ECC # 0 +0xE2FA 0x994B # 0 +0xE2FB 0xF906 # 0 +0xE2FC 0x6677 # 0 +0xE2FD 0x6B78 # 0 +0xE2FE 0x8CB4 # 0 +0xE331 0x9B3C # 0 +0xE332 0xF907 # 0 +0xE333 0x53EB # 0 +0xE334 0x572D # 0 +0xE335 0x594E # 0 +0xE336 0x63C6 # 0 +0xE337 0x69FB # 0 +0xE338 0x73EA # 0 +0xE339 0x7845 # 0 +0xE33A 0x7ABA # 0 +0xE33B 0x7AC5 # 0 +0xE33C 0x7CFE # 0 +0xE33D 0x8475 # 0 +0xE33E 0x898F # 0 +0xE33F 0x8D73 # 0 +0xE340 0x9035 # 0 +0xE341 0x95A8 # 0 +0xE342 0x52FB # 0 +0xE343 0x5747 # 0 +0xE344 0x7547 # 0 +0xE345 0x7B60 # 0 +0xE346 0x83CC # 0 +0xE347 0x921E # 0 +0xE348 0xF908 # 0 +0xE349 0x6A58 # 0 +0xE34A 0x514B # 0 +0xE34B 0x524B # 0 +0xE34C 0x5287 # 0 +0xE34D 0x621F # 0 +0xE34E 0x68D8 # 0 +0xE34F 0x6975 # 0 +0xE350 0x9699 # 0 +0xE351 0x50C5 # 0 +0xE352 0x52A4 # 0 +0xE353 0x52E4 # 0 +0xE354 0x61C3 # 0 +0xE355 0x65A4 # 0 +0xE356 0x6839 # 0 +0xE357 0x69FF # 0 +0xE358 0x747E # 0 +0xE359 0x7B4B # 0 +0xE35A 0x82B9 # 0 +0xE35B 0x83EB # 0 +0xE35C 0x89B2 # 0 +0xE35D 0x8B39 # 0 +0xE35E 0x8FD1 # 0 +0xE35F 0x9949 # 0 +0xE360 0xF909 # 0 +0xE361 0x4ECA # 0 +0xE362 0x5997 # 0 +0xE363 0x64D2 # 0 +0xE364 0x6611 # 0 +0xE365 0x6A8E # 0 +0xE366 0x7434 # 0 +0xE367 0x7981 # 0 +0xE368 0x79BD # 0 +0xE369 0x82A9 # 0 +0xE36A 0x887E # 0 +0xE36B 0x887F # 0 +0xE36C 0x895F # 0 +0xE36D 0xF90A # 0 +0xE36E 0x9326 # 0 +0xE36F 0x4F0B # 0 +0xE370 0x53CA # 0 +0xE371 0x6025 # 0 +0xE372 0x6271 # 0 +0xE373 0x6C72 # 0 +0xE374 0x7D1A # 0 +0xE375 0x7D66 # 0 +0xE376 0x4E98 # 0 +0xE377 0x5162 # 0 +0xE378 0x77DC # 0 +0xE379 0x80AF # 0 +0xE37A 0x4F01 # 0 +0xE37B 0x4F0E # 0 +0xE37C 0x5176 # 0 +0xE37D 0x5180 # 0 +0xE37E 0x55DC # 0 +0xE391 0x5668 # 0 +0xE392 0x573B # 0 +0xE393 0x57FA # 0 +0xE394 0x57FC # 0 +0xE395 0x5914 # 0 +0xE396 0x5947 # 0 +0xE397 0x5993 # 0 +0xE398 0x5BC4 # 0 +0xE399 0x5C90 # 0 +0xE39A 0x5D0E # 0 +0xE39B 0x5DF1 # 0 +0xE39C 0x5E7E # 0 +0xE39D 0x5FCC # 0 +0xE39E 0x6280 # 0 +0xE39F 0x65D7 # 0 +0xE3A0 0x65E3 # 0 +0xE3A1 0x671E # 0 +0xE3A2 0x671F # 0 +0xE3A3 0x675E # 0 +0xE3A4 0x68CB # 0 +0xE3A5 0x68C4 # 0 +0xE3A6 0x6A5F # 0 +0xE3A7 0x6B3A # 0 +0xE3A8 0x6C23 # 0 +0xE3A9 0x6C7D # 0 +0xE3AA 0x6C82 # 0 +0xE3AB 0x6DC7 # 0 +0xE3AC 0x7398 # 0 +0xE3AD 0x7426 # 0 +0xE3AE 0x742A # 0 +0xE3AF 0x7482 # 0 +0xE3B0 0x74A3 # 0 +0xE3B1 0x7578 # 0 +0xE3B2 0x757F # 0 +0xE3B3 0x7881 # 0 +0xE3B4 0x78EF # 0 +0xE3B5 0x7941 # 0 +0xE3B6 0x7947 # 0 +0xE3B7 0x7948 # 0 +0xE3B8 0x797A # 0 +0xE3B9 0x7B95 # 0 +0xE3BA 0x7D00 # 0 +0xE3BB 0x7DBA # 0 +0xE3BC 0x7F88 # 0 +0xE3BD 0x8006 # 0 +0xE3BE 0x802D # 0 +0xE3BF 0x808C # 0 +0xE3C0 0x8A18 # 0 +0xE3C1 0x8B4F # 0 +0xE3C2 0x8C48 # 0 +0xE3C3 0x8D77 # 0 +0xE3C4 0x9321 # 0 +0xE3C5 0x9324 # 0 +0xE3C6 0x98E2 # 0 +0xE3C7 0x9951 # 0 +0xE3C8 0x9A0E # 0 +0xE3C9 0x9A0F # 0 +0xE3CA 0x9A65 # 0 +0xE3CB 0x9E92 # 0 +0xE3CC 0x7DCA # 0 +0xE3CD 0x4F76 # 0 +0xE3CE 0x5409 # 0 +0xE3CF 0x62EE # 0 +0xE3D0 0x6854 # 0 +0xE3D1 0x91D1 # 0 +0xE3D2 0x55AB # 0 +0xE3D3 0x513A # 0 +0xE3D4 0xF90B # 0 +0xE3D5 0xF90C # 0 +0xE3D6 0x5A1C # 0 +0xE3D7 0x61E6 # 0 +0xE3D8 0xF90D # 0 +0xE3D9 0x62CF # 0 +0xE3DA 0x62FF # 0 +0xE3DB 0xF90E # 0 +0xE3DC 0xF90F # 0 +0xE3DD 0xF910 # 0 +0xE3DE 0xF911 # 0 +0xE3DF 0xF912 # 0 +0xE3E0 0xF913 # 0 +0xE3E1 0x90A3 # 0 +0xE3E2 0xF914 # 0 +0xE3E3 0xF915 # 0 +0xE3E4 0xF916 # 0 +0xE3E5 0xF917 # 0 +0xE3E6 0xF918 # 0 +0xE3E7 0x8AFE # 0 +0xE3E8 0xF919 # 0 +0xE3E9 0xF91A # 0 +0xE3EA 0xF91B # 0 +0xE3EB 0xF91C # 0 +0xE3EC 0x6696 # 0 +0xE3ED 0xF91D # 0 +0xE3EE 0x7156 # 0 +0xE3EF 0xF91E # 0 +0xE3F0 0xF91F # 0 +0xE3F1 0x96E3 # 0 +0xE3F2 0xF920 # 0 +0xE3F3 0x634F # 0 +0xE3F4 0x637A # 0 +0xE3F5 0x5357 # 0 +0xE3F6 0xF921 # 0 +0xE3F7 0x678F # 0 +0xE3F8 0x6960 # 0 +0xE3F9 0x6E73 # 0 +0xE3FA 0xF922 # 0 +0xE3FB 0x7537 # 0 +0xE3FC 0xF923 # 0 +0xE3FD 0xF924 # 0 +0xE3FE 0xF925 # 0 +0xE431 0x7D0D # 0 +0xE432 0xF926 # 0 +0xE433 0xF927 # 0 +0xE434 0x8872 # 0 +0xE435 0x56CA # 0 +0xE436 0x5A18 # 0 +0xE437 0xF928 # 0 +0xE438 0xF929 # 0 +0xE439 0xF92A # 0 +0xE43A 0xF92B # 0 +0xE43B 0xF92C # 0 +0xE43C 0x4E43 # 0 +0xE43D 0xF92D # 0 +0xE43E 0x5167 # 0 +0xE43F 0x5948 # 0 +0xE440 0x67F0 # 0 +0xE441 0x8010 # 0 +0xE442 0xF92E # 0 +0xE443 0x5973 # 0 +0xE444 0x5E74 # 0 +0xE445 0x649A # 0 +0xE446 0x79CA # 0 +0xE447 0x5FF5 # 0 +0xE448 0x606C # 0 +0xE449 0x62C8 # 0 +0xE44A 0x637B # 0 +0xE44B 0x5BE7 # 0 +0xE44C 0x5BD7 # 0 +0xE44D 0x52AA # 0 +0xE44E 0xF92F # 0 +0xE44F 0x5974 # 0 +0xE450 0x5F29 # 0 +0xE451 0x6012 # 0 +0xE452 0xF930 # 0 +0xE453 0xF931 # 0 +0xE454 0xF932 # 0 +0xE455 0x7459 # 0 +0xE456 0xF933 # 0 +0xE457 0xF934 # 0 +0xE458 0xF935 # 0 +0xE459 0xF936 # 0 +0xE45A 0xF937 # 0 +0xE45B 0xF938 # 0 +0xE45C 0x99D1 # 0 +0xE45D 0xF939 # 0 +0xE45E 0xF93A # 0 +0xE45F 0xF93B # 0 +0xE460 0xF93C # 0 +0xE461 0xF93D # 0 +0xE462 0xF93E # 0 +0xE463 0xF93F # 0 +0xE464 0xF940 # 0 +0xE465 0xF941 # 0 +0xE466 0xF942 # 0 +0xE467 0xF943 # 0 +0xE468 0x6FC3 # 0 +0xE469 0xF944 # 0 +0xE46A 0xF945 # 0 +0xE46B 0x81BF # 0 +0xE46C 0x8FB2 # 0 +0xE46D 0x60F1 # 0 +0xE46E 0xF946 # 0 +0xE46F 0xF947 # 0 +0xE470 0x8166 # 0 +0xE471 0xF948 # 0 +0xE472 0xF949 # 0 +0xE473 0x5C3F # 0 +0xE474 0xF94A # 0 +0xE475 0xF94B # 0 +0xE476 0xF94C # 0 +0xE477 0xF94D # 0 +0xE478 0xF94E # 0 +0xE479 0xF94F # 0 +0xE47A 0xF950 # 0 +0xE47B 0xF951 # 0 +0xE47C 0x5AE9 # 0 +0xE47D 0x8A25 # 0 +0xE47E 0x677B # 0 +0xE491 0x7D10 # 0 +0xE492 0xF952 # 0 +0xE493 0xF953 # 0 +0xE494 0xF954 # 0 +0xE495 0xF955 # 0 +0xE496 0xF956 # 0 +0xE497 0xF957 # 0 +0xE498 0x80FD # 0 +0xE499 0xF958 # 0 +0xE49A 0xF959 # 0 +0xE49B 0x5C3C # 0 +0xE49C 0x6CE5 # 0 +0xE49D 0x533F # 0 +0xE49E 0x6EBA # 0 +0xE49F 0x591A # 0 +0xE4A0 0x8336 # 0 +0xE4A1 0x4E39 # 0 +0xE4A2 0x4EB6 # 0 +0xE4A3 0x4F46 # 0 +0xE4A4 0x55AE # 0 +0xE4A5 0x5718 # 0 +0xE4A6 0x58C7 # 0 +0xE4A7 0x5F56 # 0 +0xE4A8 0x65B7 # 0 +0xE4A9 0x65E6 # 0 +0xE4AA 0x6A80 # 0 +0xE4AB 0x6BB5 # 0 +0xE4AC 0x6E4D # 0 +0xE4AD 0x77ED # 0 +0xE4AE 0x7AEF # 0 +0xE4AF 0x7C1E # 0 +0xE4B0 0x7DDE # 0 +0xE4B1 0x86CB # 0 +0xE4B2 0x8892 # 0 +0xE4B3 0x9132 # 0 +0xE4B4 0x935B # 0 +0xE4B5 0x64BB # 0 +0xE4B6 0x6FBE # 0 +0xE4B7 0x737A # 0 +0xE4B8 0x75B8 # 0 +0xE4B9 0x9054 # 0 +0xE4BA 0x5556 # 0 +0xE4BB 0x574D # 0 +0xE4BC 0x61BA # 0 +0xE4BD 0x64D4 # 0 +0xE4BE 0x66C7 # 0 +0xE4BF 0x6DE1 # 0 +0xE4C0 0x6E5B # 0 +0xE4C1 0x6F6D # 0 +0xE4C2 0x6FB9 # 0 +0xE4C3 0x75F0 # 0 +0xE4C4 0x8043 # 0 +0xE4C5 0x81BD # 0 +0xE4C6 0x8541 # 0 +0xE4C7 0x8983 # 0 +0xE4C8 0x8AC7 # 0 +0xE4C9 0x8B5A # 0 +0xE4CA 0x931F # 0 +0xE4CB 0x6C93 # 0 +0xE4CC 0x7553 # 0 +0xE4CD 0x7B54 # 0 +0xE4CE 0x8E0F # 0 +0xE4CF 0x905D # 0 +0xE4D0 0x5510 # 0 +0xE4D1 0x5802 # 0 +0xE4D2 0x5858 # 0 +0xE4D3 0x5E62 # 0 +0xE4D4 0x6207 # 0 +0xE4D5 0x649E # 0 +0xE4D6 0x68E0 # 0 +0xE4D7 0x7576 # 0 +0xE4D8 0x7CD6 # 0 +0xE4D9 0x87B3 # 0 +0xE4DA 0x9EE8 # 0 +0xE4DB 0x4EE3 # 0 +0xE4DC 0x5788 # 0 +0xE4DD 0x576E # 0 +0xE4DE 0x5927 # 0 +0xE4DF 0x5C0D # 0 +0xE4E0 0x5CB1 # 0 +0xE4E1 0x5E36 # 0 +0xE4E2 0x5F85 # 0 +0xE4E3 0x6234 # 0 +0xE4E4 0x64E1 # 0 +0xE4E5 0x73B3 # 0 +0xE4E6 0x81FA # 0 +0xE4E7 0x888B # 0 +0xE4E8 0x8CB8 # 0 +0xE4E9 0x968A # 0 +0xE4EA 0x9EDB # 0 +0xE4EB 0x5B85 # 0 +0xE4EC 0x5FB7 # 0 +0xE4ED 0x60B3 # 0 +0xE4EE 0x5012 # 0 +0xE4EF 0x5200 # 0 +0xE4F0 0x5230 # 0 +0xE4F1 0x5716 # 0 +0xE4F2 0x5835 # 0 +0xE4F3 0x5857 # 0 +0xE4F4 0x5C0E # 0 +0xE4F5 0x5C60 # 0 +0xE4F6 0x5CF6 # 0 +0xE4F7 0x5D8B # 0 +0xE4F8 0x5EA6 # 0 +0xE4F9 0x5F92 # 0 +0xE4FA 0x60BC # 0 +0xE4FB 0x6311 # 0 +0xE4FC 0x6389 # 0 +0xE4FD 0x6417 # 0 +0xE4FE 0x6843 # 0 +0xE531 0x68F9 # 0 +0xE532 0x6AC2 # 0 +0xE533 0x6DD8 # 0 +0xE534 0x6E21 # 0 +0xE535 0x6ED4 # 0 +0xE536 0x6FE4 # 0 +0xE537 0x71FE # 0 +0xE538 0x76DC # 0 +0xE539 0x7779 # 0 +0xE53A 0x79B1 # 0 +0xE53B 0x7A3B # 0 +0xE53C 0x8404 # 0 +0xE53D 0x89A9 # 0 +0xE53E 0x8CED # 0 +0xE53F 0x8DF3 # 0 +0xE540 0x8E48 # 0 +0xE541 0x9003 # 0 +0xE542 0x9014 # 0 +0xE543 0x9053 # 0 +0xE544 0x90FD # 0 +0xE545 0x934D # 0 +0xE546 0x9676 # 0 +0xE547 0x97DC # 0 +0xE548 0x6BD2 # 0 +0xE549 0x7006 # 0 +0xE54A 0x7258 # 0 +0xE54B 0x72A2 # 0 +0xE54C 0x7368 # 0 +0xE54D 0x7763 # 0 +0xE54E 0x79BF # 0 +0xE54F 0x7BE4 # 0 +0xE550 0x7E9B # 0 +0xE551 0x8B80 # 0 +0xE552 0x58A9 # 0 +0xE553 0x60C7 # 0 +0xE554 0x6566 # 0 +0xE555 0x65FD # 0 +0xE556 0x66BE # 0 +0xE557 0x6C8C # 0 +0xE558 0x711E # 0 +0xE559 0x71C9 # 0 +0xE55A 0x8C5A # 0 +0xE55B 0x9813 # 0 +0xE55C 0x4E6D # 0 +0xE55D 0x7A81 # 0 +0xE55E 0x4EDD # 0 +0xE55F 0x51AC # 0 +0xE560 0x51CD # 0 +0xE561 0x52D5 # 0 +0xE562 0x540C # 0 +0xE563 0x61A7 # 0 +0xE564 0x6771 # 0 +0xE565 0x6850 # 0 +0xE566 0x68DF # 0 +0xE567 0x6D1E # 0 +0xE568 0x6F7C # 0 +0xE569 0x75BC # 0 +0xE56A 0x77B3 # 0 +0xE56B 0x7AE5 # 0 +0xE56C 0x80F4 # 0 +0xE56D 0x8463 # 0 +0xE56E 0x9285 # 0 +0xE56F 0x515C # 0 +0xE570 0x6597 # 0 +0xE571 0x675C # 0 +0xE572 0x6793 # 0 +0xE573 0x75D8 # 0 +0xE574 0x7AC7 # 0 +0xE575 0x8373 # 0 +0xE576 0xF95A # 0 +0xE577 0x8C46 # 0 +0xE578 0x9017 # 0 +0xE579 0x982D # 0 +0xE57A 0x5C6F # 0 +0xE57B 0x81C0 # 0 +0xE57C 0x829A # 0 +0xE57D 0x9041 # 0 +0xE57E 0x906F # 0 +0xE591 0x920D # 0 +0xE592 0x5F97 # 0 +0xE593 0x5D9D # 0 +0xE594 0x6A59 # 0 +0xE595 0x71C8 # 0 +0xE596 0x767B # 0 +0xE597 0x7B49 # 0 +0xE598 0x85E4 # 0 +0xE599 0x8B04 # 0 +0xE59A 0x9127 # 0 +0xE59B 0x9A30 # 0 +0xE59C 0x5587 # 0 +0xE59D 0x61F6 # 0 +0xE59E 0xF95B # 0 +0xE59F 0x7669 # 0 +0xE5A0 0x7F85 # 0 +0xE5A1 0x863F # 0 +0xE5A2 0x87BA # 0 +0xE5A3 0x88F8 # 0 +0xE5A4 0x908F # 0 +0xE5A5 0xF95C # 0 +0xE5A6 0x6D1B # 0 +0xE5A7 0x70D9 # 0 +0xE5A8 0x73DE # 0 +0xE5A9 0x7D61 # 0 +0xE5AA 0x843D # 0 +0xE5AB 0xF95D # 0 +0xE5AC 0x916A # 0 +0xE5AD 0x99F1 # 0 +0xE5AE 0xF95E # 0 +0xE5AF 0x4E82 # 0 +0xE5B0 0x5375 # 0 +0xE5B1 0x6B04 # 0 +0xE5B2 0x6B12 # 0 +0xE5B3 0x703E # 0 +0xE5B4 0x721B # 0 +0xE5B5 0x862D # 0 +0xE5B6 0x9E1E # 0 +0xE5B7 0x524C # 0 +0xE5B8 0x8FA3 # 0 +0xE5B9 0x5D50 # 0 +0xE5BA 0x64E5 # 0 +0xE5BB 0x652C # 0 +0xE5BC 0x6B16 # 0 +0xE5BD 0x6FEB # 0 +0xE5BE 0x7C43 # 0 +0xE5BF 0x7E9C # 0 +0xE5C0 0x85CD # 0 +0xE5C1 0x8964 # 0 +0xE5C2 0x89BD # 0 +0xE5C3 0x62C9 # 0 +0xE5C4 0x81D8 # 0 +0xE5C5 0x881F # 0 +0xE5C6 0x5ECA # 0 +0xE5C7 0x6717 # 0 +0xE5C8 0x6D6A # 0 +0xE5C9 0x72FC # 0 +0xE5CA 0x7405 # 0 +0xE5CB 0x746F # 0 +0xE5CC 0x8782 # 0 +0xE5CD 0x90DE # 0 +0xE5CE 0x4F86 # 0 +0xE5CF 0x5D0D # 0 +0xE5D0 0x5FA0 # 0 +0xE5D1 0x840A # 0 +0xE5D2 0x51B7 # 0 +0xE5D3 0x63A0 # 0 +0xE5D4 0x7565 # 0 +0xE5D5 0x4EAE # 0 +0xE5D6 0x5006 # 0 +0xE5D7 0x5169 # 0 +0xE5D8 0x51C9 # 0 +0xE5D9 0x6881 # 0 +0xE5DA 0x6A11 # 0 +0xE5DB 0x7CAE # 0 +0xE5DC 0x7CB1 # 0 +0xE5DD 0x7CE7 # 0 +0xE5DE 0x826F # 0 +0xE5DF 0x8AD2 # 0 +0xE5E0 0x8F1B # 0 +0xE5E1 0x91CF # 0 +0xE5E2 0x4FB6 # 0 +0xE5E3 0x5137 # 0 +0xE5E4 0x52F5 # 0 +0xE5E5 0x5442 # 0 +0xE5E6 0x5EEC # 0 +0xE5E7 0x616E # 0 +0xE5E8 0x623E # 0 +0xE5E9 0x65C5 # 0 +0xE5EA 0x6ADA # 0 +0xE5EB 0x6FFE # 0 +0xE5EC 0x792A # 0 +0xE5ED 0x85DC # 0 +0xE5EE 0x8823 # 0 +0xE5EF 0x95AD # 0 +0xE5F0 0x9A62 # 0 +0xE5F1 0x9A6A # 0 +0xE5F2 0x9E97 # 0 +0xE5F3 0x9ECE # 0 +0xE5F4 0x529B # 0 +0xE5F5 0x66C6 # 0 +0xE5F6 0x6B77 # 0 +0xE5F7 0x701D # 0 +0xE5F8 0x792B # 0 +0xE5F9 0x8F62 # 0 +0xE5FA 0x9742 # 0 +0xE5FB 0x6190 # 0 +0xE5FC 0x6200 # 0 +0xE5FD 0x6523 # 0 +0xE5FE 0x6F23 # 0 +0xE631 0x7149 # 0 +0xE632 0x7489 # 0 +0xE633 0x7DF4 # 0 +0xE634 0x806F # 0 +0xE635 0x84EE # 0 +0xE636 0x8F26 # 0 +0xE637 0x9023 # 0 +0xE638 0x934A # 0 +0xE639 0x51BD # 0 +0xE63A 0x5217 # 0 +0xE63B 0x52A3 # 0 +0xE63C 0x6D0C # 0 +0xE63D 0x70C8 # 0 +0xE63E 0x88C2 # 0 +0xE63F 0x5EC9 # 0 +0xE640 0x6582 # 0 +0xE641 0x6BAE # 0 +0xE642 0x6FC2 # 0 +0xE643 0x7C3E # 0 +0xE644 0x7375 # 0 +0xE645 0x4EE4 # 0 +0xE646 0x4F36 # 0 +0xE647 0x56F9 # 0 +0xE648 0xF95F # 0 +0xE649 0x5CBA # 0 +0xE64A 0x5DBA # 0 +0xE64B 0x601C # 0 +0xE64C 0x73B2 # 0 +0xE64D 0x7B2D # 0 +0xE64E 0x7F9A # 0 +0xE64F 0x7FCE # 0 +0xE650 0x8046 # 0 +0xE651 0x901E # 0 +0xE652 0x9234 # 0 +0xE653 0x96F6 # 0 +0xE654 0x9748 # 0 +0xE655 0x9818 # 0 +0xE656 0x9F61 # 0 +0xE657 0x4F8B # 0 +0xE658 0x6FA7 # 0 +0xE659 0x79AE # 0 +0xE65A 0x91B4 # 0 +0xE65B 0x96B7 # 0 +0xE65C 0x52DE # 0 +0xE65D 0xF960 # 0 +0xE65E 0x6488 # 0 +0xE65F 0x64C4 # 0 +0xE660 0x6AD3 # 0 +0xE661 0x6F5E # 0 +0xE662 0x7018 # 0 +0xE663 0x7210 # 0 +0xE664 0x76E7 # 0 +0xE665 0x8001 # 0 +0xE666 0x8606 # 0 +0xE667 0x865C # 0 +0xE668 0x8DEF # 0 +0xE669 0x8F05 # 0 +0xE66A 0x9732 # 0 +0xE66B 0x9B6F # 0 +0xE66C 0x9DFA # 0 +0xE66D 0x9E75 # 0 +0xE66E 0x788C # 0 +0xE66F 0x797F # 0 +0xE670 0x7DA0 # 0 +0xE671 0x83C9 # 0 +0xE672 0x9304 # 0 +0xE673 0x9E7F # 0 +0xE674 0x9E93 # 0 +0xE675 0x8AD6 # 0 +0xE676 0x58DF # 0 +0xE677 0x5F04 # 0 +0xE678 0x6727 # 0 +0xE679 0x7027 # 0 +0xE67A 0x74CF # 0 +0xE67B 0x7C60 # 0 +0xE67C 0x807E # 0 +0xE67D 0x5121 # 0 +0xE67E 0x7028 # 0 +0xE691 0x7262 # 0 +0xE692 0x78CA # 0 +0xE693 0x8CC2 # 0 +0xE694 0x8CDA # 0 +0xE695 0x8CF4 # 0 +0xE696 0x96F7 # 0 +0xE697 0x4E86 # 0 +0xE698 0x50DA # 0 +0xE699 0x5BEE # 0 +0xE69A 0x5ED6 # 0 +0xE69B 0x6599 # 0 +0xE69C 0x71CE # 0 +0xE69D 0x7642 # 0 +0xE69E 0x77AD # 0 +0xE69F 0x804A # 0 +0xE6A0 0x84FC # 0 +0xE6A1 0x907C # 0 +0xE6A2 0x9B27 # 0 +0xE6A3 0x9F8D # 0 +0xE6A4 0x58D8 # 0 +0xE6A5 0x5A41 # 0 +0xE6A6 0x5C62 # 0 +0xE6A7 0x6A13 # 0 +0xE6A8 0x6DDA # 0 +0xE6A9 0x6F0F # 0 +0xE6AA 0x763B # 0 +0xE6AB 0x7D2F # 0 +0xE6AC 0x7E37 # 0 +0xE6AD 0x851E # 0 +0xE6AE 0x8938 # 0 +0xE6AF 0x93E4 # 0 +0xE6B0 0x964B # 0 +0xE6B1 0x5289 # 0 +0xE6B2 0x65D2 # 0 +0xE6B3 0x67F3 # 0 +0xE6B4 0x69B4 # 0 +0xE6B5 0x6D41 # 0 +0xE6B6 0x6E9C # 0 +0xE6B7 0x700F # 0 +0xE6B8 0x7409 # 0 +0xE6B9 0x7460 # 0 +0xE6BA 0x7559 # 0 +0xE6BB 0x7624 # 0 +0xE6BC 0x786B # 0 +0xE6BD 0x8B2C # 0 +0xE6BE 0x985E # 0 +0xE6BF 0x516D # 0 +0xE6C0 0x622E # 0 +0xE6C1 0x9678 # 0 +0xE6C2 0x4F96 # 0 +0xE6C3 0x502B # 0 +0xE6C4 0x5D19 # 0 +0xE6C5 0x6DEA # 0 +0xE6C6 0x7DB8 # 0 +0xE6C7 0x8F2A # 0 +0xE6C8 0x5F8B # 0 +0xE6C9 0x6144 # 0 +0xE6CA 0x6817 # 0 +0xE6CB 0xF961 # 0 +0xE6CC 0x9686 # 0 +0xE6CD 0x52D2 # 0 +0xE6CE 0x808B # 0 +0xE6CF 0x51DC # 0 +0xE6D0 0x51CC # 0 +0xE6D1 0x695E # 0 +0xE6D2 0x7A1C # 0 +0xE6D3 0x7DBE # 0 +0xE6D4 0x83F1 # 0 +0xE6D5 0x9675 # 0 +0xE6D6 0x4FDA # 0 +0xE6D7 0x5229 # 0 +0xE6D8 0x5398 # 0 +0xE6D9 0x540F # 0 +0xE6DA 0x550E # 0 +0xE6DB 0x5C65 # 0 +0xE6DC 0x60A7 # 0 +0xE6DD 0x674E # 0 +0xE6DE 0x68A8 # 0 +0xE6DF 0x6D6C # 0 +0xE6E0 0x7281 # 0 +0xE6E1 0x72F8 # 0 +0xE6E2 0x7406 # 0 +0xE6E3 0x7483 # 0 +0xE6E4 0xF962 # 0 +0xE6E5 0x75E2 # 0 +0xE6E6 0x7C6C # 0 +0xE6E7 0x7F79 # 0 +0xE6E8 0x7FB8 # 0 +0xE6E9 0x8389 # 0 +0xE6EA 0x88CF # 0 +0xE6EB 0x88E1 # 0 +0xE6EC 0x91CC # 0 +0xE6ED 0x91D0 # 0 +0xE6EE 0x96E2 # 0 +0xE6EF 0x9BC9 # 0 +0xE6F0 0x541D # 0 +0xE6F1 0x6F7E # 0 +0xE6F2 0x71D0 # 0 +0xE6F3 0x7498 # 0 +0xE6F4 0x85FA # 0 +0xE6F5 0x8EAA # 0 +0xE6F6 0x96A3 # 0 +0xE6F7 0x9C57 # 0 +0xE6F8 0x9E9F # 0 +0xE6F9 0x6797 # 0 +0xE6FA 0x6DCB # 0 +0xE6FB 0x7433 # 0 +0xE6FC 0x81E8 # 0 +0xE6FD 0x9716 # 0 +0xE6FE 0x782C # 0 +0xE731 0x7ACB # 0 +0xE732 0x7B20 # 0 +0xE733 0x7C92 # 0 +0xE734 0x6469 # 0 +0xE735 0x746A # 0 +0xE736 0x75F2 # 0 +0xE737 0x78BC # 0 +0xE738 0x78E8 # 0 +0xE739 0x99AC # 0 +0xE73A 0x9B54 # 0 +0xE73B 0x9EBB # 0 +0xE73C 0x5BDE # 0 +0xE73D 0x5E55 # 0 +0xE73E 0x6F20 # 0 +0xE73F 0x819C # 0 +0xE740 0x83AB # 0 +0xE741 0x9088 # 0 +0xE742 0x4E07 # 0 +0xE743 0x534D # 0 +0xE744 0x5A29 # 0 +0xE745 0x5DD2 # 0 +0xE746 0x5F4E # 0 +0xE747 0x6162 # 0 +0xE748 0x633D # 0 +0xE749 0x6669 # 0 +0xE74A 0x66FC # 0 +0xE74B 0x6EFF # 0 +0xE74C 0x6F2B # 0 +0xE74D 0x7063 # 0 +0xE74E 0x779E # 0 +0xE74F 0x842C # 0 +0xE750 0x8513 # 0 +0xE751 0x883B # 0 +0xE752 0x8F13 # 0 +0xE753 0x9945 # 0 +0xE754 0x9C3B # 0 +0xE755 0x551C # 0 +0xE756 0x62B9 # 0 +0xE757 0x672B # 0 +0xE758 0x6CAB # 0 +0xE759 0x8309 # 0 +0xE75A 0x896A # 0 +0xE75B 0x977A # 0 +0xE75C 0x4EA1 # 0 +0xE75D 0x5984 # 0 +0xE75E 0x5FD8 # 0 +0xE75F 0x5FD9 # 0 +0xE760 0x671B # 0 +0xE761 0x7DB2 # 0 +0xE762 0x7F54 # 0 +0xE763 0x8292 # 0 +0xE764 0x832B # 0 +0xE765 0x83BD # 0 +0xE766 0x8F1E # 0 +0xE767 0x9099 # 0 +0xE768 0x57CB # 0 +0xE769 0x59B9 # 0 +0xE76A 0x5A92 # 0 +0xE76B 0x5BD0 # 0 +0xE76C 0x6627 # 0 +0xE76D 0x679A # 0 +0xE76E 0x6885 # 0 +0xE76F 0x6BCF # 0 +0xE770 0x7164 # 0 +0xE771 0x7F75 # 0 +0xE772 0x8CB7 # 0 +0xE773 0x8CE3 # 0 +0xE774 0x9081 # 0 +0xE775 0x9B45 # 0 +0xE776 0x8108 # 0 +0xE777 0x8C8A # 0 +0xE778 0x964C # 0 +0xE779 0x9A40 # 0 +0xE77A 0x9EA5 # 0 +0xE77B 0x5B5F # 0 +0xE77C 0x6C13 # 0 +0xE77D 0x731B # 0 +0xE77E 0x76F2 # 0 +0xE791 0x76DF # 0 +0xE792 0x840C # 0 +0xE793 0x51AA # 0 +0xE794 0x8993 # 0 +0xE795 0x514D # 0 +0xE796 0x5195 # 0 +0xE797 0x52C9 # 0 +0xE798 0x68C9 # 0 +0xE799 0x6C94 # 0 +0xE79A 0x7704 # 0 +0xE79B 0x7720 # 0 +0xE79C 0x7DBF # 0 +0xE79D 0x7DEC # 0 +0xE79E 0x9762 # 0 +0xE79F 0x9EB5 # 0 +0xE7A0 0x6EC5 # 0 +0xE7A1 0x8511 # 0 +0xE7A2 0x51A5 # 0 +0xE7A3 0x540D # 0 +0xE7A4 0x547D # 0 +0xE7A5 0x660E # 0 +0xE7A6 0x669D # 0 +0xE7A7 0x6927 # 0 +0xE7A8 0x6E9F # 0 +0xE7A9 0x76BF # 0 +0xE7AA 0x7791 # 0 +0xE7AB 0x8317 # 0 +0xE7AC 0x84C2 # 0 +0xE7AD 0x879F # 0 +0xE7AE 0x9169 # 0 +0xE7AF 0x9298 # 0 +0xE7B0 0x9CF4 # 0 +0xE7B1 0x8882 # 0 +0xE7B2 0x4FAE # 0 +0xE7B3 0x5192 # 0 +0xE7B4 0x52DF # 0 +0xE7B5 0x59C6 # 0 +0xE7B6 0x5E3D # 0 +0xE7B7 0x6155 # 0 +0xE7B8 0x6478 # 0 +0xE7B9 0x6479 # 0 +0xE7BA 0x66AE # 0 +0xE7BB 0x67D0 # 0 +0xE7BC 0x6A21 # 0 +0xE7BD 0x6BCD # 0 +0xE7BE 0x6BDB # 0 +0xE7BF 0x725F # 0 +0xE7C0 0x7261 # 0 +0xE7C1 0x7441 # 0 +0xE7C2 0x7738 # 0 +0xE7C3 0x77DB # 0 +0xE7C4 0x8017 # 0 +0xE7C5 0x82BC # 0 +0xE7C6 0x8305 # 0 +0xE7C7 0x8B00 # 0 +0xE7C8 0x8B28 # 0 +0xE7C9 0x8C8C # 0 +0xE7CA 0x6728 # 0 +0xE7CB 0x6C90 # 0 +0xE7CC 0x7267 # 0 +0xE7CD 0x76EE # 0 +0xE7CE 0x7766 # 0 +0xE7CF 0x7A46 # 0 +0xE7D0 0x9DA9 # 0 +0xE7D1 0x6B7F # 0 +0xE7D2 0x6C92 # 0 +0xE7D3 0x5922 # 0 +0xE7D4 0x6726 # 0 +0xE7D5 0x8499 # 0 +0xE7D6 0x536F # 0 +0xE7D7 0x5893 # 0 +0xE7D8 0x5999 # 0 +0xE7D9 0x5EDF # 0 +0xE7DA 0x63CF # 0 +0xE7DB 0x6634 # 0 +0xE7DC 0x6773 # 0 +0xE7DD 0x6E3A # 0 +0xE7DE 0x732B # 0 +0xE7DF 0x7AD7 # 0 +0xE7E0 0x82D7 # 0 +0xE7E1 0x9328 # 0 +0xE7E2 0x52D9 # 0 +0xE7E3 0x5DEB # 0 +0xE7E4 0x61AE # 0 +0xE7E5 0x61CB # 0 +0xE7E6 0x620A # 0 +0xE7E7 0x62C7 # 0 +0xE7E8 0x64AB # 0 +0xE7E9 0x65E0 # 0 +0xE7EA 0x6959 # 0 +0xE7EB 0x6B66 # 0 +0xE7EC 0x6BCB # 0 +0xE7ED 0x7121 # 0 +0xE7EE 0x73F7 # 0 +0xE7EF 0x755D # 0 +0xE7F0 0x7E46 # 0 +0xE7F1 0x821E # 0 +0xE7F2 0x8302 # 0 +0xE7F3 0x856A # 0 +0xE7F4 0x8AA3 # 0 +0xE7F5 0x8CBF # 0 +0xE7F6 0x9727 # 0 +0xE7F7 0x9D61 # 0 +0xE7F8 0x58A8 # 0 +0xE7F9 0x9ED8 # 0 +0xE7FA 0x5011 # 0 +0xE7FB 0x520E # 0 +0xE7FC 0x543B # 0 +0xE7FD 0x554F # 0 +0xE7FE 0x6587 # 0 +0xE831 0x6C76 # 0 +0xE832 0x7D0A # 0 +0xE833 0x7D0B # 0 +0xE834 0x805E # 0 +0xE835 0x868A # 0 +0xE836 0x9580 # 0 +0xE837 0x96EF # 0 +0xE838 0x52FF # 0 +0xE839 0x6C95 # 0 +0xE83A 0x7269 # 0 +0xE83B 0x5473 # 0 +0xE83C 0x5A9A # 0 +0xE83D 0x5C3E # 0 +0xE83E 0x5D4B # 0 +0xE83F 0x5F4C # 0 +0xE840 0x5FAE # 0 +0xE841 0x672A # 0 +0xE842 0x68B6 # 0 +0xE843 0x6963 # 0 +0xE844 0x6E3C # 0 +0xE845 0x6E44 # 0 +0xE846 0x7709 # 0 +0xE847 0x7C73 # 0 +0xE848 0x7F8E # 0 +0xE849 0x8587 # 0 +0xE84A 0x8B0E # 0 +0xE84B 0x8FF7 # 0 +0xE84C 0x9761 # 0 +0xE84D 0x9EF4 # 0 +0xE84E 0x5CB7 # 0 +0xE84F 0x60B6 # 0 +0xE850 0x610D # 0 +0xE851 0x61AB # 0 +0xE852 0x654F # 0 +0xE853 0x65FB # 0 +0xE854 0x65FC # 0 +0xE855 0x6C11 # 0 +0xE856 0x6CEF # 0 +0xE857 0x739F # 0 +0xE858 0x73C9 # 0 +0xE859 0x7DE1 # 0 +0xE85A 0x9594 # 0 +0xE85B 0x5BC6 # 0 +0xE85C 0x871C # 0 +0xE85D 0x8B10 # 0 +0xE85E 0x525D # 0 +0xE85F 0x535A # 0 +0xE860 0x62CD # 0 +0xE861 0x640F # 0 +0xE862 0x64B2 # 0 +0xE863 0x6734 # 0 +0xE864 0x6A38 # 0 +0xE865 0x6CCA # 0 +0xE866 0x73C0 # 0 +0xE867 0x749E # 0 +0xE868 0x7B94 # 0 +0xE869 0x7C95 # 0 +0xE86A 0x7E1B # 0 +0xE86B 0x818A # 0 +0xE86C 0x8236 # 0 +0xE86D 0x8584 # 0 +0xE86E 0x8FEB # 0 +0xE86F 0x96F9 # 0 +0xE870 0x99C1 # 0 +0xE871 0x4F34 # 0 +0xE872 0x534A # 0 +0xE873 0x53CD # 0 +0xE874 0x53DB # 0 +0xE875 0x62CC # 0 +0xE876 0x642C # 0 +0xE877 0x6500 # 0 +0xE878 0x6591 # 0 +0xE879 0x69C3 # 0 +0xE87A 0x6CEE # 0 +0xE87B 0x6F58 # 0 +0xE87C 0x73ED # 0 +0xE87D 0x7554 # 0 +0xE87E 0x7622 # 0 +0xE891 0x76E4 # 0 +0xE892 0x76FC # 0 +0xE893 0x78D0 # 0 +0xE894 0x78FB # 0 +0xE895 0x792C # 0 +0xE896 0x7D46 # 0 +0xE897 0x822C # 0 +0xE898 0x87E0 # 0 +0xE899 0x8FD4 # 0 +0xE89A 0x9812 # 0 +0xE89B 0x98EF # 0 +0xE89C 0x52C3 # 0 +0xE89D 0x62D4 # 0 +0xE89E 0x64A5 # 0 +0xE89F 0x6E24 # 0 +0xE8A0 0x6F51 # 0 +0xE8A1 0x767C # 0 +0xE8A2 0x8DCB # 0 +0xE8A3 0x91B1 # 0 +0xE8A4 0x9262 # 0 +0xE8A5 0x9AEE # 0 +0xE8A6 0x9B43 # 0 +0xE8A7 0x5023 # 0 +0xE8A8 0x508D # 0 +0xE8A9 0x574A # 0 +0xE8AA 0x59A8 # 0 +0xE8AB 0x5C28 # 0 +0xE8AC 0x5E47 # 0 +0xE8AD 0x5F77 # 0 +0xE8AE 0x623F # 0 +0xE8AF 0x653E # 0 +0xE8B0 0x65B9 # 0 +0xE8B1 0x65C1 # 0 +0xE8B2 0x6609 # 0 +0xE8B3 0x678B # 0 +0xE8B4 0x699C # 0 +0xE8B5 0x6EC2 # 0 +0xE8B6 0x78C5 # 0 +0xE8B7 0x7D21 # 0 +0xE8B8 0x80AA # 0 +0xE8B9 0x8180 # 0 +0xE8BA 0x822B # 0 +0xE8BB 0x82B3 # 0 +0xE8BC 0x84A1 # 0 +0xE8BD 0x868C # 0 +0xE8BE 0x8A2A # 0 +0xE8BF 0x8B17 # 0 +0xE8C0 0x90A6 # 0 +0xE8C1 0x9632 # 0 +0xE8C2 0x9F90 # 0 +0xE8C3 0x500D # 0 +0xE8C4 0x4FF3 # 0 +0xE8C5 0xF963 # 0 +0xE8C6 0x57F9 # 0 +0xE8C7 0x5F98 # 0 +0xE8C8 0x62DC # 0 +0xE8C9 0x6392 # 0 +0xE8CA 0x676F # 0 +0xE8CB 0x6E43 # 0 +0xE8CC 0x7119 # 0 +0xE8CD 0x76C3 # 0 +0xE8CE 0x80CC # 0 +0xE8CF 0x80DA # 0 +0xE8D0 0x88F4 # 0 +0xE8D1 0x88F5 # 0 +0xE8D2 0x8919 # 0 +0xE8D3 0x8CE0 # 0 +0xE8D4 0x8F29 # 0 +0xE8D5 0x914D # 0 +0xE8D6 0x966A # 0 +0xE8D7 0x4F2F # 0 +0xE8D8 0x4F70 # 0 +0xE8D9 0x5E1B # 0 +0xE8DA 0x67CF # 0 +0xE8DB 0x6822 # 0 +0xE8DC 0x767D # 0 +0xE8DD 0x767E # 0 +0xE8DE 0x9B44 # 0 +0xE8DF 0x5E61 # 0 +0xE8E0 0x6A0A # 0 +0xE8E1 0x7169 # 0 +0xE8E2 0x71D4 # 0 +0xE8E3 0x756A # 0 +0xE8E4 0xF964 # 0 +0xE8E5 0x7E41 # 0 +0xE8E6 0x8543 # 0 +0xE8E7 0x85E9 # 0 +0xE8E8 0x98DC # 0 +0xE8E9 0x4F10 # 0 +0xE8EA 0x7B4F # 0 +0xE8EB 0x7F70 # 0 +0xE8EC 0x95A5 # 0 +0xE8ED 0x51E1 # 0 +0xE8EE 0x5E06 # 0 +0xE8EF 0x68B5 # 0 +0xE8F0 0x6C3E # 0 +0xE8F1 0x6C4E # 0 +0xE8F2 0x6CDB # 0 +0xE8F3 0x72AF # 0 +0xE8F4 0x7BC4 # 0 +0xE8F5 0x8303 # 0 +0xE8F6 0x6CD5 # 0 +0xE8F7 0x743A # 0 +0xE8F8 0x50FB # 0 +0xE8F9 0x5288 # 0 +0xE8FA 0x58C1 # 0 +0xE8FB 0x64D8 # 0 +0xE8FC 0x6A97 # 0 +0xE8FD 0x74A7 # 0 +0xE8FE 0x7656 # 0 +0xE931 0x78A7 # 0 +0xE932 0x8617 # 0 +0xE933 0x95E2 # 0 +0xE934 0x9739 # 0 +0xE935 0xF965 # 0 +0xE936 0x535E # 0 +0xE937 0x5F01 # 0 +0xE938 0x8B8A # 0 +0xE939 0x8FA8 # 0 +0xE93A 0x8FAF # 0 +0xE93B 0x908A # 0 +0xE93C 0x5225 # 0 +0xE93D 0x77A5 # 0 +0xE93E 0x9C49 # 0 +0xE93F 0x9F08 # 0 +0xE940 0x4E19 # 0 +0xE941 0x5002 # 0 +0xE942 0x5175 # 0 +0xE943 0x5C5B # 0 +0xE944 0x5E77 # 0 +0xE945 0x661E # 0 +0xE946 0x663A # 0 +0xE947 0x67C4 # 0 +0xE948 0x68C5 # 0 +0xE949 0x70B3 # 0 +0xE94A 0x7501 # 0 +0xE94B 0x75C5 # 0 +0xE94C 0x79C9 # 0 +0xE94D 0x7ADD # 0 +0xE94E 0x8F27 # 0 +0xE94F 0x9920 # 0 +0xE950 0x9A08 # 0 +0xE951 0x4FDD # 0 +0xE952 0x5821 # 0 +0xE953 0x5831 # 0 +0xE954 0x5BF6 # 0 +0xE955 0x666E # 0 +0xE956 0x6B65 # 0 +0xE957 0x6D11 # 0 +0xE958 0x6E7A # 0 +0xE959 0x6F7D # 0 +0xE95A 0x73E4 # 0 +0xE95B 0x752B # 0 +0xE95C 0x83E9 # 0 +0xE95D 0x88DC # 0 +0xE95E 0x8913 # 0 +0xE95F 0x8B5C # 0 +0xE960 0x8F14 # 0 +0xE961 0x4F0F # 0 +0xE962 0x50D5 # 0 +0xE963 0x5310 # 0 +0xE964 0x535C # 0 +0xE965 0x5B93 # 0 +0xE966 0x5FA9 # 0 +0xE967 0x670D # 0 +0xE968 0x798F # 0 +0xE969 0x8179 # 0 +0xE96A 0x832F # 0 +0xE96B 0x8514 # 0 +0xE96C 0x8907 # 0 +0xE96D 0x8986 # 0 +0xE96E 0x8F39 # 0 +0xE96F 0x8F3B # 0 +0xE970 0x99A5 # 0 +0xE971 0x9C12 # 0 +0xE972 0x672C # 0 +0xE973 0x4E76 # 0 +0xE974 0x4FF8 # 0 +0xE975 0x5949 # 0 +0xE976 0x5C01 # 0 +0xE977 0x5CEF # 0 +0xE978 0x5CF0 # 0 +0xE979 0x6367 # 0 +0xE97A 0x68D2 # 0 +0xE97B 0x70FD # 0 +0xE97C 0x71A2 # 0 +0xE97D 0x742B # 0 +0xE97E 0x7E2B # 0 +0xE991 0x84EC # 0 +0xE992 0x8702 # 0 +0xE993 0x9022 # 0 +0xE994 0x92D2 # 0 +0xE995 0x9CF3 # 0 +0xE996 0x4E0D # 0 +0xE997 0x4ED8 # 0 +0xE998 0x4FEF # 0 +0xE999 0x5085 # 0 +0xE99A 0x5256 # 0 +0xE99B 0x526F # 0 +0xE99C 0x5426 # 0 +0xE99D 0x5490 # 0 +0xE99E 0x57E0 # 0 +0xE99F 0x592B # 0 +0xE9A0 0x5A66 # 0 +0xE9A1 0x5B5A # 0 +0xE9A2 0x5B75 # 0 +0xE9A3 0x5BCC # 0 +0xE9A4 0x5E9C # 0 +0xE9A5 0xF966 # 0 +0xE9A6 0x6276 # 0 +0xE9A7 0x6577 # 0 +0xE9A8 0x65A7 # 0 +0xE9A9 0x6D6E # 0 +0xE9AA 0x6EA5 # 0 +0xE9AB 0x7236 # 0 +0xE9AC 0x7B26 # 0 +0xE9AD 0x7C3F # 0 +0xE9AE 0x7F36 # 0 +0xE9AF 0x8150 # 0 +0xE9B0 0x8151 # 0 +0xE9B1 0x819A # 0 +0xE9B2 0x8240 # 0 +0xE9B3 0x8299 # 0 +0xE9B4 0x83A9 # 0 +0xE9B5 0x8A03 # 0 +0xE9B6 0x8CA0 # 0 +0xE9B7 0x8CE6 # 0 +0xE9B8 0x8CFB # 0 +0xE9B9 0x8D74 # 0 +0xE9BA 0x8DBA # 0 +0xE9BB 0x90E8 # 0 +0xE9BC 0x91DC # 0 +0xE9BD 0x961C # 0 +0xE9BE 0x9644 # 0 +0xE9BF 0x99D9 # 0 +0xE9C0 0x9CE7 # 0 +0xE9C1 0x5317 # 0 +0xE9C2 0x5206 # 0 +0xE9C3 0x5429 # 0 +0xE9C4 0x5674 # 0 +0xE9C5 0x58B3 # 0 +0xE9C6 0x5954 # 0 +0xE9C7 0x596E # 0 +0xE9C8 0x5FFF # 0 +0xE9C9 0x61A4 # 0 +0xE9CA 0x626E # 0 +0xE9CB 0x6610 # 0 +0xE9CC 0x6C7E # 0 +0xE9CD 0x711A # 0 +0xE9CE 0x76C6 # 0 +0xE9CF 0x7C89 # 0 +0xE9D0 0x7CDE # 0 +0xE9D1 0x7D1B # 0 +0xE9D2 0x82AC # 0 +0xE9D3 0x8CC1 # 0 +0xE9D4 0x96F0 # 0 +0xE9D5 0xF967 # 0 +0xE9D6 0x4F5B # 0 +0xE9D7 0x5F17 # 0 +0xE9D8 0x5F7F # 0 +0xE9D9 0x62C2 # 0 +0xE9DA 0x5D29 # 0 +0xE9DB 0x670B # 0 +0xE9DC 0x68DA # 0 +0xE9DD 0x787C # 0 +0xE9DE 0x7E43 # 0 +0xE9DF 0x9D6C # 0 +0xE9E0 0x4E15 # 0 +0xE9E1 0x5099 # 0 +0xE9E2 0x5315 # 0 +0xE9E3 0x532A # 0 +0xE9E4 0x5351 # 0 +0xE9E5 0x5983 # 0 +0xE9E6 0x5A62 # 0 +0xE9E7 0x5E87 # 0 +0xE9E8 0x60B2 # 0 +0xE9E9 0x618A # 0 +0xE9EA 0x6249 # 0 +0xE9EB 0x6279 # 0 +0xE9EC 0x6590 # 0 +0xE9ED 0x6787 # 0 +0xE9EE 0x69A7 # 0 +0xE9EF 0x6BD4 # 0 +0xE9F0 0x6BD6 # 0 +0xE9F1 0x6BD7 # 0 +0xE9F2 0x6BD8 # 0 +0xE9F3 0x6CB8 # 0 +0xE9F4 0xF968 # 0 +0xE9F5 0x7435 # 0 +0xE9F6 0x75FA # 0 +0xE9F7 0x7812 # 0 +0xE9F8 0x7891 # 0 +0xE9F9 0x79D5 # 0 +0xE9FA 0x79D8 # 0 +0xE9FB 0x7C83 # 0 +0xE9FC 0x7DCB # 0 +0xE9FD 0x7FE1 # 0 +0xE9FE 0x80A5 # 0 +0xEA31 0x813E # 0 +0xEA32 0x81C2 # 0 +0xEA33 0x83F2 # 0 +0xEA34 0x871A # 0 +0xEA35 0x88E8 # 0 +0xEA36 0x8AB9 # 0 +0xEA37 0x8B6C # 0 +0xEA38 0x8CBB # 0 +0xEA39 0x9119 # 0 +0xEA3A 0x975E # 0 +0xEA3B 0x98DB # 0 +0xEA3C 0x9F3B # 0 +0xEA3D 0x56AC # 0 +0xEA3E 0x5B2A # 0 +0xEA3F 0x5F6C # 0 +0xEA40 0x658C # 0 +0xEA41 0x6AB3 # 0 +0xEA42 0x6BAF # 0 +0xEA43 0x6D5C # 0 +0xEA44 0x6FF1 # 0 +0xEA45 0x7015 # 0 +0xEA46 0x725D # 0 +0xEA47 0x73AD # 0 +0xEA48 0x8CA7 # 0 +0xEA49 0x8CD3 # 0 +0xEA4A 0x983B # 0 +0xEA4B 0x6191 # 0 +0xEA4C 0x6C37 # 0 +0xEA4D 0x8058 # 0 +0xEA4E 0x9A01 # 0 +0xEA4F 0x4E4D # 0 +0xEA50 0x4E8B # 0 +0xEA51 0x4E9B # 0 +0xEA52 0x4ED5 # 0 +0xEA53 0x4F3A # 0 +0xEA54 0x4F3C # 0 +0xEA55 0x4F7F # 0 +0xEA56 0x4FDF # 0 +0xEA57 0x50FF # 0 +0xEA58 0x53F2 # 0 +0xEA59 0x53F8 # 0 +0xEA5A 0x5506 # 0 +0xEA5B 0x55E3 # 0 +0xEA5C 0x56DB # 0 +0xEA5D 0x58EB # 0 +0xEA5E 0x5962 # 0 +0xEA5F 0x5A11 # 0 +0xEA60 0x5BEB # 0 +0xEA61 0x5BFA # 0 +0xEA62 0x5C04 # 0 +0xEA63 0x5DF3 # 0 +0xEA64 0x5E2B # 0 +0xEA65 0x5F99 # 0 +0xEA66 0x601D # 0 +0xEA67 0x6368 # 0 +0xEA68 0x659C # 0 +0xEA69 0x65AF # 0 +0xEA6A 0x67F6 # 0 +0xEA6B 0x67FB # 0 +0xEA6C 0x68AD # 0 +0xEA6D 0x6B7B # 0 +0xEA6E 0x6C99 # 0 +0xEA6F 0x6CD7 # 0 +0xEA70 0x6E23 # 0 +0xEA71 0x7009 # 0 +0xEA72 0x7345 # 0 +0xEA73 0x7802 # 0 +0xEA74 0x793E # 0 +0xEA75 0x7940 # 0 +0xEA76 0x7960 # 0 +0xEA77 0x79C1 # 0 +0xEA78 0x7BE9 # 0 +0xEA79 0x7D17 # 0 +0xEA7A 0x7D72 # 0 +0xEA7B 0x8086 # 0 +0xEA7C 0x820D # 0 +0xEA7D 0x838E # 0 +0xEA7E 0x84D1 # 0 +0xEA91 0x86C7 # 0 +0xEA92 0x88DF # 0 +0xEA93 0x8A50 # 0 +0xEA94 0x8A5E # 0 +0xEA95 0x8B1D # 0 +0xEA96 0x8CDC # 0 +0xEA97 0x8D66 # 0 +0xEA98 0x8FAD # 0 +0xEA99 0x90AA # 0 +0xEA9A 0x98FC # 0 +0xEA9B 0x99DF # 0 +0xEA9C 0x9E9D # 0 +0xEA9D 0x524A # 0 +0xEA9E 0xF969 # 0 +0xEA9F 0x6714 # 0 +0xEAA0 0xF96A # 0 +0xEAA1 0x5098 # 0 +0xEAA2 0x522A # 0 +0xEAA3 0x5C71 # 0 +0xEAA4 0x6563 # 0 +0xEAA5 0x6C55 # 0 +0xEAA6 0x73CA # 0 +0xEAA7 0x7523 # 0 +0xEAA8 0x759D # 0 +0xEAA9 0x7B97 # 0 +0xEAAA 0x849C # 0 +0xEAAB 0x9178 # 0 +0xEAAC 0x9730 # 0 +0xEAAD 0x4E77 # 0 +0xEAAE 0x6492 # 0 +0xEAAF 0x6BBA # 0 +0xEAB0 0x715E # 0 +0xEAB1 0x85A9 # 0 +0xEAB2 0x4E09 # 0 +0xEAB3 0xF96B # 0 +0xEAB4 0x6749 # 0 +0xEAB5 0x68EE # 0 +0xEAB6 0x6E17 # 0 +0xEAB7 0x829F # 0 +0xEAB8 0x8518 # 0 +0xEAB9 0x886B # 0 +0xEABA 0x63F7 # 0 +0xEABB 0x6F81 # 0 +0xEABC 0x9212 # 0 +0xEABD 0x98AF # 0 +0xEABE 0x4E0A # 0 +0xEABF 0x50B7 # 0 +0xEAC0 0x50CF # 0 +0xEAC1 0x511F # 0 +0xEAC2 0x5546 # 0 +0xEAC3 0x55AA # 0 +0xEAC4 0x5617 # 0 +0xEAC5 0x5B40 # 0 +0xEAC6 0x5C19 # 0 +0xEAC7 0x5CE0 # 0 +0xEAC8 0x5E38 # 0 +0xEAC9 0x5E8A # 0 +0xEACA 0x5EA0 # 0 +0xEACB 0x5EC2 # 0 +0xEACC 0x60F3 # 0 +0xEACD 0x6851 # 0 +0xEACE 0x6A61 # 0 +0xEACF 0x6E58 # 0 +0xEAD0 0x723D # 0 +0xEAD1 0x7240 # 0 +0xEAD2 0x72C0 # 0 +0xEAD3 0x76F8 # 0 +0xEAD4 0x7965 # 0 +0xEAD5 0x7BB1 # 0 +0xEAD6 0x7FD4 # 0 +0xEAD7 0x88F3 # 0 +0xEAD8 0x89F4 # 0 +0xEAD9 0x8A73 # 0 +0xEADA 0x8C61 # 0 +0xEADB 0x8CDE # 0 +0xEADC 0x971C # 0 +0xEADD 0x585E # 0 +0xEADE 0x74BD # 0 +0xEADF 0x8CFD # 0 +0xEAE0 0x55C7 # 0 +0xEAE1 0xF96C # 0 +0xEAE2 0x7A61 # 0 +0xEAE3 0x7D22 # 0 +0xEAE4 0x8272 # 0 +0xEAE5 0x7272 # 0 +0xEAE6 0x751F # 0 +0xEAE7 0x7525 # 0 +0xEAE8 0xF96D # 0 +0xEAE9 0x7B19 # 0 +0xEAEA 0x5885 # 0 +0xEAEB 0x58FB # 0 +0xEAEC 0x5DBC # 0 +0xEAED 0x5E8F # 0 +0xEAEE 0x5EB6 # 0 +0xEAEF 0x5F90 # 0 +0xEAF0 0x6055 # 0 +0xEAF1 0x6292 # 0 +0xEAF2 0x637F # 0 +0xEAF3 0x654D # 0 +0xEAF4 0x6691 # 0 +0xEAF5 0x66D9 # 0 +0xEAF6 0x66F8 # 0 +0xEAF7 0x6816 # 0 +0xEAF8 0x68F2 # 0 +0xEAF9 0x7280 # 0 +0xEAFA 0x745E # 0 +0xEAFB 0x7B6E # 0 +0xEAFC 0x7D6E # 0 +0xEAFD 0x7DD6 # 0 +0xEAFE 0x7F72 # 0 +0xEB31 0x80E5 # 0 +0xEB32 0x8212 # 0 +0xEB33 0x85AF # 0 +0xEB34 0x897F # 0 +0xEB35 0x8A93 # 0 +0xEB36 0x901D # 0 +0xEB37 0x92E4 # 0 +0xEB38 0x9ECD # 0 +0xEB39 0x9F20 # 0 +0xEB3A 0x5915 # 0 +0xEB3B 0x596D # 0 +0xEB3C 0x5E2D # 0 +0xEB3D 0x60DC # 0 +0xEB3E 0x6614 # 0 +0xEB3F 0x6673 # 0 +0xEB40 0x6790 # 0 +0xEB41 0x6C50 # 0 +0xEB42 0x6DC5 # 0 +0xEB43 0x6F5F # 0 +0xEB44 0x77F3 # 0 +0xEB45 0x78A9 # 0 +0xEB46 0x84C6 # 0 +0xEB47 0x91CB # 0 +0xEB48 0x932B # 0 +0xEB49 0x4ED9 # 0 +0xEB4A 0x50CA # 0 +0xEB4B 0x5148 # 0 +0xEB4C 0x5584 # 0 +0xEB4D 0x5B0B # 0 +0xEB4E 0x5BA3 # 0 +0xEB4F 0x6247 # 0 +0xEB50 0x657E # 0 +0xEB51 0x65CB # 0 +0xEB52 0x6E32 # 0 +0xEB53 0x717D # 0 +0xEB54 0x7401 # 0 +0xEB55 0x7444 # 0 +0xEB56 0x7487 # 0 +0xEB57 0x74BF # 0 +0xEB58 0x766C # 0 +0xEB59 0x79AA # 0 +0xEB5A 0x7DDA # 0 +0xEB5B 0x7E55 # 0 +0xEB5C 0x7FA8 # 0 +0xEB5D 0x817A # 0 +0xEB5E 0x81B3 # 0 +0xEB5F 0x8239 # 0 +0xEB60 0x861A # 0 +0xEB61 0x87EC # 0 +0xEB62 0x8A75 # 0 +0xEB63 0x8DE3 # 0 +0xEB64 0x9078 # 0 +0xEB65 0x9291 # 0 +0xEB66 0x9425 # 0 +0xEB67 0x994D # 0 +0xEB68 0x9BAE # 0 +0xEB69 0x5368 # 0 +0xEB6A 0x5C51 # 0 +0xEB6B 0x6954 # 0 +0xEB6C 0x6CC4 # 0 +0xEB6D 0x6D29 # 0 +0xEB6E 0x6E2B # 0 +0xEB6F 0x820C # 0 +0xEB70 0x859B # 0 +0xEB71 0x893B # 0 +0xEB72 0x8A2D # 0 +0xEB73 0x8AAA # 0 +0xEB74 0x96EA # 0 +0xEB75 0x9F67 # 0 +0xEB76 0x5261 # 0 +0xEB77 0x66B9 # 0 +0xEB78 0x6BB2 # 0 +0xEB79 0x7E96 # 0 +0xEB7A 0x87FE # 0 +0xEB7B 0x8D0D # 0 +0xEB7C 0x9583 # 0 +0xEB7D 0x965D # 0 +0xEB7E 0x651D # 0 +0xEB91 0x6D89 # 0 +0xEB92 0x71EE # 0 +0xEB93 0xF96E # 0 +0xEB94 0x57CE # 0 +0xEB95 0x59D3 # 0 +0xEB96 0x5BAC # 0 +0xEB97 0x6027 # 0 +0xEB98 0x60FA # 0 +0xEB99 0x6210 # 0 +0xEB9A 0x661F # 0 +0xEB9B 0x665F # 0 +0xEB9C 0x7329 # 0 +0xEB9D 0x73F9 # 0 +0xEB9E 0x76DB # 0 +0xEB9F 0x7701 # 0 +0xEBA0 0x7B6C # 0 +0xEBA1 0x8056 # 0 +0xEBA2 0x8072 # 0 +0xEBA3 0x8165 # 0 +0xEBA4 0x8AA0 # 0 +0xEBA5 0x9192 # 0 +0xEBA6 0x4E16 # 0 +0xEBA7 0x52E2 # 0 +0xEBA8 0x6B72 # 0 +0xEBA9 0x6D17 # 0 +0xEBAA 0x7A05 # 0 +0xEBAB 0x7B39 # 0 +0xEBAC 0x7D30 # 0 +0xEBAD 0xF96F # 0 +0xEBAE 0x8CB0 # 0 +0xEBAF 0x53EC # 0 +0xEBB0 0x562F # 0 +0xEBB1 0x5851 # 0 +0xEBB2 0x5BB5 # 0 +0xEBB3 0x5C0F # 0 +0xEBB4 0x5C11 # 0 +0xEBB5 0x5DE2 # 0 +0xEBB6 0x6240 # 0 +0xEBB7 0x6383 # 0 +0xEBB8 0x6414 # 0 +0xEBB9 0x662D # 0 +0xEBBA 0x68B3 # 0 +0xEBBB 0x6CBC # 0 +0xEBBC 0x6D88 # 0 +0xEBBD 0x6EAF # 0 +0xEBBE 0x701F # 0 +0xEBBF 0x70A4 # 0 +0xEBC0 0x71D2 # 0 +0xEBC1 0x7526 # 0 +0xEBC2 0x758F # 0 +0xEBC3 0x758E # 0 +0xEBC4 0x7619 # 0 +0xEBC5 0x7B11 # 0 +0xEBC6 0x7BE0 # 0 +0xEBC7 0x7C2B # 0 +0xEBC8 0x7D20 # 0 +0xEBC9 0x7D39 # 0 +0xEBCA 0x852C # 0 +0xEBCB 0x856D # 0 +0xEBCC 0x8607 # 0 +0xEBCD 0x8A34 # 0 +0xEBCE 0x900D # 0 +0xEBCF 0x9061 # 0 +0xEBD0 0x90B5 # 0 +0xEBD1 0x92B7 # 0 +0xEBD2 0x97F6 # 0 +0xEBD3 0x9A37 # 0 +0xEBD4 0x4FD7 # 0 +0xEBD5 0x5C6C # 0 +0xEBD6 0x675F # 0 +0xEBD7 0x6D91 # 0 +0xEBD8 0x7C9F # 0 +0xEBD9 0x7E8C # 0 +0xEBDA 0x8B16 # 0 +0xEBDB 0x8D16 # 0 +0xEBDC 0x901F # 0 +0xEBDD 0x5B6B # 0 +0xEBDE 0x5DFD # 0 +0xEBDF 0x640D # 0 +0xEBE0 0x84C0 # 0 +0xEBE1 0x905C # 0 +0xEBE2 0x98E1 # 0 +0xEBE3 0x7387 # 0 +0xEBE4 0x5B8B # 0 +0xEBE5 0x609A # 0 +0xEBE6 0x677E # 0 +0xEBE7 0x6DDE # 0 +0xEBE8 0x8A1F # 0 +0xEBE9 0x8AA6 # 0 +0xEBEA 0x9001 # 0 +0xEBEB 0x980C # 0 +0xEBEC 0x5237 # 0 +0xEBED 0xF970 # 0 +0xEBEE 0x7051 # 0 +0xEBEF 0x788E # 0 +0xEBF0 0x9396 # 0 +0xEBF1 0x8870 # 0 +0xEBF2 0x91D7 # 0 +0xEBF3 0x4FEE # 0 +0xEBF4 0x53D7 # 0 +0xEBF5 0x55FD # 0 +0xEBF6 0x56DA # 0 +0xEBF7 0x5782 # 0 +0xEBF8 0x58FD # 0 +0xEBF9 0x5AC2 # 0 +0xEBFA 0x5B88 # 0 +0xEBFB 0x5CAB # 0 +0xEBFC 0x5CC0 # 0 +0xEBFD 0x5E25 # 0 +0xEBFE 0x6101 # 0 +0xEC31 0x620D # 0 +0xEC32 0x624B # 0 +0xEC33 0x6388 # 0 +0xEC34 0x641C # 0 +0xEC35 0x6536 # 0 +0xEC36 0x6578 # 0 +0xEC37 0x6A39 # 0 +0xEC38 0x6B8A # 0 +0xEC39 0x6C34 # 0 +0xEC3A 0x6D19 # 0 +0xEC3B 0x6F31 # 0 +0xEC3C 0x71E7 # 0 +0xEC3D 0x72E9 # 0 +0xEC3E 0x7378 # 0 +0xEC3F 0x7407 # 0 +0xEC40 0x74B2 # 0 +0xEC41 0x7626 # 0 +0xEC42 0x7761 # 0 +0xEC43 0x79C0 # 0 +0xEC44 0x7A57 # 0 +0xEC45 0x7AEA # 0 +0xEC46 0x7CB9 # 0 +0xEC47 0x7D8F # 0 +0xEC48 0x7DAC # 0 +0xEC49 0x7E61 # 0 +0xEC4A 0x7F9E # 0 +0xEC4B 0x8129 # 0 +0xEC4C 0x8331 # 0 +0xEC4D 0x8490 # 0 +0xEC4E 0x84DA # 0 +0xEC4F 0x85EA # 0 +0xEC50 0x8896 # 0 +0xEC51 0x8AB0 # 0 +0xEC52 0x8B90 # 0 +0xEC53 0x8F38 # 0 +0xEC54 0x9042 # 0 +0xEC55 0x9083 # 0 +0xEC56 0x916C # 0 +0xEC57 0x9296 # 0 +0xEC58 0x92B9 # 0 +0xEC59 0x968B # 0 +0xEC5A 0x96A7 # 0 +0xEC5B 0x96A8 # 0 +0xEC5C 0x96D6 # 0 +0xEC5D 0x9700 # 0 +0xEC5E 0x9808 # 0 +0xEC5F 0x9996 # 0 +0xEC60 0x9AD3 # 0 +0xEC61 0x9B1A # 0 +0xEC62 0x53D4 # 0 +0xEC63 0x587E # 0 +0xEC64 0x5919 # 0 +0xEC65 0x5B70 # 0 +0xEC66 0x5BBF # 0 +0xEC67 0x6DD1 # 0 +0xEC68 0x6F5A # 0 +0xEC69 0x719F # 0 +0xEC6A 0x7421 # 0 +0xEC6B 0x74B9 # 0 +0xEC6C 0x8085 # 0 +0xEC6D 0x83FD # 0 +0xEC6E 0x5DE1 # 0 +0xEC6F 0x5F87 # 0 +0xEC70 0x5FAA # 0 +0xEC71 0x6042 # 0 +0xEC72 0x65EC # 0 +0xEC73 0x6812 # 0 +0xEC74 0x696F # 0 +0xEC75 0x6A53 # 0 +0xEC76 0x6B89 # 0 +0xEC77 0x6D35 # 0 +0xEC78 0x6DF3 # 0 +0xEC79 0x73E3 # 0 +0xEC7A 0x76FE # 0 +0xEC7B 0x77AC # 0 +0xEC7C 0x7B4D # 0 +0xEC7D 0x7D14 # 0 +0xEC7E 0x8123 # 0 +0xEC91 0x821C # 0 +0xEC92 0x8340 # 0 +0xEC93 0x84F4 # 0 +0xEC94 0x8563 # 0 +0xEC95 0x8A62 # 0 +0xEC96 0x8AC4 # 0 +0xEC97 0x9187 # 0 +0xEC98 0x931E # 0 +0xEC99 0x9806 # 0 +0xEC9A 0x99B4 # 0 +0xEC9B 0x620C # 0 +0xEC9C 0x8853 # 0 +0xEC9D 0x8FF0 # 0 +0xEC9E 0x9265 # 0 +0xEC9F 0x5D07 # 0 +0xECA0 0x5D27 # 0 +0xECA1 0x5D69 # 0 +0xECA2 0x745F # 0 +0xECA3 0x819D # 0 +0xECA4 0x8768 # 0 +0xECA5 0x6FD5 # 0 +0xECA6 0x62FE # 0 +0xECA7 0x7FD2 # 0 +0xECA8 0x8936 # 0 +0xECA9 0x8972 # 0 +0xECAA 0x4E1E # 0 +0xECAB 0x4E58 # 0 +0xECAC 0x50E7 # 0 +0xECAD 0x52DD # 0 +0xECAE 0x5347 # 0 +0xECAF 0x627F # 0 +0xECB0 0x6607 # 0 +0xECB1 0x7E69 # 0 +0xECB2 0x8805 # 0 +0xECB3 0x965E # 0 +0xECB4 0x4F8D # 0 +0xECB5 0x5319 # 0 +0xECB6 0x5636 # 0 +0xECB7 0x59CB # 0 +0xECB8 0x5AA4 # 0 +0xECB9 0x5C38 # 0 +0xECBA 0x5C4E # 0 +0xECBB 0x5C4D # 0 +0xECBC 0x5E02 # 0 +0xECBD 0x5F11 # 0 +0xECBE 0x6043 # 0 +0xECBF 0x65BD # 0 +0xECC0 0x662F # 0 +0xECC1 0x6642 # 0 +0xECC2 0x67BE # 0 +0xECC3 0x67F4 # 0 +0xECC4 0x731C # 0 +0xECC5 0x77E2 # 0 +0xECC6 0x793A # 0 +0xECC7 0x7FC5 # 0 +0xECC8 0x8494 # 0 +0xECC9 0x84CD # 0 +0xECCA 0x8996 # 0 +0xECCB 0x8A66 # 0 +0xECCC 0x8A69 # 0 +0xECCD 0x8AE1 # 0 +0xECCE 0x8C55 # 0 +0xECCF 0x8C7A # 0 +0xECD0 0x57F4 # 0 +0xECD1 0x5BD4 # 0 +0xECD2 0x5F0F # 0 +0xECD3 0x606F # 0 +0xECD4 0x62ED # 0 +0xECD5 0x690D # 0 +0xECD6 0x6B96 # 0 +0xECD7 0x6E5C # 0 +0xECD8 0x7184 # 0 +0xECD9 0x7BD2 # 0 +0xECDA 0x8755 # 0 +0xECDB 0x8B58 # 0 +0xECDC 0x8EFE # 0 +0xECDD 0x98DF # 0 +0xECDE 0x98FE # 0 +0xECDF 0x4F38 # 0 +0xECE0 0x4F81 # 0 +0xECE1 0x4FE1 # 0 +0xECE2 0x547B # 0 +0xECE3 0x5A20 # 0 +0xECE4 0x5BB8 # 0 +0xECE5 0x613C # 0 +0xECE6 0x65B0 # 0 +0xECE7 0x6668 # 0 +0xECE8 0x71FC # 0 +0xECE9 0x7533 # 0 +0xECEA 0x795E # 0 +0xECEB 0x7D33 # 0 +0xECEC 0x814E # 0 +0xECED 0x81E3 # 0 +0xECEE 0x8398 # 0 +0xECEF 0x85AA # 0 +0xECF0 0x85CE # 0 +0xECF1 0x8703 # 0 +0xECF2 0x8A0A # 0 +0xECF3 0x8EAB # 0 +0xECF4 0x8F9B # 0 +0xECF5 0xF971 # 0 +0xECF6 0x8FC5 # 0 +0xECF7 0x5931 # 0 +0xECF8 0x5BA4 # 0 +0xECF9 0x5BE6 # 0 +0xECFA 0x6089 # 0 +0xECFB 0x5BE9 # 0 +0xECFC 0x5C0B # 0 +0xECFD 0x5FC3 # 0 +0xECFE 0x6C81 # 0 +0xED31 0xF972 # 0 +0xED32 0x6DF1 # 0 +0xED33 0x700B # 0 +0xED34 0x751A # 0 +0xED35 0x82AF # 0 +0xED36 0x8AF6 # 0 +0xED37 0x4EC0 # 0 +0xED38 0x5341 # 0 +0xED39 0xF973 # 0 +0xED3A 0x96D9 # 0 +0xED3B 0x6C0F # 0 +0xED3C 0x4E9E # 0 +0xED3D 0x4FC4 # 0 +0xED3E 0x5152 # 0 +0xED3F 0x555E # 0 +0xED40 0x5A25 # 0 +0xED41 0x5CE8 # 0 +0xED42 0x6211 # 0 +0xED43 0x7259 # 0 +0xED44 0x82BD # 0 +0xED45 0x83AA # 0 +0xED46 0x86FE # 0 +0xED47 0x8859 # 0 +0xED48 0x8A1D # 0 +0xED49 0x963F # 0 +0xED4A 0x96C5 # 0 +0xED4B 0x9913 # 0 +0xED4C 0x9D09 # 0 +0xED4D 0x9D5D # 0 +0xED4E 0x580A # 0 +0xED4F 0x5CB3 # 0 +0xED50 0x5DBD # 0 +0xED51 0x5E44 # 0 +0xED52 0x60E1 # 0 +0xED53 0x6115 # 0 +0xED54 0x63E1 # 0 +0xED55 0x6A02 # 0 +0xED56 0x6E25 # 0 +0xED57 0x9102 # 0 +0xED58 0x9354 # 0 +0xED59 0x984E # 0 +0xED5A 0x9C10 # 0 +0xED5B 0x9F77 # 0 +0xED5C 0x5B89 # 0 +0xED5D 0x5CB8 # 0 +0xED5E 0x6309 # 0 +0xED5F 0x664F # 0 +0xED60 0x6848 # 0 +0xED61 0x773C # 0 +0xED62 0x96C1 # 0 +0xED63 0x978D # 0 +0xED64 0x9854 # 0 +0xED65 0x9B9F # 0 +0xED66 0x65A1 # 0 +0xED67 0x8B01 # 0 +0xED68 0x8ECB # 0 +0xED69 0x95BC # 0 +0xED6A 0x5535 # 0 +0xED6B 0x5CA9 # 0 +0xED6C 0x5DD6 # 0 +0xED6D 0x5EB5 # 0 +0xED6E 0x6697 # 0 +0xED6F 0x764C # 0 +0xED70 0x83F4 # 0 +0xED71 0x95C7 # 0 +0xED72 0x58D3 # 0 +0xED73 0x62BC # 0 +0xED74 0x72CE # 0 +0xED75 0x9D28 # 0 +0xED76 0x4EF0 # 0 +0xED77 0x592E # 0 +0xED78 0x600F # 0 +0xED79 0x663B # 0 +0xED7A 0x6B83 # 0 +0xED7B 0x79E7 # 0 +0xED7C 0x9D26 # 0 +0xED7D 0x5393 # 0 +0xED7E 0x54C0 # 0 +0xED91 0x57C3 # 0 +0xED92 0x5D16 # 0 +0xED93 0x611B # 0 +0xED94 0x66D6 # 0 +0xED95 0x6DAF # 0 +0xED96 0x788D # 0 +0xED97 0x827E # 0 +0xED98 0x9698 # 0 +0xED99 0x9744 # 0 +0xED9A 0x5384 # 0 +0xED9B 0x627C # 0 +0xED9C 0x6396 # 0 +0xED9D 0x6DB2 # 0 +0xED9E 0x7E0A # 0 +0xED9F 0x814B # 0 +0xEDA0 0x984D # 0 +0xEDA1 0x6AFB # 0 +0xEDA2 0x7F4C # 0 +0xEDA3 0x9DAF # 0 +0xEDA4 0x9E1A # 0 +0xEDA5 0x4E5F # 0 +0xEDA6 0x503B # 0 +0xEDA7 0x51B6 # 0 +0xEDA8 0x591C # 0 +0xEDA9 0x60F9 # 0 +0xEDAA 0x63F6 # 0 +0xEDAB 0x6930 # 0 +0xEDAC 0x723A # 0 +0xEDAD 0x8036 # 0 +0xEDAE 0xF974 # 0 +0xEDAF 0x91CE # 0 +0xEDB0 0x5F31 # 0 +0xEDB1 0xF975 # 0 +0xEDB2 0xF976 # 0 +0xEDB3 0x7D04 # 0 +0xEDB4 0x82E5 # 0 +0xEDB5 0x846F # 0 +0xEDB6 0x84BB # 0 +0xEDB7 0x85E5 # 0 +0xEDB8 0x8E8D # 0 +0xEDB9 0xF977 # 0 +0xEDBA 0x4F6F # 0 +0xEDBB 0xF978 # 0 +0xEDBC 0xF979 # 0 +0xEDBD 0x58E4 # 0 +0xEDBE 0x5B43 # 0 +0xEDBF 0x6059 # 0 +0xEDC0 0x63DA # 0 +0xEDC1 0x6518 # 0 +0xEDC2 0x656D # 0 +0xEDC3 0x6698 # 0 +0xEDC4 0xF97A # 0 +0xEDC5 0x694A # 0 +0xEDC6 0x6A23 # 0 +0xEDC7 0x6D0B # 0 +0xEDC8 0x7001 # 0 +0xEDC9 0x716C # 0 +0xEDCA 0x75D2 # 0 +0xEDCB 0x760D # 0 +0xEDCC 0x79B3 # 0 +0xEDCD 0x7A70 # 0 +0xEDCE 0xF97B # 0 +0xEDCF 0x7F8A # 0 +0xEDD0 0xF97C # 0 +0xEDD1 0x8944 # 0 +0xEDD2 0xF97D # 0 +0xEDD3 0x8B93 # 0 +0xEDD4 0x91C0 # 0 +0xEDD5 0x967D # 0 +0xEDD6 0xF97E # 0 +0xEDD7 0x990A # 0 +0xEDD8 0x5704 # 0 +0xEDD9 0x5FA1 # 0 +0xEDDA 0x65BC # 0 +0xEDDB 0x6F01 # 0 +0xEDDC 0x7600 # 0 +0xEDDD 0x79A6 # 0 +0xEDDE 0x8A9E # 0 +0xEDDF 0x99AD # 0 +0xEDE0 0x9B5A # 0 +0xEDE1 0x9F6C # 0 +0xEDE2 0x5104 # 0 +0xEDE3 0x61B6 # 0 +0xEDE4 0x6291 # 0 +0xEDE5 0x6A8D # 0 +0xEDE6 0x81C6 # 0 +0xEDE7 0x5043 # 0 +0xEDE8 0x5830 # 0 +0xEDE9 0x5F66 # 0 +0xEDEA 0x7109 # 0 +0xEDEB 0x8A00 # 0 +0xEDEC 0x8AFA # 0 +0xEDED 0x5B7C # 0 +0xEDEE 0x8616 # 0 +0xEDEF 0x4FFA # 0 +0xEDF0 0x513C # 0 +0xEDF1 0x56B4 # 0 +0xEDF2 0x5944 # 0 +0xEDF3 0x63A9 # 0 +0xEDF4 0x6DF9 # 0 +0xEDF5 0x5DAA # 0 +0xEDF6 0x696D # 0 +0xEDF7 0x5186 # 0 +0xEDF8 0x4E88 # 0 +0xEDF9 0x4F59 # 0 +0xEDFA 0xF97F # 0 +0xEDFB 0xF980 # 0 +0xEDFC 0xF981 # 0 +0xEDFD 0x5982 # 0 +0xEDFE 0xF982 # 0 +0xEE31 0xF983 # 0 +0xEE32 0x6B5F # 0 +0xEE33 0x6C5D # 0 +0xEE34 0xF984 # 0 +0xEE35 0x74B5 # 0 +0xEE36 0x7916 # 0 +0xEE37 0xF985 # 0 +0xEE38 0x8207 # 0 +0xEE39 0x8245 # 0 +0xEE3A 0x8339 # 0 +0xEE3B 0x8F3F # 0 +0xEE3C 0x8F5D # 0 +0xEE3D 0xF986 # 0 +0xEE3E 0x9918 # 0 +0xEE3F 0xF987 # 0 +0xEE40 0xF988 # 0 +0xEE41 0xF989 # 0 +0xEE42 0x4EA6 # 0 +0xEE43 0xF98A # 0 +0xEE44 0x57DF # 0 +0xEE45 0x5F79 # 0 +0xEE46 0x6613 # 0 +0xEE47 0xF98B # 0 +0xEE48 0xF98C # 0 +0xEE49 0x75AB # 0 +0xEE4A 0x7E79 # 0 +0xEE4B 0x8B6F # 0 +0xEE4C 0xF98D # 0 +0xEE4D 0x9006 # 0 +0xEE4E 0x9A5B # 0 +0xEE4F 0x56A5 # 0 +0xEE50 0x5827 # 0 +0xEE51 0x59F8 # 0 +0xEE52 0x5A1F # 0 +0xEE53 0x5BB4 # 0 +0xEE54 0xF98E # 0 +0xEE55 0x5EF6 # 0 +0xEE56 0xF98F # 0 +0xEE57 0xF990 # 0 +0xEE58 0x6350 # 0 +0xEE59 0x633B # 0 +0xEE5A 0xF991 # 0 +0xEE5B 0x693D # 0 +0xEE5C 0x6C87 # 0 +0xEE5D 0x6CBF # 0 +0xEE5E 0x6D8E # 0 +0xEE5F 0x6D93 # 0 +0xEE60 0x6DF5 # 0 +0xEE61 0x6F14 # 0 +0xEE62 0xF992 # 0 +0xEE63 0x70DF # 0 +0xEE64 0x7136 # 0 +0xEE65 0x7159 # 0 +0xEE66 0xF993 # 0 +0xEE67 0x71C3 # 0 +0xEE68 0x71D5 # 0 +0xEE69 0xF994 # 0 +0xEE6A 0x784F # 0 +0xEE6B 0x786F # 0 +0xEE6C 0xF995 # 0 +0xEE6D 0x7B75 # 0 +0xEE6E 0x7DE3 # 0 +0xEE6F 0xF996 # 0 +0xEE70 0x7E2F # 0 +0xEE71 0xF997 # 0 +0xEE72 0x884D # 0 +0xEE73 0x8EDF # 0 +0xEE74 0xF998 # 0 +0xEE75 0xF999 # 0 +0xEE76 0xF99A # 0 +0xEE77 0x925B # 0 +0xEE78 0xF99B # 0 +0xEE79 0x9CF6 # 0 +0xEE7A 0xF99C # 0 +0xEE7B 0xF99D # 0 +0xEE7C 0xF99E # 0 +0xEE7D 0x6085 # 0 +0xEE7E 0x6D85 # 0 +0xEE91 0xF99F # 0 +0xEE92 0x71B1 # 0 +0xEE93 0xF9A0 # 0 +0xEE94 0xF9A1 # 0 +0xEE95 0x95B1 # 0 +0xEE96 0x53AD # 0 +0xEE97 0xF9A2 # 0 +0xEE98 0xF9A3 # 0 +0xEE99 0xF9A4 # 0 +0xEE9A 0x67D3 # 0 +0xEE9B 0xF9A5 # 0 +0xEE9C 0x708E # 0 +0xEE9D 0x7130 # 0 +0xEE9E 0x7430 # 0 +0xEE9F 0x8276 # 0 +0xEEA0 0x82D2 # 0 +0xEEA1 0xF9A6 # 0 +0xEEA2 0x95BB # 0 +0xEEA3 0x9AE5 # 0 +0xEEA4 0x9E7D # 0 +0xEEA5 0x66C4 # 0 +0xEEA6 0xF9A7 # 0 +0xEEA7 0x71C1 # 0 +0xEEA8 0x8449 # 0 +0xEEA9 0xF9A8 # 0 +0xEEAA 0xF9A9 # 0 +0xEEAB 0x584B # 0 +0xEEAC 0xF9AA # 0 +0xEEAD 0xF9AB # 0 +0xEEAE 0x5DB8 # 0 +0xEEAF 0x5F71 # 0 +0xEEB0 0xF9AC # 0 +0xEEB1 0x6620 # 0 +0xEEB2 0x668E # 0 +0xEEB3 0x6979 # 0 +0xEEB4 0x69AE # 0 +0xEEB5 0x6C38 # 0 +0xEEB6 0x6CF3 # 0 +0xEEB7 0x6E36 # 0 +0xEEB8 0x6F41 # 0 +0xEEB9 0x6FDA # 0 +0xEEBA 0x701B # 0 +0xEEBB 0x702F # 0 +0xEEBC 0x7150 # 0 +0xEEBD 0x71DF # 0 +0xEEBE 0x7370 # 0 +0xEEBF 0xF9AD # 0 +0xEEC0 0x745B # 0 +0xEEC1 0xF9AE # 0 +0xEEC2 0x74D4 # 0 +0xEEC3 0x76C8 # 0 +0xEEC4 0x7A4E # 0 +0xEEC5 0x7E93 # 0 +0xEEC6 0xF9AF # 0 +0xEEC7 0xF9B0 # 0 +0xEEC8 0x82F1 # 0 +0xEEC9 0x8A60 # 0 +0xEECA 0x8FCE # 0 +0xEECB 0xF9B1 # 0 +0xEECC 0x9348 # 0 +0xEECD 0xF9B2 # 0 +0xEECE 0x9719 # 0 +0xEECF 0xF9B3 # 0 +0xEED0 0xF9B4 # 0 +0xEED1 0x4E42 # 0 +0xEED2 0x502A # 0 +0xEED3 0xF9B5 # 0 +0xEED4 0x5208 # 0 +0xEED5 0x53E1 # 0 +0xEED6 0x66F3 # 0 +0xEED7 0x6C6D # 0 +0xEED8 0x6FCA # 0 +0xEED9 0x730A # 0 +0xEEDA 0x777F # 0 +0xEEDB 0x7A62 # 0 +0xEEDC 0x82AE # 0 +0xEEDD 0x85DD # 0 +0xEEDE 0x8602 # 0 +0xEEDF 0xF9B6 # 0 +0xEEE0 0x88D4 # 0 +0xEEE1 0x8A63 # 0 +0xEEE2 0x8B7D # 0 +0xEEE3 0x8C6B # 0 +0xEEE4 0xF9B7 # 0 +0xEEE5 0x92B3 # 0 +0xEEE6 0xF9B8 # 0 +0xEEE7 0x9713 # 0 +0xEEE8 0x9810 # 0 +0xEEE9 0x4E94 # 0 +0xEEEA 0x4F0D # 0 +0xEEEB 0x4FC9 # 0 +0xEEEC 0x50B2 # 0 +0xEEED 0x5348 # 0 +0xEEEE 0x543E # 0 +0xEEEF 0x5433 # 0 +0xEEF0 0x55DA # 0 +0xEEF1 0x5862 # 0 +0xEEF2 0x58BA # 0 +0xEEF3 0x5967 # 0 +0xEEF4 0x5A1B # 0 +0xEEF5 0x5BE4 # 0 +0xEEF6 0x609F # 0 +0xEEF7 0xF9B9 # 0 +0xEEF8 0x61CA # 0 +0xEEF9 0x6556 # 0 +0xEEFA 0x65FF # 0 +0xEEFB 0x6664 # 0 +0xEEFC 0x68A7 # 0 +0xEEFD 0x6C5A # 0 +0xEEFE 0x6FB3 # 0 +0xEF31 0x70CF # 0 +0xEF32 0x71AC # 0 +0xEF33 0x7352 # 0 +0xEF34 0x7B7D # 0 +0xEF35 0x8708 # 0 +0xEF36 0x8AA4 # 0 +0xEF37 0x9C32 # 0 +0xEF38 0x9F07 # 0 +0xEF39 0x5C4B # 0 +0xEF3A 0x6C83 # 0 +0xEF3B 0x7344 # 0 +0xEF3C 0x7389 # 0 +0xEF3D 0x923A # 0 +0xEF3E 0x6EAB # 0 +0xEF3F 0x7465 # 0 +0xEF40 0x761F # 0 +0xEF41 0x7A69 # 0 +0xEF42 0x7E15 # 0 +0xEF43 0x860A # 0 +0xEF44 0x5140 # 0 +0xEF45 0x58C5 # 0 +0xEF46 0x64C1 # 0 +0xEF47 0x74EE # 0 +0xEF48 0x7515 # 0 +0xEF49 0x7670 # 0 +0xEF4A 0x7FC1 # 0 +0xEF4B 0x9095 # 0 +0xEF4C 0x96CD # 0 +0xEF4D 0x9954 # 0 +0xEF4E 0x6E26 # 0 +0xEF4F 0x74E6 # 0 +0xEF50 0x7AA9 # 0 +0xEF51 0x7AAA # 0 +0xEF52 0x81E5 # 0 +0xEF53 0x86D9 # 0 +0xEF54 0x8778 # 0 +0xEF55 0x8A1B # 0 +0xEF56 0x5A49 # 0 +0xEF57 0x5B8C # 0 +0xEF58 0x5B9B # 0 +0xEF59 0x68A1 # 0 +0xEF5A 0x6900 # 0 +0xEF5B 0x6D63 # 0 +0xEF5C 0x73A9 # 0 +0xEF5D 0x7413 # 0 +0xEF5E 0x742C # 0 +0xEF5F 0x7897 # 0 +0xEF60 0x7DE9 # 0 +0xEF61 0x7FEB # 0 +0xEF62 0x8118 # 0 +0xEF63 0x8155 # 0 +0xEF64 0x839E # 0 +0xEF65 0x8C4C # 0 +0xEF66 0x962E # 0 +0xEF67 0x9811 # 0 +0xEF68 0x66F0 # 0 +0xEF69 0x5F80 # 0 +0xEF6A 0x65FA # 0 +0xEF6B 0x6789 # 0 +0xEF6C 0x6C6A # 0 +0xEF6D 0x738B # 0 +0xEF6E 0x502D # 0 +0xEF6F 0x5A03 # 0 +0xEF70 0x6B6A # 0 +0xEF71 0x77EE # 0 +0xEF72 0x5916 # 0 +0xEF73 0x5D6C # 0 +0xEF74 0x5DCD # 0 +0xEF75 0x7325 # 0 +0xEF76 0x754F # 0 +0xEF77 0xF9BA # 0 +0xEF78 0xF9BB # 0 +0xEF79 0x50E5 # 0 +0xEF7A 0x51F9 # 0 +0xEF7B 0x582F # 0 +0xEF7C 0x592D # 0 +0xEF7D 0x5996 # 0 +0xEF7E 0x59DA # 0 +0xEF91 0x5BE5 # 0 +0xEF92 0xF9BC # 0 +0xEF93 0xF9BD # 0 +0xEF94 0x5DA2 # 0 +0xEF95 0x62D7 # 0 +0xEF96 0x6416 # 0 +0xEF97 0x6493 # 0 +0xEF98 0x64FE # 0 +0xEF99 0xF9BE # 0 +0xEF9A 0x66DC # 0 +0xEF9B 0xF9BF # 0 +0xEF9C 0x6A48 # 0 +0xEF9D 0xF9C0 # 0 +0xEF9E 0x71FF # 0 +0xEF9F 0x7464 # 0 +0xEFA0 0xF9C1 # 0 +0xEFA1 0x7A88 # 0 +0xEFA2 0x7AAF # 0 +0xEFA3 0x7E47 # 0 +0xEFA4 0x7E5E # 0 +0xEFA5 0x8000 # 0 +0xEFA6 0x8170 # 0 +0xEFA7 0xF9C2 # 0 +0xEFA8 0x87EF # 0 +0xEFA9 0x8981 # 0 +0xEFAA 0x8B20 # 0 +0xEFAB 0x9059 # 0 +0xEFAC 0xF9C3 # 0 +0xEFAD 0x9080 # 0 +0xEFAE 0x9952 # 0 +0xEFAF 0x617E # 0 +0xEFB0 0x6B32 # 0 +0xEFB1 0x6D74 # 0 +0xEFB2 0x7E1F # 0 +0xEFB3 0x8925 # 0 +0xEFB4 0x8FB1 # 0 +0xEFB5 0x4FD1 # 0 +0xEFB6 0x50AD # 0 +0xEFB7 0x5197 # 0 +0xEFB8 0x52C7 # 0 +0xEFB9 0x57C7 # 0 +0xEFBA 0x5889 # 0 +0xEFBB 0x5BB9 # 0 +0xEFBC 0x5EB8 # 0 +0xEFBD 0x6142 # 0 +0xEFBE 0x6995 # 0 +0xEFBF 0x6D8C # 0 +0xEFC0 0x6E67 # 0 +0xEFC1 0x6EB6 # 0 +0xEFC2 0x7194 # 0 +0xEFC3 0x7462 # 0 +0xEFC4 0x7528 # 0 +0xEFC5 0x752C # 0 +0xEFC6 0x8073 # 0 +0xEFC7 0x8338 # 0 +0xEFC8 0x84C9 # 0 +0xEFC9 0x8E0A # 0 +0xEFCA 0x9394 # 0 +0xEFCB 0x93DE # 0 +0xEFCC 0xF9C4 # 0 +0xEFCD 0x4E8E # 0 +0xEFCE 0x4F51 # 0 +0xEFCF 0x5076 # 0 +0xEFD0 0x512A # 0 +0xEFD1 0x53C8 # 0 +0xEFD2 0x53CB # 0 +0xEFD3 0x53F3 # 0 +0xEFD4 0x5B87 # 0 +0xEFD5 0x5BD3 # 0 +0xEFD6 0x5C24 # 0 +0xEFD7 0x611A # 0 +0xEFD8 0x6182 # 0 +0xEFD9 0x65F4 # 0 +0xEFDA 0x725B # 0 +0xEFDB 0x7397 # 0 +0xEFDC 0x7440 # 0 +0xEFDD 0x76C2 # 0 +0xEFDE 0x7950 # 0 +0xEFDF 0x7991 # 0 +0xEFE0 0x79B9 # 0 +0xEFE1 0x7D06 # 0 +0xEFE2 0x7FBD # 0 +0xEFE3 0x828B # 0 +0xEFE4 0x85D5 # 0 +0xEFE5 0x865E # 0 +0xEFE6 0x8FC2 # 0 +0xEFE7 0x9047 # 0 +0xEFE8 0x90F5 # 0 +0xEFE9 0x91EA # 0 +0xEFEA 0x9685 # 0 +0xEFEB 0x96E8 # 0 +0xEFEC 0x96E9 # 0 +0xEFED 0x52D6 # 0 +0xEFEE 0x5F67 # 0 +0xEFEF 0x65ED # 0 +0xEFF0 0x6631 # 0 +0xEFF1 0x682F # 0 +0xEFF2 0x715C # 0 +0xEFF3 0x7A36 # 0 +0xEFF4 0x90C1 # 0 +0xEFF5 0x980A # 0 +0xEFF6 0x4E91 # 0 +0xEFF7 0xF9C5 # 0 +0xEFF8 0x6A52 # 0 +0xEFF9 0x6B9E # 0 +0xEFFA 0x6F90 # 0 +0xEFFB 0x7189 # 0 +0xEFFC 0x8018 # 0 +0xEFFD 0x82B8 # 0 +0xEFFE 0x8553 # 0 +0xF031 0x904B # 0 +0xF032 0x9695 # 0 +0xF033 0x96F2 # 0 +0xF034 0x97FB # 0 +0xF035 0x851A # 0 +0xF036 0x9B31 # 0 +0xF037 0x4E90 # 0 +0xF038 0x718A # 0 +0xF039 0x96C4 # 0 +0xF03A 0x5143 # 0 +0xF03B 0x539F # 0 +0xF03C 0x54E1 # 0 +0xF03D 0x5713 # 0 +0xF03E 0x5712 # 0 +0xF03F 0x57A3 # 0 +0xF040 0x5A9B # 0 +0xF041 0x5AC4 # 0 +0xF042 0x5BC3 # 0 +0xF043 0x6028 # 0 +0xF044 0x613F # 0 +0xF045 0x63F4 # 0 +0xF046 0x6C85 # 0 +0xF047 0x6D39 # 0 +0xF048 0x6E72 # 0 +0xF049 0x6E90 # 0 +0xF04A 0x7230 # 0 +0xF04B 0x733F # 0 +0xF04C 0x7457 # 0 +0xF04D 0x82D1 # 0 +0xF04E 0x8881 # 0 +0xF04F 0x8F45 # 0 +0xF050 0x9060 # 0 +0xF051 0xF9C6 # 0 +0xF052 0x9662 # 0 +0xF053 0x9858 # 0 +0xF054 0x9D1B # 0 +0xF055 0x6708 # 0 +0xF056 0x8D8A # 0 +0xF057 0x925E # 0 +0xF058 0x4F4D # 0 +0xF059 0x5049 # 0 +0xF05A 0x50DE # 0 +0xF05B 0x5371 # 0 +0xF05C 0x570D # 0 +0xF05D 0x59D4 # 0 +0xF05E 0x5A01 # 0 +0xF05F 0x5C09 # 0 +0xF060 0x6170 # 0 +0xF061 0x6690 # 0 +0xF062 0x6E2D # 0 +0xF063 0x7232 # 0 +0xF064 0x744B # 0 +0xF065 0x7DEF # 0 +0xF066 0x80C3 # 0 +0xF067 0x840E # 0 +0xF068 0x8466 # 0 +0xF069 0x853F # 0 +0xF06A 0x875F # 0 +0xF06B 0x885B # 0 +0xF06C 0x8918 # 0 +0xF06D 0x8B02 # 0 +0xF06E 0x9055 # 0 +0xF06F 0x97CB # 0 +0xF070 0x9B4F # 0 +0xF071 0x4E73 # 0 +0xF072 0x4F91 # 0 +0xF073 0x5112 # 0 +0xF074 0x516A # 0 +0xF075 0xF9C7 # 0 +0xF076 0x552F # 0 +0xF077 0x55A9 # 0 +0xF078 0x5B7A # 0 +0xF079 0x5BA5 # 0 +0xF07A 0x5E7C # 0 +0xF07B 0x5E7D # 0 +0xF07C 0x5EBE # 0 +0xF07D 0x60A0 # 0 +0xF07E 0x60DF # 0 +0xF091 0x6108 # 0 +0xF092 0x6109 # 0 +0xF093 0x63C4 # 0 +0xF094 0x6538 # 0 +0xF095 0x6709 # 0 +0xF096 0xF9C8 # 0 +0xF097 0x67D4 # 0 +0xF098 0x67DA # 0 +0xF099 0xF9C9 # 0 +0xF09A 0x6961 # 0 +0xF09B 0x6962 # 0 +0xF09C 0x6CB9 # 0 +0xF09D 0x6D27 # 0 +0xF09E 0xF9CA # 0 +0xF09F 0x6E38 # 0 +0xF0A0 0xF9CB # 0 +0xF0A1 0x6FE1 # 0 +0xF0A2 0x7336 # 0 +0xF0A3 0x7337 # 0 +0xF0A4 0xF9CC # 0 +0xF0A5 0x745C # 0 +0xF0A6 0x7531 # 0 +0xF0A7 0xF9CD # 0 +0xF0A8 0x7652 # 0 +0xF0A9 0xF9CE # 0 +0xF0AA 0xF9CF # 0 +0xF0AB 0x7DAD # 0 +0xF0AC 0x81FE # 0 +0xF0AD 0x8438 # 0 +0xF0AE 0x88D5 # 0 +0xF0AF 0x8A98 # 0 +0xF0B0 0x8ADB # 0 +0xF0B1 0x8AED # 0 +0xF0B2 0x8E30 # 0 +0xF0B3 0x8E42 # 0 +0xF0B4 0x904A # 0 +0xF0B5 0x903E # 0 +0xF0B6 0x907A # 0 +0xF0B7 0x9149 # 0 +0xF0B8 0x91C9 # 0 +0xF0B9 0x936E # 0 +0xF0BA 0xF9D0 # 0 +0xF0BB 0xF9D1 # 0 +0xF0BC 0x5809 # 0 +0xF0BD 0xF9D2 # 0 +0xF0BE 0x6BD3 # 0 +0xF0BF 0x8089 # 0 +0xF0C0 0x80B2 # 0 +0xF0C1 0xF9D3 # 0 +0xF0C2 0xF9D4 # 0 +0xF0C3 0x5141 # 0 +0xF0C4 0x596B # 0 +0xF0C5 0x5C39 # 0 +0xF0C6 0xF9D5 # 0 +0xF0C7 0xF9D6 # 0 +0xF0C8 0x6F64 # 0 +0xF0C9 0x73A7 # 0 +0xF0CA 0x80E4 # 0 +0xF0CB 0x8D07 # 0 +0xF0CC 0xF9D7 # 0 +0xF0CD 0x9217 # 0 +0xF0CE 0x958F # 0 +0xF0CF 0xF9D8 # 0 +0xF0D0 0xF9D9 # 0 +0xF0D1 0xF9DA # 0 +0xF0D2 0xF9DB # 0 +0xF0D3 0x807F # 0 +0xF0D4 0x620E # 0 +0xF0D5 0x701C # 0 +0xF0D6 0x7D68 # 0 +0xF0D7 0x878D # 0 +0xF0D8 0xF9DC # 0 +0xF0D9 0x57A0 # 0 +0xF0DA 0x6069 # 0 +0xF0DB 0x6147 # 0 +0xF0DC 0x6BB7 # 0 +0xF0DD 0x8ABE # 0 +0xF0DE 0x9280 # 0 +0xF0DF 0x96B1 # 0 +0xF0E0 0x4E59 # 0 +0xF0E1 0x541F # 0 +0xF0E2 0x6DEB # 0 +0xF0E3 0x852D # 0 +0xF0E4 0x9670 # 0 +0xF0E5 0x97F3 # 0 +0xF0E6 0x98EE # 0 +0xF0E7 0x63D6 # 0 +0xF0E8 0x6CE3 # 0 +0xF0E9 0x9091 # 0 +0xF0EA 0x51DD # 0 +0xF0EB 0x61C9 # 0 +0xF0EC 0x81BA # 0 +0xF0ED 0x9DF9 # 0 +0xF0EE 0x4F9D # 0 +0xF0EF 0x501A # 0 +0xF0F0 0x5100 # 0 +0xF0F1 0x5B9C # 0 +0xF0F2 0x610F # 0 +0xF0F3 0x61FF # 0 +0xF0F4 0x64EC # 0 +0xF0F5 0x6905 # 0 +0xF0F6 0x6BC5 # 0 +0xF0F7 0x7591 # 0 +0xF0F8 0x77E3 # 0 +0xF0F9 0x7FA9 # 0 +0xF0FA 0x8264 # 0 +0xF0FB 0x858F # 0 +0xF0FC 0x87FB # 0 +0xF0FD 0x8863 # 0 +0xF0FE 0x8ABC # 0 +0xF131 0x8B70 # 0 +0xF132 0x91AB # 0 +0xF133 0x4E8C # 0 +0xF134 0x4EE5 # 0 +0xF135 0x4F0A # 0 +0xF136 0xF9DD # 0 +0xF137 0xF9DE # 0 +0xF138 0x5937 # 0 +0xF139 0x59E8 # 0 +0xF13A 0xF9DF # 0 +0xF13B 0x5DF2 # 0 +0xF13C 0x5F1B # 0 +0xF13D 0x5F5B # 0 +0xF13E 0x6021 # 0 +0xF13F 0xF9E0 # 0 +0xF140 0xF9E1 # 0 +0xF141 0xF9E2 # 0 +0xF142 0xF9E3 # 0 +0xF143 0x723E # 0 +0xF144 0x73E5 # 0 +0xF145 0xF9E4 # 0 +0xF146 0x7570 # 0 +0xF147 0x75CD # 0 +0xF148 0xF9E5 # 0 +0xF149 0x79FB # 0 +0xF14A 0xF9E6 # 0 +0xF14B 0x800C # 0 +0xF14C 0x8033 # 0 +0xF14D 0x8084 # 0 +0xF14E 0x82E1 # 0 +0xF14F 0x8351 # 0 +0xF150 0xF9E7 # 0 +0xF151 0xF9E8 # 0 +0xF152 0x8CBD # 0 +0xF153 0x8CB3 # 0 +0xF154 0x9087 # 0 +0xF155 0xF9E9 # 0 +0xF156 0xF9EA # 0 +0xF157 0x98F4 # 0 +0xF158 0x990C # 0 +0xF159 0xF9EB # 0 +0xF15A 0xF9EC # 0 +0xF15B 0x7037 # 0 +0xF15C 0x76CA # 0 +0xF15D 0x7FCA # 0 +0xF15E 0x7FCC # 0 +0xF15F 0x7FFC # 0 +0xF160 0x8B1A # 0 +0xF161 0x4EBA # 0 +0xF162 0x4EC1 # 0 +0xF163 0x5203 # 0 +0xF164 0x5370 # 0 +0xF165 0xF9ED # 0 +0xF166 0x54BD # 0 +0xF167 0x56E0 # 0 +0xF168 0x59FB # 0 +0xF169 0x5BC5 # 0 +0xF16A 0x5F15 # 0 +0xF16B 0x5FCD # 0 +0xF16C 0x6E6E # 0 +0xF16D 0xF9EE # 0 +0xF16E 0xF9EF # 0 +0xF16F 0x7D6A # 0 +0xF170 0x8335 # 0 +0xF171 0xF9F0 # 0 +0xF172 0x8693 # 0 +0xF173 0x8A8D # 0 +0xF174 0xF9F1 # 0 +0xF175 0x976D # 0 +0xF176 0x9777 # 0 +0xF177 0xF9F2 # 0 +0xF178 0xF9F3 # 0 +0xF179 0x4E00 # 0 +0xF17A 0x4F5A # 0 +0xF17B 0x4F7E # 0 +0xF17C 0x58F9 # 0 +0xF17D 0x65E5 # 0 +0xF17E 0x6EA2 # 0 +0xF191 0x9038 # 0 +0xF192 0x93B0 # 0 +0xF193 0x99B9 # 0 +0xF194 0x4EFB # 0 +0xF195 0x58EC # 0 +0xF196 0x598A # 0 +0xF197 0x59D9 # 0 +0xF198 0x6041 # 0 +0xF199 0xF9F4 # 0 +0xF19A 0xF9F5 # 0 +0xF19B 0x7A14 # 0 +0xF19C 0xF9F6 # 0 +0xF19D 0x834F # 0 +0xF19E 0x8CC3 # 0 +0xF19F 0x5165 # 0 +0xF1A0 0x5344 # 0 +0xF1A1 0xF9F7 # 0 +0xF1A2 0xF9F8 # 0 +0xF1A3 0xF9F9 # 0 +0xF1A4 0x4ECD # 0 +0xF1A5 0x5269 # 0 +0xF1A6 0x5B55 # 0 +0xF1A7 0x82BF # 0 +0xF1A8 0x4ED4 # 0 +0xF1A9 0x523A # 0 +0xF1AA 0x54A8 # 0 +0xF1AB 0x59C9 # 0 +0xF1AC 0x59FF # 0 +0xF1AD 0x5B50 # 0 +0xF1AE 0x5B57 # 0 +0xF1AF 0x5B5C # 0 +0xF1B0 0x6063 # 0 +0xF1B1 0x6148 # 0 +0xF1B2 0x6ECB # 0 +0xF1B3 0x7099 # 0 +0xF1B4 0x716E # 0 +0xF1B5 0x7386 # 0 +0xF1B6 0x74F7 # 0 +0xF1B7 0x75B5 # 0 +0xF1B8 0x78C1 # 0 +0xF1B9 0x7D2B # 0 +0xF1BA 0x8005 # 0 +0xF1BB 0x81EA # 0 +0xF1BC 0x8328 # 0 +0xF1BD 0x8517 # 0 +0xF1BE 0x85C9 # 0 +0xF1BF 0x8AEE # 0 +0xF1C0 0x8CC7 # 0 +0xF1C1 0x96CC # 0 +0xF1C2 0x4F5C # 0 +0xF1C3 0x52FA # 0 +0xF1C4 0x56BC # 0 +0xF1C5 0x65AB # 0 +0xF1C6 0x6628 # 0 +0xF1C7 0x707C # 0 +0xF1C8 0x70B8 # 0 +0xF1C9 0x7235 # 0 +0xF1CA 0x7DBD # 0 +0xF1CB 0x828D # 0 +0xF1CC 0x914C # 0 +0xF1CD 0x96C0 # 0 +0xF1CE 0x9D72 # 0 +0xF1CF 0x5B71 # 0 +0xF1D0 0x68E7 # 0 +0xF1D1 0x6B98 # 0 +0xF1D2 0x6F7A # 0 +0xF1D3 0x76DE # 0 +0xF1D4 0x5C91 # 0 +0xF1D5 0x66AB # 0 +0xF1D6 0x6F5B # 0 +0xF1D7 0x7BB4 # 0 +0xF1D8 0x7C2A # 0 +0xF1D9 0x8836 # 0 +0xF1DA 0x96DC # 0 +0xF1DB 0x4E08 # 0 +0xF1DC 0x4ED7 # 0 +0xF1DD 0x5320 # 0 +0xF1DE 0x5834 # 0 +0xF1DF 0x58BB # 0 +0xF1E0 0x58EF # 0 +0xF1E1 0x596C # 0 +0xF1E2 0x5C07 # 0 +0xF1E3 0x5E33 # 0 +0xF1E4 0x5E84 # 0 +0xF1E5 0x5F35 # 0 +0xF1E6 0x638C # 0 +0xF1E7 0x66B2 # 0 +0xF1E8 0x6756 # 0 +0xF1E9 0x6A1F # 0 +0xF1EA 0x6AA3 # 0 +0xF1EB 0x6B0C # 0 +0xF1EC 0x6F3F # 0 +0xF1ED 0x7246 # 0 +0xF1EE 0xF9FA # 0 +0xF1EF 0x7350 # 0 +0xF1F0 0x748B # 0 +0xF1F1 0x7AE0 # 0 +0xF1F2 0x7CA7 # 0 +0xF1F3 0x8178 # 0 +0xF1F4 0x81DF # 0 +0xF1F5 0x81E7 # 0 +0xF1F6 0x838A # 0 +0xF1F7 0x846C # 0 +0xF1F8 0x8523 # 0 +0xF1F9 0x8594 # 0 +0xF1FA 0x85CF # 0 +0xF1FB 0x88DD # 0 +0xF1FC 0x8D13 # 0 +0xF1FD 0x91AC # 0 +0xF1FE 0x9577 # 0 +0xF231 0x969C # 0 +0xF232 0x518D # 0 +0xF233 0x54C9 # 0 +0xF234 0x5728 # 0 +0xF235 0x5BB0 # 0 +0xF236 0x624D # 0 +0xF237 0x6750 # 0 +0xF238 0x683D # 0 +0xF239 0x6893 # 0 +0xF23A 0x6E3D # 0 +0xF23B 0x6ED3 # 0 +0xF23C 0x707D # 0 +0xF23D 0x7E21 # 0 +0xF23E 0x88C1 # 0 +0xF23F 0x8CA1 # 0 +0xF240 0x8F09 # 0 +0xF241 0x9F4B # 0 +0xF242 0x9F4E # 0 +0xF243 0x722D # 0 +0xF244 0x7B8F # 0 +0xF245 0x8ACD # 0 +0xF246 0x931A # 0 +0xF247 0x4F47 # 0 +0xF248 0x4F4E # 0 +0xF249 0x5132 # 0 +0xF24A 0x5480 # 0 +0xF24B 0x59D0 # 0 +0xF24C 0x5E95 # 0 +0xF24D 0x62B5 # 0 +0xF24E 0x6775 # 0 +0xF24F 0x696E # 0 +0xF250 0x6A17 # 0 +0xF251 0x6CAE # 0 +0xF252 0x6E1A # 0 +0xF253 0x72D9 # 0 +0xF254 0x732A # 0 +0xF255 0x75BD # 0 +0xF256 0x7BB8 # 0 +0xF257 0x7D35 # 0 +0xF258 0x82E7 # 0 +0xF259 0x83F9 # 0 +0xF25A 0x8457 # 0 +0xF25B 0x85F7 # 0 +0xF25C 0x8A5B # 0 +0xF25D 0x8CAF # 0 +0xF25E 0x8E87 # 0 +0xF25F 0x9019 # 0 +0xF260 0x90B8 # 0 +0xF261 0x96CE # 0 +0xF262 0x9F5F # 0 +0xF263 0x52E3 # 0 +0xF264 0x540A # 0 +0xF265 0x5AE1 # 0 +0xF266 0x5BC2 # 0 +0xF267 0x6458 # 0 +0xF268 0x6575 # 0 +0xF269 0x6EF4 # 0 +0xF26A 0x72C4 # 0 +0xF26B 0xF9FB # 0 +0xF26C 0x7684 # 0 +0xF26D 0x7A4D # 0 +0xF26E 0x7B1B # 0 +0xF26F 0x7C4D # 0 +0xF270 0x7E3E # 0 +0xF271 0x7FDF # 0 +0xF272 0x837B # 0 +0xF273 0x8B2B # 0 +0xF274 0x8CCA # 0 +0xF275 0x8D64 # 0 +0xF276 0x8DE1 # 0 +0xF277 0x8E5F # 0 +0xF278 0x8FEA # 0 +0xF279 0x8FF9 # 0 +0xF27A 0x9069 # 0 +0xF27B 0x93D1 # 0 +0xF27C 0x4F43 # 0 +0xF27D 0x4F7A # 0 +0xF27E 0x50B3 # 0 +0xF291 0x5168 # 0 +0xF292 0x5178 # 0 +0xF293 0x524D # 0 +0xF294 0x526A # 0 +0xF295 0x5861 # 0 +0xF296 0x587C # 0 +0xF297 0x5960 # 0 +0xF298 0x5C08 # 0 +0xF299 0x5C55 # 0 +0xF29A 0x5EDB # 0 +0xF29B 0x609B # 0 +0xF29C 0x6230 # 0 +0xF29D 0x6813 # 0 +0xF29E 0x6BBF # 0 +0xF29F 0x6C08 # 0 +0xF2A0 0x6FB1 # 0 +0xF2A1 0x714E # 0 +0xF2A2 0x7420 # 0 +0xF2A3 0x7530 # 0 +0xF2A4 0x7538 # 0 +0xF2A5 0x7551 # 0 +0xF2A6 0x7672 # 0 +0xF2A7 0x7B4C # 0 +0xF2A8 0x7B8B # 0 +0xF2A9 0x7BAD # 0 +0xF2AA 0x7BC6 # 0 +0xF2AB 0x7E8F # 0 +0xF2AC 0x8A6E # 0 +0xF2AD 0x8F3E # 0 +0xF2AE 0x8F49 # 0 +0xF2AF 0x923F # 0 +0xF2B0 0x9293 # 0 +0xF2B1 0x9322 # 0 +0xF2B2 0x942B # 0 +0xF2B3 0x96FB # 0 +0xF2B4 0x985A # 0 +0xF2B5 0x986B # 0 +0xF2B6 0x991E # 0 +0xF2B7 0x5207 # 0 +0xF2B8 0x622A # 0 +0xF2B9 0x6298 # 0 +0xF2BA 0x6D59 # 0 +0xF2BB 0x7664 # 0 +0xF2BC 0x7ACA # 0 +0xF2BD 0x7BC0 # 0 +0xF2BE 0x7D76 # 0 +0xF2BF 0x5360 # 0 +0xF2C0 0x5CBE # 0 +0xF2C1 0x5E97 # 0 +0xF2C2 0x6F38 # 0 +0xF2C3 0x70B9 # 0 +0xF2C4 0x7C98 # 0 +0xF2C5 0x9711 # 0 +0xF2C6 0x9B8E # 0 +0xF2C7 0x9EDE # 0 +0xF2C8 0x63A5 # 0 +0xF2C9 0x647A # 0 +0xF2CA 0x8776 # 0 +0xF2CB 0x4E01 # 0 +0xF2CC 0x4E95 # 0 +0xF2CD 0x4EAD # 0 +0xF2CE 0x505C # 0 +0xF2CF 0x5075 # 0 +0xF2D0 0x5448 # 0 +0xF2D1 0x59C3 # 0 +0xF2D2 0x5B9A # 0 +0xF2D3 0x5E40 # 0 +0xF2D4 0x5EAD # 0 +0xF2D5 0x5EF7 # 0 +0xF2D6 0x5F81 # 0 +0xF2D7 0x60C5 # 0 +0xF2D8 0x633A # 0 +0xF2D9 0x653F # 0 +0xF2DA 0x6574 # 0 +0xF2DB 0x65CC # 0 +0xF2DC 0x6676 # 0 +0xF2DD 0x6678 # 0 +0xF2DE 0x67FE # 0 +0xF2DF 0x6968 # 0 +0xF2E0 0x6A89 # 0 +0xF2E1 0x6B63 # 0 +0xF2E2 0x6C40 # 0 +0xF2E3 0x6DC0 # 0 +0xF2E4 0x6DE8 # 0 +0xF2E5 0x6E1F # 0 +0xF2E6 0x6E5E # 0 +0xF2E7 0x701E # 0 +0xF2E8 0x70A1 # 0 +0xF2E9 0x738E # 0 +0xF2EA 0x73FD # 0 +0xF2EB 0x753A # 0 +0xF2EC 0x775B # 0 +0xF2ED 0x7887 # 0 +0xF2EE 0x798E # 0 +0xF2EF 0x7A0B # 0 +0xF2F0 0x7A7D # 0 +0xF2F1 0x7CBE # 0 +0xF2F2 0x7D8E # 0 +0xF2F3 0x8247 # 0 +0xF2F4 0x8A02 # 0 +0xF2F5 0x8AEA # 0 +0xF2F6 0x8C9E # 0 +0xF2F7 0x912D # 0 +0xF2F8 0x914A # 0 +0xF2F9 0x91D8 # 0 +0xF2FA 0x9266 # 0 +0xF2FB 0x92CC # 0 +0xF2FC 0x9320 # 0 +0xF2FD 0x9706 # 0 +0xF2FE 0x9756 # 0 +0xF331 0x975C # 0 +0xF332 0x9802 # 0 +0xF333 0x9F0E # 0 +0xF334 0x5236 # 0 +0xF335 0x5291 # 0 +0xF336 0x557C # 0 +0xF337 0x5824 # 0 +0xF338 0x5E1D # 0 +0xF339 0x5F1F # 0 +0xF33A 0x608C # 0 +0xF33B 0x63D0 # 0 +0xF33C 0x68AF # 0 +0xF33D 0x6FDF # 0 +0xF33E 0x796D # 0 +0xF33F 0x7B2C # 0 +0xF340 0x81CD # 0 +0xF341 0x85BA # 0 +0xF342 0x88FD # 0 +0xF343 0x8AF8 # 0 +0xF344 0x8E44 # 0 +0xF345 0x918D # 0 +0xF346 0x9664 # 0 +0xF347 0x969B # 0 +0xF348 0x973D # 0 +0xF349 0x984C # 0 +0xF34A 0x9F4A # 0 +0xF34B 0x4FCE # 0 +0xF34C 0x5146 # 0 +0xF34D 0x51CB # 0 +0xF34E 0x52A9 # 0 +0xF34F 0x5632 # 0 +0xF350 0x5F14 # 0 +0xF351 0x5F6B # 0 +0xF352 0x63AA # 0 +0xF353 0x64CD # 0 +0xF354 0x65E9 # 0 +0xF355 0x6641 # 0 +0xF356 0x66FA # 0 +0xF357 0x66F9 # 0 +0xF358 0x671D # 0 +0xF359 0x689D # 0 +0xF35A 0x68D7 # 0 +0xF35B 0x69FD # 0 +0xF35C 0x6F15 # 0 +0xF35D 0x6F6E # 0 +0xF35E 0x7167 # 0 +0xF35F 0x71E5 # 0 +0xF360 0x722A # 0 +0xF361 0x74AA # 0 +0xF362 0x773A # 0 +0xF363 0x7956 # 0 +0xF364 0x795A # 0 +0xF365 0x79DF # 0 +0xF366 0x7A20 # 0 +0xF367 0x7A95 # 0 +0xF368 0x7C97 # 0 +0xF369 0x7CDF # 0 +0xF36A 0x7D44 # 0 +0xF36B 0x7E70 # 0 +0xF36C 0x8087 # 0 +0xF36D 0x85FB # 0 +0xF36E 0x86A4 # 0 +0xF36F 0x8A54 # 0 +0xF370 0x8ABF # 0 +0xF371 0x8D99 # 0 +0xF372 0x8E81 # 0 +0xF373 0x9020 # 0 +0xF374 0x906D # 0 +0xF375 0x91E3 # 0 +0xF376 0x963B # 0 +0xF377 0x96D5 # 0 +0xF378 0x9CE5 # 0 +0xF379 0x65CF # 0 +0xF37A 0x7C07 # 0 +0xF37B 0x8DB3 # 0 +0xF37C 0x93C3 # 0 +0xF37D 0x5B58 # 0 +0xF37E 0x5C0A # 0 +0xF391 0x5352 # 0 +0xF392 0x62D9 # 0 +0xF393 0x731D # 0 +0xF394 0x5027 # 0 +0xF395 0x5B97 # 0 +0xF396 0x5F9E # 0 +0xF397 0x60B0 # 0 +0xF398 0x616B # 0 +0xF399 0x68D5 # 0 +0xF39A 0x6DD9 # 0 +0xF39B 0x742E # 0 +0xF39C 0x7A2E # 0 +0xF39D 0x7D42 # 0 +0xF39E 0x7D9C # 0 +0xF39F 0x7E31 # 0 +0xF3A0 0x816B # 0 +0xF3A1 0x8E2A # 0 +0xF3A2 0x8E35 # 0 +0xF3A3 0x937E # 0 +0xF3A4 0x9418 # 0 +0xF3A5 0x4F50 # 0 +0xF3A6 0x5750 # 0 +0xF3A7 0x5DE6 # 0 +0xF3A8 0x5EA7 # 0 +0xF3A9 0x632B # 0 +0xF3AA 0x7F6A # 0 +0xF3AB 0x4E3B # 0 +0xF3AC 0x4F4F # 0 +0xF3AD 0x4F8F # 0 +0xF3AE 0x505A # 0 +0xF3AF 0x59DD # 0 +0xF3B0 0x80C4 # 0 +0xF3B1 0x546A # 0 +0xF3B2 0x5468 # 0 +0xF3B3 0x55FE # 0 +0xF3B4 0x594F # 0 +0xF3B5 0x5B99 # 0 +0xF3B6 0x5DDE # 0 +0xF3B7 0x5EDA # 0 +0xF3B8 0x665D # 0 +0xF3B9 0x6731 # 0 +0xF3BA 0x67F1 # 0 +0xF3BB 0x682A # 0 +0xF3BC 0x6CE8 # 0 +0xF3BD 0x6D32 # 0 +0xF3BE 0x6E4A # 0 +0xF3BF 0x6F8D # 0 +0xF3C0 0x70B7 # 0 +0xF3C1 0x73E0 # 0 +0xF3C2 0x7587 # 0 +0xF3C3 0x7C4C # 0 +0xF3C4 0x7D02 # 0 +0xF3C5 0x7D2C # 0 +0xF3C6 0x7DA2 # 0 +0xF3C7 0x821F # 0 +0xF3C8 0x86DB # 0 +0xF3C9 0x8A3B # 0 +0xF3CA 0x8A85 # 0 +0xF3CB 0x8D70 # 0 +0xF3CC 0x8E8A # 0 +0xF3CD 0x8F33 # 0 +0xF3CE 0x9031 # 0 +0xF3CF 0x914E # 0 +0xF3D0 0x9152 # 0 +0xF3D1 0x9444 # 0 +0xF3D2 0x99D0 # 0 +0xF3D3 0x7AF9 # 0 +0xF3D4 0x7CA5 # 0 +0xF3D5 0x4FCA # 0 +0xF3D6 0x5101 # 0 +0xF3D7 0x51C6 # 0 +0xF3D8 0x57C8 # 0 +0xF3D9 0x5BEF # 0 +0xF3DA 0x5CFB # 0 +0xF3DB 0x6659 # 0 +0xF3DC 0x6A3D # 0 +0xF3DD 0x6D5A # 0 +0xF3DE 0x6E96 # 0 +0xF3DF 0x6FEC # 0 +0xF3E0 0x710C # 0 +0xF3E1 0x756F # 0 +0xF3E2 0x7AE3 # 0 +0xF3E3 0x8822 # 0 +0xF3E4 0x9021 # 0 +0xF3E5 0x9075 # 0 +0xF3E6 0x96CB # 0 +0xF3E7 0x99FF # 0 +0xF3E8 0x8301 # 0 +0xF3E9 0x4E2D # 0 +0xF3EA 0x4EF2 # 0 +0xF3EB 0x8846 # 0 +0xF3EC 0x91CD # 0 +0xF3ED 0x537D # 0 +0xF3EE 0x6ADB # 0 +0xF3EF 0x696B # 0 +0xF3F0 0x6C41 # 0 +0xF3F1 0x847A # 0 +0xF3F2 0x589E # 0 +0xF3F3 0x618E # 0 +0xF3F4 0x66FE # 0 +0xF3F5 0x62EF # 0 +0xF3F6 0x70DD # 0 +0xF3F7 0x7511 # 0 +0xF3F8 0x75C7 # 0 +0xF3F9 0x7E52 # 0 +0xF3FA 0x84B8 # 0 +0xF3FB 0x8B49 # 0 +0xF3FC 0x8D08 # 0 +0xF3FD 0x4E4B # 0 +0xF3FE 0x53EA # 0 +0xF431 0x54AB # 0 +0xF432 0x5730 # 0 +0xF433 0x5740 # 0 +0xF434 0x5FD7 # 0 +0xF435 0x6301 # 0 +0xF436 0x6307 # 0 +0xF437 0x646F # 0 +0xF438 0x652F # 0 +0xF439 0x65E8 # 0 +0xF43A 0x667A # 0 +0xF43B 0x679D # 0 +0xF43C 0x67B3 # 0 +0xF43D 0x6B62 # 0 +0xF43E 0x6C60 # 0 +0xF43F 0x6C9A # 0 +0xF440 0x6F2C # 0 +0xF441 0x77E5 # 0 +0xF442 0x7825 # 0 +0xF443 0x7949 # 0 +0xF444 0x7957 # 0 +0xF445 0x7D19 # 0 +0xF446 0x80A2 # 0 +0xF447 0x8102 # 0 +0xF448 0x81F3 # 0 +0xF449 0x829D # 0 +0xF44A 0x82B7 # 0 +0xF44B 0x8718 # 0 +0xF44C 0x8A8C # 0 +0xF44D 0xF9FC # 0 +0xF44E 0x8D04 # 0 +0xF44F 0x8DBE # 0 +0xF450 0x9072 # 0 +0xF451 0x76F4 # 0 +0xF452 0x7A19 # 0 +0xF453 0x7A37 # 0 +0xF454 0x7E54 # 0 +0xF455 0x8077 # 0 +0xF456 0x5507 # 0 +0xF457 0x55D4 # 0 +0xF458 0x5875 # 0 +0xF459 0x632F # 0 +0xF45A 0x6422 # 0 +0xF45B 0x6649 # 0 +0xF45C 0x664B # 0 +0xF45D 0x686D # 0 +0xF45E 0x699B # 0 +0xF45F 0x6B84 # 0 +0xF460 0x6D25 # 0 +0xF461 0x6EB1 # 0 +0xF462 0x73CD # 0 +0xF463 0x7468 # 0 +0xF464 0x74A1 # 0 +0xF465 0x755B # 0 +0xF466 0x75B9 # 0 +0xF467 0x76E1 # 0 +0xF468 0x771E # 0 +0xF469 0x778B # 0 +0xF46A 0x79E6 # 0 +0xF46B 0x7E09 # 0 +0xF46C 0x7E1D # 0 +0xF46D 0x81FB # 0 +0xF46E 0x852F # 0 +0xF46F 0x8897 # 0 +0xF470 0x8A3A # 0 +0xF471 0x8CD1 # 0 +0xF472 0x8EEB # 0 +0xF473 0x8FB0 # 0 +0xF474 0x9032 # 0 +0xF475 0x93AD # 0 +0xF476 0x9663 # 0 +0xF477 0x9673 # 0 +0xF478 0x9707 # 0 +0xF479 0x4F84 # 0 +0xF47A 0x53F1 # 0 +0xF47B 0x59EA # 0 +0xF47C 0x5AC9 # 0 +0xF47D 0x5E19 # 0 +0xF47E 0x684E # 0 +0xF491 0x74C6 # 0 +0xF492 0x75BE # 0 +0xF493 0x79E9 # 0 +0xF494 0x7A92 # 0 +0xF495 0x81A3 # 0 +0xF496 0x86ED # 0 +0xF497 0x8CEA # 0 +0xF498 0x8DCC # 0 +0xF499 0x8FED # 0 +0xF49A 0x659F # 0 +0xF49B 0x6715 # 0 +0xF49C 0xF9FD # 0 +0xF49D 0x57F7 # 0 +0xF49E 0x6F57 # 0 +0xF49F 0x7DDD # 0 +0xF4A0 0x8F2F # 0 +0xF4A1 0x93F6 # 0 +0xF4A2 0x96C6 # 0 +0xF4A3 0x5FB5 # 0 +0xF4A4 0x61F2 # 0 +0xF4A5 0x6F84 # 0 +0xF4A6 0x4E14 # 0 +0xF4A7 0x4F98 # 0 +0xF4A8 0x501F # 0 +0xF4A9 0x53C9 # 0 +0xF4AA 0x55DF # 0 +0xF4AB 0x5D6F # 0 +0xF4AC 0x5DEE # 0 +0xF4AD 0x6B21 # 0 +0xF4AE 0x6B64 # 0 +0xF4AF 0x78CB # 0 +0xF4B0 0x7B9A # 0 +0xF4B1 0xF9FE # 0 +0xF4B2 0x8E49 # 0 +0xF4B3 0x8ECA # 0 +0xF4B4 0x906E # 0 +0xF4B5 0x6349 # 0 +0xF4B6 0x643E # 0 +0xF4B7 0x7740 # 0 +0xF4B8 0x7A84 # 0 +0xF4B9 0x932F # 0 +0xF4BA 0x947F # 0 +0xF4BB 0x9F6A # 0 +0xF4BC 0x64B0 # 0 +0xF4BD 0x6FAF # 0 +0xF4BE 0x71E6 # 0 +0xF4BF 0x74A8 # 0 +0xF4C0 0x74DA # 0 +0xF4C1 0x7AC4 # 0 +0xF4C2 0x7C12 # 0 +0xF4C3 0x7E82 # 0 +0xF4C4 0x7CB2 # 0 +0xF4C5 0x7E98 # 0 +0xF4C6 0x8B9A # 0 +0xF4C7 0x8D0A # 0 +0xF4C8 0x947D # 0 +0xF4C9 0x9910 # 0 +0xF4CA 0x994C # 0 +0xF4CB 0x5239 # 0 +0xF4CC 0x5BDF # 0 +0xF4CD 0x64E6 # 0 +0xF4CE 0x672D # 0 +0xF4CF 0x7D2E # 0 +0xF4D0 0x50ED # 0 +0xF4D1 0x53C3 # 0 +0xF4D2 0x5879 # 0 +0xF4D3 0x6158 # 0 +0xF4D4 0x6159 # 0 +0xF4D5 0x61FA # 0 +0xF4D6 0x65AC # 0 +0xF4D7 0x7AD9 # 0 +0xF4D8 0x8B92 # 0 +0xF4D9 0x8B96 # 0 +0xF4DA 0x5009 # 0 +0xF4DB 0x5021 # 0 +0xF4DC 0x5275 # 0 +0xF4DD 0x5531 # 0 +0xF4DE 0x5A3C # 0 +0xF4DF 0x5EE0 # 0 +0xF4E0 0x5F70 # 0 +0xF4E1 0x6134 # 0 +0xF4E2 0x655E # 0 +0xF4E3 0x660C # 0 +0xF4E4 0x6636 # 0 +0xF4E5 0x66A2 # 0 +0xF4E6 0x69CD # 0 +0xF4E7 0x6EC4 # 0 +0xF4E8 0x6F32 # 0 +0xF4E9 0x7316 # 0 +0xF4EA 0x7621 # 0 +0xF4EB 0x7A93 # 0 +0xF4EC 0x8139 # 0 +0xF4ED 0x8259 # 0 +0xF4EE 0x83D6 # 0 +0xF4EF 0x84BC # 0 +0xF4F0 0x50B5 # 0 +0xF4F1 0x57F0 # 0 +0xF4F2 0x5BC0 # 0 +0xF4F3 0x5BE8 # 0 +0xF4F4 0x5F69 # 0 +0xF4F5 0x63A1 # 0 +0xF4F6 0x7826 # 0 +0xF4F7 0x7DB5 # 0 +0xF4F8 0x83DC # 0 +0xF4F9 0x8521 # 0 +0xF4FA 0x91C7 # 0 +0xF4FB 0x91F5 # 0 +0xF4FC 0x518A # 0 +0xF4FD 0x67F5 # 0 +0xF4FE 0x7B56 # 0 +0xF531 0x8CAC # 0 +0xF532 0x51C4 # 0 +0xF533 0x59BB # 0 +0xF534 0x60BD # 0 +0xF535 0x8655 # 0 +0xF536 0x501C # 0 +0xF537 0xF9FF # 0 +0xF538 0x5254 # 0 +0xF539 0x5C3A # 0 +0xF53A 0x617D # 0 +0xF53B 0x621A # 0 +0xF53C 0x62D3 # 0 +0xF53D 0x64F2 # 0 +0xF53E 0x65A5 # 0 +0xF53F 0x6ECC # 0 +0xF540 0x7620 # 0 +0xF541 0x810A # 0 +0xF542 0x8E60 # 0 +0xF543 0x965F # 0 +0xF544 0x96BB # 0 +0xF545 0x4EDF # 0 +0xF546 0x5343 # 0 +0xF547 0x5598 # 0 +0xF548 0x5929 # 0 +0xF549 0x5DDD # 0 +0xF54A 0x64C5 # 0 +0xF54B 0x6CC9 # 0 +0xF54C 0x6DFA # 0 +0xF54D 0x7394 # 0 +0xF54E 0x7A7F # 0 +0xF54F 0x821B # 0 +0xF550 0x85A6 # 0 +0xF551 0x8CE4 # 0 +0xF552 0x8E10 # 0 +0xF553 0x9077 # 0 +0xF554 0x91E7 # 0 +0xF555 0x95E1 # 0 +0xF556 0x9621 # 0 +0xF557 0x97C6 # 0 +0xF558 0x51F8 # 0 +0xF559 0x54F2 # 0 +0xF55A 0x5586 # 0 +0xF55B 0x5FB9 # 0 +0xF55C 0x64A4 # 0 +0xF55D 0x6F88 # 0 +0xF55E 0x7DB4 # 0 +0xF55F 0x8F1F # 0 +0xF560 0x8F4D # 0 +0xF561 0x9435 # 0 +0xF562 0x50C9 # 0 +0xF563 0x5C16 # 0 +0xF564 0x6CBE # 0 +0xF565 0x6DFB # 0 +0xF566 0x751B # 0 +0xF567 0x77BB # 0 +0xF568 0x7C3D # 0 +0xF569 0x7C64 # 0 +0xF56A 0x8A79 # 0 +0xF56B 0x8AC2 # 0 +0xF56C 0x581E # 0 +0xF56D 0x59BE # 0 +0xF56E 0x5E16 # 0 +0xF56F 0x6377 # 0 +0xF570 0x7252 # 0 +0xF571 0x758A # 0 +0xF572 0x776B # 0 +0xF573 0x8ADC # 0 +0xF574 0x8CBC # 0 +0xF575 0x8F12 # 0 +0xF576 0x5EF3 # 0 +0xF577 0x6674 # 0 +0xF578 0x6DF8 # 0 +0xF579 0x807D # 0 +0xF57A 0x83C1 # 0 +0xF57B 0x8ACB # 0 +0xF57C 0x9751 # 0 +0xF57D 0x9BD6 # 0 +0xF57E 0xFA00 # 0 +0xF591 0x5243 # 0 +0xF592 0x66FF # 0 +0xF593 0x6D95 # 0 +0xF594 0x6EEF # 0 +0xF595 0x7DE0 # 0 +0xF596 0x8AE6 # 0 +0xF597 0x902E # 0 +0xF598 0x905E # 0 +0xF599 0x9AD4 # 0 +0xF59A 0x521D # 0 +0xF59B 0x527F # 0 +0xF59C 0x54E8 # 0 +0xF59D 0x6194 # 0 +0xF59E 0x6284 # 0 +0xF59F 0x62DB # 0 +0xF5A0 0x68A2 # 0 +0xF5A1 0x6912 # 0 +0xF5A2 0x695A # 0 +0xF5A3 0x6A35 # 0 +0xF5A4 0x7092 # 0 +0xF5A5 0x7126 # 0 +0xF5A6 0x785D # 0 +0xF5A7 0x7901 # 0 +0xF5A8 0x790E # 0 +0xF5A9 0x79D2 # 0 +0xF5AA 0x7A0D # 0 +0xF5AB 0x8096 # 0 +0xF5AC 0x8278 # 0 +0xF5AD 0x82D5 # 0 +0xF5AE 0x8349 # 0 +0xF5AF 0x8549 # 0 +0xF5B0 0x8C82 # 0 +0xF5B1 0x8D85 # 0 +0xF5B2 0x9162 # 0 +0xF5B3 0x918B # 0 +0xF5B4 0x91AE # 0 +0xF5B5 0x4FC3 # 0 +0xF5B6 0x56D1 # 0 +0xF5B7 0x71ED # 0 +0xF5B8 0x77D7 # 0 +0xF5B9 0x8700 # 0 +0xF5BA 0x89F8 # 0 +0xF5BB 0x5BF8 # 0 +0xF5BC 0x5FD6 # 0 +0xF5BD 0x6751 # 0 +0xF5BE 0x90A8 # 0 +0xF5BF 0x53E2 # 0 +0xF5C0 0x585A # 0 +0xF5C1 0x5BF5 # 0 +0xF5C2 0x60A4 # 0 +0xF5C3 0x6181 # 0 +0xF5C4 0x6460 # 0 +0xF5C5 0x7E3D # 0 +0xF5C6 0x8070 # 0 +0xF5C7 0x8525 # 0 +0xF5C8 0x9283 # 0 +0xF5C9 0x64AE # 0 +0xF5CA 0x50AC # 0 +0xF5CB 0x5D14 # 0 +0xF5CC 0x6700 # 0 +0xF5CD 0x589C # 0 +0xF5CE 0x62BD # 0 +0xF5CF 0x63A8 # 0 +0xF5D0 0x690E # 0 +0xF5D1 0x6978 # 0 +0xF5D2 0x6A1E # 0 +0xF5D3 0x6E6B # 0 +0xF5D4 0x76BA # 0 +0xF5D5 0x79CB # 0 +0xF5D6 0x82BB # 0 +0xF5D7 0x8429 # 0 +0xF5D8 0x8ACF # 0 +0xF5D9 0x8DA8 # 0 +0xF5DA 0x8FFD # 0 +0xF5DB 0x9112 # 0 +0xF5DC 0x914B # 0 +0xF5DD 0x919C # 0 +0xF5DE 0x9310 # 0 +0xF5DF 0x9318 # 0 +0xF5E0 0x939A # 0 +0xF5E1 0x96DB # 0 +0xF5E2 0x9A36 # 0 +0xF5E3 0x9C0D # 0 +0xF5E4 0x4E11 # 0 +0xF5E5 0x755C # 0 +0xF5E6 0x795D # 0 +0xF5E7 0x7AFA # 0 +0xF5E8 0x7B51 # 0 +0xF5E9 0x7BC9 # 0 +0xF5EA 0x7E2E # 0 +0xF5EB 0x84C4 # 0 +0xF5EC 0x8E59 # 0 +0xF5ED 0x8E74 # 0 +0xF5EE 0x8EF8 # 0 +0xF5EF 0x9010 # 0 +0xF5F0 0x6625 # 0 +0xF5F1 0x693F # 0 +0xF5F2 0x7443 # 0 +0xF5F3 0x51FA # 0 +0xF5F4 0x672E # 0 +0xF5F5 0x9EDC # 0 +0xF5F6 0x5145 # 0 +0xF5F7 0x5FE0 # 0 +0xF5F8 0x6C96 # 0 +0xF5F9 0x87F2 # 0 +0xF5FA 0x885D # 0 +0xF5FB 0x8877 # 0 +0xF5FC 0x60B4 # 0 +0xF5FD 0x81B5 # 0 +0xF5FE 0x8403 # 0 +0xF631 0x8D05 # 0 +0xF632 0x53D6 # 0 +0xF633 0x5439 # 0 +0xF634 0x5634 # 0 +0xF635 0x5A36 # 0 +0xF636 0x5C31 # 0 +0xF637 0x708A # 0 +0xF638 0x7FE0 # 0 +0xF639 0x805A # 0 +0xF63A 0x8106 # 0 +0xF63B 0x81ED # 0 +0xF63C 0x8DA3 # 0 +0xF63D 0x9189 # 0 +0xF63E 0x9A5F # 0 +0xF63F 0x9DF2 # 0 +0xF640 0x5074 # 0 +0xF641 0x4EC4 # 0 +0xF642 0x53A0 # 0 +0xF643 0x60FB # 0 +0xF644 0x6E2C # 0 +0xF645 0x5C64 # 0 +0xF646 0x4F88 # 0 +0xF647 0x5024 # 0 +0xF648 0x55E4 # 0 +0xF649 0x5CD9 # 0 +0xF64A 0x5E5F # 0 +0xF64B 0x6065 # 0 +0xF64C 0x6894 # 0 +0xF64D 0x6CBB # 0 +0xF64E 0x6DC4 # 0 +0xF64F 0x71BE # 0 +0xF650 0x75D4 # 0 +0xF651 0x75F4 # 0 +0xF652 0x7661 # 0 +0xF653 0x7A1A # 0 +0xF654 0x7A49 # 0 +0xF655 0x7DC7 # 0 +0xF656 0x7DFB # 0 +0xF657 0x7F6E # 0 +0xF658 0x81F4 # 0 +0xF659 0x86A9 # 0 +0xF65A 0x8F1C # 0 +0xF65B 0x96C9 # 0 +0xF65C 0x99B3 # 0 +0xF65D 0x9F52 # 0 +0xF65E 0x5247 # 0 +0xF65F 0x52C5 # 0 +0xF660 0x98ED # 0 +0xF661 0x89AA # 0 +0xF662 0x4E03 # 0 +0xF663 0x67D2 # 0 +0xF664 0x6F06 # 0 +0xF665 0x4FB5 # 0 +0xF666 0x5BE2 # 0 +0xF667 0x6795 # 0 +0xF668 0x6C88 # 0 +0xF669 0x6D78 # 0 +0xF66A 0x741B # 0 +0xF66B 0x7827 # 0 +0xF66C 0x91DD # 0 +0xF66D 0x937C # 0 +0xF66E 0x87C4 # 0 +0xF66F 0x79E4 # 0 +0xF670 0x7A31 # 0 +0xF671 0x5FEB # 0 +0xF672 0x4ED6 # 0 +0xF673 0x54A4 # 0 +0xF674 0x553E # 0 +0xF675 0x58AE # 0 +0xF676 0x59A5 # 0 +0xF677 0x60F0 # 0 +0xF678 0x6253 # 0 +0xF679 0x62D6 # 0 +0xF67A 0x6736 # 0 +0xF67B 0x6955 # 0 +0xF67C 0x8235 # 0 +0xF67D 0x9640 # 0 +0xF67E 0x99B1 # 0 +0xF691 0x99DD # 0 +0xF692 0x502C # 0 +0xF693 0x5353 # 0 +0xF694 0x5544 # 0 +0xF695 0x577C # 0 +0xF696 0xFA01 # 0 +0xF697 0x6258 # 0 +0xF698 0xFA02 # 0 +0xF699 0x64E2 # 0 +0xF69A 0x666B # 0 +0xF69B 0x67DD # 0 +0xF69C 0x6FC1 # 0 +0xF69D 0x6FEF # 0 +0xF69E 0x7422 # 0 +0xF69F 0x7438 # 0 +0xF6A0 0x8A17 # 0 +0xF6A1 0x9438 # 0 +0xF6A2 0x5451 # 0 +0xF6A3 0x5606 # 0 +0xF6A4 0x5766 # 0 +0xF6A5 0x5F48 # 0 +0xF6A6 0x619A # 0 +0xF6A7 0x6B4E # 0 +0xF6A8 0x7058 # 0 +0xF6A9 0x70AD # 0 +0xF6AA 0x7DBB # 0 +0xF6AB 0x8A95 # 0 +0xF6AC 0x596A # 0 +0xF6AD 0x812B # 0 +0xF6AE 0x63A2 # 0 +0xF6AF 0x7708 # 0 +0xF6B0 0x803D # 0 +0xF6B1 0x8CAA # 0 +0xF6B2 0x5854 # 0 +0xF6B3 0x642D # 0 +0xF6B4 0x69BB # 0 +0xF6B5 0x5B95 # 0 +0xF6B6 0x5E11 # 0 +0xF6B7 0x6E6F # 0 +0xF6B8 0xFA03 # 0 +0xF6B9 0x8569 # 0 +0xF6BA 0x514C # 0 +0xF6BB 0x53F0 # 0 +0xF6BC 0x592A # 0 +0xF6BD 0x6020 # 0 +0xF6BE 0x614B # 0 +0xF6BF 0x6B86 # 0 +0xF6C0 0x6C70 # 0 +0xF6C1 0x6CF0 # 0 +0xF6C2 0x7B1E # 0 +0xF6C3 0x80CE # 0 +0xF6C4 0x82D4 # 0 +0xF6C5 0x8DC6 # 0 +0xF6C6 0x90B0 # 0 +0xF6C7 0x98B1 # 0 +0xF6C8 0xFA04 # 0 +0xF6C9 0x64C7 # 0 +0xF6CA 0x6FA4 # 0 +0xF6CB 0x6491 # 0 +0xF6CC 0x6504 # 0 +0xF6CD 0x514E # 0 +0xF6CE 0x5410 # 0 +0xF6CF 0x571F # 0 +0xF6D0 0x8A0E # 0 +0xF6D1 0x615F # 0 +0xF6D2 0x6876 # 0 +0xF6D3 0xFA05 # 0 +0xF6D4 0x75DB # 0 +0xF6D5 0x7B52 # 0 +0xF6D6 0x7D71 # 0 +0xF6D7 0x901A # 0 +0xF6D8 0x5806 # 0 +0xF6D9 0x69CC # 0 +0xF6DA 0x817F # 0 +0xF6DB 0x892A # 0 +0xF6DC 0x9000 # 0 +0xF6DD 0x9839 # 0 +0xF6DE 0x5078 # 0 +0xF6DF 0x5957 # 0 +0xF6E0 0x59AC # 0 +0xF6E1 0x6295 # 0 +0xF6E2 0x900F # 0 +0xF6E3 0x9B2A # 0 +0xF6E4 0x615D # 0 +0xF6E5 0x7279 # 0 +0xF6E6 0x95D6 # 0 +0xF6E7 0x5761 # 0 +0xF6E8 0x5A46 # 0 +0xF6E9 0x5DF4 # 0 +0xF6EA 0x628A # 0 +0xF6EB 0x64AD # 0 +0xF6EC 0x64FA # 0 +0xF6ED 0x6777 # 0 +0xF6EE 0x6CE2 # 0 +0xF6EF 0x6D3E # 0 +0xF6F0 0x722C # 0 +0xF6F1 0x7436 # 0 +0xF6F2 0x7834 # 0 +0xF6F3 0x7F77 # 0 +0xF6F4 0x82AD # 0 +0xF6F5 0x8DDB # 0 +0xF6F6 0x9817 # 0 +0xF6F7 0x5224 # 0 +0xF6F8 0x5742 # 0 +0xF6F9 0x677F # 0 +0xF6FA 0x7248 # 0 +0xF6FB 0x74E3 # 0 +0xF6FC 0x8CA9 # 0 +0xF6FD 0x8FA6 # 0 +0xF6FE 0x9211 # 0 +0xF731 0x962A # 0 +0xF732 0x516B # 0 +0xF733 0x53ED # 0 +0xF734 0x634C # 0 +0xF735 0x4F69 # 0 +0xF736 0x5504 # 0 +0xF737 0x6096 # 0 +0xF738 0x6557 # 0 +0xF739 0x6C9B # 0 +0xF73A 0x6D7F # 0 +0xF73B 0x724C # 0 +0xF73C 0x72FD # 0 +0xF73D 0x7A17 # 0 +0xF73E 0x8987 # 0 +0xF73F 0x8C9D # 0 +0xF740 0x5F6D # 0 +0xF741 0x6F8E # 0 +0xF742 0x70F9 # 0 +0xF743 0x81A8 # 0 +0xF744 0x610E # 0 +0xF745 0x4FBF # 0 +0xF746 0x504F # 0 +0xF747 0x6241 # 0 +0xF748 0x7247 # 0 +0xF749 0x7BC7 # 0 +0xF74A 0x7DE8 # 0 +0xF74B 0x7FE9 # 0 +0xF74C 0x904D # 0 +0xF74D 0x97AD # 0 +0xF74E 0x9A19 # 0 +0xF74F 0x8CB6 # 0 +0xF750 0x576A # 0 +0xF751 0x5E73 # 0 +0xF752 0x67B0 # 0 +0xF753 0x840D # 0 +0xF754 0x8A55 # 0 +0xF755 0x5420 # 0 +0xF756 0x5B16 # 0 +0xF757 0x5E63 # 0 +0xF758 0x5EE2 # 0 +0xF759 0x5F0A # 0 +0xF75A 0x6583 # 0 +0xF75B 0x80BA # 0 +0xF75C 0x853D # 0 +0xF75D 0x9589 # 0 +0xF75E 0x965B # 0 +0xF75F 0x4F48 # 0 +0xF760 0x5305 # 0 +0xF761 0x530D # 0 +0xF762 0x530F # 0 +0xF763 0x5486 # 0 +0xF764 0x54FA # 0 +0xF765 0x5703 # 0 +0xF766 0x5E03 # 0 +0xF767 0x6016 # 0 +0xF768 0x629B # 0 +0xF769 0x62B1 # 0 +0xF76A 0x6355 # 0 +0xF76B 0xFA06 # 0 +0xF76C 0x6CE1 # 0 +0xF76D 0x6D66 # 0 +0xF76E 0x75B1 # 0 +0xF76F 0x7832 # 0 +0xF770 0x80DE # 0 +0xF771 0x812F # 0 +0xF772 0x82DE # 0 +0xF773 0x8461 # 0 +0xF774 0x84B2 # 0 +0xF775 0x888D # 0 +0xF776 0x8912 # 0 +0xF777 0x900B # 0 +0xF778 0x92EA # 0 +0xF779 0x98FD # 0 +0xF77A 0x9B91 # 0 +0xF77B 0x5E45 # 0 +0xF77C 0x66B4 # 0 +0xF77D 0x66DD # 0 +0xF77E 0x7011 # 0 +0xF791 0x7206 # 0 +0xF792 0xFA07 # 0 +0xF793 0x4FF5 # 0 +0xF794 0x527D # 0 +0xF795 0x5F6A # 0 +0xF796 0x6153 # 0 +0xF797 0x6753 # 0 +0xF798 0x6A19 # 0 +0xF799 0x6F02 # 0 +0xF79A 0x74E2 # 0 +0xF79B 0x7968 # 0 +0xF79C 0x8868 # 0 +0xF79D 0x8C79 # 0 +0xF79E 0x98C7 # 0 +0xF79F 0x98C4 # 0 +0xF7A0 0x9A43 # 0 +0xF7A1 0x54C1 # 0 +0xF7A2 0x7A1F # 0 +0xF7A3 0x6953 # 0 +0xF7A4 0x8AF7 # 0 +0xF7A5 0x8C4A # 0 +0xF7A6 0x98A8 # 0 +0xF7A7 0x99AE # 0 +0xF7A8 0x5F7C # 0 +0xF7A9 0x62AB # 0 +0xF7AA 0x75B2 # 0 +0xF7AB 0x76AE # 0 +0xF7AC 0x88AB # 0 +0xF7AD 0x907F # 0 +0xF7AE 0x9642 # 0 +0xF7AF 0x5339 # 0 +0xF7B0 0x5F3C # 0 +0xF7B1 0x5FC5 # 0 +0xF7B2 0x6CCC # 0 +0xF7B3 0x73CC # 0 +0xF7B4 0x7562 # 0 +0xF7B5 0x758B # 0 +0xF7B6 0x7B46 # 0 +0xF7B7 0x82FE # 0 +0xF7B8 0x999D # 0 +0xF7B9 0x4E4F # 0 +0xF7BA 0x903C # 0 +0xF7BB 0x4E0B # 0 +0xF7BC 0x4F55 # 0 +0xF7BD 0x53A6 # 0 +0xF7BE 0x590F # 0 +0xF7BF 0x5EC8 # 0 +0xF7C0 0x6630 # 0 +0xF7C1 0x6CB3 # 0 +0xF7C2 0x7455 # 0 +0xF7C3 0x8377 # 0 +0xF7C4 0x8766 # 0 +0xF7C5 0x8CC0 # 0 +0xF7C6 0x9050 # 0 +0xF7C7 0x971E # 0 +0xF7C8 0x9C15 # 0 +0xF7C9 0x58D1 # 0 +0xF7CA 0x5B78 # 0 +0xF7CB 0x8650 # 0 +0xF7CC 0x8B14 # 0 +0xF7CD 0x9DB4 # 0 +0xF7CE 0x5BD2 # 0 +0xF7CF 0x6068 # 0 +0xF7D0 0x608D # 0 +0xF7D1 0x65F1 # 0 +0xF7D2 0x6C57 # 0 +0xF7D3 0x6F22 # 0 +0xF7D4 0x6FA3 # 0 +0xF7D5 0x701A # 0 +0xF7D6 0x7F55 # 0 +0xF7D7 0x7FF0 # 0 +0xF7D8 0x9591 # 0 +0xF7D9 0x9592 # 0 +0xF7DA 0x9650 # 0 +0xF7DB 0x97D3 # 0 +0xF7DC 0x5272 # 0 +0xF7DD 0x8F44 # 0 +0xF7DE 0x51FD # 0 +0xF7DF 0x542B # 0 +0xF7E0 0x54B8 # 0 +0xF7E1 0x5563 # 0 +0xF7E2 0x558A # 0 +0xF7E3 0x6ABB # 0 +0xF7E4 0x6DB5 # 0 +0xF7E5 0x7DD8 # 0 +0xF7E6 0x8266 # 0 +0xF7E7 0x929C # 0 +0xF7E8 0x9677 # 0 +0xF7E9 0x9E79 # 0 +0xF7EA 0x5408 # 0 +0xF7EB 0x54C8 # 0 +0xF7EC 0x76D2 # 0 +0xF7ED 0x86E4 # 0 +0xF7EE 0x95A4 # 0 +0xF7EF 0x95D4 # 0 +0xF7F0 0x965C # 0 +0xF7F1 0x4EA2 # 0 +0xF7F2 0x4F09 # 0 +0xF7F3 0x59EE # 0 +0xF7F4 0x5AE6 # 0 +0xF7F5 0x5DF7 # 0 +0xF7F6 0x6052 # 0 +0xF7F7 0x6297 # 0 +0xF7F8 0x676D # 0 +0xF7F9 0x6841 # 0 +0xF7FA 0x6C86 # 0 +0xF7FB 0x6E2F # 0 +0xF7FC 0x7F38 # 0 +0xF7FD 0x809B # 0 +0xF7FE 0x822A # 0 +0xF831 0xFA08 # 0 +0xF832 0xFA09 # 0 +0xF833 0x9805 # 0 +0xF834 0x4EA5 # 0 +0xF835 0x5055 # 0 +0xF836 0x54B3 # 0 +0xF837 0x5793 # 0 +0xF838 0x595A # 0 +0xF839 0x5B69 # 0 +0xF83A 0x5BB3 # 0 +0xF83B 0x61C8 # 0 +0xF83C 0x6977 # 0 +0xF83D 0x6D77 # 0 +0xF83E 0x7023 # 0 +0xF83F 0x87F9 # 0 +0xF840 0x89E3 # 0 +0xF841 0x8A72 # 0 +0xF842 0x8AE7 # 0 +0xF843 0x9082 # 0 +0xF844 0x99ED # 0 +0xF845 0x9AB8 # 0 +0xF846 0x52BE # 0 +0xF847 0x6838 # 0 +0xF848 0x5016 # 0 +0xF849 0x5E78 # 0 +0xF84A 0x674F # 0 +0xF84B 0x8347 # 0 +0xF84C 0x884C # 0 +0xF84D 0x4EAB # 0 +0xF84E 0x5411 # 0 +0xF84F 0x56AE # 0 +0xF850 0x73E6 # 0 +0xF851 0x9115 # 0 +0xF852 0x97FF # 0 +0xF853 0x9909 # 0 +0xF854 0x9957 # 0 +0xF855 0x9999 # 0 +0xF856 0x5653 # 0 +0xF857 0x589F # 0 +0xF858 0x865B # 0 +0xF859 0x8A31 # 0 +0xF85A 0x61B2 # 0 +0xF85B 0x6AF6 # 0 +0xF85C 0x737B # 0 +0xF85D 0x8ED2 # 0 +0xF85E 0x6B47 # 0 +0xF85F 0x96AA # 0 +0xF860 0x9A57 # 0 +0xF861 0x5955 # 0 +0xF862 0x7200 # 0 +0xF863 0x8D6B # 0 +0xF864 0x9769 # 0 +0xF865 0x4FD4 # 0 +0xF866 0x5CF4 # 0 +0xF867 0x5F26 # 0 +0xF868 0x61F8 # 0 +0xF869 0x665B # 0 +0xF86A 0x6CEB # 0 +0xF86B 0x70AB # 0 +0xF86C 0x7384 # 0 +0xF86D 0x73B9 # 0 +0xF86E 0x73FE # 0 +0xF86F 0x7729 # 0 +0xF870 0x774D # 0 +0xF871 0x7D43 # 0 +0xF872 0x7D62 # 0 +0xF873 0x7E23 # 0 +0xF874 0x8237 # 0 +0xF875 0x8852 # 0 +0xF876 0xFA0A # 0 +0xF877 0x8CE2 # 0 +0xF878 0x9249 # 0 +0xF879 0x986F # 0 +0xF87A 0x5B51 # 0 +0xF87B 0x7A74 # 0 +0xF87C 0x8840 # 0 +0xF87D 0x9801 # 0 +0xF87E 0x5ACC # 0 +0xF891 0x4FE0 # 0 +0xF892 0x5354 # 0 +0xF893 0x593E # 0 +0xF894 0x5CFD # 0 +0xF895 0x633E # 0 +0xF896 0x6D79 # 0 +0xF897 0x72F9 # 0 +0xF898 0x8105 # 0 +0xF899 0x8107 # 0 +0xF89A 0x83A2 # 0 +0xF89B 0x92CF # 0 +0xF89C 0x9830 # 0 +0xF89D 0x4EA8 # 0 +0xF89E 0x5144 # 0 +0xF89F 0x5211 # 0 +0xF8A0 0x578B # 0 +0xF8A1 0x5F62 # 0 +0xF8A2 0x6CC2 # 0 +0xF8A3 0x6ECE # 0 +0xF8A4 0x7005 # 0 +0xF8A5 0x7050 # 0 +0xF8A6 0x70AF # 0 +0xF8A7 0x7192 # 0 +0xF8A8 0x73E9 # 0 +0xF8A9 0x7469 # 0 +0xF8AA 0x834A # 0 +0xF8AB 0x87A2 # 0 +0xF8AC 0x8861 # 0 +0xF8AD 0x9008 # 0 +0xF8AE 0x90A2 # 0 +0xF8AF 0x93A3 # 0 +0xF8B0 0x99A8 # 0 +0xF8B1 0x516E # 0 +0xF8B2 0x5F57 # 0 +0xF8B3 0x60E0 # 0 +0xF8B4 0x6167 # 0 +0xF8B5 0x66B3 # 0 +0xF8B6 0x8559 # 0 +0xF8B7 0x8E4A # 0 +0xF8B8 0x91AF # 0 +0xF8B9 0x978B # 0 +0xF8BA 0x4E4E # 0 +0xF8BB 0x4E92 # 0 +0xF8BC 0x547C # 0 +0xF8BD 0x58D5 # 0 +0xF8BE 0x58FA # 0 +0xF8BF 0x597D # 0 +0xF8C0 0x5CB5 # 0 +0xF8C1 0x5F27 # 0 +0xF8C2 0x6236 # 0 +0xF8C3 0x6248 # 0 +0xF8C4 0x660A # 0 +0xF8C5 0x6667 # 0 +0xF8C6 0x6BEB # 0 +0xF8C7 0x6D69 # 0 +0xF8C8 0x6DCF # 0 +0xF8C9 0x6E56 # 0 +0xF8CA 0x6EF8 # 0 +0xF8CB 0x6F94 # 0 +0xF8CC 0x6FE0 # 0 +0xF8CD 0x6FE9 # 0 +0xF8CE 0x705D # 0 +0xF8CF 0x72D0 # 0 +0xF8D0 0x7425 # 0 +0xF8D1 0x745A # 0 +0xF8D2 0x74E0 # 0 +0xF8D3 0x7693 # 0 +0xF8D4 0x795C # 0 +0xF8D5 0x7CCA # 0 +0xF8D6 0x7E1E # 0 +0xF8D7 0x80E1 # 0 +0xF8D8 0x82A6 # 0 +0xF8D9 0x846B # 0 +0xF8DA 0x84BF # 0 +0xF8DB 0x864E # 0 +0xF8DC 0x865F # 0 +0xF8DD 0x8774 # 0 +0xF8DE 0x8B77 # 0 +0xF8DF 0x8C6A # 0 +0xF8E0 0x93AC # 0 +0xF8E1 0x9800 # 0 +0xF8E2 0x9865 # 0 +0xF8E3 0x60D1 # 0 +0xF8E4 0x6216 # 0 +0xF8E5 0x9177 # 0 +0xF8E6 0x5A5A # 0 +0xF8E7 0x660F # 0 +0xF8E8 0x6DF7 # 0 +0xF8E9 0x6E3E # 0 +0xF8EA 0x743F # 0 +0xF8EB 0x9B42 # 0 +0xF8EC 0x5FFD # 0 +0xF8ED 0x60DA # 0 +0xF8EE 0x7B0F # 0 +0xF8EF 0x54C4 # 0 +0xF8F0 0x5F18 # 0 +0xF8F1 0x6C5E # 0 +0xF8F2 0x6CD3 # 0 +0xF8F3 0x6D2A # 0 +0xF8F4 0x70D8 # 0 +0xF8F5 0x7D05 # 0 +0xF8F6 0x8679 # 0 +0xF8F7 0x8A0C # 0 +0xF8F8 0x9D3B # 0 +0xF8F9 0x5316 # 0 +0xF8FA 0x548C # 0 +0xF8FB 0x5B05 # 0 +0xF8FC 0x6A3A # 0 +0xF8FD 0x706B # 0 +0xF8FE 0x7575 # 0 +0xF931 0x798D # 0 +0xF932 0x79BE # 0 +0xF933 0x82B1 # 0 +0xF934 0x83EF # 0 +0xF935 0x8A71 # 0 +0xF936 0x8B41 # 0 +0xF937 0x8CA8 # 0 +0xF938 0x9774 # 0 +0xF939 0xFA0B # 0 +0xF93A 0x64F4 # 0 +0xF93B 0x652B # 0 +0xF93C 0x78BA # 0 +0xF93D 0x78BB # 0 +0xF93E 0x7A6B # 0 +0xF93F 0x4E38 # 0 +0xF940 0x559A # 0 +0xF941 0x5950 # 0 +0xF942 0x5BA6 # 0 +0xF943 0x5E7B # 0 +0xF944 0x60A3 # 0 +0xF945 0x63DB # 0 +0xF946 0x6B61 # 0 +0xF947 0x6665 # 0 +0xF948 0x6853 # 0 +0xF949 0x6E19 # 0 +0xF94A 0x7165 # 0 +0xF94B 0x74B0 # 0 +0xF94C 0x7D08 # 0 +0xF94D 0x9084 # 0 +0xF94E 0x9A69 # 0 +0xF94F 0x9C25 # 0 +0xF950 0x6D3B # 0 +0xF951 0x6ED1 # 0 +0xF952 0x733E # 0 +0xF953 0x8C41 # 0 +0xF954 0x95CA # 0 +0xF955 0x51F0 # 0 +0xF956 0x5E4C # 0 +0xF957 0x5FA8 # 0 +0xF958 0x604D # 0 +0xF959 0x60F6 # 0 +0xF95A 0x6130 # 0 +0xF95B 0x614C # 0 +0xF95C 0x6643 # 0 +0xF95D 0x6644 # 0 +0xF95E 0x69A5 # 0 +0xF95F 0x6CC1 # 0 +0xF960 0x6E5F # 0 +0xF961 0x6EC9 # 0 +0xF962 0x6F62 # 0 +0xF963 0x714C # 0 +0xF964 0x749C # 0 +0xF965 0x7687 # 0 +0xF966 0x7BC1 # 0 +0xF967 0x7C27 # 0 +0xF968 0x8352 # 0 +0xF969 0x8757 # 0 +0xF96A 0x9051 # 0 +0xF96B 0x968D # 0 +0xF96C 0x9EC3 # 0 +0xF96D 0x532F # 0 +0xF96E 0x56DE # 0 +0xF96F 0x5EFB # 0 +0xF970 0x5F8A # 0 +0xF971 0x6062 # 0 +0xF972 0x6094 # 0 +0xF973 0x61F7 # 0 +0xF974 0x6666 # 0 +0xF975 0x6703 # 0 +0xF976 0x6A9C # 0 +0xF977 0x6DEE # 0 +0xF978 0x6FAE # 0 +0xF979 0x7070 # 0 +0xF97A 0x736A # 0 +0xF97B 0x7E6A # 0 +0xF97C 0x81BE # 0 +0xF97D 0x8334 # 0 +0xF97E 0x86D4 # 0 +0xF991 0x8AA8 # 0 +0xF992 0x8CC4 # 0 +0xF993 0x5283 # 0 +0xF994 0x7372 # 0 +0xF995 0x5B96 # 0 +0xF996 0x6A6B # 0 +0xF997 0x9404 # 0 +0xF998 0x54EE # 0 +0xF999 0x5686 # 0 +0xF99A 0x5B5D # 0 +0xF99B 0x6548 # 0 +0xF99C 0x6585 # 0 +0xF99D 0x66C9 # 0 +0xF99E 0x689F # 0 +0xF99F 0x6D8D # 0 +0xF9A0 0x6DC6 # 0 +0xF9A1 0x723B # 0 +0xF9A2 0x80B4 # 0 +0xF9A3 0x9175 # 0 +0xF9A4 0x9A4D # 0 +0xF9A5 0x4FAF # 0 +0xF9A6 0x5019 # 0 +0xF9A7 0x539A # 0 +0xF9A8 0x540E # 0 +0xF9A9 0x543C # 0 +0xF9AA 0x5589 # 0 +0xF9AB 0x55C5 # 0 +0xF9AC 0x5E3F # 0 +0xF9AD 0x5F8C # 0 +0xF9AE 0x673D # 0 +0xF9AF 0x7166 # 0 +0xF9B0 0x73DD # 0 +0xF9B1 0x9005 # 0 +0xF9B2 0x52DB # 0 +0xF9B3 0x52F3 # 0 +0xF9B4 0x5864 # 0 +0xF9B5 0x58CE # 0 +0xF9B6 0x7104 # 0 +0xF9B7 0x718F # 0 +0xF9B8 0x71FB # 0 +0xF9B9 0x85B0 # 0 +0xF9BA 0x8A13 # 0 +0xF9BB 0x6688 # 0 +0xF9BC 0x85A8 # 0 +0xF9BD 0x55A7 # 0 +0xF9BE 0x6684 # 0 +0xF9BF 0x714A # 0 +0xF9C0 0x8431 # 0 +0xF9C1 0x5349 # 0 +0xF9C2 0x5599 # 0 +0xF9C3 0x6BC1 # 0 +0xF9C4 0x5F59 # 0 +0xF9C5 0x5FBD # 0 +0xF9C6 0x63EE # 0 +0xF9C7 0x6689 # 0 +0xF9C8 0x7147 # 0 +0xF9C9 0x8AF1 # 0 +0xF9CA 0x8F1D # 0 +0xF9CB 0x9EBE # 0 +0xF9CC 0x4F11 # 0 +0xF9CD 0x643A # 0 +0xF9CE 0x70CB # 0 +0xF9CF 0x7566 # 0 +0xF9D0 0x8667 # 0 +0xF9D1 0x6064 # 0 +0xF9D2 0x8B4E # 0 +0xF9D3 0x9DF8 # 0 +0xF9D4 0x5147 # 0 +0xF9D5 0x51F6 # 0 +0xF9D6 0x5308 # 0 +0xF9D7 0x6D36 # 0 +0xF9D8 0x80F8 # 0 +0xF9D9 0x9ED1 # 0 +0xF9DA 0x6615 # 0 +0xF9DB 0x6B23 # 0 +0xF9DC 0x7098 # 0 +0xF9DD 0x75D5 # 0 +0xF9DE 0x5403 # 0 +0xF9DF 0x5C79 # 0 +0xF9E0 0x7D07 # 0 +0xF9E1 0x8A16 # 0 +0xF9E2 0x6B20 # 0 +0xF9E3 0x6B3D # 0 +0xF9E4 0x6B46 # 0 +0xF9E5 0x5438 # 0 +0xF9E6 0x6070 # 0 +0xF9E7 0x6D3D # 0 +0xF9E8 0x7FD5 # 0 +0xF9E9 0x8208 # 0 +0xF9EA 0x50D6 # 0 +0xF9EB 0x51DE # 0 +0xF9EC 0x559C # 0 +0xF9ED 0x566B # 0 +0xF9EE 0x56CD # 0 +0xF9EF 0x59EC # 0 +0xF9F0 0x5B09 # 0 +0xF9F1 0x5E0C # 0 +0xF9F2 0x6199 # 0 +0xF9F3 0x6198 # 0 +0xF9F4 0x6231 # 0 +0xF9F5 0x665E # 0 +0xF9F6 0x66E6 # 0 +0xF9F7 0x7199 # 0 +0xF9F8 0x71B9 # 0 +0xF9F9 0x71BA # 0 +0xF9FA 0x72A7 # 0 +0xF9FB 0x79A7 # 0 +0xF9FC 0x7A00 # 0 +0xF9FD 0x7FB2 # 0 +0xF9FE 0x8A70 # 0 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/data/windows-874.txt b/data/windows-874.txt new file mode 100644 index 000000000..1eb71dfe1 --- /dev/null +++ b/data/windows-874.txt @@ -0,0 +1,274 @@ +# +# Name: cp874 to Unicode table +# Unicode version: 2.0 +# Table version: 2.01 +# Table format: Format A +# Date: 02/28/98 +# +# Contact: cpxlate@microsoft.com +# +# General notes: none +# +# Format: Three tab-separated columns +# Column #1 is the cp874 code (in hex) +# Column #2 is the Unicode (in hex as 0xXXXX) +# Column #3 is the Unicode name (follows a comment sign, '#') +# +# The entries are in cp874 order +# +0x00 0x0000 #NULL +0x01 0x0001 #START OF HEADING +0x02 0x0002 #START OF TEXT +0x03 0x0003 #END OF TEXT +0x04 0x0004 #END OF TRANSMISSION +0x05 0x0005 #ENQUIRY +0x06 0x0006 #ACKNOWLEDGE +0x07 0x0007 #BELL +0x08 0x0008 #BACKSPACE +0x09 0x0009 #HORIZONTAL TABULATION +0x0A 0x000A #LINE FEED +0x0B 0x000B #VERTICAL TABULATION +0x0C 0x000C #FORM FEED +0x0D 0x000D #CARRIAGE RETURN +0x0E 0x000E #SHIFT OUT +0x0F 0x000F #SHIFT IN +0x10 0x0010 #DATA LINK ESCAPE +0x11 0x0011 #DEVICE CONTROL ONE +0x12 0x0012 #DEVICE CONTROL TWO +0x13 0x0013 #DEVICE CONTROL THREE +0x14 0x0014 #DEVICE CONTROL FOUR +0x15 0x0015 #NEGATIVE ACKNOWLEDGE +0x16 0x0016 #SYNCHRONOUS IDLE +0x17 0x0017 #END OF TRANSMISSION BLOCK +0x18 0x0018 #CANCEL +0x19 0x0019 #END OF MEDIUM +0x1A 0x001A #SUBSTITUTE +0x1B 0x001B #ESCAPE +0x1C 0x001C #FILE SEPARATOR +0x1D 0x001D #GROUP SEPARATOR +0x1E 0x001E #RECORD SEPARATOR +0x1F 0x001F #UNIT SEPARATOR +0x20 0x0020 #SPACE +0x21 0x0021 #EXCLAMATION MARK +0x22 0x0022 #QUOTATION MARK +0x23 0x0023 #NUMBER SIGN +0x24 0x0024 #DOLLAR SIGN +0x25 0x0025 #PERCENT SIGN +0x26 0x0026 #AMPERSAND +0x27 0x0027 #APOSTROPHE +0x28 0x0028 #LEFT PARENTHESIS +0x29 0x0029 #RIGHT PARENTHESIS +0x2A 0x002A #ASTERISK +0x2B 0x002B #PLUS SIGN +0x2C 0x002C #COMMA +0x2D 0x002D #HYPHEN-MINUS +0x2E 0x002E #FULL STOP +0x2F 0x002F #SOLIDUS +0x30 0x0030 #DIGIT ZERO +0x31 0x0031 #DIGIT ONE +0x32 0x0032 #DIGIT TWO +0x33 0x0033 #DIGIT THREE +0x34 0x0034 #DIGIT FOUR +0x35 0x0035 #DIGIT FIVE +0x36 0x0036 #DIGIT SIX +0x37 0x0037 #DIGIT SEVEN +0x38 0x0038 #DIGIT EIGHT +0x39 0x0039 #DIGIT NINE +0x3A 0x003A #COLON +0x3B 0x003B #SEMICOLON +0x3C 0x003C #LESS-THAN SIGN +0x3D 0x003D #EQUALS SIGN +0x3E 0x003E #GREATER-THAN SIGN +0x3F 0x003F #QUESTION MARK +0x40 0x0040 #COMMERCIAL AT +0x41 0x0041 #LATIN CAPITAL LETTER A +0x42 0x0042 #LATIN CAPITAL LETTER B +0x43 0x0043 #LATIN CAPITAL LETTER C +0x44 0x0044 #LATIN CAPITAL LETTER D +0x45 0x0045 #LATIN CAPITAL LETTER E +0x46 0x0046 #LATIN CAPITAL LETTER F +0x47 0x0047 #LATIN CAPITAL LETTER G +0x48 0x0048 #LATIN CAPITAL LETTER H +0x49 0x0049 #LATIN CAPITAL LETTER I +0x4A 0x004A #LATIN CAPITAL LETTER J +0x4B 0x004B #LATIN CAPITAL LETTER K +0x4C 0x004C #LATIN CAPITAL LETTER L +0x4D 0x004D #LATIN CAPITAL LETTER M +0x4E 0x004E #LATIN CAPITAL LETTER N +0x4F 0x004F #LATIN CAPITAL LETTER O +0x50 0x0050 #LATIN CAPITAL LETTER P +0x51 0x0051 #LATIN CAPITAL LETTER Q +0x52 0x0052 #LATIN CAPITAL LETTER R +0x53 0x0053 #LATIN CAPITAL LETTER S +0x54 0x0054 #LATIN CAPITAL LETTER T +0x55 0x0055 #LATIN CAPITAL LETTER U +0x56 0x0056 #LATIN CAPITAL LETTER V +0x57 0x0057 #LATIN CAPITAL LETTER W +0x58 0x0058 #LATIN CAPITAL LETTER X +0x59 0x0059 #LATIN CAPITAL LETTER Y +0x5A 0x005A #LATIN CAPITAL LETTER Z +0x5B 0x005B #LEFT SQUARE BRACKET +0x5C 0x005C #REVERSE SOLIDUS +0x5D 0x005D #RIGHT SQUARE BRACKET +0x5E 0x005E #CIRCUMFLEX ACCENT +0x5F 0x005F #LOW LINE +0x60 0x0060 #GRAVE ACCENT +0x61 0x0061 #LATIN SMALL LETTER A +0x62 0x0062 #LATIN SMALL LETTER B +0x63 0x0063 #LATIN SMALL LETTER C +0x64 0x0064 #LATIN SMALL LETTER D +0x65 0x0065 #LATIN SMALL LETTER E +0x66 0x0066 #LATIN SMALL LETTER F +0x67 0x0067 #LATIN SMALL LETTER G +0x68 0x0068 #LATIN SMALL LETTER H +0x69 0x0069 #LATIN SMALL LETTER I +0x6A 0x006A #LATIN SMALL LETTER J +0x6B 0x006B #LATIN SMALL LETTER K +0x6C 0x006C #LATIN SMALL LETTER L +0x6D 0x006D #LATIN SMALL LETTER M +0x6E 0x006E #LATIN SMALL LETTER N +0x6F 0x006F #LATIN SMALL LETTER O +0x70 0x0070 #LATIN SMALL LETTER P +0x71 0x0071 #LATIN SMALL LETTER Q +0x72 0x0072 #LATIN SMALL LETTER R +0x73 0x0073 #LATIN SMALL LETTER S +0x74 0x0074 #LATIN SMALL LETTER T +0x75 0x0075 #LATIN SMALL LETTER U +0x76 0x0076 #LATIN SMALL LETTER V +0x77 0x0077 #LATIN SMALL LETTER W +0x78 0x0078 #LATIN SMALL LETTER X +0x79 0x0079 #LATIN SMALL LETTER Y +0x7A 0x007A #LATIN SMALL LETTER Z +0x7B 0x007B #LEFT CURLY BRACKET +0x7C 0x007C #VERTICAL LINE +0x7D 0x007D #RIGHT CURLY BRACKET +0x7E 0x007E #TILDE +0x7F 0x007F #DELETE +0x80 0x20AC #EURO SIGN +0x81 #UNDEFINED +0x82 #UNDEFINED +0x83 #UNDEFINED +0x84 #UNDEFINED +0x85 0x2026 #HORIZONTAL ELLIPSIS +0x86 #UNDEFINED +0x87 #UNDEFINED +0x88 #UNDEFINED +0x89 #UNDEFINED +0x8A #UNDEFINED +0x8B #UNDEFINED +0x8C #UNDEFINED +0x8D #UNDEFINED +0x8E #UNDEFINED +0x8F #UNDEFINED +0x90 #UNDEFINED +0x91 0x2018 #LEFT SINGLE QUOTATION MARK +0x92 0x2019 #RIGHT SINGLE QUOTATION MARK +0x93 0x201C #LEFT DOUBLE QUOTATION MARK +0x94 0x201D #RIGHT DOUBLE QUOTATION MARK +0x95 0x2022 #BULLET +0x96 0x2013 #EN DASH +0x97 0x2014 #EM DASH +0x98 #UNDEFINED +0x99 #UNDEFINED +0x9A #UNDEFINED +0x9B #UNDEFINED +0x9C #UNDEFINED +0x9D #UNDEFINED +0x9E #UNDEFINED +0x9F #UNDEFINED +0xA0 0x00A0 #NO-BREAK SPACE +0xA1 0x0E01 #THAI CHARACTER KO KAI +0xA2 0x0E02 #THAI CHARACTER KHO KHAI +0xA3 0x0E03 #THAI CHARACTER KHO KHUAT +0xA4 0x0E04 #THAI CHARACTER KHO KHWAI +0xA5 0x0E05 #THAI CHARACTER KHO KHON +0xA6 0x0E06 #THAI CHARACTER KHO RAKHANG +0xA7 0x0E07 #THAI CHARACTER NGO NGU +0xA8 0x0E08 #THAI CHARACTER CHO CHAN +0xA9 0x0E09 #THAI CHARACTER CHO CHING +0xAA 0x0E0A #THAI CHARACTER CHO CHANG +0xAB 0x0E0B #THAI CHARACTER SO SO +0xAC 0x0E0C #THAI CHARACTER CHO CHOE +0xAD 0x0E0D #THAI CHARACTER YO YING +0xAE 0x0E0E #THAI CHARACTER DO CHADA +0xAF 0x0E0F #THAI CHARACTER TO PATAK +0xB0 0x0E10 #THAI CHARACTER THO THAN +0xB1 0x0E11 #THAI CHARACTER THO NANGMONTHO +0xB2 0x0E12 #THAI CHARACTER THO PHUTHAO +0xB3 0x0E13 #THAI CHARACTER NO NEN +0xB4 0x0E14 #THAI CHARACTER DO DEK +0xB5 0x0E15 #THAI CHARACTER TO TAO +0xB6 0x0E16 #THAI CHARACTER THO THUNG +0xB7 0x0E17 #THAI CHARACTER THO THAHAN +0xB8 0x0E18 #THAI CHARACTER THO THONG +0xB9 0x0E19 #THAI CHARACTER NO NU +0xBA 0x0E1A #THAI CHARACTER BO BAIMAI +0xBB 0x0E1B #THAI CHARACTER PO PLA +0xBC 0x0E1C #THAI CHARACTER PHO PHUNG +0xBD 0x0E1D #THAI CHARACTER FO FA +0xBE 0x0E1E #THAI CHARACTER PHO PHAN +0xBF 0x0E1F #THAI CHARACTER FO FAN +0xC0 0x0E20 #THAI CHARACTER PHO SAMPHAO +0xC1 0x0E21 #THAI CHARACTER MO MA +0xC2 0x0E22 #THAI CHARACTER YO YAK +0xC3 0x0E23 #THAI CHARACTER RO RUA +0xC4 0x0E24 #THAI CHARACTER RU +0xC5 0x0E25 #THAI CHARACTER LO LING +0xC6 0x0E26 #THAI CHARACTER LU +0xC7 0x0E27 #THAI CHARACTER WO WAEN +0xC8 0x0E28 #THAI CHARACTER SO SALA +0xC9 0x0E29 #THAI CHARACTER SO RUSI +0xCA 0x0E2A #THAI CHARACTER SO SUA +0xCB 0x0E2B #THAI CHARACTER HO HIP +0xCC 0x0E2C #THAI CHARACTER LO CHULA +0xCD 0x0E2D #THAI CHARACTER O ANG +0xCE 0x0E2E #THAI CHARACTER HO NOKHUK +0xCF 0x0E2F #THAI CHARACTER PAIYANNOI +0xD0 0x0E30 #THAI CHARACTER SARA A +0xD1 0x0E31 #THAI CHARACTER MAI HAN-AKAT +0xD2 0x0E32 #THAI CHARACTER SARA AA +0xD3 0x0E33 #THAI CHARACTER SARA AM +0xD4 0x0E34 #THAI CHARACTER SARA I +0xD5 0x0E35 #THAI CHARACTER SARA II +0xD6 0x0E36 #THAI CHARACTER SARA UE +0xD7 0x0E37 #THAI CHARACTER SARA UEE +0xD8 0x0E38 #THAI CHARACTER SARA U +0xD9 0x0E39 #THAI CHARACTER SARA UU +0xDA 0x0E3A #THAI CHARACTER PHINTHU +0xDB #UNDEFINED +0xDC #UNDEFINED +0xDD #UNDEFINED +0xDE #UNDEFINED +0xDF 0x0E3F #THAI CURRENCY SYMBOL BAHT +0xE0 0x0E40 #THAI CHARACTER SARA E +0xE1 0x0E41 #THAI CHARACTER SARA AE +0xE2 0x0E42 #THAI CHARACTER SARA O +0xE3 0x0E43 #THAI CHARACTER SARA AI MAIMUAN +0xE4 0x0E44 #THAI CHARACTER SARA AI MAIMALAI +0xE5 0x0E45 #THAI CHARACTER LAKKHANGYAO +0xE6 0x0E46 #THAI CHARACTER MAIYAMOK +0xE7 0x0E47 #THAI CHARACTER MAITAIKHU +0xE8 0x0E48 #THAI CHARACTER MAI EK +0xE9 0x0E49 #THAI CHARACTER MAI THO +0xEA 0x0E4A #THAI CHARACTER MAI TRI +0xEB 0x0E4B #THAI CHARACTER MAI CHATTAWA +0xEC 0x0E4C #THAI CHARACTER THANTHAKHAT +0xED 0x0E4D #THAI CHARACTER NIKHAHIT +0xEE 0x0E4E #THAI CHARACTER YAMAKKAN +0xEF 0x0E4F #THAI CHARACTER FONGMAN +0xF0 0x0E50 #THAI DIGIT ZERO +0xF1 0x0E51 #THAI DIGIT ONE +0xF2 0x0E52 #THAI DIGIT TWO +0xF3 0x0E53 #THAI DIGIT THREE +0xF4 0x0E54 #THAI DIGIT FOUR +0xF5 0x0E55 #THAI DIGIT FIVE +0xF6 0x0E56 #THAI DIGIT SIX +0xF7 0x0E57 #THAI DIGIT SEVEN +0xF8 0x0E58 #THAI DIGIT EIGHT +0xF9 0x0E59 #THAI DIGIT NINE +0xFA 0x0E5A #THAI CHARACTER ANGKHANKHU +0xFB 0x0E5B #THAI CHARACTER KHOMUT +0xFC #UNDEFINED +0xFD #UNDEFINED +0xFE #UNDEFINED +0xFF #UNDEFINED diff --git a/data/windows-932.txt b/data/windows-932.txt new file mode 100644 index 000000000..b754215d9 --- /dev/null +++ b/data/windows-932.txt @@ -0,0 +1,9403 @@ +# cp932.txt - Legacy to Unicode charmap +0x0000 0x0000 # 0 +0x0001 0x0001 # 0 +0x0002 0x0002 # 0 +0x0003 0x0003 # 0 +0x0004 0x0004 # 0 +0x0005 0x0005 # 0 +0x0006 0x0006 # 0 +0x0007 0x0007 # 0 +0x0008 0x0008 # 0 +0x0009 0x0009 # 0 +0x000A 0x000A # 0 +0x000B 0x000B # 0 +0x000C 0x000C # 0 +0x000D 0x000D # 0 +0x000E 0x000E # 0 +0x000F 0x000F # 0 +0x0010 0x0010 # 0 +0x0011 0x0011 # 0 +0x0012 0x0012 # 0 +0x0013 0x0013 # 0 +0x0014 0x0014 # 0 +0x0015 0x0015 # 0 +0x0016 0x0016 # 0 +0x0017 0x0017 # 0 +0x0018 0x0018 # 0 +0x0019 0x0019 # 0 +0x001A 0x001A # 0 +0x001B 0x001B # 0 +0x001C 0x001C # 0 +0x001D 0x001D # 0 +0x001E 0x001E # 0 +0x001F 0x001F # 0 +0x0020 0x0020 # 0 +0x0021 0x0021 # 0 +0x0022 0x0022 # 0 +0x0023 0x0023 # 0 +0x0024 0x0024 # 0 +0x0025 0x0025 # 0 +0x0026 0x0026 # 0 +0x0027 0x0027 # 0 +0x0028 0x0028 # 0 +0x0029 0x0029 # 0 +0x002A 0x002A # 0 +0x002B 0x002B # 0 +0x002C 0x002C # 0 +0x002D 0x002D # 0 +0x002E 0x002E # 0 +0x002F 0x002F # 0 +0x0030 0x0030 # 0 +0x0031 0x0031 # 0 +0x0032 0x0032 # 0 +0x0033 0x0033 # 0 +0x0034 0x0034 # 0 +0x0035 0x0035 # 0 +0x0036 0x0036 # 0 +0x0037 0x0037 # 0 +0x0038 0x0038 # 0 +0x0039 0x0039 # 0 +0x003A 0x003A # 0 +0x003B 0x003B # 0 +0x003C 0x003C # 0 +0x003D 0x003D # 0 +0x003E 0x003E # 0 +0x003F 0x003F # 0 +0x0040 0x0040 # 0 +0x0041 0x0041 # 0 +0x0042 0x0042 # 0 +0x0043 0x0043 # 0 +0x0044 0x0044 # 0 +0x0045 0x0045 # 0 +0x0046 0x0046 # 0 +0x0047 0x0047 # 0 +0x0048 0x0048 # 0 +0x0049 0x0049 # 0 +0x004A 0x004A # 0 +0x004B 0x004B # 0 +0x004C 0x004C # 0 +0x004D 0x004D # 0 +0x004E 0x004E # 0 +0x004F 0x004F # 0 +0x0050 0x0050 # 0 +0x0051 0x0051 # 0 +0x0052 0x0052 # 0 +0x0053 0x0053 # 0 +0x0054 0x0054 # 0 +0x0055 0x0055 # 0 +0x0056 0x0056 # 0 +0x0057 0x0057 # 0 +0x0058 0x0058 # 0 +0x0059 0x0059 # 0 +0x005A 0x005A # 0 +0x005B 0x005B # 0 +0x005C 0x005C # 0 +0x005D 0x005D # 0 +0x005E 0x005E # 0 +0x005F 0x005F # 0 +0x0060 0x0060 # 0 +0x0061 0x0061 # 0 +0x0062 0x0062 # 0 +0x0063 0x0063 # 0 +0x0064 0x0064 # 0 +0x0065 0x0065 # 0 +0x0066 0x0066 # 0 +0x0067 0x0067 # 0 +0x0068 0x0068 # 0 +0x0069 0x0069 # 0 +0x006A 0x006A # 0 +0x006B 0x006B # 0 +0x006C 0x006C # 0 +0x006D 0x006D # 0 +0x006E 0x006E # 0 +0x006F 0x006F # 0 +0x0070 0x0070 # 0 +0x0071 0x0071 # 0 +0x0072 0x0072 # 0 +0x0073 0x0073 # 0 +0x0074 0x0074 # 0 +0x0075 0x0075 # 0 +0x0076 0x0076 # 0 +0x0077 0x0077 # 0 +0x0078 0x0078 # 0 +0x0079 0x0079 # 0 +0x007A 0x007A # 0 +0x007B 0x007B # 0 +0x007C 0x007C # 0 +0x007D 0x007D # 0 +0x007E 0x007E # 0 +0x007F 0x007F # 0 +0x0080 0x0080 # 0 +0x00A0 0xF8F0 # 0 +0x00A1 0xFF61 # 0 +0x00A2 0xFF62 # 0 +0x00A3 0xFF63 # 0 +0x00A4 0xFF64 # 0 +0x00A5 0xFF65 # 0 +0x00A6 0xFF66 # 0 +0x00A7 0xFF67 # 0 +0x00A8 0xFF68 # 0 +0x00A9 0xFF69 # 0 +0x00AA 0xFF6A # 0 +0x00AB 0xFF6B # 0 +0x00AC 0xFF6C # 0 +0x00AD 0xFF6D # 0 +0x00AE 0xFF6E # 0 +0x00AF 0xFF6F # 0 +0x00B0 0xFF70 # 0 +0x00B1 0xFF71 # 0 +0x00B2 0xFF72 # 0 +0x00B3 0xFF73 # 0 +0x00B4 0xFF74 # 0 +0x00B5 0xFF75 # 0 +0x00B6 0xFF76 # 0 +0x00B7 0xFF77 # 0 +0x00B8 0xFF78 # 0 +0x00B9 0xFF79 # 0 +0x00BA 0xFF7A # 0 +0x00BB 0xFF7B # 0 +0x00BC 0xFF7C # 0 +0x00BD 0xFF7D # 0 +0x00BE 0xFF7E # 0 +0x00BF 0xFF7F # 0 +0x00C0 0xFF80 # 0 +0x00C1 0xFF81 # 0 +0x00C2 0xFF82 # 0 +0x00C3 0xFF83 # 0 +0x00C4 0xFF84 # 0 +0x00C5 0xFF85 # 0 +0x00C6 0xFF86 # 0 +0x00C7 0xFF87 # 0 +0x00C8 0xFF88 # 0 +0x00C9 0xFF89 # 0 +0x00CA 0xFF8A # 0 +0x00CB 0xFF8B # 0 +0x00CC 0xFF8C # 0 +0x00CD 0xFF8D # 0 +0x00CE 0xFF8E # 0 +0x00CF 0xFF8F # 0 +0x00D0 0xFF90 # 0 +0x00D1 0xFF91 # 0 +0x00D2 0xFF92 # 0 +0x00D3 0xFF93 # 0 +0x00D4 0xFF94 # 0 +0x00D5 0xFF95 # 0 +0x00D6 0xFF96 # 0 +0x00D7 0xFF97 # 0 +0x00D8 0xFF98 # 0 +0x00D9 0xFF99 # 0 +0x00DA 0xFF9A # 0 +0x00DB 0xFF9B # 0 +0x00DC 0xFF9C # 0 +0x00DD 0xFF9D # 0 +0x00DE 0xFF9E # 0 +0x00DF 0xFF9F # 0 +0x00FD 0xF8F1 # 0 +0x00FE 0xF8F2 # 0 +0x00FF 0xF8F3 # 0 +0x8140 0x3000 # 0 +0x8141 0x3001 # 0 +0x8142 0x3002 # 0 +0x8143 0xFF0C # 0 +0x8144 0xFF0E # 0 +0x8145 0x30FB # 0 +0x8146 0xFF1A # 0 +0x8147 0xFF1B # 0 +0x8148 0xFF1F # 0 +0x8149 0xFF01 # 0 +0x814A 0x309B # 0 +0x814B 0x309C # 0 +0x814C 0x00B4 # 0 +0x814D 0xFF40 # 0 +0x814E 0x00A8 # 0 +0x814F 0xFF3E # 0 +0x8150 0xFFE3 # 0 +0x8151 0xFF3F # 0 +0x8152 0x30FD # 0 +0x8153 0x30FE # 0 +0x8154 0x309D # 0 +0x8155 0x309E # 0 +0x8156 0x3003 # 0 +0x8157 0x4EDD # 0 +0x8158 0x3005 # 0 +0x8159 0x3006 # 0 +0x815A 0x3007 # 0 +0x815B 0x30FC # 0 +0x815C 0x2015 # 0 +0x815D 0x2010 # 0 +0x815E 0xFF0F # 0 +0x815F 0xFF3C # 0 +0x8160 0xFF5E # 0 +0x8161 0x2225 # 0 +0x8162 0xFF5C # 0 +0x8163 0x2026 # 0 +0x8164 0x2025 # 0 +0x8165 0x2018 # 0 +0x8166 0x2019 # 0 +0x8167 0x201C # 0 +0x8168 0x201D # 0 +0x8169 0xFF08 # 0 +0x816A 0xFF09 # 0 +0x816B 0x3014 # 0 +0x816C 0x3015 # 0 +0x816D 0xFF3B # 0 +0x816E 0xFF3D # 0 +0x816F 0xFF5B # 0 +0x8170 0xFF5D # 0 +0x8171 0x3008 # 0 +0x8172 0x3009 # 0 +0x8173 0x300A # 0 +0x8174 0x300B # 0 +0x8175 0x300C # 0 +0x8176 0x300D # 0 +0x8177 0x300E # 0 +0x8178 0x300F # 0 +0x8179 0x3010 # 0 +0x817A 0x3011 # 0 +0x817B 0xFF0B # 0 +0x817C 0xFF0D # 0 +0x817D 0x00B1 # 0 +0x817E 0x00D7 # 0 +0x8180 0x00F7 # 0 +0x8181 0xFF1D # 0 +0x8182 0x2260 # 0 +0x8183 0xFF1C # 0 +0x8184 0xFF1E # 0 +0x8185 0x2266 # 0 +0x8186 0x2267 # 0 +0x8187 0x221E # 0 +0x8188 0x2234 # 0 +0x8189 0x2642 # 0 +0x818A 0x2640 # 0 +0x818B 0x00B0 # 0 +0x818C 0x2032 # 0 +0x818D 0x2033 # 0 +0x818E 0x2103 # 0 +0x818F 0xFFE5 # 0 +0x8190 0xFF04 # 0 +0x8191 0xFFE0 # 0 +0x8192 0xFFE1 # 0 +0x8193 0xFF05 # 0 +0x8194 0xFF03 # 0 +0x8195 0xFF06 # 0 +0x8196 0xFF0A # 0 +0x8197 0xFF20 # 0 +0x8198 0x00A7 # 0 +0x8199 0x2606 # 0 +0x819A 0x2605 # 0 +0x819B 0x25CB # 0 +0x819C 0x25CF # 0 +0x819D 0x25CE # 0 +0x819E 0x25C7 # 0 +0x819F 0x25C6 # 0 +0x81A0 0x25A1 # 0 +0x81A1 0x25A0 # 0 +0x81A2 0x25B3 # 0 +0x81A3 0x25B2 # 0 +0x81A4 0x25BD # 0 +0x81A5 0x25BC # 0 +0x81A6 0x203B # 0 +0x81A7 0x3012 # 0 +0x81A8 0x2192 # 0 +0x81A9 0x2190 # 0 +0x81AA 0x2191 # 0 +0x81AB 0x2193 # 0 +0x81AC 0x3013 # 0 +0x81B8 0x2208 # 0 +0x81B9 0x220B # 0 +0x81BA 0x2286 # 0 +0x81BB 0x2287 # 0 +0x81BC 0x2282 # 0 +0x81BD 0x2283 # 0 +0x81BE 0x222A # 0 +0x81BF 0x2229 # 0 +0x81C8 0x2227 # 0 +0x81C9 0x2228 # 0 +0x81CA 0xFFE2 # 0 +0x81CB 0x21D2 # 0 +0x81CC 0x21D4 # 0 +0x81CD 0x2200 # 0 +0x81CE 0x2203 # 0 +0x81DA 0x2220 # 0 +0x81DB 0x22A5 # 0 +0x81DC 0x2312 # 0 +0x81DD 0x2202 # 0 +0x81DE 0x2207 # 0 +0x81DF 0x2261 # 0 +0x81E0 0x2252 # 0 +0x81E1 0x226A # 0 +0x81E2 0x226B # 0 +0x81E3 0x221A # 0 +0x81E4 0x223D # 0 +0x81E5 0x221D # 0 +0x81E6 0x2235 # 0 +0x81E7 0x222B # 0 +0x81E8 0x222C # 0 +0x81F0 0x212B # 0 +0x81F1 0x2030 # 0 +0x81F2 0x266F # 0 +0x81F3 0x266D # 0 +0x81F4 0x266A # 0 +0x81F5 0x2020 # 0 +0x81F6 0x2021 # 0 +0x81F7 0x00B6 # 0 +0x81FC 0x25EF # 0 +0x824F 0xFF10 # 0 +0x8250 0xFF11 # 0 +0x8251 0xFF12 # 0 +0x8252 0xFF13 # 0 +0x8253 0xFF14 # 0 +0x8254 0xFF15 # 0 +0x8255 0xFF16 # 0 +0x8256 0xFF17 # 0 +0x8257 0xFF18 # 0 +0x8258 0xFF19 # 0 +0x8260 0xFF21 # 0 +0x8261 0xFF22 # 0 +0x8262 0xFF23 # 0 +0x8263 0xFF24 # 0 +0x8264 0xFF25 # 0 +0x8265 0xFF26 # 0 +0x8266 0xFF27 # 0 +0x8267 0xFF28 # 0 +0x8268 0xFF29 # 0 +0x8269 0xFF2A # 0 +0x826A 0xFF2B # 0 +0x826B 0xFF2C # 0 +0x826C 0xFF2D # 0 +0x826D 0xFF2E # 0 +0x826E 0xFF2F # 0 +0x826F 0xFF30 # 0 +0x8270 0xFF31 # 0 +0x8271 0xFF32 # 0 +0x8272 0xFF33 # 0 +0x8273 0xFF34 # 0 +0x8274 0xFF35 # 0 +0x8275 0xFF36 # 0 +0x8276 0xFF37 # 0 +0x8277 0xFF38 # 0 +0x8278 0xFF39 # 0 +0x8279 0xFF3A # 0 +0x8281 0xFF41 # 0 +0x8282 0xFF42 # 0 +0x8283 0xFF43 # 0 +0x8284 0xFF44 # 0 +0x8285 0xFF45 # 0 +0x8286 0xFF46 # 0 +0x8287 0xFF47 # 0 +0x8288 0xFF48 # 0 +0x8289 0xFF49 # 0 +0x828A 0xFF4A # 0 +0x828B 0xFF4B # 0 +0x828C 0xFF4C # 0 +0x828D 0xFF4D # 0 +0x828E 0xFF4E # 0 +0x828F 0xFF4F # 0 +0x8290 0xFF50 # 0 +0x8291 0xFF51 # 0 +0x8292 0xFF52 # 0 +0x8293 0xFF53 # 0 +0x8294 0xFF54 # 0 +0x8295 0xFF55 # 0 +0x8296 0xFF56 # 0 +0x8297 0xFF57 # 0 +0x8298 0xFF58 # 0 +0x8299 0xFF59 # 0 +0x829A 0xFF5A # 0 +0x829F 0x3041 # 0 +0x82A0 0x3042 # 0 +0x82A1 0x3043 # 0 +0x82A2 0x3044 # 0 +0x82A3 0x3045 # 0 +0x82A4 0x3046 # 0 +0x82A5 0x3047 # 0 +0x82A6 0x3048 # 0 +0x82A7 0x3049 # 0 +0x82A8 0x304A # 0 +0x82A9 0x304B # 0 +0x82AA 0x304C # 0 +0x82AB 0x304D # 0 +0x82AC 0x304E # 0 +0x82AD 0x304F # 0 +0x82AE 0x3050 # 0 +0x82AF 0x3051 # 0 +0x82B0 0x3052 # 0 +0x82B1 0x3053 # 0 +0x82B2 0x3054 # 0 +0x82B3 0x3055 # 0 +0x82B4 0x3056 # 0 +0x82B5 0x3057 # 0 +0x82B6 0x3058 # 0 +0x82B7 0x3059 # 0 +0x82B8 0x305A # 0 +0x82B9 0x305B # 0 +0x82BA 0x305C # 0 +0x82BB 0x305D # 0 +0x82BC 0x305E # 0 +0x82BD 0x305F # 0 +0x82BE 0x3060 # 0 +0x82BF 0x3061 # 0 +0x82C0 0x3062 # 0 +0x82C1 0x3063 # 0 +0x82C2 0x3064 # 0 +0x82C3 0x3065 # 0 +0x82C4 0x3066 # 0 +0x82C5 0x3067 # 0 +0x82C6 0x3068 # 0 +0x82C7 0x3069 # 0 +0x82C8 0x306A # 0 +0x82C9 0x306B # 0 +0x82CA 0x306C # 0 +0x82CB 0x306D # 0 +0x82CC 0x306E # 0 +0x82CD 0x306F # 0 +0x82CE 0x3070 # 0 +0x82CF 0x3071 # 0 +0x82D0 0x3072 # 0 +0x82D1 0x3073 # 0 +0x82D2 0x3074 # 0 +0x82D3 0x3075 # 0 +0x82D4 0x3076 # 0 +0x82D5 0x3077 # 0 +0x82D6 0x3078 # 0 +0x82D7 0x3079 # 0 +0x82D8 0x307A # 0 +0x82D9 0x307B # 0 +0x82DA 0x307C # 0 +0x82DB 0x307D # 0 +0x82DC 0x307E # 0 +0x82DD 0x307F # 0 +0x82DE 0x3080 # 0 +0x82DF 0x3081 # 0 +0x82E0 0x3082 # 0 +0x82E1 0x3083 # 0 +0x82E2 0x3084 # 0 +0x82E3 0x3085 # 0 +0x82E4 0x3086 # 0 +0x82E5 0x3087 # 0 +0x82E6 0x3088 # 0 +0x82E7 0x3089 # 0 +0x82E8 0x308A # 0 +0x82E9 0x308B # 0 +0x82EA 0x308C # 0 +0x82EB 0x308D # 0 +0x82EC 0x308E # 0 +0x82ED 0x308F # 0 +0x82EE 0x3090 # 0 +0x82EF 0x3091 # 0 +0x82F0 0x3092 # 0 +0x82F1 0x3093 # 0 +0x8340 0x30A1 # 0 +0x8341 0x30A2 # 0 +0x8342 0x30A3 # 0 +0x8343 0x30A4 # 0 +0x8344 0x30A5 # 0 +0x8345 0x30A6 # 0 +0x8346 0x30A7 # 0 +0x8347 0x30A8 # 0 +0x8348 0x30A9 # 0 +0x8349 0x30AA # 0 +0x834A 0x30AB # 0 +0x834B 0x30AC # 0 +0x834C 0x30AD # 0 +0x834D 0x30AE # 0 +0x834E 0x30AF # 0 +0x834F 0x30B0 # 0 +0x8350 0x30B1 # 0 +0x8351 0x30B2 # 0 +0x8352 0x30B3 # 0 +0x8353 0x30B4 # 0 +0x8354 0x30B5 # 0 +0x8355 0x30B6 # 0 +0x8356 0x30B7 # 0 +0x8357 0x30B8 # 0 +0x8358 0x30B9 # 0 +0x8359 0x30BA # 0 +0x835A 0x30BB # 0 +0x835B 0x30BC # 0 +0x835C 0x30BD # 0 +0x835D 0x30BE # 0 +0x835E 0x30BF # 0 +0x835F 0x30C0 # 0 +0x8360 0x30C1 # 0 +0x8361 0x30C2 # 0 +0x8362 0x30C3 # 0 +0x8363 0x30C4 # 0 +0x8364 0x30C5 # 0 +0x8365 0x30C6 # 0 +0x8366 0x30C7 # 0 +0x8367 0x30C8 # 0 +0x8368 0x30C9 # 0 +0x8369 0x30CA # 0 +0x836A 0x30CB # 0 +0x836B 0x30CC # 0 +0x836C 0x30CD # 0 +0x836D 0x30CE # 0 +0x836E 0x30CF # 0 +0x836F 0x30D0 # 0 +0x8370 0x30D1 # 0 +0x8371 0x30D2 # 0 +0x8372 0x30D3 # 0 +0x8373 0x30D4 # 0 +0x8374 0x30D5 # 0 +0x8375 0x30D6 # 0 +0x8376 0x30D7 # 0 +0x8377 0x30D8 # 0 +0x8378 0x30D9 # 0 +0x8379 0x30DA # 0 +0x837A 0x30DB # 0 +0x837B 0x30DC # 0 +0x837C 0x30DD # 0 +0x837D 0x30DE # 0 +0x837E 0x30DF # 0 +0x8380 0x30E0 # 0 +0x8381 0x30E1 # 0 +0x8382 0x30E2 # 0 +0x8383 0x30E3 # 0 +0x8384 0x30E4 # 0 +0x8385 0x30E5 # 0 +0x8386 0x30E6 # 0 +0x8387 0x30E7 # 0 +0x8388 0x30E8 # 0 +0x8389 0x30E9 # 0 +0x838A 0x30EA # 0 +0x838B 0x30EB # 0 +0x838C 0x30EC # 0 +0x838D 0x30ED # 0 +0x838E 0x30EE # 0 +0x838F 0x30EF # 0 +0x8390 0x30F0 # 0 +0x8391 0x30F1 # 0 +0x8392 0x30F2 # 0 +0x8393 0x30F3 # 0 +0x8394 0x30F4 # 0 +0x8395 0x30F5 # 0 +0x8396 0x30F6 # 0 +0x839F 0x0391 # 0 +0x83A0 0x0392 # 0 +0x83A1 0x0393 # 0 +0x83A2 0x0394 # 0 +0x83A3 0x0395 # 0 +0x83A4 0x0396 # 0 +0x83A5 0x0397 # 0 +0x83A6 0x0398 # 0 +0x83A7 0x0399 # 0 +0x83A8 0x039A # 0 +0x83A9 0x039B # 0 +0x83AA 0x039C # 0 +0x83AB 0x039D # 0 +0x83AC 0x039E # 0 +0x83AD 0x039F # 0 +0x83AE 0x03A0 # 0 +0x83AF 0x03A1 # 0 +0x83B0 0x03A3 # 0 +0x83B1 0x03A4 # 0 +0x83B2 0x03A5 # 0 +0x83B3 0x03A6 # 0 +0x83B4 0x03A7 # 0 +0x83B5 0x03A8 # 0 +0x83B6 0x03A9 # 0 +0x83BF 0x03B1 # 0 +0x83C0 0x03B2 # 0 +0x83C1 0x03B3 # 0 +0x83C2 0x03B4 # 0 +0x83C3 0x03B5 # 0 +0x83C4 0x03B6 # 0 +0x83C5 0x03B7 # 0 +0x83C6 0x03B8 # 0 +0x83C7 0x03B9 # 0 +0x83C8 0x03BA # 0 +0x83C9 0x03BB # 0 +0x83CA 0x03BC # 0 +0x83CB 0x03BD # 0 +0x83CC 0x03BE # 0 +0x83CD 0x03BF # 0 +0x83CE 0x03C0 # 0 +0x83CF 0x03C1 # 0 +0x83D0 0x03C3 # 0 +0x83D1 0x03C4 # 0 +0x83D2 0x03C5 # 0 +0x83D3 0x03C6 # 0 +0x83D4 0x03C7 # 0 +0x83D5 0x03C8 # 0 +0x83D6 0x03C9 # 0 +0x8440 0x0410 # 0 +0x8441 0x0411 # 0 +0x8442 0x0412 # 0 +0x8443 0x0413 # 0 +0x8444 0x0414 # 0 +0x8445 0x0415 # 0 +0x8446 0x0401 # 0 +0x8447 0x0416 # 0 +0x8448 0x0417 # 0 +0x8449 0x0418 # 0 +0x844A 0x0419 # 0 +0x844B 0x041A # 0 +0x844C 0x041B # 0 +0x844D 0x041C # 0 +0x844E 0x041D # 0 +0x844F 0x041E # 0 +0x8450 0x041F # 0 +0x8451 0x0420 # 0 +0x8452 0x0421 # 0 +0x8453 0x0422 # 0 +0x8454 0x0423 # 0 +0x8455 0x0424 # 0 +0x8456 0x0425 # 0 +0x8457 0x0426 # 0 +0x8458 0x0427 # 0 +0x8459 0x0428 # 0 +0x845A 0x0429 # 0 +0x845B 0x042A # 0 +0x845C 0x042B # 0 +0x845D 0x042C # 0 +0x845E 0x042D # 0 +0x845F 0x042E # 0 +0x8460 0x042F # 0 +0x8470 0x0430 # 0 +0x8471 0x0431 # 0 +0x8472 0x0432 # 0 +0x8473 0x0433 # 0 +0x8474 0x0434 # 0 +0x8475 0x0435 # 0 +0x8476 0x0451 # 0 +0x8477 0x0436 # 0 +0x8478 0x0437 # 0 +0x8479 0x0438 # 0 +0x847A 0x0439 # 0 +0x847B 0x043A # 0 +0x847C 0x043B # 0 +0x847D 0x043C # 0 +0x847E 0x043D # 0 +0x8480 0x043E # 0 +0x8481 0x043F # 0 +0x8482 0x0440 # 0 +0x8483 0x0441 # 0 +0x8484 0x0442 # 0 +0x8485 0x0443 # 0 +0x8486 0x0444 # 0 +0x8487 0x0445 # 0 +0x8488 0x0446 # 0 +0x8489 0x0447 # 0 +0x848A 0x0448 # 0 +0x848B 0x0449 # 0 +0x848C 0x044A # 0 +0x848D 0x044B # 0 +0x848E 0x044C # 0 +0x848F 0x044D # 0 +0x8490 0x044E # 0 +0x8491 0x044F # 0 +0x849F 0x2500 # 0 +0x84A0 0x2502 # 0 +0x84A1 0x250C # 0 +0x84A2 0x2510 # 0 +0x84A3 0x2518 # 0 +0x84A4 0x2514 # 0 +0x84A5 0x251C # 0 +0x84A6 0x252C # 0 +0x84A7 0x2524 # 0 +0x84A8 0x2534 # 0 +0x84A9 0x253C # 0 +0x84AA 0x2501 # 0 +0x84AB 0x2503 # 0 +0x84AC 0x250F # 0 +0x84AD 0x2513 # 0 +0x84AE 0x251B # 0 +0x84AF 0x2517 # 0 +0x84B0 0x2523 # 0 +0x84B1 0x2533 # 0 +0x84B2 0x252B # 0 +0x84B3 0x253B # 0 +0x84B4 0x254B # 0 +0x84B5 0x2520 # 0 +0x84B6 0x252F # 0 +0x84B7 0x2528 # 0 +0x84B8 0x2537 # 0 +0x84B9 0x253F # 0 +0x84BA 0x251D # 0 +0x84BB 0x2530 # 0 +0x84BC 0x2525 # 0 +0x84BD 0x2538 # 0 +0x84BE 0x2542 # 0 +0x8740 0x2460 # 0 +0x8741 0x2461 # 0 +0x8742 0x2462 # 0 +0x8743 0x2463 # 0 +0x8744 0x2464 # 0 +0x8745 0x2465 # 0 +0x8746 0x2466 # 0 +0x8747 0x2467 # 0 +0x8748 0x2468 # 0 +0x8749 0x2469 # 0 +0x874A 0x246A # 0 +0x874B 0x246B # 0 +0x874C 0x246C # 0 +0x874D 0x246D # 0 +0x874E 0x246E # 0 +0x874F 0x246F # 0 +0x8750 0x2470 # 0 +0x8751 0x2471 # 0 +0x8752 0x2472 # 0 +0x8753 0x2473 # 0 +0x8754 0x2160 # 0 +0x8755 0x2161 # 0 +0x8756 0x2162 # 0 +0x8757 0x2163 # 0 +0x8758 0x2164 # 0 +0x8759 0x2165 # 0 +0x875A 0x2166 # 0 +0x875B 0x2167 # 0 +0x875C 0x2168 # 0 +0x875D 0x2169 # 0 +0x875F 0x3349 # 0 +0x8760 0x3314 # 0 +0x8761 0x3322 # 0 +0x8762 0x334D # 0 +0x8763 0x3318 # 0 +0x8764 0x3327 # 0 +0x8765 0x3303 # 0 +0x8766 0x3336 # 0 +0x8767 0x3351 # 0 +0x8768 0x3357 # 0 +0x8769 0x330D # 0 +0x876A 0x3326 # 0 +0x876B 0x3323 # 0 +0x876C 0x332B # 0 +0x876D 0x334A # 0 +0x876E 0x333B # 0 +0x876F 0x339C # 0 +0x8770 0x339D # 0 +0x8771 0x339E # 0 +0x8772 0x338E # 0 +0x8773 0x338F # 0 +0x8774 0x33C4 # 0 +0x8775 0x33A1 # 0 +0x877E 0x337B # 0 +0x8780 0x301D # 0 +0x8781 0x301F # 0 +0x8782 0x2116 # 0 +0x8783 0x33CD # 0 +0x8784 0x2121 # 0 +0x8785 0x32A4 # 0 +0x8786 0x32A5 # 0 +0x8787 0x32A6 # 0 +0x8788 0x32A7 # 0 +0x8789 0x32A8 # 0 +0x878A 0x3231 # 0 +0x878B 0x3232 # 0 +0x878C 0x3239 # 0 +0x878D 0x337E # 0 +0x878E 0x337D # 0 +0x878F 0x337C # 0 +0x8793 0x222E # 0 +0x8794 0x2211 # 0 +0x8798 0x221F # 0 +0x8799 0x22BF # 0 +0x889F 0x4E9C # 0 +0x88A0 0x5516 # 0 +0x88A1 0x5A03 # 0 +0x88A2 0x963F # 0 +0x88A3 0x54C0 # 0 +0x88A4 0x611B # 0 +0x88A5 0x6328 # 0 +0x88A6 0x59F6 # 0 +0x88A7 0x9022 # 0 +0x88A8 0x8475 # 0 +0x88A9 0x831C # 0 +0x88AA 0x7A50 # 0 +0x88AB 0x60AA # 0 +0x88AC 0x63E1 # 0 +0x88AD 0x6E25 # 0 +0x88AE 0x65ED # 0 +0x88AF 0x8466 # 0 +0x88B0 0x82A6 # 0 +0x88B1 0x9BF5 # 0 +0x88B2 0x6893 # 0 +0x88B3 0x5727 # 0 +0x88B4 0x65A1 # 0 +0x88B5 0x6271 # 0 +0x88B6 0x5B9B # 0 +0x88B7 0x59D0 # 0 +0x88B8 0x867B # 0 +0x88B9 0x98F4 # 0 +0x88BA 0x7D62 # 0 +0x88BB 0x7DBE # 0 +0x88BC 0x9B8E # 0 +0x88BD 0x6216 # 0 +0x88BE 0x7C9F # 0 +0x88BF 0x88B7 # 0 +0x88C0 0x5B89 # 0 +0x88C1 0x5EB5 # 0 +0x88C2 0x6309 # 0 +0x88C3 0x6697 # 0 +0x88C4 0x6848 # 0 +0x88C5 0x95C7 # 0 +0x88C6 0x978D # 0 +0x88C7 0x674F # 0 +0x88C8 0x4EE5 # 0 +0x88C9 0x4F0A # 0 +0x88CA 0x4F4D # 0 +0x88CB 0x4F9D # 0 +0x88CC 0x5049 # 0 +0x88CD 0x56F2 # 0 +0x88CE 0x5937 # 0 +0x88CF 0x59D4 # 0 +0x88D0 0x5A01 # 0 +0x88D1 0x5C09 # 0 +0x88D2 0x60DF # 0 +0x88D3 0x610F # 0 +0x88D4 0x6170 # 0 +0x88D5 0x6613 # 0 +0x88D6 0x6905 # 0 +0x88D7 0x70BA # 0 +0x88D8 0x754F # 0 +0x88D9 0x7570 # 0 +0x88DA 0x79FB # 0 +0x88DB 0x7DAD # 0 +0x88DC 0x7DEF # 0 +0x88DD 0x80C3 # 0 +0x88DE 0x840E # 0 +0x88DF 0x8863 # 0 +0x88E0 0x8B02 # 0 +0x88E1 0x9055 # 0 +0x88E2 0x907A # 0 +0x88E3 0x533B # 0 +0x88E4 0x4E95 # 0 +0x88E5 0x4EA5 # 0 +0x88E6 0x57DF # 0 +0x88E7 0x80B2 # 0 +0x88E8 0x90C1 # 0 +0x88E9 0x78EF # 0 +0x88EA 0x4E00 # 0 +0x88EB 0x58F1 # 0 +0x88EC 0x6EA2 # 0 +0x88ED 0x9038 # 0 +0x88EE 0x7A32 # 0 +0x88EF 0x8328 # 0 +0x88F0 0x828B # 0 +0x88F1 0x9C2F # 0 +0x88F2 0x5141 # 0 +0x88F3 0x5370 # 0 +0x88F4 0x54BD # 0 +0x88F5 0x54E1 # 0 +0x88F6 0x56E0 # 0 +0x88F7 0x59FB # 0 +0x88F8 0x5F15 # 0 +0x88F9 0x98F2 # 0 +0x88FA 0x6DEB # 0 +0x88FB 0x80E4 # 0 +0x88FC 0x852D # 0 +0x8940 0x9662 # 0 +0x8941 0x9670 # 0 +0x8942 0x96A0 # 0 +0x8943 0x97FB # 0 +0x8944 0x540B # 0 +0x8945 0x53F3 # 0 +0x8946 0x5B87 # 0 +0x8947 0x70CF # 0 +0x8948 0x7FBD # 0 +0x8949 0x8FC2 # 0 +0x894A 0x96E8 # 0 +0x894B 0x536F # 0 +0x894C 0x9D5C # 0 +0x894D 0x7ABA # 0 +0x894E 0x4E11 # 0 +0x894F 0x7893 # 0 +0x8950 0x81FC # 0 +0x8951 0x6E26 # 0 +0x8952 0x5618 # 0 +0x8953 0x5504 # 0 +0x8954 0x6B1D # 0 +0x8955 0x851A # 0 +0x8956 0x9C3B # 0 +0x8957 0x59E5 # 0 +0x8958 0x53A9 # 0 +0x8959 0x6D66 # 0 +0x895A 0x74DC # 0 +0x895B 0x958F # 0 +0x895C 0x5642 # 0 +0x895D 0x4E91 # 0 +0x895E 0x904B # 0 +0x895F 0x96F2 # 0 +0x8960 0x834F # 0 +0x8961 0x990C # 0 +0x8962 0x53E1 # 0 +0x8963 0x55B6 # 0 +0x8964 0x5B30 # 0 +0x8965 0x5F71 # 0 +0x8966 0x6620 # 0 +0x8967 0x66F3 # 0 +0x8968 0x6804 # 0 +0x8969 0x6C38 # 0 +0x896A 0x6CF3 # 0 +0x896B 0x6D29 # 0 +0x896C 0x745B # 0 +0x896D 0x76C8 # 0 +0x896E 0x7A4E # 0 +0x896F 0x9834 # 0 +0x8970 0x82F1 # 0 +0x8971 0x885B # 0 +0x8972 0x8A60 # 0 +0x8973 0x92ED # 0 +0x8974 0x6DB2 # 0 +0x8975 0x75AB # 0 +0x8976 0x76CA # 0 +0x8977 0x99C5 # 0 +0x8978 0x60A6 # 0 +0x8979 0x8B01 # 0 +0x897A 0x8D8A # 0 +0x897B 0x95B2 # 0 +0x897C 0x698E # 0 +0x897D 0x53AD # 0 +0x897E 0x5186 # 0 +0x8980 0x5712 # 0 +0x8981 0x5830 # 0 +0x8982 0x5944 # 0 +0x8983 0x5BB4 # 0 +0x8984 0x5EF6 # 0 +0x8985 0x6028 # 0 +0x8986 0x63A9 # 0 +0x8987 0x63F4 # 0 +0x8988 0x6CBF # 0 +0x8989 0x6F14 # 0 +0x898A 0x708E # 0 +0x898B 0x7114 # 0 +0x898C 0x7159 # 0 +0x898D 0x71D5 # 0 +0x898E 0x733F # 0 +0x898F 0x7E01 # 0 +0x8990 0x8276 # 0 +0x8991 0x82D1 # 0 +0x8992 0x8597 # 0 +0x8993 0x9060 # 0 +0x8994 0x925B # 0 +0x8995 0x9D1B # 0 +0x8996 0x5869 # 0 +0x8997 0x65BC # 0 +0x8998 0x6C5A # 0 +0x8999 0x7525 # 0 +0x899A 0x51F9 # 0 +0x899B 0x592E # 0 +0x899C 0x5965 # 0 +0x899D 0x5F80 # 0 +0x899E 0x5FDC # 0 +0x899F 0x62BC # 0 +0x89A0 0x65FA # 0 +0x89A1 0x6A2A # 0 +0x89A2 0x6B27 # 0 +0x89A3 0x6BB4 # 0 +0x89A4 0x738B # 0 +0x89A5 0x7FC1 # 0 +0x89A6 0x8956 # 0 +0x89A7 0x9D2C # 0 +0x89A8 0x9D0E # 0 +0x89A9 0x9EC4 # 0 +0x89AA 0x5CA1 # 0 +0x89AB 0x6C96 # 0 +0x89AC 0x837B # 0 +0x89AD 0x5104 # 0 +0x89AE 0x5C4B # 0 +0x89AF 0x61B6 # 0 +0x89B0 0x81C6 # 0 +0x89B1 0x6876 # 0 +0x89B2 0x7261 # 0 +0x89B3 0x4E59 # 0 +0x89B4 0x4FFA # 0 +0x89B5 0x5378 # 0 +0x89B6 0x6069 # 0 +0x89B7 0x6E29 # 0 +0x89B8 0x7A4F # 0 +0x89B9 0x97F3 # 0 +0x89BA 0x4E0B # 0 +0x89BB 0x5316 # 0 +0x89BC 0x4EEE # 0 +0x89BD 0x4F55 # 0 +0x89BE 0x4F3D # 0 +0x89BF 0x4FA1 # 0 +0x89C0 0x4F73 # 0 +0x89C1 0x52A0 # 0 +0x89C2 0x53EF # 0 +0x89C3 0x5609 # 0 +0x89C4 0x590F # 0 +0x89C5 0x5AC1 # 0 +0x89C6 0x5BB6 # 0 +0x89C7 0x5BE1 # 0 +0x89C8 0x79D1 # 0 +0x89C9 0x6687 # 0 +0x89CA 0x679C # 0 +0x89CB 0x67B6 # 0 +0x89CC 0x6B4C # 0 +0x89CD 0x6CB3 # 0 +0x89CE 0x706B # 0 +0x89CF 0x73C2 # 0 +0x89D0 0x798D # 0 +0x89D1 0x79BE # 0 +0x89D2 0x7A3C # 0 +0x89D3 0x7B87 # 0 +0x89D4 0x82B1 # 0 +0x89D5 0x82DB # 0 +0x89D6 0x8304 # 0 +0x89D7 0x8377 # 0 +0x89D8 0x83EF # 0 +0x89D9 0x83D3 # 0 +0x89DA 0x8766 # 0 +0x89DB 0x8AB2 # 0 +0x89DC 0x5629 # 0 +0x89DD 0x8CA8 # 0 +0x89DE 0x8FE6 # 0 +0x89DF 0x904E # 0 +0x89E0 0x971E # 0 +0x89E1 0x868A # 0 +0x89E2 0x4FC4 # 0 +0x89E3 0x5CE8 # 0 +0x89E4 0x6211 # 0 +0x89E5 0x7259 # 0 +0x89E6 0x753B # 0 +0x89E7 0x81E5 # 0 +0x89E8 0x82BD # 0 +0x89E9 0x86FE # 0 +0x89EA 0x8CC0 # 0 +0x89EB 0x96C5 # 0 +0x89EC 0x9913 # 0 +0x89ED 0x99D5 # 0 +0x89EE 0x4ECB # 0 +0x89EF 0x4F1A # 0 +0x89F0 0x89E3 # 0 +0x89F1 0x56DE # 0 +0x89F2 0x584A # 0 +0x89F3 0x58CA # 0 +0x89F4 0x5EFB # 0 +0x89F5 0x5FEB # 0 +0x89F6 0x602A # 0 +0x89F7 0x6094 # 0 +0x89F8 0x6062 # 0 +0x89F9 0x61D0 # 0 +0x89FA 0x6212 # 0 +0x89FB 0x62D0 # 0 +0x89FC 0x6539 # 0 +0x8A40 0x9B41 # 0 +0x8A41 0x6666 # 0 +0x8A42 0x68B0 # 0 +0x8A43 0x6D77 # 0 +0x8A44 0x7070 # 0 +0x8A45 0x754C # 0 +0x8A46 0x7686 # 0 +0x8A47 0x7D75 # 0 +0x8A48 0x82A5 # 0 +0x8A49 0x87F9 # 0 +0x8A4A 0x958B # 0 +0x8A4B 0x968E # 0 +0x8A4C 0x8C9D # 0 +0x8A4D 0x51F1 # 0 +0x8A4E 0x52BE # 0 +0x8A4F 0x5916 # 0 +0x8A50 0x54B3 # 0 +0x8A51 0x5BB3 # 0 +0x8A52 0x5D16 # 0 +0x8A53 0x6168 # 0 +0x8A54 0x6982 # 0 +0x8A55 0x6DAF # 0 +0x8A56 0x788D # 0 +0x8A57 0x84CB # 0 +0x8A58 0x8857 # 0 +0x8A59 0x8A72 # 0 +0x8A5A 0x93A7 # 0 +0x8A5B 0x9AB8 # 0 +0x8A5C 0x6D6C # 0 +0x8A5D 0x99A8 # 0 +0x8A5E 0x86D9 # 0 +0x8A5F 0x57A3 # 0 +0x8A60 0x67FF # 0 +0x8A61 0x86CE # 0 +0x8A62 0x920E # 0 +0x8A63 0x5283 # 0 +0x8A64 0x5687 # 0 +0x8A65 0x5404 # 0 +0x8A66 0x5ED3 # 0 +0x8A67 0x62E1 # 0 +0x8A68 0x64B9 # 0 +0x8A69 0x683C # 0 +0x8A6A 0x6838 # 0 +0x8A6B 0x6BBB # 0 +0x8A6C 0x7372 # 0 +0x8A6D 0x78BA # 0 +0x8A6E 0x7A6B # 0 +0x8A6F 0x899A # 0 +0x8A70 0x89D2 # 0 +0x8A71 0x8D6B # 0 +0x8A72 0x8F03 # 0 +0x8A73 0x90ED # 0 +0x8A74 0x95A3 # 0 +0x8A75 0x9694 # 0 +0x8A76 0x9769 # 0 +0x8A77 0x5B66 # 0 +0x8A78 0x5CB3 # 0 +0x8A79 0x697D # 0 +0x8A7A 0x984D # 0 +0x8A7B 0x984E # 0 +0x8A7C 0x639B # 0 +0x8A7D 0x7B20 # 0 +0x8A7E 0x6A2B # 0 +0x8A80 0x6A7F # 0 +0x8A81 0x68B6 # 0 +0x8A82 0x9C0D # 0 +0x8A83 0x6F5F # 0 +0x8A84 0x5272 # 0 +0x8A85 0x559D # 0 +0x8A86 0x6070 # 0 +0x8A87 0x62EC # 0 +0x8A88 0x6D3B # 0 +0x8A89 0x6E07 # 0 +0x8A8A 0x6ED1 # 0 +0x8A8B 0x845B # 0 +0x8A8C 0x8910 # 0 +0x8A8D 0x8F44 # 0 +0x8A8E 0x4E14 # 0 +0x8A8F 0x9C39 # 0 +0x8A90 0x53F6 # 0 +0x8A91 0x691B # 0 +0x8A92 0x6A3A # 0 +0x8A93 0x9784 # 0 +0x8A94 0x682A # 0 +0x8A95 0x515C # 0 +0x8A96 0x7AC3 # 0 +0x8A97 0x84B2 # 0 +0x8A98 0x91DC # 0 +0x8A99 0x938C # 0 +0x8A9A 0x565B # 0 +0x8A9B 0x9D28 # 0 +0x8A9C 0x6822 # 0 +0x8A9D 0x8305 # 0 +0x8A9E 0x8431 # 0 +0x8A9F 0x7CA5 # 0 +0x8AA0 0x5208 # 0 +0x8AA1 0x82C5 # 0 +0x8AA2 0x74E6 # 0 +0x8AA3 0x4E7E # 0 +0x8AA4 0x4F83 # 0 +0x8AA5 0x51A0 # 0 +0x8AA6 0x5BD2 # 0 +0x8AA7 0x520A # 0 +0x8AA8 0x52D8 # 0 +0x8AA9 0x52E7 # 0 +0x8AAA 0x5DFB # 0 +0x8AAB 0x559A # 0 +0x8AAC 0x582A # 0 +0x8AAD 0x59E6 # 0 +0x8AAE 0x5B8C # 0 +0x8AAF 0x5B98 # 0 +0x8AB0 0x5BDB # 0 +0x8AB1 0x5E72 # 0 +0x8AB2 0x5E79 # 0 +0x8AB3 0x60A3 # 0 +0x8AB4 0x611F # 0 +0x8AB5 0x6163 # 0 +0x8AB6 0x61BE # 0 +0x8AB7 0x63DB # 0 +0x8AB8 0x6562 # 0 +0x8AB9 0x67D1 # 0 +0x8ABA 0x6853 # 0 +0x8ABB 0x68FA # 0 +0x8ABC 0x6B3E # 0 +0x8ABD 0x6B53 # 0 +0x8ABE 0x6C57 # 0 +0x8ABF 0x6F22 # 0 +0x8AC0 0x6F97 # 0 +0x8AC1 0x6F45 # 0 +0x8AC2 0x74B0 # 0 +0x8AC3 0x7518 # 0 +0x8AC4 0x76E3 # 0 +0x8AC5 0x770B # 0 +0x8AC6 0x7AFF # 0 +0x8AC7 0x7BA1 # 0 +0x8AC8 0x7C21 # 0 +0x8AC9 0x7DE9 # 0 +0x8ACA 0x7F36 # 0 +0x8ACB 0x7FF0 # 0 +0x8ACC 0x809D # 0 +0x8ACD 0x8266 # 0 +0x8ACE 0x839E # 0 +0x8ACF 0x89B3 # 0 +0x8AD0 0x8ACC # 0 +0x8AD1 0x8CAB # 0 +0x8AD2 0x9084 # 0 +0x8AD3 0x9451 # 0 +0x8AD4 0x9593 # 0 +0x8AD5 0x9591 # 0 +0x8AD6 0x95A2 # 0 +0x8AD7 0x9665 # 0 +0x8AD8 0x97D3 # 0 +0x8AD9 0x9928 # 0 +0x8ADA 0x8218 # 0 +0x8ADB 0x4E38 # 0 +0x8ADC 0x542B # 0 +0x8ADD 0x5CB8 # 0 +0x8ADE 0x5DCC # 0 +0x8ADF 0x73A9 # 0 +0x8AE0 0x764C # 0 +0x8AE1 0x773C # 0 +0x8AE2 0x5CA9 # 0 +0x8AE3 0x7FEB # 0 +0x8AE4 0x8D0B # 0 +0x8AE5 0x96C1 # 0 +0x8AE6 0x9811 # 0 +0x8AE7 0x9854 # 0 +0x8AE8 0x9858 # 0 +0x8AE9 0x4F01 # 0 +0x8AEA 0x4F0E # 0 +0x8AEB 0x5371 # 0 +0x8AEC 0x559C # 0 +0x8AED 0x5668 # 0 +0x8AEE 0x57FA # 0 +0x8AEF 0x5947 # 0 +0x8AF0 0x5B09 # 0 +0x8AF1 0x5BC4 # 0 +0x8AF2 0x5C90 # 0 +0x8AF3 0x5E0C # 0 +0x8AF4 0x5E7E # 0 +0x8AF5 0x5FCC # 0 +0x8AF6 0x63EE # 0 +0x8AF7 0x673A # 0 +0x8AF8 0x65D7 # 0 +0x8AF9 0x65E2 # 0 +0x8AFA 0x671F # 0 +0x8AFB 0x68CB # 0 +0x8AFC 0x68C4 # 0 +0x8B40 0x6A5F # 0 +0x8B41 0x5E30 # 0 +0x8B42 0x6BC5 # 0 +0x8B43 0x6C17 # 0 +0x8B44 0x6C7D # 0 +0x8B45 0x757F # 0 +0x8B46 0x7948 # 0 +0x8B47 0x5B63 # 0 +0x8B48 0x7A00 # 0 +0x8B49 0x7D00 # 0 +0x8B4A 0x5FBD # 0 +0x8B4B 0x898F # 0 +0x8B4C 0x8A18 # 0 +0x8B4D 0x8CB4 # 0 +0x8B4E 0x8D77 # 0 +0x8B4F 0x8ECC # 0 +0x8B50 0x8F1D # 0 +0x8B51 0x98E2 # 0 +0x8B52 0x9A0E # 0 +0x8B53 0x9B3C # 0 +0x8B54 0x4E80 # 0 +0x8B55 0x507D # 0 +0x8B56 0x5100 # 0 +0x8B57 0x5993 # 0 +0x8B58 0x5B9C # 0 +0x8B59 0x622F # 0 +0x8B5A 0x6280 # 0 +0x8B5B 0x64EC # 0 +0x8B5C 0x6B3A # 0 +0x8B5D 0x72A0 # 0 +0x8B5E 0x7591 # 0 +0x8B5F 0x7947 # 0 +0x8B60 0x7FA9 # 0 +0x8B61 0x87FB # 0 +0x8B62 0x8ABC # 0 +0x8B63 0x8B70 # 0 +0x8B64 0x63AC # 0 +0x8B65 0x83CA # 0 +0x8B66 0x97A0 # 0 +0x8B67 0x5409 # 0 +0x8B68 0x5403 # 0 +0x8B69 0x55AB # 0 +0x8B6A 0x6854 # 0 +0x8B6B 0x6A58 # 0 +0x8B6C 0x8A70 # 0 +0x8B6D 0x7827 # 0 +0x8B6E 0x6775 # 0 +0x8B6F 0x9ECD # 0 +0x8B70 0x5374 # 0 +0x8B71 0x5BA2 # 0 +0x8B72 0x811A # 0 +0x8B73 0x8650 # 0 +0x8B74 0x9006 # 0 +0x8B75 0x4E18 # 0 +0x8B76 0x4E45 # 0 +0x8B77 0x4EC7 # 0 +0x8B78 0x4F11 # 0 +0x8B79 0x53CA # 0 +0x8B7A 0x5438 # 0 +0x8B7B 0x5BAE # 0 +0x8B7C 0x5F13 # 0 +0x8B7D 0x6025 # 0 +0x8B7E 0x6551 # 0 +0x8B80 0x673D # 0 +0x8B81 0x6C42 # 0 +0x8B82 0x6C72 # 0 +0x8B83 0x6CE3 # 0 +0x8B84 0x7078 # 0 +0x8B85 0x7403 # 0 +0x8B86 0x7A76 # 0 +0x8B87 0x7AAE # 0 +0x8B88 0x7B08 # 0 +0x8B89 0x7D1A # 0 +0x8B8A 0x7CFE # 0 +0x8B8B 0x7D66 # 0 +0x8B8C 0x65E7 # 0 +0x8B8D 0x725B # 0 +0x8B8E 0x53BB # 0 +0x8B8F 0x5C45 # 0 +0x8B90 0x5DE8 # 0 +0x8B91 0x62D2 # 0 +0x8B92 0x62E0 # 0 +0x8B93 0x6319 # 0 +0x8B94 0x6E20 # 0 +0x8B95 0x865A # 0 +0x8B96 0x8A31 # 0 +0x8B97 0x8DDD # 0 +0x8B98 0x92F8 # 0 +0x8B99 0x6F01 # 0 +0x8B9A 0x79A6 # 0 +0x8B9B 0x9B5A # 0 +0x8B9C 0x4EA8 # 0 +0x8B9D 0x4EAB # 0 +0x8B9E 0x4EAC # 0 +0x8B9F 0x4F9B # 0 +0x8BA0 0x4FA0 # 0 +0x8BA1 0x50D1 # 0 +0x8BA2 0x5147 # 0 +0x8BA3 0x7AF6 # 0 +0x8BA4 0x5171 # 0 +0x8BA5 0x51F6 # 0 +0x8BA6 0x5354 # 0 +0x8BA7 0x5321 # 0 +0x8BA8 0x537F # 0 +0x8BA9 0x53EB # 0 +0x8BAA 0x55AC # 0 +0x8BAB 0x5883 # 0 +0x8BAC 0x5CE1 # 0 +0x8BAD 0x5F37 # 0 +0x8BAE 0x5F4A # 0 +0x8BAF 0x602F # 0 +0x8BB0 0x6050 # 0 +0x8BB1 0x606D # 0 +0x8BB2 0x631F # 0 +0x8BB3 0x6559 # 0 +0x8BB4 0x6A4B # 0 +0x8BB5 0x6CC1 # 0 +0x8BB6 0x72C2 # 0 +0x8BB7 0x72ED # 0 +0x8BB8 0x77EF # 0 +0x8BB9 0x80F8 # 0 +0x8BBA 0x8105 # 0 +0x8BBB 0x8208 # 0 +0x8BBC 0x854E # 0 +0x8BBD 0x90F7 # 0 +0x8BBE 0x93E1 # 0 +0x8BBF 0x97FF # 0 +0x8BC0 0x9957 # 0 +0x8BC1 0x9A5A # 0 +0x8BC2 0x4EF0 # 0 +0x8BC3 0x51DD # 0 +0x8BC4 0x5C2D # 0 +0x8BC5 0x6681 # 0 +0x8BC6 0x696D # 0 +0x8BC7 0x5C40 # 0 +0x8BC8 0x66F2 # 0 +0x8BC9 0x6975 # 0 +0x8BCA 0x7389 # 0 +0x8BCB 0x6850 # 0 +0x8BCC 0x7C81 # 0 +0x8BCD 0x50C5 # 0 +0x8BCE 0x52E4 # 0 +0x8BCF 0x5747 # 0 +0x8BD0 0x5DFE # 0 +0x8BD1 0x9326 # 0 +0x8BD2 0x65A4 # 0 +0x8BD3 0x6B23 # 0 +0x8BD4 0x6B3D # 0 +0x8BD5 0x7434 # 0 +0x8BD6 0x7981 # 0 +0x8BD7 0x79BD # 0 +0x8BD8 0x7B4B # 0 +0x8BD9 0x7DCA # 0 +0x8BDA 0x82B9 # 0 +0x8BDB 0x83CC # 0 +0x8BDC 0x887F # 0 +0x8BDD 0x895F # 0 +0x8BDE 0x8B39 # 0 +0x8BDF 0x8FD1 # 0 +0x8BE0 0x91D1 # 0 +0x8BE1 0x541F # 0 +0x8BE2 0x9280 # 0 +0x8BE3 0x4E5D # 0 +0x8BE4 0x5036 # 0 +0x8BE5 0x53E5 # 0 +0x8BE6 0x533A # 0 +0x8BE7 0x72D7 # 0 +0x8BE8 0x7396 # 0 +0x8BE9 0x77E9 # 0 +0x8BEA 0x82E6 # 0 +0x8BEB 0x8EAF # 0 +0x8BEC 0x99C6 # 0 +0x8BED 0x99C8 # 0 +0x8BEE 0x99D2 # 0 +0x8BEF 0x5177 # 0 +0x8BF0 0x611A # 0 +0x8BF1 0x865E # 0 +0x8BF2 0x55B0 # 0 +0x8BF3 0x7A7A # 0 +0x8BF4 0x5076 # 0 +0x8BF5 0x5BD3 # 0 +0x8BF6 0x9047 # 0 +0x8BF7 0x9685 # 0 +0x8BF8 0x4E32 # 0 +0x8BF9 0x6ADB # 0 +0x8BFA 0x91E7 # 0 +0x8BFB 0x5C51 # 0 +0x8BFC 0x5C48 # 0 +0x8C40 0x6398 # 0 +0x8C41 0x7A9F # 0 +0x8C42 0x6C93 # 0 +0x8C43 0x9774 # 0 +0x8C44 0x8F61 # 0 +0x8C45 0x7AAA # 0 +0x8C46 0x718A # 0 +0x8C47 0x9688 # 0 +0x8C48 0x7C82 # 0 +0x8C49 0x6817 # 0 +0x8C4A 0x7E70 # 0 +0x8C4B 0x6851 # 0 +0x8C4C 0x936C # 0 +0x8C4D 0x52F2 # 0 +0x8C4E 0x541B # 0 +0x8C4F 0x85AB # 0 +0x8C50 0x8A13 # 0 +0x8C51 0x7FA4 # 0 +0x8C52 0x8ECD # 0 +0x8C53 0x90E1 # 0 +0x8C54 0x5366 # 0 +0x8C55 0x8888 # 0 +0x8C56 0x7941 # 0 +0x8C57 0x4FC2 # 0 +0x8C58 0x50BE # 0 +0x8C59 0x5211 # 0 +0x8C5A 0x5144 # 0 +0x8C5B 0x5553 # 0 +0x8C5C 0x572D # 0 +0x8C5D 0x73EA # 0 +0x8C5E 0x578B # 0 +0x8C5F 0x5951 # 0 +0x8C60 0x5F62 # 0 +0x8C61 0x5F84 # 0 +0x8C62 0x6075 # 0 +0x8C63 0x6176 # 0 +0x8C64 0x6167 # 0 +0x8C65 0x61A9 # 0 +0x8C66 0x63B2 # 0 +0x8C67 0x643A # 0 +0x8C68 0x656C # 0 +0x8C69 0x666F # 0 +0x8C6A 0x6842 # 0 +0x8C6B 0x6E13 # 0 +0x8C6C 0x7566 # 0 +0x8C6D 0x7A3D # 0 +0x8C6E 0x7CFB # 0 +0x8C6F 0x7D4C # 0 +0x8C70 0x7D99 # 0 +0x8C71 0x7E4B # 0 +0x8C72 0x7F6B # 0 +0x8C73 0x830E # 0 +0x8C74 0x834A # 0 +0x8C75 0x86CD # 0 +0x8C76 0x8A08 # 0 +0x8C77 0x8A63 # 0 +0x8C78 0x8B66 # 0 +0x8C79 0x8EFD # 0 +0x8C7A 0x981A # 0 +0x8C7B 0x9D8F # 0 +0x8C7C 0x82B8 # 0 +0x8C7D 0x8FCE # 0 +0x8C7E 0x9BE8 # 0 +0x8C80 0x5287 # 0 +0x8C81 0x621F # 0 +0x8C82 0x6483 # 0 +0x8C83 0x6FC0 # 0 +0x8C84 0x9699 # 0 +0x8C85 0x6841 # 0 +0x8C86 0x5091 # 0 +0x8C87 0x6B20 # 0 +0x8C88 0x6C7A # 0 +0x8C89 0x6F54 # 0 +0x8C8A 0x7A74 # 0 +0x8C8B 0x7D50 # 0 +0x8C8C 0x8840 # 0 +0x8C8D 0x8A23 # 0 +0x8C8E 0x6708 # 0 +0x8C8F 0x4EF6 # 0 +0x8C90 0x5039 # 0 +0x8C91 0x5026 # 0 +0x8C92 0x5065 # 0 +0x8C93 0x517C # 0 +0x8C94 0x5238 # 0 +0x8C95 0x5263 # 0 +0x8C96 0x55A7 # 0 +0x8C97 0x570F # 0 +0x8C98 0x5805 # 0 +0x8C99 0x5ACC # 0 +0x8C9A 0x5EFA # 0 +0x8C9B 0x61B2 # 0 +0x8C9C 0x61F8 # 0 +0x8C9D 0x62F3 # 0 +0x8C9E 0x6372 # 0 +0x8C9F 0x691C # 0 +0x8CA0 0x6A29 # 0 +0x8CA1 0x727D # 0 +0x8CA2 0x72AC # 0 +0x8CA3 0x732E # 0 +0x8CA4 0x7814 # 0 +0x8CA5 0x786F # 0 +0x8CA6 0x7D79 # 0 +0x8CA7 0x770C # 0 +0x8CA8 0x80A9 # 0 +0x8CA9 0x898B # 0 +0x8CAA 0x8B19 # 0 +0x8CAB 0x8CE2 # 0 +0x8CAC 0x8ED2 # 0 +0x8CAD 0x9063 # 0 +0x8CAE 0x9375 # 0 +0x8CAF 0x967A # 0 +0x8CB0 0x9855 # 0 +0x8CB1 0x9A13 # 0 +0x8CB2 0x9E78 # 0 +0x8CB3 0x5143 # 0 +0x8CB4 0x539F # 0 +0x8CB5 0x53B3 # 0 +0x8CB6 0x5E7B # 0 +0x8CB7 0x5F26 # 0 +0x8CB8 0x6E1B # 0 +0x8CB9 0x6E90 # 0 +0x8CBA 0x7384 # 0 +0x8CBB 0x73FE # 0 +0x8CBC 0x7D43 # 0 +0x8CBD 0x8237 # 0 +0x8CBE 0x8A00 # 0 +0x8CBF 0x8AFA # 0 +0x8CC0 0x9650 # 0 +0x8CC1 0x4E4E # 0 +0x8CC2 0x500B # 0 +0x8CC3 0x53E4 # 0 +0x8CC4 0x547C # 0 +0x8CC5 0x56FA # 0 +0x8CC6 0x59D1 # 0 +0x8CC7 0x5B64 # 0 +0x8CC8 0x5DF1 # 0 +0x8CC9 0x5EAB # 0 +0x8CCA 0x5F27 # 0 +0x8CCB 0x6238 # 0 +0x8CCC 0x6545 # 0 +0x8CCD 0x67AF # 0 +0x8CCE 0x6E56 # 0 +0x8CCF 0x72D0 # 0 +0x8CD0 0x7CCA # 0 +0x8CD1 0x88B4 # 0 +0x8CD2 0x80A1 # 0 +0x8CD3 0x80E1 # 0 +0x8CD4 0x83F0 # 0 +0x8CD5 0x864E # 0 +0x8CD6 0x8A87 # 0 +0x8CD7 0x8DE8 # 0 +0x8CD8 0x9237 # 0 +0x8CD9 0x96C7 # 0 +0x8CDA 0x9867 # 0 +0x8CDB 0x9F13 # 0 +0x8CDC 0x4E94 # 0 +0x8CDD 0x4E92 # 0 +0x8CDE 0x4F0D # 0 +0x8CDF 0x5348 # 0 +0x8CE0 0x5449 # 0 +0x8CE1 0x543E # 0 +0x8CE2 0x5A2F # 0 +0x8CE3 0x5F8C # 0 +0x8CE4 0x5FA1 # 0 +0x8CE5 0x609F # 0 +0x8CE6 0x68A7 # 0 +0x8CE7 0x6A8E # 0 +0x8CE8 0x745A # 0 +0x8CE9 0x7881 # 0 +0x8CEA 0x8A9E # 0 +0x8CEB 0x8AA4 # 0 +0x8CEC 0x8B77 # 0 +0x8CED 0x9190 # 0 +0x8CEE 0x4E5E # 0 +0x8CEF 0x9BC9 # 0 +0x8CF0 0x4EA4 # 0 +0x8CF1 0x4F7C # 0 +0x8CF2 0x4FAF # 0 +0x8CF3 0x5019 # 0 +0x8CF4 0x5016 # 0 +0x8CF5 0x5149 # 0 +0x8CF6 0x516C # 0 +0x8CF7 0x529F # 0 +0x8CF8 0x52B9 # 0 +0x8CF9 0x52FE # 0 +0x8CFA 0x539A # 0 +0x8CFB 0x53E3 # 0 +0x8CFC 0x5411 # 0 +0x8D40 0x540E # 0 +0x8D41 0x5589 # 0 +0x8D42 0x5751 # 0 +0x8D43 0x57A2 # 0 +0x8D44 0x597D # 0 +0x8D45 0x5B54 # 0 +0x8D46 0x5B5D # 0 +0x8D47 0x5B8F # 0 +0x8D48 0x5DE5 # 0 +0x8D49 0x5DE7 # 0 +0x8D4A 0x5DF7 # 0 +0x8D4B 0x5E78 # 0 +0x8D4C 0x5E83 # 0 +0x8D4D 0x5E9A # 0 +0x8D4E 0x5EB7 # 0 +0x8D4F 0x5F18 # 0 +0x8D50 0x6052 # 0 +0x8D51 0x614C # 0 +0x8D52 0x6297 # 0 +0x8D53 0x62D8 # 0 +0x8D54 0x63A7 # 0 +0x8D55 0x653B # 0 +0x8D56 0x6602 # 0 +0x8D57 0x6643 # 0 +0x8D58 0x66F4 # 0 +0x8D59 0x676D # 0 +0x8D5A 0x6821 # 0 +0x8D5B 0x6897 # 0 +0x8D5C 0x69CB # 0 +0x8D5D 0x6C5F # 0 +0x8D5E 0x6D2A # 0 +0x8D5F 0x6D69 # 0 +0x8D60 0x6E2F # 0 +0x8D61 0x6E9D # 0 +0x8D62 0x7532 # 0 +0x8D63 0x7687 # 0 +0x8D64 0x786C # 0 +0x8D65 0x7A3F # 0 +0x8D66 0x7CE0 # 0 +0x8D67 0x7D05 # 0 +0x8D68 0x7D18 # 0 +0x8D69 0x7D5E # 0 +0x8D6A 0x7DB1 # 0 +0x8D6B 0x8015 # 0 +0x8D6C 0x8003 # 0 +0x8D6D 0x80AF # 0 +0x8D6E 0x80B1 # 0 +0x8D6F 0x8154 # 0 +0x8D70 0x818F # 0 +0x8D71 0x822A # 0 +0x8D72 0x8352 # 0 +0x8D73 0x884C # 0 +0x8D74 0x8861 # 0 +0x8D75 0x8B1B # 0 +0x8D76 0x8CA2 # 0 +0x8D77 0x8CFC # 0 +0x8D78 0x90CA # 0 +0x8D79 0x9175 # 0 +0x8D7A 0x9271 # 0 +0x8D7B 0x783F # 0 +0x8D7C 0x92FC # 0 +0x8D7D 0x95A4 # 0 +0x8D7E 0x964D # 0 +0x8D80 0x9805 # 0 +0x8D81 0x9999 # 0 +0x8D82 0x9AD8 # 0 +0x8D83 0x9D3B # 0 +0x8D84 0x525B # 0 +0x8D85 0x52AB # 0 +0x8D86 0x53F7 # 0 +0x8D87 0x5408 # 0 +0x8D88 0x58D5 # 0 +0x8D89 0x62F7 # 0 +0x8D8A 0x6FE0 # 0 +0x8D8B 0x8C6A # 0 +0x8D8C 0x8F5F # 0 +0x8D8D 0x9EB9 # 0 +0x8D8E 0x514B # 0 +0x8D8F 0x523B # 0 +0x8D90 0x544A # 0 +0x8D91 0x56FD # 0 +0x8D92 0x7A40 # 0 +0x8D93 0x9177 # 0 +0x8D94 0x9D60 # 0 +0x8D95 0x9ED2 # 0 +0x8D96 0x7344 # 0 +0x8D97 0x6F09 # 0 +0x8D98 0x8170 # 0 +0x8D99 0x7511 # 0 +0x8D9A 0x5FFD # 0 +0x8D9B 0x60DA # 0 +0x8D9C 0x9AA8 # 0 +0x8D9D 0x72DB # 0 +0x8D9E 0x8FBC # 0 +0x8D9F 0x6B64 # 0 +0x8DA0 0x9803 # 0 +0x8DA1 0x4ECA # 0 +0x8DA2 0x56F0 # 0 +0x8DA3 0x5764 # 0 +0x8DA4 0x58BE # 0 +0x8DA5 0x5A5A # 0 +0x8DA6 0x6068 # 0 +0x8DA7 0x61C7 # 0 +0x8DA8 0x660F # 0 +0x8DA9 0x6606 # 0 +0x8DAA 0x6839 # 0 +0x8DAB 0x68B1 # 0 +0x8DAC 0x6DF7 # 0 +0x8DAD 0x75D5 # 0 +0x8DAE 0x7D3A # 0 +0x8DAF 0x826E # 0 +0x8DB0 0x9B42 # 0 +0x8DB1 0x4E9B # 0 +0x8DB2 0x4F50 # 0 +0x8DB3 0x53C9 # 0 +0x8DB4 0x5506 # 0 +0x8DB5 0x5D6F # 0 +0x8DB6 0x5DE6 # 0 +0x8DB7 0x5DEE # 0 +0x8DB8 0x67FB # 0 +0x8DB9 0x6C99 # 0 +0x8DBA 0x7473 # 0 +0x8DBB 0x7802 # 0 +0x8DBC 0x8A50 # 0 +0x8DBD 0x9396 # 0 +0x8DBE 0x88DF # 0 +0x8DBF 0x5750 # 0 +0x8DC0 0x5EA7 # 0 +0x8DC1 0x632B # 0 +0x8DC2 0x50B5 # 0 +0x8DC3 0x50AC # 0 +0x8DC4 0x518D # 0 +0x8DC5 0x6700 # 0 +0x8DC6 0x54C9 # 0 +0x8DC7 0x585E # 0 +0x8DC8 0x59BB # 0 +0x8DC9 0x5BB0 # 0 +0x8DCA 0x5F69 # 0 +0x8DCB 0x624D # 0 +0x8DCC 0x63A1 # 0 +0x8DCD 0x683D # 0 +0x8DCE 0x6B73 # 0 +0x8DCF 0x6E08 # 0 +0x8DD0 0x707D # 0 +0x8DD1 0x91C7 # 0 +0x8DD2 0x7280 # 0 +0x8DD3 0x7815 # 0 +0x8DD4 0x7826 # 0 +0x8DD5 0x796D # 0 +0x8DD6 0x658E # 0 +0x8DD7 0x7D30 # 0 +0x8DD8 0x83DC # 0 +0x8DD9 0x88C1 # 0 +0x8DDA 0x8F09 # 0 +0x8DDB 0x969B # 0 +0x8DDC 0x5264 # 0 +0x8DDD 0x5728 # 0 +0x8DDE 0x6750 # 0 +0x8DDF 0x7F6A # 0 +0x8DE0 0x8CA1 # 0 +0x8DE1 0x51B4 # 0 +0x8DE2 0x5742 # 0 +0x8DE3 0x962A # 0 +0x8DE4 0x583A # 0 +0x8DE5 0x698A # 0 +0x8DE6 0x80B4 # 0 +0x8DE7 0x54B2 # 0 +0x8DE8 0x5D0E # 0 +0x8DE9 0x57FC # 0 +0x8DEA 0x7895 # 0 +0x8DEB 0x9DFA # 0 +0x8DEC 0x4F5C # 0 +0x8DED 0x524A # 0 +0x8DEE 0x548B # 0 +0x8DEF 0x643E # 0 +0x8DF0 0x6628 # 0 +0x8DF1 0x6714 # 0 +0x8DF2 0x67F5 # 0 +0x8DF3 0x7A84 # 0 +0x8DF4 0x7B56 # 0 +0x8DF5 0x7D22 # 0 +0x8DF6 0x932F # 0 +0x8DF7 0x685C # 0 +0x8DF8 0x9BAD # 0 +0x8DF9 0x7B39 # 0 +0x8DFA 0x5319 # 0 +0x8DFB 0x518A # 0 +0x8DFC 0x5237 # 0 +0x8E40 0x5BDF # 0 +0x8E41 0x62F6 # 0 +0x8E42 0x64AE # 0 +0x8E43 0x64E6 # 0 +0x8E44 0x672D # 0 +0x8E45 0x6BBA # 0 +0x8E46 0x85A9 # 0 +0x8E47 0x96D1 # 0 +0x8E48 0x7690 # 0 +0x8E49 0x9BD6 # 0 +0x8E4A 0x634C # 0 +0x8E4B 0x9306 # 0 +0x8E4C 0x9BAB # 0 +0x8E4D 0x76BF # 0 +0x8E4E 0x6652 # 0 +0x8E4F 0x4E09 # 0 +0x8E50 0x5098 # 0 +0x8E51 0x53C2 # 0 +0x8E52 0x5C71 # 0 +0x8E53 0x60E8 # 0 +0x8E54 0x6492 # 0 +0x8E55 0x6563 # 0 +0x8E56 0x685F # 0 +0x8E57 0x71E6 # 0 +0x8E58 0x73CA # 0 +0x8E59 0x7523 # 0 +0x8E5A 0x7B97 # 0 +0x8E5B 0x7E82 # 0 +0x8E5C 0x8695 # 0 +0x8E5D 0x8B83 # 0 +0x8E5E 0x8CDB # 0 +0x8E5F 0x9178 # 0 +0x8E60 0x9910 # 0 +0x8E61 0x65AC # 0 +0x8E62 0x66AB # 0 +0x8E63 0x6B8B # 0 +0x8E64 0x4ED5 # 0 +0x8E65 0x4ED4 # 0 +0x8E66 0x4F3A # 0 +0x8E67 0x4F7F # 0 +0x8E68 0x523A # 0 +0x8E69 0x53F8 # 0 +0x8E6A 0x53F2 # 0 +0x8E6B 0x55E3 # 0 +0x8E6C 0x56DB # 0 +0x8E6D 0x58EB # 0 +0x8E6E 0x59CB # 0 +0x8E6F 0x59C9 # 0 +0x8E70 0x59FF # 0 +0x8E71 0x5B50 # 0 +0x8E72 0x5C4D # 0 +0x8E73 0x5E02 # 0 +0x8E74 0x5E2B # 0 +0x8E75 0x5FD7 # 0 +0x8E76 0x601D # 0 +0x8E77 0x6307 # 0 +0x8E78 0x652F # 0 +0x8E79 0x5B5C # 0 +0x8E7A 0x65AF # 0 +0x8E7B 0x65BD # 0 +0x8E7C 0x65E8 # 0 +0x8E7D 0x679D # 0 +0x8E7E 0x6B62 # 0 +0x8E80 0x6B7B # 0 +0x8E81 0x6C0F # 0 +0x8E82 0x7345 # 0 +0x8E83 0x7949 # 0 +0x8E84 0x79C1 # 0 +0x8E85 0x7CF8 # 0 +0x8E86 0x7D19 # 0 +0x8E87 0x7D2B # 0 +0x8E88 0x80A2 # 0 +0x8E89 0x8102 # 0 +0x8E8A 0x81F3 # 0 +0x8E8B 0x8996 # 0 +0x8E8C 0x8A5E # 0 +0x8E8D 0x8A69 # 0 +0x8E8E 0x8A66 # 0 +0x8E8F 0x8A8C # 0 +0x8E90 0x8AEE # 0 +0x8E91 0x8CC7 # 0 +0x8E92 0x8CDC # 0 +0x8E93 0x96CC # 0 +0x8E94 0x98FC # 0 +0x8E95 0x6B6F # 0 +0x8E96 0x4E8B # 0 +0x8E97 0x4F3C # 0 +0x8E98 0x4F8D # 0 +0x8E99 0x5150 # 0 +0x8E9A 0x5B57 # 0 +0x8E9B 0x5BFA # 0 +0x8E9C 0x6148 # 0 +0x8E9D 0x6301 # 0 +0x8E9E 0x6642 # 0 +0x8E9F 0x6B21 # 0 +0x8EA0 0x6ECB # 0 +0x8EA1 0x6CBB # 0 +0x8EA2 0x723E # 0 +0x8EA3 0x74BD # 0 +0x8EA4 0x75D4 # 0 +0x8EA5 0x78C1 # 0 +0x8EA6 0x793A # 0 +0x8EA7 0x800C # 0 +0x8EA8 0x8033 # 0 +0x8EA9 0x81EA # 0 +0x8EAA 0x8494 # 0 +0x8EAB 0x8F9E # 0 +0x8EAC 0x6C50 # 0 +0x8EAD 0x9E7F # 0 +0x8EAE 0x5F0F # 0 +0x8EAF 0x8B58 # 0 +0x8EB0 0x9D2B # 0 +0x8EB1 0x7AFA # 0 +0x8EB2 0x8EF8 # 0 +0x8EB3 0x5B8D # 0 +0x8EB4 0x96EB # 0 +0x8EB5 0x4E03 # 0 +0x8EB6 0x53F1 # 0 +0x8EB7 0x57F7 # 0 +0x8EB8 0x5931 # 0 +0x8EB9 0x5AC9 # 0 +0x8EBA 0x5BA4 # 0 +0x8EBB 0x6089 # 0 +0x8EBC 0x6E7F # 0 +0x8EBD 0x6F06 # 0 +0x8EBE 0x75BE # 0 +0x8EBF 0x8CEA # 0 +0x8EC0 0x5B9F # 0 +0x8EC1 0x8500 # 0 +0x8EC2 0x7BE0 # 0 +0x8EC3 0x5072 # 0 +0x8EC4 0x67F4 # 0 +0x8EC5 0x829D # 0 +0x8EC6 0x5C61 # 0 +0x8EC7 0x854A # 0 +0x8EC8 0x7E1E # 0 +0x8EC9 0x820E # 0 +0x8ECA 0x5199 # 0 +0x8ECB 0x5C04 # 0 +0x8ECC 0x6368 # 0 +0x8ECD 0x8D66 # 0 +0x8ECE 0x659C # 0 +0x8ECF 0x716E # 0 +0x8ED0 0x793E # 0 +0x8ED1 0x7D17 # 0 +0x8ED2 0x8005 # 0 +0x8ED3 0x8B1D # 0 +0x8ED4 0x8ECA # 0 +0x8ED5 0x906E # 0 +0x8ED6 0x86C7 # 0 +0x8ED7 0x90AA # 0 +0x8ED8 0x501F # 0 +0x8ED9 0x52FA # 0 +0x8EDA 0x5C3A # 0 +0x8EDB 0x6753 # 0 +0x8EDC 0x707C # 0 +0x8EDD 0x7235 # 0 +0x8EDE 0x914C # 0 +0x8EDF 0x91C8 # 0 +0x8EE0 0x932B # 0 +0x8EE1 0x82E5 # 0 +0x8EE2 0x5BC2 # 0 +0x8EE3 0x5F31 # 0 +0x8EE4 0x60F9 # 0 +0x8EE5 0x4E3B # 0 +0x8EE6 0x53D6 # 0 +0x8EE7 0x5B88 # 0 +0x8EE8 0x624B # 0 +0x8EE9 0x6731 # 0 +0x8EEA 0x6B8A # 0 +0x8EEB 0x72E9 # 0 +0x8EEC 0x73E0 # 0 +0x8EED 0x7A2E # 0 +0x8EEE 0x816B # 0 +0x8EEF 0x8DA3 # 0 +0x8EF0 0x9152 # 0 +0x8EF1 0x9996 # 0 +0x8EF2 0x5112 # 0 +0x8EF3 0x53D7 # 0 +0x8EF4 0x546A # 0 +0x8EF5 0x5BFF # 0 +0x8EF6 0x6388 # 0 +0x8EF7 0x6A39 # 0 +0x8EF8 0x7DAC # 0 +0x8EF9 0x9700 # 0 +0x8EFA 0x56DA # 0 +0x8EFB 0x53CE # 0 +0x8EFC 0x5468 # 0 +0x8F40 0x5B97 # 0 +0x8F41 0x5C31 # 0 +0x8F42 0x5DDE # 0 +0x8F43 0x4FEE # 0 +0x8F44 0x6101 # 0 +0x8F45 0x62FE # 0 +0x8F46 0x6D32 # 0 +0x8F47 0x79C0 # 0 +0x8F48 0x79CB # 0 +0x8F49 0x7D42 # 0 +0x8F4A 0x7E4D # 0 +0x8F4B 0x7FD2 # 0 +0x8F4C 0x81ED # 0 +0x8F4D 0x821F # 0 +0x8F4E 0x8490 # 0 +0x8F4F 0x8846 # 0 +0x8F50 0x8972 # 0 +0x8F51 0x8B90 # 0 +0x8F52 0x8E74 # 0 +0x8F53 0x8F2F # 0 +0x8F54 0x9031 # 0 +0x8F55 0x914B # 0 +0x8F56 0x916C # 0 +0x8F57 0x96C6 # 0 +0x8F58 0x919C # 0 +0x8F59 0x4EC0 # 0 +0x8F5A 0x4F4F # 0 +0x8F5B 0x5145 # 0 +0x8F5C 0x5341 # 0 +0x8F5D 0x5F93 # 0 +0x8F5E 0x620E # 0 +0x8F5F 0x67D4 # 0 +0x8F60 0x6C41 # 0 +0x8F61 0x6E0B # 0 +0x8F62 0x7363 # 0 +0x8F63 0x7E26 # 0 +0x8F64 0x91CD # 0 +0x8F65 0x9283 # 0 +0x8F66 0x53D4 # 0 +0x8F67 0x5919 # 0 +0x8F68 0x5BBF # 0 +0x8F69 0x6DD1 # 0 +0x8F6A 0x795D # 0 +0x8F6B 0x7E2E # 0 +0x8F6C 0x7C9B # 0 +0x8F6D 0x587E # 0 +0x8F6E 0x719F # 0 +0x8F6F 0x51FA # 0 +0x8F70 0x8853 # 0 +0x8F71 0x8FF0 # 0 +0x8F72 0x4FCA # 0 +0x8F73 0x5CFB # 0 +0x8F74 0x6625 # 0 +0x8F75 0x77AC # 0 +0x8F76 0x7AE3 # 0 +0x8F77 0x821C # 0 +0x8F78 0x99FF # 0 +0x8F79 0x51C6 # 0 +0x8F7A 0x5FAA # 0 +0x8F7B 0x65EC # 0 +0x8F7C 0x696F # 0 +0x8F7D 0x6B89 # 0 +0x8F7E 0x6DF3 # 0 +0x8F80 0x6E96 # 0 +0x8F81 0x6F64 # 0 +0x8F82 0x76FE # 0 +0x8F83 0x7D14 # 0 +0x8F84 0x5DE1 # 0 +0x8F85 0x9075 # 0 +0x8F86 0x9187 # 0 +0x8F87 0x9806 # 0 +0x8F88 0x51E6 # 0 +0x8F89 0x521D # 0 +0x8F8A 0x6240 # 0 +0x8F8B 0x6691 # 0 +0x8F8C 0x66D9 # 0 +0x8F8D 0x6E1A # 0 +0x8F8E 0x5EB6 # 0 +0x8F8F 0x7DD2 # 0 +0x8F90 0x7F72 # 0 +0x8F91 0x66F8 # 0 +0x8F92 0x85AF # 0 +0x8F93 0x85F7 # 0 +0x8F94 0x8AF8 # 0 +0x8F95 0x52A9 # 0 +0x8F96 0x53D9 # 0 +0x8F97 0x5973 # 0 +0x8F98 0x5E8F # 0 +0x8F99 0x5F90 # 0 +0x8F9A 0x6055 # 0 +0x8F9B 0x92E4 # 0 +0x8F9C 0x9664 # 0 +0x8F9D 0x50B7 # 0 +0x8F9E 0x511F # 0 +0x8F9F 0x52DD # 0 +0x8FA0 0x5320 # 0 +0x8FA1 0x5347 # 0 +0x8FA2 0x53EC # 0 +0x8FA3 0x54E8 # 0 +0x8FA4 0x5546 # 0 +0x8FA5 0x5531 # 0 +0x8FA6 0x5617 # 0 +0x8FA7 0x5968 # 0 +0x8FA8 0x59BE # 0 +0x8FA9 0x5A3C # 0 +0x8FAA 0x5BB5 # 0 +0x8FAB 0x5C06 # 0 +0x8FAC 0x5C0F # 0 +0x8FAD 0x5C11 # 0 +0x8FAE 0x5C1A # 0 +0x8FAF 0x5E84 # 0 +0x8FB0 0x5E8A # 0 +0x8FB1 0x5EE0 # 0 +0x8FB2 0x5F70 # 0 +0x8FB3 0x627F # 0 +0x8FB4 0x6284 # 0 +0x8FB5 0x62DB # 0 +0x8FB6 0x638C # 0 +0x8FB7 0x6377 # 0 +0x8FB8 0x6607 # 0 +0x8FB9 0x660C # 0 +0x8FBA 0x662D # 0 +0x8FBB 0x6676 # 0 +0x8FBC 0x677E # 0 +0x8FBD 0x68A2 # 0 +0x8FBE 0x6A1F # 0 +0x8FBF 0x6A35 # 0 +0x8FC0 0x6CBC # 0 +0x8FC1 0x6D88 # 0 +0x8FC2 0x6E09 # 0 +0x8FC3 0x6E58 # 0 +0x8FC4 0x713C # 0 +0x8FC5 0x7126 # 0 +0x8FC6 0x7167 # 0 +0x8FC7 0x75C7 # 0 +0x8FC8 0x7701 # 0 +0x8FC9 0x785D # 0 +0x8FCA 0x7901 # 0 +0x8FCB 0x7965 # 0 +0x8FCC 0x79F0 # 0 +0x8FCD 0x7AE0 # 0 +0x8FCE 0x7B11 # 0 +0x8FCF 0x7CA7 # 0 +0x8FD0 0x7D39 # 0 +0x8FD1 0x8096 # 0 +0x8FD2 0x83D6 # 0 +0x8FD3 0x848B # 0 +0x8FD4 0x8549 # 0 +0x8FD5 0x885D # 0 +0x8FD6 0x88F3 # 0 +0x8FD7 0x8A1F # 0 +0x8FD8 0x8A3C # 0 +0x8FD9 0x8A54 # 0 +0x8FDA 0x8A73 # 0 +0x8FDB 0x8C61 # 0 +0x8FDC 0x8CDE # 0 +0x8FDD 0x91A4 # 0 +0x8FDE 0x9266 # 0 +0x8FDF 0x937E # 0 +0x8FE0 0x9418 # 0 +0x8FE1 0x969C # 0 +0x8FE2 0x9798 # 0 +0x8FE3 0x4E0A # 0 +0x8FE4 0x4E08 # 0 +0x8FE5 0x4E1E # 0 +0x8FE6 0x4E57 # 0 +0x8FE7 0x5197 # 0 +0x8FE8 0x5270 # 0 +0x8FE9 0x57CE # 0 +0x8FEA 0x5834 # 0 +0x8FEB 0x58CC # 0 +0x8FEC 0x5B22 # 0 +0x8FED 0x5E38 # 0 +0x8FEE 0x60C5 # 0 +0x8FEF 0x64FE # 0 +0x8FF0 0x6761 # 0 +0x8FF1 0x6756 # 0 +0x8FF2 0x6D44 # 0 +0x8FF3 0x72B6 # 0 +0x8FF4 0x7573 # 0 +0x8FF5 0x7A63 # 0 +0x8FF6 0x84B8 # 0 +0x8FF7 0x8B72 # 0 +0x8FF8 0x91B8 # 0 +0x8FF9 0x9320 # 0 +0x8FFA 0x5631 # 0 +0x8FFB 0x57F4 # 0 +0x8FFC 0x98FE # 0 +0x9040 0x62ED # 0 +0x9041 0x690D # 0 +0x9042 0x6B96 # 0 +0x9043 0x71ED # 0 +0x9044 0x7E54 # 0 +0x9045 0x8077 # 0 +0x9046 0x8272 # 0 +0x9047 0x89E6 # 0 +0x9048 0x98DF # 0 +0x9049 0x8755 # 0 +0x904A 0x8FB1 # 0 +0x904B 0x5C3B # 0 +0x904C 0x4F38 # 0 +0x904D 0x4FE1 # 0 +0x904E 0x4FB5 # 0 +0x904F 0x5507 # 0 +0x9050 0x5A20 # 0 +0x9051 0x5BDD # 0 +0x9052 0x5BE9 # 0 +0x9053 0x5FC3 # 0 +0x9054 0x614E # 0 +0x9055 0x632F # 0 +0x9056 0x65B0 # 0 +0x9057 0x664B # 0 +0x9058 0x68EE # 0 +0x9059 0x699B # 0 +0x905A 0x6D78 # 0 +0x905B 0x6DF1 # 0 +0x905C 0x7533 # 0 +0x905D 0x75B9 # 0 +0x905E 0x771F # 0 +0x905F 0x795E # 0 +0x9060 0x79E6 # 0 +0x9061 0x7D33 # 0 +0x9062 0x81E3 # 0 +0x9063 0x82AF # 0 +0x9064 0x85AA # 0 +0x9065 0x89AA # 0 +0x9066 0x8A3A # 0 +0x9067 0x8EAB # 0 +0x9068 0x8F9B # 0 +0x9069 0x9032 # 0 +0x906A 0x91DD # 0 +0x906B 0x9707 # 0 +0x906C 0x4EBA # 0 +0x906D 0x4EC1 # 0 +0x906E 0x5203 # 0 +0x906F 0x5875 # 0 +0x9070 0x58EC # 0 +0x9071 0x5C0B # 0 +0x9072 0x751A # 0 +0x9073 0x5C3D # 0 +0x9074 0x814E # 0 +0x9075 0x8A0A # 0 +0x9076 0x8FC5 # 0 +0x9077 0x9663 # 0 +0x9078 0x976D # 0 +0x9079 0x7B25 # 0 +0x907A 0x8ACF # 0 +0x907B 0x9808 # 0 +0x907C 0x9162 # 0 +0x907D 0x56F3 # 0 +0x907E 0x53A8 # 0 +0x9080 0x9017 # 0 +0x9081 0x5439 # 0 +0x9082 0x5782 # 0 +0x9083 0x5E25 # 0 +0x9084 0x63A8 # 0 +0x9085 0x6C34 # 0 +0x9086 0x708A # 0 +0x9087 0x7761 # 0 +0x9088 0x7C8B # 0 +0x9089 0x7FE0 # 0 +0x908A 0x8870 # 0 +0x908B 0x9042 # 0 +0x908C 0x9154 # 0 +0x908D 0x9310 # 0 +0x908E 0x9318 # 0 +0x908F 0x968F # 0 +0x9090 0x745E # 0 +0x9091 0x9AC4 # 0 +0x9092 0x5D07 # 0 +0x9093 0x5D69 # 0 +0x9094 0x6570 # 0 +0x9095 0x67A2 # 0 +0x9096 0x8DA8 # 0 +0x9097 0x96DB # 0 +0x9098 0x636E # 0 +0x9099 0x6749 # 0 +0x909A 0x6919 # 0 +0x909B 0x83C5 # 0 +0x909C 0x9817 # 0 +0x909D 0x96C0 # 0 +0x909E 0x88FE # 0 +0x909F 0x6F84 # 0 +0x90A0 0x647A # 0 +0x90A1 0x5BF8 # 0 +0x90A2 0x4E16 # 0 +0x90A3 0x702C # 0 +0x90A4 0x755D # 0 +0x90A5 0x662F # 0 +0x90A6 0x51C4 # 0 +0x90A7 0x5236 # 0 +0x90A8 0x52E2 # 0 +0x90A9 0x59D3 # 0 +0x90AA 0x5F81 # 0 +0x90AB 0x6027 # 0 +0x90AC 0x6210 # 0 +0x90AD 0x653F # 0 +0x90AE 0x6574 # 0 +0x90AF 0x661F # 0 +0x90B0 0x6674 # 0 +0x90B1 0x68F2 # 0 +0x90B2 0x6816 # 0 +0x90B3 0x6B63 # 0 +0x90B4 0x6E05 # 0 +0x90B5 0x7272 # 0 +0x90B6 0x751F # 0 +0x90B7 0x76DB # 0 +0x90B8 0x7CBE # 0 +0x90B9 0x8056 # 0 +0x90BA 0x58F0 # 0 +0x90BB 0x88FD # 0 +0x90BC 0x897F # 0 +0x90BD 0x8AA0 # 0 +0x90BE 0x8A93 # 0 +0x90BF 0x8ACB # 0 +0x90C0 0x901D # 0 +0x90C1 0x9192 # 0 +0x90C2 0x9752 # 0 +0x90C3 0x9759 # 0 +0x90C4 0x6589 # 0 +0x90C5 0x7A0E # 0 +0x90C6 0x8106 # 0 +0x90C7 0x96BB # 0 +0x90C8 0x5E2D # 0 +0x90C9 0x60DC # 0 +0x90CA 0x621A # 0 +0x90CB 0x65A5 # 0 +0x90CC 0x6614 # 0 +0x90CD 0x6790 # 0 +0x90CE 0x77F3 # 0 +0x90CF 0x7A4D # 0 +0x90D0 0x7C4D # 0 +0x90D1 0x7E3E # 0 +0x90D2 0x810A # 0 +0x90D3 0x8CAC # 0 +0x90D4 0x8D64 # 0 +0x90D5 0x8DE1 # 0 +0x90D6 0x8E5F # 0 +0x90D7 0x78A9 # 0 +0x90D8 0x5207 # 0 +0x90D9 0x62D9 # 0 +0x90DA 0x63A5 # 0 +0x90DB 0x6442 # 0 +0x90DC 0x6298 # 0 +0x90DD 0x8A2D # 0 +0x90DE 0x7A83 # 0 +0x90DF 0x7BC0 # 0 +0x90E0 0x8AAC # 0 +0x90E1 0x96EA # 0 +0x90E2 0x7D76 # 0 +0x90E3 0x820C # 0 +0x90E4 0x8749 # 0 +0x90E5 0x4ED9 # 0 +0x90E6 0x5148 # 0 +0x90E7 0x5343 # 0 +0x90E8 0x5360 # 0 +0x90E9 0x5BA3 # 0 +0x90EA 0x5C02 # 0 +0x90EB 0x5C16 # 0 +0x90EC 0x5DDD # 0 +0x90ED 0x6226 # 0 +0x90EE 0x6247 # 0 +0x90EF 0x64B0 # 0 +0x90F0 0x6813 # 0 +0x90F1 0x6834 # 0 +0x90F2 0x6CC9 # 0 +0x90F3 0x6D45 # 0 +0x90F4 0x6D17 # 0 +0x90F5 0x67D3 # 0 +0x90F6 0x6F5C # 0 +0x90F7 0x714E # 0 +0x90F8 0x717D # 0 +0x90F9 0x65CB # 0 +0x90FA 0x7A7F # 0 +0x90FB 0x7BAD # 0 +0x90FC 0x7DDA # 0 +0x9140 0x7E4A # 0 +0x9141 0x7FA8 # 0 +0x9142 0x817A # 0 +0x9143 0x821B # 0 +0x9144 0x8239 # 0 +0x9145 0x85A6 # 0 +0x9146 0x8A6E # 0 +0x9147 0x8CCE # 0 +0x9148 0x8DF5 # 0 +0x9149 0x9078 # 0 +0x914A 0x9077 # 0 +0x914B 0x92AD # 0 +0x914C 0x9291 # 0 +0x914D 0x9583 # 0 +0x914E 0x9BAE # 0 +0x914F 0x524D # 0 +0x9150 0x5584 # 0 +0x9151 0x6F38 # 0 +0x9152 0x7136 # 0 +0x9153 0x5168 # 0 +0x9154 0x7985 # 0 +0x9155 0x7E55 # 0 +0x9156 0x81B3 # 0 +0x9157 0x7CCE # 0 +0x9158 0x564C # 0 +0x9159 0x5851 # 0 +0x915A 0x5CA8 # 0 +0x915B 0x63AA # 0 +0x915C 0x66FE # 0 +0x915D 0x66FD # 0 +0x915E 0x695A # 0 +0x915F 0x72D9 # 0 +0x9160 0x758F # 0 +0x9161 0x758E # 0 +0x9162 0x790E # 0 +0x9163 0x7956 # 0 +0x9164 0x79DF # 0 +0x9165 0x7C97 # 0 +0x9166 0x7D20 # 0 +0x9167 0x7D44 # 0 +0x9168 0x8607 # 0 +0x9169 0x8A34 # 0 +0x916A 0x963B # 0 +0x916B 0x9061 # 0 +0x916C 0x9F20 # 0 +0x916D 0x50E7 # 0 +0x916E 0x5275 # 0 +0x916F 0x53CC # 0 +0x9170 0x53E2 # 0 +0x9171 0x5009 # 0 +0x9172 0x55AA # 0 +0x9173 0x58EE # 0 +0x9174 0x594F # 0 +0x9175 0x723D # 0 +0x9176 0x5B8B # 0 +0x9177 0x5C64 # 0 +0x9178 0x531D # 0 +0x9179 0x60E3 # 0 +0x917A 0x60F3 # 0 +0x917B 0x635C # 0 +0x917C 0x6383 # 0 +0x917D 0x633F # 0 +0x917E 0x63BB # 0 +0x9180 0x64CD # 0 +0x9181 0x65E9 # 0 +0x9182 0x66F9 # 0 +0x9183 0x5DE3 # 0 +0x9184 0x69CD # 0 +0x9185 0x69FD # 0 +0x9186 0x6F15 # 0 +0x9187 0x71E5 # 0 +0x9188 0x4E89 # 0 +0x9189 0x75E9 # 0 +0x918A 0x76F8 # 0 +0x918B 0x7A93 # 0 +0x918C 0x7CDF # 0 +0x918D 0x7DCF # 0 +0x918E 0x7D9C # 0 +0x918F 0x8061 # 0 +0x9190 0x8349 # 0 +0x9191 0x8358 # 0 +0x9192 0x846C # 0 +0x9193 0x84BC # 0 +0x9194 0x85FB # 0 +0x9195 0x88C5 # 0 +0x9196 0x8D70 # 0 +0x9197 0x9001 # 0 +0x9198 0x906D # 0 +0x9199 0x9397 # 0 +0x919A 0x971C # 0 +0x919B 0x9A12 # 0 +0x919C 0x50CF # 0 +0x919D 0x5897 # 0 +0x919E 0x618E # 0 +0x919F 0x81D3 # 0 +0x91A0 0x8535 # 0 +0x91A1 0x8D08 # 0 +0x91A2 0x9020 # 0 +0x91A3 0x4FC3 # 0 +0x91A4 0x5074 # 0 +0x91A5 0x5247 # 0 +0x91A6 0x5373 # 0 +0x91A7 0x606F # 0 +0x91A8 0x6349 # 0 +0x91A9 0x675F # 0 +0x91AA 0x6E2C # 0 +0x91AB 0x8DB3 # 0 +0x91AC 0x901F # 0 +0x91AD 0x4FD7 # 0 +0x91AE 0x5C5E # 0 +0x91AF 0x8CCA # 0 +0x91B0 0x65CF # 0 +0x91B1 0x7D9A # 0 +0x91B2 0x5352 # 0 +0x91B3 0x8896 # 0 +0x91B4 0x5176 # 0 +0x91B5 0x63C3 # 0 +0x91B6 0x5B58 # 0 +0x91B7 0x5B6B # 0 +0x91B8 0x5C0A # 0 +0x91B9 0x640D # 0 +0x91BA 0x6751 # 0 +0x91BB 0x905C # 0 +0x91BC 0x4ED6 # 0 +0x91BD 0x591A # 0 +0x91BE 0x592A # 0 +0x91BF 0x6C70 # 0 +0x91C0 0x8A51 # 0 +0x91C1 0x553E # 0 +0x91C2 0x5815 # 0 +0x91C3 0x59A5 # 0 +0x91C4 0x60F0 # 0 +0x91C5 0x6253 # 0 +0x91C6 0x67C1 # 0 +0x91C7 0x8235 # 0 +0x91C8 0x6955 # 0 +0x91C9 0x9640 # 0 +0x91CA 0x99C4 # 0 +0x91CB 0x9A28 # 0 +0x91CC 0x4F53 # 0 +0x91CD 0x5806 # 0 +0x91CE 0x5BFE # 0 +0x91CF 0x8010 # 0 +0x91D0 0x5CB1 # 0 +0x91D1 0x5E2F # 0 +0x91D2 0x5F85 # 0 +0x91D3 0x6020 # 0 +0x91D4 0x614B # 0 +0x91D5 0x6234 # 0 +0x91D6 0x66FF # 0 +0x91D7 0x6CF0 # 0 +0x91D8 0x6EDE # 0 +0x91D9 0x80CE # 0 +0x91DA 0x817F # 0 +0x91DB 0x82D4 # 0 +0x91DC 0x888B # 0 +0x91DD 0x8CB8 # 0 +0x91DE 0x9000 # 0 +0x91DF 0x902E # 0 +0x91E0 0x968A # 0 +0x91E1 0x9EDB # 0 +0x91E2 0x9BDB # 0 +0x91E3 0x4EE3 # 0 +0x91E4 0x53F0 # 0 +0x91E5 0x5927 # 0 +0x91E6 0x7B2C # 0 +0x91E7 0x918D # 0 +0x91E8 0x984C # 0 +0x91E9 0x9DF9 # 0 +0x91EA 0x6EDD # 0 +0x91EB 0x7027 # 0 +0x91EC 0x5353 # 0 +0x91ED 0x5544 # 0 +0x91EE 0x5B85 # 0 +0x91EF 0x6258 # 0 +0x91F0 0x629E # 0 +0x91F1 0x62D3 # 0 +0x91F2 0x6CA2 # 0 +0x91F3 0x6FEF # 0 +0x91F4 0x7422 # 0 +0x91F5 0x8A17 # 0 +0x91F6 0x9438 # 0 +0x91F7 0x6FC1 # 0 +0x91F8 0x8AFE # 0 +0x91F9 0x8338 # 0 +0x91FA 0x51E7 # 0 +0x91FB 0x86F8 # 0 +0x91FC 0x53EA # 0 +0x9240 0x53E9 # 0 +0x9241 0x4F46 # 0 +0x9242 0x9054 # 0 +0x9243 0x8FB0 # 0 +0x9244 0x596A # 0 +0x9245 0x8131 # 0 +0x9246 0x5DFD # 0 +0x9247 0x7AEA # 0 +0x9248 0x8FBF # 0 +0x9249 0x68DA # 0 +0x924A 0x8C37 # 0 +0x924B 0x72F8 # 0 +0x924C 0x9C48 # 0 +0x924D 0x6A3D # 0 +0x924E 0x8AB0 # 0 +0x924F 0x4E39 # 0 +0x9250 0x5358 # 0 +0x9251 0x5606 # 0 +0x9252 0x5766 # 0 +0x9253 0x62C5 # 0 +0x9254 0x63A2 # 0 +0x9255 0x65E6 # 0 +0x9256 0x6B4E # 0 +0x9257 0x6DE1 # 0 +0x9258 0x6E5B # 0 +0x9259 0x70AD # 0 +0x925A 0x77ED # 0 +0x925B 0x7AEF # 0 +0x925C 0x7BAA # 0 +0x925D 0x7DBB # 0 +0x925E 0x803D # 0 +0x925F 0x80C6 # 0 +0x9260 0x86CB # 0 +0x9261 0x8A95 # 0 +0x9262 0x935B # 0 +0x9263 0x56E3 # 0 +0x9264 0x58C7 # 0 +0x9265 0x5F3E # 0 +0x9266 0x65AD # 0 +0x9267 0x6696 # 0 +0x9268 0x6A80 # 0 +0x9269 0x6BB5 # 0 +0x926A 0x7537 # 0 +0x926B 0x8AC7 # 0 +0x926C 0x5024 # 0 +0x926D 0x77E5 # 0 +0x926E 0x5730 # 0 +0x926F 0x5F1B # 0 +0x9270 0x6065 # 0 +0x9271 0x667A # 0 +0x9272 0x6C60 # 0 +0x9273 0x75F4 # 0 +0x9274 0x7A1A # 0 +0x9275 0x7F6E # 0 +0x9276 0x81F4 # 0 +0x9277 0x8718 # 0 +0x9278 0x9045 # 0 +0x9279 0x99B3 # 0 +0x927A 0x7BC9 # 0 +0x927B 0x755C # 0 +0x927C 0x7AF9 # 0 +0x927D 0x7B51 # 0 +0x927E 0x84C4 # 0 +0x9280 0x9010 # 0 +0x9281 0x79E9 # 0 +0x9282 0x7A92 # 0 +0x9283 0x8336 # 0 +0x9284 0x5AE1 # 0 +0x9285 0x7740 # 0 +0x9286 0x4E2D # 0 +0x9287 0x4EF2 # 0 +0x9288 0x5B99 # 0 +0x9289 0x5FE0 # 0 +0x928A 0x62BD # 0 +0x928B 0x663C # 0 +0x928C 0x67F1 # 0 +0x928D 0x6CE8 # 0 +0x928E 0x866B # 0 +0x928F 0x8877 # 0 +0x9290 0x8A3B # 0 +0x9291 0x914E # 0 +0x9292 0x92F3 # 0 +0x9293 0x99D0 # 0 +0x9294 0x6A17 # 0 +0x9295 0x7026 # 0 +0x9296 0x732A # 0 +0x9297 0x82E7 # 0 +0x9298 0x8457 # 0 +0x9299 0x8CAF # 0 +0x929A 0x4E01 # 0 +0x929B 0x5146 # 0 +0x929C 0x51CB # 0 +0x929D 0x558B # 0 +0x929E 0x5BF5 # 0 +0x929F 0x5E16 # 0 +0x92A0 0x5E33 # 0 +0x92A1 0x5E81 # 0 +0x92A2 0x5F14 # 0 +0x92A3 0x5F35 # 0 +0x92A4 0x5F6B # 0 +0x92A5 0x5FB4 # 0 +0x92A6 0x61F2 # 0 +0x92A7 0x6311 # 0 +0x92A8 0x66A2 # 0 +0x92A9 0x671D # 0 +0x92AA 0x6F6E # 0 +0x92AB 0x7252 # 0 +0x92AC 0x753A # 0 +0x92AD 0x773A # 0 +0x92AE 0x8074 # 0 +0x92AF 0x8139 # 0 +0x92B0 0x8178 # 0 +0x92B1 0x8776 # 0 +0x92B2 0x8ABF # 0 +0x92B3 0x8ADC # 0 +0x92B4 0x8D85 # 0 +0x92B5 0x8DF3 # 0 +0x92B6 0x929A # 0 +0x92B7 0x9577 # 0 +0x92B8 0x9802 # 0 +0x92B9 0x9CE5 # 0 +0x92BA 0x52C5 # 0 +0x92BB 0x6357 # 0 +0x92BC 0x76F4 # 0 +0x92BD 0x6715 # 0 +0x92BE 0x6C88 # 0 +0x92BF 0x73CD # 0 +0x92C0 0x8CC3 # 0 +0x92C1 0x93AE # 0 +0x92C2 0x9673 # 0 +0x92C3 0x6D25 # 0 +0x92C4 0x589C # 0 +0x92C5 0x690E # 0 +0x92C6 0x69CC # 0 +0x92C7 0x8FFD # 0 +0x92C8 0x939A # 0 +0x92C9 0x75DB # 0 +0x92CA 0x901A # 0 +0x92CB 0x585A # 0 +0x92CC 0x6802 # 0 +0x92CD 0x63B4 # 0 +0x92CE 0x69FB # 0 +0x92CF 0x4F43 # 0 +0x92D0 0x6F2C # 0 +0x92D1 0x67D8 # 0 +0x92D2 0x8FBB # 0 +0x92D3 0x8526 # 0 +0x92D4 0x7DB4 # 0 +0x92D5 0x9354 # 0 +0x92D6 0x693F # 0 +0x92D7 0x6F70 # 0 +0x92D8 0x576A # 0 +0x92D9 0x58F7 # 0 +0x92DA 0x5B2C # 0 +0x92DB 0x7D2C # 0 +0x92DC 0x722A # 0 +0x92DD 0x540A # 0 +0x92DE 0x91E3 # 0 +0x92DF 0x9DB4 # 0 +0x92E0 0x4EAD # 0 +0x92E1 0x4F4E # 0 +0x92E2 0x505C # 0 +0x92E3 0x5075 # 0 +0x92E4 0x5243 # 0 +0x92E5 0x8C9E # 0 +0x92E6 0x5448 # 0 +0x92E7 0x5824 # 0 +0x92E8 0x5B9A # 0 +0x92E9 0x5E1D # 0 +0x92EA 0x5E95 # 0 +0x92EB 0x5EAD # 0 +0x92EC 0x5EF7 # 0 +0x92ED 0x5F1F # 0 +0x92EE 0x608C # 0 +0x92EF 0x62B5 # 0 +0x92F0 0x633A # 0 +0x92F1 0x63D0 # 0 +0x92F2 0x68AF # 0 +0x92F3 0x6C40 # 0 +0x92F4 0x7887 # 0 +0x92F5 0x798E # 0 +0x92F6 0x7A0B # 0 +0x92F7 0x7DE0 # 0 +0x92F8 0x8247 # 0 +0x92F9 0x8A02 # 0 +0x92FA 0x8AE6 # 0 +0x92FB 0x8E44 # 0 +0x92FC 0x9013 # 0 +0x9340 0x90B8 # 0 +0x9341 0x912D # 0 +0x9342 0x91D8 # 0 +0x9343 0x9F0E # 0 +0x9344 0x6CE5 # 0 +0x9345 0x6458 # 0 +0x9346 0x64E2 # 0 +0x9347 0x6575 # 0 +0x9348 0x6EF4 # 0 +0x9349 0x7684 # 0 +0x934A 0x7B1B # 0 +0x934B 0x9069 # 0 +0x934C 0x93D1 # 0 +0x934D 0x6EBA # 0 +0x934E 0x54F2 # 0 +0x934F 0x5FB9 # 0 +0x9350 0x64A4 # 0 +0x9351 0x8F4D # 0 +0x9352 0x8FED # 0 +0x9353 0x9244 # 0 +0x9354 0x5178 # 0 +0x9355 0x586B # 0 +0x9356 0x5929 # 0 +0x9357 0x5C55 # 0 +0x9358 0x5E97 # 0 +0x9359 0x6DFB # 0 +0x935A 0x7E8F # 0 +0x935B 0x751C # 0 +0x935C 0x8CBC # 0 +0x935D 0x8EE2 # 0 +0x935E 0x985B # 0 +0x935F 0x70B9 # 0 +0x9360 0x4F1D # 0 +0x9361 0x6BBF # 0 +0x9362 0x6FB1 # 0 +0x9363 0x7530 # 0 +0x9364 0x96FB # 0 +0x9365 0x514E # 0 +0x9366 0x5410 # 0 +0x9367 0x5835 # 0 +0x9368 0x5857 # 0 +0x9369 0x59AC # 0 +0x936A 0x5C60 # 0 +0x936B 0x5F92 # 0 +0x936C 0x6597 # 0 +0x936D 0x675C # 0 +0x936E 0x6E21 # 0 +0x936F 0x767B # 0 +0x9370 0x83DF # 0 +0x9371 0x8CED # 0 +0x9372 0x9014 # 0 +0x9373 0x90FD # 0 +0x9374 0x934D # 0 +0x9375 0x7825 # 0 +0x9376 0x783A # 0 +0x9377 0x52AA # 0 +0x9378 0x5EA6 # 0 +0x9379 0x571F # 0 +0x937A 0x5974 # 0 +0x937B 0x6012 # 0 +0x937C 0x5012 # 0 +0x937D 0x515A # 0 +0x937E 0x51AC # 0 +0x9380 0x51CD # 0 +0x9381 0x5200 # 0 +0x9382 0x5510 # 0 +0x9383 0x5854 # 0 +0x9384 0x5858 # 0 +0x9385 0x5957 # 0 +0x9386 0x5B95 # 0 +0x9387 0x5CF6 # 0 +0x9388 0x5D8B # 0 +0x9389 0x60BC # 0 +0x938A 0x6295 # 0 +0x938B 0x642D # 0 +0x938C 0x6771 # 0 +0x938D 0x6843 # 0 +0x938E 0x68BC # 0 +0x938F 0x68DF # 0 +0x9390 0x76D7 # 0 +0x9391 0x6DD8 # 0 +0x9392 0x6E6F # 0 +0x9393 0x6D9B # 0 +0x9394 0x706F # 0 +0x9395 0x71C8 # 0 +0x9396 0x5F53 # 0 +0x9397 0x75D8 # 0 +0x9398 0x7977 # 0 +0x9399 0x7B49 # 0 +0x939A 0x7B54 # 0 +0x939B 0x7B52 # 0 +0x939C 0x7CD6 # 0 +0x939D 0x7D71 # 0 +0x939E 0x5230 # 0 +0x939F 0x8463 # 0 +0x93A0 0x8569 # 0 +0x93A1 0x85E4 # 0 +0x93A2 0x8A0E # 0 +0x93A3 0x8B04 # 0 +0x93A4 0x8C46 # 0 +0x93A5 0x8E0F # 0 +0x93A6 0x9003 # 0 +0x93A7 0x900F # 0 +0x93A8 0x9419 # 0 +0x93A9 0x9676 # 0 +0x93AA 0x982D # 0 +0x93AB 0x9A30 # 0 +0x93AC 0x95D8 # 0 +0x93AD 0x50CD # 0 +0x93AE 0x52D5 # 0 +0x93AF 0x540C # 0 +0x93B0 0x5802 # 0 +0x93B1 0x5C0E # 0 +0x93B2 0x61A7 # 0 +0x93B3 0x649E # 0 +0x93B4 0x6D1E # 0 +0x93B5 0x77B3 # 0 +0x93B6 0x7AE5 # 0 +0x93B7 0x80F4 # 0 +0x93B8 0x8404 # 0 +0x93B9 0x9053 # 0 +0x93BA 0x9285 # 0 +0x93BB 0x5CE0 # 0 +0x93BC 0x9D07 # 0 +0x93BD 0x533F # 0 +0x93BE 0x5F97 # 0 +0x93BF 0x5FB3 # 0 +0x93C0 0x6D9C # 0 +0x93C1 0x7279 # 0 +0x93C2 0x7763 # 0 +0x93C3 0x79BF # 0 +0x93C4 0x7BE4 # 0 +0x93C5 0x6BD2 # 0 +0x93C6 0x72EC # 0 +0x93C7 0x8AAD # 0 +0x93C8 0x6803 # 0 +0x93C9 0x6A61 # 0 +0x93CA 0x51F8 # 0 +0x93CB 0x7A81 # 0 +0x93CC 0x6934 # 0 +0x93CD 0x5C4A # 0 +0x93CE 0x9CF6 # 0 +0x93CF 0x82EB # 0 +0x93D0 0x5BC5 # 0 +0x93D1 0x9149 # 0 +0x93D2 0x701E # 0 +0x93D3 0x5678 # 0 +0x93D4 0x5C6F # 0 +0x93D5 0x60C7 # 0 +0x93D6 0x6566 # 0 +0x93D7 0x6C8C # 0 +0x93D8 0x8C5A # 0 +0x93D9 0x9041 # 0 +0x93DA 0x9813 # 0 +0x93DB 0x5451 # 0 +0x93DC 0x66C7 # 0 +0x93DD 0x920D # 0 +0x93DE 0x5948 # 0 +0x93DF 0x90A3 # 0 +0x93E0 0x5185 # 0 +0x93E1 0x4E4D # 0 +0x93E2 0x51EA # 0 +0x93E3 0x8599 # 0 +0x93E4 0x8B0E # 0 +0x93E5 0x7058 # 0 +0x93E6 0x637A # 0 +0x93E7 0x934B # 0 +0x93E8 0x6962 # 0 +0x93E9 0x99B4 # 0 +0x93EA 0x7E04 # 0 +0x93EB 0x7577 # 0 +0x93EC 0x5357 # 0 +0x93ED 0x6960 # 0 +0x93EE 0x8EDF # 0 +0x93EF 0x96E3 # 0 +0x93F0 0x6C5D # 0 +0x93F1 0x4E8C # 0 +0x93F2 0x5C3C # 0 +0x93F3 0x5F10 # 0 +0x93F4 0x8FE9 # 0 +0x93F5 0x5302 # 0 +0x93F6 0x8CD1 # 0 +0x93F7 0x8089 # 0 +0x93F8 0x8679 # 0 +0x93F9 0x5EFF # 0 +0x93FA 0x65E5 # 0 +0x93FB 0x4E73 # 0 +0x93FC 0x5165 # 0 +0x9440 0x5982 # 0 +0x9441 0x5C3F # 0 +0x9442 0x97EE # 0 +0x9443 0x4EFB # 0 +0x9444 0x598A # 0 +0x9445 0x5FCD # 0 +0x9446 0x8A8D # 0 +0x9447 0x6FE1 # 0 +0x9448 0x79B0 # 0 +0x9449 0x7962 # 0 +0x944A 0x5BE7 # 0 +0x944B 0x8471 # 0 +0x944C 0x732B # 0 +0x944D 0x71B1 # 0 +0x944E 0x5E74 # 0 +0x944F 0x5FF5 # 0 +0x9450 0x637B # 0 +0x9451 0x649A # 0 +0x9452 0x71C3 # 0 +0x9453 0x7C98 # 0 +0x9454 0x4E43 # 0 +0x9455 0x5EFC # 0 +0x9456 0x4E4B # 0 +0x9457 0x57DC # 0 +0x9458 0x56A2 # 0 +0x9459 0x60A9 # 0 +0x945A 0x6FC3 # 0 +0x945B 0x7D0D # 0 +0x945C 0x80FD # 0 +0x945D 0x8133 # 0 +0x945E 0x81BF # 0 +0x945F 0x8FB2 # 0 +0x9460 0x8997 # 0 +0x9461 0x86A4 # 0 +0x9462 0x5DF4 # 0 +0x9463 0x628A # 0 +0x9464 0x64AD # 0 +0x9465 0x8987 # 0 +0x9466 0x6777 # 0 +0x9467 0x6CE2 # 0 +0x9468 0x6D3E # 0 +0x9469 0x7436 # 0 +0x946A 0x7834 # 0 +0x946B 0x5A46 # 0 +0x946C 0x7F75 # 0 +0x946D 0x82AD # 0 +0x946E 0x99AC # 0 +0x946F 0x4FF3 # 0 +0x9470 0x5EC3 # 0 +0x9471 0x62DD # 0 +0x9472 0x6392 # 0 +0x9473 0x6557 # 0 +0x9474 0x676F # 0 +0x9475 0x76C3 # 0 +0x9476 0x724C # 0 +0x9477 0x80CC # 0 +0x9478 0x80BA # 0 +0x9479 0x8F29 # 0 +0x947A 0x914D # 0 +0x947B 0x500D # 0 +0x947C 0x57F9 # 0 +0x947D 0x5A92 # 0 +0x947E 0x6885 # 0 +0x9480 0x6973 # 0 +0x9481 0x7164 # 0 +0x9482 0x72FD # 0 +0x9483 0x8CB7 # 0 +0x9484 0x58F2 # 0 +0x9485 0x8CE0 # 0 +0x9486 0x966A # 0 +0x9487 0x9019 # 0 +0x9488 0x877F # 0 +0x9489 0x79E4 # 0 +0x948A 0x77E7 # 0 +0x948B 0x8429 # 0 +0x948C 0x4F2F # 0 +0x948D 0x5265 # 0 +0x948E 0x535A # 0 +0x948F 0x62CD # 0 +0x9490 0x67CF # 0 +0x9491 0x6CCA # 0 +0x9492 0x767D # 0 +0x9493 0x7B94 # 0 +0x9494 0x7C95 # 0 +0x9495 0x8236 # 0 +0x9496 0x8584 # 0 +0x9497 0x8FEB # 0 +0x9498 0x66DD # 0 +0x9499 0x6F20 # 0 +0x949A 0x7206 # 0 +0x949B 0x7E1B # 0 +0x949C 0x83AB # 0 +0x949D 0x99C1 # 0 +0x949E 0x9EA6 # 0 +0x949F 0x51FD # 0 +0x94A0 0x7BB1 # 0 +0x94A1 0x7872 # 0 +0x94A2 0x7BB8 # 0 +0x94A3 0x8087 # 0 +0x94A4 0x7B48 # 0 +0x94A5 0x6AE8 # 0 +0x94A6 0x5E61 # 0 +0x94A7 0x808C # 0 +0x94A8 0x7551 # 0 +0x94A9 0x7560 # 0 +0x94AA 0x516B # 0 +0x94AB 0x9262 # 0 +0x94AC 0x6E8C # 0 +0x94AD 0x767A # 0 +0x94AE 0x9197 # 0 +0x94AF 0x9AEA # 0 +0x94B0 0x4F10 # 0 +0x94B1 0x7F70 # 0 +0x94B2 0x629C # 0 +0x94B3 0x7B4F # 0 +0x94B4 0x95A5 # 0 +0x94B5 0x9CE9 # 0 +0x94B6 0x567A # 0 +0x94B7 0x5859 # 0 +0x94B8 0x86E4 # 0 +0x94B9 0x96BC # 0 +0x94BA 0x4F34 # 0 +0x94BB 0x5224 # 0 +0x94BC 0x534A # 0 +0x94BD 0x53CD # 0 +0x94BE 0x53DB # 0 +0x94BF 0x5E06 # 0 +0x94C0 0x642C # 0 +0x94C1 0x6591 # 0 +0x94C2 0x677F # 0 +0x94C3 0x6C3E # 0 +0x94C4 0x6C4E # 0 +0x94C5 0x7248 # 0 +0x94C6 0x72AF # 0 +0x94C7 0x73ED # 0 +0x94C8 0x7554 # 0 +0x94C9 0x7E41 # 0 +0x94CA 0x822C # 0 +0x94CB 0x85E9 # 0 +0x94CC 0x8CA9 # 0 +0x94CD 0x7BC4 # 0 +0x94CE 0x91C6 # 0 +0x94CF 0x7169 # 0 +0x94D0 0x9812 # 0 +0x94D1 0x98EF # 0 +0x94D2 0x633D # 0 +0x94D3 0x6669 # 0 +0x94D4 0x756A # 0 +0x94D5 0x76E4 # 0 +0x94D6 0x78D0 # 0 +0x94D7 0x8543 # 0 +0x94D8 0x86EE # 0 +0x94D9 0x532A # 0 +0x94DA 0x5351 # 0 +0x94DB 0x5426 # 0 +0x94DC 0x5983 # 0 +0x94DD 0x5E87 # 0 +0x94DE 0x5F7C # 0 +0x94DF 0x60B2 # 0 +0x94E0 0x6249 # 0 +0x94E1 0x6279 # 0 +0x94E2 0x62AB # 0 +0x94E3 0x6590 # 0 +0x94E4 0x6BD4 # 0 +0x94E5 0x6CCC # 0 +0x94E6 0x75B2 # 0 +0x94E7 0x76AE # 0 +0x94E8 0x7891 # 0 +0x94E9 0x79D8 # 0 +0x94EA 0x7DCB # 0 +0x94EB 0x7F77 # 0 +0x94EC 0x80A5 # 0 +0x94ED 0x88AB # 0 +0x94EE 0x8AB9 # 0 +0x94EF 0x8CBB # 0 +0x94F0 0x907F # 0 +0x94F1 0x975E # 0 +0x94F2 0x98DB # 0 +0x94F3 0x6A0B # 0 +0x94F4 0x7C38 # 0 +0x94F5 0x5099 # 0 +0x94F6 0x5C3E # 0 +0x94F7 0x5FAE # 0 +0x94F8 0x6787 # 0 +0x94F9 0x6BD8 # 0 +0x94FA 0x7435 # 0 +0x94FB 0x7709 # 0 +0x94FC 0x7F8E # 0 +0x9540 0x9F3B # 0 +0x9541 0x67CA # 0 +0x9542 0x7A17 # 0 +0x9543 0x5339 # 0 +0x9544 0x758B # 0 +0x9545 0x9AED # 0 +0x9546 0x5F66 # 0 +0x9547 0x819D # 0 +0x9548 0x83F1 # 0 +0x9549 0x8098 # 0 +0x954A 0x5F3C # 0 +0x954B 0x5FC5 # 0 +0x954C 0x7562 # 0 +0x954D 0x7B46 # 0 +0x954E 0x903C # 0 +0x954F 0x6867 # 0 +0x9550 0x59EB # 0 +0x9551 0x5A9B # 0 +0x9552 0x7D10 # 0 +0x9553 0x767E # 0 +0x9554 0x8B2C # 0 +0x9555 0x4FF5 # 0 +0x9556 0x5F6A # 0 +0x9557 0x6A19 # 0 +0x9558 0x6C37 # 0 +0x9559 0x6F02 # 0 +0x955A 0x74E2 # 0 +0x955B 0x7968 # 0 +0x955C 0x8868 # 0 +0x955D 0x8A55 # 0 +0x955E 0x8C79 # 0 +0x955F 0x5EDF # 0 +0x9560 0x63CF # 0 +0x9561 0x75C5 # 0 +0x9562 0x79D2 # 0 +0x9563 0x82D7 # 0 +0x9564 0x9328 # 0 +0x9565 0x92F2 # 0 +0x9566 0x849C # 0 +0x9567 0x86ED # 0 +0x9568 0x9C2D # 0 +0x9569 0x54C1 # 0 +0x956A 0x5F6C # 0 +0x956B 0x658C # 0 +0x956C 0x6D5C # 0 +0x956D 0x7015 # 0 +0x956E 0x8CA7 # 0 +0x956F 0x8CD3 # 0 +0x9570 0x983B # 0 +0x9571 0x654F # 0 +0x9572 0x74F6 # 0 +0x9573 0x4E0D # 0 +0x9574 0x4ED8 # 0 +0x9575 0x57E0 # 0 +0x9576 0x592B # 0 +0x9577 0x5A66 # 0 +0x9578 0x5BCC # 0 +0x9579 0x51A8 # 0 +0x957A 0x5E03 # 0 +0x957B 0x5E9C # 0 +0x957C 0x6016 # 0 +0x957D 0x6276 # 0 +0x957E 0x6577 # 0 +0x9580 0x65A7 # 0 +0x9581 0x666E # 0 +0x9582 0x6D6E # 0 +0x9583 0x7236 # 0 +0x9584 0x7B26 # 0 +0x9585 0x8150 # 0 +0x9586 0x819A # 0 +0x9587 0x8299 # 0 +0x9588 0x8B5C # 0 +0x9589 0x8CA0 # 0 +0x958A 0x8CE6 # 0 +0x958B 0x8D74 # 0 +0x958C 0x961C # 0 +0x958D 0x9644 # 0 +0x958E 0x4FAE # 0 +0x958F 0x64AB # 0 +0x9590 0x6B66 # 0 +0x9591 0x821E # 0 +0x9592 0x8461 # 0 +0x9593 0x856A # 0 +0x9594 0x90E8 # 0 +0x9595 0x5C01 # 0 +0x9596 0x6953 # 0 +0x9597 0x98A8 # 0 +0x9598 0x847A # 0 +0x9599 0x8557 # 0 +0x959A 0x4F0F # 0 +0x959B 0x526F # 0 +0x959C 0x5FA9 # 0 +0x959D 0x5E45 # 0 +0x959E 0x670D # 0 +0x959F 0x798F # 0 +0x95A0 0x8179 # 0 +0x95A1 0x8907 # 0 +0x95A2 0x8986 # 0 +0x95A3 0x6DF5 # 0 +0x95A4 0x5F17 # 0 +0x95A5 0x6255 # 0 +0x95A6 0x6CB8 # 0 +0x95A7 0x4ECF # 0 +0x95A8 0x7269 # 0 +0x95A9 0x9B92 # 0 +0x95AA 0x5206 # 0 +0x95AB 0x543B # 0 +0x95AC 0x5674 # 0 +0x95AD 0x58B3 # 0 +0x95AE 0x61A4 # 0 +0x95AF 0x626E # 0 +0x95B0 0x711A # 0 +0x95B1 0x596E # 0 +0x95B2 0x7C89 # 0 +0x95B3 0x7CDE # 0 +0x95B4 0x7D1B # 0 +0x95B5 0x96F0 # 0 +0x95B6 0x6587 # 0 +0x95B7 0x805E # 0 +0x95B8 0x4E19 # 0 +0x95B9 0x4F75 # 0 +0x95BA 0x5175 # 0 +0x95BB 0x5840 # 0 +0x95BC 0x5E63 # 0 +0x95BD 0x5E73 # 0 +0x95BE 0x5F0A # 0 +0x95BF 0x67C4 # 0 +0x95C0 0x4E26 # 0 +0x95C1 0x853D # 0 +0x95C2 0x9589 # 0 +0x95C3 0x965B # 0 +0x95C4 0x7C73 # 0 +0x95C5 0x9801 # 0 +0x95C6 0x50FB # 0 +0x95C7 0x58C1 # 0 +0x95C8 0x7656 # 0 +0x95C9 0x78A7 # 0 +0x95CA 0x5225 # 0 +0x95CB 0x77A5 # 0 +0x95CC 0x8511 # 0 +0x95CD 0x7B86 # 0 +0x95CE 0x504F # 0 +0x95CF 0x5909 # 0 +0x95D0 0x7247 # 0 +0x95D1 0x7BC7 # 0 +0x95D2 0x7DE8 # 0 +0x95D3 0x8FBA # 0 +0x95D4 0x8FD4 # 0 +0x95D5 0x904D # 0 +0x95D6 0x4FBF # 0 +0x95D7 0x52C9 # 0 +0x95D8 0x5A29 # 0 +0x95D9 0x5F01 # 0 +0x95DA 0x97AD # 0 +0x95DB 0x4FDD # 0 +0x95DC 0x8217 # 0 +0x95DD 0x92EA # 0 +0x95DE 0x5703 # 0 +0x95DF 0x6355 # 0 +0x95E0 0x6B69 # 0 +0x95E1 0x752B # 0 +0x95E2 0x88DC # 0 +0x95E3 0x8F14 # 0 +0x95E4 0x7A42 # 0 +0x95E5 0x52DF # 0 +0x95E6 0x5893 # 0 +0x95E7 0x6155 # 0 +0x95E8 0x620A # 0 +0x95E9 0x66AE # 0 +0x95EA 0x6BCD # 0 +0x95EB 0x7C3F # 0 +0x95EC 0x83E9 # 0 +0x95ED 0x5023 # 0 +0x95EE 0x4FF8 # 0 +0x95EF 0x5305 # 0 +0x95F0 0x5446 # 0 +0x95F1 0x5831 # 0 +0x95F2 0x5949 # 0 +0x95F3 0x5B9D # 0 +0x95F4 0x5CF0 # 0 +0x95F5 0x5CEF # 0 +0x95F6 0x5D29 # 0 +0x95F7 0x5E96 # 0 +0x95F8 0x62B1 # 0 +0x95F9 0x6367 # 0 +0x95FA 0x653E # 0 +0x95FB 0x65B9 # 0 +0x95FC 0x670B # 0 +0x9640 0x6CD5 # 0 +0x9641 0x6CE1 # 0 +0x9642 0x70F9 # 0 +0x9643 0x7832 # 0 +0x9644 0x7E2B # 0 +0x9645 0x80DE # 0 +0x9646 0x82B3 # 0 +0x9647 0x840C # 0 +0x9648 0x84EC # 0 +0x9649 0x8702 # 0 +0x964A 0x8912 # 0 +0x964B 0x8A2A # 0 +0x964C 0x8C4A # 0 +0x964D 0x90A6 # 0 +0x964E 0x92D2 # 0 +0x964F 0x98FD # 0 +0x9650 0x9CF3 # 0 +0x9651 0x9D6C # 0 +0x9652 0x4E4F # 0 +0x9653 0x4EA1 # 0 +0x9654 0x508D # 0 +0x9655 0x5256 # 0 +0x9656 0x574A # 0 +0x9657 0x59A8 # 0 +0x9658 0x5E3D # 0 +0x9659 0x5FD8 # 0 +0x965A 0x5FD9 # 0 +0x965B 0x623F # 0 +0x965C 0x66B4 # 0 +0x965D 0x671B # 0 +0x965E 0x67D0 # 0 +0x965F 0x68D2 # 0 +0x9660 0x5192 # 0 +0x9661 0x7D21 # 0 +0x9662 0x80AA # 0 +0x9663 0x81A8 # 0 +0x9664 0x8B00 # 0 +0x9665 0x8C8C # 0 +0x9666 0x8CBF # 0 +0x9667 0x927E # 0 +0x9668 0x9632 # 0 +0x9669 0x5420 # 0 +0x966A 0x982C # 0 +0x966B 0x5317 # 0 +0x966C 0x50D5 # 0 +0x966D 0x535C # 0 +0x966E 0x58A8 # 0 +0x966F 0x64B2 # 0 +0x9670 0x6734 # 0 +0x9671 0x7267 # 0 +0x9672 0x7766 # 0 +0x9673 0x7A46 # 0 +0x9674 0x91E6 # 0 +0x9675 0x52C3 # 0 +0x9676 0x6CA1 # 0 +0x9677 0x6B86 # 0 +0x9678 0x5800 # 0 +0x9679 0x5E4C # 0 +0x967A 0x5954 # 0 +0x967B 0x672C # 0 +0x967C 0x7FFB # 0 +0x967D 0x51E1 # 0 +0x967E 0x76C6 # 0 +0x9680 0x6469 # 0 +0x9681 0x78E8 # 0 +0x9682 0x9B54 # 0 +0x9683 0x9EBB # 0 +0x9684 0x57CB # 0 +0x9685 0x59B9 # 0 +0x9686 0x6627 # 0 +0x9687 0x679A # 0 +0x9688 0x6BCE # 0 +0x9689 0x54E9 # 0 +0x968A 0x69D9 # 0 +0x968B 0x5E55 # 0 +0x968C 0x819C # 0 +0x968D 0x6795 # 0 +0x968E 0x9BAA # 0 +0x968F 0x67FE # 0 +0x9690 0x9C52 # 0 +0x9691 0x685D # 0 +0x9692 0x4EA6 # 0 +0x9693 0x4FE3 # 0 +0x9694 0x53C8 # 0 +0x9695 0x62B9 # 0 +0x9696 0x672B # 0 +0x9697 0x6CAB # 0 +0x9698 0x8FC4 # 0 +0x9699 0x4FAD # 0 +0x969A 0x7E6D # 0 +0x969B 0x9EBF # 0 +0x969C 0x4E07 # 0 +0x969D 0x6162 # 0 +0x969E 0x6E80 # 0 +0x969F 0x6F2B # 0 +0x96A0 0x8513 # 0 +0x96A1 0x5473 # 0 +0x96A2 0x672A # 0 +0x96A3 0x9B45 # 0 +0x96A4 0x5DF3 # 0 +0x96A5 0x7B95 # 0 +0x96A6 0x5CAC # 0 +0x96A7 0x5BC6 # 0 +0x96A8 0x871C # 0 +0x96A9 0x6E4A # 0 +0x96AA 0x84D1 # 0 +0x96AB 0x7A14 # 0 +0x96AC 0x8108 # 0 +0x96AD 0x5999 # 0 +0x96AE 0x7C8D # 0 +0x96AF 0x6C11 # 0 +0x96B0 0x7720 # 0 +0x96B1 0x52D9 # 0 +0x96B2 0x5922 # 0 +0x96B3 0x7121 # 0 +0x96B4 0x725F # 0 +0x96B5 0x77DB # 0 +0x96B6 0x9727 # 0 +0x96B7 0x9D61 # 0 +0x96B8 0x690B # 0 +0x96B9 0x5A7F # 0 +0x96BA 0x5A18 # 0 +0x96BB 0x51A5 # 0 +0x96BC 0x540D # 0 +0x96BD 0x547D # 0 +0x96BE 0x660E # 0 +0x96BF 0x76DF # 0 +0x96C0 0x8FF7 # 0 +0x96C1 0x9298 # 0 +0x96C2 0x9CF4 # 0 +0x96C3 0x59EA # 0 +0x96C4 0x725D # 0 +0x96C5 0x6EC5 # 0 +0x96C6 0x514D # 0 +0x96C7 0x68C9 # 0 +0x96C8 0x7DBF # 0 +0x96C9 0x7DEC # 0 +0x96CA 0x9762 # 0 +0x96CB 0x9EBA # 0 +0x96CC 0x6478 # 0 +0x96CD 0x6A21 # 0 +0x96CE 0x8302 # 0 +0x96CF 0x5984 # 0 +0x96D0 0x5B5F # 0 +0x96D1 0x6BDB # 0 +0x96D2 0x731B # 0 +0x96D3 0x76F2 # 0 +0x96D4 0x7DB2 # 0 +0x96D5 0x8017 # 0 +0x96D6 0x8499 # 0 +0x96D7 0x5132 # 0 +0x96D8 0x6728 # 0 +0x96D9 0x9ED9 # 0 +0x96DA 0x76EE # 0 +0x96DB 0x6762 # 0 +0x96DC 0x52FF # 0 +0x96DD 0x9905 # 0 +0x96DE 0x5C24 # 0 +0x96DF 0x623B # 0 +0x96E0 0x7C7E # 0 +0x96E1 0x8CB0 # 0 +0x96E2 0x554F # 0 +0x96E3 0x60B6 # 0 +0x96E4 0x7D0B # 0 +0x96E5 0x9580 # 0 +0x96E6 0x5301 # 0 +0x96E7 0x4E5F # 0 +0x96E8 0x51B6 # 0 +0x96E9 0x591C # 0 +0x96EA 0x723A # 0 +0x96EB 0x8036 # 0 +0x96EC 0x91CE # 0 +0x96ED 0x5F25 # 0 +0x96EE 0x77E2 # 0 +0x96EF 0x5384 # 0 +0x96F0 0x5F79 # 0 +0x96F1 0x7D04 # 0 +0x96F2 0x85AC # 0 +0x96F3 0x8A33 # 0 +0x96F4 0x8E8D # 0 +0x96F5 0x9756 # 0 +0x96F6 0x67F3 # 0 +0x96F7 0x85AE # 0 +0x96F8 0x9453 # 0 +0x96F9 0x6109 # 0 +0x96FA 0x6108 # 0 +0x96FB 0x6CB9 # 0 +0x96FC 0x7652 # 0 +0x9740 0x8AED # 0 +0x9741 0x8F38 # 0 +0x9742 0x552F # 0 +0x9743 0x4F51 # 0 +0x9744 0x512A # 0 +0x9745 0x52C7 # 0 +0x9746 0x53CB # 0 +0x9747 0x5BA5 # 0 +0x9748 0x5E7D # 0 +0x9749 0x60A0 # 0 +0x974A 0x6182 # 0 +0x974B 0x63D6 # 0 +0x974C 0x6709 # 0 +0x974D 0x67DA # 0 +0x974E 0x6E67 # 0 +0x974F 0x6D8C # 0 +0x9750 0x7336 # 0 +0x9751 0x7337 # 0 +0x9752 0x7531 # 0 +0x9753 0x7950 # 0 +0x9754 0x88D5 # 0 +0x9755 0x8A98 # 0 +0x9756 0x904A # 0 +0x9757 0x9091 # 0 +0x9758 0x90F5 # 0 +0x9759 0x96C4 # 0 +0x975A 0x878D # 0 +0x975B 0x5915 # 0 +0x975C 0x4E88 # 0 +0x975D 0x4F59 # 0 +0x975E 0x4E0E # 0 +0x975F 0x8A89 # 0 +0x9760 0x8F3F # 0 +0x9761 0x9810 # 0 +0x9762 0x50AD # 0 +0x9763 0x5E7C # 0 +0x9764 0x5996 # 0 +0x9765 0x5BB9 # 0 +0x9766 0x5EB8 # 0 +0x9767 0x63DA # 0 +0x9768 0x63FA # 0 +0x9769 0x64C1 # 0 +0x976A 0x66DC # 0 +0x976B 0x694A # 0 +0x976C 0x69D8 # 0 +0x976D 0x6D0B # 0 +0x976E 0x6EB6 # 0 +0x976F 0x7194 # 0 +0x9770 0x7528 # 0 +0x9771 0x7AAF # 0 +0x9772 0x7F8A # 0 +0x9773 0x8000 # 0 +0x9774 0x8449 # 0 +0x9775 0x84C9 # 0 +0x9776 0x8981 # 0 +0x9777 0x8B21 # 0 +0x9778 0x8E0A # 0 +0x9779 0x9065 # 0 +0x977A 0x967D # 0 +0x977B 0x990A # 0 +0x977C 0x617E # 0 +0x977D 0x6291 # 0 +0x977E 0x6B32 # 0 +0x9780 0x6C83 # 0 +0x9781 0x6D74 # 0 +0x9782 0x7FCC # 0 +0x9783 0x7FFC # 0 +0x9784 0x6DC0 # 0 +0x9785 0x7F85 # 0 +0x9786 0x87BA # 0 +0x9787 0x88F8 # 0 +0x9788 0x6765 # 0 +0x9789 0x83B1 # 0 +0x978A 0x983C # 0 +0x978B 0x96F7 # 0 +0x978C 0x6D1B # 0 +0x978D 0x7D61 # 0 +0x978E 0x843D # 0 +0x978F 0x916A # 0 +0x9790 0x4E71 # 0 +0x9791 0x5375 # 0 +0x9792 0x5D50 # 0 +0x9793 0x6B04 # 0 +0x9794 0x6FEB # 0 +0x9795 0x85CD # 0 +0x9796 0x862D # 0 +0x9797 0x89A7 # 0 +0x9798 0x5229 # 0 +0x9799 0x540F # 0 +0x979A 0x5C65 # 0 +0x979B 0x674E # 0 +0x979C 0x68A8 # 0 +0x979D 0x7406 # 0 +0x979E 0x7483 # 0 +0x979F 0x75E2 # 0 +0x97A0 0x88CF # 0 +0x97A1 0x88E1 # 0 +0x97A2 0x91CC # 0 +0x97A3 0x96E2 # 0 +0x97A4 0x9678 # 0 +0x97A5 0x5F8B # 0 +0x97A6 0x7387 # 0 +0x97A7 0x7ACB # 0 +0x97A8 0x844E # 0 +0x97A9 0x63A0 # 0 +0x97AA 0x7565 # 0 +0x97AB 0x5289 # 0 +0x97AC 0x6D41 # 0 +0x97AD 0x6E9C # 0 +0x97AE 0x7409 # 0 +0x97AF 0x7559 # 0 +0x97B0 0x786B # 0 +0x97B1 0x7C92 # 0 +0x97B2 0x9686 # 0 +0x97B3 0x7ADC # 0 +0x97B4 0x9F8D # 0 +0x97B5 0x4FB6 # 0 +0x97B6 0x616E # 0 +0x97B7 0x65C5 # 0 +0x97B8 0x865C # 0 +0x97B9 0x4E86 # 0 +0x97BA 0x4EAE # 0 +0x97BB 0x50DA # 0 +0x97BC 0x4E21 # 0 +0x97BD 0x51CC # 0 +0x97BE 0x5BEE # 0 +0x97BF 0x6599 # 0 +0x97C0 0x6881 # 0 +0x97C1 0x6DBC # 0 +0x97C2 0x731F # 0 +0x97C3 0x7642 # 0 +0x97C4 0x77AD # 0 +0x97C5 0x7A1C # 0 +0x97C6 0x7CE7 # 0 +0x97C7 0x826F # 0 +0x97C8 0x8AD2 # 0 +0x97C9 0x907C # 0 +0x97CA 0x91CF # 0 +0x97CB 0x9675 # 0 +0x97CC 0x9818 # 0 +0x97CD 0x529B # 0 +0x97CE 0x7DD1 # 0 +0x97CF 0x502B # 0 +0x97D0 0x5398 # 0 +0x97D1 0x6797 # 0 +0x97D2 0x6DCB # 0 +0x97D3 0x71D0 # 0 +0x97D4 0x7433 # 0 +0x97D5 0x81E8 # 0 +0x97D6 0x8F2A # 0 +0x97D7 0x96A3 # 0 +0x97D8 0x9C57 # 0 +0x97D9 0x9E9F # 0 +0x97DA 0x7460 # 0 +0x97DB 0x5841 # 0 +0x97DC 0x6D99 # 0 +0x97DD 0x7D2F # 0 +0x97DE 0x985E # 0 +0x97DF 0x4EE4 # 0 +0x97E0 0x4F36 # 0 +0x97E1 0x4F8B # 0 +0x97E2 0x51B7 # 0 +0x97E3 0x52B1 # 0 +0x97E4 0x5DBA # 0 +0x97E5 0x601C # 0 +0x97E6 0x73B2 # 0 +0x97E7 0x793C # 0 +0x97E8 0x82D3 # 0 +0x97E9 0x9234 # 0 +0x97EA 0x96B7 # 0 +0x97EB 0x96F6 # 0 +0x97EC 0x970A # 0 +0x97ED 0x9E97 # 0 +0x97EE 0x9F62 # 0 +0x97EF 0x66A6 # 0 +0x97F0 0x6B74 # 0 +0x97F1 0x5217 # 0 +0x97F2 0x52A3 # 0 +0x97F3 0x70C8 # 0 +0x97F4 0x88C2 # 0 +0x97F5 0x5EC9 # 0 +0x97F6 0x604B # 0 +0x97F7 0x6190 # 0 +0x97F8 0x6F23 # 0 +0x97F9 0x7149 # 0 +0x97FA 0x7C3E # 0 +0x97FB 0x7DF4 # 0 +0x97FC 0x806F # 0 +0x9840 0x84EE # 0 +0x9841 0x9023 # 0 +0x9842 0x932C # 0 +0x9843 0x5442 # 0 +0x9844 0x9B6F # 0 +0x9845 0x6AD3 # 0 +0x9846 0x7089 # 0 +0x9847 0x8CC2 # 0 +0x9848 0x8DEF # 0 +0x9849 0x9732 # 0 +0x984A 0x52B4 # 0 +0x984B 0x5A41 # 0 +0x984C 0x5ECA # 0 +0x984D 0x5F04 # 0 +0x984E 0x6717 # 0 +0x984F 0x697C # 0 +0x9850 0x6994 # 0 +0x9851 0x6D6A # 0 +0x9852 0x6F0F # 0 +0x9853 0x7262 # 0 +0x9854 0x72FC # 0 +0x9855 0x7BED # 0 +0x9856 0x8001 # 0 +0x9857 0x807E # 0 +0x9858 0x874B # 0 +0x9859 0x90CE # 0 +0x985A 0x516D # 0 +0x985B 0x9E93 # 0 +0x985C 0x7984 # 0 +0x985D 0x808B # 0 +0x985E 0x9332 # 0 +0x985F 0x8AD6 # 0 +0x9860 0x502D # 0 +0x9861 0x548C # 0 +0x9862 0x8A71 # 0 +0x9863 0x6B6A # 0 +0x9864 0x8CC4 # 0 +0x9865 0x8107 # 0 +0x9866 0x60D1 # 0 +0x9867 0x67A0 # 0 +0x9868 0x9DF2 # 0 +0x9869 0x4E99 # 0 +0x986A 0x4E98 # 0 +0x986B 0x9C10 # 0 +0x986C 0x8A6B # 0 +0x986D 0x85C1 # 0 +0x986E 0x8568 # 0 +0x986F 0x6900 # 0 +0x9870 0x6E7E # 0 +0x9871 0x7897 # 0 +0x9872 0x8155 # 0 +0x989F 0x5F0C # 0 +0x98A0 0x4E10 # 0 +0x98A1 0x4E15 # 0 +0x98A2 0x4E2A # 0 +0x98A3 0x4E31 # 0 +0x98A4 0x4E36 # 0 +0x98A5 0x4E3C # 0 +0x98A6 0x4E3F # 0 +0x98A7 0x4E42 # 0 +0x98A8 0x4E56 # 0 +0x98A9 0x4E58 # 0 +0x98AA 0x4E82 # 0 +0x98AB 0x4E85 # 0 +0x98AC 0x8C6B # 0 +0x98AD 0x4E8A # 0 +0x98AE 0x8212 # 0 +0x98AF 0x5F0D # 0 +0x98B0 0x4E8E # 0 +0x98B1 0x4E9E # 0 +0x98B2 0x4E9F # 0 +0x98B3 0x4EA0 # 0 +0x98B4 0x4EA2 # 0 +0x98B5 0x4EB0 # 0 +0x98B6 0x4EB3 # 0 +0x98B7 0x4EB6 # 0 +0x98B8 0x4ECE # 0 +0x98B9 0x4ECD # 0 +0x98BA 0x4EC4 # 0 +0x98BB 0x4EC6 # 0 +0x98BC 0x4EC2 # 0 +0x98BD 0x4ED7 # 0 +0x98BE 0x4EDE # 0 +0x98BF 0x4EED # 0 +0x98C0 0x4EDF # 0 +0x98C1 0x4EF7 # 0 +0x98C2 0x4F09 # 0 +0x98C3 0x4F5A # 0 +0x98C4 0x4F30 # 0 +0x98C5 0x4F5B # 0 +0x98C6 0x4F5D # 0 +0x98C7 0x4F57 # 0 +0x98C8 0x4F47 # 0 +0x98C9 0x4F76 # 0 +0x98CA 0x4F88 # 0 +0x98CB 0x4F8F # 0 +0x98CC 0x4F98 # 0 +0x98CD 0x4F7B # 0 +0x98CE 0x4F69 # 0 +0x98CF 0x4F70 # 0 +0x98D0 0x4F91 # 0 +0x98D1 0x4F6F # 0 +0x98D2 0x4F86 # 0 +0x98D3 0x4F96 # 0 +0x98D4 0x5118 # 0 +0x98D5 0x4FD4 # 0 +0x98D6 0x4FDF # 0 +0x98D7 0x4FCE # 0 +0x98D8 0x4FD8 # 0 +0x98D9 0x4FDB # 0 +0x98DA 0x4FD1 # 0 +0x98DB 0x4FDA # 0 +0x98DC 0x4FD0 # 0 +0x98DD 0x4FE4 # 0 +0x98DE 0x4FE5 # 0 +0x98DF 0x501A # 0 +0x98E0 0x5028 # 0 +0x98E1 0x5014 # 0 +0x98E2 0x502A # 0 +0x98E3 0x5025 # 0 +0x98E4 0x5005 # 0 +0x98E5 0x4F1C # 0 +0x98E6 0x4FF6 # 0 +0x98E7 0x5021 # 0 +0x98E8 0x5029 # 0 +0x98E9 0x502C # 0 +0x98EA 0x4FFE # 0 +0x98EB 0x4FEF # 0 +0x98EC 0x5011 # 0 +0x98ED 0x5006 # 0 +0x98EE 0x5043 # 0 +0x98EF 0x5047 # 0 +0x98F0 0x6703 # 0 +0x98F1 0x5055 # 0 +0x98F2 0x5050 # 0 +0x98F3 0x5048 # 0 +0x98F4 0x505A # 0 +0x98F5 0x5056 # 0 +0x98F6 0x506C # 0 +0x98F7 0x5078 # 0 +0x98F8 0x5080 # 0 +0x98F9 0x509A # 0 +0x98FA 0x5085 # 0 +0x98FB 0x50B4 # 0 +0x98FC 0x50B2 # 0 +0x9940 0x50C9 # 0 +0x9941 0x50CA # 0 +0x9942 0x50B3 # 0 +0x9943 0x50C2 # 0 +0x9944 0x50D6 # 0 +0x9945 0x50DE # 0 +0x9946 0x50E5 # 0 +0x9947 0x50ED # 0 +0x9948 0x50E3 # 0 +0x9949 0x50EE # 0 +0x994A 0x50F9 # 0 +0x994B 0x50F5 # 0 +0x994C 0x5109 # 0 +0x994D 0x5101 # 0 +0x994E 0x5102 # 0 +0x994F 0x5116 # 0 +0x9950 0x5115 # 0 +0x9951 0x5114 # 0 +0x9952 0x511A # 0 +0x9953 0x5121 # 0 +0x9954 0x513A # 0 +0x9955 0x5137 # 0 +0x9956 0x513C # 0 +0x9957 0x513B # 0 +0x9958 0x513F # 0 +0x9959 0x5140 # 0 +0x995A 0x5152 # 0 +0x995B 0x514C # 0 +0x995C 0x5154 # 0 +0x995D 0x5162 # 0 +0x995E 0x7AF8 # 0 +0x995F 0x5169 # 0 +0x9960 0x516A # 0 +0x9961 0x516E # 0 +0x9962 0x5180 # 0 +0x9963 0x5182 # 0 +0x9964 0x56D8 # 0 +0x9965 0x518C # 0 +0x9966 0x5189 # 0 +0x9967 0x518F # 0 +0x9968 0x5191 # 0 +0x9969 0x5193 # 0 +0x996A 0x5195 # 0 +0x996B 0x5196 # 0 +0x996C 0x51A4 # 0 +0x996D 0x51A6 # 0 +0x996E 0x51A2 # 0 +0x996F 0x51A9 # 0 +0x9970 0x51AA # 0 +0x9971 0x51AB # 0 +0x9972 0x51B3 # 0 +0x9973 0x51B1 # 0 +0x9974 0x51B2 # 0 +0x9975 0x51B0 # 0 +0x9976 0x51B5 # 0 +0x9977 0x51BD # 0 +0x9978 0x51C5 # 0 +0x9979 0x51C9 # 0 +0x997A 0x51DB # 0 +0x997B 0x51E0 # 0 +0x997C 0x8655 # 0 +0x997D 0x51E9 # 0 +0x997E 0x51ED # 0 +0x9980 0x51F0 # 0 +0x9981 0x51F5 # 0 +0x9982 0x51FE # 0 +0x9983 0x5204 # 0 +0x9984 0x520B # 0 +0x9985 0x5214 # 0 +0x9986 0x520E # 0 +0x9987 0x5227 # 0 +0x9988 0x522A # 0 +0x9989 0x522E # 0 +0x998A 0x5233 # 0 +0x998B 0x5239 # 0 +0x998C 0x524F # 0 +0x998D 0x5244 # 0 +0x998E 0x524B # 0 +0x998F 0x524C # 0 +0x9990 0x525E # 0 +0x9991 0x5254 # 0 +0x9992 0x526A # 0 +0x9993 0x5274 # 0 +0x9994 0x5269 # 0 +0x9995 0x5273 # 0 +0x9996 0x527F # 0 +0x9997 0x527D # 0 +0x9998 0x528D # 0 +0x9999 0x5294 # 0 +0x999A 0x5292 # 0 +0x999B 0x5271 # 0 +0x999C 0x5288 # 0 +0x999D 0x5291 # 0 +0x999E 0x8FA8 # 0 +0x999F 0x8FA7 # 0 +0x99A0 0x52AC # 0 +0x99A1 0x52AD # 0 +0x99A2 0x52BC # 0 +0x99A3 0x52B5 # 0 +0x99A4 0x52C1 # 0 +0x99A5 0x52CD # 0 +0x99A6 0x52D7 # 0 +0x99A7 0x52DE # 0 +0x99A8 0x52E3 # 0 +0x99A9 0x52E6 # 0 +0x99AA 0x98ED # 0 +0x99AB 0x52E0 # 0 +0x99AC 0x52F3 # 0 +0x99AD 0x52F5 # 0 +0x99AE 0x52F8 # 0 +0x99AF 0x52F9 # 0 +0x99B0 0x5306 # 0 +0x99B1 0x5308 # 0 +0x99B2 0x7538 # 0 +0x99B3 0x530D # 0 +0x99B4 0x5310 # 0 +0x99B5 0x530F # 0 +0x99B6 0x5315 # 0 +0x99B7 0x531A # 0 +0x99B8 0x5323 # 0 +0x99B9 0x532F # 0 +0x99BA 0x5331 # 0 +0x99BB 0x5333 # 0 +0x99BC 0x5338 # 0 +0x99BD 0x5340 # 0 +0x99BE 0x5346 # 0 +0x99BF 0x5345 # 0 +0x99C0 0x4E17 # 0 +0x99C1 0x5349 # 0 +0x99C2 0x534D # 0 +0x99C3 0x51D6 # 0 +0x99C4 0x535E # 0 +0x99C5 0x5369 # 0 +0x99C6 0x536E # 0 +0x99C7 0x5918 # 0 +0x99C8 0x537B # 0 +0x99C9 0x5377 # 0 +0x99CA 0x5382 # 0 +0x99CB 0x5396 # 0 +0x99CC 0x53A0 # 0 +0x99CD 0x53A6 # 0 +0x99CE 0x53A5 # 0 +0x99CF 0x53AE # 0 +0x99D0 0x53B0 # 0 +0x99D1 0x53B6 # 0 +0x99D2 0x53C3 # 0 +0x99D3 0x7C12 # 0 +0x99D4 0x96D9 # 0 +0x99D5 0x53DF # 0 +0x99D6 0x66FC # 0 +0x99D7 0x71EE # 0 +0x99D8 0x53EE # 0 +0x99D9 0x53E8 # 0 +0x99DA 0x53ED # 0 +0x99DB 0x53FA # 0 +0x99DC 0x5401 # 0 +0x99DD 0x543D # 0 +0x99DE 0x5440 # 0 +0x99DF 0x542C # 0 +0x99E0 0x542D # 0 +0x99E1 0x543C # 0 +0x99E2 0x542E # 0 +0x99E3 0x5436 # 0 +0x99E4 0x5429 # 0 +0x99E5 0x541D # 0 +0x99E6 0x544E # 0 +0x99E7 0x548F # 0 +0x99E8 0x5475 # 0 +0x99E9 0x548E # 0 +0x99EA 0x545F # 0 +0x99EB 0x5471 # 0 +0x99EC 0x5477 # 0 +0x99ED 0x5470 # 0 +0x99EE 0x5492 # 0 +0x99EF 0x547B # 0 +0x99F0 0x5480 # 0 +0x99F1 0x5476 # 0 +0x99F2 0x5484 # 0 +0x99F3 0x5490 # 0 +0x99F4 0x5486 # 0 +0x99F5 0x54C7 # 0 +0x99F6 0x54A2 # 0 +0x99F7 0x54B8 # 0 +0x99F8 0x54A5 # 0 +0x99F9 0x54AC # 0 +0x99FA 0x54C4 # 0 +0x99FB 0x54C8 # 0 +0x99FC 0x54A8 # 0 +0x9A40 0x54AB # 0 +0x9A41 0x54C2 # 0 +0x9A42 0x54A4 # 0 +0x9A43 0x54BE # 0 +0x9A44 0x54BC # 0 +0x9A45 0x54D8 # 0 +0x9A46 0x54E5 # 0 +0x9A47 0x54E6 # 0 +0x9A48 0x550F # 0 +0x9A49 0x5514 # 0 +0x9A4A 0x54FD # 0 +0x9A4B 0x54EE # 0 +0x9A4C 0x54ED # 0 +0x9A4D 0x54FA # 0 +0x9A4E 0x54E2 # 0 +0x9A4F 0x5539 # 0 +0x9A50 0x5540 # 0 +0x9A51 0x5563 # 0 +0x9A52 0x554C # 0 +0x9A53 0x552E # 0 +0x9A54 0x555C # 0 +0x9A55 0x5545 # 0 +0x9A56 0x5556 # 0 +0x9A57 0x5557 # 0 +0x9A58 0x5538 # 0 +0x9A59 0x5533 # 0 +0x9A5A 0x555D # 0 +0x9A5B 0x5599 # 0 +0x9A5C 0x5580 # 0 +0x9A5D 0x54AF # 0 +0x9A5E 0x558A # 0 +0x9A5F 0x559F # 0 +0x9A60 0x557B # 0 +0x9A61 0x557E # 0 +0x9A62 0x5598 # 0 +0x9A63 0x559E # 0 +0x9A64 0x55AE # 0 +0x9A65 0x557C # 0 +0x9A66 0x5583 # 0 +0x9A67 0x55A9 # 0 +0x9A68 0x5587 # 0 +0x9A69 0x55A8 # 0 +0x9A6A 0x55DA # 0 +0x9A6B 0x55C5 # 0 +0x9A6C 0x55DF # 0 +0x9A6D 0x55C4 # 0 +0x9A6E 0x55DC # 0 +0x9A6F 0x55E4 # 0 +0x9A70 0x55D4 # 0 +0x9A71 0x5614 # 0 +0x9A72 0x55F7 # 0 +0x9A73 0x5616 # 0 +0x9A74 0x55FE # 0 +0x9A75 0x55FD # 0 +0x9A76 0x561B # 0 +0x9A77 0x55F9 # 0 +0x9A78 0x564E # 0 +0x9A79 0x5650 # 0 +0x9A7A 0x71DF # 0 +0x9A7B 0x5634 # 0 +0x9A7C 0x5636 # 0 +0x9A7D 0x5632 # 0 +0x9A7E 0x5638 # 0 +0x9A80 0x566B # 0 +0x9A81 0x5664 # 0 +0x9A82 0x562F # 0 +0x9A83 0x566C # 0 +0x9A84 0x566A # 0 +0x9A85 0x5686 # 0 +0x9A86 0x5680 # 0 +0x9A87 0x568A # 0 +0x9A88 0x56A0 # 0 +0x9A89 0x5694 # 0 +0x9A8A 0x568F # 0 +0x9A8B 0x56A5 # 0 +0x9A8C 0x56AE # 0 +0x9A8D 0x56B6 # 0 +0x9A8E 0x56B4 # 0 +0x9A8F 0x56C2 # 0 +0x9A90 0x56BC # 0 +0x9A91 0x56C1 # 0 +0x9A92 0x56C3 # 0 +0x9A93 0x56C0 # 0 +0x9A94 0x56C8 # 0 +0x9A95 0x56CE # 0 +0x9A96 0x56D1 # 0 +0x9A97 0x56D3 # 0 +0x9A98 0x56D7 # 0 +0x9A99 0x56EE # 0 +0x9A9A 0x56F9 # 0 +0x9A9B 0x5700 # 0 +0x9A9C 0x56FF # 0 +0x9A9D 0x5704 # 0 +0x9A9E 0x5709 # 0 +0x9A9F 0x5708 # 0 +0x9AA0 0x570B # 0 +0x9AA1 0x570D # 0 +0x9AA2 0x5713 # 0 +0x9AA3 0x5718 # 0 +0x9AA4 0x5716 # 0 +0x9AA5 0x55C7 # 0 +0x9AA6 0x571C # 0 +0x9AA7 0x5726 # 0 +0x9AA8 0x5737 # 0 +0x9AA9 0x5738 # 0 +0x9AAA 0x574E # 0 +0x9AAB 0x573B # 0 +0x9AAC 0x5740 # 0 +0x9AAD 0x574F # 0 +0x9AAE 0x5769 # 0 +0x9AAF 0x57C0 # 0 +0x9AB0 0x5788 # 0 +0x9AB1 0x5761 # 0 +0x9AB2 0x577F # 0 +0x9AB3 0x5789 # 0 +0x9AB4 0x5793 # 0 +0x9AB5 0x57A0 # 0 +0x9AB6 0x57B3 # 0 +0x9AB7 0x57A4 # 0 +0x9AB8 0x57AA # 0 +0x9AB9 0x57B0 # 0 +0x9ABA 0x57C3 # 0 +0x9ABB 0x57C6 # 0 +0x9ABC 0x57D4 # 0 +0x9ABD 0x57D2 # 0 +0x9ABE 0x57D3 # 0 +0x9ABF 0x580A # 0 +0x9AC0 0x57D6 # 0 +0x9AC1 0x57E3 # 0 +0x9AC2 0x580B # 0 +0x9AC3 0x5819 # 0 +0x9AC4 0x581D # 0 +0x9AC5 0x5872 # 0 +0x9AC6 0x5821 # 0 +0x9AC7 0x5862 # 0 +0x9AC8 0x584B # 0 +0x9AC9 0x5870 # 0 +0x9ACA 0x6BC0 # 0 +0x9ACB 0x5852 # 0 +0x9ACC 0x583D # 0 +0x9ACD 0x5879 # 0 +0x9ACE 0x5885 # 0 +0x9ACF 0x58B9 # 0 +0x9AD0 0x589F # 0 +0x9AD1 0x58AB # 0 +0x9AD2 0x58BA # 0 +0x9AD3 0x58DE # 0 +0x9AD4 0x58BB # 0 +0x9AD5 0x58B8 # 0 +0x9AD6 0x58AE # 0 +0x9AD7 0x58C5 # 0 +0x9AD8 0x58D3 # 0 +0x9AD9 0x58D1 # 0 +0x9ADA 0x58D7 # 0 +0x9ADB 0x58D9 # 0 +0x9ADC 0x58D8 # 0 +0x9ADD 0x58E5 # 0 +0x9ADE 0x58DC # 0 +0x9ADF 0x58E4 # 0 +0x9AE0 0x58DF # 0 +0x9AE1 0x58EF # 0 +0x9AE2 0x58FA # 0 +0x9AE3 0x58F9 # 0 +0x9AE4 0x58FB # 0 +0x9AE5 0x58FC # 0 +0x9AE6 0x58FD # 0 +0x9AE7 0x5902 # 0 +0x9AE8 0x590A # 0 +0x9AE9 0x5910 # 0 +0x9AEA 0x591B # 0 +0x9AEB 0x68A6 # 0 +0x9AEC 0x5925 # 0 +0x9AED 0x592C # 0 +0x9AEE 0x592D # 0 +0x9AEF 0x5932 # 0 +0x9AF0 0x5938 # 0 +0x9AF1 0x593E # 0 +0x9AF2 0x7AD2 # 0 +0x9AF3 0x5955 # 0 +0x9AF4 0x5950 # 0 +0x9AF5 0x594E # 0 +0x9AF6 0x595A # 0 +0x9AF7 0x5958 # 0 +0x9AF8 0x5962 # 0 +0x9AF9 0x5960 # 0 +0x9AFA 0x5967 # 0 +0x9AFB 0x596C # 0 +0x9AFC 0x5969 # 0 +0x9B40 0x5978 # 0 +0x9B41 0x5981 # 0 +0x9B42 0x599D # 0 +0x9B43 0x4F5E # 0 +0x9B44 0x4FAB # 0 +0x9B45 0x59A3 # 0 +0x9B46 0x59B2 # 0 +0x9B47 0x59C6 # 0 +0x9B48 0x59E8 # 0 +0x9B49 0x59DC # 0 +0x9B4A 0x598D # 0 +0x9B4B 0x59D9 # 0 +0x9B4C 0x59DA # 0 +0x9B4D 0x5A25 # 0 +0x9B4E 0x5A1F # 0 +0x9B4F 0x5A11 # 0 +0x9B50 0x5A1C # 0 +0x9B51 0x5A09 # 0 +0x9B52 0x5A1A # 0 +0x9B53 0x5A40 # 0 +0x9B54 0x5A6C # 0 +0x9B55 0x5A49 # 0 +0x9B56 0x5A35 # 0 +0x9B57 0x5A36 # 0 +0x9B58 0x5A62 # 0 +0x9B59 0x5A6A # 0 +0x9B5A 0x5A9A # 0 +0x9B5B 0x5ABC # 0 +0x9B5C 0x5ABE # 0 +0x9B5D 0x5ACB # 0 +0x9B5E 0x5AC2 # 0 +0x9B5F 0x5ABD # 0 +0x9B60 0x5AE3 # 0 +0x9B61 0x5AD7 # 0 +0x9B62 0x5AE6 # 0 +0x9B63 0x5AE9 # 0 +0x9B64 0x5AD6 # 0 +0x9B65 0x5AFA # 0 +0x9B66 0x5AFB # 0 +0x9B67 0x5B0C # 0 +0x9B68 0x5B0B # 0 +0x9B69 0x5B16 # 0 +0x9B6A 0x5B32 # 0 +0x9B6B 0x5AD0 # 0 +0x9B6C 0x5B2A # 0 +0x9B6D 0x5B36 # 0 +0x9B6E 0x5B3E # 0 +0x9B6F 0x5B43 # 0 +0x9B70 0x5B45 # 0 +0x9B71 0x5B40 # 0 +0x9B72 0x5B51 # 0 +0x9B73 0x5B55 # 0 +0x9B74 0x5B5A # 0 +0x9B75 0x5B5B # 0 +0x9B76 0x5B65 # 0 +0x9B77 0x5B69 # 0 +0x9B78 0x5B70 # 0 +0x9B79 0x5B73 # 0 +0x9B7A 0x5B75 # 0 +0x9B7B 0x5B78 # 0 +0x9B7C 0x6588 # 0 +0x9B7D 0x5B7A # 0 +0x9B7E 0x5B80 # 0 +0x9B80 0x5B83 # 0 +0x9B81 0x5BA6 # 0 +0x9B82 0x5BB8 # 0 +0x9B83 0x5BC3 # 0 +0x9B84 0x5BC7 # 0 +0x9B85 0x5BC9 # 0 +0x9B86 0x5BD4 # 0 +0x9B87 0x5BD0 # 0 +0x9B88 0x5BE4 # 0 +0x9B89 0x5BE6 # 0 +0x9B8A 0x5BE2 # 0 +0x9B8B 0x5BDE # 0 +0x9B8C 0x5BE5 # 0 +0x9B8D 0x5BEB # 0 +0x9B8E 0x5BF0 # 0 +0x9B8F 0x5BF6 # 0 +0x9B90 0x5BF3 # 0 +0x9B91 0x5C05 # 0 +0x9B92 0x5C07 # 0 +0x9B93 0x5C08 # 0 +0x9B94 0x5C0D # 0 +0x9B95 0x5C13 # 0 +0x9B96 0x5C20 # 0 +0x9B97 0x5C22 # 0 +0x9B98 0x5C28 # 0 +0x9B99 0x5C38 # 0 +0x9B9A 0x5C39 # 0 +0x9B9B 0x5C41 # 0 +0x9B9C 0x5C46 # 0 +0x9B9D 0x5C4E # 0 +0x9B9E 0x5C53 # 0 +0x9B9F 0x5C50 # 0 +0x9BA0 0x5C4F # 0 +0x9BA1 0x5B71 # 0 +0x9BA2 0x5C6C # 0 +0x9BA3 0x5C6E # 0 +0x9BA4 0x4E62 # 0 +0x9BA5 0x5C76 # 0 +0x9BA6 0x5C79 # 0 +0x9BA7 0x5C8C # 0 +0x9BA8 0x5C91 # 0 +0x9BA9 0x5C94 # 0 +0x9BAA 0x599B # 0 +0x9BAB 0x5CAB # 0 +0x9BAC 0x5CBB # 0 +0x9BAD 0x5CB6 # 0 +0x9BAE 0x5CBC # 0 +0x9BAF 0x5CB7 # 0 +0x9BB0 0x5CC5 # 0 +0x9BB1 0x5CBE # 0 +0x9BB2 0x5CC7 # 0 +0x9BB3 0x5CD9 # 0 +0x9BB4 0x5CE9 # 0 +0x9BB5 0x5CFD # 0 +0x9BB6 0x5CFA # 0 +0x9BB7 0x5CED # 0 +0x9BB8 0x5D8C # 0 +0x9BB9 0x5CEA # 0 +0x9BBA 0x5D0B # 0 +0x9BBB 0x5D15 # 0 +0x9BBC 0x5D17 # 0 +0x9BBD 0x5D5C # 0 +0x9BBE 0x5D1F # 0 +0x9BBF 0x5D1B # 0 +0x9BC0 0x5D11 # 0 +0x9BC1 0x5D14 # 0 +0x9BC2 0x5D22 # 0 +0x9BC3 0x5D1A # 0 +0x9BC4 0x5D19 # 0 +0x9BC5 0x5D18 # 0 +0x9BC6 0x5D4C # 0 +0x9BC7 0x5D52 # 0 +0x9BC8 0x5D4E # 0 +0x9BC9 0x5D4B # 0 +0x9BCA 0x5D6C # 0 +0x9BCB 0x5D73 # 0 +0x9BCC 0x5D76 # 0 +0x9BCD 0x5D87 # 0 +0x9BCE 0x5D84 # 0 +0x9BCF 0x5D82 # 0 +0x9BD0 0x5DA2 # 0 +0x9BD1 0x5D9D # 0 +0x9BD2 0x5DAC # 0 +0x9BD3 0x5DAE # 0 +0x9BD4 0x5DBD # 0 +0x9BD5 0x5D90 # 0 +0x9BD6 0x5DB7 # 0 +0x9BD7 0x5DBC # 0 +0x9BD8 0x5DC9 # 0 +0x9BD9 0x5DCD # 0 +0x9BDA 0x5DD3 # 0 +0x9BDB 0x5DD2 # 0 +0x9BDC 0x5DD6 # 0 +0x9BDD 0x5DDB # 0 +0x9BDE 0x5DEB # 0 +0x9BDF 0x5DF2 # 0 +0x9BE0 0x5DF5 # 0 +0x9BE1 0x5E0B # 0 +0x9BE2 0x5E1A # 0 +0x9BE3 0x5E19 # 0 +0x9BE4 0x5E11 # 0 +0x9BE5 0x5E1B # 0 +0x9BE6 0x5E36 # 0 +0x9BE7 0x5E37 # 0 +0x9BE8 0x5E44 # 0 +0x9BE9 0x5E43 # 0 +0x9BEA 0x5E40 # 0 +0x9BEB 0x5E4E # 0 +0x9BEC 0x5E57 # 0 +0x9BED 0x5E54 # 0 +0x9BEE 0x5E5F # 0 +0x9BEF 0x5E62 # 0 +0x9BF0 0x5E64 # 0 +0x9BF1 0x5E47 # 0 +0x9BF2 0x5E75 # 0 +0x9BF3 0x5E76 # 0 +0x9BF4 0x5E7A # 0 +0x9BF5 0x9EBC # 0 +0x9BF6 0x5E7F # 0 +0x9BF7 0x5EA0 # 0 +0x9BF8 0x5EC1 # 0 +0x9BF9 0x5EC2 # 0 +0x9BFA 0x5EC8 # 0 +0x9BFB 0x5ED0 # 0 +0x9BFC 0x5ECF # 0 +0x9C40 0x5ED6 # 0 +0x9C41 0x5EE3 # 0 +0x9C42 0x5EDD # 0 +0x9C43 0x5EDA # 0 +0x9C44 0x5EDB # 0 +0x9C45 0x5EE2 # 0 +0x9C46 0x5EE1 # 0 +0x9C47 0x5EE8 # 0 +0x9C48 0x5EE9 # 0 +0x9C49 0x5EEC # 0 +0x9C4A 0x5EF1 # 0 +0x9C4B 0x5EF3 # 0 +0x9C4C 0x5EF0 # 0 +0x9C4D 0x5EF4 # 0 +0x9C4E 0x5EF8 # 0 +0x9C4F 0x5EFE # 0 +0x9C50 0x5F03 # 0 +0x9C51 0x5F09 # 0 +0x9C52 0x5F5D # 0 +0x9C53 0x5F5C # 0 +0x9C54 0x5F0B # 0 +0x9C55 0x5F11 # 0 +0x9C56 0x5F16 # 0 +0x9C57 0x5F29 # 0 +0x9C58 0x5F2D # 0 +0x9C59 0x5F38 # 0 +0x9C5A 0x5F41 # 0 +0x9C5B 0x5F48 # 0 +0x9C5C 0x5F4C # 0 +0x9C5D 0x5F4E # 0 +0x9C5E 0x5F2F # 0 +0x9C5F 0x5F51 # 0 +0x9C60 0x5F56 # 0 +0x9C61 0x5F57 # 0 +0x9C62 0x5F59 # 0 +0x9C63 0x5F61 # 0 +0x9C64 0x5F6D # 0 +0x9C65 0x5F73 # 0 +0x9C66 0x5F77 # 0 +0x9C67 0x5F83 # 0 +0x9C68 0x5F82 # 0 +0x9C69 0x5F7F # 0 +0x9C6A 0x5F8A # 0 +0x9C6B 0x5F88 # 0 +0x9C6C 0x5F91 # 0 +0x9C6D 0x5F87 # 0 +0x9C6E 0x5F9E # 0 +0x9C6F 0x5F99 # 0 +0x9C70 0x5F98 # 0 +0x9C71 0x5FA0 # 0 +0x9C72 0x5FA8 # 0 +0x9C73 0x5FAD # 0 +0x9C74 0x5FBC # 0 +0x9C75 0x5FD6 # 0 +0x9C76 0x5FFB # 0 +0x9C77 0x5FE4 # 0 +0x9C78 0x5FF8 # 0 +0x9C79 0x5FF1 # 0 +0x9C7A 0x5FDD # 0 +0x9C7B 0x60B3 # 0 +0x9C7C 0x5FFF # 0 +0x9C7D 0x6021 # 0 +0x9C7E 0x6060 # 0 +0x9C80 0x6019 # 0 +0x9C81 0x6010 # 0 +0x9C82 0x6029 # 0 +0x9C83 0x600E # 0 +0x9C84 0x6031 # 0 +0x9C85 0x601B # 0 +0x9C86 0x6015 # 0 +0x9C87 0x602B # 0 +0x9C88 0x6026 # 0 +0x9C89 0x600F # 0 +0x9C8A 0x603A # 0 +0x9C8B 0x605A # 0 +0x9C8C 0x6041 # 0 +0x9C8D 0x606A # 0 +0x9C8E 0x6077 # 0 +0x9C8F 0x605F # 0 +0x9C90 0x604A # 0 +0x9C91 0x6046 # 0 +0x9C92 0x604D # 0 +0x9C93 0x6063 # 0 +0x9C94 0x6043 # 0 +0x9C95 0x6064 # 0 +0x9C96 0x6042 # 0 +0x9C97 0x606C # 0 +0x9C98 0x606B # 0 +0x9C99 0x6059 # 0 +0x9C9A 0x6081 # 0 +0x9C9B 0x608D # 0 +0x9C9C 0x60E7 # 0 +0x9C9D 0x6083 # 0 +0x9C9E 0x609A # 0 +0x9C9F 0x6084 # 0 +0x9CA0 0x609B # 0 +0x9CA1 0x6096 # 0 +0x9CA2 0x6097 # 0 +0x9CA3 0x6092 # 0 +0x9CA4 0x60A7 # 0 +0x9CA5 0x608B # 0 +0x9CA6 0x60E1 # 0 +0x9CA7 0x60B8 # 0 +0x9CA8 0x60E0 # 0 +0x9CA9 0x60D3 # 0 +0x9CAA 0x60B4 # 0 +0x9CAB 0x5FF0 # 0 +0x9CAC 0x60BD # 0 +0x9CAD 0x60C6 # 0 +0x9CAE 0x60B5 # 0 +0x9CAF 0x60D8 # 0 +0x9CB0 0x614D # 0 +0x9CB1 0x6115 # 0 +0x9CB2 0x6106 # 0 +0x9CB3 0x60F6 # 0 +0x9CB4 0x60F7 # 0 +0x9CB5 0x6100 # 0 +0x9CB6 0x60F4 # 0 +0x9CB7 0x60FA # 0 +0x9CB8 0x6103 # 0 +0x9CB9 0x6121 # 0 +0x9CBA 0x60FB # 0 +0x9CBB 0x60F1 # 0 +0x9CBC 0x610D # 0 +0x9CBD 0x610E # 0 +0x9CBE 0x6147 # 0 +0x9CBF 0x613E # 0 +0x9CC0 0x6128 # 0 +0x9CC1 0x6127 # 0 +0x9CC2 0x614A # 0 +0x9CC3 0x613F # 0 +0x9CC4 0x613C # 0 +0x9CC5 0x612C # 0 +0x9CC6 0x6134 # 0 +0x9CC7 0x613D # 0 +0x9CC8 0x6142 # 0 +0x9CC9 0x6144 # 0 +0x9CCA 0x6173 # 0 +0x9CCB 0x6177 # 0 +0x9CCC 0x6158 # 0 +0x9CCD 0x6159 # 0 +0x9CCE 0x615A # 0 +0x9CCF 0x616B # 0 +0x9CD0 0x6174 # 0 +0x9CD1 0x616F # 0 +0x9CD2 0x6165 # 0 +0x9CD3 0x6171 # 0 +0x9CD4 0x615F # 0 +0x9CD5 0x615D # 0 +0x9CD6 0x6153 # 0 +0x9CD7 0x6175 # 0 +0x9CD8 0x6199 # 0 +0x9CD9 0x6196 # 0 +0x9CDA 0x6187 # 0 +0x9CDB 0x61AC # 0 +0x9CDC 0x6194 # 0 +0x9CDD 0x619A # 0 +0x9CDE 0x618A # 0 +0x9CDF 0x6191 # 0 +0x9CE0 0x61AB # 0 +0x9CE1 0x61AE # 0 +0x9CE2 0x61CC # 0 +0x9CE3 0x61CA # 0 +0x9CE4 0x61C9 # 0 +0x9CE5 0x61F7 # 0 +0x9CE6 0x61C8 # 0 +0x9CE7 0x61C3 # 0 +0x9CE8 0x61C6 # 0 +0x9CE9 0x61BA # 0 +0x9CEA 0x61CB # 0 +0x9CEB 0x7F79 # 0 +0x9CEC 0x61CD # 0 +0x9CED 0x61E6 # 0 +0x9CEE 0x61E3 # 0 +0x9CEF 0x61F6 # 0 +0x9CF0 0x61FA # 0 +0x9CF1 0x61F4 # 0 +0x9CF2 0x61FF # 0 +0x9CF3 0x61FD # 0 +0x9CF4 0x61FC # 0 +0x9CF5 0x61FE # 0 +0x9CF6 0x6200 # 0 +0x9CF7 0x6208 # 0 +0x9CF8 0x6209 # 0 +0x9CF9 0x620D # 0 +0x9CFA 0x620C # 0 +0x9CFB 0x6214 # 0 +0x9CFC 0x621B # 0 +0x9D40 0x621E # 0 +0x9D41 0x6221 # 0 +0x9D42 0x622A # 0 +0x9D43 0x622E # 0 +0x9D44 0x6230 # 0 +0x9D45 0x6232 # 0 +0x9D46 0x6233 # 0 +0x9D47 0x6241 # 0 +0x9D48 0x624E # 0 +0x9D49 0x625E # 0 +0x9D4A 0x6263 # 0 +0x9D4B 0x625B # 0 +0x9D4C 0x6260 # 0 +0x9D4D 0x6268 # 0 +0x9D4E 0x627C # 0 +0x9D4F 0x6282 # 0 +0x9D50 0x6289 # 0 +0x9D51 0x627E # 0 +0x9D52 0x6292 # 0 +0x9D53 0x6293 # 0 +0x9D54 0x6296 # 0 +0x9D55 0x62D4 # 0 +0x9D56 0x6283 # 0 +0x9D57 0x6294 # 0 +0x9D58 0x62D7 # 0 +0x9D59 0x62D1 # 0 +0x9D5A 0x62BB # 0 +0x9D5B 0x62CF # 0 +0x9D5C 0x62FF # 0 +0x9D5D 0x62C6 # 0 +0x9D5E 0x64D4 # 0 +0x9D5F 0x62C8 # 0 +0x9D60 0x62DC # 0 +0x9D61 0x62CC # 0 +0x9D62 0x62CA # 0 +0x9D63 0x62C2 # 0 +0x9D64 0x62C7 # 0 +0x9D65 0x629B # 0 +0x9D66 0x62C9 # 0 +0x9D67 0x630C # 0 +0x9D68 0x62EE # 0 +0x9D69 0x62F1 # 0 +0x9D6A 0x6327 # 0 +0x9D6B 0x6302 # 0 +0x9D6C 0x6308 # 0 +0x9D6D 0x62EF # 0 +0x9D6E 0x62F5 # 0 +0x9D6F 0x6350 # 0 +0x9D70 0x633E # 0 +0x9D71 0x634D # 0 +0x9D72 0x641C # 0 +0x9D73 0x634F # 0 +0x9D74 0x6396 # 0 +0x9D75 0x638E # 0 +0x9D76 0x6380 # 0 +0x9D77 0x63AB # 0 +0x9D78 0x6376 # 0 +0x9D79 0x63A3 # 0 +0x9D7A 0x638F # 0 +0x9D7B 0x6389 # 0 +0x9D7C 0x639F # 0 +0x9D7D 0x63B5 # 0 +0x9D7E 0x636B # 0 +0x9D80 0x6369 # 0 +0x9D81 0x63BE # 0 +0x9D82 0x63E9 # 0 +0x9D83 0x63C0 # 0 +0x9D84 0x63C6 # 0 +0x9D85 0x63E3 # 0 +0x9D86 0x63C9 # 0 +0x9D87 0x63D2 # 0 +0x9D88 0x63F6 # 0 +0x9D89 0x63C4 # 0 +0x9D8A 0x6416 # 0 +0x9D8B 0x6434 # 0 +0x9D8C 0x6406 # 0 +0x9D8D 0x6413 # 0 +0x9D8E 0x6426 # 0 +0x9D8F 0x6436 # 0 +0x9D90 0x651D # 0 +0x9D91 0x6417 # 0 +0x9D92 0x6428 # 0 +0x9D93 0x640F # 0 +0x9D94 0x6467 # 0 +0x9D95 0x646F # 0 +0x9D96 0x6476 # 0 +0x9D97 0x644E # 0 +0x9D98 0x652A # 0 +0x9D99 0x6495 # 0 +0x9D9A 0x6493 # 0 +0x9D9B 0x64A5 # 0 +0x9D9C 0x64A9 # 0 +0x9D9D 0x6488 # 0 +0x9D9E 0x64BC # 0 +0x9D9F 0x64DA # 0 +0x9DA0 0x64D2 # 0 +0x9DA1 0x64C5 # 0 +0x9DA2 0x64C7 # 0 +0x9DA3 0x64BB # 0 +0x9DA4 0x64D8 # 0 +0x9DA5 0x64C2 # 0 +0x9DA6 0x64F1 # 0 +0x9DA7 0x64E7 # 0 +0x9DA8 0x8209 # 0 +0x9DA9 0x64E0 # 0 +0x9DAA 0x64E1 # 0 +0x9DAB 0x62AC # 0 +0x9DAC 0x64E3 # 0 +0x9DAD 0x64EF # 0 +0x9DAE 0x652C # 0 +0x9DAF 0x64F6 # 0 +0x9DB0 0x64F4 # 0 +0x9DB1 0x64F2 # 0 +0x9DB2 0x64FA # 0 +0x9DB3 0x6500 # 0 +0x9DB4 0x64FD # 0 +0x9DB5 0x6518 # 0 +0x9DB6 0x651C # 0 +0x9DB7 0x6505 # 0 +0x9DB8 0x6524 # 0 +0x9DB9 0x6523 # 0 +0x9DBA 0x652B # 0 +0x9DBB 0x6534 # 0 +0x9DBC 0x6535 # 0 +0x9DBD 0x6537 # 0 +0x9DBE 0x6536 # 0 +0x9DBF 0x6538 # 0 +0x9DC0 0x754B # 0 +0x9DC1 0x6548 # 0 +0x9DC2 0x6556 # 0 +0x9DC3 0x6555 # 0 +0x9DC4 0x654D # 0 +0x9DC5 0x6558 # 0 +0x9DC6 0x655E # 0 +0x9DC7 0x655D # 0 +0x9DC8 0x6572 # 0 +0x9DC9 0x6578 # 0 +0x9DCA 0x6582 # 0 +0x9DCB 0x6583 # 0 +0x9DCC 0x8B8A # 0 +0x9DCD 0x659B # 0 +0x9DCE 0x659F # 0 +0x9DCF 0x65AB # 0 +0x9DD0 0x65B7 # 0 +0x9DD1 0x65C3 # 0 +0x9DD2 0x65C6 # 0 +0x9DD3 0x65C1 # 0 +0x9DD4 0x65C4 # 0 +0x9DD5 0x65CC # 0 +0x9DD6 0x65D2 # 0 +0x9DD7 0x65DB # 0 +0x9DD8 0x65D9 # 0 +0x9DD9 0x65E0 # 0 +0x9DDA 0x65E1 # 0 +0x9DDB 0x65F1 # 0 +0x9DDC 0x6772 # 0 +0x9DDD 0x660A # 0 +0x9DDE 0x6603 # 0 +0x9DDF 0x65FB # 0 +0x9DE0 0x6773 # 0 +0x9DE1 0x6635 # 0 +0x9DE2 0x6636 # 0 +0x9DE3 0x6634 # 0 +0x9DE4 0x661C # 0 +0x9DE5 0x664F # 0 +0x9DE6 0x6644 # 0 +0x9DE7 0x6649 # 0 +0x9DE8 0x6641 # 0 +0x9DE9 0x665E # 0 +0x9DEA 0x665D # 0 +0x9DEB 0x6664 # 0 +0x9DEC 0x6667 # 0 +0x9DED 0x6668 # 0 +0x9DEE 0x665F # 0 +0x9DEF 0x6662 # 0 +0x9DF0 0x6670 # 0 +0x9DF1 0x6683 # 0 +0x9DF2 0x6688 # 0 +0x9DF3 0x668E # 0 +0x9DF4 0x6689 # 0 +0x9DF5 0x6684 # 0 +0x9DF6 0x6698 # 0 +0x9DF7 0x669D # 0 +0x9DF8 0x66C1 # 0 +0x9DF9 0x66B9 # 0 +0x9DFA 0x66C9 # 0 +0x9DFB 0x66BE # 0 +0x9DFC 0x66BC # 0 +0x9E40 0x66C4 # 0 +0x9E41 0x66B8 # 0 +0x9E42 0x66D6 # 0 +0x9E43 0x66DA # 0 +0x9E44 0x66E0 # 0 +0x9E45 0x663F # 0 +0x9E46 0x66E6 # 0 +0x9E47 0x66E9 # 0 +0x9E48 0x66F0 # 0 +0x9E49 0x66F5 # 0 +0x9E4A 0x66F7 # 0 +0x9E4B 0x670F # 0 +0x9E4C 0x6716 # 0 +0x9E4D 0x671E # 0 +0x9E4E 0x6726 # 0 +0x9E4F 0x6727 # 0 +0x9E50 0x9738 # 0 +0x9E51 0x672E # 0 +0x9E52 0x673F # 0 +0x9E53 0x6736 # 0 +0x9E54 0x6741 # 0 +0x9E55 0x6738 # 0 +0x9E56 0x6737 # 0 +0x9E57 0x6746 # 0 +0x9E58 0x675E # 0 +0x9E59 0x6760 # 0 +0x9E5A 0x6759 # 0 +0x9E5B 0x6763 # 0 +0x9E5C 0x6764 # 0 +0x9E5D 0x6789 # 0 +0x9E5E 0x6770 # 0 +0x9E5F 0x67A9 # 0 +0x9E60 0x677C # 0 +0x9E61 0x676A # 0 +0x9E62 0x678C # 0 +0x9E63 0x678B # 0 +0x9E64 0x67A6 # 0 +0x9E65 0x67A1 # 0 +0x9E66 0x6785 # 0 +0x9E67 0x67B7 # 0 +0x9E68 0x67EF # 0 +0x9E69 0x67B4 # 0 +0x9E6A 0x67EC # 0 +0x9E6B 0x67B3 # 0 +0x9E6C 0x67E9 # 0 +0x9E6D 0x67B8 # 0 +0x9E6E 0x67E4 # 0 +0x9E6F 0x67DE # 0 +0x9E70 0x67DD # 0 +0x9E71 0x67E2 # 0 +0x9E72 0x67EE # 0 +0x9E73 0x67B9 # 0 +0x9E74 0x67CE # 0 +0x9E75 0x67C6 # 0 +0x9E76 0x67E7 # 0 +0x9E77 0x6A9C # 0 +0x9E78 0x681E # 0 +0x9E79 0x6846 # 0 +0x9E7A 0x6829 # 0 +0x9E7B 0x6840 # 0 +0x9E7C 0x684D # 0 +0x9E7D 0x6832 # 0 +0x9E7E 0x684E # 0 +0x9E80 0x68B3 # 0 +0x9E81 0x682B # 0 +0x9E82 0x6859 # 0 +0x9E83 0x6863 # 0 +0x9E84 0x6877 # 0 +0x9E85 0x687F # 0 +0x9E86 0x689F # 0 +0x9E87 0x688F # 0 +0x9E88 0x68AD # 0 +0x9E89 0x6894 # 0 +0x9E8A 0x689D # 0 +0x9E8B 0x689B # 0 +0x9E8C 0x6883 # 0 +0x9E8D 0x6AAE # 0 +0x9E8E 0x68B9 # 0 +0x9E8F 0x6874 # 0 +0x9E90 0x68B5 # 0 +0x9E91 0x68A0 # 0 +0x9E92 0x68BA # 0 +0x9E93 0x690F # 0 +0x9E94 0x688D # 0 +0x9E95 0x687E # 0 +0x9E96 0x6901 # 0 +0x9E97 0x68CA # 0 +0x9E98 0x6908 # 0 +0x9E99 0x68D8 # 0 +0x9E9A 0x6922 # 0 +0x9E9B 0x6926 # 0 +0x9E9C 0x68E1 # 0 +0x9E9D 0x690C # 0 +0x9E9E 0x68CD # 0 +0x9E9F 0x68D4 # 0 +0x9EA0 0x68E7 # 0 +0x9EA1 0x68D5 # 0 +0x9EA2 0x6936 # 0 +0x9EA3 0x6912 # 0 +0x9EA4 0x6904 # 0 +0x9EA5 0x68D7 # 0 +0x9EA6 0x68E3 # 0 +0x9EA7 0x6925 # 0 +0x9EA8 0x68F9 # 0 +0x9EA9 0x68E0 # 0 +0x9EAA 0x68EF # 0 +0x9EAB 0x6928 # 0 +0x9EAC 0x692A # 0 +0x9EAD 0x691A # 0 +0x9EAE 0x6923 # 0 +0x9EAF 0x6921 # 0 +0x9EB0 0x68C6 # 0 +0x9EB1 0x6979 # 0 +0x9EB2 0x6977 # 0 +0x9EB3 0x695C # 0 +0x9EB4 0x6978 # 0 +0x9EB5 0x696B # 0 +0x9EB6 0x6954 # 0 +0x9EB7 0x697E # 0 +0x9EB8 0x696E # 0 +0x9EB9 0x6939 # 0 +0x9EBA 0x6974 # 0 +0x9EBB 0x693D # 0 +0x9EBC 0x6959 # 0 +0x9EBD 0x6930 # 0 +0x9EBE 0x6961 # 0 +0x9EBF 0x695E # 0 +0x9EC0 0x695D # 0 +0x9EC1 0x6981 # 0 +0x9EC2 0x696A # 0 +0x9EC3 0x69B2 # 0 +0x9EC4 0x69AE # 0 +0x9EC5 0x69D0 # 0 +0x9EC6 0x69BF # 0 +0x9EC7 0x69C1 # 0 +0x9EC8 0x69D3 # 0 +0x9EC9 0x69BE # 0 +0x9ECA 0x69CE # 0 +0x9ECB 0x5BE8 # 0 +0x9ECC 0x69CA # 0 +0x9ECD 0x69DD # 0 +0x9ECE 0x69BB # 0 +0x9ECF 0x69C3 # 0 +0x9ED0 0x69A7 # 0 +0x9ED1 0x6A2E # 0 +0x9ED2 0x6991 # 0 +0x9ED3 0x69A0 # 0 +0x9ED4 0x699C # 0 +0x9ED5 0x6995 # 0 +0x9ED6 0x69B4 # 0 +0x9ED7 0x69DE # 0 +0x9ED8 0x69E8 # 0 +0x9ED9 0x6A02 # 0 +0x9EDA 0x6A1B # 0 +0x9EDB 0x69FF # 0 +0x9EDC 0x6B0A # 0 +0x9EDD 0x69F9 # 0 +0x9EDE 0x69F2 # 0 +0x9EDF 0x69E7 # 0 +0x9EE0 0x6A05 # 0 +0x9EE1 0x69B1 # 0 +0x9EE2 0x6A1E # 0 +0x9EE3 0x69ED # 0 +0x9EE4 0x6A14 # 0 +0x9EE5 0x69EB # 0 +0x9EE6 0x6A0A # 0 +0x9EE7 0x6A12 # 0 +0x9EE8 0x6AC1 # 0 +0x9EE9 0x6A23 # 0 +0x9EEA 0x6A13 # 0 +0x9EEB 0x6A44 # 0 +0x9EEC 0x6A0C # 0 +0x9EED 0x6A72 # 0 +0x9EEE 0x6A36 # 0 +0x9EEF 0x6A78 # 0 +0x9EF0 0x6A47 # 0 +0x9EF1 0x6A62 # 0 +0x9EF2 0x6A59 # 0 +0x9EF3 0x6A66 # 0 +0x9EF4 0x6A48 # 0 +0x9EF5 0x6A38 # 0 +0x9EF6 0x6A22 # 0 +0x9EF7 0x6A90 # 0 +0x9EF8 0x6A8D # 0 +0x9EF9 0x6AA0 # 0 +0x9EFA 0x6A84 # 0 +0x9EFB 0x6AA2 # 0 +0x9EFC 0x6AA3 # 0 +0x9F40 0x6A97 # 0 +0x9F41 0x8617 # 0 +0x9F42 0x6ABB # 0 +0x9F43 0x6AC3 # 0 +0x9F44 0x6AC2 # 0 +0x9F45 0x6AB8 # 0 +0x9F46 0x6AB3 # 0 +0x9F47 0x6AAC # 0 +0x9F48 0x6ADE # 0 +0x9F49 0x6AD1 # 0 +0x9F4A 0x6ADF # 0 +0x9F4B 0x6AAA # 0 +0x9F4C 0x6ADA # 0 +0x9F4D 0x6AEA # 0 +0x9F4E 0x6AFB # 0 +0x9F4F 0x6B05 # 0 +0x9F50 0x8616 # 0 +0x9F51 0x6AFA # 0 +0x9F52 0x6B12 # 0 +0x9F53 0x6B16 # 0 +0x9F54 0x9B31 # 0 +0x9F55 0x6B1F # 0 +0x9F56 0x6B38 # 0 +0x9F57 0x6B37 # 0 +0x9F58 0x76DC # 0 +0x9F59 0x6B39 # 0 +0x9F5A 0x98EE # 0 +0x9F5B 0x6B47 # 0 +0x9F5C 0x6B43 # 0 +0x9F5D 0x6B49 # 0 +0x9F5E 0x6B50 # 0 +0x9F5F 0x6B59 # 0 +0x9F60 0x6B54 # 0 +0x9F61 0x6B5B # 0 +0x9F62 0x6B5F # 0 +0x9F63 0x6B61 # 0 +0x9F64 0x6B78 # 0 +0x9F65 0x6B79 # 0 +0x9F66 0x6B7F # 0 +0x9F67 0x6B80 # 0 +0x9F68 0x6B84 # 0 +0x9F69 0x6B83 # 0 +0x9F6A 0x6B8D # 0 +0x9F6B 0x6B98 # 0 +0x9F6C 0x6B95 # 0 +0x9F6D 0x6B9E # 0 +0x9F6E 0x6BA4 # 0 +0x9F6F 0x6BAA # 0 +0x9F70 0x6BAB # 0 +0x9F71 0x6BAF # 0 +0x9F72 0x6BB2 # 0 +0x9F73 0x6BB1 # 0 +0x9F74 0x6BB3 # 0 +0x9F75 0x6BB7 # 0 +0x9F76 0x6BBC # 0 +0x9F77 0x6BC6 # 0 +0x9F78 0x6BCB # 0 +0x9F79 0x6BD3 # 0 +0x9F7A 0x6BDF # 0 +0x9F7B 0x6BEC # 0 +0x9F7C 0x6BEB # 0 +0x9F7D 0x6BF3 # 0 +0x9F7E 0x6BEF # 0 +0x9F80 0x9EBE # 0 +0x9F81 0x6C08 # 0 +0x9F82 0x6C13 # 0 +0x9F83 0x6C14 # 0 +0x9F84 0x6C1B # 0 +0x9F85 0x6C24 # 0 +0x9F86 0x6C23 # 0 +0x9F87 0x6C5E # 0 +0x9F88 0x6C55 # 0 +0x9F89 0x6C62 # 0 +0x9F8A 0x6C6A # 0 +0x9F8B 0x6C82 # 0 +0x9F8C 0x6C8D # 0 +0x9F8D 0x6C9A # 0 +0x9F8E 0x6C81 # 0 +0x9F8F 0x6C9B # 0 +0x9F90 0x6C7E # 0 +0x9F91 0x6C68 # 0 +0x9F92 0x6C73 # 0 +0x9F93 0x6C92 # 0 +0x9F94 0x6C90 # 0 +0x9F95 0x6CC4 # 0 +0x9F96 0x6CF1 # 0 +0x9F97 0x6CD3 # 0 +0x9F98 0x6CBD # 0 +0x9F99 0x6CD7 # 0 +0x9F9A 0x6CC5 # 0 +0x9F9B 0x6CDD # 0 +0x9F9C 0x6CAE # 0 +0x9F9D 0x6CB1 # 0 +0x9F9E 0x6CBE # 0 +0x9F9F 0x6CBA # 0 +0x9FA0 0x6CDB # 0 +0x9FA1 0x6CEF # 0 +0x9FA2 0x6CD9 # 0 +0x9FA3 0x6CEA # 0 +0x9FA4 0x6D1F # 0 +0x9FA5 0x884D # 0 +0x9FA6 0x6D36 # 0 +0x9FA7 0x6D2B # 0 +0x9FA8 0x6D3D # 0 +0x9FA9 0x6D38 # 0 +0x9FAA 0x6D19 # 0 +0x9FAB 0x6D35 # 0 +0x9FAC 0x6D33 # 0 +0x9FAD 0x6D12 # 0 +0x9FAE 0x6D0C # 0 +0x9FAF 0x6D63 # 0 +0x9FB0 0x6D93 # 0 +0x9FB1 0x6D64 # 0 +0x9FB2 0x6D5A # 0 +0x9FB3 0x6D79 # 0 +0x9FB4 0x6D59 # 0 +0x9FB5 0x6D8E # 0 +0x9FB6 0x6D95 # 0 +0x9FB7 0x6FE4 # 0 +0x9FB8 0x6D85 # 0 +0x9FB9 0x6DF9 # 0 +0x9FBA 0x6E15 # 0 +0x9FBB 0x6E0A # 0 +0x9FBC 0x6DB5 # 0 +0x9FBD 0x6DC7 # 0 +0x9FBE 0x6DE6 # 0 +0x9FBF 0x6DB8 # 0 +0x9FC0 0x6DC6 # 0 +0x9FC1 0x6DEC # 0 +0x9FC2 0x6DDE # 0 +0x9FC3 0x6DCC # 0 +0x9FC4 0x6DE8 # 0 +0x9FC5 0x6DD2 # 0 +0x9FC6 0x6DC5 # 0 +0x9FC7 0x6DFA # 0 +0x9FC8 0x6DD9 # 0 +0x9FC9 0x6DE4 # 0 +0x9FCA 0x6DD5 # 0 +0x9FCB 0x6DEA # 0 +0x9FCC 0x6DEE # 0 +0x9FCD 0x6E2D # 0 +0x9FCE 0x6E6E # 0 +0x9FCF 0x6E2E # 0 +0x9FD0 0x6E19 # 0 +0x9FD1 0x6E72 # 0 +0x9FD2 0x6E5F # 0 +0x9FD3 0x6E3E # 0 +0x9FD4 0x6E23 # 0 +0x9FD5 0x6E6B # 0 +0x9FD6 0x6E2B # 0 +0x9FD7 0x6E76 # 0 +0x9FD8 0x6E4D # 0 +0x9FD9 0x6E1F # 0 +0x9FDA 0x6E43 # 0 +0x9FDB 0x6E3A # 0 +0x9FDC 0x6E4E # 0 +0x9FDD 0x6E24 # 0 +0x9FDE 0x6EFF # 0 +0x9FDF 0x6E1D # 0 +0x9FE0 0x6E38 # 0 +0x9FE1 0x6E82 # 0 +0x9FE2 0x6EAA # 0 +0x9FE3 0x6E98 # 0 +0x9FE4 0x6EC9 # 0 +0x9FE5 0x6EB7 # 0 +0x9FE6 0x6ED3 # 0 +0x9FE7 0x6EBD # 0 +0x9FE8 0x6EAF # 0 +0x9FE9 0x6EC4 # 0 +0x9FEA 0x6EB2 # 0 +0x9FEB 0x6ED4 # 0 +0x9FEC 0x6ED5 # 0 +0x9FED 0x6E8F # 0 +0x9FEE 0x6EA5 # 0 +0x9FEF 0x6EC2 # 0 +0x9FF0 0x6E9F # 0 +0x9FF1 0x6F41 # 0 +0x9FF2 0x6F11 # 0 +0x9FF3 0x704C # 0 +0x9FF4 0x6EEC # 0 +0x9FF5 0x6EF8 # 0 +0x9FF6 0x6EFE # 0 +0x9FF7 0x6F3F # 0 +0x9FF8 0x6EF2 # 0 +0x9FF9 0x6F31 # 0 +0x9FFA 0x6EEF # 0 +0x9FFB 0x6F32 # 0 +0x9FFC 0x6ECC # 0 +0xE040 0x6F3E # 0 +0xE041 0x6F13 # 0 +0xE042 0x6EF7 # 0 +0xE043 0x6F86 # 0 +0xE044 0x6F7A # 0 +0xE045 0x6F78 # 0 +0xE046 0x6F81 # 0 +0xE047 0x6F80 # 0 +0xE048 0x6F6F # 0 +0xE049 0x6F5B # 0 +0xE04A 0x6FF3 # 0 +0xE04B 0x6F6D # 0 +0xE04C 0x6F82 # 0 +0xE04D 0x6F7C # 0 +0xE04E 0x6F58 # 0 +0xE04F 0x6F8E # 0 +0xE050 0x6F91 # 0 +0xE051 0x6FC2 # 0 +0xE052 0x6F66 # 0 +0xE053 0x6FB3 # 0 +0xE054 0x6FA3 # 0 +0xE055 0x6FA1 # 0 +0xE056 0x6FA4 # 0 +0xE057 0x6FB9 # 0 +0xE058 0x6FC6 # 0 +0xE059 0x6FAA # 0 +0xE05A 0x6FDF # 0 +0xE05B 0x6FD5 # 0 +0xE05C 0x6FEC # 0 +0xE05D 0x6FD4 # 0 +0xE05E 0x6FD8 # 0 +0xE05F 0x6FF1 # 0 +0xE060 0x6FEE # 0 +0xE061 0x6FDB # 0 +0xE062 0x7009 # 0 +0xE063 0x700B # 0 +0xE064 0x6FFA # 0 +0xE065 0x7011 # 0 +0xE066 0x7001 # 0 +0xE067 0x700F # 0 +0xE068 0x6FFE # 0 +0xE069 0x701B # 0 +0xE06A 0x701A # 0 +0xE06B 0x6F74 # 0 +0xE06C 0x701D # 0 +0xE06D 0x7018 # 0 +0xE06E 0x701F # 0 +0xE06F 0x7030 # 0 +0xE070 0x703E # 0 +0xE071 0x7032 # 0 +0xE072 0x7051 # 0 +0xE073 0x7063 # 0 +0xE074 0x7099 # 0 +0xE075 0x7092 # 0 +0xE076 0x70AF # 0 +0xE077 0x70F1 # 0 +0xE078 0x70AC # 0 +0xE079 0x70B8 # 0 +0xE07A 0x70B3 # 0 +0xE07B 0x70AE # 0 +0xE07C 0x70DF # 0 +0xE07D 0x70CB # 0 +0xE07E 0x70DD # 0 +0xE080 0x70D9 # 0 +0xE081 0x7109 # 0 +0xE082 0x70FD # 0 +0xE083 0x711C # 0 +0xE084 0x7119 # 0 +0xE085 0x7165 # 0 +0xE086 0x7155 # 0 +0xE087 0x7188 # 0 +0xE088 0x7166 # 0 +0xE089 0x7162 # 0 +0xE08A 0x714C # 0 +0xE08B 0x7156 # 0 +0xE08C 0x716C # 0 +0xE08D 0x718F # 0 +0xE08E 0x71FB # 0 +0xE08F 0x7184 # 0 +0xE090 0x7195 # 0 +0xE091 0x71A8 # 0 +0xE092 0x71AC # 0 +0xE093 0x71D7 # 0 +0xE094 0x71B9 # 0 +0xE095 0x71BE # 0 +0xE096 0x71D2 # 0 +0xE097 0x71C9 # 0 +0xE098 0x71D4 # 0 +0xE099 0x71CE # 0 +0xE09A 0x71E0 # 0 +0xE09B 0x71EC # 0 +0xE09C 0x71E7 # 0 +0xE09D 0x71F5 # 0 +0xE09E 0x71FC # 0 +0xE09F 0x71F9 # 0 +0xE0A0 0x71FF # 0 +0xE0A1 0x720D # 0 +0xE0A2 0x7210 # 0 +0xE0A3 0x721B # 0 +0xE0A4 0x7228 # 0 +0xE0A5 0x722D # 0 +0xE0A6 0x722C # 0 +0xE0A7 0x7230 # 0 +0xE0A8 0x7232 # 0 +0xE0A9 0x723B # 0 +0xE0AA 0x723C # 0 +0xE0AB 0x723F # 0 +0xE0AC 0x7240 # 0 +0xE0AD 0x7246 # 0 +0xE0AE 0x724B # 0 +0xE0AF 0x7258 # 0 +0xE0B0 0x7274 # 0 +0xE0B1 0x727E # 0 +0xE0B2 0x7282 # 0 +0xE0B3 0x7281 # 0 +0xE0B4 0x7287 # 0 +0xE0B5 0x7292 # 0 +0xE0B6 0x7296 # 0 +0xE0B7 0x72A2 # 0 +0xE0B8 0x72A7 # 0 +0xE0B9 0x72B9 # 0 +0xE0BA 0x72B2 # 0 +0xE0BB 0x72C3 # 0 +0xE0BC 0x72C6 # 0 +0xE0BD 0x72C4 # 0 +0xE0BE 0x72CE # 0 +0xE0BF 0x72D2 # 0 +0xE0C0 0x72E2 # 0 +0xE0C1 0x72E0 # 0 +0xE0C2 0x72E1 # 0 +0xE0C3 0x72F9 # 0 +0xE0C4 0x72F7 # 0 +0xE0C5 0x500F # 0 +0xE0C6 0x7317 # 0 +0xE0C7 0x730A # 0 +0xE0C8 0x731C # 0 +0xE0C9 0x7316 # 0 +0xE0CA 0x731D # 0 +0xE0CB 0x7334 # 0 +0xE0CC 0x732F # 0 +0xE0CD 0x7329 # 0 +0xE0CE 0x7325 # 0 +0xE0CF 0x733E # 0 +0xE0D0 0x734E # 0 +0xE0D1 0x734F # 0 +0xE0D2 0x9ED8 # 0 +0xE0D3 0x7357 # 0 +0xE0D4 0x736A # 0 +0xE0D5 0x7368 # 0 +0xE0D6 0x7370 # 0 +0xE0D7 0x7378 # 0 +0xE0D8 0x7375 # 0 +0xE0D9 0x737B # 0 +0xE0DA 0x737A # 0 +0xE0DB 0x73C8 # 0 +0xE0DC 0x73B3 # 0 +0xE0DD 0x73CE # 0 +0xE0DE 0x73BB # 0 +0xE0DF 0x73C0 # 0 +0xE0E0 0x73E5 # 0 +0xE0E1 0x73EE # 0 +0xE0E2 0x73DE # 0 +0xE0E3 0x74A2 # 0 +0xE0E4 0x7405 # 0 +0xE0E5 0x746F # 0 +0xE0E6 0x7425 # 0 +0xE0E7 0x73F8 # 0 +0xE0E8 0x7432 # 0 +0xE0E9 0x743A # 0 +0xE0EA 0x7455 # 0 +0xE0EB 0x743F # 0 +0xE0EC 0x745F # 0 +0xE0ED 0x7459 # 0 +0xE0EE 0x7441 # 0 +0xE0EF 0x745C # 0 +0xE0F0 0x7469 # 0 +0xE0F1 0x7470 # 0 +0xE0F2 0x7463 # 0 +0xE0F3 0x746A # 0 +0xE0F4 0x7476 # 0 +0xE0F5 0x747E # 0 +0xE0F6 0x748B # 0 +0xE0F7 0x749E # 0 +0xE0F8 0x74A7 # 0 +0xE0F9 0x74CA # 0 +0xE0FA 0x74CF # 0 +0xE0FB 0x74D4 # 0 +0xE0FC 0x73F1 # 0 +0xE140 0x74E0 # 0 +0xE141 0x74E3 # 0 +0xE142 0x74E7 # 0 +0xE143 0x74E9 # 0 +0xE144 0x74EE # 0 +0xE145 0x74F2 # 0 +0xE146 0x74F0 # 0 +0xE147 0x74F1 # 0 +0xE148 0x74F8 # 0 +0xE149 0x74F7 # 0 +0xE14A 0x7504 # 0 +0xE14B 0x7503 # 0 +0xE14C 0x7505 # 0 +0xE14D 0x750C # 0 +0xE14E 0x750E # 0 +0xE14F 0x750D # 0 +0xE150 0x7515 # 0 +0xE151 0x7513 # 0 +0xE152 0x751E # 0 +0xE153 0x7526 # 0 +0xE154 0x752C # 0 +0xE155 0x753C # 0 +0xE156 0x7544 # 0 +0xE157 0x754D # 0 +0xE158 0x754A # 0 +0xE159 0x7549 # 0 +0xE15A 0x755B # 0 +0xE15B 0x7546 # 0 +0xE15C 0x755A # 0 +0xE15D 0x7569 # 0 +0xE15E 0x7564 # 0 +0xE15F 0x7567 # 0 +0xE160 0x756B # 0 +0xE161 0x756D # 0 +0xE162 0x7578 # 0 +0xE163 0x7576 # 0 +0xE164 0x7586 # 0 +0xE165 0x7587 # 0 +0xE166 0x7574 # 0 +0xE167 0x758A # 0 +0xE168 0x7589 # 0 +0xE169 0x7582 # 0 +0xE16A 0x7594 # 0 +0xE16B 0x759A # 0 +0xE16C 0x759D # 0 +0xE16D 0x75A5 # 0 +0xE16E 0x75A3 # 0 +0xE16F 0x75C2 # 0 +0xE170 0x75B3 # 0 +0xE171 0x75C3 # 0 +0xE172 0x75B5 # 0 +0xE173 0x75BD # 0 +0xE174 0x75B8 # 0 +0xE175 0x75BC # 0 +0xE176 0x75B1 # 0 +0xE177 0x75CD # 0 +0xE178 0x75CA # 0 +0xE179 0x75D2 # 0 +0xE17A 0x75D9 # 0 +0xE17B 0x75E3 # 0 +0xE17C 0x75DE # 0 +0xE17D 0x75FE # 0 +0xE17E 0x75FF # 0 +0xE180 0x75FC # 0 +0xE181 0x7601 # 0 +0xE182 0x75F0 # 0 +0xE183 0x75FA # 0 +0xE184 0x75F2 # 0 +0xE185 0x75F3 # 0 +0xE186 0x760B # 0 +0xE187 0x760D # 0 +0xE188 0x7609 # 0 +0xE189 0x761F # 0 +0xE18A 0x7627 # 0 +0xE18B 0x7620 # 0 +0xE18C 0x7621 # 0 +0xE18D 0x7622 # 0 +0xE18E 0x7624 # 0 +0xE18F 0x7634 # 0 +0xE190 0x7630 # 0 +0xE191 0x763B # 0 +0xE192 0x7647 # 0 +0xE193 0x7648 # 0 +0xE194 0x7646 # 0 +0xE195 0x765C # 0 +0xE196 0x7658 # 0 +0xE197 0x7661 # 0 +0xE198 0x7662 # 0 +0xE199 0x7668 # 0 +0xE19A 0x7669 # 0 +0xE19B 0x766A # 0 +0xE19C 0x7667 # 0 +0xE19D 0x766C # 0 +0xE19E 0x7670 # 0 +0xE19F 0x7672 # 0 +0xE1A0 0x7676 # 0 +0xE1A1 0x7678 # 0 +0xE1A2 0x767C # 0 +0xE1A3 0x7680 # 0 +0xE1A4 0x7683 # 0 +0xE1A5 0x7688 # 0 +0xE1A6 0x768B # 0 +0xE1A7 0x768E # 0 +0xE1A8 0x7696 # 0 +0xE1A9 0x7693 # 0 +0xE1AA 0x7699 # 0 +0xE1AB 0x769A # 0 +0xE1AC 0x76B0 # 0 +0xE1AD 0x76B4 # 0 +0xE1AE 0x76B8 # 0 +0xE1AF 0x76B9 # 0 +0xE1B0 0x76BA # 0 +0xE1B1 0x76C2 # 0 +0xE1B2 0x76CD # 0 +0xE1B3 0x76D6 # 0 +0xE1B4 0x76D2 # 0 +0xE1B5 0x76DE # 0 +0xE1B6 0x76E1 # 0 +0xE1B7 0x76E5 # 0 +0xE1B8 0x76E7 # 0 +0xE1B9 0x76EA # 0 +0xE1BA 0x862F # 0 +0xE1BB 0x76FB # 0 +0xE1BC 0x7708 # 0 +0xE1BD 0x7707 # 0 +0xE1BE 0x7704 # 0 +0xE1BF 0x7729 # 0 +0xE1C0 0x7724 # 0 +0xE1C1 0x771E # 0 +0xE1C2 0x7725 # 0 +0xE1C3 0x7726 # 0 +0xE1C4 0x771B # 0 +0xE1C5 0x7737 # 0 +0xE1C6 0x7738 # 0 +0xE1C7 0x7747 # 0 +0xE1C8 0x775A # 0 +0xE1C9 0x7768 # 0 +0xE1CA 0x776B # 0 +0xE1CB 0x775B # 0 +0xE1CC 0x7765 # 0 +0xE1CD 0x777F # 0 +0xE1CE 0x777E # 0 +0xE1CF 0x7779 # 0 +0xE1D0 0x778E # 0 +0xE1D1 0x778B # 0 +0xE1D2 0x7791 # 0 +0xE1D3 0x77A0 # 0 +0xE1D4 0x779E # 0 +0xE1D5 0x77B0 # 0 +0xE1D6 0x77B6 # 0 +0xE1D7 0x77B9 # 0 +0xE1D8 0x77BF # 0 +0xE1D9 0x77BC # 0 +0xE1DA 0x77BD # 0 +0xE1DB 0x77BB # 0 +0xE1DC 0x77C7 # 0 +0xE1DD 0x77CD # 0 +0xE1DE 0x77D7 # 0 +0xE1DF 0x77DA # 0 +0xE1E0 0x77DC # 0 +0xE1E1 0x77E3 # 0 +0xE1E2 0x77EE # 0 +0xE1E3 0x77FC # 0 +0xE1E4 0x780C # 0 +0xE1E5 0x7812 # 0 +0xE1E6 0x7926 # 0 +0xE1E7 0x7820 # 0 +0xE1E8 0x792A # 0 +0xE1E9 0x7845 # 0 +0xE1EA 0x788E # 0 +0xE1EB 0x7874 # 0 +0xE1EC 0x7886 # 0 +0xE1ED 0x787C # 0 +0xE1EE 0x789A # 0 +0xE1EF 0x788C # 0 +0xE1F0 0x78A3 # 0 +0xE1F1 0x78B5 # 0 +0xE1F2 0x78AA # 0 +0xE1F3 0x78AF # 0 +0xE1F4 0x78D1 # 0 +0xE1F5 0x78C6 # 0 +0xE1F6 0x78CB # 0 +0xE1F7 0x78D4 # 0 +0xE1F8 0x78BE # 0 +0xE1F9 0x78BC # 0 +0xE1FA 0x78C5 # 0 +0xE1FB 0x78CA # 0 +0xE1FC 0x78EC # 0 +0xE240 0x78E7 # 0 +0xE241 0x78DA # 0 +0xE242 0x78FD # 0 +0xE243 0x78F4 # 0 +0xE244 0x7907 # 0 +0xE245 0x7912 # 0 +0xE246 0x7911 # 0 +0xE247 0x7919 # 0 +0xE248 0x792C # 0 +0xE249 0x792B # 0 +0xE24A 0x7940 # 0 +0xE24B 0x7960 # 0 +0xE24C 0x7957 # 0 +0xE24D 0x795F # 0 +0xE24E 0x795A # 0 +0xE24F 0x7955 # 0 +0xE250 0x7953 # 0 +0xE251 0x797A # 0 +0xE252 0x797F # 0 +0xE253 0x798A # 0 +0xE254 0x799D # 0 +0xE255 0x79A7 # 0 +0xE256 0x9F4B # 0 +0xE257 0x79AA # 0 +0xE258 0x79AE # 0 +0xE259 0x79B3 # 0 +0xE25A 0x79B9 # 0 +0xE25B 0x79BA # 0 +0xE25C 0x79C9 # 0 +0xE25D 0x79D5 # 0 +0xE25E 0x79E7 # 0 +0xE25F 0x79EC # 0 +0xE260 0x79E1 # 0 +0xE261 0x79E3 # 0 +0xE262 0x7A08 # 0 +0xE263 0x7A0D # 0 +0xE264 0x7A18 # 0 +0xE265 0x7A19 # 0 +0xE266 0x7A20 # 0 +0xE267 0x7A1F # 0 +0xE268 0x7980 # 0 +0xE269 0x7A31 # 0 +0xE26A 0x7A3B # 0 +0xE26B 0x7A3E # 0 +0xE26C 0x7A37 # 0 +0xE26D 0x7A43 # 0 +0xE26E 0x7A57 # 0 +0xE26F 0x7A49 # 0 +0xE270 0x7A61 # 0 +0xE271 0x7A62 # 0 +0xE272 0x7A69 # 0 +0xE273 0x9F9D # 0 +0xE274 0x7A70 # 0 +0xE275 0x7A79 # 0 +0xE276 0x7A7D # 0 +0xE277 0x7A88 # 0 +0xE278 0x7A97 # 0 +0xE279 0x7A95 # 0 +0xE27A 0x7A98 # 0 +0xE27B 0x7A96 # 0 +0xE27C 0x7AA9 # 0 +0xE27D 0x7AC8 # 0 +0xE27E 0x7AB0 # 0 +0xE280 0x7AB6 # 0 +0xE281 0x7AC5 # 0 +0xE282 0x7AC4 # 0 +0xE283 0x7ABF # 0 +0xE284 0x9083 # 0 +0xE285 0x7AC7 # 0 +0xE286 0x7ACA # 0 +0xE287 0x7ACD # 0 +0xE288 0x7ACF # 0 +0xE289 0x7AD5 # 0 +0xE28A 0x7AD3 # 0 +0xE28B 0x7AD9 # 0 +0xE28C 0x7ADA # 0 +0xE28D 0x7ADD # 0 +0xE28E 0x7AE1 # 0 +0xE28F 0x7AE2 # 0 +0xE290 0x7AE6 # 0 +0xE291 0x7AED # 0 +0xE292 0x7AF0 # 0 +0xE293 0x7B02 # 0 +0xE294 0x7B0F # 0 +0xE295 0x7B0A # 0 +0xE296 0x7B06 # 0 +0xE297 0x7B33 # 0 +0xE298 0x7B18 # 0 +0xE299 0x7B19 # 0 +0xE29A 0x7B1E # 0 +0xE29B 0x7B35 # 0 +0xE29C 0x7B28 # 0 +0xE29D 0x7B36 # 0 +0xE29E 0x7B50 # 0 +0xE29F 0x7B7A # 0 +0xE2A0 0x7B04 # 0 +0xE2A1 0x7B4D # 0 +0xE2A2 0x7B0B # 0 +0xE2A3 0x7B4C # 0 +0xE2A4 0x7B45 # 0 +0xE2A5 0x7B75 # 0 +0xE2A6 0x7B65 # 0 +0xE2A7 0x7B74 # 0 +0xE2A8 0x7B67 # 0 +0xE2A9 0x7B70 # 0 +0xE2AA 0x7B71 # 0 +0xE2AB 0x7B6C # 0 +0xE2AC 0x7B6E # 0 +0xE2AD 0x7B9D # 0 +0xE2AE 0x7B98 # 0 +0xE2AF 0x7B9F # 0 +0xE2B0 0x7B8D # 0 +0xE2B1 0x7B9C # 0 +0xE2B2 0x7B9A # 0 +0xE2B3 0x7B8B # 0 +0xE2B4 0x7B92 # 0 +0xE2B5 0x7B8F # 0 +0xE2B6 0x7B5D # 0 +0xE2B7 0x7B99 # 0 +0xE2B8 0x7BCB # 0 +0xE2B9 0x7BC1 # 0 +0xE2BA 0x7BCC # 0 +0xE2BB 0x7BCF # 0 +0xE2BC 0x7BB4 # 0 +0xE2BD 0x7BC6 # 0 +0xE2BE 0x7BDD # 0 +0xE2BF 0x7BE9 # 0 +0xE2C0 0x7C11 # 0 +0xE2C1 0x7C14 # 0 +0xE2C2 0x7BE6 # 0 +0xE2C3 0x7BE5 # 0 +0xE2C4 0x7C60 # 0 +0xE2C5 0x7C00 # 0 +0xE2C6 0x7C07 # 0 +0xE2C7 0x7C13 # 0 +0xE2C8 0x7BF3 # 0 +0xE2C9 0x7BF7 # 0 +0xE2CA 0x7C17 # 0 +0xE2CB 0x7C0D # 0 +0xE2CC 0x7BF6 # 0 +0xE2CD 0x7C23 # 0 +0xE2CE 0x7C27 # 0 +0xE2CF 0x7C2A # 0 +0xE2D0 0x7C1F # 0 +0xE2D1 0x7C37 # 0 +0xE2D2 0x7C2B # 0 +0xE2D3 0x7C3D # 0 +0xE2D4 0x7C4C # 0 +0xE2D5 0x7C43 # 0 +0xE2D6 0x7C54 # 0 +0xE2D7 0x7C4F # 0 +0xE2D8 0x7C40 # 0 +0xE2D9 0x7C50 # 0 +0xE2DA 0x7C58 # 0 +0xE2DB 0x7C5F # 0 +0xE2DC 0x7C64 # 0 +0xE2DD 0x7C56 # 0 +0xE2DE 0x7C65 # 0 +0xE2DF 0x7C6C # 0 +0xE2E0 0x7C75 # 0 +0xE2E1 0x7C83 # 0 +0xE2E2 0x7C90 # 0 +0xE2E3 0x7CA4 # 0 +0xE2E4 0x7CAD # 0 +0xE2E5 0x7CA2 # 0 +0xE2E6 0x7CAB # 0 +0xE2E7 0x7CA1 # 0 +0xE2E8 0x7CA8 # 0 +0xE2E9 0x7CB3 # 0 +0xE2EA 0x7CB2 # 0 +0xE2EB 0x7CB1 # 0 +0xE2EC 0x7CAE # 0 +0xE2ED 0x7CB9 # 0 +0xE2EE 0x7CBD # 0 +0xE2EF 0x7CC0 # 0 +0xE2F0 0x7CC5 # 0 +0xE2F1 0x7CC2 # 0 +0xE2F2 0x7CD8 # 0 +0xE2F3 0x7CD2 # 0 +0xE2F4 0x7CDC # 0 +0xE2F5 0x7CE2 # 0 +0xE2F6 0x9B3B # 0 +0xE2F7 0x7CEF # 0 +0xE2F8 0x7CF2 # 0 +0xE2F9 0x7CF4 # 0 +0xE2FA 0x7CF6 # 0 +0xE2FB 0x7CFA # 0 +0xE2FC 0x7D06 # 0 +0xE340 0x7D02 # 0 +0xE341 0x7D1C # 0 +0xE342 0x7D15 # 0 +0xE343 0x7D0A # 0 +0xE344 0x7D45 # 0 +0xE345 0x7D4B # 0 +0xE346 0x7D2E # 0 +0xE347 0x7D32 # 0 +0xE348 0x7D3F # 0 +0xE349 0x7D35 # 0 +0xE34A 0x7D46 # 0 +0xE34B 0x7D73 # 0 +0xE34C 0x7D56 # 0 +0xE34D 0x7D4E # 0 +0xE34E 0x7D72 # 0 +0xE34F 0x7D68 # 0 +0xE350 0x7D6E # 0 +0xE351 0x7D4F # 0 +0xE352 0x7D63 # 0 +0xE353 0x7D93 # 0 +0xE354 0x7D89 # 0 +0xE355 0x7D5B # 0 +0xE356 0x7D8F # 0 +0xE357 0x7D7D # 0 +0xE358 0x7D9B # 0 +0xE359 0x7DBA # 0 +0xE35A 0x7DAE # 0 +0xE35B 0x7DA3 # 0 +0xE35C 0x7DB5 # 0 +0xE35D 0x7DC7 # 0 +0xE35E 0x7DBD # 0 +0xE35F 0x7DAB # 0 +0xE360 0x7E3D # 0 +0xE361 0x7DA2 # 0 +0xE362 0x7DAF # 0 +0xE363 0x7DDC # 0 +0xE364 0x7DB8 # 0 +0xE365 0x7D9F # 0 +0xE366 0x7DB0 # 0 +0xE367 0x7DD8 # 0 +0xE368 0x7DDD # 0 +0xE369 0x7DE4 # 0 +0xE36A 0x7DDE # 0 +0xE36B 0x7DFB # 0 +0xE36C 0x7DF2 # 0 +0xE36D 0x7DE1 # 0 +0xE36E 0x7E05 # 0 +0xE36F 0x7E0A # 0 +0xE370 0x7E23 # 0 +0xE371 0x7E21 # 0 +0xE372 0x7E12 # 0 +0xE373 0x7E31 # 0 +0xE374 0x7E1F # 0 +0xE375 0x7E09 # 0 +0xE376 0x7E0B # 0 +0xE377 0x7E22 # 0 +0xE378 0x7E46 # 0 +0xE379 0x7E66 # 0 +0xE37A 0x7E3B # 0 +0xE37B 0x7E35 # 0 +0xE37C 0x7E39 # 0 +0xE37D 0x7E43 # 0 +0xE37E 0x7E37 # 0 +0xE380 0x7E32 # 0 +0xE381 0x7E3A # 0 +0xE382 0x7E67 # 0 +0xE383 0x7E5D # 0 +0xE384 0x7E56 # 0 +0xE385 0x7E5E # 0 +0xE386 0x7E59 # 0 +0xE387 0x7E5A # 0 +0xE388 0x7E79 # 0 +0xE389 0x7E6A # 0 +0xE38A 0x7E69 # 0 +0xE38B 0x7E7C # 0 +0xE38C 0x7E7B # 0 +0xE38D 0x7E83 # 0 +0xE38E 0x7DD5 # 0 +0xE38F 0x7E7D # 0 +0xE390 0x8FAE # 0 +0xE391 0x7E7F # 0 +0xE392 0x7E88 # 0 +0xE393 0x7E89 # 0 +0xE394 0x7E8C # 0 +0xE395 0x7E92 # 0 +0xE396 0x7E90 # 0 +0xE397 0x7E93 # 0 +0xE398 0x7E94 # 0 +0xE399 0x7E96 # 0 +0xE39A 0x7E8E # 0 +0xE39B 0x7E9B # 0 +0xE39C 0x7E9C # 0 +0xE39D 0x7F38 # 0 +0xE39E 0x7F3A # 0 +0xE39F 0x7F45 # 0 +0xE3A0 0x7F4C # 0 +0xE3A1 0x7F4D # 0 +0xE3A2 0x7F4E # 0 +0xE3A3 0x7F50 # 0 +0xE3A4 0x7F51 # 0 +0xE3A5 0x7F55 # 0 +0xE3A6 0x7F54 # 0 +0xE3A7 0x7F58 # 0 +0xE3A8 0x7F5F # 0 +0xE3A9 0x7F60 # 0 +0xE3AA 0x7F68 # 0 +0xE3AB 0x7F69 # 0 +0xE3AC 0x7F67 # 0 +0xE3AD 0x7F78 # 0 +0xE3AE 0x7F82 # 0 +0xE3AF 0x7F86 # 0 +0xE3B0 0x7F83 # 0 +0xE3B1 0x7F88 # 0 +0xE3B2 0x7F87 # 0 +0xE3B3 0x7F8C # 0 +0xE3B4 0x7F94 # 0 +0xE3B5 0x7F9E # 0 +0xE3B6 0x7F9D # 0 +0xE3B7 0x7F9A # 0 +0xE3B8 0x7FA3 # 0 +0xE3B9 0x7FAF # 0 +0xE3BA 0x7FB2 # 0 +0xE3BB 0x7FB9 # 0 +0xE3BC 0x7FAE # 0 +0xE3BD 0x7FB6 # 0 +0xE3BE 0x7FB8 # 0 +0xE3BF 0x8B71 # 0 +0xE3C0 0x7FC5 # 0 +0xE3C1 0x7FC6 # 0 +0xE3C2 0x7FCA # 0 +0xE3C3 0x7FD5 # 0 +0xE3C4 0x7FD4 # 0 +0xE3C5 0x7FE1 # 0 +0xE3C6 0x7FE6 # 0 +0xE3C7 0x7FE9 # 0 +0xE3C8 0x7FF3 # 0 +0xE3C9 0x7FF9 # 0 +0xE3CA 0x98DC # 0 +0xE3CB 0x8006 # 0 +0xE3CC 0x8004 # 0 +0xE3CD 0x800B # 0 +0xE3CE 0x8012 # 0 +0xE3CF 0x8018 # 0 +0xE3D0 0x8019 # 0 +0xE3D1 0x801C # 0 +0xE3D2 0x8021 # 0 +0xE3D3 0x8028 # 0 +0xE3D4 0x803F # 0 +0xE3D5 0x803B # 0 +0xE3D6 0x804A # 0 +0xE3D7 0x8046 # 0 +0xE3D8 0x8052 # 0 +0xE3D9 0x8058 # 0 +0xE3DA 0x805A # 0 +0xE3DB 0x805F # 0 +0xE3DC 0x8062 # 0 +0xE3DD 0x8068 # 0 +0xE3DE 0x8073 # 0 +0xE3DF 0x8072 # 0 +0xE3E0 0x8070 # 0 +0xE3E1 0x8076 # 0 +0xE3E2 0x8079 # 0 +0xE3E3 0x807D # 0 +0xE3E4 0x807F # 0 +0xE3E5 0x8084 # 0 +0xE3E6 0x8086 # 0 +0xE3E7 0x8085 # 0 +0xE3E8 0x809B # 0 +0xE3E9 0x8093 # 0 +0xE3EA 0x809A # 0 +0xE3EB 0x80AD # 0 +0xE3EC 0x5190 # 0 +0xE3ED 0x80AC # 0 +0xE3EE 0x80DB # 0 +0xE3EF 0x80E5 # 0 +0xE3F0 0x80D9 # 0 +0xE3F1 0x80DD # 0 +0xE3F2 0x80C4 # 0 +0xE3F3 0x80DA # 0 +0xE3F4 0x80D6 # 0 +0xE3F5 0x8109 # 0 +0xE3F6 0x80EF # 0 +0xE3F7 0x80F1 # 0 +0xE3F8 0x811B # 0 +0xE3F9 0x8129 # 0 +0xE3FA 0x8123 # 0 +0xE3FB 0x812F # 0 +0xE3FC 0x814B # 0 +0xE440 0x968B # 0 +0xE441 0x8146 # 0 +0xE442 0x813E # 0 +0xE443 0x8153 # 0 +0xE444 0x8151 # 0 +0xE445 0x80FC # 0 +0xE446 0x8171 # 0 +0xE447 0x816E # 0 +0xE448 0x8165 # 0 +0xE449 0x8166 # 0 +0xE44A 0x8174 # 0 +0xE44B 0x8183 # 0 +0xE44C 0x8188 # 0 +0xE44D 0x818A # 0 +0xE44E 0x8180 # 0 +0xE44F 0x8182 # 0 +0xE450 0x81A0 # 0 +0xE451 0x8195 # 0 +0xE452 0x81A4 # 0 +0xE453 0x81A3 # 0 +0xE454 0x815F # 0 +0xE455 0x8193 # 0 +0xE456 0x81A9 # 0 +0xE457 0x81B0 # 0 +0xE458 0x81B5 # 0 +0xE459 0x81BE # 0 +0xE45A 0x81B8 # 0 +0xE45B 0x81BD # 0 +0xE45C 0x81C0 # 0 +0xE45D 0x81C2 # 0 +0xE45E 0x81BA # 0 +0xE45F 0x81C9 # 0 +0xE460 0x81CD # 0 +0xE461 0x81D1 # 0 +0xE462 0x81D9 # 0 +0xE463 0x81D8 # 0 +0xE464 0x81C8 # 0 +0xE465 0x81DA # 0 +0xE466 0x81DF # 0 +0xE467 0x81E0 # 0 +0xE468 0x81E7 # 0 +0xE469 0x81FA # 0 +0xE46A 0x81FB # 0 +0xE46B 0x81FE # 0 +0xE46C 0x8201 # 0 +0xE46D 0x8202 # 0 +0xE46E 0x8205 # 0 +0xE46F 0x8207 # 0 +0xE470 0x820A # 0 +0xE471 0x820D # 0 +0xE472 0x8210 # 0 +0xE473 0x8216 # 0 +0xE474 0x8229 # 0 +0xE475 0x822B # 0 +0xE476 0x8238 # 0 +0xE477 0x8233 # 0 +0xE478 0x8240 # 0 +0xE479 0x8259 # 0 +0xE47A 0x8258 # 0 +0xE47B 0x825D # 0 +0xE47C 0x825A # 0 +0xE47D 0x825F # 0 +0xE47E 0x8264 # 0 +0xE480 0x8262 # 0 +0xE481 0x8268 # 0 +0xE482 0x826A # 0 +0xE483 0x826B # 0 +0xE484 0x822E # 0 +0xE485 0x8271 # 0 +0xE486 0x8277 # 0 +0xE487 0x8278 # 0 +0xE488 0x827E # 0 +0xE489 0x828D # 0 +0xE48A 0x8292 # 0 +0xE48B 0x82AB # 0 +0xE48C 0x829F # 0 +0xE48D 0x82BB # 0 +0xE48E 0x82AC # 0 +0xE48F 0x82E1 # 0 +0xE490 0x82E3 # 0 +0xE491 0x82DF # 0 +0xE492 0x82D2 # 0 +0xE493 0x82F4 # 0 +0xE494 0x82F3 # 0 +0xE495 0x82FA # 0 +0xE496 0x8393 # 0 +0xE497 0x8303 # 0 +0xE498 0x82FB # 0 +0xE499 0x82F9 # 0 +0xE49A 0x82DE # 0 +0xE49B 0x8306 # 0 +0xE49C 0x82DC # 0 +0xE49D 0x8309 # 0 +0xE49E 0x82D9 # 0 +0xE49F 0x8335 # 0 +0xE4A0 0x8334 # 0 +0xE4A1 0x8316 # 0 +0xE4A2 0x8332 # 0 +0xE4A3 0x8331 # 0 +0xE4A4 0x8340 # 0 +0xE4A5 0x8339 # 0 +0xE4A6 0x8350 # 0 +0xE4A7 0x8345 # 0 +0xE4A8 0x832F # 0 +0xE4A9 0x832B # 0 +0xE4AA 0x8317 # 0 +0xE4AB 0x8318 # 0 +0xE4AC 0x8385 # 0 +0xE4AD 0x839A # 0 +0xE4AE 0x83AA # 0 +0xE4AF 0x839F # 0 +0xE4B0 0x83A2 # 0 +0xE4B1 0x8396 # 0 +0xE4B2 0x8323 # 0 +0xE4B3 0x838E # 0 +0xE4B4 0x8387 # 0 +0xE4B5 0x838A # 0 +0xE4B6 0x837C # 0 +0xE4B7 0x83B5 # 0 +0xE4B8 0x8373 # 0 +0xE4B9 0x8375 # 0 +0xE4BA 0x83A0 # 0 +0xE4BB 0x8389 # 0 +0xE4BC 0x83A8 # 0 +0xE4BD 0x83F4 # 0 +0xE4BE 0x8413 # 0 +0xE4BF 0x83EB # 0 +0xE4C0 0x83CE # 0 +0xE4C1 0x83FD # 0 +0xE4C2 0x8403 # 0 +0xE4C3 0x83D8 # 0 +0xE4C4 0x840B # 0 +0xE4C5 0x83C1 # 0 +0xE4C6 0x83F7 # 0 +0xE4C7 0x8407 # 0 +0xE4C8 0x83E0 # 0 +0xE4C9 0x83F2 # 0 +0xE4CA 0x840D # 0 +0xE4CB 0x8422 # 0 +0xE4CC 0x8420 # 0 +0xE4CD 0x83BD # 0 +0xE4CE 0x8438 # 0 +0xE4CF 0x8506 # 0 +0xE4D0 0x83FB # 0 +0xE4D1 0x846D # 0 +0xE4D2 0x842A # 0 +0xE4D3 0x843C # 0 +0xE4D4 0x855A # 0 +0xE4D5 0x8484 # 0 +0xE4D6 0x8477 # 0 +0xE4D7 0x846B # 0 +0xE4D8 0x84AD # 0 +0xE4D9 0x846E # 0 +0xE4DA 0x8482 # 0 +0xE4DB 0x8469 # 0 +0xE4DC 0x8446 # 0 +0xE4DD 0x842C # 0 +0xE4DE 0x846F # 0 +0xE4DF 0x8479 # 0 +0xE4E0 0x8435 # 0 +0xE4E1 0x84CA # 0 +0xE4E2 0x8462 # 0 +0xE4E3 0x84B9 # 0 +0xE4E4 0x84BF # 0 +0xE4E5 0x849F # 0 +0xE4E6 0x84D9 # 0 +0xE4E7 0x84CD # 0 +0xE4E8 0x84BB # 0 +0xE4E9 0x84DA # 0 +0xE4EA 0x84D0 # 0 +0xE4EB 0x84C1 # 0 +0xE4EC 0x84C6 # 0 +0xE4ED 0x84D6 # 0 +0xE4EE 0x84A1 # 0 +0xE4EF 0x8521 # 0 +0xE4F0 0x84FF # 0 +0xE4F1 0x84F4 # 0 +0xE4F2 0x8517 # 0 +0xE4F3 0x8518 # 0 +0xE4F4 0x852C # 0 +0xE4F5 0x851F # 0 +0xE4F6 0x8515 # 0 +0xE4F7 0x8514 # 0 +0xE4F8 0x84FC # 0 +0xE4F9 0x8540 # 0 +0xE4FA 0x8563 # 0 +0xE4FB 0x8558 # 0 +0xE4FC 0x8548 # 0 +0xE540 0x8541 # 0 +0xE541 0x8602 # 0 +0xE542 0x854B # 0 +0xE543 0x8555 # 0 +0xE544 0x8580 # 0 +0xE545 0x85A4 # 0 +0xE546 0x8588 # 0 +0xE547 0x8591 # 0 +0xE548 0x858A # 0 +0xE549 0x85A8 # 0 +0xE54A 0x856D # 0 +0xE54B 0x8594 # 0 +0xE54C 0x859B # 0 +0xE54D 0x85EA # 0 +0xE54E 0x8587 # 0 +0xE54F 0x859C # 0 +0xE550 0x8577 # 0 +0xE551 0x857E # 0 +0xE552 0x8590 # 0 +0xE553 0x85C9 # 0 +0xE554 0x85BA # 0 +0xE555 0x85CF # 0 +0xE556 0x85B9 # 0 +0xE557 0x85D0 # 0 +0xE558 0x85D5 # 0 +0xE559 0x85DD # 0 +0xE55A 0x85E5 # 0 +0xE55B 0x85DC # 0 +0xE55C 0x85F9 # 0 +0xE55D 0x860A # 0 +0xE55E 0x8613 # 0 +0xE55F 0x860B # 0 +0xE560 0x85FE # 0 +0xE561 0x85FA # 0 +0xE562 0x8606 # 0 +0xE563 0x8622 # 0 +0xE564 0x861A # 0 +0xE565 0x8630 # 0 +0xE566 0x863F # 0 +0xE567 0x864D # 0 +0xE568 0x4E55 # 0 +0xE569 0x8654 # 0 +0xE56A 0x865F # 0 +0xE56B 0x8667 # 0 +0xE56C 0x8671 # 0 +0xE56D 0x8693 # 0 +0xE56E 0x86A3 # 0 +0xE56F 0x86A9 # 0 +0xE570 0x86AA # 0 +0xE571 0x868B # 0 +0xE572 0x868C # 0 +0xE573 0x86B6 # 0 +0xE574 0x86AF # 0 +0xE575 0x86C4 # 0 +0xE576 0x86C6 # 0 +0xE577 0x86B0 # 0 +0xE578 0x86C9 # 0 +0xE579 0x8823 # 0 +0xE57A 0x86AB # 0 +0xE57B 0x86D4 # 0 +0xE57C 0x86DE # 0 +0xE57D 0x86E9 # 0 +0xE57E 0x86EC # 0 +0xE580 0x86DF # 0 +0xE581 0x86DB # 0 +0xE582 0x86EF # 0 +0xE583 0x8712 # 0 +0xE584 0x8706 # 0 +0xE585 0x8708 # 0 +0xE586 0x8700 # 0 +0xE587 0x8703 # 0 +0xE588 0x86FB # 0 +0xE589 0x8711 # 0 +0xE58A 0x8709 # 0 +0xE58B 0x870D # 0 +0xE58C 0x86F9 # 0 +0xE58D 0x870A # 0 +0xE58E 0x8734 # 0 +0xE58F 0x873F # 0 +0xE590 0x8737 # 0 +0xE591 0x873B # 0 +0xE592 0x8725 # 0 +0xE593 0x8729 # 0 +0xE594 0x871A # 0 +0xE595 0x8760 # 0 +0xE596 0x875F # 0 +0xE597 0x8778 # 0 +0xE598 0x874C # 0 +0xE599 0x874E # 0 +0xE59A 0x8774 # 0 +0xE59B 0x8757 # 0 +0xE59C 0x8768 # 0 +0xE59D 0x876E # 0 +0xE59E 0x8759 # 0 +0xE59F 0x8753 # 0 +0xE5A0 0x8763 # 0 +0xE5A1 0x876A # 0 +0xE5A2 0x8805 # 0 +0xE5A3 0x87A2 # 0 +0xE5A4 0x879F # 0 +0xE5A5 0x8782 # 0 +0xE5A6 0x87AF # 0 +0xE5A7 0x87CB # 0 +0xE5A8 0x87BD # 0 +0xE5A9 0x87C0 # 0 +0xE5AA 0x87D0 # 0 +0xE5AB 0x96D6 # 0 +0xE5AC 0x87AB # 0 +0xE5AD 0x87C4 # 0 +0xE5AE 0x87B3 # 0 +0xE5AF 0x87C7 # 0 +0xE5B0 0x87C6 # 0 +0xE5B1 0x87BB # 0 +0xE5B2 0x87EF # 0 +0xE5B3 0x87F2 # 0 +0xE5B4 0x87E0 # 0 +0xE5B5 0x880F # 0 +0xE5B6 0x880D # 0 +0xE5B7 0x87FE # 0 +0xE5B8 0x87F6 # 0 +0xE5B9 0x87F7 # 0 +0xE5BA 0x880E # 0 +0xE5BB 0x87D2 # 0 +0xE5BC 0x8811 # 0 +0xE5BD 0x8816 # 0 +0xE5BE 0x8815 # 0 +0xE5BF 0x8822 # 0 +0xE5C0 0x8821 # 0 +0xE5C1 0x8831 # 0 +0xE5C2 0x8836 # 0 +0xE5C3 0x8839 # 0 +0xE5C4 0x8827 # 0 +0xE5C5 0x883B # 0 +0xE5C6 0x8844 # 0 +0xE5C7 0x8842 # 0 +0xE5C8 0x8852 # 0 +0xE5C9 0x8859 # 0 +0xE5CA 0x885E # 0 +0xE5CB 0x8862 # 0 +0xE5CC 0x886B # 0 +0xE5CD 0x8881 # 0 +0xE5CE 0x887E # 0 +0xE5CF 0x889E # 0 +0xE5D0 0x8875 # 0 +0xE5D1 0x887D # 0 +0xE5D2 0x88B5 # 0 +0xE5D3 0x8872 # 0 +0xE5D4 0x8882 # 0 +0xE5D5 0x8897 # 0 +0xE5D6 0x8892 # 0 +0xE5D7 0x88AE # 0 +0xE5D8 0x8899 # 0 +0xE5D9 0x88A2 # 0 +0xE5DA 0x888D # 0 +0xE5DB 0x88A4 # 0 +0xE5DC 0x88B0 # 0 +0xE5DD 0x88BF # 0 +0xE5DE 0x88B1 # 0 +0xE5DF 0x88C3 # 0 +0xE5E0 0x88C4 # 0 +0xE5E1 0x88D4 # 0 +0xE5E2 0x88D8 # 0 +0xE5E3 0x88D9 # 0 +0xE5E4 0x88DD # 0 +0xE5E5 0x88F9 # 0 +0xE5E6 0x8902 # 0 +0xE5E7 0x88FC # 0 +0xE5E8 0x88F4 # 0 +0xE5E9 0x88E8 # 0 +0xE5EA 0x88F2 # 0 +0xE5EB 0x8904 # 0 +0xE5EC 0x890C # 0 +0xE5ED 0x890A # 0 +0xE5EE 0x8913 # 0 +0xE5EF 0x8943 # 0 +0xE5F0 0x891E # 0 +0xE5F1 0x8925 # 0 +0xE5F2 0x892A # 0 +0xE5F3 0x892B # 0 +0xE5F4 0x8941 # 0 +0xE5F5 0x8944 # 0 +0xE5F6 0x893B # 0 +0xE5F7 0x8936 # 0 +0xE5F8 0x8938 # 0 +0xE5F9 0x894C # 0 +0xE5FA 0x891D # 0 +0xE5FB 0x8960 # 0 +0xE5FC 0x895E # 0 +0xE640 0x8966 # 0 +0xE641 0x8964 # 0 +0xE642 0x896D # 0 +0xE643 0x896A # 0 +0xE644 0x896F # 0 +0xE645 0x8974 # 0 +0xE646 0x8977 # 0 +0xE647 0x897E # 0 +0xE648 0x8983 # 0 +0xE649 0x8988 # 0 +0xE64A 0x898A # 0 +0xE64B 0x8993 # 0 +0xE64C 0x8998 # 0 +0xE64D 0x89A1 # 0 +0xE64E 0x89A9 # 0 +0xE64F 0x89A6 # 0 +0xE650 0x89AC # 0 +0xE651 0x89AF # 0 +0xE652 0x89B2 # 0 +0xE653 0x89BA # 0 +0xE654 0x89BD # 0 +0xE655 0x89BF # 0 +0xE656 0x89C0 # 0 +0xE657 0x89DA # 0 +0xE658 0x89DC # 0 +0xE659 0x89DD # 0 +0xE65A 0x89E7 # 0 +0xE65B 0x89F4 # 0 +0xE65C 0x89F8 # 0 +0xE65D 0x8A03 # 0 +0xE65E 0x8A16 # 0 +0xE65F 0x8A10 # 0 +0xE660 0x8A0C # 0 +0xE661 0x8A1B # 0 +0xE662 0x8A1D # 0 +0xE663 0x8A25 # 0 +0xE664 0x8A36 # 0 +0xE665 0x8A41 # 0 +0xE666 0x8A5B # 0 +0xE667 0x8A52 # 0 +0xE668 0x8A46 # 0 +0xE669 0x8A48 # 0 +0xE66A 0x8A7C # 0 +0xE66B 0x8A6D # 0 +0xE66C 0x8A6C # 0 +0xE66D 0x8A62 # 0 +0xE66E 0x8A85 # 0 +0xE66F 0x8A82 # 0 +0xE670 0x8A84 # 0 +0xE671 0x8AA8 # 0 +0xE672 0x8AA1 # 0 +0xE673 0x8A91 # 0 +0xE674 0x8AA5 # 0 +0xE675 0x8AA6 # 0 +0xE676 0x8A9A # 0 +0xE677 0x8AA3 # 0 +0xE678 0x8AC4 # 0 +0xE679 0x8ACD # 0 +0xE67A 0x8AC2 # 0 +0xE67B 0x8ADA # 0 +0xE67C 0x8AEB # 0 +0xE67D 0x8AF3 # 0 +0xE67E 0x8AE7 # 0 +0xE680 0x8AE4 # 0 +0xE681 0x8AF1 # 0 +0xE682 0x8B14 # 0 +0xE683 0x8AE0 # 0 +0xE684 0x8AE2 # 0 +0xE685 0x8AF7 # 0 +0xE686 0x8ADE # 0 +0xE687 0x8ADB # 0 +0xE688 0x8B0C # 0 +0xE689 0x8B07 # 0 +0xE68A 0x8B1A # 0 +0xE68B 0x8AE1 # 0 +0xE68C 0x8B16 # 0 +0xE68D 0x8B10 # 0 +0xE68E 0x8B17 # 0 +0xE68F 0x8B20 # 0 +0xE690 0x8B33 # 0 +0xE691 0x97AB # 0 +0xE692 0x8B26 # 0 +0xE693 0x8B2B # 0 +0xE694 0x8B3E # 0 +0xE695 0x8B28 # 0 +0xE696 0x8B41 # 0 +0xE697 0x8B4C # 0 +0xE698 0x8B4F # 0 +0xE699 0x8B4E # 0 +0xE69A 0x8B49 # 0 +0xE69B 0x8B56 # 0 +0xE69C 0x8B5B # 0 +0xE69D 0x8B5A # 0 +0xE69E 0x8B6B # 0 +0xE69F 0x8B5F # 0 +0xE6A0 0x8B6C # 0 +0xE6A1 0x8B6F # 0 +0xE6A2 0x8B74 # 0 +0xE6A3 0x8B7D # 0 +0xE6A4 0x8B80 # 0 +0xE6A5 0x8B8C # 0 +0xE6A6 0x8B8E # 0 +0xE6A7 0x8B92 # 0 +0xE6A8 0x8B93 # 0 +0xE6A9 0x8B96 # 0 +0xE6AA 0x8B99 # 0 +0xE6AB 0x8B9A # 0 +0xE6AC 0x8C3A # 0 +0xE6AD 0x8C41 # 0 +0xE6AE 0x8C3F # 0 +0xE6AF 0x8C48 # 0 +0xE6B0 0x8C4C # 0 +0xE6B1 0x8C4E # 0 +0xE6B2 0x8C50 # 0 +0xE6B3 0x8C55 # 0 +0xE6B4 0x8C62 # 0 +0xE6B5 0x8C6C # 0 +0xE6B6 0x8C78 # 0 +0xE6B7 0x8C7A # 0 +0xE6B8 0x8C82 # 0 +0xE6B9 0x8C89 # 0 +0xE6BA 0x8C85 # 0 +0xE6BB 0x8C8A # 0 +0xE6BC 0x8C8D # 0 +0xE6BD 0x8C8E # 0 +0xE6BE 0x8C94 # 0 +0xE6BF 0x8C7C # 0 +0xE6C0 0x8C98 # 0 +0xE6C1 0x621D # 0 +0xE6C2 0x8CAD # 0 +0xE6C3 0x8CAA # 0 +0xE6C4 0x8CBD # 0 +0xE6C5 0x8CB2 # 0 +0xE6C6 0x8CB3 # 0 +0xE6C7 0x8CAE # 0 +0xE6C8 0x8CB6 # 0 +0xE6C9 0x8CC8 # 0 +0xE6CA 0x8CC1 # 0 +0xE6CB 0x8CE4 # 0 +0xE6CC 0x8CE3 # 0 +0xE6CD 0x8CDA # 0 +0xE6CE 0x8CFD # 0 +0xE6CF 0x8CFA # 0 +0xE6D0 0x8CFB # 0 +0xE6D1 0x8D04 # 0 +0xE6D2 0x8D05 # 0 +0xE6D3 0x8D0A # 0 +0xE6D4 0x8D07 # 0 +0xE6D5 0x8D0F # 0 +0xE6D6 0x8D0D # 0 +0xE6D7 0x8D10 # 0 +0xE6D8 0x9F4E # 0 +0xE6D9 0x8D13 # 0 +0xE6DA 0x8CCD # 0 +0xE6DB 0x8D14 # 0 +0xE6DC 0x8D16 # 0 +0xE6DD 0x8D67 # 0 +0xE6DE 0x8D6D # 0 +0xE6DF 0x8D71 # 0 +0xE6E0 0x8D73 # 0 +0xE6E1 0x8D81 # 0 +0xE6E2 0x8D99 # 0 +0xE6E3 0x8DC2 # 0 +0xE6E4 0x8DBE # 0 +0xE6E5 0x8DBA # 0 +0xE6E6 0x8DCF # 0 +0xE6E7 0x8DDA # 0 +0xE6E8 0x8DD6 # 0 +0xE6E9 0x8DCC # 0 +0xE6EA 0x8DDB # 0 +0xE6EB 0x8DCB # 0 +0xE6EC 0x8DEA # 0 +0xE6ED 0x8DEB # 0 +0xE6EE 0x8DDF # 0 +0xE6EF 0x8DE3 # 0 +0xE6F0 0x8DFC # 0 +0xE6F1 0x8E08 # 0 +0xE6F2 0x8E09 # 0 +0xE6F3 0x8DFF # 0 +0xE6F4 0x8E1D # 0 +0xE6F5 0x8E1E # 0 +0xE6F6 0x8E10 # 0 +0xE6F7 0x8E1F # 0 +0xE6F8 0x8E42 # 0 +0xE6F9 0x8E35 # 0 +0xE6FA 0x8E30 # 0 +0xE6FB 0x8E34 # 0 +0xE6FC 0x8E4A # 0 +0xE740 0x8E47 # 0 +0xE741 0x8E49 # 0 +0xE742 0x8E4C # 0 +0xE743 0x8E50 # 0 +0xE744 0x8E48 # 0 +0xE745 0x8E59 # 0 +0xE746 0x8E64 # 0 +0xE747 0x8E60 # 0 +0xE748 0x8E2A # 0 +0xE749 0x8E63 # 0 +0xE74A 0x8E55 # 0 +0xE74B 0x8E76 # 0 +0xE74C 0x8E72 # 0 +0xE74D 0x8E7C # 0 +0xE74E 0x8E81 # 0 +0xE74F 0x8E87 # 0 +0xE750 0x8E85 # 0 +0xE751 0x8E84 # 0 +0xE752 0x8E8B # 0 +0xE753 0x8E8A # 0 +0xE754 0x8E93 # 0 +0xE755 0x8E91 # 0 +0xE756 0x8E94 # 0 +0xE757 0x8E99 # 0 +0xE758 0x8EAA # 0 +0xE759 0x8EA1 # 0 +0xE75A 0x8EAC # 0 +0xE75B 0x8EB0 # 0 +0xE75C 0x8EC6 # 0 +0xE75D 0x8EB1 # 0 +0xE75E 0x8EBE # 0 +0xE75F 0x8EC5 # 0 +0xE760 0x8EC8 # 0 +0xE761 0x8ECB # 0 +0xE762 0x8EDB # 0 +0xE763 0x8EE3 # 0 +0xE764 0x8EFC # 0 +0xE765 0x8EFB # 0 +0xE766 0x8EEB # 0 +0xE767 0x8EFE # 0 +0xE768 0x8F0A # 0 +0xE769 0x8F05 # 0 +0xE76A 0x8F15 # 0 +0xE76B 0x8F12 # 0 +0xE76C 0x8F19 # 0 +0xE76D 0x8F13 # 0 +0xE76E 0x8F1C # 0 +0xE76F 0x8F1F # 0 +0xE770 0x8F1B # 0 +0xE771 0x8F0C # 0 +0xE772 0x8F26 # 0 +0xE773 0x8F33 # 0 +0xE774 0x8F3B # 0 +0xE775 0x8F39 # 0 +0xE776 0x8F45 # 0 +0xE777 0x8F42 # 0 +0xE778 0x8F3E # 0 +0xE779 0x8F4C # 0 +0xE77A 0x8F49 # 0 +0xE77B 0x8F46 # 0 +0xE77C 0x8F4E # 0 +0xE77D 0x8F57 # 0 +0xE77E 0x8F5C # 0 +0xE780 0x8F62 # 0 +0xE781 0x8F63 # 0 +0xE782 0x8F64 # 0 +0xE783 0x8F9C # 0 +0xE784 0x8F9F # 0 +0xE785 0x8FA3 # 0 +0xE786 0x8FAD # 0 +0xE787 0x8FAF # 0 +0xE788 0x8FB7 # 0 +0xE789 0x8FDA # 0 +0xE78A 0x8FE5 # 0 +0xE78B 0x8FE2 # 0 +0xE78C 0x8FEA # 0 +0xE78D 0x8FEF # 0 +0xE78E 0x9087 # 0 +0xE78F 0x8FF4 # 0 +0xE790 0x9005 # 0 +0xE791 0x8FF9 # 0 +0xE792 0x8FFA # 0 +0xE793 0x9011 # 0 +0xE794 0x9015 # 0 +0xE795 0x9021 # 0 +0xE796 0x900D # 0 +0xE797 0x901E # 0 +0xE798 0x9016 # 0 +0xE799 0x900B # 0 +0xE79A 0x9027 # 0 +0xE79B 0x9036 # 0 +0xE79C 0x9035 # 0 +0xE79D 0x9039 # 0 +0xE79E 0x8FF8 # 0 +0xE79F 0x904F # 0 +0xE7A0 0x9050 # 0 +0xE7A1 0x9051 # 0 +0xE7A2 0x9052 # 0 +0xE7A3 0x900E # 0 +0xE7A4 0x9049 # 0 +0xE7A5 0x903E # 0 +0xE7A6 0x9056 # 0 +0xE7A7 0x9058 # 0 +0xE7A8 0x905E # 0 +0xE7A9 0x9068 # 0 +0xE7AA 0x906F # 0 +0xE7AB 0x9076 # 0 +0xE7AC 0x96A8 # 0 +0xE7AD 0x9072 # 0 +0xE7AE 0x9082 # 0 +0xE7AF 0x907D # 0 +0xE7B0 0x9081 # 0 +0xE7B1 0x9080 # 0 +0xE7B2 0x908A # 0 +0xE7B3 0x9089 # 0 +0xE7B4 0x908F # 0 +0xE7B5 0x90A8 # 0 +0xE7B6 0x90AF # 0 +0xE7B7 0x90B1 # 0 +0xE7B8 0x90B5 # 0 +0xE7B9 0x90E2 # 0 +0xE7BA 0x90E4 # 0 +0xE7BB 0x6248 # 0 +0xE7BC 0x90DB # 0 +0xE7BD 0x9102 # 0 +0xE7BE 0x9112 # 0 +0xE7BF 0x9119 # 0 +0xE7C0 0x9132 # 0 +0xE7C1 0x9130 # 0 +0xE7C2 0x914A # 0 +0xE7C3 0x9156 # 0 +0xE7C4 0x9158 # 0 +0xE7C5 0x9163 # 0 +0xE7C6 0x9165 # 0 +0xE7C7 0x9169 # 0 +0xE7C8 0x9173 # 0 +0xE7C9 0x9172 # 0 +0xE7CA 0x918B # 0 +0xE7CB 0x9189 # 0 +0xE7CC 0x9182 # 0 +0xE7CD 0x91A2 # 0 +0xE7CE 0x91AB # 0 +0xE7CF 0x91AF # 0 +0xE7D0 0x91AA # 0 +0xE7D1 0x91B5 # 0 +0xE7D2 0x91B4 # 0 +0xE7D3 0x91BA # 0 +0xE7D4 0x91C0 # 0 +0xE7D5 0x91C1 # 0 +0xE7D6 0x91C9 # 0 +0xE7D7 0x91CB # 0 +0xE7D8 0x91D0 # 0 +0xE7D9 0x91D6 # 0 +0xE7DA 0x91DF # 0 +0xE7DB 0x91E1 # 0 +0xE7DC 0x91DB # 0 +0xE7DD 0x91FC # 0 +0xE7DE 0x91F5 # 0 +0xE7DF 0x91F6 # 0 +0xE7E0 0x921E # 0 +0xE7E1 0x91FF # 0 +0xE7E2 0x9214 # 0 +0xE7E3 0x922C # 0 +0xE7E4 0x9215 # 0 +0xE7E5 0x9211 # 0 +0xE7E6 0x925E # 0 +0xE7E7 0x9257 # 0 +0xE7E8 0x9245 # 0 +0xE7E9 0x9249 # 0 +0xE7EA 0x9264 # 0 +0xE7EB 0x9248 # 0 +0xE7EC 0x9295 # 0 +0xE7ED 0x923F # 0 +0xE7EE 0x924B # 0 +0xE7EF 0x9250 # 0 +0xE7F0 0x929C # 0 +0xE7F1 0x9296 # 0 +0xE7F2 0x9293 # 0 +0xE7F3 0x929B # 0 +0xE7F4 0x925A # 0 +0xE7F5 0x92CF # 0 +0xE7F6 0x92B9 # 0 +0xE7F7 0x92B7 # 0 +0xE7F8 0x92E9 # 0 +0xE7F9 0x930F # 0 +0xE7FA 0x92FA # 0 +0xE7FB 0x9344 # 0 +0xE7FC 0x932E # 0 +0xE840 0x9319 # 0 +0xE841 0x9322 # 0 +0xE842 0x931A # 0 +0xE843 0x9323 # 0 +0xE844 0x933A # 0 +0xE845 0x9335 # 0 +0xE846 0x933B # 0 +0xE847 0x935C # 0 +0xE848 0x9360 # 0 +0xE849 0x937C # 0 +0xE84A 0x936E # 0 +0xE84B 0x9356 # 0 +0xE84C 0x93B0 # 0 +0xE84D 0x93AC # 0 +0xE84E 0x93AD # 0 +0xE84F 0x9394 # 0 +0xE850 0x93B9 # 0 +0xE851 0x93D6 # 0 +0xE852 0x93D7 # 0 +0xE853 0x93E8 # 0 +0xE854 0x93E5 # 0 +0xE855 0x93D8 # 0 +0xE856 0x93C3 # 0 +0xE857 0x93DD # 0 +0xE858 0x93D0 # 0 +0xE859 0x93C8 # 0 +0xE85A 0x93E4 # 0 +0xE85B 0x941A # 0 +0xE85C 0x9414 # 0 +0xE85D 0x9413 # 0 +0xE85E 0x9403 # 0 +0xE85F 0x9407 # 0 +0xE860 0x9410 # 0 +0xE861 0x9436 # 0 +0xE862 0x942B # 0 +0xE863 0x9435 # 0 +0xE864 0x9421 # 0 +0xE865 0x943A # 0 +0xE866 0x9441 # 0 +0xE867 0x9452 # 0 +0xE868 0x9444 # 0 +0xE869 0x945B # 0 +0xE86A 0x9460 # 0 +0xE86B 0x9462 # 0 +0xE86C 0x945E # 0 +0xE86D 0x946A # 0 +0xE86E 0x9229 # 0 +0xE86F 0x9470 # 0 +0xE870 0x9475 # 0 +0xE871 0x9477 # 0 +0xE872 0x947D # 0 +0xE873 0x945A # 0 +0xE874 0x947C # 0 +0xE875 0x947E # 0 +0xE876 0x9481 # 0 +0xE877 0x947F # 0 +0xE878 0x9582 # 0 +0xE879 0x9587 # 0 +0xE87A 0x958A # 0 +0xE87B 0x9594 # 0 +0xE87C 0x9596 # 0 +0xE87D 0x9598 # 0 +0xE87E 0x9599 # 0 +0xE880 0x95A0 # 0 +0xE881 0x95A8 # 0 +0xE882 0x95A7 # 0 +0xE883 0x95AD # 0 +0xE884 0x95BC # 0 +0xE885 0x95BB # 0 +0xE886 0x95B9 # 0 +0xE887 0x95BE # 0 +0xE888 0x95CA # 0 +0xE889 0x6FF6 # 0 +0xE88A 0x95C3 # 0 +0xE88B 0x95CD # 0 +0xE88C 0x95CC # 0 +0xE88D 0x95D5 # 0 +0xE88E 0x95D4 # 0 +0xE88F 0x95D6 # 0 +0xE890 0x95DC # 0 +0xE891 0x95E1 # 0 +0xE892 0x95E5 # 0 +0xE893 0x95E2 # 0 +0xE894 0x9621 # 0 +0xE895 0x9628 # 0 +0xE896 0x962E # 0 +0xE897 0x962F # 0 +0xE898 0x9642 # 0 +0xE899 0x964C # 0 +0xE89A 0x964F # 0 +0xE89B 0x964B # 0 +0xE89C 0x9677 # 0 +0xE89D 0x965C # 0 +0xE89E 0x965E # 0 +0xE89F 0x965D # 0 +0xE8A0 0x965F # 0 +0xE8A1 0x9666 # 0 +0xE8A2 0x9672 # 0 +0xE8A3 0x966C # 0 +0xE8A4 0x968D # 0 +0xE8A5 0x9698 # 0 +0xE8A6 0x9695 # 0 +0xE8A7 0x9697 # 0 +0xE8A8 0x96AA # 0 +0xE8A9 0x96A7 # 0 +0xE8AA 0x96B1 # 0 +0xE8AB 0x96B2 # 0 +0xE8AC 0x96B0 # 0 +0xE8AD 0x96B4 # 0 +0xE8AE 0x96B6 # 0 +0xE8AF 0x96B8 # 0 +0xE8B0 0x96B9 # 0 +0xE8B1 0x96CE # 0 +0xE8B2 0x96CB # 0 +0xE8B3 0x96C9 # 0 +0xE8B4 0x96CD # 0 +0xE8B5 0x894D # 0 +0xE8B6 0x96DC # 0 +0xE8B7 0x970D # 0 +0xE8B8 0x96D5 # 0 +0xE8B9 0x96F9 # 0 +0xE8BA 0x9704 # 0 +0xE8BB 0x9706 # 0 +0xE8BC 0x9708 # 0 +0xE8BD 0x9713 # 0 +0xE8BE 0x970E # 0 +0xE8BF 0x9711 # 0 +0xE8C0 0x970F # 0 +0xE8C1 0x9716 # 0 +0xE8C2 0x9719 # 0 +0xE8C3 0x9724 # 0 +0xE8C4 0x972A # 0 +0xE8C5 0x9730 # 0 +0xE8C6 0x9739 # 0 +0xE8C7 0x973D # 0 +0xE8C8 0x973E # 0 +0xE8C9 0x9744 # 0 +0xE8CA 0x9746 # 0 +0xE8CB 0x9748 # 0 +0xE8CC 0x9742 # 0 +0xE8CD 0x9749 # 0 +0xE8CE 0x975C # 0 +0xE8CF 0x9760 # 0 +0xE8D0 0x9764 # 0 +0xE8D1 0x9766 # 0 +0xE8D2 0x9768 # 0 +0xE8D3 0x52D2 # 0 +0xE8D4 0x976B # 0 +0xE8D5 0x9771 # 0 +0xE8D6 0x9779 # 0 +0xE8D7 0x9785 # 0 +0xE8D8 0x977C # 0 +0xE8D9 0x9781 # 0 +0xE8DA 0x977A # 0 +0xE8DB 0x9786 # 0 +0xE8DC 0x978B # 0 +0xE8DD 0x978F # 0 +0xE8DE 0x9790 # 0 +0xE8DF 0x979C # 0 +0xE8E0 0x97A8 # 0 +0xE8E1 0x97A6 # 0 +0xE8E2 0x97A3 # 0 +0xE8E3 0x97B3 # 0 +0xE8E4 0x97B4 # 0 +0xE8E5 0x97C3 # 0 +0xE8E6 0x97C6 # 0 +0xE8E7 0x97C8 # 0 +0xE8E8 0x97CB # 0 +0xE8E9 0x97DC # 0 +0xE8EA 0x97ED # 0 +0xE8EB 0x9F4F # 0 +0xE8EC 0x97F2 # 0 +0xE8ED 0x7ADF # 0 +0xE8EE 0x97F6 # 0 +0xE8EF 0x97F5 # 0 +0xE8F0 0x980F # 0 +0xE8F1 0x980C # 0 +0xE8F2 0x9838 # 0 +0xE8F3 0x9824 # 0 +0xE8F4 0x9821 # 0 +0xE8F5 0x9837 # 0 +0xE8F6 0x983D # 0 +0xE8F7 0x9846 # 0 +0xE8F8 0x984F # 0 +0xE8F9 0x984B # 0 +0xE8FA 0x986B # 0 +0xE8FB 0x986F # 0 +0xE8FC 0x9870 # 0 +0xE940 0x9871 # 0 +0xE941 0x9874 # 0 +0xE942 0x9873 # 0 +0xE943 0x98AA # 0 +0xE944 0x98AF # 0 +0xE945 0x98B1 # 0 +0xE946 0x98B6 # 0 +0xE947 0x98C4 # 0 +0xE948 0x98C3 # 0 +0xE949 0x98C6 # 0 +0xE94A 0x98E9 # 0 +0xE94B 0x98EB # 0 +0xE94C 0x9903 # 0 +0xE94D 0x9909 # 0 +0xE94E 0x9912 # 0 +0xE94F 0x9914 # 0 +0xE950 0x9918 # 0 +0xE951 0x9921 # 0 +0xE952 0x991D # 0 +0xE953 0x991E # 0 +0xE954 0x9924 # 0 +0xE955 0x9920 # 0 +0xE956 0x992C # 0 +0xE957 0x992E # 0 +0xE958 0x993D # 0 +0xE959 0x993E # 0 +0xE95A 0x9942 # 0 +0xE95B 0x9949 # 0 +0xE95C 0x9945 # 0 +0xE95D 0x9950 # 0 +0xE95E 0x994B # 0 +0xE95F 0x9951 # 0 +0xE960 0x9952 # 0 +0xE961 0x994C # 0 +0xE962 0x9955 # 0 +0xE963 0x9997 # 0 +0xE964 0x9998 # 0 +0xE965 0x99A5 # 0 +0xE966 0x99AD # 0 +0xE967 0x99AE # 0 +0xE968 0x99BC # 0 +0xE969 0x99DF # 0 +0xE96A 0x99DB # 0 +0xE96B 0x99DD # 0 +0xE96C 0x99D8 # 0 +0xE96D 0x99D1 # 0 +0xE96E 0x99ED # 0 +0xE96F 0x99EE # 0 +0xE970 0x99F1 # 0 +0xE971 0x99F2 # 0 +0xE972 0x99FB # 0 +0xE973 0x99F8 # 0 +0xE974 0x9A01 # 0 +0xE975 0x9A0F # 0 +0xE976 0x9A05 # 0 +0xE977 0x99E2 # 0 +0xE978 0x9A19 # 0 +0xE979 0x9A2B # 0 +0xE97A 0x9A37 # 0 +0xE97B 0x9A45 # 0 +0xE97C 0x9A42 # 0 +0xE97D 0x9A40 # 0 +0xE97E 0x9A43 # 0 +0xE980 0x9A3E # 0 +0xE981 0x9A55 # 0 +0xE982 0x9A4D # 0 +0xE983 0x9A5B # 0 +0xE984 0x9A57 # 0 +0xE985 0x9A5F # 0 +0xE986 0x9A62 # 0 +0xE987 0x9A65 # 0 +0xE988 0x9A64 # 0 +0xE989 0x9A69 # 0 +0xE98A 0x9A6B # 0 +0xE98B 0x9A6A # 0 +0xE98C 0x9AAD # 0 +0xE98D 0x9AB0 # 0 +0xE98E 0x9ABC # 0 +0xE98F 0x9AC0 # 0 +0xE990 0x9ACF # 0 +0xE991 0x9AD1 # 0 +0xE992 0x9AD3 # 0 +0xE993 0x9AD4 # 0 +0xE994 0x9ADE # 0 +0xE995 0x9ADF # 0 +0xE996 0x9AE2 # 0 +0xE997 0x9AE3 # 0 +0xE998 0x9AE6 # 0 +0xE999 0x9AEF # 0 +0xE99A 0x9AEB # 0 +0xE99B 0x9AEE # 0 +0xE99C 0x9AF4 # 0 +0xE99D 0x9AF1 # 0 +0xE99E 0x9AF7 # 0 +0xE99F 0x9AFB # 0 +0xE9A0 0x9B06 # 0 +0xE9A1 0x9B18 # 0 +0xE9A2 0x9B1A # 0 +0xE9A3 0x9B1F # 0 +0xE9A4 0x9B22 # 0 +0xE9A5 0x9B23 # 0 +0xE9A6 0x9B25 # 0 +0xE9A7 0x9B27 # 0 +0xE9A8 0x9B28 # 0 +0xE9A9 0x9B29 # 0 +0xE9AA 0x9B2A # 0 +0xE9AB 0x9B2E # 0 +0xE9AC 0x9B2F # 0 +0xE9AD 0x9B32 # 0 +0xE9AE 0x9B44 # 0 +0xE9AF 0x9B43 # 0 +0xE9B0 0x9B4F # 0 +0xE9B1 0x9B4D # 0 +0xE9B2 0x9B4E # 0 +0xE9B3 0x9B51 # 0 +0xE9B4 0x9B58 # 0 +0xE9B5 0x9B74 # 0 +0xE9B6 0x9B93 # 0 +0xE9B7 0x9B83 # 0 +0xE9B8 0x9B91 # 0 +0xE9B9 0x9B96 # 0 +0xE9BA 0x9B97 # 0 +0xE9BB 0x9B9F # 0 +0xE9BC 0x9BA0 # 0 +0xE9BD 0x9BA8 # 0 +0xE9BE 0x9BB4 # 0 +0xE9BF 0x9BC0 # 0 +0xE9C0 0x9BCA # 0 +0xE9C1 0x9BB9 # 0 +0xE9C2 0x9BC6 # 0 +0xE9C3 0x9BCF # 0 +0xE9C4 0x9BD1 # 0 +0xE9C5 0x9BD2 # 0 +0xE9C6 0x9BE3 # 0 +0xE9C7 0x9BE2 # 0 +0xE9C8 0x9BE4 # 0 +0xE9C9 0x9BD4 # 0 +0xE9CA 0x9BE1 # 0 +0xE9CB 0x9C3A # 0 +0xE9CC 0x9BF2 # 0 +0xE9CD 0x9BF1 # 0 +0xE9CE 0x9BF0 # 0 +0xE9CF 0x9C15 # 0 +0xE9D0 0x9C14 # 0 +0xE9D1 0x9C09 # 0 +0xE9D2 0x9C13 # 0 +0xE9D3 0x9C0C # 0 +0xE9D4 0x9C06 # 0 +0xE9D5 0x9C08 # 0 +0xE9D6 0x9C12 # 0 +0xE9D7 0x9C0A # 0 +0xE9D8 0x9C04 # 0 +0xE9D9 0x9C2E # 0 +0xE9DA 0x9C1B # 0 +0xE9DB 0x9C25 # 0 +0xE9DC 0x9C24 # 0 +0xE9DD 0x9C21 # 0 +0xE9DE 0x9C30 # 0 +0xE9DF 0x9C47 # 0 +0xE9E0 0x9C32 # 0 +0xE9E1 0x9C46 # 0 +0xE9E2 0x9C3E # 0 +0xE9E3 0x9C5A # 0 +0xE9E4 0x9C60 # 0 +0xE9E5 0x9C67 # 0 +0xE9E6 0x9C76 # 0 +0xE9E7 0x9C78 # 0 +0xE9E8 0x9CE7 # 0 +0xE9E9 0x9CEC # 0 +0xE9EA 0x9CF0 # 0 +0xE9EB 0x9D09 # 0 +0xE9EC 0x9D08 # 0 +0xE9ED 0x9CEB # 0 +0xE9EE 0x9D03 # 0 +0xE9EF 0x9D06 # 0 +0xE9F0 0x9D2A # 0 +0xE9F1 0x9D26 # 0 +0xE9F2 0x9DAF # 0 +0xE9F3 0x9D23 # 0 +0xE9F4 0x9D1F # 0 +0xE9F5 0x9D44 # 0 +0xE9F6 0x9D15 # 0 +0xE9F7 0x9D12 # 0 +0xE9F8 0x9D41 # 0 +0xE9F9 0x9D3F # 0 +0xE9FA 0x9D3E # 0 +0xE9FB 0x9D46 # 0 +0xE9FC 0x9D48 # 0 +0xEA40 0x9D5D # 0 +0xEA41 0x9D5E # 0 +0xEA42 0x9D64 # 0 +0xEA43 0x9D51 # 0 +0xEA44 0x9D50 # 0 +0xEA45 0x9D59 # 0 +0xEA46 0x9D72 # 0 +0xEA47 0x9D89 # 0 +0xEA48 0x9D87 # 0 +0xEA49 0x9DAB # 0 +0xEA4A 0x9D6F # 0 +0xEA4B 0x9D7A # 0 +0xEA4C 0x9D9A # 0 +0xEA4D 0x9DA4 # 0 +0xEA4E 0x9DA9 # 0 +0xEA4F 0x9DB2 # 0 +0xEA50 0x9DC4 # 0 +0xEA51 0x9DC1 # 0 +0xEA52 0x9DBB # 0 +0xEA53 0x9DB8 # 0 +0xEA54 0x9DBA # 0 +0xEA55 0x9DC6 # 0 +0xEA56 0x9DCF # 0 +0xEA57 0x9DC2 # 0 +0xEA58 0x9DD9 # 0 +0xEA59 0x9DD3 # 0 +0xEA5A 0x9DF8 # 0 +0xEA5B 0x9DE6 # 0 +0xEA5C 0x9DED # 0 +0xEA5D 0x9DEF # 0 +0xEA5E 0x9DFD # 0 +0xEA5F 0x9E1A # 0 +0xEA60 0x9E1B # 0 +0xEA61 0x9E1E # 0 +0xEA62 0x9E75 # 0 +0xEA63 0x9E79 # 0 +0xEA64 0x9E7D # 0 +0xEA65 0x9E81 # 0 +0xEA66 0x9E88 # 0 +0xEA67 0x9E8B # 0 +0xEA68 0x9E8C # 0 +0xEA69 0x9E92 # 0 +0xEA6A 0x9E95 # 0 +0xEA6B 0x9E91 # 0 +0xEA6C 0x9E9D # 0 +0xEA6D 0x9EA5 # 0 +0xEA6E 0x9EA9 # 0 +0xEA6F 0x9EB8 # 0 +0xEA70 0x9EAA # 0 +0xEA71 0x9EAD # 0 +0xEA72 0x9761 # 0 +0xEA73 0x9ECC # 0 +0xEA74 0x9ECE # 0 +0xEA75 0x9ECF # 0 +0xEA76 0x9ED0 # 0 +0xEA77 0x9ED4 # 0 +0xEA78 0x9EDC # 0 +0xEA79 0x9EDE # 0 +0xEA7A 0x9EDD # 0 +0xEA7B 0x9EE0 # 0 +0xEA7C 0x9EE5 # 0 +0xEA7D 0x9EE8 # 0 +0xEA7E 0x9EEF # 0 +0xEA80 0x9EF4 # 0 +0xEA81 0x9EF6 # 0 +0xEA82 0x9EF7 # 0 +0xEA83 0x9EF9 # 0 +0xEA84 0x9EFB # 0 +0xEA85 0x9EFC # 0 +0xEA86 0x9EFD # 0 +0xEA87 0x9F07 # 0 +0xEA88 0x9F08 # 0 +0xEA89 0x76B7 # 0 +0xEA8A 0x9F15 # 0 +0xEA8B 0x9F21 # 0 +0xEA8C 0x9F2C # 0 +0xEA8D 0x9F3E # 0 +0xEA8E 0x9F4A # 0 +0xEA8F 0x9F52 # 0 +0xEA90 0x9F54 # 0 +0xEA91 0x9F63 # 0 +0xEA92 0x9F5F # 0 +0xEA93 0x9F60 # 0 +0xEA94 0x9F61 # 0 +0xEA95 0x9F66 # 0 +0xEA96 0x9F67 # 0 +0xEA97 0x9F6C # 0 +0xEA98 0x9F6A # 0 +0xEA99 0x9F77 # 0 +0xEA9A 0x9F72 # 0 +0xEA9B 0x9F76 # 0 +0xEA9C 0x9F95 # 0 +0xEA9D 0x9F9C # 0 +0xEA9E 0x9FA0 # 0 +0xEA9F 0x582F # 0 +0xEAA0 0x69C7 # 0 +0xEAA1 0x9059 # 0 +0xEAA2 0x7464 # 0 +0xEAA3 0x51DC # 0 +0xEAA4 0x7199 # 0 +0xF040 0xE000 # 0 +0xF041 0xE001 # 0 +0xF042 0xE002 # 0 +0xF043 0xE003 # 0 +0xF044 0xE004 # 0 +0xF045 0xE005 # 0 +0xF046 0xE006 # 0 +0xF047 0xE007 # 0 +0xF048 0xE008 # 0 +0xF049 0xE009 # 0 +0xF04A 0xE00A # 0 +0xF04B 0xE00B # 0 +0xF04C 0xE00C # 0 +0xF04D 0xE00D # 0 +0xF04E 0xE00E # 0 +0xF04F 0xE00F # 0 +0xF050 0xE010 # 0 +0xF051 0xE011 # 0 +0xF052 0xE012 # 0 +0xF053 0xE013 # 0 +0xF054 0xE014 # 0 +0xF055 0xE015 # 0 +0xF056 0xE016 # 0 +0xF057 0xE017 # 0 +0xF058 0xE018 # 0 +0xF059 0xE019 # 0 +0xF05A 0xE01A # 0 +0xF05B 0xE01B # 0 +0xF05C 0xE01C # 0 +0xF05D 0xE01D # 0 +0xF05E 0xE01E # 0 +0xF05F 0xE01F # 0 +0xF060 0xE020 # 0 +0xF061 0xE021 # 0 +0xF062 0xE022 # 0 +0xF063 0xE023 # 0 +0xF064 0xE024 # 0 +0xF065 0xE025 # 0 +0xF066 0xE026 # 0 +0xF067 0xE027 # 0 +0xF068 0xE028 # 0 +0xF069 0xE029 # 0 +0xF06A 0xE02A # 0 +0xF06B 0xE02B # 0 +0xF06C 0xE02C # 0 +0xF06D 0xE02D # 0 +0xF06E 0xE02E # 0 +0xF06F 0xE02F # 0 +0xF070 0xE030 # 0 +0xF071 0xE031 # 0 +0xF072 0xE032 # 0 +0xF073 0xE033 # 0 +0xF074 0xE034 # 0 +0xF075 0xE035 # 0 +0xF076 0xE036 # 0 +0xF077 0xE037 # 0 +0xF078 0xE038 # 0 +0xF079 0xE039 # 0 +0xF07A 0xE03A # 0 +0xF07B 0xE03B # 0 +0xF07C 0xE03C # 0 +0xF07D 0xE03D # 0 +0xF07E 0xE03E # 0 +0xF080 0xE03F # 0 +0xF081 0xE040 # 0 +0xF082 0xE041 # 0 +0xF083 0xE042 # 0 +0xF084 0xE043 # 0 +0xF085 0xE044 # 0 +0xF086 0xE045 # 0 +0xF087 0xE046 # 0 +0xF088 0xE047 # 0 +0xF089 0xE048 # 0 +0xF08A 0xE049 # 0 +0xF08B 0xE04A # 0 +0xF08C 0xE04B # 0 +0xF08D 0xE04C # 0 +0xF08E 0xE04D # 0 +0xF08F 0xE04E # 0 +0xF090 0xE04F # 0 +0xF091 0xE050 # 0 +0xF092 0xE051 # 0 +0xF093 0xE052 # 0 +0xF094 0xE053 # 0 +0xF095 0xE054 # 0 +0xF096 0xE055 # 0 +0xF097 0xE056 # 0 +0xF098 0xE057 # 0 +0xF099 0xE058 # 0 +0xF09A 0xE059 # 0 +0xF09B 0xE05A # 0 +0xF09C 0xE05B # 0 +0xF09D 0xE05C # 0 +0xF09E 0xE05D # 0 +0xF09F 0xE05E # 0 +0xF0A0 0xE05F # 0 +0xF0A1 0xE060 # 0 +0xF0A2 0xE061 # 0 +0xF0A3 0xE062 # 0 +0xF0A4 0xE063 # 0 +0xF0A5 0xE064 # 0 +0xF0A6 0xE065 # 0 +0xF0A7 0xE066 # 0 +0xF0A8 0xE067 # 0 +0xF0A9 0xE068 # 0 +0xF0AA 0xE069 # 0 +0xF0AB 0xE06A # 0 +0xF0AC 0xE06B # 0 +0xF0AD 0xE06C # 0 +0xF0AE 0xE06D # 0 +0xF0AF 0xE06E # 0 +0xF0B0 0xE06F # 0 +0xF0B1 0xE070 # 0 +0xF0B2 0xE071 # 0 +0xF0B3 0xE072 # 0 +0xF0B4 0xE073 # 0 +0xF0B5 0xE074 # 0 +0xF0B6 0xE075 # 0 +0xF0B7 0xE076 # 0 +0xF0B8 0xE077 # 0 +0xF0B9 0xE078 # 0 +0xF0BA 0xE079 # 0 +0xF0BB 0xE07A # 0 +0xF0BC 0xE07B # 0 +0xF0BD 0xE07C # 0 +0xF0BE 0xE07D # 0 +0xF0BF 0xE07E # 0 +0xF0C0 0xE07F # 0 +0xF0C1 0xE080 # 0 +0xF0C2 0xE081 # 0 +0xF0C3 0xE082 # 0 +0xF0C4 0xE083 # 0 +0xF0C5 0xE084 # 0 +0xF0C6 0xE085 # 0 +0xF0C7 0xE086 # 0 +0xF0C8 0xE087 # 0 +0xF0C9 0xE088 # 0 +0xF0CA 0xE089 # 0 +0xF0CB 0xE08A # 0 +0xF0CC 0xE08B # 0 +0xF0CD 0xE08C # 0 +0xF0CE 0xE08D # 0 +0xF0CF 0xE08E # 0 +0xF0D0 0xE08F # 0 +0xF0D1 0xE090 # 0 +0xF0D2 0xE091 # 0 +0xF0D3 0xE092 # 0 +0xF0D4 0xE093 # 0 +0xF0D5 0xE094 # 0 +0xF0D6 0xE095 # 0 +0xF0D7 0xE096 # 0 +0xF0D8 0xE097 # 0 +0xF0D9 0xE098 # 0 +0xF0DA 0xE099 # 0 +0xF0DB 0xE09A # 0 +0xF0DC 0xE09B # 0 +0xF0DD 0xE09C # 0 +0xF0DE 0xE09D # 0 +0xF0DF 0xE09E # 0 +0xF0E0 0xE09F # 0 +0xF0E1 0xE0A0 # 0 +0xF0E2 0xE0A1 # 0 +0xF0E3 0xE0A2 # 0 +0xF0E4 0xE0A3 # 0 +0xF0E5 0xE0A4 # 0 +0xF0E6 0xE0A5 # 0 +0xF0E7 0xE0A6 # 0 +0xF0E8 0xE0A7 # 0 +0xF0E9 0xE0A8 # 0 +0xF0EA 0xE0A9 # 0 +0xF0EB 0xE0AA # 0 +0xF0EC 0xE0AB # 0 +0xF0ED 0xE0AC # 0 +0xF0EE 0xE0AD # 0 +0xF0EF 0xE0AE # 0 +0xF0F0 0xE0AF # 0 +0xF0F1 0xE0B0 # 0 +0xF0F2 0xE0B1 # 0 +0xF0F3 0xE0B2 # 0 +0xF0F4 0xE0B3 # 0 +0xF0F5 0xE0B4 # 0 +0xF0F6 0xE0B5 # 0 +0xF0F7 0xE0B6 # 0 +0xF0F8 0xE0B7 # 0 +0xF0F9 0xE0B8 # 0 +0xF0FA 0xE0B9 # 0 +0xF0FB 0xE0BA # 0 +0xF0FC 0xE0BB # 0 +0xF140 0xE0BC # 0 +0xF141 0xE0BD # 0 +0xF142 0xE0BE # 0 +0xF143 0xE0BF # 0 +0xF144 0xE0C0 # 0 +0xF145 0xE0C1 # 0 +0xF146 0xE0C2 # 0 +0xF147 0xE0C3 # 0 +0xF148 0xE0C4 # 0 +0xF149 0xE0C5 # 0 +0xF14A 0xE0C6 # 0 +0xF14B 0xE0C7 # 0 +0xF14C 0xE0C8 # 0 +0xF14D 0xE0C9 # 0 +0xF14E 0xE0CA # 0 +0xF14F 0xE0CB # 0 +0xF150 0xE0CC # 0 +0xF151 0xE0CD # 0 +0xF152 0xE0CE # 0 +0xF153 0xE0CF # 0 +0xF154 0xE0D0 # 0 +0xF155 0xE0D1 # 0 +0xF156 0xE0D2 # 0 +0xF157 0xE0D3 # 0 +0xF158 0xE0D4 # 0 +0xF159 0xE0D5 # 0 +0xF15A 0xE0D6 # 0 +0xF15B 0xE0D7 # 0 +0xF15C 0xE0D8 # 0 +0xF15D 0xE0D9 # 0 +0xF15E 0xE0DA # 0 +0xF15F 0xE0DB # 0 +0xF160 0xE0DC # 0 +0xF161 0xE0DD # 0 +0xF162 0xE0DE # 0 +0xF163 0xE0DF # 0 +0xF164 0xE0E0 # 0 +0xF165 0xE0E1 # 0 +0xF166 0xE0E2 # 0 +0xF167 0xE0E3 # 0 +0xF168 0xE0E4 # 0 +0xF169 0xE0E5 # 0 +0xF16A 0xE0E6 # 0 +0xF16B 0xE0E7 # 0 +0xF16C 0xE0E8 # 0 +0xF16D 0xE0E9 # 0 +0xF16E 0xE0EA # 0 +0xF16F 0xE0EB # 0 +0xF170 0xE0EC # 0 +0xF171 0xE0ED # 0 +0xF172 0xE0EE # 0 +0xF173 0xE0EF # 0 +0xF174 0xE0F0 # 0 +0xF175 0xE0F1 # 0 +0xF176 0xE0F2 # 0 +0xF177 0xE0F3 # 0 +0xF178 0xE0F4 # 0 +0xF179 0xE0F5 # 0 +0xF17A 0xE0F6 # 0 +0xF17B 0xE0F7 # 0 +0xF17C 0xE0F8 # 0 +0xF17D 0xE0F9 # 0 +0xF17E 0xE0FA # 0 +0xF180 0xE0FB # 0 +0xF181 0xE0FC # 0 +0xF182 0xE0FD # 0 +0xF183 0xE0FE # 0 +0xF184 0xE0FF # 0 +0xF185 0xE100 # 0 +0xF186 0xE101 # 0 +0xF187 0xE102 # 0 +0xF188 0xE103 # 0 +0xF189 0xE104 # 0 +0xF18A 0xE105 # 0 +0xF18B 0xE106 # 0 +0xF18C 0xE107 # 0 +0xF18D 0xE108 # 0 +0xF18E 0xE109 # 0 +0xF18F 0xE10A # 0 +0xF190 0xE10B # 0 +0xF191 0xE10C # 0 +0xF192 0xE10D # 0 +0xF193 0xE10E # 0 +0xF194 0xE10F # 0 +0xF195 0xE110 # 0 +0xF196 0xE111 # 0 +0xF197 0xE112 # 0 +0xF198 0xE113 # 0 +0xF199 0xE114 # 0 +0xF19A 0xE115 # 0 +0xF19B 0xE116 # 0 +0xF19C 0xE117 # 0 +0xF19D 0xE118 # 0 +0xF19E 0xE119 # 0 +0xF19F 0xE11A # 0 +0xF1A0 0xE11B # 0 +0xF1A1 0xE11C # 0 +0xF1A2 0xE11D # 0 +0xF1A3 0xE11E # 0 +0xF1A4 0xE11F # 0 +0xF1A5 0xE120 # 0 +0xF1A6 0xE121 # 0 +0xF1A7 0xE122 # 0 +0xF1A8 0xE123 # 0 +0xF1A9 0xE124 # 0 +0xF1AA 0xE125 # 0 +0xF1AB 0xE126 # 0 +0xF1AC 0xE127 # 0 +0xF1AD 0xE128 # 0 +0xF1AE 0xE129 # 0 +0xF1AF 0xE12A # 0 +0xF1B0 0xE12B # 0 +0xF1B1 0xE12C # 0 +0xF1B2 0xE12D # 0 +0xF1B3 0xE12E # 0 +0xF1B4 0xE12F # 0 +0xF1B5 0xE130 # 0 +0xF1B6 0xE131 # 0 +0xF1B7 0xE132 # 0 +0xF1B8 0xE133 # 0 +0xF1B9 0xE134 # 0 +0xF1BA 0xE135 # 0 +0xF1BB 0xE136 # 0 +0xF1BC 0xE137 # 0 +0xF1BD 0xE138 # 0 +0xF1BE 0xE139 # 0 +0xF1BF 0xE13A # 0 +0xF1C0 0xE13B # 0 +0xF1C1 0xE13C # 0 +0xF1C2 0xE13D # 0 +0xF1C3 0xE13E # 0 +0xF1C4 0xE13F # 0 +0xF1C5 0xE140 # 0 +0xF1C6 0xE141 # 0 +0xF1C7 0xE142 # 0 +0xF1C8 0xE143 # 0 +0xF1C9 0xE144 # 0 +0xF1CA 0xE145 # 0 +0xF1CB 0xE146 # 0 +0xF1CC 0xE147 # 0 +0xF1CD 0xE148 # 0 +0xF1CE 0xE149 # 0 +0xF1CF 0xE14A # 0 +0xF1D0 0xE14B # 0 +0xF1D1 0xE14C # 0 +0xF1D2 0xE14D # 0 +0xF1D3 0xE14E # 0 +0xF1D4 0xE14F # 0 +0xF1D5 0xE150 # 0 +0xF1D6 0xE151 # 0 +0xF1D7 0xE152 # 0 +0xF1D8 0xE153 # 0 +0xF1D9 0xE154 # 0 +0xF1DA 0xE155 # 0 +0xF1DB 0xE156 # 0 +0xF1DC 0xE157 # 0 +0xF1DD 0xE158 # 0 +0xF1DE 0xE159 # 0 +0xF1DF 0xE15A # 0 +0xF1E0 0xE15B # 0 +0xF1E1 0xE15C # 0 +0xF1E2 0xE15D # 0 +0xF1E3 0xE15E # 0 +0xF1E4 0xE15F # 0 +0xF1E5 0xE160 # 0 +0xF1E6 0xE161 # 0 +0xF1E7 0xE162 # 0 +0xF1E8 0xE163 # 0 +0xF1E9 0xE164 # 0 +0xF1EA 0xE165 # 0 +0xF1EB 0xE166 # 0 +0xF1EC 0xE167 # 0 +0xF1ED 0xE168 # 0 +0xF1EE 0xE169 # 0 +0xF1EF 0xE16A # 0 +0xF1F0 0xE16B # 0 +0xF1F1 0xE16C # 0 +0xF1F2 0xE16D # 0 +0xF1F3 0xE16E # 0 +0xF1F4 0xE16F # 0 +0xF1F5 0xE170 # 0 +0xF1F6 0xE171 # 0 +0xF1F7 0xE172 # 0 +0xF1F8 0xE173 # 0 +0xF1F9 0xE174 # 0 +0xF1FA 0xE175 # 0 +0xF1FB 0xE176 # 0 +0xF1FC 0xE177 # 0 +0xF240 0xE178 # 0 +0xF241 0xE179 # 0 +0xF242 0xE17A # 0 +0xF243 0xE17B # 0 +0xF244 0xE17C # 0 +0xF245 0xE17D # 0 +0xF246 0xE17E # 0 +0xF247 0xE17F # 0 +0xF248 0xE180 # 0 +0xF249 0xE181 # 0 +0xF24A 0xE182 # 0 +0xF24B 0xE183 # 0 +0xF24C 0xE184 # 0 +0xF24D 0xE185 # 0 +0xF24E 0xE186 # 0 +0xF24F 0xE187 # 0 +0xF250 0xE188 # 0 +0xF251 0xE189 # 0 +0xF252 0xE18A # 0 +0xF253 0xE18B # 0 +0xF254 0xE18C # 0 +0xF255 0xE18D # 0 +0xF256 0xE18E # 0 +0xF257 0xE18F # 0 +0xF258 0xE190 # 0 +0xF259 0xE191 # 0 +0xF25A 0xE192 # 0 +0xF25B 0xE193 # 0 +0xF25C 0xE194 # 0 +0xF25D 0xE195 # 0 +0xF25E 0xE196 # 0 +0xF25F 0xE197 # 0 +0xF260 0xE198 # 0 +0xF261 0xE199 # 0 +0xF262 0xE19A # 0 +0xF263 0xE19B # 0 +0xF264 0xE19C # 0 +0xF265 0xE19D # 0 +0xF266 0xE19E # 0 +0xF267 0xE19F # 0 +0xF268 0xE1A0 # 0 +0xF269 0xE1A1 # 0 +0xF26A 0xE1A2 # 0 +0xF26B 0xE1A3 # 0 +0xF26C 0xE1A4 # 0 +0xF26D 0xE1A5 # 0 +0xF26E 0xE1A6 # 0 +0xF26F 0xE1A7 # 0 +0xF270 0xE1A8 # 0 +0xF271 0xE1A9 # 0 +0xF272 0xE1AA # 0 +0xF273 0xE1AB # 0 +0xF274 0xE1AC # 0 +0xF275 0xE1AD # 0 +0xF276 0xE1AE # 0 +0xF277 0xE1AF # 0 +0xF278 0xE1B0 # 0 +0xF279 0xE1B1 # 0 +0xF27A 0xE1B2 # 0 +0xF27B 0xE1B3 # 0 +0xF27C 0xE1B4 # 0 +0xF27D 0xE1B5 # 0 +0xF27E 0xE1B6 # 0 +0xF280 0xE1B7 # 0 +0xF281 0xE1B8 # 0 +0xF282 0xE1B9 # 0 +0xF283 0xE1BA # 0 +0xF284 0xE1BB # 0 +0xF285 0xE1BC # 0 +0xF286 0xE1BD # 0 +0xF287 0xE1BE # 0 +0xF288 0xE1BF # 0 +0xF289 0xE1C0 # 0 +0xF28A 0xE1C1 # 0 +0xF28B 0xE1C2 # 0 +0xF28C 0xE1C3 # 0 +0xF28D 0xE1C4 # 0 +0xF28E 0xE1C5 # 0 +0xF28F 0xE1C6 # 0 +0xF290 0xE1C7 # 0 +0xF291 0xE1C8 # 0 +0xF292 0xE1C9 # 0 +0xF293 0xE1CA # 0 +0xF294 0xE1CB # 0 +0xF295 0xE1CC # 0 +0xF296 0xE1CD # 0 +0xF297 0xE1CE # 0 +0xF298 0xE1CF # 0 +0xF299 0xE1D0 # 0 +0xF29A 0xE1D1 # 0 +0xF29B 0xE1D2 # 0 +0xF29C 0xE1D3 # 0 +0xF29D 0xE1D4 # 0 +0xF29E 0xE1D5 # 0 +0xF29F 0xE1D6 # 0 +0xF2A0 0xE1D7 # 0 +0xF2A1 0xE1D8 # 0 +0xF2A2 0xE1D9 # 0 +0xF2A3 0xE1DA # 0 +0xF2A4 0xE1DB # 0 +0xF2A5 0xE1DC # 0 +0xF2A6 0xE1DD # 0 +0xF2A7 0xE1DE # 0 +0xF2A8 0xE1DF # 0 +0xF2A9 0xE1E0 # 0 +0xF2AA 0xE1E1 # 0 +0xF2AB 0xE1E2 # 0 +0xF2AC 0xE1E3 # 0 +0xF2AD 0xE1E4 # 0 +0xF2AE 0xE1E5 # 0 +0xF2AF 0xE1E6 # 0 +0xF2B0 0xE1E7 # 0 +0xF2B1 0xE1E8 # 0 +0xF2B2 0xE1E9 # 0 +0xF2B3 0xE1EA # 0 +0xF2B4 0xE1EB # 0 +0xF2B5 0xE1EC # 0 +0xF2B6 0xE1ED # 0 +0xF2B7 0xE1EE # 0 +0xF2B8 0xE1EF # 0 +0xF2B9 0xE1F0 # 0 +0xF2BA 0xE1F1 # 0 +0xF2BB 0xE1F2 # 0 +0xF2BC 0xE1F3 # 0 +0xF2BD 0xE1F4 # 0 +0xF2BE 0xE1F5 # 0 +0xF2BF 0xE1F6 # 0 +0xF2C0 0xE1F7 # 0 +0xF2C1 0xE1F8 # 0 +0xF2C2 0xE1F9 # 0 +0xF2C3 0xE1FA # 0 +0xF2C4 0xE1FB # 0 +0xF2C5 0xE1FC # 0 +0xF2C6 0xE1FD # 0 +0xF2C7 0xE1FE # 0 +0xF2C8 0xE1FF # 0 +0xF2C9 0xE200 # 0 +0xF2CA 0xE201 # 0 +0xF2CB 0xE202 # 0 +0xF2CC 0xE203 # 0 +0xF2CD 0xE204 # 0 +0xF2CE 0xE205 # 0 +0xF2CF 0xE206 # 0 +0xF2D0 0xE207 # 0 +0xF2D1 0xE208 # 0 +0xF2D2 0xE209 # 0 +0xF2D3 0xE20A # 0 +0xF2D4 0xE20B # 0 +0xF2D5 0xE20C # 0 +0xF2D6 0xE20D # 0 +0xF2D7 0xE20E # 0 +0xF2D8 0xE20F # 0 +0xF2D9 0xE210 # 0 +0xF2DA 0xE211 # 0 +0xF2DB 0xE212 # 0 +0xF2DC 0xE213 # 0 +0xF2DD 0xE214 # 0 +0xF2DE 0xE215 # 0 +0xF2DF 0xE216 # 0 +0xF2E0 0xE217 # 0 +0xF2E1 0xE218 # 0 +0xF2E2 0xE219 # 0 +0xF2E3 0xE21A # 0 +0xF2E4 0xE21B # 0 +0xF2E5 0xE21C # 0 +0xF2E6 0xE21D # 0 +0xF2E7 0xE21E # 0 +0xF2E8 0xE21F # 0 +0xF2E9 0xE220 # 0 +0xF2EA 0xE221 # 0 +0xF2EB 0xE222 # 0 +0xF2EC 0xE223 # 0 +0xF2ED 0xE224 # 0 +0xF2EE 0xE225 # 0 +0xF2EF 0xE226 # 0 +0xF2F0 0xE227 # 0 +0xF2F1 0xE228 # 0 +0xF2F2 0xE229 # 0 +0xF2F3 0xE22A # 0 +0xF2F4 0xE22B # 0 +0xF2F5 0xE22C # 0 +0xF2F6 0xE22D # 0 +0xF2F7 0xE22E # 0 +0xF2F8 0xE22F # 0 +0xF2F9 0xE230 # 0 +0xF2FA 0xE231 # 0 +0xF2FB 0xE232 # 0 +0xF2FC 0xE233 # 0 +0xF340 0xE234 # 0 +0xF341 0xE235 # 0 +0xF342 0xE236 # 0 +0xF343 0xE237 # 0 +0xF344 0xE238 # 0 +0xF345 0xE239 # 0 +0xF346 0xE23A # 0 +0xF347 0xE23B # 0 +0xF348 0xE23C # 0 +0xF349 0xE23D # 0 +0xF34A 0xE23E # 0 +0xF34B 0xE23F # 0 +0xF34C 0xE240 # 0 +0xF34D 0xE241 # 0 +0xF34E 0xE242 # 0 +0xF34F 0xE243 # 0 +0xF350 0xE244 # 0 +0xF351 0xE245 # 0 +0xF352 0xE246 # 0 +0xF353 0xE247 # 0 +0xF354 0xE248 # 0 +0xF355 0xE249 # 0 +0xF356 0xE24A # 0 +0xF357 0xE24B # 0 +0xF358 0xE24C # 0 +0xF359 0xE24D # 0 +0xF35A 0xE24E # 0 +0xF35B 0xE24F # 0 +0xF35C 0xE250 # 0 +0xF35D 0xE251 # 0 +0xF35E 0xE252 # 0 +0xF35F 0xE253 # 0 +0xF360 0xE254 # 0 +0xF361 0xE255 # 0 +0xF362 0xE256 # 0 +0xF363 0xE257 # 0 +0xF364 0xE258 # 0 +0xF365 0xE259 # 0 +0xF366 0xE25A # 0 +0xF367 0xE25B # 0 +0xF368 0xE25C # 0 +0xF369 0xE25D # 0 +0xF36A 0xE25E # 0 +0xF36B 0xE25F # 0 +0xF36C 0xE260 # 0 +0xF36D 0xE261 # 0 +0xF36E 0xE262 # 0 +0xF36F 0xE263 # 0 +0xF370 0xE264 # 0 +0xF371 0xE265 # 0 +0xF372 0xE266 # 0 +0xF373 0xE267 # 0 +0xF374 0xE268 # 0 +0xF375 0xE269 # 0 +0xF376 0xE26A # 0 +0xF377 0xE26B # 0 +0xF378 0xE26C # 0 +0xF379 0xE26D # 0 +0xF37A 0xE26E # 0 +0xF37B 0xE26F # 0 +0xF37C 0xE270 # 0 +0xF37D 0xE271 # 0 +0xF37E 0xE272 # 0 +0xF380 0xE273 # 0 +0xF381 0xE274 # 0 +0xF382 0xE275 # 0 +0xF383 0xE276 # 0 +0xF384 0xE277 # 0 +0xF385 0xE278 # 0 +0xF386 0xE279 # 0 +0xF387 0xE27A # 0 +0xF388 0xE27B # 0 +0xF389 0xE27C # 0 +0xF38A 0xE27D # 0 +0xF38B 0xE27E # 0 +0xF38C 0xE27F # 0 +0xF38D 0xE280 # 0 +0xF38E 0xE281 # 0 +0xF38F 0xE282 # 0 +0xF390 0xE283 # 0 +0xF391 0xE284 # 0 +0xF392 0xE285 # 0 +0xF393 0xE286 # 0 +0xF394 0xE287 # 0 +0xF395 0xE288 # 0 +0xF396 0xE289 # 0 +0xF397 0xE28A # 0 +0xF398 0xE28B # 0 +0xF399 0xE28C # 0 +0xF39A 0xE28D # 0 +0xF39B 0xE28E # 0 +0xF39C 0xE28F # 0 +0xF39D 0xE290 # 0 +0xF39E 0xE291 # 0 +0xF39F 0xE292 # 0 +0xF3A0 0xE293 # 0 +0xF3A1 0xE294 # 0 +0xF3A2 0xE295 # 0 +0xF3A3 0xE296 # 0 +0xF3A4 0xE297 # 0 +0xF3A5 0xE298 # 0 +0xF3A6 0xE299 # 0 +0xF3A7 0xE29A # 0 +0xF3A8 0xE29B # 0 +0xF3A9 0xE29C # 0 +0xF3AA 0xE29D # 0 +0xF3AB 0xE29E # 0 +0xF3AC 0xE29F # 0 +0xF3AD 0xE2A0 # 0 +0xF3AE 0xE2A1 # 0 +0xF3AF 0xE2A2 # 0 +0xF3B0 0xE2A3 # 0 +0xF3B1 0xE2A4 # 0 +0xF3B2 0xE2A5 # 0 +0xF3B3 0xE2A6 # 0 +0xF3B4 0xE2A7 # 0 +0xF3B5 0xE2A8 # 0 +0xF3B6 0xE2A9 # 0 +0xF3B7 0xE2AA # 0 +0xF3B8 0xE2AB # 0 +0xF3B9 0xE2AC # 0 +0xF3BA 0xE2AD # 0 +0xF3BB 0xE2AE # 0 +0xF3BC 0xE2AF # 0 +0xF3BD 0xE2B0 # 0 +0xF3BE 0xE2B1 # 0 +0xF3BF 0xE2B2 # 0 +0xF3C0 0xE2B3 # 0 +0xF3C1 0xE2B4 # 0 +0xF3C2 0xE2B5 # 0 +0xF3C3 0xE2B6 # 0 +0xF3C4 0xE2B7 # 0 +0xF3C5 0xE2B8 # 0 +0xF3C6 0xE2B9 # 0 +0xF3C7 0xE2BA # 0 +0xF3C8 0xE2BB # 0 +0xF3C9 0xE2BC # 0 +0xF3CA 0xE2BD # 0 +0xF3CB 0xE2BE # 0 +0xF3CC 0xE2BF # 0 +0xF3CD 0xE2C0 # 0 +0xF3CE 0xE2C1 # 0 +0xF3CF 0xE2C2 # 0 +0xF3D0 0xE2C3 # 0 +0xF3D1 0xE2C4 # 0 +0xF3D2 0xE2C5 # 0 +0xF3D3 0xE2C6 # 0 +0xF3D4 0xE2C7 # 0 +0xF3D5 0xE2C8 # 0 +0xF3D6 0xE2C9 # 0 +0xF3D7 0xE2CA # 0 +0xF3D8 0xE2CB # 0 +0xF3D9 0xE2CC # 0 +0xF3DA 0xE2CD # 0 +0xF3DB 0xE2CE # 0 +0xF3DC 0xE2CF # 0 +0xF3DD 0xE2D0 # 0 +0xF3DE 0xE2D1 # 0 +0xF3DF 0xE2D2 # 0 +0xF3E0 0xE2D3 # 0 +0xF3E1 0xE2D4 # 0 +0xF3E2 0xE2D5 # 0 +0xF3E3 0xE2D6 # 0 +0xF3E4 0xE2D7 # 0 +0xF3E5 0xE2D8 # 0 +0xF3E6 0xE2D9 # 0 +0xF3E7 0xE2DA # 0 +0xF3E8 0xE2DB # 0 +0xF3E9 0xE2DC # 0 +0xF3EA 0xE2DD # 0 +0xF3EB 0xE2DE # 0 +0xF3EC 0xE2DF # 0 +0xF3ED 0xE2E0 # 0 +0xF3EE 0xE2E1 # 0 +0xF3EF 0xE2E2 # 0 +0xF3F0 0xE2E3 # 0 +0xF3F1 0xE2E4 # 0 +0xF3F2 0xE2E5 # 0 +0xF3F3 0xE2E6 # 0 +0xF3F4 0xE2E7 # 0 +0xF3F5 0xE2E8 # 0 +0xF3F6 0xE2E9 # 0 +0xF3F7 0xE2EA # 0 +0xF3F8 0xE2EB # 0 +0xF3F9 0xE2EC # 0 +0xF3FA 0xE2ED # 0 +0xF3FB 0xE2EE # 0 +0xF3FC 0xE2EF # 0 +0xF440 0xE2F0 # 0 +0xF441 0xE2F1 # 0 +0xF442 0xE2F2 # 0 +0xF443 0xE2F3 # 0 +0xF444 0xE2F4 # 0 +0xF445 0xE2F5 # 0 +0xF446 0xE2F6 # 0 +0xF447 0xE2F7 # 0 +0xF448 0xE2F8 # 0 +0xF449 0xE2F9 # 0 +0xF44A 0xE2FA # 0 +0xF44B 0xE2FB # 0 +0xF44C 0xE2FC # 0 +0xF44D 0xE2FD # 0 +0xF44E 0xE2FE # 0 +0xF44F 0xE2FF # 0 +0xF450 0xE300 # 0 +0xF451 0xE301 # 0 +0xF452 0xE302 # 0 +0xF453 0xE303 # 0 +0xF454 0xE304 # 0 +0xF455 0xE305 # 0 +0xF456 0xE306 # 0 +0xF457 0xE307 # 0 +0xF458 0xE308 # 0 +0xF459 0xE309 # 0 +0xF45A 0xE30A # 0 +0xF45B 0xE30B # 0 +0xF45C 0xE30C # 0 +0xF45D 0xE30D # 0 +0xF45E 0xE30E # 0 +0xF45F 0xE30F # 0 +0xF460 0xE310 # 0 +0xF461 0xE311 # 0 +0xF462 0xE312 # 0 +0xF463 0xE313 # 0 +0xF464 0xE314 # 0 +0xF465 0xE315 # 0 +0xF466 0xE316 # 0 +0xF467 0xE317 # 0 +0xF468 0xE318 # 0 +0xF469 0xE319 # 0 +0xF46A 0xE31A # 0 +0xF46B 0xE31B # 0 +0xF46C 0xE31C # 0 +0xF46D 0xE31D # 0 +0xF46E 0xE31E # 0 +0xF46F 0xE31F # 0 +0xF470 0xE320 # 0 +0xF471 0xE321 # 0 +0xF472 0xE322 # 0 +0xF473 0xE323 # 0 +0xF474 0xE324 # 0 +0xF475 0xE325 # 0 +0xF476 0xE326 # 0 +0xF477 0xE327 # 0 +0xF478 0xE328 # 0 +0xF479 0xE329 # 0 +0xF47A 0xE32A # 0 +0xF47B 0xE32B # 0 +0xF47C 0xE32C # 0 +0xF47D 0xE32D # 0 +0xF47E 0xE32E # 0 +0xF480 0xE32F # 0 +0xF481 0xE330 # 0 +0xF482 0xE331 # 0 +0xF483 0xE332 # 0 +0xF484 0xE333 # 0 +0xF485 0xE334 # 0 +0xF486 0xE335 # 0 +0xF487 0xE336 # 0 +0xF488 0xE337 # 0 +0xF489 0xE338 # 0 +0xF48A 0xE339 # 0 +0xF48B 0xE33A # 0 +0xF48C 0xE33B # 0 +0xF48D 0xE33C # 0 +0xF48E 0xE33D # 0 +0xF48F 0xE33E # 0 +0xF490 0xE33F # 0 +0xF491 0xE340 # 0 +0xF492 0xE341 # 0 +0xF493 0xE342 # 0 +0xF494 0xE343 # 0 +0xF495 0xE344 # 0 +0xF496 0xE345 # 0 +0xF497 0xE346 # 0 +0xF498 0xE347 # 0 +0xF499 0xE348 # 0 +0xF49A 0xE349 # 0 +0xF49B 0xE34A # 0 +0xF49C 0xE34B # 0 +0xF49D 0xE34C # 0 +0xF49E 0xE34D # 0 +0xF49F 0xE34E # 0 +0xF4A0 0xE34F # 0 +0xF4A1 0xE350 # 0 +0xF4A2 0xE351 # 0 +0xF4A3 0xE352 # 0 +0xF4A4 0xE353 # 0 +0xF4A5 0xE354 # 0 +0xF4A6 0xE355 # 0 +0xF4A7 0xE356 # 0 +0xF4A8 0xE357 # 0 +0xF4A9 0xE358 # 0 +0xF4AA 0xE359 # 0 +0xF4AB 0xE35A # 0 +0xF4AC 0xE35B # 0 +0xF4AD 0xE35C # 0 +0xF4AE 0xE35D # 0 +0xF4AF 0xE35E # 0 +0xF4B0 0xE35F # 0 +0xF4B1 0xE360 # 0 +0xF4B2 0xE361 # 0 +0xF4B3 0xE362 # 0 +0xF4B4 0xE363 # 0 +0xF4B5 0xE364 # 0 +0xF4B6 0xE365 # 0 +0xF4B7 0xE366 # 0 +0xF4B8 0xE367 # 0 +0xF4B9 0xE368 # 0 +0xF4BA 0xE369 # 0 +0xF4BB 0xE36A # 0 +0xF4BC 0xE36B # 0 +0xF4BD 0xE36C # 0 +0xF4BE 0xE36D # 0 +0xF4BF 0xE36E # 0 +0xF4C0 0xE36F # 0 +0xF4C1 0xE370 # 0 +0xF4C2 0xE371 # 0 +0xF4C3 0xE372 # 0 +0xF4C4 0xE373 # 0 +0xF4C5 0xE374 # 0 +0xF4C6 0xE375 # 0 +0xF4C7 0xE376 # 0 +0xF4C8 0xE377 # 0 +0xF4C9 0xE378 # 0 +0xF4CA 0xE379 # 0 +0xF4CB 0xE37A # 0 +0xF4CC 0xE37B # 0 +0xF4CD 0xE37C # 0 +0xF4CE 0xE37D # 0 +0xF4CF 0xE37E # 0 +0xF4D0 0xE37F # 0 +0xF4D1 0xE380 # 0 +0xF4D2 0xE381 # 0 +0xF4D3 0xE382 # 0 +0xF4D4 0xE383 # 0 +0xF4D5 0xE384 # 0 +0xF4D6 0xE385 # 0 +0xF4D7 0xE386 # 0 +0xF4D8 0xE387 # 0 +0xF4D9 0xE388 # 0 +0xF4DA 0xE389 # 0 +0xF4DB 0xE38A # 0 +0xF4DC 0xE38B # 0 +0xF4DD 0xE38C # 0 +0xF4DE 0xE38D # 0 +0xF4DF 0xE38E # 0 +0xF4E0 0xE38F # 0 +0xF4E1 0xE390 # 0 +0xF4E2 0xE391 # 0 +0xF4E3 0xE392 # 0 +0xF4E4 0xE393 # 0 +0xF4E5 0xE394 # 0 +0xF4E6 0xE395 # 0 +0xF4E7 0xE396 # 0 +0xF4E8 0xE397 # 0 +0xF4E9 0xE398 # 0 +0xF4EA 0xE399 # 0 +0xF4EB 0xE39A # 0 +0xF4EC 0xE39B # 0 +0xF4ED 0xE39C # 0 +0xF4EE 0xE39D # 0 +0xF4EF 0xE39E # 0 +0xF4F0 0xE39F # 0 +0xF4F1 0xE3A0 # 0 +0xF4F2 0xE3A1 # 0 +0xF4F3 0xE3A2 # 0 +0xF4F4 0xE3A3 # 0 +0xF4F5 0xE3A4 # 0 +0xF4F6 0xE3A5 # 0 +0xF4F7 0xE3A6 # 0 +0xF4F8 0xE3A7 # 0 +0xF4F9 0xE3A8 # 0 +0xF4FA 0xE3A9 # 0 +0xF4FB 0xE3AA # 0 +0xF4FC 0xE3AB # 0 +0xF540 0xE3AC # 0 +0xF541 0xE3AD # 0 +0xF542 0xE3AE # 0 +0xF543 0xE3AF # 0 +0xF544 0xE3B0 # 0 +0xF545 0xE3B1 # 0 +0xF546 0xE3B2 # 0 +0xF547 0xE3B3 # 0 +0xF548 0xE3B4 # 0 +0xF549 0xE3B5 # 0 +0xF54A 0xE3B6 # 0 +0xF54B 0xE3B7 # 0 +0xF54C 0xE3B8 # 0 +0xF54D 0xE3B9 # 0 +0xF54E 0xE3BA # 0 +0xF54F 0xE3BB # 0 +0xF550 0xE3BC # 0 +0xF551 0xE3BD # 0 +0xF552 0xE3BE # 0 +0xF553 0xE3BF # 0 +0xF554 0xE3C0 # 0 +0xF555 0xE3C1 # 0 +0xF556 0xE3C2 # 0 +0xF557 0xE3C3 # 0 +0xF558 0xE3C4 # 0 +0xF559 0xE3C5 # 0 +0xF55A 0xE3C6 # 0 +0xF55B 0xE3C7 # 0 +0xF55C 0xE3C8 # 0 +0xF55D 0xE3C9 # 0 +0xF55E 0xE3CA # 0 +0xF55F 0xE3CB # 0 +0xF560 0xE3CC # 0 +0xF561 0xE3CD # 0 +0xF562 0xE3CE # 0 +0xF563 0xE3CF # 0 +0xF564 0xE3D0 # 0 +0xF565 0xE3D1 # 0 +0xF566 0xE3D2 # 0 +0xF567 0xE3D3 # 0 +0xF568 0xE3D4 # 0 +0xF569 0xE3D5 # 0 +0xF56A 0xE3D6 # 0 +0xF56B 0xE3D7 # 0 +0xF56C 0xE3D8 # 0 +0xF56D 0xE3D9 # 0 +0xF56E 0xE3DA # 0 +0xF56F 0xE3DB # 0 +0xF570 0xE3DC # 0 +0xF571 0xE3DD # 0 +0xF572 0xE3DE # 0 +0xF573 0xE3DF # 0 +0xF574 0xE3E0 # 0 +0xF575 0xE3E1 # 0 +0xF576 0xE3E2 # 0 +0xF577 0xE3E3 # 0 +0xF578 0xE3E4 # 0 +0xF579 0xE3E5 # 0 +0xF57A 0xE3E6 # 0 +0xF57B 0xE3E7 # 0 +0xF57C 0xE3E8 # 0 +0xF57D 0xE3E9 # 0 +0xF57E 0xE3EA # 0 +0xF580 0xE3EB # 0 +0xF581 0xE3EC # 0 +0xF582 0xE3ED # 0 +0xF583 0xE3EE # 0 +0xF584 0xE3EF # 0 +0xF585 0xE3F0 # 0 +0xF586 0xE3F1 # 0 +0xF587 0xE3F2 # 0 +0xF588 0xE3F3 # 0 +0xF589 0xE3F4 # 0 +0xF58A 0xE3F5 # 0 +0xF58B 0xE3F6 # 0 +0xF58C 0xE3F7 # 0 +0xF58D 0xE3F8 # 0 +0xF58E 0xE3F9 # 0 +0xF58F 0xE3FA # 0 +0xF590 0xE3FB # 0 +0xF591 0xE3FC # 0 +0xF592 0xE3FD # 0 +0xF593 0xE3FE # 0 +0xF594 0xE3FF # 0 +0xF595 0xE400 # 0 +0xF596 0xE401 # 0 +0xF597 0xE402 # 0 +0xF598 0xE403 # 0 +0xF599 0xE404 # 0 +0xF59A 0xE405 # 0 +0xF59B 0xE406 # 0 +0xF59C 0xE407 # 0 +0xF59D 0xE408 # 0 +0xF59E 0xE409 # 0 +0xF59F 0xE40A # 0 +0xF5A0 0xE40B # 0 +0xF5A1 0xE40C # 0 +0xF5A2 0xE40D # 0 +0xF5A3 0xE40E # 0 +0xF5A4 0xE40F # 0 +0xF5A5 0xE410 # 0 +0xF5A6 0xE411 # 0 +0xF5A7 0xE412 # 0 +0xF5A8 0xE413 # 0 +0xF5A9 0xE414 # 0 +0xF5AA 0xE415 # 0 +0xF5AB 0xE416 # 0 +0xF5AC 0xE417 # 0 +0xF5AD 0xE418 # 0 +0xF5AE 0xE419 # 0 +0xF5AF 0xE41A # 0 +0xF5B0 0xE41B # 0 +0xF5B1 0xE41C # 0 +0xF5B2 0xE41D # 0 +0xF5B3 0xE41E # 0 +0xF5B4 0xE41F # 0 +0xF5B5 0xE420 # 0 +0xF5B6 0xE421 # 0 +0xF5B7 0xE422 # 0 +0xF5B8 0xE423 # 0 +0xF5B9 0xE424 # 0 +0xF5BA 0xE425 # 0 +0xF5BB 0xE426 # 0 +0xF5BC 0xE427 # 0 +0xF5BD 0xE428 # 0 +0xF5BE 0xE429 # 0 +0xF5BF 0xE42A # 0 +0xF5C0 0xE42B # 0 +0xF5C1 0xE42C # 0 +0xF5C2 0xE42D # 0 +0xF5C3 0xE42E # 0 +0xF5C4 0xE42F # 0 +0xF5C5 0xE430 # 0 +0xF5C6 0xE431 # 0 +0xF5C7 0xE432 # 0 +0xF5C8 0xE433 # 0 +0xF5C9 0xE434 # 0 +0xF5CA 0xE435 # 0 +0xF5CB 0xE436 # 0 +0xF5CC 0xE437 # 0 +0xF5CD 0xE438 # 0 +0xF5CE 0xE439 # 0 +0xF5CF 0xE43A # 0 +0xF5D0 0xE43B # 0 +0xF5D1 0xE43C # 0 +0xF5D2 0xE43D # 0 +0xF5D3 0xE43E # 0 +0xF5D4 0xE43F # 0 +0xF5D5 0xE440 # 0 +0xF5D6 0xE441 # 0 +0xF5D7 0xE442 # 0 +0xF5D8 0xE443 # 0 +0xF5D9 0xE444 # 0 +0xF5DA 0xE445 # 0 +0xF5DB 0xE446 # 0 +0xF5DC 0xE447 # 0 +0xF5DD 0xE448 # 0 +0xF5DE 0xE449 # 0 +0xF5DF 0xE44A # 0 +0xF5E0 0xE44B # 0 +0xF5E1 0xE44C # 0 +0xF5E2 0xE44D # 0 +0xF5E3 0xE44E # 0 +0xF5E4 0xE44F # 0 +0xF5E5 0xE450 # 0 +0xF5E6 0xE451 # 0 +0xF5E7 0xE452 # 0 +0xF5E8 0xE453 # 0 +0xF5E9 0xE454 # 0 +0xF5EA 0xE455 # 0 +0xF5EB 0xE456 # 0 +0xF5EC 0xE457 # 0 +0xF5ED 0xE458 # 0 +0xF5EE 0xE459 # 0 +0xF5EF 0xE45A # 0 +0xF5F0 0xE45B # 0 +0xF5F1 0xE45C # 0 +0xF5F2 0xE45D # 0 +0xF5F3 0xE45E # 0 +0xF5F4 0xE45F # 0 +0xF5F5 0xE460 # 0 +0xF5F6 0xE461 # 0 +0xF5F7 0xE462 # 0 +0xF5F8 0xE463 # 0 +0xF5F9 0xE464 # 0 +0xF5FA 0xE465 # 0 +0xF5FB 0xE466 # 0 +0xF5FC 0xE467 # 0 +0xF640 0xE468 # 0 +0xF641 0xE469 # 0 +0xF642 0xE46A # 0 +0xF643 0xE46B # 0 +0xF644 0xE46C # 0 +0xF645 0xE46D # 0 +0xF646 0xE46E # 0 +0xF647 0xE46F # 0 +0xF648 0xE470 # 0 +0xF649 0xE471 # 0 +0xF64A 0xE472 # 0 +0xF64B 0xE473 # 0 +0xF64C 0xE474 # 0 +0xF64D 0xE475 # 0 +0xF64E 0xE476 # 0 +0xF64F 0xE477 # 0 +0xF650 0xE478 # 0 +0xF651 0xE479 # 0 +0xF652 0xE47A # 0 +0xF653 0xE47B # 0 +0xF654 0xE47C # 0 +0xF655 0xE47D # 0 +0xF656 0xE47E # 0 +0xF657 0xE47F # 0 +0xF658 0xE480 # 0 +0xF659 0xE481 # 0 +0xF65A 0xE482 # 0 +0xF65B 0xE483 # 0 +0xF65C 0xE484 # 0 +0xF65D 0xE485 # 0 +0xF65E 0xE486 # 0 +0xF65F 0xE487 # 0 +0xF660 0xE488 # 0 +0xF661 0xE489 # 0 +0xF662 0xE48A # 0 +0xF663 0xE48B # 0 +0xF664 0xE48C # 0 +0xF665 0xE48D # 0 +0xF666 0xE48E # 0 +0xF667 0xE48F # 0 +0xF668 0xE490 # 0 +0xF669 0xE491 # 0 +0xF66A 0xE492 # 0 +0xF66B 0xE493 # 0 +0xF66C 0xE494 # 0 +0xF66D 0xE495 # 0 +0xF66E 0xE496 # 0 +0xF66F 0xE497 # 0 +0xF670 0xE498 # 0 +0xF671 0xE499 # 0 +0xF672 0xE49A # 0 +0xF673 0xE49B # 0 +0xF674 0xE49C # 0 +0xF675 0xE49D # 0 +0xF676 0xE49E # 0 +0xF677 0xE49F # 0 +0xF678 0xE4A0 # 0 +0xF679 0xE4A1 # 0 +0xF67A 0xE4A2 # 0 +0xF67B 0xE4A3 # 0 +0xF67C 0xE4A4 # 0 +0xF67D 0xE4A5 # 0 +0xF67E 0xE4A6 # 0 +0xF680 0xE4A7 # 0 +0xF681 0xE4A8 # 0 +0xF682 0xE4A9 # 0 +0xF683 0xE4AA # 0 +0xF684 0xE4AB # 0 +0xF685 0xE4AC # 0 +0xF686 0xE4AD # 0 +0xF687 0xE4AE # 0 +0xF688 0xE4AF # 0 +0xF689 0xE4B0 # 0 +0xF68A 0xE4B1 # 0 +0xF68B 0xE4B2 # 0 +0xF68C 0xE4B3 # 0 +0xF68D 0xE4B4 # 0 +0xF68E 0xE4B5 # 0 +0xF68F 0xE4B6 # 0 +0xF690 0xE4B7 # 0 +0xF691 0xE4B8 # 0 +0xF692 0xE4B9 # 0 +0xF693 0xE4BA # 0 +0xF694 0xE4BB # 0 +0xF695 0xE4BC # 0 +0xF696 0xE4BD # 0 +0xF697 0xE4BE # 0 +0xF698 0xE4BF # 0 +0xF699 0xE4C0 # 0 +0xF69A 0xE4C1 # 0 +0xF69B 0xE4C2 # 0 +0xF69C 0xE4C3 # 0 +0xF69D 0xE4C4 # 0 +0xF69E 0xE4C5 # 0 +0xF69F 0xE4C6 # 0 +0xF6A0 0xE4C7 # 0 +0xF6A1 0xE4C8 # 0 +0xF6A2 0xE4C9 # 0 +0xF6A3 0xE4CA # 0 +0xF6A4 0xE4CB # 0 +0xF6A5 0xE4CC # 0 +0xF6A6 0xE4CD # 0 +0xF6A7 0xE4CE # 0 +0xF6A8 0xE4CF # 0 +0xF6A9 0xE4D0 # 0 +0xF6AA 0xE4D1 # 0 +0xF6AB 0xE4D2 # 0 +0xF6AC 0xE4D3 # 0 +0xF6AD 0xE4D4 # 0 +0xF6AE 0xE4D5 # 0 +0xF6AF 0xE4D6 # 0 +0xF6B0 0xE4D7 # 0 +0xF6B1 0xE4D8 # 0 +0xF6B2 0xE4D9 # 0 +0xF6B3 0xE4DA # 0 +0xF6B4 0xE4DB # 0 +0xF6B5 0xE4DC # 0 +0xF6B6 0xE4DD # 0 +0xF6B7 0xE4DE # 0 +0xF6B8 0xE4DF # 0 +0xF6B9 0xE4E0 # 0 +0xF6BA 0xE4E1 # 0 +0xF6BB 0xE4E2 # 0 +0xF6BC 0xE4E3 # 0 +0xF6BD 0xE4E4 # 0 +0xF6BE 0xE4E5 # 0 +0xF6BF 0xE4E6 # 0 +0xF6C0 0xE4E7 # 0 +0xF6C1 0xE4E8 # 0 +0xF6C2 0xE4E9 # 0 +0xF6C3 0xE4EA # 0 +0xF6C4 0xE4EB # 0 +0xF6C5 0xE4EC # 0 +0xF6C6 0xE4ED # 0 +0xF6C7 0xE4EE # 0 +0xF6C8 0xE4EF # 0 +0xF6C9 0xE4F0 # 0 +0xF6CA 0xE4F1 # 0 +0xF6CB 0xE4F2 # 0 +0xF6CC 0xE4F3 # 0 +0xF6CD 0xE4F4 # 0 +0xF6CE 0xE4F5 # 0 +0xF6CF 0xE4F6 # 0 +0xF6D0 0xE4F7 # 0 +0xF6D1 0xE4F8 # 0 +0xF6D2 0xE4F9 # 0 +0xF6D3 0xE4FA # 0 +0xF6D4 0xE4FB # 0 +0xF6D5 0xE4FC # 0 +0xF6D6 0xE4FD # 0 +0xF6D7 0xE4FE # 0 +0xF6D8 0xE4FF # 0 +0xF6D9 0xE500 # 0 +0xF6DA 0xE501 # 0 +0xF6DB 0xE502 # 0 +0xF6DC 0xE503 # 0 +0xF6DD 0xE504 # 0 +0xF6DE 0xE505 # 0 +0xF6DF 0xE506 # 0 +0xF6E0 0xE507 # 0 +0xF6E1 0xE508 # 0 +0xF6E2 0xE509 # 0 +0xF6E3 0xE50A # 0 +0xF6E4 0xE50B # 0 +0xF6E5 0xE50C # 0 +0xF6E6 0xE50D # 0 +0xF6E7 0xE50E # 0 +0xF6E8 0xE50F # 0 +0xF6E9 0xE510 # 0 +0xF6EA 0xE511 # 0 +0xF6EB 0xE512 # 0 +0xF6EC 0xE513 # 0 +0xF6ED 0xE514 # 0 +0xF6EE 0xE515 # 0 +0xF6EF 0xE516 # 0 +0xF6F0 0xE517 # 0 +0xF6F1 0xE518 # 0 +0xF6F2 0xE519 # 0 +0xF6F3 0xE51A # 0 +0xF6F4 0xE51B # 0 +0xF6F5 0xE51C # 0 +0xF6F6 0xE51D # 0 +0xF6F7 0xE51E # 0 +0xF6F8 0xE51F # 0 +0xF6F9 0xE520 # 0 +0xF6FA 0xE521 # 0 +0xF6FB 0xE522 # 0 +0xF6FC 0xE523 # 0 +0xF740 0xE524 # 0 +0xF741 0xE525 # 0 +0xF742 0xE526 # 0 +0xF743 0xE527 # 0 +0xF744 0xE528 # 0 +0xF745 0xE529 # 0 +0xF746 0xE52A # 0 +0xF747 0xE52B # 0 +0xF748 0xE52C # 0 +0xF749 0xE52D # 0 +0xF74A 0xE52E # 0 +0xF74B 0xE52F # 0 +0xF74C 0xE530 # 0 +0xF74D 0xE531 # 0 +0xF74E 0xE532 # 0 +0xF74F 0xE533 # 0 +0xF750 0xE534 # 0 +0xF751 0xE535 # 0 +0xF752 0xE536 # 0 +0xF753 0xE537 # 0 +0xF754 0xE538 # 0 +0xF755 0xE539 # 0 +0xF756 0xE53A # 0 +0xF757 0xE53B # 0 +0xF758 0xE53C # 0 +0xF759 0xE53D # 0 +0xF75A 0xE53E # 0 +0xF75B 0xE53F # 0 +0xF75C 0xE540 # 0 +0xF75D 0xE541 # 0 +0xF75E 0xE542 # 0 +0xF75F 0xE543 # 0 +0xF760 0xE544 # 0 +0xF761 0xE545 # 0 +0xF762 0xE546 # 0 +0xF763 0xE547 # 0 +0xF764 0xE548 # 0 +0xF765 0xE549 # 0 +0xF766 0xE54A # 0 +0xF767 0xE54B # 0 +0xF768 0xE54C # 0 +0xF769 0xE54D # 0 +0xF76A 0xE54E # 0 +0xF76B 0xE54F # 0 +0xF76C 0xE550 # 0 +0xF76D 0xE551 # 0 +0xF76E 0xE552 # 0 +0xF76F 0xE553 # 0 +0xF770 0xE554 # 0 +0xF771 0xE555 # 0 +0xF772 0xE556 # 0 +0xF773 0xE557 # 0 +0xF774 0xE558 # 0 +0xF775 0xE559 # 0 +0xF776 0xE55A # 0 +0xF777 0xE55B # 0 +0xF778 0xE55C # 0 +0xF779 0xE55D # 0 +0xF77A 0xE55E # 0 +0xF77B 0xE55F # 0 +0xF77C 0xE560 # 0 +0xF77D 0xE561 # 0 +0xF77E 0xE562 # 0 +0xF780 0xE563 # 0 +0xF781 0xE564 # 0 +0xF782 0xE565 # 0 +0xF783 0xE566 # 0 +0xF784 0xE567 # 0 +0xF785 0xE568 # 0 +0xF786 0xE569 # 0 +0xF787 0xE56A # 0 +0xF788 0xE56B # 0 +0xF789 0xE56C # 0 +0xF78A 0xE56D # 0 +0xF78B 0xE56E # 0 +0xF78C 0xE56F # 0 +0xF78D 0xE570 # 0 +0xF78E 0xE571 # 0 +0xF78F 0xE572 # 0 +0xF790 0xE573 # 0 +0xF791 0xE574 # 0 +0xF792 0xE575 # 0 +0xF793 0xE576 # 0 +0xF794 0xE577 # 0 +0xF795 0xE578 # 0 +0xF796 0xE579 # 0 +0xF797 0xE57A # 0 +0xF798 0xE57B # 0 +0xF799 0xE57C # 0 +0xF79A 0xE57D # 0 +0xF79B 0xE57E # 0 +0xF79C 0xE57F # 0 +0xF79D 0xE580 # 0 +0xF79E 0xE581 # 0 +0xF79F 0xE582 # 0 +0xF7A0 0xE583 # 0 +0xF7A1 0xE584 # 0 +0xF7A2 0xE585 # 0 +0xF7A3 0xE586 # 0 +0xF7A4 0xE587 # 0 +0xF7A5 0xE588 # 0 +0xF7A6 0xE589 # 0 +0xF7A7 0xE58A # 0 +0xF7A8 0xE58B # 0 +0xF7A9 0xE58C # 0 +0xF7AA 0xE58D # 0 +0xF7AB 0xE58E # 0 +0xF7AC 0xE58F # 0 +0xF7AD 0xE590 # 0 +0xF7AE 0xE591 # 0 +0xF7AF 0xE592 # 0 +0xF7B0 0xE593 # 0 +0xF7B1 0xE594 # 0 +0xF7B2 0xE595 # 0 +0xF7B3 0xE596 # 0 +0xF7B4 0xE597 # 0 +0xF7B5 0xE598 # 0 +0xF7B6 0xE599 # 0 +0xF7B7 0xE59A # 0 +0xF7B8 0xE59B # 0 +0xF7B9 0xE59C # 0 +0xF7BA 0xE59D # 0 +0xF7BB 0xE59E # 0 +0xF7BC 0xE59F # 0 +0xF7BD 0xE5A0 # 0 +0xF7BE 0xE5A1 # 0 +0xF7BF 0xE5A2 # 0 +0xF7C0 0xE5A3 # 0 +0xF7C1 0xE5A4 # 0 +0xF7C2 0xE5A5 # 0 +0xF7C3 0xE5A6 # 0 +0xF7C4 0xE5A7 # 0 +0xF7C5 0xE5A8 # 0 +0xF7C6 0xE5A9 # 0 +0xF7C7 0xE5AA # 0 +0xF7C8 0xE5AB # 0 +0xF7C9 0xE5AC # 0 +0xF7CA 0xE5AD # 0 +0xF7CB 0xE5AE # 0 +0xF7CC 0xE5AF # 0 +0xF7CD 0xE5B0 # 0 +0xF7CE 0xE5B1 # 0 +0xF7CF 0xE5B2 # 0 +0xF7D0 0xE5B3 # 0 +0xF7D1 0xE5B4 # 0 +0xF7D2 0xE5B5 # 0 +0xF7D3 0xE5B6 # 0 +0xF7D4 0xE5B7 # 0 +0xF7D5 0xE5B8 # 0 +0xF7D6 0xE5B9 # 0 +0xF7D7 0xE5BA # 0 +0xF7D8 0xE5BB # 0 +0xF7D9 0xE5BC # 0 +0xF7DA 0xE5BD # 0 +0xF7DB 0xE5BE # 0 +0xF7DC 0xE5BF # 0 +0xF7DD 0xE5C0 # 0 +0xF7DE 0xE5C1 # 0 +0xF7DF 0xE5C2 # 0 +0xF7E0 0xE5C3 # 0 +0xF7E1 0xE5C4 # 0 +0xF7E2 0xE5C5 # 0 +0xF7E3 0xE5C6 # 0 +0xF7E4 0xE5C7 # 0 +0xF7E5 0xE5C8 # 0 +0xF7E6 0xE5C9 # 0 +0xF7E7 0xE5CA # 0 +0xF7E8 0xE5CB # 0 +0xF7E9 0xE5CC # 0 +0xF7EA 0xE5CD # 0 +0xF7EB 0xE5CE # 0 +0xF7EC 0xE5CF # 0 +0xF7ED 0xE5D0 # 0 +0xF7EE 0xE5D1 # 0 +0xF7EF 0xE5D2 # 0 +0xF7F0 0xE5D3 # 0 +0xF7F1 0xE5D4 # 0 +0xF7F2 0xE5D5 # 0 +0xF7F3 0xE5D6 # 0 +0xF7F4 0xE5D7 # 0 +0xF7F5 0xE5D8 # 0 +0xF7F6 0xE5D9 # 0 +0xF7F7 0xE5DA # 0 +0xF7F8 0xE5DB # 0 +0xF7F9 0xE5DC # 0 +0xF7FA 0xE5DD # 0 +0xF7FB 0xE5DE # 0 +0xF7FC 0xE5DF # 0 +0xF840 0xE5E0 # 0 +0xF841 0xE5E1 # 0 +0xF842 0xE5E2 # 0 +0xF843 0xE5E3 # 0 +0xF844 0xE5E4 # 0 +0xF845 0xE5E5 # 0 +0xF846 0xE5E6 # 0 +0xF847 0xE5E7 # 0 +0xF848 0xE5E8 # 0 +0xF849 0xE5E9 # 0 +0xF84A 0xE5EA # 0 +0xF84B 0xE5EB # 0 +0xF84C 0xE5EC # 0 +0xF84D 0xE5ED # 0 +0xF84E 0xE5EE # 0 +0xF84F 0xE5EF # 0 +0xF850 0xE5F0 # 0 +0xF851 0xE5F1 # 0 +0xF852 0xE5F2 # 0 +0xF853 0xE5F3 # 0 +0xF854 0xE5F4 # 0 +0xF855 0xE5F5 # 0 +0xF856 0xE5F6 # 0 +0xF857 0xE5F7 # 0 +0xF858 0xE5F8 # 0 +0xF859 0xE5F9 # 0 +0xF85A 0xE5FA # 0 +0xF85B 0xE5FB # 0 +0xF85C 0xE5FC # 0 +0xF85D 0xE5FD # 0 +0xF85E 0xE5FE # 0 +0xF85F 0xE5FF # 0 +0xF860 0xE600 # 0 +0xF861 0xE601 # 0 +0xF862 0xE602 # 0 +0xF863 0xE603 # 0 +0xF864 0xE604 # 0 +0xF865 0xE605 # 0 +0xF866 0xE606 # 0 +0xF867 0xE607 # 0 +0xF868 0xE608 # 0 +0xF869 0xE609 # 0 +0xF86A 0xE60A # 0 +0xF86B 0xE60B # 0 +0xF86C 0xE60C # 0 +0xF86D 0xE60D # 0 +0xF86E 0xE60E # 0 +0xF86F 0xE60F # 0 +0xF870 0xE610 # 0 +0xF871 0xE611 # 0 +0xF872 0xE612 # 0 +0xF873 0xE613 # 0 +0xF874 0xE614 # 0 +0xF875 0xE615 # 0 +0xF876 0xE616 # 0 +0xF877 0xE617 # 0 +0xF878 0xE618 # 0 +0xF879 0xE619 # 0 +0xF87A 0xE61A # 0 +0xF87B 0xE61B # 0 +0xF87C 0xE61C # 0 +0xF87D 0xE61D # 0 +0xF87E 0xE61E # 0 +0xF880 0xE61F # 0 +0xF881 0xE620 # 0 +0xF882 0xE621 # 0 +0xF883 0xE622 # 0 +0xF884 0xE623 # 0 +0xF885 0xE624 # 0 +0xF886 0xE625 # 0 +0xF887 0xE626 # 0 +0xF888 0xE627 # 0 +0xF889 0xE628 # 0 +0xF88A 0xE629 # 0 +0xF88B 0xE62A # 0 +0xF88C 0xE62B # 0 +0xF88D 0xE62C # 0 +0xF88E 0xE62D # 0 +0xF88F 0xE62E # 0 +0xF890 0xE62F # 0 +0xF891 0xE630 # 0 +0xF892 0xE631 # 0 +0xF893 0xE632 # 0 +0xF894 0xE633 # 0 +0xF895 0xE634 # 0 +0xF896 0xE635 # 0 +0xF897 0xE636 # 0 +0xF898 0xE637 # 0 +0xF899 0xE638 # 0 +0xF89A 0xE639 # 0 +0xF89B 0xE63A # 0 +0xF89C 0xE63B # 0 +0xF89D 0xE63C # 0 +0xF89E 0xE63D # 0 +0xF89F 0xE63E # 0 +0xF8A0 0xE63F # 0 +0xF8A1 0xE640 # 0 +0xF8A2 0xE641 # 0 +0xF8A3 0xE642 # 0 +0xF8A4 0xE643 # 0 +0xF8A5 0xE644 # 0 +0xF8A6 0xE645 # 0 +0xF8A7 0xE646 # 0 +0xF8A8 0xE647 # 0 +0xF8A9 0xE648 # 0 +0xF8AA 0xE649 # 0 +0xF8AB 0xE64A # 0 +0xF8AC 0xE64B # 0 +0xF8AD 0xE64C # 0 +0xF8AE 0xE64D # 0 +0xF8AF 0xE64E # 0 +0xF8B0 0xE64F # 0 +0xF8B1 0xE650 # 0 +0xF8B2 0xE651 # 0 +0xF8B3 0xE652 # 0 +0xF8B4 0xE653 # 0 +0xF8B5 0xE654 # 0 +0xF8B6 0xE655 # 0 +0xF8B7 0xE656 # 0 +0xF8B8 0xE657 # 0 +0xF8B9 0xE658 # 0 +0xF8BA 0xE659 # 0 +0xF8BB 0xE65A # 0 +0xF8BC 0xE65B # 0 +0xF8BD 0xE65C # 0 +0xF8BE 0xE65D # 0 +0xF8BF 0xE65E # 0 +0xF8C0 0xE65F # 0 +0xF8C1 0xE660 # 0 +0xF8C2 0xE661 # 0 +0xF8C3 0xE662 # 0 +0xF8C4 0xE663 # 0 +0xF8C5 0xE664 # 0 +0xF8C6 0xE665 # 0 +0xF8C7 0xE666 # 0 +0xF8C8 0xE667 # 0 +0xF8C9 0xE668 # 0 +0xF8CA 0xE669 # 0 +0xF8CB 0xE66A # 0 +0xF8CC 0xE66B # 0 +0xF8CD 0xE66C # 0 +0xF8CE 0xE66D # 0 +0xF8CF 0xE66E # 0 +0xF8D0 0xE66F # 0 +0xF8D1 0xE670 # 0 +0xF8D2 0xE671 # 0 +0xF8D3 0xE672 # 0 +0xF8D4 0xE673 # 0 +0xF8D5 0xE674 # 0 +0xF8D6 0xE675 # 0 +0xF8D7 0xE676 # 0 +0xF8D8 0xE677 # 0 +0xF8D9 0xE678 # 0 +0xF8DA 0xE679 # 0 +0xF8DB 0xE67A # 0 +0xF8DC 0xE67B # 0 +0xF8DD 0xE67C # 0 +0xF8DE 0xE67D # 0 +0xF8DF 0xE67E # 0 +0xF8E0 0xE67F # 0 +0xF8E1 0xE680 # 0 +0xF8E2 0xE681 # 0 +0xF8E3 0xE682 # 0 +0xF8E4 0xE683 # 0 +0xF8E5 0xE684 # 0 +0xF8E6 0xE685 # 0 +0xF8E7 0xE686 # 0 +0xF8E8 0xE687 # 0 +0xF8E9 0xE688 # 0 +0xF8EA 0xE689 # 0 +0xF8EB 0xE68A # 0 +0xF8EC 0xE68B # 0 +0xF8ED 0xE68C # 0 +0xF8EE 0xE68D # 0 +0xF8EF 0xE68E # 0 +0xF8F0 0xE68F # 0 +0xF8F1 0xE690 # 0 +0xF8F2 0xE691 # 0 +0xF8F3 0xE692 # 0 +0xF8F4 0xE693 # 0 +0xF8F5 0xE694 # 0 +0xF8F6 0xE695 # 0 +0xF8F7 0xE696 # 0 +0xF8F8 0xE697 # 0 +0xF8F9 0xE698 # 0 +0xF8FA 0xE699 # 0 +0xF8FB 0xE69A # 0 +0xF8FC 0xE69B # 0 +0xF940 0xE69C # 0 +0xF941 0xE69D # 0 +0xF942 0xE69E # 0 +0xF943 0xE69F # 0 +0xF944 0xE6A0 # 0 +0xF945 0xE6A1 # 0 +0xF946 0xE6A2 # 0 +0xF947 0xE6A3 # 0 +0xF948 0xE6A4 # 0 +0xF949 0xE6A5 # 0 +0xF94A 0xE6A6 # 0 +0xF94B 0xE6A7 # 0 +0xF94C 0xE6A8 # 0 +0xF94D 0xE6A9 # 0 +0xF94E 0xE6AA # 0 +0xF94F 0xE6AB # 0 +0xF950 0xE6AC # 0 +0xF951 0xE6AD # 0 +0xF952 0xE6AE # 0 +0xF953 0xE6AF # 0 +0xF954 0xE6B0 # 0 +0xF955 0xE6B1 # 0 +0xF956 0xE6B2 # 0 +0xF957 0xE6B3 # 0 +0xF958 0xE6B4 # 0 +0xF959 0xE6B5 # 0 +0xF95A 0xE6B6 # 0 +0xF95B 0xE6B7 # 0 +0xF95C 0xE6B8 # 0 +0xF95D 0xE6B9 # 0 +0xF95E 0xE6BA # 0 +0xF95F 0xE6BB # 0 +0xF960 0xE6BC # 0 +0xF961 0xE6BD # 0 +0xF962 0xE6BE # 0 +0xF963 0xE6BF # 0 +0xF964 0xE6C0 # 0 +0xF965 0xE6C1 # 0 +0xF966 0xE6C2 # 0 +0xF967 0xE6C3 # 0 +0xF968 0xE6C4 # 0 +0xF969 0xE6C5 # 0 +0xF96A 0xE6C6 # 0 +0xF96B 0xE6C7 # 0 +0xF96C 0xE6C8 # 0 +0xF96D 0xE6C9 # 0 +0xF96E 0xE6CA # 0 +0xF96F 0xE6CB # 0 +0xF970 0xE6CC # 0 +0xF971 0xE6CD # 0 +0xF972 0xE6CE # 0 +0xF973 0xE6CF # 0 +0xF974 0xE6D0 # 0 +0xF975 0xE6D1 # 0 +0xF976 0xE6D2 # 0 +0xF977 0xE6D3 # 0 +0xF978 0xE6D4 # 0 +0xF979 0xE6D5 # 0 +0xF97A 0xE6D6 # 0 +0xF97B 0xE6D7 # 0 +0xF97C 0xE6D8 # 0 +0xF97D 0xE6D9 # 0 +0xF97E 0xE6DA # 0 +0xF980 0xE6DB # 0 +0xF981 0xE6DC # 0 +0xF982 0xE6DD # 0 +0xF983 0xE6DE # 0 +0xF984 0xE6DF # 0 +0xF985 0xE6E0 # 0 +0xF986 0xE6E1 # 0 +0xF987 0xE6E2 # 0 +0xF988 0xE6E3 # 0 +0xF989 0xE6E4 # 0 +0xF98A 0xE6E5 # 0 +0xF98B 0xE6E6 # 0 +0xF98C 0xE6E7 # 0 +0xF98D 0xE6E8 # 0 +0xF98E 0xE6E9 # 0 +0xF98F 0xE6EA # 0 +0xF990 0xE6EB # 0 +0xF991 0xE6EC # 0 +0xF992 0xE6ED # 0 +0xF993 0xE6EE # 0 +0xF994 0xE6EF # 0 +0xF995 0xE6F0 # 0 +0xF996 0xE6F1 # 0 +0xF997 0xE6F2 # 0 +0xF998 0xE6F3 # 0 +0xF999 0xE6F4 # 0 +0xF99A 0xE6F5 # 0 +0xF99B 0xE6F6 # 0 +0xF99C 0xE6F7 # 0 +0xF99D 0xE6F8 # 0 +0xF99E 0xE6F9 # 0 +0xF99F 0xE6FA # 0 +0xF9A0 0xE6FB # 0 +0xF9A1 0xE6FC # 0 +0xF9A2 0xE6FD # 0 +0xF9A3 0xE6FE # 0 +0xF9A4 0xE6FF # 0 +0xF9A5 0xE700 # 0 +0xF9A6 0xE701 # 0 +0xF9A7 0xE702 # 0 +0xF9A8 0xE703 # 0 +0xF9A9 0xE704 # 0 +0xF9AA 0xE705 # 0 +0xF9AB 0xE706 # 0 +0xF9AC 0xE707 # 0 +0xF9AD 0xE708 # 0 +0xF9AE 0xE709 # 0 +0xF9AF 0xE70A # 0 +0xF9B0 0xE70B # 0 +0xF9B1 0xE70C # 0 +0xF9B2 0xE70D # 0 +0xF9B3 0xE70E # 0 +0xF9B4 0xE70F # 0 +0xF9B5 0xE710 # 0 +0xF9B6 0xE711 # 0 +0xF9B7 0xE712 # 0 +0xF9B8 0xE713 # 0 +0xF9B9 0xE714 # 0 +0xF9BA 0xE715 # 0 +0xF9BB 0xE716 # 0 +0xF9BC 0xE717 # 0 +0xF9BD 0xE718 # 0 +0xF9BE 0xE719 # 0 +0xF9BF 0xE71A # 0 +0xF9C0 0xE71B # 0 +0xF9C1 0xE71C # 0 +0xF9C2 0xE71D # 0 +0xF9C3 0xE71E # 0 +0xF9C4 0xE71F # 0 +0xF9C5 0xE720 # 0 +0xF9C6 0xE721 # 0 +0xF9C7 0xE722 # 0 +0xF9C8 0xE723 # 0 +0xF9C9 0xE724 # 0 +0xF9CA 0xE725 # 0 +0xF9CB 0xE726 # 0 +0xF9CC 0xE727 # 0 +0xF9CD 0xE728 # 0 +0xF9CE 0xE729 # 0 +0xF9CF 0xE72A # 0 +0xF9D0 0xE72B # 0 +0xF9D1 0xE72C # 0 +0xF9D2 0xE72D # 0 +0xF9D3 0xE72E # 0 +0xF9D4 0xE72F # 0 +0xF9D5 0xE730 # 0 +0xF9D6 0xE731 # 0 +0xF9D7 0xE732 # 0 +0xF9D8 0xE733 # 0 +0xF9D9 0xE734 # 0 +0xF9DA 0xE735 # 0 +0xF9DB 0xE736 # 0 +0xF9DC 0xE737 # 0 +0xF9DD 0xE738 # 0 +0xF9DE 0xE739 # 0 +0xF9DF 0xE73A # 0 +0xF9E0 0xE73B # 0 +0xF9E1 0xE73C # 0 +0xF9E2 0xE73D # 0 +0xF9E3 0xE73E # 0 +0xF9E4 0xE73F # 0 +0xF9E5 0xE740 # 0 +0xF9E6 0xE741 # 0 +0xF9E7 0xE742 # 0 +0xF9E8 0xE743 # 0 +0xF9E9 0xE744 # 0 +0xF9EA 0xE745 # 0 +0xF9EB 0xE746 # 0 +0xF9EC 0xE747 # 0 +0xF9ED 0xE748 # 0 +0xF9EE 0xE749 # 0 +0xF9EF 0xE74A # 0 +0xF9F0 0xE74B # 0 +0xF9F1 0xE74C # 0 +0xF9F2 0xE74D # 0 +0xF9F3 0xE74E # 0 +0xF9F4 0xE74F # 0 +0xF9F5 0xE750 # 0 +0xF9F6 0xE751 # 0 +0xF9F7 0xE752 # 0 +0xF9F8 0xE753 # 0 +0xF9F9 0xE754 # 0 +0xF9FA 0xE755 # 0 +0xF9FB 0xE756 # 0 +0xF9FC 0xE757 # 0 +0xFA40 0x2170 # 0 +0xFA41 0x2171 # 0 +0xFA42 0x2172 # 0 +0xFA43 0x2173 # 0 +0xFA44 0x2174 # 0 +0xFA45 0x2175 # 0 +0xFA46 0x2176 # 0 +0xFA47 0x2177 # 0 +0xFA48 0x2178 # 0 +0xFA49 0x2179 # 0 +0xFA55 0xFFE4 # 0 +0xFA56 0xFF07 # 0 +0xFA57 0xFF02 # 0 +0xFA5C 0x7E8A # 0 +0xFA5D 0x891C # 0 +0xFA5E 0x9348 # 0 +0xFA5F 0x9288 # 0 +0xFA60 0x84DC # 0 +0xFA61 0x4FC9 # 0 +0xFA62 0x70BB # 0 +0xFA63 0x6631 # 0 +0xFA64 0x68C8 # 0 +0xFA65 0x92F9 # 0 +0xFA66 0x66FB # 0 +0xFA67 0x5F45 # 0 +0xFA68 0x4E28 # 0 +0xFA69 0x4EE1 # 0 +0xFA6A 0x4EFC # 0 +0xFA6B 0x4F00 # 0 +0xFA6C 0x4F03 # 0 +0xFA6D 0x4F39 # 0 +0xFA6E 0x4F56 # 0 +0xFA6F 0x4F92 # 0 +0xFA70 0x4F8A # 0 +0xFA71 0x4F9A # 0 +0xFA72 0x4F94 # 0 +0xFA73 0x4FCD # 0 +0xFA74 0x5040 # 0 +0xFA75 0x5022 # 0 +0xFA76 0x4FFF # 0 +0xFA77 0x501E # 0 +0xFA78 0x5046 # 0 +0xFA79 0x5070 # 0 +0xFA7A 0x5042 # 0 +0xFA7B 0x5094 # 0 +0xFA7C 0x50F4 # 0 +0xFA7D 0x50D8 # 0 +0xFA7E 0x514A # 0 +0xFA80 0x5164 # 0 +0xFA81 0x519D # 0 +0xFA82 0x51BE # 0 +0xFA83 0x51EC # 0 +0xFA84 0x5215 # 0 +0xFA85 0x529C # 0 +0xFA86 0x52A6 # 0 +0xFA87 0x52C0 # 0 +0xFA88 0x52DB # 0 +0xFA89 0x5300 # 0 +0xFA8A 0x5307 # 0 +0xFA8B 0x5324 # 0 +0xFA8C 0x5372 # 0 +0xFA8D 0x5393 # 0 +0xFA8E 0x53B2 # 0 +0xFA8F 0x53DD # 0 +0xFA90 0xFA0E # 0 +0xFA91 0x549C # 0 +0xFA92 0x548A # 0 +0xFA93 0x54A9 # 0 +0xFA94 0x54FF # 0 +0xFA95 0x5586 # 0 +0xFA96 0x5759 # 0 +0xFA97 0x5765 # 0 +0xFA98 0x57AC # 0 +0xFA99 0x57C8 # 0 +0xFA9A 0x57C7 # 0 +0xFA9B 0xFA0F # 0 +0xFA9C 0xFA10 # 0 +0xFA9D 0x589E # 0 +0xFA9E 0x58B2 # 0 +0xFA9F 0x590B # 0 +0xFAA0 0x5953 # 0 +0xFAA1 0x595B # 0 +0xFAA2 0x595D # 0 +0xFAA3 0x5963 # 0 +0xFAA4 0x59A4 # 0 +0xFAA5 0x59BA # 0 +0xFAA6 0x5B56 # 0 +0xFAA7 0x5BC0 # 0 +0xFAA8 0x752F # 0 +0xFAA9 0x5BD8 # 0 +0xFAAA 0x5BEC # 0 +0xFAAB 0x5C1E # 0 +0xFAAC 0x5CA6 # 0 +0xFAAD 0x5CBA # 0 +0xFAAE 0x5CF5 # 0 +0xFAAF 0x5D27 # 0 +0xFAB0 0x5D53 # 0 +0xFAB1 0xFA11 # 0 +0xFAB2 0x5D42 # 0 +0xFAB3 0x5D6D # 0 +0xFAB4 0x5DB8 # 0 +0xFAB5 0x5DB9 # 0 +0xFAB6 0x5DD0 # 0 +0xFAB7 0x5F21 # 0 +0xFAB8 0x5F34 # 0 +0xFAB9 0x5F67 # 0 +0xFABA 0x5FB7 # 0 +0xFABB 0x5FDE # 0 +0xFABC 0x605D # 0 +0xFABD 0x6085 # 0 +0xFABE 0x608A # 0 +0xFABF 0x60DE # 0 +0xFAC0 0x60D5 # 0 +0xFAC1 0x6120 # 0 +0xFAC2 0x60F2 # 0 +0xFAC3 0x6111 # 0 +0xFAC4 0x6137 # 0 +0xFAC5 0x6130 # 0 +0xFAC6 0x6198 # 0 +0xFAC7 0x6213 # 0 +0xFAC8 0x62A6 # 0 +0xFAC9 0x63F5 # 0 +0xFACA 0x6460 # 0 +0xFACB 0x649D # 0 +0xFACC 0x64CE # 0 +0xFACD 0x654E # 0 +0xFACE 0x6600 # 0 +0xFACF 0x6615 # 0 +0xFAD0 0x663B # 0 +0xFAD1 0x6609 # 0 +0xFAD2 0x662E # 0 +0xFAD3 0x661E # 0 +0xFAD4 0x6624 # 0 +0xFAD5 0x6665 # 0 +0xFAD6 0x6657 # 0 +0xFAD7 0x6659 # 0 +0xFAD8 0xFA12 # 0 +0xFAD9 0x6673 # 0 +0xFADA 0x6699 # 0 +0xFADB 0x66A0 # 0 +0xFADC 0x66B2 # 0 +0xFADD 0x66BF # 0 +0xFADE 0x66FA # 0 +0xFADF 0x670E # 0 +0xFAE0 0xF929 # 0 +0xFAE1 0x6766 # 0 +0xFAE2 0x67BB # 0 +0xFAE3 0x6852 # 0 +0xFAE4 0x67C0 # 0 +0xFAE5 0x6801 # 0 +0xFAE6 0x6844 # 0 +0xFAE7 0x68CF # 0 +0xFAE8 0xFA13 # 0 +0xFAE9 0x6968 # 0 +0xFAEA 0xFA14 # 0 +0xFAEB 0x6998 # 0 +0xFAEC 0x69E2 # 0 +0xFAED 0x6A30 # 0 +0xFAEE 0x6A6B # 0 +0xFAEF 0x6A46 # 0 +0xFAF0 0x6A73 # 0 +0xFAF1 0x6A7E # 0 +0xFAF2 0x6AE2 # 0 +0xFAF3 0x6AE4 # 0 +0xFAF4 0x6BD6 # 0 +0xFAF5 0x6C3F # 0 +0xFAF6 0x6C5C # 0 +0xFAF7 0x6C86 # 0 +0xFAF8 0x6C6F # 0 +0xFAF9 0x6CDA # 0 +0xFAFA 0x6D04 # 0 +0xFAFB 0x6D87 # 0 +0xFAFC 0x6D6F # 0 +0xFB40 0x6D96 # 0 +0xFB41 0x6DAC # 0 +0xFB42 0x6DCF # 0 +0xFB43 0x6DF8 # 0 +0xFB44 0x6DF2 # 0 +0xFB45 0x6DFC # 0 +0xFB46 0x6E39 # 0 +0xFB47 0x6E5C # 0 +0xFB48 0x6E27 # 0 +0xFB49 0x6E3C # 0 +0xFB4A 0x6EBF # 0 +0xFB4B 0x6F88 # 0 +0xFB4C 0x6FB5 # 0 +0xFB4D 0x6FF5 # 0 +0xFB4E 0x7005 # 0 +0xFB4F 0x7007 # 0 +0xFB50 0x7028 # 0 +0xFB51 0x7085 # 0 +0xFB52 0x70AB # 0 +0xFB53 0x710F # 0 +0xFB54 0x7104 # 0 +0xFB55 0x715C # 0 +0xFB56 0x7146 # 0 +0xFB57 0x7147 # 0 +0xFB58 0xFA15 # 0 +0xFB59 0x71C1 # 0 +0xFB5A 0x71FE # 0 +0xFB5B 0x72B1 # 0 +0xFB5C 0x72BE # 0 +0xFB5D 0x7324 # 0 +0xFB5E 0xFA16 # 0 +0xFB5F 0x7377 # 0 +0xFB60 0x73BD # 0 +0xFB61 0x73C9 # 0 +0xFB62 0x73D6 # 0 +0xFB63 0x73E3 # 0 +0xFB64 0x73D2 # 0 +0xFB65 0x7407 # 0 +0xFB66 0x73F5 # 0 +0xFB67 0x7426 # 0 +0xFB68 0x742A # 0 +0xFB69 0x7429 # 0 +0xFB6A 0x742E # 0 +0xFB6B 0x7462 # 0 +0xFB6C 0x7489 # 0 +0xFB6D 0x749F # 0 +0xFB6E 0x7501 # 0 +0xFB6F 0x756F # 0 +0xFB70 0x7682 # 0 +0xFB71 0x769C # 0 +0xFB72 0x769E # 0 +0xFB73 0x769B # 0 +0xFB74 0x76A6 # 0 +0xFB75 0xFA17 # 0 +0xFB76 0x7746 # 0 +0xFB77 0x52AF # 0 +0xFB78 0x7821 # 0 +0xFB79 0x784E # 0 +0xFB7A 0x7864 # 0 +0xFB7B 0x787A # 0 +0xFB7C 0x7930 # 0 +0xFB7D 0xFA18 # 0 +0xFB7E 0xFA19 # 0 +0xFB80 0xFA1A # 0 +0xFB81 0x7994 # 0 +0xFB82 0xFA1B # 0 +0xFB83 0x799B # 0 +0xFB84 0x7AD1 # 0 +0xFB85 0x7AE7 # 0 +0xFB86 0xFA1C # 0 +0xFB87 0x7AEB # 0 +0xFB88 0x7B9E # 0 +0xFB89 0xFA1D # 0 +0xFB8A 0x7D48 # 0 +0xFB8B 0x7D5C # 0 +0xFB8C 0x7DB7 # 0 +0xFB8D 0x7DA0 # 0 +0xFB8E 0x7DD6 # 0 +0xFB8F 0x7E52 # 0 +0xFB90 0x7F47 # 0 +0xFB91 0x7FA1 # 0 +0xFB92 0xFA1E # 0 +0xFB93 0x8301 # 0 +0xFB94 0x8362 # 0 +0xFB95 0x837F # 0 +0xFB96 0x83C7 # 0 +0xFB97 0x83F6 # 0 +0xFB98 0x8448 # 0 +0xFB99 0x84B4 # 0 +0xFB9A 0x8553 # 0 +0xFB9B 0x8559 # 0 +0xFB9C 0x856B # 0 +0xFB9D 0xFA1F # 0 +0xFB9E 0x85B0 # 0 +0xFB9F 0xFA20 # 0 +0xFBA0 0xFA21 # 0 +0xFBA1 0x8807 # 0 +0xFBA2 0x88F5 # 0 +0xFBA3 0x8A12 # 0 +0xFBA4 0x8A37 # 0 +0xFBA5 0x8A79 # 0 +0xFBA6 0x8AA7 # 0 +0xFBA7 0x8ABE # 0 +0xFBA8 0x8ADF # 0 +0xFBA9 0xFA22 # 0 +0xFBAA 0x8AF6 # 0 +0xFBAB 0x8B53 # 0 +0xFBAC 0x8B7F # 0 +0xFBAD 0x8CF0 # 0 +0xFBAE 0x8CF4 # 0 +0xFBAF 0x8D12 # 0 +0xFBB0 0x8D76 # 0 +0xFBB1 0xFA23 # 0 +0xFBB2 0x8ECF # 0 +0xFBB3 0xFA24 # 0 +0xFBB4 0xFA25 # 0 +0xFBB5 0x9067 # 0 +0xFBB6 0x90DE # 0 +0xFBB7 0xFA26 # 0 +0xFBB8 0x9115 # 0 +0xFBB9 0x9127 # 0 +0xFBBA 0x91DA # 0 +0xFBBB 0x91D7 # 0 +0xFBBC 0x91DE # 0 +0xFBBD 0x91ED # 0 +0xFBBE 0x91EE # 0 +0xFBBF 0x91E4 # 0 +0xFBC0 0x91E5 # 0 +0xFBC1 0x9206 # 0 +0xFBC2 0x9210 # 0 +0xFBC3 0x920A # 0 +0xFBC4 0x923A # 0 +0xFBC5 0x9240 # 0 +0xFBC6 0x923C # 0 +0xFBC7 0x924E # 0 +0xFBC8 0x9259 # 0 +0xFBC9 0x9251 # 0 +0xFBCA 0x9239 # 0 +0xFBCB 0x9267 # 0 +0xFBCC 0x92A7 # 0 +0xFBCD 0x9277 # 0 +0xFBCE 0x9278 # 0 +0xFBCF 0x92E7 # 0 +0xFBD0 0x92D7 # 0 +0xFBD1 0x92D9 # 0 +0xFBD2 0x92D0 # 0 +0xFBD3 0xFA27 # 0 +0xFBD4 0x92D5 # 0 +0xFBD5 0x92E0 # 0 +0xFBD6 0x92D3 # 0 +0xFBD7 0x9325 # 0 +0xFBD8 0x9321 # 0 +0xFBD9 0x92FB # 0 +0xFBDA 0xFA28 # 0 +0xFBDB 0x931E # 0 +0xFBDC 0x92FF # 0 +0xFBDD 0x931D # 0 +0xFBDE 0x9302 # 0 +0xFBDF 0x9370 # 0 +0xFBE0 0x9357 # 0 +0xFBE1 0x93A4 # 0 +0xFBE2 0x93C6 # 0 +0xFBE3 0x93DE # 0 +0xFBE4 0x93F8 # 0 +0xFBE5 0x9431 # 0 +0xFBE6 0x9445 # 0 +0xFBE7 0x9448 # 0 +0xFBE8 0x9592 # 0 +0xFBE9 0xF9DC # 0 +0xFBEA 0xFA29 # 0 +0xFBEB 0x969D # 0 +0xFBEC 0x96AF # 0 +0xFBED 0x9733 # 0 +0xFBEE 0x973B # 0 +0xFBEF 0x9743 # 0 +0xFBF0 0x974D # 0 +0xFBF1 0x974F # 0 +0xFBF2 0x9751 # 0 +0xFBF3 0x9755 # 0 +0xFBF4 0x9857 # 0 +0xFBF5 0x9865 # 0 +0xFBF6 0xFA2A # 0 +0xFBF7 0xFA2B # 0 +0xFBF8 0x9927 # 0 +0xFBF9 0xFA2C # 0 +0xFBFA 0x999E # 0 +0xFBFB 0x9A4E # 0 +0xFBFC 0x9AD9 # 0 +0xFC40 0x9ADC # 0 +0xFC41 0x9B75 # 0 +0xFC42 0x9B72 # 0 +0xFC43 0x9B8F # 0 +0xFC44 0x9BB1 # 0 +0xFC45 0x9BBB # 0 +0xFC46 0x9C00 # 0 +0xFC47 0x9D70 # 0 +0xFC48 0x9D6B # 0 +0xFC49 0xFA2D # 0 +0xFC4A 0x9E19 # 0 +0xFC4B 0x9ED1 # 0 diff --git a/data/windows-936.txt b/data/windows-936.txt new file mode 100644 index 000000000..2a1548200 --- /dev/null +++ b/data/windows-936.txt @@ -0,0 +1,24071 @@ +# cp936.txt - Legacy to Unicode charmap +0x0000 0x0000 # 0 +0x0001 0x0001 # 0 +0x0002 0x0002 # 0 +0x0003 0x0003 # 0 +0x0004 0x0004 # 0 +0x0005 0x0005 # 0 +0x0006 0x0006 # 0 +0x0007 0x0007 # 0 +0x0008 0x0008 # 0 +0x0009 0x0009 # 0 +0x000A 0x000A # 0 +0x000B 0x000B # 0 +0x000C 0x000C # 0 +0x000D 0x000D # 0 +0x000E 0x000E # 0 +0x000F 0x000F # 0 +0x0010 0x0010 # 0 +0x0011 0x0011 # 0 +0x0012 0x0012 # 0 +0x0013 0x0013 # 0 +0x0014 0x0014 # 0 +0x0015 0x0015 # 0 +0x0016 0x0016 # 0 +0x0017 0x0017 # 0 +0x0018 0x0018 # 0 +0x0019 0x0019 # 0 +0x001A 0x001A # 0 +0x001B 0x001B # 0 +0x001C 0x001C # 0 +0x001D 0x001D # 0 +0x001E 0x001E # 0 +0x001F 0x001F # 0 +0x0020 0x0020 # 0 +0x0021 0x0021 # 0 +0x0022 0x0022 # 0 +0x0023 0x0023 # 0 +0x0024 0x0024 # 0 +0x0025 0x0025 # 0 +0x0026 0x0026 # 0 +0x0027 0x0027 # 0 +0x0028 0x0028 # 0 +0x0029 0x0029 # 0 +0x002A 0x002A # 0 +0x002B 0x002B # 0 +0x002C 0x002C # 0 +0x002D 0x002D # 0 +0x002E 0x002E # 0 +0x002F 0x002F # 0 +0x0030 0x0030 # 0 +0x0031 0x0031 # 0 +0x0032 0x0032 # 0 +0x0033 0x0033 # 0 +0x0034 0x0034 # 0 +0x0035 0x0035 # 0 +0x0036 0x0036 # 0 +0x0037 0x0037 # 0 +0x0038 0x0038 # 0 +0x0039 0x0039 # 0 +0x003A 0x003A # 0 +0x003B 0x003B # 0 +0x003C 0x003C # 0 +0x003D 0x003D # 0 +0x003E 0x003E # 0 +0x003F 0x003F # 0 +0x0040 0x0040 # 0 +0x0041 0x0041 # 0 +0x0042 0x0042 # 0 +0x0043 0x0043 # 0 +0x0044 0x0044 # 0 +0x0045 0x0045 # 0 +0x0046 0x0046 # 0 +0x0047 0x0047 # 0 +0x0048 0x0048 # 0 +0x0049 0x0049 # 0 +0x004A 0x004A # 0 +0x004B 0x004B # 0 +0x004C 0x004C # 0 +0x004D 0x004D # 0 +0x004E 0x004E # 0 +0x004F 0x004F # 0 +0x0050 0x0050 # 0 +0x0051 0x0051 # 0 +0x0052 0x0052 # 0 +0x0053 0x0053 # 0 +0x0054 0x0054 # 0 +0x0055 0x0055 # 0 +0x0056 0x0056 # 0 +0x0057 0x0057 # 0 +0x0058 0x0058 # 0 +0x0059 0x0059 # 0 +0x005A 0x005A # 0 +0x005B 0x005B # 0 +0x005C 0x005C # 0 +0x005D 0x005D # 0 +0x005E 0x005E # 0 +0x005F 0x005F # 0 +0x0060 0x0060 # 0 +0x0061 0x0061 # 0 +0x0062 0x0062 # 0 +0x0063 0x0063 # 0 +0x0064 0x0064 # 0 +0x0065 0x0065 # 0 +0x0066 0x0066 # 0 +0x0067 0x0067 # 0 +0x0068 0x0068 # 0 +0x0069 0x0069 # 0 +0x006A 0x006A # 0 +0x006B 0x006B # 0 +0x006C 0x006C # 0 +0x006D 0x006D # 0 +0x006E 0x006E # 0 +0x006F 0x006F # 0 +0x0070 0x0070 # 0 +0x0071 0x0071 # 0 +0x0072 0x0072 # 0 +0x0073 0x0073 # 0 +0x0074 0x0074 # 0 +0x0075 0x0075 # 0 +0x0076 0x0076 # 0 +0x0077 0x0077 # 0 +0x0078 0x0078 # 0 +0x0079 0x0079 # 0 +0x007A 0x007A # 0 +0x007B 0x007B # 0 +0x007C 0x007C # 0 +0x007D 0x007D # 0 +0x007E 0x007E # 0 +0x007F 0x007F # 0 +0x0080 0x20AC # 0 +0x00FF 0xF8F5 # 0 +0x8140 0x4E02 # 0 +0x8141 0x4E04 # 0 +0x8142 0x4E05 # 0 +0x8143 0x4E06 # 0 +0x8144 0x4E0F # 0 +0x8145 0x4E12 # 0 +0x8146 0x4E17 # 0 +0x8147 0x4E1F # 0 +0x8148 0x4E20 # 0 +0x8149 0x4E21 # 0 +0x814A 0x4E23 # 0 +0x814B 0x4E26 # 0 +0x814C 0x4E29 # 0 +0x814D 0x4E2E # 0 +0x814E 0x4E2F # 0 +0x814F 0x4E31 # 0 +0x8150 0x4E33 # 0 +0x8151 0x4E35 # 0 +0x8152 0x4E37 # 0 +0x8153 0x4E3C # 0 +0x8154 0x4E40 # 0 +0x8155 0x4E41 # 0 +0x8156 0x4E42 # 0 +0x8157 0x4E44 # 0 +0x8158 0x4E46 # 0 +0x8159 0x4E4A # 0 +0x815A 0x4E51 # 0 +0x815B 0x4E55 # 0 +0x815C 0x4E57 # 0 +0x815D 0x4E5A # 0 +0x815E 0x4E5B # 0 +0x815F 0x4E62 # 0 +0x8160 0x4E63 # 0 +0x8161 0x4E64 # 0 +0x8162 0x4E65 # 0 +0x8163 0x4E67 # 0 +0x8164 0x4E68 # 0 +0x8165 0x4E6A # 0 +0x8166 0x4E6B # 0 +0x8167 0x4E6C # 0 +0x8168 0x4E6D # 0 +0x8169 0x4E6E # 0 +0x816A 0x4E6F # 0 +0x816B 0x4E72 # 0 +0x816C 0x4E74 # 0 +0x816D 0x4E75 # 0 +0x816E 0x4E76 # 0 +0x816F 0x4E77 # 0 +0x8170 0x4E78 # 0 +0x8171 0x4E79 # 0 +0x8172 0x4E7A # 0 +0x8173 0x4E7B # 0 +0x8174 0x4E7C # 0 +0x8175 0x4E7D # 0 +0x8176 0x4E7F # 0 +0x8177 0x4E80 # 0 +0x8178 0x4E81 # 0 +0x8179 0x4E82 # 0 +0x817A 0x4E83 # 0 +0x817B 0x4E84 # 0 +0x817C 0x4E85 # 0 +0x817D 0x4E87 # 0 +0x817E 0x4E8A # 0 +0x8180 0x4E90 # 0 +0x8181 0x4E96 # 0 +0x8182 0x4E97 # 0 +0x8183 0x4E99 # 0 +0x8184 0x4E9C # 0 +0x8185 0x4E9D # 0 +0x8186 0x4E9E # 0 +0x8187 0x4EA3 # 0 +0x8188 0x4EAA # 0 +0x8189 0x4EAF # 0 +0x818A 0x4EB0 # 0 +0x818B 0x4EB1 # 0 +0x818C 0x4EB4 # 0 +0x818D 0x4EB6 # 0 +0x818E 0x4EB7 # 0 +0x818F 0x4EB8 # 0 +0x8190 0x4EB9 # 0 +0x8191 0x4EBC # 0 +0x8192 0x4EBD # 0 +0x8193 0x4EBE # 0 +0x8194 0x4EC8 # 0 +0x8195 0x4ECC # 0 +0x8196 0x4ECF # 0 +0x8197 0x4ED0 # 0 +0x8198 0x4ED2 # 0 +0x8199 0x4EDA # 0 +0x819A 0x4EDB # 0 +0x819B 0x4EDC # 0 +0x819C 0x4EE0 # 0 +0x819D 0x4EE2 # 0 +0x819E 0x4EE6 # 0 +0x819F 0x4EE7 # 0 +0x81A0 0x4EE9 # 0 +0x81A1 0x4EED # 0 +0x81A2 0x4EEE # 0 +0x81A3 0x4EEF # 0 +0x81A4 0x4EF1 # 0 +0x81A5 0x4EF4 # 0 +0x81A6 0x4EF8 # 0 +0x81A7 0x4EF9 # 0 +0x81A8 0x4EFA # 0 +0x81A9 0x4EFC # 0 +0x81AA 0x4EFE # 0 +0x81AB 0x4F00 # 0 +0x81AC 0x4F02 # 0 +0x81AD 0x4F03 # 0 +0x81AE 0x4F04 # 0 +0x81AF 0x4F05 # 0 +0x81B0 0x4F06 # 0 +0x81B1 0x4F07 # 0 +0x81B2 0x4F08 # 0 +0x81B3 0x4F0B # 0 +0x81B4 0x4F0C # 0 +0x81B5 0x4F12 # 0 +0x81B6 0x4F13 # 0 +0x81B7 0x4F14 # 0 +0x81B8 0x4F15 # 0 +0x81B9 0x4F16 # 0 +0x81BA 0x4F1C # 0 +0x81BB 0x4F1D # 0 +0x81BC 0x4F21 # 0 +0x81BD 0x4F23 # 0 +0x81BE 0x4F28 # 0 +0x81BF 0x4F29 # 0 +0x81C0 0x4F2C # 0 +0x81C1 0x4F2D # 0 +0x81C2 0x4F2E # 0 +0x81C3 0x4F31 # 0 +0x81C4 0x4F33 # 0 +0x81C5 0x4F35 # 0 +0x81C6 0x4F37 # 0 +0x81C7 0x4F39 # 0 +0x81C8 0x4F3B # 0 +0x81C9 0x4F3E # 0 +0x81CA 0x4F3F # 0 +0x81CB 0x4F40 # 0 +0x81CC 0x4F41 # 0 +0x81CD 0x4F42 # 0 +0x81CE 0x4F44 # 0 +0x81CF 0x4F45 # 0 +0x81D0 0x4F47 # 0 +0x81D1 0x4F48 # 0 +0x81D2 0x4F49 # 0 +0x81D3 0x4F4A # 0 +0x81D4 0x4F4B # 0 +0x81D5 0x4F4C # 0 +0x81D6 0x4F52 # 0 +0x81D7 0x4F54 # 0 +0x81D8 0x4F56 # 0 +0x81D9 0x4F61 # 0 +0x81DA 0x4F62 # 0 +0x81DB 0x4F66 # 0 +0x81DC 0x4F68 # 0 +0x81DD 0x4F6A # 0 +0x81DE 0x4F6B # 0 +0x81DF 0x4F6D # 0 +0x81E0 0x4F6E # 0 +0x81E1 0x4F71 # 0 +0x81E2 0x4F72 # 0 +0x81E3 0x4F75 # 0 +0x81E4 0x4F77 # 0 +0x81E5 0x4F78 # 0 +0x81E6 0x4F79 # 0 +0x81E7 0x4F7A # 0 +0x81E8 0x4F7D # 0 +0x81E9 0x4F80 # 0 +0x81EA 0x4F81 # 0 +0x81EB 0x4F82 # 0 +0x81EC 0x4F85 # 0 +0x81ED 0x4F86 # 0 +0x81EE 0x4F87 # 0 +0x81EF 0x4F8A # 0 +0x81F0 0x4F8C # 0 +0x81F1 0x4F8E # 0 +0x81F2 0x4F90 # 0 +0x81F3 0x4F92 # 0 +0x81F4 0x4F93 # 0 +0x81F5 0x4F95 # 0 +0x81F6 0x4F96 # 0 +0x81F7 0x4F98 # 0 +0x81F8 0x4F99 # 0 +0x81F9 0x4F9A # 0 +0x81FA 0x4F9C # 0 +0x81FB 0x4F9E # 0 +0x81FC 0x4F9F # 0 +0x81FD 0x4FA1 # 0 +0x81FE 0x4FA2 # 0 +0x8240 0x4FA4 # 0 +0x8241 0x4FAB # 0 +0x8242 0x4FAD # 0 +0x8243 0x4FB0 # 0 +0x8244 0x4FB1 # 0 +0x8245 0x4FB2 # 0 +0x8246 0x4FB3 # 0 +0x8247 0x4FB4 # 0 +0x8248 0x4FB6 # 0 +0x8249 0x4FB7 # 0 +0x824A 0x4FB8 # 0 +0x824B 0x4FB9 # 0 +0x824C 0x4FBA # 0 +0x824D 0x4FBB # 0 +0x824E 0x4FBC # 0 +0x824F 0x4FBD # 0 +0x8250 0x4FBE # 0 +0x8251 0x4FC0 # 0 +0x8252 0x4FC1 # 0 +0x8253 0x4FC2 # 0 +0x8254 0x4FC6 # 0 +0x8255 0x4FC7 # 0 +0x8256 0x4FC8 # 0 +0x8257 0x4FC9 # 0 +0x8258 0x4FCB # 0 +0x8259 0x4FCC # 0 +0x825A 0x4FCD # 0 +0x825B 0x4FD2 # 0 +0x825C 0x4FD3 # 0 +0x825D 0x4FD4 # 0 +0x825E 0x4FD5 # 0 +0x825F 0x4FD6 # 0 +0x8260 0x4FD9 # 0 +0x8261 0x4FDB # 0 +0x8262 0x4FE0 # 0 +0x8263 0x4FE2 # 0 +0x8264 0x4FE4 # 0 +0x8265 0x4FE5 # 0 +0x8266 0x4FE7 # 0 +0x8267 0x4FEB # 0 +0x8268 0x4FEC # 0 +0x8269 0x4FF0 # 0 +0x826A 0x4FF2 # 0 +0x826B 0x4FF4 # 0 +0x826C 0x4FF5 # 0 +0x826D 0x4FF6 # 0 +0x826E 0x4FF7 # 0 +0x826F 0x4FF9 # 0 +0x8270 0x4FFB # 0 +0x8271 0x4FFC # 0 +0x8272 0x4FFD # 0 +0x8273 0x4FFF # 0 +0x8274 0x5000 # 0 +0x8275 0x5001 # 0 +0x8276 0x5002 # 0 +0x8277 0x5003 # 0 +0x8278 0x5004 # 0 +0x8279 0x5005 # 0 +0x827A 0x5006 # 0 +0x827B 0x5007 # 0 +0x827C 0x5008 # 0 +0x827D 0x5009 # 0 +0x827E 0x500A # 0 +0x8280 0x500B # 0 +0x8281 0x500E # 0 +0x8282 0x5010 # 0 +0x8283 0x5011 # 0 +0x8284 0x5013 # 0 +0x8285 0x5015 # 0 +0x8286 0x5016 # 0 +0x8287 0x5017 # 0 +0x8288 0x501B # 0 +0x8289 0x501D # 0 +0x828A 0x501E # 0 +0x828B 0x5020 # 0 +0x828C 0x5022 # 0 +0x828D 0x5023 # 0 +0x828E 0x5024 # 0 +0x828F 0x5027 # 0 +0x8290 0x502B # 0 +0x8291 0x502F # 0 +0x8292 0x5030 # 0 +0x8293 0x5031 # 0 +0x8294 0x5032 # 0 +0x8295 0x5033 # 0 +0x8296 0x5034 # 0 +0x8297 0x5035 # 0 +0x8298 0x5036 # 0 +0x8299 0x5037 # 0 +0x829A 0x5038 # 0 +0x829B 0x5039 # 0 +0x829C 0x503B # 0 +0x829D 0x503D # 0 +0x829E 0x503F # 0 +0x829F 0x5040 # 0 +0x82A0 0x5041 # 0 +0x82A1 0x5042 # 0 +0x82A2 0x5044 # 0 +0x82A3 0x5045 # 0 +0x82A4 0x5046 # 0 +0x82A5 0x5049 # 0 +0x82A6 0x504A # 0 +0x82A7 0x504B # 0 +0x82A8 0x504D # 0 +0x82A9 0x5050 # 0 +0x82AA 0x5051 # 0 +0x82AB 0x5052 # 0 +0x82AC 0x5053 # 0 +0x82AD 0x5054 # 0 +0x82AE 0x5056 # 0 +0x82AF 0x5057 # 0 +0x82B0 0x5058 # 0 +0x82B1 0x5059 # 0 +0x82B2 0x505B # 0 +0x82B3 0x505D # 0 +0x82B4 0x505E # 0 +0x82B5 0x505F # 0 +0x82B6 0x5060 # 0 +0x82B7 0x5061 # 0 +0x82B8 0x5062 # 0 +0x82B9 0x5063 # 0 +0x82BA 0x5064 # 0 +0x82BB 0x5066 # 0 +0x82BC 0x5067 # 0 +0x82BD 0x5068 # 0 +0x82BE 0x5069 # 0 +0x82BF 0x506A # 0 +0x82C0 0x506B # 0 +0x82C1 0x506D # 0 +0x82C2 0x506E # 0 +0x82C3 0x506F # 0 +0x82C4 0x5070 # 0 +0x82C5 0x5071 # 0 +0x82C6 0x5072 # 0 +0x82C7 0x5073 # 0 +0x82C8 0x5074 # 0 +0x82C9 0x5075 # 0 +0x82CA 0x5078 # 0 +0x82CB 0x5079 # 0 +0x82CC 0x507A # 0 +0x82CD 0x507C # 0 +0x82CE 0x507D # 0 +0x82CF 0x5081 # 0 +0x82D0 0x5082 # 0 +0x82D1 0x5083 # 0 +0x82D2 0x5084 # 0 +0x82D3 0x5086 # 0 +0x82D4 0x5087 # 0 +0x82D5 0x5089 # 0 +0x82D6 0x508A # 0 +0x82D7 0x508B # 0 +0x82D8 0x508C # 0 +0x82D9 0x508E # 0 +0x82DA 0x508F # 0 +0x82DB 0x5090 # 0 +0x82DC 0x5091 # 0 +0x82DD 0x5092 # 0 +0x82DE 0x5093 # 0 +0x82DF 0x5094 # 0 +0x82E0 0x5095 # 0 +0x82E1 0x5096 # 0 +0x82E2 0x5097 # 0 +0x82E3 0x5098 # 0 +0x82E4 0x5099 # 0 +0x82E5 0x509A # 0 +0x82E6 0x509B # 0 +0x82E7 0x509C # 0 +0x82E8 0x509D # 0 +0x82E9 0x509E # 0 +0x82EA 0x509F # 0 +0x82EB 0x50A0 # 0 +0x82EC 0x50A1 # 0 +0x82ED 0x50A2 # 0 +0x82EE 0x50A4 # 0 +0x82EF 0x50A6 # 0 +0x82F0 0x50AA # 0 +0x82F1 0x50AB # 0 +0x82F2 0x50AD # 0 +0x82F3 0x50AE # 0 +0x82F4 0x50AF # 0 +0x82F5 0x50B0 # 0 +0x82F6 0x50B1 # 0 +0x82F7 0x50B3 # 0 +0x82F8 0x50B4 # 0 +0x82F9 0x50B5 # 0 +0x82FA 0x50B6 # 0 +0x82FB 0x50B7 # 0 +0x82FC 0x50B8 # 0 +0x82FD 0x50B9 # 0 +0x82FE 0x50BC # 0 +0x8340 0x50BD # 0 +0x8341 0x50BE # 0 +0x8342 0x50BF # 0 +0x8343 0x50C0 # 0 +0x8344 0x50C1 # 0 +0x8345 0x50C2 # 0 +0x8346 0x50C3 # 0 +0x8347 0x50C4 # 0 +0x8348 0x50C5 # 0 +0x8349 0x50C6 # 0 +0x834A 0x50C7 # 0 +0x834B 0x50C8 # 0 +0x834C 0x50C9 # 0 +0x834D 0x50CA # 0 +0x834E 0x50CB # 0 +0x834F 0x50CC # 0 +0x8350 0x50CD # 0 +0x8351 0x50CE # 0 +0x8352 0x50D0 # 0 +0x8353 0x50D1 # 0 +0x8354 0x50D2 # 0 +0x8355 0x50D3 # 0 +0x8356 0x50D4 # 0 +0x8357 0x50D5 # 0 +0x8358 0x50D7 # 0 +0x8359 0x50D8 # 0 +0x835A 0x50D9 # 0 +0x835B 0x50DB # 0 +0x835C 0x50DC # 0 +0x835D 0x50DD # 0 +0x835E 0x50DE # 0 +0x835F 0x50DF # 0 +0x8360 0x50E0 # 0 +0x8361 0x50E1 # 0 +0x8362 0x50E2 # 0 +0x8363 0x50E3 # 0 +0x8364 0x50E4 # 0 +0x8365 0x50E5 # 0 +0x8366 0x50E8 # 0 +0x8367 0x50E9 # 0 +0x8368 0x50EA # 0 +0x8369 0x50EB # 0 +0x836A 0x50EF # 0 +0x836B 0x50F0 # 0 +0x836C 0x50F1 # 0 +0x836D 0x50F2 # 0 +0x836E 0x50F4 # 0 +0x836F 0x50F6 # 0 +0x8370 0x50F7 # 0 +0x8371 0x50F8 # 0 +0x8372 0x50F9 # 0 +0x8373 0x50FA # 0 +0x8374 0x50FC # 0 +0x8375 0x50FD # 0 +0x8376 0x50FE # 0 +0x8377 0x50FF # 0 +0x8378 0x5100 # 0 +0x8379 0x5101 # 0 +0x837A 0x5102 # 0 +0x837B 0x5103 # 0 +0x837C 0x5104 # 0 +0x837D 0x5105 # 0 +0x837E 0x5108 # 0 +0x8380 0x5109 # 0 +0x8381 0x510A # 0 +0x8382 0x510C # 0 +0x8383 0x510D # 0 +0x8384 0x510E # 0 +0x8385 0x510F # 0 +0x8386 0x5110 # 0 +0x8387 0x5111 # 0 +0x8388 0x5113 # 0 +0x8389 0x5114 # 0 +0x838A 0x5115 # 0 +0x838B 0x5116 # 0 +0x838C 0x5117 # 0 +0x838D 0x5118 # 0 +0x838E 0x5119 # 0 +0x838F 0x511A # 0 +0x8390 0x511B # 0 +0x8391 0x511C # 0 +0x8392 0x511D # 0 +0x8393 0x511E # 0 +0x8394 0x511F # 0 +0x8395 0x5120 # 0 +0x8396 0x5122 # 0 +0x8397 0x5123 # 0 +0x8398 0x5124 # 0 +0x8399 0x5125 # 0 +0x839A 0x5126 # 0 +0x839B 0x5127 # 0 +0x839C 0x5128 # 0 +0x839D 0x5129 # 0 +0x839E 0x512A # 0 +0x839F 0x512B # 0 +0x83A0 0x512C # 0 +0x83A1 0x512D # 0 +0x83A2 0x512E # 0 +0x83A3 0x512F # 0 +0x83A4 0x5130 # 0 +0x83A5 0x5131 # 0 +0x83A6 0x5132 # 0 +0x83A7 0x5133 # 0 +0x83A8 0x5134 # 0 +0x83A9 0x5135 # 0 +0x83AA 0x5136 # 0 +0x83AB 0x5137 # 0 +0x83AC 0x5138 # 0 +0x83AD 0x5139 # 0 +0x83AE 0x513A # 0 +0x83AF 0x513B # 0 +0x83B0 0x513C # 0 +0x83B1 0x513D # 0 +0x83B2 0x513E # 0 +0x83B3 0x5142 # 0 +0x83B4 0x5147 # 0 +0x83B5 0x514A # 0 +0x83B6 0x514C # 0 +0x83B7 0x514E # 0 +0x83B8 0x514F # 0 +0x83B9 0x5150 # 0 +0x83BA 0x5152 # 0 +0x83BB 0x5153 # 0 +0x83BC 0x5157 # 0 +0x83BD 0x5158 # 0 +0x83BE 0x5159 # 0 +0x83BF 0x515B # 0 +0x83C0 0x515D # 0 +0x83C1 0x515E # 0 +0x83C2 0x515F # 0 +0x83C3 0x5160 # 0 +0x83C4 0x5161 # 0 +0x83C5 0x5163 # 0 +0x83C6 0x5164 # 0 +0x83C7 0x5166 # 0 +0x83C8 0x5167 # 0 +0x83C9 0x5169 # 0 +0x83CA 0x516A # 0 +0x83CB 0x516F # 0 +0x83CC 0x5172 # 0 +0x83CD 0x517A # 0 +0x83CE 0x517E # 0 +0x83CF 0x517F # 0 +0x83D0 0x5183 # 0 +0x83D1 0x5184 # 0 +0x83D2 0x5186 # 0 +0x83D3 0x5187 # 0 +0x83D4 0x518A # 0 +0x83D5 0x518B # 0 +0x83D6 0x518E # 0 +0x83D7 0x518F # 0 +0x83D8 0x5190 # 0 +0x83D9 0x5191 # 0 +0x83DA 0x5193 # 0 +0x83DB 0x5194 # 0 +0x83DC 0x5198 # 0 +0x83DD 0x519A # 0 +0x83DE 0x519D # 0 +0x83DF 0x519E # 0 +0x83E0 0x519F # 0 +0x83E1 0x51A1 # 0 +0x83E2 0x51A3 # 0 +0x83E3 0x51A6 # 0 +0x83E4 0x51A7 # 0 +0x83E5 0x51A8 # 0 +0x83E6 0x51A9 # 0 +0x83E7 0x51AA # 0 +0x83E8 0x51AD # 0 +0x83E9 0x51AE # 0 +0x83EA 0x51B4 # 0 +0x83EB 0x51B8 # 0 +0x83EC 0x51B9 # 0 +0x83ED 0x51BA # 0 +0x83EE 0x51BE # 0 +0x83EF 0x51BF # 0 +0x83F0 0x51C1 # 0 +0x83F1 0x51C2 # 0 +0x83F2 0x51C3 # 0 +0x83F3 0x51C5 # 0 +0x83F4 0x51C8 # 0 +0x83F5 0x51CA # 0 +0x83F6 0x51CD # 0 +0x83F7 0x51CE # 0 +0x83F8 0x51D0 # 0 +0x83F9 0x51D2 # 0 +0x83FA 0x51D3 # 0 +0x83FB 0x51D4 # 0 +0x83FC 0x51D5 # 0 +0x83FD 0x51D6 # 0 +0x83FE 0x51D7 # 0 +0x8440 0x51D8 # 0 +0x8441 0x51D9 # 0 +0x8442 0x51DA # 0 +0x8443 0x51DC # 0 +0x8444 0x51DE # 0 +0x8445 0x51DF # 0 +0x8446 0x51E2 # 0 +0x8447 0x51E3 # 0 +0x8448 0x51E5 # 0 +0x8449 0x51E6 # 0 +0x844A 0x51E7 # 0 +0x844B 0x51E8 # 0 +0x844C 0x51E9 # 0 +0x844D 0x51EA # 0 +0x844E 0x51EC # 0 +0x844F 0x51EE # 0 +0x8450 0x51F1 # 0 +0x8451 0x51F2 # 0 +0x8452 0x51F4 # 0 +0x8453 0x51F7 # 0 +0x8454 0x51FE # 0 +0x8455 0x5204 # 0 +0x8456 0x5205 # 0 +0x8457 0x5209 # 0 +0x8458 0x520B # 0 +0x8459 0x520C # 0 +0x845A 0x520F # 0 +0x845B 0x5210 # 0 +0x845C 0x5213 # 0 +0x845D 0x5214 # 0 +0x845E 0x5215 # 0 +0x845F 0x521C # 0 +0x8460 0x521E # 0 +0x8461 0x521F # 0 +0x8462 0x5221 # 0 +0x8463 0x5222 # 0 +0x8464 0x5223 # 0 +0x8465 0x5225 # 0 +0x8466 0x5226 # 0 +0x8467 0x5227 # 0 +0x8468 0x522A # 0 +0x8469 0x522C # 0 +0x846A 0x522F # 0 +0x846B 0x5231 # 0 +0x846C 0x5232 # 0 +0x846D 0x5234 # 0 +0x846E 0x5235 # 0 +0x846F 0x523C # 0 +0x8470 0x523E # 0 +0x8471 0x5244 # 0 +0x8472 0x5245 # 0 +0x8473 0x5246 # 0 +0x8474 0x5247 # 0 +0x8475 0x5248 # 0 +0x8476 0x5249 # 0 +0x8477 0x524B # 0 +0x8478 0x524E # 0 +0x8479 0x524F # 0 +0x847A 0x5252 # 0 +0x847B 0x5253 # 0 +0x847C 0x5255 # 0 +0x847D 0x5257 # 0 +0x847E 0x5258 # 0 +0x8480 0x5259 # 0 +0x8481 0x525A # 0 +0x8482 0x525B # 0 +0x8483 0x525D # 0 +0x8484 0x525F # 0 +0x8485 0x5260 # 0 +0x8486 0x5262 # 0 +0x8487 0x5263 # 0 +0x8488 0x5264 # 0 +0x8489 0x5266 # 0 +0x848A 0x5268 # 0 +0x848B 0x526B # 0 +0x848C 0x526C # 0 +0x848D 0x526D # 0 +0x848E 0x526E # 0 +0x848F 0x5270 # 0 +0x8490 0x5271 # 0 +0x8491 0x5273 # 0 +0x8492 0x5274 # 0 +0x8493 0x5275 # 0 +0x8494 0x5276 # 0 +0x8495 0x5277 # 0 +0x8496 0x5278 # 0 +0x8497 0x5279 # 0 +0x8498 0x527A # 0 +0x8499 0x527B # 0 +0x849A 0x527C # 0 +0x849B 0x527E # 0 +0x849C 0x5280 # 0 +0x849D 0x5283 # 0 +0x849E 0x5284 # 0 +0x849F 0x5285 # 0 +0x84A0 0x5286 # 0 +0x84A1 0x5287 # 0 +0x84A2 0x5289 # 0 +0x84A3 0x528A # 0 +0x84A4 0x528B # 0 +0x84A5 0x528C # 0 +0x84A6 0x528D # 0 +0x84A7 0x528E # 0 +0x84A8 0x528F # 0 +0x84A9 0x5291 # 0 +0x84AA 0x5292 # 0 +0x84AB 0x5294 # 0 +0x84AC 0x5295 # 0 +0x84AD 0x5296 # 0 +0x84AE 0x5297 # 0 +0x84AF 0x5298 # 0 +0x84B0 0x5299 # 0 +0x84B1 0x529A # 0 +0x84B2 0x529C # 0 +0x84B3 0x52A4 # 0 +0x84B4 0x52A5 # 0 +0x84B5 0x52A6 # 0 +0x84B6 0x52A7 # 0 +0x84B7 0x52AE # 0 +0x84B8 0x52AF # 0 +0x84B9 0x52B0 # 0 +0x84BA 0x52B4 # 0 +0x84BB 0x52B5 # 0 +0x84BC 0x52B6 # 0 +0x84BD 0x52B7 # 0 +0x84BE 0x52B8 # 0 +0x84BF 0x52B9 # 0 +0x84C0 0x52BA # 0 +0x84C1 0x52BB # 0 +0x84C2 0x52BC # 0 +0x84C3 0x52BD # 0 +0x84C4 0x52C0 # 0 +0x84C5 0x52C1 # 0 +0x84C6 0x52C2 # 0 +0x84C7 0x52C4 # 0 +0x84C8 0x52C5 # 0 +0x84C9 0x52C6 # 0 +0x84CA 0x52C8 # 0 +0x84CB 0x52CA # 0 +0x84CC 0x52CC # 0 +0x84CD 0x52CD # 0 +0x84CE 0x52CE # 0 +0x84CF 0x52CF # 0 +0x84D0 0x52D1 # 0 +0x84D1 0x52D3 # 0 +0x84D2 0x52D4 # 0 +0x84D3 0x52D5 # 0 +0x84D4 0x52D7 # 0 +0x84D5 0x52D9 # 0 +0x84D6 0x52DA # 0 +0x84D7 0x52DB # 0 +0x84D8 0x52DC # 0 +0x84D9 0x52DD # 0 +0x84DA 0x52DE # 0 +0x84DB 0x52E0 # 0 +0x84DC 0x52E1 # 0 +0x84DD 0x52E2 # 0 +0x84DE 0x52E3 # 0 +0x84DF 0x52E5 # 0 +0x84E0 0x52E6 # 0 +0x84E1 0x52E7 # 0 +0x84E2 0x52E8 # 0 +0x84E3 0x52E9 # 0 +0x84E4 0x52EA # 0 +0x84E5 0x52EB # 0 +0x84E6 0x52EC # 0 +0x84E7 0x52ED # 0 +0x84E8 0x52EE # 0 +0x84E9 0x52EF # 0 +0x84EA 0x52F1 # 0 +0x84EB 0x52F2 # 0 +0x84EC 0x52F3 # 0 +0x84ED 0x52F4 # 0 +0x84EE 0x52F5 # 0 +0x84EF 0x52F6 # 0 +0x84F0 0x52F7 # 0 +0x84F1 0x52F8 # 0 +0x84F2 0x52FB # 0 +0x84F3 0x52FC # 0 +0x84F4 0x52FD # 0 +0x84F5 0x5301 # 0 +0x84F6 0x5302 # 0 +0x84F7 0x5303 # 0 +0x84F8 0x5304 # 0 +0x84F9 0x5307 # 0 +0x84FA 0x5309 # 0 +0x84FB 0x530A # 0 +0x84FC 0x530B # 0 +0x84FD 0x530C # 0 +0x84FE 0x530E # 0 +0x8540 0x5311 # 0 +0x8541 0x5312 # 0 +0x8542 0x5313 # 0 +0x8543 0x5314 # 0 +0x8544 0x5318 # 0 +0x8545 0x531B # 0 +0x8546 0x531C # 0 +0x8547 0x531E # 0 +0x8548 0x531F # 0 +0x8549 0x5322 # 0 +0x854A 0x5324 # 0 +0x854B 0x5325 # 0 +0x854C 0x5327 # 0 +0x854D 0x5328 # 0 +0x854E 0x5329 # 0 +0x854F 0x532B # 0 +0x8550 0x532C # 0 +0x8551 0x532D # 0 +0x8552 0x532F # 0 +0x8553 0x5330 # 0 +0x8554 0x5331 # 0 +0x8555 0x5332 # 0 +0x8556 0x5333 # 0 +0x8557 0x5334 # 0 +0x8558 0x5335 # 0 +0x8559 0x5336 # 0 +0x855A 0x5337 # 0 +0x855B 0x5338 # 0 +0x855C 0x533C # 0 +0x855D 0x533D # 0 +0x855E 0x5340 # 0 +0x855F 0x5342 # 0 +0x8560 0x5344 # 0 +0x8561 0x5346 # 0 +0x8562 0x534B # 0 +0x8563 0x534C # 0 +0x8564 0x534D # 0 +0x8565 0x5350 # 0 +0x8566 0x5354 # 0 +0x8567 0x5358 # 0 +0x8568 0x5359 # 0 +0x8569 0x535B # 0 +0x856A 0x535D # 0 +0x856B 0x5365 # 0 +0x856C 0x5368 # 0 +0x856D 0x536A # 0 +0x856E 0x536C # 0 +0x856F 0x536D # 0 +0x8570 0x5372 # 0 +0x8571 0x5376 # 0 +0x8572 0x5379 # 0 +0x8573 0x537B # 0 +0x8574 0x537C # 0 +0x8575 0x537D # 0 +0x8576 0x537E # 0 +0x8577 0x5380 # 0 +0x8578 0x5381 # 0 +0x8579 0x5383 # 0 +0x857A 0x5387 # 0 +0x857B 0x5388 # 0 +0x857C 0x538A # 0 +0x857D 0x538E # 0 +0x857E 0x538F # 0 +0x8580 0x5390 # 0 +0x8581 0x5391 # 0 +0x8582 0x5392 # 0 +0x8583 0x5393 # 0 +0x8584 0x5394 # 0 +0x8585 0x5396 # 0 +0x8586 0x5397 # 0 +0x8587 0x5399 # 0 +0x8588 0x539B # 0 +0x8589 0x539C # 0 +0x858A 0x539E # 0 +0x858B 0x53A0 # 0 +0x858C 0x53A1 # 0 +0x858D 0x53A4 # 0 +0x858E 0x53A7 # 0 +0x858F 0x53AA # 0 +0x8590 0x53AB # 0 +0x8591 0x53AC # 0 +0x8592 0x53AD # 0 +0x8593 0x53AF # 0 +0x8594 0x53B0 # 0 +0x8595 0x53B1 # 0 +0x8596 0x53B2 # 0 +0x8597 0x53B3 # 0 +0x8598 0x53B4 # 0 +0x8599 0x53B5 # 0 +0x859A 0x53B7 # 0 +0x859B 0x53B8 # 0 +0x859C 0x53B9 # 0 +0x859D 0x53BA # 0 +0x859E 0x53BC # 0 +0x859F 0x53BD # 0 +0x85A0 0x53BE # 0 +0x85A1 0x53C0 # 0 +0x85A2 0x53C3 # 0 +0x85A3 0x53C4 # 0 +0x85A4 0x53C5 # 0 +0x85A5 0x53C6 # 0 +0x85A6 0x53C7 # 0 +0x85A7 0x53CE # 0 +0x85A8 0x53CF # 0 +0x85A9 0x53D0 # 0 +0x85AA 0x53D2 # 0 +0x85AB 0x53D3 # 0 +0x85AC 0x53D5 # 0 +0x85AD 0x53DA # 0 +0x85AE 0x53DC # 0 +0x85AF 0x53DD # 0 +0x85B0 0x53DE # 0 +0x85B1 0x53E1 # 0 +0x85B2 0x53E2 # 0 +0x85B3 0x53E7 # 0 +0x85B4 0x53F4 # 0 +0x85B5 0x53FA # 0 +0x85B6 0x53FE # 0 +0x85B7 0x53FF # 0 +0x85B8 0x5400 # 0 +0x85B9 0x5402 # 0 +0x85BA 0x5405 # 0 +0x85BB 0x5407 # 0 +0x85BC 0x540B # 0 +0x85BD 0x5414 # 0 +0x85BE 0x5418 # 0 +0x85BF 0x5419 # 0 +0x85C0 0x541A # 0 +0x85C1 0x541C # 0 +0x85C2 0x5422 # 0 +0x85C3 0x5424 # 0 +0x85C4 0x5425 # 0 +0x85C5 0x542A # 0 +0x85C6 0x5430 # 0 +0x85C7 0x5433 # 0 +0x85C8 0x5436 # 0 +0x85C9 0x5437 # 0 +0x85CA 0x543A # 0 +0x85CB 0x543D # 0 +0x85CC 0x543F # 0 +0x85CD 0x5441 # 0 +0x85CE 0x5442 # 0 +0x85CF 0x5444 # 0 +0x85D0 0x5445 # 0 +0x85D1 0x5447 # 0 +0x85D2 0x5449 # 0 +0x85D3 0x544C # 0 +0x85D4 0x544D # 0 +0x85D5 0x544E # 0 +0x85D6 0x544F # 0 +0x85D7 0x5451 # 0 +0x85D8 0x545A # 0 +0x85D9 0x545D # 0 +0x85DA 0x545E # 0 +0x85DB 0x545F # 0 +0x85DC 0x5460 # 0 +0x85DD 0x5461 # 0 +0x85DE 0x5463 # 0 +0x85DF 0x5465 # 0 +0x85E0 0x5467 # 0 +0x85E1 0x5469 # 0 +0x85E2 0x546A # 0 +0x85E3 0x546B # 0 +0x85E4 0x546C # 0 +0x85E5 0x546D # 0 +0x85E6 0x546E # 0 +0x85E7 0x546F # 0 +0x85E8 0x5470 # 0 +0x85E9 0x5474 # 0 +0x85EA 0x5479 # 0 +0x85EB 0x547A # 0 +0x85EC 0x547E # 0 +0x85ED 0x547F # 0 +0x85EE 0x5481 # 0 +0x85EF 0x5483 # 0 +0x85F0 0x5485 # 0 +0x85F1 0x5487 # 0 +0x85F2 0x5488 # 0 +0x85F3 0x5489 # 0 +0x85F4 0x548A # 0 +0x85F5 0x548D # 0 +0x85F6 0x5491 # 0 +0x85F7 0x5493 # 0 +0x85F8 0x5497 # 0 +0x85F9 0x5498 # 0 +0x85FA 0x549C # 0 +0x85FB 0x549E # 0 +0x85FC 0x549F # 0 +0x85FD 0x54A0 # 0 +0x85FE 0x54A1 # 0 +0x8640 0x54A2 # 0 +0x8641 0x54A5 # 0 +0x8642 0x54AE # 0 +0x8643 0x54B0 # 0 +0x8644 0x54B2 # 0 +0x8645 0x54B5 # 0 +0x8646 0x54B6 # 0 +0x8647 0x54B7 # 0 +0x8648 0x54B9 # 0 +0x8649 0x54BA # 0 +0x864A 0x54BC # 0 +0x864B 0x54BE # 0 +0x864C 0x54C3 # 0 +0x864D 0x54C5 # 0 +0x864E 0x54CA # 0 +0x864F 0x54CB # 0 +0x8650 0x54D6 # 0 +0x8651 0x54D8 # 0 +0x8652 0x54DB # 0 +0x8653 0x54E0 # 0 +0x8654 0x54E1 # 0 +0x8655 0x54E2 # 0 +0x8656 0x54E3 # 0 +0x8657 0x54E4 # 0 +0x8658 0x54EB # 0 +0x8659 0x54EC # 0 +0x865A 0x54EF # 0 +0x865B 0x54F0 # 0 +0x865C 0x54F1 # 0 +0x865D 0x54F4 # 0 +0x865E 0x54F5 # 0 +0x865F 0x54F6 # 0 +0x8660 0x54F7 # 0 +0x8661 0x54F8 # 0 +0x8662 0x54F9 # 0 +0x8663 0x54FB # 0 +0x8664 0x54FE # 0 +0x8665 0x5500 # 0 +0x8666 0x5502 # 0 +0x8667 0x5503 # 0 +0x8668 0x5504 # 0 +0x8669 0x5505 # 0 +0x866A 0x5508 # 0 +0x866B 0x550A # 0 +0x866C 0x550B # 0 +0x866D 0x550C # 0 +0x866E 0x550D # 0 +0x866F 0x550E # 0 +0x8670 0x5512 # 0 +0x8671 0x5513 # 0 +0x8672 0x5515 # 0 +0x8673 0x5516 # 0 +0x8674 0x5517 # 0 +0x8675 0x5518 # 0 +0x8676 0x5519 # 0 +0x8677 0x551A # 0 +0x8678 0x551C # 0 +0x8679 0x551D # 0 +0x867A 0x551E # 0 +0x867B 0x551F # 0 +0x867C 0x5521 # 0 +0x867D 0x5525 # 0 +0x867E 0x5526 # 0 +0x8680 0x5528 # 0 +0x8681 0x5529 # 0 +0x8682 0x552B # 0 +0x8683 0x552D # 0 +0x8684 0x5532 # 0 +0x8685 0x5534 # 0 +0x8686 0x5535 # 0 +0x8687 0x5536 # 0 +0x8688 0x5538 # 0 +0x8689 0x5539 # 0 +0x868A 0x553A # 0 +0x868B 0x553B # 0 +0x868C 0x553D # 0 +0x868D 0x5540 # 0 +0x868E 0x5542 # 0 +0x868F 0x5545 # 0 +0x8690 0x5547 # 0 +0x8691 0x5548 # 0 +0x8692 0x554B # 0 +0x8693 0x554C # 0 +0x8694 0x554D # 0 +0x8695 0x554E # 0 +0x8696 0x554F # 0 +0x8697 0x5551 # 0 +0x8698 0x5552 # 0 +0x8699 0x5553 # 0 +0x869A 0x5554 # 0 +0x869B 0x5557 # 0 +0x869C 0x5558 # 0 +0x869D 0x5559 # 0 +0x869E 0x555A # 0 +0x869F 0x555B # 0 +0x86A0 0x555D # 0 +0x86A1 0x555E # 0 +0x86A2 0x555F # 0 +0x86A3 0x5560 # 0 +0x86A4 0x5562 # 0 +0x86A5 0x5563 # 0 +0x86A6 0x5568 # 0 +0x86A7 0x5569 # 0 +0x86A8 0x556B # 0 +0x86A9 0x556F # 0 +0x86AA 0x5570 # 0 +0x86AB 0x5571 # 0 +0x86AC 0x5572 # 0 +0x86AD 0x5573 # 0 +0x86AE 0x5574 # 0 +0x86AF 0x5579 # 0 +0x86B0 0x557A # 0 +0x86B1 0x557D # 0 +0x86B2 0x557F # 0 +0x86B3 0x5585 # 0 +0x86B4 0x5586 # 0 +0x86B5 0x558C # 0 +0x86B6 0x558D # 0 +0x86B7 0x558E # 0 +0x86B8 0x5590 # 0 +0x86B9 0x5592 # 0 +0x86BA 0x5593 # 0 +0x86BB 0x5595 # 0 +0x86BC 0x5596 # 0 +0x86BD 0x5597 # 0 +0x86BE 0x559A # 0 +0x86BF 0x559B # 0 +0x86C0 0x559E # 0 +0x86C1 0x55A0 # 0 +0x86C2 0x55A1 # 0 +0x86C3 0x55A2 # 0 +0x86C4 0x55A3 # 0 +0x86C5 0x55A4 # 0 +0x86C6 0x55A5 # 0 +0x86C7 0x55A6 # 0 +0x86C8 0x55A8 # 0 +0x86C9 0x55A9 # 0 +0x86CA 0x55AA # 0 +0x86CB 0x55AB # 0 +0x86CC 0x55AC # 0 +0x86CD 0x55AD # 0 +0x86CE 0x55AE # 0 +0x86CF 0x55AF # 0 +0x86D0 0x55B0 # 0 +0x86D1 0x55B2 # 0 +0x86D2 0x55B4 # 0 +0x86D3 0x55B6 # 0 +0x86D4 0x55B8 # 0 +0x86D5 0x55BA # 0 +0x86D6 0x55BC # 0 +0x86D7 0x55BF # 0 +0x86D8 0x55C0 # 0 +0x86D9 0x55C1 # 0 +0x86DA 0x55C2 # 0 +0x86DB 0x55C3 # 0 +0x86DC 0x55C6 # 0 +0x86DD 0x55C7 # 0 +0x86DE 0x55C8 # 0 +0x86DF 0x55CA # 0 +0x86E0 0x55CB # 0 +0x86E1 0x55CE # 0 +0x86E2 0x55CF # 0 +0x86E3 0x55D0 # 0 +0x86E4 0x55D5 # 0 +0x86E5 0x55D7 # 0 +0x86E6 0x55D8 # 0 +0x86E7 0x55D9 # 0 +0x86E8 0x55DA # 0 +0x86E9 0x55DB # 0 +0x86EA 0x55DE # 0 +0x86EB 0x55E0 # 0 +0x86EC 0x55E2 # 0 +0x86ED 0x55E7 # 0 +0x86EE 0x55E9 # 0 +0x86EF 0x55ED # 0 +0x86F0 0x55EE # 0 +0x86F1 0x55F0 # 0 +0x86F2 0x55F1 # 0 +0x86F3 0x55F4 # 0 +0x86F4 0x55F6 # 0 +0x86F5 0x55F8 # 0 +0x86F6 0x55F9 # 0 +0x86F7 0x55FA # 0 +0x86F8 0x55FB # 0 +0x86F9 0x55FC # 0 +0x86FA 0x55FF # 0 +0x86FB 0x5602 # 0 +0x86FC 0x5603 # 0 +0x86FD 0x5604 # 0 +0x86FE 0x5605 # 0 +0x8740 0x5606 # 0 +0x8741 0x5607 # 0 +0x8742 0x560A # 0 +0x8743 0x560B # 0 +0x8744 0x560D # 0 +0x8745 0x5610 # 0 +0x8746 0x5611 # 0 +0x8747 0x5612 # 0 +0x8748 0x5613 # 0 +0x8749 0x5614 # 0 +0x874A 0x5615 # 0 +0x874B 0x5616 # 0 +0x874C 0x5617 # 0 +0x874D 0x5619 # 0 +0x874E 0x561A # 0 +0x874F 0x561C # 0 +0x8750 0x561D # 0 +0x8751 0x5620 # 0 +0x8752 0x5621 # 0 +0x8753 0x5622 # 0 +0x8754 0x5625 # 0 +0x8755 0x5626 # 0 +0x8756 0x5628 # 0 +0x8757 0x5629 # 0 +0x8758 0x562A # 0 +0x8759 0x562B # 0 +0x875A 0x562E # 0 +0x875B 0x562F # 0 +0x875C 0x5630 # 0 +0x875D 0x5633 # 0 +0x875E 0x5635 # 0 +0x875F 0x5637 # 0 +0x8760 0x5638 # 0 +0x8761 0x563A # 0 +0x8762 0x563C # 0 +0x8763 0x563D # 0 +0x8764 0x563E # 0 +0x8765 0x5640 # 0 +0x8766 0x5641 # 0 +0x8767 0x5642 # 0 +0x8768 0x5643 # 0 +0x8769 0x5644 # 0 +0x876A 0x5645 # 0 +0x876B 0x5646 # 0 +0x876C 0x5647 # 0 +0x876D 0x5648 # 0 +0x876E 0x5649 # 0 +0x876F 0x564A # 0 +0x8770 0x564B # 0 +0x8771 0x564F # 0 +0x8772 0x5650 # 0 +0x8773 0x5651 # 0 +0x8774 0x5652 # 0 +0x8775 0x5653 # 0 +0x8776 0x5655 # 0 +0x8777 0x5656 # 0 +0x8778 0x565A # 0 +0x8779 0x565B # 0 +0x877A 0x565D # 0 +0x877B 0x565E # 0 +0x877C 0x565F # 0 +0x877D 0x5660 # 0 +0x877E 0x5661 # 0 +0x8780 0x5663 # 0 +0x8781 0x5665 # 0 +0x8782 0x5666 # 0 +0x8783 0x5667 # 0 +0x8784 0x566D # 0 +0x8785 0x566E # 0 +0x8786 0x566F # 0 +0x8787 0x5670 # 0 +0x8788 0x5672 # 0 +0x8789 0x5673 # 0 +0x878A 0x5674 # 0 +0x878B 0x5675 # 0 +0x878C 0x5677 # 0 +0x878D 0x5678 # 0 +0x878E 0x5679 # 0 +0x878F 0x567A # 0 +0x8790 0x567D # 0 +0x8791 0x567E # 0 +0x8792 0x567F # 0 +0x8793 0x5680 # 0 +0x8794 0x5681 # 0 +0x8795 0x5682 # 0 +0x8796 0x5683 # 0 +0x8797 0x5684 # 0 +0x8798 0x5687 # 0 +0x8799 0x5688 # 0 +0x879A 0x5689 # 0 +0x879B 0x568A # 0 +0x879C 0x568B # 0 +0x879D 0x568C # 0 +0x879E 0x568D # 0 +0x879F 0x5690 # 0 +0x87A0 0x5691 # 0 +0x87A1 0x5692 # 0 +0x87A2 0x5694 # 0 +0x87A3 0x5695 # 0 +0x87A4 0x5696 # 0 +0x87A5 0x5697 # 0 +0x87A6 0x5698 # 0 +0x87A7 0x5699 # 0 +0x87A8 0x569A # 0 +0x87A9 0x569B # 0 +0x87AA 0x569C # 0 +0x87AB 0x569D # 0 +0x87AC 0x569E # 0 +0x87AD 0x569F # 0 +0x87AE 0x56A0 # 0 +0x87AF 0x56A1 # 0 +0x87B0 0x56A2 # 0 +0x87B1 0x56A4 # 0 +0x87B2 0x56A5 # 0 +0x87B3 0x56A6 # 0 +0x87B4 0x56A7 # 0 +0x87B5 0x56A8 # 0 +0x87B6 0x56A9 # 0 +0x87B7 0x56AA # 0 +0x87B8 0x56AB # 0 +0x87B9 0x56AC # 0 +0x87BA 0x56AD # 0 +0x87BB 0x56AE # 0 +0x87BC 0x56B0 # 0 +0x87BD 0x56B1 # 0 +0x87BE 0x56B2 # 0 +0x87BF 0x56B3 # 0 +0x87C0 0x56B4 # 0 +0x87C1 0x56B5 # 0 +0x87C2 0x56B6 # 0 +0x87C3 0x56B8 # 0 +0x87C4 0x56B9 # 0 +0x87C5 0x56BA # 0 +0x87C6 0x56BB # 0 +0x87C7 0x56BD # 0 +0x87C8 0x56BE # 0 +0x87C9 0x56BF # 0 +0x87CA 0x56C0 # 0 +0x87CB 0x56C1 # 0 +0x87CC 0x56C2 # 0 +0x87CD 0x56C3 # 0 +0x87CE 0x56C4 # 0 +0x87CF 0x56C5 # 0 +0x87D0 0x56C6 # 0 +0x87D1 0x56C7 # 0 +0x87D2 0x56C8 # 0 +0x87D3 0x56C9 # 0 +0x87D4 0x56CB # 0 +0x87D5 0x56CC # 0 +0x87D6 0x56CD # 0 +0x87D7 0x56CE # 0 +0x87D8 0x56CF # 0 +0x87D9 0x56D0 # 0 +0x87DA 0x56D1 # 0 +0x87DB 0x56D2 # 0 +0x87DC 0x56D3 # 0 +0x87DD 0x56D5 # 0 +0x87DE 0x56D6 # 0 +0x87DF 0x56D8 # 0 +0x87E0 0x56D9 # 0 +0x87E1 0x56DC # 0 +0x87E2 0x56E3 # 0 +0x87E3 0x56E5 # 0 +0x87E4 0x56E6 # 0 +0x87E5 0x56E7 # 0 +0x87E6 0x56E8 # 0 +0x87E7 0x56E9 # 0 +0x87E8 0x56EA # 0 +0x87E9 0x56EC # 0 +0x87EA 0x56EE # 0 +0x87EB 0x56EF # 0 +0x87EC 0x56F2 # 0 +0x87ED 0x56F3 # 0 +0x87EE 0x56F6 # 0 +0x87EF 0x56F7 # 0 +0x87F0 0x56F8 # 0 +0x87F1 0x56FB # 0 +0x87F2 0x56FC # 0 +0x87F3 0x5700 # 0 +0x87F4 0x5701 # 0 +0x87F5 0x5702 # 0 +0x87F6 0x5705 # 0 +0x87F7 0x5707 # 0 +0x87F8 0x570B # 0 +0x87F9 0x570C # 0 +0x87FA 0x570D # 0 +0x87FB 0x570E # 0 +0x87FC 0x570F # 0 +0x87FD 0x5710 # 0 +0x87FE 0x5711 # 0 +0x8840 0x5712 # 0 +0x8841 0x5713 # 0 +0x8842 0x5714 # 0 +0x8843 0x5715 # 0 +0x8844 0x5716 # 0 +0x8845 0x5717 # 0 +0x8846 0x5718 # 0 +0x8847 0x5719 # 0 +0x8848 0x571A # 0 +0x8849 0x571B # 0 +0x884A 0x571D # 0 +0x884B 0x571E # 0 +0x884C 0x5720 # 0 +0x884D 0x5721 # 0 +0x884E 0x5722 # 0 +0x884F 0x5724 # 0 +0x8850 0x5725 # 0 +0x8851 0x5726 # 0 +0x8852 0x5727 # 0 +0x8853 0x572B # 0 +0x8854 0x5731 # 0 +0x8855 0x5732 # 0 +0x8856 0x5734 # 0 +0x8857 0x5735 # 0 +0x8858 0x5736 # 0 +0x8859 0x5737 # 0 +0x885A 0x5738 # 0 +0x885B 0x573C # 0 +0x885C 0x573D # 0 +0x885D 0x573F # 0 +0x885E 0x5741 # 0 +0x885F 0x5743 # 0 +0x8860 0x5744 # 0 +0x8861 0x5745 # 0 +0x8862 0x5746 # 0 +0x8863 0x5748 # 0 +0x8864 0x5749 # 0 +0x8865 0x574B # 0 +0x8866 0x5752 # 0 +0x8867 0x5753 # 0 +0x8868 0x5754 # 0 +0x8869 0x5755 # 0 +0x886A 0x5756 # 0 +0x886B 0x5758 # 0 +0x886C 0x5759 # 0 +0x886D 0x5762 # 0 +0x886E 0x5763 # 0 +0x886F 0x5765 # 0 +0x8870 0x5767 # 0 +0x8871 0x576C # 0 +0x8872 0x576E # 0 +0x8873 0x5770 # 0 +0x8874 0x5771 # 0 +0x8875 0x5772 # 0 +0x8876 0x5774 # 0 +0x8877 0x5775 # 0 +0x8878 0x5778 # 0 +0x8879 0x5779 # 0 +0x887A 0x577A # 0 +0x887B 0x577D # 0 +0x887C 0x577E # 0 +0x887D 0x577F # 0 +0x887E 0x5780 # 0 +0x8880 0x5781 # 0 +0x8881 0x5787 # 0 +0x8882 0x5788 # 0 +0x8883 0x5789 # 0 +0x8884 0x578A # 0 +0x8885 0x578D # 0 +0x8886 0x578E # 0 +0x8887 0x578F # 0 +0x8888 0x5790 # 0 +0x8889 0x5791 # 0 +0x888A 0x5794 # 0 +0x888B 0x5795 # 0 +0x888C 0x5796 # 0 +0x888D 0x5797 # 0 +0x888E 0x5798 # 0 +0x888F 0x5799 # 0 +0x8890 0x579A # 0 +0x8891 0x579C # 0 +0x8892 0x579D # 0 +0x8893 0x579E # 0 +0x8894 0x579F # 0 +0x8895 0x57A5 # 0 +0x8896 0x57A8 # 0 +0x8897 0x57AA # 0 +0x8898 0x57AC # 0 +0x8899 0x57AF # 0 +0x889A 0x57B0 # 0 +0x889B 0x57B1 # 0 +0x889C 0x57B3 # 0 +0x889D 0x57B5 # 0 +0x889E 0x57B6 # 0 +0x889F 0x57B7 # 0 +0x88A0 0x57B9 # 0 +0x88A1 0x57BA # 0 +0x88A2 0x57BB # 0 +0x88A3 0x57BC # 0 +0x88A4 0x57BD # 0 +0x88A5 0x57BE # 0 +0x88A6 0x57BF # 0 +0x88A7 0x57C0 # 0 +0x88A8 0x57C1 # 0 +0x88A9 0x57C4 # 0 +0x88AA 0x57C5 # 0 +0x88AB 0x57C6 # 0 +0x88AC 0x57C7 # 0 +0x88AD 0x57C8 # 0 +0x88AE 0x57C9 # 0 +0x88AF 0x57CA # 0 +0x88B0 0x57CC # 0 +0x88B1 0x57CD # 0 +0x88B2 0x57D0 # 0 +0x88B3 0x57D1 # 0 +0x88B4 0x57D3 # 0 +0x88B5 0x57D6 # 0 +0x88B6 0x57D7 # 0 +0x88B7 0x57DB # 0 +0x88B8 0x57DC # 0 +0x88B9 0x57DE # 0 +0x88BA 0x57E1 # 0 +0x88BB 0x57E2 # 0 +0x88BC 0x57E3 # 0 +0x88BD 0x57E5 # 0 +0x88BE 0x57E6 # 0 +0x88BF 0x57E7 # 0 +0x88C0 0x57E8 # 0 +0x88C1 0x57E9 # 0 +0x88C2 0x57EA # 0 +0x88C3 0x57EB # 0 +0x88C4 0x57EC # 0 +0x88C5 0x57EE # 0 +0x88C6 0x57F0 # 0 +0x88C7 0x57F1 # 0 +0x88C8 0x57F2 # 0 +0x88C9 0x57F3 # 0 +0x88CA 0x57F5 # 0 +0x88CB 0x57F6 # 0 +0x88CC 0x57F7 # 0 +0x88CD 0x57FB # 0 +0x88CE 0x57FC # 0 +0x88CF 0x57FE # 0 +0x88D0 0x57FF # 0 +0x88D1 0x5801 # 0 +0x88D2 0x5803 # 0 +0x88D3 0x5804 # 0 +0x88D4 0x5805 # 0 +0x88D5 0x5808 # 0 +0x88D6 0x5809 # 0 +0x88D7 0x580A # 0 +0x88D8 0x580C # 0 +0x88D9 0x580E # 0 +0x88DA 0x580F # 0 +0x88DB 0x5810 # 0 +0x88DC 0x5812 # 0 +0x88DD 0x5813 # 0 +0x88DE 0x5814 # 0 +0x88DF 0x5816 # 0 +0x88E0 0x5817 # 0 +0x88E1 0x5818 # 0 +0x88E2 0x581A # 0 +0x88E3 0x581B # 0 +0x88E4 0x581C # 0 +0x88E5 0x581D # 0 +0x88E6 0x581F # 0 +0x88E7 0x5822 # 0 +0x88E8 0x5823 # 0 +0x88E9 0x5825 # 0 +0x88EA 0x5826 # 0 +0x88EB 0x5827 # 0 +0x88EC 0x5828 # 0 +0x88ED 0x5829 # 0 +0x88EE 0x582B # 0 +0x88EF 0x582C # 0 +0x88F0 0x582D # 0 +0x88F1 0x582E # 0 +0x88F2 0x582F # 0 +0x88F3 0x5831 # 0 +0x88F4 0x5832 # 0 +0x88F5 0x5833 # 0 +0x88F6 0x5834 # 0 +0x88F7 0x5836 # 0 +0x88F8 0x5837 # 0 +0x88F9 0x5838 # 0 +0x88FA 0x5839 # 0 +0x88FB 0x583A # 0 +0x88FC 0x583B # 0 +0x88FD 0x583C # 0 +0x88FE 0x583D # 0 +0x8940 0x583E # 0 +0x8941 0x583F # 0 +0x8942 0x5840 # 0 +0x8943 0x5841 # 0 +0x8944 0x5842 # 0 +0x8945 0x5843 # 0 +0x8946 0x5845 # 0 +0x8947 0x5846 # 0 +0x8948 0x5847 # 0 +0x8949 0x5848 # 0 +0x894A 0x5849 # 0 +0x894B 0x584A # 0 +0x894C 0x584B # 0 +0x894D 0x584E # 0 +0x894E 0x584F # 0 +0x894F 0x5850 # 0 +0x8950 0x5852 # 0 +0x8951 0x5853 # 0 +0x8952 0x5855 # 0 +0x8953 0x5856 # 0 +0x8954 0x5857 # 0 +0x8955 0x5859 # 0 +0x8956 0x585A # 0 +0x8957 0x585B # 0 +0x8958 0x585C # 0 +0x8959 0x585D # 0 +0x895A 0x585F # 0 +0x895B 0x5860 # 0 +0x895C 0x5861 # 0 +0x895D 0x5862 # 0 +0x895E 0x5863 # 0 +0x895F 0x5864 # 0 +0x8960 0x5866 # 0 +0x8961 0x5867 # 0 +0x8962 0x5868 # 0 +0x8963 0x5869 # 0 +0x8964 0x586A # 0 +0x8965 0x586D # 0 +0x8966 0x586E # 0 +0x8967 0x586F # 0 +0x8968 0x5870 # 0 +0x8969 0x5871 # 0 +0x896A 0x5872 # 0 +0x896B 0x5873 # 0 +0x896C 0x5874 # 0 +0x896D 0x5875 # 0 +0x896E 0x5876 # 0 +0x896F 0x5877 # 0 +0x8970 0x5878 # 0 +0x8971 0x5879 # 0 +0x8972 0x587A # 0 +0x8973 0x587B # 0 +0x8974 0x587C # 0 +0x8975 0x587D # 0 +0x8976 0x587F # 0 +0x8977 0x5882 # 0 +0x8978 0x5884 # 0 +0x8979 0x5886 # 0 +0x897A 0x5887 # 0 +0x897B 0x5888 # 0 +0x897C 0x588A # 0 +0x897D 0x588B # 0 +0x897E 0x588C # 0 +0x8980 0x588D # 0 +0x8981 0x588E # 0 +0x8982 0x588F # 0 +0x8983 0x5890 # 0 +0x8984 0x5891 # 0 +0x8985 0x5894 # 0 +0x8986 0x5895 # 0 +0x8987 0x5896 # 0 +0x8988 0x5897 # 0 +0x8989 0x5898 # 0 +0x898A 0x589B # 0 +0x898B 0x589C # 0 +0x898C 0x589D # 0 +0x898D 0x58A0 # 0 +0x898E 0x58A1 # 0 +0x898F 0x58A2 # 0 +0x8990 0x58A3 # 0 +0x8991 0x58A4 # 0 +0x8992 0x58A5 # 0 +0x8993 0x58A6 # 0 +0x8994 0x58A7 # 0 +0x8995 0x58AA # 0 +0x8996 0x58AB # 0 +0x8997 0x58AC # 0 +0x8998 0x58AD # 0 +0x8999 0x58AE # 0 +0x899A 0x58AF # 0 +0x899B 0x58B0 # 0 +0x899C 0x58B1 # 0 +0x899D 0x58B2 # 0 +0x899E 0x58B3 # 0 +0x899F 0x58B4 # 0 +0x89A0 0x58B5 # 0 +0x89A1 0x58B6 # 0 +0x89A2 0x58B7 # 0 +0x89A3 0x58B8 # 0 +0x89A4 0x58B9 # 0 +0x89A5 0x58BA # 0 +0x89A6 0x58BB # 0 +0x89A7 0x58BD # 0 +0x89A8 0x58BE # 0 +0x89A9 0x58BF # 0 +0x89AA 0x58C0 # 0 +0x89AB 0x58C2 # 0 +0x89AC 0x58C3 # 0 +0x89AD 0x58C4 # 0 +0x89AE 0x58C6 # 0 +0x89AF 0x58C7 # 0 +0x89B0 0x58C8 # 0 +0x89B1 0x58C9 # 0 +0x89B2 0x58CA # 0 +0x89B3 0x58CB # 0 +0x89B4 0x58CC # 0 +0x89B5 0x58CD # 0 +0x89B6 0x58CE # 0 +0x89B7 0x58CF # 0 +0x89B8 0x58D0 # 0 +0x89B9 0x58D2 # 0 +0x89BA 0x58D3 # 0 +0x89BB 0x58D4 # 0 +0x89BC 0x58D6 # 0 +0x89BD 0x58D7 # 0 +0x89BE 0x58D8 # 0 +0x89BF 0x58D9 # 0 +0x89C0 0x58DA # 0 +0x89C1 0x58DB # 0 +0x89C2 0x58DC # 0 +0x89C3 0x58DD # 0 +0x89C4 0x58DE # 0 +0x89C5 0x58DF # 0 +0x89C6 0x58E0 # 0 +0x89C7 0x58E1 # 0 +0x89C8 0x58E2 # 0 +0x89C9 0x58E3 # 0 +0x89CA 0x58E5 # 0 +0x89CB 0x58E6 # 0 +0x89CC 0x58E7 # 0 +0x89CD 0x58E8 # 0 +0x89CE 0x58E9 # 0 +0x89CF 0x58EA # 0 +0x89D0 0x58ED # 0 +0x89D1 0x58EF # 0 +0x89D2 0x58F1 # 0 +0x89D3 0x58F2 # 0 +0x89D4 0x58F4 # 0 +0x89D5 0x58F5 # 0 +0x89D6 0x58F7 # 0 +0x89D7 0x58F8 # 0 +0x89D8 0x58FA # 0 +0x89D9 0x58FB # 0 +0x89DA 0x58FC # 0 +0x89DB 0x58FD # 0 +0x89DC 0x58FE # 0 +0x89DD 0x58FF # 0 +0x89DE 0x5900 # 0 +0x89DF 0x5901 # 0 +0x89E0 0x5903 # 0 +0x89E1 0x5905 # 0 +0x89E2 0x5906 # 0 +0x89E3 0x5908 # 0 +0x89E4 0x5909 # 0 +0x89E5 0x590A # 0 +0x89E6 0x590B # 0 +0x89E7 0x590C # 0 +0x89E8 0x590E # 0 +0x89E9 0x5910 # 0 +0x89EA 0x5911 # 0 +0x89EB 0x5912 # 0 +0x89EC 0x5913 # 0 +0x89ED 0x5917 # 0 +0x89EE 0x5918 # 0 +0x89EF 0x591B # 0 +0x89F0 0x591D # 0 +0x89F1 0x591E # 0 +0x89F2 0x5920 # 0 +0x89F3 0x5921 # 0 +0x89F4 0x5922 # 0 +0x89F5 0x5923 # 0 +0x89F6 0x5926 # 0 +0x89F7 0x5928 # 0 +0x89F8 0x592C # 0 +0x89F9 0x5930 # 0 +0x89FA 0x5932 # 0 +0x89FB 0x5933 # 0 +0x89FC 0x5935 # 0 +0x89FD 0x5936 # 0 +0x89FE 0x593B # 0 +0x8A40 0x593D # 0 +0x8A41 0x593E # 0 +0x8A42 0x593F # 0 +0x8A43 0x5940 # 0 +0x8A44 0x5943 # 0 +0x8A45 0x5945 # 0 +0x8A46 0x5946 # 0 +0x8A47 0x594A # 0 +0x8A48 0x594C # 0 +0x8A49 0x594D # 0 +0x8A4A 0x5950 # 0 +0x8A4B 0x5952 # 0 +0x8A4C 0x5953 # 0 +0x8A4D 0x5959 # 0 +0x8A4E 0x595B # 0 +0x8A4F 0x595C # 0 +0x8A50 0x595D # 0 +0x8A51 0x595E # 0 +0x8A52 0x595F # 0 +0x8A53 0x5961 # 0 +0x8A54 0x5963 # 0 +0x8A55 0x5964 # 0 +0x8A56 0x5966 # 0 +0x8A57 0x5967 # 0 +0x8A58 0x5968 # 0 +0x8A59 0x5969 # 0 +0x8A5A 0x596A # 0 +0x8A5B 0x596B # 0 +0x8A5C 0x596C # 0 +0x8A5D 0x596D # 0 +0x8A5E 0x596E # 0 +0x8A5F 0x596F # 0 +0x8A60 0x5970 # 0 +0x8A61 0x5971 # 0 +0x8A62 0x5972 # 0 +0x8A63 0x5975 # 0 +0x8A64 0x5977 # 0 +0x8A65 0x597A # 0 +0x8A66 0x597B # 0 +0x8A67 0x597C # 0 +0x8A68 0x597E # 0 +0x8A69 0x597F # 0 +0x8A6A 0x5980 # 0 +0x8A6B 0x5985 # 0 +0x8A6C 0x5989 # 0 +0x8A6D 0x598B # 0 +0x8A6E 0x598C # 0 +0x8A6F 0x598E # 0 +0x8A70 0x598F # 0 +0x8A71 0x5990 # 0 +0x8A72 0x5991 # 0 +0x8A73 0x5994 # 0 +0x8A74 0x5995 # 0 +0x8A75 0x5998 # 0 +0x8A76 0x599A # 0 +0x8A77 0x599B # 0 +0x8A78 0x599C # 0 +0x8A79 0x599D # 0 +0x8A7A 0x599F # 0 +0x8A7B 0x59A0 # 0 +0x8A7C 0x59A1 # 0 +0x8A7D 0x59A2 # 0 +0x8A7E 0x59A6 # 0 +0x8A80 0x59A7 # 0 +0x8A81 0x59AC # 0 +0x8A82 0x59AD # 0 +0x8A83 0x59B0 # 0 +0x8A84 0x59B1 # 0 +0x8A85 0x59B3 # 0 +0x8A86 0x59B4 # 0 +0x8A87 0x59B5 # 0 +0x8A88 0x59B6 # 0 +0x8A89 0x59B7 # 0 +0x8A8A 0x59B8 # 0 +0x8A8B 0x59BA # 0 +0x8A8C 0x59BC # 0 +0x8A8D 0x59BD # 0 +0x8A8E 0x59BF # 0 +0x8A8F 0x59C0 # 0 +0x8A90 0x59C1 # 0 +0x8A91 0x59C2 # 0 +0x8A92 0x59C3 # 0 +0x8A93 0x59C4 # 0 +0x8A94 0x59C5 # 0 +0x8A95 0x59C7 # 0 +0x8A96 0x59C8 # 0 +0x8A97 0x59C9 # 0 +0x8A98 0x59CC # 0 +0x8A99 0x59CD # 0 +0x8A9A 0x59CE # 0 +0x8A9B 0x59CF # 0 +0x8A9C 0x59D5 # 0 +0x8A9D 0x59D6 # 0 +0x8A9E 0x59D9 # 0 +0x8A9F 0x59DB # 0 +0x8AA0 0x59DE # 0 +0x8AA1 0x59DF # 0 +0x8AA2 0x59E0 # 0 +0x8AA3 0x59E1 # 0 +0x8AA4 0x59E2 # 0 +0x8AA5 0x59E4 # 0 +0x8AA6 0x59E6 # 0 +0x8AA7 0x59E7 # 0 +0x8AA8 0x59E9 # 0 +0x8AA9 0x59EA # 0 +0x8AAA 0x59EB # 0 +0x8AAB 0x59ED # 0 +0x8AAC 0x59EE # 0 +0x8AAD 0x59EF # 0 +0x8AAE 0x59F0 # 0 +0x8AAF 0x59F1 # 0 +0x8AB0 0x59F2 # 0 +0x8AB1 0x59F3 # 0 +0x8AB2 0x59F4 # 0 +0x8AB3 0x59F5 # 0 +0x8AB4 0x59F6 # 0 +0x8AB5 0x59F7 # 0 +0x8AB6 0x59F8 # 0 +0x8AB7 0x59FA # 0 +0x8AB8 0x59FC # 0 +0x8AB9 0x59FD # 0 +0x8ABA 0x59FE # 0 +0x8ABB 0x5A00 # 0 +0x8ABC 0x5A02 # 0 +0x8ABD 0x5A0A # 0 +0x8ABE 0x5A0B # 0 +0x8ABF 0x5A0D # 0 +0x8AC0 0x5A0E # 0 +0x8AC1 0x5A0F # 0 +0x8AC2 0x5A10 # 0 +0x8AC3 0x5A12 # 0 +0x8AC4 0x5A14 # 0 +0x8AC5 0x5A15 # 0 +0x8AC6 0x5A16 # 0 +0x8AC7 0x5A17 # 0 +0x8AC8 0x5A19 # 0 +0x8AC9 0x5A1A # 0 +0x8ACA 0x5A1B # 0 +0x8ACB 0x5A1D # 0 +0x8ACC 0x5A1E # 0 +0x8ACD 0x5A21 # 0 +0x8ACE 0x5A22 # 0 +0x8ACF 0x5A24 # 0 +0x8AD0 0x5A26 # 0 +0x8AD1 0x5A27 # 0 +0x8AD2 0x5A28 # 0 +0x8AD3 0x5A2A # 0 +0x8AD4 0x5A2B # 0 +0x8AD5 0x5A2C # 0 +0x8AD6 0x5A2D # 0 +0x8AD7 0x5A2E # 0 +0x8AD8 0x5A2F # 0 +0x8AD9 0x5A30 # 0 +0x8ADA 0x5A33 # 0 +0x8ADB 0x5A35 # 0 +0x8ADC 0x5A37 # 0 +0x8ADD 0x5A38 # 0 +0x8ADE 0x5A39 # 0 +0x8ADF 0x5A3A # 0 +0x8AE0 0x5A3B # 0 +0x8AE1 0x5A3D # 0 +0x8AE2 0x5A3E # 0 +0x8AE3 0x5A3F # 0 +0x8AE4 0x5A41 # 0 +0x8AE5 0x5A42 # 0 +0x8AE6 0x5A43 # 0 +0x8AE7 0x5A44 # 0 +0x8AE8 0x5A45 # 0 +0x8AE9 0x5A47 # 0 +0x8AEA 0x5A48 # 0 +0x8AEB 0x5A4B # 0 +0x8AEC 0x5A4C # 0 +0x8AED 0x5A4D # 0 +0x8AEE 0x5A4E # 0 +0x8AEF 0x5A4F # 0 +0x8AF0 0x5A50 # 0 +0x8AF1 0x5A51 # 0 +0x8AF2 0x5A52 # 0 +0x8AF3 0x5A53 # 0 +0x8AF4 0x5A54 # 0 +0x8AF5 0x5A56 # 0 +0x8AF6 0x5A57 # 0 +0x8AF7 0x5A58 # 0 +0x8AF8 0x5A59 # 0 +0x8AF9 0x5A5B # 0 +0x8AFA 0x5A5C # 0 +0x8AFB 0x5A5D # 0 +0x8AFC 0x5A5E # 0 +0x8AFD 0x5A5F # 0 +0x8AFE 0x5A60 # 0 +0x8B40 0x5A61 # 0 +0x8B41 0x5A63 # 0 +0x8B42 0x5A64 # 0 +0x8B43 0x5A65 # 0 +0x8B44 0x5A66 # 0 +0x8B45 0x5A68 # 0 +0x8B46 0x5A69 # 0 +0x8B47 0x5A6B # 0 +0x8B48 0x5A6C # 0 +0x8B49 0x5A6D # 0 +0x8B4A 0x5A6E # 0 +0x8B4B 0x5A6F # 0 +0x8B4C 0x5A70 # 0 +0x8B4D 0x5A71 # 0 +0x8B4E 0x5A72 # 0 +0x8B4F 0x5A73 # 0 +0x8B50 0x5A78 # 0 +0x8B51 0x5A79 # 0 +0x8B52 0x5A7B # 0 +0x8B53 0x5A7C # 0 +0x8B54 0x5A7D # 0 +0x8B55 0x5A7E # 0 +0x8B56 0x5A80 # 0 +0x8B57 0x5A81 # 0 +0x8B58 0x5A82 # 0 +0x8B59 0x5A83 # 0 +0x8B5A 0x5A84 # 0 +0x8B5B 0x5A85 # 0 +0x8B5C 0x5A86 # 0 +0x8B5D 0x5A87 # 0 +0x8B5E 0x5A88 # 0 +0x8B5F 0x5A89 # 0 +0x8B60 0x5A8A # 0 +0x8B61 0x5A8B # 0 +0x8B62 0x5A8C # 0 +0x8B63 0x5A8D # 0 +0x8B64 0x5A8E # 0 +0x8B65 0x5A8F # 0 +0x8B66 0x5A90 # 0 +0x8B67 0x5A91 # 0 +0x8B68 0x5A93 # 0 +0x8B69 0x5A94 # 0 +0x8B6A 0x5A95 # 0 +0x8B6B 0x5A96 # 0 +0x8B6C 0x5A97 # 0 +0x8B6D 0x5A98 # 0 +0x8B6E 0x5A99 # 0 +0x8B6F 0x5A9C # 0 +0x8B70 0x5A9D # 0 +0x8B71 0x5A9E # 0 +0x8B72 0x5A9F # 0 +0x8B73 0x5AA0 # 0 +0x8B74 0x5AA1 # 0 +0x8B75 0x5AA2 # 0 +0x8B76 0x5AA3 # 0 +0x8B77 0x5AA4 # 0 +0x8B78 0x5AA5 # 0 +0x8B79 0x5AA6 # 0 +0x8B7A 0x5AA7 # 0 +0x8B7B 0x5AA8 # 0 +0x8B7C 0x5AA9 # 0 +0x8B7D 0x5AAB # 0 +0x8B7E 0x5AAC # 0 +0x8B80 0x5AAD # 0 +0x8B81 0x5AAE # 0 +0x8B82 0x5AAF # 0 +0x8B83 0x5AB0 # 0 +0x8B84 0x5AB1 # 0 +0x8B85 0x5AB4 # 0 +0x8B86 0x5AB6 # 0 +0x8B87 0x5AB7 # 0 +0x8B88 0x5AB9 # 0 +0x8B89 0x5ABA # 0 +0x8B8A 0x5ABB # 0 +0x8B8B 0x5ABC # 0 +0x8B8C 0x5ABD # 0 +0x8B8D 0x5ABF # 0 +0x8B8E 0x5AC0 # 0 +0x8B8F 0x5AC3 # 0 +0x8B90 0x5AC4 # 0 +0x8B91 0x5AC5 # 0 +0x8B92 0x5AC6 # 0 +0x8B93 0x5AC7 # 0 +0x8B94 0x5AC8 # 0 +0x8B95 0x5ACA # 0 +0x8B96 0x5ACB # 0 +0x8B97 0x5ACD # 0 +0x8B98 0x5ACE # 0 +0x8B99 0x5ACF # 0 +0x8B9A 0x5AD0 # 0 +0x8B9B 0x5AD1 # 0 +0x8B9C 0x5AD3 # 0 +0x8B9D 0x5AD5 # 0 +0x8B9E 0x5AD7 # 0 +0x8B9F 0x5AD9 # 0 +0x8BA0 0x5ADA # 0 +0x8BA1 0x5ADB # 0 +0x8BA2 0x5ADD # 0 +0x8BA3 0x5ADE # 0 +0x8BA4 0x5ADF # 0 +0x8BA5 0x5AE2 # 0 +0x8BA6 0x5AE4 # 0 +0x8BA7 0x5AE5 # 0 +0x8BA8 0x5AE7 # 0 +0x8BA9 0x5AE8 # 0 +0x8BAA 0x5AEA # 0 +0x8BAB 0x5AEC # 0 +0x8BAC 0x5AED # 0 +0x8BAD 0x5AEE # 0 +0x8BAE 0x5AEF # 0 +0x8BAF 0x5AF0 # 0 +0x8BB0 0x5AF2 # 0 +0x8BB1 0x5AF3 # 0 +0x8BB2 0x5AF4 # 0 +0x8BB3 0x5AF5 # 0 +0x8BB4 0x5AF6 # 0 +0x8BB5 0x5AF7 # 0 +0x8BB6 0x5AF8 # 0 +0x8BB7 0x5AF9 # 0 +0x8BB8 0x5AFA # 0 +0x8BB9 0x5AFB # 0 +0x8BBA 0x5AFC # 0 +0x8BBB 0x5AFD # 0 +0x8BBC 0x5AFE # 0 +0x8BBD 0x5AFF # 0 +0x8BBE 0x5B00 # 0 +0x8BBF 0x5B01 # 0 +0x8BC0 0x5B02 # 0 +0x8BC1 0x5B03 # 0 +0x8BC2 0x5B04 # 0 +0x8BC3 0x5B05 # 0 +0x8BC4 0x5B06 # 0 +0x8BC5 0x5B07 # 0 +0x8BC6 0x5B08 # 0 +0x8BC7 0x5B0A # 0 +0x8BC8 0x5B0B # 0 +0x8BC9 0x5B0C # 0 +0x8BCA 0x5B0D # 0 +0x8BCB 0x5B0E # 0 +0x8BCC 0x5B0F # 0 +0x8BCD 0x5B10 # 0 +0x8BCE 0x5B11 # 0 +0x8BCF 0x5B12 # 0 +0x8BD0 0x5B13 # 0 +0x8BD1 0x5B14 # 0 +0x8BD2 0x5B15 # 0 +0x8BD3 0x5B18 # 0 +0x8BD4 0x5B19 # 0 +0x8BD5 0x5B1A # 0 +0x8BD6 0x5B1B # 0 +0x8BD7 0x5B1C # 0 +0x8BD8 0x5B1D # 0 +0x8BD9 0x5B1E # 0 +0x8BDA 0x5B1F # 0 +0x8BDB 0x5B20 # 0 +0x8BDC 0x5B21 # 0 +0x8BDD 0x5B22 # 0 +0x8BDE 0x5B23 # 0 +0x8BDF 0x5B24 # 0 +0x8BE0 0x5B25 # 0 +0x8BE1 0x5B26 # 0 +0x8BE2 0x5B27 # 0 +0x8BE3 0x5B28 # 0 +0x8BE4 0x5B29 # 0 +0x8BE5 0x5B2A # 0 +0x8BE6 0x5B2B # 0 +0x8BE7 0x5B2C # 0 +0x8BE8 0x5B2D # 0 +0x8BE9 0x5B2E # 0 +0x8BEA 0x5B2F # 0 +0x8BEB 0x5B30 # 0 +0x8BEC 0x5B31 # 0 +0x8BED 0x5B33 # 0 +0x8BEE 0x5B35 # 0 +0x8BEF 0x5B36 # 0 +0x8BF0 0x5B38 # 0 +0x8BF1 0x5B39 # 0 +0x8BF2 0x5B3A # 0 +0x8BF3 0x5B3B # 0 +0x8BF4 0x5B3C # 0 +0x8BF5 0x5B3D # 0 +0x8BF6 0x5B3E # 0 +0x8BF7 0x5B3F # 0 +0x8BF8 0x5B41 # 0 +0x8BF9 0x5B42 # 0 +0x8BFA 0x5B43 # 0 +0x8BFB 0x5B44 # 0 +0x8BFC 0x5B45 # 0 +0x8BFD 0x5B46 # 0 +0x8BFE 0x5B47 # 0 +0x8C40 0x5B48 # 0 +0x8C41 0x5B49 # 0 +0x8C42 0x5B4A # 0 +0x8C43 0x5B4B # 0 +0x8C44 0x5B4C # 0 +0x8C45 0x5B4D # 0 +0x8C46 0x5B4E # 0 +0x8C47 0x5B4F # 0 +0x8C48 0x5B52 # 0 +0x8C49 0x5B56 # 0 +0x8C4A 0x5B5E # 0 +0x8C4B 0x5B60 # 0 +0x8C4C 0x5B61 # 0 +0x8C4D 0x5B67 # 0 +0x8C4E 0x5B68 # 0 +0x8C4F 0x5B6B # 0 +0x8C50 0x5B6D # 0 +0x8C51 0x5B6E # 0 +0x8C52 0x5B6F # 0 +0x8C53 0x5B72 # 0 +0x8C54 0x5B74 # 0 +0x8C55 0x5B76 # 0 +0x8C56 0x5B77 # 0 +0x8C57 0x5B78 # 0 +0x8C58 0x5B79 # 0 +0x8C59 0x5B7B # 0 +0x8C5A 0x5B7C # 0 +0x8C5B 0x5B7E # 0 +0x8C5C 0x5B7F # 0 +0x8C5D 0x5B82 # 0 +0x8C5E 0x5B86 # 0 +0x8C5F 0x5B8A # 0 +0x8C60 0x5B8D # 0 +0x8C61 0x5B8E # 0 +0x8C62 0x5B90 # 0 +0x8C63 0x5B91 # 0 +0x8C64 0x5B92 # 0 +0x8C65 0x5B94 # 0 +0x8C66 0x5B96 # 0 +0x8C67 0x5B9F # 0 +0x8C68 0x5BA7 # 0 +0x8C69 0x5BA8 # 0 +0x8C6A 0x5BA9 # 0 +0x8C6B 0x5BAC # 0 +0x8C6C 0x5BAD # 0 +0x8C6D 0x5BAE # 0 +0x8C6E 0x5BAF # 0 +0x8C6F 0x5BB1 # 0 +0x8C70 0x5BB2 # 0 +0x8C71 0x5BB7 # 0 +0x8C72 0x5BBA # 0 +0x8C73 0x5BBB # 0 +0x8C74 0x5BBC # 0 +0x8C75 0x5BC0 # 0 +0x8C76 0x5BC1 # 0 +0x8C77 0x5BC3 # 0 +0x8C78 0x5BC8 # 0 +0x8C79 0x5BC9 # 0 +0x8C7A 0x5BCA # 0 +0x8C7B 0x5BCB # 0 +0x8C7C 0x5BCD # 0 +0x8C7D 0x5BCE # 0 +0x8C7E 0x5BCF # 0 +0x8C80 0x5BD1 # 0 +0x8C81 0x5BD4 # 0 +0x8C82 0x5BD5 # 0 +0x8C83 0x5BD6 # 0 +0x8C84 0x5BD7 # 0 +0x8C85 0x5BD8 # 0 +0x8C86 0x5BD9 # 0 +0x8C87 0x5BDA # 0 +0x8C88 0x5BDB # 0 +0x8C89 0x5BDC # 0 +0x8C8A 0x5BE0 # 0 +0x8C8B 0x5BE2 # 0 +0x8C8C 0x5BE3 # 0 +0x8C8D 0x5BE6 # 0 +0x8C8E 0x5BE7 # 0 +0x8C8F 0x5BE9 # 0 +0x8C90 0x5BEA # 0 +0x8C91 0x5BEB # 0 +0x8C92 0x5BEC # 0 +0x8C93 0x5BED # 0 +0x8C94 0x5BEF # 0 +0x8C95 0x5BF1 # 0 +0x8C96 0x5BF2 # 0 +0x8C97 0x5BF3 # 0 +0x8C98 0x5BF4 # 0 +0x8C99 0x5BF5 # 0 +0x8C9A 0x5BF6 # 0 +0x8C9B 0x5BF7 # 0 +0x8C9C 0x5BFD # 0 +0x8C9D 0x5BFE # 0 +0x8C9E 0x5C00 # 0 +0x8C9F 0x5C02 # 0 +0x8CA0 0x5C03 # 0 +0x8CA1 0x5C05 # 0 +0x8CA2 0x5C07 # 0 +0x8CA3 0x5C08 # 0 +0x8CA4 0x5C0B # 0 +0x8CA5 0x5C0C # 0 +0x8CA6 0x5C0D # 0 +0x8CA7 0x5C0E # 0 +0x8CA8 0x5C10 # 0 +0x8CA9 0x5C12 # 0 +0x8CAA 0x5C13 # 0 +0x8CAB 0x5C17 # 0 +0x8CAC 0x5C19 # 0 +0x8CAD 0x5C1B # 0 +0x8CAE 0x5C1E # 0 +0x8CAF 0x5C1F # 0 +0x8CB0 0x5C20 # 0 +0x8CB1 0x5C21 # 0 +0x8CB2 0x5C23 # 0 +0x8CB3 0x5C26 # 0 +0x8CB4 0x5C28 # 0 +0x8CB5 0x5C29 # 0 +0x8CB6 0x5C2A # 0 +0x8CB7 0x5C2B # 0 +0x8CB8 0x5C2D # 0 +0x8CB9 0x5C2E # 0 +0x8CBA 0x5C2F # 0 +0x8CBB 0x5C30 # 0 +0x8CBC 0x5C32 # 0 +0x8CBD 0x5C33 # 0 +0x8CBE 0x5C35 # 0 +0x8CBF 0x5C36 # 0 +0x8CC0 0x5C37 # 0 +0x8CC1 0x5C43 # 0 +0x8CC2 0x5C44 # 0 +0x8CC3 0x5C46 # 0 +0x8CC4 0x5C47 # 0 +0x8CC5 0x5C4C # 0 +0x8CC6 0x5C4D # 0 +0x8CC7 0x5C52 # 0 +0x8CC8 0x5C53 # 0 +0x8CC9 0x5C54 # 0 +0x8CCA 0x5C56 # 0 +0x8CCB 0x5C57 # 0 +0x8CCC 0x5C58 # 0 +0x8CCD 0x5C5A # 0 +0x8CCE 0x5C5B # 0 +0x8CCF 0x5C5C # 0 +0x8CD0 0x5C5D # 0 +0x8CD1 0x5C5F # 0 +0x8CD2 0x5C62 # 0 +0x8CD3 0x5C64 # 0 +0x8CD4 0x5C67 # 0 +0x8CD5 0x5C68 # 0 +0x8CD6 0x5C69 # 0 +0x8CD7 0x5C6A # 0 +0x8CD8 0x5C6B # 0 +0x8CD9 0x5C6C # 0 +0x8CDA 0x5C6D # 0 +0x8CDB 0x5C70 # 0 +0x8CDC 0x5C72 # 0 +0x8CDD 0x5C73 # 0 +0x8CDE 0x5C74 # 0 +0x8CDF 0x5C75 # 0 +0x8CE0 0x5C76 # 0 +0x8CE1 0x5C77 # 0 +0x8CE2 0x5C78 # 0 +0x8CE3 0x5C7B # 0 +0x8CE4 0x5C7C # 0 +0x8CE5 0x5C7D # 0 +0x8CE6 0x5C7E # 0 +0x8CE7 0x5C80 # 0 +0x8CE8 0x5C83 # 0 +0x8CE9 0x5C84 # 0 +0x8CEA 0x5C85 # 0 +0x8CEB 0x5C86 # 0 +0x8CEC 0x5C87 # 0 +0x8CED 0x5C89 # 0 +0x8CEE 0x5C8A # 0 +0x8CEF 0x5C8B # 0 +0x8CF0 0x5C8E # 0 +0x8CF1 0x5C8F # 0 +0x8CF2 0x5C92 # 0 +0x8CF3 0x5C93 # 0 +0x8CF4 0x5C95 # 0 +0x8CF5 0x5C9D # 0 +0x8CF6 0x5C9E # 0 +0x8CF7 0x5C9F # 0 +0x8CF8 0x5CA0 # 0 +0x8CF9 0x5CA1 # 0 +0x8CFA 0x5CA4 # 0 +0x8CFB 0x5CA5 # 0 +0x8CFC 0x5CA6 # 0 +0x8CFD 0x5CA7 # 0 +0x8CFE 0x5CA8 # 0 +0x8D40 0x5CAA # 0 +0x8D41 0x5CAE # 0 +0x8D42 0x5CAF # 0 +0x8D43 0x5CB0 # 0 +0x8D44 0x5CB2 # 0 +0x8D45 0x5CB4 # 0 +0x8D46 0x5CB6 # 0 +0x8D47 0x5CB9 # 0 +0x8D48 0x5CBA # 0 +0x8D49 0x5CBB # 0 +0x8D4A 0x5CBC # 0 +0x8D4B 0x5CBE # 0 +0x8D4C 0x5CC0 # 0 +0x8D4D 0x5CC2 # 0 +0x8D4E 0x5CC3 # 0 +0x8D4F 0x5CC5 # 0 +0x8D50 0x5CC6 # 0 +0x8D51 0x5CC7 # 0 +0x8D52 0x5CC8 # 0 +0x8D53 0x5CC9 # 0 +0x8D54 0x5CCA # 0 +0x8D55 0x5CCC # 0 +0x8D56 0x5CCD # 0 +0x8D57 0x5CCE # 0 +0x8D58 0x5CCF # 0 +0x8D59 0x5CD0 # 0 +0x8D5A 0x5CD1 # 0 +0x8D5B 0x5CD3 # 0 +0x8D5C 0x5CD4 # 0 +0x8D5D 0x5CD5 # 0 +0x8D5E 0x5CD6 # 0 +0x8D5F 0x5CD7 # 0 +0x8D60 0x5CD8 # 0 +0x8D61 0x5CDA # 0 +0x8D62 0x5CDB # 0 +0x8D63 0x5CDC # 0 +0x8D64 0x5CDD # 0 +0x8D65 0x5CDE # 0 +0x8D66 0x5CDF # 0 +0x8D67 0x5CE0 # 0 +0x8D68 0x5CE2 # 0 +0x8D69 0x5CE3 # 0 +0x8D6A 0x5CE7 # 0 +0x8D6B 0x5CE9 # 0 +0x8D6C 0x5CEB # 0 +0x8D6D 0x5CEC # 0 +0x8D6E 0x5CEE # 0 +0x8D6F 0x5CEF # 0 +0x8D70 0x5CF1 # 0 +0x8D71 0x5CF2 # 0 +0x8D72 0x5CF3 # 0 +0x8D73 0x5CF4 # 0 +0x8D74 0x5CF5 # 0 +0x8D75 0x5CF6 # 0 +0x8D76 0x5CF7 # 0 +0x8D77 0x5CF8 # 0 +0x8D78 0x5CF9 # 0 +0x8D79 0x5CFA # 0 +0x8D7A 0x5CFC # 0 +0x8D7B 0x5CFD # 0 +0x8D7C 0x5CFE # 0 +0x8D7D 0x5CFF # 0 +0x8D7E 0x5D00 # 0 +0x8D80 0x5D01 # 0 +0x8D81 0x5D04 # 0 +0x8D82 0x5D05 # 0 +0x8D83 0x5D08 # 0 +0x8D84 0x5D09 # 0 +0x8D85 0x5D0A # 0 +0x8D86 0x5D0B # 0 +0x8D87 0x5D0C # 0 +0x8D88 0x5D0D # 0 +0x8D89 0x5D0F # 0 +0x8D8A 0x5D10 # 0 +0x8D8B 0x5D11 # 0 +0x8D8C 0x5D12 # 0 +0x8D8D 0x5D13 # 0 +0x8D8E 0x5D15 # 0 +0x8D8F 0x5D17 # 0 +0x8D90 0x5D18 # 0 +0x8D91 0x5D19 # 0 +0x8D92 0x5D1A # 0 +0x8D93 0x5D1C # 0 +0x8D94 0x5D1D # 0 +0x8D95 0x5D1F # 0 +0x8D96 0x5D20 # 0 +0x8D97 0x5D21 # 0 +0x8D98 0x5D22 # 0 +0x8D99 0x5D23 # 0 +0x8D9A 0x5D25 # 0 +0x8D9B 0x5D28 # 0 +0x8D9C 0x5D2A # 0 +0x8D9D 0x5D2B # 0 +0x8D9E 0x5D2C # 0 +0x8D9F 0x5D2F # 0 +0x8DA0 0x5D30 # 0 +0x8DA1 0x5D31 # 0 +0x8DA2 0x5D32 # 0 +0x8DA3 0x5D33 # 0 +0x8DA4 0x5D35 # 0 +0x8DA5 0x5D36 # 0 +0x8DA6 0x5D37 # 0 +0x8DA7 0x5D38 # 0 +0x8DA8 0x5D39 # 0 +0x8DA9 0x5D3A # 0 +0x8DAA 0x5D3B # 0 +0x8DAB 0x5D3C # 0 +0x8DAC 0x5D3F # 0 +0x8DAD 0x5D40 # 0 +0x8DAE 0x5D41 # 0 +0x8DAF 0x5D42 # 0 +0x8DB0 0x5D43 # 0 +0x8DB1 0x5D44 # 0 +0x8DB2 0x5D45 # 0 +0x8DB3 0x5D46 # 0 +0x8DB4 0x5D48 # 0 +0x8DB5 0x5D49 # 0 +0x8DB6 0x5D4D # 0 +0x8DB7 0x5D4E # 0 +0x8DB8 0x5D4F # 0 +0x8DB9 0x5D50 # 0 +0x8DBA 0x5D51 # 0 +0x8DBB 0x5D52 # 0 +0x8DBC 0x5D53 # 0 +0x8DBD 0x5D54 # 0 +0x8DBE 0x5D55 # 0 +0x8DBF 0x5D56 # 0 +0x8DC0 0x5D57 # 0 +0x8DC1 0x5D59 # 0 +0x8DC2 0x5D5A # 0 +0x8DC3 0x5D5C # 0 +0x8DC4 0x5D5E # 0 +0x8DC5 0x5D5F # 0 +0x8DC6 0x5D60 # 0 +0x8DC7 0x5D61 # 0 +0x8DC8 0x5D62 # 0 +0x8DC9 0x5D63 # 0 +0x8DCA 0x5D64 # 0 +0x8DCB 0x5D65 # 0 +0x8DCC 0x5D66 # 0 +0x8DCD 0x5D67 # 0 +0x8DCE 0x5D68 # 0 +0x8DCF 0x5D6A # 0 +0x8DD0 0x5D6D # 0 +0x8DD1 0x5D6E # 0 +0x8DD2 0x5D70 # 0 +0x8DD3 0x5D71 # 0 +0x8DD4 0x5D72 # 0 +0x8DD5 0x5D73 # 0 +0x8DD6 0x5D75 # 0 +0x8DD7 0x5D76 # 0 +0x8DD8 0x5D77 # 0 +0x8DD9 0x5D78 # 0 +0x8DDA 0x5D79 # 0 +0x8DDB 0x5D7A # 0 +0x8DDC 0x5D7B # 0 +0x8DDD 0x5D7C # 0 +0x8DDE 0x5D7D # 0 +0x8DDF 0x5D7E # 0 +0x8DE0 0x5D7F # 0 +0x8DE1 0x5D80 # 0 +0x8DE2 0x5D81 # 0 +0x8DE3 0x5D83 # 0 +0x8DE4 0x5D84 # 0 +0x8DE5 0x5D85 # 0 +0x8DE6 0x5D86 # 0 +0x8DE7 0x5D87 # 0 +0x8DE8 0x5D88 # 0 +0x8DE9 0x5D89 # 0 +0x8DEA 0x5D8A # 0 +0x8DEB 0x5D8B # 0 +0x8DEC 0x5D8C # 0 +0x8DED 0x5D8D # 0 +0x8DEE 0x5D8E # 0 +0x8DEF 0x5D8F # 0 +0x8DF0 0x5D90 # 0 +0x8DF1 0x5D91 # 0 +0x8DF2 0x5D92 # 0 +0x8DF3 0x5D93 # 0 +0x8DF4 0x5D94 # 0 +0x8DF5 0x5D95 # 0 +0x8DF6 0x5D96 # 0 +0x8DF7 0x5D97 # 0 +0x8DF8 0x5D98 # 0 +0x8DF9 0x5D9A # 0 +0x8DFA 0x5D9B # 0 +0x8DFB 0x5D9C # 0 +0x8DFC 0x5D9E # 0 +0x8DFD 0x5D9F # 0 +0x8DFE 0x5DA0 # 0 +0x8E40 0x5DA1 # 0 +0x8E41 0x5DA2 # 0 +0x8E42 0x5DA3 # 0 +0x8E43 0x5DA4 # 0 +0x8E44 0x5DA5 # 0 +0x8E45 0x5DA6 # 0 +0x8E46 0x5DA7 # 0 +0x8E47 0x5DA8 # 0 +0x8E48 0x5DA9 # 0 +0x8E49 0x5DAA # 0 +0x8E4A 0x5DAB # 0 +0x8E4B 0x5DAC # 0 +0x8E4C 0x5DAD # 0 +0x8E4D 0x5DAE # 0 +0x8E4E 0x5DAF # 0 +0x8E4F 0x5DB0 # 0 +0x8E50 0x5DB1 # 0 +0x8E51 0x5DB2 # 0 +0x8E52 0x5DB3 # 0 +0x8E53 0x5DB4 # 0 +0x8E54 0x5DB5 # 0 +0x8E55 0x5DB6 # 0 +0x8E56 0x5DB8 # 0 +0x8E57 0x5DB9 # 0 +0x8E58 0x5DBA # 0 +0x8E59 0x5DBB # 0 +0x8E5A 0x5DBC # 0 +0x8E5B 0x5DBD # 0 +0x8E5C 0x5DBE # 0 +0x8E5D 0x5DBF # 0 +0x8E5E 0x5DC0 # 0 +0x8E5F 0x5DC1 # 0 +0x8E60 0x5DC2 # 0 +0x8E61 0x5DC3 # 0 +0x8E62 0x5DC4 # 0 +0x8E63 0x5DC6 # 0 +0x8E64 0x5DC7 # 0 +0x8E65 0x5DC8 # 0 +0x8E66 0x5DC9 # 0 +0x8E67 0x5DCA # 0 +0x8E68 0x5DCB # 0 +0x8E69 0x5DCC # 0 +0x8E6A 0x5DCE # 0 +0x8E6B 0x5DCF # 0 +0x8E6C 0x5DD0 # 0 +0x8E6D 0x5DD1 # 0 +0x8E6E 0x5DD2 # 0 +0x8E6F 0x5DD3 # 0 +0x8E70 0x5DD4 # 0 +0x8E71 0x5DD5 # 0 +0x8E72 0x5DD6 # 0 +0x8E73 0x5DD7 # 0 +0x8E74 0x5DD8 # 0 +0x8E75 0x5DD9 # 0 +0x8E76 0x5DDA # 0 +0x8E77 0x5DDC # 0 +0x8E78 0x5DDF # 0 +0x8E79 0x5DE0 # 0 +0x8E7A 0x5DE3 # 0 +0x8E7B 0x5DE4 # 0 +0x8E7C 0x5DEA # 0 +0x8E7D 0x5DEC # 0 +0x8E7E 0x5DED # 0 +0x8E80 0x5DF0 # 0 +0x8E81 0x5DF5 # 0 +0x8E82 0x5DF6 # 0 +0x8E83 0x5DF8 # 0 +0x8E84 0x5DF9 # 0 +0x8E85 0x5DFA # 0 +0x8E86 0x5DFB # 0 +0x8E87 0x5DFC # 0 +0x8E88 0x5DFF # 0 +0x8E89 0x5E00 # 0 +0x8E8A 0x5E04 # 0 +0x8E8B 0x5E07 # 0 +0x8E8C 0x5E09 # 0 +0x8E8D 0x5E0A # 0 +0x8E8E 0x5E0B # 0 +0x8E8F 0x5E0D # 0 +0x8E90 0x5E0E # 0 +0x8E91 0x5E12 # 0 +0x8E92 0x5E13 # 0 +0x8E93 0x5E17 # 0 +0x8E94 0x5E1E # 0 +0x8E95 0x5E1F # 0 +0x8E96 0x5E20 # 0 +0x8E97 0x5E21 # 0 +0x8E98 0x5E22 # 0 +0x8E99 0x5E23 # 0 +0x8E9A 0x5E24 # 0 +0x8E9B 0x5E25 # 0 +0x8E9C 0x5E28 # 0 +0x8E9D 0x5E29 # 0 +0x8E9E 0x5E2A # 0 +0x8E9F 0x5E2B # 0 +0x8EA0 0x5E2C # 0 +0x8EA1 0x5E2F # 0 +0x8EA2 0x5E30 # 0 +0x8EA3 0x5E32 # 0 +0x8EA4 0x5E33 # 0 +0x8EA5 0x5E34 # 0 +0x8EA6 0x5E35 # 0 +0x8EA7 0x5E36 # 0 +0x8EA8 0x5E39 # 0 +0x8EA9 0x5E3A # 0 +0x8EAA 0x5E3E # 0 +0x8EAB 0x5E3F # 0 +0x8EAC 0x5E40 # 0 +0x8EAD 0x5E41 # 0 +0x8EAE 0x5E43 # 0 +0x8EAF 0x5E46 # 0 +0x8EB0 0x5E47 # 0 +0x8EB1 0x5E48 # 0 +0x8EB2 0x5E49 # 0 +0x8EB3 0x5E4A # 0 +0x8EB4 0x5E4B # 0 +0x8EB5 0x5E4D # 0 +0x8EB6 0x5E4E # 0 +0x8EB7 0x5E4F # 0 +0x8EB8 0x5E50 # 0 +0x8EB9 0x5E51 # 0 +0x8EBA 0x5E52 # 0 +0x8EBB 0x5E53 # 0 +0x8EBC 0x5E56 # 0 +0x8EBD 0x5E57 # 0 +0x8EBE 0x5E58 # 0 +0x8EBF 0x5E59 # 0 +0x8EC0 0x5E5A # 0 +0x8EC1 0x5E5C # 0 +0x8EC2 0x5E5D # 0 +0x8EC3 0x5E5F # 0 +0x8EC4 0x5E60 # 0 +0x8EC5 0x5E63 # 0 +0x8EC6 0x5E64 # 0 +0x8EC7 0x5E65 # 0 +0x8EC8 0x5E66 # 0 +0x8EC9 0x5E67 # 0 +0x8ECA 0x5E68 # 0 +0x8ECB 0x5E69 # 0 +0x8ECC 0x5E6A # 0 +0x8ECD 0x5E6B # 0 +0x8ECE 0x5E6C # 0 +0x8ECF 0x5E6D # 0 +0x8ED0 0x5E6E # 0 +0x8ED1 0x5E6F # 0 +0x8ED2 0x5E70 # 0 +0x8ED3 0x5E71 # 0 +0x8ED4 0x5E75 # 0 +0x8ED5 0x5E77 # 0 +0x8ED6 0x5E79 # 0 +0x8ED7 0x5E7E # 0 +0x8ED8 0x5E81 # 0 +0x8ED9 0x5E82 # 0 +0x8EDA 0x5E83 # 0 +0x8EDB 0x5E85 # 0 +0x8EDC 0x5E88 # 0 +0x8EDD 0x5E89 # 0 +0x8EDE 0x5E8C # 0 +0x8EDF 0x5E8D # 0 +0x8EE0 0x5E8E # 0 +0x8EE1 0x5E92 # 0 +0x8EE2 0x5E98 # 0 +0x8EE3 0x5E9B # 0 +0x8EE4 0x5E9D # 0 +0x8EE5 0x5EA1 # 0 +0x8EE6 0x5EA2 # 0 +0x8EE7 0x5EA3 # 0 +0x8EE8 0x5EA4 # 0 +0x8EE9 0x5EA8 # 0 +0x8EEA 0x5EA9 # 0 +0x8EEB 0x5EAA # 0 +0x8EEC 0x5EAB # 0 +0x8EED 0x5EAC # 0 +0x8EEE 0x5EAE # 0 +0x8EEF 0x5EAF # 0 +0x8EF0 0x5EB0 # 0 +0x8EF1 0x5EB1 # 0 +0x8EF2 0x5EB2 # 0 +0x8EF3 0x5EB4 # 0 +0x8EF4 0x5EBA # 0 +0x8EF5 0x5EBB # 0 +0x8EF6 0x5EBC # 0 +0x8EF7 0x5EBD # 0 +0x8EF8 0x5EBF # 0 +0x8EF9 0x5EC0 # 0 +0x8EFA 0x5EC1 # 0 +0x8EFB 0x5EC2 # 0 +0x8EFC 0x5EC3 # 0 +0x8EFD 0x5EC4 # 0 +0x8EFE 0x5EC5 # 0 +0x8F40 0x5EC6 # 0 +0x8F41 0x5EC7 # 0 +0x8F42 0x5EC8 # 0 +0x8F43 0x5ECB # 0 +0x8F44 0x5ECC # 0 +0x8F45 0x5ECD # 0 +0x8F46 0x5ECE # 0 +0x8F47 0x5ECF # 0 +0x8F48 0x5ED0 # 0 +0x8F49 0x5ED4 # 0 +0x8F4A 0x5ED5 # 0 +0x8F4B 0x5ED7 # 0 +0x8F4C 0x5ED8 # 0 +0x8F4D 0x5ED9 # 0 +0x8F4E 0x5EDA # 0 +0x8F4F 0x5EDC # 0 +0x8F50 0x5EDD # 0 +0x8F51 0x5EDE # 0 +0x8F52 0x5EDF # 0 +0x8F53 0x5EE0 # 0 +0x8F54 0x5EE1 # 0 +0x8F55 0x5EE2 # 0 +0x8F56 0x5EE3 # 0 +0x8F57 0x5EE4 # 0 +0x8F58 0x5EE5 # 0 +0x8F59 0x5EE6 # 0 +0x8F5A 0x5EE7 # 0 +0x8F5B 0x5EE9 # 0 +0x8F5C 0x5EEB # 0 +0x8F5D 0x5EEC # 0 +0x8F5E 0x5EED # 0 +0x8F5F 0x5EEE # 0 +0x8F60 0x5EEF # 0 +0x8F61 0x5EF0 # 0 +0x8F62 0x5EF1 # 0 +0x8F63 0x5EF2 # 0 +0x8F64 0x5EF3 # 0 +0x8F65 0x5EF5 # 0 +0x8F66 0x5EF8 # 0 +0x8F67 0x5EF9 # 0 +0x8F68 0x5EFB # 0 +0x8F69 0x5EFC # 0 +0x8F6A 0x5EFD # 0 +0x8F6B 0x5F05 # 0 +0x8F6C 0x5F06 # 0 +0x8F6D 0x5F07 # 0 +0x8F6E 0x5F09 # 0 +0x8F6F 0x5F0C # 0 +0x8F70 0x5F0D # 0 +0x8F71 0x5F0E # 0 +0x8F72 0x5F10 # 0 +0x8F73 0x5F12 # 0 +0x8F74 0x5F14 # 0 +0x8F75 0x5F16 # 0 +0x8F76 0x5F19 # 0 +0x8F77 0x5F1A # 0 +0x8F78 0x5F1C # 0 +0x8F79 0x5F1D # 0 +0x8F7A 0x5F1E # 0 +0x8F7B 0x5F21 # 0 +0x8F7C 0x5F22 # 0 +0x8F7D 0x5F23 # 0 +0x8F7E 0x5F24 # 0 +0x8F80 0x5F28 # 0 +0x8F81 0x5F2B # 0 +0x8F82 0x5F2C # 0 +0x8F83 0x5F2E # 0 +0x8F84 0x5F30 # 0 +0x8F85 0x5F32 # 0 +0x8F86 0x5F33 # 0 +0x8F87 0x5F34 # 0 +0x8F88 0x5F35 # 0 +0x8F89 0x5F36 # 0 +0x8F8A 0x5F37 # 0 +0x8F8B 0x5F38 # 0 +0x8F8C 0x5F3B # 0 +0x8F8D 0x5F3D # 0 +0x8F8E 0x5F3E # 0 +0x8F8F 0x5F3F # 0 +0x8F90 0x5F41 # 0 +0x8F91 0x5F42 # 0 +0x8F92 0x5F43 # 0 +0x8F93 0x5F44 # 0 +0x8F94 0x5F45 # 0 +0x8F95 0x5F46 # 0 +0x8F96 0x5F47 # 0 +0x8F97 0x5F48 # 0 +0x8F98 0x5F49 # 0 +0x8F99 0x5F4A # 0 +0x8F9A 0x5F4B # 0 +0x8F9B 0x5F4C # 0 +0x8F9C 0x5F4D # 0 +0x8F9D 0x5F4E # 0 +0x8F9E 0x5F4F # 0 +0x8F9F 0x5F51 # 0 +0x8FA0 0x5F54 # 0 +0x8FA1 0x5F59 # 0 +0x8FA2 0x5F5A # 0 +0x8FA3 0x5F5B # 0 +0x8FA4 0x5F5C # 0 +0x8FA5 0x5F5E # 0 +0x8FA6 0x5F5F # 0 +0x8FA7 0x5F60 # 0 +0x8FA8 0x5F63 # 0 +0x8FA9 0x5F65 # 0 +0x8FAA 0x5F67 # 0 +0x8FAB 0x5F68 # 0 +0x8FAC 0x5F6B # 0 +0x8FAD 0x5F6E # 0 +0x8FAE 0x5F6F # 0 +0x8FAF 0x5F72 # 0 +0x8FB0 0x5F74 # 0 +0x8FB1 0x5F75 # 0 +0x8FB2 0x5F76 # 0 +0x8FB3 0x5F78 # 0 +0x8FB4 0x5F7A # 0 +0x8FB5 0x5F7D # 0 +0x8FB6 0x5F7E # 0 +0x8FB7 0x5F7F # 0 +0x8FB8 0x5F83 # 0 +0x8FB9 0x5F86 # 0 +0x8FBA 0x5F8D # 0 +0x8FBB 0x5F8E # 0 +0x8FBC 0x5F8F # 0 +0x8FBD 0x5F91 # 0 +0x8FBE 0x5F93 # 0 +0x8FBF 0x5F94 # 0 +0x8FC0 0x5F96 # 0 +0x8FC1 0x5F9A # 0 +0x8FC2 0x5F9B # 0 +0x8FC3 0x5F9D # 0 +0x8FC4 0x5F9E # 0 +0x8FC5 0x5F9F # 0 +0x8FC6 0x5FA0 # 0 +0x8FC7 0x5FA2 # 0 +0x8FC8 0x5FA3 # 0 +0x8FC9 0x5FA4 # 0 +0x8FCA 0x5FA5 # 0 +0x8FCB 0x5FA6 # 0 +0x8FCC 0x5FA7 # 0 +0x8FCD 0x5FA9 # 0 +0x8FCE 0x5FAB # 0 +0x8FCF 0x5FAC # 0 +0x8FD0 0x5FAF # 0 +0x8FD1 0x5FB0 # 0 +0x8FD2 0x5FB1 # 0 +0x8FD3 0x5FB2 # 0 +0x8FD4 0x5FB3 # 0 +0x8FD5 0x5FB4 # 0 +0x8FD6 0x5FB6 # 0 +0x8FD7 0x5FB8 # 0 +0x8FD8 0x5FB9 # 0 +0x8FD9 0x5FBA # 0 +0x8FDA 0x5FBB # 0 +0x8FDB 0x5FBE # 0 +0x8FDC 0x5FBF # 0 +0x8FDD 0x5FC0 # 0 +0x8FDE 0x5FC1 # 0 +0x8FDF 0x5FC2 # 0 +0x8FE0 0x5FC7 # 0 +0x8FE1 0x5FC8 # 0 +0x8FE2 0x5FCA # 0 +0x8FE3 0x5FCB # 0 +0x8FE4 0x5FCE # 0 +0x8FE5 0x5FD3 # 0 +0x8FE6 0x5FD4 # 0 +0x8FE7 0x5FD5 # 0 +0x8FE8 0x5FDA # 0 +0x8FE9 0x5FDB # 0 +0x8FEA 0x5FDC # 0 +0x8FEB 0x5FDE # 0 +0x8FEC 0x5FDF # 0 +0x8FED 0x5FE2 # 0 +0x8FEE 0x5FE3 # 0 +0x8FEF 0x5FE5 # 0 +0x8FF0 0x5FE6 # 0 +0x8FF1 0x5FE8 # 0 +0x8FF2 0x5FE9 # 0 +0x8FF3 0x5FEC # 0 +0x8FF4 0x5FEF # 0 +0x8FF5 0x5FF0 # 0 +0x8FF6 0x5FF2 # 0 +0x8FF7 0x5FF3 # 0 +0x8FF8 0x5FF4 # 0 +0x8FF9 0x5FF6 # 0 +0x8FFA 0x5FF7 # 0 +0x8FFB 0x5FF9 # 0 +0x8FFC 0x5FFA # 0 +0x8FFD 0x5FFC # 0 +0x8FFE 0x6007 # 0 +0x9040 0x6008 # 0 +0x9041 0x6009 # 0 +0x9042 0x600B # 0 +0x9043 0x600C # 0 +0x9044 0x6010 # 0 +0x9045 0x6011 # 0 +0x9046 0x6013 # 0 +0x9047 0x6017 # 0 +0x9048 0x6018 # 0 +0x9049 0x601A # 0 +0x904A 0x601E # 0 +0x904B 0x601F # 0 +0x904C 0x6022 # 0 +0x904D 0x6023 # 0 +0x904E 0x6024 # 0 +0x904F 0x602C # 0 +0x9050 0x602D # 0 +0x9051 0x602E # 0 +0x9052 0x6030 # 0 +0x9053 0x6031 # 0 +0x9054 0x6032 # 0 +0x9055 0x6033 # 0 +0x9056 0x6034 # 0 +0x9057 0x6036 # 0 +0x9058 0x6037 # 0 +0x9059 0x6038 # 0 +0x905A 0x6039 # 0 +0x905B 0x603A # 0 +0x905C 0x603D # 0 +0x905D 0x603E # 0 +0x905E 0x6040 # 0 +0x905F 0x6044 # 0 +0x9060 0x6045 # 0 +0x9061 0x6046 # 0 +0x9062 0x6047 # 0 +0x9063 0x6048 # 0 +0x9064 0x6049 # 0 +0x9065 0x604A # 0 +0x9066 0x604C # 0 +0x9067 0x604E # 0 +0x9068 0x604F # 0 +0x9069 0x6051 # 0 +0x906A 0x6053 # 0 +0x906B 0x6054 # 0 +0x906C 0x6056 # 0 +0x906D 0x6057 # 0 +0x906E 0x6058 # 0 +0x906F 0x605B # 0 +0x9070 0x605C # 0 +0x9071 0x605E # 0 +0x9072 0x605F # 0 +0x9073 0x6060 # 0 +0x9074 0x6061 # 0 +0x9075 0x6065 # 0 +0x9076 0x6066 # 0 +0x9077 0x606E # 0 +0x9078 0x6071 # 0 +0x9079 0x6072 # 0 +0x907A 0x6074 # 0 +0x907B 0x6075 # 0 +0x907C 0x6077 # 0 +0x907D 0x607E # 0 +0x907E 0x6080 # 0 +0x9080 0x6081 # 0 +0x9081 0x6082 # 0 +0x9082 0x6085 # 0 +0x9083 0x6086 # 0 +0x9084 0x6087 # 0 +0x9085 0x6088 # 0 +0x9086 0x608A # 0 +0x9087 0x608B # 0 +0x9088 0x608E # 0 +0x9089 0x608F # 0 +0x908A 0x6090 # 0 +0x908B 0x6091 # 0 +0x908C 0x6093 # 0 +0x908D 0x6095 # 0 +0x908E 0x6097 # 0 +0x908F 0x6098 # 0 +0x9090 0x6099 # 0 +0x9091 0x609C # 0 +0x9092 0x609E # 0 +0x9093 0x60A1 # 0 +0x9094 0x60A2 # 0 +0x9095 0x60A4 # 0 +0x9096 0x60A5 # 0 +0x9097 0x60A7 # 0 +0x9098 0x60A9 # 0 +0x9099 0x60AA # 0 +0x909A 0x60AE # 0 +0x909B 0x60B0 # 0 +0x909C 0x60B3 # 0 +0x909D 0x60B5 # 0 +0x909E 0x60B6 # 0 +0x909F 0x60B7 # 0 +0x90A0 0x60B9 # 0 +0x90A1 0x60BA # 0 +0x90A2 0x60BD # 0 +0x90A3 0x60BE # 0 +0x90A4 0x60BF # 0 +0x90A5 0x60C0 # 0 +0x90A6 0x60C1 # 0 +0x90A7 0x60C2 # 0 +0x90A8 0x60C3 # 0 +0x90A9 0x60C4 # 0 +0x90AA 0x60C7 # 0 +0x90AB 0x60C8 # 0 +0x90AC 0x60C9 # 0 +0x90AD 0x60CC # 0 +0x90AE 0x60CD # 0 +0x90AF 0x60CE # 0 +0x90B0 0x60CF # 0 +0x90B1 0x60D0 # 0 +0x90B2 0x60D2 # 0 +0x90B3 0x60D3 # 0 +0x90B4 0x60D4 # 0 +0x90B5 0x60D6 # 0 +0x90B6 0x60D7 # 0 +0x90B7 0x60D9 # 0 +0x90B8 0x60DB # 0 +0x90B9 0x60DE # 0 +0x90BA 0x60E1 # 0 +0x90BB 0x60E2 # 0 +0x90BC 0x60E3 # 0 +0x90BD 0x60E4 # 0 +0x90BE 0x60E5 # 0 +0x90BF 0x60EA # 0 +0x90C0 0x60F1 # 0 +0x90C1 0x60F2 # 0 +0x90C2 0x60F5 # 0 +0x90C3 0x60F7 # 0 +0x90C4 0x60F8 # 0 +0x90C5 0x60FB # 0 +0x90C6 0x60FC # 0 +0x90C7 0x60FD # 0 +0x90C8 0x60FE # 0 +0x90C9 0x60FF # 0 +0x90CA 0x6102 # 0 +0x90CB 0x6103 # 0 +0x90CC 0x6104 # 0 +0x90CD 0x6105 # 0 +0x90CE 0x6107 # 0 +0x90CF 0x610A # 0 +0x90D0 0x610B # 0 +0x90D1 0x610C # 0 +0x90D2 0x6110 # 0 +0x90D3 0x6111 # 0 +0x90D4 0x6112 # 0 +0x90D5 0x6113 # 0 +0x90D6 0x6114 # 0 +0x90D7 0x6116 # 0 +0x90D8 0x6117 # 0 +0x90D9 0x6118 # 0 +0x90DA 0x6119 # 0 +0x90DB 0x611B # 0 +0x90DC 0x611C # 0 +0x90DD 0x611D # 0 +0x90DE 0x611E # 0 +0x90DF 0x6121 # 0 +0x90E0 0x6122 # 0 +0x90E1 0x6125 # 0 +0x90E2 0x6128 # 0 +0x90E3 0x6129 # 0 +0x90E4 0x612A # 0 +0x90E5 0x612C # 0 +0x90E6 0x612D # 0 +0x90E7 0x612E # 0 +0x90E8 0x612F # 0 +0x90E9 0x6130 # 0 +0x90EA 0x6131 # 0 +0x90EB 0x6132 # 0 +0x90EC 0x6133 # 0 +0x90ED 0x6134 # 0 +0x90EE 0x6135 # 0 +0x90EF 0x6136 # 0 +0x90F0 0x6137 # 0 +0x90F1 0x6138 # 0 +0x90F2 0x6139 # 0 +0x90F3 0x613A # 0 +0x90F4 0x613B # 0 +0x90F5 0x613C # 0 +0x90F6 0x613D # 0 +0x90F7 0x613E # 0 +0x90F8 0x6140 # 0 +0x90F9 0x6141 # 0 +0x90FA 0x6142 # 0 +0x90FB 0x6143 # 0 +0x90FC 0x6144 # 0 +0x90FD 0x6145 # 0 +0x90FE 0x6146 # 0 +0x9140 0x6147 # 0 +0x9141 0x6149 # 0 +0x9142 0x614B # 0 +0x9143 0x614D # 0 +0x9144 0x614F # 0 +0x9145 0x6150 # 0 +0x9146 0x6152 # 0 +0x9147 0x6153 # 0 +0x9148 0x6154 # 0 +0x9149 0x6156 # 0 +0x914A 0x6157 # 0 +0x914B 0x6158 # 0 +0x914C 0x6159 # 0 +0x914D 0x615A # 0 +0x914E 0x615B # 0 +0x914F 0x615C # 0 +0x9150 0x615E # 0 +0x9151 0x615F # 0 +0x9152 0x6160 # 0 +0x9153 0x6161 # 0 +0x9154 0x6163 # 0 +0x9155 0x6164 # 0 +0x9156 0x6165 # 0 +0x9157 0x6166 # 0 +0x9158 0x6169 # 0 +0x9159 0x616A # 0 +0x915A 0x616B # 0 +0x915B 0x616C # 0 +0x915C 0x616D # 0 +0x915D 0x616E # 0 +0x915E 0x616F # 0 +0x915F 0x6171 # 0 +0x9160 0x6172 # 0 +0x9161 0x6173 # 0 +0x9162 0x6174 # 0 +0x9163 0x6176 # 0 +0x9164 0x6178 # 0 +0x9165 0x6179 # 0 +0x9166 0x617A # 0 +0x9167 0x617B # 0 +0x9168 0x617C # 0 +0x9169 0x617D # 0 +0x916A 0x617E # 0 +0x916B 0x617F # 0 +0x916C 0x6180 # 0 +0x916D 0x6181 # 0 +0x916E 0x6182 # 0 +0x916F 0x6183 # 0 +0x9170 0x6184 # 0 +0x9171 0x6185 # 0 +0x9172 0x6186 # 0 +0x9173 0x6187 # 0 +0x9174 0x6188 # 0 +0x9175 0x6189 # 0 +0x9176 0x618A # 0 +0x9177 0x618C # 0 +0x9178 0x618D # 0 +0x9179 0x618F # 0 +0x917A 0x6190 # 0 +0x917B 0x6191 # 0 +0x917C 0x6192 # 0 +0x917D 0x6193 # 0 +0x917E 0x6195 # 0 +0x9180 0x6196 # 0 +0x9181 0x6197 # 0 +0x9182 0x6198 # 0 +0x9183 0x6199 # 0 +0x9184 0x619A # 0 +0x9185 0x619B # 0 +0x9186 0x619C # 0 +0x9187 0x619E # 0 +0x9188 0x619F # 0 +0x9189 0x61A0 # 0 +0x918A 0x61A1 # 0 +0x918B 0x61A2 # 0 +0x918C 0x61A3 # 0 +0x918D 0x61A4 # 0 +0x918E 0x61A5 # 0 +0x918F 0x61A6 # 0 +0x9190 0x61AA # 0 +0x9191 0x61AB # 0 +0x9192 0x61AD # 0 +0x9193 0x61AE # 0 +0x9194 0x61AF # 0 +0x9195 0x61B0 # 0 +0x9196 0x61B1 # 0 +0x9197 0x61B2 # 0 +0x9198 0x61B3 # 0 +0x9199 0x61B4 # 0 +0x919A 0x61B5 # 0 +0x919B 0x61B6 # 0 +0x919C 0x61B8 # 0 +0x919D 0x61B9 # 0 +0x919E 0x61BA # 0 +0x919F 0x61BB # 0 +0x91A0 0x61BC # 0 +0x91A1 0x61BD # 0 +0x91A2 0x61BF # 0 +0x91A3 0x61C0 # 0 +0x91A4 0x61C1 # 0 +0x91A5 0x61C3 # 0 +0x91A6 0x61C4 # 0 +0x91A7 0x61C5 # 0 +0x91A8 0x61C6 # 0 +0x91A9 0x61C7 # 0 +0x91AA 0x61C9 # 0 +0x91AB 0x61CC # 0 +0x91AC 0x61CD # 0 +0x91AD 0x61CE # 0 +0x91AE 0x61CF # 0 +0x91AF 0x61D0 # 0 +0x91B0 0x61D3 # 0 +0x91B1 0x61D5 # 0 +0x91B2 0x61D6 # 0 +0x91B3 0x61D7 # 0 +0x91B4 0x61D8 # 0 +0x91B5 0x61D9 # 0 +0x91B6 0x61DA # 0 +0x91B7 0x61DB # 0 +0x91B8 0x61DC # 0 +0x91B9 0x61DD # 0 +0x91BA 0x61DE # 0 +0x91BB 0x61DF # 0 +0x91BC 0x61E0 # 0 +0x91BD 0x61E1 # 0 +0x91BE 0x61E2 # 0 +0x91BF 0x61E3 # 0 +0x91C0 0x61E4 # 0 +0x91C1 0x61E5 # 0 +0x91C2 0x61E7 # 0 +0x91C3 0x61E8 # 0 +0x91C4 0x61E9 # 0 +0x91C5 0x61EA # 0 +0x91C6 0x61EB # 0 +0x91C7 0x61EC # 0 +0x91C8 0x61ED # 0 +0x91C9 0x61EE # 0 +0x91CA 0x61EF # 0 +0x91CB 0x61F0 # 0 +0x91CC 0x61F1 # 0 +0x91CD 0x61F2 # 0 +0x91CE 0x61F3 # 0 +0x91CF 0x61F4 # 0 +0x91D0 0x61F6 # 0 +0x91D1 0x61F7 # 0 +0x91D2 0x61F8 # 0 +0x91D3 0x61F9 # 0 +0x91D4 0x61FA # 0 +0x91D5 0x61FB # 0 +0x91D6 0x61FC # 0 +0x91D7 0x61FD # 0 +0x91D8 0x61FE # 0 +0x91D9 0x6200 # 0 +0x91DA 0x6201 # 0 +0x91DB 0x6202 # 0 +0x91DC 0x6203 # 0 +0x91DD 0x6204 # 0 +0x91DE 0x6205 # 0 +0x91DF 0x6207 # 0 +0x91E0 0x6209 # 0 +0x91E1 0x6213 # 0 +0x91E2 0x6214 # 0 +0x91E3 0x6219 # 0 +0x91E4 0x621C # 0 +0x91E5 0x621D # 0 +0x91E6 0x621E # 0 +0x91E7 0x6220 # 0 +0x91E8 0x6223 # 0 +0x91E9 0x6226 # 0 +0x91EA 0x6227 # 0 +0x91EB 0x6228 # 0 +0x91EC 0x6229 # 0 +0x91ED 0x622B # 0 +0x91EE 0x622D # 0 +0x91EF 0x622F # 0 +0x91F0 0x6230 # 0 +0x91F1 0x6231 # 0 +0x91F2 0x6232 # 0 +0x91F3 0x6235 # 0 +0x91F4 0x6236 # 0 +0x91F5 0x6238 # 0 +0x91F6 0x6239 # 0 +0x91F7 0x623A # 0 +0x91F8 0x623B # 0 +0x91F9 0x623C # 0 +0x91FA 0x6242 # 0 +0x91FB 0x6244 # 0 +0x91FC 0x6245 # 0 +0x91FD 0x6246 # 0 +0x91FE 0x624A # 0 +0x9240 0x624F # 0 +0x9241 0x6250 # 0 +0x9242 0x6255 # 0 +0x9243 0x6256 # 0 +0x9244 0x6257 # 0 +0x9245 0x6259 # 0 +0x9246 0x625A # 0 +0x9247 0x625C # 0 +0x9248 0x625D # 0 +0x9249 0x625E # 0 +0x924A 0x625F # 0 +0x924B 0x6260 # 0 +0x924C 0x6261 # 0 +0x924D 0x6262 # 0 +0x924E 0x6264 # 0 +0x924F 0x6265 # 0 +0x9250 0x6268 # 0 +0x9251 0x6271 # 0 +0x9252 0x6272 # 0 +0x9253 0x6274 # 0 +0x9254 0x6275 # 0 +0x9255 0x6277 # 0 +0x9256 0x6278 # 0 +0x9257 0x627A # 0 +0x9258 0x627B # 0 +0x9259 0x627D # 0 +0x925A 0x6281 # 0 +0x925B 0x6282 # 0 +0x925C 0x6283 # 0 +0x925D 0x6285 # 0 +0x925E 0x6286 # 0 +0x925F 0x6287 # 0 +0x9260 0x6288 # 0 +0x9261 0x628B # 0 +0x9262 0x628C # 0 +0x9263 0x628D # 0 +0x9264 0x628E # 0 +0x9265 0x628F # 0 +0x9266 0x6290 # 0 +0x9267 0x6294 # 0 +0x9268 0x6299 # 0 +0x9269 0x629C # 0 +0x926A 0x629D # 0 +0x926B 0x629E # 0 +0x926C 0x62A3 # 0 +0x926D 0x62A6 # 0 +0x926E 0x62A7 # 0 +0x926F 0x62A9 # 0 +0x9270 0x62AA # 0 +0x9271 0x62AD # 0 +0x9272 0x62AE # 0 +0x9273 0x62AF # 0 +0x9274 0x62B0 # 0 +0x9275 0x62B2 # 0 +0x9276 0x62B3 # 0 +0x9277 0x62B4 # 0 +0x9278 0x62B6 # 0 +0x9279 0x62B7 # 0 +0x927A 0x62B8 # 0 +0x927B 0x62BA # 0 +0x927C 0x62BE # 0 +0x927D 0x62C0 # 0 +0x927E 0x62C1 # 0 +0x9280 0x62C3 # 0 +0x9281 0x62CB # 0 +0x9282 0x62CF # 0 +0x9283 0x62D1 # 0 +0x9284 0x62D5 # 0 +0x9285 0x62DD # 0 +0x9286 0x62DE # 0 +0x9287 0x62E0 # 0 +0x9288 0x62E1 # 0 +0x9289 0x62E4 # 0 +0x928A 0x62EA # 0 +0x928B 0x62EB # 0 +0x928C 0x62F0 # 0 +0x928D 0x62F2 # 0 +0x928E 0x62F5 # 0 +0x928F 0x62F8 # 0 +0x9290 0x62F9 # 0 +0x9291 0x62FA # 0 +0x9292 0x62FB # 0 +0x9293 0x6300 # 0 +0x9294 0x6303 # 0 +0x9295 0x6304 # 0 +0x9296 0x6305 # 0 +0x9297 0x6306 # 0 +0x9298 0x630A # 0 +0x9299 0x630B # 0 +0x929A 0x630C # 0 +0x929B 0x630D # 0 +0x929C 0x630F # 0 +0x929D 0x6310 # 0 +0x929E 0x6312 # 0 +0x929F 0x6313 # 0 +0x92A0 0x6314 # 0 +0x92A1 0x6315 # 0 +0x92A2 0x6317 # 0 +0x92A3 0x6318 # 0 +0x92A4 0x6319 # 0 +0x92A5 0x631C # 0 +0x92A6 0x6326 # 0 +0x92A7 0x6327 # 0 +0x92A8 0x6329 # 0 +0x92A9 0x632C # 0 +0x92AA 0x632D # 0 +0x92AB 0x632E # 0 +0x92AC 0x6330 # 0 +0x92AD 0x6331 # 0 +0x92AE 0x6333 # 0 +0x92AF 0x6334 # 0 +0x92B0 0x6335 # 0 +0x92B1 0x6336 # 0 +0x92B2 0x6337 # 0 +0x92B3 0x6338 # 0 +0x92B4 0x633B # 0 +0x92B5 0x633C # 0 +0x92B6 0x633E # 0 +0x92B7 0x633F # 0 +0x92B8 0x6340 # 0 +0x92B9 0x6341 # 0 +0x92BA 0x6344 # 0 +0x92BB 0x6347 # 0 +0x92BC 0x6348 # 0 +0x92BD 0x634A # 0 +0x92BE 0x6351 # 0 +0x92BF 0x6352 # 0 +0x92C0 0x6353 # 0 +0x92C1 0x6354 # 0 +0x92C2 0x6356 # 0 +0x92C3 0x6357 # 0 +0x92C4 0x6358 # 0 +0x92C5 0x6359 # 0 +0x92C6 0x635A # 0 +0x92C7 0x635B # 0 +0x92C8 0x635C # 0 +0x92C9 0x635D # 0 +0x92CA 0x6360 # 0 +0x92CB 0x6364 # 0 +0x92CC 0x6365 # 0 +0x92CD 0x6366 # 0 +0x92CE 0x6368 # 0 +0x92CF 0x636A # 0 +0x92D0 0x636B # 0 +0x92D1 0x636C # 0 +0x92D2 0x636F # 0 +0x92D3 0x6370 # 0 +0x92D4 0x6372 # 0 +0x92D5 0x6373 # 0 +0x92D6 0x6374 # 0 +0x92D7 0x6375 # 0 +0x92D8 0x6378 # 0 +0x92D9 0x6379 # 0 +0x92DA 0x637C # 0 +0x92DB 0x637D # 0 +0x92DC 0x637E # 0 +0x92DD 0x637F # 0 +0x92DE 0x6381 # 0 +0x92DF 0x6383 # 0 +0x92E0 0x6384 # 0 +0x92E1 0x6385 # 0 +0x92E2 0x6386 # 0 +0x92E3 0x638B # 0 +0x92E4 0x638D # 0 +0x92E5 0x6391 # 0 +0x92E6 0x6393 # 0 +0x92E7 0x6394 # 0 +0x92E8 0x6395 # 0 +0x92E9 0x6397 # 0 +0x92EA 0x6399 # 0 +0x92EB 0x639A # 0 +0x92EC 0x639B # 0 +0x92ED 0x639C # 0 +0x92EE 0x639D # 0 +0x92EF 0x639E # 0 +0x92F0 0x639F # 0 +0x92F1 0x63A1 # 0 +0x92F2 0x63A4 # 0 +0x92F3 0x63A6 # 0 +0x92F4 0x63AB # 0 +0x92F5 0x63AF # 0 +0x92F6 0x63B1 # 0 +0x92F7 0x63B2 # 0 +0x92F8 0x63B5 # 0 +0x92F9 0x63B6 # 0 +0x92FA 0x63B9 # 0 +0x92FB 0x63BB # 0 +0x92FC 0x63BD # 0 +0x92FD 0x63BF # 0 +0x92FE 0x63C0 # 0 +0x9340 0x63C1 # 0 +0x9341 0x63C2 # 0 +0x9342 0x63C3 # 0 +0x9343 0x63C5 # 0 +0x9344 0x63C7 # 0 +0x9345 0x63C8 # 0 +0x9346 0x63CA # 0 +0x9347 0x63CB # 0 +0x9348 0x63CC # 0 +0x9349 0x63D1 # 0 +0x934A 0x63D3 # 0 +0x934B 0x63D4 # 0 +0x934C 0x63D5 # 0 +0x934D 0x63D7 # 0 +0x934E 0x63D8 # 0 +0x934F 0x63D9 # 0 +0x9350 0x63DA # 0 +0x9351 0x63DB # 0 +0x9352 0x63DC # 0 +0x9353 0x63DD # 0 +0x9354 0x63DF # 0 +0x9355 0x63E2 # 0 +0x9356 0x63E4 # 0 +0x9357 0x63E5 # 0 +0x9358 0x63E6 # 0 +0x9359 0x63E7 # 0 +0x935A 0x63E8 # 0 +0x935B 0x63EB # 0 +0x935C 0x63EC # 0 +0x935D 0x63EE # 0 +0x935E 0x63EF # 0 +0x935F 0x63F0 # 0 +0x9360 0x63F1 # 0 +0x9361 0x63F3 # 0 +0x9362 0x63F5 # 0 +0x9363 0x63F7 # 0 +0x9364 0x63F9 # 0 +0x9365 0x63FA # 0 +0x9366 0x63FB # 0 +0x9367 0x63FC # 0 +0x9368 0x63FE # 0 +0x9369 0x6403 # 0 +0x936A 0x6404 # 0 +0x936B 0x6406 # 0 +0x936C 0x6407 # 0 +0x936D 0x6408 # 0 +0x936E 0x6409 # 0 +0x936F 0x640A # 0 +0x9370 0x640D # 0 +0x9371 0x640E # 0 +0x9372 0x6411 # 0 +0x9373 0x6412 # 0 +0x9374 0x6415 # 0 +0x9375 0x6416 # 0 +0x9376 0x6417 # 0 +0x9377 0x6418 # 0 +0x9378 0x6419 # 0 +0x9379 0x641A # 0 +0x937A 0x641D # 0 +0x937B 0x641F # 0 +0x937C 0x6422 # 0 +0x937D 0x6423 # 0 +0x937E 0x6424 # 0 +0x9380 0x6425 # 0 +0x9381 0x6427 # 0 +0x9382 0x6428 # 0 +0x9383 0x6429 # 0 +0x9384 0x642B # 0 +0x9385 0x642E # 0 +0x9386 0x642F # 0 +0x9387 0x6430 # 0 +0x9388 0x6431 # 0 +0x9389 0x6432 # 0 +0x938A 0x6433 # 0 +0x938B 0x6435 # 0 +0x938C 0x6436 # 0 +0x938D 0x6437 # 0 +0x938E 0x6438 # 0 +0x938F 0x6439 # 0 +0x9390 0x643B # 0 +0x9391 0x643C # 0 +0x9392 0x643E # 0 +0x9393 0x6440 # 0 +0x9394 0x6442 # 0 +0x9395 0x6443 # 0 +0x9396 0x6449 # 0 +0x9397 0x644B # 0 +0x9398 0x644C # 0 +0x9399 0x644D # 0 +0x939A 0x644E # 0 +0x939B 0x644F # 0 +0x939C 0x6450 # 0 +0x939D 0x6451 # 0 +0x939E 0x6453 # 0 +0x939F 0x6455 # 0 +0x93A0 0x6456 # 0 +0x93A1 0x6457 # 0 +0x93A2 0x6459 # 0 +0x93A3 0x645A # 0 +0x93A4 0x645B # 0 +0x93A5 0x645C # 0 +0x93A6 0x645D # 0 +0x93A7 0x645F # 0 +0x93A8 0x6460 # 0 +0x93A9 0x6461 # 0 +0x93AA 0x6462 # 0 +0x93AB 0x6463 # 0 +0x93AC 0x6464 # 0 +0x93AD 0x6465 # 0 +0x93AE 0x6466 # 0 +0x93AF 0x6468 # 0 +0x93B0 0x646A # 0 +0x93B1 0x646B # 0 +0x93B2 0x646C # 0 +0x93B3 0x646E # 0 +0x93B4 0x646F # 0 +0x93B5 0x6470 # 0 +0x93B6 0x6471 # 0 +0x93B7 0x6472 # 0 +0x93B8 0x6473 # 0 +0x93B9 0x6474 # 0 +0x93BA 0x6475 # 0 +0x93BB 0x6476 # 0 +0x93BC 0x6477 # 0 +0x93BD 0x647B # 0 +0x93BE 0x647C # 0 +0x93BF 0x647D # 0 +0x93C0 0x647E # 0 +0x93C1 0x647F # 0 +0x93C2 0x6480 # 0 +0x93C3 0x6481 # 0 +0x93C4 0x6483 # 0 +0x93C5 0x6486 # 0 +0x93C6 0x6488 # 0 +0x93C7 0x6489 # 0 +0x93C8 0x648A # 0 +0x93C9 0x648B # 0 +0x93CA 0x648C # 0 +0x93CB 0x648D # 0 +0x93CC 0x648E # 0 +0x93CD 0x648F # 0 +0x93CE 0x6490 # 0 +0x93CF 0x6493 # 0 +0x93D0 0x6494 # 0 +0x93D1 0x6497 # 0 +0x93D2 0x6498 # 0 +0x93D3 0x649A # 0 +0x93D4 0x649B # 0 +0x93D5 0x649C # 0 +0x93D6 0x649D # 0 +0x93D7 0x649F # 0 +0x93D8 0x64A0 # 0 +0x93D9 0x64A1 # 0 +0x93DA 0x64A2 # 0 +0x93DB 0x64A3 # 0 +0x93DC 0x64A5 # 0 +0x93DD 0x64A6 # 0 +0x93DE 0x64A7 # 0 +0x93DF 0x64A8 # 0 +0x93E0 0x64AA # 0 +0x93E1 0x64AB # 0 +0x93E2 0x64AF # 0 +0x93E3 0x64B1 # 0 +0x93E4 0x64B2 # 0 +0x93E5 0x64B3 # 0 +0x93E6 0x64B4 # 0 +0x93E7 0x64B6 # 0 +0x93E8 0x64B9 # 0 +0x93E9 0x64BB # 0 +0x93EA 0x64BD # 0 +0x93EB 0x64BE # 0 +0x93EC 0x64BF # 0 +0x93ED 0x64C1 # 0 +0x93EE 0x64C3 # 0 +0x93EF 0x64C4 # 0 +0x93F0 0x64C6 # 0 +0x93F1 0x64C7 # 0 +0x93F2 0x64C8 # 0 +0x93F3 0x64C9 # 0 +0x93F4 0x64CA # 0 +0x93F5 0x64CB # 0 +0x93F6 0x64CC # 0 +0x93F7 0x64CF # 0 +0x93F8 0x64D1 # 0 +0x93F9 0x64D3 # 0 +0x93FA 0x64D4 # 0 +0x93FB 0x64D5 # 0 +0x93FC 0x64D6 # 0 +0x93FD 0x64D9 # 0 +0x93FE 0x64DA # 0 +0x9440 0x64DB # 0 +0x9441 0x64DC # 0 +0x9442 0x64DD # 0 +0x9443 0x64DF # 0 +0x9444 0x64E0 # 0 +0x9445 0x64E1 # 0 +0x9446 0x64E3 # 0 +0x9447 0x64E5 # 0 +0x9448 0x64E7 # 0 +0x9449 0x64E8 # 0 +0x944A 0x64E9 # 0 +0x944B 0x64EA # 0 +0x944C 0x64EB # 0 +0x944D 0x64EC # 0 +0x944E 0x64ED # 0 +0x944F 0x64EE # 0 +0x9450 0x64EF # 0 +0x9451 0x64F0 # 0 +0x9452 0x64F1 # 0 +0x9453 0x64F2 # 0 +0x9454 0x64F3 # 0 +0x9455 0x64F4 # 0 +0x9456 0x64F5 # 0 +0x9457 0x64F6 # 0 +0x9458 0x64F7 # 0 +0x9459 0x64F8 # 0 +0x945A 0x64F9 # 0 +0x945B 0x64FA # 0 +0x945C 0x64FB # 0 +0x945D 0x64FC # 0 +0x945E 0x64FD # 0 +0x945F 0x64FE # 0 +0x9460 0x64FF # 0 +0x9461 0x6501 # 0 +0x9462 0x6502 # 0 +0x9463 0x6503 # 0 +0x9464 0x6504 # 0 +0x9465 0x6505 # 0 +0x9466 0x6506 # 0 +0x9467 0x6507 # 0 +0x9468 0x6508 # 0 +0x9469 0x650A # 0 +0x946A 0x650B # 0 +0x946B 0x650C # 0 +0x946C 0x650D # 0 +0x946D 0x650E # 0 +0x946E 0x650F # 0 +0x946F 0x6510 # 0 +0x9470 0x6511 # 0 +0x9471 0x6513 # 0 +0x9472 0x6514 # 0 +0x9473 0x6515 # 0 +0x9474 0x6516 # 0 +0x9475 0x6517 # 0 +0x9476 0x6519 # 0 +0x9477 0x651A # 0 +0x9478 0x651B # 0 +0x9479 0x651C # 0 +0x947A 0x651D # 0 +0x947B 0x651E # 0 +0x947C 0x651F # 0 +0x947D 0x6520 # 0 +0x947E 0x6521 # 0 +0x9480 0x6522 # 0 +0x9481 0x6523 # 0 +0x9482 0x6524 # 0 +0x9483 0x6526 # 0 +0x9484 0x6527 # 0 +0x9485 0x6528 # 0 +0x9486 0x6529 # 0 +0x9487 0x652A # 0 +0x9488 0x652C # 0 +0x9489 0x652D # 0 +0x948A 0x6530 # 0 +0x948B 0x6531 # 0 +0x948C 0x6532 # 0 +0x948D 0x6533 # 0 +0x948E 0x6537 # 0 +0x948F 0x653A # 0 +0x9490 0x653C # 0 +0x9491 0x653D # 0 +0x9492 0x6540 # 0 +0x9493 0x6541 # 0 +0x9494 0x6542 # 0 +0x9495 0x6543 # 0 +0x9496 0x6544 # 0 +0x9497 0x6546 # 0 +0x9498 0x6547 # 0 +0x9499 0x654A # 0 +0x949A 0x654B # 0 +0x949B 0x654D # 0 +0x949C 0x654E # 0 +0x949D 0x6550 # 0 +0x949E 0x6552 # 0 +0x949F 0x6553 # 0 +0x94A0 0x6554 # 0 +0x94A1 0x6557 # 0 +0x94A2 0x6558 # 0 +0x94A3 0x655A # 0 +0x94A4 0x655C # 0 +0x94A5 0x655F # 0 +0x94A6 0x6560 # 0 +0x94A7 0x6561 # 0 +0x94A8 0x6564 # 0 +0x94A9 0x6565 # 0 +0x94AA 0x6567 # 0 +0x94AB 0x6568 # 0 +0x94AC 0x6569 # 0 +0x94AD 0x656A # 0 +0x94AE 0x656D # 0 +0x94AF 0x656E # 0 +0x94B0 0x656F # 0 +0x94B1 0x6571 # 0 +0x94B2 0x6573 # 0 +0x94B3 0x6575 # 0 +0x94B4 0x6576 # 0 +0x94B5 0x6578 # 0 +0x94B6 0x6579 # 0 +0x94B7 0x657A # 0 +0x94B8 0x657B # 0 +0x94B9 0x657C # 0 +0x94BA 0x657D # 0 +0x94BB 0x657E # 0 +0x94BC 0x657F # 0 +0x94BD 0x6580 # 0 +0x94BE 0x6581 # 0 +0x94BF 0x6582 # 0 +0x94C0 0x6583 # 0 +0x94C1 0x6584 # 0 +0x94C2 0x6585 # 0 +0x94C3 0x6586 # 0 +0x94C4 0x6588 # 0 +0x94C5 0x6589 # 0 +0x94C6 0x658A # 0 +0x94C7 0x658D # 0 +0x94C8 0x658E # 0 +0x94C9 0x658F # 0 +0x94CA 0x6592 # 0 +0x94CB 0x6594 # 0 +0x94CC 0x6595 # 0 +0x94CD 0x6596 # 0 +0x94CE 0x6598 # 0 +0x94CF 0x659A # 0 +0x94D0 0x659D # 0 +0x94D1 0x659E # 0 +0x94D2 0x65A0 # 0 +0x94D3 0x65A2 # 0 +0x94D4 0x65A3 # 0 +0x94D5 0x65A6 # 0 +0x94D6 0x65A8 # 0 +0x94D7 0x65AA # 0 +0x94D8 0x65AC # 0 +0x94D9 0x65AE # 0 +0x94DA 0x65B1 # 0 +0x94DB 0x65B2 # 0 +0x94DC 0x65B3 # 0 +0x94DD 0x65B4 # 0 +0x94DE 0x65B5 # 0 +0x94DF 0x65B6 # 0 +0x94E0 0x65B7 # 0 +0x94E1 0x65B8 # 0 +0x94E2 0x65BA # 0 +0x94E3 0x65BB # 0 +0x94E4 0x65BE # 0 +0x94E5 0x65BF # 0 +0x94E6 0x65C0 # 0 +0x94E7 0x65C2 # 0 +0x94E8 0x65C7 # 0 +0x94E9 0x65C8 # 0 +0x94EA 0x65C9 # 0 +0x94EB 0x65CA # 0 +0x94EC 0x65CD # 0 +0x94ED 0x65D0 # 0 +0x94EE 0x65D1 # 0 +0x94EF 0x65D3 # 0 +0x94F0 0x65D4 # 0 +0x94F1 0x65D5 # 0 +0x94F2 0x65D8 # 0 +0x94F3 0x65D9 # 0 +0x94F4 0x65DA # 0 +0x94F5 0x65DB # 0 +0x94F6 0x65DC # 0 +0x94F7 0x65DD # 0 +0x94F8 0x65DE # 0 +0x94F9 0x65DF # 0 +0x94FA 0x65E1 # 0 +0x94FB 0x65E3 # 0 +0x94FC 0x65E4 # 0 +0x94FD 0x65EA # 0 +0x94FE 0x65EB # 0 +0x9540 0x65F2 # 0 +0x9541 0x65F3 # 0 +0x9542 0x65F4 # 0 +0x9543 0x65F5 # 0 +0x9544 0x65F8 # 0 +0x9545 0x65F9 # 0 +0x9546 0x65FB # 0 +0x9547 0x65FC # 0 +0x9548 0x65FD # 0 +0x9549 0x65FE # 0 +0x954A 0x65FF # 0 +0x954B 0x6601 # 0 +0x954C 0x6604 # 0 +0x954D 0x6605 # 0 +0x954E 0x6607 # 0 +0x954F 0x6608 # 0 +0x9550 0x6609 # 0 +0x9551 0x660B # 0 +0x9552 0x660D # 0 +0x9553 0x6610 # 0 +0x9554 0x6611 # 0 +0x9555 0x6612 # 0 +0x9556 0x6616 # 0 +0x9557 0x6617 # 0 +0x9558 0x6618 # 0 +0x9559 0x661A # 0 +0x955A 0x661B # 0 +0x955B 0x661C # 0 +0x955C 0x661E # 0 +0x955D 0x6621 # 0 +0x955E 0x6622 # 0 +0x955F 0x6623 # 0 +0x9560 0x6624 # 0 +0x9561 0x6626 # 0 +0x9562 0x6629 # 0 +0x9563 0x662A # 0 +0x9564 0x662B # 0 +0x9565 0x662C # 0 +0x9566 0x662E # 0 +0x9567 0x6630 # 0 +0x9568 0x6632 # 0 +0x9569 0x6633 # 0 +0x956A 0x6637 # 0 +0x956B 0x6638 # 0 +0x956C 0x6639 # 0 +0x956D 0x663A # 0 +0x956E 0x663B # 0 +0x956F 0x663D # 0 +0x9570 0x663F # 0 +0x9571 0x6640 # 0 +0x9572 0x6642 # 0 +0x9573 0x6644 # 0 +0x9574 0x6645 # 0 +0x9575 0x6646 # 0 +0x9576 0x6647 # 0 +0x9577 0x6648 # 0 +0x9578 0x6649 # 0 +0x9579 0x664A # 0 +0x957A 0x664D # 0 +0x957B 0x664E # 0 +0x957C 0x6650 # 0 +0x957D 0x6651 # 0 +0x957E 0x6658 # 0 +0x9580 0x6659 # 0 +0x9581 0x665B # 0 +0x9582 0x665C # 0 +0x9583 0x665D # 0 +0x9584 0x665E # 0 +0x9585 0x6660 # 0 +0x9586 0x6662 # 0 +0x9587 0x6663 # 0 +0x9588 0x6665 # 0 +0x9589 0x6667 # 0 +0x958A 0x6669 # 0 +0x958B 0x666A # 0 +0x958C 0x666B # 0 +0x958D 0x666C # 0 +0x958E 0x666D # 0 +0x958F 0x6671 # 0 +0x9590 0x6672 # 0 +0x9591 0x6673 # 0 +0x9592 0x6675 # 0 +0x9593 0x6678 # 0 +0x9594 0x6679 # 0 +0x9595 0x667B # 0 +0x9596 0x667C # 0 +0x9597 0x667D # 0 +0x9598 0x667F # 0 +0x9599 0x6680 # 0 +0x959A 0x6681 # 0 +0x959B 0x6683 # 0 +0x959C 0x6685 # 0 +0x959D 0x6686 # 0 +0x959E 0x6688 # 0 +0x959F 0x6689 # 0 +0x95A0 0x668A # 0 +0x95A1 0x668B # 0 +0x95A2 0x668D # 0 +0x95A3 0x668E # 0 +0x95A4 0x668F # 0 +0x95A5 0x6690 # 0 +0x95A6 0x6692 # 0 +0x95A7 0x6693 # 0 +0x95A8 0x6694 # 0 +0x95A9 0x6695 # 0 +0x95AA 0x6698 # 0 +0x95AB 0x6699 # 0 +0x95AC 0x669A # 0 +0x95AD 0x669B # 0 +0x95AE 0x669C # 0 +0x95AF 0x669E # 0 +0x95B0 0x669F # 0 +0x95B1 0x66A0 # 0 +0x95B2 0x66A1 # 0 +0x95B3 0x66A2 # 0 +0x95B4 0x66A3 # 0 +0x95B5 0x66A4 # 0 +0x95B6 0x66A5 # 0 +0x95B7 0x66A6 # 0 +0x95B8 0x66A9 # 0 +0x95B9 0x66AA # 0 +0x95BA 0x66AB # 0 +0x95BB 0x66AC # 0 +0x95BC 0x66AD # 0 +0x95BD 0x66AF # 0 +0x95BE 0x66B0 # 0 +0x95BF 0x66B1 # 0 +0x95C0 0x66B2 # 0 +0x95C1 0x66B3 # 0 +0x95C2 0x66B5 # 0 +0x95C3 0x66B6 # 0 +0x95C4 0x66B7 # 0 +0x95C5 0x66B8 # 0 +0x95C6 0x66BA # 0 +0x95C7 0x66BB # 0 +0x95C8 0x66BC # 0 +0x95C9 0x66BD # 0 +0x95CA 0x66BF # 0 +0x95CB 0x66C0 # 0 +0x95CC 0x66C1 # 0 +0x95CD 0x66C2 # 0 +0x95CE 0x66C3 # 0 +0x95CF 0x66C4 # 0 +0x95D0 0x66C5 # 0 +0x95D1 0x66C6 # 0 +0x95D2 0x66C7 # 0 +0x95D3 0x66C8 # 0 +0x95D4 0x66C9 # 0 +0x95D5 0x66CA # 0 +0x95D6 0x66CB # 0 +0x95D7 0x66CC # 0 +0x95D8 0x66CD # 0 +0x95D9 0x66CE # 0 +0x95DA 0x66CF # 0 +0x95DB 0x66D0 # 0 +0x95DC 0x66D1 # 0 +0x95DD 0x66D2 # 0 +0x95DE 0x66D3 # 0 +0x95DF 0x66D4 # 0 +0x95E0 0x66D5 # 0 +0x95E1 0x66D6 # 0 +0x95E2 0x66D7 # 0 +0x95E3 0x66D8 # 0 +0x95E4 0x66DA # 0 +0x95E5 0x66DE # 0 +0x95E6 0x66DF # 0 +0x95E7 0x66E0 # 0 +0x95E8 0x66E1 # 0 +0x95E9 0x66E2 # 0 +0x95EA 0x66E3 # 0 +0x95EB 0x66E4 # 0 +0x95EC 0x66E5 # 0 +0x95ED 0x66E7 # 0 +0x95EE 0x66E8 # 0 +0x95EF 0x66EA # 0 +0x95F0 0x66EB # 0 +0x95F1 0x66EC # 0 +0x95F2 0x66ED # 0 +0x95F3 0x66EE # 0 +0x95F4 0x66EF # 0 +0x95F5 0x66F1 # 0 +0x95F6 0x66F5 # 0 +0x95F7 0x66F6 # 0 +0x95F8 0x66F8 # 0 +0x95F9 0x66FA # 0 +0x95FA 0x66FB # 0 +0x95FB 0x66FD # 0 +0x95FC 0x6701 # 0 +0x95FD 0x6702 # 0 +0x95FE 0x6703 # 0 +0x9640 0x6704 # 0 +0x9641 0x6705 # 0 +0x9642 0x6706 # 0 +0x9643 0x6707 # 0 +0x9644 0x670C # 0 +0x9645 0x670E # 0 +0x9646 0x670F # 0 +0x9647 0x6711 # 0 +0x9648 0x6712 # 0 +0x9649 0x6713 # 0 +0x964A 0x6716 # 0 +0x964B 0x6718 # 0 +0x964C 0x6719 # 0 +0x964D 0x671A # 0 +0x964E 0x671C # 0 +0x964F 0x671E # 0 +0x9650 0x6720 # 0 +0x9651 0x6721 # 0 +0x9652 0x6722 # 0 +0x9653 0x6723 # 0 +0x9654 0x6724 # 0 +0x9655 0x6725 # 0 +0x9656 0x6727 # 0 +0x9657 0x6729 # 0 +0x9658 0x672E # 0 +0x9659 0x6730 # 0 +0x965A 0x6732 # 0 +0x965B 0x6733 # 0 +0x965C 0x6736 # 0 +0x965D 0x6737 # 0 +0x965E 0x6738 # 0 +0x965F 0x6739 # 0 +0x9660 0x673B # 0 +0x9661 0x673C # 0 +0x9662 0x673E # 0 +0x9663 0x673F # 0 +0x9664 0x6741 # 0 +0x9665 0x6744 # 0 +0x9666 0x6745 # 0 +0x9667 0x6747 # 0 +0x9668 0x674A # 0 +0x9669 0x674B # 0 +0x966A 0x674D # 0 +0x966B 0x6752 # 0 +0x966C 0x6754 # 0 +0x966D 0x6755 # 0 +0x966E 0x6757 # 0 +0x966F 0x6758 # 0 +0x9670 0x6759 # 0 +0x9671 0x675A # 0 +0x9672 0x675B # 0 +0x9673 0x675D # 0 +0x9674 0x6762 # 0 +0x9675 0x6763 # 0 +0x9676 0x6764 # 0 +0x9677 0x6766 # 0 +0x9678 0x6767 # 0 +0x9679 0x676B # 0 +0x967A 0x676C # 0 +0x967B 0x676E # 0 +0x967C 0x6771 # 0 +0x967D 0x6774 # 0 +0x967E 0x6776 # 0 +0x9680 0x6778 # 0 +0x9681 0x6779 # 0 +0x9682 0x677A # 0 +0x9683 0x677B # 0 +0x9684 0x677D # 0 +0x9685 0x6780 # 0 +0x9686 0x6782 # 0 +0x9687 0x6783 # 0 +0x9688 0x6785 # 0 +0x9689 0x6786 # 0 +0x968A 0x6788 # 0 +0x968B 0x678A # 0 +0x968C 0x678C # 0 +0x968D 0x678D # 0 +0x968E 0x678E # 0 +0x968F 0x678F # 0 +0x9690 0x6791 # 0 +0x9691 0x6792 # 0 +0x9692 0x6793 # 0 +0x9693 0x6794 # 0 +0x9694 0x6796 # 0 +0x9695 0x6799 # 0 +0x9696 0x679B # 0 +0x9697 0x679F # 0 +0x9698 0x67A0 # 0 +0x9699 0x67A1 # 0 +0x969A 0x67A4 # 0 +0x969B 0x67A6 # 0 +0x969C 0x67A9 # 0 +0x969D 0x67AC # 0 +0x969E 0x67AE # 0 +0x969F 0x67B1 # 0 +0x96A0 0x67B2 # 0 +0x96A1 0x67B4 # 0 +0x96A2 0x67B9 # 0 +0x96A3 0x67BA # 0 +0x96A4 0x67BB # 0 +0x96A5 0x67BC # 0 +0x96A6 0x67BD # 0 +0x96A7 0x67BE # 0 +0x96A8 0x67BF # 0 +0x96A9 0x67C0 # 0 +0x96AA 0x67C2 # 0 +0x96AB 0x67C5 # 0 +0x96AC 0x67C6 # 0 +0x96AD 0x67C7 # 0 +0x96AE 0x67C8 # 0 +0x96AF 0x67C9 # 0 +0x96B0 0x67CA # 0 +0x96B1 0x67CB # 0 +0x96B2 0x67CC # 0 +0x96B3 0x67CD # 0 +0x96B4 0x67CE # 0 +0x96B5 0x67D5 # 0 +0x96B6 0x67D6 # 0 +0x96B7 0x67D7 # 0 +0x96B8 0x67DB # 0 +0x96B9 0x67DF # 0 +0x96BA 0x67E1 # 0 +0x96BB 0x67E3 # 0 +0x96BC 0x67E4 # 0 +0x96BD 0x67E6 # 0 +0x96BE 0x67E7 # 0 +0x96BF 0x67E8 # 0 +0x96C0 0x67EA # 0 +0x96C1 0x67EB # 0 +0x96C2 0x67ED # 0 +0x96C3 0x67EE # 0 +0x96C4 0x67F2 # 0 +0x96C5 0x67F5 # 0 +0x96C6 0x67F6 # 0 +0x96C7 0x67F7 # 0 +0x96C8 0x67F8 # 0 +0x96C9 0x67F9 # 0 +0x96CA 0x67FA # 0 +0x96CB 0x67FB # 0 +0x96CC 0x67FC # 0 +0x96CD 0x67FE # 0 +0x96CE 0x6801 # 0 +0x96CF 0x6802 # 0 +0x96D0 0x6803 # 0 +0x96D1 0x6804 # 0 +0x96D2 0x6806 # 0 +0x96D3 0x680D # 0 +0x96D4 0x6810 # 0 +0x96D5 0x6812 # 0 +0x96D6 0x6814 # 0 +0x96D7 0x6815 # 0 +0x96D8 0x6818 # 0 +0x96D9 0x6819 # 0 +0x96DA 0x681A # 0 +0x96DB 0x681B # 0 +0x96DC 0x681C # 0 +0x96DD 0x681E # 0 +0x96DE 0x681F # 0 +0x96DF 0x6820 # 0 +0x96E0 0x6822 # 0 +0x96E1 0x6823 # 0 +0x96E2 0x6824 # 0 +0x96E3 0x6825 # 0 +0x96E4 0x6826 # 0 +0x96E5 0x6827 # 0 +0x96E6 0x6828 # 0 +0x96E7 0x682B # 0 +0x96E8 0x682C # 0 +0x96E9 0x682D # 0 +0x96EA 0x682E # 0 +0x96EB 0x682F # 0 +0x96EC 0x6830 # 0 +0x96ED 0x6831 # 0 +0x96EE 0x6834 # 0 +0x96EF 0x6835 # 0 +0x96F0 0x6836 # 0 +0x96F1 0x683A # 0 +0x96F2 0x683B # 0 +0x96F3 0x683F # 0 +0x96F4 0x6847 # 0 +0x96F5 0x684B # 0 +0x96F6 0x684D # 0 +0x96F7 0x684F # 0 +0x96F8 0x6852 # 0 +0x96F9 0x6856 # 0 +0x96FA 0x6857 # 0 +0x96FB 0x6858 # 0 +0x96FC 0x6859 # 0 +0x96FD 0x685A # 0 +0x96FE 0x685B # 0 +0x9740 0x685C # 0 +0x9741 0x685D # 0 +0x9742 0x685E # 0 +0x9743 0x685F # 0 +0x9744 0x686A # 0 +0x9745 0x686C # 0 +0x9746 0x686D # 0 +0x9747 0x686E # 0 +0x9748 0x686F # 0 +0x9749 0x6870 # 0 +0x974A 0x6871 # 0 +0x974B 0x6872 # 0 +0x974C 0x6873 # 0 +0x974D 0x6875 # 0 +0x974E 0x6878 # 0 +0x974F 0x6879 # 0 +0x9750 0x687A # 0 +0x9751 0x687B # 0 +0x9752 0x687C # 0 +0x9753 0x687D # 0 +0x9754 0x687E # 0 +0x9755 0x687F # 0 +0x9756 0x6880 # 0 +0x9757 0x6882 # 0 +0x9758 0x6884 # 0 +0x9759 0x6887 # 0 +0x975A 0x6888 # 0 +0x975B 0x6889 # 0 +0x975C 0x688A # 0 +0x975D 0x688B # 0 +0x975E 0x688C # 0 +0x975F 0x688D # 0 +0x9760 0x688E # 0 +0x9761 0x6890 # 0 +0x9762 0x6891 # 0 +0x9763 0x6892 # 0 +0x9764 0x6894 # 0 +0x9765 0x6895 # 0 +0x9766 0x6896 # 0 +0x9767 0x6898 # 0 +0x9768 0x6899 # 0 +0x9769 0x689A # 0 +0x976A 0x689B # 0 +0x976B 0x689C # 0 +0x976C 0x689D # 0 +0x976D 0x689E # 0 +0x976E 0x689F # 0 +0x976F 0x68A0 # 0 +0x9770 0x68A1 # 0 +0x9771 0x68A3 # 0 +0x9772 0x68A4 # 0 +0x9773 0x68A5 # 0 +0x9774 0x68A9 # 0 +0x9775 0x68AA # 0 +0x9776 0x68AB # 0 +0x9777 0x68AC # 0 +0x9778 0x68AE # 0 +0x9779 0x68B1 # 0 +0x977A 0x68B2 # 0 +0x977B 0x68B4 # 0 +0x977C 0x68B6 # 0 +0x977D 0x68B7 # 0 +0x977E 0x68B8 # 0 +0x9780 0x68B9 # 0 +0x9781 0x68BA # 0 +0x9782 0x68BB # 0 +0x9783 0x68BC # 0 +0x9784 0x68BD # 0 +0x9785 0x68BE # 0 +0x9786 0x68BF # 0 +0x9787 0x68C1 # 0 +0x9788 0x68C3 # 0 +0x9789 0x68C4 # 0 +0x978A 0x68C5 # 0 +0x978B 0x68C6 # 0 +0x978C 0x68C7 # 0 +0x978D 0x68C8 # 0 +0x978E 0x68CA # 0 +0x978F 0x68CC # 0 +0x9790 0x68CE # 0 +0x9791 0x68CF # 0 +0x9792 0x68D0 # 0 +0x9793 0x68D1 # 0 +0x9794 0x68D3 # 0 +0x9795 0x68D4 # 0 +0x9796 0x68D6 # 0 +0x9797 0x68D7 # 0 +0x9798 0x68D9 # 0 +0x9799 0x68DB # 0 +0x979A 0x68DC # 0 +0x979B 0x68DD # 0 +0x979C 0x68DE # 0 +0x979D 0x68DF # 0 +0x979E 0x68E1 # 0 +0x979F 0x68E2 # 0 +0x97A0 0x68E4 # 0 +0x97A1 0x68E5 # 0 +0x97A2 0x68E6 # 0 +0x97A3 0x68E7 # 0 +0x97A4 0x68E8 # 0 +0x97A5 0x68E9 # 0 +0x97A6 0x68EA # 0 +0x97A7 0x68EB # 0 +0x97A8 0x68EC # 0 +0x97A9 0x68ED # 0 +0x97AA 0x68EF # 0 +0x97AB 0x68F2 # 0 +0x97AC 0x68F3 # 0 +0x97AD 0x68F4 # 0 +0x97AE 0x68F6 # 0 +0x97AF 0x68F7 # 0 +0x97B0 0x68F8 # 0 +0x97B1 0x68FB # 0 +0x97B2 0x68FD # 0 +0x97B3 0x68FE # 0 +0x97B4 0x68FF # 0 +0x97B5 0x6900 # 0 +0x97B6 0x6902 # 0 +0x97B7 0x6903 # 0 +0x97B8 0x6904 # 0 +0x97B9 0x6906 # 0 +0x97BA 0x6907 # 0 +0x97BB 0x6908 # 0 +0x97BC 0x6909 # 0 +0x97BD 0x690A # 0 +0x97BE 0x690C # 0 +0x97BF 0x690F # 0 +0x97C0 0x6911 # 0 +0x97C1 0x6913 # 0 +0x97C2 0x6914 # 0 +0x97C3 0x6915 # 0 +0x97C4 0x6916 # 0 +0x97C5 0x6917 # 0 +0x97C6 0x6918 # 0 +0x97C7 0x6919 # 0 +0x97C8 0x691A # 0 +0x97C9 0x691B # 0 +0x97CA 0x691C # 0 +0x97CB 0x691D # 0 +0x97CC 0x691E # 0 +0x97CD 0x6921 # 0 +0x97CE 0x6922 # 0 +0x97CF 0x6923 # 0 +0x97D0 0x6925 # 0 +0x97D1 0x6926 # 0 +0x97D2 0x6927 # 0 +0x97D3 0x6928 # 0 +0x97D4 0x6929 # 0 +0x97D5 0x692A # 0 +0x97D6 0x692B # 0 +0x97D7 0x692C # 0 +0x97D8 0x692E # 0 +0x97D9 0x692F # 0 +0x97DA 0x6931 # 0 +0x97DB 0x6932 # 0 +0x97DC 0x6933 # 0 +0x97DD 0x6935 # 0 +0x97DE 0x6936 # 0 +0x97DF 0x6937 # 0 +0x97E0 0x6938 # 0 +0x97E1 0x693A # 0 +0x97E2 0x693B # 0 +0x97E3 0x693C # 0 +0x97E4 0x693E # 0 +0x97E5 0x6940 # 0 +0x97E6 0x6941 # 0 +0x97E7 0x6943 # 0 +0x97E8 0x6944 # 0 +0x97E9 0x6945 # 0 +0x97EA 0x6946 # 0 +0x97EB 0x6947 # 0 +0x97EC 0x6948 # 0 +0x97ED 0x6949 # 0 +0x97EE 0x694A # 0 +0x97EF 0x694B # 0 +0x97F0 0x694C # 0 +0x97F1 0x694D # 0 +0x97F2 0x694E # 0 +0x97F3 0x694F # 0 +0x97F4 0x6950 # 0 +0x97F5 0x6951 # 0 +0x97F6 0x6952 # 0 +0x97F7 0x6953 # 0 +0x97F8 0x6955 # 0 +0x97F9 0x6956 # 0 +0x97FA 0x6958 # 0 +0x97FB 0x6959 # 0 +0x97FC 0x695B # 0 +0x97FD 0x695C # 0 +0x97FE 0x695F # 0 +0x9840 0x6961 # 0 +0x9841 0x6962 # 0 +0x9842 0x6964 # 0 +0x9843 0x6965 # 0 +0x9844 0x6967 # 0 +0x9845 0x6968 # 0 +0x9846 0x6969 # 0 +0x9847 0x696A # 0 +0x9848 0x696C # 0 +0x9849 0x696D # 0 +0x984A 0x696F # 0 +0x984B 0x6970 # 0 +0x984C 0x6972 # 0 +0x984D 0x6973 # 0 +0x984E 0x6974 # 0 +0x984F 0x6975 # 0 +0x9850 0x6976 # 0 +0x9851 0x697A # 0 +0x9852 0x697B # 0 +0x9853 0x697D # 0 +0x9854 0x697E # 0 +0x9855 0x697F # 0 +0x9856 0x6981 # 0 +0x9857 0x6983 # 0 +0x9858 0x6985 # 0 +0x9859 0x698A # 0 +0x985A 0x698B # 0 +0x985B 0x698C # 0 +0x985C 0x698E # 0 +0x985D 0x698F # 0 +0x985E 0x6990 # 0 +0x985F 0x6991 # 0 +0x9860 0x6992 # 0 +0x9861 0x6993 # 0 +0x9862 0x6996 # 0 +0x9863 0x6997 # 0 +0x9864 0x6999 # 0 +0x9865 0x699A # 0 +0x9866 0x699D # 0 +0x9867 0x699E # 0 +0x9868 0x699F # 0 +0x9869 0x69A0 # 0 +0x986A 0x69A1 # 0 +0x986B 0x69A2 # 0 +0x986C 0x69A3 # 0 +0x986D 0x69A4 # 0 +0x986E 0x69A5 # 0 +0x986F 0x69A6 # 0 +0x9870 0x69A9 # 0 +0x9871 0x69AA # 0 +0x9872 0x69AC # 0 +0x9873 0x69AE # 0 +0x9874 0x69AF # 0 +0x9875 0x69B0 # 0 +0x9876 0x69B2 # 0 +0x9877 0x69B3 # 0 +0x9878 0x69B5 # 0 +0x9879 0x69B6 # 0 +0x987A 0x69B8 # 0 +0x987B 0x69B9 # 0 +0x987C 0x69BA # 0 +0x987D 0x69BC # 0 +0x987E 0x69BD # 0 +0x9880 0x69BE # 0 +0x9881 0x69BF # 0 +0x9882 0x69C0 # 0 +0x9883 0x69C2 # 0 +0x9884 0x69C3 # 0 +0x9885 0x69C4 # 0 +0x9886 0x69C5 # 0 +0x9887 0x69C6 # 0 +0x9888 0x69C7 # 0 +0x9889 0x69C8 # 0 +0x988A 0x69C9 # 0 +0x988B 0x69CB # 0 +0x988C 0x69CD # 0 +0x988D 0x69CF # 0 +0x988E 0x69D1 # 0 +0x988F 0x69D2 # 0 +0x9890 0x69D3 # 0 +0x9891 0x69D5 # 0 +0x9892 0x69D6 # 0 +0x9893 0x69D7 # 0 +0x9894 0x69D8 # 0 +0x9895 0x69D9 # 0 +0x9896 0x69DA # 0 +0x9897 0x69DC # 0 +0x9898 0x69DD # 0 +0x9899 0x69DE # 0 +0x989A 0x69E1 # 0 +0x989B 0x69E2 # 0 +0x989C 0x69E3 # 0 +0x989D 0x69E4 # 0 +0x989E 0x69E5 # 0 +0x989F 0x69E6 # 0 +0x98A0 0x69E7 # 0 +0x98A1 0x69E8 # 0 +0x98A2 0x69E9 # 0 +0x98A3 0x69EA # 0 +0x98A4 0x69EB # 0 +0x98A5 0x69EC # 0 +0x98A6 0x69EE # 0 +0x98A7 0x69EF # 0 +0x98A8 0x69F0 # 0 +0x98A9 0x69F1 # 0 +0x98AA 0x69F3 # 0 +0x98AB 0x69F4 # 0 +0x98AC 0x69F5 # 0 +0x98AD 0x69F6 # 0 +0x98AE 0x69F7 # 0 +0x98AF 0x69F8 # 0 +0x98B0 0x69F9 # 0 +0x98B1 0x69FA # 0 +0x98B2 0x69FB # 0 +0x98B3 0x69FC # 0 +0x98B4 0x69FE # 0 +0x98B5 0x6A00 # 0 +0x98B6 0x6A01 # 0 +0x98B7 0x6A02 # 0 +0x98B8 0x6A03 # 0 +0x98B9 0x6A04 # 0 +0x98BA 0x6A05 # 0 +0x98BB 0x6A06 # 0 +0x98BC 0x6A07 # 0 +0x98BD 0x6A08 # 0 +0x98BE 0x6A09 # 0 +0x98BF 0x6A0B # 0 +0x98C0 0x6A0C # 0 +0x98C1 0x6A0D # 0 +0x98C2 0x6A0E # 0 +0x98C3 0x6A0F # 0 +0x98C4 0x6A10 # 0 +0x98C5 0x6A11 # 0 +0x98C6 0x6A12 # 0 +0x98C7 0x6A13 # 0 +0x98C8 0x6A14 # 0 +0x98C9 0x6A15 # 0 +0x98CA 0x6A16 # 0 +0x98CB 0x6A19 # 0 +0x98CC 0x6A1A # 0 +0x98CD 0x6A1B # 0 +0x98CE 0x6A1C # 0 +0x98CF 0x6A1D # 0 +0x98D0 0x6A1E # 0 +0x98D1 0x6A20 # 0 +0x98D2 0x6A22 # 0 +0x98D3 0x6A23 # 0 +0x98D4 0x6A24 # 0 +0x98D5 0x6A25 # 0 +0x98D6 0x6A26 # 0 +0x98D7 0x6A27 # 0 +0x98D8 0x6A29 # 0 +0x98D9 0x6A2B # 0 +0x98DA 0x6A2C # 0 +0x98DB 0x6A2D # 0 +0x98DC 0x6A2E # 0 +0x98DD 0x6A30 # 0 +0x98DE 0x6A32 # 0 +0x98DF 0x6A33 # 0 +0x98E0 0x6A34 # 0 +0x98E1 0x6A36 # 0 +0x98E2 0x6A37 # 0 +0x98E3 0x6A38 # 0 +0x98E4 0x6A39 # 0 +0x98E5 0x6A3A # 0 +0x98E6 0x6A3B # 0 +0x98E7 0x6A3C # 0 +0x98E8 0x6A3F # 0 +0x98E9 0x6A40 # 0 +0x98EA 0x6A41 # 0 +0x98EB 0x6A42 # 0 +0x98EC 0x6A43 # 0 +0x98ED 0x6A45 # 0 +0x98EE 0x6A46 # 0 +0x98EF 0x6A48 # 0 +0x98F0 0x6A49 # 0 +0x98F1 0x6A4A # 0 +0x98F2 0x6A4B # 0 +0x98F3 0x6A4C # 0 +0x98F4 0x6A4D # 0 +0x98F5 0x6A4E # 0 +0x98F6 0x6A4F # 0 +0x98F7 0x6A51 # 0 +0x98F8 0x6A52 # 0 +0x98F9 0x6A53 # 0 +0x98FA 0x6A54 # 0 +0x98FB 0x6A55 # 0 +0x98FC 0x6A56 # 0 +0x98FD 0x6A57 # 0 +0x98FE 0x6A5A # 0 +0x9940 0x6A5C # 0 +0x9941 0x6A5D # 0 +0x9942 0x6A5E # 0 +0x9943 0x6A5F # 0 +0x9944 0x6A60 # 0 +0x9945 0x6A62 # 0 +0x9946 0x6A63 # 0 +0x9947 0x6A64 # 0 +0x9948 0x6A66 # 0 +0x9949 0x6A67 # 0 +0x994A 0x6A68 # 0 +0x994B 0x6A69 # 0 +0x994C 0x6A6A # 0 +0x994D 0x6A6B # 0 +0x994E 0x6A6C # 0 +0x994F 0x6A6D # 0 +0x9950 0x6A6E # 0 +0x9951 0x6A6F # 0 +0x9952 0x6A70 # 0 +0x9953 0x6A72 # 0 +0x9954 0x6A73 # 0 +0x9955 0x6A74 # 0 +0x9956 0x6A75 # 0 +0x9957 0x6A76 # 0 +0x9958 0x6A77 # 0 +0x9959 0x6A78 # 0 +0x995A 0x6A7A # 0 +0x995B 0x6A7B # 0 +0x995C 0x6A7D # 0 +0x995D 0x6A7E # 0 +0x995E 0x6A7F # 0 +0x995F 0x6A81 # 0 +0x9960 0x6A82 # 0 +0x9961 0x6A83 # 0 +0x9962 0x6A85 # 0 +0x9963 0x6A86 # 0 +0x9964 0x6A87 # 0 +0x9965 0x6A88 # 0 +0x9966 0x6A89 # 0 +0x9967 0x6A8A # 0 +0x9968 0x6A8B # 0 +0x9969 0x6A8C # 0 +0x996A 0x6A8D # 0 +0x996B 0x6A8F # 0 +0x996C 0x6A92 # 0 +0x996D 0x6A93 # 0 +0x996E 0x6A94 # 0 +0x996F 0x6A95 # 0 +0x9970 0x6A96 # 0 +0x9971 0x6A98 # 0 +0x9972 0x6A99 # 0 +0x9973 0x6A9A # 0 +0x9974 0x6A9B # 0 +0x9975 0x6A9C # 0 +0x9976 0x6A9D # 0 +0x9977 0x6A9E # 0 +0x9978 0x6A9F # 0 +0x9979 0x6AA1 # 0 +0x997A 0x6AA2 # 0 +0x997B 0x6AA3 # 0 +0x997C 0x6AA4 # 0 +0x997D 0x6AA5 # 0 +0x997E 0x6AA6 # 0 +0x9980 0x6AA7 # 0 +0x9981 0x6AA8 # 0 +0x9982 0x6AAA # 0 +0x9983 0x6AAD # 0 +0x9984 0x6AAE # 0 +0x9985 0x6AAF # 0 +0x9986 0x6AB0 # 0 +0x9987 0x6AB1 # 0 +0x9988 0x6AB2 # 0 +0x9989 0x6AB3 # 0 +0x998A 0x6AB4 # 0 +0x998B 0x6AB5 # 0 +0x998C 0x6AB6 # 0 +0x998D 0x6AB7 # 0 +0x998E 0x6AB8 # 0 +0x998F 0x6AB9 # 0 +0x9990 0x6ABA # 0 +0x9991 0x6ABB # 0 +0x9992 0x6ABC # 0 +0x9993 0x6ABD # 0 +0x9994 0x6ABE # 0 +0x9995 0x6ABF # 0 +0x9996 0x6AC0 # 0 +0x9997 0x6AC1 # 0 +0x9998 0x6AC2 # 0 +0x9999 0x6AC3 # 0 +0x999A 0x6AC4 # 0 +0x999B 0x6AC5 # 0 +0x999C 0x6AC6 # 0 +0x999D 0x6AC7 # 0 +0x999E 0x6AC8 # 0 +0x999F 0x6AC9 # 0 +0x99A0 0x6ACA # 0 +0x99A1 0x6ACB # 0 +0x99A2 0x6ACC # 0 +0x99A3 0x6ACD # 0 +0x99A4 0x6ACE # 0 +0x99A5 0x6ACF # 0 +0x99A6 0x6AD0 # 0 +0x99A7 0x6AD1 # 0 +0x99A8 0x6AD2 # 0 +0x99A9 0x6AD3 # 0 +0x99AA 0x6AD4 # 0 +0x99AB 0x6AD5 # 0 +0x99AC 0x6AD6 # 0 +0x99AD 0x6AD7 # 0 +0x99AE 0x6AD8 # 0 +0x99AF 0x6AD9 # 0 +0x99B0 0x6ADA # 0 +0x99B1 0x6ADB # 0 +0x99B2 0x6ADC # 0 +0x99B3 0x6ADD # 0 +0x99B4 0x6ADE # 0 +0x99B5 0x6ADF # 0 +0x99B6 0x6AE0 # 0 +0x99B7 0x6AE1 # 0 +0x99B8 0x6AE2 # 0 +0x99B9 0x6AE3 # 0 +0x99BA 0x6AE4 # 0 +0x99BB 0x6AE5 # 0 +0x99BC 0x6AE6 # 0 +0x99BD 0x6AE7 # 0 +0x99BE 0x6AE8 # 0 +0x99BF 0x6AE9 # 0 +0x99C0 0x6AEA # 0 +0x99C1 0x6AEB # 0 +0x99C2 0x6AEC # 0 +0x99C3 0x6AED # 0 +0x99C4 0x6AEE # 0 +0x99C5 0x6AEF # 0 +0x99C6 0x6AF0 # 0 +0x99C7 0x6AF1 # 0 +0x99C8 0x6AF2 # 0 +0x99C9 0x6AF3 # 0 +0x99CA 0x6AF4 # 0 +0x99CB 0x6AF5 # 0 +0x99CC 0x6AF6 # 0 +0x99CD 0x6AF7 # 0 +0x99CE 0x6AF8 # 0 +0x99CF 0x6AF9 # 0 +0x99D0 0x6AFA # 0 +0x99D1 0x6AFB # 0 +0x99D2 0x6AFC # 0 +0x99D3 0x6AFD # 0 +0x99D4 0x6AFE # 0 +0x99D5 0x6AFF # 0 +0x99D6 0x6B00 # 0 +0x99D7 0x6B01 # 0 +0x99D8 0x6B02 # 0 +0x99D9 0x6B03 # 0 +0x99DA 0x6B04 # 0 +0x99DB 0x6B05 # 0 +0x99DC 0x6B06 # 0 +0x99DD 0x6B07 # 0 +0x99DE 0x6B08 # 0 +0x99DF 0x6B09 # 0 +0x99E0 0x6B0A # 0 +0x99E1 0x6B0B # 0 +0x99E2 0x6B0C # 0 +0x99E3 0x6B0D # 0 +0x99E4 0x6B0E # 0 +0x99E5 0x6B0F # 0 +0x99E6 0x6B10 # 0 +0x99E7 0x6B11 # 0 +0x99E8 0x6B12 # 0 +0x99E9 0x6B13 # 0 +0x99EA 0x6B14 # 0 +0x99EB 0x6B15 # 0 +0x99EC 0x6B16 # 0 +0x99ED 0x6B17 # 0 +0x99EE 0x6B18 # 0 +0x99EF 0x6B19 # 0 +0x99F0 0x6B1A # 0 +0x99F1 0x6B1B # 0 +0x99F2 0x6B1C # 0 +0x99F3 0x6B1D # 0 +0x99F4 0x6B1E # 0 +0x99F5 0x6B1F # 0 +0x99F6 0x6B25 # 0 +0x99F7 0x6B26 # 0 +0x99F8 0x6B28 # 0 +0x99F9 0x6B29 # 0 +0x99FA 0x6B2A # 0 +0x99FB 0x6B2B # 0 +0x99FC 0x6B2C # 0 +0x99FD 0x6B2D # 0 +0x99FE 0x6B2E # 0 +0x9A40 0x6B2F # 0 +0x9A41 0x6B30 # 0 +0x9A42 0x6B31 # 0 +0x9A43 0x6B33 # 0 +0x9A44 0x6B34 # 0 +0x9A45 0x6B35 # 0 +0x9A46 0x6B36 # 0 +0x9A47 0x6B38 # 0 +0x9A48 0x6B3B # 0 +0x9A49 0x6B3C # 0 +0x9A4A 0x6B3D # 0 +0x9A4B 0x6B3F # 0 +0x9A4C 0x6B40 # 0 +0x9A4D 0x6B41 # 0 +0x9A4E 0x6B42 # 0 +0x9A4F 0x6B44 # 0 +0x9A50 0x6B45 # 0 +0x9A51 0x6B48 # 0 +0x9A52 0x6B4A # 0 +0x9A53 0x6B4B # 0 +0x9A54 0x6B4D # 0 +0x9A55 0x6B4E # 0 +0x9A56 0x6B4F # 0 +0x9A57 0x6B50 # 0 +0x9A58 0x6B51 # 0 +0x9A59 0x6B52 # 0 +0x9A5A 0x6B53 # 0 +0x9A5B 0x6B54 # 0 +0x9A5C 0x6B55 # 0 +0x9A5D 0x6B56 # 0 +0x9A5E 0x6B57 # 0 +0x9A5F 0x6B58 # 0 +0x9A60 0x6B5A # 0 +0x9A61 0x6B5B # 0 +0x9A62 0x6B5C # 0 +0x9A63 0x6B5D # 0 +0x9A64 0x6B5E # 0 +0x9A65 0x6B5F # 0 +0x9A66 0x6B60 # 0 +0x9A67 0x6B61 # 0 +0x9A68 0x6B68 # 0 +0x9A69 0x6B69 # 0 +0x9A6A 0x6B6B # 0 +0x9A6B 0x6B6C # 0 +0x9A6C 0x6B6D # 0 +0x9A6D 0x6B6E # 0 +0x9A6E 0x6B6F # 0 +0x9A6F 0x6B70 # 0 +0x9A70 0x6B71 # 0 +0x9A71 0x6B72 # 0 +0x9A72 0x6B73 # 0 +0x9A73 0x6B74 # 0 +0x9A74 0x6B75 # 0 +0x9A75 0x6B76 # 0 +0x9A76 0x6B77 # 0 +0x9A77 0x6B78 # 0 +0x9A78 0x6B7A # 0 +0x9A79 0x6B7D # 0 +0x9A7A 0x6B7E # 0 +0x9A7B 0x6B7F # 0 +0x9A7C 0x6B80 # 0 +0x9A7D 0x6B85 # 0 +0x9A7E 0x6B88 # 0 +0x9A80 0x6B8C # 0 +0x9A81 0x6B8E # 0 +0x9A82 0x6B8F # 0 +0x9A83 0x6B90 # 0 +0x9A84 0x6B91 # 0 +0x9A85 0x6B94 # 0 +0x9A86 0x6B95 # 0 +0x9A87 0x6B97 # 0 +0x9A88 0x6B98 # 0 +0x9A89 0x6B99 # 0 +0x9A8A 0x6B9C # 0 +0x9A8B 0x6B9D # 0 +0x9A8C 0x6B9E # 0 +0x9A8D 0x6B9F # 0 +0x9A8E 0x6BA0 # 0 +0x9A8F 0x6BA2 # 0 +0x9A90 0x6BA3 # 0 +0x9A91 0x6BA4 # 0 +0x9A92 0x6BA5 # 0 +0x9A93 0x6BA6 # 0 +0x9A94 0x6BA7 # 0 +0x9A95 0x6BA8 # 0 +0x9A96 0x6BA9 # 0 +0x9A97 0x6BAB # 0 +0x9A98 0x6BAC # 0 +0x9A99 0x6BAD # 0 +0x9A9A 0x6BAE # 0 +0x9A9B 0x6BAF # 0 +0x9A9C 0x6BB0 # 0 +0x9A9D 0x6BB1 # 0 +0x9A9E 0x6BB2 # 0 +0x9A9F 0x6BB6 # 0 +0x9AA0 0x6BB8 # 0 +0x9AA1 0x6BB9 # 0 +0x9AA2 0x6BBA # 0 +0x9AA3 0x6BBB # 0 +0x9AA4 0x6BBC # 0 +0x9AA5 0x6BBD # 0 +0x9AA6 0x6BBE # 0 +0x9AA7 0x6BC0 # 0 +0x9AA8 0x6BC3 # 0 +0x9AA9 0x6BC4 # 0 +0x9AAA 0x6BC6 # 0 +0x9AAB 0x6BC7 # 0 +0x9AAC 0x6BC8 # 0 +0x9AAD 0x6BC9 # 0 +0x9AAE 0x6BCA # 0 +0x9AAF 0x6BCC # 0 +0x9AB0 0x6BCE # 0 +0x9AB1 0x6BD0 # 0 +0x9AB2 0x6BD1 # 0 +0x9AB3 0x6BD8 # 0 +0x9AB4 0x6BDA # 0 +0x9AB5 0x6BDC # 0 +0x9AB6 0x6BDD # 0 +0x9AB7 0x6BDE # 0 +0x9AB8 0x6BDF # 0 +0x9AB9 0x6BE0 # 0 +0x9ABA 0x6BE2 # 0 +0x9ABB 0x6BE3 # 0 +0x9ABC 0x6BE4 # 0 +0x9ABD 0x6BE5 # 0 +0x9ABE 0x6BE6 # 0 +0x9ABF 0x6BE7 # 0 +0x9AC0 0x6BE8 # 0 +0x9AC1 0x6BE9 # 0 +0x9AC2 0x6BEC # 0 +0x9AC3 0x6BED # 0 +0x9AC4 0x6BEE # 0 +0x9AC5 0x6BF0 # 0 +0x9AC6 0x6BF1 # 0 +0x9AC7 0x6BF2 # 0 +0x9AC8 0x6BF4 # 0 +0x9AC9 0x6BF6 # 0 +0x9ACA 0x6BF7 # 0 +0x9ACB 0x6BF8 # 0 +0x9ACC 0x6BFA # 0 +0x9ACD 0x6BFB # 0 +0x9ACE 0x6BFC # 0 +0x9ACF 0x6BFE # 0 +0x9AD0 0x6BFF # 0 +0x9AD1 0x6C00 # 0 +0x9AD2 0x6C01 # 0 +0x9AD3 0x6C02 # 0 +0x9AD4 0x6C03 # 0 +0x9AD5 0x6C04 # 0 +0x9AD6 0x6C08 # 0 +0x9AD7 0x6C09 # 0 +0x9AD8 0x6C0A # 0 +0x9AD9 0x6C0B # 0 +0x9ADA 0x6C0C # 0 +0x9ADB 0x6C0E # 0 +0x9ADC 0x6C12 # 0 +0x9ADD 0x6C17 # 0 +0x9ADE 0x6C1C # 0 +0x9ADF 0x6C1D # 0 +0x9AE0 0x6C1E # 0 +0x9AE1 0x6C20 # 0 +0x9AE2 0x6C23 # 0 +0x9AE3 0x6C25 # 0 +0x9AE4 0x6C2B # 0 +0x9AE5 0x6C2C # 0 +0x9AE6 0x6C2D # 0 +0x9AE7 0x6C31 # 0 +0x9AE8 0x6C33 # 0 +0x9AE9 0x6C36 # 0 +0x9AEA 0x6C37 # 0 +0x9AEB 0x6C39 # 0 +0x9AEC 0x6C3A # 0 +0x9AED 0x6C3B # 0 +0x9AEE 0x6C3C # 0 +0x9AEF 0x6C3E # 0 +0x9AF0 0x6C3F # 0 +0x9AF1 0x6C43 # 0 +0x9AF2 0x6C44 # 0 +0x9AF3 0x6C45 # 0 +0x9AF4 0x6C48 # 0 +0x9AF5 0x6C4B # 0 +0x9AF6 0x6C4C # 0 +0x9AF7 0x6C4D # 0 +0x9AF8 0x6C4E # 0 +0x9AF9 0x6C4F # 0 +0x9AFA 0x6C51 # 0 +0x9AFB 0x6C52 # 0 +0x9AFC 0x6C53 # 0 +0x9AFD 0x6C56 # 0 +0x9AFE 0x6C58 # 0 +0x9B40 0x6C59 # 0 +0x9B41 0x6C5A # 0 +0x9B42 0x6C62 # 0 +0x9B43 0x6C63 # 0 +0x9B44 0x6C65 # 0 +0x9B45 0x6C66 # 0 +0x9B46 0x6C67 # 0 +0x9B47 0x6C6B # 0 +0x9B48 0x6C6C # 0 +0x9B49 0x6C6D # 0 +0x9B4A 0x6C6E # 0 +0x9B4B 0x6C6F # 0 +0x9B4C 0x6C71 # 0 +0x9B4D 0x6C73 # 0 +0x9B4E 0x6C75 # 0 +0x9B4F 0x6C77 # 0 +0x9B50 0x6C78 # 0 +0x9B51 0x6C7A # 0 +0x9B52 0x6C7B # 0 +0x9B53 0x6C7C # 0 +0x9B54 0x6C7F # 0 +0x9B55 0x6C80 # 0 +0x9B56 0x6C84 # 0 +0x9B57 0x6C87 # 0 +0x9B58 0x6C8A # 0 +0x9B59 0x6C8B # 0 +0x9B5A 0x6C8D # 0 +0x9B5B 0x6C8E # 0 +0x9B5C 0x6C91 # 0 +0x9B5D 0x6C92 # 0 +0x9B5E 0x6C95 # 0 +0x9B5F 0x6C96 # 0 +0x9B60 0x6C97 # 0 +0x9B61 0x6C98 # 0 +0x9B62 0x6C9A # 0 +0x9B63 0x6C9C # 0 +0x9B64 0x6C9D # 0 +0x9B65 0x6C9E # 0 +0x9B66 0x6CA0 # 0 +0x9B67 0x6CA2 # 0 +0x9B68 0x6CA8 # 0 +0x9B69 0x6CAC # 0 +0x9B6A 0x6CAF # 0 +0x9B6B 0x6CB0 # 0 +0x9B6C 0x6CB4 # 0 +0x9B6D 0x6CB5 # 0 +0x9B6E 0x6CB6 # 0 +0x9B6F 0x6CB7 # 0 +0x9B70 0x6CBA # 0 +0x9B71 0x6CC0 # 0 +0x9B72 0x6CC1 # 0 +0x9B73 0x6CC2 # 0 +0x9B74 0x6CC3 # 0 +0x9B75 0x6CC6 # 0 +0x9B76 0x6CC7 # 0 +0x9B77 0x6CC8 # 0 +0x9B78 0x6CCB # 0 +0x9B79 0x6CCD # 0 +0x9B7A 0x6CCE # 0 +0x9B7B 0x6CCF # 0 +0x9B7C 0x6CD1 # 0 +0x9B7D 0x6CD2 # 0 +0x9B7E 0x6CD8 # 0 +0x9B80 0x6CD9 # 0 +0x9B81 0x6CDA # 0 +0x9B82 0x6CDC # 0 +0x9B83 0x6CDD # 0 +0x9B84 0x6CDF # 0 +0x9B85 0x6CE4 # 0 +0x9B86 0x6CE6 # 0 +0x9B87 0x6CE7 # 0 +0x9B88 0x6CE9 # 0 +0x9B89 0x6CEC # 0 +0x9B8A 0x6CED # 0 +0x9B8B 0x6CF2 # 0 +0x9B8C 0x6CF4 # 0 +0x9B8D 0x6CF9 # 0 +0x9B8E 0x6CFF # 0 +0x9B8F 0x6D00 # 0 +0x9B90 0x6D02 # 0 +0x9B91 0x6D03 # 0 +0x9B92 0x6D05 # 0 +0x9B93 0x6D06 # 0 +0x9B94 0x6D08 # 0 +0x9B95 0x6D09 # 0 +0x9B96 0x6D0A # 0 +0x9B97 0x6D0D # 0 +0x9B98 0x6D0F # 0 +0x9B99 0x6D10 # 0 +0x9B9A 0x6D11 # 0 +0x9B9B 0x6D13 # 0 +0x9B9C 0x6D14 # 0 +0x9B9D 0x6D15 # 0 +0x9B9E 0x6D16 # 0 +0x9B9F 0x6D18 # 0 +0x9BA0 0x6D1C # 0 +0x9BA1 0x6D1D # 0 +0x9BA2 0x6D1F # 0 +0x9BA3 0x6D20 # 0 +0x9BA4 0x6D21 # 0 +0x9BA5 0x6D22 # 0 +0x9BA6 0x6D23 # 0 +0x9BA7 0x6D24 # 0 +0x9BA8 0x6D26 # 0 +0x9BA9 0x6D28 # 0 +0x9BAA 0x6D29 # 0 +0x9BAB 0x6D2C # 0 +0x9BAC 0x6D2D # 0 +0x9BAD 0x6D2F # 0 +0x9BAE 0x6D30 # 0 +0x9BAF 0x6D34 # 0 +0x9BB0 0x6D36 # 0 +0x9BB1 0x6D37 # 0 +0x9BB2 0x6D38 # 0 +0x9BB3 0x6D3A # 0 +0x9BB4 0x6D3F # 0 +0x9BB5 0x6D40 # 0 +0x9BB6 0x6D42 # 0 +0x9BB7 0x6D44 # 0 +0x9BB8 0x6D49 # 0 +0x9BB9 0x6D4C # 0 +0x9BBA 0x6D50 # 0 +0x9BBB 0x6D55 # 0 +0x9BBC 0x6D56 # 0 +0x9BBD 0x6D57 # 0 +0x9BBE 0x6D58 # 0 +0x9BBF 0x6D5B # 0 +0x9BC0 0x6D5D # 0 +0x9BC1 0x6D5F # 0 +0x9BC2 0x6D61 # 0 +0x9BC3 0x6D62 # 0 +0x9BC4 0x6D64 # 0 +0x9BC5 0x6D65 # 0 +0x9BC6 0x6D67 # 0 +0x9BC7 0x6D68 # 0 +0x9BC8 0x6D6B # 0 +0x9BC9 0x6D6C # 0 +0x9BCA 0x6D6D # 0 +0x9BCB 0x6D70 # 0 +0x9BCC 0x6D71 # 0 +0x9BCD 0x6D72 # 0 +0x9BCE 0x6D73 # 0 +0x9BCF 0x6D75 # 0 +0x9BD0 0x6D76 # 0 +0x9BD1 0x6D79 # 0 +0x9BD2 0x6D7A # 0 +0x9BD3 0x6D7B # 0 +0x9BD4 0x6D7D # 0 +0x9BD5 0x6D7E # 0 +0x9BD6 0x6D7F # 0 +0x9BD7 0x6D80 # 0 +0x9BD8 0x6D81 # 0 +0x9BD9 0x6D83 # 0 +0x9BDA 0x6D84 # 0 +0x9BDB 0x6D86 # 0 +0x9BDC 0x6D87 # 0 +0x9BDD 0x6D8A # 0 +0x9BDE 0x6D8B # 0 +0x9BDF 0x6D8D # 0 +0x9BE0 0x6D8F # 0 +0x9BE1 0x6D90 # 0 +0x9BE2 0x6D92 # 0 +0x9BE3 0x6D96 # 0 +0x9BE4 0x6D97 # 0 +0x9BE5 0x6D98 # 0 +0x9BE6 0x6D99 # 0 +0x9BE7 0x6D9A # 0 +0x9BE8 0x6D9C # 0 +0x9BE9 0x6DA2 # 0 +0x9BEA 0x6DA5 # 0 +0x9BEB 0x6DAC # 0 +0x9BEC 0x6DAD # 0 +0x9BED 0x6DB0 # 0 +0x9BEE 0x6DB1 # 0 +0x9BEF 0x6DB3 # 0 +0x9BF0 0x6DB4 # 0 +0x9BF1 0x6DB6 # 0 +0x9BF2 0x6DB7 # 0 +0x9BF3 0x6DB9 # 0 +0x9BF4 0x6DBA # 0 +0x9BF5 0x6DBB # 0 +0x9BF6 0x6DBC # 0 +0x9BF7 0x6DBD # 0 +0x9BF8 0x6DBE # 0 +0x9BF9 0x6DC1 # 0 +0x9BFA 0x6DC2 # 0 +0x9BFB 0x6DC3 # 0 +0x9BFC 0x6DC8 # 0 +0x9BFD 0x6DC9 # 0 +0x9BFE 0x6DCA # 0 +0x9C40 0x6DCD # 0 +0x9C41 0x6DCE # 0 +0x9C42 0x6DCF # 0 +0x9C43 0x6DD0 # 0 +0x9C44 0x6DD2 # 0 +0x9C45 0x6DD3 # 0 +0x9C46 0x6DD4 # 0 +0x9C47 0x6DD5 # 0 +0x9C48 0x6DD7 # 0 +0x9C49 0x6DDA # 0 +0x9C4A 0x6DDB # 0 +0x9C4B 0x6DDC # 0 +0x9C4C 0x6DDF # 0 +0x9C4D 0x6DE2 # 0 +0x9C4E 0x6DE3 # 0 +0x9C4F 0x6DE5 # 0 +0x9C50 0x6DE7 # 0 +0x9C51 0x6DE8 # 0 +0x9C52 0x6DE9 # 0 +0x9C53 0x6DEA # 0 +0x9C54 0x6DED # 0 +0x9C55 0x6DEF # 0 +0x9C56 0x6DF0 # 0 +0x9C57 0x6DF2 # 0 +0x9C58 0x6DF4 # 0 +0x9C59 0x6DF5 # 0 +0x9C5A 0x6DF6 # 0 +0x9C5B 0x6DF8 # 0 +0x9C5C 0x6DFA # 0 +0x9C5D 0x6DFD # 0 +0x9C5E 0x6DFE # 0 +0x9C5F 0x6DFF # 0 +0x9C60 0x6E00 # 0 +0x9C61 0x6E01 # 0 +0x9C62 0x6E02 # 0 +0x9C63 0x6E03 # 0 +0x9C64 0x6E04 # 0 +0x9C65 0x6E06 # 0 +0x9C66 0x6E07 # 0 +0x9C67 0x6E08 # 0 +0x9C68 0x6E09 # 0 +0x9C69 0x6E0B # 0 +0x9C6A 0x6E0F # 0 +0x9C6B 0x6E12 # 0 +0x9C6C 0x6E13 # 0 +0x9C6D 0x6E15 # 0 +0x9C6E 0x6E18 # 0 +0x9C6F 0x6E19 # 0 +0x9C70 0x6E1B # 0 +0x9C71 0x6E1C # 0 +0x9C72 0x6E1E # 0 +0x9C73 0x6E1F # 0 +0x9C74 0x6E22 # 0 +0x9C75 0x6E26 # 0 +0x9C76 0x6E27 # 0 +0x9C77 0x6E28 # 0 +0x9C78 0x6E2A # 0 +0x9C79 0x6E2C # 0 +0x9C7A 0x6E2E # 0 +0x9C7B 0x6E30 # 0 +0x9C7C 0x6E31 # 0 +0x9C7D 0x6E33 # 0 +0x9C7E 0x6E35 # 0 +0x9C80 0x6E36 # 0 +0x9C81 0x6E37 # 0 +0x9C82 0x6E39 # 0 +0x9C83 0x6E3B # 0 +0x9C84 0x6E3C # 0 +0x9C85 0x6E3D # 0 +0x9C86 0x6E3E # 0 +0x9C87 0x6E3F # 0 +0x9C88 0x6E40 # 0 +0x9C89 0x6E41 # 0 +0x9C8A 0x6E42 # 0 +0x9C8B 0x6E45 # 0 +0x9C8C 0x6E46 # 0 +0x9C8D 0x6E47 # 0 +0x9C8E 0x6E48 # 0 +0x9C8F 0x6E49 # 0 +0x9C90 0x6E4A # 0 +0x9C91 0x6E4B # 0 +0x9C92 0x6E4C # 0 +0x9C93 0x6E4F # 0 +0x9C94 0x6E50 # 0 +0x9C95 0x6E51 # 0 +0x9C96 0x6E52 # 0 +0x9C97 0x6E55 # 0 +0x9C98 0x6E57 # 0 +0x9C99 0x6E59 # 0 +0x9C9A 0x6E5A # 0 +0x9C9B 0x6E5C # 0 +0x9C9C 0x6E5D # 0 +0x9C9D 0x6E5E # 0 +0x9C9E 0x6E60 # 0 +0x9C9F 0x6E61 # 0 +0x9CA0 0x6E62 # 0 +0x9CA1 0x6E63 # 0 +0x9CA2 0x6E64 # 0 +0x9CA3 0x6E65 # 0 +0x9CA4 0x6E66 # 0 +0x9CA5 0x6E67 # 0 +0x9CA6 0x6E68 # 0 +0x9CA7 0x6E69 # 0 +0x9CA8 0x6E6A # 0 +0x9CA9 0x6E6C # 0 +0x9CAA 0x6E6D # 0 +0x9CAB 0x6E6F # 0 +0x9CAC 0x6E70 # 0 +0x9CAD 0x6E71 # 0 +0x9CAE 0x6E72 # 0 +0x9CAF 0x6E73 # 0 +0x9CB0 0x6E74 # 0 +0x9CB1 0x6E75 # 0 +0x9CB2 0x6E76 # 0 +0x9CB3 0x6E77 # 0 +0x9CB4 0x6E78 # 0 +0x9CB5 0x6E79 # 0 +0x9CB6 0x6E7A # 0 +0x9CB7 0x6E7B # 0 +0x9CB8 0x6E7C # 0 +0x9CB9 0x6E7D # 0 +0x9CBA 0x6E80 # 0 +0x9CBB 0x6E81 # 0 +0x9CBC 0x6E82 # 0 +0x9CBD 0x6E84 # 0 +0x9CBE 0x6E87 # 0 +0x9CBF 0x6E88 # 0 +0x9CC0 0x6E8A # 0 +0x9CC1 0x6E8B # 0 +0x9CC2 0x6E8C # 0 +0x9CC3 0x6E8D # 0 +0x9CC4 0x6E8E # 0 +0x9CC5 0x6E91 # 0 +0x9CC6 0x6E92 # 0 +0x9CC7 0x6E93 # 0 +0x9CC8 0x6E94 # 0 +0x9CC9 0x6E95 # 0 +0x9CCA 0x6E96 # 0 +0x9CCB 0x6E97 # 0 +0x9CCC 0x6E99 # 0 +0x9CCD 0x6E9A # 0 +0x9CCE 0x6E9B # 0 +0x9CCF 0x6E9D # 0 +0x9CD0 0x6E9E # 0 +0x9CD1 0x6EA0 # 0 +0x9CD2 0x6EA1 # 0 +0x9CD3 0x6EA3 # 0 +0x9CD4 0x6EA4 # 0 +0x9CD5 0x6EA6 # 0 +0x9CD6 0x6EA8 # 0 +0x9CD7 0x6EA9 # 0 +0x9CD8 0x6EAB # 0 +0x9CD9 0x6EAC # 0 +0x9CDA 0x6EAD # 0 +0x9CDB 0x6EAE # 0 +0x9CDC 0x6EB0 # 0 +0x9CDD 0x6EB3 # 0 +0x9CDE 0x6EB5 # 0 +0x9CDF 0x6EB8 # 0 +0x9CE0 0x6EB9 # 0 +0x9CE1 0x6EBC # 0 +0x9CE2 0x6EBE # 0 +0x9CE3 0x6EBF # 0 +0x9CE4 0x6EC0 # 0 +0x9CE5 0x6EC3 # 0 +0x9CE6 0x6EC4 # 0 +0x9CE7 0x6EC5 # 0 +0x9CE8 0x6EC6 # 0 +0x9CE9 0x6EC8 # 0 +0x9CEA 0x6EC9 # 0 +0x9CEB 0x6ECA # 0 +0x9CEC 0x6ECC # 0 +0x9CED 0x6ECD # 0 +0x9CEE 0x6ECE # 0 +0x9CEF 0x6ED0 # 0 +0x9CF0 0x6ED2 # 0 +0x9CF1 0x6ED6 # 0 +0x9CF2 0x6ED8 # 0 +0x9CF3 0x6ED9 # 0 +0x9CF4 0x6EDB # 0 +0x9CF5 0x6EDC # 0 +0x9CF6 0x6EDD # 0 +0x9CF7 0x6EE3 # 0 +0x9CF8 0x6EE7 # 0 +0x9CF9 0x6EEA # 0 +0x9CFA 0x6EEB # 0 +0x9CFB 0x6EEC # 0 +0x9CFC 0x6EED # 0 +0x9CFD 0x6EEE # 0 +0x9CFE 0x6EEF # 0 +0x9D40 0x6EF0 # 0 +0x9D41 0x6EF1 # 0 +0x9D42 0x6EF2 # 0 +0x9D43 0x6EF3 # 0 +0x9D44 0x6EF5 # 0 +0x9D45 0x6EF6 # 0 +0x9D46 0x6EF7 # 0 +0x9D47 0x6EF8 # 0 +0x9D48 0x6EFA # 0 +0x9D49 0x6EFB # 0 +0x9D4A 0x6EFC # 0 +0x9D4B 0x6EFD # 0 +0x9D4C 0x6EFE # 0 +0x9D4D 0x6EFF # 0 +0x9D4E 0x6F00 # 0 +0x9D4F 0x6F01 # 0 +0x9D50 0x6F03 # 0 +0x9D51 0x6F04 # 0 +0x9D52 0x6F05 # 0 +0x9D53 0x6F07 # 0 +0x9D54 0x6F08 # 0 +0x9D55 0x6F0A # 0 +0x9D56 0x6F0B # 0 +0x9D57 0x6F0C # 0 +0x9D58 0x6F0D # 0 +0x9D59 0x6F0E # 0 +0x9D5A 0x6F10 # 0 +0x9D5B 0x6F11 # 0 +0x9D5C 0x6F12 # 0 +0x9D5D 0x6F16 # 0 +0x9D5E 0x6F17 # 0 +0x9D5F 0x6F18 # 0 +0x9D60 0x6F19 # 0 +0x9D61 0x6F1A # 0 +0x9D62 0x6F1B # 0 +0x9D63 0x6F1C # 0 +0x9D64 0x6F1D # 0 +0x9D65 0x6F1E # 0 +0x9D66 0x6F1F # 0 +0x9D67 0x6F21 # 0 +0x9D68 0x6F22 # 0 +0x9D69 0x6F23 # 0 +0x9D6A 0x6F25 # 0 +0x9D6B 0x6F26 # 0 +0x9D6C 0x6F27 # 0 +0x9D6D 0x6F28 # 0 +0x9D6E 0x6F2C # 0 +0x9D6F 0x6F2E # 0 +0x9D70 0x6F30 # 0 +0x9D71 0x6F32 # 0 +0x9D72 0x6F34 # 0 +0x9D73 0x6F35 # 0 +0x9D74 0x6F37 # 0 +0x9D75 0x6F38 # 0 +0x9D76 0x6F39 # 0 +0x9D77 0x6F3A # 0 +0x9D78 0x6F3B # 0 +0x9D79 0x6F3C # 0 +0x9D7A 0x6F3D # 0 +0x9D7B 0x6F3F # 0 +0x9D7C 0x6F40 # 0 +0x9D7D 0x6F41 # 0 +0x9D7E 0x6F42 # 0 +0x9D80 0x6F43 # 0 +0x9D81 0x6F44 # 0 +0x9D82 0x6F45 # 0 +0x9D83 0x6F48 # 0 +0x9D84 0x6F49 # 0 +0x9D85 0x6F4A # 0 +0x9D86 0x6F4C # 0 +0x9D87 0x6F4E # 0 +0x9D88 0x6F4F # 0 +0x9D89 0x6F50 # 0 +0x9D8A 0x6F51 # 0 +0x9D8B 0x6F52 # 0 +0x9D8C 0x6F53 # 0 +0x9D8D 0x6F54 # 0 +0x9D8E 0x6F55 # 0 +0x9D8F 0x6F56 # 0 +0x9D90 0x6F57 # 0 +0x9D91 0x6F59 # 0 +0x9D92 0x6F5A # 0 +0x9D93 0x6F5B # 0 +0x9D94 0x6F5D # 0 +0x9D95 0x6F5F # 0 +0x9D96 0x6F60 # 0 +0x9D97 0x6F61 # 0 +0x9D98 0x6F63 # 0 +0x9D99 0x6F64 # 0 +0x9D9A 0x6F65 # 0 +0x9D9B 0x6F67 # 0 +0x9D9C 0x6F68 # 0 +0x9D9D 0x6F69 # 0 +0x9D9E 0x6F6A # 0 +0x9D9F 0x6F6B # 0 +0x9DA0 0x6F6C # 0 +0x9DA1 0x6F6F # 0 +0x9DA2 0x6F70 # 0 +0x9DA3 0x6F71 # 0 +0x9DA4 0x6F73 # 0 +0x9DA5 0x6F75 # 0 +0x9DA6 0x6F76 # 0 +0x9DA7 0x6F77 # 0 +0x9DA8 0x6F79 # 0 +0x9DA9 0x6F7B # 0 +0x9DAA 0x6F7D # 0 +0x9DAB 0x6F7E # 0 +0x9DAC 0x6F7F # 0 +0x9DAD 0x6F80 # 0 +0x9DAE 0x6F81 # 0 +0x9DAF 0x6F82 # 0 +0x9DB0 0x6F83 # 0 +0x9DB1 0x6F85 # 0 +0x9DB2 0x6F86 # 0 +0x9DB3 0x6F87 # 0 +0x9DB4 0x6F8A # 0 +0x9DB5 0x6F8B # 0 +0x9DB6 0x6F8F # 0 +0x9DB7 0x6F90 # 0 +0x9DB8 0x6F91 # 0 +0x9DB9 0x6F92 # 0 +0x9DBA 0x6F93 # 0 +0x9DBB 0x6F94 # 0 +0x9DBC 0x6F95 # 0 +0x9DBD 0x6F96 # 0 +0x9DBE 0x6F97 # 0 +0x9DBF 0x6F98 # 0 +0x9DC0 0x6F99 # 0 +0x9DC1 0x6F9A # 0 +0x9DC2 0x6F9B # 0 +0x9DC3 0x6F9D # 0 +0x9DC4 0x6F9E # 0 +0x9DC5 0x6F9F # 0 +0x9DC6 0x6FA0 # 0 +0x9DC7 0x6FA2 # 0 +0x9DC8 0x6FA3 # 0 +0x9DC9 0x6FA4 # 0 +0x9DCA 0x6FA5 # 0 +0x9DCB 0x6FA6 # 0 +0x9DCC 0x6FA8 # 0 +0x9DCD 0x6FA9 # 0 +0x9DCE 0x6FAA # 0 +0x9DCF 0x6FAB # 0 +0x9DD0 0x6FAC # 0 +0x9DD1 0x6FAD # 0 +0x9DD2 0x6FAE # 0 +0x9DD3 0x6FAF # 0 +0x9DD4 0x6FB0 # 0 +0x9DD5 0x6FB1 # 0 +0x9DD6 0x6FB2 # 0 +0x9DD7 0x6FB4 # 0 +0x9DD8 0x6FB5 # 0 +0x9DD9 0x6FB7 # 0 +0x9DDA 0x6FB8 # 0 +0x9DDB 0x6FBA # 0 +0x9DDC 0x6FBB # 0 +0x9DDD 0x6FBC # 0 +0x9DDE 0x6FBD # 0 +0x9DDF 0x6FBE # 0 +0x9DE0 0x6FBF # 0 +0x9DE1 0x6FC1 # 0 +0x9DE2 0x6FC3 # 0 +0x9DE3 0x6FC4 # 0 +0x9DE4 0x6FC5 # 0 +0x9DE5 0x6FC6 # 0 +0x9DE6 0x6FC7 # 0 +0x9DE7 0x6FC8 # 0 +0x9DE8 0x6FCA # 0 +0x9DE9 0x6FCB # 0 +0x9DEA 0x6FCC # 0 +0x9DEB 0x6FCD # 0 +0x9DEC 0x6FCE # 0 +0x9DED 0x6FCF # 0 +0x9DEE 0x6FD0 # 0 +0x9DEF 0x6FD3 # 0 +0x9DF0 0x6FD4 # 0 +0x9DF1 0x6FD5 # 0 +0x9DF2 0x6FD6 # 0 +0x9DF3 0x6FD7 # 0 +0x9DF4 0x6FD8 # 0 +0x9DF5 0x6FD9 # 0 +0x9DF6 0x6FDA # 0 +0x9DF7 0x6FDB # 0 +0x9DF8 0x6FDC # 0 +0x9DF9 0x6FDD # 0 +0x9DFA 0x6FDF # 0 +0x9DFB 0x6FE2 # 0 +0x9DFC 0x6FE3 # 0 +0x9DFD 0x6FE4 # 0 +0x9DFE 0x6FE5 # 0 +0x9E40 0x6FE6 # 0 +0x9E41 0x6FE7 # 0 +0x9E42 0x6FE8 # 0 +0x9E43 0x6FE9 # 0 +0x9E44 0x6FEA # 0 +0x9E45 0x6FEB # 0 +0x9E46 0x6FEC # 0 +0x9E47 0x6FED # 0 +0x9E48 0x6FF0 # 0 +0x9E49 0x6FF1 # 0 +0x9E4A 0x6FF2 # 0 +0x9E4B 0x6FF3 # 0 +0x9E4C 0x6FF4 # 0 +0x9E4D 0x6FF5 # 0 +0x9E4E 0x6FF6 # 0 +0x9E4F 0x6FF7 # 0 +0x9E50 0x6FF8 # 0 +0x9E51 0x6FF9 # 0 +0x9E52 0x6FFA # 0 +0x9E53 0x6FFB # 0 +0x9E54 0x6FFC # 0 +0x9E55 0x6FFD # 0 +0x9E56 0x6FFE # 0 +0x9E57 0x6FFF # 0 +0x9E58 0x7000 # 0 +0x9E59 0x7001 # 0 +0x9E5A 0x7002 # 0 +0x9E5B 0x7003 # 0 +0x9E5C 0x7004 # 0 +0x9E5D 0x7005 # 0 +0x9E5E 0x7006 # 0 +0x9E5F 0x7007 # 0 +0x9E60 0x7008 # 0 +0x9E61 0x7009 # 0 +0x9E62 0x700A # 0 +0x9E63 0x700B # 0 +0x9E64 0x700C # 0 +0x9E65 0x700D # 0 +0x9E66 0x700E # 0 +0x9E67 0x700F # 0 +0x9E68 0x7010 # 0 +0x9E69 0x7012 # 0 +0x9E6A 0x7013 # 0 +0x9E6B 0x7014 # 0 +0x9E6C 0x7015 # 0 +0x9E6D 0x7016 # 0 +0x9E6E 0x7017 # 0 +0x9E6F 0x7018 # 0 +0x9E70 0x7019 # 0 +0x9E71 0x701C # 0 +0x9E72 0x701D # 0 +0x9E73 0x701E # 0 +0x9E74 0x701F # 0 +0x9E75 0x7020 # 0 +0x9E76 0x7021 # 0 +0x9E77 0x7022 # 0 +0x9E78 0x7024 # 0 +0x9E79 0x7025 # 0 +0x9E7A 0x7026 # 0 +0x9E7B 0x7027 # 0 +0x9E7C 0x7028 # 0 +0x9E7D 0x7029 # 0 +0x9E7E 0x702A # 0 +0x9E80 0x702B # 0 +0x9E81 0x702C # 0 +0x9E82 0x702D # 0 +0x9E83 0x702E # 0 +0x9E84 0x702F # 0 +0x9E85 0x7030 # 0 +0x9E86 0x7031 # 0 +0x9E87 0x7032 # 0 +0x9E88 0x7033 # 0 +0x9E89 0x7034 # 0 +0x9E8A 0x7036 # 0 +0x9E8B 0x7037 # 0 +0x9E8C 0x7038 # 0 +0x9E8D 0x703A # 0 +0x9E8E 0x703B # 0 +0x9E8F 0x703C # 0 +0x9E90 0x703D # 0 +0x9E91 0x703E # 0 +0x9E92 0x703F # 0 +0x9E93 0x7040 # 0 +0x9E94 0x7041 # 0 +0x9E95 0x7042 # 0 +0x9E96 0x7043 # 0 +0x9E97 0x7044 # 0 +0x9E98 0x7045 # 0 +0x9E99 0x7046 # 0 +0x9E9A 0x7047 # 0 +0x9E9B 0x7048 # 0 +0x9E9C 0x7049 # 0 +0x9E9D 0x704A # 0 +0x9E9E 0x704B # 0 +0x9E9F 0x704D # 0 +0x9EA0 0x704E # 0 +0x9EA1 0x7050 # 0 +0x9EA2 0x7051 # 0 +0x9EA3 0x7052 # 0 +0x9EA4 0x7053 # 0 +0x9EA5 0x7054 # 0 +0x9EA6 0x7055 # 0 +0x9EA7 0x7056 # 0 +0x9EA8 0x7057 # 0 +0x9EA9 0x7058 # 0 +0x9EAA 0x7059 # 0 +0x9EAB 0x705A # 0 +0x9EAC 0x705B # 0 +0x9EAD 0x705C # 0 +0x9EAE 0x705D # 0 +0x9EAF 0x705F # 0 +0x9EB0 0x7060 # 0 +0x9EB1 0x7061 # 0 +0x9EB2 0x7062 # 0 +0x9EB3 0x7063 # 0 +0x9EB4 0x7064 # 0 +0x9EB5 0x7065 # 0 +0x9EB6 0x7066 # 0 +0x9EB7 0x7067 # 0 +0x9EB8 0x7068 # 0 +0x9EB9 0x7069 # 0 +0x9EBA 0x706A # 0 +0x9EBB 0x706E # 0 +0x9EBC 0x7071 # 0 +0x9EBD 0x7072 # 0 +0x9EBE 0x7073 # 0 +0x9EBF 0x7074 # 0 +0x9EC0 0x7077 # 0 +0x9EC1 0x7079 # 0 +0x9EC2 0x707A # 0 +0x9EC3 0x707B # 0 +0x9EC4 0x707D # 0 +0x9EC5 0x7081 # 0 +0x9EC6 0x7082 # 0 +0x9EC7 0x7083 # 0 +0x9EC8 0x7084 # 0 +0x9EC9 0x7086 # 0 +0x9ECA 0x7087 # 0 +0x9ECB 0x7088 # 0 +0x9ECC 0x708B # 0 +0x9ECD 0x708C # 0 +0x9ECE 0x708D # 0 +0x9ECF 0x708F # 0 +0x9ED0 0x7090 # 0 +0x9ED1 0x7091 # 0 +0x9ED2 0x7093 # 0 +0x9ED3 0x7097 # 0 +0x9ED4 0x7098 # 0 +0x9ED5 0x709A # 0 +0x9ED6 0x709B # 0 +0x9ED7 0x709E # 0 +0x9ED8 0x709F # 0 +0x9ED9 0x70A0 # 0 +0x9EDA 0x70A1 # 0 +0x9EDB 0x70A2 # 0 +0x9EDC 0x70A3 # 0 +0x9EDD 0x70A4 # 0 +0x9EDE 0x70A5 # 0 +0x9EDF 0x70A6 # 0 +0x9EE0 0x70A7 # 0 +0x9EE1 0x70A8 # 0 +0x9EE2 0x70A9 # 0 +0x9EE3 0x70AA # 0 +0x9EE4 0x70B0 # 0 +0x9EE5 0x70B2 # 0 +0x9EE6 0x70B4 # 0 +0x9EE7 0x70B5 # 0 +0x9EE8 0x70B6 # 0 +0x9EE9 0x70BA # 0 +0x9EEA 0x70BE # 0 +0x9EEB 0x70BF # 0 +0x9EEC 0x70C4 # 0 +0x9EED 0x70C5 # 0 +0x9EEE 0x70C6 # 0 +0x9EEF 0x70C7 # 0 +0x9EF0 0x70C9 # 0 +0x9EF1 0x70CB # 0 +0x9EF2 0x70CC # 0 +0x9EF3 0x70CD # 0 +0x9EF4 0x70CE # 0 +0x9EF5 0x70CF # 0 +0x9EF6 0x70D0 # 0 +0x9EF7 0x70D1 # 0 +0x9EF8 0x70D2 # 0 +0x9EF9 0x70D3 # 0 +0x9EFA 0x70D4 # 0 +0x9EFB 0x70D5 # 0 +0x9EFC 0x70D6 # 0 +0x9EFD 0x70D7 # 0 +0x9EFE 0x70DA # 0 +0x9F40 0x70DC # 0 +0x9F41 0x70DD # 0 +0x9F42 0x70DE # 0 +0x9F43 0x70E0 # 0 +0x9F44 0x70E1 # 0 +0x9F45 0x70E2 # 0 +0x9F46 0x70E3 # 0 +0x9F47 0x70E5 # 0 +0x9F48 0x70EA # 0 +0x9F49 0x70EE # 0 +0x9F4A 0x70F0 # 0 +0x9F4B 0x70F1 # 0 +0x9F4C 0x70F2 # 0 +0x9F4D 0x70F3 # 0 +0x9F4E 0x70F4 # 0 +0x9F4F 0x70F5 # 0 +0x9F50 0x70F6 # 0 +0x9F51 0x70F8 # 0 +0x9F52 0x70FA # 0 +0x9F53 0x70FB # 0 +0x9F54 0x70FC # 0 +0x9F55 0x70FE # 0 +0x9F56 0x70FF # 0 +0x9F57 0x7100 # 0 +0x9F58 0x7101 # 0 +0x9F59 0x7102 # 0 +0x9F5A 0x7103 # 0 +0x9F5B 0x7104 # 0 +0x9F5C 0x7105 # 0 +0x9F5D 0x7106 # 0 +0x9F5E 0x7107 # 0 +0x9F5F 0x7108 # 0 +0x9F60 0x710B # 0 +0x9F61 0x710C # 0 +0x9F62 0x710D # 0 +0x9F63 0x710E # 0 +0x9F64 0x710F # 0 +0x9F65 0x7111 # 0 +0x9F66 0x7112 # 0 +0x9F67 0x7114 # 0 +0x9F68 0x7117 # 0 +0x9F69 0x711B # 0 +0x9F6A 0x711C # 0 +0x9F6B 0x711D # 0 +0x9F6C 0x711E # 0 +0x9F6D 0x711F # 0 +0x9F6E 0x7120 # 0 +0x9F6F 0x7121 # 0 +0x9F70 0x7122 # 0 +0x9F71 0x7123 # 0 +0x9F72 0x7124 # 0 +0x9F73 0x7125 # 0 +0x9F74 0x7127 # 0 +0x9F75 0x7128 # 0 +0x9F76 0x7129 # 0 +0x9F77 0x712A # 0 +0x9F78 0x712B # 0 +0x9F79 0x712C # 0 +0x9F7A 0x712D # 0 +0x9F7B 0x712E # 0 +0x9F7C 0x7132 # 0 +0x9F7D 0x7133 # 0 +0x9F7E 0x7134 # 0 +0x9F80 0x7135 # 0 +0x9F81 0x7137 # 0 +0x9F82 0x7138 # 0 +0x9F83 0x7139 # 0 +0x9F84 0x713A # 0 +0x9F85 0x713B # 0 +0x9F86 0x713C # 0 +0x9F87 0x713D # 0 +0x9F88 0x713E # 0 +0x9F89 0x713F # 0 +0x9F8A 0x7140 # 0 +0x9F8B 0x7141 # 0 +0x9F8C 0x7142 # 0 +0x9F8D 0x7143 # 0 +0x9F8E 0x7144 # 0 +0x9F8F 0x7146 # 0 +0x9F90 0x7147 # 0 +0x9F91 0x7148 # 0 +0x9F92 0x7149 # 0 +0x9F93 0x714B # 0 +0x9F94 0x714D # 0 +0x9F95 0x714F # 0 +0x9F96 0x7150 # 0 +0x9F97 0x7151 # 0 +0x9F98 0x7152 # 0 +0x9F99 0x7153 # 0 +0x9F9A 0x7154 # 0 +0x9F9B 0x7155 # 0 +0x9F9C 0x7156 # 0 +0x9F9D 0x7157 # 0 +0x9F9E 0x7158 # 0 +0x9F9F 0x7159 # 0 +0x9FA0 0x715A # 0 +0x9FA1 0x715B # 0 +0x9FA2 0x715D # 0 +0x9FA3 0x715F # 0 +0x9FA4 0x7160 # 0 +0x9FA5 0x7161 # 0 +0x9FA6 0x7162 # 0 +0x9FA7 0x7163 # 0 +0x9FA8 0x7165 # 0 +0x9FA9 0x7169 # 0 +0x9FAA 0x716A # 0 +0x9FAB 0x716B # 0 +0x9FAC 0x716C # 0 +0x9FAD 0x716D # 0 +0x9FAE 0x716F # 0 +0x9FAF 0x7170 # 0 +0x9FB0 0x7171 # 0 +0x9FB1 0x7174 # 0 +0x9FB2 0x7175 # 0 +0x9FB3 0x7176 # 0 +0x9FB4 0x7177 # 0 +0x9FB5 0x7179 # 0 +0x9FB6 0x717B # 0 +0x9FB7 0x717C # 0 +0x9FB8 0x717E # 0 +0x9FB9 0x717F # 0 +0x9FBA 0x7180 # 0 +0x9FBB 0x7181 # 0 +0x9FBC 0x7182 # 0 +0x9FBD 0x7183 # 0 +0x9FBE 0x7185 # 0 +0x9FBF 0x7186 # 0 +0x9FC0 0x7187 # 0 +0x9FC1 0x7188 # 0 +0x9FC2 0x7189 # 0 +0x9FC3 0x718B # 0 +0x9FC4 0x718C # 0 +0x9FC5 0x718D # 0 +0x9FC6 0x718E # 0 +0x9FC7 0x7190 # 0 +0x9FC8 0x7191 # 0 +0x9FC9 0x7192 # 0 +0x9FCA 0x7193 # 0 +0x9FCB 0x7195 # 0 +0x9FCC 0x7196 # 0 +0x9FCD 0x7197 # 0 +0x9FCE 0x719A # 0 +0x9FCF 0x719B # 0 +0x9FD0 0x719C # 0 +0x9FD1 0x719D # 0 +0x9FD2 0x719E # 0 +0x9FD3 0x71A1 # 0 +0x9FD4 0x71A2 # 0 +0x9FD5 0x71A3 # 0 +0x9FD6 0x71A4 # 0 +0x9FD7 0x71A5 # 0 +0x9FD8 0x71A6 # 0 +0x9FD9 0x71A7 # 0 +0x9FDA 0x71A9 # 0 +0x9FDB 0x71AA # 0 +0x9FDC 0x71AB # 0 +0x9FDD 0x71AD # 0 +0x9FDE 0x71AE # 0 +0x9FDF 0x71AF # 0 +0x9FE0 0x71B0 # 0 +0x9FE1 0x71B1 # 0 +0x9FE2 0x71B2 # 0 +0x9FE3 0x71B4 # 0 +0x9FE4 0x71B6 # 0 +0x9FE5 0x71B7 # 0 +0x9FE6 0x71B8 # 0 +0x9FE7 0x71BA # 0 +0x9FE8 0x71BB # 0 +0x9FE9 0x71BC # 0 +0x9FEA 0x71BD # 0 +0x9FEB 0x71BE # 0 +0x9FEC 0x71BF # 0 +0x9FED 0x71C0 # 0 +0x9FEE 0x71C1 # 0 +0x9FEF 0x71C2 # 0 +0x9FF0 0x71C4 # 0 +0x9FF1 0x71C5 # 0 +0x9FF2 0x71C6 # 0 +0x9FF3 0x71C7 # 0 +0x9FF4 0x71C8 # 0 +0x9FF5 0x71C9 # 0 +0x9FF6 0x71CA # 0 +0x9FF7 0x71CB # 0 +0x9FF8 0x71CC # 0 +0x9FF9 0x71CD # 0 +0x9FFA 0x71CF # 0 +0x9FFB 0x71D0 # 0 +0x9FFC 0x71D1 # 0 +0x9FFD 0x71D2 # 0 +0x9FFE 0x71D3 # 0 +0xA040 0x71D6 # 0 +0xA041 0x71D7 # 0 +0xA042 0x71D8 # 0 +0xA043 0x71D9 # 0 +0xA044 0x71DA # 0 +0xA045 0x71DB # 0 +0xA046 0x71DC # 0 +0xA047 0x71DD # 0 +0xA048 0x71DE # 0 +0xA049 0x71DF # 0 +0xA04A 0x71E1 # 0 +0xA04B 0x71E2 # 0 +0xA04C 0x71E3 # 0 +0xA04D 0x71E4 # 0 +0xA04E 0x71E6 # 0 +0xA04F 0x71E8 # 0 +0xA050 0x71E9 # 0 +0xA051 0x71EA # 0 +0xA052 0x71EB # 0 +0xA053 0x71EC # 0 +0xA054 0x71ED # 0 +0xA055 0x71EF # 0 +0xA056 0x71F0 # 0 +0xA057 0x71F1 # 0 +0xA058 0x71F2 # 0 +0xA059 0x71F3 # 0 +0xA05A 0x71F4 # 0 +0xA05B 0x71F5 # 0 +0xA05C 0x71F6 # 0 +0xA05D 0x71F7 # 0 +0xA05E 0x71F8 # 0 +0xA05F 0x71FA # 0 +0xA060 0x71FB # 0 +0xA061 0x71FC # 0 +0xA062 0x71FD # 0 +0xA063 0x71FE # 0 +0xA064 0x71FF # 0 +0xA065 0x7200 # 0 +0xA066 0x7201 # 0 +0xA067 0x7202 # 0 +0xA068 0x7203 # 0 +0xA069 0x7204 # 0 +0xA06A 0x7205 # 0 +0xA06B 0x7207 # 0 +0xA06C 0x7208 # 0 +0xA06D 0x7209 # 0 +0xA06E 0x720A # 0 +0xA06F 0x720B # 0 +0xA070 0x720C # 0 +0xA071 0x720D # 0 +0xA072 0x720E # 0 +0xA073 0x720F # 0 +0xA074 0x7210 # 0 +0xA075 0x7211 # 0 +0xA076 0x7212 # 0 +0xA077 0x7213 # 0 +0xA078 0x7214 # 0 +0xA079 0x7215 # 0 +0xA07A 0x7216 # 0 +0xA07B 0x7217 # 0 +0xA07C 0x7218 # 0 +0xA07D 0x7219 # 0 +0xA07E 0x721A # 0 +0xA080 0x721B # 0 +0xA081 0x721C # 0 +0xA082 0x721E # 0 +0xA083 0x721F # 0 +0xA084 0x7220 # 0 +0xA085 0x7221 # 0 +0xA086 0x7222 # 0 +0xA087 0x7223 # 0 +0xA088 0x7224 # 0 +0xA089 0x7225 # 0 +0xA08A 0x7226 # 0 +0xA08B 0x7227 # 0 +0xA08C 0x7229 # 0 +0xA08D 0x722B # 0 +0xA08E 0x722D # 0 +0xA08F 0x722E # 0 +0xA090 0x722F # 0 +0xA091 0x7232 # 0 +0xA092 0x7233 # 0 +0xA093 0x7234 # 0 +0xA094 0x723A # 0 +0xA095 0x723C # 0 +0xA096 0x723E # 0 +0xA097 0x7240 # 0 +0xA098 0x7241 # 0 +0xA099 0x7242 # 0 +0xA09A 0x7243 # 0 +0xA09B 0x7244 # 0 +0xA09C 0x7245 # 0 +0xA09D 0x7246 # 0 +0xA09E 0x7249 # 0 +0xA09F 0x724A # 0 +0xA0A0 0x724B # 0 +0xA0A1 0x724E # 0 +0xA0A2 0x724F # 0 +0xA0A3 0x7250 # 0 +0xA0A4 0x7251 # 0 +0xA0A5 0x7253 # 0 +0xA0A6 0x7254 # 0 +0xA0A7 0x7255 # 0 +0xA0A8 0x7257 # 0 +0xA0A9 0x7258 # 0 +0xA0AA 0x725A # 0 +0xA0AB 0x725C # 0 +0xA0AC 0x725E # 0 +0xA0AD 0x7260 # 0 +0xA0AE 0x7263 # 0 +0xA0AF 0x7264 # 0 +0xA0B0 0x7265 # 0 +0xA0B1 0x7268 # 0 +0xA0B2 0x726A # 0 +0xA0B3 0x726B # 0 +0xA0B4 0x726C # 0 +0xA0B5 0x726D # 0 +0xA0B6 0x7270 # 0 +0xA0B7 0x7271 # 0 +0xA0B8 0x7273 # 0 +0xA0B9 0x7274 # 0 +0xA0BA 0x7276 # 0 +0xA0BB 0x7277 # 0 +0xA0BC 0x7278 # 0 +0xA0BD 0x727B # 0 +0xA0BE 0x727C # 0 +0xA0BF 0x727D # 0 +0xA0C0 0x7282 # 0 +0xA0C1 0x7283 # 0 +0xA0C2 0x7285 # 0 +0xA0C3 0x7286 # 0 +0xA0C4 0x7287 # 0 +0xA0C5 0x7288 # 0 +0xA0C6 0x7289 # 0 +0xA0C7 0x728C # 0 +0xA0C8 0x728E # 0 +0xA0C9 0x7290 # 0 +0xA0CA 0x7291 # 0 +0xA0CB 0x7293 # 0 +0xA0CC 0x7294 # 0 +0xA0CD 0x7295 # 0 +0xA0CE 0x7296 # 0 +0xA0CF 0x7297 # 0 +0xA0D0 0x7298 # 0 +0xA0D1 0x7299 # 0 +0xA0D2 0x729A # 0 +0xA0D3 0x729B # 0 +0xA0D4 0x729C # 0 +0xA0D5 0x729D # 0 +0xA0D6 0x729E # 0 +0xA0D7 0x72A0 # 0 +0xA0D8 0x72A1 # 0 +0xA0D9 0x72A2 # 0 +0xA0DA 0x72A3 # 0 +0xA0DB 0x72A4 # 0 +0xA0DC 0x72A5 # 0 +0xA0DD 0x72A6 # 0 +0xA0DE 0x72A7 # 0 +0xA0DF 0x72A8 # 0 +0xA0E0 0x72A9 # 0 +0xA0E1 0x72AA # 0 +0xA0E2 0x72AB # 0 +0xA0E3 0x72AE # 0 +0xA0E4 0x72B1 # 0 +0xA0E5 0x72B2 # 0 +0xA0E6 0x72B3 # 0 +0xA0E7 0x72B5 # 0 +0xA0E8 0x72BA # 0 +0xA0E9 0x72BB # 0 +0xA0EA 0x72BC # 0 +0xA0EB 0x72BD # 0 +0xA0EC 0x72BE # 0 +0xA0ED 0x72BF # 0 +0xA0EE 0x72C0 # 0 +0xA0EF 0x72C5 # 0 +0xA0F0 0x72C6 # 0 +0xA0F1 0x72C7 # 0 +0xA0F2 0x72C9 # 0 +0xA0F3 0x72CA # 0 +0xA0F4 0x72CB # 0 +0xA0F5 0x72CC # 0 +0xA0F6 0x72CF # 0 +0xA0F7 0x72D1 # 0 +0xA0F8 0x72D3 # 0 +0xA0F9 0x72D4 # 0 +0xA0FA 0x72D5 # 0 +0xA0FB 0x72D6 # 0 +0xA0FC 0x72D8 # 0 +0xA0FD 0x72DA # 0 +0xA0FE 0x72DB # 0 +0xA140 0xE4C6 # 0 +0xA141 0xE4C7 # 0 +0xA142 0xE4C8 # 0 +0xA143 0xE4C9 # 0 +0xA144 0xE4CA # 0 +0xA145 0xE4CB # 0 +0xA146 0xE4CC # 0 +0xA147 0xE4CD # 0 +0xA148 0xE4CE # 0 +0xA149 0xE4CF # 0 +0xA14A 0xE4D0 # 0 +0xA14B 0xE4D1 # 0 +0xA14C 0xE4D2 # 0 +0xA14D 0xE4D3 # 0 +0xA14E 0xE4D4 # 0 +0xA14F 0xE4D5 # 0 +0xA150 0xE4D6 # 0 +0xA151 0xE4D7 # 0 +0xA152 0xE4D8 # 0 +0xA153 0xE4D9 # 0 +0xA154 0xE4DA # 0 +0xA155 0xE4DB # 0 +0xA156 0xE4DC # 0 +0xA157 0xE4DD # 0 +0xA158 0xE4DE # 0 +0xA159 0xE4DF # 0 +0xA15A 0xE4E0 # 0 +0xA15B 0xE4E1 # 0 +0xA15C 0xE4E2 # 0 +0xA15D 0xE4E3 # 0 +0xA15E 0xE4E4 # 0 +0xA15F 0xE4E5 # 0 +0xA160 0xE4E6 # 0 +0xA161 0xE4E7 # 0 +0xA162 0xE4E8 # 0 +0xA163 0xE4E9 # 0 +0xA164 0xE4EA # 0 +0xA165 0xE4EB # 0 +0xA166 0xE4EC # 0 +0xA167 0xE4ED # 0 +0xA168 0xE4EE # 0 +0xA169 0xE4EF # 0 +0xA16A 0xE4F0 # 0 +0xA16B 0xE4F1 # 0 +0xA16C 0xE4F2 # 0 +0xA16D 0xE4F3 # 0 +0xA16E 0xE4F4 # 0 +0xA16F 0xE4F5 # 0 +0xA170 0xE4F6 # 0 +0xA171 0xE4F7 # 0 +0xA172 0xE4F8 # 0 +0xA173 0xE4F9 # 0 +0xA174 0xE4FA # 0 +0xA175 0xE4FB # 0 +0xA176 0xE4FC # 0 +0xA177 0xE4FD # 0 +0xA178 0xE4FE # 0 +0xA179 0xE4FF # 0 +0xA17A 0xE500 # 0 +0xA17B 0xE501 # 0 +0xA17C 0xE502 # 0 +0xA17D 0xE503 # 0 +0xA17E 0xE504 # 0 +0xA180 0xE505 # 0 +0xA181 0xE506 # 0 +0xA182 0xE507 # 0 +0xA183 0xE508 # 0 +0xA184 0xE509 # 0 +0xA185 0xE50A # 0 +0xA186 0xE50B # 0 +0xA187 0xE50C # 0 +0xA188 0xE50D # 0 +0xA189 0xE50E # 0 +0xA18A 0xE50F # 0 +0xA18B 0xE510 # 0 +0xA18C 0xE511 # 0 +0xA18D 0xE512 # 0 +0xA18E 0xE513 # 0 +0xA18F 0xE514 # 0 +0xA190 0xE515 # 0 +0xA191 0xE516 # 0 +0xA192 0xE517 # 0 +0xA193 0xE518 # 0 +0xA194 0xE519 # 0 +0xA195 0xE51A # 0 +0xA196 0xE51B # 0 +0xA197 0xE51C # 0 +0xA198 0xE51D # 0 +0xA199 0xE51E # 0 +0xA19A 0xE51F # 0 +0xA19B 0xE520 # 0 +0xA19C 0xE521 # 0 +0xA19D 0xE522 # 0 +0xA19E 0xE523 # 0 +0xA19F 0xE524 # 0 +0xA1A0 0xE525 # 0 +0xA1A1 0x3000 # 0 +0xA1A2 0x3001 # 0 +0xA1A3 0x3002 # 0 +0xA1A4 0x00B7 # 0 +0xA1A5 0x02C9 # 0 +0xA1A6 0x02C7 # 0 +0xA1A7 0x00A8 # 0 +0xA1A8 0x3003 # 0 +0xA1A9 0x3005 # 0 +0xA1AA 0x2014 # 0 +0xA1AB 0xFF5E # 0 +0xA1AC 0x2016 # 0 +0xA1AD 0x2026 # 0 +0xA1AE 0x2018 # 0 +0xA1AF 0x2019 # 0 +0xA1B0 0x201C # 0 +0xA1B1 0x201D # 0 +0xA1B2 0x3014 # 0 +0xA1B3 0x3015 # 0 +0xA1B4 0x3008 # 0 +0xA1B5 0x3009 # 0 +0xA1B6 0x300A # 0 +0xA1B7 0x300B # 0 +0xA1B8 0x300C # 0 +0xA1B9 0x300D # 0 +0xA1BA 0x300E # 0 +0xA1BB 0x300F # 0 +0xA1BC 0x3016 # 0 +0xA1BD 0x3017 # 0 +0xA1BE 0x3010 # 0 +0xA1BF 0x3011 # 0 +0xA1C0 0x00B1 # 0 +0xA1C1 0x00D7 # 0 +0xA1C2 0x00F7 # 0 +0xA1C3 0x2236 # 0 +0xA1C4 0x2227 # 0 +0xA1C5 0x2228 # 0 +0xA1C6 0x2211 # 0 +0xA1C7 0x220F # 0 +0xA1C8 0x222A # 0 +0xA1C9 0x2229 # 0 +0xA1CA 0x2208 # 0 +0xA1CB 0x2237 # 0 +0xA1CC 0x221A # 0 +0xA1CD 0x22A5 # 0 +0xA1CE 0x2225 # 0 +0xA1CF 0x2220 # 0 +0xA1D0 0x2312 # 0 +0xA1D1 0x2299 # 0 +0xA1D2 0x222B # 0 +0xA1D3 0x222E # 0 +0xA1D4 0x2261 # 0 +0xA1D5 0x224C # 0 +0xA1D6 0x2248 # 0 +0xA1D7 0x223D # 0 +0xA1D8 0x221D # 0 +0xA1D9 0x2260 # 0 +0xA1DA 0x226E # 0 +0xA1DB 0x226F # 0 +0xA1DC 0x2264 # 0 +0xA1DD 0x2265 # 0 +0xA1DE 0x221E # 0 +0xA1DF 0x2235 # 0 +0xA1E0 0x2234 # 0 +0xA1E1 0x2642 # 0 +0xA1E2 0x2640 # 0 +0xA1E3 0x00B0 # 0 +0xA1E4 0x2032 # 0 +0xA1E5 0x2033 # 0 +0xA1E6 0x2103 # 0 +0xA1E7 0xFF04 # 0 +0xA1E8 0x00A4 # 0 +0xA1E9 0xFFE0 # 0 +0xA1EA 0xFFE1 # 0 +0xA1EB 0x2030 # 0 +0xA1EC 0x00A7 # 0 +0xA1ED 0x2116 # 0 +0xA1EE 0x2606 # 0 +0xA1EF 0x2605 # 0 +0xA1F0 0x25CB # 0 +0xA1F1 0x25CF # 0 +0xA1F2 0x25CE # 0 +0xA1F3 0x25C7 # 0 +0xA1F4 0x25C6 # 0 +0xA1F5 0x25A1 # 0 +0xA1F6 0x25A0 # 0 +0xA1F7 0x25B3 # 0 +0xA1F8 0x25B2 # 0 +0xA1F9 0x203B # 0 +0xA1FA 0x2192 # 0 +0xA1FB 0x2190 # 0 +0xA1FC 0x2191 # 0 +0xA1FD 0x2193 # 0 +0xA1FE 0x3013 # 0 +0xA240 0xE526 # 0 +0xA241 0xE527 # 0 +0xA242 0xE528 # 0 +0xA243 0xE529 # 0 +0xA244 0xE52A # 0 +0xA245 0xE52B # 0 +0xA246 0xE52C # 0 +0xA247 0xE52D # 0 +0xA248 0xE52E # 0 +0xA249 0xE52F # 0 +0xA24A 0xE530 # 0 +0xA24B 0xE531 # 0 +0xA24C 0xE532 # 0 +0xA24D 0xE533 # 0 +0xA24E 0xE534 # 0 +0xA24F 0xE535 # 0 +0xA250 0xE536 # 0 +0xA251 0xE537 # 0 +0xA252 0xE538 # 0 +0xA253 0xE539 # 0 +0xA254 0xE53A # 0 +0xA255 0xE53B # 0 +0xA256 0xE53C # 0 +0xA257 0xE53D # 0 +0xA258 0xE53E # 0 +0xA259 0xE53F # 0 +0xA25A 0xE540 # 0 +0xA25B 0xE541 # 0 +0xA25C 0xE542 # 0 +0xA25D 0xE543 # 0 +0xA25E 0xE544 # 0 +0xA25F 0xE545 # 0 +0xA260 0xE546 # 0 +0xA261 0xE547 # 0 +0xA262 0xE548 # 0 +0xA263 0xE549 # 0 +0xA264 0xE54A # 0 +0xA265 0xE54B # 0 +0xA266 0xE54C # 0 +0xA267 0xE54D # 0 +0xA268 0xE54E # 0 +0xA269 0xE54F # 0 +0xA26A 0xE550 # 0 +0xA26B 0xE551 # 0 +0xA26C 0xE552 # 0 +0xA26D 0xE553 # 0 +0xA26E 0xE554 # 0 +0xA26F 0xE555 # 0 +0xA270 0xE556 # 0 +0xA271 0xE557 # 0 +0xA272 0xE558 # 0 +0xA273 0xE559 # 0 +0xA274 0xE55A # 0 +0xA275 0xE55B # 0 +0xA276 0xE55C # 0 +0xA277 0xE55D # 0 +0xA278 0xE55E # 0 +0xA279 0xE55F # 0 +0xA27A 0xE560 # 0 +0xA27B 0xE561 # 0 +0xA27C 0xE562 # 0 +0xA27D 0xE563 # 0 +0xA27E 0xE564 # 0 +0xA280 0xE565 # 0 +0xA281 0xE566 # 0 +0xA282 0xE567 # 0 +0xA283 0xE568 # 0 +0xA284 0xE569 # 0 +0xA285 0xE56A # 0 +0xA286 0xE56B # 0 +0xA287 0xE56C # 0 +0xA288 0xE56D # 0 +0xA289 0xE56E # 0 +0xA28A 0xE56F # 0 +0xA28B 0xE570 # 0 +0xA28C 0xE571 # 0 +0xA28D 0xE572 # 0 +0xA28E 0xE573 # 0 +0xA28F 0xE574 # 0 +0xA290 0xE575 # 0 +0xA291 0xE576 # 0 +0xA292 0xE577 # 0 +0xA293 0xE578 # 0 +0xA294 0xE579 # 0 +0xA295 0xE57A # 0 +0xA296 0xE57B # 0 +0xA297 0xE57C # 0 +0xA298 0xE57D # 0 +0xA299 0xE57E # 0 +0xA29A 0xE57F # 0 +0xA29B 0xE580 # 0 +0xA29C 0xE581 # 0 +0xA29D 0xE582 # 0 +0xA29E 0xE583 # 0 +0xA29F 0xE584 # 0 +0xA2A0 0xE585 # 0 +0xA2A1 0x2170 # 0 +0xA2A2 0x2171 # 0 +0xA2A3 0x2172 # 0 +0xA2A4 0x2173 # 0 +0xA2A5 0x2174 # 0 +0xA2A6 0x2175 # 0 +0xA2A7 0x2176 # 0 +0xA2A8 0x2177 # 0 +0xA2A9 0x2178 # 0 +0xA2AA 0x2179 # 0 +0xA2AB 0xE766 # 0 +0xA2AC 0xE767 # 0 +0xA2AD 0xE768 # 0 +0xA2AE 0xE769 # 0 +0xA2AF 0xE76A # 0 +0xA2B0 0xE76B # 0 +0xA2B1 0x2488 # 0 +0xA2B2 0x2489 # 0 +0xA2B3 0x248A # 0 +0xA2B4 0x248B # 0 +0xA2B5 0x248C # 0 +0xA2B6 0x248D # 0 +0xA2B7 0x248E # 0 +0xA2B8 0x248F # 0 +0xA2B9 0x2490 # 0 +0xA2BA 0x2491 # 0 +0xA2BB 0x2492 # 0 +0xA2BC 0x2493 # 0 +0xA2BD 0x2494 # 0 +0xA2BE 0x2495 # 0 +0xA2BF 0x2496 # 0 +0xA2C0 0x2497 # 0 +0xA2C1 0x2498 # 0 +0xA2C2 0x2499 # 0 +0xA2C3 0x249A # 0 +0xA2C4 0x249B # 0 +0xA2C5 0x2474 # 0 +0xA2C6 0x2475 # 0 +0xA2C7 0x2476 # 0 +0xA2C8 0x2477 # 0 +0xA2C9 0x2478 # 0 +0xA2CA 0x2479 # 0 +0xA2CB 0x247A # 0 +0xA2CC 0x247B # 0 +0xA2CD 0x247C # 0 +0xA2CE 0x247D # 0 +0xA2CF 0x247E # 0 +0xA2D0 0x247F # 0 +0xA2D1 0x2480 # 0 +0xA2D2 0x2481 # 0 +0xA2D3 0x2482 # 0 +0xA2D4 0x2483 # 0 +0xA2D5 0x2484 # 0 +0xA2D6 0x2485 # 0 +0xA2D7 0x2486 # 0 +0xA2D8 0x2487 # 0 +0xA2D9 0x2460 # 0 +0xA2DA 0x2461 # 0 +0xA2DB 0x2462 # 0 +0xA2DC 0x2463 # 0 +0xA2DD 0x2464 # 0 +0xA2DE 0x2465 # 0 +0xA2DF 0x2466 # 0 +0xA2E0 0x2467 # 0 +0xA2E1 0x2468 # 0 +0xA2E2 0x2469 # 0 +0xA2E3 0xE76C # 0 +0xA2E4 0xE76D # 0 +0xA2E5 0x3220 # 0 +0xA2E6 0x3221 # 0 +0xA2E7 0x3222 # 0 +0xA2E8 0x3223 # 0 +0xA2E9 0x3224 # 0 +0xA2EA 0x3225 # 0 +0xA2EB 0x3226 # 0 +0xA2EC 0x3227 # 0 +0xA2ED 0x3228 # 0 +0xA2EE 0x3229 # 0 +0xA2EF 0xE76E # 0 +0xA2F0 0xE76F # 0 +0xA2F1 0x2160 # 0 +0xA2F2 0x2161 # 0 +0xA2F3 0x2162 # 0 +0xA2F4 0x2163 # 0 +0xA2F5 0x2164 # 0 +0xA2F6 0x2165 # 0 +0xA2F7 0x2166 # 0 +0xA2F8 0x2167 # 0 +0xA2F9 0x2168 # 0 +0xA2FA 0x2169 # 0 +0xA2FB 0x216A # 0 +0xA2FC 0x216B # 0 +0xA2FD 0xE770 # 0 +0xA2FE 0xE771 # 0 +0xA340 0xE586 # 0 +0xA341 0xE587 # 0 +0xA342 0xE588 # 0 +0xA343 0xE589 # 0 +0xA344 0xE58A # 0 +0xA345 0xE58B # 0 +0xA346 0xE58C # 0 +0xA347 0xE58D # 0 +0xA348 0xE58E # 0 +0xA349 0xE58F # 0 +0xA34A 0xE590 # 0 +0xA34B 0xE591 # 0 +0xA34C 0xE592 # 0 +0xA34D 0xE593 # 0 +0xA34E 0xE594 # 0 +0xA34F 0xE595 # 0 +0xA350 0xE596 # 0 +0xA351 0xE597 # 0 +0xA352 0xE598 # 0 +0xA353 0xE599 # 0 +0xA354 0xE59A # 0 +0xA355 0xE59B # 0 +0xA356 0xE59C # 0 +0xA357 0xE59D # 0 +0xA358 0xE59E # 0 +0xA359 0xE59F # 0 +0xA35A 0xE5A0 # 0 +0xA35B 0xE5A1 # 0 +0xA35C 0xE5A2 # 0 +0xA35D 0xE5A3 # 0 +0xA35E 0xE5A4 # 0 +0xA35F 0xE5A5 # 0 +0xA360 0xE5A6 # 0 +0xA361 0xE5A7 # 0 +0xA362 0xE5A8 # 0 +0xA363 0xE5A9 # 0 +0xA364 0xE5AA # 0 +0xA365 0xE5AB # 0 +0xA366 0xE5AC # 0 +0xA367 0xE5AD # 0 +0xA368 0xE5AE # 0 +0xA369 0xE5AF # 0 +0xA36A 0xE5B0 # 0 +0xA36B 0xE5B1 # 0 +0xA36C 0xE5B2 # 0 +0xA36D 0xE5B3 # 0 +0xA36E 0xE5B4 # 0 +0xA36F 0xE5B5 # 0 +0xA370 0xE5B6 # 0 +0xA371 0xE5B7 # 0 +0xA372 0xE5B8 # 0 +0xA373 0xE5B9 # 0 +0xA374 0xE5BA # 0 +0xA375 0xE5BB # 0 +0xA376 0xE5BC # 0 +0xA377 0xE5BD # 0 +0xA378 0xE5BE # 0 +0xA379 0xE5BF # 0 +0xA37A 0xE5C0 # 0 +0xA37B 0xE5C1 # 0 +0xA37C 0xE5C2 # 0 +0xA37D 0xE5C3 # 0 +0xA37E 0xE5C4 # 0 +0xA380 0xE5C5 # 0 +0xA381 0xE5C6 # 0 +0xA382 0xE5C7 # 0 +0xA383 0xE5C8 # 0 +0xA384 0xE5C9 # 0 +0xA385 0xE5CA # 0 +0xA386 0xE5CB # 0 +0xA387 0xE5CC # 0 +0xA388 0xE5CD # 0 +0xA389 0xE5CE # 0 +0xA38A 0xE5CF # 0 +0xA38B 0xE5D0 # 0 +0xA38C 0xE5D1 # 0 +0xA38D 0xE5D2 # 0 +0xA38E 0xE5D3 # 0 +0xA38F 0xE5D4 # 0 +0xA390 0xE5D5 # 0 +0xA391 0xE5D6 # 0 +0xA392 0xE5D7 # 0 +0xA393 0xE5D8 # 0 +0xA394 0xE5D9 # 0 +0xA395 0xE5DA # 0 +0xA396 0xE5DB # 0 +0xA397 0xE5DC # 0 +0xA398 0xE5DD # 0 +0xA399 0xE5DE # 0 +0xA39A 0xE5DF # 0 +0xA39B 0xE5E0 # 0 +0xA39C 0xE5E1 # 0 +0xA39D 0xE5E2 # 0 +0xA39E 0xE5E3 # 0 +0xA39F 0xE5E4 # 0 +0xA3A0 0xE5E5 # 0 +0xA3A1 0xFF01 # 0 +0xA3A2 0xFF02 # 0 +0xA3A3 0xFF03 # 0 +0xA3A4 0xFFE5 # 0 +0xA3A5 0xFF05 # 0 +0xA3A6 0xFF06 # 0 +0xA3A7 0xFF07 # 0 +0xA3A8 0xFF08 # 0 +0xA3A9 0xFF09 # 0 +0xA3AA 0xFF0A # 0 +0xA3AB 0xFF0B # 0 +0xA3AC 0xFF0C # 0 +0xA3AD 0xFF0D # 0 +0xA3AE 0xFF0E # 0 +0xA3AF 0xFF0F # 0 +0xA3B0 0xFF10 # 0 +0xA3B1 0xFF11 # 0 +0xA3B2 0xFF12 # 0 +0xA3B3 0xFF13 # 0 +0xA3B4 0xFF14 # 0 +0xA3B5 0xFF15 # 0 +0xA3B6 0xFF16 # 0 +0xA3B7 0xFF17 # 0 +0xA3B8 0xFF18 # 0 +0xA3B9 0xFF19 # 0 +0xA3BA 0xFF1A # 0 +0xA3BB 0xFF1B # 0 +0xA3BC 0xFF1C # 0 +0xA3BD 0xFF1D # 0 +0xA3BE 0xFF1E # 0 +0xA3BF 0xFF1F # 0 +0xA3C0 0xFF20 # 0 +0xA3C1 0xFF21 # 0 +0xA3C2 0xFF22 # 0 +0xA3C3 0xFF23 # 0 +0xA3C4 0xFF24 # 0 +0xA3C5 0xFF25 # 0 +0xA3C6 0xFF26 # 0 +0xA3C7 0xFF27 # 0 +0xA3C8 0xFF28 # 0 +0xA3C9 0xFF29 # 0 +0xA3CA 0xFF2A # 0 +0xA3CB 0xFF2B # 0 +0xA3CC 0xFF2C # 0 +0xA3CD 0xFF2D # 0 +0xA3CE 0xFF2E # 0 +0xA3CF 0xFF2F # 0 +0xA3D0 0xFF30 # 0 +0xA3D1 0xFF31 # 0 +0xA3D2 0xFF32 # 0 +0xA3D3 0xFF33 # 0 +0xA3D4 0xFF34 # 0 +0xA3D5 0xFF35 # 0 +0xA3D6 0xFF36 # 0 +0xA3D7 0xFF37 # 0 +0xA3D8 0xFF38 # 0 +0xA3D9 0xFF39 # 0 +0xA3DA 0xFF3A # 0 +0xA3DB 0xFF3B # 0 +0xA3DC 0xFF3C # 0 +0xA3DD 0xFF3D # 0 +0xA3DE 0xFF3E # 0 +0xA3DF 0xFF3F # 0 +0xA3E0 0xFF40 # 0 +0xA3E1 0xFF41 # 0 +0xA3E2 0xFF42 # 0 +0xA3E3 0xFF43 # 0 +0xA3E4 0xFF44 # 0 +0xA3E5 0xFF45 # 0 +0xA3E6 0xFF46 # 0 +0xA3E7 0xFF47 # 0 +0xA3E8 0xFF48 # 0 +0xA3E9 0xFF49 # 0 +0xA3EA 0xFF4A # 0 +0xA3EB 0xFF4B # 0 +0xA3EC 0xFF4C # 0 +0xA3ED 0xFF4D # 0 +0xA3EE 0xFF4E # 0 +0xA3EF 0xFF4F # 0 +0xA3F0 0xFF50 # 0 +0xA3F1 0xFF51 # 0 +0xA3F2 0xFF52 # 0 +0xA3F3 0xFF53 # 0 +0xA3F4 0xFF54 # 0 +0xA3F5 0xFF55 # 0 +0xA3F6 0xFF56 # 0 +0xA3F7 0xFF57 # 0 +0xA3F8 0xFF58 # 0 +0xA3F9 0xFF59 # 0 +0xA3FA 0xFF5A # 0 +0xA3FB 0xFF5B # 0 +0xA3FC 0xFF5C # 0 +0xA3FD 0xFF5D # 0 +0xA3FE 0xFFE3 # 0 +0xA440 0xE5E6 # 0 +0xA441 0xE5E7 # 0 +0xA442 0xE5E8 # 0 +0xA443 0xE5E9 # 0 +0xA444 0xE5EA # 0 +0xA445 0xE5EB # 0 +0xA446 0xE5EC # 0 +0xA447 0xE5ED # 0 +0xA448 0xE5EE # 0 +0xA449 0xE5EF # 0 +0xA44A 0xE5F0 # 0 +0xA44B 0xE5F1 # 0 +0xA44C 0xE5F2 # 0 +0xA44D 0xE5F3 # 0 +0xA44E 0xE5F4 # 0 +0xA44F 0xE5F5 # 0 +0xA450 0xE5F6 # 0 +0xA451 0xE5F7 # 0 +0xA452 0xE5F8 # 0 +0xA453 0xE5F9 # 0 +0xA454 0xE5FA # 0 +0xA455 0xE5FB # 0 +0xA456 0xE5FC # 0 +0xA457 0xE5FD # 0 +0xA458 0xE5FE # 0 +0xA459 0xE5FF # 0 +0xA45A 0xE600 # 0 +0xA45B 0xE601 # 0 +0xA45C 0xE602 # 0 +0xA45D 0xE603 # 0 +0xA45E 0xE604 # 0 +0xA45F 0xE605 # 0 +0xA460 0xE606 # 0 +0xA461 0xE607 # 0 +0xA462 0xE608 # 0 +0xA463 0xE609 # 0 +0xA464 0xE60A # 0 +0xA465 0xE60B # 0 +0xA466 0xE60C # 0 +0xA467 0xE60D # 0 +0xA468 0xE60E # 0 +0xA469 0xE60F # 0 +0xA46A 0xE610 # 0 +0xA46B 0xE611 # 0 +0xA46C 0xE612 # 0 +0xA46D 0xE613 # 0 +0xA46E 0xE614 # 0 +0xA46F 0xE615 # 0 +0xA470 0xE616 # 0 +0xA471 0xE617 # 0 +0xA472 0xE618 # 0 +0xA473 0xE619 # 0 +0xA474 0xE61A # 0 +0xA475 0xE61B # 0 +0xA476 0xE61C # 0 +0xA477 0xE61D # 0 +0xA478 0xE61E # 0 +0xA479 0xE61F # 0 +0xA47A 0xE620 # 0 +0xA47B 0xE621 # 0 +0xA47C 0xE622 # 0 +0xA47D 0xE623 # 0 +0xA47E 0xE624 # 0 +0xA480 0xE625 # 0 +0xA481 0xE626 # 0 +0xA482 0xE627 # 0 +0xA483 0xE628 # 0 +0xA484 0xE629 # 0 +0xA485 0xE62A # 0 +0xA486 0xE62B # 0 +0xA487 0xE62C # 0 +0xA488 0xE62D # 0 +0xA489 0xE62E # 0 +0xA48A 0xE62F # 0 +0xA48B 0xE630 # 0 +0xA48C 0xE631 # 0 +0xA48D 0xE632 # 0 +0xA48E 0xE633 # 0 +0xA48F 0xE634 # 0 +0xA490 0xE635 # 0 +0xA491 0xE636 # 0 +0xA492 0xE637 # 0 +0xA493 0xE638 # 0 +0xA494 0xE639 # 0 +0xA495 0xE63A # 0 +0xA496 0xE63B # 0 +0xA497 0xE63C # 0 +0xA498 0xE63D # 0 +0xA499 0xE63E # 0 +0xA49A 0xE63F # 0 +0xA49B 0xE640 # 0 +0xA49C 0xE641 # 0 +0xA49D 0xE642 # 0 +0xA49E 0xE643 # 0 +0xA49F 0xE644 # 0 +0xA4A0 0xE645 # 0 +0xA4A1 0x3041 # 0 +0xA4A2 0x3042 # 0 +0xA4A3 0x3043 # 0 +0xA4A4 0x3044 # 0 +0xA4A5 0x3045 # 0 +0xA4A6 0x3046 # 0 +0xA4A7 0x3047 # 0 +0xA4A8 0x3048 # 0 +0xA4A9 0x3049 # 0 +0xA4AA 0x304A # 0 +0xA4AB 0x304B # 0 +0xA4AC 0x304C # 0 +0xA4AD 0x304D # 0 +0xA4AE 0x304E # 0 +0xA4AF 0x304F # 0 +0xA4B0 0x3050 # 0 +0xA4B1 0x3051 # 0 +0xA4B2 0x3052 # 0 +0xA4B3 0x3053 # 0 +0xA4B4 0x3054 # 0 +0xA4B5 0x3055 # 0 +0xA4B6 0x3056 # 0 +0xA4B7 0x3057 # 0 +0xA4B8 0x3058 # 0 +0xA4B9 0x3059 # 0 +0xA4BA 0x305A # 0 +0xA4BB 0x305B # 0 +0xA4BC 0x305C # 0 +0xA4BD 0x305D # 0 +0xA4BE 0x305E # 0 +0xA4BF 0x305F # 0 +0xA4C0 0x3060 # 0 +0xA4C1 0x3061 # 0 +0xA4C2 0x3062 # 0 +0xA4C3 0x3063 # 0 +0xA4C4 0x3064 # 0 +0xA4C5 0x3065 # 0 +0xA4C6 0x3066 # 0 +0xA4C7 0x3067 # 0 +0xA4C8 0x3068 # 0 +0xA4C9 0x3069 # 0 +0xA4CA 0x306A # 0 +0xA4CB 0x306B # 0 +0xA4CC 0x306C # 0 +0xA4CD 0x306D # 0 +0xA4CE 0x306E # 0 +0xA4CF 0x306F # 0 +0xA4D0 0x3070 # 0 +0xA4D1 0x3071 # 0 +0xA4D2 0x3072 # 0 +0xA4D3 0x3073 # 0 +0xA4D4 0x3074 # 0 +0xA4D5 0x3075 # 0 +0xA4D6 0x3076 # 0 +0xA4D7 0x3077 # 0 +0xA4D8 0x3078 # 0 +0xA4D9 0x3079 # 0 +0xA4DA 0x307A # 0 +0xA4DB 0x307B # 0 +0xA4DC 0x307C # 0 +0xA4DD 0x307D # 0 +0xA4DE 0x307E # 0 +0xA4DF 0x307F # 0 +0xA4E0 0x3080 # 0 +0xA4E1 0x3081 # 0 +0xA4E2 0x3082 # 0 +0xA4E3 0x3083 # 0 +0xA4E4 0x3084 # 0 +0xA4E5 0x3085 # 0 +0xA4E6 0x3086 # 0 +0xA4E7 0x3087 # 0 +0xA4E8 0x3088 # 0 +0xA4E9 0x3089 # 0 +0xA4EA 0x308A # 0 +0xA4EB 0x308B # 0 +0xA4EC 0x308C # 0 +0xA4ED 0x308D # 0 +0xA4EE 0x308E # 0 +0xA4EF 0x308F # 0 +0xA4F0 0x3090 # 0 +0xA4F1 0x3091 # 0 +0xA4F2 0x3092 # 0 +0xA4F3 0x3093 # 0 +0xA4F4 0xE772 # 0 +0xA4F5 0xE773 # 0 +0xA4F6 0xE774 # 0 +0xA4F7 0xE775 # 0 +0xA4F8 0xE776 # 0 +0xA4F9 0xE777 # 0 +0xA4FA 0xE778 # 0 +0xA4FB 0xE779 # 0 +0xA4FC 0xE77A # 0 +0xA4FD 0xE77B # 0 +0xA4FE 0xE77C # 0 +0xA540 0xE646 # 0 +0xA541 0xE647 # 0 +0xA542 0xE648 # 0 +0xA543 0xE649 # 0 +0xA544 0xE64A # 0 +0xA545 0xE64B # 0 +0xA546 0xE64C # 0 +0xA547 0xE64D # 0 +0xA548 0xE64E # 0 +0xA549 0xE64F # 0 +0xA54A 0xE650 # 0 +0xA54B 0xE651 # 0 +0xA54C 0xE652 # 0 +0xA54D 0xE653 # 0 +0xA54E 0xE654 # 0 +0xA54F 0xE655 # 0 +0xA550 0xE656 # 0 +0xA551 0xE657 # 0 +0xA552 0xE658 # 0 +0xA553 0xE659 # 0 +0xA554 0xE65A # 0 +0xA555 0xE65B # 0 +0xA556 0xE65C # 0 +0xA557 0xE65D # 0 +0xA558 0xE65E # 0 +0xA559 0xE65F # 0 +0xA55A 0xE660 # 0 +0xA55B 0xE661 # 0 +0xA55C 0xE662 # 0 +0xA55D 0xE663 # 0 +0xA55E 0xE664 # 0 +0xA55F 0xE665 # 0 +0xA560 0xE666 # 0 +0xA561 0xE667 # 0 +0xA562 0xE668 # 0 +0xA563 0xE669 # 0 +0xA564 0xE66A # 0 +0xA565 0xE66B # 0 +0xA566 0xE66C # 0 +0xA567 0xE66D # 0 +0xA568 0xE66E # 0 +0xA569 0xE66F # 0 +0xA56A 0xE670 # 0 +0xA56B 0xE671 # 0 +0xA56C 0xE672 # 0 +0xA56D 0xE673 # 0 +0xA56E 0xE674 # 0 +0xA56F 0xE675 # 0 +0xA570 0xE676 # 0 +0xA571 0xE677 # 0 +0xA572 0xE678 # 0 +0xA573 0xE679 # 0 +0xA574 0xE67A # 0 +0xA575 0xE67B # 0 +0xA576 0xE67C # 0 +0xA577 0xE67D # 0 +0xA578 0xE67E # 0 +0xA579 0xE67F # 0 +0xA57A 0xE680 # 0 +0xA57B 0xE681 # 0 +0xA57C 0xE682 # 0 +0xA57D 0xE683 # 0 +0xA57E 0xE684 # 0 +0xA580 0xE685 # 0 +0xA581 0xE686 # 0 +0xA582 0xE687 # 0 +0xA583 0xE688 # 0 +0xA584 0xE689 # 0 +0xA585 0xE68A # 0 +0xA586 0xE68B # 0 +0xA587 0xE68C # 0 +0xA588 0xE68D # 0 +0xA589 0xE68E # 0 +0xA58A 0xE68F # 0 +0xA58B 0xE690 # 0 +0xA58C 0xE691 # 0 +0xA58D 0xE692 # 0 +0xA58E 0xE693 # 0 +0xA58F 0xE694 # 0 +0xA590 0xE695 # 0 +0xA591 0xE696 # 0 +0xA592 0xE697 # 0 +0xA593 0xE698 # 0 +0xA594 0xE699 # 0 +0xA595 0xE69A # 0 +0xA596 0xE69B # 0 +0xA597 0xE69C # 0 +0xA598 0xE69D # 0 +0xA599 0xE69E # 0 +0xA59A 0xE69F # 0 +0xA59B 0xE6A0 # 0 +0xA59C 0xE6A1 # 0 +0xA59D 0xE6A2 # 0 +0xA59E 0xE6A3 # 0 +0xA59F 0xE6A4 # 0 +0xA5A0 0xE6A5 # 0 +0xA5A1 0x30A1 # 0 +0xA5A2 0x30A2 # 0 +0xA5A3 0x30A3 # 0 +0xA5A4 0x30A4 # 0 +0xA5A5 0x30A5 # 0 +0xA5A6 0x30A6 # 0 +0xA5A7 0x30A7 # 0 +0xA5A8 0x30A8 # 0 +0xA5A9 0x30A9 # 0 +0xA5AA 0x30AA # 0 +0xA5AB 0x30AB # 0 +0xA5AC 0x30AC # 0 +0xA5AD 0x30AD # 0 +0xA5AE 0x30AE # 0 +0xA5AF 0x30AF # 0 +0xA5B0 0x30B0 # 0 +0xA5B1 0x30B1 # 0 +0xA5B2 0x30B2 # 0 +0xA5B3 0x30B3 # 0 +0xA5B4 0x30B4 # 0 +0xA5B5 0x30B5 # 0 +0xA5B6 0x30B6 # 0 +0xA5B7 0x30B7 # 0 +0xA5B8 0x30B8 # 0 +0xA5B9 0x30B9 # 0 +0xA5BA 0x30BA # 0 +0xA5BB 0x30BB # 0 +0xA5BC 0x30BC # 0 +0xA5BD 0x30BD # 0 +0xA5BE 0x30BE # 0 +0xA5BF 0x30BF # 0 +0xA5C0 0x30C0 # 0 +0xA5C1 0x30C1 # 0 +0xA5C2 0x30C2 # 0 +0xA5C3 0x30C3 # 0 +0xA5C4 0x30C4 # 0 +0xA5C5 0x30C5 # 0 +0xA5C6 0x30C6 # 0 +0xA5C7 0x30C7 # 0 +0xA5C8 0x30C8 # 0 +0xA5C9 0x30C9 # 0 +0xA5CA 0x30CA # 0 +0xA5CB 0x30CB # 0 +0xA5CC 0x30CC # 0 +0xA5CD 0x30CD # 0 +0xA5CE 0x30CE # 0 +0xA5CF 0x30CF # 0 +0xA5D0 0x30D0 # 0 +0xA5D1 0x30D1 # 0 +0xA5D2 0x30D2 # 0 +0xA5D3 0x30D3 # 0 +0xA5D4 0x30D4 # 0 +0xA5D5 0x30D5 # 0 +0xA5D6 0x30D6 # 0 +0xA5D7 0x30D7 # 0 +0xA5D8 0x30D8 # 0 +0xA5D9 0x30D9 # 0 +0xA5DA 0x30DA # 0 +0xA5DB 0x30DB # 0 +0xA5DC 0x30DC # 0 +0xA5DD 0x30DD # 0 +0xA5DE 0x30DE # 0 +0xA5DF 0x30DF # 0 +0xA5E0 0x30E0 # 0 +0xA5E1 0x30E1 # 0 +0xA5E2 0x30E2 # 0 +0xA5E3 0x30E3 # 0 +0xA5E4 0x30E4 # 0 +0xA5E5 0x30E5 # 0 +0xA5E6 0x30E6 # 0 +0xA5E7 0x30E7 # 0 +0xA5E8 0x30E8 # 0 +0xA5E9 0x30E9 # 0 +0xA5EA 0x30EA # 0 +0xA5EB 0x30EB # 0 +0xA5EC 0x30EC # 0 +0xA5ED 0x30ED # 0 +0xA5EE 0x30EE # 0 +0xA5EF 0x30EF # 0 +0xA5F0 0x30F0 # 0 +0xA5F1 0x30F1 # 0 +0xA5F2 0x30F2 # 0 +0xA5F3 0x30F3 # 0 +0xA5F4 0x30F4 # 0 +0xA5F5 0x30F5 # 0 +0xA5F6 0x30F6 # 0 +0xA5F7 0xE77D # 0 +0xA5F8 0xE77E # 0 +0xA5F9 0xE77F # 0 +0xA5FA 0xE780 # 0 +0xA5FB 0xE781 # 0 +0xA5FC 0xE782 # 0 +0xA5FD 0xE783 # 0 +0xA5FE 0xE784 # 0 +0xA640 0xE6A6 # 0 +0xA641 0xE6A7 # 0 +0xA642 0xE6A8 # 0 +0xA643 0xE6A9 # 0 +0xA644 0xE6AA # 0 +0xA645 0xE6AB # 0 +0xA646 0xE6AC # 0 +0xA647 0xE6AD # 0 +0xA648 0xE6AE # 0 +0xA649 0xE6AF # 0 +0xA64A 0xE6B0 # 0 +0xA64B 0xE6B1 # 0 +0xA64C 0xE6B2 # 0 +0xA64D 0xE6B3 # 0 +0xA64E 0xE6B4 # 0 +0xA64F 0xE6B5 # 0 +0xA650 0xE6B6 # 0 +0xA651 0xE6B7 # 0 +0xA652 0xE6B8 # 0 +0xA653 0xE6B9 # 0 +0xA654 0xE6BA # 0 +0xA655 0xE6BB # 0 +0xA656 0xE6BC # 0 +0xA657 0xE6BD # 0 +0xA658 0xE6BE # 0 +0xA659 0xE6BF # 0 +0xA65A 0xE6C0 # 0 +0xA65B 0xE6C1 # 0 +0xA65C 0xE6C2 # 0 +0xA65D 0xE6C3 # 0 +0xA65E 0xE6C4 # 0 +0xA65F 0xE6C5 # 0 +0xA660 0xE6C6 # 0 +0xA661 0xE6C7 # 0 +0xA662 0xE6C8 # 0 +0xA663 0xE6C9 # 0 +0xA664 0xE6CA # 0 +0xA665 0xE6CB # 0 +0xA666 0xE6CC # 0 +0xA667 0xE6CD # 0 +0xA668 0xE6CE # 0 +0xA669 0xE6CF # 0 +0xA66A 0xE6D0 # 0 +0xA66B 0xE6D1 # 0 +0xA66C 0xE6D2 # 0 +0xA66D 0xE6D3 # 0 +0xA66E 0xE6D4 # 0 +0xA66F 0xE6D5 # 0 +0xA670 0xE6D6 # 0 +0xA671 0xE6D7 # 0 +0xA672 0xE6D8 # 0 +0xA673 0xE6D9 # 0 +0xA674 0xE6DA # 0 +0xA675 0xE6DB # 0 +0xA676 0xE6DC # 0 +0xA677 0xE6DD # 0 +0xA678 0xE6DE # 0 +0xA679 0xE6DF # 0 +0xA67A 0xE6E0 # 0 +0xA67B 0xE6E1 # 0 +0xA67C 0xE6E2 # 0 +0xA67D 0xE6E3 # 0 +0xA67E 0xE6E4 # 0 +0xA680 0xE6E5 # 0 +0xA681 0xE6E6 # 0 +0xA682 0xE6E7 # 0 +0xA683 0xE6E8 # 0 +0xA684 0xE6E9 # 0 +0xA685 0xE6EA # 0 +0xA686 0xE6EB # 0 +0xA687 0xE6EC # 0 +0xA688 0xE6ED # 0 +0xA689 0xE6EE # 0 +0xA68A 0xE6EF # 0 +0xA68B 0xE6F0 # 0 +0xA68C 0xE6F1 # 0 +0xA68D 0xE6F2 # 0 +0xA68E 0xE6F3 # 0 +0xA68F 0xE6F4 # 0 +0xA690 0xE6F5 # 0 +0xA691 0xE6F6 # 0 +0xA692 0xE6F7 # 0 +0xA693 0xE6F8 # 0 +0xA694 0xE6F9 # 0 +0xA695 0xE6FA # 0 +0xA696 0xE6FB # 0 +0xA697 0xE6FC # 0 +0xA698 0xE6FD # 0 +0xA699 0xE6FE # 0 +0xA69A 0xE6FF # 0 +0xA69B 0xE700 # 0 +0xA69C 0xE701 # 0 +0xA69D 0xE702 # 0 +0xA69E 0xE703 # 0 +0xA69F 0xE704 # 0 +0xA6A0 0xE705 # 0 +0xA6A1 0x0391 # 0 +0xA6A2 0x0392 # 0 +0xA6A3 0x0393 # 0 +0xA6A4 0x0394 # 0 +0xA6A5 0x0395 # 0 +0xA6A6 0x0396 # 0 +0xA6A7 0x0397 # 0 +0xA6A8 0x0398 # 0 +0xA6A9 0x0399 # 0 +0xA6AA 0x039A # 0 +0xA6AB 0x039B # 0 +0xA6AC 0x039C # 0 +0xA6AD 0x039D # 0 +0xA6AE 0x039E # 0 +0xA6AF 0x039F # 0 +0xA6B0 0x03A0 # 0 +0xA6B1 0x03A1 # 0 +0xA6B2 0x03A3 # 0 +0xA6B3 0x03A4 # 0 +0xA6B4 0x03A5 # 0 +0xA6B5 0x03A6 # 0 +0xA6B6 0x03A7 # 0 +0xA6B7 0x03A8 # 0 +0xA6B8 0x03A9 # 0 +0xA6B9 0xE785 # 0 +0xA6BA 0xE786 # 0 +0xA6BB 0xE787 # 0 +0xA6BC 0xE788 # 0 +0xA6BD 0xE789 # 0 +0xA6BE 0xE78A # 0 +0xA6BF 0xE78B # 0 +0xA6C0 0xE78C # 0 +0xA6C1 0x03B1 # 0 +0xA6C2 0x03B2 # 0 +0xA6C3 0x03B3 # 0 +0xA6C4 0x03B4 # 0 +0xA6C5 0x03B5 # 0 +0xA6C6 0x03B6 # 0 +0xA6C7 0x03B7 # 0 +0xA6C8 0x03B8 # 0 +0xA6C9 0x03B9 # 0 +0xA6CA 0x03BA # 0 +0xA6CB 0x03BB # 0 +0xA6CC 0x03BC # 0 +0xA6CD 0x03BD # 0 +0xA6CE 0x03BE # 0 +0xA6CF 0x03BF # 0 +0xA6D0 0x03C0 # 0 +0xA6D1 0x03C1 # 0 +0xA6D2 0x03C3 # 0 +0xA6D3 0x03C4 # 0 +0xA6D4 0x03C5 # 0 +0xA6D5 0x03C6 # 0 +0xA6D6 0x03C7 # 0 +0xA6D7 0x03C8 # 0 +0xA6D8 0x03C9 # 0 +0xA6D9 0xE78D # 0 +0xA6DA 0xE78E # 0 +0xA6DB 0xE78F # 0 +0xA6DC 0xE790 # 0 +0xA6DD 0xE791 # 0 +0xA6DE 0xE792 # 0 +0xA6DF 0xE793 # 0 +0xA6E0 0xFE35 # 0 +0xA6E1 0xFE36 # 0 +0xA6E2 0xFE39 # 0 +0xA6E3 0xFE3A # 0 +0xA6E4 0xFE3F # 0 +0xA6E5 0xFE40 # 0 +0xA6E6 0xFE3D # 0 +0xA6E7 0xFE3E # 0 +0xA6E8 0xFE41 # 0 +0xA6E9 0xFE42 # 0 +0xA6EA 0xFE43 # 0 +0xA6EB 0xFE44 # 0 +0xA6EC 0xE794 # 0 +0xA6ED 0xE795 # 0 +0xA6EE 0xFE3B # 0 +0xA6EF 0xFE3C # 0 +0xA6F0 0xFE37 # 0 +0xA6F1 0xFE38 # 0 +0xA6F2 0xFE31 # 0 +0xA6F3 0xE796 # 0 +0xA6F4 0xFE33 # 0 +0xA6F5 0xFE34 # 0 +0xA6F6 0xE797 # 0 +0xA6F7 0xE798 # 0 +0xA6F8 0xE799 # 0 +0xA6F9 0xE79A # 0 +0xA6FA 0xE79B # 0 +0xA6FB 0xE79C # 0 +0xA6FC 0xE79D # 0 +0xA6FD 0xE79E # 0 +0xA6FE 0xE79F # 0 +0xA740 0xE706 # 0 +0xA741 0xE707 # 0 +0xA742 0xE708 # 0 +0xA743 0xE709 # 0 +0xA744 0xE70A # 0 +0xA745 0xE70B # 0 +0xA746 0xE70C # 0 +0xA747 0xE70D # 0 +0xA748 0xE70E # 0 +0xA749 0xE70F # 0 +0xA74A 0xE710 # 0 +0xA74B 0xE711 # 0 +0xA74C 0xE712 # 0 +0xA74D 0xE713 # 0 +0xA74E 0xE714 # 0 +0xA74F 0xE715 # 0 +0xA750 0xE716 # 0 +0xA751 0xE717 # 0 +0xA752 0xE718 # 0 +0xA753 0xE719 # 0 +0xA754 0xE71A # 0 +0xA755 0xE71B # 0 +0xA756 0xE71C # 0 +0xA757 0xE71D # 0 +0xA758 0xE71E # 0 +0xA759 0xE71F # 0 +0xA75A 0xE720 # 0 +0xA75B 0xE721 # 0 +0xA75C 0xE722 # 0 +0xA75D 0xE723 # 0 +0xA75E 0xE724 # 0 +0xA75F 0xE725 # 0 +0xA760 0xE726 # 0 +0xA761 0xE727 # 0 +0xA762 0xE728 # 0 +0xA763 0xE729 # 0 +0xA764 0xE72A # 0 +0xA765 0xE72B # 0 +0xA766 0xE72C # 0 +0xA767 0xE72D # 0 +0xA768 0xE72E # 0 +0xA769 0xE72F # 0 +0xA76A 0xE730 # 0 +0xA76B 0xE731 # 0 +0xA76C 0xE732 # 0 +0xA76D 0xE733 # 0 +0xA76E 0xE734 # 0 +0xA76F 0xE735 # 0 +0xA770 0xE736 # 0 +0xA771 0xE737 # 0 +0xA772 0xE738 # 0 +0xA773 0xE739 # 0 +0xA774 0xE73A # 0 +0xA775 0xE73B # 0 +0xA776 0xE73C # 0 +0xA777 0xE73D # 0 +0xA778 0xE73E # 0 +0xA779 0xE73F # 0 +0xA77A 0xE740 # 0 +0xA77B 0xE741 # 0 +0xA77C 0xE742 # 0 +0xA77D 0xE743 # 0 +0xA77E 0xE744 # 0 +0xA780 0xE745 # 0 +0xA781 0xE746 # 0 +0xA782 0xE747 # 0 +0xA783 0xE748 # 0 +0xA784 0xE749 # 0 +0xA785 0xE74A # 0 +0xA786 0xE74B # 0 +0xA787 0xE74C # 0 +0xA788 0xE74D # 0 +0xA789 0xE74E # 0 +0xA78A 0xE74F # 0 +0xA78B 0xE750 # 0 +0xA78C 0xE751 # 0 +0xA78D 0xE752 # 0 +0xA78E 0xE753 # 0 +0xA78F 0xE754 # 0 +0xA790 0xE755 # 0 +0xA791 0xE756 # 0 +0xA792 0xE757 # 0 +0xA793 0xE758 # 0 +0xA794 0xE759 # 0 +0xA795 0xE75A # 0 +0xA796 0xE75B # 0 +0xA797 0xE75C # 0 +0xA798 0xE75D # 0 +0xA799 0xE75E # 0 +0xA79A 0xE75F # 0 +0xA79B 0xE760 # 0 +0xA79C 0xE761 # 0 +0xA79D 0xE762 # 0 +0xA79E 0xE763 # 0 +0xA79F 0xE764 # 0 +0xA7A0 0xE765 # 0 +0xA7A1 0x0410 # 0 +0xA7A2 0x0411 # 0 +0xA7A3 0x0412 # 0 +0xA7A4 0x0413 # 0 +0xA7A5 0x0414 # 0 +0xA7A6 0x0415 # 0 +0xA7A7 0x0401 # 0 +0xA7A8 0x0416 # 0 +0xA7A9 0x0417 # 0 +0xA7AA 0x0418 # 0 +0xA7AB 0x0419 # 0 +0xA7AC 0x041A # 0 +0xA7AD 0x041B # 0 +0xA7AE 0x041C # 0 +0xA7AF 0x041D # 0 +0xA7B0 0x041E # 0 +0xA7B1 0x041F # 0 +0xA7B2 0x0420 # 0 +0xA7B3 0x0421 # 0 +0xA7B4 0x0422 # 0 +0xA7B5 0x0423 # 0 +0xA7B6 0x0424 # 0 +0xA7B7 0x0425 # 0 +0xA7B8 0x0426 # 0 +0xA7B9 0x0427 # 0 +0xA7BA 0x0428 # 0 +0xA7BB 0x0429 # 0 +0xA7BC 0x042A # 0 +0xA7BD 0x042B # 0 +0xA7BE 0x042C # 0 +0xA7BF 0x042D # 0 +0xA7C0 0x042E # 0 +0xA7C1 0x042F # 0 +0xA7C2 0xE7A0 # 0 +0xA7C3 0xE7A1 # 0 +0xA7C4 0xE7A2 # 0 +0xA7C5 0xE7A3 # 0 +0xA7C6 0xE7A4 # 0 +0xA7C7 0xE7A5 # 0 +0xA7C8 0xE7A6 # 0 +0xA7C9 0xE7A7 # 0 +0xA7CA 0xE7A8 # 0 +0xA7CB 0xE7A9 # 0 +0xA7CC 0xE7AA # 0 +0xA7CD 0xE7AB # 0 +0xA7CE 0xE7AC # 0 +0xA7CF 0xE7AD # 0 +0xA7D0 0xE7AE # 0 +0xA7D1 0x0430 # 0 +0xA7D2 0x0431 # 0 +0xA7D3 0x0432 # 0 +0xA7D4 0x0433 # 0 +0xA7D5 0x0434 # 0 +0xA7D6 0x0435 # 0 +0xA7D7 0x0451 # 0 +0xA7D8 0x0436 # 0 +0xA7D9 0x0437 # 0 +0xA7DA 0x0438 # 0 +0xA7DB 0x0439 # 0 +0xA7DC 0x043A # 0 +0xA7DD 0x043B # 0 +0xA7DE 0x043C # 0 +0xA7DF 0x043D # 0 +0xA7E0 0x043E # 0 +0xA7E1 0x043F # 0 +0xA7E2 0x0440 # 0 +0xA7E3 0x0441 # 0 +0xA7E4 0x0442 # 0 +0xA7E5 0x0443 # 0 +0xA7E6 0x0444 # 0 +0xA7E7 0x0445 # 0 +0xA7E8 0x0446 # 0 +0xA7E9 0x0447 # 0 +0xA7EA 0x0448 # 0 +0xA7EB 0x0449 # 0 +0xA7EC 0x044A # 0 +0xA7ED 0x044B # 0 +0xA7EE 0x044C # 0 +0xA7EF 0x044D # 0 +0xA7F0 0x044E # 0 +0xA7F1 0x044F # 0 +0xA7F2 0xE7AF # 0 +0xA7F3 0xE7B0 # 0 +0xA7F4 0xE7B1 # 0 +0xA7F5 0xE7B2 # 0 +0xA7F6 0xE7B3 # 0 +0xA7F7 0xE7B4 # 0 +0xA7F8 0xE7B5 # 0 +0xA7F9 0xE7B6 # 0 +0xA7FA 0xE7B7 # 0 +0xA7FB 0xE7B8 # 0 +0xA7FC 0xE7B9 # 0 +0xA7FD 0xE7BA # 0 +0xA7FE 0xE7BB # 0 +0xA840 0x02CA # 0 +0xA841 0x02CB # 0 +0xA842 0x02D9 # 0 +0xA843 0x2013 # 0 +0xA844 0x2015 # 0 +0xA845 0x2025 # 0 +0xA846 0x2035 # 0 +0xA847 0x2105 # 0 +0xA848 0x2109 # 0 +0xA849 0x2196 # 0 +0xA84A 0x2197 # 0 +0xA84B 0x2198 # 0 +0xA84C 0x2199 # 0 +0xA84D 0x2215 # 0 +0xA84E 0x221F # 0 +0xA84F 0x2223 # 0 +0xA850 0x2252 # 0 +0xA851 0x2266 # 0 +0xA852 0x2267 # 0 +0xA853 0x22BF # 0 +0xA854 0x2550 # 0 +0xA855 0x2551 # 0 +0xA856 0x2552 # 0 +0xA857 0x2553 # 0 +0xA858 0x2554 # 0 +0xA859 0x2555 # 0 +0xA85A 0x2556 # 0 +0xA85B 0x2557 # 0 +0xA85C 0x2558 # 0 +0xA85D 0x2559 # 0 +0xA85E 0x255A # 0 +0xA85F 0x255B # 0 +0xA860 0x255C # 0 +0xA861 0x255D # 0 +0xA862 0x255E # 0 +0xA863 0x255F # 0 +0xA864 0x2560 # 0 +0xA865 0x2561 # 0 +0xA866 0x2562 # 0 +0xA867 0x2563 # 0 +0xA868 0x2564 # 0 +0xA869 0x2565 # 0 +0xA86A 0x2566 # 0 +0xA86B 0x2567 # 0 +0xA86C 0x2568 # 0 +0xA86D 0x2569 # 0 +0xA86E 0x256A # 0 +0xA86F 0x256B # 0 +0xA870 0x256C # 0 +0xA871 0x256D # 0 +0xA872 0x256E # 0 +0xA873 0x256F # 0 +0xA874 0x2570 # 0 +0xA875 0x2571 # 0 +0xA876 0x2572 # 0 +0xA877 0x2573 # 0 +0xA878 0x2581 # 0 +0xA879 0x2582 # 0 +0xA87A 0x2583 # 0 +0xA87B 0x2584 # 0 +0xA87C 0x2585 # 0 +0xA87D 0x2586 # 0 +0xA87E 0x2587 # 0 +0xA880 0x2588 # 0 +0xA881 0x2589 # 0 +0xA882 0x258A # 0 +0xA883 0x258B # 0 +0xA884 0x258C # 0 +0xA885 0x258D # 0 +0xA886 0x258E # 0 +0xA887 0x258F # 0 +0xA888 0x2593 # 0 +0xA889 0x2594 # 0 +0xA88A 0x2595 # 0 +0xA88B 0x25BC # 0 +0xA88C 0x25BD # 0 +0xA88D 0x25E2 # 0 +0xA88E 0x25E3 # 0 +0xA88F 0x25E4 # 0 +0xA890 0x25E5 # 0 +0xA891 0x2609 # 0 +0xA892 0x2295 # 0 +0xA893 0x3012 # 0 +0xA894 0x301D # 0 +0xA895 0x301E # 0 +0xA896 0xE7BC # 0 +0xA897 0xE7BD # 0 +0xA898 0xE7BE # 0 +0xA899 0xE7BF # 0 +0xA89A 0xE7C0 # 0 +0xA89B 0xE7C1 # 0 +0xA89C 0xE7C2 # 0 +0xA89D 0xE7C3 # 0 +0xA89E 0xE7C4 # 0 +0xA89F 0xE7C5 # 0 +0xA8A0 0xE7C6 # 0 +0xA8A1 0x0101 # 0 +0xA8A2 0x00E1 # 0 +0xA8A3 0x01CE # 0 +0xA8A4 0x00E0 # 0 +0xA8A5 0x0113 # 0 +0xA8A6 0x00E9 # 0 +0xA8A7 0x011B # 0 +0xA8A8 0x00E8 # 0 +0xA8A9 0x012B # 0 +0xA8AA 0x00ED # 0 +0xA8AB 0x01D0 # 0 +0xA8AC 0x00EC # 0 +0xA8AD 0x014D # 0 +0xA8AE 0x00F3 # 0 +0xA8AF 0x01D2 # 0 +0xA8B0 0x00F2 # 0 +0xA8B1 0x016B # 0 +0xA8B2 0x00FA # 0 +0xA8B3 0x01D4 # 0 +0xA8B4 0x00F9 # 0 +0xA8B5 0x01D6 # 0 +0xA8B6 0x01D8 # 0 +0xA8B7 0x01DA # 0 +0xA8B8 0x01DC # 0 +0xA8B9 0x00FC # 0 +0xA8BA 0x00EA # 0 +0xA8BB 0x0251 # 0 +0xA8BC 0xE7C7 # 0 +0xA8BD 0x0144 # 0 +0xA8BE 0x0148 # 0 +0xA8BF 0xE7C8 # 0 +0xA8C0 0x0261 # 0 +0xA8C1 0xE7C9 # 0 +0xA8C2 0xE7CA # 0 +0xA8C3 0xE7CB # 0 +0xA8C4 0xE7CC # 0 +0xA8C5 0x3105 # 0 +0xA8C6 0x3106 # 0 +0xA8C7 0x3107 # 0 +0xA8C8 0x3108 # 0 +0xA8C9 0x3109 # 0 +0xA8CA 0x310A # 0 +0xA8CB 0x310B # 0 +0xA8CC 0x310C # 0 +0xA8CD 0x310D # 0 +0xA8CE 0x310E # 0 +0xA8CF 0x310F # 0 +0xA8D0 0x3110 # 0 +0xA8D1 0x3111 # 0 +0xA8D2 0x3112 # 0 +0xA8D3 0x3113 # 0 +0xA8D4 0x3114 # 0 +0xA8D5 0x3115 # 0 +0xA8D6 0x3116 # 0 +0xA8D7 0x3117 # 0 +0xA8D8 0x3118 # 0 +0xA8D9 0x3119 # 0 +0xA8DA 0x311A # 0 +0xA8DB 0x311B # 0 +0xA8DC 0x311C # 0 +0xA8DD 0x311D # 0 +0xA8DE 0x311E # 0 +0xA8DF 0x311F # 0 +0xA8E0 0x3120 # 0 +0xA8E1 0x3121 # 0 +0xA8E2 0x3122 # 0 +0xA8E3 0x3123 # 0 +0xA8E4 0x3124 # 0 +0xA8E5 0x3125 # 0 +0xA8E6 0x3126 # 0 +0xA8E7 0x3127 # 0 +0xA8E8 0x3128 # 0 +0xA8E9 0x3129 # 0 +0xA8EA 0xE7CD # 0 +0xA8EB 0xE7CE # 0 +0xA8EC 0xE7CF # 0 +0xA8ED 0xE7D0 # 0 +0xA8EE 0xE7D1 # 0 +0xA8EF 0xE7D2 # 0 +0xA8F0 0xE7D3 # 0 +0xA8F1 0xE7D4 # 0 +0xA8F2 0xE7D5 # 0 +0xA8F3 0xE7D6 # 0 +0xA8F4 0xE7D7 # 0 +0xA8F5 0xE7D8 # 0 +0xA8F6 0xE7D9 # 0 +0xA8F7 0xE7DA # 0 +0xA8F8 0xE7DB # 0 +0xA8F9 0xE7DC # 0 +0xA8FA 0xE7DD # 0 +0xA8FB 0xE7DE # 0 +0xA8FC 0xE7DF # 0 +0xA8FD 0xE7E0 # 0 +0xA8FE 0xE7E1 # 0 +0xA940 0x3021 # 0 +0xA941 0x3022 # 0 +0xA942 0x3023 # 0 +0xA943 0x3024 # 0 +0xA944 0x3025 # 0 +0xA945 0x3026 # 0 +0xA946 0x3027 # 0 +0xA947 0x3028 # 0 +0xA948 0x3029 # 0 +0xA949 0x32A3 # 0 +0xA94A 0x338E # 0 +0xA94B 0x338F # 0 +0xA94C 0x339C # 0 +0xA94D 0x339D # 0 +0xA94E 0x339E # 0 +0xA94F 0x33A1 # 0 +0xA950 0x33C4 # 0 +0xA951 0x33CE # 0 +0xA952 0x33D1 # 0 +0xA953 0x33D2 # 0 +0xA954 0x33D5 # 0 +0xA955 0xFE30 # 0 +0xA956 0xFFE2 # 0 +0xA957 0xFFE4 # 0 +0xA958 0xE7E2 # 0 +0xA959 0x2121 # 0 +0xA95A 0x3231 # 0 +0xA95B 0xE7E3 # 0 +0xA95C 0x2010 # 0 +0xA95D 0xE7E4 # 0 +0xA95E 0xE7E5 # 0 +0xA95F 0xE7E6 # 0 +0xA960 0x30FC # 0 +0xA961 0x309B # 0 +0xA962 0x309C # 0 +0xA963 0x30FD # 0 +0xA964 0x30FE # 0 +0xA965 0x3006 # 0 +0xA966 0x309D # 0 +0xA967 0x309E # 0 +0xA968 0xFE49 # 0 +0xA969 0xFE4A # 0 +0xA96A 0xFE4B # 0 +0xA96B 0xFE4C # 0 +0xA96C 0xFE4D # 0 +0xA96D 0xFE4E # 0 +0xA96E 0xFE4F # 0 +0xA96F 0xFE50 # 0 +0xA970 0xFE51 # 0 +0xA971 0xFE52 # 0 +0xA972 0xFE54 # 0 +0xA973 0xFE55 # 0 +0xA974 0xFE56 # 0 +0xA975 0xFE57 # 0 +0xA976 0xFE59 # 0 +0xA977 0xFE5A # 0 +0xA978 0xFE5B # 0 +0xA979 0xFE5C # 0 +0xA97A 0xFE5D # 0 +0xA97B 0xFE5E # 0 +0xA97C 0xFE5F # 0 +0xA97D 0xFE60 # 0 +0xA97E 0xFE61 # 0 +0xA980 0xFE62 # 0 +0xA981 0xFE63 # 0 +0xA982 0xFE64 # 0 +0xA983 0xFE65 # 0 +0xA984 0xFE66 # 0 +0xA985 0xFE68 # 0 +0xA986 0xFE69 # 0 +0xA987 0xFE6A # 0 +0xA988 0xFE6B # 0 +0xA989 0xE7E7 # 0 +0xA98A 0xE7E8 # 0 +0xA98B 0xE7E9 # 0 +0xA98C 0xE7EA # 0 +0xA98D 0xE7EB # 0 +0xA98E 0xE7EC # 0 +0xA98F 0xE7ED # 0 +0xA990 0xE7EE # 0 +0xA991 0xE7EF # 0 +0xA992 0xE7F0 # 0 +0xA993 0xE7F1 # 0 +0xA994 0xE7F2 # 0 +0xA995 0xE7F3 # 0 +0xA996 0x3007 # 0 +0xA997 0xE7F4 # 0 +0xA998 0xE7F5 # 0 +0xA999 0xE7F6 # 0 +0xA99A 0xE7F7 # 0 +0xA99B 0xE7F8 # 0 +0xA99C 0xE7F9 # 0 +0xA99D 0xE7FA # 0 +0xA99E 0xE7FB # 0 +0xA99F 0xE7FC # 0 +0xA9A0 0xE7FD # 0 +0xA9A1 0xE7FE # 0 +0xA9A2 0xE7FF # 0 +0xA9A3 0xE800 # 0 +0xA9A4 0x2500 # 0 +0xA9A5 0x2501 # 0 +0xA9A6 0x2502 # 0 +0xA9A7 0x2503 # 0 +0xA9A8 0x2504 # 0 +0xA9A9 0x2505 # 0 +0xA9AA 0x2506 # 0 +0xA9AB 0x2507 # 0 +0xA9AC 0x2508 # 0 +0xA9AD 0x2509 # 0 +0xA9AE 0x250A # 0 +0xA9AF 0x250B # 0 +0xA9B0 0x250C # 0 +0xA9B1 0x250D # 0 +0xA9B2 0x250E # 0 +0xA9B3 0x250F # 0 +0xA9B4 0x2510 # 0 +0xA9B5 0x2511 # 0 +0xA9B6 0x2512 # 0 +0xA9B7 0x2513 # 0 +0xA9B8 0x2514 # 0 +0xA9B9 0x2515 # 0 +0xA9BA 0x2516 # 0 +0xA9BB 0x2517 # 0 +0xA9BC 0x2518 # 0 +0xA9BD 0x2519 # 0 +0xA9BE 0x251A # 0 +0xA9BF 0x251B # 0 +0xA9C0 0x251C # 0 +0xA9C1 0x251D # 0 +0xA9C2 0x251E # 0 +0xA9C3 0x251F # 0 +0xA9C4 0x2520 # 0 +0xA9C5 0x2521 # 0 +0xA9C6 0x2522 # 0 +0xA9C7 0x2523 # 0 +0xA9C8 0x2524 # 0 +0xA9C9 0x2525 # 0 +0xA9CA 0x2526 # 0 +0xA9CB 0x2527 # 0 +0xA9CC 0x2528 # 0 +0xA9CD 0x2529 # 0 +0xA9CE 0x252A # 0 +0xA9CF 0x252B # 0 +0xA9D0 0x252C # 0 +0xA9D1 0x252D # 0 +0xA9D2 0x252E # 0 +0xA9D3 0x252F # 0 +0xA9D4 0x2530 # 0 +0xA9D5 0x2531 # 0 +0xA9D6 0x2532 # 0 +0xA9D7 0x2533 # 0 +0xA9D8 0x2534 # 0 +0xA9D9 0x2535 # 0 +0xA9DA 0x2536 # 0 +0xA9DB 0x2537 # 0 +0xA9DC 0x2538 # 0 +0xA9DD 0x2539 # 0 +0xA9DE 0x253A # 0 +0xA9DF 0x253B # 0 +0xA9E0 0x253C # 0 +0xA9E1 0x253D # 0 +0xA9E2 0x253E # 0 +0xA9E3 0x253F # 0 +0xA9E4 0x2540 # 0 +0xA9E5 0x2541 # 0 +0xA9E6 0x2542 # 0 +0xA9E7 0x2543 # 0 +0xA9E8 0x2544 # 0 +0xA9E9 0x2545 # 0 +0xA9EA 0x2546 # 0 +0xA9EB 0x2547 # 0 +0xA9EC 0x2548 # 0 +0xA9ED 0x2549 # 0 +0xA9EE 0x254A # 0 +0xA9EF 0x254B # 0 +0xA9F0 0xE801 # 0 +0xA9F1 0xE802 # 0 +0xA9F2 0xE803 # 0 +0xA9F3 0xE804 # 0 +0xA9F4 0xE805 # 0 +0xA9F5 0xE806 # 0 +0xA9F6 0xE807 # 0 +0xA9F7 0xE808 # 0 +0xA9F8 0xE809 # 0 +0xA9F9 0xE80A # 0 +0xA9FA 0xE80B # 0 +0xA9FB 0xE80C # 0 +0xA9FC 0xE80D # 0 +0xA9FD 0xE80E # 0 +0xA9FE 0xE80F # 0 +0xAA40 0x72DC # 0 +0xAA41 0x72DD # 0 +0xAA42 0x72DF # 0 +0xAA43 0x72E2 # 0 +0xAA44 0x72E3 # 0 +0xAA45 0x72E4 # 0 +0xAA46 0x72E5 # 0 +0xAA47 0x72E6 # 0 +0xAA48 0x72E7 # 0 +0xAA49 0x72EA # 0 +0xAA4A 0x72EB # 0 +0xAA4B 0x72F5 # 0 +0xAA4C 0x72F6 # 0 +0xAA4D 0x72F9 # 0 +0xAA4E 0x72FD # 0 +0xAA4F 0x72FE # 0 +0xAA50 0x72FF # 0 +0xAA51 0x7300 # 0 +0xAA52 0x7302 # 0 +0xAA53 0x7304 # 0 +0xAA54 0x7305 # 0 +0xAA55 0x7306 # 0 +0xAA56 0x7307 # 0 +0xAA57 0x7308 # 0 +0xAA58 0x7309 # 0 +0xAA59 0x730B # 0 +0xAA5A 0x730C # 0 +0xAA5B 0x730D # 0 +0xAA5C 0x730F # 0 +0xAA5D 0x7310 # 0 +0xAA5E 0x7311 # 0 +0xAA5F 0x7312 # 0 +0xAA60 0x7314 # 0 +0xAA61 0x7318 # 0 +0xAA62 0x7319 # 0 +0xAA63 0x731A # 0 +0xAA64 0x731F # 0 +0xAA65 0x7320 # 0 +0xAA66 0x7323 # 0 +0xAA67 0x7324 # 0 +0xAA68 0x7326 # 0 +0xAA69 0x7327 # 0 +0xAA6A 0x7328 # 0 +0xAA6B 0x732D # 0 +0xAA6C 0x732F # 0 +0xAA6D 0x7330 # 0 +0xAA6E 0x7332 # 0 +0xAA6F 0x7333 # 0 +0xAA70 0x7335 # 0 +0xAA71 0x7336 # 0 +0xAA72 0x733A # 0 +0xAA73 0x733B # 0 +0xAA74 0x733C # 0 +0xAA75 0x733D # 0 +0xAA76 0x7340 # 0 +0xAA77 0x7341 # 0 +0xAA78 0x7342 # 0 +0xAA79 0x7343 # 0 +0xAA7A 0x7344 # 0 +0xAA7B 0x7345 # 0 +0xAA7C 0x7346 # 0 +0xAA7D 0x7347 # 0 +0xAA7E 0x7348 # 0 +0xAA80 0x7349 # 0 +0xAA81 0x734A # 0 +0xAA82 0x734B # 0 +0xAA83 0x734C # 0 +0xAA84 0x734E # 0 +0xAA85 0x734F # 0 +0xAA86 0x7351 # 0 +0xAA87 0x7353 # 0 +0xAA88 0x7354 # 0 +0xAA89 0x7355 # 0 +0xAA8A 0x7356 # 0 +0xAA8B 0x7358 # 0 +0xAA8C 0x7359 # 0 +0xAA8D 0x735A # 0 +0xAA8E 0x735B # 0 +0xAA8F 0x735C # 0 +0xAA90 0x735D # 0 +0xAA91 0x735E # 0 +0xAA92 0x735F # 0 +0xAA93 0x7361 # 0 +0xAA94 0x7362 # 0 +0xAA95 0x7363 # 0 +0xAA96 0x7364 # 0 +0xAA97 0x7365 # 0 +0xAA98 0x7366 # 0 +0xAA99 0x7367 # 0 +0xAA9A 0x7368 # 0 +0xAA9B 0x7369 # 0 +0xAA9C 0x736A # 0 +0xAA9D 0x736B # 0 +0xAA9E 0x736E # 0 +0xAA9F 0x7370 # 0 +0xAAA0 0x7371 # 0 +0xAAA1 0xE000 # 0 +0xAAA2 0xE001 # 0 +0xAAA3 0xE002 # 0 +0xAAA4 0xE003 # 0 +0xAAA5 0xE004 # 0 +0xAAA6 0xE005 # 0 +0xAAA7 0xE006 # 0 +0xAAA8 0xE007 # 0 +0xAAA9 0xE008 # 0 +0xAAAA 0xE009 # 0 +0xAAAB 0xE00A # 0 +0xAAAC 0xE00B # 0 +0xAAAD 0xE00C # 0 +0xAAAE 0xE00D # 0 +0xAAAF 0xE00E # 0 +0xAAB0 0xE00F # 0 +0xAAB1 0xE010 # 0 +0xAAB2 0xE011 # 0 +0xAAB3 0xE012 # 0 +0xAAB4 0xE013 # 0 +0xAAB5 0xE014 # 0 +0xAAB6 0xE015 # 0 +0xAAB7 0xE016 # 0 +0xAAB8 0xE017 # 0 +0xAAB9 0xE018 # 0 +0xAABA 0xE019 # 0 +0xAABB 0xE01A # 0 +0xAABC 0xE01B # 0 +0xAABD 0xE01C # 0 +0xAABE 0xE01D # 0 +0xAABF 0xE01E # 0 +0xAAC0 0xE01F # 0 +0xAAC1 0xE020 # 0 +0xAAC2 0xE021 # 0 +0xAAC3 0xE022 # 0 +0xAAC4 0xE023 # 0 +0xAAC5 0xE024 # 0 +0xAAC6 0xE025 # 0 +0xAAC7 0xE026 # 0 +0xAAC8 0xE027 # 0 +0xAAC9 0xE028 # 0 +0xAACA 0xE029 # 0 +0xAACB 0xE02A # 0 +0xAACC 0xE02B # 0 +0xAACD 0xE02C # 0 +0xAACE 0xE02D # 0 +0xAACF 0xE02E # 0 +0xAAD0 0xE02F # 0 +0xAAD1 0xE030 # 0 +0xAAD2 0xE031 # 0 +0xAAD3 0xE032 # 0 +0xAAD4 0xE033 # 0 +0xAAD5 0xE034 # 0 +0xAAD6 0xE035 # 0 +0xAAD7 0xE036 # 0 +0xAAD8 0xE037 # 0 +0xAAD9 0xE038 # 0 +0xAADA 0xE039 # 0 +0xAADB 0xE03A # 0 +0xAADC 0xE03B # 0 +0xAADD 0xE03C # 0 +0xAADE 0xE03D # 0 +0xAADF 0xE03E # 0 +0xAAE0 0xE03F # 0 +0xAAE1 0xE040 # 0 +0xAAE2 0xE041 # 0 +0xAAE3 0xE042 # 0 +0xAAE4 0xE043 # 0 +0xAAE5 0xE044 # 0 +0xAAE6 0xE045 # 0 +0xAAE7 0xE046 # 0 +0xAAE8 0xE047 # 0 +0xAAE9 0xE048 # 0 +0xAAEA 0xE049 # 0 +0xAAEB 0xE04A # 0 +0xAAEC 0xE04B # 0 +0xAAED 0xE04C # 0 +0xAAEE 0xE04D # 0 +0xAAEF 0xE04E # 0 +0xAAF0 0xE04F # 0 +0xAAF1 0xE050 # 0 +0xAAF2 0xE051 # 0 +0xAAF3 0xE052 # 0 +0xAAF4 0xE053 # 0 +0xAAF5 0xE054 # 0 +0xAAF6 0xE055 # 0 +0xAAF7 0xE056 # 0 +0xAAF8 0xE057 # 0 +0xAAF9 0xE058 # 0 +0xAAFA 0xE059 # 0 +0xAAFB 0xE05A # 0 +0xAAFC 0xE05B # 0 +0xAAFD 0xE05C # 0 +0xAAFE 0xE05D # 0 +0xAB40 0x7372 # 0 +0xAB41 0x7373 # 0 +0xAB42 0x7374 # 0 +0xAB43 0x7375 # 0 +0xAB44 0x7376 # 0 +0xAB45 0x7377 # 0 +0xAB46 0x7378 # 0 +0xAB47 0x7379 # 0 +0xAB48 0x737A # 0 +0xAB49 0x737B # 0 +0xAB4A 0x737C # 0 +0xAB4B 0x737D # 0 +0xAB4C 0x737F # 0 +0xAB4D 0x7380 # 0 +0xAB4E 0x7381 # 0 +0xAB4F 0x7382 # 0 +0xAB50 0x7383 # 0 +0xAB51 0x7385 # 0 +0xAB52 0x7386 # 0 +0xAB53 0x7388 # 0 +0xAB54 0x738A # 0 +0xAB55 0x738C # 0 +0xAB56 0x738D # 0 +0xAB57 0x738F # 0 +0xAB58 0x7390 # 0 +0xAB59 0x7392 # 0 +0xAB5A 0x7393 # 0 +0xAB5B 0x7394 # 0 +0xAB5C 0x7395 # 0 +0xAB5D 0x7397 # 0 +0xAB5E 0x7398 # 0 +0xAB5F 0x7399 # 0 +0xAB60 0x739A # 0 +0xAB61 0x739C # 0 +0xAB62 0x739D # 0 +0xAB63 0x739E # 0 +0xAB64 0x73A0 # 0 +0xAB65 0x73A1 # 0 +0xAB66 0x73A3 # 0 +0xAB67 0x73A4 # 0 +0xAB68 0x73A5 # 0 +0xAB69 0x73A6 # 0 +0xAB6A 0x73A7 # 0 +0xAB6B 0x73A8 # 0 +0xAB6C 0x73AA # 0 +0xAB6D 0x73AC # 0 +0xAB6E 0x73AD # 0 +0xAB6F 0x73B1 # 0 +0xAB70 0x73B4 # 0 +0xAB71 0x73B5 # 0 +0xAB72 0x73B6 # 0 +0xAB73 0x73B8 # 0 +0xAB74 0x73B9 # 0 +0xAB75 0x73BC # 0 +0xAB76 0x73BD # 0 +0xAB77 0x73BE # 0 +0xAB78 0x73BF # 0 +0xAB79 0x73C1 # 0 +0xAB7A 0x73C3 # 0 +0xAB7B 0x73C4 # 0 +0xAB7C 0x73C5 # 0 +0xAB7D 0x73C6 # 0 +0xAB7E 0x73C7 # 0 +0xAB80 0x73CB # 0 +0xAB81 0x73CC # 0 +0xAB82 0x73CE # 0 +0xAB83 0x73D2 # 0 +0xAB84 0x73D3 # 0 +0xAB85 0x73D4 # 0 +0xAB86 0x73D5 # 0 +0xAB87 0x73D6 # 0 +0xAB88 0x73D7 # 0 +0xAB89 0x73D8 # 0 +0xAB8A 0x73DA # 0 +0xAB8B 0x73DB # 0 +0xAB8C 0x73DC # 0 +0xAB8D 0x73DD # 0 +0xAB8E 0x73DF # 0 +0xAB8F 0x73E1 # 0 +0xAB90 0x73E2 # 0 +0xAB91 0x73E3 # 0 +0xAB92 0x73E4 # 0 +0xAB93 0x73E6 # 0 +0xAB94 0x73E8 # 0 +0xAB95 0x73EA # 0 +0xAB96 0x73EB # 0 +0xAB97 0x73EC # 0 +0xAB98 0x73EE # 0 +0xAB99 0x73EF # 0 +0xAB9A 0x73F0 # 0 +0xAB9B 0x73F1 # 0 +0xAB9C 0x73F3 # 0 +0xAB9D 0x73F4 # 0 +0xAB9E 0x73F5 # 0 +0xAB9F 0x73F6 # 0 +0xABA0 0x73F7 # 0 +0xABA1 0xE05E # 0 +0xABA2 0xE05F # 0 +0xABA3 0xE060 # 0 +0xABA4 0xE061 # 0 +0xABA5 0xE062 # 0 +0xABA6 0xE063 # 0 +0xABA7 0xE064 # 0 +0xABA8 0xE065 # 0 +0xABA9 0xE066 # 0 +0xABAA 0xE067 # 0 +0xABAB 0xE068 # 0 +0xABAC 0xE069 # 0 +0xABAD 0xE06A # 0 +0xABAE 0xE06B # 0 +0xABAF 0xE06C # 0 +0xABB0 0xE06D # 0 +0xABB1 0xE06E # 0 +0xABB2 0xE06F # 0 +0xABB3 0xE070 # 0 +0xABB4 0xE071 # 0 +0xABB5 0xE072 # 0 +0xABB6 0xE073 # 0 +0xABB7 0xE074 # 0 +0xABB8 0xE075 # 0 +0xABB9 0xE076 # 0 +0xABBA 0xE077 # 0 +0xABBB 0xE078 # 0 +0xABBC 0xE079 # 0 +0xABBD 0xE07A # 0 +0xABBE 0xE07B # 0 +0xABBF 0xE07C # 0 +0xABC0 0xE07D # 0 +0xABC1 0xE07E # 0 +0xABC2 0xE07F # 0 +0xABC3 0xE080 # 0 +0xABC4 0xE081 # 0 +0xABC5 0xE082 # 0 +0xABC6 0xE083 # 0 +0xABC7 0xE084 # 0 +0xABC8 0xE085 # 0 +0xABC9 0xE086 # 0 +0xABCA 0xE087 # 0 +0xABCB 0xE088 # 0 +0xABCC 0xE089 # 0 +0xABCD 0xE08A # 0 +0xABCE 0xE08B # 0 +0xABCF 0xE08C # 0 +0xABD0 0xE08D # 0 +0xABD1 0xE08E # 0 +0xABD2 0xE08F # 0 +0xABD3 0xE090 # 0 +0xABD4 0xE091 # 0 +0xABD5 0xE092 # 0 +0xABD6 0xE093 # 0 +0xABD7 0xE094 # 0 +0xABD8 0xE095 # 0 +0xABD9 0xE096 # 0 +0xABDA 0xE097 # 0 +0xABDB 0xE098 # 0 +0xABDC 0xE099 # 0 +0xABDD 0xE09A # 0 +0xABDE 0xE09B # 0 +0xABDF 0xE09C # 0 +0xABE0 0xE09D # 0 +0xABE1 0xE09E # 0 +0xABE2 0xE09F # 0 +0xABE3 0xE0A0 # 0 +0xABE4 0xE0A1 # 0 +0xABE5 0xE0A2 # 0 +0xABE6 0xE0A3 # 0 +0xABE7 0xE0A4 # 0 +0xABE8 0xE0A5 # 0 +0xABE9 0xE0A6 # 0 +0xABEA 0xE0A7 # 0 +0xABEB 0xE0A8 # 0 +0xABEC 0xE0A9 # 0 +0xABED 0xE0AA # 0 +0xABEE 0xE0AB # 0 +0xABEF 0xE0AC # 0 +0xABF0 0xE0AD # 0 +0xABF1 0xE0AE # 0 +0xABF2 0xE0AF # 0 +0xABF3 0xE0B0 # 0 +0xABF4 0xE0B1 # 0 +0xABF5 0xE0B2 # 0 +0xABF6 0xE0B3 # 0 +0xABF7 0xE0B4 # 0 +0xABF8 0xE0B5 # 0 +0xABF9 0xE0B6 # 0 +0xABFA 0xE0B7 # 0 +0xABFB 0xE0B8 # 0 +0xABFC 0xE0B9 # 0 +0xABFD 0xE0BA # 0 +0xABFE 0xE0BB # 0 +0xAC40 0x73F8 # 0 +0xAC41 0x73F9 # 0 +0xAC42 0x73FA # 0 +0xAC43 0x73FB # 0 +0xAC44 0x73FC # 0 +0xAC45 0x73FD # 0 +0xAC46 0x73FE # 0 +0xAC47 0x73FF # 0 +0xAC48 0x7400 # 0 +0xAC49 0x7401 # 0 +0xAC4A 0x7402 # 0 +0xAC4B 0x7404 # 0 +0xAC4C 0x7407 # 0 +0xAC4D 0x7408 # 0 +0xAC4E 0x740B # 0 +0xAC4F 0x740C # 0 +0xAC50 0x740D # 0 +0xAC51 0x740E # 0 +0xAC52 0x7411 # 0 +0xAC53 0x7412 # 0 +0xAC54 0x7413 # 0 +0xAC55 0x7414 # 0 +0xAC56 0x7415 # 0 +0xAC57 0x7416 # 0 +0xAC58 0x7417 # 0 +0xAC59 0x7418 # 0 +0xAC5A 0x7419 # 0 +0xAC5B 0x741C # 0 +0xAC5C 0x741D # 0 +0xAC5D 0x741E # 0 +0xAC5E 0x741F # 0 +0xAC5F 0x7420 # 0 +0xAC60 0x7421 # 0 +0xAC61 0x7423 # 0 +0xAC62 0x7424 # 0 +0xAC63 0x7427 # 0 +0xAC64 0x7429 # 0 +0xAC65 0x742B # 0 +0xAC66 0x742D # 0 +0xAC67 0x742F # 0 +0xAC68 0x7431 # 0 +0xAC69 0x7432 # 0 +0xAC6A 0x7437 # 0 +0xAC6B 0x7438 # 0 +0xAC6C 0x7439 # 0 +0xAC6D 0x743A # 0 +0xAC6E 0x743B # 0 +0xAC6F 0x743D # 0 +0xAC70 0x743E # 0 +0xAC71 0x743F # 0 +0xAC72 0x7440 # 0 +0xAC73 0x7442 # 0 +0xAC74 0x7443 # 0 +0xAC75 0x7444 # 0 +0xAC76 0x7445 # 0 +0xAC77 0x7446 # 0 +0xAC78 0x7447 # 0 +0xAC79 0x7448 # 0 +0xAC7A 0x7449 # 0 +0xAC7B 0x744A # 0 +0xAC7C 0x744B # 0 +0xAC7D 0x744C # 0 +0xAC7E 0x744D # 0 +0xAC80 0x744E # 0 +0xAC81 0x744F # 0 +0xAC82 0x7450 # 0 +0xAC83 0x7451 # 0 +0xAC84 0x7452 # 0 +0xAC85 0x7453 # 0 +0xAC86 0x7454 # 0 +0xAC87 0x7456 # 0 +0xAC88 0x7458 # 0 +0xAC89 0x745D # 0 +0xAC8A 0x7460 # 0 +0xAC8B 0x7461 # 0 +0xAC8C 0x7462 # 0 +0xAC8D 0x7463 # 0 +0xAC8E 0x7464 # 0 +0xAC8F 0x7465 # 0 +0xAC90 0x7466 # 0 +0xAC91 0x7467 # 0 +0xAC92 0x7468 # 0 +0xAC93 0x7469 # 0 +0xAC94 0x746A # 0 +0xAC95 0x746B # 0 +0xAC96 0x746C # 0 +0xAC97 0x746E # 0 +0xAC98 0x746F # 0 +0xAC99 0x7471 # 0 +0xAC9A 0x7472 # 0 +0xAC9B 0x7473 # 0 +0xAC9C 0x7474 # 0 +0xAC9D 0x7475 # 0 +0xAC9E 0x7478 # 0 +0xAC9F 0x7479 # 0 +0xACA0 0x747A # 0 +0xACA1 0xE0BC # 0 +0xACA2 0xE0BD # 0 +0xACA3 0xE0BE # 0 +0xACA4 0xE0BF # 0 +0xACA5 0xE0C0 # 0 +0xACA6 0xE0C1 # 0 +0xACA7 0xE0C2 # 0 +0xACA8 0xE0C3 # 0 +0xACA9 0xE0C4 # 0 +0xACAA 0xE0C5 # 0 +0xACAB 0xE0C6 # 0 +0xACAC 0xE0C7 # 0 +0xACAD 0xE0C8 # 0 +0xACAE 0xE0C9 # 0 +0xACAF 0xE0CA # 0 +0xACB0 0xE0CB # 0 +0xACB1 0xE0CC # 0 +0xACB2 0xE0CD # 0 +0xACB3 0xE0CE # 0 +0xACB4 0xE0CF # 0 +0xACB5 0xE0D0 # 0 +0xACB6 0xE0D1 # 0 +0xACB7 0xE0D2 # 0 +0xACB8 0xE0D3 # 0 +0xACB9 0xE0D4 # 0 +0xACBA 0xE0D5 # 0 +0xACBB 0xE0D6 # 0 +0xACBC 0xE0D7 # 0 +0xACBD 0xE0D8 # 0 +0xACBE 0xE0D9 # 0 +0xACBF 0xE0DA # 0 +0xACC0 0xE0DB # 0 +0xACC1 0xE0DC # 0 +0xACC2 0xE0DD # 0 +0xACC3 0xE0DE # 0 +0xACC4 0xE0DF # 0 +0xACC5 0xE0E0 # 0 +0xACC6 0xE0E1 # 0 +0xACC7 0xE0E2 # 0 +0xACC8 0xE0E3 # 0 +0xACC9 0xE0E4 # 0 +0xACCA 0xE0E5 # 0 +0xACCB 0xE0E6 # 0 +0xACCC 0xE0E7 # 0 +0xACCD 0xE0E8 # 0 +0xACCE 0xE0E9 # 0 +0xACCF 0xE0EA # 0 +0xACD0 0xE0EB # 0 +0xACD1 0xE0EC # 0 +0xACD2 0xE0ED # 0 +0xACD3 0xE0EE # 0 +0xACD4 0xE0EF # 0 +0xACD5 0xE0F0 # 0 +0xACD6 0xE0F1 # 0 +0xACD7 0xE0F2 # 0 +0xACD8 0xE0F3 # 0 +0xACD9 0xE0F4 # 0 +0xACDA 0xE0F5 # 0 +0xACDB 0xE0F6 # 0 +0xACDC 0xE0F7 # 0 +0xACDD 0xE0F8 # 0 +0xACDE 0xE0F9 # 0 +0xACDF 0xE0FA # 0 +0xACE0 0xE0FB # 0 +0xACE1 0xE0FC # 0 +0xACE2 0xE0FD # 0 +0xACE3 0xE0FE # 0 +0xACE4 0xE0FF # 0 +0xACE5 0xE100 # 0 +0xACE6 0xE101 # 0 +0xACE7 0xE102 # 0 +0xACE8 0xE103 # 0 +0xACE9 0xE104 # 0 +0xACEA 0xE105 # 0 +0xACEB 0xE106 # 0 +0xACEC 0xE107 # 0 +0xACED 0xE108 # 0 +0xACEE 0xE109 # 0 +0xACEF 0xE10A # 0 +0xACF0 0xE10B # 0 +0xACF1 0xE10C # 0 +0xACF2 0xE10D # 0 +0xACF3 0xE10E # 0 +0xACF4 0xE10F # 0 +0xACF5 0xE110 # 0 +0xACF6 0xE111 # 0 +0xACF7 0xE112 # 0 +0xACF8 0xE113 # 0 +0xACF9 0xE114 # 0 +0xACFA 0xE115 # 0 +0xACFB 0xE116 # 0 +0xACFC 0xE117 # 0 +0xACFD 0xE118 # 0 +0xACFE 0xE119 # 0 +0xAD40 0x747B # 0 +0xAD41 0x747C # 0 +0xAD42 0x747D # 0 +0xAD43 0x747F # 0 +0xAD44 0x7482 # 0 +0xAD45 0x7484 # 0 +0xAD46 0x7485 # 0 +0xAD47 0x7486 # 0 +0xAD48 0x7488 # 0 +0xAD49 0x7489 # 0 +0xAD4A 0x748A # 0 +0xAD4B 0x748C # 0 +0xAD4C 0x748D # 0 +0xAD4D 0x748F # 0 +0xAD4E 0x7491 # 0 +0xAD4F 0x7492 # 0 +0xAD50 0x7493 # 0 +0xAD51 0x7494 # 0 +0xAD52 0x7495 # 0 +0xAD53 0x7496 # 0 +0xAD54 0x7497 # 0 +0xAD55 0x7498 # 0 +0xAD56 0x7499 # 0 +0xAD57 0x749A # 0 +0xAD58 0x749B # 0 +0xAD59 0x749D # 0 +0xAD5A 0x749F # 0 +0xAD5B 0x74A0 # 0 +0xAD5C 0x74A1 # 0 +0xAD5D 0x74A2 # 0 +0xAD5E 0x74A3 # 0 +0xAD5F 0x74A4 # 0 +0xAD60 0x74A5 # 0 +0xAD61 0x74A6 # 0 +0xAD62 0x74AA # 0 +0xAD63 0x74AB # 0 +0xAD64 0x74AC # 0 +0xAD65 0x74AD # 0 +0xAD66 0x74AE # 0 +0xAD67 0x74AF # 0 +0xAD68 0x74B0 # 0 +0xAD69 0x74B1 # 0 +0xAD6A 0x74B2 # 0 +0xAD6B 0x74B3 # 0 +0xAD6C 0x74B4 # 0 +0xAD6D 0x74B5 # 0 +0xAD6E 0x74B6 # 0 +0xAD6F 0x74B7 # 0 +0xAD70 0x74B8 # 0 +0xAD71 0x74B9 # 0 +0xAD72 0x74BB # 0 +0xAD73 0x74BC # 0 +0xAD74 0x74BD # 0 +0xAD75 0x74BE # 0 +0xAD76 0x74BF # 0 +0xAD77 0x74C0 # 0 +0xAD78 0x74C1 # 0 +0xAD79 0x74C2 # 0 +0xAD7A 0x74C3 # 0 +0xAD7B 0x74C4 # 0 +0xAD7C 0x74C5 # 0 +0xAD7D 0x74C6 # 0 +0xAD7E 0x74C7 # 0 +0xAD80 0x74C8 # 0 +0xAD81 0x74C9 # 0 +0xAD82 0x74CA # 0 +0xAD83 0x74CB # 0 +0xAD84 0x74CC # 0 +0xAD85 0x74CD # 0 +0xAD86 0x74CE # 0 +0xAD87 0x74CF # 0 +0xAD88 0x74D0 # 0 +0xAD89 0x74D1 # 0 +0xAD8A 0x74D3 # 0 +0xAD8B 0x74D4 # 0 +0xAD8C 0x74D5 # 0 +0xAD8D 0x74D6 # 0 +0xAD8E 0x74D7 # 0 +0xAD8F 0x74D8 # 0 +0xAD90 0x74D9 # 0 +0xAD91 0x74DA # 0 +0xAD92 0x74DB # 0 +0xAD93 0x74DD # 0 +0xAD94 0x74DF # 0 +0xAD95 0x74E1 # 0 +0xAD96 0x74E5 # 0 +0xAD97 0x74E7 # 0 +0xAD98 0x74E8 # 0 +0xAD99 0x74E9 # 0 +0xAD9A 0x74EA # 0 +0xAD9B 0x74EB # 0 +0xAD9C 0x74EC # 0 +0xAD9D 0x74ED # 0 +0xAD9E 0x74F0 # 0 +0xAD9F 0x74F1 # 0 +0xADA0 0x74F2 # 0 +0xADA1 0xE11A # 0 +0xADA2 0xE11B # 0 +0xADA3 0xE11C # 0 +0xADA4 0xE11D # 0 +0xADA5 0xE11E # 0 +0xADA6 0xE11F # 0 +0xADA7 0xE120 # 0 +0xADA8 0xE121 # 0 +0xADA9 0xE122 # 0 +0xADAA 0xE123 # 0 +0xADAB 0xE124 # 0 +0xADAC 0xE125 # 0 +0xADAD 0xE126 # 0 +0xADAE 0xE127 # 0 +0xADAF 0xE128 # 0 +0xADB0 0xE129 # 0 +0xADB1 0xE12A # 0 +0xADB2 0xE12B # 0 +0xADB3 0xE12C # 0 +0xADB4 0xE12D # 0 +0xADB5 0xE12E # 0 +0xADB6 0xE12F # 0 +0xADB7 0xE130 # 0 +0xADB8 0xE131 # 0 +0xADB9 0xE132 # 0 +0xADBA 0xE133 # 0 +0xADBB 0xE134 # 0 +0xADBC 0xE135 # 0 +0xADBD 0xE136 # 0 +0xADBE 0xE137 # 0 +0xADBF 0xE138 # 0 +0xADC0 0xE139 # 0 +0xADC1 0xE13A # 0 +0xADC2 0xE13B # 0 +0xADC3 0xE13C # 0 +0xADC4 0xE13D # 0 +0xADC5 0xE13E # 0 +0xADC6 0xE13F # 0 +0xADC7 0xE140 # 0 +0xADC8 0xE141 # 0 +0xADC9 0xE142 # 0 +0xADCA 0xE143 # 0 +0xADCB 0xE144 # 0 +0xADCC 0xE145 # 0 +0xADCD 0xE146 # 0 +0xADCE 0xE147 # 0 +0xADCF 0xE148 # 0 +0xADD0 0xE149 # 0 +0xADD1 0xE14A # 0 +0xADD2 0xE14B # 0 +0xADD3 0xE14C # 0 +0xADD4 0xE14D # 0 +0xADD5 0xE14E # 0 +0xADD6 0xE14F # 0 +0xADD7 0xE150 # 0 +0xADD8 0xE151 # 0 +0xADD9 0xE152 # 0 +0xADDA 0xE153 # 0 +0xADDB 0xE154 # 0 +0xADDC 0xE155 # 0 +0xADDD 0xE156 # 0 +0xADDE 0xE157 # 0 +0xADDF 0xE158 # 0 +0xADE0 0xE159 # 0 +0xADE1 0xE15A # 0 +0xADE2 0xE15B # 0 +0xADE3 0xE15C # 0 +0xADE4 0xE15D # 0 +0xADE5 0xE15E # 0 +0xADE6 0xE15F # 0 +0xADE7 0xE160 # 0 +0xADE8 0xE161 # 0 +0xADE9 0xE162 # 0 +0xADEA 0xE163 # 0 +0xADEB 0xE164 # 0 +0xADEC 0xE165 # 0 +0xADED 0xE166 # 0 +0xADEE 0xE167 # 0 +0xADEF 0xE168 # 0 +0xADF0 0xE169 # 0 +0xADF1 0xE16A # 0 +0xADF2 0xE16B # 0 +0xADF3 0xE16C # 0 +0xADF4 0xE16D # 0 +0xADF5 0xE16E # 0 +0xADF6 0xE16F # 0 +0xADF7 0xE170 # 0 +0xADF8 0xE171 # 0 +0xADF9 0xE172 # 0 +0xADFA 0xE173 # 0 +0xADFB 0xE174 # 0 +0xADFC 0xE175 # 0 +0xADFD 0xE176 # 0 +0xADFE 0xE177 # 0 +0xAE40 0x74F3 # 0 +0xAE41 0x74F5 # 0 +0xAE42 0x74F8 # 0 +0xAE43 0x74F9 # 0 +0xAE44 0x74FA # 0 +0xAE45 0x74FB # 0 +0xAE46 0x74FC # 0 +0xAE47 0x74FD # 0 +0xAE48 0x74FE # 0 +0xAE49 0x7500 # 0 +0xAE4A 0x7501 # 0 +0xAE4B 0x7502 # 0 +0xAE4C 0x7503 # 0 +0xAE4D 0x7505 # 0 +0xAE4E 0x7506 # 0 +0xAE4F 0x7507 # 0 +0xAE50 0x7508 # 0 +0xAE51 0x7509 # 0 +0xAE52 0x750A # 0 +0xAE53 0x750B # 0 +0xAE54 0x750C # 0 +0xAE55 0x750E # 0 +0xAE56 0x7510 # 0 +0xAE57 0x7512 # 0 +0xAE58 0x7514 # 0 +0xAE59 0x7515 # 0 +0xAE5A 0x7516 # 0 +0xAE5B 0x7517 # 0 +0xAE5C 0x751B # 0 +0xAE5D 0x751D # 0 +0xAE5E 0x751E # 0 +0xAE5F 0x7520 # 0 +0xAE60 0x7521 # 0 +0xAE61 0x7522 # 0 +0xAE62 0x7523 # 0 +0xAE63 0x7524 # 0 +0xAE64 0x7526 # 0 +0xAE65 0x7527 # 0 +0xAE66 0x752A # 0 +0xAE67 0x752E # 0 +0xAE68 0x7534 # 0 +0xAE69 0x7536 # 0 +0xAE6A 0x7539 # 0 +0xAE6B 0x753C # 0 +0xAE6C 0x753D # 0 +0xAE6D 0x753F # 0 +0xAE6E 0x7541 # 0 +0xAE6F 0x7542 # 0 +0xAE70 0x7543 # 0 +0xAE71 0x7544 # 0 +0xAE72 0x7546 # 0 +0xAE73 0x7547 # 0 +0xAE74 0x7549 # 0 +0xAE75 0x754A # 0 +0xAE76 0x754D # 0 +0xAE77 0x7550 # 0 +0xAE78 0x7551 # 0 +0xAE79 0x7552 # 0 +0xAE7A 0x7553 # 0 +0xAE7B 0x7555 # 0 +0xAE7C 0x7556 # 0 +0xAE7D 0x7557 # 0 +0xAE7E 0x7558 # 0 +0xAE80 0x755D # 0 +0xAE81 0x755E # 0 +0xAE82 0x755F # 0 +0xAE83 0x7560 # 0 +0xAE84 0x7561 # 0 +0xAE85 0x7562 # 0 +0xAE86 0x7563 # 0 +0xAE87 0x7564 # 0 +0xAE88 0x7567 # 0 +0xAE89 0x7568 # 0 +0xAE8A 0x7569 # 0 +0xAE8B 0x756B # 0 +0xAE8C 0x756C # 0 +0xAE8D 0x756D # 0 +0xAE8E 0x756E # 0 +0xAE8F 0x756F # 0 +0xAE90 0x7570 # 0 +0xAE91 0x7571 # 0 +0xAE92 0x7573 # 0 +0xAE93 0x7575 # 0 +0xAE94 0x7576 # 0 +0xAE95 0x7577 # 0 +0xAE96 0x757A # 0 +0xAE97 0x757B # 0 +0xAE98 0x757C # 0 +0xAE99 0x757D # 0 +0xAE9A 0x757E # 0 +0xAE9B 0x7580 # 0 +0xAE9C 0x7581 # 0 +0xAE9D 0x7582 # 0 +0xAE9E 0x7584 # 0 +0xAE9F 0x7585 # 0 +0xAEA0 0x7587 # 0 +0xAEA1 0xE178 # 0 +0xAEA2 0xE179 # 0 +0xAEA3 0xE17A # 0 +0xAEA4 0xE17B # 0 +0xAEA5 0xE17C # 0 +0xAEA6 0xE17D # 0 +0xAEA7 0xE17E # 0 +0xAEA8 0xE17F # 0 +0xAEA9 0xE180 # 0 +0xAEAA 0xE181 # 0 +0xAEAB 0xE182 # 0 +0xAEAC 0xE183 # 0 +0xAEAD 0xE184 # 0 +0xAEAE 0xE185 # 0 +0xAEAF 0xE186 # 0 +0xAEB0 0xE187 # 0 +0xAEB1 0xE188 # 0 +0xAEB2 0xE189 # 0 +0xAEB3 0xE18A # 0 +0xAEB4 0xE18B # 0 +0xAEB5 0xE18C # 0 +0xAEB6 0xE18D # 0 +0xAEB7 0xE18E # 0 +0xAEB8 0xE18F # 0 +0xAEB9 0xE190 # 0 +0xAEBA 0xE191 # 0 +0xAEBB 0xE192 # 0 +0xAEBC 0xE193 # 0 +0xAEBD 0xE194 # 0 +0xAEBE 0xE195 # 0 +0xAEBF 0xE196 # 0 +0xAEC0 0xE197 # 0 +0xAEC1 0xE198 # 0 +0xAEC2 0xE199 # 0 +0xAEC3 0xE19A # 0 +0xAEC4 0xE19B # 0 +0xAEC5 0xE19C # 0 +0xAEC6 0xE19D # 0 +0xAEC7 0xE19E # 0 +0xAEC8 0xE19F # 0 +0xAEC9 0xE1A0 # 0 +0xAECA 0xE1A1 # 0 +0xAECB 0xE1A2 # 0 +0xAECC 0xE1A3 # 0 +0xAECD 0xE1A4 # 0 +0xAECE 0xE1A5 # 0 +0xAECF 0xE1A6 # 0 +0xAED0 0xE1A7 # 0 +0xAED1 0xE1A8 # 0 +0xAED2 0xE1A9 # 0 +0xAED3 0xE1AA # 0 +0xAED4 0xE1AB # 0 +0xAED5 0xE1AC # 0 +0xAED6 0xE1AD # 0 +0xAED7 0xE1AE # 0 +0xAED8 0xE1AF # 0 +0xAED9 0xE1B0 # 0 +0xAEDA 0xE1B1 # 0 +0xAEDB 0xE1B2 # 0 +0xAEDC 0xE1B3 # 0 +0xAEDD 0xE1B4 # 0 +0xAEDE 0xE1B5 # 0 +0xAEDF 0xE1B6 # 0 +0xAEE0 0xE1B7 # 0 +0xAEE1 0xE1B8 # 0 +0xAEE2 0xE1B9 # 0 +0xAEE3 0xE1BA # 0 +0xAEE4 0xE1BB # 0 +0xAEE5 0xE1BC # 0 +0xAEE6 0xE1BD # 0 +0xAEE7 0xE1BE # 0 +0xAEE8 0xE1BF # 0 +0xAEE9 0xE1C0 # 0 +0xAEEA 0xE1C1 # 0 +0xAEEB 0xE1C2 # 0 +0xAEEC 0xE1C3 # 0 +0xAEED 0xE1C4 # 0 +0xAEEE 0xE1C5 # 0 +0xAEEF 0xE1C6 # 0 +0xAEF0 0xE1C7 # 0 +0xAEF1 0xE1C8 # 0 +0xAEF2 0xE1C9 # 0 +0xAEF3 0xE1CA # 0 +0xAEF4 0xE1CB # 0 +0xAEF5 0xE1CC # 0 +0xAEF6 0xE1CD # 0 +0xAEF7 0xE1CE # 0 +0xAEF8 0xE1CF # 0 +0xAEF9 0xE1D0 # 0 +0xAEFA 0xE1D1 # 0 +0xAEFB 0xE1D2 # 0 +0xAEFC 0xE1D3 # 0 +0xAEFD 0xE1D4 # 0 +0xAEFE 0xE1D5 # 0 +0xAF40 0x7588 # 0 +0xAF41 0x7589 # 0 +0xAF42 0x758A # 0 +0xAF43 0x758C # 0 +0xAF44 0x758D # 0 +0xAF45 0x758E # 0 +0xAF46 0x7590 # 0 +0xAF47 0x7593 # 0 +0xAF48 0x7595 # 0 +0xAF49 0x7598 # 0 +0xAF4A 0x759B # 0 +0xAF4B 0x759C # 0 +0xAF4C 0x759E # 0 +0xAF4D 0x75A2 # 0 +0xAF4E 0x75A6 # 0 +0xAF4F 0x75A7 # 0 +0xAF50 0x75A8 # 0 +0xAF51 0x75A9 # 0 +0xAF52 0x75AA # 0 +0xAF53 0x75AD # 0 +0xAF54 0x75B6 # 0 +0xAF55 0x75B7 # 0 +0xAF56 0x75BA # 0 +0xAF57 0x75BB # 0 +0xAF58 0x75BF # 0 +0xAF59 0x75C0 # 0 +0xAF5A 0x75C1 # 0 +0xAF5B 0x75C6 # 0 +0xAF5C 0x75CB # 0 +0xAF5D 0x75CC # 0 +0xAF5E 0x75CE # 0 +0xAF5F 0x75CF # 0 +0xAF60 0x75D0 # 0 +0xAF61 0x75D1 # 0 +0xAF62 0x75D3 # 0 +0xAF63 0x75D7 # 0 +0xAF64 0x75D9 # 0 +0xAF65 0x75DA # 0 +0xAF66 0x75DC # 0 +0xAF67 0x75DD # 0 +0xAF68 0x75DF # 0 +0xAF69 0x75E0 # 0 +0xAF6A 0x75E1 # 0 +0xAF6B 0x75E5 # 0 +0xAF6C 0x75E9 # 0 +0xAF6D 0x75EC # 0 +0xAF6E 0x75ED # 0 +0xAF6F 0x75EE # 0 +0xAF70 0x75EF # 0 +0xAF71 0x75F2 # 0 +0xAF72 0x75F3 # 0 +0xAF73 0x75F5 # 0 +0xAF74 0x75F6 # 0 +0xAF75 0x75F7 # 0 +0xAF76 0x75F8 # 0 +0xAF77 0x75FA # 0 +0xAF78 0x75FB # 0 +0xAF79 0x75FD # 0 +0xAF7A 0x75FE # 0 +0xAF7B 0x7602 # 0 +0xAF7C 0x7604 # 0 +0xAF7D 0x7606 # 0 +0xAF7E 0x7607 # 0 +0xAF80 0x7608 # 0 +0xAF81 0x7609 # 0 +0xAF82 0x760B # 0 +0xAF83 0x760D # 0 +0xAF84 0x760E # 0 +0xAF85 0x760F # 0 +0xAF86 0x7611 # 0 +0xAF87 0x7612 # 0 +0xAF88 0x7613 # 0 +0xAF89 0x7614 # 0 +0xAF8A 0x7616 # 0 +0xAF8B 0x761A # 0 +0xAF8C 0x761C # 0 +0xAF8D 0x761D # 0 +0xAF8E 0x761E # 0 +0xAF8F 0x7621 # 0 +0xAF90 0x7623 # 0 +0xAF91 0x7627 # 0 +0xAF92 0x7628 # 0 +0xAF93 0x762C # 0 +0xAF94 0x762E # 0 +0xAF95 0x762F # 0 +0xAF96 0x7631 # 0 +0xAF97 0x7632 # 0 +0xAF98 0x7636 # 0 +0xAF99 0x7637 # 0 +0xAF9A 0x7639 # 0 +0xAF9B 0x763A # 0 +0xAF9C 0x763B # 0 +0xAF9D 0x763D # 0 +0xAF9E 0x7641 # 0 +0xAF9F 0x7642 # 0 +0xAFA0 0x7644 # 0 +0xAFA1 0xE1D6 # 0 +0xAFA2 0xE1D7 # 0 +0xAFA3 0xE1D8 # 0 +0xAFA4 0xE1D9 # 0 +0xAFA5 0xE1DA # 0 +0xAFA6 0xE1DB # 0 +0xAFA7 0xE1DC # 0 +0xAFA8 0xE1DD # 0 +0xAFA9 0xE1DE # 0 +0xAFAA 0xE1DF # 0 +0xAFAB 0xE1E0 # 0 +0xAFAC 0xE1E1 # 0 +0xAFAD 0xE1E2 # 0 +0xAFAE 0xE1E3 # 0 +0xAFAF 0xE1E4 # 0 +0xAFB0 0xE1E5 # 0 +0xAFB1 0xE1E6 # 0 +0xAFB2 0xE1E7 # 0 +0xAFB3 0xE1E8 # 0 +0xAFB4 0xE1E9 # 0 +0xAFB5 0xE1EA # 0 +0xAFB6 0xE1EB # 0 +0xAFB7 0xE1EC # 0 +0xAFB8 0xE1ED # 0 +0xAFB9 0xE1EE # 0 +0xAFBA 0xE1EF # 0 +0xAFBB 0xE1F0 # 0 +0xAFBC 0xE1F1 # 0 +0xAFBD 0xE1F2 # 0 +0xAFBE 0xE1F3 # 0 +0xAFBF 0xE1F4 # 0 +0xAFC0 0xE1F5 # 0 +0xAFC1 0xE1F6 # 0 +0xAFC2 0xE1F7 # 0 +0xAFC3 0xE1F8 # 0 +0xAFC4 0xE1F9 # 0 +0xAFC5 0xE1FA # 0 +0xAFC6 0xE1FB # 0 +0xAFC7 0xE1FC # 0 +0xAFC8 0xE1FD # 0 +0xAFC9 0xE1FE # 0 +0xAFCA 0xE1FF # 0 +0xAFCB 0xE200 # 0 +0xAFCC 0xE201 # 0 +0xAFCD 0xE202 # 0 +0xAFCE 0xE203 # 0 +0xAFCF 0xE204 # 0 +0xAFD0 0xE205 # 0 +0xAFD1 0xE206 # 0 +0xAFD2 0xE207 # 0 +0xAFD3 0xE208 # 0 +0xAFD4 0xE209 # 0 +0xAFD5 0xE20A # 0 +0xAFD6 0xE20B # 0 +0xAFD7 0xE20C # 0 +0xAFD8 0xE20D # 0 +0xAFD9 0xE20E # 0 +0xAFDA 0xE20F # 0 +0xAFDB 0xE210 # 0 +0xAFDC 0xE211 # 0 +0xAFDD 0xE212 # 0 +0xAFDE 0xE213 # 0 +0xAFDF 0xE214 # 0 +0xAFE0 0xE215 # 0 +0xAFE1 0xE216 # 0 +0xAFE2 0xE217 # 0 +0xAFE3 0xE218 # 0 +0xAFE4 0xE219 # 0 +0xAFE5 0xE21A # 0 +0xAFE6 0xE21B # 0 +0xAFE7 0xE21C # 0 +0xAFE8 0xE21D # 0 +0xAFE9 0xE21E # 0 +0xAFEA 0xE21F # 0 +0xAFEB 0xE220 # 0 +0xAFEC 0xE221 # 0 +0xAFED 0xE222 # 0 +0xAFEE 0xE223 # 0 +0xAFEF 0xE224 # 0 +0xAFF0 0xE225 # 0 +0xAFF1 0xE226 # 0 +0xAFF2 0xE227 # 0 +0xAFF3 0xE228 # 0 +0xAFF4 0xE229 # 0 +0xAFF5 0xE22A # 0 +0xAFF6 0xE22B # 0 +0xAFF7 0xE22C # 0 +0xAFF8 0xE22D # 0 +0xAFF9 0xE22E # 0 +0xAFFA 0xE22F # 0 +0xAFFB 0xE230 # 0 +0xAFFC 0xE231 # 0 +0xAFFD 0xE232 # 0 +0xAFFE 0xE233 # 0 +0xB040 0x7645 # 0 +0xB041 0x7646 # 0 +0xB042 0x7647 # 0 +0xB043 0x7648 # 0 +0xB044 0x7649 # 0 +0xB045 0x764A # 0 +0xB046 0x764B # 0 +0xB047 0x764E # 0 +0xB048 0x764F # 0 +0xB049 0x7650 # 0 +0xB04A 0x7651 # 0 +0xB04B 0x7652 # 0 +0xB04C 0x7653 # 0 +0xB04D 0x7655 # 0 +0xB04E 0x7657 # 0 +0xB04F 0x7658 # 0 +0xB050 0x7659 # 0 +0xB051 0x765A # 0 +0xB052 0x765B # 0 +0xB053 0x765D # 0 +0xB054 0x765F # 0 +0xB055 0x7660 # 0 +0xB056 0x7661 # 0 +0xB057 0x7662 # 0 +0xB058 0x7664 # 0 +0xB059 0x7665 # 0 +0xB05A 0x7666 # 0 +0xB05B 0x7667 # 0 +0xB05C 0x7668 # 0 +0xB05D 0x7669 # 0 +0xB05E 0x766A # 0 +0xB05F 0x766C # 0 +0xB060 0x766D # 0 +0xB061 0x766E # 0 +0xB062 0x7670 # 0 +0xB063 0x7671 # 0 +0xB064 0x7672 # 0 +0xB065 0x7673 # 0 +0xB066 0x7674 # 0 +0xB067 0x7675 # 0 +0xB068 0x7676 # 0 +0xB069 0x7677 # 0 +0xB06A 0x7679 # 0 +0xB06B 0x767A # 0 +0xB06C 0x767C # 0 +0xB06D 0x767F # 0 +0xB06E 0x7680 # 0 +0xB06F 0x7681 # 0 +0xB070 0x7683 # 0 +0xB071 0x7685 # 0 +0xB072 0x7689 # 0 +0xB073 0x768A # 0 +0xB074 0x768C # 0 +0xB075 0x768D # 0 +0xB076 0x768F # 0 +0xB077 0x7690 # 0 +0xB078 0x7692 # 0 +0xB079 0x7694 # 0 +0xB07A 0x7695 # 0 +0xB07B 0x7697 # 0 +0xB07C 0x7698 # 0 +0xB07D 0x769A # 0 +0xB07E 0x769B # 0 +0xB080 0x769C # 0 +0xB081 0x769D # 0 +0xB082 0x769E # 0 +0xB083 0x769F # 0 +0xB084 0x76A0 # 0 +0xB085 0x76A1 # 0 +0xB086 0x76A2 # 0 +0xB087 0x76A3 # 0 +0xB088 0x76A5 # 0 +0xB089 0x76A6 # 0 +0xB08A 0x76A7 # 0 +0xB08B 0x76A8 # 0 +0xB08C 0x76A9 # 0 +0xB08D 0x76AA # 0 +0xB08E 0x76AB # 0 +0xB08F 0x76AC # 0 +0xB090 0x76AD # 0 +0xB091 0x76AF # 0 +0xB092 0x76B0 # 0 +0xB093 0x76B3 # 0 +0xB094 0x76B5 # 0 +0xB095 0x76B6 # 0 +0xB096 0x76B7 # 0 +0xB097 0x76B8 # 0 +0xB098 0x76B9 # 0 +0xB099 0x76BA # 0 +0xB09A 0x76BB # 0 +0xB09B 0x76BC # 0 +0xB09C 0x76BD # 0 +0xB09D 0x76BE # 0 +0xB09E 0x76C0 # 0 +0xB09F 0x76C1 # 0 +0xB0A0 0x76C3 # 0 +0xB0A1 0x554A # 0 +0xB0A2 0x963F # 0 +0xB0A3 0x57C3 # 0 +0xB0A4 0x6328 # 0 +0xB0A5 0x54CE # 0 +0xB0A6 0x5509 # 0 +0xB0A7 0x54C0 # 0 +0xB0A8 0x7691 # 0 +0xB0A9 0x764C # 0 +0xB0AA 0x853C # 0 +0xB0AB 0x77EE # 0 +0xB0AC 0x827E # 0 +0xB0AD 0x788D # 0 +0xB0AE 0x7231 # 0 +0xB0AF 0x9698 # 0 +0xB0B0 0x978D # 0 +0xB0B1 0x6C28 # 0 +0xB0B2 0x5B89 # 0 +0xB0B3 0x4FFA # 0 +0xB0B4 0x6309 # 0 +0xB0B5 0x6697 # 0 +0xB0B6 0x5CB8 # 0 +0xB0B7 0x80FA # 0 +0xB0B8 0x6848 # 0 +0xB0B9 0x80AE # 0 +0xB0BA 0x6602 # 0 +0xB0BB 0x76CE # 0 +0xB0BC 0x51F9 # 0 +0xB0BD 0x6556 # 0 +0xB0BE 0x71AC # 0 +0xB0BF 0x7FF1 # 0 +0xB0C0 0x8884 # 0 +0xB0C1 0x50B2 # 0 +0xB0C2 0x5965 # 0 +0xB0C3 0x61CA # 0 +0xB0C4 0x6FB3 # 0 +0xB0C5 0x82AD # 0 +0xB0C6 0x634C # 0 +0xB0C7 0x6252 # 0 +0xB0C8 0x53ED # 0 +0xB0C9 0x5427 # 0 +0xB0CA 0x7B06 # 0 +0xB0CB 0x516B # 0 +0xB0CC 0x75A4 # 0 +0xB0CD 0x5DF4 # 0 +0xB0CE 0x62D4 # 0 +0xB0CF 0x8DCB # 0 +0xB0D0 0x9776 # 0 +0xB0D1 0x628A # 0 +0xB0D2 0x8019 # 0 +0xB0D3 0x575D # 0 +0xB0D4 0x9738 # 0 +0xB0D5 0x7F62 # 0 +0xB0D6 0x7238 # 0 +0xB0D7 0x767D # 0 +0xB0D8 0x67CF # 0 +0xB0D9 0x767E # 0 +0xB0DA 0x6446 # 0 +0xB0DB 0x4F70 # 0 +0xB0DC 0x8D25 # 0 +0xB0DD 0x62DC # 0 +0xB0DE 0x7A17 # 0 +0xB0DF 0x6591 # 0 +0xB0E0 0x73ED # 0 +0xB0E1 0x642C # 0 +0xB0E2 0x6273 # 0 +0xB0E3 0x822C # 0 +0xB0E4 0x9881 # 0 +0xB0E5 0x677F # 0 +0xB0E6 0x7248 # 0 +0xB0E7 0x626E # 0 +0xB0E8 0x62CC # 0 +0xB0E9 0x4F34 # 0 +0xB0EA 0x74E3 # 0 +0xB0EB 0x534A # 0 +0xB0EC 0x529E # 0 +0xB0ED 0x7ECA # 0 +0xB0EE 0x90A6 # 0 +0xB0EF 0x5E2E # 0 +0xB0F0 0x6886 # 0 +0xB0F1 0x699C # 0 +0xB0F2 0x8180 # 0 +0xB0F3 0x7ED1 # 0 +0xB0F4 0x68D2 # 0 +0xB0F5 0x78C5 # 0 +0xB0F6 0x868C # 0 +0xB0F7 0x9551 # 0 +0xB0F8 0x508D # 0 +0xB0F9 0x8C24 # 0 +0xB0FA 0x82DE # 0 +0xB0FB 0x80DE # 0 +0xB0FC 0x5305 # 0 +0xB0FD 0x8912 # 0 +0xB0FE 0x5265 # 0 +0xB140 0x76C4 # 0 +0xB141 0x76C7 # 0 +0xB142 0x76C9 # 0 +0xB143 0x76CB # 0 +0xB144 0x76CC # 0 +0xB145 0x76D3 # 0 +0xB146 0x76D5 # 0 +0xB147 0x76D9 # 0 +0xB148 0x76DA # 0 +0xB149 0x76DC # 0 +0xB14A 0x76DD # 0 +0xB14B 0x76DE # 0 +0xB14C 0x76E0 # 0 +0xB14D 0x76E1 # 0 +0xB14E 0x76E2 # 0 +0xB14F 0x76E3 # 0 +0xB150 0x76E4 # 0 +0xB151 0x76E6 # 0 +0xB152 0x76E7 # 0 +0xB153 0x76E8 # 0 +0xB154 0x76E9 # 0 +0xB155 0x76EA # 0 +0xB156 0x76EB # 0 +0xB157 0x76EC # 0 +0xB158 0x76ED # 0 +0xB159 0x76F0 # 0 +0xB15A 0x76F3 # 0 +0xB15B 0x76F5 # 0 +0xB15C 0x76F6 # 0 +0xB15D 0x76F7 # 0 +0xB15E 0x76FA # 0 +0xB15F 0x76FB # 0 +0xB160 0x76FD # 0 +0xB161 0x76FF # 0 +0xB162 0x7700 # 0 +0xB163 0x7702 # 0 +0xB164 0x7703 # 0 +0xB165 0x7705 # 0 +0xB166 0x7706 # 0 +0xB167 0x770A # 0 +0xB168 0x770C # 0 +0xB169 0x770E # 0 +0xB16A 0x770F # 0 +0xB16B 0x7710 # 0 +0xB16C 0x7711 # 0 +0xB16D 0x7712 # 0 +0xB16E 0x7713 # 0 +0xB16F 0x7714 # 0 +0xB170 0x7715 # 0 +0xB171 0x7716 # 0 +0xB172 0x7717 # 0 +0xB173 0x7718 # 0 +0xB174 0x771B # 0 +0xB175 0x771C # 0 +0xB176 0x771D # 0 +0xB177 0x771E # 0 +0xB178 0x7721 # 0 +0xB179 0x7723 # 0 +0xB17A 0x7724 # 0 +0xB17B 0x7725 # 0 +0xB17C 0x7727 # 0 +0xB17D 0x772A # 0 +0xB17E 0x772B # 0 +0xB180 0x772C # 0 +0xB181 0x772E # 0 +0xB182 0x7730 # 0 +0xB183 0x7731 # 0 +0xB184 0x7732 # 0 +0xB185 0x7733 # 0 +0xB186 0x7734 # 0 +0xB187 0x7739 # 0 +0xB188 0x773B # 0 +0xB189 0x773D # 0 +0xB18A 0x773E # 0 +0xB18B 0x773F # 0 +0xB18C 0x7742 # 0 +0xB18D 0x7744 # 0 +0xB18E 0x7745 # 0 +0xB18F 0x7746 # 0 +0xB190 0x7748 # 0 +0xB191 0x7749 # 0 +0xB192 0x774A # 0 +0xB193 0x774B # 0 +0xB194 0x774C # 0 +0xB195 0x774D # 0 +0xB196 0x774E # 0 +0xB197 0x774F # 0 +0xB198 0x7752 # 0 +0xB199 0x7753 # 0 +0xB19A 0x7754 # 0 +0xB19B 0x7755 # 0 +0xB19C 0x7756 # 0 +0xB19D 0x7757 # 0 +0xB19E 0x7758 # 0 +0xB19F 0x7759 # 0 +0xB1A0 0x775C # 0 +0xB1A1 0x8584 # 0 +0xB1A2 0x96F9 # 0 +0xB1A3 0x4FDD # 0 +0xB1A4 0x5821 # 0 +0xB1A5 0x9971 # 0 +0xB1A6 0x5B9D # 0 +0xB1A7 0x62B1 # 0 +0xB1A8 0x62A5 # 0 +0xB1A9 0x66B4 # 0 +0xB1AA 0x8C79 # 0 +0xB1AB 0x9C8D # 0 +0xB1AC 0x7206 # 0 +0xB1AD 0x676F # 0 +0xB1AE 0x7891 # 0 +0xB1AF 0x60B2 # 0 +0xB1B0 0x5351 # 0 +0xB1B1 0x5317 # 0 +0xB1B2 0x8F88 # 0 +0xB1B3 0x80CC # 0 +0xB1B4 0x8D1D # 0 +0xB1B5 0x94A1 # 0 +0xB1B6 0x500D # 0 +0xB1B7 0x72C8 # 0 +0xB1B8 0x5907 # 0 +0xB1B9 0x60EB # 0 +0xB1BA 0x7119 # 0 +0xB1BB 0x88AB # 0 +0xB1BC 0x5954 # 0 +0xB1BD 0x82EF # 0 +0xB1BE 0x672C # 0 +0xB1BF 0x7B28 # 0 +0xB1C0 0x5D29 # 0 +0xB1C1 0x7EF7 # 0 +0xB1C2 0x752D # 0 +0xB1C3 0x6CF5 # 0 +0xB1C4 0x8E66 # 0 +0xB1C5 0x8FF8 # 0 +0xB1C6 0x903C # 0 +0xB1C7 0x9F3B # 0 +0xB1C8 0x6BD4 # 0 +0xB1C9 0x9119 # 0 +0xB1CA 0x7B14 # 0 +0xB1CB 0x5F7C # 0 +0xB1CC 0x78A7 # 0 +0xB1CD 0x84D6 # 0 +0xB1CE 0x853D # 0 +0xB1CF 0x6BD5 # 0 +0xB1D0 0x6BD9 # 0 +0xB1D1 0x6BD6 # 0 +0xB1D2 0x5E01 # 0 +0xB1D3 0x5E87 # 0 +0xB1D4 0x75F9 # 0 +0xB1D5 0x95ED # 0 +0xB1D6 0x655D # 0 +0xB1D7 0x5F0A # 0 +0xB1D8 0x5FC5 # 0 +0xB1D9 0x8F9F # 0 +0xB1DA 0x58C1 # 0 +0xB1DB 0x81C2 # 0 +0xB1DC 0x907F # 0 +0xB1DD 0x965B # 0 +0xB1DE 0x97AD # 0 +0xB1DF 0x8FB9 # 0 +0xB1E0 0x7F16 # 0 +0xB1E1 0x8D2C # 0 +0xB1E2 0x6241 # 0 +0xB1E3 0x4FBF # 0 +0xB1E4 0x53D8 # 0 +0xB1E5 0x535E # 0 +0xB1E6 0x8FA8 # 0 +0xB1E7 0x8FA9 # 0 +0xB1E8 0x8FAB # 0 +0xB1E9 0x904D # 0 +0xB1EA 0x6807 # 0 +0xB1EB 0x5F6A # 0 +0xB1EC 0x8198 # 0 +0xB1ED 0x8868 # 0 +0xB1EE 0x9CD6 # 0 +0xB1EF 0x618B # 0 +0xB1F0 0x522B # 0 +0xB1F1 0x762A # 0 +0xB1F2 0x5F6C # 0 +0xB1F3 0x658C # 0 +0xB1F4 0x6FD2 # 0 +0xB1F5 0x6EE8 # 0 +0xB1F6 0x5BBE # 0 +0xB1F7 0x6448 # 0 +0xB1F8 0x5175 # 0 +0xB1F9 0x51B0 # 0 +0xB1FA 0x67C4 # 0 +0xB1FB 0x4E19 # 0 +0xB1FC 0x79C9 # 0 +0xB1FD 0x997C # 0 +0xB1FE 0x70B3 # 0 +0xB240 0x775D # 0 +0xB241 0x775E # 0 +0xB242 0x775F # 0 +0xB243 0x7760 # 0 +0xB244 0x7764 # 0 +0xB245 0x7767 # 0 +0xB246 0x7769 # 0 +0xB247 0x776A # 0 +0xB248 0x776D # 0 +0xB249 0x776E # 0 +0xB24A 0x776F # 0 +0xB24B 0x7770 # 0 +0xB24C 0x7771 # 0 +0xB24D 0x7772 # 0 +0xB24E 0x7773 # 0 +0xB24F 0x7774 # 0 +0xB250 0x7775 # 0 +0xB251 0x7776 # 0 +0xB252 0x7777 # 0 +0xB253 0x7778 # 0 +0xB254 0x777A # 0 +0xB255 0x777B # 0 +0xB256 0x777C # 0 +0xB257 0x7781 # 0 +0xB258 0x7782 # 0 +0xB259 0x7783 # 0 +0xB25A 0x7786 # 0 +0xB25B 0x7787 # 0 +0xB25C 0x7788 # 0 +0xB25D 0x7789 # 0 +0xB25E 0x778A # 0 +0xB25F 0x778B # 0 +0xB260 0x778F # 0 +0xB261 0x7790 # 0 +0xB262 0x7793 # 0 +0xB263 0x7794 # 0 +0xB264 0x7795 # 0 +0xB265 0x7796 # 0 +0xB266 0x7797 # 0 +0xB267 0x7798 # 0 +0xB268 0x7799 # 0 +0xB269 0x779A # 0 +0xB26A 0x779B # 0 +0xB26B 0x779C # 0 +0xB26C 0x779D # 0 +0xB26D 0x779E # 0 +0xB26E 0x77A1 # 0 +0xB26F 0x77A3 # 0 +0xB270 0x77A4 # 0 +0xB271 0x77A6 # 0 +0xB272 0x77A8 # 0 +0xB273 0x77AB # 0 +0xB274 0x77AD # 0 +0xB275 0x77AE # 0 +0xB276 0x77AF # 0 +0xB277 0x77B1 # 0 +0xB278 0x77B2 # 0 +0xB279 0x77B4 # 0 +0xB27A 0x77B6 # 0 +0xB27B 0x77B7 # 0 +0xB27C 0x77B8 # 0 +0xB27D 0x77B9 # 0 +0xB27E 0x77BA # 0 +0xB280 0x77BC # 0 +0xB281 0x77BE # 0 +0xB282 0x77C0 # 0 +0xB283 0x77C1 # 0 +0xB284 0x77C2 # 0 +0xB285 0x77C3 # 0 +0xB286 0x77C4 # 0 +0xB287 0x77C5 # 0 +0xB288 0x77C6 # 0 +0xB289 0x77C7 # 0 +0xB28A 0x77C8 # 0 +0xB28B 0x77C9 # 0 +0xB28C 0x77CA # 0 +0xB28D 0x77CB # 0 +0xB28E 0x77CC # 0 +0xB28F 0x77CE # 0 +0xB290 0x77CF # 0 +0xB291 0x77D0 # 0 +0xB292 0x77D1 # 0 +0xB293 0x77D2 # 0 +0xB294 0x77D3 # 0 +0xB295 0x77D4 # 0 +0xB296 0x77D5 # 0 +0xB297 0x77D6 # 0 +0xB298 0x77D8 # 0 +0xB299 0x77D9 # 0 +0xB29A 0x77DA # 0 +0xB29B 0x77DD # 0 +0xB29C 0x77DE # 0 +0xB29D 0x77DF # 0 +0xB29E 0x77E0 # 0 +0xB29F 0x77E1 # 0 +0xB2A0 0x77E4 # 0 +0xB2A1 0x75C5 # 0 +0xB2A2 0x5E76 # 0 +0xB2A3 0x73BB # 0 +0xB2A4 0x83E0 # 0 +0xB2A5 0x64AD # 0 +0xB2A6 0x62E8 # 0 +0xB2A7 0x94B5 # 0 +0xB2A8 0x6CE2 # 0 +0xB2A9 0x535A # 0 +0xB2AA 0x52C3 # 0 +0xB2AB 0x640F # 0 +0xB2AC 0x94C2 # 0 +0xB2AD 0x7B94 # 0 +0xB2AE 0x4F2F # 0 +0xB2AF 0x5E1B # 0 +0xB2B0 0x8236 # 0 +0xB2B1 0x8116 # 0 +0xB2B2 0x818A # 0 +0xB2B3 0x6E24 # 0 +0xB2B4 0x6CCA # 0 +0xB2B5 0x9A73 # 0 +0xB2B6 0x6355 # 0 +0xB2B7 0x535C # 0 +0xB2B8 0x54FA # 0 +0xB2B9 0x8865 # 0 +0xB2BA 0x57E0 # 0 +0xB2BB 0x4E0D # 0 +0xB2BC 0x5E03 # 0 +0xB2BD 0x6B65 # 0 +0xB2BE 0x7C3F # 0 +0xB2BF 0x90E8 # 0 +0xB2C0 0x6016 # 0 +0xB2C1 0x64E6 # 0 +0xB2C2 0x731C # 0 +0xB2C3 0x88C1 # 0 +0xB2C4 0x6750 # 0 +0xB2C5 0x624D # 0 +0xB2C6 0x8D22 # 0 +0xB2C7 0x776C # 0 +0xB2C8 0x8E29 # 0 +0xB2C9 0x91C7 # 0 +0xB2CA 0x5F69 # 0 +0xB2CB 0x83DC # 0 +0xB2CC 0x8521 # 0 +0xB2CD 0x9910 # 0 +0xB2CE 0x53C2 # 0 +0xB2CF 0x8695 # 0 +0xB2D0 0x6B8B # 0 +0xB2D1 0x60ED # 0 +0xB2D2 0x60E8 # 0 +0xB2D3 0x707F # 0 +0xB2D4 0x82CD # 0 +0xB2D5 0x8231 # 0 +0xB2D6 0x4ED3 # 0 +0xB2D7 0x6CA7 # 0 +0xB2D8 0x85CF # 0 +0xB2D9 0x64CD # 0 +0xB2DA 0x7CD9 # 0 +0xB2DB 0x69FD # 0 +0xB2DC 0x66F9 # 0 +0xB2DD 0x8349 # 0 +0xB2DE 0x5395 # 0 +0xB2DF 0x7B56 # 0 +0xB2E0 0x4FA7 # 0 +0xB2E1 0x518C # 0 +0xB2E2 0x6D4B # 0 +0xB2E3 0x5C42 # 0 +0xB2E4 0x8E6D # 0 +0xB2E5 0x63D2 # 0 +0xB2E6 0x53C9 # 0 +0xB2E7 0x832C # 0 +0xB2E8 0x8336 # 0 +0xB2E9 0x67E5 # 0 +0xB2EA 0x78B4 # 0 +0xB2EB 0x643D # 0 +0xB2EC 0x5BDF # 0 +0xB2ED 0x5C94 # 0 +0xB2EE 0x5DEE # 0 +0xB2EF 0x8BE7 # 0 +0xB2F0 0x62C6 # 0 +0xB2F1 0x67F4 # 0 +0xB2F2 0x8C7A # 0 +0xB2F3 0x6400 # 0 +0xB2F4 0x63BA # 0 +0xB2F5 0x8749 # 0 +0xB2F6 0x998B # 0 +0xB2F7 0x8C17 # 0 +0xB2F8 0x7F20 # 0 +0xB2F9 0x94F2 # 0 +0xB2FA 0x4EA7 # 0 +0xB2FB 0x9610 # 0 +0xB2FC 0x98A4 # 0 +0xB2FD 0x660C # 0 +0xB2FE 0x7316 # 0 +0xB340 0x77E6 # 0 +0xB341 0x77E8 # 0 +0xB342 0x77EA # 0 +0xB343 0x77EF # 0 +0xB344 0x77F0 # 0 +0xB345 0x77F1 # 0 +0xB346 0x77F2 # 0 +0xB347 0x77F4 # 0 +0xB348 0x77F5 # 0 +0xB349 0x77F7 # 0 +0xB34A 0x77F9 # 0 +0xB34B 0x77FA # 0 +0xB34C 0x77FB # 0 +0xB34D 0x77FC # 0 +0xB34E 0x7803 # 0 +0xB34F 0x7804 # 0 +0xB350 0x7805 # 0 +0xB351 0x7806 # 0 +0xB352 0x7807 # 0 +0xB353 0x7808 # 0 +0xB354 0x780A # 0 +0xB355 0x780B # 0 +0xB356 0x780E # 0 +0xB357 0x780F # 0 +0xB358 0x7810 # 0 +0xB359 0x7813 # 0 +0xB35A 0x7815 # 0 +0xB35B 0x7819 # 0 +0xB35C 0x781B # 0 +0xB35D 0x781E # 0 +0xB35E 0x7820 # 0 +0xB35F 0x7821 # 0 +0xB360 0x7822 # 0 +0xB361 0x7824 # 0 +0xB362 0x7828 # 0 +0xB363 0x782A # 0 +0xB364 0x782B # 0 +0xB365 0x782E # 0 +0xB366 0x782F # 0 +0xB367 0x7831 # 0 +0xB368 0x7832 # 0 +0xB369 0x7833 # 0 +0xB36A 0x7835 # 0 +0xB36B 0x7836 # 0 +0xB36C 0x783D # 0 +0xB36D 0x783F # 0 +0xB36E 0x7841 # 0 +0xB36F 0x7842 # 0 +0xB370 0x7843 # 0 +0xB371 0x7844 # 0 +0xB372 0x7846 # 0 +0xB373 0x7848 # 0 +0xB374 0x7849 # 0 +0xB375 0x784A # 0 +0xB376 0x784B # 0 +0xB377 0x784D # 0 +0xB378 0x784F # 0 +0xB379 0x7851 # 0 +0xB37A 0x7853 # 0 +0xB37B 0x7854 # 0 +0xB37C 0x7858 # 0 +0xB37D 0x7859 # 0 +0xB37E 0x785A # 0 +0xB380 0x785B # 0 +0xB381 0x785C # 0 +0xB382 0x785E # 0 +0xB383 0x785F # 0 +0xB384 0x7860 # 0 +0xB385 0x7861 # 0 +0xB386 0x7862 # 0 +0xB387 0x7863 # 0 +0xB388 0x7864 # 0 +0xB389 0x7865 # 0 +0xB38A 0x7866 # 0 +0xB38B 0x7867 # 0 +0xB38C 0x7868 # 0 +0xB38D 0x7869 # 0 +0xB38E 0x786F # 0 +0xB38F 0x7870 # 0 +0xB390 0x7871 # 0 +0xB391 0x7872 # 0 +0xB392 0x7873 # 0 +0xB393 0x7874 # 0 +0xB394 0x7875 # 0 +0xB395 0x7876 # 0 +0xB396 0x7878 # 0 +0xB397 0x7879 # 0 +0xB398 0x787A # 0 +0xB399 0x787B # 0 +0xB39A 0x787D # 0 +0xB39B 0x787E # 0 +0xB39C 0x787F # 0 +0xB39D 0x7880 # 0 +0xB39E 0x7881 # 0 +0xB39F 0x7882 # 0 +0xB3A0 0x7883 # 0 +0xB3A1 0x573A # 0 +0xB3A2 0x5C1D # 0 +0xB3A3 0x5E38 # 0 +0xB3A4 0x957F # 0 +0xB3A5 0x507F # 0 +0xB3A6 0x80A0 # 0 +0xB3A7 0x5382 # 0 +0xB3A8 0x655E # 0 +0xB3A9 0x7545 # 0 +0xB3AA 0x5531 # 0 +0xB3AB 0x5021 # 0 +0xB3AC 0x8D85 # 0 +0xB3AD 0x6284 # 0 +0xB3AE 0x949E # 0 +0xB3AF 0x671D # 0 +0xB3B0 0x5632 # 0 +0xB3B1 0x6F6E # 0 +0xB3B2 0x5DE2 # 0 +0xB3B3 0x5435 # 0 +0xB3B4 0x7092 # 0 +0xB3B5 0x8F66 # 0 +0xB3B6 0x626F # 0 +0xB3B7 0x64A4 # 0 +0xB3B8 0x63A3 # 0 +0xB3B9 0x5F7B # 0 +0xB3BA 0x6F88 # 0 +0xB3BB 0x90F4 # 0 +0xB3BC 0x81E3 # 0 +0xB3BD 0x8FB0 # 0 +0xB3BE 0x5C18 # 0 +0xB3BF 0x6668 # 0 +0xB3C0 0x5FF1 # 0 +0xB3C1 0x6C89 # 0 +0xB3C2 0x9648 # 0 +0xB3C3 0x8D81 # 0 +0xB3C4 0x886C # 0 +0xB3C5 0x6491 # 0 +0xB3C6 0x79F0 # 0 +0xB3C7 0x57CE # 0 +0xB3C8 0x6A59 # 0 +0xB3C9 0x6210 # 0 +0xB3CA 0x5448 # 0 +0xB3CB 0x4E58 # 0 +0xB3CC 0x7A0B # 0 +0xB3CD 0x60E9 # 0 +0xB3CE 0x6F84 # 0 +0xB3CF 0x8BDA # 0 +0xB3D0 0x627F # 0 +0xB3D1 0x901E # 0 +0xB3D2 0x9A8B # 0 +0xB3D3 0x79E4 # 0 +0xB3D4 0x5403 # 0 +0xB3D5 0x75F4 # 0 +0xB3D6 0x6301 # 0 +0xB3D7 0x5319 # 0 +0xB3D8 0x6C60 # 0 +0xB3D9 0x8FDF # 0 +0xB3DA 0x5F1B # 0 +0xB3DB 0x9A70 # 0 +0xB3DC 0x803B # 0 +0xB3DD 0x9F7F # 0 +0xB3DE 0x4F88 # 0 +0xB3DF 0x5C3A # 0 +0xB3E0 0x8D64 # 0 +0xB3E1 0x7FC5 # 0 +0xB3E2 0x65A5 # 0 +0xB3E3 0x70BD # 0 +0xB3E4 0x5145 # 0 +0xB3E5 0x51B2 # 0 +0xB3E6 0x866B # 0 +0xB3E7 0x5D07 # 0 +0xB3E8 0x5BA0 # 0 +0xB3E9 0x62BD # 0 +0xB3EA 0x916C # 0 +0xB3EB 0x7574 # 0 +0xB3EC 0x8E0C # 0 +0xB3ED 0x7A20 # 0 +0xB3EE 0x6101 # 0 +0xB3EF 0x7B79 # 0 +0xB3F0 0x4EC7 # 0 +0xB3F1 0x7EF8 # 0 +0xB3F2 0x7785 # 0 +0xB3F3 0x4E11 # 0 +0xB3F4 0x81ED # 0 +0xB3F5 0x521D # 0 +0xB3F6 0x51FA # 0 +0xB3F7 0x6A71 # 0 +0xB3F8 0x53A8 # 0 +0xB3F9 0x8E87 # 0 +0xB3FA 0x9504 # 0 +0xB3FB 0x96CF # 0 +0xB3FC 0x6EC1 # 0 +0xB3FD 0x9664 # 0 +0xB3FE 0x695A # 0 +0xB440 0x7884 # 0 +0xB441 0x7885 # 0 +0xB442 0x7886 # 0 +0xB443 0x7888 # 0 +0xB444 0x788A # 0 +0xB445 0x788B # 0 +0xB446 0x788F # 0 +0xB447 0x7890 # 0 +0xB448 0x7892 # 0 +0xB449 0x7894 # 0 +0xB44A 0x7895 # 0 +0xB44B 0x7896 # 0 +0xB44C 0x7899 # 0 +0xB44D 0x789D # 0 +0xB44E 0x789E # 0 +0xB44F 0x78A0 # 0 +0xB450 0x78A2 # 0 +0xB451 0x78A4 # 0 +0xB452 0x78A6 # 0 +0xB453 0x78A8 # 0 +0xB454 0x78A9 # 0 +0xB455 0x78AA # 0 +0xB456 0x78AB # 0 +0xB457 0x78AC # 0 +0xB458 0x78AD # 0 +0xB459 0x78AE # 0 +0xB45A 0x78AF # 0 +0xB45B 0x78B5 # 0 +0xB45C 0x78B6 # 0 +0xB45D 0x78B7 # 0 +0xB45E 0x78B8 # 0 +0xB45F 0x78BA # 0 +0xB460 0x78BB # 0 +0xB461 0x78BC # 0 +0xB462 0x78BD # 0 +0xB463 0x78BF # 0 +0xB464 0x78C0 # 0 +0xB465 0x78C2 # 0 +0xB466 0x78C3 # 0 +0xB467 0x78C4 # 0 +0xB468 0x78C6 # 0 +0xB469 0x78C7 # 0 +0xB46A 0x78C8 # 0 +0xB46B 0x78CC # 0 +0xB46C 0x78CD # 0 +0xB46D 0x78CE # 0 +0xB46E 0x78CF # 0 +0xB46F 0x78D1 # 0 +0xB470 0x78D2 # 0 +0xB471 0x78D3 # 0 +0xB472 0x78D6 # 0 +0xB473 0x78D7 # 0 +0xB474 0x78D8 # 0 +0xB475 0x78DA # 0 +0xB476 0x78DB # 0 +0xB477 0x78DC # 0 +0xB478 0x78DD # 0 +0xB479 0x78DE # 0 +0xB47A 0x78DF # 0 +0xB47B 0x78E0 # 0 +0xB47C 0x78E1 # 0 +0xB47D 0x78E2 # 0 +0xB47E 0x78E3 # 0 +0xB480 0x78E4 # 0 +0xB481 0x78E5 # 0 +0xB482 0x78E6 # 0 +0xB483 0x78E7 # 0 +0xB484 0x78E9 # 0 +0xB485 0x78EA # 0 +0xB486 0x78EB # 0 +0xB487 0x78ED # 0 +0xB488 0x78EE # 0 +0xB489 0x78EF # 0 +0xB48A 0x78F0 # 0 +0xB48B 0x78F1 # 0 +0xB48C 0x78F3 # 0 +0xB48D 0x78F5 # 0 +0xB48E 0x78F6 # 0 +0xB48F 0x78F8 # 0 +0xB490 0x78F9 # 0 +0xB491 0x78FB # 0 +0xB492 0x78FC # 0 +0xB493 0x78FD # 0 +0xB494 0x78FE # 0 +0xB495 0x78FF # 0 +0xB496 0x7900 # 0 +0xB497 0x7902 # 0 +0xB498 0x7903 # 0 +0xB499 0x7904 # 0 +0xB49A 0x7906 # 0 +0xB49B 0x7907 # 0 +0xB49C 0x7908 # 0 +0xB49D 0x7909 # 0 +0xB49E 0x790A # 0 +0xB49F 0x790B # 0 +0xB4A0 0x790C # 0 +0xB4A1 0x7840 # 0 +0xB4A2 0x50A8 # 0 +0xB4A3 0x77D7 # 0 +0xB4A4 0x6410 # 0 +0xB4A5 0x89E6 # 0 +0xB4A6 0x5904 # 0 +0xB4A7 0x63E3 # 0 +0xB4A8 0x5DDD # 0 +0xB4A9 0x7A7F # 0 +0xB4AA 0x693D # 0 +0xB4AB 0x4F20 # 0 +0xB4AC 0x8239 # 0 +0xB4AD 0x5598 # 0 +0xB4AE 0x4E32 # 0 +0xB4AF 0x75AE # 0 +0xB4B0 0x7A97 # 0 +0xB4B1 0x5E62 # 0 +0xB4B2 0x5E8A # 0 +0xB4B3 0x95EF # 0 +0xB4B4 0x521B # 0 +0xB4B5 0x5439 # 0 +0xB4B6 0x708A # 0 +0xB4B7 0x6376 # 0 +0xB4B8 0x9524 # 0 +0xB4B9 0x5782 # 0 +0xB4BA 0x6625 # 0 +0xB4BB 0x693F # 0 +0xB4BC 0x9187 # 0 +0xB4BD 0x5507 # 0 +0xB4BE 0x6DF3 # 0 +0xB4BF 0x7EAF # 0 +0xB4C0 0x8822 # 0 +0xB4C1 0x6233 # 0 +0xB4C2 0x7EF0 # 0 +0xB4C3 0x75B5 # 0 +0xB4C4 0x8328 # 0 +0xB4C5 0x78C1 # 0 +0xB4C6 0x96CC # 0 +0xB4C7 0x8F9E # 0 +0xB4C8 0x6148 # 0 +0xB4C9 0x74F7 # 0 +0xB4CA 0x8BCD # 0 +0xB4CB 0x6B64 # 0 +0xB4CC 0x523A # 0 +0xB4CD 0x8D50 # 0 +0xB4CE 0x6B21 # 0 +0xB4CF 0x806A # 0 +0xB4D0 0x8471 # 0 +0xB4D1 0x56F1 # 0 +0xB4D2 0x5306 # 0 +0xB4D3 0x4ECE # 0 +0xB4D4 0x4E1B # 0 +0xB4D5 0x51D1 # 0 +0xB4D6 0x7C97 # 0 +0xB4D7 0x918B # 0 +0xB4D8 0x7C07 # 0 +0xB4D9 0x4FC3 # 0 +0xB4DA 0x8E7F # 0 +0xB4DB 0x7BE1 # 0 +0xB4DC 0x7A9C # 0 +0xB4DD 0x6467 # 0 +0xB4DE 0x5D14 # 0 +0xB4DF 0x50AC # 0 +0xB4E0 0x8106 # 0 +0xB4E1 0x7601 # 0 +0xB4E2 0x7CB9 # 0 +0xB4E3 0x6DEC # 0 +0xB4E4 0x7FE0 # 0 +0xB4E5 0x6751 # 0 +0xB4E6 0x5B58 # 0 +0xB4E7 0x5BF8 # 0 +0xB4E8 0x78CB # 0 +0xB4E9 0x64AE # 0 +0xB4EA 0x6413 # 0 +0xB4EB 0x63AA # 0 +0xB4EC 0x632B # 0 +0xB4ED 0x9519 # 0 +0xB4EE 0x642D # 0 +0xB4EF 0x8FBE # 0 +0xB4F0 0x7B54 # 0 +0xB4F1 0x7629 # 0 +0xB4F2 0x6253 # 0 +0xB4F3 0x5927 # 0 +0xB4F4 0x5446 # 0 +0xB4F5 0x6B79 # 0 +0xB4F6 0x50A3 # 0 +0xB4F7 0x6234 # 0 +0xB4F8 0x5E26 # 0 +0xB4F9 0x6B86 # 0 +0xB4FA 0x4EE3 # 0 +0xB4FB 0x8D37 # 0 +0xB4FC 0x888B # 0 +0xB4FD 0x5F85 # 0 +0xB4FE 0x902E # 0 +0xB540 0x790D # 0 +0xB541 0x790E # 0 +0xB542 0x790F # 0 +0xB543 0x7910 # 0 +0xB544 0x7911 # 0 +0xB545 0x7912 # 0 +0xB546 0x7914 # 0 +0xB547 0x7915 # 0 +0xB548 0x7916 # 0 +0xB549 0x7917 # 0 +0xB54A 0x7918 # 0 +0xB54B 0x7919 # 0 +0xB54C 0x791A # 0 +0xB54D 0x791B # 0 +0xB54E 0x791C # 0 +0xB54F 0x791D # 0 +0xB550 0x791F # 0 +0xB551 0x7920 # 0 +0xB552 0x7921 # 0 +0xB553 0x7922 # 0 +0xB554 0x7923 # 0 +0xB555 0x7925 # 0 +0xB556 0x7926 # 0 +0xB557 0x7927 # 0 +0xB558 0x7928 # 0 +0xB559 0x7929 # 0 +0xB55A 0x792A # 0 +0xB55B 0x792B # 0 +0xB55C 0x792C # 0 +0xB55D 0x792D # 0 +0xB55E 0x792E # 0 +0xB55F 0x792F # 0 +0xB560 0x7930 # 0 +0xB561 0x7931 # 0 +0xB562 0x7932 # 0 +0xB563 0x7933 # 0 +0xB564 0x7935 # 0 +0xB565 0x7936 # 0 +0xB566 0x7937 # 0 +0xB567 0x7938 # 0 +0xB568 0x7939 # 0 +0xB569 0x793D # 0 +0xB56A 0x793F # 0 +0xB56B 0x7942 # 0 +0xB56C 0x7943 # 0 +0xB56D 0x7944 # 0 +0xB56E 0x7945 # 0 +0xB56F 0x7947 # 0 +0xB570 0x794A # 0 +0xB571 0x794B # 0 +0xB572 0x794C # 0 +0xB573 0x794D # 0 +0xB574 0x794E # 0 +0xB575 0x794F # 0 +0xB576 0x7950 # 0 +0xB577 0x7951 # 0 +0xB578 0x7952 # 0 +0xB579 0x7954 # 0 +0xB57A 0x7955 # 0 +0xB57B 0x7958 # 0 +0xB57C 0x7959 # 0 +0xB57D 0x7961 # 0 +0xB57E 0x7963 # 0 +0xB580 0x7964 # 0 +0xB581 0x7966 # 0 +0xB582 0x7969 # 0 +0xB583 0x796A # 0 +0xB584 0x796B # 0 +0xB585 0x796C # 0 +0xB586 0x796E # 0 +0xB587 0x7970 # 0 +0xB588 0x7971 # 0 +0xB589 0x7972 # 0 +0xB58A 0x7973 # 0 +0xB58B 0x7974 # 0 +0xB58C 0x7975 # 0 +0xB58D 0x7976 # 0 +0xB58E 0x7979 # 0 +0xB58F 0x797B # 0 +0xB590 0x797C # 0 +0xB591 0x797D # 0 +0xB592 0x797E # 0 +0xB593 0x797F # 0 +0xB594 0x7982 # 0 +0xB595 0x7983 # 0 +0xB596 0x7986 # 0 +0xB597 0x7987 # 0 +0xB598 0x7988 # 0 +0xB599 0x7989 # 0 +0xB59A 0x798B # 0 +0xB59B 0x798C # 0 +0xB59C 0x798D # 0 +0xB59D 0x798E # 0 +0xB59E 0x7990 # 0 +0xB59F 0x7991 # 0 +0xB5A0 0x7992 # 0 +0xB5A1 0x6020 # 0 +0xB5A2 0x803D # 0 +0xB5A3 0x62C5 # 0 +0xB5A4 0x4E39 # 0 +0xB5A5 0x5355 # 0 +0xB5A6 0x90F8 # 0 +0xB5A7 0x63B8 # 0 +0xB5A8 0x80C6 # 0 +0xB5A9 0x65E6 # 0 +0xB5AA 0x6C2E # 0 +0xB5AB 0x4F46 # 0 +0xB5AC 0x60EE # 0 +0xB5AD 0x6DE1 # 0 +0xB5AE 0x8BDE # 0 +0xB5AF 0x5F39 # 0 +0xB5B0 0x86CB # 0 +0xB5B1 0x5F53 # 0 +0xB5B2 0x6321 # 0 +0xB5B3 0x515A # 0 +0xB5B4 0x8361 # 0 +0xB5B5 0x6863 # 0 +0xB5B6 0x5200 # 0 +0xB5B7 0x6363 # 0 +0xB5B8 0x8E48 # 0 +0xB5B9 0x5012 # 0 +0xB5BA 0x5C9B # 0 +0xB5BB 0x7977 # 0 +0xB5BC 0x5BFC # 0 +0xB5BD 0x5230 # 0 +0xB5BE 0x7A3B # 0 +0xB5BF 0x60BC # 0 +0xB5C0 0x9053 # 0 +0xB5C1 0x76D7 # 0 +0xB5C2 0x5FB7 # 0 +0xB5C3 0x5F97 # 0 +0xB5C4 0x7684 # 0 +0xB5C5 0x8E6C # 0 +0xB5C6 0x706F # 0 +0xB5C7 0x767B # 0 +0xB5C8 0x7B49 # 0 +0xB5C9 0x77AA # 0 +0xB5CA 0x51F3 # 0 +0xB5CB 0x9093 # 0 +0xB5CC 0x5824 # 0 +0xB5CD 0x4F4E # 0 +0xB5CE 0x6EF4 # 0 +0xB5CF 0x8FEA # 0 +0xB5D0 0x654C # 0 +0xB5D1 0x7B1B # 0 +0xB5D2 0x72C4 # 0 +0xB5D3 0x6DA4 # 0 +0xB5D4 0x7FDF # 0 +0xB5D5 0x5AE1 # 0 +0xB5D6 0x62B5 # 0 +0xB5D7 0x5E95 # 0 +0xB5D8 0x5730 # 0 +0xB5D9 0x8482 # 0 +0xB5DA 0x7B2C # 0 +0xB5DB 0x5E1D # 0 +0xB5DC 0x5F1F # 0 +0xB5DD 0x9012 # 0 +0xB5DE 0x7F14 # 0 +0xB5DF 0x98A0 # 0 +0xB5E0 0x6382 # 0 +0xB5E1 0x6EC7 # 0 +0xB5E2 0x7898 # 0 +0xB5E3 0x70B9 # 0 +0xB5E4 0x5178 # 0 +0xB5E5 0x975B # 0 +0xB5E6 0x57AB # 0 +0xB5E7 0x7535 # 0 +0xB5E8 0x4F43 # 0 +0xB5E9 0x7538 # 0 +0xB5EA 0x5E97 # 0 +0xB5EB 0x60E6 # 0 +0xB5EC 0x5960 # 0 +0xB5ED 0x6DC0 # 0 +0xB5EE 0x6BBF # 0 +0xB5EF 0x7889 # 0 +0xB5F0 0x53FC # 0 +0xB5F1 0x96D5 # 0 +0xB5F2 0x51CB # 0 +0xB5F3 0x5201 # 0 +0xB5F4 0x6389 # 0 +0xB5F5 0x540A # 0 +0xB5F6 0x9493 # 0 +0xB5F7 0x8C03 # 0 +0xB5F8 0x8DCC # 0 +0xB5F9 0x7239 # 0 +0xB5FA 0x789F # 0 +0xB5FB 0x8776 # 0 +0xB5FC 0x8FED # 0 +0xB5FD 0x8C0D # 0 +0xB5FE 0x53E0 # 0 +0xB640 0x7993 # 0 +0xB641 0x7994 # 0 +0xB642 0x7995 # 0 +0xB643 0x7996 # 0 +0xB644 0x7997 # 0 +0xB645 0x7998 # 0 +0xB646 0x7999 # 0 +0xB647 0x799B # 0 +0xB648 0x799C # 0 +0xB649 0x799D # 0 +0xB64A 0x799E # 0 +0xB64B 0x799F # 0 +0xB64C 0x79A0 # 0 +0xB64D 0x79A1 # 0 +0xB64E 0x79A2 # 0 +0xB64F 0x79A3 # 0 +0xB650 0x79A4 # 0 +0xB651 0x79A5 # 0 +0xB652 0x79A6 # 0 +0xB653 0x79A8 # 0 +0xB654 0x79A9 # 0 +0xB655 0x79AA # 0 +0xB656 0x79AB # 0 +0xB657 0x79AC # 0 +0xB658 0x79AD # 0 +0xB659 0x79AE # 0 +0xB65A 0x79AF # 0 +0xB65B 0x79B0 # 0 +0xB65C 0x79B1 # 0 +0xB65D 0x79B2 # 0 +0xB65E 0x79B4 # 0 +0xB65F 0x79B5 # 0 +0xB660 0x79B6 # 0 +0xB661 0x79B7 # 0 +0xB662 0x79B8 # 0 +0xB663 0x79BC # 0 +0xB664 0x79BF # 0 +0xB665 0x79C2 # 0 +0xB666 0x79C4 # 0 +0xB667 0x79C5 # 0 +0xB668 0x79C7 # 0 +0xB669 0x79C8 # 0 +0xB66A 0x79CA # 0 +0xB66B 0x79CC # 0 +0xB66C 0x79CE # 0 +0xB66D 0x79CF # 0 +0xB66E 0x79D0 # 0 +0xB66F 0x79D3 # 0 +0xB670 0x79D4 # 0 +0xB671 0x79D6 # 0 +0xB672 0x79D7 # 0 +0xB673 0x79D9 # 0 +0xB674 0x79DA # 0 +0xB675 0x79DB # 0 +0xB676 0x79DC # 0 +0xB677 0x79DD # 0 +0xB678 0x79DE # 0 +0xB679 0x79E0 # 0 +0xB67A 0x79E1 # 0 +0xB67B 0x79E2 # 0 +0xB67C 0x79E5 # 0 +0xB67D 0x79E8 # 0 +0xB67E 0x79EA # 0 +0xB680 0x79EC # 0 +0xB681 0x79EE # 0 +0xB682 0x79F1 # 0 +0xB683 0x79F2 # 0 +0xB684 0x79F3 # 0 +0xB685 0x79F4 # 0 +0xB686 0x79F5 # 0 +0xB687 0x79F6 # 0 +0xB688 0x79F7 # 0 +0xB689 0x79F9 # 0 +0xB68A 0x79FA # 0 +0xB68B 0x79FC # 0 +0xB68C 0x79FE # 0 +0xB68D 0x79FF # 0 +0xB68E 0x7A01 # 0 +0xB68F 0x7A04 # 0 +0xB690 0x7A05 # 0 +0xB691 0x7A07 # 0 +0xB692 0x7A08 # 0 +0xB693 0x7A09 # 0 +0xB694 0x7A0A # 0 +0xB695 0x7A0C # 0 +0xB696 0x7A0F # 0 +0xB697 0x7A10 # 0 +0xB698 0x7A11 # 0 +0xB699 0x7A12 # 0 +0xB69A 0x7A13 # 0 +0xB69B 0x7A15 # 0 +0xB69C 0x7A16 # 0 +0xB69D 0x7A18 # 0 +0xB69E 0x7A19 # 0 +0xB69F 0x7A1B # 0 +0xB6A0 0x7A1C # 0 +0xB6A1 0x4E01 # 0 +0xB6A2 0x76EF # 0 +0xB6A3 0x53EE # 0 +0xB6A4 0x9489 # 0 +0xB6A5 0x9876 # 0 +0xB6A6 0x9F0E # 0 +0xB6A7 0x952D # 0 +0xB6A8 0x5B9A # 0 +0xB6A9 0x8BA2 # 0 +0xB6AA 0x4E22 # 0 +0xB6AB 0x4E1C # 0 +0xB6AC 0x51AC # 0 +0xB6AD 0x8463 # 0 +0xB6AE 0x61C2 # 0 +0xB6AF 0x52A8 # 0 +0xB6B0 0x680B # 0 +0xB6B1 0x4F97 # 0 +0xB6B2 0x606B # 0 +0xB6B3 0x51BB # 0 +0xB6B4 0x6D1E # 0 +0xB6B5 0x515C # 0 +0xB6B6 0x6296 # 0 +0xB6B7 0x6597 # 0 +0xB6B8 0x9661 # 0 +0xB6B9 0x8C46 # 0 +0xB6BA 0x9017 # 0 +0xB6BB 0x75D8 # 0 +0xB6BC 0x90FD # 0 +0xB6BD 0x7763 # 0 +0xB6BE 0x6BD2 # 0 +0xB6BF 0x728A # 0 +0xB6C0 0x72EC # 0 +0xB6C1 0x8BFB # 0 +0xB6C2 0x5835 # 0 +0xB6C3 0x7779 # 0 +0xB6C4 0x8D4C # 0 +0xB6C5 0x675C # 0 +0xB6C6 0x9540 # 0 +0xB6C7 0x809A # 0 +0xB6C8 0x5EA6 # 0 +0xB6C9 0x6E21 # 0 +0xB6CA 0x5992 # 0 +0xB6CB 0x7AEF # 0 +0xB6CC 0x77ED # 0 +0xB6CD 0x953B # 0 +0xB6CE 0x6BB5 # 0 +0xB6CF 0x65AD # 0 +0xB6D0 0x7F0E # 0 +0xB6D1 0x5806 # 0 +0xB6D2 0x5151 # 0 +0xB6D3 0x961F # 0 +0xB6D4 0x5BF9 # 0 +0xB6D5 0x58A9 # 0 +0xB6D6 0x5428 # 0 +0xB6D7 0x8E72 # 0 +0xB6D8 0x6566 # 0 +0xB6D9 0x987F # 0 +0xB6DA 0x56E4 # 0 +0xB6DB 0x949D # 0 +0xB6DC 0x76FE # 0 +0xB6DD 0x9041 # 0 +0xB6DE 0x6387 # 0 +0xB6DF 0x54C6 # 0 +0xB6E0 0x591A # 0 +0xB6E1 0x593A # 0 +0xB6E2 0x579B # 0 +0xB6E3 0x8EB2 # 0 +0xB6E4 0x6735 # 0 +0xB6E5 0x8DFA # 0 +0xB6E6 0x8235 # 0 +0xB6E7 0x5241 # 0 +0xB6E8 0x60F0 # 0 +0xB6E9 0x5815 # 0 +0xB6EA 0x86FE # 0 +0xB6EB 0x5CE8 # 0 +0xB6EC 0x9E45 # 0 +0xB6ED 0x4FC4 # 0 +0xB6EE 0x989D # 0 +0xB6EF 0x8BB9 # 0 +0xB6F0 0x5A25 # 0 +0xB6F1 0x6076 # 0 +0xB6F2 0x5384 # 0 +0xB6F3 0x627C # 0 +0xB6F4 0x904F # 0 +0xB6F5 0x9102 # 0 +0xB6F6 0x997F # 0 +0xB6F7 0x6069 # 0 +0xB6F8 0x800C # 0 +0xB6F9 0x513F # 0 +0xB6FA 0x8033 # 0 +0xB6FB 0x5C14 # 0 +0xB6FC 0x9975 # 0 +0xB6FD 0x6D31 # 0 +0xB6FE 0x4E8C # 0 +0xB740 0x7A1D # 0 +0xB741 0x7A1F # 0 +0xB742 0x7A21 # 0 +0xB743 0x7A22 # 0 +0xB744 0x7A24 # 0 +0xB745 0x7A25 # 0 +0xB746 0x7A26 # 0 +0xB747 0x7A27 # 0 +0xB748 0x7A28 # 0 +0xB749 0x7A29 # 0 +0xB74A 0x7A2A # 0 +0xB74B 0x7A2B # 0 +0xB74C 0x7A2C # 0 +0xB74D 0x7A2D # 0 +0xB74E 0x7A2E # 0 +0xB74F 0x7A2F # 0 +0xB750 0x7A30 # 0 +0xB751 0x7A31 # 0 +0xB752 0x7A32 # 0 +0xB753 0x7A34 # 0 +0xB754 0x7A35 # 0 +0xB755 0x7A36 # 0 +0xB756 0x7A38 # 0 +0xB757 0x7A3A # 0 +0xB758 0x7A3E # 0 +0xB759 0x7A40 # 0 +0xB75A 0x7A41 # 0 +0xB75B 0x7A42 # 0 +0xB75C 0x7A43 # 0 +0xB75D 0x7A44 # 0 +0xB75E 0x7A45 # 0 +0xB75F 0x7A47 # 0 +0xB760 0x7A48 # 0 +0xB761 0x7A49 # 0 +0xB762 0x7A4A # 0 +0xB763 0x7A4B # 0 +0xB764 0x7A4C # 0 +0xB765 0x7A4D # 0 +0xB766 0x7A4E # 0 +0xB767 0x7A4F # 0 +0xB768 0x7A50 # 0 +0xB769 0x7A52 # 0 +0xB76A 0x7A53 # 0 +0xB76B 0x7A54 # 0 +0xB76C 0x7A55 # 0 +0xB76D 0x7A56 # 0 +0xB76E 0x7A58 # 0 +0xB76F 0x7A59 # 0 +0xB770 0x7A5A # 0 +0xB771 0x7A5B # 0 +0xB772 0x7A5C # 0 +0xB773 0x7A5D # 0 +0xB774 0x7A5E # 0 +0xB775 0x7A5F # 0 +0xB776 0x7A60 # 0 +0xB777 0x7A61 # 0 +0xB778 0x7A62 # 0 +0xB779 0x7A63 # 0 +0xB77A 0x7A64 # 0 +0xB77B 0x7A65 # 0 +0xB77C 0x7A66 # 0 +0xB77D 0x7A67 # 0 +0xB77E 0x7A68 # 0 +0xB780 0x7A69 # 0 +0xB781 0x7A6A # 0 +0xB782 0x7A6B # 0 +0xB783 0x7A6C # 0 +0xB784 0x7A6D # 0 +0xB785 0x7A6E # 0 +0xB786 0x7A6F # 0 +0xB787 0x7A71 # 0 +0xB788 0x7A72 # 0 +0xB789 0x7A73 # 0 +0xB78A 0x7A75 # 0 +0xB78B 0x7A7B # 0 +0xB78C 0x7A7C # 0 +0xB78D 0x7A7D # 0 +0xB78E 0x7A7E # 0 +0xB78F 0x7A82 # 0 +0xB790 0x7A85 # 0 +0xB791 0x7A87 # 0 +0xB792 0x7A89 # 0 +0xB793 0x7A8A # 0 +0xB794 0x7A8B # 0 +0xB795 0x7A8C # 0 +0xB796 0x7A8E # 0 +0xB797 0x7A8F # 0 +0xB798 0x7A90 # 0 +0xB799 0x7A93 # 0 +0xB79A 0x7A94 # 0 +0xB79B 0x7A99 # 0 +0xB79C 0x7A9A # 0 +0xB79D 0x7A9B # 0 +0xB79E 0x7A9E # 0 +0xB79F 0x7AA1 # 0 +0xB7A0 0x7AA2 # 0 +0xB7A1 0x8D30 # 0 +0xB7A2 0x53D1 # 0 +0xB7A3 0x7F5A # 0 +0xB7A4 0x7B4F # 0 +0xB7A5 0x4F10 # 0 +0xB7A6 0x4E4F # 0 +0xB7A7 0x9600 # 0 +0xB7A8 0x6CD5 # 0 +0xB7A9 0x73D0 # 0 +0xB7AA 0x85E9 # 0 +0xB7AB 0x5E06 # 0 +0xB7AC 0x756A # 0 +0xB7AD 0x7FFB # 0 +0xB7AE 0x6A0A # 0 +0xB7AF 0x77FE # 0 +0xB7B0 0x9492 # 0 +0xB7B1 0x7E41 # 0 +0xB7B2 0x51E1 # 0 +0xB7B3 0x70E6 # 0 +0xB7B4 0x53CD # 0 +0xB7B5 0x8FD4 # 0 +0xB7B6 0x8303 # 0 +0xB7B7 0x8D29 # 0 +0xB7B8 0x72AF # 0 +0xB7B9 0x996D # 0 +0xB7BA 0x6CDB # 0 +0xB7BB 0x574A # 0 +0xB7BC 0x82B3 # 0 +0xB7BD 0x65B9 # 0 +0xB7BE 0x80AA # 0 +0xB7BF 0x623F # 0 +0xB7C0 0x9632 # 0 +0xB7C1 0x59A8 # 0 +0xB7C2 0x4EFF # 0 +0xB7C3 0x8BBF # 0 +0xB7C4 0x7EBA # 0 +0xB7C5 0x653E # 0 +0xB7C6 0x83F2 # 0 +0xB7C7 0x975E # 0 +0xB7C8 0x5561 # 0 +0xB7C9 0x98DE # 0 +0xB7CA 0x80A5 # 0 +0xB7CB 0x532A # 0 +0xB7CC 0x8BFD # 0 +0xB7CD 0x5420 # 0 +0xB7CE 0x80BA # 0 +0xB7CF 0x5E9F # 0 +0xB7D0 0x6CB8 # 0 +0xB7D1 0x8D39 # 0 +0xB7D2 0x82AC # 0 +0xB7D3 0x915A # 0 +0xB7D4 0x5429 # 0 +0xB7D5 0x6C1B # 0 +0xB7D6 0x5206 # 0 +0xB7D7 0x7EB7 # 0 +0xB7D8 0x575F # 0 +0xB7D9 0x711A # 0 +0xB7DA 0x6C7E # 0 +0xB7DB 0x7C89 # 0 +0xB7DC 0x594B # 0 +0xB7DD 0x4EFD # 0 +0xB7DE 0x5FFF # 0 +0xB7DF 0x6124 # 0 +0xB7E0 0x7CAA # 0 +0xB7E1 0x4E30 # 0 +0xB7E2 0x5C01 # 0 +0xB7E3 0x67AB # 0 +0xB7E4 0x8702 # 0 +0xB7E5 0x5CF0 # 0 +0xB7E6 0x950B # 0 +0xB7E7 0x98CE # 0 +0xB7E8 0x75AF # 0 +0xB7E9 0x70FD # 0 +0xB7EA 0x9022 # 0 +0xB7EB 0x51AF # 0 +0xB7EC 0x7F1D # 0 +0xB7ED 0x8BBD # 0 +0xB7EE 0x5949 # 0 +0xB7EF 0x51E4 # 0 +0xB7F0 0x4F5B # 0 +0xB7F1 0x5426 # 0 +0xB7F2 0x592B # 0 +0xB7F3 0x6577 # 0 +0xB7F4 0x80A4 # 0 +0xB7F5 0x5B75 # 0 +0xB7F6 0x6276 # 0 +0xB7F7 0x62C2 # 0 +0xB7F8 0x8F90 # 0 +0xB7F9 0x5E45 # 0 +0xB7FA 0x6C1F # 0 +0xB7FB 0x7B26 # 0 +0xB7FC 0x4F0F # 0 +0xB7FD 0x4FD8 # 0 +0xB7FE 0x670D # 0 +0xB840 0x7AA3 # 0 +0xB841 0x7AA4 # 0 +0xB842 0x7AA7 # 0 +0xB843 0x7AA9 # 0 +0xB844 0x7AAA # 0 +0xB845 0x7AAB # 0 +0xB846 0x7AAE # 0 +0xB847 0x7AAF # 0 +0xB848 0x7AB0 # 0 +0xB849 0x7AB1 # 0 +0xB84A 0x7AB2 # 0 +0xB84B 0x7AB4 # 0 +0xB84C 0x7AB5 # 0 +0xB84D 0x7AB6 # 0 +0xB84E 0x7AB7 # 0 +0xB84F 0x7AB8 # 0 +0xB850 0x7AB9 # 0 +0xB851 0x7ABA # 0 +0xB852 0x7ABB # 0 +0xB853 0x7ABC # 0 +0xB854 0x7ABD # 0 +0xB855 0x7ABE # 0 +0xB856 0x7AC0 # 0 +0xB857 0x7AC1 # 0 +0xB858 0x7AC2 # 0 +0xB859 0x7AC3 # 0 +0xB85A 0x7AC4 # 0 +0xB85B 0x7AC5 # 0 +0xB85C 0x7AC6 # 0 +0xB85D 0x7AC7 # 0 +0xB85E 0x7AC8 # 0 +0xB85F 0x7AC9 # 0 +0xB860 0x7ACA # 0 +0xB861 0x7ACC # 0 +0xB862 0x7ACD # 0 +0xB863 0x7ACE # 0 +0xB864 0x7ACF # 0 +0xB865 0x7AD0 # 0 +0xB866 0x7AD1 # 0 +0xB867 0x7AD2 # 0 +0xB868 0x7AD3 # 0 +0xB869 0x7AD4 # 0 +0xB86A 0x7AD5 # 0 +0xB86B 0x7AD7 # 0 +0xB86C 0x7AD8 # 0 +0xB86D 0x7ADA # 0 +0xB86E 0x7ADB # 0 +0xB86F 0x7ADC # 0 +0xB870 0x7ADD # 0 +0xB871 0x7AE1 # 0 +0xB872 0x7AE2 # 0 +0xB873 0x7AE4 # 0 +0xB874 0x7AE7 # 0 +0xB875 0x7AE8 # 0 +0xB876 0x7AE9 # 0 +0xB877 0x7AEA # 0 +0xB878 0x7AEB # 0 +0xB879 0x7AEC # 0 +0xB87A 0x7AEE # 0 +0xB87B 0x7AF0 # 0 +0xB87C 0x7AF1 # 0 +0xB87D 0x7AF2 # 0 +0xB87E 0x7AF3 # 0 +0xB880 0x7AF4 # 0 +0xB881 0x7AF5 # 0 +0xB882 0x7AF6 # 0 +0xB883 0x7AF7 # 0 +0xB884 0x7AF8 # 0 +0xB885 0x7AFB # 0 +0xB886 0x7AFC # 0 +0xB887 0x7AFE # 0 +0xB888 0x7B00 # 0 +0xB889 0x7B01 # 0 +0xB88A 0x7B02 # 0 +0xB88B 0x7B05 # 0 +0xB88C 0x7B07 # 0 +0xB88D 0x7B09 # 0 +0xB88E 0x7B0C # 0 +0xB88F 0x7B0D # 0 +0xB890 0x7B0E # 0 +0xB891 0x7B10 # 0 +0xB892 0x7B12 # 0 +0xB893 0x7B13 # 0 +0xB894 0x7B16 # 0 +0xB895 0x7B17 # 0 +0xB896 0x7B18 # 0 +0xB897 0x7B1A # 0 +0xB898 0x7B1C # 0 +0xB899 0x7B1D # 0 +0xB89A 0x7B1F # 0 +0xB89B 0x7B21 # 0 +0xB89C 0x7B22 # 0 +0xB89D 0x7B23 # 0 +0xB89E 0x7B27 # 0 +0xB89F 0x7B29 # 0 +0xB8A0 0x7B2D # 0 +0xB8A1 0x6D6E # 0 +0xB8A2 0x6DAA # 0 +0xB8A3 0x798F # 0 +0xB8A4 0x88B1 # 0 +0xB8A5 0x5F17 # 0 +0xB8A6 0x752B # 0 +0xB8A7 0x629A # 0 +0xB8A8 0x8F85 # 0 +0xB8A9 0x4FEF # 0 +0xB8AA 0x91DC # 0 +0xB8AB 0x65A7 # 0 +0xB8AC 0x812F # 0 +0xB8AD 0x8151 # 0 +0xB8AE 0x5E9C # 0 +0xB8AF 0x8150 # 0 +0xB8B0 0x8D74 # 0 +0xB8B1 0x526F # 0 +0xB8B2 0x8986 # 0 +0xB8B3 0x8D4B # 0 +0xB8B4 0x590D # 0 +0xB8B5 0x5085 # 0 +0xB8B6 0x4ED8 # 0 +0xB8B7 0x961C # 0 +0xB8B8 0x7236 # 0 +0xB8B9 0x8179 # 0 +0xB8BA 0x8D1F # 0 +0xB8BB 0x5BCC # 0 +0xB8BC 0x8BA3 # 0 +0xB8BD 0x9644 # 0 +0xB8BE 0x5987 # 0 +0xB8BF 0x7F1A # 0 +0xB8C0 0x5490 # 0 +0xB8C1 0x5676 # 0 +0xB8C2 0x560E # 0 +0xB8C3 0x8BE5 # 0 +0xB8C4 0x6539 # 0 +0xB8C5 0x6982 # 0 +0xB8C6 0x9499 # 0 +0xB8C7 0x76D6 # 0 +0xB8C8 0x6E89 # 0 +0xB8C9 0x5E72 # 0 +0xB8CA 0x7518 # 0 +0xB8CB 0x6746 # 0 +0xB8CC 0x67D1 # 0 +0xB8CD 0x7AFF # 0 +0xB8CE 0x809D # 0 +0xB8CF 0x8D76 # 0 +0xB8D0 0x611F # 0 +0xB8D1 0x79C6 # 0 +0xB8D2 0x6562 # 0 +0xB8D3 0x8D63 # 0 +0xB8D4 0x5188 # 0 +0xB8D5 0x521A # 0 +0xB8D6 0x94A2 # 0 +0xB8D7 0x7F38 # 0 +0xB8D8 0x809B # 0 +0xB8D9 0x7EB2 # 0 +0xB8DA 0x5C97 # 0 +0xB8DB 0x6E2F # 0 +0xB8DC 0x6760 # 0 +0xB8DD 0x7BD9 # 0 +0xB8DE 0x768B # 0 +0xB8DF 0x9AD8 # 0 +0xB8E0 0x818F # 0 +0xB8E1 0x7F94 # 0 +0xB8E2 0x7CD5 # 0 +0xB8E3 0x641E # 0 +0xB8E4 0x9550 # 0 +0xB8E5 0x7A3F # 0 +0xB8E6 0x544A # 0 +0xB8E7 0x54E5 # 0 +0xB8E8 0x6B4C # 0 +0xB8E9 0x6401 # 0 +0xB8EA 0x6208 # 0 +0xB8EB 0x9E3D # 0 +0xB8EC 0x80F3 # 0 +0xB8ED 0x7599 # 0 +0xB8EE 0x5272 # 0 +0xB8EF 0x9769 # 0 +0xB8F0 0x845B # 0 +0xB8F1 0x683C # 0 +0xB8F2 0x86E4 # 0 +0xB8F3 0x9601 # 0 +0xB8F4 0x9694 # 0 +0xB8F5 0x94EC # 0 +0xB8F6 0x4E2A # 0 +0xB8F7 0x5404 # 0 +0xB8F8 0x7ED9 # 0 +0xB8F9 0x6839 # 0 +0xB8FA 0x8DDF # 0 +0xB8FB 0x8015 # 0 +0xB8FC 0x66F4 # 0 +0xB8FD 0x5E9A # 0 +0xB8FE 0x7FB9 # 0 +0xB940 0x7B2F # 0 +0xB941 0x7B30 # 0 +0xB942 0x7B32 # 0 +0xB943 0x7B34 # 0 +0xB944 0x7B35 # 0 +0xB945 0x7B36 # 0 +0xB946 0x7B37 # 0 +0xB947 0x7B39 # 0 +0xB948 0x7B3B # 0 +0xB949 0x7B3D # 0 +0xB94A 0x7B3F # 0 +0xB94B 0x7B40 # 0 +0xB94C 0x7B41 # 0 +0xB94D 0x7B42 # 0 +0xB94E 0x7B43 # 0 +0xB94F 0x7B44 # 0 +0xB950 0x7B46 # 0 +0xB951 0x7B48 # 0 +0xB952 0x7B4A # 0 +0xB953 0x7B4D # 0 +0xB954 0x7B4E # 0 +0xB955 0x7B53 # 0 +0xB956 0x7B55 # 0 +0xB957 0x7B57 # 0 +0xB958 0x7B59 # 0 +0xB959 0x7B5C # 0 +0xB95A 0x7B5E # 0 +0xB95B 0x7B5F # 0 +0xB95C 0x7B61 # 0 +0xB95D 0x7B63 # 0 +0xB95E 0x7B64 # 0 +0xB95F 0x7B65 # 0 +0xB960 0x7B66 # 0 +0xB961 0x7B67 # 0 +0xB962 0x7B68 # 0 +0xB963 0x7B69 # 0 +0xB964 0x7B6A # 0 +0xB965 0x7B6B # 0 +0xB966 0x7B6C # 0 +0xB967 0x7B6D # 0 +0xB968 0x7B6F # 0 +0xB969 0x7B70 # 0 +0xB96A 0x7B73 # 0 +0xB96B 0x7B74 # 0 +0xB96C 0x7B76 # 0 +0xB96D 0x7B78 # 0 +0xB96E 0x7B7A # 0 +0xB96F 0x7B7C # 0 +0xB970 0x7B7D # 0 +0xB971 0x7B7F # 0 +0xB972 0x7B81 # 0 +0xB973 0x7B82 # 0 +0xB974 0x7B83 # 0 +0xB975 0x7B84 # 0 +0xB976 0x7B86 # 0 +0xB977 0x7B87 # 0 +0xB978 0x7B88 # 0 +0xB979 0x7B89 # 0 +0xB97A 0x7B8A # 0 +0xB97B 0x7B8B # 0 +0xB97C 0x7B8C # 0 +0xB97D 0x7B8E # 0 +0xB97E 0x7B8F # 0 +0xB980 0x7B91 # 0 +0xB981 0x7B92 # 0 +0xB982 0x7B93 # 0 +0xB983 0x7B96 # 0 +0xB984 0x7B98 # 0 +0xB985 0x7B99 # 0 +0xB986 0x7B9A # 0 +0xB987 0x7B9B # 0 +0xB988 0x7B9E # 0 +0xB989 0x7B9F # 0 +0xB98A 0x7BA0 # 0 +0xB98B 0x7BA3 # 0 +0xB98C 0x7BA4 # 0 +0xB98D 0x7BA5 # 0 +0xB98E 0x7BAE # 0 +0xB98F 0x7BAF # 0 +0xB990 0x7BB0 # 0 +0xB991 0x7BB2 # 0 +0xB992 0x7BB3 # 0 +0xB993 0x7BB5 # 0 +0xB994 0x7BB6 # 0 +0xB995 0x7BB7 # 0 +0xB996 0x7BB9 # 0 +0xB997 0x7BBA # 0 +0xB998 0x7BBB # 0 +0xB999 0x7BBC # 0 +0xB99A 0x7BBD # 0 +0xB99B 0x7BBE # 0 +0xB99C 0x7BBF # 0 +0xB99D 0x7BC0 # 0 +0xB99E 0x7BC2 # 0 +0xB99F 0x7BC3 # 0 +0xB9A0 0x7BC4 # 0 +0xB9A1 0x57C2 # 0 +0xB9A2 0x803F # 0 +0xB9A3 0x6897 # 0 +0xB9A4 0x5DE5 # 0 +0xB9A5 0x653B # 0 +0xB9A6 0x529F # 0 +0xB9A7 0x606D # 0 +0xB9A8 0x9F9A # 0 +0xB9A9 0x4F9B # 0 +0xB9AA 0x8EAC # 0 +0xB9AB 0x516C # 0 +0xB9AC 0x5BAB # 0 +0xB9AD 0x5F13 # 0 +0xB9AE 0x5DE9 # 0 +0xB9AF 0x6C5E # 0 +0xB9B0 0x62F1 # 0 +0xB9B1 0x8D21 # 0 +0xB9B2 0x5171 # 0 +0xB9B3 0x94A9 # 0 +0xB9B4 0x52FE # 0 +0xB9B5 0x6C9F # 0 +0xB9B6 0x82DF # 0 +0xB9B7 0x72D7 # 0 +0xB9B8 0x57A2 # 0 +0xB9B9 0x6784 # 0 +0xB9BA 0x8D2D # 0 +0xB9BB 0x591F # 0 +0xB9BC 0x8F9C # 0 +0xB9BD 0x83C7 # 0 +0xB9BE 0x5495 # 0 +0xB9BF 0x7B8D # 0 +0xB9C0 0x4F30 # 0 +0xB9C1 0x6CBD # 0 +0xB9C2 0x5B64 # 0 +0xB9C3 0x59D1 # 0 +0xB9C4 0x9F13 # 0 +0xB9C5 0x53E4 # 0 +0xB9C6 0x86CA # 0 +0xB9C7 0x9AA8 # 0 +0xB9C8 0x8C37 # 0 +0xB9C9 0x80A1 # 0 +0xB9CA 0x6545 # 0 +0xB9CB 0x987E # 0 +0xB9CC 0x56FA # 0 +0xB9CD 0x96C7 # 0 +0xB9CE 0x522E # 0 +0xB9CF 0x74DC # 0 +0xB9D0 0x5250 # 0 +0xB9D1 0x5BE1 # 0 +0xB9D2 0x6302 # 0 +0xB9D3 0x8902 # 0 +0xB9D4 0x4E56 # 0 +0xB9D5 0x62D0 # 0 +0xB9D6 0x602A # 0 +0xB9D7 0x68FA # 0 +0xB9D8 0x5173 # 0 +0xB9D9 0x5B98 # 0 +0xB9DA 0x51A0 # 0 +0xB9DB 0x89C2 # 0 +0xB9DC 0x7BA1 # 0 +0xB9DD 0x9986 # 0 +0xB9DE 0x7F50 # 0 +0xB9DF 0x60EF # 0 +0xB9E0 0x704C # 0 +0xB9E1 0x8D2F # 0 +0xB9E2 0x5149 # 0 +0xB9E3 0x5E7F # 0 +0xB9E4 0x901B # 0 +0xB9E5 0x7470 # 0 +0xB9E6 0x89C4 # 0 +0xB9E7 0x572D # 0 +0xB9E8 0x7845 # 0 +0xB9E9 0x5F52 # 0 +0xB9EA 0x9F9F # 0 +0xB9EB 0x95FA # 0 +0xB9EC 0x8F68 # 0 +0xB9ED 0x9B3C # 0 +0xB9EE 0x8BE1 # 0 +0xB9EF 0x7678 # 0 +0xB9F0 0x6842 # 0 +0xB9F1 0x67DC # 0 +0xB9F2 0x8DEA # 0 +0xB9F3 0x8D35 # 0 +0xB9F4 0x523D # 0 +0xB9F5 0x8F8A # 0 +0xB9F6 0x6EDA # 0 +0xB9F7 0x68CD # 0 +0xB9F8 0x9505 # 0 +0xB9F9 0x90ED # 0 +0xB9FA 0x56FD # 0 +0xB9FB 0x679C # 0 +0xB9FC 0x88F9 # 0 +0xB9FD 0x8FC7 # 0 +0xB9FE 0x54C8 # 0 +0xBA40 0x7BC5 # 0 +0xBA41 0x7BC8 # 0 +0xBA42 0x7BC9 # 0 +0xBA43 0x7BCA # 0 +0xBA44 0x7BCB # 0 +0xBA45 0x7BCD # 0 +0xBA46 0x7BCE # 0 +0xBA47 0x7BCF # 0 +0xBA48 0x7BD0 # 0 +0xBA49 0x7BD2 # 0 +0xBA4A 0x7BD4 # 0 +0xBA4B 0x7BD5 # 0 +0xBA4C 0x7BD6 # 0 +0xBA4D 0x7BD7 # 0 +0xBA4E 0x7BD8 # 0 +0xBA4F 0x7BDB # 0 +0xBA50 0x7BDC # 0 +0xBA51 0x7BDE # 0 +0xBA52 0x7BDF # 0 +0xBA53 0x7BE0 # 0 +0xBA54 0x7BE2 # 0 +0xBA55 0x7BE3 # 0 +0xBA56 0x7BE4 # 0 +0xBA57 0x7BE7 # 0 +0xBA58 0x7BE8 # 0 +0xBA59 0x7BE9 # 0 +0xBA5A 0x7BEB # 0 +0xBA5B 0x7BEC # 0 +0xBA5C 0x7BED # 0 +0xBA5D 0x7BEF # 0 +0xBA5E 0x7BF0 # 0 +0xBA5F 0x7BF2 # 0 +0xBA60 0x7BF3 # 0 +0xBA61 0x7BF4 # 0 +0xBA62 0x7BF5 # 0 +0xBA63 0x7BF6 # 0 +0xBA64 0x7BF8 # 0 +0xBA65 0x7BF9 # 0 +0xBA66 0x7BFA # 0 +0xBA67 0x7BFB # 0 +0xBA68 0x7BFD # 0 +0xBA69 0x7BFF # 0 +0xBA6A 0x7C00 # 0 +0xBA6B 0x7C01 # 0 +0xBA6C 0x7C02 # 0 +0xBA6D 0x7C03 # 0 +0xBA6E 0x7C04 # 0 +0xBA6F 0x7C05 # 0 +0xBA70 0x7C06 # 0 +0xBA71 0x7C08 # 0 +0xBA72 0x7C09 # 0 +0xBA73 0x7C0A # 0 +0xBA74 0x7C0D # 0 +0xBA75 0x7C0E # 0 +0xBA76 0x7C10 # 0 +0xBA77 0x7C11 # 0 +0xBA78 0x7C12 # 0 +0xBA79 0x7C13 # 0 +0xBA7A 0x7C14 # 0 +0xBA7B 0x7C15 # 0 +0xBA7C 0x7C17 # 0 +0xBA7D 0x7C18 # 0 +0xBA7E 0x7C19 # 0 +0xBA80 0x7C1A # 0 +0xBA81 0x7C1B # 0 +0xBA82 0x7C1C # 0 +0xBA83 0x7C1D # 0 +0xBA84 0x7C1E # 0 +0xBA85 0x7C20 # 0 +0xBA86 0x7C21 # 0 +0xBA87 0x7C22 # 0 +0xBA88 0x7C23 # 0 +0xBA89 0x7C24 # 0 +0xBA8A 0x7C25 # 0 +0xBA8B 0x7C28 # 0 +0xBA8C 0x7C29 # 0 +0xBA8D 0x7C2B # 0 +0xBA8E 0x7C2C # 0 +0xBA8F 0x7C2D # 0 +0xBA90 0x7C2E # 0 +0xBA91 0x7C2F # 0 +0xBA92 0x7C30 # 0 +0xBA93 0x7C31 # 0 +0xBA94 0x7C32 # 0 +0xBA95 0x7C33 # 0 +0xBA96 0x7C34 # 0 +0xBA97 0x7C35 # 0 +0xBA98 0x7C36 # 0 +0xBA99 0x7C37 # 0 +0xBA9A 0x7C39 # 0 +0xBA9B 0x7C3A # 0 +0xBA9C 0x7C3B # 0 +0xBA9D 0x7C3C # 0 +0xBA9E 0x7C3D # 0 +0xBA9F 0x7C3E # 0 +0xBAA0 0x7C42 # 0 +0xBAA1 0x9AB8 # 0 +0xBAA2 0x5B69 # 0 +0xBAA3 0x6D77 # 0 +0xBAA4 0x6C26 # 0 +0xBAA5 0x4EA5 # 0 +0xBAA6 0x5BB3 # 0 +0xBAA7 0x9A87 # 0 +0xBAA8 0x9163 # 0 +0xBAA9 0x61A8 # 0 +0xBAAA 0x90AF # 0 +0xBAAB 0x97E9 # 0 +0xBAAC 0x542B # 0 +0xBAAD 0x6DB5 # 0 +0xBAAE 0x5BD2 # 0 +0xBAAF 0x51FD # 0 +0xBAB0 0x558A # 0 +0xBAB1 0x7F55 # 0 +0xBAB2 0x7FF0 # 0 +0xBAB3 0x64BC # 0 +0xBAB4 0x634D # 0 +0xBAB5 0x65F1 # 0 +0xBAB6 0x61BE # 0 +0xBAB7 0x608D # 0 +0xBAB8 0x710A # 0 +0xBAB9 0x6C57 # 0 +0xBABA 0x6C49 # 0 +0xBABB 0x592F # 0 +0xBABC 0x676D # 0 +0xBABD 0x822A # 0 +0xBABE 0x58D5 # 0 +0xBABF 0x568E # 0 +0xBAC0 0x8C6A # 0 +0xBAC1 0x6BEB # 0 +0xBAC2 0x90DD # 0 +0xBAC3 0x597D # 0 +0xBAC4 0x8017 # 0 +0xBAC5 0x53F7 # 0 +0xBAC6 0x6D69 # 0 +0xBAC7 0x5475 # 0 +0xBAC8 0x559D # 0 +0xBAC9 0x8377 # 0 +0xBACA 0x83CF # 0 +0xBACB 0x6838 # 0 +0xBACC 0x79BE # 0 +0xBACD 0x548C # 0 +0xBACE 0x4F55 # 0 +0xBACF 0x5408 # 0 +0xBAD0 0x76D2 # 0 +0xBAD1 0x8C89 # 0 +0xBAD2 0x9602 # 0 +0xBAD3 0x6CB3 # 0 +0xBAD4 0x6DB8 # 0 +0xBAD5 0x8D6B # 0 +0xBAD6 0x8910 # 0 +0xBAD7 0x9E64 # 0 +0xBAD8 0x8D3A # 0 +0xBAD9 0x563F # 0 +0xBADA 0x9ED1 # 0 +0xBADB 0x75D5 # 0 +0xBADC 0x5F88 # 0 +0xBADD 0x72E0 # 0 +0xBADE 0x6068 # 0 +0xBADF 0x54FC # 0 +0xBAE0 0x4EA8 # 0 +0xBAE1 0x6A2A # 0 +0xBAE2 0x8861 # 0 +0xBAE3 0x6052 # 0 +0xBAE4 0x8F70 # 0 +0xBAE5 0x54C4 # 0 +0xBAE6 0x70D8 # 0 +0xBAE7 0x8679 # 0 +0xBAE8 0x9E3F # 0 +0xBAE9 0x6D2A # 0 +0xBAEA 0x5B8F # 0 +0xBAEB 0x5F18 # 0 +0xBAEC 0x7EA2 # 0 +0xBAED 0x5589 # 0 +0xBAEE 0x4FAF # 0 +0xBAEF 0x7334 # 0 +0xBAF0 0x543C # 0 +0xBAF1 0x539A # 0 +0xBAF2 0x5019 # 0 +0xBAF3 0x540E # 0 +0xBAF4 0x547C # 0 +0xBAF5 0x4E4E # 0 +0xBAF6 0x5FFD # 0 +0xBAF7 0x745A # 0 +0xBAF8 0x58F6 # 0 +0xBAF9 0x846B # 0 +0xBAFA 0x80E1 # 0 +0xBAFB 0x8774 # 0 +0xBAFC 0x72D0 # 0 +0xBAFD 0x7CCA # 0 +0xBAFE 0x6E56 # 0 +0xBB40 0x7C43 # 0 +0xBB41 0x7C44 # 0 +0xBB42 0x7C45 # 0 +0xBB43 0x7C46 # 0 +0xBB44 0x7C47 # 0 +0xBB45 0x7C48 # 0 +0xBB46 0x7C49 # 0 +0xBB47 0x7C4A # 0 +0xBB48 0x7C4B # 0 +0xBB49 0x7C4C # 0 +0xBB4A 0x7C4E # 0 +0xBB4B 0x7C4F # 0 +0xBB4C 0x7C50 # 0 +0xBB4D 0x7C51 # 0 +0xBB4E 0x7C52 # 0 +0xBB4F 0x7C53 # 0 +0xBB50 0x7C54 # 0 +0xBB51 0x7C55 # 0 +0xBB52 0x7C56 # 0 +0xBB53 0x7C57 # 0 +0xBB54 0x7C58 # 0 +0xBB55 0x7C59 # 0 +0xBB56 0x7C5A # 0 +0xBB57 0x7C5B # 0 +0xBB58 0x7C5C # 0 +0xBB59 0x7C5D # 0 +0xBB5A 0x7C5E # 0 +0xBB5B 0x7C5F # 0 +0xBB5C 0x7C60 # 0 +0xBB5D 0x7C61 # 0 +0xBB5E 0x7C62 # 0 +0xBB5F 0x7C63 # 0 +0xBB60 0x7C64 # 0 +0xBB61 0x7C65 # 0 +0xBB62 0x7C66 # 0 +0xBB63 0x7C67 # 0 +0xBB64 0x7C68 # 0 +0xBB65 0x7C69 # 0 +0xBB66 0x7C6A # 0 +0xBB67 0x7C6B # 0 +0xBB68 0x7C6C # 0 +0xBB69 0x7C6D # 0 +0xBB6A 0x7C6E # 0 +0xBB6B 0x7C6F # 0 +0xBB6C 0x7C70 # 0 +0xBB6D 0x7C71 # 0 +0xBB6E 0x7C72 # 0 +0xBB6F 0x7C75 # 0 +0xBB70 0x7C76 # 0 +0xBB71 0x7C77 # 0 +0xBB72 0x7C78 # 0 +0xBB73 0x7C79 # 0 +0xBB74 0x7C7A # 0 +0xBB75 0x7C7E # 0 +0xBB76 0x7C7F # 0 +0xBB77 0x7C80 # 0 +0xBB78 0x7C81 # 0 +0xBB79 0x7C82 # 0 +0xBB7A 0x7C83 # 0 +0xBB7B 0x7C84 # 0 +0xBB7C 0x7C85 # 0 +0xBB7D 0x7C86 # 0 +0xBB7E 0x7C87 # 0 +0xBB80 0x7C88 # 0 +0xBB81 0x7C8A # 0 +0xBB82 0x7C8B # 0 +0xBB83 0x7C8C # 0 +0xBB84 0x7C8D # 0 +0xBB85 0x7C8E # 0 +0xBB86 0x7C8F # 0 +0xBB87 0x7C90 # 0 +0xBB88 0x7C93 # 0 +0xBB89 0x7C94 # 0 +0xBB8A 0x7C96 # 0 +0xBB8B 0x7C99 # 0 +0xBB8C 0x7C9A # 0 +0xBB8D 0x7C9B # 0 +0xBB8E 0x7CA0 # 0 +0xBB8F 0x7CA1 # 0 +0xBB90 0x7CA3 # 0 +0xBB91 0x7CA6 # 0 +0xBB92 0x7CA7 # 0 +0xBB93 0x7CA8 # 0 +0xBB94 0x7CA9 # 0 +0xBB95 0x7CAB # 0 +0xBB96 0x7CAC # 0 +0xBB97 0x7CAD # 0 +0xBB98 0x7CAF # 0 +0xBB99 0x7CB0 # 0 +0xBB9A 0x7CB4 # 0 +0xBB9B 0x7CB5 # 0 +0xBB9C 0x7CB6 # 0 +0xBB9D 0x7CB7 # 0 +0xBB9E 0x7CB8 # 0 +0xBB9F 0x7CBA # 0 +0xBBA0 0x7CBB # 0 +0xBBA1 0x5F27 # 0 +0xBBA2 0x864E # 0 +0xBBA3 0x552C # 0 +0xBBA4 0x62A4 # 0 +0xBBA5 0x4E92 # 0 +0xBBA6 0x6CAA # 0 +0xBBA7 0x6237 # 0 +0xBBA8 0x82B1 # 0 +0xBBA9 0x54D7 # 0 +0xBBAA 0x534E # 0 +0xBBAB 0x733E # 0 +0xBBAC 0x6ED1 # 0 +0xBBAD 0x753B # 0 +0xBBAE 0x5212 # 0 +0xBBAF 0x5316 # 0 +0xBBB0 0x8BDD # 0 +0xBBB1 0x69D0 # 0 +0xBBB2 0x5F8A # 0 +0xBBB3 0x6000 # 0 +0xBBB4 0x6DEE # 0 +0xBBB5 0x574F # 0 +0xBBB6 0x6B22 # 0 +0xBBB7 0x73AF # 0 +0xBBB8 0x6853 # 0 +0xBBB9 0x8FD8 # 0 +0xBBBA 0x7F13 # 0 +0xBBBB 0x6362 # 0 +0xBBBC 0x60A3 # 0 +0xBBBD 0x5524 # 0 +0xBBBE 0x75EA # 0 +0xBBBF 0x8C62 # 0 +0xBBC0 0x7115 # 0 +0xBBC1 0x6DA3 # 0 +0xBBC2 0x5BA6 # 0 +0xBBC3 0x5E7B # 0 +0xBBC4 0x8352 # 0 +0xBBC5 0x614C # 0 +0xBBC6 0x9EC4 # 0 +0xBBC7 0x78FA # 0 +0xBBC8 0x8757 # 0 +0xBBC9 0x7C27 # 0 +0xBBCA 0x7687 # 0 +0xBBCB 0x51F0 # 0 +0xBBCC 0x60F6 # 0 +0xBBCD 0x714C # 0 +0xBBCE 0x6643 # 0 +0xBBCF 0x5E4C # 0 +0xBBD0 0x604D # 0 +0xBBD1 0x8C0E # 0 +0xBBD2 0x7070 # 0 +0xBBD3 0x6325 # 0 +0xBBD4 0x8F89 # 0 +0xBBD5 0x5FBD # 0 +0xBBD6 0x6062 # 0 +0xBBD7 0x86D4 # 0 +0xBBD8 0x56DE # 0 +0xBBD9 0x6BC1 # 0 +0xBBDA 0x6094 # 0 +0xBBDB 0x6167 # 0 +0xBBDC 0x5349 # 0 +0xBBDD 0x60E0 # 0 +0xBBDE 0x6666 # 0 +0xBBDF 0x8D3F # 0 +0xBBE0 0x79FD # 0 +0xBBE1 0x4F1A # 0 +0xBBE2 0x70E9 # 0 +0xBBE3 0x6C47 # 0 +0xBBE4 0x8BB3 # 0 +0xBBE5 0x8BF2 # 0 +0xBBE6 0x7ED8 # 0 +0xBBE7 0x8364 # 0 +0xBBE8 0x660F # 0 +0xBBE9 0x5A5A # 0 +0xBBEA 0x9B42 # 0 +0xBBEB 0x6D51 # 0 +0xBBEC 0x6DF7 # 0 +0xBBED 0x8C41 # 0 +0xBBEE 0x6D3B # 0 +0xBBEF 0x4F19 # 0 +0xBBF0 0x706B # 0 +0xBBF1 0x83B7 # 0 +0xBBF2 0x6216 # 0 +0xBBF3 0x60D1 # 0 +0xBBF4 0x970D # 0 +0xBBF5 0x8D27 # 0 +0xBBF6 0x7978 # 0 +0xBBF7 0x51FB # 0 +0xBBF8 0x573E # 0 +0xBBF9 0x57FA # 0 +0xBBFA 0x673A # 0 +0xBBFB 0x7578 # 0 +0xBBFC 0x7A3D # 0 +0xBBFD 0x79EF # 0 +0xBBFE 0x7B95 # 0 +0xBC40 0x7CBF # 0 +0xBC41 0x7CC0 # 0 +0xBC42 0x7CC2 # 0 +0xBC43 0x7CC3 # 0 +0xBC44 0x7CC4 # 0 +0xBC45 0x7CC6 # 0 +0xBC46 0x7CC9 # 0 +0xBC47 0x7CCB # 0 +0xBC48 0x7CCE # 0 +0xBC49 0x7CCF # 0 +0xBC4A 0x7CD0 # 0 +0xBC4B 0x7CD1 # 0 +0xBC4C 0x7CD2 # 0 +0xBC4D 0x7CD3 # 0 +0xBC4E 0x7CD4 # 0 +0xBC4F 0x7CD8 # 0 +0xBC50 0x7CDA # 0 +0xBC51 0x7CDB # 0 +0xBC52 0x7CDD # 0 +0xBC53 0x7CDE # 0 +0xBC54 0x7CE1 # 0 +0xBC55 0x7CE2 # 0 +0xBC56 0x7CE3 # 0 +0xBC57 0x7CE4 # 0 +0xBC58 0x7CE5 # 0 +0xBC59 0x7CE6 # 0 +0xBC5A 0x7CE7 # 0 +0xBC5B 0x7CE9 # 0 +0xBC5C 0x7CEA # 0 +0xBC5D 0x7CEB # 0 +0xBC5E 0x7CEC # 0 +0xBC5F 0x7CED # 0 +0xBC60 0x7CEE # 0 +0xBC61 0x7CF0 # 0 +0xBC62 0x7CF1 # 0 +0xBC63 0x7CF2 # 0 +0xBC64 0x7CF3 # 0 +0xBC65 0x7CF4 # 0 +0xBC66 0x7CF5 # 0 +0xBC67 0x7CF6 # 0 +0xBC68 0x7CF7 # 0 +0xBC69 0x7CF9 # 0 +0xBC6A 0x7CFA # 0 +0xBC6B 0x7CFC # 0 +0xBC6C 0x7CFD # 0 +0xBC6D 0x7CFE # 0 +0xBC6E 0x7CFF # 0 +0xBC6F 0x7D00 # 0 +0xBC70 0x7D01 # 0 +0xBC71 0x7D02 # 0 +0xBC72 0x7D03 # 0 +0xBC73 0x7D04 # 0 +0xBC74 0x7D05 # 0 +0xBC75 0x7D06 # 0 +0xBC76 0x7D07 # 0 +0xBC77 0x7D08 # 0 +0xBC78 0x7D09 # 0 +0xBC79 0x7D0B # 0 +0xBC7A 0x7D0C # 0 +0xBC7B 0x7D0D # 0 +0xBC7C 0x7D0E # 0 +0xBC7D 0x7D0F # 0 +0xBC7E 0x7D10 # 0 +0xBC80 0x7D11 # 0 +0xBC81 0x7D12 # 0 +0xBC82 0x7D13 # 0 +0xBC83 0x7D14 # 0 +0xBC84 0x7D15 # 0 +0xBC85 0x7D16 # 0 +0xBC86 0x7D17 # 0 +0xBC87 0x7D18 # 0 +0xBC88 0x7D19 # 0 +0xBC89 0x7D1A # 0 +0xBC8A 0x7D1B # 0 +0xBC8B 0x7D1C # 0 +0xBC8C 0x7D1D # 0 +0xBC8D 0x7D1E # 0 +0xBC8E 0x7D1F # 0 +0xBC8F 0x7D21 # 0 +0xBC90 0x7D23 # 0 +0xBC91 0x7D24 # 0 +0xBC92 0x7D25 # 0 +0xBC93 0x7D26 # 0 +0xBC94 0x7D28 # 0 +0xBC95 0x7D29 # 0 +0xBC96 0x7D2A # 0 +0xBC97 0x7D2C # 0 +0xBC98 0x7D2D # 0 +0xBC99 0x7D2E # 0 +0xBC9A 0x7D30 # 0 +0xBC9B 0x7D31 # 0 +0xBC9C 0x7D32 # 0 +0xBC9D 0x7D33 # 0 +0xBC9E 0x7D34 # 0 +0xBC9F 0x7D35 # 0 +0xBCA0 0x7D36 # 0 +0xBCA1 0x808C # 0 +0xBCA2 0x9965 # 0 +0xBCA3 0x8FF9 # 0 +0xBCA4 0x6FC0 # 0 +0xBCA5 0x8BA5 # 0 +0xBCA6 0x9E21 # 0 +0xBCA7 0x59EC # 0 +0xBCA8 0x7EE9 # 0 +0xBCA9 0x7F09 # 0 +0xBCAA 0x5409 # 0 +0xBCAB 0x6781 # 0 +0xBCAC 0x68D8 # 0 +0xBCAD 0x8F91 # 0 +0xBCAE 0x7C4D # 0 +0xBCAF 0x96C6 # 0 +0xBCB0 0x53CA # 0 +0xBCB1 0x6025 # 0 +0xBCB2 0x75BE # 0 +0xBCB3 0x6C72 # 0 +0xBCB4 0x5373 # 0 +0xBCB5 0x5AC9 # 0 +0xBCB6 0x7EA7 # 0 +0xBCB7 0x6324 # 0 +0xBCB8 0x51E0 # 0 +0xBCB9 0x810A # 0 +0xBCBA 0x5DF1 # 0 +0xBCBB 0x84DF # 0 +0xBCBC 0x6280 # 0 +0xBCBD 0x5180 # 0 +0xBCBE 0x5B63 # 0 +0xBCBF 0x4F0E # 0 +0xBCC0 0x796D # 0 +0xBCC1 0x5242 # 0 +0xBCC2 0x60B8 # 0 +0xBCC3 0x6D4E # 0 +0xBCC4 0x5BC4 # 0 +0xBCC5 0x5BC2 # 0 +0xBCC6 0x8BA1 # 0 +0xBCC7 0x8BB0 # 0 +0xBCC8 0x65E2 # 0 +0xBCC9 0x5FCC # 0 +0xBCCA 0x9645 # 0 +0xBCCB 0x5993 # 0 +0xBCCC 0x7EE7 # 0 +0xBCCD 0x7EAA # 0 +0xBCCE 0x5609 # 0 +0xBCCF 0x67B7 # 0 +0xBCD0 0x5939 # 0 +0xBCD1 0x4F73 # 0 +0xBCD2 0x5BB6 # 0 +0xBCD3 0x52A0 # 0 +0xBCD4 0x835A # 0 +0xBCD5 0x988A # 0 +0xBCD6 0x8D3E # 0 +0xBCD7 0x7532 # 0 +0xBCD8 0x94BE # 0 +0xBCD9 0x5047 # 0 +0xBCDA 0x7A3C # 0 +0xBCDB 0x4EF7 # 0 +0xBCDC 0x67B6 # 0 +0xBCDD 0x9A7E # 0 +0xBCDE 0x5AC1 # 0 +0xBCDF 0x6B7C # 0 +0xBCE0 0x76D1 # 0 +0xBCE1 0x575A # 0 +0xBCE2 0x5C16 # 0 +0xBCE3 0x7B3A # 0 +0xBCE4 0x95F4 # 0 +0xBCE5 0x714E # 0 +0xBCE6 0x517C # 0 +0xBCE7 0x80A9 # 0 +0xBCE8 0x8270 # 0 +0xBCE9 0x5978 # 0 +0xBCEA 0x7F04 # 0 +0xBCEB 0x8327 # 0 +0xBCEC 0x68C0 # 0 +0xBCED 0x67EC # 0 +0xBCEE 0x78B1 # 0 +0xBCEF 0x7877 # 0 +0xBCF0 0x62E3 # 0 +0xBCF1 0x6361 # 0 +0xBCF2 0x7B80 # 0 +0xBCF3 0x4FED # 0 +0xBCF4 0x526A # 0 +0xBCF5 0x51CF # 0 +0xBCF6 0x8350 # 0 +0xBCF7 0x69DB # 0 +0xBCF8 0x9274 # 0 +0xBCF9 0x8DF5 # 0 +0xBCFA 0x8D31 # 0 +0xBCFB 0x89C1 # 0 +0xBCFC 0x952E # 0 +0xBCFD 0x7BAD # 0 +0xBCFE 0x4EF6 # 0 +0xBD40 0x7D37 # 0 +0xBD41 0x7D38 # 0 +0xBD42 0x7D39 # 0 +0xBD43 0x7D3A # 0 +0xBD44 0x7D3B # 0 +0xBD45 0x7D3C # 0 +0xBD46 0x7D3D # 0 +0xBD47 0x7D3E # 0 +0xBD48 0x7D3F # 0 +0xBD49 0x7D40 # 0 +0xBD4A 0x7D41 # 0 +0xBD4B 0x7D42 # 0 +0xBD4C 0x7D43 # 0 +0xBD4D 0x7D44 # 0 +0xBD4E 0x7D45 # 0 +0xBD4F 0x7D46 # 0 +0xBD50 0x7D47 # 0 +0xBD51 0x7D48 # 0 +0xBD52 0x7D49 # 0 +0xBD53 0x7D4A # 0 +0xBD54 0x7D4B # 0 +0xBD55 0x7D4C # 0 +0xBD56 0x7D4D # 0 +0xBD57 0x7D4E # 0 +0xBD58 0x7D4F # 0 +0xBD59 0x7D50 # 0 +0xBD5A 0x7D51 # 0 +0xBD5B 0x7D52 # 0 +0xBD5C 0x7D53 # 0 +0xBD5D 0x7D54 # 0 +0xBD5E 0x7D55 # 0 +0xBD5F 0x7D56 # 0 +0xBD60 0x7D57 # 0 +0xBD61 0x7D58 # 0 +0xBD62 0x7D59 # 0 +0xBD63 0x7D5A # 0 +0xBD64 0x7D5B # 0 +0xBD65 0x7D5C # 0 +0xBD66 0x7D5D # 0 +0xBD67 0x7D5E # 0 +0xBD68 0x7D5F # 0 +0xBD69 0x7D60 # 0 +0xBD6A 0x7D61 # 0 +0xBD6B 0x7D62 # 0 +0xBD6C 0x7D63 # 0 +0xBD6D 0x7D64 # 0 +0xBD6E 0x7D65 # 0 +0xBD6F 0x7D66 # 0 +0xBD70 0x7D67 # 0 +0xBD71 0x7D68 # 0 +0xBD72 0x7D69 # 0 +0xBD73 0x7D6A # 0 +0xBD74 0x7D6B # 0 +0xBD75 0x7D6C # 0 +0xBD76 0x7D6D # 0 +0xBD77 0x7D6F # 0 +0xBD78 0x7D70 # 0 +0xBD79 0x7D71 # 0 +0xBD7A 0x7D72 # 0 +0xBD7B 0x7D73 # 0 +0xBD7C 0x7D74 # 0 +0xBD7D 0x7D75 # 0 +0xBD7E 0x7D76 # 0 +0xBD80 0x7D78 # 0 +0xBD81 0x7D79 # 0 +0xBD82 0x7D7A # 0 +0xBD83 0x7D7B # 0 +0xBD84 0x7D7C # 0 +0xBD85 0x7D7D # 0 +0xBD86 0x7D7E # 0 +0xBD87 0x7D7F # 0 +0xBD88 0x7D80 # 0 +0xBD89 0x7D81 # 0 +0xBD8A 0x7D82 # 0 +0xBD8B 0x7D83 # 0 +0xBD8C 0x7D84 # 0 +0xBD8D 0x7D85 # 0 +0xBD8E 0x7D86 # 0 +0xBD8F 0x7D87 # 0 +0xBD90 0x7D88 # 0 +0xBD91 0x7D89 # 0 +0xBD92 0x7D8A # 0 +0xBD93 0x7D8B # 0 +0xBD94 0x7D8C # 0 +0xBD95 0x7D8D # 0 +0xBD96 0x7D8E # 0 +0xBD97 0x7D8F # 0 +0xBD98 0x7D90 # 0 +0xBD99 0x7D91 # 0 +0xBD9A 0x7D92 # 0 +0xBD9B 0x7D93 # 0 +0xBD9C 0x7D94 # 0 +0xBD9D 0x7D95 # 0 +0xBD9E 0x7D96 # 0 +0xBD9F 0x7D97 # 0 +0xBDA0 0x7D98 # 0 +0xBDA1 0x5065 # 0 +0xBDA2 0x8230 # 0 +0xBDA3 0x5251 # 0 +0xBDA4 0x996F # 0 +0xBDA5 0x6E10 # 0 +0xBDA6 0x6E85 # 0 +0xBDA7 0x6DA7 # 0 +0xBDA8 0x5EFA # 0 +0xBDA9 0x50F5 # 0 +0xBDAA 0x59DC # 0 +0xBDAB 0x5C06 # 0 +0xBDAC 0x6D46 # 0 +0xBDAD 0x6C5F # 0 +0xBDAE 0x7586 # 0 +0xBDAF 0x848B # 0 +0xBDB0 0x6868 # 0 +0xBDB1 0x5956 # 0 +0xBDB2 0x8BB2 # 0 +0xBDB3 0x5320 # 0 +0xBDB4 0x9171 # 0 +0xBDB5 0x964D # 0 +0xBDB6 0x8549 # 0 +0xBDB7 0x6912 # 0 +0xBDB8 0x7901 # 0 +0xBDB9 0x7126 # 0 +0xBDBA 0x80F6 # 0 +0xBDBB 0x4EA4 # 0 +0xBDBC 0x90CA # 0 +0xBDBD 0x6D47 # 0 +0xBDBE 0x9A84 # 0 +0xBDBF 0x5A07 # 0 +0xBDC0 0x56BC # 0 +0xBDC1 0x6405 # 0 +0xBDC2 0x94F0 # 0 +0xBDC3 0x77EB # 0 +0xBDC4 0x4FA5 # 0 +0xBDC5 0x811A # 0 +0xBDC6 0x72E1 # 0 +0xBDC7 0x89D2 # 0 +0xBDC8 0x997A # 0 +0xBDC9 0x7F34 # 0 +0xBDCA 0x7EDE # 0 +0xBDCB 0x527F # 0 +0xBDCC 0x6559 # 0 +0xBDCD 0x9175 # 0 +0xBDCE 0x8F7F # 0 +0xBDCF 0x8F83 # 0 +0xBDD0 0x53EB # 0 +0xBDD1 0x7A96 # 0 +0xBDD2 0x63ED # 0 +0xBDD3 0x63A5 # 0 +0xBDD4 0x7686 # 0 +0xBDD5 0x79F8 # 0 +0xBDD6 0x8857 # 0 +0xBDD7 0x9636 # 0 +0xBDD8 0x622A # 0 +0xBDD9 0x52AB # 0 +0xBDDA 0x8282 # 0 +0xBDDB 0x6854 # 0 +0xBDDC 0x6770 # 0 +0xBDDD 0x6377 # 0 +0xBDDE 0x776B # 0 +0xBDDF 0x7AED # 0 +0xBDE0 0x6D01 # 0 +0xBDE1 0x7ED3 # 0 +0xBDE2 0x89E3 # 0 +0xBDE3 0x59D0 # 0 +0xBDE4 0x6212 # 0 +0xBDE5 0x85C9 # 0 +0xBDE6 0x82A5 # 0 +0xBDE7 0x754C # 0 +0xBDE8 0x501F # 0 +0xBDE9 0x4ECB # 0 +0xBDEA 0x75A5 # 0 +0xBDEB 0x8BEB # 0 +0xBDEC 0x5C4A # 0 +0xBDED 0x5DFE # 0 +0xBDEE 0x7B4B # 0 +0xBDEF 0x65A4 # 0 +0xBDF0 0x91D1 # 0 +0xBDF1 0x4ECA # 0 +0xBDF2 0x6D25 # 0 +0xBDF3 0x895F # 0 +0xBDF4 0x7D27 # 0 +0xBDF5 0x9526 # 0 +0xBDF6 0x4EC5 # 0 +0xBDF7 0x8C28 # 0 +0xBDF8 0x8FDB # 0 +0xBDF9 0x9773 # 0 +0xBDFA 0x664B # 0 +0xBDFB 0x7981 # 0 +0xBDFC 0x8FD1 # 0 +0xBDFD 0x70EC # 0 +0xBDFE 0x6D78 # 0 +0xBE40 0x7D99 # 0 +0xBE41 0x7D9A # 0 +0xBE42 0x7D9B # 0 +0xBE43 0x7D9C # 0 +0xBE44 0x7D9D # 0 +0xBE45 0x7D9E # 0 +0xBE46 0x7D9F # 0 +0xBE47 0x7DA0 # 0 +0xBE48 0x7DA1 # 0 +0xBE49 0x7DA2 # 0 +0xBE4A 0x7DA3 # 0 +0xBE4B 0x7DA4 # 0 +0xBE4C 0x7DA5 # 0 +0xBE4D 0x7DA7 # 0 +0xBE4E 0x7DA8 # 0 +0xBE4F 0x7DA9 # 0 +0xBE50 0x7DAA # 0 +0xBE51 0x7DAB # 0 +0xBE52 0x7DAC # 0 +0xBE53 0x7DAD # 0 +0xBE54 0x7DAF # 0 +0xBE55 0x7DB0 # 0 +0xBE56 0x7DB1 # 0 +0xBE57 0x7DB2 # 0 +0xBE58 0x7DB3 # 0 +0xBE59 0x7DB4 # 0 +0xBE5A 0x7DB5 # 0 +0xBE5B 0x7DB6 # 0 +0xBE5C 0x7DB7 # 0 +0xBE5D 0x7DB8 # 0 +0xBE5E 0x7DB9 # 0 +0xBE5F 0x7DBA # 0 +0xBE60 0x7DBB # 0 +0xBE61 0x7DBC # 0 +0xBE62 0x7DBD # 0 +0xBE63 0x7DBE # 0 +0xBE64 0x7DBF # 0 +0xBE65 0x7DC0 # 0 +0xBE66 0x7DC1 # 0 +0xBE67 0x7DC2 # 0 +0xBE68 0x7DC3 # 0 +0xBE69 0x7DC4 # 0 +0xBE6A 0x7DC5 # 0 +0xBE6B 0x7DC6 # 0 +0xBE6C 0x7DC7 # 0 +0xBE6D 0x7DC8 # 0 +0xBE6E 0x7DC9 # 0 +0xBE6F 0x7DCA # 0 +0xBE70 0x7DCB # 0 +0xBE71 0x7DCC # 0 +0xBE72 0x7DCD # 0 +0xBE73 0x7DCE # 0 +0xBE74 0x7DCF # 0 +0xBE75 0x7DD0 # 0 +0xBE76 0x7DD1 # 0 +0xBE77 0x7DD2 # 0 +0xBE78 0x7DD3 # 0 +0xBE79 0x7DD4 # 0 +0xBE7A 0x7DD5 # 0 +0xBE7B 0x7DD6 # 0 +0xBE7C 0x7DD7 # 0 +0xBE7D 0x7DD8 # 0 +0xBE7E 0x7DD9 # 0 +0xBE80 0x7DDA # 0 +0xBE81 0x7DDB # 0 +0xBE82 0x7DDC # 0 +0xBE83 0x7DDD # 0 +0xBE84 0x7DDE # 0 +0xBE85 0x7DDF # 0 +0xBE86 0x7DE0 # 0 +0xBE87 0x7DE1 # 0 +0xBE88 0x7DE2 # 0 +0xBE89 0x7DE3 # 0 +0xBE8A 0x7DE4 # 0 +0xBE8B 0x7DE5 # 0 +0xBE8C 0x7DE6 # 0 +0xBE8D 0x7DE7 # 0 +0xBE8E 0x7DE8 # 0 +0xBE8F 0x7DE9 # 0 +0xBE90 0x7DEA # 0 +0xBE91 0x7DEB # 0 +0xBE92 0x7DEC # 0 +0xBE93 0x7DED # 0 +0xBE94 0x7DEE # 0 +0xBE95 0x7DEF # 0 +0xBE96 0x7DF0 # 0 +0xBE97 0x7DF1 # 0 +0xBE98 0x7DF2 # 0 +0xBE99 0x7DF3 # 0 +0xBE9A 0x7DF4 # 0 +0xBE9B 0x7DF5 # 0 +0xBE9C 0x7DF6 # 0 +0xBE9D 0x7DF7 # 0 +0xBE9E 0x7DF8 # 0 +0xBE9F 0x7DF9 # 0 +0xBEA0 0x7DFA # 0 +0xBEA1 0x5C3D # 0 +0xBEA2 0x52B2 # 0 +0xBEA3 0x8346 # 0 +0xBEA4 0x5162 # 0 +0xBEA5 0x830E # 0 +0xBEA6 0x775B # 0 +0xBEA7 0x6676 # 0 +0xBEA8 0x9CB8 # 0 +0xBEA9 0x4EAC # 0 +0xBEAA 0x60CA # 0 +0xBEAB 0x7CBE # 0 +0xBEAC 0x7CB3 # 0 +0xBEAD 0x7ECF # 0 +0xBEAE 0x4E95 # 0 +0xBEAF 0x8B66 # 0 +0xBEB0 0x666F # 0 +0xBEB1 0x9888 # 0 +0xBEB2 0x9759 # 0 +0xBEB3 0x5883 # 0 +0xBEB4 0x656C # 0 +0xBEB5 0x955C # 0 +0xBEB6 0x5F84 # 0 +0xBEB7 0x75C9 # 0 +0xBEB8 0x9756 # 0 +0xBEB9 0x7ADF # 0 +0xBEBA 0x7ADE # 0 +0xBEBB 0x51C0 # 0 +0xBEBC 0x70AF # 0 +0xBEBD 0x7A98 # 0 +0xBEBE 0x63EA # 0 +0xBEBF 0x7A76 # 0 +0xBEC0 0x7EA0 # 0 +0xBEC1 0x7396 # 0 +0xBEC2 0x97ED # 0 +0xBEC3 0x4E45 # 0 +0xBEC4 0x7078 # 0 +0xBEC5 0x4E5D # 0 +0xBEC6 0x9152 # 0 +0xBEC7 0x53A9 # 0 +0xBEC8 0x6551 # 0 +0xBEC9 0x65E7 # 0 +0xBECA 0x81FC # 0 +0xBECB 0x8205 # 0 +0xBECC 0x548E # 0 +0xBECD 0x5C31 # 0 +0xBECE 0x759A # 0 +0xBECF 0x97A0 # 0 +0xBED0 0x62D8 # 0 +0xBED1 0x72D9 # 0 +0xBED2 0x75BD # 0 +0xBED3 0x5C45 # 0 +0xBED4 0x9A79 # 0 +0xBED5 0x83CA # 0 +0xBED6 0x5C40 # 0 +0xBED7 0x5480 # 0 +0xBED8 0x77E9 # 0 +0xBED9 0x4E3E # 0 +0xBEDA 0x6CAE # 0 +0xBEDB 0x805A # 0 +0xBEDC 0x62D2 # 0 +0xBEDD 0x636E # 0 +0xBEDE 0x5DE8 # 0 +0xBEDF 0x5177 # 0 +0xBEE0 0x8DDD # 0 +0xBEE1 0x8E1E # 0 +0xBEE2 0x952F # 0 +0xBEE3 0x4FF1 # 0 +0xBEE4 0x53E5 # 0 +0xBEE5 0x60E7 # 0 +0xBEE6 0x70AC # 0 +0xBEE7 0x5267 # 0 +0xBEE8 0x6350 # 0 +0xBEE9 0x9E43 # 0 +0xBEEA 0x5A1F # 0 +0xBEEB 0x5026 # 0 +0xBEEC 0x7737 # 0 +0xBEED 0x5377 # 0 +0xBEEE 0x7EE2 # 0 +0xBEEF 0x6485 # 0 +0xBEF0 0x652B # 0 +0xBEF1 0x6289 # 0 +0xBEF2 0x6398 # 0 +0xBEF3 0x5014 # 0 +0xBEF4 0x7235 # 0 +0xBEF5 0x89C9 # 0 +0xBEF6 0x51B3 # 0 +0xBEF7 0x8BC0 # 0 +0xBEF8 0x7EDD # 0 +0xBEF9 0x5747 # 0 +0xBEFA 0x83CC # 0 +0xBEFB 0x94A7 # 0 +0xBEFC 0x519B # 0 +0xBEFD 0x541B # 0 +0xBEFE 0x5CFB # 0 +0xBF40 0x7DFB # 0 +0xBF41 0x7DFC # 0 +0xBF42 0x7DFD # 0 +0xBF43 0x7DFE # 0 +0xBF44 0x7DFF # 0 +0xBF45 0x7E00 # 0 +0xBF46 0x7E01 # 0 +0xBF47 0x7E02 # 0 +0xBF48 0x7E03 # 0 +0xBF49 0x7E04 # 0 +0xBF4A 0x7E05 # 0 +0xBF4B 0x7E06 # 0 +0xBF4C 0x7E07 # 0 +0xBF4D 0x7E08 # 0 +0xBF4E 0x7E09 # 0 +0xBF4F 0x7E0A # 0 +0xBF50 0x7E0B # 0 +0xBF51 0x7E0C # 0 +0xBF52 0x7E0D # 0 +0xBF53 0x7E0E # 0 +0xBF54 0x7E0F # 0 +0xBF55 0x7E10 # 0 +0xBF56 0x7E11 # 0 +0xBF57 0x7E12 # 0 +0xBF58 0x7E13 # 0 +0xBF59 0x7E14 # 0 +0xBF5A 0x7E15 # 0 +0xBF5B 0x7E16 # 0 +0xBF5C 0x7E17 # 0 +0xBF5D 0x7E18 # 0 +0xBF5E 0x7E19 # 0 +0xBF5F 0x7E1A # 0 +0xBF60 0x7E1B # 0 +0xBF61 0x7E1C # 0 +0xBF62 0x7E1D # 0 +0xBF63 0x7E1E # 0 +0xBF64 0x7E1F # 0 +0xBF65 0x7E20 # 0 +0xBF66 0x7E21 # 0 +0xBF67 0x7E22 # 0 +0xBF68 0x7E23 # 0 +0xBF69 0x7E24 # 0 +0xBF6A 0x7E25 # 0 +0xBF6B 0x7E26 # 0 +0xBF6C 0x7E27 # 0 +0xBF6D 0x7E28 # 0 +0xBF6E 0x7E29 # 0 +0xBF6F 0x7E2A # 0 +0xBF70 0x7E2B # 0 +0xBF71 0x7E2C # 0 +0xBF72 0x7E2D # 0 +0xBF73 0x7E2E # 0 +0xBF74 0x7E2F # 0 +0xBF75 0x7E30 # 0 +0xBF76 0x7E31 # 0 +0xBF77 0x7E32 # 0 +0xBF78 0x7E33 # 0 +0xBF79 0x7E34 # 0 +0xBF7A 0x7E35 # 0 +0xBF7B 0x7E36 # 0 +0xBF7C 0x7E37 # 0 +0xBF7D 0x7E38 # 0 +0xBF7E 0x7E39 # 0 +0xBF80 0x7E3A # 0 +0xBF81 0x7E3C # 0 +0xBF82 0x7E3D # 0 +0xBF83 0x7E3E # 0 +0xBF84 0x7E3F # 0 +0xBF85 0x7E40 # 0 +0xBF86 0x7E42 # 0 +0xBF87 0x7E43 # 0 +0xBF88 0x7E44 # 0 +0xBF89 0x7E45 # 0 +0xBF8A 0x7E46 # 0 +0xBF8B 0x7E48 # 0 +0xBF8C 0x7E49 # 0 +0xBF8D 0x7E4A # 0 +0xBF8E 0x7E4B # 0 +0xBF8F 0x7E4C # 0 +0xBF90 0x7E4D # 0 +0xBF91 0x7E4E # 0 +0xBF92 0x7E4F # 0 +0xBF93 0x7E50 # 0 +0xBF94 0x7E51 # 0 +0xBF95 0x7E52 # 0 +0xBF96 0x7E53 # 0 +0xBF97 0x7E54 # 0 +0xBF98 0x7E55 # 0 +0xBF99 0x7E56 # 0 +0xBF9A 0x7E57 # 0 +0xBF9B 0x7E58 # 0 +0xBF9C 0x7E59 # 0 +0xBF9D 0x7E5A # 0 +0xBF9E 0x7E5B # 0 +0xBF9F 0x7E5C # 0 +0xBFA0 0x7E5D # 0 +0xBFA1 0x4FCA # 0 +0xBFA2 0x7AE3 # 0 +0xBFA3 0x6D5A # 0 +0xBFA4 0x90E1 # 0 +0xBFA5 0x9A8F # 0 +0xBFA6 0x5580 # 0 +0xBFA7 0x5496 # 0 +0xBFA8 0x5361 # 0 +0xBFA9 0x54AF # 0 +0xBFAA 0x5F00 # 0 +0xBFAB 0x63E9 # 0 +0xBFAC 0x6977 # 0 +0xBFAD 0x51EF # 0 +0xBFAE 0x6168 # 0 +0xBFAF 0x520A # 0 +0xBFB0 0x582A # 0 +0xBFB1 0x52D8 # 0 +0xBFB2 0x574E # 0 +0xBFB3 0x780D # 0 +0xBFB4 0x770B # 0 +0xBFB5 0x5EB7 # 0 +0xBFB6 0x6177 # 0 +0xBFB7 0x7CE0 # 0 +0xBFB8 0x625B # 0 +0xBFB9 0x6297 # 0 +0xBFBA 0x4EA2 # 0 +0xBFBB 0x7095 # 0 +0xBFBC 0x8003 # 0 +0xBFBD 0x62F7 # 0 +0xBFBE 0x70E4 # 0 +0xBFBF 0x9760 # 0 +0xBFC0 0x5777 # 0 +0xBFC1 0x82DB # 0 +0xBFC2 0x67EF # 0 +0xBFC3 0x68F5 # 0 +0xBFC4 0x78D5 # 0 +0xBFC5 0x9897 # 0 +0xBFC6 0x79D1 # 0 +0xBFC7 0x58F3 # 0 +0xBFC8 0x54B3 # 0 +0xBFC9 0x53EF # 0 +0xBFCA 0x6E34 # 0 +0xBFCB 0x514B # 0 +0xBFCC 0x523B # 0 +0xBFCD 0x5BA2 # 0 +0xBFCE 0x8BFE # 0 +0xBFCF 0x80AF # 0 +0xBFD0 0x5543 # 0 +0xBFD1 0x57A6 # 0 +0xBFD2 0x6073 # 0 +0xBFD3 0x5751 # 0 +0xBFD4 0x542D # 0 +0xBFD5 0x7A7A # 0 +0xBFD6 0x6050 # 0 +0xBFD7 0x5B54 # 0 +0xBFD8 0x63A7 # 0 +0xBFD9 0x62A0 # 0 +0xBFDA 0x53E3 # 0 +0xBFDB 0x6263 # 0 +0xBFDC 0x5BC7 # 0 +0xBFDD 0x67AF # 0 +0xBFDE 0x54ED # 0 +0xBFDF 0x7A9F # 0 +0xBFE0 0x82E6 # 0 +0xBFE1 0x9177 # 0 +0xBFE2 0x5E93 # 0 +0xBFE3 0x88E4 # 0 +0xBFE4 0x5938 # 0 +0xBFE5 0x57AE # 0 +0xBFE6 0x630E # 0 +0xBFE7 0x8DE8 # 0 +0xBFE8 0x80EF # 0 +0xBFE9 0x5757 # 0 +0xBFEA 0x7B77 # 0 +0xBFEB 0x4FA9 # 0 +0xBFEC 0x5FEB # 0 +0xBFED 0x5BBD # 0 +0xBFEE 0x6B3E # 0 +0xBFEF 0x5321 # 0 +0xBFF0 0x7B50 # 0 +0xBFF1 0x72C2 # 0 +0xBFF2 0x6846 # 0 +0xBFF3 0x77FF # 0 +0xBFF4 0x7736 # 0 +0xBFF5 0x65F7 # 0 +0xBFF6 0x51B5 # 0 +0xBFF7 0x4E8F # 0 +0xBFF8 0x76D4 # 0 +0xBFF9 0x5CBF # 0 +0xBFFA 0x7AA5 # 0 +0xBFFB 0x8475 # 0 +0xBFFC 0x594E # 0 +0xBFFD 0x9B41 # 0 +0xBFFE 0x5080 # 0 +0xC040 0x7E5E # 0 +0xC041 0x7E5F # 0 +0xC042 0x7E60 # 0 +0xC043 0x7E61 # 0 +0xC044 0x7E62 # 0 +0xC045 0x7E63 # 0 +0xC046 0x7E64 # 0 +0xC047 0x7E65 # 0 +0xC048 0x7E66 # 0 +0xC049 0x7E67 # 0 +0xC04A 0x7E68 # 0 +0xC04B 0x7E69 # 0 +0xC04C 0x7E6A # 0 +0xC04D 0x7E6B # 0 +0xC04E 0x7E6C # 0 +0xC04F 0x7E6D # 0 +0xC050 0x7E6E # 0 +0xC051 0x7E6F # 0 +0xC052 0x7E70 # 0 +0xC053 0x7E71 # 0 +0xC054 0x7E72 # 0 +0xC055 0x7E73 # 0 +0xC056 0x7E74 # 0 +0xC057 0x7E75 # 0 +0xC058 0x7E76 # 0 +0xC059 0x7E77 # 0 +0xC05A 0x7E78 # 0 +0xC05B 0x7E79 # 0 +0xC05C 0x7E7A # 0 +0xC05D 0x7E7B # 0 +0xC05E 0x7E7C # 0 +0xC05F 0x7E7D # 0 +0xC060 0x7E7E # 0 +0xC061 0x7E7F # 0 +0xC062 0x7E80 # 0 +0xC063 0x7E81 # 0 +0xC064 0x7E83 # 0 +0xC065 0x7E84 # 0 +0xC066 0x7E85 # 0 +0xC067 0x7E86 # 0 +0xC068 0x7E87 # 0 +0xC069 0x7E88 # 0 +0xC06A 0x7E89 # 0 +0xC06B 0x7E8A # 0 +0xC06C 0x7E8B # 0 +0xC06D 0x7E8C # 0 +0xC06E 0x7E8D # 0 +0xC06F 0x7E8E # 0 +0xC070 0x7E8F # 0 +0xC071 0x7E90 # 0 +0xC072 0x7E91 # 0 +0xC073 0x7E92 # 0 +0xC074 0x7E93 # 0 +0xC075 0x7E94 # 0 +0xC076 0x7E95 # 0 +0xC077 0x7E96 # 0 +0xC078 0x7E97 # 0 +0xC079 0x7E98 # 0 +0xC07A 0x7E99 # 0 +0xC07B 0x7E9A # 0 +0xC07C 0x7E9C # 0 +0xC07D 0x7E9D # 0 +0xC07E 0x7E9E # 0 +0xC080 0x7EAE # 0 +0xC081 0x7EB4 # 0 +0xC082 0x7EBB # 0 +0xC083 0x7EBC # 0 +0xC084 0x7ED6 # 0 +0xC085 0x7EE4 # 0 +0xC086 0x7EEC # 0 +0xC087 0x7EF9 # 0 +0xC088 0x7F0A # 0 +0xC089 0x7F10 # 0 +0xC08A 0x7F1E # 0 +0xC08B 0x7F37 # 0 +0xC08C 0x7F39 # 0 +0xC08D 0x7F3B # 0 +0xC08E 0x7F3C # 0 +0xC08F 0x7F3D # 0 +0xC090 0x7F3E # 0 +0xC091 0x7F3F # 0 +0xC092 0x7F40 # 0 +0xC093 0x7F41 # 0 +0xC094 0x7F43 # 0 +0xC095 0x7F46 # 0 +0xC096 0x7F47 # 0 +0xC097 0x7F48 # 0 +0xC098 0x7F49 # 0 +0xC099 0x7F4A # 0 +0xC09A 0x7F4B # 0 +0xC09B 0x7F4C # 0 +0xC09C 0x7F4D # 0 +0xC09D 0x7F4E # 0 +0xC09E 0x7F4F # 0 +0xC09F 0x7F52 # 0 +0xC0A0 0x7F53 # 0 +0xC0A1 0x9988 # 0 +0xC0A2 0x6127 # 0 +0xC0A3 0x6E83 # 0 +0xC0A4 0x5764 # 0 +0xC0A5 0x6606 # 0 +0xC0A6 0x6346 # 0 +0xC0A7 0x56F0 # 0 +0xC0A8 0x62EC # 0 +0xC0A9 0x6269 # 0 +0xC0AA 0x5ED3 # 0 +0xC0AB 0x9614 # 0 +0xC0AC 0x5783 # 0 +0xC0AD 0x62C9 # 0 +0xC0AE 0x5587 # 0 +0xC0AF 0x8721 # 0 +0xC0B0 0x814A # 0 +0xC0B1 0x8FA3 # 0 +0xC0B2 0x5566 # 0 +0xC0B3 0x83B1 # 0 +0xC0B4 0x6765 # 0 +0xC0B5 0x8D56 # 0 +0xC0B6 0x84DD # 0 +0xC0B7 0x5A6A # 0 +0xC0B8 0x680F # 0 +0xC0B9 0x62E6 # 0 +0xC0BA 0x7BEE # 0 +0xC0BB 0x9611 # 0 +0xC0BC 0x5170 # 0 +0xC0BD 0x6F9C # 0 +0xC0BE 0x8C30 # 0 +0xC0BF 0x63FD # 0 +0xC0C0 0x89C8 # 0 +0xC0C1 0x61D2 # 0 +0xC0C2 0x7F06 # 0 +0xC0C3 0x70C2 # 0 +0xC0C4 0x6EE5 # 0 +0xC0C5 0x7405 # 0 +0xC0C6 0x6994 # 0 +0xC0C7 0x72FC # 0 +0xC0C8 0x5ECA # 0 +0xC0C9 0x90CE # 0 +0xC0CA 0x6717 # 0 +0xC0CB 0x6D6A # 0 +0xC0CC 0x635E # 0 +0xC0CD 0x52B3 # 0 +0xC0CE 0x7262 # 0 +0xC0CF 0x8001 # 0 +0xC0D0 0x4F6C # 0 +0xC0D1 0x59E5 # 0 +0xC0D2 0x916A # 0 +0xC0D3 0x70D9 # 0 +0xC0D4 0x6D9D # 0 +0xC0D5 0x52D2 # 0 +0xC0D6 0x4E50 # 0 +0xC0D7 0x96F7 # 0 +0xC0D8 0x956D # 0 +0xC0D9 0x857E # 0 +0xC0DA 0x78CA # 0 +0xC0DB 0x7D2F # 0 +0xC0DC 0x5121 # 0 +0xC0DD 0x5792 # 0 +0xC0DE 0x64C2 # 0 +0xC0DF 0x808B # 0 +0xC0E0 0x7C7B # 0 +0xC0E1 0x6CEA # 0 +0xC0E2 0x68F1 # 0 +0xC0E3 0x695E # 0 +0xC0E4 0x51B7 # 0 +0xC0E5 0x5398 # 0 +0xC0E6 0x68A8 # 0 +0xC0E7 0x7281 # 0 +0xC0E8 0x9ECE # 0 +0xC0E9 0x7BF1 # 0 +0xC0EA 0x72F8 # 0 +0xC0EB 0x79BB # 0 +0xC0EC 0x6F13 # 0 +0xC0ED 0x7406 # 0 +0xC0EE 0x674E # 0 +0xC0EF 0x91CC # 0 +0xC0F0 0x9CA4 # 0 +0xC0F1 0x793C # 0 +0xC0F2 0x8389 # 0 +0xC0F3 0x8354 # 0 +0xC0F4 0x540F # 0 +0xC0F5 0x6817 # 0 +0xC0F6 0x4E3D # 0 +0xC0F7 0x5389 # 0 +0xC0F8 0x52B1 # 0 +0xC0F9 0x783E # 0 +0xC0FA 0x5386 # 0 +0xC0FB 0x5229 # 0 +0xC0FC 0x5088 # 0 +0xC0FD 0x4F8B # 0 +0xC0FE 0x4FD0 # 0 +0xC140 0x7F56 # 0 +0xC141 0x7F59 # 0 +0xC142 0x7F5B # 0 +0xC143 0x7F5C # 0 +0xC144 0x7F5D # 0 +0xC145 0x7F5E # 0 +0xC146 0x7F60 # 0 +0xC147 0x7F63 # 0 +0xC148 0x7F64 # 0 +0xC149 0x7F65 # 0 +0xC14A 0x7F66 # 0 +0xC14B 0x7F67 # 0 +0xC14C 0x7F6B # 0 +0xC14D 0x7F6C # 0 +0xC14E 0x7F6D # 0 +0xC14F 0x7F6F # 0 +0xC150 0x7F70 # 0 +0xC151 0x7F73 # 0 +0xC152 0x7F75 # 0 +0xC153 0x7F76 # 0 +0xC154 0x7F77 # 0 +0xC155 0x7F78 # 0 +0xC156 0x7F7A # 0 +0xC157 0x7F7B # 0 +0xC158 0x7F7C # 0 +0xC159 0x7F7D # 0 +0xC15A 0x7F7F # 0 +0xC15B 0x7F80 # 0 +0xC15C 0x7F82 # 0 +0xC15D 0x7F83 # 0 +0xC15E 0x7F84 # 0 +0xC15F 0x7F85 # 0 +0xC160 0x7F86 # 0 +0xC161 0x7F87 # 0 +0xC162 0x7F88 # 0 +0xC163 0x7F89 # 0 +0xC164 0x7F8B # 0 +0xC165 0x7F8D # 0 +0xC166 0x7F8F # 0 +0xC167 0x7F90 # 0 +0xC168 0x7F91 # 0 +0xC169 0x7F92 # 0 +0xC16A 0x7F93 # 0 +0xC16B 0x7F95 # 0 +0xC16C 0x7F96 # 0 +0xC16D 0x7F97 # 0 +0xC16E 0x7F98 # 0 +0xC16F 0x7F99 # 0 +0xC170 0x7F9B # 0 +0xC171 0x7F9C # 0 +0xC172 0x7FA0 # 0 +0xC173 0x7FA2 # 0 +0xC174 0x7FA3 # 0 +0xC175 0x7FA5 # 0 +0xC176 0x7FA6 # 0 +0xC177 0x7FA8 # 0 +0xC178 0x7FA9 # 0 +0xC179 0x7FAA # 0 +0xC17A 0x7FAB # 0 +0xC17B 0x7FAC # 0 +0xC17C 0x7FAD # 0 +0xC17D 0x7FAE # 0 +0xC17E 0x7FB1 # 0 +0xC180 0x7FB3 # 0 +0xC181 0x7FB4 # 0 +0xC182 0x7FB5 # 0 +0xC183 0x7FB6 # 0 +0xC184 0x7FB7 # 0 +0xC185 0x7FBA # 0 +0xC186 0x7FBB # 0 +0xC187 0x7FBE # 0 +0xC188 0x7FC0 # 0 +0xC189 0x7FC2 # 0 +0xC18A 0x7FC3 # 0 +0xC18B 0x7FC4 # 0 +0xC18C 0x7FC6 # 0 +0xC18D 0x7FC7 # 0 +0xC18E 0x7FC8 # 0 +0xC18F 0x7FC9 # 0 +0xC190 0x7FCB # 0 +0xC191 0x7FCD # 0 +0xC192 0x7FCF # 0 +0xC193 0x7FD0 # 0 +0xC194 0x7FD1 # 0 +0xC195 0x7FD2 # 0 +0xC196 0x7FD3 # 0 +0xC197 0x7FD6 # 0 +0xC198 0x7FD7 # 0 +0xC199 0x7FD9 # 0 +0xC19A 0x7FDA # 0 +0xC19B 0x7FDB # 0 +0xC19C 0x7FDC # 0 +0xC19D 0x7FDD # 0 +0xC19E 0x7FDE # 0 +0xC19F 0x7FE2 # 0 +0xC1A0 0x7FE3 # 0 +0xC1A1 0x75E2 # 0 +0xC1A2 0x7ACB # 0 +0xC1A3 0x7C92 # 0 +0xC1A4 0x6CA5 # 0 +0xC1A5 0x96B6 # 0 +0xC1A6 0x529B # 0 +0xC1A7 0x7483 # 0 +0xC1A8 0x54E9 # 0 +0xC1A9 0x4FE9 # 0 +0xC1AA 0x8054 # 0 +0xC1AB 0x83B2 # 0 +0xC1AC 0x8FDE # 0 +0xC1AD 0x9570 # 0 +0xC1AE 0x5EC9 # 0 +0xC1AF 0x601C # 0 +0xC1B0 0x6D9F # 0 +0xC1B1 0x5E18 # 0 +0xC1B2 0x655B # 0 +0xC1B3 0x8138 # 0 +0xC1B4 0x94FE # 0 +0xC1B5 0x604B # 0 +0xC1B6 0x70BC # 0 +0xC1B7 0x7EC3 # 0 +0xC1B8 0x7CAE # 0 +0xC1B9 0x51C9 # 0 +0xC1BA 0x6881 # 0 +0xC1BB 0x7CB1 # 0 +0xC1BC 0x826F # 0 +0xC1BD 0x4E24 # 0 +0xC1BE 0x8F86 # 0 +0xC1BF 0x91CF # 0 +0xC1C0 0x667E # 0 +0xC1C1 0x4EAE # 0 +0xC1C2 0x8C05 # 0 +0xC1C3 0x64A9 # 0 +0xC1C4 0x804A # 0 +0xC1C5 0x50DA # 0 +0xC1C6 0x7597 # 0 +0xC1C7 0x71CE # 0 +0xC1C8 0x5BE5 # 0 +0xC1C9 0x8FBD # 0 +0xC1CA 0x6F66 # 0 +0xC1CB 0x4E86 # 0 +0xC1CC 0x6482 # 0 +0xC1CD 0x9563 # 0 +0xC1CE 0x5ED6 # 0 +0xC1CF 0x6599 # 0 +0xC1D0 0x5217 # 0 +0xC1D1 0x88C2 # 0 +0xC1D2 0x70C8 # 0 +0xC1D3 0x52A3 # 0 +0xC1D4 0x730E # 0 +0xC1D5 0x7433 # 0 +0xC1D6 0x6797 # 0 +0xC1D7 0x78F7 # 0 +0xC1D8 0x9716 # 0 +0xC1D9 0x4E34 # 0 +0xC1DA 0x90BB # 0 +0xC1DB 0x9CDE # 0 +0xC1DC 0x6DCB # 0 +0xC1DD 0x51DB # 0 +0xC1DE 0x8D41 # 0 +0xC1DF 0x541D # 0 +0xC1E0 0x62CE # 0 +0xC1E1 0x73B2 # 0 +0xC1E2 0x83F1 # 0 +0xC1E3 0x96F6 # 0 +0xC1E4 0x9F84 # 0 +0xC1E5 0x94C3 # 0 +0xC1E6 0x4F36 # 0 +0xC1E7 0x7F9A # 0 +0xC1E8 0x51CC # 0 +0xC1E9 0x7075 # 0 +0xC1EA 0x9675 # 0 +0xC1EB 0x5CAD # 0 +0xC1EC 0x9886 # 0 +0xC1ED 0x53E6 # 0 +0xC1EE 0x4EE4 # 0 +0xC1EF 0x6E9C # 0 +0xC1F0 0x7409 # 0 +0xC1F1 0x69B4 # 0 +0xC1F2 0x786B # 0 +0xC1F3 0x998F # 0 +0xC1F4 0x7559 # 0 +0xC1F5 0x5218 # 0 +0xC1F6 0x7624 # 0 +0xC1F7 0x6D41 # 0 +0xC1F8 0x67F3 # 0 +0xC1F9 0x516D # 0 +0xC1FA 0x9F99 # 0 +0xC1FB 0x804B # 0 +0xC1FC 0x5499 # 0 +0xC1FD 0x7B3C # 0 +0xC1FE 0x7ABF # 0 +0xC240 0x7FE4 # 0 +0xC241 0x7FE7 # 0 +0xC242 0x7FE8 # 0 +0xC243 0x7FEA # 0 +0xC244 0x7FEB # 0 +0xC245 0x7FEC # 0 +0xC246 0x7FED # 0 +0xC247 0x7FEF # 0 +0xC248 0x7FF2 # 0 +0xC249 0x7FF4 # 0 +0xC24A 0x7FF5 # 0 +0xC24B 0x7FF6 # 0 +0xC24C 0x7FF7 # 0 +0xC24D 0x7FF8 # 0 +0xC24E 0x7FF9 # 0 +0xC24F 0x7FFA # 0 +0xC250 0x7FFD # 0 +0xC251 0x7FFE # 0 +0xC252 0x7FFF # 0 +0xC253 0x8002 # 0 +0xC254 0x8007 # 0 +0xC255 0x8008 # 0 +0xC256 0x8009 # 0 +0xC257 0x800A # 0 +0xC258 0x800E # 0 +0xC259 0x800F # 0 +0xC25A 0x8011 # 0 +0xC25B 0x8013 # 0 +0xC25C 0x801A # 0 +0xC25D 0x801B # 0 +0xC25E 0x801D # 0 +0xC25F 0x801E # 0 +0xC260 0x801F # 0 +0xC261 0x8021 # 0 +0xC262 0x8023 # 0 +0xC263 0x8024 # 0 +0xC264 0x802B # 0 +0xC265 0x802C # 0 +0xC266 0x802D # 0 +0xC267 0x802E # 0 +0xC268 0x802F # 0 +0xC269 0x8030 # 0 +0xC26A 0x8032 # 0 +0xC26B 0x8034 # 0 +0xC26C 0x8039 # 0 +0xC26D 0x803A # 0 +0xC26E 0x803C # 0 +0xC26F 0x803E # 0 +0xC270 0x8040 # 0 +0xC271 0x8041 # 0 +0xC272 0x8044 # 0 +0xC273 0x8045 # 0 +0xC274 0x8047 # 0 +0xC275 0x8048 # 0 +0xC276 0x8049 # 0 +0xC277 0x804E # 0 +0xC278 0x804F # 0 +0xC279 0x8050 # 0 +0xC27A 0x8051 # 0 +0xC27B 0x8053 # 0 +0xC27C 0x8055 # 0 +0xC27D 0x8056 # 0 +0xC27E 0x8057 # 0 +0xC280 0x8059 # 0 +0xC281 0x805B # 0 +0xC282 0x805C # 0 +0xC283 0x805D # 0 +0xC284 0x805E # 0 +0xC285 0x805F # 0 +0xC286 0x8060 # 0 +0xC287 0x8061 # 0 +0xC288 0x8062 # 0 +0xC289 0x8063 # 0 +0xC28A 0x8064 # 0 +0xC28B 0x8065 # 0 +0xC28C 0x8066 # 0 +0xC28D 0x8067 # 0 +0xC28E 0x8068 # 0 +0xC28F 0x806B # 0 +0xC290 0x806C # 0 +0xC291 0x806D # 0 +0xC292 0x806E # 0 +0xC293 0x806F # 0 +0xC294 0x8070 # 0 +0xC295 0x8072 # 0 +0xC296 0x8073 # 0 +0xC297 0x8074 # 0 +0xC298 0x8075 # 0 +0xC299 0x8076 # 0 +0xC29A 0x8077 # 0 +0xC29B 0x8078 # 0 +0xC29C 0x8079 # 0 +0xC29D 0x807A # 0 +0xC29E 0x807B # 0 +0xC29F 0x807C # 0 +0xC2A0 0x807D # 0 +0xC2A1 0x9686 # 0 +0xC2A2 0x5784 # 0 +0xC2A3 0x62E2 # 0 +0xC2A4 0x9647 # 0 +0xC2A5 0x697C # 0 +0xC2A6 0x5A04 # 0 +0xC2A7 0x6402 # 0 +0xC2A8 0x7BD3 # 0 +0xC2A9 0x6F0F # 0 +0xC2AA 0x964B # 0 +0xC2AB 0x82A6 # 0 +0xC2AC 0x5362 # 0 +0xC2AD 0x9885 # 0 +0xC2AE 0x5E90 # 0 +0xC2AF 0x7089 # 0 +0xC2B0 0x63B3 # 0 +0xC2B1 0x5364 # 0 +0xC2B2 0x864F # 0 +0xC2B3 0x9C81 # 0 +0xC2B4 0x9E93 # 0 +0xC2B5 0x788C # 0 +0xC2B6 0x9732 # 0 +0xC2B7 0x8DEF # 0 +0xC2B8 0x8D42 # 0 +0xC2B9 0x9E7F # 0 +0xC2BA 0x6F5E # 0 +0xC2BB 0x7984 # 0 +0xC2BC 0x5F55 # 0 +0xC2BD 0x9646 # 0 +0xC2BE 0x622E # 0 +0xC2BF 0x9A74 # 0 +0xC2C0 0x5415 # 0 +0xC2C1 0x94DD # 0 +0xC2C2 0x4FA3 # 0 +0xC2C3 0x65C5 # 0 +0xC2C4 0x5C65 # 0 +0xC2C5 0x5C61 # 0 +0xC2C6 0x7F15 # 0 +0xC2C7 0x8651 # 0 +0xC2C8 0x6C2F # 0 +0xC2C9 0x5F8B # 0 +0xC2CA 0x7387 # 0 +0xC2CB 0x6EE4 # 0 +0xC2CC 0x7EFF # 0 +0xC2CD 0x5CE6 # 0 +0xC2CE 0x631B # 0 +0xC2CF 0x5B6A # 0 +0xC2D0 0x6EE6 # 0 +0xC2D1 0x5375 # 0 +0xC2D2 0x4E71 # 0 +0xC2D3 0x63A0 # 0 +0xC2D4 0x7565 # 0 +0xC2D5 0x62A1 # 0 +0xC2D6 0x8F6E # 0 +0xC2D7 0x4F26 # 0 +0xC2D8 0x4ED1 # 0 +0xC2D9 0x6CA6 # 0 +0xC2DA 0x7EB6 # 0 +0xC2DB 0x8BBA # 0 +0xC2DC 0x841D # 0 +0xC2DD 0x87BA # 0 +0xC2DE 0x7F57 # 0 +0xC2DF 0x903B # 0 +0xC2E0 0x9523 # 0 +0xC2E1 0x7BA9 # 0 +0xC2E2 0x9AA1 # 0 +0xC2E3 0x88F8 # 0 +0xC2E4 0x843D # 0 +0xC2E5 0x6D1B # 0 +0xC2E6 0x9A86 # 0 +0xC2E7 0x7EDC # 0 +0xC2E8 0x5988 # 0 +0xC2E9 0x9EBB # 0 +0xC2EA 0x739B # 0 +0xC2EB 0x7801 # 0 +0xC2EC 0x8682 # 0 +0xC2ED 0x9A6C # 0 +0xC2EE 0x9A82 # 0 +0xC2EF 0x561B # 0 +0xC2F0 0x5417 # 0 +0xC2F1 0x57CB # 0 +0xC2F2 0x4E70 # 0 +0xC2F3 0x9EA6 # 0 +0xC2F4 0x5356 # 0 +0xC2F5 0x8FC8 # 0 +0xC2F6 0x8109 # 0 +0xC2F7 0x7792 # 0 +0xC2F8 0x9992 # 0 +0xC2F9 0x86EE # 0 +0xC2FA 0x6EE1 # 0 +0xC2FB 0x8513 # 0 +0xC2FC 0x66FC # 0 +0xC2FD 0x6162 # 0 +0xC2FE 0x6F2B # 0 +0xC340 0x807E # 0 +0xC341 0x8081 # 0 +0xC342 0x8082 # 0 +0xC343 0x8085 # 0 +0xC344 0x8088 # 0 +0xC345 0x808A # 0 +0xC346 0x808D # 0 +0xC347 0x808E # 0 +0xC348 0x808F # 0 +0xC349 0x8090 # 0 +0xC34A 0x8091 # 0 +0xC34B 0x8092 # 0 +0xC34C 0x8094 # 0 +0xC34D 0x8095 # 0 +0xC34E 0x8097 # 0 +0xC34F 0x8099 # 0 +0xC350 0x809E # 0 +0xC351 0x80A3 # 0 +0xC352 0x80A6 # 0 +0xC353 0x80A7 # 0 +0xC354 0x80A8 # 0 +0xC355 0x80AC # 0 +0xC356 0x80B0 # 0 +0xC357 0x80B3 # 0 +0xC358 0x80B5 # 0 +0xC359 0x80B6 # 0 +0xC35A 0x80B8 # 0 +0xC35B 0x80B9 # 0 +0xC35C 0x80BB # 0 +0xC35D 0x80C5 # 0 +0xC35E 0x80C7 # 0 +0xC35F 0x80C8 # 0 +0xC360 0x80C9 # 0 +0xC361 0x80CA # 0 +0xC362 0x80CB # 0 +0xC363 0x80CF # 0 +0xC364 0x80D0 # 0 +0xC365 0x80D1 # 0 +0xC366 0x80D2 # 0 +0xC367 0x80D3 # 0 +0xC368 0x80D4 # 0 +0xC369 0x80D5 # 0 +0xC36A 0x80D8 # 0 +0xC36B 0x80DF # 0 +0xC36C 0x80E0 # 0 +0xC36D 0x80E2 # 0 +0xC36E 0x80E3 # 0 +0xC36F 0x80E6 # 0 +0xC370 0x80EE # 0 +0xC371 0x80F5 # 0 +0xC372 0x80F7 # 0 +0xC373 0x80F9 # 0 +0xC374 0x80FB # 0 +0xC375 0x80FE # 0 +0xC376 0x80FF # 0 +0xC377 0x8100 # 0 +0xC378 0x8101 # 0 +0xC379 0x8103 # 0 +0xC37A 0x8104 # 0 +0xC37B 0x8105 # 0 +0xC37C 0x8107 # 0 +0xC37D 0x8108 # 0 +0xC37E 0x810B # 0 +0xC380 0x810C # 0 +0xC381 0x8115 # 0 +0xC382 0x8117 # 0 +0xC383 0x8119 # 0 +0xC384 0x811B # 0 +0xC385 0x811C # 0 +0xC386 0x811D # 0 +0xC387 0x811F # 0 +0xC388 0x8120 # 0 +0xC389 0x8121 # 0 +0xC38A 0x8122 # 0 +0xC38B 0x8123 # 0 +0xC38C 0x8124 # 0 +0xC38D 0x8125 # 0 +0xC38E 0x8126 # 0 +0xC38F 0x8127 # 0 +0xC390 0x8128 # 0 +0xC391 0x8129 # 0 +0xC392 0x812A # 0 +0xC393 0x812B # 0 +0xC394 0x812D # 0 +0xC395 0x812E # 0 +0xC396 0x8130 # 0 +0xC397 0x8133 # 0 +0xC398 0x8134 # 0 +0xC399 0x8135 # 0 +0xC39A 0x8137 # 0 +0xC39B 0x8139 # 0 +0xC39C 0x813A # 0 +0xC39D 0x813B # 0 +0xC39E 0x813C # 0 +0xC39F 0x813D # 0 +0xC3A0 0x813F # 0 +0xC3A1 0x8C29 # 0 +0xC3A2 0x8292 # 0 +0xC3A3 0x832B # 0 +0xC3A4 0x76F2 # 0 +0xC3A5 0x6C13 # 0 +0xC3A6 0x5FD9 # 0 +0xC3A7 0x83BD # 0 +0xC3A8 0x732B # 0 +0xC3A9 0x8305 # 0 +0xC3AA 0x951A # 0 +0xC3AB 0x6BDB # 0 +0xC3AC 0x77DB # 0 +0xC3AD 0x94C6 # 0 +0xC3AE 0x536F # 0 +0xC3AF 0x8302 # 0 +0xC3B0 0x5192 # 0 +0xC3B1 0x5E3D # 0 +0xC3B2 0x8C8C # 0 +0xC3B3 0x8D38 # 0 +0xC3B4 0x4E48 # 0 +0xC3B5 0x73AB # 0 +0xC3B6 0x679A # 0 +0xC3B7 0x6885 # 0 +0xC3B8 0x9176 # 0 +0xC3B9 0x9709 # 0 +0xC3BA 0x7164 # 0 +0xC3BB 0x6CA1 # 0 +0xC3BC 0x7709 # 0 +0xC3BD 0x5A92 # 0 +0xC3BE 0x9541 # 0 +0xC3BF 0x6BCF # 0 +0xC3C0 0x7F8E # 0 +0xC3C1 0x6627 # 0 +0xC3C2 0x5BD0 # 0 +0xC3C3 0x59B9 # 0 +0xC3C4 0x5A9A # 0 +0xC3C5 0x95E8 # 0 +0xC3C6 0x95F7 # 0 +0xC3C7 0x4EEC # 0 +0xC3C8 0x840C # 0 +0xC3C9 0x8499 # 0 +0xC3CA 0x6AAC # 0 +0xC3CB 0x76DF # 0 +0xC3CC 0x9530 # 0 +0xC3CD 0x731B # 0 +0xC3CE 0x68A6 # 0 +0xC3CF 0x5B5F # 0 +0xC3D0 0x772F # 0 +0xC3D1 0x919A # 0 +0xC3D2 0x9761 # 0 +0xC3D3 0x7CDC # 0 +0xC3D4 0x8FF7 # 0 +0xC3D5 0x8C1C # 0 +0xC3D6 0x5F25 # 0 +0xC3D7 0x7C73 # 0 +0xC3D8 0x79D8 # 0 +0xC3D9 0x89C5 # 0 +0xC3DA 0x6CCC # 0 +0xC3DB 0x871C # 0 +0xC3DC 0x5BC6 # 0 +0xC3DD 0x5E42 # 0 +0xC3DE 0x68C9 # 0 +0xC3DF 0x7720 # 0 +0xC3E0 0x7EF5 # 0 +0xC3E1 0x5195 # 0 +0xC3E2 0x514D # 0 +0xC3E3 0x52C9 # 0 +0xC3E4 0x5A29 # 0 +0xC3E5 0x7F05 # 0 +0xC3E6 0x9762 # 0 +0xC3E7 0x82D7 # 0 +0xC3E8 0x63CF # 0 +0xC3E9 0x7784 # 0 +0xC3EA 0x85D0 # 0 +0xC3EB 0x79D2 # 0 +0xC3EC 0x6E3A # 0 +0xC3ED 0x5E99 # 0 +0xC3EE 0x5999 # 0 +0xC3EF 0x8511 # 0 +0xC3F0 0x706D # 0 +0xC3F1 0x6C11 # 0 +0xC3F2 0x62BF # 0 +0xC3F3 0x76BF # 0 +0xC3F4 0x654F # 0 +0xC3F5 0x60AF # 0 +0xC3F6 0x95FD # 0 +0xC3F7 0x660E # 0 +0xC3F8 0x879F # 0 +0xC3F9 0x9E23 # 0 +0xC3FA 0x94ED # 0 +0xC3FB 0x540D # 0 +0xC3FC 0x547D # 0 +0xC3FD 0x8C2C # 0 +0xC3FE 0x6478 # 0 +0xC440 0x8140 # 0 +0xC441 0x8141 # 0 +0xC442 0x8142 # 0 +0xC443 0x8143 # 0 +0xC444 0x8144 # 0 +0xC445 0x8145 # 0 +0xC446 0x8147 # 0 +0xC447 0x8149 # 0 +0xC448 0x814D # 0 +0xC449 0x814E # 0 +0xC44A 0x814F # 0 +0xC44B 0x8152 # 0 +0xC44C 0x8156 # 0 +0xC44D 0x8157 # 0 +0xC44E 0x8158 # 0 +0xC44F 0x815B # 0 +0xC450 0x815C # 0 +0xC451 0x815D # 0 +0xC452 0x815E # 0 +0xC453 0x815F # 0 +0xC454 0x8161 # 0 +0xC455 0x8162 # 0 +0xC456 0x8163 # 0 +0xC457 0x8164 # 0 +0xC458 0x8166 # 0 +0xC459 0x8168 # 0 +0xC45A 0x816A # 0 +0xC45B 0x816B # 0 +0xC45C 0x816C # 0 +0xC45D 0x816F # 0 +0xC45E 0x8172 # 0 +0xC45F 0x8173 # 0 +0xC460 0x8175 # 0 +0xC461 0x8176 # 0 +0xC462 0x8177 # 0 +0xC463 0x8178 # 0 +0xC464 0x8181 # 0 +0xC465 0x8183 # 0 +0xC466 0x8184 # 0 +0xC467 0x8185 # 0 +0xC468 0x8186 # 0 +0xC469 0x8187 # 0 +0xC46A 0x8189 # 0 +0xC46B 0x818B # 0 +0xC46C 0x818C # 0 +0xC46D 0x818D # 0 +0xC46E 0x818E # 0 +0xC46F 0x8190 # 0 +0xC470 0x8192 # 0 +0xC471 0x8193 # 0 +0xC472 0x8194 # 0 +0xC473 0x8195 # 0 +0xC474 0x8196 # 0 +0xC475 0x8197 # 0 +0xC476 0x8199 # 0 +0xC477 0x819A # 0 +0xC478 0x819E # 0 +0xC479 0x819F # 0 +0xC47A 0x81A0 # 0 +0xC47B 0x81A1 # 0 +0xC47C 0x81A2 # 0 +0xC47D 0x81A4 # 0 +0xC47E 0x81A5 # 0 +0xC480 0x81A7 # 0 +0xC481 0x81A9 # 0 +0xC482 0x81AB # 0 +0xC483 0x81AC # 0 +0xC484 0x81AD # 0 +0xC485 0x81AE # 0 +0xC486 0x81AF # 0 +0xC487 0x81B0 # 0 +0xC488 0x81B1 # 0 +0xC489 0x81B2 # 0 +0xC48A 0x81B4 # 0 +0xC48B 0x81B5 # 0 +0xC48C 0x81B6 # 0 +0xC48D 0x81B7 # 0 +0xC48E 0x81B8 # 0 +0xC48F 0x81B9 # 0 +0xC490 0x81BC # 0 +0xC491 0x81BD # 0 +0xC492 0x81BE # 0 +0xC493 0x81BF # 0 +0xC494 0x81C4 # 0 +0xC495 0x81C5 # 0 +0xC496 0x81C7 # 0 +0xC497 0x81C8 # 0 +0xC498 0x81C9 # 0 +0xC499 0x81CB # 0 +0xC49A 0x81CD # 0 +0xC49B 0x81CE # 0 +0xC49C 0x81CF # 0 +0xC49D 0x81D0 # 0 +0xC49E 0x81D1 # 0 +0xC49F 0x81D2 # 0 +0xC4A0 0x81D3 # 0 +0xC4A1 0x6479 # 0 +0xC4A2 0x8611 # 0 +0xC4A3 0x6A21 # 0 +0xC4A4 0x819C # 0 +0xC4A5 0x78E8 # 0 +0xC4A6 0x6469 # 0 +0xC4A7 0x9B54 # 0 +0xC4A8 0x62B9 # 0 +0xC4A9 0x672B # 0 +0xC4AA 0x83AB # 0 +0xC4AB 0x58A8 # 0 +0xC4AC 0x9ED8 # 0 +0xC4AD 0x6CAB # 0 +0xC4AE 0x6F20 # 0 +0xC4AF 0x5BDE # 0 +0xC4B0 0x964C # 0 +0xC4B1 0x8C0B # 0 +0xC4B2 0x725F # 0 +0xC4B3 0x67D0 # 0 +0xC4B4 0x62C7 # 0 +0xC4B5 0x7261 # 0 +0xC4B6 0x4EA9 # 0 +0xC4B7 0x59C6 # 0 +0xC4B8 0x6BCD # 0 +0xC4B9 0x5893 # 0 +0xC4BA 0x66AE # 0 +0xC4BB 0x5E55 # 0 +0xC4BC 0x52DF # 0 +0xC4BD 0x6155 # 0 +0xC4BE 0x6728 # 0 +0xC4BF 0x76EE # 0 +0xC4C0 0x7766 # 0 +0xC4C1 0x7267 # 0 +0xC4C2 0x7A46 # 0 +0xC4C3 0x62FF # 0 +0xC4C4 0x54EA # 0 +0xC4C5 0x5450 # 0 +0xC4C6 0x94A0 # 0 +0xC4C7 0x90A3 # 0 +0xC4C8 0x5A1C # 0 +0xC4C9 0x7EB3 # 0 +0xC4CA 0x6C16 # 0 +0xC4CB 0x4E43 # 0 +0xC4CC 0x5976 # 0 +0xC4CD 0x8010 # 0 +0xC4CE 0x5948 # 0 +0xC4CF 0x5357 # 0 +0xC4D0 0x7537 # 0 +0xC4D1 0x96BE # 0 +0xC4D2 0x56CA # 0 +0xC4D3 0x6320 # 0 +0xC4D4 0x8111 # 0 +0xC4D5 0x607C # 0 +0xC4D6 0x95F9 # 0 +0xC4D7 0x6DD6 # 0 +0xC4D8 0x5462 # 0 +0xC4D9 0x9981 # 0 +0xC4DA 0x5185 # 0 +0xC4DB 0x5AE9 # 0 +0xC4DC 0x80FD # 0 +0xC4DD 0x59AE # 0 +0xC4DE 0x9713 # 0 +0xC4DF 0x502A # 0 +0xC4E0 0x6CE5 # 0 +0xC4E1 0x5C3C # 0 +0xC4E2 0x62DF # 0 +0xC4E3 0x4F60 # 0 +0xC4E4 0x533F # 0 +0xC4E5 0x817B # 0 +0xC4E6 0x9006 # 0 +0xC4E7 0x6EBA # 0 +0xC4E8 0x852B # 0 +0xC4E9 0x62C8 # 0 +0xC4EA 0x5E74 # 0 +0xC4EB 0x78BE # 0 +0xC4EC 0x64B5 # 0 +0xC4ED 0x637B # 0 +0xC4EE 0x5FF5 # 0 +0xC4EF 0x5A18 # 0 +0xC4F0 0x917F # 0 +0xC4F1 0x9E1F # 0 +0xC4F2 0x5C3F # 0 +0xC4F3 0x634F # 0 +0xC4F4 0x8042 # 0 +0xC4F5 0x5B7D # 0 +0xC4F6 0x556E # 0 +0xC4F7 0x954A # 0 +0xC4F8 0x954D # 0 +0xC4F9 0x6D85 # 0 +0xC4FA 0x60A8 # 0 +0xC4FB 0x67E0 # 0 +0xC4FC 0x72DE # 0 +0xC4FD 0x51DD # 0 +0xC4FE 0x5B81 # 0 +0xC540 0x81D4 # 0 +0xC541 0x81D5 # 0 +0xC542 0x81D6 # 0 +0xC543 0x81D7 # 0 +0xC544 0x81D8 # 0 +0xC545 0x81D9 # 0 +0xC546 0x81DA # 0 +0xC547 0x81DB # 0 +0xC548 0x81DC # 0 +0xC549 0x81DD # 0 +0xC54A 0x81DE # 0 +0xC54B 0x81DF # 0 +0xC54C 0x81E0 # 0 +0xC54D 0x81E1 # 0 +0xC54E 0x81E2 # 0 +0xC54F 0x81E4 # 0 +0xC550 0x81E5 # 0 +0xC551 0x81E6 # 0 +0xC552 0x81E8 # 0 +0xC553 0x81E9 # 0 +0xC554 0x81EB # 0 +0xC555 0x81EE # 0 +0xC556 0x81EF # 0 +0xC557 0x81F0 # 0 +0xC558 0x81F1 # 0 +0xC559 0x81F2 # 0 +0xC55A 0x81F5 # 0 +0xC55B 0x81F6 # 0 +0xC55C 0x81F7 # 0 +0xC55D 0x81F8 # 0 +0xC55E 0x81F9 # 0 +0xC55F 0x81FA # 0 +0xC560 0x81FD # 0 +0xC561 0x81FF # 0 +0xC562 0x8203 # 0 +0xC563 0x8207 # 0 +0xC564 0x8208 # 0 +0xC565 0x8209 # 0 +0xC566 0x820A # 0 +0xC567 0x820B # 0 +0xC568 0x820E # 0 +0xC569 0x820F # 0 +0xC56A 0x8211 # 0 +0xC56B 0x8213 # 0 +0xC56C 0x8215 # 0 +0xC56D 0x8216 # 0 +0xC56E 0x8217 # 0 +0xC56F 0x8218 # 0 +0xC570 0x8219 # 0 +0xC571 0x821A # 0 +0xC572 0x821D # 0 +0xC573 0x8220 # 0 +0xC574 0x8224 # 0 +0xC575 0x8225 # 0 +0xC576 0x8226 # 0 +0xC577 0x8227 # 0 +0xC578 0x8229 # 0 +0xC579 0x822E # 0 +0xC57A 0x8232 # 0 +0xC57B 0x823A # 0 +0xC57C 0x823C # 0 +0xC57D 0x823D # 0 +0xC57E 0x823F # 0 +0xC580 0x8240 # 0 +0xC581 0x8241 # 0 +0xC582 0x8242 # 0 +0xC583 0x8243 # 0 +0xC584 0x8245 # 0 +0xC585 0x8246 # 0 +0xC586 0x8248 # 0 +0xC587 0x824A # 0 +0xC588 0x824C # 0 +0xC589 0x824D # 0 +0xC58A 0x824E # 0 +0xC58B 0x8250 # 0 +0xC58C 0x8251 # 0 +0xC58D 0x8252 # 0 +0xC58E 0x8253 # 0 +0xC58F 0x8254 # 0 +0xC590 0x8255 # 0 +0xC591 0x8256 # 0 +0xC592 0x8257 # 0 +0xC593 0x8259 # 0 +0xC594 0x825B # 0 +0xC595 0x825C # 0 +0xC596 0x825D # 0 +0xC597 0x825E # 0 +0xC598 0x8260 # 0 +0xC599 0x8261 # 0 +0xC59A 0x8262 # 0 +0xC59B 0x8263 # 0 +0xC59C 0x8264 # 0 +0xC59D 0x8265 # 0 +0xC59E 0x8266 # 0 +0xC59F 0x8267 # 0 +0xC5A0 0x8269 # 0 +0xC5A1 0x62E7 # 0 +0xC5A2 0x6CDE # 0 +0xC5A3 0x725B # 0 +0xC5A4 0x626D # 0 +0xC5A5 0x94AE # 0 +0xC5A6 0x7EBD # 0 +0xC5A7 0x8113 # 0 +0xC5A8 0x6D53 # 0 +0xC5A9 0x519C # 0 +0xC5AA 0x5F04 # 0 +0xC5AB 0x5974 # 0 +0xC5AC 0x52AA # 0 +0xC5AD 0x6012 # 0 +0xC5AE 0x5973 # 0 +0xC5AF 0x6696 # 0 +0xC5B0 0x8650 # 0 +0xC5B1 0x759F # 0 +0xC5B2 0x632A # 0 +0xC5B3 0x61E6 # 0 +0xC5B4 0x7CEF # 0 +0xC5B5 0x8BFA # 0 +0xC5B6 0x54E6 # 0 +0xC5B7 0x6B27 # 0 +0xC5B8 0x9E25 # 0 +0xC5B9 0x6BB4 # 0 +0xC5BA 0x85D5 # 0 +0xC5BB 0x5455 # 0 +0xC5BC 0x5076 # 0 +0xC5BD 0x6CA4 # 0 +0xC5BE 0x556A # 0 +0xC5BF 0x8DB4 # 0 +0xC5C0 0x722C # 0 +0xC5C1 0x5E15 # 0 +0xC5C2 0x6015 # 0 +0xC5C3 0x7436 # 0 +0xC5C4 0x62CD # 0 +0xC5C5 0x6392 # 0 +0xC5C6 0x724C # 0 +0xC5C7 0x5F98 # 0 +0xC5C8 0x6E43 # 0 +0xC5C9 0x6D3E # 0 +0xC5CA 0x6500 # 0 +0xC5CB 0x6F58 # 0 +0xC5CC 0x76D8 # 0 +0xC5CD 0x78D0 # 0 +0xC5CE 0x76FC # 0 +0xC5CF 0x7554 # 0 +0xC5D0 0x5224 # 0 +0xC5D1 0x53DB # 0 +0xC5D2 0x4E53 # 0 +0xC5D3 0x5E9E # 0 +0xC5D4 0x65C1 # 0 +0xC5D5 0x802A # 0 +0xC5D6 0x80D6 # 0 +0xC5D7 0x629B # 0 +0xC5D8 0x5486 # 0 +0xC5D9 0x5228 # 0 +0xC5DA 0x70AE # 0 +0xC5DB 0x888D # 0 +0xC5DC 0x8DD1 # 0 +0xC5DD 0x6CE1 # 0 +0xC5DE 0x5478 # 0 +0xC5DF 0x80DA # 0 +0xC5E0 0x57F9 # 0 +0xC5E1 0x88F4 # 0 +0xC5E2 0x8D54 # 0 +0xC5E3 0x966A # 0 +0xC5E4 0x914D # 0 +0xC5E5 0x4F69 # 0 +0xC5E6 0x6C9B # 0 +0xC5E7 0x55B7 # 0 +0xC5E8 0x76C6 # 0 +0xC5E9 0x7830 # 0 +0xC5EA 0x62A8 # 0 +0xC5EB 0x70F9 # 0 +0xC5EC 0x6F8E # 0 +0xC5ED 0x5F6D # 0 +0xC5EE 0x84EC # 0 +0xC5EF 0x68DA # 0 +0xC5F0 0x787C # 0 +0xC5F1 0x7BF7 # 0 +0xC5F2 0x81A8 # 0 +0xC5F3 0x670B # 0 +0xC5F4 0x9E4F # 0 +0xC5F5 0x6367 # 0 +0xC5F6 0x78B0 # 0 +0xC5F7 0x576F # 0 +0xC5F8 0x7812 # 0 +0xC5F9 0x9739 # 0 +0xC5FA 0x6279 # 0 +0xC5FB 0x62AB # 0 +0xC5FC 0x5288 # 0 +0xC5FD 0x7435 # 0 +0xC5FE 0x6BD7 # 0 +0xC640 0x826A # 0 +0xC641 0x826B # 0 +0xC642 0x826C # 0 +0xC643 0x826D # 0 +0xC644 0x8271 # 0 +0xC645 0x8275 # 0 +0xC646 0x8276 # 0 +0xC647 0x8277 # 0 +0xC648 0x8278 # 0 +0xC649 0x827B # 0 +0xC64A 0x827C # 0 +0xC64B 0x8280 # 0 +0xC64C 0x8281 # 0 +0xC64D 0x8283 # 0 +0xC64E 0x8285 # 0 +0xC64F 0x8286 # 0 +0xC650 0x8287 # 0 +0xC651 0x8289 # 0 +0xC652 0x828C # 0 +0xC653 0x8290 # 0 +0xC654 0x8293 # 0 +0xC655 0x8294 # 0 +0xC656 0x8295 # 0 +0xC657 0x8296 # 0 +0xC658 0x829A # 0 +0xC659 0x829B # 0 +0xC65A 0x829E # 0 +0xC65B 0x82A0 # 0 +0xC65C 0x82A2 # 0 +0xC65D 0x82A3 # 0 +0xC65E 0x82A7 # 0 +0xC65F 0x82B2 # 0 +0xC660 0x82B5 # 0 +0xC661 0x82B6 # 0 +0xC662 0x82BA # 0 +0xC663 0x82BB # 0 +0xC664 0x82BC # 0 +0xC665 0x82BF # 0 +0xC666 0x82C0 # 0 +0xC667 0x82C2 # 0 +0xC668 0x82C3 # 0 +0xC669 0x82C5 # 0 +0xC66A 0x82C6 # 0 +0xC66B 0x82C9 # 0 +0xC66C 0x82D0 # 0 +0xC66D 0x82D6 # 0 +0xC66E 0x82D9 # 0 +0xC66F 0x82DA # 0 +0xC670 0x82DD # 0 +0xC671 0x82E2 # 0 +0xC672 0x82E7 # 0 +0xC673 0x82E8 # 0 +0xC674 0x82E9 # 0 +0xC675 0x82EA # 0 +0xC676 0x82EC # 0 +0xC677 0x82ED # 0 +0xC678 0x82EE # 0 +0xC679 0x82F0 # 0 +0xC67A 0x82F2 # 0 +0xC67B 0x82F3 # 0 +0xC67C 0x82F5 # 0 +0xC67D 0x82F6 # 0 +0xC67E 0x82F8 # 0 +0xC680 0x82FA # 0 +0xC681 0x82FC # 0 +0xC682 0x82FD # 0 +0xC683 0x82FE # 0 +0xC684 0x82FF # 0 +0xC685 0x8300 # 0 +0xC686 0x830A # 0 +0xC687 0x830B # 0 +0xC688 0x830D # 0 +0xC689 0x8310 # 0 +0xC68A 0x8312 # 0 +0xC68B 0x8313 # 0 +0xC68C 0x8316 # 0 +0xC68D 0x8318 # 0 +0xC68E 0x8319 # 0 +0xC68F 0x831D # 0 +0xC690 0x831E # 0 +0xC691 0x831F # 0 +0xC692 0x8320 # 0 +0xC693 0x8321 # 0 +0xC694 0x8322 # 0 +0xC695 0x8323 # 0 +0xC696 0x8324 # 0 +0xC697 0x8325 # 0 +0xC698 0x8326 # 0 +0xC699 0x8329 # 0 +0xC69A 0x832A # 0 +0xC69B 0x832E # 0 +0xC69C 0x8330 # 0 +0xC69D 0x8332 # 0 +0xC69E 0x8337 # 0 +0xC69F 0x833B # 0 +0xC6A0 0x833D # 0 +0xC6A1 0x5564 # 0 +0xC6A2 0x813E # 0 +0xC6A3 0x75B2 # 0 +0xC6A4 0x76AE # 0 +0xC6A5 0x5339 # 0 +0xC6A6 0x75DE # 0 +0xC6A7 0x50FB # 0 +0xC6A8 0x5C41 # 0 +0xC6A9 0x8B6C # 0 +0xC6AA 0x7BC7 # 0 +0xC6AB 0x504F # 0 +0xC6AC 0x7247 # 0 +0xC6AD 0x9A97 # 0 +0xC6AE 0x98D8 # 0 +0xC6AF 0x6F02 # 0 +0xC6B0 0x74E2 # 0 +0xC6B1 0x7968 # 0 +0xC6B2 0x6487 # 0 +0xC6B3 0x77A5 # 0 +0xC6B4 0x62FC # 0 +0xC6B5 0x9891 # 0 +0xC6B6 0x8D2B # 0 +0xC6B7 0x54C1 # 0 +0xC6B8 0x8058 # 0 +0xC6B9 0x4E52 # 0 +0xC6BA 0x576A # 0 +0xC6BB 0x82F9 # 0 +0xC6BC 0x840D # 0 +0xC6BD 0x5E73 # 0 +0xC6BE 0x51ED # 0 +0xC6BF 0x74F6 # 0 +0xC6C0 0x8BC4 # 0 +0xC6C1 0x5C4F # 0 +0xC6C2 0x5761 # 0 +0xC6C3 0x6CFC # 0 +0xC6C4 0x9887 # 0 +0xC6C5 0x5A46 # 0 +0xC6C6 0x7834 # 0 +0xC6C7 0x9B44 # 0 +0xC6C8 0x8FEB # 0 +0xC6C9 0x7C95 # 0 +0xC6CA 0x5256 # 0 +0xC6CB 0x6251 # 0 +0xC6CC 0x94FA # 0 +0xC6CD 0x4EC6 # 0 +0xC6CE 0x8386 # 0 +0xC6CF 0x8461 # 0 +0xC6D0 0x83E9 # 0 +0xC6D1 0x84B2 # 0 +0xC6D2 0x57D4 # 0 +0xC6D3 0x6734 # 0 +0xC6D4 0x5703 # 0 +0xC6D5 0x666E # 0 +0xC6D6 0x6D66 # 0 +0xC6D7 0x8C31 # 0 +0xC6D8 0x66DD # 0 +0xC6D9 0x7011 # 0 +0xC6DA 0x671F # 0 +0xC6DB 0x6B3A # 0 +0xC6DC 0x6816 # 0 +0xC6DD 0x621A # 0 +0xC6DE 0x59BB # 0 +0xC6DF 0x4E03 # 0 +0xC6E0 0x51C4 # 0 +0xC6E1 0x6F06 # 0 +0xC6E2 0x67D2 # 0 +0xC6E3 0x6C8F # 0 +0xC6E4 0x5176 # 0 +0xC6E5 0x68CB # 0 +0xC6E6 0x5947 # 0 +0xC6E7 0x6B67 # 0 +0xC6E8 0x7566 # 0 +0xC6E9 0x5D0E # 0 +0xC6EA 0x8110 # 0 +0xC6EB 0x9F50 # 0 +0xC6EC 0x65D7 # 0 +0xC6ED 0x7948 # 0 +0xC6EE 0x7941 # 0 +0xC6EF 0x9A91 # 0 +0xC6F0 0x8D77 # 0 +0xC6F1 0x5C82 # 0 +0xC6F2 0x4E5E # 0 +0xC6F3 0x4F01 # 0 +0xC6F4 0x542F # 0 +0xC6F5 0x5951 # 0 +0xC6F6 0x780C # 0 +0xC6F7 0x5668 # 0 +0xC6F8 0x6C14 # 0 +0xC6F9 0x8FC4 # 0 +0xC6FA 0x5F03 # 0 +0xC6FB 0x6C7D # 0 +0xC6FC 0x6CE3 # 0 +0xC6FD 0x8BAB # 0 +0xC6FE 0x6390 # 0 +0xC740 0x833E # 0 +0xC741 0x833F # 0 +0xC742 0x8341 # 0 +0xC743 0x8342 # 0 +0xC744 0x8344 # 0 +0xC745 0x8345 # 0 +0xC746 0x8348 # 0 +0xC747 0x834A # 0 +0xC748 0x834B # 0 +0xC749 0x834C # 0 +0xC74A 0x834D # 0 +0xC74B 0x834E # 0 +0xC74C 0x8353 # 0 +0xC74D 0x8355 # 0 +0xC74E 0x8356 # 0 +0xC74F 0x8357 # 0 +0xC750 0x8358 # 0 +0xC751 0x8359 # 0 +0xC752 0x835D # 0 +0xC753 0x8362 # 0 +0xC754 0x8370 # 0 +0xC755 0x8371 # 0 +0xC756 0x8372 # 0 +0xC757 0x8373 # 0 +0xC758 0x8374 # 0 +0xC759 0x8375 # 0 +0xC75A 0x8376 # 0 +0xC75B 0x8379 # 0 +0xC75C 0x837A # 0 +0xC75D 0x837E # 0 +0xC75E 0x837F # 0 +0xC75F 0x8380 # 0 +0xC760 0x8381 # 0 +0xC761 0x8382 # 0 +0xC762 0x8383 # 0 +0xC763 0x8384 # 0 +0xC764 0x8387 # 0 +0xC765 0x8388 # 0 +0xC766 0x838A # 0 +0xC767 0x838B # 0 +0xC768 0x838C # 0 +0xC769 0x838D # 0 +0xC76A 0x838F # 0 +0xC76B 0x8390 # 0 +0xC76C 0x8391 # 0 +0xC76D 0x8394 # 0 +0xC76E 0x8395 # 0 +0xC76F 0x8396 # 0 +0xC770 0x8397 # 0 +0xC771 0x8399 # 0 +0xC772 0x839A # 0 +0xC773 0x839D # 0 +0xC774 0x839F # 0 +0xC775 0x83A1 # 0 +0xC776 0x83A2 # 0 +0xC777 0x83A3 # 0 +0xC778 0x83A4 # 0 +0xC779 0x83A5 # 0 +0xC77A 0x83A6 # 0 +0xC77B 0x83A7 # 0 +0xC77C 0x83AC # 0 +0xC77D 0x83AD # 0 +0xC77E 0x83AE # 0 +0xC780 0x83AF # 0 +0xC781 0x83B5 # 0 +0xC782 0x83BB # 0 +0xC783 0x83BE # 0 +0xC784 0x83BF # 0 +0xC785 0x83C2 # 0 +0xC786 0x83C3 # 0 +0xC787 0x83C4 # 0 +0xC788 0x83C6 # 0 +0xC789 0x83C8 # 0 +0xC78A 0x83C9 # 0 +0xC78B 0x83CB # 0 +0xC78C 0x83CD # 0 +0xC78D 0x83CE # 0 +0xC78E 0x83D0 # 0 +0xC78F 0x83D1 # 0 +0xC790 0x83D2 # 0 +0xC791 0x83D3 # 0 +0xC792 0x83D5 # 0 +0xC793 0x83D7 # 0 +0xC794 0x83D9 # 0 +0xC795 0x83DA # 0 +0xC796 0x83DB # 0 +0xC797 0x83DE # 0 +0xC798 0x83E2 # 0 +0xC799 0x83E3 # 0 +0xC79A 0x83E4 # 0 +0xC79B 0x83E6 # 0 +0xC79C 0x83E7 # 0 +0xC79D 0x83E8 # 0 +0xC79E 0x83EB # 0 +0xC79F 0x83EC # 0 +0xC7A0 0x83ED # 0 +0xC7A1 0x6070 # 0 +0xC7A2 0x6D3D # 0 +0xC7A3 0x7275 # 0 +0xC7A4 0x6266 # 0 +0xC7A5 0x948E # 0 +0xC7A6 0x94C5 # 0 +0xC7A7 0x5343 # 0 +0xC7A8 0x8FC1 # 0 +0xC7A9 0x7B7E # 0 +0xC7AA 0x4EDF # 0 +0xC7AB 0x8C26 # 0 +0xC7AC 0x4E7E # 0 +0xC7AD 0x9ED4 # 0 +0xC7AE 0x94B1 # 0 +0xC7AF 0x94B3 # 0 +0xC7B0 0x524D # 0 +0xC7B1 0x6F5C # 0 +0xC7B2 0x9063 # 0 +0xC7B3 0x6D45 # 0 +0xC7B4 0x8C34 # 0 +0xC7B5 0x5811 # 0 +0xC7B6 0x5D4C # 0 +0xC7B7 0x6B20 # 0 +0xC7B8 0x6B49 # 0 +0xC7B9 0x67AA # 0 +0xC7BA 0x545B # 0 +0xC7BB 0x8154 # 0 +0xC7BC 0x7F8C # 0 +0xC7BD 0x5899 # 0 +0xC7BE 0x8537 # 0 +0xC7BF 0x5F3A # 0 +0xC7C0 0x62A2 # 0 +0xC7C1 0x6A47 # 0 +0xC7C2 0x9539 # 0 +0xC7C3 0x6572 # 0 +0xC7C4 0x6084 # 0 +0xC7C5 0x6865 # 0 +0xC7C6 0x77A7 # 0 +0xC7C7 0x4E54 # 0 +0xC7C8 0x4FA8 # 0 +0xC7C9 0x5DE7 # 0 +0xC7CA 0x9798 # 0 +0xC7CB 0x64AC # 0 +0xC7CC 0x7FD8 # 0 +0xC7CD 0x5CED # 0 +0xC7CE 0x4FCF # 0 +0xC7CF 0x7A8D # 0 +0xC7D0 0x5207 # 0 +0xC7D1 0x8304 # 0 +0xC7D2 0x4E14 # 0 +0xC7D3 0x602F # 0 +0xC7D4 0x7A83 # 0 +0xC7D5 0x94A6 # 0 +0xC7D6 0x4FB5 # 0 +0xC7D7 0x4EB2 # 0 +0xC7D8 0x79E6 # 0 +0xC7D9 0x7434 # 0 +0xC7DA 0x52E4 # 0 +0xC7DB 0x82B9 # 0 +0xC7DC 0x64D2 # 0 +0xC7DD 0x79BD # 0 +0xC7DE 0x5BDD # 0 +0xC7DF 0x6C81 # 0 +0xC7E0 0x9752 # 0 +0xC7E1 0x8F7B # 0 +0xC7E2 0x6C22 # 0 +0xC7E3 0x503E # 0 +0xC7E4 0x537F # 0 +0xC7E5 0x6E05 # 0 +0xC7E6 0x64CE # 0 +0xC7E7 0x6674 # 0 +0xC7E8 0x6C30 # 0 +0xC7E9 0x60C5 # 0 +0xC7EA 0x9877 # 0 +0xC7EB 0x8BF7 # 0 +0xC7EC 0x5E86 # 0 +0xC7ED 0x743C # 0 +0xC7EE 0x7A77 # 0 +0xC7EF 0x79CB # 0 +0xC7F0 0x4E18 # 0 +0xC7F1 0x90B1 # 0 +0xC7F2 0x7403 # 0 +0xC7F3 0x6C42 # 0 +0xC7F4 0x56DA # 0 +0xC7F5 0x914B # 0 +0xC7F6 0x6CC5 # 0 +0xC7F7 0x8D8B # 0 +0xC7F8 0x533A # 0 +0xC7F9 0x86C6 # 0 +0xC7FA 0x66F2 # 0 +0xC7FB 0x8EAF # 0 +0xC7FC 0x5C48 # 0 +0xC7FD 0x9A71 # 0 +0xC7FE 0x6E20 # 0 +0xC840 0x83EE # 0 +0xC841 0x83EF # 0 +0xC842 0x83F3 # 0 +0xC843 0x83F4 # 0 +0xC844 0x83F5 # 0 +0xC845 0x83F6 # 0 +0xC846 0x83F7 # 0 +0xC847 0x83FA # 0 +0xC848 0x83FB # 0 +0xC849 0x83FC # 0 +0xC84A 0x83FE # 0 +0xC84B 0x83FF # 0 +0xC84C 0x8400 # 0 +0xC84D 0x8402 # 0 +0xC84E 0x8405 # 0 +0xC84F 0x8407 # 0 +0xC850 0x8408 # 0 +0xC851 0x8409 # 0 +0xC852 0x840A # 0 +0xC853 0x8410 # 0 +0xC854 0x8412 # 0 +0xC855 0x8413 # 0 +0xC856 0x8414 # 0 +0xC857 0x8415 # 0 +0xC858 0x8416 # 0 +0xC859 0x8417 # 0 +0xC85A 0x8419 # 0 +0xC85B 0x841A # 0 +0xC85C 0x841B # 0 +0xC85D 0x841E # 0 +0xC85E 0x841F # 0 +0xC85F 0x8420 # 0 +0xC860 0x8421 # 0 +0xC861 0x8422 # 0 +0xC862 0x8423 # 0 +0xC863 0x8429 # 0 +0xC864 0x842A # 0 +0xC865 0x842B # 0 +0xC866 0x842C # 0 +0xC867 0x842D # 0 +0xC868 0x842E # 0 +0xC869 0x842F # 0 +0xC86A 0x8430 # 0 +0xC86B 0x8432 # 0 +0xC86C 0x8433 # 0 +0xC86D 0x8434 # 0 +0xC86E 0x8435 # 0 +0xC86F 0x8436 # 0 +0xC870 0x8437 # 0 +0xC871 0x8439 # 0 +0xC872 0x843A # 0 +0xC873 0x843B # 0 +0xC874 0x843E # 0 +0xC875 0x843F # 0 +0xC876 0x8440 # 0 +0xC877 0x8441 # 0 +0xC878 0x8442 # 0 +0xC879 0x8443 # 0 +0xC87A 0x8444 # 0 +0xC87B 0x8445 # 0 +0xC87C 0x8447 # 0 +0xC87D 0x8448 # 0 +0xC87E 0x8449 # 0 +0xC880 0x844A # 0 +0xC881 0x844B # 0 +0xC882 0x844C # 0 +0xC883 0x844D # 0 +0xC884 0x844E # 0 +0xC885 0x844F # 0 +0xC886 0x8450 # 0 +0xC887 0x8452 # 0 +0xC888 0x8453 # 0 +0xC889 0x8454 # 0 +0xC88A 0x8455 # 0 +0xC88B 0x8456 # 0 +0xC88C 0x8458 # 0 +0xC88D 0x845D # 0 +0xC88E 0x845E # 0 +0xC88F 0x845F # 0 +0xC890 0x8460 # 0 +0xC891 0x8462 # 0 +0xC892 0x8464 # 0 +0xC893 0x8465 # 0 +0xC894 0x8466 # 0 +0xC895 0x8467 # 0 +0xC896 0x8468 # 0 +0xC897 0x846A # 0 +0xC898 0x846E # 0 +0xC899 0x846F # 0 +0xC89A 0x8470 # 0 +0xC89B 0x8472 # 0 +0xC89C 0x8474 # 0 +0xC89D 0x8477 # 0 +0xC89E 0x8479 # 0 +0xC89F 0x847B # 0 +0xC8A0 0x847C # 0 +0xC8A1 0x53D6 # 0 +0xC8A2 0x5A36 # 0 +0xC8A3 0x9F8B # 0 +0xC8A4 0x8DA3 # 0 +0xC8A5 0x53BB # 0 +0xC8A6 0x5708 # 0 +0xC8A7 0x98A7 # 0 +0xC8A8 0x6743 # 0 +0xC8A9 0x919B # 0 +0xC8AA 0x6CC9 # 0 +0xC8AB 0x5168 # 0 +0xC8AC 0x75CA # 0 +0xC8AD 0x62F3 # 0 +0xC8AE 0x72AC # 0 +0xC8AF 0x5238 # 0 +0xC8B0 0x529D # 0 +0xC8B1 0x7F3A # 0 +0xC8B2 0x7094 # 0 +0xC8B3 0x7638 # 0 +0xC8B4 0x5374 # 0 +0xC8B5 0x9E4A # 0 +0xC8B6 0x69B7 # 0 +0xC8B7 0x786E # 0 +0xC8B8 0x96C0 # 0 +0xC8B9 0x88D9 # 0 +0xC8BA 0x7FA4 # 0 +0xC8BB 0x7136 # 0 +0xC8BC 0x71C3 # 0 +0xC8BD 0x5189 # 0 +0xC8BE 0x67D3 # 0 +0xC8BF 0x74E4 # 0 +0xC8C0 0x58E4 # 0 +0xC8C1 0x6518 # 0 +0xC8C2 0x56B7 # 0 +0xC8C3 0x8BA9 # 0 +0xC8C4 0x9976 # 0 +0xC8C5 0x6270 # 0 +0xC8C6 0x7ED5 # 0 +0xC8C7 0x60F9 # 0 +0xC8C8 0x70ED # 0 +0xC8C9 0x58EC # 0 +0xC8CA 0x4EC1 # 0 +0xC8CB 0x4EBA # 0 +0xC8CC 0x5FCD # 0 +0xC8CD 0x97E7 # 0 +0xC8CE 0x4EFB # 0 +0xC8CF 0x8BA4 # 0 +0xC8D0 0x5203 # 0 +0xC8D1 0x598A # 0 +0xC8D2 0x7EAB # 0 +0xC8D3 0x6254 # 0 +0xC8D4 0x4ECD # 0 +0xC8D5 0x65E5 # 0 +0xC8D6 0x620E # 0 +0xC8D7 0x8338 # 0 +0xC8D8 0x84C9 # 0 +0xC8D9 0x8363 # 0 +0xC8DA 0x878D # 0 +0xC8DB 0x7194 # 0 +0xC8DC 0x6EB6 # 0 +0xC8DD 0x5BB9 # 0 +0xC8DE 0x7ED2 # 0 +0xC8DF 0x5197 # 0 +0xC8E0 0x63C9 # 0 +0xC8E1 0x67D4 # 0 +0xC8E2 0x8089 # 0 +0xC8E3 0x8339 # 0 +0xC8E4 0x8815 # 0 +0xC8E5 0x5112 # 0 +0xC8E6 0x5B7A # 0 +0xC8E7 0x5982 # 0 +0xC8E8 0x8FB1 # 0 +0xC8E9 0x4E73 # 0 +0xC8EA 0x6C5D # 0 +0xC8EB 0x5165 # 0 +0xC8EC 0x8925 # 0 +0xC8ED 0x8F6F # 0 +0xC8EE 0x962E # 0 +0xC8EF 0x854A # 0 +0xC8F0 0x745E # 0 +0xC8F1 0x9510 # 0 +0xC8F2 0x95F0 # 0 +0xC8F3 0x6DA6 # 0 +0xC8F4 0x82E5 # 0 +0xC8F5 0x5F31 # 0 +0xC8F6 0x6492 # 0 +0xC8F7 0x6D12 # 0 +0xC8F8 0x8428 # 0 +0xC8F9 0x816E # 0 +0xC8FA 0x9CC3 # 0 +0xC8FB 0x585E # 0 +0xC8FC 0x8D5B # 0 +0xC8FD 0x4E09 # 0 +0xC8FE 0x53C1 # 0 +0xC940 0x847D # 0 +0xC941 0x847E # 0 +0xC942 0x847F # 0 +0xC943 0x8480 # 0 +0xC944 0x8481 # 0 +0xC945 0x8483 # 0 +0xC946 0x8484 # 0 +0xC947 0x8485 # 0 +0xC948 0x8486 # 0 +0xC949 0x848A # 0 +0xC94A 0x848D # 0 +0xC94B 0x848F # 0 +0xC94C 0x8490 # 0 +0xC94D 0x8491 # 0 +0xC94E 0x8492 # 0 +0xC94F 0x8493 # 0 +0xC950 0x8494 # 0 +0xC951 0x8495 # 0 +0xC952 0x8496 # 0 +0xC953 0x8498 # 0 +0xC954 0x849A # 0 +0xC955 0x849B # 0 +0xC956 0x849D # 0 +0xC957 0x849E # 0 +0xC958 0x849F # 0 +0xC959 0x84A0 # 0 +0xC95A 0x84A2 # 0 +0xC95B 0x84A3 # 0 +0xC95C 0x84A4 # 0 +0xC95D 0x84A5 # 0 +0xC95E 0x84A6 # 0 +0xC95F 0x84A7 # 0 +0xC960 0x84A8 # 0 +0xC961 0x84A9 # 0 +0xC962 0x84AA # 0 +0xC963 0x84AB # 0 +0xC964 0x84AC # 0 +0xC965 0x84AD # 0 +0xC966 0x84AE # 0 +0xC967 0x84B0 # 0 +0xC968 0x84B1 # 0 +0xC969 0x84B3 # 0 +0xC96A 0x84B5 # 0 +0xC96B 0x84B6 # 0 +0xC96C 0x84B7 # 0 +0xC96D 0x84BB # 0 +0xC96E 0x84BC # 0 +0xC96F 0x84BE # 0 +0xC970 0x84C0 # 0 +0xC971 0x84C2 # 0 +0xC972 0x84C3 # 0 +0xC973 0x84C5 # 0 +0xC974 0x84C6 # 0 +0xC975 0x84C7 # 0 +0xC976 0x84C8 # 0 +0xC977 0x84CB # 0 +0xC978 0x84CC # 0 +0xC979 0x84CE # 0 +0xC97A 0x84CF # 0 +0xC97B 0x84D2 # 0 +0xC97C 0x84D4 # 0 +0xC97D 0x84D5 # 0 +0xC97E 0x84D7 # 0 +0xC980 0x84D8 # 0 +0xC981 0x84D9 # 0 +0xC982 0x84DA # 0 +0xC983 0x84DB # 0 +0xC984 0x84DC # 0 +0xC985 0x84DE # 0 +0xC986 0x84E1 # 0 +0xC987 0x84E2 # 0 +0xC988 0x84E4 # 0 +0xC989 0x84E7 # 0 +0xC98A 0x84E8 # 0 +0xC98B 0x84E9 # 0 +0xC98C 0x84EA # 0 +0xC98D 0x84EB # 0 +0xC98E 0x84ED # 0 +0xC98F 0x84EE # 0 +0xC990 0x84EF # 0 +0xC991 0x84F1 # 0 +0xC992 0x84F2 # 0 +0xC993 0x84F3 # 0 +0xC994 0x84F4 # 0 +0xC995 0x84F5 # 0 +0xC996 0x84F6 # 0 +0xC997 0x84F7 # 0 +0xC998 0x84F8 # 0 +0xC999 0x84F9 # 0 +0xC99A 0x84FA # 0 +0xC99B 0x84FB # 0 +0xC99C 0x84FD # 0 +0xC99D 0x84FE # 0 +0xC99E 0x8500 # 0 +0xC99F 0x8501 # 0 +0xC9A0 0x8502 # 0 +0xC9A1 0x4F1E # 0 +0xC9A2 0x6563 # 0 +0xC9A3 0x6851 # 0 +0xC9A4 0x55D3 # 0 +0xC9A5 0x4E27 # 0 +0xC9A6 0x6414 # 0 +0xC9A7 0x9A9A # 0 +0xC9A8 0x626B # 0 +0xC9A9 0x5AC2 # 0 +0xC9AA 0x745F # 0 +0xC9AB 0x8272 # 0 +0xC9AC 0x6DA9 # 0 +0xC9AD 0x68EE # 0 +0xC9AE 0x50E7 # 0 +0xC9AF 0x838E # 0 +0xC9B0 0x7802 # 0 +0xC9B1 0x6740 # 0 +0xC9B2 0x5239 # 0 +0xC9B3 0x6C99 # 0 +0xC9B4 0x7EB1 # 0 +0xC9B5 0x50BB # 0 +0xC9B6 0x5565 # 0 +0xC9B7 0x715E # 0 +0xC9B8 0x7B5B # 0 +0xC9B9 0x6652 # 0 +0xC9BA 0x73CA # 0 +0xC9BB 0x82EB # 0 +0xC9BC 0x6749 # 0 +0xC9BD 0x5C71 # 0 +0xC9BE 0x5220 # 0 +0xC9BF 0x717D # 0 +0xC9C0 0x886B # 0 +0xC9C1 0x95EA # 0 +0xC9C2 0x9655 # 0 +0xC9C3 0x64C5 # 0 +0xC9C4 0x8D61 # 0 +0xC9C5 0x81B3 # 0 +0xC9C6 0x5584 # 0 +0xC9C7 0x6C55 # 0 +0xC9C8 0x6247 # 0 +0xC9C9 0x7F2E # 0 +0xC9CA 0x5892 # 0 +0xC9CB 0x4F24 # 0 +0xC9CC 0x5546 # 0 +0xC9CD 0x8D4F # 0 +0xC9CE 0x664C # 0 +0xC9CF 0x4E0A # 0 +0xC9D0 0x5C1A # 0 +0xC9D1 0x88F3 # 0 +0xC9D2 0x68A2 # 0 +0xC9D3 0x634E # 0 +0xC9D4 0x7A0D # 0 +0xC9D5 0x70E7 # 0 +0xC9D6 0x828D # 0 +0xC9D7 0x52FA # 0 +0xC9D8 0x97F6 # 0 +0xC9D9 0x5C11 # 0 +0xC9DA 0x54E8 # 0 +0xC9DB 0x90B5 # 0 +0xC9DC 0x7ECD # 0 +0xC9DD 0x5962 # 0 +0xC9DE 0x8D4A # 0 +0xC9DF 0x86C7 # 0 +0xC9E0 0x820C # 0 +0xC9E1 0x820D # 0 +0xC9E2 0x8D66 # 0 +0xC9E3 0x6444 # 0 +0xC9E4 0x5C04 # 0 +0xC9E5 0x6151 # 0 +0xC9E6 0x6D89 # 0 +0xC9E7 0x793E # 0 +0xC9E8 0x8BBE # 0 +0xC9E9 0x7837 # 0 +0xC9EA 0x7533 # 0 +0xC9EB 0x547B # 0 +0xC9EC 0x4F38 # 0 +0xC9ED 0x8EAB # 0 +0xC9EE 0x6DF1 # 0 +0xC9EF 0x5A20 # 0 +0xC9F0 0x7EC5 # 0 +0xC9F1 0x795E # 0 +0xC9F2 0x6C88 # 0 +0xC9F3 0x5BA1 # 0 +0xC9F4 0x5A76 # 0 +0xC9F5 0x751A # 0 +0xC9F6 0x80BE # 0 +0xC9F7 0x614E # 0 +0xC9F8 0x6E17 # 0 +0xC9F9 0x58F0 # 0 +0xC9FA 0x751F # 0 +0xC9FB 0x7525 # 0 +0xC9FC 0x7272 # 0 +0xC9FD 0x5347 # 0 +0xC9FE 0x7EF3 # 0 +0xCA40 0x8503 # 0 +0xCA41 0x8504 # 0 +0xCA42 0x8505 # 0 +0xCA43 0x8506 # 0 +0xCA44 0x8507 # 0 +0xCA45 0x8508 # 0 +0xCA46 0x8509 # 0 +0xCA47 0x850A # 0 +0xCA48 0x850B # 0 +0xCA49 0x850D # 0 +0xCA4A 0x850E # 0 +0xCA4B 0x850F # 0 +0xCA4C 0x8510 # 0 +0xCA4D 0x8512 # 0 +0xCA4E 0x8514 # 0 +0xCA4F 0x8515 # 0 +0xCA50 0x8516 # 0 +0xCA51 0x8518 # 0 +0xCA52 0x8519 # 0 +0xCA53 0x851B # 0 +0xCA54 0x851C # 0 +0xCA55 0x851D # 0 +0xCA56 0x851E # 0 +0xCA57 0x8520 # 0 +0xCA58 0x8522 # 0 +0xCA59 0x8523 # 0 +0xCA5A 0x8524 # 0 +0xCA5B 0x8525 # 0 +0xCA5C 0x8526 # 0 +0xCA5D 0x8527 # 0 +0xCA5E 0x8528 # 0 +0xCA5F 0x8529 # 0 +0xCA60 0x852A # 0 +0xCA61 0x852D # 0 +0xCA62 0x852E # 0 +0xCA63 0x852F # 0 +0xCA64 0x8530 # 0 +0xCA65 0x8531 # 0 +0xCA66 0x8532 # 0 +0xCA67 0x8533 # 0 +0xCA68 0x8534 # 0 +0xCA69 0x8535 # 0 +0xCA6A 0x8536 # 0 +0xCA6B 0x853E # 0 +0xCA6C 0x853F # 0 +0xCA6D 0x8540 # 0 +0xCA6E 0x8541 # 0 +0xCA6F 0x8542 # 0 +0xCA70 0x8544 # 0 +0xCA71 0x8545 # 0 +0xCA72 0x8546 # 0 +0xCA73 0x8547 # 0 +0xCA74 0x854B # 0 +0xCA75 0x854C # 0 +0xCA76 0x854D # 0 +0xCA77 0x854E # 0 +0xCA78 0x854F # 0 +0xCA79 0x8550 # 0 +0xCA7A 0x8551 # 0 +0xCA7B 0x8552 # 0 +0xCA7C 0x8553 # 0 +0xCA7D 0x8554 # 0 +0xCA7E 0x8555 # 0 +0xCA80 0x8557 # 0 +0xCA81 0x8558 # 0 +0xCA82 0x855A # 0 +0xCA83 0x855B # 0 +0xCA84 0x855C # 0 +0xCA85 0x855D # 0 +0xCA86 0x855F # 0 +0xCA87 0x8560 # 0 +0xCA88 0x8561 # 0 +0xCA89 0x8562 # 0 +0xCA8A 0x8563 # 0 +0xCA8B 0x8565 # 0 +0xCA8C 0x8566 # 0 +0xCA8D 0x8567 # 0 +0xCA8E 0x8569 # 0 +0xCA8F 0x856A # 0 +0xCA90 0x856B # 0 +0xCA91 0x856C # 0 +0xCA92 0x856D # 0 +0xCA93 0x856E # 0 +0xCA94 0x856F # 0 +0xCA95 0x8570 # 0 +0xCA96 0x8571 # 0 +0xCA97 0x8573 # 0 +0xCA98 0x8575 # 0 +0xCA99 0x8576 # 0 +0xCA9A 0x8577 # 0 +0xCA9B 0x8578 # 0 +0xCA9C 0x857C # 0 +0xCA9D 0x857D # 0 +0xCA9E 0x857F # 0 +0xCA9F 0x8580 # 0 +0xCAA0 0x8581 # 0 +0xCAA1 0x7701 # 0 +0xCAA2 0x76DB # 0 +0xCAA3 0x5269 # 0 +0xCAA4 0x80DC # 0 +0xCAA5 0x5723 # 0 +0xCAA6 0x5E08 # 0 +0xCAA7 0x5931 # 0 +0xCAA8 0x72EE # 0 +0xCAA9 0x65BD # 0 +0xCAAA 0x6E7F # 0 +0xCAAB 0x8BD7 # 0 +0xCAAC 0x5C38 # 0 +0xCAAD 0x8671 # 0 +0xCAAE 0x5341 # 0 +0xCAAF 0x77F3 # 0 +0xCAB0 0x62FE # 0 +0xCAB1 0x65F6 # 0 +0xCAB2 0x4EC0 # 0 +0xCAB3 0x98DF # 0 +0xCAB4 0x8680 # 0 +0xCAB5 0x5B9E # 0 +0xCAB6 0x8BC6 # 0 +0xCAB7 0x53F2 # 0 +0xCAB8 0x77E2 # 0 +0xCAB9 0x4F7F # 0 +0xCABA 0x5C4E # 0 +0xCABB 0x9A76 # 0 +0xCABC 0x59CB # 0 +0xCABD 0x5F0F # 0 +0xCABE 0x793A # 0 +0xCABF 0x58EB # 0 +0xCAC0 0x4E16 # 0 +0xCAC1 0x67FF # 0 +0xCAC2 0x4E8B # 0 +0xCAC3 0x62ED # 0 +0xCAC4 0x8A93 # 0 +0xCAC5 0x901D # 0 +0xCAC6 0x52BF # 0 +0xCAC7 0x662F # 0 +0xCAC8 0x55DC # 0 +0xCAC9 0x566C # 0 +0xCACA 0x9002 # 0 +0xCACB 0x4ED5 # 0 +0xCACC 0x4F8D # 0 +0xCACD 0x91CA # 0 +0xCACE 0x9970 # 0 +0xCACF 0x6C0F # 0 +0xCAD0 0x5E02 # 0 +0xCAD1 0x6043 # 0 +0xCAD2 0x5BA4 # 0 +0xCAD3 0x89C6 # 0 +0xCAD4 0x8BD5 # 0 +0xCAD5 0x6536 # 0 +0xCAD6 0x624B # 0 +0xCAD7 0x9996 # 0 +0xCAD8 0x5B88 # 0 +0xCAD9 0x5BFF # 0 +0xCADA 0x6388 # 0 +0xCADB 0x552E # 0 +0xCADC 0x53D7 # 0 +0xCADD 0x7626 # 0 +0xCADE 0x517D # 0 +0xCADF 0x852C # 0 +0xCAE0 0x67A2 # 0 +0xCAE1 0x68B3 # 0 +0xCAE2 0x6B8A # 0 +0xCAE3 0x6292 # 0 +0xCAE4 0x8F93 # 0 +0xCAE5 0x53D4 # 0 +0xCAE6 0x8212 # 0 +0xCAE7 0x6DD1 # 0 +0xCAE8 0x758F # 0 +0xCAE9 0x4E66 # 0 +0xCAEA 0x8D4E # 0 +0xCAEB 0x5B70 # 0 +0xCAEC 0x719F # 0 +0xCAED 0x85AF # 0 +0xCAEE 0x6691 # 0 +0xCAEF 0x66D9 # 0 +0xCAF0 0x7F72 # 0 +0xCAF1 0x8700 # 0 +0xCAF2 0x9ECD # 0 +0xCAF3 0x9F20 # 0 +0xCAF4 0x5C5E # 0 +0xCAF5 0x672F # 0 +0xCAF6 0x8FF0 # 0 +0xCAF7 0x6811 # 0 +0xCAF8 0x675F # 0 +0xCAF9 0x620D # 0 +0xCAFA 0x7AD6 # 0 +0xCAFB 0x5885 # 0 +0xCAFC 0x5EB6 # 0 +0xCAFD 0x6570 # 0 +0xCAFE 0x6F31 # 0 +0xCB40 0x8582 # 0 +0xCB41 0x8583 # 0 +0xCB42 0x8586 # 0 +0xCB43 0x8588 # 0 +0xCB44 0x8589 # 0 +0xCB45 0x858A # 0 +0xCB46 0x858B # 0 +0xCB47 0x858C # 0 +0xCB48 0x858D # 0 +0xCB49 0x858E # 0 +0xCB4A 0x8590 # 0 +0xCB4B 0x8591 # 0 +0xCB4C 0x8592 # 0 +0xCB4D 0x8593 # 0 +0xCB4E 0x8594 # 0 +0xCB4F 0x8595 # 0 +0xCB50 0x8596 # 0 +0xCB51 0x8597 # 0 +0xCB52 0x8598 # 0 +0xCB53 0x8599 # 0 +0xCB54 0x859A # 0 +0xCB55 0x859D # 0 +0xCB56 0x859E # 0 +0xCB57 0x859F # 0 +0xCB58 0x85A0 # 0 +0xCB59 0x85A1 # 0 +0xCB5A 0x85A2 # 0 +0xCB5B 0x85A3 # 0 +0xCB5C 0x85A5 # 0 +0xCB5D 0x85A6 # 0 +0xCB5E 0x85A7 # 0 +0xCB5F 0x85A9 # 0 +0xCB60 0x85AB # 0 +0xCB61 0x85AC # 0 +0xCB62 0x85AD # 0 +0xCB63 0x85B1 # 0 +0xCB64 0x85B2 # 0 +0xCB65 0x85B3 # 0 +0xCB66 0x85B4 # 0 +0xCB67 0x85B5 # 0 +0xCB68 0x85B6 # 0 +0xCB69 0x85B8 # 0 +0xCB6A 0x85BA # 0 +0xCB6B 0x85BB # 0 +0xCB6C 0x85BC # 0 +0xCB6D 0x85BD # 0 +0xCB6E 0x85BE # 0 +0xCB6F 0x85BF # 0 +0xCB70 0x85C0 # 0 +0xCB71 0x85C2 # 0 +0xCB72 0x85C3 # 0 +0xCB73 0x85C4 # 0 +0xCB74 0x85C5 # 0 +0xCB75 0x85C6 # 0 +0xCB76 0x85C7 # 0 +0xCB77 0x85C8 # 0 +0xCB78 0x85CA # 0 +0xCB79 0x85CB # 0 +0xCB7A 0x85CC # 0 +0xCB7B 0x85CD # 0 +0xCB7C 0x85CE # 0 +0xCB7D 0x85D1 # 0 +0xCB7E 0x85D2 # 0 +0xCB80 0x85D4 # 0 +0xCB81 0x85D6 # 0 +0xCB82 0x85D7 # 0 +0xCB83 0x85D8 # 0 +0xCB84 0x85D9 # 0 +0xCB85 0x85DA # 0 +0xCB86 0x85DB # 0 +0xCB87 0x85DD # 0 +0xCB88 0x85DE # 0 +0xCB89 0x85DF # 0 +0xCB8A 0x85E0 # 0 +0xCB8B 0x85E1 # 0 +0xCB8C 0x85E2 # 0 +0xCB8D 0x85E3 # 0 +0xCB8E 0x85E5 # 0 +0xCB8F 0x85E6 # 0 +0xCB90 0x85E7 # 0 +0xCB91 0x85E8 # 0 +0xCB92 0x85EA # 0 +0xCB93 0x85EB # 0 +0xCB94 0x85EC # 0 +0xCB95 0x85ED # 0 +0xCB96 0x85EE # 0 +0xCB97 0x85EF # 0 +0xCB98 0x85F0 # 0 +0xCB99 0x85F1 # 0 +0xCB9A 0x85F2 # 0 +0xCB9B 0x85F3 # 0 +0xCB9C 0x85F4 # 0 +0xCB9D 0x85F5 # 0 +0xCB9E 0x85F6 # 0 +0xCB9F 0x85F7 # 0 +0xCBA0 0x85F8 # 0 +0xCBA1 0x6055 # 0 +0xCBA2 0x5237 # 0 +0xCBA3 0x800D # 0 +0xCBA4 0x6454 # 0 +0xCBA5 0x8870 # 0 +0xCBA6 0x7529 # 0 +0xCBA7 0x5E05 # 0 +0xCBA8 0x6813 # 0 +0xCBA9 0x62F4 # 0 +0xCBAA 0x971C # 0 +0xCBAB 0x53CC # 0 +0xCBAC 0x723D # 0 +0xCBAD 0x8C01 # 0 +0xCBAE 0x6C34 # 0 +0xCBAF 0x7761 # 0 +0xCBB0 0x7A0E # 0 +0xCBB1 0x542E # 0 +0xCBB2 0x77AC # 0 +0xCBB3 0x987A # 0 +0xCBB4 0x821C # 0 +0xCBB5 0x8BF4 # 0 +0xCBB6 0x7855 # 0 +0xCBB7 0x6714 # 0 +0xCBB8 0x70C1 # 0 +0xCBB9 0x65AF # 0 +0xCBBA 0x6495 # 0 +0xCBBB 0x5636 # 0 +0xCBBC 0x601D # 0 +0xCBBD 0x79C1 # 0 +0xCBBE 0x53F8 # 0 +0xCBBF 0x4E1D # 0 +0xCBC0 0x6B7B # 0 +0xCBC1 0x8086 # 0 +0xCBC2 0x5BFA # 0 +0xCBC3 0x55E3 # 0 +0xCBC4 0x56DB # 0 +0xCBC5 0x4F3A # 0 +0xCBC6 0x4F3C # 0 +0xCBC7 0x9972 # 0 +0xCBC8 0x5DF3 # 0 +0xCBC9 0x677E # 0 +0xCBCA 0x8038 # 0 +0xCBCB 0x6002 # 0 +0xCBCC 0x9882 # 0 +0xCBCD 0x9001 # 0 +0xCBCE 0x5B8B # 0 +0xCBCF 0x8BBC # 0 +0xCBD0 0x8BF5 # 0 +0xCBD1 0x641C # 0 +0xCBD2 0x8258 # 0 +0xCBD3 0x64DE # 0 +0xCBD4 0x55FD # 0 +0xCBD5 0x82CF # 0 +0xCBD6 0x9165 # 0 +0xCBD7 0x4FD7 # 0 +0xCBD8 0x7D20 # 0 +0xCBD9 0x901F # 0 +0xCBDA 0x7C9F # 0 +0xCBDB 0x50F3 # 0 +0xCBDC 0x5851 # 0 +0xCBDD 0x6EAF # 0 +0xCBDE 0x5BBF # 0 +0xCBDF 0x8BC9 # 0 +0xCBE0 0x8083 # 0 +0xCBE1 0x9178 # 0 +0xCBE2 0x849C # 0 +0xCBE3 0x7B97 # 0 +0xCBE4 0x867D # 0 +0xCBE5 0x968B # 0 +0xCBE6 0x968F # 0 +0xCBE7 0x7EE5 # 0 +0xCBE8 0x9AD3 # 0 +0xCBE9 0x788E # 0 +0xCBEA 0x5C81 # 0 +0xCBEB 0x7A57 # 0 +0xCBEC 0x9042 # 0 +0xCBED 0x96A7 # 0 +0xCBEE 0x795F # 0 +0xCBEF 0x5B59 # 0 +0xCBF0 0x635F # 0 +0xCBF1 0x7B0B # 0 +0xCBF2 0x84D1 # 0 +0xCBF3 0x68AD # 0 +0xCBF4 0x5506 # 0 +0xCBF5 0x7F29 # 0 +0xCBF6 0x7410 # 0 +0xCBF7 0x7D22 # 0 +0xCBF8 0x9501 # 0 +0xCBF9 0x6240 # 0 +0xCBFA 0x584C # 0 +0xCBFB 0x4ED6 # 0 +0xCBFC 0x5B83 # 0 +0xCBFD 0x5979 # 0 +0xCBFE 0x5854 # 0 +0xCC40 0x85F9 # 0 +0xCC41 0x85FA # 0 +0xCC42 0x85FC # 0 +0xCC43 0x85FD # 0 +0xCC44 0x85FE # 0 +0xCC45 0x8600 # 0 +0xCC46 0x8601 # 0 +0xCC47 0x8602 # 0 +0xCC48 0x8603 # 0 +0xCC49 0x8604 # 0 +0xCC4A 0x8606 # 0 +0xCC4B 0x8607 # 0 +0xCC4C 0x8608 # 0 +0xCC4D 0x8609 # 0 +0xCC4E 0x860A # 0 +0xCC4F 0x860B # 0 +0xCC50 0x860C # 0 +0xCC51 0x860D # 0 +0xCC52 0x860E # 0 +0xCC53 0x860F # 0 +0xCC54 0x8610 # 0 +0xCC55 0x8612 # 0 +0xCC56 0x8613 # 0 +0xCC57 0x8614 # 0 +0xCC58 0x8615 # 0 +0xCC59 0x8617 # 0 +0xCC5A 0x8618 # 0 +0xCC5B 0x8619 # 0 +0xCC5C 0x861A # 0 +0xCC5D 0x861B # 0 +0xCC5E 0x861C # 0 +0xCC5F 0x861D # 0 +0xCC60 0x861E # 0 +0xCC61 0x861F # 0 +0xCC62 0x8620 # 0 +0xCC63 0x8621 # 0 +0xCC64 0x8622 # 0 +0xCC65 0x8623 # 0 +0xCC66 0x8624 # 0 +0xCC67 0x8625 # 0 +0xCC68 0x8626 # 0 +0xCC69 0x8628 # 0 +0xCC6A 0x862A # 0 +0xCC6B 0x862B # 0 +0xCC6C 0x862C # 0 +0xCC6D 0x862D # 0 +0xCC6E 0x862E # 0 +0xCC6F 0x862F # 0 +0xCC70 0x8630 # 0 +0xCC71 0x8631 # 0 +0xCC72 0x8632 # 0 +0xCC73 0x8633 # 0 +0xCC74 0x8634 # 0 +0xCC75 0x8635 # 0 +0xCC76 0x8636 # 0 +0xCC77 0x8637 # 0 +0xCC78 0x8639 # 0 +0xCC79 0x863A # 0 +0xCC7A 0x863B # 0 +0xCC7B 0x863D # 0 +0xCC7C 0x863E # 0 +0xCC7D 0x863F # 0 +0xCC7E 0x8640 # 0 +0xCC80 0x8641 # 0 +0xCC81 0x8642 # 0 +0xCC82 0x8643 # 0 +0xCC83 0x8644 # 0 +0xCC84 0x8645 # 0 +0xCC85 0x8646 # 0 +0xCC86 0x8647 # 0 +0xCC87 0x8648 # 0 +0xCC88 0x8649 # 0 +0xCC89 0x864A # 0 +0xCC8A 0x864B # 0 +0xCC8B 0x864C # 0 +0xCC8C 0x8652 # 0 +0xCC8D 0x8653 # 0 +0xCC8E 0x8655 # 0 +0xCC8F 0x8656 # 0 +0xCC90 0x8657 # 0 +0xCC91 0x8658 # 0 +0xCC92 0x8659 # 0 +0xCC93 0x865B # 0 +0xCC94 0x865C # 0 +0xCC95 0x865D # 0 +0xCC96 0x865F # 0 +0xCC97 0x8660 # 0 +0xCC98 0x8661 # 0 +0xCC99 0x8663 # 0 +0xCC9A 0x8664 # 0 +0xCC9B 0x8665 # 0 +0xCC9C 0x8666 # 0 +0xCC9D 0x8667 # 0 +0xCC9E 0x8668 # 0 +0xCC9F 0x8669 # 0 +0xCCA0 0x866A # 0 +0xCCA1 0x736D # 0 +0xCCA2 0x631E # 0 +0xCCA3 0x8E4B # 0 +0xCCA4 0x8E0F # 0 +0xCCA5 0x80CE # 0 +0xCCA6 0x82D4 # 0 +0xCCA7 0x62AC # 0 +0xCCA8 0x53F0 # 0 +0xCCA9 0x6CF0 # 0 +0xCCAA 0x915E # 0 +0xCCAB 0x592A # 0 +0xCCAC 0x6001 # 0 +0xCCAD 0x6C70 # 0 +0xCCAE 0x574D # 0 +0xCCAF 0x644A # 0 +0xCCB0 0x8D2A # 0 +0xCCB1 0x762B # 0 +0xCCB2 0x6EE9 # 0 +0xCCB3 0x575B # 0 +0xCCB4 0x6A80 # 0 +0xCCB5 0x75F0 # 0 +0xCCB6 0x6F6D # 0 +0xCCB7 0x8C2D # 0 +0xCCB8 0x8C08 # 0 +0xCCB9 0x5766 # 0 +0xCCBA 0x6BEF # 0 +0xCCBB 0x8892 # 0 +0xCCBC 0x78B3 # 0 +0xCCBD 0x63A2 # 0 +0xCCBE 0x53F9 # 0 +0xCCBF 0x70AD # 0 +0xCCC0 0x6C64 # 0 +0xCCC1 0x5858 # 0 +0xCCC2 0x642A # 0 +0xCCC3 0x5802 # 0 +0xCCC4 0x68E0 # 0 +0xCCC5 0x819B # 0 +0xCCC6 0x5510 # 0 +0xCCC7 0x7CD6 # 0 +0xCCC8 0x5018 # 0 +0xCCC9 0x8EBA # 0 +0xCCCA 0x6DCC # 0 +0xCCCB 0x8D9F # 0 +0xCCCC 0x70EB # 0 +0xCCCD 0x638F # 0 +0xCCCE 0x6D9B # 0 +0xCCCF 0x6ED4 # 0 +0xCCD0 0x7EE6 # 0 +0xCCD1 0x8404 # 0 +0xCCD2 0x6843 # 0 +0xCCD3 0x9003 # 0 +0xCCD4 0x6DD8 # 0 +0xCCD5 0x9676 # 0 +0xCCD6 0x8BA8 # 0 +0xCCD7 0x5957 # 0 +0xCCD8 0x7279 # 0 +0xCCD9 0x85E4 # 0 +0xCCDA 0x817E # 0 +0xCCDB 0x75BC # 0 +0xCCDC 0x8A8A # 0 +0xCCDD 0x68AF # 0 +0xCCDE 0x5254 # 0 +0xCCDF 0x8E22 # 0 +0xCCE0 0x9511 # 0 +0xCCE1 0x63D0 # 0 +0xCCE2 0x9898 # 0 +0xCCE3 0x8E44 # 0 +0xCCE4 0x557C # 0 +0xCCE5 0x4F53 # 0 +0xCCE6 0x66FF # 0 +0xCCE7 0x568F # 0 +0xCCE8 0x60D5 # 0 +0xCCE9 0x6D95 # 0 +0xCCEA 0x5243 # 0 +0xCCEB 0x5C49 # 0 +0xCCEC 0x5929 # 0 +0xCCED 0x6DFB # 0 +0xCCEE 0x586B # 0 +0xCCEF 0x7530 # 0 +0xCCF0 0x751C # 0 +0xCCF1 0x606C # 0 +0xCCF2 0x8214 # 0 +0xCCF3 0x8146 # 0 +0xCCF4 0x6311 # 0 +0xCCF5 0x6761 # 0 +0xCCF6 0x8FE2 # 0 +0xCCF7 0x773A # 0 +0xCCF8 0x8DF3 # 0 +0xCCF9 0x8D34 # 0 +0xCCFA 0x94C1 # 0 +0xCCFB 0x5E16 # 0 +0xCCFC 0x5385 # 0 +0xCCFD 0x542C # 0 +0xCCFE 0x70C3 # 0 +0xCD40 0x866D # 0 +0xCD41 0x866F # 0 +0xCD42 0x8670 # 0 +0xCD43 0x8672 # 0 +0xCD44 0x8673 # 0 +0xCD45 0x8674 # 0 +0xCD46 0x8675 # 0 +0xCD47 0x8676 # 0 +0xCD48 0x8677 # 0 +0xCD49 0x8678 # 0 +0xCD4A 0x8683 # 0 +0xCD4B 0x8684 # 0 +0xCD4C 0x8685 # 0 +0xCD4D 0x8686 # 0 +0xCD4E 0x8687 # 0 +0xCD4F 0x8688 # 0 +0xCD50 0x8689 # 0 +0xCD51 0x868E # 0 +0xCD52 0x868F # 0 +0xCD53 0x8690 # 0 +0xCD54 0x8691 # 0 +0xCD55 0x8692 # 0 +0xCD56 0x8694 # 0 +0xCD57 0x8696 # 0 +0xCD58 0x8697 # 0 +0xCD59 0x8698 # 0 +0xCD5A 0x8699 # 0 +0xCD5B 0x869A # 0 +0xCD5C 0x869B # 0 +0xCD5D 0x869E # 0 +0xCD5E 0x869F # 0 +0xCD5F 0x86A0 # 0 +0xCD60 0x86A1 # 0 +0xCD61 0x86A2 # 0 +0xCD62 0x86A5 # 0 +0xCD63 0x86A6 # 0 +0xCD64 0x86AB # 0 +0xCD65 0x86AD # 0 +0xCD66 0x86AE # 0 +0xCD67 0x86B2 # 0 +0xCD68 0x86B3 # 0 +0xCD69 0x86B7 # 0 +0xCD6A 0x86B8 # 0 +0xCD6B 0x86B9 # 0 +0xCD6C 0x86BB # 0 +0xCD6D 0x86BC # 0 +0xCD6E 0x86BD # 0 +0xCD6F 0x86BE # 0 +0xCD70 0x86BF # 0 +0xCD71 0x86C1 # 0 +0xCD72 0x86C2 # 0 +0xCD73 0x86C3 # 0 +0xCD74 0x86C5 # 0 +0xCD75 0x86C8 # 0 +0xCD76 0x86CC # 0 +0xCD77 0x86CD # 0 +0xCD78 0x86D2 # 0 +0xCD79 0x86D3 # 0 +0xCD7A 0x86D5 # 0 +0xCD7B 0x86D6 # 0 +0xCD7C 0x86D7 # 0 +0xCD7D 0x86DA # 0 +0xCD7E 0x86DC # 0 +0xCD80 0x86DD # 0 +0xCD81 0x86E0 # 0 +0xCD82 0x86E1 # 0 +0xCD83 0x86E2 # 0 +0xCD84 0x86E3 # 0 +0xCD85 0x86E5 # 0 +0xCD86 0x86E6 # 0 +0xCD87 0x86E7 # 0 +0xCD88 0x86E8 # 0 +0xCD89 0x86EA # 0 +0xCD8A 0x86EB # 0 +0xCD8B 0x86EC # 0 +0xCD8C 0x86EF # 0 +0xCD8D 0x86F5 # 0 +0xCD8E 0x86F6 # 0 +0xCD8F 0x86F7 # 0 +0xCD90 0x86FA # 0 +0xCD91 0x86FB # 0 +0xCD92 0x86FC # 0 +0xCD93 0x86FD # 0 +0xCD94 0x86FF # 0 +0xCD95 0x8701 # 0 +0xCD96 0x8704 # 0 +0xCD97 0x8705 # 0 +0xCD98 0x8706 # 0 +0xCD99 0x870B # 0 +0xCD9A 0x870C # 0 +0xCD9B 0x870E # 0 +0xCD9C 0x870F # 0 +0xCD9D 0x8710 # 0 +0xCD9E 0x8711 # 0 +0xCD9F 0x8714 # 0 +0xCDA0 0x8716 # 0 +0xCDA1 0x6C40 # 0 +0xCDA2 0x5EF7 # 0 +0xCDA3 0x505C # 0 +0xCDA4 0x4EAD # 0 +0xCDA5 0x5EAD # 0 +0xCDA6 0x633A # 0 +0xCDA7 0x8247 # 0 +0xCDA8 0x901A # 0 +0xCDA9 0x6850 # 0 +0xCDAA 0x916E # 0 +0xCDAB 0x77B3 # 0 +0xCDAC 0x540C # 0 +0xCDAD 0x94DC # 0 +0xCDAE 0x5F64 # 0 +0xCDAF 0x7AE5 # 0 +0xCDB0 0x6876 # 0 +0xCDB1 0x6345 # 0 +0xCDB2 0x7B52 # 0 +0xCDB3 0x7EDF # 0 +0xCDB4 0x75DB # 0 +0xCDB5 0x5077 # 0 +0xCDB6 0x6295 # 0 +0xCDB7 0x5934 # 0 +0xCDB8 0x900F # 0 +0xCDB9 0x51F8 # 0 +0xCDBA 0x79C3 # 0 +0xCDBB 0x7A81 # 0 +0xCDBC 0x56FE # 0 +0xCDBD 0x5F92 # 0 +0xCDBE 0x9014 # 0 +0xCDBF 0x6D82 # 0 +0xCDC0 0x5C60 # 0 +0xCDC1 0x571F # 0 +0xCDC2 0x5410 # 0 +0xCDC3 0x5154 # 0 +0xCDC4 0x6E4D # 0 +0xCDC5 0x56E2 # 0 +0xCDC6 0x63A8 # 0 +0xCDC7 0x9893 # 0 +0xCDC8 0x817F # 0 +0xCDC9 0x8715 # 0 +0xCDCA 0x892A # 0 +0xCDCB 0x9000 # 0 +0xCDCC 0x541E # 0 +0xCDCD 0x5C6F # 0 +0xCDCE 0x81C0 # 0 +0xCDCF 0x62D6 # 0 +0xCDD0 0x6258 # 0 +0xCDD1 0x8131 # 0 +0xCDD2 0x9E35 # 0 +0xCDD3 0x9640 # 0 +0xCDD4 0x9A6E # 0 +0xCDD5 0x9A7C # 0 +0xCDD6 0x692D # 0 +0xCDD7 0x59A5 # 0 +0xCDD8 0x62D3 # 0 +0xCDD9 0x553E # 0 +0xCDDA 0x6316 # 0 +0xCDDB 0x54C7 # 0 +0xCDDC 0x86D9 # 0 +0xCDDD 0x6D3C # 0 +0xCDDE 0x5A03 # 0 +0xCDDF 0x74E6 # 0 +0xCDE0 0x889C # 0 +0xCDE1 0x6B6A # 0 +0xCDE2 0x5916 # 0 +0xCDE3 0x8C4C # 0 +0xCDE4 0x5F2F # 0 +0xCDE5 0x6E7E # 0 +0xCDE6 0x73A9 # 0 +0xCDE7 0x987D # 0 +0xCDE8 0x4E38 # 0 +0xCDE9 0x70F7 # 0 +0xCDEA 0x5B8C # 0 +0xCDEB 0x7897 # 0 +0xCDEC 0x633D # 0 +0xCDED 0x665A # 0 +0xCDEE 0x7696 # 0 +0xCDEF 0x60CB # 0 +0xCDF0 0x5B9B # 0 +0xCDF1 0x5A49 # 0 +0xCDF2 0x4E07 # 0 +0xCDF3 0x8155 # 0 +0xCDF4 0x6C6A # 0 +0xCDF5 0x738B # 0 +0xCDF6 0x4EA1 # 0 +0xCDF7 0x6789 # 0 +0xCDF8 0x7F51 # 0 +0xCDF9 0x5F80 # 0 +0xCDFA 0x65FA # 0 +0xCDFB 0x671B # 0 +0xCDFC 0x5FD8 # 0 +0xCDFD 0x5984 # 0 +0xCDFE 0x5A01 # 0 +0xCE40 0x8719 # 0 +0xCE41 0x871B # 0 +0xCE42 0x871D # 0 +0xCE43 0x871F # 0 +0xCE44 0x8720 # 0 +0xCE45 0x8724 # 0 +0xCE46 0x8726 # 0 +0xCE47 0x8727 # 0 +0xCE48 0x8728 # 0 +0xCE49 0x872A # 0 +0xCE4A 0x872B # 0 +0xCE4B 0x872C # 0 +0xCE4C 0x872D # 0 +0xCE4D 0x872F # 0 +0xCE4E 0x8730 # 0 +0xCE4F 0x8732 # 0 +0xCE50 0x8733 # 0 +0xCE51 0x8735 # 0 +0xCE52 0x8736 # 0 +0xCE53 0x8738 # 0 +0xCE54 0x8739 # 0 +0xCE55 0x873A # 0 +0xCE56 0x873C # 0 +0xCE57 0x873D # 0 +0xCE58 0x8740 # 0 +0xCE59 0x8741 # 0 +0xCE5A 0x8742 # 0 +0xCE5B 0x8743 # 0 +0xCE5C 0x8744 # 0 +0xCE5D 0x8745 # 0 +0xCE5E 0x8746 # 0 +0xCE5F 0x874A # 0 +0xCE60 0x874B # 0 +0xCE61 0x874D # 0 +0xCE62 0x874F # 0 +0xCE63 0x8750 # 0 +0xCE64 0x8751 # 0 +0xCE65 0x8752 # 0 +0xCE66 0x8754 # 0 +0xCE67 0x8755 # 0 +0xCE68 0x8756 # 0 +0xCE69 0x8758 # 0 +0xCE6A 0x875A # 0 +0xCE6B 0x875B # 0 +0xCE6C 0x875C # 0 +0xCE6D 0x875D # 0 +0xCE6E 0x875E # 0 +0xCE6F 0x875F # 0 +0xCE70 0x8761 # 0 +0xCE71 0x8762 # 0 +0xCE72 0x8766 # 0 +0xCE73 0x8767 # 0 +0xCE74 0x8768 # 0 +0xCE75 0x8769 # 0 +0xCE76 0x876A # 0 +0xCE77 0x876B # 0 +0xCE78 0x876C # 0 +0xCE79 0x876D # 0 +0xCE7A 0x876F # 0 +0xCE7B 0x8771 # 0 +0xCE7C 0x8772 # 0 +0xCE7D 0x8773 # 0 +0xCE7E 0x8775 # 0 +0xCE80 0x8777 # 0 +0xCE81 0x8778 # 0 +0xCE82 0x8779 # 0 +0xCE83 0x877A # 0 +0xCE84 0x877F # 0 +0xCE85 0x8780 # 0 +0xCE86 0x8781 # 0 +0xCE87 0x8784 # 0 +0xCE88 0x8786 # 0 +0xCE89 0x8787 # 0 +0xCE8A 0x8789 # 0 +0xCE8B 0x878A # 0 +0xCE8C 0x878C # 0 +0xCE8D 0x878E # 0 +0xCE8E 0x878F # 0 +0xCE8F 0x8790 # 0 +0xCE90 0x8791 # 0 +0xCE91 0x8792 # 0 +0xCE92 0x8794 # 0 +0xCE93 0x8795 # 0 +0xCE94 0x8796 # 0 +0xCE95 0x8798 # 0 +0xCE96 0x8799 # 0 +0xCE97 0x879A # 0 +0xCE98 0x879B # 0 +0xCE99 0x879C # 0 +0xCE9A 0x879D # 0 +0xCE9B 0x879E # 0 +0xCE9C 0x87A0 # 0 +0xCE9D 0x87A1 # 0 +0xCE9E 0x87A2 # 0 +0xCE9F 0x87A3 # 0 +0xCEA0 0x87A4 # 0 +0xCEA1 0x5DCD # 0 +0xCEA2 0x5FAE # 0 +0xCEA3 0x5371 # 0 +0xCEA4 0x97E6 # 0 +0xCEA5 0x8FDD # 0 +0xCEA6 0x6845 # 0 +0xCEA7 0x56F4 # 0 +0xCEA8 0x552F # 0 +0xCEA9 0x60DF # 0 +0xCEAA 0x4E3A # 0 +0xCEAB 0x6F4D # 0 +0xCEAC 0x7EF4 # 0 +0xCEAD 0x82C7 # 0 +0xCEAE 0x840E # 0 +0xCEAF 0x59D4 # 0 +0xCEB0 0x4F1F # 0 +0xCEB1 0x4F2A # 0 +0xCEB2 0x5C3E # 0 +0xCEB3 0x7EAC # 0 +0xCEB4 0x672A # 0 +0xCEB5 0x851A # 0 +0xCEB6 0x5473 # 0 +0xCEB7 0x754F # 0 +0xCEB8 0x80C3 # 0 +0xCEB9 0x5582 # 0 +0xCEBA 0x9B4F # 0 +0xCEBB 0x4F4D # 0 +0xCEBC 0x6E2D # 0 +0xCEBD 0x8C13 # 0 +0xCEBE 0x5C09 # 0 +0xCEBF 0x6170 # 0 +0xCEC0 0x536B # 0 +0xCEC1 0x761F # 0 +0xCEC2 0x6E29 # 0 +0xCEC3 0x868A # 0 +0xCEC4 0x6587 # 0 +0xCEC5 0x95FB # 0 +0xCEC6 0x7EB9 # 0 +0xCEC7 0x543B # 0 +0xCEC8 0x7A33 # 0 +0xCEC9 0x7D0A # 0 +0xCECA 0x95EE # 0 +0xCECB 0x55E1 # 0 +0xCECC 0x7FC1 # 0 +0xCECD 0x74EE # 0 +0xCECE 0x631D # 0 +0xCECF 0x8717 # 0 +0xCED0 0x6DA1 # 0 +0xCED1 0x7A9D # 0 +0xCED2 0x6211 # 0 +0xCED3 0x65A1 # 0 +0xCED4 0x5367 # 0 +0xCED5 0x63E1 # 0 +0xCED6 0x6C83 # 0 +0xCED7 0x5DEB # 0 +0xCED8 0x545C # 0 +0xCED9 0x94A8 # 0 +0xCEDA 0x4E4C # 0 +0xCEDB 0x6C61 # 0 +0xCEDC 0x8BEC # 0 +0xCEDD 0x5C4B # 0 +0xCEDE 0x65E0 # 0 +0xCEDF 0x829C # 0 +0xCEE0 0x68A7 # 0 +0xCEE1 0x543E # 0 +0xCEE2 0x5434 # 0 +0xCEE3 0x6BCB # 0 +0xCEE4 0x6B66 # 0 +0xCEE5 0x4E94 # 0 +0xCEE6 0x6342 # 0 +0xCEE7 0x5348 # 0 +0xCEE8 0x821E # 0 +0xCEE9 0x4F0D # 0 +0xCEEA 0x4FAE # 0 +0xCEEB 0x575E # 0 +0xCEEC 0x620A # 0 +0xCEED 0x96FE # 0 +0xCEEE 0x6664 # 0 +0xCEEF 0x7269 # 0 +0xCEF0 0x52FF # 0 +0xCEF1 0x52A1 # 0 +0xCEF2 0x609F # 0 +0xCEF3 0x8BEF # 0 +0xCEF4 0x6614 # 0 +0xCEF5 0x7199 # 0 +0xCEF6 0x6790 # 0 +0xCEF7 0x897F # 0 +0xCEF8 0x7852 # 0 +0xCEF9 0x77FD # 0 +0xCEFA 0x6670 # 0 +0xCEFB 0x563B # 0 +0xCEFC 0x5438 # 0 +0xCEFD 0x9521 # 0 +0xCEFE 0x727A # 0 +0xCF40 0x87A5 # 0 +0xCF41 0x87A6 # 0 +0xCF42 0x87A7 # 0 +0xCF43 0x87A9 # 0 +0xCF44 0x87AA # 0 +0xCF45 0x87AE # 0 +0xCF46 0x87B0 # 0 +0xCF47 0x87B1 # 0 +0xCF48 0x87B2 # 0 +0xCF49 0x87B4 # 0 +0xCF4A 0x87B6 # 0 +0xCF4B 0x87B7 # 0 +0xCF4C 0x87B8 # 0 +0xCF4D 0x87B9 # 0 +0xCF4E 0x87BB # 0 +0xCF4F 0x87BC # 0 +0xCF50 0x87BE # 0 +0xCF51 0x87BF # 0 +0xCF52 0x87C1 # 0 +0xCF53 0x87C2 # 0 +0xCF54 0x87C3 # 0 +0xCF55 0x87C4 # 0 +0xCF56 0x87C5 # 0 +0xCF57 0x87C7 # 0 +0xCF58 0x87C8 # 0 +0xCF59 0x87C9 # 0 +0xCF5A 0x87CC # 0 +0xCF5B 0x87CD # 0 +0xCF5C 0x87CE # 0 +0xCF5D 0x87CF # 0 +0xCF5E 0x87D0 # 0 +0xCF5F 0x87D4 # 0 +0xCF60 0x87D5 # 0 +0xCF61 0x87D6 # 0 +0xCF62 0x87D7 # 0 +0xCF63 0x87D8 # 0 +0xCF64 0x87D9 # 0 +0xCF65 0x87DA # 0 +0xCF66 0x87DC # 0 +0xCF67 0x87DD # 0 +0xCF68 0x87DE # 0 +0xCF69 0x87DF # 0 +0xCF6A 0x87E1 # 0 +0xCF6B 0x87E2 # 0 +0xCF6C 0x87E3 # 0 +0xCF6D 0x87E4 # 0 +0xCF6E 0x87E6 # 0 +0xCF6F 0x87E7 # 0 +0xCF70 0x87E8 # 0 +0xCF71 0x87E9 # 0 +0xCF72 0x87EB # 0 +0xCF73 0x87EC # 0 +0xCF74 0x87ED # 0 +0xCF75 0x87EF # 0 +0xCF76 0x87F0 # 0 +0xCF77 0x87F1 # 0 +0xCF78 0x87F2 # 0 +0xCF79 0x87F3 # 0 +0xCF7A 0x87F4 # 0 +0xCF7B 0x87F5 # 0 +0xCF7C 0x87F6 # 0 +0xCF7D 0x87F7 # 0 +0xCF7E 0x87F8 # 0 +0xCF80 0x87FA # 0 +0xCF81 0x87FB # 0 +0xCF82 0x87FC # 0 +0xCF83 0x87FD # 0 +0xCF84 0x87FF # 0 +0xCF85 0x8800 # 0 +0xCF86 0x8801 # 0 +0xCF87 0x8802 # 0 +0xCF88 0x8804 # 0 +0xCF89 0x8805 # 0 +0xCF8A 0x8806 # 0 +0xCF8B 0x8807 # 0 +0xCF8C 0x8808 # 0 +0xCF8D 0x8809 # 0 +0xCF8E 0x880B # 0 +0xCF8F 0x880C # 0 +0xCF90 0x880D # 0 +0xCF91 0x880E # 0 +0xCF92 0x880F # 0 +0xCF93 0x8810 # 0 +0xCF94 0x8811 # 0 +0xCF95 0x8812 # 0 +0xCF96 0x8814 # 0 +0xCF97 0x8817 # 0 +0xCF98 0x8818 # 0 +0xCF99 0x8819 # 0 +0xCF9A 0x881A # 0 +0xCF9B 0x881C # 0 +0xCF9C 0x881D # 0 +0xCF9D 0x881E # 0 +0xCF9E 0x881F # 0 +0xCF9F 0x8820 # 0 +0xCFA0 0x8823 # 0 +0xCFA1 0x7A00 # 0 +0xCFA2 0x606F # 0 +0xCFA3 0x5E0C # 0 +0xCFA4 0x6089 # 0 +0xCFA5 0x819D # 0 +0xCFA6 0x5915 # 0 +0xCFA7 0x60DC # 0 +0xCFA8 0x7184 # 0 +0xCFA9 0x70EF # 0 +0xCFAA 0x6EAA # 0 +0xCFAB 0x6C50 # 0 +0xCFAC 0x7280 # 0 +0xCFAD 0x6A84 # 0 +0xCFAE 0x88AD # 0 +0xCFAF 0x5E2D # 0 +0xCFB0 0x4E60 # 0 +0xCFB1 0x5AB3 # 0 +0xCFB2 0x559C # 0 +0xCFB3 0x94E3 # 0 +0xCFB4 0x6D17 # 0 +0xCFB5 0x7CFB # 0 +0xCFB6 0x9699 # 0 +0xCFB7 0x620F # 0 +0xCFB8 0x7EC6 # 0 +0xCFB9 0x778E # 0 +0xCFBA 0x867E # 0 +0xCFBB 0x5323 # 0 +0xCFBC 0x971E # 0 +0xCFBD 0x8F96 # 0 +0xCFBE 0x6687 # 0 +0xCFBF 0x5CE1 # 0 +0xCFC0 0x4FA0 # 0 +0xCFC1 0x72ED # 0 +0xCFC2 0x4E0B # 0 +0xCFC3 0x53A6 # 0 +0xCFC4 0x590F # 0 +0xCFC5 0x5413 # 0 +0xCFC6 0x6380 # 0 +0xCFC7 0x9528 # 0 +0xCFC8 0x5148 # 0 +0xCFC9 0x4ED9 # 0 +0xCFCA 0x9C9C # 0 +0xCFCB 0x7EA4 # 0 +0xCFCC 0x54B8 # 0 +0xCFCD 0x8D24 # 0 +0xCFCE 0x8854 # 0 +0xCFCF 0x8237 # 0 +0xCFD0 0x95F2 # 0 +0xCFD1 0x6D8E # 0 +0xCFD2 0x5F26 # 0 +0xCFD3 0x5ACC # 0 +0xCFD4 0x663E # 0 +0xCFD5 0x9669 # 0 +0xCFD6 0x73B0 # 0 +0xCFD7 0x732E # 0 +0xCFD8 0x53BF # 0 +0xCFD9 0x817A # 0 +0xCFDA 0x9985 # 0 +0xCFDB 0x7FA1 # 0 +0xCFDC 0x5BAA # 0 +0xCFDD 0x9677 # 0 +0xCFDE 0x9650 # 0 +0xCFDF 0x7EBF # 0 +0xCFE0 0x76F8 # 0 +0xCFE1 0x53A2 # 0 +0xCFE2 0x9576 # 0 +0xCFE3 0x9999 # 0 +0xCFE4 0x7BB1 # 0 +0xCFE5 0x8944 # 0 +0xCFE6 0x6E58 # 0 +0xCFE7 0x4E61 # 0 +0xCFE8 0x7FD4 # 0 +0xCFE9 0x7965 # 0 +0xCFEA 0x8BE6 # 0 +0xCFEB 0x60F3 # 0 +0xCFEC 0x54CD # 0 +0xCFED 0x4EAB # 0 +0xCFEE 0x9879 # 0 +0xCFEF 0x5DF7 # 0 +0xCFF0 0x6A61 # 0 +0xCFF1 0x50CF # 0 +0xCFF2 0x5411 # 0 +0xCFF3 0x8C61 # 0 +0xCFF4 0x8427 # 0 +0xCFF5 0x785D # 0 +0xCFF6 0x9704 # 0 +0xCFF7 0x524A # 0 +0xCFF8 0x54EE # 0 +0xCFF9 0x56A3 # 0 +0xCFFA 0x9500 # 0 +0xCFFB 0x6D88 # 0 +0xCFFC 0x5BB5 # 0 +0xCFFD 0x6DC6 # 0 +0xCFFE 0x6653 # 0 +0xD040 0x8824 # 0 +0xD041 0x8825 # 0 +0xD042 0x8826 # 0 +0xD043 0x8827 # 0 +0xD044 0x8828 # 0 +0xD045 0x8829 # 0 +0xD046 0x882A # 0 +0xD047 0x882B # 0 +0xD048 0x882C # 0 +0xD049 0x882D # 0 +0xD04A 0x882E # 0 +0xD04B 0x882F # 0 +0xD04C 0x8830 # 0 +0xD04D 0x8831 # 0 +0xD04E 0x8833 # 0 +0xD04F 0x8834 # 0 +0xD050 0x8835 # 0 +0xD051 0x8836 # 0 +0xD052 0x8837 # 0 +0xD053 0x8838 # 0 +0xD054 0x883A # 0 +0xD055 0x883B # 0 +0xD056 0x883D # 0 +0xD057 0x883E # 0 +0xD058 0x883F # 0 +0xD059 0x8841 # 0 +0xD05A 0x8842 # 0 +0xD05B 0x8843 # 0 +0xD05C 0x8846 # 0 +0xD05D 0x8847 # 0 +0xD05E 0x8848 # 0 +0xD05F 0x8849 # 0 +0xD060 0x884A # 0 +0xD061 0x884B # 0 +0xD062 0x884E # 0 +0xD063 0x884F # 0 +0xD064 0x8850 # 0 +0xD065 0x8851 # 0 +0xD066 0x8852 # 0 +0xD067 0x8853 # 0 +0xD068 0x8855 # 0 +0xD069 0x8856 # 0 +0xD06A 0x8858 # 0 +0xD06B 0x885A # 0 +0xD06C 0x885B # 0 +0xD06D 0x885C # 0 +0xD06E 0x885D # 0 +0xD06F 0x885E # 0 +0xD070 0x885F # 0 +0xD071 0x8860 # 0 +0xD072 0x8866 # 0 +0xD073 0x8867 # 0 +0xD074 0x886A # 0 +0xD075 0x886D # 0 +0xD076 0x886F # 0 +0xD077 0x8871 # 0 +0xD078 0x8873 # 0 +0xD079 0x8874 # 0 +0xD07A 0x8875 # 0 +0xD07B 0x8876 # 0 +0xD07C 0x8878 # 0 +0xD07D 0x8879 # 0 +0xD07E 0x887A # 0 +0xD080 0x887B # 0 +0xD081 0x887C # 0 +0xD082 0x8880 # 0 +0xD083 0x8883 # 0 +0xD084 0x8886 # 0 +0xD085 0x8887 # 0 +0xD086 0x8889 # 0 +0xD087 0x888A # 0 +0xD088 0x888C # 0 +0xD089 0x888E # 0 +0xD08A 0x888F # 0 +0xD08B 0x8890 # 0 +0xD08C 0x8891 # 0 +0xD08D 0x8893 # 0 +0xD08E 0x8894 # 0 +0xD08F 0x8895 # 0 +0xD090 0x8897 # 0 +0xD091 0x8898 # 0 +0xD092 0x8899 # 0 +0xD093 0x889A # 0 +0xD094 0x889B # 0 +0xD095 0x889D # 0 +0xD096 0x889E # 0 +0xD097 0x889F # 0 +0xD098 0x88A0 # 0 +0xD099 0x88A1 # 0 +0xD09A 0x88A3 # 0 +0xD09B 0x88A5 # 0 +0xD09C 0x88A6 # 0 +0xD09D 0x88A7 # 0 +0xD09E 0x88A8 # 0 +0xD09F 0x88A9 # 0 +0xD0A0 0x88AA # 0 +0xD0A1 0x5C0F # 0 +0xD0A2 0x5B5D # 0 +0xD0A3 0x6821 # 0 +0xD0A4 0x8096 # 0 +0xD0A5 0x5578 # 0 +0xD0A6 0x7B11 # 0 +0xD0A7 0x6548 # 0 +0xD0A8 0x6954 # 0 +0xD0A9 0x4E9B # 0 +0xD0AA 0x6B47 # 0 +0xD0AB 0x874E # 0 +0xD0AC 0x978B # 0 +0xD0AD 0x534F # 0 +0xD0AE 0x631F # 0 +0xD0AF 0x643A # 0 +0xD0B0 0x90AA # 0 +0xD0B1 0x659C # 0 +0xD0B2 0x80C1 # 0 +0xD0B3 0x8C10 # 0 +0xD0B4 0x5199 # 0 +0xD0B5 0x68B0 # 0 +0xD0B6 0x5378 # 0 +0xD0B7 0x87F9 # 0 +0xD0B8 0x61C8 # 0 +0xD0B9 0x6CC4 # 0 +0xD0BA 0x6CFB # 0 +0xD0BB 0x8C22 # 0 +0xD0BC 0x5C51 # 0 +0xD0BD 0x85AA # 0 +0xD0BE 0x82AF # 0 +0xD0BF 0x950C # 0 +0xD0C0 0x6B23 # 0 +0xD0C1 0x8F9B # 0 +0xD0C2 0x65B0 # 0 +0xD0C3 0x5FFB # 0 +0xD0C4 0x5FC3 # 0 +0xD0C5 0x4FE1 # 0 +0xD0C6 0x8845 # 0 +0xD0C7 0x661F # 0 +0xD0C8 0x8165 # 0 +0xD0C9 0x7329 # 0 +0xD0CA 0x60FA # 0 +0xD0CB 0x5174 # 0 +0xD0CC 0x5211 # 0 +0xD0CD 0x578B # 0 +0xD0CE 0x5F62 # 0 +0xD0CF 0x90A2 # 0 +0xD0D0 0x884C # 0 +0xD0D1 0x9192 # 0 +0xD0D2 0x5E78 # 0 +0xD0D3 0x674F # 0 +0xD0D4 0x6027 # 0 +0xD0D5 0x59D3 # 0 +0xD0D6 0x5144 # 0 +0xD0D7 0x51F6 # 0 +0xD0D8 0x80F8 # 0 +0xD0D9 0x5308 # 0 +0xD0DA 0x6C79 # 0 +0xD0DB 0x96C4 # 0 +0xD0DC 0x718A # 0 +0xD0DD 0x4F11 # 0 +0xD0DE 0x4FEE # 0 +0xD0DF 0x7F9E # 0 +0xD0E0 0x673D # 0 +0xD0E1 0x55C5 # 0 +0xD0E2 0x9508 # 0 +0xD0E3 0x79C0 # 0 +0xD0E4 0x8896 # 0 +0xD0E5 0x7EE3 # 0 +0xD0E6 0x589F # 0 +0xD0E7 0x620C # 0 +0xD0E8 0x9700 # 0 +0xD0E9 0x865A # 0 +0xD0EA 0x5618 # 0 +0xD0EB 0x987B # 0 +0xD0EC 0x5F90 # 0 +0xD0ED 0x8BB8 # 0 +0xD0EE 0x84C4 # 0 +0xD0EF 0x9157 # 0 +0xD0F0 0x53D9 # 0 +0xD0F1 0x65ED # 0 +0xD0F2 0x5E8F # 0 +0xD0F3 0x755C # 0 +0xD0F4 0x6064 # 0 +0xD0F5 0x7D6E # 0 +0xD0F6 0x5A7F # 0 +0xD0F7 0x7EEA # 0 +0xD0F8 0x7EED # 0 +0xD0F9 0x8F69 # 0 +0xD0FA 0x55A7 # 0 +0xD0FB 0x5BA3 # 0 +0xD0FC 0x60AC # 0 +0xD0FD 0x65CB # 0 +0xD0FE 0x7384 # 0 +0xD140 0x88AC # 0 +0xD141 0x88AE # 0 +0xD142 0x88AF # 0 +0xD143 0x88B0 # 0 +0xD144 0x88B2 # 0 +0xD145 0x88B3 # 0 +0xD146 0x88B4 # 0 +0xD147 0x88B5 # 0 +0xD148 0x88B6 # 0 +0xD149 0x88B8 # 0 +0xD14A 0x88B9 # 0 +0xD14B 0x88BA # 0 +0xD14C 0x88BB # 0 +0xD14D 0x88BD # 0 +0xD14E 0x88BE # 0 +0xD14F 0x88BF # 0 +0xD150 0x88C0 # 0 +0xD151 0x88C3 # 0 +0xD152 0x88C4 # 0 +0xD153 0x88C7 # 0 +0xD154 0x88C8 # 0 +0xD155 0x88CA # 0 +0xD156 0x88CB # 0 +0xD157 0x88CC # 0 +0xD158 0x88CD # 0 +0xD159 0x88CF # 0 +0xD15A 0x88D0 # 0 +0xD15B 0x88D1 # 0 +0xD15C 0x88D3 # 0 +0xD15D 0x88D6 # 0 +0xD15E 0x88D7 # 0 +0xD15F 0x88DA # 0 +0xD160 0x88DB # 0 +0xD161 0x88DC # 0 +0xD162 0x88DD # 0 +0xD163 0x88DE # 0 +0xD164 0x88E0 # 0 +0xD165 0x88E1 # 0 +0xD166 0x88E6 # 0 +0xD167 0x88E7 # 0 +0xD168 0x88E9 # 0 +0xD169 0x88EA # 0 +0xD16A 0x88EB # 0 +0xD16B 0x88EC # 0 +0xD16C 0x88ED # 0 +0xD16D 0x88EE # 0 +0xD16E 0x88EF # 0 +0xD16F 0x88F2 # 0 +0xD170 0x88F5 # 0 +0xD171 0x88F6 # 0 +0xD172 0x88F7 # 0 +0xD173 0x88FA # 0 +0xD174 0x88FB # 0 +0xD175 0x88FD # 0 +0xD176 0x88FF # 0 +0xD177 0x8900 # 0 +0xD178 0x8901 # 0 +0xD179 0x8903 # 0 +0xD17A 0x8904 # 0 +0xD17B 0x8905 # 0 +0xD17C 0x8906 # 0 +0xD17D 0x8907 # 0 +0xD17E 0x8908 # 0 +0xD180 0x8909 # 0 +0xD181 0x890B # 0 +0xD182 0x890C # 0 +0xD183 0x890D # 0 +0xD184 0x890E # 0 +0xD185 0x890F # 0 +0xD186 0x8911 # 0 +0xD187 0x8914 # 0 +0xD188 0x8915 # 0 +0xD189 0x8916 # 0 +0xD18A 0x8917 # 0 +0xD18B 0x8918 # 0 +0xD18C 0x891C # 0 +0xD18D 0x891D # 0 +0xD18E 0x891E # 0 +0xD18F 0x891F # 0 +0xD190 0x8920 # 0 +0xD191 0x8922 # 0 +0xD192 0x8923 # 0 +0xD193 0x8924 # 0 +0xD194 0x8926 # 0 +0xD195 0x8927 # 0 +0xD196 0x8928 # 0 +0xD197 0x8929 # 0 +0xD198 0x892C # 0 +0xD199 0x892D # 0 +0xD19A 0x892E # 0 +0xD19B 0x892F # 0 +0xD19C 0x8931 # 0 +0xD19D 0x8932 # 0 +0xD19E 0x8933 # 0 +0xD19F 0x8935 # 0 +0xD1A0 0x8937 # 0 +0xD1A1 0x9009 # 0 +0xD1A2 0x7663 # 0 +0xD1A3 0x7729 # 0 +0xD1A4 0x7EDA # 0 +0xD1A5 0x9774 # 0 +0xD1A6 0x859B # 0 +0xD1A7 0x5B66 # 0 +0xD1A8 0x7A74 # 0 +0xD1A9 0x96EA # 0 +0xD1AA 0x8840 # 0 +0xD1AB 0x52CB # 0 +0xD1AC 0x718F # 0 +0xD1AD 0x5FAA # 0 +0xD1AE 0x65EC # 0 +0xD1AF 0x8BE2 # 0 +0xD1B0 0x5BFB # 0 +0xD1B1 0x9A6F # 0 +0xD1B2 0x5DE1 # 0 +0xD1B3 0x6B89 # 0 +0xD1B4 0x6C5B # 0 +0xD1B5 0x8BAD # 0 +0xD1B6 0x8BAF # 0 +0xD1B7 0x900A # 0 +0xD1B8 0x8FC5 # 0 +0xD1B9 0x538B # 0 +0xD1BA 0x62BC # 0 +0xD1BB 0x9E26 # 0 +0xD1BC 0x9E2D # 0 +0xD1BD 0x5440 # 0 +0xD1BE 0x4E2B # 0 +0xD1BF 0x82BD # 0 +0xD1C0 0x7259 # 0 +0xD1C1 0x869C # 0 +0xD1C2 0x5D16 # 0 +0xD1C3 0x8859 # 0 +0xD1C4 0x6DAF # 0 +0xD1C5 0x96C5 # 0 +0xD1C6 0x54D1 # 0 +0xD1C7 0x4E9A # 0 +0xD1C8 0x8BB6 # 0 +0xD1C9 0x7109 # 0 +0xD1CA 0x54BD # 0 +0xD1CB 0x9609 # 0 +0xD1CC 0x70DF # 0 +0xD1CD 0x6DF9 # 0 +0xD1CE 0x76D0 # 0 +0xD1CF 0x4E25 # 0 +0xD1D0 0x7814 # 0 +0xD1D1 0x8712 # 0 +0xD1D2 0x5CA9 # 0 +0xD1D3 0x5EF6 # 0 +0xD1D4 0x8A00 # 0 +0xD1D5 0x989C # 0 +0xD1D6 0x960E # 0 +0xD1D7 0x708E # 0 +0xD1D8 0x6CBF # 0 +0xD1D9 0x5944 # 0 +0xD1DA 0x63A9 # 0 +0xD1DB 0x773C # 0 +0xD1DC 0x884D # 0 +0xD1DD 0x6F14 # 0 +0xD1DE 0x8273 # 0 +0xD1DF 0x5830 # 0 +0xD1E0 0x71D5 # 0 +0xD1E1 0x538C # 0 +0xD1E2 0x781A # 0 +0xD1E3 0x96C1 # 0 +0xD1E4 0x5501 # 0 +0xD1E5 0x5F66 # 0 +0xD1E6 0x7130 # 0 +0xD1E7 0x5BB4 # 0 +0xD1E8 0x8C1A # 0 +0xD1E9 0x9A8C # 0 +0xD1EA 0x6B83 # 0 +0xD1EB 0x592E # 0 +0xD1EC 0x9E2F # 0 +0xD1ED 0x79E7 # 0 +0xD1EE 0x6768 # 0 +0xD1EF 0x626C # 0 +0xD1F0 0x4F6F # 0 +0xD1F1 0x75A1 # 0 +0xD1F2 0x7F8A # 0 +0xD1F3 0x6D0B # 0 +0xD1F4 0x9633 # 0 +0xD1F5 0x6C27 # 0 +0xD1F6 0x4EF0 # 0 +0xD1F7 0x75D2 # 0 +0xD1F8 0x517B # 0 +0xD1F9 0x6837 # 0 +0xD1FA 0x6F3E # 0 +0xD1FB 0x9080 # 0 +0xD1FC 0x8170 # 0 +0xD1FD 0x5996 # 0 +0xD1FE 0x7476 # 0 +0xD240 0x8938 # 0 +0xD241 0x8939 # 0 +0xD242 0x893A # 0 +0xD243 0x893B # 0 +0xD244 0x893C # 0 +0xD245 0x893D # 0 +0xD246 0x893E # 0 +0xD247 0x893F # 0 +0xD248 0x8940 # 0 +0xD249 0x8942 # 0 +0xD24A 0x8943 # 0 +0xD24B 0x8945 # 0 +0xD24C 0x8946 # 0 +0xD24D 0x8947 # 0 +0xD24E 0x8948 # 0 +0xD24F 0x8949 # 0 +0xD250 0x894A # 0 +0xD251 0x894B # 0 +0xD252 0x894C # 0 +0xD253 0x894D # 0 +0xD254 0x894E # 0 +0xD255 0x894F # 0 +0xD256 0x8950 # 0 +0xD257 0x8951 # 0 +0xD258 0x8952 # 0 +0xD259 0x8953 # 0 +0xD25A 0x8954 # 0 +0xD25B 0x8955 # 0 +0xD25C 0x8956 # 0 +0xD25D 0x8957 # 0 +0xD25E 0x8958 # 0 +0xD25F 0x8959 # 0 +0xD260 0x895A # 0 +0xD261 0x895B # 0 +0xD262 0x895C # 0 +0xD263 0x895D # 0 +0xD264 0x8960 # 0 +0xD265 0x8961 # 0 +0xD266 0x8962 # 0 +0xD267 0x8963 # 0 +0xD268 0x8964 # 0 +0xD269 0x8965 # 0 +0xD26A 0x8967 # 0 +0xD26B 0x8968 # 0 +0xD26C 0x8969 # 0 +0xD26D 0x896A # 0 +0xD26E 0x896B # 0 +0xD26F 0x896C # 0 +0xD270 0x896D # 0 +0xD271 0x896E # 0 +0xD272 0x896F # 0 +0xD273 0x8970 # 0 +0xD274 0x8971 # 0 +0xD275 0x8972 # 0 +0xD276 0x8973 # 0 +0xD277 0x8974 # 0 +0xD278 0x8975 # 0 +0xD279 0x8976 # 0 +0xD27A 0x8977 # 0 +0xD27B 0x8978 # 0 +0xD27C 0x8979 # 0 +0xD27D 0x897A # 0 +0xD27E 0x897C # 0 +0xD280 0x897D # 0 +0xD281 0x897E # 0 +0xD282 0x8980 # 0 +0xD283 0x8982 # 0 +0xD284 0x8984 # 0 +0xD285 0x8985 # 0 +0xD286 0x8987 # 0 +0xD287 0x8988 # 0 +0xD288 0x8989 # 0 +0xD289 0x898A # 0 +0xD28A 0x898B # 0 +0xD28B 0x898C # 0 +0xD28C 0x898D # 0 +0xD28D 0x898E # 0 +0xD28E 0x898F # 0 +0xD28F 0x8990 # 0 +0xD290 0x8991 # 0 +0xD291 0x8992 # 0 +0xD292 0x8993 # 0 +0xD293 0x8994 # 0 +0xD294 0x8995 # 0 +0xD295 0x8996 # 0 +0xD296 0x8997 # 0 +0xD297 0x8998 # 0 +0xD298 0x8999 # 0 +0xD299 0x899A # 0 +0xD29A 0x899B # 0 +0xD29B 0x899C # 0 +0xD29C 0x899D # 0 +0xD29D 0x899E # 0 +0xD29E 0x899F # 0 +0xD29F 0x89A0 # 0 +0xD2A0 0x89A1 # 0 +0xD2A1 0x6447 # 0 +0xD2A2 0x5C27 # 0 +0xD2A3 0x9065 # 0 +0xD2A4 0x7A91 # 0 +0xD2A5 0x8C23 # 0 +0xD2A6 0x59DA # 0 +0xD2A7 0x54AC # 0 +0xD2A8 0x8200 # 0 +0xD2A9 0x836F # 0 +0xD2AA 0x8981 # 0 +0xD2AB 0x8000 # 0 +0xD2AC 0x6930 # 0 +0xD2AD 0x564E # 0 +0xD2AE 0x8036 # 0 +0xD2AF 0x7237 # 0 +0xD2B0 0x91CE # 0 +0xD2B1 0x51B6 # 0 +0xD2B2 0x4E5F # 0 +0xD2B3 0x9875 # 0 +0xD2B4 0x6396 # 0 +0xD2B5 0x4E1A # 0 +0xD2B6 0x53F6 # 0 +0xD2B7 0x66F3 # 0 +0xD2B8 0x814B # 0 +0xD2B9 0x591C # 0 +0xD2BA 0x6DB2 # 0 +0xD2BB 0x4E00 # 0 +0xD2BC 0x58F9 # 0 +0xD2BD 0x533B # 0 +0xD2BE 0x63D6 # 0 +0xD2BF 0x94F1 # 0 +0xD2C0 0x4F9D # 0 +0xD2C1 0x4F0A # 0 +0xD2C2 0x8863 # 0 +0xD2C3 0x9890 # 0 +0xD2C4 0x5937 # 0 +0xD2C5 0x9057 # 0 +0xD2C6 0x79FB # 0 +0xD2C7 0x4EEA # 0 +0xD2C8 0x80F0 # 0 +0xD2C9 0x7591 # 0 +0xD2CA 0x6C82 # 0 +0xD2CB 0x5B9C # 0 +0xD2CC 0x59E8 # 0 +0xD2CD 0x5F5D # 0 +0xD2CE 0x6905 # 0 +0xD2CF 0x8681 # 0 +0xD2D0 0x501A # 0 +0xD2D1 0x5DF2 # 0 +0xD2D2 0x4E59 # 0 +0xD2D3 0x77E3 # 0 +0xD2D4 0x4EE5 # 0 +0xD2D5 0x827A # 0 +0xD2D6 0x6291 # 0 +0xD2D7 0x6613 # 0 +0xD2D8 0x9091 # 0 +0xD2D9 0x5C79 # 0 +0xD2DA 0x4EBF # 0 +0xD2DB 0x5F79 # 0 +0xD2DC 0x81C6 # 0 +0xD2DD 0x9038 # 0 +0xD2DE 0x8084 # 0 +0xD2DF 0x75AB # 0 +0xD2E0 0x4EA6 # 0 +0xD2E1 0x88D4 # 0 +0xD2E2 0x610F # 0 +0xD2E3 0x6BC5 # 0 +0xD2E4 0x5FC6 # 0 +0xD2E5 0x4E49 # 0 +0xD2E6 0x76CA # 0 +0xD2E7 0x6EA2 # 0 +0xD2E8 0x8BE3 # 0 +0xD2E9 0x8BAE # 0 +0xD2EA 0x8C0A # 0 +0xD2EB 0x8BD1 # 0 +0xD2EC 0x5F02 # 0 +0xD2ED 0x7FFC # 0 +0xD2EE 0x7FCC # 0 +0xD2EF 0x7ECE # 0 +0xD2F0 0x8335 # 0 +0xD2F1 0x836B # 0 +0xD2F2 0x56E0 # 0 +0xD2F3 0x6BB7 # 0 +0xD2F4 0x97F3 # 0 +0xD2F5 0x9634 # 0 +0xD2F6 0x59FB # 0 +0xD2F7 0x541F # 0 +0xD2F8 0x94F6 # 0 +0xD2F9 0x6DEB # 0 +0xD2FA 0x5BC5 # 0 +0xD2FB 0x996E # 0 +0xD2FC 0x5C39 # 0 +0xD2FD 0x5F15 # 0 +0xD2FE 0x9690 # 0 +0xD340 0x89A2 # 0 +0xD341 0x89A3 # 0 +0xD342 0x89A4 # 0 +0xD343 0x89A5 # 0 +0xD344 0x89A6 # 0 +0xD345 0x89A7 # 0 +0xD346 0x89A8 # 0 +0xD347 0x89A9 # 0 +0xD348 0x89AA # 0 +0xD349 0x89AB # 0 +0xD34A 0x89AC # 0 +0xD34B 0x89AD # 0 +0xD34C 0x89AE # 0 +0xD34D 0x89AF # 0 +0xD34E 0x89B0 # 0 +0xD34F 0x89B1 # 0 +0xD350 0x89B2 # 0 +0xD351 0x89B3 # 0 +0xD352 0x89B4 # 0 +0xD353 0x89B5 # 0 +0xD354 0x89B6 # 0 +0xD355 0x89B7 # 0 +0xD356 0x89B8 # 0 +0xD357 0x89B9 # 0 +0xD358 0x89BA # 0 +0xD359 0x89BB # 0 +0xD35A 0x89BC # 0 +0xD35B 0x89BD # 0 +0xD35C 0x89BE # 0 +0xD35D 0x89BF # 0 +0xD35E 0x89C0 # 0 +0xD35F 0x89C3 # 0 +0xD360 0x89CD # 0 +0xD361 0x89D3 # 0 +0xD362 0x89D4 # 0 +0xD363 0x89D5 # 0 +0xD364 0x89D7 # 0 +0xD365 0x89D8 # 0 +0xD366 0x89D9 # 0 +0xD367 0x89DB # 0 +0xD368 0x89DD # 0 +0xD369 0x89DF # 0 +0xD36A 0x89E0 # 0 +0xD36B 0x89E1 # 0 +0xD36C 0x89E2 # 0 +0xD36D 0x89E4 # 0 +0xD36E 0x89E7 # 0 +0xD36F 0x89E8 # 0 +0xD370 0x89E9 # 0 +0xD371 0x89EA # 0 +0xD372 0x89EC # 0 +0xD373 0x89ED # 0 +0xD374 0x89EE # 0 +0xD375 0x89F0 # 0 +0xD376 0x89F1 # 0 +0xD377 0x89F2 # 0 +0xD378 0x89F4 # 0 +0xD379 0x89F5 # 0 +0xD37A 0x89F6 # 0 +0xD37B 0x89F7 # 0 +0xD37C 0x89F8 # 0 +0xD37D 0x89F9 # 0 +0xD37E 0x89FA # 0 +0xD380 0x89FB # 0 +0xD381 0x89FC # 0 +0xD382 0x89FD # 0 +0xD383 0x89FE # 0 +0xD384 0x89FF # 0 +0xD385 0x8A01 # 0 +0xD386 0x8A02 # 0 +0xD387 0x8A03 # 0 +0xD388 0x8A04 # 0 +0xD389 0x8A05 # 0 +0xD38A 0x8A06 # 0 +0xD38B 0x8A08 # 0 +0xD38C 0x8A09 # 0 +0xD38D 0x8A0A # 0 +0xD38E 0x8A0B # 0 +0xD38F 0x8A0C # 0 +0xD390 0x8A0D # 0 +0xD391 0x8A0E # 0 +0xD392 0x8A0F # 0 +0xD393 0x8A10 # 0 +0xD394 0x8A11 # 0 +0xD395 0x8A12 # 0 +0xD396 0x8A13 # 0 +0xD397 0x8A14 # 0 +0xD398 0x8A15 # 0 +0xD399 0x8A16 # 0 +0xD39A 0x8A17 # 0 +0xD39B 0x8A18 # 0 +0xD39C 0x8A19 # 0 +0xD39D 0x8A1A # 0 +0xD39E 0x8A1B # 0 +0xD39F 0x8A1C # 0 +0xD3A0 0x8A1D # 0 +0xD3A1 0x5370 # 0 +0xD3A2 0x82F1 # 0 +0xD3A3 0x6A31 # 0 +0xD3A4 0x5A74 # 0 +0xD3A5 0x9E70 # 0 +0xD3A6 0x5E94 # 0 +0xD3A7 0x7F28 # 0 +0xD3A8 0x83B9 # 0 +0xD3A9 0x8424 # 0 +0xD3AA 0x8425 # 0 +0xD3AB 0x8367 # 0 +0xD3AC 0x8747 # 0 +0xD3AD 0x8FCE # 0 +0xD3AE 0x8D62 # 0 +0xD3AF 0x76C8 # 0 +0xD3B0 0x5F71 # 0 +0xD3B1 0x9896 # 0 +0xD3B2 0x786C # 0 +0xD3B3 0x6620 # 0 +0xD3B4 0x54DF # 0 +0xD3B5 0x62E5 # 0 +0xD3B6 0x4F63 # 0 +0xD3B7 0x81C3 # 0 +0xD3B8 0x75C8 # 0 +0xD3B9 0x5EB8 # 0 +0xD3BA 0x96CD # 0 +0xD3BB 0x8E0A # 0 +0xD3BC 0x86F9 # 0 +0xD3BD 0x548F # 0 +0xD3BE 0x6CF3 # 0 +0xD3BF 0x6D8C # 0 +0xD3C0 0x6C38 # 0 +0xD3C1 0x607F # 0 +0xD3C2 0x52C7 # 0 +0xD3C3 0x7528 # 0 +0xD3C4 0x5E7D # 0 +0xD3C5 0x4F18 # 0 +0xD3C6 0x60A0 # 0 +0xD3C7 0x5FE7 # 0 +0xD3C8 0x5C24 # 0 +0xD3C9 0x7531 # 0 +0xD3CA 0x90AE # 0 +0xD3CB 0x94C0 # 0 +0xD3CC 0x72B9 # 0 +0xD3CD 0x6CB9 # 0 +0xD3CE 0x6E38 # 0 +0xD3CF 0x9149 # 0 +0xD3D0 0x6709 # 0 +0xD3D1 0x53CB # 0 +0xD3D2 0x53F3 # 0 +0xD3D3 0x4F51 # 0 +0xD3D4 0x91C9 # 0 +0xD3D5 0x8BF1 # 0 +0xD3D6 0x53C8 # 0 +0xD3D7 0x5E7C # 0 +0xD3D8 0x8FC2 # 0 +0xD3D9 0x6DE4 # 0 +0xD3DA 0x4E8E # 0 +0xD3DB 0x76C2 # 0 +0xD3DC 0x6986 # 0 +0xD3DD 0x865E # 0 +0xD3DE 0x611A # 0 +0xD3DF 0x8206 # 0 +0xD3E0 0x4F59 # 0 +0xD3E1 0x4FDE # 0 +0xD3E2 0x903E # 0 +0xD3E3 0x9C7C # 0 +0xD3E4 0x6109 # 0 +0xD3E5 0x6E1D # 0 +0xD3E6 0x6E14 # 0 +0xD3E7 0x9685 # 0 +0xD3E8 0x4E88 # 0 +0xD3E9 0x5A31 # 0 +0xD3EA 0x96E8 # 0 +0xD3EB 0x4E0E # 0 +0xD3EC 0x5C7F # 0 +0xD3ED 0x79B9 # 0 +0xD3EE 0x5B87 # 0 +0xD3EF 0x8BED # 0 +0xD3F0 0x7FBD # 0 +0xD3F1 0x7389 # 0 +0xD3F2 0x57DF # 0 +0xD3F3 0x828B # 0 +0xD3F4 0x90C1 # 0 +0xD3F5 0x5401 # 0 +0xD3F6 0x9047 # 0 +0xD3F7 0x55BB # 0 +0xD3F8 0x5CEA # 0 +0xD3F9 0x5FA1 # 0 +0xD3FA 0x6108 # 0 +0xD3FB 0x6B32 # 0 +0xD3FC 0x72F1 # 0 +0xD3FD 0x80B2 # 0 +0xD3FE 0x8A89 # 0 +0xD440 0x8A1E # 0 +0xD441 0x8A1F # 0 +0xD442 0x8A20 # 0 +0xD443 0x8A21 # 0 +0xD444 0x8A22 # 0 +0xD445 0x8A23 # 0 +0xD446 0x8A24 # 0 +0xD447 0x8A25 # 0 +0xD448 0x8A26 # 0 +0xD449 0x8A27 # 0 +0xD44A 0x8A28 # 0 +0xD44B 0x8A29 # 0 +0xD44C 0x8A2A # 0 +0xD44D 0x8A2B # 0 +0xD44E 0x8A2C # 0 +0xD44F 0x8A2D # 0 +0xD450 0x8A2E # 0 +0xD451 0x8A2F # 0 +0xD452 0x8A30 # 0 +0xD453 0x8A31 # 0 +0xD454 0x8A32 # 0 +0xD455 0x8A33 # 0 +0xD456 0x8A34 # 0 +0xD457 0x8A35 # 0 +0xD458 0x8A36 # 0 +0xD459 0x8A37 # 0 +0xD45A 0x8A38 # 0 +0xD45B 0x8A39 # 0 +0xD45C 0x8A3A # 0 +0xD45D 0x8A3B # 0 +0xD45E 0x8A3C # 0 +0xD45F 0x8A3D # 0 +0xD460 0x8A3F # 0 +0xD461 0x8A40 # 0 +0xD462 0x8A41 # 0 +0xD463 0x8A42 # 0 +0xD464 0x8A43 # 0 +0xD465 0x8A44 # 0 +0xD466 0x8A45 # 0 +0xD467 0x8A46 # 0 +0xD468 0x8A47 # 0 +0xD469 0x8A49 # 0 +0xD46A 0x8A4A # 0 +0xD46B 0x8A4B # 0 +0xD46C 0x8A4C # 0 +0xD46D 0x8A4D # 0 +0xD46E 0x8A4E # 0 +0xD46F 0x8A4F # 0 +0xD470 0x8A50 # 0 +0xD471 0x8A51 # 0 +0xD472 0x8A52 # 0 +0xD473 0x8A53 # 0 +0xD474 0x8A54 # 0 +0xD475 0x8A55 # 0 +0xD476 0x8A56 # 0 +0xD477 0x8A57 # 0 +0xD478 0x8A58 # 0 +0xD479 0x8A59 # 0 +0xD47A 0x8A5A # 0 +0xD47B 0x8A5B # 0 +0xD47C 0x8A5C # 0 +0xD47D 0x8A5D # 0 +0xD47E 0x8A5E # 0 +0xD480 0x8A5F # 0 +0xD481 0x8A60 # 0 +0xD482 0x8A61 # 0 +0xD483 0x8A62 # 0 +0xD484 0x8A63 # 0 +0xD485 0x8A64 # 0 +0xD486 0x8A65 # 0 +0xD487 0x8A66 # 0 +0xD488 0x8A67 # 0 +0xD489 0x8A68 # 0 +0xD48A 0x8A69 # 0 +0xD48B 0x8A6A # 0 +0xD48C 0x8A6B # 0 +0xD48D 0x8A6C # 0 +0xD48E 0x8A6D # 0 +0xD48F 0x8A6E # 0 +0xD490 0x8A6F # 0 +0xD491 0x8A70 # 0 +0xD492 0x8A71 # 0 +0xD493 0x8A72 # 0 +0xD494 0x8A73 # 0 +0xD495 0x8A74 # 0 +0xD496 0x8A75 # 0 +0xD497 0x8A76 # 0 +0xD498 0x8A77 # 0 +0xD499 0x8A78 # 0 +0xD49A 0x8A7A # 0 +0xD49B 0x8A7B # 0 +0xD49C 0x8A7C # 0 +0xD49D 0x8A7D # 0 +0xD49E 0x8A7E # 0 +0xD49F 0x8A7F # 0 +0xD4A0 0x8A80 # 0 +0xD4A1 0x6D74 # 0 +0xD4A2 0x5BD3 # 0 +0xD4A3 0x88D5 # 0 +0xD4A4 0x9884 # 0 +0xD4A5 0x8C6B # 0 +0xD4A6 0x9A6D # 0 +0xD4A7 0x9E33 # 0 +0xD4A8 0x6E0A # 0 +0xD4A9 0x51A4 # 0 +0xD4AA 0x5143 # 0 +0xD4AB 0x57A3 # 0 +0xD4AC 0x8881 # 0 +0xD4AD 0x539F # 0 +0xD4AE 0x63F4 # 0 +0xD4AF 0x8F95 # 0 +0xD4B0 0x56ED # 0 +0xD4B1 0x5458 # 0 +0xD4B2 0x5706 # 0 +0xD4B3 0x733F # 0 +0xD4B4 0x6E90 # 0 +0xD4B5 0x7F18 # 0 +0xD4B6 0x8FDC # 0 +0xD4B7 0x82D1 # 0 +0xD4B8 0x613F # 0 +0xD4B9 0x6028 # 0 +0xD4BA 0x9662 # 0 +0xD4BB 0x66F0 # 0 +0xD4BC 0x7EA6 # 0 +0xD4BD 0x8D8A # 0 +0xD4BE 0x8DC3 # 0 +0xD4BF 0x94A5 # 0 +0xD4C0 0x5CB3 # 0 +0xD4C1 0x7CA4 # 0 +0xD4C2 0x6708 # 0 +0xD4C3 0x60A6 # 0 +0xD4C4 0x9605 # 0 +0xD4C5 0x8018 # 0 +0xD4C6 0x4E91 # 0 +0xD4C7 0x90E7 # 0 +0xD4C8 0x5300 # 0 +0xD4C9 0x9668 # 0 +0xD4CA 0x5141 # 0 +0xD4CB 0x8FD0 # 0 +0xD4CC 0x8574 # 0 +0xD4CD 0x915D # 0 +0xD4CE 0x6655 # 0 +0xD4CF 0x97F5 # 0 +0xD4D0 0x5B55 # 0 +0xD4D1 0x531D # 0 +0xD4D2 0x7838 # 0 +0xD4D3 0x6742 # 0 +0xD4D4 0x683D # 0 +0xD4D5 0x54C9 # 0 +0xD4D6 0x707E # 0 +0xD4D7 0x5BB0 # 0 +0xD4D8 0x8F7D # 0 +0xD4D9 0x518D # 0 +0xD4DA 0x5728 # 0 +0xD4DB 0x54B1 # 0 +0xD4DC 0x6512 # 0 +0xD4DD 0x6682 # 0 +0xD4DE 0x8D5E # 0 +0xD4DF 0x8D43 # 0 +0xD4E0 0x810F # 0 +0xD4E1 0x846C # 0 +0xD4E2 0x906D # 0 +0xD4E3 0x7CDF # 0 +0xD4E4 0x51FF # 0 +0xD4E5 0x85FB # 0 +0xD4E6 0x67A3 # 0 +0xD4E7 0x65E9 # 0 +0xD4E8 0x6FA1 # 0 +0xD4E9 0x86A4 # 0 +0xD4EA 0x8E81 # 0 +0xD4EB 0x566A # 0 +0xD4EC 0x9020 # 0 +0xD4ED 0x7682 # 0 +0xD4EE 0x7076 # 0 +0xD4EF 0x71E5 # 0 +0xD4F0 0x8D23 # 0 +0xD4F1 0x62E9 # 0 +0xD4F2 0x5219 # 0 +0xD4F3 0x6CFD # 0 +0xD4F4 0x8D3C # 0 +0xD4F5 0x600E # 0 +0xD4F6 0x589E # 0 +0xD4F7 0x618E # 0 +0xD4F8 0x66FE # 0 +0xD4F9 0x8D60 # 0 +0xD4FA 0x624E # 0 +0xD4FB 0x55B3 # 0 +0xD4FC 0x6E23 # 0 +0xD4FD 0x672D # 0 +0xD4FE 0x8F67 # 0 +0xD540 0x8A81 # 0 +0xD541 0x8A82 # 0 +0xD542 0x8A83 # 0 +0xD543 0x8A84 # 0 +0xD544 0x8A85 # 0 +0xD545 0x8A86 # 0 +0xD546 0x8A87 # 0 +0xD547 0x8A88 # 0 +0xD548 0x8A8B # 0 +0xD549 0x8A8C # 0 +0xD54A 0x8A8D # 0 +0xD54B 0x8A8E # 0 +0xD54C 0x8A8F # 0 +0xD54D 0x8A90 # 0 +0xD54E 0x8A91 # 0 +0xD54F 0x8A92 # 0 +0xD550 0x8A94 # 0 +0xD551 0x8A95 # 0 +0xD552 0x8A96 # 0 +0xD553 0x8A97 # 0 +0xD554 0x8A98 # 0 +0xD555 0x8A99 # 0 +0xD556 0x8A9A # 0 +0xD557 0x8A9B # 0 +0xD558 0x8A9C # 0 +0xD559 0x8A9D # 0 +0xD55A 0x8A9E # 0 +0xD55B 0x8A9F # 0 +0xD55C 0x8AA0 # 0 +0xD55D 0x8AA1 # 0 +0xD55E 0x8AA2 # 0 +0xD55F 0x8AA3 # 0 +0xD560 0x8AA4 # 0 +0xD561 0x8AA5 # 0 +0xD562 0x8AA6 # 0 +0xD563 0x8AA7 # 0 +0xD564 0x8AA8 # 0 +0xD565 0x8AA9 # 0 +0xD566 0x8AAA # 0 +0xD567 0x8AAB # 0 +0xD568 0x8AAC # 0 +0xD569 0x8AAD # 0 +0xD56A 0x8AAE # 0 +0xD56B 0x8AAF # 0 +0xD56C 0x8AB0 # 0 +0xD56D 0x8AB1 # 0 +0xD56E 0x8AB2 # 0 +0xD56F 0x8AB3 # 0 +0xD570 0x8AB4 # 0 +0xD571 0x8AB5 # 0 +0xD572 0x8AB6 # 0 +0xD573 0x8AB7 # 0 +0xD574 0x8AB8 # 0 +0xD575 0x8AB9 # 0 +0xD576 0x8ABA # 0 +0xD577 0x8ABB # 0 +0xD578 0x8ABC # 0 +0xD579 0x8ABD # 0 +0xD57A 0x8ABE # 0 +0xD57B 0x8ABF # 0 +0xD57C 0x8AC0 # 0 +0xD57D 0x8AC1 # 0 +0xD57E 0x8AC2 # 0 +0xD580 0x8AC3 # 0 +0xD581 0x8AC4 # 0 +0xD582 0x8AC5 # 0 +0xD583 0x8AC6 # 0 +0xD584 0x8AC7 # 0 +0xD585 0x8AC8 # 0 +0xD586 0x8AC9 # 0 +0xD587 0x8ACA # 0 +0xD588 0x8ACB # 0 +0xD589 0x8ACC # 0 +0xD58A 0x8ACD # 0 +0xD58B 0x8ACE # 0 +0xD58C 0x8ACF # 0 +0xD58D 0x8AD0 # 0 +0xD58E 0x8AD1 # 0 +0xD58F 0x8AD2 # 0 +0xD590 0x8AD3 # 0 +0xD591 0x8AD4 # 0 +0xD592 0x8AD5 # 0 +0xD593 0x8AD6 # 0 +0xD594 0x8AD7 # 0 +0xD595 0x8AD8 # 0 +0xD596 0x8AD9 # 0 +0xD597 0x8ADA # 0 +0xD598 0x8ADB # 0 +0xD599 0x8ADC # 0 +0xD59A 0x8ADD # 0 +0xD59B 0x8ADE # 0 +0xD59C 0x8ADF # 0 +0xD59D 0x8AE0 # 0 +0xD59E 0x8AE1 # 0 +0xD59F 0x8AE2 # 0 +0xD5A0 0x8AE3 # 0 +0xD5A1 0x94E1 # 0 +0xD5A2 0x95F8 # 0 +0xD5A3 0x7728 # 0 +0xD5A4 0x6805 # 0 +0xD5A5 0x69A8 # 0 +0xD5A6 0x548B # 0 +0xD5A7 0x4E4D # 0 +0xD5A8 0x70B8 # 0 +0xD5A9 0x8BC8 # 0 +0xD5AA 0x6458 # 0 +0xD5AB 0x658B # 0 +0xD5AC 0x5B85 # 0 +0xD5AD 0x7A84 # 0 +0xD5AE 0x503A # 0 +0xD5AF 0x5BE8 # 0 +0xD5B0 0x77BB # 0 +0xD5B1 0x6BE1 # 0 +0xD5B2 0x8A79 # 0 +0xD5B3 0x7C98 # 0 +0xD5B4 0x6CBE # 0 +0xD5B5 0x76CF # 0 +0xD5B6 0x65A9 # 0 +0xD5B7 0x8F97 # 0 +0xD5B8 0x5D2D # 0 +0xD5B9 0x5C55 # 0 +0xD5BA 0x8638 # 0 +0xD5BB 0x6808 # 0 +0xD5BC 0x5360 # 0 +0xD5BD 0x6218 # 0 +0xD5BE 0x7AD9 # 0 +0xD5BF 0x6E5B # 0 +0xD5C0 0x7EFD # 0 +0xD5C1 0x6A1F # 0 +0xD5C2 0x7AE0 # 0 +0xD5C3 0x5F70 # 0 +0xD5C4 0x6F33 # 0 +0xD5C5 0x5F20 # 0 +0xD5C6 0x638C # 0 +0xD5C7 0x6DA8 # 0 +0xD5C8 0x6756 # 0 +0xD5C9 0x4E08 # 0 +0xD5CA 0x5E10 # 0 +0xD5CB 0x8D26 # 0 +0xD5CC 0x4ED7 # 0 +0xD5CD 0x80C0 # 0 +0xD5CE 0x7634 # 0 +0xD5CF 0x969C # 0 +0xD5D0 0x62DB # 0 +0xD5D1 0x662D # 0 +0xD5D2 0x627E # 0 +0xD5D3 0x6CBC # 0 +0xD5D4 0x8D75 # 0 +0xD5D5 0x7167 # 0 +0xD5D6 0x7F69 # 0 +0xD5D7 0x5146 # 0 +0xD5D8 0x8087 # 0 +0xD5D9 0x53EC # 0 +0xD5DA 0x906E # 0 +0xD5DB 0x6298 # 0 +0xD5DC 0x54F2 # 0 +0xD5DD 0x86F0 # 0 +0xD5DE 0x8F99 # 0 +0xD5DF 0x8005 # 0 +0xD5E0 0x9517 # 0 +0xD5E1 0x8517 # 0 +0xD5E2 0x8FD9 # 0 +0xD5E3 0x6D59 # 0 +0xD5E4 0x73CD # 0 +0xD5E5 0x659F # 0 +0xD5E6 0x771F # 0 +0xD5E7 0x7504 # 0 +0xD5E8 0x7827 # 0 +0xD5E9 0x81FB # 0 +0xD5EA 0x8D1E # 0 +0xD5EB 0x9488 # 0 +0xD5EC 0x4FA6 # 0 +0xD5ED 0x6795 # 0 +0xD5EE 0x75B9 # 0 +0xD5EF 0x8BCA # 0 +0xD5F0 0x9707 # 0 +0xD5F1 0x632F # 0 +0xD5F2 0x9547 # 0 +0xD5F3 0x9635 # 0 +0xD5F4 0x84B8 # 0 +0xD5F5 0x6323 # 0 +0xD5F6 0x7741 # 0 +0xD5F7 0x5F81 # 0 +0xD5F8 0x72F0 # 0 +0xD5F9 0x4E89 # 0 +0xD5FA 0x6014 # 0 +0xD5FB 0x6574 # 0 +0xD5FC 0x62EF # 0 +0xD5FD 0x6B63 # 0 +0xD5FE 0x653F # 0 +0xD640 0x8AE4 # 0 +0xD641 0x8AE5 # 0 +0xD642 0x8AE6 # 0 +0xD643 0x8AE7 # 0 +0xD644 0x8AE8 # 0 +0xD645 0x8AE9 # 0 +0xD646 0x8AEA # 0 +0xD647 0x8AEB # 0 +0xD648 0x8AEC # 0 +0xD649 0x8AED # 0 +0xD64A 0x8AEE # 0 +0xD64B 0x8AEF # 0 +0xD64C 0x8AF0 # 0 +0xD64D 0x8AF1 # 0 +0xD64E 0x8AF2 # 0 +0xD64F 0x8AF3 # 0 +0xD650 0x8AF4 # 0 +0xD651 0x8AF5 # 0 +0xD652 0x8AF6 # 0 +0xD653 0x8AF7 # 0 +0xD654 0x8AF8 # 0 +0xD655 0x8AF9 # 0 +0xD656 0x8AFA # 0 +0xD657 0x8AFB # 0 +0xD658 0x8AFC # 0 +0xD659 0x8AFD # 0 +0xD65A 0x8AFE # 0 +0xD65B 0x8AFF # 0 +0xD65C 0x8B00 # 0 +0xD65D 0x8B01 # 0 +0xD65E 0x8B02 # 0 +0xD65F 0x8B03 # 0 +0xD660 0x8B04 # 0 +0xD661 0x8B05 # 0 +0xD662 0x8B06 # 0 +0xD663 0x8B08 # 0 +0xD664 0x8B09 # 0 +0xD665 0x8B0A # 0 +0xD666 0x8B0B # 0 +0xD667 0x8B0C # 0 +0xD668 0x8B0D # 0 +0xD669 0x8B0E # 0 +0xD66A 0x8B0F # 0 +0xD66B 0x8B10 # 0 +0xD66C 0x8B11 # 0 +0xD66D 0x8B12 # 0 +0xD66E 0x8B13 # 0 +0xD66F 0x8B14 # 0 +0xD670 0x8B15 # 0 +0xD671 0x8B16 # 0 +0xD672 0x8B17 # 0 +0xD673 0x8B18 # 0 +0xD674 0x8B19 # 0 +0xD675 0x8B1A # 0 +0xD676 0x8B1B # 0 +0xD677 0x8B1C # 0 +0xD678 0x8B1D # 0 +0xD679 0x8B1E # 0 +0xD67A 0x8B1F # 0 +0xD67B 0x8B20 # 0 +0xD67C 0x8B21 # 0 +0xD67D 0x8B22 # 0 +0xD67E 0x8B23 # 0 +0xD680 0x8B24 # 0 +0xD681 0x8B25 # 0 +0xD682 0x8B27 # 0 +0xD683 0x8B28 # 0 +0xD684 0x8B29 # 0 +0xD685 0x8B2A # 0 +0xD686 0x8B2B # 0 +0xD687 0x8B2C # 0 +0xD688 0x8B2D # 0 +0xD689 0x8B2E # 0 +0xD68A 0x8B2F # 0 +0xD68B 0x8B30 # 0 +0xD68C 0x8B31 # 0 +0xD68D 0x8B32 # 0 +0xD68E 0x8B33 # 0 +0xD68F 0x8B34 # 0 +0xD690 0x8B35 # 0 +0xD691 0x8B36 # 0 +0xD692 0x8B37 # 0 +0xD693 0x8B38 # 0 +0xD694 0x8B39 # 0 +0xD695 0x8B3A # 0 +0xD696 0x8B3B # 0 +0xD697 0x8B3C # 0 +0xD698 0x8B3D # 0 +0xD699 0x8B3E # 0 +0xD69A 0x8B3F # 0 +0xD69B 0x8B40 # 0 +0xD69C 0x8B41 # 0 +0xD69D 0x8B42 # 0 +0xD69E 0x8B43 # 0 +0xD69F 0x8B44 # 0 +0xD6A0 0x8B45 # 0 +0xD6A1 0x5E27 # 0 +0xD6A2 0x75C7 # 0 +0xD6A3 0x90D1 # 0 +0xD6A4 0x8BC1 # 0 +0xD6A5 0x829D # 0 +0xD6A6 0x679D # 0 +0xD6A7 0x652F # 0 +0xD6A8 0x5431 # 0 +0xD6A9 0x8718 # 0 +0xD6AA 0x77E5 # 0 +0xD6AB 0x80A2 # 0 +0xD6AC 0x8102 # 0 +0xD6AD 0x6C41 # 0 +0xD6AE 0x4E4B # 0 +0xD6AF 0x7EC7 # 0 +0xD6B0 0x804C # 0 +0xD6B1 0x76F4 # 0 +0xD6B2 0x690D # 0 +0xD6B3 0x6B96 # 0 +0xD6B4 0x6267 # 0 +0xD6B5 0x503C # 0 +0xD6B6 0x4F84 # 0 +0xD6B7 0x5740 # 0 +0xD6B8 0x6307 # 0 +0xD6B9 0x6B62 # 0 +0xD6BA 0x8DBE # 0 +0xD6BB 0x53EA # 0 +0xD6BC 0x65E8 # 0 +0xD6BD 0x7EB8 # 0 +0xD6BE 0x5FD7 # 0 +0xD6BF 0x631A # 0 +0xD6C0 0x63B7 # 0 +0xD6C1 0x81F3 # 0 +0xD6C2 0x81F4 # 0 +0xD6C3 0x7F6E # 0 +0xD6C4 0x5E1C # 0 +0xD6C5 0x5CD9 # 0 +0xD6C6 0x5236 # 0 +0xD6C7 0x667A # 0 +0xD6C8 0x79E9 # 0 +0xD6C9 0x7A1A # 0 +0xD6CA 0x8D28 # 0 +0xD6CB 0x7099 # 0 +0xD6CC 0x75D4 # 0 +0xD6CD 0x6EDE # 0 +0xD6CE 0x6CBB # 0 +0xD6CF 0x7A92 # 0 +0xD6D0 0x4E2D # 0 +0xD6D1 0x76C5 # 0 +0xD6D2 0x5FE0 # 0 +0xD6D3 0x949F # 0 +0xD6D4 0x8877 # 0 +0xD6D5 0x7EC8 # 0 +0xD6D6 0x79CD # 0 +0xD6D7 0x80BF # 0 +0xD6D8 0x91CD # 0 +0xD6D9 0x4EF2 # 0 +0xD6DA 0x4F17 # 0 +0xD6DB 0x821F # 0 +0xD6DC 0x5468 # 0 +0xD6DD 0x5DDE # 0 +0xD6DE 0x6D32 # 0 +0xD6DF 0x8BCC # 0 +0xD6E0 0x7CA5 # 0 +0xD6E1 0x8F74 # 0 +0xD6E2 0x8098 # 0 +0xD6E3 0x5E1A # 0 +0xD6E4 0x5492 # 0 +0xD6E5 0x76B1 # 0 +0xD6E6 0x5B99 # 0 +0xD6E7 0x663C # 0 +0xD6E8 0x9AA4 # 0 +0xD6E9 0x73E0 # 0 +0xD6EA 0x682A # 0 +0xD6EB 0x86DB # 0 +0xD6EC 0x6731 # 0 +0xD6ED 0x732A # 0 +0xD6EE 0x8BF8 # 0 +0xD6EF 0x8BDB # 0 +0xD6F0 0x9010 # 0 +0xD6F1 0x7AF9 # 0 +0xD6F2 0x70DB # 0 +0xD6F3 0x716E # 0 +0xD6F4 0x62C4 # 0 +0xD6F5 0x77A9 # 0 +0xD6F6 0x5631 # 0 +0xD6F7 0x4E3B # 0 +0xD6F8 0x8457 # 0 +0xD6F9 0x67F1 # 0 +0xD6FA 0x52A9 # 0 +0xD6FB 0x86C0 # 0 +0xD6FC 0x8D2E # 0 +0xD6FD 0x94F8 # 0 +0xD6FE 0x7B51 # 0 +0xD740 0x8B46 # 0 +0xD741 0x8B47 # 0 +0xD742 0x8B48 # 0 +0xD743 0x8B49 # 0 +0xD744 0x8B4A # 0 +0xD745 0x8B4B # 0 +0xD746 0x8B4C # 0 +0xD747 0x8B4D # 0 +0xD748 0x8B4E # 0 +0xD749 0x8B4F # 0 +0xD74A 0x8B50 # 0 +0xD74B 0x8B51 # 0 +0xD74C 0x8B52 # 0 +0xD74D 0x8B53 # 0 +0xD74E 0x8B54 # 0 +0xD74F 0x8B55 # 0 +0xD750 0x8B56 # 0 +0xD751 0x8B57 # 0 +0xD752 0x8B58 # 0 +0xD753 0x8B59 # 0 +0xD754 0x8B5A # 0 +0xD755 0x8B5B # 0 +0xD756 0x8B5C # 0 +0xD757 0x8B5D # 0 +0xD758 0x8B5E # 0 +0xD759 0x8B5F # 0 +0xD75A 0x8B60 # 0 +0xD75B 0x8B61 # 0 +0xD75C 0x8B62 # 0 +0xD75D 0x8B63 # 0 +0xD75E 0x8B64 # 0 +0xD75F 0x8B65 # 0 +0xD760 0x8B67 # 0 +0xD761 0x8B68 # 0 +0xD762 0x8B69 # 0 +0xD763 0x8B6A # 0 +0xD764 0x8B6B # 0 +0xD765 0x8B6D # 0 +0xD766 0x8B6E # 0 +0xD767 0x8B6F # 0 +0xD768 0x8B70 # 0 +0xD769 0x8B71 # 0 +0xD76A 0x8B72 # 0 +0xD76B 0x8B73 # 0 +0xD76C 0x8B74 # 0 +0xD76D 0x8B75 # 0 +0xD76E 0x8B76 # 0 +0xD76F 0x8B77 # 0 +0xD770 0x8B78 # 0 +0xD771 0x8B79 # 0 +0xD772 0x8B7A # 0 +0xD773 0x8B7B # 0 +0xD774 0x8B7C # 0 +0xD775 0x8B7D # 0 +0xD776 0x8B7E # 0 +0xD777 0x8B7F # 0 +0xD778 0x8B80 # 0 +0xD779 0x8B81 # 0 +0xD77A 0x8B82 # 0 +0xD77B 0x8B83 # 0 +0xD77C 0x8B84 # 0 +0xD77D 0x8B85 # 0 +0xD77E 0x8B86 # 0 +0xD780 0x8B87 # 0 +0xD781 0x8B88 # 0 +0xD782 0x8B89 # 0 +0xD783 0x8B8A # 0 +0xD784 0x8B8B # 0 +0xD785 0x8B8C # 0 +0xD786 0x8B8D # 0 +0xD787 0x8B8E # 0 +0xD788 0x8B8F # 0 +0xD789 0x8B90 # 0 +0xD78A 0x8B91 # 0 +0xD78B 0x8B92 # 0 +0xD78C 0x8B93 # 0 +0xD78D 0x8B94 # 0 +0xD78E 0x8B95 # 0 +0xD78F 0x8B96 # 0 +0xD790 0x8B97 # 0 +0xD791 0x8B98 # 0 +0xD792 0x8B99 # 0 +0xD793 0x8B9A # 0 +0xD794 0x8B9B # 0 +0xD795 0x8B9C # 0 +0xD796 0x8B9D # 0 +0xD797 0x8B9E # 0 +0xD798 0x8B9F # 0 +0xD799 0x8BAC # 0 +0xD79A 0x8BB1 # 0 +0xD79B 0x8BBB # 0 +0xD79C 0x8BC7 # 0 +0xD79D 0x8BD0 # 0 +0xD79E 0x8BEA # 0 +0xD79F 0x8C09 # 0 +0xD7A0 0x8C1E # 0 +0xD7A1 0x4F4F # 0 +0xD7A2 0x6CE8 # 0 +0xD7A3 0x795D # 0 +0xD7A4 0x9A7B # 0 +0xD7A5 0x6293 # 0 +0xD7A6 0x722A # 0 +0xD7A7 0x62FD # 0 +0xD7A8 0x4E13 # 0 +0xD7A9 0x7816 # 0 +0xD7AA 0x8F6C # 0 +0xD7AB 0x64B0 # 0 +0xD7AC 0x8D5A # 0 +0xD7AD 0x7BC6 # 0 +0xD7AE 0x6869 # 0 +0xD7AF 0x5E84 # 0 +0xD7B0 0x88C5 # 0 +0xD7B1 0x5986 # 0 +0xD7B2 0x649E # 0 +0xD7B3 0x58EE # 0 +0xD7B4 0x72B6 # 0 +0xD7B5 0x690E # 0 +0xD7B6 0x9525 # 0 +0xD7B7 0x8FFD # 0 +0xD7B8 0x8D58 # 0 +0xD7B9 0x5760 # 0 +0xD7BA 0x7F00 # 0 +0xD7BB 0x8C06 # 0 +0xD7BC 0x51C6 # 0 +0xD7BD 0x6349 # 0 +0xD7BE 0x62D9 # 0 +0xD7BF 0x5353 # 0 +0xD7C0 0x684C # 0 +0xD7C1 0x7422 # 0 +0xD7C2 0x8301 # 0 +0xD7C3 0x914C # 0 +0xD7C4 0x5544 # 0 +0xD7C5 0x7740 # 0 +0xD7C6 0x707C # 0 +0xD7C7 0x6D4A # 0 +0xD7C8 0x5179 # 0 +0xD7C9 0x54A8 # 0 +0xD7CA 0x8D44 # 0 +0xD7CB 0x59FF # 0 +0xD7CC 0x6ECB # 0 +0xD7CD 0x6DC4 # 0 +0xD7CE 0x5B5C # 0 +0xD7CF 0x7D2B # 0 +0xD7D0 0x4ED4 # 0 +0xD7D1 0x7C7D # 0 +0xD7D2 0x6ED3 # 0 +0xD7D3 0x5B50 # 0 +0xD7D4 0x81EA # 0 +0xD7D5 0x6E0D # 0 +0xD7D6 0x5B57 # 0 +0xD7D7 0x9B03 # 0 +0xD7D8 0x68D5 # 0 +0xD7D9 0x8E2A # 0 +0xD7DA 0x5B97 # 0 +0xD7DB 0x7EFC # 0 +0xD7DC 0x603B # 0 +0xD7DD 0x7EB5 # 0 +0xD7DE 0x90B9 # 0 +0xD7DF 0x8D70 # 0 +0xD7E0 0x594F # 0 +0xD7E1 0x63CD # 0 +0xD7E2 0x79DF # 0 +0xD7E3 0x8DB3 # 0 +0xD7E4 0x5352 # 0 +0xD7E5 0x65CF # 0 +0xD7E6 0x7956 # 0 +0xD7E7 0x8BC5 # 0 +0xD7E8 0x963B # 0 +0xD7E9 0x7EC4 # 0 +0xD7EA 0x94BB # 0 +0xD7EB 0x7E82 # 0 +0xD7EC 0x5634 # 0 +0xD7ED 0x9189 # 0 +0xD7EE 0x6700 # 0 +0xD7EF 0x7F6A # 0 +0xD7F0 0x5C0A # 0 +0xD7F1 0x9075 # 0 +0xD7F2 0x6628 # 0 +0xD7F3 0x5DE6 # 0 +0xD7F4 0x4F50 # 0 +0xD7F5 0x67DE # 0 +0xD7F6 0x505A # 0 +0xD7F7 0x4F5C # 0 +0xD7F8 0x5750 # 0 +0xD7F9 0x5EA7 # 0 +0xD7FA 0xE810 # 0 +0xD7FB 0xE811 # 0 +0xD7FC 0xE812 # 0 +0xD7FD 0xE813 # 0 +0xD7FE 0xE814 # 0 +0xD840 0x8C38 # 0 +0xD841 0x8C39 # 0 +0xD842 0x8C3A # 0 +0xD843 0x8C3B # 0 +0xD844 0x8C3C # 0 +0xD845 0x8C3D # 0 +0xD846 0x8C3E # 0 +0xD847 0x8C3F # 0 +0xD848 0x8C40 # 0 +0xD849 0x8C42 # 0 +0xD84A 0x8C43 # 0 +0xD84B 0x8C44 # 0 +0xD84C 0x8C45 # 0 +0xD84D 0x8C48 # 0 +0xD84E 0x8C4A # 0 +0xD84F 0x8C4B # 0 +0xD850 0x8C4D # 0 +0xD851 0x8C4E # 0 +0xD852 0x8C4F # 0 +0xD853 0x8C50 # 0 +0xD854 0x8C51 # 0 +0xD855 0x8C52 # 0 +0xD856 0x8C53 # 0 +0xD857 0x8C54 # 0 +0xD858 0x8C56 # 0 +0xD859 0x8C57 # 0 +0xD85A 0x8C58 # 0 +0xD85B 0x8C59 # 0 +0xD85C 0x8C5B # 0 +0xD85D 0x8C5C # 0 +0xD85E 0x8C5D # 0 +0xD85F 0x8C5E # 0 +0xD860 0x8C5F # 0 +0xD861 0x8C60 # 0 +0xD862 0x8C63 # 0 +0xD863 0x8C64 # 0 +0xD864 0x8C65 # 0 +0xD865 0x8C66 # 0 +0xD866 0x8C67 # 0 +0xD867 0x8C68 # 0 +0xD868 0x8C69 # 0 +0xD869 0x8C6C # 0 +0xD86A 0x8C6D # 0 +0xD86B 0x8C6E # 0 +0xD86C 0x8C6F # 0 +0xD86D 0x8C70 # 0 +0xD86E 0x8C71 # 0 +0xD86F 0x8C72 # 0 +0xD870 0x8C74 # 0 +0xD871 0x8C75 # 0 +0xD872 0x8C76 # 0 +0xD873 0x8C77 # 0 +0xD874 0x8C7B # 0 +0xD875 0x8C7C # 0 +0xD876 0x8C7D # 0 +0xD877 0x8C7E # 0 +0xD878 0x8C7F # 0 +0xD879 0x8C80 # 0 +0xD87A 0x8C81 # 0 +0xD87B 0x8C83 # 0 +0xD87C 0x8C84 # 0 +0xD87D 0x8C86 # 0 +0xD87E 0x8C87 # 0 +0xD880 0x8C88 # 0 +0xD881 0x8C8B # 0 +0xD882 0x8C8D # 0 +0xD883 0x8C8E # 0 +0xD884 0x8C8F # 0 +0xD885 0x8C90 # 0 +0xD886 0x8C91 # 0 +0xD887 0x8C92 # 0 +0xD888 0x8C93 # 0 +0xD889 0x8C95 # 0 +0xD88A 0x8C96 # 0 +0xD88B 0x8C97 # 0 +0xD88C 0x8C99 # 0 +0xD88D 0x8C9A # 0 +0xD88E 0x8C9B # 0 +0xD88F 0x8C9C # 0 +0xD890 0x8C9D # 0 +0xD891 0x8C9E # 0 +0xD892 0x8C9F # 0 +0xD893 0x8CA0 # 0 +0xD894 0x8CA1 # 0 +0xD895 0x8CA2 # 0 +0xD896 0x8CA3 # 0 +0xD897 0x8CA4 # 0 +0xD898 0x8CA5 # 0 +0xD899 0x8CA6 # 0 +0xD89A 0x8CA7 # 0 +0xD89B 0x8CA8 # 0 +0xD89C 0x8CA9 # 0 +0xD89D 0x8CAA # 0 +0xD89E 0x8CAB # 0 +0xD89F 0x8CAC # 0 +0xD8A0 0x8CAD # 0 +0xD8A1 0x4E8D # 0 +0xD8A2 0x4E0C # 0 +0xD8A3 0x5140 # 0 +0xD8A4 0x4E10 # 0 +0xD8A5 0x5EFF # 0 +0xD8A6 0x5345 # 0 +0xD8A7 0x4E15 # 0 +0xD8A8 0x4E98 # 0 +0xD8A9 0x4E1E # 0 +0xD8AA 0x9B32 # 0 +0xD8AB 0x5B6C # 0 +0xD8AC 0x5669 # 0 +0xD8AD 0x4E28 # 0 +0xD8AE 0x79BA # 0 +0xD8AF 0x4E3F # 0 +0xD8B0 0x5315 # 0 +0xD8B1 0x4E47 # 0 +0xD8B2 0x592D # 0 +0xD8B3 0x723B # 0 +0xD8B4 0x536E # 0 +0xD8B5 0x6C10 # 0 +0xD8B6 0x56DF # 0 +0xD8B7 0x80E4 # 0 +0xD8B8 0x9997 # 0 +0xD8B9 0x6BD3 # 0 +0xD8BA 0x777E # 0 +0xD8BB 0x9F17 # 0 +0xD8BC 0x4E36 # 0 +0xD8BD 0x4E9F # 0 +0xD8BE 0x9F10 # 0 +0xD8BF 0x4E5C # 0 +0xD8C0 0x4E69 # 0 +0xD8C1 0x4E93 # 0 +0xD8C2 0x8288 # 0 +0xD8C3 0x5B5B # 0 +0xD8C4 0x556C # 0 +0xD8C5 0x560F # 0 +0xD8C6 0x4EC4 # 0 +0xD8C7 0x538D # 0 +0xD8C8 0x539D # 0 +0xD8C9 0x53A3 # 0 +0xD8CA 0x53A5 # 0 +0xD8CB 0x53AE # 0 +0xD8CC 0x9765 # 0 +0xD8CD 0x8D5D # 0 +0xD8CE 0x531A # 0 +0xD8CF 0x53F5 # 0 +0xD8D0 0x5326 # 0 +0xD8D1 0x532E # 0 +0xD8D2 0x533E # 0 +0xD8D3 0x8D5C # 0 +0xD8D4 0x5366 # 0 +0xD8D5 0x5363 # 0 +0xD8D6 0x5202 # 0 +0xD8D7 0x5208 # 0 +0xD8D8 0x520E # 0 +0xD8D9 0x522D # 0 +0xD8DA 0x5233 # 0 +0xD8DB 0x523F # 0 +0xD8DC 0x5240 # 0 +0xD8DD 0x524C # 0 +0xD8DE 0x525E # 0 +0xD8DF 0x5261 # 0 +0xD8E0 0x525C # 0 +0xD8E1 0x84AF # 0 +0xD8E2 0x527D # 0 +0xD8E3 0x5282 # 0 +0xD8E4 0x5281 # 0 +0xD8E5 0x5290 # 0 +0xD8E6 0x5293 # 0 +0xD8E7 0x5182 # 0 +0xD8E8 0x7F54 # 0 +0xD8E9 0x4EBB # 0 +0xD8EA 0x4EC3 # 0 +0xD8EB 0x4EC9 # 0 +0xD8EC 0x4EC2 # 0 +0xD8ED 0x4EE8 # 0 +0xD8EE 0x4EE1 # 0 +0xD8EF 0x4EEB # 0 +0xD8F0 0x4EDE # 0 +0xD8F1 0x4F1B # 0 +0xD8F2 0x4EF3 # 0 +0xD8F3 0x4F22 # 0 +0xD8F4 0x4F64 # 0 +0xD8F5 0x4EF5 # 0 +0xD8F6 0x4F25 # 0 +0xD8F7 0x4F27 # 0 +0xD8F8 0x4F09 # 0 +0xD8F9 0x4F2B # 0 +0xD8FA 0x4F5E # 0 +0xD8FB 0x4F67 # 0 +0xD8FC 0x6538 # 0 +0xD8FD 0x4F5A # 0 +0xD8FE 0x4F5D # 0 +0xD940 0x8CAE # 0 +0xD941 0x8CAF # 0 +0xD942 0x8CB0 # 0 +0xD943 0x8CB1 # 0 +0xD944 0x8CB2 # 0 +0xD945 0x8CB3 # 0 +0xD946 0x8CB4 # 0 +0xD947 0x8CB5 # 0 +0xD948 0x8CB6 # 0 +0xD949 0x8CB7 # 0 +0xD94A 0x8CB8 # 0 +0xD94B 0x8CB9 # 0 +0xD94C 0x8CBA # 0 +0xD94D 0x8CBB # 0 +0xD94E 0x8CBC # 0 +0xD94F 0x8CBD # 0 +0xD950 0x8CBE # 0 +0xD951 0x8CBF # 0 +0xD952 0x8CC0 # 0 +0xD953 0x8CC1 # 0 +0xD954 0x8CC2 # 0 +0xD955 0x8CC3 # 0 +0xD956 0x8CC4 # 0 +0xD957 0x8CC5 # 0 +0xD958 0x8CC6 # 0 +0xD959 0x8CC7 # 0 +0xD95A 0x8CC8 # 0 +0xD95B 0x8CC9 # 0 +0xD95C 0x8CCA # 0 +0xD95D 0x8CCB # 0 +0xD95E 0x8CCC # 0 +0xD95F 0x8CCD # 0 +0xD960 0x8CCE # 0 +0xD961 0x8CCF # 0 +0xD962 0x8CD0 # 0 +0xD963 0x8CD1 # 0 +0xD964 0x8CD2 # 0 +0xD965 0x8CD3 # 0 +0xD966 0x8CD4 # 0 +0xD967 0x8CD5 # 0 +0xD968 0x8CD6 # 0 +0xD969 0x8CD7 # 0 +0xD96A 0x8CD8 # 0 +0xD96B 0x8CD9 # 0 +0xD96C 0x8CDA # 0 +0xD96D 0x8CDB # 0 +0xD96E 0x8CDC # 0 +0xD96F 0x8CDD # 0 +0xD970 0x8CDE # 0 +0xD971 0x8CDF # 0 +0xD972 0x8CE0 # 0 +0xD973 0x8CE1 # 0 +0xD974 0x8CE2 # 0 +0xD975 0x8CE3 # 0 +0xD976 0x8CE4 # 0 +0xD977 0x8CE5 # 0 +0xD978 0x8CE6 # 0 +0xD979 0x8CE7 # 0 +0xD97A 0x8CE8 # 0 +0xD97B 0x8CE9 # 0 +0xD97C 0x8CEA # 0 +0xD97D 0x8CEB # 0 +0xD97E 0x8CEC # 0 +0xD980 0x8CED # 0 +0xD981 0x8CEE # 0 +0xD982 0x8CEF # 0 +0xD983 0x8CF0 # 0 +0xD984 0x8CF1 # 0 +0xD985 0x8CF2 # 0 +0xD986 0x8CF3 # 0 +0xD987 0x8CF4 # 0 +0xD988 0x8CF5 # 0 +0xD989 0x8CF6 # 0 +0xD98A 0x8CF7 # 0 +0xD98B 0x8CF8 # 0 +0xD98C 0x8CF9 # 0 +0xD98D 0x8CFA # 0 +0xD98E 0x8CFB # 0 +0xD98F 0x8CFC # 0 +0xD990 0x8CFD # 0 +0xD991 0x8CFE # 0 +0xD992 0x8CFF # 0 +0xD993 0x8D00 # 0 +0xD994 0x8D01 # 0 +0xD995 0x8D02 # 0 +0xD996 0x8D03 # 0 +0xD997 0x8D04 # 0 +0xD998 0x8D05 # 0 +0xD999 0x8D06 # 0 +0xD99A 0x8D07 # 0 +0xD99B 0x8D08 # 0 +0xD99C 0x8D09 # 0 +0xD99D 0x8D0A # 0 +0xD99E 0x8D0B # 0 +0xD99F 0x8D0C # 0 +0xD9A0 0x8D0D # 0 +0xD9A1 0x4F5F # 0 +0xD9A2 0x4F57 # 0 +0xD9A3 0x4F32 # 0 +0xD9A4 0x4F3D # 0 +0xD9A5 0x4F76 # 0 +0xD9A6 0x4F74 # 0 +0xD9A7 0x4F91 # 0 +0xD9A8 0x4F89 # 0 +0xD9A9 0x4F83 # 0 +0xD9AA 0x4F8F # 0 +0xD9AB 0x4F7E # 0 +0xD9AC 0x4F7B # 0 +0xD9AD 0x4FAA # 0 +0xD9AE 0x4F7C # 0 +0xD9AF 0x4FAC # 0 +0xD9B0 0x4F94 # 0 +0xD9B1 0x4FE6 # 0 +0xD9B2 0x4FE8 # 0 +0xD9B3 0x4FEA # 0 +0xD9B4 0x4FC5 # 0 +0xD9B5 0x4FDA # 0 +0xD9B6 0x4FE3 # 0 +0xD9B7 0x4FDC # 0 +0xD9B8 0x4FD1 # 0 +0xD9B9 0x4FDF # 0 +0xD9BA 0x4FF8 # 0 +0xD9BB 0x5029 # 0 +0xD9BC 0x504C # 0 +0xD9BD 0x4FF3 # 0 +0xD9BE 0x502C # 0 +0xD9BF 0x500F # 0 +0xD9C0 0x502E # 0 +0xD9C1 0x502D # 0 +0xD9C2 0x4FFE # 0 +0xD9C3 0x501C # 0 +0xD9C4 0x500C # 0 +0xD9C5 0x5025 # 0 +0xD9C6 0x5028 # 0 +0xD9C7 0x507E # 0 +0xD9C8 0x5043 # 0 +0xD9C9 0x5055 # 0 +0xD9CA 0x5048 # 0 +0xD9CB 0x504E # 0 +0xD9CC 0x506C # 0 +0xD9CD 0x507B # 0 +0xD9CE 0x50A5 # 0 +0xD9CF 0x50A7 # 0 +0xD9D0 0x50A9 # 0 +0xD9D1 0x50BA # 0 +0xD9D2 0x50D6 # 0 +0xD9D3 0x5106 # 0 +0xD9D4 0x50ED # 0 +0xD9D5 0x50EC # 0 +0xD9D6 0x50E6 # 0 +0xD9D7 0x50EE # 0 +0xD9D8 0x5107 # 0 +0xD9D9 0x510B # 0 +0xD9DA 0x4EDD # 0 +0xD9DB 0x6C3D # 0 +0xD9DC 0x4F58 # 0 +0xD9DD 0x4F65 # 0 +0xD9DE 0x4FCE # 0 +0xD9DF 0x9FA0 # 0 +0xD9E0 0x6C46 # 0 +0xD9E1 0x7C74 # 0 +0xD9E2 0x516E # 0 +0xD9E3 0x5DFD # 0 +0xD9E4 0x9EC9 # 0 +0xD9E5 0x9998 # 0 +0xD9E6 0x5181 # 0 +0xD9E7 0x5914 # 0 +0xD9E8 0x52F9 # 0 +0xD9E9 0x530D # 0 +0xD9EA 0x8A07 # 0 +0xD9EB 0x5310 # 0 +0xD9EC 0x51EB # 0 +0xD9ED 0x5919 # 0 +0xD9EE 0x5155 # 0 +0xD9EF 0x4EA0 # 0 +0xD9F0 0x5156 # 0 +0xD9F1 0x4EB3 # 0 +0xD9F2 0x886E # 0 +0xD9F3 0x88A4 # 0 +0xD9F4 0x4EB5 # 0 +0xD9F5 0x8114 # 0 +0xD9F6 0x88D2 # 0 +0xD9F7 0x7980 # 0 +0xD9F8 0x5B34 # 0 +0xD9F9 0x8803 # 0 +0xD9FA 0x7FB8 # 0 +0xD9FB 0x51AB # 0 +0xD9FC 0x51B1 # 0 +0xD9FD 0x51BD # 0 +0xD9FE 0x51BC # 0 +0xDA40 0x8D0E # 0 +0xDA41 0x8D0F # 0 +0xDA42 0x8D10 # 0 +0xDA43 0x8D11 # 0 +0xDA44 0x8D12 # 0 +0xDA45 0x8D13 # 0 +0xDA46 0x8D14 # 0 +0xDA47 0x8D15 # 0 +0xDA48 0x8D16 # 0 +0xDA49 0x8D17 # 0 +0xDA4A 0x8D18 # 0 +0xDA4B 0x8D19 # 0 +0xDA4C 0x8D1A # 0 +0xDA4D 0x8D1B # 0 +0xDA4E 0x8D1C # 0 +0xDA4F 0x8D20 # 0 +0xDA50 0x8D51 # 0 +0xDA51 0x8D52 # 0 +0xDA52 0x8D57 # 0 +0xDA53 0x8D5F # 0 +0xDA54 0x8D65 # 0 +0xDA55 0x8D68 # 0 +0xDA56 0x8D69 # 0 +0xDA57 0x8D6A # 0 +0xDA58 0x8D6C # 0 +0xDA59 0x8D6E # 0 +0xDA5A 0x8D6F # 0 +0xDA5B 0x8D71 # 0 +0xDA5C 0x8D72 # 0 +0xDA5D 0x8D78 # 0 +0xDA5E 0x8D79 # 0 +0xDA5F 0x8D7A # 0 +0xDA60 0x8D7B # 0 +0xDA61 0x8D7C # 0 +0xDA62 0x8D7D # 0 +0xDA63 0x8D7E # 0 +0xDA64 0x8D7F # 0 +0xDA65 0x8D80 # 0 +0xDA66 0x8D82 # 0 +0xDA67 0x8D83 # 0 +0xDA68 0x8D86 # 0 +0xDA69 0x8D87 # 0 +0xDA6A 0x8D88 # 0 +0xDA6B 0x8D89 # 0 +0xDA6C 0x8D8C # 0 +0xDA6D 0x8D8D # 0 +0xDA6E 0x8D8E # 0 +0xDA6F 0x8D8F # 0 +0xDA70 0x8D90 # 0 +0xDA71 0x8D92 # 0 +0xDA72 0x8D93 # 0 +0xDA73 0x8D95 # 0 +0xDA74 0x8D96 # 0 +0xDA75 0x8D97 # 0 +0xDA76 0x8D98 # 0 +0xDA77 0x8D99 # 0 +0xDA78 0x8D9A # 0 +0xDA79 0x8D9B # 0 +0xDA7A 0x8D9C # 0 +0xDA7B 0x8D9D # 0 +0xDA7C 0x8D9E # 0 +0xDA7D 0x8DA0 # 0 +0xDA7E 0x8DA1 # 0 +0xDA80 0x8DA2 # 0 +0xDA81 0x8DA4 # 0 +0xDA82 0x8DA5 # 0 +0xDA83 0x8DA6 # 0 +0xDA84 0x8DA7 # 0 +0xDA85 0x8DA8 # 0 +0xDA86 0x8DA9 # 0 +0xDA87 0x8DAA # 0 +0xDA88 0x8DAB # 0 +0xDA89 0x8DAC # 0 +0xDA8A 0x8DAD # 0 +0xDA8B 0x8DAE # 0 +0xDA8C 0x8DAF # 0 +0xDA8D 0x8DB0 # 0 +0xDA8E 0x8DB2 # 0 +0xDA8F 0x8DB6 # 0 +0xDA90 0x8DB7 # 0 +0xDA91 0x8DB9 # 0 +0xDA92 0x8DBB # 0 +0xDA93 0x8DBD # 0 +0xDA94 0x8DC0 # 0 +0xDA95 0x8DC1 # 0 +0xDA96 0x8DC2 # 0 +0xDA97 0x8DC5 # 0 +0xDA98 0x8DC7 # 0 +0xDA99 0x8DC8 # 0 +0xDA9A 0x8DC9 # 0 +0xDA9B 0x8DCA # 0 +0xDA9C 0x8DCD # 0 +0xDA9D 0x8DD0 # 0 +0xDA9E 0x8DD2 # 0 +0xDA9F 0x8DD3 # 0 +0xDAA0 0x8DD4 # 0 +0xDAA1 0x51C7 # 0 +0xDAA2 0x5196 # 0 +0xDAA3 0x51A2 # 0 +0xDAA4 0x51A5 # 0 +0xDAA5 0x8BA0 # 0 +0xDAA6 0x8BA6 # 0 +0xDAA7 0x8BA7 # 0 +0xDAA8 0x8BAA # 0 +0xDAA9 0x8BB4 # 0 +0xDAAA 0x8BB5 # 0 +0xDAAB 0x8BB7 # 0 +0xDAAC 0x8BC2 # 0 +0xDAAD 0x8BC3 # 0 +0xDAAE 0x8BCB # 0 +0xDAAF 0x8BCF # 0 +0xDAB0 0x8BCE # 0 +0xDAB1 0x8BD2 # 0 +0xDAB2 0x8BD3 # 0 +0xDAB3 0x8BD4 # 0 +0xDAB4 0x8BD6 # 0 +0xDAB5 0x8BD8 # 0 +0xDAB6 0x8BD9 # 0 +0xDAB7 0x8BDC # 0 +0xDAB8 0x8BDF # 0 +0xDAB9 0x8BE0 # 0 +0xDABA 0x8BE4 # 0 +0xDABB 0x8BE8 # 0 +0xDABC 0x8BE9 # 0 +0xDABD 0x8BEE # 0 +0xDABE 0x8BF0 # 0 +0xDABF 0x8BF3 # 0 +0xDAC0 0x8BF6 # 0 +0xDAC1 0x8BF9 # 0 +0xDAC2 0x8BFC # 0 +0xDAC3 0x8BFF # 0 +0xDAC4 0x8C00 # 0 +0xDAC5 0x8C02 # 0 +0xDAC6 0x8C04 # 0 +0xDAC7 0x8C07 # 0 +0xDAC8 0x8C0C # 0 +0xDAC9 0x8C0F # 0 +0xDACA 0x8C11 # 0 +0xDACB 0x8C12 # 0 +0xDACC 0x8C14 # 0 +0xDACD 0x8C15 # 0 +0xDACE 0x8C16 # 0 +0xDACF 0x8C19 # 0 +0xDAD0 0x8C1B # 0 +0xDAD1 0x8C18 # 0 +0xDAD2 0x8C1D # 0 +0xDAD3 0x8C1F # 0 +0xDAD4 0x8C20 # 0 +0xDAD5 0x8C21 # 0 +0xDAD6 0x8C25 # 0 +0xDAD7 0x8C27 # 0 +0xDAD8 0x8C2A # 0 +0xDAD9 0x8C2B # 0 +0xDADA 0x8C2E # 0 +0xDADB 0x8C2F # 0 +0xDADC 0x8C32 # 0 +0xDADD 0x8C33 # 0 +0xDADE 0x8C35 # 0 +0xDADF 0x8C36 # 0 +0xDAE0 0x5369 # 0 +0xDAE1 0x537A # 0 +0xDAE2 0x961D # 0 +0xDAE3 0x9622 # 0 +0xDAE4 0x9621 # 0 +0xDAE5 0x9631 # 0 +0xDAE6 0x962A # 0 +0xDAE7 0x963D # 0 +0xDAE8 0x963C # 0 +0xDAE9 0x9642 # 0 +0xDAEA 0x9649 # 0 +0xDAEB 0x9654 # 0 +0xDAEC 0x965F # 0 +0xDAED 0x9667 # 0 +0xDAEE 0x966C # 0 +0xDAEF 0x9672 # 0 +0xDAF0 0x9674 # 0 +0xDAF1 0x9688 # 0 +0xDAF2 0x968D # 0 +0xDAF3 0x9697 # 0 +0xDAF4 0x96B0 # 0 +0xDAF5 0x9097 # 0 +0xDAF6 0x909B # 0 +0xDAF7 0x909D # 0 +0xDAF8 0x9099 # 0 +0xDAF9 0x90AC # 0 +0xDAFA 0x90A1 # 0 +0xDAFB 0x90B4 # 0 +0xDAFC 0x90B3 # 0 +0xDAFD 0x90B6 # 0 +0xDAFE 0x90BA # 0 +0xDB40 0x8DD5 # 0 +0xDB41 0x8DD8 # 0 +0xDB42 0x8DD9 # 0 +0xDB43 0x8DDC # 0 +0xDB44 0x8DE0 # 0 +0xDB45 0x8DE1 # 0 +0xDB46 0x8DE2 # 0 +0xDB47 0x8DE5 # 0 +0xDB48 0x8DE6 # 0 +0xDB49 0x8DE7 # 0 +0xDB4A 0x8DE9 # 0 +0xDB4B 0x8DED # 0 +0xDB4C 0x8DEE # 0 +0xDB4D 0x8DF0 # 0 +0xDB4E 0x8DF1 # 0 +0xDB4F 0x8DF2 # 0 +0xDB50 0x8DF4 # 0 +0xDB51 0x8DF6 # 0 +0xDB52 0x8DFC # 0 +0xDB53 0x8DFE # 0 +0xDB54 0x8DFF # 0 +0xDB55 0x8E00 # 0 +0xDB56 0x8E01 # 0 +0xDB57 0x8E02 # 0 +0xDB58 0x8E03 # 0 +0xDB59 0x8E04 # 0 +0xDB5A 0x8E06 # 0 +0xDB5B 0x8E07 # 0 +0xDB5C 0x8E08 # 0 +0xDB5D 0x8E0B # 0 +0xDB5E 0x8E0D # 0 +0xDB5F 0x8E0E # 0 +0xDB60 0x8E10 # 0 +0xDB61 0x8E11 # 0 +0xDB62 0x8E12 # 0 +0xDB63 0x8E13 # 0 +0xDB64 0x8E15 # 0 +0xDB65 0x8E16 # 0 +0xDB66 0x8E17 # 0 +0xDB67 0x8E18 # 0 +0xDB68 0x8E19 # 0 +0xDB69 0x8E1A # 0 +0xDB6A 0x8E1B # 0 +0xDB6B 0x8E1C # 0 +0xDB6C 0x8E20 # 0 +0xDB6D 0x8E21 # 0 +0xDB6E 0x8E24 # 0 +0xDB6F 0x8E25 # 0 +0xDB70 0x8E26 # 0 +0xDB71 0x8E27 # 0 +0xDB72 0x8E28 # 0 +0xDB73 0x8E2B # 0 +0xDB74 0x8E2D # 0 +0xDB75 0x8E30 # 0 +0xDB76 0x8E32 # 0 +0xDB77 0x8E33 # 0 +0xDB78 0x8E34 # 0 +0xDB79 0x8E36 # 0 +0xDB7A 0x8E37 # 0 +0xDB7B 0x8E38 # 0 +0xDB7C 0x8E3B # 0 +0xDB7D 0x8E3C # 0 +0xDB7E 0x8E3E # 0 +0xDB80 0x8E3F # 0 +0xDB81 0x8E43 # 0 +0xDB82 0x8E45 # 0 +0xDB83 0x8E46 # 0 +0xDB84 0x8E4C # 0 +0xDB85 0x8E4D # 0 +0xDB86 0x8E4E # 0 +0xDB87 0x8E4F # 0 +0xDB88 0x8E50 # 0 +0xDB89 0x8E53 # 0 +0xDB8A 0x8E54 # 0 +0xDB8B 0x8E55 # 0 +0xDB8C 0x8E56 # 0 +0xDB8D 0x8E57 # 0 +0xDB8E 0x8E58 # 0 +0xDB8F 0x8E5A # 0 +0xDB90 0x8E5B # 0 +0xDB91 0x8E5C # 0 +0xDB92 0x8E5D # 0 +0xDB93 0x8E5E # 0 +0xDB94 0x8E5F # 0 +0xDB95 0x8E60 # 0 +0xDB96 0x8E61 # 0 +0xDB97 0x8E62 # 0 +0xDB98 0x8E63 # 0 +0xDB99 0x8E64 # 0 +0xDB9A 0x8E65 # 0 +0xDB9B 0x8E67 # 0 +0xDB9C 0x8E68 # 0 +0xDB9D 0x8E6A # 0 +0xDB9E 0x8E6B # 0 +0xDB9F 0x8E6E # 0 +0xDBA0 0x8E71 # 0 +0xDBA1 0x90B8 # 0 +0xDBA2 0x90B0 # 0 +0xDBA3 0x90CF # 0 +0xDBA4 0x90C5 # 0 +0xDBA5 0x90BE # 0 +0xDBA6 0x90D0 # 0 +0xDBA7 0x90C4 # 0 +0xDBA8 0x90C7 # 0 +0xDBA9 0x90D3 # 0 +0xDBAA 0x90E6 # 0 +0xDBAB 0x90E2 # 0 +0xDBAC 0x90DC # 0 +0xDBAD 0x90D7 # 0 +0xDBAE 0x90DB # 0 +0xDBAF 0x90EB # 0 +0xDBB0 0x90EF # 0 +0xDBB1 0x90FE # 0 +0xDBB2 0x9104 # 0 +0xDBB3 0x9122 # 0 +0xDBB4 0x911E # 0 +0xDBB5 0x9123 # 0 +0xDBB6 0x9131 # 0 +0xDBB7 0x912F # 0 +0xDBB8 0x9139 # 0 +0xDBB9 0x9143 # 0 +0xDBBA 0x9146 # 0 +0xDBBB 0x520D # 0 +0xDBBC 0x5942 # 0 +0xDBBD 0x52A2 # 0 +0xDBBE 0x52AC # 0 +0xDBBF 0x52AD # 0 +0xDBC0 0x52BE # 0 +0xDBC1 0x54FF # 0 +0xDBC2 0x52D0 # 0 +0xDBC3 0x52D6 # 0 +0xDBC4 0x52F0 # 0 +0xDBC5 0x53DF # 0 +0xDBC6 0x71EE # 0 +0xDBC7 0x77CD # 0 +0xDBC8 0x5EF4 # 0 +0xDBC9 0x51F5 # 0 +0xDBCA 0x51FC # 0 +0xDBCB 0x9B2F # 0 +0xDBCC 0x53B6 # 0 +0xDBCD 0x5F01 # 0 +0xDBCE 0x755A # 0 +0xDBCF 0x5DEF # 0 +0xDBD0 0x574C # 0 +0xDBD1 0x57A9 # 0 +0xDBD2 0x57A1 # 0 +0xDBD3 0x587E # 0 +0xDBD4 0x58BC # 0 +0xDBD5 0x58C5 # 0 +0xDBD6 0x58D1 # 0 +0xDBD7 0x5729 # 0 +0xDBD8 0x572C # 0 +0xDBD9 0x572A # 0 +0xDBDA 0x5733 # 0 +0xDBDB 0x5739 # 0 +0xDBDC 0x572E # 0 +0xDBDD 0x572F # 0 +0xDBDE 0x575C # 0 +0xDBDF 0x573B # 0 +0xDBE0 0x5742 # 0 +0xDBE1 0x5769 # 0 +0xDBE2 0x5785 # 0 +0xDBE3 0x576B # 0 +0xDBE4 0x5786 # 0 +0xDBE5 0x577C # 0 +0xDBE6 0x577B # 0 +0xDBE7 0x5768 # 0 +0xDBE8 0x576D # 0 +0xDBE9 0x5776 # 0 +0xDBEA 0x5773 # 0 +0xDBEB 0x57AD # 0 +0xDBEC 0x57A4 # 0 +0xDBED 0x578C # 0 +0xDBEE 0x57B2 # 0 +0xDBEF 0x57CF # 0 +0xDBF0 0x57A7 # 0 +0xDBF1 0x57B4 # 0 +0xDBF2 0x5793 # 0 +0xDBF3 0x57A0 # 0 +0xDBF4 0x57D5 # 0 +0xDBF5 0x57D8 # 0 +0xDBF6 0x57DA # 0 +0xDBF7 0x57D9 # 0 +0xDBF8 0x57D2 # 0 +0xDBF9 0x57B8 # 0 +0xDBFA 0x57F4 # 0 +0xDBFB 0x57EF # 0 +0xDBFC 0x57F8 # 0 +0xDBFD 0x57E4 # 0 +0xDBFE 0x57DD # 0 +0xDC40 0x8E73 # 0 +0xDC41 0x8E75 # 0 +0xDC42 0x8E77 # 0 +0xDC43 0x8E78 # 0 +0xDC44 0x8E79 # 0 +0xDC45 0x8E7A # 0 +0xDC46 0x8E7B # 0 +0xDC47 0x8E7D # 0 +0xDC48 0x8E7E # 0 +0xDC49 0x8E80 # 0 +0xDC4A 0x8E82 # 0 +0xDC4B 0x8E83 # 0 +0xDC4C 0x8E84 # 0 +0xDC4D 0x8E86 # 0 +0xDC4E 0x8E88 # 0 +0xDC4F 0x8E89 # 0 +0xDC50 0x8E8A # 0 +0xDC51 0x8E8B # 0 +0xDC52 0x8E8C # 0 +0xDC53 0x8E8D # 0 +0xDC54 0x8E8E # 0 +0xDC55 0x8E91 # 0 +0xDC56 0x8E92 # 0 +0xDC57 0x8E93 # 0 +0xDC58 0x8E95 # 0 +0xDC59 0x8E96 # 0 +0xDC5A 0x8E97 # 0 +0xDC5B 0x8E98 # 0 +0xDC5C 0x8E99 # 0 +0xDC5D 0x8E9A # 0 +0xDC5E 0x8E9B # 0 +0xDC5F 0x8E9D # 0 +0xDC60 0x8E9F # 0 +0xDC61 0x8EA0 # 0 +0xDC62 0x8EA1 # 0 +0xDC63 0x8EA2 # 0 +0xDC64 0x8EA3 # 0 +0xDC65 0x8EA4 # 0 +0xDC66 0x8EA5 # 0 +0xDC67 0x8EA6 # 0 +0xDC68 0x8EA7 # 0 +0xDC69 0x8EA8 # 0 +0xDC6A 0x8EA9 # 0 +0xDC6B 0x8EAA # 0 +0xDC6C 0x8EAD # 0 +0xDC6D 0x8EAE # 0 +0xDC6E 0x8EB0 # 0 +0xDC6F 0x8EB1 # 0 +0xDC70 0x8EB3 # 0 +0xDC71 0x8EB4 # 0 +0xDC72 0x8EB5 # 0 +0xDC73 0x8EB6 # 0 +0xDC74 0x8EB7 # 0 +0xDC75 0x8EB8 # 0 +0xDC76 0x8EB9 # 0 +0xDC77 0x8EBB # 0 +0xDC78 0x8EBC # 0 +0xDC79 0x8EBD # 0 +0xDC7A 0x8EBE # 0 +0xDC7B 0x8EBF # 0 +0xDC7C 0x8EC0 # 0 +0xDC7D 0x8EC1 # 0 +0xDC7E 0x8EC2 # 0 +0xDC80 0x8EC3 # 0 +0xDC81 0x8EC4 # 0 +0xDC82 0x8EC5 # 0 +0xDC83 0x8EC6 # 0 +0xDC84 0x8EC7 # 0 +0xDC85 0x8EC8 # 0 +0xDC86 0x8EC9 # 0 +0xDC87 0x8ECA # 0 +0xDC88 0x8ECB # 0 +0xDC89 0x8ECC # 0 +0xDC8A 0x8ECD # 0 +0xDC8B 0x8ECF # 0 +0xDC8C 0x8ED0 # 0 +0xDC8D 0x8ED1 # 0 +0xDC8E 0x8ED2 # 0 +0xDC8F 0x8ED3 # 0 +0xDC90 0x8ED4 # 0 +0xDC91 0x8ED5 # 0 +0xDC92 0x8ED6 # 0 +0xDC93 0x8ED7 # 0 +0xDC94 0x8ED8 # 0 +0xDC95 0x8ED9 # 0 +0xDC96 0x8EDA # 0 +0xDC97 0x8EDB # 0 +0xDC98 0x8EDC # 0 +0xDC99 0x8EDD # 0 +0xDC9A 0x8EDE # 0 +0xDC9B 0x8EDF # 0 +0xDC9C 0x8EE0 # 0 +0xDC9D 0x8EE1 # 0 +0xDC9E 0x8EE2 # 0 +0xDC9F 0x8EE3 # 0 +0xDCA0 0x8EE4 # 0 +0xDCA1 0x580B # 0 +0xDCA2 0x580D # 0 +0xDCA3 0x57FD # 0 +0xDCA4 0x57ED # 0 +0xDCA5 0x5800 # 0 +0xDCA6 0x581E # 0 +0xDCA7 0x5819 # 0 +0xDCA8 0x5844 # 0 +0xDCA9 0x5820 # 0 +0xDCAA 0x5865 # 0 +0xDCAB 0x586C # 0 +0xDCAC 0x5881 # 0 +0xDCAD 0x5889 # 0 +0xDCAE 0x589A # 0 +0xDCAF 0x5880 # 0 +0xDCB0 0x99A8 # 0 +0xDCB1 0x9F19 # 0 +0xDCB2 0x61FF # 0 +0xDCB3 0x8279 # 0 +0xDCB4 0x827D # 0 +0xDCB5 0x827F # 0 +0xDCB6 0x828F # 0 +0xDCB7 0x828A # 0 +0xDCB8 0x82A8 # 0 +0xDCB9 0x8284 # 0 +0xDCBA 0x828E # 0 +0xDCBB 0x8291 # 0 +0xDCBC 0x8297 # 0 +0xDCBD 0x8299 # 0 +0xDCBE 0x82AB # 0 +0xDCBF 0x82B8 # 0 +0xDCC0 0x82BE # 0 +0xDCC1 0x82B0 # 0 +0xDCC2 0x82C8 # 0 +0xDCC3 0x82CA # 0 +0xDCC4 0x82E3 # 0 +0xDCC5 0x8298 # 0 +0xDCC6 0x82B7 # 0 +0xDCC7 0x82AE # 0 +0xDCC8 0x82CB # 0 +0xDCC9 0x82CC # 0 +0xDCCA 0x82C1 # 0 +0xDCCB 0x82A9 # 0 +0xDCCC 0x82B4 # 0 +0xDCCD 0x82A1 # 0 +0xDCCE 0x82AA # 0 +0xDCCF 0x829F # 0 +0xDCD0 0x82C4 # 0 +0xDCD1 0x82CE # 0 +0xDCD2 0x82A4 # 0 +0xDCD3 0x82E1 # 0 +0xDCD4 0x8309 # 0 +0xDCD5 0x82F7 # 0 +0xDCD6 0x82E4 # 0 +0xDCD7 0x830F # 0 +0xDCD8 0x8307 # 0 +0xDCD9 0x82DC # 0 +0xDCDA 0x82F4 # 0 +0xDCDB 0x82D2 # 0 +0xDCDC 0x82D8 # 0 +0xDCDD 0x830C # 0 +0xDCDE 0x82FB # 0 +0xDCDF 0x82D3 # 0 +0xDCE0 0x8311 # 0 +0xDCE1 0x831A # 0 +0xDCE2 0x8306 # 0 +0xDCE3 0x8314 # 0 +0xDCE4 0x8315 # 0 +0xDCE5 0x82E0 # 0 +0xDCE6 0x82D5 # 0 +0xDCE7 0x831C # 0 +0xDCE8 0x8351 # 0 +0xDCE9 0x835B # 0 +0xDCEA 0x835C # 0 +0xDCEB 0x8308 # 0 +0xDCEC 0x8392 # 0 +0xDCED 0x833C # 0 +0xDCEE 0x8334 # 0 +0xDCEF 0x8331 # 0 +0xDCF0 0x839B # 0 +0xDCF1 0x835E # 0 +0xDCF2 0x832F # 0 +0xDCF3 0x834F # 0 +0xDCF4 0x8347 # 0 +0xDCF5 0x8343 # 0 +0xDCF6 0x835F # 0 +0xDCF7 0x8340 # 0 +0xDCF8 0x8317 # 0 +0xDCF9 0x8360 # 0 +0xDCFA 0x832D # 0 +0xDCFB 0x833A # 0 +0xDCFC 0x8333 # 0 +0xDCFD 0x8366 # 0 +0xDCFE 0x8365 # 0 +0xDD40 0x8EE5 # 0 +0xDD41 0x8EE6 # 0 +0xDD42 0x8EE7 # 0 +0xDD43 0x8EE8 # 0 +0xDD44 0x8EE9 # 0 +0xDD45 0x8EEA # 0 +0xDD46 0x8EEB # 0 +0xDD47 0x8EEC # 0 +0xDD48 0x8EED # 0 +0xDD49 0x8EEE # 0 +0xDD4A 0x8EEF # 0 +0xDD4B 0x8EF0 # 0 +0xDD4C 0x8EF1 # 0 +0xDD4D 0x8EF2 # 0 +0xDD4E 0x8EF3 # 0 +0xDD4F 0x8EF4 # 0 +0xDD50 0x8EF5 # 0 +0xDD51 0x8EF6 # 0 +0xDD52 0x8EF7 # 0 +0xDD53 0x8EF8 # 0 +0xDD54 0x8EF9 # 0 +0xDD55 0x8EFA # 0 +0xDD56 0x8EFB # 0 +0xDD57 0x8EFC # 0 +0xDD58 0x8EFD # 0 +0xDD59 0x8EFE # 0 +0xDD5A 0x8EFF # 0 +0xDD5B 0x8F00 # 0 +0xDD5C 0x8F01 # 0 +0xDD5D 0x8F02 # 0 +0xDD5E 0x8F03 # 0 +0xDD5F 0x8F04 # 0 +0xDD60 0x8F05 # 0 +0xDD61 0x8F06 # 0 +0xDD62 0x8F07 # 0 +0xDD63 0x8F08 # 0 +0xDD64 0x8F09 # 0 +0xDD65 0x8F0A # 0 +0xDD66 0x8F0B # 0 +0xDD67 0x8F0C # 0 +0xDD68 0x8F0D # 0 +0xDD69 0x8F0E # 0 +0xDD6A 0x8F0F # 0 +0xDD6B 0x8F10 # 0 +0xDD6C 0x8F11 # 0 +0xDD6D 0x8F12 # 0 +0xDD6E 0x8F13 # 0 +0xDD6F 0x8F14 # 0 +0xDD70 0x8F15 # 0 +0xDD71 0x8F16 # 0 +0xDD72 0x8F17 # 0 +0xDD73 0x8F18 # 0 +0xDD74 0x8F19 # 0 +0xDD75 0x8F1A # 0 +0xDD76 0x8F1B # 0 +0xDD77 0x8F1C # 0 +0xDD78 0x8F1D # 0 +0xDD79 0x8F1E # 0 +0xDD7A 0x8F1F # 0 +0xDD7B 0x8F20 # 0 +0xDD7C 0x8F21 # 0 +0xDD7D 0x8F22 # 0 +0xDD7E 0x8F23 # 0 +0xDD80 0x8F24 # 0 +0xDD81 0x8F25 # 0 +0xDD82 0x8F26 # 0 +0xDD83 0x8F27 # 0 +0xDD84 0x8F28 # 0 +0xDD85 0x8F29 # 0 +0xDD86 0x8F2A # 0 +0xDD87 0x8F2B # 0 +0xDD88 0x8F2C # 0 +0xDD89 0x8F2D # 0 +0xDD8A 0x8F2E # 0 +0xDD8B 0x8F2F # 0 +0xDD8C 0x8F30 # 0 +0xDD8D 0x8F31 # 0 +0xDD8E 0x8F32 # 0 +0xDD8F 0x8F33 # 0 +0xDD90 0x8F34 # 0 +0xDD91 0x8F35 # 0 +0xDD92 0x8F36 # 0 +0xDD93 0x8F37 # 0 +0xDD94 0x8F38 # 0 +0xDD95 0x8F39 # 0 +0xDD96 0x8F3A # 0 +0xDD97 0x8F3B # 0 +0xDD98 0x8F3C # 0 +0xDD99 0x8F3D # 0 +0xDD9A 0x8F3E # 0 +0xDD9B 0x8F3F # 0 +0xDD9C 0x8F40 # 0 +0xDD9D 0x8F41 # 0 +0xDD9E 0x8F42 # 0 +0xDD9F 0x8F43 # 0 +0xDDA0 0x8F44 # 0 +0xDDA1 0x8368 # 0 +0xDDA2 0x831B # 0 +0xDDA3 0x8369 # 0 +0xDDA4 0x836C # 0 +0xDDA5 0x836A # 0 +0xDDA6 0x836D # 0 +0xDDA7 0x836E # 0 +0xDDA8 0x83B0 # 0 +0xDDA9 0x8378 # 0 +0xDDAA 0x83B3 # 0 +0xDDAB 0x83B4 # 0 +0xDDAC 0x83A0 # 0 +0xDDAD 0x83AA # 0 +0xDDAE 0x8393 # 0 +0xDDAF 0x839C # 0 +0xDDB0 0x8385 # 0 +0xDDB1 0x837C # 0 +0xDDB2 0x83B6 # 0 +0xDDB3 0x83A9 # 0 +0xDDB4 0x837D # 0 +0xDDB5 0x83B8 # 0 +0xDDB6 0x837B # 0 +0xDDB7 0x8398 # 0 +0xDDB8 0x839E # 0 +0xDDB9 0x83A8 # 0 +0xDDBA 0x83BA # 0 +0xDDBB 0x83BC # 0 +0xDDBC 0x83C1 # 0 +0xDDBD 0x8401 # 0 +0xDDBE 0x83E5 # 0 +0xDDBF 0x83D8 # 0 +0xDDC0 0x5807 # 0 +0xDDC1 0x8418 # 0 +0xDDC2 0x840B # 0 +0xDDC3 0x83DD # 0 +0xDDC4 0x83FD # 0 +0xDDC5 0x83D6 # 0 +0xDDC6 0x841C # 0 +0xDDC7 0x8438 # 0 +0xDDC8 0x8411 # 0 +0xDDC9 0x8406 # 0 +0xDDCA 0x83D4 # 0 +0xDDCB 0x83DF # 0 +0xDDCC 0x840F # 0 +0xDDCD 0x8403 # 0 +0xDDCE 0x83F8 # 0 +0xDDCF 0x83F9 # 0 +0xDDD0 0x83EA # 0 +0xDDD1 0x83C5 # 0 +0xDDD2 0x83C0 # 0 +0xDDD3 0x8426 # 0 +0xDDD4 0x83F0 # 0 +0xDDD5 0x83E1 # 0 +0xDDD6 0x845C # 0 +0xDDD7 0x8451 # 0 +0xDDD8 0x845A # 0 +0xDDD9 0x8459 # 0 +0xDDDA 0x8473 # 0 +0xDDDB 0x8487 # 0 +0xDDDC 0x8488 # 0 +0xDDDD 0x847A # 0 +0xDDDE 0x8489 # 0 +0xDDDF 0x8478 # 0 +0xDDE0 0x843C # 0 +0xDDE1 0x8446 # 0 +0xDDE2 0x8469 # 0 +0xDDE3 0x8476 # 0 +0xDDE4 0x848C # 0 +0xDDE5 0x848E # 0 +0xDDE6 0x8431 # 0 +0xDDE7 0x846D # 0 +0xDDE8 0x84C1 # 0 +0xDDE9 0x84CD # 0 +0xDDEA 0x84D0 # 0 +0xDDEB 0x84E6 # 0 +0xDDEC 0x84BD # 0 +0xDDED 0x84D3 # 0 +0xDDEE 0x84CA # 0 +0xDDEF 0x84BF # 0 +0xDDF0 0x84BA # 0 +0xDDF1 0x84E0 # 0 +0xDDF2 0x84A1 # 0 +0xDDF3 0x84B9 # 0 +0xDDF4 0x84B4 # 0 +0xDDF5 0x8497 # 0 +0xDDF6 0x84E5 # 0 +0xDDF7 0x84E3 # 0 +0xDDF8 0x850C # 0 +0xDDF9 0x750D # 0 +0xDDFA 0x8538 # 0 +0xDDFB 0x84F0 # 0 +0xDDFC 0x8539 # 0 +0xDDFD 0x851F # 0 +0xDDFE 0x853A # 0 +0xDE40 0x8F45 # 0 +0xDE41 0x8F46 # 0 +0xDE42 0x8F47 # 0 +0xDE43 0x8F48 # 0 +0xDE44 0x8F49 # 0 +0xDE45 0x8F4A # 0 +0xDE46 0x8F4B # 0 +0xDE47 0x8F4C # 0 +0xDE48 0x8F4D # 0 +0xDE49 0x8F4E # 0 +0xDE4A 0x8F4F # 0 +0xDE4B 0x8F50 # 0 +0xDE4C 0x8F51 # 0 +0xDE4D 0x8F52 # 0 +0xDE4E 0x8F53 # 0 +0xDE4F 0x8F54 # 0 +0xDE50 0x8F55 # 0 +0xDE51 0x8F56 # 0 +0xDE52 0x8F57 # 0 +0xDE53 0x8F58 # 0 +0xDE54 0x8F59 # 0 +0xDE55 0x8F5A # 0 +0xDE56 0x8F5B # 0 +0xDE57 0x8F5C # 0 +0xDE58 0x8F5D # 0 +0xDE59 0x8F5E # 0 +0xDE5A 0x8F5F # 0 +0xDE5B 0x8F60 # 0 +0xDE5C 0x8F61 # 0 +0xDE5D 0x8F62 # 0 +0xDE5E 0x8F63 # 0 +0xDE5F 0x8F64 # 0 +0xDE60 0x8F65 # 0 +0xDE61 0x8F6A # 0 +0xDE62 0x8F80 # 0 +0xDE63 0x8F8C # 0 +0xDE64 0x8F92 # 0 +0xDE65 0x8F9D # 0 +0xDE66 0x8FA0 # 0 +0xDE67 0x8FA1 # 0 +0xDE68 0x8FA2 # 0 +0xDE69 0x8FA4 # 0 +0xDE6A 0x8FA5 # 0 +0xDE6B 0x8FA6 # 0 +0xDE6C 0x8FA7 # 0 +0xDE6D 0x8FAA # 0 +0xDE6E 0x8FAC # 0 +0xDE6F 0x8FAD # 0 +0xDE70 0x8FAE # 0 +0xDE71 0x8FAF # 0 +0xDE72 0x8FB2 # 0 +0xDE73 0x8FB3 # 0 +0xDE74 0x8FB4 # 0 +0xDE75 0x8FB5 # 0 +0xDE76 0x8FB7 # 0 +0xDE77 0x8FB8 # 0 +0xDE78 0x8FBA # 0 +0xDE79 0x8FBB # 0 +0xDE7A 0x8FBC # 0 +0xDE7B 0x8FBF # 0 +0xDE7C 0x8FC0 # 0 +0xDE7D 0x8FC3 # 0 +0xDE7E 0x8FC6 # 0 +0xDE80 0x8FC9 # 0 +0xDE81 0x8FCA # 0 +0xDE82 0x8FCB # 0 +0xDE83 0x8FCC # 0 +0xDE84 0x8FCD # 0 +0xDE85 0x8FCF # 0 +0xDE86 0x8FD2 # 0 +0xDE87 0x8FD6 # 0 +0xDE88 0x8FD7 # 0 +0xDE89 0x8FDA # 0 +0xDE8A 0x8FE0 # 0 +0xDE8B 0x8FE1 # 0 +0xDE8C 0x8FE3 # 0 +0xDE8D 0x8FE7 # 0 +0xDE8E 0x8FEC # 0 +0xDE8F 0x8FEF # 0 +0xDE90 0x8FF1 # 0 +0xDE91 0x8FF2 # 0 +0xDE92 0x8FF4 # 0 +0xDE93 0x8FF5 # 0 +0xDE94 0x8FF6 # 0 +0xDE95 0x8FFA # 0 +0xDE96 0x8FFB # 0 +0xDE97 0x8FFC # 0 +0xDE98 0x8FFE # 0 +0xDE99 0x8FFF # 0 +0xDE9A 0x9007 # 0 +0xDE9B 0x9008 # 0 +0xDE9C 0x900C # 0 +0xDE9D 0x900E # 0 +0xDE9E 0x9013 # 0 +0xDE9F 0x9015 # 0 +0xDEA0 0x9018 # 0 +0xDEA1 0x8556 # 0 +0xDEA2 0x853B # 0 +0xDEA3 0x84FF # 0 +0xDEA4 0x84FC # 0 +0xDEA5 0x8559 # 0 +0xDEA6 0x8548 # 0 +0xDEA7 0x8568 # 0 +0xDEA8 0x8564 # 0 +0xDEA9 0x855E # 0 +0xDEAA 0x857A # 0 +0xDEAB 0x77A2 # 0 +0xDEAC 0x8543 # 0 +0xDEAD 0x8572 # 0 +0xDEAE 0x857B # 0 +0xDEAF 0x85A4 # 0 +0xDEB0 0x85A8 # 0 +0xDEB1 0x8587 # 0 +0xDEB2 0x858F # 0 +0xDEB3 0x8579 # 0 +0xDEB4 0x85AE # 0 +0xDEB5 0x859C # 0 +0xDEB6 0x8585 # 0 +0xDEB7 0x85B9 # 0 +0xDEB8 0x85B7 # 0 +0xDEB9 0x85B0 # 0 +0xDEBA 0x85D3 # 0 +0xDEBB 0x85C1 # 0 +0xDEBC 0x85DC # 0 +0xDEBD 0x85FF # 0 +0xDEBE 0x8627 # 0 +0xDEBF 0x8605 # 0 +0xDEC0 0x8629 # 0 +0xDEC1 0x8616 # 0 +0xDEC2 0x863C # 0 +0xDEC3 0x5EFE # 0 +0xDEC4 0x5F08 # 0 +0xDEC5 0x593C # 0 +0xDEC6 0x5941 # 0 +0xDEC7 0x8037 # 0 +0xDEC8 0x5955 # 0 +0xDEC9 0x595A # 0 +0xDECA 0x5958 # 0 +0xDECB 0x530F # 0 +0xDECC 0x5C22 # 0 +0xDECD 0x5C25 # 0 +0xDECE 0x5C2C # 0 +0xDECF 0x5C34 # 0 +0xDED0 0x624C # 0 +0xDED1 0x626A # 0 +0xDED2 0x629F # 0 +0xDED3 0x62BB # 0 +0xDED4 0x62CA # 0 +0xDED5 0x62DA # 0 +0xDED6 0x62D7 # 0 +0xDED7 0x62EE # 0 +0xDED8 0x6322 # 0 +0xDED9 0x62F6 # 0 +0xDEDA 0x6339 # 0 +0xDEDB 0x634B # 0 +0xDEDC 0x6343 # 0 +0xDEDD 0x63AD # 0 +0xDEDE 0x63F6 # 0 +0xDEDF 0x6371 # 0 +0xDEE0 0x637A # 0 +0xDEE1 0x638E # 0 +0xDEE2 0x63B4 # 0 +0xDEE3 0x636D # 0 +0xDEE4 0x63AC # 0 +0xDEE5 0x638A # 0 +0xDEE6 0x6369 # 0 +0xDEE7 0x63AE # 0 +0xDEE8 0x63BC # 0 +0xDEE9 0x63F2 # 0 +0xDEEA 0x63F8 # 0 +0xDEEB 0x63E0 # 0 +0xDEEC 0x63FF # 0 +0xDEED 0x63C4 # 0 +0xDEEE 0x63DE # 0 +0xDEEF 0x63CE # 0 +0xDEF0 0x6452 # 0 +0xDEF1 0x63C6 # 0 +0xDEF2 0x63BE # 0 +0xDEF3 0x6445 # 0 +0xDEF4 0x6441 # 0 +0xDEF5 0x640B # 0 +0xDEF6 0x641B # 0 +0xDEF7 0x6420 # 0 +0xDEF8 0x640C # 0 +0xDEF9 0x6426 # 0 +0xDEFA 0x6421 # 0 +0xDEFB 0x645E # 0 +0xDEFC 0x6484 # 0 +0xDEFD 0x646D # 0 +0xDEFE 0x6496 # 0 +0xDF40 0x9019 # 0 +0xDF41 0x901C # 0 +0xDF42 0x9023 # 0 +0xDF43 0x9024 # 0 +0xDF44 0x9025 # 0 +0xDF45 0x9027 # 0 +0xDF46 0x9028 # 0 +0xDF47 0x9029 # 0 +0xDF48 0x902A # 0 +0xDF49 0x902B # 0 +0xDF4A 0x902C # 0 +0xDF4B 0x9030 # 0 +0xDF4C 0x9031 # 0 +0xDF4D 0x9032 # 0 +0xDF4E 0x9033 # 0 +0xDF4F 0x9034 # 0 +0xDF50 0x9037 # 0 +0xDF51 0x9039 # 0 +0xDF52 0x903A # 0 +0xDF53 0x903D # 0 +0xDF54 0x903F # 0 +0xDF55 0x9040 # 0 +0xDF56 0x9043 # 0 +0xDF57 0x9045 # 0 +0xDF58 0x9046 # 0 +0xDF59 0x9048 # 0 +0xDF5A 0x9049 # 0 +0xDF5B 0x904A # 0 +0xDF5C 0x904B # 0 +0xDF5D 0x904C # 0 +0xDF5E 0x904E # 0 +0xDF5F 0x9054 # 0 +0xDF60 0x9055 # 0 +0xDF61 0x9056 # 0 +0xDF62 0x9059 # 0 +0xDF63 0x905A # 0 +0xDF64 0x905C # 0 +0xDF65 0x905D # 0 +0xDF66 0x905E # 0 +0xDF67 0x905F # 0 +0xDF68 0x9060 # 0 +0xDF69 0x9061 # 0 +0xDF6A 0x9064 # 0 +0xDF6B 0x9066 # 0 +0xDF6C 0x9067 # 0 +0xDF6D 0x9069 # 0 +0xDF6E 0x906A # 0 +0xDF6F 0x906B # 0 +0xDF70 0x906C # 0 +0xDF71 0x906F # 0 +0xDF72 0x9070 # 0 +0xDF73 0x9071 # 0 +0xDF74 0x9072 # 0 +0xDF75 0x9073 # 0 +0xDF76 0x9076 # 0 +0xDF77 0x9077 # 0 +0xDF78 0x9078 # 0 +0xDF79 0x9079 # 0 +0xDF7A 0x907A # 0 +0xDF7B 0x907B # 0 +0xDF7C 0x907C # 0 +0xDF7D 0x907E # 0 +0xDF7E 0x9081 # 0 +0xDF80 0x9084 # 0 +0xDF81 0x9085 # 0 +0xDF82 0x9086 # 0 +0xDF83 0x9087 # 0 +0xDF84 0x9089 # 0 +0xDF85 0x908A # 0 +0xDF86 0x908C # 0 +0xDF87 0x908D # 0 +0xDF88 0x908E # 0 +0xDF89 0x908F # 0 +0xDF8A 0x9090 # 0 +0xDF8B 0x9092 # 0 +0xDF8C 0x9094 # 0 +0xDF8D 0x9096 # 0 +0xDF8E 0x9098 # 0 +0xDF8F 0x909A # 0 +0xDF90 0x909C # 0 +0xDF91 0x909E # 0 +0xDF92 0x909F # 0 +0xDF93 0x90A0 # 0 +0xDF94 0x90A4 # 0 +0xDF95 0x90A5 # 0 +0xDF96 0x90A7 # 0 +0xDF97 0x90A8 # 0 +0xDF98 0x90A9 # 0 +0xDF99 0x90AB # 0 +0xDF9A 0x90AD # 0 +0xDF9B 0x90B2 # 0 +0xDF9C 0x90B7 # 0 +0xDF9D 0x90BC # 0 +0xDF9E 0x90BD # 0 +0xDF9F 0x90BF # 0 +0xDFA0 0x90C0 # 0 +0xDFA1 0x647A # 0 +0xDFA2 0x64B7 # 0 +0xDFA3 0x64B8 # 0 +0xDFA4 0x6499 # 0 +0xDFA5 0x64BA # 0 +0xDFA6 0x64C0 # 0 +0xDFA7 0x64D0 # 0 +0xDFA8 0x64D7 # 0 +0xDFA9 0x64E4 # 0 +0xDFAA 0x64E2 # 0 +0xDFAB 0x6509 # 0 +0xDFAC 0x6525 # 0 +0xDFAD 0x652E # 0 +0xDFAE 0x5F0B # 0 +0xDFAF 0x5FD2 # 0 +0xDFB0 0x7519 # 0 +0xDFB1 0x5F11 # 0 +0xDFB2 0x535F # 0 +0xDFB3 0x53F1 # 0 +0xDFB4 0x53FD # 0 +0xDFB5 0x53E9 # 0 +0xDFB6 0x53E8 # 0 +0xDFB7 0x53FB # 0 +0xDFB8 0x5412 # 0 +0xDFB9 0x5416 # 0 +0xDFBA 0x5406 # 0 +0xDFBB 0x544B # 0 +0xDFBC 0x5452 # 0 +0xDFBD 0x5453 # 0 +0xDFBE 0x5454 # 0 +0xDFBF 0x5456 # 0 +0xDFC0 0x5443 # 0 +0xDFC1 0x5421 # 0 +0xDFC2 0x5457 # 0 +0xDFC3 0x5459 # 0 +0xDFC4 0x5423 # 0 +0xDFC5 0x5432 # 0 +0xDFC6 0x5482 # 0 +0xDFC7 0x5494 # 0 +0xDFC8 0x5477 # 0 +0xDFC9 0x5471 # 0 +0xDFCA 0x5464 # 0 +0xDFCB 0x549A # 0 +0xDFCC 0x549B # 0 +0xDFCD 0x5484 # 0 +0xDFCE 0x5476 # 0 +0xDFCF 0x5466 # 0 +0xDFD0 0x549D # 0 +0xDFD1 0x54D0 # 0 +0xDFD2 0x54AD # 0 +0xDFD3 0x54C2 # 0 +0xDFD4 0x54B4 # 0 +0xDFD5 0x54D2 # 0 +0xDFD6 0x54A7 # 0 +0xDFD7 0x54A6 # 0 +0xDFD8 0x54D3 # 0 +0xDFD9 0x54D4 # 0 +0xDFDA 0x5472 # 0 +0xDFDB 0x54A3 # 0 +0xDFDC 0x54D5 # 0 +0xDFDD 0x54BB # 0 +0xDFDE 0x54BF # 0 +0xDFDF 0x54CC # 0 +0xDFE0 0x54D9 # 0 +0xDFE1 0x54DA # 0 +0xDFE2 0x54DC # 0 +0xDFE3 0x54A9 # 0 +0xDFE4 0x54AA # 0 +0xDFE5 0x54A4 # 0 +0xDFE6 0x54DD # 0 +0xDFE7 0x54CF # 0 +0xDFE8 0x54DE # 0 +0xDFE9 0x551B # 0 +0xDFEA 0x54E7 # 0 +0xDFEB 0x5520 # 0 +0xDFEC 0x54FD # 0 +0xDFED 0x5514 # 0 +0xDFEE 0x54F3 # 0 +0xDFEF 0x5522 # 0 +0xDFF0 0x5523 # 0 +0xDFF1 0x550F # 0 +0xDFF2 0x5511 # 0 +0xDFF3 0x5527 # 0 +0xDFF4 0x552A # 0 +0xDFF5 0x5567 # 0 +0xDFF6 0x558F # 0 +0xDFF7 0x55B5 # 0 +0xDFF8 0x5549 # 0 +0xDFF9 0x556D # 0 +0xDFFA 0x5541 # 0 +0xDFFB 0x5555 # 0 +0xDFFC 0x553F # 0 +0xDFFD 0x5550 # 0 +0xDFFE 0x553C # 0 +0xE040 0x90C2 # 0 +0xE041 0x90C3 # 0 +0xE042 0x90C6 # 0 +0xE043 0x90C8 # 0 +0xE044 0x90C9 # 0 +0xE045 0x90CB # 0 +0xE046 0x90CC # 0 +0xE047 0x90CD # 0 +0xE048 0x90D2 # 0 +0xE049 0x90D4 # 0 +0xE04A 0x90D5 # 0 +0xE04B 0x90D6 # 0 +0xE04C 0x90D8 # 0 +0xE04D 0x90D9 # 0 +0xE04E 0x90DA # 0 +0xE04F 0x90DE # 0 +0xE050 0x90DF # 0 +0xE051 0x90E0 # 0 +0xE052 0x90E3 # 0 +0xE053 0x90E4 # 0 +0xE054 0x90E5 # 0 +0xE055 0x90E9 # 0 +0xE056 0x90EA # 0 +0xE057 0x90EC # 0 +0xE058 0x90EE # 0 +0xE059 0x90F0 # 0 +0xE05A 0x90F1 # 0 +0xE05B 0x90F2 # 0 +0xE05C 0x90F3 # 0 +0xE05D 0x90F5 # 0 +0xE05E 0x90F6 # 0 +0xE05F 0x90F7 # 0 +0xE060 0x90F9 # 0 +0xE061 0x90FA # 0 +0xE062 0x90FB # 0 +0xE063 0x90FC # 0 +0xE064 0x90FF # 0 +0xE065 0x9100 # 0 +0xE066 0x9101 # 0 +0xE067 0x9103 # 0 +0xE068 0x9105 # 0 +0xE069 0x9106 # 0 +0xE06A 0x9107 # 0 +0xE06B 0x9108 # 0 +0xE06C 0x9109 # 0 +0xE06D 0x910A # 0 +0xE06E 0x910B # 0 +0xE06F 0x910C # 0 +0xE070 0x910D # 0 +0xE071 0x910E # 0 +0xE072 0x910F # 0 +0xE073 0x9110 # 0 +0xE074 0x9111 # 0 +0xE075 0x9112 # 0 +0xE076 0x9113 # 0 +0xE077 0x9114 # 0 +0xE078 0x9115 # 0 +0xE079 0x9116 # 0 +0xE07A 0x9117 # 0 +0xE07B 0x9118 # 0 +0xE07C 0x911A # 0 +0xE07D 0x911B # 0 +0xE07E 0x911C # 0 +0xE080 0x911D # 0 +0xE081 0x911F # 0 +0xE082 0x9120 # 0 +0xE083 0x9121 # 0 +0xE084 0x9124 # 0 +0xE085 0x9125 # 0 +0xE086 0x9126 # 0 +0xE087 0x9127 # 0 +0xE088 0x9128 # 0 +0xE089 0x9129 # 0 +0xE08A 0x912A # 0 +0xE08B 0x912B # 0 +0xE08C 0x912C # 0 +0xE08D 0x912D # 0 +0xE08E 0x912E # 0 +0xE08F 0x9130 # 0 +0xE090 0x9132 # 0 +0xE091 0x9133 # 0 +0xE092 0x9134 # 0 +0xE093 0x9135 # 0 +0xE094 0x9136 # 0 +0xE095 0x9137 # 0 +0xE096 0x9138 # 0 +0xE097 0x913A # 0 +0xE098 0x913B # 0 +0xE099 0x913C # 0 +0xE09A 0x913D # 0 +0xE09B 0x913E # 0 +0xE09C 0x913F # 0 +0xE09D 0x9140 # 0 +0xE09E 0x9141 # 0 +0xE09F 0x9142 # 0 +0xE0A0 0x9144 # 0 +0xE0A1 0x5537 # 0 +0xE0A2 0x5556 # 0 +0xE0A3 0x5575 # 0 +0xE0A4 0x5576 # 0 +0xE0A5 0x5577 # 0 +0xE0A6 0x5533 # 0 +0xE0A7 0x5530 # 0 +0xE0A8 0x555C # 0 +0xE0A9 0x558B # 0 +0xE0AA 0x55D2 # 0 +0xE0AB 0x5583 # 0 +0xE0AC 0x55B1 # 0 +0xE0AD 0x55B9 # 0 +0xE0AE 0x5588 # 0 +0xE0AF 0x5581 # 0 +0xE0B0 0x559F # 0 +0xE0B1 0x557E # 0 +0xE0B2 0x55D6 # 0 +0xE0B3 0x5591 # 0 +0xE0B4 0x557B # 0 +0xE0B5 0x55DF # 0 +0xE0B6 0x55BD # 0 +0xE0B7 0x55BE # 0 +0xE0B8 0x5594 # 0 +0xE0B9 0x5599 # 0 +0xE0BA 0x55EA # 0 +0xE0BB 0x55F7 # 0 +0xE0BC 0x55C9 # 0 +0xE0BD 0x561F # 0 +0xE0BE 0x55D1 # 0 +0xE0BF 0x55EB # 0 +0xE0C0 0x55EC # 0 +0xE0C1 0x55D4 # 0 +0xE0C2 0x55E6 # 0 +0xE0C3 0x55DD # 0 +0xE0C4 0x55C4 # 0 +0xE0C5 0x55EF # 0 +0xE0C6 0x55E5 # 0 +0xE0C7 0x55F2 # 0 +0xE0C8 0x55F3 # 0 +0xE0C9 0x55CC # 0 +0xE0CA 0x55CD # 0 +0xE0CB 0x55E8 # 0 +0xE0CC 0x55F5 # 0 +0xE0CD 0x55E4 # 0 +0xE0CE 0x8F94 # 0 +0xE0CF 0x561E # 0 +0xE0D0 0x5608 # 0 +0xE0D1 0x560C # 0 +0xE0D2 0x5601 # 0 +0xE0D3 0x5624 # 0 +0xE0D4 0x5623 # 0 +0xE0D5 0x55FE # 0 +0xE0D6 0x5600 # 0 +0xE0D7 0x5627 # 0 +0xE0D8 0x562D # 0 +0xE0D9 0x5658 # 0 +0xE0DA 0x5639 # 0 +0xE0DB 0x5657 # 0 +0xE0DC 0x562C # 0 +0xE0DD 0x564D # 0 +0xE0DE 0x5662 # 0 +0xE0DF 0x5659 # 0 +0xE0E0 0x565C # 0 +0xE0E1 0x564C # 0 +0xE0E2 0x5654 # 0 +0xE0E3 0x5686 # 0 +0xE0E4 0x5664 # 0 +0xE0E5 0x5671 # 0 +0xE0E6 0x566B # 0 +0xE0E7 0x567B # 0 +0xE0E8 0x567C # 0 +0xE0E9 0x5685 # 0 +0xE0EA 0x5693 # 0 +0xE0EB 0x56AF # 0 +0xE0EC 0x56D4 # 0 +0xE0ED 0x56D7 # 0 +0xE0EE 0x56DD # 0 +0xE0EF 0x56E1 # 0 +0xE0F0 0x56F5 # 0 +0xE0F1 0x56EB # 0 +0xE0F2 0x56F9 # 0 +0xE0F3 0x56FF # 0 +0xE0F4 0x5704 # 0 +0xE0F5 0x570A # 0 +0xE0F6 0x5709 # 0 +0xE0F7 0x571C # 0 +0xE0F8 0x5E0F # 0 +0xE0F9 0x5E19 # 0 +0xE0FA 0x5E14 # 0 +0xE0FB 0x5E11 # 0 +0xE0FC 0x5E31 # 0 +0xE0FD 0x5E3B # 0 +0xE0FE 0x5E3C # 0 +0xE140 0x9145 # 0 +0xE141 0x9147 # 0 +0xE142 0x9148 # 0 +0xE143 0x9151 # 0 +0xE144 0x9153 # 0 +0xE145 0x9154 # 0 +0xE146 0x9155 # 0 +0xE147 0x9156 # 0 +0xE148 0x9158 # 0 +0xE149 0x9159 # 0 +0xE14A 0x915B # 0 +0xE14B 0x915C # 0 +0xE14C 0x915F # 0 +0xE14D 0x9160 # 0 +0xE14E 0x9166 # 0 +0xE14F 0x9167 # 0 +0xE150 0x9168 # 0 +0xE151 0x916B # 0 +0xE152 0x916D # 0 +0xE153 0x9173 # 0 +0xE154 0x917A # 0 +0xE155 0x917B # 0 +0xE156 0x917C # 0 +0xE157 0x9180 # 0 +0xE158 0x9181 # 0 +0xE159 0x9182 # 0 +0xE15A 0x9183 # 0 +0xE15B 0x9184 # 0 +0xE15C 0x9186 # 0 +0xE15D 0x9188 # 0 +0xE15E 0x918A # 0 +0xE15F 0x918E # 0 +0xE160 0x918F # 0 +0xE161 0x9193 # 0 +0xE162 0x9194 # 0 +0xE163 0x9195 # 0 +0xE164 0x9196 # 0 +0xE165 0x9197 # 0 +0xE166 0x9198 # 0 +0xE167 0x9199 # 0 +0xE168 0x919C # 0 +0xE169 0x919D # 0 +0xE16A 0x919E # 0 +0xE16B 0x919F # 0 +0xE16C 0x91A0 # 0 +0xE16D 0x91A1 # 0 +0xE16E 0x91A4 # 0 +0xE16F 0x91A5 # 0 +0xE170 0x91A6 # 0 +0xE171 0x91A7 # 0 +0xE172 0x91A8 # 0 +0xE173 0x91A9 # 0 +0xE174 0x91AB # 0 +0xE175 0x91AC # 0 +0xE176 0x91B0 # 0 +0xE177 0x91B1 # 0 +0xE178 0x91B2 # 0 +0xE179 0x91B3 # 0 +0xE17A 0x91B6 # 0 +0xE17B 0x91B7 # 0 +0xE17C 0x91B8 # 0 +0xE17D 0x91B9 # 0 +0xE17E 0x91BB # 0 +0xE180 0x91BC # 0 +0xE181 0x91BD # 0 +0xE182 0x91BE # 0 +0xE183 0x91BF # 0 +0xE184 0x91C0 # 0 +0xE185 0x91C1 # 0 +0xE186 0x91C2 # 0 +0xE187 0x91C3 # 0 +0xE188 0x91C4 # 0 +0xE189 0x91C5 # 0 +0xE18A 0x91C6 # 0 +0xE18B 0x91C8 # 0 +0xE18C 0x91CB # 0 +0xE18D 0x91D0 # 0 +0xE18E 0x91D2 # 0 +0xE18F 0x91D3 # 0 +0xE190 0x91D4 # 0 +0xE191 0x91D5 # 0 +0xE192 0x91D6 # 0 +0xE193 0x91D7 # 0 +0xE194 0x91D8 # 0 +0xE195 0x91D9 # 0 +0xE196 0x91DA # 0 +0xE197 0x91DB # 0 +0xE198 0x91DD # 0 +0xE199 0x91DE # 0 +0xE19A 0x91DF # 0 +0xE19B 0x91E0 # 0 +0xE19C 0x91E1 # 0 +0xE19D 0x91E2 # 0 +0xE19E 0x91E3 # 0 +0xE19F 0x91E4 # 0 +0xE1A0 0x91E5 # 0 +0xE1A1 0x5E37 # 0 +0xE1A2 0x5E44 # 0 +0xE1A3 0x5E54 # 0 +0xE1A4 0x5E5B # 0 +0xE1A5 0x5E5E # 0 +0xE1A6 0x5E61 # 0 +0xE1A7 0x5C8C # 0 +0xE1A8 0x5C7A # 0 +0xE1A9 0x5C8D # 0 +0xE1AA 0x5C90 # 0 +0xE1AB 0x5C96 # 0 +0xE1AC 0x5C88 # 0 +0xE1AD 0x5C98 # 0 +0xE1AE 0x5C99 # 0 +0xE1AF 0x5C91 # 0 +0xE1B0 0x5C9A # 0 +0xE1B1 0x5C9C # 0 +0xE1B2 0x5CB5 # 0 +0xE1B3 0x5CA2 # 0 +0xE1B4 0x5CBD # 0 +0xE1B5 0x5CAC # 0 +0xE1B6 0x5CAB # 0 +0xE1B7 0x5CB1 # 0 +0xE1B8 0x5CA3 # 0 +0xE1B9 0x5CC1 # 0 +0xE1BA 0x5CB7 # 0 +0xE1BB 0x5CC4 # 0 +0xE1BC 0x5CD2 # 0 +0xE1BD 0x5CE4 # 0 +0xE1BE 0x5CCB # 0 +0xE1BF 0x5CE5 # 0 +0xE1C0 0x5D02 # 0 +0xE1C1 0x5D03 # 0 +0xE1C2 0x5D27 # 0 +0xE1C3 0x5D26 # 0 +0xE1C4 0x5D2E # 0 +0xE1C5 0x5D24 # 0 +0xE1C6 0x5D1E # 0 +0xE1C7 0x5D06 # 0 +0xE1C8 0x5D1B # 0 +0xE1C9 0x5D58 # 0 +0xE1CA 0x5D3E # 0 +0xE1CB 0x5D34 # 0 +0xE1CC 0x5D3D # 0 +0xE1CD 0x5D6C # 0 +0xE1CE 0x5D5B # 0 +0xE1CF 0x5D6F # 0 +0xE1D0 0x5D5D # 0 +0xE1D1 0x5D6B # 0 +0xE1D2 0x5D4B # 0 +0xE1D3 0x5D4A # 0 +0xE1D4 0x5D69 # 0 +0xE1D5 0x5D74 # 0 +0xE1D6 0x5D82 # 0 +0xE1D7 0x5D99 # 0 +0xE1D8 0x5D9D # 0 +0xE1D9 0x8C73 # 0 +0xE1DA 0x5DB7 # 0 +0xE1DB 0x5DC5 # 0 +0xE1DC 0x5F73 # 0 +0xE1DD 0x5F77 # 0 +0xE1DE 0x5F82 # 0 +0xE1DF 0x5F87 # 0 +0xE1E0 0x5F89 # 0 +0xE1E1 0x5F8C # 0 +0xE1E2 0x5F95 # 0 +0xE1E3 0x5F99 # 0 +0xE1E4 0x5F9C # 0 +0xE1E5 0x5FA8 # 0 +0xE1E6 0x5FAD # 0 +0xE1E7 0x5FB5 # 0 +0xE1E8 0x5FBC # 0 +0xE1E9 0x8862 # 0 +0xE1EA 0x5F61 # 0 +0xE1EB 0x72AD # 0 +0xE1EC 0x72B0 # 0 +0xE1ED 0x72B4 # 0 +0xE1EE 0x72B7 # 0 +0xE1EF 0x72B8 # 0 +0xE1F0 0x72C3 # 0 +0xE1F1 0x72C1 # 0 +0xE1F2 0x72CE # 0 +0xE1F3 0x72CD # 0 +0xE1F4 0x72D2 # 0 +0xE1F5 0x72E8 # 0 +0xE1F6 0x72EF # 0 +0xE1F7 0x72E9 # 0 +0xE1F8 0x72F2 # 0 +0xE1F9 0x72F4 # 0 +0xE1FA 0x72F7 # 0 +0xE1FB 0x7301 # 0 +0xE1FC 0x72F3 # 0 +0xE1FD 0x7303 # 0 +0xE1FE 0x72FA # 0 +0xE240 0x91E6 # 0 +0xE241 0x91E7 # 0 +0xE242 0x91E8 # 0 +0xE243 0x91E9 # 0 +0xE244 0x91EA # 0 +0xE245 0x91EB # 0 +0xE246 0x91EC # 0 +0xE247 0x91ED # 0 +0xE248 0x91EE # 0 +0xE249 0x91EF # 0 +0xE24A 0x91F0 # 0 +0xE24B 0x91F1 # 0 +0xE24C 0x91F2 # 0 +0xE24D 0x91F3 # 0 +0xE24E 0x91F4 # 0 +0xE24F 0x91F5 # 0 +0xE250 0x91F6 # 0 +0xE251 0x91F7 # 0 +0xE252 0x91F8 # 0 +0xE253 0x91F9 # 0 +0xE254 0x91FA # 0 +0xE255 0x91FB # 0 +0xE256 0x91FC # 0 +0xE257 0x91FD # 0 +0xE258 0x91FE # 0 +0xE259 0x91FF # 0 +0xE25A 0x9200 # 0 +0xE25B 0x9201 # 0 +0xE25C 0x9202 # 0 +0xE25D 0x9203 # 0 +0xE25E 0x9204 # 0 +0xE25F 0x9205 # 0 +0xE260 0x9206 # 0 +0xE261 0x9207 # 0 +0xE262 0x9208 # 0 +0xE263 0x9209 # 0 +0xE264 0x920A # 0 +0xE265 0x920B # 0 +0xE266 0x920C # 0 +0xE267 0x920D # 0 +0xE268 0x920E # 0 +0xE269 0x920F # 0 +0xE26A 0x9210 # 0 +0xE26B 0x9211 # 0 +0xE26C 0x9212 # 0 +0xE26D 0x9213 # 0 +0xE26E 0x9214 # 0 +0xE26F 0x9215 # 0 +0xE270 0x9216 # 0 +0xE271 0x9217 # 0 +0xE272 0x9218 # 0 +0xE273 0x9219 # 0 +0xE274 0x921A # 0 +0xE275 0x921B # 0 +0xE276 0x921C # 0 +0xE277 0x921D # 0 +0xE278 0x921E # 0 +0xE279 0x921F # 0 +0xE27A 0x9220 # 0 +0xE27B 0x9221 # 0 +0xE27C 0x9222 # 0 +0xE27D 0x9223 # 0 +0xE27E 0x9224 # 0 +0xE280 0x9225 # 0 +0xE281 0x9226 # 0 +0xE282 0x9227 # 0 +0xE283 0x9228 # 0 +0xE284 0x9229 # 0 +0xE285 0x922A # 0 +0xE286 0x922B # 0 +0xE287 0x922C # 0 +0xE288 0x922D # 0 +0xE289 0x922E # 0 +0xE28A 0x922F # 0 +0xE28B 0x9230 # 0 +0xE28C 0x9231 # 0 +0xE28D 0x9232 # 0 +0xE28E 0x9233 # 0 +0xE28F 0x9234 # 0 +0xE290 0x9235 # 0 +0xE291 0x9236 # 0 +0xE292 0x9237 # 0 +0xE293 0x9238 # 0 +0xE294 0x9239 # 0 +0xE295 0x923A # 0 +0xE296 0x923B # 0 +0xE297 0x923C # 0 +0xE298 0x923D # 0 +0xE299 0x923E # 0 +0xE29A 0x923F # 0 +0xE29B 0x9240 # 0 +0xE29C 0x9241 # 0 +0xE29D 0x9242 # 0 +0xE29E 0x9243 # 0 +0xE29F 0x9244 # 0 +0xE2A0 0x9245 # 0 +0xE2A1 0x72FB # 0 +0xE2A2 0x7317 # 0 +0xE2A3 0x7313 # 0 +0xE2A4 0x7321 # 0 +0xE2A5 0x730A # 0 +0xE2A6 0x731E # 0 +0xE2A7 0x731D # 0 +0xE2A8 0x7315 # 0 +0xE2A9 0x7322 # 0 +0xE2AA 0x7339 # 0 +0xE2AB 0x7325 # 0 +0xE2AC 0x732C # 0 +0xE2AD 0x7338 # 0 +0xE2AE 0x7331 # 0 +0xE2AF 0x7350 # 0 +0xE2B0 0x734D # 0 +0xE2B1 0x7357 # 0 +0xE2B2 0x7360 # 0 +0xE2B3 0x736C # 0 +0xE2B4 0x736F # 0 +0xE2B5 0x737E # 0 +0xE2B6 0x821B # 0 +0xE2B7 0x5925 # 0 +0xE2B8 0x98E7 # 0 +0xE2B9 0x5924 # 0 +0xE2BA 0x5902 # 0 +0xE2BB 0x9963 # 0 +0xE2BC 0x9967 # 0 +0xE2BD 0x9968 # 0 +0xE2BE 0x9969 # 0 +0xE2BF 0x996A # 0 +0xE2C0 0x996B # 0 +0xE2C1 0x996C # 0 +0xE2C2 0x9974 # 0 +0xE2C3 0x9977 # 0 +0xE2C4 0x997D # 0 +0xE2C5 0x9980 # 0 +0xE2C6 0x9984 # 0 +0xE2C7 0x9987 # 0 +0xE2C8 0x998A # 0 +0xE2C9 0x998D # 0 +0xE2CA 0x9990 # 0 +0xE2CB 0x9991 # 0 +0xE2CC 0x9993 # 0 +0xE2CD 0x9994 # 0 +0xE2CE 0x9995 # 0 +0xE2CF 0x5E80 # 0 +0xE2D0 0x5E91 # 0 +0xE2D1 0x5E8B # 0 +0xE2D2 0x5E96 # 0 +0xE2D3 0x5EA5 # 0 +0xE2D4 0x5EA0 # 0 +0xE2D5 0x5EB9 # 0 +0xE2D6 0x5EB5 # 0 +0xE2D7 0x5EBE # 0 +0xE2D8 0x5EB3 # 0 +0xE2D9 0x8D53 # 0 +0xE2DA 0x5ED2 # 0 +0xE2DB 0x5ED1 # 0 +0xE2DC 0x5EDB # 0 +0xE2DD 0x5EE8 # 0 +0xE2DE 0x5EEA # 0 +0xE2DF 0x81BA # 0 +0xE2E0 0x5FC4 # 0 +0xE2E1 0x5FC9 # 0 +0xE2E2 0x5FD6 # 0 +0xE2E3 0x5FCF # 0 +0xE2E4 0x6003 # 0 +0xE2E5 0x5FEE # 0 +0xE2E6 0x6004 # 0 +0xE2E7 0x5FE1 # 0 +0xE2E8 0x5FE4 # 0 +0xE2E9 0x5FFE # 0 +0xE2EA 0x6005 # 0 +0xE2EB 0x6006 # 0 +0xE2EC 0x5FEA # 0 +0xE2ED 0x5FED # 0 +0xE2EE 0x5FF8 # 0 +0xE2EF 0x6019 # 0 +0xE2F0 0x6035 # 0 +0xE2F1 0x6026 # 0 +0xE2F2 0x601B # 0 +0xE2F3 0x600F # 0 +0xE2F4 0x600D # 0 +0xE2F5 0x6029 # 0 +0xE2F6 0x602B # 0 +0xE2F7 0x600A # 0 +0xE2F8 0x603F # 0 +0xE2F9 0x6021 # 0 +0xE2FA 0x6078 # 0 +0xE2FB 0x6079 # 0 +0xE2FC 0x607B # 0 +0xE2FD 0x607A # 0 +0xE2FE 0x6042 # 0 +0xE340 0x9246 # 0 +0xE341 0x9247 # 0 +0xE342 0x9248 # 0 +0xE343 0x9249 # 0 +0xE344 0x924A # 0 +0xE345 0x924B # 0 +0xE346 0x924C # 0 +0xE347 0x924D # 0 +0xE348 0x924E # 0 +0xE349 0x924F # 0 +0xE34A 0x9250 # 0 +0xE34B 0x9251 # 0 +0xE34C 0x9252 # 0 +0xE34D 0x9253 # 0 +0xE34E 0x9254 # 0 +0xE34F 0x9255 # 0 +0xE350 0x9256 # 0 +0xE351 0x9257 # 0 +0xE352 0x9258 # 0 +0xE353 0x9259 # 0 +0xE354 0x925A # 0 +0xE355 0x925B # 0 +0xE356 0x925C # 0 +0xE357 0x925D # 0 +0xE358 0x925E # 0 +0xE359 0x925F # 0 +0xE35A 0x9260 # 0 +0xE35B 0x9261 # 0 +0xE35C 0x9262 # 0 +0xE35D 0x9263 # 0 +0xE35E 0x9264 # 0 +0xE35F 0x9265 # 0 +0xE360 0x9266 # 0 +0xE361 0x9267 # 0 +0xE362 0x9268 # 0 +0xE363 0x9269 # 0 +0xE364 0x926A # 0 +0xE365 0x926B # 0 +0xE366 0x926C # 0 +0xE367 0x926D # 0 +0xE368 0x926E # 0 +0xE369 0x926F # 0 +0xE36A 0x9270 # 0 +0xE36B 0x9271 # 0 +0xE36C 0x9272 # 0 +0xE36D 0x9273 # 0 +0xE36E 0x9275 # 0 +0xE36F 0x9276 # 0 +0xE370 0x9277 # 0 +0xE371 0x9278 # 0 +0xE372 0x9279 # 0 +0xE373 0x927A # 0 +0xE374 0x927B # 0 +0xE375 0x927C # 0 +0xE376 0x927D # 0 +0xE377 0x927E # 0 +0xE378 0x927F # 0 +0xE379 0x9280 # 0 +0xE37A 0x9281 # 0 +0xE37B 0x9282 # 0 +0xE37C 0x9283 # 0 +0xE37D 0x9284 # 0 +0xE37E 0x9285 # 0 +0xE380 0x9286 # 0 +0xE381 0x9287 # 0 +0xE382 0x9288 # 0 +0xE383 0x9289 # 0 +0xE384 0x928A # 0 +0xE385 0x928B # 0 +0xE386 0x928C # 0 +0xE387 0x928D # 0 +0xE388 0x928F # 0 +0xE389 0x9290 # 0 +0xE38A 0x9291 # 0 +0xE38B 0x9292 # 0 +0xE38C 0x9293 # 0 +0xE38D 0x9294 # 0 +0xE38E 0x9295 # 0 +0xE38F 0x9296 # 0 +0xE390 0x9297 # 0 +0xE391 0x9298 # 0 +0xE392 0x9299 # 0 +0xE393 0x929A # 0 +0xE394 0x929B # 0 +0xE395 0x929C # 0 +0xE396 0x929D # 0 +0xE397 0x929E # 0 +0xE398 0x929F # 0 +0xE399 0x92A0 # 0 +0xE39A 0x92A1 # 0 +0xE39B 0x92A2 # 0 +0xE39C 0x92A3 # 0 +0xE39D 0x92A4 # 0 +0xE39E 0x92A5 # 0 +0xE39F 0x92A6 # 0 +0xE3A0 0x92A7 # 0 +0xE3A1 0x606A # 0 +0xE3A2 0x607D # 0 +0xE3A3 0x6096 # 0 +0xE3A4 0x609A # 0 +0xE3A5 0x60AD # 0 +0xE3A6 0x609D # 0 +0xE3A7 0x6083 # 0 +0xE3A8 0x6092 # 0 +0xE3A9 0x608C # 0 +0xE3AA 0x609B # 0 +0xE3AB 0x60EC # 0 +0xE3AC 0x60BB # 0 +0xE3AD 0x60B1 # 0 +0xE3AE 0x60DD # 0 +0xE3AF 0x60D8 # 0 +0xE3B0 0x60C6 # 0 +0xE3B1 0x60DA # 0 +0xE3B2 0x60B4 # 0 +0xE3B3 0x6120 # 0 +0xE3B4 0x6126 # 0 +0xE3B5 0x6115 # 0 +0xE3B6 0x6123 # 0 +0xE3B7 0x60F4 # 0 +0xE3B8 0x6100 # 0 +0xE3B9 0x610E # 0 +0xE3BA 0x612B # 0 +0xE3BB 0x614A # 0 +0xE3BC 0x6175 # 0 +0xE3BD 0x61AC # 0 +0xE3BE 0x6194 # 0 +0xE3BF 0x61A7 # 0 +0xE3C0 0x61B7 # 0 +0xE3C1 0x61D4 # 0 +0xE3C2 0x61F5 # 0 +0xE3C3 0x5FDD # 0 +0xE3C4 0x96B3 # 0 +0xE3C5 0x95E9 # 0 +0xE3C6 0x95EB # 0 +0xE3C7 0x95F1 # 0 +0xE3C8 0x95F3 # 0 +0xE3C9 0x95F5 # 0 +0xE3CA 0x95F6 # 0 +0xE3CB 0x95FC # 0 +0xE3CC 0x95FE # 0 +0xE3CD 0x9603 # 0 +0xE3CE 0x9604 # 0 +0xE3CF 0x9606 # 0 +0xE3D0 0x9608 # 0 +0xE3D1 0x960A # 0 +0xE3D2 0x960B # 0 +0xE3D3 0x960C # 0 +0xE3D4 0x960D # 0 +0xE3D5 0x960F # 0 +0xE3D6 0x9612 # 0 +0xE3D7 0x9615 # 0 +0xE3D8 0x9616 # 0 +0xE3D9 0x9617 # 0 +0xE3DA 0x9619 # 0 +0xE3DB 0x961A # 0 +0xE3DC 0x4E2C # 0 +0xE3DD 0x723F # 0 +0xE3DE 0x6215 # 0 +0xE3DF 0x6C35 # 0 +0xE3E0 0x6C54 # 0 +0xE3E1 0x6C5C # 0 +0xE3E2 0x6C4A # 0 +0xE3E3 0x6CA3 # 0 +0xE3E4 0x6C85 # 0 +0xE3E5 0x6C90 # 0 +0xE3E6 0x6C94 # 0 +0xE3E7 0x6C8C # 0 +0xE3E8 0x6C68 # 0 +0xE3E9 0x6C69 # 0 +0xE3EA 0x6C74 # 0 +0xE3EB 0x6C76 # 0 +0xE3EC 0x6C86 # 0 +0xE3ED 0x6CA9 # 0 +0xE3EE 0x6CD0 # 0 +0xE3EF 0x6CD4 # 0 +0xE3F0 0x6CAD # 0 +0xE3F1 0x6CF7 # 0 +0xE3F2 0x6CF8 # 0 +0xE3F3 0x6CF1 # 0 +0xE3F4 0x6CD7 # 0 +0xE3F5 0x6CB2 # 0 +0xE3F6 0x6CE0 # 0 +0xE3F7 0x6CD6 # 0 +0xE3F8 0x6CFA # 0 +0xE3F9 0x6CEB # 0 +0xE3FA 0x6CEE # 0 +0xE3FB 0x6CB1 # 0 +0xE3FC 0x6CD3 # 0 +0xE3FD 0x6CEF # 0 +0xE3FE 0x6CFE # 0 +0xE440 0x92A8 # 0 +0xE441 0x92A9 # 0 +0xE442 0x92AA # 0 +0xE443 0x92AB # 0 +0xE444 0x92AC # 0 +0xE445 0x92AD # 0 +0xE446 0x92AF # 0 +0xE447 0x92B0 # 0 +0xE448 0x92B1 # 0 +0xE449 0x92B2 # 0 +0xE44A 0x92B3 # 0 +0xE44B 0x92B4 # 0 +0xE44C 0x92B5 # 0 +0xE44D 0x92B6 # 0 +0xE44E 0x92B7 # 0 +0xE44F 0x92B8 # 0 +0xE450 0x92B9 # 0 +0xE451 0x92BA # 0 +0xE452 0x92BB # 0 +0xE453 0x92BC # 0 +0xE454 0x92BD # 0 +0xE455 0x92BE # 0 +0xE456 0x92BF # 0 +0xE457 0x92C0 # 0 +0xE458 0x92C1 # 0 +0xE459 0x92C2 # 0 +0xE45A 0x92C3 # 0 +0xE45B 0x92C4 # 0 +0xE45C 0x92C5 # 0 +0xE45D 0x92C6 # 0 +0xE45E 0x92C7 # 0 +0xE45F 0x92C9 # 0 +0xE460 0x92CA # 0 +0xE461 0x92CB # 0 +0xE462 0x92CC # 0 +0xE463 0x92CD # 0 +0xE464 0x92CE # 0 +0xE465 0x92CF # 0 +0xE466 0x92D0 # 0 +0xE467 0x92D1 # 0 +0xE468 0x92D2 # 0 +0xE469 0x92D3 # 0 +0xE46A 0x92D4 # 0 +0xE46B 0x92D5 # 0 +0xE46C 0x92D6 # 0 +0xE46D 0x92D7 # 0 +0xE46E 0x92D8 # 0 +0xE46F 0x92D9 # 0 +0xE470 0x92DA # 0 +0xE471 0x92DB # 0 +0xE472 0x92DC # 0 +0xE473 0x92DD # 0 +0xE474 0x92DE # 0 +0xE475 0x92DF # 0 +0xE476 0x92E0 # 0 +0xE477 0x92E1 # 0 +0xE478 0x92E2 # 0 +0xE479 0x92E3 # 0 +0xE47A 0x92E4 # 0 +0xE47B 0x92E5 # 0 +0xE47C 0x92E6 # 0 +0xE47D 0x92E7 # 0 +0xE47E 0x92E8 # 0 +0xE480 0x92E9 # 0 +0xE481 0x92EA # 0 +0xE482 0x92EB # 0 +0xE483 0x92EC # 0 +0xE484 0x92ED # 0 +0xE485 0x92EE # 0 +0xE486 0x92EF # 0 +0xE487 0x92F0 # 0 +0xE488 0x92F1 # 0 +0xE489 0x92F2 # 0 +0xE48A 0x92F3 # 0 +0xE48B 0x92F4 # 0 +0xE48C 0x92F5 # 0 +0xE48D 0x92F6 # 0 +0xE48E 0x92F7 # 0 +0xE48F 0x92F8 # 0 +0xE490 0x92F9 # 0 +0xE491 0x92FA # 0 +0xE492 0x92FB # 0 +0xE493 0x92FC # 0 +0xE494 0x92FD # 0 +0xE495 0x92FE # 0 +0xE496 0x92FF # 0 +0xE497 0x9300 # 0 +0xE498 0x9301 # 0 +0xE499 0x9302 # 0 +0xE49A 0x9303 # 0 +0xE49B 0x9304 # 0 +0xE49C 0x9305 # 0 +0xE49D 0x9306 # 0 +0xE49E 0x9307 # 0 +0xE49F 0x9308 # 0 +0xE4A0 0x9309 # 0 +0xE4A1 0x6D39 # 0 +0xE4A2 0x6D27 # 0 +0xE4A3 0x6D0C # 0 +0xE4A4 0x6D43 # 0 +0xE4A5 0x6D48 # 0 +0xE4A6 0x6D07 # 0 +0xE4A7 0x6D04 # 0 +0xE4A8 0x6D19 # 0 +0xE4A9 0x6D0E # 0 +0xE4AA 0x6D2B # 0 +0xE4AB 0x6D4D # 0 +0xE4AC 0x6D2E # 0 +0xE4AD 0x6D35 # 0 +0xE4AE 0x6D1A # 0 +0xE4AF 0x6D4F # 0 +0xE4B0 0x6D52 # 0 +0xE4B1 0x6D54 # 0 +0xE4B2 0x6D33 # 0 +0xE4B3 0x6D91 # 0 +0xE4B4 0x6D6F # 0 +0xE4B5 0x6D9E # 0 +0xE4B6 0x6DA0 # 0 +0xE4B7 0x6D5E # 0 +0xE4B8 0x6D93 # 0 +0xE4B9 0x6D94 # 0 +0xE4BA 0x6D5C # 0 +0xE4BB 0x6D60 # 0 +0xE4BC 0x6D7C # 0 +0xE4BD 0x6D63 # 0 +0xE4BE 0x6E1A # 0 +0xE4BF 0x6DC7 # 0 +0xE4C0 0x6DC5 # 0 +0xE4C1 0x6DDE # 0 +0xE4C2 0x6E0E # 0 +0xE4C3 0x6DBF # 0 +0xE4C4 0x6DE0 # 0 +0xE4C5 0x6E11 # 0 +0xE4C6 0x6DE6 # 0 +0xE4C7 0x6DDD # 0 +0xE4C8 0x6DD9 # 0 +0xE4C9 0x6E16 # 0 +0xE4CA 0x6DAB # 0 +0xE4CB 0x6E0C # 0 +0xE4CC 0x6DAE # 0 +0xE4CD 0x6E2B # 0 +0xE4CE 0x6E6E # 0 +0xE4CF 0x6E4E # 0 +0xE4D0 0x6E6B # 0 +0xE4D1 0x6EB2 # 0 +0xE4D2 0x6E5F # 0 +0xE4D3 0x6E86 # 0 +0xE4D4 0x6E53 # 0 +0xE4D5 0x6E54 # 0 +0xE4D6 0x6E32 # 0 +0xE4D7 0x6E25 # 0 +0xE4D8 0x6E44 # 0 +0xE4D9 0x6EDF # 0 +0xE4DA 0x6EB1 # 0 +0xE4DB 0x6E98 # 0 +0xE4DC 0x6EE0 # 0 +0xE4DD 0x6F2D # 0 +0xE4DE 0x6EE2 # 0 +0xE4DF 0x6EA5 # 0 +0xE4E0 0x6EA7 # 0 +0xE4E1 0x6EBD # 0 +0xE4E2 0x6EBB # 0 +0xE4E3 0x6EB7 # 0 +0xE4E4 0x6ED7 # 0 +0xE4E5 0x6EB4 # 0 +0xE4E6 0x6ECF # 0 +0xE4E7 0x6E8F # 0 +0xE4E8 0x6EC2 # 0 +0xE4E9 0x6E9F # 0 +0xE4EA 0x6F62 # 0 +0xE4EB 0x6F46 # 0 +0xE4EC 0x6F47 # 0 +0xE4ED 0x6F24 # 0 +0xE4EE 0x6F15 # 0 +0xE4EF 0x6EF9 # 0 +0xE4F0 0x6F2F # 0 +0xE4F1 0x6F36 # 0 +0xE4F2 0x6F4B # 0 +0xE4F3 0x6F74 # 0 +0xE4F4 0x6F2A # 0 +0xE4F5 0x6F09 # 0 +0xE4F6 0x6F29 # 0 +0xE4F7 0x6F89 # 0 +0xE4F8 0x6F8D # 0 +0xE4F9 0x6F8C # 0 +0xE4FA 0x6F78 # 0 +0xE4FB 0x6F72 # 0 +0xE4FC 0x6F7C # 0 +0xE4FD 0x6F7A # 0 +0xE4FE 0x6FD1 # 0 +0xE540 0x930A # 0 +0xE541 0x930B # 0 +0xE542 0x930C # 0 +0xE543 0x930D # 0 +0xE544 0x930E # 0 +0xE545 0x930F # 0 +0xE546 0x9310 # 0 +0xE547 0x9311 # 0 +0xE548 0x9312 # 0 +0xE549 0x9313 # 0 +0xE54A 0x9314 # 0 +0xE54B 0x9315 # 0 +0xE54C 0x9316 # 0 +0xE54D 0x9317 # 0 +0xE54E 0x9318 # 0 +0xE54F 0x9319 # 0 +0xE550 0x931A # 0 +0xE551 0x931B # 0 +0xE552 0x931C # 0 +0xE553 0x931D # 0 +0xE554 0x931E # 0 +0xE555 0x931F # 0 +0xE556 0x9320 # 0 +0xE557 0x9321 # 0 +0xE558 0x9322 # 0 +0xE559 0x9323 # 0 +0xE55A 0x9324 # 0 +0xE55B 0x9325 # 0 +0xE55C 0x9326 # 0 +0xE55D 0x9327 # 0 +0xE55E 0x9328 # 0 +0xE55F 0x9329 # 0 +0xE560 0x932A # 0 +0xE561 0x932B # 0 +0xE562 0x932C # 0 +0xE563 0x932D # 0 +0xE564 0x932E # 0 +0xE565 0x932F # 0 +0xE566 0x9330 # 0 +0xE567 0x9331 # 0 +0xE568 0x9332 # 0 +0xE569 0x9333 # 0 +0xE56A 0x9334 # 0 +0xE56B 0x9335 # 0 +0xE56C 0x9336 # 0 +0xE56D 0x9337 # 0 +0xE56E 0x9338 # 0 +0xE56F 0x9339 # 0 +0xE570 0x933A # 0 +0xE571 0x933B # 0 +0xE572 0x933C # 0 +0xE573 0x933D # 0 +0xE574 0x933F # 0 +0xE575 0x9340 # 0 +0xE576 0x9341 # 0 +0xE577 0x9342 # 0 +0xE578 0x9343 # 0 +0xE579 0x9344 # 0 +0xE57A 0x9345 # 0 +0xE57B 0x9346 # 0 +0xE57C 0x9347 # 0 +0xE57D 0x9348 # 0 +0xE57E 0x9349 # 0 +0xE580 0x934A # 0 +0xE581 0x934B # 0 +0xE582 0x934C # 0 +0xE583 0x934D # 0 +0xE584 0x934E # 0 +0xE585 0x934F # 0 +0xE586 0x9350 # 0 +0xE587 0x9351 # 0 +0xE588 0x9352 # 0 +0xE589 0x9353 # 0 +0xE58A 0x9354 # 0 +0xE58B 0x9355 # 0 +0xE58C 0x9356 # 0 +0xE58D 0x9357 # 0 +0xE58E 0x9358 # 0 +0xE58F 0x9359 # 0 +0xE590 0x935A # 0 +0xE591 0x935B # 0 +0xE592 0x935C # 0 +0xE593 0x935D # 0 +0xE594 0x935E # 0 +0xE595 0x935F # 0 +0xE596 0x9360 # 0 +0xE597 0x9361 # 0 +0xE598 0x9362 # 0 +0xE599 0x9363 # 0 +0xE59A 0x9364 # 0 +0xE59B 0x9365 # 0 +0xE59C 0x9366 # 0 +0xE59D 0x9367 # 0 +0xE59E 0x9368 # 0 +0xE59F 0x9369 # 0 +0xE5A0 0x936B # 0 +0xE5A1 0x6FC9 # 0 +0xE5A2 0x6FA7 # 0 +0xE5A3 0x6FB9 # 0 +0xE5A4 0x6FB6 # 0 +0xE5A5 0x6FC2 # 0 +0xE5A6 0x6FE1 # 0 +0xE5A7 0x6FEE # 0 +0xE5A8 0x6FDE # 0 +0xE5A9 0x6FE0 # 0 +0xE5AA 0x6FEF # 0 +0xE5AB 0x701A # 0 +0xE5AC 0x7023 # 0 +0xE5AD 0x701B # 0 +0xE5AE 0x7039 # 0 +0xE5AF 0x7035 # 0 +0xE5B0 0x704F # 0 +0xE5B1 0x705E # 0 +0xE5B2 0x5B80 # 0 +0xE5B3 0x5B84 # 0 +0xE5B4 0x5B95 # 0 +0xE5B5 0x5B93 # 0 +0xE5B6 0x5BA5 # 0 +0xE5B7 0x5BB8 # 0 +0xE5B8 0x752F # 0 +0xE5B9 0x9A9E # 0 +0xE5BA 0x6434 # 0 +0xE5BB 0x5BE4 # 0 +0xE5BC 0x5BEE # 0 +0xE5BD 0x8930 # 0 +0xE5BE 0x5BF0 # 0 +0xE5BF 0x8E47 # 0 +0xE5C0 0x8B07 # 0 +0xE5C1 0x8FB6 # 0 +0xE5C2 0x8FD3 # 0 +0xE5C3 0x8FD5 # 0 +0xE5C4 0x8FE5 # 0 +0xE5C5 0x8FEE # 0 +0xE5C6 0x8FE4 # 0 +0xE5C7 0x8FE9 # 0 +0xE5C8 0x8FE6 # 0 +0xE5C9 0x8FF3 # 0 +0xE5CA 0x8FE8 # 0 +0xE5CB 0x9005 # 0 +0xE5CC 0x9004 # 0 +0xE5CD 0x900B # 0 +0xE5CE 0x9026 # 0 +0xE5CF 0x9011 # 0 +0xE5D0 0x900D # 0 +0xE5D1 0x9016 # 0 +0xE5D2 0x9021 # 0 +0xE5D3 0x9035 # 0 +0xE5D4 0x9036 # 0 +0xE5D5 0x902D # 0 +0xE5D6 0x902F # 0 +0xE5D7 0x9044 # 0 +0xE5D8 0x9051 # 0 +0xE5D9 0x9052 # 0 +0xE5DA 0x9050 # 0 +0xE5DB 0x9068 # 0 +0xE5DC 0x9058 # 0 +0xE5DD 0x9062 # 0 +0xE5DE 0x905B # 0 +0xE5DF 0x66B9 # 0 +0xE5E0 0x9074 # 0 +0xE5E1 0x907D # 0 +0xE5E2 0x9082 # 0 +0xE5E3 0x9088 # 0 +0xE5E4 0x9083 # 0 +0xE5E5 0x908B # 0 +0xE5E6 0x5F50 # 0 +0xE5E7 0x5F57 # 0 +0xE5E8 0x5F56 # 0 +0xE5E9 0x5F58 # 0 +0xE5EA 0x5C3B # 0 +0xE5EB 0x54AB # 0 +0xE5EC 0x5C50 # 0 +0xE5ED 0x5C59 # 0 +0xE5EE 0x5B71 # 0 +0xE5EF 0x5C63 # 0 +0xE5F0 0x5C66 # 0 +0xE5F1 0x7FBC # 0 +0xE5F2 0x5F2A # 0 +0xE5F3 0x5F29 # 0 +0xE5F4 0x5F2D # 0 +0xE5F5 0x8274 # 0 +0xE5F6 0x5F3C # 0 +0xE5F7 0x9B3B # 0 +0xE5F8 0x5C6E # 0 +0xE5F9 0x5981 # 0 +0xE5FA 0x5983 # 0 +0xE5FB 0x598D # 0 +0xE5FC 0x59A9 # 0 +0xE5FD 0x59AA # 0 +0xE5FE 0x59A3 # 0 +0xE640 0x936C # 0 +0xE641 0x936D # 0 +0xE642 0x936E # 0 +0xE643 0x936F # 0 +0xE644 0x9370 # 0 +0xE645 0x9371 # 0 +0xE646 0x9372 # 0 +0xE647 0x9373 # 0 +0xE648 0x9374 # 0 +0xE649 0x9375 # 0 +0xE64A 0x9376 # 0 +0xE64B 0x9377 # 0 +0xE64C 0x9378 # 0 +0xE64D 0x9379 # 0 +0xE64E 0x937A # 0 +0xE64F 0x937B # 0 +0xE650 0x937C # 0 +0xE651 0x937D # 0 +0xE652 0x937E # 0 +0xE653 0x937F # 0 +0xE654 0x9380 # 0 +0xE655 0x9381 # 0 +0xE656 0x9382 # 0 +0xE657 0x9383 # 0 +0xE658 0x9384 # 0 +0xE659 0x9385 # 0 +0xE65A 0x9386 # 0 +0xE65B 0x9387 # 0 +0xE65C 0x9388 # 0 +0xE65D 0x9389 # 0 +0xE65E 0x938A # 0 +0xE65F 0x938B # 0 +0xE660 0x938C # 0 +0xE661 0x938D # 0 +0xE662 0x938E # 0 +0xE663 0x9390 # 0 +0xE664 0x9391 # 0 +0xE665 0x9392 # 0 +0xE666 0x9393 # 0 +0xE667 0x9394 # 0 +0xE668 0x9395 # 0 +0xE669 0x9396 # 0 +0xE66A 0x9397 # 0 +0xE66B 0x9398 # 0 +0xE66C 0x9399 # 0 +0xE66D 0x939A # 0 +0xE66E 0x939B # 0 +0xE66F 0x939C # 0 +0xE670 0x939D # 0 +0xE671 0x939E # 0 +0xE672 0x939F # 0 +0xE673 0x93A0 # 0 +0xE674 0x93A1 # 0 +0xE675 0x93A2 # 0 +0xE676 0x93A3 # 0 +0xE677 0x93A4 # 0 +0xE678 0x93A5 # 0 +0xE679 0x93A6 # 0 +0xE67A 0x93A7 # 0 +0xE67B 0x93A8 # 0 +0xE67C 0x93A9 # 0 +0xE67D 0x93AA # 0 +0xE67E 0x93AB # 0 +0xE680 0x93AC # 0 +0xE681 0x93AD # 0 +0xE682 0x93AE # 0 +0xE683 0x93AF # 0 +0xE684 0x93B0 # 0 +0xE685 0x93B1 # 0 +0xE686 0x93B2 # 0 +0xE687 0x93B3 # 0 +0xE688 0x93B4 # 0 +0xE689 0x93B5 # 0 +0xE68A 0x93B6 # 0 +0xE68B 0x93B7 # 0 +0xE68C 0x93B8 # 0 +0xE68D 0x93B9 # 0 +0xE68E 0x93BA # 0 +0xE68F 0x93BB # 0 +0xE690 0x93BC # 0 +0xE691 0x93BD # 0 +0xE692 0x93BE # 0 +0xE693 0x93BF # 0 +0xE694 0x93C0 # 0 +0xE695 0x93C1 # 0 +0xE696 0x93C2 # 0 +0xE697 0x93C3 # 0 +0xE698 0x93C4 # 0 +0xE699 0x93C5 # 0 +0xE69A 0x93C6 # 0 +0xE69B 0x93C7 # 0 +0xE69C 0x93C8 # 0 +0xE69D 0x93C9 # 0 +0xE69E 0x93CB # 0 +0xE69F 0x93CC # 0 +0xE6A0 0x93CD # 0 +0xE6A1 0x5997 # 0 +0xE6A2 0x59CA # 0 +0xE6A3 0x59AB # 0 +0xE6A4 0x599E # 0 +0xE6A5 0x59A4 # 0 +0xE6A6 0x59D2 # 0 +0xE6A7 0x59B2 # 0 +0xE6A8 0x59AF # 0 +0xE6A9 0x59D7 # 0 +0xE6AA 0x59BE # 0 +0xE6AB 0x5A05 # 0 +0xE6AC 0x5A06 # 0 +0xE6AD 0x59DD # 0 +0xE6AE 0x5A08 # 0 +0xE6AF 0x59E3 # 0 +0xE6B0 0x59D8 # 0 +0xE6B1 0x59F9 # 0 +0xE6B2 0x5A0C # 0 +0xE6B3 0x5A09 # 0 +0xE6B4 0x5A32 # 0 +0xE6B5 0x5A34 # 0 +0xE6B6 0x5A11 # 0 +0xE6B7 0x5A23 # 0 +0xE6B8 0x5A13 # 0 +0xE6B9 0x5A40 # 0 +0xE6BA 0x5A67 # 0 +0xE6BB 0x5A4A # 0 +0xE6BC 0x5A55 # 0 +0xE6BD 0x5A3C # 0 +0xE6BE 0x5A62 # 0 +0xE6BF 0x5A75 # 0 +0xE6C0 0x80EC # 0 +0xE6C1 0x5AAA # 0 +0xE6C2 0x5A9B # 0 +0xE6C3 0x5A77 # 0 +0xE6C4 0x5A7A # 0 +0xE6C5 0x5ABE # 0 +0xE6C6 0x5AEB # 0 +0xE6C7 0x5AB2 # 0 +0xE6C8 0x5AD2 # 0 +0xE6C9 0x5AD4 # 0 +0xE6CA 0x5AB8 # 0 +0xE6CB 0x5AE0 # 0 +0xE6CC 0x5AE3 # 0 +0xE6CD 0x5AF1 # 0 +0xE6CE 0x5AD6 # 0 +0xE6CF 0x5AE6 # 0 +0xE6D0 0x5AD8 # 0 +0xE6D1 0x5ADC # 0 +0xE6D2 0x5B09 # 0 +0xE6D3 0x5B17 # 0 +0xE6D4 0x5B16 # 0 +0xE6D5 0x5B32 # 0 +0xE6D6 0x5B37 # 0 +0xE6D7 0x5B40 # 0 +0xE6D8 0x5C15 # 0 +0xE6D9 0x5C1C # 0 +0xE6DA 0x5B5A # 0 +0xE6DB 0x5B65 # 0 +0xE6DC 0x5B73 # 0 +0xE6DD 0x5B51 # 0 +0xE6DE 0x5B53 # 0 +0xE6DF 0x5B62 # 0 +0xE6E0 0x9A75 # 0 +0xE6E1 0x9A77 # 0 +0xE6E2 0x9A78 # 0 +0xE6E3 0x9A7A # 0 +0xE6E4 0x9A7F # 0 +0xE6E5 0x9A7D # 0 +0xE6E6 0x9A80 # 0 +0xE6E7 0x9A81 # 0 +0xE6E8 0x9A85 # 0 +0xE6E9 0x9A88 # 0 +0xE6EA 0x9A8A # 0 +0xE6EB 0x9A90 # 0 +0xE6EC 0x9A92 # 0 +0xE6ED 0x9A93 # 0 +0xE6EE 0x9A96 # 0 +0xE6EF 0x9A98 # 0 +0xE6F0 0x9A9B # 0 +0xE6F1 0x9A9C # 0 +0xE6F2 0x9A9D # 0 +0xE6F3 0x9A9F # 0 +0xE6F4 0x9AA0 # 0 +0xE6F5 0x9AA2 # 0 +0xE6F6 0x9AA3 # 0 +0xE6F7 0x9AA5 # 0 +0xE6F8 0x9AA7 # 0 +0xE6F9 0x7E9F # 0 +0xE6FA 0x7EA1 # 0 +0xE6FB 0x7EA3 # 0 +0xE6FC 0x7EA5 # 0 +0xE6FD 0x7EA8 # 0 +0xE6FE 0x7EA9 # 0 +0xE740 0x93CE # 0 +0xE741 0x93CF # 0 +0xE742 0x93D0 # 0 +0xE743 0x93D1 # 0 +0xE744 0x93D2 # 0 +0xE745 0x93D3 # 0 +0xE746 0x93D4 # 0 +0xE747 0x93D5 # 0 +0xE748 0x93D7 # 0 +0xE749 0x93D8 # 0 +0xE74A 0x93D9 # 0 +0xE74B 0x93DA # 0 +0xE74C 0x93DB # 0 +0xE74D 0x93DC # 0 +0xE74E 0x93DD # 0 +0xE74F 0x93DE # 0 +0xE750 0x93DF # 0 +0xE751 0x93E0 # 0 +0xE752 0x93E1 # 0 +0xE753 0x93E2 # 0 +0xE754 0x93E3 # 0 +0xE755 0x93E4 # 0 +0xE756 0x93E5 # 0 +0xE757 0x93E6 # 0 +0xE758 0x93E7 # 0 +0xE759 0x93E8 # 0 +0xE75A 0x93E9 # 0 +0xE75B 0x93EA # 0 +0xE75C 0x93EB # 0 +0xE75D 0x93EC # 0 +0xE75E 0x93ED # 0 +0xE75F 0x93EE # 0 +0xE760 0x93EF # 0 +0xE761 0x93F0 # 0 +0xE762 0x93F1 # 0 +0xE763 0x93F2 # 0 +0xE764 0x93F3 # 0 +0xE765 0x93F4 # 0 +0xE766 0x93F5 # 0 +0xE767 0x93F6 # 0 +0xE768 0x93F7 # 0 +0xE769 0x93F8 # 0 +0xE76A 0x93F9 # 0 +0xE76B 0x93FA # 0 +0xE76C 0x93FB # 0 +0xE76D 0x93FC # 0 +0xE76E 0x93FD # 0 +0xE76F 0x93FE # 0 +0xE770 0x93FF # 0 +0xE771 0x9400 # 0 +0xE772 0x9401 # 0 +0xE773 0x9402 # 0 +0xE774 0x9403 # 0 +0xE775 0x9404 # 0 +0xE776 0x9405 # 0 +0xE777 0x9406 # 0 +0xE778 0x9407 # 0 +0xE779 0x9408 # 0 +0xE77A 0x9409 # 0 +0xE77B 0x940A # 0 +0xE77C 0x940B # 0 +0xE77D 0x940C # 0 +0xE77E 0x940D # 0 +0xE780 0x940E # 0 +0xE781 0x940F # 0 +0xE782 0x9410 # 0 +0xE783 0x9411 # 0 +0xE784 0x9412 # 0 +0xE785 0x9413 # 0 +0xE786 0x9414 # 0 +0xE787 0x9415 # 0 +0xE788 0x9416 # 0 +0xE789 0x9417 # 0 +0xE78A 0x9418 # 0 +0xE78B 0x9419 # 0 +0xE78C 0x941A # 0 +0xE78D 0x941B # 0 +0xE78E 0x941C # 0 +0xE78F 0x941D # 0 +0xE790 0x941E # 0 +0xE791 0x941F # 0 +0xE792 0x9420 # 0 +0xE793 0x9421 # 0 +0xE794 0x9422 # 0 +0xE795 0x9423 # 0 +0xE796 0x9424 # 0 +0xE797 0x9425 # 0 +0xE798 0x9426 # 0 +0xE799 0x9427 # 0 +0xE79A 0x9428 # 0 +0xE79B 0x9429 # 0 +0xE79C 0x942A # 0 +0xE79D 0x942B # 0 +0xE79E 0x942C # 0 +0xE79F 0x942D # 0 +0xE7A0 0x942E # 0 +0xE7A1 0x7EAD # 0 +0xE7A2 0x7EB0 # 0 +0xE7A3 0x7EBE # 0 +0xE7A4 0x7EC0 # 0 +0xE7A5 0x7EC1 # 0 +0xE7A6 0x7EC2 # 0 +0xE7A7 0x7EC9 # 0 +0xE7A8 0x7ECB # 0 +0xE7A9 0x7ECC # 0 +0xE7AA 0x7ED0 # 0 +0xE7AB 0x7ED4 # 0 +0xE7AC 0x7ED7 # 0 +0xE7AD 0x7EDB # 0 +0xE7AE 0x7EE0 # 0 +0xE7AF 0x7EE1 # 0 +0xE7B0 0x7EE8 # 0 +0xE7B1 0x7EEB # 0 +0xE7B2 0x7EEE # 0 +0xE7B3 0x7EEF # 0 +0xE7B4 0x7EF1 # 0 +0xE7B5 0x7EF2 # 0 +0xE7B6 0x7F0D # 0 +0xE7B7 0x7EF6 # 0 +0xE7B8 0x7EFA # 0 +0xE7B9 0x7EFB # 0 +0xE7BA 0x7EFE # 0 +0xE7BB 0x7F01 # 0 +0xE7BC 0x7F02 # 0 +0xE7BD 0x7F03 # 0 +0xE7BE 0x7F07 # 0 +0xE7BF 0x7F08 # 0 +0xE7C0 0x7F0B # 0 +0xE7C1 0x7F0C # 0 +0xE7C2 0x7F0F # 0 +0xE7C3 0x7F11 # 0 +0xE7C4 0x7F12 # 0 +0xE7C5 0x7F17 # 0 +0xE7C6 0x7F19 # 0 +0xE7C7 0x7F1C # 0 +0xE7C8 0x7F1B # 0 +0xE7C9 0x7F1F # 0 +0xE7CA 0x7F21 # 0 +0xE7CB 0x7F22 # 0 +0xE7CC 0x7F23 # 0 +0xE7CD 0x7F24 # 0 +0xE7CE 0x7F25 # 0 +0xE7CF 0x7F26 # 0 +0xE7D0 0x7F27 # 0 +0xE7D1 0x7F2A # 0 +0xE7D2 0x7F2B # 0 +0xE7D3 0x7F2C # 0 +0xE7D4 0x7F2D # 0 +0xE7D5 0x7F2F # 0 +0xE7D6 0x7F30 # 0 +0xE7D7 0x7F31 # 0 +0xE7D8 0x7F32 # 0 +0xE7D9 0x7F33 # 0 +0xE7DA 0x7F35 # 0 +0xE7DB 0x5E7A # 0 +0xE7DC 0x757F # 0 +0xE7DD 0x5DDB # 0 +0xE7DE 0x753E # 0 +0xE7DF 0x9095 # 0 +0xE7E0 0x738E # 0 +0xE7E1 0x7391 # 0 +0xE7E2 0x73AE # 0 +0xE7E3 0x73A2 # 0 +0xE7E4 0x739F # 0 +0xE7E5 0x73CF # 0 +0xE7E6 0x73C2 # 0 +0xE7E7 0x73D1 # 0 +0xE7E8 0x73B7 # 0 +0xE7E9 0x73B3 # 0 +0xE7EA 0x73C0 # 0 +0xE7EB 0x73C9 # 0 +0xE7EC 0x73C8 # 0 +0xE7ED 0x73E5 # 0 +0xE7EE 0x73D9 # 0 +0xE7EF 0x987C # 0 +0xE7F0 0x740A # 0 +0xE7F1 0x73E9 # 0 +0xE7F2 0x73E7 # 0 +0xE7F3 0x73DE # 0 +0xE7F4 0x73BA # 0 +0xE7F5 0x73F2 # 0 +0xE7F6 0x740F # 0 +0xE7F7 0x742A # 0 +0xE7F8 0x745B # 0 +0xE7F9 0x7426 # 0 +0xE7FA 0x7425 # 0 +0xE7FB 0x7428 # 0 +0xE7FC 0x7430 # 0 +0xE7FD 0x742E # 0 +0xE7FE 0x742C # 0 +0xE840 0x942F # 0 +0xE841 0x9430 # 0 +0xE842 0x9431 # 0 +0xE843 0x9432 # 0 +0xE844 0x9433 # 0 +0xE845 0x9434 # 0 +0xE846 0x9435 # 0 +0xE847 0x9436 # 0 +0xE848 0x9437 # 0 +0xE849 0x9438 # 0 +0xE84A 0x9439 # 0 +0xE84B 0x943A # 0 +0xE84C 0x943B # 0 +0xE84D 0x943C # 0 +0xE84E 0x943D # 0 +0xE84F 0x943F # 0 +0xE850 0x9440 # 0 +0xE851 0x9441 # 0 +0xE852 0x9442 # 0 +0xE853 0x9443 # 0 +0xE854 0x9444 # 0 +0xE855 0x9445 # 0 +0xE856 0x9446 # 0 +0xE857 0x9447 # 0 +0xE858 0x9448 # 0 +0xE859 0x9449 # 0 +0xE85A 0x944A # 0 +0xE85B 0x944B # 0 +0xE85C 0x944C # 0 +0xE85D 0x944D # 0 +0xE85E 0x944E # 0 +0xE85F 0x944F # 0 +0xE860 0x9450 # 0 +0xE861 0x9451 # 0 +0xE862 0x9452 # 0 +0xE863 0x9453 # 0 +0xE864 0x9454 # 0 +0xE865 0x9455 # 0 +0xE866 0x9456 # 0 +0xE867 0x9457 # 0 +0xE868 0x9458 # 0 +0xE869 0x9459 # 0 +0xE86A 0x945A # 0 +0xE86B 0x945B # 0 +0xE86C 0x945C # 0 +0xE86D 0x945D # 0 +0xE86E 0x945E # 0 +0xE86F 0x945F # 0 +0xE870 0x9460 # 0 +0xE871 0x9461 # 0 +0xE872 0x9462 # 0 +0xE873 0x9463 # 0 +0xE874 0x9464 # 0 +0xE875 0x9465 # 0 +0xE876 0x9466 # 0 +0xE877 0x9467 # 0 +0xE878 0x9468 # 0 +0xE879 0x9469 # 0 +0xE87A 0x946A # 0 +0xE87B 0x946C # 0 +0xE87C 0x946D # 0 +0xE87D 0x946E # 0 +0xE87E 0x946F # 0 +0xE880 0x9470 # 0 +0xE881 0x9471 # 0 +0xE882 0x9472 # 0 +0xE883 0x9473 # 0 +0xE884 0x9474 # 0 +0xE885 0x9475 # 0 +0xE886 0x9476 # 0 +0xE887 0x9477 # 0 +0xE888 0x9478 # 0 +0xE889 0x9479 # 0 +0xE88A 0x947A # 0 +0xE88B 0x947B # 0 +0xE88C 0x947C # 0 +0xE88D 0x947D # 0 +0xE88E 0x947E # 0 +0xE88F 0x947F # 0 +0xE890 0x9480 # 0 +0xE891 0x9481 # 0 +0xE892 0x9482 # 0 +0xE893 0x9483 # 0 +0xE894 0x9484 # 0 +0xE895 0x9491 # 0 +0xE896 0x9496 # 0 +0xE897 0x9498 # 0 +0xE898 0x94C7 # 0 +0xE899 0x94CF # 0 +0xE89A 0x94D3 # 0 +0xE89B 0x94D4 # 0 +0xE89C 0x94DA # 0 +0xE89D 0x94E6 # 0 +0xE89E 0x94FB # 0 +0xE89F 0x951C # 0 +0xE8A0 0x9520 # 0 +0xE8A1 0x741B # 0 +0xE8A2 0x741A # 0 +0xE8A3 0x7441 # 0 +0xE8A4 0x745C # 0 +0xE8A5 0x7457 # 0 +0xE8A6 0x7455 # 0 +0xE8A7 0x7459 # 0 +0xE8A8 0x7477 # 0 +0xE8A9 0x746D # 0 +0xE8AA 0x747E # 0 +0xE8AB 0x749C # 0 +0xE8AC 0x748E # 0 +0xE8AD 0x7480 # 0 +0xE8AE 0x7481 # 0 +0xE8AF 0x7487 # 0 +0xE8B0 0x748B # 0 +0xE8B1 0x749E # 0 +0xE8B2 0x74A8 # 0 +0xE8B3 0x74A9 # 0 +0xE8B4 0x7490 # 0 +0xE8B5 0x74A7 # 0 +0xE8B6 0x74D2 # 0 +0xE8B7 0x74BA # 0 +0xE8B8 0x97EA # 0 +0xE8B9 0x97EB # 0 +0xE8BA 0x97EC # 0 +0xE8BB 0x674C # 0 +0xE8BC 0x6753 # 0 +0xE8BD 0x675E # 0 +0xE8BE 0x6748 # 0 +0xE8BF 0x6769 # 0 +0xE8C0 0x67A5 # 0 +0xE8C1 0x6787 # 0 +0xE8C2 0x676A # 0 +0xE8C3 0x6773 # 0 +0xE8C4 0x6798 # 0 +0xE8C5 0x67A7 # 0 +0xE8C6 0x6775 # 0 +0xE8C7 0x67A8 # 0 +0xE8C8 0x679E # 0 +0xE8C9 0x67AD # 0 +0xE8CA 0x678B # 0 +0xE8CB 0x6777 # 0 +0xE8CC 0x677C # 0 +0xE8CD 0x67F0 # 0 +0xE8CE 0x6809 # 0 +0xE8CF 0x67D8 # 0 +0xE8D0 0x680A # 0 +0xE8D1 0x67E9 # 0 +0xE8D2 0x67B0 # 0 +0xE8D3 0x680C # 0 +0xE8D4 0x67D9 # 0 +0xE8D5 0x67B5 # 0 +0xE8D6 0x67DA # 0 +0xE8D7 0x67B3 # 0 +0xE8D8 0x67DD # 0 +0xE8D9 0x6800 # 0 +0xE8DA 0x67C3 # 0 +0xE8DB 0x67B8 # 0 +0xE8DC 0x67E2 # 0 +0xE8DD 0x680E # 0 +0xE8DE 0x67C1 # 0 +0xE8DF 0x67FD # 0 +0xE8E0 0x6832 # 0 +0xE8E1 0x6833 # 0 +0xE8E2 0x6860 # 0 +0xE8E3 0x6861 # 0 +0xE8E4 0x684E # 0 +0xE8E5 0x6862 # 0 +0xE8E6 0x6844 # 0 +0xE8E7 0x6864 # 0 +0xE8E8 0x6883 # 0 +0xE8E9 0x681D # 0 +0xE8EA 0x6855 # 0 +0xE8EB 0x6866 # 0 +0xE8EC 0x6841 # 0 +0xE8ED 0x6867 # 0 +0xE8EE 0x6840 # 0 +0xE8EF 0x683E # 0 +0xE8F0 0x684A # 0 +0xE8F1 0x6849 # 0 +0xE8F2 0x6829 # 0 +0xE8F3 0x68B5 # 0 +0xE8F4 0x688F # 0 +0xE8F5 0x6874 # 0 +0xE8F6 0x6877 # 0 +0xE8F7 0x6893 # 0 +0xE8F8 0x686B # 0 +0xE8F9 0x68C2 # 0 +0xE8FA 0x696E # 0 +0xE8FB 0x68FC # 0 +0xE8FC 0x691F # 0 +0xE8FD 0x6920 # 0 +0xE8FE 0x68F9 # 0 +0xE940 0x9527 # 0 +0xE941 0x9533 # 0 +0xE942 0x953D # 0 +0xE943 0x9543 # 0 +0xE944 0x9548 # 0 +0xE945 0x954B # 0 +0xE946 0x9555 # 0 +0xE947 0x955A # 0 +0xE948 0x9560 # 0 +0xE949 0x956E # 0 +0xE94A 0x9574 # 0 +0xE94B 0x9575 # 0 +0xE94C 0x9577 # 0 +0xE94D 0x9578 # 0 +0xE94E 0x9579 # 0 +0xE94F 0x957A # 0 +0xE950 0x957B # 0 +0xE951 0x957C # 0 +0xE952 0x957D # 0 +0xE953 0x957E # 0 +0xE954 0x9580 # 0 +0xE955 0x9581 # 0 +0xE956 0x9582 # 0 +0xE957 0x9583 # 0 +0xE958 0x9584 # 0 +0xE959 0x9585 # 0 +0xE95A 0x9586 # 0 +0xE95B 0x9587 # 0 +0xE95C 0x9588 # 0 +0xE95D 0x9589 # 0 +0xE95E 0x958A # 0 +0xE95F 0x958B # 0 +0xE960 0x958C # 0 +0xE961 0x958D # 0 +0xE962 0x958E # 0 +0xE963 0x958F # 0 +0xE964 0x9590 # 0 +0xE965 0x9591 # 0 +0xE966 0x9592 # 0 +0xE967 0x9593 # 0 +0xE968 0x9594 # 0 +0xE969 0x9595 # 0 +0xE96A 0x9596 # 0 +0xE96B 0x9597 # 0 +0xE96C 0x9598 # 0 +0xE96D 0x9599 # 0 +0xE96E 0x959A # 0 +0xE96F 0x959B # 0 +0xE970 0x959C # 0 +0xE971 0x959D # 0 +0xE972 0x959E # 0 +0xE973 0x959F # 0 +0xE974 0x95A0 # 0 +0xE975 0x95A1 # 0 +0xE976 0x95A2 # 0 +0xE977 0x95A3 # 0 +0xE978 0x95A4 # 0 +0xE979 0x95A5 # 0 +0xE97A 0x95A6 # 0 +0xE97B 0x95A7 # 0 +0xE97C 0x95A8 # 0 +0xE97D 0x95A9 # 0 +0xE97E 0x95AA # 0 +0xE980 0x95AB # 0 +0xE981 0x95AC # 0 +0xE982 0x95AD # 0 +0xE983 0x95AE # 0 +0xE984 0x95AF # 0 +0xE985 0x95B0 # 0 +0xE986 0x95B1 # 0 +0xE987 0x95B2 # 0 +0xE988 0x95B3 # 0 +0xE989 0x95B4 # 0 +0xE98A 0x95B5 # 0 +0xE98B 0x95B6 # 0 +0xE98C 0x95B7 # 0 +0xE98D 0x95B8 # 0 +0xE98E 0x95B9 # 0 +0xE98F 0x95BA # 0 +0xE990 0x95BB # 0 +0xE991 0x95BC # 0 +0xE992 0x95BD # 0 +0xE993 0x95BE # 0 +0xE994 0x95BF # 0 +0xE995 0x95C0 # 0 +0xE996 0x95C1 # 0 +0xE997 0x95C2 # 0 +0xE998 0x95C3 # 0 +0xE999 0x95C4 # 0 +0xE99A 0x95C5 # 0 +0xE99B 0x95C6 # 0 +0xE99C 0x95C7 # 0 +0xE99D 0x95C8 # 0 +0xE99E 0x95C9 # 0 +0xE99F 0x95CA # 0 +0xE9A0 0x95CB # 0 +0xE9A1 0x6924 # 0 +0xE9A2 0x68F0 # 0 +0xE9A3 0x690B # 0 +0xE9A4 0x6901 # 0 +0xE9A5 0x6957 # 0 +0xE9A6 0x68E3 # 0 +0xE9A7 0x6910 # 0 +0xE9A8 0x6971 # 0 +0xE9A9 0x6939 # 0 +0xE9AA 0x6960 # 0 +0xE9AB 0x6942 # 0 +0xE9AC 0x695D # 0 +0xE9AD 0x6984 # 0 +0xE9AE 0x696B # 0 +0xE9AF 0x6980 # 0 +0xE9B0 0x6998 # 0 +0xE9B1 0x6978 # 0 +0xE9B2 0x6934 # 0 +0xE9B3 0x69CC # 0 +0xE9B4 0x6987 # 0 +0xE9B5 0x6988 # 0 +0xE9B6 0x69CE # 0 +0xE9B7 0x6989 # 0 +0xE9B8 0x6966 # 0 +0xE9B9 0x6963 # 0 +0xE9BA 0x6979 # 0 +0xE9BB 0x699B # 0 +0xE9BC 0x69A7 # 0 +0xE9BD 0x69BB # 0 +0xE9BE 0x69AB # 0 +0xE9BF 0x69AD # 0 +0xE9C0 0x69D4 # 0 +0xE9C1 0x69B1 # 0 +0xE9C2 0x69C1 # 0 +0xE9C3 0x69CA # 0 +0xE9C4 0x69DF # 0 +0xE9C5 0x6995 # 0 +0xE9C6 0x69E0 # 0 +0xE9C7 0x698D # 0 +0xE9C8 0x69FF # 0 +0xE9C9 0x6A2F # 0 +0xE9CA 0x69ED # 0 +0xE9CB 0x6A17 # 0 +0xE9CC 0x6A18 # 0 +0xE9CD 0x6A65 # 0 +0xE9CE 0x69F2 # 0 +0xE9CF 0x6A44 # 0 +0xE9D0 0x6A3E # 0 +0xE9D1 0x6AA0 # 0 +0xE9D2 0x6A50 # 0 +0xE9D3 0x6A5B # 0 +0xE9D4 0x6A35 # 0 +0xE9D5 0x6A8E # 0 +0xE9D6 0x6A79 # 0 +0xE9D7 0x6A3D # 0 +0xE9D8 0x6A28 # 0 +0xE9D9 0x6A58 # 0 +0xE9DA 0x6A7C # 0 +0xE9DB 0x6A91 # 0 +0xE9DC 0x6A90 # 0 +0xE9DD 0x6AA9 # 0 +0xE9DE 0x6A97 # 0 +0xE9DF 0x6AAB # 0 +0xE9E0 0x7337 # 0 +0xE9E1 0x7352 # 0 +0xE9E2 0x6B81 # 0 +0xE9E3 0x6B82 # 0 +0xE9E4 0x6B87 # 0 +0xE9E5 0x6B84 # 0 +0xE9E6 0x6B92 # 0 +0xE9E7 0x6B93 # 0 +0xE9E8 0x6B8D # 0 +0xE9E9 0x6B9A # 0 +0xE9EA 0x6B9B # 0 +0xE9EB 0x6BA1 # 0 +0xE9EC 0x6BAA # 0 +0xE9ED 0x8F6B # 0 +0xE9EE 0x8F6D # 0 +0xE9EF 0x8F71 # 0 +0xE9F0 0x8F72 # 0 +0xE9F1 0x8F73 # 0 +0xE9F2 0x8F75 # 0 +0xE9F3 0x8F76 # 0 +0xE9F4 0x8F78 # 0 +0xE9F5 0x8F77 # 0 +0xE9F6 0x8F79 # 0 +0xE9F7 0x8F7A # 0 +0xE9F8 0x8F7C # 0 +0xE9F9 0x8F7E # 0 +0xE9FA 0x8F81 # 0 +0xE9FB 0x8F82 # 0 +0xE9FC 0x8F84 # 0 +0xE9FD 0x8F87 # 0 +0xE9FE 0x8F8B # 0 +0xEA40 0x95CC # 0 +0xEA41 0x95CD # 0 +0xEA42 0x95CE # 0 +0xEA43 0x95CF # 0 +0xEA44 0x95D0 # 0 +0xEA45 0x95D1 # 0 +0xEA46 0x95D2 # 0 +0xEA47 0x95D3 # 0 +0xEA48 0x95D4 # 0 +0xEA49 0x95D5 # 0 +0xEA4A 0x95D6 # 0 +0xEA4B 0x95D7 # 0 +0xEA4C 0x95D8 # 0 +0xEA4D 0x95D9 # 0 +0xEA4E 0x95DA # 0 +0xEA4F 0x95DB # 0 +0xEA50 0x95DC # 0 +0xEA51 0x95DD # 0 +0xEA52 0x95DE # 0 +0xEA53 0x95DF # 0 +0xEA54 0x95E0 # 0 +0xEA55 0x95E1 # 0 +0xEA56 0x95E2 # 0 +0xEA57 0x95E3 # 0 +0xEA58 0x95E4 # 0 +0xEA59 0x95E5 # 0 +0xEA5A 0x95E6 # 0 +0xEA5B 0x95E7 # 0 +0xEA5C 0x95EC # 0 +0xEA5D 0x95FF # 0 +0xEA5E 0x9607 # 0 +0xEA5F 0x9613 # 0 +0xEA60 0x9618 # 0 +0xEA61 0x961B # 0 +0xEA62 0x961E # 0 +0xEA63 0x9620 # 0 +0xEA64 0x9623 # 0 +0xEA65 0x9624 # 0 +0xEA66 0x9625 # 0 +0xEA67 0x9626 # 0 +0xEA68 0x9627 # 0 +0xEA69 0x9628 # 0 +0xEA6A 0x9629 # 0 +0xEA6B 0x962B # 0 +0xEA6C 0x962C # 0 +0xEA6D 0x962D # 0 +0xEA6E 0x962F # 0 +0xEA6F 0x9630 # 0 +0xEA70 0x9637 # 0 +0xEA71 0x9638 # 0 +0xEA72 0x9639 # 0 +0xEA73 0x963A # 0 +0xEA74 0x963E # 0 +0xEA75 0x9641 # 0 +0xEA76 0x9643 # 0 +0xEA77 0x964A # 0 +0xEA78 0x964E # 0 +0xEA79 0x964F # 0 +0xEA7A 0x9651 # 0 +0xEA7B 0x9652 # 0 +0xEA7C 0x9653 # 0 +0xEA7D 0x9656 # 0 +0xEA7E 0x9657 # 0 +0xEA80 0x9658 # 0 +0xEA81 0x9659 # 0 +0xEA82 0x965A # 0 +0xEA83 0x965C # 0 +0xEA84 0x965D # 0 +0xEA85 0x965E # 0 +0xEA86 0x9660 # 0 +0xEA87 0x9663 # 0 +0xEA88 0x9665 # 0 +0xEA89 0x9666 # 0 +0xEA8A 0x966B # 0 +0xEA8B 0x966D # 0 +0xEA8C 0x966E # 0 +0xEA8D 0x966F # 0 +0xEA8E 0x9670 # 0 +0xEA8F 0x9671 # 0 +0xEA90 0x9673 # 0 +0xEA91 0x9678 # 0 +0xEA92 0x9679 # 0 +0xEA93 0x967A # 0 +0xEA94 0x967B # 0 +0xEA95 0x967C # 0 +0xEA96 0x967D # 0 +0xEA97 0x967E # 0 +0xEA98 0x967F # 0 +0xEA99 0x9680 # 0 +0xEA9A 0x9681 # 0 +0xEA9B 0x9682 # 0 +0xEA9C 0x9683 # 0 +0xEA9D 0x9684 # 0 +0xEA9E 0x9687 # 0 +0xEA9F 0x9689 # 0 +0xEAA0 0x968A # 0 +0xEAA1 0x8F8D # 0 +0xEAA2 0x8F8E # 0 +0xEAA3 0x8F8F # 0 +0xEAA4 0x8F98 # 0 +0xEAA5 0x8F9A # 0 +0xEAA6 0x8ECE # 0 +0xEAA7 0x620B # 0 +0xEAA8 0x6217 # 0 +0xEAA9 0x621B # 0 +0xEAAA 0x621F # 0 +0xEAAB 0x6222 # 0 +0xEAAC 0x6221 # 0 +0xEAAD 0x6225 # 0 +0xEAAE 0x6224 # 0 +0xEAAF 0x622C # 0 +0xEAB0 0x81E7 # 0 +0xEAB1 0x74EF # 0 +0xEAB2 0x74F4 # 0 +0xEAB3 0x74FF # 0 +0xEAB4 0x750F # 0 +0xEAB5 0x7511 # 0 +0xEAB6 0x7513 # 0 +0xEAB7 0x6534 # 0 +0xEAB8 0x65EE # 0 +0xEAB9 0x65EF # 0 +0xEABA 0x65F0 # 0 +0xEABB 0x660A # 0 +0xEABC 0x6619 # 0 +0xEABD 0x6772 # 0 +0xEABE 0x6603 # 0 +0xEABF 0x6615 # 0 +0xEAC0 0x6600 # 0 +0xEAC1 0x7085 # 0 +0xEAC2 0x66F7 # 0 +0xEAC3 0x661D # 0 +0xEAC4 0x6634 # 0 +0xEAC5 0x6631 # 0 +0xEAC6 0x6636 # 0 +0xEAC7 0x6635 # 0 +0xEAC8 0x8006 # 0 +0xEAC9 0x665F # 0 +0xEACA 0x6654 # 0 +0xEACB 0x6641 # 0 +0xEACC 0x664F # 0 +0xEACD 0x6656 # 0 +0xEACE 0x6661 # 0 +0xEACF 0x6657 # 0 +0xEAD0 0x6677 # 0 +0xEAD1 0x6684 # 0 +0xEAD2 0x668C # 0 +0xEAD3 0x66A7 # 0 +0xEAD4 0x669D # 0 +0xEAD5 0x66BE # 0 +0xEAD6 0x66DB # 0 +0xEAD7 0x66DC # 0 +0xEAD8 0x66E6 # 0 +0xEAD9 0x66E9 # 0 +0xEADA 0x8D32 # 0 +0xEADB 0x8D33 # 0 +0xEADC 0x8D36 # 0 +0xEADD 0x8D3B # 0 +0xEADE 0x8D3D # 0 +0xEADF 0x8D40 # 0 +0xEAE0 0x8D45 # 0 +0xEAE1 0x8D46 # 0 +0xEAE2 0x8D48 # 0 +0xEAE3 0x8D49 # 0 +0xEAE4 0x8D47 # 0 +0xEAE5 0x8D4D # 0 +0xEAE6 0x8D55 # 0 +0xEAE7 0x8D59 # 0 +0xEAE8 0x89C7 # 0 +0xEAE9 0x89CA # 0 +0xEAEA 0x89CB # 0 +0xEAEB 0x89CC # 0 +0xEAEC 0x89CE # 0 +0xEAED 0x89CF # 0 +0xEAEE 0x89D0 # 0 +0xEAEF 0x89D1 # 0 +0xEAF0 0x726E # 0 +0xEAF1 0x729F # 0 +0xEAF2 0x725D # 0 +0xEAF3 0x7266 # 0 +0xEAF4 0x726F # 0 +0xEAF5 0x727E # 0 +0xEAF6 0x727F # 0 +0xEAF7 0x7284 # 0 +0xEAF8 0x728B # 0 +0xEAF9 0x728D # 0 +0xEAFA 0x728F # 0 +0xEAFB 0x7292 # 0 +0xEAFC 0x6308 # 0 +0xEAFD 0x6332 # 0 +0xEAFE 0x63B0 # 0 +0xEB40 0x968C # 0 +0xEB41 0x968E # 0 +0xEB42 0x9691 # 0 +0xEB43 0x9692 # 0 +0xEB44 0x9693 # 0 +0xEB45 0x9695 # 0 +0xEB46 0x9696 # 0 +0xEB47 0x969A # 0 +0xEB48 0x969B # 0 +0xEB49 0x969D # 0 +0xEB4A 0x969E # 0 +0xEB4B 0x969F # 0 +0xEB4C 0x96A0 # 0 +0xEB4D 0x96A1 # 0 +0xEB4E 0x96A2 # 0 +0xEB4F 0x96A3 # 0 +0xEB50 0x96A4 # 0 +0xEB51 0x96A5 # 0 +0xEB52 0x96A6 # 0 +0xEB53 0x96A8 # 0 +0xEB54 0x96A9 # 0 +0xEB55 0x96AA # 0 +0xEB56 0x96AB # 0 +0xEB57 0x96AC # 0 +0xEB58 0x96AD # 0 +0xEB59 0x96AE # 0 +0xEB5A 0x96AF # 0 +0xEB5B 0x96B1 # 0 +0xEB5C 0x96B2 # 0 +0xEB5D 0x96B4 # 0 +0xEB5E 0x96B5 # 0 +0xEB5F 0x96B7 # 0 +0xEB60 0x96B8 # 0 +0xEB61 0x96BA # 0 +0xEB62 0x96BB # 0 +0xEB63 0x96BF # 0 +0xEB64 0x96C2 # 0 +0xEB65 0x96C3 # 0 +0xEB66 0x96C8 # 0 +0xEB67 0x96CA # 0 +0xEB68 0x96CB # 0 +0xEB69 0x96D0 # 0 +0xEB6A 0x96D1 # 0 +0xEB6B 0x96D3 # 0 +0xEB6C 0x96D4 # 0 +0xEB6D 0x96D6 # 0 +0xEB6E 0x96D7 # 0 +0xEB6F 0x96D8 # 0 +0xEB70 0x96D9 # 0 +0xEB71 0x96DA # 0 +0xEB72 0x96DB # 0 +0xEB73 0x96DC # 0 +0xEB74 0x96DD # 0 +0xEB75 0x96DE # 0 +0xEB76 0x96DF # 0 +0xEB77 0x96E1 # 0 +0xEB78 0x96E2 # 0 +0xEB79 0x96E3 # 0 +0xEB7A 0x96E4 # 0 +0xEB7B 0x96E5 # 0 +0xEB7C 0x96E6 # 0 +0xEB7D 0x96E7 # 0 +0xEB7E 0x96EB # 0 +0xEB80 0x96EC # 0 +0xEB81 0x96ED # 0 +0xEB82 0x96EE # 0 +0xEB83 0x96F0 # 0 +0xEB84 0x96F1 # 0 +0xEB85 0x96F2 # 0 +0xEB86 0x96F4 # 0 +0xEB87 0x96F5 # 0 +0xEB88 0x96F8 # 0 +0xEB89 0x96FA # 0 +0xEB8A 0x96FB # 0 +0xEB8B 0x96FC # 0 +0xEB8C 0x96FD # 0 +0xEB8D 0x96FF # 0 +0xEB8E 0x9702 # 0 +0xEB8F 0x9703 # 0 +0xEB90 0x9705 # 0 +0xEB91 0x970A # 0 +0xEB92 0x970B # 0 +0xEB93 0x970C # 0 +0xEB94 0x9710 # 0 +0xEB95 0x9711 # 0 +0xEB96 0x9712 # 0 +0xEB97 0x9714 # 0 +0xEB98 0x9715 # 0 +0xEB99 0x9717 # 0 +0xEB9A 0x9718 # 0 +0xEB9B 0x9719 # 0 +0xEB9C 0x971A # 0 +0xEB9D 0x971B # 0 +0xEB9E 0x971D # 0 +0xEB9F 0x971F # 0 +0xEBA0 0x9720 # 0 +0xEBA1 0x643F # 0 +0xEBA2 0x64D8 # 0 +0xEBA3 0x8004 # 0 +0xEBA4 0x6BEA # 0 +0xEBA5 0x6BF3 # 0 +0xEBA6 0x6BFD # 0 +0xEBA7 0x6BF5 # 0 +0xEBA8 0x6BF9 # 0 +0xEBA9 0x6C05 # 0 +0xEBAA 0x6C07 # 0 +0xEBAB 0x6C06 # 0 +0xEBAC 0x6C0D # 0 +0xEBAD 0x6C15 # 0 +0xEBAE 0x6C18 # 0 +0xEBAF 0x6C19 # 0 +0xEBB0 0x6C1A # 0 +0xEBB1 0x6C21 # 0 +0xEBB2 0x6C29 # 0 +0xEBB3 0x6C24 # 0 +0xEBB4 0x6C2A # 0 +0xEBB5 0x6C32 # 0 +0xEBB6 0x6535 # 0 +0xEBB7 0x6555 # 0 +0xEBB8 0x656B # 0 +0xEBB9 0x724D # 0 +0xEBBA 0x7252 # 0 +0xEBBB 0x7256 # 0 +0xEBBC 0x7230 # 0 +0xEBBD 0x8662 # 0 +0xEBBE 0x5216 # 0 +0xEBBF 0x809F # 0 +0xEBC0 0x809C # 0 +0xEBC1 0x8093 # 0 +0xEBC2 0x80BC # 0 +0xEBC3 0x670A # 0 +0xEBC4 0x80BD # 0 +0xEBC5 0x80B1 # 0 +0xEBC6 0x80AB # 0 +0xEBC7 0x80AD # 0 +0xEBC8 0x80B4 # 0 +0xEBC9 0x80B7 # 0 +0xEBCA 0x80E7 # 0 +0xEBCB 0x80E8 # 0 +0xEBCC 0x80E9 # 0 +0xEBCD 0x80EA # 0 +0xEBCE 0x80DB # 0 +0xEBCF 0x80C2 # 0 +0xEBD0 0x80C4 # 0 +0xEBD1 0x80D9 # 0 +0xEBD2 0x80CD # 0 +0xEBD3 0x80D7 # 0 +0xEBD4 0x6710 # 0 +0xEBD5 0x80DD # 0 +0xEBD6 0x80EB # 0 +0xEBD7 0x80F1 # 0 +0xEBD8 0x80F4 # 0 +0xEBD9 0x80ED # 0 +0xEBDA 0x810D # 0 +0xEBDB 0x810E # 0 +0xEBDC 0x80F2 # 0 +0xEBDD 0x80FC # 0 +0xEBDE 0x6715 # 0 +0xEBDF 0x8112 # 0 +0xEBE0 0x8C5A # 0 +0xEBE1 0x8136 # 0 +0xEBE2 0x811E # 0 +0xEBE3 0x812C # 0 +0xEBE4 0x8118 # 0 +0xEBE5 0x8132 # 0 +0xEBE6 0x8148 # 0 +0xEBE7 0x814C # 0 +0xEBE8 0x8153 # 0 +0xEBE9 0x8174 # 0 +0xEBEA 0x8159 # 0 +0xEBEB 0x815A # 0 +0xEBEC 0x8171 # 0 +0xEBED 0x8160 # 0 +0xEBEE 0x8169 # 0 +0xEBEF 0x817C # 0 +0xEBF0 0x817D # 0 +0xEBF1 0x816D # 0 +0xEBF2 0x8167 # 0 +0xEBF3 0x584D # 0 +0xEBF4 0x5AB5 # 0 +0xEBF5 0x8188 # 0 +0xEBF6 0x8182 # 0 +0xEBF7 0x8191 # 0 +0xEBF8 0x6ED5 # 0 +0xEBF9 0x81A3 # 0 +0xEBFA 0x81AA # 0 +0xEBFB 0x81CC # 0 +0xEBFC 0x6726 # 0 +0xEBFD 0x81CA # 0 +0xEBFE 0x81BB # 0 +0xEC40 0x9721 # 0 +0xEC41 0x9722 # 0 +0xEC42 0x9723 # 0 +0xEC43 0x9724 # 0 +0xEC44 0x9725 # 0 +0xEC45 0x9726 # 0 +0xEC46 0x9727 # 0 +0xEC47 0x9728 # 0 +0xEC48 0x9729 # 0 +0xEC49 0x972B # 0 +0xEC4A 0x972C # 0 +0xEC4B 0x972E # 0 +0xEC4C 0x972F # 0 +0xEC4D 0x9731 # 0 +0xEC4E 0x9733 # 0 +0xEC4F 0x9734 # 0 +0xEC50 0x9735 # 0 +0xEC51 0x9736 # 0 +0xEC52 0x9737 # 0 +0xEC53 0x973A # 0 +0xEC54 0x973B # 0 +0xEC55 0x973C # 0 +0xEC56 0x973D # 0 +0xEC57 0x973F # 0 +0xEC58 0x9740 # 0 +0xEC59 0x9741 # 0 +0xEC5A 0x9742 # 0 +0xEC5B 0x9743 # 0 +0xEC5C 0x9744 # 0 +0xEC5D 0x9745 # 0 +0xEC5E 0x9746 # 0 +0xEC5F 0x9747 # 0 +0xEC60 0x9748 # 0 +0xEC61 0x9749 # 0 +0xEC62 0x974A # 0 +0xEC63 0x974B # 0 +0xEC64 0x974C # 0 +0xEC65 0x974D # 0 +0xEC66 0x974E # 0 +0xEC67 0x974F # 0 +0xEC68 0x9750 # 0 +0xEC69 0x9751 # 0 +0xEC6A 0x9754 # 0 +0xEC6B 0x9755 # 0 +0xEC6C 0x9757 # 0 +0xEC6D 0x9758 # 0 +0xEC6E 0x975A # 0 +0xEC6F 0x975C # 0 +0xEC70 0x975D # 0 +0xEC71 0x975F # 0 +0xEC72 0x9763 # 0 +0xEC73 0x9764 # 0 +0xEC74 0x9766 # 0 +0xEC75 0x9767 # 0 +0xEC76 0x9768 # 0 +0xEC77 0x976A # 0 +0xEC78 0x976B # 0 +0xEC79 0x976C # 0 +0xEC7A 0x976D # 0 +0xEC7B 0x976E # 0 +0xEC7C 0x976F # 0 +0xEC7D 0x9770 # 0 +0xEC7E 0x9771 # 0 +0xEC80 0x9772 # 0 +0xEC81 0x9775 # 0 +0xEC82 0x9777 # 0 +0xEC83 0x9778 # 0 +0xEC84 0x9779 # 0 +0xEC85 0x977A # 0 +0xEC86 0x977B # 0 +0xEC87 0x977D # 0 +0xEC88 0x977E # 0 +0xEC89 0x977F # 0 +0xEC8A 0x9780 # 0 +0xEC8B 0x9781 # 0 +0xEC8C 0x9782 # 0 +0xEC8D 0x9783 # 0 +0xEC8E 0x9784 # 0 +0xEC8F 0x9786 # 0 +0xEC90 0x9787 # 0 +0xEC91 0x9788 # 0 +0xEC92 0x9789 # 0 +0xEC93 0x978A # 0 +0xEC94 0x978C # 0 +0xEC95 0x978E # 0 +0xEC96 0x978F # 0 +0xEC97 0x9790 # 0 +0xEC98 0x9793 # 0 +0xEC99 0x9795 # 0 +0xEC9A 0x9796 # 0 +0xEC9B 0x9797 # 0 +0xEC9C 0x9799 # 0 +0xEC9D 0x979A # 0 +0xEC9E 0x979B # 0 +0xEC9F 0x979C # 0 +0xECA0 0x979D # 0 +0xECA1 0x81C1 # 0 +0xECA2 0x81A6 # 0 +0xECA3 0x6B24 # 0 +0xECA4 0x6B37 # 0 +0xECA5 0x6B39 # 0 +0xECA6 0x6B43 # 0 +0xECA7 0x6B46 # 0 +0xECA8 0x6B59 # 0 +0xECA9 0x98D1 # 0 +0xECAA 0x98D2 # 0 +0xECAB 0x98D3 # 0 +0xECAC 0x98D5 # 0 +0xECAD 0x98D9 # 0 +0xECAE 0x98DA # 0 +0xECAF 0x6BB3 # 0 +0xECB0 0x5F40 # 0 +0xECB1 0x6BC2 # 0 +0xECB2 0x89F3 # 0 +0xECB3 0x6590 # 0 +0xECB4 0x9F51 # 0 +0xECB5 0x6593 # 0 +0xECB6 0x65BC # 0 +0xECB7 0x65C6 # 0 +0xECB8 0x65C4 # 0 +0xECB9 0x65C3 # 0 +0xECBA 0x65CC # 0 +0xECBB 0x65CE # 0 +0xECBC 0x65D2 # 0 +0xECBD 0x65D6 # 0 +0xECBE 0x7080 # 0 +0xECBF 0x709C # 0 +0xECC0 0x7096 # 0 +0xECC1 0x709D # 0 +0xECC2 0x70BB # 0 +0xECC3 0x70C0 # 0 +0xECC4 0x70B7 # 0 +0xECC5 0x70AB # 0 +0xECC6 0x70B1 # 0 +0xECC7 0x70E8 # 0 +0xECC8 0x70CA # 0 +0xECC9 0x7110 # 0 +0xECCA 0x7113 # 0 +0xECCB 0x7116 # 0 +0xECCC 0x712F # 0 +0xECCD 0x7131 # 0 +0xECCE 0x7173 # 0 +0xECCF 0x715C # 0 +0xECD0 0x7168 # 0 +0xECD1 0x7145 # 0 +0xECD2 0x7172 # 0 +0xECD3 0x714A # 0 +0xECD4 0x7178 # 0 +0xECD5 0x717A # 0 +0xECD6 0x7198 # 0 +0xECD7 0x71B3 # 0 +0xECD8 0x71B5 # 0 +0xECD9 0x71A8 # 0 +0xECDA 0x71A0 # 0 +0xECDB 0x71E0 # 0 +0xECDC 0x71D4 # 0 +0xECDD 0x71E7 # 0 +0xECDE 0x71F9 # 0 +0xECDF 0x721D # 0 +0xECE0 0x7228 # 0 +0xECE1 0x706C # 0 +0xECE2 0x7118 # 0 +0xECE3 0x7166 # 0 +0xECE4 0x71B9 # 0 +0xECE5 0x623E # 0 +0xECE6 0x623D # 0 +0xECE7 0x6243 # 0 +0xECE8 0x6248 # 0 +0xECE9 0x6249 # 0 +0xECEA 0x793B # 0 +0xECEB 0x7940 # 0 +0xECEC 0x7946 # 0 +0xECED 0x7949 # 0 +0xECEE 0x795B # 0 +0xECEF 0x795C # 0 +0xECF0 0x7953 # 0 +0xECF1 0x795A # 0 +0xECF2 0x7962 # 0 +0xECF3 0x7957 # 0 +0xECF4 0x7960 # 0 +0xECF5 0x796F # 0 +0xECF6 0x7967 # 0 +0xECF7 0x797A # 0 +0xECF8 0x7985 # 0 +0xECF9 0x798A # 0 +0xECFA 0x799A # 0 +0xECFB 0x79A7 # 0 +0xECFC 0x79B3 # 0 +0xECFD 0x5FD1 # 0 +0xECFE 0x5FD0 # 0 +0xED40 0x979E # 0 +0xED41 0x979F # 0 +0xED42 0x97A1 # 0 +0xED43 0x97A2 # 0 +0xED44 0x97A4 # 0 +0xED45 0x97A5 # 0 +0xED46 0x97A6 # 0 +0xED47 0x97A7 # 0 +0xED48 0x97A8 # 0 +0xED49 0x97A9 # 0 +0xED4A 0x97AA # 0 +0xED4B 0x97AC # 0 +0xED4C 0x97AE # 0 +0xED4D 0x97B0 # 0 +0xED4E 0x97B1 # 0 +0xED4F 0x97B3 # 0 +0xED50 0x97B5 # 0 +0xED51 0x97B6 # 0 +0xED52 0x97B7 # 0 +0xED53 0x97B8 # 0 +0xED54 0x97B9 # 0 +0xED55 0x97BA # 0 +0xED56 0x97BB # 0 +0xED57 0x97BC # 0 +0xED58 0x97BD # 0 +0xED59 0x97BE # 0 +0xED5A 0x97BF # 0 +0xED5B 0x97C0 # 0 +0xED5C 0x97C1 # 0 +0xED5D 0x97C2 # 0 +0xED5E 0x97C3 # 0 +0xED5F 0x97C4 # 0 +0xED60 0x97C5 # 0 +0xED61 0x97C6 # 0 +0xED62 0x97C7 # 0 +0xED63 0x97C8 # 0 +0xED64 0x97C9 # 0 +0xED65 0x97CA # 0 +0xED66 0x97CB # 0 +0xED67 0x97CC # 0 +0xED68 0x97CD # 0 +0xED69 0x97CE # 0 +0xED6A 0x97CF # 0 +0xED6B 0x97D0 # 0 +0xED6C 0x97D1 # 0 +0xED6D 0x97D2 # 0 +0xED6E 0x97D3 # 0 +0xED6F 0x97D4 # 0 +0xED70 0x97D5 # 0 +0xED71 0x97D6 # 0 +0xED72 0x97D7 # 0 +0xED73 0x97D8 # 0 +0xED74 0x97D9 # 0 +0xED75 0x97DA # 0 +0xED76 0x97DB # 0 +0xED77 0x97DC # 0 +0xED78 0x97DD # 0 +0xED79 0x97DE # 0 +0xED7A 0x97DF # 0 +0xED7B 0x97E0 # 0 +0xED7C 0x97E1 # 0 +0xED7D 0x97E2 # 0 +0xED7E 0x97E3 # 0 +0xED80 0x97E4 # 0 +0xED81 0x97E5 # 0 +0xED82 0x97E8 # 0 +0xED83 0x97EE # 0 +0xED84 0x97EF # 0 +0xED85 0x97F0 # 0 +0xED86 0x97F1 # 0 +0xED87 0x97F2 # 0 +0xED88 0x97F4 # 0 +0xED89 0x97F7 # 0 +0xED8A 0x97F8 # 0 +0xED8B 0x97F9 # 0 +0xED8C 0x97FA # 0 +0xED8D 0x97FB # 0 +0xED8E 0x97FC # 0 +0xED8F 0x97FD # 0 +0xED90 0x97FE # 0 +0xED91 0x97FF # 0 +0xED92 0x9800 # 0 +0xED93 0x9801 # 0 +0xED94 0x9802 # 0 +0xED95 0x9803 # 0 +0xED96 0x9804 # 0 +0xED97 0x9805 # 0 +0xED98 0x9806 # 0 +0xED99 0x9807 # 0 +0xED9A 0x9808 # 0 +0xED9B 0x9809 # 0 +0xED9C 0x980A # 0 +0xED9D 0x980B # 0 +0xED9E 0x980C # 0 +0xED9F 0x980D # 0 +0xEDA0 0x980E # 0 +0xEDA1 0x603C # 0 +0xEDA2 0x605D # 0 +0xEDA3 0x605A # 0 +0xEDA4 0x6067 # 0 +0xEDA5 0x6041 # 0 +0xEDA6 0x6059 # 0 +0xEDA7 0x6063 # 0 +0xEDA8 0x60AB # 0 +0xEDA9 0x6106 # 0 +0xEDAA 0x610D # 0 +0xEDAB 0x615D # 0 +0xEDAC 0x61A9 # 0 +0xEDAD 0x619D # 0 +0xEDAE 0x61CB # 0 +0xEDAF 0x61D1 # 0 +0xEDB0 0x6206 # 0 +0xEDB1 0x8080 # 0 +0xEDB2 0x807F # 0 +0xEDB3 0x6C93 # 0 +0xEDB4 0x6CF6 # 0 +0xEDB5 0x6DFC # 0 +0xEDB6 0x77F6 # 0 +0xEDB7 0x77F8 # 0 +0xEDB8 0x7800 # 0 +0xEDB9 0x7809 # 0 +0xEDBA 0x7817 # 0 +0xEDBB 0x7818 # 0 +0xEDBC 0x7811 # 0 +0xEDBD 0x65AB # 0 +0xEDBE 0x782D # 0 +0xEDBF 0x781C # 0 +0xEDC0 0x781D # 0 +0xEDC1 0x7839 # 0 +0xEDC2 0x783A # 0 +0xEDC3 0x783B # 0 +0xEDC4 0x781F # 0 +0xEDC5 0x783C # 0 +0xEDC6 0x7825 # 0 +0xEDC7 0x782C # 0 +0xEDC8 0x7823 # 0 +0xEDC9 0x7829 # 0 +0xEDCA 0x784E # 0 +0xEDCB 0x786D # 0 +0xEDCC 0x7856 # 0 +0xEDCD 0x7857 # 0 +0xEDCE 0x7826 # 0 +0xEDCF 0x7850 # 0 +0xEDD0 0x7847 # 0 +0xEDD1 0x784C # 0 +0xEDD2 0x786A # 0 +0xEDD3 0x789B # 0 +0xEDD4 0x7893 # 0 +0xEDD5 0x789A # 0 +0xEDD6 0x7887 # 0 +0xEDD7 0x789C # 0 +0xEDD8 0x78A1 # 0 +0xEDD9 0x78A3 # 0 +0xEDDA 0x78B2 # 0 +0xEDDB 0x78B9 # 0 +0xEDDC 0x78A5 # 0 +0xEDDD 0x78D4 # 0 +0xEDDE 0x78D9 # 0 +0xEDDF 0x78C9 # 0 +0xEDE0 0x78EC # 0 +0xEDE1 0x78F2 # 0 +0xEDE2 0x7905 # 0 +0xEDE3 0x78F4 # 0 +0xEDE4 0x7913 # 0 +0xEDE5 0x7924 # 0 +0xEDE6 0x791E # 0 +0xEDE7 0x7934 # 0 +0xEDE8 0x9F9B # 0 +0xEDE9 0x9EF9 # 0 +0xEDEA 0x9EFB # 0 +0xEDEB 0x9EFC # 0 +0xEDEC 0x76F1 # 0 +0xEDED 0x7704 # 0 +0xEDEE 0x770D # 0 +0xEDEF 0x76F9 # 0 +0xEDF0 0x7707 # 0 +0xEDF1 0x7708 # 0 +0xEDF2 0x771A # 0 +0xEDF3 0x7722 # 0 +0xEDF4 0x7719 # 0 +0xEDF5 0x772D # 0 +0xEDF6 0x7726 # 0 +0xEDF7 0x7735 # 0 +0xEDF8 0x7738 # 0 +0xEDF9 0x7750 # 0 +0xEDFA 0x7751 # 0 +0xEDFB 0x7747 # 0 +0xEDFC 0x7743 # 0 +0xEDFD 0x775A # 0 +0xEDFE 0x7768 # 0 +0xEE40 0x980F # 0 +0xEE41 0x9810 # 0 +0xEE42 0x9811 # 0 +0xEE43 0x9812 # 0 +0xEE44 0x9813 # 0 +0xEE45 0x9814 # 0 +0xEE46 0x9815 # 0 +0xEE47 0x9816 # 0 +0xEE48 0x9817 # 0 +0xEE49 0x9818 # 0 +0xEE4A 0x9819 # 0 +0xEE4B 0x981A # 0 +0xEE4C 0x981B # 0 +0xEE4D 0x981C # 0 +0xEE4E 0x981D # 0 +0xEE4F 0x981E # 0 +0xEE50 0x981F # 0 +0xEE51 0x9820 # 0 +0xEE52 0x9821 # 0 +0xEE53 0x9822 # 0 +0xEE54 0x9823 # 0 +0xEE55 0x9824 # 0 +0xEE56 0x9825 # 0 +0xEE57 0x9826 # 0 +0xEE58 0x9827 # 0 +0xEE59 0x9828 # 0 +0xEE5A 0x9829 # 0 +0xEE5B 0x982A # 0 +0xEE5C 0x982B # 0 +0xEE5D 0x982C # 0 +0xEE5E 0x982D # 0 +0xEE5F 0x982E # 0 +0xEE60 0x982F # 0 +0xEE61 0x9830 # 0 +0xEE62 0x9831 # 0 +0xEE63 0x9832 # 0 +0xEE64 0x9833 # 0 +0xEE65 0x9834 # 0 +0xEE66 0x9835 # 0 +0xEE67 0x9836 # 0 +0xEE68 0x9837 # 0 +0xEE69 0x9838 # 0 +0xEE6A 0x9839 # 0 +0xEE6B 0x983A # 0 +0xEE6C 0x983B # 0 +0xEE6D 0x983C # 0 +0xEE6E 0x983D # 0 +0xEE6F 0x983E # 0 +0xEE70 0x983F # 0 +0xEE71 0x9840 # 0 +0xEE72 0x9841 # 0 +0xEE73 0x9842 # 0 +0xEE74 0x9843 # 0 +0xEE75 0x9844 # 0 +0xEE76 0x9845 # 0 +0xEE77 0x9846 # 0 +0xEE78 0x9847 # 0 +0xEE79 0x9848 # 0 +0xEE7A 0x9849 # 0 +0xEE7B 0x984A # 0 +0xEE7C 0x984B # 0 +0xEE7D 0x984C # 0 +0xEE7E 0x984D # 0 +0xEE80 0x984E # 0 +0xEE81 0x984F # 0 +0xEE82 0x9850 # 0 +0xEE83 0x9851 # 0 +0xEE84 0x9852 # 0 +0xEE85 0x9853 # 0 +0xEE86 0x9854 # 0 +0xEE87 0x9855 # 0 +0xEE88 0x9856 # 0 +0xEE89 0x9857 # 0 +0xEE8A 0x9858 # 0 +0xEE8B 0x9859 # 0 +0xEE8C 0x985A # 0 +0xEE8D 0x985B # 0 +0xEE8E 0x985C # 0 +0xEE8F 0x985D # 0 +0xEE90 0x985E # 0 +0xEE91 0x985F # 0 +0xEE92 0x9860 # 0 +0xEE93 0x9861 # 0 +0xEE94 0x9862 # 0 +0xEE95 0x9863 # 0 +0xEE96 0x9864 # 0 +0xEE97 0x9865 # 0 +0xEE98 0x9866 # 0 +0xEE99 0x9867 # 0 +0xEE9A 0x9868 # 0 +0xEE9B 0x9869 # 0 +0xEE9C 0x986A # 0 +0xEE9D 0x986B # 0 +0xEE9E 0x986C # 0 +0xEE9F 0x986D # 0 +0xEEA0 0x986E # 0 +0xEEA1 0x7762 # 0 +0xEEA2 0x7765 # 0 +0xEEA3 0x777F # 0 +0xEEA4 0x778D # 0 +0xEEA5 0x777D # 0 +0xEEA6 0x7780 # 0 +0xEEA7 0x778C # 0 +0xEEA8 0x7791 # 0 +0xEEA9 0x779F # 0 +0xEEAA 0x77A0 # 0 +0xEEAB 0x77B0 # 0 +0xEEAC 0x77B5 # 0 +0xEEAD 0x77BD # 0 +0xEEAE 0x753A # 0 +0xEEAF 0x7540 # 0 +0xEEB0 0x754E # 0 +0xEEB1 0x754B # 0 +0xEEB2 0x7548 # 0 +0xEEB3 0x755B # 0 +0xEEB4 0x7572 # 0 +0xEEB5 0x7579 # 0 +0xEEB6 0x7583 # 0 +0xEEB7 0x7F58 # 0 +0xEEB8 0x7F61 # 0 +0xEEB9 0x7F5F # 0 +0xEEBA 0x8A48 # 0 +0xEEBB 0x7F68 # 0 +0xEEBC 0x7F74 # 0 +0xEEBD 0x7F71 # 0 +0xEEBE 0x7F79 # 0 +0xEEBF 0x7F81 # 0 +0xEEC0 0x7F7E # 0 +0xEEC1 0x76CD # 0 +0xEEC2 0x76E5 # 0 +0xEEC3 0x8832 # 0 +0xEEC4 0x9485 # 0 +0xEEC5 0x9486 # 0 +0xEEC6 0x9487 # 0 +0xEEC7 0x948B # 0 +0xEEC8 0x948A # 0 +0xEEC9 0x948C # 0 +0xEECA 0x948D # 0 +0xEECB 0x948F # 0 +0xEECC 0x9490 # 0 +0xEECD 0x9494 # 0 +0xEECE 0x9497 # 0 +0xEECF 0x9495 # 0 +0xEED0 0x949A # 0 +0xEED1 0x949B # 0 +0xEED2 0x949C # 0 +0xEED3 0x94A3 # 0 +0xEED4 0x94A4 # 0 +0xEED5 0x94AB # 0 +0xEED6 0x94AA # 0 +0xEED7 0x94AD # 0 +0xEED8 0x94AC # 0 +0xEED9 0x94AF # 0 +0xEEDA 0x94B0 # 0 +0xEEDB 0x94B2 # 0 +0xEEDC 0x94B4 # 0 +0xEEDD 0x94B6 # 0 +0xEEDE 0x94B7 # 0 +0xEEDF 0x94B8 # 0 +0xEEE0 0x94B9 # 0 +0xEEE1 0x94BA # 0 +0xEEE2 0x94BC # 0 +0xEEE3 0x94BD # 0 +0xEEE4 0x94BF # 0 +0xEEE5 0x94C4 # 0 +0xEEE6 0x94C8 # 0 +0xEEE7 0x94C9 # 0 +0xEEE8 0x94CA # 0 +0xEEE9 0x94CB # 0 +0xEEEA 0x94CC # 0 +0xEEEB 0x94CD # 0 +0xEEEC 0x94CE # 0 +0xEEED 0x94D0 # 0 +0xEEEE 0x94D1 # 0 +0xEEEF 0x94D2 # 0 +0xEEF0 0x94D5 # 0 +0xEEF1 0x94D6 # 0 +0xEEF2 0x94D7 # 0 +0xEEF3 0x94D9 # 0 +0xEEF4 0x94D8 # 0 +0xEEF5 0x94DB # 0 +0xEEF6 0x94DE # 0 +0xEEF7 0x94DF # 0 +0xEEF8 0x94E0 # 0 +0xEEF9 0x94E2 # 0 +0xEEFA 0x94E4 # 0 +0xEEFB 0x94E5 # 0 +0xEEFC 0x94E7 # 0 +0xEEFD 0x94E8 # 0 +0xEEFE 0x94EA # 0 +0xEF40 0x986F # 0 +0xEF41 0x9870 # 0 +0xEF42 0x9871 # 0 +0xEF43 0x9872 # 0 +0xEF44 0x9873 # 0 +0xEF45 0x9874 # 0 +0xEF46 0x988B # 0 +0xEF47 0x988E # 0 +0xEF48 0x9892 # 0 +0xEF49 0x9895 # 0 +0xEF4A 0x9899 # 0 +0xEF4B 0x98A3 # 0 +0xEF4C 0x98A8 # 0 +0xEF4D 0x98A9 # 0 +0xEF4E 0x98AA # 0 +0xEF4F 0x98AB # 0 +0xEF50 0x98AC # 0 +0xEF51 0x98AD # 0 +0xEF52 0x98AE # 0 +0xEF53 0x98AF # 0 +0xEF54 0x98B0 # 0 +0xEF55 0x98B1 # 0 +0xEF56 0x98B2 # 0 +0xEF57 0x98B3 # 0 +0xEF58 0x98B4 # 0 +0xEF59 0x98B5 # 0 +0xEF5A 0x98B6 # 0 +0xEF5B 0x98B7 # 0 +0xEF5C 0x98B8 # 0 +0xEF5D 0x98B9 # 0 +0xEF5E 0x98BA # 0 +0xEF5F 0x98BB # 0 +0xEF60 0x98BC # 0 +0xEF61 0x98BD # 0 +0xEF62 0x98BE # 0 +0xEF63 0x98BF # 0 +0xEF64 0x98C0 # 0 +0xEF65 0x98C1 # 0 +0xEF66 0x98C2 # 0 +0xEF67 0x98C3 # 0 +0xEF68 0x98C4 # 0 +0xEF69 0x98C5 # 0 +0xEF6A 0x98C6 # 0 +0xEF6B 0x98C7 # 0 +0xEF6C 0x98C8 # 0 +0xEF6D 0x98C9 # 0 +0xEF6E 0x98CA # 0 +0xEF6F 0x98CB # 0 +0xEF70 0x98CC # 0 +0xEF71 0x98CD # 0 +0xEF72 0x98CF # 0 +0xEF73 0x98D0 # 0 +0xEF74 0x98D4 # 0 +0xEF75 0x98D6 # 0 +0xEF76 0x98D7 # 0 +0xEF77 0x98DB # 0 +0xEF78 0x98DC # 0 +0xEF79 0x98DD # 0 +0xEF7A 0x98E0 # 0 +0xEF7B 0x98E1 # 0 +0xEF7C 0x98E2 # 0 +0xEF7D 0x98E3 # 0 +0xEF7E 0x98E4 # 0 +0xEF80 0x98E5 # 0 +0xEF81 0x98E6 # 0 +0xEF82 0x98E9 # 0 +0xEF83 0x98EA # 0 +0xEF84 0x98EB # 0 +0xEF85 0x98EC # 0 +0xEF86 0x98ED # 0 +0xEF87 0x98EE # 0 +0xEF88 0x98EF # 0 +0xEF89 0x98F0 # 0 +0xEF8A 0x98F1 # 0 +0xEF8B 0x98F2 # 0 +0xEF8C 0x98F3 # 0 +0xEF8D 0x98F4 # 0 +0xEF8E 0x98F5 # 0 +0xEF8F 0x98F6 # 0 +0xEF90 0x98F7 # 0 +0xEF91 0x98F8 # 0 +0xEF92 0x98F9 # 0 +0xEF93 0x98FA # 0 +0xEF94 0x98FB # 0 +0xEF95 0x98FC # 0 +0xEF96 0x98FD # 0 +0xEF97 0x98FE # 0 +0xEF98 0x98FF # 0 +0xEF99 0x9900 # 0 +0xEF9A 0x9901 # 0 +0xEF9B 0x9902 # 0 +0xEF9C 0x9903 # 0 +0xEF9D 0x9904 # 0 +0xEF9E 0x9905 # 0 +0xEF9F 0x9906 # 0 +0xEFA0 0x9907 # 0 +0xEFA1 0x94E9 # 0 +0xEFA2 0x94EB # 0 +0xEFA3 0x94EE # 0 +0xEFA4 0x94EF # 0 +0xEFA5 0x94F3 # 0 +0xEFA6 0x94F4 # 0 +0xEFA7 0x94F5 # 0 +0xEFA8 0x94F7 # 0 +0xEFA9 0x94F9 # 0 +0xEFAA 0x94FC # 0 +0xEFAB 0x94FD # 0 +0xEFAC 0x94FF # 0 +0xEFAD 0x9503 # 0 +0xEFAE 0x9502 # 0 +0xEFAF 0x9506 # 0 +0xEFB0 0x9507 # 0 +0xEFB1 0x9509 # 0 +0xEFB2 0x950A # 0 +0xEFB3 0x950D # 0 +0xEFB4 0x950E # 0 +0xEFB5 0x950F # 0 +0xEFB6 0x9512 # 0 +0xEFB7 0x9513 # 0 +0xEFB8 0x9514 # 0 +0xEFB9 0x9515 # 0 +0xEFBA 0x9516 # 0 +0xEFBB 0x9518 # 0 +0xEFBC 0x951B # 0 +0xEFBD 0x951D # 0 +0xEFBE 0x951E # 0 +0xEFBF 0x951F # 0 +0xEFC0 0x9522 # 0 +0xEFC1 0x952A # 0 +0xEFC2 0x952B # 0 +0xEFC3 0x9529 # 0 +0xEFC4 0x952C # 0 +0xEFC5 0x9531 # 0 +0xEFC6 0x9532 # 0 +0xEFC7 0x9534 # 0 +0xEFC8 0x9536 # 0 +0xEFC9 0x9537 # 0 +0xEFCA 0x9538 # 0 +0xEFCB 0x953C # 0 +0xEFCC 0x953E # 0 +0xEFCD 0x953F # 0 +0xEFCE 0x9542 # 0 +0xEFCF 0x9535 # 0 +0xEFD0 0x9544 # 0 +0xEFD1 0x9545 # 0 +0xEFD2 0x9546 # 0 +0xEFD3 0x9549 # 0 +0xEFD4 0x954C # 0 +0xEFD5 0x954E # 0 +0xEFD6 0x954F # 0 +0xEFD7 0x9552 # 0 +0xEFD8 0x9553 # 0 +0xEFD9 0x9554 # 0 +0xEFDA 0x9556 # 0 +0xEFDB 0x9557 # 0 +0xEFDC 0x9558 # 0 +0xEFDD 0x9559 # 0 +0xEFDE 0x955B # 0 +0xEFDF 0x955E # 0 +0xEFE0 0x955F # 0 +0xEFE1 0x955D # 0 +0xEFE2 0x9561 # 0 +0xEFE3 0x9562 # 0 +0xEFE4 0x9564 # 0 +0xEFE5 0x9565 # 0 +0xEFE6 0x9566 # 0 +0xEFE7 0x9567 # 0 +0xEFE8 0x9568 # 0 +0xEFE9 0x9569 # 0 +0xEFEA 0x956A # 0 +0xEFEB 0x956B # 0 +0xEFEC 0x956C # 0 +0xEFED 0x956F # 0 +0xEFEE 0x9571 # 0 +0xEFEF 0x9572 # 0 +0xEFF0 0x9573 # 0 +0xEFF1 0x953A # 0 +0xEFF2 0x77E7 # 0 +0xEFF3 0x77EC # 0 +0xEFF4 0x96C9 # 0 +0xEFF5 0x79D5 # 0 +0xEFF6 0x79ED # 0 +0xEFF7 0x79E3 # 0 +0xEFF8 0x79EB # 0 +0xEFF9 0x7A06 # 0 +0xEFFA 0x5D47 # 0 +0xEFFB 0x7A03 # 0 +0xEFFC 0x7A02 # 0 +0xEFFD 0x7A1E # 0 +0xEFFE 0x7A14 # 0 +0xF040 0x9908 # 0 +0xF041 0x9909 # 0 +0xF042 0x990A # 0 +0xF043 0x990B # 0 +0xF044 0x990C # 0 +0xF045 0x990E # 0 +0xF046 0x990F # 0 +0xF047 0x9911 # 0 +0xF048 0x9912 # 0 +0xF049 0x9913 # 0 +0xF04A 0x9914 # 0 +0xF04B 0x9915 # 0 +0xF04C 0x9916 # 0 +0xF04D 0x9917 # 0 +0xF04E 0x9918 # 0 +0xF04F 0x9919 # 0 +0xF050 0x991A # 0 +0xF051 0x991B # 0 +0xF052 0x991C # 0 +0xF053 0x991D # 0 +0xF054 0x991E # 0 +0xF055 0x991F # 0 +0xF056 0x9920 # 0 +0xF057 0x9921 # 0 +0xF058 0x9922 # 0 +0xF059 0x9923 # 0 +0xF05A 0x9924 # 0 +0xF05B 0x9925 # 0 +0xF05C 0x9926 # 0 +0xF05D 0x9927 # 0 +0xF05E 0x9928 # 0 +0xF05F 0x9929 # 0 +0xF060 0x992A # 0 +0xF061 0x992B # 0 +0xF062 0x992C # 0 +0xF063 0x992D # 0 +0xF064 0x992F # 0 +0xF065 0x9930 # 0 +0xF066 0x9931 # 0 +0xF067 0x9932 # 0 +0xF068 0x9933 # 0 +0xF069 0x9934 # 0 +0xF06A 0x9935 # 0 +0xF06B 0x9936 # 0 +0xF06C 0x9937 # 0 +0xF06D 0x9938 # 0 +0xF06E 0x9939 # 0 +0xF06F 0x993A # 0 +0xF070 0x993B # 0 +0xF071 0x993C # 0 +0xF072 0x993D # 0 +0xF073 0x993E # 0 +0xF074 0x993F # 0 +0xF075 0x9940 # 0 +0xF076 0x9941 # 0 +0xF077 0x9942 # 0 +0xF078 0x9943 # 0 +0xF079 0x9944 # 0 +0xF07A 0x9945 # 0 +0xF07B 0x9946 # 0 +0xF07C 0x9947 # 0 +0xF07D 0x9948 # 0 +0xF07E 0x9949 # 0 +0xF080 0x994A # 0 +0xF081 0x994B # 0 +0xF082 0x994C # 0 +0xF083 0x994D # 0 +0xF084 0x994E # 0 +0xF085 0x994F # 0 +0xF086 0x9950 # 0 +0xF087 0x9951 # 0 +0xF088 0x9952 # 0 +0xF089 0x9953 # 0 +0xF08A 0x9956 # 0 +0xF08B 0x9957 # 0 +0xF08C 0x9958 # 0 +0xF08D 0x9959 # 0 +0xF08E 0x995A # 0 +0xF08F 0x995B # 0 +0xF090 0x995C # 0 +0xF091 0x995D # 0 +0xF092 0x995E # 0 +0xF093 0x995F # 0 +0xF094 0x9960 # 0 +0xF095 0x9961 # 0 +0xF096 0x9962 # 0 +0xF097 0x9964 # 0 +0xF098 0x9966 # 0 +0xF099 0x9973 # 0 +0xF09A 0x9978 # 0 +0xF09B 0x9979 # 0 +0xF09C 0x997B # 0 +0xF09D 0x997E # 0 +0xF09E 0x9982 # 0 +0xF09F 0x9983 # 0 +0xF0A0 0x9989 # 0 +0xF0A1 0x7A39 # 0 +0xF0A2 0x7A37 # 0 +0xF0A3 0x7A51 # 0 +0xF0A4 0x9ECF # 0 +0xF0A5 0x99A5 # 0 +0xF0A6 0x7A70 # 0 +0xF0A7 0x7688 # 0 +0xF0A8 0x768E # 0 +0xF0A9 0x7693 # 0 +0xF0AA 0x7699 # 0 +0xF0AB 0x76A4 # 0 +0xF0AC 0x74DE # 0 +0xF0AD 0x74E0 # 0 +0xF0AE 0x752C # 0 +0xF0AF 0x9E20 # 0 +0xF0B0 0x9E22 # 0 +0xF0B1 0x9E28 # 0 +0xF0B2 0x9E29 # 0 +0xF0B3 0x9E2A # 0 +0xF0B4 0x9E2B # 0 +0xF0B5 0x9E2C # 0 +0xF0B6 0x9E32 # 0 +0xF0B7 0x9E31 # 0 +0xF0B8 0x9E36 # 0 +0xF0B9 0x9E38 # 0 +0xF0BA 0x9E37 # 0 +0xF0BB 0x9E39 # 0 +0xF0BC 0x9E3A # 0 +0xF0BD 0x9E3E # 0 +0xF0BE 0x9E41 # 0 +0xF0BF 0x9E42 # 0 +0xF0C0 0x9E44 # 0 +0xF0C1 0x9E46 # 0 +0xF0C2 0x9E47 # 0 +0xF0C3 0x9E48 # 0 +0xF0C4 0x9E49 # 0 +0xF0C5 0x9E4B # 0 +0xF0C6 0x9E4C # 0 +0xF0C7 0x9E4E # 0 +0xF0C8 0x9E51 # 0 +0xF0C9 0x9E55 # 0 +0xF0CA 0x9E57 # 0 +0xF0CB 0x9E5A # 0 +0xF0CC 0x9E5B # 0 +0xF0CD 0x9E5C # 0 +0xF0CE 0x9E5E # 0 +0xF0CF 0x9E63 # 0 +0xF0D0 0x9E66 # 0 +0xF0D1 0x9E67 # 0 +0xF0D2 0x9E68 # 0 +0xF0D3 0x9E69 # 0 +0xF0D4 0x9E6A # 0 +0xF0D5 0x9E6B # 0 +0xF0D6 0x9E6C # 0 +0xF0D7 0x9E71 # 0 +0xF0D8 0x9E6D # 0 +0xF0D9 0x9E73 # 0 +0xF0DA 0x7592 # 0 +0xF0DB 0x7594 # 0 +0xF0DC 0x7596 # 0 +0xF0DD 0x75A0 # 0 +0xF0DE 0x759D # 0 +0xF0DF 0x75AC # 0 +0xF0E0 0x75A3 # 0 +0xF0E1 0x75B3 # 0 +0xF0E2 0x75B4 # 0 +0xF0E3 0x75B8 # 0 +0xF0E4 0x75C4 # 0 +0xF0E5 0x75B1 # 0 +0xF0E6 0x75B0 # 0 +0xF0E7 0x75C3 # 0 +0xF0E8 0x75C2 # 0 +0xF0E9 0x75D6 # 0 +0xF0EA 0x75CD # 0 +0xF0EB 0x75E3 # 0 +0xF0EC 0x75E8 # 0 +0xF0ED 0x75E6 # 0 +0xF0EE 0x75E4 # 0 +0xF0EF 0x75EB # 0 +0xF0F0 0x75E7 # 0 +0xF0F1 0x7603 # 0 +0xF0F2 0x75F1 # 0 +0xF0F3 0x75FC # 0 +0xF0F4 0x75FF # 0 +0xF0F5 0x7610 # 0 +0xF0F6 0x7600 # 0 +0xF0F7 0x7605 # 0 +0xF0F8 0x760C # 0 +0xF0F9 0x7617 # 0 +0xF0FA 0x760A # 0 +0xF0FB 0x7625 # 0 +0xF0FC 0x7618 # 0 +0xF0FD 0x7615 # 0 +0xF0FE 0x7619 # 0 +0xF140 0x998C # 0 +0xF141 0x998E # 0 +0xF142 0x999A # 0 +0xF143 0x999B # 0 +0xF144 0x999C # 0 +0xF145 0x999D # 0 +0xF146 0x999E # 0 +0xF147 0x999F # 0 +0xF148 0x99A0 # 0 +0xF149 0x99A1 # 0 +0xF14A 0x99A2 # 0 +0xF14B 0x99A3 # 0 +0xF14C 0x99A4 # 0 +0xF14D 0x99A6 # 0 +0xF14E 0x99A7 # 0 +0xF14F 0x99A9 # 0 +0xF150 0x99AA # 0 +0xF151 0x99AB # 0 +0xF152 0x99AC # 0 +0xF153 0x99AD # 0 +0xF154 0x99AE # 0 +0xF155 0x99AF # 0 +0xF156 0x99B0 # 0 +0xF157 0x99B1 # 0 +0xF158 0x99B2 # 0 +0xF159 0x99B3 # 0 +0xF15A 0x99B4 # 0 +0xF15B 0x99B5 # 0 +0xF15C 0x99B6 # 0 +0xF15D 0x99B7 # 0 +0xF15E 0x99B8 # 0 +0xF15F 0x99B9 # 0 +0xF160 0x99BA # 0 +0xF161 0x99BB # 0 +0xF162 0x99BC # 0 +0xF163 0x99BD # 0 +0xF164 0x99BE # 0 +0xF165 0x99BF # 0 +0xF166 0x99C0 # 0 +0xF167 0x99C1 # 0 +0xF168 0x99C2 # 0 +0xF169 0x99C3 # 0 +0xF16A 0x99C4 # 0 +0xF16B 0x99C5 # 0 +0xF16C 0x99C6 # 0 +0xF16D 0x99C7 # 0 +0xF16E 0x99C8 # 0 +0xF16F 0x99C9 # 0 +0xF170 0x99CA # 0 +0xF171 0x99CB # 0 +0xF172 0x99CC # 0 +0xF173 0x99CD # 0 +0xF174 0x99CE # 0 +0xF175 0x99CF # 0 +0xF176 0x99D0 # 0 +0xF177 0x99D1 # 0 +0xF178 0x99D2 # 0 +0xF179 0x99D3 # 0 +0xF17A 0x99D4 # 0 +0xF17B 0x99D5 # 0 +0xF17C 0x99D6 # 0 +0xF17D 0x99D7 # 0 +0xF17E 0x99D8 # 0 +0xF180 0x99D9 # 0 +0xF181 0x99DA # 0 +0xF182 0x99DB # 0 +0xF183 0x99DC # 0 +0xF184 0x99DD # 0 +0xF185 0x99DE # 0 +0xF186 0x99DF # 0 +0xF187 0x99E0 # 0 +0xF188 0x99E1 # 0 +0xF189 0x99E2 # 0 +0xF18A 0x99E3 # 0 +0xF18B 0x99E4 # 0 +0xF18C 0x99E5 # 0 +0xF18D 0x99E6 # 0 +0xF18E 0x99E7 # 0 +0xF18F 0x99E8 # 0 +0xF190 0x99E9 # 0 +0xF191 0x99EA # 0 +0xF192 0x99EB # 0 +0xF193 0x99EC # 0 +0xF194 0x99ED # 0 +0xF195 0x99EE # 0 +0xF196 0x99EF # 0 +0xF197 0x99F0 # 0 +0xF198 0x99F1 # 0 +0xF199 0x99F2 # 0 +0xF19A 0x99F3 # 0 +0xF19B 0x99F4 # 0 +0xF19C 0x99F5 # 0 +0xF19D 0x99F6 # 0 +0xF19E 0x99F7 # 0 +0xF19F 0x99F8 # 0 +0xF1A0 0x99F9 # 0 +0xF1A1 0x761B # 0 +0xF1A2 0x763C # 0 +0xF1A3 0x7622 # 0 +0xF1A4 0x7620 # 0 +0xF1A5 0x7640 # 0 +0xF1A6 0x762D # 0 +0xF1A7 0x7630 # 0 +0xF1A8 0x763F # 0 +0xF1A9 0x7635 # 0 +0xF1AA 0x7643 # 0 +0xF1AB 0x763E # 0 +0xF1AC 0x7633 # 0 +0xF1AD 0x764D # 0 +0xF1AE 0x765E # 0 +0xF1AF 0x7654 # 0 +0xF1B0 0x765C # 0 +0xF1B1 0x7656 # 0 +0xF1B2 0x766B # 0 +0xF1B3 0x766F # 0 +0xF1B4 0x7FCA # 0 +0xF1B5 0x7AE6 # 0 +0xF1B6 0x7A78 # 0 +0xF1B7 0x7A79 # 0 +0xF1B8 0x7A80 # 0 +0xF1B9 0x7A86 # 0 +0xF1BA 0x7A88 # 0 +0xF1BB 0x7A95 # 0 +0xF1BC 0x7AA6 # 0 +0xF1BD 0x7AA0 # 0 +0xF1BE 0x7AAC # 0 +0xF1BF 0x7AA8 # 0 +0xF1C0 0x7AAD # 0 +0xF1C1 0x7AB3 # 0 +0xF1C2 0x8864 # 0 +0xF1C3 0x8869 # 0 +0xF1C4 0x8872 # 0 +0xF1C5 0x887D # 0 +0xF1C6 0x887F # 0 +0xF1C7 0x8882 # 0 +0xF1C8 0x88A2 # 0 +0xF1C9 0x88C6 # 0 +0xF1CA 0x88B7 # 0 +0xF1CB 0x88BC # 0 +0xF1CC 0x88C9 # 0 +0xF1CD 0x88E2 # 0 +0xF1CE 0x88CE # 0 +0xF1CF 0x88E3 # 0 +0xF1D0 0x88E5 # 0 +0xF1D1 0x88F1 # 0 +0xF1D2 0x891A # 0 +0xF1D3 0x88FC # 0 +0xF1D4 0x88E8 # 0 +0xF1D5 0x88FE # 0 +0xF1D6 0x88F0 # 0 +0xF1D7 0x8921 # 0 +0xF1D8 0x8919 # 0 +0xF1D9 0x8913 # 0 +0xF1DA 0x891B # 0 +0xF1DB 0x890A # 0 +0xF1DC 0x8934 # 0 +0xF1DD 0x892B # 0 +0xF1DE 0x8936 # 0 +0xF1DF 0x8941 # 0 +0xF1E0 0x8966 # 0 +0xF1E1 0x897B # 0 +0xF1E2 0x758B # 0 +0xF1E3 0x80E5 # 0 +0xF1E4 0x76B2 # 0 +0xF1E5 0x76B4 # 0 +0xF1E6 0x77DC # 0 +0xF1E7 0x8012 # 0 +0xF1E8 0x8014 # 0 +0xF1E9 0x8016 # 0 +0xF1EA 0x801C # 0 +0xF1EB 0x8020 # 0 +0xF1EC 0x8022 # 0 +0xF1ED 0x8025 # 0 +0xF1EE 0x8026 # 0 +0xF1EF 0x8027 # 0 +0xF1F0 0x8029 # 0 +0xF1F1 0x8028 # 0 +0xF1F2 0x8031 # 0 +0xF1F3 0x800B # 0 +0xF1F4 0x8035 # 0 +0xF1F5 0x8043 # 0 +0xF1F6 0x8046 # 0 +0xF1F7 0x804D # 0 +0xF1F8 0x8052 # 0 +0xF1F9 0x8069 # 0 +0xF1FA 0x8071 # 0 +0xF1FB 0x8983 # 0 +0xF1FC 0x9878 # 0 +0xF1FD 0x9880 # 0 +0xF1FE 0x9883 # 0 +0xF240 0x99FA # 0 +0xF241 0x99FB # 0 +0xF242 0x99FC # 0 +0xF243 0x99FD # 0 +0xF244 0x99FE # 0 +0xF245 0x99FF # 0 +0xF246 0x9A00 # 0 +0xF247 0x9A01 # 0 +0xF248 0x9A02 # 0 +0xF249 0x9A03 # 0 +0xF24A 0x9A04 # 0 +0xF24B 0x9A05 # 0 +0xF24C 0x9A06 # 0 +0xF24D 0x9A07 # 0 +0xF24E 0x9A08 # 0 +0xF24F 0x9A09 # 0 +0xF250 0x9A0A # 0 +0xF251 0x9A0B # 0 +0xF252 0x9A0C # 0 +0xF253 0x9A0D # 0 +0xF254 0x9A0E # 0 +0xF255 0x9A0F # 0 +0xF256 0x9A10 # 0 +0xF257 0x9A11 # 0 +0xF258 0x9A12 # 0 +0xF259 0x9A13 # 0 +0xF25A 0x9A14 # 0 +0xF25B 0x9A15 # 0 +0xF25C 0x9A16 # 0 +0xF25D 0x9A17 # 0 +0xF25E 0x9A18 # 0 +0xF25F 0x9A19 # 0 +0xF260 0x9A1A # 0 +0xF261 0x9A1B # 0 +0xF262 0x9A1C # 0 +0xF263 0x9A1D # 0 +0xF264 0x9A1E # 0 +0xF265 0x9A1F # 0 +0xF266 0x9A20 # 0 +0xF267 0x9A21 # 0 +0xF268 0x9A22 # 0 +0xF269 0x9A23 # 0 +0xF26A 0x9A24 # 0 +0xF26B 0x9A25 # 0 +0xF26C 0x9A26 # 0 +0xF26D 0x9A27 # 0 +0xF26E 0x9A28 # 0 +0xF26F 0x9A29 # 0 +0xF270 0x9A2A # 0 +0xF271 0x9A2B # 0 +0xF272 0x9A2C # 0 +0xF273 0x9A2D # 0 +0xF274 0x9A2E # 0 +0xF275 0x9A2F # 0 +0xF276 0x9A30 # 0 +0xF277 0x9A31 # 0 +0xF278 0x9A32 # 0 +0xF279 0x9A33 # 0 +0xF27A 0x9A34 # 0 +0xF27B 0x9A35 # 0 +0xF27C 0x9A36 # 0 +0xF27D 0x9A37 # 0 +0xF27E 0x9A38 # 0 +0xF280 0x9A39 # 0 +0xF281 0x9A3A # 0 +0xF282 0x9A3B # 0 +0xF283 0x9A3C # 0 +0xF284 0x9A3D # 0 +0xF285 0x9A3E # 0 +0xF286 0x9A3F # 0 +0xF287 0x9A40 # 0 +0xF288 0x9A41 # 0 +0xF289 0x9A42 # 0 +0xF28A 0x9A43 # 0 +0xF28B 0x9A44 # 0 +0xF28C 0x9A45 # 0 +0xF28D 0x9A46 # 0 +0xF28E 0x9A47 # 0 +0xF28F 0x9A48 # 0 +0xF290 0x9A49 # 0 +0xF291 0x9A4A # 0 +0xF292 0x9A4B # 0 +0xF293 0x9A4C # 0 +0xF294 0x9A4D # 0 +0xF295 0x9A4E # 0 +0xF296 0x9A4F # 0 +0xF297 0x9A50 # 0 +0xF298 0x9A51 # 0 +0xF299 0x9A52 # 0 +0xF29A 0x9A53 # 0 +0xF29B 0x9A54 # 0 +0xF29C 0x9A55 # 0 +0xF29D 0x9A56 # 0 +0xF29E 0x9A57 # 0 +0xF29F 0x9A58 # 0 +0xF2A0 0x9A59 # 0 +0xF2A1 0x9889 # 0 +0xF2A2 0x988C # 0 +0xF2A3 0x988D # 0 +0xF2A4 0x988F # 0 +0xF2A5 0x9894 # 0 +0xF2A6 0x989A # 0 +0xF2A7 0x989B # 0 +0xF2A8 0x989E # 0 +0xF2A9 0x989F # 0 +0xF2AA 0x98A1 # 0 +0xF2AB 0x98A2 # 0 +0xF2AC 0x98A5 # 0 +0xF2AD 0x98A6 # 0 +0xF2AE 0x864D # 0 +0xF2AF 0x8654 # 0 +0xF2B0 0x866C # 0 +0xF2B1 0x866E # 0 +0xF2B2 0x867F # 0 +0xF2B3 0x867A # 0 +0xF2B4 0x867C # 0 +0xF2B5 0x867B # 0 +0xF2B6 0x86A8 # 0 +0xF2B7 0x868D # 0 +0xF2B8 0x868B # 0 +0xF2B9 0x86AC # 0 +0xF2BA 0x869D # 0 +0xF2BB 0x86A7 # 0 +0xF2BC 0x86A3 # 0 +0xF2BD 0x86AA # 0 +0xF2BE 0x8693 # 0 +0xF2BF 0x86A9 # 0 +0xF2C0 0x86B6 # 0 +0xF2C1 0x86C4 # 0 +0xF2C2 0x86B5 # 0 +0xF2C3 0x86CE # 0 +0xF2C4 0x86B0 # 0 +0xF2C5 0x86BA # 0 +0xF2C6 0x86B1 # 0 +0xF2C7 0x86AF # 0 +0xF2C8 0x86C9 # 0 +0xF2C9 0x86CF # 0 +0xF2CA 0x86B4 # 0 +0xF2CB 0x86E9 # 0 +0xF2CC 0x86F1 # 0 +0xF2CD 0x86F2 # 0 +0xF2CE 0x86ED # 0 +0xF2CF 0x86F3 # 0 +0xF2D0 0x86D0 # 0 +0xF2D1 0x8713 # 0 +0xF2D2 0x86DE # 0 +0xF2D3 0x86F4 # 0 +0xF2D4 0x86DF # 0 +0xF2D5 0x86D8 # 0 +0xF2D6 0x86D1 # 0 +0xF2D7 0x8703 # 0 +0xF2D8 0x8707 # 0 +0xF2D9 0x86F8 # 0 +0xF2DA 0x8708 # 0 +0xF2DB 0x870A # 0 +0xF2DC 0x870D # 0 +0xF2DD 0x8709 # 0 +0xF2DE 0x8723 # 0 +0xF2DF 0x873B # 0 +0xF2E0 0x871E # 0 +0xF2E1 0x8725 # 0 +0xF2E2 0x872E # 0 +0xF2E3 0x871A # 0 +0xF2E4 0x873E # 0 +0xF2E5 0x8748 # 0 +0xF2E6 0x8734 # 0 +0xF2E7 0x8731 # 0 +0xF2E8 0x8729 # 0 +0xF2E9 0x8737 # 0 +0xF2EA 0x873F # 0 +0xF2EB 0x8782 # 0 +0xF2EC 0x8722 # 0 +0xF2ED 0x877D # 0 +0xF2EE 0x877E # 0 +0xF2EF 0x877B # 0 +0xF2F0 0x8760 # 0 +0xF2F1 0x8770 # 0 +0xF2F2 0x874C # 0 +0xF2F3 0x876E # 0 +0xF2F4 0x878B # 0 +0xF2F5 0x8753 # 0 +0xF2F6 0x8763 # 0 +0xF2F7 0x877C # 0 +0xF2F8 0x8764 # 0 +0xF2F9 0x8759 # 0 +0xF2FA 0x8765 # 0 +0xF2FB 0x8793 # 0 +0xF2FC 0x87AF # 0 +0xF2FD 0x87A8 # 0 +0xF2FE 0x87D2 # 0 +0xF340 0x9A5A # 0 +0xF341 0x9A5B # 0 +0xF342 0x9A5C # 0 +0xF343 0x9A5D # 0 +0xF344 0x9A5E # 0 +0xF345 0x9A5F # 0 +0xF346 0x9A60 # 0 +0xF347 0x9A61 # 0 +0xF348 0x9A62 # 0 +0xF349 0x9A63 # 0 +0xF34A 0x9A64 # 0 +0xF34B 0x9A65 # 0 +0xF34C 0x9A66 # 0 +0xF34D 0x9A67 # 0 +0xF34E 0x9A68 # 0 +0xF34F 0x9A69 # 0 +0xF350 0x9A6A # 0 +0xF351 0x9A6B # 0 +0xF352 0x9A72 # 0 +0xF353 0x9A83 # 0 +0xF354 0x9A89 # 0 +0xF355 0x9A8D # 0 +0xF356 0x9A8E # 0 +0xF357 0x9A94 # 0 +0xF358 0x9A95 # 0 +0xF359 0x9A99 # 0 +0xF35A 0x9AA6 # 0 +0xF35B 0x9AA9 # 0 +0xF35C 0x9AAA # 0 +0xF35D 0x9AAB # 0 +0xF35E 0x9AAC # 0 +0xF35F 0x9AAD # 0 +0xF360 0x9AAE # 0 +0xF361 0x9AAF # 0 +0xF362 0x9AB2 # 0 +0xF363 0x9AB3 # 0 +0xF364 0x9AB4 # 0 +0xF365 0x9AB5 # 0 +0xF366 0x9AB9 # 0 +0xF367 0x9ABB # 0 +0xF368 0x9ABD # 0 +0xF369 0x9ABE # 0 +0xF36A 0x9ABF # 0 +0xF36B 0x9AC3 # 0 +0xF36C 0x9AC4 # 0 +0xF36D 0x9AC6 # 0 +0xF36E 0x9AC7 # 0 +0xF36F 0x9AC8 # 0 +0xF370 0x9AC9 # 0 +0xF371 0x9ACA # 0 +0xF372 0x9ACD # 0 +0xF373 0x9ACE # 0 +0xF374 0x9ACF # 0 +0xF375 0x9AD0 # 0 +0xF376 0x9AD2 # 0 +0xF377 0x9AD4 # 0 +0xF378 0x9AD5 # 0 +0xF379 0x9AD6 # 0 +0xF37A 0x9AD7 # 0 +0xF37B 0x9AD9 # 0 +0xF37C 0x9ADA # 0 +0xF37D 0x9ADB # 0 +0xF37E 0x9ADC # 0 +0xF380 0x9ADD # 0 +0xF381 0x9ADE # 0 +0xF382 0x9AE0 # 0 +0xF383 0x9AE2 # 0 +0xF384 0x9AE3 # 0 +0xF385 0x9AE4 # 0 +0xF386 0x9AE5 # 0 +0xF387 0x9AE7 # 0 +0xF388 0x9AE8 # 0 +0xF389 0x9AE9 # 0 +0xF38A 0x9AEA # 0 +0xF38B 0x9AEC # 0 +0xF38C 0x9AEE # 0 +0xF38D 0x9AF0 # 0 +0xF38E 0x9AF1 # 0 +0xF38F 0x9AF2 # 0 +0xF390 0x9AF3 # 0 +0xF391 0x9AF4 # 0 +0xF392 0x9AF5 # 0 +0xF393 0x9AF6 # 0 +0xF394 0x9AF7 # 0 +0xF395 0x9AF8 # 0 +0xF396 0x9AFA # 0 +0xF397 0x9AFC # 0 +0xF398 0x9AFD # 0 +0xF399 0x9AFE # 0 +0xF39A 0x9AFF # 0 +0xF39B 0x9B00 # 0 +0xF39C 0x9B01 # 0 +0xF39D 0x9B02 # 0 +0xF39E 0x9B04 # 0 +0xF39F 0x9B05 # 0 +0xF3A0 0x9B06 # 0 +0xF3A1 0x87C6 # 0 +0xF3A2 0x8788 # 0 +0xF3A3 0x8785 # 0 +0xF3A4 0x87AD # 0 +0xF3A5 0x8797 # 0 +0xF3A6 0x8783 # 0 +0xF3A7 0x87AB # 0 +0xF3A8 0x87E5 # 0 +0xF3A9 0x87AC # 0 +0xF3AA 0x87B5 # 0 +0xF3AB 0x87B3 # 0 +0xF3AC 0x87CB # 0 +0xF3AD 0x87D3 # 0 +0xF3AE 0x87BD # 0 +0xF3AF 0x87D1 # 0 +0xF3B0 0x87C0 # 0 +0xF3B1 0x87CA # 0 +0xF3B2 0x87DB # 0 +0xF3B3 0x87EA # 0 +0xF3B4 0x87E0 # 0 +0xF3B5 0x87EE # 0 +0xF3B6 0x8816 # 0 +0xF3B7 0x8813 # 0 +0xF3B8 0x87FE # 0 +0xF3B9 0x880A # 0 +0xF3BA 0x881B # 0 +0xF3BB 0x8821 # 0 +0xF3BC 0x8839 # 0 +0xF3BD 0x883C # 0 +0xF3BE 0x7F36 # 0 +0xF3BF 0x7F42 # 0 +0xF3C0 0x7F44 # 0 +0xF3C1 0x7F45 # 0 +0xF3C2 0x8210 # 0 +0xF3C3 0x7AFA # 0 +0xF3C4 0x7AFD # 0 +0xF3C5 0x7B08 # 0 +0xF3C6 0x7B03 # 0 +0xF3C7 0x7B04 # 0 +0xF3C8 0x7B15 # 0 +0xF3C9 0x7B0A # 0 +0xF3CA 0x7B2B # 0 +0xF3CB 0x7B0F # 0 +0xF3CC 0x7B47 # 0 +0xF3CD 0x7B38 # 0 +0xF3CE 0x7B2A # 0 +0xF3CF 0x7B19 # 0 +0xF3D0 0x7B2E # 0 +0xF3D1 0x7B31 # 0 +0xF3D2 0x7B20 # 0 +0xF3D3 0x7B25 # 0 +0xF3D4 0x7B24 # 0 +0xF3D5 0x7B33 # 0 +0xF3D6 0x7B3E # 0 +0xF3D7 0x7B1E # 0 +0xF3D8 0x7B58 # 0 +0xF3D9 0x7B5A # 0 +0xF3DA 0x7B45 # 0 +0xF3DB 0x7B75 # 0 +0xF3DC 0x7B4C # 0 +0xF3DD 0x7B5D # 0 +0xF3DE 0x7B60 # 0 +0xF3DF 0x7B6E # 0 +0xF3E0 0x7B7B # 0 +0xF3E1 0x7B62 # 0 +0xF3E2 0x7B72 # 0 +0xF3E3 0x7B71 # 0 +0xF3E4 0x7B90 # 0 +0xF3E5 0x7BA6 # 0 +0xF3E6 0x7BA7 # 0 +0xF3E7 0x7BB8 # 0 +0xF3E8 0x7BAC # 0 +0xF3E9 0x7B9D # 0 +0xF3EA 0x7BA8 # 0 +0xF3EB 0x7B85 # 0 +0xF3EC 0x7BAA # 0 +0xF3ED 0x7B9C # 0 +0xF3EE 0x7BA2 # 0 +0xF3EF 0x7BAB # 0 +0xF3F0 0x7BB4 # 0 +0xF3F1 0x7BD1 # 0 +0xF3F2 0x7BC1 # 0 +0xF3F3 0x7BCC # 0 +0xF3F4 0x7BDD # 0 +0xF3F5 0x7BDA # 0 +0xF3F6 0x7BE5 # 0 +0xF3F7 0x7BE6 # 0 +0xF3F8 0x7BEA # 0 +0xF3F9 0x7C0C # 0 +0xF3FA 0x7BFE # 0 +0xF3FB 0x7BFC # 0 +0xF3FC 0x7C0F # 0 +0xF3FD 0x7C16 # 0 +0xF3FE 0x7C0B # 0 +0xF440 0x9B07 # 0 +0xF441 0x9B09 # 0 +0xF442 0x9B0A # 0 +0xF443 0x9B0B # 0 +0xF444 0x9B0C # 0 +0xF445 0x9B0D # 0 +0xF446 0x9B0E # 0 +0xF447 0x9B10 # 0 +0xF448 0x9B11 # 0 +0xF449 0x9B12 # 0 +0xF44A 0x9B14 # 0 +0xF44B 0x9B15 # 0 +0xF44C 0x9B16 # 0 +0xF44D 0x9B17 # 0 +0xF44E 0x9B18 # 0 +0xF44F 0x9B19 # 0 +0xF450 0x9B1A # 0 +0xF451 0x9B1B # 0 +0xF452 0x9B1C # 0 +0xF453 0x9B1D # 0 +0xF454 0x9B1E # 0 +0xF455 0x9B20 # 0 +0xF456 0x9B21 # 0 +0xF457 0x9B22 # 0 +0xF458 0x9B24 # 0 +0xF459 0x9B25 # 0 +0xF45A 0x9B26 # 0 +0xF45B 0x9B27 # 0 +0xF45C 0x9B28 # 0 +0xF45D 0x9B29 # 0 +0xF45E 0x9B2A # 0 +0xF45F 0x9B2B # 0 +0xF460 0x9B2C # 0 +0xF461 0x9B2D # 0 +0xF462 0x9B2E # 0 +0xF463 0x9B30 # 0 +0xF464 0x9B31 # 0 +0xF465 0x9B33 # 0 +0xF466 0x9B34 # 0 +0xF467 0x9B35 # 0 +0xF468 0x9B36 # 0 +0xF469 0x9B37 # 0 +0xF46A 0x9B38 # 0 +0xF46B 0x9B39 # 0 +0xF46C 0x9B3A # 0 +0xF46D 0x9B3D # 0 +0xF46E 0x9B3E # 0 +0xF46F 0x9B3F # 0 +0xF470 0x9B40 # 0 +0xF471 0x9B46 # 0 +0xF472 0x9B4A # 0 +0xF473 0x9B4B # 0 +0xF474 0x9B4C # 0 +0xF475 0x9B4E # 0 +0xF476 0x9B50 # 0 +0xF477 0x9B52 # 0 +0xF478 0x9B53 # 0 +0xF479 0x9B55 # 0 +0xF47A 0x9B56 # 0 +0xF47B 0x9B57 # 0 +0xF47C 0x9B58 # 0 +0xF47D 0x9B59 # 0 +0xF47E 0x9B5A # 0 +0xF480 0x9B5B # 0 +0xF481 0x9B5C # 0 +0xF482 0x9B5D # 0 +0xF483 0x9B5E # 0 +0xF484 0x9B5F # 0 +0xF485 0x9B60 # 0 +0xF486 0x9B61 # 0 +0xF487 0x9B62 # 0 +0xF488 0x9B63 # 0 +0xF489 0x9B64 # 0 +0xF48A 0x9B65 # 0 +0xF48B 0x9B66 # 0 +0xF48C 0x9B67 # 0 +0xF48D 0x9B68 # 0 +0xF48E 0x9B69 # 0 +0xF48F 0x9B6A # 0 +0xF490 0x9B6B # 0 +0xF491 0x9B6C # 0 +0xF492 0x9B6D # 0 +0xF493 0x9B6E # 0 +0xF494 0x9B6F # 0 +0xF495 0x9B70 # 0 +0xF496 0x9B71 # 0 +0xF497 0x9B72 # 0 +0xF498 0x9B73 # 0 +0xF499 0x9B74 # 0 +0xF49A 0x9B75 # 0 +0xF49B 0x9B76 # 0 +0xF49C 0x9B77 # 0 +0xF49D 0x9B78 # 0 +0xF49E 0x9B79 # 0 +0xF49F 0x9B7A # 0 +0xF4A0 0x9B7B # 0 +0xF4A1 0x7C1F # 0 +0xF4A2 0x7C2A # 0 +0xF4A3 0x7C26 # 0 +0xF4A4 0x7C38 # 0 +0xF4A5 0x7C41 # 0 +0xF4A6 0x7C40 # 0 +0xF4A7 0x81FE # 0 +0xF4A8 0x8201 # 0 +0xF4A9 0x8202 # 0 +0xF4AA 0x8204 # 0 +0xF4AB 0x81EC # 0 +0xF4AC 0x8844 # 0 +0xF4AD 0x8221 # 0 +0xF4AE 0x8222 # 0 +0xF4AF 0x8223 # 0 +0xF4B0 0x822D # 0 +0xF4B1 0x822F # 0 +0xF4B2 0x8228 # 0 +0xF4B3 0x822B # 0 +0xF4B4 0x8238 # 0 +0xF4B5 0x823B # 0 +0xF4B6 0x8233 # 0 +0xF4B7 0x8234 # 0 +0xF4B8 0x823E # 0 +0xF4B9 0x8244 # 0 +0xF4BA 0x8249 # 0 +0xF4BB 0x824B # 0 +0xF4BC 0x824F # 0 +0xF4BD 0x825A # 0 +0xF4BE 0x825F # 0 +0xF4BF 0x8268 # 0 +0xF4C0 0x887E # 0 +0xF4C1 0x8885 # 0 +0xF4C2 0x8888 # 0 +0xF4C3 0x88D8 # 0 +0xF4C4 0x88DF # 0 +0xF4C5 0x895E # 0 +0xF4C6 0x7F9D # 0 +0xF4C7 0x7F9F # 0 +0xF4C8 0x7FA7 # 0 +0xF4C9 0x7FAF # 0 +0xF4CA 0x7FB0 # 0 +0xF4CB 0x7FB2 # 0 +0xF4CC 0x7C7C # 0 +0xF4CD 0x6549 # 0 +0xF4CE 0x7C91 # 0 +0xF4CF 0x7C9D # 0 +0xF4D0 0x7C9C # 0 +0xF4D1 0x7C9E # 0 +0xF4D2 0x7CA2 # 0 +0xF4D3 0x7CB2 # 0 +0xF4D4 0x7CBC # 0 +0xF4D5 0x7CBD # 0 +0xF4D6 0x7CC1 # 0 +0xF4D7 0x7CC7 # 0 +0xF4D8 0x7CCC # 0 +0xF4D9 0x7CCD # 0 +0xF4DA 0x7CC8 # 0 +0xF4DB 0x7CC5 # 0 +0xF4DC 0x7CD7 # 0 +0xF4DD 0x7CE8 # 0 +0xF4DE 0x826E # 0 +0xF4DF 0x66A8 # 0 +0xF4E0 0x7FBF # 0 +0xF4E1 0x7FCE # 0 +0xF4E2 0x7FD5 # 0 +0xF4E3 0x7FE5 # 0 +0xF4E4 0x7FE1 # 0 +0xF4E5 0x7FE6 # 0 +0xF4E6 0x7FE9 # 0 +0xF4E7 0x7FEE # 0 +0xF4E8 0x7FF3 # 0 +0xF4E9 0x7CF8 # 0 +0xF4EA 0x7D77 # 0 +0xF4EB 0x7DA6 # 0 +0xF4EC 0x7DAE # 0 +0xF4ED 0x7E47 # 0 +0xF4EE 0x7E9B # 0 +0xF4EF 0x9EB8 # 0 +0xF4F0 0x9EB4 # 0 +0xF4F1 0x8D73 # 0 +0xF4F2 0x8D84 # 0 +0xF4F3 0x8D94 # 0 +0xF4F4 0x8D91 # 0 +0xF4F5 0x8DB1 # 0 +0xF4F6 0x8D67 # 0 +0xF4F7 0x8D6D # 0 +0xF4F8 0x8C47 # 0 +0xF4F9 0x8C49 # 0 +0xF4FA 0x914A # 0 +0xF4FB 0x9150 # 0 +0xF4FC 0x914E # 0 +0xF4FD 0x914F # 0 +0xF4FE 0x9164 # 0 +0xF540 0x9B7C # 0 +0xF541 0x9B7D # 0 +0xF542 0x9B7E # 0 +0xF543 0x9B7F # 0 +0xF544 0x9B80 # 0 +0xF545 0x9B81 # 0 +0xF546 0x9B82 # 0 +0xF547 0x9B83 # 0 +0xF548 0x9B84 # 0 +0xF549 0x9B85 # 0 +0xF54A 0x9B86 # 0 +0xF54B 0x9B87 # 0 +0xF54C 0x9B88 # 0 +0xF54D 0x9B89 # 0 +0xF54E 0x9B8A # 0 +0xF54F 0x9B8B # 0 +0xF550 0x9B8C # 0 +0xF551 0x9B8D # 0 +0xF552 0x9B8E # 0 +0xF553 0x9B8F # 0 +0xF554 0x9B90 # 0 +0xF555 0x9B91 # 0 +0xF556 0x9B92 # 0 +0xF557 0x9B93 # 0 +0xF558 0x9B94 # 0 +0xF559 0x9B95 # 0 +0xF55A 0x9B96 # 0 +0xF55B 0x9B97 # 0 +0xF55C 0x9B98 # 0 +0xF55D 0x9B99 # 0 +0xF55E 0x9B9A # 0 +0xF55F 0x9B9B # 0 +0xF560 0x9B9C # 0 +0xF561 0x9B9D # 0 +0xF562 0x9B9E # 0 +0xF563 0x9B9F # 0 +0xF564 0x9BA0 # 0 +0xF565 0x9BA1 # 0 +0xF566 0x9BA2 # 0 +0xF567 0x9BA3 # 0 +0xF568 0x9BA4 # 0 +0xF569 0x9BA5 # 0 +0xF56A 0x9BA6 # 0 +0xF56B 0x9BA7 # 0 +0xF56C 0x9BA8 # 0 +0xF56D 0x9BA9 # 0 +0xF56E 0x9BAA # 0 +0xF56F 0x9BAB # 0 +0xF570 0x9BAC # 0 +0xF571 0x9BAD # 0 +0xF572 0x9BAE # 0 +0xF573 0x9BAF # 0 +0xF574 0x9BB0 # 0 +0xF575 0x9BB1 # 0 +0xF576 0x9BB2 # 0 +0xF577 0x9BB3 # 0 +0xF578 0x9BB4 # 0 +0xF579 0x9BB5 # 0 +0xF57A 0x9BB6 # 0 +0xF57B 0x9BB7 # 0 +0xF57C 0x9BB8 # 0 +0xF57D 0x9BB9 # 0 +0xF57E 0x9BBA # 0 +0xF580 0x9BBB # 0 +0xF581 0x9BBC # 0 +0xF582 0x9BBD # 0 +0xF583 0x9BBE # 0 +0xF584 0x9BBF # 0 +0xF585 0x9BC0 # 0 +0xF586 0x9BC1 # 0 +0xF587 0x9BC2 # 0 +0xF588 0x9BC3 # 0 +0xF589 0x9BC4 # 0 +0xF58A 0x9BC5 # 0 +0xF58B 0x9BC6 # 0 +0xF58C 0x9BC7 # 0 +0xF58D 0x9BC8 # 0 +0xF58E 0x9BC9 # 0 +0xF58F 0x9BCA # 0 +0xF590 0x9BCB # 0 +0xF591 0x9BCC # 0 +0xF592 0x9BCD # 0 +0xF593 0x9BCE # 0 +0xF594 0x9BCF # 0 +0xF595 0x9BD0 # 0 +0xF596 0x9BD1 # 0 +0xF597 0x9BD2 # 0 +0xF598 0x9BD3 # 0 +0xF599 0x9BD4 # 0 +0xF59A 0x9BD5 # 0 +0xF59B 0x9BD6 # 0 +0xF59C 0x9BD7 # 0 +0xF59D 0x9BD8 # 0 +0xF59E 0x9BD9 # 0 +0xF59F 0x9BDA # 0 +0xF5A0 0x9BDB # 0 +0xF5A1 0x9162 # 0 +0xF5A2 0x9161 # 0 +0xF5A3 0x9170 # 0 +0xF5A4 0x9169 # 0 +0xF5A5 0x916F # 0 +0xF5A6 0x917D # 0 +0xF5A7 0x917E # 0 +0xF5A8 0x9172 # 0 +0xF5A9 0x9174 # 0 +0xF5AA 0x9179 # 0 +0xF5AB 0x918C # 0 +0xF5AC 0x9185 # 0 +0xF5AD 0x9190 # 0 +0xF5AE 0x918D # 0 +0xF5AF 0x9191 # 0 +0xF5B0 0x91A2 # 0 +0xF5B1 0x91A3 # 0 +0xF5B2 0x91AA # 0 +0xF5B3 0x91AD # 0 +0xF5B4 0x91AE # 0 +0xF5B5 0x91AF # 0 +0xF5B6 0x91B5 # 0 +0xF5B7 0x91B4 # 0 +0xF5B8 0x91BA # 0 +0xF5B9 0x8C55 # 0 +0xF5BA 0x9E7E # 0 +0xF5BB 0x8DB8 # 0 +0xF5BC 0x8DEB # 0 +0xF5BD 0x8E05 # 0 +0xF5BE 0x8E59 # 0 +0xF5BF 0x8E69 # 0 +0xF5C0 0x8DB5 # 0 +0xF5C1 0x8DBF # 0 +0xF5C2 0x8DBC # 0 +0xF5C3 0x8DBA # 0 +0xF5C4 0x8DC4 # 0 +0xF5C5 0x8DD6 # 0 +0xF5C6 0x8DD7 # 0 +0xF5C7 0x8DDA # 0 +0xF5C8 0x8DDE # 0 +0xF5C9 0x8DCE # 0 +0xF5CA 0x8DCF # 0 +0xF5CB 0x8DDB # 0 +0xF5CC 0x8DC6 # 0 +0xF5CD 0x8DEC # 0 +0xF5CE 0x8DF7 # 0 +0xF5CF 0x8DF8 # 0 +0xF5D0 0x8DE3 # 0 +0xF5D1 0x8DF9 # 0 +0xF5D2 0x8DFB # 0 +0xF5D3 0x8DE4 # 0 +0xF5D4 0x8E09 # 0 +0xF5D5 0x8DFD # 0 +0xF5D6 0x8E14 # 0 +0xF5D7 0x8E1D # 0 +0xF5D8 0x8E1F # 0 +0xF5D9 0x8E2C # 0 +0xF5DA 0x8E2E # 0 +0xF5DB 0x8E23 # 0 +0xF5DC 0x8E2F # 0 +0xF5DD 0x8E3A # 0 +0xF5DE 0x8E40 # 0 +0xF5DF 0x8E39 # 0 +0xF5E0 0x8E35 # 0 +0xF5E1 0x8E3D # 0 +0xF5E2 0x8E31 # 0 +0xF5E3 0x8E49 # 0 +0xF5E4 0x8E41 # 0 +0xF5E5 0x8E42 # 0 +0xF5E6 0x8E51 # 0 +0xF5E7 0x8E52 # 0 +0xF5E8 0x8E4A # 0 +0xF5E9 0x8E70 # 0 +0xF5EA 0x8E76 # 0 +0xF5EB 0x8E7C # 0 +0xF5EC 0x8E6F # 0 +0xF5ED 0x8E74 # 0 +0xF5EE 0x8E85 # 0 +0xF5EF 0x8E8F # 0 +0xF5F0 0x8E94 # 0 +0xF5F1 0x8E90 # 0 +0xF5F2 0x8E9C # 0 +0xF5F3 0x8E9E # 0 +0xF5F4 0x8C78 # 0 +0xF5F5 0x8C82 # 0 +0xF5F6 0x8C8A # 0 +0xF5F7 0x8C85 # 0 +0xF5F8 0x8C98 # 0 +0xF5F9 0x8C94 # 0 +0xF5FA 0x659B # 0 +0xF5FB 0x89D6 # 0 +0xF5FC 0x89DE # 0 +0xF5FD 0x89DA # 0 +0xF5FE 0x89DC # 0 +0xF640 0x9BDC # 0 +0xF641 0x9BDD # 0 +0xF642 0x9BDE # 0 +0xF643 0x9BDF # 0 +0xF644 0x9BE0 # 0 +0xF645 0x9BE1 # 0 +0xF646 0x9BE2 # 0 +0xF647 0x9BE3 # 0 +0xF648 0x9BE4 # 0 +0xF649 0x9BE5 # 0 +0xF64A 0x9BE6 # 0 +0xF64B 0x9BE7 # 0 +0xF64C 0x9BE8 # 0 +0xF64D 0x9BE9 # 0 +0xF64E 0x9BEA # 0 +0xF64F 0x9BEB # 0 +0xF650 0x9BEC # 0 +0xF651 0x9BED # 0 +0xF652 0x9BEE # 0 +0xF653 0x9BEF # 0 +0xF654 0x9BF0 # 0 +0xF655 0x9BF1 # 0 +0xF656 0x9BF2 # 0 +0xF657 0x9BF3 # 0 +0xF658 0x9BF4 # 0 +0xF659 0x9BF5 # 0 +0xF65A 0x9BF6 # 0 +0xF65B 0x9BF7 # 0 +0xF65C 0x9BF8 # 0 +0xF65D 0x9BF9 # 0 +0xF65E 0x9BFA # 0 +0xF65F 0x9BFB # 0 +0xF660 0x9BFC # 0 +0xF661 0x9BFD # 0 +0xF662 0x9BFE # 0 +0xF663 0x9BFF # 0 +0xF664 0x9C00 # 0 +0xF665 0x9C01 # 0 +0xF666 0x9C02 # 0 +0xF667 0x9C03 # 0 +0xF668 0x9C04 # 0 +0xF669 0x9C05 # 0 +0xF66A 0x9C06 # 0 +0xF66B 0x9C07 # 0 +0xF66C 0x9C08 # 0 +0xF66D 0x9C09 # 0 +0xF66E 0x9C0A # 0 +0xF66F 0x9C0B # 0 +0xF670 0x9C0C # 0 +0xF671 0x9C0D # 0 +0xF672 0x9C0E # 0 +0xF673 0x9C0F # 0 +0xF674 0x9C10 # 0 +0xF675 0x9C11 # 0 +0xF676 0x9C12 # 0 +0xF677 0x9C13 # 0 +0xF678 0x9C14 # 0 +0xF679 0x9C15 # 0 +0xF67A 0x9C16 # 0 +0xF67B 0x9C17 # 0 +0xF67C 0x9C18 # 0 +0xF67D 0x9C19 # 0 +0xF67E 0x9C1A # 0 +0xF680 0x9C1B # 0 +0xF681 0x9C1C # 0 +0xF682 0x9C1D # 0 +0xF683 0x9C1E # 0 +0xF684 0x9C1F # 0 +0xF685 0x9C20 # 0 +0xF686 0x9C21 # 0 +0xF687 0x9C22 # 0 +0xF688 0x9C23 # 0 +0xF689 0x9C24 # 0 +0xF68A 0x9C25 # 0 +0xF68B 0x9C26 # 0 +0xF68C 0x9C27 # 0 +0xF68D 0x9C28 # 0 +0xF68E 0x9C29 # 0 +0xF68F 0x9C2A # 0 +0xF690 0x9C2B # 0 +0xF691 0x9C2C # 0 +0xF692 0x9C2D # 0 +0xF693 0x9C2E # 0 +0xF694 0x9C2F # 0 +0xF695 0x9C30 # 0 +0xF696 0x9C31 # 0 +0xF697 0x9C32 # 0 +0xF698 0x9C33 # 0 +0xF699 0x9C34 # 0 +0xF69A 0x9C35 # 0 +0xF69B 0x9C36 # 0 +0xF69C 0x9C37 # 0 +0xF69D 0x9C38 # 0 +0xF69E 0x9C39 # 0 +0xF69F 0x9C3A # 0 +0xF6A0 0x9C3B # 0 +0xF6A1 0x89E5 # 0 +0xF6A2 0x89EB # 0 +0xF6A3 0x89EF # 0 +0xF6A4 0x8A3E # 0 +0xF6A5 0x8B26 # 0 +0xF6A6 0x9753 # 0 +0xF6A7 0x96E9 # 0 +0xF6A8 0x96F3 # 0 +0xF6A9 0x96EF # 0 +0xF6AA 0x9706 # 0 +0xF6AB 0x9701 # 0 +0xF6AC 0x9708 # 0 +0xF6AD 0x970F # 0 +0xF6AE 0x970E # 0 +0xF6AF 0x972A # 0 +0xF6B0 0x972D # 0 +0xF6B1 0x9730 # 0 +0xF6B2 0x973E # 0 +0xF6B3 0x9F80 # 0 +0xF6B4 0x9F83 # 0 +0xF6B5 0x9F85 # 0 +0xF6B6 0x9F86 # 0 +0xF6B7 0x9F87 # 0 +0xF6B8 0x9F88 # 0 +0xF6B9 0x9F89 # 0 +0xF6BA 0x9F8A # 0 +0xF6BB 0x9F8C # 0 +0xF6BC 0x9EFE # 0 +0xF6BD 0x9F0B # 0 +0xF6BE 0x9F0D # 0 +0xF6BF 0x96B9 # 0 +0xF6C0 0x96BC # 0 +0xF6C1 0x96BD # 0 +0xF6C2 0x96CE # 0 +0xF6C3 0x96D2 # 0 +0xF6C4 0x77BF # 0 +0xF6C5 0x96E0 # 0 +0xF6C6 0x928E # 0 +0xF6C7 0x92AE # 0 +0xF6C8 0x92C8 # 0 +0xF6C9 0x933E # 0 +0xF6CA 0x936A # 0 +0xF6CB 0x93CA # 0 +0xF6CC 0x938F # 0 +0xF6CD 0x943E # 0 +0xF6CE 0x946B # 0 +0xF6CF 0x9C7F # 0 +0xF6D0 0x9C82 # 0 +0xF6D1 0x9C85 # 0 +0xF6D2 0x9C86 # 0 +0xF6D3 0x9C87 # 0 +0xF6D4 0x9C88 # 0 +0xF6D5 0x7A23 # 0 +0xF6D6 0x9C8B # 0 +0xF6D7 0x9C8E # 0 +0xF6D8 0x9C90 # 0 +0xF6D9 0x9C91 # 0 +0xF6DA 0x9C92 # 0 +0xF6DB 0x9C94 # 0 +0xF6DC 0x9C95 # 0 +0xF6DD 0x9C9A # 0 +0xF6DE 0x9C9B # 0 +0xF6DF 0x9C9E # 0 +0xF6E0 0x9C9F # 0 +0xF6E1 0x9CA0 # 0 +0xF6E2 0x9CA1 # 0 +0xF6E3 0x9CA2 # 0 +0xF6E4 0x9CA3 # 0 +0xF6E5 0x9CA5 # 0 +0xF6E6 0x9CA6 # 0 +0xF6E7 0x9CA7 # 0 +0xF6E8 0x9CA8 # 0 +0xF6E9 0x9CA9 # 0 +0xF6EA 0x9CAB # 0 +0xF6EB 0x9CAD # 0 +0xF6EC 0x9CAE # 0 +0xF6ED 0x9CB0 # 0 +0xF6EE 0x9CB1 # 0 +0xF6EF 0x9CB2 # 0 +0xF6F0 0x9CB3 # 0 +0xF6F1 0x9CB4 # 0 +0xF6F2 0x9CB5 # 0 +0xF6F3 0x9CB6 # 0 +0xF6F4 0x9CB7 # 0 +0xF6F5 0x9CBA # 0 +0xF6F6 0x9CBB # 0 +0xF6F7 0x9CBC # 0 +0xF6F8 0x9CBD # 0 +0xF6F9 0x9CC4 # 0 +0xF6FA 0x9CC5 # 0 +0xF6FB 0x9CC6 # 0 +0xF6FC 0x9CC7 # 0 +0xF6FD 0x9CCA # 0 +0xF6FE 0x9CCB # 0 +0xF740 0x9C3C # 0 +0xF741 0x9C3D # 0 +0xF742 0x9C3E # 0 +0xF743 0x9C3F # 0 +0xF744 0x9C40 # 0 +0xF745 0x9C41 # 0 +0xF746 0x9C42 # 0 +0xF747 0x9C43 # 0 +0xF748 0x9C44 # 0 +0xF749 0x9C45 # 0 +0xF74A 0x9C46 # 0 +0xF74B 0x9C47 # 0 +0xF74C 0x9C48 # 0 +0xF74D 0x9C49 # 0 +0xF74E 0x9C4A # 0 +0xF74F 0x9C4B # 0 +0xF750 0x9C4C # 0 +0xF751 0x9C4D # 0 +0xF752 0x9C4E # 0 +0xF753 0x9C4F # 0 +0xF754 0x9C50 # 0 +0xF755 0x9C51 # 0 +0xF756 0x9C52 # 0 +0xF757 0x9C53 # 0 +0xF758 0x9C54 # 0 +0xF759 0x9C55 # 0 +0xF75A 0x9C56 # 0 +0xF75B 0x9C57 # 0 +0xF75C 0x9C58 # 0 +0xF75D 0x9C59 # 0 +0xF75E 0x9C5A # 0 +0xF75F 0x9C5B # 0 +0xF760 0x9C5C # 0 +0xF761 0x9C5D # 0 +0xF762 0x9C5E # 0 +0xF763 0x9C5F # 0 +0xF764 0x9C60 # 0 +0xF765 0x9C61 # 0 +0xF766 0x9C62 # 0 +0xF767 0x9C63 # 0 +0xF768 0x9C64 # 0 +0xF769 0x9C65 # 0 +0xF76A 0x9C66 # 0 +0xF76B 0x9C67 # 0 +0xF76C 0x9C68 # 0 +0xF76D 0x9C69 # 0 +0xF76E 0x9C6A # 0 +0xF76F 0x9C6B # 0 +0xF770 0x9C6C # 0 +0xF771 0x9C6D # 0 +0xF772 0x9C6E # 0 +0xF773 0x9C6F # 0 +0xF774 0x9C70 # 0 +0xF775 0x9C71 # 0 +0xF776 0x9C72 # 0 +0xF777 0x9C73 # 0 +0xF778 0x9C74 # 0 +0xF779 0x9C75 # 0 +0xF77A 0x9C76 # 0 +0xF77B 0x9C77 # 0 +0xF77C 0x9C78 # 0 +0xF77D 0x9C79 # 0 +0xF77E 0x9C7A # 0 +0xF780 0x9C7B # 0 +0xF781 0x9C7D # 0 +0xF782 0x9C7E # 0 +0xF783 0x9C80 # 0 +0xF784 0x9C83 # 0 +0xF785 0x9C84 # 0 +0xF786 0x9C89 # 0 +0xF787 0x9C8A # 0 +0xF788 0x9C8C # 0 +0xF789 0x9C8F # 0 +0xF78A 0x9C93 # 0 +0xF78B 0x9C96 # 0 +0xF78C 0x9C97 # 0 +0xF78D 0x9C98 # 0 +0xF78E 0x9C99 # 0 +0xF78F 0x9C9D # 0 +0xF790 0x9CAA # 0 +0xF791 0x9CAC # 0 +0xF792 0x9CAF # 0 +0xF793 0x9CB9 # 0 +0xF794 0x9CBE # 0 +0xF795 0x9CBF # 0 +0xF796 0x9CC0 # 0 +0xF797 0x9CC1 # 0 +0xF798 0x9CC2 # 0 +0xF799 0x9CC8 # 0 +0xF79A 0x9CC9 # 0 +0xF79B 0x9CD1 # 0 +0xF79C 0x9CD2 # 0 +0xF79D 0x9CDA # 0 +0xF79E 0x9CDB # 0 +0xF79F 0x9CE0 # 0 +0xF7A0 0x9CE1 # 0 +0xF7A1 0x9CCC # 0 +0xF7A2 0x9CCD # 0 +0xF7A3 0x9CCE # 0 +0xF7A4 0x9CCF # 0 +0xF7A5 0x9CD0 # 0 +0xF7A6 0x9CD3 # 0 +0xF7A7 0x9CD4 # 0 +0xF7A8 0x9CD5 # 0 +0xF7A9 0x9CD7 # 0 +0xF7AA 0x9CD8 # 0 +0xF7AB 0x9CD9 # 0 +0xF7AC 0x9CDC # 0 +0xF7AD 0x9CDD # 0 +0xF7AE 0x9CDF # 0 +0xF7AF 0x9CE2 # 0 +0xF7B0 0x977C # 0 +0xF7B1 0x9785 # 0 +0xF7B2 0x9791 # 0 +0xF7B3 0x9792 # 0 +0xF7B4 0x9794 # 0 +0xF7B5 0x97AF # 0 +0xF7B6 0x97AB # 0 +0xF7B7 0x97A3 # 0 +0xF7B8 0x97B2 # 0 +0xF7B9 0x97B4 # 0 +0xF7BA 0x9AB1 # 0 +0xF7BB 0x9AB0 # 0 +0xF7BC 0x9AB7 # 0 +0xF7BD 0x9E58 # 0 +0xF7BE 0x9AB6 # 0 +0xF7BF 0x9ABA # 0 +0xF7C0 0x9ABC # 0 +0xF7C1 0x9AC1 # 0 +0xF7C2 0x9AC0 # 0 +0xF7C3 0x9AC5 # 0 +0xF7C4 0x9AC2 # 0 +0xF7C5 0x9ACB # 0 +0xF7C6 0x9ACC # 0 +0xF7C7 0x9AD1 # 0 +0xF7C8 0x9B45 # 0 +0xF7C9 0x9B43 # 0 +0xF7CA 0x9B47 # 0 +0xF7CB 0x9B49 # 0 +0xF7CC 0x9B48 # 0 +0xF7CD 0x9B4D # 0 +0xF7CE 0x9B51 # 0 +0xF7CF 0x98E8 # 0 +0xF7D0 0x990D # 0 +0xF7D1 0x992E # 0 +0xF7D2 0x9955 # 0 +0xF7D3 0x9954 # 0 +0xF7D4 0x9ADF # 0 +0xF7D5 0x9AE1 # 0 +0xF7D6 0x9AE6 # 0 +0xF7D7 0x9AEF # 0 +0xF7D8 0x9AEB # 0 +0xF7D9 0x9AFB # 0 +0xF7DA 0x9AED # 0 +0xF7DB 0x9AF9 # 0 +0xF7DC 0x9B08 # 0 +0xF7DD 0x9B0F # 0 +0xF7DE 0x9B13 # 0 +0xF7DF 0x9B1F # 0 +0xF7E0 0x9B23 # 0 +0xF7E1 0x9EBD # 0 +0xF7E2 0x9EBE # 0 +0xF7E3 0x7E3B # 0 +0xF7E4 0x9E82 # 0 +0xF7E5 0x9E87 # 0 +0xF7E6 0x9E88 # 0 +0xF7E7 0x9E8B # 0 +0xF7E8 0x9E92 # 0 +0xF7E9 0x93D6 # 0 +0xF7EA 0x9E9D # 0 +0xF7EB 0x9E9F # 0 +0xF7EC 0x9EDB # 0 +0xF7ED 0x9EDC # 0 +0xF7EE 0x9EDD # 0 +0xF7EF 0x9EE0 # 0 +0xF7F0 0x9EDF # 0 +0xF7F1 0x9EE2 # 0 +0xF7F2 0x9EE9 # 0 +0xF7F3 0x9EE7 # 0 +0xF7F4 0x9EE5 # 0 +0xF7F5 0x9EEA # 0 +0xF7F6 0x9EEF # 0 +0xF7F7 0x9F22 # 0 +0xF7F8 0x9F2C # 0 +0xF7F9 0x9F2F # 0 +0xF7FA 0x9F39 # 0 +0xF7FB 0x9F37 # 0 +0xF7FC 0x9F3D # 0 +0xF7FD 0x9F3E # 0 +0xF7FE 0x9F44 # 0 +0xF840 0x9CE3 # 0 +0xF841 0x9CE4 # 0 +0xF842 0x9CE5 # 0 +0xF843 0x9CE6 # 0 +0xF844 0x9CE7 # 0 +0xF845 0x9CE8 # 0 +0xF846 0x9CE9 # 0 +0xF847 0x9CEA # 0 +0xF848 0x9CEB # 0 +0xF849 0x9CEC # 0 +0xF84A 0x9CED # 0 +0xF84B 0x9CEE # 0 +0xF84C 0x9CEF # 0 +0xF84D 0x9CF0 # 0 +0xF84E 0x9CF1 # 0 +0xF84F 0x9CF2 # 0 +0xF850 0x9CF3 # 0 +0xF851 0x9CF4 # 0 +0xF852 0x9CF5 # 0 +0xF853 0x9CF6 # 0 +0xF854 0x9CF7 # 0 +0xF855 0x9CF8 # 0 +0xF856 0x9CF9 # 0 +0xF857 0x9CFA # 0 +0xF858 0x9CFB # 0 +0xF859 0x9CFC # 0 +0xF85A 0x9CFD # 0 +0xF85B 0x9CFE # 0 +0xF85C 0x9CFF # 0 +0xF85D 0x9D00 # 0 +0xF85E 0x9D01 # 0 +0xF85F 0x9D02 # 0 +0xF860 0x9D03 # 0 +0xF861 0x9D04 # 0 +0xF862 0x9D05 # 0 +0xF863 0x9D06 # 0 +0xF864 0x9D07 # 0 +0xF865 0x9D08 # 0 +0xF866 0x9D09 # 0 +0xF867 0x9D0A # 0 +0xF868 0x9D0B # 0 +0xF869 0x9D0C # 0 +0xF86A 0x9D0D # 0 +0xF86B 0x9D0E # 0 +0xF86C 0x9D0F # 0 +0xF86D 0x9D10 # 0 +0xF86E 0x9D11 # 0 +0xF86F 0x9D12 # 0 +0xF870 0x9D13 # 0 +0xF871 0x9D14 # 0 +0xF872 0x9D15 # 0 +0xF873 0x9D16 # 0 +0xF874 0x9D17 # 0 +0xF875 0x9D18 # 0 +0xF876 0x9D19 # 0 +0xF877 0x9D1A # 0 +0xF878 0x9D1B # 0 +0xF879 0x9D1C # 0 +0xF87A 0x9D1D # 0 +0xF87B 0x9D1E # 0 +0xF87C 0x9D1F # 0 +0xF87D 0x9D20 # 0 +0xF87E 0x9D21 # 0 +0xF880 0x9D22 # 0 +0xF881 0x9D23 # 0 +0xF882 0x9D24 # 0 +0xF883 0x9D25 # 0 +0xF884 0x9D26 # 0 +0xF885 0x9D27 # 0 +0xF886 0x9D28 # 0 +0xF887 0x9D29 # 0 +0xF888 0x9D2A # 0 +0xF889 0x9D2B # 0 +0xF88A 0x9D2C # 0 +0xF88B 0x9D2D # 0 +0xF88C 0x9D2E # 0 +0xF88D 0x9D2F # 0 +0xF88E 0x9D30 # 0 +0xF88F 0x9D31 # 0 +0xF890 0x9D32 # 0 +0xF891 0x9D33 # 0 +0xF892 0x9D34 # 0 +0xF893 0x9D35 # 0 +0xF894 0x9D36 # 0 +0xF895 0x9D37 # 0 +0xF896 0x9D38 # 0 +0xF897 0x9D39 # 0 +0xF898 0x9D3A # 0 +0xF899 0x9D3B # 0 +0xF89A 0x9D3C # 0 +0xF89B 0x9D3D # 0 +0xF89C 0x9D3E # 0 +0xF89D 0x9D3F # 0 +0xF89E 0x9D40 # 0 +0xF89F 0x9D41 # 0 +0xF8A0 0x9D42 # 0 +0xF8A1 0xE234 # 0 +0xF8A2 0xE235 # 0 +0xF8A3 0xE236 # 0 +0xF8A4 0xE237 # 0 +0xF8A5 0xE238 # 0 +0xF8A6 0xE239 # 0 +0xF8A7 0xE23A # 0 +0xF8A8 0xE23B # 0 +0xF8A9 0xE23C # 0 +0xF8AA 0xE23D # 0 +0xF8AB 0xE23E # 0 +0xF8AC 0xE23F # 0 +0xF8AD 0xE240 # 0 +0xF8AE 0xE241 # 0 +0xF8AF 0xE242 # 0 +0xF8B0 0xE243 # 0 +0xF8B1 0xE244 # 0 +0xF8B2 0xE245 # 0 +0xF8B3 0xE246 # 0 +0xF8B4 0xE247 # 0 +0xF8B5 0xE248 # 0 +0xF8B6 0xE249 # 0 +0xF8B7 0xE24A # 0 +0xF8B8 0xE24B # 0 +0xF8B9 0xE24C # 0 +0xF8BA 0xE24D # 0 +0xF8BB 0xE24E # 0 +0xF8BC 0xE24F # 0 +0xF8BD 0xE250 # 0 +0xF8BE 0xE251 # 0 +0xF8BF 0xE252 # 0 +0xF8C0 0xE253 # 0 +0xF8C1 0xE254 # 0 +0xF8C2 0xE255 # 0 +0xF8C3 0xE256 # 0 +0xF8C4 0xE257 # 0 +0xF8C5 0xE258 # 0 +0xF8C6 0xE259 # 0 +0xF8C7 0xE25A # 0 +0xF8C8 0xE25B # 0 +0xF8C9 0xE25C # 0 +0xF8CA 0xE25D # 0 +0xF8CB 0xE25E # 0 +0xF8CC 0xE25F # 0 +0xF8CD 0xE260 # 0 +0xF8CE 0xE261 # 0 +0xF8CF 0xE262 # 0 +0xF8D0 0xE263 # 0 +0xF8D1 0xE264 # 0 +0xF8D2 0xE265 # 0 +0xF8D3 0xE266 # 0 +0xF8D4 0xE267 # 0 +0xF8D5 0xE268 # 0 +0xF8D6 0xE269 # 0 +0xF8D7 0xE26A # 0 +0xF8D8 0xE26B # 0 +0xF8D9 0xE26C # 0 +0xF8DA 0xE26D # 0 +0xF8DB 0xE26E # 0 +0xF8DC 0xE26F # 0 +0xF8DD 0xE270 # 0 +0xF8DE 0xE271 # 0 +0xF8DF 0xE272 # 0 +0xF8E0 0xE273 # 0 +0xF8E1 0xE274 # 0 +0xF8E2 0xE275 # 0 +0xF8E3 0xE276 # 0 +0xF8E4 0xE277 # 0 +0xF8E5 0xE278 # 0 +0xF8E6 0xE279 # 0 +0xF8E7 0xE27A # 0 +0xF8E8 0xE27B # 0 +0xF8E9 0xE27C # 0 +0xF8EA 0xE27D # 0 +0xF8EB 0xE27E # 0 +0xF8EC 0xE27F # 0 +0xF8ED 0xE280 # 0 +0xF8EE 0xE281 # 0 +0xF8EF 0xE282 # 0 +0xF8F0 0xE283 # 0 +0xF8F1 0xE284 # 0 +0xF8F2 0xE285 # 0 +0xF8F3 0xE286 # 0 +0xF8F4 0xE287 # 0 +0xF8F5 0xE288 # 0 +0xF8F6 0xE289 # 0 +0xF8F7 0xE28A # 0 +0xF8F8 0xE28B # 0 +0xF8F9 0xE28C # 0 +0xF8FA 0xE28D # 0 +0xF8FB 0xE28E # 0 +0xF8FC 0xE28F # 0 +0xF8FD 0xE290 # 0 +0xF8FE 0xE291 # 0 +0xF940 0x9D43 # 0 +0xF941 0x9D44 # 0 +0xF942 0x9D45 # 0 +0xF943 0x9D46 # 0 +0xF944 0x9D47 # 0 +0xF945 0x9D48 # 0 +0xF946 0x9D49 # 0 +0xF947 0x9D4A # 0 +0xF948 0x9D4B # 0 +0xF949 0x9D4C # 0 +0xF94A 0x9D4D # 0 +0xF94B 0x9D4E # 0 +0xF94C 0x9D4F # 0 +0xF94D 0x9D50 # 0 +0xF94E 0x9D51 # 0 +0xF94F 0x9D52 # 0 +0xF950 0x9D53 # 0 +0xF951 0x9D54 # 0 +0xF952 0x9D55 # 0 +0xF953 0x9D56 # 0 +0xF954 0x9D57 # 0 +0xF955 0x9D58 # 0 +0xF956 0x9D59 # 0 +0xF957 0x9D5A # 0 +0xF958 0x9D5B # 0 +0xF959 0x9D5C # 0 +0xF95A 0x9D5D # 0 +0xF95B 0x9D5E # 0 +0xF95C 0x9D5F # 0 +0xF95D 0x9D60 # 0 +0xF95E 0x9D61 # 0 +0xF95F 0x9D62 # 0 +0xF960 0x9D63 # 0 +0xF961 0x9D64 # 0 +0xF962 0x9D65 # 0 +0xF963 0x9D66 # 0 +0xF964 0x9D67 # 0 +0xF965 0x9D68 # 0 +0xF966 0x9D69 # 0 +0xF967 0x9D6A # 0 +0xF968 0x9D6B # 0 +0xF969 0x9D6C # 0 +0xF96A 0x9D6D # 0 +0xF96B 0x9D6E # 0 +0xF96C 0x9D6F # 0 +0xF96D 0x9D70 # 0 +0xF96E 0x9D71 # 0 +0xF96F 0x9D72 # 0 +0xF970 0x9D73 # 0 +0xF971 0x9D74 # 0 +0xF972 0x9D75 # 0 +0xF973 0x9D76 # 0 +0xF974 0x9D77 # 0 +0xF975 0x9D78 # 0 +0xF976 0x9D79 # 0 +0xF977 0x9D7A # 0 +0xF978 0x9D7B # 0 +0xF979 0x9D7C # 0 +0xF97A 0x9D7D # 0 +0xF97B 0x9D7E # 0 +0xF97C 0x9D7F # 0 +0xF97D 0x9D80 # 0 +0xF97E 0x9D81 # 0 +0xF980 0x9D82 # 0 +0xF981 0x9D83 # 0 +0xF982 0x9D84 # 0 +0xF983 0x9D85 # 0 +0xF984 0x9D86 # 0 +0xF985 0x9D87 # 0 +0xF986 0x9D88 # 0 +0xF987 0x9D89 # 0 +0xF988 0x9D8A # 0 +0xF989 0x9D8B # 0 +0xF98A 0x9D8C # 0 +0xF98B 0x9D8D # 0 +0xF98C 0x9D8E # 0 +0xF98D 0x9D8F # 0 +0xF98E 0x9D90 # 0 +0xF98F 0x9D91 # 0 +0xF990 0x9D92 # 0 +0xF991 0x9D93 # 0 +0xF992 0x9D94 # 0 +0xF993 0x9D95 # 0 +0xF994 0x9D96 # 0 +0xF995 0x9D97 # 0 +0xF996 0x9D98 # 0 +0xF997 0x9D99 # 0 +0xF998 0x9D9A # 0 +0xF999 0x9D9B # 0 +0xF99A 0x9D9C # 0 +0xF99B 0x9D9D # 0 +0xF99C 0x9D9E # 0 +0xF99D 0x9D9F # 0 +0xF99E 0x9DA0 # 0 +0xF99F 0x9DA1 # 0 +0xF9A0 0x9DA2 # 0 +0xF9A1 0xE292 # 0 +0xF9A2 0xE293 # 0 +0xF9A3 0xE294 # 0 +0xF9A4 0xE295 # 0 +0xF9A5 0xE296 # 0 +0xF9A6 0xE297 # 0 +0xF9A7 0xE298 # 0 +0xF9A8 0xE299 # 0 +0xF9A9 0xE29A # 0 +0xF9AA 0xE29B # 0 +0xF9AB 0xE29C # 0 +0xF9AC 0xE29D # 0 +0xF9AD 0xE29E # 0 +0xF9AE 0xE29F # 0 +0xF9AF 0xE2A0 # 0 +0xF9B0 0xE2A1 # 0 +0xF9B1 0xE2A2 # 0 +0xF9B2 0xE2A3 # 0 +0xF9B3 0xE2A4 # 0 +0xF9B4 0xE2A5 # 0 +0xF9B5 0xE2A6 # 0 +0xF9B6 0xE2A7 # 0 +0xF9B7 0xE2A8 # 0 +0xF9B8 0xE2A9 # 0 +0xF9B9 0xE2AA # 0 +0xF9BA 0xE2AB # 0 +0xF9BB 0xE2AC # 0 +0xF9BC 0xE2AD # 0 +0xF9BD 0xE2AE # 0 +0xF9BE 0xE2AF # 0 +0xF9BF 0xE2B0 # 0 +0xF9C0 0xE2B1 # 0 +0xF9C1 0xE2B2 # 0 +0xF9C2 0xE2B3 # 0 +0xF9C3 0xE2B4 # 0 +0xF9C4 0xE2B5 # 0 +0xF9C5 0xE2B6 # 0 +0xF9C6 0xE2B7 # 0 +0xF9C7 0xE2B8 # 0 +0xF9C8 0xE2B9 # 0 +0xF9C9 0xE2BA # 0 +0xF9CA 0xE2BB # 0 +0xF9CB 0xE2BC # 0 +0xF9CC 0xE2BD # 0 +0xF9CD 0xE2BE # 0 +0xF9CE 0xE2BF # 0 +0xF9CF 0xE2C0 # 0 +0xF9D0 0xE2C1 # 0 +0xF9D1 0xE2C2 # 0 +0xF9D2 0xE2C3 # 0 +0xF9D3 0xE2C4 # 0 +0xF9D4 0xE2C5 # 0 +0xF9D5 0xE2C6 # 0 +0xF9D6 0xE2C7 # 0 +0xF9D7 0xE2C8 # 0 +0xF9D8 0xE2C9 # 0 +0xF9D9 0xE2CA # 0 +0xF9DA 0xE2CB # 0 +0xF9DB 0xE2CC # 0 +0xF9DC 0xE2CD # 0 +0xF9DD 0xE2CE # 0 +0xF9DE 0xE2CF # 0 +0xF9DF 0xE2D0 # 0 +0xF9E0 0xE2D1 # 0 +0xF9E1 0xE2D2 # 0 +0xF9E2 0xE2D3 # 0 +0xF9E3 0xE2D4 # 0 +0xF9E4 0xE2D5 # 0 +0xF9E5 0xE2D6 # 0 +0xF9E6 0xE2D7 # 0 +0xF9E7 0xE2D8 # 0 +0xF9E8 0xE2D9 # 0 +0xF9E9 0xE2DA # 0 +0xF9EA 0xE2DB # 0 +0xF9EB 0xE2DC # 0 +0xF9EC 0xE2DD # 0 +0xF9ED 0xE2DE # 0 +0xF9EE 0xE2DF # 0 +0xF9EF 0xE2E0 # 0 +0xF9F0 0xE2E1 # 0 +0xF9F1 0xE2E2 # 0 +0xF9F2 0xE2E3 # 0 +0xF9F3 0xE2E4 # 0 +0xF9F4 0xE2E5 # 0 +0xF9F5 0xE2E6 # 0 +0xF9F6 0xE2E7 # 0 +0xF9F7 0xE2E8 # 0 +0xF9F8 0xE2E9 # 0 +0xF9F9 0xE2EA # 0 +0xF9FA 0xE2EB # 0 +0xF9FB 0xE2EC # 0 +0xF9FC 0xE2ED # 0 +0xF9FD 0xE2EE # 0 +0xF9FE 0xE2EF # 0 +0xFA40 0x9DA3 # 0 +0xFA41 0x9DA4 # 0 +0xFA42 0x9DA5 # 0 +0xFA43 0x9DA6 # 0 +0xFA44 0x9DA7 # 0 +0xFA45 0x9DA8 # 0 +0xFA46 0x9DA9 # 0 +0xFA47 0x9DAA # 0 +0xFA48 0x9DAB # 0 +0xFA49 0x9DAC # 0 +0xFA4A 0x9DAD # 0 +0xFA4B 0x9DAE # 0 +0xFA4C 0x9DAF # 0 +0xFA4D 0x9DB0 # 0 +0xFA4E 0x9DB1 # 0 +0xFA4F 0x9DB2 # 0 +0xFA50 0x9DB3 # 0 +0xFA51 0x9DB4 # 0 +0xFA52 0x9DB5 # 0 +0xFA53 0x9DB6 # 0 +0xFA54 0x9DB7 # 0 +0xFA55 0x9DB8 # 0 +0xFA56 0x9DB9 # 0 +0xFA57 0x9DBA # 0 +0xFA58 0x9DBB # 0 +0xFA59 0x9DBC # 0 +0xFA5A 0x9DBD # 0 +0xFA5B 0x9DBE # 0 +0xFA5C 0x9DBF # 0 +0xFA5D 0x9DC0 # 0 +0xFA5E 0x9DC1 # 0 +0xFA5F 0x9DC2 # 0 +0xFA60 0x9DC3 # 0 +0xFA61 0x9DC4 # 0 +0xFA62 0x9DC5 # 0 +0xFA63 0x9DC6 # 0 +0xFA64 0x9DC7 # 0 +0xFA65 0x9DC8 # 0 +0xFA66 0x9DC9 # 0 +0xFA67 0x9DCA # 0 +0xFA68 0x9DCB # 0 +0xFA69 0x9DCC # 0 +0xFA6A 0x9DCD # 0 +0xFA6B 0x9DCE # 0 +0xFA6C 0x9DCF # 0 +0xFA6D 0x9DD0 # 0 +0xFA6E 0x9DD1 # 0 +0xFA6F 0x9DD2 # 0 +0xFA70 0x9DD3 # 0 +0xFA71 0x9DD4 # 0 +0xFA72 0x9DD5 # 0 +0xFA73 0x9DD6 # 0 +0xFA74 0x9DD7 # 0 +0xFA75 0x9DD8 # 0 +0xFA76 0x9DD9 # 0 +0xFA77 0x9DDA # 0 +0xFA78 0x9DDB # 0 +0xFA79 0x9DDC # 0 +0xFA7A 0x9DDD # 0 +0xFA7B 0x9DDE # 0 +0xFA7C 0x9DDF # 0 +0xFA7D 0x9DE0 # 0 +0xFA7E 0x9DE1 # 0 +0xFA80 0x9DE2 # 0 +0xFA81 0x9DE3 # 0 +0xFA82 0x9DE4 # 0 +0xFA83 0x9DE5 # 0 +0xFA84 0x9DE6 # 0 +0xFA85 0x9DE7 # 0 +0xFA86 0x9DE8 # 0 +0xFA87 0x9DE9 # 0 +0xFA88 0x9DEA # 0 +0xFA89 0x9DEB # 0 +0xFA8A 0x9DEC # 0 +0xFA8B 0x9DED # 0 +0xFA8C 0x9DEE # 0 +0xFA8D 0x9DEF # 0 +0xFA8E 0x9DF0 # 0 +0xFA8F 0x9DF1 # 0 +0xFA90 0x9DF2 # 0 +0xFA91 0x9DF3 # 0 +0xFA92 0x9DF4 # 0 +0xFA93 0x9DF5 # 0 +0xFA94 0x9DF6 # 0 +0xFA95 0x9DF7 # 0 +0xFA96 0x9DF8 # 0 +0xFA97 0x9DF9 # 0 +0xFA98 0x9DFA # 0 +0xFA99 0x9DFB # 0 +0xFA9A 0x9DFC # 0 +0xFA9B 0x9DFD # 0 +0xFA9C 0x9DFE # 0 +0xFA9D 0x9DFF # 0 +0xFA9E 0x9E00 # 0 +0xFA9F 0x9E01 # 0 +0xFAA0 0x9E02 # 0 +0xFAA1 0xE2F0 # 0 +0xFAA2 0xE2F1 # 0 +0xFAA3 0xE2F2 # 0 +0xFAA4 0xE2F3 # 0 +0xFAA5 0xE2F4 # 0 +0xFAA6 0xE2F5 # 0 +0xFAA7 0xE2F6 # 0 +0xFAA8 0xE2F7 # 0 +0xFAA9 0xE2F8 # 0 +0xFAAA 0xE2F9 # 0 +0xFAAB 0xE2FA # 0 +0xFAAC 0xE2FB # 0 +0xFAAD 0xE2FC # 0 +0xFAAE 0xE2FD # 0 +0xFAAF 0xE2FE # 0 +0xFAB0 0xE2FF # 0 +0xFAB1 0xE300 # 0 +0xFAB2 0xE301 # 0 +0xFAB3 0xE302 # 0 +0xFAB4 0xE303 # 0 +0xFAB5 0xE304 # 0 +0xFAB6 0xE305 # 0 +0xFAB7 0xE306 # 0 +0xFAB8 0xE307 # 0 +0xFAB9 0xE308 # 0 +0xFABA 0xE309 # 0 +0xFABB 0xE30A # 0 +0xFABC 0xE30B # 0 +0xFABD 0xE30C # 0 +0xFABE 0xE30D # 0 +0xFABF 0xE30E # 0 +0xFAC0 0xE30F # 0 +0xFAC1 0xE310 # 0 +0xFAC2 0xE311 # 0 +0xFAC3 0xE312 # 0 +0xFAC4 0xE313 # 0 +0xFAC5 0xE314 # 0 +0xFAC6 0xE315 # 0 +0xFAC7 0xE316 # 0 +0xFAC8 0xE317 # 0 +0xFAC9 0xE318 # 0 +0xFACA 0xE319 # 0 +0xFACB 0xE31A # 0 +0xFACC 0xE31B # 0 +0xFACD 0xE31C # 0 +0xFACE 0xE31D # 0 +0xFACF 0xE31E # 0 +0xFAD0 0xE31F # 0 +0xFAD1 0xE320 # 0 +0xFAD2 0xE321 # 0 +0xFAD3 0xE322 # 0 +0xFAD4 0xE323 # 0 +0xFAD5 0xE324 # 0 +0xFAD6 0xE325 # 0 +0xFAD7 0xE326 # 0 +0xFAD8 0xE327 # 0 +0xFAD9 0xE328 # 0 +0xFADA 0xE329 # 0 +0xFADB 0xE32A # 0 +0xFADC 0xE32B # 0 +0xFADD 0xE32C # 0 +0xFADE 0xE32D # 0 +0xFADF 0xE32E # 0 +0xFAE0 0xE32F # 0 +0xFAE1 0xE330 # 0 +0xFAE2 0xE331 # 0 +0xFAE3 0xE332 # 0 +0xFAE4 0xE333 # 0 +0xFAE5 0xE334 # 0 +0xFAE6 0xE335 # 0 +0xFAE7 0xE336 # 0 +0xFAE8 0xE337 # 0 +0xFAE9 0xE338 # 0 +0xFAEA 0xE339 # 0 +0xFAEB 0xE33A # 0 +0xFAEC 0xE33B # 0 +0xFAED 0xE33C # 0 +0xFAEE 0xE33D # 0 +0xFAEF 0xE33E # 0 +0xFAF0 0xE33F # 0 +0xFAF1 0xE340 # 0 +0xFAF2 0xE341 # 0 +0xFAF3 0xE342 # 0 +0xFAF4 0xE343 # 0 +0xFAF5 0xE344 # 0 +0xFAF6 0xE345 # 0 +0xFAF7 0xE346 # 0 +0xFAF8 0xE347 # 0 +0xFAF9 0xE348 # 0 +0xFAFA 0xE349 # 0 +0xFAFB 0xE34A # 0 +0xFAFC 0xE34B # 0 +0xFAFD 0xE34C # 0 +0xFAFE 0xE34D # 0 +0xFB40 0x9E03 # 0 +0xFB41 0x9E04 # 0 +0xFB42 0x9E05 # 0 +0xFB43 0x9E06 # 0 +0xFB44 0x9E07 # 0 +0xFB45 0x9E08 # 0 +0xFB46 0x9E09 # 0 +0xFB47 0x9E0A # 0 +0xFB48 0x9E0B # 0 +0xFB49 0x9E0C # 0 +0xFB4A 0x9E0D # 0 +0xFB4B 0x9E0E # 0 +0xFB4C 0x9E0F # 0 +0xFB4D 0x9E10 # 0 +0xFB4E 0x9E11 # 0 +0xFB4F 0x9E12 # 0 +0xFB50 0x9E13 # 0 +0xFB51 0x9E14 # 0 +0xFB52 0x9E15 # 0 +0xFB53 0x9E16 # 0 +0xFB54 0x9E17 # 0 +0xFB55 0x9E18 # 0 +0xFB56 0x9E19 # 0 +0xFB57 0x9E1A # 0 +0xFB58 0x9E1B # 0 +0xFB59 0x9E1C # 0 +0xFB5A 0x9E1D # 0 +0xFB5B 0x9E1E # 0 +0xFB5C 0x9E24 # 0 +0xFB5D 0x9E27 # 0 +0xFB5E 0x9E2E # 0 +0xFB5F 0x9E30 # 0 +0xFB60 0x9E34 # 0 +0xFB61 0x9E3B # 0 +0xFB62 0x9E3C # 0 +0xFB63 0x9E40 # 0 +0xFB64 0x9E4D # 0 +0xFB65 0x9E50 # 0 +0xFB66 0x9E52 # 0 +0xFB67 0x9E53 # 0 +0xFB68 0x9E54 # 0 +0xFB69 0x9E56 # 0 +0xFB6A 0x9E59 # 0 +0xFB6B 0x9E5D # 0 +0xFB6C 0x9E5F # 0 +0xFB6D 0x9E60 # 0 +0xFB6E 0x9E61 # 0 +0xFB6F 0x9E62 # 0 +0xFB70 0x9E65 # 0 +0xFB71 0x9E6E # 0 +0xFB72 0x9E6F # 0 +0xFB73 0x9E72 # 0 +0xFB74 0x9E74 # 0 +0xFB75 0x9E75 # 0 +0xFB76 0x9E76 # 0 +0xFB77 0x9E77 # 0 +0xFB78 0x9E78 # 0 +0xFB79 0x9E79 # 0 +0xFB7A 0x9E7A # 0 +0xFB7B 0x9E7B # 0 +0xFB7C 0x9E7C # 0 +0xFB7D 0x9E7D # 0 +0xFB7E 0x9E80 # 0 +0xFB80 0x9E81 # 0 +0xFB81 0x9E83 # 0 +0xFB82 0x9E84 # 0 +0xFB83 0x9E85 # 0 +0xFB84 0x9E86 # 0 +0xFB85 0x9E89 # 0 +0xFB86 0x9E8A # 0 +0xFB87 0x9E8C # 0 +0xFB88 0x9E8D # 0 +0xFB89 0x9E8E # 0 +0xFB8A 0x9E8F # 0 +0xFB8B 0x9E90 # 0 +0xFB8C 0x9E91 # 0 +0xFB8D 0x9E94 # 0 +0xFB8E 0x9E95 # 0 +0xFB8F 0x9E96 # 0 +0xFB90 0x9E97 # 0 +0xFB91 0x9E98 # 0 +0xFB92 0x9E99 # 0 +0xFB93 0x9E9A # 0 +0xFB94 0x9E9B # 0 +0xFB95 0x9E9C # 0 +0xFB96 0x9E9E # 0 +0xFB97 0x9EA0 # 0 +0xFB98 0x9EA1 # 0 +0xFB99 0x9EA2 # 0 +0xFB9A 0x9EA3 # 0 +0xFB9B 0x9EA4 # 0 +0xFB9C 0x9EA5 # 0 +0xFB9D 0x9EA7 # 0 +0xFB9E 0x9EA8 # 0 +0xFB9F 0x9EA9 # 0 +0xFBA0 0x9EAA # 0 +0xFBA1 0xE34E # 0 +0xFBA2 0xE34F # 0 +0xFBA3 0xE350 # 0 +0xFBA4 0xE351 # 0 +0xFBA5 0xE352 # 0 +0xFBA6 0xE353 # 0 +0xFBA7 0xE354 # 0 +0xFBA8 0xE355 # 0 +0xFBA9 0xE356 # 0 +0xFBAA 0xE357 # 0 +0xFBAB 0xE358 # 0 +0xFBAC 0xE359 # 0 +0xFBAD 0xE35A # 0 +0xFBAE 0xE35B # 0 +0xFBAF 0xE35C # 0 +0xFBB0 0xE35D # 0 +0xFBB1 0xE35E # 0 +0xFBB2 0xE35F # 0 +0xFBB3 0xE360 # 0 +0xFBB4 0xE361 # 0 +0xFBB5 0xE362 # 0 +0xFBB6 0xE363 # 0 +0xFBB7 0xE364 # 0 +0xFBB8 0xE365 # 0 +0xFBB9 0xE366 # 0 +0xFBBA 0xE367 # 0 +0xFBBB 0xE368 # 0 +0xFBBC 0xE369 # 0 +0xFBBD 0xE36A # 0 +0xFBBE 0xE36B # 0 +0xFBBF 0xE36C # 0 +0xFBC0 0xE36D # 0 +0xFBC1 0xE36E # 0 +0xFBC2 0xE36F # 0 +0xFBC3 0xE370 # 0 +0xFBC4 0xE371 # 0 +0xFBC5 0xE372 # 0 +0xFBC6 0xE373 # 0 +0xFBC7 0xE374 # 0 +0xFBC8 0xE375 # 0 +0xFBC9 0xE376 # 0 +0xFBCA 0xE377 # 0 +0xFBCB 0xE378 # 0 +0xFBCC 0xE379 # 0 +0xFBCD 0xE37A # 0 +0xFBCE 0xE37B # 0 +0xFBCF 0xE37C # 0 +0xFBD0 0xE37D # 0 +0xFBD1 0xE37E # 0 +0xFBD2 0xE37F # 0 +0xFBD3 0xE380 # 0 +0xFBD4 0xE381 # 0 +0xFBD5 0xE382 # 0 +0xFBD6 0xE383 # 0 +0xFBD7 0xE384 # 0 +0xFBD8 0xE385 # 0 +0xFBD9 0xE386 # 0 +0xFBDA 0xE387 # 0 +0xFBDB 0xE388 # 0 +0xFBDC 0xE389 # 0 +0xFBDD 0xE38A # 0 +0xFBDE 0xE38B # 0 +0xFBDF 0xE38C # 0 +0xFBE0 0xE38D # 0 +0xFBE1 0xE38E # 0 +0xFBE2 0xE38F # 0 +0xFBE3 0xE390 # 0 +0xFBE4 0xE391 # 0 +0xFBE5 0xE392 # 0 +0xFBE6 0xE393 # 0 +0xFBE7 0xE394 # 0 +0xFBE8 0xE395 # 0 +0xFBE9 0xE396 # 0 +0xFBEA 0xE397 # 0 +0xFBEB 0xE398 # 0 +0xFBEC 0xE399 # 0 +0xFBED 0xE39A # 0 +0xFBEE 0xE39B # 0 +0xFBEF 0xE39C # 0 +0xFBF0 0xE39D # 0 +0xFBF1 0xE39E # 0 +0xFBF2 0xE39F # 0 +0xFBF3 0xE3A0 # 0 +0xFBF4 0xE3A1 # 0 +0xFBF5 0xE3A2 # 0 +0xFBF6 0xE3A3 # 0 +0xFBF7 0xE3A4 # 0 +0xFBF8 0xE3A5 # 0 +0xFBF9 0xE3A6 # 0 +0xFBFA 0xE3A7 # 0 +0xFBFB 0xE3A8 # 0 +0xFBFC 0xE3A9 # 0 +0xFBFD 0xE3AA # 0 +0xFBFE 0xE3AB # 0 +0xFC40 0x9EAB # 0 +0xFC41 0x9EAC # 0 +0xFC42 0x9EAD # 0 +0xFC43 0x9EAE # 0 +0xFC44 0x9EAF # 0 +0xFC45 0x9EB0 # 0 +0xFC46 0x9EB1 # 0 +0xFC47 0x9EB2 # 0 +0xFC48 0x9EB3 # 0 +0xFC49 0x9EB5 # 0 +0xFC4A 0x9EB6 # 0 +0xFC4B 0x9EB7 # 0 +0xFC4C 0x9EB9 # 0 +0xFC4D 0x9EBA # 0 +0xFC4E 0x9EBC # 0 +0xFC4F 0x9EBF # 0 +0xFC50 0x9EC0 # 0 +0xFC51 0x9EC1 # 0 +0xFC52 0x9EC2 # 0 +0xFC53 0x9EC3 # 0 +0xFC54 0x9EC5 # 0 +0xFC55 0x9EC6 # 0 +0xFC56 0x9EC7 # 0 +0xFC57 0x9EC8 # 0 +0xFC58 0x9ECA # 0 +0xFC59 0x9ECB # 0 +0xFC5A 0x9ECC # 0 +0xFC5B 0x9ED0 # 0 +0xFC5C 0x9ED2 # 0 +0xFC5D 0x9ED3 # 0 +0xFC5E 0x9ED5 # 0 +0xFC5F 0x9ED6 # 0 +0xFC60 0x9ED7 # 0 +0xFC61 0x9ED9 # 0 +0xFC62 0x9EDA # 0 +0xFC63 0x9EDE # 0 +0xFC64 0x9EE1 # 0 +0xFC65 0x9EE3 # 0 +0xFC66 0x9EE4 # 0 +0xFC67 0x9EE6 # 0 +0xFC68 0x9EE8 # 0 +0xFC69 0x9EEB # 0 +0xFC6A 0x9EEC # 0 +0xFC6B 0x9EED # 0 +0xFC6C 0x9EEE # 0 +0xFC6D 0x9EF0 # 0 +0xFC6E 0x9EF1 # 0 +0xFC6F 0x9EF2 # 0 +0xFC70 0x9EF3 # 0 +0xFC71 0x9EF4 # 0 +0xFC72 0x9EF5 # 0 +0xFC73 0x9EF6 # 0 +0xFC74 0x9EF7 # 0 +0xFC75 0x9EF8 # 0 +0xFC76 0x9EFA # 0 +0xFC77 0x9EFD # 0 +0xFC78 0x9EFF # 0 +0xFC79 0x9F00 # 0 +0xFC7A 0x9F01 # 0 +0xFC7B 0x9F02 # 0 +0xFC7C 0x9F03 # 0 +0xFC7D 0x9F04 # 0 +0xFC7E 0x9F05 # 0 +0xFC80 0x9F06 # 0 +0xFC81 0x9F07 # 0 +0xFC82 0x9F08 # 0 +0xFC83 0x9F09 # 0 +0xFC84 0x9F0A # 0 +0xFC85 0x9F0C # 0 +0xFC86 0x9F0F # 0 +0xFC87 0x9F11 # 0 +0xFC88 0x9F12 # 0 +0xFC89 0x9F14 # 0 +0xFC8A 0x9F15 # 0 +0xFC8B 0x9F16 # 0 +0xFC8C 0x9F18 # 0 +0xFC8D 0x9F1A # 0 +0xFC8E 0x9F1B # 0 +0xFC8F 0x9F1C # 0 +0xFC90 0x9F1D # 0 +0xFC91 0x9F1E # 0 +0xFC92 0x9F1F # 0 +0xFC93 0x9F21 # 0 +0xFC94 0x9F23 # 0 +0xFC95 0x9F24 # 0 +0xFC96 0x9F25 # 0 +0xFC97 0x9F26 # 0 +0xFC98 0x9F27 # 0 +0xFC99 0x9F28 # 0 +0xFC9A 0x9F29 # 0 +0xFC9B 0x9F2A # 0 +0xFC9C 0x9F2B # 0 +0xFC9D 0x9F2D # 0 +0xFC9E 0x9F2E # 0 +0xFC9F 0x9F30 # 0 +0xFCA0 0x9F31 # 0 +0xFCA1 0xE3AC # 0 +0xFCA2 0xE3AD # 0 +0xFCA3 0xE3AE # 0 +0xFCA4 0xE3AF # 0 +0xFCA5 0xE3B0 # 0 +0xFCA6 0xE3B1 # 0 +0xFCA7 0xE3B2 # 0 +0xFCA8 0xE3B3 # 0 +0xFCA9 0xE3B4 # 0 +0xFCAA 0xE3B5 # 0 +0xFCAB 0xE3B6 # 0 +0xFCAC 0xE3B7 # 0 +0xFCAD 0xE3B8 # 0 +0xFCAE 0xE3B9 # 0 +0xFCAF 0xE3BA # 0 +0xFCB0 0xE3BB # 0 +0xFCB1 0xE3BC # 0 +0xFCB2 0xE3BD # 0 +0xFCB3 0xE3BE # 0 +0xFCB4 0xE3BF # 0 +0xFCB5 0xE3C0 # 0 +0xFCB6 0xE3C1 # 0 +0xFCB7 0xE3C2 # 0 +0xFCB8 0xE3C3 # 0 +0xFCB9 0xE3C4 # 0 +0xFCBA 0xE3C5 # 0 +0xFCBB 0xE3C6 # 0 +0xFCBC 0xE3C7 # 0 +0xFCBD 0xE3C8 # 0 +0xFCBE 0xE3C9 # 0 +0xFCBF 0xE3CA # 0 +0xFCC0 0xE3CB # 0 +0xFCC1 0xE3CC # 0 +0xFCC2 0xE3CD # 0 +0xFCC3 0xE3CE # 0 +0xFCC4 0xE3CF # 0 +0xFCC5 0xE3D0 # 0 +0xFCC6 0xE3D1 # 0 +0xFCC7 0xE3D2 # 0 +0xFCC8 0xE3D3 # 0 +0xFCC9 0xE3D4 # 0 +0xFCCA 0xE3D5 # 0 +0xFCCB 0xE3D6 # 0 +0xFCCC 0xE3D7 # 0 +0xFCCD 0xE3D8 # 0 +0xFCCE 0xE3D9 # 0 +0xFCCF 0xE3DA # 0 +0xFCD0 0xE3DB # 0 +0xFCD1 0xE3DC # 0 +0xFCD2 0xE3DD # 0 +0xFCD3 0xE3DE # 0 +0xFCD4 0xE3DF # 0 +0xFCD5 0xE3E0 # 0 +0xFCD6 0xE3E1 # 0 +0xFCD7 0xE3E2 # 0 +0xFCD8 0xE3E3 # 0 +0xFCD9 0xE3E4 # 0 +0xFCDA 0xE3E5 # 0 +0xFCDB 0xE3E6 # 0 +0xFCDC 0xE3E7 # 0 +0xFCDD 0xE3E8 # 0 +0xFCDE 0xE3E9 # 0 +0xFCDF 0xE3EA # 0 +0xFCE0 0xE3EB # 0 +0xFCE1 0xE3EC # 0 +0xFCE2 0xE3ED # 0 +0xFCE3 0xE3EE # 0 +0xFCE4 0xE3EF # 0 +0xFCE5 0xE3F0 # 0 +0xFCE6 0xE3F1 # 0 +0xFCE7 0xE3F2 # 0 +0xFCE8 0xE3F3 # 0 +0xFCE9 0xE3F4 # 0 +0xFCEA 0xE3F5 # 0 +0xFCEB 0xE3F6 # 0 +0xFCEC 0xE3F7 # 0 +0xFCED 0xE3F8 # 0 +0xFCEE 0xE3F9 # 0 +0xFCEF 0xE3FA # 0 +0xFCF0 0xE3FB # 0 +0xFCF1 0xE3FC # 0 +0xFCF2 0xE3FD # 0 +0xFCF3 0xE3FE # 0 +0xFCF4 0xE3FF # 0 +0xFCF5 0xE400 # 0 +0xFCF6 0xE401 # 0 +0xFCF7 0xE402 # 0 +0xFCF8 0xE403 # 0 +0xFCF9 0xE404 # 0 +0xFCFA 0xE405 # 0 +0xFCFB 0xE406 # 0 +0xFCFC 0xE407 # 0 +0xFCFD 0xE408 # 0 +0xFCFE 0xE409 # 0 +0xFD40 0x9F32 # 0 +0xFD41 0x9F33 # 0 +0xFD42 0x9F34 # 0 +0xFD43 0x9F35 # 0 +0xFD44 0x9F36 # 0 +0xFD45 0x9F38 # 0 +0xFD46 0x9F3A # 0 +0xFD47 0x9F3C # 0 +0xFD48 0x9F3F # 0 +0xFD49 0x9F40 # 0 +0xFD4A 0x9F41 # 0 +0xFD4B 0x9F42 # 0 +0xFD4C 0x9F43 # 0 +0xFD4D 0x9F45 # 0 +0xFD4E 0x9F46 # 0 +0xFD4F 0x9F47 # 0 +0xFD50 0x9F48 # 0 +0xFD51 0x9F49 # 0 +0xFD52 0x9F4A # 0 +0xFD53 0x9F4B # 0 +0xFD54 0x9F4C # 0 +0xFD55 0x9F4D # 0 +0xFD56 0x9F4E # 0 +0xFD57 0x9F4F # 0 +0xFD58 0x9F52 # 0 +0xFD59 0x9F53 # 0 +0xFD5A 0x9F54 # 0 +0xFD5B 0x9F55 # 0 +0xFD5C 0x9F56 # 0 +0xFD5D 0x9F57 # 0 +0xFD5E 0x9F58 # 0 +0xFD5F 0x9F59 # 0 +0xFD60 0x9F5A # 0 +0xFD61 0x9F5B # 0 +0xFD62 0x9F5C # 0 +0xFD63 0x9F5D # 0 +0xFD64 0x9F5E # 0 +0xFD65 0x9F5F # 0 +0xFD66 0x9F60 # 0 +0xFD67 0x9F61 # 0 +0xFD68 0x9F62 # 0 +0xFD69 0x9F63 # 0 +0xFD6A 0x9F64 # 0 +0xFD6B 0x9F65 # 0 +0xFD6C 0x9F66 # 0 +0xFD6D 0x9F67 # 0 +0xFD6E 0x9F68 # 0 +0xFD6F 0x9F69 # 0 +0xFD70 0x9F6A # 0 +0xFD71 0x9F6B # 0 +0xFD72 0x9F6C # 0 +0xFD73 0x9F6D # 0 +0xFD74 0x9F6E # 0 +0xFD75 0x9F6F # 0 +0xFD76 0x9F70 # 0 +0xFD77 0x9F71 # 0 +0xFD78 0x9F72 # 0 +0xFD79 0x9F73 # 0 +0xFD7A 0x9F74 # 0 +0xFD7B 0x9F75 # 0 +0xFD7C 0x9F76 # 0 +0xFD7D 0x9F77 # 0 +0xFD7E 0x9F78 # 0 +0xFD80 0x9F79 # 0 +0xFD81 0x9F7A # 0 +0xFD82 0x9F7B # 0 +0xFD83 0x9F7C # 0 +0xFD84 0x9F7D # 0 +0xFD85 0x9F7E # 0 +0xFD86 0x9F81 # 0 +0xFD87 0x9F82 # 0 +0xFD88 0x9F8D # 0 +0xFD89 0x9F8E # 0 +0xFD8A 0x9F8F # 0 +0xFD8B 0x9F90 # 0 +0xFD8C 0x9F91 # 0 +0xFD8D 0x9F92 # 0 +0xFD8E 0x9F93 # 0 +0xFD8F 0x9F94 # 0 +0xFD90 0x9F95 # 0 +0xFD91 0x9F96 # 0 +0xFD92 0x9F97 # 0 +0xFD93 0x9F98 # 0 +0xFD94 0x9F9C # 0 +0xFD95 0x9F9D # 0 +0xFD96 0x9F9E # 0 +0xFD97 0x9FA1 # 0 +0xFD98 0x9FA2 # 0 +0xFD99 0x9FA3 # 0 +0xFD9A 0x9FA4 # 0 +0xFD9B 0x9FA5 # 0 +0xFD9C 0xF92C # 0 +0xFD9D 0xF979 # 0 +0xFD9E 0xF995 # 0 +0xFD9F 0xF9E7 # 0 +0xFDA0 0xF9F1 # 0 +0xFDA1 0xE40A # 0 +0xFDA2 0xE40B # 0 +0xFDA3 0xE40C # 0 +0xFDA4 0xE40D # 0 +0xFDA5 0xE40E # 0 +0xFDA6 0xE40F # 0 +0xFDA7 0xE410 # 0 +0xFDA8 0xE411 # 0 +0xFDA9 0xE412 # 0 +0xFDAA 0xE413 # 0 +0xFDAB 0xE414 # 0 +0xFDAC 0xE415 # 0 +0xFDAD 0xE416 # 0 +0xFDAE 0xE417 # 0 +0xFDAF 0xE418 # 0 +0xFDB0 0xE419 # 0 +0xFDB1 0xE41A # 0 +0xFDB2 0xE41B # 0 +0xFDB3 0xE41C # 0 +0xFDB4 0xE41D # 0 +0xFDB5 0xE41E # 0 +0xFDB6 0xE41F # 0 +0xFDB7 0xE420 # 0 +0xFDB8 0xE421 # 0 +0xFDB9 0xE422 # 0 +0xFDBA 0xE423 # 0 +0xFDBB 0xE424 # 0 +0xFDBC 0xE425 # 0 +0xFDBD 0xE426 # 0 +0xFDBE 0xE427 # 0 +0xFDBF 0xE428 # 0 +0xFDC0 0xE429 # 0 +0xFDC1 0xE42A # 0 +0xFDC2 0xE42B # 0 +0xFDC3 0xE42C # 0 +0xFDC4 0xE42D # 0 +0xFDC5 0xE42E # 0 +0xFDC6 0xE42F # 0 +0xFDC7 0xE430 # 0 +0xFDC8 0xE431 # 0 +0xFDC9 0xE432 # 0 +0xFDCA 0xE433 # 0 +0xFDCB 0xE434 # 0 +0xFDCC 0xE435 # 0 +0xFDCD 0xE436 # 0 +0xFDCE 0xE437 # 0 +0xFDCF 0xE438 # 0 +0xFDD0 0xE439 # 0 +0xFDD1 0xE43A # 0 +0xFDD2 0xE43B # 0 +0xFDD3 0xE43C # 0 +0xFDD4 0xE43D # 0 +0xFDD5 0xE43E # 0 +0xFDD6 0xE43F # 0 +0xFDD7 0xE440 # 0 +0xFDD8 0xE441 # 0 +0xFDD9 0xE442 # 0 +0xFDDA 0xE443 # 0 +0xFDDB 0xE444 # 0 +0xFDDC 0xE445 # 0 +0xFDDD 0xE446 # 0 +0xFDDE 0xE447 # 0 +0xFDDF 0xE448 # 0 +0xFDE0 0xE449 # 0 +0xFDE1 0xE44A # 0 +0xFDE2 0xE44B # 0 +0xFDE3 0xE44C # 0 +0xFDE4 0xE44D # 0 +0xFDE5 0xE44E # 0 +0xFDE6 0xE44F # 0 +0xFDE7 0xE450 # 0 +0xFDE8 0xE451 # 0 +0xFDE9 0xE452 # 0 +0xFDEA 0xE453 # 0 +0xFDEB 0xE454 # 0 +0xFDEC 0xE455 # 0 +0xFDED 0xE456 # 0 +0xFDEE 0xE457 # 0 +0xFDEF 0xE458 # 0 +0xFDF0 0xE459 # 0 +0xFDF1 0xE45A # 0 +0xFDF2 0xE45B # 0 +0xFDF3 0xE45C # 0 +0xFDF4 0xE45D # 0 +0xFDF5 0xE45E # 0 +0xFDF6 0xE45F # 0 +0xFDF7 0xE460 # 0 +0xFDF8 0xE461 # 0 +0xFDF9 0xE462 # 0 +0xFDFA 0xE463 # 0 +0xFDFB 0xE464 # 0 +0xFDFC 0xE465 # 0 +0xFDFD 0xE466 # 0 +0xFDFE 0xE467 # 0 +0xFE40 0xFA0C # 0 +0xFE41 0xFA0D # 0 +0xFE42 0xFA0E # 0 +0xFE43 0xFA0F # 0 +0xFE44 0xFA11 # 0 +0xFE45 0xFA13 # 0 +0xFE46 0xFA14 # 0 +0xFE47 0xFA18 # 0 +0xFE48 0xFA1F # 0 +0xFE49 0xFA20 # 0 +0xFE4A 0xFA21 # 0 +0xFE4B 0xFA23 # 0 +0xFE4C 0xFA24 # 0 +0xFE4D 0xFA27 # 0 +0xFE4E 0xFA28 # 0 +0xFE4F 0xFA29 # 0 +0xFE50 0xE815 # 0 +0xFE51 0xE816 # 0 +0xFE52 0xE817 # 0 +0xFE53 0xE818 # 0 +0xFE54 0xE819 # 0 +0xFE55 0xE81A # 0 +0xFE56 0xE81B # 0 +0xFE57 0xE81C # 0 +0xFE58 0xE81D # 0 +0xFE59 0xE81E # 0 +0xFE5A 0xE81F # 0 +0xFE5B 0xE820 # 0 +0xFE5C 0xE821 # 0 +0xFE5D 0xE822 # 0 +0xFE5E 0xE823 # 0 +0xFE5F 0xE824 # 0 +0xFE60 0xE825 # 0 +0xFE61 0xE826 # 0 +0xFE62 0xE827 # 0 +0xFE63 0xE828 # 0 +0xFE64 0xE829 # 0 +0xFE65 0xE82A # 0 +0xFE66 0xE82B # 0 +0xFE67 0xE82C # 0 +0xFE68 0xE82D # 0 +0xFE69 0xE82E # 0 +0xFE6A 0xE82F # 0 +0xFE6B 0xE830 # 0 +0xFE6C 0xE831 # 0 +0xFE6D 0xE832 # 0 +0xFE6E 0xE833 # 0 +0xFE6F 0xE834 # 0 +0xFE70 0xE835 # 0 +0xFE71 0xE836 # 0 +0xFE72 0xE837 # 0 +0xFE73 0xE838 # 0 +0xFE74 0xE839 # 0 +0xFE75 0xE83A # 0 +0xFE76 0xE83B # 0 +0xFE77 0xE83C # 0 +0xFE78 0xE83D # 0 +0xFE79 0xE83E # 0 +0xFE7A 0xE83F # 0 +0xFE7B 0xE840 # 0 +0xFE7C 0xE841 # 0 +0xFE7D 0xE842 # 0 +0xFE7E 0xE843 # 0 +0xFE80 0xE844 # 0 +0xFE81 0xE845 # 0 +0xFE82 0xE846 # 0 +0xFE83 0xE847 # 0 +0xFE84 0xE848 # 0 +0xFE85 0xE849 # 0 +0xFE86 0xE84A # 0 +0xFE87 0xE84B # 0 +0xFE88 0xE84C # 0 +0xFE89 0xE84D # 0 +0xFE8A 0xE84E # 0 +0xFE8B 0xE84F # 0 +0xFE8C 0xE850 # 0 +0xFE8D 0xE851 # 0 +0xFE8E 0xE852 # 0 +0xFE8F 0xE853 # 0 +0xFE90 0xE854 # 0 +0xFE91 0xE855 # 0 +0xFE92 0xE856 # 0 +0xFE93 0xE857 # 0 +0xFE94 0xE858 # 0 +0xFE95 0xE859 # 0 +0xFE96 0xE85A # 0 +0xFE97 0xE85B # 0 +0xFE98 0xE85C # 0 +0xFE99 0xE85D # 0 +0xFE9A 0xE85E # 0 +0xFE9B 0xE85F # 0 +0xFE9C 0xE860 # 0 +0xFE9D 0xE861 # 0 +0xFE9E 0xE862 # 0 +0xFE9F 0xE863 # 0 +0xFEA0 0xE864 # 0 +0xFEA1 0xE468 # 0 +0xFEA2 0xE469 # 0 +0xFEA3 0xE46A # 0 +0xFEA4 0xE46B # 0 +0xFEA5 0xE46C # 0 +0xFEA6 0xE46D # 0 +0xFEA7 0xE46E # 0 +0xFEA8 0xE46F # 0 +0xFEA9 0xE470 # 0 +0xFEAA 0xE471 # 0 +0xFEAB 0xE472 # 0 +0xFEAC 0xE473 # 0 +0xFEAD 0xE474 # 0 +0xFEAE 0xE475 # 0 +0xFEAF 0xE476 # 0 +0xFEB0 0xE477 # 0 +0xFEB1 0xE478 # 0 +0xFEB2 0xE479 # 0 +0xFEB3 0xE47A # 0 +0xFEB4 0xE47B # 0 +0xFEB5 0xE47C # 0 +0xFEB6 0xE47D # 0 +0xFEB7 0xE47E # 0 +0xFEB8 0xE47F # 0 +0xFEB9 0xE480 # 0 +0xFEBA 0xE481 # 0 +0xFEBB 0xE482 # 0 +0xFEBC 0xE483 # 0 +0xFEBD 0xE484 # 0 +0xFEBE 0xE485 # 0 +0xFEBF 0xE486 # 0 +0xFEC0 0xE487 # 0 +0xFEC1 0xE488 # 0 +0xFEC2 0xE489 # 0 +0xFEC3 0xE48A # 0 +0xFEC4 0xE48B # 0 +0xFEC5 0xE48C # 0 +0xFEC6 0xE48D # 0 +0xFEC7 0xE48E # 0 +0xFEC8 0xE48F # 0 +0xFEC9 0xE490 # 0 +0xFECA 0xE491 # 0 +0xFECB 0xE492 # 0 +0xFECC 0xE493 # 0 +0xFECD 0xE494 # 0 +0xFECE 0xE495 # 0 +0xFECF 0xE496 # 0 +0xFED0 0xE497 # 0 +0xFED1 0xE498 # 0 +0xFED2 0xE499 # 0 +0xFED3 0xE49A # 0 +0xFED4 0xE49B # 0 +0xFED5 0xE49C # 0 +0xFED6 0xE49D # 0 +0xFED7 0xE49E # 0 +0xFED8 0xE49F # 0 +0xFED9 0xE4A0 # 0 +0xFEDA 0xE4A1 # 0 +0xFEDB 0xE4A2 # 0 +0xFEDC 0xE4A3 # 0 +0xFEDD 0xE4A4 # 0 +0xFEDE 0xE4A5 # 0 +0xFEDF 0xE4A6 # 0 +0xFEE0 0xE4A7 # 0 +0xFEE1 0xE4A8 # 0 +0xFEE2 0xE4A9 # 0 +0xFEE3 0xE4AA # 0 +0xFEE4 0xE4AB # 0 +0xFEE5 0xE4AC # 0 +0xFEE6 0xE4AD # 0 +0xFEE7 0xE4AE # 0 +0xFEE8 0xE4AF # 0 +0xFEE9 0xE4B0 # 0 +0xFEEA 0xE4B1 # 0 +0xFEEB 0xE4B2 # 0 +0xFEEC 0xE4B3 # 0 +0xFEED 0xE4B4 # 0 +0xFEEE 0xE4B5 # 0 +0xFEEF 0xE4B6 # 0 +0xFEF0 0xE4B7 # 0 +0xFEF1 0xE4B8 # 0 +0xFEF2 0xE4B9 # 0 +0xFEF3 0xE4BA # 0 +0xFEF4 0xE4BB # 0 +0xFEF5 0xE4BC # 0 +0xFEF6 0xE4BD # 0 +0xFEF7 0xE4BE # 0 +0xFEF8 0xE4BF # 0 +0xFEF9 0xE4C0 # 0 +0xFEFA 0xE4C1 # 0 +0xFEFB 0xE4C2 # 0 +0xFEFC 0xE4C3 # 0 +0xFEFD 0xE4C4 # 0 +0xFEFE 0xE4C5 # 0 diff --git a/data/windows-949.txt b/data/windows-949.txt new file mode 100644 index 000000000..68cf9fa7f --- /dev/null +++ b/data/windows-949.txt @@ -0,0 +1,17367 @@ +# cp949.txt - Legacy to Unicode charmap +0x0000 0x0000 # 0 +0x0001 0x0001 # 0 +0x0002 0x0002 # 0 +0x0003 0x0003 # 0 +0x0004 0x0004 # 0 +0x0005 0x0005 # 0 +0x0006 0x0006 # 0 +0x0007 0x0007 # 0 +0x0008 0x0008 # 0 +0x0009 0x0009 # 0 +0x000A 0x000A # 0 +0x000B 0x000B # 0 +0x000C 0x000C # 0 +0x000D 0x000D # 0 +0x000E 0x000E # 0 +0x000F 0x000F # 0 +0x0010 0x0010 # 0 +0x0011 0x0011 # 0 +0x0012 0x0012 # 0 +0x0013 0x0013 # 0 +0x0014 0x0014 # 0 +0x0015 0x0015 # 0 +0x0016 0x0016 # 0 +0x0017 0x0017 # 0 +0x0018 0x0018 # 0 +0x0019 0x0019 # 0 +0x001A 0x001A # 0 +0x001B 0x001B # 0 +0x001C 0x001C # 0 +0x001D 0x001D # 0 +0x001E 0x001E # 0 +0x001F 0x001F # 0 +0x0020 0x0020 # 0 +0x0021 0x0021 # 0 +0x0022 0x0022 # 0 +0x0023 0x0023 # 0 +0x0024 0x0024 # 0 +0x0025 0x0025 # 0 +0x0026 0x0026 # 0 +0x0027 0x0027 # 0 +0x0028 0x0028 # 0 +0x0029 0x0029 # 0 +0x002A 0x002A # 0 +0x002B 0x002B # 0 +0x002C 0x002C # 0 +0x002D 0x002D # 0 +0x002E 0x002E # 0 +0x002F 0x002F # 0 +0x0030 0x0030 # 0 +0x0031 0x0031 # 0 +0x0032 0x0032 # 0 +0x0033 0x0033 # 0 +0x0034 0x0034 # 0 +0x0035 0x0035 # 0 +0x0036 0x0036 # 0 +0x0037 0x0037 # 0 +0x0038 0x0038 # 0 +0x0039 0x0039 # 0 +0x003A 0x003A # 0 +0x003B 0x003B # 0 +0x003C 0x003C # 0 +0x003D 0x003D # 0 +0x003E 0x003E # 0 +0x003F 0x003F # 0 +0x0040 0x0040 # 0 +0x0041 0x0041 # 0 +0x0042 0x0042 # 0 +0x0043 0x0043 # 0 +0x0044 0x0044 # 0 +0x0045 0x0045 # 0 +0x0046 0x0046 # 0 +0x0047 0x0047 # 0 +0x0048 0x0048 # 0 +0x0049 0x0049 # 0 +0x004A 0x004A # 0 +0x004B 0x004B # 0 +0x004C 0x004C # 0 +0x004D 0x004D # 0 +0x004E 0x004E # 0 +0x004F 0x004F # 0 +0x0050 0x0050 # 0 +0x0051 0x0051 # 0 +0x0052 0x0052 # 0 +0x0053 0x0053 # 0 +0x0054 0x0054 # 0 +0x0055 0x0055 # 0 +0x0056 0x0056 # 0 +0x0057 0x0057 # 0 +0x0058 0x0058 # 0 +0x0059 0x0059 # 0 +0x005A 0x005A # 0 +0x005B 0x005B # 0 +0x005C 0x005C # 0 +0x005D 0x005D # 0 +0x005E 0x005E # 0 +0x005F 0x005F # 0 +0x0060 0x0060 # 0 +0x0061 0x0061 # 0 +0x0062 0x0062 # 0 +0x0063 0x0063 # 0 +0x0064 0x0064 # 0 +0x0065 0x0065 # 0 +0x0066 0x0066 # 0 +0x0067 0x0067 # 0 +0x0068 0x0068 # 0 +0x0069 0x0069 # 0 +0x006A 0x006A # 0 +0x006B 0x006B # 0 +0x006C 0x006C # 0 +0x006D 0x006D # 0 +0x006E 0x006E # 0 +0x006F 0x006F # 0 +0x0070 0x0070 # 0 +0x0071 0x0071 # 0 +0x0072 0x0072 # 0 +0x0073 0x0073 # 0 +0x0074 0x0074 # 0 +0x0075 0x0075 # 0 +0x0076 0x0076 # 0 +0x0077 0x0077 # 0 +0x0078 0x0078 # 0 +0x0079 0x0079 # 0 +0x007A 0x007A # 0 +0x007B 0x007B # 0 +0x007C 0x007C # 0 +0x007D 0x007D # 0 +0x007E 0x007E # 0 +0x007F 0x007F # 0 +0x0080 0x0080 # 0 +0x00FF 0xF8F7 # 0 +0x8141 0xAC02 # 0 +0x8142 0xAC03 # 0 +0x8143 0xAC05 # 0 +0x8144 0xAC06 # 0 +0x8145 0xAC0B # 0 +0x8146 0xAC0C # 0 +0x8147 0xAC0D # 0 +0x8148 0xAC0E # 0 +0x8149 0xAC0F # 0 +0x814A 0xAC18 # 0 +0x814B 0xAC1E # 0 +0x814C 0xAC1F # 0 +0x814D 0xAC21 # 0 +0x814E 0xAC22 # 0 +0x814F 0xAC23 # 0 +0x8150 0xAC25 # 0 +0x8151 0xAC26 # 0 +0x8152 0xAC27 # 0 +0x8153 0xAC28 # 0 +0x8154 0xAC29 # 0 +0x8155 0xAC2A # 0 +0x8156 0xAC2B # 0 +0x8157 0xAC2E # 0 +0x8158 0xAC32 # 0 +0x8159 0xAC33 # 0 +0x815A 0xAC34 # 0 +0x8161 0xAC35 # 0 +0x8162 0xAC36 # 0 +0x8163 0xAC37 # 0 +0x8164 0xAC3A # 0 +0x8165 0xAC3B # 0 +0x8166 0xAC3D # 0 +0x8167 0xAC3E # 0 +0x8168 0xAC3F # 0 +0x8169 0xAC41 # 0 +0x816A 0xAC42 # 0 +0x816B 0xAC43 # 0 +0x816C 0xAC44 # 0 +0x816D 0xAC45 # 0 +0x816E 0xAC46 # 0 +0x816F 0xAC47 # 0 +0x8170 0xAC48 # 0 +0x8171 0xAC49 # 0 +0x8172 0xAC4A # 0 +0x8173 0xAC4C # 0 +0x8174 0xAC4E # 0 +0x8175 0xAC4F # 0 +0x8176 0xAC50 # 0 +0x8177 0xAC51 # 0 +0x8178 0xAC52 # 0 +0x8179 0xAC53 # 0 +0x817A 0xAC55 # 0 +0x8181 0xAC56 # 0 +0x8182 0xAC57 # 0 +0x8183 0xAC59 # 0 +0x8184 0xAC5A # 0 +0x8185 0xAC5B # 0 +0x8186 0xAC5D # 0 +0x8187 0xAC5E # 0 +0x8188 0xAC5F # 0 +0x8189 0xAC60 # 0 +0x818A 0xAC61 # 0 +0x818B 0xAC62 # 0 +0x818C 0xAC63 # 0 +0x818D 0xAC64 # 0 +0x818E 0xAC65 # 0 +0x818F 0xAC66 # 0 +0x8190 0xAC67 # 0 +0x8191 0xAC68 # 0 +0x8192 0xAC69 # 0 +0x8193 0xAC6A # 0 +0x8194 0xAC6B # 0 +0x8195 0xAC6C # 0 +0x8196 0xAC6D # 0 +0x8197 0xAC6E # 0 +0x8198 0xAC6F # 0 +0x8199 0xAC72 # 0 +0x819A 0xAC73 # 0 +0x819B 0xAC75 # 0 +0x819C 0xAC76 # 0 +0x819D 0xAC79 # 0 +0x819E 0xAC7B # 0 +0x819F 0xAC7C # 0 +0x81A0 0xAC7D # 0 +0x81A1 0xAC7E # 0 +0x81A2 0xAC7F # 0 +0x81A3 0xAC82 # 0 +0x81A4 0xAC87 # 0 +0x81A5 0xAC88 # 0 +0x81A6 0xAC8D # 0 +0x81A7 0xAC8E # 0 +0x81A8 0xAC8F # 0 +0x81A9 0xAC91 # 0 +0x81AA 0xAC92 # 0 +0x81AB 0xAC93 # 0 +0x81AC 0xAC95 # 0 +0x81AD 0xAC96 # 0 +0x81AE 0xAC97 # 0 +0x81AF 0xAC98 # 0 +0x81B0 0xAC99 # 0 +0x81B1 0xAC9A # 0 +0x81B2 0xAC9B # 0 +0x81B3 0xAC9E # 0 +0x81B4 0xACA2 # 0 +0x81B5 0xACA3 # 0 +0x81B6 0xACA4 # 0 +0x81B7 0xACA5 # 0 +0x81B8 0xACA6 # 0 +0x81B9 0xACA7 # 0 +0x81BA 0xACAB # 0 +0x81BB 0xACAD # 0 +0x81BC 0xACAE # 0 +0x81BD 0xACB1 # 0 +0x81BE 0xACB2 # 0 +0x81BF 0xACB3 # 0 +0x81C0 0xACB4 # 0 +0x81C1 0xACB5 # 0 +0x81C2 0xACB6 # 0 +0x81C3 0xACB7 # 0 +0x81C4 0xACBA # 0 +0x81C5 0xACBE # 0 +0x81C6 0xACBF # 0 +0x81C7 0xACC0 # 0 +0x81C8 0xACC2 # 0 +0x81C9 0xACC3 # 0 +0x81CA 0xACC5 # 0 +0x81CB 0xACC6 # 0 +0x81CC 0xACC7 # 0 +0x81CD 0xACC9 # 0 +0x81CE 0xACCA # 0 +0x81CF 0xACCB # 0 +0x81D0 0xACCD # 0 +0x81D1 0xACCE # 0 +0x81D2 0xACCF # 0 +0x81D3 0xACD0 # 0 +0x81D4 0xACD1 # 0 +0x81D5 0xACD2 # 0 +0x81D6 0xACD3 # 0 +0x81D7 0xACD4 # 0 +0x81D8 0xACD6 # 0 +0x81D9 0xACD8 # 0 +0x81DA 0xACD9 # 0 +0x81DB 0xACDA # 0 +0x81DC 0xACDB # 0 +0x81DD 0xACDC # 0 +0x81DE 0xACDD # 0 +0x81DF 0xACDE # 0 +0x81E0 0xACDF # 0 +0x81E1 0xACE2 # 0 +0x81E2 0xACE3 # 0 +0x81E3 0xACE5 # 0 +0x81E4 0xACE6 # 0 +0x81E5 0xACE9 # 0 +0x81E6 0xACEB # 0 +0x81E7 0xACED # 0 +0x81E8 0xACEE # 0 +0x81E9 0xACF2 # 0 +0x81EA 0xACF4 # 0 +0x81EB 0xACF7 # 0 +0x81EC 0xACF8 # 0 +0x81ED 0xACF9 # 0 +0x81EE 0xACFA # 0 +0x81EF 0xACFB # 0 +0x81F0 0xACFE # 0 +0x81F1 0xACFF # 0 +0x81F2 0xAD01 # 0 +0x81F3 0xAD02 # 0 +0x81F4 0xAD03 # 0 +0x81F5 0xAD05 # 0 +0x81F6 0xAD07 # 0 +0x81F7 0xAD08 # 0 +0x81F8 0xAD09 # 0 +0x81F9 0xAD0A # 0 +0x81FA 0xAD0B # 0 +0x81FB 0xAD0E # 0 +0x81FC 0xAD10 # 0 +0x81FD 0xAD12 # 0 +0x81FE 0xAD13 # 0 +0x8241 0xAD14 # 0 +0x8242 0xAD15 # 0 +0x8243 0xAD16 # 0 +0x8244 0xAD17 # 0 +0x8245 0xAD19 # 0 +0x8246 0xAD1A # 0 +0x8247 0xAD1B # 0 +0x8248 0xAD1D # 0 +0x8249 0xAD1E # 0 +0x824A 0xAD1F # 0 +0x824B 0xAD21 # 0 +0x824C 0xAD22 # 0 +0x824D 0xAD23 # 0 +0x824E 0xAD24 # 0 +0x824F 0xAD25 # 0 +0x8250 0xAD26 # 0 +0x8251 0xAD27 # 0 +0x8252 0xAD28 # 0 +0x8253 0xAD2A # 0 +0x8254 0xAD2B # 0 +0x8255 0xAD2E # 0 +0x8256 0xAD2F # 0 +0x8257 0xAD30 # 0 +0x8258 0xAD31 # 0 +0x8259 0xAD32 # 0 +0x825A 0xAD33 # 0 +0x8261 0xAD36 # 0 +0x8262 0xAD37 # 0 +0x8263 0xAD39 # 0 +0x8264 0xAD3A # 0 +0x8265 0xAD3B # 0 +0x8266 0xAD3D # 0 +0x8267 0xAD3E # 0 +0x8268 0xAD3F # 0 +0x8269 0xAD40 # 0 +0x826A 0xAD41 # 0 +0x826B 0xAD42 # 0 +0x826C 0xAD43 # 0 +0x826D 0xAD46 # 0 +0x826E 0xAD48 # 0 +0x826F 0xAD4A # 0 +0x8270 0xAD4B # 0 +0x8271 0xAD4C # 0 +0x8272 0xAD4D # 0 +0x8273 0xAD4E # 0 +0x8274 0xAD4F # 0 +0x8275 0xAD51 # 0 +0x8276 0xAD52 # 0 +0x8277 0xAD53 # 0 +0x8278 0xAD55 # 0 +0x8279 0xAD56 # 0 +0x827A 0xAD57 # 0 +0x8281 0xAD59 # 0 +0x8282 0xAD5A # 0 +0x8283 0xAD5B # 0 +0x8284 0xAD5C # 0 +0x8285 0xAD5D # 0 +0x8286 0xAD5E # 0 +0x8287 0xAD5F # 0 +0x8288 0xAD60 # 0 +0x8289 0xAD62 # 0 +0x828A 0xAD64 # 0 +0x828B 0xAD65 # 0 +0x828C 0xAD66 # 0 +0x828D 0xAD67 # 0 +0x828E 0xAD68 # 0 +0x828F 0xAD69 # 0 +0x8290 0xAD6A # 0 +0x8291 0xAD6B # 0 +0x8292 0xAD6E # 0 +0x8293 0xAD6F # 0 +0x8294 0xAD71 # 0 +0x8295 0xAD72 # 0 +0x8296 0xAD77 # 0 +0x8297 0xAD78 # 0 +0x8298 0xAD79 # 0 +0x8299 0xAD7A # 0 +0x829A 0xAD7E # 0 +0x829B 0xAD80 # 0 +0x829C 0xAD83 # 0 +0x829D 0xAD84 # 0 +0x829E 0xAD85 # 0 +0x829F 0xAD86 # 0 +0x82A0 0xAD87 # 0 +0x82A1 0xAD8A # 0 +0x82A2 0xAD8B # 0 +0x82A3 0xAD8D # 0 +0x82A4 0xAD8E # 0 +0x82A5 0xAD8F # 0 +0x82A6 0xAD91 # 0 +0x82A7 0xAD92 # 0 +0x82A8 0xAD93 # 0 +0x82A9 0xAD94 # 0 +0x82AA 0xAD95 # 0 +0x82AB 0xAD96 # 0 +0x82AC 0xAD97 # 0 +0x82AD 0xAD98 # 0 +0x82AE 0xAD99 # 0 +0x82AF 0xAD9A # 0 +0x82B0 0xAD9B # 0 +0x82B1 0xAD9E # 0 +0x82B2 0xAD9F # 0 +0x82B3 0xADA0 # 0 +0x82B4 0xADA1 # 0 +0x82B5 0xADA2 # 0 +0x82B6 0xADA3 # 0 +0x82B7 0xADA5 # 0 +0x82B8 0xADA6 # 0 +0x82B9 0xADA7 # 0 +0x82BA 0xADA8 # 0 +0x82BB 0xADA9 # 0 +0x82BC 0xADAA # 0 +0x82BD 0xADAB # 0 +0x82BE 0xADAC # 0 +0x82BF 0xADAD # 0 +0x82C0 0xADAE # 0 +0x82C1 0xADAF # 0 +0x82C2 0xADB0 # 0 +0x82C3 0xADB1 # 0 +0x82C4 0xADB2 # 0 +0x82C5 0xADB3 # 0 +0x82C6 0xADB4 # 0 +0x82C7 0xADB5 # 0 +0x82C8 0xADB6 # 0 +0x82C9 0xADB8 # 0 +0x82CA 0xADB9 # 0 +0x82CB 0xADBA # 0 +0x82CC 0xADBB # 0 +0x82CD 0xADBC # 0 +0x82CE 0xADBD # 0 +0x82CF 0xADBE # 0 +0x82D0 0xADBF # 0 +0x82D1 0xADC2 # 0 +0x82D2 0xADC3 # 0 +0x82D3 0xADC5 # 0 +0x82D4 0xADC6 # 0 +0x82D5 0xADC7 # 0 +0x82D6 0xADC9 # 0 +0x82D7 0xADCA # 0 +0x82D8 0xADCB # 0 +0x82D9 0xADCC # 0 +0x82DA 0xADCD # 0 +0x82DB 0xADCE # 0 +0x82DC 0xADCF # 0 +0x82DD 0xADD2 # 0 +0x82DE 0xADD4 # 0 +0x82DF 0xADD5 # 0 +0x82E0 0xADD6 # 0 +0x82E1 0xADD7 # 0 +0x82E2 0xADD8 # 0 +0x82E3 0xADD9 # 0 +0x82E4 0xADDA # 0 +0x82E5 0xADDB # 0 +0x82E6 0xADDD # 0 +0x82E7 0xADDE # 0 +0x82E8 0xADDF # 0 +0x82E9 0xADE1 # 0 +0x82EA 0xADE2 # 0 +0x82EB 0xADE3 # 0 +0x82EC 0xADE5 # 0 +0x82ED 0xADE6 # 0 +0x82EE 0xADE7 # 0 +0x82EF 0xADE8 # 0 +0x82F0 0xADE9 # 0 +0x82F1 0xADEA # 0 +0x82F2 0xADEB # 0 +0x82F3 0xADEC # 0 +0x82F4 0xADED # 0 +0x82F5 0xADEE # 0 +0x82F6 0xADEF # 0 +0x82F7 0xADF0 # 0 +0x82F8 0xADF1 # 0 +0x82F9 0xADF2 # 0 +0x82FA 0xADF3 # 0 +0x82FB 0xADF4 # 0 +0x82FC 0xADF5 # 0 +0x82FD 0xADF6 # 0 +0x82FE 0xADF7 # 0 +0x8341 0xADFA # 0 +0x8342 0xADFB # 0 +0x8343 0xADFD # 0 +0x8344 0xADFE # 0 +0x8345 0xAE02 # 0 +0x8346 0xAE03 # 0 +0x8347 0xAE04 # 0 +0x8348 0xAE05 # 0 +0x8349 0xAE06 # 0 +0x834A 0xAE07 # 0 +0x834B 0xAE0A # 0 +0x834C 0xAE0C # 0 +0x834D 0xAE0E # 0 +0x834E 0xAE0F # 0 +0x834F 0xAE10 # 0 +0x8350 0xAE11 # 0 +0x8351 0xAE12 # 0 +0x8352 0xAE13 # 0 +0x8353 0xAE15 # 0 +0x8354 0xAE16 # 0 +0x8355 0xAE17 # 0 +0x8356 0xAE18 # 0 +0x8357 0xAE19 # 0 +0x8358 0xAE1A # 0 +0x8359 0xAE1B # 0 +0x835A 0xAE1C # 0 +0x8361 0xAE1D # 0 +0x8362 0xAE1E # 0 +0x8363 0xAE1F # 0 +0x8364 0xAE20 # 0 +0x8365 0xAE21 # 0 +0x8366 0xAE22 # 0 +0x8367 0xAE23 # 0 +0x8368 0xAE24 # 0 +0x8369 0xAE25 # 0 +0x836A 0xAE26 # 0 +0x836B 0xAE27 # 0 +0x836C 0xAE28 # 0 +0x836D 0xAE29 # 0 +0x836E 0xAE2A # 0 +0x836F 0xAE2B # 0 +0x8370 0xAE2C # 0 +0x8371 0xAE2D # 0 +0x8372 0xAE2E # 0 +0x8373 0xAE2F # 0 +0x8374 0xAE32 # 0 +0x8375 0xAE33 # 0 +0x8376 0xAE35 # 0 +0x8377 0xAE36 # 0 +0x8378 0xAE39 # 0 +0x8379 0xAE3B # 0 +0x837A 0xAE3C # 0 +0x8381 0xAE3D # 0 +0x8382 0xAE3E # 0 +0x8383 0xAE3F # 0 +0x8384 0xAE42 # 0 +0x8385 0xAE44 # 0 +0x8386 0xAE47 # 0 +0x8387 0xAE48 # 0 +0x8388 0xAE49 # 0 +0x8389 0xAE4B # 0 +0x838A 0xAE4F # 0 +0x838B 0xAE51 # 0 +0x838C 0xAE52 # 0 +0x838D 0xAE53 # 0 +0x838E 0xAE55 # 0 +0x838F 0xAE57 # 0 +0x8390 0xAE58 # 0 +0x8391 0xAE59 # 0 +0x8392 0xAE5A # 0 +0x8393 0xAE5B # 0 +0x8394 0xAE5E # 0 +0x8395 0xAE62 # 0 +0x8396 0xAE63 # 0 +0x8397 0xAE64 # 0 +0x8398 0xAE66 # 0 +0x8399 0xAE67 # 0 +0x839A 0xAE6A # 0 +0x839B 0xAE6B # 0 +0x839C 0xAE6D # 0 +0x839D 0xAE6E # 0 +0x839E 0xAE6F # 0 +0x839F 0xAE71 # 0 +0x83A0 0xAE72 # 0 +0x83A1 0xAE73 # 0 +0x83A2 0xAE74 # 0 +0x83A3 0xAE75 # 0 +0x83A4 0xAE76 # 0 +0x83A5 0xAE77 # 0 +0x83A6 0xAE7A # 0 +0x83A7 0xAE7E # 0 +0x83A8 0xAE7F # 0 +0x83A9 0xAE80 # 0 +0x83AA 0xAE81 # 0 +0x83AB 0xAE82 # 0 +0x83AC 0xAE83 # 0 +0x83AD 0xAE86 # 0 +0x83AE 0xAE87 # 0 +0x83AF 0xAE88 # 0 +0x83B0 0xAE89 # 0 +0x83B1 0xAE8A # 0 +0x83B2 0xAE8B # 0 +0x83B3 0xAE8D # 0 +0x83B4 0xAE8E # 0 +0x83B5 0xAE8F # 0 +0x83B6 0xAE90 # 0 +0x83B7 0xAE91 # 0 +0x83B8 0xAE92 # 0 +0x83B9 0xAE93 # 0 +0x83BA 0xAE94 # 0 +0x83BB 0xAE95 # 0 +0x83BC 0xAE96 # 0 +0x83BD 0xAE97 # 0 +0x83BE 0xAE98 # 0 +0x83BF 0xAE99 # 0 +0x83C0 0xAE9A # 0 +0x83C1 0xAE9B # 0 +0x83C2 0xAE9C # 0 +0x83C3 0xAE9D # 0 +0x83C4 0xAE9E # 0 +0x83C5 0xAE9F # 0 +0x83C6 0xAEA0 # 0 +0x83C7 0xAEA1 # 0 +0x83C8 0xAEA2 # 0 +0x83C9 0xAEA3 # 0 +0x83CA 0xAEA4 # 0 +0x83CB 0xAEA5 # 0 +0x83CC 0xAEA6 # 0 +0x83CD 0xAEA7 # 0 +0x83CE 0xAEA8 # 0 +0x83CF 0xAEA9 # 0 +0x83D0 0xAEAA # 0 +0x83D1 0xAEAB # 0 +0x83D2 0xAEAC # 0 +0x83D3 0xAEAD # 0 +0x83D4 0xAEAE # 0 +0x83D5 0xAEAF # 0 +0x83D6 0xAEB0 # 0 +0x83D7 0xAEB1 # 0 +0x83D8 0xAEB2 # 0 +0x83D9 0xAEB3 # 0 +0x83DA 0xAEB4 # 0 +0x83DB 0xAEB5 # 0 +0x83DC 0xAEB6 # 0 +0x83DD 0xAEB7 # 0 +0x83DE 0xAEB8 # 0 +0x83DF 0xAEB9 # 0 +0x83E0 0xAEBA # 0 +0x83E1 0xAEBB # 0 +0x83E2 0xAEBF # 0 +0x83E3 0xAEC1 # 0 +0x83E4 0xAEC2 # 0 +0x83E5 0xAEC3 # 0 +0x83E6 0xAEC5 # 0 +0x83E7 0xAEC6 # 0 +0x83E8 0xAEC7 # 0 +0x83E9 0xAEC8 # 0 +0x83EA 0xAEC9 # 0 +0x83EB 0xAECA # 0 +0x83EC 0xAECB # 0 +0x83ED 0xAECE # 0 +0x83EE 0xAED2 # 0 +0x83EF 0xAED3 # 0 +0x83F0 0xAED4 # 0 +0x83F1 0xAED5 # 0 +0x83F2 0xAED6 # 0 +0x83F3 0xAED7 # 0 +0x83F4 0xAEDA # 0 +0x83F5 0xAEDB # 0 +0x83F6 0xAEDD # 0 +0x83F7 0xAEDE # 0 +0x83F8 0xAEDF # 0 +0x83F9 0xAEE0 # 0 +0x83FA 0xAEE1 # 0 +0x83FB 0xAEE2 # 0 +0x83FC 0xAEE3 # 0 +0x83FD 0xAEE4 # 0 +0x83FE 0xAEE5 # 0 +0x8441 0xAEE6 # 0 +0x8442 0xAEE7 # 0 +0x8443 0xAEE9 # 0 +0x8444 0xAEEA # 0 +0x8445 0xAEEC # 0 +0x8446 0xAEEE # 0 +0x8447 0xAEEF # 0 +0x8448 0xAEF0 # 0 +0x8449 0xAEF1 # 0 +0x844A 0xAEF2 # 0 +0x844B 0xAEF3 # 0 +0x844C 0xAEF5 # 0 +0x844D 0xAEF6 # 0 +0x844E 0xAEF7 # 0 +0x844F 0xAEF9 # 0 +0x8450 0xAEFA # 0 +0x8451 0xAEFB # 0 +0x8452 0xAEFD # 0 +0x8453 0xAEFE # 0 +0x8454 0xAEFF # 0 +0x8455 0xAF00 # 0 +0x8456 0xAF01 # 0 +0x8457 0xAF02 # 0 +0x8458 0xAF03 # 0 +0x8459 0xAF04 # 0 +0x845A 0xAF05 # 0 +0x8461 0xAF06 # 0 +0x8462 0xAF09 # 0 +0x8463 0xAF0A # 0 +0x8464 0xAF0B # 0 +0x8465 0xAF0C # 0 +0x8466 0xAF0E # 0 +0x8467 0xAF0F # 0 +0x8468 0xAF11 # 0 +0x8469 0xAF12 # 0 +0x846A 0xAF13 # 0 +0x846B 0xAF14 # 0 +0x846C 0xAF15 # 0 +0x846D 0xAF16 # 0 +0x846E 0xAF17 # 0 +0x846F 0xAF18 # 0 +0x8470 0xAF19 # 0 +0x8471 0xAF1A # 0 +0x8472 0xAF1B # 0 +0x8473 0xAF1C # 0 +0x8474 0xAF1D # 0 +0x8475 0xAF1E # 0 +0x8476 0xAF1F # 0 +0x8477 0xAF20 # 0 +0x8478 0xAF21 # 0 +0x8479 0xAF22 # 0 +0x847A 0xAF23 # 0 +0x8481 0xAF24 # 0 +0x8482 0xAF25 # 0 +0x8483 0xAF26 # 0 +0x8484 0xAF27 # 0 +0x8485 0xAF28 # 0 +0x8486 0xAF29 # 0 +0x8487 0xAF2A # 0 +0x8488 0xAF2B # 0 +0x8489 0xAF2E # 0 +0x848A 0xAF2F # 0 +0x848B 0xAF31 # 0 +0x848C 0xAF33 # 0 +0x848D 0xAF35 # 0 +0x848E 0xAF36 # 0 +0x848F 0xAF37 # 0 +0x8490 0xAF38 # 0 +0x8491 0xAF39 # 0 +0x8492 0xAF3A # 0 +0x8493 0xAF3B # 0 +0x8494 0xAF3E # 0 +0x8495 0xAF40 # 0 +0x8496 0xAF44 # 0 +0x8497 0xAF45 # 0 +0x8498 0xAF46 # 0 +0x8499 0xAF47 # 0 +0x849A 0xAF4A # 0 +0x849B 0xAF4B # 0 +0x849C 0xAF4C # 0 +0x849D 0xAF4D # 0 +0x849E 0xAF4E # 0 +0x849F 0xAF4F # 0 +0x84A0 0xAF51 # 0 +0x84A1 0xAF52 # 0 +0x84A2 0xAF53 # 0 +0x84A3 0xAF54 # 0 +0x84A4 0xAF55 # 0 +0x84A5 0xAF56 # 0 +0x84A6 0xAF57 # 0 +0x84A7 0xAF58 # 0 +0x84A8 0xAF59 # 0 +0x84A9 0xAF5A # 0 +0x84AA 0xAF5B # 0 +0x84AB 0xAF5E # 0 +0x84AC 0xAF5F # 0 +0x84AD 0xAF60 # 0 +0x84AE 0xAF61 # 0 +0x84AF 0xAF62 # 0 +0x84B0 0xAF63 # 0 +0x84B1 0xAF66 # 0 +0x84B2 0xAF67 # 0 +0x84B3 0xAF68 # 0 +0x84B4 0xAF69 # 0 +0x84B5 0xAF6A # 0 +0x84B6 0xAF6B # 0 +0x84B7 0xAF6C # 0 +0x84B8 0xAF6D # 0 +0x84B9 0xAF6E # 0 +0x84BA 0xAF6F # 0 +0x84BB 0xAF70 # 0 +0x84BC 0xAF71 # 0 +0x84BD 0xAF72 # 0 +0x84BE 0xAF73 # 0 +0x84BF 0xAF74 # 0 +0x84C0 0xAF75 # 0 +0x84C1 0xAF76 # 0 +0x84C2 0xAF77 # 0 +0x84C3 0xAF78 # 0 +0x84C4 0xAF7A # 0 +0x84C5 0xAF7B # 0 +0x84C6 0xAF7C # 0 +0x84C7 0xAF7D # 0 +0x84C8 0xAF7E # 0 +0x84C9 0xAF7F # 0 +0x84CA 0xAF81 # 0 +0x84CB 0xAF82 # 0 +0x84CC 0xAF83 # 0 +0x84CD 0xAF85 # 0 +0x84CE 0xAF86 # 0 +0x84CF 0xAF87 # 0 +0x84D0 0xAF89 # 0 +0x84D1 0xAF8A # 0 +0x84D2 0xAF8B # 0 +0x84D3 0xAF8C # 0 +0x84D4 0xAF8D # 0 +0x84D5 0xAF8E # 0 +0x84D6 0xAF8F # 0 +0x84D7 0xAF92 # 0 +0x84D8 0xAF93 # 0 +0x84D9 0xAF94 # 0 +0x84DA 0xAF96 # 0 +0x84DB 0xAF97 # 0 +0x84DC 0xAF98 # 0 +0x84DD 0xAF99 # 0 +0x84DE 0xAF9A # 0 +0x84DF 0xAF9B # 0 +0x84E0 0xAF9D # 0 +0x84E1 0xAF9E # 0 +0x84E2 0xAF9F # 0 +0x84E3 0xAFA0 # 0 +0x84E4 0xAFA1 # 0 +0x84E5 0xAFA2 # 0 +0x84E6 0xAFA3 # 0 +0x84E7 0xAFA4 # 0 +0x84E8 0xAFA5 # 0 +0x84E9 0xAFA6 # 0 +0x84EA 0xAFA7 # 0 +0x84EB 0xAFA8 # 0 +0x84EC 0xAFA9 # 0 +0x84ED 0xAFAA # 0 +0x84EE 0xAFAB # 0 +0x84EF 0xAFAC # 0 +0x84F0 0xAFAD # 0 +0x84F1 0xAFAE # 0 +0x84F2 0xAFAF # 0 +0x84F3 0xAFB0 # 0 +0x84F4 0xAFB1 # 0 +0x84F5 0xAFB2 # 0 +0x84F6 0xAFB3 # 0 +0x84F7 0xAFB4 # 0 +0x84F8 0xAFB5 # 0 +0x84F9 0xAFB6 # 0 +0x84FA 0xAFB7 # 0 +0x84FB 0xAFBA # 0 +0x84FC 0xAFBB # 0 +0x84FD 0xAFBD # 0 +0x84FE 0xAFBE # 0 +0x8541 0xAFBF # 0 +0x8542 0xAFC1 # 0 +0x8543 0xAFC2 # 0 +0x8544 0xAFC3 # 0 +0x8545 0xAFC4 # 0 +0x8546 0xAFC5 # 0 +0x8547 0xAFC6 # 0 +0x8548 0xAFCA # 0 +0x8549 0xAFCC # 0 +0x854A 0xAFCF # 0 +0x854B 0xAFD0 # 0 +0x854C 0xAFD1 # 0 +0x854D 0xAFD2 # 0 +0x854E 0xAFD3 # 0 +0x854F 0xAFD5 # 0 +0x8550 0xAFD6 # 0 +0x8551 0xAFD7 # 0 +0x8552 0xAFD8 # 0 +0x8553 0xAFD9 # 0 +0x8554 0xAFDA # 0 +0x8555 0xAFDB # 0 +0x8556 0xAFDD # 0 +0x8557 0xAFDE # 0 +0x8558 0xAFDF # 0 +0x8559 0xAFE0 # 0 +0x855A 0xAFE1 # 0 +0x8561 0xAFE2 # 0 +0x8562 0xAFE3 # 0 +0x8563 0xAFE4 # 0 +0x8564 0xAFE5 # 0 +0x8565 0xAFE6 # 0 +0x8566 0xAFE7 # 0 +0x8567 0xAFEA # 0 +0x8568 0xAFEB # 0 +0x8569 0xAFEC # 0 +0x856A 0xAFED # 0 +0x856B 0xAFEE # 0 +0x856C 0xAFEF # 0 +0x856D 0xAFF2 # 0 +0x856E 0xAFF3 # 0 +0x856F 0xAFF5 # 0 +0x8570 0xAFF6 # 0 +0x8571 0xAFF7 # 0 +0x8572 0xAFF9 # 0 +0x8573 0xAFFA # 0 +0x8574 0xAFFB # 0 +0x8575 0xAFFC # 0 +0x8576 0xAFFD # 0 +0x8577 0xAFFE # 0 +0x8578 0xAFFF # 0 +0x8579 0xB002 # 0 +0x857A 0xB003 # 0 +0x8581 0xB005 # 0 +0x8582 0xB006 # 0 +0x8583 0xB007 # 0 +0x8584 0xB008 # 0 +0x8585 0xB009 # 0 +0x8586 0xB00A # 0 +0x8587 0xB00B # 0 +0x8588 0xB00D # 0 +0x8589 0xB00E # 0 +0x858A 0xB00F # 0 +0x858B 0xB011 # 0 +0x858C 0xB012 # 0 +0x858D 0xB013 # 0 +0x858E 0xB015 # 0 +0x858F 0xB016 # 0 +0x8590 0xB017 # 0 +0x8591 0xB018 # 0 +0x8592 0xB019 # 0 +0x8593 0xB01A # 0 +0x8594 0xB01B # 0 +0x8595 0xB01E # 0 +0x8596 0xB01F # 0 +0x8597 0xB020 # 0 +0x8598 0xB021 # 0 +0x8599 0xB022 # 0 +0x859A 0xB023 # 0 +0x859B 0xB024 # 0 +0x859C 0xB025 # 0 +0x859D 0xB026 # 0 +0x859E 0xB027 # 0 +0x859F 0xB029 # 0 +0x85A0 0xB02A # 0 +0x85A1 0xB02B # 0 +0x85A2 0xB02C # 0 +0x85A3 0xB02D # 0 +0x85A4 0xB02E # 0 +0x85A5 0xB02F # 0 +0x85A6 0xB030 # 0 +0x85A7 0xB031 # 0 +0x85A8 0xB032 # 0 +0x85A9 0xB033 # 0 +0x85AA 0xB034 # 0 +0x85AB 0xB035 # 0 +0x85AC 0xB036 # 0 +0x85AD 0xB037 # 0 +0x85AE 0xB038 # 0 +0x85AF 0xB039 # 0 +0x85B0 0xB03A # 0 +0x85B1 0xB03B # 0 +0x85B2 0xB03C # 0 +0x85B3 0xB03D # 0 +0x85B4 0xB03E # 0 +0x85B5 0xB03F # 0 +0x85B6 0xB040 # 0 +0x85B7 0xB041 # 0 +0x85B8 0xB042 # 0 +0x85B9 0xB043 # 0 +0x85BA 0xB046 # 0 +0x85BB 0xB047 # 0 +0x85BC 0xB049 # 0 +0x85BD 0xB04B # 0 +0x85BE 0xB04D # 0 +0x85BF 0xB04F # 0 +0x85C0 0xB050 # 0 +0x85C1 0xB051 # 0 +0x85C2 0xB052 # 0 +0x85C3 0xB056 # 0 +0x85C4 0xB058 # 0 +0x85C5 0xB05A # 0 +0x85C6 0xB05B # 0 +0x85C7 0xB05C # 0 +0x85C8 0xB05E # 0 +0x85C9 0xB05F # 0 +0x85CA 0xB060 # 0 +0x85CB 0xB061 # 0 +0x85CC 0xB062 # 0 +0x85CD 0xB063 # 0 +0x85CE 0xB064 # 0 +0x85CF 0xB065 # 0 +0x85D0 0xB066 # 0 +0x85D1 0xB067 # 0 +0x85D2 0xB068 # 0 +0x85D3 0xB069 # 0 +0x85D4 0xB06A # 0 +0x85D5 0xB06B # 0 +0x85D6 0xB06C # 0 +0x85D7 0xB06D # 0 +0x85D8 0xB06E # 0 +0x85D9 0xB06F # 0 +0x85DA 0xB070 # 0 +0x85DB 0xB071 # 0 +0x85DC 0xB072 # 0 +0x85DD 0xB073 # 0 +0x85DE 0xB074 # 0 +0x85DF 0xB075 # 0 +0x85E0 0xB076 # 0 +0x85E1 0xB077 # 0 +0x85E2 0xB078 # 0 +0x85E3 0xB079 # 0 +0x85E4 0xB07A # 0 +0x85E5 0xB07B # 0 +0x85E6 0xB07E # 0 +0x85E7 0xB07F # 0 +0x85E8 0xB081 # 0 +0x85E9 0xB082 # 0 +0x85EA 0xB083 # 0 +0x85EB 0xB085 # 0 +0x85EC 0xB086 # 0 +0x85ED 0xB087 # 0 +0x85EE 0xB088 # 0 +0x85EF 0xB089 # 0 +0x85F0 0xB08A # 0 +0x85F1 0xB08B # 0 +0x85F2 0xB08E # 0 +0x85F3 0xB090 # 0 +0x85F4 0xB092 # 0 +0x85F5 0xB093 # 0 +0x85F6 0xB094 # 0 +0x85F7 0xB095 # 0 +0x85F8 0xB096 # 0 +0x85F9 0xB097 # 0 +0x85FA 0xB09B # 0 +0x85FB 0xB09D # 0 +0x85FC 0xB09E # 0 +0x85FD 0xB0A3 # 0 +0x85FE 0xB0A4 # 0 +0x8641 0xB0A5 # 0 +0x8642 0xB0A6 # 0 +0x8643 0xB0A7 # 0 +0x8644 0xB0AA # 0 +0x8645 0xB0B0 # 0 +0x8646 0xB0B2 # 0 +0x8647 0xB0B6 # 0 +0x8648 0xB0B7 # 0 +0x8649 0xB0B9 # 0 +0x864A 0xB0BA # 0 +0x864B 0xB0BB # 0 +0x864C 0xB0BD # 0 +0x864D 0xB0BE # 0 +0x864E 0xB0BF # 0 +0x864F 0xB0C0 # 0 +0x8650 0xB0C1 # 0 +0x8651 0xB0C2 # 0 +0x8652 0xB0C3 # 0 +0x8653 0xB0C6 # 0 +0x8654 0xB0CA # 0 +0x8655 0xB0CB # 0 +0x8656 0xB0CC # 0 +0x8657 0xB0CD # 0 +0x8658 0xB0CE # 0 +0x8659 0xB0CF # 0 +0x865A 0xB0D2 # 0 +0x8661 0xB0D3 # 0 +0x8662 0xB0D5 # 0 +0x8663 0xB0D6 # 0 +0x8664 0xB0D7 # 0 +0x8665 0xB0D9 # 0 +0x8666 0xB0DA # 0 +0x8667 0xB0DB # 0 +0x8668 0xB0DC # 0 +0x8669 0xB0DD # 0 +0x866A 0xB0DE # 0 +0x866B 0xB0DF # 0 +0x866C 0xB0E1 # 0 +0x866D 0xB0E2 # 0 +0x866E 0xB0E3 # 0 +0x866F 0xB0E4 # 0 +0x8670 0xB0E6 # 0 +0x8671 0xB0E7 # 0 +0x8672 0xB0E8 # 0 +0x8673 0xB0E9 # 0 +0x8674 0xB0EA # 0 +0x8675 0xB0EB # 0 +0x8676 0xB0EC # 0 +0x8677 0xB0ED # 0 +0x8678 0xB0EE # 0 +0x8679 0xB0EF # 0 +0x867A 0xB0F0 # 0 +0x8681 0xB0F1 # 0 +0x8682 0xB0F2 # 0 +0x8683 0xB0F3 # 0 +0x8684 0xB0F4 # 0 +0x8685 0xB0F5 # 0 +0x8686 0xB0F6 # 0 +0x8687 0xB0F7 # 0 +0x8688 0xB0F8 # 0 +0x8689 0xB0F9 # 0 +0x868A 0xB0FA # 0 +0x868B 0xB0FB # 0 +0x868C 0xB0FC # 0 +0x868D 0xB0FD # 0 +0x868E 0xB0FE # 0 +0x868F 0xB0FF # 0 +0x8690 0xB100 # 0 +0x8691 0xB101 # 0 +0x8692 0xB102 # 0 +0x8693 0xB103 # 0 +0x8694 0xB104 # 0 +0x8695 0xB105 # 0 +0x8696 0xB106 # 0 +0x8697 0xB107 # 0 +0x8698 0xB10A # 0 +0x8699 0xB10D # 0 +0x869A 0xB10E # 0 +0x869B 0xB10F # 0 +0x869C 0xB111 # 0 +0x869D 0xB114 # 0 +0x869E 0xB115 # 0 +0x869F 0xB116 # 0 +0x86A0 0xB117 # 0 +0x86A1 0xB11A # 0 +0x86A2 0xB11E # 0 +0x86A3 0xB11F # 0 +0x86A4 0xB120 # 0 +0x86A5 0xB121 # 0 +0x86A6 0xB122 # 0 +0x86A7 0xB126 # 0 +0x86A8 0xB127 # 0 +0x86A9 0xB129 # 0 +0x86AA 0xB12A # 0 +0x86AB 0xB12B # 0 +0x86AC 0xB12D # 0 +0x86AD 0xB12E # 0 +0x86AE 0xB12F # 0 +0x86AF 0xB130 # 0 +0x86B0 0xB131 # 0 +0x86B1 0xB132 # 0 +0x86B2 0xB133 # 0 +0x86B3 0xB136 # 0 +0x86B4 0xB13A # 0 +0x86B5 0xB13B # 0 +0x86B6 0xB13C # 0 +0x86B7 0xB13D # 0 +0x86B8 0xB13E # 0 +0x86B9 0xB13F # 0 +0x86BA 0xB142 # 0 +0x86BB 0xB143 # 0 +0x86BC 0xB145 # 0 +0x86BD 0xB146 # 0 +0x86BE 0xB147 # 0 +0x86BF 0xB149 # 0 +0x86C0 0xB14A # 0 +0x86C1 0xB14B # 0 +0x86C2 0xB14C # 0 +0x86C3 0xB14D # 0 +0x86C4 0xB14E # 0 +0x86C5 0xB14F # 0 +0x86C6 0xB152 # 0 +0x86C7 0xB153 # 0 +0x86C8 0xB156 # 0 +0x86C9 0xB157 # 0 +0x86CA 0xB159 # 0 +0x86CB 0xB15A # 0 +0x86CC 0xB15B # 0 +0x86CD 0xB15D # 0 +0x86CE 0xB15E # 0 +0x86CF 0xB15F # 0 +0x86D0 0xB161 # 0 +0x86D1 0xB162 # 0 +0x86D2 0xB163 # 0 +0x86D3 0xB164 # 0 +0x86D4 0xB165 # 0 +0x86D5 0xB166 # 0 +0x86D6 0xB167 # 0 +0x86D7 0xB168 # 0 +0x86D8 0xB169 # 0 +0x86D9 0xB16A # 0 +0x86DA 0xB16B # 0 +0x86DB 0xB16C # 0 +0x86DC 0xB16D # 0 +0x86DD 0xB16E # 0 +0x86DE 0xB16F # 0 +0x86DF 0xB170 # 0 +0x86E0 0xB171 # 0 +0x86E1 0xB172 # 0 +0x86E2 0xB173 # 0 +0x86E3 0xB174 # 0 +0x86E4 0xB175 # 0 +0x86E5 0xB176 # 0 +0x86E6 0xB177 # 0 +0x86E7 0xB17A # 0 +0x86E8 0xB17B # 0 +0x86E9 0xB17D # 0 +0x86EA 0xB17E # 0 +0x86EB 0xB17F # 0 +0x86EC 0xB181 # 0 +0x86ED 0xB183 # 0 +0x86EE 0xB184 # 0 +0x86EF 0xB185 # 0 +0x86F0 0xB186 # 0 +0x86F1 0xB187 # 0 +0x86F2 0xB18A # 0 +0x86F3 0xB18C # 0 +0x86F4 0xB18E # 0 +0x86F5 0xB18F # 0 +0x86F6 0xB190 # 0 +0x86F7 0xB191 # 0 +0x86F8 0xB195 # 0 +0x86F9 0xB196 # 0 +0x86FA 0xB197 # 0 +0x86FB 0xB199 # 0 +0x86FC 0xB19A # 0 +0x86FD 0xB19B # 0 +0x86FE 0xB19D # 0 +0x8741 0xB19E # 0 +0x8742 0xB19F # 0 +0x8743 0xB1A0 # 0 +0x8744 0xB1A1 # 0 +0x8745 0xB1A2 # 0 +0x8746 0xB1A3 # 0 +0x8747 0xB1A4 # 0 +0x8748 0xB1A5 # 0 +0x8749 0xB1A6 # 0 +0x874A 0xB1A7 # 0 +0x874B 0xB1A9 # 0 +0x874C 0xB1AA # 0 +0x874D 0xB1AB # 0 +0x874E 0xB1AC # 0 +0x874F 0xB1AD # 0 +0x8750 0xB1AE # 0 +0x8751 0xB1AF # 0 +0x8752 0xB1B0 # 0 +0x8753 0xB1B1 # 0 +0x8754 0xB1B2 # 0 +0x8755 0xB1B3 # 0 +0x8756 0xB1B4 # 0 +0x8757 0xB1B5 # 0 +0x8758 0xB1B6 # 0 +0x8759 0xB1B7 # 0 +0x875A 0xB1B8 # 0 +0x8761 0xB1B9 # 0 +0x8762 0xB1BA # 0 +0x8763 0xB1BB # 0 +0x8764 0xB1BC # 0 +0x8765 0xB1BD # 0 +0x8766 0xB1BE # 0 +0x8767 0xB1BF # 0 +0x8768 0xB1C0 # 0 +0x8769 0xB1C1 # 0 +0x876A 0xB1C2 # 0 +0x876B 0xB1C3 # 0 +0x876C 0xB1C4 # 0 +0x876D 0xB1C5 # 0 +0x876E 0xB1C6 # 0 +0x876F 0xB1C7 # 0 +0x8770 0xB1C8 # 0 +0x8771 0xB1C9 # 0 +0x8772 0xB1CA # 0 +0x8773 0xB1CB # 0 +0x8774 0xB1CD # 0 +0x8775 0xB1CE # 0 +0x8776 0xB1CF # 0 +0x8777 0xB1D1 # 0 +0x8778 0xB1D2 # 0 +0x8779 0xB1D3 # 0 +0x877A 0xB1D5 # 0 +0x8781 0xB1D6 # 0 +0x8782 0xB1D7 # 0 +0x8783 0xB1D8 # 0 +0x8784 0xB1D9 # 0 +0x8785 0xB1DA # 0 +0x8786 0xB1DB # 0 +0x8787 0xB1DE # 0 +0x8788 0xB1E0 # 0 +0x8789 0xB1E1 # 0 +0x878A 0xB1E2 # 0 +0x878B 0xB1E3 # 0 +0x878C 0xB1E4 # 0 +0x878D 0xB1E5 # 0 +0x878E 0xB1E6 # 0 +0x878F 0xB1E7 # 0 +0x8790 0xB1EA # 0 +0x8791 0xB1EB # 0 +0x8792 0xB1ED # 0 +0x8793 0xB1EE # 0 +0x8794 0xB1EF # 0 +0x8795 0xB1F1 # 0 +0x8796 0xB1F2 # 0 +0x8797 0xB1F3 # 0 +0x8798 0xB1F4 # 0 +0x8799 0xB1F5 # 0 +0x879A 0xB1F6 # 0 +0x879B 0xB1F7 # 0 +0x879C 0xB1F8 # 0 +0x879D 0xB1FA # 0 +0x879E 0xB1FC # 0 +0x879F 0xB1FE # 0 +0x87A0 0xB1FF # 0 +0x87A1 0xB200 # 0 +0x87A2 0xB201 # 0 +0x87A3 0xB202 # 0 +0x87A4 0xB203 # 0 +0x87A5 0xB206 # 0 +0x87A6 0xB207 # 0 +0x87A7 0xB209 # 0 +0x87A8 0xB20A # 0 +0x87A9 0xB20D # 0 +0x87AA 0xB20E # 0 +0x87AB 0xB20F # 0 +0x87AC 0xB210 # 0 +0x87AD 0xB211 # 0 +0x87AE 0xB212 # 0 +0x87AF 0xB213 # 0 +0x87B0 0xB216 # 0 +0x87B1 0xB218 # 0 +0x87B2 0xB21A # 0 +0x87B3 0xB21B # 0 +0x87B4 0xB21C # 0 +0x87B5 0xB21D # 0 +0x87B6 0xB21E # 0 +0x87B7 0xB21F # 0 +0x87B8 0xB221 # 0 +0x87B9 0xB222 # 0 +0x87BA 0xB223 # 0 +0x87BB 0xB224 # 0 +0x87BC 0xB225 # 0 +0x87BD 0xB226 # 0 +0x87BE 0xB227 # 0 +0x87BF 0xB228 # 0 +0x87C0 0xB229 # 0 +0x87C1 0xB22A # 0 +0x87C2 0xB22B # 0 +0x87C3 0xB22C # 0 +0x87C4 0xB22D # 0 +0x87C5 0xB22E # 0 +0x87C6 0xB22F # 0 +0x87C7 0xB230 # 0 +0x87C8 0xB231 # 0 +0x87C9 0xB232 # 0 +0x87CA 0xB233 # 0 +0x87CB 0xB235 # 0 +0x87CC 0xB236 # 0 +0x87CD 0xB237 # 0 +0x87CE 0xB238 # 0 +0x87CF 0xB239 # 0 +0x87D0 0xB23A # 0 +0x87D1 0xB23B # 0 +0x87D2 0xB23D # 0 +0x87D3 0xB23E # 0 +0x87D4 0xB23F # 0 +0x87D5 0xB240 # 0 +0x87D6 0xB241 # 0 +0x87D7 0xB242 # 0 +0x87D8 0xB243 # 0 +0x87D9 0xB244 # 0 +0x87DA 0xB245 # 0 +0x87DB 0xB246 # 0 +0x87DC 0xB247 # 0 +0x87DD 0xB248 # 0 +0x87DE 0xB249 # 0 +0x87DF 0xB24A # 0 +0x87E0 0xB24B # 0 +0x87E1 0xB24C # 0 +0x87E2 0xB24D # 0 +0x87E3 0xB24E # 0 +0x87E4 0xB24F # 0 +0x87E5 0xB250 # 0 +0x87E6 0xB251 # 0 +0x87E7 0xB252 # 0 +0x87E8 0xB253 # 0 +0x87E9 0xB254 # 0 +0x87EA 0xB255 # 0 +0x87EB 0xB256 # 0 +0x87EC 0xB257 # 0 +0x87ED 0xB259 # 0 +0x87EE 0xB25A # 0 +0x87EF 0xB25B # 0 +0x87F0 0xB25D # 0 +0x87F1 0xB25E # 0 +0x87F2 0xB25F # 0 +0x87F3 0xB261 # 0 +0x87F4 0xB262 # 0 +0x87F5 0xB263 # 0 +0x87F6 0xB264 # 0 +0x87F7 0xB265 # 0 +0x87F8 0xB266 # 0 +0x87F9 0xB267 # 0 +0x87FA 0xB26A # 0 +0x87FB 0xB26B # 0 +0x87FC 0xB26C # 0 +0x87FD 0xB26D # 0 +0x87FE 0xB26E # 0 +0x8841 0xB26F # 0 +0x8842 0xB270 # 0 +0x8843 0xB271 # 0 +0x8844 0xB272 # 0 +0x8845 0xB273 # 0 +0x8846 0xB276 # 0 +0x8847 0xB277 # 0 +0x8848 0xB278 # 0 +0x8849 0xB279 # 0 +0x884A 0xB27A # 0 +0x884B 0xB27B # 0 +0x884C 0xB27D # 0 +0x884D 0xB27E # 0 +0x884E 0xB27F # 0 +0x884F 0xB280 # 0 +0x8850 0xB281 # 0 +0x8851 0xB282 # 0 +0x8852 0xB283 # 0 +0x8853 0xB286 # 0 +0x8854 0xB287 # 0 +0x8855 0xB288 # 0 +0x8856 0xB28A # 0 +0x8857 0xB28B # 0 +0x8858 0xB28C # 0 +0x8859 0xB28D # 0 +0x885A 0xB28E # 0 +0x8861 0xB28F # 0 +0x8862 0xB292 # 0 +0x8863 0xB293 # 0 +0x8864 0xB295 # 0 +0x8865 0xB296 # 0 +0x8866 0xB297 # 0 +0x8867 0xB29B # 0 +0x8868 0xB29C # 0 +0x8869 0xB29D # 0 +0x886A 0xB29E # 0 +0x886B 0xB29F # 0 +0x886C 0xB2A2 # 0 +0x886D 0xB2A4 # 0 +0x886E 0xB2A7 # 0 +0x886F 0xB2A8 # 0 +0x8870 0xB2A9 # 0 +0x8871 0xB2AB # 0 +0x8872 0xB2AD # 0 +0x8873 0xB2AE # 0 +0x8874 0xB2AF # 0 +0x8875 0xB2B1 # 0 +0x8876 0xB2B2 # 0 +0x8877 0xB2B3 # 0 +0x8878 0xB2B5 # 0 +0x8879 0xB2B6 # 0 +0x887A 0xB2B7 # 0 +0x8881 0xB2B8 # 0 +0x8882 0xB2B9 # 0 +0x8883 0xB2BA # 0 +0x8884 0xB2BB # 0 +0x8885 0xB2BC # 0 +0x8886 0xB2BD # 0 +0x8887 0xB2BE # 0 +0x8888 0xB2BF # 0 +0x8889 0xB2C0 # 0 +0x888A 0xB2C1 # 0 +0x888B 0xB2C2 # 0 +0x888C 0xB2C3 # 0 +0x888D 0xB2C4 # 0 +0x888E 0xB2C5 # 0 +0x888F 0xB2C6 # 0 +0x8890 0xB2C7 # 0 +0x8891 0xB2CA # 0 +0x8892 0xB2CB # 0 +0x8893 0xB2CD # 0 +0x8894 0xB2CE # 0 +0x8895 0xB2CF # 0 +0x8896 0xB2D1 # 0 +0x8897 0xB2D3 # 0 +0x8898 0xB2D4 # 0 +0x8899 0xB2D5 # 0 +0x889A 0xB2D6 # 0 +0x889B 0xB2D7 # 0 +0x889C 0xB2DA # 0 +0x889D 0xB2DC # 0 +0x889E 0xB2DE # 0 +0x889F 0xB2DF # 0 +0x88A0 0xB2E0 # 0 +0x88A1 0xB2E1 # 0 +0x88A2 0xB2E3 # 0 +0x88A3 0xB2E7 # 0 +0x88A4 0xB2E9 # 0 +0x88A5 0xB2EA # 0 +0x88A6 0xB2F0 # 0 +0x88A7 0xB2F1 # 0 +0x88A8 0xB2F2 # 0 +0x88A9 0xB2F6 # 0 +0x88AA 0xB2FC # 0 +0x88AB 0xB2FD # 0 +0x88AC 0xB2FE # 0 +0x88AD 0xB302 # 0 +0x88AE 0xB303 # 0 +0x88AF 0xB305 # 0 +0x88B0 0xB306 # 0 +0x88B1 0xB307 # 0 +0x88B2 0xB309 # 0 +0x88B3 0xB30A # 0 +0x88B4 0xB30B # 0 +0x88B5 0xB30C # 0 +0x88B6 0xB30D # 0 +0x88B7 0xB30E # 0 +0x88B8 0xB30F # 0 +0x88B9 0xB312 # 0 +0x88BA 0xB316 # 0 +0x88BB 0xB317 # 0 +0x88BC 0xB318 # 0 +0x88BD 0xB319 # 0 +0x88BE 0xB31A # 0 +0x88BF 0xB31B # 0 +0x88C0 0xB31D # 0 +0x88C1 0xB31E # 0 +0x88C2 0xB31F # 0 +0x88C3 0xB320 # 0 +0x88C4 0xB321 # 0 +0x88C5 0xB322 # 0 +0x88C6 0xB323 # 0 +0x88C7 0xB324 # 0 +0x88C8 0xB325 # 0 +0x88C9 0xB326 # 0 +0x88CA 0xB327 # 0 +0x88CB 0xB328 # 0 +0x88CC 0xB329 # 0 +0x88CD 0xB32A # 0 +0x88CE 0xB32B # 0 +0x88CF 0xB32C # 0 +0x88D0 0xB32D # 0 +0x88D1 0xB32E # 0 +0x88D2 0xB32F # 0 +0x88D3 0xB330 # 0 +0x88D4 0xB331 # 0 +0x88D5 0xB332 # 0 +0x88D6 0xB333 # 0 +0x88D7 0xB334 # 0 +0x88D8 0xB335 # 0 +0x88D9 0xB336 # 0 +0x88DA 0xB337 # 0 +0x88DB 0xB338 # 0 +0x88DC 0xB339 # 0 +0x88DD 0xB33A # 0 +0x88DE 0xB33B # 0 +0x88DF 0xB33C # 0 +0x88E0 0xB33D # 0 +0x88E1 0xB33E # 0 +0x88E2 0xB33F # 0 +0x88E3 0xB340 # 0 +0x88E4 0xB341 # 0 +0x88E5 0xB342 # 0 +0x88E6 0xB343 # 0 +0x88E7 0xB344 # 0 +0x88E8 0xB345 # 0 +0x88E9 0xB346 # 0 +0x88EA 0xB347 # 0 +0x88EB 0xB348 # 0 +0x88EC 0xB349 # 0 +0x88ED 0xB34A # 0 +0x88EE 0xB34B # 0 +0x88EF 0xB34C # 0 +0x88F0 0xB34D # 0 +0x88F1 0xB34E # 0 +0x88F2 0xB34F # 0 +0x88F3 0xB350 # 0 +0x88F4 0xB351 # 0 +0x88F5 0xB352 # 0 +0x88F6 0xB353 # 0 +0x88F7 0xB357 # 0 +0x88F8 0xB359 # 0 +0x88F9 0xB35A # 0 +0x88FA 0xB35D # 0 +0x88FB 0xB360 # 0 +0x88FC 0xB361 # 0 +0x88FD 0xB362 # 0 +0x88FE 0xB363 # 0 +0x8941 0xB366 # 0 +0x8942 0xB368 # 0 +0x8943 0xB36A # 0 +0x8944 0xB36C # 0 +0x8945 0xB36D # 0 +0x8946 0xB36F # 0 +0x8947 0xB372 # 0 +0x8948 0xB373 # 0 +0x8949 0xB375 # 0 +0x894A 0xB376 # 0 +0x894B 0xB377 # 0 +0x894C 0xB379 # 0 +0x894D 0xB37A # 0 +0x894E 0xB37B # 0 +0x894F 0xB37C # 0 +0x8950 0xB37D # 0 +0x8951 0xB37E # 0 +0x8952 0xB37F # 0 +0x8953 0xB382 # 0 +0x8954 0xB386 # 0 +0x8955 0xB387 # 0 +0x8956 0xB388 # 0 +0x8957 0xB389 # 0 +0x8958 0xB38A # 0 +0x8959 0xB38B # 0 +0x895A 0xB38D # 0 +0x8961 0xB38E # 0 +0x8962 0xB38F # 0 +0x8963 0xB391 # 0 +0x8964 0xB392 # 0 +0x8965 0xB393 # 0 +0x8966 0xB395 # 0 +0x8967 0xB396 # 0 +0x8968 0xB397 # 0 +0x8969 0xB398 # 0 +0x896A 0xB399 # 0 +0x896B 0xB39A # 0 +0x896C 0xB39B # 0 +0x896D 0xB39C # 0 +0x896E 0xB39D # 0 +0x896F 0xB39E # 0 +0x8970 0xB39F # 0 +0x8971 0xB3A2 # 0 +0x8972 0xB3A3 # 0 +0x8973 0xB3A4 # 0 +0x8974 0xB3A5 # 0 +0x8975 0xB3A6 # 0 +0x8976 0xB3A7 # 0 +0x8977 0xB3A9 # 0 +0x8978 0xB3AA # 0 +0x8979 0xB3AB # 0 +0x897A 0xB3AD # 0 +0x8981 0xB3AE # 0 +0x8982 0xB3AF # 0 +0x8983 0xB3B0 # 0 +0x8984 0xB3B1 # 0 +0x8985 0xB3B2 # 0 +0x8986 0xB3B3 # 0 +0x8987 0xB3B4 # 0 +0x8988 0xB3B5 # 0 +0x8989 0xB3B6 # 0 +0x898A 0xB3B7 # 0 +0x898B 0xB3B8 # 0 +0x898C 0xB3B9 # 0 +0x898D 0xB3BA # 0 +0x898E 0xB3BB # 0 +0x898F 0xB3BC # 0 +0x8990 0xB3BD # 0 +0x8991 0xB3BE # 0 +0x8992 0xB3BF # 0 +0x8993 0xB3C0 # 0 +0x8994 0xB3C1 # 0 +0x8995 0xB3C2 # 0 +0x8996 0xB3C3 # 0 +0x8997 0xB3C6 # 0 +0x8998 0xB3C7 # 0 +0x8999 0xB3C9 # 0 +0x899A 0xB3CA # 0 +0x899B 0xB3CD # 0 +0x899C 0xB3CF # 0 +0x899D 0xB3D1 # 0 +0x899E 0xB3D2 # 0 +0x899F 0xB3D3 # 0 +0x89A0 0xB3D6 # 0 +0x89A1 0xB3D8 # 0 +0x89A2 0xB3DA # 0 +0x89A3 0xB3DC # 0 +0x89A4 0xB3DE # 0 +0x89A5 0xB3DF # 0 +0x89A6 0xB3E1 # 0 +0x89A7 0xB3E2 # 0 +0x89A8 0xB3E3 # 0 +0x89A9 0xB3E5 # 0 +0x89AA 0xB3E6 # 0 +0x89AB 0xB3E7 # 0 +0x89AC 0xB3E9 # 0 +0x89AD 0xB3EA # 0 +0x89AE 0xB3EB # 0 +0x89AF 0xB3EC # 0 +0x89B0 0xB3ED # 0 +0x89B1 0xB3EE # 0 +0x89B2 0xB3EF # 0 +0x89B3 0xB3F0 # 0 +0x89B4 0xB3F1 # 0 +0x89B5 0xB3F2 # 0 +0x89B6 0xB3F3 # 0 +0x89B7 0xB3F4 # 0 +0x89B8 0xB3F5 # 0 +0x89B9 0xB3F6 # 0 +0x89BA 0xB3F7 # 0 +0x89BB 0xB3F8 # 0 +0x89BC 0xB3F9 # 0 +0x89BD 0xB3FA # 0 +0x89BE 0xB3FB # 0 +0x89BF 0xB3FD # 0 +0x89C0 0xB3FE # 0 +0x89C1 0xB3FF # 0 +0x89C2 0xB400 # 0 +0x89C3 0xB401 # 0 +0x89C4 0xB402 # 0 +0x89C5 0xB403 # 0 +0x89C6 0xB404 # 0 +0x89C7 0xB405 # 0 +0x89C8 0xB406 # 0 +0x89C9 0xB407 # 0 +0x89CA 0xB408 # 0 +0x89CB 0xB409 # 0 +0x89CC 0xB40A # 0 +0x89CD 0xB40B # 0 +0x89CE 0xB40C # 0 +0x89CF 0xB40D # 0 +0x89D0 0xB40E # 0 +0x89D1 0xB40F # 0 +0x89D2 0xB411 # 0 +0x89D3 0xB412 # 0 +0x89D4 0xB413 # 0 +0x89D5 0xB414 # 0 +0x89D6 0xB415 # 0 +0x89D7 0xB416 # 0 +0x89D8 0xB417 # 0 +0x89D9 0xB419 # 0 +0x89DA 0xB41A # 0 +0x89DB 0xB41B # 0 +0x89DC 0xB41D # 0 +0x89DD 0xB41E # 0 +0x89DE 0xB41F # 0 +0x89DF 0xB421 # 0 +0x89E0 0xB422 # 0 +0x89E1 0xB423 # 0 +0x89E2 0xB424 # 0 +0x89E3 0xB425 # 0 +0x89E4 0xB426 # 0 +0x89E5 0xB427 # 0 +0x89E6 0xB42A # 0 +0x89E7 0xB42C # 0 +0x89E8 0xB42D # 0 +0x89E9 0xB42E # 0 +0x89EA 0xB42F # 0 +0x89EB 0xB430 # 0 +0x89EC 0xB431 # 0 +0x89ED 0xB432 # 0 +0x89EE 0xB433 # 0 +0x89EF 0xB435 # 0 +0x89F0 0xB436 # 0 +0x89F1 0xB437 # 0 +0x89F2 0xB438 # 0 +0x89F3 0xB439 # 0 +0x89F4 0xB43A # 0 +0x89F5 0xB43B # 0 +0x89F6 0xB43C # 0 +0x89F7 0xB43D # 0 +0x89F8 0xB43E # 0 +0x89F9 0xB43F # 0 +0x89FA 0xB440 # 0 +0x89FB 0xB441 # 0 +0x89FC 0xB442 # 0 +0x89FD 0xB443 # 0 +0x89FE 0xB444 # 0 +0x8A41 0xB445 # 0 +0x8A42 0xB446 # 0 +0x8A43 0xB447 # 0 +0x8A44 0xB448 # 0 +0x8A45 0xB449 # 0 +0x8A46 0xB44A # 0 +0x8A47 0xB44B # 0 +0x8A48 0xB44C # 0 +0x8A49 0xB44D # 0 +0x8A4A 0xB44E # 0 +0x8A4B 0xB44F # 0 +0x8A4C 0xB452 # 0 +0x8A4D 0xB453 # 0 +0x8A4E 0xB455 # 0 +0x8A4F 0xB456 # 0 +0x8A50 0xB457 # 0 +0x8A51 0xB459 # 0 +0x8A52 0xB45A # 0 +0x8A53 0xB45B # 0 +0x8A54 0xB45C # 0 +0x8A55 0xB45D # 0 +0x8A56 0xB45E # 0 +0x8A57 0xB45F # 0 +0x8A58 0xB462 # 0 +0x8A59 0xB464 # 0 +0x8A5A 0xB466 # 0 +0x8A61 0xB467 # 0 +0x8A62 0xB468 # 0 +0x8A63 0xB469 # 0 +0x8A64 0xB46A # 0 +0x8A65 0xB46B # 0 +0x8A66 0xB46D # 0 +0x8A67 0xB46E # 0 +0x8A68 0xB46F # 0 +0x8A69 0xB470 # 0 +0x8A6A 0xB471 # 0 +0x8A6B 0xB472 # 0 +0x8A6C 0xB473 # 0 +0x8A6D 0xB474 # 0 +0x8A6E 0xB475 # 0 +0x8A6F 0xB476 # 0 +0x8A70 0xB477 # 0 +0x8A71 0xB478 # 0 +0x8A72 0xB479 # 0 +0x8A73 0xB47A # 0 +0x8A74 0xB47B # 0 +0x8A75 0xB47C # 0 +0x8A76 0xB47D # 0 +0x8A77 0xB47E # 0 +0x8A78 0xB47F # 0 +0x8A79 0xB481 # 0 +0x8A7A 0xB482 # 0 +0x8A81 0xB483 # 0 +0x8A82 0xB484 # 0 +0x8A83 0xB485 # 0 +0x8A84 0xB486 # 0 +0x8A85 0xB487 # 0 +0x8A86 0xB489 # 0 +0x8A87 0xB48A # 0 +0x8A88 0xB48B # 0 +0x8A89 0xB48C # 0 +0x8A8A 0xB48D # 0 +0x8A8B 0xB48E # 0 +0x8A8C 0xB48F # 0 +0x8A8D 0xB490 # 0 +0x8A8E 0xB491 # 0 +0x8A8F 0xB492 # 0 +0x8A90 0xB493 # 0 +0x8A91 0xB494 # 0 +0x8A92 0xB495 # 0 +0x8A93 0xB496 # 0 +0x8A94 0xB497 # 0 +0x8A95 0xB498 # 0 +0x8A96 0xB499 # 0 +0x8A97 0xB49A # 0 +0x8A98 0xB49B # 0 +0x8A99 0xB49C # 0 +0x8A9A 0xB49E # 0 +0x8A9B 0xB49F # 0 +0x8A9C 0xB4A0 # 0 +0x8A9D 0xB4A1 # 0 +0x8A9E 0xB4A2 # 0 +0x8A9F 0xB4A3 # 0 +0x8AA0 0xB4A5 # 0 +0x8AA1 0xB4A6 # 0 +0x8AA2 0xB4A7 # 0 +0x8AA3 0xB4A9 # 0 +0x8AA4 0xB4AA # 0 +0x8AA5 0xB4AB # 0 +0x8AA6 0xB4AD # 0 +0x8AA7 0xB4AE # 0 +0x8AA8 0xB4AF # 0 +0x8AA9 0xB4B0 # 0 +0x8AAA 0xB4B1 # 0 +0x8AAB 0xB4B2 # 0 +0x8AAC 0xB4B3 # 0 +0x8AAD 0xB4B4 # 0 +0x8AAE 0xB4B6 # 0 +0x8AAF 0xB4B8 # 0 +0x8AB0 0xB4BA # 0 +0x8AB1 0xB4BB # 0 +0x8AB2 0xB4BC # 0 +0x8AB3 0xB4BD # 0 +0x8AB4 0xB4BE # 0 +0x8AB5 0xB4BF # 0 +0x8AB6 0xB4C1 # 0 +0x8AB7 0xB4C2 # 0 +0x8AB8 0xB4C3 # 0 +0x8AB9 0xB4C5 # 0 +0x8ABA 0xB4C6 # 0 +0x8ABB 0xB4C7 # 0 +0x8ABC 0xB4C9 # 0 +0x8ABD 0xB4CA # 0 +0x8ABE 0xB4CB # 0 +0x8ABF 0xB4CC # 0 +0x8AC0 0xB4CD # 0 +0x8AC1 0xB4CE # 0 +0x8AC2 0xB4CF # 0 +0x8AC3 0xB4D1 # 0 +0x8AC4 0xB4D2 # 0 +0x8AC5 0xB4D3 # 0 +0x8AC6 0xB4D4 # 0 +0x8AC7 0xB4D6 # 0 +0x8AC8 0xB4D7 # 0 +0x8AC9 0xB4D8 # 0 +0x8ACA 0xB4D9 # 0 +0x8ACB 0xB4DA # 0 +0x8ACC 0xB4DB # 0 +0x8ACD 0xB4DE # 0 +0x8ACE 0xB4DF # 0 +0x8ACF 0xB4E1 # 0 +0x8AD0 0xB4E2 # 0 +0x8AD1 0xB4E5 # 0 +0x8AD2 0xB4E7 # 0 +0x8AD3 0xB4E8 # 0 +0x8AD4 0xB4E9 # 0 +0x8AD5 0xB4EA # 0 +0x8AD6 0xB4EB # 0 +0x8AD7 0xB4EE # 0 +0x8AD8 0xB4F0 # 0 +0x8AD9 0xB4F2 # 0 +0x8ADA 0xB4F3 # 0 +0x8ADB 0xB4F4 # 0 +0x8ADC 0xB4F5 # 0 +0x8ADD 0xB4F6 # 0 +0x8ADE 0xB4F7 # 0 +0x8ADF 0xB4F9 # 0 +0x8AE0 0xB4FA # 0 +0x8AE1 0xB4FB # 0 +0x8AE2 0xB4FC # 0 +0x8AE3 0xB4FD # 0 +0x8AE4 0xB4FE # 0 +0x8AE5 0xB4FF # 0 +0x8AE6 0xB500 # 0 +0x8AE7 0xB501 # 0 +0x8AE8 0xB502 # 0 +0x8AE9 0xB503 # 0 +0x8AEA 0xB504 # 0 +0x8AEB 0xB505 # 0 +0x8AEC 0xB506 # 0 +0x8AED 0xB507 # 0 +0x8AEE 0xB508 # 0 +0x8AEF 0xB509 # 0 +0x8AF0 0xB50A # 0 +0x8AF1 0xB50B # 0 +0x8AF2 0xB50C # 0 +0x8AF3 0xB50D # 0 +0x8AF4 0xB50E # 0 +0x8AF5 0xB50F # 0 +0x8AF6 0xB510 # 0 +0x8AF7 0xB511 # 0 +0x8AF8 0xB512 # 0 +0x8AF9 0xB513 # 0 +0x8AFA 0xB516 # 0 +0x8AFB 0xB517 # 0 +0x8AFC 0xB519 # 0 +0x8AFD 0xB51A # 0 +0x8AFE 0xB51D # 0 +0x8B41 0xB51E # 0 +0x8B42 0xB51F # 0 +0x8B43 0xB520 # 0 +0x8B44 0xB521 # 0 +0x8B45 0xB522 # 0 +0x8B46 0xB523 # 0 +0x8B47 0xB526 # 0 +0x8B48 0xB52B # 0 +0x8B49 0xB52C # 0 +0x8B4A 0xB52D # 0 +0x8B4B 0xB52E # 0 +0x8B4C 0xB52F # 0 +0x8B4D 0xB532 # 0 +0x8B4E 0xB533 # 0 +0x8B4F 0xB535 # 0 +0x8B50 0xB536 # 0 +0x8B51 0xB537 # 0 +0x8B52 0xB539 # 0 +0x8B53 0xB53A # 0 +0x8B54 0xB53B # 0 +0x8B55 0xB53C # 0 +0x8B56 0xB53D # 0 +0x8B57 0xB53E # 0 +0x8B58 0xB53F # 0 +0x8B59 0xB542 # 0 +0x8B5A 0xB546 # 0 +0x8B61 0xB547 # 0 +0x8B62 0xB548 # 0 +0x8B63 0xB549 # 0 +0x8B64 0xB54A # 0 +0x8B65 0xB54E # 0 +0x8B66 0xB54F # 0 +0x8B67 0xB551 # 0 +0x8B68 0xB552 # 0 +0x8B69 0xB553 # 0 +0x8B6A 0xB555 # 0 +0x8B6B 0xB556 # 0 +0x8B6C 0xB557 # 0 +0x8B6D 0xB558 # 0 +0x8B6E 0xB559 # 0 +0x8B6F 0xB55A # 0 +0x8B70 0xB55B # 0 +0x8B71 0xB55E # 0 +0x8B72 0xB562 # 0 +0x8B73 0xB563 # 0 +0x8B74 0xB564 # 0 +0x8B75 0xB565 # 0 +0x8B76 0xB566 # 0 +0x8B77 0xB567 # 0 +0x8B78 0xB568 # 0 +0x8B79 0xB569 # 0 +0x8B7A 0xB56A # 0 +0x8B81 0xB56B # 0 +0x8B82 0xB56C # 0 +0x8B83 0xB56D # 0 +0x8B84 0xB56E # 0 +0x8B85 0xB56F # 0 +0x8B86 0xB570 # 0 +0x8B87 0xB571 # 0 +0x8B88 0xB572 # 0 +0x8B89 0xB573 # 0 +0x8B8A 0xB574 # 0 +0x8B8B 0xB575 # 0 +0x8B8C 0xB576 # 0 +0x8B8D 0xB577 # 0 +0x8B8E 0xB578 # 0 +0x8B8F 0xB579 # 0 +0x8B90 0xB57A # 0 +0x8B91 0xB57B # 0 +0x8B92 0xB57C # 0 +0x8B93 0xB57D # 0 +0x8B94 0xB57E # 0 +0x8B95 0xB57F # 0 +0x8B96 0xB580 # 0 +0x8B97 0xB581 # 0 +0x8B98 0xB582 # 0 +0x8B99 0xB583 # 0 +0x8B9A 0xB584 # 0 +0x8B9B 0xB585 # 0 +0x8B9C 0xB586 # 0 +0x8B9D 0xB587 # 0 +0x8B9E 0xB588 # 0 +0x8B9F 0xB589 # 0 +0x8BA0 0xB58A # 0 +0x8BA1 0xB58B # 0 +0x8BA2 0xB58C # 0 +0x8BA3 0xB58D # 0 +0x8BA4 0xB58E # 0 +0x8BA5 0xB58F # 0 +0x8BA6 0xB590 # 0 +0x8BA7 0xB591 # 0 +0x8BA8 0xB592 # 0 +0x8BA9 0xB593 # 0 +0x8BAA 0xB594 # 0 +0x8BAB 0xB595 # 0 +0x8BAC 0xB596 # 0 +0x8BAD 0xB597 # 0 +0x8BAE 0xB598 # 0 +0x8BAF 0xB599 # 0 +0x8BB0 0xB59A # 0 +0x8BB1 0xB59B # 0 +0x8BB2 0xB59C # 0 +0x8BB3 0xB59D # 0 +0x8BB4 0xB59E # 0 +0x8BB5 0xB59F # 0 +0x8BB6 0xB5A2 # 0 +0x8BB7 0xB5A3 # 0 +0x8BB8 0xB5A5 # 0 +0x8BB9 0xB5A6 # 0 +0x8BBA 0xB5A7 # 0 +0x8BBB 0xB5A9 # 0 +0x8BBC 0xB5AC # 0 +0x8BBD 0xB5AD # 0 +0x8BBE 0xB5AE # 0 +0x8BBF 0xB5AF # 0 +0x8BC0 0xB5B2 # 0 +0x8BC1 0xB5B6 # 0 +0x8BC2 0xB5B7 # 0 +0x8BC3 0xB5B8 # 0 +0x8BC4 0xB5B9 # 0 +0x8BC5 0xB5BA # 0 +0x8BC6 0xB5BE # 0 +0x8BC7 0xB5BF # 0 +0x8BC8 0xB5C1 # 0 +0x8BC9 0xB5C2 # 0 +0x8BCA 0xB5C3 # 0 +0x8BCB 0xB5C5 # 0 +0x8BCC 0xB5C6 # 0 +0x8BCD 0xB5C7 # 0 +0x8BCE 0xB5C8 # 0 +0x8BCF 0xB5C9 # 0 +0x8BD0 0xB5CA # 0 +0x8BD1 0xB5CB # 0 +0x8BD2 0xB5CE # 0 +0x8BD3 0xB5D2 # 0 +0x8BD4 0xB5D3 # 0 +0x8BD5 0xB5D4 # 0 +0x8BD6 0xB5D5 # 0 +0x8BD7 0xB5D6 # 0 +0x8BD8 0xB5D7 # 0 +0x8BD9 0xB5D9 # 0 +0x8BDA 0xB5DA # 0 +0x8BDB 0xB5DB # 0 +0x8BDC 0xB5DC # 0 +0x8BDD 0xB5DD # 0 +0x8BDE 0xB5DE # 0 +0x8BDF 0xB5DF # 0 +0x8BE0 0xB5E0 # 0 +0x8BE1 0xB5E1 # 0 +0x8BE2 0xB5E2 # 0 +0x8BE3 0xB5E3 # 0 +0x8BE4 0xB5E4 # 0 +0x8BE5 0xB5E5 # 0 +0x8BE6 0xB5E6 # 0 +0x8BE7 0xB5E7 # 0 +0x8BE8 0xB5E8 # 0 +0x8BE9 0xB5E9 # 0 +0x8BEA 0xB5EA # 0 +0x8BEB 0xB5EB # 0 +0x8BEC 0xB5ED # 0 +0x8BED 0xB5EE # 0 +0x8BEE 0xB5EF # 0 +0x8BEF 0xB5F0 # 0 +0x8BF0 0xB5F1 # 0 +0x8BF1 0xB5F2 # 0 +0x8BF2 0xB5F3 # 0 +0x8BF3 0xB5F4 # 0 +0x8BF4 0xB5F5 # 0 +0x8BF5 0xB5F6 # 0 +0x8BF6 0xB5F7 # 0 +0x8BF7 0xB5F8 # 0 +0x8BF8 0xB5F9 # 0 +0x8BF9 0xB5FA # 0 +0x8BFA 0xB5FB # 0 +0x8BFB 0xB5FC # 0 +0x8BFC 0xB5FD # 0 +0x8BFD 0xB5FE # 0 +0x8BFE 0xB5FF # 0 +0x8C41 0xB600 # 0 +0x8C42 0xB601 # 0 +0x8C43 0xB602 # 0 +0x8C44 0xB603 # 0 +0x8C45 0xB604 # 0 +0x8C46 0xB605 # 0 +0x8C47 0xB606 # 0 +0x8C48 0xB607 # 0 +0x8C49 0xB608 # 0 +0x8C4A 0xB609 # 0 +0x8C4B 0xB60A # 0 +0x8C4C 0xB60B # 0 +0x8C4D 0xB60C # 0 +0x8C4E 0xB60D # 0 +0x8C4F 0xB60E # 0 +0x8C50 0xB60F # 0 +0x8C51 0xB612 # 0 +0x8C52 0xB613 # 0 +0x8C53 0xB615 # 0 +0x8C54 0xB616 # 0 +0x8C55 0xB617 # 0 +0x8C56 0xB619 # 0 +0x8C57 0xB61A # 0 +0x8C58 0xB61B # 0 +0x8C59 0xB61C # 0 +0x8C5A 0xB61D # 0 +0x8C61 0xB61E # 0 +0x8C62 0xB61F # 0 +0x8C63 0xB620 # 0 +0x8C64 0xB621 # 0 +0x8C65 0xB622 # 0 +0x8C66 0xB623 # 0 +0x8C67 0xB624 # 0 +0x8C68 0xB626 # 0 +0x8C69 0xB627 # 0 +0x8C6A 0xB628 # 0 +0x8C6B 0xB629 # 0 +0x8C6C 0xB62A # 0 +0x8C6D 0xB62B # 0 +0x8C6E 0xB62D # 0 +0x8C6F 0xB62E # 0 +0x8C70 0xB62F # 0 +0x8C71 0xB630 # 0 +0x8C72 0xB631 # 0 +0x8C73 0xB632 # 0 +0x8C74 0xB633 # 0 +0x8C75 0xB635 # 0 +0x8C76 0xB636 # 0 +0x8C77 0xB637 # 0 +0x8C78 0xB638 # 0 +0x8C79 0xB639 # 0 +0x8C7A 0xB63A # 0 +0x8C81 0xB63B # 0 +0x8C82 0xB63C # 0 +0x8C83 0xB63D # 0 +0x8C84 0xB63E # 0 +0x8C85 0xB63F # 0 +0x8C86 0xB640 # 0 +0x8C87 0xB641 # 0 +0x8C88 0xB642 # 0 +0x8C89 0xB643 # 0 +0x8C8A 0xB644 # 0 +0x8C8B 0xB645 # 0 +0x8C8C 0xB646 # 0 +0x8C8D 0xB647 # 0 +0x8C8E 0xB649 # 0 +0x8C8F 0xB64A # 0 +0x8C90 0xB64B # 0 +0x8C91 0xB64C # 0 +0x8C92 0xB64D # 0 +0x8C93 0xB64E # 0 +0x8C94 0xB64F # 0 +0x8C95 0xB650 # 0 +0x8C96 0xB651 # 0 +0x8C97 0xB652 # 0 +0x8C98 0xB653 # 0 +0x8C99 0xB654 # 0 +0x8C9A 0xB655 # 0 +0x8C9B 0xB656 # 0 +0x8C9C 0xB657 # 0 +0x8C9D 0xB658 # 0 +0x8C9E 0xB659 # 0 +0x8C9F 0xB65A # 0 +0x8CA0 0xB65B # 0 +0x8CA1 0xB65C # 0 +0x8CA2 0xB65D # 0 +0x8CA3 0xB65E # 0 +0x8CA4 0xB65F # 0 +0x8CA5 0xB660 # 0 +0x8CA6 0xB661 # 0 +0x8CA7 0xB662 # 0 +0x8CA8 0xB663 # 0 +0x8CA9 0xB665 # 0 +0x8CAA 0xB666 # 0 +0x8CAB 0xB667 # 0 +0x8CAC 0xB669 # 0 +0x8CAD 0xB66A # 0 +0x8CAE 0xB66B # 0 +0x8CAF 0xB66C # 0 +0x8CB0 0xB66D # 0 +0x8CB1 0xB66E # 0 +0x8CB2 0xB66F # 0 +0x8CB3 0xB670 # 0 +0x8CB4 0xB671 # 0 +0x8CB5 0xB672 # 0 +0x8CB6 0xB673 # 0 +0x8CB7 0xB674 # 0 +0x8CB8 0xB675 # 0 +0x8CB9 0xB676 # 0 +0x8CBA 0xB677 # 0 +0x8CBB 0xB678 # 0 +0x8CBC 0xB679 # 0 +0x8CBD 0xB67A # 0 +0x8CBE 0xB67B # 0 +0x8CBF 0xB67C # 0 +0x8CC0 0xB67D # 0 +0x8CC1 0xB67E # 0 +0x8CC2 0xB67F # 0 +0x8CC3 0xB680 # 0 +0x8CC4 0xB681 # 0 +0x8CC5 0xB682 # 0 +0x8CC6 0xB683 # 0 +0x8CC7 0xB684 # 0 +0x8CC8 0xB685 # 0 +0x8CC9 0xB686 # 0 +0x8CCA 0xB687 # 0 +0x8CCB 0xB688 # 0 +0x8CCC 0xB689 # 0 +0x8CCD 0xB68A # 0 +0x8CCE 0xB68B # 0 +0x8CCF 0xB68C # 0 +0x8CD0 0xB68D # 0 +0x8CD1 0xB68E # 0 +0x8CD2 0xB68F # 0 +0x8CD3 0xB690 # 0 +0x8CD4 0xB691 # 0 +0x8CD5 0xB692 # 0 +0x8CD6 0xB693 # 0 +0x8CD7 0xB694 # 0 +0x8CD8 0xB695 # 0 +0x8CD9 0xB696 # 0 +0x8CDA 0xB697 # 0 +0x8CDB 0xB698 # 0 +0x8CDC 0xB699 # 0 +0x8CDD 0xB69A # 0 +0x8CDE 0xB69B # 0 +0x8CDF 0xB69E # 0 +0x8CE0 0xB69F # 0 +0x8CE1 0xB6A1 # 0 +0x8CE2 0xB6A2 # 0 +0x8CE3 0xB6A3 # 0 +0x8CE4 0xB6A5 # 0 +0x8CE5 0xB6A6 # 0 +0x8CE6 0xB6A7 # 0 +0x8CE7 0xB6A8 # 0 +0x8CE8 0xB6A9 # 0 +0x8CE9 0xB6AA # 0 +0x8CEA 0xB6AD # 0 +0x8CEB 0xB6AE # 0 +0x8CEC 0xB6AF # 0 +0x8CED 0xB6B0 # 0 +0x8CEE 0xB6B2 # 0 +0x8CEF 0xB6B3 # 0 +0x8CF0 0xB6B4 # 0 +0x8CF1 0xB6B5 # 0 +0x8CF2 0xB6B6 # 0 +0x8CF3 0xB6B7 # 0 +0x8CF4 0xB6B8 # 0 +0x8CF5 0xB6B9 # 0 +0x8CF6 0xB6BA # 0 +0x8CF7 0xB6BB # 0 +0x8CF8 0xB6BC # 0 +0x8CF9 0xB6BD # 0 +0x8CFA 0xB6BE # 0 +0x8CFB 0xB6BF # 0 +0x8CFC 0xB6C0 # 0 +0x8CFD 0xB6C1 # 0 +0x8CFE 0xB6C2 # 0 +0x8D41 0xB6C3 # 0 +0x8D42 0xB6C4 # 0 +0x8D43 0xB6C5 # 0 +0x8D44 0xB6C6 # 0 +0x8D45 0xB6C7 # 0 +0x8D46 0xB6C8 # 0 +0x8D47 0xB6C9 # 0 +0x8D48 0xB6CA # 0 +0x8D49 0xB6CB # 0 +0x8D4A 0xB6CC # 0 +0x8D4B 0xB6CD # 0 +0x8D4C 0xB6CE # 0 +0x8D4D 0xB6CF # 0 +0x8D4E 0xB6D0 # 0 +0x8D4F 0xB6D1 # 0 +0x8D50 0xB6D2 # 0 +0x8D51 0xB6D3 # 0 +0x8D52 0xB6D5 # 0 +0x8D53 0xB6D6 # 0 +0x8D54 0xB6D7 # 0 +0x8D55 0xB6D8 # 0 +0x8D56 0xB6D9 # 0 +0x8D57 0xB6DA # 0 +0x8D58 0xB6DB # 0 +0x8D59 0xB6DC # 0 +0x8D5A 0xB6DD # 0 +0x8D61 0xB6DE # 0 +0x8D62 0xB6DF # 0 +0x8D63 0xB6E0 # 0 +0x8D64 0xB6E1 # 0 +0x8D65 0xB6E2 # 0 +0x8D66 0xB6E3 # 0 +0x8D67 0xB6E4 # 0 +0x8D68 0xB6E5 # 0 +0x8D69 0xB6E6 # 0 +0x8D6A 0xB6E7 # 0 +0x8D6B 0xB6E8 # 0 +0x8D6C 0xB6E9 # 0 +0x8D6D 0xB6EA # 0 +0x8D6E 0xB6EB # 0 +0x8D6F 0xB6EC # 0 +0x8D70 0xB6ED # 0 +0x8D71 0xB6EE # 0 +0x8D72 0xB6EF # 0 +0x8D73 0xB6F1 # 0 +0x8D74 0xB6F2 # 0 +0x8D75 0xB6F3 # 0 +0x8D76 0xB6F5 # 0 +0x8D77 0xB6F6 # 0 +0x8D78 0xB6F7 # 0 +0x8D79 0xB6F9 # 0 +0x8D7A 0xB6FA # 0 +0x8D81 0xB6FB # 0 +0x8D82 0xB6FC # 0 +0x8D83 0xB6FD # 0 +0x8D84 0xB6FE # 0 +0x8D85 0xB6FF # 0 +0x8D86 0xB702 # 0 +0x8D87 0xB703 # 0 +0x8D88 0xB704 # 0 +0x8D89 0xB706 # 0 +0x8D8A 0xB707 # 0 +0x8D8B 0xB708 # 0 +0x8D8C 0xB709 # 0 +0x8D8D 0xB70A # 0 +0x8D8E 0xB70B # 0 +0x8D8F 0xB70C # 0 +0x8D90 0xB70D # 0 +0x8D91 0xB70E # 0 +0x8D92 0xB70F # 0 +0x8D93 0xB710 # 0 +0x8D94 0xB711 # 0 +0x8D95 0xB712 # 0 +0x8D96 0xB713 # 0 +0x8D97 0xB714 # 0 +0x8D98 0xB715 # 0 +0x8D99 0xB716 # 0 +0x8D9A 0xB717 # 0 +0x8D9B 0xB718 # 0 +0x8D9C 0xB719 # 0 +0x8D9D 0xB71A # 0 +0x8D9E 0xB71B # 0 +0x8D9F 0xB71C # 0 +0x8DA0 0xB71D # 0 +0x8DA1 0xB71E # 0 +0x8DA2 0xB71F # 0 +0x8DA3 0xB720 # 0 +0x8DA4 0xB721 # 0 +0x8DA5 0xB722 # 0 +0x8DA6 0xB723 # 0 +0x8DA7 0xB724 # 0 +0x8DA8 0xB725 # 0 +0x8DA9 0xB726 # 0 +0x8DAA 0xB727 # 0 +0x8DAB 0xB72A # 0 +0x8DAC 0xB72B # 0 +0x8DAD 0xB72D # 0 +0x8DAE 0xB72E # 0 +0x8DAF 0xB731 # 0 +0x8DB0 0xB732 # 0 +0x8DB1 0xB733 # 0 +0x8DB2 0xB734 # 0 +0x8DB3 0xB735 # 0 +0x8DB4 0xB736 # 0 +0x8DB5 0xB737 # 0 +0x8DB6 0xB73A # 0 +0x8DB7 0xB73C # 0 +0x8DB8 0xB73D # 0 +0x8DB9 0xB73E # 0 +0x8DBA 0xB73F # 0 +0x8DBB 0xB740 # 0 +0x8DBC 0xB741 # 0 +0x8DBD 0xB742 # 0 +0x8DBE 0xB743 # 0 +0x8DBF 0xB745 # 0 +0x8DC0 0xB746 # 0 +0x8DC1 0xB747 # 0 +0x8DC2 0xB749 # 0 +0x8DC3 0xB74A # 0 +0x8DC4 0xB74B # 0 +0x8DC5 0xB74D # 0 +0x8DC6 0xB74E # 0 +0x8DC7 0xB74F # 0 +0x8DC8 0xB750 # 0 +0x8DC9 0xB751 # 0 +0x8DCA 0xB752 # 0 +0x8DCB 0xB753 # 0 +0x8DCC 0xB756 # 0 +0x8DCD 0xB757 # 0 +0x8DCE 0xB758 # 0 +0x8DCF 0xB759 # 0 +0x8DD0 0xB75A # 0 +0x8DD1 0xB75B # 0 +0x8DD2 0xB75C # 0 +0x8DD3 0xB75D # 0 +0x8DD4 0xB75E # 0 +0x8DD5 0xB75F # 0 +0x8DD6 0xB761 # 0 +0x8DD7 0xB762 # 0 +0x8DD8 0xB763 # 0 +0x8DD9 0xB765 # 0 +0x8DDA 0xB766 # 0 +0x8DDB 0xB767 # 0 +0x8DDC 0xB769 # 0 +0x8DDD 0xB76A # 0 +0x8DDE 0xB76B # 0 +0x8DDF 0xB76C # 0 +0x8DE0 0xB76D # 0 +0x8DE1 0xB76E # 0 +0x8DE2 0xB76F # 0 +0x8DE3 0xB772 # 0 +0x8DE4 0xB774 # 0 +0x8DE5 0xB776 # 0 +0x8DE6 0xB777 # 0 +0x8DE7 0xB778 # 0 +0x8DE8 0xB779 # 0 +0x8DE9 0xB77A # 0 +0x8DEA 0xB77B # 0 +0x8DEB 0xB77E # 0 +0x8DEC 0xB77F # 0 +0x8DED 0xB781 # 0 +0x8DEE 0xB782 # 0 +0x8DEF 0xB783 # 0 +0x8DF0 0xB785 # 0 +0x8DF1 0xB786 # 0 +0x8DF2 0xB787 # 0 +0x8DF3 0xB788 # 0 +0x8DF4 0xB789 # 0 +0x8DF5 0xB78A # 0 +0x8DF6 0xB78B # 0 +0x8DF7 0xB78E # 0 +0x8DF8 0xB793 # 0 +0x8DF9 0xB794 # 0 +0x8DFA 0xB795 # 0 +0x8DFB 0xB79A # 0 +0x8DFC 0xB79B # 0 +0x8DFD 0xB79D # 0 +0x8DFE 0xB79E # 0 +0x8E41 0xB79F # 0 +0x8E42 0xB7A1 # 0 +0x8E43 0xB7A2 # 0 +0x8E44 0xB7A3 # 0 +0x8E45 0xB7A4 # 0 +0x8E46 0xB7A5 # 0 +0x8E47 0xB7A6 # 0 +0x8E48 0xB7A7 # 0 +0x8E49 0xB7AA # 0 +0x8E4A 0xB7AE # 0 +0x8E4B 0xB7AF # 0 +0x8E4C 0xB7B0 # 0 +0x8E4D 0xB7B1 # 0 +0x8E4E 0xB7B2 # 0 +0x8E4F 0xB7B3 # 0 +0x8E50 0xB7B6 # 0 +0x8E51 0xB7B7 # 0 +0x8E52 0xB7B9 # 0 +0x8E53 0xB7BA # 0 +0x8E54 0xB7BB # 0 +0x8E55 0xB7BC # 0 +0x8E56 0xB7BD # 0 +0x8E57 0xB7BE # 0 +0x8E58 0xB7BF # 0 +0x8E59 0xB7C0 # 0 +0x8E5A 0xB7C1 # 0 +0x8E61 0xB7C2 # 0 +0x8E62 0xB7C3 # 0 +0x8E63 0xB7C4 # 0 +0x8E64 0xB7C5 # 0 +0x8E65 0xB7C6 # 0 +0x8E66 0xB7C8 # 0 +0x8E67 0xB7CA # 0 +0x8E68 0xB7CB # 0 +0x8E69 0xB7CC # 0 +0x8E6A 0xB7CD # 0 +0x8E6B 0xB7CE # 0 +0x8E6C 0xB7CF # 0 +0x8E6D 0xB7D0 # 0 +0x8E6E 0xB7D1 # 0 +0x8E6F 0xB7D2 # 0 +0x8E70 0xB7D3 # 0 +0x8E71 0xB7D4 # 0 +0x8E72 0xB7D5 # 0 +0x8E73 0xB7D6 # 0 +0x8E74 0xB7D7 # 0 +0x8E75 0xB7D8 # 0 +0x8E76 0xB7D9 # 0 +0x8E77 0xB7DA # 0 +0x8E78 0xB7DB # 0 +0x8E79 0xB7DC # 0 +0x8E7A 0xB7DD # 0 +0x8E81 0xB7DE # 0 +0x8E82 0xB7DF # 0 +0x8E83 0xB7E0 # 0 +0x8E84 0xB7E1 # 0 +0x8E85 0xB7E2 # 0 +0x8E86 0xB7E3 # 0 +0x8E87 0xB7E4 # 0 +0x8E88 0xB7E5 # 0 +0x8E89 0xB7E6 # 0 +0x8E8A 0xB7E7 # 0 +0x8E8B 0xB7E8 # 0 +0x8E8C 0xB7E9 # 0 +0x8E8D 0xB7EA # 0 +0x8E8E 0xB7EB # 0 +0x8E8F 0xB7EE # 0 +0x8E90 0xB7EF # 0 +0x8E91 0xB7F1 # 0 +0x8E92 0xB7F2 # 0 +0x8E93 0xB7F3 # 0 +0x8E94 0xB7F5 # 0 +0x8E95 0xB7F6 # 0 +0x8E96 0xB7F7 # 0 +0x8E97 0xB7F8 # 0 +0x8E98 0xB7F9 # 0 +0x8E99 0xB7FA # 0 +0x8E9A 0xB7FB # 0 +0x8E9B 0xB7FE # 0 +0x8E9C 0xB802 # 0 +0x8E9D 0xB803 # 0 +0x8E9E 0xB804 # 0 +0x8E9F 0xB805 # 0 +0x8EA0 0xB806 # 0 +0x8EA1 0xB80A # 0 +0x8EA2 0xB80B # 0 +0x8EA3 0xB80D # 0 +0x8EA4 0xB80E # 0 +0x8EA5 0xB80F # 0 +0x8EA6 0xB811 # 0 +0x8EA7 0xB812 # 0 +0x8EA8 0xB813 # 0 +0x8EA9 0xB814 # 0 +0x8EAA 0xB815 # 0 +0x8EAB 0xB816 # 0 +0x8EAC 0xB817 # 0 +0x8EAD 0xB81A # 0 +0x8EAE 0xB81C # 0 +0x8EAF 0xB81E # 0 +0x8EB0 0xB81F # 0 +0x8EB1 0xB820 # 0 +0x8EB2 0xB821 # 0 +0x8EB3 0xB822 # 0 +0x8EB4 0xB823 # 0 +0x8EB5 0xB826 # 0 +0x8EB6 0xB827 # 0 +0x8EB7 0xB829 # 0 +0x8EB8 0xB82A # 0 +0x8EB9 0xB82B # 0 +0x8EBA 0xB82D # 0 +0x8EBB 0xB82E # 0 +0x8EBC 0xB82F # 0 +0x8EBD 0xB830 # 0 +0x8EBE 0xB831 # 0 +0x8EBF 0xB832 # 0 +0x8EC0 0xB833 # 0 +0x8EC1 0xB836 # 0 +0x8EC2 0xB83A # 0 +0x8EC3 0xB83B # 0 +0x8EC4 0xB83C # 0 +0x8EC5 0xB83D # 0 +0x8EC6 0xB83E # 0 +0x8EC7 0xB83F # 0 +0x8EC8 0xB841 # 0 +0x8EC9 0xB842 # 0 +0x8ECA 0xB843 # 0 +0x8ECB 0xB845 # 0 +0x8ECC 0xB846 # 0 +0x8ECD 0xB847 # 0 +0x8ECE 0xB848 # 0 +0x8ECF 0xB849 # 0 +0x8ED0 0xB84A # 0 +0x8ED1 0xB84B # 0 +0x8ED2 0xB84C # 0 +0x8ED3 0xB84D # 0 +0x8ED4 0xB84E # 0 +0x8ED5 0xB84F # 0 +0x8ED6 0xB850 # 0 +0x8ED7 0xB852 # 0 +0x8ED8 0xB854 # 0 +0x8ED9 0xB855 # 0 +0x8EDA 0xB856 # 0 +0x8EDB 0xB857 # 0 +0x8EDC 0xB858 # 0 +0x8EDD 0xB859 # 0 +0x8EDE 0xB85A # 0 +0x8EDF 0xB85B # 0 +0x8EE0 0xB85E # 0 +0x8EE1 0xB85F # 0 +0x8EE2 0xB861 # 0 +0x8EE3 0xB862 # 0 +0x8EE4 0xB863 # 0 +0x8EE5 0xB865 # 0 +0x8EE6 0xB866 # 0 +0x8EE7 0xB867 # 0 +0x8EE8 0xB868 # 0 +0x8EE9 0xB869 # 0 +0x8EEA 0xB86A # 0 +0x8EEB 0xB86B # 0 +0x8EEC 0xB86E # 0 +0x8EED 0xB870 # 0 +0x8EEE 0xB872 # 0 +0x8EEF 0xB873 # 0 +0x8EF0 0xB874 # 0 +0x8EF1 0xB875 # 0 +0x8EF2 0xB876 # 0 +0x8EF3 0xB877 # 0 +0x8EF4 0xB879 # 0 +0x8EF5 0xB87A # 0 +0x8EF6 0xB87B # 0 +0x8EF7 0xB87D # 0 +0x8EF8 0xB87E # 0 +0x8EF9 0xB87F # 0 +0x8EFA 0xB880 # 0 +0x8EFB 0xB881 # 0 +0x8EFC 0xB882 # 0 +0x8EFD 0xB883 # 0 +0x8EFE 0xB884 # 0 +0x8F41 0xB885 # 0 +0x8F42 0xB886 # 0 +0x8F43 0xB887 # 0 +0x8F44 0xB888 # 0 +0x8F45 0xB889 # 0 +0x8F46 0xB88A # 0 +0x8F47 0xB88B # 0 +0x8F48 0xB88C # 0 +0x8F49 0xB88E # 0 +0x8F4A 0xB88F # 0 +0x8F4B 0xB890 # 0 +0x8F4C 0xB891 # 0 +0x8F4D 0xB892 # 0 +0x8F4E 0xB893 # 0 +0x8F4F 0xB894 # 0 +0x8F50 0xB895 # 0 +0x8F51 0xB896 # 0 +0x8F52 0xB897 # 0 +0x8F53 0xB898 # 0 +0x8F54 0xB899 # 0 +0x8F55 0xB89A # 0 +0x8F56 0xB89B # 0 +0x8F57 0xB89C # 0 +0x8F58 0xB89D # 0 +0x8F59 0xB89E # 0 +0x8F5A 0xB89F # 0 +0x8F61 0xB8A0 # 0 +0x8F62 0xB8A1 # 0 +0x8F63 0xB8A2 # 0 +0x8F64 0xB8A3 # 0 +0x8F65 0xB8A4 # 0 +0x8F66 0xB8A5 # 0 +0x8F67 0xB8A6 # 0 +0x8F68 0xB8A7 # 0 +0x8F69 0xB8A9 # 0 +0x8F6A 0xB8AA # 0 +0x8F6B 0xB8AB # 0 +0x8F6C 0xB8AC # 0 +0x8F6D 0xB8AD # 0 +0x8F6E 0xB8AE # 0 +0x8F6F 0xB8AF # 0 +0x8F70 0xB8B1 # 0 +0x8F71 0xB8B2 # 0 +0x8F72 0xB8B3 # 0 +0x8F73 0xB8B5 # 0 +0x8F74 0xB8B6 # 0 +0x8F75 0xB8B7 # 0 +0x8F76 0xB8B9 # 0 +0x8F77 0xB8BA # 0 +0x8F78 0xB8BB # 0 +0x8F79 0xB8BC # 0 +0x8F7A 0xB8BD # 0 +0x8F81 0xB8BE # 0 +0x8F82 0xB8BF # 0 +0x8F83 0xB8C2 # 0 +0x8F84 0xB8C4 # 0 +0x8F85 0xB8C6 # 0 +0x8F86 0xB8C7 # 0 +0x8F87 0xB8C8 # 0 +0x8F88 0xB8C9 # 0 +0x8F89 0xB8CA # 0 +0x8F8A 0xB8CB # 0 +0x8F8B 0xB8CD # 0 +0x8F8C 0xB8CE # 0 +0x8F8D 0xB8CF # 0 +0x8F8E 0xB8D1 # 0 +0x8F8F 0xB8D2 # 0 +0x8F90 0xB8D3 # 0 +0x8F91 0xB8D5 # 0 +0x8F92 0xB8D6 # 0 +0x8F93 0xB8D7 # 0 +0x8F94 0xB8D8 # 0 +0x8F95 0xB8D9 # 0 +0x8F96 0xB8DA # 0 +0x8F97 0xB8DB # 0 +0x8F98 0xB8DC # 0 +0x8F99 0xB8DE # 0 +0x8F9A 0xB8E0 # 0 +0x8F9B 0xB8E2 # 0 +0x8F9C 0xB8E3 # 0 +0x8F9D 0xB8E4 # 0 +0x8F9E 0xB8E5 # 0 +0x8F9F 0xB8E6 # 0 +0x8FA0 0xB8E7 # 0 +0x8FA1 0xB8EA # 0 +0x8FA2 0xB8EB # 0 +0x8FA3 0xB8ED # 0 +0x8FA4 0xB8EE # 0 +0x8FA5 0xB8EF # 0 +0x8FA6 0xB8F1 # 0 +0x8FA7 0xB8F2 # 0 +0x8FA8 0xB8F3 # 0 +0x8FA9 0xB8F4 # 0 +0x8FAA 0xB8F5 # 0 +0x8FAB 0xB8F6 # 0 +0x8FAC 0xB8F7 # 0 +0x8FAD 0xB8FA # 0 +0x8FAE 0xB8FC # 0 +0x8FAF 0xB8FE # 0 +0x8FB0 0xB8FF # 0 +0x8FB1 0xB900 # 0 +0x8FB2 0xB901 # 0 +0x8FB3 0xB902 # 0 +0x8FB4 0xB903 # 0 +0x8FB5 0xB905 # 0 +0x8FB6 0xB906 # 0 +0x8FB7 0xB907 # 0 +0x8FB8 0xB908 # 0 +0x8FB9 0xB909 # 0 +0x8FBA 0xB90A # 0 +0x8FBB 0xB90B # 0 +0x8FBC 0xB90C # 0 +0x8FBD 0xB90D # 0 +0x8FBE 0xB90E # 0 +0x8FBF 0xB90F # 0 +0x8FC0 0xB910 # 0 +0x8FC1 0xB911 # 0 +0x8FC2 0xB912 # 0 +0x8FC3 0xB913 # 0 +0x8FC4 0xB914 # 0 +0x8FC5 0xB915 # 0 +0x8FC6 0xB916 # 0 +0x8FC7 0xB917 # 0 +0x8FC8 0xB919 # 0 +0x8FC9 0xB91A # 0 +0x8FCA 0xB91B # 0 +0x8FCB 0xB91C # 0 +0x8FCC 0xB91D # 0 +0x8FCD 0xB91E # 0 +0x8FCE 0xB91F # 0 +0x8FCF 0xB921 # 0 +0x8FD0 0xB922 # 0 +0x8FD1 0xB923 # 0 +0x8FD2 0xB924 # 0 +0x8FD3 0xB925 # 0 +0x8FD4 0xB926 # 0 +0x8FD5 0xB927 # 0 +0x8FD6 0xB928 # 0 +0x8FD7 0xB929 # 0 +0x8FD8 0xB92A # 0 +0x8FD9 0xB92B # 0 +0x8FDA 0xB92C # 0 +0x8FDB 0xB92D # 0 +0x8FDC 0xB92E # 0 +0x8FDD 0xB92F # 0 +0x8FDE 0xB930 # 0 +0x8FDF 0xB931 # 0 +0x8FE0 0xB932 # 0 +0x8FE1 0xB933 # 0 +0x8FE2 0xB934 # 0 +0x8FE3 0xB935 # 0 +0x8FE4 0xB936 # 0 +0x8FE5 0xB937 # 0 +0x8FE6 0xB938 # 0 +0x8FE7 0xB939 # 0 +0x8FE8 0xB93A # 0 +0x8FE9 0xB93B # 0 +0x8FEA 0xB93E # 0 +0x8FEB 0xB93F # 0 +0x8FEC 0xB941 # 0 +0x8FED 0xB942 # 0 +0x8FEE 0xB943 # 0 +0x8FEF 0xB945 # 0 +0x8FF0 0xB946 # 0 +0x8FF1 0xB947 # 0 +0x8FF2 0xB948 # 0 +0x8FF3 0xB949 # 0 +0x8FF4 0xB94A # 0 +0x8FF5 0xB94B # 0 +0x8FF6 0xB94D # 0 +0x8FF7 0xB94E # 0 +0x8FF8 0xB950 # 0 +0x8FF9 0xB952 # 0 +0x8FFA 0xB953 # 0 +0x8FFB 0xB954 # 0 +0x8FFC 0xB955 # 0 +0x8FFD 0xB956 # 0 +0x8FFE 0xB957 # 0 +0x9041 0xB95A # 0 +0x9042 0xB95B # 0 +0x9043 0xB95D # 0 +0x9044 0xB95E # 0 +0x9045 0xB95F # 0 +0x9046 0xB961 # 0 +0x9047 0xB962 # 0 +0x9048 0xB963 # 0 +0x9049 0xB964 # 0 +0x904A 0xB965 # 0 +0x904B 0xB966 # 0 +0x904C 0xB967 # 0 +0x904D 0xB96A # 0 +0x904E 0xB96C # 0 +0x904F 0xB96E # 0 +0x9050 0xB96F # 0 +0x9051 0xB970 # 0 +0x9052 0xB971 # 0 +0x9053 0xB972 # 0 +0x9054 0xB973 # 0 +0x9055 0xB976 # 0 +0x9056 0xB977 # 0 +0x9057 0xB979 # 0 +0x9058 0xB97A # 0 +0x9059 0xB97B # 0 +0x905A 0xB97D # 0 +0x9061 0xB97E # 0 +0x9062 0xB97F # 0 +0x9063 0xB980 # 0 +0x9064 0xB981 # 0 +0x9065 0xB982 # 0 +0x9066 0xB983 # 0 +0x9067 0xB986 # 0 +0x9068 0xB988 # 0 +0x9069 0xB98B # 0 +0x906A 0xB98C # 0 +0x906B 0xB98F # 0 +0x906C 0xB990 # 0 +0x906D 0xB991 # 0 +0x906E 0xB992 # 0 +0x906F 0xB993 # 0 +0x9070 0xB994 # 0 +0x9071 0xB995 # 0 +0x9072 0xB996 # 0 +0x9073 0xB997 # 0 +0x9074 0xB998 # 0 +0x9075 0xB999 # 0 +0x9076 0xB99A # 0 +0x9077 0xB99B # 0 +0x9078 0xB99C # 0 +0x9079 0xB99D # 0 +0x907A 0xB99E # 0 +0x9081 0xB99F # 0 +0x9082 0xB9A0 # 0 +0x9083 0xB9A1 # 0 +0x9084 0xB9A2 # 0 +0x9085 0xB9A3 # 0 +0x9086 0xB9A4 # 0 +0x9087 0xB9A5 # 0 +0x9088 0xB9A6 # 0 +0x9089 0xB9A7 # 0 +0x908A 0xB9A8 # 0 +0x908B 0xB9A9 # 0 +0x908C 0xB9AA # 0 +0x908D 0xB9AB # 0 +0x908E 0xB9AE # 0 +0x908F 0xB9AF # 0 +0x9090 0xB9B1 # 0 +0x9091 0xB9B2 # 0 +0x9092 0xB9B3 # 0 +0x9093 0xB9B5 # 0 +0x9094 0xB9B6 # 0 +0x9095 0xB9B7 # 0 +0x9096 0xB9B8 # 0 +0x9097 0xB9B9 # 0 +0x9098 0xB9BA # 0 +0x9099 0xB9BB # 0 +0x909A 0xB9BE # 0 +0x909B 0xB9C0 # 0 +0x909C 0xB9C2 # 0 +0x909D 0xB9C3 # 0 +0x909E 0xB9C4 # 0 +0x909F 0xB9C5 # 0 +0x90A0 0xB9C6 # 0 +0x90A1 0xB9C7 # 0 +0x90A2 0xB9CA # 0 +0x90A3 0xB9CB # 0 +0x90A4 0xB9CD # 0 +0x90A5 0xB9D3 # 0 +0x90A6 0xB9D4 # 0 +0x90A7 0xB9D5 # 0 +0x90A8 0xB9D6 # 0 +0x90A9 0xB9D7 # 0 +0x90AA 0xB9DA # 0 +0x90AB 0xB9DC # 0 +0x90AC 0xB9DF # 0 +0x90AD 0xB9E0 # 0 +0x90AE 0xB9E2 # 0 +0x90AF 0xB9E6 # 0 +0x90B0 0xB9E7 # 0 +0x90B1 0xB9E9 # 0 +0x90B2 0xB9EA # 0 +0x90B3 0xB9EB # 0 +0x90B4 0xB9ED # 0 +0x90B5 0xB9EE # 0 +0x90B6 0xB9EF # 0 +0x90B7 0xB9F0 # 0 +0x90B8 0xB9F1 # 0 +0x90B9 0xB9F2 # 0 +0x90BA 0xB9F3 # 0 +0x90BB 0xB9F6 # 0 +0x90BC 0xB9FB # 0 +0x90BD 0xB9FC # 0 +0x90BE 0xB9FD # 0 +0x90BF 0xB9FE # 0 +0x90C0 0xB9FF # 0 +0x90C1 0xBA02 # 0 +0x90C2 0xBA03 # 0 +0x90C3 0xBA04 # 0 +0x90C4 0xBA05 # 0 +0x90C5 0xBA06 # 0 +0x90C6 0xBA07 # 0 +0x90C7 0xBA09 # 0 +0x90C8 0xBA0A # 0 +0x90C9 0xBA0B # 0 +0x90CA 0xBA0C # 0 +0x90CB 0xBA0D # 0 +0x90CC 0xBA0E # 0 +0x90CD 0xBA0F # 0 +0x90CE 0xBA10 # 0 +0x90CF 0xBA11 # 0 +0x90D0 0xBA12 # 0 +0x90D1 0xBA13 # 0 +0x90D2 0xBA14 # 0 +0x90D3 0xBA16 # 0 +0x90D4 0xBA17 # 0 +0x90D5 0xBA18 # 0 +0x90D6 0xBA19 # 0 +0x90D7 0xBA1A # 0 +0x90D8 0xBA1B # 0 +0x90D9 0xBA1C # 0 +0x90DA 0xBA1D # 0 +0x90DB 0xBA1E # 0 +0x90DC 0xBA1F # 0 +0x90DD 0xBA20 # 0 +0x90DE 0xBA21 # 0 +0x90DF 0xBA22 # 0 +0x90E0 0xBA23 # 0 +0x90E1 0xBA24 # 0 +0x90E2 0xBA25 # 0 +0x90E3 0xBA26 # 0 +0x90E4 0xBA27 # 0 +0x90E5 0xBA28 # 0 +0x90E6 0xBA29 # 0 +0x90E7 0xBA2A # 0 +0x90E8 0xBA2B # 0 +0x90E9 0xBA2C # 0 +0x90EA 0xBA2D # 0 +0x90EB 0xBA2E # 0 +0x90EC 0xBA2F # 0 +0x90ED 0xBA30 # 0 +0x90EE 0xBA31 # 0 +0x90EF 0xBA32 # 0 +0x90F0 0xBA33 # 0 +0x90F1 0xBA34 # 0 +0x90F2 0xBA35 # 0 +0x90F3 0xBA36 # 0 +0x90F4 0xBA37 # 0 +0x90F5 0xBA3A # 0 +0x90F6 0xBA3B # 0 +0x90F7 0xBA3D # 0 +0x90F8 0xBA3E # 0 +0x90F9 0xBA3F # 0 +0x90FA 0xBA41 # 0 +0x90FB 0xBA43 # 0 +0x90FC 0xBA44 # 0 +0x90FD 0xBA45 # 0 +0x90FE 0xBA46 # 0 +0x9141 0xBA47 # 0 +0x9142 0xBA4A # 0 +0x9143 0xBA4C # 0 +0x9144 0xBA4F # 0 +0x9145 0xBA50 # 0 +0x9146 0xBA51 # 0 +0x9147 0xBA52 # 0 +0x9148 0xBA56 # 0 +0x9149 0xBA57 # 0 +0x914A 0xBA59 # 0 +0x914B 0xBA5A # 0 +0x914C 0xBA5B # 0 +0x914D 0xBA5D # 0 +0x914E 0xBA5E # 0 +0x914F 0xBA5F # 0 +0x9150 0xBA60 # 0 +0x9151 0xBA61 # 0 +0x9152 0xBA62 # 0 +0x9153 0xBA63 # 0 +0x9154 0xBA66 # 0 +0x9155 0xBA6A # 0 +0x9156 0xBA6B # 0 +0x9157 0xBA6C # 0 +0x9158 0xBA6D # 0 +0x9159 0xBA6E # 0 +0x915A 0xBA6F # 0 +0x9161 0xBA72 # 0 +0x9162 0xBA73 # 0 +0x9163 0xBA75 # 0 +0x9164 0xBA76 # 0 +0x9165 0xBA77 # 0 +0x9166 0xBA79 # 0 +0x9167 0xBA7A # 0 +0x9168 0xBA7B # 0 +0x9169 0xBA7C # 0 +0x916A 0xBA7D # 0 +0x916B 0xBA7E # 0 +0x916C 0xBA7F # 0 +0x916D 0xBA80 # 0 +0x916E 0xBA81 # 0 +0x916F 0xBA82 # 0 +0x9170 0xBA86 # 0 +0x9171 0xBA88 # 0 +0x9172 0xBA89 # 0 +0x9173 0xBA8A # 0 +0x9174 0xBA8B # 0 +0x9175 0xBA8D # 0 +0x9176 0xBA8E # 0 +0x9177 0xBA8F # 0 +0x9178 0xBA90 # 0 +0x9179 0xBA91 # 0 +0x917A 0xBA92 # 0 +0x9181 0xBA93 # 0 +0x9182 0xBA94 # 0 +0x9183 0xBA95 # 0 +0x9184 0xBA96 # 0 +0x9185 0xBA97 # 0 +0x9186 0xBA98 # 0 +0x9187 0xBA99 # 0 +0x9188 0xBA9A # 0 +0x9189 0xBA9B # 0 +0x918A 0xBA9C # 0 +0x918B 0xBA9D # 0 +0x918C 0xBA9E # 0 +0x918D 0xBA9F # 0 +0x918E 0xBAA0 # 0 +0x918F 0xBAA1 # 0 +0x9190 0xBAA2 # 0 +0x9191 0xBAA3 # 0 +0x9192 0xBAA4 # 0 +0x9193 0xBAA5 # 0 +0x9194 0xBAA6 # 0 +0x9195 0xBAA7 # 0 +0x9196 0xBAAA # 0 +0x9197 0xBAAD # 0 +0x9198 0xBAAE # 0 +0x9199 0xBAAF # 0 +0x919A 0xBAB1 # 0 +0x919B 0xBAB3 # 0 +0x919C 0xBAB4 # 0 +0x919D 0xBAB5 # 0 +0x919E 0xBAB6 # 0 +0x919F 0xBAB7 # 0 +0x91A0 0xBABA # 0 +0x91A1 0xBABC # 0 +0x91A2 0xBABE # 0 +0x91A3 0xBABF # 0 +0x91A4 0xBAC0 # 0 +0x91A5 0xBAC1 # 0 +0x91A6 0xBAC2 # 0 +0x91A7 0xBAC3 # 0 +0x91A8 0xBAC5 # 0 +0x91A9 0xBAC6 # 0 +0x91AA 0xBAC7 # 0 +0x91AB 0xBAC9 # 0 +0x91AC 0xBACA # 0 +0x91AD 0xBACB # 0 +0x91AE 0xBACC # 0 +0x91AF 0xBACD # 0 +0x91B0 0xBACE # 0 +0x91B1 0xBACF # 0 +0x91B2 0xBAD0 # 0 +0x91B3 0xBAD1 # 0 +0x91B4 0xBAD2 # 0 +0x91B5 0xBAD3 # 0 +0x91B6 0xBAD4 # 0 +0x91B7 0xBAD5 # 0 +0x91B8 0xBAD6 # 0 +0x91B9 0xBAD7 # 0 +0x91BA 0xBADA # 0 +0x91BB 0xBADB # 0 +0x91BC 0xBADC # 0 +0x91BD 0xBADD # 0 +0x91BE 0xBADE # 0 +0x91BF 0xBADF # 0 +0x91C0 0xBAE0 # 0 +0x91C1 0xBAE1 # 0 +0x91C2 0xBAE2 # 0 +0x91C3 0xBAE3 # 0 +0x91C4 0xBAE4 # 0 +0x91C5 0xBAE5 # 0 +0x91C6 0xBAE6 # 0 +0x91C7 0xBAE7 # 0 +0x91C8 0xBAE8 # 0 +0x91C9 0xBAE9 # 0 +0x91CA 0xBAEA # 0 +0x91CB 0xBAEB # 0 +0x91CC 0xBAEC # 0 +0x91CD 0xBAED # 0 +0x91CE 0xBAEE # 0 +0x91CF 0xBAEF # 0 +0x91D0 0xBAF0 # 0 +0x91D1 0xBAF1 # 0 +0x91D2 0xBAF2 # 0 +0x91D3 0xBAF3 # 0 +0x91D4 0xBAF4 # 0 +0x91D5 0xBAF5 # 0 +0x91D6 0xBAF6 # 0 +0x91D7 0xBAF7 # 0 +0x91D8 0xBAF8 # 0 +0x91D9 0xBAF9 # 0 +0x91DA 0xBAFA # 0 +0x91DB 0xBAFB # 0 +0x91DC 0xBAFD # 0 +0x91DD 0xBAFE # 0 +0x91DE 0xBAFF # 0 +0x91DF 0xBB01 # 0 +0x91E0 0xBB02 # 0 +0x91E1 0xBB03 # 0 +0x91E2 0xBB05 # 0 +0x91E3 0xBB06 # 0 +0x91E4 0xBB07 # 0 +0x91E5 0xBB08 # 0 +0x91E6 0xBB09 # 0 +0x91E7 0xBB0A # 0 +0x91E8 0xBB0B # 0 +0x91E9 0xBB0C # 0 +0x91EA 0xBB0E # 0 +0x91EB 0xBB10 # 0 +0x91EC 0xBB12 # 0 +0x91ED 0xBB13 # 0 +0x91EE 0xBB14 # 0 +0x91EF 0xBB15 # 0 +0x91F0 0xBB16 # 0 +0x91F1 0xBB17 # 0 +0x91F2 0xBB19 # 0 +0x91F3 0xBB1A # 0 +0x91F4 0xBB1B # 0 +0x91F5 0xBB1D # 0 +0x91F6 0xBB1E # 0 +0x91F7 0xBB1F # 0 +0x91F8 0xBB21 # 0 +0x91F9 0xBB22 # 0 +0x91FA 0xBB23 # 0 +0x91FB 0xBB24 # 0 +0x91FC 0xBB25 # 0 +0x91FD 0xBB26 # 0 +0x91FE 0xBB27 # 0 +0x9241 0xBB28 # 0 +0x9242 0xBB2A # 0 +0x9243 0xBB2C # 0 +0x9244 0xBB2D # 0 +0x9245 0xBB2E # 0 +0x9246 0xBB2F # 0 +0x9247 0xBB30 # 0 +0x9248 0xBB31 # 0 +0x9249 0xBB32 # 0 +0x924A 0xBB33 # 0 +0x924B 0xBB37 # 0 +0x924C 0xBB39 # 0 +0x924D 0xBB3A # 0 +0x924E 0xBB3F # 0 +0x924F 0xBB40 # 0 +0x9250 0xBB41 # 0 +0x9251 0xBB42 # 0 +0x9252 0xBB43 # 0 +0x9253 0xBB46 # 0 +0x9254 0xBB48 # 0 +0x9255 0xBB4A # 0 +0x9256 0xBB4B # 0 +0x9257 0xBB4C # 0 +0x9258 0xBB4E # 0 +0x9259 0xBB51 # 0 +0x925A 0xBB52 # 0 +0x9261 0xBB53 # 0 +0x9262 0xBB55 # 0 +0x9263 0xBB56 # 0 +0x9264 0xBB57 # 0 +0x9265 0xBB59 # 0 +0x9266 0xBB5A # 0 +0x9267 0xBB5B # 0 +0x9268 0xBB5C # 0 +0x9269 0xBB5D # 0 +0x926A 0xBB5E # 0 +0x926B 0xBB5F # 0 +0x926C 0xBB60 # 0 +0x926D 0xBB62 # 0 +0x926E 0xBB64 # 0 +0x926F 0xBB65 # 0 +0x9270 0xBB66 # 0 +0x9271 0xBB67 # 0 +0x9272 0xBB68 # 0 +0x9273 0xBB69 # 0 +0x9274 0xBB6A # 0 +0x9275 0xBB6B # 0 +0x9276 0xBB6D # 0 +0x9277 0xBB6E # 0 +0x9278 0xBB6F # 0 +0x9279 0xBB70 # 0 +0x927A 0xBB71 # 0 +0x9281 0xBB72 # 0 +0x9282 0xBB73 # 0 +0x9283 0xBB74 # 0 +0x9284 0xBB75 # 0 +0x9285 0xBB76 # 0 +0x9286 0xBB77 # 0 +0x9287 0xBB78 # 0 +0x9288 0xBB79 # 0 +0x9289 0xBB7A # 0 +0x928A 0xBB7B # 0 +0x928B 0xBB7C # 0 +0x928C 0xBB7D # 0 +0x928D 0xBB7E # 0 +0x928E 0xBB7F # 0 +0x928F 0xBB80 # 0 +0x9290 0xBB81 # 0 +0x9291 0xBB82 # 0 +0x9292 0xBB83 # 0 +0x9293 0xBB84 # 0 +0x9294 0xBB85 # 0 +0x9295 0xBB86 # 0 +0x9296 0xBB87 # 0 +0x9297 0xBB89 # 0 +0x9298 0xBB8A # 0 +0x9299 0xBB8B # 0 +0x929A 0xBB8D # 0 +0x929B 0xBB8E # 0 +0x929C 0xBB8F # 0 +0x929D 0xBB91 # 0 +0x929E 0xBB92 # 0 +0x929F 0xBB93 # 0 +0x92A0 0xBB94 # 0 +0x92A1 0xBB95 # 0 +0x92A2 0xBB96 # 0 +0x92A3 0xBB97 # 0 +0x92A4 0xBB98 # 0 +0x92A5 0xBB99 # 0 +0x92A6 0xBB9A # 0 +0x92A7 0xBB9B # 0 +0x92A8 0xBB9C # 0 +0x92A9 0xBB9D # 0 +0x92AA 0xBB9E # 0 +0x92AB 0xBB9F # 0 +0x92AC 0xBBA0 # 0 +0x92AD 0xBBA1 # 0 +0x92AE 0xBBA2 # 0 +0x92AF 0xBBA3 # 0 +0x92B0 0xBBA5 # 0 +0x92B1 0xBBA6 # 0 +0x92B2 0xBBA7 # 0 +0x92B3 0xBBA9 # 0 +0x92B4 0xBBAA # 0 +0x92B5 0xBBAB # 0 +0x92B6 0xBBAD # 0 +0x92B7 0xBBAE # 0 +0x92B8 0xBBAF # 0 +0x92B9 0xBBB0 # 0 +0x92BA 0xBBB1 # 0 +0x92BB 0xBBB2 # 0 +0x92BC 0xBBB3 # 0 +0x92BD 0xBBB5 # 0 +0x92BE 0xBBB6 # 0 +0x92BF 0xBBB8 # 0 +0x92C0 0xBBB9 # 0 +0x92C1 0xBBBA # 0 +0x92C2 0xBBBB # 0 +0x92C3 0xBBBC # 0 +0x92C4 0xBBBD # 0 +0x92C5 0xBBBE # 0 +0x92C6 0xBBBF # 0 +0x92C7 0xBBC1 # 0 +0x92C8 0xBBC2 # 0 +0x92C9 0xBBC3 # 0 +0x92CA 0xBBC5 # 0 +0x92CB 0xBBC6 # 0 +0x92CC 0xBBC7 # 0 +0x92CD 0xBBC9 # 0 +0x92CE 0xBBCA # 0 +0x92CF 0xBBCB # 0 +0x92D0 0xBBCC # 0 +0x92D1 0xBBCD # 0 +0x92D2 0xBBCE # 0 +0x92D3 0xBBCF # 0 +0x92D4 0xBBD1 # 0 +0x92D5 0xBBD2 # 0 +0x92D6 0xBBD4 # 0 +0x92D7 0xBBD5 # 0 +0x92D8 0xBBD6 # 0 +0x92D9 0xBBD7 # 0 +0x92DA 0xBBD8 # 0 +0x92DB 0xBBD9 # 0 +0x92DC 0xBBDA # 0 +0x92DD 0xBBDB # 0 +0x92DE 0xBBDC # 0 +0x92DF 0xBBDD # 0 +0x92E0 0xBBDE # 0 +0x92E1 0xBBDF # 0 +0x92E2 0xBBE0 # 0 +0x92E3 0xBBE1 # 0 +0x92E4 0xBBE2 # 0 +0x92E5 0xBBE3 # 0 +0x92E6 0xBBE4 # 0 +0x92E7 0xBBE5 # 0 +0x92E8 0xBBE6 # 0 +0x92E9 0xBBE7 # 0 +0x92EA 0xBBE8 # 0 +0x92EB 0xBBE9 # 0 +0x92EC 0xBBEA # 0 +0x92ED 0xBBEB # 0 +0x92EE 0xBBEC # 0 +0x92EF 0xBBED # 0 +0x92F0 0xBBEE # 0 +0x92F1 0xBBEF # 0 +0x92F2 0xBBF0 # 0 +0x92F3 0xBBF1 # 0 +0x92F4 0xBBF2 # 0 +0x92F5 0xBBF3 # 0 +0x92F6 0xBBF4 # 0 +0x92F7 0xBBF5 # 0 +0x92F8 0xBBF6 # 0 +0x92F9 0xBBF7 # 0 +0x92FA 0xBBFA # 0 +0x92FB 0xBBFB # 0 +0x92FC 0xBBFD # 0 +0x92FD 0xBBFE # 0 +0x92FE 0xBC01 # 0 +0x9341 0xBC03 # 0 +0x9342 0xBC04 # 0 +0x9343 0xBC05 # 0 +0x9344 0xBC06 # 0 +0x9345 0xBC07 # 0 +0x9346 0xBC0A # 0 +0x9347 0xBC0E # 0 +0x9348 0xBC10 # 0 +0x9349 0xBC12 # 0 +0x934A 0xBC13 # 0 +0x934B 0xBC19 # 0 +0x934C 0xBC1A # 0 +0x934D 0xBC20 # 0 +0x934E 0xBC21 # 0 +0x934F 0xBC22 # 0 +0x9350 0xBC23 # 0 +0x9351 0xBC26 # 0 +0x9352 0xBC28 # 0 +0x9353 0xBC2A # 0 +0x9354 0xBC2B # 0 +0x9355 0xBC2C # 0 +0x9356 0xBC2E # 0 +0x9357 0xBC2F # 0 +0x9358 0xBC32 # 0 +0x9359 0xBC33 # 0 +0x935A 0xBC35 # 0 +0x9361 0xBC36 # 0 +0x9362 0xBC37 # 0 +0x9363 0xBC39 # 0 +0x9364 0xBC3A # 0 +0x9365 0xBC3B # 0 +0x9366 0xBC3C # 0 +0x9367 0xBC3D # 0 +0x9368 0xBC3E # 0 +0x9369 0xBC3F # 0 +0x936A 0xBC42 # 0 +0x936B 0xBC46 # 0 +0x936C 0xBC47 # 0 +0x936D 0xBC48 # 0 +0x936E 0xBC4A # 0 +0x936F 0xBC4B # 0 +0x9370 0xBC4E # 0 +0x9371 0xBC4F # 0 +0x9372 0xBC51 # 0 +0x9373 0xBC52 # 0 +0x9374 0xBC53 # 0 +0x9375 0xBC54 # 0 +0x9376 0xBC55 # 0 +0x9377 0xBC56 # 0 +0x9378 0xBC57 # 0 +0x9379 0xBC58 # 0 +0x937A 0xBC59 # 0 +0x9381 0xBC5A # 0 +0x9382 0xBC5B # 0 +0x9383 0xBC5C # 0 +0x9384 0xBC5E # 0 +0x9385 0xBC5F # 0 +0x9386 0xBC60 # 0 +0x9387 0xBC61 # 0 +0x9388 0xBC62 # 0 +0x9389 0xBC63 # 0 +0x938A 0xBC64 # 0 +0x938B 0xBC65 # 0 +0x938C 0xBC66 # 0 +0x938D 0xBC67 # 0 +0x938E 0xBC68 # 0 +0x938F 0xBC69 # 0 +0x9390 0xBC6A # 0 +0x9391 0xBC6B # 0 +0x9392 0xBC6C # 0 +0x9393 0xBC6D # 0 +0x9394 0xBC6E # 0 +0x9395 0xBC6F # 0 +0x9396 0xBC70 # 0 +0x9397 0xBC71 # 0 +0x9398 0xBC72 # 0 +0x9399 0xBC73 # 0 +0x939A 0xBC74 # 0 +0x939B 0xBC75 # 0 +0x939C 0xBC76 # 0 +0x939D 0xBC77 # 0 +0x939E 0xBC78 # 0 +0x939F 0xBC79 # 0 +0x93A0 0xBC7A # 0 +0x93A1 0xBC7B # 0 +0x93A2 0xBC7C # 0 +0x93A3 0xBC7D # 0 +0x93A4 0xBC7E # 0 +0x93A5 0xBC7F # 0 +0x93A6 0xBC80 # 0 +0x93A7 0xBC81 # 0 +0x93A8 0xBC82 # 0 +0x93A9 0xBC83 # 0 +0x93AA 0xBC86 # 0 +0x93AB 0xBC87 # 0 +0x93AC 0xBC89 # 0 +0x93AD 0xBC8A # 0 +0x93AE 0xBC8D # 0 +0x93AF 0xBC8F # 0 +0x93B0 0xBC90 # 0 +0x93B1 0xBC91 # 0 +0x93B2 0xBC92 # 0 +0x93B3 0xBC93 # 0 +0x93B4 0xBC96 # 0 +0x93B5 0xBC98 # 0 +0x93B6 0xBC9B # 0 +0x93B7 0xBC9C # 0 +0x93B8 0xBC9D # 0 +0x93B9 0xBC9E # 0 +0x93BA 0xBC9F # 0 +0x93BB 0xBCA2 # 0 +0x93BC 0xBCA3 # 0 +0x93BD 0xBCA5 # 0 +0x93BE 0xBCA6 # 0 +0x93BF 0xBCA9 # 0 +0x93C0 0xBCAA # 0 +0x93C1 0xBCAB # 0 +0x93C2 0xBCAC # 0 +0x93C3 0xBCAD # 0 +0x93C4 0xBCAE # 0 +0x93C5 0xBCAF # 0 +0x93C6 0xBCB2 # 0 +0x93C7 0xBCB6 # 0 +0x93C8 0xBCB7 # 0 +0x93C9 0xBCB8 # 0 +0x93CA 0xBCB9 # 0 +0x93CB 0xBCBA # 0 +0x93CC 0xBCBB # 0 +0x93CD 0xBCBE # 0 +0x93CE 0xBCBF # 0 +0x93CF 0xBCC1 # 0 +0x93D0 0xBCC2 # 0 +0x93D1 0xBCC3 # 0 +0x93D2 0xBCC5 # 0 +0x93D3 0xBCC6 # 0 +0x93D4 0xBCC7 # 0 +0x93D5 0xBCC8 # 0 +0x93D6 0xBCC9 # 0 +0x93D7 0xBCCA # 0 +0x93D8 0xBCCB # 0 +0x93D9 0xBCCC # 0 +0x93DA 0xBCCE # 0 +0x93DB 0xBCD2 # 0 +0x93DC 0xBCD3 # 0 +0x93DD 0xBCD4 # 0 +0x93DE 0xBCD6 # 0 +0x93DF 0xBCD7 # 0 +0x93E0 0xBCD9 # 0 +0x93E1 0xBCDA # 0 +0x93E2 0xBCDB # 0 +0x93E3 0xBCDD # 0 +0x93E4 0xBCDE # 0 +0x93E5 0xBCDF # 0 +0x93E6 0xBCE0 # 0 +0x93E7 0xBCE1 # 0 +0x93E8 0xBCE2 # 0 +0x93E9 0xBCE3 # 0 +0x93EA 0xBCE4 # 0 +0x93EB 0xBCE5 # 0 +0x93EC 0xBCE6 # 0 +0x93ED 0xBCE7 # 0 +0x93EE 0xBCE8 # 0 +0x93EF 0xBCE9 # 0 +0x93F0 0xBCEA # 0 +0x93F1 0xBCEB # 0 +0x93F2 0xBCEC # 0 +0x93F3 0xBCED # 0 +0x93F4 0xBCEE # 0 +0x93F5 0xBCEF # 0 +0x93F6 0xBCF0 # 0 +0x93F7 0xBCF1 # 0 +0x93F8 0xBCF2 # 0 +0x93F9 0xBCF3 # 0 +0x93FA 0xBCF7 # 0 +0x93FB 0xBCF9 # 0 +0x93FC 0xBCFA # 0 +0x93FD 0xBCFB # 0 +0x93FE 0xBCFD # 0 +0x9441 0xBCFE # 0 +0x9442 0xBCFF # 0 +0x9443 0xBD00 # 0 +0x9444 0xBD01 # 0 +0x9445 0xBD02 # 0 +0x9446 0xBD03 # 0 +0x9447 0xBD06 # 0 +0x9448 0xBD08 # 0 +0x9449 0xBD0A # 0 +0x944A 0xBD0B # 0 +0x944B 0xBD0C # 0 +0x944C 0xBD0D # 0 +0x944D 0xBD0E # 0 +0x944E 0xBD0F # 0 +0x944F 0xBD11 # 0 +0x9450 0xBD12 # 0 +0x9451 0xBD13 # 0 +0x9452 0xBD15 # 0 +0x9453 0xBD16 # 0 +0x9454 0xBD17 # 0 +0x9455 0xBD18 # 0 +0x9456 0xBD19 # 0 +0x9457 0xBD1A # 0 +0x9458 0xBD1B # 0 +0x9459 0xBD1C # 0 +0x945A 0xBD1D # 0 +0x9461 0xBD1E # 0 +0x9462 0xBD1F # 0 +0x9463 0xBD20 # 0 +0x9464 0xBD21 # 0 +0x9465 0xBD22 # 0 +0x9466 0xBD23 # 0 +0x9467 0xBD25 # 0 +0x9468 0xBD26 # 0 +0x9469 0xBD27 # 0 +0x946A 0xBD28 # 0 +0x946B 0xBD29 # 0 +0x946C 0xBD2A # 0 +0x946D 0xBD2B # 0 +0x946E 0xBD2D # 0 +0x946F 0xBD2E # 0 +0x9470 0xBD2F # 0 +0x9471 0xBD30 # 0 +0x9472 0xBD31 # 0 +0x9473 0xBD32 # 0 +0x9474 0xBD33 # 0 +0x9475 0xBD34 # 0 +0x9476 0xBD35 # 0 +0x9477 0xBD36 # 0 +0x9478 0xBD37 # 0 +0x9479 0xBD38 # 0 +0x947A 0xBD39 # 0 +0x9481 0xBD3A # 0 +0x9482 0xBD3B # 0 +0x9483 0xBD3C # 0 +0x9484 0xBD3D # 0 +0x9485 0xBD3E # 0 +0x9486 0xBD3F # 0 +0x9487 0xBD41 # 0 +0x9488 0xBD42 # 0 +0x9489 0xBD43 # 0 +0x948A 0xBD44 # 0 +0x948B 0xBD45 # 0 +0x948C 0xBD46 # 0 +0x948D 0xBD47 # 0 +0x948E 0xBD4A # 0 +0x948F 0xBD4B # 0 +0x9490 0xBD4D # 0 +0x9491 0xBD4E # 0 +0x9492 0xBD4F # 0 +0x9493 0xBD51 # 0 +0x9494 0xBD52 # 0 +0x9495 0xBD53 # 0 +0x9496 0xBD54 # 0 +0x9497 0xBD55 # 0 +0x9498 0xBD56 # 0 +0x9499 0xBD57 # 0 +0x949A 0xBD5A # 0 +0x949B 0xBD5B # 0 +0x949C 0xBD5C # 0 +0x949D 0xBD5D # 0 +0x949E 0xBD5E # 0 +0x949F 0xBD5F # 0 +0x94A0 0xBD60 # 0 +0x94A1 0xBD61 # 0 +0x94A2 0xBD62 # 0 +0x94A3 0xBD63 # 0 +0x94A4 0xBD65 # 0 +0x94A5 0xBD66 # 0 +0x94A6 0xBD67 # 0 +0x94A7 0xBD69 # 0 +0x94A8 0xBD6A # 0 +0x94A9 0xBD6B # 0 +0x94AA 0xBD6C # 0 +0x94AB 0xBD6D # 0 +0x94AC 0xBD6E # 0 +0x94AD 0xBD6F # 0 +0x94AE 0xBD70 # 0 +0x94AF 0xBD71 # 0 +0x94B0 0xBD72 # 0 +0x94B1 0xBD73 # 0 +0x94B2 0xBD74 # 0 +0x94B3 0xBD75 # 0 +0x94B4 0xBD76 # 0 +0x94B5 0xBD77 # 0 +0x94B6 0xBD78 # 0 +0x94B7 0xBD79 # 0 +0x94B8 0xBD7A # 0 +0x94B9 0xBD7B # 0 +0x94BA 0xBD7C # 0 +0x94BB 0xBD7D # 0 +0x94BC 0xBD7E # 0 +0x94BD 0xBD7F # 0 +0x94BE 0xBD82 # 0 +0x94BF 0xBD83 # 0 +0x94C0 0xBD85 # 0 +0x94C1 0xBD86 # 0 +0x94C2 0xBD8B # 0 +0x94C3 0xBD8C # 0 +0x94C4 0xBD8D # 0 +0x94C5 0xBD8E # 0 +0x94C6 0xBD8F # 0 +0x94C7 0xBD92 # 0 +0x94C8 0xBD94 # 0 +0x94C9 0xBD96 # 0 +0x94CA 0xBD97 # 0 +0x94CB 0xBD98 # 0 +0x94CC 0xBD9B # 0 +0x94CD 0xBD9D # 0 +0x94CE 0xBD9E # 0 +0x94CF 0xBD9F # 0 +0x94D0 0xBDA0 # 0 +0x94D1 0xBDA1 # 0 +0x94D2 0xBDA2 # 0 +0x94D3 0xBDA3 # 0 +0x94D4 0xBDA5 # 0 +0x94D5 0xBDA6 # 0 +0x94D6 0xBDA7 # 0 +0x94D7 0xBDA8 # 0 +0x94D8 0xBDA9 # 0 +0x94D9 0xBDAA # 0 +0x94DA 0xBDAB # 0 +0x94DB 0xBDAC # 0 +0x94DC 0xBDAD # 0 +0x94DD 0xBDAE # 0 +0x94DE 0xBDAF # 0 +0x94DF 0xBDB1 # 0 +0x94E0 0xBDB2 # 0 +0x94E1 0xBDB3 # 0 +0x94E2 0xBDB4 # 0 +0x94E3 0xBDB5 # 0 +0x94E4 0xBDB6 # 0 +0x94E5 0xBDB7 # 0 +0x94E6 0xBDB9 # 0 +0x94E7 0xBDBA # 0 +0x94E8 0xBDBB # 0 +0x94E9 0xBDBC # 0 +0x94EA 0xBDBD # 0 +0x94EB 0xBDBE # 0 +0x94EC 0xBDBF # 0 +0x94ED 0xBDC0 # 0 +0x94EE 0xBDC1 # 0 +0x94EF 0xBDC2 # 0 +0x94F0 0xBDC3 # 0 +0x94F1 0xBDC4 # 0 +0x94F2 0xBDC5 # 0 +0x94F3 0xBDC6 # 0 +0x94F4 0xBDC7 # 0 +0x94F5 0xBDC8 # 0 +0x94F6 0xBDC9 # 0 +0x94F7 0xBDCA # 0 +0x94F8 0xBDCB # 0 +0x94F9 0xBDCC # 0 +0x94FA 0xBDCD # 0 +0x94FB 0xBDCE # 0 +0x94FC 0xBDCF # 0 +0x94FD 0xBDD0 # 0 +0x94FE 0xBDD1 # 0 +0x9541 0xBDD2 # 0 +0x9542 0xBDD3 # 0 +0x9543 0xBDD6 # 0 +0x9544 0xBDD7 # 0 +0x9545 0xBDD9 # 0 +0x9546 0xBDDA # 0 +0x9547 0xBDDB # 0 +0x9548 0xBDDD # 0 +0x9549 0xBDDE # 0 +0x954A 0xBDDF # 0 +0x954B 0xBDE0 # 0 +0x954C 0xBDE1 # 0 +0x954D 0xBDE2 # 0 +0x954E 0xBDE3 # 0 +0x954F 0xBDE4 # 0 +0x9550 0xBDE5 # 0 +0x9551 0xBDE6 # 0 +0x9552 0xBDE7 # 0 +0x9553 0xBDE8 # 0 +0x9554 0xBDEA # 0 +0x9555 0xBDEB # 0 +0x9556 0xBDEC # 0 +0x9557 0xBDED # 0 +0x9558 0xBDEE # 0 +0x9559 0xBDEF # 0 +0x955A 0xBDF1 # 0 +0x9561 0xBDF2 # 0 +0x9562 0xBDF3 # 0 +0x9563 0xBDF5 # 0 +0x9564 0xBDF6 # 0 +0x9565 0xBDF7 # 0 +0x9566 0xBDF9 # 0 +0x9567 0xBDFA # 0 +0x9568 0xBDFB # 0 +0x9569 0xBDFC # 0 +0x956A 0xBDFD # 0 +0x956B 0xBDFE # 0 +0x956C 0xBDFF # 0 +0x956D 0xBE01 # 0 +0x956E 0xBE02 # 0 +0x956F 0xBE04 # 0 +0x9570 0xBE06 # 0 +0x9571 0xBE07 # 0 +0x9572 0xBE08 # 0 +0x9573 0xBE09 # 0 +0x9574 0xBE0A # 0 +0x9575 0xBE0B # 0 +0x9576 0xBE0E # 0 +0x9577 0xBE0F # 0 +0x9578 0xBE11 # 0 +0x9579 0xBE12 # 0 +0x957A 0xBE13 # 0 +0x9581 0xBE15 # 0 +0x9582 0xBE16 # 0 +0x9583 0xBE17 # 0 +0x9584 0xBE18 # 0 +0x9585 0xBE19 # 0 +0x9586 0xBE1A # 0 +0x9587 0xBE1B # 0 +0x9588 0xBE1E # 0 +0x9589 0xBE20 # 0 +0x958A 0xBE21 # 0 +0x958B 0xBE22 # 0 +0x958C 0xBE23 # 0 +0x958D 0xBE24 # 0 +0x958E 0xBE25 # 0 +0x958F 0xBE26 # 0 +0x9590 0xBE27 # 0 +0x9591 0xBE28 # 0 +0x9592 0xBE29 # 0 +0x9593 0xBE2A # 0 +0x9594 0xBE2B # 0 +0x9595 0xBE2C # 0 +0x9596 0xBE2D # 0 +0x9597 0xBE2E # 0 +0x9598 0xBE2F # 0 +0x9599 0xBE30 # 0 +0x959A 0xBE31 # 0 +0x959B 0xBE32 # 0 +0x959C 0xBE33 # 0 +0x959D 0xBE34 # 0 +0x959E 0xBE35 # 0 +0x959F 0xBE36 # 0 +0x95A0 0xBE37 # 0 +0x95A1 0xBE38 # 0 +0x95A2 0xBE39 # 0 +0x95A3 0xBE3A # 0 +0x95A4 0xBE3B # 0 +0x95A5 0xBE3C # 0 +0x95A6 0xBE3D # 0 +0x95A7 0xBE3E # 0 +0x95A8 0xBE3F # 0 +0x95A9 0xBE40 # 0 +0x95AA 0xBE41 # 0 +0x95AB 0xBE42 # 0 +0x95AC 0xBE43 # 0 +0x95AD 0xBE46 # 0 +0x95AE 0xBE47 # 0 +0x95AF 0xBE49 # 0 +0x95B0 0xBE4A # 0 +0x95B1 0xBE4B # 0 +0x95B2 0xBE4D # 0 +0x95B3 0xBE4F # 0 +0x95B4 0xBE50 # 0 +0x95B5 0xBE51 # 0 +0x95B6 0xBE52 # 0 +0x95B7 0xBE53 # 0 +0x95B8 0xBE56 # 0 +0x95B9 0xBE58 # 0 +0x95BA 0xBE5C # 0 +0x95BB 0xBE5D # 0 +0x95BC 0xBE5E # 0 +0x95BD 0xBE5F # 0 +0x95BE 0xBE62 # 0 +0x95BF 0xBE63 # 0 +0x95C0 0xBE65 # 0 +0x95C1 0xBE66 # 0 +0x95C2 0xBE67 # 0 +0x95C3 0xBE69 # 0 +0x95C4 0xBE6B # 0 +0x95C5 0xBE6C # 0 +0x95C6 0xBE6D # 0 +0x95C7 0xBE6E # 0 +0x95C8 0xBE6F # 0 +0x95C9 0xBE72 # 0 +0x95CA 0xBE76 # 0 +0x95CB 0xBE77 # 0 +0x95CC 0xBE78 # 0 +0x95CD 0xBE79 # 0 +0x95CE 0xBE7A # 0 +0x95CF 0xBE7E # 0 +0x95D0 0xBE7F # 0 +0x95D1 0xBE81 # 0 +0x95D2 0xBE82 # 0 +0x95D3 0xBE83 # 0 +0x95D4 0xBE85 # 0 +0x95D5 0xBE86 # 0 +0x95D6 0xBE87 # 0 +0x95D7 0xBE88 # 0 +0x95D8 0xBE89 # 0 +0x95D9 0xBE8A # 0 +0x95DA 0xBE8B # 0 +0x95DB 0xBE8E # 0 +0x95DC 0xBE92 # 0 +0x95DD 0xBE93 # 0 +0x95DE 0xBE94 # 0 +0x95DF 0xBE95 # 0 +0x95E0 0xBE96 # 0 +0x95E1 0xBE97 # 0 +0x95E2 0xBE9A # 0 +0x95E3 0xBE9B # 0 +0x95E4 0xBE9C # 0 +0x95E5 0xBE9D # 0 +0x95E6 0xBE9E # 0 +0x95E7 0xBE9F # 0 +0x95E8 0xBEA0 # 0 +0x95E9 0xBEA1 # 0 +0x95EA 0xBEA2 # 0 +0x95EB 0xBEA3 # 0 +0x95EC 0xBEA4 # 0 +0x95ED 0xBEA5 # 0 +0x95EE 0xBEA6 # 0 +0x95EF 0xBEA7 # 0 +0x95F0 0xBEA9 # 0 +0x95F1 0xBEAA # 0 +0x95F2 0xBEAB # 0 +0x95F3 0xBEAC # 0 +0x95F4 0xBEAD # 0 +0x95F5 0xBEAE # 0 +0x95F6 0xBEAF # 0 +0x95F7 0xBEB0 # 0 +0x95F8 0xBEB1 # 0 +0x95F9 0xBEB2 # 0 +0x95FA 0xBEB3 # 0 +0x95FB 0xBEB4 # 0 +0x95FC 0xBEB5 # 0 +0x95FD 0xBEB6 # 0 +0x95FE 0xBEB7 # 0 +0x9641 0xBEB8 # 0 +0x9642 0xBEB9 # 0 +0x9643 0xBEBA # 0 +0x9644 0xBEBB # 0 +0x9645 0xBEBC # 0 +0x9646 0xBEBD # 0 +0x9647 0xBEBE # 0 +0x9648 0xBEBF # 0 +0x9649 0xBEC0 # 0 +0x964A 0xBEC1 # 0 +0x964B 0xBEC2 # 0 +0x964C 0xBEC3 # 0 +0x964D 0xBEC4 # 0 +0x964E 0xBEC5 # 0 +0x964F 0xBEC6 # 0 +0x9650 0xBEC7 # 0 +0x9651 0xBEC8 # 0 +0x9652 0xBEC9 # 0 +0x9653 0xBECA # 0 +0x9654 0xBECB # 0 +0x9655 0xBECC # 0 +0x9656 0xBECD # 0 +0x9657 0xBECE # 0 +0x9658 0xBECF # 0 +0x9659 0xBED2 # 0 +0x965A 0xBED3 # 0 +0x9661 0xBED5 # 0 +0x9662 0xBED6 # 0 +0x9663 0xBED9 # 0 +0x9664 0xBEDA # 0 +0x9665 0xBEDB # 0 +0x9666 0xBEDC # 0 +0x9667 0xBEDD # 0 +0x9668 0xBEDE # 0 +0x9669 0xBEDF # 0 +0x966A 0xBEE1 # 0 +0x966B 0xBEE2 # 0 +0x966C 0xBEE6 # 0 +0x966D 0xBEE7 # 0 +0x966E 0xBEE8 # 0 +0x966F 0xBEE9 # 0 +0x9670 0xBEEA # 0 +0x9671 0xBEEB # 0 +0x9672 0xBEED # 0 +0x9673 0xBEEE # 0 +0x9674 0xBEEF # 0 +0x9675 0xBEF0 # 0 +0x9676 0xBEF1 # 0 +0x9677 0xBEF2 # 0 +0x9678 0xBEF3 # 0 +0x9679 0xBEF4 # 0 +0x967A 0xBEF5 # 0 +0x9681 0xBEF6 # 0 +0x9682 0xBEF7 # 0 +0x9683 0xBEF8 # 0 +0x9684 0xBEF9 # 0 +0x9685 0xBEFA # 0 +0x9686 0xBEFB # 0 +0x9687 0xBEFC # 0 +0x9688 0xBEFD # 0 +0x9689 0xBEFE # 0 +0x968A 0xBEFF # 0 +0x968B 0xBF00 # 0 +0x968C 0xBF02 # 0 +0x968D 0xBF03 # 0 +0x968E 0xBF04 # 0 +0x968F 0xBF05 # 0 +0x9690 0xBF06 # 0 +0x9691 0xBF07 # 0 +0x9692 0xBF0A # 0 +0x9693 0xBF0B # 0 +0x9694 0xBF0C # 0 +0x9695 0xBF0D # 0 +0x9696 0xBF0E # 0 +0x9697 0xBF0F # 0 +0x9698 0xBF10 # 0 +0x9699 0xBF11 # 0 +0x969A 0xBF12 # 0 +0x969B 0xBF13 # 0 +0x969C 0xBF14 # 0 +0x969D 0xBF15 # 0 +0x969E 0xBF16 # 0 +0x969F 0xBF17 # 0 +0x96A0 0xBF1A # 0 +0x96A1 0xBF1E # 0 +0x96A2 0xBF1F # 0 +0x96A3 0xBF20 # 0 +0x96A4 0xBF21 # 0 +0x96A5 0xBF22 # 0 +0x96A6 0xBF23 # 0 +0x96A7 0xBF24 # 0 +0x96A8 0xBF25 # 0 +0x96A9 0xBF26 # 0 +0x96AA 0xBF27 # 0 +0x96AB 0xBF28 # 0 +0x96AC 0xBF29 # 0 +0x96AD 0xBF2A # 0 +0x96AE 0xBF2B # 0 +0x96AF 0xBF2C # 0 +0x96B0 0xBF2D # 0 +0x96B1 0xBF2E # 0 +0x96B2 0xBF2F # 0 +0x96B3 0xBF30 # 0 +0x96B4 0xBF31 # 0 +0x96B5 0xBF32 # 0 +0x96B6 0xBF33 # 0 +0x96B7 0xBF34 # 0 +0x96B8 0xBF35 # 0 +0x96B9 0xBF36 # 0 +0x96BA 0xBF37 # 0 +0x96BB 0xBF38 # 0 +0x96BC 0xBF39 # 0 +0x96BD 0xBF3A # 0 +0x96BE 0xBF3B # 0 +0x96BF 0xBF3C # 0 +0x96C0 0xBF3D # 0 +0x96C1 0xBF3E # 0 +0x96C2 0xBF3F # 0 +0x96C3 0xBF42 # 0 +0x96C4 0xBF43 # 0 +0x96C5 0xBF45 # 0 +0x96C6 0xBF46 # 0 +0x96C7 0xBF47 # 0 +0x96C8 0xBF49 # 0 +0x96C9 0xBF4A # 0 +0x96CA 0xBF4B # 0 +0x96CB 0xBF4C # 0 +0x96CC 0xBF4D # 0 +0x96CD 0xBF4E # 0 +0x96CE 0xBF4F # 0 +0x96CF 0xBF52 # 0 +0x96D0 0xBF53 # 0 +0x96D1 0xBF54 # 0 +0x96D2 0xBF56 # 0 +0x96D3 0xBF57 # 0 +0x96D4 0xBF58 # 0 +0x96D5 0xBF59 # 0 +0x96D6 0xBF5A # 0 +0x96D7 0xBF5B # 0 +0x96D8 0xBF5C # 0 +0x96D9 0xBF5D # 0 +0x96DA 0xBF5E # 0 +0x96DB 0xBF5F # 0 +0x96DC 0xBF60 # 0 +0x96DD 0xBF61 # 0 +0x96DE 0xBF62 # 0 +0x96DF 0xBF63 # 0 +0x96E0 0xBF64 # 0 +0x96E1 0xBF65 # 0 +0x96E2 0xBF66 # 0 +0x96E3 0xBF67 # 0 +0x96E4 0xBF68 # 0 +0x96E5 0xBF69 # 0 +0x96E6 0xBF6A # 0 +0x96E7 0xBF6B # 0 +0x96E8 0xBF6C # 0 +0x96E9 0xBF6D # 0 +0x96EA 0xBF6E # 0 +0x96EB 0xBF6F # 0 +0x96EC 0xBF70 # 0 +0x96ED 0xBF71 # 0 +0x96EE 0xBF72 # 0 +0x96EF 0xBF73 # 0 +0x96F0 0xBF74 # 0 +0x96F1 0xBF75 # 0 +0x96F2 0xBF76 # 0 +0x96F3 0xBF77 # 0 +0x96F4 0xBF78 # 0 +0x96F5 0xBF79 # 0 +0x96F6 0xBF7A # 0 +0x96F7 0xBF7B # 0 +0x96F8 0xBF7C # 0 +0x96F9 0xBF7D # 0 +0x96FA 0xBF7E # 0 +0x96FB 0xBF7F # 0 +0x96FC 0xBF80 # 0 +0x96FD 0xBF81 # 0 +0x96FE 0xBF82 # 0 +0x9741 0xBF83 # 0 +0x9742 0xBF84 # 0 +0x9743 0xBF85 # 0 +0x9744 0xBF86 # 0 +0x9745 0xBF87 # 0 +0x9746 0xBF88 # 0 +0x9747 0xBF89 # 0 +0x9748 0xBF8A # 0 +0x9749 0xBF8B # 0 +0x974A 0xBF8C # 0 +0x974B 0xBF8D # 0 +0x974C 0xBF8E # 0 +0x974D 0xBF8F # 0 +0x974E 0xBF90 # 0 +0x974F 0xBF91 # 0 +0x9750 0xBF92 # 0 +0x9751 0xBF93 # 0 +0x9752 0xBF95 # 0 +0x9753 0xBF96 # 0 +0x9754 0xBF97 # 0 +0x9755 0xBF98 # 0 +0x9756 0xBF99 # 0 +0x9757 0xBF9A # 0 +0x9758 0xBF9B # 0 +0x9759 0xBF9C # 0 +0x975A 0xBF9D # 0 +0x9761 0xBF9E # 0 +0x9762 0xBF9F # 0 +0x9763 0xBFA0 # 0 +0x9764 0xBFA1 # 0 +0x9765 0xBFA2 # 0 +0x9766 0xBFA3 # 0 +0x9767 0xBFA4 # 0 +0x9768 0xBFA5 # 0 +0x9769 0xBFA6 # 0 +0x976A 0xBFA7 # 0 +0x976B 0xBFA8 # 0 +0x976C 0xBFA9 # 0 +0x976D 0xBFAA # 0 +0x976E 0xBFAB # 0 +0x976F 0xBFAC # 0 +0x9770 0xBFAD # 0 +0x9771 0xBFAE # 0 +0x9772 0xBFAF # 0 +0x9773 0xBFB1 # 0 +0x9774 0xBFB2 # 0 +0x9775 0xBFB3 # 0 +0x9776 0xBFB4 # 0 +0x9777 0xBFB5 # 0 +0x9778 0xBFB6 # 0 +0x9779 0xBFB7 # 0 +0x977A 0xBFB8 # 0 +0x9781 0xBFB9 # 0 +0x9782 0xBFBA # 0 +0x9783 0xBFBB # 0 +0x9784 0xBFBC # 0 +0x9785 0xBFBD # 0 +0x9786 0xBFBE # 0 +0x9787 0xBFBF # 0 +0x9788 0xBFC0 # 0 +0x9789 0xBFC1 # 0 +0x978A 0xBFC2 # 0 +0x978B 0xBFC3 # 0 +0x978C 0xBFC4 # 0 +0x978D 0xBFC6 # 0 +0x978E 0xBFC7 # 0 +0x978F 0xBFC8 # 0 +0x9790 0xBFC9 # 0 +0x9791 0xBFCA # 0 +0x9792 0xBFCB # 0 +0x9793 0xBFCE # 0 +0x9794 0xBFCF # 0 +0x9795 0xBFD1 # 0 +0x9796 0xBFD2 # 0 +0x9797 0xBFD3 # 0 +0x9798 0xBFD5 # 0 +0x9799 0xBFD6 # 0 +0x979A 0xBFD7 # 0 +0x979B 0xBFD8 # 0 +0x979C 0xBFD9 # 0 +0x979D 0xBFDA # 0 +0x979E 0xBFDB # 0 +0x979F 0xBFDD # 0 +0x97A0 0xBFDE # 0 +0x97A1 0xBFE0 # 0 +0x97A2 0xBFE2 # 0 +0x97A3 0xBFE3 # 0 +0x97A4 0xBFE4 # 0 +0x97A5 0xBFE5 # 0 +0x97A6 0xBFE6 # 0 +0x97A7 0xBFE7 # 0 +0x97A8 0xBFE8 # 0 +0x97A9 0xBFE9 # 0 +0x97AA 0xBFEA # 0 +0x97AB 0xBFEB # 0 +0x97AC 0xBFEC # 0 +0x97AD 0xBFED # 0 +0x97AE 0xBFEE # 0 +0x97AF 0xBFEF # 0 +0x97B0 0xBFF0 # 0 +0x97B1 0xBFF1 # 0 +0x97B2 0xBFF2 # 0 +0x97B3 0xBFF3 # 0 +0x97B4 0xBFF4 # 0 +0x97B5 0xBFF5 # 0 +0x97B6 0xBFF6 # 0 +0x97B7 0xBFF7 # 0 +0x97B8 0xBFF8 # 0 +0x97B9 0xBFF9 # 0 +0x97BA 0xBFFA # 0 +0x97BB 0xBFFB # 0 +0x97BC 0xBFFC # 0 +0x97BD 0xBFFD # 0 +0x97BE 0xBFFE # 0 +0x97BF 0xBFFF # 0 +0x97C0 0xC000 # 0 +0x97C1 0xC001 # 0 +0x97C2 0xC002 # 0 +0x97C3 0xC003 # 0 +0x97C4 0xC004 # 0 +0x97C5 0xC005 # 0 +0x97C6 0xC006 # 0 +0x97C7 0xC007 # 0 +0x97C8 0xC008 # 0 +0x97C9 0xC009 # 0 +0x97CA 0xC00A # 0 +0x97CB 0xC00B # 0 +0x97CC 0xC00C # 0 +0x97CD 0xC00D # 0 +0x97CE 0xC00E # 0 +0x97CF 0xC00F # 0 +0x97D0 0xC010 # 0 +0x97D1 0xC011 # 0 +0x97D2 0xC012 # 0 +0x97D3 0xC013 # 0 +0x97D4 0xC014 # 0 +0x97D5 0xC015 # 0 +0x97D6 0xC016 # 0 +0x97D7 0xC017 # 0 +0x97D8 0xC018 # 0 +0x97D9 0xC019 # 0 +0x97DA 0xC01A # 0 +0x97DB 0xC01B # 0 +0x97DC 0xC01C # 0 +0x97DD 0xC01D # 0 +0x97DE 0xC01E # 0 +0x97DF 0xC01F # 0 +0x97E0 0xC020 # 0 +0x97E1 0xC021 # 0 +0x97E2 0xC022 # 0 +0x97E3 0xC023 # 0 +0x97E4 0xC024 # 0 +0x97E5 0xC025 # 0 +0x97E6 0xC026 # 0 +0x97E7 0xC027 # 0 +0x97E8 0xC028 # 0 +0x97E9 0xC029 # 0 +0x97EA 0xC02A # 0 +0x97EB 0xC02B # 0 +0x97EC 0xC02C # 0 +0x97ED 0xC02D # 0 +0x97EE 0xC02E # 0 +0x97EF 0xC02F # 0 +0x97F0 0xC030 # 0 +0x97F1 0xC031 # 0 +0x97F2 0xC032 # 0 +0x97F3 0xC033 # 0 +0x97F4 0xC034 # 0 +0x97F5 0xC035 # 0 +0x97F6 0xC036 # 0 +0x97F7 0xC037 # 0 +0x97F8 0xC038 # 0 +0x97F9 0xC039 # 0 +0x97FA 0xC03A # 0 +0x97FB 0xC03B # 0 +0x97FC 0xC03D # 0 +0x97FD 0xC03E # 0 +0x97FE 0xC03F # 0 +0x9841 0xC040 # 0 +0x9842 0xC041 # 0 +0x9843 0xC042 # 0 +0x9844 0xC043 # 0 +0x9845 0xC044 # 0 +0x9846 0xC045 # 0 +0x9847 0xC046 # 0 +0x9848 0xC047 # 0 +0x9849 0xC048 # 0 +0x984A 0xC049 # 0 +0x984B 0xC04A # 0 +0x984C 0xC04B # 0 +0x984D 0xC04C # 0 +0x984E 0xC04D # 0 +0x984F 0xC04E # 0 +0x9850 0xC04F # 0 +0x9851 0xC050 # 0 +0x9852 0xC052 # 0 +0x9853 0xC053 # 0 +0x9854 0xC054 # 0 +0x9855 0xC055 # 0 +0x9856 0xC056 # 0 +0x9857 0xC057 # 0 +0x9858 0xC059 # 0 +0x9859 0xC05A # 0 +0x985A 0xC05B # 0 +0x9861 0xC05D # 0 +0x9862 0xC05E # 0 +0x9863 0xC05F # 0 +0x9864 0xC061 # 0 +0x9865 0xC062 # 0 +0x9866 0xC063 # 0 +0x9867 0xC064 # 0 +0x9868 0xC065 # 0 +0x9869 0xC066 # 0 +0x986A 0xC067 # 0 +0x986B 0xC06A # 0 +0x986C 0xC06B # 0 +0x986D 0xC06C # 0 +0x986E 0xC06D # 0 +0x986F 0xC06E # 0 +0x9870 0xC06F # 0 +0x9871 0xC070 # 0 +0x9872 0xC071 # 0 +0x9873 0xC072 # 0 +0x9874 0xC073 # 0 +0x9875 0xC074 # 0 +0x9876 0xC075 # 0 +0x9877 0xC076 # 0 +0x9878 0xC077 # 0 +0x9879 0xC078 # 0 +0x987A 0xC079 # 0 +0x9881 0xC07A # 0 +0x9882 0xC07B # 0 +0x9883 0xC07C # 0 +0x9884 0xC07D # 0 +0x9885 0xC07E # 0 +0x9886 0xC07F # 0 +0x9887 0xC080 # 0 +0x9888 0xC081 # 0 +0x9889 0xC082 # 0 +0x988A 0xC083 # 0 +0x988B 0xC084 # 0 +0x988C 0xC085 # 0 +0x988D 0xC086 # 0 +0x988E 0xC087 # 0 +0x988F 0xC088 # 0 +0x9890 0xC089 # 0 +0x9891 0xC08A # 0 +0x9892 0xC08B # 0 +0x9893 0xC08C # 0 +0x9894 0xC08D # 0 +0x9895 0xC08E # 0 +0x9896 0xC08F # 0 +0x9897 0xC092 # 0 +0x9898 0xC093 # 0 +0x9899 0xC095 # 0 +0x989A 0xC096 # 0 +0x989B 0xC097 # 0 +0x989C 0xC099 # 0 +0x989D 0xC09A # 0 +0x989E 0xC09B # 0 +0x989F 0xC09C # 0 +0x98A0 0xC09D # 0 +0x98A1 0xC09E # 0 +0x98A2 0xC09F # 0 +0x98A3 0xC0A2 # 0 +0x98A4 0xC0A4 # 0 +0x98A5 0xC0A6 # 0 +0x98A6 0xC0A7 # 0 +0x98A7 0xC0A8 # 0 +0x98A8 0xC0A9 # 0 +0x98A9 0xC0AA # 0 +0x98AA 0xC0AB # 0 +0x98AB 0xC0AE # 0 +0x98AC 0xC0B1 # 0 +0x98AD 0xC0B2 # 0 +0x98AE 0xC0B7 # 0 +0x98AF 0xC0B8 # 0 +0x98B0 0xC0B9 # 0 +0x98B1 0xC0BA # 0 +0x98B2 0xC0BB # 0 +0x98B3 0xC0BE # 0 +0x98B4 0xC0C2 # 0 +0x98B5 0xC0C3 # 0 +0x98B6 0xC0C4 # 0 +0x98B7 0xC0C6 # 0 +0x98B8 0xC0C7 # 0 +0x98B9 0xC0CA # 0 +0x98BA 0xC0CB # 0 +0x98BB 0xC0CD # 0 +0x98BC 0xC0CE # 0 +0x98BD 0xC0CF # 0 +0x98BE 0xC0D1 # 0 +0x98BF 0xC0D2 # 0 +0x98C0 0xC0D3 # 0 +0x98C1 0xC0D4 # 0 +0x98C2 0xC0D5 # 0 +0x98C3 0xC0D6 # 0 +0x98C4 0xC0D7 # 0 +0x98C5 0xC0DA # 0 +0x98C6 0xC0DE # 0 +0x98C7 0xC0DF # 0 +0x98C8 0xC0E0 # 0 +0x98C9 0xC0E1 # 0 +0x98CA 0xC0E2 # 0 +0x98CB 0xC0E3 # 0 +0x98CC 0xC0E6 # 0 +0x98CD 0xC0E7 # 0 +0x98CE 0xC0E9 # 0 +0x98CF 0xC0EA # 0 +0x98D0 0xC0EB # 0 +0x98D1 0xC0ED # 0 +0x98D2 0xC0EE # 0 +0x98D3 0xC0EF # 0 +0x98D4 0xC0F0 # 0 +0x98D5 0xC0F1 # 0 +0x98D6 0xC0F2 # 0 +0x98D7 0xC0F3 # 0 +0x98D8 0xC0F6 # 0 +0x98D9 0xC0F8 # 0 +0x98DA 0xC0FA # 0 +0x98DB 0xC0FB # 0 +0x98DC 0xC0FC # 0 +0x98DD 0xC0FD # 0 +0x98DE 0xC0FE # 0 +0x98DF 0xC0FF # 0 +0x98E0 0xC101 # 0 +0x98E1 0xC102 # 0 +0x98E2 0xC103 # 0 +0x98E3 0xC105 # 0 +0x98E4 0xC106 # 0 +0x98E5 0xC107 # 0 +0x98E6 0xC109 # 0 +0x98E7 0xC10A # 0 +0x98E8 0xC10B # 0 +0x98E9 0xC10C # 0 +0x98EA 0xC10D # 0 +0x98EB 0xC10E # 0 +0x98EC 0xC10F # 0 +0x98ED 0xC111 # 0 +0x98EE 0xC112 # 0 +0x98EF 0xC113 # 0 +0x98F0 0xC114 # 0 +0x98F1 0xC116 # 0 +0x98F2 0xC117 # 0 +0x98F3 0xC118 # 0 +0x98F4 0xC119 # 0 +0x98F5 0xC11A # 0 +0x98F6 0xC11B # 0 +0x98F7 0xC121 # 0 +0x98F8 0xC122 # 0 +0x98F9 0xC125 # 0 +0x98FA 0xC128 # 0 +0x98FB 0xC129 # 0 +0x98FC 0xC12A # 0 +0x98FD 0xC12B # 0 +0x98FE 0xC12E # 0 +0x9941 0xC132 # 0 +0x9942 0xC133 # 0 +0x9943 0xC134 # 0 +0x9944 0xC135 # 0 +0x9945 0xC137 # 0 +0x9946 0xC13A # 0 +0x9947 0xC13B # 0 +0x9948 0xC13D # 0 +0x9949 0xC13E # 0 +0x994A 0xC13F # 0 +0x994B 0xC141 # 0 +0x994C 0xC142 # 0 +0x994D 0xC143 # 0 +0x994E 0xC144 # 0 +0x994F 0xC145 # 0 +0x9950 0xC146 # 0 +0x9951 0xC147 # 0 +0x9952 0xC14A # 0 +0x9953 0xC14E # 0 +0x9954 0xC14F # 0 +0x9955 0xC150 # 0 +0x9956 0xC151 # 0 +0x9957 0xC152 # 0 +0x9958 0xC153 # 0 +0x9959 0xC156 # 0 +0x995A 0xC157 # 0 +0x9961 0xC159 # 0 +0x9962 0xC15A # 0 +0x9963 0xC15B # 0 +0x9964 0xC15D # 0 +0x9965 0xC15E # 0 +0x9966 0xC15F # 0 +0x9967 0xC160 # 0 +0x9968 0xC161 # 0 +0x9969 0xC162 # 0 +0x996A 0xC163 # 0 +0x996B 0xC166 # 0 +0x996C 0xC16A # 0 +0x996D 0xC16B # 0 +0x996E 0xC16C # 0 +0x996F 0xC16D # 0 +0x9970 0xC16E # 0 +0x9971 0xC16F # 0 +0x9972 0xC171 # 0 +0x9973 0xC172 # 0 +0x9974 0xC173 # 0 +0x9975 0xC175 # 0 +0x9976 0xC176 # 0 +0x9977 0xC177 # 0 +0x9978 0xC179 # 0 +0x9979 0xC17A # 0 +0x997A 0xC17B # 0 +0x9981 0xC17C # 0 +0x9982 0xC17D # 0 +0x9983 0xC17E # 0 +0x9984 0xC17F # 0 +0x9985 0xC180 # 0 +0x9986 0xC181 # 0 +0x9987 0xC182 # 0 +0x9988 0xC183 # 0 +0x9989 0xC184 # 0 +0x998A 0xC186 # 0 +0x998B 0xC187 # 0 +0x998C 0xC188 # 0 +0x998D 0xC189 # 0 +0x998E 0xC18A # 0 +0x998F 0xC18B # 0 +0x9990 0xC18F # 0 +0x9991 0xC191 # 0 +0x9992 0xC192 # 0 +0x9993 0xC193 # 0 +0x9994 0xC195 # 0 +0x9995 0xC197 # 0 +0x9996 0xC198 # 0 +0x9997 0xC199 # 0 +0x9998 0xC19A # 0 +0x9999 0xC19B # 0 +0x999A 0xC19E # 0 +0x999B 0xC1A0 # 0 +0x999C 0xC1A2 # 0 +0x999D 0xC1A3 # 0 +0x999E 0xC1A4 # 0 +0x999F 0xC1A6 # 0 +0x99A0 0xC1A7 # 0 +0x99A1 0xC1AA # 0 +0x99A2 0xC1AB # 0 +0x99A3 0xC1AD # 0 +0x99A4 0xC1AE # 0 +0x99A5 0xC1AF # 0 +0x99A6 0xC1B1 # 0 +0x99A7 0xC1B2 # 0 +0x99A8 0xC1B3 # 0 +0x99A9 0xC1B4 # 0 +0x99AA 0xC1B5 # 0 +0x99AB 0xC1B6 # 0 +0x99AC 0xC1B7 # 0 +0x99AD 0xC1B8 # 0 +0x99AE 0xC1B9 # 0 +0x99AF 0xC1BA # 0 +0x99B0 0xC1BB # 0 +0x99B1 0xC1BC # 0 +0x99B2 0xC1BE # 0 +0x99B3 0xC1BF # 0 +0x99B4 0xC1C0 # 0 +0x99B5 0xC1C1 # 0 +0x99B6 0xC1C2 # 0 +0x99B7 0xC1C3 # 0 +0x99B8 0xC1C5 # 0 +0x99B9 0xC1C6 # 0 +0x99BA 0xC1C7 # 0 +0x99BB 0xC1C9 # 0 +0x99BC 0xC1CA # 0 +0x99BD 0xC1CB # 0 +0x99BE 0xC1CD # 0 +0x99BF 0xC1CE # 0 +0x99C0 0xC1CF # 0 +0x99C1 0xC1D0 # 0 +0x99C2 0xC1D1 # 0 +0x99C3 0xC1D2 # 0 +0x99C4 0xC1D3 # 0 +0x99C5 0xC1D5 # 0 +0x99C6 0xC1D6 # 0 +0x99C7 0xC1D9 # 0 +0x99C8 0xC1DA # 0 +0x99C9 0xC1DB # 0 +0x99CA 0xC1DC # 0 +0x99CB 0xC1DD # 0 +0x99CC 0xC1DE # 0 +0x99CD 0xC1DF # 0 +0x99CE 0xC1E1 # 0 +0x99CF 0xC1E2 # 0 +0x99D0 0xC1E3 # 0 +0x99D1 0xC1E5 # 0 +0x99D2 0xC1E6 # 0 +0x99D3 0xC1E7 # 0 +0x99D4 0xC1E9 # 0 +0x99D5 0xC1EA # 0 +0x99D6 0xC1EB # 0 +0x99D7 0xC1EC # 0 +0x99D8 0xC1ED # 0 +0x99D9 0xC1EE # 0 +0x99DA 0xC1EF # 0 +0x99DB 0xC1F2 # 0 +0x99DC 0xC1F4 # 0 +0x99DD 0xC1F5 # 0 +0x99DE 0xC1F6 # 0 +0x99DF 0xC1F7 # 0 +0x99E0 0xC1F8 # 0 +0x99E1 0xC1F9 # 0 +0x99E2 0xC1FA # 0 +0x99E3 0xC1FB # 0 +0x99E4 0xC1FE # 0 +0x99E5 0xC1FF # 0 +0x99E6 0xC201 # 0 +0x99E7 0xC202 # 0 +0x99E8 0xC203 # 0 +0x99E9 0xC205 # 0 +0x99EA 0xC206 # 0 +0x99EB 0xC207 # 0 +0x99EC 0xC208 # 0 +0x99ED 0xC209 # 0 +0x99EE 0xC20A # 0 +0x99EF 0xC20B # 0 +0x99F0 0xC20E # 0 +0x99F1 0xC210 # 0 +0x99F2 0xC212 # 0 +0x99F3 0xC213 # 0 +0x99F4 0xC214 # 0 +0x99F5 0xC215 # 0 +0x99F6 0xC216 # 0 +0x99F7 0xC217 # 0 +0x99F8 0xC21A # 0 +0x99F9 0xC21B # 0 +0x99FA 0xC21D # 0 +0x99FB 0xC21E # 0 +0x99FC 0xC221 # 0 +0x99FD 0xC222 # 0 +0x99FE 0xC223 # 0 +0x9A41 0xC224 # 0 +0x9A42 0xC225 # 0 +0x9A43 0xC226 # 0 +0x9A44 0xC227 # 0 +0x9A45 0xC22A # 0 +0x9A46 0xC22C # 0 +0x9A47 0xC22E # 0 +0x9A48 0xC230 # 0 +0x9A49 0xC233 # 0 +0x9A4A 0xC235 # 0 +0x9A4B 0xC236 # 0 +0x9A4C 0xC237 # 0 +0x9A4D 0xC238 # 0 +0x9A4E 0xC239 # 0 +0x9A4F 0xC23A # 0 +0x9A50 0xC23B # 0 +0x9A51 0xC23C # 0 +0x9A52 0xC23D # 0 +0x9A53 0xC23E # 0 +0x9A54 0xC23F # 0 +0x9A55 0xC240 # 0 +0x9A56 0xC241 # 0 +0x9A57 0xC242 # 0 +0x9A58 0xC243 # 0 +0x9A59 0xC244 # 0 +0x9A5A 0xC245 # 0 +0x9A61 0xC246 # 0 +0x9A62 0xC247 # 0 +0x9A63 0xC249 # 0 +0x9A64 0xC24A # 0 +0x9A65 0xC24B # 0 +0x9A66 0xC24C # 0 +0x9A67 0xC24D # 0 +0x9A68 0xC24E # 0 +0x9A69 0xC24F # 0 +0x9A6A 0xC252 # 0 +0x9A6B 0xC253 # 0 +0x9A6C 0xC255 # 0 +0x9A6D 0xC256 # 0 +0x9A6E 0xC257 # 0 +0x9A6F 0xC259 # 0 +0x9A70 0xC25A # 0 +0x9A71 0xC25B # 0 +0x9A72 0xC25C # 0 +0x9A73 0xC25D # 0 +0x9A74 0xC25E # 0 +0x9A75 0xC25F # 0 +0x9A76 0xC261 # 0 +0x9A77 0xC262 # 0 +0x9A78 0xC263 # 0 +0x9A79 0xC264 # 0 +0x9A7A 0xC266 # 0 +0x9A81 0xC267 # 0 +0x9A82 0xC268 # 0 +0x9A83 0xC269 # 0 +0x9A84 0xC26A # 0 +0x9A85 0xC26B # 0 +0x9A86 0xC26E # 0 +0x9A87 0xC26F # 0 +0x9A88 0xC271 # 0 +0x9A89 0xC272 # 0 +0x9A8A 0xC273 # 0 +0x9A8B 0xC275 # 0 +0x9A8C 0xC276 # 0 +0x9A8D 0xC277 # 0 +0x9A8E 0xC278 # 0 +0x9A8F 0xC279 # 0 +0x9A90 0xC27A # 0 +0x9A91 0xC27B # 0 +0x9A92 0xC27E # 0 +0x9A93 0xC280 # 0 +0x9A94 0xC282 # 0 +0x9A95 0xC283 # 0 +0x9A96 0xC284 # 0 +0x9A97 0xC285 # 0 +0x9A98 0xC286 # 0 +0x9A99 0xC287 # 0 +0x9A9A 0xC28A # 0 +0x9A9B 0xC28B # 0 +0x9A9C 0xC28C # 0 +0x9A9D 0xC28D # 0 +0x9A9E 0xC28E # 0 +0x9A9F 0xC28F # 0 +0x9AA0 0xC291 # 0 +0x9AA1 0xC292 # 0 +0x9AA2 0xC293 # 0 +0x9AA3 0xC294 # 0 +0x9AA4 0xC295 # 0 +0x9AA5 0xC296 # 0 +0x9AA6 0xC297 # 0 +0x9AA7 0xC299 # 0 +0x9AA8 0xC29A # 0 +0x9AA9 0xC29C # 0 +0x9AAA 0xC29E # 0 +0x9AAB 0xC29F # 0 +0x9AAC 0xC2A0 # 0 +0x9AAD 0xC2A1 # 0 +0x9AAE 0xC2A2 # 0 +0x9AAF 0xC2A3 # 0 +0x9AB0 0xC2A6 # 0 +0x9AB1 0xC2A7 # 0 +0x9AB2 0xC2A9 # 0 +0x9AB3 0xC2AA # 0 +0x9AB4 0xC2AB # 0 +0x9AB5 0xC2AE # 0 +0x9AB6 0xC2AF # 0 +0x9AB7 0xC2B0 # 0 +0x9AB8 0xC2B1 # 0 +0x9AB9 0xC2B2 # 0 +0x9ABA 0xC2B3 # 0 +0x9ABB 0xC2B6 # 0 +0x9ABC 0xC2B8 # 0 +0x9ABD 0xC2BA # 0 +0x9ABE 0xC2BB # 0 +0x9ABF 0xC2BC # 0 +0x9AC0 0xC2BD # 0 +0x9AC1 0xC2BE # 0 +0x9AC2 0xC2BF # 0 +0x9AC3 0xC2C0 # 0 +0x9AC4 0xC2C1 # 0 +0x9AC5 0xC2C2 # 0 +0x9AC6 0xC2C3 # 0 +0x9AC7 0xC2C4 # 0 +0x9AC8 0xC2C5 # 0 +0x9AC9 0xC2C6 # 0 +0x9ACA 0xC2C7 # 0 +0x9ACB 0xC2C8 # 0 +0x9ACC 0xC2C9 # 0 +0x9ACD 0xC2CA # 0 +0x9ACE 0xC2CB # 0 +0x9ACF 0xC2CC # 0 +0x9AD0 0xC2CD # 0 +0x9AD1 0xC2CE # 0 +0x9AD2 0xC2CF # 0 +0x9AD3 0xC2D0 # 0 +0x9AD4 0xC2D1 # 0 +0x9AD5 0xC2D2 # 0 +0x9AD6 0xC2D3 # 0 +0x9AD7 0xC2D4 # 0 +0x9AD8 0xC2D5 # 0 +0x9AD9 0xC2D6 # 0 +0x9ADA 0xC2D7 # 0 +0x9ADB 0xC2D8 # 0 +0x9ADC 0xC2D9 # 0 +0x9ADD 0xC2DA # 0 +0x9ADE 0xC2DB # 0 +0x9ADF 0xC2DE # 0 +0x9AE0 0xC2DF # 0 +0x9AE1 0xC2E1 # 0 +0x9AE2 0xC2E2 # 0 +0x9AE3 0xC2E5 # 0 +0x9AE4 0xC2E6 # 0 +0x9AE5 0xC2E7 # 0 +0x9AE6 0xC2E8 # 0 +0x9AE7 0xC2E9 # 0 +0x9AE8 0xC2EA # 0 +0x9AE9 0xC2EE # 0 +0x9AEA 0xC2F0 # 0 +0x9AEB 0xC2F2 # 0 +0x9AEC 0xC2F3 # 0 +0x9AED 0xC2F4 # 0 +0x9AEE 0xC2F5 # 0 +0x9AEF 0xC2F7 # 0 +0x9AF0 0xC2FA # 0 +0x9AF1 0xC2FD # 0 +0x9AF2 0xC2FE # 0 +0x9AF3 0xC2FF # 0 +0x9AF4 0xC301 # 0 +0x9AF5 0xC302 # 0 +0x9AF6 0xC303 # 0 +0x9AF7 0xC304 # 0 +0x9AF8 0xC305 # 0 +0x9AF9 0xC306 # 0 +0x9AFA 0xC307 # 0 +0x9AFB 0xC30A # 0 +0x9AFC 0xC30B # 0 +0x9AFD 0xC30E # 0 +0x9AFE 0xC30F # 0 +0x9B41 0xC310 # 0 +0x9B42 0xC311 # 0 +0x9B43 0xC312 # 0 +0x9B44 0xC316 # 0 +0x9B45 0xC317 # 0 +0x9B46 0xC319 # 0 +0x9B47 0xC31A # 0 +0x9B48 0xC31B # 0 +0x9B49 0xC31D # 0 +0x9B4A 0xC31E # 0 +0x9B4B 0xC31F # 0 +0x9B4C 0xC320 # 0 +0x9B4D 0xC321 # 0 +0x9B4E 0xC322 # 0 +0x9B4F 0xC323 # 0 +0x9B50 0xC326 # 0 +0x9B51 0xC327 # 0 +0x9B52 0xC32A # 0 +0x9B53 0xC32B # 0 +0x9B54 0xC32C # 0 +0x9B55 0xC32D # 0 +0x9B56 0xC32E # 0 +0x9B57 0xC32F # 0 +0x9B58 0xC330 # 0 +0x9B59 0xC331 # 0 +0x9B5A 0xC332 # 0 +0x9B61 0xC333 # 0 +0x9B62 0xC334 # 0 +0x9B63 0xC335 # 0 +0x9B64 0xC336 # 0 +0x9B65 0xC337 # 0 +0x9B66 0xC338 # 0 +0x9B67 0xC339 # 0 +0x9B68 0xC33A # 0 +0x9B69 0xC33B # 0 +0x9B6A 0xC33C # 0 +0x9B6B 0xC33D # 0 +0x9B6C 0xC33E # 0 +0x9B6D 0xC33F # 0 +0x9B6E 0xC340 # 0 +0x9B6F 0xC341 # 0 +0x9B70 0xC342 # 0 +0x9B71 0xC343 # 0 +0x9B72 0xC344 # 0 +0x9B73 0xC346 # 0 +0x9B74 0xC347 # 0 +0x9B75 0xC348 # 0 +0x9B76 0xC349 # 0 +0x9B77 0xC34A # 0 +0x9B78 0xC34B # 0 +0x9B79 0xC34C # 0 +0x9B7A 0xC34D # 0 +0x9B81 0xC34E # 0 +0x9B82 0xC34F # 0 +0x9B83 0xC350 # 0 +0x9B84 0xC351 # 0 +0x9B85 0xC352 # 0 +0x9B86 0xC353 # 0 +0x9B87 0xC354 # 0 +0x9B88 0xC355 # 0 +0x9B89 0xC356 # 0 +0x9B8A 0xC357 # 0 +0x9B8B 0xC358 # 0 +0x9B8C 0xC359 # 0 +0x9B8D 0xC35A # 0 +0x9B8E 0xC35B # 0 +0x9B8F 0xC35C # 0 +0x9B90 0xC35D # 0 +0x9B91 0xC35E # 0 +0x9B92 0xC35F # 0 +0x9B93 0xC360 # 0 +0x9B94 0xC361 # 0 +0x9B95 0xC362 # 0 +0x9B96 0xC363 # 0 +0x9B97 0xC364 # 0 +0x9B98 0xC365 # 0 +0x9B99 0xC366 # 0 +0x9B9A 0xC367 # 0 +0x9B9B 0xC36A # 0 +0x9B9C 0xC36B # 0 +0x9B9D 0xC36D # 0 +0x9B9E 0xC36E # 0 +0x9B9F 0xC36F # 0 +0x9BA0 0xC371 # 0 +0x9BA1 0xC373 # 0 +0x9BA2 0xC374 # 0 +0x9BA3 0xC375 # 0 +0x9BA4 0xC376 # 0 +0x9BA5 0xC377 # 0 +0x9BA6 0xC37A # 0 +0x9BA7 0xC37B # 0 +0x9BA8 0xC37E # 0 +0x9BA9 0xC37F # 0 +0x9BAA 0xC380 # 0 +0x9BAB 0xC381 # 0 +0x9BAC 0xC382 # 0 +0x9BAD 0xC383 # 0 +0x9BAE 0xC385 # 0 +0x9BAF 0xC386 # 0 +0x9BB0 0xC387 # 0 +0x9BB1 0xC389 # 0 +0x9BB2 0xC38A # 0 +0x9BB3 0xC38B # 0 +0x9BB4 0xC38D # 0 +0x9BB5 0xC38E # 0 +0x9BB6 0xC38F # 0 +0x9BB7 0xC390 # 0 +0x9BB8 0xC391 # 0 +0x9BB9 0xC392 # 0 +0x9BBA 0xC393 # 0 +0x9BBB 0xC394 # 0 +0x9BBC 0xC395 # 0 +0x9BBD 0xC396 # 0 +0x9BBE 0xC397 # 0 +0x9BBF 0xC398 # 0 +0x9BC0 0xC399 # 0 +0x9BC1 0xC39A # 0 +0x9BC2 0xC39B # 0 +0x9BC3 0xC39C # 0 +0x9BC4 0xC39D # 0 +0x9BC5 0xC39E # 0 +0x9BC6 0xC39F # 0 +0x9BC7 0xC3A0 # 0 +0x9BC8 0xC3A1 # 0 +0x9BC9 0xC3A2 # 0 +0x9BCA 0xC3A3 # 0 +0x9BCB 0xC3A4 # 0 +0x9BCC 0xC3A5 # 0 +0x9BCD 0xC3A6 # 0 +0x9BCE 0xC3A7 # 0 +0x9BCF 0xC3A8 # 0 +0x9BD0 0xC3A9 # 0 +0x9BD1 0xC3AA # 0 +0x9BD2 0xC3AB # 0 +0x9BD3 0xC3AC # 0 +0x9BD4 0xC3AD # 0 +0x9BD5 0xC3AE # 0 +0x9BD6 0xC3AF # 0 +0x9BD7 0xC3B0 # 0 +0x9BD8 0xC3B1 # 0 +0x9BD9 0xC3B2 # 0 +0x9BDA 0xC3B3 # 0 +0x9BDB 0xC3B4 # 0 +0x9BDC 0xC3B5 # 0 +0x9BDD 0xC3B6 # 0 +0x9BDE 0xC3B7 # 0 +0x9BDF 0xC3B8 # 0 +0x9BE0 0xC3B9 # 0 +0x9BE1 0xC3BA # 0 +0x9BE2 0xC3BB # 0 +0x9BE3 0xC3BC # 0 +0x9BE4 0xC3BD # 0 +0x9BE5 0xC3BE # 0 +0x9BE6 0xC3BF # 0 +0x9BE7 0xC3C1 # 0 +0x9BE8 0xC3C2 # 0 +0x9BE9 0xC3C3 # 0 +0x9BEA 0xC3C4 # 0 +0x9BEB 0xC3C5 # 0 +0x9BEC 0xC3C6 # 0 +0x9BED 0xC3C7 # 0 +0x9BEE 0xC3C8 # 0 +0x9BEF 0xC3C9 # 0 +0x9BF0 0xC3CA # 0 +0x9BF1 0xC3CB # 0 +0x9BF2 0xC3CC # 0 +0x9BF3 0xC3CD # 0 +0x9BF4 0xC3CE # 0 +0x9BF5 0xC3CF # 0 +0x9BF6 0xC3D0 # 0 +0x9BF7 0xC3D1 # 0 +0x9BF8 0xC3D2 # 0 +0x9BF9 0xC3D3 # 0 +0x9BFA 0xC3D4 # 0 +0x9BFB 0xC3D5 # 0 +0x9BFC 0xC3D6 # 0 +0x9BFD 0xC3D7 # 0 +0x9BFE 0xC3DA # 0 +0x9C41 0xC3DB # 0 +0x9C42 0xC3DD # 0 +0x9C43 0xC3DE # 0 +0x9C44 0xC3E1 # 0 +0x9C45 0xC3E3 # 0 +0x9C46 0xC3E4 # 0 +0x9C47 0xC3E5 # 0 +0x9C48 0xC3E6 # 0 +0x9C49 0xC3E7 # 0 +0x9C4A 0xC3EA # 0 +0x9C4B 0xC3EB # 0 +0x9C4C 0xC3EC # 0 +0x9C4D 0xC3EE # 0 +0x9C4E 0xC3EF # 0 +0x9C4F 0xC3F0 # 0 +0x9C50 0xC3F1 # 0 +0x9C51 0xC3F2 # 0 +0x9C52 0xC3F3 # 0 +0x9C53 0xC3F6 # 0 +0x9C54 0xC3F7 # 0 +0x9C55 0xC3F9 # 0 +0x9C56 0xC3FA # 0 +0x9C57 0xC3FB # 0 +0x9C58 0xC3FC # 0 +0x9C59 0xC3FD # 0 +0x9C5A 0xC3FE # 0 +0x9C61 0xC3FF # 0 +0x9C62 0xC400 # 0 +0x9C63 0xC401 # 0 +0x9C64 0xC402 # 0 +0x9C65 0xC403 # 0 +0x9C66 0xC404 # 0 +0x9C67 0xC405 # 0 +0x9C68 0xC406 # 0 +0x9C69 0xC407 # 0 +0x9C6A 0xC409 # 0 +0x9C6B 0xC40A # 0 +0x9C6C 0xC40B # 0 +0x9C6D 0xC40C # 0 +0x9C6E 0xC40D # 0 +0x9C6F 0xC40E # 0 +0x9C70 0xC40F # 0 +0x9C71 0xC411 # 0 +0x9C72 0xC412 # 0 +0x9C73 0xC413 # 0 +0x9C74 0xC414 # 0 +0x9C75 0xC415 # 0 +0x9C76 0xC416 # 0 +0x9C77 0xC417 # 0 +0x9C78 0xC418 # 0 +0x9C79 0xC419 # 0 +0x9C7A 0xC41A # 0 +0x9C81 0xC41B # 0 +0x9C82 0xC41C # 0 +0x9C83 0xC41D # 0 +0x9C84 0xC41E # 0 +0x9C85 0xC41F # 0 +0x9C86 0xC420 # 0 +0x9C87 0xC421 # 0 +0x9C88 0xC422 # 0 +0x9C89 0xC423 # 0 +0x9C8A 0xC425 # 0 +0x9C8B 0xC426 # 0 +0x9C8C 0xC427 # 0 +0x9C8D 0xC428 # 0 +0x9C8E 0xC429 # 0 +0x9C8F 0xC42A # 0 +0x9C90 0xC42B # 0 +0x9C91 0xC42D # 0 +0x9C92 0xC42E # 0 +0x9C93 0xC42F # 0 +0x9C94 0xC431 # 0 +0x9C95 0xC432 # 0 +0x9C96 0xC433 # 0 +0x9C97 0xC435 # 0 +0x9C98 0xC436 # 0 +0x9C99 0xC437 # 0 +0x9C9A 0xC438 # 0 +0x9C9B 0xC439 # 0 +0x9C9C 0xC43A # 0 +0x9C9D 0xC43B # 0 +0x9C9E 0xC43E # 0 +0x9C9F 0xC43F # 0 +0x9CA0 0xC440 # 0 +0x9CA1 0xC441 # 0 +0x9CA2 0xC442 # 0 +0x9CA3 0xC443 # 0 +0x9CA4 0xC444 # 0 +0x9CA5 0xC445 # 0 +0x9CA6 0xC446 # 0 +0x9CA7 0xC447 # 0 +0x9CA8 0xC449 # 0 +0x9CA9 0xC44A # 0 +0x9CAA 0xC44B # 0 +0x9CAB 0xC44C # 0 +0x9CAC 0xC44D # 0 +0x9CAD 0xC44E # 0 +0x9CAE 0xC44F # 0 +0x9CAF 0xC450 # 0 +0x9CB0 0xC451 # 0 +0x9CB1 0xC452 # 0 +0x9CB2 0xC453 # 0 +0x9CB3 0xC454 # 0 +0x9CB4 0xC455 # 0 +0x9CB5 0xC456 # 0 +0x9CB6 0xC457 # 0 +0x9CB7 0xC458 # 0 +0x9CB8 0xC459 # 0 +0x9CB9 0xC45A # 0 +0x9CBA 0xC45B # 0 +0x9CBB 0xC45C # 0 +0x9CBC 0xC45D # 0 +0x9CBD 0xC45E # 0 +0x9CBE 0xC45F # 0 +0x9CBF 0xC460 # 0 +0x9CC0 0xC461 # 0 +0x9CC1 0xC462 # 0 +0x9CC2 0xC463 # 0 +0x9CC3 0xC466 # 0 +0x9CC4 0xC467 # 0 +0x9CC5 0xC469 # 0 +0x9CC6 0xC46A # 0 +0x9CC7 0xC46B # 0 +0x9CC8 0xC46D # 0 +0x9CC9 0xC46E # 0 +0x9CCA 0xC46F # 0 +0x9CCB 0xC470 # 0 +0x9CCC 0xC471 # 0 +0x9CCD 0xC472 # 0 +0x9CCE 0xC473 # 0 +0x9CCF 0xC476 # 0 +0x9CD0 0xC477 # 0 +0x9CD1 0xC478 # 0 +0x9CD2 0xC47A # 0 +0x9CD3 0xC47B # 0 +0x9CD4 0xC47C # 0 +0x9CD5 0xC47D # 0 +0x9CD6 0xC47E # 0 +0x9CD7 0xC47F # 0 +0x9CD8 0xC481 # 0 +0x9CD9 0xC482 # 0 +0x9CDA 0xC483 # 0 +0x9CDB 0xC484 # 0 +0x9CDC 0xC485 # 0 +0x9CDD 0xC486 # 0 +0x9CDE 0xC487 # 0 +0x9CDF 0xC488 # 0 +0x9CE0 0xC489 # 0 +0x9CE1 0xC48A # 0 +0x9CE2 0xC48B # 0 +0x9CE3 0xC48C # 0 +0x9CE4 0xC48D # 0 +0x9CE5 0xC48E # 0 +0x9CE6 0xC48F # 0 +0x9CE7 0xC490 # 0 +0x9CE8 0xC491 # 0 +0x9CE9 0xC492 # 0 +0x9CEA 0xC493 # 0 +0x9CEB 0xC495 # 0 +0x9CEC 0xC496 # 0 +0x9CED 0xC497 # 0 +0x9CEE 0xC498 # 0 +0x9CEF 0xC499 # 0 +0x9CF0 0xC49A # 0 +0x9CF1 0xC49B # 0 +0x9CF2 0xC49D # 0 +0x9CF3 0xC49E # 0 +0x9CF4 0xC49F # 0 +0x9CF5 0xC4A0 # 0 +0x9CF6 0xC4A1 # 0 +0x9CF7 0xC4A2 # 0 +0x9CF8 0xC4A3 # 0 +0x9CF9 0xC4A4 # 0 +0x9CFA 0xC4A5 # 0 +0x9CFB 0xC4A6 # 0 +0x9CFC 0xC4A7 # 0 +0x9CFD 0xC4A8 # 0 +0x9CFE 0xC4A9 # 0 +0x9D41 0xC4AA # 0 +0x9D42 0xC4AB # 0 +0x9D43 0xC4AC # 0 +0x9D44 0xC4AD # 0 +0x9D45 0xC4AE # 0 +0x9D46 0xC4AF # 0 +0x9D47 0xC4B0 # 0 +0x9D48 0xC4B1 # 0 +0x9D49 0xC4B2 # 0 +0x9D4A 0xC4B3 # 0 +0x9D4B 0xC4B4 # 0 +0x9D4C 0xC4B5 # 0 +0x9D4D 0xC4B6 # 0 +0x9D4E 0xC4B7 # 0 +0x9D4F 0xC4B9 # 0 +0x9D50 0xC4BA # 0 +0x9D51 0xC4BB # 0 +0x9D52 0xC4BD # 0 +0x9D53 0xC4BE # 0 +0x9D54 0xC4BF # 0 +0x9D55 0xC4C0 # 0 +0x9D56 0xC4C1 # 0 +0x9D57 0xC4C2 # 0 +0x9D58 0xC4C3 # 0 +0x9D59 0xC4C4 # 0 +0x9D5A 0xC4C5 # 0 +0x9D61 0xC4C6 # 0 +0x9D62 0xC4C7 # 0 +0x9D63 0xC4C8 # 0 +0x9D64 0xC4C9 # 0 +0x9D65 0xC4CA # 0 +0x9D66 0xC4CB # 0 +0x9D67 0xC4CC # 0 +0x9D68 0xC4CD # 0 +0x9D69 0xC4CE # 0 +0x9D6A 0xC4CF # 0 +0x9D6B 0xC4D0 # 0 +0x9D6C 0xC4D1 # 0 +0x9D6D 0xC4D2 # 0 +0x9D6E 0xC4D3 # 0 +0x9D6F 0xC4D4 # 0 +0x9D70 0xC4D5 # 0 +0x9D71 0xC4D6 # 0 +0x9D72 0xC4D7 # 0 +0x9D73 0xC4D8 # 0 +0x9D74 0xC4D9 # 0 +0x9D75 0xC4DA # 0 +0x9D76 0xC4DB # 0 +0x9D77 0xC4DC # 0 +0x9D78 0xC4DD # 0 +0x9D79 0xC4DE # 0 +0x9D7A 0xC4DF # 0 +0x9D81 0xC4E0 # 0 +0x9D82 0xC4E1 # 0 +0x9D83 0xC4E2 # 0 +0x9D84 0xC4E3 # 0 +0x9D85 0xC4E4 # 0 +0x9D86 0xC4E5 # 0 +0x9D87 0xC4E6 # 0 +0x9D88 0xC4E7 # 0 +0x9D89 0xC4E8 # 0 +0x9D8A 0xC4EA # 0 +0x9D8B 0xC4EB # 0 +0x9D8C 0xC4EC # 0 +0x9D8D 0xC4ED # 0 +0x9D8E 0xC4EE # 0 +0x9D8F 0xC4EF # 0 +0x9D90 0xC4F2 # 0 +0x9D91 0xC4F3 # 0 +0x9D92 0xC4F5 # 0 +0x9D93 0xC4F6 # 0 +0x9D94 0xC4F7 # 0 +0x9D95 0xC4F9 # 0 +0x9D96 0xC4FB # 0 +0x9D97 0xC4FC # 0 +0x9D98 0xC4FD # 0 +0x9D99 0xC4FE # 0 +0x9D9A 0xC502 # 0 +0x9D9B 0xC503 # 0 +0x9D9C 0xC504 # 0 +0x9D9D 0xC505 # 0 +0x9D9E 0xC506 # 0 +0x9D9F 0xC507 # 0 +0x9DA0 0xC508 # 0 +0x9DA1 0xC509 # 0 +0x9DA2 0xC50A # 0 +0x9DA3 0xC50B # 0 +0x9DA4 0xC50D # 0 +0x9DA5 0xC50E # 0 +0x9DA6 0xC50F # 0 +0x9DA7 0xC511 # 0 +0x9DA8 0xC512 # 0 +0x9DA9 0xC513 # 0 +0x9DAA 0xC515 # 0 +0x9DAB 0xC516 # 0 +0x9DAC 0xC517 # 0 +0x9DAD 0xC518 # 0 +0x9DAE 0xC519 # 0 +0x9DAF 0xC51A # 0 +0x9DB0 0xC51B # 0 +0x9DB1 0xC51D # 0 +0x9DB2 0xC51E # 0 +0x9DB3 0xC51F # 0 +0x9DB4 0xC520 # 0 +0x9DB5 0xC521 # 0 +0x9DB6 0xC522 # 0 +0x9DB7 0xC523 # 0 +0x9DB8 0xC524 # 0 +0x9DB9 0xC525 # 0 +0x9DBA 0xC526 # 0 +0x9DBB 0xC527 # 0 +0x9DBC 0xC52A # 0 +0x9DBD 0xC52B # 0 +0x9DBE 0xC52D # 0 +0x9DBF 0xC52E # 0 +0x9DC0 0xC52F # 0 +0x9DC1 0xC531 # 0 +0x9DC2 0xC532 # 0 +0x9DC3 0xC533 # 0 +0x9DC4 0xC534 # 0 +0x9DC5 0xC535 # 0 +0x9DC6 0xC536 # 0 +0x9DC7 0xC537 # 0 +0x9DC8 0xC53A # 0 +0x9DC9 0xC53C # 0 +0x9DCA 0xC53E # 0 +0x9DCB 0xC53F # 0 +0x9DCC 0xC540 # 0 +0x9DCD 0xC541 # 0 +0x9DCE 0xC542 # 0 +0x9DCF 0xC543 # 0 +0x9DD0 0xC546 # 0 +0x9DD1 0xC547 # 0 +0x9DD2 0xC54B # 0 +0x9DD3 0xC54F # 0 +0x9DD4 0xC550 # 0 +0x9DD5 0xC551 # 0 +0x9DD6 0xC552 # 0 +0x9DD7 0xC556 # 0 +0x9DD8 0xC55A # 0 +0x9DD9 0xC55B # 0 +0x9DDA 0xC55C # 0 +0x9DDB 0xC55F # 0 +0x9DDC 0xC562 # 0 +0x9DDD 0xC563 # 0 +0x9DDE 0xC565 # 0 +0x9DDF 0xC566 # 0 +0x9DE0 0xC567 # 0 +0x9DE1 0xC569 # 0 +0x9DE2 0xC56A # 0 +0x9DE3 0xC56B # 0 +0x9DE4 0xC56C # 0 +0x9DE5 0xC56D # 0 +0x9DE6 0xC56E # 0 +0x9DE7 0xC56F # 0 +0x9DE8 0xC572 # 0 +0x9DE9 0xC576 # 0 +0x9DEA 0xC577 # 0 +0x9DEB 0xC578 # 0 +0x9DEC 0xC579 # 0 +0x9DED 0xC57A # 0 +0x9DEE 0xC57B # 0 +0x9DEF 0xC57E # 0 +0x9DF0 0xC57F # 0 +0x9DF1 0xC581 # 0 +0x9DF2 0xC582 # 0 +0x9DF3 0xC583 # 0 +0x9DF4 0xC585 # 0 +0x9DF5 0xC586 # 0 +0x9DF6 0xC588 # 0 +0x9DF7 0xC589 # 0 +0x9DF8 0xC58A # 0 +0x9DF9 0xC58B # 0 +0x9DFA 0xC58E # 0 +0x9DFB 0xC590 # 0 +0x9DFC 0xC592 # 0 +0x9DFD 0xC593 # 0 +0x9DFE 0xC594 # 0 +0x9E41 0xC596 # 0 +0x9E42 0xC599 # 0 +0x9E43 0xC59A # 0 +0x9E44 0xC59B # 0 +0x9E45 0xC59D # 0 +0x9E46 0xC59E # 0 +0x9E47 0xC59F # 0 +0x9E48 0xC5A1 # 0 +0x9E49 0xC5A2 # 0 +0x9E4A 0xC5A3 # 0 +0x9E4B 0xC5A4 # 0 +0x9E4C 0xC5A5 # 0 +0x9E4D 0xC5A6 # 0 +0x9E4E 0xC5A7 # 0 +0x9E4F 0xC5A8 # 0 +0x9E50 0xC5AA # 0 +0x9E51 0xC5AB # 0 +0x9E52 0xC5AC # 0 +0x9E53 0xC5AD # 0 +0x9E54 0xC5AE # 0 +0x9E55 0xC5AF # 0 +0x9E56 0xC5B0 # 0 +0x9E57 0xC5B1 # 0 +0x9E58 0xC5B2 # 0 +0x9E59 0xC5B3 # 0 +0x9E5A 0xC5B6 # 0 +0x9E61 0xC5B7 # 0 +0x9E62 0xC5BA # 0 +0x9E63 0xC5BF # 0 +0x9E64 0xC5C0 # 0 +0x9E65 0xC5C1 # 0 +0x9E66 0xC5C2 # 0 +0x9E67 0xC5C3 # 0 +0x9E68 0xC5CB # 0 +0x9E69 0xC5CD # 0 +0x9E6A 0xC5CF # 0 +0x9E6B 0xC5D2 # 0 +0x9E6C 0xC5D3 # 0 +0x9E6D 0xC5D5 # 0 +0x9E6E 0xC5D6 # 0 +0x9E6F 0xC5D7 # 0 +0x9E70 0xC5D9 # 0 +0x9E71 0xC5DA # 0 +0x9E72 0xC5DB # 0 +0x9E73 0xC5DC # 0 +0x9E74 0xC5DD # 0 +0x9E75 0xC5DE # 0 +0x9E76 0xC5DF # 0 +0x9E77 0xC5E2 # 0 +0x9E78 0xC5E4 # 0 +0x9E79 0xC5E6 # 0 +0x9E7A 0xC5E7 # 0 +0x9E81 0xC5E8 # 0 +0x9E82 0xC5E9 # 0 +0x9E83 0xC5EA # 0 +0x9E84 0xC5EB # 0 +0x9E85 0xC5EF # 0 +0x9E86 0xC5F1 # 0 +0x9E87 0xC5F2 # 0 +0x9E88 0xC5F3 # 0 +0x9E89 0xC5F5 # 0 +0x9E8A 0xC5F8 # 0 +0x9E8B 0xC5F9 # 0 +0x9E8C 0xC5FA # 0 +0x9E8D 0xC5FB # 0 +0x9E8E 0xC602 # 0 +0x9E8F 0xC603 # 0 +0x9E90 0xC604 # 0 +0x9E91 0xC609 # 0 +0x9E92 0xC60A # 0 +0x9E93 0xC60B # 0 +0x9E94 0xC60D # 0 +0x9E95 0xC60E # 0 +0x9E96 0xC60F # 0 +0x9E97 0xC611 # 0 +0x9E98 0xC612 # 0 +0x9E99 0xC613 # 0 +0x9E9A 0xC614 # 0 +0x9E9B 0xC615 # 0 +0x9E9C 0xC616 # 0 +0x9E9D 0xC617 # 0 +0x9E9E 0xC61A # 0 +0x9E9F 0xC61D # 0 +0x9EA0 0xC61E # 0 +0x9EA1 0xC61F # 0 +0x9EA2 0xC620 # 0 +0x9EA3 0xC621 # 0 +0x9EA4 0xC622 # 0 +0x9EA5 0xC623 # 0 +0x9EA6 0xC626 # 0 +0x9EA7 0xC627 # 0 +0x9EA8 0xC629 # 0 +0x9EA9 0xC62A # 0 +0x9EAA 0xC62B # 0 +0x9EAB 0xC62F # 0 +0x9EAC 0xC631 # 0 +0x9EAD 0xC632 # 0 +0x9EAE 0xC636 # 0 +0x9EAF 0xC638 # 0 +0x9EB0 0xC63A # 0 +0x9EB1 0xC63C # 0 +0x9EB2 0xC63D # 0 +0x9EB3 0xC63E # 0 +0x9EB4 0xC63F # 0 +0x9EB5 0xC642 # 0 +0x9EB6 0xC643 # 0 +0x9EB7 0xC645 # 0 +0x9EB8 0xC646 # 0 +0x9EB9 0xC647 # 0 +0x9EBA 0xC649 # 0 +0x9EBB 0xC64A # 0 +0x9EBC 0xC64B # 0 +0x9EBD 0xC64C # 0 +0x9EBE 0xC64D # 0 +0x9EBF 0xC64E # 0 +0x9EC0 0xC64F # 0 +0x9EC1 0xC652 # 0 +0x9EC2 0xC656 # 0 +0x9EC3 0xC657 # 0 +0x9EC4 0xC658 # 0 +0x9EC5 0xC659 # 0 +0x9EC6 0xC65A # 0 +0x9EC7 0xC65B # 0 +0x9EC8 0xC65E # 0 +0x9EC9 0xC65F # 0 +0x9ECA 0xC661 # 0 +0x9ECB 0xC662 # 0 +0x9ECC 0xC663 # 0 +0x9ECD 0xC664 # 0 +0x9ECE 0xC665 # 0 +0x9ECF 0xC666 # 0 +0x9ED0 0xC667 # 0 +0x9ED1 0xC668 # 0 +0x9ED2 0xC669 # 0 +0x9ED3 0xC66A # 0 +0x9ED4 0xC66B # 0 +0x9ED5 0xC66D # 0 +0x9ED6 0xC66E # 0 +0x9ED7 0xC670 # 0 +0x9ED8 0xC672 # 0 +0x9ED9 0xC673 # 0 +0x9EDA 0xC674 # 0 +0x9EDB 0xC675 # 0 +0x9EDC 0xC676 # 0 +0x9EDD 0xC677 # 0 +0x9EDE 0xC67A # 0 +0x9EDF 0xC67B # 0 +0x9EE0 0xC67D # 0 +0x9EE1 0xC67E # 0 +0x9EE2 0xC67F # 0 +0x9EE3 0xC681 # 0 +0x9EE4 0xC682 # 0 +0x9EE5 0xC683 # 0 +0x9EE6 0xC684 # 0 +0x9EE7 0xC685 # 0 +0x9EE8 0xC686 # 0 +0x9EE9 0xC687 # 0 +0x9EEA 0xC68A # 0 +0x9EEB 0xC68C # 0 +0x9EEC 0xC68E # 0 +0x9EED 0xC68F # 0 +0x9EEE 0xC690 # 0 +0x9EEF 0xC691 # 0 +0x9EF0 0xC692 # 0 +0x9EF1 0xC693 # 0 +0x9EF2 0xC696 # 0 +0x9EF3 0xC697 # 0 +0x9EF4 0xC699 # 0 +0x9EF5 0xC69A # 0 +0x9EF6 0xC69B # 0 +0x9EF7 0xC69D # 0 +0x9EF8 0xC69E # 0 +0x9EF9 0xC69F # 0 +0x9EFA 0xC6A0 # 0 +0x9EFB 0xC6A1 # 0 +0x9EFC 0xC6A2 # 0 +0x9EFD 0xC6A3 # 0 +0x9EFE 0xC6A6 # 0 +0x9F41 0xC6A8 # 0 +0x9F42 0xC6AA # 0 +0x9F43 0xC6AB # 0 +0x9F44 0xC6AC # 0 +0x9F45 0xC6AD # 0 +0x9F46 0xC6AE # 0 +0x9F47 0xC6AF # 0 +0x9F48 0xC6B2 # 0 +0x9F49 0xC6B3 # 0 +0x9F4A 0xC6B5 # 0 +0x9F4B 0xC6B6 # 0 +0x9F4C 0xC6B7 # 0 +0x9F4D 0xC6BB # 0 +0x9F4E 0xC6BC # 0 +0x9F4F 0xC6BD # 0 +0x9F50 0xC6BE # 0 +0x9F51 0xC6BF # 0 +0x9F52 0xC6C2 # 0 +0x9F53 0xC6C4 # 0 +0x9F54 0xC6C6 # 0 +0x9F55 0xC6C7 # 0 +0x9F56 0xC6C8 # 0 +0x9F57 0xC6C9 # 0 +0x9F58 0xC6CA # 0 +0x9F59 0xC6CB # 0 +0x9F5A 0xC6CE # 0 +0x9F61 0xC6CF # 0 +0x9F62 0xC6D1 # 0 +0x9F63 0xC6D2 # 0 +0x9F64 0xC6D3 # 0 +0x9F65 0xC6D5 # 0 +0x9F66 0xC6D6 # 0 +0x9F67 0xC6D7 # 0 +0x9F68 0xC6D8 # 0 +0x9F69 0xC6D9 # 0 +0x9F6A 0xC6DA # 0 +0x9F6B 0xC6DB # 0 +0x9F6C 0xC6DE # 0 +0x9F6D 0xC6DF # 0 +0x9F6E 0xC6E2 # 0 +0x9F6F 0xC6E3 # 0 +0x9F70 0xC6E4 # 0 +0x9F71 0xC6E5 # 0 +0x9F72 0xC6E6 # 0 +0x9F73 0xC6E7 # 0 +0x9F74 0xC6EA # 0 +0x9F75 0xC6EB # 0 +0x9F76 0xC6ED # 0 +0x9F77 0xC6EE # 0 +0x9F78 0xC6EF # 0 +0x9F79 0xC6F1 # 0 +0x9F7A 0xC6F2 # 0 +0x9F81 0xC6F3 # 0 +0x9F82 0xC6F4 # 0 +0x9F83 0xC6F5 # 0 +0x9F84 0xC6F6 # 0 +0x9F85 0xC6F7 # 0 +0x9F86 0xC6FA # 0 +0x9F87 0xC6FB # 0 +0x9F88 0xC6FC # 0 +0x9F89 0xC6FE # 0 +0x9F8A 0xC6FF # 0 +0x9F8B 0xC700 # 0 +0x9F8C 0xC701 # 0 +0x9F8D 0xC702 # 0 +0x9F8E 0xC703 # 0 +0x9F8F 0xC706 # 0 +0x9F90 0xC707 # 0 +0x9F91 0xC709 # 0 +0x9F92 0xC70A # 0 +0x9F93 0xC70B # 0 +0x9F94 0xC70D # 0 +0x9F95 0xC70E # 0 +0x9F96 0xC70F # 0 +0x9F97 0xC710 # 0 +0x9F98 0xC711 # 0 +0x9F99 0xC712 # 0 +0x9F9A 0xC713 # 0 +0x9F9B 0xC716 # 0 +0x9F9C 0xC718 # 0 +0x9F9D 0xC71A # 0 +0x9F9E 0xC71B # 0 +0x9F9F 0xC71C # 0 +0x9FA0 0xC71D # 0 +0x9FA1 0xC71E # 0 +0x9FA2 0xC71F # 0 +0x9FA3 0xC722 # 0 +0x9FA4 0xC723 # 0 +0x9FA5 0xC725 # 0 +0x9FA6 0xC726 # 0 +0x9FA7 0xC727 # 0 +0x9FA8 0xC729 # 0 +0x9FA9 0xC72A # 0 +0x9FAA 0xC72B # 0 +0x9FAB 0xC72C # 0 +0x9FAC 0xC72D # 0 +0x9FAD 0xC72E # 0 +0x9FAE 0xC72F # 0 +0x9FAF 0xC732 # 0 +0x9FB0 0xC734 # 0 +0x9FB1 0xC736 # 0 +0x9FB2 0xC738 # 0 +0x9FB3 0xC739 # 0 +0x9FB4 0xC73A # 0 +0x9FB5 0xC73B # 0 +0x9FB6 0xC73E # 0 +0x9FB7 0xC73F # 0 +0x9FB8 0xC741 # 0 +0x9FB9 0xC742 # 0 +0x9FBA 0xC743 # 0 +0x9FBB 0xC745 # 0 +0x9FBC 0xC746 # 0 +0x9FBD 0xC747 # 0 +0x9FBE 0xC748 # 0 +0x9FBF 0xC749 # 0 +0x9FC0 0xC74B # 0 +0x9FC1 0xC74E # 0 +0x9FC2 0xC750 # 0 +0x9FC3 0xC759 # 0 +0x9FC4 0xC75A # 0 +0x9FC5 0xC75B # 0 +0x9FC6 0xC75D # 0 +0x9FC7 0xC75E # 0 +0x9FC8 0xC75F # 0 +0x9FC9 0xC761 # 0 +0x9FCA 0xC762 # 0 +0x9FCB 0xC763 # 0 +0x9FCC 0xC764 # 0 +0x9FCD 0xC765 # 0 +0x9FCE 0xC766 # 0 +0x9FCF 0xC767 # 0 +0x9FD0 0xC769 # 0 +0x9FD1 0xC76A # 0 +0x9FD2 0xC76C # 0 +0x9FD3 0xC76D # 0 +0x9FD4 0xC76E # 0 +0x9FD5 0xC76F # 0 +0x9FD6 0xC770 # 0 +0x9FD7 0xC771 # 0 +0x9FD8 0xC772 # 0 +0x9FD9 0xC773 # 0 +0x9FDA 0xC776 # 0 +0x9FDB 0xC777 # 0 +0x9FDC 0xC779 # 0 +0x9FDD 0xC77A # 0 +0x9FDE 0xC77B # 0 +0x9FDF 0xC77F # 0 +0x9FE0 0xC780 # 0 +0x9FE1 0xC781 # 0 +0x9FE2 0xC782 # 0 +0x9FE3 0xC786 # 0 +0x9FE4 0xC78B # 0 +0x9FE5 0xC78C # 0 +0x9FE6 0xC78D # 0 +0x9FE7 0xC78F # 0 +0x9FE8 0xC792 # 0 +0x9FE9 0xC793 # 0 +0x9FEA 0xC795 # 0 +0x9FEB 0xC799 # 0 +0x9FEC 0xC79B # 0 +0x9FED 0xC79C # 0 +0x9FEE 0xC79D # 0 +0x9FEF 0xC79E # 0 +0x9FF0 0xC79F # 0 +0x9FF1 0xC7A2 # 0 +0x9FF2 0xC7A7 # 0 +0x9FF3 0xC7A8 # 0 +0x9FF4 0xC7A9 # 0 +0x9FF5 0xC7AA # 0 +0x9FF6 0xC7AB # 0 +0x9FF7 0xC7AE # 0 +0x9FF8 0xC7AF # 0 +0x9FF9 0xC7B1 # 0 +0x9FFA 0xC7B2 # 0 +0x9FFB 0xC7B3 # 0 +0x9FFC 0xC7B5 # 0 +0x9FFD 0xC7B6 # 0 +0x9FFE 0xC7B7 # 0 +0xA041 0xC7B8 # 0 +0xA042 0xC7B9 # 0 +0xA043 0xC7BA # 0 +0xA044 0xC7BB # 0 +0xA045 0xC7BE # 0 +0xA046 0xC7C2 # 0 +0xA047 0xC7C3 # 0 +0xA048 0xC7C4 # 0 +0xA049 0xC7C5 # 0 +0xA04A 0xC7C6 # 0 +0xA04B 0xC7C7 # 0 +0xA04C 0xC7CA # 0 +0xA04D 0xC7CB # 0 +0xA04E 0xC7CD # 0 +0xA04F 0xC7CF # 0 +0xA050 0xC7D1 # 0 +0xA051 0xC7D2 # 0 +0xA052 0xC7D3 # 0 +0xA053 0xC7D4 # 0 +0xA054 0xC7D5 # 0 +0xA055 0xC7D6 # 0 +0xA056 0xC7D7 # 0 +0xA057 0xC7D9 # 0 +0xA058 0xC7DA # 0 +0xA059 0xC7DB # 0 +0xA05A 0xC7DC # 0 +0xA061 0xC7DE # 0 +0xA062 0xC7DF # 0 +0xA063 0xC7E0 # 0 +0xA064 0xC7E1 # 0 +0xA065 0xC7E2 # 0 +0xA066 0xC7E3 # 0 +0xA067 0xC7E5 # 0 +0xA068 0xC7E6 # 0 +0xA069 0xC7E7 # 0 +0xA06A 0xC7E9 # 0 +0xA06B 0xC7EA # 0 +0xA06C 0xC7EB # 0 +0xA06D 0xC7ED # 0 +0xA06E 0xC7EE # 0 +0xA06F 0xC7EF # 0 +0xA070 0xC7F0 # 0 +0xA071 0xC7F1 # 0 +0xA072 0xC7F2 # 0 +0xA073 0xC7F3 # 0 +0xA074 0xC7F4 # 0 +0xA075 0xC7F5 # 0 +0xA076 0xC7F6 # 0 +0xA077 0xC7F7 # 0 +0xA078 0xC7F8 # 0 +0xA079 0xC7F9 # 0 +0xA07A 0xC7FA # 0 +0xA081 0xC7FB # 0 +0xA082 0xC7FC # 0 +0xA083 0xC7FD # 0 +0xA084 0xC7FE # 0 +0xA085 0xC7FF # 0 +0xA086 0xC802 # 0 +0xA087 0xC803 # 0 +0xA088 0xC805 # 0 +0xA089 0xC806 # 0 +0xA08A 0xC807 # 0 +0xA08B 0xC809 # 0 +0xA08C 0xC80B # 0 +0xA08D 0xC80C # 0 +0xA08E 0xC80D # 0 +0xA08F 0xC80E # 0 +0xA090 0xC80F # 0 +0xA091 0xC812 # 0 +0xA092 0xC814 # 0 +0xA093 0xC817 # 0 +0xA094 0xC818 # 0 +0xA095 0xC819 # 0 +0xA096 0xC81A # 0 +0xA097 0xC81B # 0 +0xA098 0xC81E # 0 +0xA099 0xC81F # 0 +0xA09A 0xC821 # 0 +0xA09B 0xC822 # 0 +0xA09C 0xC823 # 0 +0xA09D 0xC825 # 0 +0xA09E 0xC826 # 0 +0xA09F 0xC827 # 0 +0xA0A0 0xC828 # 0 +0xA0A1 0xC829 # 0 +0xA0A2 0xC82A # 0 +0xA0A3 0xC82B # 0 +0xA0A4 0xC82E # 0 +0xA0A5 0xC830 # 0 +0xA0A6 0xC832 # 0 +0xA0A7 0xC833 # 0 +0xA0A8 0xC834 # 0 +0xA0A9 0xC835 # 0 +0xA0AA 0xC836 # 0 +0xA0AB 0xC837 # 0 +0xA0AC 0xC839 # 0 +0xA0AD 0xC83A # 0 +0xA0AE 0xC83B # 0 +0xA0AF 0xC83D # 0 +0xA0B0 0xC83E # 0 +0xA0B1 0xC83F # 0 +0xA0B2 0xC841 # 0 +0xA0B3 0xC842 # 0 +0xA0B4 0xC843 # 0 +0xA0B5 0xC844 # 0 +0xA0B6 0xC845 # 0 +0xA0B7 0xC846 # 0 +0xA0B8 0xC847 # 0 +0xA0B9 0xC84A # 0 +0xA0BA 0xC84B # 0 +0xA0BB 0xC84E # 0 +0xA0BC 0xC84F # 0 +0xA0BD 0xC850 # 0 +0xA0BE 0xC851 # 0 +0xA0BF 0xC852 # 0 +0xA0C0 0xC853 # 0 +0xA0C1 0xC855 # 0 +0xA0C2 0xC856 # 0 +0xA0C3 0xC857 # 0 +0xA0C4 0xC858 # 0 +0xA0C5 0xC859 # 0 +0xA0C6 0xC85A # 0 +0xA0C7 0xC85B # 0 +0xA0C8 0xC85C # 0 +0xA0C9 0xC85D # 0 +0xA0CA 0xC85E # 0 +0xA0CB 0xC85F # 0 +0xA0CC 0xC860 # 0 +0xA0CD 0xC861 # 0 +0xA0CE 0xC862 # 0 +0xA0CF 0xC863 # 0 +0xA0D0 0xC864 # 0 +0xA0D1 0xC865 # 0 +0xA0D2 0xC866 # 0 +0xA0D3 0xC867 # 0 +0xA0D4 0xC868 # 0 +0xA0D5 0xC869 # 0 +0xA0D6 0xC86A # 0 +0xA0D7 0xC86B # 0 +0xA0D8 0xC86C # 0 +0xA0D9 0xC86D # 0 +0xA0DA 0xC86E # 0 +0xA0DB 0xC86F # 0 +0xA0DC 0xC872 # 0 +0xA0DD 0xC873 # 0 +0xA0DE 0xC875 # 0 +0xA0DF 0xC876 # 0 +0xA0E0 0xC877 # 0 +0xA0E1 0xC879 # 0 +0xA0E2 0xC87B # 0 +0xA0E3 0xC87C # 0 +0xA0E4 0xC87D # 0 +0xA0E5 0xC87E # 0 +0xA0E6 0xC87F # 0 +0xA0E7 0xC882 # 0 +0xA0E8 0xC884 # 0 +0xA0E9 0xC888 # 0 +0xA0EA 0xC889 # 0 +0xA0EB 0xC88A # 0 +0xA0EC 0xC88E # 0 +0xA0ED 0xC88F # 0 +0xA0EE 0xC890 # 0 +0xA0EF 0xC891 # 0 +0xA0F0 0xC892 # 0 +0xA0F1 0xC893 # 0 +0xA0F2 0xC895 # 0 +0xA0F3 0xC896 # 0 +0xA0F4 0xC897 # 0 +0xA0F5 0xC898 # 0 +0xA0F6 0xC899 # 0 +0xA0F7 0xC89A # 0 +0xA0F8 0xC89B # 0 +0xA0F9 0xC89C # 0 +0xA0FA 0xC89E # 0 +0xA0FB 0xC8A0 # 0 +0xA0FC 0xC8A2 # 0 +0xA0FD 0xC8A3 # 0 +0xA0FE 0xC8A4 # 0 +0xA141 0xC8A5 # 0 +0xA142 0xC8A6 # 0 +0xA143 0xC8A7 # 0 +0xA144 0xC8A9 # 0 +0xA145 0xC8AA # 0 +0xA146 0xC8AB # 0 +0xA147 0xC8AC # 0 +0xA148 0xC8AD # 0 +0xA149 0xC8AE # 0 +0xA14A 0xC8AF # 0 +0xA14B 0xC8B0 # 0 +0xA14C 0xC8B1 # 0 +0xA14D 0xC8B2 # 0 +0xA14E 0xC8B3 # 0 +0xA14F 0xC8B4 # 0 +0xA150 0xC8B5 # 0 +0xA151 0xC8B6 # 0 +0xA152 0xC8B7 # 0 +0xA153 0xC8B8 # 0 +0xA154 0xC8B9 # 0 +0xA155 0xC8BA # 0 +0xA156 0xC8BB # 0 +0xA157 0xC8BE # 0 +0xA158 0xC8BF # 0 +0xA159 0xC8C0 # 0 +0xA15A 0xC8C1 # 0 +0xA161 0xC8C2 # 0 +0xA162 0xC8C3 # 0 +0xA163 0xC8C5 # 0 +0xA164 0xC8C6 # 0 +0xA165 0xC8C7 # 0 +0xA166 0xC8C9 # 0 +0xA167 0xC8CA # 0 +0xA168 0xC8CB # 0 +0xA169 0xC8CD # 0 +0xA16A 0xC8CE # 0 +0xA16B 0xC8CF # 0 +0xA16C 0xC8D0 # 0 +0xA16D 0xC8D1 # 0 +0xA16E 0xC8D2 # 0 +0xA16F 0xC8D3 # 0 +0xA170 0xC8D6 # 0 +0xA171 0xC8D8 # 0 +0xA172 0xC8DA # 0 +0xA173 0xC8DB # 0 +0xA174 0xC8DC # 0 +0xA175 0xC8DD # 0 +0xA176 0xC8DE # 0 +0xA177 0xC8DF # 0 +0xA178 0xC8E2 # 0 +0xA179 0xC8E3 # 0 +0xA17A 0xC8E5 # 0 +0xA181 0xC8E6 # 0 +0xA182 0xC8E7 # 0 +0xA183 0xC8E8 # 0 +0xA184 0xC8E9 # 0 +0xA185 0xC8EA # 0 +0xA186 0xC8EB # 0 +0xA187 0xC8EC # 0 +0xA188 0xC8ED # 0 +0xA189 0xC8EE # 0 +0xA18A 0xC8EF # 0 +0xA18B 0xC8F0 # 0 +0xA18C 0xC8F1 # 0 +0xA18D 0xC8F2 # 0 +0xA18E 0xC8F3 # 0 +0xA18F 0xC8F4 # 0 +0xA190 0xC8F6 # 0 +0xA191 0xC8F7 # 0 +0xA192 0xC8F8 # 0 +0xA193 0xC8F9 # 0 +0xA194 0xC8FA # 0 +0xA195 0xC8FB # 0 +0xA196 0xC8FE # 0 +0xA197 0xC8FF # 0 +0xA198 0xC901 # 0 +0xA199 0xC902 # 0 +0xA19A 0xC903 # 0 +0xA19B 0xC907 # 0 +0xA19C 0xC908 # 0 +0xA19D 0xC909 # 0 +0xA19E 0xC90A # 0 +0xA19F 0xC90B # 0 +0xA1A0 0xC90E # 0 +0xA1A1 0x3000 # 0 +0xA1A2 0x3001 # 0 +0xA1A3 0x3002 # 0 +0xA1A4 0x00B7 # 0 +0xA1A5 0x2025 # 0 +0xA1A6 0x2026 # 0 +0xA1A7 0x00A8 # 0 +0xA1A8 0x3003 # 0 +0xA1A9 0x00AD # 0 +0xA1AA 0x2015 # 0 +0xA1AB 0x2225 # 0 +0xA1AC 0xFF3C # 0 +0xA1AD 0x223C # 0 +0xA1AE 0x2018 # 0 +0xA1AF 0x2019 # 0 +0xA1B0 0x201C # 0 +0xA1B1 0x201D # 0 +0xA1B2 0x3014 # 0 +0xA1B3 0x3015 # 0 +0xA1B4 0x3008 # 0 +0xA1B5 0x3009 # 0 +0xA1B6 0x300A # 0 +0xA1B7 0x300B # 0 +0xA1B8 0x300C # 0 +0xA1B9 0x300D # 0 +0xA1BA 0x300E # 0 +0xA1BB 0x300F # 0 +0xA1BC 0x3010 # 0 +0xA1BD 0x3011 # 0 +0xA1BE 0x00B1 # 0 +0xA1BF 0x00D7 # 0 +0xA1C0 0x00F7 # 0 +0xA1C1 0x2260 # 0 +0xA1C2 0x2264 # 0 +0xA1C3 0x2265 # 0 +0xA1C4 0x221E # 0 +0xA1C5 0x2234 # 0 +0xA1C6 0x00B0 # 0 +0xA1C7 0x2032 # 0 +0xA1C8 0x2033 # 0 +0xA1C9 0x2103 # 0 +0xA1CA 0x212B # 0 +0xA1CB 0xFFE0 # 0 +0xA1CC 0xFFE1 # 0 +0xA1CD 0xFFE5 # 0 +0xA1CE 0x2642 # 0 +0xA1CF 0x2640 # 0 +0xA1D0 0x2220 # 0 +0xA1D1 0x22A5 # 0 +0xA1D2 0x2312 # 0 +0xA1D3 0x2202 # 0 +0xA1D4 0x2207 # 0 +0xA1D5 0x2261 # 0 +0xA1D6 0x2252 # 0 +0xA1D7 0x00A7 # 0 +0xA1D8 0x203B # 0 +0xA1D9 0x2606 # 0 +0xA1DA 0x2605 # 0 +0xA1DB 0x25CB # 0 +0xA1DC 0x25CF # 0 +0xA1DD 0x25CE # 0 +0xA1DE 0x25C7 # 0 +0xA1DF 0x25C6 # 0 +0xA1E0 0x25A1 # 0 +0xA1E1 0x25A0 # 0 +0xA1E2 0x25B3 # 0 +0xA1E3 0x25B2 # 0 +0xA1E4 0x25BD # 0 +0xA1E5 0x25BC # 0 +0xA1E6 0x2192 # 0 +0xA1E7 0x2190 # 0 +0xA1E8 0x2191 # 0 +0xA1E9 0x2193 # 0 +0xA1EA 0x2194 # 0 +0xA1EB 0x3013 # 0 +0xA1EC 0x226A # 0 +0xA1ED 0x226B # 0 +0xA1EE 0x221A # 0 +0xA1EF 0x223D # 0 +0xA1F0 0x221D # 0 +0xA1F1 0x2235 # 0 +0xA1F2 0x222B # 0 +0xA1F3 0x222C # 0 +0xA1F4 0x2208 # 0 +0xA1F5 0x220B # 0 +0xA1F6 0x2286 # 0 +0xA1F7 0x2287 # 0 +0xA1F8 0x2282 # 0 +0xA1F9 0x2283 # 0 +0xA1FA 0x222A # 0 +0xA1FB 0x2229 # 0 +0xA1FC 0x2227 # 0 +0xA1FD 0x2228 # 0 +0xA1FE 0xFFE2 # 0 +0xA241 0xC910 # 0 +0xA242 0xC912 # 0 +0xA243 0xC913 # 0 +0xA244 0xC914 # 0 +0xA245 0xC915 # 0 +0xA246 0xC916 # 0 +0xA247 0xC917 # 0 +0xA248 0xC919 # 0 +0xA249 0xC91A # 0 +0xA24A 0xC91B # 0 +0xA24B 0xC91C # 0 +0xA24C 0xC91D # 0 +0xA24D 0xC91E # 0 +0xA24E 0xC91F # 0 +0xA24F 0xC920 # 0 +0xA250 0xC921 # 0 +0xA251 0xC922 # 0 +0xA252 0xC923 # 0 +0xA253 0xC924 # 0 +0xA254 0xC925 # 0 +0xA255 0xC926 # 0 +0xA256 0xC927 # 0 +0xA257 0xC928 # 0 +0xA258 0xC929 # 0 +0xA259 0xC92A # 0 +0xA25A 0xC92B # 0 +0xA261 0xC92D # 0 +0xA262 0xC92E # 0 +0xA263 0xC92F # 0 +0xA264 0xC930 # 0 +0xA265 0xC931 # 0 +0xA266 0xC932 # 0 +0xA267 0xC933 # 0 +0xA268 0xC935 # 0 +0xA269 0xC936 # 0 +0xA26A 0xC937 # 0 +0xA26B 0xC938 # 0 +0xA26C 0xC939 # 0 +0xA26D 0xC93A # 0 +0xA26E 0xC93B # 0 +0xA26F 0xC93C # 0 +0xA270 0xC93D # 0 +0xA271 0xC93E # 0 +0xA272 0xC93F # 0 +0xA273 0xC940 # 0 +0xA274 0xC941 # 0 +0xA275 0xC942 # 0 +0xA276 0xC943 # 0 +0xA277 0xC944 # 0 +0xA278 0xC945 # 0 +0xA279 0xC946 # 0 +0xA27A 0xC947 # 0 +0xA281 0xC948 # 0 +0xA282 0xC949 # 0 +0xA283 0xC94A # 0 +0xA284 0xC94B # 0 +0xA285 0xC94C # 0 +0xA286 0xC94D # 0 +0xA287 0xC94E # 0 +0xA288 0xC94F # 0 +0xA289 0xC952 # 0 +0xA28A 0xC953 # 0 +0xA28B 0xC955 # 0 +0xA28C 0xC956 # 0 +0xA28D 0xC957 # 0 +0xA28E 0xC959 # 0 +0xA28F 0xC95A # 0 +0xA290 0xC95B # 0 +0xA291 0xC95C # 0 +0xA292 0xC95D # 0 +0xA293 0xC95E # 0 +0xA294 0xC95F # 0 +0xA295 0xC962 # 0 +0xA296 0xC964 # 0 +0xA297 0xC965 # 0 +0xA298 0xC966 # 0 +0xA299 0xC967 # 0 +0xA29A 0xC968 # 0 +0xA29B 0xC969 # 0 +0xA29C 0xC96A # 0 +0xA29D 0xC96B # 0 +0xA29E 0xC96D # 0 +0xA29F 0xC96E # 0 +0xA2A0 0xC96F # 0 +0xA2A1 0x21D2 # 0 +0xA2A2 0x21D4 # 0 +0xA2A3 0x2200 # 0 +0xA2A4 0x2203 # 0 +0xA2A5 0x00B4 # 0 +0xA2A6 0xFF5E # 0 +0xA2A7 0x02C7 # 0 +0xA2A8 0x02D8 # 0 +0xA2A9 0x02DD # 0 +0xA2AA 0x02DA # 0 +0xA2AB 0x02D9 # 0 +0xA2AC 0x00B8 # 0 +0xA2AD 0x02DB # 0 +0xA2AE 0x00A1 # 0 +0xA2AF 0x00BF # 0 +0xA2B0 0x02D0 # 0 +0xA2B1 0x222E # 0 +0xA2B2 0x2211 # 0 +0xA2B3 0x220F # 0 +0xA2B4 0x00A4 # 0 +0xA2B5 0x2109 # 0 +0xA2B6 0x2030 # 0 +0xA2B7 0x25C1 # 0 +0xA2B8 0x25C0 # 0 +0xA2B9 0x25B7 # 0 +0xA2BA 0x25B6 # 0 +0xA2BB 0x2664 # 0 +0xA2BC 0x2660 # 0 +0xA2BD 0x2661 # 0 +0xA2BE 0x2665 # 0 +0xA2BF 0x2667 # 0 +0xA2C0 0x2663 # 0 +0xA2C1 0x2299 # 0 +0xA2C2 0x25C8 # 0 +0xA2C3 0x25A3 # 0 +0xA2C4 0x25D0 # 0 +0xA2C5 0x25D1 # 0 +0xA2C6 0x2592 # 0 +0xA2C7 0x25A4 # 0 +0xA2C8 0x25A5 # 0 +0xA2C9 0x25A8 # 0 +0xA2CA 0x25A7 # 0 +0xA2CB 0x25A6 # 0 +0xA2CC 0x25A9 # 0 +0xA2CD 0x2668 # 0 +0xA2CE 0x260F # 0 +0xA2CF 0x260E # 0 +0xA2D0 0x261C # 0 +0xA2D1 0x261E # 0 +0xA2D2 0x00B6 # 0 +0xA2D3 0x2020 # 0 +0xA2D4 0x2021 # 0 +0xA2D5 0x2195 # 0 +0xA2D6 0x2197 # 0 +0xA2D7 0x2199 # 0 +0xA2D8 0x2196 # 0 +0xA2D9 0x2198 # 0 +0xA2DA 0x266D # 0 +0xA2DB 0x2669 # 0 +0xA2DC 0x266A # 0 +0xA2DD 0x266C # 0 +0xA2DE 0x327F # 0 +0xA2DF 0x321C # 0 +0xA2E0 0x2116 # 0 +0xA2E1 0x33C7 # 0 +0xA2E2 0x2122 # 0 +0xA2E3 0x33C2 # 0 +0xA2E4 0x33D8 # 0 +0xA2E5 0x2121 # 0 +0xA2E6 0x20AC # 0 +0xA2E7 0x00AE # 0 +0xA341 0xC971 # 0 +0xA342 0xC972 # 0 +0xA343 0xC973 # 0 +0xA344 0xC975 # 0 +0xA345 0xC976 # 0 +0xA346 0xC977 # 0 +0xA347 0xC978 # 0 +0xA348 0xC979 # 0 +0xA349 0xC97A # 0 +0xA34A 0xC97B # 0 +0xA34B 0xC97D # 0 +0xA34C 0xC97E # 0 +0xA34D 0xC97F # 0 +0xA34E 0xC980 # 0 +0xA34F 0xC981 # 0 +0xA350 0xC982 # 0 +0xA351 0xC983 # 0 +0xA352 0xC984 # 0 +0xA353 0xC985 # 0 +0xA354 0xC986 # 0 +0xA355 0xC987 # 0 +0xA356 0xC98A # 0 +0xA357 0xC98B # 0 +0xA358 0xC98D # 0 +0xA359 0xC98E # 0 +0xA35A 0xC98F # 0 +0xA361 0xC991 # 0 +0xA362 0xC992 # 0 +0xA363 0xC993 # 0 +0xA364 0xC994 # 0 +0xA365 0xC995 # 0 +0xA366 0xC996 # 0 +0xA367 0xC997 # 0 +0xA368 0xC99A # 0 +0xA369 0xC99C # 0 +0xA36A 0xC99E # 0 +0xA36B 0xC99F # 0 +0xA36C 0xC9A0 # 0 +0xA36D 0xC9A1 # 0 +0xA36E 0xC9A2 # 0 +0xA36F 0xC9A3 # 0 +0xA370 0xC9A4 # 0 +0xA371 0xC9A5 # 0 +0xA372 0xC9A6 # 0 +0xA373 0xC9A7 # 0 +0xA374 0xC9A8 # 0 +0xA375 0xC9A9 # 0 +0xA376 0xC9AA # 0 +0xA377 0xC9AB # 0 +0xA378 0xC9AC # 0 +0xA379 0xC9AD # 0 +0xA37A 0xC9AE # 0 +0xA381 0xC9AF # 0 +0xA382 0xC9B0 # 0 +0xA383 0xC9B1 # 0 +0xA384 0xC9B2 # 0 +0xA385 0xC9B3 # 0 +0xA386 0xC9B4 # 0 +0xA387 0xC9B5 # 0 +0xA388 0xC9B6 # 0 +0xA389 0xC9B7 # 0 +0xA38A 0xC9B8 # 0 +0xA38B 0xC9B9 # 0 +0xA38C 0xC9BA # 0 +0xA38D 0xC9BB # 0 +0xA38E 0xC9BC # 0 +0xA38F 0xC9BD # 0 +0xA390 0xC9BE # 0 +0xA391 0xC9BF # 0 +0xA392 0xC9C2 # 0 +0xA393 0xC9C3 # 0 +0xA394 0xC9C5 # 0 +0xA395 0xC9C6 # 0 +0xA396 0xC9C9 # 0 +0xA397 0xC9CB # 0 +0xA398 0xC9CC # 0 +0xA399 0xC9CD # 0 +0xA39A 0xC9CE # 0 +0xA39B 0xC9CF # 0 +0xA39C 0xC9D2 # 0 +0xA39D 0xC9D4 # 0 +0xA39E 0xC9D7 # 0 +0xA39F 0xC9D8 # 0 +0xA3A0 0xC9DB # 0 +0xA3A1 0xFF01 # 0 +0xA3A2 0xFF02 # 0 +0xA3A3 0xFF03 # 0 +0xA3A4 0xFF04 # 0 +0xA3A5 0xFF05 # 0 +0xA3A6 0xFF06 # 0 +0xA3A7 0xFF07 # 0 +0xA3A8 0xFF08 # 0 +0xA3A9 0xFF09 # 0 +0xA3AA 0xFF0A # 0 +0xA3AB 0xFF0B # 0 +0xA3AC 0xFF0C # 0 +0xA3AD 0xFF0D # 0 +0xA3AE 0xFF0E # 0 +0xA3AF 0xFF0F # 0 +0xA3B0 0xFF10 # 0 +0xA3B1 0xFF11 # 0 +0xA3B2 0xFF12 # 0 +0xA3B3 0xFF13 # 0 +0xA3B4 0xFF14 # 0 +0xA3B5 0xFF15 # 0 +0xA3B6 0xFF16 # 0 +0xA3B7 0xFF17 # 0 +0xA3B8 0xFF18 # 0 +0xA3B9 0xFF19 # 0 +0xA3BA 0xFF1A # 0 +0xA3BB 0xFF1B # 0 +0xA3BC 0xFF1C # 0 +0xA3BD 0xFF1D # 0 +0xA3BE 0xFF1E # 0 +0xA3BF 0xFF1F # 0 +0xA3C0 0xFF20 # 0 +0xA3C1 0xFF21 # 0 +0xA3C2 0xFF22 # 0 +0xA3C3 0xFF23 # 0 +0xA3C4 0xFF24 # 0 +0xA3C5 0xFF25 # 0 +0xA3C6 0xFF26 # 0 +0xA3C7 0xFF27 # 0 +0xA3C8 0xFF28 # 0 +0xA3C9 0xFF29 # 0 +0xA3CA 0xFF2A # 0 +0xA3CB 0xFF2B # 0 +0xA3CC 0xFF2C # 0 +0xA3CD 0xFF2D # 0 +0xA3CE 0xFF2E # 0 +0xA3CF 0xFF2F # 0 +0xA3D0 0xFF30 # 0 +0xA3D1 0xFF31 # 0 +0xA3D2 0xFF32 # 0 +0xA3D3 0xFF33 # 0 +0xA3D4 0xFF34 # 0 +0xA3D5 0xFF35 # 0 +0xA3D6 0xFF36 # 0 +0xA3D7 0xFF37 # 0 +0xA3D8 0xFF38 # 0 +0xA3D9 0xFF39 # 0 +0xA3DA 0xFF3A # 0 +0xA3DB 0xFF3B # 0 +0xA3DC 0xFFE6 # 0 +0xA3DD 0xFF3D # 0 +0xA3DE 0xFF3E # 0 +0xA3DF 0xFF3F # 0 +0xA3E0 0xFF40 # 0 +0xA3E1 0xFF41 # 0 +0xA3E2 0xFF42 # 0 +0xA3E3 0xFF43 # 0 +0xA3E4 0xFF44 # 0 +0xA3E5 0xFF45 # 0 +0xA3E6 0xFF46 # 0 +0xA3E7 0xFF47 # 0 +0xA3E8 0xFF48 # 0 +0xA3E9 0xFF49 # 0 +0xA3EA 0xFF4A # 0 +0xA3EB 0xFF4B # 0 +0xA3EC 0xFF4C # 0 +0xA3ED 0xFF4D # 0 +0xA3EE 0xFF4E # 0 +0xA3EF 0xFF4F # 0 +0xA3F0 0xFF50 # 0 +0xA3F1 0xFF51 # 0 +0xA3F2 0xFF52 # 0 +0xA3F3 0xFF53 # 0 +0xA3F4 0xFF54 # 0 +0xA3F5 0xFF55 # 0 +0xA3F6 0xFF56 # 0 +0xA3F7 0xFF57 # 0 +0xA3F8 0xFF58 # 0 +0xA3F9 0xFF59 # 0 +0xA3FA 0xFF5A # 0 +0xA3FB 0xFF5B # 0 +0xA3FC 0xFF5C # 0 +0xA3FD 0xFF5D # 0 +0xA3FE 0xFFE3 # 0 +0xA441 0xC9DE # 0 +0xA442 0xC9DF # 0 +0xA443 0xC9E1 # 0 +0xA444 0xC9E3 # 0 +0xA445 0xC9E5 # 0 +0xA446 0xC9E6 # 0 +0xA447 0xC9E8 # 0 +0xA448 0xC9E9 # 0 +0xA449 0xC9EA # 0 +0xA44A 0xC9EB # 0 +0xA44B 0xC9EE # 0 +0xA44C 0xC9F2 # 0 +0xA44D 0xC9F3 # 0 +0xA44E 0xC9F4 # 0 +0xA44F 0xC9F5 # 0 +0xA450 0xC9F6 # 0 +0xA451 0xC9F7 # 0 +0xA452 0xC9FA # 0 +0xA453 0xC9FB # 0 +0xA454 0xC9FD # 0 +0xA455 0xC9FE # 0 +0xA456 0xC9FF # 0 +0xA457 0xCA01 # 0 +0xA458 0xCA02 # 0 +0xA459 0xCA03 # 0 +0xA45A 0xCA04 # 0 +0xA461 0xCA05 # 0 +0xA462 0xCA06 # 0 +0xA463 0xCA07 # 0 +0xA464 0xCA0A # 0 +0xA465 0xCA0E # 0 +0xA466 0xCA0F # 0 +0xA467 0xCA10 # 0 +0xA468 0xCA11 # 0 +0xA469 0xCA12 # 0 +0xA46A 0xCA13 # 0 +0xA46B 0xCA15 # 0 +0xA46C 0xCA16 # 0 +0xA46D 0xCA17 # 0 +0xA46E 0xCA19 # 0 +0xA46F 0xCA1A # 0 +0xA470 0xCA1B # 0 +0xA471 0xCA1C # 0 +0xA472 0xCA1D # 0 +0xA473 0xCA1E # 0 +0xA474 0xCA1F # 0 +0xA475 0xCA20 # 0 +0xA476 0xCA21 # 0 +0xA477 0xCA22 # 0 +0xA478 0xCA23 # 0 +0xA479 0xCA24 # 0 +0xA47A 0xCA25 # 0 +0xA481 0xCA26 # 0 +0xA482 0xCA27 # 0 +0xA483 0xCA28 # 0 +0xA484 0xCA2A # 0 +0xA485 0xCA2B # 0 +0xA486 0xCA2C # 0 +0xA487 0xCA2D # 0 +0xA488 0xCA2E # 0 +0xA489 0xCA2F # 0 +0xA48A 0xCA30 # 0 +0xA48B 0xCA31 # 0 +0xA48C 0xCA32 # 0 +0xA48D 0xCA33 # 0 +0xA48E 0xCA34 # 0 +0xA48F 0xCA35 # 0 +0xA490 0xCA36 # 0 +0xA491 0xCA37 # 0 +0xA492 0xCA38 # 0 +0xA493 0xCA39 # 0 +0xA494 0xCA3A # 0 +0xA495 0xCA3B # 0 +0xA496 0xCA3C # 0 +0xA497 0xCA3D # 0 +0xA498 0xCA3E # 0 +0xA499 0xCA3F # 0 +0xA49A 0xCA40 # 0 +0xA49B 0xCA41 # 0 +0xA49C 0xCA42 # 0 +0xA49D 0xCA43 # 0 +0xA49E 0xCA44 # 0 +0xA49F 0xCA45 # 0 +0xA4A0 0xCA46 # 0 +0xA4A1 0x3131 # 0 +0xA4A2 0x3132 # 0 +0xA4A3 0x3133 # 0 +0xA4A4 0x3134 # 0 +0xA4A5 0x3135 # 0 +0xA4A6 0x3136 # 0 +0xA4A7 0x3137 # 0 +0xA4A8 0x3138 # 0 +0xA4A9 0x3139 # 0 +0xA4AA 0x313A # 0 +0xA4AB 0x313B # 0 +0xA4AC 0x313C # 0 +0xA4AD 0x313D # 0 +0xA4AE 0x313E # 0 +0xA4AF 0x313F # 0 +0xA4B0 0x3140 # 0 +0xA4B1 0x3141 # 0 +0xA4B2 0x3142 # 0 +0xA4B3 0x3143 # 0 +0xA4B4 0x3144 # 0 +0xA4B5 0x3145 # 0 +0xA4B6 0x3146 # 0 +0xA4B7 0x3147 # 0 +0xA4B8 0x3148 # 0 +0xA4B9 0x3149 # 0 +0xA4BA 0x314A # 0 +0xA4BB 0x314B # 0 +0xA4BC 0x314C # 0 +0xA4BD 0x314D # 0 +0xA4BE 0x314E # 0 +0xA4BF 0x314F # 0 +0xA4C0 0x3150 # 0 +0xA4C1 0x3151 # 0 +0xA4C2 0x3152 # 0 +0xA4C3 0x3153 # 0 +0xA4C4 0x3154 # 0 +0xA4C5 0x3155 # 0 +0xA4C6 0x3156 # 0 +0xA4C7 0x3157 # 0 +0xA4C8 0x3158 # 0 +0xA4C9 0x3159 # 0 +0xA4CA 0x315A # 0 +0xA4CB 0x315B # 0 +0xA4CC 0x315C # 0 +0xA4CD 0x315D # 0 +0xA4CE 0x315E # 0 +0xA4CF 0x315F # 0 +0xA4D0 0x3160 # 0 +0xA4D1 0x3161 # 0 +0xA4D2 0x3162 # 0 +0xA4D3 0x3163 # 0 +0xA4D4 0x3164 # 0 +0xA4D5 0x3165 # 0 +0xA4D6 0x3166 # 0 +0xA4D7 0x3167 # 0 +0xA4D8 0x3168 # 0 +0xA4D9 0x3169 # 0 +0xA4DA 0x316A # 0 +0xA4DB 0x316B # 0 +0xA4DC 0x316C # 0 +0xA4DD 0x316D # 0 +0xA4DE 0x316E # 0 +0xA4DF 0x316F # 0 +0xA4E0 0x3170 # 0 +0xA4E1 0x3171 # 0 +0xA4E2 0x3172 # 0 +0xA4E3 0x3173 # 0 +0xA4E4 0x3174 # 0 +0xA4E5 0x3175 # 0 +0xA4E6 0x3176 # 0 +0xA4E7 0x3177 # 0 +0xA4E8 0x3178 # 0 +0xA4E9 0x3179 # 0 +0xA4EA 0x317A # 0 +0xA4EB 0x317B # 0 +0xA4EC 0x317C # 0 +0xA4ED 0x317D # 0 +0xA4EE 0x317E # 0 +0xA4EF 0x317F # 0 +0xA4F0 0x3180 # 0 +0xA4F1 0x3181 # 0 +0xA4F2 0x3182 # 0 +0xA4F3 0x3183 # 0 +0xA4F4 0x3184 # 0 +0xA4F5 0x3185 # 0 +0xA4F6 0x3186 # 0 +0xA4F7 0x3187 # 0 +0xA4F8 0x3188 # 0 +0xA4F9 0x3189 # 0 +0xA4FA 0x318A # 0 +0xA4FB 0x318B # 0 +0xA4FC 0x318C # 0 +0xA4FD 0x318D # 0 +0xA4FE 0x318E # 0 +0xA541 0xCA47 # 0 +0xA542 0xCA48 # 0 +0xA543 0xCA49 # 0 +0xA544 0xCA4A # 0 +0xA545 0xCA4B # 0 +0xA546 0xCA4E # 0 +0xA547 0xCA4F # 0 +0xA548 0xCA51 # 0 +0xA549 0xCA52 # 0 +0xA54A 0xCA53 # 0 +0xA54B 0xCA55 # 0 +0xA54C 0xCA56 # 0 +0xA54D 0xCA57 # 0 +0xA54E 0xCA58 # 0 +0xA54F 0xCA59 # 0 +0xA550 0xCA5A # 0 +0xA551 0xCA5B # 0 +0xA552 0xCA5E # 0 +0xA553 0xCA62 # 0 +0xA554 0xCA63 # 0 +0xA555 0xCA64 # 0 +0xA556 0xCA65 # 0 +0xA557 0xCA66 # 0 +0xA558 0xCA67 # 0 +0xA559 0xCA69 # 0 +0xA55A 0xCA6A # 0 +0xA561 0xCA6B # 0 +0xA562 0xCA6C # 0 +0xA563 0xCA6D # 0 +0xA564 0xCA6E # 0 +0xA565 0xCA6F # 0 +0xA566 0xCA70 # 0 +0xA567 0xCA71 # 0 +0xA568 0xCA72 # 0 +0xA569 0xCA73 # 0 +0xA56A 0xCA74 # 0 +0xA56B 0xCA75 # 0 +0xA56C 0xCA76 # 0 +0xA56D 0xCA77 # 0 +0xA56E 0xCA78 # 0 +0xA56F 0xCA79 # 0 +0xA570 0xCA7A # 0 +0xA571 0xCA7B # 0 +0xA572 0xCA7C # 0 +0xA573 0xCA7E # 0 +0xA574 0xCA7F # 0 +0xA575 0xCA80 # 0 +0xA576 0xCA81 # 0 +0xA577 0xCA82 # 0 +0xA578 0xCA83 # 0 +0xA579 0xCA85 # 0 +0xA57A 0xCA86 # 0 +0xA581 0xCA87 # 0 +0xA582 0xCA88 # 0 +0xA583 0xCA89 # 0 +0xA584 0xCA8A # 0 +0xA585 0xCA8B # 0 +0xA586 0xCA8C # 0 +0xA587 0xCA8D # 0 +0xA588 0xCA8E # 0 +0xA589 0xCA8F # 0 +0xA58A 0xCA90 # 0 +0xA58B 0xCA91 # 0 +0xA58C 0xCA92 # 0 +0xA58D 0xCA93 # 0 +0xA58E 0xCA94 # 0 +0xA58F 0xCA95 # 0 +0xA590 0xCA96 # 0 +0xA591 0xCA97 # 0 +0xA592 0xCA99 # 0 +0xA593 0xCA9A # 0 +0xA594 0xCA9B # 0 +0xA595 0xCA9C # 0 +0xA596 0xCA9D # 0 +0xA597 0xCA9E # 0 +0xA598 0xCA9F # 0 +0xA599 0xCAA0 # 0 +0xA59A 0xCAA1 # 0 +0xA59B 0xCAA2 # 0 +0xA59C 0xCAA3 # 0 +0xA59D 0xCAA4 # 0 +0xA59E 0xCAA5 # 0 +0xA59F 0xCAA6 # 0 +0xA5A0 0xCAA7 # 0 +0xA5A1 0x2170 # 0 +0xA5A2 0x2171 # 0 +0xA5A3 0x2172 # 0 +0xA5A4 0x2173 # 0 +0xA5A5 0x2174 # 0 +0xA5A6 0x2175 # 0 +0xA5A7 0x2176 # 0 +0xA5A8 0x2177 # 0 +0xA5A9 0x2178 # 0 +0xA5AA 0x2179 # 0 +0xA5B0 0x2160 # 0 +0xA5B1 0x2161 # 0 +0xA5B2 0x2162 # 0 +0xA5B3 0x2163 # 0 +0xA5B4 0x2164 # 0 +0xA5B5 0x2165 # 0 +0xA5B6 0x2166 # 0 +0xA5B7 0x2167 # 0 +0xA5B8 0x2168 # 0 +0xA5B9 0x2169 # 0 +0xA5C1 0x0391 # 0 +0xA5C2 0x0392 # 0 +0xA5C3 0x0393 # 0 +0xA5C4 0x0394 # 0 +0xA5C5 0x0395 # 0 +0xA5C6 0x0396 # 0 +0xA5C7 0x0397 # 0 +0xA5C8 0x0398 # 0 +0xA5C9 0x0399 # 0 +0xA5CA 0x039A # 0 +0xA5CB 0x039B # 0 +0xA5CC 0x039C # 0 +0xA5CD 0x039D # 0 +0xA5CE 0x039E # 0 +0xA5CF 0x039F # 0 +0xA5D0 0x03A0 # 0 +0xA5D1 0x03A1 # 0 +0xA5D2 0x03A3 # 0 +0xA5D3 0x03A4 # 0 +0xA5D4 0x03A5 # 0 +0xA5D5 0x03A6 # 0 +0xA5D6 0x03A7 # 0 +0xA5D7 0x03A8 # 0 +0xA5D8 0x03A9 # 0 +0xA5E1 0x03B1 # 0 +0xA5E2 0x03B2 # 0 +0xA5E3 0x03B3 # 0 +0xA5E4 0x03B4 # 0 +0xA5E5 0x03B5 # 0 +0xA5E6 0x03B6 # 0 +0xA5E7 0x03B7 # 0 +0xA5E8 0x03B8 # 0 +0xA5E9 0x03B9 # 0 +0xA5EA 0x03BA # 0 +0xA5EB 0x03BB # 0 +0xA5EC 0x03BC # 0 +0xA5ED 0x03BD # 0 +0xA5EE 0x03BE # 0 +0xA5EF 0x03BF # 0 +0xA5F0 0x03C0 # 0 +0xA5F1 0x03C1 # 0 +0xA5F2 0x03C3 # 0 +0xA5F3 0x03C4 # 0 +0xA5F4 0x03C5 # 0 +0xA5F5 0x03C6 # 0 +0xA5F6 0x03C7 # 0 +0xA5F7 0x03C8 # 0 +0xA5F8 0x03C9 # 0 +0xA641 0xCAA8 # 0 +0xA642 0xCAA9 # 0 +0xA643 0xCAAA # 0 +0xA644 0xCAAB # 0 +0xA645 0xCAAC # 0 +0xA646 0xCAAD # 0 +0xA647 0xCAAE # 0 +0xA648 0xCAAF # 0 +0xA649 0xCAB0 # 0 +0xA64A 0xCAB1 # 0 +0xA64B 0xCAB2 # 0 +0xA64C 0xCAB3 # 0 +0xA64D 0xCAB4 # 0 +0xA64E 0xCAB5 # 0 +0xA64F 0xCAB6 # 0 +0xA650 0xCAB7 # 0 +0xA651 0xCAB8 # 0 +0xA652 0xCAB9 # 0 +0xA653 0xCABA # 0 +0xA654 0xCABB # 0 +0xA655 0xCABE # 0 +0xA656 0xCABF # 0 +0xA657 0xCAC1 # 0 +0xA658 0xCAC2 # 0 +0xA659 0xCAC3 # 0 +0xA65A 0xCAC5 # 0 +0xA661 0xCAC6 # 0 +0xA662 0xCAC7 # 0 +0xA663 0xCAC8 # 0 +0xA664 0xCAC9 # 0 +0xA665 0xCACA # 0 +0xA666 0xCACB # 0 +0xA667 0xCACE # 0 +0xA668 0xCAD0 # 0 +0xA669 0xCAD2 # 0 +0xA66A 0xCAD4 # 0 +0xA66B 0xCAD5 # 0 +0xA66C 0xCAD6 # 0 +0xA66D 0xCAD7 # 0 +0xA66E 0xCADA # 0 +0xA66F 0xCADB # 0 +0xA670 0xCADC # 0 +0xA671 0xCADD # 0 +0xA672 0xCADE # 0 +0xA673 0xCADF # 0 +0xA674 0xCAE1 # 0 +0xA675 0xCAE2 # 0 +0xA676 0xCAE3 # 0 +0xA677 0xCAE4 # 0 +0xA678 0xCAE5 # 0 +0xA679 0xCAE6 # 0 +0xA67A 0xCAE7 # 0 +0xA681 0xCAE8 # 0 +0xA682 0xCAE9 # 0 +0xA683 0xCAEA # 0 +0xA684 0xCAEB # 0 +0xA685 0xCAED # 0 +0xA686 0xCAEE # 0 +0xA687 0xCAEF # 0 +0xA688 0xCAF0 # 0 +0xA689 0xCAF1 # 0 +0xA68A 0xCAF2 # 0 +0xA68B 0xCAF3 # 0 +0xA68C 0xCAF5 # 0 +0xA68D 0xCAF6 # 0 +0xA68E 0xCAF7 # 0 +0xA68F 0xCAF8 # 0 +0xA690 0xCAF9 # 0 +0xA691 0xCAFA # 0 +0xA692 0xCAFB # 0 +0xA693 0xCAFC # 0 +0xA694 0xCAFD # 0 +0xA695 0xCAFE # 0 +0xA696 0xCAFF # 0 +0xA697 0xCB00 # 0 +0xA698 0xCB01 # 0 +0xA699 0xCB02 # 0 +0xA69A 0xCB03 # 0 +0xA69B 0xCB04 # 0 +0xA69C 0xCB05 # 0 +0xA69D 0xCB06 # 0 +0xA69E 0xCB07 # 0 +0xA69F 0xCB09 # 0 +0xA6A0 0xCB0A # 0 +0xA6A1 0x2500 # 0 +0xA6A2 0x2502 # 0 +0xA6A3 0x250C # 0 +0xA6A4 0x2510 # 0 +0xA6A5 0x2518 # 0 +0xA6A6 0x2514 # 0 +0xA6A7 0x251C # 0 +0xA6A8 0x252C # 0 +0xA6A9 0x2524 # 0 +0xA6AA 0x2534 # 0 +0xA6AB 0x253C # 0 +0xA6AC 0x2501 # 0 +0xA6AD 0x2503 # 0 +0xA6AE 0x250F # 0 +0xA6AF 0x2513 # 0 +0xA6B0 0x251B # 0 +0xA6B1 0x2517 # 0 +0xA6B2 0x2523 # 0 +0xA6B3 0x2533 # 0 +0xA6B4 0x252B # 0 +0xA6B5 0x253B # 0 +0xA6B6 0x254B # 0 +0xA6B7 0x2520 # 0 +0xA6B8 0x252F # 0 +0xA6B9 0x2528 # 0 +0xA6BA 0x2537 # 0 +0xA6BB 0x253F # 0 +0xA6BC 0x251D # 0 +0xA6BD 0x2530 # 0 +0xA6BE 0x2525 # 0 +0xA6BF 0x2538 # 0 +0xA6C0 0x2542 # 0 +0xA6C1 0x2512 # 0 +0xA6C2 0x2511 # 0 +0xA6C3 0x251A # 0 +0xA6C4 0x2519 # 0 +0xA6C5 0x2516 # 0 +0xA6C6 0x2515 # 0 +0xA6C7 0x250E # 0 +0xA6C8 0x250D # 0 +0xA6C9 0x251E # 0 +0xA6CA 0x251F # 0 +0xA6CB 0x2521 # 0 +0xA6CC 0x2522 # 0 +0xA6CD 0x2526 # 0 +0xA6CE 0x2527 # 0 +0xA6CF 0x2529 # 0 +0xA6D0 0x252A # 0 +0xA6D1 0x252D # 0 +0xA6D2 0x252E # 0 +0xA6D3 0x2531 # 0 +0xA6D4 0x2532 # 0 +0xA6D5 0x2535 # 0 +0xA6D6 0x2536 # 0 +0xA6D7 0x2539 # 0 +0xA6D8 0x253A # 0 +0xA6D9 0x253D # 0 +0xA6DA 0x253E # 0 +0xA6DB 0x2540 # 0 +0xA6DC 0x2541 # 0 +0xA6DD 0x2543 # 0 +0xA6DE 0x2544 # 0 +0xA6DF 0x2545 # 0 +0xA6E0 0x2546 # 0 +0xA6E1 0x2547 # 0 +0xA6E2 0x2548 # 0 +0xA6E3 0x2549 # 0 +0xA6E4 0x254A # 0 +0xA741 0xCB0B # 0 +0xA742 0xCB0C # 0 +0xA743 0xCB0D # 0 +0xA744 0xCB0E # 0 +0xA745 0xCB0F # 0 +0xA746 0xCB11 # 0 +0xA747 0xCB12 # 0 +0xA748 0xCB13 # 0 +0xA749 0xCB15 # 0 +0xA74A 0xCB16 # 0 +0xA74B 0xCB17 # 0 +0xA74C 0xCB19 # 0 +0xA74D 0xCB1A # 0 +0xA74E 0xCB1B # 0 +0xA74F 0xCB1C # 0 +0xA750 0xCB1D # 0 +0xA751 0xCB1E # 0 +0xA752 0xCB1F # 0 +0xA753 0xCB22 # 0 +0xA754 0xCB23 # 0 +0xA755 0xCB24 # 0 +0xA756 0xCB25 # 0 +0xA757 0xCB26 # 0 +0xA758 0xCB27 # 0 +0xA759 0xCB28 # 0 +0xA75A 0xCB29 # 0 +0xA761 0xCB2A # 0 +0xA762 0xCB2B # 0 +0xA763 0xCB2C # 0 +0xA764 0xCB2D # 0 +0xA765 0xCB2E # 0 +0xA766 0xCB2F # 0 +0xA767 0xCB30 # 0 +0xA768 0xCB31 # 0 +0xA769 0xCB32 # 0 +0xA76A 0xCB33 # 0 +0xA76B 0xCB34 # 0 +0xA76C 0xCB35 # 0 +0xA76D 0xCB36 # 0 +0xA76E 0xCB37 # 0 +0xA76F 0xCB38 # 0 +0xA770 0xCB39 # 0 +0xA771 0xCB3A # 0 +0xA772 0xCB3B # 0 +0xA773 0xCB3C # 0 +0xA774 0xCB3D # 0 +0xA775 0xCB3E # 0 +0xA776 0xCB3F # 0 +0xA777 0xCB40 # 0 +0xA778 0xCB42 # 0 +0xA779 0xCB43 # 0 +0xA77A 0xCB44 # 0 +0xA781 0xCB45 # 0 +0xA782 0xCB46 # 0 +0xA783 0xCB47 # 0 +0xA784 0xCB4A # 0 +0xA785 0xCB4B # 0 +0xA786 0xCB4D # 0 +0xA787 0xCB4E # 0 +0xA788 0xCB4F # 0 +0xA789 0xCB51 # 0 +0xA78A 0xCB52 # 0 +0xA78B 0xCB53 # 0 +0xA78C 0xCB54 # 0 +0xA78D 0xCB55 # 0 +0xA78E 0xCB56 # 0 +0xA78F 0xCB57 # 0 +0xA790 0xCB5A # 0 +0xA791 0xCB5B # 0 +0xA792 0xCB5C # 0 +0xA793 0xCB5E # 0 +0xA794 0xCB5F # 0 +0xA795 0xCB60 # 0 +0xA796 0xCB61 # 0 +0xA797 0xCB62 # 0 +0xA798 0xCB63 # 0 +0xA799 0xCB65 # 0 +0xA79A 0xCB66 # 0 +0xA79B 0xCB67 # 0 +0xA79C 0xCB68 # 0 +0xA79D 0xCB69 # 0 +0xA79E 0xCB6A # 0 +0xA79F 0xCB6B # 0 +0xA7A0 0xCB6C # 0 +0xA7A1 0x3395 # 0 +0xA7A2 0x3396 # 0 +0xA7A3 0x3397 # 0 +0xA7A4 0x2113 # 0 +0xA7A5 0x3398 # 0 +0xA7A6 0x33C4 # 0 +0xA7A7 0x33A3 # 0 +0xA7A8 0x33A4 # 0 +0xA7A9 0x33A5 # 0 +0xA7AA 0x33A6 # 0 +0xA7AB 0x3399 # 0 +0xA7AC 0x339A # 0 +0xA7AD 0x339B # 0 +0xA7AE 0x339C # 0 +0xA7AF 0x339D # 0 +0xA7B0 0x339E # 0 +0xA7B1 0x339F # 0 +0xA7B2 0x33A0 # 0 +0xA7B3 0x33A1 # 0 +0xA7B4 0x33A2 # 0 +0xA7B5 0x33CA # 0 +0xA7B6 0x338D # 0 +0xA7B7 0x338E # 0 +0xA7B8 0x338F # 0 +0xA7B9 0x33CF # 0 +0xA7BA 0x3388 # 0 +0xA7BB 0x3389 # 0 +0xA7BC 0x33C8 # 0 +0xA7BD 0x33A7 # 0 +0xA7BE 0x33A8 # 0 +0xA7BF 0x33B0 # 0 +0xA7C0 0x33B1 # 0 +0xA7C1 0x33B2 # 0 +0xA7C2 0x33B3 # 0 +0xA7C3 0x33B4 # 0 +0xA7C4 0x33B5 # 0 +0xA7C5 0x33B6 # 0 +0xA7C6 0x33B7 # 0 +0xA7C7 0x33B8 # 0 +0xA7C8 0x33B9 # 0 +0xA7C9 0x3380 # 0 +0xA7CA 0x3381 # 0 +0xA7CB 0x3382 # 0 +0xA7CC 0x3383 # 0 +0xA7CD 0x3384 # 0 +0xA7CE 0x33BA # 0 +0xA7CF 0x33BB # 0 +0xA7D0 0x33BC # 0 +0xA7D1 0x33BD # 0 +0xA7D2 0x33BE # 0 +0xA7D3 0x33BF # 0 +0xA7D4 0x3390 # 0 +0xA7D5 0x3391 # 0 +0xA7D6 0x3392 # 0 +0xA7D7 0x3393 # 0 +0xA7D8 0x3394 # 0 +0xA7D9 0x2126 # 0 +0xA7DA 0x33C0 # 0 +0xA7DB 0x33C1 # 0 +0xA7DC 0x338A # 0 +0xA7DD 0x338B # 0 +0xA7DE 0x338C # 0 +0xA7DF 0x33D6 # 0 +0xA7E0 0x33C5 # 0 +0xA7E1 0x33AD # 0 +0xA7E2 0x33AE # 0 +0xA7E3 0x33AF # 0 +0xA7E4 0x33DB # 0 +0xA7E5 0x33A9 # 0 +0xA7E6 0x33AA # 0 +0xA7E7 0x33AB # 0 +0xA7E8 0x33AC # 0 +0xA7E9 0x33DD # 0 +0xA7EA 0x33D0 # 0 +0xA7EB 0x33D3 # 0 +0xA7EC 0x33C3 # 0 +0xA7ED 0x33C9 # 0 +0xA7EE 0x33DC # 0 +0xA7EF 0x33C6 # 0 +0xA841 0xCB6D # 0 +0xA842 0xCB6E # 0 +0xA843 0xCB6F # 0 +0xA844 0xCB70 # 0 +0xA845 0xCB71 # 0 +0xA846 0xCB72 # 0 +0xA847 0xCB73 # 0 +0xA848 0xCB74 # 0 +0xA849 0xCB75 # 0 +0xA84A 0xCB76 # 0 +0xA84B 0xCB77 # 0 +0xA84C 0xCB7A # 0 +0xA84D 0xCB7B # 0 +0xA84E 0xCB7C # 0 +0xA84F 0xCB7D # 0 +0xA850 0xCB7E # 0 +0xA851 0xCB7F # 0 +0xA852 0xCB80 # 0 +0xA853 0xCB81 # 0 +0xA854 0xCB82 # 0 +0xA855 0xCB83 # 0 +0xA856 0xCB84 # 0 +0xA857 0xCB85 # 0 +0xA858 0xCB86 # 0 +0xA859 0xCB87 # 0 +0xA85A 0xCB88 # 0 +0xA861 0xCB89 # 0 +0xA862 0xCB8A # 0 +0xA863 0xCB8B # 0 +0xA864 0xCB8C # 0 +0xA865 0xCB8D # 0 +0xA866 0xCB8E # 0 +0xA867 0xCB8F # 0 +0xA868 0xCB90 # 0 +0xA869 0xCB91 # 0 +0xA86A 0xCB92 # 0 +0xA86B 0xCB93 # 0 +0xA86C 0xCB94 # 0 +0xA86D 0xCB95 # 0 +0xA86E 0xCB96 # 0 +0xA86F 0xCB97 # 0 +0xA870 0xCB98 # 0 +0xA871 0xCB99 # 0 +0xA872 0xCB9A # 0 +0xA873 0xCB9B # 0 +0xA874 0xCB9D # 0 +0xA875 0xCB9E # 0 +0xA876 0xCB9F # 0 +0xA877 0xCBA0 # 0 +0xA878 0xCBA1 # 0 +0xA879 0xCBA2 # 0 +0xA87A 0xCBA3 # 0 +0xA881 0xCBA4 # 0 +0xA882 0xCBA5 # 0 +0xA883 0xCBA6 # 0 +0xA884 0xCBA7 # 0 +0xA885 0xCBA8 # 0 +0xA886 0xCBA9 # 0 +0xA887 0xCBAA # 0 +0xA888 0xCBAB # 0 +0xA889 0xCBAC # 0 +0xA88A 0xCBAD # 0 +0xA88B 0xCBAE # 0 +0xA88C 0xCBAF # 0 +0xA88D 0xCBB0 # 0 +0xA88E 0xCBB1 # 0 +0xA88F 0xCBB2 # 0 +0xA890 0xCBB3 # 0 +0xA891 0xCBB4 # 0 +0xA892 0xCBB5 # 0 +0xA893 0xCBB6 # 0 +0xA894 0xCBB7 # 0 +0xA895 0xCBB9 # 0 +0xA896 0xCBBA # 0 +0xA897 0xCBBB # 0 +0xA898 0xCBBC # 0 +0xA899 0xCBBD # 0 +0xA89A 0xCBBE # 0 +0xA89B 0xCBBF # 0 +0xA89C 0xCBC0 # 0 +0xA89D 0xCBC1 # 0 +0xA89E 0xCBC2 # 0 +0xA89F 0xCBC3 # 0 +0xA8A0 0xCBC4 # 0 +0xA8A1 0x00C6 # 0 +0xA8A2 0x00D0 # 0 +0xA8A3 0x00AA # 0 +0xA8A4 0x0126 # 0 +0xA8A6 0x0132 # 0 +0xA8A8 0x013F # 0 +0xA8A9 0x0141 # 0 +0xA8AA 0x00D8 # 0 +0xA8AB 0x0152 # 0 +0xA8AC 0x00BA # 0 +0xA8AD 0x00DE # 0 +0xA8AE 0x0166 # 0 +0xA8AF 0x014A # 0 +0xA8B1 0x3260 # 0 +0xA8B2 0x3261 # 0 +0xA8B3 0x3262 # 0 +0xA8B4 0x3263 # 0 +0xA8B5 0x3264 # 0 +0xA8B6 0x3265 # 0 +0xA8B7 0x3266 # 0 +0xA8B8 0x3267 # 0 +0xA8B9 0x3268 # 0 +0xA8BA 0x3269 # 0 +0xA8BB 0x326A # 0 +0xA8BC 0x326B # 0 +0xA8BD 0x326C # 0 +0xA8BE 0x326D # 0 +0xA8BF 0x326E # 0 +0xA8C0 0x326F # 0 +0xA8C1 0x3270 # 0 +0xA8C2 0x3271 # 0 +0xA8C3 0x3272 # 0 +0xA8C4 0x3273 # 0 +0xA8C5 0x3274 # 0 +0xA8C6 0x3275 # 0 +0xA8C7 0x3276 # 0 +0xA8C8 0x3277 # 0 +0xA8C9 0x3278 # 0 +0xA8CA 0x3279 # 0 +0xA8CB 0x327A # 0 +0xA8CC 0x327B # 0 +0xA8CD 0x24D0 # 0 +0xA8CE 0x24D1 # 0 +0xA8CF 0x24D2 # 0 +0xA8D0 0x24D3 # 0 +0xA8D1 0x24D4 # 0 +0xA8D2 0x24D5 # 0 +0xA8D3 0x24D6 # 0 +0xA8D4 0x24D7 # 0 +0xA8D5 0x24D8 # 0 +0xA8D6 0x24D9 # 0 +0xA8D7 0x24DA # 0 +0xA8D8 0x24DB # 0 +0xA8D9 0x24DC # 0 +0xA8DA 0x24DD # 0 +0xA8DB 0x24DE # 0 +0xA8DC 0x24DF # 0 +0xA8DD 0x24E0 # 0 +0xA8DE 0x24E1 # 0 +0xA8DF 0x24E2 # 0 +0xA8E0 0x24E3 # 0 +0xA8E1 0x24E4 # 0 +0xA8E2 0x24E5 # 0 +0xA8E3 0x24E6 # 0 +0xA8E4 0x24E7 # 0 +0xA8E5 0x24E8 # 0 +0xA8E6 0x24E9 # 0 +0xA8E7 0x2460 # 0 +0xA8E8 0x2461 # 0 +0xA8E9 0x2462 # 0 +0xA8EA 0x2463 # 0 +0xA8EB 0x2464 # 0 +0xA8EC 0x2465 # 0 +0xA8ED 0x2466 # 0 +0xA8EE 0x2467 # 0 +0xA8EF 0x2468 # 0 +0xA8F0 0x2469 # 0 +0xA8F1 0x246A # 0 +0xA8F2 0x246B # 0 +0xA8F3 0x246C # 0 +0xA8F4 0x246D # 0 +0xA8F5 0x246E # 0 +0xA8F6 0x00BD # 0 +0xA8F7 0x2153 # 0 +0xA8F8 0x2154 # 0 +0xA8F9 0x00BC # 0 +0xA8FA 0x00BE # 0 +0xA8FB 0x215B # 0 +0xA8FC 0x215C # 0 +0xA8FD 0x215D # 0 +0xA8FE 0x215E # 0 +0xA941 0xCBC5 # 0 +0xA942 0xCBC6 # 0 +0xA943 0xCBC7 # 0 +0xA944 0xCBC8 # 0 +0xA945 0xCBC9 # 0 +0xA946 0xCBCA # 0 +0xA947 0xCBCB # 0 +0xA948 0xCBCC # 0 +0xA949 0xCBCD # 0 +0xA94A 0xCBCE # 0 +0xA94B 0xCBCF # 0 +0xA94C 0xCBD0 # 0 +0xA94D 0xCBD1 # 0 +0xA94E 0xCBD2 # 0 +0xA94F 0xCBD3 # 0 +0xA950 0xCBD5 # 0 +0xA951 0xCBD6 # 0 +0xA952 0xCBD7 # 0 +0xA953 0xCBD8 # 0 +0xA954 0xCBD9 # 0 +0xA955 0xCBDA # 0 +0xA956 0xCBDB # 0 +0xA957 0xCBDC # 0 +0xA958 0xCBDD # 0 +0xA959 0xCBDE # 0 +0xA95A 0xCBDF # 0 +0xA961 0xCBE0 # 0 +0xA962 0xCBE1 # 0 +0xA963 0xCBE2 # 0 +0xA964 0xCBE3 # 0 +0xA965 0xCBE5 # 0 +0xA966 0xCBE6 # 0 +0xA967 0xCBE8 # 0 +0xA968 0xCBEA # 0 +0xA969 0xCBEB # 0 +0xA96A 0xCBEC # 0 +0xA96B 0xCBED # 0 +0xA96C 0xCBEE # 0 +0xA96D 0xCBEF # 0 +0xA96E 0xCBF0 # 0 +0xA96F 0xCBF1 # 0 +0xA970 0xCBF2 # 0 +0xA971 0xCBF3 # 0 +0xA972 0xCBF4 # 0 +0xA973 0xCBF5 # 0 +0xA974 0xCBF6 # 0 +0xA975 0xCBF7 # 0 +0xA976 0xCBF8 # 0 +0xA977 0xCBF9 # 0 +0xA978 0xCBFA # 0 +0xA979 0xCBFB # 0 +0xA97A 0xCBFC # 0 +0xA981 0xCBFD # 0 +0xA982 0xCBFE # 0 +0xA983 0xCBFF # 0 +0xA984 0xCC00 # 0 +0xA985 0xCC01 # 0 +0xA986 0xCC02 # 0 +0xA987 0xCC03 # 0 +0xA988 0xCC04 # 0 +0xA989 0xCC05 # 0 +0xA98A 0xCC06 # 0 +0xA98B 0xCC07 # 0 +0xA98C 0xCC08 # 0 +0xA98D 0xCC09 # 0 +0xA98E 0xCC0A # 0 +0xA98F 0xCC0B # 0 +0xA990 0xCC0E # 0 +0xA991 0xCC0F # 0 +0xA992 0xCC11 # 0 +0xA993 0xCC12 # 0 +0xA994 0xCC13 # 0 +0xA995 0xCC15 # 0 +0xA996 0xCC16 # 0 +0xA997 0xCC17 # 0 +0xA998 0xCC18 # 0 +0xA999 0xCC19 # 0 +0xA99A 0xCC1A # 0 +0xA99B 0xCC1B # 0 +0xA99C 0xCC1E # 0 +0xA99D 0xCC1F # 0 +0xA99E 0xCC20 # 0 +0xA99F 0xCC23 # 0 +0xA9A0 0xCC24 # 0 +0xA9A1 0x00E6 # 0 +0xA9A2 0x0111 # 0 +0xA9A3 0x00F0 # 0 +0xA9A4 0x0127 # 0 +0xA9A5 0x0131 # 0 +0xA9A6 0x0133 # 0 +0xA9A7 0x0138 # 0 +0xA9A8 0x0140 # 0 +0xA9A9 0x0142 # 0 +0xA9AA 0x00F8 # 0 +0xA9AB 0x0153 # 0 +0xA9AC 0x00DF # 0 +0xA9AD 0x00FE # 0 +0xA9AE 0x0167 # 0 +0xA9AF 0x014B # 0 +0xA9B0 0x0149 # 0 +0xA9B1 0x3200 # 0 +0xA9B2 0x3201 # 0 +0xA9B3 0x3202 # 0 +0xA9B4 0x3203 # 0 +0xA9B5 0x3204 # 0 +0xA9B6 0x3205 # 0 +0xA9B7 0x3206 # 0 +0xA9B8 0x3207 # 0 +0xA9B9 0x3208 # 0 +0xA9BA 0x3209 # 0 +0xA9BB 0x320A # 0 +0xA9BC 0x320B # 0 +0xA9BD 0x320C # 0 +0xA9BE 0x320D # 0 +0xA9BF 0x320E # 0 +0xA9C0 0x320F # 0 +0xA9C1 0x3210 # 0 +0xA9C2 0x3211 # 0 +0xA9C3 0x3212 # 0 +0xA9C4 0x3213 # 0 +0xA9C5 0x3214 # 0 +0xA9C6 0x3215 # 0 +0xA9C7 0x3216 # 0 +0xA9C8 0x3217 # 0 +0xA9C9 0x3218 # 0 +0xA9CA 0x3219 # 0 +0xA9CB 0x321A # 0 +0xA9CC 0x321B # 0 +0xA9CD 0x249C # 0 +0xA9CE 0x249D # 0 +0xA9CF 0x249E # 0 +0xA9D0 0x249F # 0 +0xA9D1 0x24A0 # 0 +0xA9D2 0x24A1 # 0 +0xA9D3 0x24A2 # 0 +0xA9D4 0x24A3 # 0 +0xA9D5 0x24A4 # 0 +0xA9D6 0x24A5 # 0 +0xA9D7 0x24A6 # 0 +0xA9D8 0x24A7 # 0 +0xA9D9 0x24A8 # 0 +0xA9DA 0x24A9 # 0 +0xA9DB 0x24AA # 0 +0xA9DC 0x24AB # 0 +0xA9DD 0x24AC # 0 +0xA9DE 0x24AD # 0 +0xA9DF 0x24AE # 0 +0xA9E0 0x24AF # 0 +0xA9E1 0x24B0 # 0 +0xA9E2 0x24B1 # 0 +0xA9E3 0x24B2 # 0 +0xA9E4 0x24B3 # 0 +0xA9E5 0x24B4 # 0 +0xA9E6 0x24B5 # 0 +0xA9E7 0x2474 # 0 +0xA9E8 0x2475 # 0 +0xA9E9 0x2476 # 0 +0xA9EA 0x2477 # 0 +0xA9EB 0x2478 # 0 +0xA9EC 0x2479 # 0 +0xA9ED 0x247A # 0 +0xA9EE 0x247B # 0 +0xA9EF 0x247C # 0 +0xA9F0 0x247D # 0 +0xA9F1 0x247E # 0 +0xA9F2 0x247F # 0 +0xA9F3 0x2480 # 0 +0xA9F4 0x2481 # 0 +0xA9F5 0x2482 # 0 +0xA9F6 0x00B9 # 0 +0xA9F7 0x00B2 # 0 +0xA9F8 0x00B3 # 0 +0xA9F9 0x2074 # 0 +0xA9FA 0x207F # 0 +0xA9FB 0x2081 # 0 +0xA9FC 0x2082 # 0 +0xA9FD 0x2083 # 0 +0xA9FE 0x2084 # 0 +0xAA41 0xCC25 # 0 +0xAA42 0xCC26 # 0 +0xAA43 0xCC2A # 0 +0xAA44 0xCC2B # 0 +0xAA45 0xCC2D # 0 +0xAA46 0xCC2F # 0 +0xAA47 0xCC31 # 0 +0xAA48 0xCC32 # 0 +0xAA49 0xCC33 # 0 +0xAA4A 0xCC34 # 0 +0xAA4B 0xCC35 # 0 +0xAA4C 0xCC36 # 0 +0xAA4D 0xCC37 # 0 +0xAA4E 0xCC3A # 0 +0xAA4F 0xCC3F # 0 +0xAA50 0xCC40 # 0 +0xAA51 0xCC41 # 0 +0xAA52 0xCC42 # 0 +0xAA53 0xCC43 # 0 +0xAA54 0xCC46 # 0 +0xAA55 0xCC47 # 0 +0xAA56 0xCC49 # 0 +0xAA57 0xCC4A # 0 +0xAA58 0xCC4B # 0 +0xAA59 0xCC4D # 0 +0xAA5A 0xCC4E # 0 +0xAA61 0xCC4F # 0 +0xAA62 0xCC50 # 0 +0xAA63 0xCC51 # 0 +0xAA64 0xCC52 # 0 +0xAA65 0xCC53 # 0 +0xAA66 0xCC56 # 0 +0xAA67 0xCC5A # 0 +0xAA68 0xCC5B # 0 +0xAA69 0xCC5C # 0 +0xAA6A 0xCC5D # 0 +0xAA6B 0xCC5E # 0 +0xAA6C 0xCC5F # 0 +0xAA6D 0xCC61 # 0 +0xAA6E 0xCC62 # 0 +0xAA6F 0xCC63 # 0 +0xAA70 0xCC65 # 0 +0xAA71 0xCC67 # 0 +0xAA72 0xCC69 # 0 +0xAA73 0xCC6A # 0 +0xAA74 0xCC6B # 0 +0xAA75 0xCC6C # 0 +0xAA76 0xCC6D # 0 +0xAA77 0xCC6E # 0 +0xAA78 0xCC6F # 0 +0xAA79 0xCC71 # 0 +0xAA7A 0xCC72 # 0 +0xAA81 0xCC73 # 0 +0xAA82 0xCC74 # 0 +0xAA83 0xCC76 # 0 +0xAA84 0xCC77 # 0 +0xAA85 0xCC78 # 0 +0xAA86 0xCC79 # 0 +0xAA87 0xCC7A # 0 +0xAA88 0xCC7B # 0 +0xAA89 0xCC7C # 0 +0xAA8A 0xCC7D # 0 +0xAA8B 0xCC7E # 0 +0xAA8C 0xCC7F # 0 +0xAA8D 0xCC80 # 0 +0xAA8E 0xCC81 # 0 +0xAA8F 0xCC82 # 0 +0xAA90 0xCC83 # 0 +0xAA91 0xCC84 # 0 +0xAA92 0xCC85 # 0 +0xAA93 0xCC86 # 0 +0xAA94 0xCC87 # 0 +0xAA95 0xCC88 # 0 +0xAA96 0xCC89 # 0 +0xAA97 0xCC8A # 0 +0xAA98 0xCC8B # 0 +0xAA99 0xCC8C # 0 +0xAA9A 0xCC8D # 0 +0xAA9B 0xCC8E # 0 +0xAA9C 0xCC8F # 0 +0xAA9D 0xCC90 # 0 +0xAA9E 0xCC91 # 0 +0xAA9F 0xCC92 # 0 +0xAAA0 0xCC93 # 0 +0xAAA1 0x3041 # 0 +0xAAA2 0x3042 # 0 +0xAAA3 0x3043 # 0 +0xAAA4 0x3044 # 0 +0xAAA5 0x3045 # 0 +0xAAA6 0x3046 # 0 +0xAAA7 0x3047 # 0 +0xAAA8 0x3048 # 0 +0xAAA9 0x3049 # 0 +0xAAAA 0x304A # 0 +0xAAAB 0x304B # 0 +0xAAAC 0x304C # 0 +0xAAAD 0x304D # 0 +0xAAAE 0x304E # 0 +0xAAAF 0x304F # 0 +0xAAB0 0x3050 # 0 +0xAAB1 0x3051 # 0 +0xAAB2 0x3052 # 0 +0xAAB3 0x3053 # 0 +0xAAB4 0x3054 # 0 +0xAAB5 0x3055 # 0 +0xAAB6 0x3056 # 0 +0xAAB7 0x3057 # 0 +0xAAB8 0x3058 # 0 +0xAAB9 0x3059 # 0 +0xAABA 0x305A # 0 +0xAABB 0x305B # 0 +0xAABC 0x305C # 0 +0xAABD 0x305D # 0 +0xAABE 0x305E # 0 +0xAABF 0x305F # 0 +0xAAC0 0x3060 # 0 +0xAAC1 0x3061 # 0 +0xAAC2 0x3062 # 0 +0xAAC3 0x3063 # 0 +0xAAC4 0x3064 # 0 +0xAAC5 0x3065 # 0 +0xAAC6 0x3066 # 0 +0xAAC7 0x3067 # 0 +0xAAC8 0x3068 # 0 +0xAAC9 0x3069 # 0 +0xAACA 0x306A # 0 +0xAACB 0x306B # 0 +0xAACC 0x306C # 0 +0xAACD 0x306D # 0 +0xAACE 0x306E # 0 +0xAACF 0x306F # 0 +0xAAD0 0x3070 # 0 +0xAAD1 0x3071 # 0 +0xAAD2 0x3072 # 0 +0xAAD3 0x3073 # 0 +0xAAD4 0x3074 # 0 +0xAAD5 0x3075 # 0 +0xAAD6 0x3076 # 0 +0xAAD7 0x3077 # 0 +0xAAD8 0x3078 # 0 +0xAAD9 0x3079 # 0 +0xAADA 0x307A # 0 +0xAADB 0x307B # 0 +0xAADC 0x307C # 0 +0xAADD 0x307D # 0 +0xAADE 0x307E # 0 +0xAADF 0x307F # 0 +0xAAE0 0x3080 # 0 +0xAAE1 0x3081 # 0 +0xAAE2 0x3082 # 0 +0xAAE3 0x3083 # 0 +0xAAE4 0x3084 # 0 +0xAAE5 0x3085 # 0 +0xAAE6 0x3086 # 0 +0xAAE7 0x3087 # 0 +0xAAE8 0x3088 # 0 +0xAAE9 0x3089 # 0 +0xAAEA 0x308A # 0 +0xAAEB 0x308B # 0 +0xAAEC 0x308C # 0 +0xAAED 0x308D # 0 +0xAAEE 0x308E # 0 +0xAAEF 0x308F # 0 +0xAAF0 0x3090 # 0 +0xAAF1 0x3091 # 0 +0xAAF2 0x3092 # 0 +0xAAF3 0x3093 # 0 +0xAB41 0xCC94 # 0 +0xAB42 0xCC95 # 0 +0xAB43 0xCC96 # 0 +0xAB44 0xCC97 # 0 +0xAB45 0xCC9A # 0 +0xAB46 0xCC9B # 0 +0xAB47 0xCC9D # 0 +0xAB48 0xCC9E # 0 +0xAB49 0xCC9F # 0 +0xAB4A 0xCCA1 # 0 +0xAB4B 0xCCA2 # 0 +0xAB4C 0xCCA3 # 0 +0xAB4D 0xCCA4 # 0 +0xAB4E 0xCCA5 # 0 +0xAB4F 0xCCA6 # 0 +0xAB50 0xCCA7 # 0 +0xAB51 0xCCAA # 0 +0xAB52 0xCCAE # 0 +0xAB53 0xCCAF # 0 +0xAB54 0xCCB0 # 0 +0xAB55 0xCCB1 # 0 +0xAB56 0xCCB2 # 0 +0xAB57 0xCCB3 # 0 +0xAB58 0xCCB6 # 0 +0xAB59 0xCCB7 # 0 +0xAB5A 0xCCB9 # 0 +0xAB61 0xCCBA # 0 +0xAB62 0xCCBB # 0 +0xAB63 0xCCBD # 0 +0xAB64 0xCCBE # 0 +0xAB65 0xCCBF # 0 +0xAB66 0xCCC0 # 0 +0xAB67 0xCCC1 # 0 +0xAB68 0xCCC2 # 0 +0xAB69 0xCCC3 # 0 +0xAB6A 0xCCC6 # 0 +0xAB6B 0xCCC8 # 0 +0xAB6C 0xCCCA # 0 +0xAB6D 0xCCCB # 0 +0xAB6E 0xCCCC # 0 +0xAB6F 0xCCCD # 0 +0xAB70 0xCCCE # 0 +0xAB71 0xCCCF # 0 +0xAB72 0xCCD1 # 0 +0xAB73 0xCCD2 # 0 +0xAB74 0xCCD3 # 0 +0xAB75 0xCCD5 # 0 +0xAB76 0xCCD6 # 0 +0xAB77 0xCCD7 # 0 +0xAB78 0xCCD8 # 0 +0xAB79 0xCCD9 # 0 +0xAB7A 0xCCDA # 0 +0xAB81 0xCCDB # 0 +0xAB82 0xCCDC # 0 +0xAB83 0xCCDD # 0 +0xAB84 0xCCDE # 0 +0xAB85 0xCCDF # 0 +0xAB86 0xCCE0 # 0 +0xAB87 0xCCE1 # 0 +0xAB88 0xCCE2 # 0 +0xAB89 0xCCE3 # 0 +0xAB8A 0xCCE5 # 0 +0xAB8B 0xCCE6 # 0 +0xAB8C 0xCCE7 # 0 +0xAB8D 0xCCE8 # 0 +0xAB8E 0xCCE9 # 0 +0xAB8F 0xCCEA # 0 +0xAB90 0xCCEB # 0 +0xAB91 0xCCED # 0 +0xAB92 0xCCEE # 0 +0xAB93 0xCCEF # 0 +0xAB94 0xCCF1 # 0 +0xAB95 0xCCF2 # 0 +0xAB96 0xCCF3 # 0 +0xAB97 0xCCF4 # 0 +0xAB98 0xCCF5 # 0 +0xAB99 0xCCF6 # 0 +0xAB9A 0xCCF7 # 0 +0xAB9B 0xCCF8 # 0 +0xAB9C 0xCCF9 # 0 +0xAB9D 0xCCFA # 0 +0xAB9E 0xCCFB # 0 +0xAB9F 0xCCFC # 0 +0xABA0 0xCCFD # 0 +0xABA1 0x30A1 # 0 +0xABA2 0x30A2 # 0 +0xABA3 0x30A3 # 0 +0xABA4 0x30A4 # 0 +0xABA5 0x30A5 # 0 +0xABA6 0x30A6 # 0 +0xABA7 0x30A7 # 0 +0xABA8 0x30A8 # 0 +0xABA9 0x30A9 # 0 +0xABAA 0x30AA # 0 +0xABAB 0x30AB # 0 +0xABAC 0x30AC # 0 +0xABAD 0x30AD # 0 +0xABAE 0x30AE # 0 +0xABAF 0x30AF # 0 +0xABB0 0x30B0 # 0 +0xABB1 0x30B1 # 0 +0xABB2 0x30B2 # 0 +0xABB3 0x30B3 # 0 +0xABB4 0x30B4 # 0 +0xABB5 0x30B5 # 0 +0xABB6 0x30B6 # 0 +0xABB7 0x30B7 # 0 +0xABB8 0x30B8 # 0 +0xABB9 0x30B9 # 0 +0xABBA 0x30BA # 0 +0xABBB 0x30BB # 0 +0xABBC 0x30BC # 0 +0xABBD 0x30BD # 0 +0xABBE 0x30BE # 0 +0xABBF 0x30BF # 0 +0xABC0 0x30C0 # 0 +0xABC1 0x30C1 # 0 +0xABC2 0x30C2 # 0 +0xABC3 0x30C3 # 0 +0xABC4 0x30C4 # 0 +0xABC5 0x30C5 # 0 +0xABC6 0x30C6 # 0 +0xABC7 0x30C7 # 0 +0xABC8 0x30C8 # 0 +0xABC9 0x30C9 # 0 +0xABCA 0x30CA # 0 +0xABCB 0x30CB # 0 +0xABCC 0x30CC # 0 +0xABCD 0x30CD # 0 +0xABCE 0x30CE # 0 +0xABCF 0x30CF # 0 +0xABD0 0x30D0 # 0 +0xABD1 0x30D1 # 0 +0xABD2 0x30D2 # 0 +0xABD3 0x30D3 # 0 +0xABD4 0x30D4 # 0 +0xABD5 0x30D5 # 0 +0xABD6 0x30D6 # 0 +0xABD7 0x30D7 # 0 +0xABD8 0x30D8 # 0 +0xABD9 0x30D9 # 0 +0xABDA 0x30DA # 0 +0xABDB 0x30DB # 0 +0xABDC 0x30DC # 0 +0xABDD 0x30DD # 0 +0xABDE 0x30DE # 0 +0xABDF 0x30DF # 0 +0xABE0 0x30E0 # 0 +0xABE1 0x30E1 # 0 +0xABE2 0x30E2 # 0 +0xABE3 0x30E3 # 0 +0xABE4 0x30E4 # 0 +0xABE5 0x30E5 # 0 +0xABE6 0x30E6 # 0 +0xABE7 0x30E7 # 0 +0xABE8 0x30E8 # 0 +0xABE9 0x30E9 # 0 +0xABEA 0x30EA # 0 +0xABEB 0x30EB # 0 +0xABEC 0x30EC # 0 +0xABED 0x30ED # 0 +0xABEE 0x30EE # 0 +0xABEF 0x30EF # 0 +0xABF0 0x30F0 # 0 +0xABF1 0x30F1 # 0 +0xABF2 0x30F2 # 0 +0xABF3 0x30F3 # 0 +0xABF4 0x30F4 # 0 +0xABF5 0x30F5 # 0 +0xABF6 0x30F6 # 0 +0xAC41 0xCCFE # 0 +0xAC42 0xCCFF # 0 +0xAC43 0xCD00 # 0 +0xAC44 0xCD02 # 0 +0xAC45 0xCD03 # 0 +0xAC46 0xCD04 # 0 +0xAC47 0xCD05 # 0 +0xAC48 0xCD06 # 0 +0xAC49 0xCD07 # 0 +0xAC4A 0xCD0A # 0 +0xAC4B 0xCD0B # 0 +0xAC4C 0xCD0D # 0 +0xAC4D 0xCD0E # 0 +0xAC4E 0xCD0F # 0 +0xAC4F 0xCD11 # 0 +0xAC50 0xCD12 # 0 +0xAC51 0xCD13 # 0 +0xAC52 0xCD14 # 0 +0xAC53 0xCD15 # 0 +0xAC54 0xCD16 # 0 +0xAC55 0xCD17 # 0 +0xAC56 0xCD1A # 0 +0xAC57 0xCD1C # 0 +0xAC58 0xCD1E # 0 +0xAC59 0xCD1F # 0 +0xAC5A 0xCD20 # 0 +0xAC61 0xCD21 # 0 +0xAC62 0xCD22 # 0 +0xAC63 0xCD23 # 0 +0xAC64 0xCD25 # 0 +0xAC65 0xCD26 # 0 +0xAC66 0xCD27 # 0 +0xAC67 0xCD29 # 0 +0xAC68 0xCD2A # 0 +0xAC69 0xCD2B # 0 +0xAC6A 0xCD2D # 0 +0xAC6B 0xCD2E # 0 +0xAC6C 0xCD2F # 0 +0xAC6D 0xCD30 # 0 +0xAC6E 0xCD31 # 0 +0xAC6F 0xCD32 # 0 +0xAC70 0xCD33 # 0 +0xAC71 0xCD34 # 0 +0xAC72 0xCD35 # 0 +0xAC73 0xCD36 # 0 +0xAC74 0xCD37 # 0 +0xAC75 0xCD38 # 0 +0xAC76 0xCD3A # 0 +0xAC77 0xCD3B # 0 +0xAC78 0xCD3C # 0 +0xAC79 0xCD3D # 0 +0xAC7A 0xCD3E # 0 +0xAC81 0xCD3F # 0 +0xAC82 0xCD40 # 0 +0xAC83 0xCD41 # 0 +0xAC84 0xCD42 # 0 +0xAC85 0xCD43 # 0 +0xAC86 0xCD44 # 0 +0xAC87 0xCD45 # 0 +0xAC88 0xCD46 # 0 +0xAC89 0xCD47 # 0 +0xAC8A 0xCD48 # 0 +0xAC8B 0xCD49 # 0 +0xAC8C 0xCD4A # 0 +0xAC8D 0xCD4B # 0 +0xAC8E 0xCD4C # 0 +0xAC8F 0xCD4D # 0 +0xAC90 0xCD4E # 0 +0xAC91 0xCD4F # 0 +0xAC92 0xCD50 # 0 +0xAC93 0xCD51 # 0 +0xAC94 0xCD52 # 0 +0xAC95 0xCD53 # 0 +0xAC96 0xCD54 # 0 +0xAC97 0xCD55 # 0 +0xAC98 0xCD56 # 0 +0xAC99 0xCD57 # 0 +0xAC9A 0xCD58 # 0 +0xAC9B 0xCD59 # 0 +0xAC9C 0xCD5A # 0 +0xAC9D 0xCD5B # 0 +0xAC9E 0xCD5D # 0 +0xAC9F 0xCD5E # 0 +0xACA0 0xCD5F # 0 +0xACA1 0x0410 # 0 +0xACA2 0x0411 # 0 +0xACA3 0x0412 # 0 +0xACA4 0x0413 # 0 +0xACA5 0x0414 # 0 +0xACA6 0x0415 # 0 +0xACA7 0x0401 # 0 +0xACA8 0x0416 # 0 +0xACA9 0x0417 # 0 +0xACAA 0x0418 # 0 +0xACAB 0x0419 # 0 +0xACAC 0x041A # 0 +0xACAD 0x041B # 0 +0xACAE 0x041C # 0 +0xACAF 0x041D # 0 +0xACB0 0x041E # 0 +0xACB1 0x041F # 0 +0xACB2 0x0420 # 0 +0xACB3 0x0421 # 0 +0xACB4 0x0422 # 0 +0xACB5 0x0423 # 0 +0xACB6 0x0424 # 0 +0xACB7 0x0425 # 0 +0xACB8 0x0426 # 0 +0xACB9 0x0427 # 0 +0xACBA 0x0428 # 0 +0xACBB 0x0429 # 0 +0xACBC 0x042A # 0 +0xACBD 0x042B # 0 +0xACBE 0x042C # 0 +0xACBF 0x042D # 0 +0xACC0 0x042E # 0 +0xACC1 0x042F # 0 +0xACD1 0x0430 # 0 +0xACD2 0x0431 # 0 +0xACD3 0x0432 # 0 +0xACD4 0x0433 # 0 +0xACD5 0x0434 # 0 +0xACD6 0x0435 # 0 +0xACD7 0x0451 # 0 +0xACD8 0x0436 # 0 +0xACD9 0x0437 # 0 +0xACDA 0x0438 # 0 +0xACDB 0x0439 # 0 +0xACDC 0x043A # 0 +0xACDD 0x043B # 0 +0xACDE 0x043C # 0 +0xACDF 0x043D # 0 +0xACE0 0x043E # 0 +0xACE1 0x043F # 0 +0xACE2 0x0440 # 0 +0xACE3 0x0441 # 0 +0xACE4 0x0442 # 0 +0xACE5 0x0443 # 0 +0xACE6 0x0444 # 0 +0xACE7 0x0445 # 0 +0xACE8 0x0446 # 0 +0xACE9 0x0447 # 0 +0xACEA 0x0448 # 0 +0xACEB 0x0449 # 0 +0xACEC 0x044A # 0 +0xACED 0x044B # 0 +0xACEE 0x044C # 0 +0xACEF 0x044D # 0 +0xACF0 0x044E # 0 +0xACF1 0x044F # 0 +0xAD41 0xCD61 # 0 +0xAD42 0xCD62 # 0 +0xAD43 0xCD63 # 0 +0xAD44 0xCD65 # 0 +0xAD45 0xCD66 # 0 +0xAD46 0xCD67 # 0 +0xAD47 0xCD68 # 0 +0xAD48 0xCD69 # 0 +0xAD49 0xCD6A # 0 +0xAD4A 0xCD6B # 0 +0xAD4B 0xCD6E # 0 +0xAD4C 0xCD70 # 0 +0xAD4D 0xCD72 # 0 +0xAD4E 0xCD73 # 0 +0xAD4F 0xCD74 # 0 +0xAD50 0xCD75 # 0 +0xAD51 0xCD76 # 0 +0xAD52 0xCD77 # 0 +0xAD53 0xCD79 # 0 +0xAD54 0xCD7A # 0 +0xAD55 0xCD7B # 0 +0xAD56 0xCD7C # 0 +0xAD57 0xCD7D # 0 +0xAD58 0xCD7E # 0 +0xAD59 0xCD7F # 0 +0xAD5A 0xCD80 # 0 +0xAD61 0xCD81 # 0 +0xAD62 0xCD82 # 0 +0xAD63 0xCD83 # 0 +0xAD64 0xCD84 # 0 +0xAD65 0xCD85 # 0 +0xAD66 0xCD86 # 0 +0xAD67 0xCD87 # 0 +0xAD68 0xCD89 # 0 +0xAD69 0xCD8A # 0 +0xAD6A 0xCD8B # 0 +0xAD6B 0xCD8C # 0 +0xAD6C 0xCD8D # 0 +0xAD6D 0xCD8E # 0 +0xAD6E 0xCD8F # 0 +0xAD6F 0xCD90 # 0 +0xAD70 0xCD91 # 0 +0xAD71 0xCD92 # 0 +0xAD72 0xCD93 # 0 +0xAD73 0xCD96 # 0 +0xAD74 0xCD97 # 0 +0xAD75 0xCD99 # 0 +0xAD76 0xCD9A # 0 +0xAD77 0xCD9B # 0 +0xAD78 0xCD9D # 0 +0xAD79 0xCD9E # 0 +0xAD7A 0xCD9F # 0 +0xAD81 0xCDA0 # 0 +0xAD82 0xCDA1 # 0 +0xAD83 0xCDA2 # 0 +0xAD84 0xCDA3 # 0 +0xAD85 0xCDA6 # 0 +0xAD86 0xCDA8 # 0 +0xAD87 0xCDAA # 0 +0xAD88 0xCDAB # 0 +0xAD89 0xCDAC # 0 +0xAD8A 0xCDAD # 0 +0xAD8B 0xCDAE # 0 +0xAD8C 0xCDAF # 0 +0xAD8D 0xCDB1 # 0 +0xAD8E 0xCDB2 # 0 +0xAD8F 0xCDB3 # 0 +0xAD90 0xCDB4 # 0 +0xAD91 0xCDB5 # 0 +0xAD92 0xCDB6 # 0 +0xAD93 0xCDB7 # 0 +0xAD94 0xCDB8 # 0 +0xAD95 0xCDB9 # 0 +0xAD96 0xCDBA # 0 +0xAD97 0xCDBB # 0 +0xAD98 0xCDBC # 0 +0xAD99 0xCDBD # 0 +0xAD9A 0xCDBE # 0 +0xAD9B 0xCDBF # 0 +0xAD9C 0xCDC0 # 0 +0xAD9D 0xCDC1 # 0 +0xAD9E 0xCDC2 # 0 +0xAD9F 0xCDC3 # 0 +0xADA0 0xCDC5 # 0 +0xAE41 0xCDC6 # 0 +0xAE42 0xCDC7 # 0 +0xAE43 0xCDC8 # 0 +0xAE44 0xCDC9 # 0 +0xAE45 0xCDCA # 0 +0xAE46 0xCDCB # 0 +0xAE47 0xCDCD # 0 +0xAE48 0xCDCE # 0 +0xAE49 0xCDCF # 0 +0xAE4A 0xCDD1 # 0 +0xAE4B 0xCDD2 # 0 +0xAE4C 0xCDD3 # 0 +0xAE4D 0xCDD4 # 0 +0xAE4E 0xCDD5 # 0 +0xAE4F 0xCDD6 # 0 +0xAE50 0xCDD7 # 0 +0xAE51 0xCDD8 # 0 +0xAE52 0xCDD9 # 0 +0xAE53 0xCDDA # 0 +0xAE54 0xCDDB # 0 +0xAE55 0xCDDC # 0 +0xAE56 0xCDDD # 0 +0xAE57 0xCDDE # 0 +0xAE58 0xCDDF # 0 +0xAE59 0xCDE0 # 0 +0xAE5A 0xCDE1 # 0 +0xAE61 0xCDE2 # 0 +0xAE62 0xCDE3 # 0 +0xAE63 0xCDE4 # 0 +0xAE64 0xCDE5 # 0 +0xAE65 0xCDE6 # 0 +0xAE66 0xCDE7 # 0 +0xAE67 0xCDE9 # 0 +0xAE68 0xCDEA # 0 +0xAE69 0xCDEB # 0 +0xAE6A 0xCDED # 0 +0xAE6B 0xCDEE # 0 +0xAE6C 0xCDEF # 0 +0xAE6D 0xCDF1 # 0 +0xAE6E 0xCDF2 # 0 +0xAE6F 0xCDF3 # 0 +0xAE70 0xCDF4 # 0 +0xAE71 0xCDF5 # 0 +0xAE72 0xCDF6 # 0 +0xAE73 0xCDF7 # 0 +0xAE74 0xCDFA # 0 +0xAE75 0xCDFC # 0 +0xAE76 0xCDFE # 0 +0xAE77 0xCDFF # 0 +0xAE78 0xCE00 # 0 +0xAE79 0xCE01 # 0 +0xAE7A 0xCE02 # 0 +0xAE81 0xCE03 # 0 +0xAE82 0xCE05 # 0 +0xAE83 0xCE06 # 0 +0xAE84 0xCE07 # 0 +0xAE85 0xCE09 # 0 +0xAE86 0xCE0A # 0 +0xAE87 0xCE0B # 0 +0xAE88 0xCE0D # 0 +0xAE89 0xCE0E # 0 +0xAE8A 0xCE0F # 0 +0xAE8B 0xCE10 # 0 +0xAE8C 0xCE11 # 0 +0xAE8D 0xCE12 # 0 +0xAE8E 0xCE13 # 0 +0xAE8F 0xCE15 # 0 +0xAE90 0xCE16 # 0 +0xAE91 0xCE17 # 0 +0xAE92 0xCE18 # 0 +0xAE93 0xCE1A # 0 +0xAE94 0xCE1B # 0 +0xAE95 0xCE1C # 0 +0xAE96 0xCE1D # 0 +0xAE97 0xCE1E # 0 +0xAE98 0xCE1F # 0 +0xAE99 0xCE22 # 0 +0xAE9A 0xCE23 # 0 +0xAE9B 0xCE25 # 0 +0xAE9C 0xCE26 # 0 +0xAE9D 0xCE27 # 0 +0xAE9E 0xCE29 # 0 +0xAE9F 0xCE2A # 0 +0xAEA0 0xCE2B # 0 +0xAF41 0xCE2C # 0 +0xAF42 0xCE2D # 0 +0xAF43 0xCE2E # 0 +0xAF44 0xCE2F # 0 +0xAF45 0xCE32 # 0 +0xAF46 0xCE34 # 0 +0xAF47 0xCE36 # 0 +0xAF48 0xCE37 # 0 +0xAF49 0xCE38 # 0 +0xAF4A 0xCE39 # 0 +0xAF4B 0xCE3A # 0 +0xAF4C 0xCE3B # 0 +0xAF4D 0xCE3C # 0 +0xAF4E 0xCE3D # 0 +0xAF4F 0xCE3E # 0 +0xAF50 0xCE3F # 0 +0xAF51 0xCE40 # 0 +0xAF52 0xCE41 # 0 +0xAF53 0xCE42 # 0 +0xAF54 0xCE43 # 0 +0xAF55 0xCE44 # 0 +0xAF56 0xCE45 # 0 +0xAF57 0xCE46 # 0 +0xAF58 0xCE47 # 0 +0xAF59 0xCE48 # 0 +0xAF5A 0xCE49 # 0 +0xAF61 0xCE4A # 0 +0xAF62 0xCE4B # 0 +0xAF63 0xCE4C # 0 +0xAF64 0xCE4D # 0 +0xAF65 0xCE4E # 0 +0xAF66 0xCE4F # 0 +0xAF67 0xCE50 # 0 +0xAF68 0xCE51 # 0 +0xAF69 0xCE52 # 0 +0xAF6A 0xCE53 # 0 +0xAF6B 0xCE54 # 0 +0xAF6C 0xCE55 # 0 +0xAF6D 0xCE56 # 0 +0xAF6E 0xCE57 # 0 +0xAF6F 0xCE5A # 0 +0xAF70 0xCE5B # 0 +0xAF71 0xCE5D # 0 +0xAF72 0xCE5E # 0 +0xAF73 0xCE62 # 0 +0xAF74 0xCE63 # 0 +0xAF75 0xCE64 # 0 +0xAF76 0xCE65 # 0 +0xAF77 0xCE66 # 0 +0xAF78 0xCE67 # 0 +0xAF79 0xCE6A # 0 +0xAF7A 0xCE6C # 0 +0xAF81 0xCE6E # 0 +0xAF82 0xCE6F # 0 +0xAF83 0xCE70 # 0 +0xAF84 0xCE71 # 0 +0xAF85 0xCE72 # 0 +0xAF86 0xCE73 # 0 +0xAF87 0xCE76 # 0 +0xAF88 0xCE77 # 0 +0xAF89 0xCE79 # 0 +0xAF8A 0xCE7A # 0 +0xAF8B 0xCE7B # 0 +0xAF8C 0xCE7D # 0 +0xAF8D 0xCE7E # 0 +0xAF8E 0xCE7F # 0 +0xAF8F 0xCE80 # 0 +0xAF90 0xCE81 # 0 +0xAF91 0xCE82 # 0 +0xAF92 0xCE83 # 0 +0xAF93 0xCE86 # 0 +0xAF94 0xCE88 # 0 +0xAF95 0xCE8A # 0 +0xAF96 0xCE8B # 0 +0xAF97 0xCE8C # 0 +0xAF98 0xCE8D # 0 +0xAF99 0xCE8E # 0 +0xAF9A 0xCE8F # 0 +0xAF9B 0xCE92 # 0 +0xAF9C 0xCE93 # 0 +0xAF9D 0xCE95 # 0 +0xAF9E 0xCE96 # 0 +0xAF9F 0xCE97 # 0 +0xAFA0 0xCE99 # 0 +0xB041 0xCE9A # 0 +0xB042 0xCE9B # 0 +0xB043 0xCE9C # 0 +0xB044 0xCE9D # 0 +0xB045 0xCE9E # 0 +0xB046 0xCE9F # 0 +0xB047 0xCEA2 # 0 +0xB048 0xCEA6 # 0 +0xB049 0xCEA7 # 0 +0xB04A 0xCEA8 # 0 +0xB04B 0xCEA9 # 0 +0xB04C 0xCEAA # 0 +0xB04D 0xCEAB # 0 +0xB04E 0xCEAE # 0 +0xB04F 0xCEAF # 0 +0xB050 0xCEB0 # 0 +0xB051 0xCEB1 # 0 +0xB052 0xCEB2 # 0 +0xB053 0xCEB3 # 0 +0xB054 0xCEB4 # 0 +0xB055 0xCEB5 # 0 +0xB056 0xCEB6 # 0 +0xB057 0xCEB7 # 0 +0xB058 0xCEB8 # 0 +0xB059 0xCEB9 # 0 +0xB05A 0xCEBA # 0 +0xB061 0xCEBB # 0 +0xB062 0xCEBC # 0 +0xB063 0xCEBD # 0 +0xB064 0xCEBE # 0 +0xB065 0xCEBF # 0 +0xB066 0xCEC0 # 0 +0xB067 0xCEC2 # 0 +0xB068 0xCEC3 # 0 +0xB069 0xCEC4 # 0 +0xB06A 0xCEC5 # 0 +0xB06B 0xCEC6 # 0 +0xB06C 0xCEC7 # 0 +0xB06D 0xCEC8 # 0 +0xB06E 0xCEC9 # 0 +0xB06F 0xCECA # 0 +0xB070 0xCECB # 0 +0xB071 0xCECC # 0 +0xB072 0xCECD # 0 +0xB073 0xCECE # 0 +0xB074 0xCECF # 0 +0xB075 0xCED0 # 0 +0xB076 0xCED1 # 0 +0xB077 0xCED2 # 0 +0xB078 0xCED3 # 0 +0xB079 0xCED4 # 0 +0xB07A 0xCED5 # 0 +0xB081 0xCED6 # 0 +0xB082 0xCED7 # 0 +0xB083 0xCED8 # 0 +0xB084 0xCED9 # 0 +0xB085 0xCEDA # 0 +0xB086 0xCEDB # 0 +0xB087 0xCEDC # 0 +0xB088 0xCEDD # 0 +0xB089 0xCEDE # 0 +0xB08A 0xCEDF # 0 +0xB08B 0xCEE0 # 0 +0xB08C 0xCEE1 # 0 +0xB08D 0xCEE2 # 0 +0xB08E 0xCEE3 # 0 +0xB08F 0xCEE6 # 0 +0xB090 0xCEE7 # 0 +0xB091 0xCEE9 # 0 +0xB092 0xCEEA # 0 +0xB093 0xCEED # 0 +0xB094 0xCEEE # 0 +0xB095 0xCEEF # 0 +0xB096 0xCEF0 # 0 +0xB097 0xCEF1 # 0 +0xB098 0xCEF2 # 0 +0xB099 0xCEF3 # 0 +0xB09A 0xCEF6 # 0 +0xB09B 0xCEFA # 0 +0xB09C 0xCEFB # 0 +0xB09D 0xCEFC # 0 +0xB09E 0xCEFD # 0 +0xB09F 0xCEFE # 0 +0xB0A0 0xCEFF # 0 +0xB0A1 0xAC00 # 0 +0xB0A2 0xAC01 # 0 +0xB0A3 0xAC04 # 0 +0xB0A4 0xAC07 # 0 +0xB0A5 0xAC08 # 0 +0xB0A6 0xAC09 # 0 +0xB0A7 0xAC0A # 0 +0xB0A8 0xAC10 # 0 +0xB0A9 0xAC11 # 0 +0xB0AA 0xAC12 # 0 +0xB0AB 0xAC13 # 0 +0xB0AC 0xAC14 # 0 +0xB0AD 0xAC15 # 0 +0xB0AE 0xAC16 # 0 +0xB0AF 0xAC17 # 0 +0xB0B0 0xAC19 # 0 +0xB0B1 0xAC1A # 0 +0xB0B2 0xAC1B # 0 +0xB0B3 0xAC1C # 0 +0xB0B4 0xAC1D # 0 +0xB0B5 0xAC20 # 0 +0xB0B6 0xAC24 # 0 +0xB0B7 0xAC2C # 0 +0xB0B8 0xAC2D # 0 +0xB0B9 0xAC2F # 0 +0xB0BA 0xAC30 # 0 +0xB0BB 0xAC31 # 0 +0xB0BC 0xAC38 # 0 +0xB0BD 0xAC39 # 0 +0xB0BE 0xAC3C # 0 +0xB0BF 0xAC40 # 0 +0xB0C0 0xAC4B # 0 +0xB0C1 0xAC4D # 0 +0xB0C2 0xAC54 # 0 +0xB0C3 0xAC58 # 0 +0xB0C4 0xAC5C # 0 +0xB0C5 0xAC70 # 0 +0xB0C6 0xAC71 # 0 +0xB0C7 0xAC74 # 0 +0xB0C8 0xAC77 # 0 +0xB0C9 0xAC78 # 0 +0xB0CA 0xAC7A # 0 +0xB0CB 0xAC80 # 0 +0xB0CC 0xAC81 # 0 +0xB0CD 0xAC83 # 0 +0xB0CE 0xAC84 # 0 +0xB0CF 0xAC85 # 0 +0xB0D0 0xAC86 # 0 +0xB0D1 0xAC89 # 0 +0xB0D2 0xAC8A # 0 +0xB0D3 0xAC8B # 0 +0xB0D4 0xAC8C # 0 +0xB0D5 0xAC90 # 0 +0xB0D6 0xAC94 # 0 +0xB0D7 0xAC9C # 0 +0xB0D8 0xAC9D # 0 +0xB0D9 0xAC9F # 0 +0xB0DA 0xACA0 # 0 +0xB0DB 0xACA1 # 0 +0xB0DC 0xACA8 # 0 +0xB0DD 0xACA9 # 0 +0xB0DE 0xACAA # 0 +0xB0DF 0xACAC # 0 +0xB0E0 0xACAF # 0 +0xB0E1 0xACB0 # 0 +0xB0E2 0xACB8 # 0 +0xB0E3 0xACB9 # 0 +0xB0E4 0xACBB # 0 +0xB0E5 0xACBC # 0 +0xB0E6 0xACBD # 0 +0xB0E7 0xACC1 # 0 +0xB0E8 0xACC4 # 0 +0xB0E9 0xACC8 # 0 +0xB0EA 0xACCC # 0 +0xB0EB 0xACD5 # 0 +0xB0EC 0xACD7 # 0 +0xB0ED 0xACE0 # 0 +0xB0EE 0xACE1 # 0 +0xB0EF 0xACE4 # 0 +0xB0F0 0xACE7 # 0 +0xB0F1 0xACE8 # 0 +0xB0F2 0xACEA # 0 +0xB0F3 0xACEC # 0 +0xB0F4 0xACEF # 0 +0xB0F5 0xACF0 # 0 +0xB0F6 0xACF1 # 0 +0xB0F7 0xACF3 # 0 +0xB0F8 0xACF5 # 0 +0xB0F9 0xACF6 # 0 +0xB0FA 0xACFC # 0 +0xB0FB 0xACFD # 0 +0xB0FC 0xAD00 # 0 +0xB0FD 0xAD04 # 0 +0xB0FE 0xAD06 # 0 +0xB141 0xCF02 # 0 +0xB142 0xCF03 # 0 +0xB143 0xCF05 # 0 +0xB144 0xCF06 # 0 +0xB145 0xCF07 # 0 +0xB146 0xCF09 # 0 +0xB147 0xCF0A # 0 +0xB148 0xCF0B # 0 +0xB149 0xCF0C # 0 +0xB14A 0xCF0D # 0 +0xB14B 0xCF0E # 0 +0xB14C 0xCF0F # 0 +0xB14D 0xCF12 # 0 +0xB14E 0xCF14 # 0 +0xB14F 0xCF16 # 0 +0xB150 0xCF17 # 0 +0xB151 0xCF18 # 0 +0xB152 0xCF19 # 0 +0xB153 0xCF1A # 0 +0xB154 0xCF1B # 0 +0xB155 0xCF1D # 0 +0xB156 0xCF1E # 0 +0xB157 0xCF1F # 0 +0xB158 0xCF21 # 0 +0xB159 0xCF22 # 0 +0xB15A 0xCF23 # 0 +0xB161 0xCF25 # 0 +0xB162 0xCF26 # 0 +0xB163 0xCF27 # 0 +0xB164 0xCF28 # 0 +0xB165 0xCF29 # 0 +0xB166 0xCF2A # 0 +0xB167 0xCF2B # 0 +0xB168 0xCF2E # 0 +0xB169 0xCF32 # 0 +0xB16A 0xCF33 # 0 +0xB16B 0xCF34 # 0 +0xB16C 0xCF35 # 0 +0xB16D 0xCF36 # 0 +0xB16E 0xCF37 # 0 +0xB16F 0xCF39 # 0 +0xB170 0xCF3A # 0 +0xB171 0xCF3B # 0 +0xB172 0xCF3C # 0 +0xB173 0xCF3D # 0 +0xB174 0xCF3E # 0 +0xB175 0xCF3F # 0 +0xB176 0xCF40 # 0 +0xB177 0xCF41 # 0 +0xB178 0xCF42 # 0 +0xB179 0xCF43 # 0 +0xB17A 0xCF44 # 0 +0xB181 0xCF45 # 0 +0xB182 0xCF46 # 0 +0xB183 0xCF47 # 0 +0xB184 0xCF48 # 0 +0xB185 0xCF49 # 0 +0xB186 0xCF4A # 0 +0xB187 0xCF4B # 0 +0xB188 0xCF4C # 0 +0xB189 0xCF4D # 0 +0xB18A 0xCF4E # 0 +0xB18B 0xCF4F # 0 +0xB18C 0xCF50 # 0 +0xB18D 0xCF51 # 0 +0xB18E 0xCF52 # 0 +0xB18F 0xCF53 # 0 +0xB190 0xCF56 # 0 +0xB191 0xCF57 # 0 +0xB192 0xCF59 # 0 +0xB193 0xCF5A # 0 +0xB194 0xCF5B # 0 +0xB195 0xCF5D # 0 +0xB196 0xCF5E # 0 +0xB197 0xCF5F # 0 +0xB198 0xCF60 # 0 +0xB199 0xCF61 # 0 +0xB19A 0xCF62 # 0 +0xB19B 0xCF63 # 0 +0xB19C 0xCF66 # 0 +0xB19D 0xCF68 # 0 +0xB19E 0xCF6A # 0 +0xB19F 0xCF6B # 0 +0xB1A0 0xCF6C # 0 +0xB1A1 0xAD0C # 0 +0xB1A2 0xAD0D # 0 +0xB1A3 0xAD0F # 0 +0xB1A4 0xAD11 # 0 +0xB1A5 0xAD18 # 0 +0xB1A6 0xAD1C # 0 +0xB1A7 0xAD20 # 0 +0xB1A8 0xAD29 # 0 +0xB1A9 0xAD2C # 0 +0xB1AA 0xAD2D # 0 +0xB1AB 0xAD34 # 0 +0xB1AC 0xAD35 # 0 +0xB1AD 0xAD38 # 0 +0xB1AE 0xAD3C # 0 +0xB1AF 0xAD44 # 0 +0xB1B0 0xAD45 # 0 +0xB1B1 0xAD47 # 0 +0xB1B2 0xAD49 # 0 +0xB1B3 0xAD50 # 0 +0xB1B4 0xAD54 # 0 +0xB1B5 0xAD58 # 0 +0xB1B6 0xAD61 # 0 +0xB1B7 0xAD63 # 0 +0xB1B8 0xAD6C # 0 +0xB1B9 0xAD6D # 0 +0xB1BA 0xAD70 # 0 +0xB1BB 0xAD73 # 0 +0xB1BC 0xAD74 # 0 +0xB1BD 0xAD75 # 0 +0xB1BE 0xAD76 # 0 +0xB1BF 0xAD7B # 0 +0xB1C0 0xAD7C # 0 +0xB1C1 0xAD7D # 0 +0xB1C2 0xAD7F # 0 +0xB1C3 0xAD81 # 0 +0xB1C4 0xAD82 # 0 +0xB1C5 0xAD88 # 0 +0xB1C6 0xAD89 # 0 +0xB1C7 0xAD8C # 0 +0xB1C8 0xAD90 # 0 +0xB1C9 0xAD9C # 0 +0xB1CA 0xAD9D # 0 +0xB1CB 0xADA4 # 0 +0xB1CC 0xADB7 # 0 +0xB1CD 0xADC0 # 0 +0xB1CE 0xADC1 # 0 +0xB1CF 0xADC4 # 0 +0xB1D0 0xADC8 # 0 +0xB1D1 0xADD0 # 0 +0xB1D2 0xADD1 # 0 +0xB1D3 0xADD3 # 0 +0xB1D4 0xADDC # 0 +0xB1D5 0xADE0 # 0 +0xB1D6 0xADE4 # 0 +0xB1D7 0xADF8 # 0 +0xB1D8 0xADF9 # 0 +0xB1D9 0xADFC # 0 +0xB1DA 0xADFF # 0 +0xB1DB 0xAE00 # 0 +0xB1DC 0xAE01 # 0 +0xB1DD 0xAE08 # 0 +0xB1DE 0xAE09 # 0 +0xB1DF 0xAE0B # 0 +0xB1E0 0xAE0D # 0 +0xB1E1 0xAE14 # 0 +0xB1E2 0xAE30 # 0 +0xB1E3 0xAE31 # 0 +0xB1E4 0xAE34 # 0 +0xB1E5 0xAE37 # 0 +0xB1E6 0xAE38 # 0 +0xB1E7 0xAE3A # 0 +0xB1E8 0xAE40 # 0 +0xB1E9 0xAE41 # 0 +0xB1EA 0xAE43 # 0 +0xB1EB 0xAE45 # 0 +0xB1EC 0xAE46 # 0 +0xB1ED 0xAE4A # 0 +0xB1EE 0xAE4C # 0 +0xB1EF 0xAE4D # 0 +0xB1F0 0xAE4E # 0 +0xB1F1 0xAE50 # 0 +0xB1F2 0xAE54 # 0 +0xB1F3 0xAE56 # 0 +0xB1F4 0xAE5C # 0 +0xB1F5 0xAE5D # 0 +0xB1F6 0xAE5F # 0 +0xB1F7 0xAE60 # 0 +0xB1F8 0xAE61 # 0 +0xB1F9 0xAE65 # 0 +0xB1FA 0xAE68 # 0 +0xB1FB 0xAE69 # 0 +0xB1FC 0xAE6C # 0 +0xB1FD 0xAE70 # 0 +0xB1FE 0xAE78 # 0 +0xB241 0xCF6D # 0 +0xB242 0xCF6E # 0 +0xB243 0xCF6F # 0 +0xB244 0xCF72 # 0 +0xB245 0xCF73 # 0 +0xB246 0xCF75 # 0 +0xB247 0xCF76 # 0 +0xB248 0xCF77 # 0 +0xB249 0xCF79 # 0 +0xB24A 0xCF7A # 0 +0xB24B 0xCF7B # 0 +0xB24C 0xCF7C # 0 +0xB24D 0xCF7D # 0 +0xB24E 0xCF7E # 0 +0xB24F 0xCF7F # 0 +0xB250 0xCF81 # 0 +0xB251 0xCF82 # 0 +0xB252 0xCF83 # 0 +0xB253 0xCF84 # 0 +0xB254 0xCF86 # 0 +0xB255 0xCF87 # 0 +0xB256 0xCF88 # 0 +0xB257 0xCF89 # 0 +0xB258 0xCF8A # 0 +0xB259 0xCF8B # 0 +0xB25A 0xCF8D # 0 +0xB261 0xCF8E # 0 +0xB262 0xCF8F # 0 +0xB263 0xCF90 # 0 +0xB264 0xCF91 # 0 +0xB265 0xCF92 # 0 +0xB266 0xCF93 # 0 +0xB267 0xCF94 # 0 +0xB268 0xCF95 # 0 +0xB269 0xCF96 # 0 +0xB26A 0xCF97 # 0 +0xB26B 0xCF98 # 0 +0xB26C 0xCF99 # 0 +0xB26D 0xCF9A # 0 +0xB26E 0xCF9B # 0 +0xB26F 0xCF9C # 0 +0xB270 0xCF9D # 0 +0xB271 0xCF9E # 0 +0xB272 0xCF9F # 0 +0xB273 0xCFA0 # 0 +0xB274 0xCFA2 # 0 +0xB275 0xCFA3 # 0 +0xB276 0xCFA4 # 0 +0xB277 0xCFA5 # 0 +0xB278 0xCFA6 # 0 +0xB279 0xCFA7 # 0 +0xB27A 0xCFA9 # 0 +0xB281 0xCFAA # 0 +0xB282 0xCFAB # 0 +0xB283 0xCFAC # 0 +0xB284 0xCFAD # 0 +0xB285 0xCFAE # 0 +0xB286 0xCFAF # 0 +0xB287 0xCFB1 # 0 +0xB288 0xCFB2 # 0 +0xB289 0xCFB3 # 0 +0xB28A 0xCFB4 # 0 +0xB28B 0xCFB5 # 0 +0xB28C 0xCFB6 # 0 +0xB28D 0xCFB7 # 0 +0xB28E 0xCFB8 # 0 +0xB28F 0xCFB9 # 0 +0xB290 0xCFBA # 0 +0xB291 0xCFBB # 0 +0xB292 0xCFBC # 0 +0xB293 0xCFBD # 0 +0xB294 0xCFBE # 0 +0xB295 0xCFBF # 0 +0xB296 0xCFC0 # 0 +0xB297 0xCFC1 # 0 +0xB298 0xCFC2 # 0 +0xB299 0xCFC3 # 0 +0xB29A 0xCFC5 # 0 +0xB29B 0xCFC6 # 0 +0xB29C 0xCFC7 # 0 +0xB29D 0xCFC8 # 0 +0xB29E 0xCFC9 # 0 +0xB29F 0xCFCA # 0 +0xB2A0 0xCFCB # 0 +0xB2A1 0xAE79 # 0 +0xB2A2 0xAE7B # 0 +0xB2A3 0xAE7C # 0 +0xB2A4 0xAE7D # 0 +0xB2A5 0xAE84 # 0 +0xB2A6 0xAE85 # 0 +0xB2A7 0xAE8C # 0 +0xB2A8 0xAEBC # 0 +0xB2A9 0xAEBD # 0 +0xB2AA 0xAEBE # 0 +0xB2AB 0xAEC0 # 0 +0xB2AC 0xAEC4 # 0 +0xB2AD 0xAECC # 0 +0xB2AE 0xAECD # 0 +0xB2AF 0xAECF # 0 +0xB2B0 0xAED0 # 0 +0xB2B1 0xAED1 # 0 +0xB2B2 0xAED8 # 0 +0xB2B3 0xAED9 # 0 +0xB2B4 0xAEDC # 0 +0xB2B5 0xAEE8 # 0 +0xB2B6 0xAEEB # 0 +0xB2B7 0xAEED # 0 +0xB2B8 0xAEF4 # 0 +0xB2B9 0xAEF8 # 0 +0xB2BA 0xAEFC # 0 +0xB2BB 0xAF07 # 0 +0xB2BC 0xAF08 # 0 +0xB2BD 0xAF0D # 0 +0xB2BE 0xAF10 # 0 +0xB2BF 0xAF2C # 0 +0xB2C0 0xAF2D # 0 +0xB2C1 0xAF30 # 0 +0xB2C2 0xAF32 # 0 +0xB2C3 0xAF34 # 0 +0xB2C4 0xAF3C # 0 +0xB2C5 0xAF3D # 0 +0xB2C6 0xAF3F # 0 +0xB2C7 0xAF41 # 0 +0xB2C8 0xAF42 # 0 +0xB2C9 0xAF43 # 0 +0xB2CA 0xAF48 # 0 +0xB2CB 0xAF49 # 0 +0xB2CC 0xAF50 # 0 +0xB2CD 0xAF5C # 0 +0xB2CE 0xAF5D # 0 +0xB2CF 0xAF64 # 0 +0xB2D0 0xAF65 # 0 +0xB2D1 0xAF79 # 0 +0xB2D2 0xAF80 # 0 +0xB2D3 0xAF84 # 0 +0xB2D4 0xAF88 # 0 +0xB2D5 0xAF90 # 0 +0xB2D6 0xAF91 # 0 +0xB2D7 0xAF95 # 0 +0xB2D8 0xAF9C # 0 +0xB2D9 0xAFB8 # 0 +0xB2DA 0xAFB9 # 0 +0xB2DB 0xAFBC # 0 +0xB2DC 0xAFC0 # 0 +0xB2DD 0xAFC7 # 0 +0xB2DE 0xAFC8 # 0 +0xB2DF 0xAFC9 # 0 +0xB2E0 0xAFCB # 0 +0xB2E1 0xAFCD # 0 +0xB2E2 0xAFCE # 0 +0xB2E3 0xAFD4 # 0 +0xB2E4 0xAFDC # 0 +0xB2E5 0xAFE8 # 0 +0xB2E6 0xAFE9 # 0 +0xB2E7 0xAFF0 # 0 +0xB2E8 0xAFF1 # 0 +0xB2E9 0xAFF4 # 0 +0xB2EA 0xAFF8 # 0 +0xB2EB 0xB000 # 0 +0xB2EC 0xB001 # 0 +0xB2ED 0xB004 # 0 +0xB2EE 0xB00C # 0 +0xB2EF 0xB010 # 0 +0xB2F0 0xB014 # 0 +0xB2F1 0xB01C # 0 +0xB2F2 0xB01D # 0 +0xB2F3 0xB028 # 0 +0xB2F4 0xB044 # 0 +0xB2F5 0xB045 # 0 +0xB2F6 0xB048 # 0 +0xB2F7 0xB04A # 0 +0xB2F8 0xB04C # 0 +0xB2F9 0xB04E # 0 +0xB2FA 0xB053 # 0 +0xB2FB 0xB054 # 0 +0xB2FC 0xB055 # 0 +0xB2FD 0xB057 # 0 +0xB2FE 0xB059 # 0 +0xB341 0xCFCC # 0 +0xB342 0xCFCD # 0 +0xB343 0xCFCE # 0 +0xB344 0xCFCF # 0 +0xB345 0xCFD0 # 0 +0xB346 0xCFD1 # 0 +0xB347 0xCFD2 # 0 +0xB348 0xCFD3 # 0 +0xB349 0xCFD4 # 0 +0xB34A 0xCFD5 # 0 +0xB34B 0xCFD6 # 0 +0xB34C 0xCFD7 # 0 +0xB34D 0xCFD8 # 0 +0xB34E 0xCFD9 # 0 +0xB34F 0xCFDA # 0 +0xB350 0xCFDB # 0 +0xB351 0xCFDC # 0 +0xB352 0xCFDD # 0 +0xB353 0xCFDE # 0 +0xB354 0xCFDF # 0 +0xB355 0xCFE2 # 0 +0xB356 0xCFE3 # 0 +0xB357 0xCFE5 # 0 +0xB358 0xCFE6 # 0 +0xB359 0xCFE7 # 0 +0xB35A 0xCFE9 # 0 +0xB361 0xCFEA # 0 +0xB362 0xCFEB # 0 +0xB363 0xCFEC # 0 +0xB364 0xCFED # 0 +0xB365 0xCFEE # 0 +0xB366 0xCFEF # 0 +0xB367 0xCFF2 # 0 +0xB368 0xCFF4 # 0 +0xB369 0xCFF6 # 0 +0xB36A 0xCFF7 # 0 +0xB36B 0xCFF8 # 0 +0xB36C 0xCFF9 # 0 +0xB36D 0xCFFA # 0 +0xB36E 0xCFFB # 0 +0xB36F 0xCFFD # 0 +0xB370 0xCFFE # 0 +0xB371 0xCFFF # 0 +0xB372 0xD001 # 0 +0xB373 0xD002 # 0 +0xB374 0xD003 # 0 +0xB375 0xD005 # 0 +0xB376 0xD006 # 0 +0xB377 0xD007 # 0 +0xB378 0xD008 # 0 +0xB379 0xD009 # 0 +0xB37A 0xD00A # 0 +0xB381 0xD00B # 0 +0xB382 0xD00C # 0 +0xB383 0xD00D # 0 +0xB384 0xD00E # 0 +0xB385 0xD00F # 0 +0xB386 0xD010 # 0 +0xB387 0xD012 # 0 +0xB388 0xD013 # 0 +0xB389 0xD014 # 0 +0xB38A 0xD015 # 0 +0xB38B 0xD016 # 0 +0xB38C 0xD017 # 0 +0xB38D 0xD019 # 0 +0xB38E 0xD01A # 0 +0xB38F 0xD01B # 0 +0xB390 0xD01C # 0 +0xB391 0xD01D # 0 +0xB392 0xD01E # 0 +0xB393 0xD01F # 0 +0xB394 0xD020 # 0 +0xB395 0xD021 # 0 +0xB396 0xD022 # 0 +0xB397 0xD023 # 0 +0xB398 0xD024 # 0 +0xB399 0xD025 # 0 +0xB39A 0xD026 # 0 +0xB39B 0xD027 # 0 +0xB39C 0xD028 # 0 +0xB39D 0xD029 # 0 +0xB39E 0xD02A # 0 +0xB39F 0xD02B # 0 +0xB3A0 0xD02C # 0 +0xB3A1 0xB05D # 0 +0xB3A2 0xB07C # 0 +0xB3A3 0xB07D # 0 +0xB3A4 0xB080 # 0 +0xB3A5 0xB084 # 0 +0xB3A6 0xB08C # 0 +0xB3A7 0xB08D # 0 +0xB3A8 0xB08F # 0 +0xB3A9 0xB091 # 0 +0xB3AA 0xB098 # 0 +0xB3AB 0xB099 # 0 +0xB3AC 0xB09A # 0 +0xB3AD 0xB09C # 0 +0xB3AE 0xB09F # 0 +0xB3AF 0xB0A0 # 0 +0xB3B0 0xB0A1 # 0 +0xB3B1 0xB0A2 # 0 +0xB3B2 0xB0A8 # 0 +0xB3B3 0xB0A9 # 0 +0xB3B4 0xB0AB # 0 +0xB3B5 0xB0AC # 0 +0xB3B6 0xB0AD # 0 +0xB3B7 0xB0AE # 0 +0xB3B8 0xB0AF # 0 +0xB3B9 0xB0B1 # 0 +0xB3BA 0xB0B3 # 0 +0xB3BB 0xB0B4 # 0 +0xB3BC 0xB0B5 # 0 +0xB3BD 0xB0B8 # 0 +0xB3BE 0xB0BC # 0 +0xB3BF 0xB0C4 # 0 +0xB3C0 0xB0C5 # 0 +0xB3C1 0xB0C7 # 0 +0xB3C2 0xB0C8 # 0 +0xB3C3 0xB0C9 # 0 +0xB3C4 0xB0D0 # 0 +0xB3C5 0xB0D1 # 0 +0xB3C6 0xB0D4 # 0 +0xB3C7 0xB0D8 # 0 +0xB3C8 0xB0E0 # 0 +0xB3C9 0xB0E5 # 0 +0xB3CA 0xB108 # 0 +0xB3CB 0xB109 # 0 +0xB3CC 0xB10B # 0 +0xB3CD 0xB10C # 0 +0xB3CE 0xB110 # 0 +0xB3CF 0xB112 # 0 +0xB3D0 0xB113 # 0 +0xB3D1 0xB118 # 0 +0xB3D2 0xB119 # 0 +0xB3D3 0xB11B # 0 +0xB3D4 0xB11C # 0 +0xB3D5 0xB11D # 0 +0xB3D6 0xB123 # 0 +0xB3D7 0xB124 # 0 +0xB3D8 0xB125 # 0 +0xB3D9 0xB128 # 0 +0xB3DA 0xB12C # 0 +0xB3DB 0xB134 # 0 +0xB3DC 0xB135 # 0 +0xB3DD 0xB137 # 0 +0xB3DE 0xB138 # 0 +0xB3DF 0xB139 # 0 +0xB3E0 0xB140 # 0 +0xB3E1 0xB141 # 0 +0xB3E2 0xB144 # 0 +0xB3E3 0xB148 # 0 +0xB3E4 0xB150 # 0 +0xB3E5 0xB151 # 0 +0xB3E6 0xB154 # 0 +0xB3E7 0xB155 # 0 +0xB3E8 0xB158 # 0 +0xB3E9 0xB15C # 0 +0xB3EA 0xB160 # 0 +0xB3EB 0xB178 # 0 +0xB3EC 0xB179 # 0 +0xB3ED 0xB17C # 0 +0xB3EE 0xB180 # 0 +0xB3EF 0xB182 # 0 +0xB3F0 0xB188 # 0 +0xB3F1 0xB189 # 0 +0xB3F2 0xB18B # 0 +0xB3F3 0xB18D # 0 +0xB3F4 0xB192 # 0 +0xB3F5 0xB193 # 0 +0xB3F6 0xB194 # 0 +0xB3F7 0xB198 # 0 +0xB3F8 0xB19C # 0 +0xB3F9 0xB1A8 # 0 +0xB3FA 0xB1CC # 0 +0xB3FB 0xB1D0 # 0 +0xB3FC 0xB1D4 # 0 +0xB3FD 0xB1DC # 0 +0xB3FE 0xB1DD # 0 +0xB441 0xD02E # 0 +0xB442 0xD02F # 0 +0xB443 0xD030 # 0 +0xB444 0xD031 # 0 +0xB445 0xD032 # 0 +0xB446 0xD033 # 0 +0xB447 0xD036 # 0 +0xB448 0xD037 # 0 +0xB449 0xD039 # 0 +0xB44A 0xD03A # 0 +0xB44B 0xD03B # 0 +0xB44C 0xD03D # 0 +0xB44D 0xD03E # 0 +0xB44E 0xD03F # 0 +0xB44F 0xD040 # 0 +0xB450 0xD041 # 0 +0xB451 0xD042 # 0 +0xB452 0xD043 # 0 +0xB453 0xD046 # 0 +0xB454 0xD048 # 0 +0xB455 0xD04A # 0 +0xB456 0xD04B # 0 +0xB457 0xD04C # 0 +0xB458 0xD04D # 0 +0xB459 0xD04E # 0 +0xB45A 0xD04F # 0 +0xB461 0xD051 # 0 +0xB462 0xD052 # 0 +0xB463 0xD053 # 0 +0xB464 0xD055 # 0 +0xB465 0xD056 # 0 +0xB466 0xD057 # 0 +0xB467 0xD059 # 0 +0xB468 0xD05A # 0 +0xB469 0xD05B # 0 +0xB46A 0xD05C # 0 +0xB46B 0xD05D # 0 +0xB46C 0xD05E # 0 +0xB46D 0xD05F # 0 +0xB46E 0xD061 # 0 +0xB46F 0xD062 # 0 +0xB470 0xD063 # 0 +0xB471 0xD064 # 0 +0xB472 0xD065 # 0 +0xB473 0xD066 # 0 +0xB474 0xD067 # 0 +0xB475 0xD068 # 0 +0xB476 0xD069 # 0 +0xB477 0xD06A # 0 +0xB478 0xD06B # 0 +0xB479 0xD06E # 0 +0xB47A 0xD06F # 0 +0xB481 0xD071 # 0 +0xB482 0xD072 # 0 +0xB483 0xD073 # 0 +0xB484 0xD075 # 0 +0xB485 0xD076 # 0 +0xB486 0xD077 # 0 +0xB487 0xD078 # 0 +0xB488 0xD079 # 0 +0xB489 0xD07A # 0 +0xB48A 0xD07B # 0 +0xB48B 0xD07E # 0 +0xB48C 0xD07F # 0 +0xB48D 0xD080 # 0 +0xB48E 0xD082 # 0 +0xB48F 0xD083 # 0 +0xB490 0xD084 # 0 +0xB491 0xD085 # 0 +0xB492 0xD086 # 0 +0xB493 0xD087 # 0 +0xB494 0xD088 # 0 +0xB495 0xD089 # 0 +0xB496 0xD08A # 0 +0xB497 0xD08B # 0 +0xB498 0xD08C # 0 +0xB499 0xD08D # 0 +0xB49A 0xD08E # 0 +0xB49B 0xD08F # 0 +0xB49C 0xD090 # 0 +0xB49D 0xD091 # 0 +0xB49E 0xD092 # 0 +0xB49F 0xD093 # 0 +0xB4A0 0xD094 # 0 +0xB4A1 0xB1DF # 0 +0xB4A2 0xB1E8 # 0 +0xB4A3 0xB1E9 # 0 +0xB4A4 0xB1EC # 0 +0xB4A5 0xB1F0 # 0 +0xB4A6 0xB1F9 # 0 +0xB4A7 0xB1FB # 0 +0xB4A8 0xB1FD # 0 +0xB4A9 0xB204 # 0 +0xB4AA 0xB205 # 0 +0xB4AB 0xB208 # 0 +0xB4AC 0xB20B # 0 +0xB4AD 0xB20C # 0 +0xB4AE 0xB214 # 0 +0xB4AF 0xB215 # 0 +0xB4B0 0xB217 # 0 +0xB4B1 0xB219 # 0 +0xB4B2 0xB220 # 0 +0xB4B3 0xB234 # 0 +0xB4B4 0xB23C # 0 +0xB4B5 0xB258 # 0 +0xB4B6 0xB25C # 0 +0xB4B7 0xB260 # 0 +0xB4B8 0xB268 # 0 +0xB4B9 0xB269 # 0 +0xB4BA 0xB274 # 0 +0xB4BB 0xB275 # 0 +0xB4BC 0xB27C # 0 +0xB4BD 0xB284 # 0 +0xB4BE 0xB285 # 0 +0xB4BF 0xB289 # 0 +0xB4C0 0xB290 # 0 +0xB4C1 0xB291 # 0 +0xB4C2 0xB294 # 0 +0xB4C3 0xB298 # 0 +0xB4C4 0xB299 # 0 +0xB4C5 0xB29A # 0 +0xB4C6 0xB2A0 # 0 +0xB4C7 0xB2A1 # 0 +0xB4C8 0xB2A3 # 0 +0xB4C9 0xB2A5 # 0 +0xB4CA 0xB2A6 # 0 +0xB4CB 0xB2AA # 0 +0xB4CC 0xB2AC # 0 +0xB4CD 0xB2B0 # 0 +0xB4CE 0xB2B4 # 0 +0xB4CF 0xB2C8 # 0 +0xB4D0 0xB2C9 # 0 +0xB4D1 0xB2CC # 0 +0xB4D2 0xB2D0 # 0 +0xB4D3 0xB2D2 # 0 +0xB4D4 0xB2D8 # 0 +0xB4D5 0xB2D9 # 0 +0xB4D6 0xB2DB # 0 +0xB4D7 0xB2DD # 0 +0xB4D8 0xB2E2 # 0 +0xB4D9 0xB2E4 # 0 +0xB4DA 0xB2E5 # 0 +0xB4DB 0xB2E6 # 0 +0xB4DC 0xB2E8 # 0 +0xB4DD 0xB2EB # 0 +0xB4DE 0xB2EC # 0 +0xB4DF 0xB2ED # 0 +0xB4E0 0xB2EE # 0 +0xB4E1 0xB2EF # 0 +0xB4E2 0xB2F3 # 0 +0xB4E3 0xB2F4 # 0 +0xB4E4 0xB2F5 # 0 +0xB4E5 0xB2F7 # 0 +0xB4E6 0xB2F8 # 0 +0xB4E7 0xB2F9 # 0 +0xB4E8 0xB2FA # 0 +0xB4E9 0xB2FB # 0 +0xB4EA 0xB2FF # 0 +0xB4EB 0xB300 # 0 +0xB4EC 0xB301 # 0 +0xB4ED 0xB304 # 0 +0xB4EE 0xB308 # 0 +0xB4EF 0xB310 # 0 +0xB4F0 0xB311 # 0 +0xB4F1 0xB313 # 0 +0xB4F2 0xB314 # 0 +0xB4F3 0xB315 # 0 +0xB4F4 0xB31C # 0 +0xB4F5 0xB354 # 0 +0xB4F6 0xB355 # 0 +0xB4F7 0xB356 # 0 +0xB4F8 0xB358 # 0 +0xB4F9 0xB35B # 0 +0xB4FA 0xB35C # 0 +0xB4FB 0xB35E # 0 +0xB4FC 0xB35F # 0 +0xB4FD 0xB364 # 0 +0xB4FE 0xB365 # 0 +0xB541 0xD095 # 0 +0xB542 0xD096 # 0 +0xB543 0xD097 # 0 +0xB544 0xD098 # 0 +0xB545 0xD099 # 0 +0xB546 0xD09A # 0 +0xB547 0xD09B # 0 +0xB548 0xD09C # 0 +0xB549 0xD09D # 0 +0xB54A 0xD09E # 0 +0xB54B 0xD09F # 0 +0xB54C 0xD0A0 # 0 +0xB54D 0xD0A1 # 0 +0xB54E 0xD0A2 # 0 +0xB54F 0xD0A3 # 0 +0xB550 0xD0A6 # 0 +0xB551 0xD0A7 # 0 +0xB552 0xD0A9 # 0 +0xB553 0xD0AA # 0 +0xB554 0xD0AB # 0 +0xB555 0xD0AD # 0 +0xB556 0xD0AE # 0 +0xB557 0xD0AF # 0 +0xB558 0xD0B0 # 0 +0xB559 0xD0B1 # 0 +0xB55A 0xD0B2 # 0 +0xB561 0xD0B3 # 0 +0xB562 0xD0B6 # 0 +0xB563 0xD0B8 # 0 +0xB564 0xD0BA # 0 +0xB565 0xD0BB # 0 +0xB566 0xD0BC # 0 +0xB567 0xD0BD # 0 +0xB568 0xD0BE # 0 +0xB569 0xD0BF # 0 +0xB56A 0xD0C2 # 0 +0xB56B 0xD0C3 # 0 +0xB56C 0xD0C5 # 0 +0xB56D 0xD0C6 # 0 +0xB56E 0xD0C7 # 0 +0xB56F 0xD0CA # 0 +0xB570 0xD0CB # 0 +0xB571 0xD0CC # 0 +0xB572 0xD0CD # 0 +0xB573 0xD0CE # 0 +0xB574 0xD0CF # 0 +0xB575 0xD0D2 # 0 +0xB576 0xD0D6 # 0 +0xB577 0xD0D7 # 0 +0xB578 0xD0D8 # 0 +0xB579 0xD0D9 # 0 +0xB57A 0xD0DA # 0 +0xB581 0xD0DB # 0 +0xB582 0xD0DE # 0 +0xB583 0xD0DF # 0 +0xB584 0xD0E1 # 0 +0xB585 0xD0E2 # 0 +0xB586 0xD0E3 # 0 +0xB587 0xD0E5 # 0 +0xB588 0xD0E6 # 0 +0xB589 0xD0E7 # 0 +0xB58A 0xD0E8 # 0 +0xB58B 0xD0E9 # 0 +0xB58C 0xD0EA # 0 +0xB58D 0xD0EB # 0 +0xB58E 0xD0EE # 0 +0xB58F 0xD0F2 # 0 +0xB590 0xD0F3 # 0 +0xB591 0xD0F4 # 0 +0xB592 0xD0F5 # 0 +0xB593 0xD0F6 # 0 +0xB594 0xD0F7 # 0 +0xB595 0xD0F9 # 0 +0xB596 0xD0FA # 0 +0xB597 0xD0FB # 0 +0xB598 0xD0FC # 0 +0xB599 0xD0FD # 0 +0xB59A 0xD0FE # 0 +0xB59B 0xD0FF # 0 +0xB59C 0xD100 # 0 +0xB59D 0xD101 # 0 +0xB59E 0xD102 # 0 +0xB59F 0xD103 # 0 +0xB5A0 0xD104 # 0 +0xB5A1 0xB367 # 0 +0xB5A2 0xB369 # 0 +0xB5A3 0xB36B # 0 +0xB5A4 0xB36E # 0 +0xB5A5 0xB370 # 0 +0xB5A6 0xB371 # 0 +0xB5A7 0xB374 # 0 +0xB5A8 0xB378 # 0 +0xB5A9 0xB380 # 0 +0xB5AA 0xB381 # 0 +0xB5AB 0xB383 # 0 +0xB5AC 0xB384 # 0 +0xB5AD 0xB385 # 0 +0xB5AE 0xB38C # 0 +0xB5AF 0xB390 # 0 +0xB5B0 0xB394 # 0 +0xB5B1 0xB3A0 # 0 +0xB5B2 0xB3A1 # 0 +0xB5B3 0xB3A8 # 0 +0xB5B4 0xB3AC # 0 +0xB5B5 0xB3C4 # 0 +0xB5B6 0xB3C5 # 0 +0xB5B7 0xB3C8 # 0 +0xB5B8 0xB3CB # 0 +0xB5B9 0xB3CC # 0 +0xB5BA 0xB3CE # 0 +0xB5BB 0xB3D0 # 0 +0xB5BC 0xB3D4 # 0 +0xB5BD 0xB3D5 # 0 +0xB5BE 0xB3D7 # 0 +0xB5BF 0xB3D9 # 0 +0xB5C0 0xB3DB # 0 +0xB5C1 0xB3DD # 0 +0xB5C2 0xB3E0 # 0 +0xB5C3 0xB3E4 # 0 +0xB5C4 0xB3E8 # 0 +0xB5C5 0xB3FC # 0 +0xB5C6 0xB410 # 0 +0xB5C7 0xB418 # 0 +0xB5C8 0xB41C # 0 +0xB5C9 0xB420 # 0 +0xB5CA 0xB428 # 0 +0xB5CB 0xB429 # 0 +0xB5CC 0xB42B # 0 +0xB5CD 0xB434 # 0 +0xB5CE 0xB450 # 0 +0xB5CF 0xB451 # 0 +0xB5D0 0xB454 # 0 +0xB5D1 0xB458 # 0 +0xB5D2 0xB460 # 0 +0xB5D3 0xB461 # 0 +0xB5D4 0xB463 # 0 +0xB5D5 0xB465 # 0 +0xB5D6 0xB46C # 0 +0xB5D7 0xB480 # 0 +0xB5D8 0xB488 # 0 +0xB5D9 0xB49D # 0 +0xB5DA 0xB4A4 # 0 +0xB5DB 0xB4A8 # 0 +0xB5DC 0xB4AC # 0 +0xB5DD 0xB4B5 # 0 +0xB5DE 0xB4B7 # 0 +0xB5DF 0xB4B9 # 0 +0xB5E0 0xB4C0 # 0 +0xB5E1 0xB4C4 # 0 +0xB5E2 0xB4C8 # 0 +0xB5E3 0xB4D0 # 0 +0xB5E4 0xB4D5 # 0 +0xB5E5 0xB4DC # 0 +0xB5E6 0xB4DD # 0 +0xB5E7 0xB4E0 # 0 +0xB5E8 0xB4E3 # 0 +0xB5E9 0xB4E4 # 0 +0xB5EA 0xB4E6 # 0 +0xB5EB 0xB4EC # 0 +0xB5EC 0xB4ED # 0 +0xB5ED 0xB4EF # 0 +0xB5EE 0xB4F1 # 0 +0xB5EF 0xB4F8 # 0 +0xB5F0 0xB514 # 0 +0xB5F1 0xB515 # 0 +0xB5F2 0xB518 # 0 +0xB5F3 0xB51B # 0 +0xB5F4 0xB51C # 0 +0xB5F5 0xB524 # 0 +0xB5F6 0xB525 # 0 +0xB5F7 0xB527 # 0 +0xB5F8 0xB528 # 0 +0xB5F9 0xB529 # 0 +0xB5FA 0xB52A # 0 +0xB5FB 0xB530 # 0 +0xB5FC 0xB531 # 0 +0xB5FD 0xB534 # 0 +0xB5FE 0xB538 # 0 +0xB641 0xD105 # 0 +0xB642 0xD106 # 0 +0xB643 0xD107 # 0 +0xB644 0xD108 # 0 +0xB645 0xD109 # 0 +0xB646 0xD10A # 0 +0xB647 0xD10B # 0 +0xB648 0xD10C # 0 +0xB649 0xD10E # 0 +0xB64A 0xD10F # 0 +0xB64B 0xD110 # 0 +0xB64C 0xD111 # 0 +0xB64D 0xD112 # 0 +0xB64E 0xD113 # 0 +0xB64F 0xD114 # 0 +0xB650 0xD115 # 0 +0xB651 0xD116 # 0 +0xB652 0xD117 # 0 +0xB653 0xD118 # 0 +0xB654 0xD119 # 0 +0xB655 0xD11A # 0 +0xB656 0xD11B # 0 +0xB657 0xD11C # 0 +0xB658 0xD11D # 0 +0xB659 0xD11E # 0 +0xB65A 0xD11F # 0 +0xB661 0xD120 # 0 +0xB662 0xD121 # 0 +0xB663 0xD122 # 0 +0xB664 0xD123 # 0 +0xB665 0xD124 # 0 +0xB666 0xD125 # 0 +0xB667 0xD126 # 0 +0xB668 0xD127 # 0 +0xB669 0xD128 # 0 +0xB66A 0xD129 # 0 +0xB66B 0xD12A # 0 +0xB66C 0xD12B # 0 +0xB66D 0xD12C # 0 +0xB66E 0xD12D # 0 +0xB66F 0xD12E # 0 +0xB670 0xD12F # 0 +0xB671 0xD132 # 0 +0xB672 0xD133 # 0 +0xB673 0xD135 # 0 +0xB674 0xD136 # 0 +0xB675 0xD137 # 0 +0xB676 0xD139 # 0 +0xB677 0xD13B # 0 +0xB678 0xD13C # 0 +0xB679 0xD13D # 0 +0xB67A 0xD13E # 0 +0xB681 0xD13F # 0 +0xB682 0xD142 # 0 +0xB683 0xD146 # 0 +0xB684 0xD147 # 0 +0xB685 0xD148 # 0 +0xB686 0xD149 # 0 +0xB687 0xD14A # 0 +0xB688 0xD14B # 0 +0xB689 0xD14E # 0 +0xB68A 0xD14F # 0 +0xB68B 0xD151 # 0 +0xB68C 0xD152 # 0 +0xB68D 0xD153 # 0 +0xB68E 0xD155 # 0 +0xB68F 0xD156 # 0 +0xB690 0xD157 # 0 +0xB691 0xD158 # 0 +0xB692 0xD159 # 0 +0xB693 0xD15A # 0 +0xB694 0xD15B # 0 +0xB695 0xD15E # 0 +0xB696 0xD160 # 0 +0xB697 0xD162 # 0 +0xB698 0xD163 # 0 +0xB699 0xD164 # 0 +0xB69A 0xD165 # 0 +0xB69B 0xD166 # 0 +0xB69C 0xD167 # 0 +0xB69D 0xD169 # 0 +0xB69E 0xD16A # 0 +0xB69F 0xD16B # 0 +0xB6A0 0xD16D # 0 +0xB6A1 0xB540 # 0 +0xB6A2 0xB541 # 0 +0xB6A3 0xB543 # 0 +0xB6A4 0xB544 # 0 +0xB6A5 0xB545 # 0 +0xB6A6 0xB54B # 0 +0xB6A7 0xB54C # 0 +0xB6A8 0xB54D # 0 +0xB6A9 0xB550 # 0 +0xB6AA 0xB554 # 0 +0xB6AB 0xB55C # 0 +0xB6AC 0xB55D # 0 +0xB6AD 0xB55F # 0 +0xB6AE 0xB560 # 0 +0xB6AF 0xB561 # 0 +0xB6B0 0xB5A0 # 0 +0xB6B1 0xB5A1 # 0 +0xB6B2 0xB5A4 # 0 +0xB6B3 0xB5A8 # 0 +0xB6B4 0xB5AA # 0 +0xB6B5 0xB5AB # 0 +0xB6B6 0xB5B0 # 0 +0xB6B7 0xB5B1 # 0 +0xB6B8 0xB5B3 # 0 +0xB6B9 0xB5B4 # 0 +0xB6BA 0xB5B5 # 0 +0xB6BB 0xB5BB # 0 +0xB6BC 0xB5BC # 0 +0xB6BD 0xB5BD # 0 +0xB6BE 0xB5C0 # 0 +0xB6BF 0xB5C4 # 0 +0xB6C0 0xB5CC # 0 +0xB6C1 0xB5CD # 0 +0xB6C2 0xB5CF # 0 +0xB6C3 0xB5D0 # 0 +0xB6C4 0xB5D1 # 0 +0xB6C5 0xB5D8 # 0 +0xB6C6 0xB5EC # 0 +0xB6C7 0xB610 # 0 +0xB6C8 0xB611 # 0 +0xB6C9 0xB614 # 0 +0xB6CA 0xB618 # 0 +0xB6CB 0xB625 # 0 +0xB6CC 0xB62C # 0 +0xB6CD 0xB634 # 0 +0xB6CE 0xB648 # 0 +0xB6CF 0xB664 # 0 +0xB6D0 0xB668 # 0 +0xB6D1 0xB69C # 0 +0xB6D2 0xB69D # 0 +0xB6D3 0xB6A0 # 0 +0xB6D4 0xB6A4 # 0 +0xB6D5 0xB6AB # 0 +0xB6D6 0xB6AC # 0 +0xB6D7 0xB6B1 # 0 +0xB6D8 0xB6D4 # 0 +0xB6D9 0xB6F0 # 0 +0xB6DA 0xB6F4 # 0 +0xB6DB 0xB6F8 # 0 +0xB6DC 0xB700 # 0 +0xB6DD 0xB701 # 0 +0xB6DE 0xB705 # 0 +0xB6DF 0xB728 # 0 +0xB6E0 0xB729 # 0 +0xB6E1 0xB72C # 0 +0xB6E2 0xB72F # 0 +0xB6E3 0xB730 # 0 +0xB6E4 0xB738 # 0 +0xB6E5 0xB739 # 0 +0xB6E6 0xB73B # 0 +0xB6E7 0xB744 # 0 +0xB6E8 0xB748 # 0 +0xB6E9 0xB74C # 0 +0xB6EA 0xB754 # 0 +0xB6EB 0xB755 # 0 +0xB6EC 0xB760 # 0 +0xB6ED 0xB764 # 0 +0xB6EE 0xB768 # 0 +0xB6EF 0xB770 # 0 +0xB6F0 0xB771 # 0 +0xB6F1 0xB773 # 0 +0xB6F2 0xB775 # 0 +0xB6F3 0xB77C # 0 +0xB6F4 0xB77D # 0 +0xB6F5 0xB780 # 0 +0xB6F6 0xB784 # 0 +0xB6F7 0xB78C # 0 +0xB6F8 0xB78D # 0 +0xB6F9 0xB78F # 0 +0xB6FA 0xB790 # 0 +0xB6FB 0xB791 # 0 +0xB6FC 0xB792 # 0 +0xB6FD 0xB796 # 0 +0xB6FE 0xB797 # 0 +0xB741 0xD16E # 0 +0xB742 0xD16F # 0 +0xB743 0xD170 # 0 +0xB744 0xD171 # 0 +0xB745 0xD172 # 0 +0xB746 0xD173 # 0 +0xB747 0xD174 # 0 +0xB748 0xD175 # 0 +0xB749 0xD176 # 0 +0xB74A 0xD177 # 0 +0xB74B 0xD178 # 0 +0xB74C 0xD179 # 0 +0xB74D 0xD17A # 0 +0xB74E 0xD17B # 0 +0xB74F 0xD17D # 0 +0xB750 0xD17E # 0 +0xB751 0xD17F # 0 +0xB752 0xD180 # 0 +0xB753 0xD181 # 0 +0xB754 0xD182 # 0 +0xB755 0xD183 # 0 +0xB756 0xD185 # 0 +0xB757 0xD186 # 0 +0xB758 0xD187 # 0 +0xB759 0xD189 # 0 +0xB75A 0xD18A # 0 +0xB761 0xD18B # 0 +0xB762 0xD18C # 0 +0xB763 0xD18D # 0 +0xB764 0xD18E # 0 +0xB765 0xD18F # 0 +0xB766 0xD190 # 0 +0xB767 0xD191 # 0 +0xB768 0xD192 # 0 +0xB769 0xD193 # 0 +0xB76A 0xD194 # 0 +0xB76B 0xD195 # 0 +0xB76C 0xD196 # 0 +0xB76D 0xD197 # 0 +0xB76E 0xD198 # 0 +0xB76F 0xD199 # 0 +0xB770 0xD19A # 0 +0xB771 0xD19B # 0 +0xB772 0xD19C # 0 +0xB773 0xD19D # 0 +0xB774 0xD19E # 0 +0xB775 0xD19F # 0 +0xB776 0xD1A2 # 0 +0xB777 0xD1A3 # 0 +0xB778 0xD1A5 # 0 +0xB779 0xD1A6 # 0 +0xB77A 0xD1A7 # 0 +0xB781 0xD1A9 # 0 +0xB782 0xD1AA # 0 +0xB783 0xD1AB # 0 +0xB784 0xD1AC # 0 +0xB785 0xD1AD # 0 +0xB786 0xD1AE # 0 +0xB787 0xD1AF # 0 +0xB788 0xD1B2 # 0 +0xB789 0xD1B4 # 0 +0xB78A 0xD1B6 # 0 +0xB78B 0xD1B7 # 0 +0xB78C 0xD1B8 # 0 +0xB78D 0xD1B9 # 0 +0xB78E 0xD1BB # 0 +0xB78F 0xD1BD # 0 +0xB790 0xD1BE # 0 +0xB791 0xD1BF # 0 +0xB792 0xD1C1 # 0 +0xB793 0xD1C2 # 0 +0xB794 0xD1C3 # 0 +0xB795 0xD1C4 # 0 +0xB796 0xD1C5 # 0 +0xB797 0xD1C6 # 0 +0xB798 0xD1C7 # 0 +0xB799 0xD1C8 # 0 +0xB79A 0xD1C9 # 0 +0xB79B 0xD1CA # 0 +0xB79C 0xD1CB # 0 +0xB79D 0xD1CC # 0 +0xB79E 0xD1CD # 0 +0xB79F 0xD1CE # 0 +0xB7A0 0xD1CF # 0 +0xB7A1 0xB798 # 0 +0xB7A2 0xB799 # 0 +0xB7A3 0xB79C # 0 +0xB7A4 0xB7A0 # 0 +0xB7A5 0xB7A8 # 0 +0xB7A6 0xB7A9 # 0 +0xB7A7 0xB7AB # 0 +0xB7A8 0xB7AC # 0 +0xB7A9 0xB7AD # 0 +0xB7AA 0xB7B4 # 0 +0xB7AB 0xB7B5 # 0 +0xB7AC 0xB7B8 # 0 +0xB7AD 0xB7C7 # 0 +0xB7AE 0xB7C9 # 0 +0xB7AF 0xB7EC # 0 +0xB7B0 0xB7ED # 0 +0xB7B1 0xB7F0 # 0 +0xB7B2 0xB7F4 # 0 +0xB7B3 0xB7FC # 0 +0xB7B4 0xB7FD # 0 +0xB7B5 0xB7FF # 0 +0xB7B6 0xB800 # 0 +0xB7B7 0xB801 # 0 +0xB7B8 0xB807 # 0 +0xB7B9 0xB808 # 0 +0xB7BA 0xB809 # 0 +0xB7BB 0xB80C # 0 +0xB7BC 0xB810 # 0 +0xB7BD 0xB818 # 0 +0xB7BE 0xB819 # 0 +0xB7BF 0xB81B # 0 +0xB7C0 0xB81D # 0 +0xB7C1 0xB824 # 0 +0xB7C2 0xB825 # 0 +0xB7C3 0xB828 # 0 +0xB7C4 0xB82C # 0 +0xB7C5 0xB834 # 0 +0xB7C6 0xB835 # 0 +0xB7C7 0xB837 # 0 +0xB7C8 0xB838 # 0 +0xB7C9 0xB839 # 0 +0xB7CA 0xB840 # 0 +0xB7CB 0xB844 # 0 +0xB7CC 0xB851 # 0 +0xB7CD 0xB853 # 0 +0xB7CE 0xB85C # 0 +0xB7CF 0xB85D # 0 +0xB7D0 0xB860 # 0 +0xB7D1 0xB864 # 0 +0xB7D2 0xB86C # 0 +0xB7D3 0xB86D # 0 +0xB7D4 0xB86F # 0 +0xB7D5 0xB871 # 0 +0xB7D6 0xB878 # 0 +0xB7D7 0xB87C # 0 +0xB7D8 0xB88D # 0 +0xB7D9 0xB8A8 # 0 +0xB7DA 0xB8B0 # 0 +0xB7DB 0xB8B4 # 0 +0xB7DC 0xB8B8 # 0 +0xB7DD 0xB8C0 # 0 +0xB7DE 0xB8C1 # 0 +0xB7DF 0xB8C3 # 0 +0xB7E0 0xB8C5 # 0 +0xB7E1 0xB8CC # 0 +0xB7E2 0xB8D0 # 0 +0xB7E3 0xB8D4 # 0 +0xB7E4 0xB8DD # 0 +0xB7E5 0xB8DF # 0 +0xB7E6 0xB8E1 # 0 +0xB7E7 0xB8E8 # 0 +0xB7E8 0xB8E9 # 0 +0xB7E9 0xB8EC # 0 +0xB7EA 0xB8F0 # 0 +0xB7EB 0xB8F8 # 0 +0xB7EC 0xB8F9 # 0 +0xB7ED 0xB8FB # 0 +0xB7EE 0xB8FD # 0 +0xB7EF 0xB904 # 0 +0xB7F0 0xB918 # 0 +0xB7F1 0xB920 # 0 +0xB7F2 0xB93C # 0 +0xB7F3 0xB93D # 0 +0xB7F4 0xB940 # 0 +0xB7F5 0xB944 # 0 +0xB7F6 0xB94C # 0 +0xB7F7 0xB94F # 0 +0xB7F8 0xB951 # 0 +0xB7F9 0xB958 # 0 +0xB7FA 0xB959 # 0 +0xB7FB 0xB95C # 0 +0xB7FC 0xB960 # 0 +0xB7FD 0xB968 # 0 +0xB7FE 0xB969 # 0 +0xB841 0xD1D0 # 0 +0xB842 0xD1D1 # 0 +0xB843 0xD1D2 # 0 +0xB844 0xD1D3 # 0 +0xB845 0xD1D4 # 0 +0xB846 0xD1D5 # 0 +0xB847 0xD1D6 # 0 +0xB848 0xD1D7 # 0 +0xB849 0xD1D9 # 0 +0xB84A 0xD1DA # 0 +0xB84B 0xD1DB # 0 +0xB84C 0xD1DC # 0 +0xB84D 0xD1DD # 0 +0xB84E 0xD1DE # 0 +0xB84F 0xD1DF # 0 +0xB850 0xD1E0 # 0 +0xB851 0xD1E1 # 0 +0xB852 0xD1E2 # 0 +0xB853 0xD1E3 # 0 +0xB854 0xD1E4 # 0 +0xB855 0xD1E5 # 0 +0xB856 0xD1E6 # 0 +0xB857 0xD1E7 # 0 +0xB858 0xD1E8 # 0 +0xB859 0xD1E9 # 0 +0xB85A 0xD1EA # 0 +0xB861 0xD1EB # 0 +0xB862 0xD1EC # 0 +0xB863 0xD1ED # 0 +0xB864 0xD1EE # 0 +0xB865 0xD1EF # 0 +0xB866 0xD1F0 # 0 +0xB867 0xD1F1 # 0 +0xB868 0xD1F2 # 0 +0xB869 0xD1F3 # 0 +0xB86A 0xD1F5 # 0 +0xB86B 0xD1F6 # 0 +0xB86C 0xD1F7 # 0 +0xB86D 0xD1F9 # 0 +0xB86E 0xD1FA # 0 +0xB86F 0xD1FB # 0 +0xB870 0xD1FC # 0 +0xB871 0xD1FD # 0 +0xB872 0xD1FE # 0 +0xB873 0xD1FF # 0 +0xB874 0xD200 # 0 +0xB875 0xD201 # 0 +0xB876 0xD202 # 0 +0xB877 0xD203 # 0 +0xB878 0xD204 # 0 +0xB879 0xD205 # 0 +0xB87A 0xD206 # 0 +0xB881 0xD208 # 0 +0xB882 0xD20A # 0 +0xB883 0xD20B # 0 +0xB884 0xD20C # 0 +0xB885 0xD20D # 0 +0xB886 0xD20E # 0 +0xB887 0xD20F # 0 +0xB888 0xD211 # 0 +0xB889 0xD212 # 0 +0xB88A 0xD213 # 0 +0xB88B 0xD214 # 0 +0xB88C 0xD215 # 0 +0xB88D 0xD216 # 0 +0xB88E 0xD217 # 0 +0xB88F 0xD218 # 0 +0xB890 0xD219 # 0 +0xB891 0xD21A # 0 +0xB892 0xD21B # 0 +0xB893 0xD21C # 0 +0xB894 0xD21D # 0 +0xB895 0xD21E # 0 +0xB896 0xD21F # 0 +0xB897 0xD220 # 0 +0xB898 0xD221 # 0 +0xB899 0xD222 # 0 +0xB89A 0xD223 # 0 +0xB89B 0xD224 # 0 +0xB89C 0xD225 # 0 +0xB89D 0xD226 # 0 +0xB89E 0xD227 # 0 +0xB89F 0xD228 # 0 +0xB8A0 0xD229 # 0 +0xB8A1 0xB96B # 0 +0xB8A2 0xB96D # 0 +0xB8A3 0xB974 # 0 +0xB8A4 0xB975 # 0 +0xB8A5 0xB978 # 0 +0xB8A6 0xB97C # 0 +0xB8A7 0xB984 # 0 +0xB8A8 0xB985 # 0 +0xB8A9 0xB987 # 0 +0xB8AA 0xB989 # 0 +0xB8AB 0xB98A # 0 +0xB8AC 0xB98D # 0 +0xB8AD 0xB98E # 0 +0xB8AE 0xB9AC # 0 +0xB8AF 0xB9AD # 0 +0xB8B0 0xB9B0 # 0 +0xB8B1 0xB9B4 # 0 +0xB8B2 0xB9BC # 0 +0xB8B3 0xB9BD # 0 +0xB8B4 0xB9BF # 0 +0xB8B5 0xB9C1 # 0 +0xB8B6 0xB9C8 # 0 +0xB8B7 0xB9C9 # 0 +0xB8B8 0xB9CC # 0 +0xB8B9 0xB9CE # 0 +0xB8BA 0xB9CF # 0 +0xB8BB 0xB9D0 # 0 +0xB8BC 0xB9D1 # 0 +0xB8BD 0xB9D2 # 0 +0xB8BE 0xB9D8 # 0 +0xB8BF 0xB9D9 # 0 +0xB8C0 0xB9DB # 0 +0xB8C1 0xB9DD # 0 +0xB8C2 0xB9DE # 0 +0xB8C3 0xB9E1 # 0 +0xB8C4 0xB9E3 # 0 +0xB8C5 0xB9E4 # 0 +0xB8C6 0xB9E5 # 0 +0xB8C7 0xB9E8 # 0 +0xB8C8 0xB9EC # 0 +0xB8C9 0xB9F4 # 0 +0xB8CA 0xB9F5 # 0 +0xB8CB 0xB9F7 # 0 +0xB8CC 0xB9F8 # 0 +0xB8CD 0xB9F9 # 0 +0xB8CE 0xB9FA # 0 +0xB8CF 0xBA00 # 0 +0xB8D0 0xBA01 # 0 +0xB8D1 0xBA08 # 0 +0xB8D2 0xBA15 # 0 +0xB8D3 0xBA38 # 0 +0xB8D4 0xBA39 # 0 +0xB8D5 0xBA3C # 0 +0xB8D6 0xBA40 # 0 +0xB8D7 0xBA42 # 0 +0xB8D8 0xBA48 # 0 +0xB8D9 0xBA49 # 0 +0xB8DA 0xBA4B # 0 +0xB8DB 0xBA4D # 0 +0xB8DC 0xBA4E # 0 +0xB8DD 0xBA53 # 0 +0xB8DE 0xBA54 # 0 +0xB8DF 0xBA55 # 0 +0xB8E0 0xBA58 # 0 +0xB8E1 0xBA5C # 0 +0xB8E2 0xBA64 # 0 +0xB8E3 0xBA65 # 0 +0xB8E4 0xBA67 # 0 +0xB8E5 0xBA68 # 0 +0xB8E6 0xBA69 # 0 +0xB8E7 0xBA70 # 0 +0xB8E8 0xBA71 # 0 +0xB8E9 0xBA74 # 0 +0xB8EA 0xBA78 # 0 +0xB8EB 0xBA83 # 0 +0xB8EC 0xBA84 # 0 +0xB8ED 0xBA85 # 0 +0xB8EE 0xBA87 # 0 +0xB8EF 0xBA8C # 0 +0xB8F0 0xBAA8 # 0 +0xB8F1 0xBAA9 # 0 +0xB8F2 0xBAAB # 0 +0xB8F3 0xBAAC # 0 +0xB8F4 0xBAB0 # 0 +0xB8F5 0xBAB2 # 0 +0xB8F6 0xBAB8 # 0 +0xB8F7 0xBAB9 # 0 +0xB8F8 0xBABB # 0 +0xB8F9 0xBABD # 0 +0xB8FA 0xBAC4 # 0 +0xB8FB 0xBAC8 # 0 +0xB8FC 0xBAD8 # 0 +0xB8FD 0xBAD9 # 0 +0xB8FE 0xBAFC # 0 +0xB941 0xD22A # 0 +0xB942 0xD22B # 0 +0xB943 0xD22E # 0 +0xB944 0xD22F # 0 +0xB945 0xD231 # 0 +0xB946 0xD232 # 0 +0xB947 0xD233 # 0 +0xB948 0xD235 # 0 +0xB949 0xD236 # 0 +0xB94A 0xD237 # 0 +0xB94B 0xD238 # 0 +0xB94C 0xD239 # 0 +0xB94D 0xD23A # 0 +0xB94E 0xD23B # 0 +0xB94F 0xD23E # 0 +0xB950 0xD240 # 0 +0xB951 0xD242 # 0 +0xB952 0xD243 # 0 +0xB953 0xD244 # 0 +0xB954 0xD245 # 0 +0xB955 0xD246 # 0 +0xB956 0xD247 # 0 +0xB957 0xD249 # 0 +0xB958 0xD24A # 0 +0xB959 0xD24B # 0 +0xB95A 0xD24C # 0 +0xB961 0xD24D # 0 +0xB962 0xD24E # 0 +0xB963 0xD24F # 0 +0xB964 0xD250 # 0 +0xB965 0xD251 # 0 +0xB966 0xD252 # 0 +0xB967 0xD253 # 0 +0xB968 0xD254 # 0 +0xB969 0xD255 # 0 +0xB96A 0xD256 # 0 +0xB96B 0xD257 # 0 +0xB96C 0xD258 # 0 +0xB96D 0xD259 # 0 +0xB96E 0xD25A # 0 +0xB96F 0xD25B # 0 +0xB970 0xD25D # 0 +0xB971 0xD25E # 0 +0xB972 0xD25F # 0 +0xB973 0xD260 # 0 +0xB974 0xD261 # 0 +0xB975 0xD262 # 0 +0xB976 0xD263 # 0 +0xB977 0xD265 # 0 +0xB978 0xD266 # 0 +0xB979 0xD267 # 0 +0xB97A 0xD268 # 0 +0xB981 0xD269 # 0 +0xB982 0xD26A # 0 +0xB983 0xD26B # 0 +0xB984 0xD26C # 0 +0xB985 0xD26D # 0 +0xB986 0xD26E # 0 +0xB987 0xD26F # 0 +0xB988 0xD270 # 0 +0xB989 0xD271 # 0 +0xB98A 0xD272 # 0 +0xB98B 0xD273 # 0 +0xB98C 0xD274 # 0 +0xB98D 0xD275 # 0 +0xB98E 0xD276 # 0 +0xB98F 0xD277 # 0 +0xB990 0xD278 # 0 +0xB991 0xD279 # 0 +0xB992 0xD27A # 0 +0xB993 0xD27B # 0 +0xB994 0xD27C # 0 +0xB995 0xD27D # 0 +0xB996 0xD27E # 0 +0xB997 0xD27F # 0 +0xB998 0xD282 # 0 +0xB999 0xD283 # 0 +0xB99A 0xD285 # 0 +0xB99B 0xD286 # 0 +0xB99C 0xD287 # 0 +0xB99D 0xD289 # 0 +0xB99E 0xD28A # 0 +0xB99F 0xD28B # 0 +0xB9A0 0xD28C # 0 +0xB9A1 0xBB00 # 0 +0xB9A2 0xBB04 # 0 +0xB9A3 0xBB0D # 0 +0xB9A4 0xBB0F # 0 +0xB9A5 0xBB11 # 0 +0xB9A6 0xBB18 # 0 +0xB9A7 0xBB1C # 0 +0xB9A8 0xBB20 # 0 +0xB9A9 0xBB29 # 0 +0xB9AA 0xBB2B # 0 +0xB9AB 0xBB34 # 0 +0xB9AC 0xBB35 # 0 +0xB9AD 0xBB36 # 0 +0xB9AE 0xBB38 # 0 +0xB9AF 0xBB3B # 0 +0xB9B0 0xBB3C # 0 +0xB9B1 0xBB3D # 0 +0xB9B2 0xBB3E # 0 +0xB9B3 0xBB44 # 0 +0xB9B4 0xBB45 # 0 +0xB9B5 0xBB47 # 0 +0xB9B6 0xBB49 # 0 +0xB9B7 0xBB4D # 0 +0xB9B8 0xBB4F # 0 +0xB9B9 0xBB50 # 0 +0xB9BA 0xBB54 # 0 +0xB9BB 0xBB58 # 0 +0xB9BC 0xBB61 # 0 +0xB9BD 0xBB63 # 0 +0xB9BE 0xBB6C # 0 +0xB9BF 0xBB88 # 0 +0xB9C0 0xBB8C # 0 +0xB9C1 0xBB90 # 0 +0xB9C2 0xBBA4 # 0 +0xB9C3 0xBBA8 # 0 +0xB9C4 0xBBAC # 0 +0xB9C5 0xBBB4 # 0 +0xB9C6 0xBBB7 # 0 +0xB9C7 0xBBC0 # 0 +0xB9C8 0xBBC4 # 0 +0xB9C9 0xBBC8 # 0 +0xB9CA 0xBBD0 # 0 +0xB9CB 0xBBD3 # 0 +0xB9CC 0xBBF8 # 0 +0xB9CD 0xBBF9 # 0 +0xB9CE 0xBBFC # 0 +0xB9CF 0xBBFF # 0 +0xB9D0 0xBC00 # 0 +0xB9D1 0xBC02 # 0 +0xB9D2 0xBC08 # 0 +0xB9D3 0xBC09 # 0 +0xB9D4 0xBC0B # 0 +0xB9D5 0xBC0C # 0 +0xB9D6 0xBC0D # 0 +0xB9D7 0xBC0F # 0 +0xB9D8 0xBC11 # 0 +0xB9D9 0xBC14 # 0 +0xB9DA 0xBC15 # 0 +0xB9DB 0xBC16 # 0 +0xB9DC 0xBC17 # 0 +0xB9DD 0xBC18 # 0 +0xB9DE 0xBC1B # 0 +0xB9DF 0xBC1C # 0 +0xB9E0 0xBC1D # 0 +0xB9E1 0xBC1E # 0 +0xB9E2 0xBC1F # 0 +0xB9E3 0xBC24 # 0 +0xB9E4 0xBC25 # 0 +0xB9E5 0xBC27 # 0 +0xB9E6 0xBC29 # 0 +0xB9E7 0xBC2D # 0 +0xB9E8 0xBC30 # 0 +0xB9E9 0xBC31 # 0 +0xB9EA 0xBC34 # 0 +0xB9EB 0xBC38 # 0 +0xB9EC 0xBC40 # 0 +0xB9ED 0xBC41 # 0 +0xB9EE 0xBC43 # 0 +0xB9EF 0xBC44 # 0 +0xB9F0 0xBC45 # 0 +0xB9F1 0xBC49 # 0 +0xB9F2 0xBC4C # 0 +0xB9F3 0xBC4D # 0 +0xB9F4 0xBC50 # 0 +0xB9F5 0xBC5D # 0 +0xB9F6 0xBC84 # 0 +0xB9F7 0xBC85 # 0 +0xB9F8 0xBC88 # 0 +0xB9F9 0xBC8B # 0 +0xB9FA 0xBC8C # 0 +0xB9FB 0xBC8E # 0 +0xB9FC 0xBC94 # 0 +0xB9FD 0xBC95 # 0 +0xB9FE 0xBC97 # 0 +0xBA41 0xD28D # 0 +0xBA42 0xD28E # 0 +0xBA43 0xD28F # 0 +0xBA44 0xD292 # 0 +0xBA45 0xD293 # 0 +0xBA46 0xD294 # 0 +0xBA47 0xD296 # 0 +0xBA48 0xD297 # 0 +0xBA49 0xD298 # 0 +0xBA4A 0xD299 # 0 +0xBA4B 0xD29A # 0 +0xBA4C 0xD29B # 0 +0xBA4D 0xD29D # 0 +0xBA4E 0xD29E # 0 +0xBA4F 0xD29F # 0 +0xBA50 0xD2A1 # 0 +0xBA51 0xD2A2 # 0 +0xBA52 0xD2A3 # 0 +0xBA53 0xD2A5 # 0 +0xBA54 0xD2A6 # 0 +0xBA55 0xD2A7 # 0 +0xBA56 0xD2A8 # 0 +0xBA57 0xD2A9 # 0 +0xBA58 0xD2AA # 0 +0xBA59 0xD2AB # 0 +0xBA5A 0xD2AD # 0 +0xBA61 0xD2AE # 0 +0xBA62 0xD2AF # 0 +0xBA63 0xD2B0 # 0 +0xBA64 0xD2B2 # 0 +0xBA65 0xD2B3 # 0 +0xBA66 0xD2B4 # 0 +0xBA67 0xD2B5 # 0 +0xBA68 0xD2B6 # 0 +0xBA69 0xD2B7 # 0 +0xBA6A 0xD2BA # 0 +0xBA6B 0xD2BB # 0 +0xBA6C 0xD2BD # 0 +0xBA6D 0xD2BE # 0 +0xBA6E 0xD2C1 # 0 +0xBA6F 0xD2C3 # 0 +0xBA70 0xD2C4 # 0 +0xBA71 0xD2C5 # 0 +0xBA72 0xD2C6 # 0 +0xBA73 0xD2C7 # 0 +0xBA74 0xD2CA # 0 +0xBA75 0xD2CC # 0 +0xBA76 0xD2CD # 0 +0xBA77 0xD2CE # 0 +0xBA78 0xD2CF # 0 +0xBA79 0xD2D0 # 0 +0xBA7A 0xD2D1 # 0 +0xBA81 0xD2D2 # 0 +0xBA82 0xD2D3 # 0 +0xBA83 0xD2D5 # 0 +0xBA84 0xD2D6 # 0 +0xBA85 0xD2D7 # 0 +0xBA86 0xD2D9 # 0 +0xBA87 0xD2DA # 0 +0xBA88 0xD2DB # 0 +0xBA89 0xD2DD # 0 +0xBA8A 0xD2DE # 0 +0xBA8B 0xD2DF # 0 +0xBA8C 0xD2E0 # 0 +0xBA8D 0xD2E1 # 0 +0xBA8E 0xD2E2 # 0 +0xBA8F 0xD2E3 # 0 +0xBA90 0xD2E6 # 0 +0xBA91 0xD2E7 # 0 +0xBA92 0xD2E8 # 0 +0xBA93 0xD2E9 # 0 +0xBA94 0xD2EA # 0 +0xBA95 0xD2EB # 0 +0xBA96 0xD2EC # 0 +0xBA97 0xD2ED # 0 +0xBA98 0xD2EE # 0 +0xBA99 0xD2EF # 0 +0xBA9A 0xD2F2 # 0 +0xBA9B 0xD2F3 # 0 +0xBA9C 0xD2F5 # 0 +0xBA9D 0xD2F6 # 0 +0xBA9E 0xD2F7 # 0 +0xBA9F 0xD2F9 # 0 +0xBAA0 0xD2FA # 0 +0xBAA1 0xBC99 # 0 +0xBAA2 0xBC9A # 0 +0xBAA3 0xBCA0 # 0 +0xBAA4 0xBCA1 # 0 +0xBAA5 0xBCA4 # 0 +0xBAA6 0xBCA7 # 0 +0xBAA7 0xBCA8 # 0 +0xBAA8 0xBCB0 # 0 +0xBAA9 0xBCB1 # 0 +0xBAAA 0xBCB3 # 0 +0xBAAB 0xBCB4 # 0 +0xBAAC 0xBCB5 # 0 +0xBAAD 0xBCBC # 0 +0xBAAE 0xBCBD # 0 +0xBAAF 0xBCC0 # 0 +0xBAB0 0xBCC4 # 0 +0xBAB1 0xBCCD # 0 +0xBAB2 0xBCCF # 0 +0xBAB3 0xBCD0 # 0 +0xBAB4 0xBCD1 # 0 +0xBAB5 0xBCD5 # 0 +0xBAB6 0xBCD8 # 0 +0xBAB7 0xBCDC # 0 +0xBAB8 0xBCF4 # 0 +0xBAB9 0xBCF5 # 0 +0xBABA 0xBCF6 # 0 +0xBABB 0xBCF8 # 0 +0xBABC 0xBCFC # 0 +0xBABD 0xBD04 # 0 +0xBABE 0xBD05 # 0 +0xBABF 0xBD07 # 0 +0xBAC0 0xBD09 # 0 +0xBAC1 0xBD10 # 0 +0xBAC2 0xBD14 # 0 +0xBAC3 0xBD24 # 0 +0xBAC4 0xBD2C # 0 +0xBAC5 0xBD40 # 0 +0xBAC6 0xBD48 # 0 +0xBAC7 0xBD49 # 0 +0xBAC8 0xBD4C # 0 +0xBAC9 0xBD50 # 0 +0xBACA 0xBD58 # 0 +0xBACB 0xBD59 # 0 +0xBACC 0xBD64 # 0 +0xBACD 0xBD68 # 0 +0xBACE 0xBD80 # 0 +0xBACF 0xBD81 # 0 +0xBAD0 0xBD84 # 0 +0xBAD1 0xBD87 # 0 +0xBAD2 0xBD88 # 0 +0xBAD3 0xBD89 # 0 +0xBAD4 0xBD8A # 0 +0xBAD5 0xBD90 # 0 +0xBAD6 0xBD91 # 0 +0xBAD7 0xBD93 # 0 +0xBAD8 0xBD95 # 0 +0xBAD9 0xBD99 # 0 +0xBADA 0xBD9A # 0 +0xBADB 0xBD9C # 0 +0xBADC 0xBDA4 # 0 +0xBADD 0xBDB0 # 0 +0xBADE 0xBDB8 # 0 +0xBADF 0xBDD4 # 0 +0xBAE0 0xBDD5 # 0 +0xBAE1 0xBDD8 # 0 +0xBAE2 0xBDDC # 0 +0xBAE3 0xBDE9 # 0 +0xBAE4 0xBDF0 # 0 +0xBAE5 0xBDF4 # 0 +0xBAE6 0xBDF8 # 0 +0xBAE7 0xBE00 # 0 +0xBAE8 0xBE03 # 0 +0xBAE9 0xBE05 # 0 +0xBAEA 0xBE0C # 0 +0xBAEB 0xBE0D # 0 +0xBAEC 0xBE10 # 0 +0xBAED 0xBE14 # 0 +0xBAEE 0xBE1C # 0 +0xBAEF 0xBE1D # 0 +0xBAF0 0xBE1F # 0 +0xBAF1 0xBE44 # 0 +0xBAF2 0xBE45 # 0 +0xBAF3 0xBE48 # 0 +0xBAF4 0xBE4C # 0 +0xBAF5 0xBE4E # 0 +0xBAF6 0xBE54 # 0 +0xBAF7 0xBE55 # 0 +0xBAF8 0xBE57 # 0 +0xBAF9 0xBE59 # 0 +0xBAFA 0xBE5A # 0 +0xBAFB 0xBE5B # 0 +0xBAFC 0xBE60 # 0 +0xBAFD 0xBE61 # 0 +0xBAFE 0xBE64 # 0 +0xBB41 0xD2FB # 0 +0xBB42 0xD2FC # 0 +0xBB43 0xD2FD # 0 +0xBB44 0xD2FE # 0 +0xBB45 0xD2FF # 0 +0xBB46 0xD302 # 0 +0xBB47 0xD304 # 0 +0xBB48 0xD306 # 0 +0xBB49 0xD307 # 0 +0xBB4A 0xD308 # 0 +0xBB4B 0xD309 # 0 +0xBB4C 0xD30A # 0 +0xBB4D 0xD30B # 0 +0xBB4E 0xD30F # 0 +0xBB4F 0xD311 # 0 +0xBB50 0xD312 # 0 +0xBB51 0xD313 # 0 +0xBB52 0xD315 # 0 +0xBB53 0xD317 # 0 +0xBB54 0xD318 # 0 +0xBB55 0xD319 # 0 +0xBB56 0xD31A # 0 +0xBB57 0xD31B # 0 +0xBB58 0xD31E # 0 +0xBB59 0xD322 # 0 +0xBB5A 0xD323 # 0 +0xBB61 0xD324 # 0 +0xBB62 0xD326 # 0 +0xBB63 0xD327 # 0 +0xBB64 0xD32A # 0 +0xBB65 0xD32B # 0 +0xBB66 0xD32D # 0 +0xBB67 0xD32E # 0 +0xBB68 0xD32F # 0 +0xBB69 0xD331 # 0 +0xBB6A 0xD332 # 0 +0xBB6B 0xD333 # 0 +0xBB6C 0xD334 # 0 +0xBB6D 0xD335 # 0 +0xBB6E 0xD336 # 0 +0xBB6F 0xD337 # 0 +0xBB70 0xD33A # 0 +0xBB71 0xD33E # 0 +0xBB72 0xD33F # 0 +0xBB73 0xD340 # 0 +0xBB74 0xD341 # 0 +0xBB75 0xD342 # 0 +0xBB76 0xD343 # 0 +0xBB77 0xD346 # 0 +0xBB78 0xD347 # 0 +0xBB79 0xD348 # 0 +0xBB7A 0xD349 # 0 +0xBB81 0xD34A # 0 +0xBB82 0xD34B # 0 +0xBB83 0xD34C # 0 +0xBB84 0xD34D # 0 +0xBB85 0xD34E # 0 +0xBB86 0xD34F # 0 +0xBB87 0xD350 # 0 +0xBB88 0xD351 # 0 +0xBB89 0xD352 # 0 +0xBB8A 0xD353 # 0 +0xBB8B 0xD354 # 0 +0xBB8C 0xD355 # 0 +0xBB8D 0xD356 # 0 +0xBB8E 0xD357 # 0 +0xBB8F 0xD358 # 0 +0xBB90 0xD359 # 0 +0xBB91 0xD35A # 0 +0xBB92 0xD35B # 0 +0xBB93 0xD35C # 0 +0xBB94 0xD35D # 0 +0xBB95 0xD35E # 0 +0xBB96 0xD35F # 0 +0xBB97 0xD360 # 0 +0xBB98 0xD361 # 0 +0xBB99 0xD362 # 0 +0xBB9A 0xD363 # 0 +0xBB9B 0xD364 # 0 +0xBB9C 0xD365 # 0 +0xBB9D 0xD366 # 0 +0xBB9E 0xD367 # 0 +0xBB9F 0xD368 # 0 +0xBBA0 0xD369 # 0 +0xBBA1 0xBE68 # 0 +0xBBA2 0xBE6A # 0 +0xBBA3 0xBE70 # 0 +0xBBA4 0xBE71 # 0 +0xBBA5 0xBE73 # 0 +0xBBA6 0xBE74 # 0 +0xBBA7 0xBE75 # 0 +0xBBA8 0xBE7B # 0 +0xBBA9 0xBE7C # 0 +0xBBAA 0xBE7D # 0 +0xBBAB 0xBE80 # 0 +0xBBAC 0xBE84 # 0 +0xBBAD 0xBE8C # 0 +0xBBAE 0xBE8D # 0 +0xBBAF 0xBE8F # 0 +0xBBB0 0xBE90 # 0 +0xBBB1 0xBE91 # 0 +0xBBB2 0xBE98 # 0 +0xBBB3 0xBE99 # 0 +0xBBB4 0xBEA8 # 0 +0xBBB5 0xBED0 # 0 +0xBBB6 0xBED1 # 0 +0xBBB7 0xBED4 # 0 +0xBBB8 0xBED7 # 0 +0xBBB9 0xBED8 # 0 +0xBBBA 0xBEE0 # 0 +0xBBBB 0xBEE3 # 0 +0xBBBC 0xBEE4 # 0 +0xBBBD 0xBEE5 # 0 +0xBBBE 0xBEEC # 0 +0xBBBF 0xBF01 # 0 +0xBBC0 0xBF08 # 0 +0xBBC1 0xBF09 # 0 +0xBBC2 0xBF18 # 0 +0xBBC3 0xBF19 # 0 +0xBBC4 0xBF1B # 0 +0xBBC5 0xBF1C # 0 +0xBBC6 0xBF1D # 0 +0xBBC7 0xBF40 # 0 +0xBBC8 0xBF41 # 0 +0xBBC9 0xBF44 # 0 +0xBBCA 0xBF48 # 0 +0xBBCB 0xBF50 # 0 +0xBBCC 0xBF51 # 0 +0xBBCD 0xBF55 # 0 +0xBBCE 0xBF94 # 0 +0xBBCF 0xBFB0 # 0 +0xBBD0 0xBFC5 # 0 +0xBBD1 0xBFCC # 0 +0xBBD2 0xBFCD # 0 +0xBBD3 0xBFD0 # 0 +0xBBD4 0xBFD4 # 0 +0xBBD5 0xBFDC # 0 +0xBBD6 0xBFDF # 0 +0xBBD7 0xBFE1 # 0 +0xBBD8 0xC03C # 0 +0xBBD9 0xC051 # 0 +0xBBDA 0xC058 # 0 +0xBBDB 0xC05C # 0 +0xBBDC 0xC060 # 0 +0xBBDD 0xC068 # 0 +0xBBDE 0xC069 # 0 +0xBBDF 0xC090 # 0 +0xBBE0 0xC091 # 0 +0xBBE1 0xC094 # 0 +0xBBE2 0xC098 # 0 +0xBBE3 0xC0A0 # 0 +0xBBE4 0xC0A1 # 0 +0xBBE5 0xC0A3 # 0 +0xBBE6 0xC0A5 # 0 +0xBBE7 0xC0AC # 0 +0xBBE8 0xC0AD # 0 +0xBBE9 0xC0AF # 0 +0xBBEA 0xC0B0 # 0 +0xBBEB 0xC0B3 # 0 +0xBBEC 0xC0B4 # 0 +0xBBED 0xC0B5 # 0 +0xBBEE 0xC0B6 # 0 +0xBBEF 0xC0BC # 0 +0xBBF0 0xC0BD # 0 +0xBBF1 0xC0BF # 0 +0xBBF2 0xC0C0 # 0 +0xBBF3 0xC0C1 # 0 +0xBBF4 0xC0C5 # 0 +0xBBF5 0xC0C8 # 0 +0xBBF6 0xC0C9 # 0 +0xBBF7 0xC0CC # 0 +0xBBF8 0xC0D0 # 0 +0xBBF9 0xC0D8 # 0 +0xBBFA 0xC0D9 # 0 +0xBBFB 0xC0DB # 0 +0xBBFC 0xC0DC # 0 +0xBBFD 0xC0DD # 0 +0xBBFE 0xC0E4 # 0 +0xBC41 0xD36A # 0 +0xBC42 0xD36B # 0 +0xBC43 0xD36C # 0 +0xBC44 0xD36D # 0 +0xBC45 0xD36E # 0 +0xBC46 0xD36F # 0 +0xBC47 0xD370 # 0 +0xBC48 0xD371 # 0 +0xBC49 0xD372 # 0 +0xBC4A 0xD373 # 0 +0xBC4B 0xD374 # 0 +0xBC4C 0xD375 # 0 +0xBC4D 0xD376 # 0 +0xBC4E 0xD377 # 0 +0xBC4F 0xD378 # 0 +0xBC50 0xD379 # 0 +0xBC51 0xD37A # 0 +0xBC52 0xD37B # 0 +0xBC53 0xD37E # 0 +0xBC54 0xD37F # 0 +0xBC55 0xD381 # 0 +0xBC56 0xD382 # 0 +0xBC57 0xD383 # 0 +0xBC58 0xD385 # 0 +0xBC59 0xD386 # 0 +0xBC5A 0xD387 # 0 +0xBC61 0xD388 # 0 +0xBC62 0xD389 # 0 +0xBC63 0xD38A # 0 +0xBC64 0xD38B # 0 +0xBC65 0xD38E # 0 +0xBC66 0xD392 # 0 +0xBC67 0xD393 # 0 +0xBC68 0xD394 # 0 +0xBC69 0xD395 # 0 +0xBC6A 0xD396 # 0 +0xBC6B 0xD397 # 0 +0xBC6C 0xD39A # 0 +0xBC6D 0xD39B # 0 +0xBC6E 0xD39D # 0 +0xBC6F 0xD39E # 0 +0xBC70 0xD39F # 0 +0xBC71 0xD3A1 # 0 +0xBC72 0xD3A2 # 0 +0xBC73 0xD3A3 # 0 +0xBC74 0xD3A4 # 0 +0xBC75 0xD3A5 # 0 +0xBC76 0xD3A6 # 0 +0xBC77 0xD3A7 # 0 +0xBC78 0xD3AA # 0 +0xBC79 0xD3AC # 0 +0xBC7A 0xD3AE # 0 +0xBC81 0xD3AF # 0 +0xBC82 0xD3B0 # 0 +0xBC83 0xD3B1 # 0 +0xBC84 0xD3B2 # 0 +0xBC85 0xD3B3 # 0 +0xBC86 0xD3B5 # 0 +0xBC87 0xD3B6 # 0 +0xBC88 0xD3B7 # 0 +0xBC89 0xD3B9 # 0 +0xBC8A 0xD3BA # 0 +0xBC8B 0xD3BB # 0 +0xBC8C 0xD3BD # 0 +0xBC8D 0xD3BE # 0 +0xBC8E 0xD3BF # 0 +0xBC8F 0xD3C0 # 0 +0xBC90 0xD3C1 # 0 +0xBC91 0xD3C2 # 0 +0xBC92 0xD3C3 # 0 +0xBC93 0xD3C6 # 0 +0xBC94 0xD3C7 # 0 +0xBC95 0xD3CA # 0 +0xBC96 0xD3CB # 0 +0xBC97 0xD3CC # 0 +0xBC98 0xD3CD # 0 +0xBC99 0xD3CE # 0 +0xBC9A 0xD3CF # 0 +0xBC9B 0xD3D1 # 0 +0xBC9C 0xD3D2 # 0 +0xBC9D 0xD3D3 # 0 +0xBC9E 0xD3D4 # 0 +0xBC9F 0xD3D5 # 0 +0xBCA0 0xD3D6 # 0 +0xBCA1 0xC0E5 # 0 +0xBCA2 0xC0E8 # 0 +0xBCA3 0xC0EC # 0 +0xBCA4 0xC0F4 # 0 +0xBCA5 0xC0F5 # 0 +0xBCA6 0xC0F7 # 0 +0xBCA7 0xC0F9 # 0 +0xBCA8 0xC100 # 0 +0xBCA9 0xC104 # 0 +0xBCAA 0xC108 # 0 +0xBCAB 0xC110 # 0 +0xBCAC 0xC115 # 0 +0xBCAD 0xC11C # 0 +0xBCAE 0xC11D # 0 +0xBCAF 0xC11E # 0 +0xBCB0 0xC11F # 0 +0xBCB1 0xC120 # 0 +0xBCB2 0xC123 # 0 +0xBCB3 0xC124 # 0 +0xBCB4 0xC126 # 0 +0xBCB5 0xC127 # 0 +0xBCB6 0xC12C # 0 +0xBCB7 0xC12D # 0 +0xBCB8 0xC12F # 0 +0xBCB9 0xC130 # 0 +0xBCBA 0xC131 # 0 +0xBCBB 0xC136 # 0 +0xBCBC 0xC138 # 0 +0xBCBD 0xC139 # 0 +0xBCBE 0xC13C # 0 +0xBCBF 0xC140 # 0 +0xBCC0 0xC148 # 0 +0xBCC1 0xC149 # 0 +0xBCC2 0xC14B # 0 +0xBCC3 0xC14C # 0 +0xBCC4 0xC14D # 0 +0xBCC5 0xC154 # 0 +0xBCC6 0xC155 # 0 +0xBCC7 0xC158 # 0 +0xBCC8 0xC15C # 0 +0xBCC9 0xC164 # 0 +0xBCCA 0xC165 # 0 +0xBCCB 0xC167 # 0 +0xBCCC 0xC168 # 0 +0xBCCD 0xC169 # 0 +0xBCCE 0xC170 # 0 +0xBCCF 0xC174 # 0 +0xBCD0 0xC178 # 0 +0xBCD1 0xC185 # 0 +0xBCD2 0xC18C # 0 +0xBCD3 0xC18D # 0 +0xBCD4 0xC18E # 0 +0xBCD5 0xC190 # 0 +0xBCD6 0xC194 # 0 +0xBCD7 0xC196 # 0 +0xBCD8 0xC19C # 0 +0xBCD9 0xC19D # 0 +0xBCDA 0xC19F # 0 +0xBCDB 0xC1A1 # 0 +0xBCDC 0xC1A5 # 0 +0xBCDD 0xC1A8 # 0 +0xBCDE 0xC1A9 # 0 +0xBCDF 0xC1AC # 0 +0xBCE0 0xC1B0 # 0 +0xBCE1 0xC1BD # 0 +0xBCE2 0xC1C4 # 0 +0xBCE3 0xC1C8 # 0 +0xBCE4 0xC1CC # 0 +0xBCE5 0xC1D4 # 0 +0xBCE6 0xC1D7 # 0 +0xBCE7 0xC1D8 # 0 +0xBCE8 0xC1E0 # 0 +0xBCE9 0xC1E4 # 0 +0xBCEA 0xC1E8 # 0 +0xBCEB 0xC1F0 # 0 +0xBCEC 0xC1F1 # 0 +0xBCED 0xC1F3 # 0 +0xBCEE 0xC1FC # 0 +0xBCEF 0xC1FD # 0 +0xBCF0 0xC200 # 0 +0xBCF1 0xC204 # 0 +0xBCF2 0xC20C # 0 +0xBCF3 0xC20D # 0 +0xBCF4 0xC20F # 0 +0xBCF5 0xC211 # 0 +0xBCF6 0xC218 # 0 +0xBCF7 0xC219 # 0 +0xBCF8 0xC21C # 0 +0xBCF9 0xC21F # 0 +0xBCFA 0xC220 # 0 +0xBCFB 0xC228 # 0 +0xBCFC 0xC229 # 0 +0xBCFD 0xC22B # 0 +0xBCFE 0xC22D # 0 +0xBD41 0xD3D7 # 0 +0xBD42 0xD3D9 # 0 +0xBD43 0xD3DA # 0 +0xBD44 0xD3DB # 0 +0xBD45 0xD3DC # 0 +0xBD46 0xD3DD # 0 +0xBD47 0xD3DE # 0 +0xBD48 0xD3DF # 0 +0xBD49 0xD3E0 # 0 +0xBD4A 0xD3E2 # 0 +0xBD4B 0xD3E4 # 0 +0xBD4C 0xD3E5 # 0 +0xBD4D 0xD3E6 # 0 +0xBD4E 0xD3E7 # 0 +0xBD4F 0xD3E8 # 0 +0xBD50 0xD3E9 # 0 +0xBD51 0xD3EA # 0 +0xBD52 0xD3EB # 0 +0xBD53 0xD3EE # 0 +0xBD54 0xD3EF # 0 +0xBD55 0xD3F1 # 0 +0xBD56 0xD3F2 # 0 +0xBD57 0xD3F3 # 0 +0xBD58 0xD3F5 # 0 +0xBD59 0xD3F6 # 0 +0xBD5A 0xD3F7 # 0 +0xBD61 0xD3F8 # 0 +0xBD62 0xD3F9 # 0 +0xBD63 0xD3FA # 0 +0xBD64 0xD3FB # 0 +0xBD65 0xD3FE # 0 +0xBD66 0xD400 # 0 +0xBD67 0xD402 # 0 +0xBD68 0xD403 # 0 +0xBD69 0xD404 # 0 +0xBD6A 0xD405 # 0 +0xBD6B 0xD406 # 0 +0xBD6C 0xD407 # 0 +0xBD6D 0xD409 # 0 +0xBD6E 0xD40A # 0 +0xBD6F 0xD40B # 0 +0xBD70 0xD40C # 0 +0xBD71 0xD40D # 0 +0xBD72 0xD40E # 0 +0xBD73 0xD40F # 0 +0xBD74 0xD410 # 0 +0xBD75 0xD411 # 0 +0xBD76 0xD412 # 0 +0xBD77 0xD413 # 0 +0xBD78 0xD414 # 0 +0xBD79 0xD415 # 0 +0xBD7A 0xD416 # 0 +0xBD81 0xD417 # 0 +0xBD82 0xD418 # 0 +0xBD83 0xD419 # 0 +0xBD84 0xD41A # 0 +0xBD85 0xD41B # 0 +0xBD86 0xD41C # 0 +0xBD87 0xD41E # 0 +0xBD88 0xD41F # 0 +0xBD89 0xD420 # 0 +0xBD8A 0xD421 # 0 +0xBD8B 0xD422 # 0 +0xBD8C 0xD423 # 0 +0xBD8D 0xD424 # 0 +0xBD8E 0xD425 # 0 +0xBD8F 0xD426 # 0 +0xBD90 0xD427 # 0 +0xBD91 0xD428 # 0 +0xBD92 0xD429 # 0 +0xBD93 0xD42A # 0 +0xBD94 0xD42B # 0 +0xBD95 0xD42C # 0 +0xBD96 0xD42D # 0 +0xBD97 0xD42E # 0 +0xBD98 0xD42F # 0 +0xBD99 0xD430 # 0 +0xBD9A 0xD431 # 0 +0xBD9B 0xD432 # 0 +0xBD9C 0xD433 # 0 +0xBD9D 0xD434 # 0 +0xBD9E 0xD435 # 0 +0xBD9F 0xD436 # 0 +0xBDA0 0xD437 # 0 +0xBDA1 0xC22F # 0 +0xBDA2 0xC231 # 0 +0xBDA3 0xC232 # 0 +0xBDA4 0xC234 # 0 +0xBDA5 0xC248 # 0 +0xBDA6 0xC250 # 0 +0xBDA7 0xC251 # 0 +0xBDA8 0xC254 # 0 +0xBDA9 0xC258 # 0 +0xBDAA 0xC260 # 0 +0xBDAB 0xC265 # 0 +0xBDAC 0xC26C # 0 +0xBDAD 0xC26D # 0 +0xBDAE 0xC270 # 0 +0xBDAF 0xC274 # 0 +0xBDB0 0xC27C # 0 +0xBDB1 0xC27D # 0 +0xBDB2 0xC27F # 0 +0xBDB3 0xC281 # 0 +0xBDB4 0xC288 # 0 +0xBDB5 0xC289 # 0 +0xBDB6 0xC290 # 0 +0xBDB7 0xC298 # 0 +0xBDB8 0xC29B # 0 +0xBDB9 0xC29D # 0 +0xBDBA 0xC2A4 # 0 +0xBDBB 0xC2A5 # 0 +0xBDBC 0xC2A8 # 0 +0xBDBD 0xC2AC # 0 +0xBDBE 0xC2AD # 0 +0xBDBF 0xC2B4 # 0 +0xBDC0 0xC2B5 # 0 +0xBDC1 0xC2B7 # 0 +0xBDC2 0xC2B9 # 0 +0xBDC3 0xC2DC # 0 +0xBDC4 0xC2DD # 0 +0xBDC5 0xC2E0 # 0 +0xBDC6 0xC2E3 # 0 +0xBDC7 0xC2E4 # 0 +0xBDC8 0xC2EB # 0 +0xBDC9 0xC2EC # 0 +0xBDCA 0xC2ED # 0 +0xBDCB 0xC2EF # 0 +0xBDCC 0xC2F1 # 0 +0xBDCD 0xC2F6 # 0 +0xBDCE 0xC2F8 # 0 +0xBDCF 0xC2F9 # 0 +0xBDD0 0xC2FB # 0 +0xBDD1 0xC2FC # 0 +0xBDD2 0xC300 # 0 +0xBDD3 0xC308 # 0 +0xBDD4 0xC309 # 0 +0xBDD5 0xC30C # 0 +0xBDD6 0xC30D # 0 +0xBDD7 0xC313 # 0 +0xBDD8 0xC314 # 0 +0xBDD9 0xC315 # 0 +0xBDDA 0xC318 # 0 +0xBDDB 0xC31C # 0 +0xBDDC 0xC324 # 0 +0xBDDD 0xC325 # 0 +0xBDDE 0xC328 # 0 +0xBDDF 0xC329 # 0 +0xBDE0 0xC345 # 0 +0xBDE1 0xC368 # 0 +0xBDE2 0xC369 # 0 +0xBDE3 0xC36C # 0 +0xBDE4 0xC370 # 0 +0xBDE5 0xC372 # 0 +0xBDE6 0xC378 # 0 +0xBDE7 0xC379 # 0 +0xBDE8 0xC37C # 0 +0xBDE9 0xC37D # 0 +0xBDEA 0xC384 # 0 +0xBDEB 0xC388 # 0 +0xBDEC 0xC38C # 0 +0xBDED 0xC3C0 # 0 +0xBDEE 0xC3D8 # 0 +0xBDEF 0xC3D9 # 0 +0xBDF0 0xC3DC # 0 +0xBDF1 0xC3DF # 0 +0xBDF2 0xC3E0 # 0 +0xBDF3 0xC3E2 # 0 +0xBDF4 0xC3E8 # 0 +0xBDF5 0xC3E9 # 0 +0xBDF6 0xC3ED # 0 +0xBDF7 0xC3F4 # 0 +0xBDF8 0xC3F5 # 0 +0xBDF9 0xC3F8 # 0 +0xBDFA 0xC408 # 0 +0xBDFB 0xC410 # 0 +0xBDFC 0xC424 # 0 +0xBDFD 0xC42C # 0 +0xBDFE 0xC430 # 0 +0xBE41 0xD438 # 0 +0xBE42 0xD439 # 0 +0xBE43 0xD43A # 0 +0xBE44 0xD43B # 0 +0xBE45 0xD43C # 0 +0xBE46 0xD43D # 0 +0xBE47 0xD43E # 0 +0xBE48 0xD43F # 0 +0xBE49 0xD441 # 0 +0xBE4A 0xD442 # 0 +0xBE4B 0xD443 # 0 +0xBE4C 0xD445 # 0 +0xBE4D 0xD446 # 0 +0xBE4E 0xD447 # 0 +0xBE4F 0xD448 # 0 +0xBE50 0xD449 # 0 +0xBE51 0xD44A # 0 +0xBE52 0xD44B # 0 +0xBE53 0xD44C # 0 +0xBE54 0xD44D # 0 +0xBE55 0xD44E # 0 +0xBE56 0xD44F # 0 +0xBE57 0xD450 # 0 +0xBE58 0xD451 # 0 +0xBE59 0xD452 # 0 +0xBE5A 0xD453 # 0 +0xBE61 0xD454 # 0 +0xBE62 0xD455 # 0 +0xBE63 0xD456 # 0 +0xBE64 0xD457 # 0 +0xBE65 0xD458 # 0 +0xBE66 0xD459 # 0 +0xBE67 0xD45A # 0 +0xBE68 0xD45B # 0 +0xBE69 0xD45D # 0 +0xBE6A 0xD45E # 0 +0xBE6B 0xD45F # 0 +0xBE6C 0xD461 # 0 +0xBE6D 0xD462 # 0 +0xBE6E 0xD463 # 0 +0xBE6F 0xD465 # 0 +0xBE70 0xD466 # 0 +0xBE71 0xD467 # 0 +0xBE72 0xD468 # 0 +0xBE73 0xD469 # 0 +0xBE74 0xD46A # 0 +0xBE75 0xD46B # 0 +0xBE76 0xD46C # 0 +0xBE77 0xD46E # 0 +0xBE78 0xD470 # 0 +0xBE79 0xD471 # 0 +0xBE7A 0xD472 # 0 +0xBE81 0xD473 # 0 +0xBE82 0xD474 # 0 +0xBE83 0xD475 # 0 +0xBE84 0xD476 # 0 +0xBE85 0xD477 # 0 +0xBE86 0xD47A # 0 +0xBE87 0xD47B # 0 +0xBE88 0xD47D # 0 +0xBE89 0xD47E # 0 +0xBE8A 0xD481 # 0 +0xBE8B 0xD483 # 0 +0xBE8C 0xD484 # 0 +0xBE8D 0xD485 # 0 +0xBE8E 0xD486 # 0 +0xBE8F 0xD487 # 0 +0xBE90 0xD48A # 0 +0xBE91 0xD48C # 0 +0xBE92 0xD48E # 0 +0xBE93 0xD48F # 0 +0xBE94 0xD490 # 0 +0xBE95 0xD491 # 0 +0xBE96 0xD492 # 0 +0xBE97 0xD493 # 0 +0xBE98 0xD495 # 0 +0xBE99 0xD496 # 0 +0xBE9A 0xD497 # 0 +0xBE9B 0xD498 # 0 +0xBE9C 0xD499 # 0 +0xBE9D 0xD49A # 0 +0xBE9E 0xD49B # 0 +0xBE9F 0xD49C # 0 +0xBEA0 0xD49D # 0 +0xBEA1 0xC434 # 0 +0xBEA2 0xC43C # 0 +0xBEA3 0xC43D # 0 +0xBEA4 0xC448 # 0 +0xBEA5 0xC464 # 0 +0xBEA6 0xC465 # 0 +0xBEA7 0xC468 # 0 +0xBEA8 0xC46C # 0 +0xBEA9 0xC474 # 0 +0xBEAA 0xC475 # 0 +0xBEAB 0xC479 # 0 +0xBEAC 0xC480 # 0 +0xBEAD 0xC494 # 0 +0xBEAE 0xC49C # 0 +0xBEAF 0xC4B8 # 0 +0xBEB0 0xC4BC # 0 +0xBEB1 0xC4E9 # 0 +0xBEB2 0xC4F0 # 0 +0xBEB3 0xC4F1 # 0 +0xBEB4 0xC4F4 # 0 +0xBEB5 0xC4F8 # 0 +0xBEB6 0xC4FA # 0 +0xBEB7 0xC4FF # 0 +0xBEB8 0xC500 # 0 +0xBEB9 0xC501 # 0 +0xBEBA 0xC50C # 0 +0xBEBB 0xC510 # 0 +0xBEBC 0xC514 # 0 +0xBEBD 0xC51C # 0 +0xBEBE 0xC528 # 0 +0xBEBF 0xC529 # 0 +0xBEC0 0xC52C # 0 +0xBEC1 0xC530 # 0 +0xBEC2 0xC538 # 0 +0xBEC3 0xC539 # 0 +0xBEC4 0xC53B # 0 +0xBEC5 0xC53D # 0 +0xBEC6 0xC544 # 0 +0xBEC7 0xC545 # 0 +0xBEC8 0xC548 # 0 +0xBEC9 0xC549 # 0 +0xBECA 0xC54A # 0 +0xBECB 0xC54C # 0 +0xBECC 0xC54D # 0 +0xBECD 0xC54E # 0 +0xBECE 0xC553 # 0 +0xBECF 0xC554 # 0 +0xBED0 0xC555 # 0 +0xBED1 0xC557 # 0 +0xBED2 0xC558 # 0 +0xBED3 0xC559 # 0 +0xBED4 0xC55D # 0 +0xBED5 0xC55E # 0 +0xBED6 0xC560 # 0 +0xBED7 0xC561 # 0 +0xBED8 0xC564 # 0 +0xBED9 0xC568 # 0 +0xBEDA 0xC570 # 0 +0xBEDB 0xC571 # 0 +0xBEDC 0xC573 # 0 +0xBEDD 0xC574 # 0 +0xBEDE 0xC575 # 0 +0xBEDF 0xC57C # 0 +0xBEE0 0xC57D # 0 +0xBEE1 0xC580 # 0 +0xBEE2 0xC584 # 0 +0xBEE3 0xC587 # 0 +0xBEE4 0xC58C # 0 +0xBEE5 0xC58D # 0 +0xBEE6 0xC58F # 0 +0xBEE7 0xC591 # 0 +0xBEE8 0xC595 # 0 +0xBEE9 0xC597 # 0 +0xBEEA 0xC598 # 0 +0xBEEB 0xC59C # 0 +0xBEEC 0xC5A0 # 0 +0xBEED 0xC5A9 # 0 +0xBEEE 0xC5B4 # 0 +0xBEEF 0xC5B5 # 0 +0xBEF0 0xC5B8 # 0 +0xBEF1 0xC5B9 # 0 +0xBEF2 0xC5BB # 0 +0xBEF3 0xC5BC # 0 +0xBEF4 0xC5BD # 0 +0xBEF5 0xC5BE # 0 +0xBEF6 0xC5C4 # 0 +0xBEF7 0xC5C5 # 0 +0xBEF8 0xC5C6 # 0 +0xBEF9 0xC5C7 # 0 +0xBEFA 0xC5C8 # 0 +0xBEFB 0xC5C9 # 0 +0xBEFC 0xC5CA # 0 +0xBEFD 0xC5CC # 0 +0xBEFE 0xC5CE # 0 +0xBF41 0xD49E # 0 +0xBF42 0xD49F # 0 +0xBF43 0xD4A0 # 0 +0xBF44 0xD4A1 # 0 +0xBF45 0xD4A2 # 0 +0xBF46 0xD4A3 # 0 +0xBF47 0xD4A4 # 0 +0xBF48 0xD4A5 # 0 +0xBF49 0xD4A6 # 0 +0xBF4A 0xD4A7 # 0 +0xBF4B 0xD4A8 # 0 +0xBF4C 0xD4AA # 0 +0xBF4D 0xD4AB # 0 +0xBF4E 0xD4AC # 0 +0xBF4F 0xD4AD # 0 +0xBF50 0xD4AE # 0 +0xBF51 0xD4AF # 0 +0xBF52 0xD4B0 # 0 +0xBF53 0xD4B1 # 0 +0xBF54 0xD4B2 # 0 +0xBF55 0xD4B3 # 0 +0xBF56 0xD4B4 # 0 +0xBF57 0xD4B5 # 0 +0xBF58 0xD4B6 # 0 +0xBF59 0xD4B7 # 0 +0xBF5A 0xD4B8 # 0 +0xBF61 0xD4B9 # 0 +0xBF62 0xD4BA # 0 +0xBF63 0xD4BB # 0 +0xBF64 0xD4BC # 0 +0xBF65 0xD4BD # 0 +0xBF66 0xD4BE # 0 +0xBF67 0xD4BF # 0 +0xBF68 0xD4C0 # 0 +0xBF69 0xD4C1 # 0 +0xBF6A 0xD4C2 # 0 +0xBF6B 0xD4C3 # 0 +0xBF6C 0xD4C4 # 0 +0xBF6D 0xD4C5 # 0 +0xBF6E 0xD4C6 # 0 +0xBF6F 0xD4C7 # 0 +0xBF70 0xD4C8 # 0 +0xBF71 0xD4C9 # 0 +0xBF72 0xD4CA # 0 +0xBF73 0xD4CB # 0 +0xBF74 0xD4CD # 0 +0xBF75 0xD4CE # 0 +0xBF76 0xD4CF # 0 +0xBF77 0xD4D1 # 0 +0xBF78 0xD4D2 # 0 +0xBF79 0xD4D3 # 0 +0xBF7A 0xD4D5 # 0 +0xBF81 0xD4D6 # 0 +0xBF82 0xD4D7 # 0 +0xBF83 0xD4D8 # 0 +0xBF84 0xD4D9 # 0 +0xBF85 0xD4DA # 0 +0xBF86 0xD4DB # 0 +0xBF87 0xD4DD # 0 +0xBF88 0xD4DE # 0 +0xBF89 0xD4E0 # 0 +0xBF8A 0xD4E1 # 0 +0xBF8B 0xD4E2 # 0 +0xBF8C 0xD4E3 # 0 +0xBF8D 0xD4E4 # 0 +0xBF8E 0xD4E5 # 0 +0xBF8F 0xD4E6 # 0 +0xBF90 0xD4E7 # 0 +0xBF91 0xD4E9 # 0 +0xBF92 0xD4EA # 0 +0xBF93 0xD4EB # 0 +0xBF94 0xD4ED # 0 +0xBF95 0xD4EE # 0 +0xBF96 0xD4EF # 0 +0xBF97 0xD4F1 # 0 +0xBF98 0xD4F2 # 0 +0xBF99 0xD4F3 # 0 +0xBF9A 0xD4F4 # 0 +0xBF9B 0xD4F5 # 0 +0xBF9C 0xD4F6 # 0 +0xBF9D 0xD4F7 # 0 +0xBF9E 0xD4F9 # 0 +0xBF9F 0xD4FA # 0 +0xBFA0 0xD4FC # 0 +0xBFA1 0xC5D0 # 0 +0xBFA2 0xC5D1 # 0 +0xBFA3 0xC5D4 # 0 +0xBFA4 0xC5D8 # 0 +0xBFA5 0xC5E0 # 0 +0xBFA6 0xC5E1 # 0 +0xBFA7 0xC5E3 # 0 +0xBFA8 0xC5E5 # 0 +0xBFA9 0xC5EC # 0 +0xBFAA 0xC5ED # 0 +0xBFAB 0xC5EE # 0 +0xBFAC 0xC5F0 # 0 +0xBFAD 0xC5F4 # 0 +0xBFAE 0xC5F6 # 0 +0xBFAF 0xC5F7 # 0 +0xBFB0 0xC5FC # 0 +0xBFB1 0xC5FD # 0 +0xBFB2 0xC5FE # 0 +0xBFB3 0xC5FF # 0 +0xBFB4 0xC600 # 0 +0xBFB5 0xC601 # 0 +0xBFB6 0xC605 # 0 +0xBFB7 0xC606 # 0 +0xBFB8 0xC607 # 0 +0xBFB9 0xC608 # 0 +0xBFBA 0xC60C # 0 +0xBFBB 0xC610 # 0 +0xBFBC 0xC618 # 0 +0xBFBD 0xC619 # 0 +0xBFBE 0xC61B # 0 +0xBFBF 0xC61C # 0 +0xBFC0 0xC624 # 0 +0xBFC1 0xC625 # 0 +0xBFC2 0xC628 # 0 +0xBFC3 0xC62C # 0 +0xBFC4 0xC62D # 0 +0xBFC5 0xC62E # 0 +0xBFC6 0xC630 # 0 +0xBFC7 0xC633 # 0 +0xBFC8 0xC634 # 0 +0xBFC9 0xC635 # 0 +0xBFCA 0xC637 # 0 +0xBFCB 0xC639 # 0 +0xBFCC 0xC63B # 0 +0xBFCD 0xC640 # 0 +0xBFCE 0xC641 # 0 +0xBFCF 0xC644 # 0 +0xBFD0 0xC648 # 0 +0xBFD1 0xC650 # 0 +0xBFD2 0xC651 # 0 +0xBFD3 0xC653 # 0 +0xBFD4 0xC654 # 0 +0xBFD5 0xC655 # 0 +0xBFD6 0xC65C # 0 +0xBFD7 0xC65D # 0 +0xBFD8 0xC660 # 0 +0xBFD9 0xC66C # 0 +0xBFDA 0xC66F # 0 +0xBFDB 0xC671 # 0 +0xBFDC 0xC678 # 0 +0xBFDD 0xC679 # 0 +0xBFDE 0xC67C # 0 +0xBFDF 0xC680 # 0 +0xBFE0 0xC688 # 0 +0xBFE1 0xC689 # 0 +0xBFE2 0xC68B # 0 +0xBFE3 0xC68D # 0 +0xBFE4 0xC694 # 0 +0xBFE5 0xC695 # 0 +0xBFE6 0xC698 # 0 +0xBFE7 0xC69C # 0 +0xBFE8 0xC6A4 # 0 +0xBFE9 0xC6A5 # 0 +0xBFEA 0xC6A7 # 0 +0xBFEB 0xC6A9 # 0 +0xBFEC 0xC6B0 # 0 +0xBFED 0xC6B1 # 0 +0xBFEE 0xC6B4 # 0 +0xBFEF 0xC6B8 # 0 +0xBFF0 0xC6B9 # 0 +0xBFF1 0xC6BA # 0 +0xBFF2 0xC6C0 # 0 +0xBFF3 0xC6C1 # 0 +0xBFF4 0xC6C3 # 0 +0xBFF5 0xC6C5 # 0 +0xBFF6 0xC6CC # 0 +0xBFF7 0xC6CD # 0 +0xBFF8 0xC6D0 # 0 +0xBFF9 0xC6D4 # 0 +0xBFFA 0xC6DC # 0 +0xBFFB 0xC6DD # 0 +0xBFFC 0xC6E0 # 0 +0xBFFD 0xC6E1 # 0 +0xBFFE 0xC6E8 # 0 +0xC041 0xD4FE # 0 +0xC042 0xD4FF # 0 +0xC043 0xD500 # 0 +0xC044 0xD501 # 0 +0xC045 0xD502 # 0 +0xC046 0xD503 # 0 +0xC047 0xD505 # 0 +0xC048 0xD506 # 0 +0xC049 0xD507 # 0 +0xC04A 0xD509 # 0 +0xC04B 0xD50A # 0 +0xC04C 0xD50B # 0 +0xC04D 0xD50D # 0 +0xC04E 0xD50E # 0 +0xC04F 0xD50F # 0 +0xC050 0xD510 # 0 +0xC051 0xD511 # 0 +0xC052 0xD512 # 0 +0xC053 0xD513 # 0 +0xC054 0xD516 # 0 +0xC055 0xD518 # 0 +0xC056 0xD519 # 0 +0xC057 0xD51A # 0 +0xC058 0xD51B # 0 +0xC059 0xD51C # 0 +0xC05A 0xD51D # 0 +0xC061 0xD51E # 0 +0xC062 0xD51F # 0 +0xC063 0xD520 # 0 +0xC064 0xD521 # 0 +0xC065 0xD522 # 0 +0xC066 0xD523 # 0 +0xC067 0xD524 # 0 +0xC068 0xD525 # 0 +0xC069 0xD526 # 0 +0xC06A 0xD527 # 0 +0xC06B 0xD528 # 0 +0xC06C 0xD529 # 0 +0xC06D 0xD52A # 0 +0xC06E 0xD52B # 0 +0xC06F 0xD52C # 0 +0xC070 0xD52D # 0 +0xC071 0xD52E # 0 +0xC072 0xD52F # 0 +0xC073 0xD530 # 0 +0xC074 0xD531 # 0 +0xC075 0xD532 # 0 +0xC076 0xD533 # 0 +0xC077 0xD534 # 0 +0xC078 0xD535 # 0 +0xC079 0xD536 # 0 +0xC07A 0xD537 # 0 +0xC081 0xD538 # 0 +0xC082 0xD539 # 0 +0xC083 0xD53A # 0 +0xC084 0xD53B # 0 +0xC085 0xD53E # 0 +0xC086 0xD53F # 0 +0xC087 0xD541 # 0 +0xC088 0xD542 # 0 +0xC089 0xD543 # 0 +0xC08A 0xD545 # 0 +0xC08B 0xD546 # 0 +0xC08C 0xD547 # 0 +0xC08D 0xD548 # 0 +0xC08E 0xD549 # 0 +0xC08F 0xD54A # 0 +0xC090 0xD54B # 0 +0xC091 0xD54E # 0 +0xC092 0xD550 # 0 +0xC093 0xD552 # 0 +0xC094 0xD553 # 0 +0xC095 0xD554 # 0 +0xC096 0xD555 # 0 +0xC097 0xD556 # 0 +0xC098 0xD557 # 0 +0xC099 0xD55A # 0 +0xC09A 0xD55B # 0 +0xC09B 0xD55D # 0 +0xC09C 0xD55E # 0 +0xC09D 0xD55F # 0 +0xC09E 0xD561 # 0 +0xC09F 0xD562 # 0 +0xC0A0 0xD563 # 0 +0xC0A1 0xC6E9 # 0 +0xC0A2 0xC6EC # 0 +0xC0A3 0xC6F0 # 0 +0xC0A4 0xC6F8 # 0 +0xC0A5 0xC6F9 # 0 +0xC0A6 0xC6FD # 0 +0xC0A7 0xC704 # 0 +0xC0A8 0xC705 # 0 +0xC0A9 0xC708 # 0 +0xC0AA 0xC70C # 0 +0xC0AB 0xC714 # 0 +0xC0AC 0xC715 # 0 +0xC0AD 0xC717 # 0 +0xC0AE 0xC719 # 0 +0xC0AF 0xC720 # 0 +0xC0B0 0xC721 # 0 +0xC0B1 0xC724 # 0 +0xC0B2 0xC728 # 0 +0xC0B3 0xC730 # 0 +0xC0B4 0xC731 # 0 +0xC0B5 0xC733 # 0 +0xC0B6 0xC735 # 0 +0xC0B7 0xC737 # 0 +0xC0B8 0xC73C # 0 +0xC0B9 0xC73D # 0 +0xC0BA 0xC740 # 0 +0xC0BB 0xC744 # 0 +0xC0BC 0xC74A # 0 +0xC0BD 0xC74C # 0 +0xC0BE 0xC74D # 0 +0xC0BF 0xC74F # 0 +0xC0C0 0xC751 # 0 +0xC0C1 0xC752 # 0 +0xC0C2 0xC753 # 0 +0xC0C3 0xC754 # 0 +0xC0C4 0xC755 # 0 +0xC0C5 0xC756 # 0 +0xC0C6 0xC757 # 0 +0xC0C7 0xC758 # 0 +0xC0C8 0xC75C # 0 +0xC0C9 0xC760 # 0 +0xC0CA 0xC768 # 0 +0xC0CB 0xC76B # 0 +0xC0CC 0xC774 # 0 +0xC0CD 0xC775 # 0 +0xC0CE 0xC778 # 0 +0xC0CF 0xC77C # 0 +0xC0D0 0xC77D # 0 +0xC0D1 0xC77E # 0 +0xC0D2 0xC783 # 0 +0xC0D3 0xC784 # 0 +0xC0D4 0xC785 # 0 +0xC0D5 0xC787 # 0 +0xC0D6 0xC788 # 0 +0xC0D7 0xC789 # 0 +0xC0D8 0xC78A # 0 +0xC0D9 0xC78E # 0 +0xC0DA 0xC790 # 0 +0xC0DB 0xC791 # 0 +0xC0DC 0xC794 # 0 +0xC0DD 0xC796 # 0 +0xC0DE 0xC797 # 0 +0xC0DF 0xC798 # 0 +0xC0E0 0xC79A # 0 +0xC0E1 0xC7A0 # 0 +0xC0E2 0xC7A1 # 0 +0xC0E3 0xC7A3 # 0 +0xC0E4 0xC7A4 # 0 +0xC0E5 0xC7A5 # 0 +0xC0E6 0xC7A6 # 0 +0xC0E7 0xC7AC # 0 +0xC0E8 0xC7AD # 0 +0xC0E9 0xC7B0 # 0 +0xC0EA 0xC7B4 # 0 +0xC0EB 0xC7BC # 0 +0xC0EC 0xC7BD # 0 +0xC0ED 0xC7BF # 0 +0xC0EE 0xC7C0 # 0 +0xC0EF 0xC7C1 # 0 +0xC0F0 0xC7C8 # 0 +0xC0F1 0xC7C9 # 0 +0xC0F2 0xC7CC # 0 +0xC0F3 0xC7CE # 0 +0xC0F4 0xC7D0 # 0 +0xC0F5 0xC7D8 # 0 +0xC0F6 0xC7DD # 0 +0xC0F7 0xC7E4 # 0 +0xC0F8 0xC7E8 # 0 +0xC0F9 0xC7EC # 0 +0xC0FA 0xC800 # 0 +0xC0FB 0xC801 # 0 +0xC0FC 0xC804 # 0 +0xC0FD 0xC808 # 0 +0xC0FE 0xC80A # 0 +0xC141 0xD564 # 0 +0xC142 0xD566 # 0 +0xC143 0xD567 # 0 +0xC144 0xD56A # 0 +0xC145 0xD56C # 0 +0xC146 0xD56E # 0 +0xC147 0xD56F # 0 +0xC148 0xD570 # 0 +0xC149 0xD571 # 0 +0xC14A 0xD572 # 0 +0xC14B 0xD573 # 0 +0xC14C 0xD576 # 0 +0xC14D 0xD577 # 0 +0xC14E 0xD579 # 0 +0xC14F 0xD57A # 0 +0xC150 0xD57B # 0 +0xC151 0xD57D # 0 +0xC152 0xD57E # 0 +0xC153 0xD57F # 0 +0xC154 0xD580 # 0 +0xC155 0xD581 # 0 +0xC156 0xD582 # 0 +0xC157 0xD583 # 0 +0xC158 0xD586 # 0 +0xC159 0xD58A # 0 +0xC15A 0xD58B # 0 +0xC161 0xD58C # 0 +0xC162 0xD58D # 0 +0xC163 0xD58E # 0 +0xC164 0xD58F # 0 +0xC165 0xD591 # 0 +0xC166 0xD592 # 0 +0xC167 0xD593 # 0 +0xC168 0xD594 # 0 +0xC169 0xD595 # 0 +0xC16A 0xD596 # 0 +0xC16B 0xD597 # 0 +0xC16C 0xD598 # 0 +0xC16D 0xD599 # 0 +0xC16E 0xD59A # 0 +0xC16F 0xD59B # 0 +0xC170 0xD59C # 0 +0xC171 0xD59D # 0 +0xC172 0xD59E # 0 +0xC173 0xD59F # 0 +0xC174 0xD5A0 # 0 +0xC175 0xD5A1 # 0 +0xC176 0xD5A2 # 0 +0xC177 0xD5A3 # 0 +0xC178 0xD5A4 # 0 +0xC179 0xD5A6 # 0 +0xC17A 0xD5A7 # 0 +0xC181 0xD5A8 # 0 +0xC182 0xD5A9 # 0 +0xC183 0xD5AA # 0 +0xC184 0xD5AB # 0 +0xC185 0xD5AC # 0 +0xC186 0xD5AD # 0 +0xC187 0xD5AE # 0 +0xC188 0xD5AF # 0 +0xC189 0xD5B0 # 0 +0xC18A 0xD5B1 # 0 +0xC18B 0xD5B2 # 0 +0xC18C 0xD5B3 # 0 +0xC18D 0xD5B4 # 0 +0xC18E 0xD5B5 # 0 +0xC18F 0xD5B6 # 0 +0xC190 0xD5B7 # 0 +0xC191 0xD5B8 # 0 +0xC192 0xD5B9 # 0 +0xC193 0xD5BA # 0 +0xC194 0xD5BB # 0 +0xC195 0xD5BC # 0 +0xC196 0xD5BD # 0 +0xC197 0xD5BE # 0 +0xC198 0xD5BF # 0 +0xC199 0xD5C0 # 0 +0xC19A 0xD5C1 # 0 +0xC19B 0xD5C2 # 0 +0xC19C 0xD5C3 # 0 +0xC19D 0xD5C4 # 0 +0xC19E 0xD5C5 # 0 +0xC19F 0xD5C6 # 0 +0xC1A0 0xD5C7 # 0 +0xC1A1 0xC810 # 0 +0xC1A2 0xC811 # 0 +0xC1A3 0xC813 # 0 +0xC1A4 0xC815 # 0 +0xC1A5 0xC816 # 0 +0xC1A6 0xC81C # 0 +0xC1A7 0xC81D # 0 +0xC1A8 0xC820 # 0 +0xC1A9 0xC824 # 0 +0xC1AA 0xC82C # 0 +0xC1AB 0xC82D # 0 +0xC1AC 0xC82F # 0 +0xC1AD 0xC831 # 0 +0xC1AE 0xC838 # 0 +0xC1AF 0xC83C # 0 +0xC1B0 0xC840 # 0 +0xC1B1 0xC848 # 0 +0xC1B2 0xC849 # 0 +0xC1B3 0xC84C # 0 +0xC1B4 0xC84D # 0 +0xC1B5 0xC854 # 0 +0xC1B6 0xC870 # 0 +0xC1B7 0xC871 # 0 +0xC1B8 0xC874 # 0 +0xC1B9 0xC878 # 0 +0xC1BA 0xC87A # 0 +0xC1BB 0xC880 # 0 +0xC1BC 0xC881 # 0 +0xC1BD 0xC883 # 0 +0xC1BE 0xC885 # 0 +0xC1BF 0xC886 # 0 +0xC1C0 0xC887 # 0 +0xC1C1 0xC88B # 0 +0xC1C2 0xC88C # 0 +0xC1C3 0xC88D # 0 +0xC1C4 0xC894 # 0 +0xC1C5 0xC89D # 0 +0xC1C6 0xC89F # 0 +0xC1C7 0xC8A1 # 0 +0xC1C8 0xC8A8 # 0 +0xC1C9 0xC8BC # 0 +0xC1CA 0xC8BD # 0 +0xC1CB 0xC8C4 # 0 +0xC1CC 0xC8C8 # 0 +0xC1CD 0xC8CC # 0 +0xC1CE 0xC8D4 # 0 +0xC1CF 0xC8D5 # 0 +0xC1D0 0xC8D7 # 0 +0xC1D1 0xC8D9 # 0 +0xC1D2 0xC8E0 # 0 +0xC1D3 0xC8E1 # 0 +0xC1D4 0xC8E4 # 0 +0xC1D5 0xC8F5 # 0 +0xC1D6 0xC8FC # 0 +0xC1D7 0xC8FD # 0 +0xC1D8 0xC900 # 0 +0xC1D9 0xC904 # 0 +0xC1DA 0xC905 # 0 +0xC1DB 0xC906 # 0 +0xC1DC 0xC90C # 0 +0xC1DD 0xC90D # 0 +0xC1DE 0xC90F # 0 +0xC1DF 0xC911 # 0 +0xC1E0 0xC918 # 0 +0xC1E1 0xC92C # 0 +0xC1E2 0xC934 # 0 +0xC1E3 0xC950 # 0 +0xC1E4 0xC951 # 0 +0xC1E5 0xC954 # 0 +0xC1E6 0xC958 # 0 +0xC1E7 0xC960 # 0 +0xC1E8 0xC961 # 0 +0xC1E9 0xC963 # 0 +0xC1EA 0xC96C # 0 +0xC1EB 0xC970 # 0 +0xC1EC 0xC974 # 0 +0xC1ED 0xC97C # 0 +0xC1EE 0xC988 # 0 +0xC1EF 0xC989 # 0 +0xC1F0 0xC98C # 0 +0xC1F1 0xC990 # 0 +0xC1F2 0xC998 # 0 +0xC1F3 0xC999 # 0 +0xC1F4 0xC99B # 0 +0xC1F5 0xC99D # 0 +0xC1F6 0xC9C0 # 0 +0xC1F7 0xC9C1 # 0 +0xC1F8 0xC9C4 # 0 +0xC1F9 0xC9C7 # 0 +0xC1FA 0xC9C8 # 0 +0xC1FB 0xC9CA # 0 +0xC1FC 0xC9D0 # 0 +0xC1FD 0xC9D1 # 0 +0xC1FE 0xC9D3 # 0 +0xC241 0xD5CA # 0 +0xC242 0xD5CB # 0 +0xC243 0xD5CD # 0 +0xC244 0xD5CE # 0 +0xC245 0xD5CF # 0 +0xC246 0xD5D1 # 0 +0xC247 0xD5D3 # 0 +0xC248 0xD5D4 # 0 +0xC249 0xD5D5 # 0 +0xC24A 0xD5D6 # 0 +0xC24B 0xD5D7 # 0 +0xC24C 0xD5DA # 0 +0xC24D 0xD5DC # 0 +0xC24E 0xD5DE # 0 +0xC24F 0xD5DF # 0 +0xC250 0xD5E0 # 0 +0xC251 0xD5E1 # 0 +0xC252 0xD5E2 # 0 +0xC253 0xD5E3 # 0 +0xC254 0xD5E6 # 0 +0xC255 0xD5E7 # 0 +0xC256 0xD5E9 # 0 +0xC257 0xD5EA # 0 +0xC258 0xD5EB # 0 +0xC259 0xD5ED # 0 +0xC25A 0xD5EE # 0 +0xC261 0xD5EF # 0 +0xC262 0xD5F0 # 0 +0xC263 0xD5F1 # 0 +0xC264 0xD5F2 # 0 +0xC265 0xD5F3 # 0 +0xC266 0xD5F6 # 0 +0xC267 0xD5F8 # 0 +0xC268 0xD5FA # 0 +0xC269 0xD5FB # 0 +0xC26A 0xD5FC # 0 +0xC26B 0xD5FD # 0 +0xC26C 0xD5FE # 0 +0xC26D 0xD5FF # 0 +0xC26E 0xD602 # 0 +0xC26F 0xD603 # 0 +0xC270 0xD605 # 0 +0xC271 0xD606 # 0 +0xC272 0xD607 # 0 +0xC273 0xD609 # 0 +0xC274 0xD60A # 0 +0xC275 0xD60B # 0 +0xC276 0xD60C # 0 +0xC277 0xD60D # 0 +0xC278 0xD60E # 0 +0xC279 0xD60F # 0 +0xC27A 0xD612 # 0 +0xC281 0xD616 # 0 +0xC282 0xD617 # 0 +0xC283 0xD618 # 0 +0xC284 0xD619 # 0 +0xC285 0xD61A # 0 +0xC286 0xD61B # 0 +0xC287 0xD61D # 0 +0xC288 0xD61E # 0 +0xC289 0xD61F # 0 +0xC28A 0xD621 # 0 +0xC28B 0xD622 # 0 +0xC28C 0xD623 # 0 +0xC28D 0xD625 # 0 +0xC28E 0xD626 # 0 +0xC28F 0xD627 # 0 +0xC290 0xD628 # 0 +0xC291 0xD629 # 0 +0xC292 0xD62A # 0 +0xC293 0xD62B # 0 +0xC294 0xD62C # 0 +0xC295 0xD62E # 0 +0xC296 0xD62F # 0 +0xC297 0xD630 # 0 +0xC298 0xD631 # 0 +0xC299 0xD632 # 0 +0xC29A 0xD633 # 0 +0xC29B 0xD634 # 0 +0xC29C 0xD635 # 0 +0xC29D 0xD636 # 0 +0xC29E 0xD637 # 0 +0xC29F 0xD63A # 0 +0xC2A0 0xD63B # 0 +0xC2A1 0xC9D5 # 0 +0xC2A2 0xC9D6 # 0 +0xC2A3 0xC9D9 # 0 +0xC2A4 0xC9DA # 0 +0xC2A5 0xC9DC # 0 +0xC2A6 0xC9DD # 0 +0xC2A7 0xC9E0 # 0 +0xC2A8 0xC9E2 # 0 +0xC2A9 0xC9E4 # 0 +0xC2AA 0xC9E7 # 0 +0xC2AB 0xC9EC # 0 +0xC2AC 0xC9ED # 0 +0xC2AD 0xC9EF # 0 +0xC2AE 0xC9F0 # 0 +0xC2AF 0xC9F1 # 0 +0xC2B0 0xC9F8 # 0 +0xC2B1 0xC9F9 # 0 +0xC2B2 0xC9FC # 0 +0xC2B3 0xCA00 # 0 +0xC2B4 0xCA08 # 0 +0xC2B5 0xCA09 # 0 +0xC2B6 0xCA0B # 0 +0xC2B7 0xCA0C # 0 +0xC2B8 0xCA0D # 0 +0xC2B9 0xCA14 # 0 +0xC2BA 0xCA18 # 0 +0xC2BB 0xCA29 # 0 +0xC2BC 0xCA4C # 0 +0xC2BD 0xCA4D # 0 +0xC2BE 0xCA50 # 0 +0xC2BF 0xCA54 # 0 +0xC2C0 0xCA5C # 0 +0xC2C1 0xCA5D # 0 +0xC2C2 0xCA5F # 0 +0xC2C3 0xCA60 # 0 +0xC2C4 0xCA61 # 0 +0xC2C5 0xCA68 # 0 +0xC2C6 0xCA7D # 0 +0xC2C7 0xCA84 # 0 +0xC2C8 0xCA98 # 0 +0xC2C9 0xCABC # 0 +0xC2CA 0xCABD # 0 +0xC2CB 0xCAC0 # 0 +0xC2CC 0xCAC4 # 0 +0xC2CD 0xCACC # 0 +0xC2CE 0xCACD # 0 +0xC2CF 0xCACF # 0 +0xC2D0 0xCAD1 # 0 +0xC2D1 0xCAD3 # 0 +0xC2D2 0xCAD8 # 0 +0xC2D3 0xCAD9 # 0 +0xC2D4 0xCAE0 # 0 +0xC2D5 0xCAEC # 0 +0xC2D6 0xCAF4 # 0 +0xC2D7 0xCB08 # 0 +0xC2D8 0xCB10 # 0 +0xC2D9 0xCB14 # 0 +0xC2DA 0xCB18 # 0 +0xC2DB 0xCB20 # 0 +0xC2DC 0xCB21 # 0 +0xC2DD 0xCB41 # 0 +0xC2DE 0xCB48 # 0 +0xC2DF 0xCB49 # 0 +0xC2E0 0xCB4C # 0 +0xC2E1 0xCB50 # 0 +0xC2E2 0xCB58 # 0 +0xC2E3 0xCB59 # 0 +0xC2E4 0xCB5D # 0 +0xC2E5 0xCB64 # 0 +0xC2E6 0xCB78 # 0 +0xC2E7 0xCB79 # 0 +0xC2E8 0xCB9C # 0 +0xC2E9 0xCBB8 # 0 +0xC2EA 0xCBD4 # 0 +0xC2EB 0xCBE4 # 0 +0xC2EC 0xCBE7 # 0 +0xC2ED 0xCBE9 # 0 +0xC2EE 0xCC0C # 0 +0xC2EF 0xCC0D # 0 +0xC2F0 0xCC10 # 0 +0xC2F1 0xCC14 # 0 +0xC2F2 0xCC1C # 0 +0xC2F3 0xCC1D # 0 +0xC2F4 0xCC21 # 0 +0xC2F5 0xCC22 # 0 +0xC2F6 0xCC27 # 0 +0xC2F7 0xCC28 # 0 +0xC2F8 0xCC29 # 0 +0xC2F9 0xCC2C # 0 +0xC2FA 0xCC2E # 0 +0xC2FB 0xCC30 # 0 +0xC2FC 0xCC38 # 0 +0xC2FD 0xCC39 # 0 +0xC2FE 0xCC3B # 0 +0xC341 0xD63D # 0 +0xC342 0xD63E # 0 +0xC343 0xD63F # 0 +0xC344 0xD641 # 0 +0xC345 0xD642 # 0 +0xC346 0xD643 # 0 +0xC347 0xD644 # 0 +0xC348 0xD646 # 0 +0xC349 0xD647 # 0 +0xC34A 0xD64A # 0 +0xC34B 0xD64C # 0 +0xC34C 0xD64E # 0 +0xC34D 0xD64F # 0 +0xC34E 0xD650 # 0 +0xC34F 0xD652 # 0 +0xC350 0xD653 # 0 +0xC351 0xD656 # 0 +0xC352 0xD657 # 0 +0xC353 0xD659 # 0 +0xC354 0xD65A # 0 +0xC355 0xD65B # 0 +0xC356 0xD65D # 0 +0xC357 0xD65E # 0 +0xC358 0xD65F # 0 +0xC359 0xD660 # 0 +0xC35A 0xD661 # 0 +0xC361 0xD662 # 0 +0xC362 0xD663 # 0 +0xC363 0xD664 # 0 +0xC364 0xD665 # 0 +0xC365 0xD666 # 0 +0xC366 0xD668 # 0 +0xC367 0xD66A # 0 +0xC368 0xD66B # 0 +0xC369 0xD66C # 0 +0xC36A 0xD66D # 0 +0xC36B 0xD66E # 0 +0xC36C 0xD66F # 0 +0xC36D 0xD672 # 0 +0xC36E 0xD673 # 0 +0xC36F 0xD675 # 0 +0xC370 0xD676 # 0 +0xC371 0xD677 # 0 +0xC372 0xD678 # 0 +0xC373 0xD679 # 0 +0xC374 0xD67A # 0 +0xC375 0xD67B # 0 +0xC376 0xD67C # 0 +0xC377 0xD67D # 0 +0xC378 0xD67E # 0 +0xC379 0xD67F # 0 +0xC37A 0xD680 # 0 +0xC381 0xD681 # 0 +0xC382 0xD682 # 0 +0xC383 0xD684 # 0 +0xC384 0xD686 # 0 +0xC385 0xD687 # 0 +0xC386 0xD688 # 0 +0xC387 0xD689 # 0 +0xC388 0xD68A # 0 +0xC389 0xD68B # 0 +0xC38A 0xD68E # 0 +0xC38B 0xD68F # 0 +0xC38C 0xD691 # 0 +0xC38D 0xD692 # 0 +0xC38E 0xD693 # 0 +0xC38F 0xD695 # 0 +0xC390 0xD696 # 0 +0xC391 0xD697 # 0 +0xC392 0xD698 # 0 +0xC393 0xD699 # 0 +0xC394 0xD69A # 0 +0xC395 0xD69B # 0 +0xC396 0xD69C # 0 +0xC397 0xD69E # 0 +0xC398 0xD6A0 # 0 +0xC399 0xD6A2 # 0 +0xC39A 0xD6A3 # 0 +0xC39B 0xD6A4 # 0 +0xC39C 0xD6A5 # 0 +0xC39D 0xD6A6 # 0 +0xC39E 0xD6A7 # 0 +0xC39F 0xD6A9 # 0 +0xC3A0 0xD6AA # 0 +0xC3A1 0xCC3C # 0 +0xC3A2 0xCC3D # 0 +0xC3A3 0xCC3E # 0 +0xC3A4 0xCC44 # 0 +0xC3A5 0xCC45 # 0 +0xC3A6 0xCC48 # 0 +0xC3A7 0xCC4C # 0 +0xC3A8 0xCC54 # 0 +0xC3A9 0xCC55 # 0 +0xC3AA 0xCC57 # 0 +0xC3AB 0xCC58 # 0 +0xC3AC 0xCC59 # 0 +0xC3AD 0xCC60 # 0 +0xC3AE 0xCC64 # 0 +0xC3AF 0xCC66 # 0 +0xC3B0 0xCC68 # 0 +0xC3B1 0xCC70 # 0 +0xC3B2 0xCC75 # 0 +0xC3B3 0xCC98 # 0 +0xC3B4 0xCC99 # 0 +0xC3B5 0xCC9C # 0 +0xC3B6 0xCCA0 # 0 +0xC3B7 0xCCA8 # 0 +0xC3B8 0xCCA9 # 0 +0xC3B9 0xCCAB # 0 +0xC3BA 0xCCAC # 0 +0xC3BB 0xCCAD # 0 +0xC3BC 0xCCB4 # 0 +0xC3BD 0xCCB5 # 0 +0xC3BE 0xCCB8 # 0 +0xC3BF 0xCCBC # 0 +0xC3C0 0xCCC4 # 0 +0xC3C1 0xCCC5 # 0 +0xC3C2 0xCCC7 # 0 +0xC3C3 0xCCC9 # 0 +0xC3C4 0xCCD0 # 0 +0xC3C5 0xCCD4 # 0 +0xC3C6 0xCCE4 # 0 +0xC3C7 0xCCEC # 0 +0xC3C8 0xCCF0 # 0 +0xC3C9 0xCD01 # 0 +0xC3CA 0xCD08 # 0 +0xC3CB 0xCD09 # 0 +0xC3CC 0xCD0C # 0 +0xC3CD 0xCD10 # 0 +0xC3CE 0xCD18 # 0 +0xC3CF 0xCD19 # 0 +0xC3D0 0xCD1B # 0 +0xC3D1 0xCD1D # 0 +0xC3D2 0xCD24 # 0 +0xC3D3 0xCD28 # 0 +0xC3D4 0xCD2C # 0 +0xC3D5 0xCD39 # 0 +0xC3D6 0xCD5C # 0 +0xC3D7 0xCD60 # 0 +0xC3D8 0xCD64 # 0 +0xC3D9 0xCD6C # 0 +0xC3DA 0xCD6D # 0 +0xC3DB 0xCD6F # 0 +0xC3DC 0xCD71 # 0 +0xC3DD 0xCD78 # 0 +0xC3DE 0xCD88 # 0 +0xC3DF 0xCD94 # 0 +0xC3E0 0xCD95 # 0 +0xC3E1 0xCD98 # 0 +0xC3E2 0xCD9C # 0 +0xC3E3 0xCDA4 # 0 +0xC3E4 0xCDA5 # 0 +0xC3E5 0xCDA7 # 0 +0xC3E6 0xCDA9 # 0 +0xC3E7 0xCDB0 # 0 +0xC3E8 0xCDC4 # 0 +0xC3E9 0xCDCC # 0 +0xC3EA 0xCDD0 # 0 +0xC3EB 0xCDE8 # 0 +0xC3EC 0xCDEC # 0 +0xC3ED 0xCDF0 # 0 +0xC3EE 0xCDF8 # 0 +0xC3EF 0xCDF9 # 0 +0xC3F0 0xCDFB # 0 +0xC3F1 0xCDFD # 0 +0xC3F2 0xCE04 # 0 +0xC3F3 0xCE08 # 0 +0xC3F4 0xCE0C # 0 +0xC3F5 0xCE14 # 0 +0xC3F6 0xCE19 # 0 +0xC3F7 0xCE20 # 0 +0xC3F8 0xCE21 # 0 +0xC3F9 0xCE24 # 0 +0xC3FA 0xCE28 # 0 +0xC3FB 0xCE30 # 0 +0xC3FC 0xCE31 # 0 +0xC3FD 0xCE33 # 0 +0xC3FE 0xCE35 # 0 +0xC441 0xD6AB # 0 +0xC442 0xD6AD # 0 +0xC443 0xD6AE # 0 +0xC444 0xD6AF # 0 +0xC445 0xD6B1 # 0 +0xC446 0xD6B2 # 0 +0xC447 0xD6B3 # 0 +0xC448 0xD6B4 # 0 +0xC449 0xD6B5 # 0 +0xC44A 0xD6B6 # 0 +0xC44B 0xD6B7 # 0 +0xC44C 0xD6B8 # 0 +0xC44D 0xD6BA # 0 +0xC44E 0xD6BC # 0 +0xC44F 0xD6BD # 0 +0xC450 0xD6BE # 0 +0xC451 0xD6BF # 0 +0xC452 0xD6C0 # 0 +0xC453 0xD6C1 # 0 +0xC454 0xD6C2 # 0 +0xC455 0xD6C3 # 0 +0xC456 0xD6C6 # 0 +0xC457 0xD6C7 # 0 +0xC458 0xD6C9 # 0 +0xC459 0xD6CA # 0 +0xC45A 0xD6CB # 0 +0xC461 0xD6CD # 0 +0xC462 0xD6CE # 0 +0xC463 0xD6CF # 0 +0xC464 0xD6D0 # 0 +0xC465 0xD6D2 # 0 +0xC466 0xD6D3 # 0 +0xC467 0xD6D5 # 0 +0xC468 0xD6D6 # 0 +0xC469 0xD6D8 # 0 +0xC46A 0xD6DA # 0 +0xC46B 0xD6DB # 0 +0xC46C 0xD6DC # 0 +0xC46D 0xD6DD # 0 +0xC46E 0xD6DE # 0 +0xC46F 0xD6DF # 0 +0xC470 0xD6E1 # 0 +0xC471 0xD6E2 # 0 +0xC472 0xD6E3 # 0 +0xC473 0xD6E5 # 0 +0xC474 0xD6E6 # 0 +0xC475 0xD6E7 # 0 +0xC476 0xD6E9 # 0 +0xC477 0xD6EA # 0 +0xC478 0xD6EB # 0 +0xC479 0xD6EC # 0 +0xC47A 0xD6ED # 0 +0xC481 0xD6EE # 0 +0xC482 0xD6EF # 0 +0xC483 0xD6F1 # 0 +0xC484 0xD6F2 # 0 +0xC485 0xD6F3 # 0 +0xC486 0xD6F4 # 0 +0xC487 0xD6F6 # 0 +0xC488 0xD6F7 # 0 +0xC489 0xD6F8 # 0 +0xC48A 0xD6F9 # 0 +0xC48B 0xD6FA # 0 +0xC48C 0xD6FB # 0 +0xC48D 0xD6FE # 0 +0xC48E 0xD6FF # 0 +0xC48F 0xD701 # 0 +0xC490 0xD702 # 0 +0xC491 0xD703 # 0 +0xC492 0xD705 # 0 +0xC493 0xD706 # 0 +0xC494 0xD707 # 0 +0xC495 0xD708 # 0 +0xC496 0xD709 # 0 +0xC497 0xD70A # 0 +0xC498 0xD70B # 0 +0xC499 0xD70C # 0 +0xC49A 0xD70D # 0 +0xC49B 0xD70E # 0 +0xC49C 0xD70F # 0 +0xC49D 0xD710 # 0 +0xC49E 0xD712 # 0 +0xC49F 0xD713 # 0 +0xC4A0 0xD714 # 0 +0xC4A1 0xCE58 # 0 +0xC4A2 0xCE59 # 0 +0xC4A3 0xCE5C # 0 +0xC4A4 0xCE5F # 0 +0xC4A5 0xCE60 # 0 +0xC4A6 0xCE61 # 0 +0xC4A7 0xCE68 # 0 +0xC4A8 0xCE69 # 0 +0xC4A9 0xCE6B # 0 +0xC4AA 0xCE6D # 0 +0xC4AB 0xCE74 # 0 +0xC4AC 0xCE75 # 0 +0xC4AD 0xCE78 # 0 +0xC4AE 0xCE7C # 0 +0xC4AF 0xCE84 # 0 +0xC4B0 0xCE85 # 0 +0xC4B1 0xCE87 # 0 +0xC4B2 0xCE89 # 0 +0xC4B3 0xCE90 # 0 +0xC4B4 0xCE91 # 0 +0xC4B5 0xCE94 # 0 +0xC4B6 0xCE98 # 0 +0xC4B7 0xCEA0 # 0 +0xC4B8 0xCEA1 # 0 +0xC4B9 0xCEA3 # 0 +0xC4BA 0xCEA4 # 0 +0xC4BB 0xCEA5 # 0 +0xC4BC 0xCEAC # 0 +0xC4BD 0xCEAD # 0 +0xC4BE 0xCEC1 # 0 +0xC4BF 0xCEE4 # 0 +0xC4C0 0xCEE5 # 0 +0xC4C1 0xCEE8 # 0 +0xC4C2 0xCEEB # 0 +0xC4C3 0xCEEC # 0 +0xC4C4 0xCEF4 # 0 +0xC4C5 0xCEF5 # 0 +0xC4C6 0xCEF7 # 0 +0xC4C7 0xCEF8 # 0 +0xC4C8 0xCEF9 # 0 +0xC4C9 0xCF00 # 0 +0xC4CA 0xCF01 # 0 +0xC4CB 0xCF04 # 0 +0xC4CC 0xCF08 # 0 +0xC4CD 0xCF10 # 0 +0xC4CE 0xCF11 # 0 +0xC4CF 0xCF13 # 0 +0xC4D0 0xCF15 # 0 +0xC4D1 0xCF1C # 0 +0xC4D2 0xCF20 # 0 +0xC4D3 0xCF24 # 0 +0xC4D4 0xCF2C # 0 +0xC4D5 0xCF2D # 0 +0xC4D6 0xCF2F # 0 +0xC4D7 0xCF30 # 0 +0xC4D8 0xCF31 # 0 +0xC4D9 0xCF38 # 0 +0xC4DA 0xCF54 # 0 +0xC4DB 0xCF55 # 0 +0xC4DC 0xCF58 # 0 +0xC4DD 0xCF5C # 0 +0xC4DE 0xCF64 # 0 +0xC4DF 0xCF65 # 0 +0xC4E0 0xCF67 # 0 +0xC4E1 0xCF69 # 0 +0xC4E2 0xCF70 # 0 +0xC4E3 0xCF71 # 0 +0xC4E4 0xCF74 # 0 +0xC4E5 0xCF78 # 0 +0xC4E6 0xCF80 # 0 +0xC4E7 0xCF85 # 0 +0xC4E8 0xCF8C # 0 +0xC4E9 0xCFA1 # 0 +0xC4EA 0xCFA8 # 0 +0xC4EB 0xCFB0 # 0 +0xC4EC 0xCFC4 # 0 +0xC4ED 0xCFE0 # 0 +0xC4EE 0xCFE1 # 0 +0xC4EF 0xCFE4 # 0 +0xC4F0 0xCFE8 # 0 +0xC4F1 0xCFF0 # 0 +0xC4F2 0xCFF1 # 0 +0xC4F3 0xCFF3 # 0 +0xC4F4 0xCFF5 # 0 +0xC4F5 0xCFFC # 0 +0xC4F6 0xD000 # 0 +0xC4F7 0xD004 # 0 +0xC4F8 0xD011 # 0 +0xC4F9 0xD018 # 0 +0xC4FA 0xD02D # 0 +0xC4FB 0xD034 # 0 +0xC4FC 0xD035 # 0 +0xC4FD 0xD038 # 0 +0xC4FE 0xD03C # 0 +0xC541 0xD715 # 0 +0xC542 0xD716 # 0 +0xC543 0xD717 # 0 +0xC544 0xD71A # 0 +0xC545 0xD71B # 0 +0xC546 0xD71D # 0 +0xC547 0xD71E # 0 +0xC548 0xD71F # 0 +0xC549 0xD721 # 0 +0xC54A 0xD722 # 0 +0xC54B 0xD723 # 0 +0xC54C 0xD724 # 0 +0xC54D 0xD725 # 0 +0xC54E 0xD726 # 0 +0xC54F 0xD727 # 0 +0xC550 0xD72A # 0 +0xC551 0xD72C # 0 +0xC552 0xD72E # 0 +0xC553 0xD72F # 0 +0xC554 0xD730 # 0 +0xC555 0xD731 # 0 +0xC556 0xD732 # 0 +0xC557 0xD733 # 0 +0xC558 0xD736 # 0 +0xC559 0xD737 # 0 +0xC55A 0xD739 # 0 +0xC561 0xD73A # 0 +0xC562 0xD73B # 0 +0xC563 0xD73D # 0 +0xC564 0xD73E # 0 +0xC565 0xD73F # 0 +0xC566 0xD740 # 0 +0xC567 0xD741 # 0 +0xC568 0xD742 # 0 +0xC569 0xD743 # 0 +0xC56A 0xD745 # 0 +0xC56B 0xD746 # 0 +0xC56C 0xD748 # 0 +0xC56D 0xD74A # 0 +0xC56E 0xD74B # 0 +0xC56F 0xD74C # 0 +0xC570 0xD74D # 0 +0xC571 0xD74E # 0 +0xC572 0xD74F # 0 +0xC573 0xD752 # 0 +0xC574 0xD753 # 0 +0xC575 0xD755 # 0 +0xC576 0xD75A # 0 +0xC577 0xD75B # 0 +0xC578 0xD75C # 0 +0xC579 0xD75D # 0 +0xC57A 0xD75E # 0 +0xC581 0xD75F # 0 +0xC582 0xD762 # 0 +0xC583 0xD764 # 0 +0xC584 0xD766 # 0 +0xC585 0xD767 # 0 +0xC586 0xD768 # 0 +0xC587 0xD76A # 0 +0xC588 0xD76B # 0 +0xC589 0xD76D # 0 +0xC58A 0xD76E # 0 +0xC58B 0xD76F # 0 +0xC58C 0xD771 # 0 +0xC58D 0xD772 # 0 +0xC58E 0xD773 # 0 +0xC58F 0xD775 # 0 +0xC590 0xD776 # 0 +0xC591 0xD777 # 0 +0xC592 0xD778 # 0 +0xC593 0xD779 # 0 +0xC594 0xD77A # 0 +0xC595 0xD77B # 0 +0xC596 0xD77E # 0 +0xC597 0xD77F # 0 +0xC598 0xD780 # 0 +0xC599 0xD782 # 0 +0xC59A 0xD783 # 0 +0xC59B 0xD784 # 0 +0xC59C 0xD785 # 0 +0xC59D 0xD786 # 0 +0xC59E 0xD787 # 0 +0xC59F 0xD78A # 0 +0xC5A0 0xD78B # 0 +0xC5A1 0xD044 # 0 +0xC5A2 0xD045 # 0 +0xC5A3 0xD047 # 0 +0xC5A4 0xD049 # 0 +0xC5A5 0xD050 # 0 +0xC5A6 0xD054 # 0 +0xC5A7 0xD058 # 0 +0xC5A8 0xD060 # 0 +0xC5A9 0xD06C # 0 +0xC5AA 0xD06D # 0 +0xC5AB 0xD070 # 0 +0xC5AC 0xD074 # 0 +0xC5AD 0xD07C # 0 +0xC5AE 0xD07D # 0 +0xC5AF 0xD081 # 0 +0xC5B0 0xD0A4 # 0 +0xC5B1 0xD0A5 # 0 +0xC5B2 0xD0A8 # 0 +0xC5B3 0xD0AC # 0 +0xC5B4 0xD0B4 # 0 +0xC5B5 0xD0B5 # 0 +0xC5B6 0xD0B7 # 0 +0xC5B7 0xD0B9 # 0 +0xC5B8 0xD0C0 # 0 +0xC5B9 0xD0C1 # 0 +0xC5BA 0xD0C4 # 0 +0xC5BB 0xD0C8 # 0 +0xC5BC 0xD0C9 # 0 +0xC5BD 0xD0D0 # 0 +0xC5BE 0xD0D1 # 0 +0xC5BF 0xD0D3 # 0 +0xC5C0 0xD0D4 # 0 +0xC5C1 0xD0D5 # 0 +0xC5C2 0xD0DC # 0 +0xC5C3 0xD0DD # 0 +0xC5C4 0xD0E0 # 0 +0xC5C5 0xD0E4 # 0 +0xC5C6 0xD0EC # 0 +0xC5C7 0xD0ED # 0 +0xC5C8 0xD0EF # 0 +0xC5C9 0xD0F0 # 0 +0xC5CA 0xD0F1 # 0 +0xC5CB 0xD0F8 # 0 +0xC5CC 0xD10D # 0 +0xC5CD 0xD130 # 0 +0xC5CE 0xD131 # 0 +0xC5CF 0xD134 # 0 +0xC5D0 0xD138 # 0 +0xC5D1 0xD13A # 0 +0xC5D2 0xD140 # 0 +0xC5D3 0xD141 # 0 +0xC5D4 0xD143 # 0 +0xC5D5 0xD144 # 0 +0xC5D6 0xD145 # 0 +0xC5D7 0xD14C # 0 +0xC5D8 0xD14D # 0 +0xC5D9 0xD150 # 0 +0xC5DA 0xD154 # 0 +0xC5DB 0xD15C # 0 +0xC5DC 0xD15D # 0 +0xC5DD 0xD15F # 0 +0xC5DE 0xD161 # 0 +0xC5DF 0xD168 # 0 +0xC5E0 0xD16C # 0 +0xC5E1 0xD17C # 0 +0xC5E2 0xD184 # 0 +0xC5E3 0xD188 # 0 +0xC5E4 0xD1A0 # 0 +0xC5E5 0xD1A1 # 0 +0xC5E6 0xD1A4 # 0 +0xC5E7 0xD1A8 # 0 +0xC5E8 0xD1B0 # 0 +0xC5E9 0xD1B1 # 0 +0xC5EA 0xD1B3 # 0 +0xC5EB 0xD1B5 # 0 +0xC5EC 0xD1BA # 0 +0xC5ED 0xD1BC # 0 +0xC5EE 0xD1C0 # 0 +0xC5EF 0xD1D8 # 0 +0xC5F0 0xD1F4 # 0 +0xC5F1 0xD1F8 # 0 +0xC5F2 0xD207 # 0 +0xC5F3 0xD209 # 0 +0xC5F4 0xD210 # 0 +0xC5F5 0xD22C # 0 +0xC5F6 0xD22D # 0 +0xC5F7 0xD230 # 0 +0xC5F8 0xD234 # 0 +0xC5F9 0xD23C # 0 +0xC5FA 0xD23D # 0 +0xC5FB 0xD23F # 0 +0xC5FC 0xD241 # 0 +0xC5FD 0xD248 # 0 +0xC5FE 0xD25C # 0 +0xC641 0xD78D # 0 +0xC642 0xD78E # 0 +0xC643 0xD78F # 0 +0xC644 0xD791 # 0 +0xC645 0xD792 # 0 +0xC646 0xD793 # 0 +0xC647 0xD794 # 0 +0xC648 0xD795 # 0 +0xC649 0xD796 # 0 +0xC64A 0xD797 # 0 +0xC64B 0xD79A # 0 +0xC64C 0xD79C # 0 +0xC64D 0xD79E # 0 +0xC64E 0xD79F # 0 +0xC64F 0xD7A0 # 0 +0xC650 0xD7A1 # 0 +0xC651 0xD7A2 # 0 +0xC652 0xD7A3 # 0 +0xC6A1 0xD264 # 0 +0xC6A2 0xD280 # 0 +0xC6A3 0xD281 # 0 +0xC6A4 0xD284 # 0 +0xC6A5 0xD288 # 0 +0xC6A6 0xD290 # 0 +0xC6A7 0xD291 # 0 +0xC6A8 0xD295 # 0 +0xC6A9 0xD29C # 0 +0xC6AA 0xD2A0 # 0 +0xC6AB 0xD2A4 # 0 +0xC6AC 0xD2AC # 0 +0xC6AD 0xD2B1 # 0 +0xC6AE 0xD2B8 # 0 +0xC6AF 0xD2B9 # 0 +0xC6B0 0xD2BC # 0 +0xC6B1 0xD2BF # 0 +0xC6B2 0xD2C0 # 0 +0xC6B3 0xD2C2 # 0 +0xC6B4 0xD2C8 # 0 +0xC6B5 0xD2C9 # 0 +0xC6B6 0xD2CB # 0 +0xC6B7 0xD2D4 # 0 +0xC6B8 0xD2D8 # 0 +0xC6B9 0xD2DC # 0 +0xC6BA 0xD2E4 # 0 +0xC6BB 0xD2E5 # 0 +0xC6BC 0xD2F0 # 0 +0xC6BD 0xD2F1 # 0 +0xC6BE 0xD2F4 # 0 +0xC6BF 0xD2F8 # 0 +0xC6C0 0xD300 # 0 +0xC6C1 0xD301 # 0 +0xC6C2 0xD303 # 0 +0xC6C3 0xD305 # 0 +0xC6C4 0xD30C # 0 +0xC6C5 0xD30D # 0 +0xC6C6 0xD30E # 0 +0xC6C7 0xD310 # 0 +0xC6C8 0xD314 # 0 +0xC6C9 0xD316 # 0 +0xC6CA 0xD31C # 0 +0xC6CB 0xD31D # 0 +0xC6CC 0xD31F # 0 +0xC6CD 0xD320 # 0 +0xC6CE 0xD321 # 0 +0xC6CF 0xD325 # 0 +0xC6D0 0xD328 # 0 +0xC6D1 0xD329 # 0 +0xC6D2 0xD32C # 0 +0xC6D3 0xD330 # 0 +0xC6D4 0xD338 # 0 +0xC6D5 0xD339 # 0 +0xC6D6 0xD33B # 0 +0xC6D7 0xD33C # 0 +0xC6D8 0xD33D # 0 +0xC6D9 0xD344 # 0 +0xC6DA 0xD345 # 0 +0xC6DB 0xD37C # 0 +0xC6DC 0xD37D # 0 +0xC6DD 0xD380 # 0 +0xC6DE 0xD384 # 0 +0xC6DF 0xD38C # 0 +0xC6E0 0xD38D # 0 +0xC6E1 0xD38F # 0 +0xC6E2 0xD390 # 0 +0xC6E3 0xD391 # 0 +0xC6E4 0xD398 # 0 +0xC6E5 0xD399 # 0 +0xC6E6 0xD39C # 0 +0xC6E7 0xD3A0 # 0 +0xC6E8 0xD3A8 # 0 +0xC6E9 0xD3A9 # 0 +0xC6EA 0xD3AB # 0 +0xC6EB 0xD3AD # 0 +0xC6EC 0xD3B4 # 0 +0xC6ED 0xD3B8 # 0 +0xC6EE 0xD3BC # 0 +0xC6EF 0xD3C4 # 0 +0xC6F0 0xD3C5 # 0 +0xC6F1 0xD3C8 # 0 +0xC6F2 0xD3C9 # 0 +0xC6F3 0xD3D0 # 0 +0xC6F4 0xD3D8 # 0 +0xC6F5 0xD3E1 # 0 +0xC6F6 0xD3E3 # 0 +0xC6F7 0xD3EC # 0 +0xC6F8 0xD3ED # 0 +0xC6F9 0xD3F0 # 0 +0xC6FA 0xD3F4 # 0 +0xC6FB 0xD3FC # 0 +0xC6FC 0xD3FD # 0 +0xC6FD 0xD3FF # 0 +0xC6FE 0xD401 # 0 +0xC7A1 0xD408 # 0 +0xC7A2 0xD41D # 0 +0xC7A3 0xD440 # 0 +0xC7A4 0xD444 # 0 +0xC7A5 0xD45C # 0 +0xC7A6 0xD460 # 0 +0xC7A7 0xD464 # 0 +0xC7A8 0xD46D # 0 +0xC7A9 0xD46F # 0 +0xC7AA 0xD478 # 0 +0xC7AB 0xD479 # 0 +0xC7AC 0xD47C # 0 +0xC7AD 0xD47F # 0 +0xC7AE 0xD480 # 0 +0xC7AF 0xD482 # 0 +0xC7B0 0xD488 # 0 +0xC7B1 0xD489 # 0 +0xC7B2 0xD48B # 0 +0xC7B3 0xD48D # 0 +0xC7B4 0xD494 # 0 +0xC7B5 0xD4A9 # 0 +0xC7B6 0xD4CC # 0 +0xC7B7 0xD4D0 # 0 +0xC7B8 0xD4D4 # 0 +0xC7B9 0xD4DC # 0 +0xC7BA 0xD4DF # 0 +0xC7BB 0xD4E8 # 0 +0xC7BC 0xD4EC # 0 +0xC7BD 0xD4F0 # 0 +0xC7BE 0xD4F8 # 0 +0xC7BF 0xD4FB # 0 +0xC7C0 0xD4FD # 0 +0xC7C1 0xD504 # 0 +0xC7C2 0xD508 # 0 +0xC7C3 0xD50C # 0 +0xC7C4 0xD514 # 0 +0xC7C5 0xD515 # 0 +0xC7C6 0xD517 # 0 +0xC7C7 0xD53C # 0 +0xC7C8 0xD53D # 0 +0xC7C9 0xD540 # 0 +0xC7CA 0xD544 # 0 +0xC7CB 0xD54C # 0 +0xC7CC 0xD54D # 0 +0xC7CD 0xD54F # 0 +0xC7CE 0xD551 # 0 +0xC7CF 0xD558 # 0 +0xC7D0 0xD559 # 0 +0xC7D1 0xD55C # 0 +0xC7D2 0xD560 # 0 +0xC7D3 0xD565 # 0 +0xC7D4 0xD568 # 0 +0xC7D5 0xD569 # 0 +0xC7D6 0xD56B # 0 +0xC7D7 0xD56D # 0 +0xC7D8 0xD574 # 0 +0xC7D9 0xD575 # 0 +0xC7DA 0xD578 # 0 +0xC7DB 0xD57C # 0 +0xC7DC 0xD584 # 0 +0xC7DD 0xD585 # 0 +0xC7DE 0xD587 # 0 +0xC7DF 0xD588 # 0 +0xC7E0 0xD589 # 0 +0xC7E1 0xD590 # 0 +0xC7E2 0xD5A5 # 0 +0xC7E3 0xD5C8 # 0 +0xC7E4 0xD5C9 # 0 +0xC7E5 0xD5CC # 0 +0xC7E6 0xD5D0 # 0 +0xC7E7 0xD5D2 # 0 +0xC7E8 0xD5D8 # 0 +0xC7E9 0xD5D9 # 0 +0xC7EA 0xD5DB # 0 +0xC7EB 0xD5DD # 0 +0xC7EC 0xD5E4 # 0 +0xC7ED 0xD5E5 # 0 +0xC7EE 0xD5E8 # 0 +0xC7EF 0xD5EC # 0 +0xC7F0 0xD5F4 # 0 +0xC7F1 0xD5F5 # 0 +0xC7F2 0xD5F7 # 0 +0xC7F3 0xD5F9 # 0 +0xC7F4 0xD600 # 0 +0xC7F5 0xD601 # 0 +0xC7F6 0xD604 # 0 +0xC7F7 0xD608 # 0 +0xC7F8 0xD610 # 0 +0xC7F9 0xD611 # 0 +0xC7FA 0xD613 # 0 +0xC7FB 0xD614 # 0 +0xC7FC 0xD615 # 0 +0xC7FD 0xD61C # 0 +0xC7FE 0xD620 # 0 +0xC8A1 0xD624 # 0 +0xC8A2 0xD62D # 0 +0xC8A3 0xD638 # 0 +0xC8A4 0xD639 # 0 +0xC8A5 0xD63C # 0 +0xC8A6 0xD640 # 0 +0xC8A7 0xD645 # 0 +0xC8A8 0xD648 # 0 +0xC8A9 0xD649 # 0 +0xC8AA 0xD64B # 0 +0xC8AB 0xD64D # 0 +0xC8AC 0xD651 # 0 +0xC8AD 0xD654 # 0 +0xC8AE 0xD655 # 0 +0xC8AF 0xD658 # 0 +0xC8B0 0xD65C # 0 +0xC8B1 0xD667 # 0 +0xC8B2 0xD669 # 0 +0xC8B3 0xD670 # 0 +0xC8B4 0xD671 # 0 +0xC8B5 0xD674 # 0 +0xC8B6 0xD683 # 0 +0xC8B7 0xD685 # 0 +0xC8B8 0xD68C # 0 +0xC8B9 0xD68D # 0 +0xC8BA 0xD690 # 0 +0xC8BB 0xD694 # 0 +0xC8BC 0xD69D # 0 +0xC8BD 0xD69F # 0 +0xC8BE 0xD6A1 # 0 +0xC8BF 0xD6A8 # 0 +0xC8C0 0xD6AC # 0 +0xC8C1 0xD6B0 # 0 +0xC8C2 0xD6B9 # 0 +0xC8C3 0xD6BB # 0 +0xC8C4 0xD6C4 # 0 +0xC8C5 0xD6C5 # 0 +0xC8C6 0xD6C8 # 0 +0xC8C7 0xD6CC # 0 +0xC8C8 0xD6D1 # 0 +0xC8C9 0xD6D4 # 0 +0xC8CA 0xD6D7 # 0 +0xC8CB 0xD6D9 # 0 +0xC8CC 0xD6E0 # 0 +0xC8CD 0xD6E4 # 0 +0xC8CE 0xD6E8 # 0 +0xC8CF 0xD6F0 # 0 +0xC8D0 0xD6F5 # 0 +0xC8D1 0xD6FC # 0 +0xC8D2 0xD6FD # 0 +0xC8D3 0xD700 # 0 +0xC8D4 0xD704 # 0 +0xC8D5 0xD711 # 0 +0xC8D6 0xD718 # 0 +0xC8D7 0xD719 # 0 +0xC8D8 0xD71C # 0 +0xC8D9 0xD720 # 0 +0xC8DA 0xD728 # 0 +0xC8DB 0xD729 # 0 +0xC8DC 0xD72B # 0 +0xC8DD 0xD72D # 0 +0xC8DE 0xD734 # 0 +0xC8DF 0xD735 # 0 +0xC8E0 0xD738 # 0 +0xC8E1 0xD73C # 0 +0xC8E2 0xD744 # 0 +0xC8E3 0xD747 # 0 +0xC8E4 0xD749 # 0 +0xC8E5 0xD750 # 0 +0xC8E6 0xD751 # 0 +0xC8E7 0xD754 # 0 +0xC8E8 0xD756 # 0 +0xC8E9 0xD757 # 0 +0xC8EA 0xD758 # 0 +0xC8EB 0xD759 # 0 +0xC8EC 0xD760 # 0 +0xC8ED 0xD761 # 0 +0xC8EE 0xD763 # 0 +0xC8EF 0xD765 # 0 +0xC8F0 0xD769 # 0 +0xC8F1 0xD76C # 0 +0xC8F2 0xD770 # 0 +0xC8F3 0xD774 # 0 +0xC8F4 0xD77C # 0 +0xC8F5 0xD77D # 0 +0xC8F6 0xD781 # 0 +0xC8F7 0xD788 # 0 +0xC8F8 0xD789 # 0 +0xC8F9 0xD78C # 0 +0xC8FA 0xD790 # 0 +0xC8FB 0xD798 # 0 +0xC8FC 0xD799 # 0 +0xC8FD 0xD79B # 0 +0xC8FE 0xD79D # 0 +0xC9A1 0xE000 # 0 +0xC9A2 0xE001 # 0 +0xC9A3 0xE002 # 0 +0xC9A4 0xE003 # 0 +0xC9A5 0xE004 # 0 +0xC9A6 0xE005 # 0 +0xC9A7 0xE006 # 0 +0xC9A8 0xE007 # 0 +0xC9A9 0xE008 # 0 +0xC9AA 0xE009 # 0 +0xC9AB 0xE00A # 0 +0xC9AC 0xE00B # 0 +0xC9AD 0xE00C # 0 +0xC9AE 0xE00D # 0 +0xC9AF 0xE00E # 0 +0xC9B0 0xE00F # 0 +0xC9B1 0xE010 # 0 +0xC9B2 0xE011 # 0 +0xC9B3 0xE012 # 0 +0xC9B4 0xE013 # 0 +0xC9B5 0xE014 # 0 +0xC9B6 0xE015 # 0 +0xC9B7 0xE016 # 0 +0xC9B8 0xE017 # 0 +0xC9B9 0xE018 # 0 +0xC9BA 0xE019 # 0 +0xC9BB 0xE01A # 0 +0xC9BC 0xE01B # 0 +0xC9BD 0xE01C # 0 +0xC9BE 0xE01D # 0 +0xC9BF 0xE01E # 0 +0xC9C0 0xE01F # 0 +0xC9C1 0xE020 # 0 +0xC9C2 0xE021 # 0 +0xC9C3 0xE022 # 0 +0xC9C4 0xE023 # 0 +0xC9C5 0xE024 # 0 +0xC9C6 0xE025 # 0 +0xC9C7 0xE026 # 0 +0xC9C8 0xE027 # 0 +0xC9C9 0xE028 # 0 +0xC9CA 0xE029 # 0 +0xC9CB 0xE02A # 0 +0xC9CC 0xE02B # 0 +0xC9CD 0xE02C # 0 +0xC9CE 0xE02D # 0 +0xC9CF 0xE02E # 0 +0xC9D0 0xE02F # 0 +0xC9D1 0xE030 # 0 +0xC9D2 0xE031 # 0 +0xC9D3 0xE032 # 0 +0xC9D4 0xE033 # 0 +0xC9D5 0xE034 # 0 +0xC9D6 0xE035 # 0 +0xC9D7 0xE036 # 0 +0xC9D8 0xE037 # 0 +0xC9D9 0xE038 # 0 +0xC9DA 0xE039 # 0 +0xC9DB 0xE03A # 0 +0xC9DC 0xE03B # 0 +0xC9DD 0xE03C # 0 +0xC9DE 0xE03D # 0 +0xC9DF 0xE03E # 0 +0xC9E0 0xE03F # 0 +0xC9E1 0xE040 # 0 +0xC9E2 0xE041 # 0 +0xC9E3 0xE042 # 0 +0xC9E4 0xE043 # 0 +0xC9E5 0xE044 # 0 +0xC9E6 0xE045 # 0 +0xC9E7 0xE046 # 0 +0xC9E8 0xE047 # 0 +0xC9E9 0xE048 # 0 +0xC9EA 0xE049 # 0 +0xC9EB 0xE04A # 0 +0xC9EC 0xE04B # 0 +0xC9ED 0xE04C # 0 +0xC9EE 0xE04D # 0 +0xC9EF 0xE04E # 0 +0xC9F0 0xE04F # 0 +0xC9F1 0xE050 # 0 +0xC9F2 0xE051 # 0 +0xC9F3 0xE052 # 0 +0xC9F4 0xE053 # 0 +0xC9F5 0xE054 # 0 +0xC9F6 0xE055 # 0 +0xC9F7 0xE056 # 0 +0xC9F8 0xE057 # 0 +0xC9F9 0xE058 # 0 +0xC9FA 0xE059 # 0 +0xC9FB 0xE05A # 0 +0xC9FC 0xE05B # 0 +0xC9FD 0xE05C # 0 +0xC9FE 0xE05D # 0 +0xCAA1 0x4F3D # 0 +0xCAA2 0x4F73 # 0 +0xCAA3 0x5047 # 0 +0xCAA4 0x50F9 # 0 +0xCAA5 0x52A0 # 0 +0xCAA6 0x53EF # 0 +0xCAA7 0x5475 # 0 +0xCAA8 0x54E5 # 0 +0xCAA9 0x5609 # 0 +0xCAAA 0x5AC1 # 0 +0xCAAB 0x5BB6 # 0 +0xCAAC 0x6687 # 0 +0xCAAD 0x67B6 # 0 +0xCAAE 0x67B7 # 0 +0xCAAF 0x67EF # 0 +0xCAB0 0x6B4C # 0 +0xCAB1 0x73C2 # 0 +0xCAB2 0x75C2 # 0 +0xCAB3 0x7A3C # 0 +0xCAB4 0x82DB # 0 +0xCAB5 0x8304 # 0 +0xCAB6 0x8857 # 0 +0xCAB7 0x8888 # 0 +0xCAB8 0x8A36 # 0 +0xCAB9 0x8CC8 # 0 +0xCABA 0x8DCF # 0 +0xCABB 0x8EFB # 0 +0xCABC 0x8FE6 # 0 +0xCABD 0x99D5 # 0 +0xCABE 0x523B # 0 +0xCABF 0x5374 # 0 +0xCAC0 0x5404 # 0 +0xCAC1 0x606A # 0 +0xCAC2 0x6164 # 0 +0xCAC3 0x6BBC # 0 +0xCAC4 0x73CF # 0 +0xCAC5 0x811A # 0 +0xCAC6 0x89BA # 0 +0xCAC7 0x89D2 # 0 +0xCAC8 0x95A3 # 0 +0xCAC9 0x4F83 # 0 +0xCACA 0x520A # 0 +0xCACB 0x58BE # 0 +0xCACC 0x5978 # 0 +0xCACD 0x59E6 # 0 +0xCACE 0x5E72 # 0 +0xCACF 0x5E79 # 0 +0xCAD0 0x61C7 # 0 +0xCAD1 0x63C0 # 0 +0xCAD2 0x6746 # 0 +0xCAD3 0x67EC # 0 +0xCAD4 0x687F # 0 +0xCAD5 0x6F97 # 0 +0xCAD6 0x764E # 0 +0xCAD7 0x770B # 0 +0xCAD8 0x78F5 # 0 +0xCAD9 0x7A08 # 0 +0xCADA 0x7AFF # 0 +0xCADB 0x7C21 # 0 +0xCADC 0x809D # 0 +0xCADD 0x826E # 0 +0xCADE 0x8271 # 0 +0xCADF 0x8AEB # 0 +0xCAE0 0x9593 # 0 +0xCAE1 0x4E6B # 0 +0xCAE2 0x559D # 0 +0xCAE3 0x66F7 # 0 +0xCAE4 0x6E34 # 0 +0xCAE5 0x78A3 # 0 +0xCAE6 0x7AED # 0 +0xCAE7 0x845B # 0 +0xCAE8 0x8910 # 0 +0xCAE9 0x874E # 0 +0xCAEA 0x97A8 # 0 +0xCAEB 0x52D8 # 0 +0xCAEC 0x574E # 0 +0xCAED 0x582A # 0 +0xCAEE 0x5D4C # 0 +0xCAEF 0x611F # 0 +0xCAF0 0x61BE # 0 +0xCAF1 0x6221 # 0 +0xCAF2 0x6562 # 0 +0xCAF3 0x67D1 # 0 +0xCAF4 0x6A44 # 0 +0xCAF5 0x6E1B # 0 +0xCAF6 0x7518 # 0 +0xCAF7 0x75B3 # 0 +0xCAF8 0x76E3 # 0 +0xCAF9 0x77B0 # 0 +0xCAFA 0x7D3A # 0 +0xCAFB 0x90AF # 0 +0xCAFC 0x9451 # 0 +0xCAFD 0x9452 # 0 +0xCAFE 0x9F95 # 0 +0xCBA1 0x5323 # 0 +0xCBA2 0x5CAC # 0 +0xCBA3 0x7532 # 0 +0xCBA4 0x80DB # 0 +0xCBA5 0x9240 # 0 +0xCBA6 0x9598 # 0 +0xCBA7 0x525B # 0 +0xCBA8 0x5808 # 0 +0xCBA9 0x59DC # 0 +0xCBAA 0x5CA1 # 0 +0xCBAB 0x5D17 # 0 +0xCBAC 0x5EB7 # 0 +0xCBAD 0x5F3A # 0 +0xCBAE 0x5F4A # 0 +0xCBAF 0x6177 # 0 +0xCBB0 0x6C5F # 0 +0xCBB1 0x757A # 0 +0xCBB2 0x7586 # 0 +0xCBB3 0x7CE0 # 0 +0xCBB4 0x7D73 # 0 +0xCBB5 0x7DB1 # 0 +0xCBB6 0x7F8C # 0 +0xCBB7 0x8154 # 0 +0xCBB8 0x8221 # 0 +0xCBB9 0x8591 # 0 +0xCBBA 0x8941 # 0 +0xCBBB 0x8B1B # 0 +0xCBBC 0x92FC # 0 +0xCBBD 0x964D # 0 +0xCBBE 0x9C47 # 0 +0xCBBF 0x4ECB # 0 +0xCBC0 0x4EF7 # 0 +0xCBC1 0x500B # 0 +0xCBC2 0x51F1 # 0 +0xCBC3 0x584F # 0 +0xCBC4 0x6137 # 0 +0xCBC5 0x613E # 0 +0xCBC6 0x6168 # 0 +0xCBC7 0x6539 # 0 +0xCBC8 0x69EA # 0 +0xCBC9 0x6F11 # 0 +0xCBCA 0x75A5 # 0 +0xCBCB 0x7686 # 0 +0xCBCC 0x76D6 # 0 +0xCBCD 0x7B87 # 0 +0xCBCE 0x82A5 # 0 +0xCBCF 0x84CB # 0 +0xCBD0 0xF900 # 0 +0xCBD1 0x93A7 # 0 +0xCBD2 0x958B # 0 +0xCBD3 0x5580 # 0 +0xCBD4 0x5BA2 # 0 +0xCBD5 0x5751 # 0 +0xCBD6 0xF901 # 0 +0xCBD7 0x7CB3 # 0 +0xCBD8 0x7FB9 # 0 +0xCBD9 0x91B5 # 0 +0xCBDA 0x5028 # 0 +0xCBDB 0x53BB # 0 +0xCBDC 0x5C45 # 0 +0xCBDD 0x5DE8 # 0 +0xCBDE 0x62D2 # 0 +0xCBDF 0x636E # 0 +0xCBE0 0x64DA # 0 +0xCBE1 0x64E7 # 0 +0xCBE2 0x6E20 # 0 +0xCBE3 0x70AC # 0 +0xCBE4 0x795B # 0 +0xCBE5 0x8DDD # 0 +0xCBE6 0x8E1E # 0 +0xCBE7 0xF902 # 0 +0xCBE8 0x907D # 0 +0xCBE9 0x9245 # 0 +0xCBEA 0x92F8 # 0 +0xCBEB 0x4E7E # 0 +0xCBEC 0x4EF6 # 0 +0xCBED 0x5065 # 0 +0xCBEE 0x5DFE # 0 +0xCBEF 0x5EFA # 0 +0xCBF0 0x6106 # 0 +0xCBF1 0x6957 # 0 +0xCBF2 0x8171 # 0 +0xCBF3 0x8654 # 0 +0xCBF4 0x8E47 # 0 +0xCBF5 0x9375 # 0 +0xCBF6 0x9A2B # 0 +0xCBF7 0x4E5E # 0 +0xCBF8 0x5091 # 0 +0xCBF9 0x6770 # 0 +0xCBFA 0x6840 # 0 +0xCBFB 0x5109 # 0 +0xCBFC 0x528D # 0 +0xCBFD 0x5292 # 0 +0xCBFE 0x6AA2 # 0 +0xCCA1 0x77BC # 0 +0xCCA2 0x9210 # 0 +0xCCA3 0x9ED4 # 0 +0xCCA4 0x52AB # 0 +0xCCA5 0x602F # 0 +0xCCA6 0x8FF2 # 0 +0xCCA7 0x5048 # 0 +0xCCA8 0x61A9 # 0 +0xCCA9 0x63ED # 0 +0xCCAA 0x64CA # 0 +0xCCAB 0x683C # 0 +0xCCAC 0x6A84 # 0 +0xCCAD 0x6FC0 # 0 +0xCCAE 0x8188 # 0 +0xCCAF 0x89A1 # 0 +0xCCB0 0x9694 # 0 +0xCCB1 0x5805 # 0 +0xCCB2 0x727D # 0 +0xCCB3 0x72AC # 0 +0xCCB4 0x7504 # 0 +0xCCB5 0x7D79 # 0 +0xCCB6 0x7E6D # 0 +0xCCB7 0x80A9 # 0 +0xCCB8 0x898B # 0 +0xCCB9 0x8B74 # 0 +0xCCBA 0x9063 # 0 +0xCCBB 0x9D51 # 0 +0xCCBC 0x6289 # 0 +0xCCBD 0x6C7A # 0 +0xCCBE 0x6F54 # 0 +0xCCBF 0x7D50 # 0 +0xCCC0 0x7F3A # 0 +0xCCC1 0x8A23 # 0 +0xCCC2 0x517C # 0 +0xCCC3 0x614A # 0 +0xCCC4 0x7B9D # 0 +0xCCC5 0x8B19 # 0 +0xCCC6 0x9257 # 0 +0xCCC7 0x938C # 0 +0xCCC8 0x4EAC # 0 +0xCCC9 0x4FD3 # 0 +0xCCCA 0x501E # 0 +0xCCCB 0x50BE # 0 +0xCCCC 0x5106 # 0 +0xCCCD 0x52C1 # 0 +0xCCCE 0x52CD # 0 +0xCCCF 0x537F # 0 +0xCCD0 0x5770 # 0 +0xCCD1 0x5883 # 0 +0xCCD2 0x5E9A # 0 +0xCCD3 0x5F91 # 0 +0xCCD4 0x6176 # 0 +0xCCD5 0x61AC # 0 +0xCCD6 0x64CE # 0 +0xCCD7 0x656C # 0 +0xCCD8 0x666F # 0 +0xCCD9 0x66BB # 0 +0xCCDA 0x66F4 # 0 +0xCCDB 0x6897 # 0 +0xCCDC 0x6D87 # 0 +0xCCDD 0x7085 # 0 +0xCCDE 0x70F1 # 0 +0xCCDF 0x749F # 0 +0xCCE0 0x74A5 # 0 +0xCCE1 0x74CA # 0 +0xCCE2 0x75D9 # 0 +0xCCE3 0x786C # 0 +0xCCE4 0x78EC # 0 +0xCCE5 0x7ADF # 0 +0xCCE6 0x7AF6 # 0 +0xCCE7 0x7D45 # 0 +0xCCE8 0x7D93 # 0 +0xCCE9 0x8015 # 0 +0xCCEA 0x803F # 0 +0xCCEB 0x811B # 0 +0xCCEC 0x8396 # 0 +0xCCED 0x8B66 # 0 +0xCCEE 0x8F15 # 0 +0xCCEF 0x9015 # 0 +0xCCF0 0x93E1 # 0 +0xCCF1 0x9803 # 0 +0xCCF2 0x9838 # 0 +0xCCF3 0x9A5A # 0 +0xCCF4 0x9BE8 # 0 +0xCCF5 0x4FC2 # 0 +0xCCF6 0x5553 # 0 +0xCCF7 0x583A # 0 +0xCCF8 0x5951 # 0 +0xCCF9 0x5B63 # 0 +0xCCFA 0x5C46 # 0 +0xCCFB 0x60B8 # 0 +0xCCFC 0x6212 # 0 +0xCCFD 0x6842 # 0 +0xCCFE 0x68B0 # 0 +0xCDA1 0x68E8 # 0 +0xCDA2 0x6EAA # 0 +0xCDA3 0x754C # 0 +0xCDA4 0x7678 # 0 +0xCDA5 0x78CE # 0 +0xCDA6 0x7A3D # 0 +0xCDA7 0x7CFB # 0 +0xCDA8 0x7E6B # 0 +0xCDA9 0x7E7C # 0 +0xCDAA 0x8A08 # 0 +0xCDAB 0x8AA1 # 0 +0xCDAC 0x8C3F # 0 +0xCDAD 0x968E # 0 +0xCDAE 0x9DC4 # 0 +0xCDAF 0x53E4 # 0 +0xCDB0 0x53E9 # 0 +0xCDB1 0x544A # 0 +0xCDB2 0x5471 # 0 +0xCDB3 0x56FA # 0 +0xCDB4 0x59D1 # 0 +0xCDB5 0x5B64 # 0 +0xCDB6 0x5C3B # 0 +0xCDB7 0x5EAB # 0 +0xCDB8 0x62F7 # 0 +0xCDB9 0x6537 # 0 +0xCDBA 0x6545 # 0 +0xCDBB 0x6572 # 0 +0xCDBC 0x66A0 # 0 +0xCDBD 0x67AF # 0 +0xCDBE 0x69C1 # 0 +0xCDBF 0x6CBD # 0 +0xCDC0 0x75FC # 0 +0xCDC1 0x7690 # 0 +0xCDC2 0x777E # 0 +0xCDC3 0x7A3F # 0 +0xCDC4 0x7F94 # 0 +0xCDC5 0x8003 # 0 +0xCDC6 0x80A1 # 0 +0xCDC7 0x818F # 0 +0xCDC8 0x82E6 # 0 +0xCDC9 0x82FD # 0 +0xCDCA 0x83F0 # 0 +0xCDCB 0x85C1 # 0 +0xCDCC 0x8831 # 0 +0xCDCD 0x88B4 # 0 +0xCDCE 0x8AA5 # 0 +0xCDCF 0xF903 # 0 +0xCDD0 0x8F9C # 0 +0xCDD1 0x932E # 0 +0xCDD2 0x96C7 # 0 +0xCDD3 0x9867 # 0 +0xCDD4 0x9AD8 # 0 +0xCDD5 0x9F13 # 0 +0xCDD6 0x54ED # 0 +0xCDD7 0x659B # 0 +0xCDD8 0x66F2 # 0 +0xCDD9 0x688F # 0 +0xCDDA 0x7A40 # 0 +0xCDDB 0x8C37 # 0 +0xCDDC 0x9D60 # 0 +0xCDDD 0x56F0 # 0 +0xCDDE 0x5764 # 0 +0xCDDF 0x5D11 # 0 +0xCDE0 0x6606 # 0 +0xCDE1 0x68B1 # 0 +0xCDE2 0x68CD # 0 +0xCDE3 0x6EFE # 0 +0xCDE4 0x7428 # 0 +0xCDE5 0x889E # 0 +0xCDE6 0x9BE4 # 0 +0xCDE7 0x6C68 # 0 +0xCDE8 0xF904 # 0 +0xCDE9 0x9AA8 # 0 +0xCDEA 0x4F9B # 0 +0xCDEB 0x516C # 0 +0xCDEC 0x5171 # 0 +0xCDED 0x529F # 0 +0xCDEE 0x5B54 # 0 +0xCDEF 0x5DE5 # 0 +0xCDF0 0x6050 # 0 +0xCDF1 0x606D # 0 +0xCDF2 0x62F1 # 0 +0xCDF3 0x63A7 # 0 +0xCDF4 0x653B # 0 +0xCDF5 0x73D9 # 0 +0xCDF6 0x7A7A # 0 +0xCDF7 0x86A3 # 0 +0xCDF8 0x8CA2 # 0 +0xCDF9 0x978F # 0 +0xCDFA 0x4E32 # 0 +0xCDFB 0x5BE1 # 0 +0xCDFC 0x6208 # 0 +0xCDFD 0x679C # 0 +0xCDFE 0x74DC # 0 +0xCEA1 0x79D1 # 0 +0xCEA2 0x83D3 # 0 +0xCEA3 0x8A87 # 0 +0xCEA4 0x8AB2 # 0 +0xCEA5 0x8DE8 # 0 +0xCEA6 0x904E # 0 +0xCEA7 0x934B # 0 +0xCEA8 0x9846 # 0 +0xCEA9 0x5ED3 # 0 +0xCEAA 0x69E8 # 0 +0xCEAB 0x85FF # 0 +0xCEAC 0x90ED # 0 +0xCEAD 0xF905 # 0 +0xCEAE 0x51A0 # 0 +0xCEAF 0x5B98 # 0 +0xCEB0 0x5BEC # 0 +0xCEB1 0x6163 # 0 +0xCEB2 0x68FA # 0 +0xCEB3 0x6B3E # 0 +0xCEB4 0x704C # 0 +0xCEB5 0x742F # 0 +0xCEB6 0x74D8 # 0 +0xCEB7 0x7BA1 # 0 +0xCEB8 0x7F50 # 0 +0xCEB9 0x83C5 # 0 +0xCEBA 0x89C0 # 0 +0xCEBB 0x8CAB # 0 +0xCEBC 0x95DC # 0 +0xCEBD 0x9928 # 0 +0xCEBE 0x522E # 0 +0xCEBF 0x605D # 0 +0xCEC0 0x62EC # 0 +0xCEC1 0x9002 # 0 +0xCEC2 0x4F8A # 0 +0xCEC3 0x5149 # 0 +0xCEC4 0x5321 # 0 +0xCEC5 0x58D9 # 0 +0xCEC6 0x5EE3 # 0 +0xCEC7 0x66E0 # 0 +0xCEC8 0x6D38 # 0 +0xCEC9 0x709A # 0 +0xCECA 0x72C2 # 0 +0xCECB 0x73D6 # 0 +0xCECC 0x7B50 # 0 +0xCECD 0x80F1 # 0 +0xCECE 0x945B # 0 +0xCECF 0x5366 # 0 +0xCED0 0x639B # 0 +0xCED1 0x7F6B # 0 +0xCED2 0x4E56 # 0 +0xCED3 0x5080 # 0 +0xCED4 0x584A # 0 +0xCED5 0x58DE # 0 +0xCED6 0x602A # 0 +0xCED7 0x6127 # 0 +0xCED8 0x62D0 # 0 +0xCED9 0x69D0 # 0 +0xCEDA 0x9B41 # 0 +0xCEDB 0x5B8F # 0 +0xCEDC 0x7D18 # 0 +0xCEDD 0x80B1 # 0 +0xCEDE 0x8F5F # 0 +0xCEDF 0x4EA4 # 0 +0xCEE0 0x50D1 # 0 +0xCEE1 0x54AC # 0 +0xCEE2 0x55AC # 0 +0xCEE3 0x5B0C # 0 +0xCEE4 0x5DA0 # 0 +0xCEE5 0x5DE7 # 0 +0xCEE6 0x652A # 0 +0xCEE7 0x654E # 0 +0xCEE8 0x6821 # 0 +0xCEE9 0x6A4B # 0 +0xCEEA 0x72E1 # 0 +0xCEEB 0x768E # 0 +0xCEEC 0x77EF # 0 +0xCEED 0x7D5E # 0 +0xCEEE 0x7FF9 # 0 +0xCEEF 0x81A0 # 0 +0xCEF0 0x854E # 0 +0xCEF1 0x86DF # 0 +0xCEF2 0x8F03 # 0 +0xCEF3 0x8F4E # 0 +0xCEF4 0x90CA # 0 +0xCEF5 0x9903 # 0 +0xCEF6 0x9A55 # 0 +0xCEF7 0x9BAB # 0 +0xCEF8 0x4E18 # 0 +0xCEF9 0x4E45 # 0 +0xCEFA 0x4E5D # 0 +0xCEFB 0x4EC7 # 0 +0xCEFC 0x4FF1 # 0 +0xCEFD 0x5177 # 0 +0xCEFE 0x52FE # 0 +0xCFA1 0x5340 # 0 +0xCFA2 0x53E3 # 0 +0xCFA3 0x53E5 # 0 +0xCFA4 0x548E # 0 +0xCFA5 0x5614 # 0 +0xCFA6 0x5775 # 0 +0xCFA7 0x57A2 # 0 +0xCFA8 0x5BC7 # 0 +0xCFA9 0x5D87 # 0 +0xCFAA 0x5ED0 # 0 +0xCFAB 0x61FC # 0 +0xCFAC 0x62D8 # 0 +0xCFAD 0x6551 # 0 +0xCFAE 0x67B8 # 0 +0xCFAF 0x67E9 # 0 +0xCFB0 0x69CB # 0 +0xCFB1 0x6B50 # 0 +0xCFB2 0x6BC6 # 0 +0xCFB3 0x6BEC # 0 +0xCFB4 0x6C42 # 0 +0xCFB5 0x6E9D # 0 +0xCFB6 0x7078 # 0 +0xCFB7 0x72D7 # 0 +0xCFB8 0x7396 # 0 +0xCFB9 0x7403 # 0 +0xCFBA 0x77BF # 0 +0xCFBB 0x77E9 # 0 +0xCFBC 0x7A76 # 0 +0xCFBD 0x7D7F # 0 +0xCFBE 0x8009 # 0 +0xCFBF 0x81FC # 0 +0xCFC0 0x8205 # 0 +0xCFC1 0x820A # 0 +0xCFC2 0x82DF # 0 +0xCFC3 0x8862 # 0 +0xCFC4 0x8B33 # 0 +0xCFC5 0x8CFC # 0 +0xCFC6 0x8EC0 # 0 +0xCFC7 0x9011 # 0 +0xCFC8 0x90B1 # 0 +0xCFC9 0x9264 # 0 +0xCFCA 0x92B6 # 0 +0xCFCB 0x99D2 # 0 +0xCFCC 0x9A45 # 0 +0xCFCD 0x9CE9 # 0 +0xCFCE 0x9DD7 # 0 +0xCFCF 0x9F9C # 0 +0xCFD0 0x570B # 0 +0xCFD1 0x5C40 # 0 +0xCFD2 0x83CA # 0 +0xCFD3 0x97A0 # 0 +0xCFD4 0x97AB # 0 +0xCFD5 0x9EB4 # 0 +0xCFD6 0x541B # 0 +0xCFD7 0x7A98 # 0 +0xCFD8 0x7FA4 # 0 +0xCFD9 0x88D9 # 0 +0xCFDA 0x8ECD # 0 +0xCFDB 0x90E1 # 0 +0xCFDC 0x5800 # 0 +0xCFDD 0x5C48 # 0 +0xCFDE 0x6398 # 0 +0xCFDF 0x7A9F # 0 +0xCFE0 0x5BAE # 0 +0xCFE1 0x5F13 # 0 +0xCFE2 0x7A79 # 0 +0xCFE3 0x7AAE # 0 +0xCFE4 0x828E # 0 +0xCFE5 0x8EAC # 0 +0xCFE6 0x5026 # 0 +0xCFE7 0x5238 # 0 +0xCFE8 0x52F8 # 0 +0xCFE9 0x5377 # 0 +0xCFEA 0x5708 # 0 +0xCFEB 0x62F3 # 0 +0xCFEC 0x6372 # 0 +0xCFED 0x6B0A # 0 +0xCFEE 0x6DC3 # 0 +0xCFEF 0x7737 # 0 +0xCFF0 0x53A5 # 0 +0xCFF1 0x7357 # 0 +0xCFF2 0x8568 # 0 +0xCFF3 0x8E76 # 0 +0xCFF4 0x95D5 # 0 +0xCFF5 0x673A # 0 +0xCFF6 0x6AC3 # 0 +0xCFF7 0x6F70 # 0 +0xCFF8 0x8A6D # 0 +0xCFF9 0x8ECC # 0 +0xCFFA 0x994B # 0 +0xCFFB 0xF906 # 0 +0xCFFC 0x6677 # 0 +0xCFFD 0x6B78 # 0 +0xCFFE 0x8CB4 # 0 +0xD0A1 0x9B3C # 0 +0xD0A2 0xF907 # 0 +0xD0A3 0x53EB # 0 +0xD0A4 0x572D # 0 +0xD0A5 0x594E # 0 +0xD0A6 0x63C6 # 0 +0xD0A7 0x69FB # 0 +0xD0A8 0x73EA # 0 +0xD0A9 0x7845 # 0 +0xD0AA 0x7ABA # 0 +0xD0AB 0x7AC5 # 0 +0xD0AC 0x7CFE # 0 +0xD0AD 0x8475 # 0 +0xD0AE 0x898F # 0 +0xD0AF 0x8D73 # 0 +0xD0B0 0x9035 # 0 +0xD0B1 0x95A8 # 0 +0xD0B2 0x52FB # 0 +0xD0B3 0x5747 # 0 +0xD0B4 0x7547 # 0 +0xD0B5 0x7B60 # 0 +0xD0B6 0x83CC # 0 +0xD0B7 0x921E # 0 +0xD0B8 0xF908 # 0 +0xD0B9 0x6A58 # 0 +0xD0BA 0x514B # 0 +0xD0BB 0x524B # 0 +0xD0BC 0x5287 # 0 +0xD0BD 0x621F # 0 +0xD0BE 0x68D8 # 0 +0xD0BF 0x6975 # 0 +0xD0C0 0x9699 # 0 +0xD0C1 0x50C5 # 0 +0xD0C2 0x52A4 # 0 +0xD0C3 0x52E4 # 0 +0xD0C4 0x61C3 # 0 +0xD0C5 0x65A4 # 0 +0xD0C6 0x6839 # 0 +0xD0C7 0x69FF # 0 +0xD0C8 0x747E # 0 +0xD0C9 0x7B4B # 0 +0xD0CA 0x82B9 # 0 +0xD0CB 0x83EB # 0 +0xD0CC 0x89B2 # 0 +0xD0CD 0x8B39 # 0 +0xD0CE 0x8FD1 # 0 +0xD0CF 0x9949 # 0 +0xD0D0 0xF909 # 0 +0xD0D1 0x4ECA # 0 +0xD0D2 0x5997 # 0 +0xD0D3 0x64D2 # 0 +0xD0D4 0x6611 # 0 +0xD0D5 0x6A8E # 0 +0xD0D6 0x7434 # 0 +0xD0D7 0x7981 # 0 +0xD0D8 0x79BD # 0 +0xD0D9 0x82A9 # 0 +0xD0DA 0x887E # 0 +0xD0DB 0x887F # 0 +0xD0DC 0x895F # 0 +0xD0DD 0xF90A # 0 +0xD0DE 0x9326 # 0 +0xD0DF 0x4F0B # 0 +0xD0E0 0x53CA # 0 +0xD0E1 0x6025 # 0 +0xD0E2 0x6271 # 0 +0xD0E3 0x6C72 # 0 +0xD0E4 0x7D1A # 0 +0xD0E5 0x7D66 # 0 +0xD0E6 0x4E98 # 0 +0xD0E7 0x5162 # 0 +0xD0E8 0x77DC # 0 +0xD0E9 0x80AF # 0 +0xD0EA 0x4F01 # 0 +0xD0EB 0x4F0E # 0 +0xD0EC 0x5176 # 0 +0xD0ED 0x5180 # 0 +0xD0EE 0x55DC # 0 +0xD0EF 0x5668 # 0 +0xD0F0 0x573B # 0 +0xD0F1 0x57FA # 0 +0xD0F2 0x57FC # 0 +0xD0F3 0x5914 # 0 +0xD0F4 0x5947 # 0 +0xD0F5 0x5993 # 0 +0xD0F6 0x5BC4 # 0 +0xD0F7 0x5C90 # 0 +0xD0F8 0x5D0E # 0 +0xD0F9 0x5DF1 # 0 +0xD0FA 0x5E7E # 0 +0xD0FB 0x5FCC # 0 +0xD0FC 0x6280 # 0 +0xD0FD 0x65D7 # 0 +0xD0FE 0x65E3 # 0 +0xD1A1 0x671E # 0 +0xD1A2 0x671F # 0 +0xD1A3 0x675E # 0 +0xD1A4 0x68CB # 0 +0xD1A5 0x68C4 # 0 +0xD1A6 0x6A5F # 0 +0xD1A7 0x6B3A # 0 +0xD1A8 0x6C23 # 0 +0xD1A9 0x6C7D # 0 +0xD1AA 0x6C82 # 0 +0xD1AB 0x6DC7 # 0 +0xD1AC 0x7398 # 0 +0xD1AD 0x7426 # 0 +0xD1AE 0x742A # 0 +0xD1AF 0x7482 # 0 +0xD1B0 0x74A3 # 0 +0xD1B1 0x7578 # 0 +0xD1B2 0x757F # 0 +0xD1B3 0x7881 # 0 +0xD1B4 0x78EF # 0 +0xD1B5 0x7941 # 0 +0xD1B6 0x7947 # 0 +0xD1B7 0x7948 # 0 +0xD1B8 0x797A # 0 +0xD1B9 0x7B95 # 0 +0xD1BA 0x7D00 # 0 +0xD1BB 0x7DBA # 0 +0xD1BC 0x7F88 # 0 +0xD1BD 0x8006 # 0 +0xD1BE 0x802D # 0 +0xD1BF 0x808C # 0 +0xD1C0 0x8A18 # 0 +0xD1C1 0x8B4F # 0 +0xD1C2 0x8C48 # 0 +0xD1C3 0x8D77 # 0 +0xD1C4 0x9321 # 0 +0xD1C5 0x9324 # 0 +0xD1C6 0x98E2 # 0 +0xD1C7 0x9951 # 0 +0xD1C8 0x9A0E # 0 +0xD1C9 0x9A0F # 0 +0xD1CA 0x9A65 # 0 +0xD1CB 0x9E92 # 0 +0xD1CC 0x7DCA # 0 +0xD1CD 0x4F76 # 0 +0xD1CE 0x5409 # 0 +0xD1CF 0x62EE # 0 +0xD1D0 0x6854 # 0 +0xD1D1 0x91D1 # 0 +0xD1D2 0x55AB # 0 +0xD1D3 0x513A # 0 +0xD1D4 0xF90B # 0 +0xD1D5 0xF90C # 0 +0xD1D6 0x5A1C # 0 +0xD1D7 0x61E6 # 0 +0xD1D8 0xF90D # 0 +0xD1D9 0x62CF # 0 +0xD1DA 0x62FF # 0 +0xD1DB 0xF90E # 0 +0xD1DC 0xF90F # 0 +0xD1DD 0xF910 # 0 +0xD1DE 0xF911 # 0 +0xD1DF 0xF912 # 0 +0xD1E0 0xF913 # 0 +0xD1E1 0x90A3 # 0 +0xD1E2 0xF914 # 0 +0xD1E3 0xF915 # 0 +0xD1E4 0xF916 # 0 +0xD1E5 0xF917 # 0 +0xD1E6 0xF918 # 0 +0xD1E7 0x8AFE # 0 +0xD1E8 0xF919 # 0 +0xD1E9 0xF91A # 0 +0xD1EA 0xF91B # 0 +0xD1EB 0xF91C # 0 +0xD1EC 0x6696 # 0 +0xD1ED 0xF91D # 0 +0xD1EE 0x7156 # 0 +0xD1EF 0xF91E # 0 +0xD1F0 0xF91F # 0 +0xD1F1 0x96E3 # 0 +0xD1F2 0xF920 # 0 +0xD1F3 0x634F # 0 +0xD1F4 0x637A # 0 +0xD1F5 0x5357 # 0 +0xD1F6 0xF921 # 0 +0xD1F7 0x678F # 0 +0xD1F8 0x6960 # 0 +0xD1F9 0x6E73 # 0 +0xD1FA 0xF922 # 0 +0xD1FB 0x7537 # 0 +0xD1FC 0xF923 # 0 +0xD1FD 0xF924 # 0 +0xD1FE 0xF925 # 0 +0xD2A1 0x7D0D # 0 +0xD2A2 0xF926 # 0 +0xD2A3 0xF927 # 0 +0xD2A4 0x8872 # 0 +0xD2A5 0x56CA # 0 +0xD2A6 0x5A18 # 0 +0xD2A7 0xF928 # 0 +0xD2A8 0xF929 # 0 +0xD2A9 0xF92A # 0 +0xD2AA 0xF92B # 0 +0xD2AB 0xF92C # 0 +0xD2AC 0x4E43 # 0 +0xD2AD 0xF92D # 0 +0xD2AE 0x5167 # 0 +0xD2AF 0x5948 # 0 +0xD2B0 0x67F0 # 0 +0xD2B1 0x8010 # 0 +0xD2B2 0xF92E # 0 +0xD2B3 0x5973 # 0 +0xD2B4 0x5E74 # 0 +0xD2B5 0x649A # 0 +0xD2B6 0x79CA # 0 +0xD2B7 0x5FF5 # 0 +0xD2B8 0x606C # 0 +0xD2B9 0x62C8 # 0 +0xD2BA 0x637B # 0 +0xD2BB 0x5BE7 # 0 +0xD2BC 0x5BD7 # 0 +0xD2BD 0x52AA # 0 +0xD2BE 0xF92F # 0 +0xD2BF 0x5974 # 0 +0xD2C0 0x5F29 # 0 +0xD2C1 0x6012 # 0 +0xD2C2 0xF930 # 0 +0xD2C3 0xF931 # 0 +0xD2C4 0xF932 # 0 +0xD2C5 0x7459 # 0 +0xD2C6 0xF933 # 0 +0xD2C7 0xF934 # 0 +0xD2C8 0xF935 # 0 +0xD2C9 0xF936 # 0 +0xD2CA 0xF937 # 0 +0xD2CB 0xF938 # 0 +0xD2CC 0x99D1 # 0 +0xD2CD 0xF939 # 0 +0xD2CE 0xF93A # 0 +0xD2CF 0xF93B # 0 +0xD2D0 0xF93C # 0 +0xD2D1 0xF93D # 0 +0xD2D2 0xF93E # 0 +0xD2D3 0xF93F # 0 +0xD2D4 0xF940 # 0 +0xD2D5 0xF941 # 0 +0xD2D6 0xF942 # 0 +0xD2D7 0xF943 # 0 +0xD2D8 0x6FC3 # 0 +0xD2D9 0xF944 # 0 +0xD2DA 0xF945 # 0 +0xD2DB 0x81BF # 0 +0xD2DC 0x8FB2 # 0 +0xD2DD 0x60F1 # 0 +0xD2DE 0xF946 # 0 +0xD2DF 0xF947 # 0 +0xD2E0 0x8166 # 0 +0xD2E1 0xF948 # 0 +0xD2E2 0xF949 # 0 +0xD2E3 0x5C3F # 0 +0xD2E4 0xF94A # 0 +0xD2E5 0xF94B # 0 +0xD2E6 0xF94C # 0 +0xD2E7 0xF94D # 0 +0xD2E8 0xF94E # 0 +0xD2E9 0xF94F # 0 +0xD2EA 0xF950 # 0 +0xD2EB 0xF951 # 0 +0xD2EC 0x5AE9 # 0 +0xD2ED 0x8A25 # 0 +0xD2EE 0x677B # 0 +0xD2EF 0x7D10 # 0 +0xD2F0 0xF952 # 0 +0xD2F1 0xF953 # 0 +0xD2F2 0xF954 # 0 +0xD2F3 0xF955 # 0 +0xD2F4 0xF956 # 0 +0xD2F5 0xF957 # 0 +0xD2F6 0x80FD # 0 +0xD2F7 0xF958 # 0 +0xD2F8 0xF959 # 0 +0xD2F9 0x5C3C # 0 +0xD2FA 0x6CE5 # 0 +0xD2FB 0x533F # 0 +0xD2FC 0x6EBA # 0 +0xD2FD 0x591A # 0 +0xD2FE 0x8336 # 0 +0xD3A1 0x4E39 # 0 +0xD3A2 0x4EB6 # 0 +0xD3A3 0x4F46 # 0 +0xD3A4 0x55AE # 0 +0xD3A5 0x5718 # 0 +0xD3A6 0x58C7 # 0 +0xD3A7 0x5F56 # 0 +0xD3A8 0x65B7 # 0 +0xD3A9 0x65E6 # 0 +0xD3AA 0x6A80 # 0 +0xD3AB 0x6BB5 # 0 +0xD3AC 0x6E4D # 0 +0xD3AD 0x77ED # 0 +0xD3AE 0x7AEF # 0 +0xD3AF 0x7C1E # 0 +0xD3B0 0x7DDE # 0 +0xD3B1 0x86CB # 0 +0xD3B2 0x8892 # 0 +0xD3B3 0x9132 # 0 +0xD3B4 0x935B # 0 +0xD3B5 0x64BB # 0 +0xD3B6 0x6FBE # 0 +0xD3B7 0x737A # 0 +0xD3B8 0x75B8 # 0 +0xD3B9 0x9054 # 0 +0xD3BA 0x5556 # 0 +0xD3BB 0x574D # 0 +0xD3BC 0x61BA # 0 +0xD3BD 0x64D4 # 0 +0xD3BE 0x66C7 # 0 +0xD3BF 0x6DE1 # 0 +0xD3C0 0x6E5B # 0 +0xD3C1 0x6F6D # 0 +0xD3C2 0x6FB9 # 0 +0xD3C3 0x75F0 # 0 +0xD3C4 0x8043 # 0 +0xD3C5 0x81BD # 0 +0xD3C6 0x8541 # 0 +0xD3C7 0x8983 # 0 +0xD3C8 0x8AC7 # 0 +0xD3C9 0x8B5A # 0 +0xD3CA 0x931F # 0 +0xD3CB 0x6C93 # 0 +0xD3CC 0x7553 # 0 +0xD3CD 0x7B54 # 0 +0xD3CE 0x8E0F # 0 +0xD3CF 0x905D # 0 +0xD3D0 0x5510 # 0 +0xD3D1 0x5802 # 0 +0xD3D2 0x5858 # 0 +0xD3D3 0x5E62 # 0 +0xD3D4 0x6207 # 0 +0xD3D5 0x649E # 0 +0xD3D6 0x68E0 # 0 +0xD3D7 0x7576 # 0 +0xD3D8 0x7CD6 # 0 +0xD3D9 0x87B3 # 0 +0xD3DA 0x9EE8 # 0 +0xD3DB 0x4EE3 # 0 +0xD3DC 0x5788 # 0 +0xD3DD 0x576E # 0 +0xD3DE 0x5927 # 0 +0xD3DF 0x5C0D # 0 +0xD3E0 0x5CB1 # 0 +0xD3E1 0x5E36 # 0 +0xD3E2 0x5F85 # 0 +0xD3E3 0x6234 # 0 +0xD3E4 0x64E1 # 0 +0xD3E5 0x73B3 # 0 +0xD3E6 0x81FA # 0 +0xD3E7 0x888B # 0 +0xD3E8 0x8CB8 # 0 +0xD3E9 0x968A # 0 +0xD3EA 0x9EDB # 0 +0xD3EB 0x5B85 # 0 +0xD3EC 0x5FB7 # 0 +0xD3ED 0x60B3 # 0 +0xD3EE 0x5012 # 0 +0xD3EF 0x5200 # 0 +0xD3F0 0x5230 # 0 +0xD3F1 0x5716 # 0 +0xD3F2 0x5835 # 0 +0xD3F3 0x5857 # 0 +0xD3F4 0x5C0E # 0 +0xD3F5 0x5C60 # 0 +0xD3F6 0x5CF6 # 0 +0xD3F7 0x5D8B # 0 +0xD3F8 0x5EA6 # 0 +0xD3F9 0x5F92 # 0 +0xD3FA 0x60BC # 0 +0xD3FB 0x6311 # 0 +0xD3FC 0x6389 # 0 +0xD3FD 0x6417 # 0 +0xD3FE 0x6843 # 0 +0xD4A1 0x68F9 # 0 +0xD4A2 0x6AC2 # 0 +0xD4A3 0x6DD8 # 0 +0xD4A4 0x6E21 # 0 +0xD4A5 0x6ED4 # 0 +0xD4A6 0x6FE4 # 0 +0xD4A7 0x71FE # 0 +0xD4A8 0x76DC # 0 +0xD4A9 0x7779 # 0 +0xD4AA 0x79B1 # 0 +0xD4AB 0x7A3B # 0 +0xD4AC 0x8404 # 0 +0xD4AD 0x89A9 # 0 +0xD4AE 0x8CED # 0 +0xD4AF 0x8DF3 # 0 +0xD4B0 0x8E48 # 0 +0xD4B1 0x9003 # 0 +0xD4B2 0x9014 # 0 +0xD4B3 0x9053 # 0 +0xD4B4 0x90FD # 0 +0xD4B5 0x934D # 0 +0xD4B6 0x9676 # 0 +0xD4B7 0x97DC # 0 +0xD4B8 0x6BD2 # 0 +0xD4B9 0x7006 # 0 +0xD4BA 0x7258 # 0 +0xD4BB 0x72A2 # 0 +0xD4BC 0x7368 # 0 +0xD4BD 0x7763 # 0 +0xD4BE 0x79BF # 0 +0xD4BF 0x7BE4 # 0 +0xD4C0 0x7E9B # 0 +0xD4C1 0x8B80 # 0 +0xD4C2 0x58A9 # 0 +0xD4C3 0x60C7 # 0 +0xD4C4 0x6566 # 0 +0xD4C5 0x65FD # 0 +0xD4C6 0x66BE # 0 +0xD4C7 0x6C8C # 0 +0xD4C8 0x711E # 0 +0xD4C9 0x71C9 # 0 +0xD4CA 0x8C5A # 0 +0xD4CB 0x9813 # 0 +0xD4CC 0x4E6D # 0 +0xD4CD 0x7A81 # 0 +0xD4CE 0x4EDD # 0 +0xD4CF 0x51AC # 0 +0xD4D0 0x51CD # 0 +0xD4D1 0x52D5 # 0 +0xD4D2 0x540C # 0 +0xD4D3 0x61A7 # 0 +0xD4D4 0x6771 # 0 +0xD4D5 0x6850 # 0 +0xD4D6 0x68DF # 0 +0xD4D7 0x6D1E # 0 +0xD4D8 0x6F7C # 0 +0xD4D9 0x75BC # 0 +0xD4DA 0x77B3 # 0 +0xD4DB 0x7AE5 # 0 +0xD4DC 0x80F4 # 0 +0xD4DD 0x8463 # 0 +0xD4DE 0x9285 # 0 +0xD4DF 0x515C # 0 +0xD4E0 0x6597 # 0 +0xD4E1 0x675C # 0 +0xD4E2 0x6793 # 0 +0xD4E3 0x75D8 # 0 +0xD4E4 0x7AC7 # 0 +0xD4E5 0x8373 # 0 +0xD4E6 0xF95A # 0 +0xD4E7 0x8C46 # 0 +0xD4E8 0x9017 # 0 +0xD4E9 0x982D # 0 +0xD4EA 0x5C6F # 0 +0xD4EB 0x81C0 # 0 +0xD4EC 0x829A # 0 +0xD4ED 0x9041 # 0 +0xD4EE 0x906F # 0 +0xD4EF 0x920D # 0 +0xD4F0 0x5F97 # 0 +0xD4F1 0x5D9D # 0 +0xD4F2 0x6A59 # 0 +0xD4F3 0x71C8 # 0 +0xD4F4 0x767B # 0 +0xD4F5 0x7B49 # 0 +0xD4F6 0x85E4 # 0 +0xD4F7 0x8B04 # 0 +0xD4F8 0x9127 # 0 +0xD4F9 0x9A30 # 0 +0xD4FA 0x5587 # 0 +0xD4FB 0x61F6 # 0 +0xD4FC 0xF95B # 0 +0xD4FD 0x7669 # 0 +0xD4FE 0x7F85 # 0 +0xD5A1 0x863F # 0 +0xD5A2 0x87BA # 0 +0xD5A3 0x88F8 # 0 +0xD5A4 0x908F # 0 +0xD5A5 0xF95C # 0 +0xD5A6 0x6D1B # 0 +0xD5A7 0x70D9 # 0 +0xD5A8 0x73DE # 0 +0xD5A9 0x7D61 # 0 +0xD5AA 0x843D # 0 +0xD5AB 0xF95D # 0 +0xD5AC 0x916A # 0 +0xD5AD 0x99F1 # 0 +0xD5AE 0xF95E # 0 +0xD5AF 0x4E82 # 0 +0xD5B0 0x5375 # 0 +0xD5B1 0x6B04 # 0 +0xD5B2 0x6B12 # 0 +0xD5B3 0x703E # 0 +0xD5B4 0x721B # 0 +0xD5B5 0x862D # 0 +0xD5B6 0x9E1E # 0 +0xD5B7 0x524C # 0 +0xD5B8 0x8FA3 # 0 +0xD5B9 0x5D50 # 0 +0xD5BA 0x64E5 # 0 +0xD5BB 0x652C # 0 +0xD5BC 0x6B16 # 0 +0xD5BD 0x6FEB # 0 +0xD5BE 0x7C43 # 0 +0xD5BF 0x7E9C # 0 +0xD5C0 0x85CD # 0 +0xD5C1 0x8964 # 0 +0xD5C2 0x89BD # 0 +0xD5C3 0x62C9 # 0 +0xD5C4 0x81D8 # 0 +0xD5C5 0x881F # 0 +0xD5C6 0x5ECA # 0 +0xD5C7 0x6717 # 0 +0xD5C8 0x6D6A # 0 +0xD5C9 0x72FC # 0 +0xD5CA 0x7405 # 0 +0xD5CB 0x746F # 0 +0xD5CC 0x8782 # 0 +0xD5CD 0x90DE # 0 +0xD5CE 0x4F86 # 0 +0xD5CF 0x5D0D # 0 +0xD5D0 0x5FA0 # 0 +0xD5D1 0x840A # 0 +0xD5D2 0x51B7 # 0 +0xD5D3 0x63A0 # 0 +0xD5D4 0x7565 # 0 +0xD5D5 0x4EAE # 0 +0xD5D6 0x5006 # 0 +0xD5D7 0x5169 # 0 +0xD5D8 0x51C9 # 0 +0xD5D9 0x6881 # 0 +0xD5DA 0x6A11 # 0 +0xD5DB 0x7CAE # 0 +0xD5DC 0x7CB1 # 0 +0xD5DD 0x7CE7 # 0 +0xD5DE 0x826F # 0 +0xD5DF 0x8AD2 # 0 +0xD5E0 0x8F1B # 0 +0xD5E1 0x91CF # 0 +0xD5E2 0x4FB6 # 0 +0xD5E3 0x5137 # 0 +0xD5E4 0x52F5 # 0 +0xD5E5 0x5442 # 0 +0xD5E6 0x5EEC # 0 +0xD5E7 0x616E # 0 +0xD5E8 0x623E # 0 +0xD5E9 0x65C5 # 0 +0xD5EA 0x6ADA # 0 +0xD5EB 0x6FFE # 0 +0xD5EC 0x792A # 0 +0xD5ED 0x85DC # 0 +0xD5EE 0x8823 # 0 +0xD5EF 0x95AD # 0 +0xD5F0 0x9A62 # 0 +0xD5F1 0x9A6A # 0 +0xD5F2 0x9E97 # 0 +0xD5F3 0x9ECE # 0 +0xD5F4 0x529B # 0 +0xD5F5 0x66C6 # 0 +0xD5F6 0x6B77 # 0 +0xD5F7 0x701D # 0 +0xD5F8 0x792B # 0 +0xD5F9 0x8F62 # 0 +0xD5FA 0x9742 # 0 +0xD5FB 0x6190 # 0 +0xD5FC 0x6200 # 0 +0xD5FD 0x6523 # 0 +0xD5FE 0x6F23 # 0 +0xD6A1 0x7149 # 0 +0xD6A2 0x7489 # 0 +0xD6A3 0x7DF4 # 0 +0xD6A4 0x806F # 0 +0xD6A5 0x84EE # 0 +0xD6A6 0x8F26 # 0 +0xD6A7 0x9023 # 0 +0xD6A8 0x934A # 0 +0xD6A9 0x51BD # 0 +0xD6AA 0x5217 # 0 +0xD6AB 0x52A3 # 0 +0xD6AC 0x6D0C # 0 +0xD6AD 0x70C8 # 0 +0xD6AE 0x88C2 # 0 +0xD6AF 0x5EC9 # 0 +0xD6B0 0x6582 # 0 +0xD6B1 0x6BAE # 0 +0xD6B2 0x6FC2 # 0 +0xD6B3 0x7C3E # 0 +0xD6B4 0x7375 # 0 +0xD6B5 0x4EE4 # 0 +0xD6B6 0x4F36 # 0 +0xD6B7 0x56F9 # 0 +0xD6B8 0xF95F # 0 +0xD6B9 0x5CBA # 0 +0xD6BA 0x5DBA # 0 +0xD6BB 0x601C # 0 +0xD6BC 0x73B2 # 0 +0xD6BD 0x7B2D # 0 +0xD6BE 0x7F9A # 0 +0xD6BF 0x7FCE # 0 +0xD6C0 0x8046 # 0 +0xD6C1 0x901E # 0 +0xD6C2 0x9234 # 0 +0xD6C3 0x96F6 # 0 +0xD6C4 0x9748 # 0 +0xD6C5 0x9818 # 0 +0xD6C6 0x9F61 # 0 +0xD6C7 0x4F8B # 0 +0xD6C8 0x6FA7 # 0 +0xD6C9 0x79AE # 0 +0xD6CA 0x91B4 # 0 +0xD6CB 0x96B7 # 0 +0xD6CC 0x52DE # 0 +0xD6CD 0xF960 # 0 +0xD6CE 0x6488 # 0 +0xD6CF 0x64C4 # 0 +0xD6D0 0x6AD3 # 0 +0xD6D1 0x6F5E # 0 +0xD6D2 0x7018 # 0 +0xD6D3 0x7210 # 0 +0xD6D4 0x76E7 # 0 +0xD6D5 0x8001 # 0 +0xD6D6 0x8606 # 0 +0xD6D7 0x865C # 0 +0xD6D8 0x8DEF # 0 +0xD6D9 0x8F05 # 0 +0xD6DA 0x9732 # 0 +0xD6DB 0x9B6F # 0 +0xD6DC 0x9DFA # 0 +0xD6DD 0x9E75 # 0 +0xD6DE 0x788C # 0 +0xD6DF 0x797F # 0 +0xD6E0 0x7DA0 # 0 +0xD6E1 0x83C9 # 0 +0xD6E2 0x9304 # 0 +0xD6E3 0x9E7F # 0 +0xD6E4 0x9E93 # 0 +0xD6E5 0x8AD6 # 0 +0xD6E6 0x58DF # 0 +0xD6E7 0x5F04 # 0 +0xD6E8 0x6727 # 0 +0xD6E9 0x7027 # 0 +0xD6EA 0x74CF # 0 +0xD6EB 0x7C60 # 0 +0xD6EC 0x807E # 0 +0xD6ED 0x5121 # 0 +0xD6EE 0x7028 # 0 +0xD6EF 0x7262 # 0 +0xD6F0 0x78CA # 0 +0xD6F1 0x8CC2 # 0 +0xD6F2 0x8CDA # 0 +0xD6F3 0x8CF4 # 0 +0xD6F4 0x96F7 # 0 +0xD6F5 0x4E86 # 0 +0xD6F6 0x50DA # 0 +0xD6F7 0x5BEE # 0 +0xD6F8 0x5ED6 # 0 +0xD6F9 0x6599 # 0 +0xD6FA 0x71CE # 0 +0xD6FB 0x7642 # 0 +0xD6FC 0x77AD # 0 +0xD6FD 0x804A # 0 +0xD6FE 0x84FC # 0 +0xD7A1 0x907C # 0 +0xD7A2 0x9B27 # 0 +0xD7A3 0x9F8D # 0 +0xD7A4 0x58D8 # 0 +0xD7A5 0x5A41 # 0 +0xD7A6 0x5C62 # 0 +0xD7A7 0x6A13 # 0 +0xD7A8 0x6DDA # 0 +0xD7A9 0x6F0F # 0 +0xD7AA 0x763B # 0 +0xD7AB 0x7D2F # 0 +0xD7AC 0x7E37 # 0 +0xD7AD 0x851E # 0 +0xD7AE 0x8938 # 0 +0xD7AF 0x93E4 # 0 +0xD7B0 0x964B # 0 +0xD7B1 0x5289 # 0 +0xD7B2 0x65D2 # 0 +0xD7B3 0x67F3 # 0 +0xD7B4 0x69B4 # 0 +0xD7B5 0x6D41 # 0 +0xD7B6 0x6E9C # 0 +0xD7B7 0x700F # 0 +0xD7B8 0x7409 # 0 +0xD7B9 0x7460 # 0 +0xD7BA 0x7559 # 0 +0xD7BB 0x7624 # 0 +0xD7BC 0x786B # 0 +0xD7BD 0x8B2C # 0 +0xD7BE 0x985E # 0 +0xD7BF 0x516D # 0 +0xD7C0 0x622E # 0 +0xD7C1 0x9678 # 0 +0xD7C2 0x4F96 # 0 +0xD7C3 0x502B # 0 +0xD7C4 0x5D19 # 0 +0xD7C5 0x6DEA # 0 +0xD7C6 0x7DB8 # 0 +0xD7C7 0x8F2A # 0 +0xD7C8 0x5F8B # 0 +0xD7C9 0x6144 # 0 +0xD7CA 0x6817 # 0 +0xD7CB 0xF961 # 0 +0xD7CC 0x9686 # 0 +0xD7CD 0x52D2 # 0 +0xD7CE 0x808B # 0 +0xD7CF 0x51DC # 0 +0xD7D0 0x51CC # 0 +0xD7D1 0x695E # 0 +0xD7D2 0x7A1C # 0 +0xD7D3 0x7DBE # 0 +0xD7D4 0x83F1 # 0 +0xD7D5 0x9675 # 0 +0xD7D6 0x4FDA # 0 +0xD7D7 0x5229 # 0 +0xD7D8 0x5398 # 0 +0xD7D9 0x540F # 0 +0xD7DA 0x550E # 0 +0xD7DB 0x5C65 # 0 +0xD7DC 0x60A7 # 0 +0xD7DD 0x674E # 0 +0xD7DE 0x68A8 # 0 +0xD7DF 0x6D6C # 0 +0xD7E0 0x7281 # 0 +0xD7E1 0x72F8 # 0 +0xD7E2 0x7406 # 0 +0xD7E3 0x7483 # 0 +0xD7E4 0xF962 # 0 +0xD7E5 0x75E2 # 0 +0xD7E6 0x7C6C # 0 +0xD7E7 0x7F79 # 0 +0xD7E8 0x7FB8 # 0 +0xD7E9 0x8389 # 0 +0xD7EA 0x88CF # 0 +0xD7EB 0x88E1 # 0 +0xD7EC 0x91CC # 0 +0xD7ED 0x91D0 # 0 +0xD7EE 0x96E2 # 0 +0xD7EF 0x9BC9 # 0 +0xD7F0 0x541D # 0 +0xD7F1 0x6F7E # 0 +0xD7F2 0x71D0 # 0 +0xD7F3 0x7498 # 0 +0xD7F4 0x85FA # 0 +0xD7F5 0x8EAA # 0 +0xD7F6 0x96A3 # 0 +0xD7F7 0x9C57 # 0 +0xD7F8 0x9E9F # 0 +0xD7F9 0x6797 # 0 +0xD7FA 0x6DCB # 0 +0xD7FB 0x7433 # 0 +0xD7FC 0x81E8 # 0 +0xD7FD 0x9716 # 0 +0xD7FE 0x782C # 0 +0xD8A1 0x7ACB # 0 +0xD8A2 0x7B20 # 0 +0xD8A3 0x7C92 # 0 +0xD8A4 0x6469 # 0 +0xD8A5 0x746A # 0 +0xD8A6 0x75F2 # 0 +0xD8A7 0x78BC # 0 +0xD8A8 0x78E8 # 0 +0xD8A9 0x99AC # 0 +0xD8AA 0x9B54 # 0 +0xD8AB 0x9EBB # 0 +0xD8AC 0x5BDE # 0 +0xD8AD 0x5E55 # 0 +0xD8AE 0x6F20 # 0 +0xD8AF 0x819C # 0 +0xD8B0 0x83AB # 0 +0xD8B1 0x9088 # 0 +0xD8B2 0x4E07 # 0 +0xD8B3 0x534D # 0 +0xD8B4 0x5A29 # 0 +0xD8B5 0x5DD2 # 0 +0xD8B6 0x5F4E # 0 +0xD8B7 0x6162 # 0 +0xD8B8 0x633D # 0 +0xD8B9 0x6669 # 0 +0xD8BA 0x66FC # 0 +0xD8BB 0x6EFF # 0 +0xD8BC 0x6F2B # 0 +0xD8BD 0x7063 # 0 +0xD8BE 0x779E # 0 +0xD8BF 0x842C # 0 +0xD8C0 0x8513 # 0 +0xD8C1 0x883B # 0 +0xD8C2 0x8F13 # 0 +0xD8C3 0x9945 # 0 +0xD8C4 0x9C3B # 0 +0xD8C5 0x551C # 0 +0xD8C6 0x62B9 # 0 +0xD8C7 0x672B # 0 +0xD8C8 0x6CAB # 0 +0xD8C9 0x8309 # 0 +0xD8CA 0x896A # 0 +0xD8CB 0x977A # 0 +0xD8CC 0x4EA1 # 0 +0xD8CD 0x5984 # 0 +0xD8CE 0x5FD8 # 0 +0xD8CF 0x5FD9 # 0 +0xD8D0 0x671B # 0 +0xD8D1 0x7DB2 # 0 +0xD8D2 0x7F54 # 0 +0xD8D3 0x8292 # 0 +0xD8D4 0x832B # 0 +0xD8D5 0x83BD # 0 +0xD8D6 0x8F1E # 0 +0xD8D7 0x9099 # 0 +0xD8D8 0x57CB # 0 +0xD8D9 0x59B9 # 0 +0xD8DA 0x5A92 # 0 +0xD8DB 0x5BD0 # 0 +0xD8DC 0x6627 # 0 +0xD8DD 0x679A # 0 +0xD8DE 0x6885 # 0 +0xD8DF 0x6BCF # 0 +0xD8E0 0x7164 # 0 +0xD8E1 0x7F75 # 0 +0xD8E2 0x8CB7 # 0 +0xD8E3 0x8CE3 # 0 +0xD8E4 0x9081 # 0 +0xD8E5 0x9B45 # 0 +0xD8E6 0x8108 # 0 +0xD8E7 0x8C8A # 0 +0xD8E8 0x964C # 0 +0xD8E9 0x9A40 # 0 +0xD8EA 0x9EA5 # 0 +0xD8EB 0x5B5F # 0 +0xD8EC 0x6C13 # 0 +0xD8ED 0x731B # 0 +0xD8EE 0x76F2 # 0 +0xD8EF 0x76DF # 0 +0xD8F0 0x840C # 0 +0xD8F1 0x51AA # 0 +0xD8F2 0x8993 # 0 +0xD8F3 0x514D # 0 +0xD8F4 0x5195 # 0 +0xD8F5 0x52C9 # 0 +0xD8F6 0x68C9 # 0 +0xD8F7 0x6C94 # 0 +0xD8F8 0x7704 # 0 +0xD8F9 0x7720 # 0 +0xD8FA 0x7DBF # 0 +0xD8FB 0x7DEC # 0 +0xD8FC 0x9762 # 0 +0xD8FD 0x9EB5 # 0 +0xD8FE 0x6EC5 # 0 +0xD9A1 0x8511 # 0 +0xD9A2 0x51A5 # 0 +0xD9A3 0x540D # 0 +0xD9A4 0x547D # 0 +0xD9A5 0x660E # 0 +0xD9A6 0x669D # 0 +0xD9A7 0x6927 # 0 +0xD9A8 0x6E9F # 0 +0xD9A9 0x76BF # 0 +0xD9AA 0x7791 # 0 +0xD9AB 0x8317 # 0 +0xD9AC 0x84C2 # 0 +0xD9AD 0x879F # 0 +0xD9AE 0x9169 # 0 +0xD9AF 0x9298 # 0 +0xD9B0 0x9CF4 # 0 +0xD9B1 0x8882 # 0 +0xD9B2 0x4FAE # 0 +0xD9B3 0x5192 # 0 +0xD9B4 0x52DF # 0 +0xD9B5 0x59C6 # 0 +0xD9B6 0x5E3D # 0 +0xD9B7 0x6155 # 0 +0xD9B8 0x6478 # 0 +0xD9B9 0x6479 # 0 +0xD9BA 0x66AE # 0 +0xD9BB 0x67D0 # 0 +0xD9BC 0x6A21 # 0 +0xD9BD 0x6BCD # 0 +0xD9BE 0x6BDB # 0 +0xD9BF 0x725F # 0 +0xD9C0 0x7261 # 0 +0xD9C1 0x7441 # 0 +0xD9C2 0x7738 # 0 +0xD9C3 0x77DB # 0 +0xD9C4 0x8017 # 0 +0xD9C5 0x82BC # 0 +0xD9C6 0x8305 # 0 +0xD9C7 0x8B00 # 0 +0xD9C8 0x8B28 # 0 +0xD9C9 0x8C8C # 0 +0xD9CA 0x6728 # 0 +0xD9CB 0x6C90 # 0 +0xD9CC 0x7267 # 0 +0xD9CD 0x76EE # 0 +0xD9CE 0x7766 # 0 +0xD9CF 0x7A46 # 0 +0xD9D0 0x9DA9 # 0 +0xD9D1 0x6B7F # 0 +0xD9D2 0x6C92 # 0 +0xD9D3 0x5922 # 0 +0xD9D4 0x6726 # 0 +0xD9D5 0x8499 # 0 +0xD9D6 0x536F # 0 +0xD9D7 0x5893 # 0 +0xD9D8 0x5999 # 0 +0xD9D9 0x5EDF # 0 +0xD9DA 0x63CF # 0 +0xD9DB 0x6634 # 0 +0xD9DC 0x6773 # 0 +0xD9DD 0x6E3A # 0 +0xD9DE 0x732B # 0 +0xD9DF 0x7AD7 # 0 +0xD9E0 0x82D7 # 0 +0xD9E1 0x9328 # 0 +0xD9E2 0x52D9 # 0 +0xD9E3 0x5DEB # 0 +0xD9E4 0x61AE # 0 +0xD9E5 0x61CB # 0 +0xD9E6 0x620A # 0 +0xD9E7 0x62C7 # 0 +0xD9E8 0x64AB # 0 +0xD9E9 0x65E0 # 0 +0xD9EA 0x6959 # 0 +0xD9EB 0x6B66 # 0 +0xD9EC 0x6BCB # 0 +0xD9ED 0x7121 # 0 +0xD9EE 0x73F7 # 0 +0xD9EF 0x755D # 0 +0xD9F0 0x7E46 # 0 +0xD9F1 0x821E # 0 +0xD9F2 0x8302 # 0 +0xD9F3 0x856A # 0 +0xD9F4 0x8AA3 # 0 +0xD9F5 0x8CBF # 0 +0xD9F6 0x9727 # 0 +0xD9F7 0x9D61 # 0 +0xD9F8 0x58A8 # 0 +0xD9F9 0x9ED8 # 0 +0xD9FA 0x5011 # 0 +0xD9FB 0x520E # 0 +0xD9FC 0x543B # 0 +0xD9FD 0x554F # 0 +0xD9FE 0x6587 # 0 +0xDAA1 0x6C76 # 0 +0xDAA2 0x7D0A # 0 +0xDAA3 0x7D0B # 0 +0xDAA4 0x805E # 0 +0xDAA5 0x868A # 0 +0xDAA6 0x9580 # 0 +0xDAA7 0x96EF # 0 +0xDAA8 0x52FF # 0 +0xDAA9 0x6C95 # 0 +0xDAAA 0x7269 # 0 +0xDAAB 0x5473 # 0 +0xDAAC 0x5A9A # 0 +0xDAAD 0x5C3E # 0 +0xDAAE 0x5D4B # 0 +0xDAAF 0x5F4C # 0 +0xDAB0 0x5FAE # 0 +0xDAB1 0x672A # 0 +0xDAB2 0x68B6 # 0 +0xDAB3 0x6963 # 0 +0xDAB4 0x6E3C # 0 +0xDAB5 0x6E44 # 0 +0xDAB6 0x7709 # 0 +0xDAB7 0x7C73 # 0 +0xDAB8 0x7F8E # 0 +0xDAB9 0x8587 # 0 +0xDABA 0x8B0E # 0 +0xDABB 0x8FF7 # 0 +0xDABC 0x9761 # 0 +0xDABD 0x9EF4 # 0 +0xDABE 0x5CB7 # 0 +0xDABF 0x60B6 # 0 +0xDAC0 0x610D # 0 +0xDAC1 0x61AB # 0 +0xDAC2 0x654F # 0 +0xDAC3 0x65FB # 0 +0xDAC4 0x65FC # 0 +0xDAC5 0x6C11 # 0 +0xDAC6 0x6CEF # 0 +0xDAC7 0x739F # 0 +0xDAC8 0x73C9 # 0 +0xDAC9 0x7DE1 # 0 +0xDACA 0x9594 # 0 +0xDACB 0x5BC6 # 0 +0xDACC 0x871C # 0 +0xDACD 0x8B10 # 0 +0xDACE 0x525D # 0 +0xDACF 0x535A # 0 +0xDAD0 0x62CD # 0 +0xDAD1 0x640F # 0 +0xDAD2 0x64B2 # 0 +0xDAD3 0x6734 # 0 +0xDAD4 0x6A38 # 0 +0xDAD5 0x6CCA # 0 +0xDAD6 0x73C0 # 0 +0xDAD7 0x749E # 0 +0xDAD8 0x7B94 # 0 +0xDAD9 0x7C95 # 0 +0xDADA 0x7E1B # 0 +0xDADB 0x818A # 0 +0xDADC 0x8236 # 0 +0xDADD 0x8584 # 0 +0xDADE 0x8FEB # 0 +0xDADF 0x96F9 # 0 +0xDAE0 0x99C1 # 0 +0xDAE1 0x4F34 # 0 +0xDAE2 0x534A # 0 +0xDAE3 0x53CD # 0 +0xDAE4 0x53DB # 0 +0xDAE5 0x62CC # 0 +0xDAE6 0x642C # 0 +0xDAE7 0x6500 # 0 +0xDAE8 0x6591 # 0 +0xDAE9 0x69C3 # 0 +0xDAEA 0x6CEE # 0 +0xDAEB 0x6F58 # 0 +0xDAEC 0x73ED # 0 +0xDAED 0x7554 # 0 +0xDAEE 0x7622 # 0 +0xDAEF 0x76E4 # 0 +0xDAF0 0x76FC # 0 +0xDAF1 0x78D0 # 0 +0xDAF2 0x78FB # 0 +0xDAF3 0x792C # 0 +0xDAF4 0x7D46 # 0 +0xDAF5 0x822C # 0 +0xDAF6 0x87E0 # 0 +0xDAF7 0x8FD4 # 0 +0xDAF8 0x9812 # 0 +0xDAF9 0x98EF # 0 +0xDAFA 0x52C3 # 0 +0xDAFB 0x62D4 # 0 +0xDAFC 0x64A5 # 0 +0xDAFD 0x6E24 # 0 +0xDAFE 0x6F51 # 0 +0xDBA1 0x767C # 0 +0xDBA2 0x8DCB # 0 +0xDBA3 0x91B1 # 0 +0xDBA4 0x9262 # 0 +0xDBA5 0x9AEE # 0 +0xDBA6 0x9B43 # 0 +0xDBA7 0x5023 # 0 +0xDBA8 0x508D # 0 +0xDBA9 0x574A # 0 +0xDBAA 0x59A8 # 0 +0xDBAB 0x5C28 # 0 +0xDBAC 0x5E47 # 0 +0xDBAD 0x5F77 # 0 +0xDBAE 0x623F # 0 +0xDBAF 0x653E # 0 +0xDBB0 0x65B9 # 0 +0xDBB1 0x65C1 # 0 +0xDBB2 0x6609 # 0 +0xDBB3 0x678B # 0 +0xDBB4 0x699C # 0 +0xDBB5 0x6EC2 # 0 +0xDBB6 0x78C5 # 0 +0xDBB7 0x7D21 # 0 +0xDBB8 0x80AA # 0 +0xDBB9 0x8180 # 0 +0xDBBA 0x822B # 0 +0xDBBB 0x82B3 # 0 +0xDBBC 0x84A1 # 0 +0xDBBD 0x868C # 0 +0xDBBE 0x8A2A # 0 +0xDBBF 0x8B17 # 0 +0xDBC0 0x90A6 # 0 +0xDBC1 0x9632 # 0 +0xDBC2 0x9F90 # 0 +0xDBC3 0x500D # 0 +0xDBC4 0x4FF3 # 0 +0xDBC5 0xF963 # 0 +0xDBC6 0x57F9 # 0 +0xDBC7 0x5F98 # 0 +0xDBC8 0x62DC # 0 +0xDBC9 0x6392 # 0 +0xDBCA 0x676F # 0 +0xDBCB 0x6E43 # 0 +0xDBCC 0x7119 # 0 +0xDBCD 0x76C3 # 0 +0xDBCE 0x80CC # 0 +0xDBCF 0x80DA # 0 +0xDBD0 0x88F4 # 0 +0xDBD1 0x88F5 # 0 +0xDBD2 0x8919 # 0 +0xDBD3 0x8CE0 # 0 +0xDBD4 0x8F29 # 0 +0xDBD5 0x914D # 0 +0xDBD6 0x966A # 0 +0xDBD7 0x4F2F # 0 +0xDBD8 0x4F70 # 0 +0xDBD9 0x5E1B # 0 +0xDBDA 0x67CF # 0 +0xDBDB 0x6822 # 0 +0xDBDC 0x767D # 0 +0xDBDD 0x767E # 0 +0xDBDE 0x9B44 # 0 +0xDBDF 0x5E61 # 0 +0xDBE0 0x6A0A # 0 +0xDBE1 0x7169 # 0 +0xDBE2 0x71D4 # 0 +0xDBE3 0x756A # 0 +0xDBE4 0xF964 # 0 +0xDBE5 0x7E41 # 0 +0xDBE6 0x8543 # 0 +0xDBE7 0x85E9 # 0 +0xDBE8 0x98DC # 0 +0xDBE9 0x4F10 # 0 +0xDBEA 0x7B4F # 0 +0xDBEB 0x7F70 # 0 +0xDBEC 0x95A5 # 0 +0xDBED 0x51E1 # 0 +0xDBEE 0x5E06 # 0 +0xDBEF 0x68B5 # 0 +0xDBF0 0x6C3E # 0 +0xDBF1 0x6C4E # 0 +0xDBF2 0x6CDB # 0 +0xDBF3 0x72AF # 0 +0xDBF4 0x7BC4 # 0 +0xDBF5 0x8303 # 0 +0xDBF6 0x6CD5 # 0 +0xDBF7 0x743A # 0 +0xDBF8 0x50FB # 0 +0xDBF9 0x5288 # 0 +0xDBFA 0x58C1 # 0 +0xDBFB 0x64D8 # 0 +0xDBFC 0x6A97 # 0 +0xDBFD 0x74A7 # 0 +0xDBFE 0x7656 # 0 +0xDCA1 0x78A7 # 0 +0xDCA2 0x8617 # 0 +0xDCA3 0x95E2 # 0 +0xDCA4 0x9739 # 0 +0xDCA5 0xF965 # 0 +0xDCA6 0x535E # 0 +0xDCA7 0x5F01 # 0 +0xDCA8 0x8B8A # 0 +0xDCA9 0x8FA8 # 0 +0xDCAA 0x8FAF # 0 +0xDCAB 0x908A # 0 +0xDCAC 0x5225 # 0 +0xDCAD 0x77A5 # 0 +0xDCAE 0x9C49 # 0 +0xDCAF 0x9F08 # 0 +0xDCB0 0x4E19 # 0 +0xDCB1 0x5002 # 0 +0xDCB2 0x5175 # 0 +0xDCB3 0x5C5B # 0 +0xDCB4 0x5E77 # 0 +0xDCB5 0x661E # 0 +0xDCB6 0x663A # 0 +0xDCB7 0x67C4 # 0 +0xDCB8 0x68C5 # 0 +0xDCB9 0x70B3 # 0 +0xDCBA 0x7501 # 0 +0xDCBB 0x75C5 # 0 +0xDCBC 0x79C9 # 0 +0xDCBD 0x7ADD # 0 +0xDCBE 0x8F27 # 0 +0xDCBF 0x9920 # 0 +0xDCC0 0x9A08 # 0 +0xDCC1 0x4FDD # 0 +0xDCC2 0x5821 # 0 +0xDCC3 0x5831 # 0 +0xDCC4 0x5BF6 # 0 +0xDCC5 0x666E # 0 +0xDCC6 0x6B65 # 0 +0xDCC7 0x6D11 # 0 +0xDCC8 0x6E7A # 0 +0xDCC9 0x6F7D # 0 +0xDCCA 0x73E4 # 0 +0xDCCB 0x752B # 0 +0xDCCC 0x83E9 # 0 +0xDCCD 0x88DC # 0 +0xDCCE 0x8913 # 0 +0xDCCF 0x8B5C # 0 +0xDCD0 0x8F14 # 0 +0xDCD1 0x4F0F # 0 +0xDCD2 0x50D5 # 0 +0xDCD3 0x5310 # 0 +0xDCD4 0x535C # 0 +0xDCD5 0x5B93 # 0 +0xDCD6 0x5FA9 # 0 +0xDCD7 0x670D # 0 +0xDCD8 0x798F # 0 +0xDCD9 0x8179 # 0 +0xDCDA 0x832F # 0 +0xDCDB 0x8514 # 0 +0xDCDC 0x8907 # 0 +0xDCDD 0x8986 # 0 +0xDCDE 0x8F39 # 0 +0xDCDF 0x8F3B # 0 +0xDCE0 0x99A5 # 0 +0xDCE1 0x9C12 # 0 +0xDCE2 0x672C # 0 +0xDCE3 0x4E76 # 0 +0xDCE4 0x4FF8 # 0 +0xDCE5 0x5949 # 0 +0xDCE6 0x5C01 # 0 +0xDCE7 0x5CEF # 0 +0xDCE8 0x5CF0 # 0 +0xDCE9 0x6367 # 0 +0xDCEA 0x68D2 # 0 +0xDCEB 0x70FD # 0 +0xDCEC 0x71A2 # 0 +0xDCED 0x742B # 0 +0xDCEE 0x7E2B # 0 +0xDCEF 0x84EC # 0 +0xDCF0 0x8702 # 0 +0xDCF1 0x9022 # 0 +0xDCF2 0x92D2 # 0 +0xDCF3 0x9CF3 # 0 +0xDCF4 0x4E0D # 0 +0xDCF5 0x4ED8 # 0 +0xDCF6 0x4FEF # 0 +0xDCF7 0x5085 # 0 +0xDCF8 0x5256 # 0 +0xDCF9 0x526F # 0 +0xDCFA 0x5426 # 0 +0xDCFB 0x5490 # 0 +0xDCFC 0x57E0 # 0 +0xDCFD 0x592B # 0 +0xDCFE 0x5A66 # 0 +0xDDA1 0x5B5A # 0 +0xDDA2 0x5B75 # 0 +0xDDA3 0x5BCC # 0 +0xDDA4 0x5E9C # 0 +0xDDA5 0xF966 # 0 +0xDDA6 0x6276 # 0 +0xDDA7 0x6577 # 0 +0xDDA8 0x65A7 # 0 +0xDDA9 0x6D6E # 0 +0xDDAA 0x6EA5 # 0 +0xDDAB 0x7236 # 0 +0xDDAC 0x7B26 # 0 +0xDDAD 0x7C3F # 0 +0xDDAE 0x7F36 # 0 +0xDDAF 0x8150 # 0 +0xDDB0 0x8151 # 0 +0xDDB1 0x819A # 0 +0xDDB2 0x8240 # 0 +0xDDB3 0x8299 # 0 +0xDDB4 0x83A9 # 0 +0xDDB5 0x8A03 # 0 +0xDDB6 0x8CA0 # 0 +0xDDB7 0x8CE6 # 0 +0xDDB8 0x8CFB # 0 +0xDDB9 0x8D74 # 0 +0xDDBA 0x8DBA # 0 +0xDDBB 0x90E8 # 0 +0xDDBC 0x91DC # 0 +0xDDBD 0x961C # 0 +0xDDBE 0x9644 # 0 +0xDDBF 0x99D9 # 0 +0xDDC0 0x9CE7 # 0 +0xDDC1 0x5317 # 0 +0xDDC2 0x5206 # 0 +0xDDC3 0x5429 # 0 +0xDDC4 0x5674 # 0 +0xDDC5 0x58B3 # 0 +0xDDC6 0x5954 # 0 +0xDDC7 0x596E # 0 +0xDDC8 0x5FFF # 0 +0xDDC9 0x61A4 # 0 +0xDDCA 0x626E # 0 +0xDDCB 0x6610 # 0 +0xDDCC 0x6C7E # 0 +0xDDCD 0x711A # 0 +0xDDCE 0x76C6 # 0 +0xDDCF 0x7C89 # 0 +0xDDD0 0x7CDE # 0 +0xDDD1 0x7D1B # 0 +0xDDD2 0x82AC # 0 +0xDDD3 0x8CC1 # 0 +0xDDD4 0x96F0 # 0 +0xDDD5 0xF967 # 0 +0xDDD6 0x4F5B # 0 +0xDDD7 0x5F17 # 0 +0xDDD8 0x5F7F # 0 +0xDDD9 0x62C2 # 0 +0xDDDA 0x5D29 # 0 +0xDDDB 0x670B # 0 +0xDDDC 0x68DA # 0 +0xDDDD 0x787C # 0 +0xDDDE 0x7E43 # 0 +0xDDDF 0x9D6C # 0 +0xDDE0 0x4E15 # 0 +0xDDE1 0x5099 # 0 +0xDDE2 0x5315 # 0 +0xDDE3 0x532A # 0 +0xDDE4 0x5351 # 0 +0xDDE5 0x5983 # 0 +0xDDE6 0x5A62 # 0 +0xDDE7 0x5E87 # 0 +0xDDE8 0x60B2 # 0 +0xDDE9 0x618A # 0 +0xDDEA 0x6249 # 0 +0xDDEB 0x6279 # 0 +0xDDEC 0x6590 # 0 +0xDDED 0x6787 # 0 +0xDDEE 0x69A7 # 0 +0xDDEF 0x6BD4 # 0 +0xDDF0 0x6BD6 # 0 +0xDDF1 0x6BD7 # 0 +0xDDF2 0x6BD8 # 0 +0xDDF3 0x6CB8 # 0 +0xDDF4 0xF968 # 0 +0xDDF5 0x7435 # 0 +0xDDF6 0x75FA # 0 +0xDDF7 0x7812 # 0 +0xDDF8 0x7891 # 0 +0xDDF9 0x79D5 # 0 +0xDDFA 0x79D8 # 0 +0xDDFB 0x7C83 # 0 +0xDDFC 0x7DCB # 0 +0xDDFD 0x7FE1 # 0 +0xDDFE 0x80A5 # 0 +0xDEA1 0x813E # 0 +0xDEA2 0x81C2 # 0 +0xDEA3 0x83F2 # 0 +0xDEA4 0x871A # 0 +0xDEA5 0x88E8 # 0 +0xDEA6 0x8AB9 # 0 +0xDEA7 0x8B6C # 0 +0xDEA8 0x8CBB # 0 +0xDEA9 0x9119 # 0 +0xDEAA 0x975E # 0 +0xDEAB 0x98DB # 0 +0xDEAC 0x9F3B # 0 +0xDEAD 0x56AC # 0 +0xDEAE 0x5B2A # 0 +0xDEAF 0x5F6C # 0 +0xDEB0 0x658C # 0 +0xDEB1 0x6AB3 # 0 +0xDEB2 0x6BAF # 0 +0xDEB3 0x6D5C # 0 +0xDEB4 0x6FF1 # 0 +0xDEB5 0x7015 # 0 +0xDEB6 0x725D # 0 +0xDEB7 0x73AD # 0 +0xDEB8 0x8CA7 # 0 +0xDEB9 0x8CD3 # 0 +0xDEBA 0x983B # 0 +0xDEBB 0x6191 # 0 +0xDEBC 0x6C37 # 0 +0xDEBD 0x8058 # 0 +0xDEBE 0x9A01 # 0 +0xDEBF 0x4E4D # 0 +0xDEC0 0x4E8B # 0 +0xDEC1 0x4E9B # 0 +0xDEC2 0x4ED5 # 0 +0xDEC3 0x4F3A # 0 +0xDEC4 0x4F3C # 0 +0xDEC5 0x4F7F # 0 +0xDEC6 0x4FDF # 0 +0xDEC7 0x50FF # 0 +0xDEC8 0x53F2 # 0 +0xDEC9 0x53F8 # 0 +0xDECA 0x5506 # 0 +0xDECB 0x55E3 # 0 +0xDECC 0x56DB # 0 +0xDECD 0x58EB # 0 +0xDECE 0x5962 # 0 +0xDECF 0x5A11 # 0 +0xDED0 0x5BEB # 0 +0xDED1 0x5BFA # 0 +0xDED2 0x5C04 # 0 +0xDED3 0x5DF3 # 0 +0xDED4 0x5E2B # 0 +0xDED5 0x5F99 # 0 +0xDED6 0x601D # 0 +0xDED7 0x6368 # 0 +0xDED8 0x659C # 0 +0xDED9 0x65AF # 0 +0xDEDA 0x67F6 # 0 +0xDEDB 0x67FB # 0 +0xDEDC 0x68AD # 0 +0xDEDD 0x6B7B # 0 +0xDEDE 0x6C99 # 0 +0xDEDF 0x6CD7 # 0 +0xDEE0 0x6E23 # 0 +0xDEE1 0x7009 # 0 +0xDEE2 0x7345 # 0 +0xDEE3 0x7802 # 0 +0xDEE4 0x793E # 0 +0xDEE5 0x7940 # 0 +0xDEE6 0x7960 # 0 +0xDEE7 0x79C1 # 0 +0xDEE8 0x7BE9 # 0 +0xDEE9 0x7D17 # 0 +0xDEEA 0x7D72 # 0 +0xDEEB 0x8086 # 0 +0xDEEC 0x820D # 0 +0xDEED 0x838E # 0 +0xDEEE 0x84D1 # 0 +0xDEEF 0x86C7 # 0 +0xDEF0 0x88DF # 0 +0xDEF1 0x8A50 # 0 +0xDEF2 0x8A5E # 0 +0xDEF3 0x8B1D # 0 +0xDEF4 0x8CDC # 0 +0xDEF5 0x8D66 # 0 +0xDEF6 0x8FAD # 0 +0xDEF7 0x90AA # 0 +0xDEF8 0x98FC # 0 +0xDEF9 0x99DF # 0 +0xDEFA 0x9E9D # 0 +0xDEFB 0x524A # 0 +0xDEFC 0xF969 # 0 +0xDEFD 0x6714 # 0 +0xDEFE 0xF96A # 0 +0xDFA1 0x5098 # 0 +0xDFA2 0x522A # 0 +0xDFA3 0x5C71 # 0 +0xDFA4 0x6563 # 0 +0xDFA5 0x6C55 # 0 +0xDFA6 0x73CA # 0 +0xDFA7 0x7523 # 0 +0xDFA8 0x759D # 0 +0xDFA9 0x7B97 # 0 +0xDFAA 0x849C # 0 +0xDFAB 0x9178 # 0 +0xDFAC 0x9730 # 0 +0xDFAD 0x4E77 # 0 +0xDFAE 0x6492 # 0 +0xDFAF 0x6BBA # 0 +0xDFB0 0x715E # 0 +0xDFB1 0x85A9 # 0 +0xDFB2 0x4E09 # 0 +0xDFB3 0xF96B # 0 +0xDFB4 0x6749 # 0 +0xDFB5 0x68EE # 0 +0xDFB6 0x6E17 # 0 +0xDFB7 0x829F # 0 +0xDFB8 0x8518 # 0 +0xDFB9 0x886B # 0 +0xDFBA 0x63F7 # 0 +0xDFBB 0x6F81 # 0 +0xDFBC 0x9212 # 0 +0xDFBD 0x98AF # 0 +0xDFBE 0x4E0A # 0 +0xDFBF 0x50B7 # 0 +0xDFC0 0x50CF # 0 +0xDFC1 0x511F # 0 +0xDFC2 0x5546 # 0 +0xDFC3 0x55AA # 0 +0xDFC4 0x5617 # 0 +0xDFC5 0x5B40 # 0 +0xDFC6 0x5C19 # 0 +0xDFC7 0x5CE0 # 0 +0xDFC8 0x5E38 # 0 +0xDFC9 0x5E8A # 0 +0xDFCA 0x5EA0 # 0 +0xDFCB 0x5EC2 # 0 +0xDFCC 0x60F3 # 0 +0xDFCD 0x6851 # 0 +0xDFCE 0x6A61 # 0 +0xDFCF 0x6E58 # 0 +0xDFD0 0x723D # 0 +0xDFD1 0x7240 # 0 +0xDFD2 0x72C0 # 0 +0xDFD3 0x76F8 # 0 +0xDFD4 0x7965 # 0 +0xDFD5 0x7BB1 # 0 +0xDFD6 0x7FD4 # 0 +0xDFD7 0x88F3 # 0 +0xDFD8 0x89F4 # 0 +0xDFD9 0x8A73 # 0 +0xDFDA 0x8C61 # 0 +0xDFDB 0x8CDE # 0 +0xDFDC 0x971C # 0 +0xDFDD 0x585E # 0 +0xDFDE 0x74BD # 0 +0xDFDF 0x8CFD # 0 +0xDFE0 0x55C7 # 0 +0xDFE1 0xF96C # 0 +0xDFE2 0x7A61 # 0 +0xDFE3 0x7D22 # 0 +0xDFE4 0x8272 # 0 +0xDFE5 0x7272 # 0 +0xDFE6 0x751F # 0 +0xDFE7 0x7525 # 0 +0xDFE8 0xF96D # 0 +0xDFE9 0x7B19 # 0 +0xDFEA 0x5885 # 0 +0xDFEB 0x58FB # 0 +0xDFEC 0x5DBC # 0 +0xDFED 0x5E8F # 0 +0xDFEE 0x5EB6 # 0 +0xDFEF 0x5F90 # 0 +0xDFF0 0x6055 # 0 +0xDFF1 0x6292 # 0 +0xDFF2 0x637F # 0 +0xDFF3 0x654D # 0 +0xDFF4 0x6691 # 0 +0xDFF5 0x66D9 # 0 +0xDFF6 0x66F8 # 0 +0xDFF7 0x6816 # 0 +0xDFF8 0x68F2 # 0 +0xDFF9 0x7280 # 0 +0xDFFA 0x745E # 0 +0xDFFB 0x7B6E # 0 +0xDFFC 0x7D6E # 0 +0xDFFD 0x7DD6 # 0 +0xDFFE 0x7F72 # 0 +0xE0A1 0x80E5 # 0 +0xE0A2 0x8212 # 0 +0xE0A3 0x85AF # 0 +0xE0A4 0x897F # 0 +0xE0A5 0x8A93 # 0 +0xE0A6 0x901D # 0 +0xE0A7 0x92E4 # 0 +0xE0A8 0x9ECD # 0 +0xE0A9 0x9F20 # 0 +0xE0AA 0x5915 # 0 +0xE0AB 0x596D # 0 +0xE0AC 0x5E2D # 0 +0xE0AD 0x60DC # 0 +0xE0AE 0x6614 # 0 +0xE0AF 0x6673 # 0 +0xE0B0 0x6790 # 0 +0xE0B1 0x6C50 # 0 +0xE0B2 0x6DC5 # 0 +0xE0B3 0x6F5F # 0 +0xE0B4 0x77F3 # 0 +0xE0B5 0x78A9 # 0 +0xE0B6 0x84C6 # 0 +0xE0B7 0x91CB # 0 +0xE0B8 0x932B # 0 +0xE0B9 0x4ED9 # 0 +0xE0BA 0x50CA # 0 +0xE0BB 0x5148 # 0 +0xE0BC 0x5584 # 0 +0xE0BD 0x5B0B # 0 +0xE0BE 0x5BA3 # 0 +0xE0BF 0x6247 # 0 +0xE0C0 0x657E # 0 +0xE0C1 0x65CB # 0 +0xE0C2 0x6E32 # 0 +0xE0C3 0x717D # 0 +0xE0C4 0x7401 # 0 +0xE0C5 0x7444 # 0 +0xE0C6 0x7487 # 0 +0xE0C7 0x74BF # 0 +0xE0C8 0x766C # 0 +0xE0C9 0x79AA # 0 +0xE0CA 0x7DDA # 0 +0xE0CB 0x7E55 # 0 +0xE0CC 0x7FA8 # 0 +0xE0CD 0x817A # 0 +0xE0CE 0x81B3 # 0 +0xE0CF 0x8239 # 0 +0xE0D0 0x861A # 0 +0xE0D1 0x87EC # 0 +0xE0D2 0x8A75 # 0 +0xE0D3 0x8DE3 # 0 +0xE0D4 0x9078 # 0 +0xE0D5 0x9291 # 0 +0xE0D6 0x9425 # 0 +0xE0D7 0x994D # 0 +0xE0D8 0x9BAE # 0 +0xE0D9 0x5368 # 0 +0xE0DA 0x5C51 # 0 +0xE0DB 0x6954 # 0 +0xE0DC 0x6CC4 # 0 +0xE0DD 0x6D29 # 0 +0xE0DE 0x6E2B # 0 +0xE0DF 0x820C # 0 +0xE0E0 0x859B # 0 +0xE0E1 0x893B # 0 +0xE0E2 0x8A2D # 0 +0xE0E3 0x8AAA # 0 +0xE0E4 0x96EA # 0 +0xE0E5 0x9F67 # 0 +0xE0E6 0x5261 # 0 +0xE0E7 0x66B9 # 0 +0xE0E8 0x6BB2 # 0 +0xE0E9 0x7E96 # 0 +0xE0EA 0x87FE # 0 +0xE0EB 0x8D0D # 0 +0xE0EC 0x9583 # 0 +0xE0ED 0x965D # 0 +0xE0EE 0x651D # 0 +0xE0EF 0x6D89 # 0 +0xE0F0 0x71EE # 0 +0xE0F1 0xF96E # 0 +0xE0F2 0x57CE # 0 +0xE0F3 0x59D3 # 0 +0xE0F4 0x5BAC # 0 +0xE0F5 0x6027 # 0 +0xE0F6 0x60FA # 0 +0xE0F7 0x6210 # 0 +0xE0F8 0x661F # 0 +0xE0F9 0x665F # 0 +0xE0FA 0x7329 # 0 +0xE0FB 0x73F9 # 0 +0xE0FC 0x76DB # 0 +0xE0FD 0x7701 # 0 +0xE0FE 0x7B6C # 0 +0xE1A1 0x8056 # 0 +0xE1A2 0x8072 # 0 +0xE1A3 0x8165 # 0 +0xE1A4 0x8AA0 # 0 +0xE1A5 0x9192 # 0 +0xE1A6 0x4E16 # 0 +0xE1A7 0x52E2 # 0 +0xE1A8 0x6B72 # 0 +0xE1A9 0x6D17 # 0 +0xE1AA 0x7A05 # 0 +0xE1AB 0x7B39 # 0 +0xE1AC 0x7D30 # 0 +0xE1AD 0xF96F # 0 +0xE1AE 0x8CB0 # 0 +0xE1AF 0x53EC # 0 +0xE1B0 0x562F # 0 +0xE1B1 0x5851 # 0 +0xE1B2 0x5BB5 # 0 +0xE1B3 0x5C0F # 0 +0xE1B4 0x5C11 # 0 +0xE1B5 0x5DE2 # 0 +0xE1B6 0x6240 # 0 +0xE1B7 0x6383 # 0 +0xE1B8 0x6414 # 0 +0xE1B9 0x662D # 0 +0xE1BA 0x68B3 # 0 +0xE1BB 0x6CBC # 0 +0xE1BC 0x6D88 # 0 +0xE1BD 0x6EAF # 0 +0xE1BE 0x701F # 0 +0xE1BF 0x70A4 # 0 +0xE1C0 0x71D2 # 0 +0xE1C1 0x7526 # 0 +0xE1C2 0x758F # 0 +0xE1C3 0x758E # 0 +0xE1C4 0x7619 # 0 +0xE1C5 0x7B11 # 0 +0xE1C6 0x7BE0 # 0 +0xE1C7 0x7C2B # 0 +0xE1C8 0x7D20 # 0 +0xE1C9 0x7D39 # 0 +0xE1CA 0x852C # 0 +0xE1CB 0x856D # 0 +0xE1CC 0x8607 # 0 +0xE1CD 0x8A34 # 0 +0xE1CE 0x900D # 0 +0xE1CF 0x9061 # 0 +0xE1D0 0x90B5 # 0 +0xE1D1 0x92B7 # 0 +0xE1D2 0x97F6 # 0 +0xE1D3 0x9A37 # 0 +0xE1D4 0x4FD7 # 0 +0xE1D5 0x5C6C # 0 +0xE1D6 0x675F # 0 +0xE1D7 0x6D91 # 0 +0xE1D8 0x7C9F # 0 +0xE1D9 0x7E8C # 0 +0xE1DA 0x8B16 # 0 +0xE1DB 0x8D16 # 0 +0xE1DC 0x901F # 0 +0xE1DD 0x5B6B # 0 +0xE1DE 0x5DFD # 0 +0xE1DF 0x640D # 0 +0xE1E0 0x84C0 # 0 +0xE1E1 0x905C # 0 +0xE1E2 0x98E1 # 0 +0xE1E3 0x7387 # 0 +0xE1E4 0x5B8B # 0 +0xE1E5 0x609A # 0 +0xE1E6 0x677E # 0 +0xE1E7 0x6DDE # 0 +0xE1E8 0x8A1F # 0 +0xE1E9 0x8AA6 # 0 +0xE1EA 0x9001 # 0 +0xE1EB 0x980C # 0 +0xE1EC 0x5237 # 0 +0xE1ED 0xF970 # 0 +0xE1EE 0x7051 # 0 +0xE1EF 0x788E # 0 +0xE1F0 0x9396 # 0 +0xE1F1 0x8870 # 0 +0xE1F2 0x91D7 # 0 +0xE1F3 0x4FEE # 0 +0xE1F4 0x53D7 # 0 +0xE1F5 0x55FD # 0 +0xE1F6 0x56DA # 0 +0xE1F7 0x5782 # 0 +0xE1F8 0x58FD # 0 +0xE1F9 0x5AC2 # 0 +0xE1FA 0x5B88 # 0 +0xE1FB 0x5CAB # 0 +0xE1FC 0x5CC0 # 0 +0xE1FD 0x5E25 # 0 +0xE1FE 0x6101 # 0 +0xE2A1 0x620D # 0 +0xE2A2 0x624B # 0 +0xE2A3 0x6388 # 0 +0xE2A4 0x641C # 0 +0xE2A5 0x6536 # 0 +0xE2A6 0x6578 # 0 +0xE2A7 0x6A39 # 0 +0xE2A8 0x6B8A # 0 +0xE2A9 0x6C34 # 0 +0xE2AA 0x6D19 # 0 +0xE2AB 0x6F31 # 0 +0xE2AC 0x71E7 # 0 +0xE2AD 0x72E9 # 0 +0xE2AE 0x7378 # 0 +0xE2AF 0x7407 # 0 +0xE2B0 0x74B2 # 0 +0xE2B1 0x7626 # 0 +0xE2B2 0x7761 # 0 +0xE2B3 0x79C0 # 0 +0xE2B4 0x7A57 # 0 +0xE2B5 0x7AEA # 0 +0xE2B6 0x7CB9 # 0 +0xE2B7 0x7D8F # 0 +0xE2B8 0x7DAC # 0 +0xE2B9 0x7E61 # 0 +0xE2BA 0x7F9E # 0 +0xE2BB 0x8129 # 0 +0xE2BC 0x8331 # 0 +0xE2BD 0x8490 # 0 +0xE2BE 0x84DA # 0 +0xE2BF 0x85EA # 0 +0xE2C0 0x8896 # 0 +0xE2C1 0x8AB0 # 0 +0xE2C2 0x8B90 # 0 +0xE2C3 0x8F38 # 0 +0xE2C4 0x9042 # 0 +0xE2C5 0x9083 # 0 +0xE2C6 0x916C # 0 +0xE2C7 0x9296 # 0 +0xE2C8 0x92B9 # 0 +0xE2C9 0x968B # 0 +0xE2CA 0x96A7 # 0 +0xE2CB 0x96A8 # 0 +0xE2CC 0x96D6 # 0 +0xE2CD 0x9700 # 0 +0xE2CE 0x9808 # 0 +0xE2CF 0x9996 # 0 +0xE2D0 0x9AD3 # 0 +0xE2D1 0x9B1A # 0 +0xE2D2 0x53D4 # 0 +0xE2D3 0x587E # 0 +0xE2D4 0x5919 # 0 +0xE2D5 0x5B70 # 0 +0xE2D6 0x5BBF # 0 +0xE2D7 0x6DD1 # 0 +0xE2D8 0x6F5A # 0 +0xE2D9 0x719F # 0 +0xE2DA 0x7421 # 0 +0xE2DB 0x74B9 # 0 +0xE2DC 0x8085 # 0 +0xE2DD 0x83FD # 0 +0xE2DE 0x5DE1 # 0 +0xE2DF 0x5F87 # 0 +0xE2E0 0x5FAA # 0 +0xE2E1 0x6042 # 0 +0xE2E2 0x65EC # 0 +0xE2E3 0x6812 # 0 +0xE2E4 0x696F # 0 +0xE2E5 0x6A53 # 0 +0xE2E6 0x6B89 # 0 +0xE2E7 0x6D35 # 0 +0xE2E8 0x6DF3 # 0 +0xE2E9 0x73E3 # 0 +0xE2EA 0x76FE # 0 +0xE2EB 0x77AC # 0 +0xE2EC 0x7B4D # 0 +0xE2ED 0x7D14 # 0 +0xE2EE 0x8123 # 0 +0xE2EF 0x821C # 0 +0xE2F0 0x8340 # 0 +0xE2F1 0x84F4 # 0 +0xE2F2 0x8563 # 0 +0xE2F3 0x8A62 # 0 +0xE2F4 0x8AC4 # 0 +0xE2F5 0x9187 # 0 +0xE2F6 0x931E # 0 +0xE2F7 0x9806 # 0 +0xE2F8 0x99B4 # 0 +0xE2F9 0x620C # 0 +0xE2FA 0x8853 # 0 +0xE2FB 0x8FF0 # 0 +0xE2FC 0x9265 # 0 +0xE2FD 0x5D07 # 0 +0xE2FE 0x5D27 # 0 +0xE3A1 0x5D69 # 0 +0xE3A2 0x745F # 0 +0xE3A3 0x819D # 0 +0xE3A4 0x8768 # 0 +0xE3A5 0x6FD5 # 0 +0xE3A6 0x62FE # 0 +0xE3A7 0x7FD2 # 0 +0xE3A8 0x8936 # 0 +0xE3A9 0x8972 # 0 +0xE3AA 0x4E1E # 0 +0xE3AB 0x4E58 # 0 +0xE3AC 0x50E7 # 0 +0xE3AD 0x52DD # 0 +0xE3AE 0x5347 # 0 +0xE3AF 0x627F # 0 +0xE3B0 0x6607 # 0 +0xE3B1 0x7E69 # 0 +0xE3B2 0x8805 # 0 +0xE3B3 0x965E # 0 +0xE3B4 0x4F8D # 0 +0xE3B5 0x5319 # 0 +0xE3B6 0x5636 # 0 +0xE3B7 0x59CB # 0 +0xE3B8 0x5AA4 # 0 +0xE3B9 0x5C38 # 0 +0xE3BA 0x5C4E # 0 +0xE3BB 0x5C4D # 0 +0xE3BC 0x5E02 # 0 +0xE3BD 0x5F11 # 0 +0xE3BE 0x6043 # 0 +0xE3BF 0x65BD # 0 +0xE3C0 0x662F # 0 +0xE3C1 0x6642 # 0 +0xE3C2 0x67BE # 0 +0xE3C3 0x67F4 # 0 +0xE3C4 0x731C # 0 +0xE3C5 0x77E2 # 0 +0xE3C6 0x793A # 0 +0xE3C7 0x7FC5 # 0 +0xE3C8 0x8494 # 0 +0xE3C9 0x84CD # 0 +0xE3CA 0x8996 # 0 +0xE3CB 0x8A66 # 0 +0xE3CC 0x8A69 # 0 +0xE3CD 0x8AE1 # 0 +0xE3CE 0x8C55 # 0 +0xE3CF 0x8C7A # 0 +0xE3D0 0x57F4 # 0 +0xE3D1 0x5BD4 # 0 +0xE3D2 0x5F0F # 0 +0xE3D3 0x606F # 0 +0xE3D4 0x62ED # 0 +0xE3D5 0x690D # 0 +0xE3D6 0x6B96 # 0 +0xE3D7 0x6E5C # 0 +0xE3D8 0x7184 # 0 +0xE3D9 0x7BD2 # 0 +0xE3DA 0x8755 # 0 +0xE3DB 0x8B58 # 0 +0xE3DC 0x8EFE # 0 +0xE3DD 0x98DF # 0 +0xE3DE 0x98FE # 0 +0xE3DF 0x4F38 # 0 +0xE3E0 0x4F81 # 0 +0xE3E1 0x4FE1 # 0 +0xE3E2 0x547B # 0 +0xE3E3 0x5A20 # 0 +0xE3E4 0x5BB8 # 0 +0xE3E5 0x613C # 0 +0xE3E6 0x65B0 # 0 +0xE3E7 0x6668 # 0 +0xE3E8 0x71FC # 0 +0xE3E9 0x7533 # 0 +0xE3EA 0x795E # 0 +0xE3EB 0x7D33 # 0 +0xE3EC 0x814E # 0 +0xE3ED 0x81E3 # 0 +0xE3EE 0x8398 # 0 +0xE3EF 0x85AA # 0 +0xE3F0 0x85CE # 0 +0xE3F1 0x8703 # 0 +0xE3F2 0x8A0A # 0 +0xE3F3 0x8EAB # 0 +0xE3F4 0x8F9B # 0 +0xE3F5 0xF971 # 0 +0xE3F6 0x8FC5 # 0 +0xE3F7 0x5931 # 0 +0xE3F8 0x5BA4 # 0 +0xE3F9 0x5BE6 # 0 +0xE3FA 0x6089 # 0 +0xE3FB 0x5BE9 # 0 +0xE3FC 0x5C0B # 0 +0xE3FD 0x5FC3 # 0 +0xE3FE 0x6C81 # 0 +0xE4A1 0xF972 # 0 +0xE4A2 0x6DF1 # 0 +0xE4A3 0x700B # 0 +0xE4A4 0x751A # 0 +0xE4A5 0x82AF # 0 +0xE4A6 0x8AF6 # 0 +0xE4A7 0x4EC0 # 0 +0xE4A8 0x5341 # 0 +0xE4A9 0xF973 # 0 +0xE4AA 0x96D9 # 0 +0xE4AB 0x6C0F # 0 +0xE4AC 0x4E9E # 0 +0xE4AD 0x4FC4 # 0 +0xE4AE 0x5152 # 0 +0xE4AF 0x555E # 0 +0xE4B0 0x5A25 # 0 +0xE4B1 0x5CE8 # 0 +0xE4B2 0x6211 # 0 +0xE4B3 0x7259 # 0 +0xE4B4 0x82BD # 0 +0xE4B5 0x83AA # 0 +0xE4B6 0x86FE # 0 +0xE4B7 0x8859 # 0 +0xE4B8 0x8A1D # 0 +0xE4B9 0x963F # 0 +0xE4BA 0x96C5 # 0 +0xE4BB 0x9913 # 0 +0xE4BC 0x9D09 # 0 +0xE4BD 0x9D5D # 0 +0xE4BE 0x580A # 0 +0xE4BF 0x5CB3 # 0 +0xE4C0 0x5DBD # 0 +0xE4C1 0x5E44 # 0 +0xE4C2 0x60E1 # 0 +0xE4C3 0x6115 # 0 +0xE4C4 0x63E1 # 0 +0xE4C5 0x6A02 # 0 +0xE4C6 0x6E25 # 0 +0xE4C7 0x9102 # 0 +0xE4C8 0x9354 # 0 +0xE4C9 0x984E # 0 +0xE4CA 0x9C10 # 0 +0xE4CB 0x9F77 # 0 +0xE4CC 0x5B89 # 0 +0xE4CD 0x5CB8 # 0 +0xE4CE 0x6309 # 0 +0xE4CF 0x664F # 0 +0xE4D0 0x6848 # 0 +0xE4D1 0x773C # 0 +0xE4D2 0x96C1 # 0 +0xE4D3 0x978D # 0 +0xE4D4 0x9854 # 0 +0xE4D5 0x9B9F # 0 +0xE4D6 0x65A1 # 0 +0xE4D7 0x8B01 # 0 +0xE4D8 0x8ECB # 0 +0xE4D9 0x95BC # 0 +0xE4DA 0x5535 # 0 +0xE4DB 0x5CA9 # 0 +0xE4DC 0x5DD6 # 0 +0xE4DD 0x5EB5 # 0 +0xE4DE 0x6697 # 0 +0xE4DF 0x764C # 0 +0xE4E0 0x83F4 # 0 +0xE4E1 0x95C7 # 0 +0xE4E2 0x58D3 # 0 +0xE4E3 0x62BC # 0 +0xE4E4 0x72CE # 0 +0xE4E5 0x9D28 # 0 +0xE4E6 0x4EF0 # 0 +0xE4E7 0x592E # 0 +0xE4E8 0x600F # 0 +0xE4E9 0x663B # 0 +0xE4EA 0x6B83 # 0 +0xE4EB 0x79E7 # 0 +0xE4EC 0x9D26 # 0 +0xE4ED 0x5393 # 0 +0xE4EE 0x54C0 # 0 +0xE4EF 0x57C3 # 0 +0xE4F0 0x5D16 # 0 +0xE4F1 0x611B # 0 +0xE4F2 0x66D6 # 0 +0xE4F3 0x6DAF # 0 +0xE4F4 0x788D # 0 +0xE4F5 0x827E # 0 +0xE4F6 0x9698 # 0 +0xE4F7 0x9744 # 0 +0xE4F8 0x5384 # 0 +0xE4F9 0x627C # 0 +0xE4FA 0x6396 # 0 +0xE4FB 0x6DB2 # 0 +0xE4FC 0x7E0A # 0 +0xE4FD 0x814B # 0 +0xE4FE 0x984D # 0 +0xE5A1 0x6AFB # 0 +0xE5A2 0x7F4C # 0 +0xE5A3 0x9DAF # 0 +0xE5A4 0x9E1A # 0 +0xE5A5 0x4E5F # 0 +0xE5A6 0x503B # 0 +0xE5A7 0x51B6 # 0 +0xE5A8 0x591C # 0 +0xE5A9 0x60F9 # 0 +0xE5AA 0x63F6 # 0 +0xE5AB 0x6930 # 0 +0xE5AC 0x723A # 0 +0xE5AD 0x8036 # 0 +0xE5AE 0xF974 # 0 +0xE5AF 0x91CE # 0 +0xE5B0 0x5F31 # 0 +0xE5B1 0xF975 # 0 +0xE5B2 0xF976 # 0 +0xE5B3 0x7D04 # 0 +0xE5B4 0x82E5 # 0 +0xE5B5 0x846F # 0 +0xE5B6 0x84BB # 0 +0xE5B7 0x85E5 # 0 +0xE5B8 0x8E8D # 0 +0xE5B9 0xF977 # 0 +0xE5BA 0x4F6F # 0 +0xE5BB 0xF978 # 0 +0xE5BC 0xF979 # 0 +0xE5BD 0x58E4 # 0 +0xE5BE 0x5B43 # 0 +0xE5BF 0x6059 # 0 +0xE5C0 0x63DA # 0 +0xE5C1 0x6518 # 0 +0xE5C2 0x656D # 0 +0xE5C3 0x6698 # 0 +0xE5C4 0xF97A # 0 +0xE5C5 0x694A # 0 +0xE5C6 0x6A23 # 0 +0xE5C7 0x6D0B # 0 +0xE5C8 0x7001 # 0 +0xE5C9 0x716C # 0 +0xE5CA 0x75D2 # 0 +0xE5CB 0x760D # 0 +0xE5CC 0x79B3 # 0 +0xE5CD 0x7A70 # 0 +0xE5CE 0xF97B # 0 +0xE5CF 0x7F8A # 0 +0xE5D0 0xF97C # 0 +0xE5D1 0x8944 # 0 +0xE5D2 0xF97D # 0 +0xE5D3 0x8B93 # 0 +0xE5D4 0x91C0 # 0 +0xE5D5 0x967D # 0 +0xE5D6 0xF97E # 0 +0xE5D7 0x990A # 0 +0xE5D8 0x5704 # 0 +0xE5D9 0x5FA1 # 0 +0xE5DA 0x65BC # 0 +0xE5DB 0x6F01 # 0 +0xE5DC 0x7600 # 0 +0xE5DD 0x79A6 # 0 +0xE5DE 0x8A9E # 0 +0xE5DF 0x99AD # 0 +0xE5E0 0x9B5A # 0 +0xE5E1 0x9F6C # 0 +0xE5E2 0x5104 # 0 +0xE5E3 0x61B6 # 0 +0xE5E4 0x6291 # 0 +0xE5E5 0x6A8D # 0 +0xE5E6 0x81C6 # 0 +0xE5E7 0x5043 # 0 +0xE5E8 0x5830 # 0 +0xE5E9 0x5F66 # 0 +0xE5EA 0x7109 # 0 +0xE5EB 0x8A00 # 0 +0xE5EC 0x8AFA # 0 +0xE5ED 0x5B7C # 0 +0xE5EE 0x8616 # 0 +0xE5EF 0x4FFA # 0 +0xE5F0 0x513C # 0 +0xE5F1 0x56B4 # 0 +0xE5F2 0x5944 # 0 +0xE5F3 0x63A9 # 0 +0xE5F4 0x6DF9 # 0 +0xE5F5 0x5DAA # 0 +0xE5F6 0x696D # 0 +0xE5F7 0x5186 # 0 +0xE5F8 0x4E88 # 0 +0xE5F9 0x4F59 # 0 +0xE5FA 0xF97F # 0 +0xE5FB 0xF980 # 0 +0xE5FC 0xF981 # 0 +0xE5FD 0x5982 # 0 +0xE5FE 0xF982 # 0 +0xE6A1 0xF983 # 0 +0xE6A2 0x6B5F # 0 +0xE6A3 0x6C5D # 0 +0xE6A4 0xF984 # 0 +0xE6A5 0x74B5 # 0 +0xE6A6 0x7916 # 0 +0xE6A7 0xF985 # 0 +0xE6A8 0x8207 # 0 +0xE6A9 0x8245 # 0 +0xE6AA 0x8339 # 0 +0xE6AB 0x8F3F # 0 +0xE6AC 0x8F5D # 0 +0xE6AD 0xF986 # 0 +0xE6AE 0x9918 # 0 +0xE6AF 0xF987 # 0 +0xE6B0 0xF988 # 0 +0xE6B1 0xF989 # 0 +0xE6B2 0x4EA6 # 0 +0xE6B3 0xF98A # 0 +0xE6B4 0x57DF # 0 +0xE6B5 0x5F79 # 0 +0xE6B6 0x6613 # 0 +0xE6B7 0xF98B # 0 +0xE6B8 0xF98C # 0 +0xE6B9 0x75AB # 0 +0xE6BA 0x7E79 # 0 +0xE6BB 0x8B6F # 0 +0xE6BC 0xF98D # 0 +0xE6BD 0x9006 # 0 +0xE6BE 0x9A5B # 0 +0xE6BF 0x56A5 # 0 +0xE6C0 0x5827 # 0 +0xE6C1 0x59F8 # 0 +0xE6C2 0x5A1F # 0 +0xE6C3 0x5BB4 # 0 +0xE6C4 0xF98E # 0 +0xE6C5 0x5EF6 # 0 +0xE6C6 0xF98F # 0 +0xE6C7 0xF990 # 0 +0xE6C8 0x6350 # 0 +0xE6C9 0x633B # 0 +0xE6CA 0xF991 # 0 +0xE6CB 0x693D # 0 +0xE6CC 0x6C87 # 0 +0xE6CD 0x6CBF # 0 +0xE6CE 0x6D8E # 0 +0xE6CF 0x6D93 # 0 +0xE6D0 0x6DF5 # 0 +0xE6D1 0x6F14 # 0 +0xE6D2 0xF992 # 0 +0xE6D3 0x70DF # 0 +0xE6D4 0x7136 # 0 +0xE6D5 0x7159 # 0 +0xE6D6 0xF993 # 0 +0xE6D7 0x71C3 # 0 +0xE6D8 0x71D5 # 0 +0xE6D9 0xF994 # 0 +0xE6DA 0x784F # 0 +0xE6DB 0x786F # 0 +0xE6DC 0xF995 # 0 +0xE6DD 0x7B75 # 0 +0xE6DE 0x7DE3 # 0 +0xE6DF 0xF996 # 0 +0xE6E0 0x7E2F # 0 +0xE6E1 0xF997 # 0 +0xE6E2 0x884D # 0 +0xE6E3 0x8EDF # 0 +0xE6E4 0xF998 # 0 +0xE6E5 0xF999 # 0 +0xE6E6 0xF99A # 0 +0xE6E7 0x925B # 0 +0xE6E8 0xF99B # 0 +0xE6E9 0x9CF6 # 0 +0xE6EA 0xF99C # 0 +0xE6EB 0xF99D # 0 +0xE6EC 0xF99E # 0 +0xE6ED 0x6085 # 0 +0xE6EE 0x6D85 # 0 +0xE6EF 0xF99F # 0 +0xE6F0 0x71B1 # 0 +0xE6F1 0xF9A0 # 0 +0xE6F2 0xF9A1 # 0 +0xE6F3 0x95B1 # 0 +0xE6F4 0x53AD # 0 +0xE6F5 0xF9A2 # 0 +0xE6F6 0xF9A3 # 0 +0xE6F7 0xF9A4 # 0 +0xE6F8 0x67D3 # 0 +0xE6F9 0xF9A5 # 0 +0xE6FA 0x708E # 0 +0xE6FB 0x7130 # 0 +0xE6FC 0x7430 # 0 +0xE6FD 0x8276 # 0 +0xE6FE 0x82D2 # 0 +0xE7A1 0xF9A6 # 0 +0xE7A2 0x95BB # 0 +0xE7A3 0x9AE5 # 0 +0xE7A4 0x9E7D # 0 +0xE7A5 0x66C4 # 0 +0xE7A6 0xF9A7 # 0 +0xE7A7 0x71C1 # 0 +0xE7A8 0x8449 # 0 +0xE7A9 0xF9A8 # 0 +0xE7AA 0xF9A9 # 0 +0xE7AB 0x584B # 0 +0xE7AC 0xF9AA # 0 +0xE7AD 0xF9AB # 0 +0xE7AE 0x5DB8 # 0 +0xE7AF 0x5F71 # 0 +0xE7B0 0xF9AC # 0 +0xE7B1 0x6620 # 0 +0xE7B2 0x668E # 0 +0xE7B3 0x6979 # 0 +0xE7B4 0x69AE # 0 +0xE7B5 0x6C38 # 0 +0xE7B6 0x6CF3 # 0 +0xE7B7 0x6E36 # 0 +0xE7B8 0x6F41 # 0 +0xE7B9 0x6FDA # 0 +0xE7BA 0x701B # 0 +0xE7BB 0x702F # 0 +0xE7BC 0x7150 # 0 +0xE7BD 0x71DF # 0 +0xE7BE 0x7370 # 0 +0xE7BF 0xF9AD # 0 +0xE7C0 0x745B # 0 +0xE7C1 0xF9AE # 0 +0xE7C2 0x74D4 # 0 +0xE7C3 0x76C8 # 0 +0xE7C4 0x7A4E # 0 +0xE7C5 0x7E93 # 0 +0xE7C6 0xF9AF # 0 +0xE7C7 0xF9B0 # 0 +0xE7C8 0x82F1 # 0 +0xE7C9 0x8A60 # 0 +0xE7CA 0x8FCE # 0 +0xE7CB 0xF9B1 # 0 +0xE7CC 0x9348 # 0 +0xE7CD 0xF9B2 # 0 +0xE7CE 0x9719 # 0 +0xE7CF 0xF9B3 # 0 +0xE7D0 0xF9B4 # 0 +0xE7D1 0x4E42 # 0 +0xE7D2 0x502A # 0 +0xE7D3 0xF9B5 # 0 +0xE7D4 0x5208 # 0 +0xE7D5 0x53E1 # 0 +0xE7D6 0x66F3 # 0 +0xE7D7 0x6C6D # 0 +0xE7D8 0x6FCA # 0 +0xE7D9 0x730A # 0 +0xE7DA 0x777F # 0 +0xE7DB 0x7A62 # 0 +0xE7DC 0x82AE # 0 +0xE7DD 0x85DD # 0 +0xE7DE 0x8602 # 0 +0xE7DF 0xF9B6 # 0 +0xE7E0 0x88D4 # 0 +0xE7E1 0x8A63 # 0 +0xE7E2 0x8B7D # 0 +0xE7E3 0x8C6B # 0 +0xE7E4 0xF9B7 # 0 +0xE7E5 0x92B3 # 0 +0xE7E6 0xF9B8 # 0 +0xE7E7 0x9713 # 0 +0xE7E8 0x9810 # 0 +0xE7E9 0x4E94 # 0 +0xE7EA 0x4F0D # 0 +0xE7EB 0x4FC9 # 0 +0xE7EC 0x50B2 # 0 +0xE7ED 0x5348 # 0 +0xE7EE 0x543E # 0 +0xE7EF 0x5433 # 0 +0xE7F0 0x55DA # 0 +0xE7F1 0x5862 # 0 +0xE7F2 0x58BA # 0 +0xE7F3 0x5967 # 0 +0xE7F4 0x5A1B # 0 +0xE7F5 0x5BE4 # 0 +0xE7F6 0x609F # 0 +0xE7F7 0xF9B9 # 0 +0xE7F8 0x61CA # 0 +0xE7F9 0x6556 # 0 +0xE7FA 0x65FF # 0 +0xE7FB 0x6664 # 0 +0xE7FC 0x68A7 # 0 +0xE7FD 0x6C5A # 0 +0xE7FE 0x6FB3 # 0 +0xE8A1 0x70CF # 0 +0xE8A2 0x71AC # 0 +0xE8A3 0x7352 # 0 +0xE8A4 0x7B7D # 0 +0xE8A5 0x8708 # 0 +0xE8A6 0x8AA4 # 0 +0xE8A7 0x9C32 # 0 +0xE8A8 0x9F07 # 0 +0xE8A9 0x5C4B # 0 +0xE8AA 0x6C83 # 0 +0xE8AB 0x7344 # 0 +0xE8AC 0x7389 # 0 +0xE8AD 0x923A # 0 +0xE8AE 0x6EAB # 0 +0xE8AF 0x7465 # 0 +0xE8B0 0x761F # 0 +0xE8B1 0x7A69 # 0 +0xE8B2 0x7E15 # 0 +0xE8B3 0x860A # 0 +0xE8B4 0x5140 # 0 +0xE8B5 0x58C5 # 0 +0xE8B6 0x64C1 # 0 +0xE8B7 0x74EE # 0 +0xE8B8 0x7515 # 0 +0xE8B9 0x7670 # 0 +0xE8BA 0x7FC1 # 0 +0xE8BB 0x9095 # 0 +0xE8BC 0x96CD # 0 +0xE8BD 0x9954 # 0 +0xE8BE 0x6E26 # 0 +0xE8BF 0x74E6 # 0 +0xE8C0 0x7AA9 # 0 +0xE8C1 0x7AAA # 0 +0xE8C2 0x81E5 # 0 +0xE8C3 0x86D9 # 0 +0xE8C4 0x8778 # 0 +0xE8C5 0x8A1B # 0 +0xE8C6 0x5A49 # 0 +0xE8C7 0x5B8C # 0 +0xE8C8 0x5B9B # 0 +0xE8C9 0x68A1 # 0 +0xE8CA 0x6900 # 0 +0xE8CB 0x6D63 # 0 +0xE8CC 0x73A9 # 0 +0xE8CD 0x7413 # 0 +0xE8CE 0x742C # 0 +0xE8CF 0x7897 # 0 +0xE8D0 0x7DE9 # 0 +0xE8D1 0x7FEB # 0 +0xE8D2 0x8118 # 0 +0xE8D3 0x8155 # 0 +0xE8D4 0x839E # 0 +0xE8D5 0x8C4C # 0 +0xE8D6 0x962E # 0 +0xE8D7 0x9811 # 0 +0xE8D8 0x66F0 # 0 +0xE8D9 0x5F80 # 0 +0xE8DA 0x65FA # 0 +0xE8DB 0x6789 # 0 +0xE8DC 0x6C6A # 0 +0xE8DD 0x738B # 0 +0xE8DE 0x502D # 0 +0xE8DF 0x5A03 # 0 +0xE8E0 0x6B6A # 0 +0xE8E1 0x77EE # 0 +0xE8E2 0x5916 # 0 +0xE8E3 0x5D6C # 0 +0xE8E4 0x5DCD # 0 +0xE8E5 0x7325 # 0 +0xE8E6 0x754F # 0 +0xE8E7 0xF9BA # 0 +0xE8E8 0xF9BB # 0 +0xE8E9 0x50E5 # 0 +0xE8EA 0x51F9 # 0 +0xE8EB 0x582F # 0 +0xE8EC 0x592D # 0 +0xE8ED 0x5996 # 0 +0xE8EE 0x59DA # 0 +0xE8EF 0x5BE5 # 0 +0xE8F0 0xF9BC # 0 +0xE8F1 0xF9BD # 0 +0xE8F2 0x5DA2 # 0 +0xE8F3 0x62D7 # 0 +0xE8F4 0x6416 # 0 +0xE8F5 0x6493 # 0 +0xE8F6 0x64FE # 0 +0xE8F7 0xF9BE # 0 +0xE8F8 0x66DC # 0 +0xE8F9 0xF9BF # 0 +0xE8FA 0x6A48 # 0 +0xE8FB 0xF9C0 # 0 +0xE8FC 0x71FF # 0 +0xE8FD 0x7464 # 0 +0xE8FE 0xF9C1 # 0 +0xE9A1 0x7A88 # 0 +0xE9A2 0x7AAF # 0 +0xE9A3 0x7E47 # 0 +0xE9A4 0x7E5E # 0 +0xE9A5 0x8000 # 0 +0xE9A6 0x8170 # 0 +0xE9A7 0xF9C2 # 0 +0xE9A8 0x87EF # 0 +0xE9A9 0x8981 # 0 +0xE9AA 0x8B20 # 0 +0xE9AB 0x9059 # 0 +0xE9AC 0xF9C3 # 0 +0xE9AD 0x9080 # 0 +0xE9AE 0x9952 # 0 +0xE9AF 0x617E # 0 +0xE9B0 0x6B32 # 0 +0xE9B1 0x6D74 # 0 +0xE9B2 0x7E1F # 0 +0xE9B3 0x8925 # 0 +0xE9B4 0x8FB1 # 0 +0xE9B5 0x4FD1 # 0 +0xE9B6 0x50AD # 0 +0xE9B7 0x5197 # 0 +0xE9B8 0x52C7 # 0 +0xE9B9 0x57C7 # 0 +0xE9BA 0x5889 # 0 +0xE9BB 0x5BB9 # 0 +0xE9BC 0x5EB8 # 0 +0xE9BD 0x6142 # 0 +0xE9BE 0x6995 # 0 +0xE9BF 0x6D8C # 0 +0xE9C0 0x6E67 # 0 +0xE9C1 0x6EB6 # 0 +0xE9C2 0x7194 # 0 +0xE9C3 0x7462 # 0 +0xE9C4 0x7528 # 0 +0xE9C5 0x752C # 0 +0xE9C6 0x8073 # 0 +0xE9C7 0x8338 # 0 +0xE9C8 0x84C9 # 0 +0xE9C9 0x8E0A # 0 +0xE9CA 0x9394 # 0 +0xE9CB 0x93DE # 0 +0xE9CC 0xF9C4 # 0 +0xE9CD 0x4E8E # 0 +0xE9CE 0x4F51 # 0 +0xE9CF 0x5076 # 0 +0xE9D0 0x512A # 0 +0xE9D1 0x53C8 # 0 +0xE9D2 0x53CB # 0 +0xE9D3 0x53F3 # 0 +0xE9D4 0x5B87 # 0 +0xE9D5 0x5BD3 # 0 +0xE9D6 0x5C24 # 0 +0xE9D7 0x611A # 0 +0xE9D8 0x6182 # 0 +0xE9D9 0x65F4 # 0 +0xE9DA 0x725B # 0 +0xE9DB 0x7397 # 0 +0xE9DC 0x7440 # 0 +0xE9DD 0x76C2 # 0 +0xE9DE 0x7950 # 0 +0xE9DF 0x7991 # 0 +0xE9E0 0x79B9 # 0 +0xE9E1 0x7D06 # 0 +0xE9E2 0x7FBD # 0 +0xE9E3 0x828B # 0 +0xE9E4 0x85D5 # 0 +0xE9E5 0x865E # 0 +0xE9E6 0x8FC2 # 0 +0xE9E7 0x9047 # 0 +0xE9E8 0x90F5 # 0 +0xE9E9 0x91EA # 0 +0xE9EA 0x9685 # 0 +0xE9EB 0x96E8 # 0 +0xE9EC 0x96E9 # 0 +0xE9ED 0x52D6 # 0 +0xE9EE 0x5F67 # 0 +0xE9EF 0x65ED # 0 +0xE9F0 0x6631 # 0 +0xE9F1 0x682F # 0 +0xE9F2 0x715C # 0 +0xE9F3 0x7A36 # 0 +0xE9F4 0x90C1 # 0 +0xE9F5 0x980A # 0 +0xE9F6 0x4E91 # 0 +0xE9F7 0xF9C5 # 0 +0xE9F8 0x6A52 # 0 +0xE9F9 0x6B9E # 0 +0xE9FA 0x6F90 # 0 +0xE9FB 0x7189 # 0 +0xE9FC 0x8018 # 0 +0xE9FD 0x82B8 # 0 +0xE9FE 0x8553 # 0 +0xEAA1 0x904B # 0 +0xEAA2 0x9695 # 0 +0xEAA3 0x96F2 # 0 +0xEAA4 0x97FB # 0 +0xEAA5 0x851A # 0 +0xEAA6 0x9B31 # 0 +0xEAA7 0x4E90 # 0 +0xEAA8 0x718A # 0 +0xEAA9 0x96C4 # 0 +0xEAAA 0x5143 # 0 +0xEAAB 0x539F # 0 +0xEAAC 0x54E1 # 0 +0xEAAD 0x5713 # 0 +0xEAAE 0x5712 # 0 +0xEAAF 0x57A3 # 0 +0xEAB0 0x5A9B # 0 +0xEAB1 0x5AC4 # 0 +0xEAB2 0x5BC3 # 0 +0xEAB3 0x6028 # 0 +0xEAB4 0x613F # 0 +0xEAB5 0x63F4 # 0 +0xEAB6 0x6C85 # 0 +0xEAB7 0x6D39 # 0 +0xEAB8 0x6E72 # 0 +0xEAB9 0x6E90 # 0 +0xEABA 0x7230 # 0 +0xEABB 0x733F # 0 +0xEABC 0x7457 # 0 +0xEABD 0x82D1 # 0 +0xEABE 0x8881 # 0 +0xEABF 0x8F45 # 0 +0xEAC0 0x9060 # 0 +0xEAC1 0xF9C6 # 0 +0xEAC2 0x9662 # 0 +0xEAC3 0x9858 # 0 +0xEAC4 0x9D1B # 0 +0xEAC5 0x6708 # 0 +0xEAC6 0x8D8A # 0 +0xEAC7 0x925E # 0 +0xEAC8 0x4F4D # 0 +0xEAC9 0x5049 # 0 +0xEACA 0x50DE # 0 +0xEACB 0x5371 # 0 +0xEACC 0x570D # 0 +0xEACD 0x59D4 # 0 +0xEACE 0x5A01 # 0 +0xEACF 0x5C09 # 0 +0xEAD0 0x6170 # 0 +0xEAD1 0x6690 # 0 +0xEAD2 0x6E2D # 0 +0xEAD3 0x7232 # 0 +0xEAD4 0x744B # 0 +0xEAD5 0x7DEF # 0 +0xEAD6 0x80C3 # 0 +0xEAD7 0x840E # 0 +0xEAD8 0x8466 # 0 +0xEAD9 0x853F # 0 +0xEADA 0x875F # 0 +0xEADB 0x885B # 0 +0xEADC 0x8918 # 0 +0xEADD 0x8B02 # 0 +0xEADE 0x9055 # 0 +0xEADF 0x97CB # 0 +0xEAE0 0x9B4F # 0 +0xEAE1 0x4E73 # 0 +0xEAE2 0x4F91 # 0 +0xEAE3 0x5112 # 0 +0xEAE4 0x516A # 0 +0xEAE5 0xF9C7 # 0 +0xEAE6 0x552F # 0 +0xEAE7 0x55A9 # 0 +0xEAE8 0x5B7A # 0 +0xEAE9 0x5BA5 # 0 +0xEAEA 0x5E7C # 0 +0xEAEB 0x5E7D # 0 +0xEAEC 0x5EBE # 0 +0xEAED 0x60A0 # 0 +0xEAEE 0x60DF # 0 +0xEAEF 0x6108 # 0 +0xEAF0 0x6109 # 0 +0xEAF1 0x63C4 # 0 +0xEAF2 0x6538 # 0 +0xEAF3 0x6709 # 0 +0xEAF4 0xF9C8 # 0 +0xEAF5 0x67D4 # 0 +0xEAF6 0x67DA # 0 +0xEAF7 0xF9C9 # 0 +0xEAF8 0x6961 # 0 +0xEAF9 0x6962 # 0 +0xEAFA 0x6CB9 # 0 +0xEAFB 0x6D27 # 0 +0xEAFC 0xF9CA # 0 +0xEAFD 0x6E38 # 0 +0xEAFE 0xF9CB # 0 +0xEBA1 0x6FE1 # 0 +0xEBA2 0x7336 # 0 +0xEBA3 0x7337 # 0 +0xEBA4 0xF9CC # 0 +0xEBA5 0x745C # 0 +0xEBA6 0x7531 # 0 +0xEBA7 0xF9CD # 0 +0xEBA8 0x7652 # 0 +0xEBA9 0xF9CE # 0 +0xEBAA 0xF9CF # 0 +0xEBAB 0x7DAD # 0 +0xEBAC 0x81FE # 0 +0xEBAD 0x8438 # 0 +0xEBAE 0x88D5 # 0 +0xEBAF 0x8A98 # 0 +0xEBB0 0x8ADB # 0 +0xEBB1 0x8AED # 0 +0xEBB2 0x8E30 # 0 +0xEBB3 0x8E42 # 0 +0xEBB4 0x904A # 0 +0xEBB5 0x903E # 0 +0xEBB6 0x907A # 0 +0xEBB7 0x9149 # 0 +0xEBB8 0x91C9 # 0 +0xEBB9 0x936E # 0 +0xEBBA 0xF9D0 # 0 +0xEBBB 0xF9D1 # 0 +0xEBBC 0x5809 # 0 +0xEBBD 0xF9D2 # 0 +0xEBBE 0x6BD3 # 0 +0xEBBF 0x8089 # 0 +0xEBC0 0x80B2 # 0 +0xEBC1 0xF9D3 # 0 +0xEBC2 0xF9D4 # 0 +0xEBC3 0x5141 # 0 +0xEBC4 0x596B # 0 +0xEBC5 0x5C39 # 0 +0xEBC6 0xF9D5 # 0 +0xEBC7 0xF9D6 # 0 +0xEBC8 0x6F64 # 0 +0xEBC9 0x73A7 # 0 +0xEBCA 0x80E4 # 0 +0xEBCB 0x8D07 # 0 +0xEBCC 0xF9D7 # 0 +0xEBCD 0x9217 # 0 +0xEBCE 0x958F # 0 +0xEBCF 0xF9D8 # 0 +0xEBD0 0xF9D9 # 0 +0xEBD1 0xF9DA # 0 +0xEBD2 0xF9DB # 0 +0xEBD3 0x807F # 0 +0xEBD4 0x620E # 0 +0xEBD5 0x701C # 0 +0xEBD6 0x7D68 # 0 +0xEBD7 0x878D # 0 +0xEBD8 0xF9DC # 0 +0xEBD9 0x57A0 # 0 +0xEBDA 0x6069 # 0 +0xEBDB 0x6147 # 0 +0xEBDC 0x6BB7 # 0 +0xEBDD 0x8ABE # 0 +0xEBDE 0x9280 # 0 +0xEBDF 0x96B1 # 0 +0xEBE0 0x4E59 # 0 +0xEBE1 0x541F # 0 +0xEBE2 0x6DEB # 0 +0xEBE3 0x852D # 0 +0xEBE4 0x9670 # 0 +0xEBE5 0x97F3 # 0 +0xEBE6 0x98EE # 0 +0xEBE7 0x63D6 # 0 +0xEBE8 0x6CE3 # 0 +0xEBE9 0x9091 # 0 +0xEBEA 0x51DD # 0 +0xEBEB 0x61C9 # 0 +0xEBEC 0x81BA # 0 +0xEBED 0x9DF9 # 0 +0xEBEE 0x4F9D # 0 +0xEBEF 0x501A # 0 +0xEBF0 0x5100 # 0 +0xEBF1 0x5B9C # 0 +0xEBF2 0x610F # 0 +0xEBF3 0x61FF # 0 +0xEBF4 0x64EC # 0 +0xEBF5 0x6905 # 0 +0xEBF6 0x6BC5 # 0 +0xEBF7 0x7591 # 0 +0xEBF8 0x77E3 # 0 +0xEBF9 0x7FA9 # 0 +0xEBFA 0x8264 # 0 +0xEBFB 0x858F # 0 +0xEBFC 0x87FB # 0 +0xEBFD 0x8863 # 0 +0xEBFE 0x8ABC # 0 +0xECA1 0x8B70 # 0 +0xECA2 0x91AB # 0 +0xECA3 0x4E8C # 0 +0xECA4 0x4EE5 # 0 +0xECA5 0x4F0A # 0 +0xECA6 0xF9DD # 0 +0xECA7 0xF9DE # 0 +0xECA8 0x5937 # 0 +0xECA9 0x59E8 # 0 +0xECAA 0xF9DF # 0 +0xECAB 0x5DF2 # 0 +0xECAC 0x5F1B # 0 +0xECAD 0x5F5B # 0 +0xECAE 0x6021 # 0 +0xECAF 0xF9E0 # 0 +0xECB0 0xF9E1 # 0 +0xECB1 0xF9E2 # 0 +0xECB2 0xF9E3 # 0 +0xECB3 0x723E # 0 +0xECB4 0x73E5 # 0 +0xECB5 0xF9E4 # 0 +0xECB6 0x7570 # 0 +0xECB7 0x75CD # 0 +0xECB8 0xF9E5 # 0 +0xECB9 0x79FB # 0 +0xECBA 0xF9E6 # 0 +0xECBB 0x800C # 0 +0xECBC 0x8033 # 0 +0xECBD 0x8084 # 0 +0xECBE 0x82E1 # 0 +0xECBF 0x8351 # 0 +0xECC0 0xF9E7 # 0 +0xECC1 0xF9E8 # 0 +0xECC2 0x8CBD # 0 +0xECC3 0x8CB3 # 0 +0xECC4 0x9087 # 0 +0xECC5 0xF9E9 # 0 +0xECC6 0xF9EA # 0 +0xECC7 0x98F4 # 0 +0xECC8 0x990C # 0 +0xECC9 0xF9EB # 0 +0xECCA 0xF9EC # 0 +0xECCB 0x7037 # 0 +0xECCC 0x76CA # 0 +0xECCD 0x7FCA # 0 +0xECCE 0x7FCC # 0 +0xECCF 0x7FFC # 0 +0xECD0 0x8B1A # 0 +0xECD1 0x4EBA # 0 +0xECD2 0x4EC1 # 0 +0xECD3 0x5203 # 0 +0xECD4 0x5370 # 0 +0xECD5 0xF9ED # 0 +0xECD6 0x54BD # 0 +0xECD7 0x56E0 # 0 +0xECD8 0x59FB # 0 +0xECD9 0x5BC5 # 0 +0xECDA 0x5F15 # 0 +0xECDB 0x5FCD # 0 +0xECDC 0x6E6E # 0 +0xECDD 0xF9EE # 0 +0xECDE 0xF9EF # 0 +0xECDF 0x7D6A # 0 +0xECE0 0x8335 # 0 +0xECE1 0xF9F0 # 0 +0xECE2 0x8693 # 0 +0xECE3 0x8A8D # 0 +0xECE4 0xF9F1 # 0 +0xECE5 0x976D # 0 +0xECE6 0x9777 # 0 +0xECE7 0xF9F2 # 0 +0xECE8 0xF9F3 # 0 +0xECE9 0x4E00 # 0 +0xECEA 0x4F5A # 0 +0xECEB 0x4F7E # 0 +0xECEC 0x58F9 # 0 +0xECED 0x65E5 # 0 +0xECEE 0x6EA2 # 0 +0xECEF 0x9038 # 0 +0xECF0 0x93B0 # 0 +0xECF1 0x99B9 # 0 +0xECF2 0x4EFB # 0 +0xECF3 0x58EC # 0 +0xECF4 0x598A # 0 +0xECF5 0x59D9 # 0 +0xECF6 0x6041 # 0 +0xECF7 0xF9F4 # 0 +0xECF8 0xF9F5 # 0 +0xECF9 0x7A14 # 0 +0xECFA 0xF9F6 # 0 +0xECFB 0x834F # 0 +0xECFC 0x8CC3 # 0 +0xECFD 0x5165 # 0 +0xECFE 0x5344 # 0 +0xEDA1 0xF9F7 # 0 +0xEDA2 0xF9F8 # 0 +0xEDA3 0xF9F9 # 0 +0xEDA4 0x4ECD # 0 +0xEDA5 0x5269 # 0 +0xEDA6 0x5B55 # 0 +0xEDA7 0x82BF # 0 +0xEDA8 0x4ED4 # 0 +0xEDA9 0x523A # 0 +0xEDAA 0x54A8 # 0 +0xEDAB 0x59C9 # 0 +0xEDAC 0x59FF # 0 +0xEDAD 0x5B50 # 0 +0xEDAE 0x5B57 # 0 +0xEDAF 0x5B5C # 0 +0xEDB0 0x6063 # 0 +0xEDB1 0x6148 # 0 +0xEDB2 0x6ECB # 0 +0xEDB3 0x7099 # 0 +0xEDB4 0x716E # 0 +0xEDB5 0x7386 # 0 +0xEDB6 0x74F7 # 0 +0xEDB7 0x75B5 # 0 +0xEDB8 0x78C1 # 0 +0xEDB9 0x7D2B # 0 +0xEDBA 0x8005 # 0 +0xEDBB 0x81EA # 0 +0xEDBC 0x8328 # 0 +0xEDBD 0x8517 # 0 +0xEDBE 0x85C9 # 0 +0xEDBF 0x8AEE # 0 +0xEDC0 0x8CC7 # 0 +0xEDC1 0x96CC # 0 +0xEDC2 0x4F5C # 0 +0xEDC3 0x52FA # 0 +0xEDC4 0x56BC # 0 +0xEDC5 0x65AB # 0 +0xEDC6 0x6628 # 0 +0xEDC7 0x707C # 0 +0xEDC8 0x70B8 # 0 +0xEDC9 0x7235 # 0 +0xEDCA 0x7DBD # 0 +0xEDCB 0x828D # 0 +0xEDCC 0x914C # 0 +0xEDCD 0x96C0 # 0 +0xEDCE 0x9D72 # 0 +0xEDCF 0x5B71 # 0 +0xEDD0 0x68E7 # 0 +0xEDD1 0x6B98 # 0 +0xEDD2 0x6F7A # 0 +0xEDD3 0x76DE # 0 +0xEDD4 0x5C91 # 0 +0xEDD5 0x66AB # 0 +0xEDD6 0x6F5B # 0 +0xEDD7 0x7BB4 # 0 +0xEDD8 0x7C2A # 0 +0xEDD9 0x8836 # 0 +0xEDDA 0x96DC # 0 +0xEDDB 0x4E08 # 0 +0xEDDC 0x4ED7 # 0 +0xEDDD 0x5320 # 0 +0xEDDE 0x5834 # 0 +0xEDDF 0x58BB # 0 +0xEDE0 0x58EF # 0 +0xEDE1 0x596C # 0 +0xEDE2 0x5C07 # 0 +0xEDE3 0x5E33 # 0 +0xEDE4 0x5E84 # 0 +0xEDE5 0x5F35 # 0 +0xEDE6 0x638C # 0 +0xEDE7 0x66B2 # 0 +0xEDE8 0x6756 # 0 +0xEDE9 0x6A1F # 0 +0xEDEA 0x6AA3 # 0 +0xEDEB 0x6B0C # 0 +0xEDEC 0x6F3F # 0 +0xEDED 0x7246 # 0 +0xEDEE 0xF9FA # 0 +0xEDEF 0x7350 # 0 +0xEDF0 0x748B # 0 +0xEDF1 0x7AE0 # 0 +0xEDF2 0x7CA7 # 0 +0xEDF3 0x8178 # 0 +0xEDF4 0x81DF # 0 +0xEDF5 0x81E7 # 0 +0xEDF6 0x838A # 0 +0xEDF7 0x846C # 0 +0xEDF8 0x8523 # 0 +0xEDF9 0x8594 # 0 +0xEDFA 0x85CF # 0 +0xEDFB 0x88DD # 0 +0xEDFC 0x8D13 # 0 +0xEDFD 0x91AC # 0 +0xEDFE 0x9577 # 0 +0xEEA1 0x969C # 0 +0xEEA2 0x518D # 0 +0xEEA3 0x54C9 # 0 +0xEEA4 0x5728 # 0 +0xEEA5 0x5BB0 # 0 +0xEEA6 0x624D # 0 +0xEEA7 0x6750 # 0 +0xEEA8 0x683D # 0 +0xEEA9 0x6893 # 0 +0xEEAA 0x6E3D # 0 +0xEEAB 0x6ED3 # 0 +0xEEAC 0x707D # 0 +0xEEAD 0x7E21 # 0 +0xEEAE 0x88C1 # 0 +0xEEAF 0x8CA1 # 0 +0xEEB0 0x8F09 # 0 +0xEEB1 0x9F4B # 0 +0xEEB2 0x9F4E # 0 +0xEEB3 0x722D # 0 +0xEEB4 0x7B8F # 0 +0xEEB5 0x8ACD # 0 +0xEEB6 0x931A # 0 +0xEEB7 0x4F47 # 0 +0xEEB8 0x4F4E # 0 +0xEEB9 0x5132 # 0 +0xEEBA 0x5480 # 0 +0xEEBB 0x59D0 # 0 +0xEEBC 0x5E95 # 0 +0xEEBD 0x62B5 # 0 +0xEEBE 0x6775 # 0 +0xEEBF 0x696E # 0 +0xEEC0 0x6A17 # 0 +0xEEC1 0x6CAE # 0 +0xEEC2 0x6E1A # 0 +0xEEC3 0x72D9 # 0 +0xEEC4 0x732A # 0 +0xEEC5 0x75BD # 0 +0xEEC6 0x7BB8 # 0 +0xEEC7 0x7D35 # 0 +0xEEC8 0x82E7 # 0 +0xEEC9 0x83F9 # 0 +0xEECA 0x8457 # 0 +0xEECB 0x85F7 # 0 +0xEECC 0x8A5B # 0 +0xEECD 0x8CAF # 0 +0xEECE 0x8E87 # 0 +0xEECF 0x9019 # 0 +0xEED0 0x90B8 # 0 +0xEED1 0x96CE # 0 +0xEED2 0x9F5F # 0 +0xEED3 0x52E3 # 0 +0xEED4 0x540A # 0 +0xEED5 0x5AE1 # 0 +0xEED6 0x5BC2 # 0 +0xEED7 0x6458 # 0 +0xEED8 0x6575 # 0 +0xEED9 0x6EF4 # 0 +0xEEDA 0x72C4 # 0 +0xEEDB 0xF9FB # 0 +0xEEDC 0x7684 # 0 +0xEEDD 0x7A4D # 0 +0xEEDE 0x7B1B # 0 +0xEEDF 0x7C4D # 0 +0xEEE0 0x7E3E # 0 +0xEEE1 0x7FDF # 0 +0xEEE2 0x837B # 0 +0xEEE3 0x8B2B # 0 +0xEEE4 0x8CCA # 0 +0xEEE5 0x8D64 # 0 +0xEEE6 0x8DE1 # 0 +0xEEE7 0x8E5F # 0 +0xEEE8 0x8FEA # 0 +0xEEE9 0x8FF9 # 0 +0xEEEA 0x9069 # 0 +0xEEEB 0x93D1 # 0 +0xEEEC 0x4F43 # 0 +0xEEED 0x4F7A # 0 +0xEEEE 0x50B3 # 0 +0xEEEF 0x5168 # 0 +0xEEF0 0x5178 # 0 +0xEEF1 0x524D # 0 +0xEEF2 0x526A # 0 +0xEEF3 0x5861 # 0 +0xEEF4 0x587C # 0 +0xEEF5 0x5960 # 0 +0xEEF6 0x5C08 # 0 +0xEEF7 0x5C55 # 0 +0xEEF8 0x5EDB # 0 +0xEEF9 0x609B # 0 +0xEEFA 0x6230 # 0 +0xEEFB 0x6813 # 0 +0xEEFC 0x6BBF # 0 +0xEEFD 0x6C08 # 0 +0xEEFE 0x6FB1 # 0 +0xEFA1 0x714E # 0 +0xEFA2 0x7420 # 0 +0xEFA3 0x7530 # 0 +0xEFA4 0x7538 # 0 +0xEFA5 0x7551 # 0 +0xEFA6 0x7672 # 0 +0xEFA7 0x7B4C # 0 +0xEFA8 0x7B8B # 0 +0xEFA9 0x7BAD # 0 +0xEFAA 0x7BC6 # 0 +0xEFAB 0x7E8F # 0 +0xEFAC 0x8A6E # 0 +0xEFAD 0x8F3E # 0 +0xEFAE 0x8F49 # 0 +0xEFAF 0x923F # 0 +0xEFB0 0x9293 # 0 +0xEFB1 0x9322 # 0 +0xEFB2 0x942B # 0 +0xEFB3 0x96FB # 0 +0xEFB4 0x985A # 0 +0xEFB5 0x986B # 0 +0xEFB6 0x991E # 0 +0xEFB7 0x5207 # 0 +0xEFB8 0x622A # 0 +0xEFB9 0x6298 # 0 +0xEFBA 0x6D59 # 0 +0xEFBB 0x7664 # 0 +0xEFBC 0x7ACA # 0 +0xEFBD 0x7BC0 # 0 +0xEFBE 0x7D76 # 0 +0xEFBF 0x5360 # 0 +0xEFC0 0x5CBE # 0 +0xEFC1 0x5E97 # 0 +0xEFC2 0x6F38 # 0 +0xEFC3 0x70B9 # 0 +0xEFC4 0x7C98 # 0 +0xEFC5 0x9711 # 0 +0xEFC6 0x9B8E # 0 +0xEFC7 0x9EDE # 0 +0xEFC8 0x63A5 # 0 +0xEFC9 0x647A # 0 +0xEFCA 0x8776 # 0 +0xEFCB 0x4E01 # 0 +0xEFCC 0x4E95 # 0 +0xEFCD 0x4EAD # 0 +0xEFCE 0x505C # 0 +0xEFCF 0x5075 # 0 +0xEFD0 0x5448 # 0 +0xEFD1 0x59C3 # 0 +0xEFD2 0x5B9A # 0 +0xEFD3 0x5E40 # 0 +0xEFD4 0x5EAD # 0 +0xEFD5 0x5EF7 # 0 +0xEFD6 0x5F81 # 0 +0xEFD7 0x60C5 # 0 +0xEFD8 0x633A # 0 +0xEFD9 0x653F # 0 +0xEFDA 0x6574 # 0 +0xEFDB 0x65CC # 0 +0xEFDC 0x6676 # 0 +0xEFDD 0x6678 # 0 +0xEFDE 0x67FE # 0 +0xEFDF 0x6968 # 0 +0xEFE0 0x6A89 # 0 +0xEFE1 0x6B63 # 0 +0xEFE2 0x6C40 # 0 +0xEFE3 0x6DC0 # 0 +0xEFE4 0x6DE8 # 0 +0xEFE5 0x6E1F # 0 +0xEFE6 0x6E5E # 0 +0xEFE7 0x701E # 0 +0xEFE8 0x70A1 # 0 +0xEFE9 0x738E # 0 +0xEFEA 0x73FD # 0 +0xEFEB 0x753A # 0 +0xEFEC 0x775B # 0 +0xEFED 0x7887 # 0 +0xEFEE 0x798E # 0 +0xEFEF 0x7A0B # 0 +0xEFF0 0x7A7D # 0 +0xEFF1 0x7CBE # 0 +0xEFF2 0x7D8E # 0 +0xEFF3 0x8247 # 0 +0xEFF4 0x8A02 # 0 +0xEFF5 0x8AEA # 0 +0xEFF6 0x8C9E # 0 +0xEFF7 0x912D # 0 +0xEFF8 0x914A # 0 +0xEFF9 0x91D8 # 0 +0xEFFA 0x9266 # 0 +0xEFFB 0x92CC # 0 +0xEFFC 0x9320 # 0 +0xEFFD 0x9706 # 0 +0xEFFE 0x9756 # 0 +0xF0A1 0x975C # 0 +0xF0A2 0x9802 # 0 +0xF0A3 0x9F0E # 0 +0xF0A4 0x5236 # 0 +0xF0A5 0x5291 # 0 +0xF0A6 0x557C # 0 +0xF0A7 0x5824 # 0 +0xF0A8 0x5E1D # 0 +0xF0A9 0x5F1F # 0 +0xF0AA 0x608C # 0 +0xF0AB 0x63D0 # 0 +0xF0AC 0x68AF # 0 +0xF0AD 0x6FDF # 0 +0xF0AE 0x796D # 0 +0xF0AF 0x7B2C # 0 +0xF0B0 0x81CD # 0 +0xF0B1 0x85BA # 0 +0xF0B2 0x88FD # 0 +0xF0B3 0x8AF8 # 0 +0xF0B4 0x8E44 # 0 +0xF0B5 0x918D # 0 +0xF0B6 0x9664 # 0 +0xF0B7 0x969B # 0 +0xF0B8 0x973D # 0 +0xF0B9 0x984C # 0 +0xF0BA 0x9F4A # 0 +0xF0BB 0x4FCE # 0 +0xF0BC 0x5146 # 0 +0xF0BD 0x51CB # 0 +0xF0BE 0x52A9 # 0 +0xF0BF 0x5632 # 0 +0xF0C0 0x5F14 # 0 +0xF0C1 0x5F6B # 0 +0xF0C2 0x63AA # 0 +0xF0C3 0x64CD # 0 +0xF0C4 0x65E9 # 0 +0xF0C5 0x6641 # 0 +0xF0C6 0x66FA # 0 +0xF0C7 0x66F9 # 0 +0xF0C8 0x671D # 0 +0xF0C9 0x689D # 0 +0xF0CA 0x68D7 # 0 +0xF0CB 0x69FD # 0 +0xF0CC 0x6F15 # 0 +0xF0CD 0x6F6E # 0 +0xF0CE 0x7167 # 0 +0xF0CF 0x71E5 # 0 +0xF0D0 0x722A # 0 +0xF0D1 0x74AA # 0 +0xF0D2 0x773A # 0 +0xF0D3 0x7956 # 0 +0xF0D4 0x795A # 0 +0xF0D5 0x79DF # 0 +0xF0D6 0x7A20 # 0 +0xF0D7 0x7A95 # 0 +0xF0D8 0x7C97 # 0 +0xF0D9 0x7CDF # 0 +0xF0DA 0x7D44 # 0 +0xF0DB 0x7E70 # 0 +0xF0DC 0x8087 # 0 +0xF0DD 0x85FB # 0 +0xF0DE 0x86A4 # 0 +0xF0DF 0x8A54 # 0 +0xF0E0 0x8ABF # 0 +0xF0E1 0x8D99 # 0 +0xF0E2 0x8E81 # 0 +0xF0E3 0x9020 # 0 +0xF0E4 0x906D # 0 +0xF0E5 0x91E3 # 0 +0xF0E6 0x963B # 0 +0xF0E7 0x96D5 # 0 +0xF0E8 0x9CE5 # 0 +0xF0E9 0x65CF # 0 +0xF0EA 0x7C07 # 0 +0xF0EB 0x8DB3 # 0 +0xF0EC 0x93C3 # 0 +0xF0ED 0x5B58 # 0 +0xF0EE 0x5C0A # 0 +0xF0EF 0x5352 # 0 +0xF0F0 0x62D9 # 0 +0xF0F1 0x731D # 0 +0xF0F2 0x5027 # 0 +0xF0F3 0x5B97 # 0 +0xF0F4 0x5F9E # 0 +0xF0F5 0x60B0 # 0 +0xF0F6 0x616B # 0 +0xF0F7 0x68D5 # 0 +0xF0F8 0x6DD9 # 0 +0xF0F9 0x742E # 0 +0xF0FA 0x7A2E # 0 +0xF0FB 0x7D42 # 0 +0xF0FC 0x7D9C # 0 +0xF0FD 0x7E31 # 0 +0xF0FE 0x816B # 0 +0xF1A1 0x8E2A # 0 +0xF1A2 0x8E35 # 0 +0xF1A3 0x937E # 0 +0xF1A4 0x9418 # 0 +0xF1A5 0x4F50 # 0 +0xF1A6 0x5750 # 0 +0xF1A7 0x5DE6 # 0 +0xF1A8 0x5EA7 # 0 +0xF1A9 0x632B # 0 +0xF1AA 0x7F6A # 0 +0xF1AB 0x4E3B # 0 +0xF1AC 0x4F4F # 0 +0xF1AD 0x4F8F # 0 +0xF1AE 0x505A # 0 +0xF1AF 0x59DD # 0 +0xF1B0 0x80C4 # 0 +0xF1B1 0x546A # 0 +0xF1B2 0x5468 # 0 +0xF1B3 0x55FE # 0 +0xF1B4 0x594F # 0 +0xF1B5 0x5B99 # 0 +0xF1B6 0x5DDE # 0 +0xF1B7 0x5EDA # 0 +0xF1B8 0x665D # 0 +0xF1B9 0x6731 # 0 +0xF1BA 0x67F1 # 0 +0xF1BB 0x682A # 0 +0xF1BC 0x6CE8 # 0 +0xF1BD 0x6D32 # 0 +0xF1BE 0x6E4A # 0 +0xF1BF 0x6F8D # 0 +0xF1C0 0x70B7 # 0 +0xF1C1 0x73E0 # 0 +0xF1C2 0x7587 # 0 +0xF1C3 0x7C4C # 0 +0xF1C4 0x7D02 # 0 +0xF1C5 0x7D2C # 0 +0xF1C6 0x7DA2 # 0 +0xF1C7 0x821F # 0 +0xF1C8 0x86DB # 0 +0xF1C9 0x8A3B # 0 +0xF1CA 0x8A85 # 0 +0xF1CB 0x8D70 # 0 +0xF1CC 0x8E8A # 0 +0xF1CD 0x8F33 # 0 +0xF1CE 0x9031 # 0 +0xF1CF 0x914E # 0 +0xF1D0 0x9152 # 0 +0xF1D1 0x9444 # 0 +0xF1D2 0x99D0 # 0 +0xF1D3 0x7AF9 # 0 +0xF1D4 0x7CA5 # 0 +0xF1D5 0x4FCA # 0 +0xF1D6 0x5101 # 0 +0xF1D7 0x51C6 # 0 +0xF1D8 0x57C8 # 0 +0xF1D9 0x5BEF # 0 +0xF1DA 0x5CFB # 0 +0xF1DB 0x6659 # 0 +0xF1DC 0x6A3D # 0 +0xF1DD 0x6D5A # 0 +0xF1DE 0x6E96 # 0 +0xF1DF 0x6FEC # 0 +0xF1E0 0x710C # 0 +0xF1E1 0x756F # 0 +0xF1E2 0x7AE3 # 0 +0xF1E3 0x8822 # 0 +0xF1E4 0x9021 # 0 +0xF1E5 0x9075 # 0 +0xF1E6 0x96CB # 0 +0xF1E7 0x99FF # 0 +0xF1E8 0x8301 # 0 +0xF1E9 0x4E2D # 0 +0xF1EA 0x4EF2 # 0 +0xF1EB 0x8846 # 0 +0xF1EC 0x91CD # 0 +0xF1ED 0x537D # 0 +0xF1EE 0x6ADB # 0 +0xF1EF 0x696B # 0 +0xF1F0 0x6C41 # 0 +0xF1F1 0x847A # 0 +0xF1F2 0x589E # 0 +0xF1F3 0x618E # 0 +0xF1F4 0x66FE # 0 +0xF1F5 0x62EF # 0 +0xF1F6 0x70DD # 0 +0xF1F7 0x7511 # 0 +0xF1F8 0x75C7 # 0 +0xF1F9 0x7E52 # 0 +0xF1FA 0x84B8 # 0 +0xF1FB 0x8B49 # 0 +0xF1FC 0x8D08 # 0 +0xF1FD 0x4E4B # 0 +0xF1FE 0x53EA # 0 +0xF2A1 0x54AB # 0 +0xF2A2 0x5730 # 0 +0xF2A3 0x5740 # 0 +0xF2A4 0x5FD7 # 0 +0xF2A5 0x6301 # 0 +0xF2A6 0x6307 # 0 +0xF2A7 0x646F # 0 +0xF2A8 0x652F # 0 +0xF2A9 0x65E8 # 0 +0xF2AA 0x667A # 0 +0xF2AB 0x679D # 0 +0xF2AC 0x67B3 # 0 +0xF2AD 0x6B62 # 0 +0xF2AE 0x6C60 # 0 +0xF2AF 0x6C9A # 0 +0xF2B0 0x6F2C # 0 +0xF2B1 0x77E5 # 0 +0xF2B2 0x7825 # 0 +0xF2B3 0x7949 # 0 +0xF2B4 0x7957 # 0 +0xF2B5 0x7D19 # 0 +0xF2B6 0x80A2 # 0 +0xF2B7 0x8102 # 0 +0xF2B8 0x81F3 # 0 +0xF2B9 0x829D # 0 +0xF2BA 0x82B7 # 0 +0xF2BB 0x8718 # 0 +0xF2BC 0x8A8C # 0 +0xF2BD 0xF9FC # 0 +0xF2BE 0x8D04 # 0 +0xF2BF 0x8DBE # 0 +0xF2C0 0x9072 # 0 +0xF2C1 0x76F4 # 0 +0xF2C2 0x7A19 # 0 +0xF2C3 0x7A37 # 0 +0xF2C4 0x7E54 # 0 +0xF2C5 0x8077 # 0 +0xF2C6 0x5507 # 0 +0xF2C7 0x55D4 # 0 +0xF2C8 0x5875 # 0 +0xF2C9 0x632F # 0 +0xF2CA 0x6422 # 0 +0xF2CB 0x6649 # 0 +0xF2CC 0x664B # 0 +0xF2CD 0x686D # 0 +0xF2CE 0x699B # 0 +0xF2CF 0x6B84 # 0 +0xF2D0 0x6D25 # 0 +0xF2D1 0x6EB1 # 0 +0xF2D2 0x73CD # 0 +0xF2D3 0x7468 # 0 +0xF2D4 0x74A1 # 0 +0xF2D5 0x755B # 0 +0xF2D6 0x75B9 # 0 +0xF2D7 0x76E1 # 0 +0xF2D8 0x771E # 0 +0xF2D9 0x778B # 0 +0xF2DA 0x79E6 # 0 +0xF2DB 0x7E09 # 0 +0xF2DC 0x7E1D # 0 +0xF2DD 0x81FB # 0 +0xF2DE 0x852F # 0 +0xF2DF 0x8897 # 0 +0xF2E0 0x8A3A # 0 +0xF2E1 0x8CD1 # 0 +0xF2E2 0x8EEB # 0 +0xF2E3 0x8FB0 # 0 +0xF2E4 0x9032 # 0 +0xF2E5 0x93AD # 0 +0xF2E6 0x9663 # 0 +0xF2E7 0x9673 # 0 +0xF2E8 0x9707 # 0 +0xF2E9 0x4F84 # 0 +0xF2EA 0x53F1 # 0 +0xF2EB 0x59EA # 0 +0xF2EC 0x5AC9 # 0 +0xF2ED 0x5E19 # 0 +0xF2EE 0x684E # 0 +0xF2EF 0x74C6 # 0 +0xF2F0 0x75BE # 0 +0xF2F1 0x79E9 # 0 +0xF2F2 0x7A92 # 0 +0xF2F3 0x81A3 # 0 +0xF2F4 0x86ED # 0 +0xF2F5 0x8CEA # 0 +0xF2F6 0x8DCC # 0 +0xF2F7 0x8FED # 0 +0xF2F8 0x659F # 0 +0xF2F9 0x6715 # 0 +0xF2FA 0xF9FD # 0 +0xF2FB 0x57F7 # 0 +0xF2FC 0x6F57 # 0 +0xF2FD 0x7DDD # 0 +0xF2FE 0x8F2F # 0 +0xF3A1 0x93F6 # 0 +0xF3A2 0x96C6 # 0 +0xF3A3 0x5FB5 # 0 +0xF3A4 0x61F2 # 0 +0xF3A5 0x6F84 # 0 +0xF3A6 0x4E14 # 0 +0xF3A7 0x4F98 # 0 +0xF3A8 0x501F # 0 +0xF3A9 0x53C9 # 0 +0xF3AA 0x55DF # 0 +0xF3AB 0x5D6F # 0 +0xF3AC 0x5DEE # 0 +0xF3AD 0x6B21 # 0 +0xF3AE 0x6B64 # 0 +0xF3AF 0x78CB # 0 +0xF3B0 0x7B9A # 0 +0xF3B1 0xF9FE # 0 +0xF3B2 0x8E49 # 0 +0xF3B3 0x8ECA # 0 +0xF3B4 0x906E # 0 +0xF3B5 0x6349 # 0 +0xF3B6 0x643E # 0 +0xF3B7 0x7740 # 0 +0xF3B8 0x7A84 # 0 +0xF3B9 0x932F # 0 +0xF3BA 0x947F # 0 +0xF3BB 0x9F6A # 0 +0xF3BC 0x64B0 # 0 +0xF3BD 0x6FAF # 0 +0xF3BE 0x71E6 # 0 +0xF3BF 0x74A8 # 0 +0xF3C0 0x74DA # 0 +0xF3C1 0x7AC4 # 0 +0xF3C2 0x7C12 # 0 +0xF3C3 0x7E82 # 0 +0xF3C4 0x7CB2 # 0 +0xF3C5 0x7E98 # 0 +0xF3C6 0x8B9A # 0 +0xF3C7 0x8D0A # 0 +0xF3C8 0x947D # 0 +0xF3C9 0x9910 # 0 +0xF3CA 0x994C # 0 +0xF3CB 0x5239 # 0 +0xF3CC 0x5BDF # 0 +0xF3CD 0x64E6 # 0 +0xF3CE 0x672D # 0 +0xF3CF 0x7D2E # 0 +0xF3D0 0x50ED # 0 +0xF3D1 0x53C3 # 0 +0xF3D2 0x5879 # 0 +0xF3D3 0x6158 # 0 +0xF3D4 0x6159 # 0 +0xF3D5 0x61FA # 0 +0xF3D6 0x65AC # 0 +0xF3D7 0x7AD9 # 0 +0xF3D8 0x8B92 # 0 +0xF3D9 0x8B96 # 0 +0xF3DA 0x5009 # 0 +0xF3DB 0x5021 # 0 +0xF3DC 0x5275 # 0 +0xF3DD 0x5531 # 0 +0xF3DE 0x5A3C # 0 +0xF3DF 0x5EE0 # 0 +0xF3E0 0x5F70 # 0 +0xF3E1 0x6134 # 0 +0xF3E2 0x655E # 0 +0xF3E3 0x660C # 0 +0xF3E4 0x6636 # 0 +0xF3E5 0x66A2 # 0 +0xF3E6 0x69CD # 0 +0xF3E7 0x6EC4 # 0 +0xF3E8 0x6F32 # 0 +0xF3E9 0x7316 # 0 +0xF3EA 0x7621 # 0 +0xF3EB 0x7A93 # 0 +0xF3EC 0x8139 # 0 +0xF3ED 0x8259 # 0 +0xF3EE 0x83D6 # 0 +0xF3EF 0x84BC # 0 +0xF3F0 0x50B5 # 0 +0xF3F1 0x57F0 # 0 +0xF3F2 0x5BC0 # 0 +0xF3F3 0x5BE8 # 0 +0xF3F4 0x5F69 # 0 +0xF3F5 0x63A1 # 0 +0xF3F6 0x7826 # 0 +0xF3F7 0x7DB5 # 0 +0xF3F8 0x83DC # 0 +0xF3F9 0x8521 # 0 +0xF3FA 0x91C7 # 0 +0xF3FB 0x91F5 # 0 +0xF3FC 0x518A # 0 +0xF3FD 0x67F5 # 0 +0xF3FE 0x7B56 # 0 +0xF4A1 0x8CAC # 0 +0xF4A2 0x51C4 # 0 +0xF4A3 0x59BB # 0 +0xF4A4 0x60BD # 0 +0xF4A5 0x8655 # 0 +0xF4A6 0x501C # 0 +0xF4A7 0xF9FF # 0 +0xF4A8 0x5254 # 0 +0xF4A9 0x5C3A # 0 +0xF4AA 0x617D # 0 +0xF4AB 0x621A # 0 +0xF4AC 0x62D3 # 0 +0xF4AD 0x64F2 # 0 +0xF4AE 0x65A5 # 0 +0xF4AF 0x6ECC # 0 +0xF4B0 0x7620 # 0 +0xF4B1 0x810A # 0 +0xF4B2 0x8E60 # 0 +0xF4B3 0x965F # 0 +0xF4B4 0x96BB # 0 +0xF4B5 0x4EDF # 0 +0xF4B6 0x5343 # 0 +0xF4B7 0x5598 # 0 +0xF4B8 0x5929 # 0 +0xF4B9 0x5DDD # 0 +0xF4BA 0x64C5 # 0 +0xF4BB 0x6CC9 # 0 +0xF4BC 0x6DFA # 0 +0xF4BD 0x7394 # 0 +0xF4BE 0x7A7F # 0 +0xF4BF 0x821B # 0 +0xF4C0 0x85A6 # 0 +0xF4C1 0x8CE4 # 0 +0xF4C2 0x8E10 # 0 +0xF4C3 0x9077 # 0 +0xF4C4 0x91E7 # 0 +0xF4C5 0x95E1 # 0 +0xF4C6 0x9621 # 0 +0xF4C7 0x97C6 # 0 +0xF4C8 0x51F8 # 0 +0xF4C9 0x54F2 # 0 +0xF4CA 0x5586 # 0 +0xF4CB 0x5FB9 # 0 +0xF4CC 0x64A4 # 0 +0xF4CD 0x6F88 # 0 +0xF4CE 0x7DB4 # 0 +0xF4CF 0x8F1F # 0 +0xF4D0 0x8F4D # 0 +0xF4D1 0x9435 # 0 +0xF4D2 0x50C9 # 0 +0xF4D3 0x5C16 # 0 +0xF4D4 0x6CBE # 0 +0xF4D5 0x6DFB # 0 +0xF4D6 0x751B # 0 +0xF4D7 0x77BB # 0 +0xF4D8 0x7C3D # 0 +0xF4D9 0x7C64 # 0 +0xF4DA 0x8A79 # 0 +0xF4DB 0x8AC2 # 0 +0xF4DC 0x581E # 0 +0xF4DD 0x59BE # 0 +0xF4DE 0x5E16 # 0 +0xF4DF 0x6377 # 0 +0xF4E0 0x7252 # 0 +0xF4E1 0x758A # 0 +0xF4E2 0x776B # 0 +0xF4E3 0x8ADC # 0 +0xF4E4 0x8CBC # 0 +0xF4E5 0x8F12 # 0 +0xF4E6 0x5EF3 # 0 +0xF4E7 0x6674 # 0 +0xF4E8 0x6DF8 # 0 +0xF4E9 0x807D # 0 +0xF4EA 0x83C1 # 0 +0xF4EB 0x8ACB # 0 +0xF4EC 0x9751 # 0 +0xF4ED 0x9BD6 # 0 +0xF4EE 0xFA00 # 0 +0xF4EF 0x5243 # 0 +0xF4F0 0x66FF # 0 +0xF4F1 0x6D95 # 0 +0xF4F2 0x6EEF # 0 +0xF4F3 0x7DE0 # 0 +0xF4F4 0x8AE6 # 0 +0xF4F5 0x902E # 0 +0xF4F6 0x905E # 0 +0xF4F7 0x9AD4 # 0 +0xF4F8 0x521D # 0 +0xF4F9 0x527F # 0 +0xF4FA 0x54E8 # 0 +0xF4FB 0x6194 # 0 +0xF4FC 0x6284 # 0 +0xF4FD 0x62DB # 0 +0xF4FE 0x68A2 # 0 +0xF5A1 0x6912 # 0 +0xF5A2 0x695A # 0 +0xF5A3 0x6A35 # 0 +0xF5A4 0x7092 # 0 +0xF5A5 0x7126 # 0 +0xF5A6 0x785D # 0 +0xF5A7 0x7901 # 0 +0xF5A8 0x790E # 0 +0xF5A9 0x79D2 # 0 +0xF5AA 0x7A0D # 0 +0xF5AB 0x8096 # 0 +0xF5AC 0x8278 # 0 +0xF5AD 0x82D5 # 0 +0xF5AE 0x8349 # 0 +0xF5AF 0x8549 # 0 +0xF5B0 0x8C82 # 0 +0xF5B1 0x8D85 # 0 +0xF5B2 0x9162 # 0 +0xF5B3 0x918B # 0 +0xF5B4 0x91AE # 0 +0xF5B5 0x4FC3 # 0 +0xF5B6 0x56D1 # 0 +0xF5B7 0x71ED # 0 +0xF5B8 0x77D7 # 0 +0xF5B9 0x8700 # 0 +0xF5BA 0x89F8 # 0 +0xF5BB 0x5BF8 # 0 +0xF5BC 0x5FD6 # 0 +0xF5BD 0x6751 # 0 +0xF5BE 0x90A8 # 0 +0xF5BF 0x53E2 # 0 +0xF5C0 0x585A # 0 +0xF5C1 0x5BF5 # 0 +0xF5C2 0x60A4 # 0 +0xF5C3 0x6181 # 0 +0xF5C4 0x6460 # 0 +0xF5C5 0x7E3D # 0 +0xF5C6 0x8070 # 0 +0xF5C7 0x8525 # 0 +0xF5C8 0x9283 # 0 +0xF5C9 0x64AE # 0 +0xF5CA 0x50AC # 0 +0xF5CB 0x5D14 # 0 +0xF5CC 0x6700 # 0 +0xF5CD 0x589C # 0 +0xF5CE 0x62BD # 0 +0xF5CF 0x63A8 # 0 +0xF5D0 0x690E # 0 +0xF5D1 0x6978 # 0 +0xF5D2 0x6A1E # 0 +0xF5D3 0x6E6B # 0 +0xF5D4 0x76BA # 0 +0xF5D5 0x79CB # 0 +0xF5D6 0x82BB # 0 +0xF5D7 0x8429 # 0 +0xF5D8 0x8ACF # 0 +0xF5D9 0x8DA8 # 0 +0xF5DA 0x8FFD # 0 +0xF5DB 0x9112 # 0 +0xF5DC 0x914B # 0 +0xF5DD 0x919C # 0 +0xF5DE 0x9310 # 0 +0xF5DF 0x9318 # 0 +0xF5E0 0x939A # 0 +0xF5E1 0x96DB # 0 +0xF5E2 0x9A36 # 0 +0xF5E3 0x9C0D # 0 +0xF5E4 0x4E11 # 0 +0xF5E5 0x755C # 0 +0xF5E6 0x795D # 0 +0xF5E7 0x7AFA # 0 +0xF5E8 0x7B51 # 0 +0xF5E9 0x7BC9 # 0 +0xF5EA 0x7E2E # 0 +0xF5EB 0x84C4 # 0 +0xF5EC 0x8E59 # 0 +0xF5ED 0x8E74 # 0 +0xF5EE 0x8EF8 # 0 +0xF5EF 0x9010 # 0 +0xF5F0 0x6625 # 0 +0xF5F1 0x693F # 0 +0xF5F2 0x7443 # 0 +0xF5F3 0x51FA # 0 +0xF5F4 0x672E # 0 +0xF5F5 0x9EDC # 0 +0xF5F6 0x5145 # 0 +0xF5F7 0x5FE0 # 0 +0xF5F8 0x6C96 # 0 +0xF5F9 0x87F2 # 0 +0xF5FA 0x885D # 0 +0xF5FB 0x8877 # 0 +0xF5FC 0x60B4 # 0 +0xF5FD 0x81B5 # 0 +0xF5FE 0x8403 # 0 +0xF6A1 0x8D05 # 0 +0xF6A2 0x53D6 # 0 +0xF6A3 0x5439 # 0 +0xF6A4 0x5634 # 0 +0xF6A5 0x5A36 # 0 +0xF6A6 0x5C31 # 0 +0xF6A7 0x708A # 0 +0xF6A8 0x7FE0 # 0 +0xF6A9 0x805A # 0 +0xF6AA 0x8106 # 0 +0xF6AB 0x81ED # 0 +0xF6AC 0x8DA3 # 0 +0xF6AD 0x9189 # 0 +0xF6AE 0x9A5F # 0 +0xF6AF 0x9DF2 # 0 +0xF6B0 0x5074 # 0 +0xF6B1 0x4EC4 # 0 +0xF6B2 0x53A0 # 0 +0xF6B3 0x60FB # 0 +0xF6B4 0x6E2C # 0 +0xF6B5 0x5C64 # 0 +0xF6B6 0x4F88 # 0 +0xF6B7 0x5024 # 0 +0xF6B8 0x55E4 # 0 +0xF6B9 0x5CD9 # 0 +0xF6BA 0x5E5F # 0 +0xF6BB 0x6065 # 0 +0xF6BC 0x6894 # 0 +0xF6BD 0x6CBB # 0 +0xF6BE 0x6DC4 # 0 +0xF6BF 0x71BE # 0 +0xF6C0 0x75D4 # 0 +0xF6C1 0x75F4 # 0 +0xF6C2 0x7661 # 0 +0xF6C3 0x7A1A # 0 +0xF6C4 0x7A49 # 0 +0xF6C5 0x7DC7 # 0 +0xF6C6 0x7DFB # 0 +0xF6C7 0x7F6E # 0 +0xF6C8 0x81F4 # 0 +0xF6C9 0x86A9 # 0 +0xF6CA 0x8F1C # 0 +0xF6CB 0x96C9 # 0 +0xF6CC 0x99B3 # 0 +0xF6CD 0x9F52 # 0 +0xF6CE 0x5247 # 0 +0xF6CF 0x52C5 # 0 +0xF6D0 0x98ED # 0 +0xF6D1 0x89AA # 0 +0xF6D2 0x4E03 # 0 +0xF6D3 0x67D2 # 0 +0xF6D4 0x6F06 # 0 +0xF6D5 0x4FB5 # 0 +0xF6D6 0x5BE2 # 0 +0xF6D7 0x6795 # 0 +0xF6D8 0x6C88 # 0 +0xF6D9 0x6D78 # 0 +0xF6DA 0x741B # 0 +0xF6DB 0x7827 # 0 +0xF6DC 0x91DD # 0 +0xF6DD 0x937C # 0 +0xF6DE 0x87C4 # 0 +0xF6DF 0x79E4 # 0 +0xF6E0 0x7A31 # 0 +0xF6E1 0x5FEB # 0 +0xF6E2 0x4ED6 # 0 +0xF6E3 0x54A4 # 0 +0xF6E4 0x553E # 0 +0xF6E5 0x58AE # 0 +0xF6E6 0x59A5 # 0 +0xF6E7 0x60F0 # 0 +0xF6E8 0x6253 # 0 +0xF6E9 0x62D6 # 0 +0xF6EA 0x6736 # 0 +0xF6EB 0x6955 # 0 +0xF6EC 0x8235 # 0 +0xF6ED 0x9640 # 0 +0xF6EE 0x99B1 # 0 +0xF6EF 0x99DD # 0 +0xF6F0 0x502C # 0 +0xF6F1 0x5353 # 0 +0xF6F2 0x5544 # 0 +0xF6F3 0x577C # 0 +0xF6F4 0xFA01 # 0 +0xF6F5 0x6258 # 0 +0xF6F6 0xFA02 # 0 +0xF6F7 0x64E2 # 0 +0xF6F8 0x666B # 0 +0xF6F9 0x67DD # 0 +0xF6FA 0x6FC1 # 0 +0xF6FB 0x6FEF # 0 +0xF6FC 0x7422 # 0 +0xF6FD 0x7438 # 0 +0xF6FE 0x8A17 # 0 +0xF7A1 0x9438 # 0 +0xF7A2 0x5451 # 0 +0xF7A3 0x5606 # 0 +0xF7A4 0x5766 # 0 +0xF7A5 0x5F48 # 0 +0xF7A6 0x619A # 0 +0xF7A7 0x6B4E # 0 +0xF7A8 0x7058 # 0 +0xF7A9 0x70AD # 0 +0xF7AA 0x7DBB # 0 +0xF7AB 0x8A95 # 0 +0xF7AC 0x596A # 0 +0xF7AD 0x812B # 0 +0xF7AE 0x63A2 # 0 +0xF7AF 0x7708 # 0 +0xF7B0 0x803D # 0 +0xF7B1 0x8CAA # 0 +0xF7B2 0x5854 # 0 +0xF7B3 0x642D # 0 +0xF7B4 0x69BB # 0 +0xF7B5 0x5B95 # 0 +0xF7B6 0x5E11 # 0 +0xF7B7 0x6E6F # 0 +0xF7B8 0xFA03 # 0 +0xF7B9 0x8569 # 0 +0xF7BA 0x514C # 0 +0xF7BB 0x53F0 # 0 +0xF7BC 0x592A # 0 +0xF7BD 0x6020 # 0 +0xF7BE 0x614B # 0 +0xF7BF 0x6B86 # 0 +0xF7C0 0x6C70 # 0 +0xF7C1 0x6CF0 # 0 +0xF7C2 0x7B1E # 0 +0xF7C3 0x80CE # 0 +0xF7C4 0x82D4 # 0 +0xF7C5 0x8DC6 # 0 +0xF7C6 0x90B0 # 0 +0xF7C7 0x98B1 # 0 +0xF7C8 0xFA04 # 0 +0xF7C9 0x64C7 # 0 +0xF7CA 0x6FA4 # 0 +0xF7CB 0x6491 # 0 +0xF7CC 0x6504 # 0 +0xF7CD 0x514E # 0 +0xF7CE 0x5410 # 0 +0xF7CF 0x571F # 0 +0xF7D0 0x8A0E # 0 +0xF7D1 0x615F # 0 +0xF7D2 0x6876 # 0 +0xF7D3 0xFA05 # 0 +0xF7D4 0x75DB # 0 +0xF7D5 0x7B52 # 0 +0xF7D6 0x7D71 # 0 +0xF7D7 0x901A # 0 +0xF7D8 0x5806 # 0 +0xF7D9 0x69CC # 0 +0xF7DA 0x817F # 0 +0xF7DB 0x892A # 0 +0xF7DC 0x9000 # 0 +0xF7DD 0x9839 # 0 +0xF7DE 0x5078 # 0 +0xF7DF 0x5957 # 0 +0xF7E0 0x59AC # 0 +0xF7E1 0x6295 # 0 +0xF7E2 0x900F # 0 +0xF7E3 0x9B2A # 0 +0xF7E4 0x615D # 0 +0xF7E5 0x7279 # 0 +0xF7E6 0x95D6 # 0 +0xF7E7 0x5761 # 0 +0xF7E8 0x5A46 # 0 +0xF7E9 0x5DF4 # 0 +0xF7EA 0x628A # 0 +0xF7EB 0x64AD # 0 +0xF7EC 0x64FA # 0 +0xF7ED 0x6777 # 0 +0xF7EE 0x6CE2 # 0 +0xF7EF 0x6D3E # 0 +0xF7F0 0x722C # 0 +0xF7F1 0x7436 # 0 +0xF7F2 0x7834 # 0 +0xF7F3 0x7F77 # 0 +0xF7F4 0x82AD # 0 +0xF7F5 0x8DDB # 0 +0xF7F6 0x9817 # 0 +0xF7F7 0x5224 # 0 +0xF7F8 0x5742 # 0 +0xF7F9 0x677F # 0 +0xF7FA 0x7248 # 0 +0xF7FB 0x74E3 # 0 +0xF7FC 0x8CA9 # 0 +0xF7FD 0x8FA6 # 0 +0xF7FE 0x9211 # 0 +0xF8A1 0x962A # 0 +0xF8A2 0x516B # 0 +0xF8A3 0x53ED # 0 +0xF8A4 0x634C # 0 +0xF8A5 0x4F69 # 0 +0xF8A6 0x5504 # 0 +0xF8A7 0x6096 # 0 +0xF8A8 0x6557 # 0 +0xF8A9 0x6C9B # 0 +0xF8AA 0x6D7F # 0 +0xF8AB 0x724C # 0 +0xF8AC 0x72FD # 0 +0xF8AD 0x7A17 # 0 +0xF8AE 0x8987 # 0 +0xF8AF 0x8C9D # 0 +0xF8B0 0x5F6D # 0 +0xF8B1 0x6F8E # 0 +0xF8B2 0x70F9 # 0 +0xF8B3 0x81A8 # 0 +0xF8B4 0x610E # 0 +0xF8B5 0x4FBF # 0 +0xF8B6 0x504F # 0 +0xF8B7 0x6241 # 0 +0xF8B8 0x7247 # 0 +0xF8B9 0x7BC7 # 0 +0xF8BA 0x7DE8 # 0 +0xF8BB 0x7FE9 # 0 +0xF8BC 0x904D # 0 +0xF8BD 0x97AD # 0 +0xF8BE 0x9A19 # 0 +0xF8BF 0x8CB6 # 0 +0xF8C0 0x576A # 0 +0xF8C1 0x5E73 # 0 +0xF8C2 0x67B0 # 0 +0xF8C3 0x840D # 0 +0xF8C4 0x8A55 # 0 +0xF8C5 0x5420 # 0 +0xF8C6 0x5B16 # 0 +0xF8C7 0x5E63 # 0 +0xF8C8 0x5EE2 # 0 +0xF8C9 0x5F0A # 0 +0xF8CA 0x6583 # 0 +0xF8CB 0x80BA # 0 +0xF8CC 0x853D # 0 +0xF8CD 0x9589 # 0 +0xF8CE 0x965B # 0 +0xF8CF 0x4F48 # 0 +0xF8D0 0x5305 # 0 +0xF8D1 0x530D # 0 +0xF8D2 0x530F # 0 +0xF8D3 0x5486 # 0 +0xF8D4 0x54FA # 0 +0xF8D5 0x5703 # 0 +0xF8D6 0x5E03 # 0 +0xF8D7 0x6016 # 0 +0xF8D8 0x629B # 0 +0xF8D9 0x62B1 # 0 +0xF8DA 0x6355 # 0 +0xF8DB 0xFA06 # 0 +0xF8DC 0x6CE1 # 0 +0xF8DD 0x6D66 # 0 +0xF8DE 0x75B1 # 0 +0xF8DF 0x7832 # 0 +0xF8E0 0x80DE # 0 +0xF8E1 0x812F # 0 +0xF8E2 0x82DE # 0 +0xF8E3 0x8461 # 0 +0xF8E4 0x84B2 # 0 +0xF8E5 0x888D # 0 +0xF8E6 0x8912 # 0 +0xF8E7 0x900B # 0 +0xF8E8 0x92EA # 0 +0xF8E9 0x98FD # 0 +0xF8EA 0x9B91 # 0 +0xF8EB 0x5E45 # 0 +0xF8EC 0x66B4 # 0 +0xF8ED 0x66DD # 0 +0xF8EE 0x7011 # 0 +0xF8EF 0x7206 # 0 +0xF8F0 0xFA07 # 0 +0xF8F1 0x4FF5 # 0 +0xF8F2 0x527D # 0 +0xF8F3 0x5F6A # 0 +0xF8F4 0x6153 # 0 +0xF8F5 0x6753 # 0 +0xF8F6 0x6A19 # 0 +0xF8F7 0x6F02 # 0 +0xF8F8 0x74E2 # 0 +0xF8F9 0x7968 # 0 +0xF8FA 0x8868 # 0 +0xF8FB 0x8C79 # 0 +0xF8FC 0x98C7 # 0 +0xF8FD 0x98C4 # 0 +0xF8FE 0x9A43 # 0 +0xF9A1 0x54C1 # 0 +0xF9A2 0x7A1F # 0 +0xF9A3 0x6953 # 0 +0xF9A4 0x8AF7 # 0 +0xF9A5 0x8C4A # 0 +0xF9A6 0x98A8 # 0 +0xF9A7 0x99AE # 0 +0xF9A8 0x5F7C # 0 +0xF9A9 0x62AB # 0 +0xF9AA 0x75B2 # 0 +0xF9AB 0x76AE # 0 +0xF9AC 0x88AB # 0 +0xF9AD 0x907F # 0 +0xF9AE 0x9642 # 0 +0xF9AF 0x5339 # 0 +0xF9B0 0x5F3C # 0 +0xF9B1 0x5FC5 # 0 +0xF9B2 0x6CCC # 0 +0xF9B3 0x73CC # 0 +0xF9B4 0x7562 # 0 +0xF9B5 0x758B # 0 +0xF9B6 0x7B46 # 0 +0xF9B7 0x82FE # 0 +0xF9B8 0x999D # 0 +0xF9B9 0x4E4F # 0 +0xF9BA 0x903C # 0 +0xF9BB 0x4E0B # 0 +0xF9BC 0x4F55 # 0 +0xF9BD 0x53A6 # 0 +0xF9BE 0x590F # 0 +0xF9BF 0x5EC8 # 0 +0xF9C0 0x6630 # 0 +0xF9C1 0x6CB3 # 0 +0xF9C2 0x7455 # 0 +0xF9C3 0x8377 # 0 +0xF9C4 0x8766 # 0 +0xF9C5 0x8CC0 # 0 +0xF9C6 0x9050 # 0 +0xF9C7 0x971E # 0 +0xF9C8 0x9C15 # 0 +0xF9C9 0x58D1 # 0 +0xF9CA 0x5B78 # 0 +0xF9CB 0x8650 # 0 +0xF9CC 0x8B14 # 0 +0xF9CD 0x9DB4 # 0 +0xF9CE 0x5BD2 # 0 +0xF9CF 0x6068 # 0 +0xF9D0 0x608D # 0 +0xF9D1 0x65F1 # 0 +0xF9D2 0x6C57 # 0 +0xF9D3 0x6F22 # 0 +0xF9D4 0x6FA3 # 0 +0xF9D5 0x701A # 0 +0xF9D6 0x7F55 # 0 +0xF9D7 0x7FF0 # 0 +0xF9D8 0x9591 # 0 +0xF9D9 0x9592 # 0 +0xF9DA 0x9650 # 0 +0xF9DB 0x97D3 # 0 +0xF9DC 0x5272 # 0 +0xF9DD 0x8F44 # 0 +0xF9DE 0x51FD # 0 +0xF9DF 0x542B # 0 +0xF9E0 0x54B8 # 0 +0xF9E1 0x5563 # 0 +0xF9E2 0x558A # 0 +0xF9E3 0x6ABB # 0 +0xF9E4 0x6DB5 # 0 +0xF9E5 0x7DD8 # 0 +0xF9E6 0x8266 # 0 +0xF9E7 0x929C # 0 +0xF9E8 0x9677 # 0 +0xF9E9 0x9E79 # 0 +0xF9EA 0x5408 # 0 +0xF9EB 0x54C8 # 0 +0xF9EC 0x76D2 # 0 +0xF9ED 0x86E4 # 0 +0xF9EE 0x95A4 # 0 +0xF9EF 0x95D4 # 0 +0xF9F0 0x965C # 0 +0xF9F1 0x4EA2 # 0 +0xF9F2 0x4F09 # 0 +0xF9F3 0x59EE # 0 +0xF9F4 0x5AE6 # 0 +0xF9F5 0x5DF7 # 0 +0xF9F6 0x6052 # 0 +0xF9F7 0x6297 # 0 +0xF9F8 0x676D # 0 +0xF9F9 0x6841 # 0 +0xF9FA 0x6C86 # 0 +0xF9FB 0x6E2F # 0 +0xF9FC 0x7F38 # 0 +0xF9FD 0x809B # 0 +0xF9FE 0x822A # 0 +0xFAA1 0xFA08 # 0 +0xFAA2 0xFA09 # 0 +0xFAA3 0x9805 # 0 +0xFAA4 0x4EA5 # 0 +0xFAA5 0x5055 # 0 +0xFAA6 0x54B3 # 0 +0xFAA7 0x5793 # 0 +0xFAA8 0x595A # 0 +0xFAA9 0x5B69 # 0 +0xFAAA 0x5BB3 # 0 +0xFAAB 0x61C8 # 0 +0xFAAC 0x6977 # 0 +0xFAAD 0x6D77 # 0 +0xFAAE 0x7023 # 0 +0xFAAF 0x87F9 # 0 +0xFAB0 0x89E3 # 0 +0xFAB1 0x8A72 # 0 +0xFAB2 0x8AE7 # 0 +0xFAB3 0x9082 # 0 +0xFAB4 0x99ED # 0 +0xFAB5 0x9AB8 # 0 +0xFAB6 0x52BE # 0 +0xFAB7 0x6838 # 0 +0xFAB8 0x5016 # 0 +0xFAB9 0x5E78 # 0 +0xFABA 0x674F # 0 +0xFABB 0x8347 # 0 +0xFABC 0x884C # 0 +0xFABD 0x4EAB # 0 +0xFABE 0x5411 # 0 +0xFABF 0x56AE # 0 +0xFAC0 0x73E6 # 0 +0xFAC1 0x9115 # 0 +0xFAC2 0x97FF # 0 +0xFAC3 0x9909 # 0 +0xFAC4 0x9957 # 0 +0xFAC5 0x9999 # 0 +0xFAC6 0x5653 # 0 +0xFAC7 0x589F # 0 +0xFAC8 0x865B # 0 +0xFAC9 0x8A31 # 0 +0xFACA 0x61B2 # 0 +0xFACB 0x6AF6 # 0 +0xFACC 0x737B # 0 +0xFACD 0x8ED2 # 0 +0xFACE 0x6B47 # 0 +0xFACF 0x96AA # 0 +0xFAD0 0x9A57 # 0 +0xFAD1 0x5955 # 0 +0xFAD2 0x7200 # 0 +0xFAD3 0x8D6B # 0 +0xFAD4 0x9769 # 0 +0xFAD5 0x4FD4 # 0 +0xFAD6 0x5CF4 # 0 +0xFAD7 0x5F26 # 0 +0xFAD8 0x61F8 # 0 +0xFAD9 0x665B # 0 +0xFADA 0x6CEB # 0 +0xFADB 0x70AB # 0 +0xFADC 0x7384 # 0 +0xFADD 0x73B9 # 0 +0xFADE 0x73FE # 0 +0xFADF 0x7729 # 0 +0xFAE0 0x774D # 0 +0xFAE1 0x7D43 # 0 +0xFAE2 0x7D62 # 0 +0xFAE3 0x7E23 # 0 +0xFAE4 0x8237 # 0 +0xFAE5 0x8852 # 0 +0xFAE6 0xFA0A # 0 +0xFAE7 0x8CE2 # 0 +0xFAE8 0x9249 # 0 +0xFAE9 0x986F # 0 +0xFAEA 0x5B51 # 0 +0xFAEB 0x7A74 # 0 +0xFAEC 0x8840 # 0 +0xFAED 0x9801 # 0 +0xFAEE 0x5ACC # 0 +0xFAEF 0x4FE0 # 0 +0xFAF0 0x5354 # 0 +0xFAF1 0x593E # 0 +0xFAF2 0x5CFD # 0 +0xFAF3 0x633E # 0 +0xFAF4 0x6D79 # 0 +0xFAF5 0x72F9 # 0 +0xFAF6 0x8105 # 0 +0xFAF7 0x8107 # 0 +0xFAF8 0x83A2 # 0 +0xFAF9 0x92CF # 0 +0xFAFA 0x9830 # 0 +0xFAFB 0x4EA8 # 0 +0xFAFC 0x5144 # 0 +0xFAFD 0x5211 # 0 +0xFAFE 0x578B # 0 +0xFBA1 0x5F62 # 0 +0xFBA2 0x6CC2 # 0 +0xFBA3 0x6ECE # 0 +0xFBA4 0x7005 # 0 +0xFBA5 0x7050 # 0 +0xFBA6 0x70AF # 0 +0xFBA7 0x7192 # 0 +0xFBA8 0x73E9 # 0 +0xFBA9 0x7469 # 0 +0xFBAA 0x834A # 0 +0xFBAB 0x87A2 # 0 +0xFBAC 0x8861 # 0 +0xFBAD 0x9008 # 0 +0xFBAE 0x90A2 # 0 +0xFBAF 0x93A3 # 0 +0xFBB0 0x99A8 # 0 +0xFBB1 0x516E # 0 +0xFBB2 0x5F57 # 0 +0xFBB3 0x60E0 # 0 +0xFBB4 0x6167 # 0 +0xFBB5 0x66B3 # 0 +0xFBB6 0x8559 # 0 +0xFBB7 0x8E4A # 0 +0xFBB8 0x91AF # 0 +0xFBB9 0x978B # 0 +0xFBBA 0x4E4E # 0 +0xFBBB 0x4E92 # 0 +0xFBBC 0x547C # 0 +0xFBBD 0x58D5 # 0 +0xFBBE 0x58FA # 0 +0xFBBF 0x597D # 0 +0xFBC0 0x5CB5 # 0 +0xFBC1 0x5F27 # 0 +0xFBC2 0x6236 # 0 +0xFBC3 0x6248 # 0 +0xFBC4 0x660A # 0 +0xFBC5 0x6667 # 0 +0xFBC6 0x6BEB # 0 +0xFBC7 0x6D69 # 0 +0xFBC8 0x6DCF # 0 +0xFBC9 0x6E56 # 0 +0xFBCA 0x6EF8 # 0 +0xFBCB 0x6F94 # 0 +0xFBCC 0x6FE0 # 0 +0xFBCD 0x6FE9 # 0 +0xFBCE 0x705D # 0 +0xFBCF 0x72D0 # 0 +0xFBD0 0x7425 # 0 +0xFBD1 0x745A # 0 +0xFBD2 0x74E0 # 0 +0xFBD3 0x7693 # 0 +0xFBD4 0x795C # 0 +0xFBD5 0x7CCA # 0 +0xFBD6 0x7E1E # 0 +0xFBD7 0x80E1 # 0 +0xFBD8 0x82A6 # 0 +0xFBD9 0x846B # 0 +0xFBDA 0x84BF # 0 +0xFBDB 0x864E # 0 +0xFBDC 0x865F # 0 +0xFBDD 0x8774 # 0 +0xFBDE 0x8B77 # 0 +0xFBDF 0x8C6A # 0 +0xFBE0 0x93AC # 0 +0xFBE1 0x9800 # 0 +0xFBE2 0x9865 # 0 +0xFBE3 0x60D1 # 0 +0xFBE4 0x6216 # 0 +0xFBE5 0x9177 # 0 +0xFBE6 0x5A5A # 0 +0xFBE7 0x660F # 0 +0xFBE8 0x6DF7 # 0 +0xFBE9 0x6E3E # 0 +0xFBEA 0x743F # 0 +0xFBEB 0x9B42 # 0 +0xFBEC 0x5FFD # 0 +0xFBED 0x60DA # 0 +0xFBEE 0x7B0F # 0 +0xFBEF 0x54C4 # 0 +0xFBF0 0x5F18 # 0 +0xFBF1 0x6C5E # 0 +0xFBF2 0x6CD3 # 0 +0xFBF3 0x6D2A # 0 +0xFBF4 0x70D8 # 0 +0xFBF5 0x7D05 # 0 +0xFBF6 0x8679 # 0 +0xFBF7 0x8A0C # 0 +0xFBF8 0x9D3B # 0 +0xFBF9 0x5316 # 0 +0xFBFA 0x548C # 0 +0xFBFB 0x5B05 # 0 +0xFBFC 0x6A3A # 0 +0xFBFD 0x706B # 0 +0xFBFE 0x7575 # 0 +0xFCA1 0x798D # 0 +0xFCA2 0x79BE # 0 +0xFCA3 0x82B1 # 0 +0xFCA4 0x83EF # 0 +0xFCA5 0x8A71 # 0 +0xFCA6 0x8B41 # 0 +0xFCA7 0x8CA8 # 0 +0xFCA8 0x9774 # 0 +0xFCA9 0xFA0B # 0 +0xFCAA 0x64F4 # 0 +0xFCAB 0x652B # 0 +0xFCAC 0x78BA # 0 +0xFCAD 0x78BB # 0 +0xFCAE 0x7A6B # 0 +0xFCAF 0x4E38 # 0 +0xFCB0 0x559A # 0 +0xFCB1 0x5950 # 0 +0xFCB2 0x5BA6 # 0 +0xFCB3 0x5E7B # 0 +0xFCB4 0x60A3 # 0 +0xFCB5 0x63DB # 0 +0xFCB6 0x6B61 # 0 +0xFCB7 0x6665 # 0 +0xFCB8 0x6853 # 0 +0xFCB9 0x6E19 # 0 +0xFCBA 0x7165 # 0 +0xFCBB 0x74B0 # 0 +0xFCBC 0x7D08 # 0 +0xFCBD 0x9084 # 0 +0xFCBE 0x9A69 # 0 +0xFCBF 0x9C25 # 0 +0xFCC0 0x6D3B # 0 +0xFCC1 0x6ED1 # 0 +0xFCC2 0x733E # 0 +0xFCC3 0x8C41 # 0 +0xFCC4 0x95CA # 0 +0xFCC5 0x51F0 # 0 +0xFCC6 0x5E4C # 0 +0xFCC7 0x5FA8 # 0 +0xFCC8 0x604D # 0 +0xFCC9 0x60F6 # 0 +0xFCCA 0x6130 # 0 +0xFCCB 0x614C # 0 +0xFCCC 0x6643 # 0 +0xFCCD 0x6644 # 0 +0xFCCE 0x69A5 # 0 +0xFCCF 0x6CC1 # 0 +0xFCD0 0x6E5F # 0 +0xFCD1 0x6EC9 # 0 +0xFCD2 0x6F62 # 0 +0xFCD3 0x714C # 0 +0xFCD4 0x749C # 0 +0xFCD5 0x7687 # 0 +0xFCD6 0x7BC1 # 0 +0xFCD7 0x7C27 # 0 +0xFCD8 0x8352 # 0 +0xFCD9 0x8757 # 0 +0xFCDA 0x9051 # 0 +0xFCDB 0x968D # 0 +0xFCDC 0x9EC3 # 0 +0xFCDD 0x532F # 0 +0xFCDE 0x56DE # 0 +0xFCDF 0x5EFB # 0 +0xFCE0 0x5F8A # 0 +0xFCE1 0x6062 # 0 +0xFCE2 0x6094 # 0 +0xFCE3 0x61F7 # 0 +0xFCE4 0x6666 # 0 +0xFCE5 0x6703 # 0 +0xFCE6 0x6A9C # 0 +0xFCE7 0x6DEE # 0 +0xFCE8 0x6FAE # 0 +0xFCE9 0x7070 # 0 +0xFCEA 0x736A # 0 +0xFCEB 0x7E6A # 0 +0xFCEC 0x81BE # 0 +0xFCED 0x8334 # 0 +0xFCEE 0x86D4 # 0 +0xFCEF 0x8AA8 # 0 +0xFCF0 0x8CC4 # 0 +0xFCF1 0x5283 # 0 +0xFCF2 0x7372 # 0 +0xFCF3 0x5B96 # 0 +0xFCF4 0x6A6B # 0 +0xFCF5 0x9404 # 0 +0xFCF6 0x54EE # 0 +0xFCF7 0x5686 # 0 +0xFCF8 0x5B5D # 0 +0xFCF9 0x6548 # 0 +0xFCFA 0x6585 # 0 +0xFCFB 0x66C9 # 0 +0xFCFC 0x689F # 0 +0xFCFD 0x6D8D # 0 +0xFCFE 0x6DC6 # 0 +0xFDA1 0x723B # 0 +0xFDA2 0x80B4 # 0 +0xFDA3 0x9175 # 0 +0xFDA4 0x9A4D # 0 +0xFDA5 0x4FAF # 0 +0xFDA6 0x5019 # 0 +0xFDA7 0x539A # 0 +0xFDA8 0x540E # 0 +0xFDA9 0x543C # 0 +0xFDAA 0x5589 # 0 +0xFDAB 0x55C5 # 0 +0xFDAC 0x5E3F # 0 +0xFDAD 0x5F8C # 0 +0xFDAE 0x673D # 0 +0xFDAF 0x7166 # 0 +0xFDB0 0x73DD # 0 +0xFDB1 0x9005 # 0 +0xFDB2 0x52DB # 0 +0xFDB3 0x52F3 # 0 +0xFDB4 0x5864 # 0 +0xFDB5 0x58CE # 0 +0xFDB6 0x7104 # 0 +0xFDB7 0x718F # 0 +0xFDB8 0x71FB # 0 +0xFDB9 0x85B0 # 0 +0xFDBA 0x8A13 # 0 +0xFDBB 0x6688 # 0 +0xFDBC 0x85A8 # 0 +0xFDBD 0x55A7 # 0 +0xFDBE 0x6684 # 0 +0xFDBF 0x714A # 0 +0xFDC0 0x8431 # 0 +0xFDC1 0x5349 # 0 +0xFDC2 0x5599 # 0 +0xFDC3 0x6BC1 # 0 +0xFDC4 0x5F59 # 0 +0xFDC5 0x5FBD # 0 +0xFDC6 0x63EE # 0 +0xFDC7 0x6689 # 0 +0xFDC8 0x7147 # 0 +0xFDC9 0x8AF1 # 0 +0xFDCA 0x8F1D # 0 +0xFDCB 0x9EBE # 0 +0xFDCC 0x4F11 # 0 +0xFDCD 0x643A # 0 +0xFDCE 0x70CB # 0 +0xFDCF 0x7566 # 0 +0xFDD0 0x8667 # 0 +0xFDD1 0x6064 # 0 +0xFDD2 0x8B4E # 0 +0xFDD3 0x9DF8 # 0 +0xFDD4 0x5147 # 0 +0xFDD5 0x51F6 # 0 +0xFDD6 0x5308 # 0 +0xFDD7 0x6D36 # 0 +0xFDD8 0x80F8 # 0 +0xFDD9 0x9ED1 # 0 +0xFDDA 0x6615 # 0 +0xFDDB 0x6B23 # 0 +0xFDDC 0x7098 # 0 +0xFDDD 0x75D5 # 0 +0xFDDE 0x5403 # 0 +0xFDDF 0x5C79 # 0 +0xFDE0 0x7D07 # 0 +0xFDE1 0x8A16 # 0 +0xFDE2 0x6B20 # 0 +0xFDE3 0x6B3D # 0 +0xFDE4 0x6B46 # 0 +0xFDE5 0x5438 # 0 +0xFDE6 0x6070 # 0 +0xFDE7 0x6D3D # 0 +0xFDE8 0x7FD5 # 0 +0xFDE9 0x8208 # 0 +0xFDEA 0x50D6 # 0 +0xFDEB 0x51DE # 0 +0xFDEC 0x559C # 0 +0xFDED 0x566B # 0 +0xFDEE 0x56CD # 0 +0xFDEF 0x59EC # 0 +0xFDF0 0x5B09 # 0 +0xFDF1 0x5E0C # 0 +0xFDF2 0x6199 # 0 +0xFDF3 0x6198 # 0 +0xFDF4 0x6231 # 0 +0xFDF5 0x665E # 0 +0xFDF6 0x66E6 # 0 +0xFDF7 0x7199 # 0 +0xFDF8 0x71B9 # 0 +0xFDF9 0x71BA # 0 +0xFDFA 0x72A7 # 0 +0xFDFB 0x79A7 # 0 +0xFDFC 0x7A00 # 0 +0xFDFD 0x7FB2 # 0 +0xFDFE 0x8A70 # 0 +0xFEA1 0xE05E # 0 +0xFEA2 0xE05F # 0 +0xFEA3 0xE060 # 0 +0xFEA4 0xE061 # 0 +0xFEA5 0xE062 # 0 +0xFEA6 0xE063 # 0 +0xFEA7 0xE064 # 0 +0xFEA8 0xE065 # 0 +0xFEA9 0xE066 # 0 +0xFEAA 0xE067 # 0 +0xFEAB 0xE068 # 0 +0xFEAC 0xE069 # 0 +0xFEAD 0xE06A # 0 +0xFEAE 0xE06B # 0 +0xFEAF 0xE06C # 0 +0xFEB0 0xE06D # 0 +0xFEB1 0xE06E # 0 +0xFEB2 0xE06F # 0 +0xFEB3 0xE070 # 0 +0xFEB4 0xE071 # 0 +0xFEB5 0xE072 # 0 +0xFEB6 0xE073 # 0 +0xFEB7 0xE074 # 0 +0xFEB8 0xE075 # 0 +0xFEB9 0xE076 # 0 +0xFEBA 0xE077 # 0 +0xFEBB 0xE078 # 0 +0xFEBC 0xE079 # 0 +0xFEBD 0xE07A # 0 +0xFEBE 0xE07B # 0 +0xFEBF 0xE07C # 0 +0xFEC0 0xE07D # 0 +0xFEC1 0xE07E # 0 +0xFEC2 0xE07F # 0 +0xFEC3 0xE080 # 0 +0xFEC4 0xE081 # 0 +0xFEC5 0xE082 # 0 +0xFEC6 0xE083 # 0 +0xFEC7 0xE084 # 0 +0xFEC8 0xE085 # 0 +0xFEC9 0xE086 # 0 +0xFECA 0xE087 # 0 +0xFECB 0xE088 # 0 +0xFECC 0xE089 # 0 +0xFECD 0xE08A # 0 +0xFECE 0xE08B # 0 +0xFECF 0xE08C # 0 +0xFED0 0xE08D # 0 +0xFED1 0xE08E # 0 +0xFED2 0xE08F # 0 +0xFED3 0xE090 # 0 +0xFED4 0xE091 # 0 +0xFED5 0xE092 # 0 +0xFED6 0xE093 # 0 +0xFED7 0xE094 # 0 +0xFED8 0xE095 # 0 +0xFED9 0xE096 # 0 +0xFEDA 0xE097 # 0 +0xFEDB 0xE098 # 0 +0xFEDC 0xE099 # 0 +0xFEDD 0xE09A # 0 +0xFEDE 0xE09B # 0 +0xFEDF 0xE09C # 0 +0xFEE0 0xE09D # 0 +0xFEE1 0xE09E # 0 +0xFEE2 0xE09F # 0 +0xFEE3 0xE0A0 # 0 +0xFEE4 0xE0A1 # 0 +0xFEE5 0xE0A2 # 0 +0xFEE6 0xE0A3 # 0 +0xFEE7 0xE0A4 # 0 +0xFEE8 0xE0A5 # 0 +0xFEE9 0xE0A6 # 0 +0xFEEA 0xE0A7 # 0 +0xFEEB 0xE0A8 # 0 +0xFEEC 0xE0A9 # 0 +0xFEED 0xE0AA # 0 +0xFEEE 0xE0AB # 0 +0xFEEF 0xE0AC # 0 +0xFEF0 0xE0AD # 0 +0xFEF1 0xE0AE # 0 +0xFEF2 0xE0AF # 0 +0xFEF3 0xE0B0 # 0 +0xFEF4 0xE0B1 # 0 +0xFEF5 0xE0B2 # 0 +0xFEF6 0xE0B3 # 0 +0xFEF7 0xE0B4 # 0 +0xFEF8 0xE0B5 # 0 +0xFEF9 0xE0B6 # 0 +0xFEFA 0xE0B7 # 0 +0xFEFB 0xE0B8 # 0 +0xFEFC 0xE0B9 # 0 +0xFEFD 0xE0BA # 0 +0xFEFE 0xE0BB # 0 diff --git a/data/windows-950.txt b/data/windows-950.txt new file mode 100644 index 000000000..2ac92bf35 --- /dev/null +++ b/data/windows-950.txt @@ -0,0 +1,19841 @@ +# cp950.txt - Legacy to Unicode charmap +0x0000 0x0000 # 0 +0x0001 0x0001 # 0 +0x0002 0x0002 # 0 +0x0003 0x0003 # 0 +0x0004 0x0004 # 0 +0x0005 0x0005 # 0 +0x0006 0x0006 # 0 +0x0007 0x0007 # 0 +0x0008 0x0008 # 0 +0x0009 0x0009 # 0 +0x000A 0x000A # 0 +0x000B 0x000B # 0 +0x000C 0x000C # 0 +0x000D 0x000D # 0 +0x000E 0x000E # 0 +0x000F 0x000F # 0 +0x0010 0x0010 # 0 +0x0011 0x0011 # 0 +0x0012 0x0012 # 0 +0x0013 0x0013 # 0 +0x0014 0x0014 # 0 +0x0015 0x0015 # 0 +0x0016 0x0016 # 0 +0x0017 0x0017 # 0 +0x0018 0x0018 # 0 +0x0019 0x0019 # 0 +0x001A 0x001A # 0 +0x001B 0x001B # 0 +0x001C 0x001C # 0 +0x001D 0x001D # 0 +0x001E 0x001E # 0 +0x001F 0x001F # 0 +0x0020 0x0020 # 0 +0x0021 0x0021 # 0 +0x0022 0x0022 # 0 +0x0023 0x0023 # 0 +0x0024 0x0024 # 0 +0x0025 0x0025 # 0 +0x0026 0x0026 # 0 +0x0027 0x0027 # 0 +0x0028 0x0028 # 0 +0x0029 0x0029 # 0 +0x002A 0x002A # 0 +0x002B 0x002B # 0 +0x002C 0x002C # 0 +0x002D 0x002D # 0 +0x002E 0x002E # 0 +0x002F 0x002F # 0 +0x0030 0x0030 # 0 +0x0031 0x0031 # 0 +0x0032 0x0032 # 0 +0x0033 0x0033 # 0 +0x0034 0x0034 # 0 +0x0035 0x0035 # 0 +0x0036 0x0036 # 0 +0x0037 0x0037 # 0 +0x0038 0x0038 # 0 +0x0039 0x0039 # 0 +0x003A 0x003A # 0 +0x003B 0x003B # 0 +0x003C 0x003C # 0 +0x003D 0x003D # 0 +0x003E 0x003E # 0 +0x003F 0x003F # 0 +0x0040 0x0040 # 0 +0x0041 0x0041 # 0 +0x0042 0x0042 # 0 +0x0043 0x0043 # 0 +0x0044 0x0044 # 0 +0x0045 0x0045 # 0 +0x0046 0x0046 # 0 +0x0047 0x0047 # 0 +0x0048 0x0048 # 0 +0x0049 0x0049 # 0 +0x004A 0x004A # 0 +0x004B 0x004B # 0 +0x004C 0x004C # 0 +0x004D 0x004D # 0 +0x004E 0x004E # 0 +0x004F 0x004F # 0 +0x0050 0x0050 # 0 +0x0051 0x0051 # 0 +0x0052 0x0052 # 0 +0x0053 0x0053 # 0 +0x0054 0x0054 # 0 +0x0055 0x0055 # 0 +0x0056 0x0056 # 0 +0x0057 0x0057 # 0 +0x0058 0x0058 # 0 +0x0059 0x0059 # 0 +0x005A 0x005A # 0 +0x005B 0x005B # 0 +0x005C 0x005C # 0 +0x005D 0x005D # 0 +0x005E 0x005E # 0 +0x005F 0x005F # 0 +0x0060 0x0060 # 0 +0x0061 0x0061 # 0 +0x0062 0x0062 # 0 +0x0063 0x0063 # 0 +0x0064 0x0064 # 0 +0x0065 0x0065 # 0 +0x0066 0x0066 # 0 +0x0067 0x0067 # 0 +0x0068 0x0068 # 0 +0x0069 0x0069 # 0 +0x006A 0x006A # 0 +0x006B 0x006B # 0 +0x006C 0x006C # 0 +0x006D 0x006D # 0 +0x006E 0x006E # 0 +0x006F 0x006F # 0 +0x0070 0x0070 # 0 +0x0071 0x0071 # 0 +0x0072 0x0072 # 0 +0x0073 0x0073 # 0 +0x0074 0x0074 # 0 +0x0075 0x0075 # 0 +0x0076 0x0076 # 0 +0x0077 0x0077 # 0 +0x0078 0x0078 # 0 +0x0079 0x0079 # 0 +0x007A 0x007A # 0 +0x007B 0x007B # 0 +0x007C 0x007C # 0 +0x007D 0x007D # 0 +0x007E 0x007E # 0 +0x007F 0x007F # 0 +0x0080 0x0080 # 0 +0x00FF 0xF8F8 # 0 +0x8140 0xEEB8 # 0 +0x8141 0xEEB9 # 0 +0x8142 0xEEBA # 0 +0x8143 0xEEBB # 0 +0x8144 0xEEBC # 0 +0x8145 0xEEBD # 0 +0x8146 0xEEBE # 0 +0x8147 0xEEBF # 0 +0x8148 0xEEC0 # 0 +0x8149 0xEEC1 # 0 +0x814A 0xEEC2 # 0 +0x814B 0xEEC3 # 0 +0x814C 0xEEC4 # 0 +0x814D 0xEEC5 # 0 +0x814E 0xEEC6 # 0 +0x814F 0xEEC7 # 0 +0x8150 0xEEC8 # 0 +0x8151 0xEEC9 # 0 +0x8152 0xEECA # 0 +0x8153 0xEECB # 0 +0x8154 0xEECC # 0 +0x8155 0xEECD # 0 +0x8156 0xEECE # 0 +0x8157 0xEECF # 0 +0x8158 0xEED0 # 0 +0x8159 0xEED1 # 0 +0x815A 0xEED2 # 0 +0x815B 0xEED3 # 0 +0x815C 0xEED4 # 0 +0x815D 0xEED5 # 0 +0x815E 0xEED6 # 0 +0x815F 0xEED7 # 0 +0x8160 0xEED8 # 0 +0x8161 0xEED9 # 0 +0x8162 0xEEDA # 0 +0x8163 0xEEDB # 0 +0x8164 0xEEDC # 0 +0x8165 0xEEDD # 0 +0x8166 0xEEDE # 0 +0x8167 0xEEDF # 0 +0x8168 0xEEE0 # 0 +0x8169 0xEEE1 # 0 +0x816A 0xEEE2 # 0 +0x816B 0xEEE3 # 0 +0x816C 0xEEE4 # 0 +0x816D 0xEEE5 # 0 +0x816E 0xEEE6 # 0 +0x816F 0xEEE7 # 0 +0x8170 0xEEE8 # 0 +0x8171 0xEEE9 # 0 +0x8172 0xEEEA # 0 +0x8173 0xEEEB # 0 +0x8174 0xEEEC # 0 +0x8175 0xEEED # 0 +0x8176 0xEEEE # 0 +0x8177 0xEEEF # 0 +0x8178 0xEEF0 # 0 +0x8179 0xEEF1 # 0 +0x817A 0xEEF2 # 0 +0x817B 0xEEF3 # 0 +0x817C 0xEEF4 # 0 +0x817D 0xEEF5 # 0 +0x817E 0xEEF6 # 0 +0x81A1 0xEEF7 # 0 +0x81A2 0xEEF8 # 0 +0x81A3 0xEEF9 # 0 +0x81A4 0xEEFA # 0 +0x81A5 0xEEFB # 0 +0x81A6 0xEEFC # 0 +0x81A7 0xEEFD # 0 +0x81A8 0xEEFE # 0 +0x81A9 0xEEFF # 0 +0x81AA 0xEF00 # 0 +0x81AB 0xEF01 # 0 +0x81AC 0xEF02 # 0 +0x81AD 0xEF03 # 0 +0x81AE 0xEF04 # 0 +0x81AF 0xEF05 # 0 +0x81B0 0xEF06 # 0 +0x81B1 0xEF07 # 0 +0x81B2 0xEF08 # 0 +0x81B3 0xEF09 # 0 +0x81B4 0xEF0A # 0 +0x81B5 0xEF0B # 0 +0x81B6 0xEF0C # 0 +0x81B7 0xEF0D # 0 +0x81B8 0xEF0E # 0 +0x81B9 0xEF0F # 0 +0x81BA 0xEF10 # 0 +0x81BB 0xEF11 # 0 +0x81BC 0xEF12 # 0 +0x81BD 0xEF13 # 0 +0x81BE 0xEF14 # 0 +0x81BF 0xEF15 # 0 +0x81C0 0xEF16 # 0 +0x81C1 0xEF17 # 0 +0x81C2 0xEF18 # 0 +0x81C3 0xEF19 # 0 +0x81C4 0xEF1A # 0 +0x81C5 0xEF1B # 0 +0x81C6 0xEF1C # 0 +0x81C7 0xEF1D # 0 +0x81C8 0xEF1E # 0 +0x81C9 0xEF1F # 0 +0x81CA 0xEF20 # 0 +0x81CB 0xEF21 # 0 +0x81CC 0xEF22 # 0 +0x81CD 0xEF23 # 0 +0x81CE 0xEF24 # 0 +0x81CF 0xEF25 # 0 +0x81D0 0xEF26 # 0 +0x81D1 0xEF27 # 0 +0x81D2 0xEF28 # 0 +0x81D3 0xEF29 # 0 +0x81D4 0xEF2A # 0 +0x81D5 0xEF2B # 0 +0x81D6 0xEF2C # 0 +0x81D7 0xEF2D # 0 +0x81D8 0xEF2E # 0 +0x81D9 0xEF2F # 0 +0x81DA 0xEF30 # 0 +0x81DB 0xEF31 # 0 +0x81DC 0xEF32 # 0 +0x81DD 0xEF33 # 0 +0x81DE 0xEF34 # 0 +0x81DF 0xEF35 # 0 +0x81E0 0xEF36 # 0 +0x81E1 0xEF37 # 0 +0x81E2 0xEF38 # 0 +0x81E3 0xEF39 # 0 +0x81E4 0xEF3A # 0 +0x81E5 0xEF3B # 0 +0x81E6 0xEF3C # 0 +0x81E7 0xEF3D # 0 +0x81E8 0xEF3E # 0 +0x81E9 0xEF3F # 0 +0x81EA 0xEF40 # 0 +0x81EB 0xEF41 # 0 +0x81EC 0xEF42 # 0 +0x81ED 0xEF43 # 0 +0x81EE 0xEF44 # 0 +0x81EF 0xEF45 # 0 +0x81F0 0xEF46 # 0 +0x81F1 0xEF47 # 0 +0x81F2 0xEF48 # 0 +0x81F3 0xEF49 # 0 +0x81F4 0xEF4A # 0 +0x81F5 0xEF4B # 0 +0x81F6 0xEF4C # 0 +0x81F7 0xEF4D # 0 +0x81F8 0xEF4E # 0 +0x81F9 0xEF4F # 0 +0x81FA 0xEF50 # 0 +0x81FB 0xEF51 # 0 +0x81FC 0xEF52 # 0 +0x81FD 0xEF53 # 0 +0x81FE 0xEF54 # 0 +0x8240 0xEF55 # 0 +0x8241 0xEF56 # 0 +0x8242 0xEF57 # 0 +0x8243 0xEF58 # 0 +0x8244 0xEF59 # 0 +0x8245 0xEF5A # 0 +0x8246 0xEF5B # 0 +0x8247 0xEF5C # 0 +0x8248 0xEF5D # 0 +0x8249 0xEF5E # 0 +0x824A 0xEF5F # 0 +0x824B 0xEF60 # 0 +0x824C 0xEF61 # 0 +0x824D 0xEF62 # 0 +0x824E 0xEF63 # 0 +0x824F 0xEF64 # 0 +0x8250 0xEF65 # 0 +0x8251 0xEF66 # 0 +0x8252 0xEF67 # 0 +0x8253 0xEF68 # 0 +0x8254 0xEF69 # 0 +0x8255 0xEF6A # 0 +0x8256 0xEF6B # 0 +0x8257 0xEF6C # 0 +0x8258 0xEF6D # 0 +0x8259 0xEF6E # 0 +0x825A 0xEF6F # 0 +0x825B 0xEF70 # 0 +0x825C 0xEF71 # 0 +0x825D 0xEF72 # 0 +0x825E 0xEF73 # 0 +0x825F 0xEF74 # 0 +0x8260 0xEF75 # 0 +0x8261 0xEF76 # 0 +0x8262 0xEF77 # 0 +0x8263 0xEF78 # 0 +0x8264 0xEF79 # 0 +0x8265 0xEF7A # 0 +0x8266 0xEF7B # 0 +0x8267 0xEF7C # 0 +0x8268 0xEF7D # 0 +0x8269 0xEF7E # 0 +0x826A 0xEF7F # 0 +0x826B 0xEF80 # 0 +0x826C 0xEF81 # 0 +0x826D 0xEF82 # 0 +0x826E 0xEF83 # 0 +0x826F 0xEF84 # 0 +0x8270 0xEF85 # 0 +0x8271 0xEF86 # 0 +0x8272 0xEF87 # 0 +0x8273 0xEF88 # 0 +0x8274 0xEF89 # 0 +0x8275 0xEF8A # 0 +0x8276 0xEF8B # 0 +0x8277 0xEF8C # 0 +0x8278 0xEF8D # 0 +0x8279 0xEF8E # 0 +0x827A 0xEF8F # 0 +0x827B 0xEF90 # 0 +0x827C 0xEF91 # 0 +0x827D 0xEF92 # 0 +0x827E 0xEF93 # 0 +0x82A1 0xEF94 # 0 +0x82A2 0xEF95 # 0 +0x82A3 0xEF96 # 0 +0x82A4 0xEF97 # 0 +0x82A5 0xEF98 # 0 +0x82A6 0xEF99 # 0 +0x82A7 0xEF9A # 0 +0x82A8 0xEF9B # 0 +0x82A9 0xEF9C # 0 +0x82AA 0xEF9D # 0 +0x82AB 0xEF9E # 0 +0x82AC 0xEF9F # 0 +0x82AD 0xEFA0 # 0 +0x82AE 0xEFA1 # 0 +0x82AF 0xEFA2 # 0 +0x82B0 0xEFA3 # 0 +0x82B1 0xEFA4 # 0 +0x82B2 0xEFA5 # 0 +0x82B3 0xEFA6 # 0 +0x82B4 0xEFA7 # 0 +0x82B5 0xEFA8 # 0 +0x82B6 0xEFA9 # 0 +0x82B7 0xEFAA # 0 +0x82B8 0xEFAB # 0 +0x82B9 0xEFAC # 0 +0x82BA 0xEFAD # 0 +0x82BB 0xEFAE # 0 +0x82BC 0xEFAF # 0 +0x82BD 0xEFB0 # 0 +0x82BE 0xEFB1 # 0 +0x82BF 0xEFB2 # 0 +0x82C0 0xEFB3 # 0 +0x82C1 0xEFB4 # 0 +0x82C2 0xEFB5 # 0 +0x82C3 0xEFB6 # 0 +0x82C4 0xEFB7 # 0 +0x82C5 0xEFB8 # 0 +0x82C6 0xEFB9 # 0 +0x82C7 0xEFBA # 0 +0x82C8 0xEFBB # 0 +0x82C9 0xEFBC # 0 +0x82CA 0xEFBD # 0 +0x82CB 0xEFBE # 0 +0x82CC 0xEFBF # 0 +0x82CD 0xEFC0 # 0 +0x82CE 0xEFC1 # 0 +0x82CF 0xEFC2 # 0 +0x82D0 0xEFC3 # 0 +0x82D1 0xEFC4 # 0 +0x82D2 0xEFC5 # 0 +0x82D3 0xEFC6 # 0 +0x82D4 0xEFC7 # 0 +0x82D5 0xEFC8 # 0 +0x82D6 0xEFC9 # 0 +0x82D7 0xEFCA # 0 +0x82D8 0xEFCB # 0 +0x82D9 0xEFCC # 0 +0x82DA 0xEFCD # 0 +0x82DB 0xEFCE # 0 +0x82DC 0xEFCF # 0 +0x82DD 0xEFD0 # 0 +0x82DE 0xEFD1 # 0 +0x82DF 0xEFD2 # 0 +0x82E0 0xEFD3 # 0 +0x82E1 0xEFD4 # 0 +0x82E2 0xEFD5 # 0 +0x82E3 0xEFD6 # 0 +0x82E4 0xEFD7 # 0 +0x82E5 0xEFD8 # 0 +0x82E6 0xEFD9 # 0 +0x82E7 0xEFDA # 0 +0x82E8 0xEFDB # 0 +0x82E9 0xEFDC # 0 +0x82EA 0xEFDD # 0 +0x82EB 0xEFDE # 0 +0x82EC 0xEFDF # 0 +0x82ED 0xEFE0 # 0 +0x82EE 0xEFE1 # 0 +0x82EF 0xEFE2 # 0 +0x82F0 0xEFE3 # 0 +0x82F1 0xEFE4 # 0 +0x82F2 0xEFE5 # 0 +0x82F3 0xEFE6 # 0 +0x82F4 0xEFE7 # 0 +0x82F5 0xEFE8 # 0 +0x82F6 0xEFE9 # 0 +0x82F7 0xEFEA # 0 +0x82F8 0xEFEB # 0 +0x82F9 0xEFEC # 0 +0x82FA 0xEFED # 0 +0x82FB 0xEFEE # 0 +0x82FC 0xEFEF # 0 +0x82FD 0xEFF0 # 0 +0x82FE 0xEFF1 # 0 +0x8340 0xEFF2 # 0 +0x8341 0xEFF3 # 0 +0x8342 0xEFF4 # 0 +0x8343 0xEFF5 # 0 +0x8344 0xEFF6 # 0 +0x8345 0xEFF7 # 0 +0x8346 0xEFF8 # 0 +0x8347 0xEFF9 # 0 +0x8348 0xEFFA # 0 +0x8349 0xEFFB # 0 +0x834A 0xEFFC # 0 +0x834B 0xEFFD # 0 +0x834C 0xEFFE # 0 +0x834D 0xEFFF # 0 +0x834E 0xF000 # 0 +0x834F 0xF001 # 0 +0x8350 0xF002 # 0 +0x8351 0xF003 # 0 +0x8352 0xF004 # 0 +0x8353 0xF005 # 0 +0x8354 0xF006 # 0 +0x8355 0xF007 # 0 +0x8356 0xF008 # 0 +0x8357 0xF009 # 0 +0x8358 0xF00A # 0 +0x8359 0xF00B # 0 +0x835A 0xF00C # 0 +0x835B 0xF00D # 0 +0x835C 0xF00E # 0 +0x835D 0xF00F # 0 +0x835E 0xF010 # 0 +0x835F 0xF011 # 0 +0x8360 0xF012 # 0 +0x8361 0xF013 # 0 +0x8362 0xF014 # 0 +0x8363 0xF015 # 0 +0x8364 0xF016 # 0 +0x8365 0xF017 # 0 +0x8366 0xF018 # 0 +0x8367 0xF019 # 0 +0x8368 0xF01A # 0 +0x8369 0xF01B # 0 +0x836A 0xF01C # 0 +0x836B 0xF01D # 0 +0x836C 0xF01E # 0 +0x836D 0xF01F # 0 +0x836E 0xF020 # 0 +0x836F 0xF021 # 0 +0x8370 0xF022 # 0 +0x8371 0xF023 # 0 +0x8372 0xF024 # 0 +0x8373 0xF025 # 0 +0x8374 0xF026 # 0 +0x8375 0xF027 # 0 +0x8376 0xF028 # 0 +0x8377 0xF029 # 0 +0x8378 0xF02A # 0 +0x8379 0xF02B # 0 +0x837A 0xF02C # 0 +0x837B 0xF02D # 0 +0x837C 0xF02E # 0 +0x837D 0xF02F # 0 +0x837E 0xF030 # 0 +0x83A1 0xF031 # 0 +0x83A2 0xF032 # 0 +0x83A3 0xF033 # 0 +0x83A4 0xF034 # 0 +0x83A5 0xF035 # 0 +0x83A6 0xF036 # 0 +0x83A7 0xF037 # 0 +0x83A8 0xF038 # 0 +0x83A9 0xF039 # 0 +0x83AA 0xF03A # 0 +0x83AB 0xF03B # 0 +0x83AC 0xF03C # 0 +0x83AD 0xF03D # 0 +0x83AE 0xF03E # 0 +0x83AF 0xF03F # 0 +0x83B0 0xF040 # 0 +0x83B1 0xF041 # 0 +0x83B2 0xF042 # 0 +0x83B3 0xF043 # 0 +0x83B4 0xF044 # 0 +0x83B5 0xF045 # 0 +0x83B6 0xF046 # 0 +0x83B7 0xF047 # 0 +0x83B8 0xF048 # 0 +0x83B9 0xF049 # 0 +0x83BA 0xF04A # 0 +0x83BB 0xF04B # 0 +0x83BC 0xF04C # 0 +0x83BD 0xF04D # 0 +0x83BE 0xF04E # 0 +0x83BF 0xF04F # 0 +0x83C0 0xF050 # 0 +0x83C1 0xF051 # 0 +0x83C2 0xF052 # 0 +0x83C3 0xF053 # 0 +0x83C4 0xF054 # 0 +0x83C5 0xF055 # 0 +0x83C6 0xF056 # 0 +0x83C7 0xF057 # 0 +0x83C8 0xF058 # 0 +0x83C9 0xF059 # 0 +0x83CA 0xF05A # 0 +0x83CB 0xF05B # 0 +0x83CC 0xF05C # 0 +0x83CD 0xF05D # 0 +0x83CE 0xF05E # 0 +0x83CF 0xF05F # 0 +0x83D0 0xF060 # 0 +0x83D1 0xF061 # 0 +0x83D2 0xF062 # 0 +0x83D3 0xF063 # 0 +0x83D4 0xF064 # 0 +0x83D5 0xF065 # 0 +0x83D6 0xF066 # 0 +0x83D7 0xF067 # 0 +0x83D8 0xF068 # 0 +0x83D9 0xF069 # 0 +0x83DA 0xF06A # 0 +0x83DB 0xF06B # 0 +0x83DC 0xF06C # 0 +0x83DD 0xF06D # 0 +0x83DE 0xF06E # 0 +0x83DF 0xF06F # 0 +0x83E0 0xF070 # 0 +0x83E1 0xF071 # 0 +0x83E2 0xF072 # 0 +0x83E3 0xF073 # 0 +0x83E4 0xF074 # 0 +0x83E5 0xF075 # 0 +0x83E6 0xF076 # 0 +0x83E7 0xF077 # 0 +0x83E8 0xF078 # 0 +0x83E9 0xF079 # 0 +0x83EA 0xF07A # 0 +0x83EB 0xF07B # 0 +0x83EC 0xF07C # 0 +0x83ED 0xF07D # 0 +0x83EE 0xF07E # 0 +0x83EF 0xF07F # 0 +0x83F0 0xF080 # 0 +0x83F1 0xF081 # 0 +0x83F2 0xF082 # 0 +0x83F3 0xF083 # 0 +0x83F4 0xF084 # 0 +0x83F5 0xF085 # 0 +0x83F6 0xF086 # 0 +0x83F7 0xF087 # 0 +0x83F8 0xF088 # 0 +0x83F9 0xF089 # 0 +0x83FA 0xF08A # 0 +0x83FB 0xF08B # 0 +0x83FC 0xF08C # 0 +0x83FD 0xF08D # 0 +0x83FE 0xF08E # 0 +0x8440 0xF08F # 0 +0x8441 0xF090 # 0 +0x8442 0xF091 # 0 +0x8443 0xF092 # 0 +0x8444 0xF093 # 0 +0x8445 0xF094 # 0 +0x8446 0xF095 # 0 +0x8447 0xF096 # 0 +0x8448 0xF097 # 0 +0x8449 0xF098 # 0 +0x844A 0xF099 # 0 +0x844B 0xF09A # 0 +0x844C 0xF09B # 0 +0x844D 0xF09C # 0 +0x844E 0xF09D # 0 +0x844F 0xF09E # 0 +0x8450 0xF09F # 0 +0x8451 0xF0A0 # 0 +0x8452 0xF0A1 # 0 +0x8453 0xF0A2 # 0 +0x8454 0xF0A3 # 0 +0x8455 0xF0A4 # 0 +0x8456 0xF0A5 # 0 +0x8457 0xF0A6 # 0 +0x8458 0xF0A7 # 0 +0x8459 0xF0A8 # 0 +0x845A 0xF0A9 # 0 +0x845B 0xF0AA # 0 +0x845C 0xF0AB # 0 +0x845D 0xF0AC # 0 +0x845E 0xF0AD # 0 +0x845F 0xF0AE # 0 +0x8460 0xF0AF # 0 +0x8461 0xF0B0 # 0 +0x8462 0xF0B1 # 0 +0x8463 0xF0B2 # 0 +0x8464 0xF0B3 # 0 +0x8465 0xF0B4 # 0 +0x8466 0xF0B5 # 0 +0x8467 0xF0B6 # 0 +0x8468 0xF0B7 # 0 +0x8469 0xF0B8 # 0 +0x846A 0xF0B9 # 0 +0x846B 0xF0BA # 0 +0x846C 0xF0BB # 0 +0x846D 0xF0BC # 0 +0x846E 0xF0BD # 0 +0x846F 0xF0BE # 0 +0x8470 0xF0BF # 0 +0x8471 0xF0C0 # 0 +0x8472 0xF0C1 # 0 +0x8473 0xF0C2 # 0 +0x8474 0xF0C3 # 0 +0x8475 0xF0C4 # 0 +0x8476 0xF0C5 # 0 +0x8477 0xF0C6 # 0 +0x8478 0xF0C7 # 0 +0x8479 0xF0C8 # 0 +0x847A 0xF0C9 # 0 +0x847B 0xF0CA # 0 +0x847C 0xF0CB # 0 +0x847D 0xF0CC # 0 +0x847E 0xF0CD # 0 +0x84A1 0xF0CE # 0 +0x84A2 0xF0CF # 0 +0x84A3 0xF0D0 # 0 +0x84A4 0xF0D1 # 0 +0x84A5 0xF0D2 # 0 +0x84A6 0xF0D3 # 0 +0x84A7 0xF0D4 # 0 +0x84A8 0xF0D5 # 0 +0x84A9 0xF0D6 # 0 +0x84AA 0xF0D7 # 0 +0x84AB 0xF0D8 # 0 +0x84AC 0xF0D9 # 0 +0x84AD 0xF0DA # 0 +0x84AE 0xF0DB # 0 +0x84AF 0xF0DC # 0 +0x84B0 0xF0DD # 0 +0x84B1 0xF0DE # 0 +0x84B2 0xF0DF # 0 +0x84B3 0xF0E0 # 0 +0x84B4 0xF0E1 # 0 +0x84B5 0xF0E2 # 0 +0x84B6 0xF0E3 # 0 +0x84B7 0xF0E4 # 0 +0x84B8 0xF0E5 # 0 +0x84B9 0xF0E6 # 0 +0x84BA 0xF0E7 # 0 +0x84BB 0xF0E8 # 0 +0x84BC 0xF0E9 # 0 +0x84BD 0xF0EA # 0 +0x84BE 0xF0EB # 0 +0x84BF 0xF0EC # 0 +0x84C0 0xF0ED # 0 +0x84C1 0xF0EE # 0 +0x84C2 0xF0EF # 0 +0x84C3 0xF0F0 # 0 +0x84C4 0xF0F1 # 0 +0x84C5 0xF0F2 # 0 +0x84C6 0xF0F3 # 0 +0x84C7 0xF0F4 # 0 +0x84C8 0xF0F5 # 0 +0x84C9 0xF0F6 # 0 +0x84CA 0xF0F7 # 0 +0x84CB 0xF0F8 # 0 +0x84CC 0xF0F9 # 0 +0x84CD 0xF0FA # 0 +0x84CE 0xF0FB # 0 +0x84CF 0xF0FC # 0 +0x84D0 0xF0FD # 0 +0x84D1 0xF0FE # 0 +0x84D2 0xF0FF # 0 +0x84D3 0xF100 # 0 +0x84D4 0xF101 # 0 +0x84D5 0xF102 # 0 +0x84D6 0xF103 # 0 +0x84D7 0xF104 # 0 +0x84D8 0xF105 # 0 +0x84D9 0xF106 # 0 +0x84DA 0xF107 # 0 +0x84DB 0xF108 # 0 +0x84DC 0xF109 # 0 +0x84DD 0xF10A # 0 +0x84DE 0xF10B # 0 +0x84DF 0xF10C # 0 +0x84E0 0xF10D # 0 +0x84E1 0xF10E # 0 +0x84E2 0xF10F # 0 +0x84E3 0xF110 # 0 +0x84E4 0xF111 # 0 +0x84E5 0xF112 # 0 +0x84E6 0xF113 # 0 +0x84E7 0xF114 # 0 +0x84E8 0xF115 # 0 +0x84E9 0xF116 # 0 +0x84EA 0xF117 # 0 +0x84EB 0xF118 # 0 +0x84EC 0xF119 # 0 +0x84ED 0xF11A # 0 +0x84EE 0xF11B # 0 +0x84EF 0xF11C # 0 +0x84F0 0xF11D # 0 +0x84F1 0xF11E # 0 +0x84F2 0xF11F # 0 +0x84F3 0xF120 # 0 +0x84F4 0xF121 # 0 +0x84F5 0xF122 # 0 +0x84F6 0xF123 # 0 +0x84F7 0xF124 # 0 +0x84F8 0xF125 # 0 +0x84F9 0xF126 # 0 +0x84FA 0xF127 # 0 +0x84FB 0xF128 # 0 +0x84FC 0xF129 # 0 +0x84FD 0xF12A # 0 +0x84FE 0xF12B # 0 +0x8540 0xF12C # 0 +0x8541 0xF12D # 0 +0x8542 0xF12E # 0 +0x8543 0xF12F # 0 +0x8544 0xF130 # 0 +0x8545 0xF131 # 0 +0x8546 0xF132 # 0 +0x8547 0xF133 # 0 +0x8548 0xF134 # 0 +0x8549 0xF135 # 0 +0x854A 0xF136 # 0 +0x854B 0xF137 # 0 +0x854C 0xF138 # 0 +0x854D 0xF139 # 0 +0x854E 0xF13A # 0 +0x854F 0xF13B # 0 +0x8550 0xF13C # 0 +0x8551 0xF13D # 0 +0x8552 0xF13E # 0 +0x8553 0xF13F # 0 +0x8554 0xF140 # 0 +0x8555 0xF141 # 0 +0x8556 0xF142 # 0 +0x8557 0xF143 # 0 +0x8558 0xF144 # 0 +0x8559 0xF145 # 0 +0x855A 0xF146 # 0 +0x855B 0xF147 # 0 +0x855C 0xF148 # 0 +0x855D 0xF149 # 0 +0x855E 0xF14A # 0 +0x855F 0xF14B # 0 +0x8560 0xF14C # 0 +0x8561 0xF14D # 0 +0x8562 0xF14E # 0 +0x8563 0xF14F # 0 +0x8564 0xF150 # 0 +0x8565 0xF151 # 0 +0x8566 0xF152 # 0 +0x8567 0xF153 # 0 +0x8568 0xF154 # 0 +0x8569 0xF155 # 0 +0x856A 0xF156 # 0 +0x856B 0xF157 # 0 +0x856C 0xF158 # 0 +0x856D 0xF159 # 0 +0x856E 0xF15A # 0 +0x856F 0xF15B # 0 +0x8570 0xF15C # 0 +0x8571 0xF15D # 0 +0x8572 0xF15E # 0 +0x8573 0xF15F # 0 +0x8574 0xF160 # 0 +0x8575 0xF161 # 0 +0x8576 0xF162 # 0 +0x8577 0xF163 # 0 +0x8578 0xF164 # 0 +0x8579 0xF165 # 0 +0x857A 0xF166 # 0 +0x857B 0xF167 # 0 +0x857C 0xF168 # 0 +0x857D 0xF169 # 0 +0x857E 0xF16A # 0 +0x85A1 0xF16B # 0 +0x85A2 0xF16C # 0 +0x85A3 0xF16D # 0 +0x85A4 0xF16E # 0 +0x85A5 0xF16F # 0 +0x85A6 0xF170 # 0 +0x85A7 0xF171 # 0 +0x85A8 0xF172 # 0 +0x85A9 0xF173 # 0 +0x85AA 0xF174 # 0 +0x85AB 0xF175 # 0 +0x85AC 0xF176 # 0 +0x85AD 0xF177 # 0 +0x85AE 0xF178 # 0 +0x85AF 0xF179 # 0 +0x85B0 0xF17A # 0 +0x85B1 0xF17B # 0 +0x85B2 0xF17C # 0 +0x85B3 0xF17D # 0 +0x85B4 0xF17E # 0 +0x85B5 0xF17F # 0 +0x85B6 0xF180 # 0 +0x85B7 0xF181 # 0 +0x85B8 0xF182 # 0 +0x85B9 0xF183 # 0 +0x85BA 0xF184 # 0 +0x85BB 0xF185 # 0 +0x85BC 0xF186 # 0 +0x85BD 0xF187 # 0 +0x85BE 0xF188 # 0 +0x85BF 0xF189 # 0 +0x85C0 0xF18A # 0 +0x85C1 0xF18B # 0 +0x85C2 0xF18C # 0 +0x85C3 0xF18D # 0 +0x85C4 0xF18E # 0 +0x85C5 0xF18F # 0 +0x85C6 0xF190 # 0 +0x85C7 0xF191 # 0 +0x85C8 0xF192 # 0 +0x85C9 0xF193 # 0 +0x85CA 0xF194 # 0 +0x85CB 0xF195 # 0 +0x85CC 0xF196 # 0 +0x85CD 0xF197 # 0 +0x85CE 0xF198 # 0 +0x85CF 0xF199 # 0 +0x85D0 0xF19A # 0 +0x85D1 0xF19B # 0 +0x85D2 0xF19C # 0 +0x85D3 0xF19D # 0 +0x85D4 0xF19E # 0 +0x85D5 0xF19F # 0 +0x85D6 0xF1A0 # 0 +0x85D7 0xF1A1 # 0 +0x85D8 0xF1A2 # 0 +0x85D9 0xF1A3 # 0 +0x85DA 0xF1A4 # 0 +0x85DB 0xF1A5 # 0 +0x85DC 0xF1A6 # 0 +0x85DD 0xF1A7 # 0 +0x85DE 0xF1A8 # 0 +0x85DF 0xF1A9 # 0 +0x85E0 0xF1AA # 0 +0x85E1 0xF1AB # 0 +0x85E2 0xF1AC # 0 +0x85E3 0xF1AD # 0 +0x85E4 0xF1AE # 0 +0x85E5 0xF1AF # 0 +0x85E6 0xF1B0 # 0 +0x85E7 0xF1B1 # 0 +0x85E8 0xF1B2 # 0 +0x85E9 0xF1B3 # 0 +0x85EA 0xF1B4 # 0 +0x85EB 0xF1B5 # 0 +0x85EC 0xF1B6 # 0 +0x85ED 0xF1B7 # 0 +0x85EE 0xF1B8 # 0 +0x85EF 0xF1B9 # 0 +0x85F0 0xF1BA # 0 +0x85F1 0xF1BB # 0 +0x85F2 0xF1BC # 0 +0x85F3 0xF1BD # 0 +0x85F4 0xF1BE # 0 +0x85F5 0xF1BF # 0 +0x85F6 0xF1C0 # 0 +0x85F7 0xF1C1 # 0 +0x85F8 0xF1C2 # 0 +0x85F9 0xF1C3 # 0 +0x85FA 0xF1C4 # 0 +0x85FB 0xF1C5 # 0 +0x85FC 0xF1C6 # 0 +0x85FD 0xF1C7 # 0 +0x85FE 0xF1C8 # 0 +0x8640 0xF1C9 # 0 +0x8641 0xF1CA # 0 +0x8642 0xF1CB # 0 +0x8643 0xF1CC # 0 +0x8644 0xF1CD # 0 +0x8645 0xF1CE # 0 +0x8646 0xF1CF # 0 +0x8647 0xF1D0 # 0 +0x8648 0xF1D1 # 0 +0x8649 0xF1D2 # 0 +0x864A 0xF1D3 # 0 +0x864B 0xF1D4 # 0 +0x864C 0xF1D5 # 0 +0x864D 0xF1D6 # 0 +0x864E 0xF1D7 # 0 +0x864F 0xF1D8 # 0 +0x8650 0xF1D9 # 0 +0x8651 0xF1DA # 0 +0x8652 0xF1DB # 0 +0x8653 0xF1DC # 0 +0x8654 0xF1DD # 0 +0x8655 0xF1DE # 0 +0x8656 0xF1DF # 0 +0x8657 0xF1E0 # 0 +0x8658 0xF1E1 # 0 +0x8659 0xF1E2 # 0 +0x865A 0xF1E3 # 0 +0x865B 0xF1E4 # 0 +0x865C 0xF1E5 # 0 +0x865D 0xF1E6 # 0 +0x865E 0xF1E7 # 0 +0x865F 0xF1E8 # 0 +0x8660 0xF1E9 # 0 +0x8661 0xF1EA # 0 +0x8662 0xF1EB # 0 +0x8663 0xF1EC # 0 +0x8664 0xF1ED # 0 +0x8665 0xF1EE # 0 +0x8666 0xF1EF # 0 +0x8667 0xF1F0 # 0 +0x8668 0xF1F1 # 0 +0x8669 0xF1F2 # 0 +0x866A 0xF1F3 # 0 +0x866B 0xF1F4 # 0 +0x866C 0xF1F5 # 0 +0x866D 0xF1F6 # 0 +0x866E 0xF1F7 # 0 +0x866F 0xF1F8 # 0 +0x8670 0xF1F9 # 0 +0x8671 0xF1FA # 0 +0x8672 0xF1FB # 0 +0x8673 0xF1FC # 0 +0x8674 0xF1FD # 0 +0x8675 0xF1FE # 0 +0x8676 0xF1FF # 0 +0x8677 0xF200 # 0 +0x8678 0xF201 # 0 +0x8679 0xF202 # 0 +0x867A 0xF203 # 0 +0x867B 0xF204 # 0 +0x867C 0xF205 # 0 +0x867D 0xF206 # 0 +0x867E 0xF207 # 0 +0x86A1 0xF208 # 0 +0x86A2 0xF209 # 0 +0x86A3 0xF20A # 0 +0x86A4 0xF20B # 0 +0x86A5 0xF20C # 0 +0x86A6 0xF20D # 0 +0x86A7 0xF20E # 0 +0x86A8 0xF20F # 0 +0x86A9 0xF210 # 0 +0x86AA 0xF211 # 0 +0x86AB 0xF212 # 0 +0x86AC 0xF213 # 0 +0x86AD 0xF214 # 0 +0x86AE 0xF215 # 0 +0x86AF 0xF216 # 0 +0x86B0 0xF217 # 0 +0x86B1 0xF218 # 0 +0x86B2 0xF219 # 0 +0x86B3 0xF21A # 0 +0x86B4 0xF21B # 0 +0x86B5 0xF21C # 0 +0x86B6 0xF21D # 0 +0x86B7 0xF21E # 0 +0x86B8 0xF21F # 0 +0x86B9 0xF220 # 0 +0x86BA 0xF221 # 0 +0x86BB 0xF222 # 0 +0x86BC 0xF223 # 0 +0x86BD 0xF224 # 0 +0x86BE 0xF225 # 0 +0x86BF 0xF226 # 0 +0x86C0 0xF227 # 0 +0x86C1 0xF228 # 0 +0x86C2 0xF229 # 0 +0x86C3 0xF22A # 0 +0x86C4 0xF22B # 0 +0x86C5 0xF22C # 0 +0x86C6 0xF22D # 0 +0x86C7 0xF22E # 0 +0x86C8 0xF22F # 0 +0x86C9 0xF230 # 0 +0x86CA 0xF231 # 0 +0x86CB 0xF232 # 0 +0x86CC 0xF233 # 0 +0x86CD 0xF234 # 0 +0x86CE 0xF235 # 0 +0x86CF 0xF236 # 0 +0x86D0 0xF237 # 0 +0x86D1 0xF238 # 0 +0x86D2 0xF239 # 0 +0x86D3 0xF23A # 0 +0x86D4 0xF23B # 0 +0x86D5 0xF23C # 0 +0x86D6 0xF23D # 0 +0x86D7 0xF23E # 0 +0x86D8 0xF23F # 0 +0x86D9 0xF240 # 0 +0x86DA 0xF241 # 0 +0x86DB 0xF242 # 0 +0x86DC 0xF243 # 0 +0x86DD 0xF244 # 0 +0x86DE 0xF245 # 0 +0x86DF 0xF246 # 0 +0x86E0 0xF247 # 0 +0x86E1 0xF248 # 0 +0x86E2 0xF249 # 0 +0x86E3 0xF24A # 0 +0x86E4 0xF24B # 0 +0x86E5 0xF24C # 0 +0x86E6 0xF24D # 0 +0x86E7 0xF24E # 0 +0x86E8 0xF24F # 0 +0x86E9 0xF250 # 0 +0x86EA 0xF251 # 0 +0x86EB 0xF252 # 0 +0x86EC 0xF253 # 0 +0x86ED 0xF254 # 0 +0x86EE 0xF255 # 0 +0x86EF 0xF256 # 0 +0x86F0 0xF257 # 0 +0x86F1 0xF258 # 0 +0x86F2 0xF259 # 0 +0x86F3 0xF25A # 0 +0x86F4 0xF25B # 0 +0x86F5 0xF25C # 0 +0x86F6 0xF25D # 0 +0x86F7 0xF25E # 0 +0x86F8 0xF25F # 0 +0x86F9 0xF260 # 0 +0x86FA 0xF261 # 0 +0x86FB 0xF262 # 0 +0x86FC 0xF263 # 0 +0x86FD 0xF264 # 0 +0x86FE 0xF265 # 0 +0x8740 0xF266 # 0 +0x8741 0xF267 # 0 +0x8742 0xF268 # 0 +0x8743 0xF269 # 0 +0x8744 0xF26A # 0 +0x8745 0xF26B # 0 +0x8746 0xF26C # 0 +0x8747 0xF26D # 0 +0x8748 0xF26E # 0 +0x8749 0xF26F # 0 +0x874A 0xF270 # 0 +0x874B 0xF271 # 0 +0x874C 0xF272 # 0 +0x874D 0xF273 # 0 +0x874E 0xF274 # 0 +0x874F 0xF275 # 0 +0x8750 0xF276 # 0 +0x8751 0xF277 # 0 +0x8752 0xF278 # 0 +0x8753 0xF279 # 0 +0x8754 0xF27A # 0 +0x8755 0xF27B # 0 +0x8756 0xF27C # 0 +0x8757 0xF27D # 0 +0x8758 0xF27E # 0 +0x8759 0xF27F # 0 +0x875A 0xF280 # 0 +0x875B 0xF281 # 0 +0x875C 0xF282 # 0 +0x875D 0xF283 # 0 +0x875E 0xF284 # 0 +0x875F 0xF285 # 0 +0x8760 0xF286 # 0 +0x8761 0xF287 # 0 +0x8762 0xF288 # 0 +0x8763 0xF289 # 0 +0x8764 0xF28A # 0 +0x8765 0xF28B # 0 +0x8766 0xF28C # 0 +0x8767 0xF28D # 0 +0x8768 0xF28E # 0 +0x8769 0xF28F # 0 +0x876A 0xF290 # 0 +0x876B 0xF291 # 0 +0x876C 0xF292 # 0 +0x876D 0xF293 # 0 +0x876E 0xF294 # 0 +0x876F 0xF295 # 0 +0x8770 0xF296 # 0 +0x8771 0xF297 # 0 +0x8772 0xF298 # 0 +0x8773 0xF299 # 0 +0x8774 0xF29A # 0 +0x8775 0xF29B # 0 +0x8776 0xF29C # 0 +0x8777 0xF29D # 0 +0x8778 0xF29E # 0 +0x8779 0xF29F # 0 +0x877A 0xF2A0 # 0 +0x877B 0xF2A1 # 0 +0x877C 0xF2A2 # 0 +0x877D 0xF2A3 # 0 +0x877E 0xF2A4 # 0 +0x87A1 0xF2A5 # 0 +0x87A2 0xF2A6 # 0 +0x87A3 0xF2A7 # 0 +0x87A4 0xF2A8 # 0 +0x87A5 0xF2A9 # 0 +0x87A6 0xF2AA # 0 +0x87A7 0xF2AB # 0 +0x87A8 0xF2AC # 0 +0x87A9 0xF2AD # 0 +0x87AA 0xF2AE # 0 +0x87AB 0xF2AF # 0 +0x87AC 0xF2B0 # 0 +0x87AD 0xF2B1 # 0 +0x87AE 0xF2B2 # 0 +0x87AF 0xF2B3 # 0 +0x87B0 0xF2B4 # 0 +0x87B1 0xF2B5 # 0 +0x87B2 0xF2B6 # 0 +0x87B3 0xF2B7 # 0 +0x87B4 0xF2B8 # 0 +0x87B5 0xF2B9 # 0 +0x87B6 0xF2BA # 0 +0x87B7 0xF2BB # 0 +0x87B8 0xF2BC # 0 +0x87B9 0xF2BD # 0 +0x87BA 0xF2BE # 0 +0x87BB 0xF2BF # 0 +0x87BC 0xF2C0 # 0 +0x87BD 0xF2C1 # 0 +0x87BE 0xF2C2 # 0 +0x87BF 0xF2C3 # 0 +0x87C0 0xF2C4 # 0 +0x87C1 0xF2C5 # 0 +0x87C2 0xF2C6 # 0 +0x87C3 0xF2C7 # 0 +0x87C4 0xF2C8 # 0 +0x87C5 0xF2C9 # 0 +0x87C6 0xF2CA # 0 +0x87C7 0xF2CB # 0 +0x87C8 0xF2CC # 0 +0x87C9 0xF2CD # 0 +0x87CA 0xF2CE # 0 +0x87CB 0xF2CF # 0 +0x87CC 0xF2D0 # 0 +0x87CD 0xF2D1 # 0 +0x87CE 0xF2D2 # 0 +0x87CF 0xF2D3 # 0 +0x87D0 0xF2D4 # 0 +0x87D1 0xF2D5 # 0 +0x87D2 0xF2D6 # 0 +0x87D3 0xF2D7 # 0 +0x87D4 0xF2D8 # 0 +0x87D5 0xF2D9 # 0 +0x87D6 0xF2DA # 0 +0x87D7 0xF2DB # 0 +0x87D8 0xF2DC # 0 +0x87D9 0xF2DD # 0 +0x87DA 0xF2DE # 0 +0x87DB 0xF2DF # 0 +0x87DC 0xF2E0 # 0 +0x87DD 0xF2E1 # 0 +0x87DE 0xF2E2 # 0 +0x87DF 0xF2E3 # 0 +0x87E0 0xF2E4 # 0 +0x87E1 0xF2E5 # 0 +0x87E2 0xF2E6 # 0 +0x87E3 0xF2E7 # 0 +0x87E4 0xF2E8 # 0 +0x87E5 0xF2E9 # 0 +0x87E6 0xF2EA # 0 +0x87E7 0xF2EB # 0 +0x87E8 0xF2EC # 0 +0x87E9 0xF2ED # 0 +0x87EA 0xF2EE # 0 +0x87EB 0xF2EF # 0 +0x87EC 0xF2F0 # 0 +0x87ED 0xF2F1 # 0 +0x87EE 0xF2F2 # 0 +0x87EF 0xF2F3 # 0 +0x87F0 0xF2F4 # 0 +0x87F1 0xF2F5 # 0 +0x87F2 0xF2F6 # 0 +0x87F3 0xF2F7 # 0 +0x87F4 0xF2F8 # 0 +0x87F5 0xF2F9 # 0 +0x87F6 0xF2FA # 0 +0x87F7 0xF2FB # 0 +0x87F8 0xF2FC # 0 +0x87F9 0xF2FD # 0 +0x87FA 0xF2FE # 0 +0x87FB 0xF2FF # 0 +0x87FC 0xF300 # 0 +0x87FD 0xF301 # 0 +0x87FE 0xF302 # 0 +0x8840 0xF303 # 0 +0x8841 0xF304 # 0 +0x8842 0xF305 # 0 +0x8843 0xF306 # 0 +0x8844 0xF307 # 0 +0x8845 0xF308 # 0 +0x8846 0xF309 # 0 +0x8847 0xF30A # 0 +0x8848 0xF30B # 0 +0x8849 0xF30C # 0 +0x884A 0xF30D # 0 +0x884B 0xF30E # 0 +0x884C 0xF30F # 0 +0x884D 0xF310 # 0 +0x884E 0xF311 # 0 +0x884F 0xF312 # 0 +0x8850 0xF313 # 0 +0x8851 0xF314 # 0 +0x8852 0xF315 # 0 +0x8853 0xF316 # 0 +0x8854 0xF317 # 0 +0x8855 0xF318 # 0 +0x8856 0xF319 # 0 +0x8857 0xF31A # 0 +0x8858 0xF31B # 0 +0x8859 0xF31C # 0 +0x885A 0xF31D # 0 +0x885B 0xF31E # 0 +0x885C 0xF31F # 0 +0x885D 0xF320 # 0 +0x885E 0xF321 # 0 +0x885F 0xF322 # 0 +0x8860 0xF323 # 0 +0x8861 0xF324 # 0 +0x8862 0xF325 # 0 +0x8863 0xF326 # 0 +0x8864 0xF327 # 0 +0x8865 0xF328 # 0 +0x8866 0xF329 # 0 +0x8867 0xF32A # 0 +0x8868 0xF32B # 0 +0x8869 0xF32C # 0 +0x886A 0xF32D # 0 +0x886B 0xF32E # 0 +0x886C 0xF32F # 0 +0x886D 0xF330 # 0 +0x886E 0xF331 # 0 +0x886F 0xF332 # 0 +0x8870 0xF333 # 0 +0x8871 0xF334 # 0 +0x8872 0xF335 # 0 +0x8873 0xF336 # 0 +0x8874 0xF337 # 0 +0x8875 0xF338 # 0 +0x8876 0xF339 # 0 +0x8877 0xF33A # 0 +0x8878 0xF33B # 0 +0x8879 0xF33C # 0 +0x887A 0xF33D # 0 +0x887B 0xF33E # 0 +0x887C 0xF33F # 0 +0x887D 0xF340 # 0 +0x887E 0xF341 # 0 +0x88A1 0xF342 # 0 +0x88A2 0xF343 # 0 +0x88A3 0xF344 # 0 +0x88A4 0xF345 # 0 +0x88A5 0xF346 # 0 +0x88A6 0xF347 # 0 +0x88A7 0xF348 # 0 +0x88A8 0xF349 # 0 +0x88A9 0xF34A # 0 +0x88AA 0xF34B # 0 +0x88AB 0xF34C # 0 +0x88AC 0xF34D # 0 +0x88AD 0xF34E # 0 +0x88AE 0xF34F # 0 +0x88AF 0xF350 # 0 +0x88B0 0xF351 # 0 +0x88B1 0xF352 # 0 +0x88B2 0xF353 # 0 +0x88B3 0xF354 # 0 +0x88B4 0xF355 # 0 +0x88B5 0xF356 # 0 +0x88B6 0xF357 # 0 +0x88B7 0xF358 # 0 +0x88B8 0xF359 # 0 +0x88B9 0xF35A # 0 +0x88BA 0xF35B # 0 +0x88BB 0xF35C # 0 +0x88BC 0xF35D # 0 +0x88BD 0xF35E # 0 +0x88BE 0xF35F # 0 +0x88BF 0xF360 # 0 +0x88C0 0xF361 # 0 +0x88C1 0xF362 # 0 +0x88C2 0xF363 # 0 +0x88C3 0xF364 # 0 +0x88C4 0xF365 # 0 +0x88C5 0xF366 # 0 +0x88C6 0xF367 # 0 +0x88C7 0xF368 # 0 +0x88C8 0xF369 # 0 +0x88C9 0xF36A # 0 +0x88CA 0xF36B # 0 +0x88CB 0xF36C # 0 +0x88CC 0xF36D # 0 +0x88CD 0xF36E # 0 +0x88CE 0xF36F # 0 +0x88CF 0xF370 # 0 +0x88D0 0xF371 # 0 +0x88D1 0xF372 # 0 +0x88D2 0xF373 # 0 +0x88D3 0xF374 # 0 +0x88D4 0xF375 # 0 +0x88D5 0xF376 # 0 +0x88D6 0xF377 # 0 +0x88D7 0xF378 # 0 +0x88D8 0xF379 # 0 +0x88D9 0xF37A # 0 +0x88DA 0xF37B # 0 +0x88DB 0xF37C # 0 +0x88DC 0xF37D # 0 +0x88DD 0xF37E # 0 +0x88DE 0xF37F # 0 +0x88DF 0xF380 # 0 +0x88E0 0xF381 # 0 +0x88E1 0xF382 # 0 +0x88E2 0xF383 # 0 +0x88E3 0xF384 # 0 +0x88E4 0xF385 # 0 +0x88E5 0xF386 # 0 +0x88E6 0xF387 # 0 +0x88E7 0xF388 # 0 +0x88E8 0xF389 # 0 +0x88E9 0xF38A # 0 +0x88EA 0xF38B # 0 +0x88EB 0xF38C # 0 +0x88EC 0xF38D # 0 +0x88ED 0xF38E # 0 +0x88EE 0xF38F # 0 +0x88EF 0xF390 # 0 +0x88F0 0xF391 # 0 +0x88F1 0xF392 # 0 +0x88F2 0xF393 # 0 +0x88F3 0xF394 # 0 +0x88F4 0xF395 # 0 +0x88F5 0xF396 # 0 +0x88F6 0xF397 # 0 +0x88F7 0xF398 # 0 +0x88F8 0xF399 # 0 +0x88F9 0xF39A # 0 +0x88FA 0xF39B # 0 +0x88FB 0xF39C # 0 +0x88FC 0xF39D # 0 +0x88FD 0xF39E # 0 +0x88FE 0xF39F # 0 +0x8940 0xF3A0 # 0 +0x8941 0xF3A1 # 0 +0x8942 0xF3A2 # 0 +0x8943 0xF3A3 # 0 +0x8944 0xF3A4 # 0 +0x8945 0xF3A5 # 0 +0x8946 0xF3A6 # 0 +0x8947 0xF3A7 # 0 +0x8948 0xF3A8 # 0 +0x8949 0xF3A9 # 0 +0x894A 0xF3AA # 0 +0x894B 0xF3AB # 0 +0x894C 0xF3AC # 0 +0x894D 0xF3AD # 0 +0x894E 0xF3AE # 0 +0x894F 0xF3AF # 0 +0x8950 0xF3B0 # 0 +0x8951 0xF3B1 # 0 +0x8952 0xF3B2 # 0 +0x8953 0xF3B3 # 0 +0x8954 0xF3B4 # 0 +0x8955 0xF3B5 # 0 +0x8956 0xF3B6 # 0 +0x8957 0xF3B7 # 0 +0x8958 0xF3B8 # 0 +0x8959 0xF3B9 # 0 +0x895A 0xF3BA # 0 +0x895B 0xF3BB # 0 +0x895C 0xF3BC # 0 +0x895D 0xF3BD # 0 +0x895E 0xF3BE # 0 +0x895F 0xF3BF # 0 +0x8960 0xF3C0 # 0 +0x8961 0xF3C1 # 0 +0x8962 0xF3C2 # 0 +0x8963 0xF3C3 # 0 +0x8964 0xF3C4 # 0 +0x8965 0xF3C5 # 0 +0x8966 0xF3C6 # 0 +0x8967 0xF3C7 # 0 +0x8968 0xF3C8 # 0 +0x8969 0xF3C9 # 0 +0x896A 0xF3CA # 0 +0x896B 0xF3CB # 0 +0x896C 0xF3CC # 0 +0x896D 0xF3CD # 0 +0x896E 0xF3CE # 0 +0x896F 0xF3CF # 0 +0x8970 0xF3D0 # 0 +0x8971 0xF3D1 # 0 +0x8972 0xF3D2 # 0 +0x8973 0xF3D3 # 0 +0x8974 0xF3D4 # 0 +0x8975 0xF3D5 # 0 +0x8976 0xF3D6 # 0 +0x8977 0xF3D7 # 0 +0x8978 0xF3D8 # 0 +0x8979 0xF3D9 # 0 +0x897A 0xF3DA # 0 +0x897B 0xF3DB # 0 +0x897C 0xF3DC # 0 +0x897D 0xF3DD # 0 +0x897E 0xF3DE # 0 +0x89A1 0xF3DF # 0 +0x89A2 0xF3E0 # 0 +0x89A3 0xF3E1 # 0 +0x89A4 0xF3E2 # 0 +0x89A5 0xF3E3 # 0 +0x89A6 0xF3E4 # 0 +0x89A7 0xF3E5 # 0 +0x89A8 0xF3E6 # 0 +0x89A9 0xF3E7 # 0 +0x89AA 0xF3E8 # 0 +0x89AB 0xF3E9 # 0 +0x89AC 0xF3EA # 0 +0x89AD 0xF3EB # 0 +0x89AE 0xF3EC # 0 +0x89AF 0xF3ED # 0 +0x89B0 0xF3EE # 0 +0x89B1 0xF3EF # 0 +0x89B2 0xF3F0 # 0 +0x89B3 0xF3F1 # 0 +0x89B4 0xF3F2 # 0 +0x89B5 0xF3F3 # 0 +0x89B6 0xF3F4 # 0 +0x89B7 0xF3F5 # 0 +0x89B8 0xF3F6 # 0 +0x89B9 0xF3F7 # 0 +0x89BA 0xF3F8 # 0 +0x89BB 0xF3F9 # 0 +0x89BC 0xF3FA # 0 +0x89BD 0xF3FB # 0 +0x89BE 0xF3FC # 0 +0x89BF 0xF3FD # 0 +0x89C0 0xF3FE # 0 +0x89C1 0xF3FF # 0 +0x89C2 0xF400 # 0 +0x89C3 0xF401 # 0 +0x89C4 0xF402 # 0 +0x89C5 0xF403 # 0 +0x89C6 0xF404 # 0 +0x89C7 0xF405 # 0 +0x89C8 0xF406 # 0 +0x89C9 0xF407 # 0 +0x89CA 0xF408 # 0 +0x89CB 0xF409 # 0 +0x89CC 0xF40A # 0 +0x89CD 0xF40B # 0 +0x89CE 0xF40C # 0 +0x89CF 0xF40D # 0 +0x89D0 0xF40E # 0 +0x89D1 0xF40F # 0 +0x89D2 0xF410 # 0 +0x89D3 0xF411 # 0 +0x89D4 0xF412 # 0 +0x89D5 0xF413 # 0 +0x89D6 0xF414 # 0 +0x89D7 0xF415 # 0 +0x89D8 0xF416 # 0 +0x89D9 0xF417 # 0 +0x89DA 0xF418 # 0 +0x89DB 0xF419 # 0 +0x89DC 0xF41A # 0 +0x89DD 0xF41B # 0 +0x89DE 0xF41C # 0 +0x89DF 0xF41D # 0 +0x89E0 0xF41E # 0 +0x89E1 0xF41F # 0 +0x89E2 0xF420 # 0 +0x89E3 0xF421 # 0 +0x89E4 0xF422 # 0 +0x89E5 0xF423 # 0 +0x89E6 0xF424 # 0 +0x89E7 0xF425 # 0 +0x89E8 0xF426 # 0 +0x89E9 0xF427 # 0 +0x89EA 0xF428 # 0 +0x89EB 0xF429 # 0 +0x89EC 0xF42A # 0 +0x89ED 0xF42B # 0 +0x89EE 0xF42C # 0 +0x89EF 0xF42D # 0 +0x89F0 0xF42E # 0 +0x89F1 0xF42F # 0 +0x89F2 0xF430 # 0 +0x89F3 0xF431 # 0 +0x89F4 0xF432 # 0 +0x89F5 0xF433 # 0 +0x89F6 0xF434 # 0 +0x89F7 0xF435 # 0 +0x89F8 0xF436 # 0 +0x89F9 0xF437 # 0 +0x89FA 0xF438 # 0 +0x89FB 0xF439 # 0 +0x89FC 0xF43A # 0 +0x89FD 0xF43B # 0 +0x89FE 0xF43C # 0 +0x8A40 0xF43D # 0 +0x8A41 0xF43E # 0 +0x8A42 0xF43F # 0 +0x8A43 0xF440 # 0 +0x8A44 0xF441 # 0 +0x8A45 0xF442 # 0 +0x8A46 0xF443 # 0 +0x8A47 0xF444 # 0 +0x8A48 0xF445 # 0 +0x8A49 0xF446 # 0 +0x8A4A 0xF447 # 0 +0x8A4B 0xF448 # 0 +0x8A4C 0xF449 # 0 +0x8A4D 0xF44A # 0 +0x8A4E 0xF44B # 0 +0x8A4F 0xF44C # 0 +0x8A50 0xF44D # 0 +0x8A51 0xF44E # 0 +0x8A52 0xF44F # 0 +0x8A53 0xF450 # 0 +0x8A54 0xF451 # 0 +0x8A55 0xF452 # 0 +0x8A56 0xF453 # 0 +0x8A57 0xF454 # 0 +0x8A58 0xF455 # 0 +0x8A59 0xF456 # 0 +0x8A5A 0xF457 # 0 +0x8A5B 0xF458 # 0 +0x8A5C 0xF459 # 0 +0x8A5D 0xF45A # 0 +0x8A5E 0xF45B # 0 +0x8A5F 0xF45C # 0 +0x8A60 0xF45D # 0 +0x8A61 0xF45E # 0 +0x8A62 0xF45F # 0 +0x8A63 0xF460 # 0 +0x8A64 0xF461 # 0 +0x8A65 0xF462 # 0 +0x8A66 0xF463 # 0 +0x8A67 0xF464 # 0 +0x8A68 0xF465 # 0 +0x8A69 0xF466 # 0 +0x8A6A 0xF467 # 0 +0x8A6B 0xF468 # 0 +0x8A6C 0xF469 # 0 +0x8A6D 0xF46A # 0 +0x8A6E 0xF46B # 0 +0x8A6F 0xF46C # 0 +0x8A70 0xF46D # 0 +0x8A71 0xF46E # 0 +0x8A72 0xF46F # 0 +0x8A73 0xF470 # 0 +0x8A74 0xF471 # 0 +0x8A75 0xF472 # 0 +0x8A76 0xF473 # 0 +0x8A77 0xF474 # 0 +0x8A78 0xF475 # 0 +0x8A79 0xF476 # 0 +0x8A7A 0xF477 # 0 +0x8A7B 0xF478 # 0 +0x8A7C 0xF479 # 0 +0x8A7D 0xF47A # 0 +0x8A7E 0xF47B # 0 +0x8AA1 0xF47C # 0 +0x8AA2 0xF47D # 0 +0x8AA3 0xF47E # 0 +0x8AA4 0xF47F # 0 +0x8AA5 0xF480 # 0 +0x8AA6 0xF481 # 0 +0x8AA7 0xF482 # 0 +0x8AA8 0xF483 # 0 +0x8AA9 0xF484 # 0 +0x8AAA 0xF485 # 0 +0x8AAB 0xF486 # 0 +0x8AAC 0xF487 # 0 +0x8AAD 0xF488 # 0 +0x8AAE 0xF489 # 0 +0x8AAF 0xF48A # 0 +0x8AB0 0xF48B # 0 +0x8AB1 0xF48C # 0 +0x8AB2 0xF48D # 0 +0x8AB3 0xF48E # 0 +0x8AB4 0xF48F # 0 +0x8AB5 0xF490 # 0 +0x8AB6 0xF491 # 0 +0x8AB7 0xF492 # 0 +0x8AB8 0xF493 # 0 +0x8AB9 0xF494 # 0 +0x8ABA 0xF495 # 0 +0x8ABB 0xF496 # 0 +0x8ABC 0xF497 # 0 +0x8ABD 0xF498 # 0 +0x8ABE 0xF499 # 0 +0x8ABF 0xF49A # 0 +0x8AC0 0xF49B # 0 +0x8AC1 0xF49C # 0 +0x8AC2 0xF49D # 0 +0x8AC3 0xF49E # 0 +0x8AC4 0xF49F # 0 +0x8AC5 0xF4A0 # 0 +0x8AC6 0xF4A1 # 0 +0x8AC7 0xF4A2 # 0 +0x8AC8 0xF4A3 # 0 +0x8AC9 0xF4A4 # 0 +0x8ACA 0xF4A5 # 0 +0x8ACB 0xF4A6 # 0 +0x8ACC 0xF4A7 # 0 +0x8ACD 0xF4A8 # 0 +0x8ACE 0xF4A9 # 0 +0x8ACF 0xF4AA # 0 +0x8AD0 0xF4AB # 0 +0x8AD1 0xF4AC # 0 +0x8AD2 0xF4AD # 0 +0x8AD3 0xF4AE # 0 +0x8AD4 0xF4AF # 0 +0x8AD5 0xF4B0 # 0 +0x8AD6 0xF4B1 # 0 +0x8AD7 0xF4B2 # 0 +0x8AD8 0xF4B3 # 0 +0x8AD9 0xF4B4 # 0 +0x8ADA 0xF4B5 # 0 +0x8ADB 0xF4B6 # 0 +0x8ADC 0xF4B7 # 0 +0x8ADD 0xF4B8 # 0 +0x8ADE 0xF4B9 # 0 +0x8ADF 0xF4BA # 0 +0x8AE0 0xF4BB # 0 +0x8AE1 0xF4BC # 0 +0x8AE2 0xF4BD # 0 +0x8AE3 0xF4BE # 0 +0x8AE4 0xF4BF # 0 +0x8AE5 0xF4C0 # 0 +0x8AE6 0xF4C1 # 0 +0x8AE7 0xF4C2 # 0 +0x8AE8 0xF4C3 # 0 +0x8AE9 0xF4C4 # 0 +0x8AEA 0xF4C5 # 0 +0x8AEB 0xF4C6 # 0 +0x8AEC 0xF4C7 # 0 +0x8AED 0xF4C8 # 0 +0x8AEE 0xF4C9 # 0 +0x8AEF 0xF4CA # 0 +0x8AF0 0xF4CB # 0 +0x8AF1 0xF4CC # 0 +0x8AF2 0xF4CD # 0 +0x8AF3 0xF4CE # 0 +0x8AF4 0xF4CF # 0 +0x8AF5 0xF4D0 # 0 +0x8AF6 0xF4D1 # 0 +0x8AF7 0xF4D2 # 0 +0x8AF8 0xF4D3 # 0 +0x8AF9 0xF4D4 # 0 +0x8AFA 0xF4D5 # 0 +0x8AFB 0xF4D6 # 0 +0x8AFC 0xF4D7 # 0 +0x8AFD 0xF4D8 # 0 +0x8AFE 0xF4D9 # 0 +0x8B40 0xF4DA # 0 +0x8B41 0xF4DB # 0 +0x8B42 0xF4DC # 0 +0x8B43 0xF4DD # 0 +0x8B44 0xF4DE # 0 +0x8B45 0xF4DF # 0 +0x8B46 0xF4E0 # 0 +0x8B47 0xF4E1 # 0 +0x8B48 0xF4E2 # 0 +0x8B49 0xF4E3 # 0 +0x8B4A 0xF4E4 # 0 +0x8B4B 0xF4E5 # 0 +0x8B4C 0xF4E6 # 0 +0x8B4D 0xF4E7 # 0 +0x8B4E 0xF4E8 # 0 +0x8B4F 0xF4E9 # 0 +0x8B50 0xF4EA # 0 +0x8B51 0xF4EB # 0 +0x8B52 0xF4EC # 0 +0x8B53 0xF4ED # 0 +0x8B54 0xF4EE # 0 +0x8B55 0xF4EF # 0 +0x8B56 0xF4F0 # 0 +0x8B57 0xF4F1 # 0 +0x8B58 0xF4F2 # 0 +0x8B59 0xF4F3 # 0 +0x8B5A 0xF4F4 # 0 +0x8B5B 0xF4F5 # 0 +0x8B5C 0xF4F6 # 0 +0x8B5D 0xF4F7 # 0 +0x8B5E 0xF4F8 # 0 +0x8B5F 0xF4F9 # 0 +0x8B60 0xF4FA # 0 +0x8B61 0xF4FB # 0 +0x8B62 0xF4FC # 0 +0x8B63 0xF4FD # 0 +0x8B64 0xF4FE # 0 +0x8B65 0xF4FF # 0 +0x8B66 0xF500 # 0 +0x8B67 0xF501 # 0 +0x8B68 0xF502 # 0 +0x8B69 0xF503 # 0 +0x8B6A 0xF504 # 0 +0x8B6B 0xF505 # 0 +0x8B6C 0xF506 # 0 +0x8B6D 0xF507 # 0 +0x8B6E 0xF508 # 0 +0x8B6F 0xF509 # 0 +0x8B70 0xF50A # 0 +0x8B71 0xF50B # 0 +0x8B72 0xF50C # 0 +0x8B73 0xF50D # 0 +0x8B74 0xF50E # 0 +0x8B75 0xF50F # 0 +0x8B76 0xF510 # 0 +0x8B77 0xF511 # 0 +0x8B78 0xF512 # 0 +0x8B79 0xF513 # 0 +0x8B7A 0xF514 # 0 +0x8B7B 0xF515 # 0 +0x8B7C 0xF516 # 0 +0x8B7D 0xF517 # 0 +0x8B7E 0xF518 # 0 +0x8BA1 0xF519 # 0 +0x8BA2 0xF51A # 0 +0x8BA3 0xF51B # 0 +0x8BA4 0xF51C # 0 +0x8BA5 0xF51D # 0 +0x8BA6 0xF51E # 0 +0x8BA7 0xF51F # 0 +0x8BA8 0xF520 # 0 +0x8BA9 0xF521 # 0 +0x8BAA 0xF522 # 0 +0x8BAB 0xF523 # 0 +0x8BAC 0xF524 # 0 +0x8BAD 0xF525 # 0 +0x8BAE 0xF526 # 0 +0x8BAF 0xF527 # 0 +0x8BB0 0xF528 # 0 +0x8BB1 0xF529 # 0 +0x8BB2 0xF52A # 0 +0x8BB3 0xF52B # 0 +0x8BB4 0xF52C # 0 +0x8BB5 0xF52D # 0 +0x8BB6 0xF52E # 0 +0x8BB7 0xF52F # 0 +0x8BB8 0xF530 # 0 +0x8BB9 0xF531 # 0 +0x8BBA 0xF532 # 0 +0x8BBB 0xF533 # 0 +0x8BBC 0xF534 # 0 +0x8BBD 0xF535 # 0 +0x8BBE 0xF536 # 0 +0x8BBF 0xF537 # 0 +0x8BC0 0xF538 # 0 +0x8BC1 0xF539 # 0 +0x8BC2 0xF53A # 0 +0x8BC3 0xF53B # 0 +0x8BC4 0xF53C # 0 +0x8BC5 0xF53D # 0 +0x8BC6 0xF53E # 0 +0x8BC7 0xF53F # 0 +0x8BC8 0xF540 # 0 +0x8BC9 0xF541 # 0 +0x8BCA 0xF542 # 0 +0x8BCB 0xF543 # 0 +0x8BCC 0xF544 # 0 +0x8BCD 0xF545 # 0 +0x8BCE 0xF546 # 0 +0x8BCF 0xF547 # 0 +0x8BD0 0xF548 # 0 +0x8BD1 0xF549 # 0 +0x8BD2 0xF54A # 0 +0x8BD3 0xF54B # 0 +0x8BD4 0xF54C # 0 +0x8BD5 0xF54D # 0 +0x8BD6 0xF54E # 0 +0x8BD7 0xF54F # 0 +0x8BD8 0xF550 # 0 +0x8BD9 0xF551 # 0 +0x8BDA 0xF552 # 0 +0x8BDB 0xF553 # 0 +0x8BDC 0xF554 # 0 +0x8BDD 0xF555 # 0 +0x8BDE 0xF556 # 0 +0x8BDF 0xF557 # 0 +0x8BE0 0xF558 # 0 +0x8BE1 0xF559 # 0 +0x8BE2 0xF55A # 0 +0x8BE3 0xF55B # 0 +0x8BE4 0xF55C # 0 +0x8BE5 0xF55D # 0 +0x8BE6 0xF55E # 0 +0x8BE7 0xF55F # 0 +0x8BE8 0xF560 # 0 +0x8BE9 0xF561 # 0 +0x8BEA 0xF562 # 0 +0x8BEB 0xF563 # 0 +0x8BEC 0xF564 # 0 +0x8BED 0xF565 # 0 +0x8BEE 0xF566 # 0 +0x8BEF 0xF567 # 0 +0x8BF0 0xF568 # 0 +0x8BF1 0xF569 # 0 +0x8BF2 0xF56A # 0 +0x8BF3 0xF56B # 0 +0x8BF4 0xF56C # 0 +0x8BF5 0xF56D # 0 +0x8BF6 0xF56E # 0 +0x8BF7 0xF56F # 0 +0x8BF8 0xF570 # 0 +0x8BF9 0xF571 # 0 +0x8BFA 0xF572 # 0 +0x8BFB 0xF573 # 0 +0x8BFC 0xF574 # 0 +0x8BFD 0xF575 # 0 +0x8BFE 0xF576 # 0 +0x8C40 0xF577 # 0 +0x8C41 0xF578 # 0 +0x8C42 0xF579 # 0 +0x8C43 0xF57A # 0 +0x8C44 0xF57B # 0 +0x8C45 0xF57C # 0 +0x8C46 0xF57D # 0 +0x8C47 0xF57E # 0 +0x8C48 0xF57F # 0 +0x8C49 0xF580 # 0 +0x8C4A 0xF581 # 0 +0x8C4B 0xF582 # 0 +0x8C4C 0xF583 # 0 +0x8C4D 0xF584 # 0 +0x8C4E 0xF585 # 0 +0x8C4F 0xF586 # 0 +0x8C50 0xF587 # 0 +0x8C51 0xF588 # 0 +0x8C52 0xF589 # 0 +0x8C53 0xF58A # 0 +0x8C54 0xF58B # 0 +0x8C55 0xF58C # 0 +0x8C56 0xF58D # 0 +0x8C57 0xF58E # 0 +0x8C58 0xF58F # 0 +0x8C59 0xF590 # 0 +0x8C5A 0xF591 # 0 +0x8C5B 0xF592 # 0 +0x8C5C 0xF593 # 0 +0x8C5D 0xF594 # 0 +0x8C5E 0xF595 # 0 +0x8C5F 0xF596 # 0 +0x8C60 0xF597 # 0 +0x8C61 0xF598 # 0 +0x8C62 0xF599 # 0 +0x8C63 0xF59A # 0 +0x8C64 0xF59B # 0 +0x8C65 0xF59C # 0 +0x8C66 0xF59D # 0 +0x8C67 0xF59E # 0 +0x8C68 0xF59F # 0 +0x8C69 0xF5A0 # 0 +0x8C6A 0xF5A1 # 0 +0x8C6B 0xF5A2 # 0 +0x8C6C 0xF5A3 # 0 +0x8C6D 0xF5A4 # 0 +0x8C6E 0xF5A5 # 0 +0x8C6F 0xF5A6 # 0 +0x8C70 0xF5A7 # 0 +0x8C71 0xF5A8 # 0 +0x8C72 0xF5A9 # 0 +0x8C73 0xF5AA # 0 +0x8C74 0xF5AB # 0 +0x8C75 0xF5AC # 0 +0x8C76 0xF5AD # 0 +0x8C77 0xF5AE # 0 +0x8C78 0xF5AF # 0 +0x8C79 0xF5B0 # 0 +0x8C7A 0xF5B1 # 0 +0x8C7B 0xF5B2 # 0 +0x8C7C 0xF5B3 # 0 +0x8C7D 0xF5B4 # 0 +0x8C7E 0xF5B5 # 0 +0x8CA1 0xF5B6 # 0 +0x8CA2 0xF5B7 # 0 +0x8CA3 0xF5B8 # 0 +0x8CA4 0xF5B9 # 0 +0x8CA5 0xF5BA # 0 +0x8CA6 0xF5BB # 0 +0x8CA7 0xF5BC # 0 +0x8CA8 0xF5BD # 0 +0x8CA9 0xF5BE # 0 +0x8CAA 0xF5BF # 0 +0x8CAB 0xF5C0 # 0 +0x8CAC 0xF5C1 # 0 +0x8CAD 0xF5C2 # 0 +0x8CAE 0xF5C3 # 0 +0x8CAF 0xF5C4 # 0 +0x8CB0 0xF5C5 # 0 +0x8CB1 0xF5C6 # 0 +0x8CB2 0xF5C7 # 0 +0x8CB3 0xF5C8 # 0 +0x8CB4 0xF5C9 # 0 +0x8CB5 0xF5CA # 0 +0x8CB6 0xF5CB # 0 +0x8CB7 0xF5CC # 0 +0x8CB8 0xF5CD # 0 +0x8CB9 0xF5CE # 0 +0x8CBA 0xF5CF # 0 +0x8CBB 0xF5D0 # 0 +0x8CBC 0xF5D1 # 0 +0x8CBD 0xF5D2 # 0 +0x8CBE 0xF5D3 # 0 +0x8CBF 0xF5D4 # 0 +0x8CC0 0xF5D5 # 0 +0x8CC1 0xF5D6 # 0 +0x8CC2 0xF5D7 # 0 +0x8CC3 0xF5D8 # 0 +0x8CC4 0xF5D9 # 0 +0x8CC5 0xF5DA # 0 +0x8CC6 0xF5DB # 0 +0x8CC7 0xF5DC # 0 +0x8CC8 0xF5DD # 0 +0x8CC9 0xF5DE # 0 +0x8CCA 0xF5DF # 0 +0x8CCB 0xF5E0 # 0 +0x8CCC 0xF5E1 # 0 +0x8CCD 0xF5E2 # 0 +0x8CCE 0xF5E3 # 0 +0x8CCF 0xF5E4 # 0 +0x8CD0 0xF5E5 # 0 +0x8CD1 0xF5E6 # 0 +0x8CD2 0xF5E7 # 0 +0x8CD3 0xF5E8 # 0 +0x8CD4 0xF5E9 # 0 +0x8CD5 0xF5EA # 0 +0x8CD6 0xF5EB # 0 +0x8CD7 0xF5EC # 0 +0x8CD8 0xF5ED # 0 +0x8CD9 0xF5EE # 0 +0x8CDA 0xF5EF # 0 +0x8CDB 0xF5F0 # 0 +0x8CDC 0xF5F1 # 0 +0x8CDD 0xF5F2 # 0 +0x8CDE 0xF5F3 # 0 +0x8CDF 0xF5F4 # 0 +0x8CE0 0xF5F5 # 0 +0x8CE1 0xF5F6 # 0 +0x8CE2 0xF5F7 # 0 +0x8CE3 0xF5F8 # 0 +0x8CE4 0xF5F9 # 0 +0x8CE5 0xF5FA # 0 +0x8CE6 0xF5FB # 0 +0x8CE7 0xF5FC # 0 +0x8CE8 0xF5FD # 0 +0x8CE9 0xF5FE # 0 +0x8CEA 0xF5FF # 0 +0x8CEB 0xF600 # 0 +0x8CEC 0xF601 # 0 +0x8CED 0xF602 # 0 +0x8CEE 0xF603 # 0 +0x8CEF 0xF604 # 0 +0x8CF0 0xF605 # 0 +0x8CF1 0xF606 # 0 +0x8CF2 0xF607 # 0 +0x8CF3 0xF608 # 0 +0x8CF4 0xF609 # 0 +0x8CF5 0xF60A # 0 +0x8CF6 0xF60B # 0 +0x8CF7 0xF60C # 0 +0x8CF8 0xF60D # 0 +0x8CF9 0xF60E # 0 +0x8CFA 0xF60F # 0 +0x8CFB 0xF610 # 0 +0x8CFC 0xF611 # 0 +0x8CFD 0xF612 # 0 +0x8CFE 0xF613 # 0 +0x8D40 0xF614 # 0 +0x8D41 0xF615 # 0 +0x8D42 0xF616 # 0 +0x8D43 0xF617 # 0 +0x8D44 0xF618 # 0 +0x8D45 0xF619 # 0 +0x8D46 0xF61A # 0 +0x8D47 0xF61B # 0 +0x8D48 0xF61C # 0 +0x8D49 0xF61D # 0 +0x8D4A 0xF61E # 0 +0x8D4B 0xF61F # 0 +0x8D4C 0xF620 # 0 +0x8D4D 0xF621 # 0 +0x8D4E 0xF622 # 0 +0x8D4F 0xF623 # 0 +0x8D50 0xF624 # 0 +0x8D51 0xF625 # 0 +0x8D52 0xF626 # 0 +0x8D53 0xF627 # 0 +0x8D54 0xF628 # 0 +0x8D55 0xF629 # 0 +0x8D56 0xF62A # 0 +0x8D57 0xF62B # 0 +0x8D58 0xF62C # 0 +0x8D59 0xF62D # 0 +0x8D5A 0xF62E # 0 +0x8D5B 0xF62F # 0 +0x8D5C 0xF630 # 0 +0x8D5D 0xF631 # 0 +0x8D5E 0xF632 # 0 +0x8D5F 0xF633 # 0 +0x8D60 0xF634 # 0 +0x8D61 0xF635 # 0 +0x8D62 0xF636 # 0 +0x8D63 0xF637 # 0 +0x8D64 0xF638 # 0 +0x8D65 0xF639 # 0 +0x8D66 0xF63A # 0 +0x8D67 0xF63B # 0 +0x8D68 0xF63C # 0 +0x8D69 0xF63D # 0 +0x8D6A 0xF63E # 0 +0x8D6B 0xF63F # 0 +0x8D6C 0xF640 # 0 +0x8D6D 0xF641 # 0 +0x8D6E 0xF642 # 0 +0x8D6F 0xF643 # 0 +0x8D70 0xF644 # 0 +0x8D71 0xF645 # 0 +0x8D72 0xF646 # 0 +0x8D73 0xF647 # 0 +0x8D74 0xF648 # 0 +0x8D75 0xF649 # 0 +0x8D76 0xF64A # 0 +0x8D77 0xF64B # 0 +0x8D78 0xF64C # 0 +0x8D79 0xF64D # 0 +0x8D7A 0xF64E # 0 +0x8D7B 0xF64F # 0 +0x8D7C 0xF650 # 0 +0x8D7D 0xF651 # 0 +0x8D7E 0xF652 # 0 +0x8DA1 0xF653 # 0 +0x8DA2 0xF654 # 0 +0x8DA3 0xF655 # 0 +0x8DA4 0xF656 # 0 +0x8DA5 0xF657 # 0 +0x8DA6 0xF658 # 0 +0x8DA7 0xF659 # 0 +0x8DA8 0xF65A # 0 +0x8DA9 0xF65B # 0 +0x8DAA 0xF65C # 0 +0x8DAB 0xF65D # 0 +0x8DAC 0xF65E # 0 +0x8DAD 0xF65F # 0 +0x8DAE 0xF660 # 0 +0x8DAF 0xF661 # 0 +0x8DB0 0xF662 # 0 +0x8DB1 0xF663 # 0 +0x8DB2 0xF664 # 0 +0x8DB3 0xF665 # 0 +0x8DB4 0xF666 # 0 +0x8DB5 0xF667 # 0 +0x8DB6 0xF668 # 0 +0x8DB7 0xF669 # 0 +0x8DB8 0xF66A # 0 +0x8DB9 0xF66B # 0 +0x8DBA 0xF66C # 0 +0x8DBB 0xF66D # 0 +0x8DBC 0xF66E # 0 +0x8DBD 0xF66F # 0 +0x8DBE 0xF670 # 0 +0x8DBF 0xF671 # 0 +0x8DC0 0xF672 # 0 +0x8DC1 0xF673 # 0 +0x8DC2 0xF674 # 0 +0x8DC3 0xF675 # 0 +0x8DC4 0xF676 # 0 +0x8DC5 0xF677 # 0 +0x8DC6 0xF678 # 0 +0x8DC7 0xF679 # 0 +0x8DC8 0xF67A # 0 +0x8DC9 0xF67B # 0 +0x8DCA 0xF67C # 0 +0x8DCB 0xF67D # 0 +0x8DCC 0xF67E # 0 +0x8DCD 0xF67F # 0 +0x8DCE 0xF680 # 0 +0x8DCF 0xF681 # 0 +0x8DD0 0xF682 # 0 +0x8DD1 0xF683 # 0 +0x8DD2 0xF684 # 0 +0x8DD3 0xF685 # 0 +0x8DD4 0xF686 # 0 +0x8DD5 0xF687 # 0 +0x8DD6 0xF688 # 0 +0x8DD7 0xF689 # 0 +0x8DD8 0xF68A # 0 +0x8DD9 0xF68B # 0 +0x8DDA 0xF68C # 0 +0x8DDB 0xF68D # 0 +0x8DDC 0xF68E # 0 +0x8DDD 0xF68F # 0 +0x8DDE 0xF690 # 0 +0x8DDF 0xF691 # 0 +0x8DE0 0xF692 # 0 +0x8DE1 0xF693 # 0 +0x8DE2 0xF694 # 0 +0x8DE3 0xF695 # 0 +0x8DE4 0xF696 # 0 +0x8DE5 0xF697 # 0 +0x8DE6 0xF698 # 0 +0x8DE7 0xF699 # 0 +0x8DE8 0xF69A # 0 +0x8DE9 0xF69B # 0 +0x8DEA 0xF69C # 0 +0x8DEB 0xF69D # 0 +0x8DEC 0xF69E # 0 +0x8DED 0xF69F # 0 +0x8DEE 0xF6A0 # 0 +0x8DEF 0xF6A1 # 0 +0x8DF0 0xF6A2 # 0 +0x8DF1 0xF6A3 # 0 +0x8DF2 0xF6A4 # 0 +0x8DF3 0xF6A5 # 0 +0x8DF4 0xF6A6 # 0 +0x8DF5 0xF6A7 # 0 +0x8DF6 0xF6A8 # 0 +0x8DF7 0xF6A9 # 0 +0x8DF8 0xF6AA # 0 +0x8DF9 0xF6AB # 0 +0x8DFA 0xF6AC # 0 +0x8DFB 0xF6AD # 0 +0x8DFC 0xF6AE # 0 +0x8DFD 0xF6AF # 0 +0x8DFE 0xF6B0 # 0 +0x8E40 0xE311 # 0 +0x8E41 0xE312 # 0 +0x8E42 0xE313 # 0 +0x8E43 0xE314 # 0 +0x8E44 0xE315 # 0 +0x8E45 0xE316 # 0 +0x8E46 0xE317 # 0 +0x8E47 0xE318 # 0 +0x8E48 0xE319 # 0 +0x8E49 0xE31A # 0 +0x8E4A 0xE31B # 0 +0x8E4B 0xE31C # 0 +0x8E4C 0xE31D # 0 +0x8E4D 0xE31E # 0 +0x8E4E 0xE31F # 0 +0x8E4F 0xE320 # 0 +0x8E50 0xE321 # 0 +0x8E51 0xE322 # 0 +0x8E52 0xE323 # 0 +0x8E53 0xE324 # 0 +0x8E54 0xE325 # 0 +0x8E55 0xE326 # 0 +0x8E56 0xE327 # 0 +0x8E57 0xE328 # 0 +0x8E58 0xE329 # 0 +0x8E59 0xE32A # 0 +0x8E5A 0xE32B # 0 +0x8E5B 0xE32C # 0 +0x8E5C 0xE32D # 0 +0x8E5D 0xE32E # 0 +0x8E5E 0xE32F # 0 +0x8E5F 0xE330 # 0 +0x8E60 0xE331 # 0 +0x8E61 0xE332 # 0 +0x8E62 0xE333 # 0 +0x8E63 0xE334 # 0 +0x8E64 0xE335 # 0 +0x8E65 0xE336 # 0 +0x8E66 0xE337 # 0 +0x8E67 0xE338 # 0 +0x8E68 0xE339 # 0 +0x8E69 0xE33A # 0 +0x8E6A 0xE33B # 0 +0x8E6B 0xE33C # 0 +0x8E6C 0xE33D # 0 +0x8E6D 0xE33E # 0 +0x8E6E 0xE33F # 0 +0x8E6F 0xE340 # 0 +0x8E70 0xE341 # 0 +0x8E71 0xE342 # 0 +0x8E72 0xE343 # 0 +0x8E73 0xE344 # 0 +0x8E74 0xE345 # 0 +0x8E75 0xE346 # 0 +0x8E76 0xE347 # 0 +0x8E77 0xE348 # 0 +0x8E78 0xE349 # 0 +0x8E79 0xE34A # 0 +0x8E7A 0xE34B # 0 +0x8E7B 0xE34C # 0 +0x8E7C 0xE34D # 0 +0x8E7D 0xE34E # 0 +0x8E7E 0xE34F # 0 +0x8EA1 0xE350 # 0 +0x8EA2 0xE351 # 0 +0x8EA3 0xE352 # 0 +0x8EA4 0xE353 # 0 +0x8EA5 0xE354 # 0 +0x8EA6 0xE355 # 0 +0x8EA7 0xE356 # 0 +0x8EA8 0xE357 # 0 +0x8EA9 0xE358 # 0 +0x8EAA 0xE359 # 0 +0x8EAB 0xE35A # 0 +0x8EAC 0xE35B # 0 +0x8EAD 0xE35C # 0 +0x8EAE 0xE35D # 0 +0x8EAF 0xE35E # 0 +0x8EB0 0xE35F # 0 +0x8EB1 0xE360 # 0 +0x8EB2 0xE361 # 0 +0x8EB3 0xE362 # 0 +0x8EB4 0xE363 # 0 +0x8EB5 0xE364 # 0 +0x8EB6 0xE365 # 0 +0x8EB7 0xE366 # 0 +0x8EB8 0xE367 # 0 +0x8EB9 0xE368 # 0 +0x8EBA 0xE369 # 0 +0x8EBB 0xE36A # 0 +0x8EBC 0xE36B # 0 +0x8EBD 0xE36C # 0 +0x8EBE 0xE36D # 0 +0x8EBF 0xE36E # 0 +0x8EC0 0xE36F # 0 +0x8EC1 0xE370 # 0 +0x8EC2 0xE371 # 0 +0x8EC3 0xE372 # 0 +0x8EC4 0xE373 # 0 +0x8EC5 0xE374 # 0 +0x8EC6 0xE375 # 0 +0x8EC7 0xE376 # 0 +0x8EC8 0xE377 # 0 +0x8EC9 0xE378 # 0 +0x8ECA 0xE379 # 0 +0x8ECB 0xE37A # 0 +0x8ECC 0xE37B # 0 +0x8ECD 0xE37C # 0 +0x8ECE 0xE37D # 0 +0x8ECF 0xE37E # 0 +0x8ED0 0xE37F # 0 +0x8ED1 0xE380 # 0 +0x8ED2 0xE381 # 0 +0x8ED3 0xE382 # 0 +0x8ED4 0xE383 # 0 +0x8ED5 0xE384 # 0 +0x8ED6 0xE385 # 0 +0x8ED7 0xE386 # 0 +0x8ED8 0xE387 # 0 +0x8ED9 0xE388 # 0 +0x8EDA 0xE389 # 0 +0x8EDB 0xE38A # 0 +0x8EDC 0xE38B # 0 +0x8EDD 0xE38C # 0 +0x8EDE 0xE38D # 0 +0x8EDF 0xE38E # 0 +0x8EE0 0xE38F # 0 +0x8EE1 0xE390 # 0 +0x8EE2 0xE391 # 0 +0x8EE3 0xE392 # 0 +0x8EE4 0xE393 # 0 +0x8EE5 0xE394 # 0 +0x8EE6 0xE395 # 0 +0x8EE7 0xE396 # 0 +0x8EE8 0xE397 # 0 +0x8EE9 0xE398 # 0 +0x8EEA 0xE399 # 0 +0x8EEB 0xE39A # 0 +0x8EEC 0xE39B # 0 +0x8EED 0xE39C # 0 +0x8EEE 0xE39D # 0 +0x8EEF 0xE39E # 0 +0x8EF0 0xE39F # 0 +0x8EF1 0xE3A0 # 0 +0x8EF2 0xE3A1 # 0 +0x8EF3 0xE3A2 # 0 +0x8EF4 0xE3A3 # 0 +0x8EF5 0xE3A4 # 0 +0x8EF6 0xE3A5 # 0 +0x8EF7 0xE3A6 # 0 +0x8EF8 0xE3A7 # 0 +0x8EF9 0xE3A8 # 0 +0x8EFA 0xE3A9 # 0 +0x8EFB 0xE3AA # 0 +0x8EFC 0xE3AB # 0 +0x8EFD 0xE3AC # 0 +0x8EFE 0xE3AD # 0 +0x8F40 0xE3AE # 0 +0x8F41 0xE3AF # 0 +0x8F42 0xE3B0 # 0 +0x8F43 0xE3B1 # 0 +0x8F44 0xE3B2 # 0 +0x8F45 0xE3B3 # 0 +0x8F46 0xE3B4 # 0 +0x8F47 0xE3B5 # 0 +0x8F48 0xE3B6 # 0 +0x8F49 0xE3B7 # 0 +0x8F4A 0xE3B8 # 0 +0x8F4B 0xE3B9 # 0 +0x8F4C 0xE3BA # 0 +0x8F4D 0xE3BB # 0 +0x8F4E 0xE3BC # 0 +0x8F4F 0xE3BD # 0 +0x8F50 0xE3BE # 0 +0x8F51 0xE3BF # 0 +0x8F52 0xE3C0 # 0 +0x8F53 0xE3C1 # 0 +0x8F54 0xE3C2 # 0 +0x8F55 0xE3C3 # 0 +0x8F56 0xE3C4 # 0 +0x8F57 0xE3C5 # 0 +0x8F58 0xE3C6 # 0 +0x8F59 0xE3C7 # 0 +0x8F5A 0xE3C8 # 0 +0x8F5B 0xE3C9 # 0 +0x8F5C 0xE3CA # 0 +0x8F5D 0xE3CB # 0 +0x8F5E 0xE3CC # 0 +0x8F5F 0xE3CD # 0 +0x8F60 0xE3CE # 0 +0x8F61 0xE3CF # 0 +0x8F62 0xE3D0 # 0 +0x8F63 0xE3D1 # 0 +0x8F64 0xE3D2 # 0 +0x8F65 0xE3D3 # 0 +0x8F66 0xE3D4 # 0 +0x8F67 0xE3D5 # 0 +0x8F68 0xE3D6 # 0 +0x8F69 0xE3D7 # 0 +0x8F6A 0xE3D8 # 0 +0x8F6B 0xE3D9 # 0 +0x8F6C 0xE3DA # 0 +0x8F6D 0xE3DB # 0 +0x8F6E 0xE3DC # 0 +0x8F6F 0xE3DD # 0 +0x8F70 0xE3DE # 0 +0x8F71 0xE3DF # 0 +0x8F72 0xE3E0 # 0 +0x8F73 0xE3E1 # 0 +0x8F74 0xE3E2 # 0 +0x8F75 0xE3E3 # 0 +0x8F76 0xE3E4 # 0 +0x8F77 0xE3E5 # 0 +0x8F78 0xE3E6 # 0 +0x8F79 0xE3E7 # 0 +0x8F7A 0xE3E8 # 0 +0x8F7B 0xE3E9 # 0 +0x8F7C 0xE3EA # 0 +0x8F7D 0xE3EB # 0 +0x8F7E 0xE3EC # 0 +0x8FA1 0xE3ED # 0 +0x8FA2 0xE3EE # 0 +0x8FA3 0xE3EF # 0 +0x8FA4 0xE3F0 # 0 +0x8FA5 0xE3F1 # 0 +0x8FA6 0xE3F2 # 0 +0x8FA7 0xE3F3 # 0 +0x8FA8 0xE3F4 # 0 +0x8FA9 0xE3F5 # 0 +0x8FAA 0xE3F6 # 0 +0x8FAB 0xE3F7 # 0 +0x8FAC 0xE3F8 # 0 +0x8FAD 0xE3F9 # 0 +0x8FAE 0xE3FA # 0 +0x8FAF 0xE3FB # 0 +0x8FB0 0xE3FC # 0 +0x8FB1 0xE3FD # 0 +0x8FB2 0xE3FE # 0 +0x8FB3 0xE3FF # 0 +0x8FB4 0xE400 # 0 +0x8FB5 0xE401 # 0 +0x8FB6 0xE402 # 0 +0x8FB7 0xE403 # 0 +0x8FB8 0xE404 # 0 +0x8FB9 0xE405 # 0 +0x8FBA 0xE406 # 0 +0x8FBB 0xE407 # 0 +0x8FBC 0xE408 # 0 +0x8FBD 0xE409 # 0 +0x8FBE 0xE40A # 0 +0x8FBF 0xE40B # 0 +0x8FC0 0xE40C # 0 +0x8FC1 0xE40D # 0 +0x8FC2 0xE40E # 0 +0x8FC3 0xE40F # 0 +0x8FC4 0xE410 # 0 +0x8FC5 0xE411 # 0 +0x8FC6 0xE412 # 0 +0x8FC7 0xE413 # 0 +0x8FC8 0xE414 # 0 +0x8FC9 0xE415 # 0 +0x8FCA 0xE416 # 0 +0x8FCB 0xE417 # 0 +0x8FCC 0xE418 # 0 +0x8FCD 0xE419 # 0 +0x8FCE 0xE41A # 0 +0x8FCF 0xE41B # 0 +0x8FD0 0xE41C # 0 +0x8FD1 0xE41D # 0 +0x8FD2 0xE41E # 0 +0x8FD3 0xE41F # 0 +0x8FD4 0xE420 # 0 +0x8FD5 0xE421 # 0 +0x8FD6 0xE422 # 0 +0x8FD7 0xE423 # 0 +0x8FD8 0xE424 # 0 +0x8FD9 0xE425 # 0 +0x8FDA 0xE426 # 0 +0x8FDB 0xE427 # 0 +0x8FDC 0xE428 # 0 +0x8FDD 0xE429 # 0 +0x8FDE 0xE42A # 0 +0x8FDF 0xE42B # 0 +0x8FE0 0xE42C # 0 +0x8FE1 0xE42D # 0 +0x8FE2 0xE42E # 0 +0x8FE3 0xE42F # 0 +0x8FE4 0xE430 # 0 +0x8FE5 0xE431 # 0 +0x8FE6 0xE432 # 0 +0x8FE7 0xE433 # 0 +0x8FE8 0xE434 # 0 +0x8FE9 0xE435 # 0 +0x8FEA 0xE436 # 0 +0x8FEB 0xE437 # 0 +0x8FEC 0xE438 # 0 +0x8FED 0xE439 # 0 +0x8FEE 0xE43A # 0 +0x8FEF 0xE43B # 0 +0x8FF0 0xE43C # 0 +0x8FF1 0xE43D # 0 +0x8FF2 0xE43E # 0 +0x8FF3 0xE43F # 0 +0x8FF4 0xE440 # 0 +0x8FF5 0xE441 # 0 +0x8FF6 0xE442 # 0 +0x8FF7 0xE443 # 0 +0x8FF8 0xE444 # 0 +0x8FF9 0xE445 # 0 +0x8FFA 0xE446 # 0 +0x8FFB 0xE447 # 0 +0x8FFC 0xE448 # 0 +0x8FFD 0xE449 # 0 +0x8FFE 0xE44A # 0 +0x9040 0xE44B # 0 +0x9041 0xE44C # 0 +0x9042 0xE44D # 0 +0x9043 0xE44E # 0 +0x9044 0xE44F # 0 +0x9045 0xE450 # 0 +0x9046 0xE451 # 0 +0x9047 0xE452 # 0 +0x9048 0xE453 # 0 +0x9049 0xE454 # 0 +0x904A 0xE455 # 0 +0x904B 0xE456 # 0 +0x904C 0xE457 # 0 +0x904D 0xE458 # 0 +0x904E 0xE459 # 0 +0x904F 0xE45A # 0 +0x9050 0xE45B # 0 +0x9051 0xE45C # 0 +0x9052 0xE45D # 0 +0x9053 0xE45E # 0 +0x9054 0xE45F # 0 +0x9055 0xE460 # 0 +0x9056 0xE461 # 0 +0x9057 0xE462 # 0 +0x9058 0xE463 # 0 +0x9059 0xE464 # 0 +0x905A 0xE465 # 0 +0x905B 0xE466 # 0 +0x905C 0xE467 # 0 +0x905D 0xE468 # 0 +0x905E 0xE469 # 0 +0x905F 0xE46A # 0 +0x9060 0xE46B # 0 +0x9061 0xE46C # 0 +0x9062 0xE46D # 0 +0x9063 0xE46E # 0 +0x9064 0xE46F # 0 +0x9065 0xE470 # 0 +0x9066 0xE471 # 0 +0x9067 0xE472 # 0 +0x9068 0xE473 # 0 +0x9069 0xE474 # 0 +0x906A 0xE475 # 0 +0x906B 0xE476 # 0 +0x906C 0xE477 # 0 +0x906D 0xE478 # 0 +0x906E 0xE479 # 0 +0x906F 0xE47A # 0 +0x9070 0xE47B # 0 +0x9071 0xE47C # 0 +0x9072 0xE47D # 0 +0x9073 0xE47E # 0 +0x9074 0xE47F # 0 +0x9075 0xE480 # 0 +0x9076 0xE481 # 0 +0x9077 0xE482 # 0 +0x9078 0xE483 # 0 +0x9079 0xE484 # 0 +0x907A 0xE485 # 0 +0x907B 0xE486 # 0 +0x907C 0xE487 # 0 +0x907D 0xE488 # 0 +0x907E 0xE489 # 0 +0x90A1 0xE48A # 0 +0x90A2 0xE48B # 0 +0x90A3 0xE48C # 0 +0x90A4 0xE48D # 0 +0x90A5 0xE48E # 0 +0x90A6 0xE48F # 0 +0x90A7 0xE490 # 0 +0x90A8 0xE491 # 0 +0x90A9 0xE492 # 0 +0x90AA 0xE493 # 0 +0x90AB 0xE494 # 0 +0x90AC 0xE495 # 0 +0x90AD 0xE496 # 0 +0x90AE 0xE497 # 0 +0x90AF 0xE498 # 0 +0x90B0 0xE499 # 0 +0x90B1 0xE49A # 0 +0x90B2 0xE49B # 0 +0x90B3 0xE49C # 0 +0x90B4 0xE49D # 0 +0x90B5 0xE49E # 0 +0x90B6 0xE49F # 0 +0x90B7 0xE4A0 # 0 +0x90B8 0xE4A1 # 0 +0x90B9 0xE4A2 # 0 +0x90BA 0xE4A3 # 0 +0x90BB 0xE4A4 # 0 +0x90BC 0xE4A5 # 0 +0x90BD 0xE4A6 # 0 +0x90BE 0xE4A7 # 0 +0x90BF 0xE4A8 # 0 +0x90C0 0xE4A9 # 0 +0x90C1 0xE4AA # 0 +0x90C2 0xE4AB # 0 +0x90C3 0xE4AC # 0 +0x90C4 0xE4AD # 0 +0x90C5 0xE4AE # 0 +0x90C6 0xE4AF # 0 +0x90C7 0xE4B0 # 0 +0x90C8 0xE4B1 # 0 +0x90C9 0xE4B2 # 0 +0x90CA 0xE4B3 # 0 +0x90CB 0xE4B4 # 0 +0x90CC 0xE4B5 # 0 +0x90CD 0xE4B6 # 0 +0x90CE 0xE4B7 # 0 +0x90CF 0xE4B8 # 0 +0x90D0 0xE4B9 # 0 +0x90D1 0xE4BA # 0 +0x90D2 0xE4BB # 0 +0x90D3 0xE4BC # 0 +0x90D4 0xE4BD # 0 +0x90D5 0xE4BE # 0 +0x90D6 0xE4BF # 0 +0x90D7 0xE4C0 # 0 +0x90D8 0xE4C1 # 0 +0x90D9 0xE4C2 # 0 +0x90DA 0xE4C3 # 0 +0x90DB 0xE4C4 # 0 +0x90DC 0xE4C5 # 0 +0x90DD 0xE4C6 # 0 +0x90DE 0xE4C7 # 0 +0x90DF 0xE4C8 # 0 +0x90E0 0xE4C9 # 0 +0x90E1 0xE4CA # 0 +0x90E2 0xE4CB # 0 +0x90E3 0xE4CC # 0 +0x90E4 0xE4CD # 0 +0x90E5 0xE4CE # 0 +0x90E6 0xE4CF # 0 +0x90E7 0xE4D0 # 0 +0x90E8 0xE4D1 # 0 +0x90E9 0xE4D2 # 0 +0x90EA 0xE4D3 # 0 +0x90EB 0xE4D4 # 0 +0x90EC 0xE4D5 # 0 +0x90ED 0xE4D6 # 0 +0x90EE 0xE4D7 # 0 +0x90EF 0xE4D8 # 0 +0x90F0 0xE4D9 # 0 +0x90F1 0xE4DA # 0 +0x90F2 0xE4DB # 0 +0x90F3 0xE4DC # 0 +0x90F4 0xE4DD # 0 +0x90F5 0xE4DE # 0 +0x90F6 0xE4DF # 0 +0x90F7 0xE4E0 # 0 +0x90F8 0xE4E1 # 0 +0x90F9 0xE4E2 # 0 +0x90FA 0xE4E3 # 0 +0x90FB 0xE4E4 # 0 +0x90FC 0xE4E5 # 0 +0x90FD 0xE4E6 # 0 +0x90FE 0xE4E7 # 0 +0x9140 0xE4E8 # 0 +0x9141 0xE4E9 # 0 +0x9142 0xE4EA # 0 +0x9143 0xE4EB # 0 +0x9144 0xE4EC # 0 +0x9145 0xE4ED # 0 +0x9146 0xE4EE # 0 +0x9147 0xE4EF # 0 +0x9148 0xE4F0 # 0 +0x9149 0xE4F1 # 0 +0x914A 0xE4F2 # 0 +0x914B 0xE4F3 # 0 +0x914C 0xE4F4 # 0 +0x914D 0xE4F5 # 0 +0x914E 0xE4F6 # 0 +0x914F 0xE4F7 # 0 +0x9150 0xE4F8 # 0 +0x9151 0xE4F9 # 0 +0x9152 0xE4FA # 0 +0x9153 0xE4FB # 0 +0x9154 0xE4FC # 0 +0x9155 0xE4FD # 0 +0x9156 0xE4FE # 0 +0x9157 0xE4FF # 0 +0x9158 0xE500 # 0 +0x9159 0xE501 # 0 +0x915A 0xE502 # 0 +0x915B 0xE503 # 0 +0x915C 0xE504 # 0 +0x915D 0xE505 # 0 +0x915E 0xE506 # 0 +0x915F 0xE507 # 0 +0x9160 0xE508 # 0 +0x9161 0xE509 # 0 +0x9162 0xE50A # 0 +0x9163 0xE50B # 0 +0x9164 0xE50C # 0 +0x9165 0xE50D # 0 +0x9166 0xE50E # 0 +0x9167 0xE50F # 0 +0x9168 0xE510 # 0 +0x9169 0xE511 # 0 +0x916A 0xE512 # 0 +0x916B 0xE513 # 0 +0x916C 0xE514 # 0 +0x916D 0xE515 # 0 +0x916E 0xE516 # 0 +0x916F 0xE517 # 0 +0x9170 0xE518 # 0 +0x9171 0xE519 # 0 +0x9172 0xE51A # 0 +0x9173 0xE51B # 0 +0x9174 0xE51C # 0 +0x9175 0xE51D # 0 +0x9176 0xE51E # 0 +0x9177 0xE51F # 0 +0x9178 0xE520 # 0 +0x9179 0xE521 # 0 +0x917A 0xE522 # 0 +0x917B 0xE523 # 0 +0x917C 0xE524 # 0 +0x917D 0xE525 # 0 +0x917E 0xE526 # 0 +0x91A1 0xE527 # 0 +0x91A2 0xE528 # 0 +0x91A3 0xE529 # 0 +0x91A4 0xE52A # 0 +0x91A5 0xE52B # 0 +0x91A6 0xE52C # 0 +0x91A7 0xE52D # 0 +0x91A8 0xE52E # 0 +0x91A9 0xE52F # 0 +0x91AA 0xE530 # 0 +0x91AB 0xE531 # 0 +0x91AC 0xE532 # 0 +0x91AD 0xE533 # 0 +0x91AE 0xE534 # 0 +0x91AF 0xE535 # 0 +0x91B0 0xE536 # 0 +0x91B1 0xE537 # 0 +0x91B2 0xE538 # 0 +0x91B3 0xE539 # 0 +0x91B4 0xE53A # 0 +0x91B5 0xE53B # 0 +0x91B6 0xE53C # 0 +0x91B7 0xE53D # 0 +0x91B8 0xE53E # 0 +0x91B9 0xE53F # 0 +0x91BA 0xE540 # 0 +0x91BB 0xE541 # 0 +0x91BC 0xE542 # 0 +0x91BD 0xE543 # 0 +0x91BE 0xE544 # 0 +0x91BF 0xE545 # 0 +0x91C0 0xE546 # 0 +0x91C1 0xE547 # 0 +0x91C2 0xE548 # 0 +0x91C3 0xE549 # 0 +0x91C4 0xE54A # 0 +0x91C5 0xE54B # 0 +0x91C6 0xE54C # 0 +0x91C7 0xE54D # 0 +0x91C8 0xE54E # 0 +0x91C9 0xE54F # 0 +0x91CA 0xE550 # 0 +0x91CB 0xE551 # 0 +0x91CC 0xE552 # 0 +0x91CD 0xE553 # 0 +0x91CE 0xE554 # 0 +0x91CF 0xE555 # 0 +0x91D0 0xE556 # 0 +0x91D1 0xE557 # 0 +0x91D2 0xE558 # 0 +0x91D3 0xE559 # 0 +0x91D4 0xE55A # 0 +0x91D5 0xE55B # 0 +0x91D6 0xE55C # 0 +0x91D7 0xE55D # 0 +0x91D8 0xE55E # 0 +0x91D9 0xE55F # 0 +0x91DA 0xE560 # 0 +0x91DB 0xE561 # 0 +0x91DC 0xE562 # 0 +0x91DD 0xE563 # 0 +0x91DE 0xE564 # 0 +0x91DF 0xE565 # 0 +0x91E0 0xE566 # 0 +0x91E1 0xE567 # 0 +0x91E2 0xE568 # 0 +0x91E3 0xE569 # 0 +0x91E4 0xE56A # 0 +0x91E5 0xE56B # 0 +0x91E6 0xE56C # 0 +0x91E7 0xE56D # 0 +0x91E8 0xE56E # 0 +0x91E9 0xE56F # 0 +0x91EA 0xE570 # 0 +0x91EB 0xE571 # 0 +0x91EC 0xE572 # 0 +0x91ED 0xE573 # 0 +0x91EE 0xE574 # 0 +0x91EF 0xE575 # 0 +0x91F0 0xE576 # 0 +0x91F1 0xE577 # 0 +0x91F2 0xE578 # 0 +0x91F3 0xE579 # 0 +0x91F4 0xE57A # 0 +0x91F5 0xE57B # 0 +0x91F6 0xE57C # 0 +0x91F7 0xE57D # 0 +0x91F8 0xE57E # 0 +0x91F9 0xE57F # 0 +0x91FA 0xE580 # 0 +0x91FB 0xE581 # 0 +0x91FC 0xE582 # 0 +0x91FD 0xE583 # 0 +0x91FE 0xE584 # 0 +0x9240 0xE585 # 0 +0x9241 0xE586 # 0 +0x9242 0xE587 # 0 +0x9243 0xE588 # 0 +0x9244 0xE589 # 0 +0x9245 0xE58A # 0 +0x9246 0xE58B # 0 +0x9247 0xE58C # 0 +0x9248 0xE58D # 0 +0x9249 0xE58E # 0 +0x924A 0xE58F # 0 +0x924B 0xE590 # 0 +0x924C 0xE591 # 0 +0x924D 0xE592 # 0 +0x924E 0xE593 # 0 +0x924F 0xE594 # 0 +0x9250 0xE595 # 0 +0x9251 0xE596 # 0 +0x9252 0xE597 # 0 +0x9253 0xE598 # 0 +0x9254 0xE599 # 0 +0x9255 0xE59A # 0 +0x9256 0xE59B # 0 +0x9257 0xE59C # 0 +0x9258 0xE59D # 0 +0x9259 0xE59E # 0 +0x925A 0xE59F # 0 +0x925B 0xE5A0 # 0 +0x925C 0xE5A1 # 0 +0x925D 0xE5A2 # 0 +0x925E 0xE5A3 # 0 +0x925F 0xE5A4 # 0 +0x9260 0xE5A5 # 0 +0x9261 0xE5A6 # 0 +0x9262 0xE5A7 # 0 +0x9263 0xE5A8 # 0 +0x9264 0xE5A9 # 0 +0x9265 0xE5AA # 0 +0x9266 0xE5AB # 0 +0x9267 0xE5AC # 0 +0x9268 0xE5AD # 0 +0x9269 0xE5AE # 0 +0x926A 0xE5AF # 0 +0x926B 0xE5B0 # 0 +0x926C 0xE5B1 # 0 +0x926D 0xE5B2 # 0 +0x926E 0xE5B3 # 0 +0x926F 0xE5B4 # 0 +0x9270 0xE5B5 # 0 +0x9271 0xE5B6 # 0 +0x9272 0xE5B7 # 0 +0x9273 0xE5B8 # 0 +0x9274 0xE5B9 # 0 +0x9275 0xE5BA # 0 +0x9276 0xE5BB # 0 +0x9277 0xE5BC # 0 +0x9278 0xE5BD # 0 +0x9279 0xE5BE # 0 +0x927A 0xE5BF # 0 +0x927B 0xE5C0 # 0 +0x927C 0xE5C1 # 0 +0x927D 0xE5C2 # 0 +0x927E 0xE5C3 # 0 +0x92A1 0xE5C4 # 0 +0x92A2 0xE5C5 # 0 +0x92A3 0xE5C6 # 0 +0x92A4 0xE5C7 # 0 +0x92A5 0xE5C8 # 0 +0x92A6 0xE5C9 # 0 +0x92A7 0xE5CA # 0 +0x92A8 0xE5CB # 0 +0x92A9 0xE5CC # 0 +0x92AA 0xE5CD # 0 +0x92AB 0xE5CE # 0 +0x92AC 0xE5CF # 0 +0x92AD 0xE5D0 # 0 +0x92AE 0xE5D1 # 0 +0x92AF 0xE5D2 # 0 +0x92B0 0xE5D3 # 0 +0x92B1 0xE5D4 # 0 +0x92B2 0xE5D5 # 0 +0x92B3 0xE5D6 # 0 +0x92B4 0xE5D7 # 0 +0x92B5 0xE5D8 # 0 +0x92B6 0xE5D9 # 0 +0x92B7 0xE5DA # 0 +0x92B8 0xE5DB # 0 +0x92B9 0xE5DC # 0 +0x92BA 0xE5DD # 0 +0x92BB 0xE5DE # 0 +0x92BC 0xE5DF # 0 +0x92BD 0xE5E0 # 0 +0x92BE 0xE5E1 # 0 +0x92BF 0xE5E2 # 0 +0x92C0 0xE5E3 # 0 +0x92C1 0xE5E4 # 0 +0x92C2 0xE5E5 # 0 +0x92C3 0xE5E6 # 0 +0x92C4 0xE5E7 # 0 +0x92C5 0xE5E8 # 0 +0x92C6 0xE5E9 # 0 +0x92C7 0xE5EA # 0 +0x92C8 0xE5EB # 0 +0x92C9 0xE5EC # 0 +0x92CA 0xE5ED # 0 +0x92CB 0xE5EE # 0 +0x92CC 0xE5EF # 0 +0x92CD 0xE5F0 # 0 +0x92CE 0xE5F1 # 0 +0x92CF 0xE5F2 # 0 +0x92D0 0xE5F3 # 0 +0x92D1 0xE5F4 # 0 +0x92D2 0xE5F5 # 0 +0x92D3 0xE5F6 # 0 +0x92D4 0xE5F7 # 0 +0x92D5 0xE5F8 # 0 +0x92D6 0xE5F9 # 0 +0x92D7 0xE5FA # 0 +0x92D8 0xE5FB # 0 +0x92D9 0xE5FC # 0 +0x92DA 0xE5FD # 0 +0x92DB 0xE5FE # 0 +0x92DC 0xE5FF # 0 +0x92DD 0xE600 # 0 +0x92DE 0xE601 # 0 +0x92DF 0xE602 # 0 +0x92E0 0xE603 # 0 +0x92E1 0xE604 # 0 +0x92E2 0xE605 # 0 +0x92E3 0xE606 # 0 +0x92E4 0xE607 # 0 +0x92E5 0xE608 # 0 +0x92E6 0xE609 # 0 +0x92E7 0xE60A # 0 +0x92E8 0xE60B # 0 +0x92E9 0xE60C # 0 +0x92EA 0xE60D # 0 +0x92EB 0xE60E # 0 +0x92EC 0xE60F # 0 +0x92ED 0xE610 # 0 +0x92EE 0xE611 # 0 +0x92EF 0xE612 # 0 +0x92F0 0xE613 # 0 +0x92F1 0xE614 # 0 +0x92F2 0xE615 # 0 +0x92F3 0xE616 # 0 +0x92F4 0xE617 # 0 +0x92F5 0xE618 # 0 +0x92F6 0xE619 # 0 +0x92F7 0xE61A # 0 +0x92F8 0xE61B # 0 +0x92F9 0xE61C # 0 +0x92FA 0xE61D # 0 +0x92FB 0xE61E # 0 +0x92FC 0xE61F # 0 +0x92FD 0xE620 # 0 +0x92FE 0xE621 # 0 +0x9340 0xE622 # 0 +0x9341 0xE623 # 0 +0x9342 0xE624 # 0 +0x9343 0xE625 # 0 +0x9344 0xE626 # 0 +0x9345 0xE627 # 0 +0x9346 0xE628 # 0 +0x9347 0xE629 # 0 +0x9348 0xE62A # 0 +0x9349 0xE62B # 0 +0x934A 0xE62C # 0 +0x934B 0xE62D # 0 +0x934C 0xE62E # 0 +0x934D 0xE62F # 0 +0x934E 0xE630 # 0 +0x934F 0xE631 # 0 +0x9350 0xE632 # 0 +0x9351 0xE633 # 0 +0x9352 0xE634 # 0 +0x9353 0xE635 # 0 +0x9354 0xE636 # 0 +0x9355 0xE637 # 0 +0x9356 0xE638 # 0 +0x9357 0xE639 # 0 +0x9358 0xE63A # 0 +0x9359 0xE63B # 0 +0x935A 0xE63C # 0 +0x935B 0xE63D # 0 +0x935C 0xE63E # 0 +0x935D 0xE63F # 0 +0x935E 0xE640 # 0 +0x935F 0xE641 # 0 +0x9360 0xE642 # 0 +0x9361 0xE643 # 0 +0x9362 0xE644 # 0 +0x9363 0xE645 # 0 +0x9364 0xE646 # 0 +0x9365 0xE647 # 0 +0x9366 0xE648 # 0 +0x9367 0xE649 # 0 +0x9368 0xE64A # 0 +0x9369 0xE64B # 0 +0x936A 0xE64C # 0 +0x936B 0xE64D # 0 +0x936C 0xE64E # 0 +0x936D 0xE64F # 0 +0x936E 0xE650 # 0 +0x936F 0xE651 # 0 +0x9370 0xE652 # 0 +0x9371 0xE653 # 0 +0x9372 0xE654 # 0 +0x9373 0xE655 # 0 +0x9374 0xE656 # 0 +0x9375 0xE657 # 0 +0x9376 0xE658 # 0 +0x9377 0xE659 # 0 +0x9378 0xE65A # 0 +0x9379 0xE65B # 0 +0x937A 0xE65C # 0 +0x937B 0xE65D # 0 +0x937C 0xE65E # 0 +0x937D 0xE65F # 0 +0x937E 0xE660 # 0 +0x93A1 0xE661 # 0 +0x93A2 0xE662 # 0 +0x93A3 0xE663 # 0 +0x93A4 0xE664 # 0 +0x93A5 0xE665 # 0 +0x93A6 0xE666 # 0 +0x93A7 0xE667 # 0 +0x93A8 0xE668 # 0 +0x93A9 0xE669 # 0 +0x93AA 0xE66A # 0 +0x93AB 0xE66B # 0 +0x93AC 0xE66C # 0 +0x93AD 0xE66D # 0 +0x93AE 0xE66E # 0 +0x93AF 0xE66F # 0 +0x93B0 0xE670 # 0 +0x93B1 0xE671 # 0 +0x93B2 0xE672 # 0 +0x93B3 0xE673 # 0 +0x93B4 0xE674 # 0 +0x93B5 0xE675 # 0 +0x93B6 0xE676 # 0 +0x93B7 0xE677 # 0 +0x93B8 0xE678 # 0 +0x93B9 0xE679 # 0 +0x93BA 0xE67A # 0 +0x93BB 0xE67B # 0 +0x93BC 0xE67C # 0 +0x93BD 0xE67D # 0 +0x93BE 0xE67E # 0 +0x93BF 0xE67F # 0 +0x93C0 0xE680 # 0 +0x93C1 0xE681 # 0 +0x93C2 0xE682 # 0 +0x93C3 0xE683 # 0 +0x93C4 0xE684 # 0 +0x93C5 0xE685 # 0 +0x93C6 0xE686 # 0 +0x93C7 0xE687 # 0 +0x93C8 0xE688 # 0 +0x93C9 0xE689 # 0 +0x93CA 0xE68A # 0 +0x93CB 0xE68B # 0 +0x93CC 0xE68C # 0 +0x93CD 0xE68D # 0 +0x93CE 0xE68E # 0 +0x93CF 0xE68F # 0 +0x93D0 0xE690 # 0 +0x93D1 0xE691 # 0 +0x93D2 0xE692 # 0 +0x93D3 0xE693 # 0 +0x93D4 0xE694 # 0 +0x93D5 0xE695 # 0 +0x93D6 0xE696 # 0 +0x93D7 0xE697 # 0 +0x93D8 0xE698 # 0 +0x93D9 0xE699 # 0 +0x93DA 0xE69A # 0 +0x93DB 0xE69B # 0 +0x93DC 0xE69C # 0 +0x93DD 0xE69D # 0 +0x93DE 0xE69E # 0 +0x93DF 0xE69F # 0 +0x93E0 0xE6A0 # 0 +0x93E1 0xE6A1 # 0 +0x93E2 0xE6A2 # 0 +0x93E3 0xE6A3 # 0 +0x93E4 0xE6A4 # 0 +0x93E5 0xE6A5 # 0 +0x93E6 0xE6A6 # 0 +0x93E7 0xE6A7 # 0 +0x93E8 0xE6A8 # 0 +0x93E9 0xE6A9 # 0 +0x93EA 0xE6AA # 0 +0x93EB 0xE6AB # 0 +0x93EC 0xE6AC # 0 +0x93ED 0xE6AD # 0 +0x93EE 0xE6AE # 0 +0x93EF 0xE6AF # 0 +0x93F0 0xE6B0 # 0 +0x93F1 0xE6B1 # 0 +0x93F2 0xE6B2 # 0 +0x93F3 0xE6B3 # 0 +0x93F4 0xE6B4 # 0 +0x93F5 0xE6B5 # 0 +0x93F6 0xE6B6 # 0 +0x93F7 0xE6B7 # 0 +0x93F8 0xE6B8 # 0 +0x93F9 0xE6B9 # 0 +0x93FA 0xE6BA # 0 +0x93FB 0xE6BB # 0 +0x93FC 0xE6BC # 0 +0x93FD 0xE6BD # 0 +0x93FE 0xE6BE # 0 +0x9440 0xE6BF # 0 +0x9441 0xE6C0 # 0 +0x9442 0xE6C1 # 0 +0x9443 0xE6C2 # 0 +0x9444 0xE6C3 # 0 +0x9445 0xE6C4 # 0 +0x9446 0xE6C5 # 0 +0x9447 0xE6C6 # 0 +0x9448 0xE6C7 # 0 +0x9449 0xE6C8 # 0 +0x944A 0xE6C9 # 0 +0x944B 0xE6CA # 0 +0x944C 0xE6CB # 0 +0x944D 0xE6CC # 0 +0x944E 0xE6CD # 0 +0x944F 0xE6CE # 0 +0x9450 0xE6CF # 0 +0x9451 0xE6D0 # 0 +0x9452 0xE6D1 # 0 +0x9453 0xE6D2 # 0 +0x9454 0xE6D3 # 0 +0x9455 0xE6D4 # 0 +0x9456 0xE6D5 # 0 +0x9457 0xE6D6 # 0 +0x9458 0xE6D7 # 0 +0x9459 0xE6D8 # 0 +0x945A 0xE6D9 # 0 +0x945B 0xE6DA # 0 +0x945C 0xE6DB # 0 +0x945D 0xE6DC # 0 +0x945E 0xE6DD # 0 +0x945F 0xE6DE # 0 +0x9460 0xE6DF # 0 +0x9461 0xE6E0 # 0 +0x9462 0xE6E1 # 0 +0x9463 0xE6E2 # 0 +0x9464 0xE6E3 # 0 +0x9465 0xE6E4 # 0 +0x9466 0xE6E5 # 0 +0x9467 0xE6E6 # 0 +0x9468 0xE6E7 # 0 +0x9469 0xE6E8 # 0 +0x946A 0xE6E9 # 0 +0x946B 0xE6EA # 0 +0x946C 0xE6EB # 0 +0x946D 0xE6EC # 0 +0x946E 0xE6ED # 0 +0x946F 0xE6EE # 0 +0x9470 0xE6EF # 0 +0x9471 0xE6F0 # 0 +0x9472 0xE6F1 # 0 +0x9473 0xE6F2 # 0 +0x9474 0xE6F3 # 0 +0x9475 0xE6F4 # 0 +0x9476 0xE6F5 # 0 +0x9477 0xE6F6 # 0 +0x9478 0xE6F7 # 0 +0x9479 0xE6F8 # 0 +0x947A 0xE6F9 # 0 +0x947B 0xE6FA # 0 +0x947C 0xE6FB # 0 +0x947D 0xE6FC # 0 +0x947E 0xE6FD # 0 +0x94A1 0xE6FE # 0 +0x94A2 0xE6FF # 0 +0x94A3 0xE700 # 0 +0x94A4 0xE701 # 0 +0x94A5 0xE702 # 0 +0x94A6 0xE703 # 0 +0x94A7 0xE704 # 0 +0x94A8 0xE705 # 0 +0x94A9 0xE706 # 0 +0x94AA 0xE707 # 0 +0x94AB 0xE708 # 0 +0x94AC 0xE709 # 0 +0x94AD 0xE70A # 0 +0x94AE 0xE70B # 0 +0x94AF 0xE70C # 0 +0x94B0 0xE70D # 0 +0x94B1 0xE70E # 0 +0x94B2 0xE70F # 0 +0x94B3 0xE710 # 0 +0x94B4 0xE711 # 0 +0x94B5 0xE712 # 0 +0x94B6 0xE713 # 0 +0x94B7 0xE714 # 0 +0x94B8 0xE715 # 0 +0x94B9 0xE716 # 0 +0x94BA 0xE717 # 0 +0x94BB 0xE718 # 0 +0x94BC 0xE719 # 0 +0x94BD 0xE71A # 0 +0x94BE 0xE71B # 0 +0x94BF 0xE71C # 0 +0x94C0 0xE71D # 0 +0x94C1 0xE71E # 0 +0x94C2 0xE71F # 0 +0x94C3 0xE720 # 0 +0x94C4 0xE721 # 0 +0x94C5 0xE722 # 0 +0x94C6 0xE723 # 0 +0x94C7 0xE724 # 0 +0x94C8 0xE725 # 0 +0x94C9 0xE726 # 0 +0x94CA 0xE727 # 0 +0x94CB 0xE728 # 0 +0x94CC 0xE729 # 0 +0x94CD 0xE72A # 0 +0x94CE 0xE72B # 0 +0x94CF 0xE72C # 0 +0x94D0 0xE72D # 0 +0x94D1 0xE72E # 0 +0x94D2 0xE72F # 0 +0x94D3 0xE730 # 0 +0x94D4 0xE731 # 0 +0x94D5 0xE732 # 0 +0x94D6 0xE733 # 0 +0x94D7 0xE734 # 0 +0x94D8 0xE735 # 0 +0x94D9 0xE736 # 0 +0x94DA 0xE737 # 0 +0x94DB 0xE738 # 0 +0x94DC 0xE739 # 0 +0x94DD 0xE73A # 0 +0x94DE 0xE73B # 0 +0x94DF 0xE73C # 0 +0x94E0 0xE73D # 0 +0x94E1 0xE73E # 0 +0x94E2 0xE73F # 0 +0x94E3 0xE740 # 0 +0x94E4 0xE741 # 0 +0x94E5 0xE742 # 0 +0x94E6 0xE743 # 0 +0x94E7 0xE744 # 0 +0x94E8 0xE745 # 0 +0x94E9 0xE746 # 0 +0x94EA 0xE747 # 0 +0x94EB 0xE748 # 0 +0x94EC 0xE749 # 0 +0x94ED 0xE74A # 0 +0x94EE 0xE74B # 0 +0x94EF 0xE74C # 0 +0x94F0 0xE74D # 0 +0x94F1 0xE74E # 0 +0x94F2 0xE74F # 0 +0x94F3 0xE750 # 0 +0x94F4 0xE751 # 0 +0x94F5 0xE752 # 0 +0x94F6 0xE753 # 0 +0x94F7 0xE754 # 0 +0x94F8 0xE755 # 0 +0x94F9 0xE756 # 0 +0x94FA 0xE757 # 0 +0x94FB 0xE758 # 0 +0x94FC 0xE759 # 0 +0x94FD 0xE75A # 0 +0x94FE 0xE75B # 0 +0x9540 0xE75C # 0 +0x9541 0xE75D # 0 +0x9542 0xE75E # 0 +0x9543 0xE75F # 0 +0x9544 0xE760 # 0 +0x9545 0xE761 # 0 +0x9546 0xE762 # 0 +0x9547 0xE763 # 0 +0x9548 0xE764 # 0 +0x9549 0xE765 # 0 +0x954A 0xE766 # 0 +0x954B 0xE767 # 0 +0x954C 0xE768 # 0 +0x954D 0xE769 # 0 +0x954E 0xE76A # 0 +0x954F 0xE76B # 0 +0x9550 0xE76C # 0 +0x9551 0xE76D # 0 +0x9552 0xE76E # 0 +0x9553 0xE76F # 0 +0x9554 0xE770 # 0 +0x9555 0xE771 # 0 +0x9556 0xE772 # 0 +0x9557 0xE773 # 0 +0x9558 0xE774 # 0 +0x9559 0xE775 # 0 +0x955A 0xE776 # 0 +0x955B 0xE777 # 0 +0x955C 0xE778 # 0 +0x955D 0xE779 # 0 +0x955E 0xE77A # 0 +0x955F 0xE77B # 0 +0x9560 0xE77C # 0 +0x9561 0xE77D # 0 +0x9562 0xE77E # 0 +0x9563 0xE77F # 0 +0x9564 0xE780 # 0 +0x9565 0xE781 # 0 +0x9566 0xE782 # 0 +0x9567 0xE783 # 0 +0x9568 0xE784 # 0 +0x9569 0xE785 # 0 +0x956A 0xE786 # 0 +0x956B 0xE787 # 0 +0x956C 0xE788 # 0 +0x956D 0xE789 # 0 +0x956E 0xE78A # 0 +0x956F 0xE78B # 0 +0x9570 0xE78C # 0 +0x9571 0xE78D # 0 +0x9572 0xE78E # 0 +0x9573 0xE78F # 0 +0x9574 0xE790 # 0 +0x9575 0xE791 # 0 +0x9576 0xE792 # 0 +0x9577 0xE793 # 0 +0x9578 0xE794 # 0 +0x9579 0xE795 # 0 +0x957A 0xE796 # 0 +0x957B 0xE797 # 0 +0x957C 0xE798 # 0 +0x957D 0xE799 # 0 +0x957E 0xE79A # 0 +0x95A1 0xE79B # 0 +0x95A2 0xE79C # 0 +0x95A3 0xE79D # 0 +0x95A4 0xE79E # 0 +0x95A5 0xE79F # 0 +0x95A6 0xE7A0 # 0 +0x95A7 0xE7A1 # 0 +0x95A8 0xE7A2 # 0 +0x95A9 0xE7A3 # 0 +0x95AA 0xE7A4 # 0 +0x95AB 0xE7A5 # 0 +0x95AC 0xE7A6 # 0 +0x95AD 0xE7A7 # 0 +0x95AE 0xE7A8 # 0 +0x95AF 0xE7A9 # 0 +0x95B0 0xE7AA # 0 +0x95B1 0xE7AB # 0 +0x95B2 0xE7AC # 0 +0x95B3 0xE7AD # 0 +0x95B4 0xE7AE # 0 +0x95B5 0xE7AF # 0 +0x95B6 0xE7B0 # 0 +0x95B7 0xE7B1 # 0 +0x95B8 0xE7B2 # 0 +0x95B9 0xE7B3 # 0 +0x95BA 0xE7B4 # 0 +0x95BB 0xE7B5 # 0 +0x95BC 0xE7B6 # 0 +0x95BD 0xE7B7 # 0 +0x95BE 0xE7B8 # 0 +0x95BF 0xE7B9 # 0 +0x95C0 0xE7BA # 0 +0x95C1 0xE7BB # 0 +0x95C2 0xE7BC # 0 +0x95C3 0xE7BD # 0 +0x95C4 0xE7BE # 0 +0x95C5 0xE7BF # 0 +0x95C6 0xE7C0 # 0 +0x95C7 0xE7C1 # 0 +0x95C8 0xE7C2 # 0 +0x95C9 0xE7C3 # 0 +0x95CA 0xE7C4 # 0 +0x95CB 0xE7C5 # 0 +0x95CC 0xE7C6 # 0 +0x95CD 0xE7C7 # 0 +0x95CE 0xE7C8 # 0 +0x95CF 0xE7C9 # 0 +0x95D0 0xE7CA # 0 +0x95D1 0xE7CB # 0 +0x95D2 0xE7CC # 0 +0x95D3 0xE7CD # 0 +0x95D4 0xE7CE # 0 +0x95D5 0xE7CF # 0 +0x95D6 0xE7D0 # 0 +0x95D7 0xE7D1 # 0 +0x95D8 0xE7D2 # 0 +0x95D9 0xE7D3 # 0 +0x95DA 0xE7D4 # 0 +0x95DB 0xE7D5 # 0 +0x95DC 0xE7D6 # 0 +0x95DD 0xE7D7 # 0 +0x95DE 0xE7D8 # 0 +0x95DF 0xE7D9 # 0 +0x95E0 0xE7DA # 0 +0x95E1 0xE7DB # 0 +0x95E2 0xE7DC # 0 +0x95E3 0xE7DD # 0 +0x95E4 0xE7DE # 0 +0x95E5 0xE7DF # 0 +0x95E6 0xE7E0 # 0 +0x95E7 0xE7E1 # 0 +0x95E8 0xE7E2 # 0 +0x95E9 0xE7E3 # 0 +0x95EA 0xE7E4 # 0 +0x95EB 0xE7E5 # 0 +0x95EC 0xE7E6 # 0 +0x95ED 0xE7E7 # 0 +0x95EE 0xE7E8 # 0 +0x95EF 0xE7E9 # 0 +0x95F0 0xE7EA # 0 +0x95F1 0xE7EB # 0 +0x95F2 0xE7EC # 0 +0x95F3 0xE7ED # 0 +0x95F4 0xE7EE # 0 +0x95F5 0xE7EF # 0 +0x95F6 0xE7F0 # 0 +0x95F7 0xE7F1 # 0 +0x95F8 0xE7F2 # 0 +0x95F9 0xE7F3 # 0 +0x95FA 0xE7F4 # 0 +0x95FB 0xE7F5 # 0 +0x95FC 0xE7F6 # 0 +0x95FD 0xE7F7 # 0 +0x95FE 0xE7F8 # 0 +0x9640 0xE7F9 # 0 +0x9641 0xE7FA # 0 +0x9642 0xE7FB # 0 +0x9643 0xE7FC # 0 +0x9644 0xE7FD # 0 +0x9645 0xE7FE # 0 +0x9646 0xE7FF # 0 +0x9647 0xE800 # 0 +0x9648 0xE801 # 0 +0x9649 0xE802 # 0 +0x964A 0xE803 # 0 +0x964B 0xE804 # 0 +0x964C 0xE805 # 0 +0x964D 0xE806 # 0 +0x964E 0xE807 # 0 +0x964F 0xE808 # 0 +0x9650 0xE809 # 0 +0x9651 0xE80A # 0 +0x9652 0xE80B # 0 +0x9653 0xE80C # 0 +0x9654 0xE80D # 0 +0x9655 0xE80E # 0 +0x9656 0xE80F # 0 +0x9657 0xE810 # 0 +0x9658 0xE811 # 0 +0x9659 0xE812 # 0 +0x965A 0xE813 # 0 +0x965B 0xE814 # 0 +0x965C 0xE815 # 0 +0x965D 0xE816 # 0 +0x965E 0xE817 # 0 +0x965F 0xE818 # 0 +0x9660 0xE819 # 0 +0x9661 0xE81A # 0 +0x9662 0xE81B # 0 +0x9663 0xE81C # 0 +0x9664 0xE81D # 0 +0x9665 0xE81E # 0 +0x9666 0xE81F # 0 +0x9667 0xE820 # 0 +0x9668 0xE821 # 0 +0x9669 0xE822 # 0 +0x966A 0xE823 # 0 +0x966B 0xE824 # 0 +0x966C 0xE825 # 0 +0x966D 0xE826 # 0 +0x966E 0xE827 # 0 +0x966F 0xE828 # 0 +0x9670 0xE829 # 0 +0x9671 0xE82A # 0 +0x9672 0xE82B # 0 +0x9673 0xE82C # 0 +0x9674 0xE82D # 0 +0x9675 0xE82E # 0 +0x9676 0xE82F # 0 +0x9677 0xE830 # 0 +0x9678 0xE831 # 0 +0x9679 0xE832 # 0 +0x967A 0xE833 # 0 +0x967B 0xE834 # 0 +0x967C 0xE835 # 0 +0x967D 0xE836 # 0 +0x967E 0xE837 # 0 +0x96A1 0xE838 # 0 +0x96A2 0xE839 # 0 +0x96A3 0xE83A # 0 +0x96A4 0xE83B # 0 +0x96A5 0xE83C # 0 +0x96A6 0xE83D # 0 +0x96A7 0xE83E # 0 +0x96A8 0xE83F # 0 +0x96A9 0xE840 # 0 +0x96AA 0xE841 # 0 +0x96AB 0xE842 # 0 +0x96AC 0xE843 # 0 +0x96AD 0xE844 # 0 +0x96AE 0xE845 # 0 +0x96AF 0xE846 # 0 +0x96B0 0xE847 # 0 +0x96B1 0xE848 # 0 +0x96B2 0xE849 # 0 +0x96B3 0xE84A # 0 +0x96B4 0xE84B # 0 +0x96B5 0xE84C # 0 +0x96B6 0xE84D # 0 +0x96B7 0xE84E # 0 +0x96B8 0xE84F # 0 +0x96B9 0xE850 # 0 +0x96BA 0xE851 # 0 +0x96BB 0xE852 # 0 +0x96BC 0xE853 # 0 +0x96BD 0xE854 # 0 +0x96BE 0xE855 # 0 +0x96BF 0xE856 # 0 +0x96C0 0xE857 # 0 +0x96C1 0xE858 # 0 +0x96C2 0xE859 # 0 +0x96C3 0xE85A # 0 +0x96C4 0xE85B # 0 +0x96C5 0xE85C # 0 +0x96C6 0xE85D # 0 +0x96C7 0xE85E # 0 +0x96C8 0xE85F # 0 +0x96C9 0xE860 # 0 +0x96CA 0xE861 # 0 +0x96CB 0xE862 # 0 +0x96CC 0xE863 # 0 +0x96CD 0xE864 # 0 +0x96CE 0xE865 # 0 +0x96CF 0xE866 # 0 +0x96D0 0xE867 # 0 +0x96D1 0xE868 # 0 +0x96D2 0xE869 # 0 +0x96D3 0xE86A # 0 +0x96D4 0xE86B # 0 +0x96D5 0xE86C # 0 +0x96D6 0xE86D # 0 +0x96D7 0xE86E # 0 +0x96D8 0xE86F # 0 +0x96D9 0xE870 # 0 +0x96DA 0xE871 # 0 +0x96DB 0xE872 # 0 +0x96DC 0xE873 # 0 +0x96DD 0xE874 # 0 +0x96DE 0xE875 # 0 +0x96DF 0xE876 # 0 +0x96E0 0xE877 # 0 +0x96E1 0xE878 # 0 +0x96E2 0xE879 # 0 +0x96E3 0xE87A # 0 +0x96E4 0xE87B # 0 +0x96E5 0xE87C # 0 +0x96E6 0xE87D # 0 +0x96E7 0xE87E # 0 +0x96E8 0xE87F # 0 +0x96E9 0xE880 # 0 +0x96EA 0xE881 # 0 +0x96EB 0xE882 # 0 +0x96EC 0xE883 # 0 +0x96ED 0xE884 # 0 +0x96EE 0xE885 # 0 +0x96EF 0xE886 # 0 +0x96F0 0xE887 # 0 +0x96F1 0xE888 # 0 +0x96F2 0xE889 # 0 +0x96F3 0xE88A # 0 +0x96F4 0xE88B # 0 +0x96F5 0xE88C # 0 +0x96F6 0xE88D # 0 +0x96F7 0xE88E # 0 +0x96F8 0xE88F # 0 +0x96F9 0xE890 # 0 +0x96FA 0xE891 # 0 +0x96FB 0xE892 # 0 +0x96FC 0xE893 # 0 +0x96FD 0xE894 # 0 +0x96FE 0xE895 # 0 +0x9740 0xE896 # 0 +0x9741 0xE897 # 0 +0x9742 0xE898 # 0 +0x9743 0xE899 # 0 +0x9744 0xE89A # 0 +0x9745 0xE89B # 0 +0x9746 0xE89C # 0 +0x9747 0xE89D # 0 +0x9748 0xE89E # 0 +0x9749 0xE89F # 0 +0x974A 0xE8A0 # 0 +0x974B 0xE8A1 # 0 +0x974C 0xE8A2 # 0 +0x974D 0xE8A3 # 0 +0x974E 0xE8A4 # 0 +0x974F 0xE8A5 # 0 +0x9750 0xE8A6 # 0 +0x9751 0xE8A7 # 0 +0x9752 0xE8A8 # 0 +0x9753 0xE8A9 # 0 +0x9754 0xE8AA # 0 +0x9755 0xE8AB # 0 +0x9756 0xE8AC # 0 +0x9757 0xE8AD # 0 +0x9758 0xE8AE # 0 +0x9759 0xE8AF # 0 +0x975A 0xE8B0 # 0 +0x975B 0xE8B1 # 0 +0x975C 0xE8B2 # 0 +0x975D 0xE8B3 # 0 +0x975E 0xE8B4 # 0 +0x975F 0xE8B5 # 0 +0x9760 0xE8B6 # 0 +0x9761 0xE8B7 # 0 +0x9762 0xE8B8 # 0 +0x9763 0xE8B9 # 0 +0x9764 0xE8BA # 0 +0x9765 0xE8BB # 0 +0x9766 0xE8BC # 0 +0x9767 0xE8BD # 0 +0x9768 0xE8BE # 0 +0x9769 0xE8BF # 0 +0x976A 0xE8C0 # 0 +0x976B 0xE8C1 # 0 +0x976C 0xE8C2 # 0 +0x976D 0xE8C3 # 0 +0x976E 0xE8C4 # 0 +0x976F 0xE8C5 # 0 +0x9770 0xE8C6 # 0 +0x9771 0xE8C7 # 0 +0x9772 0xE8C8 # 0 +0x9773 0xE8C9 # 0 +0x9774 0xE8CA # 0 +0x9775 0xE8CB # 0 +0x9776 0xE8CC # 0 +0x9777 0xE8CD # 0 +0x9778 0xE8CE # 0 +0x9779 0xE8CF # 0 +0x977A 0xE8D0 # 0 +0x977B 0xE8D1 # 0 +0x977C 0xE8D2 # 0 +0x977D 0xE8D3 # 0 +0x977E 0xE8D4 # 0 +0x97A1 0xE8D5 # 0 +0x97A2 0xE8D6 # 0 +0x97A3 0xE8D7 # 0 +0x97A4 0xE8D8 # 0 +0x97A5 0xE8D9 # 0 +0x97A6 0xE8DA # 0 +0x97A7 0xE8DB # 0 +0x97A8 0xE8DC # 0 +0x97A9 0xE8DD # 0 +0x97AA 0xE8DE # 0 +0x97AB 0xE8DF # 0 +0x97AC 0xE8E0 # 0 +0x97AD 0xE8E1 # 0 +0x97AE 0xE8E2 # 0 +0x97AF 0xE8E3 # 0 +0x97B0 0xE8E4 # 0 +0x97B1 0xE8E5 # 0 +0x97B2 0xE8E6 # 0 +0x97B3 0xE8E7 # 0 +0x97B4 0xE8E8 # 0 +0x97B5 0xE8E9 # 0 +0x97B6 0xE8EA # 0 +0x97B7 0xE8EB # 0 +0x97B8 0xE8EC # 0 +0x97B9 0xE8ED # 0 +0x97BA 0xE8EE # 0 +0x97BB 0xE8EF # 0 +0x97BC 0xE8F0 # 0 +0x97BD 0xE8F1 # 0 +0x97BE 0xE8F2 # 0 +0x97BF 0xE8F3 # 0 +0x97C0 0xE8F4 # 0 +0x97C1 0xE8F5 # 0 +0x97C2 0xE8F6 # 0 +0x97C3 0xE8F7 # 0 +0x97C4 0xE8F8 # 0 +0x97C5 0xE8F9 # 0 +0x97C6 0xE8FA # 0 +0x97C7 0xE8FB # 0 +0x97C8 0xE8FC # 0 +0x97C9 0xE8FD # 0 +0x97CA 0xE8FE # 0 +0x97CB 0xE8FF # 0 +0x97CC 0xE900 # 0 +0x97CD 0xE901 # 0 +0x97CE 0xE902 # 0 +0x97CF 0xE903 # 0 +0x97D0 0xE904 # 0 +0x97D1 0xE905 # 0 +0x97D2 0xE906 # 0 +0x97D3 0xE907 # 0 +0x97D4 0xE908 # 0 +0x97D5 0xE909 # 0 +0x97D6 0xE90A # 0 +0x97D7 0xE90B # 0 +0x97D8 0xE90C # 0 +0x97D9 0xE90D # 0 +0x97DA 0xE90E # 0 +0x97DB 0xE90F # 0 +0x97DC 0xE910 # 0 +0x97DD 0xE911 # 0 +0x97DE 0xE912 # 0 +0x97DF 0xE913 # 0 +0x97E0 0xE914 # 0 +0x97E1 0xE915 # 0 +0x97E2 0xE916 # 0 +0x97E3 0xE917 # 0 +0x97E4 0xE918 # 0 +0x97E5 0xE919 # 0 +0x97E6 0xE91A # 0 +0x97E7 0xE91B # 0 +0x97E8 0xE91C # 0 +0x97E9 0xE91D # 0 +0x97EA 0xE91E # 0 +0x97EB 0xE91F # 0 +0x97EC 0xE920 # 0 +0x97ED 0xE921 # 0 +0x97EE 0xE922 # 0 +0x97EF 0xE923 # 0 +0x97F0 0xE924 # 0 +0x97F1 0xE925 # 0 +0x97F2 0xE926 # 0 +0x97F3 0xE927 # 0 +0x97F4 0xE928 # 0 +0x97F5 0xE929 # 0 +0x97F6 0xE92A # 0 +0x97F7 0xE92B # 0 +0x97F8 0xE92C # 0 +0x97F9 0xE92D # 0 +0x97FA 0xE92E # 0 +0x97FB 0xE92F # 0 +0x97FC 0xE930 # 0 +0x97FD 0xE931 # 0 +0x97FE 0xE932 # 0 +0x9840 0xE933 # 0 +0x9841 0xE934 # 0 +0x9842 0xE935 # 0 +0x9843 0xE936 # 0 +0x9844 0xE937 # 0 +0x9845 0xE938 # 0 +0x9846 0xE939 # 0 +0x9847 0xE93A # 0 +0x9848 0xE93B # 0 +0x9849 0xE93C # 0 +0x984A 0xE93D # 0 +0x984B 0xE93E # 0 +0x984C 0xE93F # 0 +0x984D 0xE940 # 0 +0x984E 0xE941 # 0 +0x984F 0xE942 # 0 +0x9850 0xE943 # 0 +0x9851 0xE944 # 0 +0x9852 0xE945 # 0 +0x9853 0xE946 # 0 +0x9854 0xE947 # 0 +0x9855 0xE948 # 0 +0x9856 0xE949 # 0 +0x9857 0xE94A # 0 +0x9858 0xE94B # 0 +0x9859 0xE94C # 0 +0x985A 0xE94D # 0 +0x985B 0xE94E # 0 +0x985C 0xE94F # 0 +0x985D 0xE950 # 0 +0x985E 0xE951 # 0 +0x985F 0xE952 # 0 +0x9860 0xE953 # 0 +0x9861 0xE954 # 0 +0x9862 0xE955 # 0 +0x9863 0xE956 # 0 +0x9864 0xE957 # 0 +0x9865 0xE958 # 0 +0x9866 0xE959 # 0 +0x9867 0xE95A # 0 +0x9868 0xE95B # 0 +0x9869 0xE95C # 0 +0x986A 0xE95D # 0 +0x986B 0xE95E # 0 +0x986C 0xE95F # 0 +0x986D 0xE960 # 0 +0x986E 0xE961 # 0 +0x986F 0xE962 # 0 +0x9870 0xE963 # 0 +0x9871 0xE964 # 0 +0x9872 0xE965 # 0 +0x9873 0xE966 # 0 +0x9874 0xE967 # 0 +0x9875 0xE968 # 0 +0x9876 0xE969 # 0 +0x9877 0xE96A # 0 +0x9878 0xE96B # 0 +0x9879 0xE96C # 0 +0x987A 0xE96D # 0 +0x987B 0xE96E # 0 +0x987C 0xE96F # 0 +0x987D 0xE970 # 0 +0x987E 0xE971 # 0 +0x98A1 0xE972 # 0 +0x98A2 0xE973 # 0 +0x98A3 0xE974 # 0 +0x98A4 0xE975 # 0 +0x98A5 0xE976 # 0 +0x98A6 0xE977 # 0 +0x98A7 0xE978 # 0 +0x98A8 0xE979 # 0 +0x98A9 0xE97A # 0 +0x98AA 0xE97B # 0 +0x98AB 0xE97C # 0 +0x98AC 0xE97D # 0 +0x98AD 0xE97E # 0 +0x98AE 0xE97F # 0 +0x98AF 0xE980 # 0 +0x98B0 0xE981 # 0 +0x98B1 0xE982 # 0 +0x98B2 0xE983 # 0 +0x98B3 0xE984 # 0 +0x98B4 0xE985 # 0 +0x98B5 0xE986 # 0 +0x98B6 0xE987 # 0 +0x98B7 0xE988 # 0 +0x98B8 0xE989 # 0 +0x98B9 0xE98A # 0 +0x98BA 0xE98B # 0 +0x98BB 0xE98C # 0 +0x98BC 0xE98D # 0 +0x98BD 0xE98E # 0 +0x98BE 0xE98F # 0 +0x98BF 0xE990 # 0 +0x98C0 0xE991 # 0 +0x98C1 0xE992 # 0 +0x98C2 0xE993 # 0 +0x98C3 0xE994 # 0 +0x98C4 0xE995 # 0 +0x98C5 0xE996 # 0 +0x98C6 0xE997 # 0 +0x98C7 0xE998 # 0 +0x98C8 0xE999 # 0 +0x98C9 0xE99A # 0 +0x98CA 0xE99B # 0 +0x98CB 0xE99C # 0 +0x98CC 0xE99D # 0 +0x98CD 0xE99E # 0 +0x98CE 0xE99F # 0 +0x98CF 0xE9A0 # 0 +0x98D0 0xE9A1 # 0 +0x98D1 0xE9A2 # 0 +0x98D2 0xE9A3 # 0 +0x98D3 0xE9A4 # 0 +0x98D4 0xE9A5 # 0 +0x98D5 0xE9A6 # 0 +0x98D6 0xE9A7 # 0 +0x98D7 0xE9A8 # 0 +0x98D8 0xE9A9 # 0 +0x98D9 0xE9AA # 0 +0x98DA 0xE9AB # 0 +0x98DB 0xE9AC # 0 +0x98DC 0xE9AD # 0 +0x98DD 0xE9AE # 0 +0x98DE 0xE9AF # 0 +0x98DF 0xE9B0 # 0 +0x98E0 0xE9B1 # 0 +0x98E1 0xE9B2 # 0 +0x98E2 0xE9B3 # 0 +0x98E3 0xE9B4 # 0 +0x98E4 0xE9B5 # 0 +0x98E5 0xE9B6 # 0 +0x98E6 0xE9B7 # 0 +0x98E7 0xE9B8 # 0 +0x98E8 0xE9B9 # 0 +0x98E9 0xE9BA # 0 +0x98EA 0xE9BB # 0 +0x98EB 0xE9BC # 0 +0x98EC 0xE9BD # 0 +0x98ED 0xE9BE # 0 +0x98EE 0xE9BF # 0 +0x98EF 0xE9C0 # 0 +0x98F0 0xE9C1 # 0 +0x98F1 0xE9C2 # 0 +0x98F2 0xE9C3 # 0 +0x98F3 0xE9C4 # 0 +0x98F4 0xE9C5 # 0 +0x98F5 0xE9C6 # 0 +0x98F6 0xE9C7 # 0 +0x98F7 0xE9C8 # 0 +0x98F8 0xE9C9 # 0 +0x98F9 0xE9CA # 0 +0x98FA 0xE9CB # 0 +0x98FB 0xE9CC # 0 +0x98FC 0xE9CD # 0 +0x98FD 0xE9CE # 0 +0x98FE 0xE9CF # 0 +0x9940 0xE9D0 # 0 +0x9941 0xE9D1 # 0 +0x9942 0xE9D2 # 0 +0x9943 0xE9D3 # 0 +0x9944 0xE9D4 # 0 +0x9945 0xE9D5 # 0 +0x9946 0xE9D6 # 0 +0x9947 0xE9D7 # 0 +0x9948 0xE9D8 # 0 +0x9949 0xE9D9 # 0 +0x994A 0xE9DA # 0 +0x994B 0xE9DB # 0 +0x994C 0xE9DC # 0 +0x994D 0xE9DD # 0 +0x994E 0xE9DE # 0 +0x994F 0xE9DF # 0 +0x9950 0xE9E0 # 0 +0x9951 0xE9E1 # 0 +0x9952 0xE9E2 # 0 +0x9953 0xE9E3 # 0 +0x9954 0xE9E4 # 0 +0x9955 0xE9E5 # 0 +0x9956 0xE9E6 # 0 +0x9957 0xE9E7 # 0 +0x9958 0xE9E8 # 0 +0x9959 0xE9E9 # 0 +0x995A 0xE9EA # 0 +0x995B 0xE9EB # 0 +0x995C 0xE9EC # 0 +0x995D 0xE9ED # 0 +0x995E 0xE9EE # 0 +0x995F 0xE9EF # 0 +0x9960 0xE9F0 # 0 +0x9961 0xE9F1 # 0 +0x9962 0xE9F2 # 0 +0x9963 0xE9F3 # 0 +0x9964 0xE9F4 # 0 +0x9965 0xE9F5 # 0 +0x9966 0xE9F6 # 0 +0x9967 0xE9F7 # 0 +0x9968 0xE9F8 # 0 +0x9969 0xE9F9 # 0 +0x996A 0xE9FA # 0 +0x996B 0xE9FB # 0 +0x996C 0xE9FC # 0 +0x996D 0xE9FD # 0 +0x996E 0xE9FE # 0 +0x996F 0xE9FF # 0 +0x9970 0xEA00 # 0 +0x9971 0xEA01 # 0 +0x9972 0xEA02 # 0 +0x9973 0xEA03 # 0 +0x9974 0xEA04 # 0 +0x9975 0xEA05 # 0 +0x9976 0xEA06 # 0 +0x9977 0xEA07 # 0 +0x9978 0xEA08 # 0 +0x9979 0xEA09 # 0 +0x997A 0xEA0A # 0 +0x997B 0xEA0B # 0 +0x997C 0xEA0C # 0 +0x997D 0xEA0D # 0 +0x997E 0xEA0E # 0 +0x99A1 0xEA0F # 0 +0x99A2 0xEA10 # 0 +0x99A3 0xEA11 # 0 +0x99A4 0xEA12 # 0 +0x99A5 0xEA13 # 0 +0x99A6 0xEA14 # 0 +0x99A7 0xEA15 # 0 +0x99A8 0xEA16 # 0 +0x99A9 0xEA17 # 0 +0x99AA 0xEA18 # 0 +0x99AB 0xEA19 # 0 +0x99AC 0xEA1A # 0 +0x99AD 0xEA1B # 0 +0x99AE 0xEA1C # 0 +0x99AF 0xEA1D # 0 +0x99B0 0xEA1E # 0 +0x99B1 0xEA1F # 0 +0x99B2 0xEA20 # 0 +0x99B3 0xEA21 # 0 +0x99B4 0xEA22 # 0 +0x99B5 0xEA23 # 0 +0x99B6 0xEA24 # 0 +0x99B7 0xEA25 # 0 +0x99B8 0xEA26 # 0 +0x99B9 0xEA27 # 0 +0x99BA 0xEA28 # 0 +0x99BB 0xEA29 # 0 +0x99BC 0xEA2A # 0 +0x99BD 0xEA2B # 0 +0x99BE 0xEA2C # 0 +0x99BF 0xEA2D # 0 +0x99C0 0xEA2E # 0 +0x99C1 0xEA2F # 0 +0x99C2 0xEA30 # 0 +0x99C3 0xEA31 # 0 +0x99C4 0xEA32 # 0 +0x99C5 0xEA33 # 0 +0x99C6 0xEA34 # 0 +0x99C7 0xEA35 # 0 +0x99C8 0xEA36 # 0 +0x99C9 0xEA37 # 0 +0x99CA 0xEA38 # 0 +0x99CB 0xEA39 # 0 +0x99CC 0xEA3A # 0 +0x99CD 0xEA3B # 0 +0x99CE 0xEA3C # 0 +0x99CF 0xEA3D # 0 +0x99D0 0xEA3E # 0 +0x99D1 0xEA3F # 0 +0x99D2 0xEA40 # 0 +0x99D3 0xEA41 # 0 +0x99D4 0xEA42 # 0 +0x99D5 0xEA43 # 0 +0x99D6 0xEA44 # 0 +0x99D7 0xEA45 # 0 +0x99D8 0xEA46 # 0 +0x99D9 0xEA47 # 0 +0x99DA 0xEA48 # 0 +0x99DB 0xEA49 # 0 +0x99DC 0xEA4A # 0 +0x99DD 0xEA4B # 0 +0x99DE 0xEA4C # 0 +0x99DF 0xEA4D # 0 +0x99E0 0xEA4E # 0 +0x99E1 0xEA4F # 0 +0x99E2 0xEA50 # 0 +0x99E3 0xEA51 # 0 +0x99E4 0xEA52 # 0 +0x99E5 0xEA53 # 0 +0x99E6 0xEA54 # 0 +0x99E7 0xEA55 # 0 +0x99E8 0xEA56 # 0 +0x99E9 0xEA57 # 0 +0x99EA 0xEA58 # 0 +0x99EB 0xEA59 # 0 +0x99EC 0xEA5A # 0 +0x99ED 0xEA5B # 0 +0x99EE 0xEA5C # 0 +0x99EF 0xEA5D # 0 +0x99F0 0xEA5E # 0 +0x99F1 0xEA5F # 0 +0x99F2 0xEA60 # 0 +0x99F3 0xEA61 # 0 +0x99F4 0xEA62 # 0 +0x99F5 0xEA63 # 0 +0x99F6 0xEA64 # 0 +0x99F7 0xEA65 # 0 +0x99F8 0xEA66 # 0 +0x99F9 0xEA67 # 0 +0x99FA 0xEA68 # 0 +0x99FB 0xEA69 # 0 +0x99FC 0xEA6A # 0 +0x99FD 0xEA6B # 0 +0x99FE 0xEA6C # 0 +0x9A40 0xEA6D # 0 +0x9A41 0xEA6E # 0 +0x9A42 0xEA6F # 0 +0x9A43 0xEA70 # 0 +0x9A44 0xEA71 # 0 +0x9A45 0xEA72 # 0 +0x9A46 0xEA73 # 0 +0x9A47 0xEA74 # 0 +0x9A48 0xEA75 # 0 +0x9A49 0xEA76 # 0 +0x9A4A 0xEA77 # 0 +0x9A4B 0xEA78 # 0 +0x9A4C 0xEA79 # 0 +0x9A4D 0xEA7A # 0 +0x9A4E 0xEA7B # 0 +0x9A4F 0xEA7C # 0 +0x9A50 0xEA7D # 0 +0x9A51 0xEA7E # 0 +0x9A52 0xEA7F # 0 +0x9A53 0xEA80 # 0 +0x9A54 0xEA81 # 0 +0x9A55 0xEA82 # 0 +0x9A56 0xEA83 # 0 +0x9A57 0xEA84 # 0 +0x9A58 0xEA85 # 0 +0x9A59 0xEA86 # 0 +0x9A5A 0xEA87 # 0 +0x9A5B 0xEA88 # 0 +0x9A5C 0xEA89 # 0 +0x9A5D 0xEA8A # 0 +0x9A5E 0xEA8B # 0 +0x9A5F 0xEA8C # 0 +0x9A60 0xEA8D # 0 +0x9A61 0xEA8E # 0 +0x9A62 0xEA8F # 0 +0x9A63 0xEA90 # 0 +0x9A64 0xEA91 # 0 +0x9A65 0xEA92 # 0 +0x9A66 0xEA93 # 0 +0x9A67 0xEA94 # 0 +0x9A68 0xEA95 # 0 +0x9A69 0xEA96 # 0 +0x9A6A 0xEA97 # 0 +0x9A6B 0xEA98 # 0 +0x9A6C 0xEA99 # 0 +0x9A6D 0xEA9A # 0 +0x9A6E 0xEA9B # 0 +0x9A6F 0xEA9C # 0 +0x9A70 0xEA9D # 0 +0x9A71 0xEA9E # 0 +0x9A72 0xEA9F # 0 +0x9A73 0xEAA0 # 0 +0x9A74 0xEAA1 # 0 +0x9A75 0xEAA2 # 0 +0x9A76 0xEAA3 # 0 +0x9A77 0xEAA4 # 0 +0x9A78 0xEAA5 # 0 +0x9A79 0xEAA6 # 0 +0x9A7A 0xEAA7 # 0 +0x9A7B 0xEAA8 # 0 +0x9A7C 0xEAA9 # 0 +0x9A7D 0xEAAA # 0 +0x9A7E 0xEAAB # 0 +0x9AA1 0xEAAC # 0 +0x9AA2 0xEAAD # 0 +0x9AA3 0xEAAE # 0 +0x9AA4 0xEAAF # 0 +0x9AA5 0xEAB0 # 0 +0x9AA6 0xEAB1 # 0 +0x9AA7 0xEAB2 # 0 +0x9AA8 0xEAB3 # 0 +0x9AA9 0xEAB4 # 0 +0x9AAA 0xEAB5 # 0 +0x9AAB 0xEAB6 # 0 +0x9AAC 0xEAB7 # 0 +0x9AAD 0xEAB8 # 0 +0x9AAE 0xEAB9 # 0 +0x9AAF 0xEABA # 0 +0x9AB0 0xEABB # 0 +0x9AB1 0xEABC # 0 +0x9AB2 0xEABD # 0 +0x9AB3 0xEABE # 0 +0x9AB4 0xEABF # 0 +0x9AB5 0xEAC0 # 0 +0x9AB6 0xEAC1 # 0 +0x9AB7 0xEAC2 # 0 +0x9AB8 0xEAC3 # 0 +0x9AB9 0xEAC4 # 0 +0x9ABA 0xEAC5 # 0 +0x9ABB 0xEAC6 # 0 +0x9ABC 0xEAC7 # 0 +0x9ABD 0xEAC8 # 0 +0x9ABE 0xEAC9 # 0 +0x9ABF 0xEACA # 0 +0x9AC0 0xEACB # 0 +0x9AC1 0xEACC # 0 +0x9AC2 0xEACD # 0 +0x9AC3 0xEACE # 0 +0x9AC4 0xEACF # 0 +0x9AC5 0xEAD0 # 0 +0x9AC6 0xEAD1 # 0 +0x9AC7 0xEAD2 # 0 +0x9AC8 0xEAD3 # 0 +0x9AC9 0xEAD4 # 0 +0x9ACA 0xEAD5 # 0 +0x9ACB 0xEAD6 # 0 +0x9ACC 0xEAD7 # 0 +0x9ACD 0xEAD8 # 0 +0x9ACE 0xEAD9 # 0 +0x9ACF 0xEADA # 0 +0x9AD0 0xEADB # 0 +0x9AD1 0xEADC # 0 +0x9AD2 0xEADD # 0 +0x9AD3 0xEADE # 0 +0x9AD4 0xEADF # 0 +0x9AD5 0xEAE0 # 0 +0x9AD6 0xEAE1 # 0 +0x9AD7 0xEAE2 # 0 +0x9AD8 0xEAE3 # 0 +0x9AD9 0xEAE4 # 0 +0x9ADA 0xEAE5 # 0 +0x9ADB 0xEAE6 # 0 +0x9ADC 0xEAE7 # 0 +0x9ADD 0xEAE8 # 0 +0x9ADE 0xEAE9 # 0 +0x9ADF 0xEAEA # 0 +0x9AE0 0xEAEB # 0 +0x9AE1 0xEAEC # 0 +0x9AE2 0xEAED # 0 +0x9AE3 0xEAEE # 0 +0x9AE4 0xEAEF # 0 +0x9AE5 0xEAF0 # 0 +0x9AE6 0xEAF1 # 0 +0x9AE7 0xEAF2 # 0 +0x9AE8 0xEAF3 # 0 +0x9AE9 0xEAF4 # 0 +0x9AEA 0xEAF5 # 0 +0x9AEB 0xEAF6 # 0 +0x9AEC 0xEAF7 # 0 +0x9AED 0xEAF8 # 0 +0x9AEE 0xEAF9 # 0 +0x9AEF 0xEAFA # 0 +0x9AF0 0xEAFB # 0 +0x9AF1 0xEAFC # 0 +0x9AF2 0xEAFD # 0 +0x9AF3 0xEAFE # 0 +0x9AF4 0xEAFF # 0 +0x9AF5 0xEB00 # 0 +0x9AF6 0xEB01 # 0 +0x9AF7 0xEB02 # 0 +0x9AF8 0xEB03 # 0 +0x9AF9 0xEB04 # 0 +0x9AFA 0xEB05 # 0 +0x9AFB 0xEB06 # 0 +0x9AFC 0xEB07 # 0 +0x9AFD 0xEB08 # 0 +0x9AFE 0xEB09 # 0 +0x9B40 0xEB0A # 0 +0x9B41 0xEB0B # 0 +0x9B42 0xEB0C # 0 +0x9B43 0xEB0D # 0 +0x9B44 0xEB0E # 0 +0x9B45 0xEB0F # 0 +0x9B46 0xEB10 # 0 +0x9B47 0xEB11 # 0 +0x9B48 0xEB12 # 0 +0x9B49 0xEB13 # 0 +0x9B4A 0xEB14 # 0 +0x9B4B 0xEB15 # 0 +0x9B4C 0xEB16 # 0 +0x9B4D 0xEB17 # 0 +0x9B4E 0xEB18 # 0 +0x9B4F 0xEB19 # 0 +0x9B50 0xEB1A # 0 +0x9B51 0xEB1B # 0 +0x9B52 0xEB1C # 0 +0x9B53 0xEB1D # 0 +0x9B54 0xEB1E # 0 +0x9B55 0xEB1F # 0 +0x9B56 0xEB20 # 0 +0x9B57 0xEB21 # 0 +0x9B58 0xEB22 # 0 +0x9B59 0xEB23 # 0 +0x9B5A 0xEB24 # 0 +0x9B5B 0xEB25 # 0 +0x9B5C 0xEB26 # 0 +0x9B5D 0xEB27 # 0 +0x9B5E 0xEB28 # 0 +0x9B5F 0xEB29 # 0 +0x9B60 0xEB2A # 0 +0x9B61 0xEB2B # 0 +0x9B62 0xEB2C # 0 +0x9B63 0xEB2D # 0 +0x9B64 0xEB2E # 0 +0x9B65 0xEB2F # 0 +0x9B66 0xEB30 # 0 +0x9B67 0xEB31 # 0 +0x9B68 0xEB32 # 0 +0x9B69 0xEB33 # 0 +0x9B6A 0xEB34 # 0 +0x9B6B 0xEB35 # 0 +0x9B6C 0xEB36 # 0 +0x9B6D 0xEB37 # 0 +0x9B6E 0xEB38 # 0 +0x9B6F 0xEB39 # 0 +0x9B70 0xEB3A # 0 +0x9B71 0xEB3B # 0 +0x9B72 0xEB3C # 0 +0x9B73 0xEB3D # 0 +0x9B74 0xEB3E # 0 +0x9B75 0xEB3F # 0 +0x9B76 0xEB40 # 0 +0x9B77 0xEB41 # 0 +0x9B78 0xEB42 # 0 +0x9B79 0xEB43 # 0 +0x9B7A 0xEB44 # 0 +0x9B7B 0xEB45 # 0 +0x9B7C 0xEB46 # 0 +0x9B7D 0xEB47 # 0 +0x9B7E 0xEB48 # 0 +0x9BA1 0xEB49 # 0 +0x9BA2 0xEB4A # 0 +0x9BA3 0xEB4B # 0 +0x9BA4 0xEB4C # 0 +0x9BA5 0xEB4D # 0 +0x9BA6 0xEB4E # 0 +0x9BA7 0xEB4F # 0 +0x9BA8 0xEB50 # 0 +0x9BA9 0xEB51 # 0 +0x9BAA 0xEB52 # 0 +0x9BAB 0xEB53 # 0 +0x9BAC 0xEB54 # 0 +0x9BAD 0xEB55 # 0 +0x9BAE 0xEB56 # 0 +0x9BAF 0xEB57 # 0 +0x9BB0 0xEB58 # 0 +0x9BB1 0xEB59 # 0 +0x9BB2 0xEB5A # 0 +0x9BB3 0xEB5B # 0 +0x9BB4 0xEB5C # 0 +0x9BB5 0xEB5D # 0 +0x9BB6 0xEB5E # 0 +0x9BB7 0xEB5F # 0 +0x9BB8 0xEB60 # 0 +0x9BB9 0xEB61 # 0 +0x9BBA 0xEB62 # 0 +0x9BBB 0xEB63 # 0 +0x9BBC 0xEB64 # 0 +0x9BBD 0xEB65 # 0 +0x9BBE 0xEB66 # 0 +0x9BBF 0xEB67 # 0 +0x9BC0 0xEB68 # 0 +0x9BC1 0xEB69 # 0 +0x9BC2 0xEB6A # 0 +0x9BC3 0xEB6B # 0 +0x9BC4 0xEB6C # 0 +0x9BC5 0xEB6D # 0 +0x9BC6 0xEB6E # 0 +0x9BC7 0xEB6F # 0 +0x9BC8 0xEB70 # 0 +0x9BC9 0xEB71 # 0 +0x9BCA 0xEB72 # 0 +0x9BCB 0xEB73 # 0 +0x9BCC 0xEB74 # 0 +0x9BCD 0xEB75 # 0 +0x9BCE 0xEB76 # 0 +0x9BCF 0xEB77 # 0 +0x9BD0 0xEB78 # 0 +0x9BD1 0xEB79 # 0 +0x9BD2 0xEB7A # 0 +0x9BD3 0xEB7B # 0 +0x9BD4 0xEB7C # 0 +0x9BD5 0xEB7D # 0 +0x9BD6 0xEB7E # 0 +0x9BD7 0xEB7F # 0 +0x9BD8 0xEB80 # 0 +0x9BD9 0xEB81 # 0 +0x9BDA 0xEB82 # 0 +0x9BDB 0xEB83 # 0 +0x9BDC 0xEB84 # 0 +0x9BDD 0xEB85 # 0 +0x9BDE 0xEB86 # 0 +0x9BDF 0xEB87 # 0 +0x9BE0 0xEB88 # 0 +0x9BE1 0xEB89 # 0 +0x9BE2 0xEB8A # 0 +0x9BE3 0xEB8B # 0 +0x9BE4 0xEB8C # 0 +0x9BE5 0xEB8D # 0 +0x9BE6 0xEB8E # 0 +0x9BE7 0xEB8F # 0 +0x9BE8 0xEB90 # 0 +0x9BE9 0xEB91 # 0 +0x9BEA 0xEB92 # 0 +0x9BEB 0xEB93 # 0 +0x9BEC 0xEB94 # 0 +0x9BED 0xEB95 # 0 +0x9BEE 0xEB96 # 0 +0x9BEF 0xEB97 # 0 +0x9BF0 0xEB98 # 0 +0x9BF1 0xEB99 # 0 +0x9BF2 0xEB9A # 0 +0x9BF3 0xEB9B # 0 +0x9BF4 0xEB9C # 0 +0x9BF5 0xEB9D # 0 +0x9BF6 0xEB9E # 0 +0x9BF7 0xEB9F # 0 +0x9BF8 0xEBA0 # 0 +0x9BF9 0xEBA1 # 0 +0x9BFA 0xEBA2 # 0 +0x9BFB 0xEBA3 # 0 +0x9BFC 0xEBA4 # 0 +0x9BFD 0xEBA5 # 0 +0x9BFE 0xEBA6 # 0 +0x9C40 0xEBA7 # 0 +0x9C41 0xEBA8 # 0 +0x9C42 0xEBA9 # 0 +0x9C43 0xEBAA # 0 +0x9C44 0xEBAB # 0 +0x9C45 0xEBAC # 0 +0x9C46 0xEBAD # 0 +0x9C47 0xEBAE # 0 +0x9C48 0xEBAF # 0 +0x9C49 0xEBB0 # 0 +0x9C4A 0xEBB1 # 0 +0x9C4B 0xEBB2 # 0 +0x9C4C 0xEBB3 # 0 +0x9C4D 0xEBB4 # 0 +0x9C4E 0xEBB5 # 0 +0x9C4F 0xEBB6 # 0 +0x9C50 0xEBB7 # 0 +0x9C51 0xEBB8 # 0 +0x9C52 0xEBB9 # 0 +0x9C53 0xEBBA # 0 +0x9C54 0xEBBB # 0 +0x9C55 0xEBBC # 0 +0x9C56 0xEBBD # 0 +0x9C57 0xEBBE # 0 +0x9C58 0xEBBF # 0 +0x9C59 0xEBC0 # 0 +0x9C5A 0xEBC1 # 0 +0x9C5B 0xEBC2 # 0 +0x9C5C 0xEBC3 # 0 +0x9C5D 0xEBC4 # 0 +0x9C5E 0xEBC5 # 0 +0x9C5F 0xEBC6 # 0 +0x9C60 0xEBC7 # 0 +0x9C61 0xEBC8 # 0 +0x9C62 0xEBC9 # 0 +0x9C63 0xEBCA # 0 +0x9C64 0xEBCB # 0 +0x9C65 0xEBCC # 0 +0x9C66 0xEBCD # 0 +0x9C67 0xEBCE # 0 +0x9C68 0xEBCF # 0 +0x9C69 0xEBD0 # 0 +0x9C6A 0xEBD1 # 0 +0x9C6B 0xEBD2 # 0 +0x9C6C 0xEBD3 # 0 +0x9C6D 0xEBD4 # 0 +0x9C6E 0xEBD5 # 0 +0x9C6F 0xEBD6 # 0 +0x9C70 0xEBD7 # 0 +0x9C71 0xEBD8 # 0 +0x9C72 0xEBD9 # 0 +0x9C73 0xEBDA # 0 +0x9C74 0xEBDB # 0 +0x9C75 0xEBDC # 0 +0x9C76 0xEBDD # 0 +0x9C77 0xEBDE # 0 +0x9C78 0xEBDF # 0 +0x9C79 0xEBE0 # 0 +0x9C7A 0xEBE1 # 0 +0x9C7B 0xEBE2 # 0 +0x9C7C 0xEBE3 # 0 +0x9C7D 0xEBE4 # 0 +0x9C7E 0xEBE5 # 0 +0x9CA1 0xEBE6 # 0 +0x9CA2 0xEBE7 # 0 +0x9CA3 0xEBE8 # 0 +0x9CA4 0xEBE9 # 0 +0x9CA5 0xEBEA # 0 +0x9CA6 0xEBEB # 0 +0x9CA7 0xEBEC # 0 +0x9CA8 0xEBED # 0 +0x9CA9 0xEBEE # 0 +0x9CAA 0xEBEF # 0 +0x9CAB 0xEBF0 # 0 +0x9CAC 0xEBF1 # 0 +0x9CAD 0xEBF2 # 0 +0x9CAE 0xEBF3 # 0 +0x9CAF 0xEBF4 # 0 +0x9CB0 0xEBF5 # 0 +0x9CB1 0xEBF6 # 0 +0x9CB2 0xEBF7 # 0 +0x9CB3 0xEBF8 # 0 +0x9CB4 0xEBF9 # 0 +0x9CB5 0xEBFA # 0 +0x9CB6 0xEBFB # 0 +0x9CB7 0xEBFC # 0 +0x9CB8 0xEBFD # 0 +0x9CB9 0xEBFE # 0 +0x9CBA 0xEBFF # 0 +0x9CBB 0xEC00 # 0 +0x9CBC 0xEC01 # 0 +0x9CBD 0xEC02 # 0 +0x9CBE 0xEC03 # 0 +0x9CBF 0xEC04 # 0 +0x9CC0 0xEC05 # 0 +0x9CC1 0xEC06 # 0 +0x9CC2 0xEC07 # 0 +0x9CC3 0xEC08 # 0 +0x9CC4 0xEC09 # 0 +0x9CC5 0xEC0A # 0 +0x9CC6 0xEC0B # 0 +0x9CC7 0xEC0C # 0 +0x9CC8 0xEC0D # 0 +0x9CC9 0xEC0E # 0 +0x9CCA 0xEC0F # 0 +0x9CCB 0xEC10 # 0 +0x9CCC 0xEC11 # 0 +0x9CCD 0xEC12 # 0 +0x9CCE 0xEC13 # 0 +0x9CCF 0xEC14 # 0 +0x9CD0 0xEC15 # 0 +0x9CD1 0xEC16 # 0 +0x9CD2 0xEC17 # 0 +0x9CD3 0xEC18 # 0 +0x9CD4 0xEC19 # 0 +0x9CD5 0xEC1A # 0 +0x9CD6 0xEC1B # 0 +0x9CD7 0xEC1C # 0 +0x9CD8 0xEC1D # 0 +0x9CD9 0xEC1E # 0 +0x9CDA 0xEC1F # 0 +0x9CDB 0xEC20 # 0 +0x9CDC 0xEC21 # 0 +0x9CDD 0xEC22 # 0 +0x9CDE 0xEC23 # 0 +0x9CDF 0xEC24 # 0 +0x9CE0 0xEC25 # 0 +0x9CE1 0xEC26 # 0 +0x9CE2 0xEC27 # 0 +0x9CE3 0xEC28 # 0 +0x9CE4 0xEC29 # 0 +0x9CE5 0xEC2A # 0 +0x9CE6 0xEC2B # 0 +0x9CE7 0xEC2C # 0 +0x9CE8 0xEC2D # 0 +0x9CE9 0xEC2E # 0 +0x9CEA 0xEC2F # 0 +0x9CEB 0xEC30 # 0 +0x9CEC 0xEC31 # 0 +0x9CED 0xEC32 # 0 +0x9CEE 0xEC33 # 0 +0x9CEF 0xEC34 # 0 +0x9CF0 0xEC35 # 0 +0x9CF1 0xEC36 # 0 +0x9CF2 0xEC37 # 0 +0x9CF3 0xEC38 # 0 +0x9CF4 0xEC39 # 0 +0x9CF5 0xEC3A # 0 +0x9CF6 0xEC3B # 0 +0x9CF7 0xEC3C # 0 +0x9CF8 0xEC3D # 0 +0x9CF9 0xEC3E # 0 +0x9CFA 0xEC3F # 0 +0x9CFB 0xEC40 # 0 +0x9CFC 0xEC41 # 0 +0x9CFD 0xEC42 # 0 +0x9CFE 0xEC43 # 0 +0x9D40 0xEC44 # 0 +0x9D41 0xEC45 # 0 +0x9D42 0xEC46 # 0 +0x9D43 0xEC47 # 0 +0x9D44 0xEC48 # 0 +0x9D45 0xEC49 # 0 +0x9D46 0xEC4A # 0 +0x9D47 0xEC4B # 0 +0x9D48 0xEC4C # 0 +0x9D49 0xEC4D # 0 +0x9D4A 0xEC4E # 0 +0x9D4B 0xEC4F # 0 +0x9D4C 0xEC50 # 0 +0x9D4D 0xEC51 # 0 +0x9D4E 0xEC52 # 0 +0x9D4F 0xEC53 # 0 +0x9D50 0xEC54 # 0 +0x9D51 0xEC55 # 0 +0x9D52 0xEC56 # 0 +0x9D53 0xEC57 # 0 +0x9D54 0xEC58 # 0 +0x9D55 0xEC59 # 0 +0x9D56 0xEC5A # 0 +0x9D57 0xEC5B # 0 +0x9D58 0xEC5C # 0 +0x9D59 0xEC5D # 0 +0x9D5A 0xEC5E # 0 +0x9D5B 0xEC5F # 0 +0x9D5C 0xEC60 # 0 +0x9D5D 0xEC61 # 0 +0x9D5E 0xEC62 # 0 +0x9D5F 0xEC63 # 0 +0x9D60 0xEC64 # 0 +0x9D61 0xEC65 # 0 +0x9D62 0xEC66 # 0 +0x9D63 0xEC67 # 0 +0x9D64 0xEC68 # 0 +0x9D65 0xEC69 # 0 +0x9D66 0xEC6A # 0 +0x9D67 0xEC6B # 0 +0x9D68 0xEC6C # 0 +0x9D69 0xEC6D # 0 +0x9D6A 0xEC6E # 0 +0x9D6B 0xEC6F # 0 +0x9D6C 0xEC70 # 0 +0x9D6D 0xEC71 # 0 +0x9D6E 0xEC72 # 0 +0x9D6F 0xEC73 # 0 +0x9D70 0xEC74 # 0 +0x9D71 0xEC75 # 0 +0x9D72 0xEC76 # 0 +0x9D73 0xEC77 # 0 +0x9D74 0xEC78 # 0 +0x9D75 0xEC79 # 0 +0x9D76 0xEC7A # 0 +0x9D77 0xEC7B # 0 +0x9D78 0xEC7C # 0 +0x9D79 0xEC7D # 0 +0x9D7A 0xEC7E # 0 +0x9D7B 0xEC7F # 0 +0x9D7C 0xEC80 # 0 +0x9D7D 0xEC81 # 0 +0x9D7E 0xEC82 # 0 +0x9DA1 0xEC83 # 0 +0x9DA2 0xEC84 # 0 +0x9DA3 0xEC85 # 0 +0x9DA4 0xEC86 # 0 +0x9DA5 0xEC87 # 0 +0x9DA6 0xEC88 # 0 +0x9DA7 0xEC89 # 0 +0x9DA8 0xEC8A # 0 +0x9DA9 0xEC8B # 0 +0x9DAA 0xEC8C # 0 +0x9DAB 0xEC8D # 0 +0x9DAC 0xEC8E # 0 +0x9DAD 0xEC8F # 0 +0x9DAE 0xEC90 # 0 +0x9DAF 0xEC91 # 0 +0x9DB0 0xEC92 # 0 +0x9DB1 0xEC93 # 0 +0x9DB2 0xEC94 # 0 +0x9DB3 0xEC95 # 0 +0x9DB4 0xEC96 # 0 +0x9DB5 0xEC97 # 0 +0x9DB6 0xEC98 # 0 +0x9DB7 0xEC99 # 0 +0x9DB8 0xEC9A # 0 +0x9DB9 0xEC9B # 0 +0x9DBA 0xEC9C # 0 +0x9DBB 0xEC9D # 0 +0x9DBC 0xEC9E # 0 +0x9DBD 0xEC9F # 0 +0x9DBE 0xECA0 # 0 +0x9DBF 0xECA1 # 0 +0x9DC0 0xECA2 # 0 +0x9DC1 0xECA3 # 0 +0x9DC2 0xECA4 # 0 +0x9DC3 0xECA5 # 0 +0x9DC4 0xECA6 # 0 +0x9DC5 0xECA7 # 0 +0x9DC6 0xECA8 # 0 +0x9DC7 0xECA9 # 0 +0x9DC8 0xECAA # 0 +0x9DC9 0xECAB # 0 +0x9DCA 0xECAC # 0 +0x9DCB 0xECAD # 0 +0x9DCC 0xECAE # 0 +0x9DCD 0xECAF # 0 +0x9DCE 0xECB0 # 0 +0x9DCF 0xECB1 # 0 +0x9DD0 0xECB2 # 0 +0x9DD1 0xECB3 # 0 +0x9DD2 0xECB4 # 0 +0x9DD3 0xECB5 # 0 +0x9DD4 0xECB6 # 0 +0x9DD5 0xECB7 # 0 +0x9DD6 0xECB8 # 0 +0x9DD7 0xECB9 # 0 +0x9DD8 0xECBA # 0 +0x9DD9 0xECBB # 0 +0x9DDA 0xECBC # 0 +0x9DDB 0xECBD # 0 +0x9DDC 0xECBE # 0 +0x9DDD 0xECBF # 0 +0x9DDE 0xECC0 # 0 +0x9DDF 0xECC1 # 0 +0x9DE0 0xECC2 # 0 +0x9DE1 0xECC3 # 0 +0x9DE2 0xECC4 # 0 +0x9DE3 0xECC5 # 0 +0x9DE4 0xECC6 # 0 +0x9DE5 0xECC7 # 0 +0x9DE6 0xECC8 # 0 +0x9DE7 0xECC9 # 0 +0x9DE8 0xECCA # 0 +0x9DE9 0xECCB # 0 +0x9DEA 0xECCC # 0 +0x9DEB 0xECCD # 0 +0x9DEC 0xECCE # 0 +0x9DED 0xECCF # 0 +0x9DEE 0xECD0 # 0 +0x9DEF 0xECD1 # 0 +0x9DF0 0xECD2 # 0 +0x9DF1 0xECD3 # 0 +0x9DF2 0xECD4 # 0 +0x9DF3 0xECD5 # 0 +0x9DF4 0xECD6 # 0 +0x9DF5 0xECD7 # 0 +0x9DF6 0xECD8 # 0 +0x9DF7 0xECD9 # 0 +0x9DF8 0xECDA # 0 +0x9DF9 0xECDB # 0 +0x9DFA 0xECDC # 0 +0x9DFB 0xECDD # 0 +0x9DFC 0xECDE # 0 +0x9DFD 0xECDF # 0 +0x9DFE 0xECE0 # 0 +0x9E40 0xECE1 # 0 +0x9E41 0xECE2 # 0 +0x9E42 0xECE3 # 0 +0x9E43 0xECE4 # 0 +0x9E44 0xECE5 # 0 +0x9E45 0xECE6 # 0 +0x9E46 0xECE7 # 0 +0x9E47 0xECE8 # 0 +0x9E48 0xECE9 # 0 +0x9E49 0xECEA # 0 +0x9E4A 0xECEB # 0 +0x9E4B 0xECEC # 0 +0x9E4C 0xECED # 0 +0x9E4D 0xECEE # 0 +0x9E4E 0xECEF # 0 +0x9E4F 0xECF0 # 0 +0x9E50 0xECF1 # 0 +0x9E51 0xECF2 # 0 +0x9E52 0xECF3 # 0 +0x9E53 0xECF4 # 0 +0x9E54 0xECF5 # 0 +0x9E55 0xECF6 # 0 +0x9E56 0xECF7 # 0 +0x9E57 0xECF8 # 0 +0x9E58 0xECF9 # 0 +0x9E59 0xECFA # 0 +0x9E5A 0xECFB # 0 +0x9E5B 0xECFC # 0 +0x9E5C 0xECFD # 0 +0x9E5D 0xECFE # 0 +0x9E5E 0xECFF # 0 +0x9E5F 0xED00 # 0 +0x9E60 0xED01 # 0 +0x9E61 0xED02 # 0 +0x9E62 0xED03 # 0 +0x9E63 0xED04 # 0 +0x9E64 0xED05 # 0 +0x9E65 0xED06 # 0 +0x9E66 0xED07 # 0 +0x9E67 0xED08 # 0 +0x9E68 0xED09 # 0 +0x9E69 0xED0A # 0 +0x9E6A 0xED0B # 0 +0x9E6B 0xED0C # 0 +0x9E6C 0xED0D # 0 +0x9E6D 0xED0E # 0 +0x9E6E 0xED0F # 0 +0x9E6F 0xED10 # 0 +0x9E70 0xED11 # 0 +0x9E71 0xED12 # 0 +0x9E72 0xED13 # 0 +0x9E73 0xED14 # 0 +0x9E74 0xED15 # 0 +0x9E75 0xED16 # 0 +0x9E76 0xED17 # 0 +0x9E77 0xED18 # 0 +0x9E78 0xED19 # 0 +0x9E79 0xED1A # 0 +0x9E7A 0xED1B # 0 +0x9E7B 0xED1C # 0 +0x9E7C 0xED1D # 0 +0x9E7D 0xED1E # 0 +0x9E7E 0xED1F # 0 +0x9EA1 0xED20 # 0 +0x9EA2 0xED21 # 0 +0x9EA3 0xED22 # 0 +0x9EA4 0xED23 # 0 +0x9EA5 0xED24 # 0 +0x9EA6 0xED25 # 0 +0x9EA7 0xED26 # 0 +0x9EA8 0xED27 # 0 +0x9EA9 0xED28 # 0 +0x9EAA 0xED29 # 0 +0x9EAB 0xED2A # 0 +0x9EAC 0xED2B # 0 +0x9EAD 0xED2C # 0 +0x9EAE 0xED2D # 0 +0x9EAF 0xED2E # 0 +0x9EB0 0xED2F # 0 +0x9EB1 0xED30 # 0 +0x9EB2 0xED31 # 0 +0x9EB3 0xED32 # 0 +0x9EB4 0xED33 # 0 +0x9EB5 0xED34 # 0 +0x9EB6 0xED35 # 0 +0x9EB7 0xED36 # 0 +0x9EB8 0xED37 # 0 +0x9EB9 0xED38 # 0 +0x9EBA 0xED39 # 0 +0x9EBB 0xED3A # 0 +0x9EBC 0xED3B # 0 +0x9EBD 0xED3C # 0 +0x9EBE 0xED3D # 0 +0x9EBF 0xED3E # 0 +0x9EC0 0xED3F # 0 +0x9EC1 0xED40 # 0 +0x9EC2 0xED41 # 0 +0x9EC3 0xED42 # 0 +0x9EC4 0xED43 # 0 +0x9EC5 0xED44 # 0 +0x9EC6 0xED45 # 0 +0x9EC7 0xED46 # 0 +0x9EC8 0xED47 # 0 +0x9EC9 0xED48 # 0 +0x9ECA 0xED49 # 0 +0x9ECB 0xED4A # 0 +0x9ECC 0xED4B # 0 +0x9ECD 0xED4C # 0 +0x9ECE 0xED4D # 0 +0x9ECF 0xED4E # 0 +0x9ED0 0xED4F # 0 +0x9ED1 0xED50 # 0 +0x9ED2 0xED51 # 0 +0x9ED3 0xED52 # 0 +0x9ED4 0xED53 # 0 +0x9ED5 0xED54 # 0 +0x9ED6 0xED55 # 0 +0x9ED7 0xED56 # 0 +0x9ED8 0xED57 # 0 +0x9ED9 0xED58 # 0 +0x9EDA 0xED59 # 0 +0x9EDB 0xED5A # 0 +0x9EDC 0xED5B # 0 +0x9EDD 0xED5C # 0 +0x9EDE 0xED5D # 0 +0x9EDF 0xED5E # 0 +0x9EE0 0xED5F # 0 +0x9EE1 0xED60 # 0 +0x9EE2 0xED61 # 0 +0x9EE3 0xED62 # 0 +0x9EE4 0xED63 # 0 +0x9EE5 0xED64 # 0 +0x9EE6 0xED65 # 0 +0x9EE7 0xED66 # 0 +0x9EE8 0xED67 # 0 +0x9EE9 0xED68 # 0 +0x9EEA 0xED69 # 0 +0x9EEB 0xED6A # 0 +0x9EEC 0xED6B # 0 +0x9EED 0xED6C # 0 +0x9EEE 0xED6D # 0 +0x9EEF 0xED6E # 0 +0x9EF0 0xED6F # 0 +0x9EF1 0xED70 # 0 +0x9EF2 0xED71 # 0 +0x9EF3 0xED72 # 0 +0x9EF4 0xED73 # 0 +0x9EF5 0xED74 # 0 +0x9EF6 0xED75 # 0 +0x9EF7 0xED76 # 0 +0x9EF8 0xED77 # 0 +0x9EF9 0xED78 # 0 +0x9EFA 0xED79 # 0 +0x9EFB 0xED7A # 0 +0x9EFC 0xED7B # 0 +0x9EFD 0xED7C # 0 +0x9EFE 0xED7D # 0 +0x9F40 0xED7E # 0 +0x9F41 0xED7F # 0 +0x9F42 0xED80 # 0 +0x9F43 0xED81 # 0 +0x9F44 0xED82 # 0 +0x9F45 0xED83 # 0 +0x9F46 0xED84 # 0 +0x9F47 0xED85 # 0 +0x9F48 0xED86 # 0 +0x9F49 0xED87 # 0 +0x9F4A 0xED88 # 0 +0x9F4B 0xED89 # 0 +0x9F4C 0xED8A # 0 +0x9F4D 0xED8B # 0 +0x9F4E 0xED8C # 0 +0x9F4F 0xED8D # 0 +0x9F50 0xED8E # 0 +0x9F51 0xED8F # 0 +0x9F52 0xED90 # 0 +0x9F53 0xED91 # 0 +0x9F54 0xED92 # 0 +0x9F55 0xED93 # 0 +0x9F56 0xED94 # 0 +0x9F57 0xED95 # 0 +0x9F58 0xED96 # 0 +0x9F59 0xED97 # 0 +0x9F5A 0xED98 # 0 +0x9F5B 0xED99 # 0 +0x9F5C 0xED9A # 0 +0x9F5D 0xED9B # 0 +0x9F5E 0xED9C # 0 +0x9F5F 0xED9D # 0 +0x9F60 0xED9E # 0 +0x9F61 0xED9F # 0 +0x9F62 0xEDA0 # 0 +0x9F63 0xEDA1 # 0 +0x9F64 0xEDA2 # 0 +0x9F65 0xEDA3 # 0 +0x9F66 0xEDA4 # 0 +0x9F67 0xEDA5 # 0 +0x9F68 0xEDA6 # 0 +0x9F69 0xEDA7 # 0 +0x9F6A 0xEDA8 # 0 +0x9F6B 0xEDA9 # 0 +0x9F6C 0xEDAA # 0 +0x9F6D 0xEDAB # 0 +0x9F6E 0xEDAC # 0 +0x9F6F 0xEDAD # 0 +0x9F70 0xEDAE # 0 +0x9F71 0xEDAF # 0 +0x9F72 0xEDB0 # 0 +0x9F73 0xEDB1 # 0 +0x9F74 0xEDB2 # 0 +0x9F75 0xEDB3 # 0 +0x9F76 0xEDB4 # 0 +0x9F77 0xEDB5 # 0 +0x9F78 0xEDB6 # 0 +0x9F79 0xEDB7 # 0 +0x9F7A 0xEDB8 # 0 +0x9F7B 0xEDB9 # 0 +0x9F7C 0xEDBA # 0 +0x9F7D 0xEDBB # 0 +0x9F7E 0xEDBC # 0 +0x9FA1 0xEDBD # 0 +0x9FA2 0xEDBE # 0 +0x9FA3 0xEDBF # 0 +0x9FA4 0xEDC0 # 0 +0x9FA5 0xEDC1 # 0 +0x9FA6 0xEDC2 # 0 +0x9FA7 0xEDC3 # 0 +0x9FA8 0xEDC4 # 0 +0x9FA9 0xEDC5 # 0 +0x9FAA 0xEDC6 # 0 +0x9FAB 0xEDC7 # 0 +0x9FAC 0xEDC8 # 0 +0x9FAD 0xEDC9 # 0 +0x9FAE 0xEDCA # 0 +0x9FAF 0xEDCB # 0 +0x9FB0 0xEDCC # 0 +0x9FB1 0xEDCD # 0 +0x9FB2 0xEDCE # 0 +0x9FB3 0xEDCF # 0 +0x9FB4 0xEDD0 # 0 +0x9FB5 0xEDD1 # 0 +0x9FB6 0xEDD2 # 0 +0x9FB7 0xEDD3 # 0 +0x9FB8 0xEDD4 # 0 +0x9FB9 0xEDD5 # 0 +0x9FBA 0xEDD6 # 0 +0x9FBB 0xEDD7 # 0 +0x9FBC 0xEDD8 # 0 +0x9FBD 0xEDD9 # 0 +0x9FBE 0xEDDA # 0 +0x9FBF 0xEDDB # 0 +0x9FC0 0xEDDC # 0 +0x9FC1 0xEDDD # 0 +0x9FC2 0xEDDE # 0 +0x9FC3 0xEDDF # 0 +0x9FC4 0xEDE0 # 0 +0x9FC5 0xEDE1 # 0 +0x9FC6 0xEDE2 # 0 +0x9FC7 0xEDE3 # 0 +0x9FC8 0xEDE4 # 0 +0x9FC9 0xEDE5 # 0 +0x9FCA 0xEDE6 # 0 +0x9FCB 0xEDE7 # 0 +0x9FCC 0xEDE8 # 0 +0x9FCD 0xEDE9 # 0 +0x9FCE 0xEDEA # 0 +0x9FCF 0xEDEB # 0 +0x9FD0 0xEDEC # 0 +0x9FD1 0xEDED # 0 +0x9FD2 0xEDEE # 0 +0x9FD3 0xEDEF # 0 +0x9FD4 0xEDF0 # 0 +0x9FD5 0xEDF1 # 0 +0x9FD6 0xEDF2 # 0 +0x9FD7 0xEDF3 # 0 +0x9FD8 0xEDF4 # 0 +0x9FD9 0xEDF5 # 0 +0x9FDA 0xEDF6 # 0 +0x9FDB 0xEDF7 # 0 +0x9FDC 0xEDF8 # 0 +0x9FDD 0xEDF9 # 0 +0x9FDE 0xEDFA # 0 +0x9FDF 0xEDFB # 0 +0x9FE0 0xEDFC # 0 +0x9FE1 0xEDFD # 0 +0x9FE2 0xEDFE # 0 +0x9FE3 0xEDFF # 0 +0x9FE4 0xEE00 # 0 +0x9FE5 0xEE01 # 0 +0x9FE6 0xEE02 # 0 +0x9FE7 0xEE03 # 0 +0x9FE8 0xEE04 # 0 +0x9FE9 0xEE05 # 0 +0x9FEA 0xEE06 # 0 +0x9FEB 0xEE07 # 0 +0x9FEC 0xEE08 # 0 +0x9FED 0xEE09 # 0 +0x9FEE 0xEE0A # 0 +0x9FEF 0xEE0B # 0 +0x9FF0 0xEE0C # 0 +0x9FF1 0xEE0D # 0 +0x9FF2 0xEE0E # 0 +0x9FF3 0xEE0F # 0 +0x9FF4 0xEE10 # 0 +0x9FF5 0xEE11 # 0 +0x9FF6 0xEE12 # 0 +0x9FF7 0xEE13 # 0 +0x9FF8 0xEE14 # 0 +0x9FF9 0xEE15 # 0 +0x9FFA 0xEE16 # 0 +0x9FFB 0xEE17 # 0 +0x9FFC 0xEE18 # 0 +0x9FFD 0xEE19 # 0 +0x9FFE 0xEE1A # 0 +0xA040 0xEE1B # 0 +0xA041 0xEE1C # 0 +0xA042 0xEE1D # 0 +0xA043 0xEE1E # 0 +0xA044 0xEE1F # 0 +0xA045 0xEE20 # 0 +0xA046 0xEE21 # 0 +0xA047 0xEE22 # 0 +0xA048 0xEE23 # 0 +0xA049 0xEE24 # 0 +0xA04A 0xEE25 # 0 +0xA04B 0xEE26 # 0 +0xA04C 0xEE27 # 0 +0xA04D 0xEE28 # 0 +0xA04E 0xEE29 # 0 +0xA04F 0xEE2A # 0 +0xA050 0xEE2B # 0 +0xA051 0xEE2C # 0 +0xA052 0xEE2D # 0 +0xA053 0xEE2E # 0 +0xA054 0xEE2F # 0 +0xA055 0xEE30 # 0 +0xA056 0xEE31 # 0 +0xA057 0xEE32 # 0 +0xA058 0xEE33 # 0 +0xA059 0xEE34 # 0 +0xA05A 0xEE35 # 0 +0xA05B 0xEE36 # 0 +0xA05C 0xEE37 # 0 +0xA05D 0xEE38 # 0 +0xA05E 0xEE39 # 0 +0xA05F 0xEE3A # 0 +0xA060 0xEE3B # 0 +0xA061 0xEE3C # 0 +0xA062 0xEE3D # 0 +0xA063 0xEE3E # 0 +0xA064 0xEE3F # 0 +0xA065 0xEE40 # 0 +0xA066 0xEE41 # 0 +0xA067 0xEE42 # 0 +0xA068 0xEE43 # 0 +0xA069 0xEE44 # 0 +0xA06A 0xEE45 # 0 +0xA06B 0xEE46 # 0 +0xA06C 0xEE47 # 0 +0xA06D 0xEE48 # 0 +0xA06E 0xEE49 # 0 +0xA06F 0xEE4A # 0 +0xA070 0xEE4B # 0 +0xA071 0xEE4C # 0 +0xA072 0xEE4D # 0 +0xA073 0xEE4E # 0 +0xA074 0xEE4F # 0 +0xA075 0xEE50 # 0 +0xA076 0xEE51 # 0 +0xA077 0xEE52 # 0 +0xA078 0xEE53 # 0 +0xA079 0xEE54 # 0 +0xA07A 0xEE55 # 0 +0xA07B 0xEE56 # 0 +0xA07C 0xEE57 # 0 +0xA07D 0xEE58 # 0 +0xA07E 0xEE59 # 0 +0xA0A1 0xEE5A # 0 +0xA0A2 0xEE5B # 0 +0xA0A3 0xEE5C # 0 +0xA0A4 0xEE5D # 0 +0xA0A5 0xEE5E # 0 +0xA0A6 0xEE5F # 0 +0xA0A7 0xEE60 # 0 +0xA0A8 0xEE61 # 0 +0xA0A9 0xEE62 # 0 +0xA0AA 0xEE63 # 0 +0xA0AB 0xEE64 # 0 +0xA0AC 0xEE65 # 0 +0xA0AD 0xEE66 # 0 +0xA0AE 0xEE67 # 0 +0xA0AF 0xEE68 # 0 +0xA0B0 0xEE69 # 0 +0xA0B1 0xEE6A # 0 +0xA0B2 0xEE6B # 0 +0xA0B3 0xEE6C # 0 +0xA0B4 0xEE6D # 0 +0xA0B5 0xEE6E # 0 +0xA0B6 0xEE6F # 0 +0xA0B7 0xEE70 # 0 +0xA0B8 0xEE71 # 0 +0xA0B9 0xEE72 # 0 +0xA0BA 0xEE73 # 0 +0xA0BB 0xEE74 # 0 +0xA0BC 0xEE75 # 0 +0xA0BD 0xEE76 # 0 +0xA0BE 0xEE77 # 0 +0xA0BF 0xEE78 # 0 +0xA0C0 0xEE79 # 0 +0xA0C1 0xEE7A # 0 +0xA0C2 0xEE7B # 0 +0xA0C3 0xEE7C # 0 +0xA0C4 0xEE7D # 0 +0xA0C5 0xEE7E # 0 +0xA0C6 0xEE7F # 0 +0xA0C7 0xEE80 # 0 +0xA0C8 0xEE81 # 0 +0xA0C9 0xEE82 # 0 +0xA0CA 0xEE83 # 0 +0xA0CB 0xEE84 # 0 +0xA0CC 0xEE85 # 0 +0xA0CD 0xEE86 # 0 +0xA0CE 0xEE87 # 0 +0xA0CF 0xEE88 # 0 +0xA0D0 0xEE89 # 0 +0xA0D1 0xEE8A # 0 +0xA0D2 0xEE8B # 0 +0xA0D3 0xEE8C # 0 +0xA0D4 0xEE8D # 0 +0xA0D5 0xEE8E # 0 +0xA0D6 0xEE8F # 0 +0xA0D7 0xEE90 # 0 +0xA0D8 0xEE91 # 0 +0xA0D9 0xEE92 # 0 +0xA0DA 0xEE93 # 0 +0xA0DB 0xEE94 # 0 +0xA0DC 0xEE95 # 0 +0xA0DD 0xEE96 # 0 +0xA0DE 0xEE97 # 0 +0xA0DF 0xEE98 # 0 +0xA0E0 0xEE99 # 0 +0xA0E1 0xEE9A # 0 +0xA0E2 0xEE9B # 0 +0xA0E3 0xEE9C # 0 +0xA0E4 0xEE9D # 0 +0xA0E5 0xEE9E # 0 +0xA0E6 0xEE9F # 0 +0xA0E7 0xEEA0 # 0 +0xA0E8 0xEEA1 # 0 +0xA0E9 0xEEA2 # 0 +0xA0EA 0xEEA3 # 0 +0xA0EB 0xEEA4 # 0 +0xA0EC 0xEEA5 # 0 +0xA0ED 0xEEA6 # 0 +0xA0EE 0xEEA7 # 0 +0xA0EF 0xEEA8 # 0 +0xA0F0 0xEEA9 # 0 +0xA0F1 0xEEAA # 0 +0xA0F2 0xEEAB # 0 +0xA0F3 0xEEAC # 0 +0xA0F4 0xEEAD # 0 +0xA0F5 0xEEAE # 0 +0xA0F6 0xEEAF # 0 +0xA0F7 0xEEB0 # 0 +0xA0F8 0xEEB1 # 0 +0xA0F9 0xEEB2 # 0 +0xA0FA 0xEEB3 # 0 +0xA0FB 0xEEB4 # 0 +0xA0FC 0xEEB5 # 0 +0xA0FD 0xEEB6 # 0 +0xA0FE 0xEEB7 # 0 +0xA140 0x3000 # 0 +0xA141 0xFF0C # 0 +0xA142 0x3001 # 0 +0xA143 0x3002 # 0 +0xA144 0xFF0E # 0 +0xA145 0x2027 # 0 +0xA146 0xFF1B # 0 +0xA147 0xFF1A # 0 +0xA148 0xFF1F # 0 +0xA149 0xFF01 # 0 +0xA14A 0xFE30 # 0 +0xA14B 0x2026 # 0 +0xA14C 0x2025 # 0 +0xA14D 0xFE50 # 0 +0xA14E 0xFE51 # 0 +0xA14F 0xFE52 # 0 +0xA150 0x00B7 # 0 +0xA151 0xFE54 # 0 +0xA152 0xFE55 # 0 +0xA153 0xFE56 # 0 +0xA154 0xFE57 # 0 +0xA155 0xFF5C # 0 +0xA156 0x2013 # 0 +0xA157 0xFE31 # 0 +0xA158 0x2014 # 0 +0xA159 0xFE33 # 0 +0xA15A 0x2574 # 0 +0xA15B 0xFE34 # 0 +0xA15C 0xFE4F # 0 +0xA15D 0xFF08 # 0 +0xA15E 0xFF09 # 0 +0xA15F 0xFE35 # 0 +0xA160 0xFE36 # 0 +0xA161 0xFF5B # 0 +0xA162 0xFF5D # 0 +0xA163 0xFE37 # 0 +0xA164 0xFE38 # 0 +0xA165 0x3014 # 0 +0xA166 0x3015 # 0 +0xA167 0xFE39 # 0 +0xA168 0xFE3A # 0 +0xA169 0x3010 # 0 +0xA16A 0x3011 # 0 +0xA16B 0xFE3B # 0 +0xA16C 0xFE3C # 0 +0xA16D 0x300A # 0 +0xA16E 0x300B # 0 +0xA16F 0xFE3D # 0 +0xA170 0xFE3E # 0 +0xA171 0x3008 # 0 +0xA172 0x3009 # 0 +0xA173 0xFE3F # 0 +0xA174 0xFE40 # 0 +0xA175 0x300C # 0 +0xA176 0x300D # 0 +0xA177 0xFE41 # 0 +0xA178 0xFE42 # 0 +0xA179 0x300E # 0 +0xA17A 0x300F # 0 +0xA17B 0xFE43 # 0 +0xA17C 0xFE44 # 0 +0xA17D 0xFE59 # 0 +0xA17E 0xFE5A # 0 +0xA1A1 0xFE5B # 0 +0xA1A2 0xFE5C # 0 +0xA1A3 0xFE5D # 0 +0xA1A4 0xFE5E # 0 +0xA1A5 0x2018 # 0 +0xA1A6 0x2019 # 0 +0xA1A7 0x201C # 0 +0xA1A8 0x201D # 0 +0xA1A9 0x301D # 0 +0xA1AA 0x301E # 0 +0xA1AB 0x2035 # 0 +0xA1AC 0x2032 # 0 +0xA1AD 0xFF03 # 0 +0xA1AE 0xFF06 # 0 +0xA1AF 0xFF0A # 0 +0xA1B0 0x203B # 0 +0xA1B1 0x00A7 # 0 +0xA1B2 0x3003 # 0 +0xA1B3 0x25CB # 0 +0xA1B4 0x25CF # 0 +0xA1B5 0x25B3 # 0 +0xA1B6 0x25B2 # 0 +0xA1B7 0x25CE # 0 +0xA1B8 0x2606 # 0 +0xA1B9 0x2605 # 0 +0xA1BA 0x25C7 # 0 +0xA1BB 0x25C6 # 0 +0xA1BC 0x25A1 # 0 +0xA1BD 0x25A0 # 0 +0xA1BE 0x25BD # 0 +0xA1BF 0x25BC # 0 +0xA1C0 0x32A3 # 0 +0xA1C1 0x2105 # 0 +0xA1C2 0x00AF # 0 +0xA1C3 0xFFE3 # 0 +0xA1C4 0xFF3F # 0 +0xA1C5 0x02CD # 0 +0xA1C6 0xFE49 # 0 +0xA1C7 0xFE4A # 0 +0xA1C8 0xFE4D # 0 +0xA1C9 0xFE4E # 0 +0xA1CA 0xFE4B # 0 +0xA1CB 0xFE4C # 0 +0xA1CC 0xFE5F # 0 +0xA1CD 0xFE60 # 0 +0xA1CE 0xFE61 # 0 +0xA1CF 0xFF0B # 0 +0xA1D0 0xFF0D # 0 +0xA1D1 0x00D7 # 0 +0xA1D2 0x00F7 # 0 +0xA1D3 0x00B1 # 0 +0xA1D4 0x221A # 0 +0xA1D5 0xFF1C # 0 +0xA1D6 0xFF1E # 0 +0xA1D7 0xFF1D # 0 +0xA1D8 0x2266 # 0 +0xA1D9 0x2267 # 0 +0xA1DA 0x2260 # 0 +0xA1DB 0x221E # 0 +0xA1DC 0x2252 # 0 +0xA1DD 0x2261 # 0 +0xA1DE 0xFE62 # 0 +0xA1DF 0xFE63 # 0 +0xA1E0 0xFE64 # 0 +0xA1E1 0xFE65 # 0 +0xA1E2 0xFE66 # 0 +0xA1E3 0xFF5E # 0 +0xA1E4 0x2229 # 0 +0xA1E5 0x222A # 0 +0xA1E6 0x22A5 # 0 +0xA1E7 0x2220 # 0 +0xA1E8 0x221F # 0 +0xA1E9 0x22BF # 0 +0xA1EA 0x33D2 # 0 +0xA1EB 0x33D1 # 0 +0xA1EC 0x222B # 0 +0xA1ED 0x222E # 0 +0xA1EE 0x2235 # 0 +0xA1EF 0x2234 # 0 +0xA1F0 0x2640 # 0 +0xA1F1 0x2642 # 0 +0xA1F2 0x2295 # 0 +0xA1F3 0x2299 # 0 +0xA1F4 0x2191 # 0 +0xA1F5 0x2193 # 0 +0xA1F6 0x2190 # 0 +0xA1F7 0x2192 # 0 +0xA1F8 0x2196 # 0 +0xA1F9 0x2197 # 0 +0xA1FA 0x2199 # 0 +0xA1FB 0x2198 # 0 +0xA1FC 0x2225 # 0 +0xA1FD 0x2223 # 0 +0xA1FE 0xFF0F # 0 +0xA240 0xFF3C # 0 +0xA241 0x2215 # 0 +0xA242 0xFE68 # 0 +0xA243 0xFF04 # 0 +0xA244 0xFFE5 # 0 +0xA245 0x3012 # 0 +0xA246 0xFFE0 # 0 +0xA247 0xFFE1 # 0 +0xA248 0xFF05 # 0 +0xA249 0xFF20 # 0 +0xA24A 0x2103 # 0 +0xA24B 0x2109 # 0 +0xA24C 0xFE69 # 0 +0xA24D 0xFE6A # 0 +0xA24E 0xFE6B # 0 +0xA24F 0x33D5 # 0 +0xA250 0x339C # 0 +0xA251 0x339D # 0 +0xA252 0x339E # 0 +0xA253 0x33CE # 0 +0xA254 0x33A1 # 0 +0xA255 0x338E # 0 +0xA256 0x338F # 0 +0xA257 0x33C4 # 0 +0xA258 0x00B0 # 0 +0xA259 0x5159 # 0 +0xA25A 0x515B # 0 +0xA25B 0x515E # 0 +0xA25C 0x515D # 0 +0xA25D 0x5161 # 0 +0xA25E 0x5163 # 0 +0xA25F 0x55E7 # 0 +0xA260 0x74E9 # 0 +0xA261 0x7CCE # 0 +0xA262 0x2581 # 0 +0xA263 0x2582 # 0 +0xA264 0x2583 # 0 +0xA265 0x2584 # 0 +0xA266 0x2585 # 0 +0xA267 0x2586 # 0 +0xA268 0x2587 # 0 +0xA269 0x2588 # 0 +0xA26A 0x258F # 0 +0xA26B 0x258E # 0 +0xA26C 0x258D # 0 +0xA26D 0x258C # 0 +0xA26E 0x258B # 0 +0xA26F 0x258A # 0 +0xA270 0x2589 # 0 +0xA271 0x253C # 0 +0xA272 0x2534 # 0 +0xA273 0x252C # 0 +0xA274 0x2524 # 0 +0xA275 0x251C # 0 +0xA276 0x2594 # 0 +0xA277 0x2500 # 0 +0xA278 0x2502 # 0 +0xA279 0x2595 # 0 +0xA27A 0x250C # 0 +0xA27B 0x2510 # 0 +0xA27C 0x2514 # 0 +0xA27D 0x2518 # 0 +0xA27E 0x256D # 0 +0xA2A1 0x256E # 0 +0xA2A2 0x2570 # 0 +0xA2A3 0x256F # 0 +0xA2A8 0x25E2 # 0 +0xA2A9 0x25E3 # 0 +0xA2AA 0x25E5 # 0 +0xA2AB 0x25E4 # 0 +0xA2AC 0x2571 # 0 +0xA2AD 0x2572 # 0 +0xA2AE 0x2573 # 0 +0xA2AF 0xFF10 # 0 +0xA2B0 0xFF11 # 0 +0xA2B1 0xFF12 # 0 +0xA2B2 0xFF13 # 0 +0xA2B3 0xFF14 # 0 +0xA2B4 0xFF15 # 0 +0xA2B5 0xFF16 # 0 +0xA2B6 0xFF17 # 0 +0xA2B7 0xFF18 # 0 +0xA2B8 0xFF19 # 0 +0xA2B9 0x2160 # 0 +0xA2BA 0x2161 # 0 +0xA2BB 0x2162 # 0 +0xA2BC 0x2163 # 0 +0xA2BD 0x2164 # 0 +0xA2BE 0x2165 # 0 +0xA2BF 0x2166 # 0 +0xA2C0 0x2167 # 0 +0xA2C1 0x2168 # 0 +0xA2C2 0x2169 # 0 +0xA2C3 0x3021 # 0 +0xA2C4 0x3022 # 0 +0xA2C5 0x3023 # 0 +0xA2C6 0x3024 # 0 +0xA2C7 0x3025 # 0 +0xA2C8 0x3026 # 0 +0xA2C9 0x3027 # 0 +0xA2CA 0x3028 # 0 +0xA2CB 0x3029 # 0 +0xA2CD 0x5344 # 0 +0xA2CF 0xFF21 # 0 +0xA2D0 0xFF22 # 0 +0xA2D1 0xFF23 # 0 +0xA2D2 0xFF24 # 0 +0xA2D3 0xFF25 # 0 +0xA2D4 0xFF26 # 0 +0xA2D5 0xFF27 # 0 +0xA2D6 0xFF28 # 0 +0xA2D7 0xFF29 # 0 +0xA2D8 0xFF2A # 0 +0xA2D9 0xFF2B # 0 +0xA2DA 0xFF2C # 0 +0xA2DB 0xFF2D # 0 +0xA2DC 0xFF2E # 0 +0xA2DD 0xFF2F # 0 +0xA2DE 0xFF30 # 0 +0xA2DF 0xFF31 # 0 +0xA2E0 0xFF32 # 0 +0xA2E1 0xFF33 # 0 +0xA2E2 0xFF34 # 0 +0xA2E3 0xFF35 # 0 +0xA2E4 0xFF36 # 0 +0xA2E5 0xFF37 # 0 +0xA2E6 0xFF38 # 0 +0xA2E7 0xFF39 # 0 +0xA2E8 0xFF3A # 0 +0xA2E9 0xFF41 # 0 +0xA2EA 0xFF42 # 0 +0xA2EB 0xFF43 # 0 +0xA2EC 0xFF44 # 0 +0xA2ED 0xFF45 # 0 +0xA2EE 0xFF46 # 0 +0xA2EF 0xFF47 # 0 +0xA2F0 0xFF48 # 0 +0xA2F1 0xFF49 # 0 +0xA2F2 0xFF4A # 0 +0xA2F3 0xFF4B # 0 +0xA2F4 0xFF4C # 0 +0xA2F5 0xFF4D # 0 +0xA2F6 0xFF4E # 0 +0xA2F7 0xFF4F # 0 +0xA2F8 0xFF50 # 0 +0xA2F9 0xFF51 # 0 +0xA2FA 0xFF52 # 0 +0xA2FB 0xFF53 # 0 +0xA2FC 0xFF54 # 0 +0xA2FD 0xFF55 # 0 +0xA2FE 0xFF56 # 0 +0xA340 0xFF57 # 0 +0xA341 0xFF58 # 0 +0xA342 0xFF59 # 0 +0xA343 0xFF5A # 0 +0xA344 0x0391 # 0 +0xA345 0x0392 # 0 +0xA346 0x0393 # 0 +0xA347 0x0394 # 0 +0xA348 0x0395 # 0 +0xA349 0x0396 # 0 +0xA34A 0x0397 # 0 +0xA34B 0x0398 # 0 +0xA34C 0x0399 # 0 +0xA34D 0x039A # 0 +0xA34E 0x039B # 0 +0xA34F 0x039C # 0 +0xA350 0x039D # 0 +0xA351 0x039E # 0 +0xA352 0x039F # 0 +0xA353 0x03A0 # 0 +0xA354 0x03A1 # 0 +0xA355 0x03A3 # 0 +0xA356 0x03A4 # 0 +0xA357 0x03A5 # 0 +0xA358 0x03A6 # 0 +0xA359 0x03A7 # 0 +0xA35A 0x03A8 # 0 +0xA35B 0x03A9 # 0 +0xA35C 0x03B1 # 0 +0xA35D 0x03B2 # 0 +0xA35E 0x03B3 # 0 +0xA35F 0x03B4 # 0 +0xA360 0x03B5 # 0 +0xA361 0x03B6 # 0 +0xA362 0x03B7 # 0 +0xA363 0x03B8 # 0 +0xA364 0x03B9 # 0 +0xA365 0x03BA # 0 +0xA366 0x03BB # 0 +0xA367 0x03BC # 0 +0xA368 0x03BD # 0 +0xA369 0x03BE # 0 +0xA36A 0x03BF # 0 +0xA36B 0x03C0 # 0 +0xA36C 0x03C1 # 0 +0xA36D 0x03C3 # 0 +0xA36E 0x03C4 # 0 +0xA36F 0x03C5 # 0 +0xA370 0x03C6 # 0 +0xA371 0x03C7 # 0 +0xA372 0x03C8 # 0 +0xA373 0x03C9 # 0 +0xA374 0x3105 # 0 +0xA375 0x3106 # 0 +0xA376 0x3107 # 0 +0xA377 0x3108 # 0 +0xA378 0x3109 # 0 +0xA379 0x310A # 0 +0xA37A 0x310B # 0 +0xA37B 0x310C # 0 +0xA37C 0x310D # 0 +0xA37D 0x310E # 0 +0xA37E 0x310F # 0 +0xA3A1 0x3110 # 0 +0xA3A2 0x3111 # 0 +0xA3A3 0x3112 # 0 +0xA3A4 0x3113 # 0 +0xA3A5 0x3114 # 0 +0xA3A6 0x3115 # 0 +0xA3A7 0x3116 # 0 +0xA3A8 0x3117 # 0 +0xA3A9 0x3118 # 0 +0xA3AA 0x3119 # 0 +0xA3AB 0x311A # 0 +0xA3AC 0x311B # 0 +0xA3AD 0x311C # 0 +0xA3AE 0x311D # 0 +0xA3AF 0x311E # 0 +0xA3B0 0x311F # 0 +0xA3B1 0x3120 # 0 +0xA3B2 0x3121 # 0 +0xA3B3 0x3122 # 0 +0xA3B4 0x3123 # 0 +0xA3B5 0x3124 # 0 +0xA3B6 0x3125 # 0 +0xA3B7 0x3126 # 0 +0xA3B8 0x3127 # 0 +0xA3B9 0x3128 # 0 +0xA3BA 0x3129 # 0 +0xA3BB 0x02D9 # 0 +0xA3BC 0x02C9 # 0 +0xA3BD 0x02CA # 0 +0xA3BE 0x02C7 # 0 +0xA3BF 0x02CB # 0 +0xA3E1 0x20AC # 0 +0xA440 0x4E00 # 0 +0xA441 0x4E59 # 0 +0xA442 0x4E01 # 0 +0xA443 0x4E03 # 0 +0xA444 0x4E43 # 0 +0xA445 0x4E5D # 0 +0xA446 0x4E86 # 0 +0xA447 0x4E8C # 0 +0xA448 0x4EBA # 0 +0xA449 0x513F # 0 +0xA44A 0x5165 # 0 +0xA44B 0x516B # 0 +0xA44C 0x51E0 # 0 +0xA44D 0x5200 # 0 +0xA44E 0x5201 # 0 +0xA44F 0x529B # 0 +0xA450 0x5315 # 0 +0xA451 0x5341 # 0 +0xA452 0x535C # 0 +0xA453 0x53C8 # 0 +0xA454 0x4E09 # 0 +0xA455 0x4E0B # 0 +0xA456 0x4E08 # 0 +0xA457 0x4E0A # 0 +0xA458 0x4E2B # 0 +0xA459 0x4E38 # 0 +0xA45A 0x51E1 # 0 +0xA45B 0x4E45 # 0 +0xA45C 0x4E48 # 0 +0xA45D 0x4E5F # 0 +0xA45E 0x4E5E # 0 +0xA45F 0x4E8E # 0 +0xA460 0x4EA1 # 0 +0xA461 0x5140 # 0 +0xA462 0x5203 # 0 +0xA463 0x52FA # 0 +0xA464 0x5343 # 0 +0xA465 0x53C9 # 0 +0xA466 0x53E3 # 0 +0xA467 0x571F # 0 +0xA468 0x58EB # 0 +0xA469 0x5915 # 0 +0xA46A 0x5927 # 0 +0xA46B 0x5973 # 0 +0xA46C 0x5B50 # 0 +0xA46D 0x5B51 # 0 +0xA46E 0x5B53 # 0 +0xA46F 0x5BF8 # 0 +0xA470 0x5C0F # 0 +0xA471 0x5C22 # 0 +0xA472 0x5C38 # 0 +0xA473 0x5C71 # 0 +0xA474 0x5DDD # 0 +0xA475 0x5DE5 # 0 +0xA476 0x5DF1 # 0 +0xA477 0x5DF2 # 0 +0xA478 0x5DF3 # 0 +0xA479 0x5DFE # 0 +0xA47A 0x5E72 # 0 +0xA47B 0x5EFE # 0 +0xA47C 0x5F0B # 0 +0xA47D 0x5F13 # 0 +0xA47E 0x624D # 0 +0xA4A1 0x4E11 # 0 +0xA4A2 0x4E10 # 0 +0xA4A3 0x4E0D # 0 +0xA4A4 0x4E2D # 0 +0xA4A5 0x4E30 # 0 +0xA4A6 0x4E39 # 0 +0xA4A7 0x4E4B # 0 +0xA4A8 0x5C39 # 0 +0xA4A9 0x4E88 # 0 +0xA4AA 0x4E91 # 0 +0xA4AB 0x4E95 # 0 +0xA4AC 0x4E92 # 0 +0xA4AD 0x4E94 # 0 +0xA4AE 0x4EA2 # 0 +0xA4AF 0x4EC1 # 0 +0xA4B0 0x4EC0 # 0 +0xA4B1 0x4EC3 # 0 +0xA4B2 0x4EC6 # 0 +0xA4B3 0x4EC7 # 0 +0xA4B4 0x4ECD # 0 +0xA4B5 0x4ECA # 0 +0xA4B6 0x4ECB # 0 +0xA4B7 0x4EC4 # 0 +0xA4B8 0x5143 # 0 +0xA4B9 0x5141 # 0 +0xA4BA 0x5167 # 0 +0xA4BB 0x516D # 0 +0xA4BC 0x516E # 0 +0xA4BD 0x516C # 0 +0xA4BE 0x5197 # 0 +0xA4BF 0x51F6 # 0 +0xA4C0 0x5206 # 0 +0xA4C1 0x5207 # 0 +0xA4C2 0x5208 # 0 +0xA4C3 0x52FB # 0 +0xA4C4 0x52FE # 0 +0xA4C5 0x52FF # 0 +0xA4C6 0x5316 # 0 +0xA4C7 0x5339 # 0 +0xA4C8 0x5348 # 0 +0xA4C9 0x5347 # 0 +0xA4CA 0x5345 # 0 +0xA4CB 0x535E # 0 +0xA4CC 0x5384 # 0 +0xA4CD 0x53CB # 0 +0xA4CE 0x53CA # 0 +0xA4CF 0x53CD # 0 +0xA4D0 0x58EC # 0 +0xA4D1 0x5929 # 0 +0xA4D2 0x592B # 0 +0xA4D3 0x592A # 0 +0xA4D4 0x592D # 0 +0xA4D5 0x5B54 # 0 +0xA4D6 0x5C11 # 0 +0xA4D7 0x5C24 # 0 +0xA4D8 0x5C3A # 0 +0xA4D9 0x5C6F # 0 +0xA4DA 0x5DF4 # 0 +0xA4DB 0x5E7B # 0 +0xA4DC 0x5EFF # 0 +0xA4DD 0x5F14 # 0 +0xA4DE 0x5F15 # 0 +0xA4DF 0x5FC3 # 0 +0xA4E0 0x6208 # 0 +0xA4E1 0x6236 # 0 +0xA4E2 0x624B # 0 +0xA4E3 0x624E # 0 +0xA4E4 0x652F # 0 +0xA4E5 0x6587 # 0 +0xA4E6 0x6597 # 0 +0xA4E7 0x65A4 # 0 +0xA4E8 0x65B9 # 0 +0xA4E9 0x65E5 # 0 +0xA4EA 0x66F0 # 0 +0xA4EB 0x6708 # 0 +0xA4EC 0x6728 # 0 +0xA4ED 0x6B20 # 0 +0xA4EE 0x6B62 # 0 +0xA4EF 0x6B79 # 0 +0xA4F0 0x6BCB # 0 +0xA4F1 0x6BD4 # 0 +0xA4F2 0x6BDB # 0 +0xA4F3 0x6C0F # 0 +0xA4F4 0x6C34 # 0 +0xA4F5 0x706B # 0 +0xA4F6 0x722A # 0 +0xA4F7 0x7236 # 0 +0xA4F8 0x723B # 0 +0xA4F9 0x7247 # 0 +0xA4FA 0x7259 # 0 +0xA4FB 0x725B # 0 +0xA4FC 0x72AC # 0 +0xA4FD 0x738B # 0 +0xA4FE 0x4E19 # 0 +0xA540 0x4E16 # 0 +0xA541 0x4E15 # 0 +0xA542 0x4E14 # 0 +0xA543 0x4E18 # 0 +0xA544 0x4E3B # 0 +0xA545 0x4E4D # 0 +0xA546 0x4E4F # 0 +0xA547 0x4E4E # 0 +0xA548 0x4EE5 # 0 +0xA549 0x4ED8 # 0 +0xA54A 0x4ED4 # 0 +0xA54B 0x4ED5 # 0 +0xA54C 0x4ED6 # 0 +0xA54D 0x4ED7 # 0 +0xA54E 0x4EE3 # 0 +0xA54F 0x4EE4 # 0 +0xA550 0x4ED9 # 0 +0xA551 0x4EDE # 0 +0xA552 0x5145 # 0 +0xA553 0x5144 # 0 +0xA554 0x5189 # 0 +0xA555 0x518A # 0 +0xA556 0x51AC # 0 +0xA557 0x51F9 # 0 +0xA558 0x51FA # 0 +0xA559 0x51F8 # 0 +0xA55A 0x520A # 0 +0xA55B 0x52A0 # 0 +0xA55C 0x529F # 0 +0xA55D 0x5305 # 0 +0xA55E 0x5306 # 0 +0xA55F 0x5317 # 0 +0xA560 0x531D # 0 +0xA561 0x4EDF # 0 +0xA562 0x534A # 0 +0xA563 0x5349 # 0 +0xA564 0x5361 # 0 +0xA565 0x5360 # 0 +0xA566 0x536F # 0 +0xA567 0x536E # 0 +0xA568 0x53BB # 0 +0xA569 0x53EF # 0 +0xA56A 0x53E4 # 0 +0xA56B 0x53F3 # 0 +0xA56C 0x53EC # 0 +0xA56D 0x53EE # 0 +0xA56E 0x53E9 # 0 +0xA56F 0x53E8 # 0 +0xA570 0x53FC # 0 +0xA571 0x53F8 # 0 +0xA572 0x53F5 # 0 +0xA573 0x53EB # 0 +0xA574 0x53E6 # 0 +0xA575 0x53EA # 0 +0xA576 0x53F2 # 0 +0xA577 0x53F1 # 0 +0xA578 0x53F0 # 0 +0xA579 0x53E5 # 0 +0xA57A 0x53ED # 0 +0xA57B 0x53FB # 0 +0xA57C 0x56DB # 0 +0xA57D 0x56DA # 0 +0xA57E 0x5916 # 0 +0xA5A1 0x592E # 0 +0xA5A2 0x5931 # 0 +0xA5A3 0x5974 # 0 +0xA5A4 0x5976 # 0 +0xA5A5 0x5B55 # 0 +0xA5A6 0x5B83 # 0 +0xA5A7 0x5C3C # 0 +0xA5A8 0x5DE8 # 0 +0xA5A9 0x5DE7 # 0 +0xA5AA 0x5DE6 # 0 +0xA5AB 0x5E02 # 0 +0xA5AC 0x5E03 # 0 +0xA5AD 0x5E73 # 0 +0xA5AE 0x5E7C # 0 +0xA5AF 0x5F01 # 0 +0xA5B0 0x5F18 # 0 +0xA5B1 0x5F17 # 0 +0xA5B2 0x5FC5 # 0 +0xA5B3 0x620A # 0 +0xA5B4 0x6253 # 0 +0xA5B5 0x6254 # 0 +0xA5B6 0x6252 # 0 +0xA5B7 0x6251 # 0 +0xA5B8 0x65A5 # 0 +0xA5B9 0x65E6 # 0 +0xA5BA 0x672E # 0 +0xA5BB 0x672C # 0 +0xA5BC 0x672A # 0 +0xA5BD 0x672B # 0 +0xA5BE 0x672D # 0 +0xA5BF 0x6B63 # 0 +0xA5C0 0x6BCD # 0 +0xA5C1 0x6C11 # 0 +0xA5C2 0x6C10 # 0 +0xA5C3 0x6C38 # 0 +0xA5C4 0x6C41 # 0 +0xA5C5 0x6C40 # 0 +0xA5C6 0x6C3E # 0 +0xA5C7 0x72AF # 0 +0xA5C8 0x7384 # 0 +0xA5C9 0x7389 # 0 +0xA5CA 0x74DC # 0 +0xA5CB 0x74E6 # 0 +0xA5CC 0x7518 # 0 +0xA5CD 0x751F # 0 +0xA5CE 0x7528 # 0 +0xA5CF 0x7529 # 0 +0xA5D0 0x7530 # 0 +0xA5D1 0x7531 # 0 +0xA5D2 0x7532 # 0 +0xA5D3 0x7533 # 0 +0xA5D4 0x758B # 0 +0xA5D5 0x767D # 0 +0xA5D6 0x76AE # 0 +0xA5D7 0x76BF # 0 +0xA5D8 0x76EE # 0 +0xA5D9 0x77DB # 0 +0xA5DA 0x77E2 # 0 +0xA5DB 0x77F3 # 0 +0xA5DC 0x793A # 0 +0xA5DD 0x79BE # 0 +0xA5DE 0x7A74 # 0 +0xA5DF 0x7ACB # 0 +0xA5E0 0x4E1E # 0 +0xA5E1 0x4E1F # 0 +0xA5E2 0x4E52 # 0 +0xA5E3 0x4E53 # 0 +0xA5E4 0x4E69 # 0 +0xA5E5 0x4E99 # 0 +0xA5E6 0x4EA4 # 0 +0xA5E7 0x4EA6 # 0 +0xA5E8 0x4EA5 # 0 +0xA5E9 0x4EFF # 0 +0xA5EA 0x4F09 # 0 +0xA5EB 0x4F19 # 0 +0xA5EC 0x4F0A # 0 +0xA5ED 0x4F15 # 0 +0xA5EE 0x4F0D # 0 +0xA5EF 0x4F10 # 0 +0xA5F0 0x4F11 # 0 +0xA5F1 0x4F0F # 0 +0xA5F2 0x4EF2 # 0 +0xA5F3 0x4EF6 # 0 +0xA5F4 0x4EFB # 0 +0xA5F5 0x4EF0 # 0 +0xA5F6 0x4EF3 # 0 +0xA5F7 0x4EFD # 0 +0xA5F8 0x4F01 # 0 +0xA5F9 0x4F0B # 0 +0xA5FA 0x5149 # 0 +0xA5FB 0x5147 # 0 +0xA5FC 0x5146 # 0 +0xA5FD 0x5148 # 0 +0xA5FE 0x5168 # 0 +0xA640 0x5171 # 0 +0xA641 0x518D # 0 +0xA642 0x51B0 # 0 +0xA643 0x5217 # 0 +0xA644 0x5211 # 0 +0xA645 0x5212 # 0 +0xA646 0x520E # 0 +0xA647 0x5216 # 0 +0xA648 0x52A3 # 0 +0xA649 0x5308 # 0 +0xA64A 0x5321 # 0 +0xA64B 0x5320 # 0 +0xA64C 0x5370 # 0 +0xA64D 0x5371 # 0 +0xA64E 0x5409 # 0 +0xA64F 0x540F # 0 +0xA650 0x540C # 0 +0xA651 0x540A # 0 +0xA652 0x5410 # 0 +0xA653 0x5401 # 0 +0xA654 0x540B # 0 +0xA655 0x5404 # 0 +0xA656 0x5411 # 0 +0xA657 0x540D # 0 +0xA658 0x5408 # 0 +0xA659 0x5403 # 0 +0xA65A 0x540E # 0 +0xA65B 0x5406 # 0 +0xA65C 0x5412 # 0 +0xA65D 0x56E0 # 0 +0xA65E 0x56DE # 0 +0xA65F 0x56DD # 0 +0xA660 0x5733 # 0 +0xA661 0x5730 # 0 +0xA662 0x5728 # 0 +0xA663 0x572D # 0 +0xA664 0x572C # 0 +0xA665 0x572F # 0 +0xA666 0x5729 # 0 +0xA667 0x5919 # 0 +0xA668 0x591A # 0 +0xA669 0x5937 # 0 +0xA66A 0x5938 # 0 +0xA66B 0x5984 # 0 +0xA66C 0x5978 # 0 +0xA66D 0x5983 # 0 +0xA66E 0x597D # 0 +0xA66F 0x5979 # 0 +0xA670 0x5982 # 0 +0xA671 0x5981 # 0 +0xA672 0x5B57 # 0 +0xA673 0x5B58 # 0 +0xA674 0x5B87 # 0 +0xA675 0x5B88 # 0 +0xA676 0x5B85 # 0 +0xA677 0x5B89 # 0 +0xA678 0x5BFA # 0 +0xA679 0x5C16 # 0 +0xA67A 0x5C79 # 0 +0xA67B 0x5DDE # 0 +0xA67C 0x5E06 # 0 +0xA67D 0x5E76 # 0 +0xA67E 0x5E74 # 0 +0xA6A1 0x5F0F # 0 +0xA6A2 0x5F1B # 0 +0xA6A3 0x5FD9 # 0 +0xA6A4 0x5FD6 # 0 +0xA6A5 0x620E # 0 +0xA6A6 0x620C # 0 +0xA6A7 0x620D # 0 +0xA6A8 0x6210 # 0 +0xA6A9 0x6263 # 0 +0xA6AA 0x625B # 0 +0xA6AB 0x6258 # 0 +0xA6AC 0x6536 # 0 +0xA6AD 0x65E9 # 0 +0xA6AE 0x65E8 # 0 +0xA6AF 0x65EC # 0 +0xA6B0 0x65ED # 0 +0xA6B1 0x66F2 # 0 +0xA6B2 0x66F3 # 0 +0xA6B3 0x6709 # 0 +0xA6B4 0x673D # 0 +0xA6B5 0x6734 # 0 +0xA6B6 0x6731 # 0 +0xA6B7 0x6735 # 0 +0xA6B8 0x6B21 # 0 +0xA6B9 0x6B64 # 0 +0xA6BA 0x6B7B # 0 +0xA6BB 0x6C16 # 0 +0xA6BC 0x6C5D # 0 +0xA6BD 0x6C57 # 0 +0xA6BE 0x6C59 # 0 +0xA6BF 0x6C5F # 0 +0xA6C0 0x6C60 # 0 +0xA6C1 0x6C50 # 0 +0xA6C2 0x6C55 # 0 +0xA6C3 0x6C61 # 0 +0xA6C4 0x6C5B # 0 +0xA6C5 0x6C4D # 0 +0xA6C6 0x6C4E # 0 +0xA6C7 0x7070 # 0 +0xA6C8 0x725F # 0 +0xA6C9 0x725D # 0 +0xA6CA 0x767E # 0 +0xA6CB 0x7AF9 # 0 +0xA6CC 0x7C73 # 0 +0xA6CD 0x7CF8 # 0 +0xA6CE 0x7F36 # 0 +0xA6CF 0x7F8A # 0 +0xA6D0 0x7FBD # 0 +0xA6D1 0x8001 # 0 +0xA6D2 0x8003 # 0 +0xA6D3 0x800C # 0 +0xA6D4 0x8012 # 0 +0xA6D5 0x8033 # 0 +0xA6D6 0x807F # 0 +0xA6D7 0x8089 # 0 +0xA6D8 0x808B # 0 +0xA6D9 0x808C # 0 +0xA6DA 0x81E3 # 0 +0xA6DB 0x81EA # 0 +0xA6DC 0x81F3 # 0 +0xA6DD 0x81FC # 0 +0xA6DE 0x820C # 0 +0xA6DF 0x821B # 0 +0xA6E0 0x821F # 0 +0xA6E1 0x826E # 0 +0xA6E2 0x8272 # 0 +0xA6E3 0x827E # 0 +0xA6E4 0x866B # 0 +0xA6E5 0x8840 # 0 +0xA6E6 0x884C # 0 +0xA6E7 0x8863 # 0 +0xA6E8 0x897F # 0 +0xA6E9 0x9621 # 0 +0xA6EA 0x4E32 # 0 +0xA6EB 0x4EA8 # 0 +0xA6EC 0x4F4D # 0 +0xA6ED 0x4F4F # 0 +0xA6EE 0x4F47 # 0 +0xA6EF 0x4F57 # 0 +0xA6F0 0x4F5E # 0 +0xA6F1 0x4F34 # 0 +0xA6F2 0x4F5B # 0 +0xA6F3 0x4F55 # 0 +0xA6F4 0x4F30 # 0 +0xA6F5 0x4F50 # 0 +0xA6F6 0x4F51 # 0 +0xA6F7 0x4F3D # 0 +0xA6F8 0x4F3A # 0 +0xA6F9 0x4F38 # 0 +0xA6FA 0x4F43 # 0 +0xA6FB 0x4F54 # 0 +0xA6FC 0x4F3C # 0 +0xA6FD 0x4F46 # 0 +0xA6FE 0x4F63 # 0 +0xA740 0x4F5C # 0 +0xA741 0x4F60 # 0 +0xA742 0x4F2F # 0 +0xA743 0x4F4E # 0 +0xA744 0x4F36 # 0 +0xA745 0x4F59 # 0 +0xA746 0x4F5D # 0 +0xA747 0x4F48 # 0 +0xA748 0x4F5A # 0 +0xA749 0x514C # 0 +0xA74A 0x514B # 0 +0xA74B 0x514D # 0 +0xA74C 0x5175 # 0 +0xA74D 0x51B6 # 0 +0xA74E 0x51B7 # 0 +0xA74F 0x5225 # 0 +0xA750 0x5224 # 0 +0xA751 0x5229 # 0 +0xA752 0x522A # 0 +0xA753 0x5228 # 0 +0xA754 0x52AB # 0 +0xA755 0x52A9 # 0 +0xA756 0x52AA # 0 +0xA757 0x52AC # 0 +0xA758 0x5323 # 0 +0xA759 0x5373 # 0 +0xA75A 0x5375 # 0 +0xA75B 0x541D # 0 +0xA75C 0x542D # 0 +0xA75D 0x541E # 0 +0xA75E 0x543E # 0 +0xA75F 0x5426 # 0 +0xA760 0x544E # 0 +0xA761 0x5427 # 0 +0xA762 0x5446 # 0 +0xA763 0x5443 # 0 +0xA764 0x5433 # 0 +0xA765 0x5448 # 0 +0xA766 0x5442 # 0 +0xA767 0x541B # 0 +0xA768 0x5429 # 0 +0xA769 0x544A # 0 +0xA76A 0x5439 # 0 +0xA76B 0x543B # 0 +0xA76C 0x5438 # 0 +0xA76D 0x542E # 0 +0xA76E 0x5435 # 0 +0xA76F 0x5436 # 0 +0xA770 0x5420 # 0 +0xA771 0x543C # 0 +0xA772 0x5440 # 0 +0xA773 0x5431 # 0 +0xA774 0x542B # 0 +0xA775 0x541F # 0 +0xA776 0x542C # 0 +0xA777 0x56EA # 0 +0xA778 0x56F0 # 0 +0xA779 0x56E4 # 0 +0xA77A 0x56EB # 0 +0xA77B 0x574A # 0 +0xA77C 0x5751 # 0 +0xA77D 0x5740 # 0 +0xA77E 0x574D # 0 +0xA7A1 0x5747 # 0 +0xA7A2 0x574E # 0 +0xA7A3 0x573E # 0 +0xA7A4 0x5750 # 0 +0xA7A5 0x574F # 0 +0xA7A6 0x573B # 0 +0xA7A7 0x58EF # 0 +0xA7A8 0x593E # 0 +0xA7A9 0x599D # 0 +0xA7AA 0x5992 # 0 +0xA7AB 0x59A8 # 0 +0xA7AC 0x599E # 0 +0xA7AD 0x59A3 # 0 +0xA7AE 0x5999 # 0 +0xA7AF 0x5996 # 0 +0xA7B0 0x598D # 0 +0xA7B1 0x59A4 # 0 +0xA7B2 0x5993 # 0 +0xA7B3 0x598A # 0 +0xA7B4 0x59A5 # 0 +0xA7B5 0x5B5D # 0 +0xA7B6 0x5B5C # 0 +0xA7B7 0x5B5A # 0 +0xA7B8 0x5B5B # 0 +0xA7B9 0x5B8C # 0 +0xA7BA 0x5B8B # 0 +0xA7BB 0x5B8F # 0 +0xA7BC 0x5C2C # 0 +0xA7BD 0x5C40 # 0 +0xA7BE 0x5C41 # 0 +0xA7BF 0x5C3F # 0 +0xA7C0 0x5C3E # 0 +0xA7C1 0x5C90 # 0 +0xA7C2 0x5C91 # 0 +0xA7C3 0x5C94 # 0 +0xA7C4 0x5C8C # 0 +0xA7C5 0x5DEB # 0 +0xA7C6 0x5E0C # 0 +0xA7C7 0x5E8F # 0 +0xA7C8 0x5E87 # 0 +0xA7C9 0x5E8A # 0 +0xA7CA 0x5EF7 # 0 +0xA7CB 0x5F04 # 0 +0xA7CC 0x5F1F # 0 +0xA7CD 0x5F64 # 0 +0xA7CE 0x5F62 # 0 +0xA7CF 0x5F77 # 0 +0xA7D0 0x5F79 # 0 +0xA7D1 0x5FD8 # 0 +0xA7D2 0x5FCC # 0 +0xA7D3 0x5FD7 # 0 +0xA7D4 0x5FCD # 0 +0xA7D5 0x5FF1 # 0 +0xA7D6 0x5FEB # 0 +0xA7D7 0x5FF8 # 0 +0xA7D8 0x5FEA # 0 +0xA7D9 0x6212 # 0 +0xA7DA 0x6211 # 0 +0xA7DB 0x6284 # 0 +0xA7DC 0x6297 # 0 +0xA7DD 0x6296 # 0 +0xA7DE 0x6280 # 0 +0xA7DF 0x6276 # 0 +0xA7E0 0x6289 # 0 +0xA7E1 0x626D # 0 +0xA7E2 0x628A # 0 +0xA7E3 0x627C # 0 +0xA7E4 0x627E # 0 +0xA7E5 0x6279 # 0 +0xA7E6 0x6273 # 0 +0xA7E7 0x6292 # 0 +0xA7E8 0x626F # 0 +0xA7E9 0x6298 # 0 +0xA7EA 0x626E # 0 +0xA7EB 0x6295 # 0 +0xA7EC 0x6293 # 0 +0xA7ED 0x6291 # 0 +0xA7EE 0x6286 # 0 +0xA7EF 0x6539 # 0 +0xA7F0 0x653B # 0 +0xA7F1 0x6538 # 0 +0xA7F2 0x65F1 # 0 +0xA7F3 0x66F4 # 0 +0xA7F4 0x675F # 0 +0xA7F5 0x674E # 0 +0xA7F6 0x674F # 0 +0xA7F7 0x6750 # 0 +0xA7F8 0x6751 # 0 +0xA7F9 0x675C # 0 +0xA7FA 0x6756 # 0 +0xA7FB 0x675E # 0 +0xA7FC 0x6749 # 0 +0xA7FD 0x6746 # 0 +0xA7FE 0x6760 # 0 +0xA840 0x6753 # 0 +0xA841 0x6757 # 0 +0xA842 0x6B65 # 0 +0xA843 0x6BCF # 0 +0xA844 0x6C42 # 0 +0xA845 0x6C5E # 0 +0xA846 0x6C99 # 0 +0xA847 0x6C81 # 0 +0xA848 0x6C88 # 0 +0xA849 0x6C89 # 0 +0xA84A 0x6C85 # 0 +0xA84B 0x6C9B # 0 +0xA84C 0x6C6A # 0 +0xA84D 0x6C7A # 0 +0xA84E 0x6C90 # 0 +0xA84F 0x6C70 # 0 +0xA850 0x6C8C # 0 +0xA851 0x6C68 # 0 +0xA852 0x6C96 # 0 +0xA853 0x6C92 # 0 +0xA854 0x6C7D # 0 +0xA855 0x6C83 # 0 +0xA856 0x6C72 # 0 +0xA857 0x6C7E # 0 +0xA858 0x6C74 # 0 +0xA859 0x6C86 # 0 +0xA85A 0x6C76 # 0 +0xA85B 0x6C8D # 0 +0xA85C 0x6C94 # 0 +0xA85D 0x6C98 # 0 +0xA85E 0x6C82 # 0 +0xA85F 0x7076 # 0 +0xA860 0x707C # 0 +0xA861 0x707D # 0 +0xA862 0x7078 # 0 +0xA863 0x7262 # 0 +0xA864 0x7261 # 0 +0xA865 0x7260 # 0 +0xA866 0x72C4 # 0 +0xA867 0x72C2 # 0 +0xA868 0x7396 # 0 +0xA869 0x752C # 0 +0xA86A 0x752B # 0 +0xA86B 0x7537 # 0 +0xA86C 0x7538 # 0 +0xA86D 0x7682 # 0 +0xA86E 0x76EF # 0 +0xA86F 0x77E3 # 0 +0xA870 0x79C1 # 0 +0xA871 0x79C0 # 0 +0xA872 0x79BF # 0 +0xA873 0x7A76 # 0 +0xA874 0x7CFB # 0 +0xA875 0x7F55 # 0 +0xA876 0x8096 # 0 +0xA877 0x8093 # 0 +0xA878 0x809D # 0 +0xA879 0x8098 # 0 +0xA87A 0x809B # 0 +0xA87B 0x809A # 0 +0xA87C 0x80B2 # 0 +0xA87D 0x826F # 0 +0xA87E 0x8292 # 0 +0xA8A1 0x828B # 0 +0xA8A2 0x828D # 0 +0xA8A3 0x898B # 0 +0xA8A4 0x89D2 # 0 +0xA8A5 0x8A00 # 0 +0xA8A6 0x8C37 # 0 +0xA8A7 0x8C46 # 0 +0xA8A8 0x8C55 # 0 +0xA8A9 0x8C9D # 0 +0xA8AA 0x8D64 # 0 +0xA8AB 0x8D70 # 0 +0xA8AC 0x8DB3 # 0 +0xA8AD 0x8EAB # 0 +0xA8AE 0x8ECA # 0 +0xA8AF 0x8F9B # 0 +0xA8B0 0x8FB0 # 0 +0xA8B1 0x8FC2 # 0 +0xA8B2 0x8FC6 # 0 +0xA8B3 0x8FC5 # 0 +0xA8B4 0x8FC4 # 0 +0xA8B5 0x5DE1 # 0 +0xA8B6 0x9091 # 0 +0xA8B7 0x90A2 # 0 +0xA8B8 0x90AA # 0 +0xA8B9 0x90A6 # 0 +0xA8BA 0x90A3 # 0 +0xA8BB 0x9149 # 0 +0xA8BC 0x91C6 # 0 +0xA8BD 0x91CC # 0 +0xA8BE 0x9632 # 0 +0xA8BF 0x962E # 0 +0xA8C0 0x9631 # 0 +0xA8C1 0x962A # 0 +0xA8C2 0x962C # 0 +0xA8C3 0x4E26 # 0 +0xA8C4 0x4E56 # 0 +0xA8C5 0x4E73 # 0 +0xA8C6 0x4E8B # 0 +0xA8C7 0x4E9B # 0 +0xA8C8 0x4E9E # 0 +0xA8C9 0x4EAB # 0 +0xA8CA 0x4EAC # 0 +0xA8CB 0x4F6F # 0 +0xA8CC 0x4F9D # 0 +0xA8CD 0x4F8D # 0 +0xA8CE 0x4F73 # 0 +0xA8CF 0x4F7F # 0 +0xA8D0 0x4F6C # 0 +0xA8D1 0x4F9B # 0 +0xA8D2 0x4F8B # 0 +0xA8D3 0x4F86 # 0 +0xA8D4 0x4F83 # 0 +0xA8D5 0x4F70 # 0 +0xA8D6 0x4F75 # 0 +0xA8D7 0x4F88 # 0 +0xA8D8 0x4F69 # 0 +0xA8D9 0x4F7B # 0 +0xA8DA 0x4F96 # 0 +0xA8DB 0x4F7E # 0 +0xA8DC 0x4F8F # 0 +0xA8DD 0x4F91 # 0 +0xA8DE 0x4F7A # 0 +0xA8DF 0x5154 # 0 +0xA8E0 0x5152 # 0 +0xA8E1 0x5155 # 0 +0xA8E2 0x5169 # 0 +0xA8E3 0x5177 # 0 +0xA8E4 0x5176 # 0 +0xA8E5 0x5178 # 0 +0xA8E6 0x51BD # 0 +0xA8E7 0x51FD # 0 +0xA8E8 0x523B # 0 +0xA8E9 0x5238 # 0 +0xA8EA 0x5237 # 0 +0xA8EB 0x523A # 0 +0xA8EC 0x5230 # 0 +0xA8ED 0x522E # 0 +0xA8EE 0x5236 # 0 +0xA8EF 0x5241 # 0 +0xA8F0 0x52BE # 0 +0xA8F1 0x52BB # 0 +0xA8F2 0x5352 # 0 +0xA8F3 0x5354 # 0 +0xA8F4 0x5353 # 0 +0xA8F5 0x5351 # 0 +0xA8F6 0x5366 # 0 +0xA8F7 0x5377 # 0 +0xA8F8 0x5378 # 0 +0xA8F9 0x5379 # 0 +0xA8FA 0x53D6 # 0 +0xA8FB 0x53D4 # 0 +0xA8FC 0x53D7 # 0 +0xA8FD 0x5473 # 0 +0xA8FE 0x5475 # 0 +0xA940 0x5496 # 0 +0xA941 0x5478 # 0 +0xA942 0x5495 # 0 +0xA943 0x5480 # 0 +0xA944 0x547B # 0 +0xA945 0x5477 # 0 +0xA946 0x5484 # 0 +0xA947 0x5492 # 0 +0xA948 0x5486 # 0 +0xA949 0x547C # 0 +0xA94A 0x5490 # 0 +0xA94B 0x5471 # 0 +0xA94C 0x5476 # 0 +0xA94D 0x548C # 0 +0xA94E 0x549A # 0 +0xA94F 0x5462 # 0 +0xA950 0x5468 # 0 +0xA951 0x548B # 0 +0xA952 0x547D # 0 +0xA953 0x548E # 0 +0xA954 0x56FA # 0 +0xA955 0x5783 # 0 +0xA956 0x5777 # 0 +0xA957 0x576A # 0 +0xA958 0x5769 # 0 +0xA959 0x5761 # 0 +0xA95A 0x5766 # 0 +0xA95B 0x5764 # 0 +0xA95C 0x577C # 0 +0xA95D 0x591C # 0 +0xA95E 0x5949 # 0 +0xA95F 0x5947 # 0 +0xA960 0x5948 # 0 +0xA961 0x5944 # 0 +0xA962 0x5954 # 0 +0xA963 0x59BE # 0 +0xA964 0x59BB # 0 +0xA965 0x59D4 # 0 +0xA966 0x59B9 # 0 +0xA967 0x59AE # 0 +0xA968 0x59D1 # 0 +0xA969 0x59C6 # 0 +0xA96A 0x59D0 # 0 +0xA96B 0x59CD # 0 +0xA96C 0x59CB # 0 +0xA96D 0x59D3 # 0 +0xA96E 0x59CA # 0 +0xA96F 0x59AF # 0 +0xA970 0x59B3 # 0 +0xA971 0x59D2 # 0 +0xA972 0x59C5 # 0 +0xA973 0x5B5F # 0 +0xA974 0x5B64 # 0 +0xA975 0x5B63 # 0 +0xA976 0x5B97 # 0 +0xA977 0x5B9A # 0 +0xA978 0x5B98 # 0 +0xA979 0x5B9C # 0 +0xA97A 0x5B99 # 0 +0xA97B 0x5B9B # 0 +0xA97C 0x5C1A # 0 +0xA97D 0x5C48 # 0 +0xA97E 0x5C45 # 0 +0xA9A1 0x5C46 # 0 +0xA9A2 0x5CB7 # 0 +0xA9A3 0x5CA1 # 0 +0xA9A4 0x5CB8 # 0 +0xA9A5 0x5CA9 # 0 +0xA9A6 0x5CAB # 0 +0xA9A7 0x5CB1 # 0 +0xA9A8 0x5CB3 # 0 +0xA9A9 0x5E18 # 0 +0xA9AA 0x5E1A # 0 +0xA9AB 0x5E16 # 0 +0xA9AC 0x5E15 # 0 +0xA9AD 0x5E1B # 0 +0xA9AE 0x5E11 # 0 +0xA9AF 0x5E78 # 0 +0xA9B0 0x5E9A # 0 +0xA9B1 0x5E97 # 0 +0xA9B2 0x5E9C # 0 +0xA9B3 0x5E95 # 0 +0xA9B4 0x5E96 # 0 +0xA9B5 0x5EF6 # 0 +0xA9B6 0x5F26 # 0 +0xA9B7 0x5F27 # 0 +0xA9B8 0x5F29 # 0 +0xA9B9 0x5F80 # 0 +0xA9BA 0x5F81 # 0 +0xA9BB 0x5F7F # 0 +0xA9BC 0x5F7C # 0 +0xA9BD 0x5FDD # 0 +0xA9BE 0x5FE0 # 0 +0xA9BF 0x5FFD # 0 +0xA9C0 0x5FF5 # 0 +0xA9C1 0x5FFF # 0 +0xA9C2 0x600F # 0 +0xA9C3 0x6014 # 0 +0xA9C4 0x602F # 0 +0xA9C5 0x6035 # 0 +0xA9C6 0x6016 # 0 +0xA9C7 0x602A # 0 +0xA9C8 0x6015 # 0 +0xA9C9 0x6021 # 0 +0xA9CA 0x6027 # 0 +0xA9CB 0x6029 # 0 +0xA9CC 0x602B # 0 +0xA9CD 0x601B # 0 +0xA9CE 0x6216 # 0 +0xA9CF 0x6215 # 0 +0xA9D0 0x623F # 0 +0xA9D1 0x623E # 0 +0xA9D2 0x6240 # 0 +0xA9D3 0x627F # 0 +0xA9D4 0x62C9 # 0 +0xA9D5 0x62CC # 0 +0xA9D6 0x62C4 # 0 +0xA9D7 0x62BF # 0 +0xA9D8 0x62C2 # 0 +0xA9D9 0x62B9 # 0 +0xA9DA 0x62D2 # 0 +0xA9DB 0x62DB # 0 +0xA9DC 0x62AB # 0 +0xA9DD 0x62D3 # 0 +0xA9DE 0x62D4 # 0 +0xA9DF 0x62CB # 0 +0xA9E0 0x62C8 # 0 +0xA9E1 0x62A8 # 0 +0xA9E2 0x62BD # 0 +0xA9E3 0x62BC # 0 +0xA9E4 0x62D0 # 0 +0xA9E5 0x62D9 # 0 +0xA9E6 0x62C7 # 0 +0xA9E7 0x62CD # 0 +0xA9E8 0x62B5 # 0 +0xA9E9 0x62DA # 0 +0xA9EA 0x62B1 # 0 +0xA9EB 0x62D8 # 0 +0xA9EC 0x62D6 # 0 +0xA9ED 0x62D7 # 0 +0xA9EE 0x62C6 # 0 +0xA9EF 0x62AC # 0 +0xA9F0 0x62CE # 0 +0xA9F1 0x653E # 0 +0xA9F2 0x65A7 # 0 +0xA9F3 0x65BC # 0 +0xA9F4 0x65FA # 0 +0xA9F5 0x6614 # 0 +0xA9F6 0x6613 # 0 +0xA9F7 0x660C # 0 +0xA9F8 0x6606 # 0 +0xA9F9 0x6602 # 0 +0xA9FA 0x660E # 0 +0xA9FB 0x6600 # 0 +0xA9FC 0x660F # 0 +0xA9FD 0x6615 # 0 +0xA9FE 0x660A # 0 +0xAA40 0x6607 # 0 +0xAA41 0x670D # 0 +0xAA42 0x670B # 0 +0xAA43 0x676D # 0 +0xAA44 0x678B # 0 +0xAA45 0x6795 # 0 +0xAA46 0x6771 # 0 +0xAA47 0x679C # 0 +0xAA48 0x6773 # 0 +0xAA49 0x6777 # 0 +0xAA4A 0x6787 # 0 +0xAA4B 0x679D # 0 +0xAA4C 0x6797 # 0 +0xAA4D 0x676F # 0 +0xAA4E 0x6770 # 0 +0xAA4F 0x677F # 0 +0xAA50 0x6789 # 0 +0xAA51 0x677E # 0 +0xAA52 0x6790 # 0 +0xAA53 0x6775 # 0 +0xAA54 0x679A # 0 +0xAA55 0x6793 # 0 +0xAA56 0x677C # 0 +0xAA57 0x676A # 0 +0xAA58 0x6772 # 0 +0xAA59 0x6B23 # 0 +0xAA5A 0x6B66 # 0 +0xAA5B 0x6B67 # 0 +0xAA5C 0x6B7F # 0 +0xAA5D 0x6C13 # 0 +0xAA5E 0x6C1B # 0 +0xAA5F 0x6CE3 # 0 +0xAA60 0x6CE8 # 0 +0xAA61 0x6CF3 # 0 +0xAA62 0x6CB1 # 0 +0xAA63 0x6CCC # 0 +0xAA64 0x6CE5 # 0 +0xAA65 0x6CB3 # 0 +0xAA66 0x6CBD # 0 +0xAA67 0x6CBE # 0 +0xAA68 0x6CBC # 0 +0xAA69 0x6CE2 # 0 +0xAA6A 0x6CAB # 0 +0xAA6B 0x6CD5 # 0 +0xAA6C 0x6CD3 # 0 +0xAA6D 0x6CB8 # 0 +0xAA6E 0x6CC4 # 0 +0xAA6F 0x6CB9 # 0 +0xAA70 0x6CC1 # 0 +0xAA71 0x6CAE # 0 +0xAA72 0x6CD7 # 0 +0xAA73 0x6CC5 # 0 +0xAA74 0x6CF1 # 0 +0xAA75 0x6CBF # 0 +0xAA76 0x6CBB # 0 +0xAA77 0x6CE1 # 0 +0xAA78 0x6CDB # 0 +0xAA79 0x6CCA # 0 +0xAA7A 0x6CAC # 0 +0xAA7B 0x6CEF # 0 +0xAA7C 0x6CDC # 0 +0xAA7D 0x6CD6 # 0 +0xAA7E 0x6CE0 # 0 +0xAAA1 0x7095 # 0 +0xAAA2 0x708E # 0 +0xAAA3 0x7092 # 0 +0xAAA4 0x708A # 0 +0xAAA5 0x7099 # 0 +0xAAA6 0x722C # 0 +0xAAA7 0x722D # 0 +0xAAA8 0x7238 # 0 +0xAAA9 0x7248 # 0 +0xAAAA 0x7267 # 0 +0xAAAB 0x7269 # 0 +0xAAAC 0x72C0 # 0 +0xAAAD 0x72CE # 0 +0xAAAE 0x72D9 # 0 +0xAAAF 0x72D7 # 0 +0xAAB0 0x72D0 # 0 +0xAAB1 0x73A9 # 0 +0xAAB2 0x73A8 # 0 +0xAAB3 0x739F # 0 +0xAAB4 0x73AB # 0 +0xAAB5 0x73A5 # 0 +0xAAB6 0x753D # 0 +0xAAB7 0x759D # 0 +0xAAB8 0x7599 # 0 +0xAAB9 0x759A # 0 +0xAABA 0x7684 # 0 +0xAABB 0x76C2 # 0 +0xAABC 0x76F2 # 0 +0xAABD 0x76F4 # 0 +0xAABE 0x77E5 # 0 +0xAABF 0x77FD # 0 +0xAAC0 0x793E # 0 +0xAAC1 0x7940 # 0 +0xAAC2 0x7941 # 0 +0xAAC3 0x79C9 # 0 +0xAAC4 0x79C8 # 0 +0xAAC5 0x7A7A # 0 +0xAAC6 0x7A79 # 0 +0xAAC7 0x7AFA # 0 +0xAAC8 0x7CFE # 0 +0xAAC9 0x7F54 # 0 +0xAACA 0x7F8C # 0 +0xAACB 0x7F8B # 0 +0xAACC 0x8005 # 0 +0xAACD 0x80BA # 0 +0xAACE 0x80A5 # 0 +0xAACF 0x80A2 # 0 +0xAAD0 0x80B1 # 0 +0xAAD1 0x80A1 # 0 +0xAAD2 0x80AB # 0 +0xAAD3 0x80A9 # 0 +0xAAD4 0x80B4 # 0 +0xAAD5 0x80AA # 0 +0xAAD6 0x80AF # 0 +0xAAD7 0x81E5 # 0 +0xAAD8 0x81FE # 0 +0xAAD9 0x820D # 0 +0xAADA 0x82B3 # 0 +0xAADB 0x829D # 0 +0xAADC 0x8299 # 0 +0xAADD 0x82AD # 0 +0xAADE 0x82BD # 0 +0xAADF 0x829F # 0 +0xAAE0 0x82B9 # 0 +0xAAE1 0x82B1 # 0 +0xAAE2 0x82AC # 0 +0xAAE3 0x82A5 # 0 +0xAAE4 0x82AF # 0 +0xAAE5 0x82B8 # 0 +0xAAE6 0x82A3 # 0 +0xAAE7 0x82B0 # 0 +0xAAE8 0x82BE # 0 +0xAAE9 0x82B7 # 0 +0xAAEA 0x864E # 0 +0xAAEB 0x8671 # 0 +0xAAEC 0x521D # 0 +0xAAED 0x8868 # 0 +0xAAEE 0x8ECB # 0 +0xAAEF 0x8FCE # 0 +0xAAF0 0x8FD4 # 0 +0xAAF1 0x8FD1 # 0 +0xAAF2 0x90B5 # 0 +0xAAF3 0x90B8 # 0 +0xAAF4 0x90B1 # 0 +0xAAF5 0x90B6 # 0 +0xAAF6 0x91C7 # 0 +0xAAF7 0x91D1 # 0 +0xAAF8 0x9577 # 0 +0xAAF9 0x9580 # 0 +0xAAFA 0x961C # 0 +0xAAFB 0x9640 # 0 +0xAAFC 0x963F # 0 +0xAAFD 0x963B # 0 +0xAAFE 0x9644 # 0 +0xAB40 0x9642 # 0 +0xAB41 0x96B9 # 0 +0xAB42 0x96E8 # 0 +0xAB43 0x9752 # 0 +0xAB44 0x975E # 0 +0xAB45 0x4E9F # 0 +0xAB46 0x4EAD # 0 +0xAB47 0x4EAE # 0 +0xAB48 0x4FE1 # 0 +0xAB49 0x4FB5 # 0 +0xAB4A 0x4FAF # 0 +0xAB4B 0x4FBF # 0 +0xAB4C 0x4FE0 # 0 +0xAB4D 0x4FD1 # 0 +0xAB4E 0x4FCF # 0 +0xAB4F 0x4FDD # 0 +0xAB50 0x4FC3 # 0 +0xAB51 0x4FB6 # 0 +0xAB52 0x4FD8 # 0 +0xAB53 0x4FDF # 0 +0xAB54 0x4FCA # 0 +0xAB55 0x4FD7 # 0 +0xAB56 0x4FAE # 0 +0xAB57 0x4FD0 # 0 +0xAB58 0x4FC4 # 0 +0xAB59 0x4FC2 # 0 +0xAB5A 0x4FDA # 0 +0xAB5B 0x4FCE # 0 +0xAB5C 0x4FDE # 0 +0xAB5D 0x4FB7 # 0 +0xAB5E 0x5157 # 0 +0xAB5F 0x5192 # 0 +0xAB60 0x5191 # 0 +0xAB61 0x51A0 # 0 +0xAB62 0x524E # 0 +0xAB63 0x5243 # 0 +0xAB64 0x524A # 0 +0xAB65 0x524D # 0 +0xAB66 0x524C # 0 +0xAB67 0x524B # 0 +0xAB68 0x5247 # 0 +0xAB69 0x52C7 # 0 +0xAB6A 0x52C9 # 0 +0xAB6B 0x52C3 # 0 +0xAB6C 0x52C1 # 0 +0xAB6D 0x530D # 0 +0xAB6E 0x5357 # 0 +0xAB6F 0x537B # 0 +0xAB70 0x539A # 0 +0xAB71 0x53DB # 0 +0xAB72 0x54AC # 0 +0xAB73 0x54C0 # 0 +0xAB74 0x54A8 # 0 +0xAB75 0x54CE # 0 +0xAB76 0x54C9 # 0 +0xAB77 0x54B8 # 0 +0xAB78 0x54A6 # 0 +0xAB79 0x54B3 # 0 +0xAB7A 0x54C7 # 0 +0xAB7B 0x54C2 # 0 +0xAB7C 0x54BD # 0 +0xAB7D 0x54AA # 0 +0xAB7E 0x54C1 # 0 +0xABA1 0x54C4 # 0 +0xABA2 0x54C8 # 0 +0xABA3 0x54AF # 0 +0xABA4 0x54AB # 0 +0xABA5 0x54B1 # 0 +0xABA6 0x54BB # 0 +0xABA7 0x54A9 # 0 +0xABA8 0x54A7 # 0 +0xABA9 0x54BF # 0 +0xABAA 0x56FF # 0 +0xABAB 0x5782 # 0 +0xABAC 0x578B # 0 +0xABAD 0x57A0 # 0 +0xABAE 0x57A3 # 0 +0xABAF 0x57A2 # 0 +0xABB0 0x57CE # 0 +0xABB1 0x57AE # 0 +0xABB2 0x5793 # 0 +0xABB3 0x5955 # 0 +0xABB4 0x5951 # 0 +0xABB5 0x594F # 0 +0xABB6 0x594E # 0 +0xABB7 0x5950 # 0 +0xABB8 0x59DC # 0 +0xABB9 0x59D8 # 0 +0xABBA 0x59FF # 0 +0xABBB 0x59E3 # 0 +0xABBC 0x59E8 # 0 +0xABBD 0x5A03 # 0 +0xABBE 0x59E5 # 0 +0xABBF 0x59EA # 0 +0xABC0 0x59DA # 0 +0xABC1 0x59E6 # 0 +0xABC2 0x5A01 # 0 +0xABC3 0x59FB # 0 +0xABC4 0x5B69 # 0 +0xABC5 0x5BA3 # 0 +0xABC6 0x5BA6 # 0 +0xABC7 0x5BA4 # 0 +0xABC8 0x5BA2 # 0 +0xABC9 0x5BA5 # 0 +0xABCA 0x5C01 # 0 +0xABCB 0x5C4E # 0 +0xABCC 0x5C4F # 0 +0xABCD 0x5C4D # 0 +0xABCE 0x5C4B # 0 +0xABCF 0x5CD9 # 0 +0xABD0 0x5CD2 # 0 +0xABD1 0x5DF7 # 0 +0xABD2 0x5E1D # 0 +0xABD3 0x5E25 # 0 +0xABD4 0x5E1F # 0 +0xABD5 0x5E7D # 0 +0xABD6 0x5EA0 # 0 +0xABD7 0x5EA6 # 0 +0xABD8 0x5EFA # 0 +0xABD9 0x5F08 # 0 +0xABDA 0x5F2D # 0 +0xABDB 0x5F65 # 0 +0xABDC 0x5F88 # 0 +0xABDD 0x5F85 # 0 +0xABDE 0x5F8A # 0 +0xABDF 0x5F8B # 0 +0xABE0 0x5F87 # 0 +0xABE1 0x5F8C # 0 +0xABE2 0x5F89 # 0 +0xABE3 0x6012 # 0 +0xABE4 0x601D # 0 +0xABE5 0x6020 # 0 +0xABE6 0x6025 # 0 +0xABE7 0x600E # 0 +0xABE8 0x6028 # 0 +0xABE9 0x604D # 0 +0xABEA 0x6070 # 0 +0xABEB 0x6068 # 0 +0xABEC 0x6062 # 0 +0xABED 0x6046 # 0 +0xABEE 0x6043 # 0 +0xABEF 0x606C # 0 +0xABF0 0x606B # 0 +0xABF1 0x606A # 0 +0xABF2 0x6064 # 0 +0xABF3 0x6241 # 0 +0xABF4 0x62DC # 0 +0xABF5 0x6316 # 0 +0xABF6 0x6309 # 0 +0xABF7 0x62FC # 0 +0xABF8 0x62ED # 0 +0xABF9 0x6301 # 0 +0xABFA 0x62EE # 0 +0xABFB 0x62FD # 0 +0xABFC 0x6307 # 0 +0xABFD 0x62F1 # 0 +0xABFE 0x62F7 # 0 +0xAC40 0x62EF # 0 +0xAC41 0x62EC # 0 +0xAC42 0x62FE # 0 +0xAC43 0x62F4 # 0 +0xAC44 0x6311 # 0 +0xAC45 0x6302 # 0 +0xAC46 0x653F # 0 +0xAC47 0x6545 # 0 +0xAC48 0x65AB # 0 +0xAC49 0x65BD # 0 +0xAC4A 0x65E2 # 0 +0xAC4B 0x6625 # 0 +0xAC4C 0x662D # 0 +0xAC4D 0x6620 # 0 +0xAC4E 0x6627 # 0 +0xAC4F 0x662F # 0 +0xAC50 0x661F # 0 +0xAC51 0x6628 # 0 +0xAC52 0x6631 # 0 +0xAC53 0x6624 # 0 +0xAC54 0x66F7 # 0 +0xAC55 0x67FF # 0 +0xAC56 0x67D3 # 0 +0xAC57 0x67F1 # 0 +0xAC58 0x67D4 # 0 +0xAC59 0x67D0 # 0 +0xAC5A 0x67EC # 0 +0xAC5B 0x67B6 # 0 +0xAC5C 0x67AF # 0 +0xAC5D 0x67F5 # 0 +0xAC5E 0x67E9 # 0 +0xAC5F 0x67EF # 0 +0xAC60 0x67C4 # 0 +0xAC61 0x67D1 # 0 +0xAC62 0x67B4 # 0 +0xAC63 0x67DA # 0 +0xAC64 0x67E5 # 0 +0xAC65 0x67B8 # 0 +0xAC66 0x67CF # 0 +0xAC67 0x67DE # 0 +0xAC68 0x67F3 # 0 +0xAC69 0x67B0 # 0 +0xAC6A 0x67D9 # 0 +0xAC6B 0x67E2 # 0 +0xAC6C 0x67DD # 0 +0xAC6D 0x67D2 # 0 +0xAC6E 0x6B6A # 0 +0xAC6F 0x6B83 # 0 +0xAC70 0x6B86 # 0 +0xAC71 0x6BB5 # 0 +0xAC72 0x6BD2 # 0 +0xAC73 0x6BD7 # 0 +0xAC74 0x6C1F # 0 +0xAC75 0x6CC9 # 0 +0xAC76 0x6D0B # 0 +0xAC77 0x6D32 # 0 +0xAC78 0x6D2A # 0 +0xAC79 0x6D41 # 0 +0xAC7A 0x6D25 # 0 +0xAC7B 0x6D0C # 0 +0xAC7C 0x6D31 # 0 +0xAC7D 0x6D1E # 0 +0xAC7E 0x6D17 # 0 +0xACA1 0x6D3B # 0 +0xACA2 0x6D3D # 0 +0xACA3 0x6D3E # 0 +0xACA4 0x6D36 # 0 +0xACA5 0x6D1B # 0 +0xACA6 0x6CF5 # 0 +0xACA7 0x6D39 # 0 +0xACA8 0x6D27 # 0 +0xACA9 0x6D38 # 0 +0xACAA 0x6D29 # 0 +0xACAB 0x6D2E # 0 +0xACAC 0x6D35 # 0 +0xACAD 0x6D0E # 0 +0xACAE 0x6D2B # 0 +0xACAF 0x70AB # 0 +0xACB0 0x70BA # 0 +0xACB1 0x70B3 # 0 +0xACB2 0x70AC # 0 +0xACB3 0x70AF # 0 +0xACB4 0x70AD # 0 +0xACB5 0x70B8 # 0 +0xACB6 0x70AE # 0 +0xACB7 0x70A4 # 0 +0xACB8 0x7230 # 0 +0xACB9 0x7272 # 0 +0xACBA 0x726F # 0 +0xACBB 0x7274 # 0 +0xACBC 0x72E9 # 0 +0xACBD 0x72E0 # 0 +0xACBE 0x72E1 # 0 +0xACBF 0x73B7 # 0 +0xACC0 0x73CA # 0 +0xACC1 0x73BB # 0 +0xACC2 0x73B2 # 0 +0xACC3 0x73CD # 0 +0xACC4 0x73C0 # 0 +0xACC5 0x73B3 # 0 +0xACC6 0x751A # 0 +0xACC7 0x752D # 0 +0xACC8 0x754F # 0 +0xACC9 0x754C # 0 +0xACCA 0x754E # 0 +0xACCB 0x754B # 0 +0xACCC 0x75AB # 0 +0xACCD 0x75A4 # 0 +0xACCE 0x75A5 # 0 +0xACCF 0x75A2 # 0 +0xACD0 0x75A3 # 0 +0xACD1 0x7678 # 0 +0xACD2 0x7686 # 0 +0xACD3 0x7687 # 0 +0xACD4 0x7688 # 0 +0xACD5 0x76C8 # 0 +0xACD6 0x76C6 # 0 +0xACD7 0x76C3 # 0 +0xACD8 0x76C5 # 0 +0xACD9 0x7701 # 0 +0xACDA 0x76F9 # 0 +0xACDB 0x76F8 # 0 +0xACDC 0x7709 # 0 +0xACDD 0x770B # 0 +0xACDE 0x76FE # 0 +0xACDF 0x76FC # 0 +0xACE0 0x7707 # 0 +0xACE1 0x77DC # 0 +0xACE2 0x7802 # 0 +0xACE3 0x7814 # 0 +0xACE4 0x780C # 0 +0xACE5 0x780D # 0 +0xACE6 0x7946 # 0 +0xACE7 0x7949 # 0 +0xACE8 0x7948 # 0 +0xACE9 0x7947 # 0 +0xACEA 0x79B9 # 0 +0xACEB 0x79BA # 0 +0xACEC 0x79D1 # 0 +0xACED 0x79D2 # 0 +0xACEE 0x79CB # 0 +0xACEF 0x7A7F # 0 +0xACF0 0x7A81 # 0 +0xACF1 0x7AFF # 0 +0xACF2 0x7AFD # 0 +0xACF3 0x7C7D # 0 +0xACF4 0x7D02 # 0 +0xACF5 0x7D05 # 0 +0xACF6 0x7D00 # 0 +0xACF7 0x7D09 # 0 +0xACF8 0x7D07 # 0 +0xACF9 0x7D04 # 0 +0xACFA 0x7D06 # 0 +0xACFB 0x7F38 # 0 +0xACFC 0x7F8E # 0 +0xACFD 0x7FBF # 0 +0xACFE 0x8004 # 0 +0xAD40 0x8010 # 0 +0xAD41 0x800D # 0 +0xAD42 0x8011 # 0 +0xAD43 0x8036 # 0 +0xAD44 0x80D6 # 0 +0xAD45 0x80E5 # 0 +0xAD46 0x80DA # 0 +0xAD47 0x80C3 # 0 +0xAD48 0x80C4 # 0 +0xAD49 0x80CC # 0 +0xAD4A 0x80E1 # 0 +0xAD4B 0x80DB # 0 +0xAD4C 0x80CE # 0 +0xAD4D 0x80DE # 0 +0xAD4E 0x80E4 # 0 +0xAD4F 0x80DD # 0 +0xAD50 0x81F4 # 0 +0xAD51 0x8222 # 0 +0xAD52 0x82E7 # 0 +0xAD53 0x8303 # 0 +0xAD54 0x8305 # 0 +0xAD55 0x82E3 # 0 +0xAD56 0x82DB # 0 +0xAD57 0x82E6 # 0 +0xAD58 0x8304 # 0 +0xAD59 0x82E5 # 0 +0xAD5A 0x8302 # 0 +0xAD5B 0x8309 # 0 +0xAD5C 0x82D2 # 0 +0xAD5D 0x82D7 # 0 +0xAD5E 0x82F1 # 0 +0xAD5F 0x8301 # 0 +0xAD60 0x82DC # 0 +0xAD61 0x82D4 # 0 +0xAD62 0x82D1 # 0 +0xAD63 0x82DE # 0 +0xAD64 0x82D3 # 0 +0xAD65 0x82DF # 0 +0xAD66 0x82EF # 0 +0xAD67 0x8306 # 0 +0xAD68 0x8650 # 0 +0xAD69 0x8679 # 0 +0xAD6A 0x867B # 0 +0xAD6B 0x867A # 0 +0xAD6C 0x884D # 0 +0xAD6D 0x886B # 0 +0xAD6E 0x8981 # 0 +0xAD6F 0x89D4 # 0 +0xAD70 0x8A08 # 0 +0xAD71 0x8A02 # 0 +0xAD72 0x8A03 # 0 +0xAD73 0x8C9E # 0 +0xAD74 0x8CA0 # 0 +0xAD75 0x8D74 # 0 +0xAD76 0x8D73 # 0 +0xAD77 0x8DB4 # 0 +0xAD78 0x8ECD # 0 +0xAD79 0x8ECC # 0 +0xAD7A 0x8FF0 # 0 +0xAD7B 0x8FE6 # 0 +0xAD7C 0x8FE2 # 0 +0xAD7D 0x8FEA # 0 +0xAD7E 0x8FE5 # 0 +0xADA1 0x8FED # 0 +0xADA2 0x8FEB # 0 +0xADA3 0x8FE4 # 0 +0xADA4 0x8FE8 # 0 +0xADA5 0x90CA # 0 +0xADA6 0x90CE # 0 +0xADA7 0x90C1 # 0 +0xADA8 0x90C3 # 0 +0xADA9 0x914B # 0 +0xADAA 0x914A # 0 +0xADAB 0x91CD # 0 +0xADAC 0x9582 # 0 +0xADAD 0x9650 # 0 +0xADAE 0x964B # 0 +0xADAF 0x964C # 0 +0xADB0 0x964D # 0 +0xADB1 0x9762 # 0 +0xADB2 0x9769 # 0 +0xADB3 0x97CB # 0 +0xADB4 0x97ED # 0 +0xADB5 0x97F3 # 0 +0xADB6 0x9801 # 0 +0xADB7 0x98A8 # 0 +0xADB8 0x98DB # 0 +0xADB9 0x98DF # 0 +0xADBA 0x9996 # 0 +0xADBB 0x9999 # 0 +0xADBC 0x4E58 # 0 +0xADBD 0x4EB3 # 0 +0xADBE 0x500C # 0 +0xADBF 0x500D # 0 +0xADC0 0x5023 # 0 +0xADC1 0x4FEF # 0 +0xADC2 0x5026 # 0 +0xADC3 0x5025 # 0 +0xADC4 0x4FF8 # 0 +0xADC5 0x5029 # 0 +0xADC6 0x5016 # 0 +0xADC7 0x5006 # 0 +0xADC8 0x503C # 0 +0xADC9 0x501F # 0 +0xADCA 0x501A # 0 +0xADCB 0x5012 # 0 +0xADCC 0x5011 # 0 +0xADCD 0x4FFA # 0 +0xADCE 0x5000 # 0 +0xADCF 0x5014 # 0 +0xADD0 0x5028 # 0 +0xADD1 0x4FF1 # 0 +0xADD2 0x5021 # 0 +0xADD3 0x500B # 0 +0xADD4 0x5019 # 0 +0xADD5 0x5018 # 0 +0xADD6 0x4FF3 # 0 +0xADD7 0x4FEE # 0 +0xADD8 0x502D # 0 +0xADD9 0x502A # 0 +0xADDA 0x4FFE # 0 +0xADDB 0x502B # 0 +0xADDC 0x5009 # 0 +0xADDD 0x517C # 0 +0xADDE 0x51A4 # 0 +0xADDF 0x51A5 # 0 +0xADE0 0x51A2 # 0 +0xADE1 0x51CD # 0 +0xADE2 0x51CC # 0 +0xADE3 0x51C6 # 0 +0xADE4 0x51CB # 0 +0xADE5 0x5256 # 0 +0xADE6 0x525C # 0 +0xADE7 0x5254 # 0 +0xADE8 0x525B # 0 +0xADE9 0x525D # 0 +0xADEA 0x532A # 0 +0xADEB 0x537F # 0 +0xADEC 0x539F # 0 +0xADED 0x539D # 0 +0xADEE 0x53DF # 0 +0xADEF 0x54E8 # 0 +0xADF0 0x5510 # 0 +0xADF1 0x5501 # 0 +0xADF2 0x5537 # 0 +0xADF3 0x54FC # 0 +0xADF4 0x54E5 # 0 +0xADF5 0x54F2 # 0 +0xADF6 0x5506 # 0 +0xADF7 0x54FA # 0 +0xADF8 0x5514 # 0 +0xADF9 0x54E9 # 0 +0xADFA 0x54ED # 0 +0xADFB 0x54E1 # 0 +0xADFC 0x5509 # 0 +0xADFD 0x54EE # 0 +0xADFE 0x54EA # 0 +0xAE40 0x54E6 # 0 +0xAE41 0x5527 # 0 +0xAE42 0x5507 # 0 +0xAE43 0x54FD # 0 +0xAE44 0x550F # 0 +0xAE45 0x5703 # 0 +0xAE46 0x5704 # 0 +0xAE47 0x57C2 # 0 +0xAE48 0x57D4 # 0 +0xAE49 0x57CB # 0 +0xAE4A 0x57C3 # 0 +0xAE4B 0x5809 # 0 +0xAE4C 0x590F # 0 +0xAE4D 0x5957 # 0 +0xAE4E 0x5958 # 0 +0xAE4F 0x595A # 0 +0xAE50 0x5A11 # 0 +0xAE51 0x5A18 # 0 +0xAE52 0x5A1C # 0 +0xAE53 0x5A1F # 0 +0xAE54 0x5A1B # 0 +0xAE55 0x5A13 # 0 +0xAE56 0x59EC # 0 +0xAE57 0x5A20 # 0 +0xAE58 0x5A23 # 0 +0xAE59 0x5A29 # 0 +0xAE5A 0x5A25 # 0 +0xAE5B 0x5A0C # 0 +0xAE5C 0x5A09 # 0 +0xAE5D 0x5B6B # 0 +0xAE5E 0x5C58 # 0 +0xAE5F 0x5BB0 # 0 +0xAE60 0x5BB3 # 0 +0xAE61 0x5BB6 # 0 +0xAE62 0x5BB4 # 0 +0xAE63 0x5BAE # 0 +0xAE64 0x5BB5 # 0 +0xAE65 0x5BB9 # 0 +0xAE66 0x5BB8 # 0 +0xAE67 0x5C04 # 0 +0xAE68 0x5C51 # 0 +0xAE69 0x5C55 # 0 +0xAE6A 0x5C50 # 0 +0xAE6B 0x5CED # 0 +0xAE6C 0x5CFD # 0 +0xAE6D 0x5CFB # 0 +0xAE6E 0x5CEA # 0 +0xAE6F 0x5CE8 # 0 +0xAE70 0x5CF0 # 0 +0xAE71 0x5CF6 # 0 +0xAE72 0x5D01 # 0 +0xAE73 0x5CF4 # 0 +0xAE74 0x5DEE # 0 +0xAE75 0x5E2D # 0 +0xAE76 0x5E2B # 0 +0xAE77 0x5EAB # 0 +0xAE78 0x5EAD # 0 +0xAE79 0x5EA7 # 0 +0xAE7A 0x5F31 # 0 +0xAE7B 0x5F92 # 0 +0xAE7C 0x5F91 # 0 +0xAE7D 0x5F90 # 0 +0xAE7E 0x6059 # 0 +0xAEA1 0x6063 # 0 +0xAEA2 0x6065 # 0 +0xAEA3 0x6050 # 0 +0xAEA4 0x6055 # 0 +0xAEA5 0x606D # 0 +0xAEA6 0x6069 # 0 +0xAEA7 0x606F # 0 +0xAEA8 0x6084 # 0 +0xAEA9 0x609F # 0 +0xAEAA 0x609A # 0 +0xAEAB 0x608D # 0 +0xAEAC 0x6094 # 0 +0xAEAD 0x608C # 0 +0xAEAE 0x6085 # 0 +0xAEAF 0x6096 # 0 +0xAEB0 0x6247 # 0 +0xAEB1 0x62F3 # 0 +0xAEB2 0x6308 # 0 +0xAEB3 0x62FF # 0 +0xAEB4 0x634E # 0 +0xAEB5 0x633E # 0 +0xAEB6 0x632F # 0 +0xAEB7 0x6355 # 0 +0xAEB8 0x6342 # 0 +0xAEB9 0x6346 # 0 +0xAEBA 0x634F # 0 +0xAEBB 0x6349 # 0 +0xAEBC 0x633A # 0 +0xAEBD 0x6350 # 0 +0xAEBE 0x633D # 0 +0xAEBF 0x632A # 0 +0xAEC0 0x632B # 0 +0xAEC1 0x6328 # 0 +0xAEC2 0x634D # 0 +0xAEC3 0x634C # 0 +0xAEC4 0x6548 # 0 +0xAEC5 0x6549 # 0 +0xAEC6 0x6599 # 0 +0xAEC7 0x65C1 # 0 +0xAEC8 0x65C5 # 0 +0xAEC9 0x6642 # 0 +0xAECA 0x6649 # 0 +0xAECB 0x664F # 0 +0xAECC 0x6643 # 0 +0xAECD 0x6652 # 0 +0xAECE 0x664C # 0 +0xAECF 0x6645 # 0 +0xAED0 0x6641 # 0 +0xAED1 0x66F8 # 0 +0xAED2 0x6714 # 0 +0xAED3 0x6715 # 0 +0xAED4 0x6717 # 0 +0xAED5 0x6821 # 0 +0xAED6 0x6838 # 0 +0xAED7 0x6848 # 0 +0xAED8 0x6846 # 0 +0xAED9 0x6853 # 0 +0xAEDA 0x6839 # 0 +0xAEDB 0x6842 # 0 +0xAEDC 0x6854 # 0 +0xAEDD 0x6829 # 0 +0xAEDE 0x68B3 # 0 +0xAEDF 0x6817 # 0 +0xAEE0 0x684C # 0 +0xAEE1 0x6851 # 0 +0xAEE2 0x683D # 0 +0xAEE3 0x67F4 # 0 +0xAEE4 0x6850 # 0 +0xAEE5 0x6840 # 0 +0xAEE6 0x683C # 0 +0xAEE7 0x6843 # 0 +0xAEE8 0x682A # 0 +0xAEE9 0x6845 # 0 +0xAEEA 0x6813 # 0 +0xAEEB 0x6818 # 0 +0xAEEC 0x6841 # 0 +0xAEED 0x6B8A # 0 +0xAEEE 0x6B89 # 0 +0xAEEF 0x6BB7 # 0 +0xAEF0 0x6C23 # 0 +0xAEF1 0x6C27 # 0 +0xAEF2 0x6C28 # 0 +0xAEF3 0x6C26 # 0 +0xAEF4 0x6C24 # 0 +0xAEF5 0x6CF0 # 0 +0xAEF6 0x6D6A # 0 +0xAEF7 0x6D95 # 0 +0xAEF8 0x6D88 # 0 +0xAEF9 0x6D87 # 0 +0xAEFA 0x6D66 # 0 +0xAEFB 0x6D78 # 0 +0xAEFC 0x6D77 # 0 +0xAEFD 0x6D59 # 0 +0xAEFE 0x6D93 # 0 +0xAF40 0x6D6C # 0 +0xAF41 0x6D89 # 0 +0xAF42 0x6D6E # 0 +0xAF43 0x6D5A # 0 +0xAF44 0x6D74 # 0 +0xAF45 0x6D69 # 0 +0xAF46 0x6D8C # 0 +0xAF47 0x6D8A # 0 +0xAF48 0x6D79 # 0 +0xAF49 0x6D85 # 0 +0xAF4A 0x6D65 # 0 +0xAF4B 0x6D94 # 0 +0xAF4C 0x70CA # 0 +0xAF4D 0x70D8 # 0 +0xAF4E 0x70E4 # 0 +0xAF4F 0x70D9 # 0 +0xAF50 0x70C8 # 0 +0xAF51 0x70CF # 0 +0xAF52 0x7239 # 0 +0xAF53 0x7279 # 0 +0xAF54 0x72FC # 0 +0xAF55 0x72F9 # 0 +0xAF56 0x72FD # 0 +0xAF57 0x72F8 # 0 +0xAF58 0x72F7 # 0 +0xAF59 0x7386 # 0 +0xAF5A 0x73ED # 0 +0xAF5B 0x7409 # 0 +0xAF5C 0x73EE # 0 +0xAF5D 0x73E0 # 0 +0xAF5E 0x73EA # 0 +0xAF5F 0x73DE # 0 +0xAF60 0x7554 # 0 +0xAF61 0x755D # 0 +0xAF62 0x755C # 0 +0xAF63 0x755A # 0 +0xAF64 0x7559 # 0 +0xAF65 0x75BE # 0 +0xAF66 0x75C5 # 0 +0xAF67 0x75C7 # 0 +0xAF68 0x75B2 # 0 +0xAF69 0x75B3 # 0 +0xAF6A 0x75BD # 0 +0xAF6B 0x75BC # 0 +0xAF6C 0x75B9 # 0 +0xAF6D 0x75C2 # 0 +0xAF6E 0x75B8 # 0 +0xAF6F 0x768B # 0 +0xAF70 0x76B0 # 0 +0xAF71 0x76CA # 0 +0xAF72 0x76CD # 0 +0xAF73 0x76CE # 0 +0xAF74 0x7729 # 0 +0xAF75 0x771F # 0 +0xAF76 0x7720 # 0 +0xAF77 0x7728 # 0 +0xAF78 0x77E9 # 0 +0xAF79 0x7830 # 0 +0xAF7A 0x7827 # 0 +0xAF7B 0x7838 # 0 +0xAF7C 0x781D # 0 +0xAF7D 0x7834 # 0 +0xAF7E 0x7837 # 0 +0xAFA1 0x7825 # 0 +0xAFA2 0x782D # 0 +0xAFA3 0x7820 # 0 +0xAFA4 0x781F # 0 +0xAFA5 0x7832 # 0 +0xAFA6 0x7955 # 0 +0xAFA7 0x7950 # 0 +0xAFA8 0x7960 # 0 +0xAFA9 0x795F # 0 +0xAFAA 0x7956 # 0 +0xAFAB 0x795E # 0 +0xAFAC 0x795D # 0 +0xAFAD 0x7957 # 0 +0xAFAE 0x795A # 0 +0xAFAF 0x79E4 # 0 +0xAFB0 0x79E3 # 0 +0xAFB1 0x79E7 # 0 +0xAFB2 0x79DF # 0 +0xAFB3 0x79E6 # 0 +0xAFB4 0x79E9 # 0 +0xAFB5 0x79D8 # 0 +0xAFB6 0x7A84 # 0 +0xAFB7 0x7A88 # 0 +0xAFB8 0x7AD9 # 0 +0xAFB9 0x7B06 # 0 +0xAFBA 0x7B11 # 0 +0xAFBB 0x7C89 # 0 +0xAFBC 0x7D21 # 0 +0xAFBD 0x7D17 # 0 +0xAFBE 0x7D0B # 0 +0xAFBF 0x7D0A # 0 +0xAFC0 0x7D20 # 0 +0xAFC1 0x7D22 # 0 +0xAFC2 0x7D14 # 0 +0xAFC3 0x7D10 # 0 +0xAFC4 0x7D15 # 0 +0xAFC5 0x7D1A # 0 +0xAFC6 0x7D1C # 0 +0xAFC7 0x7D0D # 0 +0xAFC8 0x7D19 # 0 +0xAFC9 0x7D1B # 0 +0xAFCA 0x7F3A # 0 +0xAFCB 0x7F5F # 0 +0xAFCC 0x7F94 # 0 +0xAFCD 0x7FC5 # 0 +0xAFCE 0x7FC1 # 0 +0xAFCF 0x8006 # 0 +0xAFD0 0x8018 # 0 +0xAFD1 0x8015 # 0 +0xAFD2 0x8019 # 0 +0xAFD3 0x8017 # 0 +0xAFD4 0x803D # 0 +0xAFD5 0x803F # 0 +0xAFD6 0x80F1 # 0 +0xAFD7 0x8102 # 0 +0xAFD8 0x80F0 # 0 +0xAFD9 0x8105 # 0 +0xAFDA 0x80ED # 0 +0xAFDB 0x80F4 # 0 +0xAFDC 0x8106 # 0 +0xAFDD 0x80F8 # 0 +0xAFDE 0x80F3 # 0 +0xAFDF 0x8108 # 0 +0xAFE0 0x80FD # 0 +0xAFE1 0x810A # 0 +0xAFE2 0x80FC # 0 +0xAFE3 0x80EF # 0 +0xAFE4 0x81ED # 0 +0xAFE5 0x81EC # 0 +0xAFE6 0x8200 # 0 +0xAFE7 0x8210 # 0 +0xAFE8 0x822A # 0 +0xAFE9 0x822B # 0 +0xAFEA 0x8228 # 0 +0xAFEB 0x822C # 0 +0xAFEC 0x82BB # 0 +0xAFED 0x832B # 0 +0xAFEE 0x8352 # 0 +0xAFEF 0x8354 # 0 +0xAFF0 0x834A # 0 +0xAFF1 0x8338 # 0 +0xAFF2 0x8350 # 0 +0xAFF3 0x8349 # 0 +0xAFF4 0x8335 # 0 +0xAFF5 0x8334 # 0 +0xAFF6 0x834F # 0 +0xAFF7 0x8332 # 0 +0xAFF8 0x8339 # 0 +0xAFF9 0x8336 # 0 +0xAFFA 0x8317 # 0 +0xAFFB 0x8340 # 0 +0xAFFC 0x8331 # 0 +0xAFFD 0x8328 # 0 +0xAFFE 0x8343 # 0 +0xB040 0x8654 # 0 +0xB041 0x868A # 0 +0xB042 0x86AA # 0 +0xB043 0x8693 # 0 +0xB044 0x86A4 # 0 +0xB045 0x86A9 # 0 +0xB046 0x868C # 0 +0xB047 0x86A3 # 0 +0xB048 0x869C # 0 +0xB049 0x8870 # 0 +0xB04A 0x8877 # 0 +0xB04B 0x8881 # 0 +0xB04C 0x8882 # 0 +0xB04D 0x887D # 0 +0xB04E 0x8879 # 0 +0xB04F 0x8A18 # 0 +0xB050 0x8A10 # 0 +0xB051 0x8A0E # 0 +0xB052 0x8A0C # 0 +0xB053 0x8A15 # 0 +0xB054 0x8A0A # 0 +0xB055 0x8A17 # 0 +0xB056 0x8A13 # 0 +0xB057 0x8A16 # 0 +0xB058 0x8A0F # 0 +0xB059 0x8A11 # 0 +0xB05A 0x8C48 # 0 +0xB05B 0x8C7A # 0 +0xB05C 0x8C79 # 0 +0xB05D 0x8CA1 # 0 +0xB05E 0x8CA2 # 0 +0xB05F 0x8D77 # 0 +0xB060 0x8EAC # 0 +0xB061 0x8ED2 # 0 +0xB062 0x8ED4 # 0 +0xB063 0x8ECF # 0 +0xB064 0x8FB1 # 0 +0xB065 0x9001 # 0 +0xB066 0x9006 # 0 +0xB067 0x8FF7 # 0 +0xB068 0x9000 # 0 +0xB069 0x8FFA # 0 +0xB06A 0x8FF4 # 0 +0xB06B 0x9003 # 0 +0xB06C 0x8FFD # 0 +0xB06D 0x9005 # 0 +0xB06E 0x8FF8 # 0 +0xB06F 0x9095 # 0 +0xB070 0x90E1 # 0 +0xB071 0x90DD # 0 +0xB072 0x90E2 # 0 +0xB073 0x9152 # 0 +0xB074 0x914D # 0 +0xB075 0x914C # 0 +0xB076 0x91D8 # 0 +0xB077 0x91DD # 0 +0xB078 0x91D7 # 0 +0xB079 0x91DC # 0 +0xB07A 0x91D9 # 0 +0xB07B 0x9583 # 0 +0xB07C 0x9662 # 0 +0xB07D 0x9663 # 0 +0xB07E 0x9661 # 0 +0xB0A1 0x965B # 0 +0xB0A2 0x965D # 0 +0xB0A3 0x9664 # 0 +0xB0A4 0x9658 # 0 +0xB0A5 0x965E # 0 +0xB0A6 0x96BB # 0 +0xB0A7 0x98E2 # 0 +0xB0A8 0x99AC # 0 +0xB0A9 0x9AA8 # 0 +0xB0AA 0x9AD8 # 0 +0xB0AB 0x9B25 # 0 +0xB0AC 0x9B32 # 0 +0xB0AD 0x9B3C # 0 +0xB0AE 0x4E7E # 0 +0xB0AF 0x507A # 0 +0xB0B0 0x507D # 0 +0xB0B1 0x505C # 0 +0xB0B2 0x5047 # 0 +0xB0B3 0x5043 # 0 +0xB0B4 0x504C # 0 +0xB0B5 0x505A # 0 +0xB0B6 0x5049 # 0 +0xB0B7 0x5065 # 0 +0xB0B8 0x5076 # 0 +0xB0B9 0x504E # 0 +0xB0BA 0x5055 # 0 +0xB0BB 0x5075 # 0 +0xB0BC 0x5074 # 0 +0xB0BD 0x5077 # 0 +0xB0BE 0x504F # 0 +0xB0BF 0x500F # 0 +0xB0C0 0x506F # 0 +0xB0C1 0x506D # 0 +0xB0C2 0x515C # 0 +0xB0C3 0x5195 # 0 +0xB0C4 0x51F0 # 0 +0xB0C5 0x526A # 0 +0xB0C6 0x526F # 0 +0xB0C7 0x52D2 # 0 +0xB0C8 0x52D9 # 0 +0xB0C9 0x52D8 # 0 +0xB0CA 0x52D5 # 0 +0xB0CB 0x5310 # 0 +0xB0CC 0x530F # 0 +0xB0CD 0x5319 # 0 +0xB0CE 0x533F # 0 +0xB0CF 0x5340 # 0 +0xB0D0 0x533E # 0 +0xB0D1 0x53C3 # 0 +0xB0D2 0x66FC # 0 +0xB0D3 0x5546 # 0 +0xB0D4 0x556A # 0 +0xB0D5 0x5566 # 0 +0xB0D6 0x5544 # 0 +0xB0D7 0x555E # 0 +0xB0D8 0x5561 # 0 +0xB0D9 0x5543 # 0 +0xB0DA 0x554A # 0 +0xB0DB 0x5531 # 0 +0xB0DC 0x5556 # 0 +0xB0DD 0x554F # 0 +0xB0DE 0x5555 # 0 +0xB0DF 0x552F # 0 +0xB0E0 0x5564 # 0 +0xB0E1 0x5538 # 0 +0xB0E2 0x552E # 0 +0xB0E3 0x555C # 0 +0xB0E4 0x552C # 0 +0xB0E5 0x5563 # 0 +0xB0E6 0x5533 # 0 +0xB0E7 0x5541 # 0 +0xB0E8 0x5557 # 0 +0xB0E9 0x5708 # 0 +0xB0EA 0x570B # 0 +0xB0EB 0x5709 # 0 +0xB0EC 0x57DF # 0 +0xB0ED 0x5805 # 0 +0xB0EE 0x580A # 0 +0xB0EF 0x5806 # 0 +0xB0F0 0x57E0 # 0 +0xB0F1 0x57E4 # 0 +0xB0F2 0x57FA # 0 +0xB0F3 0x5802 # 0 +0xB0F4 0x5835 # 0 +0xB0F5 0x57F7 # 0 +0xB0F6 0x57F9 # 0 +0xB0F7 0x5920 # 0 +0xB0F8 0x5962 # 0 +0xB0F9 0x5A36 # 0 +0xB0FA 0x5A41 # 0 +0xB0FB 0x5A49 # 0 +0xB0FC 0x5A66 # 0 +0xB0FD 0x5A6A # 0 +0xB0FE 0x5A40 # 0 +0xB140 0x5A3C # 0 +0xB141 0x5A62 # 0 +0xB142 0x5A5A # 0 +0xB143 0x5A46 # 0 +0xB144 0x5A4A # 0 +0xB145 0x5B70 # 0 +0xB146 0x5BC7 # 0 +0xB147 0x5BC5 # 0 +0xB148 0x5BC4 # 0 +0xB149 0x5BC2 # 0 +0xB14A 0x5BBF # 0 +0xB14B 0x5BC6 # 0 +0xB14C 0x5C09 # 0 +0xB14D 0x5C08 # 0 +0xB14E 0x5C07 # 0 +0xB14F 0x5C60 # 0 +0xB150 0x5C5C # 0 +0xB151 0x5C5D # 0 +0xB152 0x5D07 # 0 +0xB153 0x5D06 # 0 +0xB154 0x5D0E # 0 +0xB155 0x5D1B # 0 +0xB156 0x5D16 # 0 +0xB157 0x5D22 # 0 +0xB158 0x5D11 # 0 +0xB159 0x5D29 # 0 +0xB15A 0x5D14 # 0 +0xB15B 0x5D19 # 0 +0xB15C 0x5D24 # 0 +0xB15D 0x5D27 # 0 +0xB15E 0x5D17 # 0 +0xB15F 0x5DE2 # 0 +0xB160 0x5E38 # 0 +0xB161 0x5E36 # 0 +0xB162 0x5E33 # 0 +0xB163 0x5E37 # 0 +0xB164 0x5EB7 # 0 +0xB165 0x5EB8 # 0 +0xB166 0x5EB6 # 0 +0xB167 0x5EB5 # 0 +0xB168 0x5EBE # 0 +0xB169 0x5F35 # 0 +0xB16A 0x5F37 # 0 +0xB16B 0x5F57 # 0 +0xB16C 0x5F6C # 0 +0xB16D 0x5F69 # 0 +0xB16E 0x5F6B # 0 +0xB16F 0x5F97 # 0 +0xB170 0x5F99 # 0 +0xB171 0x5F9E # 0 +0xB172 0x5F98 # 0 +0xB173 0x5FA1 # 0 +0xB174 0x5FA0 # 0 +0xB175 0x5F9C # 0 +0xB176 0x607F # 0 +0xB177 0x60A3 # 0 +0xB178 0x6089 # 0 +0xB179 0x60A0 # 0 +0xB17A 0x60A8 # 0 +0xB17B 0x60CB # 0 +0xB17C 0x60B4 # 0 +0xB17D 0x60E6 # 0 +0xB17E 0x60BD # 0 +0xB1A1 0x60C5 # 0 +0xB1A2 0x60BB # 0 +0xB1A3 0x60B5 # 0 +0xB1A4 0x60DC # 0 +0xB1A5 0x60BC # 0 +0xB1A6 0x60D8 # 0 +0xB1A7 0x60D5 # 0 +0xB1A8 0x60C6 # 0 +0xB1A9 0x60DF # 0 +0xB1AA 0x60B8 # 0 +0xB1AB 0x60DA # 0 +0xB1AC 0x60C7 # 0 +0xB1AD 0x621A # 0 +0xB1AE 0x621B # 0 +0xB1AF 0x6248 # 0 +0xB1B0 0x63A0 # 0 +0xB1B1 0x63A7 # 0 +0xB1B2 0x6372 # 0 +0xB1B3 0x6396 # 0 +0xB1B4 0x63A2 # 0 +0xB1B5 0x63A5 # 0 +0xB1B6 0x6377 # 0 +0xB1B7 0x6367 # 0 +0xB1B8 0x6398 # 0 +0xB1B9 0x63AA # 0 +0xB1BA 0x6371 # 0 +0xB1BB 0x63A9 # 0 +0xB1BC 0x6389 # 0 +0xB1BD 0x6383 # 0 +0xB1BE 0x639B # 0 +0xB1BF 0x636B # 0 +0xB1C0 0x63A8 # 0 +0xB1C1 0x6384 # 0 +0xB1C2 0x6388 # 0 +0xB1C3 0x6399 # 0 +0xB1C4 0x63A1 # 0 +0xB1C5 0x63AC # 0 +0xB1C6 0x6392 # 0 +0xB1C7 0x638F # 0 +0xB1C8 0x6380 # 0 +0xB1C9 0x637B # 0 +0xB1CA 0x6369 # 0 +0xB1CB 0x6368 # 0 +0xB1CC 0x637A # 0 +0xB1CD 0x655D # 0 +0xB1CE 0x6556 # 0 +0xB1CF 0x6551 # 0 +0xB1D0 0x6559 # 0 +0xB1D1 0x6557 # 0 +0xB1D2 0x555F # 0 +0xB1D3 0x654F # 0 +0xB1D4 0x6558 # 0 +0xB1D5 0x6555 # 0 +0xB1D6 0x6554 # 0 +0xB1D7 0x659C # 0 +0xB1D8 0x659B # 0 +0xB1D9 0x65AC # 0 +0xB1DA 0x65CF # 0 +0xB1DB 0x65CB # 0 +0xB1DC 0x65CC # 0 +0xB1DD 0x65CE # 0 +0xB1DE 0x665D # 0 +0xB1DF 0x665A # 0 +0xB1E0 0x6664 # 0 +0xB1E1 0x6668 # 0 +0xB1E2 0x6666 # 0 +0xB1E3 0x665E # 0 +0xB1E4 0x66F9 # 0 +0xB1E5 0x52D7 # 0 +0xB1E6 0x671B # 0 +0xB1E7 0x6881 # 0 +0xB1E8 0x68AF # 0 +0xB1E9 0x68A2 # 0 +0xB1EA 0x6893 # 0 +0xB1EB 0x68B5 # 0 +0xB1EC 0x687F # 0 +0xB1ED 0x6876 # 0 +0xB1EE 0x68B1 # 0 +0xB1EF 0x68A7 # 0 +0xB1F0 0x6897 # 0 +0xB1F1 0x68B0 # 0 +0xB1F2 0x6883 # 0 +0xB1F3 0x68C4 # 0 +0xB1F4 0x68AD # 0 +0xB1F5 0x6886 # 0 +0xB1F6 0x6885 # 0 +0xB1F7 0x6894 # 0 +0xB1F8 0x689D # 0 +0xB1F9 0x68A8 # 0 +0xB1FA 0x689F # 0 +0xB1FB 0x68A1 # 0 +0xB1FC 0x6882 # 0 +0xB1FD 0x6B32 # 0 +0xB1FE 0x6BBA # 0 +0xB240 0x6BEB # 0 +0xB241 0x6BEC # 0 +0xB242 0x6C2B # 0 +0xB243 0x6D8E # 0 +0xB244 0x6DBC # 0 +0xB245 0x6DF3 # 0 +0xB246 0x6DD9 # 0 +0xB247 0x6DB2 # 0 +0xB248 0x6DE1 # 0 +0xB249 0x6DCC # 0 +0xB24A 0x6DE4 # 0 +0xB24B 0x6DFB # 0 +0xB24C 0x6DFA # 0 +0xB24D 0x6E05 # 0 +0xB24E 0x6DC7 # 0 +0xB24F 0x6DCB # 0 +0xB250 0x6DAF # 0 +0xB251 0x6DD1 # 0 +0xB252 0x6DAE # 0 +0xB253 0x6DDE # 0 +0xB254 0x6DF9 # 0 +0xB255 0x6DB8 # 0 +0xB256 0x6DF7 # 0 +0xB257 0x6DF5 # 0 +0xB258 0x6DC5 # 0 +0xB259 0x6DD2 # 0 +0xB25A 0x6E1A # 0 +0xB25B 0x6DB5 # 0 +0xB25C 0x6DDA # 0 +0xB25D 0x6DEB # 0 +0xB25E 0x6DD8 # 0 +0xB25F 0x6DEA # 0 +0xB260 0x6DF1 # 0 +0xB261 0x6DEE # 0 +0xB262 0x6DE8 # 0 +0xB263 0x6DC6 # 0 +0xB264 0x6DC4 # 0 +0xB265 0x6DAA # 0 +0xB266 0x6DEC # 0 +0xB267 0x6DBF # 0 +0xB268 0x6DE6 # 0 +0xB269 0x70F9 # 0 +0xB26A 0x7109 # 0 +0xB26B 0x710A # 0 +0xB26C 0x70FD # 0 +0xB26D 0x70EF # 0 +0xB26E 0x723D # 0 +0xB26F 0x727D # 0 +0xB270 0x7281 # 0 +0xB271 0x731C # 0 +0xB272 0x731B # 0 +0xB273 0x7316 # 0 +0xB274 0x7313 # 0 +0xB275 0x7319 # 0 +0xB276 0x7387 # 0 +0xB277 0x7405 # 0 +0xB278 0x740A # 0 +0xB279 0x7403 # 0 +0xB27A 0x7406 # 0 +0xB27B 0x73FE # 0 +0xB27C 0x740D # 0 +0xB27D 0x74E0 # 0 +0xB27E 0x74F6 # 0 +0xB2A1 0x74F7 # 0 +0xB2A2 0x751C # 0 +0xB2A3 0x7522 # 0 +0xB2A4 0x7565 # 0 +0xB2A5 0x7566 # 0 +0xB2A6 0x7562 # 0 +0xB2A7 0x7570 # 0 +0xB2A8 0x758F # 0 +0xB2A9 0x75D4 # 0 +0xB2AA 0x75D5 # 0 +0xB2AB 0x75B5 # 0 +0xB2AC 0x75CA # 0 +0xB2AD 0x75CD # 0 +0xB2AE 0x768E # 0 +0xB2AF 0x76D4 # 0 +0xB2B0 0x76D2 # 0 +0xB2B1 0x76DB # 0 +0xB2B2 0x7737 # 0 +0xB2B3 0x773E # 0 +0xB2B4 0x773C # 0 +0xB2B5 0x7736 # 0 +0xB2B6 0x7738 # 0 +0xB2B7 0x773A # 0 +0xB2B8 0x786B # 0 +0xB2B9 0x7843 # 0 +0xB2BA 0x784E # 0 +0xB2BB 0x7965 # 0 +0xB2BC 0x7968 # 0 +0xB2BD 0x796D # 0 +0xB2BE 0x79FB # 0 +0xB2BF 0x7A92 # 0 +0xB2C0 0x7A95 # 0 +0xB2C1 0x7B20 # 0 +0xB2C2 0x7B28 # 0 +0xB2C3 0x7B1B # 0 +0xB2C4 0x7B2C # 0 +0xB2C5 0x7B26 # 0 +0xB2C6 0x7B19 # 0 +0xB2C7 0x7B1E # 0 +0xB2C8 0x7B2E # 0 +0xB2C9 0x7C92 # 0 +0xB2CA 0x7C97 # 0 +0xB2CB 0x7C95 # 0 +0xB2CC 0x7D46 # 0 +0xB2CD 0x7D43 # 0 +0xB2CE 0x7D71 # 0 +0xB2CF 0x7D2E # 0 +0xB2D0 0x7D39 # 0 +0xB2D1 0x7D3C # 0 +0xB2D2 0x7D40 # 0 +0xB2D3 0x7D30 # 0 +0xB2D4 0x7D33 # 0 +0xB2D5 0x7D44 # 0 +0xB2D6 0x7D2F # 0 +0xB2D7 0x7D42 # 0 +0xB2D8 0x7D32 # 0 +0xB2D9 0x7D31 # 0 +0xB2DA 0x7F3D # 0 +0xB2DB 0x7F9E # 0 +0xB2DC 0x7F9A # 0 +0xB2DD 0x7FCC # 0 +0xB2DE 0x7FCE # 0 +0xB2DF 0x7FD2 # 0 +0xB2E0 0x801C # 0 +0xB2E1 0x804A # 0 +0xB2E2 0x8046 # 0 +0xB2E3 0x812F # 0 +0xB2E4 0x8116 # 0 +0xB2E5 0x8123 # 0 +0xB2E6 0x812B # 0 +0xB2E7 0x8129 # 0 +0xB2E8 0x8130 # 0 +0xB2E9 0x8124 # 0 +0xB2EA 0x8202 # 0 +0xB2EB 0x8235 # 0 +0xB2EC 0x8237 # 0 +0xB2ED 0x8236 # 0 +0xB2EE 0x8239 # 0 +0xB2EF 0x838E # 0 +0xB2F0 0x839E # 0 +0xB2F1 0x8398 # 0 +0xB2F2 0x8378 # 0 +0xB2F3 0x83A2 # 0 +0xB2F4 0x8396 # 0 +0xB2F5 0x83BD # 0 +0xB2F6 0x83AB # 0 +0xB2F7 0x8392 # 0 +0xB2F8 0x838A # 0 +0xB2F9 0x8393 # 0 +0xB2FA 0x8389 # 0 +0xB2FB 0x83A0 # 0 +0xB2FC 0x8377 # 0 +0xB2FD 0x837B # 0 +0xB2FE 0x837C # 0 +0xB340 0x8386 # 0 +0xB341 0x83A7 # 0 +0xB342 0x8655 # 0 +0xB343 0x5F6A # 0 +0xB344 0x86C7 # 0 +0xB345 0x86C0 # 0 +0xB346 0x86B6 # 0 +0xB347 0x86C4 # 0 +0xB348 0x86B5 # 0 +0xB349 0x86C6 # 0 +0xB34A 0x86CB # 0 +0xB34B 0x86B1 # 0 +0xB34C 0x86AF # 0 +0xB34D 0x86C9 # 0 +0xB34E 0x8853 # 0 +0xB34F 0x889E # 0 +0xB350 0x8888 # 0 +0xB351 0x88AB # 0 +0xB352 0x8892 # 0 +0xB353 0x8896 # 0 +0xB354 0x888D # 0 +0xB355 0x888B # 0 +0xB356 0x8993 # 0 +0xB357 0x898F # 0 +0xB358 0x8A2A # 0 +0xB359 0x8A1D # 0 +0xB35A 0x8A23 # 0 +0xB35B 0x8A25 # 0 +0xB35C 0x8A31 # 0 +0xB35D 0x8A2D # 0 +0xB35E 0x8A1F # 0 +0xB35F 0x8A1B # 0 +0xB360 0x8A22 # 0 +0xB361 0x8C49 # 0 +0xB362 0x8C5A # 0 +0xB363 0x8CA9 # 0 +0xB364 0x8CAC # 0 +0xB365 0x8CAB # 0 +0xB366 0x8CA8 # 0 +0xB367 0x8CAA # 0 +0xB368 0x8CA7 # 0 +0xB369 0x8D67 # 0 +0xB36A 0x8D66 # 0 +0xB36B 0x8DBE # 0 +0xB36C 0x8DBA # 0 +0xB36D 0x8EDB # 0 +0xB36E 0x8EDF # 0 +0xB36F 0x9019 # 0 +0xB370 0x900D # 0 +0xB371 0x901A # 0 +0xB372 0x9017 # 0 +0xB373 0x9023 # 0 +0xB374 0x901F # 0 +0xB375 0x901D # 0 +0xB376 0x9010 # 0 +0xB377 0x9015 # 0 +0xB378 0x901E # 0 +0xB379 0x9020 # 0 +0xB37A 0x900F # 0 +0xB37B 0x9022 # 0 +0xB37C 0x9016 # 0 +0xB37D 0x901B # 0 +0xB37E 0x9014 # 0 +0xB3A1 0x90E8 # 0 +0xB3A2 0x90ED # 0 +0xB3A3 0x90FD # 0 +0xB3A4 0x9157 # 0 +0xB3A5 0x91CE # 0 +0xB3A6 0x91F5 # 0 +0xB3A7 0x91E6 # 0 +0xB3A8 0x91E3 # 0 +0xB3A9 0x91E7 # 0 +0xB3AA 0x91ED # 0 +0xB3AB 0x91E9 # 0 +0xB3AC 0x9589 # 0 +0xB3AD 0x966A # 0 +0xB3AE 0x9675 # 0 +0xB3AF 0x9673 # 0 +0xB3B0 0x9678 # 0 +0xB3B1 0x9670 # 0 +0xB3B2 0x9674 # 0 +0xB3B3 0x9676 # 0 +0xB3B4 0x9677 # 0 +0xB3B5 0x966C # 0 +0xB3B6 0x96C0 # 0 +0xB3B7 0x96EA # 0 +0xB3B8 0x96E9 # 0 +0xB3B9 0x7AE0 # 0 +0xB3BA 0x7ADF # 0 +0xB3BB 0x9802 # 0 +0xB3BC 0x9803 # 0 +0xB3BD 0x9B5A # 0 +0xB3BE 0x9CE5 # 0 +0xB3BF 0x9E75 # 0 +0xB3C0 0x9E7F # 0 +0xB3C1 0x9EA5 # 0 +0xB3C2 0x9EBB # 0 +0xB3C3 0x50A2 # 0 +0xB3C4 0x508D # 0 +0xB3C5 0x5085 # 0 +0xB3C6 0x5099 # 0 +0xB3C7 0x5091 # 0 +0xB3C8 0x5080 # 0 +0xB3C9 0x5096 # 0 +0xB3CA 0x5098 # 0 +0xB3CB 0x509A # 0 +0xB3CC 0x6700 # 0 +0xB3CD 0x51F1 # 0 +0xB3CE 0x5272 # 0 +0xB3CF 0x5274 # 0 +0xB3D0 0x5275 # 0 +0xB3D1 0x5269 # 0 +0xB3D2 0x52DE # 0 +0xB3D3 0x52DD # 0 +0xB3D4 0x52DB # 0 +0xB3D5 0x535A # 0 +0xB3D6 0x53A5 # 0 +0xB3D7 0x557B # 0 +0xB3D8 0x5580 # 0 +0xB3D9 0x55A7 # 0 +0xB3DA 0x557C # 0 +0xB3DB 0x558A # 0 +0xB3DC 0x559D # 0 +0xB3DD 0x5598 # 0 +0xB3DE 0x5582 # 0 +0xB3DF 0x559C # 0 +0xB3E0 0x55AA # 0 +0xB3E1 0x5594 # 0 +0xB3E2 0x5587 # 0 +0xB3E3 0x558B # 0 +0xB3E4 0x5583 # 0 +0xB3E5 0x55B3 # 0 +0xB3E6 0x55AE # 0 +0xB3E7 0x559F # 0 +0xB3E8 0x553E # 0 +0xB3E9 0x55B2 # 0 +0xB3EA 0x559A # 0 +0xB3EB 0x55BB # 0 +0xB3EC 0x55AC # 0 +0xB3ED 0x55B1 # 0 +0xB3EE 0x557E # 0 +0xB3EF 0x5589 # 0 +0xB3F0 0x55AB # 0 +0xB3F1 0x5599 # 0 +0xB3F2 0x570D # 0 +0xB3F3 0x582F # 0 +0xB3F4 0x582A # 0 +0xB3F5 0x5834 # 0 +0xB3F6 0x5824 # 0 +0xB3F7 0x5830 # 0 +0xB3F8 0x5831 # 0 +0xB3F9 0x5821 # 0 +0xB3FA 0x581D # 0 +0xB3FB 0x5820 # 0 +0xB3FC 0x58F9 # 0 +0xB3FD 0x58FA # 0 +0xB3FE 0x5960 # 0 +0xB440 0x5A77 # 0 +0xB441 0x5A9A # 0 +0xB442 0x5A7F # 0 +0xB443 0x5A92 # 0 +0xB444 0x5A9B # 0 +0xB445 0x5AA7 # 0 +0xB446 0x5B73 # 0 +0xB447 0x5B71 # 0 +0xB448 0x5BD2 # 0 +0xB449 0x5BCC # 0 +0xB44A 0x5BD3 # 0 +0xB44B 0x5BD0 # 0 +0xB44C 0x5C0A # 0 +0xB44D 0x5C0B # 0 +0xB44E 0x5C31 # 0 +0xB44F 0x5D4C # 0 +0xB450 0x5D50 # 0 +0xB451 0x5D34 # 0 +0xB452 0x5D47 # 0 +0xB453 0x5DFD # 0 +0xB454 0x5E45 # 0 +0xB455 0x5E3D # 0 +0xB456 0x5E40 # 0 +0xB457 0x5E43 # 0 +0xB458 0x5E7E # 0 +0xB459 0x5ECA # 0 +0xB45A 0x5EC1 # 0 +0xB45B 0x5EC2 # 0 +0xB45C 0x5EC4 # 0 +0xB45D 0x5F3C # 0 +0xB45E 0x5F6D # 0 +0xB45F 0x5FA9 # 0 +0xB460 0x5FAA # 0 +0xB461 0x5FA8 # 0 +0xB462 0x60D1 # 0 +0xB463 0x60E1 # 0 +0xB464 0x60B2 # 0 +0xB465 0x60B6 # 0 +0xB466 0x60E0 # 0 +0xB467 0x611C # 0 +0xB468 0x6123 # 0 +0xB469 0x60FA # 0 +0xB46A 0x6115 # 0 +0xB46B 0x60F0 # 0 +0xB46C 0x60FB # 0 +0xB46D 0x60F4 # 0 +0xB46E 0x6168 # 0 +0xB46F 0x60F1 # 0 +0xB470 0x610E # 0 +0xB471 0x60F6 # 0 +0xB472 0x6109 # 0 +0xB473 0x6100 # 0 +0xB474 0x6112 # 0 +0xB475 0x621F # 0 +0xB476 0x6249 # 0 +0xB477 0x63A3 # 0 +0xB478 0x638C # 0 +0xB479 0x63CF # 0 +0xB47A 0x63C0 # 0 +0xB47B 0x63E9 # 0 +0xB47C 0x63C9 # 0 +0xB47D 0x63C6 # 0 +0xB47E 0x63CD # 0 +0xB4A1 0x63D2 # 0 +0xB4A2 0x63E3 # 0 +0xB4A3 0x63D0 # 0 +0xB4A4 0x63E1 # 0 +0xB4A5 0x63D6 # 0 +0xB4A6 0x63ED # 0 +0xB4A7 0x63EE # 0 +0xB4A8 0x6376 # 0 +0xB4A9 0x63F4 # 0 +0xB4AA 0x63EA # 0 +0xB4AB 0x63DB # 0 +0xB4AC 0x6452 # 0 +0xB4AD 0x63DA # 0 +0xB4AE 0x63F9 # 0 +0xB4AF 0x655E # 0 +0xB4B0 0x6566 # 0 +0xB4B1 0x6562 # 0 +0xB4B2 0x6563 # 0 +0xB4B3 0x6591 # 0 +0xB4B4 0x6590 # 0 +0xB4B5 0x65AF # 0 +0xB4B6 0x666E # 0 +0xB4B7 0x6670 # 0 +0xB4B8 0x6674 # 0 +0xB4B9 0x6676 # 0 +0xB4BA 0x666F # 0 +0xB4BB 0x6691 # 0 +0xB4BC 0x667A # 0 +0xB4BD 0x667E # 0 +0xB4BE 0x6677 # 0 +0xB4BF 0x66FE # 0 +0xB4C0 0x66FF # 0 +0xB4C1 0x671F # 0 +0xB4C2 0x671D # 0 +0xB4C3 0x68FA # 0 +0xB4C4 0x68D5 # 0 +0xB4C5 0x68E0 # 0 +0xB4C6 0x68D8 # 0 +0xB4C7 0x68D7 # 0 +0xB4C8 0x6905 # 0 +0xB4C9 0x68DF # 0 +0xB4CA 0x68F5 # 0 +0xB4CB 0x68EE # 0 +0xB4CC 0x68E7 # 0 +0xB4CD 0x68F9 # 0 +0xB4CE 0x68D2 # 0 +0xB4CF 0x68F2 # 0 +0xB4D0 0x68E3 # 0 +0xB4D1 0x68CB # 0 +0xB4D2 0x68CD # 0 +0xB4D3 0x690D # 0 +0xB4D4 0x6912 # 0 +0xB4D5 0x690E # 0 +0xB4D6 0x68C9 # 0 +0xB4D7 0x68DA # 0 +0xB4D8 0x696E # 0 +0xB4D9 0x68FB # 0 +0xB4DA 0x6B3E # 0 +0xB4DB 0x6B3A # 0 +0xB4DC 0x6B3D # 0 +0xB4DD 0x6B98 # 0 +0xB4DE 0x6B96 # 0 +0xB4DF 0x6BBC # 0 +0xB4E0 0x6BEF # 0 +0xB4E1 0x6C2E # 0 +0xB4E2 0x6C2F # 0 +0xB4E3 0x6C2C # 0 +0xB4E4 0x6E2F # 0 +0xB4E5 0x6E38 # 0 +0xB4E6 0x6E54 # 0 +0xB4E7 0x6E21 # 0 +0xB4E8 0x6E32 # 0 +0xB4E9 0x6E67 # 0 +0xB4EA 0x6E4A # 0 +0xB4EB 0x6E20 # 0 +0xB4EC 0x6E25 # 0 +0xB4ED 0x6E23 # 0 +0xB4EE 0x6E1B # 0 +0xB4EF 0x6E5B # 0 +0xB4F0 0x6E58 # 0 +0xB4F1 0x6E24 # 0 +0xB4F2 0x6E56 # 0 +0xB4F3 0x6E6E # 0 +0xB4F4 0x6E2D # 0 +0xB4F5 0x6E26 # 0 +0xB4F6 0x6E6F # 0 +0xB4F7 0x6E34 # 0 +0xB4F8 0x6E4D # 0 +0xB4F9 0x6E3A # 0 +0xB4FA 0x6E2C # 0 +0xB4FB 0x6E43 # 0 +0xB4FC 0x6E1D # 0 +0xB4FD 0x6E3E # 0 +0xB4FE 0x6ECB # 0 +0xB540 0x6E89 # 0 +0xB541 0x6E19 # 0 +0xB542 0x6E4E # 0 +0xB543 0x6E63 # 0 +0xB544 0x6E44 # 0 +0xB545 0x6E72 # 0 +0xB546 0x6E69 # 0 +0xB547 0x6E5F # 0 +0xB548 0x7119 # 0 +0xB549 0x711A # 0 +0xB54A 0x7126 # 0 +0xB54B 0x7130 # 0 +0xB54C 0x7121 # 0 +0xB54D 0x7136 # 0 +0xB54E 0x716E # 0 +0xB54F 0x711C # 0 +0xB550 0x724C # 0 +0xB551 0x7284 # 0 +0xB552 0x7280 # 0 +0xB553 0x7336 # 0 +0xB554 0x7325 # 0 +0xB555 0x7334 # 0 +0xB556 0x7329 # 0 +0xB557 0x743A # 0 +0xB558 0x742A # 0 +0xB559 0x7433 # 0 +0xB55A 0x7422 # 0 +0xB55B 0x7425 # 0 +0xB55C 0x7435 # 0 +0xB55D 0x7436 # 0 +0xB55E 0x7434 # 0 +0xB55F 0x742F # 0 +0xB560 0x741B # 0 +0xB561 0x7426 # 0 +0xB562 0x7428 # 0 +0xB563 0x7525 # 0 +0xB564 0x7526 # 0 +0xB565 0x756B # 0 +0xB566 0x756A # 0 +0xB567 0x75E2 # 0 +0xB568 0x75DB # 0 +0xB569 0x75E3 # 0 +0xB56A 0x75D9 # 0 +0xB56B 0x75D8 # 0 +0xB56C 0x75DE # 0 +0xB56D 0x75E0 # 0 +0xB56E 0x767B # 0 +0xB56F 0x767C # 0 +0xB570 0x7696 # 0 +0xB571 0x7693 # 0 +0xB572 0x76B4 # 0 +0xB573 0x76DC # 0 +0xB574 0x774F # 0 +0xB575 0x77ED # 0 +0xB576 0x785D # 0 +0xB577 0x786C # 0 +0xB578 0x786F # 0 +0xB579 0x7A0D # 0 +0xB57A 0x7A08 # 0 +0xB57B 0x7A0B # 0 +0xB57C 0x7A05 # 0 +0xB57D 0x7A00 # 0 +0xB57E 0x7A98 # 0 +0xB5A1 0x7A97 # 0 +0xB5A2 0x7A96 # 0 +0xB5A3 0x7AE5 # 0 +0xB5A4 0x7AE3 # 0 +0xB5A5 0x7B49 # 0 +0xB5A6 0x7B56 # 0 +0xB5A7 0x7B46 # 0 +0xB5A8 0x7B50 # 0 +0xB5A9 0x7B52 # 0 +0xB5AA 0x7B54 # 0 +0xB5AB 0x7B4D # 0 +0xB5AC 0x7B4B # 0 +0xB5AD 0x7B4F # 0 +0xB5AE 0x7B51 # 0 +0xB5AF 0x7C9F # 0 +0xB5B0 0x7CA5 # 0 +0xB5B1 0x7D5E # 0 +0xB5B2 0x7D50 # 0 +0xB5B3 0x7D68 # 0 +0xB5B4 0x7D55 # 0 +0xB5B5 0x7D2B # 0 +0xB5B6 0x7D6E # 0 +0xB5B7 0x7D72 # 0 +0xB5B8 0x7D61 # 0 +0xB5B9 0x7D66 # 0 +0xB5BA 0x7D62 # 0 +0xB5BB 0x7D70 # 0 +0xB5BC 0x7D73 # 0 +0xB5BD 0x5584 # 0 +0xB5BE 0x7FD4 # 0 +0xB5BF 0x7FD5 # 0 +0xB5C0 0x800B # 0 +0xB5C1 0x8052 # 0 +0xB5C2 0x8085 # 0 +0xB5C3 0x8155 # 0 +0xB5C4 0x8154 # 0 +0xB5C5 0x814B # 0 +0xB5C6 0x8151 # 0 +0xB5C7 0x814E # 0 +0xB5C8 0x8139 # 0 +0xB5C9 0x8146 # 0 +0xB5CA 0x813E # 0 +0xB5CB 0x814C # 0 +0xB5CC 0x8153 # 0 +0xB5CD 0x8174 # 0 +0xB5CE 0x8212 # 0 +0xB5CF 0x821C # 0 +0xB5D0 0x83E9 # 0 +0xB5D1 0x8403 # 0 +0xB5D2 0x83F8 # 0 +0xB5D3 0x840D # 0 +0xB5D4 0x83E0 # 0 +0xB5D5 0x83C5 # 0 +0xB5D6 0x840B # 0 +0xB5D7 0x83C1 # 0 +0xB5D8 0x83EF # 0 +0xB5D9 0x83F1 # 0 +0xB5DA 0x83F4 # 0 +0xB5DB 0x8457 # 0 +0xB5DC 0x840A # 0 +0xB5DD 0x83F0 # 0 +0xB5DE 0x840C # 0 +0xB5DF 0x83CC # 0 +0xB5E0 0x83FD # 0 +0xB5E1 0x83F2 # 0 +0xB5E2 0x83CA # 0 +0xB5E3 0x8438 # 0 +0xB5E4 0x840E # 0 +0xB5E5 0x8404 # 0 +0xB5E6 0x83DC # 0 +0xB5E7 0x8407 # 0 +0xB5E8 0x83D4 # 0 +0xB5E9 0x83DF # 0 +0xB5EA 0x865B # 0 +0xB5EB 0x86DF # 0 +0xB5EC 0x86D9 # 0 +0xB5ED 0x86ED # 0 +0xB5EE 0x86D4 # 0 +0xB5EF 0x86DB # 0 +0xB5F0 0x86E4 # 0 +0xB5F1 0x86D0 # 0 +0xB5F2 0x86DE # 0 +0xB5F3 0x8857 # 0 +0xB5F4 0x88C1 # 0 +0xB5F5 0x88C2 # 0 +0xB5F6 0x88B1 # 0 +0xB5F7 0x8983 # 0 +0xB5F8 0x8996 # 0 +0xB5F9 0x8A3B # 0 +0xB5FA 0x8A60 # 0 +0xB5FB 0x8A55 # 0 +0xB5FC 0x8A5E # 0 +0xB5FD 0x8A3C # 0 +0xB5FE 0x8A41 # 0 +0xB640 0x8A54 # 0 +0xB641 0x8A5B # 0 +0xB642 0x8A50 # 0 +0xB643 0x8A46 # 0 +0xB644 0x8A34 # 0 +0xB645 0x8A3A # 0 +0xB646 0x8A36 # 0 +0xB647 0x8A56 # 0 +0xB648 0x8C61 # 0 +0xB649 0x8C82 # 0 +0xB64A 0x8CAF # 0 +0xB64B 0x8CBC # 0 +0xB64C 0x8CB3 # 0 +0xB64D 0x8CBD # 0 +0xB64E 0x8CC1 # 0 +0xB64F 0x8CBB # 0 +0xB650 0x8CC0 # 0 +0xB651 0x8CB4 # 0 +0xB652 0x8CB7 # 0 +0xB653 0x8CB6 # 0 +0xB654 0x8CBF # 0 +0xB655 0x8CB8 # 0 +0xB656 0x8D8A # 0 +0xB657 0x8D85 # 0 +0xB658 0x8D81 # 0 +0xB659 0x8DCE # 0 +0xB65A 0x8DDD # 0 +0xB65B 0x8DCB # 0 +0xB65C 0x8DDA # 0 +0xB65D 0x8DD1 # 0 +0xB65E 0x8DCC # 0 +0xB65F 0x8DDB # 0 +0xB660 0x8DC6 # 0 +0xB661 0x8EFB # 0 +0xB662 0x8EF8 # 0 +0xB663 0x8EFC # 0 +0xB664 0x8F9C # 0 +0xB665 0x902E # 0 +0xB666 0x9035 # 0 +0xB667 0x9031 # 0 +0xB668 0x9038 # 0 +0xB669 0x9032 # 0 +0xB66A 0x9036 # 0 +0xB66B 0x9102 # 0 +0xB66C 0x90F5 # 0 +0xB66D 0x9109 # 0 +0xB66E 0x90FE # 0 +0xB66F 0x9163 # 0 +0xB670 0x9165 # 0 +0xB671 0x91CF # 0 +0xB672 0x9214 # 0 +0xB673 0x9215 # 0 +0xB674 0x9223 # 0 +0xB675 0x9209 # 0 +0xB676 0x921E # 0 +0xB677 0x920D # 0 +0xB678 0x9210 # 0 +0xB679 0x9207 # 0 +0xB67A 0x9211 # 0 +0xB67B 0x9594 # 0 +0xB67C 0x958F # 0 +0xB67D 0x958B # 0 +0xB67E 0x9591 # 0 +0xB6A1 0x9593 # 0 +0xB6A2 0x9592 # 0 +0xB6A3 0x958E # 0 +0xB6A4 0x968A # 0 +0xB6A5 0x968E # 0 +0xB6A6 0x968B # 0 +0xB6A7 0x967D # 0 +0xB6A8 0x9685 # 0 +0xB6A9 0x9686 # 0 +0xB6AA 0x968D # 0 +0xB6AB 0x9672 # 0 +0xB6AC 0x9684 # 0 +0xB6AD 0x96C1 # 0 +0xB6AE 0x96C5 # 0 +0xB6AF 0x96C4 # 0 +0xB6B0 0x96C6 # 0 +0xB6B1 0x96C7 # 0 +0xB6B2 0x96EF # 0 +0xB6B3 0x96F2 # 0 +0xB6B4 0x97CC # 0 +0xB6B5 0x9805 # 0 +0xB6B6 0x9806 # 0 +0xB6B7 0x9808 # 0 +0xB6B8 0x98E7 # 0 +0xB6B9 0x98EA # 0 +0xB6BA 0x98EF # 0 +0xB6BB 0x98E9 # 0 +0xB6BC 0x98F2 # 0 +0xB6BD 0x98ED # 0 +0xB6BE 0x99AE # 0 +0xB6BF 0x99AD # 0 +0xB6C0 0x9EC3 # 0 +0xB6C1 0x9ECD # 0 +0xB6C2 0x9ED1 # 0 +0xB6C3 0x4E82 # 0 +0xB6C4 0x50AD # 0 +0xB6C5 0x50B5 # 0 +0xB6C6 0x50B2 # 0 +0xB6C7 0x50B3 # 0 +0xB6C8 0x50C5 # 0 +0xB6C9 0x50BE # 0 +0xB6CA 0x50AC # 0 +0xB6CB 0x50B7 # 0 +0xB6CC 0x50BB # 0 +0xB6CD 0x50AF # 0 +0xB6CE 0x50C7 # 0 +0xB6CF 0x527F # 0 +0xB6D0 0x5277 # 0 +0xB6D1 0x527D # 0 +0xB6D2 0x52DF # 0 +0xB6D3 0x52E6 # 0 +0xB6D4 0x52E4 # 0 +0xB6D5 0x52E2 # 0 +0xB6D6 0x52E3 # 0 +0xB6D7 0x532F # 0 +0xB6D8 0x55DF # 0 +0xB6D9 0x55E8 # 0 +0xB6DA 0x55D3 # 0 +0xB6DB 0x55E6 # 0 +0xB6DC 0x55CE # 0 +0xB6DD 0x55DC # 0 +0xB6DE 0x55C7 # 0 +0xB6DF 0x55D1 # 0 +0xB6E0 0x55E3 # 0 +0xB6E1 0x55E4 # 0 +0xB6E2 0x55EF # 0 +0xB6E3 0x55DA # 0 +0xB6E4 0x55E1 # 0 +0xB6E5 0x55C5 # 0 +0xB6E6 0x55C6 # 0 +0xB6E7 0x55E5 # 0 +0xB6E8 0x55C9 # 0 +0xB6E9 0x5712 # 0 +0xB6EA 0x5713 # 0 +0xB6EB 0x585E # 0 +0xB6EC 0x5851 # 0 +0xB6ED 0x5858 # 0 +0xB6EE 0x5857 # 0 +0xB6EF 0x585A # 0 +0xB6F0 0x5854 # 0 +0xB6F1 0x586B # 0 +0xB6F2 0x584C # 0 +0xB6F3 0x586D # 0 +0xB6F4 0x584A # 0 +0xB6F5 0x5862 # 0 +0xB6F6 0x5852 # 0 +0xB6F7 0x584B # 0 +0xB6F8 0x5967 # 0 +0xB6F9 0x5AC1 # 0 +0xB6FA 0x5AC9 # 0 +0xB6FB 0x5ACC # 0 +0xB6FC 0x5ABE # 0 +0xB6FD 0x5ABD # 0 +0xB6FE 0x5ABC # 0 +0xB740 0x5AB3 # 0 +0xB741 0x5AC2 # 0 +0xB742 0x5AB2 # 0 +0xB743 0x5D69 # 0 +0xB744 0x5D6F # 0 +0xB745 0x5E4C # 0 +0xB746 0x5E79 # 0 +0xB747 0x5EC9 # 0 +0xB748 0x5EC8 # 0 +0xB749 0x5F12 # 0 +0xB74A 0x5F59 # 0 +0xB74B 0x5FAC # 0 +0xB74C 0x5FAE # 0 +0xB74D 0x611A # 0 +0xB74E 0x610F # 0 +0xB74F 0x6148 # 0 +0xB750 0x611F # 0 +0xB751 0x60F3 # 0 +0xB752 0x611B # 0 +0xB753 0x60F9 # 0 +0xB754 0x6101 # 0 +0xB755 0x6108 # 0 +0xB756 0x614E # 0 +0xB757 0x614C # 0 +0xB758 0x6144 # 0 +0xB759 0x614D # 0 +0xB75A 0x613E # 0 +0xB75B 0x6134 # 0 +0xB75C 0x6127 # 0 +0xB75D 0x610D # 0 +0xB75E 0x6106 # 0 +0xB75F 0x6137 # 0 +0xB760 0x6221 # 0 +0xB761 0x6222 # 0 +0xB762 0x6413 # 0 +0xB763 0x643E # 0 +0xB764 0x641E # 0 +0xB765 0x642A # 0 +0xB766 0x642D # 0 +0xB767 0x643D # 0 +0xB768 0x642C # 0 +0xB769 0x640F # 0 +0xB76A 0x641C # 0 +0xB76B 0x6414 # 0 +0xB76C 0x640D # 0 +0xB76D 0x6436 # 0 +0xB76E 0x6416 # 0 +0xB76F 0x6417 # 0 +0xB770 0x6406 # 0 +0xB771 0x656C # 0 +0xB772 0x659F # 0 +0xB773 0x65B0 # 0 +0xB774 0x6697 # 0 +0xB775 0x6689 # 0 +0xB776 0x6687 # 0 +0xB777 0x6688 # 0 +0xB778 0x6696 # 0 +0xB779 0x6684 # 0 +0xB77A 0x6698 # 0 +0xB77B 0x668D # 0 +0xB77C 0x6703 # 0 +0xB77D 0x6994 # 0 +0xB77E 0x696D # 0 +0xB7A1 0x695A # 0 +0xB7A2 0x6977 # 0 +0xB7A3 0x6960 # 0 +0xB7A4 0x6954 # 0 +0xB7A5 0x6975 # 0 +0xB7A6 0x6930 # 0 +0xB7A7 0x6982 # 0 +0xB7A8 0x694A # 0 +0xB7A9 0x6968 # 0 +0xB7AA 0x696B # 0 +0xB7AB 0x695E # 0 +0xB7AC 0x6953 # 0 +0xB7AD 0x6979 # 0 +0xB7AE 0x6986 # 0 +0xB7AF 0x695D # 0 +0xB7B0 0x6963 # 0 +0xB7B1 0x695B # 0 +0xB7B2 0x6B47 # 0 +0xB7B3 0x6B72 # 0 +0xB7B4 0x6BC0 # 0 +0xB7B5 0x6BBF # 0 +0xB7B6 0x6BD3 # 0 +0xB7B7 0x6BFD # 0 +0xB7B8 0x6EA2 # 0 +0xB7B9 0x6EAF # 0 +0xB7BA 0x6ED3 # 0 +0xB7BB 0x6EB6 # 0 +0xB7BC 0x6EC2 # 0 +0xB7BD 0x6E90 # 0 +0xB7BE 0x6E9D # 0 +0xB7BF 0x6EC7 # 0 +0xB7C0 0x6EC5 # 0 +0xB7C1 0x6EA5 # 0 +0xB7C2 0x6E98 # 0 +0xB7C3 0x6EBC # 0 +0xB7C4 0x6EBA # 0 +0xB7C5 0x6EAB # 0 +0xB7C6 0x6ED1 # 0 +0xB7C7 0x6E96 # 0 +0xB7C8 0x6E9C # 0 +0xB7C9 0x6EC4 # 0 +0xB7CA 0x6ED4 # 0 +0xB7CB 0x6EAA # 0 +0xB7CC 0x6EA7 # 0 +0xB7CD 0x6EB4 # 0 +0xB7CE 0x714E # 0 +0xB7CF 0x7159 # 0 +0xB7D0 0x7169 # 0 +0xB7D1 0x7164 # 0 +0xB7D2 0x7149 # 0 +0xB7D3 0x7167 # 0 +0xB7D4 0x715C # 0 +0xB7D5 0x716C # 0 +0xB7D6 0x7166 # 0 +0xB7D7 0x714C # 0 +0xB7D8 0x7165 # 0 +0xB7D9 0x715E # 0 +0xB7DA 0x7146 # 0 +0xB7DB 0x7168 # 0 +0xB7DC 0x7156 # 0 +0xB7DD 0x723A # 0 +0xB7DE 0x7252 # 0 +0xB7DF 0x7337 # 0 +0xB7E0 0x7345 # 0 +0xB7E1 0x733F # 0 +0xB7E2 0x733E # 0 +0xB7E3 0x746F # 0 +0xB7E4 0x745A # 0 +0xB7E5 0x7455 # 0 +0xB7E6 0x745F # 0 +0xB7E7 0x745E # 0 +0xB7E8 0x7441 # 0 +0xB7E9 0x743F # 0 +0xB7EA 0x7459 # 0 +0xB7EB 0x745B # 0 +0xB7EC 0x745C # 0 +0xB7ED 0x7576 # 0 +0xB7EE 0x7578 # 0 +0xB7EF 0x7600 # 0 +0xB7F0 0x75F0 # 0 +0xB7F1 0x7601 # 0 +0xB7F2 0x75F2 # 0 +0xB7F3 0x75F1 # 0 +0xB7F4 0x75FA # 0 +0xB7F5 0x75FF # 0 +0xB7F6 0x75F4 # 0 +0xB7F7 0x75F3 # 0 +0xB7F8 0x76DE # 0 +0xB7F9 0x76DF # 0 +0xB7FA 0x775B # 0 +0xB7FB 0x776B # 0 +0xB7FC 0x7766 # 0 +0xB7FD 0x775E # 0 +0xB7FE 0x7763 # 0 +0xB840 0x7779 # 0 +0xB841 0x776A # 0 +0xB842 0x776C # 0 +0xB843 0x775C # 0 +0xB844 0x7765 # 0 +0xB845 0x7768 # 0 +0xB846 0x7762 # 0 +0xB847 0x77EE # 0 +0xB848 0x788E # 0 +0xB849 0x78B0 # 0 +0xB84A 0x7897 # 0 +0xB84B 0x7898 # 0 +0xB84C 0x788C # 0 +0xB84D 0x7889 # 0 +0xB84E 0x787C # 0 +0xB84F 0x7891 # 0 +0xB850 0x7893 # 0 +0xB851 0x787F # 0 +0xB852 0x797A # 0 +0xB853 0x797F # 0 +0xB854 0x7981 # 0 +0xB855 0x842C # 0 +0xB856 0x79BD # 0 +0xB857 0x7A1C # 0 +0xB858 0x7A1A # 0 +0xB859 0x7A20 # 0 +0xB85A 0x7A14 # 0 +0xB85B 0x7A1F # 0 +0xB85C 0x7A1E # 0 +0xB85D 0x7A9F # 0 +0xB85E 0x7AA0 # 0 +0xB85F 0x7B77 # 0 +0xB860 0x7BC0 # 0 +0xB861 0x7B60 # 0 +0xB862 0x7B6E # 0 +0xB863 0x7B67 # 0 +0xB864 0x7CB1 # 0 +0xB865 0x7CB3 # 0 +0xB866 0x7CB5 # 0 +0xB867 0x7D93 # 0 +0xB868 0x7D79 # 0 +0xB869 0x7D91 # 0 +0xB86A 0x7D81 # 0 +0xB86B 0x7D8F # 0 +0xB86C 0x7D5B # 0 +0xB86D 0x7F6E # 0 +0xB86E 0x7F69 # 0 +0xB86F 0x7F6A # 0 +0xB870 0x7F72 # 0 +0xB871 0x7FA9 # 0 +0xB872 0x7FA8 # 0 +0xB873 0x7FA4 # 0 +0xB874 0x8056 # 0 +0xB875 0x8058 # 0 +0xB876 0x8086 # 0 +0xB877 0x8084 # 0 +0xB878 0x8171 # 0 +0xB879 0x8170 # 0 +0xB87A 0x8178 # 0 +0xB87B 0x8165 # 0 +0xB87C 0x816E # 0 +0xB87D 0x8173 # 0 +0xB87E 0x816B # 0 +0xB8A1 0x8179 # 0 +0xB8A2 0x817A # 0 +0xB8A3 0x8166 # 0 +0xB8A4 0x8205 # 0 +0xB8A5 0x8247 # 0 +0xB8A6 0x8482 # 0 +0xB8A7 0x8477 # 0 +0xB8A8 0x843D # 0 +0xB8A9 0x8431 # 0 +0xB8AA 0x8475 # 0 +0xB8AB 0x8466 # 0 +0xB8AC 0x846B # 0 +0xB8AD 0x8449 # 0 +0xB8AE 0x846C # 0 +0xB8AF 0x845B # 0 +0xB8B0 0x843C # 0 +0xB8B1 0x8435 # 0 +0xB8B2 0x8461 # 0 +0xB8B3 0x8463 # 0 +0xB8B4 0x8469 # 0 +0xB8B5 0x846D # 0 +0xB8B6 0x8446 # 0 +0xB8B7 0x865E # 0 +0xB8B8 0x865C # 0 +0xB8B9 0x865F # 0 +0xB8BA 0x86F9 # 0 +0xB8BB 0x8713 # 0 +0xB8BC 0x8708 # 0 +0xB8BD 0x8707 # 0 +0xB8BE 0x8700 # 0 +0xB8BF 0x86FE # 0 +0xB8C0 0x86FB # 0 +0xB8C1 0x8702 # 0 +0xB8C2 0x8703 # 0 +0xB8C3 0x8706 # 0 +0xB8C4 0x870A # 0 +0xB8C5 0x8859 # 0 +0xB8C6 0x88DF # 0 +0xB8C7 0x88D4 # 0 +0xB8C8 0x88D9 # 0 +0xB8C9 0x88DC # 0 +0xB8CA 0x88D8 # 0 +0xB8CB 0x88DD # 0 +0xB8CC 0x88E1 # 0 +0xB8CD 0x88CA # 0 +0xB8CE 0x88D5 # 0 +0xB8CF 0x88D2 # 0 +0xB8D0 0x899C # 0 +0xB8D1 0x89E3 # 0 +0xB8D2 0x8A6B # 0 +0xB8D3 0x8A72 # 0 +0xB8D4 0x8A73 # 0 +0xB8D5 0x8A66 # 0 +0xB8D6 0x8A69 # 0 +0xB8D7 0x8A70 # 0 +0xB8D8 0x8A87 # 0 +0xB8D9 0x8A7C # 0 +0xB8DA 0x8A63 # 0 +0xB8DB 0x8AA0 # 0 +0xB8DC 0x8A71 # 0 +0xB8DD 0x8A85 # 0 +0xB8DE 0x8A6D # 0 +0xB8DF 0x8A62 # 0 +0xB8E0 0x8A6E # 0 +0xB8E1 0x8A6C # 0 +0xB8E2 0x8A79 # 0 +0xB8E3 0x8A7B # 0 +0xB8E4 0x8A3E # 0 +0xB8E5 0x8A68 # 0 +0xB8E6 0x8C62 # 0 +0xB8E7 0x8C8A # 0 +0xB8E8 0x8C89 # 0 +0xB8E9 0x8CCA # 0 +0xB8EA 0x8CC7 # 0 +0xB8EB 0x8CC8 # 0 +0xB8EC 0x8CC4 # 0 +0xB8ED 0x8CB2 # 0 +0xB8EE 0x8CC3 # 0 +0xB8EF 0x8CC2 # 0 +0xB8F0 0x8CC5 # 0 +0xB8F1 0x8DE1 # 0 +0xB8F2 0x8DDF # 0 +0xB8F3 0x8DE8 # 0 +0xB8F4 0x8DEF # 0 +0xB8F5 0x8DF3 # 0 +0xB8F6 0x8DFA # 0 +0xB8F7 0x8DEA # 0 +0xB8F8 0x8DE4 # 0 +0xB8F9 0x8DE6 # 0 +0xB8FA 0x8EB2 # 0 +0xB8FB 0x8F03 # 0 +0xB8FC 0x8F09 # 0 +0xB8FD 0x8EFE # 0 +0xB8FE 0x8F0A # 0 +0xB940 0x8F9F # 0 +0xB941 0x8FB2 # 0 +0xB942 0x904B # 0 +0xB943 0x904A # 0 +0xB944 0x9053 # 0 +0xB945 0x9042 # 0 +0xB946 0x9054 # 0 +0xB947 0x903C # 0 +0xB948 0x9055 # 0 +0xB949 0x9050 # 0 +0xB94A 0x9047 # 0 +0xB94B 0x904F # 0 +0xB94C 0x904E # 0 +0xB94D 0x904D # 0 +0xB94E 0x9051 # 0 +0xB94F 0x903E # 0 +0xB950 0x9041 # 0 +0xB951 0x9112 # 0 +0xB952 0x9117 # 0 +0xB953 0x916C # 0 +0xB954 0x916A # 0 +0xB955 0x9169 # 0 +0xB956 0x91C9 # 0 +0xB957 0x9237 # 0 +0xB958 0x9257 # 0 +0xB959 0x9238 # 0 +0xB95A 0x923D # 0 +0xB95B 0x9240 # 0 +0xB95C 0x923E # 0 +0xB95D 0x925B # 0 +0xB95E 0x924B # 0 +0xB95F 0x9264 # 0 +0xB960 0x9251 # 0 +0xB961 0x9234 # 0 +0xB962 0x9249 # 0 +0xB963 0x924D # 0 +0xB964 0x9245 # 0 +0xB965 0x9239 # 0 +0xB966 0x923F # 0 +0xB967 0x925A # 0 +0xB968 0x9598 # 0 +0xB969 0x9698 # 0 +0xB96A 0x9694 # 0 +0xB96B 0x9695 # 0 +0xB96C 0x96CD # 0 +0xB96D 0x96CB # 0 +0xB96E 0x96C9 # 0 +0xB96F 0x96CA # 0 +0xB970 0x96F7 # 0 +0xB971 0x96FB # 0 +0xB972 0x96F9 # 0 +0xB973 0x96F6 # 0 +0xB974 0x9756 # 0 +0xB975 0x9774 # 0 +0xB976 0x9776 # 0 +0xB977 0x9810 # 0 +0xB978 0x9811 # 0 +0xB979 0x9813 # 0 +0xB97A 0x980A # 0 +0xB97B 0x9812 # 0 +0xB97C 0x980C # 0 +0xB97D 0x98FC # 0 +0xB97E 0x98F4 # 0 +0xB9A1 0x98FD # 0 +0xB9A2 0x98FE # 0 +0xB9A3 0x99B3 # 0 +0xB9A4 0x99B1 # 0 +0xB9A5 0x99B4 # 0 +0xB9A6 0x9AE1 # 0 +0xB9A7 0x9CE9 # 0 +0xB9A8 0x9E82 # 0 +0xB9A9 0x9F0E # 0 +0xB9AA 0x9F13 # 0 +0xB9AB 0x9F20 # 0 +0xB9AC 0x50E7 # 0 +0xB9AD 0x50EE # 0 +0xB9AE 0x50E5 # 0 +0xB9AF 0x50D6 # 0 +0xB9B0 0x50ED # 0 +0xB9B1 0x50DA # 0 +0xB9B2 0x50D5 # 0 +0xB9B3 0x50CF # 0 +0xB9B4 0x50D1 # 0 +0xB9B5 0x50F1 # 0 +0xB9B6 0x50CE # 0 +0xB9B7 0x50E9 # 0 +0xB9B8 0x5162 # 0 +0xB9B9 0x51F3 # 0 +0xB9BA 0x5283 # 0 +0xB9BB 0x5282 # 0 +0xB9BC 0x5331 # 0 +0xB9BD 0x53AD # 0 +0xB9BE 0x55FE # 0 +0xB9BF 0x5600 # 0 +0xB9C0 0x561B # 0 +0xB9C1 0x5617 # 0 +0xB9C2 0x55FD # 0 +0xB9C3 0x5614 # 0 +0xB9C4 0x5606 # 0 +0xB9C5 0x5609 # 0 +0xB9C6 0x560D # 0 +0xB9C7 0x560E # 0 +0xB9C8 0x55F7 # 0 +0xB9C9 0x5616 # 0 +0xB9CA 0x561F # 0 +0xB9CB 0x5608 # 0 +0xB9CC 0x5610 # 0 +0xB9CD 0x55F6 # 0 +0xB9CE 0x5718 # 0 +0xB9CF 0x5716 # 0 +0xB9D0 0x5875 # 0 +0xB9D1 0x587E # 0 +0xB9D2 0x5883 # 0 +0xB9D3 0x5893 # 0 +0xB9D4 0x588A # 0 +0xB9D5 0x5879 # 0 +0xB9D6 0x5885 # 0 +0xB9D7 0x587D # 0 +0xB9D8 0x58FD # 0 +0xB9D9 0x5925 # 0 +0xB9DA 0x5922 # 0 +0xB9DB 0x5924 # 0 +0xB9DC 0x596A # 0 +0xB9DD 0x5969 # 0 +0xB9DE 0x5AE1 # 0 +0xB9DF 0x5AE6 # 0 +0xB9E0 0x5AE9 # 0 +0xB9E1 0x5AD7 # 0 +0xB9E2 0x5AD6 # 0 +0xB9E3 0x5AD8 # 0 +0xB9E4 0x5AE3 # 0 +0xB9E5 0x5B75 # 0 +0xB9E6 0x5BDE # 0 +0xB9E7 0x5BE7 # 0 +0xB9E8 0x5BE1 # 0 +0xB9E9 0x5BE5 # 0 +0xB9EA 0x5BE6 # 0 +0xB9EB 0x5BE8 # 0 +0xB9EC 0x5BE2 # 0 +0xB9ED 0x5BE4 # 0 +0xB9EE 0x5BDF # 0 +0xB9EF 0x5C0D # 0 +0xB9F0 0x5C62 # 0 +0xB9F1 0x5D84 # 0 +0xB9F2 0x5D87 # 0 +0xB9F3 0x5E5B # 0 +0xB9F4 0x5E63 # 0 +0xB9F5 0x5E55 # 0 +0xB9F6 0x5E57 # 0 +0xB9F7 0x5E54 # 0 +0xB9F8 0x5ED3 # 0 +0xB9F9 0x5ED6 # 0 +0xB9FA 0x5F0A # 0 +0xB9FB 0x5F46 # 0 +0xB9FC 0x5F70 # 0 +0xB9FD 0x5FB9 # 0 +0xB9FE 0x6147 # 0 +0xBA40 0x613F # 0 +0xBA41 0x614B # 0 +0xBA42 0x6177 # 0 +0xBA43 0x6162 # 0 +0xBA44 0x6163 # 0 +0xBA45 0x615F # 0 +0xBA46 0x615A # 0 +0xBA47 0x6158 # 0 +0xBA48 0x6175 # 0 +0xBA49 0x622A # 0 +0xBA4A 0x6487 # 0 +0xBA4B 0x6458 # 0 +0xBA4C 0x6454 # 0 +0xBA4D 0x64A4 # 0 +0xBA4E 0x6478 # 0 +0xBA4F 0x645F # 0 +0xBA50 0x647A # 0 +0xBA51 0x6451 # 0 +0xBA52 0x6467 # 0 +0xBA53 0x6434 # 0 +0xBA54 0x646D # 0 +0xBA55 0x647B # 0 +0xBA56 0x6572 # 0 +0xBA57 0x65A1 # 0 +0xBA58 0x65D7 # 0 +0xBA59 0x65D6 # 0 +0xBA5A 0x66A2 # 0 +0xBA5B 0x66A8 # 0 +0xBA5C 0x669D # 0 +0xBA5D 0x699C # 0 +0xBA5E 0x69A8 # 0 +0xBA5F 0x6995 # 0 +0xBA60 0x69C1 # 0 +0xBA61 0x69AE # 0 +0xBA62 0x69D3 # 0 +0xBA63 0x69CB # 0 +0xBA64 0x699B # 0 +0xBA65 0x69B7 # 0 +0xBA66 0x69BB # 0 +0xBA67 0x69AB # 0 +0xBA68 0x69B4 # 0 +0xBA69 0x69D0 # 0 +0xBA6A 0x69CD # 0 +0xBA6B 0x69AD # 0 +0xBA6C 0x69CC # 0 +0xBA6D 0x69A6 # 0 +0xBA6E 0x69C3 # 0 +0xBA6F 0x69A3 # 0 +0xBA70 0x6B49 # 0 +0xBA71 0x6B4C # 0 +0xBA72 0x6C33 # 0 +0xBA73 0x6F33 # 0 +0xBA74 0x6F14 # 0 +0xBA75 0x6EFE # 0 +0xBA76 0x6F13 # 0 +0xBA77 0x6EF4 # 0 +0xBA78 0x6F29 # 0 +0xBA79 0x6F3E # 0 +0xBA7A 0x6F20 # 0 +0xBA7B 0x6F2C # 0 +0xBA7C 0x6F0F # 0 +0xBA7D 0x6F02 # 0 +0xBA7E 0x6F22 # 0 +0xBAA1 0x6EFF # 0 +0xBAA2 0x6EEF # 0 +0xBAA3 0x6F06 # 0 +0xBAA4 0x6F31 # 0 +0xBAA5 0x6F38 # 0 +0xBAA6 0x6F32 # 0 +0xBAA7 0x6F23 # 0 +0xBAA8 0x6F15 # 0 +0xBAA9 0x6F2B # 0 +0xBAAA 0x6F2F # 0 +0xBAAB 0x6F88 # 0 +0xBAAC 0x6F2A # 0 +0xBAAD 0x6EEC # 0 +0xBAAE 0x6F01 # 0 +0xBAAF 0x6EF2 # 0 +0xBAB0 0x6ECC # 0 +0xBAB1 0x6EF7 # 0 +0xBAB2 0x7194 # 0 +0xBAB3 0x7199 # 0 +0xBAB4 0x717D # 0 +0xBAB5 0x718A # 0 +0xBAB6 0x7184 # 0 +0xBAB7 0x7192 # 0 +0xBAB8 0x723E # 0 +0xBAB9 0x7292 # 0 +0xBABA 0x7296 # 0 +0xBABB 0x7344 # 0 +0xBABC 0x7350 # 0 +0xBABD 0x7464 # 0 +0xBABE 0x7463 # 0 +0xBABF 0x746A # 0 +0xBAC0 0x7470 # 0 +0xBAC1 0x746D # 0 +0xBAC2 0x7504 # 0 +0xBAC3 0x7591 # 0 +0xBAC4 0x7627 # 0 +0xBAC5 0x760D # 0 +0xBAC6 0x760B # 0 +0xBAC7 0x7609 # 0 +0xBAC8 0x7613 # 0 +0xBAC9 0x76E1 # 0 +0xBACA 0x76E3 # 0 +0xBACB 0x7784 # 0 +0xBACC 0x777D # 0 +0xBACD 0x777F # 0 +0xBACE 0x7761 # 0 +0xBACF 0x78C1 # 0 +0xBAD0 0x789F # 0 +0xBAD1 0x78A7 # 0 +0xBAD2 0x78B3 # 0 +0xBAD3 0x78A9 # 0 +0xBAD4 0x78A3 # 0 +0xBAD5 0x798E # 0 +0xBAD6 0x798F # 0 +0xBAD7 0x798D # 0 +0xBAD8 0x7A2E # 0 +0xBAD9 0x7A31 # 0 +0xBADA 0x7AAA # 0 +0xBADB 0x7AA9 # 0 +0xBADC 0x7AED # 0 +0xBADD 0x7AEF # 0 +0xBADE 0x7BA1 # 0 +0xBADF 0x7B95 # 0 +0xBAE0 0x7B8B # 0 +0xBAE1 0x7B75 # 0 +0xBAE2 0x7B97 # 0 +0xBAE3 0x7B9D # 0 +0xBAE4 0x7B94 # 0 +0xBAE5 0x7B8F # 0 +0xBAE6 0x7BB8 # 0 +0xBAE7 0x7B87 # 0 +0xBAE8 0x7B84 # 0 +0xBAE9 0x7CB9 # 0 +0xBAEA 0x7CBD # 0 +0xBAEB 0x7CBE # 0 +0xBAEC 0x7DBB # 0 +0xBAED 0x7DB0 # 0 +0xBAEE 0x7D9C # 0 +0xBAEF 0x7DBD # 0 +0xBAF0 0x7DBE # 0 +0xBAF1 0x7DA0 # 0 +0xBAF2 0x7DCA # 0 +0xBAF3 0x7DB4 # 0 +0xBAF4 0x7DB2 # 0 +0xBAF5 0x7DB1 # 0 +0xBAF6 0x7DBA # 0 +0xBAF7 0x7DA2 # 0 +0xBAF8 0x7DBF # 0 +0xBAF9 0x7DB5 # 0 +0xBAFA 0x7DB8 # 0 +0xBAFB 0x7DAD # 0 +0xBAFC 0x7DD2 # 0 +0xBAFD 0x7DC7 # 0 +0xBAFE 0x7DAC # 0 +0xBB40 0x7F70 # 0 +0xBB41 0x7FE0 # 0 +0xBB42 0x7FE1 # 0 +0xBB43 0x7FDF # 0 +0xBB44 0x805E # 0 +0xBB45 0x805A # 0 +0xBB46 0x8087 # 0 +0xBB47 0x8150 # 0 +0xBB48 0x8180 # 0 +0xBB49 0x818F # 0 +0xBB4A 0x8188 # 0 +0xBB4B 0x818A # 0 +0xBB4C 0x817F # 0 +0xBB4D 0x8182 # 0 +0xBB4E 0x81E7 # 0 +0xBB4F 0x81FA # 0 +0xBB50 0x8207 # 0 +0xBB51 0x8214 # 0 +0xBB52 0x821E # 0 +0xBB53 0x824B # 0 +0xBB54 0x84C9 # 0 +0xBB55 0x84BF # 0 +0xBB56 0x84C6 # 0 +0xBB57 0x84C4 # 0 +0xBB58 0x8499 # 0 +0xBB59 0x849E # 0 +0xBB5A 0x84B2 # 0 +0xBB5B 0x849C # 0 +0xBB5C 0x84CB # 0 +0xBB5D 0x84B8 # 0 +0xBB5E 0x84C0 # 0 +0xBB5F 0x84D3 # 0 +0xBB60 0x8490 # 0 +0xBB61 0x84BC # 0 +0xBB62 0x84D1 # 0 +0xBB63 0x84CA # 0 +0xBB64 0x873F # 0 +0xBB65 0x871C # 0 +0xBB66 0x873B # 0 +0xBB67 0x8722 # 0 +0xBB68 0x8725 # 0 +0xBB69 0x8734 # 0 +0xBB6A 0x8718 # 0 +0xBB6B 0x8755 # 0 +0xBB6C 0x8737 # 0 +0xBB6D 0x8729 # 0 +0xBB6E 0x88F3 # 0 +0xBB6F 0x8902 # 0 +0xBB70 0x88F4 # 0 +0xBB71 0x88F9 # 0 +0xBB72 0x88F8 # 0 +0xBB73 0x88FD # 0 +0xBB74 0x88E8 # 0 +0xBB75 0x891A # 0 +0xBB76 0x88EF # 0 +0xBB77 0x8AA6 # 0 +0xBB78 0x8A8C # 0 +0xBB79 0x8A9E # 0 +0xBB7A 0x8AA3 # 0 +0xBB7B 0x8A8D # 0 +0xBB7C 0x8AA1 # 0 +0xBB7D 0x8A93 # 0 +0xBB7E 0x8AA4 # 0 +0xBBA1 0x8AAA # 0 +0xBBA2 0x8AA5 # 0 +0xBBA3 0x8AA8 # 0 +0xBBA4 0x8A98 # 0 +0xBBA5 0x8A91 # 0 +0xBBA6 0x8A9A # 0 +0xBBA7 0x8AA7 # 0 +0xBBA8 0x8C6A # 0 +0xBBA9 0x8C8D # 0 +0xBBAA 0x8C8C # 0 +0xBBAB 0x8CD3 # 0 +0xBBAC 0x8CD1 # 0 +0xBBAD 0x8CD2 # 0 +0xBBAE 0x8D6B # 0 +0xBBAF 0x8D99 # 0 +0xBBB0 0x8D95 # 0 +0xBBB1 0x8DFC # 0 +0xBBB2 0x8F14 # 0 +0xBBB3 0x8F12 # 0 +0xBBB4 0x8F15 # 0 +0xBBB5 0x8F13 # 0 +0xBBB6 0x8FA3 # 0 +0xBBB7 0x9060 # 0 +0xBBB8 0x9058 # 0 +0xBBB9 0x905C # 0 +0xBBBA 0x9063 # 0 +0xBBBB 0x9059 # 0 +0xBBBC 0x905E # 0 +0xBBBD 0x9062 # 0 +0xBBBE 0x905D # 0 +0xBBBF 0x905B # 0 +0xBBC0 0x9119 # 0 +0xBBC1 0x9118 # 0 +0xBBC2 0x911E # 0 +0xBBC3 0x9175 # 0 +0xBBC4 0x9178 # 0 +0xBBC5 0x9177 # 0 +0xBBC6 0x9174 # 0 +0xBBC7 0x9278 # 0 +0xBBC8 0x9280 # 0 +0xBBC9 0x9285 # 0 +0xBBCA 0x9298 # 0 +0xBBCB 0x9296 # 0 +0xBBCC 0x927B # 0 +0xBBCD 0x9293 # 0 +0xBBCE 0x929C # 0 +0xBBCF 0x92A8 # 0 +0xBBD0 0x927C # 0 +0xBBD1 0x9291 # 0 +0xBBD2 0x95A1 # 0 +0xBBD3 0x95A8 # 0 +0xBBD4 0x95A9 # 0 +0xBBD5 0x95A3 # 0 +0xBBD6 0x95A5 # 0 +0xBBD7 0x95A4 # 0 +0xBBD8 0x9699 # 0 +0xBBD9 0x969C # 0 +0xBBDA 0x969B # 0 +0xBBDB 0x96CC # 0 +0xBBDC 0x96D2 # 0 +0xBBDD 0x9700 # 0 +0xBBDE 0x977C # 0 +0xBBDF 0x9785 # 0 +0xBBE0 0x97F6 # 0 +0xBBE1 0x9817 # 0 +0xBBE2 0x9818 # 0 +0xBBE3 0x98AF # 0 +0xBBE4 0x98B1 # 0 +0xBBE5 0x9903 # 0 +0xBBE6 0x9905 # 0 +0xBBE7 0x990C # 0 +0xBBE8 0x9909 # 0 +0xBBE9 0x99C1 # 0 +0xBBEA 0x9AAF # 0 +0xBBEB 0x9AB0 # 0 +0xBBEC 0x9AE6 # 0 +0xBBED 0x9B41 # 0 +0xBBEE 0x9B42 # 0 +0xBBEF 0x9CF4 # 0 +0xBBF0 0x9CF6 # 0 +0xBBF1 0x9CF3 # 0 +0xBBF2 0x9EBC # 0 +0xBBF3 0x9F3B # 0 +0xBBF4 0x9F4A # 0 +0xBBF5 0x5104 # 0 +0xBBF6 0x5100 # 0 +0xBBF7 0x50FB # 0 +0xBBF8 0x50F5 # 0 +0xBBF9 0x50F9 # 0 +0xBBFA 0x5102 # 0 +0xBBFB 0x5108 # 0 +0xBBFC 0x5109 # 0 +0xBBFD 0x5105 # 0 +0xBBFE 0x51DC # 0 +0xBC40 0x5287 # 0 +0xBC41 0x5288 # 0 +0xBC42 0x5289 # 0 +0xBC43 0x528D # 0 +0xBC44 0x528A # 0 +0xBC45 0x52F0 # 0 +0xBC46 0x53B2 # 0 +0xBC47 0x562E # 0 +0xBC48 0x563B # 0 +0xBC49 0x5639 # 0 +0xBC4A 0x5632 # 0 +0xBC4B 0x563F # 0 +0xBC4C 0x5634 # 0 +0xBC4D 0x5629 # 0 +0xBC4E 0x5653 # 0 +0xBC4F 0x564E # 0 +0xBC50 0x5657 # 0 +0xBC51 0x5674 # 0 +0xBC52 0x5636 # 0 +0xBC53 0x562F # 0 +0xBC54 0x5630 # 0 +0xBC55 0x5880 # 0 +0xBC56 0x589F # 0 +0xBC57 0x589E # 0 +0xBC58 0x58B3 # 0 +0xBC59 0x589C # 0 +0xBC5A 0x58AE # 0 +0xBC5B 0x58A9 # 0 +0xBC5C 0x58A6 # 0 +0xBC5D 0x596D # 0 +0xBC5E 0x5B09 # 0 +0xBC5F 0x5AFB # 0 +0xBC60 0x5B0B # 0 +0xBC61 0x5AF5 # 0 +0xBC62 0x5B0C # 0 +0xBC63 0x5B08 # 0 +0xBC64 0x5BEE # 0 +0xBC65 0x5BEC # 0 +0xBC66 0x5BE9 # 0 +0xBC67 0x5BEB # 0 +0xBC68 0x5C64 # 0 +0xBC69 0x5C65 # 0 +0xBC6A 0x5D9D # 0 +0xBC6B 0x5D94 # 0 +0xBC6C 0x5E62 # 0 +0xBC6D 0x5E5F # 0 +0xBC6E 0x5E61 # 0 +0xBC6F 0x5EE2 # 0 +0xBC70 0x5EDA # 0 +0xBC71 0x5EDF # 0 +0xBC72 0x5EDD # 0 +0xBC73 0x5EE3 # 0 +0xBC74 0x5EE0 # 0 +0xBC75 0x5F48 # 0 +0xBC76 0x5F71 # 0 +0xBC77 0x5FB7 # 0 +0xBC78 0x5FB5 # 0 +0xBC79 0x6176 # 0 +0xBC7A 0x6167 # 0 +0xBC7B 0x616E # 0 +0xBC7C 0x615D # 0 +0xBC7D 0x6155 # 0 +0xBC7E 0x6182 # 0 +0xBCA1 0x617C # 0 +0xBCA2 0x6170 # 0 +0xBCA3 0x616B # 0 +0xBCA4 0x617E # 0 +0xBCA5 0x61A7 # 0 +0xBCA6 0x6190 # 0 +0xBCA7 0x61AB # 0 +0xBCA8 0x618E # 0 +0xBCA9 0x61AC # 0 +0xBCAA 0x619A # 0 +0xBCAB 0x61A4 # 0 +0xBCAC 0x6194 # 0 +0xBCAD 0x61AE # 0 +0xBCAE 0x622E # 0 +0xBCAF 0x6469 # 0 +0xBCB0 0x646F # 0 +0xBCB1 0x6479 # 0 +0xBCB2 0x649E # 0 +0xBCB3 0x64B2 # 0 +0xBCB4 0x6488 # 0 +0xBCB5 0x6490 # 0 +0xBCB6 0x64B0 # 0 +0xBCB7 0x64A5 # 0 +0xBCB8 0x6493 # 0 +0xBCB9 0x6495 # 0 +0xBCBA 0x64A9 # 0 +0xBCBB 0x6492 # 0 +0xBCBC 0x64AE # 0 +0xBCBD 0x64AD # 0 +0xBCBE 0x64AB # 0 +0xBCBF 0x649A # 0 +0xBCC0 0x64AC # 0 +0xBCC1 0x6499 # 0 +0xBCC2 0x64A2 # 0 +0xBCC3 0x64B3 # 0 +0xBCC4 0x6575 # 0 +0xBCC5 0x6577 # 0 +0xBCC6 0x6578 # 0 +0xBCC7 0x66AE # 0 +0xBCC8 0x66AB # 0 +0xBCC9 0x66B4 # 0 +0xBCCA 0x66B1 # 0 +0xBCCB 0x6A23 # 0 +0xBCCC 0x6A1F # 0 +0xBCCD 0x69E8 # 0 +0xBCCE 0x6A01 # 0 +0xBCCF 0x6A1E # 0 +0xBCD0 0x6A19 # 0 +0xBCD1 0x69FD # 0 +0xBCD2 0x6A21 # 0 +0xBCD3 0x6A13 # 0 +0xBCD4 0x6A0A # 0 +0xBCD5 0x69F3 # 0 +0xBCD6 0x6A02 # 0 +0xBCD7 0x6A05 # 0 +0xBCD8 0x69ED # 0 +0xBCD9 0x6A11 # 0 +0xBCDA 0x6B50 # 0 +0xBCDB 0x6B4E # 0 +0xBCDC 0x6BA4 # 0 +0xBCDD 0x6BC5 # 0 +0xBCDE 0x6BC6 # 0 +0xBCDF 0x6F3F # 0 +0xBCE0 0x6F7C # 0 +0xBCE1 0x6F84 # 0 +0xBCE2 0x6F51 # 0 +0xBCE3 0x6F66 # 0 +0xBCE4 0x6F54 # 0 +0xBCE5 0x6F86 # 0 +0xBCE6 0x6F6D # 0 +0xBCE7 0x6F5B # 0 +0xBCE8 0x6F78 # 0 +0xBCE9 0x6F6E # 0 +0xBCEA 0x6F8E # 0 +0xBCEB 0x6F7A # 0 +0xBCEC 0x6F70 # 0 +0xBCED 0x6F64 # 0 +0xBCEE 0x6F97 # 0 +0xBCEF 0x6F58 # 0 +0xBCF0 0x6ED5 # 0 +0xBCF1 0x6F6F # 0 +0xBCF2 0x6F60 # 0 +0xBCF3 0x6F5F # 0 +0xBCF4 0x719F # 0 +0xBCF5 0x71AC # 0 +0xBCF6 0x71B1 # 0 +0xBCF7 0x71A8 # 0 +0xBCF8 0x7256 # 0 +0xBCF9 0x729B # 0 +0xBCFA 0x734E # 0 +0xBCFB 0x7357 # 0 +0xBCFC 0x7469 # 0 +0xBCFD 0x748B # 0 +0xBCFE 0x7483 # 0 +0xBD40 0x747E # 0 +0xBD41 0x7480 # 0 +0xBD42 0x757F # 0 +0xBD43 0x7620 # 0 +0xBD44 0x7629 # 0 +0xBD45 0x761F # 0 +0xBD46 0x7624 # 0 +0xBD47 0x7626 # 0 +0xBD48 0x7621 # 0 +0xBD49 0x7622 # 0 +0xBD4A 0x769A # 0 +0xBD4B 0x76BA # 0 +0xBD4C 0x76E4 # 0 +0xBD4D 0x778E # 0 +0xBD4E 0x7787 # 0 +0xBD4F 0x778C # 0 +0xBD50 0x7791 # 0 +0xBD51 0x778B # 0 +0xBD52 0x78CB # 0 +0xBD53 0x78C5 # 0 +0xBD54 0x78BA # 0 +0xBD55 0x78CA # 0 +0xBD56 0x78BE # 0 +0xBD57 0x78D5 # 0 +0xBD58 0x78BC # 0 +0xBD59 0x78D0 # 0 +0xBD5A 0x7A3F # 0 +0xBD5B 0x7A3C # 0 +0xBD5C 0x7A40 # 0 +0xBD5D 0x7A3D # 0 +0xBD5E 0x7A37 # 0 +0xBD5F 0x7A3B # 0 +0xBD60 0x7AAF # 0 +0xBD61 0x7AAE # 0 +0xBD62 0x7BAD # 0 +0xBD63 0x7BB1 # 0 +0xBD64 0x7BC4 # 0 +0xBD65 0x7BB4 # 0 +0xBD66 0x7BC6 # 0 +0xBD67 0x7BC7 # 0 +0xBD68 0x7BC1 # 0 +0xBD69 0x7BA0 # 0 +0xBD6A 0x7BCC # 0 +0xBD6B 0x7CCA # 0 +0xBD6C 0x7DE0 # 0 +0xBD6D 0x7DF4 # 0 +0xBD6E 0x7DEF # 0 +0xBD6F 0x7DFB # 0 +0xBD70 0x7DD8 # 0 +0xBD71 0x7DEC # 0 +0xBD72 0x7DDD # 0 +0xBD73 0x7DE8 # 0 +0xBD74 0x7DE3 # 0 +0xBD75 0x7DDA # 0 +0xBD76 0x7DDE # 0 +0xBD77 0x7DE9 # 0 +0xBD78 0x7D9E # 0 +0xBD79 0x7DD9 # 0 +0xBD7A 0x7DF2 # 0 +0xBD7B 0x7DF9 # 0 +0xBD7C 0x7F75 # 0 +0xBD7D 0x7F77 # 0 +0xBD7E 0x7FAF # 0 +0xBDA1 0x7FE9 # 0 +0xBDA2 0x8026 # 0 +0xBDA3 0x819B # 0 +0xBDA4 0x819C # 0 +0xBDA5 0x819D # 0 +0xBDA6 0x81A0 # 0 +0xBDA7 0x819A # 0 +0xBDA8 0x8198 # 0 +0xBDA9 0x8517 # 0 +0xBDAA 0x853D # 0 +0xBDAB 0x851A # 0 +0xBDAC 0x84EE # 0 +0xBDAD 0x852C # 0 +0xBDAE 0x852D # 0 +0xBDAF 0x8513 # 0 +0xBDB0 0x8511 # 0 +0xBDB1 0x8523 # 0 +0xBDB2 0x8521 # 0 +0xBDB3 0x8514 # 0 +0xBDB4 0x84EC # 0 +0xBDB5 0x8525 # 0 +0xBDB6 0x84FF # 0 +0xBDB7 0x8506 # 0 +0xBDB8 0x8782 # 0 +0xBDB9 0x8774 # 0 +0xBDBA 0x8776 # 0 +0xBDBB 0x8760 # 0 +0xBDBC 0x8766 # 0 +0xBDBD 0x8778 # 0 +0xBDBE 0x8768 # 0 +0xBDBF 0x8759 # 0 +0xBDC0 0x8757 # 0 +0xBDC1 0x874C # 0 +0xBDC2 0x8753 # 0 +0xBDC3 0x885B # 0 +0xBDC4 0x885D # 0 +0xBDC5 0x8910 # 0 +0xBDC6 0x8907 # 0 +0xBDC7 0x8912 # 0 +0xBDC8 0x8913 # 0 +0xBDC9 0x8915 # 0 +0xBDCA 0x890A # 0 +0xBDCB 0x8ABC # 0 +0xBDCC 0x8AD2 # 0 +0xBDCD 0x8AC7 # 0 +0xBDCE 0x8AC4 # 0 +0xBDCF 0x8A95 # 0 +0xBDD0 0x8ACB # 0 +0xBDD1 0x8AF8 # 0 +0xBDD2 0x8AB2 # 0 +0xBDD3 0x8AC9 # 0 +0xBDD4 0x8AC2 # 0 +0xBDD5 0x8ABF # 0 +0xBDD6 0x8AB0 # 0 +0xBDD7 0x8AD6 # 0 +0xBDD8 0x8ACD # 0 +0xBDD9 0x8AB6 # 0 +0xBDDA 0x8AB9 # 0 +0xBDDB 0x8ADB # 0 +0xBDDC 0x8C4C # 0 +0xBDDD 0x8C4E # 0 +0xBDDE 0x8C6C # 0 +0xBDDF 0x8CE0 # 0 +0xBDE0 0x8CDE # 0 +0xBDE1 0x8CE6 # 0 +0xBDE2 0x8CE4 # 0 +0xBDE3 0x8CEC # 0 +0xBDE4 0x8CED # 0 +0xBDE5 0x8CE2 # 0 +0xBDE6 0x8CE3 # 0 +0xBDE7 0x8CDC # 0 +0xBDE8 0x8CEA # 0 +0xBDE9 0x8CE1 # 0 +0xBDEA 0x8D6D # 0 +0xBDEB 0x8D9F # 0 +0xBDEC 0x8DA3 # 0 +0xBDED 0x8E2B # 0 +0xBDEE 0x8E10 # 0 +0xBDEF 0x8E1D # 0 +0xBDF0 0x8E22 # 0 +0xBDF1 0x8E0F # 0 +0xBDF2 0x8E29 # 0 +0xBDF3 0x8E1F # 0 +0xBDF4 0x8E21 # 0 +0xBDF5 0x8E1E # 0 +0xBDF6 0x8EBA # 0 +0xBDF7 0x8F1D # 0 +0xBDF8 0x8F1B # 0 +0xBDF9 0x8F1F # 0 +0xBDFA 0x8F29 # 0 +0xBDFB 0x8F26 # 0 +0xBDFC 0x8F2A # 0 +0xBDFD 0x8F1C # 0 +0xBDFE 0x8F1E # 0 +0xBE40 0x8F25 # 0 +0xBE41 0x9069 # 0 +0xBE42 0x906E # 0 +0xBE43 0x9068 # 0 +0xBE44 0x906D # 0 +0xBE45 0x9077 # 0 +0xBE46 0x9130 # 0 +0xBE47 0x912D # 0 +0xBE48 0x9127 # 0 +0xBE49 0x9131 # 0 +0xBE4A 0x9187 # 0 +0xBE4B 0x9189 # 0 +0xBE4C 0x918B # 0 +0xBE4D 0x9183 # 0 +0xBE4E 0x92C5 # 0 +0xBE4F 0x92BB # 0 +0xBE50 0x92B7 # 0 +0xBE51 0x92EA # 0 +0xBE52 0x92AC # 0 +0xBE53 0x92E4 # 0 +0xBE54 0x92C1 # 0 +0xBE55 0x92B3 # 0 +0xBE56 0x92BC # 0 +0xBE57 0x92D2 # 0 +0xBE58 0x92C7 # 0 +0xBE59 0x92F0 # 0 +0xBE5A 0x92B2 # 0 +0xBE5B 0x95AD # 0 +0xBE5C 0x95B1 # 0 +0xBE5D 0x9704 # 0 +0xBE5E 0x9706 # 0 +0xBE5F 0x9707 # 0 +0xBE60 0x9709 # 0 +0xBE61 0x9760 # 0 +0xBE62 0x978D # 0 +0xBE63 0x978B # 0 +0xBE64 0x978F # 0 +0xBE65 0x9821 # 0 +0xBE66 0x982B # 0 +0xBE67 0x981C # 0 +0xBE68 0x98B3 # 0 +0xBE69 0x990A # 0 +0xBE6A 0x9913 # 0 +0xBE6B 0x9912 # 0 +0xBE6C 0x9918 # 0 +0xBE6D 0x99DD # 0 +0xBE6E 0x99D0 # 0 +0xBE6F 0x99DF # 0 +0xBE70 0x99DB # 0 +0xBE71 0x99D1 # 0 +0xBE72 0x99D5 # 0 +0xBE73 0x99D2 # 0 +0xBE74 0x99D9 # 0 +0xBE75 0x9AB7 # 0 +0xBE76 0x9AEE # 0 +0xBE77 0x9AEF # 0 +0xBE78 0x9B27 # 0 +0xBE79 0x9B45 # 0 +0xBE7A 0x9B44 # 0 +0xBE7B 0x9B77 # 0 +0xBE7C 0x9B6F # 0 +0xBE7D 0x9D06 # 0 +0xBE7E 0x9D09 # 0 +0xBEA1 0x9D03 # 0 +0xBEA2 0x9EA9 # 0 +0xBEA3 0x9EBE # 0 +0xBEA4 0x9ECE # 0 +0xBEA5 0x58A8 # 0 +0xBEA6 0x9F52 # 0 +0xBEA7 0x5112 # 0 +0xBEA8 0x5118 # 0 +0xBEA9 0x5114 # 0 +0xBEAA 0x5110 # 0 +0xBEAB 0x5115 # 0 +0xBEAC 0x5180 # 0 +0xBEAD 0x51AA # 0 +0xBEAE 0x51DD # 0 +0xBEAF 0x5291 # 0 +0xBEB0 0x5293 # 0 +0xBEB1 0x52F3 # 0 +0xBEB2 0x5659 # 0 +0xBEB3 0x566B # 0 +0xBEB4 0x5679 # 0 +0xBEB5 0x5669 # 0 +0xBEB6 0x5664 # 0 +0xBEB7 0x5678 # 0 +0xBEB8 0x566A # 0 +0xBEB9 0x5668 # 0 +0xBEBA 0x5665 # 0 +0xBEBB 0x5671 # 0 +0xBEBC 0x566F # 0 +0xBEBD 0x566C # 0 +0xBEBE 0x5662 # 0 +0xBEBF 0x5676 # 0 +0xBEC0 0x58C1 # 0 +0xBEC1 0x58BE # 0 +0xBEC2 0x58C7 # 0 +0xBEC3 0x58C5 # 0 +0xBEC4 0x596E # 0 +0xBEC5 0x5B1D # 0 +0xBEC6 0x5B34 # 0 +0xBEC7 0x5B78 # 0 +0xBEC8 0x5BF0 # 0 +0xBEC9 0x5C0E # 0 +0xBECA 0x5F4A # 0 +0xBECB 0x61B2 # 0 +0xBECC 0x6191 # 0 +0xBECD 0x61A9 # 0 +0xBECE 0x618A # 0 +0xBECF 0x61CD # 0 +0xBED0 0x61B6 # 0 +0xBED1 0x61BE # 0 +0xBED2 0x61CA # 0 +0xBED3 0x61C8 # 0 +0xBED4 0x6230 # 0 +0xBED5 0x64C5 # 0 +0xBED6 0x64C1 # 0 +0xBED7 0x64CB # 0 +0xBED8 0x64BB # 0 +0xBED9 0x64BC # 0 +0xBEDA 0x64DA # 0 +0xBEDB 0x64C4 # 0 +0xBEDC 0x64C7 # 0 +0xBEDD 0x64C2 # 0 +0xBEDE 0x64CD # 0 +0xBEDF 0x64BF # 0 +0xBEE0 0x64D2 # 0 +0xBEE1 0x64D4 # 0 +0xBEE2 0x64BE # 0 +0xBEE3 0x6574 # 0 +0xBEE4 0x66C6 # 0 +0xBEE5 0x66C9 # 0 +0xBEE6 0x66B9 # 0 +0xBEE7 0x66C4 # 0 +0xBEE8 0x66C7 # 0 +0xBEE9 0x66B8 # 0 +0xBEEA 0x6A3D # 0 +0xBEEB 0x6A38 # 0 +0xBEEC 0x6A3A # 0 +0xBEED 0x6A59 # 0 +0xBEEE 0x6A6B # 0 +0xBEEF 0x6A58 # 0 +0xBEF0 0x6A39 # 0 +0xBEF1 0x6A44 # 0 +0xBEF2 0x6A62 # 0 +0xBEF3 0x6A61 # 0 +0xBEF4 0x6A4B # 0 +0xBEF5 0x6A47 # 0 +0xBEF6 0x6A35 # 0 +0xBEF7 0x6A5F # 0 +0xBEF8 0x6A48 # 0 +0xBEF9 0x6B59 # 0 +0xBEFA 0x6B77 # 0 +0xBEFB 0x6C05 # 0 +0xBEFC 0x6FC2 # 0 +0xBEFD 0x6FB1 # 0 +0xBEFE 0x6FA1 # 0 +0xBF40 0x6FC3 # 0 +0xBF41 0x6FA4 # 0 +0xBF42 0x6FC1 # 0 +0xBF43 0x6FA7 # 0 +0xBF44 0x6FB3 # 0 +0xBF45 0x6FC0 # 0 +0xBF46 0x6FB9 # 0 +0xBF47 0x6FB6 # 0 +0xBF48 0x6FA6 # 0 +0xBF49 0x6FA0 # 0 +0xBF4A 0x6FB4 # 0 +0xBF4B 0x71BE # 0 +0xBF4C 0x71C9 # 0 +0xBF4D 0x71D0 # 0 +0xBF4E 0x71D2 # 0 +0xBF4F 0x71C8 # 0 +0xBF50 0x71D5 # 0 +0xBF51 0x71B9 # 0 +0xBF52 0x71CE # 0 +0xBF53 0x71D9 # 0 +0xBF54 0x71DC # 0 +0xBF55 0x71C3 # 0 +0xBF56 0x71C4 # 0 +0xBF57 0x7368 # 0 +0xBF58 0x749C # 0 +0xBF59 0x74A3 # 0 +0xBF5A 0x7498 # 0 +0xBF5B 0x749F # 0 +0xBF5C 0x749E # 0 +0xBF5D 0x74E2 # 0 +0xBF5E 0x750C # 0 +0xBF5F 0x750D # 0 +0xBF60 0x7634 # 0 +0xBF61 0x7638 # 0 +0xBF62 0x763A # 0 +0xBF63 0x76E7 # 0 +0xBF64 0x76E5 # 0 +0xBF65 0x77A0 # 0 +0xBF66 0x779E # 0 +0xBF67 0x779F # 0 +0xBF68 0x77A5 # 0 +0xBF69 0x78E8 # 0 +0xBF6A 0x78DA # 0 +0xBF6B 0x78EC # 0 +0xBF6C 0x78E7 # 0 +0xBF6D 0x79A6 # 0 +0xBF6E 0x7A4D # 0 +0xBF6F 0x7A4E # 0 +0xBF70 0x7A46 # 0 +0xBF71 0x7A4C # 0 +0xBF72 0x7A4B # 0 +0xBF73 0x7ABA # 0 +0xBF74 0x7BD9 # 0 +0xBF75 0x7C11 # 0 +0xBF76 0x7BC9 # 0 +0xBF77 0x7BE4 # 0 +0xBF78 0x7BDB # 0 +0xBF79 0x7BE1 # 0 +0xBF7A 0x7BE9 # 0 +0xBF7B 0x7BE6 # 0 +0xBF7C 0x7CD5 # 0 +0xBF7D 0x7CD6 # 0 +0xBF7E 0x7E0A # 0 +0xBFA1 0x7E11 # 0 +0xBFA2 0x7E08 # 0 +0xBFA3 0x7E1B # 0 +0xBFA4 0x7E23 # 0 +0xBFA5 0x7E1E # 0 +0xBFA6 0x7E1D # 0 +0xBFA7 0x7E09 # 0 +0xBFA8 0x7E10 # 0 +0xBFA9 0x7F79 # 0 +0xBFAA 0x7FB2 # 0 +0xBFAB 0x7FF0 # 0 +0xBFAC 0x7FF1 # 0 +0xBFAD 0x7FEE # 0 +0xBFAE 0x8028 # 0 +0xBFAF 0x81B3 # 0 +0xBFB0 0x81A9 # 0 +0xBFB1 0x81A8 # 0 +0xBFB2 0x81FB # 0 +0xBFB3 0x8208 # 0 +0xBFB4 0x8258 # 0 +0xBFB5 0x8259 # 0 +0xBFB6 0x854A # 0 +0xBFB7 0x8559 # 0 +0xBFB8 0x8548 # 0 +0xBFB9 0x8568 # 0 +0xBFBA 0x8569 # 0 +0xBFBB 0x8543 # 0 +0xBFBC 0x8549 # 0 +0xBFBD 0x856D # 0 +0xBFBE 0x856A # 0 +0xBFBF 0x855E # 0 +0xBFC0 0x8783 # 0 +0xBFC1 0x879F # 0 +0xBFC2 0x879E # 0 +0xBFC3 0x87A2 # 0 +0xBFC4 0x878D # 0 +0xBFC5 0x8861 # 0 +0xBFC6 0x892A # 0 +0xBFC7 0x8932 # 0 +0xBFC8 0x8925 # 0 +0xBFC9 0x892B # 0 +0xBFCA 0x8921 # 0 +0xBFCB 0x89AA # 0 +0xBFCC 0x89A6 # 0 +0xBFCD 0x8AE6 # 0 +0xBFCE 0x8AFA # 0 +0xBFCF 0x8AEB # 0 +0xBFD0 0x8AF1 # 0 +0xBFD1 0x8B00 # 0 +0xBFD2 0x8ADC # 0 +0xBFD3 0x8AE7 # 0 +0xBFD4 0x8AEE # 0 +0xBFD5 0x8AFE # 0 +0xBFD6 0x8B01 # 0 +0xBFD7 0x8B02 # 0 +0xBFD8 0x8AF7 # 0 +0xBFD9 0x8AED # 0 +0xBFDA 0x8AF3 # 0 +0xBFDB 0x8AF6 # 0 +0xBFDC 0x8AFC # 0 +0xBFDD 0x8C6B # 0 +0xBFDE 0x8C6D # 0 +0xBFDF 0x8C93 # 0 +0xBFE0 0x8CF4 # 0 +0xBFE1 0x8E44 # 0 +0xBFE2 0x8E31 # 0 +0xBFE3 0x8E34 # 0 +0xBFE4 0x8E42 # 0 +0xBFE5 0x8E39 # 0 +0xBFE6 0x8E35 # 0 +0xBFE7 0x8F3B # 0 +0xBFE8 0x8F2F # 0 +0xBFE9 0x8F38 # 0 +0xBFEA 0x8F33 # 0 +0xBFEB 0x8FA8 # 0 +0xBFEC 0x8FA6 # 0 +0xBFED 0x9075 # 0 +0xBFEE 0x9074 # 0 +0xBFEF 0x9078 # 0 +0xBFF0 0x9072 # 0 +0xBFF1 0x907C # 0 +0xBFF2 0x907A # 0 +0xBFF3 0x9134 # 0 +0xBFF4 0x9192 # 0 +0xBFF5 0x9320 # 0 +0xBFF6 0x9336 # 0 +0xBFF7 0x92F8 # 0 +0xBFF8 0x9333 # 0 +0xBFF9 0x932F # 0 +0xBFFA 0x9322 # 0 +0xBFFB 0x92FC # 0 +0xBFFC 0x932B # 0 +0xBFFD 0x9304 # 0 +0xBFFE 0x931A # 0 +0xC040 0x9310 # 0 +0xC041 0x9326 # 0 +0xC042 0x9321 # 0 +0xC043 0x9315 # 0 +0xC044 0x932E # 0 +0xC045 0x9319 # 0 +0xC046 0x95BB # 0 +0xC047 0x96A7 # 0 +0xC048 0x96A8 # 0 +0xC049 0x96AA # 0 +0xC04A 0x96D5 # 0 +0xC04B 0x970E # 0 +0xC04C 0x9711 # 0 +0xC04D 0x9716 # 0 +0xC04E 0x970D # 0 +0xC04F 0x9713 # 0 +0xC050 0x970F # 0 +0xC051 0x975B # 0 +0xC052 0x975C # 0 +0xC053 0x9766 # 0 +0xC054 0x9798 # 0 +0xC055 0x9830 # 0 +0xC056 0x9838 # 0 +0xC057 0x983B # 0 +0xC058 0x9837 # 0 +0xC059 0x982D # 0 +0xC05A 0x9839 # 0 +0xC05B 0x9824 # 0 +0xC05C 0x9910 # 0 +0xC05D 0x9928 # 0 +0xC05E 0x991E # 0 +0xC05F 0x991B # 0 +0xC060 0x9921 # 0 +0xC061 0x991A # 0 +0xC062 0x99ED # 0 +0xC063 0x99E2 # 0 +0xC064 0x99F1 # 0 +0xC065 0x9AB8 # 0 +0xC066 0x9ABC # 0 +0xC067 0x9AFB # 0 +0xC068 0x9AED # 0 +0xC069 0x9B28 # 0 +0xC06A 0x9B91 # 0 +0xC06B 0x9D15 # 0 +0xC06C 0x9D23 # 0 +0xC06D 0x9D26 # 0 +0xC06E 0x9D28 # 0 +0xC06F 0x9D12 # 0 +0xC070 0x9D1B # 0 +0xC071 0x9ED8 # 0 +0xC072 0x9ED4 # 0 +0xC073 0x9F8D # 0 +0xC074 0x9F9C # 0 +0xC075 0x512A # 0 +0xC076 0x511F # 0 +0xC077 0x5121 # 0 +0xC078 0x5132 # 0 +0xC079 0x52F5 # 0 +0xC07A 0x568E # 0 +0xC07B 0x5680 # 0 +0xC07C 0x5690 # 0 +0xC07D 0x5685 # 0 +0xC07E 0x5687 # 0 +0xC0A1 0x568F # 0 +0xC0A2 0x58D5 # 0 +0xC0A3 0x58D3 # 0 +0xC0A4 0x58D1 # 0 +0xC0A5 0x58CE # 0 +0xC0A6 0x5B30 # 0 +0xC0A7 0x5B2A # 0 +0xC0A8 0x5B24 # 0 +0xC0A9 0x5B7A # 0 +0xC0AA 0x5C37 # 0 +0xC0AB 0x5C68 # 0 +0xC0AC 0x5DBC # 0 +0xC0AD 0x5DBA # 0 +0xC0AE 0x5DBD # 0 +0xC0AF 0x5DB8 # 0 +0xC0B0 0x5E6B # 0 +0xC0B1 0x5F4C # 0 +0xC0B2 0x5FBD # 0 +0xC0B3 0x61C9 # 0 +0xC0B4 0x61C2 # 0 +0xC0B5 0x61C7 # 0 +0xC0B6 0x61E6 # 0 +0xC0B7 0x61CB # 0 +0xC0B8 0x6232 # 0 +0xC0B9 0x6234 # 0 +0xC0BA 0x64CE # 0 +0xC0BB 0x64CA # 0 +0xC0BC 0x64D8 # 0 +0xC0BD 0x64E0 # 0 +0xC0BE 0x64F0 # 0 +0xC0BF 0x64E6 # 0 +0xC0C0 0x64EC # 0 +0xC0C1 0x64F1 # 0 +0xC0C2 0x64E2 # 0 +0xC0C3 0x64ED # 0 +0xC0C4 0x6582 # 0 +0xC0C5 0x6583 # 0 +0xC0C6 0x66D9 # 0 +0xC0C7 0x66D6 # 0 +0xC0C8 0x6A80 # 0 +0xC0C9 0x6A94 # 0 +0xC0CA 0x6A84 # 0 +0xC0CB 0x6AA2 # 0 +0xC0CC 0x6A9C # 0 +0xC0CD 0x6ADB # 0 +0xC0CE 0x6AA3 # 0 +0xC0CF 0x6A7E # 0 +0xC0D0 0x6A97 # 0 +0xC0D1 0x6A90 # 0 +0xC0D2 0x6AA0 # 0 +0xC0D3 0x6B5C # 0 +0xC0D4 0x6BAE # 0 +0xC0D5 0x6BDA # 0 +0xC0D6 0x6C08 # 0 +0xC0D7 0x6FD8 # 0 +0xC0D8 0x6FF1 # 0 +0xC0D9 0x6FDF # 0 +0xC0DA 0x6FE0 # 0 +0xC0DB 0x6FDB # 0 +0xC0DC 0x6FE4 # 0 +0xC0DD 0x6FEB # 0 +0xC0DE 0x6FEF # 0 +0xC0DF 0x6F80 # 0 +0xC0E0 0x6FEC # 0 +0xC0E1 0x6FE1 # 0 +0xC0E2 0x6FE9 # 0 +0xC0E3 0x6FD5 # 0 +0xC0E4 0x6FEE # 0 +0xC0E5 0x6FF0 # 0 +0xC0E6 0x71E7 # 0 +0xC0E7 0x71DF # 0 +0xC0E8 0x71EE # 0 +0xC0E9 0x71E6 # 0 +0xC0EA 0x71E5 # 0 +0xC0EB 0x71ED # 0 +0xC0EC 0x71EC # 0 +0xC0ED 0x71F4 # 0 +0xC0EE 0x71E0 # 0 +0xC0EF 0x7235 # 0 +0xC0F0 0x7246 # 0 +0xC0F1 0x7370 # 0 +0xC0F2 0x7372 # 0 +0xC0F3 0x74A9 # 0 +0xC0F4 0x74B0 # 0 +0xC0F5 0x74A6 # 0 +0xC0F6 0x74A8 # 0 +0xC0F7 0x7646 # 0 +0xC0F8 0x7642 # 0 +0xC0F9 0x764C # 0 +0xC0FA 0x76EA # 0 +0xC0FB 0x77B3 # 0 +0xC0FC 0x77AA # 0 +0xC0FD 0x77B0 # 0 +0xC0FE 0x77AC # 0 +0xC140 0x77A7 # 0 +0xC141 0x77AD # 0 +0xC142 0x77EF # 0 +0xC143 0x78F7 # 0 +0xC144 0x78FA # 0 +0xC145 0x78F4 # 0 +0xC146 0x78EF # 0 +0xC147 0x7901 # 0 +0xC148 0x79A7 # 0 +0xC149 0x79AA # 0 +0xC14A 0x7A57 # 0 +0xC14B 0x7ABF # 0 +0xC14C 0x7C07 # 0 +0xC14D 0x7C0D # 0 +0xC14E 0x7BFE # 0 +0xC14F 0x7BF7 # 0 +0xC150 0x7C0C # 0 +0xC151 0x7BE0 # 0 +0xC152 0x7CE0 # 0 +0xC153 0x7CDC # 0 +0xC154 0x7CDE # 0 +0xC155 0x7CE2 # 0 +0xC156 0x7CDF # 0 +0xC157 0x7CD9 # 0 +0xC158 0x7CDD # 0 +0xC159 0x7E2E # 0 +0xC15A 0x7E3E # 0 +0xC15B 0x7E46 # 0 +0xC15C 0x7E37 # 0 +0xC15D 0x7E32 # 0 +0xC15E 0x7E43 # 0 +0xC15F 0x7E2B # 0 +0xC160 0x7E3D # 0 +0xC161 0x7E31 # 0 +0xC162 0x7E45 # 0 +0xC163 0x7E41 # 0 +0xC164 0x7E34 # 0 +0xC165 0x7E39 # 0 +0xC166 0x7E48 # 0 +0xC167 0x7E35 # 0 +0xC168 0x7E3F # 0 +0xC169 0x7E2F # 0 +0xC16A 0x7F44 # 0 +0xC16B 0x7FF3 # 0 +0xC16C 0x7FFC # 0 +0xC16D 0x8071 # 0 +0xC16E 0x8072 # 0 +0xC16F 0x8070 # 0 +0xC170 0x806F # 0 +0xC171 0x8073 # 0 +0xC172 0x81C6 # 0 +0xC173 0x81C3 # 0 +0xC174 0x81BA # 0 +0xC175 0x81C2 # 0 +0xC176 0x81C0 # 0 +0xC177 0x81BF # 0 +0xC178 0x81BD # 0 +0xC179 0x81C9 # 0 +0xC17A 0x81BE # 0 +0xC17B 0x81E8 # 0 +0xC17C 0x8209 # 0 +0xC17D 0x8271 # 0 +0xC17E 0x85AA # 0 +0xC1A1 0x8584 # 0 +0xC1A2 0x857E # 0 +0xC1A3 0x859C # 0 +0xC1A4 0x8591 # 0 +0xC1A5 0x8594 # 0 +0xC1A6 0x85AF # 0 +0xC1A7 0x859B # 0 +0xC1A8 0x8587 # 0 +0xC1A9 0x85A8 # 0 +0xC1AA 0x858A # 0 +0xC1AB 0x8667 # 0 +0xC1AC 0x87C0 # 0 +0xC1AD 0x87D1 # 0 +0xC1AE 0x87B3 # 0 +0xC1AF 0x87D2 # 0 +0xC1B0 0x87C6 # 0 +0xC1B1 0x87AB # 0 +0xC1B2 0x87BB # 0 +0xC1B3 0x87BA # 0 +0xC1B4 0x87C8 # 0 +0xC1B5 0x87CB # 0 +0xC1B6 0x893B # 0 +0xC1B7 0x8936 # 0 +0xC1B8 0x8944 # 0 +0xC1B9 0x8938 # 0 +0xC1BA 0x893D # 0 +0xC1BB 0x89AC # 0 +0xC1BC 0x8B0E # 0 +0xC1BD 0x8B17 # 0 +0xC1BE 0x8B19 # 0 +0xC1BF 0x8B1B # 0 +0xC1C0 0x8B0A # 0 +0xC1C1 0x8B20 # 0 +0xC1C2 0x8B1D # 0 +0xC1C3 0x8B04 # 0 +0xC1C4 0x8B10 # 0 +0xC1C5 0x8C41 # 0 +0xC1C6 0x8C3F # 0 +0xC1C7 0x8C73 # 0 +0xC1C8 0x8CFA # 0 +0xC1C9 0x8CFD # 0 +0xC1CA 0x8CFC # 0 +0xC1CB 0x8CF8 # 0 +0xC1CC 0x8CFB # 0 +0xC1CD 0x8DA8 # 0 +0xC1CE 0x8E49 # 0 +0xC1CF 0x8E4B # 0 +0xC1D0 0x8E48 # 0 +0xC1D1 0x8E4A # 0 +0xC1D2 0x8F44 # 0 +0xC1D3 0x8F3E # 0 +0xC1D4 0x8F42 # 0 +0xC1D5 0x8F45 # 0 +0xC1D6 0x8F3F # 0 +0xC1D7 0x907F # 0 +0xC1D8 0x907D # 0 +0xC1D9 0x9084 # 0 +0xC1DA 0x9081 # 0 +0xC1DB 0x9082 # 0 +0xC1DC 0x9080 # 0 +0xC1DD 0x9139 # 0 +0xC1DE 0x91A3 # 0 +0xC1DF 0x919E # 0 +0xC1E0 0x919C # 0 +0xC1E1 0x934D # 0 +0xC1E2 0x9382 # 0 +0xC1E3 0x9328 # 0 +0xC1E4 0x9375 # 0 +0xC1E5 0x934A # 0 +0xC1E6 0x9365 # 0 +0xC1E7 0x934B # 0 +0xC1E8 0x9318 # 0 +0xC1E9 0x937E # 0 +0xC1EA 0x936C # 0 +0xC1EB 0x935B # 0 +0xC1EC 0x9370 # 0 +0xC1ED 0x935A # 0 +0xC1EE 0x9354 # 0 +0xC1EF 0x95CA # 0 +0xC1F0 0x95CB # 0 +0xC1F1 0x95CC # 0 +0xC1F2 0x95C8 # 0 +0xC1F3 0x95C6 # 0 +0xC1F4 0x96B1 # 0 +0xC1F5 0x96B8 # 0 +0xC1F6 0x96D6 # 0 +0xC1F7 0x971C # 0 +0xC1F8 0x971E # 0 +0xC1F9 0x97A0 # 0 +0xC1FA 0x97D3 # 0 +0xC1FB 0x9846 # 0 +0xC1FC 0x98B6 # 0 +0xC1FD 0x9935 # 0 +0xC1FE 0x9A01 # 0 +0xC240 0x99FF # 0 +0xC241 0x9BAE # 0 +0xC242 0x9BAB # 0 +0xC243 0x9BAA # 0 +0xC244 0x9BAD # 0 +0xC245 0x9D3B # 0 +0xC246 0x9D3F # 0 +0xC247 0x9E8B # 0 +0xC248 0x9ECF # 0 +0xC249 0x9EDE # 0 +0xC24A 0x9EDC # 0 +0xC24B 0x9EDD # 0 +0xC24C 0x9EDB # 0 +0xC24D 0x9F3E # 0 +0xC24E 0x9F4B # 0 +0xC24F 0x53E2 # 0 +0xC250 0x5695 # 0 +0xC251 0x56AE # 0 +0xC252 0x58D9 # 0 +0xC253 0x58D8 # 0 +0xC254 0x5B38 # 0 +0xC255 0x5F5D # 0 +0xC256 0x61E3 # 0 +0xC257 0x6233 # 0 +0xC258 0x64F4 # 0 +0xC259 0x64F2 # 0 +0xC25A 0x64FE # 0 +0xC25B 0x6506 # 0 +0xC25C 0x64FA # 0 +0xC25D 0x64FB # 0 +0xC25E 0x64F7 # 0 +0xC25F 0x65B7 # 0 +0xC260 0x66DC # 0 +0xC261 0x6726 # 0 +0xC262 0x6AB3 # 0 +0xC263 0x6AAC # 0 +0xC264 0x6AC3 # 0 +0xC265 0x6ABB # 0 +0xC266 0x6AB8 # 0 +0xC267 0x6AC2 # 0 +0xC268 0x6AAE # 0 +0xC269 0x6AAF # 0 +0xC26A 0x6B5F # 0 +0xC26B 0x6B78 # 0 +0xC26C 0x6BAF # 0 +0xC26D 0x7009 # 0 +0xC26E 0x700B # 0 +0xC26F 0x6FFE # 0 +0xC270 0x7006 # 0 +0xC271 0x6FFA # 0 +0xC272 0x7011 # 0 +0xC273 0x700F # 0 +0xC274 0x71FB # 0 +0xC275 0x71FC # 0 +0xC276 0x71FE # 0 +0xC277 0x71F8 # 0 +0xC278 0x7377 # 0 +0xC279 0x7375 # 0 +0xC27A 0x74A7 # 0 +0xC27B 0x74BF # 0 +0xC27C 0x7515 # 0 +0xC27D 0x7656 # 0 +0xC27E 0x7658 # 0 +0xC2A1 0x7652 # 0 +0xC2A2 0x77BD # 0 +0xC2A3 0x77BF # 0 +0xC2A4 0x77BB # 0 +0xC2A5 0x77BC # 0 +0xC2A6 0x790E # 0 +0xC2A7 0x79AE # 0 +0xC2A8 0x7A61 # 0 +0xC2A9 0x7A62 # 0 +0xC2AA 0x7A60 # 0 +0xC2AB 0x7AC4 # 0 +0xC2AC 0x7AC5 # 0 +0xC2AD 0x7C2B # 0 +0xC2AE 0x7C27 # 0 +0xC2AF 0x7C2A # 0 +0xC2B0 0x7C1E # 0 +0xC2B1 0x7C23 # 0 +0xC2B2 0x7C21 # 0 +0xC2B3 0x7CE7 # 0 +0xC2B4 0x7E54 # 0 +0xC2B5 0x7E55 # 0 +0xC2B6 0x7E5E # 0 +0xC2B7 0x7E5A # 0 +0xC2B8 0x7E61 # 0 +0xC2B9 0x7E52 # 0 +0xC2BA 0x7E59 # 0 +0xC2BB 0x7F48 # 0 +0xC2BC 0x7FF9 # 0 +0xC2BD 0x7FFB # 0 +0xC2BE 0x8077 # 0 +0xC2BF 0x8076 # 0 +0xC2C0 0x81CD # 0 +0xC2C1 0x81CF # 0 +0xC2C2 0x820A # 0 +0xC2C3 0x85CF # 0 +0xC2C4 0x85A9 # 0 +0xC2C5 0x85CD # 0 +0xC2C6 0x85D0 # 0 +0xC2C7 0x85C9 # 0 +0xC2C8 0x85B0 # 0 +0xC2C9 0x85BA # 0 +0xC2CA 0x85B9 # 0 +0xC2CB 0x85A6 # 0 +0xC2CC 0x87EF # 0 +0xC2CD 0x87EC # 0 +0xC2CE 0x87F2 # 0 +0xC2CF 0x87E0 # 0 +0xC2D0 0x8986 # 0 +0xC2D1 0x89B2 # 0 +0xC2D2 0x89F4 # 0 +0xC2D3 0x8B28 # 0 +0xC2D4 0x8B39 # 0 +0xC2D5 0x8B2C # 0 +0xC2D6 0x8B2B # 0 +0xC2D7 0x8C50 # 0 +0xC2D8 0x8D05 # 0 +0xC2D9 0x8E59 # 0 +0xC2DA 0x8E63 # 0 +0xC2DB 0x8E66 # 0 +0xC2DC 0x8E64 # 0 +0xC2DD 0x8E5F # 0 +0xC2DE 0x8E55 # 0 +0xC2DF 0x8EC0 # 0 +0xC2E0 0x8F49 # 0 +0xC2E1 0x8F4D # 0 +0xC2E2 0x9087 # 0 +0xC2E3 0x9083 # 0 +0xC2E4 0x9088 # 0 +0xC2E5 0x91AB # 0 +0xC2E6 0x91AC # 0 +0xC2E7 0x91D0 # 0 +0xC2E8 0x9394 # 0 +0xC2E9 0x938A # 0 +0xC2EA 0x9396 # 0 +0xC2EB 0x93A2 # 0 +0xC2EC 0x93B3 # 0 +0xC2ED 0x93AE # 0 +0xC2EE 0x93AC # 0 +0xC2EF 0x93B0 # 0 +0xC2F0 0x9398 # 0 +0xC2F1 0x939A # 0 +0xC2F2 0x9397 # 0 +0xC2F3 0x95D4 # 0 +0xC2F4 0x95D6 # 0 +0xC2F5 0x95D0 # 0 +0xC2F6 0x95D5 # 0 +0xC2F7 0x96E2 # 0 +0xC2F8 0x96DC # 0 +0xC2F9 0x96D9 # 0 +0xC2FA 0x96DB # 0 +0xC2FB 0x96DE # 0 +0xC2FC 0x9724 # 0 +0xC2FD 0x97A3 # 0 +0xC2FE 0x97A6 # 0 +0xC340 0x97AD # 0 +0xC341 0x97F9 # 0 +0xC342 0x984D # 0 +0xC343 0x984F # 0 +0xC344 0x984C # 0 +0xC345 0x984E # 0 +0xC346 0x9853 # 0 +0xC347 0x98BA # 0 +0xC348 0x993E # 0 +0xC349 0x993F # 0 +0xC34A 0x993D # 0 +0xC34B 0x992E # 0 +0xC34C 0x99A5 # 0 +0xC34D 0x9A0E # 0 +0xC34E 0x9AC1 # 0 +0xC34F 0x9B03 # 0 +0xC350 0x9B06 # 0 +0xC351 0x9B4F # 0 +0xC352 0x9B4E # 0 +0xC353 0x9B4D # 0 +0xC354 0x9BCA # 0 +0xC355 0x9BC9 # 0 +0xC356 0x9BFD # 0 +0xC357 0x9BC8 # 0 +0xC358 0x9BC0 # 0 +0xC359 0x9D51 # 0 +0xC35A 0x9D5D # 0 +0xC35B 0x9D60 # 0 +0xC35C 0x9EE0 # 0 +0xC35D 0x9F15 # 0 +0xC35E 0x9F2C # 0 +0xC35F 0x5133 # 0 +0xC360 0x56A5 # 0 +0xC361 0x58DE # 0 +0xC362 0x58DF # 0 +0xC363 0x58E2 # 0 +0xC364 0x5BF5 # 0 +0xC365 0x9F90 # 0 +0xC366 0x5EEC # 0 +0xC367 0x61F2 # 0 +0xC368 0x61F7 # 0 +0xC369 0x61F6 # 0 +0xC36A 0x61F5 # 0 +0xC36B 0x6500 # 0 +0xC36C 0x650F # 0 +0xC36D 0x66E0 # 0 +0xC36E 0x66DD # 0 +0xC36F 0x6AE5 # 0 +0xC370 0x6ADD # 0 +0xC371 0x6ADA # 0 +0xC372 0x6AD3 # 0 +0xC373 0x701B # 0 +0xC374 0x701F # 0 +0xC375 0x7028 # 0 +0xC376 0x701A # 0 +0xC377 0x701D # 0 +0xC378 0x7015 # 0 +0xC379 0x7018 # 0 +0xC37A 0x7206 # 0 +0xC37B 0x720D # 0 +0xC37C 0x7258 # 0 +0xC37D 0x72A2 # 0 +0xC37E 0x7378 # 0 +0xC3A1 0x737A # 0 +0xC3A2 0x74BD # 0 +0xC3A3 0x74CA # 0 +0xC3A4 0x74E3 # 0 +0xC3A5 0x7587 # 0 +0xC3A6 0x7586 # 0 +0xC3A7 0x765F # 0 +0xC3A8 0x7661 # 0 +0xC3A9 0x77C7 # 0 +0xC3AA 0x7919 # 0 +0xC3AB 0x79B1 # 0 +0xC3AC 0x7A6B # 0 +0xC3AD 0x7A69 # 0 +0xC3AE 0x7C3E # 0 +0xC3AF 0x7C3F # 0 +0xC3B0 0x7C38 # 0 +0xC3B1 0x7C3D # 0 +0xC3B2 0x7C37 # 0 +0xC3B3 0x7C40 # 0 +0xC3B4 0x7E6B # 0 +0xC3B5 0x7E6D # 0 +0xC3B6 0x7E79 # 0 +0xC3B7 0x7E69 # 0 +0xC3B8 0x7E6A # 0 +0xC3B9 0x7F85 # 0 +0xC3BA 0x7E73 # 0 +0xC3BB 0x7FB6 # 0 +0xC3BC 0x7FB9 # 0 +0xC3BD 0x7FB8 # 0 +0xC3BE 0x81D8 # 0 +0xC3BF 0x85E9 # 0 +0xC3C0 0x85DD # 0 +0xC3C1 0x85EA # 0 +0xC3C2 0x85D5 # 0 +0xC3C3 0x85E4 # 0 +0xC3C4 0x85E5 # 0 +0xC3C5 0x85F7 # 0 +0xC3C6 0x87FB # 0 +0xC3C7 0x8805 # 0 +0xC3C8 0x880D # 0 +0xC3C9 0x87F9 # 0 +0xC3CA 0x87FE # 0 +0xC3CB 0x8960 # 0 +0xC3CC 0x895F # 0 +0xC3CD 0x8956 # 0 +0xC3CE 0x895E # 0 +0xC3CF 0x8B41 # 0 +0xC3D0 0x8B5C # 0 +0xC3D1 0x8B58 # 0 +0xC3D2 0x8B49 # 0 +0xC3D3 0x8B5A # 0 +0xC3D4 0x8B4E # 0 +0xC3D5 0x8B4F # 0 +0xC3D6 0x8B46 # 0 +0xC3D7 0x8B59 # 0 +0xC3D8 0x8D08 # 0 +0xC3D9 0x8D0A # 0 +0xC3DA 0x8E7C # 0 +0xC3DB 0x8E72 # 0 +0xC3DC 0x8E87 # 0 +0xC3DD 0x8E76 # 0 +0xC3DE 0x8E6C # 0 +0xC3DF 0x8E7A # 0 +0xC3E0 0x8E74 # 0 +0xC3E1 0x8F54 # 0 +0xC3E2 0x8F4E # 0 +0xC3E3 0x8FAD # 0 +0xC3E4 0x908A # 0 +0xC3E5 0x908B # 0 +0xC3E6 0x91B1 # 0 +0xC3E7 0x91AE # 0 +0xC3E8 0x93E1 # 0 +0xC3E9 0x93D1 # 0 +0xC3EA 0x93DF # 0 +0xC3EB 0x93C3 # 0 +0xC3EC 0x93C8 # 0 +0xC3ED 0x93DC # 0 +0xC3EE 0x93DD # 0 +0xC3EF 0x93D6 # 0 +0xC3F0 0x93E2 # 0 +0xC3F1 0x93CD # 0 +0xC3F2 0x93D8 # 0 +0xC3F3 0x93E4 # 0 +0xC3F4 0x93D7 # 0 +0xC3F5 0x93E8 # 0 +0xC3F6 0x95DC # 0 +0xC3F7 0x96B4 # 0 +0xC3F8 0x96E3 # 0 +0xC3F9 0x972A # 0 +0xC3FA 0x9727 # 0 +0xC3FB 0x9761 # 0 +0xC3FC 0x97DC # 0 +0xC3FD 0x97FB # 0 +0xC3FE 0x985E # 0 +0xC440 0x9858 # 0 +0xC441 0x985B # 0 +0xC442 0x98BC # 0 +0xC443 0x9945 # 0 +0xC444 0x9949 # 0 +0xC445 0x9A16 # 0 +0xC446 0x9A19 # 0 +0xC447 0x9B0D # 0 +0xC448 0x9BE8 # 0 +0xC449 0x9BE7 # 0 +0xC44A 0x9BD6 # 0 +0xC44B 0x9BDB # 0 +0xC44C 0x9D89 # 0 +0xC44D 0x9D61 # 0 +0xC44E 0x9D72 # 0 +0xC44F 0x9D6A # 0 +0xC450 0x9D6C # 0 +0xC451 0x9E92 # 0 +0xC452 0x9E97 # 0 +0xC453 0x9E93 # 0 +0xC454 0x9EB4 # 0 +0xC455 0x52F8 # 0 +0xC456 0x56A8 # 0 +0xC457 0x56B7 # 0 +0xC458 0x56B6 # 0 +0xC459 0x56B4 # 0 +0xC45A 0x56BC # 0 +0xC45B 0x58E4 # 0 +0xC45C 0x5B40 # 0 +0xC45D 0x5B43 # 0 +0xC45E 0x5B7D # 0 +0xC45F 0x5BF6 # 0 +0xC460 0x5DC9 # 0 +0xC461 0x61F8 # 0 +0xC462 0x61FA # 0 +0xC463 0x6518 # 0 +0xC464 0x6514 # 0 +0xC465 0x6519 # 0 +0xC466 0x66E6 # 0 +0xC467 0x6727 # 0 +0xC468 0x6AEC # 0 +0xC469 0x703E # 0 +0xC46A 0x7030 # 0 +0xC46B 0x7032 # 0 +0xC46C 0x7210 # 0 +0xC46D 0x737B # 0 +0xC46E 0x74CF # 0 +0xC46F 0x7662 # 0 +0xC470 0x7665 # 0 +0xC471 0x7926 # 0 +0xC472 0x792A # 0 +0xC473 0x792C # 0 +0xC474 0x792B # 0 +0xC475 0x7AC7 # 0 +0xC476 0x7AF6 # 0 +0xC477 0x7C4C # 0 +0xC478 0x7C43 # 0 +0xC479 0x7C4D # 0 +0xC47A 0x7CEF # 0 +0xC47B 0x7CF0 # 0 +0xC47C 0x8FAE # 0 +0xC47D 0x7E7D # 0 +0xC47E 0x7E7C # 0 +0xC4A1 0x7E82 # 0 +0xC4A2 0x7F4C # 0 +0xC4A3 0x8000 # 0 +0xC4A4 0x81DA # 0 +0xC4A5 0x8266 # 0 +0xC4A6 0x85FB # 0 +0xC4A7 0x85F9 # 0 +0xC4A8 0x8611 # 0 +0xC4A9 0x85FA # 0 +0xC4AA 0x8606 # 0 +0xC4AB 0x860B # 0 +0xC4AC 0x8607 # 0 +0xC4AD 0x860A # 0 +0xC4AE 0x8814 # 0 +0xC4AF 0x8815 # 0 +0xC4B0 0x8964 # 0 +0xC4B1 0x89BA # 0 +0xC4B2 0x89F8 # 0 +0xC4B3 0x8B70 # 0 +0xC4B4 0x8B6C # 0 +0xC4B5 0x8B66 # 0 +0xC4B6 0x8B6F # 0 +0xC4B7 0x8B5F # 0 +0xC4B8 0x8B6B # 0 +0xC4B9 0x8D0F # 0 +0xC4BA 0x8D0D # 0 +0xC4BB 0x8E89 # 0 +0xC4BC 0x8E81 # 0 +0xC4BD 0x8E85 # 0 +0xC4BE 0x8E82 # 0 +0xC4BF 0x91B4 # 0 +0xC4C0 0x91CB # 0 +0xC4C1 0x9418 # 0 +0xC4C2 0x9403 # 0 +0xC4C3 0x93FD # 0 +0xC4C4 0x95E1 # 0 +0xC4C5 0x9730 # 0 +0xC4C6 0x98C4 # 0 +0xC4C7 0x9952 # 0 +0xC4C8 0x9951 # 0 +0xC4C9 0x99A8 # 0 +0xC4CA 0x9A2B # 0 +0xC4CB 0x9A30 # 0 +0xC4CC 0x9A37 # 0 +0xC4CD 0x9A35 # 0 +0xC4CE 0x9C13 # 0 +0xC4CF 0x9C0D # 0 +0xC4D0 0x9E79 # 0 +0xC4D1 0x9EB5 # 0 +0xC4D2 0x9EE8 # 0 +0xC4D3 0x9F2F # 0 +0xC4D4 0x9F5F # 0 +0xC4D5 0x9F63 # 0 +0xC4D6 0x9F61 # 0 +0xC4D7 0x5137 # 0 +0xC4D8 0x5138 # 0 +0xC4D9 0x56C1 # 0 +0xC4DA 0x56C0 # 0 +0xC4DB 0x56C2 # 0 +0xC4DC 0x5914 # 0 +0xC4DD 0x5C6C # 0 +0xC4DE 0x5DCD # 0 +0xC4DF 0x61FC # 0 +0xC4E0 0x61FE # 0 +0xC4E1 0x651D # 0 +0xC4E2 0x651C # 0 +0xC4E3 0x6595 # 0 +0xC4E4 0x66E9 # 0 +0xC4E5 0x6AFB # 0 +0xC4E6 0x6B04 # 0 +0xC4E7 0x6AFA # 0 +0xC4E8 0x6BB2 # 0 +0xC4E9 0x704C # 0 +0xC4EA 0x721B # 0 +0xC4EB 0x72A7 # 0 +0xC4EC 0x74D6 # 0 +0xC4ED 0x74D4 # 0 +0xC4EE 0x7669 # 0 +0xC4EF 0x77D3 # 0 +0xC4F0 0x7C50 # 0 +0xC4F1 0x7E8F # 0 +0xC4F2 0x7E8C # 0 +0xC4F3 0x7FBC # 0 +0xC4F4 0x8617 # 0 +0xC4F5 0x862D # 0 +0xC4F6 0x861A # 0 +0xC4F7 0x8823 # 0 +0xC4F8 0x8822 # 0 +0xC4F9 0x8821 # 0 +0xC4FA 0x881F # 0 +0xC4FB 0x896A # 0 +0xC4FC 0x896C # 0 +0xC4FD 0x89BD # 0 +0xC4FE 0x8B74 # 0 +0xC540 0x8B77 # 0 +0xC541 0x8B7D # 0 +0xC542 0x8D13 # 0 +0xC543 0x8E8A # 0 +0xC544 0x8E8D # 0 +0xC545 0x8E8B # 0 +0xC546 0x8F5F # 0 +0xC547 0x8FAF # 0 +0xC548 0x91BA # 0 +0xC549 0x942E # 0 +0xC54A 0x9433 # 0 +0xC54B 0x9435 # 0 +0xC54C 0x943A # 0 +0xC54D 0x9438 # 0 +0xC54E 0x9432 # 0 +0xC54F 0x942B # 0 +0xC550 0x95E2 # 0 +0xC551 0x9738 # 0 +0xC552 0x9739 # 0 +0xC553 0x9732 # 0 +0xC554 0x97FF # 0 +0xC555 0x9867 # 0 +0xC556 0x9865 # 0 +0xC557 0x9957 # 0 +0xC558 0x9A45 # 0 +0xC559 0x9A43 # 0 +0xC55A 0x9A40 # 0 +0xC55B 0x9A3E # 0 +0xC55C 0x9ACF # 0 +0xC55D 0x9B54 # 0 +0xC55E 0x9B51 # 0 +0xC55F 0x9C2D # 0 +0xC560 0x9C25 # 0 +0xC561 0x9DAF # 0 +0xC562 0x9DB4 # 0 +0xC563 0x9DC2 # 0 +0xC564 0x9DB8 # 0 +0xC565 0x9E9D # 0 +0xC566 0x9EEF # 0 +0xC567 0x9F19 # 0 +0xC568 0x9F5C # 0 +0xC569 0x9F66 # 0 +0xC56A 0x9F67 # 0 +0xC56B 0x513C # 0 +0xC56C 0x513B # 0 +0xC56D 0x56C8 # 0 +0xC56E 0x56CA # 0 +0xC56F 0x56C9 # 0 +0xC570 0x5B7F # 0 +0xC571 0x5DD4 # 0 +0xC572 0x5DD2 # 0 +0xC573 0x5F4E # 0 +0xC574 0x61FF # 0 +0xC575 0x6524 # 0 +0xC576 0x6B0A # 0 +0xC577 0x6B61 # 0 +0xC578 0x7051 # 0 +0xC579 0x7058 # 0 +0xC57A 0x7380 # 0 +0xC57B 0x74E4 # 0 +0xC57C 0x758A # 0 +0xC57D 0x766E # 0 +0xC57E 0x766C # 0 +0xC5A1 0x79B3 # 0 +0xC5A2 0x7C60 # 0 +0xC5A3 0x7C5F # 0 +0xC5A4 0x807E # 0 +0xC5A5 0x807D # 0 +0xC5A6 0x81DF # 0 +0xC5A7 0x8972 # 0 +0xC5A8 0x896F # 0 +0xC5A9 0x89FC # 0 +0xC5AA 0x8B80 # 0 +0xC5AB 0x8D16 # 0 +0xC5AC 0x8D17 # 0 +0xC5AD 0x8E91 # 0 +0xC5AE 0x8E93 # 0 +0xC5AF 0x8F61 # 0 +0xC5B0 0x9148 # 0 +0xC5B1 0x9444 # 0 +0xC5B2 0x9451 # 0 +0xC5B3 0x9452 # 0 +0xC5B4 0x973D # 0 +0xC5B5 0x973E # 0 +0xC5B6 0x97C3 # 0 +0xC5B7 0x97C1 # 0 +0xC5B8 0x986B # 0 +0xC5B9 0x9955 # 0 +0xC5BA 0x9A55 # 0 +0xC5BB 0x9A4D # 0 +0xC5BC 0x9AD2 # 0 +0xC5BD 0x9B1A # 0 +0xC5BE 0x9C49 # 0 +0xC5BF 0x9C31 # 0 +0xC5C0 0x9C3E # 0 +0xC5C1 0x9C3B # 0 +0xC5C2 0x9DD3 # 0 +0xC5C3 0x9DD7 # 0 +0xC5C4 0x9F34 # 0 +0xC5C5 0x9F6C # 0 +0xC5C6 0x9F6A # 0 +0xC5C7 0x9F94 # 0 +0xC5C8 0x56CC # 0 +0xC5C9 0x5DD6 # 0 +0xC5CA 0x6200 # 0 +0xC5CB 0x6523 # 0 +0xC5CC 0x652B # 0 +0xC5CD 0x652A # 0 +0xC5CE 0x66EC # 0 +0xC5CF 0x6B10 # 0 +0xC5D0 0x74DA # 0 +0xC5D1 0x7ACA # 0 +0xC5D2 0x7C64 # 0 +0xC5D3 0x7C63 # 0 +0xC5D4 0x7C65 # 0 +0xC5D5 0x7E93 # 0 +0xC5D6 0x7E96 # 0 +0xC5D7 0x7E94 # 0 +0xC5D8 0x81E2 # 0 +0xC5D9 0x8638 # 0 +0xC5DA 0x863F # 0 +0xC5DB 0x8831 # 0 +0xC5DC 0x8B8A # 0 +0xC5DD 0x9090 # 0 +0xC5DE 0x908F # 0 +0xC5DF 0x9463 # 0 +0xC5E0 0x9460 # 0 +0xC5E1 0x9464 # 0 +0xC5E2 0x9768 # 0 +0xC5E3 0x986F # 0 +0xC5E4 0x995C # 0 +0xC5E5 0x9A5A # 0 +0xC5E6 0x9A5B # 0 +0xC5E7 0x9A57 # 0 +0xC5E8 0x9AD3 # 0 +0xC5E9 0x9AD4 # 0 +0xC5EA 0x9AD1 # 0 +0xC5EB 0x9C54 # 0 +0xC5EC 0x9C57 # 0 +0xC5ED 0x9C56 # 0 +0xC5EE 0x9DE5 # 0 +0xC5EF 0x9E9F # 0 +0xC5F0 0x9EF4 # 0 +0xC5F1 0x56D1 # 0 +0xC5F2 0x58E9 # 0 +0xC5F3 0x652C # 0 +0xC5F4 0x705E # 0 +0xC5F5 0x7671 # 0 +0xC5F6 0x7672 # 0 +0xC5F7 0x77D7 # 0 +0xC5F8 0x7F50 # 0 +0xC5F9 0x7F88 # 0 +0xC5FA 0x8836 # 0 +0xC5FB 0x8839 # 0 +0xC5FC 0x8862 # 0 +0xC5FD 0x8B93 # 0 +0xC5FE 0x8B92 # 0 +0xC640 0x8B96 # 0 +0xC641 0x8277 # 0 +0xC642 0x8D1B # 0 +0xC643 0x91C0 # 0 +0xC644 0x946A # 0 +0xC645 0x9742 # 0 +0xC646 0x9748 # 0 +0xC647 0x9744 # 0 +0xC648 0x97C6 # 0 +0xC649 0x9870 # 0 +0xC64A 0x9A5F # 0 +0xC64B 0x9B22 # 0 +0xC64C 0x9B58 # 0 +0xC64D 0x9C5F # 0 +0xC64E 0x9DF9 # 0 +0xC64F 0x9DFA # 0 +0xC650 0x9E7C # 0 +0xC651 0x9E7D # 0 +0xC652 0x9F07 # 0 +0xC653 0x9F77 # 0 +0xC654 0x9F72 # 0 +0xC655 0x5EF3 # 0 +0xC656 0x6B16 # 0 +0xC657 0x7063 # 0 +0xC658 0x7C6C # 0 +0xC659 0x7C6E # 0 +0xC65A 0x883B # 0 +0xC65B 0x89C0 # 0 +0xC65C 0x8EA1 # 0 +0xC65D 0x91C1 # 0 +0xC65E 0x9472 # 0 +0xC65F 0x9470 # 0 +0xC660 0x9871 # 0 +0xC661 0x995E # 0 +0xC662 0x9AD6 # 0 +0xC663 0x9B23 # 0 +0xC664 0x9ECC # 0 +0xC665 0x7064 # 0 +0xC666 0x77DA # 0 +0xC667 0x8B9A # 0 +0xC668 0x9477 # 0 +0xC669 0x97C9 # 0 +0xC66A 0x9A62 # 0 +0xC66B 0x9A65 # 0 +0xC66C 0x7E9C # 0 +0xC66D 0x8B9C # 0 +0xC66E 0x8EAA # 0 +0xC66F 0x91C5 # 0 +0xC670 0x947D # 0 +0xC671 0x947E # 0 +0xC672 0x947C # 0 +0xC673 0x9C77 # 0 +0xC674 0x9C78 # 0 +0xC675 0x9EF7 # 0 +0xC676 0x8C54 # 0 +0xC677 0x947F # 0 +0xC678 0x9E1A # 0 +0xC679 0x7228 # 0 +0xC67A 0x9A6A # 0 +0xC67B 0x9B31 # 0 +0xC67C 0x9E1B # 0 +0xC67D 0x9E1E # 0 +0xC67E 0x7C72 # 0 +0xC6A1 0xF6B1 # 0 +0xC6A2 0xF6B2 # 0 +0xC6A3 0xF6B3 # 0 +0xC6A4 0xF6B4 # 0 +0xC6A5 0xF6B5 # 0 +0xC6A6 0xF6B6 # 0 +0xC6A7 0xF6B7 # 0 +0xC6A8 0xF6B8 # 0 +0xC6A9 0xF6B9 # 0 +0xC6AA 0xF6BA # 0 +0xC6AB 0xF6BB # 0 +0xC6AC 0xF6BC # 0 +0xC6AD 0xF6BD # 0 +0xC6AE 0xF6BE # 0 +0xC6AF 0xF6BF # 0 +0xC6B0 0xF6C0 # 0 +0xC6B1 0xF6C1 # 0 +0xC6B2 0xF6C2 # 0 +0xC6B3 0xF6C3 # 0 +0xC6B4 0xF6C4 # 0 +0xC6B5 0xF6C5 # 0 +0xC6B6 0xF6C6 # 0 +0xC6B7 0xF6C7 # 0 +0xC6B8 0xF6C8 # 0 +0xC6B9 0xF6C9 # 0 +0xC6BA 0xF6CA # 0 +0xC6BB 0xF6CB # 0 +0xC6BC 0xF6CC # 0 +0xC6BD 0xF6CD # 0 +0xC6BE 0xF6CE # 0 +0xC6BF 0xF6CF # 0 +0xC6C0 0xF6D0 # 0 +0xC6C1 0xF6D1 # 0 +0xC6C2 0xF6D2 # 0 +0xC6C3 0xF6D3 # 0 +0xC6C4 0xF6D4 # 0 +0xC6C5 0xF6D5 # 0 +0xC6C6 0xF6D6 # 0 +0xC6C7 0xF6D7 # 0 +0xC6C8 0xF6D8 # 0 +0xC6C9 0xF6D9 # 0 +0xC6CA 0xF6DA # 0 +0xC6CB 0xF6DB # 0 +0xC6CC 0xF6DC # 0 +0xC6CD 0xF6DD # 0 +0xC6CE 0xF6DE # 0 +0xC6CF 0xF6DF # 0 +0xC6D0 0xF6E0 # 0 +0xC6D1 0xF6E1 # 0 +0xC6D2 0xF6E2 # 0 +0xC6D3 0xF6E3 # 0 +0xC6D4 0xF6E4 # 0 +0xC6D5 0xF6E5 # 0 +0xC6D6 0xF6E6 # 0 +0xC6D7 0xF6E7 # 0 +0xC6D8 0xF6E8 # 0 +0xC6D9 0xF6E9 # 0 +0xC6DA 0xF6EA # 0 +0xC6DB 0xF6EB # 0 +0xC6DC 0xF6EC # 0 +0xC6DD 0xF6ED # 0 +0xC6DE 0xF6EE # 0 +0xC6DF 0xF6EF # 0 +0xC6E0 0xF6F0 # 0 +0xC6E1 0xF6F1 # 0 +0xC6E2 0xF6F2 # 0 +0xC6E3 0xF6F3 # 0 +0xC6E4 0xF6F4 # 0 +0xC6E5 0xF6F5 # 0 +0xC6E6 0xF6F6 # 0 +0xC6E7 0xF6F7 # 0 +0xC6E8 0xF6F8 # 0 +0xC6E9 0xF6F9 # 0 +0xC6EA 0xF6FA # 0 +0xC6EB 0xF6FB # 0 +0xC6EC 0xF6FC # 0 +0xC6ED 0xF6FD # 0 +0xC6EE 0xF6FE # 0 +0xC6EF 0xF6FF # 0 +0xC6F0 0xF700 # 0 +0xC6F1 0xF701 # 0 +0xC6F2 0xF702 # 0 +0xC6F3 0xF703 # 0 +0xC6F4 0xF704 # 0 +0xC6F5 0xF705 # 0 +0xC6F6 0xF706 # 0 +0xC6F7 0xF707 # 0 +0xC6F8 0xF708 # 0 +0xC6F9 0xF709 # 0 +0xC6FA 0xF70A # 0 +0xC6FB 0xF70B # 0 +0xC6FC 0xF70C # 0 +0xC6FD 0xF70D # 0 +0xC6FE 0xF70E # 0 +0xC740 0xF70F # 0 +0xC741 0xF710 # 0 +0xC742 0xF711 # 0 +0xC743 0xF712 # 0 +0xC744 0xF713 # 0 +0xC745 0xF714 # 0 +0xC746 0xF715 # 0 +0xC747 0xF716 # 0 +0xC748 0xF717 # 0 +0xC749 0xF718 # 0 +0xC74A 0xF719 # 0 +0xC74B 0xF71A # 0 +0xC74C 0xF71B # 0 +0xC74D 0xF71C # 0 +0xC74E 0xF71D # 0 +0xC74F 0xF71E # 0 +0xC750 0xF71F # 0 +0xC751 0xF720 # 0 +0xC752 0xF721 # 0 +0xC753 0xF722 # 0 +0xC754 0xF723 # 0 +0xC755 0xF724 # 0 +0xC756 0xF725 # 0 +0xC757 0xF726 # 0 +0xC758 0xF727 # 0 +0xC759 0xF728 # 0 +0xC75A 0xF729 # 0 +0xC75B 0xF72A # 0 +0xC75C 0xF72B # 0 +0xC75D 0xF72C # 0 +0xC75E 0xF72D # 0 +0xC75F 0xF72E # 0 +0xC760 0xF72F # 0 +0xC761 0xF730 # 0 +0xC762 0xF731 # 0 +0xC763 0xF732 # 0 +0xC764 0xF733 # 0 +0xC765 0xF734 # 0 +0xC766 0xF735 # 0 +0xC767 0xF736 # 0 +0xC768 0xF737 # 0 +0xC769 0xF738 # 0 +0xC76A 0xF739 # 0 +0xC76B 0xF73A # 0 +0xC76C 0xF73B # 0 +0xC76D 0xF73C # 0 +0xC76E 0xF73D # 0 +0xC76F 0xF73E # 0 +0xC770 0xF73F # 0 +0xC771 0xF740 # 0 +0xC772 0xF741 # 0 +0xC773 0xF742 # 0 +0xC774 0xF743 # 0 +0xC775 0xF744 # 0 +0xC776 0xF745 # 0 +0xC777 0xF746 # 0 +0xC778 0xF747 # 0 +0xC779 0xF748 # 0 +0xC77A 0xF749 # 0 +0xC77B 0xF74A # 0 +0xC77C 0xF74B # 0 +0xC77D 0xF74C # 0 +0xC77E 0xF74D # 0 +0xC7A1 0xF74E # 0 +0xC7A2 0xF74F # 0 +0xC7A3 0xF750 # 0 +0xC7A4 0xF751 # 0 +0xC7A5 0xF752 # 0 +0xC7A6 0xF753 # 0 +0xC7A7 0xF754 # 0 +0xC7A8 0xF755 # 0 +0xC7A9 0xF756 # 0 +0xC7AA 0xF757 # 0 +0xC7AB 0xF758 # 0 +0xC7AC 0xF759 # 0 +0xC7AD 0xF75A # 0 +0xC7AE 0xF75B # 0 +0xC7AF 0xF75C # 0 +0xC7B0 0xF75D # 0 +0xC7B1 0xF75E # 0 +0xC7B2 0xF75F # 0 +0xC7B3 0xF760 # 0 +0xC7B4 0xF761 # 0 +0xC7B5 0xF762 # 0 +0xC7B6 0xF763 # 0 +0xC7B7 0xF764 # 0 +0xC7B8 0xF765 # 0 +0xC7B9 0xF766 # 0 +0xC7BA 0xF767 # 0 +0xC7BB 0xF768 # 0 +0xC7BC 0xF769 # 0 +0xC7BD 0xF76A # 0 +0xC7BE 0xF76B # 0 +0xC7BF 0xF76C # 0 +0xC7C0 0xF76D # 0 +0xC7C1 0xF76E # 0 +0xC7C2 0xF76F # 0 +0xC7C3 0xF770 # 0 +0xC7C4 0xF771 # 0 +0xC7C5 0xF772 # 0 +0xC7C6 0xF773 # 0 +0xC7C7 0xF774 # 0 +0xC7C8 0xF775 # 0 +0xC7C9 0xF776 # 0 +0xC7CA 0xF777 # 0 +0xC7CB 0xF778 # 0 +0xC7CC 0xF779 # 0 +0xC7CD 0xF77A # 0 +0xC7CE 0xF77B # 0 +0xC7CF 0xF77C # 0 +0xC7D0 0xF77D # 0 +0xC7D1 0xF77E # 0 +0xC7D2 0xF77F # 0 +0xC7D3 0xF780 # 0 +0xC7D4 0xF781 # 0 +0xC7D5 0xF782 # 0 +0xC7D6 0xF783 # 0 +0xC7D7 0xF784 # 0 +0xC7D8 0xF785 # 0 +0xC7D9 0xF786 # 0 +0xC7DA 0xF787 # 0 +0xC7DB 0xF788 # 0 +0xC7DC 0xF789 # 0 +0xC7DD 0xF78A # 0 +0xC7DE 0xF78B # 0 +0xC7DF 0xF78C # 0 +0xC7E0 0xF78D # 0 +0xC7E1 0xF78E # 0 +0xC7E2 0xF78F # 0 +0xC7E3 0xF790 # 0 +0xC7E4 0xF791 # 0 +0xC7E5 0xF792 # 0 +0xC7E6 0xF793 # 0 +0xC7E7 0xF794 # 0 +0xC7E8 0xF795 # 0 +0xC7E9 0xF796 # 0 +0xC7EA 0xF797 # 0 +0xC7EB 0xF798 # 0 +0xC7EC 0xF799 # 0 +0xC7ED 0xF79A # 0 +0xC7EE 0xF79B # 0 +0xC7EF 0xF79C # 0 +0xC7F0 0xF79D # 0 +0xC7F1 0xF79E # 0 +0xC7F2 0xF79F # 0 +0xC7F3 0xF7A0 # 0 +0xC7F4 0xF7A1 # 0 +0xC7F5 0xF7A2 # 0 +0xC7F6 0xF7A3 # 0 +0xC7F7 0xF7A4 # 0 +0xC7F8 0xF7A5 # 0 +0xC7F9 0xF7A6 # 0 +0xC7FA 0xF7A7 # 0 +0xC7FB 0xF7A8 # 0 +0xC7FC 0xF7A9 # 0 +0xC7FD 0xF7AA # 0 +0xC7FE 0xF7AB # 0 +0xC840 0xF7AC # 0 +0xC841 0xF7AD # 0 +0xC842 0xF7AE # 0 +0xC843 0xF7AF # 0 +0xC844 0xF7B0 # 0 +0xC845 0xF7B1 # 0 +0xC846 0xF7B2 # 0 +0xC847 0xF7B3 # 0 +0xC848 0xF7B4 # 0 +0xC849 0xF7B5 # 0 +0xC84A 0xF7B6 # 0 +0xC84B 0xF7B7 # 0 +0xC84C 0xF7B8 # 0 +0xC84D 0xF7B9 # 0 +0xC84E 0xF7BA # 0 +0xC84F 0xF7BB # 0 +0xC850 0xF7BC # 0 +0xC851 0xF7BD # 0 +0xC852 0xF7BE # 0 +0xC853 0xF7BF # 0 +0xC854 0xF7C0 # 0 +0xC855 0xF7C1 # 0 +0xC856 0xF7C2 # 0 +0xC857 0xF7C3 # 0 +0xC858 0xF7C4 # 0 +0xC859 0xF7C5 # 0 +0xC85A 0xF7C6 # 0 +0xC85B 0xF7C7 # 0 +0xC85C 0xF7C8 # 0 +0xC85D 0xF7C9 # 0 +0xC85E 0xF7CA # 0 +0xC85F 0xF7CB # 0 +0xC860 0xF7CC # 0 +0xC861 0xF7CD # 0 +0xC862 0xF7CE # 0 +0xC863 0xF7CF # 0 +0xC864 0xF7D0 # 0 +0xC865 0xF7D1 # 0 +0xC866 0xF7D2 # 0 +0xC867 0xF7D3 # 0 +0xC868 0xF7D4 # 0 +0xC869 0xF7D5 # 0 +0xC86A 0xF7D6 # 0 +0xC86B 0xF7D7 # 0 +0xC86C 0xF7D8 # 0 +0xC86D 0xF7D9 # 0 +0xC86E 0xF7DA # 0 +0xC86F 0xF7DB # 0 +0xC870 0xF7DC # 0 +0xC871 0xF7DD # 0 +0xC872 0xF7DE # 0 +0xC873 0xF7DF # 0 +0xC874 0xF7E0 # 0 +0xC875 0xF7E1 # 0 +0xC876 0xF7E2 # 0 +0xC877 0xF7E3 # 0 +0xC878 0xF7E4 # 0 +0xC879 0xF7E5 # 0 +0xC87A 0xF7E6 # 0 +0xC87B 0xF7E7 # 0 +0xC87C 0xF7E8 # 0 +0xC87D 0xF7E9 # 0 +0xC87E 0xF7EA # 0 +0xC8A1 0xF7EB # 0 +0xC8A2 0xF7EC # 0 +0xC8A3 0xF7ED # 0 +0xC8A4 0xF7EE # 0 +0xC8A5 0xF7EF # 0 +0xC8A6 0xF7F0 # 0 +0xC8A7 0xF7F1 # 0 +0xC8A8 0xF7F2 # 0 +0xC8A9 0xF7F3 # 0 +0xC8AA 0xF7F4 # 0 +0xC8AB 0xF7F5 # 0 +0xC8AC 0xF7F6 # 0 +0xC8AD 0xF7F7 # 0 +0xC8AE 0xF7F8 # 0 +0xC8AF 0xF7F9 # 0 +0xC8B0 0xF7FA # 0 +0xC8B1 0xF7FB # 0 +0xC8B2 0xF7FC # 0 +0xC8B3 0xF7FD # 0 +0xC8B4 0xF7FE # 0 +0xC8B5 0xF7FF # 0 +0xC8B6 0xF800 # 0 +0xC8B7 0xF801 # 0 +0xC8B8 0xF802 # 0 +0xC8B9 0xF803 # 0 +0xC8BA 0xF804 # 0 +0xC8BB 0xF805 # 0 +0xC8BC 0xF806 # 0 +0xC8BD 0xF807 # 0 +0xC8BE 0xF808 # 0 +0xC8BF 0xF809 # 0 +0xC8C0 0xF80A # 0 +0xC8C1 0xF80B # 0 +0xC8C2 0xF80C # 0 +0xC8C3 0xF80D # 0 +0xC8C4 0xF80E # 0 +0xC8C5 0xF80F # 0 +0xC8C6 0xF810 # 0 +0xC8C7 0xF811 # 0 +0xC8C8 0xF812 # 0 +0xC8C9 0xF813 # 0 +0xC8CA 0xF814 # 0 +0xC8CB 0xF815 # 0 +0xC8CC 0xF816 # 0 +0xC8CD 0xF817 # 0 +0xC8CE 0xF818 # 0 +0xC8CF 0xF819 # 0 +0xC8D0 0xF81A # 0 +0xC8D1 0xF81B # 0 +0xC8D2 0xF81C # 0 +0xC8D3 0xF81D # 0 +0xC8D4 0xF81E # 0 +0xC8D5 0xF81F # 0 +0xC8D6 0xF820 # 0 +0xC8D7 0xF821 # 0 +0xC8D8 0xF822 # 0 +0xC8D9 0xF823 # 0 +0xC8DA 0xF824 # 0 +0xC8DB 0xF825 # 0 +0xC8DC 0xF826 # 0 +0xC8DD 0xF827 # 0 +0xC8DE 0xF828 # 0 +0xC8DF 0xF829 # 0 +0xC8E0 0xF82A # 0 +0xC8E1 0xF82B # 0 +0xC8E2 0xF82C # 0 +0xC8E3 0xF82D # 0 +0xC8E4 0xF82E # 0 +0xC8E5 0xF82F # 0 +0xC8E6 0xF830 # 0 +0xC8E7 0xF831 # 0 +0xC8E8 0xF832 # 0 +0xC8E9 0xF833 # 0 +0xC8EA 0xF834 # 0 +0xC8EB 0xF835 # 0 +0xC8EC 0xF836 # 0 +0xC8ED 0xF837 # 0 +0xC8EE 0xF838 # 0 +0xC8EF 0xF839 # 0 +0xC8F0 0xF83A # 0 +0xC8F1 0xF83B # 0 +0xC8F2 0xF83C # 0 +0xC8F3 0xF83D # 0 +0xC8F4 0xF83E # 0 +0xC8F5 0xF83F # 0 +0xC8F6 0xF840 # 0 +0xC8F7 0xF841 # 0 +0xC8F8 0xF842 # 0 +0xC8F9 0xF843 # 0 +0xC8FA 0xF844 # 0 +0xC8FB 0xF845 # 0 +0xC8FC 0xF846 # 0 +0xC8FD 0xF847 # 0 +0xC8FE 0xF848 # 0 +0xC940 0x4E42 # 0 +0xC941 0x4E5C # 0 +0xC942 0x51F5 # 0 +0xC943 0x531A # 0 +0xC944 0x5382 # 0 +0xC945 0x4E07 # 0 +0xC946 0x4E0C # 0 +0xC947 0x4E47 # 0 +0xC948 0x4E8D # 0 +0xC949 0x56D7 # 0 +0xC94A 0xFA0C # 0 +0xC94B 0x5C6E # 0 +0xC94C 0x5F73 # 0 +0xC94D 0x4E0F # 0 +0xC94E 0x5187 # 0 +0xC94F 0x4E0E # 0 +0xC950 0x4E2E # 0 +0xC951 0x4E93 # 0 +0xC952 0x4EC2 # 0 +0xC953 0x4EC9 # 0 +0xC954 0x4EC8 # 0 +0xC955 0x5198 # 0 +0xC956 0x52FC # 0 +0xC957 0x536C # 0 +0xC958 0x53B9 # 0 +0xC959 0x5720 # 0 +0xC95A 0x5903 # 0 +0xC95B 0x592C # 0 +0xC95C 0x5C10 # 0 +0xC95D 0x5DFF # 0 +0xC95E 0x65E1 # 0 +0xC95F 0x6BB3 # 0 +0xC960 0x6BCC # 0 +0xC961 0x6C14 # 0 +0xC962 0x723F # 0 +0xC963 0x4E31 # 0 +0xC964 0x4E3C # 0 +0xC965 0x4EE8 # 0 +0xC966 0x4EDC # 0 +0xC967 0x4EE9 # 0 +0xC968 0x4EE1 # 0 +0xC969 0x4EDD # 0 +0xC96A 0x4EDA # 0 +0xC96B 0x520C # 0 +0xC96C 0x531C # 0 +0xC96D 0x534C # 0 +0xC96E 0x5722 # 0 +0xC96F 0x5723 # 0 +0xC970 0x5917 # 0 +0xC971 0x592F # 0 +0xC972 0x5B81 # 0 +0xC973 0x5B84 # 0 +0xC974 0x5C12 # 0 +0xC975 0x5C3B # 0 +0xC976 0x5C74 # 0 +0xC977 0x5C73 # 0 +0xC978 0x5E04 # 0 +0xC979 0x5E80 # 0 +0xC97A 0x5E82 # 0 +0xC97B 0x5FC9 # 0 +0xC97C 0x6209 # 0 +0xC97D 0x6250 # 0 +0xC97E 0x6C15 # 0 +0xC9A1 0x6C36 # 0 +0xC9A2 0x6C43 # 0 +0xC9A3 0x6C3F # 0 +0xC9A4 0x6C3B # 0 +0xC9A5 0x72AE # 0 +0xC9A6 0x72B0 # 0 +0xC9A7 0x738A # 0 +0xC9A8 0x79B8 # 0 +0xC9A9 0x808A # 0 +0xC9AA 0x961E # 0 +0xC9AB 0x4F0E # 0 +0xC9AC 0x4F18 # 0 +0xC9AD 0x4F2C # 0 +0xC9AE 0x4EF5 # 0 +0xC9AF 0x4F14 # 0 +0xC9B0 0x4EF1 # 0 +0xC9B1 0x4F00 # 0 +0xC9B2 0x4EF7 # 0 +0xC9B3 0x4F08 # 0 +0xC9B4 0x4F1D # 0 +0xC9B5 0x4F02 # 0 +0xC9B6 0x4F05 # 0 +0xC9B7 0x4F22 # 0 +0xC9B8 0x4F13 # 0 +0xC9B9 0x4F04 # 0 +0xC9BA 0x4EF4 # 0 +0xC9BB 0x4F12 # 0 +0xC9BC 0x51B1 # 0 +0xC9BD 0x5213 # 0 +0xC9BE 0x5209 # 0 +0xC9BF 0x5210 # 0 +0xC9C0 0x52A6 # 0 +0xC9C1 0x5322 # 0 +0xC9C2 0x531F # 0 +0xC9C3 0x534D # 0 +0xC9C4 0x538A # 0 +0xC9C5 0x5407 # 0 +0xC9C6 0x56E1 # 0 +0xC9C7 0x56DF # 0 +0xC9C8 0x572E # 0 +0xC9C9 0x572A # 0 +0xC9CA 0x5734 # 0 +0xC9CB 0x593C # 0 +0xC9CC 0x5980 # 0 +0xC9CD 0x597C # 0 +0xC9CE 0x5985 # 0 +0xC9CF 0x597B # 0 +0xC9D0 0x597E # 0 +0xC9D1 0x5977 # 0 +0xC9D2 0x597F # 0 +0xC9D3 0x5B56 # 0 +0xC9D4 0x5C15 # 0 +0xC9D5 0x5C25 # 0 +0xC9D6 0x5C7C # 0 +0xC9D7 0x5C7A # 0 +0xC9D8 0x5C7B # 0 +0xC9D9 0x5C7E # 0 +0xC9DA 0x5DDF # 0 +0xC9DB 0x5E75 # 0 +0xC9DC 0x5E84 # 0 +0xC9DD 0x5F02 # 0 +0xC9DE 0x5F1A # 0 +0xC9DF 0x5F74 # 0 +0xC9E0 0x5FD5 # 0 +0xC9E1 0x5FD4 # 0 +0xC9E2 0x5FCF # 0 +0xC9E3 0x625C # 0 +0xC9E4 0x625E # 0 +0xC9E5 0x6264 # 0 +0xC9E6 0x6261 # 0 +0xC9E7 0x6266 # 0 +0xC9E8 0x6262 # 0 +0xC9E9 0x6259 # 0 +0xC9EA 0x6260 # 0 +0xC9EB 0x625A # 0 +0xC9EC 0x6265 # 0 +0xC9ED 0x65EF # 0 +0xC9EE 0x65EE # 0 +0xC9EF 0x673E # 0 +0xC9F0 0x6739 # 0 +0xC9F1 0x6738 # 0 +0xC9F2 0x673B # 0 +0xC9F3 0x673A # 0 +0xC9F4 0x673F # 0 +0xC9F5 0x673C # 0 +0xC9F6 0x6733 # 0 +0xC9F7 0x6C18 # 0 +0xC9F8 0x6C46 # 0 +0xC9F9 0x6C52 # 0 +0xC9FA 0x6C5C # 0 +0xC9FB 0x6C4F # 0 +0xC9FC 0x6C4A # 0 +0xC9FD 0x6C54 # 0 +0xC9FE 0x6C4B # 0 +0xCA40 0x6C4C # 0 +0xCA41 0x7071 # 0 +0xCA42 0x725E # 0 +0xCA43 0x72B4 # 0 +0xCA44 0x72B5 # 0 +0xCA45 0x738E # 0 +0xCA46 0x752A # 0 +0xCA47 0x767F # 0 +0xCA48 0x7A75 # 0 +0xCA49 0x7F51 # 0 +0xCA4A 0x8278 # 0 +0xCA4B 0x827C # 0 +0xCA4C 0x8280 # 0 +0xCA4D 0x827D # 0 +0xCA4E 0x827F # 0 +0xCA4F 0x864D # 0 +0xCA50 0x897E # 0 +0xCA51 0x9099 # 0 +0xCA52 0x9097 # 0 +0xCA53 0x9098 # 0 +0xCA54 0x909B # 0 +0xCA55 0x9094 # 0 +0xCA56 0x9622 # 0 +0xCA57 0x9624 # 0 +0xCA58 0x9620 # 0 +0xCA59 0x9623 # 0 +0xCA5A 0x4F56 # 0 +0xCA5B 0x4F3B # 0 +0xCA5C 0x4F62 # 0 +0xCA5D 0x4F49 # 0 +0xCA5E 0x4F53 # 0 +0xCA5F 0x4F64 # 0 +0xCA60 0x4F3E # 0 +0xCA61 0x4F67 # 0 +0xCA62 0x4F52 # 0 +0xCA63 0x4F5F # 0 +0xCA64 0x4F41 # 0 +0xCA65 0x4F58 # 0 +0xCA66 0x4F2D # 0 +0xCA67 0x4F33 # 0 +0xCA68 0x4F3F # 0 +0xCA69 0x4F61 # 0 +0xCA6A 0x518F # 0 +0xCA6B 0x51B9 # 0 +0xCA6C 0x521C # 0 +0xCA6D 0x521E # 0 +0xCA6E 0x5221 # 0 +0xCA6F 0x52AD # 0 +0xCA70 0x52AE # 0 +0xCA71 0x5309 # 0 +0xCA72 0x5363 # 0 +0xCA73 0x5372 # 0 +0xCA74 0x538E # 0 +0xCA75 0x538F # 0 +0xCA76 0x5430 # 0 +0xCA77 0x5437 # 0 +0xCA78 0x542A # 0 +0xCA79 0x5454 # 0 +0xCA7A 0x5445 # 0 +0xCA7B 0x5419 # 0 +0xCA7C 0x541C # 0 +0xCA7D 0x5425 # 0 +0xCA7E 0x5418 # 0 +0xCAA1 0x543D # 0 +0xCAA2 0x544F # 0 +0xCAA3 0x5441 # 0 +0xCAA4 0x5428 # 0 +0xCAA5 0x5424 # 0 +0xCAA6 0x5447 # 0 +0xCAA7 0x56EE # 0 +0xCAA8 0x56E7 # 0 +0xCAA9 0x56E5 # 0 +0xCAAA 0x5741 # 0 +0xCAAB 0x5745 # 0 +0xCAAC 0x574C # 0 +0xCAAD 0x5749 # 0 +0xCAAE 0x574B # 0 +0xCAAF 0x5752 # 0 +0xCAB0 0x5906 # 0 +0xCAB1 0x5940 # 0 +0xCAB2 0x59A6 # 0 +0xCAB3 0x5998 # 0 +0xCAB4 0x59A0 # 0 +0xCAB5 0x5997 # 0 +0xCAB6 0x598E # 0 +0xCAB7 0x59A2 # 0 +0xCAB8 0x5990 # 0 +0xCAB9 0x598F # 0 +0xCABA 0x59A7 # 0 +0xCABB 0x59A1 # 0 +0xCABC 0x5B8E # 0 +0xCABD 0x5B92 # 0 +0xCABE 0x5C28 # 0 +0xCABF 0x5C2A # 0 +0xCAC0 0x5C8D # 0 +0xCAC1 0x5C8F # 0 +0xCAC2 0x5C88 # 0 +0xCAC3 0x5C8B # 0 +0xCAC4 0x5C89 # 0 +0xCAC5 0x5C92 # 0 +0xCAC6 0x5C8A # 0 +0xCAC7 0x5C86 # 0 +0xCAC8 0x5C93 # 0 +0xCAC9 0x5C95 # 0 +0xCACA 0x5DE0 # 0 +0xCACB 0x5E0A # 0 +0xCACC 0x5E0E # 0 +0xCACD 0x5E8B # 0 +0xCACE 0x5E89 # 0 +0xCACF 0x5E8C # 0 +0xCAD0 0x5E88 # 0 +0xCAD1 0x5E8D # 0 +0xCAD2 0x5F05 # 0 +0xCAD3 0x5F1D # 0 +0xCAD4 0x5F78 # 0 +0xCAD5 0x5F76 # 0 +0xCAD6 0x5FD2 # 0 +0xCAD7 0x5FD1 # 0 +0xCAD8 0x5FD0 # 0 +0xCAD9 0x5FED # 0 +0xCADA 0x5FE8 # 0 +0xCADB 0x5FEE # 0 +0xCADC 0x5FF3 # 0 +0xCADD 0x5FE1 # 0 +0xCADE 0x5FE4 # 0 +0xCADF 0x5FE3 # 0 +0xCAE0 0x5FFA # 0 +0xCAE1 0x5FEF # 0 +0xCAE2 0x5FF7 # 0 +0xCAE3 0x5FFB # 0 +0xCAE4 0x6000 # 0 +0xCAE5 0x5FF4 # 0 +0xCAE6 0x623A # 0 +0xCAE7 0x6283 # 0 +0xCAE8 0x628C # 0 +0xCAE9 0x628E # 0 +0xCAEA 0x628F # 0 +0xCAEB 0x6294 # 0 +0xCAEC 0x6287 # 0 +0xCAED 0x6271 # 0 +0xCAEE 0x627B # 0 +0xCAEF 0x627A # 0 +0xCAF0 0x6270 # 0 +0xCAF1 0x6281 # 0 +0xCAF2 0x6288 # 0 +0xCAF3 0x6277 # 0 +0xCAF4 0x627D # 0 +0xCAF5 0x6272 # 0 +0xCAF6 0x6274 # 0 +0xCAF7 0x6537 # 0 +0xCAF8 0x65F0 # 0 +0xCAF9 0x65F4 # 0 +0xCAFA 0x65F3 # 0 +0xCAFB 0x65F2 # 0 +0xCAFC 0x65F5 # 0 +0xCAFD 0x6745 # 0 +0xCAFE 0x6747 # 0 +0xCB40 0x6759 # 0 +0xCB41 0x6755 # 0 +0xCB42 0x674C # 0 +0xCB43 0x6748 # 0 +0xCB44 0x675D # 0 +0xCB45 0x674D # 0 +0xCB46 0x675A # 0 +0xCB47 0x674B # 0 +0xCB48 0x6BD0 # 0 +0xCB49 0x6C19 # 0 +0xCB4A 0x6C1A # 0 +0xCB4B 0x6C78 # 0 +0xCB4C 0x6C67 # 0 +0xCB4D 0x6C6B # 0 +0xCB4E 0x6C84 # 0 +0xCB4F 0x6C8B # 0 +0xCB50 0x6C8F # 0 +0xCB51 0x6C71 # 0 +0xCB52 0x6C6F # 0 +0xCB53 0x6C69 # 0 +0xCB54 0x6C9A # 0 +0xCB55 0x6C6D # 0 +0xCB56 0x6C87 # 0 +0xCB57 0x6C95 # 0 +0xCB58 0x6C9C # 0 +0xCB59 0x6C66 # 0 +0xCB5A 0x6C73 # 0 +0xCB5B 0x6C65 # 0 +0xCB5C 0x6C7B # 0 +0xCB5D 0x6C8E # 0 +0xCB5E 0x7074 # 0 +0xCB5F 0x707A # 0 +0xCB60 0x7263 # 0 +0xCB61 0x72BF # 0 +0xCB62 0x72BD # 0 +0xCB63 0x72C3 # 0 +0xCB64 0x72C6 # 0 +0xCB65 0x72C1 # 0 +0xCB66 0x72BA # 0 +0xCB67 0x72C5 # 0 +0xCB68 0x7395 # 0 +0xCB69 0x7397 # 0 +0xCB6A 0x7393 # 0 +0xCB6B 0x7394 # 0 +0xCB6C 0x7392 # 0 +0xCB6D 0x753A # 0 +0xCB6E 0x7539 # 0 +0xCB6F 0x7594 # 0 +0xCB70 0x7595 # 0 +0xCB71 0x7681 # 0 +0xCB72 0x793D # 0 +0xCB73 0x8034 # 0 +0xCB74 0x8095 # 0 +0xCB75 0x8099 # 0 +0xCB76 0x8090 # 0 +0xCB77 0x8092 # 0 +0xCB78 0x809C # 0 +0xCB79 0x8290 # 0 +0xCB7A 0x828F # 0 +0xCB7B 0x8285 # 0 +0xCB7C 0x828E # 0 +0xCB7D 0x8291 # 0 +0xCB7E 0x8293 # 0 +0xCBA1 0x828A # 0 +0xCBA2 0x8283 # 0 +0xCBA3 0x8284 # 0 +0xCBA4 0x8C78 # 0 +0xCBA5 0x8FC9 # 0 +0xCBA6 0x8FBF # 0 +0xCBA7 0x909F # 0 +0xCBA8 0x90A1 # 0 +0xCBA9 0x90A5 # 0 +0xCBAA 0x909E # 0 +0xCBAB 0x90A7 # 0 +0xCBAC 0x90A0 # 0 +0xCBAD 0x9630 # 0 +0xCBAE 0x9628 # 0 +0xCBAF 0x962F # 0 +0xCBB0 0x962D # 0 +0xCBB1 0x4E33 # 0 +0xCBB2 0x4F98 # 0 +0xCBB3 0x4F7C # 0 +0xCBB4 0x4F85 # 0 +0xCBB5 0x4F7D # 0 +0xCBB6 0x4F80 # 0 +0xCBB7 0x4F87 # 0 +0xCBB8 0x4F76 # 0 +0xCBB9 0x4F74 # 0 +0xCBBA 0x4F89 # 0 +0xCBBB 0x4F84 # 0 +0xCBBC 0x4F77 # 0 +0xCBBD 0x4F4C # 0 +0xCBBE 0x4F97 # 0 +0xCBBF 0x4F6A # 0 +0xCBC0 0x4F9A # 0 +0xCBC1 0x4F79 # 0 +0xCBC2 0x4F81 # 0 +0xCBC3 0x4F78 # 0 +0xCBC4 0x4F90 # 0 +0xCBC5 0x4F9C # 0 +0xCBC6 0x4F94 # 0 +0xCBC7 0x4F9E # 0 +0xCBC8 0x4F92 # 0 +0xCBC9 0x4F82 # 0 +0xCBCA 0x4F95 # 0 +0xCBCB 0x4F6B # 0 +0xCBCC 0x4F6E # 0 +0xCBCD 0x519E # 0 +0xCBCE 0x51BC # 0 +0xCBCF 0x51BE # 0 +0xCBD0 0x5235 # 0 +0xCBD1 0x5232 # 0 +0xCBD2 0x5233 # 0 +0xCBD3 0x5246 # 0 +0xCBD4 0x5231 # 0 +0xCBD5 0x52BC # 0 +0xCBD6 0x530A # 0 +0xCBD7 0x530B # 0 +0xCBD8 0x533C # 0 +0xCBD9 0x5392 # 0 +0xCBDA 0x5394 # 0 +0xCBDB 0x5487 # 0 +0xCBDC 0x547F # 0 +0xCBDD 0x5481 # 0 +0xCBDE 0x5491 # 0 +0xCBDF 0x5482 # 0 +0xCBE0 0x5488 # 0 +0xCBE1 0x546B # 0 +0xCBE2 0x547A # 0 +0xCBE3 0x547E # 0 +0xCBE4 0x5465 # 0 +0xCBE5 0x546C # 0 +0xCBE6 0x5474 # 0 +0xCBE7 0x5466 # 0 +0xCBE8 0x548D # 0 +0xCBE9 0x546F # 0 +0xCBEA 0x5461 # 0 +0xCBEB 0x5460 # 0 +0xCBEC 0x5498 # 0 +0xCBED 0x5463 # 0 +0xCBEE 0x5467 # 0 +0xCBEF 0x5464 # 0 +0xCBF0 0x56F7 # 0 +0xCBF1 0x56F9 # 0 +0xCBF2 0x576F # 0 +0xCBF3 0x5772 # 0 +0xCBF4 0x576D # 0 +0xCBF5 0x576B # 0 +0xCBF6 0x5771 # 0 +0xCBF7 0x5770 # 0 +0xCBF8 0x5776 # 0 +0xCBF9 0x5780 # 0 +0xCBFA 0x5775 # 0 +0xCBFB 0x577B # 0 +0xCBFC 0x5773 # 0 +0xCBFD 0x5774 # 0 +0xCBFE 0x5762 # 0 +0xCC40 0x5768 # 0 +0xCC41 0x577D # 0 +0xCC42 0x590C # 0 +0xCC43 0x5945 # 0 +0xCC44 0x59B5 # 0 +0xCC45 0x59BA # 0 +0xCC46 0x59CF # 0 +0xCC47 0x59CE # 0 +0xCC48 0x59B2 # 0 +0xCC49 0x59CC # 0 +0xCC4A 0x59C1 # 0 +0xCC4B 0x59B6 # 0 +0xCC4C 0x59BC # 0 +0xCC4D 0x59C3 # 0 +0xCC4E 0x59D6 # 0 +0xCC4F 0x59B1 # 0 +0xCC50 0x59BD # 0 +0xCC51 0x59C0 # 0 +0xCC52 0x59C8 # 0 +0xCC53 0x59B4 # 0 +0xCC54 0x59C7 # 0 +0xCC55 0x5B62 # 0 +0xCC56 0x5B65 # 0 +0xCC57 0x5B93 # 0 +0xCC58 0x5B95 # 0 +0xCC59 0x5C44 # 0 +0xCC5A 0x5C47 # 0 +0xCC5B 0x5CAE # 0 +0xCC5C 0x5CA4 # 0 +0xCC5D 0x5CA0 # 0 +0xCC5E 0x5CB5 # 0 +0xCC5F 0x5CAF # 0 +0xCC60 0x5CA8 # 0 +0xCC61 0x5CAC # 0 +0xCC62 0x5C9F # 0 +0xCC63 0x5CA3 # 0 +0xCC64 0x5CAD # 0 +0xCC65 0x5CA2 # 0 +0xCC66 0x5CAA # 0 +0xCC67 0x5CA7 # 0 +0xCC68 0x5C9D # 0 +0xCC69 0x5CA5 # 0 +0xCC6A 0x5CB6 # 0 +0xCC6B 0x5CB0 # 0 +0xCC6C 0x5CA6 # 0 +0xCC6D 0x5E17 # 0 +0xCC6E 0x5E14 # 0 +0xCC6F 0x5E19 # 0 +0xCC70 0x5F28 # 0 +0xCC71 0x5F22 # 0 +0xCC72 0x5F23 # 0 +0xCC73 0x5F24 # 0 +0xCC74 0x5F54 # 0 +0xCC75 0x5F82 # 0 +0xCC76 0x5F7E # 0 +0xCC77 0x5F7D # 0 +0xCC78 0x5FDE # 0 +0xCC79 0x5FE5 # 0 +0xCC7A 0x602D # 0 +0xCC7B 0x6026 # 0 +0xCC7C 0x6019 # 0 +0xCC7D 0x6032 # 0 +0xCC7E 0x600B # 0 +0xCCA1 0x6034 # 0 +0xCCA2 0x600A # 0 +0xCCA3 0x6017 # 0 +0xCCA4 0x6033 # 0 +0xCCA5 0x601A # 0 +0xCCA6 0x601E # 0 +0xCCA7 0x602C # 0 +0xCCA8 0x6022 # 0 +0xCCA9 0x600D # 0 +0xCCAA 0x6010 # 0 +0xCCAB 0x602E # 0 +0xCCAC 0x6013 # 0 +0xCCAD 0x6011 # 0 +0xCCAE 0x600C # 0 +0xCCAF 0x6009 # 0 +0xCCB0 0x601C # 0 +0xCCB1 0x6214 # 0 +0xCCB2 0x623D # 0 +0xCCB3 0x62AD # 0 +0xCCB4 0x62B4 # 0 +0xCCB5 0x62D1 # 0 +0xCCB6 0x62BE # 0 +0xCCB7 0x62AA # 0 +0xCCB8 0x62B6 # 0 +0xCCB9 0x62CA # 0 +0xCCBA 0x62AE # 0 +0xCCBB 0x62B3 # 0 +0xCCBC 0x62AF # 0 +0xCCBD 0x62BB # 0 +0xCCBE 0x62A9 # 0 +0xCCBF 0x62B0 # 0 +0xCCC0 0x62B8 # 0 +0xCCC1 0x653D # 0 +0xCCC2 0x65A8 # 0 +0xCCC3 0x65BB # 0 +0xCCC4 0x6609 # 0 +0xCCC5 0x65FC # 0 +0xCCC6 0x6604 # 0 +0xCCC7 0x6612 # 0 +0xCCC8 0x6608 # 0 +0xCCC9 0x65FB # 0 +0xCCCA 0x6603 # 0 +0xCCCB 0x660B # 0 +0xCCCC 0x660D # 0 +0xCCCD 0x6605 # 0 +0xCCCE 0x65FD # 0 +0xCCCF 0x6611 # 0 +0xCCD0 0x6610 # 0 +0xCCD1 0x66F6 # 0 +0xCCD2 0x670A # 0 +0xCCD3 0x6785 # 0 +0xCCD4 0x676C # 0 +0xCCD5 0x678E # 0 +0xCCD6 0x6792 # 0 +0xCCD7 0x6776 # 0 +0xCCD8 0x677B # 0 +0xCCD9 0x6798 # 0 +0xCCDA 0x6786 # 0 +0xCCDB 0x6784 # 0 +0xCCDC 0x6774 # 0 +0xCCDD 0x678D # 0 +0xCCDE 0x678C # 0 +0xCCDF 0x677A # 0 +0xCCE0 0x679F # 0 +0xCCE1 0x6791 # 0 +0xCCE2 0x6799 # 0 +0xCCE3 0x6783 # 0 +0xCCE4 0x677D # 0 +0xCCE5 0x6781 # 0 +0xCCE6 0x6778 # 0 +0xCCE7 0x6779 # 0 +0xCCE8 0x6794 # 0 +0xCCE9 0x6B25 # 0 +0xCCEA 0x6B80 # 0 +0xCCEB 0x6B7E # 0 +0xCCEC 0x6BDE # 0 +0xCCED 0x6C1D # 0 +0xCCEE 0x6C93 # 0 +0xCCEF 0x6CEC # 0 +0xCCF0 0x6CEB # 0 +0xCCF1 0x6CEE # 0 +0xCCF2 0x6CD9 # 0 +0xCCF3 0x6CB6 # 0 +0xCCF4 0x6CD4 # 0 +0xCCF5 0x6CAD # 0 +0xCCF6 0x6CE7 # 0 +0xCCF7 0x6CB7 # 0 +0xCCF8 0x6CD0 # 0 +0xCCF9 0x6CC2 # 0 +0xCCFA 0x6CBA # 0 +0xCCFB 0x6CC3 # 0 +0xCCFC 0x6CC6 # 0 +0xCCFD 0x6CED # 0 +0xCCFE 0x6CF2 # 0 +0xCD40 0x6CD2 # 0 +0xCD41 0x6CDD # 0 +0xCD42 0x6CB4 # 0 +0xCD43 0x6C8A # 0 +0xCD44 0x6C9D # 0 +0xCD45 0x6C80 # 0 +0xCD46 0x6CDE # 0 +0xCD47 0x6CC0 # 0 +0xCD48 0x6D30 # 0 +0xCD49 0x6CCD # 0 +0xCD4A 0x6CC7 # 0 +0xCD4B 0x6CB0 # 0 +0xCD4C 0x6CF9 # 0 +0xCD4D 0x6CCF # 0 +0xCD4E 0x6CE9 # 0 +0xCD4F 0x6CD1 # 0 +0xCD50 0x7094 # 0 +0xCD51 0x7098 # 0 +0xCD52 0x7085 # 0 +0xCD53 0x7093 # 0 +0xCD54 0x7086 # 0 +0xCD55 0x7084 # 0 +0xCD56 0x7091 # 0 +0xCD57 0x7096 # 0 +0xCD58 0x7082 # 0 +0xCD59 0x709A # 0 +0xCD5A 0x7083 # 0 +0xCD5B 0x726A # 0 +0xCD5C 0x72D6 # 0 +0xCD5D 0x72CB # 0 +0xCD5E 0x72D8 # 0 +0xCD5F 0x72C9 # 0 +0xCD60 0x72DC # 0 +0xCD61 0x72D2 # 0 +0xCD62 0x72D4 # 0 +0xCD63 0x72DA # 0 +0xCD64 0x72CC # 0 +0xCD65 0x72D1 # 0 +0xCD66 0x73A4 # 0 +0xCD67 0x73A1 # 0 +0xCD68 0x73AD # 0 +0xCD69 0x73A6 # 0 +0xCD6A 0x73A2 # 0 +0xCD6B 0x73A0 # 0 +0xCD6C 0x73AC # 0 +0xCD6D 0x739D # 0 +0xCD6E 0x74DD # 0 +0xCD6F 0x74E8 # 0 +0xCD70 0x753F # 0 +0xCD71 0x7540 # 0 +0xCD72 0x753E # 0 +0xCD73 0x758C # 0 +0xCD74 0x7598 # 0 +0xCD75 0x76AF # 0 +0xCD76 0x76F3 # 0 +0xCD77 0x76F1 # 0 +0xCD78 0x76F0 # 0 +0xCD79 0x76F5 # 0 +0xCD7A 0x77F8 # 0 +0xCD7B 0x77FC # 0 +0xCD7C 0x77F9 # 0 +0xCD7D 0x77FB # 0 +0xCD7E 0x77FA # 0 +0xCDA1 0x77F7 # 0 +0xCDA2 0x7942 # 0 +0xCDA3 0x793F # 0 +0xCDA4 0x79C5 # 0 +0xCDA5 0x7A78 # 0 +0xCDA6 0x7A7B # 0 +0xCDA7 0x7AFB # 0 +0xCDA8 0x7C75 # 0 +0xCDA9 0x7CFD # 0 +0xCDAA 0x8035 # 0 +0xCDAB 0x808F # 0 +0xCDAC 0x80AE # 0 +0xCDAD 0x80A3 # 0 +0xCDAE 0x80B8 # 0 +0xCDAF 0x80B5 # 0 +0xCDB0 0x80AD # 0 +0xCDB1 0x8220 # 0 +0xCDB2 0x82A0 # 0 +0xCDB3 0x82C0 # 0 +0xCDB4 0x82AB # 0 +0xCDB5 0x829A # 0 +0xCDB6 0x8298 # 0 +0xCDB7 0x829B # 0 +0xCDB8 0x82B5 # 0 +0xCDB9 0x82A7 # 0 +0xCDBA 0x82AE # 0 +0xCDBB 0x82BC # 0 +0xCDBC 0x829E # 0 +0xCDBD 0x82BA # 0 +0xCDBE 0x82B4 # 0 +0xCDBF 0x82A8 # 0 +0xCDC0 0x82A1 # 0 +0xCDC1 0x82A9 # 0 +0xCDC2 0x82C2 # 0 +0xCDC3 0x82A4 # 0 +0xCDC4 0x82C3 # 0 +0xCDC5 0x82B6 # 0 +0xCDC6 0x82A2 # 0 +0xCDC7 0x8670 # 0 +0xCDC8 0x866F # 0 +0xCDC9 0x866D # 0 +0xCDCA 0x866E # 0 +0xCDCB 0x8C56 # 0 +0xCDCC 0x8FD2 # 0 +0xCDCD 0x8FCB # 0 +0xCDCE 0x8FD3 # 0 +0xCDCF 0x8FCD # 0 +0xCDD0 0x8FD6 # 0 +0xCDD1 0x8FD5 # 0 +0xCDD2 0x8FD7 # 0 +0xCDD3 0x90B2 # 0 +0xCDD4 0x90B4 # 0 +0xCDD5 0x90AF # 0 +0xCDD6 0x90B3 # 0 +0xCDD7 0x90B0 # 0 +0xCDD8 0x9639 # 0 +0xCDD9 0x963D # 0 +0xCDDA 0x963C # 0 +0xCDDB 0x963A # 0 +0xCDDC 0x9643 # 0 +0xCDDD 0x4FCD # 0 +0xCDDE 0x4FC5 # 0 +0xCDDF 0x4FD3 # 0 +0xCDE0 0x4FB2 # 0 +0xCDE1 0x4FC9 # 0 +0xCDE2 0x4FCB # 0 +0xCDE3 0x4FC1 # 0 +0xCDE4 0x4FD4 # 0 +0xCDE5 0x4FDC # 0 +0xCDE6 0x4FD9 # 0 +0xCDE7 0x4FBB # 0 +0xCDE8 0x4FB3 # 0 +0xCDE9 0x4FDB # 0 +0xCDEA 0x4FC7 # 0 +0xCDEB 0x4FD6 # 0 +0xCDEC 0x4FBA # 0 +0xCDED 0x4FC0 # 0 +0xCDEE 0x4FB9 # 0 +0xCDEF 0x4FEC # 0 +0xCDF0 0x5244 # 0 +0xCDF1 0x5249 # 0 +0xCDF2 0x52C0 # 0 +0xCDF3 0x52C2 # 0 +0xCDF4 0x533D # 0 +0xCDF5 0x537C # 0 +0xCDF6 0x5397 # 0 +0xCDF7 0x5396 # 0 +0xCDF8 0x5399 # 0 +0xCDF9 0x5398 # 0 +0xCDFA 0x54BA # 0 +0xCDFB 0x54A1 # 0 +0xCDFC 0x54AD # 0 +0xCDFD 0x54A5 # 0 +0xCDFE 0x54CF # 0 +0xCE40 0x54C3 # 0 +0xCE41 0x830D # 0 +0xCE42 0x54B7 # 0 +0xCE43 0x54AE # 0 +0xCE44 0x54D6 # 0 +0xCE45 0x54B6 # 0 +0xCE46 0x54C5 # 0 +0xCE47 0x54C6 # 0 +0xCE48 0x54A0 # 0 +0xCE49 0x5470 # 0 +0xCE4A 0x54BC # 0 +0xCE4B 0x54A2 # 0 +0xCE4C 0x54BE # 0 +0xCE4D 0x5472 # 0 +0xCE4E 0x54DE # 0 +0xCE4F 0x54B0 # 0 +0xCE50 0x57B5 # 0 +0xCE51 0x579E # 0 +0xCE52 0x579F # 0 +0xCE53 0x57A4 # 0 +0xCE54 0x578C # 0 +0xCE55 0x5797 # 0 +0xCE56 0x579D # 0 +0xCE57 0x579B # 0 +0xCE58 0x5794 # 0 +0xCE59 0x5798 # 0 +0xCE5A 0x578F # 0 +0xCE5B 0x5799 # 0 +0xCE5C 0x57A5 # 0 +0xCE5D 0x579A # 0 +0xCE5E 0x5795 # 0 +0xCE5F 0x58F4 # 0 +0xCE60 0x590D # 0 +0xCE61 0x5953 # 0 +0xCE62 0x59E1 # 0 +0xCE63 0x59DE # 0 +0xCE64 0x59EE # 0 +0xCE65 0x5A00 # 0 +0xCE66 0x59F1 # 0 +0xCE67 0x59DD # 0 +0xCE68 0x59FA # 0 +0xCE69 0x59FD # 0 +0xCE6A 0x59FC # 0 +0xCE6B 0x59F6 # 0 +0xCE6C 0x59E4 # 0 +0xCE6D 0x59F2 # 0 +0xCE6E 0x59F7 # 0 +0xCE6F 0x59DB # 0 +0xCE70 0x59E9 # 0 +0xCE71 0x59F3 # 0 +0xCE72 0x59F5 # 0 +0xCE73 0x59E0 # 0 +0xCE74 0x59FE # 0 +0xCE75 0x59F4 # 0 +0xCE76 0x59ED # 0 +0xCE77 0x5BA8 # 0 +0xCE78 0x5C4C # 0 +0xCE79 0x5CD0 # 0 +0xCE7A 0x5CD8 # 0 +0xCE7B 0x5CCC # 0 +0xCE7C 0x5CD7 # 0 +0xCE7D 0x5CCB # 0 +0xCE7E 0x5CDB # 0 +0xCEA1 0x5CDE # 0 +0xCEA2 0x5CDA # 0 +0xCEA3 0x5CC9 # 0 +0xCEA4 0x5CC7 # 0 +0xCEA5 0x5CCA # 0 +0xCEA6 0x5CD6 # 0 +0xCEA7 0x5CD3 # 0 +0xCEA8 0x5CD4 # 0 +0xCEA9 0x5CCF # 0 +0xCEAA 0x5CC8 # 0 +0xCEAB 0x5CC6 # 0 +0xCEAC 0x5CCE # 0 +0xCEAD 0x5CDF # 0 +0xCEAE 0x5CF8 # 0 +0xCEAF 0x5DF9 # 0 +0xCEB0 0x5E21 # 0 +0xCEB1 0x5E22 # 0 +0xCEB2 0x5E23 # 0 +0xCEB3 0x5E20 # 0 +0xCEB4 0x5E24 # 0 +0xCEB5 0x5EB0 # 0 +0xCEB6 0x5EA4 # 0 +0xCEB7 0x5EA2 # 0 +0xCEB8 0x5E9B # 0 +0xCEB9 0x5EA3 # 0 +0xCEBA 0x5EA5 # 0 +0xCEBB 0x5F07 # 0 +0xCEBC 0x5F2E # 0 +0xCEBD 0x5F56 # 0 +0xCEBE 0x5F86 # 0 +0xCEBF 0x6037 # 0 +0xCEC0 0x6039 # 0 +0xCEC1 0x6054 # 0 +0xCEC2 0x6072 # 0 +0xCEC3 0x605E # 0 +0xCEC4 0x6045 # 0 +0xCEC5 0x6053 # 0 +0xCEC6 0x6047 # 0 +0xCEC7 0x6049 # 0 +0xCEC8 0x605B # 0 +0xCEC9 0x604C # 0 +0xCECA 0x6040 # 0 +0xCECB 0x6042 # 0 +0xCECC 0x605F # 0 +0xCECD 0x6024 # 0 +0xCECE 0x6044 # 0 +0xCECF 0x6058 # 0 +0xCED0 0x6066 # 0 +0xCED1 0x606E # 0 +0xCED2 0x6242 # 0 +0xCED3 0x6243 # 0 +0xCED4 0x62CF # 0 +0xCED5 0x630D # 0 +0xCED6 0x630B # 0 +0xCED7 0x62F5 # 0 +0xCED8 0x630E # 0 +0xCED9 0x6303 # 0 +0xCEDA 0x62EB # 0 +0xCEDB 0x62F9 # 0 +0xCEDC 0x630F # 0 +0xCEDD 0x630C # 0 +0xCEDE 0x62F8 # 0 +0xCEDF 0x62F6 # 0 +0xCEE0 0x6300 # 0 +0xCEE1 0x6313 # 0 +0xCEE2 0x6314 # 0 +0xCEE3 0x62FA # 0 +0xCEE4 0x6315 # 0 +0xCEE5 0x62FB # 0 +0xCEE6 0x62F0 # 0 +0xCEE7 0x6541 # 0 +0xCEE8 0x6543 # 0 +0xCEE9 0x65AA # 0 +0xCEEA 0x65BF # 0 +0xCEEB 0x6636 # 0 +0xCEEC 0x6621 # 0 +0xCEED 0x6632 # 0 +0xCEEE 0x6635 # 0 +0xCEEF 0x661C # 0 +0xCEF0 0x6626 # 0 +0xCEF1 0x6622 # 0 +0xCEF2 0x6633 # 0 +0xCEF3 0x662B # 0 +0xCEF4 0x663A # 0 +0xCEF5 0x661D # 0 +0xCEF6 0x6634 # 0 +0xCEF7 0x6639 # 0 +0xCEF8 0x662E # 0 +0xCEF9 0x670F # 0 +0xCEFA 0x6710 # 0 +0xCEFB 0x67C1 # 0 +0xCEFC 0x67F2 # 0 +0xCEFD 0x67C8 # 0 +0xCEFE 0x67BA # 0 +0xCF40 0x67DC # 0 +0xCF41 0x67BB # 0 +0xCF42 0x67F8 # 0 +0xCF43 0x67D8 # 0 +0xCF44 0x67C0 # 0 +0xCF45 0x67B7 # 0 +0xCF46 0x67C5 # 0 +0xCF47 0x67EB # 0 +0xCF48 0x67E4 # 0 +0xCF49 0x67DF # 0 +0xCF4A 0x67B5 # 0 +0xCF4B 0x67CD # 0 +0xCF4C 0x67B3 # 0 +0xCF4D 0x67F7 # 0 +0xCF4E 0x67F6 # 0 +0xCF4F 0x67EE # 0 +0xCF50 0x67E3 # 0 +0xCF51 0x67C2 # 0 +0xCF52 0x67B9 # 0 +0xCF53 0x67CE # 0 +0xCF54 0x67E7 # 0 +0xCF55 0x67F0 # 0 +0xCF56 0x67B2 # 0 +0xCF57 0x67FC # 0 +0xCF58 0x67C6 # 0 +0xCF59 0x67ED # 0 +0xCF5A 0x67CC # 0 +0xCF5B 0x67AE # 0 +0xCF5C 0x67E6 # 0 +0xCF5D 0x67DB # 0 +0xCF5E 0x67FA # 0 +0xCF5F 0x67C9 # 0 +0xCF60 0x67CA # 0 +0xCF61 0x67C3 # 0 +0xCF62 0x67EA # 0 +0xCF63 0x67CB # 0 +0xCF64 0x6B28 # 0 +0xCF65 0x6B82 # 0 +0xCF66 0x6B84 # 0 +0xCF67 0x6BB6 # 0 +0xCF68 0x6BD6 # 0 +0xCF69 0x6BD8 # 0 +0xCF6A 0x6BE0 # 0 +0xCF6B 0x6C20 # 0 +0xCF6C 0x6C21 # 0 +0xCF6D 0x6D28 # 0 +0xCF6E 0x6D34 # 0 +0xCF6F 0x6D2D # 0 +0xCF70 0x6D1F # 0 +0xCF71 0x6D3C # 0 +0xCF72 0x6D3F # 0 +0xCF73 0x6D12 # 0 +0xCF74 0x6D0A # 0 +0xCF75 0x6CDA # 0 +0xCF76 0x6D33 # 0 +0xCF77 0x6D04 # 0 +0xCF78 0x6D19 # 0 +0xCF79 0x6D3A # 0 +0xCF7A 0x6D1A # 0 +0xCF7B 0x6D11 # 0 +0xCF7C 0x6D00 # 0 +0xCF7D 0x6D1D # 0 +0xCF7E 0x6D42 # 0 +0xCFA1 0x6D01 # 0 +0xCFA2 0x6D18 # 0 +0xCFA3 0x6D37 # 0 +0xCFA4 0x6D03 # 0 +0xCFA5 0x6D0F # 0 +0xCFA6 0x6D40 # 0 +0xCFA7 0x6D07 # 0 +0xCFA8 0x6D20 # 0 +0xCFA9 0x6D2C # 0 +0xCFAA 0x6D08 # 0 +0xCFAB 0x6D22 # 0 +0xCFAC 0x6D09 # 0 +0xCFAD 0x6D10 # 0 +0xCFAE 0x70B7 # 0 +0xCFAF 0x709F # 0 +0xCFB0 0x70BE # 0 +0xCFB1 0x70B1 # 0 +0xCFB2 0x70B0 # 0 +0xCFB3 0x70A1 # 0 +0xCFB4 0x70B4 # 0 +0xCFB5 0x70B5 # 0 +0xCFB6 0x70A9 # 0 +0xCFB7 0x7241 # 0 +0xCFB8 0x7249 # 0 +0xCFB9 0x724A # 0 +0xCFBA 0x726C # 0 +0xCFBB 0x7270 # 0 +0xCFBC 0x7273 # 0 +0xCFBD 0x726E # 0 +0xCFBE 0x72CA # 0 +0xCFBF 0x72E4 # 0 +0xCFC0 0x72E8 # 0 +0xCFC1 0x72EB # 0 +0xCFC2 0x72DF # 0 +0xCFC3 0x72EA # 0 +0xCFC4 0x72E6 # 0 +0xCFC5 0x72E3 # 0 +0xCFC6 0x7385 # 0 +0xCFC7 0x73CC # 0 +0xCFC8 0x73C2 # 0 +0xCFC9 0x73C8 # 0 +0xCFCA 0x73C5 # 0 +0xCFCB 0x73B9 # 0 +0xCFCC 0x73B6 # 0 +0xCFCD 0x73B5 # 0 +0xCFCE 0x73B4 # 0 +0xCFCF 0x73EB # 0 +0xCFD0 0x73BF # 0 +0xCFD1 0x73C7 # 0 +0xCFD2 0x73BE # 0 +0xCFD3 0x73C3 # 0 +0xCFD4 0x73C6 # 0 +0xCFD5 0x73B8 # 0 +0xCFD6 0x73CB # 0 +0xCFD7 0x74EC # 0 +0xCFD8 0x74EE # 0 +0xCFD9 0x752E # 0 +0xCFDA 0x7547 # 0 +0xCFDB 0x7548 # 0 +0xCFDC 0x75A7 # 0 +0xCFDD 0x75AA # 0 +0xCFDE 0x7679 # 0 +0xCFDF 0x76C4 # 0 +0xCFE0 0x7708 # 0 +0xCFE1 0x7703 # 0 +0xCFE2 0x7704 # 0 +0xCFE3 0x7705 # 0 +0xCFE4 0x770A # 0 +0xCFE5 0x76F7 # 0 +0xCFE6 0x76FB # 0 +0xCFE7 0x76FA # 0 +0xCFE8 0x77E7 # 0 +0xCFE9 0x77E8 # 0 +0xCFEA 0x7806 # 0 +0xCFEB 0x7811 # 0 +0xCFEC 0x7812 # 0 +0xCFED 0x7805 # 0 +0xCFEE 0x7810 # 0 +0xCFEF 0x780F # 0 +0xCFF0 0x780E # 0 +0xCFF1 0x7809 # 0 +0xCFF2 0x7803 # 0 +0xCFF3 0x7813 # 0 +0xCFF4 0x794A # 0 +0xCFF5 0x794C # 0 +0xCFF6 0x794B # 0 +0xCFF7 0x7945 # 0 +0xCFF8 0x7944 # 0 +0xCFF9 0x79D5 # 0 +0xCFFA 0x79CD # 0 +0xCFFB 0x79CF # 0 +0xCFFC 0x79D6 # 0 +0xCFFD 0x79CE # 0 +0xCFFE 0x7A80 # 0 +0xD040 0x7A7E # 0 +0xD041 0x7AD1 # 0 +0xD042 0x7B00 # 0 +0xD043 0x7B01 # 0 +0xD044 0x7C7A # 0 +0xD045 0x7C78 # 0 +0xD046 0x7C79 # 0 +0xD047 0x7C7F # 0 +0xD048 0x7C80 # 0 +0xD049 0x7C81 # 0 +0xD04A 0x7D03 # 0 +0xD04B 0x7D08 # 0 +0xD04C 0x7D01 # 0 +0xD04D 0x7F58 # 0 +0xD04E 0x7F91 # 0 +0xD04F 0x7F8D # 0 +0xD050 0x7FBE # 0 +0xD051 0x8007 # 0 +0xD052 0x800E # 0 +0xD053 0x800F # 0 +0xD054 0x8014 # 0 +0xD055 0x8037 # 0 +0xD056 0x80D8 # 0 +0xD057 0x80C7 # 0 +0xD058 0x80E0 # 0 +0xD059 0x80D1 # 0 +0xD05A 0x80C8 # 0 +0xD05B 0x80C2 # 0 +0xD05C 0x80D0 # 0 +0xD05D 0x80C5 # 0 +0xD05E 0x80E3 # 0 +0xD05F 0x80D9 # 0 +0xD060 0x80DC # 0 +0xD061 0x80CA # 0 +0xD062 0x80D5 # 0 +0xD063 0x80C9 # 0 +0xD064 0x80CF # 0 +0xD065 0x80D7 # 0 +0xD066 0x80E6 # 0 +0xD067 0x80CD # 0 +0xD068 0x81FF # 0 +0xD069 0x8221 # 0 +0xD06A 0x8294 # 0 +0xD06B 0x82D9 # 0 +0xD06C 0x82FE # 0 +0xD06D 0x82F9 # 0 +0xD06E 0x8307 # 0 +0xD06F 0x82E8 # 0 +0xD070 0x8300 # 0 +0xD071 0x82D5 # 0 +0xD072 0x833A # 0 +0xD073 0x82EB # 0 +0xD074 0x82D6 # 0 +0xD075 0x82F4 # 0 +0xD076 0x82EC # 0 +0xD077 0x82E1 # 0 +0xD078 0x82F2 # 0 +0xD079 0x82F5 # 0 +0xD07A 0x830C # 0 +0xD07B 0x82FB # 0 +0xD07C 0x82F6 # 0 +0xD07D 0x82F0 # 0 +0xD07E 0x82EA # 0 +0xD0A1 0x82E4 # 0 +0xD0A2 0x82E0 # 0 +0xD0A3 0x82FA # 0 +0xD0A4 0x82F3 # 0 +0xD0A5 0x82ED # 0 +0xD0A6 0x8677 # 0 +0xD0A7 0x8674 # 0 +0xD0A8 0x867C # 0 +0xD0A9 0x8673 # 0 +0xD0AA 0x8841 # 0 +0xD0AB 0x884E # 0 +0xD0AC 0x8867 # 0 +0xD0AD 0x886A # 0 +0xD0AE 0x8869 # 0 +0xD0AF 0x89D3 # 0 +0xD0B0 0x8A04 # 0 +0xD0B1 0x8A07 # 0 +0xD0B2 0x8D72 # 0 +0xD0B3 0x8FE3 # 0 +0xD0B4 0x8FE1 # 0 +0xD0B5 0x8FEE # 0 +0xD0B6 0x8FE0 # 0 +0xD0B7 0x90F1 # 0 +0xD0B8 0x90BD # 0 +0xD0B9 0x90BF # 0 +0xD0BA 0x90D5 # 0 +0xD0BB 0x90C5 # 0 +0xD0BC 0x90BE # 0 +0xD0BD 0x90C7 # 0 +0xD0BE 0x90CB # 0 +0xD0BF 0x90C8 # 0 +0xD0C0 0x91D4 # 0 +0xD0C1 0x91D3 # 0 +0xD0C2 0x9654 # 0 +0xD0C3 0x964F # 0 +0xD0C4 0x9651 # 0 +0xD0C5 0x9653 # 0 +0xD0C6 0x964A # 0 +0xD0C7 0x964E # 0 +0xD0C8 0x501E # 0 +0xD0C9 0x5005 # 0 +0xD0CA 0x5007 # 0 +0xD0CB 0x5013 # 0 +0xD0CC 0x5022 # 0 +0xD0CD 0x5030 # 0 +0xD0CE 0x501B # 0 +0xD0CF 0x4FF5 # 0 +0xD0D0 0x4FF4 # 0 +0xD0D1 0x5033 # 0 +0xD0D2 0x5037 # 0 +0xD0D3 0x502C # 0 +0xD0D4 0x4FF6 # 0 +0xD0D5 0x4FF7 # 0 +0xD0D6 0x5017 # 0 +0xD0D7 0x501C # 0 +0xD0D8 0x5020 # 0 +0xD0D9 0x5027 # 0 +0xD0DA 0x5035 # 0 +0xD0DB 0x502F # 0 +0xD0DC 0x5031 # 0 +0xD0DD 0x500E # 0 +0xD0DE 0x515A # 0 +0xD0DF 0x5194 # 0 +0xD0E0 0x5193 # 0 +0xD0E1 0x51CA # 0 +0xD0E2 0x51C4 # 0 +0xD0E3 0x51C5 # 0 +0xD0E4 0x51C8 # 0 +0xD0E5 0x51CE # 0 +0xD0E6 0x5261 # 0 +0xD0E7 0x525A # 0 +0xD0E8 0x5252 # 0 +0xD0E9 0x525E # 0 +0xD0EA 0x525F # 0 +0xD0EB 0x5255 # 0 +0xD0EC 0x5262 # 0 +0xD0ED 0x52CD # 0 +0xD0EE 0x530E # 0 +0xD0EF 0x539E # 0 +0xD0F0 0x5526 # 0 +0xD0F1 0x54E2 # 0 +0xD0F2 0x5517 # 0 +0xD0F3 0x5512 # 0 +0xD0F4 0x54E7 # 0 +0xD0F5 0x54F3 # 0 +0xD0F6 0x54E4 # 0 +0xD0F7 0x551A # 0 +0xD0F8 0x54FF # 0 +0xD0F9 0x5504 # 0 +0xD0FA 0x5508 # 0 +0xD0FB 0x54EB # 0 +0xD0FC 0x5511 # 0 +0xD0FD 0x5505 # 0 +0xD0FE 0x54F1 # 0 +0xD140 0x550A # 0 +0xD141 0x54FB # 0 +0xD142 0x54F7 # 0 +0xD143 0x54F8 # 0 +0xD144 0x54E0 # 0 +0xD145 0x550E # 0 +0xD146 0x5503 # 0 +0xD147 0x550B # 0 +0xD148 0x5701 # 0 +0xD149 0x5702 # 0 +0xD14A 0x57CC # 0 +0xD14B 0x5832 # 0 +0xD14C 0x57D5 # 0 +0xD14D 0x57D2 # 0 +0xD14E 0x57BA # 0 +0xD14F 0x57C6 # 0 +0xD150 0x57BD # 0 +0xD151 0x57BC # 0 +0xD152 0x57B8 # 0 +0xD153 0x57B6 # 0 +0xD154 0x57BF # 0 +0xD155 0x57C7 # 0 +0xD156 0x57D0 # 0 +0xD157 0x57B9 # 0 +0xD158 0x57C1 # 0 +0xD159 0x590E # 0 +0xD15A 0x594A # 0 +0xD15B 0x5A19 # 0 +0xD15C 0x5A16 # 0 +0xD15D 0x5A2D # 0 +0xD15E 0x5A2E # 0 +0xD15F 0x5A15 # 0 +0xD160 0x5A0F # 0 +0xD161 0x5A17 # 0 +0xD162 0x5A0A # 0 +0xD163 0x5A1E # 0 +0xD164 0x5A33 # 0 +0xD165 0x5B6C # 0 +0xD166 0x5BA7 # 0 +0xD167 0x5BAD # 0 +0xD168 0x5BAC # 0 +0xD169 0x5C03 # 0 +0xD16A 0x5C56 # 0 +0xD16B 0x5C54 # 0 +0xD16C 0x5CEC # 0 +0xD16D 0x5CFF # 0 +0xD16E 0x5CEE # 0 +0xD16F 0x5CF1 # 0 +0xD170 0x5CF7 # 0 +0xD171 0x5D00 # 0 +0xD172 0x5CF9 # 0 +0xD173 0x5E29 # 0 +0xD174 0x5E28 # 0 +0xD175 0x5EA8 # 0 +0xD176 0x5EAE # 0 +0xD177 0x5EAA # 0 +0xD178 0x5EAC # 0 +0xD179 0x5F33 # 0 +0xD17A 0x5F30 # 0 +0xD17B 0x5F67 # 0 +0xD17C 0x605D # 0 +0xD17D 0x605A # 0 +0xD17E 0x6067 # 0 +0xD1A1 0x6041 # 0 +0xD1A2 0x60A2 # 0 +0xD1A3 0x6088 # 0 +0xD1A4 0x6080 # 0 +0xD1A5 0x6092 # 0 +0xD1A6 0x6081 # 0 +0xD1A7 0x609D # 0 +0xD1A8 0x6083 # 0 +0xD1A9 0x6095 # 0 +0xD1AA 0x609B # 0 +0xD1AB 0x6097 # 0 +0xD1AC 0x6087 # 0 +0xD1AD 0x609C # 0 +0xD1AE 0x608E # 0 +0xD1AF 0x6219 # 0 +0xD1B0 0x6246 # 0 +0xD1B1 0x62F2 # 0 +0xD1B2 0x6310 # 0 +0xD1B3 0x6356 # 0 +0xD1B4 0x632C # 0 +0xD1B5 0x6344 # 0 +0xD1B6 0x6345 # 0 +0xD1B7 0x6336 # 0 +0xD1B8 0x6343 # 0 +0xD1B9 0x63E4 # 0 +0xD1BA 0x6339 # 0 +0xD1BB 0x634B # 0 +0xD1BC 0x634A # 0 +0xD1BD 0x633C # 0 +0xD1BE 0x6329 # 0 +0xD1BF 0x6341 # 0 +0xD1C0 0x6334 # 0 +0xD1C1 0x6358 # 0 +0xD1C2 0x6354 # 0 +0xD1C3 0x6359 # 0 +0xD1C4 0x632D # 0 +0xD1C5 0x6347 # 0 +0xD1C6 0x6333 # 0 +0xD1C7 0x635A # 0 +0xD1C8 0x6351 # 0 +0xD1C9 0x6338 # 0 +0xD1CA 0x6357 # 0 +0xD1CB 0x6340 # 0 +0xD1CC 0x6348 # 0 +0xD1CD 0x654A # 0 +0xD1CE 0x6546 # 0 +0xD1CF 0x65C6 # 0 +0xD1D0 0x65C3 # 0 +0xD1D1 0x65C4 # 0 +0xD1D2 0x65C2 # 0 +0xD1D3 0x664A # 0 +0xD1D4 0x665F # 0 +0xD1D5 0x6647 # 0 +0xD1D6 0x6651 # 0 +0xD1D7 0x6712 # 0 +0xD1D8 0x6713 # 0 +0xD1D9 0x681F # 0 +0xD1DA 0x681A # 0 +0xD1DB 0x6849 # 0 +0xD1DC 0x6832 # 0 +0xD1DD 0x6833 # 0 +0xD1DE 0x683B # 0 +0xD1DF 0x684B # 0 +0xD1E0 0x684F # 0 +0xD1E1 0x6816 # 0 +0xD1E2 0x6831 # 0 +0xD1E3 0x681C # 0 +0xD1E4 0x6835 # 0 +0xD1E5 0x682B # 0 +0xD1E6 0x682D # 0 +0xD1E7 0x682F # 0 +0xD1E8 0x684E # 0 +0xD1E9 0x6844 # 0 +0xD1EA 0x6834 # 0 +0xD1EB 0x681D # 0 +0xD1EC 0x6812 # 0 +0xD1ED 0x6814 # 0 +0xD1EE 0x6826 # 0 +0xD1EF 0x6828 # 0 +0xD1F0 0x682E # 0 +0xD1F1 0x684D # 0 +0xD1F2 0x683A # 0 +0xD1F3 0x6825 # 0 +0xD1F4 0x6820 # 0 +0xD1F5 0x6B2C # 0 +0xD1F6 0x6B2F # 0 +0xD1F7 0x6B2D # 0 +0xD1F8 0x6B31 # 0 +0xD1F9 0x6B34 # 0 +0xD1FA 0x6B6D # 0 +0xD1FB 0x8082 # 0 +0xD1FC 0x6B88 # 0 +0xD1FD 0x6BE6 # 0 +0xD1FE 0x6BE4 # 0 +0xD240 0x6BE8 # 0 +0xD241 0x6BE3 # 0 +0xD242 0x6BE2 # 0 +0xD243 0x6BE7 # 0 +0xD244 0x6C25 # 0 +0xD245 0x6D7A # 0 +0xD246 0x6D63 # 0 +0xD247 0x6D64 # 0 +0xD248 0x6D76 # 0 +0xD249 0x6D0D # 0 +0xD24A 0x6D61 # 0 +0xD24B 0x6D92 # 0 +0xD24C 0x6D58 # 0 +0xD24D 0x6D62 # 0 +0xD24E 0x6D6D # 0 +0xD24F 0x6D6F # 0 +0xD250 0x6D91 # 0 +0xD251 0x6D8D # 0 +0xD252 0x6DEF # 0 +0xD253 0x6D7F # 0 +0xD254 0x6D86 # 0 +0xD255 0x6D5E # 0 +0xD256 0x6D67 # 0 +0xD257 0x6D60 # 0 +0xD258 0x6D97 # 0 +0xD259 0x6D70 # 0 +0xD25A 0x6D7C # 0 +0xD25B 0x6D5F # 0 +0xD25C 0x6D82 # 0 +0xD25D 0x6D98 # 0 +0xD25E 0x6D2F # 0 +0xD25F 0x6D68 # 0 +0xD260 0x6D8B # 0 +0xD261 0x6D7E # 0 +0xD262 0x6D80 # 0 +0xD263 0x6D84 # 0 +0xD264 0x6D16 # 0 +0xD265 0x6D83 # 0 +0xD266 0x6D7B # 0 +0xD267 0x6D7D # 0 +0xD268 0x6D75 # 0 +0xD269 0x6D90 # 0 +0xD26A 0x70DC # 0 +0xD26B 0x70D3 # 0 +0xD26C 0x70D1 # 0 +0xD26D 0x70DD # 0 +0xD26E 0x70CB # 0 +0xD26F 0x7F39 # 0 +0xD270 0x70E2 # 0 +0xD271 0x70D7 # 0 +0xD272 0x70D2 # 0 +0xD273 0x70DE # 0 +0xD274 0x70E0 # 0 +0xD275 0x70D4 # 0 +0xD276 0x70CD # 0 +0xD277 0x70C5 # 0 +0xD278 0x70C6 # 0 +0xD279 0x70C7 # 0 +0xD27A 0x70DA # 0 +0xD27B 0x70CE # 0 +0xD27C 0x70E1 # 0 +0xD27D 0x7242 # 0 +0xD27E 0x7278 # 0 +0xD2A1 0x7277 # 0 +0xD2A2 0x7276 # 0 +0xD2A3 0x7300 # 0 +0xD2A4 0x72FA # 0 +0xD2A5 0x72F4 # 0 +0xD2A6 0x72FE # 0 +0xD2A7 0x72F6 # 0 +0xD2A8 0x72F3 # 0 +0xD2A9 0x72FB # 0 +0xD2AA 0x7301 # 0 +0xD2AB 0x73D3 # 0 +0xD2AC 0x73D9 # 0 +0xD2AD 0x73E5 # 0 +0xD2AE 0x73D6 # 0 +0xD2AF 0x73BC # 0 +0xD2B0 0x73E7 # 0 +0xD2B1 0x73E3 # 0 +0xD2B2 0x73E9 # 0 +0xD2B3 0x73DC # 0 +0xD2B4 0x73D2 # 0 +0xD2B5 0x73DB # 0 +0xD2B6 0x73D4 # 0 +0xD2B7 0x73DD # 0 +0xD2B8 0x73DA # 0 +0xD2B9 0x73D7 # 0 +0xD2BA 0x73D8 # 0 +0xD2BB 0x73E8 # 0 +0xD2BC 0x74DE # 0 +0xD2BD 0x74DF # 0 +0xD2BE 0x74F4 # 0 +0xD2BF 0x74F5 # 0 +0xD2C0 0x7521 # 0 +0xD2C1 0x755B # 0 +0xD2C2 0x755F # 0 +0xD2C3 0x75B0 # 0 +0xD2C4 0x75C1 # 0 +0xD2C5 0x75BB # 0 +0xD2C6 0x75C4 # 0 +0xD2C7 0x75C0 # 0 +0xD2C8 0x75BF # 0 +0xD2C9 0x75B6 # 0 +0xD2CA 0x75BA # 0 +0xD2CB 0x768A # 0 +0xD2CC 0x76C9 # 0 +0xD2CD 0x771D # 0 +0xD2CE 0x771B # 0 +0xD2CF 0x7710 # 0 +0xD2D0 0x7713 # 0 +0xD2D1 0x7712 # 0 +0xD2D2 0x7723 # 0 +0xD2D3 0x7711 # 0 +0xD2D4 0x7715 # 0 +0xD2D5 0x7719 # 0 +0xD2D6 0x771A # 0 +0xD2D7 0x7722 # 0 +0xD2D8 0x7727 # 0 +0xD2D9 0x7823 # 0 +0xD2DA 0x782C # 0 +0xD2DB 0x7822 # 0 +0xD2DC 0x7835 # 0 +0xD2DD 0x782F # 0 +0xD2DE 0x7828 # 0 +0xD2DF 0x782E # 0 +0xD2E0 0x782B # 0 +0xD2E1 0x7821 # 0 +0xD2E2 0x7829 # 0 +0xD2E3 0x7833 # 0 +0xD2E4 0x782A # 0 +0xD2E5 0x7831 # 0 +0xD2E6 0x7954 # 0 +0xD2E7 0x795B # 0 +0xD2E8 0x794F # 0 +0xD2E9 0x795C # 0 +0xD2EA 0x7953 # 0 +0xD2EB 0x7952 # 0 +0xD2EC 0x7951 # 0 +0xD2ED 0x79EB # 0 +0xD2EE 0x79EC # 0 +0xD2EF 0x79E0 # 0 +0xD2F0 0x79EE # 0 +0xD2F1 0x79ED # 0 +0xD2F2 0x79EA # 0 +0xD2F3 0x79DC # 0 +0xD2F4 0x79DE # 0 +0xD2F5 0x79DD # 0 +0xD2F6 0x7A86 # 0 +0xD2F7 0x7A89 # 0 +0xD2F8 0x7A85 # 0 +0xD2F9 0x7A8B # 0 +0xD2FA 0x7A8C # 0 +0xD2FB 0x7A8A # 0 +0xD2FC 0x7A87 # 0 +0xD2FD 0x7AD8 # 0 +0xD2FE 0x7B10 # 0 +0xD340 0x7B04 # 0 +0xD341 0x7B13 # 0 +0xD342 0x7B05 # 0 +0xD343 0x7B0F # 0 +0xD344 0x7B08 # 0 +0xD345 0x7B0A # 0 +0xD346 0x7B0E # 0 +0xD347 0x7B09 # 0 +0xD348 0x7B12 # 0 +0xD349 0x7C84 # 0 +0xD34A 0x7C91 # 0 +0xD34B 0x7C8A # 0 +0xD34C 0x7C8C # 0 +0xD34D 0x7C88 # 0 +0xD34E 0x7C8D # 0 +0xD34F 0x7C85 # 0 +0xD350 0x7D1E # 0 +0xD351 0x7D1D # 0 +0xD352 0x7D11 # 0 +0xD353 0x7D0E # 0 +0xD354 0x7D18 # 0 +0xD355 0x7D16 # 0 +0xD356 0x7D13 # 0 +0xD357 0x7D1F # 0 +0xD358 0x7D12 # 0 +0xD359 0x7D0F # 0 +0xD35A 0x7D0C # 0 +0xD35B 0x7F5C # 0 +0xD35C 0x7F61 # 0 +0xD35D 0x7F5E # 0 +0xD35E 0x7F60 # 0 +0xD35F 0x7F5D # 0 +0xD360 0x7F5B # 0 +0xD361 0x7F96 # 0 +0xD362 0x7F92 # 0 +0xD363 0x7FC3 # 0 +0xD364 0x7FC2 # 0 +0xD365 0x7FC0 # 0 +0xD366 0x8016 # 0 +0xD367 0x803E # 0 +0xD368 0x8039 # 0 +0xD369 0x80FA # 0 +0xD36A 0x80F2 # 0 +0xD36B 0x80F9 # 0 +0xD36C 0x80F5 # 0 +0xD36D 0x8101 # 0 +0xD36E 0x80FB # 0 +0xD36F 0x8100 # 0 +0xD370 0x8201 # 0 +0xD371 0x822F # 0 +0xD372 0x8225 # 0 +0xD373 0x8333 # 0 +0xD374 0x832D # 0 +0xD375 0x8344 # 0 +0xD376 0x8319 # 0 +0xD377 0x8351 # 0 +0xD378 0x8325 # 0 +0xD379 0x8356 # 0 +0xD37A 0x833F # 0 +0xD37B 0x8341 # 0 +0xD37C 0x8326 # 0 +0xD37D 0x831C # 0 +0xD37E 0x8322 # 0 +0xD3A1 0x8342 # 0 +0xD3A2 0x834E # 0 +0xD3A3 0x831B # 0 +0xD3A4 0x832A # 0 +0xD3A5 0x8308 # 0 +0xD3A6 0x833C # 0 +0xD3A7 0x834D # 0 +0xD3A8 0x8316 # 0 +0xD3A9 0x8324 # 0 +0xD3AA 0x8320 # 0 +0xD3AB 0x8337 # 0 +0xD3AC 0x832F # 0 +0xD3AD 0x8329 # 0 +0xD3AE 0x8347 # 0 +0xD3AF 0x8345 # 0 +0xD3B0 0x834C # 0 +0xD3B1 0x8353 # 0 +0xD3B2 0x831E # 0 +0xD3B3 0x832C # 0 +0xD3B4 0x834B # 0 +0xD3B5 0x8327 # 0 +0xD3B6 0x8348 # 0 +0xD3B7 0x8653 # 0 +0xD3B8 0x8652 # 0 +0xD3B9 0x86A2 # 0 +0xD3BA 0x86A8 # 0 +0xD3BB 0x8696 # 0 +0xD3BC 0x868D # 0 +0xD3BD 0x8691 # 0 +0xD3BE 0x869E # 0 +0xD3BF 0x8687 # 0 +0xD3C0 0x8697 # 0 +0xD3C1 0x8686 # 0 +0xD3C2 0x868B # 0 +0xD3C3 0x869A # 0 +0xD3C4 0x8685 # 0 +0xD3C5 0x86A5 # 0 +0xD3C6 0x8699 # 0 +0xD3C7 0x86A1 # 0 +0xD3C8 0x86A7 # 0 +0xD3C9 0x8695 # 0 +0xD3CA 0x8698 # 0 +0xD3CB 0x868E # 0 +0xD3CC 0x869D # 0 +0xD3CD 0x8690 # 0 +0xD3CE 0x8694 # 0 +0xD3CF 0x8843 # 0 +0xD3D0 0x8844 # 0 +0xD3D1 0x886D # 0 +0xD3D2 0x8875 # 0 +0xD3D3 0x8876 # 0 +0xD3D4 0x8872 # 0 +0xD3D5 0x8880 # 0 +0xD3D6 0x8871 # 0 +0xD3D7 0x887F # 0 +0xD3D8 0x886F # 0 +0xD3D9 0x8883 # 0 +0xD3DA 0x887E # 0 +0xD3DB 0x8874 # 0 +0xD3DC 0x887C # 0 +0xD3DD 0x8A12 # 0 +0xD3DE 0x8C47 # 0 +0xD3DF 0x8C57 # 0 +0xD3E0 0x8C7B # 0 +0xD3E1 0x8CA4 # 0 +0xD3E2 0x8CA3 # 0 +0xD3E3 0x8D76 # 0 +0xD3E4 0x8D78 # 0 +0xD3E5 0x8DB5 # 0 +0xD3E6 0x8DB7 # 0 +0xD3E7 0x8DB6 # 0 +0xD3E8 0x8ED1 # 0 +0xD3E9 0x8ED3 # 0 +0xD3EA 0x8FFE # 0 +0xD3EB 0x8FF5 # 0 +0xD3EC 0x9002 # 0 +0xD3ED 0x8FFF # 0 +0xD3EE 0x8FFB # 0 +0xD3EF 0x9004 # 0 +0xD3F0 0x8FFC # 0 +0xD3F1 0x8FF6 # 0 +0xD3F2 0x90D6 # 0 +0xD3F3 0x90E0 # 0 +0xD3F4 0x90D9 # 0 +0xD3F5 0x90DA # 0 +0xD3F6 0x90E3 # 0 +0xD3F7 0x90DF # 0 +0xD3F8 0x90E5 # 0 +0xD3F9 0x90D8 # 0 +0xD3FA 0x90DB # 0 +0xD3FB 0x90D7 # 0 +0xD3FC 0x90DC # 0 +0xD3FD 0x90E4 # 0 +0xD3FE 0x9150 # 0 +0xD440 0x914E # 0 +0xD441 0x914F # 0 +0xD442 0x91D5 # 0 +0xD443 0x91E2 # 0 +0xD444 0x91DA # 0 +0xD445 0x965C # 0 +0xD446 0x965F # 0 +0xD447 0x96BC # 0 +0xD448 0x98E3 # 0 +0xD449 0x9ADF # 0 +0xD44A 0x9B2F # 0 +0xD44B 0x4E7F # 0 +0xD44C 0x5070 # 0 +0xD44D 0x506A # 0 +0xD44E 0x5061 # 0 +0xD44F 0x505E # 0 +0xD450 0x5060 # 0 +0xD451 0x5053 # 0 +0xD452 0x504B # 0 +0xD453 0x505D # 0 +0xD454 0x5072 # 0 +0xD455 0x5048 # 0 +0xD456 0x504D # 0 +0xD457 0x5041 # 0 +0xD458 0x505B # 0 +0xD459 0x504A # 0 +0xD45A 0x5062 # 0 +0xD45B 0x5015 # 0 +0xD45C 0x5045 # 0 +0xD45D 0x505F # 0 +0xD45E 0x5069 # 0 +0xD45F 0x506B # 0 +0xD460 0x5063 # 0 +0xD461 0x5064 # 0 +0xD462 0x5046 # 0 +0xD463 0x5040 # 0 +0xD464 0x506E # 0 +0xD465 0x5073 # 0 +0xD466 0x5057 # 0 +0xD467 0x5051 # 0 +0xD468 0x51D0 # 0 +0xD469 0x526B # 0 +0xD46A 0x526D # 0 +0xD46B 0x526C # 0 +0xD46C 0x526E # 0 +0xD46D 0x52D6 # 0 +0xD46E 0x52D3 # 0 +0xD46F 0x532D # 0 +0xD470 0x539C # 0 +0xD471 0x5575 # 0 +0xD472 0x5576 # 0 +0xD473 0x553C # 0 +0xD474 0x554D # 0 +0xD475 0x5550 # 0 +0xD476 0x5534 # 0 +0xD477 0x552A # 0 +0xD478 0x5551 # 0 +0xD479 0x5562 # 0 +0xD47A 0x5536 # 0 +0xD47B 0x5535 # 0 +0xD47C 0x5530 # 0 +0xD47D 0x5552 # 0 +0xD47E 0x5545 # 0 +0xD4A1 0x550C # 0 +0xD4A2 0x5532 # 0 +0xD4A3 0x5565 # 0 +0xD4A4 0x554E # 0 +0xD4A5 0x5539 # 0 +0xD4A6 0x5548 # 0 +0xD4A7 0x552D # 0 +0xD4A8 0x553B # 0 +0xD4A9 0x5540 # 0 +0xD4AA 0x554B # 0 +0xD4AB 0x570A # 0 +0xD4AC 0x5707 # 0 +0xD4AD 0x57FB # 0 +0xD4AE 0x5814 # 0 +0xD4AF 0x57E2 # 0 +0xD4B0 0x57F6 # 0 +0xD4B1 0x57DC # 0 +0xD4B2 0x57F4 # 0 +0xD4B3 0x5800 # 0 +0xD4B4 0x57ED # 0 +0xD4B5 0x57FD # 0 +0xD4B6 0x5808 # 0 +0xD4B7 0x57F8 # 0 +0xD4B8 0x580B # 0 +0xD4B9 0x57F3 # 0 +0xD4BA 0x57CF # 0 +0xD4BB 0x5807 # 0 +0xD4BC 0x57EE # 0 +0xD4BD 0x57E3 # 0 +0xD4BE 0x57F2 # 0 +0xD4BF 0x57E5 # 0 +0xD4C0 0x57EC # 0 +0xD4C1 0x57E1 # 0 +0xD4C2 0x580E # 0 +0xD4C3 0x57FC # 0 +0xD4C4 0x5810 # 0 +0xD4C5 0x57E7 # 0 +0xD4C6 0x5801 # 0 +0xD4C7 0x580C # 0 +0xD4C8 0x57F1 # 0 +0xD4C9 0x57E9 # 0 +0xD4CA 0x57F0 # 0 +0xD4CB 0x580D # 0 +0xD4CC 0x5804 # 0 +0xD4CD 0x595C # 0 +0xD4CE 0x5A60 # 0 +0xD4CF 0x5A58 # 0 +0xD4D0 0x5A55 # 0 +0xD4D1 0x5A67 # 0 +0xD4D2 0x5A5E # 0 +0xD4D3 0x5A38 # 0 +0xD4D4 0x5A35 # 0 +0xD4D5 0x5A6D # 0 +0xD4D6 0x5A50 # 0 +0xD4D7 0x5A5F # 0 +0xD4D8 0x5A65 # 0 +0xD4D9 0x5A6C # 0 +0xD4DA 0x5A53 # 0 +0xD4DB 0x5A64 # 0 +0xD4DC 0x5A57 # 0 +0xD4DD 0x5A43 # 0 +0xD4DE 0x5A5D # 0 +0xD4DF 0x5A52 # 0 +0xD4E0 0x5A44 # 0 +0xD4E1 0x5A5B # 0 +0xD4E2 0x5A48 # 0 +0xD4E3 0x5A8E # 0 +0xD4E4 0x5A3E # 0 +0xD4E5 0x5A4D # 0 +0xD4E6 0x5A39 # 0 +0xD4E7 0x5A4C # 0 +0xD4E8 0x5A70 # 0 +0xD4E9 0x5A69 # 0 +0xD4EA 0x5A47 # 0 +0xD4EB 0x5A51 # 0 +0xD4EC 0x5A56 # 0 +0xD4ED 0x5A42 # 0 +0xD4EE 0x5A5C # 0 +0xD4EF 0x5B72 # 0 +0xD4F0 0x5B6E # 0 +0xD4F1 0x5BC1 # 0 +0xD4F2 0x5BC0 # 0 +0xD4F3 0x5C59 # 0 +0xD4F4 0x5D1E # 0 +0xD4F5 0x5D0B # 0 +0xD4F6 0x5D1D # 0 +0xD4F7 0x5D1A # 0 +0xD4F8 0x5D20 # 0 +0xD4F9 0x5D0C # 0 +0xD4FA 0x5D28 # 0 +0xD4FB 0x5D0D # 0 +0xD4FC 0x5D26 # 0 +0xD4FD 0x5D25 # 0 +0xD4FE 0x5D0F # 0 +0xD540 0x5D30 # 0 +0xD541 0x5D12 # 0 +0xD542 0x5D23 # 0 +0xD543 0x5D1F # 0 +0xD544 0x5D2E # 0 +0xD545 0x5E3E # 0 +0xD546 0x5E34 # 0 +0xD547 0x5EB1 # 0 +0xD548 0x5EB4 # 0 +0xD549 0x5EB9 # 0 +0xD54A 0x5EB2 # 0 +0xD54B 0x5EB3 # 0 +0xD54C 0x5F36 # 0 +0xD54D 0x5F38 # 0 +0xD54E 0x5F9B # 0 +0xD54F 0x5F96 # 0 +0xD550 0x5F9F # 0 +0xD551 0x608A # 0 +0xD552 0x6090 # 0 +0xD553 0x6086 # 0 +0xD554 0x60BE # 0 +0xD555 0x60B0 # 0 +0xD556 0x60BA # 0 +0xD557 0x60D3 # 0 +0xD558 0x60D4 # 0 +0xD559 0x60CF # 0 +0xD55A 0x60E4 # 0 +0xD55B 0x60D9 # 0 +0xD55C 0x60DD # 0 +0xD55D 0x60C8 # 0 +0xD55E 0x60B1 # 0 +0xD55F 0x60DB # 0 +0xD560 0x60B7 # 0 +0xD561 0x60CA # 0 +0xD562 0x60BF # 0 +0xD563 0x60C3 # 0 +0xD564 0x60CD # 0 +0xD565 0x60C0 # 0 +0xD566 0x6332 # 0 +0xD567 0x6365 # 0 +0xD568 0x638A # 0 +0xD569 0x6382 # 0 +0xD56A 0x637D # 0 +0xD56B 0x63BD # 0 +0xD56C 0x639E # 0 +0xD56D 0x63AD # 0 +0xD56E 0x639D # 0 +0xD56F 0x6397 # 0 +0xD570 0x63AB # 0 +0xD571 0x638E # 0 +0xD572 0x636F # 0 +0xD573 0x6387 # 0 +0xD574 0x6390 # 0 +0xD575 0x636E # 0 +0xD576 0x63AF # 0 +0xD577 0x6375 # 0 +0xD578 0x639C # 0 +0xD579 0x636D # 0 +0xD57A 0x63AE # 0 +0xD57B 0x637C # 0 +0xD57C 0x63A4 # 0 +0xD57D 0x633B # 0 +0xD57E 0x639F # 0 +0xD5A1 0x6378 # 0 +0xD5A2 0x6385 # 0 +0xD5A3 0x6381 # 0 +0xD5A4 0x6391 # 0 +0xD5A5 0x638D # 0 +0xD5A6 0x6370 # 0 +0xD5A7 0x6553 # 0 +0xD5A8 0x65CD # 0 +0xD5A9 0x6665 # 0 +0xD5AA 0x6661 # 0 +0xD5AB 0x665B # 0 +0xD5AC 0x6659 # 0 +0xD5AD 0x665C # 0 +0xD5AE 0x6662 # 0 +0xD5AF 0x6718 # 0 +0xD5B0 0x6879 # 0 +0xD5B1 0x6887 # 0 +0xD5B2 0x6890 # 0 +0xD5B3 0x689C # 0 +0xD5B4 0x686D # 0 +0xD5B5 0x686E # 0 +0xD5B6 0x68AE # 0 +0xD5B7 0x68AB # 0 +0xD5B8 0x6956 # 0 +0xD5B9 0x686F # 0 +0xD5BA 0x68A3 # 0 +0xD5BB 0x68AC # 0 +0xD5BC 0x68A9 # 0 +0xD5BD 0x6875 # 0 +0xD5BE 0x6874 # 0 +0xD5BF 0x68B2 # 0 +0xD5C0 0x688F # 0 +0xD5C1 0x6877 # 0 +0xD5C2 0x6892 # 0 +0xD5C3 0x687C # 0 +0xD5C4 0x686B # 0 +0xD5C5 0x6872 # 0 +0xD5C6 0x68AA # 0 +0xD5C7 0x6880 # 0 +0xD5C8 0x6871 # 0 +0xD5C9 0x687E # 0 +0xD5CA 0x689B # 0 +0xD5CB 0x6896 # 0 +0xD5CC 0x688B # 0 +0xD5CD 0x68A0 # 0 +0xD5CE 0x6889 # 0 +0xD5CF 0x68A4 # 0 +0xD5D0 0x6878 # 0 +0xD5D1 0x687B # 0 +0xD5D2 0x6891 # 0 +0xD5D3 0x688C # 0 +0xD5D4 0x688A # 0 +0xD5D5 0x687D # 0 +0xD5D6 0x6B36 # 0 +0xD5D7 0x6B33 # 0 +0xD5D8 0x6B37 # 0 +0xD5D9 0x6B38 # 0 +0xD5DA 0x6B91 # 0 +0xD5DB 0x6B8F # 0 +0xD5DC 0x6B8D # 0 +0xD5DD 0x6B8E # 0 +0xD5DE 0x6B8C # 0 +0xD5DF 0x6C2A # 0 +0xD5E0 0x6DC0 # 0 +0xD5E1 0x6DAB # 0 +0xD5E2 0x6DB4 # 0 +0xD5E3 0x6DB3 # 0 +0xD5E4 0x6E74 # 0 +0xD5E5 0x6DAC # 0 +0xD5E6 0x6DE9 # 0 +0xD5E7 0x6DE2 # 0 +0xD5E8 0x6DB7 # 0 +0xD5E9 0x6DF6 # 0 +0xD5EA 0x6DD4 # 0 +0xD5EB 0x6E00 # 0 +0xD5EC 0x6DC8 # 0 +0xD5ED 0x6DE0 # 0 +0xD5EE 0x6DDF # 0 +0xD5EF 0x6DD6 # 0 +0xD5F0 0x6DBE # 0 +0xD5F1 0x6DE5 # 0 +0xD5F2 0x6DDC # 0 +0xD5F3 0x6DDD # 0 +0xD5F4 0x6DDB # 0 +0xD5F5 0x6DF4 # 0 +0xD5F6 0x6DCA # 0 +0xD5F7 0x6DBD # 0 +0xD5F8 0x6DED # 0 +0xD5F9 0x6DF0 # 0 +0xD5FA 0x6DBA # 0 +0xD5FB 0x6DD5 # 0 +0xD5FC 0x6DC2 # 0 +0xD5FD 0x6DCF # 0 +0xD5FE 0x6DC9 # 0 +0xD640 0x6DD0 # 0 +0xD641 0x6DF2 # 0 +0xD642 0x6DD3 # 0 +0xD643 0x6DFD # 0 +0xD644 0x6DD7 # 0 +0xD645 0x6DCD # 0 +0xD646 0x6DE3 # 0 +0xD647 0x6DBB # 0 +0xD648 0x70FA # 0 +0xD649 0x710D # 0 +0xD64A 0x70F7 # 0 +0xD64B 0x7117 # 0 +0xD64C 0x70F4 # 0 +0xD64D 0x710C # 0 +0xD64E 0x70F0 # 0 +0xD64F 0x7104 # 0 +0xD650 0x70F3 # 0 +0xD651 0x7110 # 0 +0xD652 0x70FC # 0 +0xD653 0x70FF # 0 +0xD654 0x7106 # 0 +0xD655 0x7113 # 0 +0xD656 0x7100 # 0 +0xD657 0x70F8 # 0 +0xD658 0x70F6 # 0 +0xD659 0x710B # 0 +0xD65A 0x7102 # 0 +0xD65B 0x710E # 0 +0xD65C 0x727E # 0 +0xD65D 0x727B # 0 +0xD65E 0x727C # 0 +0xD65F 0x727F # 0 +0xD660 0x731D # 0 +0xD661 0x7317 # 0 +0xD662 0x7307 # 0 +0xD663 0x7311 # 0 +0xD664 0x7318 # 0 +0xD665 0x730A # 0 +0xD666 0x7308 # 0 +0xD667 0x72FF # 0 +0xD668 0x730F # 0 +0xD669 0x731E # 0 +0xD66A 0x7388 # 0 +0xD66B 0x73F6 # 0 +0xD66C 0x73F8 # 0 +0xD66D 0x73F5 # 0 +0xD66E 0x7404 # 0 +0xD66F 0x7401 # 0 +0xD670 0x73FD # 0 +0xD671 0x7407 # 0 +0xD672 0x7400 # 0 +0xD673 0x73FA # 0 +0xD674 0x73FC # 0 +0xD675 0x73FF # 0 +0xD676 0x740C # 0 +0xD677 0x740B # 0 +0xD678 0x73F4 # 0 +0xD679 0x7408 # 0 +0xD67A 0x7564 # 0 +0xD67B 0x7563 # 0 +0xD67C 0x75CE # 0 +0xD67D 0x75D2 # 0 +0xD67E 0x75CF # 0 +0xD6A1 0x75CB # 0 +0xD6A2 0x75CC # 0 +0xD6A3 0x75D1 # 0 +0xD6A4 0x75D0 # 0 +0xD6A5 0x768F # 0 +0xD6A6 0x7689 # 0 +0xD6A7 0x76D3 # 0 +0xD6A8 0x7739 # 0 +0xD6A9 0x772F # 0 +0xD6AA 0x772D # 0 +0xD6AB 0x7731 # 0 +0xD6AC 0x7732 # 0 +0xD6AD 0x7734 # 0 +0xD6AE 0x7733 # 0 +0xD6AF 0x773D # 0 +0xD6B0 0x7725 # 0 +0xD6B1 0x773B # 0 +0xD6B2 0x7735 # 0 +0xD6B3 0x7848 # 0 +0xD6B4 0x7852 # 0 +0xD6B5 0x7849 # 0 +0xD6B6 0x784D # 0 +0xD6B7 0x784A # 0 +0xD6B8 0x784C # 0 +0xD6B9 0x7826 # 0 +0xD6BA 0x7845 # 0 +0xD6BB 0x7850 # 0 +0xD6BC 0x7964 # 0 +0xD6BD 0x7967 # 0 +0xD6BE 0x7969 # 0 +0xD6BF 0x796A # 0 +0xD6C0 0x7963 # 0 +0xD6C1 0x796B # 0 +0xD6C2 0x7961 # 0 +0xD6C3 0x79BB # 0 +0xD6C4 0x79FA # 0 +0xD6C5 0x79F8 # 0 +0xD6C6 0x79F6 # 0 +0xD6C7 0x79F7 # 0 +0xD6C8 0x7A8F # 0 +0xD6C9 0x7A94 # 0 +0xD6CA 0x7A90 # 0 +0xD6CB 0x7B35 # 0 +0xD6CC 0x7B47 # 0 +0xD6CD 0x7B34 # 0 +0xD6CE 0x7B25 # 0 +0xD6CF 0x7B30 # 0 +0xD6D0 0x7B22 # 0 +0xD6D1 0x7B24 # 0 +0xD6D2 0x7B33 # 0 +0xD6D3 0x7B18 # 0 +0xD6D4 0x7B2A # 0 +0xD6D5 0x7B1D # 0 +0xD6D6 0x7B31 # 0 +0xD6D7 0x7B2B # 0 +0xD6D8 0x7B2D # 0 +0xD6D9 0x7B2F # 0 +0xD6DA 0x7B32 # 0 +0xD6DB 0x7B38 # 0 +0xD6DC 0x7B1A # 0 +0xD6DD 0x7B23 # 0 +0xD6DE 0x7C94 # 0 +0xD6DF 0x7C98 # 0 +0xD6E0 0x7C96 # 0 +0xD6E1 0x7CA3 # 0 +0xD6E2 0x7D35 # 0 +0xD6E3 0x7D3D # 0 +0xD6E4 0x7D38 # 0 +0xD6E5 0x7D36 # 0 +0xD6E6 0x7D3A # 0 +0xD6E7 0x7D45 # 0 +0xD6E8 0x7D2C # 0 +0xD6E9 0x7D29 # 0 +0xD6EA 0x7D41 # 0 +0xD6EB 0x7D47 # 0 +0xD6EC 0x7D3E # 0 +0xD6ED 0x7D3F # 0 +0xD6EE 0x7D4A # 0 +0xD6EF 0x7D3B # 0 +0xD6F0 0x7D28 # 0 +0xD6F1 0x7F63 # 0 +0xD6F2 0x7F95 # 0 +0xD6F3 0x7F9C # 0 +0xD6F4 0x7F9D # 0 +0xD6F5 0x7F9B # 0 +0xD6F6 0x7FCA # 0 +0xD6F7 0x7FCB # 0 +0xD6F8 0x7FCD # 0 +0xD6F9 0x7FD0 # 0 +0xD6FA 0x7FD1 # 0 +0xD6FB 0x7FC7 # 0 +0xD6FC 0x7FCF # 0 +0xD6FD 0x7FC9 # 0 +0xD6FE 0x801F # 0 +0xD740 0x801E # 0 +0xD741 0x801B # 0 +0xD742 0x8047 # 0 +0xD743 0x8043 # 0 +0xD744 0x8048 # 0 +0xD745 0x8118 # 0 +0xD746 0x8125 # 0 +0xD747 0x8119 # 0 +0xD748 0x811B # 0 +0xD749 0x812D # 0 +0xD74A 0x811F # 0 +0xD74B 0x812C # 0 +0xD74C 0x811E # 0 +0xD74D 0x8121 # 0 +0xD74E 0x8115 # 0 +0xD74F 0x8127 # 0 +0xD750 0x811D # 0 +0xD751 0x8122 # 0 +0xD752 0x8211 # 0 +0xD753 0x8238 # 0 +0xD754 0x8233 # 0 +0xD755 0x823A # 0 +0xD756 0x8234 # 0 +0xD757 0x8232 # 0 +0xD758 0x8274 # 0 +0xD759 0x8390 # 0 +0xD75A 0x83A3 # 0 +0xD75B 0x83A8 # 0 +0xD75C 0x838D # 0 +0xD75D 0x837A # 0 +0xD75E 0x8373 # 0 +0xD75F 0x83A4 # 0 +0xD760 0x8374 # 0 +0xD761 0x838F # 0 +0xD762 0x8381 # 0 +0xD763 0x8395 # 0 +0xD764 0x8399 # 0 +0xD765 0x8375 # 0 +0xD766 0x8394 # 0 +0xD767 0x83A9 # 0 +0xD768 0x837D # 0 +0xD769 0x8383 # 0 +0xD76A 0x838C # 0 +0xD76B 0x839D # 0 +0xD76C 0x839B # 0 +0xD76D 0x83AA # 0 +0xD76E 0x838B # 0 +0xD76F 0x837E # 0 +0xD770 0x83A5 # 0 +0xD771 0x83AF # 0 +0xD772 0x8388 # 0 +0xD773 0x8397 # 0 +0xD774 0x83B0 # 0 +0xD775 0x837F # 0 +0xD776 0x83A6 # 0 +0xD777 0x8387 # 0 +0xD778 0x83AE # 0 +0xD779 0x8376 # 0 +0xD77A 0x839A # 0 +0xD77B 0x8659 # 0 +0xD77C 0x8656 # 0 +0xD77D 0x86BF # 0 +0xD77E 0x86B7 # 0 +0xD7A1 0x86C2 # 0 +0xD7A2 0x86C1 # 0 +0xD7A3 0x86C5 # 0 +0xD7A4 0x86BA # 0 +0xD7A5 0x86B0 # 0 +0xD7A6 0x86C8 # 0 +0xD7A7 0x86B9 # 0 +0xD7A8 0x86B3 # 0 +0xD7A9 0x86B8 # 0 +0xD7AA 0x86CC # 0 +0xD7AB 0x86B4 # 0 +0xD7AC 0x86BB # 0 +0xD7AD 0x86BC # 0 +0xD7AE 0x86C3 # 0 +0xD7AF 0x86BD # 0 +0xD7B0 0x86BE # 0 +0xD7B1 0x8852 # 0 +0xD7B2 0x8889 # 0 +0xD7B3 0x8895 # 0 +0xD7B4 0x88A8 # 0 +0xD7B5 0x88A2 # 0 +0xD7B6 0x88AA # 0 +0xD7B7 0x889A # 0 +0xD7B8 0x8891 # 0 +0xD7B9 0x88A1 # 0 +0xD7BA 0x889F # 0 +0xD7BB 0x8898 # 0 +0xD7BC 0x88A7 # 0 +0xD7BD 0x8899 # 0 +0xD7BE 0x889B # 0 +0xD7BF 0x8897 # 0 +0xD7C0 0x88A4 # 0 +0xD7C1 0x88AC # 0 +0xD7C2 0x888C # 0 +0xD7C3 0x8893 # 0 +0xD7C4 0x888E # 0 +0xD7C5 0x8982 # 0 +0xD7C6 0x89D6 # 0 +0xD7C7 0x89D9 # 0 +0xD7C8 0x89D5 # 0 +0xD7C9 0x8A30 # 0 +0xD7CA 0x8A27 # 0 +0xD7CB 0x8A2C # 0 +0xD7CC 0x8A1E # 0 +0xD7CD 0x8C39 # 0 +0xD7CE 0x8C3B # 0 +0xD7CF 0x8C5C # 0 +0xD7D0 0x8C5D # 0 +0xD7D1 0x8C7D # 0 +0xD7D2 0x8CA5 # 0 +0xD7D3 0x8D7D # 0 +0xD7D4 0x8D7B # 0 +0xD7D5 0x8D79 # 0 +0xD7D6 0x8DBC # 0 +0xD7D7 0x8DC2 # 0 +0xD7D8 0x8DB9 # 0 +0xD7D9 0x8DBF # 0 +0xD7DA 0x8DC1 # 0 +0xD7DB 0x8ED8 # 0 +0xD7DC 0x8EDE # 0 +0xD7DD 0x8EDD # 0 +0xD7DE 0x8EDC # 0 +0xD7DF 0x8ED7 # 0 +0xD7E0 0x8EE0 # 0 +0xD7E1 0x8EE1 # 0 +0xD7E2 0x9024 # 0 +0xD7E3 0x900B # 0 +0xD7E4 0x9011 # 0 +0xD7E5 0x901C # 0 +0xD7E6 0x900C # 0 +0xD7E7 0x9021 # 0 +0xD7E8 0x90EF # 0 +0xD7E9 0x90EA # 0 +0xD7EA 0x90F0 # 0 +0xD7EB 0x90F4 # 0 +0xD7EC 0x90F2 # 0 +0xD7ED 0x90F3 # 0 +0xD7EE 0x90D4 # 0 +0xD7EF 0x90EB # 0 +0xD7F0 0x90EC # 0 +0xD7F1 0x90E9 # 0 +0xD7F2 0x9156 # 0 +0xD7F3 0x9158 # 0 +0xD7F4 0x915A # 0 +0xD7F5 0x9153 # 0 +0xD7F6 0x9155 # 0 +0xD7F7 0x91EC # 0 +0xD7F8 0x91F4 # 0 +0xD7F9 0x91F1 # 0 +0xD7FA 0x91F3 # 0 +0xD7FB 0x91F8 # 0 +0xD7FC 0x91E4 # 0 +0xD7FD 0x91F9 # 0 +0xD7FE 0x91EA # 0 +0xD840 0x91EB # 0 +0xD841 0x91F7 # 0 +0xD842 0x91E8 # 0 +0xD843 0x91EE # 0 +0xD844 0x957A # 0 +0xD845 0x9586 # 0 +0xD846 0x9588 # 0 +0xD847 0x967C # 0 +0xD848 0x966D # 0 +0xD849 0x966B # 0 +0xD84A 0x9671 # 0 +0xD84B 0x966F # 0 +0xD84C 0x96BF # 0 +0xD84D 0x976A # 0 +0xD84E 0x9804 # 0 +0xD84F 0x98E5 # 0 +0xD850 0x9997 # 0 +0xD851 0x509B # 0 +0xD852 0x5095 # 0 +0xD853 0x5094 # 0 +0xD854 0x509E # 0 +0xD855 0x508B # 0 +0xD856 0x50A3 # 0 +0xD857 0x5083 # 0 +0xD858 0x508C # 0 +0xD859 0x508E # 0 +0xD85A 0x509D # 0 +0xD85B 0x5068 # 0 +0xD85C 0x509C # 0 +0xD85D 0x5092 # 0 +0xD85E 0x5082 # 0 +0xD85F 0x5087 # 0 +0xD860 0x515F # 0 +0xD861 0x51D4 # 0 +0xD862 0x5312 # 0 +0xD863 0x5311 # 0 +0xD864 0x53A4 # 0 +0xD865 0x53A7 # 0 +0xD866 0x5591 # 0 +0xD867 0x55A8 # 0 +0xD868 0x55A5 # 0 +0xD869 0x55AD # 0 +0xD86A 0x5577 # 0 +0xD86B 0x5645 # 0 +0xD86C 0x55A2 # 0 +0xD86D 0x5593 # 0 +0xD86E 0x5588 # 0 +0xD86F 0x558F # 0 +0xD870 0x55B5 # 0 +0xD871 0x5581 # 0 +0xD872 0x55A3 # 0 +0xD873 0x5592 # 0 +0xD874 0x55A4 # 0 +0xD875 0x557D # 0 +0xD876 0x558C # 0 +0xD877 0x55A6 # 0 +0xD878 0x557F # 0 +0xD879 0x5595 # 0 +0xD87A 0x55A1 # 0 +0xD87B 0x558E # 0 +0xD87C 0x570C # 0 +0xD87D 0x5829 # 0 +0xD87E 0x5837 # 0 +0xD8A1 0x5819 # 0 +0xD8A2 0x581E # 0 +0xD8A3 0x5827 # 0 +0xD8A4 0x5823 # 0 +0xD8A5 0x5828 # 0 +0xD8A6 0x57F5 # 0 +0xD8A7 0x5848 # 0 +0xD8A8 0x5825 # 0 +0xD8A9 0x581C # 0 +0xD8AA 0x581B # 0 +0xD8AB 0x5833 # 0 +0xD8AC 0x583F # 0 +0xD8AD 0x5836 # 0 +0xD8AE 0x582E # 0 +0xD8AF 0x5839 # 0 +0xD8B0 0x5838 # 0 +0xD8B1 0x582D # 0 +0xD8B2 0x582C # 0 +0xD8B3 0x583B # 0 +0xD8B4 0x5961 # 0 +0xD8B5 0x5AAF # 0 +0xD8B6 0x5A94 # 0 +0xD8B7 0x5A9F # 0 +0xD8B8 0x5A7A # 0 +0xD8B9 0x5AA2 # 0 +0xD8BA 0x5A9E # 0 +0xD8BB 0x5A78 # 0 +0xD8BC 0x5AA6 # 0 +0xD8BD 0x5A7C # 0 +0xD8BE 0x5AA5 # 0 +0xD8BF 0x5AAC # 0 +0xD8C0 0x5A95 # 0 +0xD8C1 0x5AAE # 0 +0xD8C2 0x5A37 # 0 +0xD8C3 0x5A84 # 0 +0xD8C4 0x5A8A # 0 +0xD8C5 0x5A97 # 0 +0xD8C6 0x5A83 # 0 +0xD8C7 0x5A8B # 0 +0xD8C8 0x5AA9 # 0 +0xD8C9 0x5A7B # 0 +0xD8CA 0x5A7D # 0 +0xD8CB 0x5A8C # 0 +0xD8CC 0x5A9C # 0 +0xD8CD 0x5A8F # 0 +0xD8CE 0x5A93 # 0 +0xD8CF 0x5A9D # 0 +0xD8D0 0x5BEA # 0 +0xD8D1 0x5BCD # 0 +0xD8D2 0x5BCB # 0 +0xD8D3 0x5BD4 # 0 +0xD8D4 0x5BD1 # 0 +0xD8D5 0x5BCA # 0 +0xD8D6 0x5BCE # 0 +0xD8D7 0x5C0C # 0 +0xD8D8 0x5C30 # 0 +0xD8D9 0x5D37 # 0 +0xD8DA 0x5D43 # 0 +0xD8DB 0x5D6B # 0 +0xD8DC 0x5D41 # 0 +0xD8DD 0x5D4B # 0 +0xD8DE 0x5D3F # 0 +0xD8DF 0x5D35 # 0 +0xD8E0 0x5D51 # 0 +0xD8E1 0x5D4E # 0 +0xD8E2 0x5D55 # 0 +0xD8E3 0x5D33 # 0 +0xD8E4 0x5D3A # 0 +0xD8E5 0x5D52 # 0 +0xD8E6 0x5D3D # 0 +0xD8E7 0x5D31 # 0 +0xD8E8 0x5D59 # 0 +0xD8E9 0x5D42 # 0 +0xD8EA 0x5D39 # 0 +0xD8EB 0x5D49 # 0 +0xD8EC 0x5D38 # 0 +0xD8ED 0x5D3C # 0 +0xD8EE 0x5D32 # 0 +0xD8EF 0x5D36 # 0 +0xD8F0 0x5D40 # 0 +0xD8F1 0x5D45 # 0 +0xD8F2 0x5E44 # 0 +0xD8F3 0x5E41 # 0 +0xD8F4 0x5F58 # 0 +0xD8F5 0x5FA6 # 0 +0xD8F6 0x5FA5 # 0 +0xD8F7 0x5FAB # 0 +0xD8F8 0x60C9 # 0 +0xD8F9 0x60B9 # 0 +0xD8FA 0x60CC # 0 +0xD8FB 0x60E2 # 0 +0xD8FC 0x60CE # 0 +0xD8FD 0x60C4 # 0 +0xD8FE 0x6114 # 0 +0xD940 0x60F2 # 0 +0xD941 0x610A # 0 +0xD942 0x6116 # 0 +0xD943 0x6105 # 0 +0xD944 0x60F5 # 0 +0xD945 0x6113 # 0 +0xD946 0x60F8 # 0 +0xD947 0x60FC # 0 +0xD948 0x60FE # 0 +0xD949 0x60C1 # 0 +0xD94A 0x6103 # 0 +0xD94B 0x6118 # 0 +0xD94C 0x611D # 0 +0xD94D 0x6110 # 0 +0xD94E 0x60FF # 0 +0xD94F 0x6104 # 0 +0xD950 0x610B # 0 +0xD951 0x624A # 0 +0xD952 0x6394 # 0 +0xD953 0x63B1 # 0 +0xD954 0x63B0 # 0 +0xD955 0x63CE # 0 +0xD956 0x63E5 # 0 +0xD957 0x63E8 # 0 +0xD958 0x63EF # 0 +0xD959 0x63C3 # 0 +0xD95A 0x649D # 0 +0xD95B 0x63F3 # 0 +0xD95C 0x63CA # 0 +0xD95D 0x63E0 # 0 +0xD95E 0x63F6 # 0 +0xD95F 0x63D5 # 0 +0xD960 0x63F2 # 0 +0xD961 0x63F5 # 0 +0xD962 0x6461 # 0 +0xD963 0x63DF # 0 +0xD964 0x63BE # 0 +0xD965 0x63DD # 0 +0xD966 0x63DC # 0 +0xD967 0x63C4 # 0 +0xD968 0x63D8 # 0 +0xD969 0x63D3 # 0 +0xD96A 0x63C2 # 0 +0xD96B 0x63C7 # 0 +0xD96C 0x63CC # 0 +0xD96D 0x63CB # 0 +0xD96E 0x63C8 # 0 +0xD96F 0x63F0 # 0 +0xD970 0x63D7 # 0 +0xD971 0x63D9 # 0 +0xD972 0x6532 # 0 +0xD973 0x6567 # 0 +0xD974 0x656A # 0 +0xD975 0x6564 # 0 +0xD976 0x655C # 0 +0xD977 0x6568 # 0 +0xD978 0x6565 # 0 +0xD979 0x658C # 0 +0xD97A 0x659D # 0 +0xD97B 0x659E # 0 +0xD97C 0x65AE # 0 +0xD97D 0x65D0 # 0 +0xD97E 0x65D2 # 0 +0xD9A1 0x667C # 0 +0xD9A2 0x666C # 0 +0xD9A3 0x667B # 0 +0xD9A4 0x6680 # 0 +0xD9A5 0x6671 # 0 +0xD9A6 0x6679 # 0 +0xD9A7 0x666A # 0 +0xD9A8 0x6672 # 0 +0xD9A9 0x6701 # 0 +0xD9AA 0x690C # 0 +0xD9AB 0x68D3 # 0 +0xD9AC 0x6904 # 0 +0xD9AD 0x68DC # 0 +0xD9AE 0x692A # 0 +0xD9AF 0x68EC # 0 +0xD9B0 0x68EA # 0 +0xD9B1 0x68F1 # 0 +0xD9B2 0x690F # 0 +0xD9B3 0x68D6 # 0 +0xD9B4 0x68F7 # 0 +0xD9B5 0x68EB # 0 +0xD9B6 0x68E4 # 0 +0xD9B7 0x68F6 # 0 +0xD9B8 0x6913 # 0 +0xD9B9 0x6910 # 0 +0xD9BA 0x68F3 # 0 +0xD9BB 0x68E1 # 0 +0xD9BC 0x6907 # 0 +0xD9BD 0x68CC # 0 +0xD9BE 0x6908 # 0 +0xD9BF 0x6970 # 0 +0xD9C0 0x68B4 # 0 +0xD9C1 0x6911 # 0 +0xD9C2 0x68EF # 0 +0xD9C3 0x68C6 # 0 +0xD9C4 0x6914 # 0 +0xD9C5 0x68F8 # 0 +0xD9C6 0x68D0 # 0 +0xD9C7 0x68FD # 0 +0xD9C8 0x68FC # 0 +0xD9C9 0x68E8 # 0 +0xD9CA 0x690B # 0 +0xD9CB 0x690A # 0 +0xD9CC 0x6917 # 0 +0xD9CD 0x68CE # 0 +0xD9CE 0x68C8 # 0 +0xD9CF 0x68DD # 0 +0xD9D0 0x68DE # 0 +0xD9D1 0x68E6 # 0 +0xD9D2 0x68F4 # 0 +0xD9D3 0x68D1 # 0 +0xD9D4 0x6906 # 0 +0xD9D5 0x68D4 # 0 +0xD9D6 0x68E9 # 0 +0xD9D7 0x6915 # 0 +0xD9D8 0x6925 # 0 +0xD9D9 0x68C7 # 0 +0xD9DA 0x6B39 # 0 +0xD9DB 0x6B3B # 0 +0xD9DC 0x6B3F # 0 +0xD9DD 0x6B3C # 0 +0xD9DE 0x6B94 # 0 +0xD9DF 0x6B97 # 0 +0xD9E0 0x6B99 # 0 +0xD9E1 0x6B95 # 0 +0xD9E2 0x6BBD # 0 +0xD9E3 0x6BF0 # 0 +0xD9E4 0x6BF2 # 0 +0xD9E5 0x6BF3 # 0 +0xD9E6 0x6C30 # 0 +0xD9E7 0x6DFC # 0 +0xD9E8 0x6E46 # 0 +0xD9E9 0x6E47 # 0 +0xD9EA 0x6E1F # 0 +0xD9EB 0x6E49 # 0 +0xD9EC 0x6E88 # 0 +0xD9ED 0x6E3C # 0 +0xD9EE 0x6E3D # 0 +0xD9EF 0x6E45 # 0 +0xD9F0 0x6E62 # 0 +0xD9F1 0x6E2B # 0 +0xD9F2 0x6E3F # 0 +0xD9F3 0x6E41 # 0 +0xD9F4 0x6E5D # 0 +0xD9F5 0x6E73 # 0 +0xD9F6 0x6E1C # 0 +0xD9F7 0x6E33 # 0 +0xD9F8 0x6E4B # 0 +0xD9F9 0x6E40 # 0 +0xD9FA 0x6E51 # 0 +0xD9FB 0x6E3B # 0 +0xD9FC 0x6E03 # 0 +0xD9FD 0x6E2E # 0 +0xD9FE 0x6E5E # 0 +0xDA40 0x6E68 # 0 +0xDA41 0x6E5C # 0 +0xDA42 0x6E61 # 0 +0xDA43 0x6E31 # 0 +0xDA44 0x6E28 # 0 +0xDA45 0x6E60 # 0 +0xDA46 0x6E71 # 0 +0xDA47 0x6E6B # 0 +0xDA48 0x6E39 # 0 +0xDA49 0x6E22 # 0 +0xDA4A 0x6E30 # 0 +0xDA4B 0x6E53 # 0 +0xDA4C 0x6E65 # 0 +0xDA4D 0x6E27 # 0 +0xDA4E 0x6E78 # 0 +0xDA4F 0x6E64 # 0 +0xDA50 0x6E77 # 0 +0xDA51 0x6E55 # 0 +0xDA52 0x6E79 # 0 +0xDA53 0x6E52 # 0 +0xDA54 0x6E66 # 0 +0xDA55 0x6E35 # 0 +0xDA56 0x6E36 # 0 +0xDA57 0x6E5A # 0 +0xDA58 0x7120 # 0 +0xDA59 0x711E # 0 +0xDA5A 0x712F # 0 +0xDA5B 0x70FB # 0 +0xDA5C 0x712E # 0 +0xDA5D 0x7131 # 0 +0xDA5E 0x7123 # 0 +0xDA5F 0x7125 # 0 +0xDA60 0x7122 # 0 +0xDA61 0x7132 # 0 +0xDA62 0x711F # 0 +0xDA63 0x7128 # 0 +0xDA64 0x713A # 0 +0xDA65 0x711B # 0 +0xDA66 0x724B # 0 +0xDA67 0x725A # 0 +0xDA68 0x7288 # 0 +0xDA69 0x7289 # 0 +0xDA6A 0x7286 # 0 +0xDA6B 0x7285 # 0 +0xDA6C 0x728B # 0 +0xDA6D 0x7312 # 0 +0xDA6E 0x730B # 0 +0xDA6F 0x7330 # 0 +0xDA70 0x7322 # 0 +0xDA71 0x7331 # 0 +0xDA72 0x7333 # 0 +0xDA73 0x7327 # 0 +0xDA74 0x7332 # 0 +0xDA75 0x732D # 0 +0xDA76 0x7326 # 0 +0xDA77 0x7323 # 0 +0xDA78 0x7335 # 0 +0xDA79 0x730C # 0 +0xDA7A 0x742E # 0 +0xDA7B 0x742C # 0 +0xDA7C 0x7430 # 0 +0xDA7D 0x742B # 0 +0xDA7E 0x7416 # 0 +0xDAA1 0x741A # 0 +0xDAA2 0x7421 # 0 +0xDAA3 0x742D # 0 +0xDAA4 0x7431 # 0 +0xDAA5 0x7424 # 0 +0xDAA6 0x7423 # 0 +0xDAA7 0x741D # 0 +0xDAA8 0x7429 # 0 +0xDAA9 0x7420 # 0 +0xDAAA 0x7432 # 0 +0xDAAB 0x74FB # 0 +0xDAAC 0x752F # 0 +0xDAAD 0x756F # 0 +0xDAAE 0x756C # 0 +0xDAAF 0x75E7 # 0 +0xDAB0 0x75DA # 0 +0xDAB1 0x75E1 # 0 +0xDAB2 0x75E6 # 0 +0xDAB3 0x75DD # 0 +0xDAB4 0x75DF # 0 +0xDAB5 0x75E4 # 0 +0xDAB6 0x75D7 # 0 +0xDAB7 0x7695 # 0 +0xDAB8 0x7692 # 0 +0xDAB9 0x76DA # 0 +0xDABA 0x7746 # 0 +0xDABB 0x7747 # 0 +0xDABC 0x7744 # 0 +0xDABD 0x774D # 0 +0xDABE 0x7745 # 0 +0xDABF 0x774A # 0 +0xDAC0 0x774E # 0 +0xDAC1 0x774B # 0 +0xDAC2 0x774C # 0 +0xDAC3 0x77DE # 0 +0xDAC4 0x77EC # 0 +0xDAC5 0x7860 # 0 +0xDAC6 0x7864 # 0 +0xDAC7 0x7865 # 0 +0xDAC8 0x785C # 0 +0xDAC9 0x786D # 0 +0xDACA 0x7871 # 0 +0xDACB 0x786A # 0 +0xDACC 0x786E # 0 +0xDACD 0x7870 # 0 +0xDACE 0x7869 # 0 +0xDACF 0x7868 # 0 +0xDAD0 0x785E # 0 +0xDAD1 0x7862 # 0 +0xDAD2 0x7974 # 0 +0xDAD3 0x7973 # 0 +0xDAD4 0x7972 # 0 +0xDAD5 0x7970 # 0 +0xDAD6 0x7A02 # 0 +0xDAD7 0x7A0A # 0 +0xDAD8 0x7A03 # 0 +0xDAD9 0x7A0C # 0 +0xDADA 0x7A04 # 0 +0xDADB 0x7A99 # 0 +0xDADC 0x7AE6 # 0 +0xDADD 0x7AE4 # 0 +0xDADE 0x7B4A # 0 +0xDADF 0x7B3B # 0 +0xDAE0 0x7B44 # 0 +0xDAE1 0x7B48 # 0 +0xDAE2 0x7B4C # 0 +0xDAE3 0x7B4E # 0 +0xDAE4 0x7B40 # 0 +0xDAE5 0x7B58 # 0 +0xDAE6 0x7B45 # 0 +0xDAE7 0x7CA2 # 0 +0xDAE8 0x7C9E # 0 +0xDAE9 0x7CA8 # 0 +0xDAEA 0x7CA1 # 0 +0xDAEB 0x7D58 # 0 +0xDAEC 0x7D6F # 0 +0xDAED 0x7D63 # 0 +0xDAEE 0x7D53 # 0 +0xDAEF 0x7D56 # 0 +0xDAF0 0x7D67 # 0 +0xDAF1 0x7D6A # 0 +0xDAF2 0x7D4F # 0 +0xDAF3 0x7D6D # 0 +0xDAF4 0x7D5C # 0 +0xDAF5 0x7D6B # 0 +0xDAF6 0x7D52 # 0 +0xDAF7 0x7D54 # 0 +0xDAF8 0x7D69 # 0 +0xDAF9 0x7D51 # 0 +0xDAFA 0x7D5F # 0 +0xDAFB 0x7D4E # 0 +0xDAFC 0x7F3E # 0 +0xDAFD 0x7F3F # 0 +0xDAFE 0x7F65 # 0 +0xDB40 0x7F66 # 0 +0xDB41 0x7FA2 # 0 +0xDB42 0x7FA0 # 0 +0xDB43 0x7FA1 # 0 +0xDB44 0x7FD7 # 0 +0xDB45 0x8051 # 0 +0xDB46 0x804F # 0 +0xDB47 0x8050 # 0 +0xDB48 0x80FE # 0 +0xDB49 0x80D4 # 0 +0xDB4A 0x8143 # 0 +0xDB4B 0x814A # 0 +0xDB4C 0x8152 # 0 +0xDB4D 0x814F # 0 +0xDB4E 0x8147 # 0 +0xDB4F 0x813D # 0 +0xDB50 0x814D # 0 +0xDB51 0x813A # 0 +0xDB52 0x81E6 # 0 +0xDB53 0x81EE # 0 +0xDB54 0x81F7 # 0 +0xDB55 0x81F8 # 0 +0xDB56 0x81F9 # 0 +0xDB57 0x8204 # 0 +0xDB58 0x823C # 0 +0xDB59 0x823D # 0 +0xDB5A 0x823F # 0 +0xDB5B 0x8275 # 0 +0xDB5C 0x833B # 0 +0xDB5D 0x83CF # 0 +0xDB5E 0x83F9 # 0 +0xDB5F 0x8423 # 0 +0xDB60 0x83C0 # 0 +0xDB61 0x83E8 # 0 +0xDB62 0x8412 # 0 +0xDB63 0x83E7 # 0 +0xDB64 0x83E4 # 0 +0xDB65 0x83FC # 0 +0xDB66 0x83F6 # 0 +0xDB67 0x8410 # 0 +0xDB68 0x83C6 # 0 +0xDB69 0x83C8 # 0 +0xDB6A 0x83EB # 0 +0xDB6B 0x83E3 # 0 +0xDB6C 0x83BF # 0 +0xDB6D 0x8401 # 0 +0xDB6E 0x83DD # 0 +0xDB6F 0x83E5 # 0 +0xDB70 0x83D8 # 0 +0xDB71 0x83FF # 0 +0xDB72 0x83E1 # 0 +0xDB73 0x83CB # 0 +0xDB74 0x83CE # 0 +0xDB75 0x83D6 # 0 +0xDB76 0x83F5 # 0 +0xDB77 0x83C9 # 0 +0xDB78 0x8409 # 0 +0xDB79 0x840F # 0 +0xDB7A 0x83DE # 0 +0xDB7B 0x8411 # 0 +0xDB7C 0x8406 # 0 +0xDB7D 0x83C2 # 0 +0xDB7E 0x83F3 # 0 +0xDBA1 0x83D5 # 0 +0xDBA2 0x83FA # 0 +0xDBA3 0x83C7 # 0 +0xDBA4 0x83D1 # 0 +0xDBA5 0x83EA # 0 +0xDBA6 0x8413 # 0 +0xDBA7 0x83C3 # 0 +0xDBA8 0x83EC # 0 +0xDBA9 0x83EE # 0 +0xDBAA 0x83C4 # 0 +0xDBAB 0x83FB # 0 +0xDBAC 0x83D7 # 0 +0xDBAD 0x83E2 # 0 +0xDBAE 0x841B # 0 +0xDBAF 0x83DB # 0 +0xDBB0 0x83FE # 0 +0xDBB1 0x86D8 # 0 +0xDBB2 0x86E2 # 0 +0xDBB3 0x86E6 # 0 +0xDBB4 0x86D3 # 0 +0xDBB5 0x86E3 # 0 +0xDBB6 0x86DA # 0 +0xDBB7 0x86EA # 0 +0xDBB8 0x86DD # 0 +0xDBB9 0x86EB # 0 +0xDBBA 0x86DC # 0 +0xDBBB 0x86EC # 0 +0xDBBC 0x86E9 # 0 +0xDBBD 0x86D7 # 0 +0xDBBE 0x86E8 # 0 +0xDBBF 0x86D1 # 0 +0xDBC0 0x8848 # 0 +0xDBC1 0x8856 # 0 +0xDBC2 0x8855 # 0 +0xDBC3 0x88BA # 0 +0xDBC4 0x88D7 # 0 +0xDBC5 0x88B9 # 0 +0xDBC6 0x88B8 # 0 +0xDBC7 0x88C0 # 0 +0xDBC8 0x88BE # 0 +0xDBC9 0x88B6 # 0 +0xDBCA 0x88BC # 0 +0xDBCB 0x88B7 # 0 +0xDBCC 0x88BD # 0 +0xDBCD 0x88B2 # 0 +0xDBCE 0x8901 # 0 +0xDBCF 0x88C9 # 0 +0xDBD0 0x8995 # 0 +0xDBD1 0x8998 # 0 +0xDBD2 0x8997 # 0 +0xDBD3 0x89DD # 0 +0xDBD4 0x89DA # 0 +0xDBD5 0x89DB # 0 +0xDBD6 0x8A4E # 0 +0xDBD7 0x8A4D # 0 +0xDBD8 0x8A39 # 0 +0xDBD9 0x8A59 # 0 +0xDBDA 0x8A40 # 0 +0xDBDB 0x8A57 # 0 +0xDBDC 0x8A58 # 0 +0xDBDD 0x8A44 # 0 +0xDBDE 0x8A45 # 0 +0xDBDF 0x8A52 # 0 +0xDBE0 0x8A48 # 0 +0xDBE1 0x8A51 # 0 +0xDBE2 0x8A4A # 0 +0xDBE3 0x8A4C # 0 +0xDBE4 0x8A4F # 0 +0xDBE5 0x8C5F # 0 +0xDBE6 0x8C81 # 0 +0xDBE7 0x8C80 # 0 +0xDBE8 0x8CBA # 0 +0xDBE9 0x8CBE # 0 +0xDBEA 0x8CB0 # 0 +0xDBEB 0x8CB9 # 0 +0xDBEC 0x8CB5 # 0 +0xDBED 0x8D84 # 0 +0xDBEE 0x8D80 # 0 +0xDBEF 0x8D89 # 0 +0xDBF0 0x8DD8 # 0 +0xDBF1 0x8DD3 # 0 +0xDBF2 0x8DCD # 0 +0xDBF3 0x8DC7 # 0 +0xDBF4 0x8DD6 # 0 +0xDBF5 0x8DDC # 0 +0xDBF6 0x8DCF # 0 +0xDBF7 0x8DD5 # 0 +0xDBF8 0x8DD9 # 0 +0xDBF9 0x8DC8 # 0 +0xDBFA 0x8DD7 # 0 +0xDBFB 0x8DC5 # 0 +0xDBFC 0x8EEF # 0 +0xDBFD 0x8EF7 # 0 +0xDBFE 0x8EFA # 0 +0xDC40 0x8EF9 # 0 +0xDC41 0x8EE6 # 0 +0xDC42 0x8EEE # 0 +0xDC43 0x8EE5 # 0 +0xDC44 0x8EF5 # 0 +0xDC45 0x8EE7 # 0 +0xDC46 0x8EE8 # 0 +0xDC47 0x8EF6 # 0 +0xDC48 0x8EEB # 0 +0xDC49 0x8EF1 # 0 +0xDC4A 0x8EEC # 0 +0xDC4B 0x8EF4 # 0 +0xDC4C 0x8EE9 # 0 +0xDC4D 0x902D # 0 +0xDC4E 0x9034 # 0 +0xDC4F 0x902F # 0 +0xDC50 0x9106 # 0 +0xDC51 0x912C # 0 +0xDC52 0x9104 # 0 +0xDC53 0x90FF # 0 +0xDC54 0x90FC # 0 +0xDC55 0x9108 # 0 +0xDC56 0x90F9 # 0 +0xDC57 0x90FB # 0 +0xDC58 0x9101 # 0 +0xDC59 0x9100 # 0 +0xDC5A 0x9107 # 0 +0xDC5B 0x9105 # 0 +0xDC5C 0x9103 # 0 +0xDC5D 0x9161 # 0 +0xDC5E 0x9164 # 0 +0xDC5F 0x915F # 0 +0xDC60 0x9162 # 0 +0xDC61 0x9160 # 0 +0xDC62 0x9201 # 0 +0xDC63 0x920A # 0 +0xDC64 0x9225 # 0 +0xDC65 0x9203 # 0 +0xDC66 0x921A # 0 +0xDC67 0x9226 # 0 +0xDC68 0x920F # 0 +0xDC69 0x920C # 0 +0xDC6A 0x9200 # 0 +0xDC6B 0x9212 # 0 +0xDC6C 0x91FF # 0 +0xDC6D 0x91FD # 0 +0xDC6E 0x9206 # 0 +0xDC6F 0x9204 # 0 +0xDC70 0x9227 # 0 +0xDC71 0x9202 # 0 +0xDC72 0x921C # 0 +0xDC73 0x9224 # 0 +0xDC74 0x9219 # 0 +0xDC75 0x9217 # 0 +0xDC76 0x9205 # 0 +0xDC77 0x9216 # 0 +0xDC78 0x957B # 0 +0xDC79 0x958D # 0 +0xDC7A 0x958C # 0 +0xDC7B 0x9590 # 0 +0xDC7C 0x9687 # 0 +0xDC7D 0x967E # 0 +0xDC7E 0x9688 # 0 +0xDCA1 0x9689 # 0 +0xDCA2 0x9683 # 0 +0xDCA3 0x9680 # 0 +0xDCA4 0x96C2 # 0 +0xDCA5 0x96C8 # 0 +0xDCA6 0x96C3 # 0 +0xDCA7 0x96F1 # 0 +0xDCA8 0x96F0 # 0 +0xDCA9 0x976C # 0 +0xDCAA 0x9770 # 0 +0xDCAB 0x976E # 0 +0xDCAC 0x9807 # 0 +0xDCAD 0x98A9 # 0 +0xDCAE 0x98EB # 0 +0xDCAF 0x9CE6 # 0 +0xDCB0 0x9EF9 # 0 +0xDCB1 0x4E83 # 0 +0xDCB2 0x4E84 # 0 +0xDCB3 0x4EB6 # 0 +0xDCB4 0x50BD # 0 +0xDCB5 0x50BF # 0 +0xDCB6 0x50C6 # 0 +0xDCB7 0x50AE # 0 +0xDCB8 0x50C4 # 0 +0xDCB9 0x50CA # 0 +0xDCBA 0x50B4 # 0 +0xDCBB 0x50C8 # 0 +0xDCBC 0x50C2 # 0 +0xDCBD 0x50B0 # 0 +0xDCBE 0x50C1 # 0 +0xDCBF 0x50BA # 0 +0xDCC0 0x50B1 # 0 +0xDCC1 0x50CB # 0 +0xDCC2 0x50C9 # 0 +0xDCC3 0x50B6 # 0 +0xDCC4 0x50B8 # 0 +0xDCC5 0x51D7 # 0 +0xDCC6 0x527A # 0 +0xDCC7 0x5278 # 0 +0xDCC8 0x527B # 0 +0xDCC9 0x527C # 0 +0xDCCA 0x55C3 # 0 +0xDCCB 0x55DB # 0 +0xDCCC 0x55CC # 0 +0xDCCD 0x55D0 # 0 +0xDCCE 0x55CB # 0 +0xDCCF 0x55CA # 0 +0xDCD0 0x55DD # 0 +0xDCD1 0x55C0 # 0 +0xDCD2 0x55D4 # 0 +0xDCD3 0x55C4 # 0 +0xDCD4 0x55E9 # 0 +0xDCD5 0x55BF # 0 +0xDCD6 0x55D2 # 0 +0xDCD7 0x558D # 0 +0xDCD8 0x55CF # 0 +0xDCD9 0x55D5 # 0 +0xDCDA 0x55E2 # 0 +0xDCDB 0x55D6 # 0 +0xDCDC 0x55C8 # 0 +0xDCDD 0x55F2 # 0 +0xDCDE 0x55CD # 0 +0xDCDF 0x55D9 # 0 +0xDCE0 0x55C2 # 0 +0xDCE1 0x5714 # 0 +0xDCE2 0x5853 # 0 +0xDCE3 0x5868 # 0 +0xDCE4 0x5864 # 0 +0xDCE5 0x584F # 0 +0xDCE6 0x584D # 0 +0xDCE7 0x5849 # 0 +0xDCE8 0x586F # 0 +0xDCE9 0x5855 # 0 +0xDCEA 0x584E # 0 +0xDCEB 0x585D # 0 +0xDCEC 0x5859 # 0 +0xDCED 0x5865 # 0 +0xDCEE 0x585B # 0 +0xDCEF 0x583D # 0 +0xDCF0 0x5863 # 0 +0xDCF1 0x5871 # 0 +0xDCF2 0x58FC # 0 +0xDCF3 0x5AC7 # 0 +0xDCF4 0x5AC4 # 0 +0xDCF5 0x5ACB # 0 +0xDCF6 0x5ABA # 0 +0xDCF7 0x5AB8 # 0 +0xDCF8 0x5AB1 # 0 +0xDCF9 0x5AB5 # 0 +0xDCFA 0x5AB0 # 0 +0xDCFB 0x5ABF # 0 +0xDCFC 0x5AC8 # 0 +0xDCFD 0x5ABB # 0 +0xDCFE 0x5AC6 # 0 +0xDD40 0x5AB7 # 0 +0xDD41 0x5AC0 # 0 +0xDD42 0x5ACA # 0 +0xDD43 0x5AB4 # 0 +0xDD44 0x5AB6 # 0 +0xDD45 0x5ACD # 0 +0xDD46 0x5AB9 # 0 +0xDD47 0x5A90 # 0 +0xDD48 0x5BD6 # 0 +0xDD49 0x5BD8 # 0 +0xDD4A 0x5BD9 # 0 +0xDD4B 0x5C1F # 0 +0xDD4C 0x5C33 # 0 +0xDD4D 0x5D71 # 0 +0xDD4E 0x5D63 # 0 +0xDD4F 0x5D4A # 0 +0xDD50 0x5D65 # 0 +0xDD51 0x5D72 # 0 +0xDD52 0x5D6C # 0 +0xDD53 0x5D5E # 0 +0xDD54 0x5D68 # 0 +0xDD55 0x5D67 # 0 +0xDD56 0x5D62 # 0 +0xDD57 0x5DF0 # 0 +0xDD58 0x5E4F # 0 +0xDD59 0x5E4E # 0 +0xDD5A 0x5E4A # 0 +0xDD5B 0x5E4D # 0 +0xDD5C 0x5E4B # 0 +0xDD5D 0x5EC5 # 0 +0xDD5E 0x5ECC # 0 +0xDD5F 0x5EC6 # 0 +0xDD60 0x5ECB # 0 +0xDD61 0x5EC7 # 0 +0xDD62 0x5F40 # 0 +0xDD63 0x5FAF # 0 +0xDD64 0x5FAD # 0 +0xDD65 0x60F7 # 0 +0xDD66 0x6149 # 0 +0xDD67 0x614A # 0 +0xDD68 0x612B # 0 +0xDD69 0x6145 # 0 +0xDD6A 0x6136 # 0 +0xDD6B 0x6132 # 0 +0xDD6C 0x612E # 0 +0xDD6D 0x6146 # 0 +0xDD6E 0x612F # 0 +0xDD6F 0x614F # 0 +0xDD70 0x6129 # 0 +0xDD71 0x6140 # 0 +0xDD72 0x6220 # 0 +0xDD73 0x9168 # 0 +0xDD74 0x6223 # 0 +0xDD75 0x6225 # 0 +0xDD76 0x6224 # 0 +0xDD77 0x63C5 # 0 +0xDD78 0x63F1 # 0 +0xDD79 0x63EB # 0 +0xDD7A 0x6410 # 0 +0xDD7B 0x6412 # 0 +0xDD7C 0x6409 # 0 +0xDD7D 0x6420 # 0 +0xDD7E 0x6424 # 0 +0xDDA1 0x6433 # 0 +0xDDA2 0x6443 # 0 +0xDDA3 0x641F # 0 +0xDDA4 0x6415 # 0 +0xDDA5 0x6418 # 0 +0xDDA6 0x6439 # 0 +0xDDA7 0x6437 # 0 +0xDDA8 0x6422 # 0 +0xDDA9 0x6423 # 0 +0xDDAA 0x640C # 0 +0xDDAB 0x6426 # 0 +0xDDAC 0x6430 # 0 +0xDDAD 0x6428 # 0 +0xDDAE 0x6441 # 0 +0xDDAF 0x6435 # 0 +0xDDB0 0x642F # 0 +0xDDB1 0x640A # 0 +0xDDB2 0x641A # 0 +0xDDB3 0x6440 # 0 +0xDDB4 0x6425 # 0 +0xDDB5 0x6427 # 0 +0xDDB6 0x640B # 0 +0xDDB7 0x63E7 # 0 +0xDDB8 0x641B # 0 +0xDDB9 0x642E # 0 +0xDDBA 0x6421 # 0 +0xDDBB 0x640E # 0 +0xDDBC 0x656F # 0 +0xDDBD 0x6592 # 0 +0xDDBE 0x65D3 # 0 +0xDDBF 0x6686 # 0 +0xDDC0 0x668C # 0 +0xDDC1 0x6695 # 0 +0xDDC2 0x6690 # 0 +0xDDC3 0x668B # 0 +0xDDC4 0x668A # 0 +0xDDC5 0x6699 # 0 +0xDDC6 0x6694 # 0 +0xDDC7 0x6678 # 0 +0xDDC8 0x6720 # 0 +0xDDC9 0x6966 # 0 +0xDDCA 0x695F # 0 +0xDDCB 0x6938 # 0 +0xDDCC 0x694E # 0 +0xDDCD 0x6962 # 0 +0xDDCE 0x6971 # 0 +0xDDCF 0x693F # 0 +0xDDD0 0x6945 # 0 +0xDDD1 0x696A # 0 +0xDDD2 0x6939 # 0 +0xDDD3 0x6942 # 0 +0xDDD4 0x6957 # 0 +0xDDD5 0x6959 # 0 +0xDDD6 0x697A # 0 +0xDDD7 0x6948 # 0 +0xDDD8 0x6949 # 0 +0xDDD9 0x6935 # 0 +0xDDDA 0x696C # 0 +0xDDDB 0x6933 # 0 +0xDDDC 0x693D # 0 +0xDDDD 0x6965 # 0 +0xDDDE 0x68F0 # 0 +0xDDDF 0x6978 # 0 +0xDDE0 0x6934 # 0 +0xDDE1 0x6969 # 0 +0xDDE2 0x6940 # 0 +0xDDE3 0x696F # 0 +0xDDE4 0x6944 # 0 +0xDDE5 0x6976 # 0 +0xDDE6 0x6958 # 0 +0xDDE7 0x6941 # 0 +0xDDE8 0x6974 # 0 +0xDDE9 0x694C # 0 +0xDDEA 0x693B # 0 +0xDDEB 0x694B # 0 +0xDDEC 0x6937 # 0 +0xDDED 0x695C # 0 +0xDDEE 0x694F # 0 +0xDDEF 0x6951 # 0 +0xDDF0 0x6932 # 0 +0xDDF1 0x6952 # 0 +0xDDF2 0x692F # 0 +0xDDF3 0x697B # 0 +0xDDF4 0x693C # 0 +0xDDF5 0x6B46 # 0 +0xDDF6 0x6B45 # 0 +0xDDF7 0x6B43 # 0 +0xDDF8 0x6B42 # 0 +0xDDF9 0x6B48 # 0 +0xDDFA 0x6B41 # 0 +0xDDFB 0x6B9B # 0 +0xDDFC 0xFA0D # 0 +0xDDFD 0x6BFB # 0 +0xDDFE 0x6BFC # 0 +0xDE40 0x6BF9 # 0 +0xDE41 0x6BF7 # 0 +0xDE42 0x6BF8 # 0 +0xDE43 0x6E9B # 0 +0xDE44 0x6ED6 # 0 +0xDE45 0x6EC8 # 0 +0xDE46 0x6E8F # 0 +0xDE47 0x6EC0 # 0 +0xDE48 0x6E9F # 0 +0xDE49 0x6E93 # 0 +0xDE4A 0x6E94 # 0 +0xDE4B 0x6EA0 # 0 +0xDE4C 0x6EB1 # 0 +0xDE4D 0x6EB9 # 0 +0xDE4E 0x6EC6 # 0 +0xDE4F 0x6ED2 # 0 +0xDE50 0x6EBD # 0 +0xDE51 0x6EC1 # 0 +0xDE52 0x6E9E # 0 +0xDE53 0x6EC9 # 0 +0xDE54 0x6EB7 # 0 +0xDE55 0x6EB0 # 0 +0xDE56 0x6ECD # 0 +0xDE57 0x6EA6 # 0 +0xDE58 0x6ECF # 0 +0xDE59 0x6EB2 # 0 +0xDE5A 0x6EBE # 0 +0xDE5B 0x6EC3 # 0 +0xDE5C 0x6EDC # 0 +0xDE5D 0x6ED8 # 0 +0xDE5E 0x6E99 # 0 +0xDE5F 0x6E92 # 0 +0xDE60 0x6E8E # 0 +0xDE61 0x6E8D # 0 +0xDE62 0x6EA4 # 0 +0xDE63 0x6EA1 # 0 +0xDE64 0x6EBF # 0 +0xDE65 0x6EB3 # 0 +0xDE66 0x6ED0 # 0 +0xDE67 0x6ECA # 0 +0xDE68 0x6E97 # 0 +0xDE69 0x6EAE # 0 +0xDE6A 0x6EA3 # 0 +0xDE6B 0x7147 # 0 +0xDE6C 0x7154 # 0 +0xDE6D 0x7152 # 0 +0xDE6E 0x7163 # 0 +0xDE6F 0x7160 # 0 +0xDE70 0x7141 # 0 +0xDE71 0x715D # 0 +0xDE72 0x7162 # 0 +0xDE73 0x7172 # 0 +0xDE74 0x7178 # 0 +0xDE75 0x716A # 0 +0xDE76 0x7161 # 0 +0xDE77 0x7142 # 0 +0xDE78 0x7158 # 0 +0xDE79 0x7143 # 0 +0xDE7A 0x714B # 0 +0xDE7B 0x7170 # 0 +0xDE7C 0x715F # 0 +0xDE7D 0x7150 # 0 +0xDE7E 0x7153 # 0 +0xDEA1 0x7144 # 0 +0xDEA2 0x714D # 0 +0xDEA3 0x715A # 0 +0xDEA4 0x724F # 0 +0xDEA5 0x728D # 0 +0xDEA6 0x728C # 0 +0xDEA7 0x7291 # 0 +0xDEA8 0x7290 # 0 +0xDEA9 0x728E # 0 +0xDEAA 0x733C # 0 +0xDEAB 0x7342 # 0 +0xDEAC 0x733B # 0 +0xDEAD 0x733A # 0 +0xDEAE 0x7340 # 0 +0xDEAF 0x734A # 0 +0xDEB0 0x7349 # 0 +0xDEB1 0x7444 # 0 +0xDEB2 0x744A # 0 +0xDEB3 0x744B # 0 +0xDEB4 0x7452 # 0 +0xDEB5 0x7451 # 0 +0xDEB6 0x7457 # 0 +0xDEB7 0x7440 # 0 +0xDEB8 0x744F # 0 +0xDEB9 0x7450 # 0 +0xDEBA 0x744E # 0 +0xDEBB 0x7442 # 0 +0xDEBC 0x7446 # 0 +0xDEBD 0x744D # 0 +0xDEBE 0x7454 # 0 +0xDEBF 0x74E1 # 0 +0xDEC0 0x74FF # 0 +0xDEC1 0x74FE # 0 +0xDEC2 0x74FD # 0 +0xDEC3 0x751D # 0 +0xDEC4 0x7579 # 0 +0xDEC5 0x7577 # 0 +0xDEC6 0x6983 # 0 +0xDEC7 0x75EF # 0 +0xDEC8 0x760F # 0 +0xDEC9 0x7603 # 0 +0xDECA 0x75F7 # 0 +0xDECB 0x75FE # 0 +0xDECC 0x75FC # 0 +0xDECD 0x75F9 # 0 +0xDECE 0x75F8 # 0 +0xDECF 0x7610 # 0 +0xDED0 0x75FB # 0 +0xDED1 0x75F6 # 0 +0xDED2 0x75ED # 0 +0xDED3 0x75F5 # 0 +0xDED4 0x75FD # 0 +0xDED5 0x7699 # 0 +0xDED6 0x76B5 # 0 +0xDED7 0x76DD # 0 +0xDED8 0x7755 # 0 +0xDED9 0x775F # 0 +0xDEDA 0x7760 # 0 +0xDEDB 0x7752 # 0 +0xDEDC 0x7756 # 0 +0xDEDD 0x775A # 0 +0xDEDE 0x7769 # 0 +0xDEDF 0x7767 # 0 +0xDEE0 0x7754 # 0 +0xDEE1 0x7759 # 0 +0xDEE2 0x776D # 0 +0xDEE3 0x77E0 # 0 +0xDEE4 0x7887 # 0 +0xDEE5 0x789A # 0 +0xDEE6 0x7894 # 0 +0xDEE7 0x788F # 0 +0xDEE8 0x7884 # 0 +0xDEE9 0x7895 # 0 +0xDEEA 0x7885 # 0 +0xDEEB 0x7886 # 0 +0xDEEC 0x78A1 # 0 +0xDEED 0x7883 # 0 +0xDEEE 0x7879 # 0 +0xDEEF 0x7899 # 0 +0xDEF0 0x7880 # 0 +0xDEF1 0x7896 # 0 +0xDEF2 0x787B # 0 +0xDEF3 0x797C # 0 +0xDEF4 0x7982 # 0 +0xDEF5 0x797D # 0 +0xDEF6 0x7979 # 0 +0xDEF7 0x7A11 # 0 +0xDEF8 0x7A18 # 0 +0xDEF9 0x7A19 # 0 +0xDEFA 0x7A12 # 0 +0xDEFB 0x7A17 # 0 +0xDEFC 0x7A15 # 0 +0xDEFD 0x7A22 # 0 +0xDEFE 0x7A13 # 0 +0xDF40 0x7A1B # 0 +0xDF41 0x7A10 # 0 +0xDF42 0x7AA3 # 0 +0xDF43 0x7AA2 # 0 +0xDF44 0x7A9E # 0 +0xDF45 0x7AEB # 0 +0xDF46 0x7B66 # 0 +0xDF47 0x7B64 # 0 +0xDF48 0x7B6D # 0 +0xDF49 0x7B74 # 0 +0xDF4A 0x7B69 # 0 +0xDF4B 0x7B72 # 0 +0xDF4C 0x7B65 # 0 +0xDF4D 0x7B73 # 0 +0xDF4E 0x7B71 # 0 +0xDF4F 0x7B70 # 0 +0xDF50 0x7B61 # 0 +0xDF51 0x7B78 # 0 +0xDF52 0x7B76 # 0 +0xDF53 0x7B63 # 0 +0xDF54 0x7CB2 # 0 +0xDF55 0x7CB4 # 0 +0xDF56 0x7CAF # 0 +0xDF57 0x7D88 # 0 +0xDF58 0x7D86 # 0 +0xDF59 0x7D80 # 0 +0xDF5A 0x7D8D # 0 +0xDF5B 0x7D7F # 0 +0xDF5C 0x7D85 # 0 +0xDF5D 0x7D7A # 0 +0xDF5E 0x7D8E # 0 +0xDF5F 0x7D7B # 0 +0xDF60 0x7D83 # 0 +0xDF61 0x7D7C # 0 +0xDF62 0x7D8C # 0 +0xDF63 0x7D94 # 0 +0xDF64 0x7D84 # 0 +0xDF65 0x7D7D # 0 +0xDF66 0x7D92 # 0 +0xDF67 0x7F6D # 0 +0xDF68 0x7F6B # 0 +0xDF69 0x7F67 # 0 +0xDF6A 0x7F68 # 0 +0xDF6B 0x7F6C # 0 +0xDF6C 0x7FA6 # 0 +0xDF6D 0x7FA5 # 0 +0xDF6E 0x7FA7 # 0 +0xDF6F 0x7FDB # 0 +0xDF70 0x7FDC # 0 +0xDF71 0x8021 # 0 +0xDF72 0x8164 # 0 +0xDF73 0x8160 # 0 +0xDF74 0x8177 # 0 +0xDF75 0x815C # 0 +0xDF76 0x8169 # 0 +0xDF77 0x815B # 0 +0xDF78 0x8162 # 0 +0xDF79 0x8172 # 0 +0xDF7A 0x6721 # 0 +0xDF7B 0x815E # 0 +0xDF7C 0x8176 # 0 +0xDF7D 0x8167 # 0 +0xDF7E 0x816F # 0 +0xDFA1 0x8144 # 0 +0xDFA2 0x8161 # 0 +0xDFA3 0x821D # 0 +0xDFA4 0x8249 # 0 +0xDFA5 0x8244 # 0 +0xDFA6 0x8240 # 0 +0xDFA7 0x8242 # 0 +0xDFA8 0x8245 # 0 +0xDFA9 0x84F1 # 0 +0xDFAA 0x843F # 0 +0xDFAB 0x8456 # 0 +0xDFAC 0x8476 # 0 +0xDFAD 0x8479 # 0 +0xDFAE 0x848F # 0 +0xDFAF 0x848D # 0 +0xDFB0 0x8465 # 0 +0xDFB1 0x8451 # 0 +0xDFB2 0x8440 # 0 +0xDFB3 0x8486 # 0 +0xDFB4 0x8467 # 0 +0xDFB5 0x8430 # 0 +0xDFB6 0x844D # 0 +0xDFB7 0x847D # 0 +0xDFB8 0x845A # 0 +0xDFB9 0x8459 # 0 +0xDFBA 0x8474 # 0 +0xDFBB 0x8473 # 0 +0xDFBC 0x845D # 0 +0xDFBD 0x8507 # 0 +0xDFBE 0x845E # 0 +0xDFBF 0x8437 # 0 +0xDFC0 0x843A # 0 +0xDFC1 0x8434 # 0 +0xDFC2 0x847A # 0 +0xDFC3 0x8443 # 0 +0xDFC4 0x8478 # 0 +0xDFC5 0x8432 # 0 +0xDFC6 0x8445 # 0 +0xDFC7 0x8429 # 0 +0xDFC8 0x83D9 # 0 +0xDFC9 0x844B # 0 +0xDFCA 0x842F # 0 +0xDFCB 0x8442 # 0 +0xDFCC 0x842D # 0 +0xDFCD 0x845F # 0 +0xDFCE 0x8470 # 0 +0xDFCF 0x8439 # 0 +0xDFD0 0x844E # 0 +0xDFD1 0x844C # 0 +0xDFD2 0x8452 # 0 +0xDFD3 0x846F # 0 +0xDFD4 0x84C5 # 0 +0xDFD5 0x848E # 0 +0xDFD6 0x843B # 0 +0xDFD7 0x8447 # 0 +0xDFD8 0x8436 # 0 +0xDFD9 0x8433 # 0 +0xDFDA 0x8468 # 0 +0xDFDB 0x847E # 0 +0xDFDC 0x8444 # 0 +0xDFDD 0x842B # 0 +0xDFDE 0x8460 # 0 +0xDFDF 0x8454 # 0 +0xDFE0 0x846E # 0 +0xDFE1 0x8450 # 0 +0xDFE2 0x870B # 0 +0xDFE3 0x8704 # 0 +0xDFE4 0x86F7 # 0 +0xDFE5 0x870C # 0 +0xDFE6 0x86FA # 0 +0xDFE7 0x86D6 # 0 +0xDFE8 0x86F5 # 0 +0xDFE9 0x874D # 0 +0xDFEA 0x86F8 # 0 +0xDFEB 0x870E # 0 +0xDFEC 0x8709 # 0 +0xDFED 0x8701 # 0 +0xDFEE 0x86F6 # 0 +0xDFEF 0x870D # 0 +0xDFF0 0x8705 # 0 +0xDFF1 0x88D6 # 0 +0xDFF2 0x88CB # 0 +0xDFF3 0x88CD # 0 +0xDFF4 0x88CE # 0 +0xDFF5 0x88DE # 0 +0xDFF6 0x88DB # 0 +0xDFF7 0x88DA # 0 +0xDFF8 0x88CC # 0 +0xDFF9 0x88D0 # 0 +0xDFFA 0x8985 # 0 +0xDFFB 0x899B # 0 +0xDFFC 0x89DF # 0 +0xDFFD 0x89E5 # 0 +0xDFFE 0x89E4 # 0 +0xE040 0x89E1 # 0 +0xE041 0x89E0 # 0 +0xE042 0x89E2 # 0 +0xE043 0x89DC # 0 +0xE044 0x89E6 # 0 +0xE045 0x8A76 # 0 +0xE046 0x8A86 # 0 +0xE047 0x8A7F # 0 +0xE048 0x8A61 # 0 +0xE049 0x8A3F # 0 +0xE04A 0x8A77 # 0 +0xE04B 0x8A82 # 0 +0xE04C 0x8A84 # 0 +0xE04D 0x8A75 # 0 +0xE04E 0x8A83 # 0 +0xE04F 0x8A81 # 0 +0xE050 0x8A74 # 0 +0xE051 0x8A7A # 0 +0xE052 0x8C3C # 0 +0xE053 0x8C4B # 0 +0xE054 0x8C4A # 0 +0xE055 0x8C65 # 0 +0xE056 0x8C64 # 0 +0xE057 0x8C66 # 0 +0xE058 0x8C86 # 0 +0xE059 0x8C84 # 0 +0xE05A 0x8C85 # 0 +0xE05B 0x8CCC # 0 +0xE05C 0x8D68 # 0 +0xE05D 0x8D69 # 0 +0xE05E 0x8D91 # 0 +0xE05F 0x8D8C # 0 +0xE060 0x8D8E # 0 +0xE061 0x8D8F # 0 +0xE062 0x8D8D # 0 +0xE063 0x8D93 # 0 +0xE064 0x8D94 # 0 +0xE065 0x8D90 # 0 +0xE066 0x8D92 # 0 +0xE067 0x8DF0 # 0 +0xE068 0x8DE0 # 0 +0xE069 0x8DEC # 0 +0xE06A 0x8DF1 # 0 +0xE06B 0x8DEE # 0 +0xE06C 0x8DD0 # 0 +0xE06D 0x8DE9 # 0 +0xE06E 0x8DE3 # 0 +0xE06F 0x8DE2 # 0 +0xE070 0x8DE7 # 0 +0xE071 0x8DF2 # 0 +0xE072 0x8DEB # 0 +0xE073 0x8DF4 # 0 +0xE074 0x8F06 # 0 +0xE075 0x8EFF # 0 +0xE076 0x8F01 # 0 +0xE077 0x8F00 # 0 +0xE078 0x8F05 # 0 +0xE079 0x8F07 # 0 +0xE07A 0x8F08 # 0 +0xE07B 0x8F02 # 0 +0xE07C 0x8F0B # 0 +0xE07D 0x9052 # 0 +0xE07E 0x903F # 0 +0xE0A1 0x9044 # 0 +0xE0A2 0x9049 # 0 +0xE0A3 0x903D # 0 +0xE0A4 0x9110 # 0 +0xE0A5 0x910D # 0 +0xE0A6 0x910F # 0 +0xE0A7 0x9111 # 0 +0xE0A8 0x9116 # 0 +0xE0A9 0x9114 # 0 +0xE0AA 0x910B # 0 +0xE0AB 0x910E # 0 +0xE0AC 0x916E # 0 +0xE0AD 0x916F # 0 +0xE0AE 0x9248 # 0 +0xE0AF 0x9252 # 0 +0xE0B0 0x9230 # 0 +0xE0B1 0x923A # 0 +0xE0B2 0x9266 # 0 +0xE0B3 0x9233 # 0 +0xE0B4 0x9265 # 0 +0xE0B5 0x925E # 0 +0xE0B6 0x9283 # 0 +0xE0B7 0x922E # 0 +0xE0B8 0x924A # 0 +0xE0B9 0x9246 # 0 +0xE0BA 0x926D # 0 +0xE0BB 0x926C # 0 +0xE0BC 0x924F # 0 +0xE0BD 0x9260 # 0 +0xE0BE 0x9267 # 0 +0xE0BF 0x926F # 0 +0xE0C0 0x9236 # 0 +0xE0C1 0x9261 # 0 +0xE0C2 0x9270 # 0 +0xE0C3 0x9231 # 0 +0xE0C4 0x9254 # 0 +0xE0C5 0x9263 # 0 +0xE0C6 0x9250 # 0 +0xE0C7 0x9272 # 0 +0xE0C8 0x924E # 0 +0xE0C9 0x9253 # 0 +0xE0CA 0x924C # 0 +0xE0CB 0x9256 # 0 +0xE0CC 0x9232 # 0 +0xE0CD 0x959F # 0 +0xE0CE 0x959C # 0 +0xE0CF 0x959E # 0 +0xE0D0 0x959B # 0 +0xE0D1 0x9692 # 0 +0xE0D2 0x9693 # 0 +0xE0D3 0x9691 # 0 +0xE0D4 0x9697 # 0 +0xE0D5 0x96CE # 0 +0xE0D6 0x96FA # 0 +0xE0D7 0x96FD # 0 +0xE0D8 0x96F8 # 0 +0xE0D9 0x96F5 # 0 +0xE0DA 0x9773 # 0 +0xE0DB 0x9777 # 0 +0xE0DC 0x9778 # 0 +0xE0DD 0x9772 # 0 +0xE0DE 0x980F # 0 +0xE0DF 0x980D # 0 +0xE0E0 0x980E # 0 +0xE0E1 0x98AC # 0 +0xE0E2 0x98F6 # 0 +0xE0E3 0x98F9 # 0 +0xE0E4 0x99AF # 0 +0xE0E5 0x99B2 # 0 +0xE0E6 0x99B0 # 0 +0xE0E7 0x99B5 # 0 +0xE0E8 0x9AAD # 0 +0xE0E9 0x9AAB # 0 +0xE0EA 0x9B5B # 0 +0xE0EB 0x9CEA # 0 +0xE0EC 0x9CED # 0 +0xE0ED 0x9CE7 # 0 +0xE0EE 0x9E80 # 0 +0xE0EF 0x9EFD # 0 +0xE0F0 0x50E6 # 0 +0xE0F1 0x50D4 # 0 +0xE0F2 0x50D7 # 0 +0xE0F3 0x50E8 # 0 +0xE0F4 0x50F3 # 0 +0xE0F5 0x50DB # 0 +0xE0F6 0x50EA # 0 +0xE0F7 0x50DD # 0 +0xE0F8 0x50E4 # 0 +0xE0F9 0x50D3 # 0 +0xE0FA 0x50EC # 0 +0xE0FB 0x50F0 # 0 +0xE0FC 0x50EF # 0 +0xE0FD 0x50E3 # 0 +0xE0FE 0x50E0 # 0 +0xE140 0x51D8 # 0 +0xE141 0x5280 # 0 +0xE142 0x5281 # 0 +0xE143 0x52E9 # 0 +0xE144 0x52EB # 0 +0xE145 0x5330 # 0 +0xE146 0x53AC # 0 +0xE147 0x5627 # 0 +0xE148 0x5615 # 0 +0xE149 0x560C # 0 +0xE14A 0x5612 # 0 +0xE14B 0x55FC # 0 +0xE14C 0x560F # 0 +0xE14D 0x561C # 0 +0xE14E 0x5601 # 0 +0xE14F 0x5613 # 0 +0xE150 0x5602 # 0 +0xE151 0x55FA # 0 +0xE152 0x561D # 0 +0xE153 0x5604 # 0 +0xE154 0x55FF # 0 +0xE155 0x55F9 # 0 +0xE156 0x5889 # 0 +0xE157 0x587C # 0 +0xE158 0x5890 # 0 +0xE159 0x5898 # 0 +0xE15A 0x5886 # 0 +0xE15B 0x5881 # 0 +0xE15C 0x587F # 0 +0xE15D 0x5874 # 0 +0xE15E 0x588B # 0 +0xE15F 0x587A # 0 +0xE160 0x5887 # 0 +0xE161 0x5891 # 0 +0xE162 0x588E # 0 +0xE163 0x5876 # 0 +0xE164 0x5882 # 0 +0xE165 0x5888 # 0 +0xE166 0x587B # 0 +0xE167 0x5894 # 0 +0xE168 0x588F # 0 +0xE169 0x58FE # 0 +0xE16A 0x596B # 0 +0xE16B 0x5ADC # 0 +0xE16C 0x5AEE # 0 +0xE16D 0x5AE5 # 0 +0xE16E 0x5AD5 # 0 +0xE16F 0x5AEA # 0 +0xE170 0x5ADA # 0 +0xE171 0x5AED # 0 +0xE172 0x5AEB # 0 +0xE173 0x5AF3 # 0 +0xE174 0x5AE2 # 0 +0xE175 0x5AE0 # 0 +0xE176 0x5ADB # 0 +0xE177 0x5AEC # 0 +0xE178 0x5ADE # 0 +0xE179 0x5ADD # 0 +0xE17A 0x5AD9 # 0 +0xE17B 0x5AE8 # 0 +0xE17C 0x5ADF # 0 +0xE17D 0x5B77 # 0 +0xE17E 0x5BE0 # 0 +0xE1A1 0x5BE3 # 0 +0xE1A2 0x5C63 # 0 +0xE1A3 0x5D82 # 0 +0xE1A4 0x5D80 # 0 +0xE1A5 0x5D7D # 0 +0xE1A6 0x5D86 # 0 +0xE1A7 0x5D7A # 0 +0xE1A8 0x5D81 # 0 +0xE1A9 0x5D77 # 0 +0xE1AA 0x5D8A # 0 +0xE1AB 0x5D89 # 0 +0xE1AC 0x5D88 # 0 +0xE1AD 0x5D7E # 0 +0xE1AE 0x5D7C # 0 +0xE1AF 0x5D8D # 0 +0xE1B0 0x5D79 # 0 +0xE1B1 0x5D7F # 0 +0xE1B2 0x5E58 # 0 +0xE1B3 0x5E59 # 0 +0xE1B4 0x5E53 # 0 +0xE1B5 0x5ED8 # 0 +0xE1B6 0x5ED1 # 0 +0xE1B7 0x5ED7 # 0 +0xE1B8 0x5ECE # 0 +0xE1B9 0x5EDC # 0 +0xE1BA 0x5ED5 # 0 +0xE1BB 0x5ED9 # 0 +0xE1BC 0x5ED2 # 0 +0xE1BD 0x5ED4 # 0 +0xE1BE 0x5F44 # 0 +0xE1BF 0x5F43 # 0 +0xE1C0 0x5F6F # 0 +0xE1C1 0x5FB6 # 0 +0xE1C2 0x612C # 0 +0xE1C3 0x6128 # 0 +0xE1C4 0x6141 # 0 +0xE1C5 0x615E # 0 +0xE1C6 0x6171 # 0 +0xE1C7 0x6173 # 0 +0xE1C8 0x6152 # 0 +0xE1C9 0x6153 # 0 +0xE1CA 0x6172 # 0 +0xE1CB 0x616C # 0 +0xE1CC 0x6180 # 0 +0xE1CD 0x6174 # 0 +0xE1CE 0x6154 # 0 +0xE1CF 0x617A # 0 +0xE1D0 0x615B # 0 +0xE1D1 0x6165 # 0 +0xE1D2 0x613B # 0 +0xE1D3 0x616A # 0 +0xE1D4 0x6161 # 0 +0xE1D5 0x6156 # 0 +0xE1D6 0x6229 # 0 +0xE1D7 0x6227 # 0 +0xE1D8 0x622B # 0 +0xE1D9 0x642B # 0 +0xE1DA 0x644D # 0 +0xE1DB 0x645B # 0 +0xE1DC 0x645D # 0 +0xE1DD 0x6474 # 0 +0xE1DE 0x6476 # 0 +0xE1DF 0x6472 # 0 +0xE1E0 0x6473 # 0 +0xE1E1 0x647D # 0 +0xE1E2 0x6475 # 0 +0xE1E3 0x6466 # 0 +0xE1E4 0x64A6 # 0 +0xE1E5 0x644E # 0 +0xE1E6 0x6482 # 0 +0xE1E7 0x645E # 0 +0xE1E8 0x645C # 0 +0xE1E9 0x644B # 0 +0xE1EA 0x6453 # 0 +0xE1EB 0x6460 # 0 +0xE1EC 0x6450 # 0 +0xE1ED 0x647F # 0 +0xE1EE 0x643F # 0 +0xE1EF 0x646C # 0 +0xE1F0 0x646B # 0 +0xE1F1 0x6459 # 0 +0xE1F2 0x6465 # 0 +0xE1F3 0x6477 # 0 +0xE1F4 0x6573 # 0 +0xE1F5 0x65A0 # 0 +0xE1F6 0x66A1 # 0 +0xE1F7 0x66A0 # 0 +0xE1F8 0x669F # 0 +0xE1F9 0x6705 # 0 +0xE1FA 0x6704 # 0 +0xE1FB 0x6722 # 0 +0xE1FC 0x69B1 # 0 +0xE1FD 0x69B6 # 0 +0xE1FE 0x69C9 # 0 +0xE240 0x69A0 # 0 +0xE241 0x69CE # 0 +0xE242 0x6996 # 0 +0xE243 0x69B0 # 0 +0xE244 0x69AC # 0 +0xE245 0x69BC # 0 +0xE246 0x6991 # 0 +0xE247 0x6999 # 0 +0xE248 0x698E # 0 +0xE249 0x69A7 # 0 +0xE24A 0x698D # 0 +0xE24B 0x69A9 # 0 +0xE24C 0x69BE # 0 +0xE24D 0x69AF # 0 +0xE24E 0x69BF # 0 +0xE24F 0x69C4 # 0 +0xE250 0x69BD # 0 +0xE251 0x69A4 # 0 +0xE252 0x69D4 # 0 +0xE253 0x69B9 # 0 +0xE254 0x69CA # 0 +0xE255 0x699A # 0 +0xE256 0x69CF # 0 +0xE257 0x69B3 # 0 +0xE258 0x6993 # 0 +0xE259 0x69AA # 0 +0xE25A 0x69A1 # 0 +0xE25B 0x699E # 0 +0xE25C 0x69D9 # 0 +0xE25D 0x6997 # 0 +0xE25E 0x6990 # 0 +0xE25F 0x69C2 # 0 +0xE260 0x69B5 # 0 +0xE261 0x69A5 # 0 +0xE262 0x69C6 # 0 +0xE263 0x6B4A # 0 +0xE264 0x6B4D # 0 +0xE265 0x6B4B # 0 +0xE266 0x6B9E # 0 +0xE267 0x6B9F # 0 +0xE268 0x6BA0 # 0 +0xE269 0x6BC3 # 0 +0xE26A 0x6BC4 # 0 +0xE26B 0x6BFE # 0 +0xE26C 0x6ECE # 0 +0xE26D 0x6EF5 # 0 +0xE26E 0x6EF1 # 0 +0xE26F 0x6F03 # 0 +0xE270 0x6F25 # 0 +0xE271 0x6EF8 # 0 +0xE272 0x6F37 # 0 +0xE273 0x6EFB # 0 +0xE274 0x6F2E # 0 +0xE275 0x6F09 # 0 +0xE276 0x6F4E # 0 +0xE277 0x6F19 # 0 +0xE278 0x6F1A # 0 +0xE279 0x6F27 # 0 +0xE27A 0x6F18 # 0 +0xE27B 0x6F3B # 0 +0xE27C 0x6F12 # 0 +0xE27D 0x6EED # 0 +0xE27E 0x6F0A # 0 +0xE2A1 0x6F36 # 0 +0xE2A2 0x6F73 # 0 +0xE2A3 0x6EF9 # 0 +0xE2A4 0x6EEE # 0 +0xE2A5 0x6F2D # 0 +0xE2A6 0x6F40 # 0 +0xE2A7 0x6F30 # 0 +0xE2A8 0x6F3C # 0 +0xE2A9 0x6F35 # 0 +0xE2AA 0x6EEB # 0 +0xE2AB 0x6F07 # 0 +0xE2AC 0x6F0E # 0 +0xE2AD 0x6F43 # 0 +0xE2AE 0x6F05 # 0 +0xE2AF 0x6EFD # 0 +0xE2B0 0x6EF6 # 0 +0xE2B1 0x6F39 # 0 +0xE2B2 0x6F1C # 0 +0xE2B3 0x6EFC # 0 +0xE2B4 0x6F3A # 0 +0xE2B5 0x6F1F # 0 +0xE2B6 0x6F0D # 0 +0xE2B7 0x6F1E # 0 +0xE2B8 0x6F08 # 0 +0xE2B9 0x6F21 # 0 +0xE2BA 0x7187 # 0 +0xE2BB 0x7190 # 0 +0xE2BC 0x7189 # 0 +0xE2BD 0x7180 # 0 +0xE2BE 0x7185 # 0 +0xE2BF 0x7182 # 0 +0xE2C0 0x718F # 0 +0xE2C1 0x717B # 0 +0xE2C2 0x7186 # 0 +0xE2C3 0x7181 # 0 +0xE2C4 0x7197 # 0 +0xE2C5 0x7244 # 0 +0xE2C6 0x7253 # 0 +0xE2C7 0x7297 # 0 +0xE2C8 0x7295 # 0 +0xE2C9 0x7293 # 0 +0xE2CA 0x7343 # 0 +0xE2CB 0x734D # 0 +0xE2CC 0x7351 # 0 +0xE2CD 0x734C # 0 +0xE2CE 0x7462 # 0 +0xE2CF 0x7473 # 0 +0xE2D0 0x7471 # 0 +0xE2D1 0x7475 # 0 +0xE2D2 0x7472 # 0 +0xE2D3 0x7467 # 0 +0xE2D4 0x746E # 0 +0xE2D5 0x7500 # 0 +0xE2D6 0x7502 # 0 +0xE2D7 0x7503 # 0 +0xE2D8 0x757D # 0 +0xE2D9 0x7590 # 0 +0xE2DA 0x7616 # 0 +0xE2DB 0x7608 # 0 +0xE2DC 0x760C # 0 +0xE2DD 0x7615 # 0 +0xE2DE 0x7611 # 0 +0xE2DF 0x760A # 0 +0xE2E0 0x7614 # 0 +0xE2E1 0x76B8 # 0 +0xE2E2 0x7781 # 0 +0xE2E3 0x777C # 0 +0xE2E4 0x7785 # 0 +0xE2E5 0x7782 # 0 +0xE2E6 0x776E # 0 +0xE2E7 0x7780 # 0 +0xE2E8 0x776F # 0 +0xE2E9 0x777E # 0 +0xE2EA 0x7783 # 0 +0xE2EB 0x78B2 # 0 +0xE2EC 0x78AA # 0 +0xE2ED 0x78B4 # 0 +0xE2EE 0x78AD # 0 +0xE2EF 0x78A8 # 0 +0xE2F0 0x787E # 0 +0xE2F1 0x78AB # 0 +0xE2F2 0x789E # 0 +0xE2F3 0x78A5 # 0 +0xE2F4 0x78A0 # 0 +0xE2F5 0x78AC # 0 +0xE2F6 0x78A2 # 0 +0xE2F7 0x78A4 # 0 +0xE2F8 0x7998 # 0 +0xE2F9 0x798A # 0 +0xE2FA 0x798B # 0 +0xE2FB 0x7996 # 0 +0xE2FC 0x7995 # 0 +0xE2FD 0x7994 # 0 +0xE2FE 0x7993 # 0 +0xE340 0x7997 # 0 +0xE341 0x7988 # 0 +0xE342 0x7992 # 0 +0xE343 0x7990 # 0 +0xE344 0x7A2B # 0 +0xE345 0x7A4A # 0 +0xE346 0x7A30 # 0 +0xE347 0x7A2F # 0 +0xE348 0x7A28 # 0 +0xE349 0x7A26 # 0 +0xE34A 0x7AA8 # 0 +0xE34B 0x7AAB # 0 +0xE34C 0x7AAC # 0 +0xE34D 0x7AEE # 0 +0xE34E 0x7B88 # 0 +0xE34F 0x7B9C # 0 +0xE350 0x7B8A # 0 +0xE351 0x7B91 # 0 +0xE352 0x7B90 # 0 +0xE353 0x7B96 # 0 +0xE354 0x7B8D # 0 +0xE355 0x7B8C # 0 +0xE356 0x7B9B # 0 +0xE357 0x7B8E # 0 +0xE358 0x7B85 # 0 +0xE359 0x7B98 # 0 +0xE35A 0x5284 # 0 +0xE35B 0x7B99 # 0 +0xE35C 0x7BA4 # 0 +0xE35D 0x7B82 # 0 +0xE35E 0x7CBB # 0 +0xE35F 0x7CBF # 0 +0xE360 0x7CBC # 0 +0xE361 0x7CBA # 0 +0xE362 0x7DA7 # 0 +0xE363 0x7DB7 # 0 +0xE364 0x7DC2 # 0 +0xE365 0x7DA3 # 0 +0xE366 0x7DAA # 0 +0xE367 0x7DC1 # 0 +0xE368 0x7DC0 # 0 +0xE369 0x7DC5 # 0 +0xE36A 0x7D9D # 0 +0xE36B 0x7DCE # 0 +0xE36C 0x7DC4 # 0 +0xE36D 0x7DC6 # 0 +0xE36E 0x7DCB # 0 +0xE36F 0x7DCC # 0 +0xE370 0x7DAF # 0 +0xE371 0x7DB9 # 0 +0xE372 0x7D96 # 0 +0xE373 0x7DBC # 0 +0xE374 0x7D9F # 0 +0xE375 0x7DA6 # 0 +0xE376 0x7DAE # 0 +0xE377 0x7DA9 # 0 +0xE378 0x7DA1 # 0 +0xE379 0x7DC9 # 0 +0xE37A 0x7F73 # 0 +0xE37B 0x7FE2 # 0 +0xE37C 0x7FE3 # 0 +0xE37D 0x7FE5 # 0 +0xE37E 0x7FDE # 0 +0xE3A1 0x8024 # 0 +0xE3A2 0x805D # 0 +0xE3A3 0x805C # 0 +0xE3A4 0x8189 # 0 +0xE3A5 0x8186 # 0 +0xE3A6 0x8183 # 0 +0xE3A7 0x8187 # 0 +0xE3A8 0x818D # 0 +0xE3A9 0x818C # 0 +0xE3AA 0x818B # 0 +0xE3AB 0x8215 # 0 +0xE3AC 0x8497 # 0 +0xE3AD 0x84A4 # 0 +0xE3AE 0x84A1 # 0 +0xE3AF 0x849F # 0 +0xE3B0 0x84BA # 0 +0xE3B1 0x84CE # 0 +0xE3B2 0x84C2 # 0 +0xE3B3 0x84AC # 0 +0xE3B4 0x84AE # 0 +0xE3B5 0x84AB # 0 +0xE3B6 0x84B9 # 0 +0xE3B7 0x84B4 # 0 +0xE3B8 0x84C1 # 0 +0xE3B9 0x84CD # 0 +0xE3BA 0x84AA # 0 +0xE3BB 0x849A # 0 +0xE3BC 0x84B1 # 0 +0xE3BD 0x84D0 # 0 +0xE3BE 0x849D # 0 +0xE3BF 0x84A7 # 0 +0xE3C0 0x84BB # 0 +0xE3C1 0x84A2 # 0 +0xE3C2 0x8494 # 0 +0xE3C3 0x84C7 # 0 +0xE3C4 0x84CC # 0 +0xE3C5 0x849B # 0 +0xE3C6 0x84A9 # 0 +0xE3C7 0x84AF # 0 +0xE3C8 0x84A8 # 0 +0xE3C9 0x84D6 # 0 +0xE3CA 0x8498 # 0 +0xE3CB 0x84B6 # 0 +0xE3CC 0x84CF # 0 +0xE3CD 0x84A0 # 0 +0xE3CE 0x84D7 # 0 +0xE3CF 0x84D4 # 0 +0xE3D0 0x84D2 # 0 +0xE3D1 0x84DB # 0 +0xE3D2 0x84B0 # 0 +0xE3D3 0x8491 # 0 +0xE3D4 0x8661 # 0 +0xE3D5 0x8733 # 0 +0xE3D6 0x8723 # 0 +0xE3D7 0x8728 # 0 +0xE3D8 0x876B # 0 +0xE3D9 0x8740 # 0 +0xE3DA 0x872E # 0 +0xE3DB 0x871E # 0 +0xE3DC 0x8721 # 0 +0xE3DD 0x8719 # 0 +0xE3DE 0x871B # 0 +0xE3DF 0x8743 # 0 +0xE3E0 0x872C # 0 +0xE3E1 0x8741 # 0 +0xE3E2 0x873E # 0 +0xE3E3 0x8746 # 0 +0xE3E4 0x8720 # 0 +0xE3E5 0x8732 # 0 +0xE3E6 0x872A # 0 +0xE3E7 0x872D # 0 +0xE3E8 0x873C # 0 +0xE3E9 0x8712 # 0 +0xE3EA 0x873A # 0 +0xE3EB 0x8731 # 0 +0xE3EC 0x8735 # 0 +0xE3ED 0x8742 # 0 +0xE3EE 0x8726 # 0 +0xE3EF 0x8727 # 0 +0xE3F0 0x8738 # 0 +0xE3F1 0x8724 # 0 +0xE3F2 0x871A # 0 +0xE3F3 0x8730 # 0 +0xE3F4 0x8711 # 0 +0xE3F5 0x88F7 # 0 +0xE3F6 0x88E7 # 0 +0xE3F7 0x88F1 # 0 +0xE3F8 0x88F2 # 0 +0xE3F9 0x88FA # 0 +0xE3FA 0x88FE # 0 +0xE3FB 0x88EE # 0 +0xE3FC 0x88FC # 0 +0xE3FD 0x88F6 # 0 +0xE3FE 0x88FB # 0 +0xE440 0x88F0 # 0 +0xE441 0x88EC # 0 +0xE442 0x88EB # 0 +0xE443 0x899D # 0 +0xE444 0x89A1 # 0 +0xE445 0x899F # 0 +0xE446 0x899E # 0 +0xE447 0x89E9 # 0 +0xE448 0x89EB # 0 +0xE449 0x89E8 # 0 +0xE44A 0x8AAB # 0 +0xE44B 0x8A99 # 0 +0xE44C 0x8A8B # 0 +0xE44D 0x8A92 # 0 +0xE44E 0x8A8F # 0 +0xE44F 0x8A96 # 0 +0xE450 0x8C3D # 0 +0xE451 0x8C68 # 0 +0xE452 0x8C69 # 0 +0xE453 0x8CD5 # 0 +0xE454 0x8CCF # 0 +0xE455 0x8CD7 # 0 +0xE456 0x8D96 # 0 +0xE457 0x8E09 # 0 +0xE458 0x8E02 # 0 +0xE459 0x8DFF # 0 +0xE45A 0x8E0D # 0 +0xE45B 0x8DFD # 0 +0xE45C 0x8E0A # 0 +0xE45D 0x8E03 # 0 +0xE45E 0x8E07 # 0 +0xE45F 0x8E06 # 0 +0xE460 0x8E05 # 0 +0xE461 0x8DFE # 0 +0xE462 0x8E00 # 0 +0xE463 0x8E04 # 0 +0xE464 0x8F10 # 0 +0xE465 0x8F11 # 0 +0xE466 0x8F0E # 0 +0xE467 0x8F0D # 0 +0xE468 0x9123 # 0 +0xE469 0x911C # 0 +0xE46A 0x9120 # 0 +0xE46B 0x9122 # 0 +0xE46C 0x911F # 0 +0xE46D 0x911D # 0 +0xE46E 0x911A # 0 +0xE46F 0x9124 # 0 +0xE470 0x9121 # 0 +0xE471 0x911B # 0 +0xE472 0x917A # 0 +0xE473 0x9172 # 0 +0xE474 0x9179 # 0 +0xE475 0x9173 # 0 +0xE476 0x92A5 # 0 +0xE477 0x92A4 # 0 +0xE478 0x9276 # 0 +0xE479 0x929B # 0 +0xE47A 0x927A # 0 +0xE47B 0x92A0 # 0 +0xE47C 0x9294 # 0 +0xE47D 0x92AA # 0 +0xE47E 0x928D # 0 +0xE4A1 0x92A6 # 0 +0xE4A2 0x929A # 0 +0xE4A3 0x92AB # 0 +0xE4A4 0x9279 # 0 +0xE4A5 0x9297 # 0 +0xE4A6 0x927F # 0 +0xE4A7 0x92A3 # 0 +0xE4A8 0x92EE # 0 +0xE4A9 0x928E # 0 +0xE4AA 0x9282 # 0 +0xE4AB 0x9295 # 0 +0xE4AC 0x92A2 # 0 +0xE4AD 0x927D # 0 +0xE4AE 0x9288 # 0 +0xE4AF 0x92A1 # 0 +0xE4B0 0x928A # 0 +0xE4B1 0x9286 # 0 +0xE4B2 0x928C # 0 +0xE4B3 0x9299 # 0 +0xE4B4 0x92A7 # 0 +0xE4B5 0x927E # 0 +0xE4B6 0x9287 # 0 +0xE4B7 0x92A9 # 0 +0xE4B8 0x929D # 0 +0xE4B9 0x928B # 0 +0xE4BA 0x922D # 0 +0xE4BB 0x969E # 0 +0xE4BC 0x96A1 # 0 +0xE4BD 0x96FF # 0 +0xE4BE 0x9758 # 0 +0xE4BF 0x977D # 0 +0xE4C0 0x977A # 0 +0xE4C1 0x977E # 0 +0xE4C2 0x9783 # 0 +0xE4C3 0x9780 # 0 +0xE4C4 0x9782 # 0 +0xE4C5 0x977B # 0 +0xE4C6 0x9784 # 0 +0xE4C7 0x9781 # 0 +0xE4C8 0x977F # 0 +0xE4C9 0x97CE # 0 +0xE4CA 0x97CD # 0 +0xE4CB 0x9816 # 0 +0xE4CC 0x98AD # 0 +0xE4CD 0x98AE # 0 +0xE4CE 0x9902 # 0 +0xE4CF 0x9900 # 0 +0xE4D0 0x9907 # 0 +0xE4D1 0x999D # 0 +0xE4D2 0x999C # 0 +0xE4D3 0x99C3 # 0 +0xE4D4 0x99B9 # 0 +0xE4D5 0x99BB # 0 +0xE4D6 0x99BA # 0 +0xE4D7 0x99C2 # 0 +0xE4D8 0x99BD # 0 +0xE4D9 0x99C7 # 0 +0xE4DA 0x9AB1 # 0 +0xE4DB 0x9AE3 # 0 +0xE4DC 0x9AE7 # 0 +0xE4DD 0x9B3E # 0 +0xE4DE 0x9B3F # 0 +0xE4DF 0x9B60 # 0 +0xE4E0 0x9B61 # 0 +0xE4E1 0x9B5F # 0 +0xE4E2 0x9CF1 # 0 +0xE4E3 0x9CF2 # 0 +0xE4E4 0x9CF5 # 0 +0xE4E5 0x9EA7 # 0 +0xE4E6 0x50FF # 0 +0xE4E7 0x5103 # 0 +0xE4E8 0x5130 # 0 +0xE4E9 0x50F8 # 0 +0xE4EA 0x5106 # 0 +0xE4EB 0x5107 # 0 +0xE4EC 0x50F6 # 0 +0xE4ED 0x50FE # 0 +0xE4EE 0x510B # 0 +0xE4EF 0x510C # 0 +0xE4F0 0x50FD # 0 +0xE4F1 0x510A # 0 +0xE4F2 0x528B # 0 +0xE4F3 0x528C # 0 +0xE4F4 0x52F1 # 0 +0xE4F5 0x52EF # 0 +0xE4F6 0x5648 # 0 +0xE4F7 0x5642 # 0 +0xE4F8 0x564C # 0 +0xE4F9 0x5635 # 0 +0xE4FA 0x5641 # 0 +0xE4FB 0x564A # 0 +0xE4FC 0x5649 # 0 +0xE4FD 0x5646 # 0 +0xE4FE 0x5658 # 0 +0xE540 0x565A # 0 +0xE541 0x5640 # 0 +0xE542 0x5633 # 0 +0xE543 0x563D # 0 +0xE544 0x562C # 0 +0xE545 0x563E # 0 +0xE546 0x5638 # 0 +0xE547 0x562A # 0 +0xE548 0x563A # 0 +0xE549 0x571A # 0 +0xE54A 0x58AB # 0 +0xE54B 0x589D # 0 +0xE54C 0x58B1 # 0 +0xE54D 0x58A0 # 0 +0xE54E 0x58A3 # 0 +0xE54F 0x58AF # 0 +0xE550 0x58AC # 0 +0xE551 0x58A5 # 0 +0xE552 0x58A1 # 0 +0xE553 0x58FF # 0 +0xE554 0x5AFF # 0 +0xE555 0x5AF4 # 0 +0xE556 0x5AFD # 0 +0xE557 0x5AF7 # 0 +0xE558 0x5AF6 # 0 +0xE559 0x5B03 # 0 +0xE55A 0x5AF8 # 0 +0xE55B 0x5B02 # 0 +0xE55C 0x5AF9 # 0 +0xE55D 0x5B01 # 0 +0xE55E 0x5B07 # 0 +0xE55F 0x5B05 # 0 +0xE560 0x5B0F # 0 +0xE561 0x5C67 # 0 +0xE562 0x5D99 # 0 +0xE563 0x5D97 # 0 +0xE564 0x5D9F # 0 +0xE565 0x5D92 # 0 +0xE566 0x5DA2 # 0 +0xE567 0x5D93 # 0 +0xE568 0x5D95 # 0 +0xE569 0x5DA0 # 0 +0xE56A 0x5D9C # 0 +0xE56B 0x5DA1 # 0 +0xE56C 0x5D9A # 0 +0xE56D 0x5D9E # 0 +0xE56E 0x5E69 # 0 +0xE56F 0x5E5D # 0 +0xE570 0x5E60 # 0 +0xE571 0x5E5C # 0 +0xE572 0x7DF3 # 0 +0xE573 0x5EDB # 0 +0xE574 0x5EDE # 0 +0xE575 0x5EE1 # 0 +0xE576 0x5F49 # 0 +0xE577 0x5FB2 # 0 +0xE578 0x618B # 0 +0xE579 0x6183 # 0 +0xE57A 0x6179 # 0 +0xE57B 0x61B1 # 0 +0xE57C 0x61B0 # 0 +0xE57D 0x61A2 # 0 +0xE57E 0x6189 # 0 +0xE5A1 0x619B # 0 +0xE5A2 0x6193 # 0 +0xE5A3 0x61AF # 0 +0xE5A4 0x61AD # 0 +0xE5A5 0x619F # 0 +0xE5A6 0x6192 # 0 +0xE5A7 0x61AA # 0 +0xE5A8 0x61A1 # 0 +0xE5A9 0x618D # 0 +0xE5AA 0x6166 # 0 +0xE5AB 0x61B3 # 0 +0xE5AC 0x622D # 0 +0xE5AD 0x646E # 0 +0xE5AE 0x6470 # 0 +0xE5AF 0x6496 # 0 +0xE5B0 0x64A0 # 0 +0xE5B1 0x6485 # 0 +0xE5B2 0x6497 # 0 +0xE5B3 0x649C # 0 +0xE5B4 0x648F # 0 +0xE5B5 0x648B # 0 +0xE5B6 0x648A # 0 +0xE5B7 0x648C # 0 +0xE5B8 0x64A3 # 0 +0xE5B9 0x649F # 0 +0xE5BA 0x6468 # 0 +0xE5BB 0x64B1 # 0 +0xE5BC 0x6498 # 0 +0xE5BD 0x6576 # 0 +0xE5BE 0x657A # 0 +0xE5BF 0x6579 # 0 +0xE5C0 0x657B # 0 +0xE5C1 0x65B2 # 0 +0xE5C2 0x65B3 # 0 +0xE5C3 0x66B5 # 0 +0xE5C4 0x66B0 # 0 +0xE5C5 0x66A9 # 0 +0xE5C6 0x66B2 # 0 +0xE5C7 0x66B7 # 0 +0xE5C8 0x66AA # 0 +0xE5C9 0x66AF # 0 +0xE5CA 0x6A00 # 0 +0xE5CB 0x6A06 # 0 +0xE5CC 0x6A17 # 0 +0xE5CD 0x69E5 # 0 +0xE5CE 0x69F8 # 0 +0xE5CF 0x6A15 # 0 +0xE5D0 0x69F1 # 0 +0xE5D1 0x69E4 # 0 +0xE5D2 0x6A20 # 0 +0xE5D3 0x69FF # 0 +0xE5D4 0x69EC # 0 +0xE5D5 0x69E2 # 0 +0xE5D6 0x6A1B # 0 +0xE5D7 0x6A1D # 0 +0xE5D8 0x69FE # 0 +0xE5D9 0x6A27 # 0 +0xE5DA 0x69F2 # 0 +0xE5DB 0x69EE # 0 +0xE5DC 0x6A14 # 0 +0xE5DD 0x69F7 # 0 +0xE5DE 0x69E7 # 0 +0xE5DF 0x6A40 # 0 +0xE5E0 0x6A08 # 0 +0xE5E1 0x69E6 # 0 +0xE5E2 0x69FB # 0 +0xE5E3 0x6A0D # 0 +0xE5E4 0x69FC # 0 +0xE5E5 0x69EB # 0 +0xE5E6 0x6A09 # 0 +0xE5E7 0x6A04 # 0 +0xE5E8 0x6A18 # 0 +0xE5E9 0x6A25 # 0 +0xE5EA 0x6A0F # 0 +0xE5EB 0x69F6 # 0 +0xE5EC 0x6A26 # 0 +0xE5ED 0x6A07 # 0 +0xE5EE 0x69F4 # 0 +0xE5EF 0x6A16 # 0 +0xE5F0 0x6B51 # 0 +0xE5F1 0x6BA5 # 0 +0xE5F2 0x6BA3 # 0 +0xE5F3 0x6BA2 # 0 +0xE5F4 0x6BA6 # 0 +0xE5F5 0x6C01 # 0 +0xE5F6 0x6C00 # 0 +0xE5F7 0x6BFF # 0 +0xE5F8 0x6C02 # 0 +0xE5F9 0x6F41 # 0 +0xE5FA 0x6F26 # 0 +0xE5FB 0x6F7E # 0 +0xE5FC 0x6F87 # 0 +0xE5FD 0x6FC6 # 0 +0xE5FE 0x6F92 # 0 +0xE640 0x6F8D # 0 +0xE641 0x6F89 # 0 +0xE642 0x6F8C # 0 +0xE643 0x6F62 # 0 +0xE644 0x6F4F # 0 +0xE645 0x6F85 # 0 +0xE646 0x6F5A # 0 +0xE647 0x6F96 # 0 +0xE648 0x6F76 # 0 +0xE649 0x6F6C # 0 +0xE64A 0x6F82 # 0 +0xE64B 0x6F55 # 0 +0xE64C 0x6F72 # 0 +0xE64D 0x6F52 # 0 +0xE64E 0x6F50 # 0 +0xE64F 0x6F57 # 0 +0xE650 0x6F94 # 0 +0xE651 0x6F93 # 0 +0xE652 0x6F5D # 0 +0xE653 0x6F00 # 0 +0xE654 0x6F61 # 0 +0xE655 0x6F6B # 0 +0xE656 0x6F7D # 0 +0xE657 0x6F67 # 0 +0xE658 0x6F90 # 0 +0xE659 0x6F53 # 0 +0xE65A 0x6F8B # 0 +0xE65B 0x6F69 # 0 +0xE65C 0x6F7F # 0 +0xE65D 0x6F95 # 0 +0xE65E 0x6F63 # 0 +0xE65F 0x6F77 # 0 +0xE660 0x6F6A # 0 +0xE661 0x6F7B # 0 +0xE662 0x71B2 # 0 +0xE663 0x71AF # 0 +0xE664 0x719B # 0 +0xE665 0x71B0 # 0 +0xE666 0x71A0 # 0 +0xE667 0x719A # 0 +0xE668 0x71A9 # 0 +0xE669 0x71B5 # 0 +0xE66A 0x719D # 0 +0xE66B 0x71A5 # 0 +0xE66C 0x719E # 0 +0xE66D 0x71A4 # 0 +0xE66E 0x71A1 # 0 +0xE66F 0x71AA # 0 +0xE670 0x719C # 0 +0xE671 0x71A7 # 0 +0xE672 0x71B3 # 0 +0xE673 0x7298 # 0 +0xE674 0x729A # 0 +0xE675 0x7358 # 0 +0xE676 0x7352 # 0 +0xE677 0x735E # 0 +0xE678 0x735F # 0 +0xE679 0x7360 # 0 +0xE67A 0x735D # 0 +0xE67B 0x735B # 0 +0xE67C 0x7361 # 0 +0xE67D 0x735A # 0 +0xE67E 0x7359 # 0 +0xE6A1 0x7362 # 0 +0xE6A2 0x7487 # 0 +0xE6A3 0x7489 # 0 +0xE6A4 0x748A # 0 +0xE6A5 0x7486 # 0 +0xE6A6 0x7481 # 0 +0xE6A7 0x747D # 0 +0xE6A8 0x7485 # 0 +0xE6A9 0x7488 # 0 +0xE6AA 0x747C # 0 +0xE6AB 0x7479 # 0 +0xE6AC 0x7508 # 0 +0xE6AD 0x7507 # 0 +0xE6AE 0x757E # 0 +0xE6AF 0x7625 # 0 +0xE6B0 0x761E # 0 +0xE6B1 0x7619 # 0 +0xE6B2 0x761D # 0 +0xE6B3 0x761C # 0 +0xE6B4 0x7623 # 0 +0xE6B5 0x761A # 0 +0xE6B6 0x7628 # 0 +0xE6B7 0x761B # 0 +0xE6B8 0x769C # 0 +0xE6B9 0x769D # 0 +0xE6BA 0x769E # 0 +0xE6BB 0x769B # 0 +0xE6BC 0x778D # 0 +0xE6BD 0x778F # 0 +0xE6BE 0x7789 # 0 +0xE6BF 0x7788 # 0 +0xE6C0 0x78CD # 0 +0xE6C1 0x78BB # 0 +0xE6C2 0x78CF # 0 +0xE6C3 0x78CC # 0 +0xE6C4 0x78D1 # 0 +0xE6C5 0x78CE # 0 +0xE6C6 0x78D4 # 0 +0xE6C7 0x78C8 # 0 +0xE6C8 0x78C3 # 0 +0xE6C9 0x78C4 # 0 +0xE6CA 0x78C9 # 0 +0xE6CB 0x799A # 0 +0xE6CC 0x79A1 # 0 +0xE6CD 0x79A0 # 0 +0xE6CE 0x799C # 0 +0xE6CF 0x79A2 # 0 +0xE6D0 0x799B # 0 +0xE6D1 0x6B76 # 0 +0xE6D2 0x7A39 # 0 +0xE6D3 0x7AB2 # 0 +0xE6D4 0x7AB4 # 0 +0xE6D5 0x7AB3 # 0 +0xE6D6 0x7BB7 # 0 +0xE6D7 0x7BCB # 0 +0xE6D8 0x7BBE # 0 +0xE6D9 0x7BAC # 0 +0xE6DA 0x7BCE # 0 +0xE6DB 0x7BAF # 0 +0xE6DC 0x7BB9 # 0 +0xE6DD 0x7BCA # 0 +0xE6DE 0x7BB5 # 0 +0xE6DF 0x7CC5 # 0 +0xE6E0 0x7CC8 # 0 +0xE6E1 0x7CCC # 0 +0xE6E2 0x7CCB # 0 +0xE6E3 0x7DF7 # 0 +0xE6E4 0x7DDB # 0 +0xE6E5 0x7DEA # 0 +0xE6E6 0x7DE7 # 0 +0xE6E7 0x7DD7 # 0 +0xE6E8 0x7DE1 # 0 +0xE6E9 0x7E03 # 0 +0xE6EA 0x7DFA # 0 +0xE6EB 0x7DE6 # 0 +0xE6EC 0x7DF6 # 0 +0xE6ED 0x7DF1 # 0 +0xE6EE 0x7DF0 # 0 +0xE6EF 0x7DEE # 0 +0xE6F0 0x7DDF # 0 +0xE6F1 0x7F76 # 0 +0xE6F2 0x7FAC # 0 +0xE6F3 0x7FB0 # 0 +0xE6F4 0x7FAD # 0 +0xE6F5 0x7FED # 0 +0xE6F6 0x7FEB # 0 +0xE6F7 0x7FEA # 0 +0xE6F8 0x7FEC # 0 +0xE6F9 0x7FE6 # 0 +0xE6FA 0x7FE8 # 0 +0xE6FB 0x8064 # 0 +0xE6FC 0x8067 # 0 +0xE6FD 0x81A3 # 0 +0xE6FE 0x819F # 0 +0xE740 0x819E # 0 +0xE741 0x8195 # 0 +0xE742 0x81A2 # 0 +0xE743 0x8199 # 0 +0xE744 0x8197 # 0 +0xE745 0x8216 # 0 +0xE746 0x824F # 0 +0xE747 0x8253 # 0 +0xE748 0x8252 # 0 +0xE749 0x8250 # 0 +0xE74A 0x824E # 0 +0xE74B 0x8251 # 0 +0xE74C 0x8524 # 0 +0xE74D 0x853B # 0 +0xE74E 0x850F # 0 +0xE74F 0x8500 # 0 +0xE750 0x8529 # 0 +0xE751 0x850E # 0 +0xE752 0x8509 # 0 +0xE753 0x850D # 0 +0xE754 0x851F # 0 +0xE755 0x850A # 0 +0xE756 0x8527 # 0 +0xE757 0x851C # 0 +0xE758 0x84FB # 0 +0xE759 0x852B # 0 +0xE75A 0x84FA # 0 +0xE75B 0x8508 # 0 +0xE75C 0x850C # 0 +0xE75D 0x84F4 # 0 +0xE75E 0x852A # 0 +0xE75F 0x84F2 # 0 +0xE760 0x8515 # 0 +0xE761 0x84F7 # 0 +0xE762 0x84EB # 0 +0xE763 0x84F3 # 0 +0xE764 0x84FC # 0 +0xE765 0x8512 # 0 +0xE766 0x84EA # 0 +0xE767 0x84E9 # 0 +0xE768 0x8516 # 0 +0xE769 0x84FE # 0 +0xE76A 0x8528 # 0 +0xE76B 0x851D # 0 +0xE76C 0x852E # 0 +0xE76D 0x8502 # 0 +0xE76E 0x84FD # 0 +0xE76F 0x851E # 0 +0xE770 0x84F6 # 0 +0xE771 0x8531 # 0 +0xE772 0x8526 # 0 +0xE773 0x84E7 # 0 +0xE774 0x84E8 # 0 +0xE775 0x84F0 # 0 +0xE776 0x84EF # 0 +0xE777 0x84F9 # 0 +0xE778 0x8518 # 0 +0xE779 0x8520 # 0 +0xE77A 0x8530 # 0 +0xE77B 0x850B # 0 +0xE77C 0x8519 # 0 +0xE77D 0x852F # 0 +0xE77E 0x8662 # 0 +0xE7A1 0x8756 # 0 +0xE7A2 0x8763 # 0 +0xE7A3 0x8764 # 0 +0xE7A4 0x8777 # 0 +0xE7A5 0x87E1 # 0 +0xE7A6 0x8773 # 0 +0xE7A7 0x8758 # 0 +0xE7A8 0x8754 # 0 +0xE7A9 0x875B # 0 +0xE7AA 0x8752 # 0 +0xE7AB 0x8761 # 0 +0xE7AC 0x875A # 0 +0xE7AD 0x8751 # 0 +0xE7AE 0x875E # 0 +0xE7AF 0x876D # 0 +0xE7B0 0x876A # 0 +0xE7B1 0x8750 # 0 +0xE7B2 0x874E # 0 +0xE7B3 0x875F # 0 +0xE7B4 0x875D # 0 +0xE7B5 0x876F # 0 +0xE7B6 0x876C # 0 +0xE7B7 0x877A # 0 +0xE7B8 0x876E # 0 +0xE7B9 0x875C # 0 +0xE7BA 0x8765 # 0 +0xE7BB 0x874F # 0 +0xE7BC 0x877B # 0 +0xE7BD 0x8775 # 0 +0xE7BE 0x8762 # 0 +0xE7BF 0x8767 # 0 +0xE7C0 0x8769 # 0 +0xE7C1 0x885A # 0 +0xE7C2 0x8905 # 0 +0xE7C3 0x890C # 0 +0xE7C4 0x8914 # 0 +0xE7C5 0x890B # 0 +0xE7C6 0x8917 # 0 +0xE7C7 0x8918 # 0 +0xE7C8 0x8919 # 0 +0xE7C9 0x8906 # 0 +0xE7CA 0x8916 # 0 +0xE7CB 0x8911 # 0 +0xE7CC 0x890E # 0 +0xE7CD 0x8909 # 0 +0xE7CE 0x89A2 # 0 +0xE7CF 0x89A4 # 0 +0xE7D0 0x89A3 # 0 +0xE7D1 0x89ED # 0 +0xE7D2 0x89F0 # 0 +0xE7D3 0x89EC # 0 +0xE7D4 0x8ACF # 0 +0xE7D5 0x8AC6 # 0 +0xE7D6 0x8AB8 # 0 +0xE7D7 0x8AD3 # 0 +0xE7D8 0x8AD1 # 0 +0xE7D9 0x8AD4 # 0 +0xE7DA 0x8AD5 # 0 +0xE7DB 0x8ABB # 0 +0xE7DC 0x8AD7 # 0 +0xE7DD 0x8ABE # 0 +0xE7DE 0x8AC0 # 0 +0xE7DF 0x8AC5 # 0 +0xE7E0 0x8AD8 # 0 +0xE7E1 0x8AC3 # 0 +0xE7E2 0x8ABA # 0 +0xE7E3 0x8ABD # 0 +0xE7E4 0x8AD9 # 0 +0xE7E5 0x8C3E # 0 +0xE7E6 0x8C4D # 0 +0xE7E7 0x8C8F # 0 +0xE7E8 0x8CE5 # 0 +0xE7E9 0x8CDF # 0 +0xE7EA 0x8CD9 # 0 +0xE7EB 0x8CE8 # 0 +0xE7EC 0x8CDA # 0 +0xE7ED 0x8CDD # 0 +0xE7EE 0x8CE7 # 0 +0xE7EF 0x8DA0 # 0 +0xE7F0 0x8D9C # 0 +0xE7F1 0x8DA1 # 0 +0xE7F2 0x8D9B # 0 +0xE7F3 0x8E20 # 0 +0xE7F4 0x8E23 # 0 +0xE7F5 0x8E25 # 0 +0xE7F6 0x8E24 # 0 +0xE7F7 0x8E2E # 0 +0xE7F8 0x8E15 # 0 +0xE7F9 0x8E1B # 0 +0xE7FA 0x8E16 # 0 +0xE7FB 0x8E11 # 0 +0xE7FC 0x8E19 # 0 +0xE7FD 0x8E26 # 0 +0xE7FE 0x8E27 # 0 +0xE840 0x8E14 # 0 +0xE841 0x8E12 # 0 +0xE842 0x8E18 # 0 +0xE843 0x8E13 # 0 +0xE844 0x8E1C # 0 +0xE845 0x8E17 # 0 +0xE846 0x8E1A # 0 +0xE847 0x8F2C # 0 +0xE848 0x8F24 # 0 +0xE849 0x8F18 # 0 +0xE84A 0x8F1A # 0 +0xE84B 0x8F20 # 0 +0xE84C 0x8F23 # 0 +0xE84D 0x8F16 # 0 +0xE84E 0x8F17 # 0 +0xE84F 0x9073 # 0 +0xE850 0x9070 # 0 +0xE851 0x906F # 0 +0xE852 0x9067 # 0 +0xE853 0x906B # 0 +0xE854 0x912F # 0 +0xE855 0x912B # 0 +0xE856 0x9129 # 0 +0xE857 0x912A # 0 +0xE858 0x9132 # 0 +0xE859 0x9126 # 0 +0xE85A 0x912E # 0 +0xE85B 0x9185 # 0 +0xE85C 0x9186 # 0 +0xE85D 0x918A # 0 +0xE85E 0x9181 # 0 +0xE85F 0x9182 # 0 +0xE860 0x9184 # 0 +0xE861 0x9180 # 0 +0xE862 0x92D0 # 0 +0xE863 0x92C3 # 0 +0xE864 0x92C4 # 0 +0xE865 0x92C0 # 0 +0xE866 0x92D9 # 0 +0xE867 0x92B6 # 0 +0xE868 0x92CF # 0 +0xE869 0x92F1 # 0 +0xE86A 0x92DF # 0 +0xE86B 0x92D8 # 0 +0xE86C 0x92E9 # 0 +0xE86D 0x92D7 # 0 +0xE86E 0x92DD # 0 +0xE86F 0x92CC # 0 +0xE870 0x92EF # 0 +0xE871 0x92C2 # 0 +0xE872 0x92E8 # 0 +0xE873 0x92CA # 0 +0xE874 0x92C8 # 0 +0xE875 0x92CE # 0 +0xE876 0x92E6 # 0 +0xE877 0x92CD # 0 +0xE878 0x92D5 # 0 +0xE879 0x92C9 # 0 +0xE87A 0x92E0 # 0 +0xE87B 0x92DE # 0 +0xE87C 0x92E7 # 0 +0xE87D 0x92D1 # 0 +0xE87E 0x92D3 # 0 +0xE8A1 0x92B5 # 0 +0xE8A2 0x92E1 # 0 +0xE8A3 0x92C6 # 0 +0xE8A4 0x92B4 # 0 +0xE8A5 0x957C # 0 +0xE8A6 0x95AC # 0 +0xE8A7 0x95AB # 0 +0xE8A8 0x95AE # 0 +0xE8A9 0x95B0 # 0 +0xE8AA 0x96A4 # 0 +0xE8AB 0x96A2 # 0 +0xE8AC 0x96D3 # 0 +0xE8AD 0x9705 # 0 +0xE8AE 0x9708 # 0 +0xE8AF 0x9702 # 0 +0xE8B0 0x975A # 0 +0xE8B1 0x978A # 0 +0xE8B2 0x978E # 0 +0xE8B3 0x9788 # 0 +0xE8B4 0x97D0 # 0 +0xE8B5 0x97CF # 0 +0xE8B6 0x981E # 0 +0xE8B7 0x981D # 0 +0xE8B8 0x9826 # 0 +0xE8B9 0x9829 # 0 +0xE8BA 0x9828 # 0 +0xE8BB 0x9820 # 0 +0xE8BC 0x981B # 0 +0xE8BD 0x9827 # 0 +0xE8BE 0x98B2 # 0 +0xE8BF 0x9908 # 0 +0xE8C0 0x98FA # 0 +0xE8C1 0x9911 # 0 +0xE8C2 0x9914 # 0 +0xE8C3 0x9916 # 0 +0xE8C4 0x9917 # 0 +0xE8C5 0x9915 # 0 +0xE8C6 0x99DC # 0 +0xE8C7 0x99CD # 0 +0xE8C8 0x99CF # 0 +0xE8C9 0x99D3 # 0 +0xE8CA 0x99D4 # 0 +0xE8CB 0x99CE # 0 +0xE8CC 0x99C9 # 0 +0xE8CD 0x99D6 # 0 +0xE8CE 0x99D8 # 0 +0xE8CF 0x99CB # 0 +0xE8D0 0x99D7 # 0 +0xE8D1 0x99CC # 0 +0xE8D2 0x9AB3 # 0 +0xE8D3 0x9AEC # 0 +0xE8D4 0x9AEB # 0 +0xE8D5 0x9AF3 # 0 +0xE8D6 0x9AF2 # 0 +0xE8D7 0x9AF1 # 0 +0xE8D8 0x9B46 # 0 +0xE8D9 0x9B43 # 0 +0xE8DA 0x9B67 # 0 +0xE8DB 0x9B74 # 0 +0xE8DC 0x9B71 # 0 +0xE8DD 0x9B66 # 0 +0xE8DE 0x9B76 # 0 +0xE8DF 0x9B75 # 0 +0xE8E0 0x9B70 # 0 +0xE8E1 0x9B68 # 0 +0xE8E2 0x9B64 # 0 +0xE8E3 0x9B6C # 0 +0xE8E4 0x9CFC # 0 +0xE8E5 0x9CFA # 0 +0xE8E6 0x9CFD # 0 +0xE8E7 0x9CFF # 0 +0xE8E8 0x9CF7 # 0 +0xE8E9 0x9D07 # 0 +0xE8EA 0x9D00 # 0 +0xE8EB 0x9CF9 # 0 +0xE8EC 0x9CFB # 0 +0xE8ED 0x9D08 # 0 +0xE8EE 0x9D05 # 0 +0xE8EF 0x9D04 # 0 +0xE8F0 0x9E83 # 0 +0xE8F1 0x9ED3 # 0 +0xE8F2 0x9F0F # 0 +0xE8F3 0x9F10 # 0 +0xE8F4 0x511C # 0 +0xE8F5 0x5113 # 0 +0xE8F6 0x5117 # 0 +0xE8F7 0x511A # 0 +0xE8F8 0x5111 # 0 +0xE8F9 0x51DE # 0 +0xE8FA 0x5334 # 0 +0xE8FB 0x53E1 # 0 +0xE8FC 0x5670 # 0 +0xE8FD 0x5660 # 0 +0xE8FE 0x566E # 0 +0xE940 0x5673 # 0 +0xE941 0x5666 # 0 +0xE942 0x5663 # 0 +0xE943 0x566D # 0 +0xE944 0x5672 # 0 +0xE945 0x565E # 0 +0xE946 0x5677 # 0 +0xE947 0x571C # 0 +0xE948 0x571B # 0 +0xE949 0x58C8 # 0 +0xE94A 0x58BD # 0 +0xE94B 0x58C9 # 0 +0xE94C 0x58BF # 0 +0xE94D 0x58BA # 0 +0xE94E 0x58C2 # 0 +0xE94F 0x58BC # 0 +0xE950 0x58C6 # 0 +0xE951 0x5B17 # 0 +0xE952 0x5B19 # 0 +0xE953 0x5B1B # 0 +0xE954 0x5B21 # 0 +0xE955 0x5B14 # 0 +0xE956 0x5B13 # 0 +0xE957 0x5B10 # 0 +0xE958 0x5B16 # 0 +0xE959 0x5B28 # 0 +0xE95A 0x5B1A # 0 +0xE95B 0x5B20 # 0 +0xE95C 0x5B1E # 0 +0xE95D 0x5BEF # 0 +0xE95E 0x5DAC # 0 +0xE95F 0x5DB1 # 0 +0xE960 0x5DA9 # 0 +0xE961 0x5DA7 # 0 +0xE962 0x5DB5 # 0 +0xE963 0x5DB0 # 0 +0xE964 0x5DAE # 0 +0xE965 0x5DAA # 0 +0xE966 0x5DA8 # 0 +0xE967 0x5DB2 # 0 +0xE968 0x5DAD # 0 +0xE969 0x5DAF # 0 +0xE96A 0x5DB4 # 0 +0xE96B 0x5E67 # 0 +0xE96C 0x5E68 # 0 +0xE96D 0x5E66 # 0 +0xE96E 0x5E6F # 0 +0xE96F 0x5EE9 # 0 +0xE970 0x5EE7 # 0 +0xE971 0x5EE6 # 0 +0xE972 0x5EE8 # 0 +0xE973 0x5EE5 # 0 +0xE974 0x5F4B # 0 +0xE975 0x5FBC # 0 +0xE976 0x619D # 0 +0xE977 0x61A8 # 0 +0xE978 0x6196 # 0 +0xE979 0x61C5 # 0 +0xE97A 0x61B4 # 0 +0xE97B 0x61C6 # 0 +0xE97C 0x61C1 # 0 +0xE97D 0x61CC # 0 +0xE97E 0x61BA # 0 +0xE9A1 0x61BF # 0 +0xE9A2 0x61B8 # 0 +0xE9A3 0x618C # 0 +0xE9A4 0x64D7 # 0 +0xE9A5 0x64D6 # 0 +0xE9A6 0x64D0 # 0 +0xE9A7 0x64CF # 0 +0xE9A8 0x64C9 # 0 +0xE9A9 0x64BD # 0 +0xE9AA 0x6489 # 0 +0xE9AB 0x64C3 # 0 +0xE9AC 0x64DB # 0 +0xE9AD 0x64F3 # 0 +0xE9AE 0x64D9 # 0 +0xE9AF 0x6533 # 0 +0xE9B0 0x657F # 0 +0xE9B1 0x657C # 0 +0xE9B2 0x65A2 # 0 +0xE9B3 0x66C8 # 0 +0xE9B4 0x66BE # 0 +0xE9B5 0x66C0 # 0 +0xE9B6 0x66CA # 0 +0xE9B7 0x66CB # 0 +0xE9B8 0x66CF # 0 +0xE9B9 0x66BD # 0 +0xE9BA 0x66BB # 0 +0xE9BB 0x66BA # 0 +0xE9BC 0x66CC # 0 +0xE9BD 0x6723 # 0 +0xE9BE 0x6A34 # 0 +0xE9BF 0x6A66 # 0 +0xE9C0 0x6A49 # 0 +0xE9C1 0x6A67 # 0 +0xE9C2 0x6A32 # 0 +0xE9C3 0x6A68 # 0 +0xE9C4 0x6A3E # 0 +0xE9C5 0x6A5D # 0 +0xE9C6 0x6A6D # 0 +0xE9C7 0x6A76 # 0 +0xE9C8 0x6A5B # 0 +0xE9C9 0x6A51 # 0 +0xE9CA 0x6A28 # 0 +0xE9CB 0x6A5A # 0 +0xE9CC 0x6A3B # 0 +0xE9CD 0x6A3F # 0 +0xE9CE 0x6A41 # 0 +0xE9CF 0x6A6A # 0 +0xE9D0 0x6A64 # 0 +0xE9D1 0x6A50 # 0 +0xE9D2 0x6A4F # 0 +0xE9D3 0x6A54 # 0 +0xE9D4 0x6A6F # 0 +0xE9D5 0x6A69 # 0 +0xE9D6 0x6A60 # 0 +0xE9D7 0x6A3C # 0 +0xE9D8 0x6A5E # 0 +0xE9D9 0x6A56 # 0 +0xE9DA 0x6A55 # 0 +0xE9DB 0x6A4D # 0 +0xE9DC 0x6A4E # 0 +0xE9DD 0x6A46 # 0 +0xE9DE 0x6B55 # 0 +0xE9DF 0x6B54 # 0 +0xE9E0 0x6B56 # 0 +0xE9E1 0x6BA7 # 0 +0xE9E2 0x6BAA # 0 +0xE9E3 0x6BAB # 0 +0xE9E4 0x6BC8 # 0 +0xE9E5 0x6BC7 # 0 +0xE9E6 0x6C04 # 0 +0xE9E7 0x6C03 # 0 +0xE9E8 0x6C06 # 0 +0xE9E9 0x6FAD # 0 +0xE9EA 0x6FCB # 0 +0xE9EB 0x6FA3 # 0 +0xE9EC 0x6FC7 # 0 +0xE9ED 0x6FBC # 0 +0xE9EE 0x6FCE # 0 +0xE9EF 0x6FC8 # 0 +0xE9F0 0x6F5E # 0 +0xE9F1 0x6FC4 # 0 +0xE9F2 0x6FBD # 0 +0xE9F3 0x6F9E # 0 +0xE9F4 0x6FCA # 0 +0xE9F5 0x6FA8 # 0 +0xE9F6 0x7004 # 0 +0xE9F7 0x6FA5 # 0 +0xE9F8 0x6FAE # 0 +0xE9F9 0x6FBA # 0 +0xE9FA 0x6FAC # 0 +0xE9FB 0x6FAA # 0 +0xE9FC 0x6FCF # 0 +0xE9FD 0x6FBF # 0 +0xE9FE 0x6FB8 # 0 +0xEA40 0x6FA2 # 0 +0xEA41 0x6FC9 # 0 +0xEA42 0x6FAB # 0 +0xEA43 0x6FCD # 0 +0xEA44 0x6FAF # 0 +0xEA45 0x6FB2 # 0 +0xEA46 0x6FB0 # 0 +0xEA47 0x71C5 # 0 +0xEA48 0x71C2 # 0 +0xEA49 0x71BF # 0 +0xEA4A 0x71B8 # 0 +0xEA4B 0x71D6 # 0 +0xEA4C 0x71C0 # 0 +0xEA4D 0x71C1 # 0 +0xEA4E 0x71CB # 0 +0xEA4F 0x71D4 # 0 +0xEA50 0x71CA # 0 +0xEA51 0x71C7 # 0 +0xEA52 0x71CF # 0 +0xEA53 0x71BD # 0 +0xEA54 0x71D8 # 0 +0xEA55 0x71BC # 0 +0xEA56 0x71C6 # 0 +0xEA57 0x71DA # 0 +0xEA58 0x71DB # 0 +0xEA59 0x729D # 0 +0xEA5A 0x729E # 0 +0xEA5B 0x7369 # 0 +0xEA5C 0x7366 # 0 +0xEA5D 0x7367 # 0 +0xEA5E 0x736C # 0 +0xEA5F 0x7365 # 0 +0xEA60 0x736B # 0 +0xEA61 0x736A # 0 +0xEA62 0x747F # 0 +0xEA63 0x749A # 0 +0xEA64 0x74A0 # 0 +0xEA65 0x7494 # 0 +0xEA66 0x7492 # 0 +0xEA67 0x7495 # 0 +0xEA68 0x74A1 # 0 +0xEA69 0x750B # 0 +0xEA6A 0x7580 # 0 +0xEA6B 0x762F # 0 +0xEA6C 0x762D # 0 +0xEA6D 0x7631 # 0 +0xEA6E 0x763D # 0 +0xEA6F 0x7633 # 0 +0xEA70 0x763C # 0 +0xEA71 0x7635 # 0 +0xEA72 0x7632 # 0 +0xEA73 0x7630 # 0 +0xEA74 0x76BB # 0 +0xEA75 0x76E6 # 0 +0xEA76 0x779A # 0 +0xEA77 0x779D # 0 +0xEA78 0x77A1 # 0 +0xEA79 0x779C # 0 +0xEA7A 0x779B # 0 +0xEA7B 0x77A2 # 0 +0xEA7C 0x77A3 # 0 +0xEA7D 0x7795 # 0 +0xEA7E 0x7799 # 0 +0xEAA1 0x7797 # 0 +0xEAA2 0x78DD # 0 +0xEAA3 0x78E9 # 0 +0xEAA4 0x78E5 # 0 +0xEAA5 0x78EA # 0 +0xEAA6 0x78DE # 0 +0xEAA7 0x78E3 # 0 +0xEAA8 0x78DB # 0 +0xEAA9 0x78E1 # 0 +0xEAAA 0x78E2 # 0 +0xEAAB 0x78ED # 0 +0xEAAC 0x78DF # 0 +0xEAAD 0x78E0 # 0 +0xEAAE 0x79A4 # 0 +0xEAAF 0x7A44 # 0 +0xEAB0 0x7A48 # 0 +0xEAB1 0x7A47 # 0 +0xEAB2 0x7AB6 # 0 +0xEAB3 0x7AB8 # 0 +0xEAB4 0x7AB5 # 0 +0xEAB5 0x7AB1 # 0 +0xEAB6 0x7AB7 # 0 +0xEAB7 0x7BDE # 0 +0xEAB8 0x7BE3 # 0 +0xEAB9 0x7BE7 # 0 +0xEABA 0x7BDD # 0 +0xEABB 0x7BD5 # 0 +0xEABC 0x7BE5 # 0 +0xEABD 0x7BDA # 0 +0xEABE 0x7BE8 # 0 +0xEABF 0x7BF9 # 0 +0xEAC0 0x7BD4 # 0 +0xEAC1 0x7BEA # 0 +0xEAC2 0x7BE2 # 0 +0xEAC3 0x7BDC # 0 +0xEAC4 0x7BEB # 0 +0xEAC5 0x7BD8 # 0 +0xEAC6 0x7BDF # 0 +0xEAC7 0x7CD2 # 0 +0xEAC8 0x7CD4 # 0 +0xEAC9 0x7CD7 # 0 +0xEACA 0x7CD0 # 0 +0xEACB 0x7CD1 # 0 +0xEACC 0x7E12 # 0 +0xEACD 0x7E21 # 0 +0xEACE 0x7E17 # 0 +0xEACF 0x7E0C # 0 +0xEAD0 0x7E1F # 0 +0xEAD1 0x7E20 # 0 +0xEAD2 0x7E13 # 0 +0xEAD3 0x7E0E # 0 +0xEAD4 0x7E1C # 0 +0xEAD5 0x7E15 # 0 +0xEAD6 0x7E1A # 0 +0xEAD7 0x7E22 # 0 +0xEAD8 0x7E0B # 0 +0xEAD9 0x7E0F # 0 +0xEADA 0x7E16 # 0 +0xEADB 0x7E0D # 0 +0xEADC 0x7E14 # 0 +0xEADD 0x7E25 # 0 +0xEADE 0x7E24 # 0 +0xEADF 0x7F43 # 0 +0xEAE0 0x7F7B # 0 +0xEAE1 0x7F7C # 0 +0xEAE2 0x7F7A # 0 +0xEAE3 0x7FB1 # 0 +0xEAE4 0x7FEF # 0 +0xEAE5 0x802A # 0 +0xEAE6 0x8029 # 0 +0xEAE7 0x806C # 0 +0xEAE8 0x81B1 # 0 +0xEAE9 0x81A6 # 0 +0xEAEA 0x81AE # 0 +0xEAEB 0x81B9 # 0 +0xEAEC 0x81B5 # 0 +0xEAED 0x81AB # 0 +0xEAEE 0x81B0 # 0 +0xEAEF 0x81AC # 0 +0xEAF0 0x81B4 # 0 +0xEAF1 0x81B2 # 0 +0xEAF2 0x81B7 # 0 +0xEAF3 0x81A7 # 0 +0xEAF4 0x81F2 # 0 +0xEAF5 0x8255 # 0 +0xEAF6 0x8256 # 0 +0xEAF7 0x8257 # 0 +0xEAF8 0x8556 # 0 +0xEAF9 0x8545 # 0 +0xEAFA 0x856B # 0 +0xEAFB 0x854D # 0 +0xEAFC 0x8553 # 0 +0xEAFD 0x8561 # 0 +0xEAFE 0x8558 # 0 +0xEB40 0x8540 # 0 +0xEB41 0x8546 # 0 +0xEB42 0x8564 # 0 +0xEB43 0x8541 # 0 +0xEB44 0x8562 # 0 +0xEB45 0x8544 # 0 +0xEB46 0x8551 # 0 +0xEB47 0x8547 # 0 +0xEB48 0x8563 # 0 +0xEB49 0x853E # 0 +0xEB4A 0x855B # 0 +0xEB4B 0x8571 # 0 +0xEB4C 0x854E # 0 +0xEB4D 0x856E # 0 +0xEB4E 0x8575 # 0 +0xEB4F 0x8555 # 0 +0xEB50 0x8567 # 0 +0xEB51 0x8560 # 0 +0xEB52 0x858C # 0 +0xEB53 0x8566 # 0 +0xEB54 0x855D # 0 +0xEB55 0x8554 # 0 +0xEB56 0x8565 # 0 +0xEB57 0x856C # 0 +0xEB58 0x8663 # 0 +0xEB59 0x8665 # 0 +0xEB5A 0x8664 # 0 +0xEB5B 0x879B # 0 +0xEB5C 0x878F # 0 +0xEB5D 0x8797 # 0 +0xEB5E 0x8793 # 0 +0xEB5F 0x8792 # 0 +0xEB60 0x8788 # 0 +0xEB61 0x8781 # 0 +0xEB62 0x8796 # 0 +0xEB63 0x8798 # 0 +0xEB64 0x8779 # 0 +0xEB65 0x8787 # 0 +0xEB66 0x87A3 # 0 +0xEB67 0x8785 # 0 +0xEB68 0x8790 # 0 +0xEB69 0x8791 # 0 +0xEB6A 0x879D # 0 +0xEB6B 0x8784 # 0 +0xEB6C 0x8794 # 0 +0xEB6D 0x879C # 0 +0xEB6E 0x879A # 0 +0xEB6F 0x8789 # 0 +0xEB70 0x891E # 0 +0xEB71 0x8926 # 0 +0xEB72 0x8930 # 0 +0xEB73 0x892D # 0 +0xEB74 0x892E # 0 +0xEB75 0x8927 # 0 +0xEB76 0x8931 # 0 +0xEB77 0x8922 # 0 +0xEB78 0x8929 # 0 +0xEB79 0x8923 # 0 +0xEB7A 0x892F # 0 +0xEB7B 0x892C # 0 +0xEB7C 0x891F # 0 +0xEB7D 0x89F1 # 0 +0xEB7E 0x8AE0 # 0 +0xEBA1 0x8AE2 # 0 +0xEBA2 0x8AF2 # 0 +0xEBA3 0x8AF4 # 0 +0xEBA4 0x8AF5 # 0 +0xEBA5 0x8ADD # 0 +0xEBA6 0x8B14 # 0 +0xEBA7 0x8AE4 # 0 +0xEBA8 0x8ADF # 0 +0xEBA9 0x8AF0 # 0 +0xEBAA 0x8AC8 # 0 +0xEBAB 0x8ADE # 0 +0xEBAC 0x8AE1 # 0 +0xEBAD 0x8AE8 # 0 +0xEBAE 0x8AFF # 0 +0xEBAF 0x8AEF # 0 +0xEBB0 0x8AFB # 0 +0xEBB1 0x8C91 # 0 +0xEBB2 0x8C92 # 0 +0xEBB3 0x8C90 # 0 +0xEBB4 0x8CF5 # 0 +0xEBB5 0x8CEE # 0 +0xEBB6 0x8CF1 # 0 +0xEBB7 0x8CF0 # 0 +0xEBB8 0x8CF3 # 0 +0xEBB9 0x8D6C # 0 +0xEBBA 0x8D6E # 0 +0xEBBB 0x8DA5 # 0 +0xEBBC 0x8DA7 # 0 +0xEBBD 0x8E33 # 0 +0xEBBE 0x8E3E # 0 +0xEBBF 0x8E38 # 0 +0xEBC0 0x8E40 # 0 +0xEBC1 0x8E45 # 0 +0xEBC2 0x8E36 # 0 +0xEBC3 0x8E3C # 0 +0xEBC4 0x8E3D # 0 +0xEBC5 0x8E41 # 0 +0xEBC6 0x8E30 # 0 +0xEBC7 0x8E3F # 0 +0xEBC8 0x8EBD # 0 +0xEBC9 0x8F36 # 0 +0xEBCA 0x8F2E # 0 +0xEBCB 0x8F35 # 0 +0xEBCC 0x8F32 # 0 +0xEBCD 0x8F39 # 0 +0xEBCE 0x8F37 # 0 +0xEBCF 0x8F34 # 0 +0xEBD0 0x9076 # 0 +0xEBD1 0x9079 # 0 +0xEBD2 0x907B # 0 +0xEBD3 0x9086 # 0 +0xEBD4 0x90FA # 0 +0xEBD5 0x9133 # 0 +0xEBD6 0x9135 # 0 +0xEBD7 0x9136 # 0 +0xEBD8 0x9193 # 0 +0xEBD9 0x9190 # 0 +0xEBDA 0x9191 # 0 +0xEBDB 0x918D # 0 +0xEBDC 0x918F # 0 +0xEBDD 0x9327 # 0 +0xEBDE 0x931E # 0 +0xEBDF 0x9308 # 0 +0xEBE0 0x931F # 0 +0xEBE1 0x9306 # 0 +0xEBE2 0x930F # 0 +0xEBE3 0x937A # 0 +0xEBE4 0x9338 # 0 +0xEBE5 0x933C # 0 +0xEBE6 0x931B # 0 +0xEBE7 0x9323 # 0 +0xEBE8 0x9312 # 0 +0xEBE9 0x9301 # 0 +0xEBEA 0x9346 # 0 +0xEBEB 0x932D # 0 +0xEBEC 0x930E # 0 +0xEBED 0x930D # 0 +0xEBEE 0x92CB # 0 +0xEBEF 0x931D # 0 +0xEBF0 0x92FA # 0 +0xEBF1 0x9325 # 0 +0xEBF2 0x9313 # 0 +0xEBF3 0x92F9 # 0 +0xEBF4 0x92F7 # 0 +0xEBF5 0x9334 # 0 +0xEBF6 0x9302 # 0 +0xEBF7 0x9324 # 0 +0xEBF8 0x92FF # 0 +0xEBF9 0x9329 # 0 +0xEBFA 0x9339 # 0 +0xEBFB 0x9335 # 0 +0xEBFC 0x932A # 0 +0xEBFD 0x9314 # 0 +0xEBFE 0x930C # 0 +0xEC40 0x930B # 0 +0xEC41 0x92FE # 0 +0xEC42 0x9309 # 0 +0xEC43 0x9300 # 0 +0xEC44 0x92FB # 0 +0xEC45 0x9316 # 0 +0xEC46 0x95BC # 0 +0xEC47 0x95CD # 0 +0xEC48 0x95BE # 0 +0xEC49 0x95B9 # 0 +0xEC4A 0x95BA # 0 +0xEC4B 0x95B6 # 0 +0xEC4C 0x95BF # 0 +0xEC4D 0x95B5 # 0 +0xEC4E 0x95BD # 0 +0xEC4F 0x96A9 # 0 +0xEC50 0x96D4 # 0 +0xEC51 0x970B # 0 +0xEC52 0x9712 # 0 +0xEC53 0x9710 # 0 +0xEC54 0x9799 # 0 +0xEC55 0x9797 # 0 +0xEC56 0x9794 # 0 +0xEC57 0x97F0 # 0 +0xEC58 0x97F8 # 0 +0xEC59 0x9835 # 0 +0xEC5A 0x982F # 0 +0xEC5B 0x9832 # 0 +0xEC5C 0x9924 # 0 +0xEC5D 0x991F # 0 +0xEC5E 0x9927 # 0 +0xEC5F 0x9929 # 0 +0xEC60 0x999E # 0 +0xEC61 0x99EE # 0 +0xEC62 0x99EC # 0 +0xEC63 0x99E5 # 0 +0xEC64 0x99E4 # 0 +0xEC65 0x99F0 # 0 +0xEC66 0x99E3 # 0 +0xEC67 0x99EA # 0 +0xEC68 0x99E9 # 0 +0xEC69 0x99E7 # 0 +0xEC6A 0x9AB9 # 0 +0xEC6B 0x9ABF # 0 +0xEC6C 0x9AB4 # 0 +0xEC6D 0x9ABB # 0 +0xEC6E 0x9AF6 # 0 +0xEC6F 0x9AFA # 0 +0xEC70 0x9AF9 # 0 +0xEC71 0x9AF7 # 0 +0xEC72 0x9B33 # 0 +0xEC73 0x9B80 # 0 +0xEC74 0x9B85 # 0 +0xEC75 0x9B87 # 0 +0xEC76 0x9B7C # 0 +0xEC77 0x9B7E # 0 +0xEC78 0x9B7B # 0 +0xEC79 0x9B82 # 0 +0xEC7A 0x9B93 # 0 +0xEC7B 0x9B92 # 0 +0xEC7C 0x9B90 # 0 +0xEC7D 0x9B7A # 0 +0xEC7E 0x9B95 # 0 +0xECA1 0x9B7D # 0 +0xECA2 0x9B88 # 0 +0xECA3 0x9D25 # 0 +0xECA4 0x9D17 # 0 +0xECA5 0x9D20 # 0 +0xECA6 0x9D1E # 0 +0xECA7 0x9D14 # 0 +0xECA8 0x9D29 # 0 +0xECA9 0x9D1D # 0 +0xECAA 0x9D18 # 0 +0xECAB 0x9D22 # 0 +0xECAC 0x9D10 # 0 +0xECAD 0x9D19 # 0 +0xECAE 0x9D1F # 0 +0xECAF 0x9E88 # 0 +0xECB0 0x9E86 # 0 +0xECB1 0x9E87 # 0 +0xECB2 0x9EAE # 0 +0xECB3 0x9EAD # 0 +0xECB4 0x9ED5 # 0 +0xECB5 0x9ED6 # 0 +0xECB6 0x9EFA # 0 +0xECB7 0x9F12 # 0 +0xECB8 0x9F3D # 0 +0xECB9 0x5126 # 0 +0xECBA 0x5125 # 0 +0xECBB 0x5122 # 0 +0xECBC 0x5124 # 0 +0xECBD 0x5120 # 0 +0xECBE 0x5129 # 0 +0xECBF 0x52F4 # 0 +0xECC0 0x5693 # 0 +0xECC1 0x568C # 0 +0xECC2 0x568D # 0 +0xECC3 0x5686 # 0 +0xECC4 0x5684 # 0 +0xECC5 0x5683 # 0 +0xECC6 0x567E # 0 +0xECC7 0x5682 # 0 +0xECC8 0x567F # 0 +0xECC9 0x5681 # 0 +0xECCA 0x58D6 # 0 +0xECCB 0x58D4 # 0 +0xECCC 0x58CF # 0 +0xECCD 0x58D2 # 0 +0xECCE 0x5B2D # 0 +0xECCF 0x5B25 # 0 +0xECD0 0x5B32 # 0 +0xECD1 0x5B23 # 0 +0xECD2 0x5B2C # 0 +0xECD3 0x5B27 # 0 +0xECD4 0x5B26 # 0 +0xECD5 0x5B2F # 0 +0xECD6 0x5B2E # 0 +0xECD7 0x5B7B # 0 +0xECD8 0x5BF1 # 0 +0xECD9 0x5BF2 # 0 +0xECDA 0x5DB7 # 0 +0xECDB 0x5E6C # 0 +0xECDC 0x5E6A # 0 +0xECDD 0x5FBE # 0 +0xECDE 0x5FBB # 0 +0xECDF 0x61C3 # 0 +0xECE0 0x61B5 # 0 +0xECE1 0x61BC # 0 +0xECE2 0x61E7 # 0 +0xECE3 0x61E0 # 0 +0xECE4 0x61E5 # 0 +0xECE5 0x61E4 # 0 +0xECE6 0x61E8 # 0 +0xECE7 0x61DE # 0 +0xECE8 0x64EF # 0 +0xECE9 0x64E9 # 0 +0xECEA 0x64E3 # 0 +0xECEB 0x64EB # 0 +0xECEC 0x64E4 # 0 +0xECED 0x64E8 # 0 +0xECEE 0x6581 # 0 +0xECEF 0x6580 # 0 +0xECF0 0x65B6 # 0 +0xECF1 0x65DA # 0 +0xECF2 0x66D2 # 0 +0xECF3 0x6A8D # 0 +0xECF4 0x6A96 # 0 +0xECF5 0x6A81 # 0 +0xECF6 0x6AA5 # 0 +0xECF7 0x6A89 # 0 +0xECF8 0x6A9F # 0 +0xECF9 0x6A9B # 0 +0xECFA 0x6AA1 # 0 +0xECFB 0x6A9E # 0 +0xECFC 0x6A87 # 0 +0xECFD 0x6A93 # 0 +0xECFE 0x6A8E # 0 +0xED40 0x6A95 # 0 +0xED41 0x6A83 # 0 +0xED42 0x6AA8 # 0 +0xED43 0x6AA4 # 0 +0xED44 0x6A91 # 0 +0xED45 0x6A7F # 0 +0xED46 0x6AA6 # 0 +0xED47 0x6A9A # 0 +0xED48 0x6A85 # 0 +0xED49 0x6A8C # 0 +0xED4A 0x6A92 # 0 +0xED4B 0x6B5B # 0 +0xED4C 0x6BAD # 0 +0xED4D 0x6C09 # 0 +0xED4E 0x6FCC # 0 +0xED4F 0x6FA9 # 0 +0xED50 0x6FF4 # 0 +0xED51 0x6FD4 # 0 +0xED52 0x6FE3 # 0 +0xED53 0x6FDC # 0 +0xED54 0x6FED # 0 +0xED55 0x6FE7 # 0 +0xED56 0x6FE6 # 0 +0xED57 0x6FDE # 0 +0xED58 0x6FF2 # 0 +0xED59 0x6FDD # 0 +0xED5A 0x6FE2 # 0 +0xED5B 0x6FE8 # 0 +0xED5C 0x71E1 # 0 +0xED5D 0x71F1 # 0 +0xED5E 0x71E8 # 0 +0xED5F 0x71F2 # 0 +0xED60 0x71E4 # 0 +0xED61 0x71F0 # 0 +0xED62 0x71E2 # 0 +0xED63 0x7373 # 0 +0xED64 0x736E # 0 +0xED65 0x736F # 0 +0xED66 0x7497 # 0 +0xED67 0x74B2 # 0 +0xED68 0x74AB # 0 +0xED69 0x7490 # 0 +0xED6A 0x74AA # 0 +0xED6B 0x74AD # 0 +0xED6C 0x74B1 # 0 +0xED6D 0x74A5 # 0 +0xED6E 0x74AF # 0 +0xED6F 0x7510 # 0 +0xED70 0x7511 # 0 +0xED71 0x7512 # 0 +0xED72 0x750F # 0 +0xED73 0x7584 # 0 +0xED74 0x7643 # 0 +0xED75 0x7648 # 0 +0xED76 0x7649 # 0 +0xED77 0x7647 # 0 +0xED78 0x76A4 # 0 +0xED79 0x76E9 # 0 +0xED7A 0x77B5 # 0 +0xED7B 0x77AB # 0 +0xED7C 0x77B2 # 0 +0xED7D 0x77B7 # 0 +0xED7E 0x77B6 # 0 +0xEDA1 0x77B4 # 0 +0xEDA2 0x77B1 # 0 +0xEDA3 0x77A8 # 0 +0xEDA4 0x77F0 # 0 +0xEDA5 0x78F3 # 0 +0xEDA6 0x78FD # 0 +0xEDA7 0x7902 # 0 +0xEDA8 0x78FB # 0 +0xEDA9 0x78FC # 0 +0xEDAA 0x78F2 # 0 +0xEDAB 0x7905 # 0 +0xEDAC 0x78F9 # 0 +0xEDAD 0x78FE # 0 +0xEDAE 0x7904 # 0 +0xEDAF 0x79AB # 0 +0xEDB0 0x79A8 # 0 +0xEDB1 0x7A5C # 0 +0xEDB2 0x7A5B # 0 +0xEDB3 0x7A56 # 0 +0xEDB4 0x7A58 # 0 +0xEDB5 0x7A54 # 0 +0xEDB6 0x7A5A # 0 +0xEDB7 0x7ABE # 0 +0xEDB8 0x7AC0 # 0 +0xEDB9 0x7AC1 # 0 +0xEDBA 0x7C05 # 0 +0xEDBB 0x7C0F # 0 +0xEDBC 0x7BF2 # 0 +0xEDBD 0x7C00 # 0 +0xEDBE 0x7BFF # 0 +0xEDBF 0x7BFB # 0 +0xEDC0 0x7C0E # 0 +0xEDC1 0x7BF4 # 0 +0xEDC2 0x7C0B # 0 +0xEDC3 0x7BF3 # 0 +0xEDC4 0x7C02 # 0 +0xEDC5 0x7C09 # 0 +0xEDC6 0x7C03 # 0 +0xEDC7 0x7C01 # 0 +0xEDC8 0x7BF8 # 0 +0xEDC9 0x7BFD # 0 +0xEDCA 0x7C06 # 0 +0xEDCB 0x7BF0 # 0 +0xEDCC 0x7BF1 # 0 +0xEDCD 0x7C10 # 0 +0xEDCE 0x7C0A # 0 +0xEDCF 0x7CE8 # 0 +0xEDD0 0x7E2D # 0 +0xEDD1 0x7E3C # 0 +0xEDD2 0x7E42 # 0 +0xEDD3 0x7E33 # 0 +0xEDD4 0x9848 # 0 +0xEDD5 0x7E38 # 0 +0xEDD6 0x7E2A # 0 +0xEDD7 0x7E49 # 0 +0xEDD8 0x7E40 # 0 +0xEDD9 0x7E47 # 0 +0xEDDA 0x7E29 # 0 +0xEDDB 0x7E4C # 0 +0xEDDC 0x7E30 # 0 +0xEDDD 0x7E3B # 0 +0xEDDE 0x7E36 # 0 +0xEDDF 0x7E44 # 0 +0xEDE0 0x7E3A # 0 +0xEDE1 0x7F45 # 0 +0xEDE2 0x7F7F # 0 +0xEDE3 0x7F7E # 0 +0xEDE4 0x7F7D # 0 +0xEDE5 0x7FF4 # 0 +0xEDE6 0x7FF2 # 0 +0xEDE7 0x802C # 0 +0xEDE8 0x81BB # 0 +0xEDE9 0x81C4 # 0 +0xEDEA 0x81CC # 0 +0xEDEB 0x81CA # 0 +0xEDEC 0x81C5 # 0 +0xEDED 0x81C7 # 0 +0xEDEE 0x81BC # 0 +0xEDEF 0x81E9 # 0 +0xEDF0 0x825B # 0 +0xEDF1 0x825A # 0 +0xEDF2 0x825C # 0 +0xEDF3 0x8583 # 0 +0xEDF4 0x8580 # 0 +0xEDF5 0x858F # 0 +0xEDF6 0x85A7 # 0 +0xEDF7 0x8595 # 0 +0xEDF8 0x85A0 # 0 +0xEDF9 0x858B # 0 +0xEDFA 0x85A3 # 0 +0xEDFB 0x857B # 0 +0xEDFC 0x85A4 # 0 +0xEDFD 0x859A # 0 +0xEDFE 0x859E # 0 +0xEE40 0x8577 # 0 +0xEE41 0x857C # 0 +0xEE42 0x8589 # 0 +0xEE43 0x85A1 # 0 +0xEE44 0x857A # 0 +0xEE45 0x8578 # 0 +0xEE46 0x8557 # 0 +0xEE47 0x858E # 0 +0xEE48 0x8596 # 0 +0xEE49 0x8586 # 0 +0xEE4A 0x858D # 0 +0xEE4B 0x8599 # 0 +0xEE4C 0x859D # 0 +0xEE4D 0x8581 # 0 +0xEE4E 0x85A2 # 0 +0xEE4F 0x8582 # 0 +0xEE50 0x8588 # 0 +0xEE51 0x8585 # 0 +0xEE52 0x8579 # 0 +0xEE53 0x8576 # 0 +0xEE54 0x8598 # 0 +0xEE55 0x8590 # 0 +0xEE56 0x859F # 0 +0xEE57 0x8668 # 0 +0xEE58 0x87BE # 0 +0xEE59 0x87AA # 0 +0xEE5A 0x87AD # 0 +0xEE5B 0x87C5 # 0 +0xEE5C 0x87B0 # 0 +0xEE5D 0x87AC # 0 +0xEE5E 0x87B9 # 0 +0xEE5F 0x87B5 # 0 +0xEE60 0x87BC # 0 +0xEE61 0x87AE # 0 +0xEE62 0x87C9 # 0 +0xEE63 0x87C3 # 0 +0xEE64 0x87C2 # 0 +0xEE65 0x87CC # 0 +0xEE66 0x87B7 # 0 +0xEE67 0x87AF # 0 +0xEE68 0x87C4 # 0 +0xEE69 0x87CA # 0 +0xEE6A 0x87B4 # 0 +0xEE6B 0x87B6 # 0 +0xEE6C 0x87BF # 0 +0xEE6D 0x87B8 # 0 +0xEE6E 0x87BD # 0 +0xEE6F 0x87DE # 0 +0xEE70 0x87B2 # 0 +0xEE71 0x8935 # 0 +0xEE72 0x8933 # 0 +0xEE73 0x893C # 0 +0xEE74 0x893E # 0 +0xEE75 0x8941 # 0 +0xEE76 0x8952 # 0 +0xEE77 0x8937 # 0 +0xEE78 0x8942 # 0 +0xEE79 0x89AD # 0 +0xEE7A 0x89AF # 0 +0xEE7B 0x89AE # 0 +0xEE7C 0x89F2 # 0 +0xEE7D 0x89F3 # 0 +0xEE7E 0x8B1E # 0 +0xEEA1 0x8B18 # 0 +0xEEA2 0x8B16 # 0 +0xEEA3 0x8B11 # 0 +0xEEA4 0x8B05 # 0 +0xEEA5 0x8B0B # 0 +0xEEA6 0x8B22 # 0 +0xEEA7 0x8B0F # 0 +0xEEA8 0x8B12 # 0 +0xEEA9 0x8B15 # 0 +0xEEAA 0x8B07 # 0 +0xEEAB 0x8B0D # 0 +0xEEAC 0x8B08 # 0 +0xEEAD 0x8B06 # 0 +0xEEAE 0x8B1C # 0 +0xEEAF 0x8B13 # 0 +0xEEB0 0x8B1A # 0 +0xEEB1 0x8C4F # 0 +0xEEB2 0x8C70 # 0 +0xEEB3 0x8C72 # 0 +0xEEB4 0x8C71 # 0 +0xEEB5 0x8C6F # 0 +0xEEB6 0x8C95 # 0 +0xEEB7 0x8C94 # 0 +0xEEB8 0x8CF9 # 0 +0xEEB9 0x8D6F # 0 +0xEEBA 0x8E4E # 0 +0xEEBB 0x8E4D # 0 +0xEEBC 0x8E53 # 0 +0xEEBD 0x8E50 # 0 +0xEEBE 0x8E4C # 0 +0xEEBF 0x8E47 # 0 +0xEEC0 0x8F43 # 0 +0xEEC1 0x8F40 # 0 +0xEEC2 0x9085 # 0 +0xEEC3 0x907E # 0 +0xEEC4 0x9138 # 0 +0xEEC5 0x919A # 0 +0xEEC6 0x91A2 # 0 +0xEEC7 0x919B # 0 +0xEEC8 0x9199 # 0 +0xEEC9 0x919F # 0 +0xEECA 0x91A1 # 0 +0xEECB 0x919D # 0 +0xEECC 0x91A0 # 0 +0xEECD 0x93A1 # 0 +0xEECE 0x9383 # 0 +0xEECF 0x93AF # 0 +0xEED0 0x9364 # 0 +0xEED1 0x9356 # 0 +0xEED2 0x9347 # 0 +0xEED3 0x937C # 0 +0xEED4 0x9358 # 0 +0xEED5 0x935C # 0 +0xEED6 0x9376 # 0 +0xEED7 0x9349 # 0 +0xEED8 0x9350 # 0 +0xEED9 0x9351 # 0 +0xEEDA 0x9360 # 0 +0xEEDB 0x936D # 0 +0xEEDC 0x938F # 0 +0xEEDD 0x934C # 0 +0xEEDE 0x936A # 0 +0xEEDF 0x9379 # 0 +0xEEE0 0x9357 # 0 +0xEEE1 0x9355 # 0 +0xEEE2 0x9352 # 0 +0xEEE3 0x934F # 0 +0xEEE4 0x9371 # 0 +0xEEE5 0x9377 # 0 +0xEEE6 0x937B # 0 +0xEEE7 0x9361 # 0 +0xEEE8 0x935E # 0 +0xEEE9 0x9363 # 0 +0xEEEA 0x9367 # 0 +0xEEEB 0x9380 # 0 +0xEEEC 0x934E # 0 +0xEEED 0x9359 # 0 +0xEEEE 0x95C7 # 0 +0xEEEF 0x95C0 # 0 +0xEEF0 0x95C9 # 0 +0xEEF1 0x95C3 # 0 +0xEEF2 0x95C5 # 0 +0xEEF3 0x95B7 # 0 +0xEEF4 0x96AE # 0 +0xEEF5 0x96B0 # 0 +0xEEF6 0x96AC # 0 +0xEEF7 0x9720 # 0 +0xEEF8 0x971F # 0 +0xEEF9 0x9718 # 0 +0xEEFA 0x971D # 0 +0xEEFB 0x9719 # 0 +0xEEFC 0x979A # 0 +0xEEFD 0x97A1 # 0 +0xEEFE 0x979C # 0 +0xEF40 0x979E # 0 +0xEF41 0x979D # 0 +0xEF42 0x97D5 # 0 +0xEF43 0x97D4 # 0 +0xEF44 0x97F1 # 0 +0xEF45 0x9841 # 0 +0xEF46 0x9844 # 0 +0xEF47 0x984A # 0 +0xEF48 0x9849 # 0 +0xEF49 0x9845 # 0 +0xEF4A 0x9843 # 0 +0xEF4B 0x9925 # 0 +0xEF4C 0x992B # 0 +0xEF4D 0x992C # 0 +0xEF4E 0x992A # 0 +0xEF4F 0x9933 # 0 +0xEF50 0x9932 # 0 +0xEF51 0x992F # 0 +0xEF52 0x992D # 0 +0xEF53 0x9931 # 0 +0xEF54 0x9930 # 0 +0xEF55 0x9998 # 0 +0xEF56 0x99A3 # 0 +0xEF57 0x99A1 # 0 +0xEF58 0x9A02 # 0 +0xEF59 0x99FA # 0 +0xEF5A 0x99F4 # 0 +0xEF5B 0x99F7 # 0 +0xEF5C 0x99F9 # 0 +0xEF5D 0x99F8 # 0 +0xEF5E 0x99F6 # 0 +0xEF5F 0x99FB # 0 +0xEF60 0x99FD # 0 +0xEF61 0x99FE # 0 +0xEF62 0x99FC # 0 +0xEF63 0x9A03 # 0 +0xEF64 0x9ABE # 0 +0xEF65 0x9AFE # 0 +0xEF66 0x9AFD # 0 +0xEF67 0x9B01 # 0 +0xEF68 0x9AFC # 0 +0xEF69 0x9B48 # 0 +0xEF6A 0x9B9A # 0 +0xEF6B 0x9BA8 # 0 +0xEF6C 0x9B9E # 0 +0xEF6D 0x9B9B # 0 +0xEF6E 0x9BA6 # 0 +0xEF6F 0x9BA1 # 0 +0xEF70 0x9BA5 # 0 +0xEF71 0x9BA4 # 0 +0xEF72 0x9B86 # 0 +0xEF73 0x9BA2 # 0 +0xEF74 0x9BA0 # 0 +0xEF75 0x9BAF # 0 +0xEF76 0x9D33 # 0 +0xEF77 0x9D41 # 0 +0xEF78 0x9D67 # 0 +0xEF79 0x9D36 # 0 +0xEF7A 0x9D2E # 0 +0xEF7B 0x9D2F # 0 +0xEF7C 0x9D31 # 0 +0xEF7D 0x9D38 # 0 +0xEF7E 0x9D30 # 0 +0xEFA1 0x9D45 # 0 +0xEFA2 0x9D42 # 0 +0xEFA3 0x9D43 # 0 +0xEFA4 0x9D3E # 0 +0xEFA5 0x9D37 # 0 +0xEFA6 0x9D40 # 0 +0xEFA7 0x9D3D # 0 +0xEFA8 0x7FF5 # 0 +0xEFA9 0x9D2D # 0 +0xEFAA 0x9E8A # 0 +0xEFAB 0x9E89 # 0 +0xEFAC 0x9E8D # 0 +0xEFAD 0x9EB0 # 0 +0xEFAE 0x9EC8 # 0 +0xEFAF 0x9EDA # 0 +0xEFB0 0x9EFB # 0 +0xEFB1 0x9EFF # 0 +0xEFB2 0x9F24 # 0 +0xEFB3 0x9F23 # 0 +0xEFB4 0x9F22 # 0 +0xEFB5 0x9F54 # 0 +0xEFB6 0x9FA0 # 0 +0xEFB7 0x5131 # 0 +0xEFB8 0x512D # 0 +0xEFB9 0x512E # 0 +0xEFBA 0x5698 # 0 +0xEFBB 0x569C # 0 +0xEFBC 0x5697 # 0 +0xEFBD 0x569A # 0 +0xEFBE 0x569D # 0 +0xEFBF 0x5699 # 0 +0xEFC0 0x5970 # 0 +0xEFC1 0x5B3C # 0 +0xEFC2 0x5C69 # 0 +0xEFC3 0x5C6A # 0 +0xEFC4 0x5DC0 # 0 +0xEFC5 0x5E6D # 0 +0xEFC6 0x5E6E # 0 +0xEFC7 0x61D8 # 0 +0xEFC8 0x61DF # 0 +0xEFC9 0x61ED # 0 +0xEFCA 0x61EE # 0 +0xEFCB 0x61F1 # 0 +0xEFCC 0x61EA # 0 +0xEFCD 0x61F0 # 0 +0xEFCE 0x61EB # 0 +0xEFCF 0x61D6 # 0 +0xEFD0 0x61E9 # 0 +0xEFD1 0x64FF # 0 +0xEFD2 0x6504 # 0 +0xEFD3 0x64FD # 0 +0xEFD4 0x64F8 # 0 +0xEFD5 0x6501 # 0 +0xEFD6 0x6503 # 0 +0xEFD7 0x64FC # 0 +0xEFD8 0x6594 # 0 +0xEFD9 0x65DB # 0 +0xEFDA 0x66DA # 0 +0xEFDB 0x66DB # 0 +0xEFDC 0x66D8 # 0 +0xEFDD 0x6AC5 # 0 +0xEFDE 0x6AB9 # 0 +0xEFDF 0x6ABD # 0 +0xEFE0 0x6AE1 # 0 +0xEFE1 0x6AC6 # 0 +0xEFE2 0x6ABA # 0 +0xEFE3 0x6AB6 # 0 +0xEFE4 0x6AB7 # 0 +0xEFE5 0x6AC7 # 0 +0xEFE6 0x6AB4 # 0 +0xEFE7 0x6AAD # 0 +0xEFE8 0x6B5E # 0 +0xEFE9 0x6BC9 # 0 +0xEFEA 0x6C0B # 0 +0xEFEB 0x7007 # 0 +0xEFEC 0x700C # 0 +0xEFED 0x700D # 0 +0xEFEE 0x7001 # 0 +0xEFEF 0x7005 # 0 +0xEFF0 0x7014 # 0 +0xEFF1 0x700E # 0 +0xEFF2 0x6FFF # 0 +0xEFF3 0x7000 # 0 +0xEFF4 0x6FFB # 0 +0xEFF5 0x7026 # 0 +0xEFF6 0x6FFC # 0 +0xEFF7 0x6FF7 # 0 +0xEFF8 0x700A # 0 +0xEFF9 0x7201 # 0 +0xEFFA 0x71FF # 0 +0xEFFB 0x71F9 # 0 +0xEFFC 0x7203 # 0 +0xEFFD 0x71FD # 0 +0xEFFE 0x7376 # 0 +0xF040 0x74B8 # 0 +0xF041 0x74C0 # 0 +0xF042 0x74B5 # 0 +0xF043 0x74C1 # 0 +0xF044 0x74BE # 0 +0xF045 0x74B6 # 0 +0xF046 0x74BB # 0 +0xF047 0x74C2 # 0 +0xF048 0x7514 # 0 +0xF049 0x7513 # 0 +0xF04A 0x765C # 0 +0xF04B 0x7664 # 0 +0xF04C 0x7659 # 0 +0xF04D 0x7650 # 0 +0xF04E 0x7653 # 0 +0xF04F 0x7657 # 0 +0xF050 0x765A # 0 +0xF051 0x76A6 # 0 +0xF052 0x76BD # 0 +0xF053 0x76EC # 0 +0xF054 0x77C2 # 0 +0xF055 0x77BA # 0 +0xF056 0x78FF # 0 +0xF057 0x790C # 0 +0xF058 0x7913 # 0 +0xF059 0x7914 # 0 +0xF05A 0x7909 # 0 +0xF05B 0x7910 # 0 +0xF05C 0x7912 # 0 +0xF05D 0x7911 # 0 +0xF05E 0x79AD # 0 +0xF05F 0x79AC # 0 +0xF060 0x7A5F # 0 +0xF061 0x7C1C # 0 +0xF062 0x7C29 # 0 +0xF063 0x7C19 # 0 +0xF064 0x7C20 # 0 +0xF065 0x7C1F # 0 +0xF066 0x7C2D # 0 +0xF067 0x7C1D # 0 +0xF068 0x7C26 # 0 +0xF069 0x7C28 # 0 +0xF06A 0x7C22 # 0 +0xF06B 0x7C25 # 0 +0xF06C 0x7C30 # 0 +0xF06D 0x7E5C # 0 +0xF06E 0x7E50 # 0 +0xF06F 0x7E56 # 0 +0xF070 0x7E63 # 0 +0xF071 0x7E58 # 0 +0xF072 0x7E62 # 0 +0xF073 0x7E5F # 0 +0xF074 0x7E51 # 0 +0xF075 0x7E60 # 0 +0xF076 0x7E57 # 0 +0xF077 0x7E53 # 0 +0xF078 0x7FB5 # 0 +0xF079 0x7FB3 # 0 +0xF07A 0x7FF7 # 0 +0xF07B 0x7FF8 # 0 +0xF07C 0x8075 # 0 +0xF07D 0x81D1 # 0 +0xF07E 0x81D2 # 0 +0xF0A1 0x81D0 # 0 +0xF0A2 0x825F # 0 +0xF0A3 0x825E # 0 +0xF0A4 0x85B4 # 0 +0xF0A5 0x85C6 # 0 +0xF0A6 0x85C0 # 0 +0xF0A7 0x85C3 # 0 +0xF0A8 0x85C2 # 0 +0xF0A9 0x85B3 # 0 +0xF0AA 0x85B5 # 0 +0xF0AB 0x85BD # 0 +0xF0AC 0x85C7 # 0 +0xF0AD 0x85C4 # 0 +0xF0AE 0x85BF # 0 +0xF0AF 0x85CB # 0 +0xF0B0 0x85CE # 0 +0xF0B1 0x85C8 # 0 +0xF0B2 0x85C5 # 0 +0xF0B3 0x85B1 # 0 +0xF0B4 0x85B6 # 0 +0xF0B5 0x85D2 # 0 +0xF0B6 0x8624 # 0 +0xF0B7 0x85B8 # 0 +0xF0B8 0x85B7 # 0 +0xF0B9 0x85BE # 0 +0xF0BA 0x8669 # 0 +0xF0BB 0x87E7 # 0 +0xF0BC 0x87E6 # 0 +0xF0BD 0x87E2 # 0 +0xF0BE 0x87DB # 0 +0xF0BF 0x87EB # 0 +0xF0C0 0x87EA # 0 +0xF0C1 0x87E5 # 0 +0xF0C2 0x87DF # 0 +0xF0C3 0x87F3 # 0 +0xF0C4 0x87E4 # 0 +0xF0C5 0x87D4 # 0 +0xF0C6 0x87DC # 0 +0xF0C7 0x87D3 # 0 +0xF0C8 0x87ED # 0 +0xF0C9 0x87D8 # 0 +0xF0CA 0x87E3 # 0 +0xF0CB 0x87A4 # 0 +0xF0CC 0x87D7 # 0 +0xF0CD 0x87D9 # 0 +0xF0CE 0x8801 # 0 +0xF0CF 0x87F4 # 0 +0xF0D0 0x87E8 # 0 +0xF0D1 0x87DD # 0 +0xF0D2 0x8953 # 0 +0xF0D3 0x894B # 0 +0xF0D4 0x894F # 0 +0xF0D5 0x894C # 0 +0xF0D6 0x8946 # 0 +0xF0D7 0x8950 # 0 +0xF0D8 0x8951 # 0 +0xF0D9 0x8949 # 0 +0xF0DA 0x8B2A # 0 +0xF0DB 0x8B27 # 0 +0xF0DC 0x8B23 # 0 +0xF0DD 0x8B33 # 0 +0xF0DE 0x8B30 # 0 +0xF0DF 0x8B35 # 0 +0xF0E0 0x8B47 # 0 +0xF0E1 0x8B2F # 0 +0xF0E2 0x8B3C # 0 +0xF0E3 0x8B3E # 0 +0xF0E4 0x8B31 # 0 +0xF0E5 0x8B25 # 0 +0xF0E6 0x8B37 # 0 +0xF0E7 0x8B26 # 0 +0xF0E8 0x8B36 # 0 +0xF0E9 0x8B2E # 0 +0xF0EA 0x8B24 # 0 +0xF0EB 0x8B3B # 0 +0xF0EC 0x8B3D # 0 +0xF0ED 0x8B3A # 0 +0xF0EE 0x8C42 # 0 +0xF0EF 0x8C75 # 0 +0xF0F0 0x8C99 # 0 +0xF0F1 0x8C98 # 0 +0xF0F2 0x8C97 # 0 +0xF0F3 0x8CFE # 0 +0xF0F4 0x8D04 # 0 +0xF0F5 0x8D02 # 0 +0xF0F6 0x8D00 # 0 +0xF0F7 0x8E5C # 0 +0xF0F8 0x8E62 # 0 +0xF0F9 0x8E60 # 0 +0xF0FA 0x8E57 # 0 +0xF0FB 0x8E56 # 0 +0xF0FC 0x8E5E # 0 +0xF0FD 0x8E65 # 0 +0xF0FE 0x8E67 # 0 +0xF140 0x8E5B # 0 +0xF141 0x8E5A # 0 +0xF142 0x8E61 # 0 +0xF143 0x8E5D # 0 +0xF144 0x8E69 # 0 +0xF145 0x8E54 # 0 +0xF146 0x8F46 # 0 +0xF147 0x8F47 # 0 +0xF148 0x8F48 # 0 +0xF149 0x8F4B # 0 +0xF14A 0x9128 # 0 +0xF14B 0x913A # 0 +0xF14C 0x913B # 0 +0xF14D 0x913E # 0 +0xF14E 0x91A8 # 0 +0xF14F 0x91A5 # 0 +0xF150 0x91A7 # 0 +0xF151 0x91AF # 0 +0xF152 0x91AA # 0 +0xF153 0x93B5 # 0 +0xF154 0x938C # 0 +0xF155 0x9392 # 0 +0xF156 0x93B7 # 0 +0xF157 0x939B # 0 +0xF158 0x939D # 0 +0xF159 0x9389 # 0 +0xF15A 0x93A7 # 0 +0xF15B 0x938E # 0 +0xF15C 0x93AA # 0 +0xF15D 0x939E # 0 +0xF15E 0x93A6 # 0 +0xF15F 0x9395 # 0 +0xF160 0x9388 # 0 +0xF161 0x9399 # 0 +0xF162 0x939F # 0 +0xF163 0x938D # 0 +0xF164 0x93B1 # 0 +0xF165 0x9391 # 0 +0xF166 0x93B2 # 0 +0xF167 0x93A4 # 0 +0xF168 0x93A8 # 0 +0xF169 0x93B4 # 0 +0xF16A 0x93A3 # 0 +0xF16B 0x93A5 # 0 +0xF16C 0x95D2 # 0 +0xF16D 0x95D3 # 0 +0xF16E 0x95D1 # 0 +0xF16F 0x96B3 # 0 +0xF170 0x96D7 # 0 +0xF171 0x96DA # 0 +0xF172 0x5DC2 # 0 +0xF173 0x96DF # 0 +0xF174 0x96D8 # 0 +0xF175 0x96DD # 0 +0xF176 0x9723 # 0 +0xF177 0x9722 # 0 +0xF178 0x9725 # 0 +0xF179 0x97AC # 0 +0xF17A 0x97AE # 0 +0xF17B 0x97A8 # 0 +0xF17C 0x97AB # 0 +0xF17D 0x97A4 # 0 +0xF17E 0x97AA # 0 +0xF1A1 0x97A2 # 0 +0xF1A2 0x97A5 # 0 +0xF1A3 0x97D7 # 0 +0xF1A4 0x97D9 # 0 +0xF1A5 0x97D6 # 0 +0xF1A6 0x97D8 # 0 +0xF1A7 0x97FA # 0 +0xF1A8 0x9850 # 0 +0xF1A9 0x9851 # 0 +0xF1AA 0x9852 # 0 +0xF1AB 0x98B8 # 0 +0xF1AC 0x9941 # 0 +0xF1AD 0x993C # 0 +0xF1AE 0x993A # 0 +0xF1AF 0x9A0F # 0 +0xF1B0 0x9A0B # 0 +0xF1B1 0x9A09 # 0 +0xF1B2 0x9A0D # 0 +0xF1B3 0x9A04 # 0 +0xF1B4 0x9A11 # 0 +0xF1B5 0x9A0A # 0 +0xF1B6 0x9A05 # 0 +0xF1B7 0x9A07 # 0 +0xF1B8 0x9A06 # 0 +0xF1B9 0x9AC0 # 0 +0xF1BA 0x9ADC # 0 +0xF1BB 0x9B08 # 0 +0xF1BC 0x9B04 # 0 +0xF1BD 0x9B05 # 0 +0xF1BE 0x9B29 # 0 +0xF1BF 0x9B35 # 0 +0xF1C0 0x9B4A # 0 +0xF1C1 0x9B4C # 0 +0xF1C2 0x9B4B # 0 +0xF1C3 0x9BC7 # 0 +0xF1C4 0x9BC6 # 0 +0xF1C5 0x9BC3 # 0 +0xF1C6 0x9BBF # 0 +0xF1C7 0x9BC1 # 0 +0xF1C8 0x9BB5 # 0 +0xF1C9 0x9BB8 # 0 +0xF1CA 0x9BD3 # 0 +0xF1CB 0x9BB6 # 0 +0xF1CC 0x9BC4 # 0 +0xF1CD 0x9BB9 # 0 +0xF1CE 0x9BBD # 0 +0xF1CF 0x9D5C # 0 +0xF1D0 0x9D53 # 0 +0xF1D1 0x9D4F # 0 +0xF1D2 0x9D4A # 0 +0xF1D3 0x9D5B # 0 +0xF1D4 0x9D4B # 0 +0xF1D5 0x9D59 # 0 +0xF1D6 0x9D56 # 0 +0xF1D7 0x9D4C # 0 +0xF1D8 0x9D57 # 0 +0xF1D9 0x9D52 # 0 +0xF1DA 0x9D54 # 0 +0xF1DB 0x9D5F # 0 +0xF1DC 0x9D58 # 0 +0xF1DD 0x9D5A # 0 +0xF1DE 0x9E8E # 0 +0xF1DF 0x9E8C # 0 +0xF1E0 0x9EDF # 0 +0xF1E1 0x9F01 # 0 +0xF1E2 0x9F00 # 0 +0xF1E3 0x9F16 # 0 +0xF1E4 0x9F25 # 0 +0xF1E5 0x9F2B # 0 +0xF1E6 0x9F2A # 0 +0xF1E7 0x9F29 # 0 +0xF1E8 0x9F28 # 0 +0xF1E9 0x9F4C # 0 +0xF1EA 0x9F55 # 0 +0xF1EB 0x5134 # 0 +0xF1EC 0x5135 # 0 +0xF1ED 0x5296 # 0 +0xF1EE 0x52F7 # 0 +0xF1EF 0x53B4 # 0 +0xF1F0 0x56AB # 0 +0xF1F1 0x56AD # 0 +0xF1F2 0x56A6 # 0 +0xF1F3 0x56A7 # 0 +0xF1F4 0x56AA # 0 +0xF1F5 0x56AC # 0 +0xF1F6 0x58DA # 0 +0xF1F7 0x58DD # 0 +0xF1F8 0x58DB # 0 +0xF1F9 0x5912 # 0 +0xF1FA 0x5B3D # 0 +0xF1FB 0x5B3E # 0 +0xF1FC 0x5B3F # 0 +0xF1FD 0x5DC3 # 0 +0xF1FE 0x5E70 # 0 +0xF240 0x5FBF # 0 +0xF241 0x61FB # 0 +0xF242 0x6507 # 0 +0xF243 0x6510 # 0 +0xF244 0x650D # 0 +0xF245 0x6509 # 0 +0xF246 0x650C # 0 +0xF247 0x650E # 0 +0xF248 0x6584 # 0 +0xF249 0x65DE # 0 +0xF24A 0x65DD # 0 +0xF24B 0x66DE # 0 +0xF24C 0x6AE7 # 0 +0xF24D 0x6AE0 # 0 +0xF24E 0x6ACC # 0 +0xF24F 0x6AD1 # 0 +0xF250 0x6AD9 # 0 +0xF251 0x6ACB # 0 +0xF252 0x6ADF # 0 +0xF253 0x6ADC # 0 +0xF254 0x6AD0 # 0 +0xF255 0x6AEB # 0 +0xF256 0x6ACF # 0 +0xF257 0x6ACD # 0 +0xF258 0x6ADE # 0 +0xF259 0x6B60 # 0 +0xF25A 0x6BB0 # 0 +0xF25B 0x6C0C # 0 +0xF25C 0x7019 # 0 +0xF25D 0x7027 # 0 +0xF25E 0x7020 # 0 +0xF25F 0x7016 # 0 +0xF260 0x702B # 0 +0xF261 0x7021 # 0 +0xF262 0x7022 # 0 +0xF263 0x7023 # 0 +0xF264 0x7029 # 0 +0xF265 0x7017 # 0 +0xF266 0x7024 # 0 +0xF267 0x701C # 0 +0xF268 0x702A # 0 +0xF269 0x720C # 0 +0xF26A 0x720A # 0 +0xF26B 0x7207 # 0 +0xF26C 0x7202 # 0 +0xF26D 0x7205 # 0 +0xF26E 0x72A5 # 0 +0xF26F 0x72A6 # 0 +0xF270 0x72A4 # 0 +0xF271 0x72A3 # 0 +0xF272 0x72A1 # 0 +0xF273 0x74CB # 0 +0xF274 0x74C5 # 0 +0xF275 0x74B7 # 0 +0xF276 0x74C3 # 0 +0xF277 0x7516 # 0 +0xF278 0x7660 # 0 +0xF279 0x77C9 # 0 +0xF27A 0x77CA # 0 +0xF27B 0x77C4 # 0 +0xF27C 0x77F1 # 0 +0xF27D 0x791D # 0 +0xF27E 0x791B # 0 +0xF2A1 0x7921 # 0 +0xF2A2 0x791C # 0 +0xF2A3 0x7917 # 0 +0xF2A4 0x791E # 0 +0xF2A5 0x79B0 # 0 +0xF2A6 0x7A67 # 0 +0xF2A7 0x7A68 # 0 +0xF2A8 0x7C33 # 0 +0xF2A9 0x7C3C # 0 +0xF2AA 0x7C39 # 0 +0xF2AB 0x7C2C # 0 +0xF2AC 0x7C3B # 0 +0xF2AD 0x7CEC # 0 +0xF2AE 0x7CEA # 0 +0xF2AF 0x7E76 # 0 +0xF2B0 0x7E75 # 0 +0xF2B1 0x7E78 # 0 +0xF2B2 0x7E70 # 0 +0xF2B3 0x7E77 # 0 +0xF2B4 0x7E6F # 0 +0xF2B5 0x7E7A # 0 +0xF2B6 0x7E72 # 0 +0xF2B7 0x7E74 # 0 +0xF2B8 0x7E68 # 0 +0xF2B9 0x7F4B # 0 +0xF2BA 0x7F4A # 0 +0xF2BB 0x7F83 # 0 +0xF2BC 0x7F86 # 0 +0xF2BD 0x7FB7 # 0 +0xF2BE 0x7FFD # 0 +0xF2BF 0x7FFE # 0 +0xF2C0 0x8078 # 0 +0xF2C1 0x81D7 # 0 +0xF2C2 0x81D5 # 0 +0xF2C3 0x8264 # 0 +0xF2C4 0x8261 # 0 +0xF2C5 0x8263 # 0 +0xF2C6 0x85EB # 0 +0xF2C7 0x85F1 # 0 +0xF2C8 0x85ED # 0 +0xF2C9 0x85D9 # 0 +0xF2CA 0x85E1 # 0 +0xF2CB 0x85E8 # 0 +0xF2CC 0x85DA # 0 +0xF2CD 0x85D7 # 0 +0xF2CE 0x85EC # 0 +0xF2CF 0x85F2 # 0 +0xF2D0 0x85F8 # 0 +0xF2D1 0x85D8 # 0 +0xF2D2 0x85DF # 0 +0xF2D3 0x85E3 # 0 +0xF2D4 0x85DC # 0 +0xF2D5 0x85D1 # 0 +0xF2D6 0x85F0 # 0 +0xF2D7 0x85E6 # 0 +0xF2D8 0x85EF # 0 +0xF2D9 0x85DE # 0 +0xF2DA 0x85E2 # 0 +0xF2DB 0x8800 # 0 +0xF2DC 0x87FA # 0 +0xF2DD 0x8803 # 0 +0xF2DE 0x87F6 # 0 +0xF2DF 0x87F7 # 0 +0xF2E0 0x8809 # 0 +0xF2E1 0x880C # 0 +0xF2E2 0x880B # 0 +0xF2E3 0x8806 # 0 +0xF2E4 0x87FC # 0 +0xF2E5 0x8808 # 0 +0xF2E6 0x87FF # 0 +0xF2E7 0x880A # 0 +0xF2E8 0x8802 # 0 +0xF2E9 0x8962 # 0 +0xF2EA 0x895A # 0 +0xF2EB 0x895B # 0 +0xF2EC 0x8957 # 0 +0xF2ED 0x8961 # 0 +0xF2EE 0x895C # 0 +0xF2EF 0x8958 # 0 +0xF2F0 0x895D # 0 +0xF2F1 0x8959 # 0 +0xF2F2 0x8988 # 0 +0xF2F3 0x89B7 # 0 +0xF2F4 0x89B6 # 0 +0xF2F5 0x89F6 # 0 +0xF2F6 0x8B50 # 0 +0xF2F7 0x8B48 # 0 +0xF2F8 0x8B4A # 0 +0xF2F9 0x8B40 # 0 +0xF2FA 0x8B53 # 0 +0xF2FB 0x8B56 # 0 +0xF2FC 0x8B54 # 0 +0xF2FD 0x8B4B # 0 +0xF2FE 0x8B55 # 0 +0xF340 0x8B51 # 0 +0xF341 0x8B42 # 0 +0xF342 0x8B52 # 0 +0xF343 0x8B57 # 0 +0xF344 0x8C43 # 0 +0xF345 0x8C77 # 0 +0xF346 0x8C76 # 0 +0xF347 0x8C9A # 0 +0xF348 0x8D06 # 0 +0xF349 0x8D07 # 0 +0xF34A 0x8D09 # 0 +0xF34B 0x8DAC # 0 +0xF34C 0x8DAA # 0 +0xF34D 0x8DAD # 0 +0xF34E 0x8DAB # 0 +0xF34F 0x8E6D # 0 +0xF350 0x8E78 # 0 +0xF351 0x8E73 # 0 +0xF352 0x8E6A # 0 +0xF353 0x8E6F # 0 +0xF354 0x8E7B # 0 +0xF355 0x8EC2 # 0 +0xF356 0x8F52 # 0 +0xF357 0x8F51 # 0 +0xF358 0x8F4F # 0 +0xF359 0x8F50 # 0 +0xF35A 0x8F53 # 0 +0xF35B 0x8FB4 # 0 +0xF35C 0x9140 # 0 +0xF35D 0x913F # 0 +0xF35E 0x91B0 # 0 +0xF35F 0x91AD # 0 +0xF360 0x93DE # 0 +0xF361 0x93C7 # 0 +0xF362 0x93CF # 0 +0xF363 0x93C2 # 0 +0xF364 0x93DA # 0 +0xF365 0x93D0 # 0 +0xF366 0x93F9 # 0 +0xF367 0x93EC # 0 +0xF368 0x93CC # 0 +0xF369 0x93D9 # 0 +0xF36A 0x93A9 # 0 +0xF36B 0x93E6 # 0 +0xF36C 0x93CA # 0 +0xF36D 0x93D4 # 0 +0xF36E 0x93EE # 0 +0xF36F 0x93E3 # 0 +0xF370 0x93D5 # 0 +0xF371 0x93C4 # 0 +0xF372 0x93CE # 0 +0xF373 0x93C0 # 0 +0xF374 0x93D2 # 0 +0xF375 0x93E7 # 0 +0xF376 0x957D # 0 +0xF377 0x95DA # 0 +0xF378 0x95DB # 0 +0xF379 0x96E1 # 0 +0xF37A 0x9729 # 0 +0xF37B 0x972B # 0 +0xF37C 0x972C # 0 +0xF37D 0x9728 # 0 +0xF37E 0x9726 # 0 +0xF3A1 0x97B3 # 0 +0xF3A2 0x97B7 # 0 +0xF3A3 0x97B6 # 0 +0xF3A4 0x97DD # 0 +0xF3A5 0x97DE # 0 +0xF3A6 0x97DF # 0 +0xF3A7 0x985C # 0 +0xF3A8 0x9859 # 0 +0xF3A9 0x985D # 0 +0xF3AA 0x9857 # 0 +0xF3AB 0x98BF # 0 +0xF3AC 0x98BD # 0 +0xF3AD 0x98BB # 0 +0xF3AE 0x98BE # 0 +0xF3AF 0x9948 # 0 +0xF3B0 0x9947 # 0 +0xF3B1 0x9943 # 0 +0xF3B2 0x99A6 # 0 +0xF3B3 0x99A7 # 0 +0xF3B4 0x9A1A # 0 +0xF3B5 0x9A15 # 0 +0xF3B6 0x9A25 # 0 +0xF3B7 0x9A1D # 0 +0xF3B8 0x9A24 # 0 +0xF3B9 0x9A1B # 0 +0xF3BA 0x9A22 # 0 +0xF3BB 0x9A20 # 0 +0xF3BC 0x9A27 # 0 +0xF3BD 0x9A23 # 0 +0xF3BE 0x9A1E # 0 +0xF3BF 0x9A1C # 0 +0xF3C0 0x9A14 # 0 +0xF3C1 0x9AC2 # 0 +0xF3C2 0x9B0B # 0 +0xF3C3 0x9B0A # 0 +0xF3C4 0x9B0E # 0 +0xF3C5 0x9B0C # 0 +0xF3C6 0x9B37 # 0 +0xF3C7 0x9BEA # 0 +0xF3C8 0x9BEB # 0 +0xF3C9 0x9BE0 # 0 +0xF3CA 0x9BDE # 0 +0xF3CB 0x9BE4 # 0 +0xF3CC 0x9BE6 # 0 +0xF3CD 0x9BE2 # 0 +0xF3CE 0x9BF0 # 0 +0xF3CF 0x9BD4 # 0 +0xF3D0 0x9BD7 # 0 +0xF3D1 0x9BEC # 0 +0xF3D2 0x9BDC # 0 +0xF3D3 0x9BD9 # 0 +0xF3D4 0x9BE5 # 0 +0xF3D5 0x9BD5 # 0 +0xF3D6 0x9BE1 # 0 +0xF3D7 0x9BDA # 0 +0xF3D8 0x9D77 # 0 +0xF3D9 0x9D81 # 0 +0xF3DA 0x9D8A # 0 +0xF3DB 0x9D84 # 0 +0xF3DC 0x9D88 # 0 +0xF3DD 0x9D71 # 0 +0xF3DE 0x9D80 # 0 +0xF3DF 0x9D78 # 0 +0xF3E0 0x9D86 # 0 +0xF3E1 0x9D8B # 0 +0xF3E2 0x9D8C # 0 +0xF3E3 0x9D7D # 0 +0xF3E4 0x9D6B # 0 +0xF3E5 0x9D74 # 0 +0xF3E6 0x9D75 # 0 +0xF3E7 0x9D70 # 0 +0xF3E8 0x9D69 # 0 +0xF3E9 0x9D85 # 0 +0xF3EA 0x9D73 # 0 +0xF3EB 0x9D7B # 0 +0xF3EC 0x9D82 # 0 +0xF3ED 0x9D6F # 0 +0xF3EE 0x9D79 # 0 +0xF3EF 0x9D7F # 0 +0xF3F0 0x9D87 # 0 +0xF3F1 0x9D68 # 0 +0xF3F2 0x9E94 # 0 +0xF3F3 0x9E91 # 0 +0xF3F4 0x9EC0 # 0 +0xF3F5 0x9EFC # 0 +0xF3F6 0x9F2D # 0 +0xF3F7 0x9F40 # 0 +0xF3F8 0x9F41 # 0 +0xF3F9 0x9F4D # 0 +0xF3FA 0x9F56 # 0 +0xF3FB 0x9F57 # 0 +0xF3FC 0x9F58 # 0 +0xF3FD 0x5337 # 0 +0xF3FE 0x56B2 # 0 +0xF440 0x56B5 # 0 +0xF441 0x56B3 # 0 +0xF442 0x58E3 # 0 +0xF443 0x5B45 # 0 +0xF444 0x5DC6 # 0 +0xF445 0x5DC7 # 0 +0xF446 0x5EEE # 0 +0xF447 0x5EEF # 0 +0xF448 0x5FC0 # 0 +0xF449 0x5FC1 # 0 +0xF44A 0x61F9 # 0 +0xF44B 0x6517 # 0 +0xF44C 0x6516 # 0 +0xF44D 0x6515 # 0 +0xF44E 0x6513 # 0 +0xF44F 0x65DF # 0 +0xF450 0x66E8 # 0 +0xF451 0x66E3 # 0 +0xF452 0x66E4 # 0 +0xF453 0x6AF3 # 0 +0xF454 0x6AF0 # 0 +0xF455 0x6AEA # 0 +0xF456 0x6AE8 # 0 +0xF457 0x6AF9 # 0 +0xF458 0x6AF1 # 0 +0xF459 0x6AEE # 0 +0xF45A 0x6AEF # 0 +0xF45B 0x703C # 0 +0xF45C 0x7035 # 0 +0xF45D 0x702F # 0 +0xF45E 0x7037 # 0 +0xF45F 0x7034 # 0 +0xF460 0x7031 # 0 +0xF461 0x7042 # 0 +0xF462 0x7038 # 0 +0xF463 0x703F # 0 +0xF464 0x703A # 0 +0xF465 0x7039 # 0 +0xF466 0x7040 # 0 +0xF467 0x703B # 0 +0xF468 0x7033 # 0 +0xF469 0x7041 # 0 +0xF46A 0x7213 # 0 +0xF46B 0x7214 # 0 +0xF46C 0x72A8 # 0 +0xF46D 0x737D # 0 +0xF46E 0x737C # 0 +0xF46F 0x74BA # 0 +0xF470 0x76AB # 0 +0xF471 0x76AA # 0 +0xF472 0x76BE # 0 +0xF473 0x76ED # 0 +0xF474 0x77CC # 0 +0xF475 0x77CE # 0 +0xF476 0x77CF # 0 +0xF477 0x77CD # 0 +0xF478 0x77F2 # 0 +0xF479 0x7925 # 0 +0xF47A 0x7923 # 0 +0xF47B 0x7927 # 0 +0xF47C 0x7928 # 0 +0xF47D 0x7924 # 0 +0xF47E 0x7929 # 0 +0xF4A1 0x79B2 # 0 +0xF4A2 0x7A6E # 0 +0xF4A3 0x7A6C # 0 +0xF4A4 0x7A6D # 0 +0xF4A5 0x7AF7 # 0 +0xF4A6 0x7C49 # 0 +0xF4A7 0x7C48 # 0 +0xF4A8 0x7C4A # 0 +0xF4A9 0x7C47 # 0 +0xF4AA 0x7C45 # 0 +0xF4AB 0x7CEE # 0 +0xF4AC 0x7E7B # 0 +0xF4AD 0x7E7E # 0 +0xF4AE 0x7E81 # 0 +0xF4AF 0x7E80 # 0 +0xF4B0 0x7FBA # 0 +0xF4B1 0x7FFF # 0 +0xF4B2 0x8079 # 0 +0xF4B3 0x81DB # 0 +0xF4B4 0x81D9 # 0 +0xF4B5 0x820B # 0 +0xF4B6 0x8268 # 0 +0xF4B7 0x8269 # 0 +0xF4B8 0x8622 # 0 +0xF4B9 0x85FF # 0 +0xF4BA 0x8601 # 0 +0xF4BB 0x85FE # 0 +0xF4BC 0x861B # 0 +0xF4BD 0x8600 # 0 +0xF4BE 0x85F6 # 0 +0xF4BF 0x8604 # 0 +0xF4C0 0x8609 # 0 +0xF4C1 0x8605 # 0 +0xF4C2 0x860C # 0 +0xF4C3 0x85FD # 0 +0xF4C4 0x8819 # 0 +0xF4C5 0x8810 # 0 +0xF4C6 0x8811 # 0 +0xF4C7 0x8817 # 0 +0xF4C8 0x8813 # 0 +0xF4C9 0x8816 # 0 +0xF4CA 0x8963 # 0 +0xF4CB 0x8966 # 0 +0xF4CC 0x89B9 # 0 +0xF4CD 0x89F7 # 0 +0xF4CE 0x8B60 # 0 +0xF4CF 0x8B6A # 0 +0xF4D0 0x8B5D # 0 +0xF4D1 0x8B68 # 0 +0xF4D2 0x8B63 # 0 +0xF4D3 0x8B65 # 0 +0xF4D4 0x8B67 # 0 +0xF4D5 0x8B6D # 0 +0xF4D6 0x8DAE # 0 +0xF4D7 0x8E86 # 0 +0xF4D8 0x8E88 # 0 +0xF4D9 0x8E84 # 0 +0xF4DA 0x8F59 # 0 +0xF4DB 0x8F56 # 0 +0xF4DC 0x8F57 # 0 +0xF4DD 0x8F55 # 0 +0xF4DE 0x8F58 # 0 +0xF4DF 0x8F5A # 0 +0xF4E0 0x908D # 0 +0xF4E1 0x9143 # 0 +0xF4E2 0x9141 # 0 +0xF4E3 0x91B7 # 0 +0xF4E4 0x91B5 # 0 +0xF4E5 0x91B2 # 0 +0xF4E6 0x91B3 # 0 +0xF4E7 0x940B # 0 +0xF4E8 0x9413 # 0 +0xF4E9 0x93FB # 0 +0xF4EA 0x9420 # 0 +0xF4EB 0x940F # 0 +0xF4EC 0x9414 # 0 +0xF4ED 0x93FE # 0 +0xF4EE 0x9415 # 0 +0xF4EF 0x9410 # 0 +0xF4F0 0x9428 # 0 +0xF4F1 0x9419 # 0 +0xF4F2 0x940D # 0 +0xF4F3 0x93F5 # 0 +0xF4F4 0x9400 # 0 +0xF4F5 0x93F7 # 0 +0xF4F6 0x9407 # 0 +0xF4F7 0x940E # 0 +0xF4F8 0x9416 # 0 +0xF4F9 0x9412 # 0 +0xF4FA 0x93FA # 0 +0xF4FB 0x9409 # 0 +0xF4FC 0x93F8 # 0 +0xF4FD 0x940A # 0 +0xF4FE 0x93FF # 0 +0xF540 0x93FC # 0 +0xF541 0x940C # 0 +0xF542 0x93F6 # 0 +0xF543 0x9411 # 0 +0xF544 0x9406 # 0 +0xF545 0x95DE # 0 +0xF546 0x95E0 # 0 +0xF547 0x95DF # 0 +0xF548 0x972E # 0 +0xF549 0x972F # 0 +0xF54A 0x97B9 # 0 +0xF54B 0x97BB # 0 +0xF54C 0x97FD # 0 +0xF54D 0x97FE # 0 +0xF54E 0x9860 # 0 +0xF54F 0x9862 # 0 +0xF550 0x9863 # 0 +0xF551 0x985F # 0 +0xF552 0x98C1 # 0 +0xF553 0x98C2 # 0 +0xF554 0x9950 # 0 +0xF555 0x994E # 0 +0xF556 0x9959 # 0 +0xF557 0x994C # 0 +0xF558 0x994B # 0 +0xF559 0x9953 # 0 +0xF55A 0x9A32 # 0 +0xF55B 0x9A34 # 0 +0xF55C 0x9A31 # 0 +0xF55D 0x9A2C # 0 +0xF55E 0x9A2A # 0 +0xF55F 0x9A36 # 0 +0xF560 0x9A29 # 0 +0xF561 0x9A2E # 0 +0xF562 0x9A38 # 0 +0xF563 0x9A2D # 0 +0xF564 0x9AC7 # 0 +0xF565 0x9ACA # 0 +0xF566 0x9AC6 # 0 +0xF567 0x9B10 # 0 +0xF568 0x9B12 # 0 +0xF569 0x9B11 # 0 +0xF56A 0x9C0B # 0 +0xF56B 0x9C08 # 0 +0xF56C 0x9BF7 # 0 +0xF56D 0x9C05 # 0 +0xF56E 0x9C12 # 0 +0xF56F 0x9BF8 # 0 +0xF570 0x9C40 # 0 +0xF571 0x9C07 # 0 +0xF572 0x9C0E # 0 +0xF573 0x9C06 # 0 +0xF574 0x9C17 # 0 +0xF575 0x9C14 # 0 +0xF576 0x9C09 # 0 +0xF577 0x9D9F # 0 +0xF578 0x9D99 # 0 +0xF579 0x9DA4 # 0 +0xF57A 0x9D9D # 0 +0xF57B 0x9D92 # 0 +0xF57C 0x9D98 # 0 +0xF57D 0x9D90 # 0 +0xF57E 0x9D9B # 0 +0xF5A1 0x9DA0 # 0 +0xF5A2 0x9D94 # 0 +0xF5A3 0x9D9C # 0 +0xF5A4 0x9DAA # 0 +0xF5A5 0x9D97 # 0 +0xF5A6 0x9DA1 # 0 +0xF5A7 0x9D9A # 0 +0xF5A8 0x9DA2 # 0 +0xF5A9 0x9DA8 # 0 +0xF5AA 0x9D9E # 0 +0xF5AB 0x9DA3 # 0 +0xF5AC 0x9DBF # 0 +0xF5AD 0x9DA9 # 0 +0xF5AE 0x9D96 # 0 +0xF5AF 0x9DA6 # 0 +0xF5B0 0x9DA7 # 0 +0xF5B1 0x9E99 # 0 +0xF5B2 0x9E9B # 0 +0xF5B3 0x9E9A # 0 +0xF5B4 0x9EE5 # 0 +0xF5B5 0x9EE4 # 0 +0xF5B6 0x9EE7 # 0 +0xF5B7 0x9EE6 # 0 +0xF5B8 0x9F30 # 0 +0xF5B9 0x9F2E # 0 +0xF5BA 0x9F5B # 0 +0xF5BB 0x9F60 # 0 +0xF5BC 0x9F5E # 0 +0xF5BD 0x9F5D # 0 +0xF5BE 0x9F59 # 0 +0xF5BF 0x9F91 # 0 +0xF5C0 0x513A # 0 +0xF5C1 0x5139 # 0 +0xF5C2 0x5298 # 0 +0xF5C3 0x5297 # 0 +0xF5C4 0x56C3 # 0 +0xF5C5 0x56BD # 0 +0xF5C6 0x56BE # 0 +0xF5C7 0x5B48 # 0 +0xF5C8 0x5B47 # 0 +0xF5C9 0x5DCB # 0 +0xF5CA 0x5DCF # 0 +0xF5CB 0x5EF1 # 0 +0xF5CC 0x61FD # 0 +0xF5CD 0x651B # 0 +0xF5CE 0x6B02 # 0 +0xF5CF 0x6AFC # 0 +0xF5D0 0x6B03 # 0 +0xF5D1 0x6AF8 # 0 +0xF5D2 0x6B00 # 0 +0xF5D3 0x7043 # 0 +0xF5D4 0x7044 # 0 +0xF5D5 0x704A # 0 +0xF5D6 0x7048 # 0 +0xF5D7 0x7049 # 0 +0xF5D8 0x7045 # 0 +0xF5D9 0x7046 # 0 +0xF5DA 0x721D # 0 +0xF5DB 0x721A # 0 +0xF5DC 0x7219 # 0 +0xF5DD 0x737E # 0 +0xF5DE 0x7517 # 0 +0xF5DF 0x766A # 0 +0xF5E0 0x77D0 # 0 +0xF5E1 0x792D # 0 +0xF5E2 0x7931 # 0 +0xF5E3 0x792F # 0 +0xF5E4 0x7C54 # 0 +0xF5E5 0x7C53 # 0 +0xF5E6 0x7CF2 # 0 +0xF5E7 0x7E8A # 0 +0xF5E8 0x7E87 # 0 +0xF5E9 0x7E88 # 0 +0xF5EA 0x7E8B # 0 +0xF5EB 0x7E86 # 0 +0xF5EC 0x7E8D # 0 +0xF5ED 0x7F4D # 0 +0xF5EE 0x7FBB # 0 +0xF5EF 0x8030 # 0 +0xF5F0 0x81DD # 0 +0xF5F1 0x8618 # 0 +0xF5F2 0x862A # 0 +0xF5F3 0x8626 # 0 +0xF5F4 0x861F # 0 +0xF5F5 0x8623 # 0 +0xF5F6 0x861C # 0 +0xF5F7 0x8619 # 0 +0xF5F8 0x8627 # 0 +0xF5F9 0x862E # 0 +0xF5FA 0x8621 # 0 +0xF5FB 0x8620 # 0 +0xF5FC 0x8629 # 0 +0xF5FD 0x861E # 0 +0xF5FE 0x8625 # 0 +0xF640 0x8829 # 0 +0xF641 0x881D # 0 +0xF642 0x881B # 0 +0xF643 0x8820 # 0 +0xF644 0x8824 # 0 +0xF645 0x881C # 0 +0xF646 0x882B # 0 +0xF647 0x884A # 0 +0xF648 0x896D # 0 +0xF649 0x8969 # 0 +0xF64A 0x896E # 0 +0xF64B 0x896B # 0 +0xF64C 0x89FA # 0 +0xF64D 0x8B79 # 0 +0xF64E 0x8B78 # 0 +0xF64F 0x8B45 # 0 +0xF650 0x8B7A # 0 +0xF651 0x8B7B # 0 +0xF652 0x8D10 # 0 +0xF653 0x8D14 # 0 +0xF654 0x8DAF # 0 +0xF655 0x8E8E # 0 +0xF656 0x8E8C # 0 +0xF657 0x8F5E # 0 +0xF658 0x8F5B # 0 +0xF659 0x8F5D # 0 +0xF65A 0x9146 # 0 +0xF65B 0x9144 # 0 +0xF65C 0x9145 # 0 +0xF65D 0x91B9 # 0 +0xF65E 0x943F # 0 +0xF65F 0x943B # 0 +0xF660 0x9436 # 0 +0xF661 0x9429 # 0 +0xF662 0x943D # 0 +0xF663 0x943C # 0 +0xF664 0x9430 # 0 +0xF665 0x9439 # 0 +0xF666 0x942A # 0 +0xF667 0x9437 # 0 +0xF668 0x942C # 0 +0xF669 0x9440 # 0 +0xF66A 0x9431 # 0 +0xF66B 0x95E5 # 0 +0xF66C 0x95E4 # 0 +0xF66D 0x95E3 # 0 +0xF66E 0x9735 # 0 +0xF66F 0x973A # 0 +0xF670 0x97BF # 0 +0xF671 0x97E1 # 0 +0xF672 0x9864 # 0 +0xF673 0x98C9 # 0 +0xF674 0x98C6 # 0 +0xF675 0x98C0 # 0 +0xF676 0x9958 # 0 +0xF677 0x9956 # 0 +0xF678 0x9A39 # 0 +0xF679 0x9A3D # 0 +0xF67A 0x9A46 # 0 +0xF67B 0x9A44 # 0 +0xF67C 0x9A42 # 0 +0xF67D 0x9A41 # 0 +0xF67E 0x9A3A # 0 +0xF6A1 0x9A3F # 0 +0xF6A2 0x9ACD # 0 +0xF6A3 0x9B15 # 0 +0xF6A4 0x9B17 # 0 +0xF6A5 0x9B18 # 0 +0xF6A6 0x9B16 # 0 +0xF6A7 0x9B3A # 0 +0xF6A8 0x9B52 # 0 +0xF6A9 0x9C2B # 0 +0xF6AA 0x9C1D # 0 +0xF6AB 0x9C1C # 0 +0xF6AC 0x9C2C # 0 +0xF6AD 0x9C23 # 0 +0xF6AE 0x9C28 # 0 +0xF6AF 0x9C29 # 0 +0xF6B0 0x9C24 # 0 +0xF6B1 0x9C21 # 0 +0xF6B2 0x9DB7 # 0 +0xF6B3 0x9DB6 # 0 +0xF6B4 0x9DBC # 0 +0xF6B5 0x9DC1 # 0 +0xF6B6 0x9DC7 # 0 +0xF6B7 0x9DCA # 0 +0xF6B8 0x9DCF # 0 +0xF6B9 0x9DBE # 0 +0xF6BA 0x9DC5 # 0 +0xF6BB 0x9DC3 # 0 +0xF6BC 0x9DBB # 0 +0xF6BD 0x9DB5 # 0 +0xF6BE 0x9DCE # 0 +0xF6BF 0x9DB9 # 0 +0xF6C0 0x9DBA # 0 +0xF6C1 0x9DAC # 0 +0xF6C2 0x9DC8 # 0 +0xF6C3 0x9DB1 # 0 +0xF6C4 0x9DAD # 0 +0xF6C5 0x9DCC # 0 +0xF6C6 0x9DB3 # 0 +0xF6C7 0x9DCD # 0 +0xF6C8 0x9DB2 # 0 +0xF6C9 0x9E7A # 0 +0xF6CA 0x9E9C # 0 +0xF6CB 0x9EEB # 0 +0xF6CC 0x9EEE # 0 +0xF6CD 0x9EED # 0 +0xF6CE 0x9F1B # 0 +0xF6CF 0x9F18 # 0 +0xF6D0 0x9F1A # 0 +0xF6D1 0x9F31 # 0 +0xF6D2 0x9F4E # 0 +0xF6D3 0x9F65 # 0 +0xF6D4 0x9F64 # 0 +0xF6D5 0x9F92 # 0 +0xF6D6 0x4EB9 # 0 +0xF6D7 0x56C6 # 0 +0xF6D8 0x56C5 # 0 +0xF6D9 0x56CB # 0 +0xF6DA 0x5971 # 0 +0xF6DB 0x5B4B # 0 +0xF6DC 0x5B4C # 0 +0xF6DD 0x5DD5 # 0 +0xF6DE 0x5DD1 # 0 +0xF6DF 0x5EF2 # 0 +0xF6E0 0x6521 # 0 +0xF6E1 0x6520 # 0 +0xF6E2 0x6526 # 0 +0xF6E3 0x6522 # 0 +0xF6E4 0x6B0B # 0 +0xF6E5 0x6B08 # 0 +0xF6E6 0x6B09 # 0 +0xF6E7 0x6C0D # 0 +0xF6E8 0x7055 # 0 +0xF6E9 0x7056 # 0 +0xF6EA 0x7057 # 0 +0xF6EB 0x7052 # 0 +0xF6EC 0x721E # 0 +0xF6ED 0x721F # 0 +0xF6EE 0x72A9 # 0 +0xF6EF 0x737F # 0 +0xF6F0 0x74D8 # 0 +0xF6F1 0x74D5 # 0 +0xF6F2 0x74D9 # 0 +0xF6F3 0x74D7 # 0 +0xF6F4 0x766D # 0 +0xF6F5 0x76AD # 0 +0xF6F6 0x7935 # 0 +0xF6F7 0x79B4 # 0 +0xF6F8 0x7A70 # 0 +0xF6F9 0x7A71 # 0 +0xF6FA 0x7C57 # 0 +0xF6FB 0x7C5C # 0 +0xF6FC 0x7C59 # 0 +0xF6FD 0x7C5B # 0 +0xF6FE 0x7C5A # 0 +0xF740 0x7CF4 # 0 +0xF741 0x7CF1 # 0 +0xF742 0x7E91 # 0 +0xF743 0x7F4F # 0 +0xF744 0x7F87 # 0 +0xF745 0x81DE # 0 +0xF746 0x826B # 0 +0xF747 0x8634 # 0 +0xF748 0x8635 # 0 +0xF749 0x8633 # 0 +0xF74A 0x862C # 0 +0xF74B 0x8632 # 0 +0xF74C 0x8636 # 0 +0xF74D 0x882C # 0 +0xF74E 0x8828 # 0 +0xF74F 0x8826 # 0 +0xF750 0x882A # 0 +0xF751 0x8825 # 0 +0xF752 0x8971 # 0 +0xF753 0x89BF # 0 +0xF754 0x89BE # 0 +0xF755 0x89FB # 0 +0xF756 0x8B7E # 0 +0xF757 0x8B84 # 0 +0xF758 0x8B82 # 0 +0xF759 0x8B86 # 0 +0xF75A 0x8B85 # 0 +0xF75B 0x8B7F # 0 +0xF75C 0x8D15 # 0 +0xF75D 0x8E95 # 0 +0xF75E 0x8E94 # 0 +0xF75F 0x8E9A # 0 +0xF760 0x8E92 # 0 +0xF761 0x8E90 # 0 +0xF762 0x8E96 # 0 +0xF763 0x8E97 # 0 +0xF764 0x8F60 # 0 +0xF765 0x8F62 # 0 +0xF766 0x9147 # 0 +0xF767 0x944C # 0 +0xF768 0x9450 # 0 +0xF769 0x944A # 0 +0xF76A 0x944B # 0 +0xF76B 0x944F # 0 +0xF76C 0x9447 # 0 +0xF76D 0x9445 # 0 +0xF76E 0x9448 # 0 +0xF76F 0x9449 # 0 +0xF770 0x9446 # 0 +0xF771 0x973F # 0 +0xF772 0x97E3 # 0 +0xF773 0x986A # 0 +0xF774 0x9869 # 0 +0xF775 0x98CB # 0 +0xF776 0x9954 # 0 +0xF777 0x995B # 0 +0xF778 0x9A4E # 0 +0xF779 0x9A53 # 0 +0xF77A 0x9A54 # 0 +0xF77B 0x9A4C # 0 +0xF77C 0x9A4F # 0 +0xF77D 0x9A48 # 0 +0xF77E 0x9A4A # 0 +0xF7A1 0x9A49 # 0 +0xF7A2 0x9A52 # 0 +0xF7A3 0x9A50 # 0 +0xF7A4 0x9AD0 # 0 +0xF7A5 0x9B19 # 0 +0xF7A6 0x9B2B # 0 +0xF7A7 0x9B3B # 0 +0xF7A8 0x9B56 # 0 +0xF7A9 0x9B55 # 0 +0xF7AA 0x9C46 # 0 +0xF7AB 0x9C48 # 0 +0xF7AC 0x9C3F # 0 +0xF7AD 0x9C44 # 0 +0xF7AE 0x9C39 # 0 +0xF7AF 0x9C33 # 0 +0xF7B0 0x9C41 # 0 +0xF7B1 0x9C3C # 0 +0xF7B2 0x9C37 # 0 +0xF7B3 0x9C34 # 0 +0xF7B4 0x9C32 # 0 +0xF7B5 0x9C3D # 0 +0xF7B6 0x9C36 # 0 +0xF7B7 0x9DDB # 0 +0xF7B8 0x9DD2 # 0 +0xF7B9 0x9DDE # 0 +0xF7BA 0x9DDA # 0 +0xF7BB 0x9DCB # 0 +0xF7BC 0x9DD0 # 0 +0xF7BD 0x9DDC # 0 +0xF7BE 0x9DD1 # 0 +0xF7BF 0x9DDF # 0 +0xF7C0 0x9DE9 # 0 +0xF7C1 0x9DD9 # 0 +0xF7C2 0x9DD8 # 0 +0xF7C3 0x9DD6 # 0 +0xF7C4 0x9DF5 # 0 +0xF7C5 0x9DD5 # 0 +0xF7C6 0x9DDD # 0 +0xF7C7 0x9EB6 # 0 +0xF7C8 0x9EF0 # 0 +0xF7C9 0x9F35 # 0 +0xF7CA 0x9F33 # 0 +0xF7CB 0x9F32 # 0 +0xF7CC 0x9F42 # 0 +0xF7CD 0x9F6B # 0 +0xF7CE 0x9F95 # 0 +0xF7CF 0x9FA2 # 0 +0xF7D0 0x513D # 0 +0xF7D1 0x5299 # 0 +0xF7D2 0x58E8 # 0 +0xF7D3 0x58E7 # 0 +0xF7D4 0x5972 # 0 +0xF7D5 0x5B4D # 0 +0xF7D6 0x5DD8 # 0 +0xF7D7 0x882F # 0 +0xF7D8 0x5F4F # 0 +0xF7D9 0x6201 # 0 +0xF7DA 0x6203 # 0 +0xF7DB 0x6204 # 0 +0xF7DC 0x6529 # 0 +0xF7DD 0x6525 # 0 +0xF7DE 0x6596 # 0 +0xF7DF 0x66EB # 0 +0xF7E0 0x6B11 # 0 +0xF7E1 0x6B12 # 0 +0xF7E2 0x6B0F # 0 +0xF7E3 0x6BCA # 0 +0xF7E4 0x705B # 0 +0xF7E5 0x705A # 0 +0xF7E6 0x7222 # 0 +0xF7E7 0x7382 # 0 +0xF7E8 0x7381 # 0 +0xF7E9 0x7383 # 0 +0xF7EA 0x7670 # 0 +0xF7EB 0x77D4 # 0 +0xF7EC 0x7C67 # 0 +0xF7ED 0x7C66 # 0 +0xF7EE 0x7E95 # 0 +0xF7EF 0x826C # 0 +0xF7F0 0x863A # 0 +0xF7F1 0x8640 # 0 +0xF7F2 0x8639 # 0 +0xF7F3 0x863C # 0 +0xF7F4 0x8631 # 0 +0xF7F5 0x863B # 0 +0xF7F6 0x863E # 0 +0xF7F7 0x8830 # 0 +0xF7F8 0x8832 # 0 +0xF7F9 0x882E # 0 +0xF7FA 0x8833 # 0 +0xF7FB 0x8976 # 0 +0xF7FC 0x8974 # 0 +0xF7FD 0x8973 # 0 +0xF7FE 0x89FE # 0 +0xF840 0x8B8C # 0 +0xF841 0x8B8E # 0 +0xF842 0x8B8B # 0 +0xF843 0x8B88 # 0 +0xF844 0x8C45 # 0 +0xF845 0x8D19 # 0 +0xF846 0x8E98 # 0 +0xF847 0x8F64 # 0 +0xF848 0x8F63 # 0 +0xF849 0x91BC # 0 +0xF84A 0x9462 # 0 +0xF84B 0x9455 # 0 +0xF84C 0x945D # 0 +0xF84D 0x9457 # 0 +0xF84E 0x945E # 0 +0xF84F 0x97C4 # 0 +0xF850 0x97C5 # 0 +0xF851 0x9800 # 0 +0xF852 0x9A56 # 0 +0xF853 0x9A59 # 0 +0xF854 0x9B1E # 0 +0xF855 0x9B1F # 0 +0xF856 0x9B20 # 0 +0xF857 0x9C52 # 0 +0xF858 0x9C58 # 0 +0xF859 0x9C50 # 0 +0xF85A 0x9C4A # 0 +0xF85B 0x9C4D # 0 +0xF85C 0x9C4B # 0 +0xF85D 0x9C55 # 0 +0xF85E 0x9C59 # 0 +0xF85F 0x9C4C # 0 +0xF860 0x9C4E # 0 +0xF861 0x9DFB # 0 +0xF862 0x9DF7 # 0 +0xF863 0x9DEF # 0 +0xF864 0x9DE3 # 0 +0xF865 0x9DEB # 0 +0xF866 0x9DF8 # 0 +0xF867 0x9DE4 # 0 +0xF868 0x9DF6 # 0 +0xF869 0x9DE1 # 0 +0xF86A 0x9DEE # 0 +0xF86B 0x9DE6 # 0 +0xF86C 0x9DF2 # 0 +0xF86D 0x9DF0 # 0 +0xF86E 0x9DE2 # 0 +0xF86F 0x9DEC # 0 +0xF870 0x9DF4 # 0 +0xF871 0x9DF3 # 0 +0xF872 0x9DE8 # 0 +0xF873 0x9DED # 0 +0xF874 0x9EC2 # 0 +0xF875 0x9ED0 # 0 +0xF876 0x9EF2 # 0 +0xF877 0x9EF3 # 0 +0xF878 0x9F06 # 0 +0xF879 0x9F1C # 0 +0xF87A 0x9F38 # 0 +0xF87B 0x9F37 # 0 +0xF87C 0x9F36 # 0 +0xF87D 0x9F43 # 0 +0xF87E 0x9F4F # 0 +0xF8A1 0x9F71 # 0 +0xF8A2 0x9F70 # 0 +0xF8A3 0x9F6E # 0 +0xF8A4 0x9F6F # 0 +0xF8A5 0x56D3 # 0 +0xF8A6 0x56CD # 0 +0xF8A7 0x5B4E # 0 +0xF8A8 0x5C6D # 0 +0xF8A9 0x652D # 0 +0xF8AA 0x66ED # 0 +0xF8AB 0x66EE # 0 +0xF8AC 0x6B13 # 0 +0xF8AD 0x705F # 0 +0xF8AE 0x7061 # 0 +0xF8AF 0x705D # 0 +0xF8B0 0x7060 # 0 +0xF8B1 0x7223 # 0 +0xF8B2 0x74DB # 0 +0xF8B3 0x74E5 # 0 +0xF8B4 0x77D5 # 0 +0xF8B5 0x7938 # 0 +0xF8B6 0x79B7 # 0 +0xF8B7 0x79B6 # 0 +0xF8B8 0x7C6A # 0 +0xF8B9 0x7E97 # 0 +0xF8BA 0x7F89 # 0 +0xF8BB 0x826D # 0 +0xF8BC 0x8643 # 0 +0xF8BD 0x8838 # 0 +0xF8BE 0x8837 # 0 +0xF8BF 0x8835 # 0 +0xF8C0 0x884B # 0 +0xF8C1 0x8B94 # 0 +0xF8C2 0x8B95 # 0 +0xF8C3 0x8E9E # 0 +0xF8C4 0x8E9F # 0 +0xF8C5 0x8EA0 # 0 +0xF8C6 0x8E9D # 0 +0xF8C7 0x91BE # 0 +0xF8C8 0x91BD # 0 +0xF8C9 0x91C2 # 0 +0xF8CA 0x946B # 0 +0xF8CB 0x9468 # 0 +0xF8CC 0x9469 # 0 +0xF8CD 0x96E5 # 0 +0xF8CE 0x9746 # 0 +0xF8CF 0x9743 # 0 +0xF8D0 0x9747 # 0 +0xF8D1 0x97C7 # 0 +0xF8D2 0x97E5 # 0 +0xF8D3 0x9A5E # 0 +0xF8D4 0x9AD5 # 0 +0xF8D5 0x9B59 # 0 +0xF8D6 0x9C63 # 0 +0xF8D7 0x9C67 # 0 +0xF8D8 0x9C66 # 0 +0xF8D9 0x9C62 # 0 +0xF8DA 0x9C5E # 0 +0xF8DB 0x9C60 # 0 +0xF8DC 0x9E02 # 0 +0xF8DD 0x9DFE # 0 +0xF8DE 0x9E07 # 0 +0xF8DF 0x9E03 # 0 +0xF8E0 0x9E06 # 0 +0xF8E1 0x9E05 # 0 +0xF8E2 0x9E00 # 0 +0xF8E3 0x9E01 # 0 +0xF8E4 0x9E09 # 0 +0xF8E5 0x9DFF # 0 +0xF8E6 0x9DFD # 0 +0xF8E7 0x9E04 # 0 +0xF8E8 0x9EA0 # 0 +0xF8E9 0x9F1E # 0 +0xF8EA 0x9F46 # 0 +0xF8EB 0x9F74 # 0 +0xF8EC 0x9F75 # 0 +0xF8ED 0x9F76 # 0 +0xF8EE 0x56D4 # 0 +0xF8EF 0x652E # 0 +0xF8F0 0x65B8 # 0 +0xF8F1 0x6B18 # 0 +0xF8F2 0x6B19 # 0 +0xF8F3 0x6B17 # 0 +0xF8F4 0x6B1A # 0 +0xF8F5 0x7062 # 0 +0xF8F6 0x7226 # 0 +0xF8F7 0x72AA # 0 +0xF8F8 0x77D8 # 0 +0xF8F9 0x77D9 # 0 +0xF8FA 0x7939 # 0 +0xF8FB 0x7C69 # 0 +0xF8FC 0x7C6B # 0 +0xF8FD 0x7CF6 # 0 +0xF8FE 0x7E9A # 0 +0xF940 0x7E98 # 0 +0xF941 0x7E9B # 0 +0xF942 0x7E99 # 0 +0xF943 0x81E0 # 0 +0xF944 0x81E1 # 0 +0xF945 0x8646 # 0 +0xF946 0x8647 # 0 +0xF947 0x8648 # 0 +0xF948 0x8979 # 0 +0xF949 0x897A # 0 +0xF94A 0x897C # 0 +0xF94B 0x897B # 0 +0xF94C 0x89FF # 0 +0xF94D 0x8B98 # 0 +0xF94E 0x8B99 # 0 +0xF94F 0x8EA5 # 0 +0xF950 0x8EA4 # 0 +0xF951 0x8EA3 # 0 +0xF952 0x946E # 0 +0xF953 0x946D # 0 +0xF954 0x946F # 0 +0xF955 0x9471 # 0 +0xF956 0x9473 # 0 +0xF957 0x9749 # 0 +0xF958 0x9872 # 0 +0xF959 0x995F # 0 +0xF95A 0x9C68 # 0 +0xF95B 0x9C6E # 0 +0xF95C 0x9C6D # 0 +0xF95D 0x9E0B # 0 +0xF95E 0x9E0D # 0 +0xF95F 0x9E10 # 0 +0xF960 0x9E0F # 0 +0xF961 0x9E12 # 0 +0xF962 0x9E11 # 0 +0xF963 0x9EA1 # 0 +0xF964 0x9EF5 # 0 +0xF965 0x9F09 # 0 +0xF966 0x9F47 # 0 +0xF967 0x9F78 # 0 +0xF968 0x9F7B # 0 +0xF969 0x9F7A # 0 +0xF96A 0x9F79 # 0 +0xF96B 0x571E # 0 +0xF96C 0x7066 # 0 +0xF96D 0x7C6F # 0 +0xF96E 0x883C # 0 +0xF96F 0x8DB2 # 0 +0xF970 0x8EA6 # 0 +0xF971 0x91C3 # 0 +0xF972 0x9474 # 0 +0xF973 0x9478 # 0 +0xF974 0x9476 # 0 +0xF975 0x9475 # 0 +0xF976 0x9A60 # 0 +0xF977 0x9C74 # 0 +0xF978 0x9C73 # 0 +0xF979 0x9C71 # 0 +0xF97A 0x9C75 # 0 +0xF97B 0x9E14 # 0 +0xF97C 0x9E13 # 0 +0xF97D 0x9EF6 # 0 +0xF97E 0x9F0A # 0 +0xF9A1 0x9FA4 # 0 +0xF9A2 0x7068 # 0 +0xF9A3 0x7065 # 0 +0xF9A4 0x7CF7 # 0 +0xF9A5 0x866A # 0 +0xF9A6 0x883E # 0 +0xF9A7 0x883D # 0 +0xF9A8 0x883F # 0 +0xF9A9 0x8B9E # 0 +0xF9AA 0x8C9C # 0 +0xF9AB 0x8EA9 # 0 +0xF9AC 0x8EC9 # 0 +0xF9AD 0x974B # 0 +0xF9AE 0x9873 # 0 +0xF9AF 0x9874 # 0 +0xF9B0 0x98CC # 0 +0xF9B1 0x9961 # 0 +0xF9B2 0x99AB # 0 +0xF9B3 0x9A64 # 0 +0xF9B4 0x9A66 # 0 +0xF9B5 0x9A67 # 0 +0xF9B6 0x9B24 # 0 +0xF9B7 0x9E15 # 0 +0xF9B8 0x9E17 # 0 +0xF9B9 0x9F48 # 0 +0xF9BA 0x6207 # 0 +0xF9BB 0x6B1E # 0 +0xF9BC 0x7227 # 0 +0xF9BD 0x864C # 0 +0xF9BE 0x8EA8 # 0 +0xF9BF 0x9482 # 0 +0xF9C0 0x9480 # 0 +0xF9C1 0x9481 # 0 +0xF9C2 0x9A69 # 0 +0xF9C3 0x9A68 # 0 +0xF9C4 0x9B2E # 0 +0xF9C5 0x9E19 # 0 +0xF9C6 0x7229 # 0 +0xF9C7 0x864B # 0 +0xF9C8 0x8B9F # 0 +0xF9C9 0x9483 # 0 +0xF9CA 0x9C79 # 0 +0xF9CB 0x9EB7 # 0 +0xF9CC 0x7675 # 0 +0xF9CD 0x9A6B # 0 +0xF9CE 0x9C7A # 0 +0xF9CF 0x9E1D # 0 +0xF9D0 0x7069 # 0 +0xF9D1 0x706A # 0 +0xF9D2 0x9EA4 # 0 +0xF9D3 0x9F7E # 0 +0xF9D4 0x9F49 # 0 +0xF9D5 0x9F98 # 0 +0xF9D6 0x7881 # 0 +0xF9D7 0x92B9 # 0 +0xF9D8 0x88CF # 0 +0xF9D9 0x58BB # 0 +0xF9DA 0x6052 # 0 +0xF9DB 0x7CA7 # 0 +0xF9DC 0x5AFA # 0 +0xF9DD 0x2554 # 0 +0xF9DE 0x2566 # 0 +0xF9DF 0x2557 # 0 +0xF9E0 0x2560 # 0 +0xF9E1 0x256C # 0 +0xF9E2 0x2563 # 0 +0xF9E3 0x255A # 0 +0xF9E4 0x2569 # 0 +0xF9E5 0x255D # 0 +0xF9E6 0x2552 # 0 +0xF9E7 0x2564 # 0 +0xF9E8 0x2555 # 0 +0xF9E9 0x255E # 0 +0xF9EA 0x256A # 0 +0xF9EB 0x2561 # 0 +0xF9EC 0x2558 # 0 +0xF9ED 0x2567 # 0 +0xF9EE 0x255B # 0 +0xF9EF 0x2553 # 0 +0xF9F0 0x2565 # 0 +0xF9F1 0x2556 # 0 +0xF9F2 0x255F # 0 +0xF9F3 0x256B # 0 +0xF9F4 0x2562 # 0 +0xF9F5 0x2559 # 0 +0xF9F6 0x2568 # 0 +0xF9F7 0x255C # 0 +0xF9F8 0x2551 # 0 +0xF9F9 0x2550 # 0 +0xF9FE 0x2593 # 0 +0xFA40 0xE000 # 0 +0xFA41 0xE001 # 0 +0xFA42 0xE002 # 0 +0xFA43 0xE003 # 0 +0xFA44 0xE004 # 0 +0xFA45 0xE005 # 0 +0xFA46 0xE006 # 0 +0xFA47 0xE007 # 0 +0xFA48 0xE008 # 0 +0xFA49 0xE009 # 0 +0xFA4A 0xE00A # 0 +0xFA4B 0xE00B # 0 +0xFA4C 0xE00C # 0 +0xFA4D 0xE00D # 0 +0xFA4E 0xE00E # 0 +0xFA4F 0xE00F # 0 +0xFA50 0xE010 # 0 +0xFA51 0xE011 # 0 +0xFA52 0xE012 # 0 +0xFA53 0xE013 # 0 +0xFA54 0xE014 # 0 +0xFA55 0xE015 # 0 +0xFA56 0xE016 # 0 +0xFA57 0xE017 # 0 +0xFA58 0xE018 # 0 +0xFA59 0xE019 # 0 +0xFA5A 0xE01A # 0 +0xFA5B 0xE01B # 0 +0xFA5C 0xE01C # 0 +0xFA5D 0xE01D # 0 +0xFA5E 0xE01E # 0 +0xFA5F 0xE01F # 0 +0xFA60 0xE020 # 0 +0xFA61 0xE021 # 0 +0xFA62 0xE022 # 0 +0xFA63 0xE023 # 0 +0xFA64 0xE024 # 0 +0xFA65 0xE025 # 0 +0xFA66 0xE026 # 0 +0xFA67 0xE027 # 0 +0xFA68 0xE028 # 0 +0xFA69 0xE029 # 0 +0xFA6A 0xE02A # 0 +0xFA6B 0xE02B # 0 +0xFA6C 0xE02C # 0 +0xFA6D 0xE02D # 0 +0xFA6E 0xE02E # 0 +0xFA6F 0xE02F # 0 +0xFA70 0xE030 # 0 +0xFA71 0xE031 # 0 +0xFA72 0xE032 # 0 +0xFA73 0xE033 # 0 +0xFA74 0xE034 # 0 +0xFA75 0xE035 # 0 +0xFA76 0xE036 # 0 +0xFA77 0xE037 # 0 +0xFA78 0xE038 # 0 +0xFA79 0xE039 # 0 +0xFA7A 0xE03A # 0 +0xFA7B 0xE03B # 0 +0xFA7C 0xE03C # 0 +0xFA7D 0xE03D # 0 +0xFA7E 0xE03E # 0 +0xFAA1 0xE03F # 0 +0xFAA2 0xE040 # 0 +0xFAA3 0xE041 # 0 +0xFAA4 0xE042 # 0 +0xFAA5 0xE043 # 0 +0xFAA6 0xE044 # 0 +0xFAA7 0xE045 # 0 +0xFAA8 0xE046 # 0 +0xFAA9 0xE047 # 0 +0xFAAA 0xE048 # 0 +0xFAAB 0xE049 # 0 +0xFAAC 0xE04A # 0 +0xFAAD 0xE04B # 0 +0xFAAE 0xE04C # 0 +0xFAAF 0xE04D # 0 +0xFAB0 0xE04E # 0 +0xFAB1 0xE04F # 0 +0xFAB2 0xE050 # 0 +0xFAB3 0xE051 # 0 +0xFAB4 0xE052 # 0 +0xFAB5 0xE053 # 0 +0xFAB6 0xE054 # 0 +0xFAB7 0xE055 # 0 +0xFAB8 0xE056 # 0 +0xFAB9 0xE057 # 0 +0xFABA 0xE058 # 0 +0xFABB 0xE059 # 0 +0xFABC 0xE05A # 0 +0xFABD 0xE05B # 0 +0xFABE 0xE05C # 0 +0xFABF 0xE05D # 0 +0xFAC0 0xE05E # 0 +0xFAC1 0xE05F # 0 +0xFAC2 0xE060 # 0 +0xFAC3 0xE061 # 0 +0xFAC4 0xE062 # 0 +0xFAC5 0xE063 # 0 +0xFAC6 0xE064 # 0 +0xFAC7 0xE065 # 0 +0xFAC8 0xE066 # 0 +0xFAC9 0xE067 # 0 +0xFACA 0xE068 # 0 +0xFACB 0xE069 # 0 +0xFACC 0xE06A # 0 +0xFACD 0xE06B # 0 +0xFACE 0xE06C # 0 +0xFACF 0xE06D # 0 +0xFAD0 0xE06E # 0 +0xFAD1 0xE06F # 0 +0xFAD2 0xE070 # 0 +0xFAD3 0xE071 # 0 +0xFAD4 0xE072 # 0 +0xFAD5 0xE073 # 0 +0xFAD6 0xE074 # 0 +0xFAD7 0xE075 # 0 +0xFAD8 0xE076 # 0 +0xFAD9 0xE077 # 0 +0xFADA 0xE078 # 0 +0xFADB 0xE079 # 0 +0xFADC 0xE07A # 0 +0xFADD 0xE07B # 0 +0xFADE 0xE07C # 0 +0xFADF 0xE07D # 0 +0xFAE0 0xE07E # 0 +0xFAE1 0xE07F # 0 +0xFAE2 0xE080 # 0 +0xFAE3 0xE081 # 0 +0xFAE4 0xE082 # 0 +0xFAE5 0xE083 # 0 +0xFAE6 0xE084 # 0 +0xFAE7 0xE085 # 0 +0xFAE8 0xE086 # 0 +0xFAE9 0xE087 # 0 +0xFAEA 0xE088 # 0 +0xFAEB 0xE089 # 0 +0xFAEC 0xE08A # 0 +0xFAED 0xE08B # 0 +0xFAEE 0xE08C # 0 +0xFAEF 0xE08D # 0 +0xFAF0 0xE08E # 0 +0xFAF1 0xE08F # 0 +0xFAF2 0xE090 # 0 +0xFAF3 0xE091 # 0 +0xFAF4 0xE092 # 0 +0xFAF5 0xE093 # 0 +0xFAF6 0xE094 # 0 +0xFAF7 0xE095 # 0 +0xFAF8 0xE096 # 0 +0xFAF9 0xE097 # 0 +0xFAFA 0xE098 # 0 +0xFAFB 0xE099 # 0 +0xFAFC 0xE09A # 0 +0xFAFD 0xE09B # 0 +0xFAFE 0xE09C # 0 +0xFB40 0xE09D # 0 +0xFB41 0xE09E # 0 +0xFB42 0xE09F # 0 +0xFB43 0xE0A0 # 0 +0xFB44 0xE0A1 # 0 +0xFB45 0xE0A2 # 0 +0xFB46 0xE0A3 # 0 +0xFB47 0xE0A4 # 0 +0xFB48 0xE0A5 # 0 +0xFB49 0xE0A6 # 0 +0xFB4A 0xE0A7 # 0 +0xFB4B 0xE0A8 # 0 +0xFB4C 0xE0A9 # 0 +0xFB4D 0xE0AA # 0 +0xFB4E 0xE0AB # 0 +0xFB4F 0xE0AC # 0 +0xFB50 0xE0AD # 0 +0xFB51 0xE0AE # 0 +0xFB52 0xE0AF # 0 +0xFB53 0xE0B0 # 0 +0xFB54 0xE0B1 # 0 +0xFB55 0xE0B2 # 0 +0xFB56 0xE0B3 # 0 +0xFB57 0xE0B4 # 0 +0xFB58 0xE0B5 # 0 +0xFB59 0xE0B6 # 0 +0xFB5A 0xE0B7 # 0 +0xFB5B 0xE0B8 # 0 +0xFB5C 0xE0B9 # 0 +0xFB5D 0xE0BA # 0 +0xFB5E 0xE0BB # 0 +0xFB5F 0xE0BC # 0 +0xFB60 0xE0BD # 0 +0xFB61 0xE0BE # 0 +0xFB62 0xE0BF # 0 +0xFB63 0xE0C0 # 0 +0xFB64 0xE0C1 # 0 +0xFB65 0xE0C2 # 0 +0xFB66 0xE0C3 # 0 +0xFB67 0xE0C4 # 0 +0xFB68 0xE0C5 # 0 +0xFB69 0xE0C6 # 0 +0xFB6A 0xE0C7 # 0 +0xFB6B 0xE0C8 # 0 +0xFB6C 0xE0C9 # 0 +0xFB6D 0xE0CA # 0 +0xFB6E 0xE0CB # 0 +0xFB6F 0xE0CC # 0 +0xFB70 0xE0CD # 0 +0xFB71 0xE0CE # 0 +0xFB72 0xE0CF # 0 +0xFB73 0xE0D0 # 0 +0xFB74 0xE0D1 # 0 +0xFB75 0xE0D2 # 0 +0xFB76 0xE0D3 # 0 +0xFB77 0xE0D4 # 0 +0xFB78 0xE0D5 # 0 +0xFB79 0xE0D6 # 0 +0xFB7A 0xE0D7 # 0 +0xFB7B 0xE0D8 # 0 +0xFB7C 0xE0D9 # 0 +0xFB7D 0xE0DA # 0 +0xFB7E 0xE0DB # 0 +0xFBA1 0xE0DC # 0 +0xFBA2 0xE0DD # 0 +0xFBA3 0xE0DE # 0 +0xFBA4 0xE0DF # 0 +0xFBA5 0xE0E0 # 0 +0xFBA6 0xE0E1 # 0 +0xFBA7 0xE0E2 # 0 +0xFBA8 0xE0E3 # 0 +0xFBA9 0xE0E4 # 0 +0xFBAA 0xE0E5 # 0 +0xFBAB 0xE0E6 # 0 +0xFBAC 0xE0E7 # 0 +0xFBAD 0xE0E8 # 0 +0xFBAE 0xE0E9 # 0 +0xFBAF 0xE0EA # 0 +0xFBB0 0xE0EB # 0 +0xFBB1 0xE0EC # 0 +0xFBB2 0xE0ED # 0 +0xFBB3 0xE0EE # 0 +0xFBB4 0xE0EF # 0 +0xFBB5 0xE0F0 # 0 +0xFBB6 0xE0F1 # 0 +0xFBB7 0xE0F2 # 0 +0xFBB8 0xE0F3 # 0 +0xFBB9 0xE0F4 # 0 +0xFBBA 0xE0F5 # 0 +0xFBBB 0xE0F6 # 0 +0xFBBC 0xE0F7 # 0 +0xFBBD 0xE0F8 # 0 +0xFBBE 0xE0F9 # 0 +0xFBBF 0xE0FA # 0 +0xFBC0 0xE0FB # 0 +0xFBC1 0xE0FC # 0 +0xFBC2 0xE0FD # 0 +0xFBC3 0xE0FE # 0 +0xFBC4 0xE0FF # 0 +0xFBC5 0xE100 # 0 +0xFBC6 0xE101 # 0 +0xFBC7 0xE102 # 0 +0xFBC8 0xE103 # 0 +0xFBC9 0xE104 # 0 +0xFBCA 0xE105 # 0 +0xFBCB 0xE106 # 0 +0xFBCC 0xE107 # 0 +0xFBCD 0xE108 # 0 +0xFBCE 0xE109 # 0 +0xFBCF 0xE10A # 0 +0xFBD0 0xE10B # 0 +0xFBD1 0xE10C # 0 +0xFBD2 0xE10D # 0 +0xFBD3 0xE10E # 0 +0xFBD4 0xE10F # 0 +0xFBD5 0xE110 # 0 +0xFBD6 0xE111 # 0 +0xFBD7 0xE112 # 0 +0xFBD8 0xE113 # 0 +0xFBD9 0xE114 # 0 +0xFBDA 0xE115 # 0 +0xFBDB 0xE116 # 0 +0xFBDC 0xE117 # 0 +0xFBDD 0xE118 # 0 +0xFBDE 0xE119 # 0 +0xFBDF 0xE11A # 0 +0xFBE0 0xE11B # 0 +0xFBE1 0xE11C # 0 +0xFBE2 0xE11D # 0 +0xFBE3 0xE11E # 0 +0xFBE4 0xE11F # 0 +0xFBE5 0xE120 # 0 +0xFBE6 0xE121 # 0 +0xFBE7 0xE122 # 0 +0xFBE8 0xE123 # 0 +0xFBE9 0xE124 # 0 +0xFBEA 0xE125 # 0 +0xFBEB 0xE126 # 0 +0xFBEC 0xE127 # 0 +0xFBED 0xE128 # 0 +0xFBEE 0xE129 # 0 +0xFBEF 0xE12A # 0 +0xFBF0 0xE12B # 0 +0xFBF1 0xE12C # 0 +0xFBF2 0xE12D # 0 +0xFBF3 0xE12E # 0 +0xFBF4 0xE12F # 0 +0xFBF5 0xE130 # 0 +0xFBF6 0xE131 # 0 +0xFBF7 0xE132 # 0 +0xFBF8 0xE133 # 0 +0xFBF9 0xE134 # 0 +0xFBFA 0xE135 # 0 +0xFBFB 0xE136 # 0 +0xFBFC 0xE137 # 0 +0xFBFD 0xE138 # 0 +0xFBFE 0xE139 # 0 +0xFC40 0xE13A # 0 +0xFC41 0xE13B # 0 +0xFC42 0xE13C # 0 +0xFC43 0xE13D # 0 +0xFC44 0xE13E # 0 +0xFC45 0xE13F # 0 +0xFC46 0xE140 # 0 +0xFC47 0xE141 # 0 +0xFC48 0xE142 # 0 +0xFC49 0xE143 # 0 +0xFC4A 0xE144 # 0 +0xFC4B 0xE145 # 0 +0xFC4C 0xE146 # 0 +0xFC4D 0xE147 # 0 +0xFC4E 0xE148 # 0 +0xFC4F 0xE149 # 0 +0xFC50 0xE14A # 0 +0xFC51 0xE14B # 0 +0xFC52 0xE14C # 0 +0xFC53 0xE14D # 0 +0xFC54 0xE14E # 0 +0xFC55 0xE14F # 0 +0xFC56 0xE150 # 0 +0xFC57 0xE151 # 0 +0xFC58 0xE152 # 0 +0xFC59 0xE153 # 0 +0xFC5A 0xE154 # 0 +0xFC5B 0xE155 # 0 +0xFC5C 0xE156 # 0 +0xFC5D 0xE157 # 0 +0xFC5E 0xE158 # 0 +0xFC5F 0xE159 # 0 +0xFC60 0xE15A # 0 +0xFC61 0xE15B # 0 +0xFC62 0xE15C # 0 +0xFC63 0xE15D # 0 +0xFC64 0xE15E # 0 +0xFC65 0xE15F # 0 +0xFC66 0xE160 # 0 +0xFC67 0xE161 # 0 +0xFC68 0xE162 # 0 +0xFC69 0xE163 # 0 +0xFC6A 0xE164 # 0 +0xFC6B 0xE165 # 0 +0xFC6C 0xE166 # 0 +0xFC6D 0xE167 # 0 +0xFC6E 0xE168 # 0 +0xFC6F 0xE169 # 0 +0xFC70 0xE16A # 0 +0xFC71 0xE16B # 0 +0xFC72 0xE16C # 0 +0xFC73 0xE16D # 0 +0xFC74 0xE16E # 0 +0xFC75 0xE16F # 0 +0xFC76 0xE170 # 0 +0xFC77 0xE171 # 0 +0xFC78 0xE172 # 0 +0xFC79 0xE173 # 0 +0xFC7A 0xE174 # 0 +0xFC7B 0xE175 # 0 +0xFC7C 0xE176 # 0 +0xFC7D 0xE177 # 0 +0xFC7E 0xE178 # 0 +0xFCA1 0xE179 # 0 +0xFCA2 0xE17A # 0 +0xFCA3 0xE17B # 0 +0xFCA4 0xE17C # 0 +0xFCA5 0xE17D # 0 +0xFCA6 0xE17E # 0 +0xFCA7 0xE17F # 0 +0xFCA8 0xE180 # 0 +0xFCA9 0xE181 # 0 +0xFCAA 0xE182 # 0 +0xFCAB 0xE183 # 0 +0xFCAC 0xE184 # 0 +0xFCAD 0xE185 # 0 +0xFCAE 0xE186 # 0 +0xFCAF 0xE187 # 0 +0xFCB0 0xE188 # 0 +0xFCB1 0xE189 # 0 +0xFCB2 0xE18A # 0 +0xFCB3 0xE18B # 0 +0xFCB4 0xE18C # 0 +0xFCB5 0xE18D # 0 +0xFCB6 0xE18E # 0 +0xFCB7 0xE18F # 0 +0xFCB8 0xE190 # 0 +0xFCB9 0xE191 # 0 +0xFCBA 0xE192 # 0 +0xFCBB 0xE193 # 0 +0xFCBC 0xE194 # 0 +0xFCBD 0xE195 # 0 +0xFCBE 0xE196 # 0 +0xFCBF 0xE197 # 0 +0xFCC0 0xE198 # 0 +0xFCC1 0xE199 # 0 +0xFCC2 0xE19A # 0 +0xFCC3 0xE19B # 0 +0xFCC4 0xE19C # 0 +0xFCC5 0xE19D # 0 +0xFCC6 0xE19E # 0 +0xFCC7 0xE19F # 0 +0xFCC8 0xE1A0 # 0 +0xFCC9 0xE1A1 # 0 +0xFCCA 0xE1A2 # 0 +0xFCCB 0xE1A3 # 0 +0xFCCC 0xE1A4 # 0 +0xFCCD 0xE1A5 # 0 +0xFCCE 0xE1A6 # 0 +0xFCCF 0xE1A7 # 0 +0xFCD0 0xE1A8 # 0 +0xFCD1 0xE1A9 # 0 +0xFCD2 0xE1AA # 0 +0xFCD3 0xE1AB # 0 +0xFCD4 0xE1AC # 0 +0xFCD5 0xE1AD # 0 +0xFCD6 0xE1AE # 0 +0xFCD7 0xE1AF # 0 +0xFCD8 0xE1B0 # 0 +0xFCD9 0xE1B1 # 0 +0xFCDA 0xE1B2 # 0 +0xFCDB 0xE1B3 # 0 +0xFCDC 0xE1B4 # 0 +0xFCDD 0xE1B5 # 0 +0xFCDE 0xE1B6 # 0 +0xFCDF 0xE1B7 # 0 +0xFCE0 0xE1B8 # 0 +0xFCE1 0xE1B9 # 0 +0xFCE2 0xE1BA # 0 +0xFCE3 0xE1BB # 0 +0xFCE4 0xE1BC # 0 +0xFCE5 0xE1BD # 0 +0xFCE6 0xE1BE # 0 +0xFCE7 0xE1BF # 0 +0xFCE8 0xE1C0 # 0 +0xFCE9 0xE1C1 # 0 +0xFCEA 0xE1C2 # 0 +0xFCEB 0xE1C3 # 0 +0xFCEC 0xE1C4 # 0 +0xFCED 0xE1C5 # 0 +0xFCEE 0xE1C6 # 0 +0xFCEF 0xE1C7 # 0 +0xFCF0 0xE1C8 # 0 +0xFCF1 0xE1C9 # 0 +0xFCF2 0xE1CA # 0 +0xFCF3 0xE1CB # 0 +0xFCF4 0xE1CC # 0 +0xFCF5 0xE1CD # 0 +0xFCF6 0xE1CE # 0 +0xFCF7 0xE1CF # 0 +0xFCF8 0xE1D0 # 0 +0xFCF9 0xE1D1 # 0 +0xFCFA 0xE1D2 # 0 +0xFCFB 0xE1D3 # 0 +0xFCFC 0xE1D4 # 0 +0xFCFD 0xE1D5 # 0 +0xFCFE 0xE1D6 # 0 +0xFD40 0xE1D7 # 0 +0xFD41 0xE1D8 # 0 +0xFD42 0xE1D9 # 0 +0xFD43 0xE1DA # 0 +0xFD44 0xE1DB # 0 +0xFD45 0xE1DC # 0 +0xFD46 0xE1DD # 0 +0xFD47 0xE1DE # 0 +0xFD48 0xE1DF # 0 +0xFD49 0xE1E0 # 0 +0xFD4A 0xE1E1 # 0 +0xFD4B 0xE1E2 # 0 +0xFD4C 0xE1E3 # 0 +0xFD4D 0xE1E4 # 0 +0xFD4E 0xE1E5 # 0 +0xFD4F 0xE1E6 # 0 +0xFD50 0xE1E7 # 0 +0xFD51 0xE1E8 # 0 +0xFD52 0xE1E9 # 0 +0xFD53 0xE1EA # 0 +0xFD54 0xE1EB # 0 +0xFD55 0xE1EC # 0 +0xFD56 0xE1ED # 0 +0xFD57 0xE1EE # 0 +0xFD58 0xE1EF # 0 +0xFD59 0xE1F0 # 0 +0xFD5A 0xE1F1 # 0 +0xFD5B 0xE1F2 # 0 +0xFD5C 0xE1F3 # 0 +0xFD5D 0xE1F4 # 0 +0xFD5E 0xE1F5 # 0 +0xFD5F 0xE1F6 # 0 +0xFD60 0xE1F7 # 0 +0xFD61 0xE1F8 # 0 +0xFD62 0xE1F9 # 0 +0xFD63 0xE1FA # 0 +0xFD64 0xE1FB # 0 +0xFD65 0xE1FC # 0 +0xFD66 0xE1FD # 0 +0xFD67 0xE1FE # 0 +0xFD68 0xE1FF # 0 +0xFD69 0xE200 # 0 +0xFD6A 0xE201 # 0 +0xFD6B 0xE202 # 0 +0xFD6C 0xE203 # 0 +0xFD6D 0xE204 # 0 +0xFD6E 0xE205 # 0 +0xFD6F 0xE206 # 0 +0xFD70 0xE207 # 0 +0xFD71 0xE208 # 0 +0xFD72 0xE209 # 0 +0xFD73 0xE20A # 0 +0xFD74 0xE20B # 0 +0xFD75 0xE20C # 0 +0xFD76 0xE20D # 0 +0xFD77 0xE20E # 0 +0xFD78 0xE20F # 0 +0xFD79 0xE210 # 0 +0xFD7A 0xE211 # 0 +0xFD7B 0xE212 # 0 +0xFD7C 0xE213 # 0 +0xFD7D 0xE214 # 0 +0xFD7E 0xE215 # 0 +0xFDA1 0xE216 # 0 +0xFDA2 0xE217 # 0 +0xFDA3 0xE218 # 0 +0xFDA4 0xE219 # 0 +0xFDA5 0xE21A # 0 +0xFDA6 0xE21B # 0 +0xFDA7 0xE21C # 0 +0xFDA8 0xE21D # 0 +0xFDA9 0xE21E # 0 +0xFDAA 0xE21F # 0 +0xFDAB 0xE220 # 0 +0xFDAC 0xE221 # 0 +0xFDAD 0xE222 # 0 +0xFDAE 0xE223 # 0 +0xFDAF 0xE224 # 0 +0xFDB0 0xE225 # 0 +0xFDB1 0xE226 # 0 +0xFDB2 0xE227 # 0 +0xFDB3 0xE228 # 0 +0xFDB4 0xE229 # 0 +0xFDB5 0xE22A # 0 +0xFDB6 0xE22B # 0 +0xFDB7 0xE22C # 0 +0xFDB8 0xE22D # 0 +0xFDB9 0xE22E # 0 +0xFDBA 0xE22F # 0 +0xFDBB 0xE230 # 0 +0xFDBC 0xE231 # 0 +0xFDBD 0xE232 # 0 +0xFDBE 0xE233 # 0 +0xFDBF 0xE234 # 0 +0xFDC0 0xE235 # 0 +0xFDC1 0xE236 # 0 +0xFDC2 0xE237 # 0 +0xFDC3 0xE238 # 0 +0xFDC4 0xE239 # 0 +0xFDC5 0xE23A # 0 +0xFDC6 0xE23B # 0 +0xFDC7 0xE23C # 0 +0xFDC8 0xE23D # 0 +0xFDC9 0xE23E # 0 +0xFDCA 0xE23F # 0 +0xFDCB 0xE240 # 0 +0xFDCC 0xE241 # 0 +0xFDCD 0xE242 # 0 +0xFDCE 0xE243 # 0 +0xFDCF 0xE244 # 0 +0xFDD0 0xE245 # 0 +0xFDD1 0xE246 # 0 +0xFDD2 0xE247 # 0 +0xFDD3 0xE248 # 0 +0xFDD4 0xE249 # 0 +0xFDD5 0xE24A # 0 +0xFDD6 0xE24B # 0 +0xFDD7 0xE24C # 0 +0xFDD8 0xE24D # 0 +0xFDD9 0xE24E # 0 +0xFDDA 0xE24F # 0 +0xFDDB 0xE250 # 0 +0xFDDC 0xE251 # 0 +0xFDDD 0xE252 # 0 +0xFDDE 0xE253 # 0 +0xFDDF 0xE254 # 0 +0xFDE0 0xE255 # 0 +0xFDE1 0xE256 # 0 +0xFDE2 0xE257 # 0 +0xFDE3 0xE258 # 0 +0xFDE4 0xE259 # 0 +0xFDE5 0xE25A # 0 +0xFDE6 0xE25B # 0 +0xFDE7 0xE25C # 0 +0xFDE8 0xE25D # 0 +0xFDE9 0xE25E # 0 +0xFDEA 0xE25F # 0 +0xFDEB 0xE260 # 0 +0xFDEC 0xE261 # 0 +0xFDED 0xE262 # 0 +0xFDEE 0xE263 # 0 +0xFDEF 0xE264 # 0 +0xFDF0 0xE265 # 0 +0xFDF1 0xE266 # 0 +0xFDF2 0xE267 # 0 +0xFDF3 0xE268 # 0 +0xFDF4 0xE269 # 0 +0xFDF5 0xE26A # 0 +0xFDF6 0xE26B # 0 +0xFDF7 0xE26C # 0 +0xFDF8 0xE26D # 0 +0xFDF9 0xE26E # 0 +0xFDFA 0xE26F # 0 +0xFDFB 0xE270 # 0 +0xFDFC 0xE271 # 0 +0xFDFD 0xE272 # 0 +0xFDFE 0xE273 # 0 +0xFE40 0xE274 # 0 +0xFE41 0xE275 # 0 +0xFE42 0xE276 # 0 +0xFE43 0xE277 # 0 +0xFE44 0xE278 # 0 +0xFE45 0xE279 # 0 +0xFE46 0xE27A # 0 +0xFE47 0xE27B # 0 +0xFE48 0xE27C # 0 +0xFE49 0xE27D # 0 +0xFE4A 0xE27E # 0 +0xFE4B 0xE27F # 0 +0xFE4C 0xE280 # 0 +0xFE4D 0xE281 # 0 +0xFE4E 0xE282 # 0 +0xFE4F 0xE283 # 0 +0xFE50 0xE284 # 0 +0xFE51 0xE285 # 0 +0xFE52 0xE286 # 0 +0xFE53 0xE287 # 0 +0xFE54 0xE288 # 0 +0xFE55 0xE289 # 0 +0xFE56 0xE28A # 0 +0xFE57 0xE28B # 0 +0xFE58 0xE28C # 0 +0xFE59 0xE28D # 0 +0xFE5A 0xE28E # 0 +0xFE5B 0xE28F # 0 +0xFE5C 0xE290 # 0 +0xFE5D 0xE291 # 0 +0xFE5E 0xE292 # 0 +0xFE5F 0xE293 # 0 +0xFE60 0xE294 # 0 +0xFE61 0xE295 # 0 +0xFE62 0xE296 # 0 +0xFE63 0xE297 # 0 +0xFE64 0xE298 # 0 +0xFE65 0xE299 # 0 +0xFE66 0xE29A # 0 +0xFE67 0xE29B # 0 +0xFE68 0xE29C # 0 +0xFE69 0xE29D # 0 +0xFE6A 0xE29E # 0 +0xFE6B 0xE29F # 0 +0xFE6C 0xE2A0 # 0 +0xFE6D 0xE2A1 # 0 +0xFE6E 0xE2A2 # 0 +0xFE6F 0xE2A3 # 0 +0xFE70 0xE2A4 # 0 +0xFE71 0xE2A5 # 0 +0xFE72 0xE2A6 # 0 +0xFE73 0xE2A7 # 0 +0xFE74 0xE2A8 # 0 +0xFE75 0xE2A9 # 0 +0xFE76 0xE2AA # 0 +0xFE77 0xE2AB # 0 +0xFE78 0xE2AC # 0 +0xFE79 0xE2AD # 0 +0xFE7A 0xE2AE # 0 +0xFE7B 0xE2AF # 0 +0xFE7C 0xE2B0 # 0 +0xFE7D 0xE2B1 # 0 +0xFE7E 0xE2B2 # 0 +0xFEA1 0xE2B3 # 0 +0xFEA2 0xE2B4 # 0 +0xFEA3 0xE2B5 # 0 +0xFEA4 0xE2B6 # 0 +0xFEA5 0xE2B7 # 0 +0xFEA6 0xE2B8 # 0 +0xFEA7 0xE2B9 # 0 +0xFEA8 0xE2BA # 0 +0xFEA9 0xE2BB # 0 +0xFEAA 0xE2BC # 0 +0xFEAB 0xE2BD # 0 +0xFEAC 0xE2BE # 0 +0xFEAD 0xE2BF # 0 +0xFEAE 0xE2C0 # 0 +0xFEAF 0xE2C1 # 0 +0xFEB0 0xE2C2 # 0 +0xFEB1 0xE2C3 # 0 +0xFEB2 0xE2C4 # 0 +0xFEB3 0xE2C5 # 0 +0xFEB4 0xE2C6 # 0 +0xFEB5 0xE2C7 # 0 +0xFEB6 0xE2C8 # 0 +0xFEB7 0xE2C9 # 0 +0xFEB8 0xE2CA # 0 +0xFEB9 0xE2CB # 0 +0xFEBA 0xE2CC # 0 +0xFEBB 0xE2CD # 0 +0xFEBC 0xE2CE # 0 +0xFEBD 0xE2CF # 0 +0xFEBE 0xE2D0 # 0 +0xFEBF 0xE2D1 # 0 +0xFEC0 0xE2D2 # 0 +0xFEC1 0xE2D3 # 0 +0xFEC2 0xE2D4 # 0 +0xFEC3 0xE2D5 # 0 +0xFEC4 0xE2D6 # 0 +0xFEC5 0xE2D7 # 0 +0xFEC6 0xE2D8 # 0 +0xFEC7 0xE2D9 # 0 +0xFEC8 0xE2DA # 0 +0xFEC9 0xE2DB # 0 +0xFECA 0xE2DC # 0 +0xFECB 0xE2DD # 0 +0xFECC 0xE2DE # 0 +0xFECD 0xE2DF # 0 +0xFECE 0xE2E0 # 0 +0xFECF 0xE2E1 # 0 +0xFED0 0xE2E2 # 0 +0xFED1 0xE2E3 # 0 +0xFED2 0xE2E4 # 0 +0xFED3 0xE2E5 # 0 +0xFED4 0xE2E6 # 0 +0xFED5 0xE2E7 # 0 +0xFED6 0xE2E8 # 0 +0xFED7 0xE2E9 # 0 +0xFED8 0xE2EA # 0 +0xFED9 0xE2EB # 0 +0xFEDA 0xE2EC # 0 +0xFEDB 0xE2ED # 0 +0xFEDC 0xE2EE # 0 +0xFEDD 0xE2EF # 0 +0xFEDE 0xE2F0 # 0 +0xFEDF 0xE2F1 # 0 +0xFEE0 0xE2F2 # 0 +0xFEE1 0xE2F3 # 0 +0xFEE2 0xE2F4 # 0 +0xFEE3 0xE2F5 # 0 +0xFEE4 0xE2F6 # 0 +0xFEE5 0xE2F7 # 0 +0xFEE6 0xE2F8 # 0 +0xFEE7 0xE2F9 # 0 +0xFEE8 0xE2FA # 0 +0xFEE9 0xE2FB # 0 +0xFEEA 0xE2FC # 0 +0xFEEB 0xE2FD # 0 +0xFEEC 0xE2FE # 0 +0xFEED 0xE2FF # 0 +0xFEEE 0xE300 # 0 +0xFEEF 0xE301 # 0 +0xFEF0 0xE302 # 0 +0xFEF1 0xE303 # 0 +0xFEF2 0xE304 # 0 +0xFEF3 0xE305 # 0 +0xFEF4 0xE306 # 0 +0xFEF5 0xE307 # 0 +0xFEF6 0xE308 # 0 +0xFEF7 0xE309 # 0 +0xFEF8 0xE30A # 0 +0xFEF9 0xE30B # 0 +0xFEFA 0xE30C # 0 +0xFEFB 0xE30D # 0 +0xFEFC 0xE30E # 0 +0xFEFD 0xE30F # 0 +0xFEFE 0xE310 # 0 diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 000000000..ec0abad38 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,167 @@ +# +# "$Id: Makefile 4918 2006-01-12 05:14:40Z mike $" +# +# Documentation makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Document files... +# + +WEBPAGES = cups.css cupsdoc.css index.html robots.txt +WEBIMAGES = \ + images/accept-jobs.gif \ + images/add-class.gif \ + images/add-printer.gif \ + images/add-this-printer.gif \ + images/bottom-left.gif \ + images/bottom-right.gif \ + images/cancel.gif \ + images/cancel-all-jobs.gif \ + images/cancel-job.gif \ + images/change-settings.gif \ + images/classes.gif \ + images/continue.gif \ + images/delete-class.gif \ + images/delete-printer.gif \ + images/draft.gif \ + images/edit-configuration-file.gif \ + images/esp-logo.gif \ + images/happy.gif \ + images/help.gif \ + images/hold-job.gif \ + images/logo.gif \ + images/manage-classes.gif \ + images/manage-jobs.gif \ + images/manage-printers.gif \ + images/manage-server.gif \ + images/modify-class.gif \ + images/modify-printer.gif \ + images/printer-idle.gif \ + images/printer-processing.gif \ + images/printer-stopped.gif \ + images/print-test-page.gif \ + images/publish-printer.gif \ + images/reject-jobs.gif \ + images/release-job.gif \ + images/restart-job.gif \ + images/save-changes.gif \ + images/search.gif \ + images/set-allowed-users.gif \ + images/set-as-default.gif \ + images/set-printer-options.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 \ + images/tab-left.gif \ + images/tab-right.gif \ + images/top-left.gif \ + images/top-middle.gif \ + images/top-right.gif \ + images/unpublish-printer.gif \ + images/use-default-config.gif \ + images/view-access-log.gif \ + images/view-error-log.gif \ + images/view-page-log.gif +HELPFILES = \ + help/access_log-reference.html \ + help/api-array.html \ + help/api-cups.html \ + help/api-filedir.html \ + help/api-filter.html \ + help/api-httpipp.html \ + help/api-ppd.html \ + help/classes-conf-reference.html \ + help/client-conf-reference.html \ + help/cupsd-conf-reference.html \ + help/error_log-reference.html \ + help/page_log-reference.html \ + help/printers-conf-reference.html \ + help/subscriptions-conf-reference.html \ + help/man-accept.html \ + help/man-backend.html \ + help/man-cupsaddsmb.html \ + help/man-cups-config.html \ + help/man-cupsd.html \ + help/man-cupsenable.html \ + help/man-cups-lpd.html \ + help/man-cups-polld.html \ + help/man-cupstestppd.html \ + help/man-filter.html \ + help/man-lpadmin.html \ + help/man-lpc.html \ + help/man-lp.html \ + help/man-lpinfo.html \ + help/man-lpmove.html \ + help/man-lpoptions.html \ + help/man-lppasswd.html \ + help/man-lpq.html \ + help/man-lpr.html \ + help/man-lprm.html \ + help/man-lpstat.html \ + help/network.html \ + help/overview.html \ + help/spec-ppd.html \ + help/standard.html \ + help/whatsnew.html + + +# +# Make all documents... +# + +all: + + +# +# Remove all generated files... +# + +clean: + + +# +# Install all documentation files... +# + +install: + $(INSTALL_DIR) $(DOCDIR) + for file in $(WEBPAGES); do \ + $(INSTALL_MAN) $$file $(DOCDIR); \ + done + $(INSTALL_DIR) $(DOCDIR)/help + for file in $(HELPFILES); do \ + $(INSTALL_MAN) $$file $(DOCDIR)/help; \ + done + $(INSTALL_DIR) $(DOCDIR)/images + for file in $(WEBIMAGES); do \ + $(INSTALL_MAN) $$file $(DOCDIR)/images; \ + done + + +# +# End of Makefile. +# diff --git a/doc/cmp.html b/doc/cmp.html new file mode 100644 index 000000000..7bd293c56 --- /dev/null +++ b/doc/cmp.html @@ -0,0 +1,755 @@ + + + +CUPS Configuration Management Plan + + + + + + + + +
+

Table of Contents

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

1 Scope

+

1.1 Identification

+

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

+

1.2 System Overview

+

CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

+

CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

+

CUPS includes an image file RIP that supports printing of image files + to non-PostScript printers. A customized version of GNU Ghostscript + 7.05 for CUPS called ESP Ghostscript is available separately to support + printing of PostScript files within the CUPS driver framework. Sample + drivers for Dymo, EPSON, HP, and OKIDATA 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.

+

1.3 Document Overview

+

This configuration management document is organized into the + following sections:

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

2 References

+

2.1 CUPS Documentation

+

The following CUPS documentation is referenced by this document:

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

2.2 Other Documents

+

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

+ +

3 File Management

+

3.1 Directory Structure

+

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

+

3.2 Source Files

+

Source files shall be documented and formatted as described in + Appendix B, Coding Requirements. To remain compatible with older UNIX + filesystems, source file names shall not exceed 16 characters in + length.

+

3.3 Configuration Management

+

Source files shall be placed under the control of the Concurrent + Versions System ("CVS") software. Source files shall be "checked in" + with each change so that modifications can be tracked.

+

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

+

4 Trouble Report Processing

+

A Software Trouble Report ("STR") shall be submitted every time a + user or vendor experiences a problem with the CUPS software. Trouble + reports are maintained in a database with one of the following states:

+
    +
  1. STR is closed with complete resolution
  2. +
  3. STR is closed without resolution
  4. +
  5. STR is active
  6. +
  7. STR is pending (new STR or additional information available)
  8. +
+

Trouble reports shall be processed using the following steps.

+

4.1 Classification

+

When a trouble report is received it must be classified at one of the + following priority levels:

+
    +
  1. Request for enhancement, e.g. asking for a feature
  2. +
  3. Low, e.g. a documentation error or undocumented side-effect
  4. +
  5. Moderate, e.g. unable to print a file or unable to compile the + software
  6. +
  7. High, e.g. unable to print to a printer or key functionality not + working
  8. +
  9. Critical, e.g. unable to print at all
  10. +
+

Level 4 and 5 trouble reports must be resolved in the next software + release. Level 1 to 3 trouble reports are scheduled for resolution in a + specific release at the discretion of the release coordinator.

+

The scope of the problem should also be determined as:

+
    +
  1. Specific to a machine or printer
  2. +
  3. Specific to an operating system
  4. +
  5. Applies to all machines, printers, and operating systems
  6. +
+

4.2 Identification

+

Once the level and scope of the trouble report is determined the + software sub-system(s) involved with the problem are determined. This + may involve additional communication with the user or vendor to isolate + the problem to a specific cause.

+

When the sub-system(s) involved have been identified, an engineer + will then determine the change(s) needed and estimate the time required + for the change(s).

+

4.3 Correction

+

Corrections are scheduled based upon the severity and complexity of + the problem. Once all changes have been made, documented, and tested + successfully a new software release snapshot is generated. Additional + tests are added as necessary for proper testing of the changes.

+

4.4 Notification

+

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

+

5 Software Releases

+

5.1 Version Numbering

+

CUPS uses a three-part version number separated by periods to + represent the major, minor, and patch release numbers:

+
+    MAJOR.MINOR.PATCH
+    1.1.0
+
+

Beta-test releases are indentified by appending the letter B followed + by the build number:

+
+    MAJOR.MINOR.PATCHbBUILD
+    1.1.0b1
+
+

Release candidates are indentified by appending the letters RC + followed by the build number:

+
+    MAJOR.MINOR.PATCHrcBUILD
+    1.1.0rc1
+
+

A CVS snapshot is generated for every beta and final release and uses + the version number preceded by the letter "v" and with the decimal + points replaced by underscores:

+
+    v1_1_0b1
+    v1_1_0rc1
+    v1_1_0
+
+

Each change that corrects a fault in a software sub-system increments + the patch release number. If a change affects the overall software + design of CUPS then the minor release number will be incremented and + the patch release number reset to 0. If CUPS is completely redesigned + the major release number will be incremented and the minor and patch + release numbers reset to 0:

+
+    1.1.0b1    First beta release
+    1.1.0b2    Second beta release
+    1.1.0rc1   First release candidate
+    1.1.0rc2   Second release candidate
+    1.1.0      First production release
+    1.1.1b1    First beta of 1.1.1
+    1.1.1rc1   First release candidate of 1.1.1
+    1.1.1      Production release of 1.1.1
+    1.1.2b1    First beta of 1.1.2
+    1.1.2rc1   First release candidate of 1.1.2
+    1.1.2      Production release of 1.1.2
+    2.0.0b1    First beta of 2.0.0
+    2.0.0rc1   First release candidate of 2.0.0
+    2.0.0      Production release of 2.0.0
+
+

5.2 Generation

+

Software releases shall be generated for each successfully completed + software trouble report. All object and executable files shall be + deleted prior to performing a full build to ensure that source files + are recompiled.

+

5.3 Testing

+

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

+

5.4 Releases

+

When testing has been completed successfully a new distribution image + is created from the current CVS code "snapshot". No release shall + contain software that has not passed the appropriate software tests. + Three types of releases are used, beta, release candidate, and + production, and are released using the following basic schedule: +

+ + + + + + + + +
WeekVersionDescription
T-6 weeks1.1.0b1First beta
T-5 weeks1.1.0b2Second beta
T-4 weeks1.1.0b3Third beta
T-3 weeks1.1.0rc1First release candidate
T-2 weeks1.1.0rc2Second release candidate
T-0 weeks1.1.0Production
+
+

+

Beta releases are typically used prior to new major and minor version + releases. At least one release candidate is generated prior to each + production release.

+

5.4.1 Beta Releases

+

Beta releases are generated when substantial changes have been made + that may affect the reliability of the software. Beta releases may + cause loss of data, functionality, or services and are provided for + testing by qualified individuals.

+

Beta releases are an OPTIONAL part of the release process and are + generated as deemed appropriate by the release coordinator. Functional + changes may be included in subsequent beta releases until the first + release candidate.

+

5.4.2 Release Candidates

+

Release candidates are generated at least two weeks prior to a + production release. Release candidates are targeted for end-users that + wish to test new functionality or bug fixes prior to the production + release. While release candidates are intended to be substantially + bug-free, they may still contain defects and/or not compile on specific + platforms.

+

At least one release candidate is REQUIRED prior to any production + release. The distribution of a release candidate marks the end of any + functional improvements. Release candidates are generated at weekly + intervals until all level 4/5 trouble reports are resolved.

+

5.4.3 Production Releases

+

Production releases are generated after a successful release + candidate and represent a stable release of the software suitable for + all users.

+

A Glossary

+

A.1 Terms

+
+
C
+
A computer language.
+
parallel
+
Sending or receiving data more than 1 bit at a time.
+
pipe
+
A one-way communications channel between two programs.
+
serial
+
Sending or receiving data 1 bit at a time.
+
socket
+
A two-way network communications channel.
+
+

A.2 Acronyms

+
+
ASCII
+
American Standard Code for Information Interchange
+
CUPS
+
Common UNIX Printing System
+
ESC/P
+
EPSON Standard Code for Printers
+
FTP
+
File Transfer Protocol
+
HP-GL
+
Hewlett-Packard Graphics Language
+
HP-PCL
+
Hewlett-Packard Page Control Language
+
HP-PJL
+
Hewlett-Packard Printer Job Language
+
IETF
+
Internet Engineering Task Force
+
IPP
+
Internet Printing Protocol
+
ISO
+
International Standards Organization
+
LPD
+
Line Printer Daemon
+
MIME
+
Multimedia Internet Mail Exchange
+
PPD
+
PostScript Printer Description
+
SMB
+
Server Message Block
+
TFTP
+
Trivial File Transfer Protocol
+
+

B Coding Requirements

+

These coding requirements provide detailed information on source file + formatting and documentation content. These guidelines shall be applied + to all C and C++ source files provided with CUPS. Source code for other + languages should conform to these requirements as allowed by the + language.

+

B.1 Source Files

+

B.1.1 Naming

+

All source files names shall be 16 characters or less in length to + ensure compatibility with older UNIX filesystems. Source files + containing functions shall have an extension of ".c" for ANSI C and + ".cxx" for C++ source files. All other "include" files shall have an + extension of ".h".

+

B.1.2 Documentation

+

The top of each source file shall contain a header giving the name of + the file, the purpose or nature of the source file, the copyright and + licensing notice, and the functions contained in the file. The file + name and revision information is provided by the CVS "$Id$" tag:

+
+    /*
+     * "$Id$"
+     *
+     *   Description of file contents.
+     *
+     *   Copyright 1997-2005 by Easy Software Products, all rights
+     *   reserved.
+     *
+     *   These coded instructions, statements, and computer programs are
+     *   the property of Easy Software Products and are protected by
+     *   Federal copyright law.  Distribution and use rights are outlined
+     *   in the file "LICENSE.txt" which should have been included with
+     *   this file.  If this file is missing or damaged please contact
+     *   Easy Software Products at:
+     *
+     *       Attn: CUPS Licensing Information
+     *       Easy Software Products
+     *       44141 Airport View Drive, Suite 204
+     *       Hollywood, Maryland 20636 USA
+     *
+     *       Voice: (301) 373-9600
+     *       EMail: cups-info@cups.org
+     *         WWW: http://www.cups.org
+     *
+     * Contents:
+     *
+     *   function1() - Description 1.
+     *   function2() - Description 2.
+     *   function3() - Description 3.
+     */
+
+ + +

For source files that are subject to the Apple OS-Developed Software + exception, the following additional comment should appear after the + contact information:

+
+     *   This file is subject to the Apple OS-Developed Software exception.
+
+

The bottom of each source file shall contain a trailer giving the + name of the file using the CVS "$Id$" tag. The primary purpose of this + is to mark the end of a source file; if the trailer is missing it is + possible that code has been lost near the end of the file:

+
+    /*
+     * End of "$Id$".
+     */
+
+

B.2 Functions

+

B.2.1 Naming

+

Functions with a global scope shall be capitalized ("DoThis", + "DoThat", "DoSomethingElse", etc.) The only exception to this rule + shall be the CUPS interface library functions which may begin with a + prefix word in lowercase ("cupsDoThis", "cupsDoThat", etc.)

+

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

+

B.2.2 Documentation

+

Each function shall begin with a comment header describing what the + function does, the possible input limits (if any), and the possible + output values (if any), and any special information needed:

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

Return/output values are indicated using an "O" prefix, input values + are indicated using the "I" prefix, and values that are both input and + output use the "IO" prefix for the corresponding in-line comment.

+

B.3 Methods

+

B.3.1 Naming

+

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

+

B.3.2 Documentation

+

Each method shall begin with a comment header describing what the + method does, the possible input limits (if any), and the possible + output values (if any), and any special information needed:

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

Return/output values are indicated using an "O" prefix, input values + are indicated using the "I" prefix, and values that are both input and + output use the "IO" prefix for the corresponding in-line comment.

+

B.4 Variables

+

B.4.1 Naming

+

Variables with a global scope shall be capitalized ("ThisVariable", + "ThatVariable", "ThisStateVariable", etc.) The only exception to this + rule shall be the CUPS interface library global variables which must + begin with the prefix "cups" ("cupsThisVariable", "cupsThatVariable", + etc.) Global variables shall be replaced by function arguments whenever + possible.

+

Variables with a local scope shall be lowercase with underscores + between words ("this_variable", "that_variable", etc.) Any local + variables shared by functions within a source file shall be declared + "static".

+

B.4.2 Documentation

+

Each variable shall be declared on a separate line and shall be + immediately followed by a comment block describing the variable:

+
+    int this_variable;   /* The current state of this */
+    int that_variable;   /* The current state of that */
+
+

B.5 Types

+

B.5.1 Naming

+

All type names shall be lowercase with underscores between words and + "_t" appended to the end of the name ("this_type_t", "that_type_t", + etc.)

+

B.5.2 Documentation

+

Each type shall have a comment block immediately before the typedef:

+
+    /*
+     * This type is for CUPS foobar options.
+     */
+    typedef int cups_this_type_t;
+
+

B.6 Structures

+

B.6.1 Naming

+

All structure names shall be lowercase with underscores between words + and "_str" appended to the end of the name ("this_struct_str", + "that_struct_str", etc.)

+

B.6.2 Documentation

+

Each structure shall have a comment block immediately before the + struct and each member shall be documented in accordance with the + variable naming policy above:

+
+    /*
+     * This structure is for CUPS foobar options.
+     */
+    struct cups_this_struct_str
+    {
+      int this_member;   /* Current state for this */
+      int that_member;   /* Current state for that */
+    };
+
+

B.7 Classes

+

B.7.1 Naming

+

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

+

B.7.2 Documentation

+

Each class shall have a comment block immediately before the class + and each member shall be documented in accordance with the variable + naming policy above:

+
+    /*
+     * This class is for CUPS foobar options.
+     */
+    class cups_this_class
+    {
+      int this_member;   /* Current state for this */
+      int that_member;   /* Current state for that */
+    };
+
+

B.8 Constants

+

B.8.1 Naming

+

All constant names shall be uppercase with underscored between words + ("THIS_CONSTANT", "THAT_CONSTANT", etc.) Constants defined for the CUPS + interface library must begin with an uppercase prefix + ("CUPS_THIS_CONSTANT", "CUPS_THAT_CONSTANT", etc.)

+

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

+

B.8.2 Documentation

+

Comment blocks shall immediately follow each constant:

+
+    enum
+    {
+      CUPS_THIS_TRAY,   /* This tray */
+      CUPS_THAT_TRAY    /* That tray */
+    };
+
+

B.9 Code

+

B.9.1 Documentation

+

All source code shall utilize block comments within functions to + describe the operations being performed by a group of statements:

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

B.9.2 Style

+

B.9.2.a Indentation

+

All code blocks enclosed by brackets shall begin with the opening + brace on a new line. The code then follows starting on a new line after + the brace and is indented 2 spaces. The closing brace is then placed on + a new line following the code at the original indentation:

+
+    {
+      int i; /* Looping var */
+
+     /*
+      * Process foobar values from 0 to 999...
+      */
+
+      for (i = 0; i < 1000; i ++)
+      {
+	do_this(i);
+	do_that(i);
+      }
+    }
+
+

Single-line statements following "do", "else", "for", "if", and + "while" shall be indented 2 spaces as well. Blocks of code in a + "switch" block shall be indented 4 spaces after each "case" and + "default" case:

+
+    switch (array[i])
+    {
+      case STATE_IDLE :
+	  do_this(i);
+	  do_that(i);
+	  break;
+      default :
+	  do_nothing(i);
+	  break;
+    }
+
+

B.9.2.b Spacing

+

A space shall follow each reserved word ("if", "while", etc.) Spaces + shall not be inserted between a function name and the arguments in + parenthesis.

+

B.9.2.c Return Values

+

Parenthesis shall surround values returned from a function using + "return":

+
+    return (STATE_IDLE);
+
+

B.9.2.d Loops

+

Whenever convenient loops should count downward to zero to improve + program performance:

+
+    for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
+      array[i] = STATE_IDLE;
+
+

C Software Trouble Report Form

+
+ + + + + + + + + + + + + + +
Summary of Problem: +_____________________________________________
 
Problem Severity: +__1Request for enhancement, e.g. asking for a feature
__2Low, e.g. a documentation error or undocumented + side-effect
__3Moderate, e.g. unable to print a file or unable to + compile the software
__4High, e.g. unable to print to a printer or key + functionality not working
__5Critical, e.g. unable to print at all
 
Problem Scope: +__1Machine or printer
__2Operating System
__3All machines, printers, or operating systems
 
Detailed Description of Problem:_____________________________________________ +
_____________________________________________ +
_____________________________________________ +
_____________________________________________ +
_____________________________________________
+
+ + diff --git a/doc/cmp.pdf b/doc/cmp.pdf new file mode 100644 index 0000000000000000000000000000000000000000..47b50ffe31b3197cbe1d18a300263e6834f75448 GIT binary patch literal 300850 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 ^W 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

YTI64rftzkGAJu{}fbG;}yzQx=$#G35-uxVH(pE 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 literal 0 Hc-jL100001 diff --git a/doc/cmp.shtml b/doc/cmp.shtml new file mode 100644 index 000000000..360d985ef --- /dev/null +++ b/doc/cmp.shtml @@ -0,0 +1,737 @@ + + + + + + CUPS Configuration Management Plan + + + +

Scope

+ +

Identification

+ +

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

Document Overview

+ +

This configuration management document is organized into the +following sections: + +

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

File Management

+ +

Directory Structure

+ +

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

Source Files

+ +

Source files shall be documented and formatted as described +in Appendix B, Coding Requirements. To remain compatible with +older UNIX filesystems, source file names shall not exceed 16 +characters in length. + +

Configuration Management

+ +

Source files shall be placed under the control of the +Concurrent Versions System ("CVS") software. Source files shall +be "checked in" with each change so that modifications can be +tracked. + +

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

Trouble Report Processing

+ +

A Software Trouble Report ("STR") shall be submitted every +time a user or vendor experiences a problem with the CUPS +software. Trouble reports are maintained in a database with one +of the following states: + +

    +
  1. STR is closed with complete resolution
  2. +
  3. STR is closed without resolution
  4. +
  5. STR is active, waiting on information from submitter
  6. +
  7. STR is pending with additional information from submitter
  8. +
  9. STR is newly submitted
  10. +
+ +

Trouble reports shall be processed using the following steps. + +

Classification

+ +

When a trouble report is received it must be classified at +one of the following priority levels: + +

    + +
  1. Request for enhancement, e.g. asking for a + feature
  2. + +
  3. Low, e.g. a documentation error or undocumented + side-effect
  4. + +
  5. Moderate, e.g. unable to print a file or unable to + compile the software
  6. + +
  7. High, e.g. unable to print to a printer or key + functionality not working
  8. + +
  9. Critical, e.g. unable to print at all
  10. + +
+ +

Level 4 and 5 trouble reports must be resolved in the next +software release. Level 1 to 3 trouble reports are scheduled for +resolution in a specific release at the discretion of the +release coordinator. + +

The scope of the problem should also be determined as: + +

    +
  1. Specific to a machine or printer
  2. +
  3. Specific to an operating system
  4. +
  5. Applies to all machines, printers, and operating systems
  6. +
+ +

Identification

+ +

Once the level and scope of the trouble report is determined +the software sub-system(s) involved with the problem are +determined. This may involve additional communication with the +user or vendor to isolate the problem to a specific cause. + +

When the sub-system(s) involved have been identified, an +engineer will then determine the change(s) needed and estimate +the time required for the change(s). + +

Correction

+ +

Corrections are scheduled based upon the severity and +complexity of the problem. Once all changes have been made, +documented, and tested successfully a new software release +snapshot is generated. Additional tests are added as necessary +for proper testing of the changes. + +

Notification

+ +

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

Software Releases

+ +

Version Numbering

+ +

CUPS uses a three-part version number separated by periods to +represent the major, minor, and patch release numbers: + +

+    MAJOR.MINOR.PATCH
+    1.1.0
+
+ +

Beta-test releases are indentified by appending the letter B +followed by the build number: + +

+    MAJOR.MINOR.PATCHbBUILD
+    1.1.0b1
+
+ +

Release candidates are indentified by appending the letters +RC followed by the build number: + +

+    MAJOR.MINOR.PATCHrcBUILD
+    1.1.0rc1
+
+ +

A CVS snapshot is generated for every beta and final release +and uses the version number preceded by the letter "v" and with +the decimal points replaced by underscores: + +

+    v1_1_0b1
+    v1_1_0rc1
+    v1_1_0
+
+ +

Each change that corrects a fault in a software sub-system +increments the patch release number. If a change affects the +overall software design of CUPS then the minor release number +will be incremented and the patch release number reset to 0. If +CUPS is completely redesigned the major release number will be +incremented and the minor and patch release numbers reset to 0: + +

+    1.1.0b1    First beta release
+    1.1.0b2    Second beta release
+    1.1.0rc1   First release candidate
+    1.1.0rc2   Second release candidate
+    1.1.0      First production release
+    1.1.1b1    First beta of 1.1.1
+    1.1.1rc1   First release candidate of 1.1.1
+    1.1.1      Production release of 1.1.1
+    1.1.2b1    First beta of 1.1.2
+    1.1.2rc1   First release candidate of 1.1.2
+    1.1.2      Production release of 1.1.2
+    2.0.0b1    First beta of 2.0.0
+    2.0.0rc1   First release candidate of 2.0.0
+    2.0.0      Production release of 2.0.0
+
+ +

Generation

+ +

Software releases shall be generated for each successfully +completed software trouble report. All object and executable +files shall be deleted prior to performing a full build to +ensure that source files are recompiled.

+ +

Testing

+ +

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

+ +

Releases

+ +

When testing has been completed successfully a new +distribution image is created from the current CVS code +"snapshot". No release shall contain software that has not +passed the appropriate software tests. Three types of releases +are used, beta, release candidate, and production, and are +released using the following basic schedule: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
WeekVersionDescription
T-6 weeks1.1.0b1First beta
T-5 weeks1.1.0b2Second beta
T-4 weeks1.1.0b3Third beta
T-3 weeks1.1.0rc1First release candidate
T-2 weeks1.1.0rc2Second release candidate
T-0 weeks1.1.0Production
+ +

Beta releases are typically used prior to new major and minor +version releases. At least one release candidate is generated +prior to each production release.

+ +

Beta Releases

+ +

Beta releases are generated when substantial changes have +been made that may affect the reliability of the software. Beta +releases may cause loss of data, functionality, or services and +are provided for testing by qualified individuals.

+ +

Beta releases are an OPTIONAL part of the release process and +are generated as deemed appropriate by the release coordinator. +Functional changes may be included in subsequent beta releases +until the first release candidate.

+ +

Release Candidates

+ +

Release candidates are generated at least two weeks prior to +a production release. Release candidates are targeted for +end-users that wish to test new functionality or bug fixes prior +to the production release. While release candidates are intended +to be substantially bug-free, they may still contain defects +and/or not compile on specific platforms. + +

At least one release candidate is REQUIRED prior to any +production release. The distribution of a release candidate +marks the end of any functional improvements. Release candidates +are generated at weekly intervals until all level 4/5 trouble +reports are resolved. + +

Production Releases

+ +

Production releases are generated after a successful release +candidate and represent a stable release of the software +suitable for all users. + + + +

Coding Requirements

+ +

These coding requirements provide detailed information on +source file formatting and documentation content. These +guidelines shall be applied to all C and C++ source files +provided with CUPS. Source code for other languages should +conform to these requirements as allowed by the language. + +

Source Files

+ +

Naming

+ +

All source files names shall be 16 characters or less in +length to ensure compatibility with older UNIX filesystems. +Source files containing functions shall have an extension of +".c" for ANSI C and ".cxx" for C++ source files. All other +"include" files shall have an extension of ".h". + +

Documentation

+ +

The top of each source file shall contain a header giving the +name of the file, the purpose or nature of the source file, the +copyright and licensing notice, and the functions contained in +the file. The file name and revision information is provided by +the CVS "$Id$" tag: + +

+    /*
+     * "$Id$"
+     *
+     *   Description of file contents.
+     *
+     *   Copyright 1997-2005 by Easy Software Products, all rights
+     *   reserved.
+     *
+     *   These coded instructions, statements, and computer programs are
+     *   the property of Easy Software Products and are protected by
+     *   Federal copyright law.  Distribution and use rights are outlined
+     *   in the file "LICENSE.txt" which should have been included with
+     *   this file.  If this file is missing or damaged please contact
+     *   Easy Software Products at:
+     *
+     *       Attn: CUPS Licensing Information
+     *       Easy Software Products
+     *       44141 Airport View Drive, Suite 204
+     *       Hollywood, Maryland 20636 USA
+     *
+     *       Voice: (301) 373-9600
+     *       EMail: cups-info@cups.org
+     *         WWW: http://www.cups.org
+     *
+     * Contents:
+     *
+     *   function1() - Description 1.
+     *   function2() - Description 2.
+     *   function3() - Description 3.
+     */
+
+ + +

For source files that are subject to the Apple OS-Developed Software +exception, the following additional comment should appear after the +contact information: + +

+     *   This file is subject to the Apple OS-Developed Software exception.
+
+ +

The bottom of each source file shall contain a trailer giving +the name of the file using the CVS "$Id$" tag. The primary +purpose of this is to mark the end of a source file; if the +trailer is missing it is possible that code has been lost near +the end of the file: + +

+    /*
+     * End of "$Id$".
+     */
+
+ +

Functions

+ +

Naming

+ +

Functions with a global scope shall be capitalized ("DoThis", +"DoThat", "DoSomethingElse", etc.) The only exception to this +rule shall be the CUPS interface library functions which may +begin with a prefix word in lowercase ("cupsDoThis", +"cupsDoThat", etc.) + +

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

Documentation

+ +

Each function shall begin with a comment header describing +what the function does, the possible input limits (if any), and +the possible output values (if any), and any special information +needed: + +

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

Return/output values are indicated using an "O" prefix, input +values are indicated using the "I" prefix, and values that are +both input and output use the "IO" prefix for the corresponding +in-line comment. + +

Methods

+ +

Naming

+ +

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

Documentation

+ +

Each method shall begin with a comment header describing what +the method does, the possible input limits (if any), and the +possible output values (if any), and any special information +needed: + +

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

Return/output values are indicated using an "O" prefix, input +values are indicated using the "I" prefix, and values that are +both input and output use the "IO" prefix for the corresponding +in-line comment. + +

Variables

+ +

Naming

+ +

Variables with a global scope shall be capitalized +("ThisVariable", "ThatVariable", "ThisStateVariable", etc.) The +only exception to this rule shall be the CUPS interface library +global variables which must begin with the prefix "cups" +("cupsThisVariable", "cupsThatVariable", etc.) Global variables +shall be replaced by function arguments whenever possible. + +

Variables with a local scope shall be lowercase with +underscores between words ("this_variable", "that_variable", +etc.) Any local variables shared by functions within a source +file shall be declared "static". + +

Documentation

+ +

Each variable shall be declared on a separate line and shall +be immediately followed by a comment block describing the +variable: + +

+    int this_variable;   /* The current state of this */
+    int that_variable;   /* The current state of that */
+
+ +

Types

+ +

Naming

+ +

All type names shall be lowercase with underscores between +words and "_t" appended to the end of the name ("this_type_t", +"that_type_t", etc.) + +

Documentation

+ +

Each type shall have a comment block immediately before the +typedef: + +

+    /*
+     * This type is for CUPS foobar options.
+     */
+    typedef int cups_this_type_t;
+
+ +

Structures

+ +

Naming

+ +

All structure names shall be lowercase with underscores +between words and "_str" appended to the end of the name +("this_struct_str", "that_struct_str", etc.) + +

Documentation

+ +

Each structure shall have a comment block immediately before +the struct and each member shall be documented in accordance +with the variable naming policy above: + +

+    /*
+     * This structure is for CUPS foobar options.
+     */
+    struct cups_this_struct_str
+    {
+      int this_member;   /* Current state for this */
+      int that_member;   /* Current state for that */
+    };
+
+ +

Classes

+ +

Naming

+ +

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

Documentation

+ +

Each class shall have a comment block immediately before the +class and each member shall be documented in accordance with the +variable naming policy above: + +

+    /*
+     * This class is for CUPS foobar options.
+     */
+    class cups_this_class
+    {
+      int this_member;   /* Current state for this */
+      int that_member;   /* Current state for that */
+    };
+
+ +

Constants

+ +

Naming

+ +

All constant names shall be uppercase with underscored +between words ("THIS_CONSTANT", "THAT_CONSTANT", etc.) Constants +defined for the CUPS interface library must begin with an +uppercase prefix ("CUPS_THIS_CONSTANT", "CUPS_THAT_CONSTANT", +etc.) + +

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

Documentation

+ +

Comment blocks shall immediately follow each constant: + +

+    enum
+    {
+      CUPS_THIS_TRAY,   /* This tray */
+      CUPS_THAT_TRAY    /* That tray */
+    };
+
+ +

Code

+ +

Documentation

+ +

All source code shall utilize block comments within functions +to describe the operations being performed by a group of +statements: + +

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

Style

+ +

Indentation

+ +

All code blocks enclosed by brackets shall begin with the +opening brace on a new line. The code then follows starting on a +new line after the brace and is indented 2 spaces. The closing +brace is then placed on a new line following the code at the +original indentation: + +

+    {
+      int i; /* Looping var */
+
+     /*
+      * Process foobar values from 0 to 999...
+      */
+
+      for (i = 0; i < 1000; i ++)
+      {
+	do_this(i);
+	do_that(i);
+      }
+    }
+
+ +

Single-line statements following "do", "else", "for", "if", +and "while" shall be indented 2 spaces as well. Blocks of code +in a "switch" block shall be indented 4 spaces after each "case" +and "default" case: + +

+    switch (array[i])
+    {
+      case STATE_IDLE :
+	  do_this(i);
+	  do_that(i);
+	  break;
+      default :
+	  do_nothing(i);
+	  break;
+    }
+
+ +

Spacing

+ +

A space shall follow each reserved word ("if", "while", etc.) +Spaces shall not be inserted between a function name and the +arguments in parenthesis. + +

Return Values

+ +

Parenthesis shall surround values returned from a function +using "return": + +

+    return (STATE_IDLE);
+
+ +

Loops

+ +

Whenever convenient loops should count downward to zero to +improve program performance: + +

+    for (i = sizeof(array) / sizeof(array[0]) - 1; i >= 0; i --)
+      array[i] = STATE_IDLE;
+
+ +

Software Trouble Report Form

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Summary of Problem:_____________________________________________
 
Problem Severity:__1Request for enhancement, e.g. asking for a + feature
__2Low, e.g. a documentation error or undocumented + side-effect
__3Moderate, e.g. unable to print a file or unable to + compile the software
__4High, e.g. unable to print to a printer or key + functionality not working
__5Critical, e.g. unable to print at all
 
Problem Scope:__1Machine or printer
__2Operating System
__3All machines, printers, or operating systems
 
Detailed Description of Problem:_____________________________________________ +
_____________________________________________ +
_____________________________________________ +
_____________________________________________ +
_____________________________________________
+ + + diff --git a/doc/cups.css b/doc/cups.css new file mode 100644 index 000000000..c33a47c7b --- /dev/null +++ b/doc/cups.css @@ -0,0 +1,207 @@ +BODY { + background: #cccc99; + color: #000000; + font-family: sans-serif; +} + +H1, H2, H3, H4, H5, H6, P, TD, TH { + font-family: sans-serif; +} + +KBD { + color: #006600; + font-family: monospace; + font-weight: bold; +} + +PRE { + color: #7f0000; + font-family: monospace; +} + +PRE.command { + margin-left: 3em; +} + +PRE EM { + color: #3f0000; +} + +P.command { + color: #7f0000; + font-family: monospace; + margin-left: 3em; +} + +BLOCKQUOTE { + background: #cccc99; + border: solid thin #999966; + padding: 10px; +} + +A:link, A:visited { + text-decoration: none; + font-weight: bold; + color: #993300; +} + +A:link:hover, A:visited:hover, A:active { + text-decoration: underline; + font-weight: bold; + color: #bb5500; +} + +A.sel, TR.sel { + background-color: #eeeebb; + color: #993300; +} + +TR.sel TD { + padding: 4; +} + +A.unsel { + background-color: #666633; + color: #e8e8b8; +} + +A.unsel:link:hover, A.unsel:visited:hover, A.unsel:active { + background-color: #999966; + color: #663300; +} + +INPUT[TYPE="TEXT"], TEXTAREA { + font-family: monospace; +} + +INPUT[TYPE="IMAGE"] { + border: none; + padding: 2; + vertical-align: bottom; +} + +SUB, SUP { + font-size: 50%; +} + +TR.header, TR.header TH, TH.header, TR.trailer, TR.trailer TH, TH.trailer { + background-color: #bbbb88; +} + +TR.page, TD.page { + background-color: #eeeebb; + height: 100%; + padding-top: 20px; + padding-bottom: 20px; +} + +TR.data, TD.data, TR.data TD { + padding: 5; + border-bottom: solid 2px #000000; +} + +TR.data TH { + border-bottom: solid 2px #000000; + padding-top: 10; + padding-left: 5; + text-align: left; +} + +DIV.table TABLE { + border: solid thin #999966; + border-spacing: 0px; + margin-left: auto; + margin-right: auto; +} + +DIV.table CAPTION { + caption-side: top; + font-size: 120%; + font-style: italic; + font-weight: bold; + margin-left: auto; + margin-right: auto; +} + +DIV.table TABLE TD { + border: solid thin #bbbb88; + padding-top: 5px; +} + +DIV.table TABLE TH { + background: #bbbb88; + border: none; + border-bottom: solid thin #999966; +} + +TH.label { + padding-top: 10; + text-align: right; + vertical-align: top; +} + +HR { + border: solid thin; +} + +SPAN.info { + background: #000000; + border: thin solid #000000; + color: #ffffff; + font-size: 80%; + font-style: italic; + font-weight: bold; + white-space: nowrap; +} + +H3 SPAN.info { + float: right; + font-size: 100%; +} + +.conflict { + color: red; +} + +H2.title, H3.title { + border-bottom: solid 2px #000000; +} + +IMG.button { + border: none; + padding: 2; + vertical-align: middle; +} + +DIV.sidebar { + background: #ddddaa; + border: solid 2px #cccc99; + float: right; + margin-left: 10px; + padding: 5; + width: 25%; +} + +DIV.sidebar P.l0 { + margin-bottom: 0; + margin-left: 0; + margin-right: 0; + margin-top: 1em; +} + +DIV.sidebar P.l1 { + margin-bottom: 0; + margin-left: 3em; + margin-right: 0; + margin-top: 0; + text-indent: -2em; +} + +DIV.sidebar P.l2 { + font-style: italic; + margin-bottom: 0; + margin-left: 4em; + margin-right: 0; + margin-top: 0; + text-indent: -2em; +} 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/favicon.ico b/doc/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..f3aa3068b56d7e5bc842c2eb231fb553610db02c GIT binary patch literal 3638 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 + +

Terms

+ +
+ +
C +
A computer language. + +
parallel +
Sending or receiving data more than 1 bit at a time. + +
pipe +
A one-way communications channel between two programs. + +
serial +
Sending or receiving data 1 bit at a time. + +
socket +
A two-way network communications channel. + +
+ +

Acronyms

+ +
+ +
ASCII +
American Standard Code for Information Interchange + +
CUPS +
Common UNIX Printing System + +
ESC/P +
EPSON Standard Code for Printers + +
FTP +
File Transfer Protocol + +
HP-GL +
Hewlett-Packard Graphics Language + +
HP-PCL +
Hewlett-Packard Page Control Language + +
HP-PJL +
Hewlett-Packard Printer Job Language + +
IETF +
Internet Engineering Task Force + +
IPP +
Internet Printing Protocol + +
ISO +
International Standards Organization + +
LPD +
Line Printer Daemon + +
MIME +
Multimedia Internet Mail Exchange + +
PPD +
PostScript Printer Description + +
SMB +
Server Message Block + +
TFTP +
Trivial File Transfer Protocol + +
diff --git a/doc/help/access_log-reference.html b/doc/help/access_log-reference.html new file mode 100644 index 000000000..e4ce813b1 --- /dev/null +++ b/doc/help/access_log-reference.html @@ -0,0 +1,137 @@ + + + + access_log + + + +

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

+ +

+ +host group user date-time \"method resource version\" status +bytes ipp-operation ipp-status
+ +
+ +10.0.1.2 - - [01/Dec/2005:21:50:28 +0000] "POST / HTTP/1.1" 200 +317 CUPS-Get-Printers +successful-ok-ignored-or-substituted-attributes
+ +localhost - - [01/Dec/2005:21:50:32 +0000] "GET /admin HTTP/1.1" +200 0 - -
+ +localhost - - [01/Dec/2005:21:50:32 +0000] "POST / HTTP/1.1" 200 +157 CUPS-Get-Printers +successful-ok-ignored-or-substituted-attributes
+ +localhost - - [01/Dec/2005:21:50:32 +0000] "POST / HTTP/1.1" 200 +1411 CUPS-Get-Devices -
+ +localhost - - [01/Dec/2005:21:50:32 +0000] "GET /admin HTTP/1.1" +200 6667 - -
+ +

+ +

The host field will normally only be an IP address +unless you have enabled the HostNameLookups +directive in the cupsd.conf file or if the IP address +corresponds to your local machine.

+ +

The group field always contains "-".

+ +

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

+ +

The date-time field is the date and time of the request +in local time and is in the format:

+ +

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

+ +

The method field is the HTTP method used: "GET", +"OPTIONS", "PUT", or "POST". "GET" requests are used to get files +from the server, both for the web interface and to get +configuration and log files. "OPTIONS" requests are used to +upgrade connections to TLS encryption. "PUT" requests are used to +upload configuration files. "POST" requests are used for web +interface forms and IPP requests.

+ +

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

+ +

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

+ +

The status field contains the HTTP result status of the +request, as follows:

+ +
    + +
  • 200 - Successful operation.
  • + +
  • 201 - File created/modified successfully.
  • + +
  • 304 - The requested file has not changed.
  • + +
  • 400 - Bad HTTP request; typically this + means that you have a malicious program trying to access + your server.
  • + +
  • 401 - Unauthorized, authentication + (username + password) is required.
  • + +
  • 403 - Access is forbidden; typically + this means that a client tried to access a file or + resource they do not have permission to access.
  • + +
  • 404 - The file or resource does not + exist.
  • + +
  • 405 - URL access method is not allowed; + typically this means you have a web browser using your + server as a proxy.
  • + +
  • 413 - Request too large; typically this + means that a client tried to print a file larger than the + MaxRequestSize + allows.
  • + +
  • 426 - Upgrading to TLS-encrypted + connection.
  • + +
  • 500 - Server error; typically this + happens when the server is unable to open/create a file - + consult the error_log file for details.
  • + +
  • 501 - The client requested encryption + but encryption support is not enabled/compiled in.
  • + +
  • 505 - HTTP version number not supported; + typically this means that you have a malicious program + trying to access your server.
  • + +
+ +

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

+ +

The ipp-operation field contains either "-" for non-IPP +requests or the IPP operation name for POST requests containing +an IPP request.

+ +

The ipp-status field contains either "-" for non-IPP +requests or the IPP status code name for POST requests containing +an IPP response.

+ + + diff --git a/doc/help/api-array.html b/doc/help/api-array.html new file mode 100644 index 000000000..85b22235e --- /dev/null +++ b/doc/help/api-array.html @@ -0,0 +1,399 @@ + + + + + Array API + + + + + + + +

Introduction

+ +

The CUPS array API provides a high-performance generic array +container. The contents of the array container can be sorted and +the container itself is designed for optimal speed and memory +usage under a wide variety of conditions.

+ +

The CUPS scheduler (cupsd) and many of the CUPS API +functions use the array API to efficiently manage large lists of +data.

+ +

General Usage

+ +

The <cups/array.h> header file must be +included to use the cupsArray functions.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

All of these functions require CUPS 1.2 or higher.

+

Contents

+ + +

Functions

+ + +

cupsArrayAdd()

+

Description

+

Add an element to the array.

+

Syntax

+
+int
+cupsArrayAdd(
+    cups_array_t * a,
+    void * e);
+
+

Arguments

+
+ + + + +
NameDescription
aArray
eElement
+

Returns

+

1 on success, 0 on failure

+ +

cupsArrayClear()

+

Description

+

Clear the array.

+

Syntax

+
+void
+cupsArrayClear(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

Nothing.

+ +

cupsArrayCount()

+

Description

+

Get the number of elements in the array.

+

Syntax

+
+int
+cupsArrayCount(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

Number of elements

+ +

cupsArrayCurrent()

+

Description

+

Return the current element in the array.

+

Syntax

+
+void *
+cupsArrayCurrent(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

Element

+ +

cupsArrayDelete()

+

Description

+

Free all memory used by the array.

+

Syntax

+
+void
+cupsArrayDelete(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

Nothing.

+ +

cupsArrayDup()

+

Description

+

Duplicate the array.

+

Syntax

+
+cups_array_t *
+cupsArrayDup(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

Duplicate array

+ +

cupsArrayFind()

+

Description

+

Find an element in the array.

+

Syntax

+
+void *
+cupsArrayFind(
+    cups_array_t * a,
+    void * e);
+
+

Arguments

+
+ + + + +
NameDescription
aArray
eElement
+

Returns

+

Element found or NULL

+ +

cupsArrayFirst()

+

Description

+

Get the first element in the array.

+

Syntax

+
+void *
+cupsArrayFirst(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

First element or NULL

+ +

cupsArrayLast()

+

Description

+

Get the last element in the array.

+

Syntax

+
+void *
+cupsArrayLast(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

Last element or NULL

+ +

cupsArrayNew()

+

Description

+

Create a new array.

+

Syntax

+
+cups_array_t *
+cupsArrayNew(
+    cups_array_func_t f,
+    void * d);
+
+

Arguments

+
+ + + + +
NameDescription
fComparison function
dUser data
+

Returns

+

Array

+ +

cupsArrayNext()

+

Description

+

Get the next element in the array.

+

Syntax

+
+void *
+cupsArrayNext(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

Next element or NULL

+ +

cupsArrayPrev()

+

Description

+

Get the previous element in the array.

+

Syntax

+
+void *
+cupsArrayPrev(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

Previous element or NULL

+ +

cupsArrayRemove()

+

Description

+

Remove an element from the array.

+

Syntax

+
+int
+cupsArrayRemove(
+    cups_array_t * a,
+    void * e);
+
+

Arguments

+
+ + + + +
NameDescription
aArray
eElement
+

Returns

+

1 on success, 0 on failure

+ +

cupsArrayRestore()

+

Description

+

Reset the current element to the last cupsArraySave.

+

Syntax

+
+void *
+cupsArrayRestore(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

New current element

+ +

cupsArraySave()

+

Description

+

Mark the current element for a later cupsArrayRestore. + +The save/restore stack is guaranteed to be at least 32 elements deep.

+

Syntax

+
+int
+cupsArraySave(
+    cups_array_t * a);
+
+

Arguments

+
+ + + +
NameDescription
aArray
+

Returns

+

1 on success, 0 on failure

+ +

Types

+ + +

cups_array_func_t

+

Description

+

Array comparison function

+

Definition

+
+typedef int (*cups_array_func_t)(void *first, void *second, void *data);
+
+ +

cups_array_t

+

Description

+

CUPS array type

+

Definition

+
+typedef struct _cups_array_s cups_array_t;
+
+ + diff --git a/doc/help/api-cups.html b/doc/help/api-cups.html new file mode 100644 index 000000000..9d084f219 --- /dev/null +++ b/doc/help/api-cups.html @@ -0,0 +1,1464 @@ + + + + + CUPS API + + + + + + + +

Introduction

+ +

The CUPS APIs provide...

+ +

General Usage

+ +

The <cups/cups.h> header file must be included to +use the CUPS functions.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

Unless otherwise specified, the CUPS API functions require +CUPS 1.1 or higher.

+

Contents

+ + +

Enumerations

+ + +

cups_ptype_e

+

Description

+

Not a typedef'd enum so we can OR

+

Values

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
CUPS_PRINTER_AUTHENTICATED  CUPS 1.2 Printer requires authentication
CUPS_PRINTER_BIND Can bind output
CUPS_PRINTER_BW Can do B&W printing
CUPS_PRINTER_CLASS Printer class
CUPS_PRINTER_COLLATE Can collage copies
CUPS_PRINTER_COLOR Can do color printing
CUPS_PRINTER_COPIES Can do copies
CUPS_PRINTER_COVER Can cover output
CUPS_PRINTER_DEFAULT Default printer on network
CUPS_PRINTER_DELETE  CUPS 1.2 Delete printer
CUPS_PRINTER_DUPLEX Can do duplexing
CUPS_PRINTER_FAX Fax queue
CUPS_PRINTER_IMPLICIT Implicit class
CUPS_PRINTER_LARGE Can do D/E/A1/A0
CUPS_PRINTER_LOCAL Local printer or class
CUPS_PRINTER_MEDIUM Can do Tabloid/B/C/A3/A2
CUPS_PRINTER_NOT_SHARED  CUPS 1.2 Printer is not shared
CUPS_PRINTER_OPTIONS ~(CLASS | REMOTE | IMPLICIT)
CUPS_PRINTER_PUNCH Can punch output
CUPS_PRINTER_REJECTING Printer is rejecting jobs
CUPS_PRINTER_REMOTE Remote printer or class
CUPS_PRINTER_SMALL Can do Letter/Legal/A4
CUPS_PRINTER_SORT Can sort output
CUPS_PRINTER_STAPLE Can staple output
CUPS_PRINTER_VARIABLE Can do variable sizes
+ +

Functions

+ + +

cupsAddDest()

+

Description

+

Add a destination to the list of destinations. + +Use the cupsSaveDests() function to save the updated list of destinations +to the user's lpoptions file.

+

Syntax

+
+int
+cupsAddDest(
+    const char * name,
+    const char * instance,
+    int num_dests,
+    cups_dest_t ** dests);
+
+

Arguments

+
+ + + + + + +
NameDescription
nameName of destination
instanceInstance of destination or NULL for none/primary
num_destsNumber of destinations
destsDestinations
+

Returns

+

New number of destinations

+ +

cupsAddOption()

+

Description

+

Add an option to an option array.

+

Syntax

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

Arguments

+
+ + + + + + +
NameDescription
nameName of option
valueValue of option
num_optionsNumber of options
optionsPointer to options
+

Returns

+

Number of options

+ +

cupsCancelJob()

+

Description

+

Cancel a print job on the default server. + +Use the cupsLastError() and cupsLastErrorString() functions to get +the cause of any failure.

+

Syntax

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

Arguments

+
+ + + + +
NameDescription
nameName of printer or class
jobJob ID
+

Returns

+

1 on success, 0 on failure

+ +

 CUPS 1.1.20 cupsDoAuthentication()

+

Description

+

Authenticate a request. + +This function should be called in response to a HTTP_UNAUTHORIZED +status, prior to resubmitting your request. + +

+

Syntax

+
+int
+cupsDoAuthentication(
+    http_t * http,
+    const char * method,
+    const char * resource);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
methodRequest method (GET, POST, PUT)
resourceResource path
+

Returns

+

0 on success, -1 on error

+ +

cupsDoFileRequest()

+

Description

+

Do an IPP request. + +This function sends any IPP request to the specified server, retrying +and authenticating as necessary.

+

Syntax

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

Arguments

+
+ + + + + + +
NameDescription
httpHTTP connection to server
requestIPP request
resourceHTTP resource for POST
filenameFile to send or NULL for none
+

Returns

+

Response data

+ +

cupsEncodeOptions()

+

Description

+

Encode printer options into IPP attributes. + +This function adds operation, job, and then subscription attributes, +in that order. Use the cupsEncodeOptions2() function to add attributes +for a single group.

+

Syntax

+
+void
+cupsEncodeOptions(
+    ipp_t * ipp,
+    int num_options,
+    cups_option_t * options);
+
+

Arguments

+
+ + + + + +
NameDescription
ippRequest to add to
num_optionsNumber of options
optionsOptions
+

Returns

+

Nothing.

+ +

 CUPS 1.2 cupsEncodeOptions2()

+

Description

+

Encode printer options into IPP attributes for a group. + +This function only adds attributes for a single group. Call this +function multiple times for each group, or use cupsEncodeOptions() +to add the standard groups. + +

+

Syntax

+
+void
+cupsEncodeOptions2(
+    ipp_t * ipp,
+    int num_options,
+    cups_option_t * options,
+    ipp_tag_t group_tag);
+
+

Arguments

+
+ + + + + + +
NameDescription
ippRequest to add to
num_optionsNumber of options
optionsOptions
group_tagGroup to encode
+

Returns

+

Nothing.

+ +

cupsEncryption()

+

Description

+

Get the default encryption settings. + +The default encryption setting comes from the CUPS_ENCRYPTION +environment variable, then the ~/.cupsrc file, and finally the +/etc/cups/client.conf file. If not set, the default is +HTTP_ENCRYPT_IF_REQUESTED.

+

Syntax

+
+http_encryption_t
+cupsEncryption(void);
+
+

Arguments

+

None.

+

Returns

+

Encryption settings

+ +

cupsFreeDests()

+

Description

+

Free the memory used by the list of destinations.

+

Syntax

+
+void
+cupsFreeDests(
+    int num_dests,
+    cups_dest_t * dests);
+
+

Arguments

+
+ + + + +
NameDescription
num_destsNumber of destinations
destsDestinations
+

Returns

+

Nothing.

+ +

cupsFreeJobs()

+

Description

+

Free memory used by job data.

+

Syntax

+
+void
+cupsFreeJobs(
+    int num_jobs,
+    cups_job_t * jobs);
+
+

Arguments

+
+ + + + +
NameDescription
num_jobsNumber of jobs
jobsJobs
+

Returns

+

Nothing.

+ +

cupsFreeOptions()

+

Description

+

Free all memory used by options.

+

Syntax

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

Arguments

+
+ + + + +
NameDescription
num_optionsNumber of options
optionsPointer to options
+

Returns

+

Nothing.

+ +

 DEPRECATED cupsGetClasses()

+

Description

+

Get a list of printer classes from the default server. + +This function is deprecated - use cupsGetDests() instead. + +

+

Syntax

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

Arguments

+
+ + + +
NameDescription
classesClasses
+

Returns

+

Number of classes

+ +

cupsGetDefault()

+

Description

+

Get the default printer or class for the default server. + +This function returns the default printer or class as defined by +the LPDEST or PRINTER environment variables. If these environment +variables are not set, the server default destination is returned. +Applications should use the cupsGetDests() and cupsGetDest() functions +to get the user-defined default printer, as this function does not +support the lpoptions-defined default printer.

+

Syntax

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

Arguments

+

None.

+

Returns

+

Default printer or NULL

+ +

 CUPS 1.1.21 cupsGetDefault2()

+

Description

+

Get the default printer or class for the specified server. + +This function returns the default printer or class as defined by +the LPDEST or PRINTER environment variables. If these environment +variables are not set, the server default destination is returned. +Applications should use the cupsGetDests() and cupsGetDest() functions +to get the user-defined default printer, as this function does not +support the lpoptions-defined default printer. + +

+

Syntax

+
+const char *
+cupsGetDefault2(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP connection
+

Returns

+

Default printer or NULL

+ +

cupsGetDest()

+

Description

+

Get the named destination from the list. + +Use the cupsGetDests() or cupsGetDests2() functions to get a +list of supported destinations for the current user.

+

Syntax

+
+cups_dest_t *
+cupsGetDest(
+    const char * name,
+    const char * instance,
+    int num_dests,
+    cups_dest_t * dests);
+
+

Arguments

+
+ + + + + + +
NameDescription
nameName of destination
instanceInstance of destination
num_destsNumber of destinations
destsDestinations
+

Returns

+

Destination pointer or NULL

+ +

cupsGetDests()

+

Description

+

Get the list of destinations from the default server.

+

Syntax

+
+int
+cupsGetDests(
+    cups_dest_t ** dests);
+
+

Arguments

+
+ + + +
NameDescription
destsDestinations
+

Returns

+

Number of destinations

+ +

 CUPS 1.1.21 cupsGetDests2()

+

Description

+

Get the list of destinations from the specified server. + +

+

Syntax

+
+int
+cupsGetDests2(
+    http_t * http,
+    cups_dest_t ** dests);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP connection
destsDestinations
+

Returns

+

Number of destinations

+ +

 CUPS 1.1.20 cupsGetFd()

+

Description

+

Get a file from the server. + +This function returns HTTP_OK when the file is successfully retrieved. + +

+

Syntax

+
+http_status_t
+cupsGetFd(
+    http_t * http,
+    const char * resource,
+    int fd);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
resourceResource name
fdFile descriptor
+

Returns

+

Status

+ +

 CUPS 1.1.20 cupsGetFile()

+

Description

+

Get a file from the server. + +This function returns HTTP_OK when the file is successfully retrieved. + +

+

Syntax

+
+http_status_t
+cupsGetFile(
+    http_t * http,
+    const char * resource,
+    const char * filename);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
resourceResource name
filenameFilename
+

Returns

+

Status

+ +

cupsGetJobs()

+

Description

+

Get the jobs from the default server.

+

Syntax

+
+int
+cupsGetJobs(
+    cups_job_t ** jobs,
+    const char * mydest,
+    int myjobs,
+    int completed);
+
+

Arguments

+
+ + + + + + +
NameDescription
jobsJob data
mydestOnly show jobs for dest?
myjobsOnly show my jobs?
completedOnly show completed jobs?
+

Returns

+

Number of jobs

+ +

 CUPS 1.1.21 cupsGetJobs2()

+

Description

+

Get the jobs from the specified server. + +

+

Syntax

+
+int
+cupsGetJobs2(
+    http_t * http,
+    cups_job_t ** jobs,
+    const char * mydest,
+    int myjobs,
+    int completed);
+
+

Arguments

+
+ + + + + + + +
NameDescription
httpHTTP connection
jobsJob data
mydestOnly show jobs for dest?
myjobsOnly show my jobs?
completedOnly show completed jobs?
+

Returns

+

Number of jobs

+ +

cupsGetOption()

+

Description

+

Get an option value.

+

Syntax

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

Arguments

+
+ + + + + +
NameDescription
nameName of option
num_optionsNumber of options
optionsOptions
+

Returns

+

Option value or NULL

+ +

cupsGetPPD()

+

Description

+

Get the PPD file for a printer on the default server. + +For classes, cupsGetPPD() returns the PPD file for the first printer +in the class.

+

Syntax

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

Arguments

+
+ + + +
NameDescription
namePrinter name
+

Returns

+

Filename for PPD file

+ +

 CUPS 1.1.21 cupsGetPPD2()

+

Description

+

Get the PPD file for a printer from the specified server. + +For classes, cupsGetPPD2() returns the PPD file for the first printer +in the class. + +

+

Syntax

+
+const char *
+cupsGetPPD2(
+    http_t * http,
+    const char * name);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP connection
namePrinter name
+

Returns

+

Filename for PPD file

+ +

cupsGetPassword()

+

Description

+

Get a password from the user. + +Returns NULL if the user does not provide a password.

+

Syntax

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

Arguments

+
+ + + +
NameDescription
promptPrompt string
+

Returns

+

Password

+ +

 DEPRECATED cupsGetPrinters()

+

Description

+

Get a list of printers from the default server. + +This function is deprecated - use cupsGetDests() instead. + +

+

Syntax

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

Arguments

+
+ + + +
NameDescription
printersPrinters
+

Returns

+

Number of printers

+ +

cupsLangDefault()

+

Description

+

Return the default language.

+

Syntax

+
+cups_lang_t *
+cupsLangDefault(void);
+
+

Arguments

+

None.

+

Returns

+

Language data

+ +

cupsLangEncoding()

+

Description

+

Return the character encoding (us-ascii, etc.) +for the given language.

+

Syntax

+
+const char *
+cupsLangEncoding(
+    cups_lang_t * lang);
+
+

Arguments

+
+ + + +
NameDescription
langLanguage data
+

Returns

+

Character encoding

+ +

cupsLangFlush()

+

Description

+

Flush all language data out of the cache.

+

Syntax

+
+void
+cupsLangFlush(void);
+
+

Arguments

+

None.

+

Returns

+

Nothing.

+ +

cupsLangFree()

+

Description

+

Free language data. + +This does not actually free anything; use cupsLangFlush() for that.

+

Syntax

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

Arguments

+
+ + + +
NameDescription
langLanguage to free
+

Returns

+

Nothing.

+ +

cupsLangGet()

+

Description

+

Get a language.

+

Syntax

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

Arguments

+
+ + + +
NameDescription
languageLanguage or locale
+

Returns

+

Language data

+ +

cupsLastError()

+

Description

+

Return the last IPP status code.

+

Syntax

+
+ipp_status_t
+cupsLastError(void);
+
+

Arguments

+

None.

+

Returns

+

IPP status code from last request

+ +

 CUPS 1.2 cupsLastErrorString()

+

Description

+

Return the last IPP status-message. + +

+

Syntax

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

Arguments

+

None.

+

Returns

+

status-message text from last request

+ +

cupsMarkOptions()

+

Description

+

Mark command-line options in a PPD file.

+

Syntax

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

Arguments

+
+ + + + + +
NameDescription
ppdPPD file
num_optionsNumber of options
optionsOptions
+

Returns

+

1 if conflicting

+ +

cupsParseOptions()

+

Description

+

Parse options from a command-line argument. + +This function converts space-delimited name/value pairs according +to the PAPI text option ABNF specification. Collection values +("name={a=... b=... c=...}") are stored with the curley brackets +intact - use cupsParseOptions() on the value to extract the collection +attributes.

+

Syntax

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

Arguments

+
+ + + + + +
NameDescription
argArgument to parse
num_optionsNumber of options
optionsOptions found
+

Returns

+

Number of options found

+ +

cupsPrintFile()

+

Description

+

Print a file to a printer or class on the default server.

+

Syntax

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

Arguments

+
+ + + + + + + +
NameDescription
namePrinter or class name
filenameFile to print
titleTitle of job
num_optionsNumber of options
optionsOptions
+

Returns

+

Job ID

+ +

 CUPS 1.1.21 cupsPrintFile2()

+

Description

+

Print a file to a printer or class on the specified server. + +

+

Syntax

+
+int
+cupsPrintFile2(
+    http_t * http,
+    const char * name,
+    const char * filename,
+    const char * title,
+    int num_options,
+    cups_option_t * options);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
httpHTTP connection
namePrinter or class name
filenameFile to print
titleTitle of job
num_optionsNumber of options
optionsOptions
+

Returns

+

Job ID

+ +

cupsPrintFiles()

+

Description

+

Print one or more files to a printer or class on the default server.

+

Syntax

+
+int
+cupsPrintFiles(
+    const char * name,
+    int num_files,
+    const char ** files,
+    const char * title,
+    int num_options,
+    cups_option_t * options);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
namePrinter or class name
num_filesNumber of files
filesFile(s) to print
titleTitle of job
num_optionsNumber of options
optionsOptions
+

Returns

+

Job ID

+ +

 CUPS 1.1.21 cupsPrintFiles2()

+

Description

+

Print one or more files to a printer or class on the specified server. + +

+

Syntax

+
+int
+cupsPrintFiles2(
+    http_t * http,
+    const char * name,
+    int num_files,
+    const char ** files,
+    const char * title,
+    int num_options,
+    cups_option_t * options);
+
+

Arguments

+
+ + + + + + + + + +
NameDescription
httpHTTP connection
namePrinter or class name
num_filesNumber of files
filesFile(s) to print
titleTitle of job
num_optionsNumber of options
optionsOptions
+

Returns

+

Job ID

+ +

 CUPS 1.1.20 cupsPutFd()

+

Description

+

Put a file on the server. + +This function returns HTTP_CREATED when the file is stored successfully. + +

+

Syntax

+
+http_status_t
+cupsPutFd(
+    http_t * http,
+    const char * resource,
+    int fd);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
resourceResource name
fdFile descriptor
+

Returns

+

Status

+ +

 CUPS 1.1.20 cupsPutFile()

+

Description

+

Put a file on the server. + +This function returns HTTP_CREATED when the file is stored successfully. + +

+

Syntax

+
+http_status_t
+cupsPutFile(
+    http_t * http,
+    const char * resource,
+    const char * filename);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
resourceResource name
filenameFilename
+

Returns

+

Status

+ +

cupsServer()

+

Description

+

Return the hostname/address of the default server. + +The returned value can be a fully-qualified hostname, a numeric +IPv4 or IPv6 address, or a domain socket pathname.

+

Syntax

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

Arguments

+

None.

+

Returns

+

Server name

+ +

cupsSetDests()

+

Description

+

Save the list of destinations for the default server. + +This function saves the destinations to /etc/cups/lpoptions when run +as root and ~/.lpoptions when run as a normal user.

+

Syntax

+
+void
+cupsSetDests(
+    int num_dests,
+    cups_dest_t * dests);
+
+

Arguments

+
+ + + + +
NameDescription
num_destsNumber of destinations
destsDestinations
+

Returns

+

Nothing.

+ +

 CUPS 1.1.21 cupsSetDests2()

+

Description

+

Save the list of destinations for the specified server. + +This function saves the destinations to /etc/cups/lpoptions when run +as root and ~/.lpoptions when run as a normal user. + +

+

Syntax

+
+int
+cupsSetDests2(
+    http_t * http,
+    int num_dests,
+    cups_dest_t * dests);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection
num_destsNumber of destinations
destsDestinations
+

Returns

+

0 on success, -1 on error

+ +

cupsSetEncryption()

+

Description

+

Set the encryption preference.

+

Syntax

+
+void
+cupsSetEncryption(
+    http_encryption_t e);
+
+

Arguments

+
+ + + +
NameDescription
eNew encryption preference
+

Returns

+

Nothing.

+ +

cupsSetPasswordCB()

+

Description

+

Set the password callback for CUPS. + +Pass NULL to restore the default (console) password callback.

+

Syntax

+
+void
+cupsSetPasswordCB(
+    cups_password_cb_t cb);
+
+

Arguments

+
+ + + +
NameDescription
cbCallback function
+

Returns

+

Nothing.

+ +

cupsSetServer()

+

Description

+

Set the default server name. + +The "server" string can be a fully-qualified hostname, a numeric +IPv4 or IPv6 address, or a domain socket pathname. Pass NULL to +restore the default server name.

+

Syntax

+
+void
+cupsSetServer(
+    const char * server);
+
+

Arguments

+
+ + + +
NameDescription
serverServer name
+

Returns

+

Nothing.

+ +

cupsSetUser()

+

Description

+

Set the default user name. + +Pass NULL to restore the default user name.

+

Syntax

+
+void
+cupsSetUser(
+    const char * user);
+
+

Arguments

+
+ + + +
NameDescription
userUser name
+

Returns

+

Nothing.

+ +

cupsTempFd()

+

Description

+

Create a temporary file. + +The temporary filename is stored in the filename buffer.

+

Syntax

+
+int
+cupsTempFd(
+    char * filename,
+    int len);
+
+

Arguments

+
+ + + + +
NameDescription
filenamePointer to buffer
lenSize of buffer
+

Returns

+

New file descriptor

+ +

 DEPRECATED cupsTempFile()

+

Description

+

Generate a temporary filename. + +The temporary filename is stored in the filename buffer. +This function is deprecated - use cupsTempFd() or cupsTempFile2() +instead. + +

+

Syntax

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

Arguments

+
+ + + + +
NameDescription
filenamePointer to buffer
lenSize of buffer
+

Returns

+

Filename

+ +

 CUPS 1.2 cupsTempFile2()

+

Description

+

Create a temporary CUPS file. + +The temporary filename is stored in the filename buffer. + +

+

Syntax

+
+cups_file_t *
+cupsTempFile2(
+    char * filename,
+    int len);
+
+

Arguments

+
+ + + + +
NameDescription
filenamePointer to buffer
lenSize of buffer
+

Returns

+

CUPS file or NULL on error

+ +

cupsUser()

+

Description

+

Return the current user's name.

+

Syntax

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

Arguments

+

None.

+

Returns

+

User name

+ +

Structures

+ + +

cups_dest_s

+

Description

+

Destination

+

Definition

+
+struct cups_dest_s
+{
+  char *name, * instance;
+  int is_default;
+  int num_options;
+  cups_option_t * options;
+};
+
+

Members

+
+ + + + + + +
NameDescription
instance Local instance name or NULL
is_default Is this printer the default?
num_options Number of options
options Options
+ +

cups_job_s

+

Description

+

Job

+

Definition

+
+struct cups_job_s
+{
+  char *dest, *title, *user, * format;
+  int id;
+  int size, priority;
+  time_t completed_time, creation_time, processing_time;
+  ipp_jstate_t state;
+};
+
+

Members

+
+ + + + + + + +
NameDescription
format Document format
id The job ID
priority Priority (1-100)
processing_time Time the job was processed
state Job state
+ +

cups_option_s

+

Description

+

Types and structures...

+

Definition

+
+struct cups_option_s
+{
+  char * name;
+  char * value;
+};
+
+

Members

+
+ + + + +
NameDescription
name Name of option
value Value of option
+ +

Types

+ + +

char

+

Description

+

Printer Options

+

Definition

+
+typedef const * (*charcups_password_cb_t)(const char *);
+
+ +

cups_dest_t

+

Description

+

Destination

+

Definition

+
+typedef struct cups_dest_s cups_dest_t;
+
+ +

cups_job_t

+

Description

+

Job

+

Definition

+
+typedef struct cups_job_s cups_job_t;
+
+ +

cups_option_t

+

Description

+

Types and structures...

+

Definition

+
+typedef struct cups_option_s cups_option_t;
+
+ +

cups_ptype_t

+

Description

+

Printer Type/Capability Bits

+

Definition

+
+typedef unsigned cups_ptype_t;
+
+ + diff --git a/doc/help/api-filedir.html b/doc/help/api-filedir.html new file mode 100644 index 000000000..07c8a74a5 --- /dev/null +++ b/doc/help/api-filedir.html @@ -0,0 +1,661 @@ + + + + + File and Directory APIs + + + + + + + +

Introduction

+ +

The CUPS file and directory APIs provide portable interfaces +for manipulating files and listing files and directories. Unlike +stdio FILE streams, the cupsFile functions +allow you to open more than 256 files at any given time. They +also manage the platform-specific details of locking, large file +support, line endings (CR, LF, or CR LF), and reading and writing +files using Flate ("gzip") compression. Finally, you can also +connect, read from, and write to network connections using the +cupsFile functions.

+ +

The cupsDir functions manage the platform-specific +details of directory access/listing and provide a convenient way +to get both a list of files and the information (permissions, +size, timestamp, etc.) for each of those files.

+ +

The CUPS scheduler (cupsd), mailto notifier, +and many of the CUPS API functions use these functions for +everything except console (stdin, stdout, stderr) I/O.

+ +

General Usage

+ +

The <cups/dir.h> and +<cups/file.h> header files must be included to +use the cupsDir and cupsFile functions, +respectively.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

All of these functions require CUPS 1.2 or higher.

+

Contents

+ + +

Functions

+ + +

cupsDirClose()

+

Description

+

Close a directory.

+

Syntax

+
+void
+cupsDirClose(
+    cups_dir_t * dp);
+
+

Arguments

+
+ + + +
NameDescription
dpDirectory
+

Returns

+

Nothing.

+ +

cupsDirOpen()

+

Description

+

Open a directory.

+

Syntax

+
+cups_dir_t *
+cupsDirOpen(
+    const char * directory);
+
+

Arguments

+
+ + + +
NameDescription
directoryDirectory name
+

Returns

+

Directory

+ +

cupsDirRead()

+

Description

+

Read the next directory entry.

+

Syntax

+
+cups_dentry_t *
+cupsDirRead(
+    cups_dir_t * dp);
+
+

Arguments

+
+ + + +
NameDescription
dpDirectory
+

Returns

+

Directory entry

+ +

cupsDirRewind()

+

Description

+

Rewind to the start of the directory.

+

Syntax

+
+void
+cupsDirRewind(
+    cups_dir_t * dp);
+
+

Arguments

+
+ + + +
NameDescription
dpDirectory
+

Returns

+

Nothing.

+ +

cupsFileClose()

+

Description

+

Close a CUPS file.

+

Syntax

+
+int
+cupsFileClose(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

0 on success, -1 on error

+ +

cupsFileCompression()

+

Description

+

Return whether a file is compressed.

+

Syntax

+
+int
+cupsFileCompression(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

CUPS_FILE_NONE or CUPS_FILE_GZIP

+ +

cupsFileEOF()

+

Description

+

Return the end-of-file status.

+

Syntax

+
+int
+cupsFileEOF(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

1 on EOF, 0 otherwise

+ +

cupsFileFlush()

+

Description

+

Flush pending output.

+

Syntax

+
+int
+cupsFileFlush(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

0 on success, -1 on error

+ +

cupsFileGetChar()

+

Description

+

Get a single character from a file.

+

Syntax

+
+int
+cupsFileGetChar(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

Character or -1 on EOF

+ +

cupsFileGetConf()

+

Description

+

Get a line from a configuration file...

+

Syntax

+
+char *
+cupsFileGetConf(
+    cups_file_t * fp,
+    char * buf,
+    size_t buflen,
+    char ** value,
+    int * linenum);
+
+

Arguments

+
+ + + + + + + +
NameDescription
fpCUPS file
bufString buffer
buflenSize of string buffer
valuePointer to value
linenumCurrent line number
+

Returns

+

Line read of NULL on eof/error

+ +

cupsFileGets()

+

Description

+

Get a CR and/or LF-terminated line.

+

Syntax

+
+char *
+cupsFileGets(
+    cups_file_t * fp,
+    char * buf,
+    size_t buflen);
+
+

Arguments

+
+ + + + + +
NameDescription
fpCUPS file
bufString buffer
buflenSize of string buffer
+

Returns

+

Line read or NULL on eof/error

+ +

cupsFileLock()

+

Description

+

Temporarily lock access to a file.

+

Syntax

+
+int
+cupsFileLock(
+    cups_file_t * fp,
+    int block);
+
+

Arguments

+
+ + + + +
NameDescription
fpFile to lock
block1 to wait for the lock, 0 to fail right away
+

Returns

+

0 on success, -1 on error

+ +

cupsFileNumber()

+

Description

+

Return the file descriptor associated with a CUPS file.

+

Syntax

+
+int
+cupsFileNumber(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

File descriptor

+ +

cupsFileOpen()

+

Description

+

Open a CUPS file.

+

Syntax

+
+cups_file_t *
+cupsFileOpen(
+    const char * filename,
+    const char * mode);
+
+

Arguments

+
+ + + + +
NameDescription
filenameName of file
modeOpen mode
+

Returns

+

CUPS file or NULL

+ +

cupsFileOpenFd()

+

Description

+

Open a CUPS file using a file descriptor.

+

Syntax

+
+cups_file_t *
+cupsFileOpenFd(
+    int fd,
+    const char * mode);
+
+

Arguments

+
+ + + + +
NameDescription
fdFile descriptor
modeOpen mode
+

Returns

+

CUPS file or NULL

+ +

cupsFilePeekChar()

+

Description

+

Peek at the next character from a file.

+

Syntax

+
+int
+cupsFilePeekChar(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

Character or -1 on EOF

+ +

cupsFilePrintf()

+

Description

+

Write a formatted string.

+

Syntax

+
+int
+cupsFilePrintf(
+    cups_file_t * fp,
+    const char * format,
+    ...);
+
+

Arguments

+
+ + + + + +
NameDescription
fpCUPS file
formatPrintf-style format string
...Additional args as necessary
+

Returns

+

Number of bytes written or -1

+ +

cupsFilePutChar()

+

Description

+

Write a character.

+

Syntax

+
+int
+cupsFilePutChar(
+    cups_file_t * fp,
+    int c);
+
+

Arguments

+
+ + + + +
NameDescription
fpCUPS file
cCharacter to write
+

Returns

+

0 on success, -1 on error

+ +

cupsFilePuts()

+

Description

+

Write a string.

+

Syntax

+
+int
+cupsFilePuts(
+    cups_file_t * fp,
+    const char * s);
+
+

Arguments

+
+ + + + +
NameDescription
fpCUPS file
sString to write
+

Returns

+

Number of bytes written or -1

+ +

cupsFileRead()

+

Description

+

Read from a file.

+

Syntax

+
+ssize_t
+cupsFileRead(
+    cups_file_t * fp,
+    char * buf,
+    size_t bytes);
+
+

Arguments

+
+ + + + + +
NameDescription
fpCUPS file
bufBuffer
bytesNumber of bytes to read
+

Returns

+

Number of bytes read or -1

+ +

cupsFileRewind()

+

Description

+

Rewind a file.

+

Syntax

+
+off_t
+cupsFileRewind(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

New file position or -1

+ +

cupsFileSeek()

+

Description

+

Seek in a file.

+

Syntax

+
+off_t
+cupsFileSeek(
+    cups_file_t * fp,
+    off_t pos);
+
+

Arguments

+
+ + + + +
NameDescription
fpCUPS file
posPosition in file
+

Returns

+

New file position or -1

+ +

cupsFileTell()

+

Description

+

Return the current file position.

+

Syntax

+
+off_t
+cupsFileTell(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpCUPS file
+

Returns

+

File position

+ +

cupsFileUnlock()

+

Description

+

Unlock access to a file.

+

Syntax

+
+int
+cupsFileUnlock(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpFile to lock
+

Returns

+

0 on success, -1 on error

+ +

cupsFileWrite()

+

Description

+

Write to a file.

+

Syntax

+
+ssize_t
+cupsFileWrite(
+    cups_file_t * fp,
+    const char * buf,
+    size_t bytes);
+
+

Arguments

+
+ + + + + +
NameDescription
fpCUPS file
bufBuffer
bytesNumber of bytes to write
+

Returns

+

Number of bytes written

+ +

Structures

+ + +

cups_dentry_s

+

Description

+

Directory entry type

+

Definition

+
+struct cups_dentry_s
+{
+  struct stat fileinfo;
+  char filename[260];
+};
+
+

Members

+
+ + + + +
NameDescription
fileinfo File information
filename[260] File name
+ +

Types

+ + +

cups_dentry_t

+

Description

+

Directory entry type

+

Definition

+
+typedef struct cups_dentry_s cups_dentry_t;
+
+ +

cups_dir_t

+

Description

+

Directory type

+

Definition

+
+typedef struct _cups_dir_s cups_dir_t;
+
+ +

cups_file_t

+

Description

+

CUPS file type

+

Definition

+
+typedef struct _cups_file_s cups_file_t;
+
+ + diff --git a/doc/help/api-filter.html b/doc/help/api-filter.html new file mode 100644 index 000000000..51ccd2132 --- /dev/null +++ b/doc/help/api-filter.html @@ -0,0 +1,136 @@ + + + + + Filter and Backend APIs + + + + + + + +

Introduction

+ +

The CUPS filter and backend APIs provide...

+ +

General Usage

+ +

The <cups/backend.h> and +<cups/cups.h> header files must be included to +use the CUPS_BACKEND_ constants and +cupsBackchannel functions, respectively.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

All of these functions require CUPS 1.2 or higher.

+

Contents

+ + +

Functions

+ + +

 CUPS 1.2 cupsBackchannelRead()

+

Description

+

Read data from the backchannel. + +Reads up to "bytes" bytes from the backchannel. The "timeout" +parameter controls how many seconds to wait for the data - use +0.0 to return immediately if there is no data, -1.0 to wait +for data indefinitely. + +

+

Syntax

+
+int
+cupsBackchannelRead(
+    char * buffer,
+    int bytes,
+    double timeout);
+
+

Arguments

+
+ + + + + +
NameDescription
bufferBuffer to read
bytesBytes to read
timeoutTimeout in seconds
+

Returns

+

Bytes read or -1 on error

+ +

 CUPS 1.2 cupsBackchannelWrite()

+

Description

+

Write data to the backchannel. + +Writes "bytes" bytes to the backchannel. The "timeout" parameter +controls how many seconds to wait for the data to be written - use +0.0 to return immediately if the data cannot be written, -1.0 to wait +indefinitely. + +

+

Syntax

+
+int
+cupsBackchannelWrite(
+    const char * buffer,
+    int bytes,
+    double timeout);
+
+

Arguments

+
+ + + + + +
NameDescription
bufferBuffer to write
bytesBytes to write
timeoutTimeout in seconds
+

Returns

+

Bytes written or -1 on error

+ + diff --git a/doc/help/api-httpipp.html b/doc/help/api-httpipp.html new file mode 100644 index 000000000..1cd14c5c5 --- /dev/null +++ b/doc/help/api-httpipp.html @@ -0,0 +1,3795 @@ + + + + + HTTP and IPP APIs + + + + + + + +

Introduction

+ +

The CUPS HTTP and IPP APIs provide...

+ +

General Usage

+ +

The <cups/cups.h> header file must be included to +use the HTTP and IPP functions.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

Unless otherwise specified, the HTTP and IPP API functions +require CUPS 1.1 or higher.

+

Contents

+ + +

Enumerations

+ + +

cups_ptype_e

+

Description

+

Not a typedef'd enum so we can OR

+

Values

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
CUPS_PRINTER_AUTHENTICATED  CUPS 1.2 Printer requires authentication
CUPS_PRINTER_BIND Can bind output
CUPS_PRINTER_BW Can do B&W printing
CUPS_PRINTER_CLASS Printer class
CUPS_PRINTER_COLLATE Can collage copies
CUPS_PRINTER_COLOR Can do color printing
CUPS_PRINTER_COPIES Can do copies
CUPS_PRINTER_COVER Can cover output
CUPS_PRINTER_DEFAULT Default printer on network
CUPS_PRINTER_DELETE  CUPS 1.2 Delete printer
CUPS_PRINTER_DUPLEX Can do duplexing
CUPS_PRINTER_FAX Fax queue
CUPS_PRINTER_IMPLICIT Implicit class
CUPS_PRINTER_LARGE Can do D/E/A1/A0
CUPS_PRINTER_LOCAL Local printer or class
CUPS_PRINTER_MEDIUM Can do Tabloid/B/C/A3/A2
CUPS_PRINTER_NOT_SHARED  CUPS 1.2 Printer is not shared
CUPS_PRINTER_OPTIONS ~(CLASS | REMOTE | IMPLICIT)
CUPS_PRINTER_PUNCH Can punch output
CUPS_PRINTER_REJECTING Printer is rejecting jobs
CUPS_PRINTER_REMOTE Remote printer or class
CUPS_PRINTER_SMALL Can do Letter/Legal/A4
CUPS_PRINTER_SORT Can sort output
CUPS_PRINTER_STAPLE Can staple output
CUPS_PRINTER_VARIABLE Can do variable sizes
+ +

http_auth_e

+

Description

+

HTTP authentication types

+

Values

+
+ + + + + + + + +
NameDescription
HTTP_AUTH_BASIC Basic authentication in use
HTTP_AUTH_MD5 Digest authentication in use
HTTP_AUTH_MD5_INT Digest authentication in use for body
HTTP_AUTH_MD5_SESS MD5-session authentication in use
HTTP_AUTH_MD5_SESS_INT MD5-session authentication in use for body
HTTP_AUTH_NONE No authentication in use
+ +

http_encoding_e

+

Description

+

HTTP transfer encoding values

+

Values

+
+ + + + +
NameDescription
HTTP_ENCODE_CHUNKED Data is chunked
HTTP_ENCODE_LENGTH Data is sent with Content-Length
+ +

http_encryption_e

+

Description

+

HTTP encryption values

+

Values

+
+ + + + + + +
NameDescription
HTTP_ENCRYPT_ALWAYS Always encrypt (SSL)
HTTP_ENCRYPT_IF_REQUESTED Encrypt if requested (TLS upgrade)
HTTP_ENCRYPT_NEVER Never encrypt
HTTP_ENCRYPT_REQUIRED Encryption is required (TLS upgrade)
+ +

http_field_e

+

Description

+

HTTP field names

+

Values

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
HTTP_FIELD_ACCEPT_LANGUAGE Accept-Language field
HTTP_FIELD_ACCEPT_RANGES Accept-Ranges field
HTTP_FIELD_AUTHORIZATION Authorization field
HTTP_FIELD_CONNECTION Connection field
HTTP_FIELD_CONTENT_ENCODING Content-Encoding field
HTTP_FIELD_CONTENT_LANGUAGE Content-Language field
HTTP_FIELD_CONTENT_LENGTH Content-Length field
HTTP_FIELD_CONTENT_LOCATION Content-Location field
HTTP_FIELD_CONTENT_MD5 Content-MD5 field
HTTP_FIELD_CONTENT_RANGE Content-Range field
HTTP_FIELD_CONTENT_TYPE Content-Type field
HTTP_FIELD_CONTENT_VERSION Content-Version field
HTTP_FIELD_DATE Date field
HTTP_FIELD_HOST Host field
HTTP_FIELD_IF_MODIFIED_SINCE If-Modified-Since field
HTTP_FIELD_IF_UNMODIFIED_SINCE If-Unmodified-Since field
HTTP_FIELD_KEEP_ALIVE Keep-Alive field
HTTP_FIELD_LAST_MODIFIED Last-Modified field
HTTP_FIELD_LINK Link field
HTTP_FIELD_LOCATION Location field
HTTP_FIELD_MAX Maximum field index
HTTP_FIELD_RANGE Range field
HTTP_FIELD_REFERER Referer field
HTTP_FIELD_RETRY_AFTER Retry-After field
HTTP_FIELD_TRANSFER_ENCODING Transfer-Encoding field
HTTP_FIELD_UNKNOWN Unknown field
HTTP_FIELD_UPGRADE Upgrade field
HTTP_FIELD_USER_AGENT User-Agent field
HTTP_FIELD_WWW_AUTHENTICATE WWW-Authenticate field
+ +

http_keepalive_e

+

Description

+

Types and structures...

+

Values

+
+ + + + +
NameDescription
HTTP_KEEPALIVE_OFF No keep alive support
HTTP_KEEPALIVE_ON Use keep alive
+ +

http_status_e

+

Description

+

HTTP status codes

+

Values

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
HTTP_ACCEPTED DELETE command was successful
HTTP_BAD_GATEWAY Bad gateway
HTTP_BAD_REQUEST Bad request
HTTP_CONFLICT Request is self-conflicting
HTTP_CONTINUE Everything OK, keep going...
HTTP_CREATED PUT command was successful
HTTP_ERROR An error response from httpXxxx()
HTTP_FORBIDDEN Forbidden to access this URI
HTTP_GATEWAY_TIMEOUT Gateway connection timed out
HTTP_GONE Server has gone away
HTTP_LENGTH_REQUIRED A content length or encoding is required
HTTP_METHOD_NOT_ALLOWED Method is not allowed
HTTP_MOVED_PERMANENTLY Document has moved permanently
HTTP_MOVED_TEMPORARILY Document has moved temporarily
HTTP_MULTIPLE_CHOICES Multiple files match request
HTTP_NOT_ACCEPTABLE Not Acceptable
HTTP_NOT_AUTHORITATIVE Information isn't authoritative
HTTP_NOT_FOUND URI was not found
HTTP_NOT_IMPLEMENTED Feature not implemented
HTTP_NOT_MODIFIED File not modified
HTTP_NOT_SUPPORTED HTTP version not supported
HTTP_NO_CONTENT Successful command, no new data
HTTP_OK OPTIONS/GET/HEAD/POST/TRACE command was successful
HTTP_PARTIAL_CONTENT Only a partial file was recieved/sent
HTTP_PAYMENT_REQUIRED Payment required
HTTP_PRECONDITION Precondition failed
HTTP_PROXY_AUTHENTICATION Proxy Authentication is Required
HTTP_REQUEST_TIMEOUT Request timed out
HTTP_REQUEST_TOO_LARGE Request entity too large
HTTP_RESET_CONTENT Content was reset/recreated
HTTP_SEE_OTHER See this other link...
HTTP_SERVER_ERROR Internal server error
HTTP_SERVICE_UNAVAILABLE Service is unavailable
HTTP_SWITCHING_PROTOCOLS HTTP upgrade to TLS/SSL
HTTP_UNAUTHORIZED Unauthorized to access host
HTTP_UNSUPPORTED_MEDIATYPE The requested media type is unsupported
HTTP_UPGRADE_REQUIRED Upgrade to SSL/TLS required
HTTP_URI_TOO_LONG URI too long
HTTP_USE_PROXY Must use a proxy to access this URI
+ +

Functions

+ + +

cupsAddDest()

+

Description

+

Add a destination to the list of destinations. + +Use the cupsSaveDests() function to save the updated list of destinations +to the user's lpoptions file.

+

Syntax

+
+int
+cupsAddDest(
+    const char * name,
+    const char * instance,
+    int num_dests,
+    cups_dest_t ** dests);
+
+

Arguments

+
+ + + + + + +
NameDescription
nameName of destination
instanceInstance of destination or NULL for none/primary
num_destsNumber of destinations
destsDestinations
+

Returns

+

New number of destinations

+ +

cupsAddOption()

+

Description

+

Add an option to an option array.

+

Syntax

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

Arguments

+
+ + + + + + +
NameDescription
nameName of option
valueValue of option
num_optionsNumber of options
optionsPointer to options
+

Returns

+

Number of options

+ +

cupsCancelJob()

+

Description

+

Cancel a print job on the default server. + +Use the cupsLastError() and cupsLastErrorString() functions to get +the cause of any failure.

+

Syntax

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

Arguments

+
+ + + + +
NameDescription
nameName of printer or class
jobJob ID
+

Returns

+

1 on success, 0 on failure

+ +

 CUPS 1.1.20 cupsDoAuthentication()

+

Description

+

Authenticate a request. + +This function should be called in response to a HTTP_UNAUTHORIZED +status, prior to resubmitting your request. + +

+

Syntax

+
+int
+cupsDoAuthentication(
+    http_t * http,
+    const char * method,
+    const char * resource);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
methodRequest method (GET, POST, PUT)
resourceResource path
+

Returns

+

0 on success, -1 on error

+ +

cupsDoFileRequest()

+

Description

+

Do an IPP request. + +This function sends any IPP request to the specified server, retrying +and authenticating as necessary.

+

Syntax

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

Arguments

+
+ + + + + + +
NameDescription
httpHTTP connection to server
requestIPP request
resourceHTTP resource for POST
filenameFile to send or NULL for none
+

Returns

+

Response data

+ +

cupsEncodeOptions()

+

Description

+

Encode printer options into IPP attributes. + +This function adds operation, job, and then subscription attributes, +in that order. Use the cupsEncodeOptions2() function to add attributes +for a single group.

+

Syntax

+
+void
+cupsEncodeOptions(
+    ipp_t * ipp,
+    int num_options,
+    cups_option_t * options);
+
+

Arguments

+
+ + + + + +
NameDescription
ippRequest to add to
num_optionsNumber of options
optionsOptions
+

Returns

+

Nothing.

+ +

 CUPS 1.2 cupsEncodeOptions2()

+

Description

+

Encode printer options into IPP attributes for a group. + +This function only adds attributes for a single group. Call this +function multiple times for each group, or use cupsEncodeOptions() +to add the standard groups. + +

+

Syntax

+
+void
+cupsEncodeOptions2(
+    ipp_t * ipp,
+    int num_options,
+    cups_option_t * options,
+    ipp_tag_t group_tag);
+
+

Arguments

+
+ + + + + + +
NameDescription
ippRequest to add to
num_optionsNumber of options
optionsOptions
group_tagGroup to encode
+

Returns

+

Nothing.

+ +

cupsEncryption()

+

Description

+

Get the default encryption settings. + +The default encryption setting comes from the CUPS_ENCRYPTION +environment variable, then the ~/.cupsrc file, and finally the +/etc/cups/client.conf file. If not set, the default is +HTTP_ENCRYPT_IF_REQUESTED.

+

Syntax

+
+http_encryption_t
+cupsEncryption(void);
+
+

Arguments

+

None.

+

Returns

+

Encryption settings

+ +

cupsFreeDests()

+

Description

+

Free the memory used by the list of destinations.

+

Syntax

+
+void
+cupsFreeDests(
+    int num_dests,
+    cups_dest_t * dests);
+
+

Arguments

+
+ + + + +
NameDescription
num_destsNumber of destinations
destsDestinations
+

Returns

+

Nothing.

+ +

cupsFreeJobs()

+

Description

+

Free memory used by job data.

+

Syntax

+
+void
+cupsFreeJobs(
+    int num_jobs,
+    cups_job_t * jobs);
+
+

Arguments

+
+ + + + +
NameDescription
num_jobsNumber of jobs
jobsJobs
+

Returns

+

Nothing.

+ +

cupsFreeOptions()

+

Description

+

Free all memory used by options.

+

Syntax

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

Arguments

+
+ + + + +
NameDescription
num_optionsNumber of options
optionsPointer to options
+

Returns

+

Nothing.

+ +

 DEPRECATED cupsGetClasses()

+

Description

+

Get a list of printer classes from the default server. + +This function is deprecated - use cupsGetDests() instead. + +

+

Syntax

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

Arguments

+
+ + + +
NameDescription
classesClasses
+

Returns

+

Number of classes

+ +

cupsGetDefault()

+

Description

+

Get the default printer or class for the default server. + +This function returns the default printer or class as defined by +the LPDEST or PRINTER environment variables. If these environment +variables are not set, the server default destination is returned. +Applications should use the cupsGetDests() and cupsGetDest() functions +to get the user-defined default printer, as this function does not +support the lpoptions-defined default printer.

+

Syntax

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

Arguments

+

None.

+

Returns

+

Default printer or NULL

+ +

 CUPS 1.1.21 cupsGetDefault2()

+

Description

+

Get the default printer or class for the specified server. + +This function returns the default printer or class as defined by +the LPDEST or PRINTER environment variables. If these environment +variables are not set, the server default destination is returned. +Applications should use the cupsGetDests() and cupsGetDest() functions +to get the user-defined default printer, as this function does not +support the lpoptions-defined default printer. + +

+

Syntax

+
+const char *
+cupsGetDefault2(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP connection
+

Returns

+

Default printer or NULL

+ +

cupsGetDest()

+

Description

+

Get the named destination from the list. + +Use the cupsGetDests() or cupsGetDests2() functions to get a +list of supported destinations for the current user.

+

Syntax

+
+cups_dest_t *
+cupsGetDest(
+    const char * name,
+    const char * instance,
+    int num_dests,
+    cups_dest_t * dests);
+
+

Arguments

+
+ + + + + + +
NameDescription
nameName of destination
instanceInstance of destination
num_destsNumber of destinations
destsDestinations
+

Returns

+

Destination pointer or NULL

+ +

cupsGetDests()

+

Description

+

Get the list of destinations from the default server.

+

Syntax

+
+int
+cupsGetDests(
+    cups_dest_t ** dests);
+
+

Arguments

+
+ + + +
NameDescription
destsDestinations
+

Returns

+

Number of destinations

+ +

 CUPS 1.1.21 cupsGetDests2()

+

Description

+

Get the list of destinations from the specified server. + +

+

Syntax

+
+int
+cupsGetDests2(
+    http_t * http,
+    cups_dest_t ** dests);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP connection
destsDestinations
+

Returns

+

Number of destinations

+ +

 CUPS 1.1.20 cupsGetFd()

+

Description

+

Get a file from the server. + +This function returns HTTP_OK when the file is successfully retrieved. + +

+

Syntax

+
+http_status_t
+cupsGetFd(
+    http_t * http,
+    const char * resource,
+    int fd);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
resourceResource name
fdFile descriptor
+

Returns

+

Status

+ +

 CUPS 1.1.20 cupsGetFile()

+

Description

+

Get a file from the server. + +This function returns HTTP_OK when the file is successfully retrieved. + +

+

Syntax

+
+http_status_t
+cupsGetFile(
+    http_t * http,
+    const char * resource,
+    const char * filename);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
resourceResource name
filenameFilename
+

Returns

+

Status

+ +

cupsGetJobs()

+

Description

+

Get the jobs from the default server.

+

Syntax

+
+int
+cupsGetJobs(
+    cups_job_t ** jobs,
+    const char * mydest,
+    int myjobs,
+    int completed);
+
+

Arguments

+
+ + + + + + +
NameDescription
jobsJob data
mydestOnly show jobs for dest?
myjobsOnly show my jobs?
completedOnly show completed jobs?
+

Returns

+

Number of jobs

+ +

 CUPS 1.1.21 cupsGetJobs2()

+

Description

+

Get the jobs from the specified server. + +

+

Syntax

+
+int
+cupsGetJobs2(
+    http_t * http,
+    cups_job_t ** jobs,
+    const char * mydest,
+    int myjobs,
+    int completed);
+
+

Arguments

+
+ + + + + + + +
NameDescription
httpHTTP connection
jobsJob data
mydestOnly show jobs for dest?
myjobsOnly show my jobs?
completedOnly show completed jobs?
+

Returns

+

Number of jobs

+ +

cupsGetOption()

+

Description

+

Get an option value.

+

Syntax

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

Arguments

+
+ + + + + +
NameDescription
nameName of option
num_optionsNumber of options
optionsOptions
+

Returns

+

Option value or NULL

+ +

cupsGetPPD()

+

Description

+

Get the PPD file for a printer on the default server. + +For classes, cupsGetPPD() returns the PPD file for the first printer +in the class.

+

Syntax

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

Arguments

+
+ + + +
NameDescription
namePrinter name
+

Returns

+

Filename for PPD file

+ +

 CUPS 1.1.21 cupsGetPPD2()

+

Description

+

Get the PPD file for a printer from the specified server. + +For classes, cupsGetPPD2() returns the PPD file for the first printer +in the class. + +

+

Syntax

+
+const char *
+cupsGetPPD2(
+    http_t * http,
+    const char * name);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP connection
namePrinter name
+

Returns

+

Filename for PPD file

+ +

cupsGetPassword()

+

Description

+

Get a password from the user. + +Returns NULL if the user does not provide a password.

+

Syntax

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

Arguments

+
+ + + +
NameDescription
promptPrompt string
+

Returns

+

Password

+ +

 DEPRECATED cupsGetPrinters()

+

Description

+

Get a list of printers from the default server. + +This function is deprecated - use cupsGetDests() instead. + +

+

Syntax

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

Arguments

+
+ + + +
NameDescription
printersPrinters
+

Returns

+

Number of printers

+ +

cupsLastError()

+

Description

+

Return the last IPP status code.

+

Syntax

+
+ipp_status_t
+cupsLastError(void);
+
+

Arguments

+

None.

+

Returns

+

IPP status code from last request

+ +

 CUPS 1.2 cupsLastErrorString()

+

Description

+

Return the last IPP status-message. + +

+

Syntax

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

Arguments

+

None.

+

Returns

+

status-message text from last request

+ +

cupsMarkOptions()

+

Description

+

Mark command-line options in a PPD file.

+

Syntax

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

Arguments

+
+ + + + + +
NameDescription
ppdPPD file
num_optionsNumber of options
optionsOptions
+

Returns

+

1 if conflicting

+ +

cupsParseOptions()

+

Description

+

Parse options from a command-line argument. + +This function converts space-delimited name/value pairs according +to the PAPI text option ABNF specification. Collection values +("name={a=... b=... c=...}") are stored with the curley brackets +intact - use cupsParseOptions() on the value to extract the collection +attributes.

+

Syntax

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

Arguments

+
+ + + + + +
NameDescription
argArgument to parse
num_optionsNumber of options
optionsOptions found
+

Returns

+

Number of options found

+ +

cupsPrintFile()

+

Description

+

Print a file to a printer or class on the default server.

+

Syntax

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

Arguments

+
+ + + + + + + +
NameDescription
namePrinter or class name
filenameFile to print
titleTitle of job
num_optionsNumber of options
optionsOptions
+

Returns

+

Job ID

+ +

 CUPS 1.1.21 cupsPrintFile2()

+

Description

+

Print a file to a printer or class on the specified server. + +

+

Syntax

+
+int
+cupsPrintFile2(
+    http_t * http,
+    const char * name,
+    const char * filename,
+    const char * title,
+    int num_options,
+    cups_option_t * options);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
httpHTTP connection
namePrinter or class name
filenameFile to print
titleTitle of job
num_optionsNumber of options
optionsOptions
+

Returns

+

Job ID

+ +

cupsPrintFiles()

+

Description

+

Print one or more files to a printer or class on the default server.

+

Syntax

+
+int
+cupsPrintFiles(
+    const char * name,
+    int num_files,
+    const char ** files,
+    const char * title,
+    int num_options,
+    cups_option_t * options);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
namePrinter or class name
num_filesNumber of files
filesFile(s) to print
titleTitle of job
num_optionsNumber of options
optionsOptions
+

Returns

+

Job ID

+ +

 CUPS 1.1.21 cupsPrintFiles2()

+

Description

+

Print one or more files to a printer or class on the specified server. + +

+

Syntax

+
+int
+cupsPrintFiles2(
+    http_t * http,
+    const char * name,
+    int num_files,
+    const char ** files,
+    const char * title,
+    int num_options,
+    cups_option_t * options);
+
+

Arguments

+
+ + + + + + + + + +
NameDescription
httpHTTP connection
namePrinter or class name
num_filesNumber of files
filesFile(s) to print
titleTitle of job
num_optionsNumber of options
optionsOptions
+

Returns

+

Job ID

+ +

 CUPS 1.1.20 cupsPutFd()

+

Description

+

Put a file on the server. + +This function returns HTTP_CREATED when the file is stored successfully. + +

+

Syntax

+
+http_status_t
+cupsPutFd(
+    http_t * http,
+    const char * resource,
+    int fd);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
resourceResource name
fdFile descriptor
+

Returns

+

Status

+ +

 CUPS 1.1.20 cupsPutFile()

+

Description

+

Put a file on the server. + +This function returns HTTP_CREATED when the file is stored successfully. + +

+

Syntax

+
+http_status_t
+cupsPutFile(
+    http_t * http,
+    const char * resource,
+    const char * filename);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection to server
resourceResource name
filenameFilename
+

Returns

+

Status

+ +

cupsServer()

+

Description

+

Return the hostname/address of the default server. + +The returned value can be a fully-qualified hostname, a numeric +IPv4 or IPv6 address, or a domain socket pathname.

+

Syntax

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

Arguments

+

None.

+

Returns

+

Server name

+ +

cupsSetDests()

+

Description

+

Save the list of destinations for the default server. + +This function saves the destinations to /etc/cups/lpoptions when run +as root and ~/.lpoptions when run as a normal user.

+

Syntax

+
+void
+cupsSetDests(
+    int num_dests,
+    cups_dest_t * dests);
+
+

Arguments

+
+ + + + +
NameDescription
num_destsNumber of destinations
destsDestinations
+

Returns

+

Nothing.

+ +

 CUPS 1.1.21 cupsSetDests2()

+

Description

+

Save the list of destinations for the specified server. + +This function saves the destinations to /etc/cups/lpoptions when run +as root and ~/.lpoptions when run as a normal user. + +

+

Syntax

+
+int
+cupsSetDests2(
+    http_t * http,
+    int num_dests,
+    cups_dest_t * dests);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP connection
num_destsNumber of destinations
destsDestinations
+

Returns

+

0 on success, -1 on error

+ +

cupsSetEncryption()

+

Description

+

Set the encryption preference.

+

Syntax

+
+void
+cupsSetEncryption(
+    http_encryption_t e);
+
+

Arguments

+
+ + + +
NameDescription
eNew encryption preference
+

Returns

+

Nothing.

+ +

cupsSetPasswordCB()

+

Description

+

Set the password callback for CUPS. + +Pass NULL to restore the default (console) password callback.

+

Syntax

+
+void
+cupsSetPasswordCB(
+    cups_password_cb_t cb);
+
+

Arguments

+
+ + + +
NameDescription
cbCallback function
+

Returns

+

Nothing.

+ +

cupsSetServer()

+

Description

+

Set the default server name. + +The "server" string can be a fully-qualified hostname, a numeric +IPv4 or IPv6 address, or a domain socket pathname. Pass NULL to +restore the default server name.

+

Syntax

+
+void
+cupsSetServer(
+    const char * server);
+
+

Arguments

+
+ + + +
NameDescription
serverServer name
+

Returns

+

Nothing.

+ +

cupsSetUser()

+

Description

+

Set the default user name. + +Pass NULL to restore the default user name.

+

Syntax

+
+void
+cupsSetUser(
+    const char * user);
+
+

Arguments

+
+ + + +
NameDescription
userUser name
+

Returns

+

Nothing.

+ +

cupsUser()

+

Description

+

Return the current user's name.

+

Syntax

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

Arguments

+

None.

+

Returns

+

User name

+ +

 CUPS 1.2 httpAddrAny()

+

Description

+

Check for the "any" address. + +

+

Syntax

+
+int
+httpAddrAny(
+    const http_addr_t * addr);
+
+

Arguments

+
+ + + +
NameDescription
addrAddress to check
+

Returns

+

1 if "any", 0 otherwise

+ +

 CUPS 1.2 httpAddrEqual()

+

Description

+

Compare two addresses. + +

+

Syntax

+
+int
+httpAddrEqual(
+    const http_addr_t * addr1,
+    const http_addr_t * addr2);
+
+

Arguments

+
+ + + + +
NameDescription
addr1First address
addr2Second address
+

Returns

+

1 if equal, 0 if !=

+ +

 CUPS 1.2 httpAddrLength()

+

Description

+

Return the length of the address in bytes. + +

+

Syntax

+
+int
+httpAddrLength(
+    const http_addr_t * addr);
+
+

Arguments

+
+ + + +
NameDescription
addrAddress
+

Returns

+

Length in bytes

+ +

 CUPS 1.2 httpAddrLocalhost()

+

Description

+

Check for the local loopback address. + +

+

Syntax

+
+int
+httpAddrLocalhost(
+    const http_addr_t * addr);
+
+

Arguments

+
+ + + +
NameDescription
addrAddress to check
+

Returns

+

1 if local host, 0 otherwise

+ +

 CUPS 1.2 httpAddrLookup()

+

Description

+

Lookup the hostname associated with the address. + +

+

Syntax

+
+char *
+httpAddrLookup(
+    const http_addr_t * addr,
+    char * name,
+    int namelen);
+
+

Arguments

+
+ + + + + +
NameDescription
addrAddress to lookup
nameHost name buffer
namelenSize of name buffer
+

Returns

+

Host name

+ +

 CUPS 1.2 httpAddrString()

+

Description

+

Convert an IP address to a dotted string. + +

+

Syntax

+
+char *
+httpAddrString(
+    const http_addr_t * addr,
+    char * s,
+    int slen);
+
+

Arguments

+
+ + + + + +
NameDescription
addrAddress to convert
sString buffer
slenLength of string
+

Returns

+

IP string

+ +

 CUPS 1.2 httpAssembleURI()

+

Description

+

Assemble a uniform resource identifier from its +components. + +This function properly escapes all reserved characters in a URI. You +should use this function in place of traditional string functions +whenever you need to create a URI string. + +

+

Syntax

+
+http_uri_status_t
+httpAssembleURI(
+    char * uri,
+    int urilen,
+    const char * scheme,
+    const char * username,
+    const char * host,
+    int port,
+    const char * resource);
+
+

Arguments

+
+ + + + + + + + + +
NameDescription
uriURI buffer
urilenSize of URI buffer
schemeScheme name
usernameUsername
hostHostname or address
portPort number
resourceResource
+

Returns

+

URI status

+ +

 CUPS 1.2 httpAssembleURIf()

+

Description

+

Assemble a uniform resource identifier from its +components with a formatted resource. + +This function creates a formatted version of the resource string +argument "resourcef" and properly escapes all reserved characters +in a URI. You should use this function in place of traditional +string functions whenever you need to create a URI string. + +

+

Syntax

+
+http_uri_status_t
+httpAssembleURIf(
+    char * uri,
+    int urilen,
+    const char * scheme,
+    const char * username,
+    const char * host,
+    int port,
+    const char * resourcef,
+    ...);
+
+

Arguments

+
+ + + + + + + + + + +
NameDescription
uriURI buffer
urilenSize of URI buffer
schemeScheme name
usernameUsername
hostHostname or address
portPort number
resourcefPrintf-style resource
...Additional arguments as needed
+

Returns

+

URI status

+ +

httpCheck()

+

Description

+

Check to see if there is a pending response from the server.

+

Syntax

+
+int
+httpCheck(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP connection
+

Returns

+

0 = no data, 1 = data available

+ +

 CUPS 1.1.19 httpClearCookie()

+

Description

+

Clear the cookie value(s). + +

+

Syntax

+
+void
+httpClearCookie(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpConnection
+

Returns

+

Nothing.

+ +

httpClose()

+

Description

+

Close an HTTP connection...

+

Syntax

+
+void
+httpClose(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpConnection to close
+

Returns

+

Nothing.

+ +

httpConnect()

+

Description

+

Connect to a HTTP server.

+

Syntax

+
+http_t *
+httpConnect(
+    const char * host,
+    int port);
+
+

Arguments

+
+ + + + +
NameDescription
hostHost to connect to
portPort number
+

Returns

+

New HTTP connection

+ +

httpConnectEncrypt()

+

Description

+

Connect to a HTTP server using encryption.

+

Syntax

+
+http_t *
+httpConnectEncrypt(
+    const char * host,
+    int port,
+    http_encryption_t encryption);
+
+

Arguments

+
+ + + + + +
NameDescription
hostHost to connect to
portPort number
encryptionType of encryption to use
+

Returns

+

New HTTP connection

+ +

httpDecode64()

+

Description

+

Base64-decode a string.

+

Syntax

+
+char *
+httpDecode64(
+    char * out,
+    const char * in);
+
+

Arguments

+
+ + + + +
NameDescription
outString to write to
inString to read from
+

Returns

+

Decoded string

+ +

 CUPS 1.1.21 httpDecode64_2()

+

Description

+

Base64-decode a string. + +

+

Syntax

+
+char *
+httpDecode64_2(
+    char * out,
+    int * outlen,
+    const char * in);
+
+

Arguments

+
+ + + + + +
NameDescription
outString to write to
outlenSize of output string
inString to read from
+

Returns

+

Decoded string

+ +

httpDelete()

+

Description

+

Send a DELETE request to the server.

+

Syntax

+
+int
+httpDelete(
+    http_t * http,
+    const char * uri);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
uriURI to delete
+

Returns

+

Status of call (0 = success)

+ +

httpEncode64()

+

Description

+

Base64-encode a string.

+

Syntax

+
+char *
+httpEncode64(
+    char * out,
+    const char * in);
+
+

Arguments

+
+ + + + +
NameDescription
outString to write to
inString to read from
+

Returns

+

Encoded string

+ +

 CUPS 1.1.21 httpEncode64_2()

+

Description

+

Base64-encode a string. + +

+

Syntax

+
+char *
+httpEncode64_2(
+    char * out,
+    int outlen,
+    const char * in,
+    int inlen);
+
+

Arguments

+
+ + + + + + +
NameDescription
outString to write to
outlenSize of output string
inString to read from
inlenSize of input string
+

Returns

+

Encoded string

+ +

httpEncryption()

+

Description

+

Set the required encryption on the link.

+

Syntax

+
+int
+httpEncryption(
+    http_t * http,
+    http_encryption_t e);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
eNew encryption preference
+

Returns

+

-1 on error, 0 on success

+ +

httpFlush()

+

Description

+

Flush data from a HTTP connection.

+

Syntax

+
+void
+httpFlush(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP data
+

Returns

+

Nothing.

+ +

 CUPS 1.2 httpFlushWrite()

+

Description

+

Flush data in write buffer. + +

+

Syntax

+
+int
+httpFlushWrite(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP data
+

Returns

+

Bytes written or -1 on error

+ +

httpGet()

+

Description

+

Send a GET request to the server.

+

Syntax

+
+int
+httpGet(
+    http_t * http,
+    const char * uri);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
uriURI to get
+

Returns

+

Status of call (0 = success)

+ +

 DEPRECATED httpGetDateString()

+

Description

+

Get a formatted date/time string from a time value. + +

+

Syntax

+
+const char *
+httpGetDateString(
+    time_t t);
+
+

Arguments

+
+ + + +
NameDescription
tUNIX time
+

Returns

+

Date/time string

+ +

 CUPS 1.2 httpGetDateString2()

+

Description

+

Get a formatted date/time string from a time value. + +

+

Syntax

+
+const char *
+httpGetDateString2(
+    time_t t,
+    char * s,
+    int slen);
+
+

Arguments

+
+ + + + + +
NameDescription
tUNIX time
sString buffer
slenSize of string buffer
+

Returns

+

Date/time string

+ +

httpGetDateTime()

+

Description

+

Get a time value from a formatted date/time string.

+

Syntax

+
+time_t
+httpGetDateTime(
+    const char * s);
+
+

Arguments

+
+ + + +
NameDescription
sDate/time string
+

Returns

+

UNIX time

+ +

 DEPRECATED httpGetHostByName()

+

Description

+

Lookup a hostname or IPv4 address, and return +address records for the specified name. + +

+

Syntax

+
+struct hostent *
+httpGetHostByName(
+    const char * name);
+
+

Arguments

+
+ + + +
NameDescription
nameHostname or IP address
+

Returns

+

Host entry

+ +

 CUPS 1.2 httpGetHostname()

+

Description

+

Get the FQDN for the local system. + +This function uses both gethostname() and gethostbyname() to +get the local hostname with domain. + +

+

Syntax

+
+const char *
+httpGetHostname(
+    char * s,
+    int slen);
+
+

Arguments

+
+ + + + +
NameDescription
sString buffer for name
slenSize of buffer
+

Returns

+

FQDN for this system

+ +

 CUPS 1.2 httpGetLength()

+

Description

+

Get the amount of data remaining from the +content-length or transfer-encoding fields. + +This function is deprecated and will not return lengths larger than +2^31 - 1; use httpGetLength2() instead. + +

+

Syntax

+
+int
+httpGetLength(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP data
+

Returns

+

Content length

+ +

httpGetLength2()

+

Description

+

Get the amount of data remaining from the +content-length or transfer-encoding fields. + +This function returns the complete content length, even for +content larger than 2^31 - 1.

+

Syntax

+
+off_t
+httpGetLength2(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP data
+

Returns

+

Content length

+ +

 DEPRECATED httpGetSubField()

+

Description

+

Get a sub-field value. + +

+

Syntax

+
+char *
+httpGetSubField(
+    http_t * http,
+    http_field_t field,
+    const char * name,
+    char * value);
+
+

Arguments

+
+ + + + + + +
NameDescription
httpHTTP data
fieldField index
nameName of sub-field
valueValue string
+

Returns

+

Value or NULL

+ +

 CUPS 1.2 httpGetSubField2()

+

Description

+

Get a sub-field value. + +

+

Syntax

+
+char *
+httpGetSubField2(
+    http_t * http,
+    http_field_t field,
+    const char * name,
+    char * value,
+    int valuelen);
+
+

Arguments

+
+ + + + + + + +
NameDescription
httpHTTP data
fieldField index
nameName of sub-field
valueValue string
valuelenSize of value buffer
+

Returns

+

Value or NULL

+ +

httpGets()

+

Description

+

Get a line of text from a HTTP connection.

+

Syntax

+
+char *
+httpGets(
+    char * line,
+    int length,
+    http_t * http);
+
+

Arguments

+
+ + + + + +
NameDescription
lineLine to read into
lengthMax length of buffer
httpHTTP data
+

Returns

+

Line or NULL

+ +

httpHead()

+

Description

+

Send a HEAD request to the server.

+

Syntax

+
+int
+httpHead(
+    http_t * http,
+    const char * uri);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
uriURI for head
+

Returns

+

Status of call (0 = success)

+ +

httpInitialize()

+

Description

+

Initialize the HTTP interface library and set the +default HTTP proxy (if any).

+

Syntax

+
+void
+httpInitialize(void);
+
+

Arguments

+

None.

+

Returns

+

Nothing.

+ +

httpMD5()

+

Description

+

Compute the MD5 sum of the username:group:password.

+

Syntax

+
+char *
+httpMD5(
+    const char * username,
+    const char * realm,
+    const char * passwd,
+    char md5[33]);
+
+

Arguments

+
+ + + + + + +
NameDescription
usernameUser name
realmRealm name
passwdPassword string
md5[33]MD5 string
+

Returns

+

MD5 sum

+ +

httpMD5Final()

+

Description

+

Combine the MD5 sum of the username, group, and password +with the server-supplied nonce value, method, and +request-uri.

+

Syntax

+
+char *
+httpMD5Final(
+    const char * nonce,
+    const char * method,
+    const char * resource,
+    char md5[33]);
+
+

Arguments

+
+ + + + + + +
NameDescription
nonceServer nonce value
methodMETHOD (GET, POST, etc.)
resourceResource path
md5[33]MD5 sum
+

Returns

+

New sum

+ +

httpMD5String()

+

Description

+

Convert an MD5 sum to a character string.

+

Syntax

+
+char *
+httpMD5String(
+    const unsigned char * sum,
+    char md5[33]);
+
+

Arguments

+
+ + + + +
NameDescription
sumMD5 sum data
md5[33]MD5 sum in hex
+

Returns

+

MD5 sum in hex

+ +

httpOptions()

+

Description

+

Send an OPTIONS request to the server.

+

Syntax

+
+int
+httpOptions(
+    http_t * http,
+    const char * uri);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
uriURI for options
+

Returns

+

Status of call (0 = success)

+ +

httpPost()

+

Description

+

Send a POST request to the server.

+

Syntax

+
+int
+httpPost(
+    http_t * http,
+    const char * uri);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
uriURI for post
+

Returns

+

Status of call (0 = success)

+ +

httpPrintf()

+

Description

+

Print a formatted string to a HTTP connection.

+

Syntax

+
+int
+httpPrintf(
+    http_t * http,
+    const char * format,
+    ...);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP data
formatprintf-style format string
...Additional args as needed
+

Returns

+

Number of bytes written

+ +

httpPut()

+

Description

+

Send a PUT request to the server.

+

Syntax

+
+int
+httpPut(
+    http_t * http,
+    const char * uri);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
uriURI to put
+

Returns

+

Status of call (0 = success)

+ +

httpRead()

+

Description

+

Read data from a HTTP connection.

+

Syntax

+
+int
+httpRead(
+    http_t * http,
+    char * buffer,
+    int length);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP data
bufferBuffer for data
lengthMaximum number of bytes
+

Returns

+

Number of bytes read

+ +

httpReconnect()

+

Description

+

Reconnect to a HTTP server...

+

Syntax

+
+int
+httpReconnect(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP data
+

Returns

+

0 on success, non-zero on failure

+ +

httpSeparate()

+

Description

+

Separate a Universal Resource Identifier into its +components.

+

Syntax

+
+void
+httpSeparate(
+    const char * uri,
+    char * scheme,
+    char * username,
+    char * host,
+    int * port,
+    char * resource);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
uriUniversal Resource Identifier
schemeScheme [32] (http, https, etc.)
usernameUsername [1024]
hostHostname [1024]
portPort number to use
resourceResource/filename [1024]
+

Returns

+

Nothing.

+ +

 CUPS 1.1.21 httpSeparate2()

+

Description

+

Separate a Universal Resource Identifier into its +components. + +

+

Syntax

+
+void
+httpSeparate2(
+    const char * uri,
+    char * scheme,
+    int schemelen,
+    char * username,
+    int usernamelen,
+    char * host,
+    int hostlen,
+    int * port,
+    char * resource,
+    int resourcelen);
+
+

Arguments

+
+ + + + + + + + + + + + +
NameDescription
uriUniversal Resource Identifier
schemeScheme (http, https, etc.)
schemelenSize of scheme buffer
usernameUsername
usernamelenSize of username buffer
hostHostname
hostlenSize of hostname buffer
portPort number to use
resourceResource/filename
resourcelenSize of resource buffer
+

Returns

+

Nothing.

+ +

 CUPS 1.2 httpSeparateURI()

+

Description

+

Separate a Universal Resource Identifier into its +components. + +

+

Syntax

+
+http_uri_status_t
+httpSeparateURI(
+    const char * uri,
+    char * scheme,
+    int schemelen,
+    char * username,
+    int usernamelen,
+    char * host,
+    int hostlen,
+    int * port,
+    char * resource,
+    int resourcelen);
+
+

Arguments

+
+ + + + + + + + + + + + +
NameDescription
uriUniversal Resource Identifier
schemeScheme (http, https, etc.)
schemelenSize of scheme buffer
usernameUsername
usernamelenSize of username buffer
hostHostname
hostlenSize of hostname buffer
portPort number to use
resourceResource/filename
resourcelenSize of resource buffer
+

Returns

+

Result of separation

+ +

 CUPS 1.1.19 httpSetCookie()

+

Description

+

Set the cookie value(s)... + +

+

Syntax

+
+void
+httpSetCookie(
+    http_t * http,
+    const char * cookie);
+
+

Arguments

+
+ + + + +
NameDescription
httpConnection
cookieCookie string
+

Returns

+

Nothing.

+ +

httpSetField()

+

Description

+

Set the value of an HTTP header.

+

Syntax

+
+void
+httpSetField(
+    http_t * http,
+    http_field_t field,
+    const char * value);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP data
fieldField index
valueValue
+

Returns

+

Nothing.

+ +

 CUPS 1.2 httpSetLength()

+

Description

+

Set the content-length and content-encoding. + +

+

Syntax

+
+void
+httpSetLength(
+    http_t * http,
+    size_t length);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
lengthLength (0 for chunked)
+

Returns

+

Nothing.

+ +

httpStatus()

+

Description

+

Return a short string describing a HTTP status code.

+

Syntax

+
+const char *
+httpStatus(
+    http_status_t status);
+
+

Arguments

+
+ + + +
NameDescription
statusHTTP status code
+

Returns

+

String or NULL

+ +

httpTrace()

+

Description

+

Send an TRACE request to the server.

+

Syntax

+
+int
+httpTrace(
+    http_t * http,
+    const char * uri);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
uriURI for trace
+

Returns

+

Status of call (0 = success)

+ +

httpUpdate()

+

Description

+

Update the current HTTP state for incoming data.

+

Syntax

+
+http_status_t
+httpUpdate(
+    http_t * http);
+
+

Arguments

+
+ + + +
NameDescription
httpHTTP data
+

Returns

+

HTTP status

+ +

 CUPS 1.1.19 httpWait()

+

Description

+

Wait for data available on a connection. + +

+

Syntax

+
+int
+httpWait(
+    http_t * http,
+    int msec);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP data
msecMilliseconds to wait
+

Returns

+

1 if data is available, 0 otherwise

+ +

httpWrite()

+

Description

+

Write data to a HTTP connection.

+

Syntax

+
+int
+httpWrite(
+    http_t * http,
+    const char * buffer,
+    int length);
+
+

Arguments

+
+ + + + + +
NameDescription
httpHTTP data
bufferBuffer for data
lengthNumber of bytes to write
+

Returns

+

Number of bytes written

+ +

ippAddBoolean()

+

Description

+

Add a boolean attribute to an IPP request.

+

Syntax

+
+ipp_attribute_t *
+ippAddBoolean(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    char value);
+
+

Arguments

+
+ + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
valueValue of attribute
+

Returns

+

New attribute

+ +

ippAddBooleans()

+

Description

+

Add an array of boolean values.

+

Syntax

+
+ipp_attribute_t *
+ippAddBooleans(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    int num_values,
+    const char * values);
+
+

Arguments

+
+ + + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
num_valuesNumber of values
valuesValues
+

Returns

+

New attribute

+ +

 CUPS 1.1.19 ippAddCollection()

+

Description

+

Add a collection value. + +

+

Syntax

+
+ipp_attribute_t *
+ippAddCollection(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    ipp_t * value);
+
+

Arguments

+
+ + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
valueValue
+

Returns

+

New attribute

+ +

 CUPS 1.1.19 ippAddCollections()

+

Description

+

Add an array of collection values. + +

+

Syntax

+
+ipp_attribute_t *
+ippAddCollections(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    int num_values,
+    const ipp_t ** values);
+
+

Arguments

+
+ + + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
num_valuesNumber of values
valuesValues
+

Returns

+

New attribute

+ +

ippAddDate()

+

Description

+

Add a date attribute to an IPP request.

+

Syntax

+
+ipp_attribute_t *
+ippAddDate(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    const ipp_uchar_t * value);
+
+

Arguments

+
+ + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
valueValue
+

Returns

+

New attribute

+ +

ippAddInteger()

+

Description

+

Add a integer attribute to an IPP request.

+

Syntax

+
+ipp_attribute_t *
+ippAddInteger(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    ipp_tag_t type,
+    const char * name,
+    int value);
+
+

Arguments

+
+ + + + + + + +
NameDescription
ippIPP request
groupIPP group
typeType of attribute
nameName of attribute
valueValue of attribute
+

Returns

+

New attribute

+ +

ippAddIntegers()

+

Description

+

Add an array of integer values.

+

Syntax

+
+ipp_attribute_t *
+ippAddIntegers(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    ipp_tag_t type,
+    const char * name,
+    int num_values,
+    const int * values);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
ippIPP request
groupIPP group
typeType of attribute
nameName of attribute
num_valuesNumber of values
valuesValues
+

Returns

+

New attribute

+ +

 CUPS 1.2 ippAddOctetString()

+

Description

+

Add an octetString value to an IPP request. + +

+

Syntax

+
+ipp_attribute_t *
+ippAddOctetString(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    const void * data,
+    int datalen);
+
+

Arguments

+
+ + + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
dataoctetString data
datalenLength of data in bytes
+

Returns

+

New attribute

+ +

ippAddRange()

+

Description

+

Add a range of values to an IPP request.

+

Syntax

+
+ipp_attribute_t *
+ippAddRange(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    int lower,
+    int upper);
+
+

Arguments

+
+ + + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
lowerLower value
upperUpper value
+

Returns

+

New attribute

+ +

ippAddRanges()

+

Description

+

Add ranges of values to an IPP request.

+

Syntax

+
+ipp_attribute_t *
+ippAddRanges(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    int num_values,
+    const int * lower,
+    const int * upper);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
num_valuesNumber of values
lowerLower values
upperUpper values
+

Returns

+

New attribute

+ +

ippAddResolution()

+

Description

+

Add a resolution value to an IPP request.

+

Syntax

+
+ipp_attribute_t *
+ippAddResolution(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    const char * name,
+    ipp_res_t units,
+    int xres,
+    int yres);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
unitsUnits for resolution
xresX resolution
yresY resolution
+

Returns

+

New attribute

+ +

ippAddResolutions()

+

Description

+

Add resolution values to an IPP request.

+

Syntax

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

Arguments

+
+ + + + + + + + + +
NameDescription
ippIPP request
groupIPP group
nameName of attribute
num_valuesNumber of values
unitsUnits for resolution
xresX resolutions
yresY resolutions
+

Returns

+

New attribute

+ +

ippAddSeparator()

+

Description

+

Add a group separator to an IPP request.

+

Syntax

+
+ipp_attribute_t *
+ippAddSeparator(
+    ipp_t * ipp);
+
+

Arguments

+
+ + + +
NameDescription
ippIPP request
+

Returns

+

New attribute

+ +

ippAddString()

+

Description

+

Add a language-encoded string to an IPP request.

+

Syntax

+
+ipp_attribute_t *
+ippAddString(
+    ipp_t * ipp,
+    ipp_tag_t group,
+    ipp_tag_t type,
+    const char * name,
+    const char * charset,
+    const char * value);
+
+

Arguments

+
+ + + + + + + + +
NameDescription
ippIPP request
groupIPP group
typeType of attribute
nameName of attribute
charsetCharacter set
valueValue
+

Returns

+

New attribute

+ +

ippAddStrings()

+

Description

+

Add language-encoded strings to an IPP request.

+

Syntax

+
+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 *const * values);
+
+

Arguments

+
+ + + + + + + + + +
NameDescription
ippIPP request
groupIPP group
typeType of attribute
nameName of attribute
num_valuesNumber of values
charsetCharacter set
valuesValues
+

Returns

+

New attribute

+ +

ippDateToTime()

+

Description

+

Convert from RFC 1903 Date/Time format to UNIX time +in seconds.

+

Syntax

+
+time_t
+ippDateToTime(
+    const ipp_uchar_t * date);
+
+

Arguments

+
+ + + +
NameDescription
dateRFC 1903 date info
+

Returns

+

UNIX time value

+ +

ippDelete()

+

Description

+

Delete an IPP request.

+

Syntax

+
+void
+ippDelete(
+    ipp_t * ipp);
+
+

Arguments

+
+ + + +
NameDescription
ippIPP request
+

Returns

+

Nothing.

+ +

 CUPS 1.1.19 ippDeleteAttribute()

+

Description

+

Delete a single attribute in an IPP request. + +

+

Syntax

+
+void
+ippDeleteAttribute(
+    ipp_t * ipp,
+    ipp_attribute_t * attr);
+
+

Arguments

+
+ + + + +
NameDescription
ippIPP request
attrAttribute to delete
+

Returns

+

Nothing.

+ +

ippErrorString()

+

Description

+

Return a name for the given status code.

+

Syntax

+
+const char *
+ippErrorString(
+    ipp_status_t error);
+
+

Arguments

+
+ + + +
NameDescription
errorError status
+

Returns

+

Text string

+ +

 CUPS 1.2 ippErrorValue()

+

Description

+

Return a status code for the given name. + +

+

Syntax

+
+ipp_status_t
+ippErrorValue(
+    const char * name);
+
+

Arguments

+
+ + + +
NameDescription
nameName
+

Returns

+

IPP status code

+ +

ippFindAttribute()

+

Description

+

Find a named attribute in a request...

+

Syntax

+
+ipp_attribute_t *
+ippFindAttribute(
+    ipp_t * ipp,
+    const char * name,
+    ipp_tag_t type);
+
+

Arguments

+
+ + + + + +
NameDescription
ippIPP request
nameName of attribute
typeType of attribute
+

Returns

+

Matching attribute

+ +

ippFindNextAttribute()

+

Description

+

Find the next named attribute in a request...

+

Syntax

+
+ipp_attribute_t *
+ippFindNextAttribute(
+    ipp_t * ipp,
+    const char * name,
+    ipp_tag_t type);
+
+

Arguments

+
+ + + + + +
NameDescription
ippIPP request
nameName of attribute
typeType of attribute
+

Returns

+

Matching attribute

+ +

ippLength()

+

Description

+

Compute the length of an IPP request.

+

Syntax

+
+size_t
+ippLength(
+    ipp_t * ipp);
+
+

Arguments

+
+ + + +
NameDescription
ippIPP request
+

Returns

+

Size of IPP request

+ +

ippNew()

+

Description

+

Allocate a new IPP request.

+

Syntax

+
+ipp_t *
+ippNew(void);
+
+

Arguments

+

None.

+

Returns

+

New IPP request

+ +

 CUPS 1.2 ippOpString()

+

Description

+

Return a name for the given operation id. + +

+

Syntax

+
+const char *
+ippOpString(
+    ipp_op_t op);
+
+

Arguments

+
+ + + +
NameDescription
opOperation ID
+

Returns

+

Name

+ +

 CUPS 1.2 ippOpValue()

+

Description

+

Return an operation id for the given name. + +

+

Syntax

+
+ipp_op_t
+ippOpValue(
+    const char * name);
+
+

Arguments

+
+ + + +
NameDescription
nameTextual name
+

Returns

+

Operation ID

+ +

ippPort()

+

Description

+

Return the default IPP port number.

+

Syntax

+
+int
+ippPort(void);
+
+

Arguments

+

None.

+

Returns

+

Port number

+ +

ippRead()

+

Description

+

Read data for an IPP request from a HTTP connection.

+

Syntax

+
+ipp_state_t
+ippRead(
+    http_t * http,
+    ipp_t * ipp);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP connection
ippIPP data
+

Returns

+

Current state

+ +

 CUPS 1.1.19 ippReadFile()

+

Description

+

Read data for an IPP request from a file. + +

+

Syntax

+
+ipp_state_t
+ippReadFile(
+    int fd,
+    ipp_t * ipp);
+
+

Arguments

+
+ + + + +
NameDescription
fdHTTP data
ippIPP data
+

Returns

+

Current state

+ +

 CUPS 1.1.19 ippReadIO()

+

Description

+

Read data for an IPP request. + +

+

Syntax

+
+ipp_state_t
+ippReadIO(
+    void * src,
+    ipp_iocb_t cb,
+    int blocking,
+    ipp_t * parent,
+    ipp_t * ipp);
+
+

Arguments

+
+ + + + + + + +
NameDescription
srcData source
cbRead callback function
blockingUse blocking IO?
parentParent request, if any
ippIPP data
+

Returns

+

Current state

+ +

ippSetPort()

+

Description

+

Set the default port number.

+

Syntax

+
+void
+ippSetPort(
+    int p);
+
+

Arguments

+
+ + + +
NameDescription
pPort number to use
+

Returns

+

Nothing.

+ +

ippTimeToDate()

+

Description

+

Convert from UNIX time to RFC 1903 format.

+

Syntax

+
+const ipp_uchar_t *
+ippTimeToDate(
+    time_t t);
+
+

Arguments

+
+ + + +
NameDescription
tUNIX time value
+

Returns

+

RFC-1903 date/time data

+ +

ippWrite()

+

Description

+

Write data for an IPP request to a HTTP connection.

+

Syntax

+
+ipp_state_t
+ippWrite(
+    http_t * http,
+    ipp_t * ipp);
+
+

Arguments

+
+ + + + +
NameDescription
httpHTTP connection
ippIPP data
+

Returns

+

Current state

+ +

 CUPS 1.1.19 ippWriteFile()

+

Description

+

Write data for an IPP request to a file. + +

+

Syntax

+
+ipp_state_t
+ippWriteFile(
+    int fd,
+    ipp_t * ipp);
+
+

Arguments

+
+ + + + +
NameDescription
fdHTTP data
ippIPP data
+

Returns

+

Current state

+ +

 CUPS 1.1.19 ippWriteIO()

+

Description

+

Write data for an IPP request. + +

+

Syntax

+
+ipp_state_t
+ippWriteIO(
+    void * dst,
+    ipp_iocb_t cb,
+    int blocking,
+    ipp_t * parent,
+    ipp_t * ipp);
+
+

Arguments

+
+ + + + + + + +
NameDescription
dstDestination
cbWrite callback function
blockingUse blocking IO?
parentParent IPP request
ippIPP data
+

Returns

+

Current state

+ +

Structures

+ + +

cups_dest_s

+

Description

+

Destination

+

Definition

+
+struct cups_dest_s
+{
+  char *name, * instance;
+  int is_default;
+  int num_options;
+  cups_option_t * options;
+};
+
+

Members

+
+ + + + + + +
NameDescription
instance Local instance name or NULL
is_default Is this printer the default?
num_options Number of options
options Options
+ +

cups_job_s

+

Description

+

Job

+

Definition

+
+struct cups_job_s
+{
+  char *dest, *title, *user, * format;
+  int id;
+  int size, priority;
+  time_t completed_time, creation_time, processing_time;
+  ipp_jstate_t state;
+};
+
+

Members

+
+ + + + + + + +
NameDescription
format Document format
id The job ID
priority Priority (1-100)
processing_time Time the job was processed
state Job state
+ +

cups_option_s

+

Description

+

Types and structures...

+

Definition

+
+struct cups_option_s
+{
+  char * name;
+  char * value;
+};
+
+

Members

+
+ + + + +
NameDescription
name Name of option
value Value of option
+ +

 CUPS 1.2 http_addrlist_s

+

Description

+

Socket address list, which is +used to enumerate all of the +addresses that are associated +with a hostname.

+

Definition

+
+struct http_addrlist_s
+{
+  http_addr_t addr;
+  struct http_addrlist_s * next;
+};
+
+

Members

+
+ + + + +
NameDescription
addr Address
next Pointer to next address in list
+ +

http_s

+

Description

+

HTTP connection structure.

+

Definition

+
+struct http_s
+{
+  time_t activity;
+  http_addrlist_t * addrlist;
+  int auth_type;
+  int blocking;
+  char buffer[HTTP_MAX_BUFFER];
+  char * cookie;
+  char * data;
+  http_encoding_t data_encoding;
+  off_t data_remaining;
+  int digest_tries;
+  http_encryption_t encryption;
+  int error;
+  http_status_t expect;
+  int fd;
+  char hostname[HTTP_MAX_HOST], fields[HTTP_FIELD_MAX][HTTP_MAX_VALUE];
+  http_addr_t * hostaddr;
+  fd_set * input_set;
+  http_keepalive_t keep_alive;
+  _cups_md5_state_t md5_state;
+  char nonce[HTTP_MAX_VALUE];
+  int nonce_count;
+  http_state_t state;
+  http_status_t status;
+  void * tls;
+  int used;
+  char authstring[HTTP_MAX_VALUE], userpass[HTTP_MAX_VALUE];
+  http_version_t version;
+  char wbuffer[HTTP_MAX_BUFFER];
+  int wused;
+};
+
+

Members

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
activity Time since last read/write
addrlist  CUPS 1.2 List of valid addresses
auth_type Authentication in use
blocking To block or not to block
buffer[HTTP_MAX_BUFFER] Buffer for incoming data
cookie  CUPS 1.1.19 Cookie value(s)
data Pointer to data buffer
data_encoding Chunked or not
data_remaining  CUPS 1.2 Number of bytes left
digest_tries  CUPS 1.1.20 Number of tries for digest auth
encryption Encryption requirements
error Last error on read
expect  CUPS 1.1.19 Expect: header
fd File descriptor for this socket
fields[HTTP_FIELD_MAX][HTTP_MAX_VALUE] Field values
hostaddr  CUPS 1.2 Current host address and port
input_set  CUPS 1.1.19 select() set for httpWait()
keep_alive Keep-alive supported?
md5_state MD5 state
nonce[HTTP_MAX_VALUE] Nonce value
nonce_count Nonce count
state State of client
status Status of last request
tls TLS state information
used Number of bytes used in buffer
userpass[HTTP_MAX_VALUE]  CUPS 1.1.20 Username:password string
version Protocol version
wbuffer[HTTP_MAX_BUFFER] Buffer for outgoing data
wused  CUPS 1.2 Write buffer bytes used
+ +

ipp_attribute_s

+

Description

+

Attribute

+

Definition

+
+struct ipp_attribute_s
+{
+  char * name;
+  struct ipp_attribute_s * next;
+  int num_values;
+  ipp_tag_t group_tag, value_tag;
+  ipp_value_t values[1];
+};
+
+

Members

+
+ + + + + + + +
NameDescription
name Name of attribute
next Next attribute in list
num_values Number of values
value_tag What type of value is it?
values[1] Values
+ +

ipp_str

+

Description

+

IPP Request/Response/Notification

+

Definition

+
+struct ipp_str
+{
+  ipp_attribute_t *attrs, *last, * current;
+  ipp_tag_t curtag;
+  ipp_attribute_t * prev;
+  ipp_request_t request;
+  ipp_state_t state;
+};
+
+

Members

+
+ + + + + + + +
NameDescription
current Current attribute (for read/write)
curtag Current attribute group tag
prev Previous attribute (for read)
request Request header
state State of request
+ +

Types

+ + +

char

+

Description

+

Printer Options

+

Definition

+
+typedef const * (*charcups_password_cb_t)(const char *);
+
+ +

cups_dest_t

+

Description

+

Destination

+

Definition

+
+typedef struct cups_dest_s cups_dest_t;
+
+ +

cups_job_t

+

Description

+

Job

+

Definition

+
+typedef struct cups_job_s cups_job_t;
+
+ +

cups_option_t

+

Description

+

Types and structures...

+

Definition

+
+typedef struct cups_option_s cups_option_t;
+
+ +

cups_ptype_t

+

Description

+

Printer Type/Capability Bits

+

Definition

+
+typedef unsigned cups_ptype_t;
+
+ +

 CUPS 1.2 http_addrlist_t

+

Description

+

Socket address list, which is +used to enumerate all of the +addresses that are associated +with a hostname.

+

Definition

+
+typedef struct http_addrlist_s / http_addrlist_t;
+
+ +

http_auth_t

+

Description

+

HTTP authentication types

+

Definition

+
+typedef enum http_auth_e http_auth_t;
+
+ +

http_encoding_t

+

Description

+

HTTP transfer encoding values

+

Definition

+
+typedef enum http_encoding_e http_encoding_t;
+
+ +

http_encryption_t

+

Description

+

HTTP encryption values

+

Definition

+
+typedef enum http_encryption_e http_encryption_t;
+
+ +

http_t

+

Description

+

HTTP connection structure.

+

Definition

+
+typedef struct http_s http_t;
+
+ +

ipp_attribute_t

+

Description

+

Attribute

+

Definition

+
+typedef struct ipp_attribute_s ipp_attribute_t;
+
+ +

ipp_iocb_t

+

Description

+

IPP IO Callback Function

+

Definition

+
+typedef int (*ipp_iocb_t)(void *, ipp_uchar_t *, int);
+
+ +

ipp_request_t

+

Description

+

Request Header

+

Definition

+
+typedef union ipp_request_t;
+
+ +

ipp_t

+

Description

+

Attribute Value

+

Definition

+
+typedef struct ipp_str ipp_t;
+
+ +

ipp_value_t

+

Description

+

New in CUPS 1.1.19

+

Definition

+
+typedef union ipp_value_t;
+
+ + diff --git a/doc/help/api-ppd.html b/doc/help/api-ppd.html new file mode 100644 index 000000000..341908af0 --- /dev/null +++ b/doc/help/api-ppd.html @@ -0,0 +1,1250 @@ + + + + + PPD API + + + + + + + +

Introduction

+ +

The CUPS PPD API provides...

+ +

General Usage

+ +

The <cups/ppd.h> header file must be included +to use the ppd functions.

+ +

Programs using these functions must be linked to the CUPS +library: libcups.a, libcups.so.2, +libcups.2.dylib, libcups_s.a, or +libcups2.lib depending on the platform. The following +command compiles myprogram.c using GCC and the CUPS +library:

+ +
+gcc -o myprogram myprogram.c -lcups
+
+ +

Compatibility

+ +

Unless otherwise specified, the PPD API functions require CUPS +1.1 or higher.

+

Contents

+ + +

Enumerations

+ + +

ppd_cs_e

+

Description

+

Colorspaces

+

Values

+
+ + + + + + + + +
NameDescription
PPD_CS_CMY CMY colorspace
PPD_CS_CMYK CMYK colorspace
PPD_CS_GRAY Grayscale colorspace
PPD_CS_N DeviceN colorspace
PPD_CS_RGB RGB colorspace
PPD_CS_RGBK RGBK (K = gray) colorspace
+ +

 CUPS 1.2 ppd_ext_ui_e

+

Description

+

Extended UI Types

+

Values

+
+ + + + + + + + + + +
NameDescription
PPD_UI_CUPS_CURVE Specify start, end, and gamma numbers
PPD_UI_CUPS_GAMMA Specify a gamma number
PPD_UI_CUPS_INTEGER Specify an integer number
PPD_UI_CUPS_INTEGER_ARRAY Specify an array of integer numbers
PPD_UI_CUPS_REAL Specify a real number
PPD_UI_CUPS_REAL_ARRAY Specify an array of real numbers
PPD_UI_CUPS_TEXT Specify a string
PPD_UI_CUPS_XY_ARRAY Specify an array of X/Y real numbers
+ +

ppd_section_e

+

Description

+

Order dependency sections

+

Values

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

+

Description

+

Types and structures...

+

Values

+
+ + + + + + + + + + + + + + + + + + + + + + +
NameDescription
PPD_ALLOC_ERROR Memory allocation error
PPD_BAD_OPEN_GROUP Bad OpenGroup
PPD_BAD_OPEN_UI Bad OpenUI/JCLOpenUI
PPD_BAD_ORDER_DEPENDENCY Bad OrderDependency
PPD_BAD_UI_CONSTRAINTS Bad UIConstraints
PPD_FILE_OPEN_ERROR Unable to open PPD file
PPD_ILLEGAL_CHARACTER Illegal control character
PPD_ILLEGAL_MAIN_KEYWORD Illegal main keyword string
PPD_ILLEGAL_OPTION_KEYWORD Illegal option keyword string
PPD_ILLEGAL_TRANSLATION Illegal translation string
PPD_ILLEGAL_WHITESPACE Illegal whitespace character
PPD_INTERNAL_ERROR Internal error
PPD_LINE_TOO_LONG Line longer than 255 chars
PPD_MISSING_ASTERISK Missing asterisk in column 0
PPD_MISSING_PPDADOBE4 Missing PPD-Adobe-4.x header
PPD_MISSING_VALUE Missing value string
PPD_NESTED_OPEN_GROUP OpenGroup without a CloseGroup first
PPD_NESTED_OPEN_UI OpenUI/JCLOpenUI without a CloseUI/JCLCloseUI first
PPD_NULL_FILE NULL PPD file pointer
PPD_OK OK
+ +

ppd_ui_e

+

Description

+

UI Types

+

Values

+
+ + + + + +
NameDescription
PPD_UI_BOOLEAN True or False option
PPD_UI_PICKMANY Pick zero or more from a list
PPD_UI_PICKONE Pick one from a list
+ +

Functions

+ + +

ppdClose()

+

Description

+

Free all memory used by the PPD file.

+

Syntax

+
+void
+ppdClose(
+    ppd_file_t * ppd);
+
+

Arguments

+
+ + + +
NameDescription
ppdPPD file record
+

Returns

+

Nothing.

+ +

ppdCollect()

+

Description

+

Collect all marked options that reside in the specified +section.

+

Syntax

+
+int
+ppdCollect(
+    ppd_file_t * ppd,
+    ppd_section_t section,
+    ppd_choice_t *** choices);
+
+

Arguments

+
+ + + + + +
NameDescription
ppdPPD file data
sectionSection to collect
choicesPointers to choices
+

Returns

+

Number of options marked

+ +

ppdConflicts()

+

Description

+

Check to see if there are any conflicts.

+

Syntax

+
+int
+ppdConflicts(
+    ppd_file_t * ppd);
+
+

Arguments

+
+ + + +
NameDescription
ppdPPD to check
+

Returns

+

Number of conflicts found

+ +

ppdEmit()

+

Description

+

Emit code for marked options to a file.

+

Syntax

+
+int
+ppdEmit(
+    ppd_file_t * ppd,
+    FILE * fp,
+    ppd_section_t section);
+
+

Arguments

+
+ + + + + +
NameDescription
ppdPPD file record
fpFile to write to
sectionSection to write
+

Returns

+

0 on success, -1 on failure

+ +

ppdEmitFd()

+

Description

+

Emit code for marked options to a file.

+

Syntax

+
+int
+ppdEmitFd(
+    ppd_file_t * ppd,
+    int fd,
+    ppd_section_t section);
+
+

Arguments

+
+ + + + + +
NameDescription
ppdPPD file record
fdFile to write to
sectionSection to write
+

Returns

+

0 on success, -1 on failure

+ +

ppdEmitJCL()

+

Description

+

Emit code for JCL options to a file.

+

Syntax

+
+int
+ppdEmitJCL(
+    ppd_file_t * ppd,
+    FILE * fp,
+    int job_id,
+    const char * user,
+    const char * title);
+
+

Arguments

+
+ + + + + + + +
NameDescription
ppdPPD file record
fpFile to write to
job_idJob ID
userUsername
titleTitle
+

Returns

+

0 on success, -1 on failure

+ +

 CUPS 1.2 ppdEmitJCLEnd()

+

Description

+

Emit JCLEnd code to a file. + +

+

Syntax

+
+int
+ppdEmitJCLEnd(
+    ppd_file_t * ppd,
+    FILE * fp);
+
+

Arguments

+
+ + + + +
NameDescription
ppdPPD file record
fpFile to write to
+

Returns

+

0 on success, -1 on failure

+ +

 CUPS 1.1.19 ppdErrorString()

+

Description

+

Returns the text assocated with a status. + +

+

Syntax

+
+const char *
+ppdErrorString(
+    ppd_status_t status);
+
+

Arguments

+
+ + + +
NameDescription
statusPPD status
+

Returns

+

Status string

+ +

 CUPS 1.1.19 ppdFindAttr()

+

Description

+

Find the first matching attribute... + +

+

Syntax

+
+ppd_attr_t *
+ppdFindAttr(
+    ppd_file_t * ppd,
+    const char * name,
+    const char * spec);
+
+

Arguments

+
+ + + + + +
NameDescription
ppdPPD file data
nameAttribute name
specSpecifier string or NULL
+

Returns

+

Attribute or NULL if not found

+ +

ppdFindChoice()

+

Description

+

Return a pointer to an option choice.

+

Syntax

+
+ppd_choice_t *
+ppdFindChoice(
+    ppd_option_t * o,
+    const char * choice);
+
+

Arguments

+
+ + + + +
NameDescription
oPointer to option
choiceName of choice
+

Returns

+

Choice pointer or NULL

+ +

ppdFindMarkedChoice()

+

Description

+

Return the marked choice for the specified option.

+

Syntax

+
+ppd_choice_t *
+ppdFindMarkedChoice(
+    ppd_file_t * ppd,
+    const char * option);
+
+

Arguments

+
+ + + + +
NameDescription
ppdPPD file
optionKeyword/option name
+

Returns

+

Pointer to choice or NULL

+ +

 CUPS 1.1.19 ppdFindNextAttr()

+

Description

+

Find the next matching attribute... + +

+

Syntax

+
+ppd_attr_t *
+ppdFindNextAttr(
+    ppd_file_t * ppd,
+    const char * name,
+    const char * spec);
+
+

Arguments

+
+ + + + + +
NameDescription
ppdPPD file data
nameAttribute name
specSpecifier string or NULL
+

Returns

+

Attribute or NULL if not found

+ +

ppdFindOption()

+

Description

+

Return a pointer to the specified option.

+

Syntax

+
+ppd_option_t *
+ppdFindOption(
+    ppd_file_t * ppd,
+    const char * option);
+
+

Arguments

+
+ + + + +
NameDescription
ppdPPD file data
optionOption/Keyword name
+

Returns

+

Pointer to option or NULL

+ +

ppdIsMarked()

+

Description

+

Check to see if an option is marked...

+

Syntax

+
+int
+ppdIsMarked(
+    ppd_file_t * ppd,
+    const char * option,
+    const char * choice);
+
+

Arguments

+
+ + + + + +
NameDescription
ppdPPD file data
optionOption/Keyword name
choiceChoice name
+

Returns

+

Non-zero if option is marked

+ +

 CUPS 1.1.19 ppdLastError()

+

Description

+

Return the status from the last ppdOpen*(). + +

+

Syntax

+
+ppd_status_t
+ppdLastError(
+    int * line);
+
+

Arguments

+
+ + + +
NameDescription
lineLine number
+

Returns

+

Status code

+ +

ppdMarkDefaults()

+

Description

+

Mark all default options in the PPD file.

+

Syntax

+
+void
+ppdMarkDefaults(
+    ppd_file_t * ppd);
+
+

Arguments

+
+ + + +
NameDescription
ppdPPD file record
+

Returns

+

Nothing.

+ +

ppdMarkOption()

+

Description

+

Mark an option in a PPD file. + +Notes: + +-1 is returned if the given option would conflict with any currently +selected option.

+

Syntax

+
+int
+ppdMarkOption(
+    ppd_file_t * ppd,
+    const char * option,
+    const char * choice);
+
+

Arguments

+
+ + + + + +
NameDescription
ppdPPD file record
optionKeyword
choiceOption name
+

Returns

+

Number of conflicts

+ +

ppdOpen()

+

Description

+

Read a PPD file into memory.

+

Syntax

+
+ppd_file_t *
+ppdOpen(
+    FILE * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpFile to read from
+

Returns

+

PPD file record

+ +

 CUPS 1.2 ppdOpen2()

+

Description

+

Read a PPD file into memory. + +

+

Syntax

+
+ppd_file_t *
+ppdOpen2(
+    cups_file_t * fp);
+
+

Arguments

+
+ + + +
NameDescription
fpFile to read from
+

Returns

+

PPD file record

+ +

ppdOpenFd()

+

Description

+

Read a PPD file into memory.

+

Syntax

+
+ppd_file_t *
+ppdOpenFd(
+    int fd);
+
+

Arguments

+
+ + + +
NameDescription
fdFile to read from
+

Returns

+

PPD file record

+ +

ppdOpenFile()

+

Description

+

Read a PPD file into memory.

+

Syntax

+
+ppd_file_t *
+ppdOpenFile(
+    const char * filename);
+
+

Arguments

+
+ + + +
NameDescription
filenameFile to read from
+

Returns

+

PPD file record

+ +

ppdPageLength()

+

Description

+

Get the page length for the given size.

+

Syntax

+
+float
+ppdPageLength(
+    ppd_file_t * ppd,
+    const char * name);
+
+

Arguments

+
+ + + + +
NameDescription
ppdPPD file
nameSize name
+

Returns

+

Length of page in points or 0.0

+ +

ppdPageSize()

+

Description

+

Get the page size record for the given size.

+

Syntax

+
+ppd_size_t *
+ppdPageSize(
+    ppd_file_t * ppd,
+    const char * name);
+
+

Arguments

+
+ + + + +
NameDescription
ppdPPD file record
nameSize name
+

Returns

+

Size record for page or NULL

+ +

ppdPageWidth()

+

Description

+

Get the page width for the given size.

+

Syntax

+
+float
+ppdPageWidth(
+    ppd_file_t * ppd,
+    const char * name);
+
+

Arguments

+
+ + + + +
NameDescription
ppdPPD file record
nameSize name
+

Returns

+

Width of page in points or 0.0

+ +

 CUPS 1.1.20 ppdSetConformance()

+

Description

+

Set the conformance level for PPD files. + +

+

Syntax

+
+void
+ppdSetConformance(
+    ppd_conform_t c);
+
+

Arguments

+
+ + + +
NameDescription
cConformance level
+

Returns

+

Nothing.

+ +

Structures

+ + +

 CUPS 1.1.19 ppd_attr_str

+

Description

+

PPD Attribute Structure

+

Definition

+
+struct ppd_attr_str
+{
+  char name[PPD_MAX_NAME];
+  char spec[PPD_MAX_NAME];
+  char text[PPD_MAX_TEXT];
+  char * value;
+};
+
+

Members

+
+ + + + + + +
NameDescription
name[PPD_MAX_NAME] Name of attribute (cupsXYZ)
spec[PPD_MAX_NAME] Specifier string, if any
text[PPD_MAX_TEXT] Human-readable text, if any
value Value string
+ +

ppd_choice_str

+

Description

+

Option choices

+

Definition

+
+struct ppd_choice_str
+{
+  char choice[PPD_MAX_NAME];
+  char * code;
+  char marked;
+  ppd_option_t * option;
+  char text[PPD_MAX_TEXT];
+};
+
+

Members

+
+ + + + + + + +
NameDescription
choice[PPD_MAX_NAME] Computer-readable option name
code Code to send for this option
marked 0 if not selected, 1 otherwise
option Pointer to parent option structure
text[PPD_MAX_TEXT] Human-readable option name
+ +

ppd_emul_str

+

Description

+

Emulators

+

Definition

+
+struct ppd_emul_str
+{
+  char name[PPD_MAX_NAME];
+  char * start;
+  char * stop;
+};
+
+

Members

+
+ + + + + +
NameDescription
name[PPD_MAX_NAME] Emulator name
start Code to switch to this emulation
stop Code to stop this emulation
+ +

 CUPS 1.2 ppd_ext_option_str

+

Description

+

Extended Options

+

Definition

+
+struct ppd_ext_option_str
+{
+  char * code;
+  char keyword[PPD_MAX_NAME];
+  int marked;
+  int num_params;
+  ppd_option_t * option;
+  ppd_ext_param_t ** params;
+};
+
+

Members

+
+ + + + + + + + +
NameDescription
code Generic PS code for extended options
keyword[PPD_MAX_NAME] Name of option that is being extended...
marked Extended option is marked
num_params Number of parameters
option Option that is being extended...
params Parameters
+ +

 CUPS 1.2 ppd_ext_param_str

+

Description

+

Extended Parameter

+

Definition

+
+struct ppd_ext_param_str
+{
+  ppd_ext_value_t * defval;
+  char keyword[PPD_MAX_NAME];
+  ppd_ext_value_t * maxval;
+  ppd_ext_value_t * minval;
+  char text[PPD_MAX_TEXT];
+  ppd_ext_value_t * value;
+};
+
+

Members

+
+ + + + + + + + +
NameDescription
defval Default values
keyword[PPD_MAX_NAME] Parameter name
maxval Maximum numeric values
minval Minimum numeric values
text[PPD_MAX_TEXT] Human-readable text
value Current values
+ +

ppd_file_str

+

Description

+

Files

+

Definition

+
+struct ppd_file_str
+{
+  int accurate_screens;
+  ppd_attr_t ** attrs;
+  int color_device;
+  ppd_cs_t colorspace;
+  ppd_const_t * consts;
+  int contone_only;
+  int cur_attr;
+  float custom_margins[4];
+  float custom_max[2];
+  float custom_min[2];
+  ppd_emul_t * emulations;
+  ppd_ext_option_t ** extended;
+  char ** filters;
+  int flip_duplex;
+  char ** fonts;
+  ppd_group_t * groups;
+  char * jcl_begin;
+  char * jcl_end;
+  char * jcl_ps;
+  int landscape;
+  char * lang_encoding;
+  char * lang_version;
+  int language_level;
+  int manual_copies;
+  char * manufacturer;
+  int model_number;
+  char * modelname;
+  char * nickname;
+  int num_attrs;
+  int num_consts;
+  int num_emulations;
+  int num_extended;
+  int num_filters;
+  int num_fonts;
+  int num_groups;
+  int num_profiles;
+  int num_sizes;
+  char * patches;
+  char * pcfilename;
+  char * product;
+  ppd_profile_t * profiles;
+  char * protocols;
+  char * shortnickname;
+  ppd_size_t * sizes;
+  int throughput;
+  char * ttrasterizer;
+  int variable_sizes;
+};
+
+

Members

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameDescription
accurate_screens 1 = supports accurate screens, 0 = not
attrs  CUPS 1.1.19 Attributes
color_device 1 = color device, 0 = grayscale
colorspace Default colorspace
consts UI/Non-UI constraints
contone_only 1 = continuous tone only, 0 = not
cur_attr  CUPS 1.1.19 Current attribute
custom_margins[4] Margins around page
custom_max[2] Maximum variable page size
custom_min[2] Minimum variable page size
emulations Emulations and the code to invoke them
extended  CUPS 1.2 Extended options
filters Filter strings...
flip_duplex  CUPS 1.1 1 = Flip page for back sides
fonts Pre-loaded fonts
groups UI groups
jcl_begin Start JCL commands
jcl_end End JCL commands
jcl_ps Enter PostScript interpreter
landscape -90 or 90
lang_encoding Language encoding
lang_version Language version (English, Spanish, etc.)
language_level Language level of device
manual_copies 1 = Copies done manually, 0 = hardware
manufacturer Manufacturer name
model_number Device-specific model number
modelname Model name (general)
nickname Nickname (specific)
num_attrs  CUPS 1.1.19 Number of attributes
num_consts Number of UI/Non-UI constraints
num_emulations Number of emulations supported
num_extended  CUPS 1.2 Number of extended options
num_filters Number of filters
num_fonts Number of pre-loaded fonts
num_groups Number of UI groups
num_profiles Number of sRGB color profiles
num_sizes Number of page sizes
patches Patch commands to be sent to printer
pcfilename  CUPS 1.1.19 PCFileName string
product Product name (from PS RIP/interpreter)
profiles sRGB color profiles
protocols  CUPS 1.1.19 Protocols (BCP, TBCP) string
shortnickname Short version of nickname
sizes Page sizes
throughput Pages per minute
ttrasterizer Truetype rasterizer
variable_sizes 1 = supports variable sizes, 0 = doesn't
+ +

ppd_group_str

+

Description

+

Groups

+

Definition

+
+struct ppd_group_str
+{
+  char text[PPD_MAX_TEXT - PPD_MAX_NAME];
+  char name[PPD_MAX_NAME];
+  int num_options;
+  int num_subgroups;
+  ppd_option_t * options;
+  struct ppd_group_str * subgroups;
+};
+
+

Members

+
+ + + + + + + + +
NameDescription
PPD_MAX_NAME] Human-readable group name
name[PPD_MAX_NAME]  CUPS 1.1.18 Group name
num_options Number of options
num_subgroups Number of sub-groups
options Options
subgroups Sub-groups (max depth = 1)
+ +

ppd_option_str

+

Description

+

Options

+

Definition

+
+struct ppd_option_str
+{
+  ppd_choice_t * choices;
+  char conflicted;
+  char defchoice[PPD_MAX_NAME];
+  char keyword[PPD_MAX_NAME];
+  int num_choices;
+  float order;
+  ppd_section_t section;
+  char text[PPD_MAX_TEXT];
+  ppd_ui_t ui;
+};
+
+

Members

+
+ + + + + + + + + + + +
NameDescription
choices Option choices
conflicted 0 if no conflicts exist, 1 otherwise
defchoice[PPD_MAX_NAME] Default option choice
keyword[PPD_MAX_NAME] Option keyword name ("PageSize", etc.)
num_choices Number of option choices
order Order number
section Section for command
text[PPD_MAX_TEXT] Human-readable text
ui Type of UI option
+ +

ppd_profile_str

+

Description

+

sRGB Color Profiles

+

Definition

+
+struct ppd_profile_str
+{
+  float density;
+  float gamma;
+  float matrix[3][3];
+  char media_type[PPD_MAX_NAME];
+  char resolution[PPD_MAX_NAME];
+};
+
+

Members

+
+ + + + + + + +
NameDescription
density Ink density to use
gamma Gamma correction to use
matrix[3][3] Transform matrix
media_type[PPD_MAX_NAME] Media type or "-"
resolution[PPD_MAX_NAME] Resolution or "-"
+ +

ppd_size_str

+

Description

+

Page Sizes

+

Definition

+
+struct ppd_size_str
+{
+  float bottom;
+  float left;
+  float length;
+  int marked;
+  char name[PPD_MAX_NAME];
+  float right;
+  float top;
+  float width;
+};
+
+

Members

+
+ + + + + + + + + + +
NameDescription
bottom Bottom printable margin in points
left Left printable margin in points
length Length of media in points
marked Page size selected?
name[PPD_MAX_NAME] Media size option
right Right printable margin in points
top Top printable margin in points
width Width of media in points
+ +

Types

+ + +

 CUPS 1.1.19 ppd_attr_t

+

Description

+

PPD Attribute Structure

+

Definition

+
+typedef struct ppd_attr_str ppd_attr_t;
+
+ +

ppd_choice_t

+

Description

+

Option choices

+

Definition

+
+typedef struct ppd_choice_str ppd_choice_t;
+
+ +

ppd_const_t

+

Description

+

Constraints

+

Definition

+
+typedef struct ppd_const_t;
+
+ +

ppd_emul_t

+

Description

+

Emulators

+

Definition

+
+typedef struct ppd_emul_str ppd_emul_t;
+
+ +

 CUPS 1.2 ppd_ext_option_t

+

Description

+

Extended Options

+

Definition

+
+typedef struct ppd_ext_option_str ppd_ext_option_t;
+
+ +

 CUPS 1.2 ppd_ext_param_t

+

Description

+

Extended Parameter

+

Definition

+
+typedef struct ppd_ext_param_str ppd_ext_param_t;
+
+ +

 CUPS 1.2 ppd_ext_ui_t

+

Description

+

Extended UI Types

+

Definition

+
+typedef enum ppd_ext_ui_e ppd_ext_ui_t;
+
+ +

 CUPS 1.2 ppd_ext_value_t

+

Description

+

Extended Values

+

Definition

+
+typedef union ppd_ext_value_u ppd_ext_value_t;
+
+ +

ppd_file_t

+

Description

+

Files

+

Definition

+
+typedef struct ppd_file_str ppd_file_t;
+
+ +

ppd_group_t

+

Description

+

Groups

+

Definition

+
+typedef struct ppd_group_str ppd_group_t;
+
+ +

ppd_option_t

+

Description

+

Options

+

Definition

+
+typedef struct ppd_option_str ppd_option_t;
+
+ +

ppd_profile_t

+

Description

+

sRGB Color Profiles

+

Definition

+
+typedef struct ppd_profile_str ppd_profile_t;
+
+ +

ppd_section_t

+

Description

+

Order dependency sections

+

Definition

+
+typedef enum ppd_section_e ppd_section_t;
+
+ +

ppd_size_t

+

Description

+

Page Sizes

+

Definition

+
+typedef struct ppd_size_str ppd_size_t;
+
+ +

ppd_ui_t

+

Description

+

UI Types

+

Definition

+
+typedef enum ppd_ui_e ppd_ui_t;
+
+ +

Unions

+ + +

 CUPS 1.2 ppd_ext_value_u

+

Description

+

Extended Values

+

Definition

+
+union ppd_ext_value_u
+{
+  float gamma;
+  int integer;
+  float real;
+  char * text;
+};
+
+

Members

+
+ + + + + + +
NameDescription
gamma Gamma value
integer Integer value
real Real value
text Text value
+ + diff --git a/doc/help/classes-conf-reference.html b/doc/help/classes-conf-reference.html new file mode 100644 index 000000000..eba834d18 --- /dev/null +++ b/doc/help/classes-conf-reference.html @@ -0,0 +1,540 @@ + + + + classes.conf + + + +

The CUPS scheduler (cupsd) uses the +/etc/cups/classes.conf file to store the list of +available classes. This file contains only locally defined +classes, not remote classes that are created automatically via +browsing. 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.

+ +

While the class configuration file consists of plain text and +can be modified using your favorite text editor, you should +normally use the lpadmin(8) command, web interface, +or any of the available GUIs to manage your classes instead. If +you do choose to edit this file manually, you will need to +restart the scheduler to make them active.

+ + +

Accepting

+ +

Examples

+ +
+Accepting yes
+Accepting no
+
+ +

Description

+ +

The Accepting directive defines the initial state +of the printer-is-accepting-jobs attribute. This state +is also set by the accept(8) and +reject(8) commands:

+ +
+/usr/sbin/accept classname
+/usr/sbin/reject classname
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

AllowUser

+ +

Examples

+ +
+AllowUser foo_user
+AllowUser @bar_group
+
+ +

Description

+ +

The AllowUser directive adds a username or group +name to the requesting-user-name-allowed attribute +which can be set by the lpadmin(8) command:

+ +
+/usr/sbin/lpadmin -p classname -u allow:foo_user,@bar_group
+
+ +

This directive must appear inside a Class or DefaultClass directive. +This directive cannot be used with DenyUser.

+ + +

Class

+ +

Examples

+ +
+<Class name>
+...
+</Class>
+
+ +

Description

+ +

The Class directive begins a class definition. +Classes are added using the lpadmin(8) command: + +

+/usr/sbin/lpadmin -p printername -c classname
+
+ + +

DefaultClass

+ +

Examples

+ +
+<DefaultClass name>
+...
+</Class>
+
+ +

Description

+ +

The DefaultClass directive begins a class +definition as the default server destination. The default server +destination can be set using the lpadmin(8) +command:

+ +
+/usr/sbin/lpadmin -d classname
+
+ +

Note that the server default destination settings can be +overridden by the user's default destination settings which are +normally set using the lpoptions(1) command.

+ + +

DenyUser

+ +

Examples

+ +
+DenyUser foo_user
+DenyUser @bar_group
+
+ +

Description

+ +

The DenyUser directive adds a username or group +name to the requesting-user-name-denied attribute +which can be set by the lpadmin(8) command:

+ +
+/usr/sbin/lpadmin -p classname -u deny:foo_user,@bar_group
+
+ +

This directive must appear inside a Class or DefaultClass directive. +This directive cannot be used with AllowUser

+ + +

CUPS 1.2ErrorPolicy

+ +

Examples

+ +
+ErrorPolicy cancel-job
+ErrorPolicy retry-job
+ErrorPolicy stop-printer
+
+ +

Description

+ +

The ErrorPolicy directive defines the policy that +is used when a backend is unable to send a print job to the +printer. The lpadmin(8) command sets the current +error policy:

+ +
+/usr/sbin/lpadmin -p classname -o printer-error-policy=stop-printer
+
+ +

The following values are supported:

+ +
    + +
  • cancel-job - Cancel the job and proceed + with the next job in the queue
  • + +
  • retry-job - Retry the job after waiting + for N seconds; the cupsd.conf JobRetryInterval + directive controls the value of N
  • + +
  • stop-printer - Stop the printer and keep + the job for future printing; this is the default + value
  • + +
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

Info

+ +

Examples

+ +
+Info My Class
+
+ +

Description

+ +

The Info directive defines the string for the +printer-info attribute. It is normally set using the +lpadmin(8) command:

+ +
+/usr/sbin/lpadmin -p classname -D "My Class"
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

JobSheets

+ +

Examples

+ +
+JobSheets none,standard
+
+ +

Description

+ +

The JobSheets directive specifies the default +banner pages to print before and after a print job. In the above +example, only a standard banner will print after each +job. The lpadmin(8) command is normally used to set +the default banners: + +

+/usr/sbin/lpadmin -p classname -o job-sheets-default=none,standard
+
+ +

If only one banner file is specified, it will be printed +before the files in the job. If a second banner file is +specified, it is printed after the files in the job.

+ +

The available banner pages depend on the local system +configuration; CUPS includes the following standard banner +files:

+ +
    + +
  • none - Do not produce a banner + page.
  • + +
  • classified - A banner page with a + "classified" label at the top and bottom.
  • + +
  • confidential - A banner page with a + "confidential" label at the top and bottom.
  • + +
  • secret - A banner page with a + "secret" label at the top and bottom.
  • + +
  • standard - A banner page with no label + at the top and bottom.
  • + +
  • topsecret - A banner page with a + "top secret" label at the top and bottom.
  • + +
  • unclassified - A banner page with an + "unclassified" label at the top and bottom.
  • + +
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

KLimit

+ +

Examples

+ +
+KLimit 1234
+
+ +

Description

+ +

The KLimit directive defines the value of the +job-k-limit attribute. It is normally set using the +lpadmin(8) command:

+ +
+/usr/sbin/lpadmin -p classname -o job-k-limit=1234
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

Location

+ +

Examples

+ +
+Location Building 3321
+
+ +

Description

+ +

The Location directive defines the string for the +printer-location attribute. It is normally set using the +lpadmin(8) command:

+ +
+/usr/sbin/lpadmin -p classname -L "Building 3321"
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

CUPS 1.2OpPolicy

+ +

Examples

+ +
+OpPolicy default
+OpPolicy mypolicy
+
+ +

Description

+ +

The OpPolicy directive sets the operation policy +that is used for the printer. The lpadmin(8) command +sets the current operation policy:

+ +
+/usr/sbin/lpadmin -p classname -o printer-op-policy=default
+
+ +

The default policy is named "default". All policies correspond +to those defined using the cupsd.conf Policy +directive.

+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

PageLimit

+ +

Examples

+ +
+PageLimit 1234
+
+ +

Description

+ +

The PageLimit directive defines the value of the +job-page-limit attribute. It can be set using the +lpadmin(8) command:

+ +
+/usr/sbin/lpadmin -p classname -o job-page-limit=1234
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

Printer

+ +

Examples

+ +
+Printer bcp
+Printer none
+Printer tbcp
+
+ +

Description

+ +

The Printer directive adds a printer to a class. +Printers are added to a class using the lpadmin(8) +command:

+ +
+/usr/sbin/lpadmin -p printername -c classname
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

QuotaPeriod

+ +

Examples

+ +
+QuotaPeriod 604800
+
+ +

Description

+ +

The QuotaPeriod directive defines the value of +the job-quota-period attribute. Typical values are +86400 (1 day), 604800 (1 week), 2592000 (1 month), and 31536000 +(1 year). It is set using the lpadmin(8) +command:

+ +
+/usr/sbin/lpadmin -p classname -o job-quota-period=604800
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

CUPS 1.2Shared

+ +

Examples

+ +
+Shared yes
+Shared no
+
+ +

Description

+ +

The Shared directive defines the initial value of +the printer-is-shared attribute. The strings +yes and no correspond to the true and false +values, respectively. The lpadmin(8) command sets +the current state:

+ +
+/usr/sbin/lpadmin -p classname -o printer-is-shared=true
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

State

+ +

Examples

+ +
+State idle
+State stopped
+
+ +

Description

+ +

The State directive defines the initial value of +the printer-state attribute. The strings +idle and stopped correspond to the IPP +enumeration values 3 and 5, respectively. The +cupsenable(8) and cupsdisable(8) +commands set the current state:

+ +
+/usr/sbin/cupsenable classname
+/usr/sbin/cupsdisable classname
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

StateMessage

+ +

Examples

+ +
+StateMessage Ready to print.
+
+ +

Description

+ +

The StateMessage directive defines the initial +string for the printer-state-message attribute. The +following are some example messages:

+ +
+StateMessage Connected to host_name...
+StateMessage Connecting to printer_queue on port port_number...
+StateMessage Network host host_name is busy; will retry in 30 seconds...
+StateMessage Class busy; will retry in 10 seconds...
+StateMessage Class is busy; retrying print job...
+StateMessage Print file accepted - job ID id_number.
+StateMessage Ready to print.
+StateMessage Waiting for job to complete
+
+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + +

CUPS 1.2StateTime

+ +

Examples

+ +
+StateTime 1133542425
+
+ +

Description

+ +

The StateTime directive defines the UNIX time +(seconds since Jan 1, 1970) for the last state change of the +queue. It is mapped to the printer-state-change-time +attribute.

+ +

This directive must appear inside a Class or DefaultClass +directive.

+ + + + diff --git a/doc/help/client-conf-reference.html b/doc/help/client-conf-reference.html new file mode 100644 index 000000000..762edf265 --- /dev/null +++ b/doc/help/client-conf-reference.html @@ -0,0 +1,62 @@ + + + + client.conf + + + +

The /etc/cups/client.conf file contains many +directives that determine how the client behaves:

+ +

+ + + + +
+ +
  • Encryption +
  • ServerName + +
  • +

    + + +

    Encryption

    +
    + +

    Examples

    + +
      +Encryption Never
      +Encryption IfRequested
      +Encryption Required
      +Encryption Always
      +
    + +

    Description

    + +

    The Encryption directive specifies the default encryption settings for the client. +The default setting is IfRequested. + + + +

    ServerName

    +
    + +

    Examples

    + +
      +ServerName foo.bar.com
      +ServerName 11.22.33.44
      +
    + +

    Description

    + +

    The ServerName directive specifies sets the remote server that is to be used +for all client operations. That is, it redirects all client requests to the remote server. + +The default is to use the local server ("localhost"). + + + diff --git a/doc/help/cupsd-conf-reference.html b/doc/help/cupsd-conf-reference.html new file mode 100644 index 000000000..348afa573 --- /dev/null +++ b/doc/help/cupsd-conf-reference.html @@ -0,0 +1,2034 @@ + + + + cupsd.conf + + + +

    The /etc/cups/cupsd.conf file contains +configuration directives 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. +After making any changes, restart the cupsd(8) +process using the startup script for your operating system:

    + +
      + +
    • AIX: +
      +/etc/init.d/cups restart
      +	
    • + +
    • HP-UX: +
      +/sbin/init.d/cups restart
      +	
    • + +
    • IRIX: +
      +/etc/init.d/cups restart
      +	
    • + +
    • Linux: +
      +/etc/init.d/cups restart
      +	
    • + +
    • MacOS X: +
      +/System/Library/StartupItems/PrintingServices/PrintingServices restart
      +	
    • + +
    • Solaris: +
      +/etc/init.d/cups restart
      +	
    • + +
    + +

    You can also edit this file from the CUPS web interface, which +automatically handles restarting the scheduler.

    + + +

    AccessLog

    + +

    Examples

    + +
    +AccessLog /var/log/cups/access_log
    +AccessLog /var/log/cups/access_log-%s
    +AccessLog syslog
    +
    + +

    Description

    + +

    The AccessLog directive sets the name of the +access log file. If the filename is not absolute then it is +assumed to be relative to the ServerRoot 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.

    + +

    The server name can be included in the filename by using +%s in the name.

    + +

    The special name "syslog" can be used to send the access +information to the system log instead of a plain file.

    + +

    The default access log file is +/var/log/cups/access_log.

    + + +

    Allow

    + +

    Examples

    + +
    +Allow from All
    +Allow from None
    +Allow from *.domain.com
    +Allow from .domain.com
    +Allow from host.domain.com
    +Allow from nnn.*
    +Allow from nnn.nnn.*
    +Allow from nnn.nnn.nnn.*
    +Allow from nnn.nnn.nnn.nnn
    +Allow from nnn.nnn.nnn.nnn/mm
    +Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +Allow from xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
    +Allow from @LOCAL
    +Allow from @IF(name)
    +
    + +

    Description

    + +

    The Allow directive specifies a hostname, IP address, +or network that is allowed access to the server. Allow +directives are cummulative, so multiple Allow directives +can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask:

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    mmnetmaskmmnetmask
    00.0.0.08255.0.0.0
    1128.0.0.016255.255.0.0
    2192.0.0.024255.255.255.0
    ......32255.255.255.255
    + +

    The @LOCAL name will allow access from all local +interfaces. The @IF(name) name will allow access +from the named interface.

    + +

    The Allow directive must appear inside a Location directive.

    + + +

    DeprecatedAuthClass

    + +

    Examples

    + +
    +AuthClass Anonymous
    +AuthClass User
    +AuthClass System
    +AuthClass Group
    +
    + +

    Description

    + +

    The AuthClass directive defines what level of +authentication is required:

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

    The AuthClass directive must appear inside a Location directive.

    + +

    This directive is deprecated and will be removed from a +future release of CUPS. Consider using the more flexible Require directive instead.

    + + +

    DeprecatedAuthGroupName

    + +

    Examples

    + +
    +AuthGroupName mygroup
    +AuthGroupName lp
    +
    + +

    Description

    + +

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

    + +

    The AuthGroupName directive must appear inside a +Location directive.

    + +

    This directive is deprecated and will be removed from a +future release of CUPS. Consider using the more flexible Require directive instead.

    + + +

    AuthType

    + +

    Examples

    + +
    +AuthType None
    +AuthType Basic
    +AuthType Digest
    +AuthType BasicDigest
    +
    + +

    Description

    + +

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

    + +
      + +
    • None - No authentication should be + performed (default)
    • + +
    • Basic - Basic authentication should be + performed using the UNIX password and group files
    • + +
    • Digest - Digest authentication should be + performed using the /etc/cups/passwd.md5 + file
    • + +
    • BasicDigest - Basic authentication + should be performed using the + /etc/cups/passwd.md5 file
    • + +
    + +

    When using Basic, Digest, or +BasicDigest authentication, clients connecting +through the localhost interface can also +authenticate using certificates.

    + +

    The AuthType directive must appear inside a Location directive.

    + + +

    AutoPurgeJobs

    + +

    Examples

    + +
    +AutoPurgeJobs Yes
    +AutoPurgeJobs No
    +
    + +

    Description

    + +

    The AutoPurgeJobs 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 No.

    + + +

    BrowseAddress

    + +

    Examples

    + +
    +BrowseAddress 255.255.255.255:631
    +BrowseAddress 192.0.2.255:631
    +BrowseAddress host.domain.com:631
    +BrowseAddress @LOCAL
    +BrowseAddress @IF(name)
    +
    + +

    Description

    + +

    The BrowseAddress directive specifies an address +to send browsing information to. Multiple +BrowseAddress directives can be specified to send +browsing information to different networks or systems.

    + +

    The @LOCAL name will broadcast printer +information to all local interfaces. The @IF(name) +name will broadcast to the named interface.

    + +

    There is no default browse address.

    + +
    Note: + +

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

    + +
    + + +

    BrowseAllow

    + +

    Examples

    + +
    +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
    +BrowseAllow from @LOCAL
    +BrowseAllow from @IF(name)
    +
    + +

    Description

    + +

    The BrowseAllow directive specifies a system or +network to accept browse packets from. The default is to accept +browse packets from all hosts.

    + +

    Host and domain name matching require that you enable the HostNameLookups +directive.

    + +

    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.

    + +

    The @LOCAL name will allow browse data from all +local interfaces. The @IF(name) name will allow +browse data from the named interface.

    + + +

    BrowseDeny

    + +

    Examples

    + +
    +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
    +BrowseDeny from @LOCAL
    +BrowseDeny from @IF(name)
    +
    + +

    Description

    + +

    The BrowseDeny directive specifies a system or +network to reject browse packets from. The default is to not deny +browse packets from any hosts.

    + +

    Host and domain name matching require that you enable the HostNameLookups +directive.

    + +

    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.

    + +

    The @LOCAL name will block browse data from all +local interfaces. The @IF(name) name will block +browse data from the named interface.

    + + +

    BrowseOrder

    + +

    Examples

    + +
    +BrowseOrder allow,deny
    +BrowseOrder deny,allow
    +
    + +

    Description

    + +

    The BrowseOrder directive specifies the order of +allow/deny processing. The default order is +deny,allow:

    + +
      + +
    • allow,deny - Deny browse packets by + default, then check BrowseAllow lines + followed by BrowseDeny lines.
    • + +
    • deny,allow - Allow browse packets by + default, then check BrowseDeny lines + followed by BrowseAllow lines.
    • + +
    + + +

    BrowseInterval

    + +

    Examples

    + +
    +BrowseInterval 0
    +BrowseInterval 30
    +
    + +

    Description

    + +

    The BrowseInterval 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.

    + +

    The BrowseInterval value should always be less +than the BrowseTimeout +value. Otherwise printers and classes will disappear from client +systems between updates.

    + + +

    BrowsePoll

    + +

    Examples

    + +
    +BrowsePoll 192.0.2.2:631
    +BrowsePoll host.domain.com:631
    +
    + +

    Description

    + +

    The BrowsePoll directive polls a server for +available printers once every BrowseInterval seconds. +Multiple BrowsePoll directives can be specified to +poll multiple servers.

    + +

    If BrowseInterval is set to 0 then the server is +polled once every 30 seconds.

    + + +

    BrowsePort

    + +

    Examples

    + +
    +BrowsePort 631
    +BrowsePort 9999
    +
    + +

    Description

    + +

    The BrowsePort directive specifies the UDP port number +used for browse packets. The default port number is 631.

    + +
    Note: + +

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

    + + +

    BrowseProtocols

    + +

    Examples

    + +
    +BrowseProtocols CUPS
    +BrowseProtocols SLP
    +BrowseProtocols CUPS SLP
    +BrowseProtocols all
    +
    + +

    Description

    + +

    The BrowseProtocols directive specifies the +protocols to use when collecting and distributing shared printers +on the local network. The default protocol is CUPS, +which is a broadcast-based protocol.

    + +
    Note: + +

    When using the SLP protocol, you must have at least +one Directory Agent (DA) server on your network. Otherwise the +CUPS scheduler (cupsd) will not respond to client +requests for several seconds while polling the network.

    + +
    + + +

    BrowseRelay

    + +

    Examples

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

    Description

    + +

    The BrowseRelay directive specifies source and +destination addresses for relaying browsing information from one +host or network to another. Multiple BrowseRelay +directives can be specified as needed.

    + +

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

    + +
    +BrowseRelay 127.0.0.1 @LOCAL
    +
    + +

    This effectively provides access to printers on a WAN for all +clients on the LAN(s).

    + + +

    BrowseShortNames

    + +

    Examples

    + +
    +BrowseShortNames Yes
    +BrowseShortNames No
    +
    + +

    Description

    + +

    The BrowseShortNames 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".)

    + +

    The default value for this option is Yes.

    + + +

    BrowseTimeout

    + +

    Examples

    + +
    +BrowseTimeout 300
    +BrowseTimeout 60
    +
    + +

    Description

    + +

    The BrowseTimeout 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.

    + +

    The BrowseTimeout value should always be greater +than the BrowseInterval value. +Otherwise printers and classes will disappear from client systems +between updates.

    + + +

    Browsing

    + +

    Examples

    + +
    +Browsing On
    +Browsing Off
    +
    + +

    Description

    + +

    The Browsing directive controls whether or not +network printer browsing is enabled. The default setting is +On.

    + +

    This directive does not enable sharing of local printers by +itself; you must also use the BrowseAddress or BrowseProtocols +directives to advertise local printers to other systems.

    + +
    Note: + +

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

    + +
    + + +

    Classification

    + +

    Examples

    + +
    +Classification
    +Classification classified
    +Classification confidential
    +Classification secret
    +Classification topsecret
    +Classification unclassified
    +
    + +

    Description

    + +

    The Classification 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.

    + + +

    ClassifyOverride

    + +

    Examples

    + +
    +ClassifyOverride Yes
    +ClassifyOverride No
    +
    + +

    Description

    + +

    The ClassifyOverride 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 job-sheets option and +can choose to only print one security banner before or after the +job. If the job-sheets option is set to +none then the server default classification is +used.

    + +

    The default is to not allow classification overrides.

    + + +

    ConfigFilePerm

    + +

    Examples

    + +
    +ConfigFilePerm 0644
    +ConfigFilePerm 0600
    +
    + +

    Description

    + +

    The ConfigFilePerm directive specifies the +permissions to use when writing configuration files. The default +is 0600.

    + + +

    DataDir

    + +

    Examples

    + +
    +DataDir /usr/share/cups
    +
    + +

    Description

    + +

    The DataDir directive sets the directory to use +for data files.

    + + +

    DefaultCharset

    + +

    Examples

    + +
    +DefaultCharset utf-8
    +DefaultCharset iso-8859-1
    +DefaultCharset windows-1251
    +
    + +

    Description

    + +

    The DefaultCharset directive sets the default +character set to use for client connections. The default +character set is utf-8 but is overridden by the +character set for the language specified by the client or the +DefaultLanguage directive.

    + + +

    DefaultLanguage

    + +

    Examples

    + +
    +DefaultLanguage de
    +DefaultLanguage en
    +DefaultLanguage es
    +DefaultLanguage fr
    +DefaultLanguage it
    +
    + +

    Description

    + +

    The DefaultLanguage 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.

    + + +

    Deny

    + +

    Examples

    + +
    +Deny from All
    +Deny from None
    +Deny from *.domain.com
    +Deny from .domain.com
    +Deny from host.domain.com
    +Deny from nnn.*
    +Deny from nnn.nnn.*
    +Deny from nnn.nnn.nnn.*
    +Deny from nnn.nnn.nnn.nnn
    +Deny from nnn.nnn.nnn.nnn/mm
    +Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
    +Deny from xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
    +Deny from @LOCAL
    +Deny from @IF(name)
    +
    + +

    Description

    + +

    The Deny directive specifies a hostname, IP +address, or network that is allowed access to the server. +Deny directives are cummulative, so multiple +Deny directives can be used to allow access for +multiple hosts or networks. The /mm notation +specifies a CIDR netmask:

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    mmnetmaskmmnetmask
    00.0.0.08255.0.0.0
    1128.0.0.016255.255.0.0
    2192.0.0.024255.255.255.0
    ......32255.255.255.255
    + +

    The @LOCAL name will deny access from all local +interfaces. The @IF(name) name will deny access from +the named interface.

    + +

    The Deny directive must appear inside a Location directive.

    + + +

    DocumentRoot

    + +

    Examples

    + +
    +DocumentRoot /usr/share/doc/cups
    +DocumentRoot /foo/bar/doc/cups
    +
    + +

    Description

    + +

    The DocumentRoot 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 ServerRoot directory. The +default directory is /usr/share/doc/cups.

    + +

    Documents are first looked up in a sub-directory for the +primary language requested by the client (e.g. +/usr/share/doc/cups/fr/...) and then directly under +the DocumentRoot directory (e.g. +/usr/share/doc/cups/...), so it is possible to +localize the web content by providing subdirectories for each +language needed.

    + + +

    Encryption

    + +

    Examples

    + +
    +Encryption Never
    +Encryption IfRequested
    +Encryption Required
    +
    + +

    Description

    + +

    The Encryption directive must appear instead a Location section and specifies +the encryption settings for that location. The default setting is +IfRequested for all locations.

    + + +

    ErrorLog

    + +

    Examples

    + +
    +ErrorLog /var/log/cups/error_log
    +ErrorLog /var/log/cups/error_log-%s
    +ErrorLog syslog
    +
    + +

    Description

    + +

    The ErrorLog directive sets the name of the error +log file. If the filename is not absolute then it is assumed to +be relative to the ServerRoot directory. The +default error log file is /var/log/cups/error_log.

    + +

    The server name can be included in the filename by using +%s in the name.

    + +

    The special name "syslog" can be used to send the error +information to the system log instead of a plain file.

    + + +

    FileDevice

    + +

    Examples

    + +
    +FileDevice Yes
    +FileDevice No
    +
    + +

    Description

    + +

    The FileDevice directive determines whether the +scheduler allows new printers to be added using device URIs of +the form file:/filename. File devices are most often +used to test new printer drivers and do not support raw file +printing.

    + +

    The default setting is No.

    + +
    Note: + +

    File devices are managed by the scheduler. Since the +scheduler normally runs as the root user, file devices +can be used to overwrite system files and potentially +gain unauthorized access to the system. If you must +create printers using file devices, we recommend that +you set the FileDevice directive to +Yes for only as long as you need to add the +printers to the system, and then reset the directive to +No.

    + +
    + + +

    FilterLimit

    + +

    Examples

    + +
    +FilterLimit 0
    +FilterLimit 200
    +FilterLimit 1000
    +
    + +

    Description

    + +

    The FilterLimit 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.

    + +

    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.

    + +

    The default limit is 0.

    + + +

    FontPath

    + +

    Examples

    + +
    +FontPath /foo/bar/fonts
    +FontPath /usr/share/cups/fonts:/foo/bar/fonts
    +
    + +

    Description

    + +

    The FontPath directive specifies the font path to +use when searching for fonts. The default font path is +/usr/share/cups/fonts.

    + + +

    Group

    + +

    Examples

    + +
    +Group nobody
    +
    + +

    Description

    + +

    The Group directive specifies the UNIX group that +filter and CGI programs run as. The default group is +nobody.

    + + +

    HideImplicitMembers

    + +

    Examples

    + +
    +HideImplicitMembers Yes
    +HideImplicitMembers No
    +
    + +

    Description

    + +

    The HideImplicitMembers directive controls +whether the individual printers in an implicit class are hidden +from the user. The default is Yes.

    + +

    ImplicitClasses +must be enabled for this directive to have any effect.

    + + +

    HostNameLookups

    + +

    Examples

    + +
    +HostNameLookups On
    +HostNameLookups Off
    +HostNameLookups Double
    +
    + +

    Description

    + +

    The HostNameLookups directive controls whether or +not CUPS looks up the hostname for connecting clients. The +Double setting causes CUPS to verify that the +hostname resolved from the address matches one of the addresses +returned for that hostname. Double lookups also +prevent clients with unregistered addresses from connecting to +your server.

    + +

    The default is Off to avoid the potential server +performance problems with hostname lookups. Set this option to +On or Double only if absolutely +required.

    + + +

    ImplicitClasses

    + +

    Examples

    + +
    +ImplicitClasses On
    +ImplicitClasses Off
    +
    + +

    Description

    + +

    The ImplicitClasses directive controls whether +implicit classes are created based upon the available network +printers and classes. The default setting is On but +is automatically turned Off if Browsing is turned +Off.

    + + +

    ImplicitAnyClasses

    + +

    Examples

    + +
    +ImplicitAnyClasses On
    +ImplicitAnyClasses Off
    +
    + +

    Description

    + +

    The ImplicitAnyClasses directive controls +whether implicit classes for local and remote printers are +created with the name AnyPrinter. The default +setting is Off.

    + +

    ImplicitClasses +must be enabled for this directive to have any effect.

    + + +

    Include

    + +

    Examples

    + +
    +Include filename
    +Include /foo/bar/filename
    +
    + +

    Description

    + +

    The Include directive includes the named file in +the cupsd.conf file. If no leading path is provided, +the file is assumed to be relative to the ServerRoot directory.

    + + +

    KeepAlive

    + +

    Examples

    + +
    +KeepAlive On
    +KeepAlive Off
    +
    + +

    Description

    + +

    The KeepAlive directive controls whether or not +to support persistent HTTP connections. The default is +On.

    + +

    HTTP/1.1 clients automatically support persistent connections, +while HTTP/1.0 clients must specifically request them using the +Keep-Alive attribute in the Connection: +field of each request.

    + + +

    KeepAliveTimeout

    + +

    Examples

    + +
    +KeepAliveTimeout 60
    +KeepAliveTimeout 30
    +
    + +

    Description

    + +

    The KeepAliveTimeout directive controls how long +a persistent HTTP connection will remain open after the last +request. The default is 60 seconds.

    + + +

    Limit

    + +

    Examples

    + +
    +<Limit GET POST>
    +...
    +</Limit>
    +
    +<Limit ALL>
    +...
    +</Limit>
    +
    + +

    Description

    + +

    The Limit directive groups access control +directives for specific types of HTTP requests and must appear +inside a Location section. +Access can be limited for individual request types +(DELETE, GET, HEAD, +OPTIONS, POST, PUT, and +TRACE) or for all request types (ALL). +The request type names are case-sensitive for compatibility with +Apache.

    + + +

    LimitExcept

    + +

    Examples

    + +
    +<LimitExcept GET POST>
    +...
    +</LimitExcept>
    +
    + +

    Description

    + +

    The LimitExcept directive groups access control +directives for specific types of HTTP requests and must appear +inside a Location section. +Unlike the Limit directive, +LimitExcept restricts access for all requests +except those listed on the LimitExcept +line.

    + + +

    LimitRequestBody

    + +

    Examples

    + +
    +LimitRequestBody 10485760
    +LimitRequestBody 10m
    +LimitRequestBody 0
    +
    + +

    Description

    + +

    The LimitRequestBody 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.

    + + +

    Listen

    + +

    Examples

    + +
    +Listen 127.0.0.1:631
    +Listen 192.0.2.1:631
    +Listen [::1]:631
    +Listen *:631
    +
    + +

    Description

    + +

    The Listen directive specifies a network address +and port to listen for connections. Multiple Listen +directives can be provided to listen on multiple addresses.

    + +

    The Listen directive is similar to the Port directive but allows you to +restrict access to specific interfaces or networks.

    + + +

    Location

    + +

    Examples

    + +
    +<Location />
    +...
    +</Location>
    +
    +<Location /admin>
    +...
    +</Location>
    +
    +<Location /admin/conf>
    +...
    +</Location>
    +
    +<Location /admin/log>
    +...
    +</Location>
    +
    +<Location /classes>
    +...
    +</Location>
    +
    +<Location /classes/name>
    +...
    +</Location>
    +
    +<Location /jobs>
    +...
    +</Location>
    +
    +<Location /printers>
    +...
    +</Location>
    +
    +<Location /printers/name>
    +...
    +</Location>
    +
    +
    + +

    Description

    + +

    The Location directive specifies access control +and authentication options for the specified HTTP resource or +path. The Allow, AuthType, Deny, Encryption, Limit, LimitExcept, Order, Require, and Satisfy directives may all +appear inside a location.

    + +

    Note that more specific resources override the less specific +ones. So the directives inside the /printers/name +location will override ones from /printers. +Directives inside /printers will override ones from +/. None of the directives are inherited.

    + +
    + + + + + + + + + + + + + +
    Common Locations on the Server
    LocationDescription
    /The path for all get operations (get-printers, get-jobs, etc.)
    /adminThe path for all administration operations (add-printer, delete-printer, start-printer, etc.)
    /admin/confThe path for access to the CUPS configuration files (cupsd.conf, client.conf, etc.)
    /admin/logThe path for access to the CUPS log files (access_log, error_log, page_log)
    /classesThe path for all classes
    /classes/nameThe resource for class name
    /jobsThe path for all jobs (hold-job, release-job, etc.)
    /jobs/idThe resource for job id
    /printersThe path for all printers
    /printers/nameThe path for printer name
    /printers/name.ppdThe PPD file path for printer name
    + + +

    LogFilePerm

    + +

    Examples

    + +
    +LogFilePerm 0644
    +LogFilePerm 0600
    +
    + +

    Description

    + +

    The LogFilePerm directive specifies the +permissions to use when writing configuration files. The default +is 0644.

    + + +

    LogLevel

    + +

    Examples

    + +
    +LogLevel none
    +LogLevel emerg
    +LogLevel alert
    +LogLevel crit
    +LogLevel error
    +LogLevel warn
    +LogLevel notice
    +LogLevel info
    +LogLevel debug
    +LogLevel debug2
    +
    + +

    Description

    + +

    The LogLevel directive specifies the level of +logging for the ErrorLog +file. The following values are recognized (each level logs +everything under the preceding levels):

    + +
      + +
    • none - Log nothing
    • + +
    • emerg - Log emergency conditions that + prevent the server from running
    • + +
    • alert - Log alerts that must be handled + immediately
    • + +
    • crit - Log critical errors that don't + prevent the server from running
    • + +
    • error - Log general errors
    • + +
    • warn - Log errors and warnings
    • + +
    • notice - Log temporary error conditions
    • + +
    • info - Log all requests and state + changes (default)
    • + +
    • debug - Log basic debugging + information
    • + +
    • debug2 - Log all debugging + information
    • + +
    + + +

    MaxClients

    + +

    Examples

    + +
    +MaxClients 100
    +MaxClients 1024
    +
    + +

    Description

    + +

    The MaxClients directive controls the maximum +number of simultaneous clients that will be allowed by the +server. The default is 100 clients.

    + +
    Note: + +

    Since each print job requires a file descriptor for the status +pipe, the scheduler internally limits the MaxClients +value to 1/3 of the available file descriptors to avoid possible +problems when printing large numbers of jobs.

    + +
    + + +

    MaxClientsPerHost

    + +

    Examples

    + +
    +MaxClientsPerHost 10
    +
    + +

    Description

    + +

    The MaxClientsPerHost directive controls the +maximum number of simultaneous clients that will be allowed from +a single host by the server. The default is the +MaxClients value.

    + +

    This directive provides a small measure of protection against +Denial of Service attacks from a single host.

    + + +

    MaxCopies

    + +

    Examples

    + +
    +MaxCopies 100
    +MaxCopies 65535
    +
    + +

    Description

    + +

    The MaxCopies directive controls the maximum +number of copies that a user can print of a job. The default is +100 copies.

    + +
    Note: + +

    Most HP PCL laser printers internally limit the number of +copies to 100.

    + +
    + + + +

    MaxJobs

    + +

    Examples

    + +
    +MaxJobs 100
    +MaxJobs 9999
    +MaxJobs 0
    +
    + +

    Description

    + +

    The MaxJobs 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.

    + +

    Setting the maximum size to 0 disables this functionality. The +default setting is 0.

    + + +

    MaxJobsPerPrinter

    + +

    Examples

    + +
    +MaxJobsPerPrinter 100
    +MaxJobsPerPrinter 9999
    +MaxJobsPerPrinter 0
    +
    + +

    Description

    + +

    The MaxJobsPerPrinter 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 canceled.

    + +

    Setting the maximum to 0 disables this functionality. The +default setting is 0.

    + + +

    MaxJobsPerUser

    + +

    Examples

    + +
    +MaxJobsPerUser 100
    +MaxJobsPerUser 9999
    +MaxJobsPerUser 0
    +
    + +

    Description

    + +

    The MaxJobsPerUser 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 canceled.

    + +

    Setting the maximum to 0 disables this functionality. The +default setting is 0.

    + + +

    MaxLogSize

    + +

    Examples

    + +
    +MaxLogSize 1048576
    +MaxLogSize 1m
    +MaxLogSize 0
    +
    + +

    Description

    + +

    The MaxLogSize 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 filename.O. +This allows you to rotate the logs automatically. The default +size is 1048576 bytes (1MB).

    + +

    Setting the maximum size to 0 disables log rotation.

    + + +

    DeprecatedMaxRequestSize

    + +

    Examples

    + +
    +MaxRequestSize 10485760
    +MaxRequestSize 10m
    +MaxRequestSize 0
    +
    + +

    Description

    + +

    The MaxRequestSize 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.

    + +

    This directive is deprecated and will be replaced in a +future CUPS release. Use the LimitRequestBody +directive instead.

    + + +

    Order

    + +

    Examples

    + +
    +Order Allow,Deny
    +Order Deny,Allow
    +
    + +

    Description

    + +

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

    + +
      + +
    • allow,deny - Deny requests by default, + then check the Allow + lines followed by the Deny lines
    • + +
    • deny,allow - Allow requests by default, + then check the Deny + lines followed by the Allow lines
    • + +
    + +

    The Order directive must appear inside a Location directive.

    + + +

    PageLog

    + +

    Examples

    + +
    +PageLog /var/log/cups/page_log
    +PageLog /var/log/cups/page_log-%s
    +PageLog syslog
    +
    + +

    Description

    + +

    The PageLog directive sets the name of the page +log file. If the filename is not absolute then it is assumed to +be relative to the ServerRoot directory. The +default page log file is /var/log/cups/page_log.

    + +

    The server name can be included in the filename by using +%s in the name.

    + +

    The special name "syslog" can be used to send the page +information to the system log instead of a plain file.

    + + +

    Port

    + +

    Examples

    + +
    +Port 631
    +Port 80
    +
    + +

    Description

    + +

    The Port directive specifies a port to listen on. +Multiple Port lines can be specified to listen on +multiple ports. The Port directive is equivalent to +"Listen *:nnn". The default port is 631.

    + +
    Note: + +

    On systems that support IPv6, this directive will bind to both +the IPv4 and IPv6 wildcard address.

    + +
    + + +

    PreserveJobHistory

    + +

    Examples

    + +
    +PreserveJobHistory On
    +PreserveJobHistory Off
    +
    + +

    Description

    + +

    The PreserveJobHistory directive controls whether +the history of completed, canceled, or aborted print jobs is +stored on disk.

    + +

    A value of On (the default) preserves job +information until the administrator purges it with the +cancel command.

    + +

    A value of Off removes the job information as +soon as each job is completed, canceled, or aborted.

    + + +

    PreserveJobFiles

    + +

    Examples

    + +
    +PreserveJobFiles On
    +PreserveJobFiles Off
    +
    + +

    Description

    + +

    The PreserveJobFiles directive controls whether +the document files of completed, canceled, or aborted print jobs +are stored on disk.

    + +

    A value of On preserves job files until the +administrator purges them with the cancel command. +Jobs can be restarted (and reprinted) as desired until they are +purged.

    + +

    A value of Off (the default) removes the job +files as soon as each job is completed, canceled, or aborted.

    + + +

    Printcap

    + +

    Examples

    + +
    +Printcap
    +Printcap /etc/printcap
    +Printcap /etc/printers.conf
    +
    + +

    Description

    + +

    The Printcap 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 /etc/printcap.

    + +

    When a filename is specified (e.g. /etc/printcap), +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.

    + + +

    PrintcapFormat

    + +

    Examples

    + +
    +PrintcapFormat BSD
    +PrintcapFormat Solaris
    +
    + +

    Description

    + +

    The PrintcapFormat directive controls the output +format of the printcap file. The default is to generate a BSD +printcap file.

    + + +

    RemoteRoot

    + +

    Examples

    + +
    +RemoteRoot remroot
    +RemoteRoot root
    +
    + +

    Description

    + +

    The RemoteRoot directive sets the username for +unauthenticated root requests from remote hosts. The default +username is remroot. Setting RemoteRoot +to root effectively disables this security +mechanism.

    + + +

    RequestRoot

    + +

    Examples

    + +
    +RequestRoot /var/spool/cups
    +RequestRoot /foo/bar/spool/cups
    +
    + +

    Description

    + +

    The RequestRoot 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 ServerRoot directory. The +default request directory is /var/spool/cups.

    + + +

    Require

    + +

    Examples

    + +
    +Require group foo bar
    +Require user john mary
    +Require valid-user
    +Require user @groupname
    +Require user @SYSTEM
    +Require user @OWNER
    +
    + +

    Description

    + +

    The Require directive specifies that +authentication is required for the resource. The +group keyword specifies that the authenticated user +must be a member of one or more of the named groups that +follow.

    + +

    The user keyboard specifies that the +authenticated user must be one of the named users or groups that +follow. Group names are specified using the "@" prefix.

    + +

    The valid-user keyword specifies that any +authenticated user may access the resource.

    + +

    The default is to do no authentication. This directive must +appear inside a Location +directive.

    + + +

    RIPCache

    + +

    Examples

    + +
    +RIPCache 8m
    +RIPCache 1g
    +RIPCache 2048k
    +
    + +

    Description

    + +

    The RIPCache directive sets the size of the +memory cache used by Raster Image Processor ("RIP") filters such +as imagetoraster and pstoraster. 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.

    + + +

    Satisfy

    + +

    Examples

    + +
    +Satisfy all
    +Satisfy any
    +
    + +

    Description

    + +

    The Satisfy directive specifies whether all +conditions must be satisfied to allow access to the resource. If +set to all, then all authentication and access +control conditions must be satified to allow access.

    + +

    Setting Satisfy to any 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.

    + +

    The default is all. This directive must appear +inside a Location +directive.

    + + +

    ServerAdmin

    + +

    Examples

    + +
    +ServerAdmin user@host
    +ServerAdmin root@foo.bar.com
    +
    + +

    Description

    + +

    The ServerAdmin directive identifies the email +address for the administrator on the system. By default the +administrator email address is root@server, where +server is the server name.

    + + +

    ServerBin

    + +

    Examples

    + +
    +ServerBin /usr/lib/cups
    +ServerBin /foo/bar/lib/cups
    +
    + +

    Description

    + +

    The ServerBin directive sets the directory for +server-run executables. If an absolute path is not provided then +it is assumed to be relative to the ServerRoot directory. The +default executable directory is /usr/lib/cups or +/usr/lib32/cups (IRIX 6.5).

    + + +

    ServerCertificate

    + +

    Examples

    + +
    +ServerCertificate /etc/cups/ssl/server.crt
    +
    + +

    Description

    + +

    The ServerCertificate 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 +/etc/cups/ssl/server.crt.

    + + +

    ServerKey

    + +

    Examples

    + +
    +ServerKey /etc/cups/ssl/server.key
    +
    + +

    Description

    + +

    The ServerKey directive specifies the location of +the SSL private key file used by the server when negotiating +encrypted connections.

    + +

    The default key file is +/etc/cups/ssl/server.crt.

    + + +

    ServerName

    + +

    Examples

    + +
    +ServerName foo.domain.com
    +ServerName myserver.domain.com
    +
    + +

    Description

    + +

    The ServerName directive specifies the hostname +that is reported to clients. By default the server name is the +hostname.

    + + +

    ServerRoot

    + +

    Examples

    + +
    +ServerRoot /etc/cups
    +ServerRoot /foo/bar/cups
    +
    + +

    Description

    + +

    The ServerRoot directive specifies the absolute +path to the server configuration and state files. It is also used +to resolve relative paths in the cupsd.conf file. The +default server directory is /etc/cups.

    + + +

    SSLListen

    + +

    Examples

    + +
    +SSLListen 127.0.0.1:443
    +SSLListen 192.0.2.1:443
    +
    + +

    Description

    + +

    The SSLListen directive specifies a network +address and port to listen for secure connections. Multiple +SSLListen directives can be provided to listen on +multiple addresses.

    + +

    The SSLListen directive is similar to the SSLPort directive but allows you +to restrict access to specific interfaces or networks.

    + + +

    SSLPort

    + +

    Examples

    + +
    +SSLPort 443
    +
    + +

    Description

    + +

    The SSLPort directive specifies a port to listen +on for secure connections. Multiple SSLPort lines +can be specified to listen on multiple ports.

    + + +

    SystemGroup

    + +

    Examples

    + +
    +SystemGroup lpadmin
    +SystemGroup sys
    +SystemGroup system
    +SystemGroup root
    +
    + +

    Description

    + +

    The SystemGroup directive specifies the system +administration group for System authentication.

    + + +

    TempDir

    + +

    Examples

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

    Description

    + +

    The TempDir directive specifies an absolute path +for the directory to use for temporary files. The default +directory is /var/spool/cups/tmp.

    + +

    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 +/foo/bar/tmp:

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

    Timeout

    + +

    Examples

    + +
    +Timeout 300
    +Timeout 90
    +
    + +

    Description

    + +

    The Timeout directive controls the amount of time +to wait before an active HTTP or IPP request times out. The +default timeout is 300 seconds.

    + + +

    User

    + +

    Examples

    + +
    +User lp
    +User guest
    +
    + +

    Description

    + +

    The User directive specifies the UNIX user that +filter and CGI programs run as. The default user is +lp.

    + +
    Note: + +

    You may not use user root, as that would expose +the system to unacceptable security risks. The scheduler will +automatically choose user nobody if you specify a +user whose ID is 0.

    + +
    + + + + diff --git a/doc/help/error_log-reference.html b/doc/help/error_log-reference.html new file mode 100644 index 000000000..da93d0db5 --- /dev/null +++ b/doc/help/error_log-reference.html @@ -0,0 +1,52 @@ + + + + error_log + + + +

    The error_log file lists messages from the +scheduler - errors, warnings, etc. The LogLevel +directive controls which messages are logged:

    + +

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

    + +

    The level field contains the type of message:

    + +
      + +
    • A - Alert message (LogLevel alert) +
    • C - Critical error message (LogLevel crit) +
    • D - Debugging message (LogLevel debug) +
    • d - Detailed debugging message (LogLevel debug2) +
    • E - Normal error message (LogLevel error) +
    • I - Informational message (LogLevel info) +
    • N - Notice message (LogLevel notice) +
    • W - Warning message (LogLevel warn) +
    • X - Emergency error message (LogLevel emerg) + +
    + +

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

    + +

    The message fields contains a free-form textual +message. Messages from job filters are prefixed with "[Job +NNN]".

    + + + diff --git a/doc/help/network.html b/doc/help/network.html new file mode 100644 index 000000000..1cf1ed76f --- /dev/null +++ b/doc/help/network.html @@ -0,0 +1,431 @@ + + + + Using Network Printers + + + +

    Network Printer URIs

    + +

    Once you have set the IP address you can access the printer or +print server using the ipp, lpd, or +socket backends. The following is a list of common +network interfaces and printer servers and the settings you +should use with CUPS:

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Model/ManufacturerDevice URI(s)
    Apple LaserWriterlpd://address/PASSTHRU
    Axis w/o IPP
    + Axis OfficeBasic
    + (see directions)
    socket://address:9100
    + socket://address:9101
    + socket://address:9102
    Axis w/IPPipp://address/LPT1
    + ipp://address/LPT2
    + ipp://address/COM1
    Castelle LANpressTMlpd://address/pr1
    + lpd://address/pr2
    + lpd://address/pr3
    DPI NETPrintlpd://address/pr1
    + lpd://address/pr2
    + lpd://address/pr3
    DLink DP-301P+socket://address
    EFI® Fiery® RIPlpd://address/print
    EPSON® Multiprotocol Ethernet Interface Boardsocket://address
    Extended System ExtendNETlpd://address/pr1
    + lpd://address/pr2
    + lpd://address/pr3
    Hewlett Packard JetDirect w/o IPPsocket://address:9100
    + socket://address:9101
    + socket://address:9102
    Hewlett Packard JetDirect w/IPPipp://address/ipp
    + ipp://address/ipp/port1
    + ipp://address/ipp/port2
    + ipp://address/ipp/port3
    Intel® NetportExpress XL, PRO/100lpd://address/LPT1_PASSTHRU
    + lpd://address/LPT2_PASSTHRU
    + lpd://address/COM1_PASSTHRU
    LexmarkTM MarkNetlpd://address/ps
    Linksys EtherFast®
    + (see directions)
    socket://address:4010
    + socket://address:4020
    + socket://address:4030
    Linksys PSUS4lpd://address/lp
    Kodak®lpd://address/ps
    QMS® CrownNetTMlpd://address/ps
    Tektronix® PhaserShareTMsocket://address:9100
    XEROX® 4512 NIClpd://address/PORT1
    XEROX® XNIClpd://address/PASSTHRU
    XEROX® (most others)socket://address:5503
    + +

    Getting the IP Address

    + +

    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.

    + +

    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.

    + +

    Configuring the IP Address Using ARP

    + +

    The easiest way to set the IP address of a network device is +to use the arp(8) command. The arp +sends an Address Resolution Protocol ("ARP") packet to the +specified Ethernet MAC address, setting the network device's IP +address:

    + +
    +arp -s ip-address ethernet-address
    +arp -s host.domain.com 08:00:69:00:12:34
    +arp -s 192.0.2.2 08:00:69:00:12:34
    +
    + +

    Configuring the IP Address Using RARP

    + +

    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.

    + +

    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 arp command is +the way to go.

    + +

    Some UNIX operating systems use a program called +rarpd(8) to manage RARP. Others, like Linux, support +this protocol in the kernel. For systems that provide the +rarpd program you will need to start it before RARP +lookups will work:

    + +
    +rarpd
    +
    + +

    Under IRIX you can enable this functionality by default +using:

    + +
    +chkconfig rarpd on
    +
    + +

    Both the rarpd program and kernel RARP support +read a list of Ethernet and IP addresses from the file +/etc/ethers. Each line contains the Ethernet address +(colon delimited) followed by an IP address or hostname like:

    + +
    +08:00:69:00:12:34 myprinter.mydomain.com
    +08:00:69:00:12:34 192.0.2.2
    +
    + +

    Add a line to this file and cycle the power on the printer or +print server to set its address.

    + +

    Configuring the IP Address Using BOOTP

    + +

    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 bootpd(8) +program supplied with UNIX you simply need to add a line to the +/etc/bootptab file; for IRIX:

    + +
    +myprinter 08:00:69:00:12:34 192.0.2.2 myprinter.boot
    +
    + +

    Newer versions of bootpd use a different +format:

    + +
    +myprinter:ha=080069001234:ip=192.0.2.2:t144=myprinter.boot
    +
    + +

    The myprinter.boot file resides in the +/usr/local/boot directory by default. If you do not +need to provide a boot file you may leave the last part of the +line blank.

    + +
    Note: + +

    Some versions of UNIX do not enable the BOOTP service by +default. The /etc/inetd.conf usually contains a line +for the BOOTP service that can be uncommented if needed.

    + +
    + +

    Verifying the Printer Connection

    + +

    To test that the IP address has been successfully assigned and +that the printer is properly connected to your LAN, type:

    + +
    +ping ip-address
    +
    + +

    If the connection is working properly you will see something +like:

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

    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.

    + +

    Configuring Axis Print Servers

    + +

    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.

    + +

    Each print server contains a configuration file named +config 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 ftp(1) program:

    + +
    +ftp ip-address
    +Connected to ip-address.
    +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
    +ftp> user root
    +331 User name ok, need password
    +Password: pass (this is not echoed)
    +230 User logged in
    +ftp> get config
    +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> quit
    +221 Goodbye.
    +
    + +

    Next, edit the file with your favorite text editor and locate +the lines beginning with:

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

    Change the RTN_OPT line to read:

    + +
    +RTN_OPT.     : NO
    +
    + +

    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:

    + +
    +RTEL_PR1.    : 9100
    +RTEL_PR2.    : 9101
    +RTEL_PR3.    : 9102
    +RTEL_PR4.    : 9103
    +RTEL_PR5.    : 9104
    +RTEL_PR6.    : 9105
    +RTEL_PR7.    : 9106
    +RTEL_PR8.    : 9107
    +
    + +

    This essentially makes the Axis print server look like a +Hewlett Packard JetDirect EX print server. Save the file and then +upload the new config file using the ftp +command:

    + +
    +ftp ip-address
    +Connected to ip-address.
    +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
    +ftp> user root
    +331 User name ok, need password
    +Password: pass (this is not echoed)
    +230 User logged in
    +ftp> put config CONFIG
    +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> get hardreset
    +local: hardreset remote: hardreset
    +200 PORT command successful.
    +421 Axis NPS ### hard reset, closing connection.
    +ftp> quit
    +221 Goodbye.
    +
    + +

    Your Axis print server is now ready for use!

    + +

    Configuring Linksys Print Servers

    + +

    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.

    + +

    Each print server contains a configuration file named +CONFIG 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 ftp(1) program:

    + +
    +ftp -n ip-address
    +Connected to ip-address.
    +220 Print Server Ready.
    +Remote system type is Print.
    +ftp> get CONFIG
    +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> quit
    +221 Goodbye.
    +
    + +

    Next, edit the file with your favorite text editor and locate +the lines beginning with:

    + +
    +0100 L1_PROUT:P1
    +0120 L2_PROUT:P1
    +0140 L3_PROUT:P1
    +
    + +

    Change the port number for each parallel and serial port on +the server as follows:

    + +
    +0100 L1_PROUT:P1
    +0120 L2_PROUT:P2
    +0140 L3_PROUT:P3
    +
    + +

    This maps each virtual printer with a physical port. Save the +file and then upload the new CONFIG file using the +ftp command:

    + +
    +ftp -n ip-address
    +Connected to ip-address.
    +220 Print Server Ready.
    +Remote system type is Print.
    +ftp> put CONFIG
    +local: CONFIG remote: CONFIG
    +200 Command OK.
    +150 Open ASCII Mode Connection.
    +226 Transfer complete.
    +##### bytes received in #.## seconds (##### Kbytes/s)
    +ftp> quit
    +221 Goodbye.
    +
    + +

    Your Linksys print server is now ready for use!

    + + + + diff --git a/doc/help/overview.html b/doc/help/overview.html new file mode 100644 index 000000000..20641e04c --- /dev/null +++ b/doc/help/overview.html @@ -0,0 +1,504 @@ + + + + Overview of CUPS + + + +

    Printing within UNIX has historically been done using one of +two printing systems - the Berkeley Line Printer Daemon (LPD) +[RFC1179] and the AT&T Line Printer system. 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.

    + +

    Replacements for these printing systems have emerged [LPRng, +Palladin, PLP], however none of the replacements change the +fundamental capabilities of these systems.

    + +

    Over the 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.

    + +

    The Internet Printing Protocol defines extensions to the +HyperText Transport Protocol 1.1 [RFC2616] to provide support +for remote printing services. IPP/1.1 was accepted by the IETF +as a proposed standard in ??? of ???. Unlike POSIX Printing, IPP +enjoys widespread industry support and has become the standard +network printing solution for all operating systems.

    + +

    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.

    + +

    History

    + +

    The first production release of CUPS (based on IPP/1.0) was +released in October of 1999. Version 1.1 of CUPS was released in +August of 2002 ???? and added support for IPP/1.1.

    + +

    CUPS 1.2 is based on IPP/1.1 and adds many of the functional +enhancements that have been requested by our users. As with CUPS +1.1, CUPS 1.2 will be followed by patch releases that address +any problems found with the software. New features will be put +in the 1.3 release to follow.

    + +

    Design Overview

    + +

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

    + +

    CUPS Block Diagram
    +Figure 1 - CUPS Block Diagram

    + +

    Scheduler

    + +

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

    + +

    The scheduler also manages a list of available printers on +the LAN and dispatches print jobs as needed using the +appropriate filters and backends.

    + +

    Configuration Files

    + +

    The configuration files consist of:

    + +
      + +
    • The HTTP server configuration file.
    • + +
    • Printer and class definition files.
    • + +
    • MIME type and conversion rule files.
    • + +
    • PostScript Printer Description (PPD) files.
    • + +
    + +

    The HTTP server configuration file is purposely similar to +the Apache server configuration file and defines all of the +access control properties for the server.

    + +

    The printer and class definition files list the available +printer queues and classes. Printer classes are collections of +printers. Jobs sent to a class are forwarded to the first +available printer in the class, round-robin fashion.

    + +

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

    + +

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

    + +

    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 cupsFilter attributes to support +printer drivers.

    + +

    CUPS API

    + +

    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.

    + +

    Berkeley and System V Commands

    + +

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

    + +

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

    + +

    Filters

    + +

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

    + +

    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.

    + +

    The PostScript raster filter is based on the ESP Ghostscript +core. Instead of using the Ghostscript printer drivers, the CUPS +filter uses a generic CUPS 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.

    + +
    Talk about Apple's use of CUPS...
    + +

    CUPS Imaging

    + +

    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.

    + +

    Backends

    + +

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

    + +

    SAMBA version 2.0.6 and higher includes a SMB backend +(smbspool(1)) that can be used for printing to +Windows.

    + +

    Network Printing

    + +

    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.

    + +

    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.

    + +

    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.

    + +

    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!

    + +

    New Features in CUPS 1.2

    + +

    CUPS 1.2 includes many new features and capabilities: + +

      + +
    1. Backends + +
    2. Banner Page Support + +
    3. Digest Authentication + +
    4. Directory Services + +
    5. Directory Structure Changes + +
    6. Documentation + +
    7. Drivers + +
    8. Filters + +
    9. IPP Support + +
    10. Job Persistence + +
    11. LPD Client Support + +
    12. User-Defined Printers and Options + +
    13. Web Administration Interface + +
    + +

    1. Backends

    + +

    CUPS 1.2 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.

    + +

    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.

    + +

    2. Banner Page Support

    + +

    CUPS 1.2 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.

    + +

    3. Digest Authentication

    + +

    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.

    + +

    CUPS 1.2 implements Digest authentication using a special MD5 +password file instead of the UNIX password file. This file is +managed using the new lppasswd command.

    + +

    4. Directory Services

    + +

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

    + +

    5. Directory Structure Changes

    + +

    CUPS 1.2 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.

    + +

    6. Documentation

    + +

    The CUPS 1.2 documentation has gone through many revisions, +including a completely rewritten administrators manual, a new +programmers manual, and an IPP implementation reference +manual.

    + +

    7. Drivers

    + +

    CUPS 1.2 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.

    + +

    8. Filters

    + +

    CUPS 1.2 includes new image, PostScript, PDF, and text +filters. The image filters have been upgraded to support Windows +BMP and Alias PIX files.

    + +

    The PostScript filter is now based off ESP Ghostscript. The +new filter provides much better performance with +higher-resolution printers and supports all Level 3 PostScript +language features.

    + +

    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.

    + +

    The new text filter now supports bidirectional text and can +embed fonts as needed.

    + +

    9. IPP Support

    + +

    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 lp command) and support +for banner pages.

    + +

    10. Job Persistence

    + +

    CUPS 1.2 supports job persistence. This means that jobs are +preserved even after a reboot, a feature that was sorely missing +from CUPS 1.0.

    + +

    In addition, CUPS 1.2 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.

    + +

    11. LPD Client Support

    + +

    By popular request, CUPS 1.2 supports LPD-based clients using +a new mini-daemon that handles LPD requests and passes them on +to the main server.

    + +

    12. User-Defined Printers and Options

    + +

    CUPS 1.2 includes support for user-defined printers and +options via a new lpoptions 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 lpoptions command can also be used to set a +different default printer queue.

    + +

    13. Web Administration Interface

    + +

    CUPS 1.0 provided a simple class, job, and printer monitoring +interface for web browsers. CUPS 1.2 replaces this interface +with an enhanced administration interface that allows you to +add, modify, delete, configure, and control classes, jobs, and +printers.

    + +

    Software Using CUPS

    + +

    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.

    + +

    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:

    + +
    +    http://kups.sourceforge.net
    +
    + +

    The X Printing Panel (XPP) project provides a graphical +printing panel for CUPS and can be found at:

    + +
    +    http://www.phy.uni-bayreuth.de/till/xpp/
    +
    + +

    Numerous other filters, drivers, tutorials, etc. have been +made available on the CUPS Links web page, available at:

    + +
    +    http://www.cups.org/links.php
    +
    + +

    Finally, our own ESP Print Pro software uses CUPS to provide +drivers for thousands of printers and can be found at:

    + +
    +    http://www.easysw.com/printpro
    +
    + +

    Operating Systems Using CUPS

    + +

    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.

    + +

    Summary

    + +

    The Common UNIX Printing System provides a modern printing +interface for UNIX applications that is both flexible and +user-friendly. The software provides System V and Berkeley +compatible command-line interfaces to ensure compatibility with +existing applications. CUPS 1.2 adds many new features that make +it an even better choice for printing under UNIX.

    + +

    Who to Contact

    + +

    For more information on CUPS please contact us at: + +

    +    Attn: CUPS Information
    +    Easy Software Products
    +    44141 Airport View Drive Suite 204
    +    Hollywood, Maryland 20636-3142 USA
    +
    +    +1.301.373.9600
    +
    +    cups-info@cups.org
    +
    + +

    References

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

    Trademarks

    + +

    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.

    + + + diff --git a/doc/help/page_log-reference.html b/doc/help/page_log-reference.html new file mode 100644 index 000000000..f57180f7e --- /dev/null +++ b/doc/help/page_log-reference.html @@ -0,0 +1,53 @@ + + + + page_log + + + +

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

    + +

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

    + +

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

    + +

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

    + +

    The job-id field contains the job number of the page +being printed. Job numbers are reset to 1 whenever the spool +directory (/var/spool/cups) is cleared, so don't +depend on this number being unique!

    + +

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

    + +

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

    + +

    The job-billing field contains a copy of the +job-billing attribute provided with the IPP +Create-Job or Print-Job requests or "-" +if none was provided. + + + diff --git a/doc/help/printers-conf-reference.html b/doc/help/printers-conf-reference.html new file mode 100644 index 000000000..226a766d0 --- /dev/null +++ b/doc/help/printers-conf-reference.html @@ -0,0 +1,581 @@ + + + + printers.conf + + + +

    The CUPS scheduler (cupsd) uses the +/etc/cups/printers.conf file to store the list of +available printers. This file contains only locally defined +printers, not remote printers that are created automatically via +browsing. 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.

    + +

    While the printer configuration file consists of plain text +and can be modified using your favorite text editor, you should +normally use the lpadmin(8) command, web interface, +or any of the available GUIs to manage your printers instead. If +you do choose to edit this file manually, you will need to +restart the scheduler to make them active.

    + + +

    Accepting

    + +

    Examples

    + +
    +Accepting yes
    +Accepting no
    +
    + +

    Description

    + +

    The Accepting directive defines the initial state +of the printer-is-accepting-jobs attribute. This state +is also set by the accept(8) and +reject(8) commands:

    + +
    +/usr/sbin/accept printername
    +/usr/sbin/reject printername
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    AllowUser

    + +

    Examples

    + +
    +AllowUser foo_user
    +AllowUser @bar_group
    +
    + +

    Description

    + +

    The AllowUser directive adds a username or group +name to the requesting-user-name-allowed attribute +which can be set by the lpadmin(8) command:

    + +
    +/usr/sbin/lpadmin -p printername -u allow:foo_user,@bar_group
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter directive. +This directive cannot be used with DenyUser.

    + + +

    DefaultPrinter

    + +

    Examples

    + +
    +<DefaultPrinter name>
    +...
    +</Printer>
    +
    + +

    Description

    + +

    The DefaultPrinter directive begins a printer +definition as the default server destination. The default server +destination can be set using the lpadmin(8) +command:

    + +
    +/usr/sbin/lpadmin -d printername
    +
    + +

    Note that the server default destination settings can be +overridden by the user's default destination settings which are +normally set using the lpoptions(1) command.

    + + +

    DenyUser

    + +

    Examples

    + +
    +DenyUser foo_user
    +DenyUser @bar_group
    +
    + +

    Description

    + +

    The DenyUser directive adds a username or group +name to the requesting-user-name-denied attribute +which can be set by the lpadmin(8) command:

    + +
    +/usr/sbin/lpadmin -p printername -u deny:foo_user,@bar_group
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter directive. +This directive cannot be used with AllowUser

    + + +

    DeviceURI

    + +

    Examples

    + +
    +DeviceURI socket://foo.bar.com:9100
    +
    + +

    Description

    + +

    The DeviceURI directive defines the value of the +device-uri-attribute attribute. It is normally set +using the lpadmin(8) command:

    + +
    +/usr/sbin/lpadmin -p printername -v device-uri
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    CUPS 1.2ErrorPolicy

    + +

    Examples

    + +
    +ErrorPolicy cancel-job
    +ErrorPolicy retry-job
    +ErrorPolicy stop-printer
    +
    + +

    Description

    + +

    The ErrorPolicy directive defines the policy that +is used when a backend is unable to send a print job to the +printer. The lpadmin(8) command sets the current +error policy:

    + +
    +/usr/sbin/lpadmin -p printername -o printer-error-policy=stop-printer
    +
    + +

    The following values are supported:

    + +
      + +
    • cancel-job - Cancel the job and proceed + with the next job in the queue
    • + +
    • retry-job - Retry the job after waiting + for N seconds; the cupsd.conf JobRetryInterval + directive controls the value of N
    • + +
    • stop-printer - Stop the printer and keep + the job for future printing; this is the default + value
    • + +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    Info

    + +

    Examples

    + +
    +Info My Printer
    +
    + +

    Description

    + +

    The Info directive defines the string for the +printer-info attribute. It is normally set using the +lpadmin(8) command:

    + +
    +/usr/sbin/lpadmin -p printername -D "My Printer"
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    JobSheets

    + +

    Examples

    + +
    +JobSheets none,standard
    +
    + +

    Description

    + +

    The JobSheets directive specifies the default +banner pages to print before and after a print job. In the above +example, only a standard banner will print after each +job. The lpadmin(8) command is normally used to set +the default banners: + +

    +/usr/sbin/lpadmin -p printername -o job-sheets-default=none,standard
    +
    + +

    If only one banner file is specified, it will be printed +before the files in the job. If a second banner file is +specified, it is printed after the files in the job.

    + +

    The available banner pages depend on the local system +configuration; CUPS includes the following standard banner +files:

    + +
      + +
    • none - Do not produce a banner + page.
    • + +
    • classified - A banner page with a + "classified" label at the top and bottom.
    • + +
    • confidential - A banner page with a + "confidential" label at the top and bottom.
    • + +
    • secret - A banner page with a + "secret" label at the top and bottom.
    • + +
    • standard - A banner page with no label + at the top and bottom.
    • + +
    • topsecret - A banner page with a + "top secret" label at the top and bottom.
    • + +
    • unclassified - A banner page with an + "unclassified" label at the top and bottom.
    • + +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    KLimit

    + +

    Examples

    + +
    +KLimit 1234
    +
    + +

    Description

    + +

    The KLimit directive defines the value of the +job-k-limit attribute. It is normally set using the +lpadmin(8) command:

    + +
    +/usr/sbin/lpadmin -p printername -o job-k-limit=1234
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    Location

    + +

    Examples

    + +
    +Location Building 3321
    +
    + +

    Description

    + +

    The Location directive defines the string for the +printer-location attribute. It is normally set using the +lpadmin(8) command:

    + +
    +/usr/sbin/lpadmin -p printername -L "Building 3321"
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    CUPS 1.2OpPolicy

    + +

    Examples

    + +
    +OpPolicy default
    +OpPolicy mypolicy
    +
    + +

    Description

    + +

    The OpPolicy directive sets the operation policy +that is used for the printer. The lpadmin(8) command +sets the current operation policy:

    + +
    +/usr/sbin/lpadmin -p printername -o printer-op-policy=default
    +
    + +

    The default policy is named "default". All policies correspond +to those defined using the cupsd.conf Policy +directive.

    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    PageLimit

    + +

    Examples

    + +
    +PageLimit 1234
    +
    + +

    Description

    + +

    The PageLimit directive defines the value of the +job-page-limit attribute. It can be set using the +lpadmin(8) command:

    + +
    +/usr/sbin/lpadmin -p printername -o job-page-limit=1234
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    CUPS 1.2PortMonitor

    + +

    Examples

    + +
    +PortMonitor bcp
    +PortMonitor none
    +PortMonitor tbcp
    +
    + +

    Description

    + +

    The PortMonitor directive sets the filter program that +is used for every print job, typically to encode or package the print +data in a format acceptable for a particular printer interface. It is +set using the lpadmin(8) command:

    + +
    +/usr/sbin/lpadmin -p printername -o port-monitor=tbcp
    +
    + +

    The following standard port monitors are included with CUPS:

    + +
      + +
    • bcp - Encode PostScript print data using + the Adobe Binary Control Protocol (BCP)
    • + +
    • none - Do not use a port monitor
    • + +
    • tbcp - Encode PostScript print data + using the Adobe Tagged Binary Control Protocol + (TBCP)
    • + +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    Printer

    + +

    Examples

    + +
    +<Printer name>
    +...
    +</Printer>
    +
    + +

    Description

    + +

    The Printer directive begins a printer +definition. Printers are added using the lpadmin(8) +command: + +

    +/usr/sbin/lpadmin -p printername ...
    +
    + + +

    QuotaPeriod

    + +

    Examples

    + +
    +QuotaPeriod 604800
    +
    + +

    Description

    + +

    The QuotaPeriod directive defines the value of +the job-quota-period attribute. Typical values are +86400 (1 day), 604800 (1 week), 2592000 (1 month), and 31536000 +(1 year). It is set using the lpadmin(8) +command:

    + +
    +/usr/sbin/lpadmin -p printername -o job-quota-period=604800
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    CUPS 1.2Shared

    + +

    Examples

    + +
    +Shared yes
    +Shared no
    +
    + +

    Description

    + +

    The Shared directive defines the initial value of +the printer-is-shared attribute. The strings +yes and no correspond to the true and false +values, respectively. The lpadmin(8) command sets +the current state:

    + +
    +/usr/sbin/lpadmin -p printername -o printer-is-shared=true
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    State

    + +

    Examples

    + +
    +State idle
    +State stopped
    +
    + +

    Description

    + +

    The State directive defines the initial value of +the printer-state attribute. The strings +idle and stopped correspond to the IPP +enumeration values 3 and 5, respectively. The +cupsenable(8) and cupsdisable(8) +commands set the current state:

    + +
    +/usr/sbin/cupsenable printername
    +/usr/sbin/cupsdisable printername
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    StateMessage

    + +

    Examples

    + +
    +StateMessage Ready to print.
    +
    + +

    Description

    + +

    The StateMessage directive defines the initial +string for the printer-state-message attribute. The +following are some example messages:

    + +
    +StateMessage Connected to host_name...
    +StateMessage Connecting to printer_queue on port port_number...
    +StateMessage Network host host_name is busy; will retry in 30 seconds...
    +StateMessage Printer busy; will retry in 10 seconds...
    +StateMessage Printer is busy; retrying print job...
    +StateMessage Print file accepted - job ID id_number.
    +StateMessage Ready to print.
    +StateMessage Waiting for job to complete
    +
    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + +

    CUPS 1.2StateTime

    + +

    Examples

    + +
    +StateTime 1133542425
    +
    + +

    Description

    + +

    The StateTime directive defines the UNIX time +(seconds since Jan 1, 1970) for the last state change of the +queue. It is mapped to the printer-state-change-time +attribute.

    + +

    This directive must appear inside a Printer or DefaultPrinter +directive.

    + + + + diff --git a/doc/help/spec-ppd.html b/doc/help/spec-ppd.html new file mode 100644 index 000000000..a6aa4677e --- /dev/null +++ b/doc/help/spec-ppd.html @@ -0,0 +1,472 @@ + + + + + CUPS PPD Extensions + + + + + +

    Introduction

    + +

    This specification describes the attributes and extensions +that CUPS adds to +Adobe TechNote #5003: PostScript Printer Description File Format +Specification Version 4.3. PostScript Printer Description +("PPD") files describe the capabilities of each printer and are +used by CUPS to support printer-specific features and intelligent +filtering.

    + +

    PPD File Syntax

    + +

    The PPD format is text-based and uses lines of up to 255 +characters terminated by a carriage return, linefeed, or +combination of carriage return and line feed. The following ABNF +definition [RFC2234] defines the general format of lines in a PPD +file:

    + +
    +PPD-FILE = HEADER +(DATA / COMMENT / LINE-END)
    +
    +HEADER   = "*" 0x50.50.44.2D.41.64.6F.62.65 ":"   ; *PPD-Adobe:
    +           *WSP DQUOTE "4.3" DQUOTE LINE-END
    +
    +COMMENT  = "*%" *TCHAR LINE-END
    +
    +DATA     = "*" 1*KCHAR [ WSP 1*KCHAR [ "/" 1*TCHAR ] ] ":"
    +           1*(*WSP VALUE) LINE-END
    +
    +VALUE    = 1*TCHAR / DQUOTE 1*SCHAR DQUOTE
    +
    +KCHAR    = ALPHA / DIGIT / "_" / "." / "-"
    +
    +SCHAR    = LINE-END / WSP / %x21 / %x23-7E / %xA0-FF
    +
    +TCHAR    = %x20-7E / %xA0-FF
    +
    +LINE-END = CR / LF / CR LF
    +
    + + +

    General Attributes

    + +

    cupsFilter

    + +

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

    + +
    +source/type cost program
    +
    + +

    The destination type is assumed to the printer's type. If a +printer supports the source type directly, the special filter +program "-" may be specified.

    + +

    Examples:

    + +
    +*% Standard raster printer driver filter 
    +*cupsFilter: "application/vnd.cups-raster 100 rastertofoo"
    +
    +*% Plain text filter 
    +*cupsFilter: "text/plain 10 texttofoo"
    +
    +*% Pass-through filter for PostScript printers 
    +*cupsFilter: "application/vnd.cups-postscript 0 -"
    +
    + +

    cupsFlipDuplex

    + +

    This boolean attribute notifies the RIP filters that the +destination printer requires an upside-down image for the back +page. The default value is false.

    + +

    Example:

    + +
    +*% Flip the page image for the back side of duplexed output 
    +*cupsFlipDuplex: true
    +
    + +

    cupsManualCopies

    + +

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

    + +

    Example:

    + +
    +*% Tell the RIP filters to generate the copies for us 
    +*cupsManualCopies: true
    +
    + +

    cupsModelNumber

    + +

    This integer attribute specifies a printer-specific model +number. This number can be used by a filter program to adjust +the output for a specific model of printer.

    + +

    Example:

    + +
    +*% Specify an integer for a driver-specific model number 
    +*cupsModelNumber: 1234
    +
    + +

    cupsPortMonitor

    + +

    This string attribute specifies printer-specific "port +monitor" filters that may be used with the printer. The CUPS +scheduler also looks for the Protocols attribute to see +if the BCP or TBCP protocols are supported. If +so, the corresponding port monitor ("bcp" and "tbcp", +respectively) is listed in the printer's +port-monitor-supported attribute.

    + +

    Examples:

    + +
    +*% Specify a PostScript printer that supports the TBCP protocol
    +*Protocols: TBCP PJL
    +
    +*% Specify a printer-specific port monitor for an Epson USB printer 
    +*cupsPortMonitor epson-usb/USB Status Monitor: "epson-usb"
    +
    + +

    cupsVersion

    + +

    This required attribute describes which version of the CUPS +PPD file extensions was used. Currently it must be the string +"1.0", "1.1", or "1.2".

    + +

    Example:

    + +
    +*% Specify a CUPS 1.2 driver 
    +*cupsVersion: "1.2"
    +
    + + +

    Custom Options

    + +

    CUPS supports custom options using an extension of the +CustomPageSize and ParamCustomPageSize +syntax:

    + +
    +*CustomFoo True: "command"
    +*ParamCustomFoo Name1/Text 1: order type minimum maximum
    +*ParamCustomFoo Name2/Text 2: order type minimum maximum
    +...
    +*ParamCustomFoo NameN/Text N: order type minimum maximum
    +
    + +

    When the base option is part of the JCLSetup section, +the "command" string contains JCL commands with "\order" +placeholders for each numbered parameter. The CUPS API handles +any necessary value quoting for HP-PJL commands.

    + +

    For non-JCLSetup options, the "order" value is a +number from 1 to N and specifies the order of values as they are +placed on the stack before the command.

    + +

    The "type" is one of the following keywords:

    + +
      + +
    • curve - a real value from "minimum" to + "maximum" representing a gamma correction curve using the + function: f(x) = x value
    • + +
    • int - an integer value from "minimum" to + "maximum"
    • + +
    • invcurve - a real value from "minimum" to + "maximum" representing a gamma correction curve using the + function: f(x) = x 1 / value
    • + +
    • passcode - a string of numbers value with a + minimum of "minimum" numbers and a maximum of "maximum" + numbers (passcode strings are not displayed in the user + interface)
    • + +
    • password - a string value with a minimum of + "minimum" characters and a maximum of "maximum" + characters (password strings are not displayed in the + user interface)
    • + +
    • points - a measurement value in points from + "minimum" to "maximum"
    • + +
    • real - a real value from "minimum" to + "maximum"
    • + +
    • string - a string value with a minimum of + "minimum" characters and a maximum of "maximum" + characters
    • + +
    + +

    Examples:

    + +
    +*% Base JCL key code option 
    +*OpenUI JCLPasscode/Key Code: PickOne
    +*OrderDependency: 10 JCLSetup *JCLPasscode
    +*DefaultJCLPasscode: None
    +*JCLPasscode None/No Code: ""
    +*JCLPasscode 1111: "@PJL SET PASSCODE = 1111<0A>"
    +*JCLPasscode 2222: "@PJL SET PASSCODE = 2222<0A>"
    +*JCLPasscode 3333: "@PJL SET PASSCODE = 3333<0A>"
    +*JCLCloseUI: *JCLPasscode
    +
    +*% Custom JCL key code option 
    +*CustomJCLPasscode True: "@PJL SET PASSCODE = \1<0A>"
    +*ParamCustomJCLPasscode Code/Key Code: 1 passcode 4 4
    +
    +
    +*% Base PostScript gamma/density option 
    +*OpenUI GammaDensity/Gamma and Density: PickOne
    +*OrderDependency: 10 AnySetup *GammaDensity
    +*DefaultGammaDensity: Normal
    +*GammaDensity Normal/Normal: "<</cupsReal1 1.0/cupsReal2 1.0>>setpagedevice"
    +*GammaDensity Light/Lighter: "<</cupsReal1 0.9/cupsReal2 0.67>>setpagedevice"
    +*GammaDensity Dark/Darker: "<</cupsReal1 1.1/cupsReal2 1.5>>setpagedevice"
    +*JCLCloseUI: *GammaDensity
    +
    +*% Custom PostScript gamma/density option 
    +*CustomGammaDensity True: "<</cupsReal1 3 1 roll/cupsReal2 3 1>>setpagedevice"
    +*ParamCustomGammaDensity Gamma: 1 curve 0.1 10
    +*ParamCustomGammaDensity Density: 2 real 0 2
    +
    + + +

    Color Profiles

    + +

    cupsColorProfile

    + +

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

    + +
    +*cupsColorProfile Resolution/MediaType: "density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"
    +
    + +

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

    + +

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

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

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

    + +
    +| m00 m01 m02 |
    +| m10 m11 m12 |
    +| m20 m21 m22 |
    +
    + +

    Examples:

    + +
    +*% Specify a profile for printing at 360dpi on all media types 
    +*cupsColorProfile 360dpi/-: "1.0 1.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
    +
    +*% Specify a profile for printing at 720dpi on Glossy media 
    +*cupsColorProfile 720dpi/Glossy: "1.0 2.5 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
    +
    +*% Specify a default profile for printing at all other resolutions and media types 
    +*cupsColorProfile -/-: "0.9 2.0 1.0 0.0 -0.2 -0.4 1.0 0.0 -0.2 0.0 1.0"
    +
    + +

    cupsICCProfile

    + +

    This attribute specifies an ICC color profile of the +form:

    + +
    +*cupsICCProfile ColorModel.MediaType.Resolution/Description: "filename"
    +
    + +

    The ColorModel, MediaType, and +Resolution keywords specify a selector for color +profiles. If omitted, the color profile will match any option +keyword for the corresponding main keyword.

    + +

    The Description specifies human-readable text that +is associated with the color profile. The filename +portion specifies the ICC color profile to use; if the filename +is not absolute, it is loaded relative to the +/usr/share/cups/profiles directory.

    + +

    Examples:

    + +
    +*% Specify a profile for CMYK printing at 360dpi on all media types 
    +*cupsICCProfile CMYK..360dpi/360dpi CMYK: "vendor/foo-360-cmyk.icc"
    +
    +*% Specify a profile for RGB printing at 720dpi on Glossy media 
    +*cupsColorProfile RGB.Glossy.720dpi/720dpi Glossy: "vendor/foo-720-glossy-rgb.icc"
    +
    +*% Specify a default profile for printing at all other resolutions and media types 
    +*cupsICCProfile .../Default: "vendor/foo-default.icc"
    +
    + +

    Customizing the Profile Selection Keywords

    + +

    The ColorModel, MediaType, and +Resolution keywords can be reassigned to different main +keywords, allowing drivers to do color profile selection based +on different parameters. The cupsICCQualifier1, +cupsICCQualifier2, and cupsICCQualifier3 +attributes define the mapping from selector to main keyword:

    + +
    +*cupsICCQualifier1: MainKeyword
    +*cupsICCQualifier2: MainKeyword
    +*cupsICCQualifier3: MainKeyword
    +
    + +

    The default mapping is as follows:

    + +
    +*cupsICCQualifier1: ColorModel
    +*cupsICCQualifier2: MediaType
    +*cupsICCQualifier3: Resolution
    +
    + + +

    I18N Support

    + +

    CUPS 1.2 and higher adds support for PPD files containing multiple +languages by following the following rules:

    + +
      + +
    1. The LanguageVersion is English
    2. + +
    3. The LanguageEncoding is ISOLatin1
    4. + +
    5. Main and option keywords may not exceed 34 + characters, which is a subset of what the Adobe PPD spec + allows.
    6. + +
    7. Translations are specified using a locale prefix of + the form "ll" or "ll_CC." where "ll" is the 2-letter ISO + language code and "CC" is the 2-letter ISO country + code
    8. + +
    9. Translation strings are encoded using UTF-8.
    10. + +
    11. Main keywords are translated using any of the + following forms: +

      *ll.Translation MainKeyword/translation + text: ""
      + *ll_CC.Translation MainKeyword/translation + text: ""

    12. + +
    13. Option keywords are translated using any of the + following forms: +

      *ll.MainKeyword OptionKeyword/translation + text: ""
      + *ll_CC.MainKeyword OptionKeyword/translation + text: ""

    14. + +
    + +

    Examples:

    + + +
    +*LanguageVersion: English
    +*LanguageEncoding: ISOLatin1
    +*ModelName: "Foobar Laser 9999"
    +
    +*% Localize for French and German
    +*fr_FR.Translation ModelName/La Foobar Laser 9999: ""
    +*de_DE.Translation ModelName/Foobar LaserDrucken 9999: ""
    +
    +...
    +
    +*OpenUI *InputSlot/Paper Source: PickOne
    +*OrderDependency: 10 AnySetup *InputSlot
    +*DefaultInputSlot: Auto
    +*% Localize for French and German
    +*fr_FR.Translation InputSlot/Papier source: ""
    +*de_DE.Translation InputSlot/Papiereinzug: ""
    +*InputSlot Auto/Default: "<</ManualFeed false>>setpagedevice"
    +*% Localize for French and German
    +*fr_FR.InputSlot Auto/Par Defaut: ""
    +*de_DE.InputSlot Auto/Standard: ""
    +*InputSlot Manual/Manual Feed: "<</ManualFeed true>>setpagedevice"
    +*% Localize for French and German
    +*fr_FR.InputSlot Manual/Manuel mecanisme de alimentation: ""
    +*de_DE.InputSlot Manual/Manueller Einzug: ""
    +*CloseUI: *InputSlot
    +
    + + +

    Change History

    + +

    Changes in CUPS 1.2

    + +
      + +
    • Added I18N support attributes
    • + +
    • Added custom option values support
    • + +
    • Added cupsICCProfile attribute
    • + +
    • Added cupsPortMonitor attribute
    • + +
    • Removed cupsProtocol attribute
    • + +
    + +

    Changes in CUPS 1.1

    + +
      + +
    • Added cupsFlipDuplex attribute
    • + +
    • Added cupsProtocol attribute
    • + +
    + + + diff --git a/doc/help/standard.html.in b/doc/help/standard.html.in new file mode 100644 index 000000000..cbfa9d328 --- /dev/null +++ b/doc/help/standard.html.in @@ -0,0 +1,128 @@ + + + + Standard Configuration + + + +

    This document describes the standard configuration for this CUPS +server.

    + +
    Note: + + +

    This file reflects the standard CUPS configuration as distributed +by Easy Software Products, the creator of CUPS.

    + +
    + + +

    cupsd Configuration

    + +

    cupsd(8) is configured by default to show +printers shared by other systems and only allow local access to +the system and its printers. Administration operations require +Basic authentication with membership in the group +"@CUPS_GROUP@".

    + +

    Connections are accepted via domain socket +(@CUPS_DEFAULT_DOMAINSOCKET@) or "localhost" +(127.0.0.1).

    + + +

    Directories

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectoryPurpose
    @CUPS_SERVERROOT@The location of configuration files such as + printers.conf. Overridden by the ServerRoot + directive in cupsd.conf.
    @bindir@The location of user programs.
    @includedir@The location of CUPS include files.
    @libdir@The location of CUPS library files.
    @CUPS_SERVERBIN@The location of server programs such as backends and + filters. Overridden by the ServerBin + directive in cupsd.conf.
    @sbindir@The location of administrator programs.
    @CUPS_DATADIR@The location of data files such as fonts. Overridden + by the DataDir + directive in cupsd.conf.
    @CUPS_DOCROOT@The location of documentation files. Overridden by + the DocumentRoot + directive in cupsd.conf.
    @CUPS_LOCALEDIR@The location of localization files.
    @CUPS_CACHEDIR@The location of cache files such as + ppds.dat and remote.cache. + Overridden by the CacheDir + directive in cupsd.conf.
    @CUPS_LOGDIR@The location of the access_log, + error_log, and page_log files. + Overridden by the AccessLog, + ErrorLog, + PageLog, + directive in cupsd.conf.
    @CUPS_STATEDIR@The location of the domain socket file and state data + such as authentication certificates. Overridden by the StateDir + directive in cupsd.conf.
    @CUPS_REQUESTS@The location of spooled print jobs. Overridden by the + RequestRoot + directive in cupsd.conf.
    + + + + diff --git a/doc/help/subscriptions-conf-reference.html b/doc/help/subscriptions-conf-reference.html new file mode 100644 index 000000000..270043d67 --- /dev/null +++ b/doc/help/subscriptions-conf-reference.html @@ -0,0 +1,81 @@ + + + + subscriptions.conf + + + +

    The CUPS scheduler (cupsd) uses the /etc/cups/subscriptions.conf file +to store the list of active subscriptions. This file contains only locally defined +classes, but not remote or implicit classes that are created automatically. +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 classes configuration file consists of plain text, you can +use your favorite text editor to make changes to it. + +

    The subscription.conf file contains many directives that +determine how the subscriptions behave:

    + +

    + + + + + + + + +
    + +
  • Accepting +
  • AllowUser +
  • Class +
  • DefaultClass +
  • DenyUser + +
  • +    + + +
  • Info +
  • JobSheets +
  • KLimit +
  • Location +
  • PageLimit + +
  • +    + + +
  • Printer +
  • QuotaPeriod +
  • State +
  • StateMessage + +
  • +

    + + +

    Accepting

    +
    + +

    Examples

    + +
      +Accepting yes
      +
      +Accepting no
      +
    + +

    Description

    + +

    The Accepting directive defines the initial Boolean +value for the printer-is-accepting-job attribute which can +be set by the accept and reject commands. + +

    This directive must appear inside a Class +or DefaultClass directive. + + + diff --git a/doc/help/whatsnew.html b/doc/help/whatsnew.html new file mode 100644 index 000000000..864ec23ff --- /dev/null +++ b/doc/help/whatsnew.html @@ -0,0 +1,188 @@ + + + + What's New in CUPS 1.2 + + + +

    This document describes the new features in CUPS 1.2. If you +have never used CUPS before, read the "Overview of CUPS" document instead. +CUPS 1.2 adds many new features to CUPS 1.1.x:

    + + + + +

    Networking

    + +<-- +1. Networking + a. IPv6 + i. Next-generation Internet support + ii. ???? + b. Domain sockets + i. Enhanced performance under load for local clients. + ii. Authentication without passwords on platforms that support it. +--> + +

    CUPS 1.2 adds support for IPv6 and domain sockets. The IPv6 +support allows CUPS to work with the next-generation Internet as +well as taking advantage of automatic local network +configuration. Domain sockets provide 5 to 10 times faster +printing from the desktop.

    + + +

    Printer Browsing

    + +<-- +2. Printer Browsing + a. CUPS browsing updates + i. "Delete" bit for printers + ii. "lease-time" for printers so that clients and servers don't need + the same browse timeout/interval settings + iii. Additional attributes/default options for network-wide defaults + iv. Network default printer + v. Ability to control send and receive protocols independently + b. Rendevous support + c. LDAP support + d. Per-printer sharing +--> + +

    CUPS 1.2 adds support for Bonjour/mDNS and LDAP-based printer +sharing. Printers can be shared or "published" individually, +allowing a server to only share specific printers, and you can +set which protocols to use for local and remote printers. +Previously CUPS would share all or none of its printers and use +the same protocols for local and remote printers.

    + +

    CUPS Browse Protocol

    + +

    The CUPS browse protocol has also been upgraded. New type +bits, authenticated, default, and deleted, provide key +information to clients. The "authenticated" type bit tells +clients that the print queue requires authentication when +printing. The "default" type bit tells clients that the print +queue should be used as the default unless the user sets a +different one. The "deleted" type bit is set when a printer is +deleted from the server - this allows the client to remove its +copy of a printer immediately rather than waiting for it to +timeout.

    + +

    Previously, a change to the BrowseTimeout setting on the +server had to be mirrored to each client. Browse packets now +include printer lease time information which allows the server to +use a different timeout setting than its clients, making +configuration simpler and more reliable.

    + +

    Browse packets can also now contain connection options to be +used when printing to the server. This allows the administrator +to require encryption or compress print jobs for certain +printers. This is most often used when printing over +limited-bandwidth WAN connections.

    + + +

    Web Interface

    + + + +

    The web interface features an all-new administration interface +which provides ...

    + + +

    IPP Support

    + + + + +

    Scheduler

    + + + + +

    Localization and Internationalization

    + + + + +

    Printer Drivers

    + + + + +

    CUPS API

    + + + + +

    CUPS Imaging API

    + + + + + diff --git a/doc/idd.html b/doc/idd.html new file mode 100644 index 000000000..dc52454ee --- /dev/null +++ b/doc/idd.html @@ -0,0 +1,1083 @@ + + + +CUPS Interface Design Description + + + + + + + +

    +

    CUPS Interface Design Description


    +CUPS-IDD-1.2
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

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

    1 Scope

    +

    1.1 Identification

    +

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

    +

    1.2 System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    +

    1.3 Document Overview

    +

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

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

    2 References

    +

    2.1 CUPS Documentation

    +

    The following CUPS documentation is referenced by this document:

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

    2.2 Other Documents

    +

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

    + +

    3 Internal Interfaces

    +

    3.1 Character Set Files

    +

    The character set files define a mapping between 8-bit characters and + the Unicode character set, or between Unicode and printer fonts. They + are named using the IETF charset names defined in RFCnnnn. These files + are ASCII text, the content of which is described below. Comments can + be included by using the # character in the first column of a + line.

    +

    3.1.1 8-Bit Character Set Files

    +

    8-bit character set files start with a line reading:

    +
      +
      +charset 8bit
      +
      +
    +

    Following this are lines that define the font information:

    +
      +
      +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", "rtol", or "rtola" + indicating left-to-right, right-to-left, or right-to-left Arabic text.

    +

    Width is the string "single" or "double"; double means + that the glyphs are twice as wide as ASCII characters in the Courier + typeface.

    +

    Normal, bold, italic, and bold-italic are the + typefaces to use for each presentation. If characters are only + available in a single style then only one typeface should be listed + (e.g. "Symbol".) Each font that is listed will be used (and downloaded + if needed) when printing.

    +

    The remaining lines define a character to Unicode glyph mapping for + the character set. The character and glyph values are hexadecimal:

    +
      +
      +xx yyyy
      +
      +
    +

    3.1.2 Unicode Character Set Files

    +

    Unicode character set files start with a line reading:

    +
      +
      +charset encoding
      +
      +
    +

    Encoding is the encoding to use for the text; currently + only the string "utf8" is supported.

    +

    Following this are lines defining the font information:

    +
      +
      +first 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", "rtol", or "rtola" + indicating left-to-right, right-to-left, or right-to-left Arabic text.

    +

    Width is the string "single" or "double"; double means + that the glyphs are twice as wide as ASCII characters in the Courier + typeface.

    +

    Normal, bold, italic, and bold-italic are the + typefaces to use for each presentation. If characters are only + available in a single style then only one typeface should be listed + (e.g. "Symbol".) Each font that is listed will be used (and downloaded + if needed) when printing.

    +

    3.2 Language Files

    +

    The language files define the default character set and a collection + of text messages in that language. They are named by prefixing the + string "cups_" to the front of the language specifier (e.g. "cups_en", + "cups_fr", etc.) Each file consists of two or more lines of ASCII text.

    +

    The first line identifies the character set to be used for the + messages. The currently recognized values are:

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

    The second and succeeding lines define text messages. If the message + text is preceded by a number, then the current message number is + updated and the text after the number is used.

    +

    3.3 MIME Files

    +

    CUPS uses two MIME files in its standard configuration.

    +

    3.3.1 mime.types

    +

    The mime.types file defines the recognized file types and consists of + 1 or more lines of ASCII text. Comment lines start with the pound ("#") + character. The backslash ("\") character can be used at the end of a + line to continue that line to the next.

    +

    Each non-blank line starts with a MIME type identifier ("super/type") + as registered with the IANA. All text following the MIME type is + treated as a series of type recognition rules:

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

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

    +

    3.3.2 mime.convs

    +

    The mime.types file defines the recognized file filters and consists + of 1 or more lines of ASCII text. Comment lines start with the pound + ("#") character.

    +

    Each non-blank line starts with two MIME type identifiers + ("super/type") representing the source and destination types. Following + the MIME types are a cost value (0 to 100) and the filter program to + use. If the filter program is not specified using the full path then it + must reside in the CUPS filter directory:

    +
      +
      +super/type SP super/type2 SP cost SP program
      +
      +
    +

    3.4 Option Files

    +

    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 (/etc/cups/lpoptions) are loaded first, + followed by the user option file ($HOME/.lpoptions). + Options in the user file replace those defined in the system file for + the same destination. Each line in the files can be one of the + following:

    +
      +
      +Dest name option=value option=value ... option=value
      +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
      +
      +
    +

    The line beginning with "Default" indicates the default destination + for print jobs; a default line in the user option file overrides the + default defined in the system option file.

    +

    Name is the name of a printer known to the local server.

    +

    Instance can be any string of letters, numbers, and the + underscore up to 127 characters in length.

    +

    The remainder of the line contains a list of space-separated options + and their values.

    +

    3.5 PostScript Printer Description Files

    +

    PostScript Printer Description ("PPD") files describe the + capabilities of each printer and are used by CUPS to support + printer-specific features and intelligent filtering.

    +

    3.5.1 PPD Specification

    +

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

    +

    3.5.2 CUPS Extensions to PPD Files

    +

    CUPS adds several new attributes that are described below.

    +

    3.5.2.1 cupsFilter

    +

    This string attribute provides a conversion rule of the form:

    +
      +
      +source/type cost program
      +
      +
    +

    The destination type is assumed to the printer's type. If a printer + supports the source type directly the special filter program "-" may be + specified.

    +

    3.5.2.2 cupsManualCopies

    +

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

    +

    3.5.2.3 cupsModelNumber

    +

    This integer attribute specifies a printer-specific model number. + This number can be used by a filter program to adjust the output for a + specific model of printer.

    +

    3.5.2.4 cupsProfile

    +

    This string attribute specifies a color profile of the form:

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

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

    +

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

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

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

    +

    3.5.2.5 cupsVersion

    +

    This required attribute describes which version of the CUPS IDD was + used for the PPD file extensions. Currently it must be the string + "1.0", "1.1", or "1.2".

    +

    3.6 Scheduler Configuration Files

    +

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

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

    3.6.1 classes.conf

    +

    The classes.conf file consists of 1 or more lines of ASCII text. + Comment lines start with the pound ("#") character.

    +

    Each non-blank line starts with the name of a configuration directive + followed by its value. The following directives are understood: +

    + + + + + + + + + + + + + + +
    DirectiveDescription
    <Class name> +
    </Class>
    Surrounds a class definition.
    <DefaultClass name> +
    </Class>
    Surrounds a class definition for the default + destination.
    AcceptingSpecifies whether the class is accepting new + jobs. May be the names "Yes" or "No".
    AllowUsersSpecifies a list of users that are allowed to + access the class.
    BannerStartSpecifies the banner that is printed before + other files in a job.
    BannerEndSpecifies the banner that is printed after + other files in a job.
    DenyUsersSpecifies a list of users that are not allowed + to access the class.
    InfoA textual description of the class.
    LocationA textual location of the class.
    PrinterSpecifies a printer that is a member of the + class.
    StateSpecifies the initial state of the class; can be + "Idle" or "Stopped".
    StateMessageSpecifies a textual message for the current + class state.
    +
    +

    +

    3.6.2 cupsd.conf

    +

    The cupsd.conf file consists of 1 or more lines of ASCII text. + Comment lines start with the pound ("#") character.

    +

    Each non-blank line starts with the name of a configuration directive + followed by its value. The following directives are understood: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectiveDefaultDescription
    AccessLogaccess_logSpecifies the location of + the access log file. The special name "syslog" can be used to send + access log information to the system log.
    Allow-Allows connections from the specified + host, network, or domain.
    AuthClass-Specifies what level of + authentication is required; may be "User", "System", or "Group".
    AuthTypeNoneSpecifies the type of + authentication to perform; may be "None", "Basic", or "Digest".
    BrowseAddress255.255.255.255Specifies a + broadcast address to send CUPS browsing packets to.
    BrowseAllow-Specifies hosts or addresses from + which browsing information should be used.
    BrowseDeny-Specifies hosts or addresses from + which browsing information should not be used.
    BrowseInterval30Specifies the number of + seconds between browsing updates. A browse interval of 0 seconds + disables outgoing packets.
    BrowseOrderAllow,DenySpecifies the order of + BrowseAllow and BrowseDeny directive processing; can be "Deny,Allow" to + implicitly deny hosts unless they are allowed by a BrowseAllow line, or + "Allow,Deny" to implicitly allow hosts unless they are denied by a + BrowseDeny line.
    BrowsePoll-Specifies a server to poll for + available printers and classes.
    BrowsePort631Specifies the UDP port number to + use for browse packets.
    BrowseRelay-Specifies a source and destination + address for relaying browser information from one subnet to another.
    BrowseShortNamesyesSpecifies whether or not to + provide short names (without the "@server" part) for remote printers.
    BrowseTimeout300Specifies the number of + seconds to wait until remote destinations are removed from the local + destination list.
    BrowsingOnSpecifies whether or not printer and + class browsing is enabled; can be "On" or "Off".
    DataDir/usr/share/cupsSpecifies the directory + where CUPS data files are stored.
    DefaultCharsetiso-8859-1Specifies the default + character set.
    DefaultLanguagecurrent localeSpecifies the + default language.
    Deny-Refuses connections from the specified + host, network, or domain.
    DocumentRoot/usr/share/doc/cupsSpecifies the + document data root directory.
    ErrorLogerror_logSpecifies the error log file + location. The special name "syslog" can be used to send error log + information to the system log.
    Grouproot, sys, systemSpecifies the group name + or ID that is used when running external programs.
    HostNameLookupsOffSpecifies whether or not to + perform reverse IP address lookups to get the actual hostname; may be + "On" or "Off". Hostname lookups can significantly degrade the + performance of the CUPS server if one or more DNS servers is not + functioning properly.
    ImplicitClassesOnSpecifies whether or not to + automatically create printer classes when more than one printer or + class of the same name is detected on the network; may be "On" or + "Off".
    KeepAliveOnSpecifies whether or not to use the + HTTP Keep-Alive feature; may be "On" or "Off".
    KeepAliveTimeout30Specifies the amount of time + to keep the HTTP connection alive before closing it.
    <Location path> +
    </Location>
    -Specifies a location to restrict + access to.
    LogLevelinfoControls the amount of information + that is logged in the error log file. Can be one of "debug", "info", + "warn", "error", or "none", in decreasing order or verbosity.
    MaxClients100Specifies the maximum number of + simultaneous active clients. This value is internally limited to 1/3 of + the total number of available file descriptors.
    MaxLogSize0Specifies the maximum size of the + access, error, and page log files in bytes. If set to 0 then no maximum + size is set. Log files are rotated automatically when this size is + exceeded.
    MaxRequestSize0Specifies the maximum size of + HTTP requests in bytes. If set to 0 then there is no maximum.
    OrderAllow,DenySpecifies the order of Allow + and Deny directive processing; can be "Deny,Allow" to implicitly deny + hosts unless they are allowed by an Allow line, or "Allow,Deny" to + implicitly allow hosts unless they are denied by a Deny line.
    PageLogpage_logSpecifies the location of the + page log file. The special name "syslog" can be used to send page log + information to the system log.
    Port631Specifies a port number to listen to + for HTTP connections.
    Printcap/etc/printcapSpecifies the location of + a Berkeley printcap file to update with a list of current printers and + classes. If no filename is supplied then this automatic generation is + disabled.
    RequestRoot/var/spool/cupsSpecifies the + location of request files.
    RIPCache8mSpecifies the size of the memory + cache in bytes that is used by RIP filters.
    ServerAdminroot@ServerNameSpecifies the person + to contact with problems.
    ServerNamehostnameSpecifies the hostname that + is supplied to HTTP clients. This is also used to determine the default + CUPS server for the CUPS IPP client applications.
    ServerRoot/etc/cupsSpecifies the root + directory for server configuration files.
    SystemGrouproot, sys, systemSpecifies the + group name used for System class authentication.
    TempDir/var/tmpSpecifies the temporary + directory to use.
    Timeout300The timeout in seconds before client + connections are closed in the middle of a request.
    UserlpSpecifies the user that is used when + running external programs.
    +
    +

    +

    3.6.3 printers.conf

    +

    The printers.conf file consists of 1 or more lines of ASCII text. + Comment lines start with the pound ("#") character.

    +

    Each non-blank line starts with the name of a configuration directive + followed by its value. The following directives are understood: +

    + + + + + + + + + + + + + + +
    DirectiveDescription
    AcceptingSpecifies whether the printer is accepting new + jobs. May be the names "Yes" or "No".
    <DefaultPrinter name> +
    </Printer>
    Surrounds the printer definition for a default + destination.
    AllowUsersSpecifies a list of users that are allowed to + access the printer.
    BannerStartSpecifies the banner that is printed before + other files in a job.
    BannerEndSpecifies the banner that is printed after + other files in a job.
    DenyUsersSpecifies a list of users that are not allowed + to access the printer.
    DeviceURISpecifies the device-uri attribute for the + printer.
    InfoA textual description of the printer.
    LocationA textual location of the printer.
    <Printer name> +
    </Printer>
    Surrounds the printer definition.
    StateSpecifies the initial state of the printer; can be + "Idle" or "Stopped".
    StateMessageSpecifies a textual message for the current + printer state.
    +
    +

    +

    4 External Interfaces

    +

    4.1 AppSocket Protocol

    +

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

    +

    The AppSocket protocol is used by the Hewlett Packard JetDirect + network interfaces and print servers, as well as many other vendors' + products. See the CUPS Software Administrators Manual for a list of + supported products.

    +

    4.2 CUPS Browsing Protocol

    +

    The CUPS Browsing Protocol is a UDP/IP-based broadcast service. By + default this service operates on IP service port 631.

    +

    Each broadcast packet describes the state of a single printer or + class and is an ASCII text string of up to 1450 bytes ending with a + newline (0x0a). The string is formatted as follows:

    +
      +
      +type SP state SP uri SP "location" SP "info" SP "make-and-model" NL
      +
      +
    +

    State, uri, location, info, and make-and-model, + correspond to the IPP printer-state, +printer-uri-supported, printer-location, +printer-info, and printer-make-and-model attributes.

    +

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

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

    +

    4.3 CUPS Form File

    +

    CUPS Form files are XML files used by the CUPS formtops + filter to produce dynamic banner pages and support preprinted forms.

    +

    The MIME type for CUPS Form files is application/vnd.cups-form +.

    +

    4.3.1 CUPS Form DTD

    +

    The following DTD describes the available elements and attributes in + a CUPS Form file: +

    + + +
    +
    +<!ENTITY % Angle "CDATA" -- angle in degrees -->
    +
    +<!ENTITY % Color "CDATA" -- a color using sRGB: #RRGGBB as Hex values -->
    +
    +<!ENTITY % Length "CDATA" -- nn for pixels or nn% for percentage length -->
    +
    +<!ENTITY % Lengths "CDATA" -- comma-separated Length values -->
    +
    +<!ENTITY % Text "CDATA">
    +
    +<!ENTITY % heading "H1|H2|H3|H4|H5|H6">
    +
    +<!ENTITY % preformatted "PRE">
    +
    +<!ENTITY % i18n
    + "lang        %LanguageCode; #IMPLIED  -- language code --
    +  dir         (ltr|rtl)      #IMPLIED  -- direction for weak/neutral text --"
    +  >
    +
    +<!ENTITY % attrs "%i18n;">
    +
    +<!ENTITY % fontstyle
    + "B | FONT | I | TT">
    +
    +<!ENTITY % graphics
    + "BOX | RECT | LINE | POLY | ARC | PIE | TEXT">
    +
    +<!ENTITY % insert
    + "IMG | VAR">
    +
    +<!-- %inline; covers inline or "text-level" elements -->
    +<!ENTITY % inline "#PCDATA | %fontstyle; | %graphics; | %insert;">
    +
    +<!ELEMENT (%fontstyle;) - - (%inline;)*>
    +<!ATTLIST (%fontstyle;)
    +  %attrs;                              -- %i18n --
    +  >
    +
    +<!ELEMENT BR - O EMPTY                 -- forced line break -->
    +<!ATTLIST BR
    +  %attrs;                              -- %i18n --
    +  >
    +
    +<!ENTITY % block
    +     "P | %heading; | %preformatted;">
    +
    +<!ENTITY % flow "%block; | %inline;">
    +
    +<!ELEMENT PAGE O O (%flow;)+           -- document body -->
    +<!ATTLIST PAGE
    +  %attrs;                              -- %i18n --
    +  align       (left|center|right) #IMPLIED -- horizontal alignment --
    +  valign      (top|middle|center|bottom) #IMPLIED -- vertical alignment --
    +  >
    +
    +<!ELEMENT P - O (%inline;)*            -- paragraph -->
    +<!ATTLIST P
    +  %attrs;                              -- %i18n --
    +  align       (left|center|right) #IMPLIED -- horizontal alignment --
    +  >
    +
    +<!ELEMENT (%heading;)  - - (%inline;)* -- heading -->
    +<!ATTLIST (%heading;)
    +  %attrs;                              -- %i18n --
    +  align       (left|center|right) #IMPLIED -- horizontal alignment --
    +  >
    +
    +<!ELEMENT PRE - - (%inline;)*          -- preformatted text -->
    +<!ATTLIST PRE
    +  %attrs;                              -- %i18n --
    +  align       (left|center|right) #IMPLIED -- horizontal alignment --
    +  >
    +
    +<!ELEMENT BOX - O EMPTY                -- unfilled box -->
    +<!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 --
    +  >
    +
    +<!ELEMENT RECT - O EMPTY               -- filled box -->
    +<!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 --
    +  >
    +
    +<!ELEMENT LINE - O EMPTY               -- polyline -->
    +<!ATTLIST LINE
    +  color       %Color;        #IMPLIED  -- override color --
    +  thickness   %Length;       #IMPLIED  -- override line thickness --
    +  x           %Lengths;      #REQUIRED -- horizontal positions --
    +  y           %Lengths;      #REQUIRED -- vertical positions --
    +  >
    +
    +<!ELEMENT POLY - O EMPTY               -- polygon (filled) -->
    +<!ATTLIST POLY
    +  color       %Color;        #IMPLIED  -- override color --
    +  x           %Lengths;      #REQUIRED -- horizontal positions --
    +  y           %Lengths;      #REQUIRED -- vertical positions --
    +  >
    +
    +<!ELEMENT ARC - O EMPTY                -- unfilled arc -->
    +<!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 --
    +  >
    +
    +<!ELEMENT PIE - O EMPTY                -- filled arc -->
    +<!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 --
    +  >
    +
    +<!ELEMENT TEXT - - (%flow;)*           -- text box -->
    +<!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 --
    +  >
    +
    +
    +<!ELEMENT IMG - O EMPTY                -- Embedded image -->
    +<!ATTLIST IMG
    +  %attrs;                              -- %coreattrs, %i18n, %events --
    +  src         %URI;          #REQUIRED -- URI of image to embed --
    +  height      %Length;       #IMPLIED  -- override height --
    +  width       %Length;       #IMPLIED  -- override width --
    +  >
    +
    +<!ELEMENT HEAD O O (DEFVAR)*           -- document head -->
    +<!ATTLIST HEAD
    +  %i18n;                               -- lang, dir --
    +  >
    +
    +<!ELEMENT DEFVAR - O EMPTY             -- variable definition -->
    +<!ATTLIST DEFVAR
    +  name        CDATA          #REQUIRED -- name
    +  value       CDATA          #REQUIRED -- value
    +  >
    +
    +
    +<!ENTITY % html.content "HEAD, PAGE">
    +
    +<!ELEMENT CUPSFORM - - (HEAD) (PAGE)+  -- document root element -->
    +<!ATTLIST CUPSFORM
    +  %i18n;                               -- lang, dir --
    +  >
    +
    +
    +
    +

    +

    4.4 CUPS PostScript File

    +

    CUPS PostScript files are device-dependent Adobe PostScript program + files. The PostScript language is described in the + Adobe PostScript Language Reference Manual, Third Edition.

    +

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

    +

    4.5 CUPS Raster File

    +

    CUPS raster files are device-dependent raster image files that + contain a PostScript page device dictionary and device-dependent raster + imagery for each page in the document. These files are used to transfer + raster data from the PostScript and image file RIPs to device-dependent + filters that convert the raster data to a printable format.

    +

    A raster file begins with a four byte synchronization word: + 0x52615374 ("RaSt") for big-endian architectures and 0x74536152 + ("tSaR") for little-endian architectures. The writer of the raster file + will use the native word order, and the reader is responsible for + detecting a reversed word order file and swapping bytes as needed. The + CUPS Image Library raster functions perform this function + automatically.

    +

    Following the synchronization word are a series of raster pages. Each + page starts with a page device dictionary header and is followed + immediately by the raster data for that page. +

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

    +

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

    +

    4.6 CUPS Raw Files

    +

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

    +

    4.7 Internet Printing Protocol

    +

    The Internet Printing Protocol and the CUPS extensions to it are + described in the CUPS Implementation of IPP document.

    +

    4.8 Line Printer Daemon Protocol

    +

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

    +

    The URI method name for LPD is "lpd".

    +

    4.9 Server Message Block Protocol

    +

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

    +

    The URI method name for SMB is "smb". Support for this protocol is + provided via the SAMBA smbspool(1) program provided with + SAMBA 2.0.6 and higher.

    +

    5 Directories

    +
    +
    /etc/cups
    +
    The scheduler configuration and MIME files reside here.
    +
    /etc/cups/certs
    +
    The authentication certificates reside here.
    +
    /etc/cups/interfaces
    +
    System V interface scripts reside here.
    +
    /etc/cups/ppd
    +
    This directory contains PPD files for each printer.
    +
    /usr/bin
    +
    The cancel, lp, lpq, +lpr, lprm, and lpstat commands reside + here.
    +
    /usr/lib, /usr/lib32
    +
    The shared libraries (DSOs) reside here.
    +
    /usr/lib/cups/backend
    +
    The backend filters reside here.
    +
    /usr/lib/cups/cgi-bin
    +
    The CGI programs reside here.
    +
    /usr/lib/cups/daemon
    +
    The polling and LPD daemons reside here.
    +
    /usr/lib/cups/filter
    +
    The file filters reside here.
    +
    /usr/sbin
    +
    The accept, cupsd, lpadmin, +lpc, and reject commands reside here.
    +
    /usr/share/cups
    +
    This is the root directory of the CUPS static data.
    +
    /usr/share/cups/charsets
    +
    The character set files reside here.
    +
    /usr/share/cups/data
    +
    The filter data files reside here.
    +
    /usr/share/cups/fonts
    +
    The pstoraster font files reside here.
    +
    /usr/share/cups/model
    +
    The sample PPD files reside here.
    +
    /usr/share/cups/pstoraster
    +
    The pstoraster data files reside here.
    +
    /usr/share/doc/cups
    +
    The scheduler documentation files reside here.
    +
    /var/log/cups
    +
    The access_log, error_log, and +page_log files reside here.
    +
    /var/spool/cups
    +
    This directory contains print job files.
    +
    +

    A Glossary

    +

    A.1 Terms

    +
    +
    C
    +
    A computer language.
    +
    parallel
    +
    Sending or receiving data more than 1 bit at a time.
    +
    pipe
    +
    A one-way communications channel between two programs.
    +
    serial
    +
    Sending or receiving data 1 bit at a time.
    +
    socket
    +
    A two-way network communications channel.
    +
    +

    A.2 Acronyms

    +
    +
    ASCII
    +
    American Standard Code for Information Interchange
    +
    CUPS
    +
    Common UNIX Printing System
    +
    ESC/P
    +
    EPSON Standard Code for Printers
    +
    FTP
    +
    File Transfer Protocol
    +
    HP-GL
    +
    Hewlett-Packard Graphics Language
    +
    HP-PCL
    +
    Hewlett-Packard Page Control Language
    +
    HP-PJL
    +
    Hewlett-Packard Printer Job Language
    +
    IETF
    +
    Internet Engineering Task Force
    +
    IPP
    +
    Internet Printing Protocol
    +
    ISO
    +
    International Standards Organization
    +
    LPD
    +
    Line Printer Daemon
    +
    MIME
    +
    Multimedia Internet Mail Exchange
    +
    PPD
    +
    PostScript Printer Description
    +
    SMB
    +
    Server Message Block
    +
    TFTP
    +
    Trivial File Transfer Protocol
    +
    + + diff --git a/doc/idd.pdf b/doc/idd.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ad1fc130be9fdf498eef99dbcc28ec82cba9a498 GIT binary patch literal 395751 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 ^Wn2D0P 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 z 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

    Scope

    + +

    Identification

    + +

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

    Document Overview

    + +

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

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

    Internal Interfaces

    + +

    Character Set Files

    + +

    The character set files define a mapping between 8-bit characters +and the Unicode character set, or between Unicode and printer fonts. +They are named using the IETF charset names defined in RFCnnnn. These +files are ASCII text, the content of which is described below. Comments +can be included by using the # character in the first column +of a line. + +

    8-Bit Character Set Files

    + +

    8-bit character set files start with a line reading: + +

      +charset 8bit
      +
    + +

    Following this are lines that define the font information: + +

      +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", "rtol", or "rtola" indicating +left-to-right, right-to-left, or right-to-left Arabic text. + +

    Width is the string "single" or "double"; double means that the +glyphs are twice as wide as ASCII characters in the Courier typeface. + +

    Normal, bold, italic, and bold-italic are the +typefaces to use for each presentation. If characters are only available in +a single style then only one typeface should be listed (e.g. "Symbol".) +Each font that is listed will be used (and downloaded if needed) when +printing. + +

    The remaining lines define a character to Unicode glyph mapping for the +character set. The character and glyph values are hexadecimal: + +

      +xx yyyy
      +
    + +

    Unicode Character Set Files

    + +

    Unicode character set files start with a line reading: + +

      +charset encoding
      +
    + +

    Encoding is the encoding to use for the text; currently only +the string "utf8" is supported. + +

    Following this are lines defining the font information: + +

      +first 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", "rtol", or "rtola" indicating +left-to-right, right-to-left, or right-to-left Arabic text. + +

    Width is the string "single" or "double"; double means that the +glyphs are twice as wide as ASCII characters in the Courier typeface. + +

    Normal, bold, italic, and bold-italic are the +typefaces to use for each presentation. If characters are only available in +a single style then only one typeface should be listed (e.g. "Symbol".) +Each font that is listed will be used (and downloaded if needed) when +printing. + +

    Language Files

    + +

    The language files define the default character set and a collection of +text messages in that language. They are named by prefixing the string "cups_" +to the front of the language specifier (e.g. "cups_en", "cups_fr", etc.) Each +file consists of two or more lines of ASCII text. + +

    The first line identifies the character set to be used for the messages. +The currently recognized values are: + +

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

    The second and succeeding lines define text messages. If the message text +is preceded by a number, then the current message number is updated and the +text after the number is used. + +

    MIME Files

    + +

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

    mime.types

    + +

    The mime.types file defines the recognized file types and consists +of 1 or more lines of ASCII text. Comment lines start with the pound +("#") character. The backslash ("\") character can be used at the end +of a line to continue that line to the next. + +

    Each non-blank line starts with a MIME type identifier ("super/type") +as registered with the IANA. All text following the MIME type is treated as +a series of type recognition rules: + +

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

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

    mime.convs

    + +

    The mime.types file defines the recognized file filters and consists +of 1 or more lines of ASCII text. Comment lines start with the pound +("#") character. + +

    Each non-blank line starts with two MIME type identifiers ("super/type") +representing the source and destination types. Following the MIME types are +a cost value (0 to 100) and the filter program to use. If the filter program +is not specified using the full path then it must reside in the CUPS filter +directory: + +

      +super/type SP super/type2 SP cost SP program
      +
    + +

    Option Files

    + +

    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 (/etc/cups/lpoptions) are loaded first, +followed by the user option file ($HOME/.lpoptions). +Options in the user file replace those defined in the system file for +the same destination. Each line in the files can be one of the +following: + +

      +Dest name option=value option=value ... option=value
      +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
      +
    + +

    The line beginning with "Default" indicates the default destination for +print jobs; a default line in the user option file overrides the default +defined in the system option file. + +

    Name is the name of a printer known to the local server. + +

    Instance can be any string of letters, numbers, and the underscore +up to 127 characters in length. + +

    The remainder of the line contains a list of space-separated options +and their values. + +

    PostScript Printer Description Files

    + +

    PostScript Printer Description ("PPD") files describe the capabilities +of each printer and are used by CUPS to support printer-specific features +and intelligent filtering. + +

    PPD Specification

    + +

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

    CUPS Extensions to PPD Files

    + +

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

    cupsFilter

    + +

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

      +source/type cost program
      +
    + +

    The destination type is assumed to the printer's type. If a printer +supports the source type directly the special filter program "-" may be +specified. + +

    cupsFlipDuplex

    + +

    This boolean attribute notifies the RIP filters that the +destination printer requires an upside-down image for the back +page. The default value is false. + +

    cupsManualCopies

    + +

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

    cupsModelNumber

    + +

    This integer attribute specifies a printer-specific model number. This number +can be used by a filter program to adjust the output for a specific model of +printer. + +

    cupsProfile

    + +

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

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

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

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

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

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

    cupsProtocol

    + +

    This optional attribute describes which binary communication +protocol to use when printing binary PostScript data. The +strings "None", "BCP", and "TBCP" are recognized, corresponding +to no encoding, BCP, and TBCP respectively. + +

    cupsVersion

    + +

    This required attribute describes which version of the CUPS +IDD was used for the PPD file extensions. Currently it must be +the string "1.0", "1.1", or "1.2". + +

    Scheduler Configuration Files

    + +

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

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

    classes.conf

    + +

    The classes.conf file consists of 1 or more lines of ASCII text. +Comment lines start with the pound ("#") character. + +

    Each non-blank line starts with the name of a configuration directive +followed by its value. The following directives are understood: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectiveDescription
    <Class name>
    + </Class>
    Surrounds a class definition.
    <DefaultClass name>
    + </Class>
    Surrounds a class definition for the default destination.
    AcceptingSpecifies whether the class is accepting new jobs. May be + the names "Yes" or "No".
    AllowUsersSpecifies a list of users that are allowed to access the class.
    BannerStartSpecifies the banner that is printed before other files in a + job.
    BannerEndSpecifies the banner that is printed after other files in a + job.
    DenyUsersSpecifies a list of users that are not allowed to access the + class.
    InfoA textual description of the class.
    LocationA textual location of the class.
    PrinterSpecifies a printer that is a member of the class.
    StateSpecifies the initial state of the class; can be "Idle" or + "Stopped".
    StateMessageSpecifies a textual message for the current class state.
    + +

    cupsd.conf

    + +

    The cupsd.conf file consists of 1 or more lines of ASCII text. +Comment lines start with the pound ("#") character. + +

    Each non-blank line starts with the name of a configuration directive +followed by its value. The following directives are understood: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectiveDefaultDescription
    AccessLogaccess_logSpecifies the location of the access log file. The special name + "syslog" can be used to send access log information to the system + log.
    Allow-Allows connections from the specified host, network, or + domain.
    AuthClass-Specifies what level of authentication is required; may be + "User", "System", or "Group".
    AuthTypeNoneSpecifies the type of authentication to perform; may be + "None", "Basic", or "Digest".
    BrowseAddress255.255.255.255Specifies a broadcast address to send CUPS browsing packets to.
    BrowseAllow-Specifies hosts or addresses from which browsing information + should be used.
    BrowseDeny-Specifies hosts or addresses from which browsing information + should not be used.
    BrowseInterval30Specifies the number of seconds between browsing updates. A + browse interval of 0 seconds disables outgoing packets.
    BrowseOrderAllow,DenySpecifies the order of BrowseAllow and BrowseDeny directive + processing; can be "Deny,Allow" to implicitly deny hosts unless + they are allowed by a BrowseAllow line, or "Allow,Deny" to + implicitly allow hosts unless they are denied by a BrowseDeny + line.
    BrowsePoll-Specifies a server to poll for available printers and classes.
    BrowsePort631Specifies the UDP port number to use for browse packets.
    BrowseRelay-Specifies a source and destination address for relaying browser + information from one subnet to another.
    BrowseShortNamesyesSpecifies whether or not to provide short names (without the + "@server" part) for remote printers.
    BrowseTimeout300Specifies the number of seconds to wait until remote destinations + are removed from the local destination list.
    BrowsingOnSpecifies whether or not printer and class browsing is enabled; can + be "On" or "Off".
    DataDir/usr/share/cupsSpecifies the directory where CUPS data files are stored.
    DefaultCharsetiso-8859-1Specifies the default character set.
    DefaultLanguagecurrent localeSpecifies the default language.
    Deny-Refuses connections from the specified host, network, or + domain.
    DocumentRoot/usr/share/doc/cupsSpecifies the document data root directory.
    ErrorLogerror_logSpecifies the error log file location. The special name + "syslog" can be used to send error log information to the system + log.
    Grouproot, sys, systemSpecifies the group name or ID that is used when running + external programs.
    HostNameLookupsOffSpecifies whether or not to perform reverse IP address lookups to + get the actual hostname; may be "On" or "Off". Hostname lookups can + significantly degrade the performance of the CUPS server if one or + more DNS servers is not functioning properly.
    ImplicitClassesOnSpecifies whether or not to automatically create printer classes + when more than one printer or class of the same name is detected on + the network; may be "On" or "Off".
    KeepAliveOnSpecifies whether or not to use the HTTP Keep-Alive feature; may + be "On" or "Off".
    KeepAliveTimeout30Specifies the amount of time to keep the HTTP connection alive + before closing it.
    <Location path>
    + </Location>
    -Specifies a location to restrict access to.
    LogLevelinfoControls the amount of information that is logged in the + error log file. Can be one of "debug", "info", "warn", "error", + or "none", in decreasing order or verbosity.
    MaxClients100Specifies the maximum number of simultaneous active clients. + This value is internally limited to 1/3 of the total number of + available file descriptors.
    MaxLogSize0Specifies the maximum size of the access, error, and page + log files in bytes. If set to 0 then no maximum size is set. + Log files are rotated automatically when this size is + exceeded.
    MaxRequestSize0Specifies the maximum size of HTTP requests in bytes. If set to 0 + then there is no maximum.
    OrderAllow,DenySpecifies the order of Allow and Deny directive processing; can + be "Deny,Allow" to implicitly deny hosts unless they are allowed by + an Allow line, or "Allow,Deny" to implicitly allow hosts unless they + are denied by a Deny line.
    PageLogpage_logSpecifies the location of the page log file. The special name + "syslog" can be used to send page log information to the system + log.
    Port631Specifies a port number to listen to for HTTP connections.
    Printcap/etc/printcapSpecifies the location of a Berkeley printcap file to update + with a list of current printers and classes. If no filename is + supplied then this automatic generation is disabled.
    RequestRoot/var/spool/cupsSpecifies the location of request files.
    RIPCache8mSpecifies the size of the memory cache in bytes that is used by + RIP filters.
    ServerAdminroot@ServerNameSpecifies the person to contact with problems.
    ServerNamehostnameSpecifies the hostname that is supplied to HTTP clients. This + is also used to determine the default CUPS server for the CUPS IPP + client applications.
    ServerRoot/etc/cupsSpecifies the root directory for server configuration files.
    SystemGrouproot, sys, systemSpecifies the group name used for System class authentication.
    TempDir/var/tmpSpecifies the temporary directory to use.
    Timeout300The timeout in seconds before client connections are closed + in the middle of a request.
    UserlpSpecifies the user that is used when running external programs.
    + +

    printers.conf

    + +

    The printers.conf file consists of 1 or more lines of ASCII text. +Comment lines start with the pound ("#") character. + +

    Each non-blank line starts with the name of a configuration directive +followed by its value. The following directives are understood: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DirectiveDescription
    AcceptingSpecifies whether the printer is accepting new jobs. May be + the names "Yes" or "No".
    <DefaultPrinter name>
    + </Printer>
    Surrounds the printer definition for a default destination.
    AllowUsersSpecifies a list of users that are allowed to access the printer.
    BannerStartSpecifies the banner that is printed before other files in a + job.
    BannerEndSpecifies the banner that is printed after other files in a + job.
    DenyUsersSpecifies a list of users that are not allowed to access the + printer.
    DeviceURISpecifies the device-uri attribute for the printer.
    InfoA textual description of the printer.
    LocationA textual location of the printer.
    <Printer name>
    + </Printer>
    Surrounds the printer definition.
    StateSpecifies the initial state of the printer; can be "Idle" or + "Stopped".
    StateMessageSpecifies a textual message for the current printer state.
    + +

    External Interfaces

    + +

    AppSocket Protocol

    + +

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

    The AppSocket protocol is used by the Hewlett Packard JetDirect +network interfaces and print servers, as well as many other vendors' +products. See the CUPS Software Administrators Manual for a list of +supported products. + +

    CUPS Browsing Protocol

    + +

    The CUPS Browsing Protocol is a UDP/IP-based broadcast service. By default +this service operates on IP service port 631. + +

    Each broadcast packet describes the state of a single printer or class and +is an ASCII text string of up to 1450 bytes ending with a newline (0x0a). The +string is formatted as follows: + +

      +type SP state SP uri SP "location" SP "info" SP "make-and-model" NL
      +
    + +

    State, uri, location, info, and make-and-model, +correspond to the IPP printer-state, +printer-uri-supported, printer-location, +printer-info, and printer-make-and-model +attributes. + +

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

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

    CUPS Form File

    + +

    CUPS Form files are XML files used by the CUPS formtops +filter to produce dynamic banner pages and support preprinted forms. + +

    The MIME type for CUPS Form files is +application/vnd.cups-form. + +

    CUPS Form DTD

    + +

    The following DTD describes the available elements and attributes in +a CUPS Form file: + +

    + + + +
    +<!ENTITY % Angle "CDATA" -- angle in degrees -->
    +
    +<!ENTITY % Color "CDATA" -- a color using sRGB: #RRGGBB as Hex values -->
    +
    +<!ENTITY % Length "CDATA" -- nn for pixels or nn% for percentage length -->
    +
    +<!ENTITY % Lengths "CDATA" -- comma-separated Length values -->
    +
    +<!ENTITY % Text "CDATA">
    +
    +<!ENTITY % heading "H1|H2|H3|H4|H5|H6">
    +
    +<!ENTITY % preformatted "PRE">
    +
    +<!ENTITY % i18n
    + "lang        %LanguageCode; #IMPLIED  -- language code --
    +  dir         (ltr|rtl)      #IMPLIED  -- direction for weak/neutral text --"
    +  >
    +
    +<!ENTITY % attrs "%i18n;">
    +
    +<!ENTITY % fontstyle
    + "B | FONT | I | TT">
    +
    +<!ENTITY % graphics
    + "BOX | RECT | LINE | POLY | ARC | PIE | TEXT">
    +
    +<!ENTITY % insert
    + "IMG | VAR">
    +
    +<!-- %inline; covers inline or "text-level" elements -->
    +<!ENTITY % inline "#PCDATA | %fontstyle; | %graphics; | %insert;">
    +
    +<!ELEMENT (%fontstyle;) - - (%inline;)*>
    +<!ATTLIST (%fontstyle;)
    +  %attrs;                              -- %i18n --
    +  >
    +
    +<!ELEMENT BR - O EMPTY                 -- forced line break -->
    +<!ATTLIST BR
    +  %attrs;                              -- %i18n --
    +  >
    +
    +<!ENTITY % block
    +     "P | %heading; | %preformatted;">
    +
    +<!ENTITY % flow "%block; | %inline;">
    +
    +<!ELEMENT PAGE O O (%flow;)+           -- document body -->
    +<!ATTLIST PAGE
    +  %attrs;                              -- %i18n --
    +  align       (left|center|right) #IMPLIED -- horizontal alignment --
    +  valign      (top|middle|center|bottom) #IMPLIED -- vertical alignment --
    +  >
    +
    +<!ELEMENT P - O (%inline;)*            -- paragraph -->
    +<!ATTLIST P
    +  %attrs;                              -- %i18n --
    +  align       (left|center|right) #IMPLIED -- horizontal alignment --
    +  >
    +
    +<!ELEMENT (%heading;)  - - (%inline;)* -- heading -->
    +<!ATTLIST (%heading;)
    +  %attrs;                              -- %i18n --
    +  align       (left|center|right) #IMPLIED -- horizontal alignment --
    +  >
    +
    +<!ELEMENT PRE - - (%inline;)*          -- preformatted text -->
    +<!ATTLIST PRE
    +  %attrs;                              -- %i18n --
    +  align       (left|center|right) #IMPLIED -- horizontal alignment --
    +  >
    +
    +<!ELEMENT BOX - O EMPTY                -- unfilled box -->
    +<!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 --
    +  >
    +
    +<!ELEMENT RECT - O EMPTY               -- filled box -->
    +<!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 --
    +  >
    +
    +<!ELEMENT LINE - O EMPTY               -- polyline -->
    +<!ATTLIST LINE
    +  color       %Color;        #IMPLIED  -- override color --
    +  thickness   %Length;       #IMPLIED  -- override line thickness --
    +  x           %Lengths;      #REQUIRED -- horizontal positions --
    +  y           %Lengths;      #REQUIRED -- vertical positions --
    +  >
    +
    +<!ELEMENT POLY - O EMPTY               -- polygon (filled) -->
    +<!ATTLIST POLY
    +  color       %Color;        #IMPLIED  -- override color --
    +  x           %Lengths;      #REQUIRED -- horizontal positions --
    +  y           %Lengths;      #REQUIRED -- vertical positions --
    +  >
    +
    +<!ELEMENT ARC - O EMPTY                -- unfilled arc -->
    +<!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 --
    +  >
    +
    +<!ELEMENT PIE - O EMPTY                -- filled arc -->
    +<!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 --
    +  >
    +
    +<!ELEMENT TEXT - - (%flow;)*           -- text box -->
    +<!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 --
    +  >
    +
    +
    +<!ELEMENT IMG - O EMPTY                -- Embedded image -->
    +<!ATTLIST IMG
    +  %attrs;                              -- %coreattrs, %i18n, %events --
    +  src         %URI;          #REQUIRED -- URI of image to embed --
    +  height      %Length;       #IMPLIED  -- override height --
    +  width       %Length;       #IMPLIED  -- override width --
    +  >
    +
    +<!ELEMENT HEAD O O (DEFVAR)*           -- document head -->
    +<!ATTLIST HEAD
    +  %i18n;                               -- lang, dir --
    +  >
    +
    +<!ELEMENT DEFVAR - O EMPTY             -- variable definition -->
    +<!ATTLIST DEFVAR
    +  name        CDATA          #REQUIRED -- name
    +  value       CDATA          #REQUIRED -- value
    +  >
    +
    +
    +<!ENTITY % html.content "HEAD, PAGE">
    +
    +<!ELEMENT CUPSFORM - - (HEAD) (PAGE)+  -- document root element -->
    +<!ATTLIST CUPSFORM
    +  %i18n;                               -- lang, dir --
    +  >
    +
    + +

    CUPS PostScript File

    + +

    CUPS PostScript files are device-dependent Adobe PostScript program files. +The PostScript language is described in the + +Adobe PostScript Language Reference Manual, Third Edition. + +

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

    CUPS Raster File

    + +

    CUPS raster files are device-dependent raster image files that contain a +PostScript page device dictionary and device-dependent raster imagery for +each page in the document. These files are used to transfer raster data +from the PostScript and image file RIPs to device-dependent filters that +convert the raster data to a printable format. + +

    A raster file begins with a four byte synchronization word: 0x52615374 +("RaSt") for big-endian architectures and 0x74536152 ("tSaR") for little-endian +architectures. The writer of the raster file will use the native word order, +and the reader is responsible for detecting a reversed word order file and +swapping bytes as needed. The CUPS Image Library raster functions perform +this function automatically. + +

    Following the synchronization word are a series of raster pages. Each page +starts with a page device dictionary header and is followed immediately by the +raster data for that page. + +

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

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

    CUPS Raw Files

    + +

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

    Internet Printing Protocol

    + +

    The Internet Printing Protocol and the CUPS extensions to it are +described in the CUPS Implementation of IPP document. + +

    Line Printer Daemon Protocol

    + +

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

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

    Server Message Block Protocol

    + +

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

    The URI method name for SMB is "smb". Support for this protocol is +provided via the SAMBA smbspool(1) program provided with +SAMBA 2.0.6 and higher. + +

    Directories

    + +
    + +
    /etc/cups +
    The scheduler configuration and MIME files reside here. + +
    /etc/cups/certs +
    The authentication certificates reside here. + +
    /etc/cups/interfaces +
    System V interface scripts reside here. + +
    /etc/cups/ppd +
    This directory contains PPD files for each printer. + +
    /usr/bin +
    The cancel, lp, lpq, + lpr, lprm, and lpstat commands + reside here. + +
    /usr/lib, /usr/lib32 +
    The shared libraries (DSOs) reside here. + +
    /usr/lib/cups/backend +
    The backend filters reside here. + +
    /usr/lib/cups/cgi-bin +
    The CGI programs reside here. + +
    /usr/lib/cups/daemon +
    The polling and LPD daemons reside here. + +
    /usr/lib/cups/filter +
    The file filters reside here. + +
    /usr/sbin +
    The accept, cupsd, + lpadmin, lpc, and reject + commands reside here. + +
    /usr/share/cups +
    This is the root directory of the CUPS static data. + +
    /usr/share/cups/charsets +
    The character set files reside here. + +
    /usr/share/cups/data +
    The filter data files reside here. + +
    /usr/share/cups/fonts +
    The pstoraster font files reside here. + +
    /usr/share/cups/model +
    The sample PPD files reside here. + +
    /usr/share/cups/pstoraster +
    The pstoraster data files reside here. + +
    /usr/share/doc/cups +
    The scheduler documentation files reside here. + +
    /var/log/cups +
    The access_log, error_log, and + page_log files reside here. + +
    /var/spool/cups +
    This directory contains print job files. + +
    + + + + + diff --git a/doc/images/accept-jobs.gif b/doc/images/accept-jobs.gif new file mode 100644 index 0000000000000000000000000000000000000000..acbf73f66a161a572cf22e34f9230089aa52b25a GIT binary patch literal 527 zc-nLKbhEHbjAamEXc1swn90B}msfnLlB{6~cb0E{ zxaH8ZgIC{PdG__iuYbSN(u_$$ia%Kxxflc(bQpjDWTyk`KLwRO0YMgrRqJwI?<>&R zt?t;TA!EUML1ooZCjp5iEiRAWF(}yd^s^~mbg)efXJ8g|FbE2Cdgv$+!`u|%kTPTE z-S#`xe&!QWI&^CPU)uhsSc%1eJyeUGUxS;+#g?JFmw}O&OPwh*g^`mxLCqvGIyRmm z+>e=&Rh^yB&@88B!^TZ|Wy(f=Aw`?(-D>yhH8k$h<>Ehf%r<<=Sem?(Zp8M;+j^BrsqW>Lcs4kh)v?vl)AJL<7OVYZ9sQMrOc89B<0Y?)TXpqCWr){}f^X7NIeDB$OxW^%EY59M3p*{)1d literal 0 Hc-jL100001 diff --git a/doc/images/add-class.gif b/doc/images/add-class.gif new file mode 100644 index 0000000000000000000000000000000000000000..14de2d082461e94be0dc0515c08d2498dda79cea GIT binary patch literal 484 zc-nLKbhEHb3}6spXc1t@NHxgGwk|1ls;diXZH?*f4DapBm_9Xm+N_FYi(7Z?UUKQ; z!AB2oynXZJ)0Yo_{{2o%GbRZs{$yd~Vh~`^VE_V16uRvSm zNyWa#WQLxmXPj4(8ASL(n%x_wx=8kMvO5^Cu=rhhEUG3ToAh8q#UHB)NnKgqbCZ^{ zaUVZ?u)^*{QsBeZgcXYzJvkY>nqIqkFXgtW+5IQU4^`rqd27E;Xne}BLg210Z_j#ntxo1OE)&W=ESuu6Sm7j} zNP)x+>q!L*xsrZPQ1CvG;5WgaSH@z;428#T64eP31sgh3j8xr{1QxJ}2|7$F%b)Pq zpg`UIpom%Yz6IYWoZaNFu~~&fD*K?Jc4*e$00ma{V7(nNCxRSV532WSElluTqH%5x tD|6P;%n1pO%#1uHPR^^pE$9wmeEiH&eS02v+|#UQ|-!vF*zI~`d6DX8=XC^BTMT9@;BUqKHS ztL41>2NDj87wlqrWyrzDuC0`HAc9A_`QYPB1sgxFMrRFIy9JHY9ZDw5JpaPvjYF5_ z6x|9hyP6yOZKj6wiiyT?@M>}LGX`-o@wl{imN4|WGgS9`OzCG~VC3ai51eLTno_fP z$nA!)(BD#P$X#A$!^yW{?*`9}2PYSJd9`q#;^vrdAYifd(&hAI zvx`@5Ub<#xe(V0yJ1VJ561AT_Sa#2Vm*0Nfp+k&qTzoHPR_b!x$V#p^;1csVxTVFh zxy)mROo@s+*R(i}Wj00^-nB1ccj7Q9xZrSNaopjMKh=o`h6wR8W!{Wdo=#<#Qw|ME22-VpPQL8pgO*+HP_CC!f+|#UQ|-!vF*zI~`d6DX8=XC^BTMT9@;BUxCi~ zH31VI|77c9G~g1^Z>-{JJL-6PMU??hOMAix296nwvB8`YI%2NJ8l>917=0Ro>k|Sbh8b51Tg*U79nzV>BCb`Pg;RXQ^lRip_j142-d9LT%!?-sk85V5_NM)tD_R&Y z>RmSxFkIMcx54wlrRXOsCb2B!*>Pd{vMmjHUYz{#@ttpV1)`4q`TI|!sNl_S_YDa$ zGEBT$F)Nf5_^hg8)=to9RytgF;>*#D4+!ul|~+DSS+M(yI8X-p~2BTic`v>z@a6UOG{lY$0>l-_u}Ha9Rdjt7B~j4 zvT=Dmn&eU?mxK6r47pa*rjC^eJZs25SHT8tV@L literal 0 Hc-jL100001 diff --git a/doc/images/bottom-left.gif b/doc/images/bottom-left.gif new file mode 100644 index 0000000000000000000000000000000000000000..b7d10331012c08c2907efa3c8c0ec694247c339d GIT binary patch literal 122 zc-nLKbh9u||M9XPh}R6BFq$ z00Bs^1B<@E3D0b=WmyH^_9=+vG%Z(c^=xgH+IP~C|M9XPh}R6BFq$ z00Bs^1B-#c3D4DA)s|MD=bfomG|eICs2krSF^(e_&%M%Q{pRw-Az(7&k@rp#g5O^YIi{>cr`=<;B>x>vZY%mloCXb22e9v9U1bFtX=$<#BRP zFXrV`pV8~UtHs*0LBA_GHJu?Z*i6IGpjx%{z`;Yt`veTQq7Pf!w()Z~bqAf9ka(r? zn88F%W^PW-GYdm5YplO_k9jr2ef~E&m)^(wwl7HJj%MO=xvD2%b?SdsCN;uaM z{ORejSj~kz51*|$HlLkqhe5%D&nisbT~Vhl?RdbrQjsNS5@P_vgl49_8b?1odKWg? zBfE!Z$E-XZ%M7o_mX4dgxm;({4!xK2vC!2#JLd3(;6j!q-s?5rE!%obQ#9I@ciAEX zhO@47)^e?hV*0@8m2#kgc@6g~6?wrDJ<&BLKN=1sxLdIpR2*AHe>3t6-zg5*|`7U zz7wa8-?(+{`O9a&|Ncr#GbRZs{$yd~Vh~`^VE_VuVjk4<=G1`F*32SFeWgvS5`7qa&kAO@^Y#-mFsqgM@IK}2k4vDmM&Vn zXn~Re7srycX*%80t7{C`YcX?ka$3)E4BVy3%D-a=^IGl7X$30``bqF6d|-EN zFy|LpAaLM-BeVLKAf2Qi4*~`1`8L#i5`N4l5w|<2M$zbiV`GOx1aIJ_uYwNE%m&xi z?qGe*d0Oja*3YONljon3G!HbnFoWO8owYzlC1TPF&Px+2`RqJ01XcLAIr6p literal 0 Hc-jL100001 diff --git a/doc/images/cancel.gif b/doc/images/cancel.gif new file mode 100644 index 0000000000000000000000000000000000000000..f183b567941d75f7d2a8f22e4ce9b73d2377041f GIT binary patch literal 383 zc-nLKbhEHbv|$ioXc1sI%fN7+o$G>>>>bWWy59>6dz7C3qOJAqf<^Dw zum67W!p|p9e!qM7_wTQ?G-HyG;!hSvE(QSx9R?r(+3CRgM?s}eK#(D0)w-P5n;0GY zmRsB8DKd04+x0j-+!(D>#_VvQkl_y7_US<>6Qb5fOm9??)sf+MH<;bK%cW(VvmpnM z5c@&r=@lw(_b=HP>tHCR&J16uR!Pg z+JFg~p~5E9xzv$?^+TVQ6Z4Dwg_;DJZ~4XgNT>WtV`44Aq3`1u@@S{urld3yRdDr_bhDzO?kb1^e9 zbIwSez{JnO#Fe@{dF8@rHb!1`MCj%+4wZicPf!`%5;G>)Ztr!3;%#2>uH!%N@1 zboPy#w{Es88}M-1PrR*bV`sen@e@q}1IAU4PBU=u>`$L?+EeoaC;$HaGh$c*E--ZN zuU|Gp^Dw*Td=Ul~2?k3x=B7ENhD=8+TLmW^3wibI!G;?fmz=aOdFuAe;^d~KCnlDC zm{aU29Bn?yTBe1|;S_`O^qgxv4i7G~>WjEDi@fzXKG~s9Ye6n&dy2QHd2nDr)`1ht z#oTj)Y$Ufm%5K&Wl2`GV?I0YM9wk}O8g}(ysJLJGmmh&sk{cBH6%}v1PBUmcTz*t4 zAmRG*#3O;1beCw)Ffh?tm===~s4ut5DDN`wG1lAt=?rH+zt9=dPf| ztnMn?t+b~n&Q#&!iHu>3ddQYWekDW9>r@Mh0sDhk^C8 literal 0 Hc-jL100001 diff --git a/doc/images/classes.gif b/doc/images/classes.gif new file mode 100644 index 0000000000000000000000000000000000000000..ace15df98035c8ff3e41036b0be59f2664f7d0d3 GIT binary patch literal 591 zc-jF^08~U*5-X9+fD*emQ%-t<0(_wQriGZ zZZazx6{;H!rfZ&NF^DjR%UP$gL12(v1z%TG%JvI>t<>1d$R6}E?QFaBuG=p#CYq`w ziZLKnI#?fMDjR}LReukMU5I;WPjg%#kve@k4n}f;gCRUfWn^cOf{Z>uD@%zdL!5^? zZErJON@0|Ace@NlyuZK^mQ+k1!FGr)XqH-AsBeLx4HT-7rY(4&t$Tq1JGN%5Vb2<> zecNi2Y_Y^HEYhh!)TfI?l!TXqlgPG)&Q*(hvyg$SQ4d$HfyWfAV+V3h%sVe{>bzsg*v?&fS|wvO z;ipJR`P$Vo+Q`t9b~&`r2nMgIIb~O{sU$>Hj3ZL$G-e2z&tV~XEGM?mG=|~0JOR9Q zx~ivQkCoAuorL9KVzjCZsL7LY2n_~8V(13pGyvmhOX_!0g^}SfQhCYc7E-lJ z<8mqB@6klgfj#Q`%u%b%(iC7vD_0O};S&#LvOb}>9YnB~>XIW%d3BaYhzM(>GRB~0 zFrl4c{!(`{Okt{tJ(sb!5}DI%@Dx;B@|5J*;qU$?8QeVQ>viyE2Cb&1&70FFgU_{d d<`(xg{4v$bVfLjbU+|#UQ|-!vF*zI~`d6DX8=XC^BTMT9@;B-@1Sa zk6-fnUohiZV6wvfa6-i#Ic5eu3mvX$2OAGGG6+o2Z+yYKUvv;hkJVcym$cv zMt&BZfF%tRBO(IoJn}p^`FXbTgz5{JE!ZUHZ&? zT+EEjoJ|QF>WsHfMiuF;)Mf7CUERq)w~PN;OYQ5q8$DTg`S>^u9-CX9a$}IO+SD5= z6wa!6^mjAEM8;Z!rj09DKO8yWKR@bd^-=-WK1SZsii?+856m>-QRQ0{ee{yMLb$Ft j$IhY;Po%_W&3hT+xcH`D`o*596Mh)?@GMkhV6X-NSqP$d literal 0 Hc-jL100001 diff --git a/doc/images/cups-black-button-2.2.scm b/doc/images/cups-black-button-2.2.scm new file mode 100644 index 000000000..23cf817de --- /dev/null +++ b/doc/images/cups-black-button-2.2.scm @@ -0,0 +1,80 @@ +; CUPS Black Button +; Create a flat rounded button + +(define (script-fu-cups-black-button text text-color button-height button-color bg-color) + (let* ( + (img (car (gimp-image-new 256 256 RGB))) + (old-fg (car (gimp-palette-get-foreground))) + (old-bg (car (gimp-palette-get-background))) + (font-size (+ (/ (* 3 button-height) 5) 1)) + (dummy (gimp-palette-set-foreground text-color)) + (text-layer (car (gimp-text-fontname img -1 0 0 text 0 + TRUE font-size PIXELS + "Sans L,"))) + (text-width (car (gimp-drawable-width text-layer))) + (text-height (car (gimp-drawable-height text-layer))) + (button-width (+ text-width button-height)) + (bg-layer (car (gimp-layer-new img button-width button-height + RGBA-IMAGE "Background" 100 + NORMAL-MODE))) + ) + + ; Disable undo while we do our work... + (gimp-image-undo-disable img) + + ; Resize the image as needed... + (gimp-image-resize img button-width button-height 0 0) + (gimp-image-add-layer img bg-layer 1) + (gimp-layer-set-preserve-trans text-layer TRUE) + + ; Clear the background... + (gimp-selection-clear img) + (gimp-palette-set-background bg-color) + (gimp-edit-fill bg-layer 1) + + ; Make selections as needed for a rounded box. + (gimp-rect-select img (* 0.5 button-height) 0 + (- button-width button-height) button-height + REPLACE 0 0) + (gimp-ellipse-select img (- button-width button-height) 0 + button-height button-height ADD 1 0 0) + (gimp-ellipse-select img 0 0 button-height button-height ADD 1 0 0) + + ; Fill in the background... + (gimp-palette-set-background button-color) + (gimp-edit-fill bg-layer 1) + + ; Clear the border around the button image... + (gimp-selection-invert img) + (gimp-edit-clear bg-layer) + (gimp-selection-clear img) + + ; Restore original colors... + (gimp-palette-set-foreground old-fg) + (gimp-palette-set-background old-bg) + + ; Translate the text later to center it... + (gimp-layer-translate text-layer (* 0.5 button-height) + (- (* 0.5 (- button-height text-height)) 1)) + + ; Then flatten the image... + (gimp-image-merge-visible-layers img CLIP-TO-IMAGE) + (gimp-convert-indexed img 0 0 16 0 1 "") + (gimp-image-undo-enable img) + (gimp-display-new img) + ) +) + +(script-fu-register "script-fu-cups-black-button" + "/Btns/CUPS Black Button" + "CUPS Black Button" + "Michael Sweet " + "Michael Sweet " + "2000" + "" + SF-VALUE "Text String" "\"Button\"" + SF-COLOR "Text Color" '(255 255 255) + SF-VALUE "Button Size (in pixels)" "20" + SF-COLOR "Button Color" '(0 0 0) + SF-COLOR "Background Color" '(212 212 164) +) diff --git a/doc/images/cups-block-diagram.gif b/doc/images/cups-block-diagram.gif new file mode 100644 index 0000000000000000000000000000000000000000..2fe505e44b91deeb805b568a4db3a0fb508b0805 GIT binary patch literal 11637 zc-jGVEsD}dNk%w1VXXsI0pkDw2nGl@j*28mNsdrbK4^1IG&XX^bWBTSySu%Iii>h` zzFwzbprxnV;NQk_bpQYVA^8LW3IGoPEC2ui0IdU60YC))@X1N5y*TU5yZ>M)j$~<` zXsWJk>%MR-&vb3yc&_hclL&yI5Fii`0?4Ft$!t2G(5MtiC=P{!M1#lW9RLJ_cuX#v z&*-#z&2GEj@VIXf`cFpKtTdiii?bmj*pCoL|cTF8ed_1nwy+) z0YL-{V+2A0a6z48sHXs_uCK6keU`Mfwznmu0Fb=BzQ4dxpp`>@gP5_&%9;VXU}CFk z(W~BLiV^yfNT<=GNRujE%Cu>eZ6IULX!%mARUI>(YTeod=pdn2 z!-^F_b*$O55X+)n%OWe+w_Cjm0?W4UShaTZ>Rrfguip=Dk7~S96yK0Uy5Ld?;t@d9 zzmRX?jZC?6iOH5J2gVqL5hx~yl5}1&8cAu>yFP6so!Y1_1h8Yvo=v;9?c2C14Fym@ zf$!hIg9{%{ytwh>$dfBy&b+zv=g^}|pH98H_2?fn1MaK6@@Cf>i#!R>)+46|MTqdZT^5+fO>t$lud^ExRD(WqoR+`U<16Y`9t1preAnUGS zrAQaAz`7G_uxI&N>#a@=<`}We{)%PnHLW%)?F^&xXl)R>O$#AxEoOP`x8PnwqHnNi zYp!L_A{gzt?4nR@xI$#x?!5HYOKG~-u50hU8@&6iy!-|%@W89W3oXG2W8kk%04MD5 z!w|1DY{U*P952NfXRI+T6K_1QzYTjV^2j8+&~bMh7U00jEVu0P%P_|*^UO5YZ1c@H z=dAP2JojAln4AV}-J~TKP4UUvrR?+4OgHWH(@;nKG|)mcA8|WO=iAjhVvzb zlLj%s-;hTx`Q(&WZh6!G4Z#{`qh4Pwbr3d#&a&tZkiN2)k2^5Hm@Pxu@;0fje4^)4 z2RVYbMl;mdh@&D(<0?Ktf|o4)euUOsJn&&!vMI?KrGO}ymIPp`a7nhQ~toSj?G zboDNqPWtep^Okz_tpo7#n6W!ByZ1}mZuR`hH4Z@g@Yme@0LhFzf(@WHHl<5M32Cul$l0+@B(J+WbMBA1CV8b8!CPQ8%A{lkJ#s3J8fmw{B9Op>K;-wHK zE2K;d>&Qnr%8-75B%B1iq`^WO@{ov3q#_r|$VNKyk&uj}BqvG9N?P)gn9QUmH_1s% zN)eA#d{c@#Ny<{1@|37dr6WnG%2vAam4zgl-DYX8Jkk$oVXIk@`*o@&DlbFqJdh?r5i)LD;S)*!#^PK2R zC(X7oNH{`qgoI3D|H_v-*uBn*#(SRXSXVyj!4r=BY+ydE7&8Zku!P4GLi+qUgnCAh zp+a!z2mTj0zd;wh`J|no%jDECz3QTF=*!h5EhSYo*G-^X##=d(FaGCmqX$3n-RTR$Cst8Re zRLKX=s$TG`%NuA+kH^uknl-9EZE8ntszh-fQv)a!D%hH*R*FKetS*&l>MlCbsOB`R zA4DtZ>iSW(%GG)8gKr$oVE-)qp92+n}7dCRLT@f!HR2zHxwJAmCIZ1=%VI7G;J@GC$x zcfivHLIKe5i4E762xSP8e(^gB5Qq2~ANKGVRD<92is29=CWQdZ00i<*1H$zTq% zn8W;J97Xw-Q@%)RX`A5i7NNCF+42sI+~bJwxXz(EGcD6>W#7tK2Xw}BCG;%*Xvh%S zZhY=DZ~vTwKo?pNhkkT{?!4ec10zUKsKRl{!x|tB!NICYP?7dD4Mw**glFJ{FQ>Nhy6Z z{No@GdApaDXLv(a;?RZ^zP00Vk-PlmFxQX6w`KCTqCDk_S$SrBm+JnW`~2rX54zBY zPV}M=T~{SH>8mGzYn%i35Z+z7tBkd3sRsz+yToqOoz4`EB*5yx0&ms9ZW*jUngI%k z+hKgN-HaGls2 zna}<1`|Yvt@V!)ke?@~9G_VupzVqpGd$Udd+x4ry^>4RL@BZ8W{$B(CJH#Io@=Z&h#_6nZC?Z&YR4OBv~JWFaNcHzcldmXm4<+GReYFEWS9>82NVAHhv2k^nDTGA zlYP&jh>0VA(h-D)IEj>4J~z03W*8ZTSc%w#h(FkH{&aJEqPQJOH;Q60h^Cl|5toUo zIB2Zcim-T0s2GcF@ru8c0H2tPy10wQ@pah~hyl_7yqJqOG>o6Phn$#r{Wt6i{FYhIgfc1*lU9a)kT%k1+#=-WW627?2tihFaK;Vug_ZXgX@QK?B%@4Ea$Q z6o=XPLd*zR(0G5qWP@+@>n1ysTQ3vQc@+dp>m`(h1kt-RK`eTlQwvjS< zlix&*Gl-KssZJUBRyNs_LfK5zSc67+lt`KWluEgjOqpPpxL}solu|jBR9Tf)d6nT% z3k?7pXon?50Ffl6K}A3%w}k+%Co)lqm1?<`Y}uA>DN?>ji;aR>akzG%Rw{1Cf&>tE z34>%~_LqPem?%+Za=8~ja1Ct7b&8N$hY^?T;+KLMnUXn~%RrcgIe46=n1XQ_X9*}M zMwtcSX;=^na&TjtV47=ynxL6sBzKu((O+4nnOh+V3&1OoxthwLn!3OWub`S~;G4Ml zT$bsY@SqE^DVvaT2uK$cZ24uuNe-xH1Y{s%Wk8+Q@MY0J3eH($FJ@vTmS3g`4kfmo zp9u=j84v~bmQ4ASb+&cLi7bcE7?}Q71GjmesZa#cPz}JjUn91k27sDCKw{p&4dTfL z{%N0`Fq~KCj8f*F?`bPSAfH}_pyUv0^EI6pI$|1%YM*HU{e=zRc^CyM1|0fd`9-10 zprG(Ei$`+>cln?>cLfr93>}K1HhQCzsiNJ%qQq4i6!D@kiWEP}T{G$rHHxE1nxtT+ zquRlvTVrbB0i;373yeu5U7>q_P|FcMc_;xVN_Vx|s)rCp$< zIl!e~8mDq<5Mf$&42otHN2P3rAa4d|Lb_(@Nf?P)4>~skZi)kGsh*0usEpdEM>(H% zijIz4o$3LoiZG!ns%l26bC#*8 z3MY~}s~p3rv(&1tiVuY<1BXhBt7@wm5Uc~EtGj9sy&40*8jHj#tQOF$0b{I+pqx!W zt@n_pT9K?Uu&l5Mt?+&}$WErIH||ZONAw=BV^qul9Pc zJ_o7ZfvbpCuD;-)N}y@Gh90fa9;cBWslg!r+6&qW87*gw5F4?`W~vKXtA!@5iZGgc zA_RBIvD|ee1`D$GW^t?WuE7SY5c04RyRs}RG!(m{{8~2{`(Rb@qPk|Op%^ME+p^D5 zmvVD`(Kkj2_ZvP7{(a>pM1-?Dc*wIe)S8Xrt@|>w$4YBC+i^X_w9@ggjyQioyR>=8 zHrO|Agi|6iq$YESwL{~yixRV1Bejr_r)N59eb%slv9o9kgpf!$0;fiAhkX{A9E@lt z-o}Dod$(7kubRQOt9Wruk*5|HuzK>bF6t*JOCWY@xZu`rV=Hc%3x9YkwqP55z@u(& zLvTKbxxAAqP+Ln2J8_JAC+*53NMKx28fTR|Y*&lAjTkqJgM9)tZa!#{pvy+ak$t9{ zx4K&#FT10PYcy{A2##B@t#PwS@M{YDy6{@HjdHok+r8fFMu;03tJ_PhJGHN>y>i06 z-@Cr-tGsIdyJHqBXwPfDk3hG6p}y^#zxlhoP1?LgGr#oP2===d_^ZDL?7jRerv6(p z035)JFu>pHtLPiSkhZ`jvkk}Tz(^6F6kH2K(7~24zWXvJwX4Av;SB5v!lfFaDqO+w z`)Unow>t+h9E{f16}F6NIM)UEOiVJ zhjAOEd&(O(oW$vHEm#}_JO?iauzLuQ00dC9SYQNx8f<`iEd@XT3Gl>QtPtSx#xKyt z-}1$B`~VG5#CO~s@Uq7&K*zY_$AbJSA~nb<0LbBB$A-MfZ$eUxYyyZp1d9B~lnfu? zRmuJ%5XoeO$()=S2G+?SfXI^!%A~BoFI>tVK*ytu%B=hsJ)EjMx5}+N%X#t2uq?^6 zoXdV;%eTDAy8O#_!OL8r$@p5##(d273e53l!Lz51Ls>_jc))_B%r?i&zvs-)JV((i z&E7`M)qKhX5|r5tL)*;FK;+G`XwBn?&EuR!{;#I9XD< zkXVPpA-G@y99c5FdMMArM9({5&-V;J`P_p>8-IHXw2wGOgu)n`hs+wi(Hy;&Zfs}Z z93Tu0KWglOE%-qPX@3vRh7di`UfUf1*2KYsj167W&lIj9tj_(%&gB=65@|pWdHzpO zfTI`fVK1vw81*WM)8LP(Peq0lpJ<@nLJ%GD^t)BiWwXC*=^dDQykkED%M37FVj zawt@tdoAhK2$WQ8wS*uAIu|J0>$6h{HQUmYQy%%#QFzv4MNbK7Q(M(KY;{pBg^wT@ zP|K6j4ye(Zoi{Lv)lQ_;h07{v6D8g;<+u?MT6*Uj zoZji4{^_6|>Y_gCq+aT#e(I>6>Z-o#tlsLb{_3#)>Q=$yIM4vGe(SiN>$<+{p3b|x zej>ac?7}|mp^nfAJ?L^w>&EWQ%Fe9FzURg!IPa^gTTy#J=lsBl4Ok>G%ge#*>mmFH=`#IwVf?L~ZmPn2*Ub z^&%qWf9Ud9WZ(!$+$?Fy~{el&iB2IY}ixIiYvQ*Q4< zWPbI*P5^q$;4+EwG{fA1zgPFe@noIbb}x~b#rQ)B_e)gS4yiX^Z`h)9QE;936WQ^K zZ!<=HP%Ihsx*g*%E`|}b_yYb_1^HDmpW;2O^}J;Al;!p4$NO}DS5Jk0C*ArADM7zK zRly&EEYF9e|3qL}+8CIPRA1r*_5A?J_g2L-VE(UIy!+lSKKO+FPXnY@u20$})cIn6 z_n%GtyJY;6_2IU!l6BSd5HQ?y0MJ>iq}qalqbzJ9F%KNHGF3}BmS?)QZ#>s!?RmCc zP&nj$3Pfa5xnwq-Pbk!a@Kvo>Y*xGFcD-M4SUe_!6`*KZy=J%FZ+Lvy`vF99d|toj z_x-o2GQmN@Lc>EutFxoOM#o3UNXZyFpvg|fB^*#w5Q@Z<0rLtRNI+%b$uRK<7+~4b)#_EOAj=gXz<_B|l|{vlC0o|)S+r@@uJw8J>sz>S zMKw?WQ6g5ndG+q4Dsfx^1;^xC3(MB6iZG3wz1IT-kK$m>yyR_6PCM1ivrD0= zG$1u0Wz!pRcx1^xm{R`y@lhW`ipernO@ygYLw`K9C0S`q@>NsMlXO&Kixp=}On=+c zQ)ZjR3d(B2K}wqag6$6kU27UL+aBfN)}>y*T+wdb6<)s^2akq37K6=xJ4_0xvoCn^K(U*$k%3yKF zCcDtChif|7r~U!pIO@Uj2Dxg$=i3cy0JMIF>$($Hd~xIo=i7?B_kJ8MjqQ^+aLhS# z&;r5@cLs6BLl=GYp6j*cN)-jcmDard1uh~-~0A=BeaVzK6{OlKhxyeOND-X@|Tu=LF%iIEBL-r z)jniN|L&f1<-up(_VV-B|J?HxOke%CuHVG_;R9+WCb9fMe z^!r}c{%U6|AO=y0LnLAmjd;XyRLF%Fgkb=$7a<(pLn2fBNENMk#VK+SA2x&{4;yH| zCWbK!FBD@LwZTL)qC|%CqDU6eltqeEjfA2CV;aRsMmy%w8Fw8!Hd#tkis6*0 z)P*NO3CTg?i+_@+6fR!n#9vYhb*gEpuB z6F&py#xt0q8P(RAjCRr!GV>H@8VOoZWTI0-`>ajts1qpR$;JmX9l%`arD`ja*UFuScb~J_=l_@!CTGMj^KujUc%6Bkgj;UP6 zB2OIF2gJl8B$}gw%s4|*o%&R$Mpdd)1;}-lxG|g_;-j1?Y5R1Vk&(7(Q^-T7La!H+ zzj@}UR1HS~su7Qo96+vfrE6X7dRM&WRj+&HYhV5PSHK2Vu!ALRVGVmoj;g!SQ7 zp_WxaY;`kT?FeO`Skkh7^&;2nDrM^<%E!SqOQR)iX-#`t)TUOot7UC#UHksp);4x> z9L1?*VW(N_aTd2f)huRlYu2xJcDMAQD1$@`TjVBJxyxm4bDjHK=yFK5kE3l(ZL68s zX+*6S*)DG%u!3$<^gB{%9>GG|*GQDm(tCHX795_D-esG7e1dfr+7erah z&^e;Cp@)d$#8)zzhfKU75_?$2Q;M)D?R#G@RM^7%ya4$bDl1GJAv^ z<{4jE%O`#^jKAE}55>67NZxaYGyoVm+d0o)?lYV{T;q;SxT9!JGaEt6w>KO5!GWey zq4Dfx4<*^lcOI>#70_itcgWM1mNbzOZ9%M>xeScP%{=&d+2MY&&FhJDsTpkPCUZK} z7@7x)$#LXL1E9)H)pf5iZR;VQ+G%B0^%yZ6re_0qo3qAFt&uHXT#IiTvj5J;%zETn=qd z>FK{7_{uk3@P#iO!VkCc&Uv0=iqps90v7N&kT)!eath?jQM%UM{&u)SH|M>JIL}!P zQlCp(tOBmL?BwO~POV)zZI6554S#sl&V71ym-yXnGxnikyk)ZMu4m$dR!2{=dW1)O z=RN=VTrV}xysJOV zfj!tDHnxgD37kL*tiXW~J)J|q1Z1}bWI(`izztN8_W%I=2*Eodzh(<74}2X^F+npj zG8a6--dnEp#X_3_}~a7c}IXD-4G* zj6=HPLNtWHFKk1;*bODJLjXFsGX%stR73titc*3|!@Q7`1As$9e4IHHhdO*j(Qpob zuqr}ifT^PmMLfH4IDko{#OgUXbPz@5_y<$8f(FpUh|r-%i=vWa07p#4--*O=2t`_q z3rpMwOw2_rV1T+f2QJDSSX40uz(rq#AyPDgWSoqCXhu~6MsKr+ESiWby2g*FMtle{ z29O+RG$UIi2W0$4l-Nal=tXiYga+6KVEiW8|*kZwePSxm=DTE@1r$GF%BeeB0( z499X9M}K?=bF2q+97u!&M0`}Sgj9-rXh?{(Lx3~~fs9CMC`frYNQ>M^7hK4{;K+oy z2ap^|7o5m*s7R7*28=8RjZ8_GH2yP>{I!?FhI*Jun^ZNEln0c&NnKb;acD`N3`&8D z$*mB|FFFUKOiF~x$$8jGr4$99v;d%dN~(0HCalUqKuWCKN`bmct{elOoXW2pOI-3w zvIK*2I7_uuCbL{iF2G2!bW6EZq_&*PEEos7%*%~JLA@LVbBxQr49q5~OTnyz`zuVu zWJ117%rLM-z+_Cw96vlv7P@dhxU0F+dWvzVoOik5X zP1bBp*L+Rbj7`~`P1>x@*0ey}BnZ#cLeNwSUI+%@Oof-@%;h@F-7LM{Op4zOPUh5v z;Uv!FGS1_)yTw$F>imuC%ue!bgze-`*YeKqRJG(piSaB? z_}qi@L{HXI&-KKy_B@IAj8FcIgZZRS)w0j~gsl8ri2dwO1Z9K&1kl7wzX9FA0#%3u zO;8Gjf(2zz(-P1JwXX1dKs2aO5M6@{eJxTHH%oIedEgLIw7TeY&<#b-4tBaoyad2dIE~ZQdQ1yBQqk~IRS*dW z7=RBofeQfBAQ0332E`I7-88DpG&7Vt%`*bqY*a^mR7j0fNu5+mtyD|BR7|Z+LqrHJ zMF>1ig%b$VI|$WK1ymXk)YJMl6dTPmEjTg_kylOCMRf&JtyNpigiSq&PCbZEMTJt$ z0aE?bTcw0pH7!ufwI~&~OheHsQPo!M&RM;KVVzcL)q`Aphh2S#UOk0hm4Q+v0T7!2 zJ|%}y4S^4kfN>oMY3&76ZBP&xwx=^WBY@Wyd)E1SS2b1EA&u5*?N@(=gKKq%Y;}ii z)CY$)tO}ir`3V3eS#9D(XaJ|p*^FN<&vYtRjBpW zm?R0 zFEdenEz=ScH&XkvB4gHnTd`3?WDPOm`TAT~2;KJWUKoz!@-5sm&fy!N-LW;@8IasD zj$OG`TBudyOMc-DhTIn(}Wg6CI zZ*JoSmS7ErV1X@K$-w1YX4hl3U|&|a7*n~HBQ#^~QGSlPJ*(%dP38vvweDqJb7o_8 zCR}a4VT2}ScCLXsc3)!k-Gqi?RsP^Lwpm8-01mij7}(w3ZGqywV|PaWSz2BXd7fuk z*kxa?vnMNNE{n0w{ZX0TwVD>_NG52Oh5{Gv>FiADX|QE$SZSbM1((J;nC7&6{u0DmNUND{J<<+`sOCD>sR#LBy2BNM8 zv2N>3DC_7t)+96JE5U0ajjbxCYrtO8w}yteriQr=Z0$VjeG`X|{V>KxF11E%$qv!M zeul!HhQpq0N3d%+jcm>SZ2qk5JpyaU$ZXK=1J1@!&pvI|Zcfo|hRc=)({AlNNbL*$ zYue6jvc=<>I$H*rZQX_g+Xm39c3|T^ZsbnxBRXlK_3Z_LK;{09Zt0$G>c$5xO~BYz z%Iv;w?k0roHp=hrZt+$n(vHmV9&hySg7fCd^-gd1=D^op&-Q+A`kwEZv~T)OZ~S)2 z{myUk?r)L=aR0t;0SCzfAMh7F@QqY(1RqcakH`ma@b8T9hNN%_-%Sfg$PDM3C#-G{ z|8NkWZss=I_!bSQ4sjGuaTSj$Ne*roe}xiPh7CUi;C^u%PlHxi>l@#3NQm)dm~lg> zaULJ?B*<|hKXOU%aby7ULJ)E!e{vi!awwm2K2UOEU~)omaw^|)l5TM>|8h34@>VKu zxzKVj-*PEmg^4a>U;yPJSYeVbY08H41|D(6CG)s2^Zp7w2OTGZ!%c%f=jt>^1vlSj ztVV)B7u>)t^f%|>^+jI}PMZKc5SLC|vw?bb(^0y+=#PH*c$pY$vKbYLZQH3(st zh4iPjWK{1@NjF$ZPYO#H1WY&F6@K*^z;(ZE?NEnxI%o6}_TO@lfN-5$a>d`j_zN3A zby*JSL!W`m#b!TsY88W7YPVxLrd(@RR}6@D12%MV=<_58aXV*^T95R=O<`}R-gSTB z^X>LwNA_^f_Hv+iZXfGj=LB!(;Wmc%aBcw)hIdFmVF~7D8?a#j?({%!_S8jngZI<; zE!=N~^Z@qvxJ6(7l~`3rS`e?Eb9ePDHePWC{$Py%P!f1|fp>NfhFcp>;eJu(NXr#wsofr2>5c7EY z_|X1al&9m;Ys~l zp#RgN|M!G``ZP}9hUR&Y?)o{7U8%i$wJmouv-_HFiegzx&Xk6D)w_MfNw7&zZQ_vngNT~kKbxzFg4mwkwK`m$I0$k+8fpn7*= zeE8(sQm*}*e_I@8{oyBmvH#Q1H+C)l=6Rsz{7YE(Rxf9WCWmbo_FuDo%Fp{}=l*-Q zcg)rPR37|RzV_1x_wYA%>u={H^!@Ub2e^d_>Q{ek=lQH(ceo{g=?DMx&uZxZ1qc9O zxN0xXdh_l-7>XlVnkSm7nuI(r9LqCZ+c%!;JKy`iP5~&aipC={sa!If&S$9rcu6SG ztEY/Btns/CUPS Green Button" + "CUPS Green Button" + "Michael Sweet " + "Michael Sweet " + "2000" + "" + SF-VALUE "Text String" "\"Button\"" + SF-COLOR "Text Color" '(255 255 255) + SF-VALUE "Button Size (in pixels)" "20" + SF-COLOR "Button Color" '(0 153 0) + SF-COLOR "Background Color" '(212 212 164) +) diff --git a/doc/images/cups-large.gif b/doc/images/cups-large.gif new file mode 100644 index 0000000000000000000000000000000000000000..fc66ef07c01137f4eccbb23328f27c1de5abce14 GIT binary patch literal 7457 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 B-D3a% literal 0 Hc-jL100001 diff --git a/doc/images/cups-red-button-2.2.scm b/doc/images/cups-red-button-2.2.scm new file mode 100644 index 000000000..e608db5f0 --- /dev/null +++ b/doc/images/cups-red-button-2.2.scm @@ -0,0 +1,80 @@ +; CUPS Red Button +; Create a flat rounded button + +(define (script-fu-cups-red-button text text-color button-height button-color bg-color) + (let* ( + (img (car (gimp-image-new 256 256 RGB))) + (old-fg (car (gimp-palette-get-foreground))) + (old-bg (car (gimp-palette-get-background))) + (font-size (+ (/ (* 3 button-height) 5) 1)) + (dummy (gimp-palette-set-foreground text-color)) + (text-layer (car (gimp-text-fontname img -1 0 0 text 0 + TRUE font-size PIXELS + "Sans L,"))) + (text-width (car (gimp-drawable-width text-layer))) + (text-height (car (gimp-drawable-height text-layer))) + (button-width (+ text-width button-height)) + (bg-layer (car (gimp-layer-new img button-width button-height + RGBA-IMAGE "Background" 100 + NORMAL-MODE))) + ) + + ; Disable undo while we do our work... + (gimp-image-undo-disable img) + + ; Resize the image as needed... + (gimp-image-resize img button-width button-height 0 0) + (gimp-image-add-layer img bg-layer 1) + (gimp-layer-set-preserve-trans text-layer TRUE) + + ; Clear the background... + (gimp-selection-clear img) + (gimp-palette-set-background bg-color) + (gimp-edit-fill bg-layer 1) + + ; Make selections as needed for a rounded box. + (gimp-rect-select img (* 0.5 button-height) 0 + (- button-width button-height) button-height + REPLACE 0 0) + (gimp-ellipse-select img (- button-width button-height) 0 + button-height button-height ADD 1 0 0) + (gimp-ellipse-select img 0 0 button-height button-height ADD 1 0 0) + + ; Fill in the background... + (gimp-palette-set-background button-color) + (gimp-edit-fill bg-layer 1) + + ; Clear the border around the button image... + (gimp-selection-invert img) + (gimp-edit-clear bg-layer) + (gimp-selection-clear img) + + ; Restore original colors... + (gimp-palette-set-foreground old-fg) + (gimp-palette-set-background old-bg) + + ; Translate the text later to center it... + (gimp-layer-translate text-layer (* 0.5 button-height) + (- (* 0.5 (- button-height text-height)) 1)) + + ; Then flatten the image... + (gimp-image-merge-visible-layers img CLIP-TO-IMAGE) + (gimp-convert-indexed img 0 0 16 0 1 "") + (gimp-image-undo-enable img) + (gimp-display-new img) + ) +) + +(script-fu-register "script-fu-cups-red-button" + "/Btns/CUPS Red Button" + "CUPS Red Button" + "Michael Sweet " + "Michael Sweet " + "2000" + "" + SF-VALUE "Text String" "\"Button\"" + SF-COLOR "Text Color" '(255 255 255) + SF-VALUE "Button Size (in pixels)" "20" + SF-COLOR "Button Color" '(204 0 0) + SF-COLOR "Background Color" '(212 212 164) +) diff --git a/doc/images/cups-small.gif b/doc/images/cups-small.gif new file mode 100644 index 0000000000000000000000000000000000000000..6adb4a29ffbd6b806d8eed34fdad33f6138e8890 GIT binary patch literal 1266 zc-jH-1P%K~Nk%w1VQ2t*0P+9;%*@Q0nVDv0W-~K000030|NsC0|NsC0A^8LW000F5 zEC2ui0B8Vv073))Si0Q)Fv>}*y;P9RyZ>M)f&+k^&M>Z|5CEnF2ZGAp#DF#d?g_gf zMB^g>Geuovvm_`sy(66bkjl^nG{>zj(HFtg+CH;@**F8gro_jj zgj?4byer~)Nf456i8gNvL_|X0AKjZb>HiP(?JJY134<#O)`DciDjrm5wU?-9CnKXPnbDTvVa3|4f5K7S6B=AM! zSYIVh=MMvpL6%}^eK=5Ac<_z(R8;T0D3mP`7Qt9sGhSe$EOS+sTM)thaLtgUiD6_2 zhR`Sjh1$62wZ88{PYI*?4fc95P!hd?1I4wU9X6lPAS{=i&_ zo?VF1doqTGo^>DAmj)l0_Jo62Oos5|L@{Wf#B=Lafe9Y8?x1TS<83QJnBi<_-$QF~ zvqbn}J9Ra2PGl=fQ*CO_rXl%ZbOXykTl6(kKS27Gix4ug5I1RZMXO zBbFK{-Eb^oSCF{BD!VbP${lImYwjA1)NIC4D-y>1WqfmY9^86Ew$5hPT}r(E%AOU% zhC(C`+PyIFy&mz^)!zKG&baOq|v6_F*_C|4I;#4HBJ&n(8w@p2}RL(2}!DTz7 zIG=4kc*1vOOfO{;dR^(rrfcEDoT>YJgRMGB_C>cOroJw|OtX+}?8J8AwwtsUuK4Sw z5B0$9=>jZSq?PU7mVgl?>3n3RM_&Z&00rl%Ljuo*JnjL4`dgCQKS1hOMq(ehtE`8? zrH@~CI=#Aew*Nrz)z~kCpmbjemmzCuiKEn_sG606e}~$YGVqr`cF?JT*DDeP!%`*$ cc1nF?aZ~|iF+YF}&@50&%OUg^gaiNpJ5-EOApigX literal 0 Hc-jL100001 diff --git a/doc/images/cups-standard-button-2.2.scm b/doc/images/cups-standard-button-2.2.scm new file mode 100644 index 000000000..565c3221e --- /dev/null +++ b/doc/images/cups-standard-button-2.2.scm @@ -0,0 +1,80 @@ +; CUPS Standard Button +; Create a flat rounded button + +(define (script-fu-cups-standard-button text text-color button-height button-color bg-color) + (let* ( + (img (car (gimp-image-new 256 256 RGB))) + (old-fg (car (gimp-palette-get-foreground))) + (old-bg (car (gimp-palette-get-background))) + (font-size (+ (/ (* 3 button-height) 5) 1)) + (dummy (gimp-palette-set-foreground text-color)) + (text-layer (car (gimp-text-fontname img -1 0 0 text 0 + TRUE font-size PIXELS + "Sans L,"))) + (text-width (car (gimp-drawable-width text-layer))) + (text-height (car (gimp-drawable-height text-layer))) + (button-width (+ text-width button-height)) + (bg-layer (car (gimp-layer-new img button-width button-height + RGBA-IMAGE "Background" 100 + NORMAL-MODE))) + ) + + ; Disable undo while we do our work... + (gimp-image-undo-disable img) + + ; Resize the image as needed... + (gimp-image-resize img button-width button-height 0 0) + (gimp-image-add-layer img bg-layer 1) + (gimp-layer-set-preserve-trans text-layer TRUE) + + ; Clear the background... + (gimp-selection-clear img) + (gimp-palette-set-background bg-color) + (gimp-edit-fill bg-layer 1) + + ; Make selections as needed for a rounded box. + (gimp-rect-select img (* 0.5 button-height) 0 + (- button-width button-height) button-height + REPLACE 0 0) + (gimp-ellipse-select img (- button-width button-height) 0 + button-height button-height ADD 1 0 0) + (gimp-ellipse-select img 0 0 button-height button-height ADD 1 0 0) + + ; Fill in the background... + (gimp-palette-set-background button-color) + (gimp-edit-fill bg-layer 1) + + ; Clear the border around the button image... + (gimp-selection-invert img) + (gimp-edit-clear bg-layer) + (gimp-selection-clear img) + + ; Restore original colors... + (gimp-palette-set-foreground old-fg) + (gimp-palette-set-background old-bg) + + ; Translate the text later to center it... + (gimp-layer-translate text-layer (* 0.5 button-height) + (- (* 0.5 (- button-height text-height)) 1)) + + ; Then flatten the image... + (gimp-image-merge-visible-layers img CLIP-TO-IMAGE) + (gimp-convert-indexed img 0 0 16 0 1 "") + (gimp-image-undo-enable img) + (gimp-display-new img) + ) +) + +(script-fu-register "script-fu-cups-standard-button" + "/Btns/CUPS Standard Button" + "CUPS Standard Button" + "Michael Sweet " + "Michael Sweet " + "2000" + "" + SF-VALUE "Text String" "\"Button\"" + SF-COLOR "Text Color" '(255 255 255) + SF-VALUE "Button Size (in pixels)" "20" + SF-COLOR "Button Color" '(102 102 51) + SF-COLOR "Background Color" '(212 212 164) +) diff --git a/doc/images/delete-class.gif b/doc/images/delete-class.gif new file mode 100644 index 0000000000000000000000000000000000000000..c60b07118be87ae482e6995fb7c8cd8eccc9a39b GIT binary patch literal 520 zc-nLKbhEHbjAIaCXc1swU}TVz7FW|yH8L^s@^+4mkIBi)u4}06>gk*~dBU<4OE+!V zc;wij^B2$FdwBQz&u?jI#v~!dpDc`A3<3-~3_t*~(}DG$f=Zu&AVbEgbvdv174WdL zSk8N|yrSxZNJFFF2ZkRFhvuI9!L1j3B+R5jOQhCX*|@uy)rDndg^%8B#;t+x4yLul zUjFR0pkNDU;ZAOzXf{57J}z}err@R)FJ_Gnw@6JVF6LHt)5O-1J4Z^jwC@3<7$RwA{ieZC^0aXwaH01G)_8uN}Na9 zj_HF!!&F8KS&5D!+Rs-t3Uvxk)1QjZehAJxy+V1Q@IV%*f6p literal 0 Hc-jL100001 diff --git a/doc/images/delete-printer.gif b/doc/images/delete-printer.gif new file mode 100644 index 0000000000000000000000000000000000000000..6812fc5adb59fc2f4a0c4cbe5b84cb6442a20c50 GIT binary patch literal 508 zc-nLKbhEHbOkogVXc1swU}TVz7FW|yH8wT!_Hl`gi^gk+4cjn5~%MTph zf8x~fYd5YweEi_opPy-I#v~!dpDc`A3<3-~3_t*~(}DG$f=Zu&AVbEgbvdv173i#H zbnJWno8y(71?zzX^$Lc%gNpg(EL<~fw&gSiA z+&1x@WBiiXqu;yEyc?Sw8c9Nx8<%|uUW~)&vk^0<>29?nLdY(9-FD_GdpOm z&Dm2sjRY)L-@TWUZhq(fllu?NEuOx*_gtlX#r)Tw*1X(m!^qD6zJ81D@BQuqU%Ws1 zyE+yu&tqI{+R(_X-XLYiv#H@6qaxp22j`8R5sXp4wA2^^J|1-Kl&X^FxSU!bzK)&I zj&H`x0}gUCO?XodTP}DeXU8WHGil39KT`&q+Nw#0eXMFMVH`Yjl3Z2=%Y})?Ev;(3 zCA21Z^URN--Th47j3O6aGHJZMW%BdVj@k$6UM9W@dzm__U3BlJ>V%(|>AvH3Z*!~g U>5SHMEsu_CXDw(JU}CTa04zSwG5`Po literal 0 Hc-jL100001 diff --git a/doc/images/draft.gif b/doc/images/draft.gif new file mode 100644 index 0000000000000000000000000000000000000000..77d9716abdee066f1d5907c2748a595ef174d6a5 GIT binary patch literal 926 zc-jG;17Z9}Nk%w1VE_RD0e}Di!^6Y>|NkNW4ozWXWgvHHbZ8()Nlj1yEC2ui00031 z0RRI2jE||y?GK}zwAzca-n{z{hT=$;=82~2%C_zc$MQ_q_KoNI&iDQg3<`(DqVb4K zDwoWr^9hYgr_`$Tip^@b+^+Wv4vWX+viXcotJmzd`wfrF=k&V$j?e4&{J#GW7$`VM zSZH{Nn5ekO*y#8O87VnQS!sERnW?$S+3EQS8Y((UT55WVnyR|W+UoiW8!J0YTWfoZ z+W?T;1mMf7BmGNVZH=8Ry}e_7?TrH-E?z@kZZ3m9 ztq#Nf?EV5C&@Ioht6gt@kMirBfM357&*B9HIFQ7$eGCL9{NQjw#D^K^Jh?ofCY<;rVU zmR-@ecA?_j>oROZt$_CtMru}U+Q4`V&;09Guw%q}88@Cxd9hW=nA`R}xVE!r%bzhD z{zuj+=fd_LGi*M<<1Jrg z9bM+0O};_bTX;Ghh+ka76(^v7H$6z)gRxP#8gdSDHl2k`NoL(^&h52ah{Z{$TRY`F zMxZ+!%7$KaE&c}-ds)o~4S)SDrV@_%eRpDy^`W?pctL{L6p{29x#NiPsi@$JGS2uU zl|{Zc+f@xFCuEmS1{o!iNqXobGE0%ArIOSD*koTG{`97oR(|-Uh_z{WSDZtZ8K#<5 z(l#eWhso)upn5uoXP)y-^=4N%u9c{ZWI|f!gq7~dqG@1~HkhV%TG^;=7KSQng?x&Z zA*rQ087XU_sj4ZXr+T{Qtg)WNrl%27wWY2{_Udb!um=03i*LUA z?#pk#{{9Pazyc3UaKQ#2jBvsVFU)Ym4nGWW#1c+|#UQ|-!vF*zI~`d6DX8=XC^BTMT9@;BUxCi~ z5?*dr%X#mOH!!+0J(afUu%BvpAxVRQi)~|~f{mYDgP?#6lU$qbr_&NFhZ{ghUJbYnnvKBo)2SyQty8!taUw`WUFuK~M?ZO3G89anb)W^O)yJ{~sHtgab- zI!VowC$mH^H&$Xbuw&f3xrUR8d%DX4?XWH;W-bnfyujpm`^ZXuE@qwtrUbV0C+#n? zF>ysE)My+nD62iLxyGH5ms_2=TgS3t>4%S>KATQZ-uOoM(IX9R|DHdOSVc@W%;x1V zWLmXyGoSE&27Znihgde=l1OzIduO#(my?N&yJ+J<=Z%kdOuqYXn~H}>(ZLPk0xvGi zzL^xZrN*Rq(~rf@%g)VrsQ+|jqweTjs2qaFn~z zUzcx|r|*I6Hs+l4XO&NbrYT&D%8WkwgZXt9cRDYhsY=@m`L3?=`BQIxeRFalJLi!H zPet0Un3*yQ$=v$fGc)O+=K+yzQ`XCHG4aTle0a2I-I5Ru0h@wV+&8;at=BVjw6#t@ zskT-jq z*hlpvOuQe==Na?!JiFDp=WgNzwK)NdlQ{y88Z$65J`hUmuzYzyq)TU;hiIV6j0cZ; M{2wwTb1+x~09@`ORsaA1 literal 0 Hc-jL100001 diff --git a/doc/images/esp-logo.gif b/doc/images/esp-logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..8a879b144081160e6bca59002e3269432c7166d0 GIT binary patch literal 2529 zc-nQ-2S3}11Ay_^u@fQ^CQ@4?r0hpbQPaGd9*W zF+rP}VtjSrW@cD(bDV{Ro~5Opm6bjoZ-B=e+SnM`+8Wu}86P=fVs8&Hb#O3qbOe|? zIhh|lYT@i`>EZ&gI(E$Z_;G6j0q^Pxupts{NF-Y_+0Nblh=&KjoTP#rTeLNYT$v$9T{JsXyt9hQ?5e(v1K^XDUS zb0hQeqApwjM1TK%OnyFq#o+*Axm-XTj~7>1c&exfz~=MW#l`UgLBhq0fW(rLq|#DA z^4l2iva;mz@|4QT)0LH}LSb4}Ra$j*x=55>Q+j#cG&2Ken4N8ypTE4Y(73pGWofBtdAa$) z1AzG9L-EQ=%i3D&`g;4f{~zXyw1fia8_4Xx6aIUG06qkLlh>j2izm2Xb(65U{uVbr z2NL11PPDT8=?%pB0&|X$HI(QZKyM*0ij7916WUBnMg zoNQ^GIkStBvqqX1Vu=_2o=a;hQbJfV+pVl6Nql8ZBN97RJPwkOz-J z`%+pd$O!T+n52y+y&wzgW84rfi$CK$c6fLrV5b@4CE4;sDC|DS24O3e8HVYR=Q+<_ zpR%m}TbFY9C*AOQ<~&NYK}R7OGaPmLSq(1S@pB}3@oRvFTM=VjHxPzzUvS5{BBF?j z7r_MNHjVwl2Y-gy61Y7=sbpG)4!%dxHRi2&`U+jJ5T*f%=(8~7mV9^d-8^t7+86|a;w&23|IPvoNmrj zI$tNXUpRwg@jl3CGMUygFds7x3F-z~olP{c(y5{{%;CtERK63ICDoKOvf@z*!HO_HACDEE5=hk|qI+`2TZd3RgXO_Z zr~yerrT*7>u|m$c!oM{pJNh!a*qL#>8;3xpq`a>?Fd8jes zki}iu*MomD9Co##;}VPPMnCoBdOvSiS|Yj}JmDprbR#;~l2yhi?RQ{lxwwh_U5EA2 zuJ+-z8CeVtPu_vwvzU|ZjG0|fy7Q@j9G0Tc6)98k^`$Ewa19s8g0EX|jcacoJ7a~upY+e}*g4(2Hyl1HV|ukn>++eMLU^zr z^u9VxFG?Ef`gxqI(mT2{sbD0snv~OFM@~pXY{ei+c{8+xVhFlm;jbxE#^aFq-i^m6 z(v|}^!*g~wHX}I7L0eG*mp>4!Dta6;t|4s)$!-}VwouEuGn-1)GhojM7% z*Lm{!x3LxPAPIEy8S6HcrTX;hPV4q#U}~KkFVb!wA&JEI^PS8v(sHG<5IjX?MH*|a zC_k;{O4ZCU`fQGI{>xGF*Pr`%jAoUBey&Pa1;wejM>VLQ7=RETX3b62hnEB&KEQ;k zew4X+Q(4bFB#p4h(8EH-vusHltQuJ~0q^a;81!`WCx|;VO+#P%SCe`5`CEO~RUZ-; zF13<|igeKQc8<;97NIh#xG!=kMy<0FwYgPkY_wZy%K&TYw@zK%?MdW^QP$LU1_ukt z`8rSx|AJQwGamf4EVph9sNiN9LR>puT6axcR(F6&K?nV}xXR*{gPsNs1aX z#XGX_fRAC%h#T)i6Os;IFY2V5+sDNUG@fj3MGM@&uC7)@)AWOQktBkO5N*;8mMrX~ zmQnXG+x=XJ*)QgNT3P%L_qObH)vEZmd@TGa%VzZVq56)2sebLpkP!-_gEe1Kw@eo_EMA^%>oK^jA)KF3}}|zVWGHOYdVIt>))| zcc+fOq}$~L#eV12{K^0Kw43K_??3m(%#L2U@bKD;e`$Wp9_xRjHhTX!k#NxHIo6TY z(q6yZ6Zdgzxo8~6SvSHEv2E(C6h+!kW^*+M%Vbx eQZ8agkh&P@3ifiSvmSXIXLtD*l(r!nbo75FMMDYz literal 0 Hc-jL100001 diff --git a/doc/images/happy.gif b/doc/images/happy.gif new file mode 100644 index 0000000000000000000000000000000000000000..c69ac0169de7c708084066db8137ea4ea73620bd GIT binary patch literal 3522 zc-jHN4L$NlNk%w1VZ;EC0OJn;0096G5e_3IB0WAlS6EbQYGQA0R)>atiHL8ap@yKL znz*={yuP~B)yn<<{N3H%A^8LW$N&!jEC2ui0K@>006+x(@X1N5y*TU5yZ>M)j^qOj zT0#J^&670{_6EP!b5h1^~)oz-&67P$pqYty-_u*Teuo48LF?(nne) zCItY)!EU?X@VI==0B9cxdw9?Pq|YQ=UJ_giZVd%CHw6uIjtVO*0|$+74JQo1rk84+|%zwxyMBHWWy%zI(K+B&ezZr3^L#hPDkz0LyVJ zWDjP)Au2fpYYdQzIROL(3Dd0!HUS41y%Wwk?g3H-1_*$gX@fv2IH>6r3GMC(xB)0& zl7cmG7$AIephdqD2hQCQk)WQn1O^Crlf**g2gGsvLv5)}ahIAbh$$cuo5o)=~S1ZQC9h#4DQ7(&LvDF>Y* zpbGh90f7Q_1IR2vKw~0L6ztMkps{4Y*$ZMj^}tAAAC4VKsdcp)B(H=8NYI5KOMyn< ze_EQs9m(XOin|!3x)VUai{U;902p{cqlN$hs|w!v42JcF1Aljh4(dU34$icPxDFG# z0F4_g;8m@#TS#$h$dPn*#hAl!7z>gipRVCK1_XU?FUL^LgY^`Dsf+)D-Q9rECB9pS z4Z!R8_wY3=_#J%v2C+ZgBFEN3{{$HcApU@W0R|K>1rw)j zz7SJ_j1t(uMFW-b+ABzE@Y5MeT4lJTuhsyk|`Ss zxU?AolFISZ01dFGSO(@4fx`!${+(e)e#ut9{WR2k@yF~gbysi)PGD&VCgiLrh}NM1y3Mw z1$7Pl;}4-W)8U>tO$_C{9Ef|<2D8mo(=;kfLcszJbWC3h_Ibx~D|5QsipCfGv?rD& zu546p$-UeOz!}gSg3xV(VAy<#afB`hO3DmIbg~p3WPLnSOvVaE`}{#3QA_Q03L4!e zj=WiGkl)v6zgJ$N2K17~!0!c!2dbwvF@-$yu3%lidg}_sF8k~X zMG3&-p9gVI2{B_^XO+NTGTDl``?AUrFCzgw@D1Subn(35e3c$0w&%za^+6-YCGG7R z$MF-u2z@6+dnv&RGWEJV9L3sDfE!nyXyW*scuoTG6V$Rkl0M!}|0d=e0b|6pKOWUV zMQr+CA3_HL@f8UG1w2xB1S2^G{@{6|lHMrbaH%OR?^4=x!01dMA`5;2a6|K-1d!lC zl&~O#En)x;-Uo-~Z9#fP`v_-{f}COD?l1|Ifc{MJs6s_5cD>q^GD`6z6m~)%EJz9h z6fppV&@CL2;s*Xvrlq(cys3f|T$13LyrUDJl1d9%pTE!b| zrT|5V>H=R}q1NWo0>Vva0c-(?QHIljID!L^IkOiZZ_$8mK=2JV2~Hyq z$RdXDs#(3HCYXc4EE#Z43Dk>Q&a6!w`?Jk9oXH{SYymcvDFjc!Lk1a9&<^ssfs{=^ z0Vb0`#Qq+-1H7P9J{fsQ;s%<6M2u|%1|284z<|Nb9DocTVFG3hCKn0Bs{#;h7};K- zGpe| zS}w4#xRAqK5Pe8jS9nxp@qlO)34j3_z@b&7CRPL`UsGpsj)8`ZGK7&SPnN1Og0ze{ za|J{1C@@P)ttPOAK`dcI6sNmZ0BJSh)2MWYo5cPiG$C;sC(tTM_c%5)l>Mt*e*v^t z^<^KHQtZA|>w#}own=DR43jjwiP#no3EK+JdG^2sj@lLjKf$UA@1xqbaf_!D9H|hl z{yN;%3U;5@JYN8O%i5gWV5QCdf(pFh0-k<_wG&H>ceBd}qY^t7W|I7sS0lb8gPNXCLnt% zDv%`#(0~Y(NAnzIyc6EU2>&C=MSwU2rj_P2PaI+t1<@lHzDR+j^(&(UfSMQq`N~*ERXsQt<#4?i#Zen# z1aHwlhjzKAvmHTiCa}RV-(rMQK66f{TY>>T!_7GgVvXdy0VjT-%y_m1Eq%BCB|cw( zfgf<-1B?`CQ}m@CMm98I-#7v#=Z{6CK*T;;_=bMQ;Yq)BZ%IL>!Qa6F61TC_92#It zbc~S=VJ@Vk*-_mJa4rqnE9a|Qggr@UPfcw8@~kIN<@5l+%q(nlLZ&q6QS%wm9)NS{ zlue2;7)*u3p0r5i^I|bm`_nJ;^Q?DAg5HHj)!#N-sre?htCMc zJ}0N;%{gbw8QL9?w!G!gKYLRE${?`cEUXuYT^~tJZy2GX?ak#Q(}|A_!SwpBG;Pya zT8QkQosy_MRNYq^qfoktnoNF zaSq{bAl56liOLyZlYO(H;MDm@2Bzo`DI6phT9oESzYx-d)7uU%(j*!K($6wB?R9gD-v~Jf7SOM(rkQ{|ihB|f)Zmt@QnjRkV@ zNCaTpK=7dj6itJ0urUEELu4icdI3 zGJ>E~24|IQT)>S9%Xt5+zCk=T_0zfNJuTASbVcVo3!M2At^O%r1aC^imc&1N&wIZG zQZRbQcQV+aVnKm=C%`jqw?sM@5GyBl3Y8G&pa7M3dmFF<2bCA%(jGUqf!}v{;pYl` zK`7xcbdDD&$=53KhXVvq2@O~%E|hn$M+#hl4$e?k7SJpc;Tk_NNKMjC3e_3t0!6DJ zQttpP%(e!Ua16m@9=lS3&L99rhb={CQK2MI;{i)TM9|wa5u6Qy^6;W2m8>yuo@pM1s^oAsr zX06pyAMq|vK`bnlSCx@ozF-@=g^N+42vdlP&qy0Tg%{QsFs_)5)ID2VY#&fc5Rs_SA;##C+GqjnfrEZW z8!zP#6-8DS@Giz!jua?4+?ZOwU?Pa&R&BNZlPlQ=Jh+D+@LA_Gj1XfN>v#bW#diMz zT7DH2GD&Lk6DSA*DYRyh)#Q|wzM(05a}ks+xn zP0)#EwUzni3#LblwKb2-RTdjbIe_^EahaFrMNP-JS@TFverQjLsg;OGmV%jP(V|g+ zv6OreTY_{3rpJvtBOZ;30nUaUkEEH}A~-v+m=Thi7vOJkC7HYkPhLZt7GRs8xd-A# zUFEjC7@gLlKg3J`PCoeHD4Y;paqJIc{iSbRW|Yw9u?{e>e(P%iEYZ&lSR;$9r_9# wb}AaWSlM@?QMW1o>7G1M1pDZszVM+4N>J?KoiPx# literal 0 Hc-jL100001 diff --git a/doc/images/help.gif b/doc/images/help.gif new file mode 100644 index 0000000000000000000000000000000000000000..f08a95f8509c6b9b4b9f4880328064a3747866a8 GIT binary patch literal 327 zc-nLKbhEHb)MF4~Xc1t@NHxgLvMMQduB#1dX^HCY4DaktnLagn($u2G3mbRsUV8fM z-p7w_zIpTX)0dBb|Nl-)GbRZs{$yd~Vh~`^VE_VO=*d>DH{GLU?d~`$zLJxlyOo=xCX}&JS0JFaJj&Cse?swOL!)WaW~g}2)?#F- zE$s`b>d~y3t~xQnoQ;Q%*QS$mGh2QG|DL_f9QV|7NT!+8_W mb(IXv+>%UWEum%9dQ+~t% literal 0 Hc-jL100001 diff --git a/doc/images/hold-job.gif b/doc/images/hold-job.gif new file mode 100644 index 0000000000000000000000000000000000000000..0d20d50a60837bb3319bab6ca76927de568ba5bf GIT binary patch literal 436 zc-nLKbhEHbbY~D@Xc1sI%fN7sf#rgrzy(RkD+)^2RJ6`Jo7}LoJs;_QKPL7`e&O?` zrq4$X|Ga#>1!C4x_7nPaT_oSSWMi-&dkUexJxU_Z0Esa{fEuWkDp06sSvNk%v~VMhQc0QCR>@bK{O@9&O|j*E+not>SVo14DAzPr1-mX?;3l$2gx zURqjOYHDg`W@dJFc5`!c2?+@W1qIX7)6me+&CSiq%F3*)tf{G~!^6YCz`*P4>+0(2 zqobpsprGaD<>ch#`T6aBzr-i0J6(DJdx+ARyr2;N0BY;^N|_rl!cq$W>KU^z`&HGBUBT zu>b%7EC2ui07n2Q07VA=z+G-gEOL%WWM|22b_md@lu)Qz3#+VFi|Be0iEudO3V}lC z$#2d6q1ZbBY~4HjZnj@Wv*~YUe;$H@AB7$tHaLhjjEyHZCnqSA5)%}b4GsXC0c~s| zeHtX5EHfwq0~{V45DWu93MB(L0|_<)IvFi8J|_YtEfNGRE)~WVIvC2z2F(W~3J)59 zeKXdBGan9gJug2HjSb=rEEtfI5|tB{6vrt&${88W2G1lV1V0=;{1z4$7l!PJL1@vU zMvQJKjC3O1oC_4%=|Hv&1HA*!o|P!U&xgN{L^yO1`Gg9W1Y|&{T*(rRO8`80Y?8UD zW&i*I0%*{wQ-l6bKGv?y7*r4k4n{{CK{|(mfrAh+L*Q6L0N@ZCb7cIG;3L8h7kzsC z(BR=3whxC6B~64-;W>2bA|9iNArsF48+_*VV~v1UHUd7V_#q;K3akQbL>OV?0xSs; z7QA_|4Z(;M6f*o!u_HnT4D&KzBte>E#|00DnmvT}gHfbwZA9`)VG;wv5n52#WcbS@o=xDt^i`z)^>>3gOZQUL`zB(qF2SmN~IPDtX_hYP>;;Q==@OqD8^!NLzUm_P#!6+l3P06(;Fn|=`-zzPX9&``n; z{txW%f(0tnV8I9rxF^y;s->ysQL(uN3Ab&$@Yx08`EUei_;gS}4kd7aKn^DGvw{FC z{4>A+IjkUq3-Jy>tw(H1G-jZku&xLYuY~-{1Xxr@MYnJ2{;ST zu~OVcVygtWB16}mp=t!IN5cjrFG*0WfQ1+d*eCVG7t5f6g%@UxVN3u52vtoV+5{q! zd|6YbiT1JvGC~zfl8H-DneYSt4V!%J z04^}d(7_KFRN&Jc3-qucAWHTPVNxruK8daC$oV==JVeX+4*|q*2Lvf>0D}S>)Bpnu z#vZ#Q$Sc0(Gs)}-olKrJ*#QHA1@2@w-hjZ+f(L<+p5|*#Lg}U?l&F$ijPWT9UQ>hflHDp-bRo|?44?o_i0wdp%F7HE*n(ZG zfdnvMK#eeP8yB=7H-O4RaehF72)IB5Fn|mUdLRP`JOBnFNLf5aI2vd;ASXNF$zJ}@ zhZ=lC6%KmA0uJ#58|>gP5U7C-p!0$gydVNP^4AM?aGMEW;0FmP&8PlCMFOMwpoBe1 z5ZS0Ghz-2sFDmeW3PjKW8%#h17Vx47Y+!&9VBiEJNQVPPP=FD%Km;wQ69+~h0us=} zSLZpJM^Mv~891&%R%8KdTqOfG&B`scq7pkOFn}G@X^9uX$kATr1Ay${0ehLCYKBq> zE3%;lY{`cw79fG|rCgU;zpkK@b1{JDeydnE(I) literal 0 Hc-jL100001 diff --git a/doc/images/manage-classes.gif b/doc/images/manage-classes.gif new file mode 100644 index 0000000000000000000000000000000000000000..264d9f885af84e51142292004f42a048b02cab90 GIT binary patch literal 619 zc-nLKbhEHbEM*X3Xc1t@NHxgGwk|1luB#1dYme{l4DapFm_9Xm`pk+Y3!B!ip0It# z!ZT<0K6-fL!^bzj|Ncr#GbRZs{$yd~Vh~`^VE_V16uR!Pg zx_}9ff7&%KW?(t~pwWnjfs_5!MFRmjb>$$*54yZe?o0+Y%i0*PZK&{JVzF^}&|4$!J=?TzQ*YLLmzZ=akIF~>cV zp_qT+GH&KNHb!0^b>=1w|3)TeE{^%jnHDjv4NgChwr)cV^Zvv%ee;TG=Pz8WYFD1c z%d5%NbIF8QYKCh^&nicPZzIXvl3`HHUFtOr(;Az90+#p&QI^R65SiZe%XH z`r2RgI(r}MJf(yk8?TEAM=sgfmg{qU{n9-je%P=T%ur3uHUhL fg;)tgqiJY!SMbVxdo516uRv$9 zlVjiW-#mRx0(}RWT_qTV_^vEYRIu?onr!sILxZx)CqC#CW4OPHLsublQ_>1HzI}fa z9yl!N(_1KK@ZuB0L0S1Axj7{dKQ3!xTkDX>^We#;)gnIa3mQ8vF-S2*w6FWI>6y#* zRT@$nKbEXvJ+RhI%D}-Zvv*>~jXSd@t9f)>We<^;{Q1jtV#ErrNqZU=Zx?C`ZdD46 zY!HdoUdSmSf3Uc;d#fs2)PmC!iOWJnqSa{~# zzI%5rzj%J{!^by&{{2o%GbRZs{$yd~Vh~`^VE_V16uR!Pg znt%z9f7&%KW?(t~pizm3fs_5!MFRmjb>$$*0+nfOjm(S^a-lX?8a754u^mqRT*;Na zGw#4+8U7bBOcxuEwM$Cz^K-}7wze6vt5^qU@wl{4C~9o<)y|w)tHf%M$i*L?$;8jX zG|xS;h-M`oU1@|kD{vtNcruW=22`#^3U&rrre|7ip^i>_Z z*jSPrc1-qlW3aw2<>fMwo&9j9gz>cliGhoc_cLfcy1~5Z$?**C2ja1U!Y5L=16uR!O# zlVjiW-#mUy0(}RWT_qTV_^vEYRIu?onrw6-Sc)ZdVW4Y?arwTwv&7 ze7gCTs(@@-h2-zTbHD!^u&Y@4YweqMg9 zxIj_KY(WL_m95;b?*wpcT;wV$l>cDIiH}KcLgiLnPb72|73H^H{m~QRsOr&IYh5<_mK#xfC(ZEv3u<7zA|w!EV%FAaJHb= zaU$z7HlAA?h0U2on%n2~_)ODY{Vv94w*6{_)&=fc58t_C^e^n%SzU_`lbLyo&vm@X z{`KQV>*fZ2;hvvA63!kxvHeW@tR159MKLMl7&rc*G$;Heg3&~ z`|jSk^y0<651-!t`S&|5&6p&l_>+Z^i$Q=vhXDvcb~>>BQ&8y(P-MthwJzuNz5*R? zR?B(sjV(AGOq$udE_xdbN7cJ$^W#;DN=i_1XD>hPMHAv#(x9xIa;Bt55VC1gz*YM~u<8K9QM;EhK*9W-1UAN)LXP^D%5Z+;cQo=J39-`}kR3;OWJ@v%h|2nf?65Df8p}vED`w zVKJ41Y750087J|ww7owkB;wfjR6@W(q#=NDqeZ}hLWZVL&b0@pR7^>TWM+wBdy_c9 zC#{)nZh@V{0sdAS(K{;30$LcBPfBuotm4ttJ*!EZ%VX0a=4X!Xs~_y>c&L`;IA>wR zb_Uhdz7(#!v~&gL3k?TF)e}!dw0bV}*^$Cl!IE@QZ?2`rg$WuzzGWKlm}V!>4N&>a z=qnQBRLZo0hhbs6_5;zP4GPlJJ@my*1P&ZHs93VZ*LZ`vugfWk)VT8-F9vLT8z;g$ QjiYk6`HUDdCk6&<03mS9wEzGB literal 0 Hc-jL100001 diff --git a/doc/images/modify-printer.gif b/doc/images/modify-printer.gif new file mode 100644 index 0000000000000000000000000000000000000000..14bda3e71c9919376e9e96bf4d13f7bb046e45fa GIT binary patch literal 559 zc-nLKbhEHbOk)sXXc1t@NHxgGvMMQZs;diXZ;$Wp44*V5fBMwq6-zs|Zke_Jz^ZfS z_usv9>E(<2A3nYN`~P=ZnlVX8@h1x-7lQzU4g(N?>~vuLr=ZdopvaK1YF*CjeFZw3 zogDj~|K{;y66ih1eDs5=L_-5}<1NnF%nXMFf0#yCUuoEwVZ`QtU~!^?jbG$JA%z~h zeWBAGN@m+tDqV}m*~qUoIM$HArzb@_vDQe5)gY3S-zU+P!98at6L))n zh8G{3Ze&DY;;Kk~7EfMo^@OBA1GADzd-m=#s#l)ImD-QfP#BkiYc&*mUjP})z*19eG z4&+=&2s!KXGr;6TgQ(BYscE9X28fi0m8 z7cA~=vgqFG;J?$2SEQl$D%aKRI!>G?Vwt^SD)Ql(d%`MH@IBvs=Ocd zuuAml>xV0JpG9;%+8VY{H^0EwQZ#HP)5O(Qbx~z68CNlK%k)fSpV?~AUL16uR!Pg zihv1^f7&ry8E{`|Hk7bw;bneU_-N-GQ+K8W8IC!OvLUR0Ss7d64l#0gw6Y!C`AevS zZ_ADvzi>&Z{>1(=g}0w7J+<8m-5MG=N@Loay7ZM;4WeUgTNncT_*nd_Q+c`7U76Sz z8Im<-=}b1|XJO*93ForsUowB;TpjcLzPS`p~V<^OE=Hr+b2$$6OZKk zWLSi?OgxzS4z=^QUcGIYaG!yd&ub}1!UNW(hSYB#Z>T?CysC?FlU~}H=W0SnMciif zI3}zW+o|wGP9wvx(}9_tciD_zm1@t=mDtVTsV!*ZYM#IKz#ks2!%ycsaG7jd6twxV zX>N3ekc77DS)C=_8?syk6F3=WMe%m1YF}YJA$oaE#Gxr?BfB>6Uwd`9<86xLUiXZ) zRjlQ0(kX4<-xV^Q*1i|REM}oGy={f1$W;C94WeIGYO?bk3A%XZ=R}T<4XHc|6H*}*y^CnUxh7pGd<14vpEz!6>%QY4&ve>uB}(tM*u$=0 zh~*0aj!0x6HzDkv(CC0T1OcxjAXDO$YNXGu%!(~jZg(+7?vyLqy7<$y%2h8}_!c5O1#O@a zR!WRP_!jAB`?Z9$cdG_4C31H(A zdizN3T)OVI;oZx(uiw9b{pt&>?ju3M1^W$@co=a3AuVIfv^w~$y{pB-h-^IRve9Bg zZG=2w@aN}0nh$QUqw#^j(+Ej~1F`Ce!zK{J!PXLzHp!B$F;!J<`YG|1zggYpvXeMA z%FvQ4S$-^KZ{23iki0V_sP*gF|CtQpooYbnMxmBBKcy4M-C5$iA{&z@e5CS~(%)GY zwuySBIn~$SY5(E223JIZ}*wI++r^T@^^jv{DWCws3gD8=aCR3G_lbf6jnVq1aqNAh{ODr@msT`{UV~RXa zb|9cdbtSI`sH!zhz8kV)B833O#aR`3i#xZty1;+Jjb~JacFD}j%SVjU-XDP2+p*dK zeBV&f;AMi7hp^*EQtE!0h@tlH+VmOukfogbDLI z6u`|b))n)fk!G4+fU%3!vgav2879Rp@fd}_GxTc(nAWJ z9e*AbdbDXnrc(x{OOD=pkAS@z@ztpvHjzaIt{&cubs z;yQA&y$zTrab7GZzJxB>Y%X@P*KC&P^ZNDKs^mw4WnkgPw59do|` ztnAKQ#LZWp6HV1LR8dE*F%mz^4M-q^n;i&Mf~G9fl!MTf#EyhSwRaa<3^J7lTTdNh z%^4piRp5wfVPaQVUP*`CTtSe9RE%Jlg9c&fOqWb|IHpA-J2omv4vx(1HDrx+q^Kia zN-pVFlQ8DEjgV3<=3|v_eHCSoe{6XpUdmwk4OX+H0HlgZ#&RZ!b+tnql6tx62V<3$ zl0{-@Y51l+0YS26pFx3HS_PT$Ne-T&dFD=JS87$6WqL+-)>fQRijZYxrqk$Zi86!B jr?YWNDsBxl`U$Fts>&*41HCGWVY1e0>#evxlmGxb6oz`@ literal 0 Hc-jL100001 diff --git a/doc/images/printer-stopped.gif b/doc/images/printer-stopped.gif new file mode 100644 index 0000000000000000000000000000000000000000..76f45649b132bde80d5a90530f0cf990aa4f5278 GIT binary patch literal 794 zc-jFP1LgcjNk%w1VOjuC0P+9;;Nak@s;d70099300001gk-vYDzkiXxA^8LW000F5 zEC2ui09pW0073))Si0Q)Fv>}*y^LtUxh7o*d<14vpEz!6>%LuB}(tM*u$=0 zh~*myj!5JnHzDkv&}e`-1OcxjAXDO$YNXGu%!(}weV8v8{Hb9z$++MQBS{AMyne4< zPg!tsf`dqaWG`DLdy9O1et%1cW{D@23XFLUVl$E}mY<-ZqN56DR9c&K9d@8jryiYU zvOce{9C&d{6`PNLh*qjAvjj$XH@joJy)|yLZ(7L9e^IH1F zLyI0wx-^8frUUk5m6{($lP6iX&TwkxP?)kaCyX2}-JSFs9tCLZ!0u1?hk zx4T9zA5O7W3S386j!j09Ix3mZRpw$`N+@{m&Z!V1q&>o0?%loOjx9b{`_quYOaEm? zeBmB*TIHu7fAQF47gS^=HD6Vck>^l?Vfa!Pbqz-Mo=eSm=fP9kC6i!R8dex!Qr>`w z9*6ENg&|ewfq>OPD^Oa}{c(S6uiji|^0mQ_G<_92nSAtu+6 z!Xz0%BoKbnq+e+5r`BDI%qXK(Sk8qNLTowarFngYDGoeAaEaH2Q@|I9nu$$_A_SFr zxno678s`-Tl`Rn=T!+QMrhK8~IpiZ692QAY4l0u8RvAT_sG=?*I$EIbHE3x=j+G)2 YPqX2ntm^8kuqFTiJFzuv761SM literal 0 Hc-jL100001 diff --git a/doc/images/publish-printer.gif b/doc/images/publish-printer.gif new file mode 100644 index 0000000000000000000000000000000000000000..0b4f529b148eda5444bff6250c286e8eb7800e5c GIT binary patch literal 550 zc-nLKbhEHb%wiB>Xc1t@NHxgGwk|1luB!`b??~wG4DXweIelvK^jQ@vmv!yjwdm~m z{SWS6d-dwUr!OD={{QozM4Mm}=?hR~$XK;5=k>k>zttLs#jZ6uiaX1pu}p>t`!i<ylZ+~UXIe+<7oj-0&e=E{(v z!}YKD$m-Yy4D6y70XvdzOkil}vhA_Bm~c#tL*rVdux0?4BKwl|DOC*%8kt!y9#AQG zso*HiJUt;yq~($alZlr6gBpgNLXYfTwc!HqT%%}aLEE+MITA&h{so6Ej3)Y zwB_r?r~*$DWl6)20Zt2YeUvwo$EphHqbK1X*;^v-XMCrUN%ok?AI zfLo27=g5(oMIuJqLr(4E*qrnByMyEx53j#PgRxI`2<-s7-t+BYELWJe?fzP4>k|`V9gwEz| z=Us9q`Cr7FD0g$8TaR|TvQ(Ed#IiE*aH%sfS9Ww+bCof+F~nJxhlWQ^wPv-NtijG} zV47C7e8o!L0_7&n%2k?m+MBhu<_H*u@Mv)G`}(rG?>oSCh+k)Wp!EjtkT7O0{%Au1 zi;Wvr#xrp2*{GLlcK!a7ry38<%%8n}@ko7hGs!SeInU6_b6&F`fc-#|rTwovl@ZU+H8b9SE6dL<&}33^;Lw}y zD8ePd(&0Ao;Kpj<<-D8^}GU+})3No_%@#>))@mG-HyG;!hSvE(QSx9R?r(+3CRgPeG+GK#;{@)w-P5`wDcn zr#tp({NX8WW?($d=x~Eq&Ox!zU4(^?uc1LwK&AcY!EVk76{b$tR|gejE(Od+g*X1~%>!9xmJ| znP*St>iM{9F!F~j=E~Z?^SL3b9|zCQZ1V#zKD{&l@cH|O_vW|PF;@R5^gA&jHShEy zEv{Q17qS(&>bEzalDuTN!a+odN5({=soUXLuO^>K#R3)vCU%u+^$AxjRAz`|b354z z{8Vt(g42(>C0$*PKG+x0~?{Pr&f#9b`{{>o=nT+YFTwKdFrEb(HPDtWn zF<=!5;@!JAN#u%m_zgQ=Do-knKc{k;! uR)rFGfu+Fni7y)%nUCwGnYv78c-qvl_FJx;ZhOLBp;*t!>k6${7_0$mmCn2X literal 0 Hc-jL100001 diff --git a/doc/images/restart-job.gif b/doc/images/restart-job.gif new file mode 100644 index 0000000000000000000000000000000000000000..cdeb955ee6801a245ae7aa808199961cb3f54437 GIT binary patch literal 493 zc-nLKbhEHb3}X;sXc1t@NHxgLvMMQduB#1d??~wG4DajDm_9Xm`mBoOOWU?@n|JQ~ z{=0WBy?B1_{l~X|{{Q|@B2fIv!pOxSz@Wnb1Ry&dSpO-g^aUs~WUN}3^Lk%F4;QQD zy!XZojTcoI8ksFFFv{^ZEo!VXU^|+2*r8%hkDiV*V}QXDmLts{ggW?)BAKS=?M`G5 zdgoaF?%oQGeUI;QE>iyIyC5zJOr_H!mYYEB795jya4|ttXcsnm&nN=mc zlV)~d&E0#BX1DJ@zI)3ogNx99C_I8kj{` zBrJYhRB2>pPwBG|xqO77nLS1?=}b}jfuria0wx6y&Kx~pS(-hkQ}IC22|;GZH8P6E zoNDUz6Io7NsXUt2Jc%**sUoKX&+hsYMUskQoa*ZH4A B16uRv$N zlVjg=ZxjE?PZ$m}OeheLZA@TRC{ST&K5iiDyQzxp&|?*wMH`|V5BxMWnSZg-fs2D7 zn(1Pq+xpw-Z1**PgFdtuJzEPgI#8#cz}E3@{+>6;ZzIdSroZi8|Yf7oel9xmNU zmnI98GIF^waPZ9K*Wl)2%;DspJGWEwIm@-+oClBMKW%uN`ttQm1{NOM2L~HIu+2W0 zo3~E0t9bE)gYE2+_YN>_eB|7z@+@MHaISJs8cS@?Pr(ERCXY*p7QNA$$uP;OU++16&B?Lv zxwi@bRyDJ>g-6g#^d?s2if9 zN4Sp!FNk1Z;#DtDs1SIOlf&R!!{!;-q-zwJ)!V0+pq#|d*x%b3Ezrxz#mm6S@9Ue% z!Q;!{?l48WX@-tK__R&^OvW2F@6g-2&1C03t=+~^`}?QHOx&)^Xy?z&(RL&#FnVjg z-f6Cl8Z10~y!P`g>^$9TQWko$@$hp+UyEjBd8_bW83g7t96^M zBf}lzwngVBv|M8H^A-)9t`^I+Yv#$eB%hgVZ6Y>5wjG$Pz{o8jw_tUILF+|#UQ|-!vF*zI~`d6DX8=XC^BTMT9@;BUxCi~ zEm|T^D)za2Ht3vtppk(`j+tSSXn_O+FYBv}ngtR;tjr4{7zFH-lOt^SW^rB#+8V~s za{54LjPF0Tv<4Y90okmE#-`?$26h#FW^O)yJ|5R5uH2B2R^8mZ9M5S6O01pS985*r zag4m&>J?rr+8n%EocxSa!WbfAq8YgPGZUhhuXL-}%eZH@CKoTumZc0#Y>e@IRV!AN zd0x20aYf&vZqCC;k6YW7J2#um&}891rMdOV%voPPX$zP#zTdQTsq5?AavUN*RN|I0 zcs$@KP*~8|=>F%IqQ?ba&P|n7(*z!D<#BMS7Yod(xv=pvU$w@+;AL+nKVEWbx?lHt9!mu)k2$w3H<1sU7snE{S84QzNe?I9d zoT$xVP;fzkm$@-Bti*@df`8Iw*flRdDYvAk)*MsgmKOg*F z>$8BF)k&1|h~7%gF4o|{1C9dx?_@y9@T{{mLE(WwrYvG26G-re4)r|o+H7;U=08>2MRa< literal 0 Hc-jL100001 diff --git a/doc/images/set-as-default.gif b/doc/images/set-as-default.gif new file mode 100644 index 0000000000000000000000000000000000000000..fa89e660150021464d4a26d1abddfbb22e5f0408 GIT binary patch literal 585 zc-nLKbhEHb%w!N@Xc1t@NHxgKwk|DksjCZWYftFz4DajDm_9Xm`pk+I%Q|-LUUK5} zuA5hnKYw=T16uRv$N zlVjg=ZxjB>Png)53@UgS+`HI2ug|Rt;oKE{L#+<6Pd-{KG@Cd&O#R1*+QhT@VI$O=S&}&mO zhw!GIi3SS~w`b=Ww0LYx>S{H=6LH5w{lEe7(_FhEJ{?wOa?w35V3T~1`P5cMxswZ1 z4lYUDT&o?qq0!`0;~G)xUn&d_ULU+5$|WY!$*$nY%+A*rB^kl*aDmOaQX==1vX-PV z^97Nqr<&Az7}!J{a+@A7Hg1pGE?Lm9N<=M7e)+N!Mho8F&U9vFRrtUk;gE1IB!D`z_K utXNie{fU=?J&)Vpe>`hU9R+13N1s`-=jXu*Lf$%Met(rVN-HujSOWm*mE%zW literal 0 Hc-jL100001 diff --git a/doc/images/set-printer-options.gif b/doc/images/set-printer-options.gif new file mode 100644 index 0000000000000000000000000000000000000000..04cd56bc7213f7e483190631b9657b80e88e74a1 GIT binary patch literal 649 zc-nLKbhEHbY-SK)Xc1t@NHxgGvMMQZs;diX??~wG4DajDm_9Xm+RXA*E4p{?Ty*~Y z{=0WBy?B1_B2fIv!pOxSz@Wnb1Ry&dSpO-g^aUs~WUN}3^Lk%_&iO6c zB2OyzxqLS0oO_^=fk%#+VbWF;Be50tA4ud%aP(g;im*{z+IYoq4wsHRZ_^?{-ylXF zR)>Qt;x;#>CZr3?W;HZ6H90o7v8(7abMx`@@whhdPo5m6o!_S0J(=6nXvRz(CDtx( z4yJ1E07hPJ^4#va?CpOi=#rcymMY#ammuoEAwGdv#b&2sJ-Ao3ThzqT5>B zl}Y~KmXigmt{e>5&SK;)=E2#^WW=9xx2j5wGwp1ub3D_V52r8KMBOoI=4~*$V^%4$ zWpiM2SM)O8;2xbD%YIC{zqRamuw%Yb!lNy@{@RO0+D?iyUGphgkZ^pF+cc3oe%=9P z9~&RF*SQ;)JW;FPvaQ~?-r{3PCesnSM=zRU&iz01c3Y4ygIL97KfRe82@jg?-FXni H!C(ylBFZJX literal 0 Hc-jL100001 diff --git a/doc/images/show-active.gif b/doc/images/show-active.gif new file mode 100644 index 0000000000000000000000000000000000000000..b2e8cbe22ce8f6d845692cb998b8b2651f8cdd61 GIT binary patch literal 662 zc-nLKbhEHbtYr{kXc1t@NHxgGvMMQZs;v!d??~+K44*V5fBMwqmCHJ|Y@T`G;OevI z_TIg7>E(<2A3nYP^Y2$$nlVX8@h1x-7lQzU4g(N?>~vuLr=ZdopvaK1YF*CjeFZw_ zO|(RwRP1y4Y|tV5;G%(moVpv+gaif=?uLi#5+-4c?2H!zmWXjXCNxw{VCQEzB*^fE zfr))lR@qfXuVuwI6nr?DN*SGWnUvT~JG;7jdQI3>^qIN&`1yF)Qd9c0Im?YQ<~YyR zo!_a%I*FSti78;#hDu)zF8<=+YE8CqO%DFt1ZJja=jeqDkwqGeyosSpw97YDm%1Nf z%gr{hXkT>i{)3(g%9Hjly)eg}Ymff2Iq$SSmn%G z?&*h*-7U++)pInLbM!VjiagSMC1b3Retyb=vJ*%8YTLhkVBt%UsCsy+ed*fW=Q+&Y z?0R=#x!JBmiW=gr>deRI&2TncnJ`i8cNxn+!yl6z7)uNdLb;#(NqNA1BaMVA3nbQ^Y8b65`p4R7Dg@x0R|lgAOP9v!1_-?r7u8{A!F6LoY(sbbhbM= z_C5DD;ctG@;C|SlVvYo-Lla|w4nvzhWK;AK=wW13 z@GY5f^Zk!Kait1-*|_=m`FPkg@~d?@I}&=6Qu?cvSnIjjmh%*2vG8%N=v_PUVwFHS zFEA$OG4nAww`z0qKYiM^_QHw2+bJ7jSe|4V3KSjsZjj5!k?}*5$^6w%X^#Rw2N_mj zF&2ppd~z{d4<{r}(%ej8r1I-EXx%J6jKi?a-KCxlG=X}L~?%bZOj+vHE>OGT$gECv@&9azzwB*+=0 bw&nXh-u9i%+=nYJw0wAMlqJK%$Y2csM-%&M literal 0 Hc-jL100001 diff --git a/doc/images/show-ascending.gif b/doc/images/show-ascending.gif new file mode 100644 index 0000000000000000000000000000000000000000..50e636cc9536bcd8406bd60efc3cd89f509a213b GIT binary patch literal 638 zc-nLKbhEHbEM*X3Xc1t@NHxgGvMMQZs;doZ??~+K4DX+iIelvKw3+2AmUZmjz2xlK zy?5_idhz_;hmUXn{QLc%M4Mm}=?hR~$XK;5=k>k&a|+n7H8kXH6ks{PSsq--vO5^Fy< zM;cSg^wpl;z6{*_*@5ddIYKo#`IFcf894bgQka<{8F^EK6Xwi!*vMSE+UW>C7c&ok zt*&|f!h820H1;a@@7A4jpM{TW$3wjr_XHXl-&~rn!5AOM%*W(1RXfR6Vg@g3V+1e9 zhL2OV1to(o>oIy4>Ob1jS-fRygTRrw$NP<$IvSTdG4S;%{0Uw)CGk^A-&BL-Wf`5! z6BOEv>>u%%@}+Xyrm-o!a5f6z*E879av|b`il%t@q_rp7dQY3mCrGV1dHg7&nh4h# z+kg%wM}Es#B~_yn2O6*Sga*cBUtpHfSatP@QHDb2%C6-G)3gd2R3EGAs|(z3TB_~9 zv_yl);sfiM>EhX%pK5!Z7Hpo=ba|1%8jfGx8He?)j&-C3-k+$qe!B_hZ!2RfHh&|2 zKIZpZxYC%V4sXl$fAQL?F8$Q%gLx0EWDhJ)NZ#NfK5LJbn8UZCRl2I1R7Q|a`` vHaH;TqFDD&Jn@|ViKlbqvlti+xo>S;;kn=b#5}#35AHWK-FOhh!C(yl@{Slb literal 0 Hc-jL100001 diff --git a/doc/images/show-completed.gif b/doc/images/show-completed.gif new file mode 100644 index 0000000000000000000000000000000000000000..2a5c0e9c6d272cb6515ff5d4a0c9628a5408c982 GIT binary patch literal 764 zc-nLKbhEHboW>x+&?3N)k!p~eV_j10Tw5E|)*j#889r%B!St!gE0(rz**s(afmLVD z?zwyW(u?Q!K74%p=il$NG-HyG;!hSvE(QSx9R?r(+3CRgPeG+GK#?J1)w-P5`wDc< zm*{e{TF%qIXv4$8{~<$yqhDB=(ZhhDi}e5l%a4#|_XS&X>^gfGA8nM-+2`7{i17py z3!lqxLxpP(KfO^9aK9K^&k*ZZ$IBAJ!c@=btjnatZZ>K16b6pysWWHkva9H)@$vKV zu+^2$)>yEJhh;_aibkD{o0d;fVx7;;#?%wIY=3h+7k^Pmyp{(SGZQoC(u4c+rsb3| z?#pB3g5bKe@TtY;p;9LL?M=uW-?~H(qMGPE$Ppg+GzqqhGfY<2iM&(skSN~WxsUwA1 zApTHL zg$vL7D?V|oNcdEpURkD8Ag!`tMUGokJ- zpKep&QvIpeWpQaml8bQ1R>5S!r6-hcIf;GTpp?G2K*b?z@q?>}IN~|KirdNeB|TKL bDhPc#J>gP;Sm^dU;?HIVJakCoV6X-N*$p?C literal 0 Hc-jL100001 diff --git a/doc/images/show-descending.gif b/doc/images/show-descending.gif new file mode 100644 index 0000000000000000000000000000000000000000..146e5f51008788d23bfe1d774eb1e98bfd7877da GIT binary patch literal 659 zc-nLKbhEHbtYHvgXc1t@NHxgKwk|1luB{Df??~wG4DXweIelvKw3+2Amv!vkz2xk< zy?5_ie)0U?hmUXn{QLEvM4Mm}=?hR~$XK;5=k>kg_AFmkvBbrnTd^&VUI@I;oAKNnIn^&&u?Yia(Ue) zCVnnv9{%~d77a_DJbl*Er#ylGn9ju|?|q+}yk8<<%E%RVX+~LcBC`yKM$${KWoC>* z8b*`37#O2?IT|wCofHqZUEHAX+PrJNN$czbTN@No=AE3}{EunE%H@yz`zC25pPKT} zsJ(BdMe(*3o=OuGx~$Tfu1@J&!fokzN#Vy4qbm(2T&}OKs7}2wKiFNCWp~nn+d^9R zBvLXzq@KPWx07#E@reVBH@obMbJ&uEz6mXY$rPm;5q4f5wt6!cQ%}M%fu89QrU_@Dpe5 zF{u;53lxfOiEu4gkvH-D!TmmgaoNX8B0t@~b@;Y~+sEVmc7A*!YtmGf-R5`Ws%71G zDKoIkV@?;xhi}e{c%!<$9nyak$fM65G_Uylq7RMF#b2?gKComKa5%>FyGQ8CE(<2A3nYP^Y8b65`p4R7Dg@x0R|lgAOP9v!1_-?r7u8{A!F6LoY(sdbVQz1 z>~r~SaDvx{m-%5~k_rPSo5My1iLwUA>~US-=ujKabW!nG-tPNv zm|vPkSjh3YeK&8|FUO^oUZ<HSB~3!a#oy?FcbwLo^k-gj>|2|UwewPrfdctGCYz*XtM0Y^6mj)n~u54XN$JTAtQ$YQYI z0He4uBdY-8g5qZ)tejb@3uZhDZdMDOClK+9A$Ylgt9@VfIuO)jYyY+GHfMEk60 VvpF^)_D*xU(x*p~ADkE%tN}sn<{|(9 literal 0 Hc-jL100001 diff --git a/doc/images/show-previous.gif b/doc/images/show-previous.gif new file mode 100644 index 0000000000000000000000000000000000000000..b0c74b2870d2739ef4cdd7173147b17d3d1520a4 GIT binary patch literal 582 zc-nLKbhEHb%w`Z_Xc1t@NHxgGwk|1hs;v!dZ%^p%44*hTZ~D~a70WudZkcuP(3&%6 z_uRRC>BaMVA3nYP^Y8b65`p4R7Dg@x0R|lgAOP9v!1_-?r7u8{A!F6LoY(sbbdEbY z_C5DD;ctG@;C|SlVvYo-Lla|w4nvzO$(DqvY~^&oR=h|$%R zs~>Q2Fhnz5Og#4f_x}bxb`^bQZa#iK9yX1V#xVYgPCX3;{rXC*t=w!(Wq!R8juE-u z8eIHIfj(i2)|T>et20M1@+C%QGc5HfW?|teVoOgoFsqt=^3-YlX607?be+CaR~WCH zIVDib$Q8PH;k4`V;e1Ta-Rmz$aPV`#pToe-wJoCHQTVh6EZj~kh63+Wq&)-z=1DVg zYsFN2VC!oYP&8B7c)Wj0hr~|{?iYu`nEaV}0uGhE^lD&WJ|Z-OQKUiWpv^2RtAGg~ z8XFV1HnDtWTF^Kn+mpeffK~5$XNYs7;9R`4DO%Zm zlC`0GL!%a#kc;;NlfETvU!?waf9iIak^TQtA7j9@^@6oUavBQ1loYoFEd2GY^|TA4 zR-=lb`_7I-4iaGnBLA;0Jr>F^)!>uJH?hn#KKGJkpI9#Nou0EmOG(_cCF8`(jGZMx od+#pT%)qu?;?H3frNxCE=2~*`^Kup+7HXU6?H~BKl7qn-06`1`KmY&$ literal 0 Hc-jL100001 diff --git a/doc/images/start-class.gif b/doc/images/start-class.gif new file mode 100644 index 0000000000000000000000000000000000000000..8d66a46a80f0b50fb86be1c5c6edbb9e5373c346 GIT binary patch literal 498 zc-nLKbhEHb3}p~uXc1swn90B}k56o=l*Sr8yS3)t+r1+;yQLmXZ8}pw@lxN?+e;5U zJ9z8E&1YXvxkJ9d&nLmD!{#0f8%U1^;t+}bsYZuL0eDI;}qSJgFOiVl$4h=VV z7@UeR3HZ=@t(l#p$DrWC1BXe< IA0vY`032e!RsaA1 literal 0 Hc-jL100001 diff --git a/doc/images/start-printer.gif b/doc/images/start-printer.gif new file mode 100644 index 0000000000000000000000000000000000000000..33660a0115bf627a0b3d41852bc7aff27dbe84ae GIT binary patch literal 500 zc-nLKbhEHbjAjsFXc1swn90B}k57E5r1UCHll3N!8|}llxCiYDN*j+n<8TeQjnD|{dlb!k|X#3A{YV@4$+t0wr z!==s?J6+#2qj}x>4Gaa!?fj{lvki96*Yt7C-km3q%f+*2QxI2^|G|R}b5AdD^5x*? zy54!-NMQTMd-n~}&F(&Uy6%yg`Lov>UZ~W+`M6>89erLqMke+)2KFa9|K_9!O7y*x=|kaZ${N z?m!1eX7)cttUD&D1RLA&)O=xi!0B-=(`i+%VuPT^vVxq7tk13{w+uzk%@Rp%+cICb z|6$usj)0y%XPK!yp@()HxG{N4f^FVZHimT#mi${XnjO98-48c=@K;u*Ic}HGe~$Hw J3oTd}tN{+ez?lF5 literal 0 Hc-jL100001 diff --git a/doc/images/stop-class.gif b/doc/images/stop-class.gif new file mode 100644 index 0000000000000000000000000000000000000000..6d84fb2f629726c9e182307e13afe5d4fe55ff01 GIT binary patch literal 500 zc-nLKbhEHb3}FyqXc1sI%fN7+h4Z46939R_y5EnEeq3DgqNC&O!bKmq zZ25BL^sgt+e!qM7_s_4iG-HyG;!hSvE(QSx9R?r(+3CRgPeG+mK#;{@)w-P5`wDpG zvsfl;IvpWc|u&~^IXD%innUZnMaaP`L zMz)~5hZPnQ?d5)f`^8sOWhk*!vxhTrc`)#?YPh)Zcrv?nX$NpkX69fIi3#I$WbBRL zja$sV)W9^YaqYUbh02zJda-M{IdvP>>kH)QyRD23&|r*B+NOETNvDCGn~RG-nA?W+ z%C(ezd$yjrb3fH=|NSTV56#S@8lLVjV`0J~ zSyl^&Sm_TF9bK)tOQIHiE@e;%;GJhGU~uvLv|T(#yC!ValeDolyZ2Xi&N8`OLh2mC K%L*-67_0#>=)E-n literal 0 Hc-jL100001 diff --git a/doc/images/stop-printer.gif b/doc/images/stop-printer.gif new file mode 100644 index 0000000000000000000000000000000000000000..1c71ee69f2d532d2a7a64ed9dda5c20e1c1470ae GIT binary patch literal 501 zc-nLKbhEHbjA9UBXc1sI%fN7+mFuFEoE*Ads1BTqNC&O{DmJj zZTx!X)XyhR{=9qt_uucdG-HyG;!hSvE(QSx9R?r(+3CRgPeG+mK#(D0)w-P5`wGsm zu~^P~f5C>QiMgM#Ya)Y+n8rPYg9)sG&8$KvBzWXJ-4=cjU}$AL&R8I-mB={J@tEJw zTOWR$b~vRg!_S_qQ*QUqrbaWoHdl$ol8Zf#i7S|o)!Eg@)5+b>X+}y!{8WYs8ob=< zOldRqO|x28uUT87Y&mCEtH0*fob9awg`B+eTIOxtId|59L(3RA_=19x59sL#u(&dffMf&F&DRwhn9ZN|^KU)NkxsCwwo zC@#wVNkQSTga0yib}5q&>94O$73QBJ`{2t0hGupy29=Tx1q{rcHN{3&7Dtm3dYHIm z8eWMk;AUXtH*h;tc|lB}+`=l)%jo^d$-U8BCJ`DYZF?i;WlcJDlk@quEdL%`mu(-l zPK#y6u>@Q&=x37or8Ki-hRXS-d7{xNPj_79SfOFGRiK*DJ7#N1QO+D@ABl6jiqyEY M{Tvs^a4=W{0JWdO@c;k- literal 0 Hc-jL100001 diff --git a/doc/images/tab-left.gif b/doc/images/tab-left.gif new file mode 100644 index 0000000000000000000000000000000000000000..4f3deebddda9caf325dc0aee1baef4759a86d2aa GIT binary patch literal 46 yc-nLKbhEHbWMN=oXkcX6y}RT8|Nn|VSs1w(7#VaJfB+=Jz{J`j&$u#%!5RP@jtX`F literal 0 Hc-jL100001 diff --git a/doc/images/tab-right.gif b/doc/images/tab-right.gif new file mode 100644 index 0000000000000000000000000000000000000000..5930ce2a61d0c2fb0f7e1a6cdc105429d85f70cf GIT binary patch literal 47 zc-nLKbhEHbWMN=oXkcX6y}RT8|Nn|VSs1w(7#VaJfB+=Jz{J)fn7ERMmBAVSCw~fl literal 0 Hc-jL100001 diff --git a/doc/images/top-left.gif b/doc/images/top-left.gif new file mode 100644 index 0000000000000000000000000000000000000000..1af936fac268223b110ffae375da45c5607c1f9e GIT binary patch literal 473 zc-nLKbh9u|6;r1yho_Toz1qDI1wb7lO zDLp-Dy}fDErsXbLRJMM7{qEfzd-inh-P^TqU-$m~JqHi=9Xiy1`0#`yMnNOWNpE~8zJ;9%qtElciXTs$aR*l;8GWbc6;r1yho_Toz1qDI1wb7lO zDLp-Dy}fDErsXbLRJMM7{qEfzd-inh-P^TqU-$m~JqHi=9Xiy1`0#`yM24eAPD zVQOKiWo}`rWv?$~nO@b;Sy9D3O@NW9i8(WXgOP!WzdnPRNua8vJi0!wic5&KWQ7ph z{zHdXM7AC|u`RABD3_7rgpgo(E(7D4!-7p$??kfZU-Wa96@B<@1=rnIubA61W0>AO z59G+*9nA3E|Lf}IvxHviJzOZP$S}Wh#lN$apO0T^^q4W{$F9lh!E2+c4!B-?!E%Vv zgqN9-X$SYABNG+p3Pe~cBpGIK)PIe-mgBu)MnGECMRnDte~qOMr#~F=EQt_Ql+h94 zz2108f`f}oAR##I0%M<{;vXI^6NeRvue}m)??}kr-dwOF=5XdU?!~hr@9Bjuo8~3f zr>-rRpd272HY4*^o};kpfuKdnp;=NYodWXq+PoTPR<9J9JCz|^&F+jP7XuT=jHRa5u%O$ddt7Yn`mFI$dsvND^8}^** znD*G%?Z*e^>ayJo^V+>LqVkqX7_89iJ=m0cw{2PEhOX6CHx1<#A|jtnY`lEpv#_<* zlV-N1zXAh~u=%leba5yqIGkaA)SIp#vM%7LXvX=uhZ|bnO-*!Y-TzPHLR{PH7Db-YjXmVeYTVo3dcj<`n$+_?^vT+Nw&!_Bqu zze!6w%U25#2gS*{KRX$w{wVCxcJSJGNi~Tf;XvGShqNHgD5J`&TI>=9T+H@@Qb!qW z1QptuSX>+&3Q9Gq&uOg#M%FDq6#TZXiJZVFBCEi_{ME!kPj11!g{K=f zZSpF3t6yRia6pSa@nf4=&YG#SJhWY%;zKqp4U}2MYP0B;$5)X9$E1J%yQsfu7LUr~ z4Y!3RFKvt{Nt}^hQWn-Pe%rGorXkc<+$i0(sIX`P$=%f&MfEj@bbS&dI| zUs{Px&(x?ZHnGx4e;4`Aj9W96t<7=ip1!K&2^>kL%o*LME(Vu7Hf%WIb6GW9_h-z< M8!6LeeFYe-0je?nl>h($ literal 0 Hc-jL100001 diff --git a/doc/images/top-right.gif b/doc/images/top-right.gif new file mode 100644 index 0000000000000000000000000000000000000000..2a268631cae7ba3d063820ae3e4a7319d6d3d926 GIT binary patch literal 121 zc-nLKbh9u||M9XPh}R6BFq$ z00Bs^1B;#ji=*Ezi{`V|`kl{tXJv4uC8SJ$xpv`e*&5K{f* zfVYCxg#^x@wddde4rEucw)JbNkJkuE)9ujV@9*bj)9$Xpbn0HrOz-q?NVz&(mTvirL zQZXks@H@#^N_oxEc&x~2EfW0VV#S)H$9ifOFn$Tkn7LJr@q$|7>j(`8F;+giWi^ct zl;y2vdQ3B3;B`tE?%59>6x5k!pf76U)6d4$-0lu&e Ar~m)} literal 0 Hc-jL100001 diff --git a/doc/images/use-default-config.gif b/doc/images/use-default-config.gif new file mode 100644 index 0000000000000000000000000000000000000000..5f1e7219ec937e607d3fe240133894f03b338c00 GIT binary patch literal 864 zc-nLKbhEHbJjfuz&?3N)k!p~eZCzUITvr>^)*j#88Q#~QF@0+C^qJ+$m$dHKG5_qj zeRpnOeDVC=hmUXm{QLc%M4Mm}=?hR~$XK;5=k>k9X*!NjEA$jm4q(e4z|up>umK3n3UL|@jqE7DI%W*CYvuqxj%5Rg+> zws_#tvYCJVhl3I5z%uceu@b8R7cUFrE^Y=U zw$vs@UT$^fWnFblTzpPpPM!lUw8$!{?~)_$KOPF*sdo0f2gD*sE^vB|^P$0W>@Yhz49 zn(%3V^Y~Ji#%{J2iKJy5iW?FH8y%L2X{0hOjc7>l5;v%9YG}OFbL-MVy|kAaCt#>C*>l;_PxC#K#O{CdETDX?@G50mqIN8jzbe4jdn z`sJivadOG#9C*FvfG+boadVSX4-7umzMGMrxbf}BC#Mez%qeL0NetlPIC9^af$^qk zxr+eju7e9?*RgzPD|>W8gilgOWa5$Ht^;CX5}fPA`1QgoRFAfbdomq2RhX0}XmqdC zaZ!`-A%`1WxfWBM7@jf&C^d3L7^eg~-K>}&Ccbt-NV~pRpqp#{-H0~fccDdrlcdTX zD)t0V68Ec*;N*OiZ@-s8rR*igh1h;yk*yqgi3fsCNfdqi(ZY08_kx3zo8d|Ixi)Vv zou2!nQ*&C`RvQ7u1(#Y_Gi2+SW~ti#G_`!(mU_&RYmV-cDK}Rb@fh?nOr3PglYh#} aSFctdS+He>vGt*>*K4h6t~hfrSOWkFYJ+qD literal 0 Hc-jL100001 diff --git a/doc/images/view-access-log.gif b/doc/images/view-access-log.gif new file mode 100644 index 0000000000000000000000000000000000000000..16c953b297a78ecda71cc55d231ea08c549419fe GIT binary patch literal 638 zc-nLKbhEHbtYi>jXc1t@NHxgGvMMQZs;v!d>qzMC4DajDm_9Xm`pk+IOFMS%TyXZ> zzPooWzkG53!^gM3|Ncr#GbRZs{$yd~Vh~`^VE_V16uR!Pg zrho~LfAaA&eo&Wlc;N6yj`=84Lxn+IZ|H$U1{0B$N1X&D7Ho;pzj#8LV?x7$mv2Hh zU(jL;`#47}pnsLOg4Kn84UJ9B8f?7${M>Q6>?(RC+T5H@Et*^fQ(I=tWKd!?;_lRR zV&sjsk6T#o>#xNTsL9FC$PkrQwT&rs>2l`nTR8Zf*$y1i_Fz1@rHEldIu|ofrM`LX zoa;Ak*7qtKgl}AXorRxk!!489a|Dby`51ZJ+!;1SMRDZtG4Zl}nAq_@wBmx4sWo_@TG6+R#F5BC%;PIT}{q>VJ-fV7GJ~3J2Px=SVnaWE~PuB{2 z^nrQvGT%J4=$_dXZQb*H+Be)dV=+;9zQ6vdr3nS?LX2#DQgIYNFEt zCiX>bHN3w~Ud^p+mzm=`;oF+7l8bY6x~?(2@fY(*H1OWw5+}^maCP4*Rc!~Rg_=A& zW^ccd6nK1H6^q}89`&7TT$1e~Ht#&?&|95kqy1ufNtd?2NX)B)T`dGUhX6`qk99 zA6fA5cD-MnNAd=bYt8$mU3uolXEHFFa-Z2a!*l~vuLr=ZdopvaK1YF*CjeFZxE zogDj~TidW~m~Y*1pz(t(TNmqr4+%e{Rwu8vr}>vQP59=&LK>Sfp9j!q3&Dlh~o9#A?Ldrs>GY%k99-z{T(CQ`;QMxR5bp zM%>cmm?fPH7BZ~xW8&vz=E>AI%jw>=dyj6VvH@?D2FJYauDz>H3K((lMP#`#aPV_q z<7V5)%*Vvb#&dCg@Y0~huo)*#X*_d3*Zfdd!1Cmmui6W5=`opq`u6X?=C_ZB88;-@ zHk#j(h{<>#zF&+*x1(khugs02hk|U)&Ky%blARW43Ni+|#UQ|-!vF*zI~`d6DX8=XC^BTMT9@;BUxChX zC&#|$);25~=36%$nE1h#t&5f6W5N%q)yi210+=|M9S$*a2n6yU-mv5JswG-&ObZIC zx*I-tD_EU*_haV5j}-E@G^m4ViIUO6*YioJg`t>uWYAdlCao1@&GV*de zM9y{f@e6FwWU^u6a$n08lDKfO-ReSS#yyM-Svh{2woK78E1hxj)M?{(Wdq)94bGLP zr!!8!w)2#LQ8XhDM=*a>9rtsNwak1>lOL|q + + + + Home - CUPS @CUPS_VERSION@ + + + + + + + + + + + + + + + + + + + + + + + + + +

    Common UNIX Printing System @CUPS_VERSION@

    + +  Home   + +   Administration   + +   Classes   + +   Documentation/Help   + +   Jobs   + +   Printers   + +
      + +

    Welcome!

    + +

    These web pages allow you to monitor your printers and jobs as well +as perform system administration tasks. Click on any of the tabs above +or on the buttons below to perform a task.

    + +

    +Help +Add Class +Add Printer +Manage Classes +Manage Jobs +Manage Printers +Manage Server +

    + +

    If you are asked for a username and password, enter your login +username and password or the "root" username and password.

    + +

    About CUPS

    + +

    +Happy Computer and Printer + + + +CUPS provides a portable printing layer for +UNIX®-based operating systems. It is developed and +maintained by Easy Software +Products to promote a standard printing solution. CUPS is the +standard printing system used on MacOS® X and most +Linux® distributions.

    + +

    CUPS uses the Internet Printing Protocol ("IPP") as the +basis for managing print jobs and queues and adds network +printer browsing and PostScript Printer Description ("PPD") +based printing options to support real-world printing.

    + +

    For Printer Drivers and Assistance

    + +

    Visit the official CUPS site for printer drivers and +assistance:

    + +
    +    www.cups.org
    +
    + +
     
     
    + +

    The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software +Products. CUPS is copyright 1997-2006 by Easy Software Products, +All Rights Reserved.

    + +
    + + diff --git a/doc/ipp.html b/doc/ipp.html new file mode 100644 index 000000000..7542acd20 --- /dev/null +++ b/doc/ipp.html @@ -0,0 +1,1473 @@ + + + +CUPS Implementation of IPP + + + + + + + +

    +

    CUPS Implementation of IPP


    +CUPS-IPP-1.2
    +Easy Software Products
    +Copyright 1997-2003 All Rights Reserved
    +
    +
    +

    Table of Contents

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

    1 Scope

    +

    1.1 Identification

    +

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

    +

    1.2 System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    +

    1.3 Document Overview

    +

    This document is organized into the following sections:

    + +

    2 References

    +

    2.1 CUPS Documentation

    +

    The following CUPS documentation is referenced by this document:

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

    2.2 Other Documents

    +

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

    + +

    3 Overview

    +

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

    +

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

    +

    3.1 IPP URIs

    +

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

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

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

    +

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

    +

    3.2 CUPS IPP Operations

    +

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

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

    +

    4 Operations

    +

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

    +

    4.1 Print-Job Operation

    +

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

    +

    4.1.1 Print-Job Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

      The client MUST supply a URI for the specified printer.

      +
    +

    Group 2: Job Template Attributes

    +
      +

      "job-billing" (text(MAX)):

      +

      (CUPS 1.1 and higher)

      +

      The client OPTIONALLY supplies a billing string that is logged with + the page accounting information.

      +

      "job-sheets" (1setof type3 keyword | name(MAX)):

      +

      (CUPS 1.1 and higher)

      +

      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.

      +

      Note: Standard IPP only allows specification of a single + job-sheets attribute value.

      +

      "media" (1setof type3 keyword | name(MAX)):

      +

      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.

      +

      Note: Standard IPP only allows specification of a single media + attribute value.

      +

      Other Job Template Attributes

      +
    +

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

    +

    4.1.2 Print-Job Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    Group 2: Job Attributes

    +
      +

      Standard Job Attributes

      +
    +

    4.2 Create-Job Operation

    +

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

    +

    4.2.1 Create-Job Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

      The client MUST supply a URI for the specified printer.

      +
    +

    Group 2: Job Template Attributes

    +
      +

      "job-billing" (text(MAX)):

      +

      (CUPS 1.1 and higher)

      +

      The client OPTIONALLY supplies a billing string that is logged with + the page accounting information.

      +

      "job-sheets" (1setof type3 keyword | name(MAX)):

      +

      (CUPS 1.1 and higher)

      +

      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.

      +

      Note: Standard IPP only allows specification of a single + job-sheets attribute value.

      +

      "media" (1setof type3 keyword | name(MAX)):

      +

      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.

      +

      Note: Standard IPP only allows specification of a single media + attribute value.

      +

      Standard Job Template Attributes

      +
    +

    4.2.2 Create-Job Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    Group 2: Job Attributes

    +
      +

      Standard Job Attributes

      +
    +

    4.3 Set-Job-Attributes Operation

    +

    The Set-Job-Attributes operation (0x0014) changes the attributes of + an active (not completed) job.

    +

    4.3.1 Set-Job-Attributes Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

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

      +

      OR

      +

      "job-uri":

      +

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

      +
    +

    Group 2: Job Template Attributes

    +
      +

      "job-sheets" (1setof type3 keyword | name(MAX)):

      +

      (CUPS 1.1 and higher)

      +

      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.

      +

      Note: Standard IPP only allows specification of a single + job-sheets attribute value.

      +

      "media" (1setof type3 keyword | name(MAX)):

      +

      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.

      +

      Note: Standard IPP only allows specification of a single media + attribute value.

      +

      Other Job Template Attributes

      +
    +

    4.3.2 Set-Job-Attributes Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    4.4 CUPS-Get-Default Operation

    +

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

    +

    4.4.1 CUPS-Get-Default Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "requested-attributes" (1setOf keyword) :

      +

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

      +
    +

    4.4.2 CUPS-Get-Default Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    Group 2: Printer Object Attributes

    +
      +

      The set of requested attributes and their current values.

      +
    +

    4.5 CUPS-Get-Printers Operation

    +

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

    +

    4.5.1 CUPS-Get-Printers Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

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

      +

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

      +

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

      +

      (CUPS 1.1 and higher)

      +

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

      +

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

      +

      (CUPS 1.1 and higher)

      +

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

      +

      "printer-type" (type2 enum):

      +

      (CUPS 1.1 and higher)

      +

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

      +

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

      +

      (CUPS 1.1 and higher)

      +

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

      +

      "requested-attributes" (1setOf keyword) :

      +

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

      +
    +

    4.5.2 CUPS-Get-Printers Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    Group 2: Printer Object Attributes

    +
      +

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

      +
    +

    4.6 CUPS-Add-Modify-Printer Operation

    +

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

    +

    4.6.1 CUPS-Add-Modify-Printer Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

      The client MUST supply a URI for the specified printer.

      +
    +

    Group 2: Printer Object Attributes

    +
      +

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

      +

      (CUPS 1.1 and higher)

      +

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

      +

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

      +

      (CUPS 1.1 and higher)

      +

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

      +

      "device-uri" (uri):

      +

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

      +

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

      +

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

      +

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

      +

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

      +

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

      +

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

      +

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

      +

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

      +

      "printer-more-info" (uri):

      +

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

      +

      "printer-state" (type2 enum):

      +

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

      +

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

      +

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

      +

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

      +

      OR

      +

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

      +

      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.

      +
    +

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

    +

    4.6.2 CUPS-Add-Modify-Printer Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    4.7 CUPS-Delete-Printer Operation

    +

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

    +

    4.7.1 CUPS-Delete-Printer Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

      The client MUST supply a URI for the specified printer.

      +
    +

    4.7.2 CUPS-Delete-Printer Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    4.8 CUPS-Get-Classes Operation

    +

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

    +

    4.8.1 CUPS-Get-Classes Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

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

      +

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

      +

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

      +

      (CUPS 1.1 and higher)

      +

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

      +

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

      +

      (CUPS 1.1 and higher)

      +

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

      +

      "printer-type" (type2 enum):

      +

      (CUPS 1.1 and higher)

      +

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

      +

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

      +

      (CUPS 1.1 and higher)

      +

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

      +

      "requested-attributes" (1setOf keyword) :

      +

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

      +
    +

    4.8.2 CUPS-Get-Classes Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    Group 2: Printer Class Object Attributes

    +
      +

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

      +
    +

    4.9 CUPS-Add-Modify-Class Operation

    +

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

    +

    4.9.1 CUPS-Add-Modify-Class Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

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

      +
    +

    Group 2: Printer Object Attributes

    +
      +

      "member-uris" (1setof uri):

      +

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

      +

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

      +

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

      +

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

      +

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

      +

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

      +

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

      +

      "printer-more-info" (uri):

      +

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

      +

      "printer-state" (type2 enum):

      +

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

      +

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

      +

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

      +

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

      +

      OR

      +

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

      +

      The client OPTIONALLY supplies one of these attributes to specify an + access control list for incoming print jobs. To allow all users access + to a class, use the delete tag for the attribute value.

      +
    +

    4.9.2 CUPS-Add-Modify-Class Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    4.10 CUPS-Delete-Class Operation

    +

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

    +

    4.10.1 CUPS-Delete-Class Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

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

      +
    +

    4.10.2 CUPS-Delete-Class Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    4.11 CUPS-Accept-Jobs Operation

    +

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

    +

    4.11.1 CUPS-Accept-Jobs Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

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

      +
    +

    4.11.2 CUPS-Accept-Jobs Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    4.12 CUPS-Reject-Jobs Operation

    +

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

    +

    4.12.1 CUPS-Reject-Jobs Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

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

      +
    +

    Group 2: Printer Object Attributes

    +
      +

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

      +

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

      +
    +

    4.12.2 CUPS-Reject-Jobs Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    4.13 CUPS-Set-Default Operation

    +

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

    +

    4.13.1 CUPS-Set-Default Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "printer-uri" (uri):

      +

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

      +
    +

    4.13.2 CUPS-Set-Default Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    4.14 CUPS-Get-Devices Operation

    +

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

    +

    4.14.1 CUPS-Get-Devices Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

      "device-class" (type1 keyword):

      +

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

      +

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

      +

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

      +

      "requested-attributes" (1setOf keyword) :

      +

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

      +
    +

    4.14.2 CUPS-Get-Devices Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    Group 2: Device Object Attributes

    +
      +

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

      +
    +

    4.15 CUPS-Get-PPDs Operation

    +

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

    +

    4.15.1 CUPS-Get-PPDs Request

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

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

      +

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

      +

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

      +

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

      +

      "requested-attributes" (1setOf keyword) :

      +

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

      +
    +

    4.15.2 CUPS-Get-PPDs Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    Group 2: PPD Attributes

    +
      +

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

      +
    +

    4.16 CUPS-Move-Job Operation

    +

    The CUPS-Move-Job operation (0x400D) moves an active print job to a + different printer (CUPS 1.1 and higher).

    +

    4.16.1 CUPS-Move-Job Request

    +

    The following groups of attributes are supplied as part of the + CUPS-Move-Job request:

    +

    Group 1: Operation Attributes

    +
      +

      Natural Language and Character Set:

      +

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

      +

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

      +

      OR

      +

      "job-uri":

      +

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

      +
    +

    Group 2: Job Template Attributes

    +
      +

      "job-printer-uri" (uri)

      +

      The client MUST supply a URI for a printer on the same server.

      +
    +

    4.16.2 CUPS-Move-Job Response

    +

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

    +

    Group 1: Operation Attributes

    +
      +

      Status Message:

      +

      The standard response status message.

      +

      Natural Language and Character Set:

      +

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

      +
    +

    5 Attributes

    +

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

    +

    5.1 Device Attributes

    +

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

    +

    5.1.1 device-class (type2 keyword)

    +

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

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

    5.1.2 device-info (text(127))

    +

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

    +

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

    +

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

    +

    5.1.4 device-uri (uri)

    +

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

    +
      +
    • "file" - The device-uri will be of the form + "file:/path/to/filename".
    • +
    • "direct" - The device-uri will be of the form + "method:/dev/filename", where method may be "parallel" or "usb" in the + current implementation.
    • +
    • "serial" - The device-uri will be of the form + "serial:/dev/filename?baud=value+parity=value+flow=value". The 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). +

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

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

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

      +

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

      +
    • + +
    +

    5.2 Job Template Attributes

    +

    5.2.1 blackplot (boolean)

    +

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

    +

    5.2.2 brightness (integer(0:200))

    +

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

    +

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

    +

    5.2.3 columns (integer(1:4))

    +

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

    +

    5.2.4 cpi (type2 enum)

    +

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

    +

    5.2.5 fitplot (boolean)

    +

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

    +

    5.2.6 gamma (integer(1:10000))

    +

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

    +

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

    +

    5.2.7 hue (integer(-180:180))

    +

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

    +

    5.2.8 job-billing (text(MAX))

    +

    (CUPS 1.1 and higher)

    +

    The job-billing attribute provides a text value to associate with a + job for billing purposes.

    +

    5.2.9 job-hold-until (keyword | name(MAX))

    +

    (CUPS 1.1 and higher)

    +

    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 not in the local time zone. If + the specified time is less than the current time, the job is held until + the next day.

    +

    5.2.10 job-sheets (1setof type3 keyword | + name(MAX))

    +

    (CUPS 1.1 and higher)

    +

    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.

    +

    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.

    +

    5.2.11 job-originating-host-name (name(MAX))

    +

    (CUPS 1.1.5 and higher)

    +

    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 always resolved to the name + "localhost".

    +

    This attribute is read-only.

    +

    5.2.12 lpi (type2 enum)

    +

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

    +

    5.2.13 natural-scaling (integer(1:1000))

    +

    (CUPS 1.1.9 and higher)

    +

    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.

    +

    The ppi option can be used to override the natural resolution of the + image, which controls the natural size.

    +

    5.2.14 number-up-layout (type2 keyword)

    +

    (CUPS 1.1.15 and higher)

    +

    The number-up-layout attribute specifies the order each input page is + placed on each output page. The following keywords are presently + defined:

    +
      +
    • btlr - Bottom to top, left to right
    • +
    • btrl - Bottom to top, right to left
    • +
    • lrbt - Left to right, bottom to top
    • +
    • lrtb - Left to right, top to bottom (default)
    • +
    • rlbt - Right to left, bottom to top
    • +
    • rltb - Right to left, top to bottom
    • +
    • tblr - Top to bottom, left to right
    • +
    • tbrl - Top to bottom, right to left
    • +
    +

    5.2.15 page-border (type2 keyword)

    +

    (CUPS 1.1.15 and higher)

    +

    The page-border attribute specifies whether a border is draw around + each page. The following keywords are presently defined:

    +
      +
    • double - Two hairline borders are drawn
    • +
    • double-thick - Two 1pt borders are drawn
    • +
    • none - No border is drawn (default)
    • +
    • single - A single hairline border is drawn
    • +
    • single-thick - A single 1pt border is drawn
    • +
    +

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

    +

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

    +

    5.2.17 page-label (text(MAX))

    +

    (CUPS 1.1.7 and higher)

    +

    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.

    +

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

    +

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

    +

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

    +

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

    +

    5.2.20 page-set (type2 keyword)

    +

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

    +

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

    +

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

    +

    5.2.22 penwidth (integer(0:MAX))

    +

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

    +

    5.2.23 position (type2 keyword)

    +

    The position attribute specifies the location of image files on the + media. The following keyword values are recognized:

    +
      +
    • center - Center the image on the page (default)
    • +
    • top - Print the image centered at the top of the page
    • +
    • left - Print the image centered on the left of page
    • +
    • right - Print the image centered on the right of the + page
    • +
    • top-left - Print the image at the top left corner of + the page
    • +
    • top-right - Print the image at the top right corner of + the page
    • +
    • bottom - Print the image centered at the bottom of the + page
    • +
    • bottom-left - Print the image at the bottom left corner + of the page
    • +
    • bottom-right - Print the image at the bottom right + corner of the page
    • +
    +

    5.2.24 ppi (integer(1:MAX))

    +

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

    +

    5.2.25 prettyprint (boolean)

    +

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

    +

    5.2.26 saturation (integer(0:200))

    +

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

    +

    5.2.27 scaling (integer(1:1000))

    +

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

    +

    The scaling attribute overrides the ppi attribute if specified.

    +

    5.2.28 wrap (boolean)

    +

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

    +

    5.3 PPD Attributes

    +

    5.3.1 ppd-natural-language (naturalLanguage)

    +

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

    +

    5.3.2 ppd-make (text(127))

    +

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

    +

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

    +

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

    +

    5.3.4 ppd-name (name(255))

    +

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

    +

    5.4 Printer Attributes

    +

    5.4.1 job-k-limit (integer)

    +

    (CUPS 1.1 and higher)

    +

    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.

    +

    5.4.2 job-page-limit (integer)

    +

    (CUPS 1.1 and higher)

    +

    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.

    +

    5.4.3 job-quota-period (integer)

    +

    (CUPS 1.1 and higher)

    +

    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.

    +

    5.4.4 job-sheets-supported (1setof type3 keyword | + name(MAX))

    +

    (CUPS 1.1 and higher)

    +

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

    +

    5.4.5 printer-type (type2 enum)

    +

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

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

    +

    5.4.6 printer-type-mask (type2 enum)

    +

    (CUPS 1.1 and higher)

    +

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

    +

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

    +

    (CUPS 1.1 and higher)

    +

    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.

    +

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

    +

    (CUPS 1.1 and higher)

    +

    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.

    +

    5.5 Printer Class Attributes

    +

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

    +

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

    +

    5.5.2 member-uris (1setof uri)

    +

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

    +

    A Glossary

    +

    A.1 Terms

    +
    +
    C
    +
    A computer language.
    +
    parallel
    +
    Sending or receiving data more than 1 bit at a time.
    +
    pipe
    +
    A one-way communications channel between two programs.
    +
    serial
    +
    Sending or receiving data 1 bit at a time.
    +
    socket
    +
    A two-way network communications channel.
    +
    +

    A.2 Acronyms

    +
    +
    ASCII
    +
    American Standard Code for Information Interchange
    +
    CUPS
    +
    Common UNIX Printing System
    +
    ESC/P
    +
    EPSON Standard Code for Printers
    +
    FTP
    +
    File Transfer Protocol
    +
    HP-GL
    +
    Hewlett-Packard Graphics Language
    +
    HP-PCL
    +
    Hewlett-Packard Page Control Language
    +
    HP-PJL
    +
    Hewlett-Packard Printer Job Language
    +
    IETF
    +
    Internet Engineering Task Force
    +
    IPP
    +
    Internet Printing Protocol
    +
    ISO
    +
    International Standards Organization
    +
    LPD
    +
    Line Printer Daemon
    +
    MIME
    +
    Multimedia Internet Mail Exchange
    +
    PPD
    +
    PostScript Printer Description
    +
    SMB
    +
    Server Message Block
    +
    TFTP
    +
    Trivial File Transfer Protocol
    +
    + + diff --git a/doc/ipp.pdf b/doc/ipp.pdf new file mode 100644 index 0000000000000000000000000000000000000000..84771cd3fff5b5e1e8f94dec2ea0b75d1436ac29 GIT binary patch literal 111519 zc-pMJ2|QHa|398e3o7rdA)GqcbG z^g)S5uRH1=NdW3tb*7i!k|h{B7SlV7&R}V72n`JIX42IGeUd&1sGBl_BUrxcH-xGK zWHM0?#9~2pa~eBB-GS*7x{=0WsH0bgvUSys0|L}3h%8&3!eBF4;S6tmEsQCPK@0U| z2AR=98JcDWNDWvLfX8BS5Jc9&!UtLyN8iu@hNh{LorAhnU~m8s#T>*K>F6Fq%k zAF*jc-l#Aet}}pv35K-|3SjtzqDLG}F*J54gXPQi#{>t2u`zUJU?2?>=oeCg1Y?RZ!O+9^=57i!f-|-GQt9oVNDNXA%i*s69EquFBa3E5rlLin?dJ{ zg7IqTV}68Tvb=rZ5yTl#2srGNOw`^1%=Nx>T0jsp6tf{BcmrG^i?QApfns=L0%>$a zU2n#EWS}A=8y(W{;AMw##x)Ba#N#CzJuH-g2@FGAg9eX|;0@gIkF6l99=*8yf#pZupY(9RK6)Ize%2@p&V>K>g9=ZXu3WZyZimyh+SN|ct znkz7VRbW^^sBdsU1ZFkre@^J7PUxjhe_ZM`e$5*6OGh}G!lR183WP_sR{$GB<2ok# zHSLdUX(%jhyb2np8)$H#8S4fHdNBjNnDNKOjPa{{Q5j!U#`g~y-*FiR+zmk}91|61 zqTT3nuJK z4q;xQNC7zmU`*iX!8vUT$71;U@fk!NnOP{~HQ^^-lcR4SgRMtl!WI!!8}xsz&4d}? zEvPcW|Ftr!P+EX5T~KwziC1UI2nc6{!a+n(U8Mhqx`eisJn;%0A_Bdb0pnK!Sl&xr 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 z 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 + + + + + CUPS Implementation of IPP + + + +

    Scope

    + +

    Identification

    + +

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

    Document Overview

    + +

    This document is organized into the following sections: + +

    + + + +

    Overview

    + +

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

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

    IPP URIs

    + +

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

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

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

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

    CUPS IPP Operations

    + +

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

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

    Operations

    + +

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

    Print-Job Operation

    + +

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

    Print-Job Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    Group 2: Job Template Attributes + +

      + +

      "job-billing" (text(MAX)): + +

      (CUPS 1.1 and higher) + +

      The client OPTIONALLY supplies a billing string that is logged + with the page accounting information. + +

      "job-sheets" (1setof type3 keyword | name(MAX)): + +

      (CUPS 1.1 and higher) + +

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

      Note: Standard IPP only allows specification of a single + job-sheets attribute value. + +

      "media" (1setof type3 keyword | name(MAX)): + +

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

      Note: Standard IPP only allows specification of a single + media attribute value. + +

      Other Job Template Attributes + +

    + +

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

    Print-Job Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    Group 2: Job Attributes + +

      + +

      Standard Job Attributes + +

    + +

    Create-Job Operation

    + +

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

    Create-Job Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    Group 2: Job Template Attributes + +

      + +

      "job-billing" (text(MAX)): + +

      (CUPS 1.1 and higher) + +

      The client OPTIONALLY supplies a billing string that is logged + with the page accounting information. + +

      "job-sheets" (1setof type3 keyword | name(MAX)): + +

      (CUPS 1.1 and higher) + +

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

      Note: Standard IPP only allows specification of a single + job-sheets attribute value. + +

      "media" (1setof type3 keyword | name(MAX)): + +

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

      Note: Standard IPP only allows specification of a single + media attribute value. + +

      Standard Job Template Attributes + +

    + +

    Create-Job Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    Group 2: Job Attributes + +

      + +

      Standard Job Attributes + +

    + +

    Set-Job-Attributes Operation

    + +

    The Set-Job-Attributes operation (0x0014) changes the attributes of +an active (not completed) job. + +

    Set-Job-Attributes Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

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

      OR +

      "job-uri": + +

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

    + +

    Group 2: Job Template Attributes + +

      + +

      "job-sheets" (1setof type3 keyword | name(MAX)): + +

      (CUPS 1.1 and higher) + +

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

      Note: Standard IPP only allows specification of a single + job-sheets attribute value. + +

      "media" (1setof type3 keyword | name(MAX)): + +

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

      Note: Standard IPP only allows specification of a single + media attribute value. + +

      Other Job Template Attributes + +

    + +

    Set-Job-Attributes Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    CUPS-Get-Default Operation

    + +

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

    CUPS-Get-Default Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

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

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

    + +

    CUPS-Get-Default Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    Group 2: Printer Object Attributes + +

      + +

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

    + +

    CUPS-Get-Printers Operation

    + +

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

    CUPS-Get-Printers Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

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

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

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

      (CUPS 1.1 and higher) + +

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

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

      (CUPS 1.1 and higher) + +

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

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

      (CUPS 1.1 and higher) + +

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

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

      (CUPS 1.1 and higher) + +

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

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

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

    + +

    CUPS-Get-Printers Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    Group 2: Printer Object Attributes + +

      + +

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

    + +

    CUPS-Add-Modify-Printer Operation

    + +

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

    CUPS-Add-Modify-Printer Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    Group 2: Printer Object Attributes + +

      + +

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

      (CUPS 1.1 and higher) + +

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

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

      (CUPS 1.1 and higher) + +

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

      "device-uri" (uri): + +

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      OR +

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

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

    + +

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

    CUPS-Add-Modify-Printer Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    CUPS-Delete-Printer Operation

    + +

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

    CUPS-Delete-Printer Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    CUPS-Delete-Printer Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    CUPS-Get-Classes Operation

    + +

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

    CUPS-Get-Classes Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

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

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

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

      (CUPS 1.1 and higher) + +

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

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

      (CUPS 1.1 and higher) + +

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

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

      (CUPS 1.1 and higher) + +

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

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

      (CUPS 1.1 and higher) + +

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

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

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

    + +

    CUPS-Get-Classes Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    Group 2: Printer Class Object Attributes + +

      + +

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

    + +

    CUPS-Add-Modify-Class Operation

    + +

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

    CUPS-Add-Modify-Class Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    Group 2: Printer Object Attributes + +

      + +

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      OR +

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

      The client OPTIONALLY supplies one of these attributes to + specify an access control list for incoming print jobs. To allow + all users access to a class, use the delete tag for the + attribute value. + +

    + +

    CUPS-Add-Modify-Class Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    CUPS-Delete-Class Operation

    + +

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

    CUPS-Delete-Class Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    CUPS-Delete-Class Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    CUPS-Accept-Jobs Operation

    + +

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

    CUPS-Accept-Jobs Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    CUPS-Accept-Jobs Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    CUPS-Reject-Jobs Operation

    + +

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

    CUPS-Reject-Jobs Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    Group 2: Printer Object Attributes + +

      + +

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

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

    + +

    CUPS-Reject-Jobs Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    CUPS-Set-Default Operation

    + +

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

    CUPS-Set-Default Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

      "printer-uri" (uri): + +

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

    + +

    CUPS-Set-Default Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    CUPS-Get-Devices Operation

    + +

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

    CUPS-Get-Devices Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

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

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

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

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

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

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

    + +

    CUPS-Get-Devices Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    Group 2: Device Object Attributes + +

      + +

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

    + +

    CUPS-Get-PPDs Operation

    + +

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

    CUPS-Get-PPDs Request

    + +

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

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

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

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

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

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

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

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

    + +

    CUPS-Get-PPDs Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    Group 2: PPD Attributes + +

      + +

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

    + +

    CUPS-Move-Job Operation

    + +

    The CUPS-Move-Job operation (0x400D) moves an active print job to a +different printer (CUPS 1.1 and higher). + +

    CUPS-Move-Job Request

    + +

    The following groups of attributes are supplied as part of the +CUPS-Move-Job request: + +

    Group 1: Operation Attributes + +

      + +

      Natural Language and Character Set: + +

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

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

      OR +

      "job-uri": + +

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

    + +

    Group 2: Job Template Attributes + +

      + +

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

      The client MUST supply a URI for a printer on the same server. + +

    + +

    CUPS-Move-Job Response

    + +

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

    Group 1: Operation Attributes + +

      + +

      Status Message: + +

      The standard response status message. + +

      Natural Language and Character Set: + +

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

    + +

    Attributes

    + +

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

    Device Attributes

    + +

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

    device-class (type2 keyword)

    + +

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

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

    device-info (text(127))

    + +

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

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

    + +

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

    device-uri (uri)

    + +

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

      + +
    • "file" - The device-uri will be of the form + "file:/path/to/filename". + +
    • "direct" - The device-uri will be of the form + "method:/dev/filename", where method may be "parallel" or "usb" + in the current implementation. + +
    • "serial" - The device-uri will be of the form + "serial:/dev/filename?baud=value+parity=value+flow=value". + The 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). + +

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

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

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

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

    + +

    Job Template Attributes

    + +

    blackplot (boolean)

    + +

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

    brightness (integer(0:200))

    + +

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

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

    columns (integer(1:4))

    + +

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

    cpi (type2 enum)

    + +

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

    fitplot (boolean)

    + +

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

    gamma (integer(1:10000))

    + +

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

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

    hue (integer(-180:180))

    + +

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

    job-billing (text(MAX))

    + +

    (CUPS 1.1 and higher) + +

    The job-billing attribute provides a text value to associate with a job +for billing purposes. + +

    job-hold-until (keyword | name(MAX))

    + +

    (CUPS 1.1 and higher) + +

    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 not in the local time zone. If the +specified time is less than the current time, the job is held until the +next day. + +

    job-sheets (1setof type3 keyword | name(MAX))

    + +

    (CUPS 1.1 and higher) + +

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

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

    job-originating-host-name (name(MAX))

    + +

    (CUPS 1.1.5 and higher) + +

    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 +always resolved to the name "localhost". + +

    This attribute is read-only. + +

    lpi (type2 enum)

    + +

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

    mirror (boolean)

    + +

    The mirror attribute specifies whether pages are mirrored on +their X axis, which is useful for printing transfer images on +special media. The default value is false. + +

    natural-scaling (integer(1:1000))

    + +

    (CUPS 1.1.9 and higher) + +

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

    The ppi option can be used to override the natural resolution of the +image, which controls the natural size. + +

    number-up-layout (type2 keyword)

    + +

    (CUPS 1.1.15 and higher) + +

    The number-up-layout attribute specifies the order each input +page is placed on each output page. The following keywords are +presently defined: + +

      + +
    • btlr - Bottom to top, left to right
    • + +
    • btrl - Bottom to top, right to left
    • + +
    • lrbt - Left to right, bottom to top
    • + +
    • lrtb - Left to right, top to bottom (default)
    • + +
    • rlbt - Right to left, bottom to top
    • + +
    • rltb - Right to left, top to bottom
    • + +
    • tblr - Top to bottom, left to right
    • + +
    • tbrl - Top to bottom, right to left
    • + +
    + +

    page-border (type2 keyword)

    + +

    (CUPS 1.1.15 and higher) + +

    The page-border attribute specifies whether a border is +draw around each page. The following keywords are presently +defined: + +

      + +
    • double - Two hairline borders are drawn
    • + +
    • double-thick - Two 1pt borders are drawn
    • + +
    • none - No border is drawn (default)
    • + +
    • single - A single hairline border is drawn
    • + +
    • single-thick - A single 1pt border is drawn
    • + +
    + +

    page-bottom (integer(0:MAX))

    + +

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

    page-label (text(MAX))

    + +

    (CUPS 1.1.7 and higher) + +

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

    page-left (integer(0:MAX))

    + +

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

    page-right (integer(0:MAX))

    + +

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

    page-set (type2 keyword)

    + +

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

    page-top (integer(0:MAX))

    + +

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

    penwidth (integer(0:MAX))

    + +

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

    position (type2 keyword)

    + +

    The position attribute specifies the location of image files on the +media. The following keyword values are recognized: + +

      + +
    • center - Center the image on the page (default) + +
    • top - Print the image centered at the top of the page + +
    • left - Print the image centered on the left of page + +
    • right - Print the image centered on the right of the page + +
    • top-left - Print the image at the top left corner of + the page + +
    • top-right - Print the image at the top right corner of + the page + +
    • bottom - Print the image centered at the bottom of + the page + +
    • bottom-left - Print the image at the bottom left + corner of the page + +
    • bottom-right - Print the image at the bottom right + corner of the page + +
    + +

    ppi (integer(1:MAX))

    + +

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

    prettyprint (boolean)

    + +

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

    saturation (integer(0:200))

    + +

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

    scaling (integer(1:1000))

    + +

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

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

    wrap (boolean)

    + +

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

    PPD Attributes

    + +

    ppd-natural-language (naturalLanguage)

    + +

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

    ppd-make (text(127))

    + +

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

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

    + +

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

    ppd-name (name(255))

    + +

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

    Printer Attributes

    + +

    job-k-limit (integer)

    + +

    (CUPS 1.1 and higher) + +

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

    job-page-limit (integer)

    + +

    (CUPS 1.1 and higher) + +

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

    job-quota-period (integer)

    + +

    (CUPS 1.1 and higher) + +

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

    job-sheets-supported (1setof type3 keyword | name(MAX))

    + +

    (CUPS 1.1 and higher) + +

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

    printer-type (type2 enum)

    + +

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

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

    printer-type-mask (type2 enum)

    + +

    (CUPS 1.1 and higher) + +

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

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

    + +

    (CUPS 1.1 and higher) + +

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

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

    + +

    (CUPS 1.1 and higher) + +

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

    Printer Class Attributes

    + +

    member-names (1setof name(127))

    + +

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

    member-uris (1setof uri)

    + +

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

    An Overview of the
    + Common UNIX Printing System,
    + Version 1.2

    + +

    July 3, 2004
    + Michael Sweet, Easy Software Products
    + Copyright 1998-2004, All Rights Reserved.

    +
    + +

    +New Outline:
    +
    +New Features:
    +
    +1. Networking
    +   a. IPv6
    +        i. Next-generation Internet support
    +       ii. ????
    +   b. Domain sockets
    +        i. Enhanced performance under load for local clients.
    +       ii. Authentication without passwords on platforms that support it.
    +   c. CUPS browsing updates
    +        i. "Delete" bit for printers
    +       ii. "lease-time" for printers so that clients and servers don't need
    +          the same browse timeout/interval settings
    +      iii. Additional attributes/default options for network-wide defaults
    +       iv. Network default printer
    +        v. Ability to control send and receive protocols independently
    +   d. Rendevous support
    +   e. LDAP support
    +   f. Per-printer sharing
    +
    +2. IPP Support
    +   a. Notifications
    +   b. Document object
    +   c. Send-URI, Print-URI
    +   d. Other stuff?
    +   e. Add/delete device operations
    +
    +3. Scheduler
    +   a. Backchannel support
    +   b. Port monitor support
    +   c. Device monitor
    +      i. Dynamic device discovery/management
    +   d. All errors include a localized message.
    +   e. Fine-grain policies, server default + per-printer
    +   f. UTF-8 throughout
    +
    +4. Web Interface
    +   a. cupsd.conf interface
    +   b. Move-Job
    +   c. Export printers to windows
    +   d. Per-printer sharing controls
    +   e. Per-printer access control lists 
    +   f. Policy stuff
    +
    +5. I18N
    +   a. Support for ... character sets
    +   b. All commands and messages are localized
    +   c. Character set transcoding
    +   d. ... , and Japanese localizations
    +
    +6. Drivers
    +   a. New HP-RTL driver.
    +
    +
    + +

    This whitepaper describes the Common UNIX Printing +SystemTM (CUPSTM), a portable and +extensible printing system for Linux®, +MacOS® X, UNIX®. CUPS is developed +by Easy Software Products, 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.

    + +

    CUPS is used by Apple to provide printing on MacOS X and is +the defacto-standard for Linux. Additional information on CUPS +is available on the World Wide Web at the following URL:

    + +
    +    http://www.cups.org/
    +
    + + +

    Background

    + +

    Printing within UNIX has historically been done using one of +two printing systems - the Berkeley Line Printer Daemon (LPD) +[RFC1179] and the AT&T Line Printer system. 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.

    + +

    Replacements for these printing systems have emerged [LPRng, +Palladin, PLP], however none of the replacements change the +fundamental capabilities of these systems.

    + +

    Over the 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.

    + +

    The Internet Printing Protocol defines extensions to the +HyperText Transport Protocol 1.1 [RFC2616] to provide support +for remote printing services. IPP/1.1 was accepted by the IETF +as a proposed standard in ??? of ???. Unlike POSIX Printing, IPP +enjoys widespread industry support and has become the standard +network printing solution for all operating systems.

    + +

    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.

    + +

    History

    + +

    The first production release of CUPS (based on IPP/1.0) was +released in October of 1999. Version 1.1 of CUPS was released in +August of 2002 ???? and added support for IPP/1.1.

    + +

    CUPS 1.2 is based on IPP/1.1 and adds many of the functional +enhancements that have been requested by our users. As with CUPS +1.1, CUPS 1.2 will be followed by patch releases that address +any problems found with the software. New features will be put +in the 1.3 release to follow.

    + +

    Design Overview

    + +

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

    + +

    CUPS Block Diagram
    +Figure 1 - CUPS Block Diagram

    + +

    Scheduler

    + +

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

    + +

    The scheduler also manages a list of available printers on +the LAN and dispatches print jobs as needed using the +appropriate filters and backends.

    + +

    Configuration Files

    + +

    The configuration files consist of:

    + +
      + +
    • The HTTP server configuration file.
    • + +
    • Printer and class definition files.
    • + +
    • MIME type and conversion rule files.
    • + +
    • PostScript Printer Description (PPD) files.
    • + +
    + +

    The HTTP server configuration file is purposely similar to +the Apache server configuration file and defines all of the +access control properties for the server.

    + +

    The printer and class definition files list the available +printer queues and classes. Printer classes are collections of +printers. Jobs sent to a class are forwarded to the first +available printer in the class, round-robin fashion.

    + +

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

    + +

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

    + +

    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 cupsFilter attributes to support +printer drivers.

    + +

    CUPS API

    + +

    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.

    + +

    Berkeley and System V Commands

    + +

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

    + +

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

    + +

    Filters

    + +

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

    + +

    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.

    + +

    The PostScript raster filter is based on the ESP Ghostscript +core. Instead of using the Ghostscript printer drivers, the CUPS +filter uses a generic CUPS 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.

    + +
    Talk about Apple's use of CUPS...
    + +

    CUPS Imaging

    + +

    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.

    + +

    Backends

    + +

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

    + +

    SAMBA version 2.0.6 and higher includes a SMB backend +(smbspool(1)) that can be used for printing to +Windows.

    + +

    Network Printing

    + +

    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.

    + +

    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.

    + +

    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.

    + +

    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!

    + +

    New Features in CUPS 1.2

    + +

    CUPS 1.2 includes many new features and capabilities: + +

      + +
    1. Backends + +
    2. Banner Page Support + +
    3. Digest Authentication + +
    4. Directory Services + +
    5. Directory Structure Changes + +
    6. Documentation + +
    7. Drivers + +
    8. Filters + +
    9. IPP Support + +
    10. Job Persistence + +
    11. LPD Client Support + +
    12. User-Defined Printers and Options + +
    13. Web Administration Interface + +
    + +

    1. Backends

    + +

    CUPS 1.2 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.

    + +

    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.

    + +

    2. Banner Page Support

    + +

    CUPS 1.2 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.

    + +

    3. Digest Authentication

    + +

    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.

    + +

    CUPS 1.2 implements Digest authentication using a special MD5 +password file instead of the UNIX password file. This file is +managed using the new lppasswd command.

    + +

    4. Directory Services

    + +

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

    + +

    5. Directory Structure Changes

    + +

    CUPS 1.2 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.

    + +

    6. Documentation

    + +

    The CUPS 1.2 documentation has gone through many revisions, +including a completely rewritten administrators manual, a new +programmers manual, and an IPP implementation reference +manual.

    + +

    7. Drivers

    + +

    CUPS 1.2 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.

    + +

    8. Filters

    + +

    CUPS 1.2 includes new image, PostScript, PDF, and text +filters. The image filters have been upgraded to support Windows +BMP and Alias PIX files.

    + +

    The PostScript filter is now based off ESP Ghostscript. The +new filter provides much better performance with +higher-resolution printers and supports all Level 3 PostScript +language features.

    + +

    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.

    + +

    The new text filter now supports bidirectional text and can +embed fonts as needed.

    + +

    9. IPP Support

    + +

    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 lp command) and support +for banner pages.

    + +

    10. Job Persistence

    + +

    CUPS 1.2 supports job persistence. This means that jobs are +preserved even after a reboot, a feature that was sorely missing +from CUPS 1.0.

    + +

    In addition, CUPS 1.2 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.

    + +

    11. LPD Client Support

    + +

    By popular request, CUPS 1.2 supports LPD-based clients using +a new mini-daemon that handles LPD requests and passes them on +to the main server.

    + +

    12. User-Defined Printers and Options

    + +

    CUPS 1.2 includes support for user-defined printers and +options via a new lpoptions 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 lpoptions command can also be used to set a +different default printer queue.

    + +

    13. Web Administration Interface

    + +

    CUPS 1.0 provided a simple class, job, and printer monitoring +interface for web browsers. CUPS 1.2 replaces this interface +with an enhanced administration interface that allows you to +add, modify, delete, configure, and control classes, jobs, and +printers.

    + +

    Software Using CUPS

    + +

    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.

    + +

    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:

    + +
    +    http://kups.sourceforge.net
    +
    + +

    The X Printing Panel (XPP) project provides a graphical +printing panel for CUPS and can be found at:

    + +
    +    http://www.phy.uni-bayreuth.de/till/xpp/
    +
    + +

    Numerous other filters, drivers, tutorials, etc. have been +made available on the CUPS Links web page, available at:

    + +
    +    http://www.cups.org/links.php
    +
    + +

    Finally, our own ESP Print Pro software uses CUPS to provide +drivers for thousands of printers and can be found at:

    + +
    +    http://www.easysw.com/printpro
    +
    + +

    Operating Systems Using CUPS

    + +

    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.

    + +

    Summary

    + +

    The Common UNIX Printing System provides a modern printing +interface for UNIX applications that is both flexible and +user-friendly. The software provides System V and Berkeley +compatible command-line interfaces to ensure compatibility with +existing applications. CUPS 1.2 adds many new features that make +it an even better choice for printing under UNIX.

    + +

    Who to Contact

    + +

    For more information on CUPS please contact us at: + +

    +    Attn: CUPS Information
    +    Easy Software Products
    +    44141 Airport View Drive Suite 204
    +    Hollywood, Maryland 20636-3142 USA
    +
    +    +1.301.373.9600
    +
    +    cups-info@cups.org
    +
    + +

    References

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

    Trademarks

    + +

    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.

    + + + diff --git a/doc/overview.pdf b/doc/overview.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ada9b01a55d8a4cf83818f9fd35e0c28a4cf1bb6 GIT binary patch literal 50052 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 + + CUPS PostScript Printer Description (PPD) File Specification + + + + + + + +

    Scope

    + +

    Identification

    + +

    This document describes the PostScript Printer Description +(PPD) file format and the supported extensions for the Common +UNIX Printing System ("CUPS") Version 1.2. It should be used in +conjunction with the Adobe PostScript Printer Description File +Format Specification, Version 4.3 when creating PPD files for +CUPS.

    + + + +

    Document Overview

    + +

    This CUPS PostScript Printer Description File Specification +document is organized into the following sections:

    + +
      + +
    • 1 - Scope
    • + +
    • 2 - References
    • + +
    • 3 - PPD File Syntax
    • + +
    • 4 - General Attributes
    • + +
    • 5 - Custom Options
    • + +
    • 6 - Color Profiles
    • + +
    • 7 - I18N Support
    • + +
    • A - Glossary
    • + +
    • B - Change History
    • + +
    + + + +

    PPD File Syntax

    + +

    PostScript Printer Description ("PPD") files describe the +capabilities of each printer and are used by CUPS to support +printer-specific features and intelligent filtering.

    + +

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

    + +

    The format is text-based and uses lines of up to 255 +characters terminated by a carriage return, linefeed, or +combination of carriage return and line feed. The following ABNF +definition [RFC2234] defines the general format of lines in a +PPD file:

    + +
    +    PPD-FILE = HEADER +(DATA / COMMENT / LINE-END)
    +
    +    HEADER   = "*" 0x50.50.44.2D.41.64.6F.62.65 ":"   ; *PPD-Adobe:
    +               *WSP DQUOTE "4.3" DQUOTE LINE-END
    +
    +    COMMENT  = "*%" *TCHAR LINE-END
    +
    +    DATA     = "*" 1*KCHAR [ WSP 1*KCHAR [ "/" 1*TCHAR ] ] ":"
    +               1*(*WSP VALUE) LINE-END
    +
    +    VALUE    = 1*TCHAR / DQUOTE 1*SCHAR DQUOTE
    +
    +    KCHAR    = ALPHA / DIGIT / "_" / "." / "-"
    +
    +    SCHAR    = LINE-END / WSP / %x21 / %x23-7E / %xA0-FF
    +
    +    TCHAR    = %x20-7E / %xA0-FF
    +
    +    LINE-END = CR / LF / CR LF
    +
    + + +

    General Attributes

    + +

    cupsFilter

    + +

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

    + +
    +    source/type cost program
    +
    + +

    The destination type is assumed to the printer's type. If a +printer supports the source type directly the special filter +program "-" may be specified.

    + +

    cupsFlipDuplex

    + +

    This boolean attribute notifies the RIP filters that the +destination printer requires an upside-down image for the back +page. The default value is false.

    + +

    cupsManualCopies

    + +

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

    + +

    cupsModelNumber

    + +

    This integer attribute specifies a printer-specific model +number. This number can be used by a filter program to adjust +the output for a specific model of printer.

    + +

    cupsProtocol

    + +

    This optional attribute describes which binary communication +protocol to use when printing binary PostScript data. The +strings "None", "BCP", and "TBCP" are recognized, corresponding +to no encoding, BCP, and TBCP respectively.

    + +

    cupsVersion

    + +

    This required attribute describes which version of the CUPS +IDD was used for the PPD file extensions. Currently it must be +the string "1.0", "1.1", or "1.2".

    + + +

    Custom Options

    + + +

    Color Profiles

    + +

    cupsColorProfile

    + +

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

    + +
    +    *cupsColorProfile Resolution/MediaType: "density gamma m00 m01 m02 m10 m11 m12 m20 m21 m22"
    +
    + +

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

    + +

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

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

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

    + +
    +    | m00 m01 m02 |
    +    | m10 m11 m12 |
    +    | m20 m21 m22 |
    +
    + +

    cupsICCProfile

    + +

    This attribute specifies an ICC color profile of the +form:

    + +
    +    *cupsICCProfile ColorModel.MediaType.Resolution/Description: "filename"
    +
    + +

    The ColorModel, MediaType, and +Resolution keywords specify a selector for color +profiles. If omitted, the color profile will match any option +keyword for the corresponding main keyword.

    + +

    The Description specifies human-readable text that +is associated with the color profile. The filename +portion specifies the ICC color profile to use; if the filename +is not absolute, it is loaded relative to the +/usr/share/cups/profiles directory.

    + +

    Customizing the Profile Selection Keywords

    + +

    The ColorModel, MediaType, and +Resolution keywords can be reassigned to different main +keywords, allowing drivers to do color profile selection based +on different parameters. The cupsICCQualifier1, +cupsICCQualifier2, and cupsICCQualifier3 +attributes define the mapping from selector to main keyword:

    + +
    +    *cupsICCQualifier1: MainKeyword
    +    *cupsICCQualifier2: MainKeyword
    +    *cupsICCQualifier3: MainKeyword
    +
    + +

    The default mapping is as follows:

    + +
    +    *cupsICCQualifier1: ColorModel
    +    *cupsICCQualifier2: MediaType
    +    *cupsICCQualifier3: Resolution
    +
    + +

    I18N Support

    + +

    CUPS 1.2 and higher adds support for PPD files containing multiple +languages by following the following rules:

    + +
      + +
    1. The LanguageVersion is English
    2. + +
    3. The LanguageEncoding is ISOLatin1
    4. + +
    5. Main and option keywords may not exceed 34 + characters, which is a subset of what the Adobe PPD spec + allows.
    6. + +
    7. Translations are specified using a locale prefix of + the form "ll" or "ll_CC." where "ll" is the 2-letter ISO + language code and "CC" is the 2-letter ISO country + code
    8. + +
    9. Translation strings are encoded using UTF-8.
    10. + +
    11. Main keywords are translated using any of the + following forms: +

      *ll.Translation MainKeyword/translation + text: ""
      + *ll_CC.Translation MainKeyword/translation + text: ""

    12. + +
    13. Option keywords are translated using any of the + following forms: +

      *ll.MainKeyword OptionKeyword/translation + text: ""
      + *ll_CC.MainKeyword OptionKeyword/translation + text: ""

    14. + +
    + +

    The following example shows how a fictional Foobar Laser 9999 +PPD file would be localized for English, French, and German:

    + +
    +    *LanguageVersion: English
    +    *LanguageEncoding: ISOLatin1
    +    *ModelName: "Foobar Laser 9999"
    +    *fr_FR.Translation ModelName/La Foobar Laser 9999: ""
    +    *de_DE.Translation ModelName/Foobar LaserDrucken 9999: ""
    +    ...
    +    *OpenUI *InputSlot/Paper Source: PickOne
    +    *OrderDependency: 10 AnySetup *InputSlot
    +    *DefaultInputSlot: Auto
    +    *fr_FR.Translation InputSlot/Papier source: ""
    +    *de_DE.Translation InputSlot/Papiereinzug: ""
    +    *InputSlot Auto/Default: "<>setpagedevice"
    +    *fr_FR.InputSlot Auto/Par Defaut: ""
    +    *de_DE.InputSlot Auto/Standard: ""
    +    *InputSlot Manual/Manual Feed: "<>setpagedevice"
    +    *fr_FR.InputSlot Manual/Manuel mecanisme de alimentation: ""
    +    *de_DE.InputSlot Manual/Manueller Einzug: ""
    +    *CloseUI: *InputSlot
    +
    + + + +

    Change History

    + +

    Changes in CUPS 1.2

    + +
      + +
    • cupsICCProfile
    • + +
    • New I18N support
    • + +
    • + +
    • + +
    • + +
    • + +
    • + +
    • + +
    • + +
    + +

    Changes in CUPS 1.1

    + +
      + +
    • cupsProtocol
    • + +
    • cupsFlipDuplex
    • + +
    • + +
    • + +
    • + +
    • + +
    • + +
    • + +
    • + +
    + + + 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 @@ +

    1 - Printing System Overview

    + +

    This chapter provides an overview of how the Common UNIX Printing System +works. + +

    The Printing Problem

    + +

    For years the printing problem has plagued UNIX. Unlike +Microsoft® Windows® or Mac OS, UNIX has no standard interface or +system in place for supporting printers. Among the solutions currently +available, the Berkeley and System V printing systems are the most +prevalent. + +

    These printing systems support line printers (text only) or +PostScript printers (text and graphics), and with some coaxing they can +be made to support a full range of printers and file formats. However, +because each varient of the UNIX operating system uses a different +printing system than the next developing printer drivers for a wide +range of printers and operating systems is extremely difficult. That +combined with the limited volume of customers for each UNIX varient has +forced most printer vendors to give up supporting UNIX entirely. + +

    CUPS is designed to eliminate the printing problem. One +common printing system can be used by all UNIX varients to support the +printing needs of users. Printer vendors can use its modular filter +interface to develop a single driver program that supports a wide range +of file formats with little or no effort. Since CUPS provides both the +System V and Berkeley printing commands, users (and applications) can +reap the benefits of this new technology with no changes. + +

    The Technology

    + +

    CUPS is based upon an emerging Internet standard called the Internet +Printing Protocol. IPP has been embraced by dozens of printer and +printer server manufacturers and is supported by Microsoft Windows +2000. + +

    IPP defines a standard protocol for printing as well as managing +print jobs and printer options like media size, resolution, and so +forth. Like all IP-based protocols, IPP can be used locally or over the +Internet to printers hundreds or thousands of miles away. Unlike other +protocols, however, IPP also supports access control, authentication, +and encryption, making it a much more capable and secure printing +solution than older ones. + +

    IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP") +which is the basis of web servers on the Internet. This allows users +to view documentation, check status information on a printer or server, +and manage their printers, classes, and jobs using their web browser. + +

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

    Jobs

    + +

    Each file or set of files that is submitted for printing is called a +job. Jobs are identified by a unique number starting at 1 and +are assigned to a particular destination, usually a printer. Jobs can +also have options associated with them such as media size, number of +copies, and priority. + +

    Classes

    + +

    CUPS supports collections of printers known as classes. Jobs +sent to a class are forwarded to the first available printer in the +class. + +

    Filters

    + +

    Filters allow a user or application to print many types of files +without extra effort. Print jobs sent to a CUPS server are filtered +before sending them to a printer. Some filters convert job files to +different formats that the printer can understand. Others perform page +selection and ordering tasks. + +

    CUPS provides filters for printing many types of image files, +HP-GL/2 files, PDF files, and text files. CUPS also supplies PostScript +and image file Raster Image Processor ("RIP") filters that convert +PostScript or image files into bitmaps that can be sent to a raster +printer. + +

    Backends

    + +

    Backends perform the most important task of all - they send the +filtered print data to the printer. + +

    CUPS provides backends for printing over parallel, serial, and USB +ports, and over the network via the IPP, JetDirect (AppSocket), and +Line Printer Daemon ("LPD") protocols. Additional backends are +available in network service packages such as the SMB backend +included with the popular SAMBA software. + +

    Backends are also used to determine the available devices. On +startup each backend is asked for a list of devices it supports, +and any information that is available. This allows the parallel +backend to tell CUPS that an EPSON Stylus Color 600 printer is +attached to parallel port 1, for example. + +

    Printer Drivers

    + +

    Printer drivers in CUPS consist of one of more filters specific to a +printer. CUPS includes sample printer drivers for Hewlett-Packard +LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color, +and Stylus Photo printers. While these drivers do not generate optimal +output for the different printer models, they do provide basic printing +and demonstrate how you can write your own printer drivers and +incorporate them into CUPS. + +

    Networking

    + +

    Printers and classes on the local system are automatically shared +with other systems on the network. This allows you to setup one system +to print to a printer and use this system as a printer server or spool +host for all of the others. Users may then select a local printer by +name or a remote printer using "name@server". + +

    CUPS also provides implicit classes, which are collections of +printers and/or classes with the same name. This allows you to setup +multiple servers pointing to the same physical network printer, for +example, so that you aren't relying on a single system for printing. +Because this also works with printer classes, you can setup multiple +servers and printers and never worry about a single point of failure +unless all of the printers and servers go down! diff --git a/doc/references.shtml b/doc/references.shtml new file mode 100644 index 000000000..6a8dd82df --- /dev/null +++ b/doc/references.shtml @@ -0,0 +1,42 @@ +

    References

    + +

    CUPS Documentation

    + +

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

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

    Other Documents

    + +

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

    diff --git a/doc/robots.txt b/doc/robots.txt new file mode 100644 index 000000000..45dcdc221 --- /dev/null +++ b/doc/robots.txt @@ -0,0 +1,31 @@ +# +# "$Id: robots.txt 3494 2003-03-19 15:37:44Z mike $" +# +# This file tells search engines not to index your CUPS server. +# +# Copyright 1993-2003 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy 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 +# + +User-agent: * +Disallow: / + +# +# End of "$Id: robots.txt 3494 2003-03-19 15:37:44Z mike $". +# + diff --git a/doc/sam.html b/doc/sam.html new file mode 100644 index 000000000..85e9e4bcc --- /dev/null +++ b/doc/sam.html @@ -0,0 +1,5281 @@ + + + +CUPS Software Administrators Manual + + + + + + + +

    +

    CUPS Software Administrators Manual


    +CUPS-SAM-1.2.0
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    Preface + +1 - Printing System Overview + +2 - Building and Installing CUPS + +3 - Managing Printers + +4 - Printer Classes + +5 - Client Setup + +6 - Printing System Management + +7 - Printing with Other Systems + +A - Software License Agreement + +B - Common Network Settings + +C - Printer Drivers + +D - List of Files +
    +
    E - Troubleshooting Common Problems + +
    +

    Preface

    +

    This software administrators manual provides printer administration + information for the Common UNIX Printing SystemTM ("CUPS +TM"), version 1.2.0.

    +

    System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    + + +

    Document Overview

    +

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

    + +

    Notation Conventions

    +

    Various font and syntax conventions are used in this guide. Examples + and their meanings and uses are explained below: +

    + + + + + + + + + + + + +
    Example   Description
     
    lpstat +
    lpstat(1)
       The names of commands; + the first mention of a command or function in a chapter is followed by + a manual page section number.
     
    /var +
    /usr/share/cups/data/testprint.ps
        +File and directory names.
     
    Request ID is Printer-123 +   Screen output.
     
    lp -d printer filename ENTER +   Literal user input; special keys like ENTER are + in ALL CAPS.
     
    12.3   Numbers in the text are + written using the period (.) to indicate the decimal point.
    +
    + + +

    +

    Abbreviations

    + The following abbreviations are used throughout this manual: +
      +
      +
      kb
      +
      Kilobytes, or 1024 bytes +
       
      +
      Mb
      +
      Megabytes, or 1048576 bytes +
       
      +
      Gb
      +
      Gigabytes, or 1073741824 bytes +
       
      +
      +
    +

    Other References

    +
      +
      +
      CUPS Software Programmers Manual
      +
      A programmer guide for interfacing with and/or extending the CUPS + software. +
       
      +
      CUPS Software Users Manual
      +
      An end-user guide for using the CUPS software. +
       
      +
      +
    +

    1 - Printing System Overview

    +

    This chapter provides an overview of how the Common UNIX Printing + System works.

    +

    The Printing Problem

    +

    For years the printing problem has plagued UNIX. Unlike + Microsoft® Windows® or Mac OS, UNIX has no standard interface or system + in place for supporting printers. Among the solutions currently + available, the Berkeley and System V printing systems are the most + prevalent.

    +

    These printing systems support line printers (text only) or + PostScript printers (text and graphics), and with some coaxing they can + be made to support a full range of printers and file formats. However, + because each varient of the UNIX operating system uses a different + printing system than the next developing printer drivers for a wide + range of printers and operating systems is extremely difficult. That + combined with the limited volume of customers for each UNIX varient has + forced most printer vendors to give up supporting UNIX entirely.

    +

    CUPS is designed to eliminate the printing problem. One common + printing system can be used by all UNIX varients to support the + printing needs of users. Printer vendors can use its modular filter + interface to develop a single driver program that supports a wide range + of file formats with little or no effort. Since CUPS provides both the + System V and Berkeley printing commands, users (and applications) can + reap the benefits of this new technology with no changes.

    +

    The Technology

    +

    CUPS is based upon an emerging Internet standard called the Internet + Printing Protocol. IPP has been embraced by dozens of printer and + printer server manufacturers and is supported by Microsoft Windows + 2000.

    +

    IPP defines a standard protocol for printing as well as managing + print jobs and printer options like media size, resolution, and so + forth. Like all IP-based protocols, IPP can be used locally or over the + Internet to printers hundreds or thousands of miles away. Unlike other + protocols, however, IPP also supports access control, authentication, + and encryption, making it a much more capable and secure printing + solution than older ones.

    +

    IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP") + which is the basis of web servers on the Internet. This allows users to + view documentation, check status information on a printer or server, + and manage their printers, classes, and jobs using their web browser.

    +

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

    +

    Jobs

    +

    Each file or set of files that is submitted for printing is called a + job. Jobs are identified by a unique number starting at 1 and are + assigned to a particular destination, usually a printer. Jobs can also + have options associated with them such as media size, number of copies, + and priority.

    +

    Classes

    +

    CUPS supports collections of printers known as classes. Jobs + sent to a class are forwarded to the first available printer in the + class.

    +

    Filters

    +

    Filters allow a user or application to print many types of files + without extra effort. Print jobs sent to a CUPS server are filtered + before sending them to a printer. Some filters convert job files to + different formats that the printer can understand. Others perform page + selection and ordering tasks.

    +

    CUPS provides filters for printing many types of image files, HP-GL/2 + files, PDF files, and text files. CUPS also supplies PostScript and + image file Raster Image Processor ("RIP") filters that convert + PostScript or image files into bitmaps that can be sent to a raster + printer.

    +

    Backends

    +

    Backends perform the most important task of all - they send the + filtered print data to the printer.

    +

    CUPS provides backends for printing over parallel, serial, and USB + ports, and over the network via the IPP, JetDirect (AppSocket), and + Line Printer Daemon ("LPD") protocols. Additional backends are + available in network service packages such as the SMB backend included + with the popular SAMBA software.

    +

    Backends are also used to determine the available devices. On startup + each backend is asked for a list of devices it supports, and any + information that is available. This allows the parallel backend to tell + CUPS that an EPSON Stylus Color 600 printer is attached to parallel + port 1, for example.

    +

    Printer Drivers

    +

    Printer drivers in CUPS consist of one of more filters specific to a + printer. CUPS includes sample printer drivers for Hewlett-Packard + LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color, + and Stylus Photo printers. While these drivers do not generate optimal + output for the different printer models, they do provide basic printing + and demonstrate how you can write your own printer drivers and + incorporate them into CUPS.

    +

    Networking

    +

    Printers and classes on the local system are automatically shared + with other systems on the network. This allows you to setup one system + to print to a printer and use this system as a printer server or spool + host for all of the others. Users may then select a local printer by + name or a remote printer using "name@server".

    +

    CUPS also provides implicit classes, which are collections of + printers and/or classes with the same name. This allows you to setup + multiple servers pointing to the same physical network printer, for + example, so that you aren't relying on a single system for printing. + Because this also works with printer classes, you can setup multiple + servers and printers and never worry about a single point of failure + unless all of the printers and servers go down!

    +

    2 - Building and + Installing CUPS

    +

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

    +

    Installing a Source Distribution

    +

    This section describes how to compile and install CUPS on your system + from the source code.

    +

    Requirements

    +

    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.

    +

    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:

    + +

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

    + +

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

    + +

    Finally, you'll need a make program that understands the + include directive - FreeBSD, NetBSD, and OpenBSD + developers should use the gmake program.

    +

    Compiling CUPS

    +

    CUPS uses GNU autoconf to configure the makefiles and source code for + your system. Type the following command to configure CUPS for your + system:

    +
      +
      +./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, and LDFLAGS environment variables prior to + running configure:

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

    or:

    +
      +
      +CFLAGS="-I/some/directory"; export CFLAGS ENTER
      +CXXFLAGS="-I/some/directory"; export CXXFLAGS ENTER
      +LDFLAGS="-L/some/directory"; export LDFLAGS ENTER
      +DSOFLAGS="-L/some/directory"; export DSOFLAGS 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:

    + +

    If the OpenSSL headers and libraries are not installed in the + standard directories, use the --with-openssl-includes and +--with-openssl-libs options:

    +
      +
      +./configure --enable-ssl \
      +    --with-openssl-includes=/foo/bar/include \
      +    --with-openssl-libs=/foo/bar/lib
      +
      +
    +

    Once you have configured things, just type:

    +
      +
      +make ENTER
      +
      +
    +

    to build the software. + +

    +

    Installing the Software

    +

    Use the "install" target to install the software:

    +
      +
      +make install ENTER
      +
      +
    +
    + + +
    WARNING: +

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

    +
    +
    +

    Running the Software

    +

    Once you have installed the software you can start the CUPS server by + typing:

    +
      +
      +/usr/sbin/cupsd ENTER
      +
      +
    + + +

    Installing a Binary Distribution

    +

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

    + + +
    WARNING: +

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

    +
    +
    +

    +

    Installing a Portable Distribution

    +

    To install the CUPS software from a portable distribution 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 an RPM Distribution

    +

    To install the CUPS software from an RPM distribution you will need + to be logged in as root; doing an su is good enough. Once + you are the root user, run RPM with:

    +
      +
      +rpm -e lpr
      +rpm -i cups-1.1-linux-M.m.n-intel.rpm ENTER
      +
      +
    +

    After a short delay the CUPS software will be installed and the + scheduler will be started automatically.

    +

    Installing an Debian Distribution

    +

    To install the CUPS software from a Debian distribution you will need + to be logged in as root; doing an su is good enough. Once + you are the root user, run dpkg with:

    +
      +
      +dpkg -i cups-1.1-linux-M.m.n-intel.deb ENTER
      +
      +
    +

    After a short delay the CUPS software will be installed and the + scheduler will be started automatically.

    +

    3 - Managing Printers

    +

    This chapter describes how to add your first printer and how to + manage your printers.

    +

    The Basics

    +

    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.

    +

    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 parallel:/dev/lp1. + +

    +

    You can see a complete list of supported devices by running the +lpinfo(8) command:

    +
      +
      +lpinfo -v ENTER
      +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
      +
      +
    +

    The -v 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 +file:/directory/filename while network devices use the more + familiar method://server or method://server/path + format.

    +

    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.

    +

    Adding Your First Printer

    +

    CUPS provides two methods for adding printers: a command-line program + called lpadmin(8) and a Web interface. The lpadmin + command allows you to perform most printer administration tasks from + the command-line and is located in /usr/sbin. The Web + interface is located at:

    + +

    and steps you through printer configuration. If you don't like + command-line interfaces, try the Web interface + instead.

    +

    Adding Your First Printer from the Command-Line

    +

    Run the lpadmin command with the -p option + to add a printer to CUPS:

    +
      +
      +/usr/sbin/lpadmin -p printer -E -v device -m ppd ENTER
      +
      +
    +

    For a HP DeskJet printer connected to the parallel port this would + look like:

    +
      +
      +/usr/sbin/lpadmin -p DeskJet -E -v parallel:/dev/lp1 -m deskjet.ppd ENTER
      +
      +
    +

    Similarly, a HP LaserJet printer using a JetDirect network interface + at IP address 11.22.33.44 would be added with the command:

    +
      +
      +/usr/sbin/lpadmin -p LaserJet -E -v socket://11.22.33.44 -m laserjet.ppd ENTER
      +
      +
    +

    As you can see, deskjet.ppd and laserjet.ppd + 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 Appendix C, "Printer + Drivers".

    +

    For a dot matrix printer connected to the serial port this would + might look like:

    +
      +
      +/usr/sbin/lpadmin -p DotMatrix -E -v serial:/dev/ttyS0?baud=9600+size=8+parity=none+flow=soft deskjet.ppd ENTER
      +
      +
    +

    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.

    +

    Adding Your First Printer from the Web

    +

    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:

    + +

    Click on the Add Printer button to add a printer.

    +

    Managing Printers from the Command-Line

    +

    The lpadmin command enables you to perform most printer + administration tasks from the command-line. You'll find lpadmin + in the /usr/sbin directory.

    +

    Adding and Modifying Printers

    +

    Run the lpadmin command with the -p option + to add or modify a printer:

    +
      +
      +/usr/sbin/lpadmin -p printer options ENTER
      +
      +
    +

    The options arguments can be any of the following:

    +
      +
      +
      -c class
      +
      Adds the named printer to printer class class. If the + class does not exist then it is created.
      +
      -i interface
      +
      Copies the named interface 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.
      +
      -m model
      +
      Specifies a standard printer driver which is usually a PPD file. A + list of all available models can be displayed using the lpinfo + command with the -m option. A list of printer drivers + included with CUPS can be found in Appendix + C, "Printer Drivers".
      +
      -r class
      +
      Removes the named printer from printer class class. If + the resulting class becomes empty then it is removed.
      +
      -v device-uri
      +
      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.
      +
      -D info
      +
      Provides a textual description of the printer, e.g. "John's Personal + Printer".
      +
      -E
      +
      Enables the printer and accepts job. This option is equivalent to + running the enable(1) and accept(8) commands + on the printer.
      +
      -L location
      +
      Provides a textual location for the printer, e.g. "Computer Lab 5".
      +
      -P ppd-file
      +
      Specifies a local PPD file for the printer driver.
      +
      +
    +

    Deleting Printers

    +

    Run the lpadmin command with the -x option + to delete a printer:

    +
      +
      +/usr/sbin/lpadmin -x printer ENTER
      +
      +
    +

    Setting the Default Printer

    +

    Run the lpadmin command with the -d option + to set a default printer:

    +
      +
      +/usr/sbin/lpadmin -d printer ENTER
      +
      +
    +

    The default printer can be overridden by the user using the +lpoptions(1) command.

    +

    Starting and Stopping Printers

    +

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

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

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

    +

    Accepting and Rejecting Print Jobs

    +

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

    +
      +
      +/usr/sbin/accept printer ENTER
      +/usr/sbin/reject printer ENTER
      +
      +
    +

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

    +

    Setting Quotas on a Printer

    +

    CUPS supports page and size-based quotas for each printer. The quotas + are tracked individually for each user, but a single set of limits + applies to all users for a partiuclar printer. For example, you can + limit every user to 5 pages per day on an expensive printer, but you + cannot limit every user except Johnny.

    +

    The job-k-limit, job-page-limit, and job-quota-peiod + options determine whether and how quotas are enforced for a printer. + The job-quota-period option determines the time interval for + quota tracking. The interval is expressed in seconds, so a day is + 86,400, a week is 604,800 and a month is 2,592,000 seconds. The + job-k-limit option specifies the job size limit in killobytes. The + job-page-limit option specifies the number of pages limit.

    +

    For quotas to be enforced, the period and at least one of the limits + must be set to a non-zero value. The following options will enable + quotas:

    +
      +
      +/usr/sbin/lpadmin -p printer -o job-quota-period=604800 -o job-k-limit=1024 ENTER
      +/usr/sbin/lpadmin -p printer -o job-quota-period=604800 -o job-page-limit=100 ENTER
      +
      +
    +

    Or, you can combine all three options on the same line.

    +

    Restricting User Access to a Printer

    +

    The -u option of the lpadmin command + controls which users can print to a printer. The default configuration + allows all users to print to a printer:

    +
      +
      +/usr/sbin/lpadmin -p printer -u allow:all ENTER
      +
      +
    +

    CUPS supports allow and deny lists so that you can specify a list of + users who are allowed to print or not allowed to print. Along with your + list of users, you can specify whether they are allowed or not allowed + to use the printer:

    +
      +
      +/usr/sbin/lpadmin -p printer -u allow:peter,paul,mary ENTER
      +
      +
    +

    This command allows peter, paul, and mary to print to the named + printer, but all other users cannot print. The command:

    +
      +
      +/usr/sbin/lpadmin -p printer -u deny:peter,paul,mary ENTER
      +
      +
    +

    has the opposite effect. All users except peter, paul, and mary will + be able to print to the named printer.

    +
    + + +
    NOTE: +

    The allow and deny options are not cummulative. That + is, you must provide the complete list of users to allow or deny each + time.

    +

    Also, CUPS only maintains one list of users - the list can allow or + deny users from printing. If you specify an allow list and then specify + a deny list, the deny list will replace the allow list - only one list + is active at any time.

    +
    +
    +

    Managing Printers from the Web

    +

    The Web interface is located at:

    + +

    From there you can perform all printer management tasks with a few + simple mouse clicks.

    +

    4 - Printer Classes

    +

    This chapter describes what printer classes are and how to manage + them.

    +

    The Basics

    +

    CUPS provides collections of printers called printer classes. + 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.

    +

    CUPS also supports implicit classes. 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.

    +

    Managing Printer Classes from the Command-Line

    +

    Run the lpadmin command with the -p and +-c options to add a printer to a class:

    +
      +
      +/usr/sbin/lpadmin -p printer -c class ENTER
      +
      +
    +

    The class is created automatically if it doesn't exist. To + remove a printer from a class use the -r option:

    +
      +
      +/usr/sbin/lpadmin -p printer -r class ENTER
      +
      +
    +

    To remove the entire class just use the -x option:

    +
      +
      +/usr/sbin/lpadmin -x class ENTER
      +
      +
    +

    Managing Printer Classes from the Web Interface

    +

    The Web interface is located at:

    + +

    The Add Class and Modify Class interfaces + provide a list of available printers; click on the printers of interest + to add them to the class.

    +

    Implicit Classes

    +

    A noted earlier, implicit classes are created automatically from the + available network printers and classes. To disable this functionality, + set the ImplicitClasses + directive to Off in the cupsd.conf file. You + will find more information on doing this in + Chapter 6, "Printing System Management".

    +

    5 - Client Setup

    +

    This chapter discusses several ways to configure CUPS clients for + printing.

    +

    The Basics

    +

    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.

    +

    CUPS supports several methods of configuring client machines:

    + +

    Manual Configuration of Print Queues

    +

    The most tedious method of configuring client machines is to + configure each remote queue by hand using the lpadmin + command:

    +
      +
      +lpadmin -p printer -E -v ipp://server/printers/printer ENTER
      +
      +
    +

    The printer name is the name of the printer on the + server machine. The server name is the hostname or IP + address of the server machine. Repeat the lpadmin command + for each remote printer you wish to use.

    +
    + + +
    NOTE: +

    Manual configuration of print queues is not recommended for large + numbers of client machines because of the administration nightmare it + creates. For busy networks, consider subnetting groups of clients and + polling and relaying printer information instead.

    +
    +
    +

    Specifying a Single Server for Printing

    +

    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.

    +

    The default server is normally "localhost". To override the default + server create a file named /etc/cups/client.conf and add a + line reading:

    +
      +
      +ServerName server
      +
      +
    +

    to the file. The server name can be the hostname or IP + address of the default server.

    +

    The default server can also be customized on a per-user basis. To set + a user-specific server create a file named ~/.cupsrc and add + a line reading:

    +
      +
      +ServerName server
      +
      +
    +

    to the file. The server name can be the hostname or IP + address of the default server.

    +

    Automatic Configuration of Print Queues

    +

    CUPS supports automatic client configuration of printers on the same + subnet. To configure printers on the same subnet, do nothing. + 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.

    +

    If you want to see printers on other subnets as well, use the + BrowsePoll directive as described next.

    +
    + + +
    NOTE: +

    The BrowseAddress directive + enables broadcast traffic from your server. The default configuration + braodcasts printer information every 30 seconds. Although this printer + information does not use much bandwidth, typically about 80 bytes per + printer, it can add up with large numbers of servers and printers.

    +

    Use the BrowseInterval and BrowseTimeout directives to tune + the amount of data that is added to your network load. In addition, + subnets can be used to minimize the amount of traffic that is carried + by the "backbone" of your large network.

    +
    +
    +

    Specifying Multiple Servers for Printing

    +

    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.

    +

    Polling is enabled by specifying one or more +BrowsePoll directives in the /etc/cups/cupsd.conf + file. For information on making these changes, see + Chapter 6, "Printing System Management".

    +

    Multiple BrowsePoll lines can + be used to poll multiple CUPS servers. To limit the amount of polling + you do from client machines, you can have only one of the clients do + the polling and relay that information to the others on the same subnet + (described next).

    +

    Relaying Printers to Other Clients

    +

    When you have clients and servers spread across multiple subnets, the + polling method is inefficient. CUPS provides a +BrowseRelay directive that enables a single client to relay + (broadcast) the polled printer information to the local subnet.

    +

    For example, Server A and Server B are on subnet 1 and subnet 2, + while the clients are on subnet 3. To provide printers to all of the + clients in subnet 3, client C will be configured with the following + directives in /etc/cups/cupsd.conf:

    +
      +
      +# Poll the two servers
      +
      +BrowsePoll ServerA ENTER
      +BrowsePoll ServerB ENTER
      +
      +
      +# Relay the printers to the local subnet
      +
      +BrowseRelay 127.0.0.1 192.168.3.255 ENTER
      +
      +
    +

    The BrowseRelay line + specifies a source address and mask. Any browse packets coming from a + matching address wil be sent to the given broadcast address. In this + case, we want the packets from the local machine (127.0.0.1) relayed to + the other clients.

    +

    As printers are found using polling, they are relayed from client C + to the rest of the clients through a broadcast on subnet 3. The rest of + the clients can use the standard cupsd.conf configuration.

    +

    The BrowseRelay directive can + also be used to relay browsing packets from one network interface to + another. For example, if client C in the previous example had network + interfaces attaches to both subnet 1 and subnet 2, it could use the + BrowseRelay directive exclusively:

    +
      +
      +# Relay the printers from subnet 1 and 2 to subnet 3
      +
      +BrowseRelay 192.168.1 192.168.3.255 ENTER
      +BrowseRelay 192.168.2 192.168.3.255 ENTER
      +
      +
    +

    Load Balancing and Failsafe Operation

    +

    When using server polling or broadcasting, CUPS clients can + automatically merge identical printers on multiple servers into a + single implicit class queue. Clients assume that printers with + the same name on multiple servers are in fact the same printer or type + of printer being served by multiple machines.

    +

    If you have two printers, LaserJet@ServerA and LaserJet@ServerB, a + third implicit class called LaserJet will be created + automatically on the client that refers to both printers. If the client + also has a local printer with the name LaserJet then an implicit class + named AnyLaserJet will be created instead.

    +

    The client will alternate between servers and automatically stop + sending jobs to a server if it goes down, providing a load-balancing + effect and fail-safe operation with automatic switchover.

    +
    + + +
    NOTE: +

    Note that implicit classes ( +ImplicitClasses) are enabled by default.

    +
    +
    +

    6 - Printing System + Management

    +

    This chapter shows how you can configure the CUPS server.

    +

    The Basics

    +

    Several text files are used to configure CUPS. All of the server + configuration files are located in the /etc/cups directory:

    +
      +
      + + +
      classes.conf
      +
      This file contains information on each printer class. Normally you + manipulate this file using the lpadmin command or the Web + interface. +
        + +
      +
      client.conf
      +
      This file provides the default server name for client machines. See Chapter 5, "Client Setup" for more + information. +
        + +
      +
      cupsd.conf
      +
      This file controls how the CUPS server (/usr/sbin/cupsd) + operates and is normally edited by hand. +
        + +
      +
      mime.convs
      +
      This file contains a list of standard file conversion filters and + their costs. You normally do not edit this file. +
        + +
      +
      mime.types
      +
      This file contains a list of standard file formats and how to + recognize them. You normally do not edit this file. +
        + +
      +
      printers.conf
      +
      This file contains information on each printer. Normally you + manipulate this file using the lpadmin command or the Web + Interface. +
       
      +
      +
    +

    Restarting the CUPS Server

    +

    Once you have made a change to a configuration file you need to + restart the CUPS server by sending it a HUP signal or + using the supplied initialization script. The CUPS distributions + install the script in the init.d directory with the name + cups. The location varies based upon the operating system:

    +
      +
      +/etc/software/init.d/cups restart ENTER
      +/etc/rc.d/init.d/cups restart ENTER
      +/etc/init.d/cups restart ENTER
      +/sbin/init.d/cups restart ENTER
      +
      +
    +

    Changing the Server Configuration

    +

    The /etc/cups/cupsd.conf file contains configuration + directives 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. + +

    +

    Server Directives

    +

    The cupsd.conf file contains many directives that + determine how the server operates:

    + + + +

    AccessLog

    +
    +

    Examples

    +
      +
      +AccessLog /var/log/cups/access_log
      +AccessLog /var/log/cups/access_log-%s
      +AccessLog syslog
      +
      +
    +

    Description

    +

    The AccessLog directive sets the name of the access log + file. If the filename is not absolute then it is assumed to be relative + to the ServerRoot 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.

    +

    The server name can be included in the filename by using %s + in the name.

    +

    The special name "syslog" can be used to send the access information + to the system log instead of a plain file.

    +

    The default access log file is /var/log/cups/access_log. + +

    +

    Allow

    +
    +

    Examples

    +
      +
      +Allow from All
      +Allow from None
      +Allow from *.domain.com
      +Allow from .domain.com
      +Allow from host.domain.com
      +Allow from nnn.*
      +Allow from nnn.nnn.*
      +Allow from nnn.nnn.nnn.*
      +Allow from nnn.nnn.nnn.nnn
      +Allow from nnn.nnn.nnn.nnn/mm
      +Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
      +Allow from @LOCAL
      +Allow from @IF(name)
      +
      +
    +

    Description

    +

    The Allow directive specifies a hostname, IP address, or + network that is allowed access to the server. Allow + directives are cummulative, so multiple Allow directives + can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: +

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

    +

    The @LOCAL name will allow access from all local network + interfaces, but not remote point-to-point interfaces. The +@IF(name) name will allow access from the named interface.

    +

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

    +

    AuthClass

    +
    +

    Examples

    +
      +
      +AuthClass Anonymous
      +AuthClass User
      +AuthClass System
      +AuthClass Group
      +
      +
    +

    Description

    +

    The AuthClass directive defines what level of + authentication is required:

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

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

    +

    AuthGroupName

    +
    +

    Examples

    +
      +
      +AuthGroupName mygroup
      +AuthGroupName lp
      +
      +
    +

    Description

    +

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

    +

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

    +

    AuthType

    +
    +

    Examples

    +
      +
      +AuthType None
      +AuthType Basic
      +AuthType Digest
      +AuthType BasicDigest
      +
      +
    +

    Description

    +

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

    +
      +
    • None - No authentication should be performed (default.)
    • +
    • Basic - Basic authentication should be performed using + the UNIX password and group files.
    • +
    • Digest - Digest authentication should be performed + using the /etc/cups/passwd.md5 file.
    • +
    • BasicDigest - Basic authentication should be performed + using the /etc/cups/passwd.md5 file.
    • +
    +

    When using Basic, Digest, or +BasicDigest authentication, clients connecting through the +localhost interface can also authenticate using + certificates.

    +

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

    +

    AutoPurgeJobs

    +
    +

    Examples

    +
      +
      +AutoPurgeJobs Yes
      +AutoPurgeJobs No
      +
      +
    +

    Description

    +

    The AutoPurgeJobs 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 +No. + +

    +

    BrowseAddress

    +
    +

    Examples

    +
      +
      +BrowseAddress 255.255.255.255:631
      +BrowseAddress 192.0.2.255:631
      +BrowseAddress host.domain.com:631
      +BrowseAddress @LOCAL
      +BrowseAddress @IF(name)
      +
      +
    +

    Description

    +

    The BrowseAddress directive specifies an address to send + browsing information to. Multiple BrowseAddress directives + can be specified to send browsing information to different networks or + systems.

    +

    The @LOCAL name will broadcast printer information to + all local interfaces. The @IF(name) name will broadcast to + the named interface.

    +

    No browse addresses are set by default.

    +
    + + +
    NOTE: +

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

    +
    +
    + + +

    BrowseAllow

    +
    +

    Examples

    +
      +
      +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
      +BrowseAllow from @LOCAL
      +BrowseAllow from @IF(name)
      +
      +
    +

    Description

    +

    The BrowseAllow directive specifies a system or network + to accept browse packets from. The default is to accept browse packets + from all hosts.

    +

    Host and domain name matching require that you enable the + HostNameLookups directive.

    +

    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.

    +

    The @LOCAL name will allow browse data from all local + network interfaces, but not remote point-to-point interfaces. The +@IF(name) name will allow browse data from the named interface. + +

    +

    BrowseDeny

    +
    +

    Examples

    +
      +
      +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
      +BrowseDeny from @LOCAL
      +BrowseDeny from @IF(name)
      +
      +
    +

    Description

    +

    The BrowseDeny directive specifies a system or network + to reject browse packets from. The default is to deny browse packets + from no hosts.

    +

    Host and domain name matching require that you enable the + HostNameLookups directive.

    +

    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.

    +

    The @LOCAL name will block browse data from all local + network interfaces, but not remote point-to-point interfaces. The +@IF(name) name will block browse data from the named interface. + +

    +

    BrowseOrder

    +
    +

    Examples

    +
      +
      +BrowseOrder allow,deny
      +BrowseOrder deny,allow
      +
      +
    +

    Description

    +

    The BrowseOrder directive specifies the order of + allow/deny processing. The default order is deny,allow:

    +
      +
    • allow,deny - Browse packets are accepted unless + specifically denied.
    • +
    • deny,allow - Browse packets are rejected unless + specifically allowed.
    • +
    + + +

    BrowseInterval

    +
    +

    Examples

    +
      +
      +BrowseInterval 0
      +BrowseInterval 30
      +
      +
    +

    Description

    +

    The BrowseInterval 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.

    +

    The BrowseInterval value should always be less than the BrowseTimeout value. Otherwise + printers and classes will disappear from client systems between + updates. + +

    +

    BrowsePoll

    +
    +

    Examples

    +
      +
      +BrowsePoll 192.0.2.2:631
      +BrowsePoll host.domain.com:631
      +
      +
    +

    Description

    +

    The BrowsePoll directive polls a server for available + printers once every BrowseInterval + seconds. Multiple BrowsePoll directives can be + specified to poll multiple servers.

    +

    If BrowseInterval is set to 0 then the server is polled + once every 30 seconds. + +

    +

    BrowsePort

    +
    +

    Examples

    +
      +
      +BrowsePort 631
      +BrowsePort 9999
      +
      +
    +

    Description

    +

    The BrowsePort directive specifies the UDP port number + used for browse packets. The default port number is 631.

    +
    + + +
    NOTE: +

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

    +
    +
    + + +

    BrowseProtocols

    +
    +

    Examples

    +
      +
      +BrowseProtocols CUPS
      +BrowseProtocols SLP
      +BrowseProtocols CUPS SLP
      +BrowseProtocols all
      +
      +
    +

    Description

    +

    The BrowseProtocols directive specifies the protocols to + use when collecting and distributing shared printers on the local + network. The default protocol is CUPS, which is a + broadcast-based protocol.

    +
    + + +
    NOTE: +

    When using the SLP protocol, you must have at least one + Directory Agent (DA) server on your network. Otherwise the CUPS + scheduler (cupsd) will not respond to client requests for + several seconds while polling the network.

    +
    +
    + + +

    BrowseRelay

    +
    +

    Examples

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

    Description

    +

    The BrowseRelay directive specifies source and + destination addresses for relaying browsing information from one host + or network to another. Multiple BrowseRelay directives can + be specified as needed.

    +

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

    +
      +
      +BrowseRelay 127.0.0.1 255.255.255.255
      +
      +
    +

    This effectively provides access to printers on a WAN for all clients + on the LAN(s). + +

    +

    BrowseShortNames

    +
    +

    Examples

    +
      +
      +BrowseShortNames Yes
      +BrowseShortNames No
      +
      +
    +

    Description

    +

    The BrowseShortNames 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".)

    +

    The default value for this option is Yes. + +

    +

    BrowseTimeout

    +
    +

    Examples

    +
      +
      +BrowseTimeout 300
      +BrowseTimeout 60
      +
      +
    +

    Description

    +

    The BrowseTimeout 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.

    +

    The BrowseTimeout value should always be greater than + the BrowseInterval value. + Otherwise printers and classes will disappear from client systems + between updates. + +

    +

    Browsing

    +
    +

    Examples

    +
      +
      +Browsing On
      +Browsing Off
      +
      +
    +

    Description

    +

    The Browsing directive controls whether or not network + printer browsing is enabled. The default setting is On.

    +
    + + +
    NOTE: +

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

    +
    +
    + + +

    Classification

    +
    +

    Examples

    +
      +
      +Classification
      +Classification classified
      +Classification confidential
      +Classification secret
      +Classification topsecret
      +Classification unclassified
      +
      +
    +

    Description

    +

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

    +

    ClassifyOverride

    +
    +

    Examples

    +
      +
      +ClassifyOverride Yes
      +ClassifyOverride No
      +
      +
    +

    Description

    +

    The ClassifyOverride 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 job-sheets option and can choose to only print one + security banner before or after the job. If the job-sheets + option is set to none then the server default + classification is used.

    +

    The default is to not allow classification overrides. + +

    +

    ConfigFilePerm

    +
    +

    Examples

    +
      +
      +ConfigFilePerm 0644
      +ConfigFilePerm 0600
      +
      +
    +

    Description

    +

    The ConfigFilePerm directive specifies the permissions + to use when writing configuration files. The default is 0600. + +

    +

    DataDir

    +
    +

    Examples

    +
      +
      +DataDir /usr/share/cups
      +
      +
    +

    Description

    +

    The DataDir directive sets the directory to use for data + files. + +

    +

    DefaultCharset

    +
    +

    Examples

    +
      +
      +DefaultCharset utf-8
      +DefaultCharset iso-8859-1
      +DefaultCharset windows-1251
      +
      +
    +

    Description

    +

    The DefaultCharset directive sets the default character + set to use for client connections. The default character set is +utf-8 but is overridden by the character set for the language + specified by the client or the DefaultLanguage directive. + +

    +

    DefaultLanguage

    +
    +

    Examples

    +
      +
      +DefaultLanguage de
      +DefaultLanguage en
      +DefaultLanguage es
      +DefaultLanguage fr
      +DefaultLanguage it
      +
      +
    +

    Description

    +

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

    +

    Deny

    +
    +

    Examples

    +
      +
      +Deny from All
      +Deny from None
      +Deny from *.domain.com
      +Deny from .domain.com
      +Deny from host.domain.com
      +Deny from nnn.*
      +Deny from nnn.nnn.*
      +Deny from nnn.nnn.nnn.*
      +Deny from nnn.nnn.nnn.nnn
      +Deny from nnn.nnn.nnn.nnn/mm
      +Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
      +Deny from @LOCAL
      +Deny from @IF(name)
      +
      +
    +

    Description

    +

    The Deny directive specifies a hostname, IP address, or + network that is allowed access to the server. Deny + directives are cummulative, so multiple Deny directives + can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: +

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

    +

    The @LOCAL name will deny access from all local network + interfaces, but not remote point-to-point interfaces. The +@IF(name) name will deny access from the named interface.

    +

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

    +

    DocumentRoot

    +
    +

    Examples

    +
      +
      +DocumentRoot /usr/share/doc/cups
      +DocumentRoot /foo/bar/doc/cups
      +
      +
    +

    Description

    +

    The DocumentRoot 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 + ServerRoot directory. The default directory is + /usr/share/doc/cups.

    +

    Documents are first looked up in a sub-directory for the primary + language requested by the client (e.g. /usr/share/doc/cups/fr/... +) and then directly under the DocumentRoot directory (e.g. + /usr/share/doc/cups/...), so it is possible to localize the web + content by providing subdirectories for each language needed. + +

    +

    Encryption

    +
    +

    Examples

    +
      +
      +Encryption Never
      +Encryption IfRequested
      +Encryption Required
      +Encryption Always
      +
      +
    +

    Description

    +

    The Encryption directive must appear instead a + Location section and specifies the encryption settings + for that location. The default setting is IfRequested for + all locations. + +

    +

    ErrorLog

    +
    +

    Examples

    +
      +
      +ErrorLog /var/log/cups/error_log
      +ErrorLog /var/log/cups/error_log-%s
      +ErrorLog syslog
      +
      +
    +

    Description

    +

    The ErrorLog directive sets the name of the error log + file. If the filename is not absolute then it is assumed to be relative + to the ServerRoot directory. The + default error log file is /var/log/cups/error_log.

    +

    The server name can be included in the filename by using %s + in the name.

    +

    The special name "syslog" can be used to send the error information + to the system log instead of a plain file. + +

    +

    FilterLimit

    +
    +

    Examples

    +
      +
      +FilterLimit 0
      +FilterLimit 200
      +FilterLimit 1000
      +
      +
    +

    Description

    +

    The FilterLimit 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.

    +

    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.

    +

    The default limit is 0. + +

    +

    FilterNice

    +
    +

    Examples

    +
      +
      +FilterNice 0
      +FilterNice 39
      +FilterNice -10
      +
      +
    +

    Description

    +

    The FilterNice directive sets the scheduling priority of + job filters. Values larger than 0 give filters a lower priority while + values smaller than 0 give filters a higher priority. The +FilterNice value does not affect the priority of job backends.

    +

    The default priority is 0. + +

    +

    FontPath

    +
    +

    Examples

    +
      +
      +FontPath /foo/bar/fonts
      +FontPath /usr/share/cups/fonts:/foo/bar/fonts
      +
      +
    +

    Description

    +

    The FontPath directive specifies the font path to use + when searching for fonts. The default font path is +/usr/share/cups/fonts. + +

    +

    Group

    +
    +

    Examples

    +
      +
      +Group sys
      +Group system
      +Group root
      +
      +
    +

    Description

    +

    The Group directive specifies the UNIX group that filter + and CGI programs run as. The default group is sys, +system, or root depending on the operating system. + +

    +

    HideImplicitMembers

    +
    +

    Examples

    +
      +
      +HideImplicitMembers Yes
      +HideImplicitMembers No
      +
      +
    +

    Description

    +

    The HideImplicitMembers directive controls whether the + individual printers in an implicit class are shown to the user. The + default is No.

    +

    ImplicitClasses must be + enabled for this directive to have any effect.

    + + +

    HostNameLookups

    +
    +

    Examples

    +
      +
      +HostNameLookups On
      +HostNameLookups Off
      +HostNameLookups Double
      +
      +
    +

    Description

    +

    The HostNameLookups directive controls whether or not + CUPS looks up the hostname for connecting clients. The Double + setting causes CUPS to verify that the hostname resolved from the + address matches one of the addresses returned for that hostname. +Double lookups also prevent clients with unregistered addresses + from connecting to your server. The default is Off to + avoid the potential server performance problems with hostname lookups. + Set this option to On or Double only if + absolutely required. + +

    +

    ImplicitClasses

    +
    +

    Examples

    +
      +
      +ImplicitClasses On
      +ImplicitClasses Off
      +
      +
    +

    Description

    +

    The ImplicitClasses directive controls whether implicit + classes are created based upon the available network printers and + classes. The default setting is On but is automatically + turned Off if Browsing + is turned Off. + +

    +

    ImplicitAnyClasses

    +
    +

    Examples

    +
      +
      +ImplicitAnyClasses On
      +ImplicitAnyClasses Off
      +
      +
    +

    Description

    +

    The ImplicitAnyClasses directive controls whether + implicit classes for local and remote printers are created with the + name AnyPrinter. The default setting is Off.

    +

    ImplicitClasses must be + enabled for this directive to have any effect.

    + + +

    Include

    +
    +

    Examples

    +
      +
      +Include filename
      +Include /foo/bar/filename
      +
      +
    +

    Description

    +

    The Include directive includes the named file in the +cupsd.conf file. If no leading path is provided, the file is + assumed to be relative to the ServerRoot + directory.

    + + +

    KeepAlive

    +
    +

    Examples

    +
      +
      +KeepAlive On
      +KeepAlive Off
      +
      +
    +

    Description

    +

    The KeepAlive directive controls whether or not to + support persistent HTTP connections. The default is On.

    +

    HTTP/1.1 clients automatically support persistent connections, while + HTTP/1.0 clients must specifically request them using the +Keep-Alive attribute in the Connection: field of + each request. + +

    +

    KeepAliveTimeout

    +
    +

    Examples

    +
      +
      +KeepAliveTimeout 60
      +KeepAliveTimeout 30
      +
      +
    +

    Description

    +

    The KeepAliveTimeout directive controls how long a + persistent HTTP connection will remain open after the last request. The + default is 60 seconds. + +

    +

    Limit

    +
    +

    Examples

    +
      +
      +<Limit GET POST>
      +...
      +</Limit>
      +
      +<Limit ALL>
      +...
      +</Limit>
      +
      +
    +

    Description

    +

    The Limit directive groups access control directives for + specific types of HTTP requests and must appear inside a + Location section. Access can be limited for individual + request types (DELETE, GET, HEAD +, OPTIONS, POST, PUT, and +TRACE) or for all request types (ALL). The request + type names are case-sensitive for compatibility with Apache. + +

    +

    LimitExcept

    +
    +

    Examples

    +
      +
      +<LimitExcept GET POST>
      +...
      +</LimitExcept>
      +
      +
    +

    Description

    +

    The LimitExcept directive groups access control + directives for specific types of HTTP requests and must appear inside a Location section. Unlike the + Limit directive, LimitExcept restricts + access for all requests except those listed on the +LimitExcept line. + +

    +

    LimitRequestBody

    +
    +

    Examples

    +
      +
      +LimitRequestBody 10485760
      +LimitRequestBody 10m
      +LimitRequestBody 0
      +
      +
    +

    Description

    +

    The LimitRequestBody 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.

    +

    Also see the identical MaxRequestSize + directive. + +

    +

    Listen

    +
    +

    Examples

    +
      +
      +Listen 127.0.0.1:631
      +Listen 192.0.2.1:631
      +
      +
    +

    Description

    +

    The Listen directive specifies a network address and + port to listen for connections. Multiple Listen directives + can be provided to listen on multiple addresses.

    +

    The Listen directive is similar to the +Port directive but allows you to restrict access to specific + interfaces or networks. + +

    +

    Location

    +
    +

    Examples

    +
      +
      +<Location />
      +...
      +</Location>
      +
      +<Location /admin>
      +...
      +</Location>
      +
      +<Location /printers>
      +...
      +</Location>
      +
      +<Location /printers/name>
      +...
      +</Location>
      +
      +<Location /classes>
      +...
      +</Location>
      +
      +<Location /classes/name>
      +...
      +</Location>
      +
      +
    +

    Description

    +

    The Location directive specifies access control and + authentication options for the specified HTTP resource or path. The + Allow, AuthClass +, AuthGroupName, + AuthType, Deny, + Encryption, Limit, + LimitExcept, Order, Require, and +Satisfy directives may all appear inside a location. +

    + + + + + + + + + + + + + + +
    Locations on the Server.
    LocationDescription
    /The path for all get operations (get-printers, + get-jobs, etc.)
    /adminThe path for all administration operations + (add-printer, delete-printer, start-printer, etc.)
    /admin/confThe path for access to the ESP Print Pro + configuration files (cupsd.conf, client.conf, etc.)
    /classesThe path for all classes
    /classes/nameThe resource for class name
    /jobsThe path for all jobs (hold-job, release-job, + etc.)
    /jobs/idThe resource for job id
    /printersThe path for all printers
    /printers/nameThe path for printer name
    /printers/name.ppdThe PPD file path for printer +name
    +
    +

    +

    Note that more specific resources override the less specific ones. So + the directives inside the /printers/name location will + override ones from /printers. Directives inside +/printers will override ones from /.   None of the + directives are inherited. More information can be found in section + "Printing System Security". + +

    +

    LogFilePerm

    +
    +

    Examples

    +
      +
      +LogFilePerm 0644
      +LogFilePerm 0600
      +
      +
    +

    Description

    +

    The LogFilePerm directive specifies the permissions to + use when writing configuration files. The default is 0644. + +

    +

    LogLevel

    +
    +

    Examples

    +
      +
      +LogLevel none
      +LogLevel emerg
      +LogLevel alert
      +LogLevel crit
      +LogLevel error
      +LogLevel warn
      +LogLevel notice
      +LogLevel info
      +LogLevel debug
      +LogLevel debug2
      +
      +
    +

    Description

    +

    The LogLevel directive specifies the level of logging + for the ErrorLog file. The + following values are recognized (each level logs everything under the + preceding levels):

    +
      +
    • none - Log nothing.
    • +
    • emerg - Log emergency conditions that prevent the + server from running.
    • +
    • alert - Log alerts that must be handled immediately.
    • +
    • crit - Log critical errors that don't prevent the + server from running.
    • +
    • error - Log general errors.
    • +
    • warn - Log errors and warnings.
    • +
    • notice - Log temporary error conditions.
    • +
    • info - Log all requests and state changes (default).
    • +
    • debug - Log basic debugging information.
    • +
    • debug2 - Log all debugging information.
    • +
    + + +

    MaxClients

    +
    +

    Examples

    +
      +
      +MaxClients 100
      +MaxClients 1024
      +
      +
    +

    Description

    +

    The MaxClients directive controls the maximum number of + simultaneous clients that will be allowed by the server. The default is + 100 clients.

    +
    + + +
    NOTE: +

    Since each print job requires a file descriptor for the status pipe, + the CUPS server internally limits the MaxClients value to + 1/3 of the available file descriptors to avoid possible problems when + printing large numbers of jobs.

    +
    +
    + + +

    MaxCopies

    +
    +

    Examples

    +
      +
      +MaxCopies 100
      +MaxCopies 65535
      +
      +
    +

    Description

    +

    The MaxCopies directive controls the maximum number of + copies that a user can print of a job. The default is 100 copies.

    +
    + + +
    NOTE: +

    Most HP PCL laser printers internally limit the number of copies to + 100.

    +
    +
    + + +

    MaxJobs

    +
    +

    Examples

    +
      +
      +MaxJobs 100
      +MaxJobs 9999
      +MaxJobs 0
      +
      +
    +

    Description

    +

    The MaxJobs 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.

    +

    Setting the maximum to 0 disables this functionality. The default + setting is 0. + +

    +

    MaxJobsPerPrinter

    +
    +

    Examples

    +
      +
      +MaxJobsPerPrinter 100
      +MaxJobsPerPrinter 9999
      +MaxJobsPerPrinter 0
      +
      +
    +

    Description

    +

    The MaxJobsPerPrinter 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.

    +

    Setting the maximum to 0 disables this functionality. The default + setting is 0. + +

    +

    MaxJobsPerUser

    +
    +

    Examples

    +
      +
      +MaxJobsPerUser 100
      +MaxJobsPerUser 9999
      +MaxJobsPerUser 0
      +
      +
    +

    Description

    +

    The MaxJobsPerUser 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.

    +

    Setting the maximum to 0 disables this functionality. The default + setting is 0. + +

    +

    MaxLogSize

    +
    +

    Examples

    +
      +
      +MaxLogSize 1048576
      +MaxLogSize 1m
      +MaxLogSize 0
      +
      +
    +

    Description

    +

    The MaxLogSize 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 filename.O. This allows you to + rotate the logs automatically. The default size is 1048576 bytes (1MB).

    +

    Setting the maximum size to 0 disables log rotation. + +

    +

    MaxRequestSize

    +
    +

    Examples

    +
      +
      +MaxRequestSize 10485760
      +MaxRequestSize 10m
      +MaxRequestSize 0
      +
      +
    +

    Description

    +

    The MaxRequestSize 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.

    +

    Also see the identical +LimitRequestBody directive. + +

    +

    Order

    +
    +

    Examples

    +
      +
      +Order Allow,Deny
      +Order Deny,Allow
      +
      +
    +

    Description

    +

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

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

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

    +

    PageLog

    +
    +

    Examples

    +
      +
      +PageLog /var/log/cups/page_log
      +PageLog /var/log/cups/page_log-%s
      +PageLog syslog
      +
      +
    +

    Description

    +

    The PageLog directive sets the name of the page log + file. If the filename is not absolute then it is assumed to be relative + to the ServerRoot directory. The + default page log file is /var/log/cups/page_log.

    +

    The server name can be included in the filename by using %s + in the name.

    +

    The special name "syslog" can be used to send the page information to + the system log instead of a plain file. + +

    +

    Port

    +
    +

    Examples

    +
      +
      +Port 631
      +Port 80
      +
      +
    +

    Description

    +

    The Port directive specifies a port to listen on. + Multiple Port lines can be specified to listen on multiple + ports. The default port is 631. + +

    +

    PreserveJobHistory

    +
    +

    Examples

    +
      +
      +PreserveJobHistory On
      +PreserveJobHistory Off
      +
      +
    +

    Description

    +

    The PreserveJobHistory directive controls whether the + history of completed, cancelled, or aborted print jobs is stored on + disk.

    +

    A value of On (the default) preserves job information + until the administrator purges it with the cancel command.

    +

    A value of Off removes the job information as soon as + each job is completed, cancelled, or aborted. + +

    +

    PreserveJobFiles

    +
    +

    Examples

    +
      +
      +PreserveJobFiles On
      +PreserveJobFiles Off
      +
      +
    +

    Description

    +

    The PreserveJobFiles directive controls whether the + document files of completed, cancelled, or aborted print jobs are + stored on disk.

    +

    A value of On preserves job files until the + administrator purges them with the cancel command. Jobs + can be restarted (and reprinted) as desired until they are purged.

    +

    A value of Off (the default) removes the job files as + soon as each job is completed, cancelled, or aborted. + +

    +

    Printcap

    +
    +

    Examples

    +
      +
      +Printcap
      +Printcap /etc/printcap
      +Printcap /etc/printers.conf
      +
      +
    +

    Description

    +

    The Printcap 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 + /etc/printcap.

    +

    When a filename is specified (e.g. /etc/printcap), 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. + +

    +

    PrintcapFormat

    +
    +

    Examples

    +
      +
      +PrintcapFormat BSD
      +PrintcapFormat Solaris
      +
      +
    +

    Description

    +

    The PrintcapFormat directive controls the output format + of the printcap file. The default is to generate a BSD printcap file. + +

    +

    PrintcapGUI

    +
    +

    Example

    +
      +
      +PrintcapGUI /usr/bin/glpoptions
      +
      +
    +

    Description

    +

    The PrintcapGUI 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.

    +

    The program must accept the -d option to specify a + printer and the -o 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 -o to the + standard output. + +

    +

    RemoteRoot

    +
    +

    Examples

    +
      +
      +RemoteRoot remroot
      +RemoteRoot root
      +
      +
    +

    Description

    +

    The RemoteRoot directive sets the username for + unauthenticated root requests from remote hosts. The default username + is remroot. Setting RemoteRoot to root + effectively disables this security mechanism. + +

    +

    RequestRoot

    +
    +

    Examples

    +
      +
      +RequestRoot /var/spool/cups
      +RequestRoot /foo/bar/spool/cups
      +
      +
    +

    Description

    +

    The RequestRoot 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 + ServerRoot directory. The default request directory is + /var/spool/cups. + +

    +

    Require

    +
    +

    Examples

    +
      +
      +Require group foo bar
      +Require user john mary
      +Require valid-user
      +
      +
    +

    Description

    +

    The Require directive specifies that authentication is + required for the resource. The group keyword specifies + that the authenticated user must be a member of one or more of the + named groups that follow.

    +

    The user keyboard specifies that the authenticated user + must be one of the named users that follow.

    +

    The valid-user keyword specifies that any authenticated + user may access the resource.

    +

    The default is to do no authentication. This directive must appear + inside a Location directive. + +

    +

    RIPCache

    +
    +

    Examples

    +
      +
      +RIPCache 8m
      +RIPCache 1g
      +RIPCache 2048k
      +
      +
    +

    Description

    +

    The RIPCache directive sets the size of the memory cache + used by Raster Image Processor ("RIP") filters such as +imagetoraster and pstoraster. 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. + +

    +

    RootCertDuration

    +
    +

    Examples

    +
      +
      +RootCertDuration 300
      +RootCertDuration 0
      +
      +
    +

    Description

    +

    The RootCertDuration directive controls the interval + between updates of the root authentication certificate. The default is +300 seconds which updates the root certificate approximately once + every 5 minutes. Set the interval to 0 to disable certificate updates + entirely. + +

    +

    RunAsUser

    +
    +

    Examples

    +
      +
      +RunAsUser Yes
      +RunAsUser No
      +
      +
    +

    Description

    +

    The RunAsUser directive controls whether the scheduler + runs as the unpriviledged user account (usually lp). The + default is No which leaves the scheduler running as the +root user.

    +

    Note: Running as a non-priviledged user may prevent LPD and + locally connected printers from working due to permission problems. The + lpd backend will automatically use a non-priviledged mode + that is not 100% compliant with RFC 1179. The parallel, +serial, and usb backends will need write access to + the corresponding device files. + +

    +

    Satisfy

    +
    +

    Examples

    +
      +
      +Satisfy all
      +Satisfy any
      +
      +
    +

    Description

    +

    The Satisfy directive specifies whether all conditions + must be satisfied to allow access to the resource. If set to all +, then all authentication and access control conditions must be satified + to allow access.

    +

    Setting Satisfy to any 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.

    +

    The default is all. This directive must appear inside a Location directive. + +

    +

    ServerAdmin

    +
    +

    Examples

    +
      +
      +ServerAdmin user@host
      +ServerAdmin root@foo.bar.com
      +
      +
    +

    Description

    +

    The ServerAdmin directive identifies the email address + for the administrator on the system. By default the administrator email + address is root@server, where server is the + server name. + +

    +

    ServerBin

    +
    +

    Examples

    +
      +
      +ServerBin /usr/lib/cups
      +ServerBin /foo/bar/lib/cups
      +
      +
    +

    Description

    +

    The ServerBin directive sets the directory for + server-run executables. If an absolute path is not provided then it is + assumed to be relative to the ServerRoot + directory. The default executable directory is /usr/lib/cups +. + +

    +

    ServerCertificate

    +
    +

    Examples

    +
      +
      +ServerCertificate /etc/cups/ssl/server.crt
      +
      +
    +

    Description

    +

    The ServerCertificate 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 + /etc/cups/ssl/server.crt. + +

    +

    ServerKey

    +
    +

    Examples

    +
      +
      +ServerKey /etc/cups/ssl/server.key
      +
      +
    +

    Description

    +

    The ServerKey directive specifies the location of the + SSL private key file used by the server when negotiating encrypted + connections. The default key file is /etc/cups/ssl/server.crt +. + +

    +

    ServerName

    +
    +

    Examples

    +
      +
      +ServerName foo.domain.com
      +ServerName myserver.domain.com
      +
      +
    +

    Description

    +

    The ServerName directive specifies the hostname that is + reported to clients. By default the server name is the hostname. + +

    +

    ServerRoot

    +
    +

    Examples

    +
      +
      +ServerRoot /etc/cups
      +ServerRoot /foo/bar/cups
      +
      +
    +

    Description

    +

    The ServerRoot directive specifies the absolute path to + the server configuration and state files. It is also used to resolve + relative paths in the cupsd.conf file. The default server + directory is /etc/cups. + +

    +

    SSLListen

    +
    +

    Examples

    +
      +
      +SSLListen 127.0.0.1:443
      +SSLListen 192.0.2.1:443
      +
      +
    +

    Description

    +

    The SSLListen directive specifies a network address and + port to listen for secure connections. Multiple SSLListen + directives can be provided to listen on multiple addresses.

    +

    The SSLListen directive is similar to the + SSLPort directive but allows you to restrict access to + specific interfaces or networks. + +

    +

    SSLPort

    +
    +

    Examples

    +
      +
      +SSLPort 443
      +
      +
    +

    Description

    +

    The SSLPort directive specifies a port to listen on for + secure connections. Multiple SSLPort lines can be + specified to listen on multiple ports. + +

    +

    SystemGroup

    +
    +

    Examples

    +
      +
      +SystemGroup sys
      +SystemGroup system
      +SystemGroup root
      +
      +
    +

    Description

    +

    The SystemGroup directive specifies the system + administration group for System authentication. More + information can be found later in this chapter in + "Printing System Security". + +

    +

    TempDir

    +
    +

    Examples

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

    Description

    +

    The TempDir directive specifies an absolute path for the + directory to use for temporary files. The default directory is + /var/tmp.

    +

    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 /foo/bar/tmp:

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

    Timeout

    +
    +

    Examples

    +
      +
      +Timeout 300
      +Timeout 90
      +
      +
    +

    Description

    +

    The Timeout directive controls the amount of time to + wait before an active HTTP or IPP request times out. The default + timeout is 300 seconds. + +

    +

    User

    +
    +

    Examples

    +
      +
      +User lp
      +User guest
      +
      +
    +

    Description

    +

    The User directive specifies the UNIX user that filter + and CGI programs run as. The default user is lp. + +

    +

    Printing System Security

    +

    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.

    +

    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.

    +

    CUPS maintains a list of locations that have access control and/or + authentication enabled. Locations are specified using the + Location directive:

    + +

    Locations generally follow the directory structure of the + DocumentRoot directory, however CUPS does have several + virtual locations for administration, classes, jobs, and printers: +

    + + + + + + + + + + + + +
    LocationDescription
    /adminThe path for all administration operations.
    /classesThe path for all classes.
    /classes/nameThe resource for class name.
    /jobsThe path for all jobs.
    /jobs/idThe resource for job id.
    /printersThe path for all printers.
    /printers/nameThe path for printer name.
    /printers/name.ppdThe PPD file path for printer +name.
    +
    +

    +

    Authentication Using Certificates

    +

    CUPS supports a local certificate-based authentication scheme that + can be used in place of Basic or Digest + authentication by clients connecting through the localhost + interface. Certificate authentication is not supported or allowed from + clients on any other interface.

    +

    Certificates are 128-bit random numbers that refer to an internal + authentication record in the server. A client connecting via the +localhost interface sends a request with an authorization header + of:

    +
      +
      +Authorization: Local 0123456789ABCDEF0123456789ABCDEF
      +
      +
    +

    The server then looks up the local certificate and authenticates + using the username associated with it.

    +

    Certificates are generated by the server automatically and stored in + the /etc/cups/certs directory using the process ID of the + CGI program started by the server. Certificate files are only readable + by the User and +Group defined in the cupsd.conf file. When the CGI + program ends the certificate is removed and invalidated automatically.

    +

    The special file /etc/cups/certs/0 defines the root + certificate which can be used by any client running as the + super-user or another user that is part of the group defined by the + SystemGroup directive. The root certificate is + automatically regenerated every 5 minutes.

    +

    Using Basic Authentication

    +

    Basic authentication uses UNIX users and passwords to authenticate + access to resources such as printers and classes, and to limit access + to administrative functions.

    +
    + + +
    NOTE: +

    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.

    +
    +
    +

    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.

    +

    Once a valid username and password is authenticated by CUPS, any + additional group membership requirements are checked.

    +
    + + +
    NOTE: +

    The root user is considered by CUPS to be a member of every group.

    +
    +
    + + +

    Use the AuthType directive to enable Basic + authentication:

    +
      +
      +AuthType Basic
      +
      +
    + + +

    Using Digest Authentication

    +

    Digest authentication uses users and passwords defined in the + /etc/cups/passwd.md5 file to authenticate access to resources + such as printers and classes, and to limit access to administrative + functions.

    +
    + + +
    NOTE: +

    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.

    +

    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.

    +

    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. + Support for Digest authentication in web browsers is not yet + universally available.

    +
    +
    + + +

    The lppasswd(1) command is used to add, change, or + remove accounts from the passwd.md5 file. To add a user to + the default system group, type:

    +
      +
      +lppasswd -a user ENTER
      +Password: (password) ENTER [password is not echoed]
      +Password again: (password) ENTER [password is not echoed]
      +
      +
    + + +

    Once added, a user can change his/her password by typing:

    +
      +
      +lppasswd ENTER
      +Old password: (password) ENTER [password is not echoed]
      +Password: (password) ENTER [password is not echoed]
      +Password again: (password) ENTER [password is not echoed]
      +
      +
    + + +

    To remove a user from the password file, type:

    +
      +
      +lppasswd -x user ENTER
      +
      +
    +

    Once a valid username and password is authenticated by CUPS, any + additional group membership requirements are checked.

    +
    + + +
    NOTE: +

    The root user is considered by CUPS to be a member of every group.

    +
    +
    +

    Use the AuthType directive to enable Digest + authentication:

    +
      +
      +AuthType Digest
      +
      +
    +

    System and Group Authentication

    +

    The AuthClass directive + controls the level of authentication to perform. System + and Group authentication extend the normal user-based + authentication to require membership in a UNIX group. For System + authentication each user must belong to the sys, +system, or root group; the actual group depends on + the operating system.

    +

    For Group authentication each user must belong to the + group named by the AuthGroupName + directive:

    +
      +
      +<Location /path>
      +AuthType Digest
      +AuthClass Group
      +AuthGroupName mygroup
      +</Location>
      +
      +
    +

    The named group must be a valid UNIX user group, usually defined in + the /etc/group or /etc/netgroup files. + Additionally, when using Digest authentication you need to create user + accounts with the named group:

    +
      +
      +lppasswd -g mygroup -a user ENTER
      +Password: (password) ENTER [password is not echoed]
      +Password again: (password) ENTER [password is not echoed]
      +
      +
    + + +

    Printer Accounting

    +

    CUPS maintains a log of all accesses, errors, and pages that are + printed. The log files are normally stored in the /var/log/cups + directory. You can change this by editing the /etc/cups/cupsd.conf + configuration file.

    +

    The access_log File

    +

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

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

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

    +

    The group field always contains "-" in CUPS.

    +

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

    +

    The date-time field is the date and time of the request in + local time and is in the format:

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

    where ZZZZ is the timezone offset in hours and minutes from + Greenwich Mean Time (a.k.a. GMT a.k.a. ZULU.)

    +

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

    +

    The resource field is the filename of the requested resource.

    +

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

    +

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

    +

    The bytes field contains the number of bytes in the request. + For POST requests the bytes field contains the number of bytes + that was received from the client.

    +

    The error_log File

    +

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

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

    The level field contains the type of message:

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

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

    +

    The message fields contains a free-form textual message.

    +

    The page_log File

    +

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

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

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

    +

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

    +

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

    +

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

    +

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

    +

    The job-billing field contains a copy of the job-billing + attribute provided with the IPP create-job or +print-job requests or "-" if none was provided. + +

    +

    File Typing and Filtering

    +

    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 /etc/cups + directory (or a directory specified by the +ServerRoot 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.

    +

    The mime.types and mime.convs files define the + standard file types and filters that are available on the system.

    +

    mime.types

    +

    The mime.types 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 text/html + file type is defined as:

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

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

    +

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

    +

    The available tests are:

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

    All numeric values can be in decimal (123), octal (0123), or + hexadecimal (0x123) as desired. + +

    +

    Strings can be in quotes, all by themselves, as a string of + hexadecimal values, or some combination:

    +
      +
      +"string"
      +'string'
      +string
      +<737472696e67>
      +<7374>ring
      +
      +
    +

    As shown in the text/html example, rules can continue on + multiple lines using the backslash (\) character. A more complex + example is the image/jpeg rules:

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

    This rule states that any file with an extension of .jpeg, + .jpg, or .jpe is a JPEG file. In addition, any file + starting with the hexadecimal string <FFD8FF> (JPEG + Start-Of-Image) followed by a character between and including +0xe0 and 0xef (JPEG APPn markers) is also a JPEG + file.

    +

    mime.convs

    +

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

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

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

    +

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

    +

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

    +

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

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

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

    +

    Adding Filetypes and Filters

    +

    Adding a new file type or filter is fairly straight-forward. Rather + than adding the new type and filter to the mime.types and + mime.convs files which are overwritten when you upgrade to a new + version of CUPS, you simple need to create new files with .types + and .convs extensions in the /etc/cups directory. + We recommend that you use the product or format name, e.g.:

    +
      +
      +myproduct.types
      +myproduct.convs
      +
      +
    +

    If you are providing a filter for a common file format or printer, + add the company or author name:

    +
      +
      +acme-msword.types
      +acme.msword.convs
      +
      +
    +

    This will help to prevent name collisions if you install many + different file types and filters.

    +

    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 cupsd process as + described earlier in "Restarting the CUPS Server" +.

    +

    Printer Drivers and PPD Files

    +

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

    +
      +
      +*cupsFilter: "application/vnd.cups-raster 0 rastertohp"
      +
      +
    +

    The filter is specified using the source file type only; the + destination file type is assumed to be printer/name - + suitable for sending to the printer.

    +

    Writing Your Own Filter or Printer Driver

    +

    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.

    +

    7 - Printing with Other + Systems

    +

    This chapter describes how to print from client systems that use the + LPD, Mac OS, or Windows printing protocols.

    +

    The Basics

    +

    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.

    +

    Printing from LPD Clients

    +

    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.

    +

    The cups-lpd(8) program provides support for LPD clients + and can be used from either the inetd(8) or +xinetd(8) programs. Add the following line to the + /etc/inetd.conf file to enable LPD support on your server through + the inetd program:

    +
      +
      +printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
      +
      +
    +

    The path to the cups-lpd may vary depending on your + installation.

    +

    Once you have added this line, send the inetd process a +HUP signal or reboot the system:

    +
      +
      +killall -HUP inetd ENTER [IRIX and some versions of Linux]
      +kill -HUP pid ENTER [Others]
      +reboot ENTER [For all systems if the HUP signal fails]
      +
      +
    +

    If you are using the xinetd program, create a file named + /etc/xinetd.d/printer containing the following lines:

    +
      +
      +service printer
      +{
      +    socket_type = stream
      +    protocol = tcp
      +    wait = no
      +    user = lp
      +    server = /usr/lib/cups/daemon/cups-lpd
      +}
      +
      +
    +

    The xinetd program automatically reads the new + configuration file and enables LPD printing support. +

    + + +
    Warning: +

    cups-lpd currently does not perform any access control + based on the settings in cupsd.conf or in the + hosts.allow or hosts.deny files used by TCP wrappers. + Therefore, running cups-lpd on your server will allow any + computer on your network (and perhaps the entire Internet) to print to + your server.

    +

    While xinetd has built-in access control support, you + should use the TCP wrappers package with inetd to limit + access to only those computers that should be able to print through + your server.

    +
    +
    +

    +

    Printing to LPD Servers

    +

    CUPS provides the lpd backend for printing to LPD-based + servers and printers. Use a device URI of lpd://server/name + to print to a printer on an LPD server, where server is + the hostname or IP address of the server and name is the + queue name.

    +

    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.

    +

    Printing from Mac OS Clients

    +

    CUPS does not provide Mac OS support directly. However, there are + several free and commercial software packages that do.

    +

    Columbia Appletalk Package (CAP)

    +

    Because the CAP LaserWriter server (lwsrv(8)) does not + support specification of PPD files, we do not recommend that you use + CAP with CUPS. However, you can run the lpsrv program for + limited printing with the command:

    +
      +
      +lwsrv -n "Name" -p printer -a /usr/lib/adicts -f /usr/lib/LW+Fonts
      +
      +
    +

    where Name is the name you want to use when sharing the + printer, and printer is the name of the CUPS print queue. + +

    +

    XINET KA/Spool

    +

    To use your system as a print server for Mac OS clients, configure + each printer using a papserver(8) in the + /usr/adm/appletalk/services file, specifying the corresponding + PPD file in the /etc/cups/ppd directory for each printer. + For a printer named MyPrinter the entry would look like:

    +
      +
      +/usr/etc/appletalk/papserver -I -L -P /etc/cups/ppd/MyPrinter.ppd \
      +"Printer Description" MyPrinter
      +
      +
    +
    + + +
    NOTE: +

    Enter the text above on a single line without the backslash (\) + character.

    +
    +
    +

    NetATalk

    +

    To use your system as a print server for Mac OS clients, configure + each printer in the papd.conf file, specifying the + corresponding PPD file in the /etc/cups/ppd directory for + each printer. For a printer named MyPrinter the entry + would look like:

    +
      +
      +Printer Description:MyPrinter@MyServer:\
      +        :pr=|/usr/bin/lp -d MyPrinter:\
      +        :op=daemon:\
      +        :pd=/etc/cups/ppd/MyPrinter.ppd:
      +
      +
    + + +

    Printing to Mac OS Servers

    +

    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 /usr/lib/cups/backend directory that sends a print file + using the appropriate command. The following is a short script that + will run the papif command provided with CAP.

    +

    After copying this script to /usr/lib/cups/backend/cap, + specify a device URI of cap://server/printer to use this + backend with a print queue. + +

    +
      +
      +"/usr/lib/cups/backend/cap"
      +#!/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 > $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}' > /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 < $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
      +
      +
    + + +

    Printing from Windows Clients

    +

    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:

    + +

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

    +
      +
      +printing = cups
      +printcap name = cups
      +
      +
    +

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

    +

    Exporting Printer Drivers

    +

    You can optionally export printer drivers from your CUPS server using + the cupsaddsmb command and the SAMBA 2.2.0 or higher + software.

    +

    Before you can export the printers you must download the current + Adobe PostScript printer drivers from the Adobe web site ( +http://www.adobe.com/). Use the free unzip software to + extract the files from the self-extracting ZIP file containing the + drivers; you will need the following files:

    +
      +
      +ADFONTS.MFM
      +ADOBEPS4.DRV
      +ADOBEPS4.HLP
      +ADOBEPS5.DLL
      +ADOBEPSU.DLL
      +ADOBEPSU.HLP
      +DEFPRTR2.PPD
      +ICONLIB.DLL
      +PSMON.DLL
      +
      +
    +

    Copy these files to the /usr/share/cups/drivers directory + - you may need to rename some of the files so the filenames are all + UPPERCASE.

    +

    Next, add a print$ share for the printer drivers to your + smb.conf file:

    +
      +
      +[print$]
      +    comment = Printer Drivers
      +    path = /etc/samba/drivers
      +    browseable = yes
      +    guest ok = no
      +    read only = yes
      +    write list = root
      +
      +
    +

    The directory for your printer drivers can be anywhere on the system; + just make sure it is writable by the users specified by the write + list directive. Also, make sure that you have SAMBA passwords + defined for each user in the write list using the +smbpasswd(1) command. Otherwise you will not be able to + authenticate

    +

    Finally, run the cupsaddsmb command to export the + printer drivers for one or more queues:

    +
      +
      +cupsaddsmb -U root printer1 ... printerN ENTER
      +
      +
    +

    Running cupsaddsmb with the -a option will + export all printers:

    +
      +
      +cupsaddsmb -U root -a ENTER
      +
      +
    +

    Printing to Windows Servers

    +

    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 LPD section earlier in this + chapter.

    +

    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:

    + +

    To configure CUPS for SAMBA, run the following command:

    +
      +
      +ln -s `which smbspool` /usr/lib/cups/backend/smb ENTER
      +
      +
    +

    The smbspool(1) 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:

    +
      +
      +smb://workgroup/server/sharename
      +smb://server/sharename
      +smb://user:pass@workgroup/server/sharename
      +smb://user:pass@server/sharename
      +
      +
    +

    The workgroup name need only be specified if your system + is using a different workgroup. The user:pass strings are + required when printing to Windows NT servers or to shares with + passwords enabled under Windows 95 and 98.

    +

    A - Software License Agreement

    +

    Common UNIX Printing System License + Agreement

    +

    Copyright 1997-2003 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, with exceptions for + Apple operating systems and the OpenSSL toolkit. A copy of the + exceptions and 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 "cups" include + directory and library files in the binary distributions. The GNU GPL + applies to the remainder of the CUPS distribution, including the + "pdftops" filter which is based upon Xpdf and the CUPS imaging library.

    +

    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 only exceptions to this are the portions of + the CUPS software covered by the Apple operating system license + exceptions outlined later in this license agreement.

    +

    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.

    +

    License Exceptions

    +

    In addition, as the copyright holder of CUPS, Easy Software Products + grants the following special exceptions:

    +
      +
    1. Apple Operating System Development License Exception; +
        +
      1. Software that is developed by any person or entity for an Apple + Operating System ("Apple OS-Developed Software"), including but not + limited to Apple and third party printer drivers, filters, and backends + for an Apple Operating System, that is linked to the CUPS imaging + library or based on any sample filters or backends provided with CUPS + shall not be considered to be a derivative work or collective work + based on the CUPS program and is exempt from the mandatory source code + release clauses of the GNU GPL. You may therefore distribute linked + combinations of the CUPS imaging library with Apple OS-Developed + Software without releasing the source code of the Apple OS-Developed + Software. You may also use sample filters and backends provided with + CUPS to develop Apple OS-Developed Software without releasing the + source code of the Apple OS-Developed Software.
      2. +
      3. An Apple Operating System means any operating system software + developed and/or marketed by Apple Computer, Inc., including but not + limited to all existing releases and versions of Apple's Darwin, Mac OS + X, and Mac OS X Server products and all follow-on releases and future + versions thereof.
      4. +
      5. This exception is only available for Apple OS-Developed Software and + does not apply to software that is distributed for use on other + operating systems.
      6. +
      7. All CUPS software that falls under this license exception have the + following text at the top of each source file:
        This file is + subject to the Apple OS-Developed Software exception.
      8. +
      +
    2. +
    3. OpenSSL Toolkit License Exception; +
        +
      1. Easy Software Products explicitly allows the compilation and + distribution of the CUPS software with the OpenSSL Toolkit.
      2. +
      +
    4. +
    +

    No developer is required to provide these exceptions in a derived + work.

    +

    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. Please contract Easy + Software Products for written permission to use them in derivative + products. 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 "pdftops" filter that is + based on the Xpdf 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:

    + + + +

    GNU GENERAL PUBLIC LICENSE

    +

    Version 2, June 1991

    +
    +Copyright 1989, 1991 Free Software Foundation, Inc.
    +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    +
    +Everyone is permitted to copy and distribute verbatim
    +copies of this license document, but changing it is not allowed.
    +
    +

    Preamble

    +

    The licenses for most software are designed to take away your freedom + to share and change it. By contrast, the GNU General Public License is + intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Library General Public License instead.) You can apply it to + your programs, too.

    +

    When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it in + new free programs; and that you know you can do these things.

    +

    To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it.

    +

    For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights.

    +

    We protect your rights with two steps: (1) copyright the software, + and (2) offer you this license which gives you legal permission to + copy, distribute and/or modify the software.

    +

    Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations.

    +

    Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all.

    +

    The precise terms and conditions for copying, distribution and + modification follow.

    +

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

    +
      +
    1. This License applies to any program or other work which contains a + notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". +

      Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + the Program is not restricted, and the output from the Program is + covered only if its contents constitute a work based on the Program + (independent of having been made by running the Program). Whether that + is true depends on what the Program does.

      +
    2. You may copy and distribute verbatim copies of the Program's source + code as you receive it, in any medium, provided that you conspicuously + and appropriately publish on each copy an appropriate copyright notice + and disclaimer of warranty; keep intact all the notices that refer to + this License and to the absence of any warranty; and give any other + recipients of the Program a copy of this License along with the + Program. +

      You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee.

      +
    3. You may modify your copy or copies of the Program or any portion of + it, thus forming a work based on the Program, and copy and distribute + such modifications or work under the terms of Section 1 above, provided + that you also meet all of these conditions: +
        +
      1. You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change.
      2. +
      3. 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.
      4. +
      5. 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.)
      6. +
      +

      These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote + it.

      +

      Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program.

      +

      In addition, mere aggregation of another work not based on the + Program with the Program (or with a work based on the Program) on a + volume of a storage or distribution medium does not bring the other + work under the scope of this License.

      +
    4. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: +
        +
      1. Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 + above on a medium customarily used for software interchange; or,
      2. +
      3. 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,
      4. +
      5. 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.)
      6. +
      +

      The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to control + compilation and installation of the executable. However, as a special + exception, the source code distributed need not include anything that + is normally distributed (in either source or binary form) with the + major components (compiler, kernel, and so on) of the operating system + on which the executable runs, unless that component itself accompanies + the executable.

      +

      If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent access + to copy the source code from the same place counts as distribution of + the source code, even though third parties are not compelled to copy + the source along with the object code.

      +
    5. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt otherwise + to copy, modify, sublicense or distribute the Program is void, and will + automatically terminate your rights under this License. However, + parties who have received copies, or rights, from you under this + License will not have their licenses terminated so long as such parties + remain in full compliance.
    6. +
    7. 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.
    8. +
    9. 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.
    10. +
    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 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.

      +
    12. 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.
    13. +
    14. 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.

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

    NO WARRANTY

    +
      +
    1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH + YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION.
    2. +
    3. 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.
    4. +
    +

    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.

    +

    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:

    +
      +
    1. The modified work must itself be a software library. +

      +
    2. You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. +

      +
    3. You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. +

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

      +
    5. + + + +
    +

    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:

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

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

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

      +
    4. Verify that the user has already received a copy of these materials + or that you have already sent this user a copy.
    5. + + + +
    +

    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:

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

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

    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

    +

    B - Common Network Settings +

    +

    This appendix covers many of the popular TCP/IP network interfaces + and printer servers available on the market today.

    +

    Configuring a Network Interface

    +

    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.

    +

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

    +

    Configuring the IP Address Using ARP

    +

    The easiest way to set the IP address of a network device is to use + the arp(8) command. The arp sends an Address + Resolution Protocol ("ARP") packet to the specified Ethernet MAC + address, setting the network device's IP address:

    +
      +
      +arp -s ip-address ethernet-address ENTER
      +arp -s host.domain.com 08:00:69:00:12:34 ENTER
      +arp -s 192.0.2.2 08:00:69:00:12:34 ENTER
      +
      +
    +

    Configuring the IP Address Using RARP

    +

    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.

    +

    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 arp command is the way to go.

    +

    Some UNIX operating systems use a program called rarpd(8) + to manage RARP. Others, like Linux, support this protocol in the + kernel. For systems that provide the rarpd program you + will need to start it before RARP lookups will work:

    +
      +
      +rarpd ENTER
      +
      +
    +

    Under IRIX you can enable this functionality by default using:

    +
      +
      +chkconfig rarpd on ENTER
      +
      +
    +

    Both the rarpd program and kernel RARP support read a + list of Ethernet and IP addresses from the file /etc/ethers. + Each line contains the Ethernet address (colon delimited) followed by + an IP address or hostname like:

    +
      +
      +08:00:69:00:12:34 myprinter.mydomain.com
      +08:00:69:00:12:34 192.0.2.2
      +
      +
    +

    Add a line to this file and cycle the power on the printer or print + server to set its address. + +

    +

    Configuring the IP Address Using BOOTP

    +

    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 bootpd(8) program supplied + with UNIX you simply need to add a line to the /etc/bootptab + file; for IRIX:

    +
      +
      +myprinter 08:00:69:00:12:34 192.0.2.2 myprinter.boot
      +
      +
    + + +

    Newer versions of bootpd use a different format:

    +
      +
      +myprinter:ha=080069001234:ip=192.0.2.2:t144=myprinter.boot
      +
      +
    +

    The myprinter.boot file resides in the + /usr/local/boot directory by default. If you do not need to + provide a boot file you may leave the last part of the line blank.

    + + +
    + + +
    NOTE: +

    Some versions of UNIX do not enable the BOOTP service by default. The + /etc/inetd.conf usually contains a line for the BOOTP service + that can be uncommented if needed.

    +
    +
    +

    Verifying the Printer Connection

    +

    To test that the IP address has been successfully assigned and that + the printer is properly connected to your LAN, type:

    +
      +
      +ping ip-address ENTER
      +
      +
    +

    If the connection is working properly you will see something like:

    +
      +
      +ping myprinter ENTER
      +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
      +
      +
    +

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

    +

    Common Network Interface Settings

    +

    Once you have set the IP address you can access the printer or print + server using the ipp, lpd, or socket + backends. The following is a list of common network interfaces and + printer servers and the settings you should use with CUPS: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Model/ManufacturerDevice + URI(s)
    Apple LaserWriterlpd:// +address/PASSTHRU
    Axis w/o IPP +
    (see directions)
    socket://address +:9100 +
    socket://address:9101 +
    socket://address:9102
    Axis w/IPPipp://address +/LPT1 +
    ipp://address/LPT2 +
    ipp://address/COM1
    Castelle LANpressTM +lpd://address/pr1 +
    lpd://address/pr2 +
    lpd://address/pr3
    DPI NETPrintlpd://address +/pr1 +
    lpd://address/pr2 +
    lpd://address/pr3
    EFI® Fiery® RIPlpd:// +address/print
    EPSON® Multiprotocol Ethernet + Interface Boardsocket://address
    Extended System ExtendNET +lpd://address/pr1 +
    lpd://address/pr2 +
    lpd://address/pr3
    Hewlett Packard JetDirect w/o IPP +socket://address:9100 +
    socket://address:9101 +
    socket://address:9102
    Hewlett Packard JetDirect w/IPP +ipp://address/ipp +
    ipp://address/ipp/port1 +
    ipp://address/ipp/port2 +
    ipp://address/ipp/port3
    Intel® NetportExpress XL, PRO/100 +lpd://address/LPT1_PASSTHRU +
    lpd://address/LPT2_PASSTHRU +
    lpd://address/COM1_PASSTHRU
    LexmarkTM MarkNet +lpd://address/ps
    Linksys EtherFast® +
    (see directions)
    socket://address +:4010 +
    socket://address:4020 +
    socket://address:4030
    Kodak®lpd://address/ps
    QMS® CrownNetTM +lpd://address/ps
    Tektronix® PhaserShareTM +socket://address:9100
    XEROX® 4512 NIClpd:// +address/PORT1
    XEROX® XNIClpd://address +/PASSTHRU
    XEROX® (most others)socket:// +address:5503
    +
    +

    +

    Configuring Axis Print Servers

    +

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

    +

    Each print server contains a configuration file named config + 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 ftp(1) program:

    +
      +
      +ftp ip-address ENTER
      +Connected to ip-address.
      +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
      +ftp> user root ENTER
      +331 User name ok, need password
      +Password: pass ENTER (this is not echoed)
      +230 User logged in
      +ftp> get config ENTER
      +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> quit ENTER
      +221 Goodbye.
      +
      +
    + + +

    Next, edit the file with your favorite text editor and locate the + lines beginning with:

    +
      +
      +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
      +
      +
    + + + Change the RTN_OPT line to read: +
      +
      +RTN_OPT.     : NO
      +
      +
    + + +

    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:

    +
      +
      +RTEL_PR1.    : 9100
      +RTEL_PR2.    : 9101
      +RTEL_PR3.    : 9102
      +RTEL_PR4.    : 9103
      +RTEL_PR5.    : 9104
      +RTEL_PR6.    : 9105
      +RTEL_PR7.    : 9106
      +RTEL_PR8.    : 9107
      +
      +
    + + +

    This essentially makes the Axis print server look like a Hewlett + Packard JetDirect EX print server. Save the file and then upload the + new config file using the ftp command:

    +
      +
      +ftp ip-address ENTER
      +Connected to ip-address.
      +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
      +ftp> user root ENTER
      +331 User name ok, need password
      +Password: pass ENTER (this is not echoed)
      +230 User logged in
      +ftp> put config CONFIG ENTER
      +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> get hardreset ENTER
      +local: hardreset remote: hardreset
      +200 PORT command successful.
      +421 Axis NPS ### hard reset, closing connection.
      +ftp> quit ENTER
      +221 Goodbye.
      +
      +
    +

    Your Axis print server is now ready for use!

    +

    Configuring Linksys Print Servers

    +

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

    +

    Each print server contains a configuration file named CONFIG + 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 ftp(1) program:

    +
      +
      +ftp -n ip-address ENTER
      +Connected to ip-address.
      +220 Print Server Ready.
      +Remote system type is Print.
      +ftp> get CONFIG ENTER
      +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> quit ENTER
      +221 Goodbye.
      +
      +
    + + +

    Next, edit the file with your favorite text editor and locate the + lines beginning with:

    +
      +
      +0100 L1_PROUT:P1
      +0120 L2_PROUT:P1
      +0140 L3_PROUT:P1
      +
      +
    +

    Change the port number for each parallel and serial port on the + server as follows:

    +
      +
      +0100 L1_PROUT:P1
      +0120 L2_PROUT:P2
      +0140 L3_PROUT:P3
      +
      +
    + + +

    This maps each virtual printer with a physical port. Save the file + and then upload the new CONFIG file using the ftp + command:

    +
      +
      +ftp -n ip-address ENTER
      +Connected to ip-address.
      +220 Print Server Ready.
      +Remote system type is Print.
      +ftp> put CONFIG ENTER
      +local: CONFIG remote: CONFIG
      +200 Command OK.
      +150 Open ASCII Mode Connection.
      +226 Transfer complete.
      +##### bytes received in #.## seconds (##### Kbytes/s)
      +ftp> quit ENTER
      +221 Goodbye.
      +
      +
    +

    Your Linksys print server is now ready for use!

    +

    C - Printer Drivers

    +

    This appendix lists the printer drivers that are provided with CUPS.

    +

    Printer Drivers

    +

    CUPS includes the following printer drivers:

    + +

    EPSON 9-pin Dot Matrix

    +

    The EPSON 9-pin Dot Matrix driver (epson9.ppd) supports + 9-pin dot matrix printers that implement the ESC/P command set. It + provides 60x72, 120x72, and 240x72 DPI output in black only.

    +

    EPSON 24-pin Dot Matrix

    +

    The EPSON 24-pin Dot Matrix driver (epson9.ppd) 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.

    +

    EPSON Stylus Color

    +

    The EPSON Stylus Color driver (stcolor.ppd) 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).

    +

    EPSON Stylus Photo

    +

    The EPSON Stylus Photo driver (stphoto.ppd) 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).

    +

    HP DeskJet

    +

    The HP DeskJet driver (deskjet.ppd) supports HP DeskJet + printers that implement the PCL command set. It provides 150, 300, and + 600 DPI output in black and color (CMYK).

    +

    The DeskJet printers that implement the HP-PPA command set (720C, + 722C, 820C, and 1100C) are not supported due to a complete lack + of documentation and support from Hewlett Packard.

    +

    The duplexer provided with the HP DeskJet 900 series printers is also + not supported for similar reasons.

    +

    HP LaserJet

    +

    The HP LaserJet driver (laserjet.ppd) 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.

    +

    LaserJet printers that do not implement PCL (3100, 3150) are not + supported due to a complete lack of documentation and support from + Hewlett Packard.

    +

    D - List of Files

    +

    This appendix lists the files and directories that are installed for + the Common UNIX Printing System. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PathnameDescription
    /etc/cups/certs/The location of + authentication certificate files for local HTTP clients.
    /etc/cups/classes.confThe printer classes + configuration file for the scheduler.
    /etc/cups/cupsd.confThe scheduler + configuration file.
    /etc/cups/interfaces/The location of + System V interface scripts for printers.
    /etc/cups/mime.convsThe list of standard + file filters included with CUPS.
    /etc/cups/mime.typesThe list of recognized + file types for CUPS.
    /etc/cups/ppd/The location of PostScript + Printer Description ("PPD") files for printers.
    /etc/cups/printers.confThe printer + configuration file for the scheduler.
    /usr/bin/cancelThe System V cancel job(s) + command.
    /usr/bin/disableThe System V disable + printer command.
    /usr/bin/enableThe System V enable printer + command.
    /usr/bin/lpThe System V print command.
    /usr/bin/lpoptionsSets user-defined + printing options and defaults.
    /usr/bin/lppasswdAdds, changes, or removes + Digest password accounts.
    /usr/bin/lpqThe Berkeley status command.
    /usr/bin/lprThe Berkeley print command.
    /usr/bin/lprmThe Berkeley cancel job(s) + command.
    /usr/bin/lpstatThe System V status + command.
    /usr/include/cups/CUPS API header files.
    /usr/lib32/libcups.a +
    /usr/lib32/libcupsimage.a
    Static libraries (IRIX 6.5)
    /usr/lib/libcups.a +
    /usr/lib/libcupsimage.a
    Static libraries (all others)
    /usr/lib/libcups.sl.2 +
    /usr/lib/libcupsimage.sl.2
    Shared libraries (HP-UX)
    /usr/lib32/libcups.so.2 +
    /usr/lib32/libcupsimage.so.2
    Shared libraries (IRIX 6.5)
    /usr/lib/libcups.so.2 +
    /usr/lib/libcupsimage.so.2
    Shared libraries (all others)
    /usr/lib/cups/backend/Backends for various + types of printer connections.
    /usr/lib/cups/cgi-bin/CGI programs for the + scheduler.
    /usr/lib/cups/daemon/Daemons for polling + and LPD support.
    /usr/lib/cups/filter/Filters for various + types of files.
    /usr/lib/locale/The location of + language-specific message files. (System V)
    /usr/lib/nls/msg/The location of + language-specific message files. (Compaq Tru64 UNIX)
    /usr/share/locale/The location of + language-specific message files. (Linux, *BSD)
    /usr/sbin/acceptThe accept-jobs command.
    /usr/sbin/cupsdThe CUPS print scheduler.
    /usr/sbin/lpadminThe System V printer + administration tool.
    /usr/sbin/lpcThe Berkeley printer + administration tool.
    /usr/sbin/lpinfoThe get-devices and + get-ppds command.
    /usr/sbin/lpmoveThe move-jobs command.
    /usr/sbin/rejectThe reject-jobs command.
    /usr/share/catman/a_man/ +
    /usr/share/catman/u_man/
    Man pages (IRIX)
    /usr/share/man/Man pages (Compaq Tru64 + UNIX, HP-UX, Solaris)
    /usr/man/Man pages (all others)
    /usr/share/cups/data/The location of + filter data files.
    /usr/share/cups/data/testprint.psThe + PostScript test page file.
    /usr/share/cups/fonts/The location of + PostScript fonts for the PostScript RIP.
    /usr/share/cups/model/The location of + PostScript Printer Description ("PPD") files and interface scripts that + may be used to setup a printer queue.
    /usr/share/cups/pstoraster/Other + PostScript RIP initialization files.
    /usr/share/cups/pstoraster/FontmapThe font + mapping file (converts filenames to fontnames)
    /usr/share/cups/templates/The location of + HTML template files for the web interfaces.
    /usr/share/doc/cups/Documentation and web + page data for the scheduler.
    /var/log/cups/The location of scheduler + log files.
    /var/spool/cups/The location of print + files waiting to be printed.
    +
    +

    +

    E - Troubleshooting Common Problems

    +

    This appendix covers some of the common problems first-time users + encounter when installing and configuring CUPS.

    +

    Commercial support for CUPS is available from Easy Software Products. + For more information please contact us at:

    + +

    My Applications Don't See the Available Printers

    +

    Many applications read the /etc/printcap file to get a + list of available printers.

    +

    The default CUPS configuration creates the /etc/printcap + file automatically. To enable or disable automatic creation and + updating of this file, use the Printcap + directive described in Chapter 6, + "Printing System Management".

    +

    CUPS Doesn't Recognize My Username or Password!

    +

    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 root username and + the corresponding password to authenticate the request.

    +

    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 root account then you won't be + able to add printers remotely or via the web interface! + +

    +

    To disable password authentication you need to edit the + /etc/cups/cupsd.conf file and comment out the lines reading:

    +
      +
      +AuthType Basic
      +AuthClass System
      +
      +
    +

    for the /admin location. Then restart the CUPS server as + described in Chapter 6, "Printing System + Management".

    +
    + + +
    NOTE: +

    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.

    +
    +
    +

    I Can't Do Administration Tasks from Another + Machine!

    +

    The default CUPS configuration limits administration to the local + machine. To open up access, edit the /etc/cups/cupsd.conf + and comment out the lines reading:

    +
      +
      +Order deny,allow
      +Deny from all
      +Allow from 127.0.0.1
      +
      +
    +

    for the /admin location. Then restart the CUPS server as + described in Chapter 6, "Printing System + Management".

    +
    + + +
    NOTE: +

    Allowing administration access from all hosts is a potential security + risk. Please read Chapter 6, "Printing + System Management" for a description of these risks and ways to + minimize them.

    +
    +
    + + +

    I Can't Do Administration Tasks from My Web Browser! +

    +

    This problem is usually caused by:

    +
      +
    1. not specifying the correct password for the root account.
    2. +
    3. 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 + "I Can't Do Administration Tasks from Another Machine!" section + earlier in this appendix.
    4. +
    5. not setting a password on the root account. CUPS will not + authenticate a user account that does not have a password for security + reasons.
    6. +
    7. authenticating using an account other than root, but the account you + are using is not a member of the system group.
    8. +
    9. configuring CUPS to use Digest authentication, but your web browser + does not support Digest authentication.
    10. +
    +

    Connection Refused Messages

    +

    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.

    +

    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.

    +

    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.

    +

    Write Error Messages

    +

    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.

    +

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

    +

    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:

    +
      +
      +telnet ip-address ENTER
      +
      +Trying ip-address...
      +Connected to ip-address.
      +Escape character is `^]'.
      +
      +Please type [Return] two times, to initialize telnet configuration
      +For HELP type "?"
      +> idle-timeout: 180 ENTER
      +> quit ENTER
      +
      +
    + + diff --git a/doc/sam.pdf b/doc/sam.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ae1b1481714f54f4296c774e9c7e7aff343088dc GIT binary patch literal 273391 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 + + + + + CUPS Software Administrators Manual + + + +

    Preface

    + +

    This software administrators manual provides printer administration +information for the Common UNIX Printing SystemTM +("CUPSTM"), version 1.2.0. + + + + +

    Document Overview

    + +

    This software administrators manual is organized into the following sections:

    + +
    + +

    Notation Conventions

    + +

    Various font and syntax conventions are used in this guide. Examples and +their meanings and uses are explained below: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Example   Description
     
    lpstat
    + lpstat(1)
       The names of commands; the first mention of a command or + function in a chapter is followed by a manual page section + number.
     
    /var
    + /usr/share/cups/data/testprint.ps
       File and directory names.
     
    Request ID is Printer-123   Screen output.
     
    lp -d printer filename ENTER   Literal user input; special keys like ENTER are + in ALL CAPS.
     
    12.3   Numbers in the text are written using the period (.) to indicate + the decimal point.
    + + +

    Abbreviations

    + +The following abbreviations are used throughout this manual: + +
      +
      + +
      kb +
      Kilobytes, or 1024 bytes
        + +
      Mb +
      Megabytes, or 1048576 bytes
        + +
      Gb +
      Gigabytes, or 1073741824 bytes
        + +
      +
    + +

    Other References

    + +
      +
      + +
      CUPS Software Programmers Manual + +
      A programmer guide for interfacing with and/or extending the CUPS + software.
        + +
      CUPS Software Users Manual + +
      An end-user guide for using the CUPS software.
        + +
      +
    + + + + + +

    2 - Building and Installing CUPS

    + +

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

    Installing a Source Distribution

    + +

    This section describes how to compile and install CUPS on your system +from the source code. + +

    Requirements

    + +

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

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

    + +

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

    + +

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

    + +

    Finally, you'll need a make program that +understands the include directive - FreeBSD, +NetBSD, and OpenBSD developers should use the gmake +program. + +

    Compiling CUPS

    + +

    CUPS uses GNU autoconf to configure the makefiles and source code +for your system. Type the following command to configure CUPS for your +system: + +

      +./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, and LDFLAGS environment variables +prior to running configure: + +

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

    or: + +

      +CFLAGS="-I/some/directory"; export CFLAGS ENTER
      +CXXFLAGS="-I/some/directory"; export CXXFLAGS ENTER
      +LDFLAGS="-L/some/directory"; export LDFLAGS ENTER
      +DSOFLAGS="-L/some/directory"; export DSOFLAGS 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: + +

    + +

    If the OpenSSL headers and libraries are not installed in the +standard directories, use the --with-openssl-includes +and --with-openssl-libs options:

    + +
      +./configure --enable-ssl \
      +    --with-openssl-includes=/foo/bar/include \
      +    --with-openssl-libs=/foo/bar/lib
      +
    + +

    Once you have configured things, just type: + +

      +make ENTER
      +
    + +

    to build the software. + + +

    Installing the Software

    + +

    Use the "install" target to install the software: + +

      +make install ENTER
      +
    + +
    + + + +
    + WARNING: + +

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

    + +

    Running the Software

    + +

    Once you have installed the software you can start the CUPS server by +typing: + +

      +/usr/sbin/cupsd ENTER
      +
    + + +

    Installing a Binary Distribution

    + +

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

    + + + +
    + WARNING: + +

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

    + + +

    Installing a Portable Distribution

    + +

    To install the CUPS software from a portable distribution 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 an RPM Distribution

    + +

    To install the CUPS software from an RPM distribution you will need +to be logged in as root; doing an su is good enough. Once +you are the root user, run RPM with: + +

      +rpm -e lpr
      +rpm -i cups-1.1-linux-M.m.n-intel.rpm ENTER
      +
    + +

    After a short delay the CUPS software will be +installed and the scheduler will be started automatically. + +

    Installing an Debian Distribution

    + +

    To install the CUPS software from a Debian distribution you will +need to be logged in as root; doing an su is good enough. +Once you are the root user, run dpkg with: + +

      +dpkg -i cups-1.1-linux-M.m.n-intel.deb ENTER
      +
    + +

    After a short delay the CUPS software will be installed and the +scheduler will be started automatically. + + +

    3 - Managing Printers

    + +

    This chapter describes how to add your first printer and how to +manage your printers. + +

    The Basics

    + +

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

    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 +parallel:/dev/lp1. + + +

    You can see a complete list of supported devices by running the +lpinfo(8) command: + +

      +lpinfo -v ENTER
      +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
      +
    + +

    The -v 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 +file:/directory/filename while network devices use the more +familiar method://server or method://server/path +format. + +

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

    Adding Your First Printer

    + +

    CUPS provides two methods for adding printers: a command-line +program called lpadmin(8) and a Web interface. The +lpadmin command allows you to perform most printer +administration tasks from the command-line and is located in +/usr/sbin. The Web interface is located at: + +

    + +

    and steps you through printer configuration. If you don't like +command-line interfaces, try the Web interface instead. + +

    Adding Your First Printer from the Command-Line

    + +

    Run the lpadmin command with the -p option to add a +printer to CUPS: + +

      +/usr/sbin/lpadmin -p printer -E -v device -m ppd ENTER
      +
    + +

    For a HP DeskJet printer connected to the parallel port this would look +like: + +

      +/usr/sbin/lpadmin -p DeskJet -E -v parallel:/dev/lp1 -m deskjet.ppd ENTER
      +
    + +

    Similarly, a HP LaserJet printer using a JetDirect network interface at +IP address 11.22.33.44 would be added with the command: + +

      +/usr/sbin/lpadmin -p LaserJet -E -v socket://11.22.33.44 -m laserjet.ppd ENTER
      +
    + +

    As you can see, deskjet.ppd and laserjet.ppd 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 Appendix C, "Printer Drivers". + + +

    For a dot matrix printer connected to the serial port this would might look like: + +

      +/usr/sbin/lpadmin -p DotMatrix -E -v serial:/dev/ttyS0?baud=9600+size=8+parity=none+flow=soft deskjet.ppd ENTER
      +
    + +

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

    Adding Your First Printer from the Web

    + +

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

    + +

    Click on the Add Printer button to add a printer. + +

    Managing Printers from the Command-Line

    + +

    The lpadmin command enables you to perform most printer +administration tasks from the command-line. You'll find lpadmin +in the /usr/sbin directory. + +

    Adding and Modifying Printers

    + +

    Run the lpadmin command with the -p option +to add or modify a printer: + +

      +/usr/sbin/lpadmin -p printer options ENTER
      +
    + +

    The options arguments can be any of the following: + +

      +
      + +
      -c class + +
      Adds the named printer to printer class class. + If the class does not exist then it is created. + +
      -i interface + +
      Copies the named interface 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. + +
      -m model + +
      Specifies a standard printer driver which is usually a PPD + file. A list of all available models can be displayed using the + lpinfo command with the -m option. A + list of printer drivers included with CUPS can be found in + Appendix C, "Printer Drivers". + +
      -r class + +
      Removes the named printer from printer class class. + If the resulting class becomes empty then it is removed. + +
      -v device-uri + +
      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. + +
      -D info + +
      Provides a textual description of the printer, e.g. + "John's Personal Printer". + +
      -E + +
      Enables the printer and accepts job. This option is + equivalent to running the enable(1) and + accept(8) commands on the printer. + +
      -L location + +
      Provides a textual location for the printer, e.g. + "Computer Lab 5". + +
      -P ppd-file + +
      Specifies a local PPD file for the printer driver. + +
      +
    + +

    Deleting Printers

    + +

    Run the lpadmin command with the -x option +to delete a printer: + +

      +/usr/sbin/lpadmin -x printer ENTER
      +
    + +

    Setting the Default Printer

    + +

    Run the lpadmin command with the -d option +to set a default printer: + +

      +/usr/sbin/lpadmin -d printer ENTER
      +
    + +

    The default printer can be overridden by the user using the +lpoptions(1) command. + +

    Starting and Stopping Printers

    + +

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

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

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

    Accepting and Rejecting Print Jobs

    + +

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

      +/usr/sbin/accept printer ENTER
      +/usr/sbin/reject printer ENTER
      +
    + +

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

    Setting Quotas on a Printer

    + +

    CUPS supports page and size-based quotas for each printer. +The quotas are tracked individually for each user, but a single set of +limits applies to all users for a partiuclar printer. For example, you +can limit every user to 5 pages per day on an expensive printer, but +you cannot limit every user except Johnny.

    + +

    The job-k-limit, job-page-limit, and job-quota-peiod +options determine whether and how quotas are enforced for a printer. +The job-quota-period option determines the time interval for +quota tracking. The interval is expressed in seconds, so a day is +86,400, a week is 604,800 and a month is 2,592,000 seconds. The +job-k-limit option specifies the job size limit in killobytes. The +job-page-limit option specifies the number of pages limit.

    + +

    For quotas to be enforced, the period and at least one of the limits +must be set to a non-zero value. The following options will enable +quotas:

    + +
      +
      +/usr/sbin/lpadmin -p printer -o job-quota-period=604800 -o job-k-limit=1024 ENTER
      +/usr/sbin/lpadmin -p printer -o job-quota-period=604800 -o job-page-limit=100 ENTER
      +
      +
    + +

    Or, you can combine all three options on the same line.

    + +

    Restricting User Access to a Printer

    + +

    The -u option of the lpadmin command controls which users can +print to a printer. The default configuration allows all users to print +to a printer:

    + +
      +
      +/usr/sbin/lpadmin -p printer -u allow:all ENTER
      +
      +
    + +

    CUPS supports allow and deny lists so that you can specify a +list of users who are allowed to print or not allowed to print. Along +with your list of users, you can specify whether they are allowed or +not allowed to use the printer:

    + +
      +
      +/usr/sbin/lpadmin -p printer -u allow:peter,paul,mary ENTER
      +
      +
    + +

    This command allows peter, paul, and mary to print to the named +printer, but all other users cannot print. The command:

    + +
      +
      +/usr/sbin/lpadmin -p printer -u deny:peter,paul,mary ENTER
      +
      +
    + +

    has the opposite effect. All users except peter, paul, and mary will +be able to print to the named printer.

    + +

    You can control access by UNIX groups as well by placing an +"@" character before each group name. The command:

    + +
      +
      +/usr/sbin/lpadmin -p printer -u allow:peter,paul,mary,@printgods ENTER
      +
      +
    + +

    allows the users peter, paul, and mary to print, as well as +any user in the printgods group to print. + +

    + + + + +
    NOTE: + +

    The allow and deny options are not cummulative. That + is, you must provide the complete list of users to allow or deny each + time.

    + +

    Also, CUPS only maintains one list of users - the list can + allow or deny users from printing. If you specify an allow list and + then specify a deny list, the deny list will replace the allow list - + only one list is active at any time.

    + +
    +
    + +

    Managing Printers from the Web

    + +

    The Web interface is located at: + +

    + +

    From there you can perform all printer management tasks with a few +simple mouse clicks. + + +

    4 - Printer Classes

    + +

    This chapter describes what printer classes are and how to manage them. + +

    The Basics

    + +

    CUPS provides collections of printers called printer classes. 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. + +

    CUPS also supports implicit classes. 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. + +

    Managing Printer Classes from the Command-Line

    + +

    Run the lpadmin command with the -p and -c options +to add a printer to a class: + +

      +/usr/sbin/lpadmin -p printer -c class ENTER
      +
    + +

    The class is created automatically if it doesn't exist. To remove a +printer from a class use the -r option: + +

      +/usr/sbin/lpadmin -p printer -r class ENTER
      +
    + +

    To remove the entire class just use the -x option: + +

      +/usr/sbin/lpadmin -x class ENTER
      +
    + +

    Managing Printer Classes from the Web Interface

    + +

    The Web interface is located at: + +

    + +

    The Add Class and Modify Class interfaces provide a +list of available printers; click on the printers of interest to add them to +the class. + +

    Implicit Classes

    + +

    A noted earlier, implicit classes are created automatically from the +available network printers and classes. To disable this functionality, +set the ImplicitClasses +directive to Off in the cupsd.conf file. You +will find more information on doing this in +Chapter 6, "Printing System +Management". + + +

    5 - Client Setup

    + +

    This chapter discusses several ways to configure CUPS clients for +printing. + +

    The Basics

    + +

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

    CUPS supports several methods of configuring client machines: + +

    + +

    Manual Configuration of Print Queues

    + +

    The most tedious method of configuring client machines is to configure +each remote queue by hand using the lpadmin command: + +

      +lpadmin -p printer -E -v ipp://server/printers/printer ENTER
      +
    + +

    The printer name is the name of the printer on the server +machine. The server name is the hostname or IP address of the +server machine. Repeat the lpadmin command for each remote +printer you wish to use.

    + +
    + + + + +
    NOTE: +

    Manual configuration of print queues is not recommended for large + numbers of client machines because of the administration nightmare it + creates. For busy networks, consider subnetting groups of clients and + polling and relaying printer information instead.

    +
    +
    + +

    Specifying a Single Server for Printing

    + +

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

    The default server is normally "localhost". To override the default +server create a file named /etc/cups/client.conf and add +a line reading: + +

      +ServerName server
      +
    + +

    to the file. The server name can be the hostname or IP address +of the default server. + +

    The default server can also be customized on a per-user basis. To set a +user-specific server create a file named ~/.cupsrc and add a line +reading: + +

      +ServerName server
      +
    + +

    to the file. The server name can be the hostname or IP +address of the default server. + +

    Automatic Configuration of Print Queues

    + +

    CUPS supports automatic client configuration of printers on the same +subnet. To configure printers on the same subnet, do nothing. +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. + +

    If you want to see printers on other subnets as well, use the +BrowsePoll +directive as described next.

    + +
    + + + + +
    NOTE: +

    The BrowseAddress directive + enables broadcast traffic from your server. The default configuration + braodcasts printer information every 30 seconds. Although this printer + information does not use much bandwidth, typically about 80 bytes per + printer, it can add up with large numbers of servers and printers.

    +

    Use the BrowseInterval + and BrowseTimeout directives to tune + the amount of data that is added to your network load. In addition, + subnets can be used to minimize the amount of traffic that is carried + by the "backbone" of your large network.

    +
    +
    + +

    Specifying Multiple Servers for Printing

    + +

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

    Polling is enabled by specifying one or more +BrowsePoll +directives in the /etc/cups/cupsd.conf file. +For information on making these changes, see +Chapter 6, "Printing System Management". + +

    Multiple BrowsePoll lines can +be used to poll multiple CUPS servers. To limit the amount of +polling you do from client machines, you can have only one of the +clients do the polling and relay that information to the others on the +same subnet (described next).

    + +

    Relaying Printers to Other Clients

    + +

    When you have clients and servers spread across multiple subnets, the +polling method is inefficient. CUPS provides a +BrowseRelay directive that enables a +single client to relay (broadcast) the polled printer information to the local subnet.

    + +

    For example, Server A and Server B are on subnet 1 and subnet 2, +while the clients are on subnet 3. +To provide printers to all of the clients in subnet 3, +client C will be configured with the following directives in /etc/cups/cupsd.conf:

    + +
      +# Poll the two servers
      +
      +BrowsePoll ServerA ENTER
      +BrowsePoll ServerB ENTER
      +
      +
      +# Relay the printers to the local subnet
      +
      +BrowseRelay 127.0.0.1 192.168.3.255 ENTER
      +
    + +

    The BrowseRelay line specifies a source address and mask. +Any browse packets coming from a matching address wil be sent to the given broadcast address. +In this case, we want the packets from the local machine (127.0.0.1) relayed to the other clients.

    + +

    As printers are found using polling, +they are relayed from client C to the rest of the clients through a broadcast on subnet 3. +The rest of the clients can use the standard cupsd.conf configuration.

    + +

    The BrowseRelay directive can also be used to relay +browsing packets from one network interface to another. +For example, if client C in the previous example had network interfaces attaches to both +subnet 1 and subnet 2, it could use the BrowseRelay directive exclusively: + +

      +# Relay the printers from subnet 1 and 2 to subnet 3
      +
      +BrowseRelay 192.168.1 192.168.3.255 ENTER
      +BrowseRelay 192.168.2 192.168.3.255 ENTER
      +
    + +

    Load Balancing and Failsafe Operation

    + +

    When using server polling or broadcasting, CUPS clients can +automatically merge identical printers on multiple servers into a +single implicit class queue. Clients assume that printers with +the same name on multiple servers are in fact the same printer or type +of printer being served by multiple machines.

    + +

    If you have two printers, LaserJet@ServerA and LaserJet@ServerB, a +third implicit class called LaserJet will be created +automatically on the client that refers to both printers. If the client +also has a local printer with the name LaserJet then an implicit class +named AnyLaserJet will be created instead.

    + +

    The client will alternate between servers and automatically stop +sending jobs to a server if it goes down, providing a load-balancing +effect and fail-safe operation with automatic switchover.

    + +
    + + + +
    NOTE: +

    Note that implicit classes (ImplicitClasses) + are enabled by default.

    +
    + +

    6 - Printing System Management

    + +

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

    The Basics

    + +

    Several text files are used to configure CUPS. All of the server +configuration files are located in the /etc/cups directory: + +

      +
      + + +
      classes.conf + +
      This file contains information on each printer class. + Normally you manipulate this file using the + lpadmin command or the Web interface.
        + + +
      client.conf + +
      This file provides the default server name for client + machines. See Chapter 5, "Client + Setup" for more information.
        + + +
      cupsd.conf + +
      This file controls how the CUPS server + (/usr/sbin/cupsd) operates and is normally edited by + hand.
        + + +
      mime.convs + +
      This file contains a list of standard file conversion filters + and their costs. You normally do not edit this file.
        + + +
      mime.types + +
      This file contains a list of standard file formats and how to + recognize them. You normally do not edit this file.
        + + +
      printers.conf + +
      This file contains information on each printer. Normally + you manipulate this file using the lpadmin command + or the Web Interface.
        + +
      +
    + +

    Restarting the CUPS Server

    + +

    Once you have made a change to a configuration file you need to +restart the CUPS server by sending it a HUP signal or using the +supplied initialization script. The CUPS distributions install the +script in the init.d directory with the name +cups. The location varies based upon the operating system: + +

      +/etc/software/init.d/cups restart ENTER
      +/etc/rc.d/init.d/cups restart ENTER
      +/etc/init.d/cups restart ENTER
      +/sbin/init.d/cups restart ENTER
      +
    + +

    Changing the Server Configuration

    + +

    The /etc/cups/cupsd.conf file contains configuration +directives 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. + + +

    Server Directives

    + +

    The cupsd.conf file contains many directives that +determine how the server operates: + +

    + + +

    AccessLog

    +
    + +

    Examples

    + +
      +AccessLog /var/log/cups/access_log
      +AccessLog /var/log/cups/access_log-%s
      +AccessLog syslog
      +
    + +

    Description

    + +

    The AccessLog directive sets the name of the access log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot 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. + +

    The server name can be included in the filename by using +%s in the name. + +

    The special name "syslog" can be used to send the access information +to the system log instead of a plain file. + +

    The default access log file is /var/log/cups/access_log. + + +

    Allow

    +
    + +

    Examples

    + +
      +Allow from All
      +Allow from None
      +Allow from *.domain.com
      +Allow from .domain.com
      +Allow from host.domain.com
      +Allow from nnn.*
      +Allow from nnn.nnn.*
      +Allow from nnn.nnn.nnn.*
      +Allow from nnn.nnn.nnn.nnn
      +Allow from nnn.nnn.nnn.nnn/mm
      +Allow from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
      +Allow from @LOCAL
      +Allow from @IF(name)
      +
    + +

    Description

    + +

    The Allow directive specifies a hostname, IP address, +or network that is allowed access to the server. Allow +directives are cummulative, so multiple Allow directives +can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    mmnetmaskmmnetmask
    00.0.0.08255.0.0.0
    1128.0.0.016255.255.0.0
    2192.0.0.024255.255.255.0
    ......32255.255.255.255
    + +

    The @LOCAL name will allow access from all local +network interfaces, but not remote point-to-point interfaces. The +@IF(name) name will allow access from the named +interface. + +

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

    AuthClass

    +
    + +

    Examples

    + +
      +AuthClass Anonymous
      +AuthClass User
      +AuthClass System
      +AuthClass Group
      +
    + +

    Description

    + +

    The AuthClass directive defines what level of authentication +is required: + +

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

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

    AuthGroupName

    +
    + +

    Examples

    + +
      +AuthGroupName mygroup
      +AuthGroupName lp
      +
    + +

    Description

    + +

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

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

    AuthType

    +
    + +

    Examples

    + +
      +AuthType None
      +AuthType Basic
      +AuthType Digest
      +AuthType BasicDigest
      +
    + +

    Description

    + +

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

      + +
    • None - No authentication should be performed + (default.) + +
    • Basic - Basic authentication should be + performed using the UNIX password and group files. + +
    • Digest - Digest authentication should be + performed using the /etc/cups/passwd.md5 file. + +
    • BasicDigest - Basic authentication should be + performed using the /etc/cups/passwd.md5 file. + +
    + +

    When using Basic, Digest, or +BasicDigest authentication, clients connecting +through the localhost interface can also +authenticate using certificates. + +

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

    AutoPurgeJobs

    +
    + +

    Examples

    + +
      +AutoPurgeJobs Yes
      +AutoPurgeJobs No
      +
    + +

    Description

    + +

    The AutoPurgeJobs 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 No. + + +

    BrowseAddress

    +
    + +

    Examples

    + +
      +BrowseAddress 255.255.255.255:631
      +BrowseAddress 192.0.2.255:631
      +BrowseAddress host.domain.com:631
      +BrowseAddress @LOCAL
      +BrowseAddress @IF(name)
      +
    + +

    Description

    + +

    The BrowseAddress directive specifies an address to +send browsing information to. Multiple BrowseAddress +directives can be specified to send browsing information to different +networks or systems. + +

    The @LOCAL name will broadcast printer +information to all local interfaces. The @IF(name) +name will broadcast to the named interface. + +

    No browse addresses are set by default.

    + +
    + + + +
    + NOTE: + +

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

    + + +

    BrowseAllow

    +
    + +

    Examples

    + +
      +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
      +BrowseAllow from @LOCAL
      +BrowseAllow from @IF(name)
      +
    + +

    Description

    + +

    The BrowseAllow directive specifies a system or network +to accept browse packets from. The default is to accept browse packets +from all hosts. + +

    Host and domain name matching require that you enable the +HostNameLookups directive. + +

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

    The @LOCAL name will allow browse data from all +local network interfaces, but not remote point-to-point +interfaces. The @IF(name) name will allow browse +data from the named interface. + + + +

    BrowseDeny

    +
    + +

    Examples

    + +
      +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
      +BrowseDeny from @LOCAL
      +BrowseDeny from @IF(name)
      +
    + +

    Description

    + +

    The BrowseDeny directive specifies a system or network +to reject browse packets from. The default is to deny browse packets +from no hosts. + +

    Host and domain name matching require that you enable the +HostNameLookups directive. + +

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

    The @LOCAL name will block browse data from all +local network interfaces, but not remote point-to-point +interfaces. The @IF(name) name will block browse +data from the named interface. + + + +

    BrowseOrder

    +
    + +

    Examples

    + +
      +BrowseOrder allow,deny
      +BrowseOrder deny,allow
      +
    + +

    Description

    + +

    The BrowseOrder directive specifies the order of allow/deny +processing. The default order is deny,allow: + +

      + +
    • allow,deny - Browse packets are accepted unless + specifically denied. + +
    • deny,allow - Browse packets are rejected unless + specifically allowed. + +
    + + +

    BrowseInterval

    +
    + +

    Examples

    + +
      +BrowseInterval 0
      +BrowseInterval 30
      +
    + +

    Description

    + +

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

    The BrowseInterval value should always be less than the +BrowseTimeout value. Otherwise +printers and classes will disappear from client systems between updates. + + +

    BrowsePoll

    +
    + +

    Examples

    + +
      +BrowsePoll 192.0.2.2:631
      +BrowsePoll host.domain.com:631
      +
    + +

    Description

    + +

    The BrowsePoll directive polls a server for available +printers once every +BrowseInterval seconds. +Multiple BrowsePoll directives can be specified to poll +multiple servers. + +

    If BrowseInterval is set to 0 then the server is polled +once every 30 seconds. + + +

    BrowsePort

    +
    + +

    Examples

    + +
      +BrowsePort 631
      +BrowsePort 9999
      +
    + +

    Description

    + +

    The BrowsePort directive specifies the UDP port number +used for browse packets. The default port number is 631.

    + +
    + + + +
    + NOTE: + +

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

    + + +

    BrowseProtocols

    +
    + +

    Examples

    + +
      +BrowseProtocols CUPS
      +BrowseProtocols SLP
      +BrowseProtocols CUPS SLP
      +BrowseProtocols all
      +
    + +

    Description

    + +

    The BrowseProtocols directive specifies the protocols to +use when collecting and distributing shared printers on the local network. +The default protocol is CUPS, which is a broadcast-based +protocol.

    + +
    + + + +
    + NOTE: + +

    When using the SLP protocol, you must have at least + one Directory Agent (DA) server on your network. Otherwise the + CUPS scheduler (cupsd) will not respond to client + requests for several seconds while polling the network. +

    + + +

    BrowseRelay

    +
    + +

    Examples

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

    Description

    + +

    The BrowseRelay directive specifies source and destination +addresses for relaying browsing information from one host or network to +another. Multiple BrowseRelay directives can be specified +as needed. + +

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

      +BrowseRelay 127.0.0.1 255.255.255.255
      +
    + +

    This effectively provides access to printers on a WAN for all clients +on the LAN(s). + + +

    BrowseShortNames

    +
    + +

    Examples

    + +
      +BrowseShortNames Yes
      +BrowseShortNames No
      +
    + +

    Description

    + +

    The BrowseShortNames 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".) + +

    The default value for this option is Yes. + + +

    BrowseTimeout

    +
    + +

    Examples

    + +
      +BrowseTimeout 300
      +BrowseTimeout 60
      +
    + +

    Description

    + +

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

    The BrowseTimeout value should always be greater than the +BrowseInterval value. Otherwise +printers and classes will disappear from client systems between updates. + + +

    Browsing

    +
    + +

    Examples

    + +
      +Browsing On
      +Browsing Off
      +
    + +

    Description

    + +

    The Browsing directive controls whether or not network printer +browsing is enabled. The default setting is On.

    + +
    + + + +
    + NOTE: + +

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

    + + +

    Classification

    +
    + +

    Examples

    + +
      +Classification
      +Classification classified
      +Classification confidential
      +Classification secret
      +Classification topsecret
      +Classification unclassified
      +
    + +

    Description

    + +

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

    ClassifyOverride

    +
    + +

    Examples

    + +
      +ClassifyOverride Yes
      +ClassifyOverride No
      +
    + +

    Description

    + +

    The ClassifyOverride 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 job-sheets option and can choose to only print one +security banner before or after the job. If the job-sheets +option is set to none then the server default classification +is used. + +

    The default is to not allow classification overrides. + + +

    ConfigFilePerm

    +
    + +

    Examples

    + +
      +ConfigFilePerm 0644
      +ConfigFilePerm 0600
      +
    + +

    Description

    + +

    The ConfigFilePerm directive specifies the permissions +to use when writing configuration files. The default is 0600. + + +

    DataDir

    +
    + +

    Examples

    + +
      +DataDir /usr/share/cups
      +
    + +

    Description

    + +

    The DataDir directive sets the directory to use for data +files. + + +

    DefaultCharset

    +
    + +

    Examples

    + +
      +DefaultCharset utf-8
      +DefaultCharset iso-8859-1
      +DefaultCharset windows-1251
      +
    + +

    Description

    + +

    The DefaultCharset directive sets the default character set +to use for client connections. The default character set is +utf-8 but is overridden by the character set for the language +specified by the client or the DefaultLanguage directive. + + +

    DefaultLanguage

    +
    + +

    Examples

    + +
      +DefaultLanguage de
      +DefaultLanguage en
      +DefaultLanguage es
      +DefaultLanguage fr
      +DefaultLanguage it
      +
    + +

    Description

    + +

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

    Deny

    +
    + +

    Examples

    + +
      +Deny from All
      +Deny from None
      +Deny from *.domain.com
      +Deny from .domain.com
      +Deny from host.domain.com
      +Deny from nnn.*
      +Deny from nnn.nnn.*
      +Deny from nnn.nnn.nnn.*
      +Deny from nnn.nnn.nnn.nnn
      +Deny from nnn.nnn.nnn.nnn/mm
      +Deny from nnn.nnn.nnn.nnn/mmm.mmm.mmm.mmm
      +Deny from @LOCAL
      +Deny from @IF(name)
      +
    + +

    Description

    + +

    The Deny directive specifies a hostname, IP address, or +network that is allowed access to the server. Deny +directives are cummulative, so multiple Deny directives +can be used to allow access for multiple hosts or networks. The +/mm notation specifies a CIDR netmask: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    mmnetmaskmmnetmask
    00.0.0.08255.0.0.0
    1128.0.0.016255.255.0.0
    2192.0.0.024255.255.255.0
    ......32255.255.255.255
    + +

    The @LOCAL name will deny access from all local +network interfaces, but not remote point-to-point interfaces. The +@IF(name) name will deny access from the named +interface. + +

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

    DocumentRoot

    +
    + +

    Examples

    + +
      +DocumentRoot /usr/share/doc/cups
      +DocumentRoot /foo/bar/doc/cups
      +
    + +

    Description

    + +

    The DocumentRoot 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 +ServerRoot directory. The +default directory is /usr/share/doc/cups. + +

    Documents are first looked up in a sub-directory for the primary +language requested by the client (e.g. /usr/share/doc/cups/fr/...) +and then directly under the DocumentRoot directory +(e.g. /usr/share/doc/cups/...), so it is possible to localize +the web content by providing subdirectories for each language needed. + + +

    Encryption

    +
    + +

    Examples

    + +
      +Encryption Never
      +Encryption IfRequested
      +Encryption Required
      +Encryption Always
      +
    + +

    Description

    + +

    The Encryption directive must appear instead a +Location +section and specifies the encryption settings for that location. +The default setting is IfRequested for all locations. + + +

    ErrorLog

    +
    + +

    Examples

    + +
      +ErrorLog /var/log/cups/error_log
      +ErrorLog /var/log/cups/error_log-%s
      +ErrorLog syslog
      +
    + +

    Description

    + +

    The ErrorLog directive sets the name of the error log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot directory. The +default error log file is /var/log/cups/error_log. + +

    The server name can be included in the filename by using +%s in the name. + +

    The special name "syslog" can be used to send the error information +to the system log instead of a plain file. + + +

    FilterLimit

    +
    + +

    Examples

    + +
      +FilterLimit 0
      +FilterLimit 200
      +FilterLimit 1000
      +
    + +

    Description

    + +

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

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

    The default limit is 0. + + +

    FilterNice

    +
    + +

    Examples

    + +
      +FilterNice 0
      +FilterNice 39
      +FilterNice -10
      +
    + +

    Description

    + +

    The FilterNice directive sets the scheduling +priority of job filters. Values larger than 0 give filters a +lower priority while values smaller than 0 give filters a higher +priority. The FilterNice value does not affect the +priority of job backends. + +

    The default priority is 0. + + +

    FontPath

    +
    + +

    Examples

    + +
      +FontPath /foo/bar/fonts
      +FontPath /usr/share/cups/fonts:/foo/bar/fonts
      +
    + +

    Description

    + +

    The FontPath directive specifies the font path to use when +searching for fonts. The default font path is +/usr/share/cups/fonts. + + +

    Group

    +
    + +

    Examples

    + +
      +Group sys
      +Group system
      +Group root
      +
    + +

    Description

    + +

    The Group directive specifies the UNIX group that +filter and CGI programs run as. The default group is sys, +system, or root depending on the operating +system. + + +

    HideImplicitMembers

    +
    + +

    Examples

    + +
      +HideImplicitMembers Yes
      +HideImplicitMembers No
      +
    + +

    Description

    + +

    The HideImplicitMembers directive controls +whether the individual printers in an implicit class are shown +to the user. The default is No.

    + +

    ImplicitClasses +must be enabled for this directive to have any effect.

    + + +

    HostNameLookups

    +
    + +

    Examples

    + +
      +HostNameLookups On
      +HostNameLookups Off
      +HostNameLookups Double
      +
    + +

    Description

    + +

    The HostNameLookups directive controls whether +or not CUPS looks up the hostname for connecting clients. The +Double setting causes CUPS to verify that the +hostname resolved from the address matches one of the addresses +returned for that hostname. Double lookups also +prevent clients with unregistered addresses from connecting +to your server. + +The default is Off to avoid the potential server +performance problems with hostname lookups. Set this option to +On or Double only if absolutely +required. + + +

    ImplicitClasses

    +
    + +

    Examples

    + +
      +ImplicitClasses On
      +ImplicitClasses Off
      +
    + +

    Description

    + +

    The ImplicitClasses directive controls whether implicit +classes are created based upon the available network printers and classes. +The default setting is On but is automatically turned +Off if Browsing is +turned Off. + + +

    ImplicitAnyClasses

    +
    + +

    Examples

    + +
      +ImplicitAnyClasses On
      +ImplicitAnyClasses Off
      +
    + +

    Description

    + +

    The ImplicitAnyClasses directive controls +whether implicit classes for local and remote printers are +created with the name AnyPrinter. The default +setting is Off.

    + +

    ImplicitClasses +must be enabled for this directive to have any effect.

    + + +

    Include

    +
    + +

    Examples

    + +
      +Include filename
      +Include /foo/bar/filename
      +
    + +

    Description

    + +

    The Include directive includes the named file in +the cupsd.conf file. If no leading path is +provided, the file is assumed to be relative to the +ServerRoot directory.

    + + +

    KeepAlive

    +
    + +

    Examples

    + +
      +KeepAlive On
      +KeepAlive Off
      +
    + +

    Description

    + +

    The KeepAlive directive controls whether or not to support +persistent HTTP connections. The default is On. + +

    HTTP/1.1 clients automatically support persistent connections, while +HTTP/1.0 clients must specifically request them using the +Keep-Alive attribute in the Connection: +field of each request. + + +

    KeepAliveTimeout

    +
    + +

    Examples

    + +
      +KeepAliveTimeout 60
      +KeepAliveTimeout 30
      +
    + +

    Description

    + +

    The KeepAliveTimeout directive controls how long a +persistent HTTP connection will remain open after the last request. The +default is 60 seconds. + + +

    Limit

    +
    + +

    Examples

    + +
      +<Limit GET POST>
      +...
      +</Limit>
      +
      +<Limit ALL>
      +...
      +</Limit>
      +
    + +

    Description

    + +

    The Limit directive groups access control directives for +specific types of HTTP requests and must appear inside a +Location section. Access can be limited +for individual request types (DELETE, GET, +HEAD, OPTIONS, POST, PUT, +and TRACE) or for all request types (ALL). The +request type names are case-sensitive for compatibility with Apache. + + +

    LimitExcept

    +
    + +

    Examples

    + +
      +<LimitExcept GET POST>
      +...
      +</LimitExcept>
      +
    + +

    Description

    + +

    The LimitExcept directive groups access control directives for +specific types of HTTP requests and must appear inside a +Location section. Unlike the +Limit directive, LimitExcept +restricts access for all requests except those listed on the +LimitExcept line. + + +

    LimitRequestBody

    +
    + +

    Examples

    + +
      +LimitRequestBody 10485760
      +LimitRequestBody 10m
      +LimitRequestBody 0
      +
    + +

    Description

    + +

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

    Also see the identical +MaxRequestSize directive. + + +

    Listen

    +
    + +

    Examples

    + +
      +Listen 127.0.0.1:631
      +Listen 192.0.2.1:631
      +
    + +

    Description

    + +

    The Listen directive specifies a network address and port +to listen for connections. Multiple Listen directives can be +provided to listen on multiple addresses. + +

    The Listen directive is similar to the +Port directive but allows you to restrict +access to specific interfaces or networks. + + +

    Location

    +
    + +

    Examples

    + +
      +<Location />
      +...
      +</Location>
      +
      +<Location /admin>
      +...
      +</Location>
      +
      +<Location /printers>
      +...
      +</Location>
      +
      +<Location /printers/name>
      +...
      +</Location>
      +
      +<Location /classes>
      +...
      +</Location>
      +
      +<Location /classes/name>
      +...
      +</Location>
      +
    + +

    Description

    + +

    The Location directive specifies access control and +authentication options for the specified HTTP resource or path. +The +Allow, +AuthClass, +AuthGroupName, +AuthType, +Deny, +Encryption, +Limit, +LimitExcept, +Order, +Require, and +Satisfy +directives may all appear inside a location. + +

    + + + + + + + + + + + +
    Locations on the Server.
    LocationDescription
    /The path for all get operations (get-printers, get-jobs, etc.)
    /adminThe path for all administration operations (add-printer, delete-printer, start-printer, etc.)
    /admin/confThe path for access to the ESP Print Pro configuration files (cupsd.conf, client.conf, etc.)
    /classesThe path for all classes
    /classes/nameThe resource for class name
    /jobsThe path for all jobs (hold-job, release-job, etc.)
    /jobs/idThe resource for job id
    /printersThe path for all printers
    /printers/nameThe path for printer name
    /printers/name.ppdThe PPD file path for printer name
    + +

    Note that more specific resources override the less specific ones. +So the directives inside the /printers/name location will override ones from /printers. +Directives inside /printers will override ones from /.   +None of the directives are inherited. +More information can be found in section "Printing System Security". + + +

    LogFilePerm

    +
    + +

    Examples

    + +
      +LogFilePerm 0644
      +LogFilePerm 0600
      +
    + +

    Description

    + +

    The LogFilePerm directive specifies the permissions +to use when writing configuration files. The default is 0644. + + +

    LogLevel

    +
    + +

    Examples

    + +
      +LogLevel none
      +LogLevel emerg
      +LogLevel alert
      +LogLevel crit
      +LogLevel error
      +LogLevel warn
      +LogLevel notice
      +LogLevel info
      +LogLevel debug
      +LogLevel debug2
      +
    + +

    Description

    + +

    The LogLevel directive specifies the level of logging +for the ErrorLog file. The +following values are recognized (each level logs everything under the +preceding levels): + +

      + +
    • none - Log nothing. + +
    • emerg - Log emergency conditions that prevent the + server from running. + +
    • alert - Log alerts that must be handled immediately. + +
    • crit - Log critical errors that don't prevent + the server from running. + +
    • error - Log general errors. + +
    • warn - Log errors and warnings. + +
    • notice - Log temporary error conditions. + +
    • info - Log all requests and state changes (default). + +
    • debug - Log basic debugging information. + +
    • debug2 - Log all debugging information. + +
    + + +

    MaxClients

    +
    + +

    Examples

    + +
      +MaxClients 100
      +MaxClients 1024
      +
    + +

    Description

    + +

    The MaxClients directive controls the maximum number of +simultaneous clients that will be allowed by the server. The default is +100 clients.

    + +
    + + + +
    + NOTE: + +

    Since each print job requires a file descriptor for the + status pipe, the CUPS server internally limits the + MaxClients value to 1/3 of the available file descriptors + to avoid possible problems when printing large numbers of jobs. +

    + + +

    MaxCopies

    +
    + +

    Examples

    + +
      +MaxCopies 100
      +MaxCopies 65535
      +
    + +

    Description

    + +

    The MaxCopies directive controls the maximum +number of copies that a user can print of a job. The default is +100 copies.

    + +
    + + + +
    + NOTE: + +

    Most HP PCL laser printers internally limit the + number of copies to 100. + +

    + + +

    MaxJobs

    +
    + +

    Examples

    + +
      +MaxJobs 100
      +MaxJobs 9999
      +MaxJobs 0
      +
    + +

    Description

    + +

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

    Setting the maximum to 0 disables this functionality. The default +setting is 0. + + +

    MaxJobsPerPrinter

    +
    + +

    Examples

    + +
      +MaxJobsPerPrinter 100
      +MaxJobsPerPrinter 9999
      +MaxJobsPerPrinter 0
      +
    + +

    Description

    + +

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

    Setting the maximum to 0 disables this functionality. The default +setting is 0. + + +

    MaxJobsPerUser

    +
    + +

    Examples

    + +
      +MaxJobsPerUser 100
      +MaxJobsPerUser 9999
      +MaxJobsPerUser 0
      +
    + +

    Description

    + +

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

    Setting the maximum to 0 disables this functionality. The default +setting is 0. + + +

    MaxLogSize

    +
    + +

    Examples

    + +
      +MaxLogSize 1048576
      +MaxLogSize 1m
      +MaxLogSize 0
      +
    + +

    Description

    + +

    The MaxLogSize 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 filename.O. This allows you to rotate the logs +automatically. The default size is 1048576 bytes (1MB). + +

    Setting the maximum size to 0 disables log rotation. + + +

    MaxRequestSize

    +
    + +

    Examples

    + +
      +MaxRequestSize 10485760
      +MaxRequestSize 10m
      +MaxRequestSize 0
      +
    + +

    Description

    + +

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

    Also see the identical +LimitRequestBody directive. + + +

    Order

    +
    + +

    Examples

    + +
      +Order Allow,Deny
      +Order Deny,Allow
      +
    + +

    Description

    + +

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

      + +
    • Allow,Deny - Allow requests from all + systems except for those listed in a Deny + directive. + +
    • Deny,Allow - Allow requests only from + those listed in an Allow directive. + +
    + +

    The Order directive must appear inside a +Location directive. + + +

    PageLog

    +
    + +

    Examples

    + +
      +PageLog /var/log/cups/page_log
      +PageLog /var/log/cups/page_log-%s
      +PageLog syslog
      +
    + +

    Description

    + +

    The PageLog directive sets the name of the page log +file. If the filename is not absolute then it is assumed to be relative +to the ServerRoot directory. The +default page log file is /var/log/cups/page_log. + +

    The server name can be included in the filename by using +%s in the name. + +

    The special name "syslog" can be used to send the page information +to the system log instead of a plain file. + + +

    Port

    +
    + +

    Examples

    + +
      +Port 631
      +Port 80
      +
    + +

    Description

    + +

    The Port directive specifies a port to listen on. +Multiple Port lines can be specified to listen on multiple +ports. The default port is 631. + + +

    PreserveJobHistory

    +
    + +

    Examples

    + +
      +PreserveJobHistory On
      +PreserveJobHistory Off
      +
    + +

    Description

    + +

    The PreserveJobHistory directive controls whether +the history of completed, cancelled, or aborted print jobs is stored +on disk. + +

    A value of On (the default) preserves job information +until the administrator purges it with the cancel +command. + +

    A value of Off removes the job information as soon as +each job is completed, cancelled, or aborted. + + +

    PreserveJobFiles

    +
    + +

    Examples

    + +
      +PreserveJobFiles On
      +PreserveJobFiles Off
      +
    + +

    Description

    + +

    The PreserveJobFiles directive controls whether the +document files of completed, cancelled, or aborted print jobs are +stored on disk. + +

    A value of On preserves job files until the +administrator purges them with the cancel command. Jobs +can be restarted (and reprinted) as desired until they are purged. + +

    A value of Off (the default) removes the job files as +soon as each job is completed, cancelled, or aborted. + + +

    Printcap

    +
    + +

    Examples

    + +
      +Printcap
      +Printcap /etc/printcap
      +Printcap /etc/printers.conf
      +
    + +

    Description

    + +

    The Printcap 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 /etc/printcap. + +

    When a filename is specified (e.g. /etc/printcap), 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. + + +

    PrintcapFormat

    +
    + +

    Examples

    + +
      +PrintcapFormat BSD
      +PrintcapFormat Solaris
      +
    + +

    Description

    + +

    The PrintcapFormat directive controls the output +format of the printcap file. The default is to generate a BSD +printcap file. + + +

    PrintcapGUI

    +
    + +

    Example

    + +
      +PrintcapGUI /usr/bin/glpoptions
      +
    + +

    Description

    + +

    The PrintcapGUI 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. + +

    The program must accept the -d option to specify +a printer and the -o 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 +-o to the standard output. + + +

    RemoteRoot

    +
    + +

    Examples

    + +
      +RemoteRoot remroot
      +RemoteRoot root
      +
    + +

    Description

    + +

    The RemoteRoot directive sets the username for +unauthenticated root requests from remote hosts. The default +username is remroot. Setting RemoteRoot +to root effectively disables this security mechanism. + + +

    RequestRoot

    +
    + +

    Examples

    + +
      +RequestRoot /var/spool/cups
      +RequestRoot /foo/bar/spool/cups
      +
    + +

    Description

    + +

    The RequestRoot 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 +ServerRoot directory. The +default request directory is /var/spool/cups. + + +

    Require

    +
    + +

    Examples

    + +
      +Require group foo bar
      +Require user john mary
      +Require valid-user
      +
    + +

    Description

    + +

    The Require directive specifies that +authentication is required for the resource. The +group keyword specifies that the authenticated user +must be a member of one or more of the named groups that follow. + +

    The user keyboard specifies that the +authenticated user must be one of the named users that follow. + +

    The valid-user keyword specifies that any +authenticated user may access the resource. + +

    The default is to do no authentication. This directive must +appear inside a Location +directive. + + +

    RIPCache

    +
    + +

    Examples

    + +
      +RIPCache 8m
      +RIPCache 1g
      +RIPCache 2048k
      +
    + +

    Description

    + +

    The RIPCache directive sets the size of the memory +cache used by Raster Image Processor ("RIP") filters such as +imagetoraster and pstoraster. 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. + + +

    RootCertDuration

    +
    + +

    Examples

    + +
      +RootCertDuration 300
      +RootCertDuration 0
      +
    + +

    Description

    + +

    The RootCertDuration directive controls the +interval between updates of the root authentication certificate. +The default is 300 seconds which updates the root +certificate approximately once every 5 minutes. Set the interval +to 0 to disable certificate updates entirely. + + + +

    RunAsUser

    +
    + +

    Examples

    + +
      +RunAsUser Yes
      +RunAsUser No
      +
    + +

    Description

    + +

    The RunAsUser directive controls whether the +scheduler runs as the unpriviledged user account (usually lp). +The default is No which leaves the scheduler running as +the root user. + +

    Note: Running as a non-priviledged user may prevent +LPD and locally connected printers from working due to +permission problems. The lpd backend will +automatically use a non-priviledged mode that is not 100% +compliant with RFC 1179. The parallel, +serial, and usb backends will need +write access to the corresponding device files. + + +

    Satisfy

    +
    + +

    Examples

    + +
      +Satisfy all
      +Satisfy any
      +
    + +

    Description

    + +

    The Satisfy directive specifies whether all +conditions must be satisfied to allow access to the resource. If +set to all, then all authentication and access +control conditions must be satified to allow access. + +

    Setting Satisfy to any 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. + +

    The default is all. This directive must appear +inside a Location +directive. + + +

    ServerAdmin

    +
    + +

    Examples

    + +
      +ServerAdmin user@host
      +ServerAdmin root@foo.bar.com
      +
    + +

    Description

    + +

    The ServerAdmin directive identifies the email address for the +administrator on the system. By default the administrator email address is +root@server, where server is the server name. + + +

    ServerBin

    +
    + +

    Examples

    + +
      +ServerBin /usr/lib/cups
      +ServerBin /foo/bar/lib/cups
      +
    + +

    Description

    + +

    The ServerBin directive sets the directory for +server-run executables. If an absolute path is not provided then it is +assumed to be relative to the +ServerRoot directory. The +default executable directory is /usr/lib/cups. + + +

    ServerCertificate

    +
    + +

    Examples

    + +
      +ServerCertificate /etc/cups/ssl/server.crt
      +
    + +

    Description

    + +

    The ServerCertificate 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 /etc/cups/ssl/server.crt. + + +

    ServerKey

    +
    + +

    Examples

    + +
      +ServerKey /etc/cups/ssl/server.key
      +
    + +

    Description

    + +

    The ServerKey directive specifies the location +of the SSL private key file used by the server when negotiating +encrypted connections. The default key file is +/etc/cups/ssl/server.crt. + + +

    ServerName

    +
    + +

    Examples

    + +
      +ServerName foo.domain.com
      +ServerName myserver.domain.com
      +
    + +

    Description

    + +

    The ServerName directive specifies the hostname that is +reported to clients. By default the server name is the hostname. + + +

    ServerRoot

    +
    + +

    Examples

    + +
      +ServerRoot /etc/cups
      +ServerRoot /foo/bar/cups
      +
    + +

    Description

    + +

    The ServerRoot directive specifies the absolute path to +the server configuration and state files. It is also used to resolve +relative paths in the cupsd.conf file. The default server +directory is /etc/cups. + + +

    ServerTokens

    +
    + +

    Examples

    + +
      +ServerTokens None
      +ServerTokens ProductOnly
      +ServerTokens Major
      +ServerTokens Minor
      +ServerTokens Minimal
      +ServerTokens OS
      +ServerTokens Full
      +
    + +

    Description

    + +

    The ServerTokens directive specifies the information +that is included in the Server header of HTTP responses. The default value +is Minor which generates "CUPS/1.1". + + +

    SSLListen

    +
    + +

    Examples

    + +
      +SSLListen 127.0.0.1:443
      +SSLListen 192.0.2.1:443
      +
    + +

    Description

    + +

    The SSLListen directive specifies a network +address and port to listen for secure connections. Multiple +SSLListen directives can be provided to listen on +multiple addresses. + +

    The SSLListen directive is similar to the +SSLPort directive but allows +you to restrict access to specific interfaces or networks. + + +

    SSLPort

    +
    + +

    Examples

    + +
      +SSLPort 443
      +
    + +

    Description

    + +

    The SSLPort directive specifies a port to listen +on for secure connections. Multiple SSLPort lines +can be specified to listen on multiple ports. + + +

    SystemGroup

    +
    + +

    Examples

    + +
      +SystemGroup sys
      +SystemGroup system
      +SystemGroup root
      +
    + +

    Description

    + +

    The SystemGroup directive specifies the system +administration group for System authentication. More +information can be found later in this chapter in +"Printing System Security". + + +

    TempDir

    +
    + +

    Examples

    + +
      +TempDir /var/tmp
      +TempDir /foo/bar/tmp
      +
    + +

    Description

    + +

    The TempDir directive specifies an absolute path for +the directory to use for temporary files. The default directory is +/var/tmp. + +

    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 /foo/bar/tmp: + +

      +mkdir /foo/bar/tmp ENTER
      +chmod a+rwxt /foo/bar/tmp ENTER
      +
    + + +

    Timeout

    +
    + +

    Examples

    + +
      +Timeout 300
      +Timeout 90
      +
    + +

    Description

    + +

    The Timeout directive controls the amount of time to +wait before an active HTTP or IPP request times out. The default +timeout is 300 seconds. + + +

    User

    +
    + +

    Examples

    + +
      +User lp
      +User guest
      +
    + +

    Description

    + +

    The User directive specifies the UNIX user that +filter and CGI programs run as. The default user is lp. + + +

    Printing System Security

    + +

    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. + +

    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. + +

    CUPS maintains a list of locations that have access control and/or +authentication enabled. Locations are specified using the +Location directive: + +

    + +

    Locations generally follow the directory structure of the +DocumentRoot directory, however +CUPS does have several virtual locations for administration, classes, jobs, +and printers: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    LocationDescription
    /adminThe path for all administration operations.
    /classesThe path for all classes.
    /classes/nameThe resource for class name.
    /jobsThe path for all jobs.
    /jobs/idThe resource for job id.
    /printersThe path for all printers.
    /printers/nameThe path for printer name.
    /printers/name.ppdThe PPD file path for printer name.
    + +

    Authentication Using Certificates

    + +

    CUPS supports a local certificate-based authentication scheme that +can be used in place of Basic or Digest +authentication by clients connecting through the localhost +interface. Certificate authentication is not supported or allowed from +clients on any other interface. + +

    Certificates are 128-bit random numbers that refer to an internal +authentication record in the server. A client connecting via the +localhost interface sends a request with an +authorization header of: + +

      +Authorization: Local 0123456789ABCDEF0123456789ABCDEF
      +
    + +

    The server then looks up the local certificate and authenticates +using the username associated with it. + +

    Certificates are generated by the server automatically and stored in +the /etc/cups/certs directory using the process ID of the +CGI program started by the server. Certificate files are only readable +by the User and +Group defined in the +cupsd.conf file. When the CGI program ends the certificate +is removed and invalidated automatically. + +

    The special file /etc/cups/certs/0 defines the root +certificate which can be used by any client running as the super-user +or another user that is part of the group defined by the +SystemGroup directive. The +root certificate is automatically regenerated every 5 minutes. + +

    Using Basic Authentication

    + +

    Basic authentication uses UNIX users and passwords to authenticate +access to resources such as printers and classes, and to limit access +to administrative functions.

    + +
    + + + +
    + NOTE: + +

    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. +

    + +

    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. + +

    Once a valid username and password is authenticated by CUPS, any +additional group membership requirements are checked.

    + +
    + + + +
    + NOTE: + +

    The root user is considered by CUPS to be a member of every + group. +

    + + +

    Use the AuthType directive to enable Basic authentication: + +

      +AuthType Basic
      +
    + + +

    Using Digest Authentication

    + +

    Digest authentication uses users and passwords defined in the +/etc/cups/passwd.md5 file to authenticate access to +resources such as printers and classes, and to limit access to +administrative functions.

    + +
    + + + +
    + NOTE: + +

    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. + +

    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. + +

    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. Support for Digest + authentication in web browsers is not yet universally + available. +

    + + +

    The lppasswd(1) command is used to add, change, or +remove accounts from the passwd.md5 file. To add a +user to the default system group, type: + +

      +lppasswd -a user ENTER
      +Password: (password) ENTER [password is not echoed]
      +Password again: (password) ENTER [password is not echoed]
      +
    + + +

    Once added, a user can change his/her password by typing: + +

      +lppasswd ENTER
      +Old password: (password) ENTER [password is not echoed]
      +Password: (password) ENTER [password is not echoed]
      +Password again: (password) ENTER [password is not echoed]
      +
    + + +

    To remove a user from the password file, type: + +

      +lppasswd -x user ENTER
      +
    + +

    Once a valid username and password is authenticated by CUPS, any +additional group membership requirements are checked.

    + +
    + + + +
    + NOTE: + +

    The root user is considered by CUPS to be a member of every + group. +

    + +

    Use the AuthType directive to enable Digest authentication: + +

      +AuthType Digest
      +
    + +

    System and Group Authentication

    + +

    The AuthClass directive controls +the level of authentication to perform. System and +Group authentication extend the normal user-based authentication +to require membership in a UNIX group. For System authentication +each user must belong to the sys, system, or +root group; the actual group depends on the operating system. + +

    For Group authentication each user must belong to the +group named by the AuthGroupName +directive: + +

      +<Location /path>
      +AuthType Digest
      +AuthClass Group
      +AuthGroupName mygroup
      +</Location>
      +
    + +

    The named group must be a valid UNIX user group, usually defined in the +/etc/group or /etc/netgroup files. Additionally, when +using Digest authentication you need to create user accounts with the named +group: + +

      +lppasswd -g mygroup -a user ENTER
      +Password: (password) ENTER [password is not echoed]
      +Password again: (password) ENTER [password is not echoed]
      +
    + + +

    Printer Accounting

    + +

    CUPS maintains a log of all accesses, errors, and +pages that are printed. The log files are normally stored in the +/var/log/cups directory. You can change this by +editing the /etc/cups/cupsd.conf configuration file. + +

    The access_log File

    + +

    The access_log file lists each HTTP resource that is accessed +by a web browser or CUPS/IPP client. Each line is in the so-called "Common +Log Format" used by many web servers and web reporting tools: + +

      +host group user date-time \"method resource version\" status bytes
      +
      +127.0.0.1 - - [20/May/1999:19:20:29 +0000] "POST /admin/ HTTP/1.1" 401 0
      +127.0.0.1 - mike [20/May/1999:19:20:31 +0000] "POST /admin/ HTTP/1.1" 200 0
      +
    + +

    The host field will normally only be an IP address unless you +have enabled the HostNameLookups +directive in the cupsd.conf file. + +

    The group field always contains "-" in CUPS. + +

    The user field is the authenticated username of the requesting user. +If no username and password is supplied for the request then this field +contains "-". + +

    The date-time field is the date and time of the request in local time +and is in the format: + +

      +[DD/MON/YYYY:HH:MM:SS +ZZZZ]
      +
    + +

    where ZZZZ is the timezone offset in hours and minutes from Greenwich +Mean Time (a.k.a. GMT a.k.a. ZULU.) + +

    The method field is the HTTP method used ("GET", "PUT", "POST", etc.) + +

    The resource field is the filename of the requested resource. + +

    The version field is the HTTP specification version used by the +client. For CUPS clients this will always be "HTTP/1.1". + +

    The status field contains the HTTP result status of the +request. Usually it is "200", but other HTTP status codes are possible. +For example, 401 is the "unauthorized access" status in the example +above. + +

    The bytes field contains the number of bytes in the request. +For POST requests the bytes field contains the number of bytes +that was received from the client. + +

    The error_log File

    + +

    The error_log file lists messages from the scheduler (errors, +warnings, etc.): + +

      +level date-time message
      +
      +I [20/May/1999:19:18:28 +0000] Job 1 queued on 'DeskJet' by 'mike'.
      +I [20/May/1999:19:21:02 +0000] Job 2 queued on 'DeskJet' by 'mike'.
      +I [20/May/1999:19:22:24 +0000] Job 2 was cancelled by 'mike'.
      +
    + +

    The level field contains the type of message: + +

      + +
    • E - An error occurred. + +
    • W - The server was unable to perform some action. + +
    • I - Informational message. + +
    • D - Debugging message. + +
    + +

    The date-time field contains the date and time of when the page +started printing. The format of this field is identical to the data-time +field in the access_log file. + +

    The message fields contains a free-form textual message. + +

    The page_log File

    + +

    The page_log file lists each page that is sent to a printer. +Each line contains the following information: + +

      +printer user job-id date-time page-number num-copies job-billing
      +
      +DeskJet root 2 [20/May/1999:19:21:05 +0000] 1 0 acme-123
      +
    + +

    The printer field contains the name of the printer that +printed the page. If you send a job to a printer class, this field will +contain the name of the printer that was assigned the job. + +

    The user field contains the name of the user (the IPP +requesting-user-name attribute) that submitted this file for +printing. + +

    The job-id field contains the job number of the page being printed. +Job numbers are reset to 1 whenever the CUPS server is started, so don't depend +on this number being unique! + +

    The date-time field contains the date and time of when the page +started printing. The format of this field is identical to the data-time +field in the access_log file. + +

    The page-number and num-pages fields contain the page number +and number of copies being printed of that page. For printer that can not +produce copies on their own, the num-pages field will always be 1. + +

    The job-billing field contains a copy of the +job-billing attribute provided with the IPP +create-job or print-job requests or "-" if none +was provided. + + +

    File Typing and Filtering

    + +

    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 /etc/cups +directory (or a directory specified by the +ServerRoot 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. + +

    The mime.types and mime.convs files define the +standard file types and filters that are available on the system. + +

    mime.types

    + +

    The mime.types 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 +text/html file type is defined as: + +

      +text/html       html htm \
      +                printable(0,1024) + \
      +                (string(0,"<HTML>") string(0,"<!DOCTYPE"))
      +
    + +

    The first two rules say that any file with an extension of +.html or .htm is a HTML file. The third rule +says that any file whose first 1024 characters are printable text and +starts with the strings <HTML> or +<!DOCTYPE is a HTML file as well. + +

    The first two rules deal solely with the name of the file being +typed. This is useful when the original filename is known, however for +print files the server doesn't have a filename to work with. The third +rule takes care of this possibility and automatically figures out the +file type based upon the contents of the file instead. + +

    The available tests are: + +

      + +
    • ( expr ) - Parenthesis for expression grouping + +
    • + - Logical AND + +
    • , or whitespace - Logical OR + +
    • ! - Logical NOT + +
    • match("pattern") - Pattern match on filename + +
    • extension - Pattern match on "*.extension" + +
    • ascii(offset,length) - True if bytes are valid + printable ASCII (CR, NL, TAB, BS, 32-126) + +
    • printable(offset,length) - True if bytes are + printable 8-bit chars (CR, NL, TAB, BS, 32-126, 160-254) + +
    • string(offset,"string") - True if bytes are + identical to string + +
    • contains(offset,range,"string") - True if the + range of bytes contains the string + +
    • char(offset,value) - True if byte is identical + +
    • short(offset,value) - True if 16-bit integer + is identical (network or "big-endian" byte order) + +
    • int(offset,value) - True if 32-bit integer is + identical (network or "big-endian" byte order) + +
    • locale("string") - True if current locale + matches string + +
    + +

    All numeric values can be in decimal (123), octal (0123), or hexadecimal +(0x123) as desired. + + +

    Strings can be in quotes, all by themselves, as a string +of hexadecimal values, or some combination: + +

      +"string"
      +'string'
      +string
      +<737472696e67>
      +<7374>ring
      +
    + +

    As shown in the text/html example, rules can continue on +multiple lines using the backslash (\) character. A more complex example is +the image/jpeg rules: + +

      +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))
      +
    + +

    This rule states that any file with an extension of +.jpeg, .jpg, or .jpe is a JPEG file. +In addition, any file starting with the hexadecimal string +<FFD8FF> (JPEG Start-Of-Image) followed by a +character between and including 0xe0 and 0xef +(JPEG APPn markers) is also a JPEG file. + +

    mime.convs

    + +

    The mime.convs file defines all of the filter programs that +are known to the system. Each line consists of: + +

      +source destination cost program
      +
      +text/plain application/postscript 50 texttops
      +application/vnd.cups-postscript application/vnd.cups-raster 50 pstoraster
      +image/* application/vnd.cups-postscript 50 imagetops
      +image/* application/vnd.cups-raster 50 imagetoraster
      +
    + +

    The source field is a MIME type, optionally using a wildcard for +the super-type or sub-type (e.g. "text/plain", "image/*", "*/postscript"). + +

    The destination field is a MIME type defined in the +mime.types file. + +

    The cost field defines a relative cost for the filtering +operation from 1 to 100. The cost is used to choose between two +different sets of filters when converting a file. For example, to convert +from image/jpeg to application/vnd.cups-raster, +you could use the imagetops and pstoraster +filters for a total cost of 100, or the imagetoraster filter +for a total cost of 50. + +

    The program field defines the filter program to run; the +special program "-" can be used to make two file types equivalent. The +program must accept the standard filter arguments and environment +variables described in the CUPS Interface Design Description and CUPS +Software Programmers Manual: + +

      +program job user title options [filename]
      +
    + +

    If specified, the filename argument defines a file to read +when filtering, otherwise the filter must read from the standard input. +All filtered output must go to the standard output. + + +

    Adding Filetypes and Filters

    + +

    Adding a new file type or filter is fairly straight-forward. Rather +than adding the new type and filter to the mime.types and +mime.convs files which are overwritten when you upgrade to a +new version of CUPS, you simple need to create new files with +.types and .convs extensions in the +/etc/cups directory. We recommend that you use the product +or format name, e.g.: + +

      +myproduct.types
      +myproduct.convs
      +
    + +

    If you are providing a filter for a common file format or printer, +add the company or author name: + +

      +acme-msword.types
      +acme.msword.convs
      +
    + +

    This will help to prevent name collisions if you install many +different file types and filters. + +

    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 cupsd process as +described earlier in "Restarting the CUPS Server". + +

    Printer Drivers and PPD Files

    + +

    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 cupsFilter attributes: + +

      +*cupsFilter: "application/vnd.cups-raster 0 rastertohp"
      +
    + +

    The filter is specified using the source file type only; the destination +file type is assumed to be printer/name - suitable for sending +to the printer. + +

    Writing Your Own Filter or Printer Driver

    + +

    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. + + +

    7 - Printing with Other Systems

    + +

    This chapter describes how to print from client systems that use the +LPD, Mac OS, or Windows printing protocols. + +

    The Basics

    + +

    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. + +

    Printing from LPD Clients

    + +

    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. + +

    The cups-lpd(8) program provides support for LPD +clients and can be used from either the inetd(8) or +xinetd(8) programs. Add the following line to the +/etc/inetd.conf file to enable LPD support on your +server through the inetd program: + +

      +printer stream tcp nowait lp /usr/lib/cups/daemon/cups-lpd cups-lpd
      +
    + +

    The path to the cups-lpd may vary depending on your +installation. + +

    Once you have added this line, send the inetd +process a HUP signal or reboot the system: + +

      +killall -HUP inetd ENTER [IRIX and some versions of Linux]
      +kill -HUP pid ENTER [Others]
      +reboot ENTER [For all systems if the HUP signal fails]
      +
    + +

    If you are using the xinetd program, create a +file named /etc/xinetd.d/printer containing the +following lines: + +

      +service printer
      +{
      +    socket_type = stream
      +    protocol = tcp
      +    wait = no
      +    user = lp
      +    server = /usr/lib/cups/daemon/cups-lpd
      +}
      +
    + +

    The xinetd program automatically reads the new +configuration file and enables LPD printing support. + +

    + + + +
    Warning: + +

    cups-lpd currently does not perform any + access control based on the settings in + cupsd.conf or in the hosts.allow + or hosts.deny files used by TCP wrappers. + Therefore, running cups-lpd on your server + will allow any computer on your network (and perhaps the + entire Internet) to print to your server. + +

    While xinetd has built-in access control + support, you should use the TCP wrappers package with + inetd to limit access to only those + computers that should be able to print through your + server. + +

    + +

    Printing to LPD Servers

    + +

    CUPS provides the lpd backend for printing to LPD-based +servers and printers. Use a device URI of lpd://server/name +to print to a printer on an LPD server, where server +is the hostname or IP address of the server and name is +the queue name. + +

    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. + +

    Printing from Mac OS Clients

    + +

    CUPS does not provide Mac OS support directly. However, there are several +free and commercial software packages that do. + +

    Columbia Appletalk Package (CAP)

    + +

    Because the CAP LaserWriter server (lwsrv(8)) does +not support specification of PPD files, we do not recommend that you +use CAP with CUPS. However, you can run the lpsrv program +for limited printing with the command: + +

      +lwsrv -n "Name" -p printer -a /usr/lib/adicts -f /usr/lib/LW+Fonts
      +
    + +

    where Name is the name you want to use when sharing the +printer, and printer is the name of the CUPS print queue. + + +

    XINET KA/Spool

    + +

    To use your system as a print server for Mac OS clients, +configure each printer using a papserver(8) in the +/usr/adm/appletalk/services file, specifying the +corresponding PPD file in the /etc/cups/ppd directory for +each printer. For a printer named MyPrinter the entry +would look like: + +

      +/usr/etc/appletalk/papserver -I -L -P /etc/cups/ppd/MyPrinter.ppd \
      +"Printer Description" MyPrinter
      +
    + +
    + + + +
    + NOTE: + +

    Enter the text above on a single line without the backslash (\) + character. +

    + +

    NetATalk

    + +

    To use your system as a print server for Mac OS clients, +configure each printer in the papd.conf file, specifying the +corresponding PPD file in the /etc/cups/ppd directory for +each printer. For a printer named MyPrinter the entry +would look like: + +

      +Printer Description:MyPrinter@MyServer:\
      +        :pr=|/usr/bin/lp -d MyPrinter:\
      +        :op=daemon:\
      +        :pd=/etc/cups/ppd/MyPrinter.ppd:
      +
    + + + +

    Printing to Mac OS Servers

    + +

    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 /usr/lib/cups/backend directory that sends a print file +using the appropriate command. The following is a short script that will +run the papif command provided with CAP. + +

    After copying this script to /usr/lib/cups/backend/cap, +specify a device URI of cap://server/printer to use this +backend with a print queue. + + +

      +
      +"/usr/lib/cups/backend/cap"
      +#!/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 > $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}' > /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 < $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
      +
    + + +

    Printing from Windows Clients

    + +

    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: + +

    + +

    To configure SAMBA for CUPS, edit the smb.conf file and +replace the existing printing commands and options with the line: + +

      +printing = cups
      +printcap name = cups
      +
    + +

    That's all there is to it! Remote users will now be able to browse and +print to printers on your system. + +

    Exporting Printer Drivers

    + +

    You can optionally export printer drivers from your CUPS +server using the cupsaddsmb command and the SAMBA +2.2.0 or higher software. + +

    Before you can export the printers you must download the +current Adobe PostScript printer drivers from the Adobe web +site (http://www.adobe.com/). +Use the free unzip software to extract the files +from the self-extracting ZIP file containing the drivers; you +will need the following files: + +

      +ADFONTS.MFM
      +ADOBEPS4.DRV
      +ADOBEPS4.HLP
      +ADOBEPS5.DLL
      +ADOBEPSU.DLL
      +ADOBEPSU.HLP
      +DEFPRTR2.PPD
      +ICONLIB.DLL
      +PSMON.DLL
      +
    + +

    Copy these files to the /usr/share/cups/drivers +directory - you may need to rename some of the files so the +filenames are all UPPERCASE. + +

    Next, add a print$ share for the printer +drivers to your smb.conf file: + +

      +[print$]
      +    comment = Printer Drivers
      +    path = /etc/samba/drivers
      +    browseable = yes
      +    guest ok = no
      +    read only = yes
      +    write list = root
      +
    + +

    The directory for your printer drivers can be anywhere on the +system; just make sure it is writable by the users specified by +the write list directive. Also, make sure that you +have SAMBA passwords defined for each user in the write +list using the smbpasswd(1) command. +Otherwise you will not be able to authenticate + +

    Finally, run the cupsaddsmb command to export +the printer drivers for one or more queues: + +

      +cupsaddsmb -U root printer1 ... printerN ENTER
      +
    + +

    Running cupsaddsmb with the -a option +will export all printers: + +

      +cupsaddsmb -U root -a ENTER
      +
    + +

    Printing to Windows Servers

    + +

    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 +LPD section earlier in this chapter. + +

    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: + +

    + +

    To configure CUPS for SAMBA, run the following command: + +

      +ln -s `which smbspool` /usr/lib/cups/backend/smb ENTER
      +
    + +

    The smbspool(1) 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: + +

      +smb://workgroup/server/sharename
      +smb://server/sharename
      +smb://user:pass@workgroup/server/sharename
      +smb://user:pass@server/sharename
      +
    + +

    The workgroup name need only be specified if your +system is using a different workgroup. The user:pass +strings are required when printing to Windows NT servers or to shares +with passwords enabled under Windows 95 and 98. + + +

    A - Software License Agreement

    + + + + +

    B - Common Network Settings

    + +

    This appendix covers many of the popular TCP/IP network interfaces +and printer servers available on the market today. + +

    Configuring a Network Interface

    + +

    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. + +

    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. + + +

    Configuring the IP Address Using ARP

    + +

    The easiest way to set the IP address of a network device is to use +the arp(8) command. The arp sends an Address +Resolution Protocol ("ARP") packet to the specified Ethernet MAC address, +setting the network device's IP address: + +

      +arp -s ip-address ethernet-address ENTER
      +arp -s host.domain.com 08:00:69:00:12:34 ENTER
      +arp -s 192.0.2.2 08:00:69:00:12:34 ENTER
      +
    + +

    Configuring the IP Address Using RARP

    + +

    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. + +

    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 arp command is the way to go. + +

    Some UNIX operating systems use a program called +rarpd(8) to manage RARP. Others, like Linux, support this +protocol in the kernel. For systems that provide the rarpd +program you will need to start it before RARP lookups will work: + +

      +rarpd ENTER
      +
    + +

    Under IRIX you can enable this functionality by default using: + +

      +chkconfig rarpd on ENTER
      +
    + +

    Both the rarpd program and kernel RARP support read a +list of Ethernet and IP addresses from the file /etc/ethers. +Each line contains the Ethernet address (colon delimited) followed by +an IP address or hostname like: + +

      +08:00:69:00:12:34 myprinter.mydomain.com
      +08:00:69:00:12:34 192.0.2.2
      +
    + +

    Add a line to this file and cycle the power on the printer or print +server to set its address. + + +

    Configuring the IP Address Using BOOTP

    + +

    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 bootpd(8) program supplied with UNIX you simply need to +add a line to the /etc/bootptab file; for IRIX: + +

      +myprinter 08:00:69:00:12:34 192.0.2.2 myprinter.boot
      +
    + + +

    Newer versions of bootpd use a different format: + +

      +myprinter:ha=080069001234:ip=192.0.2.2:t144=myprinter.boot
      +
    + +

    The myprinter.boot file resides in the /usr/local/boot +directory by default. If you do not need to provide a boot file you may leave +the last part of the line blank.

    + + +
    + + + +
    + NOTE: + +

    Some versions of UNIX do not enable the BOOTP service by + default. The /etc/inetd.conf usually contains a + line for the BOOTP service that can be uncommented if + needed. +

    + +

    Verifying the Printer Connection

    + +

    To test that the IP address has been successfully assigned and that the +printer is properly connected to your LAN, type: + +

      +ping ip-address ENTER
      +
    + +

    If the connection is working properly you will see something like: + +

      +ping myprinter ENTER
      +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
      +
    + +

    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. + + +

    Common Network Interface Settings

    + +

    Once you have set the IP address you can access the printer or print +server using the ipp, lpd, or +socket backends. The following is a list of common network +interfaces and printer servers and the settings you should use with +CUPS: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Model/ManufacturerDevice URI(s)
    Apple LaserWriterlpd://address/PASSTHRU
    Axis w/o IPP
    + (see directions)
    socket://address:9100
    + socket://address:9101
    + socket://address:9102
    Axis w/IPPipp://address/LPT1
    + ipp://address/LPT2
    + ipp://address/COM1
    Castelle LANpressTMlpd://address/pr1
    + lpd://address/pr2
    + lpd://address/pr3
    DPI NETPrintlpd://address/pr1
    + lpd://address/pr2
    + lpd://address/pr3
    EFI® Fiery® RIPlpd://address/print
    EPSON® Multiprotocol Ethernet Interface Boardsocket://address
    Extended System ExtendNETlpd://address/pr1
    + lpd://address/pr2
    + lpd://address/pr3
    Hewlett Packard JetDirect w/o IPPsocket://address:9100
    + socket://address:9101
    + socket://address:9102
    Hewlett Packard JetDirect w/IPPipp://address/ipp
    + ipp://address/ipp/port1
    + ipp://address/ipp/port2
    + ipp://address/ipp/port3
    Intel® NetportExpress XL, PRO/100lpd://address/LPT1_PASSTHRU
    + lpd://address/LPT2_PASSTHRU
    + lpd://address/COM1_PASSTHRU
    LexmarkTM MarkNetlpd://address/ps
    Linksys EtherFast®
    + (see directions)
    socket://address:4010
    + socket://address:4020
    + socket://address:4030
    Kodak®lpd://address/ps
    QMS® CrownNetTMlpd://address/ps
    Tektronix® PhaserShareTMsocket://address:9100
    XEROX® 4512 NIClpd://address/PORT1
    XEROX® XNIClpd://address/PASSTHRU
    XEROX® (most others)socket://address:5503
    + +

    Configuring Axis Print Servers

    + +

    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. + + +

    Each print server contains a configuration file named +config 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 ftp(1) program: + +

      +ftp ip-address ENTER
      +Connected to ip-address.
      +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
      +ftp> user root ENTER
      +331 User name ok, need password
      +Password: pass ENTER (this is not echoed)
      +230 User logged in
      +ftp> get config ENTER
      +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> quit ENTER
      +221 Goodbye.
      +
    + + +

    Next, edit the file with your favorite text editor and locate the +lines beginning with: + +

      +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
      +
    + + +Change the RTN_OPT line to read: + +
      +RTN_OPT.     : NO
      +
    + + +

    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: + +

      +RTEL_PR1.    : 9100
      +RTEL_PR2.    : 9101
      +RTEL_PR3.    : 9102
      +RTEL_PR4.    : 9103
      +RTEL_PR5.    : 9104
      +RTEL_PR6.    : 9105
      +RTEL_PR7.    : 9106
      +RTEL_PR8.    : 9107
      +
    + + +

    This essentially makes the Axis print server look like a Hewlett +Packard JetDirect EX print server. Save the file and then upload the +new config file using the ftp command: + +

      +ftp ip-address ENTER
      +Connected to ip-address.
      +220 Axis NPS ### FTP Printer Server V#.## MON DD YEAR ready.
      +ftp> user root ENTER
      +331 User name ok, need password
      +Password: pass ENTER (this is not echoed)
      +230 User logged in
      +ftp> put config CONFIG ENTER
      +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> get hardreset ENTER
      +local: hardreset remote: hardreset
      +200 PORT command successful.
      +421 Axis NPS ### hard reset, closing connection.
      +ftp> quit ENTER
      +221 Goodbye.
      +
    + +

    Your Axis print server is now ready for use! + +

    Configuring Linksys Print Servers

    + +

    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. + + +

    Each print server contains a configuration file named +CONFIG 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 ftp(1) program: + +

      +ftp -n ip-address ENTER
      +Connected to ip-address.
      +220 Print Server Ready.
      +Remote system type is Print.
      +ftp> get CONFIG ENTER
      +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> quit ENTER
      +221 Goodbye.
      +
    + + +

    Next, edit the file with your favorite text editor and locate the +lines beginning with: + +

      +0100 L1_PROUT:P1
      +0120 L2_PROUT:P1
      +0140 L3_PROUT:P1
      +
    + +

    Change the port number for +each parallel and serial port on the server as follows: + +

      +0100 L1_PROUT:P1
      +0120 L2_PROUT:P2
      +0140 L3_PROUT:P3
      +
    + + +

    This maps each virtual printer with a physical port. Save the file and then upload the +new CONFIG file using the ftp command: + +

      +ftp -n ip-address ENTER
      +Connected to ip-address.
      +220 Print Server Ready.
      +Remote system type is Print.
      +ftp> put CONFIG ENTER
      +local: CONFIG remote: CONFIG
      +200 Command OK.
      +150 Open ASCII Mode Connection.
      +226 Transfer complete.
      +##### bytes received in #.## seconds (##### Kbytes/s)
      +ftp> quit ENTER
      +221 Goodbye.
      +
    + +

    Your Linksys print server is now ready for use! + + +

    C - Printer Drivers

    + +

    This appendix lists the printer drivers that are provided with CUPS. + +

    Printer Drivers

    + +

    CUPS includes the following printer drivers: + +

    + +

    EPSON 9-pin Dot Matrix

    + +

    The EPSON 9-pin Dot Matrix driver (epson9.ppd) supports +9-pin dot matrix printers that implement the ESC/P command set. It +provides 60x72, 120x72, and 240x72 DPI output in black only. + +

    EPSON 24-pin Dot Matrix

    + +

    The EPSON 24-pin Dot Matrix driver (epson9.ppd) 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. + +

    EPSON Stylus Color

    + +

    The EPSON Stylus Color driver (stcolor.ppd) 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). + +

    EPSON Stylus Photo

    + +

    The EPSON Stylus Photo driver (stphoto.ppd) 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). + +

    HP DeskJet

    + +

    The HP DeskJet driver (deskjet.ppd) supports HP DeskJet +printers that implement the PCL command set. It provides 150, 300, and +600 DPI output in black and color (CMYK). + +

    The DeskJet printers that implement the HP-PPA command set (720C, +722C, 820C, and 1100C) are not supported due to a complete lack +of documentation and support from Hewlett Packard. + +

    The duplexer provided with the HP DeskJet 900 series printers is also +not supported for similar reasons. + +

    HP LaserJet

    + +

    The HP LaserJet driver (laserjet.ppd) 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. + +

    LaserJet printers that do not implement PCL (3100, 3150) are not +supported due to a complete lack of documentation and support from +Hewlett Packard. + + +

    D - List of Files

    + +

    This appendix lists the files and directories that are installed for +the Common UNIX Printing System. + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PathnameDescription
    /etc/cups/certs/The location of authentication certificate files for local + HTTP clients.
    /etc/cups/classes.confThe printer classes configuration file for the scheduler.
    /etc/cups/cupsd.confThe scheduler configuration file.
    /etc/cups/interfaces/The location of System V interface scripts for printers.
    /etc/cups/mime.convsThe list of standard file filters included with CUPS.
    /etc/cups/mime.typesThe list of recognized file types for CUPS.
    /etc/cups/ppd/The location of PostScript Printer Description ("PPD") files for + printers.
    /etc/cups/printers.confThe printer configuration file for the scheduler.
    /usr/bin/cancelThe System V cancel job(s) command.
    /usr/bin/disableThe System V disable printer command.
    /usr/bin/enableThe System V enable printer command.
    /usr/bin/lpThe System V print command.
    /usr/bin/lpoptionsSets user-defined printing options and defaults.
    /usr/bin/lppasswdAdds, changes, or removes Digest password accounts.
    /usr/bin/lpqThe Berkeley status command.
    /usr/bin/lprThe Berkeley print command.
    /usr/bin/lprmThe Berkeley cancel job(s) command.
    /usr/bin/lpstatThe System V status command.
    /usr/include/cups/CUPS API header files.
    /usr/lib32/libcups.a
    + /usr/lib32/libcupsimage.a
    Static libraries (IRIX 6.5)
    /usr/lib/libcups.a
    + /usr/lib/libcupsimage.a
    Static libraries (all others)
    /usr/lib/libcups.sl.2
    + /usr/lib/libcupsimage.sl.2
    Shared libraries (HP-UX)
    /usr/lib32/libcups.so.2
    + /usr/lib32/libcupsimage.so.2
    Shared libraries (IRIX 6.5)
    /usr/lib/libcups.so.2
    + /usr/lib/libcupsimage.so.2
    Shared libraries (all others)
    /usr/lib/cups/backend/Backends for various types of printer connections.
    /usr/lib/cups/cgi-bin/CGI programs for the scheduler.
    /usr/lib/cups/daemon/Daemons for polling and LPD support.
    /usr/lib/cups/filter/Filters for various types of files.
    /usr/lib/locale/The location of language-specific message files. (System V)
    /usr/lib/nls/msg/The location of language-specific message files. (Compaq Tru64 UNIX)
    /usr/share/locale/The location of language-specific message files. (Linux, *BSD)
    /usr/sbin/acceptThe accept-jobs command.
    /usr/sbin/cupsdThe CUPS print scheduler.
    /usr/sbin/lpadminThe System V printer administration tool.
    /usr/sbin/lpcThe Berkeley printer administration tool.
    /usr/sbin/lpinfoThe get-devices and get-ppds command.
    /usr/sbin/lpmoveThe move-jobs command.
    /usr/sbin/rejectThe reject-jobs command.
    /usr/share/catman/a_man/
    + /usr/share/catman/u_man/
    Man pages (IRIX)
    /usr/share/man/Man pages (Compaq Tru64 UNIX, HP-UX, Solaris)
    /usr/man/Man pages (all others)
    /usr/share/cups/data/The location of filter data files.
    /usr/share/cups/data/testprint.psThe PostScript test page file.
    /usr/share/cups/fonts/The location of PostScript fonts for the PostScript RIP.
    /usr/share/cups/model/The location of PostScript Printer Description ("PPD") files and + interface scripts that may be used to setup a printer queue.
    /usr/share/cups/pstoraster/Other PostScript RIP initialization files.
    /usr/share/cups/pstoraster/FontmapThe font mapping file (converts filenames to fontnames)
    /usr/share/cups/templates/The location of HTML template files for the web interfaces.
    /usr/share/doc/cups/Documentation and web page data for the scheduler.
    /var/log/cups/The location of scheduler log files.
    /var/spool/cups/The location of print files waiting to be printed.
    + + +

    E - Troubleshooting Common Problems

    + +

    This appendix covers some of the common problems first-time users +encounter when installing and configuring CUPS. + +

    Commercial support for CUPS is available from Easy Software Products. +For more information please contact us at: + +

    + +

    My Applications Don't See the Available Printers

    + +

    Many applications read the /etc/printcap file to +get a list of available printers. + +

    The default CUPS configuration creates the +/etc/printcap file automatically. To enable or +disable automatic creation and updating of this file, use the Printcap directive described +in Chapter 6, "Printing System +Management". + +

    CUPS Doesn't Recognize My Username or Password!

    + +

    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 root username and +the corresponding password to authenticate the request. + +

    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 root account then you won't be +able to add printers remotely or via the web interface! + + +

    To disable password authentication you need to edit the +/etc/cups/cupsd.conf file and comment out the +lines reading: + +

      +AuthType Basic
      +AuthClass System
      +
    + +

    for the /admin location. Then restart the CUPS server as +described in Chapter 6, "Printing System +Management".

    + +
    + + + +
    + NOTE: + +

    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. +

    + +

    I Can't Do Administration Tasks from Another Machine!

    + +

    The default CUPS configuration limits administration to the local +machine. To open up access, edit the /etc/cups/cupsd.conf +and comment out the lines reading: + +

      +Order deny,allow
      +Deny from all
      +Allow from 127.0.0.1
      +
    + +

    for the /admin location. Then restart the CUPS server as +described in Chapter 6, "Printing System +Management".

    + +
    + + + +
    + NOTE: + +

    Allowing administration access from all hosts is a potential + security risk. Please read Chapter + 6, "Printing System Management" for a description of these + risks and ways to minimize them. +

    + + +

    I Can't Do Administration Tasks from My Web Browser!

    + +

    This problem is usually caused by: + +

      + +
    1. not specifying the correct password for the + root account. + +
    2. 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 "I Can't Do + Administration Tasks from Another Machine!" section earlier + in this appendix. + +
    3. not setting a password on the root account. CUPS will not + authenticate a user account that does not have a password for + security reasons. + +
    4. authenticating using an account other than root, but the + account you are using is not a member of the system group. + +
    5. configuring CUPS to use Digest authentication, but + your web browser does not support Digest authentication. + +
    + +

    Connection Refused Messages

    + +

    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. + +

    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. + +

    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. + +

    Write Error Messages

    + +

    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. + +

    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. + + +

    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: + +

      +telnet ip-address ENTER
      +
      +Trying ip-address...
      +Connected to ip-address.
      +Escape character is `^]'.
      +
      +Please type [Return] two times, to initialize telnet configuration
      +For HELP type "?"
      +> idle-timeout: 180 ENTER
      +> quit ENTER
      +
    + + + diff --git a/doc/sdd.html b/doc/sdd.html new file mode 100644 index 000000000..92172102a --- /dev/null +++ b/doc/sdd.html @@ -0,0 +1,591 @@ + + + +CUPS Software Design Description + + + + + + + +

    +

    CUPS Software Design Description


    +CUPS-SDD-1.2
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    1 Scope + +2 References + +3 Design Overview + +A Glossary + +
    +

    1 Scope

    +

    1.1 Identification

    + This software design description document provides general information + on the architecture and coding of the Common UNIX Printing System + ("CUPS") Version 1.2. +

    1.2 System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    +

    1.3 Document Overview

    + This software design description document is organized into the + following sections: +
      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Design Overview
    • +
    • A - Glossary
    • +
    +

    2 References

    +

    2.1 CUPS Documentation

    +

    The following CUPS documentation is referenced by this document:

    +
      +
    • CUPS-CMP-1.2: CUPS Configuration Management Plan
    • +
    • CUPS-IDD-1.2: CUPS System Interface Design Description
    • +
    • CUPS-IPP-1.2: CUPS Implementation of IPP
    • +
    • CUPS-SAM-1.2.x: CUPS Software Administrators Manual
    • +
    • CUPS-SDD-1.2: CUPS Software Design Description
    • +
    • CUPS-SPM-1.2.x: CUPS Software Programming Manual
    • +
    • CUPS-SSR-1.2: CUPS Software Security Report
    • +
    • CUPS-STP-1.2: CUPS Software Test Plan
    • +
    • CUPS-SUM-1.2.x: CUPS Software Users Manual
    • +
    • CUPS-SVD-1.2: CUPS Software Version Description
    • +
    +

    2.2 Other Documents

    +

    The following non-CUPS documents are referenced by this document:

    + +

    3 Design Overview

    + CUPS is composed of 9 software sub-systems that operate together to + perform common printing tasks: +
      +
    • Backends
    • +
    • Berkeley Commands
    • +
    • CGI
    • +
    • CUPS Application Programmers Interface
    • +
    • CUPS Imaging Library
    • +
    • Daemons
    • +
    • Filters
    • +
    • Scheduler
    • +
    • System V Commands
    • +
    +

    3.1 Backends

    + The backends implement communications over a number of different + interfaces. All backends are called with a common set of arguments: +
      +
    • Device URI - the Uniform Resource Identifier for the output device + (e.g. parallel:/dev/plp, ipp://hostname/resource +).
    • +
    • Job Identifier - the job identifier for this job (integer).
    • +
    • User Name - the user associated with this job (name string).
    • +
    • Title - the title/job-name associated with this job (name string).
    • +
    • Copies - the number of copies required (integer).
    • +
    • Options - the options associated with this job (space separated + option strings).
    • +
    • Filename (optional) - the file to print; if this option is not + specified, the backend must read the print file from the standard + input.
    • +
    +

    Backends are named using the scheme of the URI, so a URI of + "ipp://hostname/resource" would be processed by the "ipp" backend.

    +

    3.1.1 ipp

    +

    The ipp backend sends the specified job to a network printer or host + using the Internet Printing Protocol. The URI is as specified by the +printer-uri-supported attribute from the printer or host.

    +

    3.1.2 lpd

    +

    The lpd backend sends the specified job to a network printer or host + using the Line Printer Daemon protocol. The URI is of the form:

    +
      +
      lpd://hostname/queue
      +
      +
    +

    3.1.3 parallel

    +

    The parallel backend sends the specified job to a local printer + connected via the specified parallel port device. The URI is of the + form:

    +
      +
      parallel:/dev/file
      +
      +
    +

    3.1.4 serial

    +

    The serial backend sends the specified job to a local printer + connected via the specified serial port device. The URI is of the form:

    +
      +
      serial:/dev/file?option[+option+...]
      +
      +
    + The options can be any combination of the following: +
      +
    • baud=rate - Sets the baud rate for the device.
    • +
    • bits=7 or 8 - Sets the number of data bits.
    • +
    • parity=even - Sets even parity checking.
    • +
    • parity=odd - Sets odd parity checking.
    • +
    • parity=none - Turns parity checking off.
    • +
    • flow=dtrdsr - Turns DTR/DSR (hardware) flow + control on.
    • +
    • flow=hard - Turns RTS/CTS (hardware) flow + control on.
    • +
    • flow=none - Turns flow control off.
    • +
    • flow=rtscts - Turns RTS/CTS (hardware) flow + control on.
    • +
    • flow=xonxoff - Turns XON/XOFF (software) flow + control on.
    • +
    +

    3.1.5 socket

    +

    The socket backend sends the specified job to a network host using + the AppSocket protocol commonly used by Hewlett-Packard and Tektronix + printers. The URI is of the form:

    +
      +
      socket://hostname[:port]
      +
      +
    + The default port number is 9100. +

    3.1.6 usb

    +

    The usb backend sends the specified job to a local printer connected + via the specified usb port device. The URI is of the form:

    +
      +
      usb:/dev/file
      +
      +
    +

    3.2 Berkeley Commands

    +

    The Berkeley commands provide a simple command-line interface to CUPS + to submit and control print jobs. It is provided for compatibility with + existing software that is hardcoded to use the Berkeley commands.

    +

    3.2.1 lpc

    + The lpc command allows users and administrators to check the status and + control print queues. The version provided with CUPS supports the + following commands: +
      +
    • quit - Quits the lpc command.
    • +
    • status - Shows the status of printers and jobs in the queue.
    • +
    +

    3.2.2 lpq

    +

    The lpq command shows the current queue status.

    +

    3.2.3 lpr

    +

    The lpr command submits a job for printing. The CUPS version of lpr + silently ignores the "i", "t", "m", "h", and "s" options.

    +

    3.2.4 lprm

    +

    The lprm removes one or more print jobs.

    +

    3.3 CGI

    +

    The Common Gateway Interface (CGI) programs provide a web-based + status interface to monitor the status of printers, classes, and jobs. + Each of the CGIs utilize HTML template files that can be customized to + provide alternate appearances.

    +

    3.3.1 admin.cgi

    +

    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.

    +

    3.3.2 classes.cgi

    +

    The classes CGI lists the available printer classes and any pending + jobs for the class. The user can click on individual classes to limit + the display and click on jobs to see the job status.

    +

    3.3.3 jobs.cgi

    +

    The jobs CGI lists the queued print jobs in order of priority. The + list can be limited by printer or job.

    +

    3.3.4 printers.cgi

    +

    The printers CGI lists the available printer queues and any pending + jobs for the printer. The user can click on individual printers to + limit the display and click on jobs to see the job status.

    +

    3.4 CUPS Application Programmers Interface

    +

    The CUPS Application Programmers Interface ("API") provides common + convenience, HTTP, IPP, language, and PPD functions used by the CUPS + software.

    +

    3.4.1 Convenience Functions

    +

    Convenience functions are provided to submit an IPP request, send a + print file, cancel a job, get a list of available printers, get a list + of available classes, get the default printer or class, get the default + server name, get the local username, and get a password string.

    +

    3.4.2 HTTP Functions

    +

    The HTTP functions provide functions to connect to HTTP servers, + issue requests, read data from a server, and write data to a server.

    +

    3.4.3 IPP Functions

    +

    The IPP function provide functions to manage IPP request data and + attributes, read IPP responses from a server, and write IPP requests to + a server.

    +

    3.4.4 Language Functions

    +

    The language functions provide a standard interface for retrieving + common textual messages for a particular locale and determining the + correct encoding (e.g. US ASCII, UTF-8, ISO-8859-1, etc.)

    +

    3.4.5 PPD Functions

    +

    The PostScript Printer Description functions manage PPD files, select + options, check for option conflicts, and emit selected options in the + correct order.

    +

    3.5 CUPS Imaging Library

    +

    The CUPS imaging library provides colorspace conversion, color + management, image management, scaling, image file, and raster functions + used by the CUPS raster filters.

    +

    3.5.1 Colorspace Conversion Functions

    +

    The colorspace conversion functions handle conversion of grayscale + and RGB colors to grayscale, RGB, K, CMY, CMYK, and CMYKcm colorspaces.

    +

    3.5.2 Color Management Functions

    +

    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.

    +

    3.5.3 Image Management Functions

    +

    The image management functions manage a tiled image database that is + swapped to/from disk as needed.

    +

    3.5.4 Scaling Functions

    +

    The scaling functions provide image scaling services using + nearest-neighbor sampling and bilinear interpolation as appropriate.

    +

    3.5.5 Image File Functions

    +

    The image file functions handle loading of all image file formats.

    +

    3.5.6 Raster Functions

    +

    The raster functions manage streams of CUPS raster data (described in + the Interface Design Document) used by non-PostScript printer drivers + and raster filters.

    +

    3.6 Daemons

    +

    The daemons provide additional network functions for the scheduler. + Currently only two daemons are provided with CUPS.

    +

    3.6.1 Line Printer Daemon

    +

    The line printer daemon provides remote LPD client support and is run + by the inetd(8) daemon as needed.

    +

    3.6.2 Polling Daemon

    +

    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.

    +

    3.7 Filters

    +

    The filters implement file conversion services for CUPS. All filters + are called with a common set of arguments:

    +
      +
    • Printer name - the name of the destination printer (name string).
    • +
    • Job Identifier - the job identifier for this job (integer).
    • +
    • User Name - the user associated with this job (name string).
    • +
    • Title - the title/job-name associated with this job (name string).
    • +
    • Copies - the number of copies required (integer).
    • +
    • Options - the options associated with this job (space separated + option strings).
    • +
    • Filename (optional) - the file to print; if this option is not + specified, the filter must read the input file from the standard input.
    • +
    +

    Filters are added to the MIME conversion data file and implement all + necessary conversions from one file type to another.

    +

    3.7.1 hpgltops

    +

    The hpgltops filter converts HP-GL/2 files into PostScript.

    +

    3.7.2 imagetops

    +

    The imagetops filter converts image files into PostScript.

    +

    3.7.3 imagetoraster

    +

    The imagetoraster filter converts image files into CUPS raster data.

    +

    3.7.4 pdftops

    +

    The pdftops filter converts PDF files into PostScript.

    +

    3.7.5 pstops

    +

    The pstops filter inserts printer-specific commands from PPD files + and performs page filtering as requested by the user.

    +

    3.7.6 pstoraster

    +

    The pstoraster filter converts PostScript program data into CUPS + raster data.

    +

    3.7.7 rastertoepson

    +

    The rastertoepson filter handles converting CUPS raster data to ESC/P + and supports both color and black-and-white printers.

    +

    3.7.8 rastertohp

    +

    The rastertohp filter handles converting CUPS raster data to HP-PCL + and supports both color and black-and-white printers.

    +

    3.7.9 texttops

    +

    The texttops filter converts text files into PostScript.

    +

    3.8 Scheduler

    +

    The scheduler is a fully-functional HTTP/1.1 and IPP/1.1 server that + manages the printers, classes, and jobs in the system. It also handles + a simple broadcast-based directory service so that remote print queues + and classes can be accessed transparently from the local system.

    +

    3.8.1 Authorization

    +

    The authorization module is responsible for performing access control + and authentication for all HTTP and IPP requests entering the system.

    +

    3.8.2 Classes

    +

    The classes module is responsible for managing printer classes in the + system. Each class is a collection of local and/or remote printers. The + classes module also reads and writes the classes configuration file.

    +

    3.8.3 Client

    +

    The client module is responsible for all HTTP client communications. + It handles listening on selected interfaces, accepting connections from + prospective clients, processing incoming HTTP requests, and sending + HTTP responses to those requests. The client module also is responsible + for executing the external CGI programs as needed to support web-based + printer, class, and job status monitoring and administration.

    +

    Once authorized, all IPP requests are sent to the IPP module.

    +

    3.8.4 Configuration

    +

    The configuration module is responsible for reading the CUPS + configuration file and initializing the appropriate data structures and + values. The configuration module also stops CUPS services before + reading the configuration file and restarts them after the + configuration file has been read.

    +

    3.8.5 Devices

    +

    The devices module is responsible for managing the list of available + devices for the CUPS-Get-Devices operation.

    +

    3.8.6 Directory Services

    +

    The directory services module sends and recieves printer state + information over a broadcast socket. Remote printers and classes are + automatically added to or removed from the local printer and class + lists as needed.

    +

    The directory services module can only recieve printer state + information over a single UDP port, however it can broadcast to + multiple addresses and ports as needed.

    +

    3.8.7 IPP

    +

    The IPP module handles IPP requests and acts accordingly. URI + validation is also performed here, as a client can post IPP data to any + URI on the server which might sidestep the access control or + authentication of the HTTP server.

    +

    3.8.8 Jobs

    +

    The jobs module manages print jobs, starts filter and backend + processes for jobs to be printed, and monitors status messages from + those filters and backends.

    +

    3.8.9 Logging

    +

    The logging module manages the access, error, and page log files that + are generated by the scheduler.

    +

    3.8.10 Main

    +

    The main module is responsible for timing out and dispatching input + and output for client connections. It also watches for incoming +SIGHUP and SIGCHLD signals, reloads the server + configuration files as needed, and handles child process errors and + exits.

    +

    3.8.11 MIME

    +

    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.

    +

    3.8.12 PPDs

    +

    The PPDs module is responsible for managing the list of available PPD + files for the CUPS-Get-PPDs operation.

    +

    3.8.13 Printers

    +

    The printers module is responsible for managing printers and PPD + files in the system. The printers module also reads and writes the + printers configuration file.

    +

    3.9 System V Commands

    +

    The System V commands provide a robust command-line interface to CUPS + to submit and control printers and jobs.

    +

    3.9.1 accept

    +

    The accept command tells the scheduler to accept new jobs for + specific printers.

    +

    3.9.2 cancel

    +

    The cancel command tells the scheduler to cancel one or more jobs + that are queued for printing.

    +

    3.9.3 disable

    +

    The disable command tells the scheduler to stop printing jobs on the + specified printers.

    +

    3.9.4 enable

    +

    The enable command tells the scheduler to start printing jobs on the + specified printers.

    +

    3.9.5 lp

    +

    The lp command submits submits files for printing. Unlike the + standard System V lp command, a single CUPS lp command will generate a + separate job ID for each file that is printed. Also, the Solaris "f", + "H", "P", "S", and "y" options are silently ignored.

    +

    3.9.6 lpadmin

    +

    The lpadmin command manages printer queues and classes. The Solaris + "A", "F", "I", "M", "P", "Q", "S", "T", "U", "W", "f", "l", "m", "o", + "s", "t", and "u" options are not supported, and new options "P" (PPD + file) and "E" (enable and accept) are provided to configure + CUPS-specific features.

    +

    3.9.7 lpinfo

    +

    The lpinfo command lists the available PPD files or devices as + selected by the user.

    +

    3.9.8 lpmove

    +

    The lpmove command moves a print job to a new destination.

    +

    3.9.9 lpoptions

    +

    The lpoptions command manages user-defined printers and options.

    +

    3.9.10 lpstat

    +

    The lpstat command lists printers, classes, and jobs as requested by + the user.

    +

    3.9.11 reject

    +

    The reject command tells the scheduler not to accept new jobs for + specific printers.

    +

    A Glossary

    +

    A.1 Terms

    +
    +
    C
    +
    A computer language.
    +
    parallel
    +
    Sending or receiving data more than 1 bit at a time.
    +
    pipe
    +
    A one-way communications channel between two programs.
    +
    serial
    +
    Sending or receiving data 1 bit at a time.
    +
    socket
    +
    A two-way network communications channel.
    +
    +

    A.2 Acronyms

    +
    +
    ASCII
    +
    American Standard Code for Information Interchange
    +
    CUPS
    +
    Common UNIX Printing System
    +
    ESC/P
    +
    EPSON Standard Code for Printers
    +
    FTP
    +
    File Transfer Protocol
    +
    HP-GL
    +
    Hewlett-Packard Graphics Language
    +
    HP-PCL
    +
    Hewlett-Packard Page Control Language
    +
    HP-PJL
    +
    Hewlett-Packard Printer Job Language
    +
    IETF
    +
    Internet Engineering Task Force
    +
    IPP
    +
    Internet Printing Protocol
    +
    ISO
    +
    International Standards Organization
    +
    LPD
    +
    Line Printer Daemon
    +
    MIME
    +
    Multimedia Internet Mail Exchange
    +
    PPD
    +
    PostScript Printer Description
    +
    SMB
    +
    Server Message Block
    +
    TFTP
    +
    Trivial File Transfer Protocol
    +
    + + diff --git a/doc/sdd.pdf b/doc/sdd.pdf new file mode 100644 index 0000000000000000000000000000000000000000..15a684056e8d6f5d6703f347f9a267a752c0e1d7 GIT binary patch literal 71633 zc-pMI2|U!__dlK_g`%=$*CPAOYxYTzHHFk5V#pX{8EZ3^5M`}oX_KW=Q6kwYWrRXe z))Xm}Hd{g^OCXn*bItFByGH@9WJL;A#u-!Bddv7v@Chz3s=4$UjmH||8st7QKtEU%TSw_>xwBVj70aM(46TmFi%%+I*jb$=0<|KIlF_`APZ*?dl=o7M0bMu zQ)nJA4|fX8%hv2BX8gVBRnv zm@n)g%n#YeK%rTj znKzhMEa9f%{@e!}tVed<;9V~mXpzw5QQVkc%yGcHXe4`z8;Rxuqt60lb@c#;ipInC z**k;A3d#Sso!Wc&y2F^(2w9jbWY%PF8f4UdFh9^#>}Vb?6nAJ6=@c^43TD`lryU9A zL9=%NEr@AQ5V$MF&4Zh5LWT-i zHp`?zlHZlK=1 zUD@QD65Sm#b{b^o;H4AE)qw>$b(210{mhBdWLcypOAgJy^sdR$h33rcXwsm$)YOG( zPm83>>a5G^tov7I-I-oHSTs9WG&}yH*)c<->*WO7#ey?tksGtfjsGGyo+6m(<>u|` zT1m*_I#XDkDSvgQ%=B_*(Kxecod2S6o}rKItD`roqxWAOy=Qv(u^xIcC&6#}w)M>JfMnkt^gKXcGV!+af*Q~r z0Hy`59?aX?;93m!pV>iVpq+&_(xh5IjH~&&3V% zzjD*^aJ8R{8TNl=w!@3$>P()C9q!-R=~G;NC|=;QG#4-Y{{ydi#|pszoui4Lo1KU2 zpRNFVR|{i1D!35O^xok{a-@Lf0Pa^N(6Vj?+X3#M2f>w4hvMT*rVzGk$)LBunI9zc zgJFK~%#SwnqsRQHTZ3J}CC}5t72Nh^yl9|V={dVXE2AECM~4EAjRG@ww)b+9K_LNf z?93<%4S>=+d(n4OXxbibp5Q9#?j?hQ8B*LGK|(Yhjh114)Ya);U_{}@bFiiF;{JeC zjEqlIzhE5tRsXwwyoK?o^>>E8S4Yp!p}>p84P8+@ zuFn~=Ecm(`dq>0NoqxcNCmY{1pQ2AFt+w$~*R2^kZ_x2VLN+PyyP88X<89TW;$P<5 zE1HTo*z6n=6KWoKWc74cgXeL?w|zG2-_u_5KG5zwZcw!0t-%=mKz6pi*4atn&awC< ziu;N;H0Nxv*kOF)fZt0^V_O02%k4iI%i`rvZ_tAuBP?tBPWH*(muq30yI6Up=uM6j z9832YEZx7wR?=bzE#bIQK|789%r!ePPyOL%d_m09FB{JX_j=sg_IgPd^^9&+>_eh; z9-oM&plndMqcitSO`f$a97+v*p9NFt-cM6H1S2yo&hg?O+j6Z;{P@^bGWmq^u#Rfp zmc6H!zEfQPZYOPk=(buH@7K9nSAv-6m`z^28`g0 zg$cPgpL6uCSz+49p(MD%u#qD(67|(Gwu5R{ev41^rt!x;oJ*A&4@S`|4jdQFll$mz zky^3dLG)(*##9H<8Z6Pcete>Sg#OdFWK_WCq3yZ%J1-rM+4S?Lluj;3=-2YNT^lA& z+>3{EF1>QJ_jRG^Sl1CB&v%<6)++in4!o85Y4?u;QlydxhA{<*9vAN54G$pxAk<^gdRpNPp{S zdz0smfUXVV7et92t|lig`Nh3p6msQ0u~oQuLiu~fC8g8XZqp3uDq*@yT6Z&&xS~#y zBhjZai99Ek-Az57B>>q0|ve%T3x#JWdrkDnIYblnl@OCQyfqOD#Vd zx~WOuWs(>s)p$_#z0_64xfqXQ4yqPjH0$d9cV$E3g?7H=R@~SuPDk?HDs;(*pX|W)~+i!Pr@l(b^5?j=^a(ZvwZ8*1H@HMvPPQ;g68*gw>!wc zT3#M*US7m+yEm!!yO!s(VcxIHV&y{O8lRvFq zwNk{rPFjx9vg|1Dz38*XG+8tCi$c5<-Paq;SM9OaH;qwHy;)Ts6`mw@eYxt@sxCTx zXoL9T?5ax+U0R|a972>riqUsv9UQVTdZ)JYTDpA-5!IFIJF-$Q8$oD#nE3qVqm6cE zE7}^{6ACOXoznepRT^`WCx2~iOLk68r=1uY+%X-Zlc=y_}xP_coej6!GGZLyKG@ z684?$WgO`)N@LL0H#ZI6s+6%$KCAwM9;efVu8m7%NLk9tXG;A*a_e~>d`Jrvi;w8N z(x>v457@cCw_r1skMh1{EkkOZ#h&4vVqdhm$6Ays>25W|rmpph@+SsXDjnNq zC>#_a|K5Y9Jv9Qr9-5@NCQ4hWx%7$m#Ld1T^HCMG%v?7VF@zeiH@mIIyJ&ITN2KZX zzPqO7O@!KKRdGp-Z0X@$M5#OanoDk(XXg>m2e_#;H{p`g)heGXTa|8u@698&elSVC zLp-g&XK%*Fy5u8@;%ZyWhklCwAg*wUqpnzWZ+&)*Ys3p;RtWOL>YKHvmtJ?-b~gHE zCH=VZ?Pv5iMv-^+J%8`N>`^{#*SkWmEm%7G=2o=}&p7vBRtl;X1V#lLpjKH|E-d3`B`uW0| z8V)1ON>ujw=jRJ}>VBRCZl8Q@EOsE;|B5*_u#+r*#K{Bi4-ds`=? zt2TKS(wDi$a6);PQq-jP8R zBKyB)sP4?^QcO%#Tl_I0c(rbaSM~{S^G@%MWYRHAu$lt#rZxqA_qnIF|NhSf**-8) z+3m-><#wl}TTXUUUvDGC^)?)rHTP@!blUyccAbYDH;sB=epCWX9- zcwI$2w)K2;=?0%$DGr?3bq|}`4sI@##VlL9C`6*4PcComB)n}>f-b2cy?E@->ON7C+Qs344MWd*|w@e|Ct7?&G?R#7}U$?7BTG$sJTi1L+g7*8EJlxcTFll^;7de@`t>XH@0L z4PvuDWIlZ#ed0Fy!D7{K9rnMgnu73&m9#9a&JJCfcWty^4Mhb(R!;|ae7Nxn0c-YC z?+H4;rC6~wDE7_U25)t@J8mxauk1N4SgFetNR4C4pYC&E_()`5Og2c~q0vv=*c#aL zZN&{__lJn`{05r$*kDIUU&)U}OOaAuzttd=5P;d)qzV39@`0<;5j*fG5RI_G% z+~@^&4Dl#K6z^7mqBst~v5IBuJpowNXvU>UjjQEXc>No38+=JZqk z-CornIZQ>p%RIL}KZe@(-O5dbUm}~7N?1_?L*ajfRo{L=EPH5{$e^uk&TX(wBi0}| zO+}l?1yUMLw(3P)X@IUW3F`i}8jfSA;K$Vb&E)u-EbM7l!={+`rXhkm)D)>~aI zzGtOvwiRqsP(fI5Z+f#IcyCE_!Jcd0xkr|#et)aWe$9r%8*`)RBn@>qg z4f}^8T?b+daYc1UKZs!zmpb3@&3-O!ZYf@Hb+=j1hj*K$V_cpctB;dqJP-ZRdVYV2 zTfmne))K_7@&hZx;!fKs5yPcb6()DbV6$7L7$qk{dk^8VHB1`Ys?)Zy9P8VJ3bM_(d8Kg zB16Ykl~nNf3OF6$t$fa>!pqOObUkV^rg0oKaNe-=ir*S8^UC)GaiPyklst&TZROhA zR690HpEGbXbw2$~qo9StP+S@RJl*etq6WrKq>G9t?p!ZBa;vyfT(x>9KQW~I8b(pN zYyafx#paTy4NB^cc7o8UgH@shVk_fYoCKDi6H$%tKtyIHbbiJWsq4Kd7o=0)oz5P7 z&sZ9LmLoHBEn`=w>Rt)e{8LGKOGH$AhxI-`F_Zf)+_zWys|iT+yXwSa2dV7w^NaYb z1tEhx{Csa1clN=m){T>2A5@NaWf5JT1`B<^sF~|=J4^N6NR?R-J&>Li>@uj!`0h;; zY9~(r2YL;*8Ebwp`_aW-az|*1`Ob{{%FPd|)oPxb8~Q4Ei*)+0wb^g7AG4vDw9CZ& zu-IjdjGZWvYf;7YPQ~p#;?(4lLtD_<)$cZEoWBxW@H@sF^|`vJu#!}{zb0BysaZ4d zGN~Y}Q)fru6%xJugGl=M?R&G|NDwbuS;l`~B7W6_?=zy{ZZQH~?kQB5ia6P&dFAR; zzFtHDt%(rg>3xaY*qCPhvnfCJg}+I#AddwOPTXY=73{zWgsJ}GVt7Kq(9^lV#CcuhnhD*H#!p)uh2ZChe^ z(F*gGXMdBn4Cz>lnfn};h>Nb?m~8%gtrYdZCEKi|t67-_A6nX^D=W`D?Rrm@(s*NH zyUpnN%chM7I=-j279QC5oPS`lZEN7!iyQXldu^{G#y|2dne;wvc>gjnu}8XY3xV*h zaj!;lW|7hJK|%E;9~BLIaQBcMyFwJ?2)oKq8ycYtwTQZF){vOQ@g}q$G!IjOZVMz-YWJ~ zVo!XTw|9-mJ&Dr>{tf4LUKu})H?ihvZUXL!NK2pY9bETCK7MDs>*jqTl^|W;wG#1o z^g!?aE9cSIhOcz@ewg_Fc*V=E$uwbA>7TA1u#dV%WQ$MTpH~+oo#3)*qaDoN?tu;6 z{WTCTz-C%g!Gtz% zvnhDT@9Ozazf%friHUYrJsaXPRKt0*<4Gps@zurW2|v4Ngs$r#tEArAq?(Jp@Zw)B zPkT>BpK`eYPG%r($d(wrCAqS+l5ew`S$tX3*1eo(h^iw3Ic_gBVzskELAq?vu-@L? z*l423oqcggV)(!^XB*{RP1ihk41}+!G&8!{6hT}A>Ud*Jb&rh?c8~WH^q%-qv-@FS;d@y|9ju|cP+LHnclYh>(ADvUyB>cl-g-~#r+=|uNo4)Etp*Lkl_Pe6 z^xAsL;WytmGj2>;W&6hwhgZbBP-GB=Yubr}bi9hPd2PP+#`w_(9aZK}Df^GOmB^dl z-Ie`;cWFsXd*!#<{6)>*!0Up6Z}^+1dBKN+T%0A$23uSI56bGMBw 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 + + + + + CUPS Software Design Description + + + +

    Scope

    + +

    Identification

    + +This software design description document provides general information +on the architecture and coding of the Common UNIX Printing System +("CUPS") Version 1.2. + + + +

    Document Overview

    + +This software design description document is organized into the +following sections: + +
      + +
    • 1 - Scope + +
    • 2 - References + +
    • 3 - Design Overview + +
    • A - Glossary + +
    + + + +

    Design Overview

    + +CUPS is composed of 9 software sub-systems that operate together to +perform common printing tasks: + +
      + +
    • Backends + +
    • Berkeley Commands + +
    • CGI + +
    • CUPS Application Programmers Interface + +
    • CUPS Imaging Library + +
    • Daemons + +
    • Filters + +
    • Scheduler + +
    • System V Commands + +
    + +

    Backends

    + +The backends implement communications over a number of different interfaces. +All backends are called with a common set of arguments: + +
      + +
    • Device URI - the Uniform Resource Identifier for the output device + (e.g. parallel:/dev/plp, + ipp://hostname/resource). + +
    • Job Identifier - the job identifier for this job (integer). + +
    • User Name - the user associated with this job (name string). + +
    • Title - the title/job-name associated with this job (name string). + +
    • Copies - the number of copies required (integer). + +
    • Options - the options associated with this job (space separated + option strings). + +
    • Filename (optional) - the file to print; if this option is not + specified, the backend must read the print file from the standard + input. + +
    + +

    Backends are named using the scheme of the URI, so a URI of +"ipp://hostname/resource" would be processed by the "ipp" backend. + +

    ipp

    + +

    The ipp backend sends the specified job to a network printer or host using +the Internet Printing Protocol. The URI is as specified by the +printer-uri-supported attribute from the printer or host. + +

    lpd

    + +

    The lpd backend sends the specified job to a network printer or host using +the Line Printer Daemon protocol. The URI is of the form: + +

      lpd://hostname/queue
      +
    + +

    parallel

    + +

    The parallel backend sends the specified job to a local printer connected +via the specified parallel port device. The URI is of the form: + +

      parallel:/dev/file
      +
    + +

    serial

    + +

    The serial backend sends the specified job to a local printer connected +via the specified serial port device. The URI is of the form: + +

      serial:/dev/file?option[+option+...]
      +
    + +The options can be any combination of the following: + +
      + +
    • baud=rate - Sets the baud rate for the device. + +
    • bits=7 or 8 - Sets the number of data bits. + +
    • parity=even - Sets even parity checking. + +
    • parity=odd - Sets odd parity checking. + +
    • parity=none - Turns parity checking off. + +
    • flow=dtrdsr - Turns DTR/DSR (hardware) flow + control on. + +
    • flow=hard - Turns RTS/CTS + (hardware) flow control on. + +
    • flow=none - Turns flow control off. + +
    • flow=rtscts - Turns RTS/CTS + (hardware) flow control on. + +
    • flow=xonxoff - Turns XON/XOFF + (software) flow control on. + +
    + +

    socket

    + +

    The socket backend sends the specified job to a network host using the +AppSocket protocol commonly used by Hewlett-Packard and Tektronix +printers. The URI is of the form: + +

      socket://hostname[:port]
      +
    + +The default port number is 9100. + +

    usb

    + +

    The usb backend sends the specified job to a local printer connected +via the specified usb port device. The URI is of the form: + +

      usb:/dev/file
      +
    + +

    Berkeley Commands

    + +

    The Berkeley commands provide a simple command-line interface to CUPS +to submit and control print jobs. It is provided for compatibility with +existing software that is hardcoded to use the Berkeley commands. + +

    lpc

    + +The lpc command allows users and administrators to check the status and +control print queues. The version provided with CUPS supports the following +commands: + +
      + +
    • quit - Quits the lpc command. + +
    • status - Shows the status of printers and jobs in the queue. + +
    + +

    lpq

    + +

    The lpq command shows the current queue status. + +

    lpr

    + +

    The lpr command submits a job for printing. The CUPS version of lpr silently +ignores the "i", "t", "m", "h", and "s" options. + +

    lprm

    + +

    The lprm removes one or more print jobs. + +

    CGI

    + +

    The Common Gateway Interface (CGI) programs provide a web-based +status interface to monitor the status of printers, classes, and jobs. +Each of the CGIs utilize HTML template files that can be customized to +provide alternate appearances. + +

    admin.cgi

    + +

    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. + +

    classes.cgi

    + +

    The classes CGI lists the available printer classes and any pending +jobs for the class. The user can click on individual classes to limit +the display and click on jobs to see the job status. + +

    jobs.cgi

    + +

    The jobs CGI lists the queued print jobs in order of priority. The +list can be limited by printer or job. + +

    printers.cgi

    + +

    The printers CGI lists the available printer queues and any pending +jobs for the printer. The user can click on individual printers to +limit the display and click on jobs to see the job status. + +

    CUPS Application Programmers Interface

    + +

    The CUPS Application Programmers Interface ("API") provides common +convenience, HTTP, IPP, language, and PPD functions used by the CUPS +software. + +

    Convenience Functions

    + +

    Convenience functions are provided to submit an IPP request, send a +print file, cancel a job, get a list of available printers, get a list +of available classes, get the default printer or class, get the default +server name, get the local username, and get a password string. + +

    HTTP Functions

    + +

    The HTTP functions provide functions to connect to HTTP servers, +issue requests, read data from a server, and write data to a server. + +

    IPP Functions

    + +

    The IPP function provide functions to manage IPP request data and +attributes, read IPP responses from a server, and write IPP requests to +a server. + +

    Language Functions

    + +

    The language functions provide a standard interface for retrieving +common textual messages for a particular locale and determining the +correct encoding (e.g. US ASCII, UTF-8, ISO-8859-1, etc.) + +

    PPD Functions

    + +

    The PostScript Printer Description functions manage PPD files, +select options, check for option conflicts, and emit selected options +in the correct order. + +

    CUPS Imaging Library

    + +

    The CUPS imaging library provides colorspace conversion, color +management, image management, scaling, image file, and raster functions +used by the CUPS raster filters. + +

    Colorspace Conversion Functions

    + +

    The colorspace conversion functions handle conversion of grayscale +and RGB colors to grayscale, RGB, K, CMY, CMYK, and CMYKcm colorspaces. + +

    Color Management Functions

    + +

    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. + +

    Image Management Functions

    + +

    The image management functions manage a tiled image database that is +swapped to/from disk as needed. + +

    Scaling Functions

    + +

    The scaling functions provide image scaling services using +nearest-neighbor sampling and bilinear interpolation as appropriate. + +

    Image File Functions

    + +

    The image file functions handle loading of all image file formats. + +

    Raster Functions

    + +

    The raster functions manage streams of CUPS raster data (described +in the Interface Design Document) used by non-PostScript printer +drivers and raster filters. + +

    Daemons

    + +

    The daemons provide additional network functions for the scheduler. +Currently only two daemons are provided with CUPS. + +

    Line Printer Daemon

    + +

    The line printer daemon provides remote LPD client support and is +run by the inetd(8) daemon as needed. + +

    Polling Daemon

    + +

    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. + +

    Filters

    + +

    The filters implement file conversion services for CUPS. All filters +are called with a common set of arguments: + +

      + +
    • Printer name - the name of the destination printer (name string). + +
    • Job Identifier - the job identifier for this job (integer). + +
    • User Name - the user associated with this job (name string). + +
    • Title - the title/job-name associated with this job (name string). + +
    • Copies - the number of copies required (integer). + +
    • Options - the options associated with this job (space separated + option strings). + +
    • Filename (optional) - the file to print; if this option is not + specified, the filter must read the input file from the standard + input. + +
    + +

    Filters are added to the MIME conversion data file and implement all +necessary conversions from one file type to another. + +

    hpgltops

    + +

    The hpgltops filter converts HP-GL/2 files into PostScript. + +

    imagetops

    + +

    The imagetops filter converts image files into PostScript. + +

    imagetoraster

    + +

    The imagetoraster filter converts image files into CUPS raster data. + +

    pdftops

    + +

    The pdftops filter converts PDF files into PostScript. + +

    pstops

    + +

    The pstops filter inserts printer-specific commands from PPD files and +performs page filtering as requested by the user. + +

    pstoraster

    + +

    The pstoraster filter converts PostScript program data into CUPS +raster data. + +

    rastertoepson

    + +

    The rastertoepson filter handles converting CUPS raster data to +ESC/P and supports both color and black-and-white printers. + +

    rastertohp

    + +

    The rastertohp filter handles converting CUPS raster data to HP-PCL +and supports both color and black-and-white printers. + +

    texttops

    + +

    The texttops filter converts text files into PostScript. + +

    Scheduler

    + +

    The scheduler is a fully-functional HTTP/1.1 and IPP/1.1 server that +manages the printers, classes, and jobs in the system. It also handles +a simple broadcast-based directory service so that remote print queues +and classes can be accessed transparently from the local system. + +

    Authorization

    + +

    The authorization module is responsible for performing access +control and authentication for all HTTP and IPP requests entering the +system. + +

    Classes

    + +

    The classes module is responsible for managing printer classes in +the system. Each class is a collection of local and/or remote +printers. The classes module also reads and writes the classes +configuration file. + +

    Client

    + +

    The client module is responsible for all HTTP client +communications. It handles listening on selected interfaces, accepting +connections from prospective clients, processing incoming HTTP +requests, and sending HTTP responses to those requests. The client +module also is responsible for executing the external CGI programs as +needed to support web-based printer, class, and job status monitoring +and administration. + +

    Once authorized, all IPP requests are sent to the IPP module. + +

    Configuration

    + +

    The configuration module is responsible for reading the CUPS +configuration file and initializing the appropriate data structures and +values. The configuration module also stops CUPS services before +reading the configuration file and restarts them after the +configuration file has been read. + +

    Devices

    + +

    The devices module is responsible for managing the list of available +devices for the CUPS-Get-Devices operation. + +

    Directory Services

    + +

    The directory services module sends and recieves printer state +information over a broadcast socket. Remote printers and classes are +automatically added to or removed from the local printer and class +lists as needed. + +

    The directory services module can only recieve printer state information +over a single UDP port, however it can broadcast to multiple addresses and +ports as needed. + +

    IPP

    + +

    The IPP module handles IPP requests and acts accordingly. URI +validation is also performed here, as a client can post IPP data to any +URI on the server which might sidestep the access control or +authentication of the HTTP server. + +

    Jobs

    + +

    The jobs module manages print jobs, starts filter and backend +processes for jobs to be printed, and monitors status messages from +those filters and backends. + +

    Logging

    + +

    The logging module manages the access, error, and page log files +that are generated by the scheduler. + +

    Main

    + +

    The main module is responsible for timing out and dispatching input +and output for client connections. It also watches for incoming +SIGHUP and SIGCHLD signals, reloads the +server configuration files as needed, and handles child process errors +and exits. + +

    MIME

    + +

    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. + +

    PPDs

    + +

    The PPDs module is responsible for managing the list of available +PPD files for the CUPS-Get-PPDs operation. + +

    Printers

    + +

    The printers module is responsible for managing printers and PPD +files in the system. The printers module also reads and writes the +printers configuration file. + +

    System V Commands

    + +

    The System V commands provide a robust command-line interface to +CUPS to submit and control printers and jobs. + +

    accept

    + +

    The accept command tells the scheduler to accept new jobs for specific +printers. + +

    cancel

    + +

    The cancel command tells the scheduler to cancel one or more jobs that are +queued for printing. + +

    disable

    + +

    The disable command tells the scheduler to stop printing jobs on the +specified printers. + +

    enable

    + +

    The enable command tells the scheduler to start printing jobs on the +specified printers. + +

    lp

    + +

    The lp command submits submits files for printing. Unlike the standard +System V lp command, a single CUPS lp command will generate a separate +job ID for each file that is printed. Also, the Solaris "f", "H", "P", "S", +and "y" options are silently ignored. + +

    lpadmin

    + +

    The lpadmin command manages printer queues and classes. The Solaris +"A", "F", "I", "M", "P", "Q", "S", "T", "U", "W", "f", "l", "m", "o", +"s", "t", and "u" options are not supported, and new options "P" (PPD +file) and "E" (enable and accept) are provided to configure +CUPS-specific features. + +

    lpinfo

    + +

    The lpinfo command lists the available PPD files or devices as selected +by the user. + +

    lpmove

    + +

    The lpmove command moves a print job to a new destination. + +

    lpoptions

    + +

    The lpoptions command manages user-defined printers and options. + +

    lpstat

    + +

    The lpstat command lists printers, classes, and jobs as requested by the +user. + +

    reject

    + +

    The reject command tells the scheduler not to accept new jobs for specific +printers. + + + + + diff --git a/doc/spm.html b/doc/spm.html new file mode 100644 index 000000000..925b1c29e --- /dev/null +++ b/doc/spm.html @@ -0,0 +1,8919 @@ + + + +CUPS Software Programmers Manual + + + + + + + +


    +

    CUPS Software Programmers Manual


    +CUPS-SPM-1.2.0
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    Preface + +1 - Printing System Overview + +2 - The CUPS API + +3 - Writing Filters + +4 - Writing Printer Drivers + +5 - Writing Backends + +A - Software License Agreement + +B - Constants + +C - Structures + +D - Functions + +
    +

    Preface

    +

    This software programmers manual provides software programming + information for the Common UNIX Printing System ("CUPS") Version 1.2.0.

    +

    System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    + + +

    Document Overview

    +

    This software programmers manual is organized into the following + sections:

    + +

    Notation Conventions

    +

    Various font and syntax conventions are used in this guide. Examples + and their meanings and uses are explained below: +

    + + + + + + + + + + + + +
    Example   Description
     
    lpstat +
    lpstat(1)
       The names of commands; + the first mention of a command or function in a chapter is followed by + a manual page section number.
     
    /var +
    /usr/share/cups/data/testprint.ps
        +File and directory names.
     
    Request ID is Printer-123 +   Screen output.
     
    lp -d printer filename ENTER +   Literal user input; special keys like ENTER are + in ALL CAPS.
     
    12.3   Numbers in the text are + written using the period (.) to indicate the decimal point.
    +
    + + +

    +

    Abbreviations

    + The following abbreviations are used throughout this manual: +
      +
      +
      kb
      +
      Kilobytes, or 1024 bytes +
       
      +
      Mb
      +
      Megabytes, or 1048576 bytes +
       
      +
      Gb
      +
      Gigabytes, or 1073741824 bytes +
       
      +
      +
    +

    Other References

    +
      +
      +
      CUPS Software Administrators Manual
      +
      An administration guide for the CUPS software. +
       
      +
      CUPS Software Users Manual
      +
      An end-user guide for using the CUPS software. +
       
      +
      +
    +

    1 - Printing System Overview

    +

    This chapter provides an overview of how the Common UNIX Printing + System works.

    +

    The Printing Problem

    +

    For years the printing problem has plagued UNIX. Unlike + Microsoft® Windows® or Mac OS, UNIX has no standard interface or system + in place for supporting printers. Among the solutions currently + available, the Berkeley and System V printing systems are the most + prevalent.

    +

    These printing systems support line printers (text only) or + PostScript printers (text and graphics), and with some coaxing they can + be made to support a full range of printers and file formats. However, + because each varient of the UNIX operating system uses a different + printing system than the next developing printer drivers for a wide + range of printers and operating systems is extremely difficult. That + combined with the limited volume of customers for each UNIX varient has + forced most printer vendors to give up supporting UNIX entirely.

    +

    CUPS is designed to eliminate the printing problem. One common + printing system can be used by all UNIX varients to support the + printing needs of users. Printer vendors can use its modular filter + interface to develop a single driver program that supports a wide range + of file formats with little or no effort. Since CUPS provides both the + System V and Berkeley printing commands, users (and applications) can + reap the benefits of this new technology with no changes.

    +

    The Technology

    +

    CUPS is based upon an emerging Internet standard called the Internet + Printing Protocol. IPP has been embraced by dozens of printer and + printer server manufacturers and is supported by Microsoft Windows + 2000.

    +

    IPP defines a standard protocol for printing as well as managing + print jobs and printer options like media size, resolution, and so + forth. Like all IP-based protocols, IPP can be used locally or over the + Internet to printers hundreds or thousands of miles away. Unlike other + protocols, however, IPP also supports access control, authentication, + and encryption, making it a much more capable and secure printing + solution than older ones.

    +

    IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP") + which is the basis of web servers on the Internet. This allows users to + view documentation, check status information on a printer or server, + and manage their printers, classes, and jobs using their web browser.

    +

    CUPS provides a complete IPP/1.1 based printing system that provides + Basic, Digest, and local certificate authentication and user, domain, + or IP-based access control. TLS encryption will be available in future + versions of CUPS.

    +

    Jobs

    +

    Each file or set of files that is submitted for printing is called a + job. Jobs are identified by a unique number starting at 1 and are + assigned to a particular destination, usually a printer. Jobs can also + have options associated with them such as media size, number of copies, + and priority.

    +

    Classes

    +

    CUPS supports collections of printers known as classes. Jobs + sent to a class are forwarded to the first available printer in the + class.

    +

    Filters

    +

    Filters allow a user or application to print many types of files + without extra effort. Print jobs sent to a CUPS server are filtered + before sending them to a printer. Some filters convert job files to + different formats that the printer can understand. Others perform page + selection and ordering tasks.

    +

    CUPS provides filters for printing many types of image files, HP-GL/2 + files, PDF files, and text files. CUPS also supplies PostScript and + image file Raster Image Processor ("RIP") filters that convert + PostScript or image files into bitmaps that can be sent to a raster + printer.

    +

    Backends

    +

    Backends perform the most important task of all - they send the + filtered print data to the printer.

    +

    CUPS provides backends for printing over parallel, serial, and USB + ports, and over the network via the IPP, JetDirect (AppSocket), and + Line Printer Daemon ("LPD") protocols. Additional backends are + available in network service packages such as the SMB backend included + with the popular SAMBA software.

    +

    Backends are also used to determine the available devices. On startup + each backend is asked for a list of devices it supports, and any + information that is available. This allows the parallel backend to tell + CUPS that an EPSON Stylus Color 600 printer is attached to parallel + port 1, for example.

    +

    Printer Drivers

    +

    Printer drivers in CUPS consist of one of more filters specific to a + printer. CUPS includes sample printer drivers for Hewlett-Packard + LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color, + and Stylus Photo printers. While these drivers do not generate optimal + output for the different printer models, they do provide basic printing + and demonstrate how you can write your own printer drivers and + incorporate them into CUPS.

    +

    Networking

    +

    Printers and classes on the local system are automatically shared + with other systems on the network. This allows you to setup one system + to print to a printer and use this system as a printer server or spool + host for all of the others. Users may then select a local printer by + name or a remote printer using "name@server".

    +

    CUPS also provides implicit classes, which are collections of + printers and/or classes with the same name. This allows you to setup + multiple servers pointing to the same physical network printer, for + example, so that you aren't relying on a single system for printing. + Because this also works with printer classes, you can setup multiple + servers and printers and never worry about a single point of failure + unless all of the printers and servers go down!

    +

    2 - The CUPS API

    +

    This chapter describes the CUPS Application Programmers Interface + ("API").

    +

    The CUPS API Library

    +

    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.

    +

    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.

    +

    Programs that use the CUPS API library typically will include the +<cups/cups.h> header file:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +jobid = cupsPrintFile("myprinter", "filename.ps", "title",
      +                      num_options, options);
      +
      +
    +

    Use the -lcups compiler option when linking to the CUPS + API library:

    +
      +
      +cc -o program program.c -lcups ENTER
      +
      +
    +

    Additional options and libraries may be required depending on the + operating system and the location of the CUPS API library.

    +

    Detecting the CUPS API Library in GNU Autoconf

    +

    GNU autoconf is a popular configuration tool used by many programs. + Add the following lines to your configure.in file to check + for the CUPS API library in your configuration script:

    +
      +
      +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)
      +
      +
    +

    Printing Services

    +

    The CUPS API library provides some basic printing services for + applications that need to print files.

    +

    Include Files

    +

    The include file used by all of these functions is +<cups/cups.h>:

    +
      +
      +#include <cups/cups.h>
      +
      +
    +

    Printing a File

    +

    The CUPS API provides two functions for printing files. The first is +cupsPrintFile which prints a single named file:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int jobid;
      +
      +...
      +
      +jobid = cupsPrintFile("name", "filename", "title", 0, NULL);
      +
      +
    +

    The name string is the name of the printer or class to + print to. The filename string is the name of the file to + print. The title string is the name of the print job, e.g. + "Acme Word Document".

    +

    The return value is a unique ID number for the print job or 0 if + there was an error.

    +

    Printing Multiple Files

    +

    The second printing function is cupsPrintFiles:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int        jobid;
      +int        num_files;
      +const char *files[100];
      +...
      +
      +jobid = cupsPrintFiles("name", num_files, files, "title", 0, NULL);
      +
      +
    +

    Instead of passing a filename string as with cupsPrintFile() + you pass a file count (num_files) and filename pointer + array (files) for each file that you want to print.

    +

    As with cupsPrintFile() the return value is a unique ID + for the print job.

    +

    Cancelling Jobs

    +

    The cupsCancelJob() function cancels a queued print job:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int jobid;
      +int status;
      +...
      +
      +status = cupsCancelJob("name", jobid);
      +
      +
    +

    The name string specifies the destination and is used to + determine the server to send the request to. The jobid + value is the integer returned from a previous cupsPrintFile() + or cupsPrintFiles() call.

    +

    cupsCancelJob() returns 1 if the job was + successfully cancelled and 0 if there was an error.

    +

    Getting the Available Printers and Classes

    +

    The cupsGetDests() function can be used to get a list of + the available printers, classes, and instances that a user has defined:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int         num_dests;
      +cups_dest_t *dests;
      +
      +...
      +
      +num_dests = cupsGetDests(&dests);
      +
      +
    +

    Each destination is stored in a cups_dest_t 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:

    +
      +
      +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;
      +
      +
    +

    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 cupsGetDest() + function:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int         num_dests;
      +cups_dest_t *dests;
      +cups_dest_t *mydest;
      +
      +...
      +
      +mydest = cupsGetDest("name", "instance", num_dests, dests);
      +
      +
    +

    The name string is the printer or class name. You can + pass a value of NULL to get the default destination.

    +

    The instance string is the user-defined instance name. + Pass NULL to select the default instance, e.g. "name" + instead of "name/instance".

    +

    Printing with Options

    +

    All of the previous printing examples have passed 0 and +NULL for the last two arguments to the cupsPrintFile() + and cupsPrintFiles() functions. These last two arguments + are the number of options and a pointer to the option array:

    +
      +
      +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);
      +
      +
    +

    The cups_option_t structure holds each option and its + value. These are converted as needed and passed to the CUPS server when + printing a file.

    +

    The simplest way of handling options is to use the num_options + and options members of the cups_dest_t + structure described earlier:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int         jobid;
      +int         num_dests;
      +cups_dest_t *dests;
      +cups_dest_t *mydest;
      +
      +...
      +
      +mydest = cupsGetDest("name", "instance", num_dests, dests);
      +
      +jobid  = cupsPrintFile(mydest->name, "filename", "title",
      +                       mydest->num_options, mydest->options);
      +
      +
    +

    This effectively uses the options a user has previous selected + without a lot of code.

    +

    Setting Printer Options

    +

    Options can also be set by your program using the +cupsAddOption() function:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int           num_options;
      +cups_option_t *options;
      +
      +...
      +
      +num_options = 0;
      +options     = NULL;
      +
      +...
      +
      +num_options = cupsAddOption("name", "value", num_options, &options);
      +num_options = cupsAddOption("name", "value", num_options, &options);
      +num_options = cupsAddOption("name", "value", num_options, &options);
      +num_options = cupsAddOption("name", "value", num_options, &options);
      +
      +
    +

    The name string is the name of the option, and the +value string is the value for that option.

    +

    Each call to cupsAddOption() 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 +cupsAddOptions() 20 times will result in 20 options.

    +

    Call cupsFreeOptions once you are done using the + options:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int           num_options;
      +cups_option_t *options;
      +
      +...
      +
      +cupsFreeOptions(num_options, options);
      +
      +
    +

    Getting Errors

    +

    If any of the CUPS API printing functions returns an error, the + reason for that error can be found by calling cupsLastError() + and cupsErrorString(). cupsLastError() + returns the last IPP error code that was encountered. +cupsErrorString() converts the error code to a localized message + string suitable for presentation to the user:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +int jobid;
      +
      +...
      +
      +if (jobid == 0)
      +  puts(cupsErrorString(cupsLastError()));
      +
      +
    +

    Passwords and Authentication

    +

    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.

    +

    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.

    +

    The cupsSetPasswordCB() + function is used to set a password callback in your program. Only one + function can be used at any time.

    +

    The cupsSetUser() function + sets the current username for authentication. This function can be + called by your password callback function to change the current + username as needed.

    +

    The following example shows a simple password callback that gets a + username and password from the user:

    +
      +
      +#include <cups/cups.h>
      +
      +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);
      +
      +
    +

    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 +cupsUser() to make things easier on the user.

    +

    PPD Services

    +

    CUPS includes functions to access and manipulate PostScript Printer + Description ("PPD") files that are used with the printer drivers in + CUPS.

    +

    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.)

    +

    Include Files

    +

    Include the <cups/ppd.h> header file to use the PPD + functions:

    +
      +
      +#include <cups/ppd.h>
      +
      +
    +

    This header file is also included by the <cups/cups.h> + header file.

    +

    Getting a PPD File for a Printer

    +

    The cupsGetPPD() function retrieves the PPD file for the + named printer or class:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +const char *filename;
      +
      +filename = cupsGetPPD("name");
      +
      +
    +

    The name string is the name of the printer or class, + including the remote server name as appropriate (e.g. + "printer@server".)

    +

    The return value is a pointer to a filename in static storage; this + value is overwritten with each call to cupsGetPPD(). If + the printer or class does not exist, a NULL pointer will + be returned.

    +

    Loading a PPD File

    +

    The ppdOpenFile() function "opens" a PPD file and loads + it into memory:

    +
      +
      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +
      +ppd = ppdOpenFile("filename");
      +
      +
    +

    The filename string is the name of the file to load, + such as the value returned by the cupsGetPPD() function.

    +

    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.

    +

    Freeing PPD File Information

    +

    Once you are done using a PPD file, call the ppdClose() + function to free all memory that has been used:

    +
      +
      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +
      +...
      +
      +ppdClose(ppd);
      +
      +
    +

    The PPD File Structure

    +

    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 +ppd_file_t structure.

    +

    Capabilities

    +

    Each PPD file contains a number of informational attributes that + describe the capabilities of the printer. These are provided in the +ppd_file_t structure in the following members: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    accurate_screensint1 + = supports accurate screens
    color_deviceint1 = + color device
    colorspaceppd_cs_t +Default colorspace: PPD_CS_CMYK, PPD_CS_CMY, PPD_CS_GRAY, PPD_CS_RGB, + PPD_CS_RGBK, PPD_CS_N
    contone_onlyint1 = + printer is continuous tone only
    num_emulations +
    emulations
    int +
    ppd_emul_t *
    Emulations supported by the printer
    flip_duplexint1 = + need to flip odd pages when duplexing
    num_fonts +
    fonts
    int +
    char **
    The fonts available on the printer.
    jcl_begin +
    jcl_ps +
    jcl_end
    char *Job Control + Language commands for PostScript output
    landscapeint +Landscape orientation, -90 or 90 degrees
    lang_encodingchar * +The character used for the option strings
    lang_versionchar * +The language used for the options strings (English, French, etc.)
    language_levelint +PostScript language level, 1 to 3
    manual_copiesint1 = + Copies are done manually
    model_numberint +Driver-specific model number.
    patcheschar *Patch + commands to send to the printer
    manufacturerchar * +The Manufacturer attribute from the PPD file, if any
    modelnamechar *The + ModelName attribute from the PPD file
    nicknamechar *The + NickName attribute from the PPD file, if any
    productchar *The + Product attribute from the PPD file, if any
    shortnicknamechar * +The ShortNickName attribute from the PPD file, if any
    throughputintNumber + of pages per minute
    ttrasterizerchar * +The TruType font rasterizer (Type42)
    variable_sizesint1 = + supports variable sizes
    +
    +

    +

    Options and Groups

    +

    PPD files support multiple options, which are stored in +ppd_option_t and ppd_choice_t structures by the PPD + functions.

    +

    Each option in turn is associated with a group stored in the +ppd_group_t 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.

    +

    Groups can also have sub-groups; CUPS currently limits the depth of + sub-groups to 1 level to reduce programming complexity.

    +

    Conflicts

    +

    PPD files support specification of conflict conditions between + different options. Conflicts are stored in ppd_conflict_t + structures which specify the options that conflict with each other.

    +

    Page Sizes

    +

    PPD files specify all of the available pages sizes and the physical + margins associated with them. These sizes are stored in +ppd_size_t structures and are available in the num_sizes + and sizes members of the ppd_file_t + structure. You can lookup a particular page size with the +ppdPageWidth(), ppdPageLength(), and +ppdPageSize() functions:

    +
      +
      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +ppd_size_t *size;
      +float      width;
      +float      length;
      +
      +...
      +
      +size   = ppdPageSize(ppd, "size");
      +width  = ppdPageWidth(ppd, "size");
      +length = ppdPageLength(ppd, "size");
      +
      +
    +

    The size string is the named page size option. The width + and length are in points; there are 72 points per inch. The +ppd_size_t structure contains the width, length, and margin + information:

    +
      +
      +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;
      +
      +
    +

    Custom Page Sizes

    +

    Besides the standard page sizes listed in a PPD file, some printers + support variable or custom page sizes. If variables_sizes + is non-zero, the custom_min, custom_max, and +custom_margins members of the ppd_file_t structure + define the limits of the variable sizes.

    +

    To get the resulting media size, use a page size string of +Custom.widthxlength, where width and +length are integer values in points:

    +
      +
      +Custom.612x792   [8.5 inches wide, 11 inches long]
      +Custom.1224x792  [17 inches wide, 11 inches long]
      +
      +
    +

    Marking Options

    +

    Before marking any user-defined options, call the +ppdMarkDefaults() function to mark the default options from the + PPD file:

    +
      +
      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +
      +...
      +
      +ppdMarkDefaults(ppd);
      +
      +
    +

    Then call the ppdMarkOption() function to mark + individual options:

    +
      +
      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +int        conflicts;
      +
      +...
      +
      +conflicts = ppdMarkOption(ppd, "name", "value");
      +
      +
    +

    The name and value strings choose a + particular option and choice, respectively. The return value is 0 if + there are not conflicts created by the selection.

    +

    CUPS also provides a convenience function for marking all options in + the cups_option_t structure:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +ppd_file_t    *ppd;
      +int           num_options;
      +cups_option_t *options;
      +int           conflicts;
      +
      +...
      +
      +conflicts = cupsMarkOptions(ppd, num_options, options);
      +
      +
    +

    The cupsMarkOptions() function also handles mapping the + IPP job template attributes to PPD options. The return value is the + number of conflicts present.

    +

    Checking for Conflicts

    +

    The ppdMarkOption() and cupsMarkOptions() + functions return the number of conflicts with the currently marked + options.

    +

    Call the ppdConflicts() function to get the number of + conflicts after you have marked all of the options:

    +
      +
      +#include <cups/cups.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +int        conflicts;
      +
      +...
      +
      +conflicts = ppdConflicts(ppd);
      +
      +
    +

    The return value is the number of conflicting options, or 0 if there + are no conflicts.

    +

    3 - Writing Filters

    +

    This chapter describes how to write a file filter for CUPS.

    +

    Overview

    +

    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.

    +

    Security Considerations

    +

    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.

    +

    Users and Groups

    +

    The default CUPS configuration runs filters as user "lp" and group + "other".

    +

    Temporary Files

    +

    Temporary files should be created in the directory specified by the + "TMPDIR" environment variable. The +cupsTempFile() function can be used to safely choose + temporary files in this directory.

    +

    Sending Messages to the User

    +

    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 LogLevel directive.

    +

    The type of message is determined by an initial prefix sent on each + line:

    +
      +
    • DEBUG: - a debug message
    • +
    • INFO: - an informational message
    • +
    • WARNING: - a warning message
    • +
    • ERROR: - an error message
    • +
    • PAGE: - a page accounting message
    • +
    +

    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 printer-state-message attribute for the printer, and + also added to the error_log unless it is an informational or + page accounting message.

    +

    Page Accounting

    +

    Page accounting messages are used to inform the server when one or + more pages are printed. Each line has the form:

    +
      +
      +PAGE: page-number copy-count
      +
      +
    +

    The page-number field is the current page number, starting at + 1. The copy-count field specifies the number of copies of that + page that was produced.

    +

    Page account messages are added to the page_log file and + cause the job-sheets-completed attribute to be updated for + the job.

    +

    Command-Line Arguments

    +

    Every filter accepts exactly 6 or 7 command-line arguments:

    +
      +
      +printer job user title copies options [filename]
      +
      +
    • printer - The name of the printer queue (normally this + is the name of the program being run)
    • +
    • job - The numeric job ID for the job being printed
    • +
    • user - The string from the originating-user-name + attribute
    • +
    • title - The string from the job-name + attribute
    • +
    • copies - The numeric value from the number-copies + attribute
    • +
    • options - 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
    • +
    • filename - The request file
    • +
    +

    The filename argument is only provided to the first filter in + the chain; all filters must be prepared to read the print file + from the standard input if the filename argument is omitted.

    +

    Copy Generation

    +

    The copies argument specifies the number of copies to produce + of the input file. In general, you should only generate copies if the + filename 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 pstops is responsible for copy generation.

    +

    Environment Variables

    +

    Every filter receives a fixed set of environment variables that can + be used by the filter:

    +
      +
    • CHARSET - The character set used by the client for this + print file
    • +
    • CONTENT_TYPE - The original document type, such as + "application/postscript"
    • +
    • CUPS_DATADIR - The location of CUPS data files
    • +
    • CUPS_SERVERROOT - The location of CUPS configuration + files
    • +
    • DEVICE_URI - The output device URI
    • +
    • LANG - The language used by the client for this print + file
    • +
    • PATH - The execution path exported to the filter
    • +
    • PPD - The full filename of the printer's PPD file
    • +
    • PRINTER - The name of the printer queue
    • +
    • RIP_CACHE - The maximum amount of memory each filter + should use
    • +
    • SOFTWARE - The name of the CUPS software, typically + "CUPS/1.1"
    • +
    • TZ - The local timezone
    • +
    • USER - The name of the current user
    • +
    +

    Dissecting the HP-GL/2 Filter

    +

    The HP-GL/2 filter (hpgltops) 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.

    +

    Initializing the Filter

    +

    The first task of any filter is to ensure that the correct number of + command-line arguments are present:

    +
      +
      +if (argc < 6 || argc > 7)
      +{
      +  fputs("ERROR: hpgltops job-id user title copies options [file]\n", stderr);
      +  return (1);
      +}
      +
      +
    +

    After this you open the print file or read from the standard input as + needed:

    +
      +
      +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);
      +  }
      +}
      +
      +
    +

    Once the print file has been opened, options can be processed using + the cupsParseOptions() and cupsGetOption() functions:

    +
      +
      +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("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;
      +
      +
    +

    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.

    +

    PostScript Output

    +

    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:

    +
      +
      +%!PS-Adobe-3.0
      +%%BoundingBox: left bottom right top
      +%%Pages: (atend)
      +%%EndComments
      +
      +
    +

    The left, bottom, right, and top values + are integers in points from the lower-lefthand corner of the page.

    +

    Pages must be surrounded by:

    +
      +
      +%%Page: number number
      +gsave
      +...
      +grestore
      +showpage
      +
      +
    +

    And the end of each file must contain:

    +
      +
      +%%Trailer
      +%%Pages: number-pages
      +%%EOF
      +
      +
    +

    These comments allow the PostScript filter to correctly perform page + accounting, copy generation, N-up printing, and so forth.

    +

    4 - Writing Printer Drivers +

    +

    This chapter discusses how to write a printer driver, which is a + special filter program that converts CUPS raster data into the + appropriate commands and data required for a printer.

    +

    Overview

    +

    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.

    +

    CUPS Raster Data

    +

    CUPS raster data (application/vnd.cups-raster) consists + of a stream of raster page descriptions produced by one of the RIP + filters, such as pstoraster or imagetoraster.

    +

    Each page of data begins with a page dictionary structure called + cups_raster_header_t. This structure contains the + colorspace, bits per color, media size, media type, hardware + resolution, and so forth.

    +

    After the page dictionary comes the page data which is a + full-resolution, uncompressed bitmap representing the page in the + printer's output colorspace.

    +

    Page Accounting

    +

    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.

    +

    Color Management

    +

    Printer drivers can implement their color management via the +cupsColorProfile 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.

    +

    For example, the pstoraster 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.

    +

    Device and Bitmap Variables

    +

    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: +

    + + + + + + + + + + + + + + +
    VariableTypeDescription
    cupsWidthread-only integerWidth of bitmap in + pixels
    cupsHeightread-only integerHeight of bitmap in + pixels
    cupsMediaTyperead-write integerDevice-specific + media type code
    cupsBitsPerColorread-write integerNumber of + bits per color; 1, 2, 4, and 8 are currently supported
    cupsBitsPerPixelread-only integerNumber of + bits per pixel; 1 to 32
    cupsBytesPerLineread-only integerNumber of + bytes per line of raster graphics
    cupsColorOrderread-write enumThe order of + color values in the bitmap: +
      +
    • CUPS_ORDER_CHUNKED - CMYK CMYK CMYK
    • +
    • CUPS_ORDER_BANDED - CCC MMM YYY KKK
    • +
    • CUPS_ORDER_PLANAR - CCC ... MMM ... YYY ... KKK ...
    • +
    +
    cupsColorSpaceread-write enumThe colorspace of + the bitmap: +
      +
    • CUPS_CSPACE_W - White (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 - Metallic yellow (gold), metallic + magenta, metallic cyan, black
    • +
    • CUPS_CSPACE_GMCS - Metallic yellow (gold), metallic + magenta, metallic cyan, metallic grey (silver)
    • +
    • CUPS_CSPACE_WHITE - White pigment (black as white + pigment)
    • +
    • CUPS_CSPACE_GOLD - Gold foil (black as gold foil)
    • +
    • CUPS_CSPACE_SILVER - Silver foil (black as silver foil)
    • +
    +
    cupsCompressionread-write integer +Device-specific compression type code
    cupsRowCountread-write integerDevice-specific + row count value
    cupsRowFeedread-write integerDevice-specific + row feed value
    cupsRowStepread-write integerDevice-specific + row step value
    +
    +

    +

    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.

    +

    Dissecting the HP-PCL Driver

    +

    The HP-PCL driver provided with CUPS (rastertohp) + 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 - deskjet.ppd or + laserjet.ppd.

    +

    PPD Files

    +

    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.

    +

    A typical CUPS printer driver will include ColorModel, +InputSlot, PageSize, PageRegion, and +Resolution options. Each option is shown using the standard PPD + format:

    +
      +
      +*OpenUI *PageSize/Media Size: PickOne
      +*OrderDependency: 10 AnySetup *PageSize
      +*DefaultPageSize: Letter
      +*PageSize Letter/US Letter: "<<
      +/PageSize [612 792]
      +/ImagingBBox null
      +>> setpagedevice"
      +*End
      +*PageSize Legal/US Legal: "<<
      +/PageSize [612 1008]
      +/ImagingBBox null
      +>> setpagedevice"
      +*End
      +*PageSize A4/A4: "<<
      +/PageSize [595 842]
      +/ImagingBBox null
      +>> setpagedevice"
      +*End
      +*CloseUI: *PageSize
      +
      +
    +

    The OpenUI 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.

    +

    Every option must have a default value, specified using the +DefaultOption keyword.

    +

    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:

    +
      +
      +*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>> setpagedevice"
      +
      +
    +

    or broken down on separate lines using the End keyword + to terminate them:

    +
      +
      +*PageSize A4/A4: "<<
      +/PageSize [595 842]
      +/ImagingBBox null
      +>> setpagedevice"
      +*End
      +
      +
    +

    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.

    +

    Reading Raster Data

    +

    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 cupsRasterOpen() + function opens a raster stream for printing:

    +
      +
      +int           fd;   /* File descriptor */
      +cups_raster_t *ras; /* Raster stream for printing */
      +
      +
      +/*
      + * Check for valid arguments...
      + */
      +
      +if (argc < 6 || argc > 7)
      +{
      + /*
      +  * We don't have the correct number of arguments; write an error message
      +  * and return.
      +  */
      +
      +  fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr);
      +  return (1);
      +}
      +
      +/*
      + * Open the page stream...
      + */
      +
      +if (argc == 7)
      +{
      +  if ((fd = open(argv[6], O_RDONLY)) == -1)
      +  {
      +    perror("ERROR: Unable to open raster file - ");
      +    sleep(1);
      +    return (1);
      +  }
      +}
      +else
      +  fd = 0;
      +
      +ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
      +
      +
    +

    Once you have opened the raster stream you just need to read each + page and print it:

    +
      +
      +cups_raster_header_t header;
      +int                  y;
      +unsigned char        data[8192];
      +
      +while (cupsRasterReadHeader(ras, &header))
      +{
      +  ... initialize the printer ...
      +  for (y = header.cupsHeight; y > 0; y ++)
      +  {
      +    cupsRasterReadPixels(ras, data, header.cupsBytesPerLine);
      +    ... send raster line to printer ...
      +  }
      +}
      +
      +
    +

    After you have processed all pages, close the raster stream and + return:

    +
      +
      +cupsRasterClose(ras);
      +
      +return (0);
      +
      +
    +

    5 - Writing Backends

    +

    This chapter describes how to write a backend for CUPS. Backends + communicate directly with printers and allow printer drivers and + filters to send data using any type of connection transparently.

    +

    Overview

    +

    Backends are special filters that communicate with printers directly. + They are treated slightly differently than filters, however, and have + some unique requirements.

    +

    Security Considerations

    +

    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.

    +

    Command-Line Arguments

    +

    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.

    +

    Copy Generation

    +

    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.

    +

    Page Accounting

    +

    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.

    +

    Exclusive Access

    +

    Backends that talk to local character or block devices should open + the device file in exclusive mode (O_EXCL) to cooperate + with other printers defined for the same device.

    +

    Retries

    +

    All backends must 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.

    +

    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.

    +

    Dissecting the Serial Port Backend

    +

    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.

    +

    Supporting Device Discovery

    +

    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...)

    +

    The serial backend lists devices by looking at serial port files in + the /dev directory, by consulting a hardware inventory + (IRIX), and in some cases by trying to open the ports to see if they + actually exist.

    +

    Once it finds a serial port it writes a single line for each port to + the standard error file. Each line looks like this:

    +
      +
      +serial serial:/dev/ttyS0?baud=115200 "Unknown" "Serial Port 1"
      +
      +
    +

    The first word "serial" is the device class; this identifies + the class of device which can be used to categorize it in user + interfaces. CUPS currently recognizes the following classes:

    +
      +
    • "file" - a disk file.
    • +
    • "direct" - a parallel or fixed-rate serial data port, currently used + for Centronics, IEEE-1284, and USB printer ports.
    • +
    • "serial" - a variable-rate serial port.
    • +
    • "network" - a network connection, typically via AppSocket, HTTP, + IPP, LPD, or SMB/CIFS protocols.
    • +
    +

    After the device class is the device URI, 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.

    +

    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.

    +

    Opening the Serial Port

    +

    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 do-while loop:

    +
      +
      +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 < 0);
      +
      +
    +

    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.

    +

    Writing Data to the Port

    +

    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:

    +
      +
      +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;
      +}
      +
      +
    +

    The check for the ENOTTY error is needed on some + platforms to clear an error from a previous ioctl() call.

    +

    Finishing Up

    +

    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.

    +

    A - Software License Agreement

    +

    Common UNIX Printing System License + Agreement

    +

    Copyright 1997-2003 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, with exceptions for + Apple operating systems and the OpenSSL toolkit. A copy of the + exceptions and 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 "cups" include + directory and library files in the binary distributions. The GNU GPL + applies to the remainder of the CUPS distribution, including the + "pdftops" filter which is based upon Xpdf and the CUPS imaging library.

    +

    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 only exceptions to this are the portions of + the CUPS software covered by the Apple operating system license + exceptions outlined later in this license agreement.

    +

    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.

    +

    License Exceptions

    +

    In addition, as the copyright holder of CUPS, Easy Software Products + grants the following special exceptions:

    +
      +
    1. Apple Operating System Development License Exception; +
        +
      1. Software that is developed by any person or entity for an Apple + Operating System ("Apple OS-Developed Software"), including but not + limited to Apple and third party printer drivers, filters, and backends + for an Apple Operating System, that is linked to the CUPS imaging + library or based on any sample filters or backends provided with CUPS + shall not be considered to be a derivative work or collective work + based on the CUPS program and is exempt from the mandatory source code + release clauses of the GNU GPL. You may therefore distribute linked + combinations of the CUPS imaging library with Apple OS-Developed + Software without releasing the source code of the Apple OS-Developed + Software. You may also use sample filters and backends provided with + CUPS to develop Apple OS-Developed Software without releasing the + source code of the Apple OS-Developed Software.
      2. +
      3. An Apple Operating System means any operating system software + developed and/or marketed by Apple Computer, Inc., including but not + limited to all existing releases and versions of Apple's Darwin, Mac OS + X, and Mac OS X Server products and all follow-on releases and future + versions thereof.
      4. +
      5. This exception is only available for Apple OS-Developed Software and + does not apply to software that is distributed for use on other + operating systems.
      6. +
      7. All CUPS software that falls under this license exception have the + following text at the top of each source file:
        This file is + subject to the Apple OS-Developed Software exception.
      8. +
      +
    2. +
    3. OpenSSL Toolkit License Exception; +
        +
      1. Easy Software Products explicitly allows the compilation and + distribution of the CUPS software with the OpenSSL Toolkit.
      2. +
      +
    4. +
    +

    No developer is required to provide these exceptions in a derived + work.

    +

    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. Please contract Easy + Software Products for written permission to use them in derivative + products. 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 "pdftops" filter that is + based on the Xpdf 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:

    + + + +

    GNU GENERAL PUBLIC LICENSE

    +

    Version 2, June 1991

    +
    +Copyright 1989, 1991 Free Software Foundation, Inc.
    +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    +
    +Everyone is permitted to copy and distribute verbatim
    +copies of this license document, but changing it is not allowed.
    +
    +

    Preamble

    +

    The licenses for most software are designed to take away your freedom + to share and change it. By contrast, the GNU General Public License is + intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Library General Public License instead.) You can apply it to + your programs, too.

    +

    When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it in + new free programs; and that you know you can do these things.

    +

    To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it.

    +

    For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights.

    +

    We protect your rights with two steps: (1) copyright the software, + and (2) offer you this license which gives you legal permission to + copy, distribute and/or modify the software.

    +

    Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations.

    +

    Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all.

    +

    The precise terms and conditions for copying, distribution and + modification follow.

    +

    GNU GENERAL PUBLIC LICENSE +
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

    +
      +
    1. This License applies to any program or other work which contains a + notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". +

      Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + the Program is not restricted, and the output from the Program is + covered only if its contents constitute a work based on the Program + (independent of having been made by running the Program). Whether that + is true depends on what the Program does.

      +
    2. You may copy and distribute verbatim copies of the Program's source + code as you receive it, in any medium, provided that you conspicuously + and appropriately publish on each copy an appropriate copyright notice + and disclaimer of warranty; keep intact all the notices that refer to + this License and to the absence of any warranty; and give any other + recipients of the Program a copy of this License along with the + Program. +

      You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee.

      +
    3. You may modify your copy or copies of the Program or any portion of + it, thus forming a work based on the Program, and copy and distribute + such modifications or work under the terms of Section 1 above, provided + that you also meet all of these conditions: +
        +
      1. You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change.
      2. +
      3. 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.
      4. +
      5. 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.)
      6. +
      +

      These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote + it.

      +

      Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program.

      +

      In addition, mere aggregation of another work not based on the + Program with the Program (or with a work based on the Program) on a + volume of a storage or distribution medium does not bring the other + work under the scope of this License.

      +
    4. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: +
        +
      1. Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 + above on a medium customarily used for software interchange; or,
      2. +
      3. 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,
      4. +
      5. 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.)
      6. +
      +

      The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to control + compilation and installation of the executable. However, as a special + exception, the source code distributed need not include anything that + is normally distributed (in either source or binary form) with the + major components (compiler, kernel, and so on) of the operating system + on which the executable runs, unless that component itself accompanies + the executable.

      +

      If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent access + to copy the source code from the same place counts as distribution of + the source code, even though third parties are not compelled to copy + the source along with the object code.

      +
    5. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt otherwise + to copy, modify, sublicense or distribute the Program is void, and will + automatically terminate your rights under this License. However, + parties who have received copies, or rights, from you under this + License will not have their licenses terminated so long as such parties + remain in full compliance.
    6. +
    7. 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.
    8. +
    9. 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.
    10. +
    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 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.

      +
    12. 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.
    13. +
    14. 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.

      +
    15. 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.
    16. + + + + + + +
    +

    NO WARRANTY

    +
      +
    1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH + YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION.
    2. +
    3. 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.
    4. +
    +

    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.

    +

    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:

    +
      +
    1. The modified work must itself be a software library. +

      +
    2. You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. +

      +
    3. You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. +

      +
    4. 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.)

      +
    5. + + + +
    +

    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:

    +
      +
    1. 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.) +

      +
    2. 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. +

      +
    3. 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. +

      +
    4. Verify that the user has already received a copy of these materials + or that you have already sent this user a copy.
    5. + + + +
    +

    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:

    +
      +
    1. 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. +

      +
    2. 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.
    3. + +
    +

    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

    +

    B - Constants

    +

    This appendix lists all of the constants that are defined by the CUPS + API.

    +

    CUPS Constants

    +

    Version Number

    +

    The CUPS_VERSION 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.

    +

    Printer Capabilities

    +

    The CUPS_PRINTER constants represent capability bits for + printers and classes:

    +
      +
    • CUPS_PRINTER_LOCAL - Is a local printer or class.
    • +
    • CUPS_PRINTER_REMOTE - Is a remote printer or class.
    • +
    • CUPS_PRINTER_CLASS - Is a class.
    • +
    • CUPS_PRINTER_BW - Printer prints in black and white.
    • +
    • CUPS_PRINTER_COLOR - Printer prints in color.
    • +
    • CUPS_PRINTER_DUPLEX - Printer can print double-sided.
    • +
    • CUPS_PRINTER_STAPLE - Printer can staple output.
    • +
    • CUPS_PRINTER_COPIES - Printer can produce multiple + copies on its own.
    • +
    • CUPS_PRINTER_COLLATE - Printer can collate copies.
    • +
    • CUPS_PRINTER_PUNCH - Printer can punch holes in output.
    • +
    • CUPS_PRINTER_COVER - Printer can put covers on output.
    • +
    • CUPS_PRINTER_BIND - Printer can bind output.
    • +
    • CUPS_PRINTER_SORT - Printer can sort output.
    • +
    • CUPS_PRINTER_SMALL - Printer can print on media up to + 9x14 inches.
    • +
    • CUPS_PRINTER_MEDIUM - Printer can print on media from + 9x14 to 18x24 inches.
    • +
    • CUPS_PRINTER_LARGE - Printer can print on media larger + than 18x24 inches.
    • +
    • CUPS_PRINTER_VARIABLE - Printer can print on variable + or custom media sizes.
    • +
    • CUPS_PRINTER_IMPLICIT - Is an implicit class.
    • +
    • CUPS_PRINTER_OPTIONS - All of the printer capability + and option bits.
    • +
    +

    Encodings

    +

    CUPS defines the following character set encoding constants:

    +
      +
    • CUPS_US_ASCII - US ASCII character set.
    • +
    • CUPS_UTF_8 - UTF-8 encoding of Unicode.
    • +
    • CUPS_ISO8859_1 - ISO-8859-1 character set.
    • +
    • CUPS_ISO8859_2 - ISO-8859-2 character set.
    • +
    • CUPS_ISO8859_3 - ISO-8859-3 character set.
    • +
    • CUPS_ISO8859_4 - ISO-8859-4 character set.
    • +
    • CUPS_ISO8859_5 - ISO-8859-5 character set.
    • +
    • CUPS_ISO8859_6 - ISO-8859-6 character set.
    • +
    • CUPS_ISO8859_7 - ISO-8859-7 character set.
    • +
    • CUPS_ISO8859_8 - ISO-8859-8 character set.
    • +
    • CUPS_ISO8859_9 - ISO-8859-9 character set.
    • +
    • CUPS_ISO8859_10 - ISO-8859-10 character set.
    • +
    • CUPS_ISO8859_13 - ISO-8859-13 character set.
    • +
    • CUPS_ISO8859_14 - ISO-8859-14 character set.
    • +
    • CUPS_ISO8859_15 - ISO-8859-15 character set.
    • +
    • CUPS_WINDOWS_874 - Windows code page 874.
    • +
    • CUPS_WINDOWS_1250 - Windows code page 1250.
    • +
    • CUPS_WINDOWS_1251 - Windows code page 1251.
    • +
    • CUPS_WINDOWS_1252 - Windows code page 1252.
    • +
    • CUPS_WINDOWS_1253 - Windows code page 1253.
    • +
    • CUPS_WINDOWS_1254 - Windows code page 1254.
    • +
    • CUPS_WINDOWS_1255 - Windows code page 1255.
    • +
    • CUPS_WINDOWS_1256 - Windows code page 1256.
    • +
    • CUPS_WINDOWS_1257 - Windows code page 1257.
    • +
    • CUPS_WINDOWS_1258 - Windows code page 1258.
    • +
    • CUPS_KOI8_R - Russian code page koi8-r.
    • +
    • CUPS_KOI8_U - Ukrainian code page koi8-r.
    • +
    +

    HTTP Constants

    +

    Limits

    +

    The following constants define the limits for strings:

    +
      +
    • HTTP_MAX_BUFFER - Size of socket buffer.
    • +
    • HTTP_MAX_HOST - Maximum length of hostname.
    • +
    • HTTP_MAX_URI - Maximum length of URI.
    • +
    • HTTP_MAX_VALUE - Maximum length of field values.
    • +
    +

    Status Codes

    +

    The following status codes can be returned by httpUpdate() +:

    +
      +
    • HTTP_ERROR - A network error occurred
    • +
    • HTTP_CONTINUE - Continue response from HTTP proxy
    • +
    • HTTP_OK - 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
    • +
    • HTTP_RESET_CONTENT - Content was reset/recreated
    • +
    • HTTP_PARTIAL_CONTENT - Only a partial file was + recieved/sent
    • +
    • HTTP_MULTIPLE_CHOICES - 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 - Bad request
    • +
    • HTTP_UNAUTHORIZED - Unauthorized to access host
    • +
    • HTTP_PAYMENT_REQUIRED - Payment required
    • +
    • HTTP_FORBIDDEN - Forbidden to access this URI
    • +
    • HTTP_NOT_FOUND - URI was not found
    • +
    • HTTP_METHOD_NOT_ALLOWED - Method is not allowed
    • +
    • HTTP_NOT_ACCEPTABLE - Not Acceptable
    • +
    • HTTP_PROXY_AUTHENTICATION - Proxy Authentication is + Required
    • +
    • HTTP_REQUEST_TIMEOUT - Request timed out
    • +
    • HTTP_CONFLICT - Request is self-conflicting
    • +
    • HTTP_GONE - Server has gone away
    • +
    • HTTP_LENGTH_REQUIRED - A content length or encoding is + required
    • +
    • HTTP_PRECONDITION - Precondition failed
    • +
    • HTTP_REQUEST_TOO_LARGE - Request entity too large
    • +
    • HTTP_URI_TOO_LONG - URI too long
    • +
    • HTTP_UNSUPPORTED_MEDIATYPE - The requested media type + is unsupported
    • +
    • HTTP_SERVER_ERROR - 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
    • +
    +

    Fields

    +

    The following fields are indices for each of the standard HTTP fields + in HTTP 1/1:

    +
      +
    • HTTP_FIELD_ACCEPT_LANGUAGE - Accept-Language
    • +
    • HTTP_FIELD_ACCEPT_RANGES - Accept-Ranges
    • +
    • HTTP_FIELD_AUTHORIZATION - Authorization
    • +
    • HTTP_FIELD_CONNECTION - Connection
    • +
    • HTTP_FIELD_CONTENT_ENCODING - Content-Encoding
    • +
    • HTTP_FIELD_CONTENT_LANGUAGE - Content-Language
    • +
    • HTTP_FIELD_CONTENT_LENGTH - Content-Length
    • +
    • HTTP_FIELD_CONTENT_LOCATION - Content-Location
    • +
    • HTTP_FIELD_CONTENT_MD5 - Content-MD5
    • +
    • HTTP_FIELD_CONTENT_RANGE - Content-Range
    • +
    • HTTP_FIELD_CONTENT_TYPE - Content-Type
    • +
    • HTTP_FIELD_CONTENT_VERSION - Content-Version
    • +
    • HTTP_FIELD_DATE - Date
    • +
    • HTTP_FIELD_HOST - Host
    • +
    • HTTP_FIELD_IF_MODIFIED_SINCE - If-Modified-Since
    • +
    • HTTP_FIELD_IF_UNMODIFIED_SINCE - If-Unmodified-Since
    • +
    • HTTP_FIELD_KEEP_ALIVE - Keep-Alive
    • +
    • HTTP_FIELD_LAST_MODIFIED - Last-Modified
    • +
    • HTTP_FIELD_LINK - Link
    • +
    • HTTP_FIELD_LOCATION - Location
    • +
    • HTTP_FIELD_RANGE - Range
    • +
    • HTTP_FIELD_REFERER - Referer
    • +
    • HTTP_FIELD_RETRY_AFTER - Retry-After
    • +
    • HTTP_FIELD_TRANSFER_ENCODING - Transfer-Encoding
    • +
    • HTTP_FIELD_UPGRADE - Upgrade
    • +
    • HTTP_FIELD_USER_AGENT - User-Agent
    • +
    • HTTP_FIELD_WWW_AUTHENTICATE - WWW-Authenticate
    • +
    +

    IPP Constants

    +

    Limits

    +

    The following constants define array limits for IPP data:

    +
      +
    • IPP_MAX_NAME - Maximum length of an attribute name
    • +
    • IPP_MAX_VALUES - Maximum number of set-of values that + can be read in a request.
    • +
    +

    Tags

    +
      +
    • IPP_TAG_ZERO - Wildcard tag value for searches; also + used to separate groups of attributes
    • +
    • IPP_TAG_OPERATION - Tag for values of type operation
    • +
    • IPP_TAG_JOB - Tag for values of type job
    • +
    • IPP_TAG_END - Tag for values of type end
    • +
    • IPP_TAG_PRINTER - Tag for values of type printer
    • +
    • IPP_TAG_UNSUPPORTED_GROUP - Tag for values of type + unsupported_group
    • +
    • IPP_TAG_UNSUPPORTED_VALUE - Tag for values of type + unsupported_value
    • +
    • IPP_TAG_DEFAULT - Tag for values of type default
    • +
    • IPP_TAG_UNKNOWN - Tag for values of type unknown
    • +
    • IPP_TAG_NOVALUE - Tag for values of type novalue
    • +
    • IPP_TAG_NOTSETTABLE - Tag for values of type + notsettable
    • +
    • IPP_TAG_DELETEATTR - Tag for values of type deleteattr
    • +
    • IPP_TAG_ANYVALUE - Tag for values of type anyvalue
    • +
    • IPP_TAG_INTEGER - Tag for values of type integer
    • +
    • IPP_TAG_BOOLEAN - Tag for values of type boolean
    • +
    • IPP_TAG_ENUM - Tag for values of type enum
    • +
    • IPP_TAG_STRING - Tag for values of type string
    • +
    • IPP_TAG_DATE - Tag for values of type date
    • +
    • IPP_TAG_RESOLUTION - Tag for values of type resolution
    • +
    • IPP_TAG_RANGE - Tag for values of type range
    • +
    • IPP_TAG_COLLECTION - Tag for values of type collection
    • +
    • IPP_TAG_TEXTLANG - Tag for values of type textlang
    • +
    • IPP_TAG_NAMELANG - Tag for values of type namelang
    • +
    • IPP_TAG_TEXT - Tag for values of type text
    • +
    • IPP_TAG_NAME - Tag for values of type name
    • +
    • IPP_TAG_KEYWORD - Tag for values of type keyword
    • +
    • IPP_TAG_URI - Tag for values of type uri
    • +
    • IPP_TAG_URISCHEME - Tag for values of type urischeme
    • +
    • IPP_TAG_CHARSET - Tag for values of type charset
    • +
    • IPP_TAG_LANGUAGE - Tag for values of type language
    • +
    • IPP_TAG_MIMETYPE - Tag for values of type mimetype
    • +
    +

    Resolution Units

    +

    The IPP_RES_PER_INCH and IPP_RES_PER_CM + constants specify dots per inch and dots per centimeter, respectively.

    +

    Finishings

    +

    The finishing values specify special finishing operations to be + performed on the job.

    +
      +
    • IPP_FINISH_NONE - Do no finishing
    • +
    • IPP_FINISH_STAPLE - Staple the job
    • +
    • IPP_FINISH_PUNCH - Punch the job
    • +
    • IPP_FINISH_COVER - Cover the job
    • +
    • IPP_FINISH_BIND - Bind the job
    • +
    +

    Orientations

    +

    The orientation values specify the orientation of the job.

    +
      +
    • IPP_PORTRAIT - No rotation
    • +
    • IPP_LANDSCAPE - 90 degrees counter-clockwise
    • +
    • IPP_REVERSE_LANDSCAPE - 90 degrees clockwise
    • +
    • IPP_REVERSE_PORTRAIT - 180 degrees
    • +
    +

    Qualities

    +

    The quality values specify the desired quality of the print.

    +
      +
    • IPP_QUALITY_DRAFT - Draft quality
    • +
    • IPP_QUALITY_NORMAL - Normal quality
    • +
    • IPP_QUALITY_HIGH - High quality
    • +
    +

    Job States

    +

    The job state values are used to represent the current job state.

    +
      +
    • IPP_JOB_PENDING - Job is pending
    • +
    • IPP_JOB_HELD - Job is held
    • +
    • IPP_JOB_PROCESSING - Job is processing
    • +
    • IPP_JOB_STOPPED - Job is stopped
    • +
    • IPP_JOB_CANCELLED - Job is cancelled
    • +
    • IPP_JOB_ABORTED - Job is aborted
    • +
    • IPP_JOB_COMPLETED - Job is completed
    • +
    +

    Printer States

    +

    The printer state values are used to represent the current printer + state.

    +
      +
    • IPP_PRINTER_IDLE - Printer is idle
    • +
    • IPP_PRINTER_PROCESSING - Printer is processing
    • +
    • IPP_PRINTER_STOPPED - Printer is stopped
    • +
    +

    Operations

    +

    The operation values represent the available IPP operations.

    +
      +
    • IPP_PRINT_JOB - Print a file
    • +
    • IPP_PRINT_URI - Print a URI
    • +
    • IPP_VALIDATE_JOB - Validate job attributes
    • +
    • IPP_CREATE_JOB - Create a new job
    • +
    • IPP_SEND_DOCUMENT - Send a document to a job
    • +
    • IPP_SEND_URI - Send a URI to a job
    • +
    • IPP_CANCEL_JOB - Cancel a job
    • +
    • IPP_GET_JOB_ATTRIBUTES - Get job attributes
    • +
    • IPP_GET_JOBS - Get a list of all jobs
    • +
    • IPP_GET_PRINTER_ATTRIBUTES - Get printer attributes
    • +
    • IPP_HOLD_JOB - Hold a pending job
    • +
    • IPP_RELEASE_JOB - Release a held job
    • +
    • IPP_RESTART_JOB - Restart a completed job
    • +
    • IPP_PAUSE_PRINTER - Pause a printer
    • +
    • IPP_RESUME_PRINTER - Restart a paused printer
    • +
    • IPP_PURGE_JOBS - Purge jobs from the queue
    • +
    • IPP_SET_PRINTER_ATTRIBUTES - Set printer attributes
    • +
    • IPP_SET_JOB_ATTRIBUTES - Set job attributes
    • +
    • IPP_GET_PRINTER_SUPPORTED_VALUES - Get printer + supported values
    • +
    • CUPS_GET_DEFAULT - Get the default destination
    • +
    • CUPS_GET_PRINTERS - Get a list of all printers
    • +
    • CUPS_ADD_PRINTER - Add or modify a printer
    • +
    • CUPS_DELETE_PRINTER - Delete a printer
    • +
    • CUPS_GET_CLASSES - Get a list of all classes
    • +
    • CUPS_ADD_CLASS - Add or modify a class
    • +
    • CUPS_DELETE_CLASS - Delete a class
    • +
    • CUPS_ACCEPT_JOBS - Accept jobs on a printer or class
    • +
    • CUPS_REJECT_JOBS - Reject jobs on a printer or class
    • +
    • CUPS_SET_DEFAULT - Set the default destination
    • +
    • CUPS_GET_DEVICES - Get a list of all devices
    • +
    • CUPS_GET_PPDS - Get a list of all PPDs
    • +
    • CUPS_MOVE_JOB - Move a job to a new destination
    • +
    +

    Status Codes

    +

    Status codes are returned by all IPP requests.

    +
      +
    • IPP_OK - Request completed with no errors
    • +
    • IPP_OK_SUBST - Request completed but some attribute + values were substituted
    • +
    • IPP_OK_CONFLICT - Request completed but some attributes + conflicted
    • +
    • IPP_BAD_REQUEST - The request was bad
    • +
    • IPP_FORBIDDEN - You don't have access to the resource
    • +
    • IPP_NOT_AUTHENTICATED - You are not authenticated for + the resource
    • +
    • IPP_NOT_AUTHORIZED - You not authorized to access the + resource
    • +
    • IPP_NOT_POSSIBLE - The requested operation cannot be + completed
    • +
    • IPP_TIMEOUT - A timeout occurred
    • +
    • IPP_NOT_FOUND - The resource was not found
    • +
    • IPP_GONE - The resource has gone away
    • +
    • IPP_REQUEST_ENTITY - The request was too large
    • +
    • IPP_REQUEST_VALUE - The request contained a value that + was unknown to the server
    • +
    • IPP_DOCUMENT_FORMAT - The document format is not + supported by the server
    • +
    • IPP_ATTRIBUTES - Required attributes are missing
    • +
    • IPP_URI_SCHEME - The URI scheme is not supported
    • +
    • IPP_CHARSET - The charset is not supported
    • +
    • IPP_CONFLICT - One or more attributes conflict
    • +
    • IPP_COMPRESSION_NOT_SUPPORTED - The specified + compression is not supported
    • +
    • IPP_COMPRESSION_ERROR - The compressed data contained + an error
    • +
    • IPP_DOCUMENT_FORMAT_ERROR - The document data contained + an error in it
    • +
    • IPP_DOCUMENT_ACCESS_ERROR - The remote document could + not be accessed
    • +
    • IPP_INTERNAL_ERROR - The server encountered an internal + error
    • +
    • IPP_OPERATION_NOT_SUPPORTED - The requested operation + is not supported
    • +
    • IPP_SERVICE_UNAVAILABLE - The requested service is + unavailable
    • +
    • IPP_VERSION_NOT_SUPPORTED - The IPP request version is + not supported
    • +
    • IPP_DEVICE_ERROR - The output device encountered an + error
    • +
    • IPP_TEMPORARY_ERROR - A temporary error occurred
    • +
    • IPP_NOT_ACCEPTING - The destination is not accepting + jobs
    • +
    • IPP_PRINTER_BUSY - The destination is busy
    • +
    • IPP_ERROR_JOB_CANCELLED - The requested job has been + cancelled
    • +
    • IPP_MULTIPLE_JOBS_NOT_SUPPORTED - The server does not + support multiple jobs
    • +
    +

    PPD Constants

    +

    PPD Format Version

    +

    The PPD_VERSION constant defines a floating point number + representing the newest format version that is supported by CUPS, + currently 4.3.

    +

    PPD User-Interface Types

    +

    Each printer option has a type associated with it:

    +
      +
    • PPD_UI_BOOLEAN - The user can turn this option on or + off
    • +
    • PPD_UI_PICKONE - The user can choose one option value + to use.
    • +
    • PPD_UI_PICKMANY - The user can choose zero or more + option values.
    • +
    +

    PPD Sections

    +

    Some options must be output before others, or in different sections + of the output document. The ppd_section_t enumeration + defines which section the option must be output in:

    +
      +
    • PPD_ORDER_ANY - The option can be output in any of the + document, page, or prolog sections of the document
    • +
    • PPD_ORDER_DOCUMENT - The option must be output in the + DocumentSetup section of the document
    • +
    • PPD_ORDER_EXIT - The option must be output before the + document
    • +
    • PPD_ORDER_JCL - The option must be output in the job + control section of the document
    • +
    • PPD_ORDER_PAGE - The option must be output in the + PageSetup section of the document
    • +
    • PPD_ORDER_PROLOG - The option must be output in the + Prolog section of the document
    • +
    +

    PPD Colorspaces

    +

    Each printer has a default colorspace:

    +
      +
    • PPD_CS_CMYK - The printer uses CMYK colors by default
    • +
    • PPD_CS_CMY - The printer uses CMY colors by default
    • +
    • PPD_CS_GRAY - The printer uses grayscale by default
    • +
    • PPD_CS_RGB - The printer uses RGB colors by default
    • +
    • PPD_CS_RGBK - The printer uses RGBK colors by default
    • +
    • PPD_CS_N - The printer uses a DeviceN colorspace by + default
    • +
    +

    Raster Constants

    +

    Raster Sync Words

    +

    The CUPS_RASTER_SYNC and CUPS_RASTER_REVSYNC + constants define the standard sync words at the beginning of each CUPS + raster file.

    +

    Raster Stream Modes

    +

    The CUPS_RASTER_READ and CUPS_RASTER_WRITE + constants are used with the +cupsRasterOpen() function to specify a stream for reading or + writing.

    +

    Raster Boolean Constants

    +

    The CUPS_FALSE and CUPS_TRUE constants + represent boolean values in the page header.

    +

    Raster Jog Values

    +

    The cups_jog_t enumeration defines constants for the Jog + page device dictionary variable:

    +
      +
    • CUPS_JOG_NONE - Do no jogging
    • +
    • CUPS_JOG_FILE - Jog pages after each file
    • +
    • CUPS_JOG_JOB - Jog pages after each job
    • +
    • CUPS_JOG_SET - Jog pages after each set of jobs
    • +
    +

    Raster Orientation Values

    +

    The cups_orient_t enumeration defines constants for the + Orientation page device dictionary variable:

    +
      +
    • CUPS_ORIENT_0 - Portrait orientation
    • +
    • CUPS_ORIENT_90 - Landscape orientation
    • +
    • CUPS_ORIENT_180 - Reverse-portrait orientation
    • +
    • CUPS_ORIENT_270 - Reverse-landscape orientation
    • +
    +

    Raster CutMedia Values

    +

    The cups_cut_t enumeration defines constants for the + CutMedia page device dictionary variable:

    +
      +
    • CUPS_CUT_NONE - Do no jogging
    • +
    • CUPS_CUT_FILE - Cut pages after each file
    • +
    • CUPS_CUT_JOB - Cut pages after each job
    • +
    • CUPS_CUT_SET - Cut pages after each set of jobs
    • +
    • CUPS_CUT_PAGE - Cut each page
    • +
    +

    Raster AdvanceMedia Values

    +

    The cups_advance_t enumeration defines constants for the + AdvanceMedia page device dictionary variable:

    +
      +
    • CUPS_ADVANCE_NONE - Do no jogging
    • +
    • CUPS_ADVANCE_FILE - Advance media after each file
    • +
    • CUPS_ADVANCE_JOB - Advance media after each job
    • +
    • CUPS_ADVANCE_SET - Advance media after each set of jobs
    • +
    • CUPS_ADVANCE_PAGE - Advance media for each page
    • +
    +

    Raster LeadingEdge Values

    +

    The cups_edge_t enumeration defines constants for the + LeadingEdge page device dictionary variable:

    +
      +
    • CUPS_EDGE_TOP - The top of the media is the leading + edge
    • +
    • CUPS_EDGE_RIGHT - The right of the media is the leading + edge
    • +
    • CUPS_EDGE_BOTTOM - The bottom of the media is the + leading edge
    • +
    • CUPS_EDGE_LEFT - The left of the media is the leading + edge
    • +
    +

    Raster Color Order Values

    +

    The cups_order_t enumeration defines the possible color + value orderings:

    +
      +
    • CUPS_ORDER_CHUNKED - CMYK CMYK CMYK
    • +
    • CUPS_ORDER_BANDED - CCC MMM YYY KKK
    • +
    • CUPS_ORDER_PLANAR - CCC ... MMM ... YYY ... KKK ...
    • +
    +

    Raster Colorspace Values

    +

    The cups_cspace_t enumeration defines the possible + colorspaces:

    +
      +
    • CUPS_CSPACE_W - White (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 - Metallic yellow (gold), metallic + magenta, metallic cyan, black
    • +
    • CUPS_CSPACE_GMCS - Metallic yellow (gold), metallic + magenta, metallic cyan, metallic grey (silver)
    • +
    • CUPS_CSPACE_WHITE - White pigment (black as white + pigment)
    • +
    • CUPS_CSPACE_GOLD - Gold foil (black as gold foil)
    • +
    • CUPS_CSPACE_SILVER - Silver foil (black as silver foil)
    • +
    +

    C - Structures

    +

    This appendix describes all of the structures that are defined by the + CUPS API.

    +

    CUPS Structures

    +

    CUPS Destinations

    +

    The CUPS destination structure (cups_dest_t) contains + information on a specific destination or instance: +

    + + + + + + + + +
    MemberTypeDescription
    namechar *The name of the printer or class.
    instancechar *The instance of the printer or + class; NULL for the primary instance.
    is_defaultint1 if the destination is set as + the default, 0 otherwise.
    num_optionsintThe number of options associated + with this destination.
    optionscups_option_t * +The options associated with this destination.
    +
    +

    +

    CUPS Jobs

    +

    The CUPS job structure (cups_job_t) contains information + on a specific job: +

    + + + + + + + + + + + + + + + +
    MemberTypeDescription
    idintThe job ID for this job.
    destchar *The destination for this job + (printer or class name).
    titlechar *The job-name for this job (title).
    userchar *The job-originating-user-name for + this job (username).
    formatchar *The document-format for this job + (MIME type string).
    stateipp_jstateThe current state of the job.
    sizeintThe size of this job in kilobytes.
    priorityintThe priority of this job from 1 to + 100 (50 is normal).
    completed_timetime_tThe time the job was + completed, or 0 if not yet completed.
    creation_timetime_tThe time the job was + queued.
    processing_timetime_tThe time the job started + printing.
    +
    +

    +

    CUPS Messages

    +

    The CUPS messages structure (cups_lang_t) contains the + character set, locale name, and messages array: +

    + + + + + + + + + +
    MemberTypeDescription
    nextcups_lang_t *Pointer to the next messages + structure in memory.
    usedintThe number of active users of this + messages structure.
    encodingcups_encoding_tThe character encoding + of the message strings.
    languagechar [16]The language/locale name.
    messageschar *[]The array of message strings.
    +
    +

    +

    CUPS Options

    +

    The CUPS option structure (cups_option_t) contains the + option name and string value: +

    + + + + + +
    MemberTypeDescription
    namechar *The name of the option.
    valuechar *The string value of the option.
    +
    +

    +

    Networking Structures

    +

    HTTP State

    +

    The HTTP state structure (http_t) contains the current + state of a HTTP request or response: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    fdintThe socket for the HTTP connection.
    blockingint1 if the HTTP functions should + block, 0 if not.
    errorintThe last OS error that occurred on the + socket.
    activitytime_tThe last time the HTTP + connection was used.
    statehttp_state_tThe current HTTP + request/response state.
    statusintThe last HTTP status seen.
    versionhttp_version_tThe HTTP protocol version + in use.
    keep_alivehttp_keep_alive_tWhether or not to + use Keep-Alive
    hostaddrstruct sockaddr_inThe IPv4 address of + the HTTP server.
    hostnamechar []The hostname of the HTTP + server.
    fieldschar [][]The string values of all HTTP + request/response fields.
    datachar *Current byte in data buffer.
    data_encodinghttp_encoding_tThe transfer + encoding for the request/response.
    data_remainingintThe number of bytes remaining + in the current request, response, or chunk.
    usedintThe number of bytes that are used in + the buffer.
    bufferchar []The read/write buffer.
    auth_typeintThe type of authentication in use.
    md5_statemd5_state_tThe current MD5 digest + state.
    noncechar []The nonce value for Digest + authentication.
    nonce_countintThe nonce count value.
    tlsvoid *A pointer to private encryption data.
    encryptionhttp_encryption_tThe current + encryption mode.
    +
    +

    +

    IPP State

    +

    The IPP state structure (ipp_t) contains the current + state of a IPP request or response: +

    + + + +
    MemberTypeDescription
    +
    +

    +

    Raster Structures

    +

    Raster Page Header

    +

    The raster page header (cups_raster_header_t) consists + of the PostScript page device dictionary for the page: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    MediaClasschar[64]The media class name
    MediaColorchar[64]The media color name
    MediaTypechar[64]The media type name
    OutputTypechar[64]The output type name
    AdvanceDistanceunsignedThe distance to advance + the media in points
    AdvanceMediacups_adv_tWhen to advance the + media
    Collatecups_bool_tWhether or not to produce + collated copies
    CutMediacups_cut_tWhen to cut the media
    Duplexcups_bool_tWhether or not to print on + both sides of the paper
    HWResolutionunsigned[2]The resolution of the + page image in pixels per inch; the HWResolution[0] represents the + horizontal resolution and HWResolution[1] represents the vertical + resolution
    ImagingBoundingBoxunsigned[4]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)
    InsertSheetcups_bool_tWhether or not to insert + a sheet before this page
    Jogcups_jog_tWhen to jog copies of the page
    LeadingEdgecups_edge_tThe leading edge of the + page
    Marginsunsigned[2]The lower-lefthand margin of + the page in points
    ManualFeedcups_bool_tWhether or not to + manually feed the page
    MediaPositionunsignedThe input slot number to + use
    MediaWeightunsignedThe weight of the output + media in grams/m2
    MirrorPrintcups_bool_tWhether or not to mirror + the print
    NegativePrintcups_bool_tWhether or not to + invert the print
    NumCopiesunsignedThe number of copies to + produce
    Orientationcups_orient_tThe orientation of the + page image
    OutputFaceUpcups_bool_tWhether or not to + output the page face up
    PageSizeunsigned[2]The width and height of the + page in points
    Separationscups_bool_tWhether or not to output + separations
    TraySwitchcups_bool_tWhether or not to + automatically switch trays for the requested media size/type
    Tumblecups_bool_tWhether or not to rotate the + back side of the page
    cupsWidthunsignedThe width of the page image + in pixels
    cupsHeightunsignedThe height of the page image + in pixels
    cupsMediaTypeunsignedThe device-specific media + type code
    cupsBitsPerColorunsignedThe number of bits per + color
    cupsBitsPerPixelunsignedThe number of bits per + pixel
    cupsBytesPerLineunsignedThe number of bytes + per line of image data
    cupsColorOrdercups_order_tThe order of color + values
    cupsColorSpacecups_cspace_tThe type of color + values
    cupsCompressionunsignedThe device-specific + compression code
    cupsRowCountunsignedThe device-specific row + count
    cupsRowFeedunsignedThe device-specific row + feed
    cupsRowStepunsignedThe device-specific row + step
    +
    +

    +

    D - Functions

    +

    This appendix provides a reference for all of the CUPS API functions. + +

    +

    cupsAddDest()

    +

    Usage

    +
    +int
    +cupsAddDest(const char  *name,
    +            const char  *instance,
    +            int         num_dests,
    +	    cups_dest_t **dests);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    nameThe name of the destination.
    instanceThe instance of the destination, or NULL for + the primary instance.
    num_destsThe number of destinations in the array.
    destA pointer to the destination array pointer.
    +
    +

    Returns

    +

    The new number of destinations in the array.

    +

    Description

    +

    cupsAddDest() adds the named destination to the + destination array if it does not already exist.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +
    +
    +num_dests = cupsAddDests("foo", "bar", num_dests, &dests);
    +
    +

    See Also

    +

    cupsFreeDests(), + cupsGetDest(), +cupsGetDests() + +

    +

    cupsAddOption()

    +

    Usage

    +
    +int
    +cupsAddOption(const char    *name,
    +              const char    *value,
    +              int           num_options,
    +	      cups_option_t **options);
    +
    +

    Arguments

    +
    + + + + + + + +
    ArgumentDescription
    nameThe name of the option.
    valueThe value of the option.
    num_optionsNumber of options currently in the array.
    optionsPointer to the options array.
    +
    +

    Returns

    +

    The new number of options.

    +

    Description

    +

    cupsAddOption() adds an option to the specified array.

    +

    Example

    +
    +#include <cups.h>
    +
    +...
    +
    +/* Declare the options array */
    +int           num_options;
    +cups_option_t *options;
    +
    +/* Initialize the options array */
    +num_options = 0;
    +options     = (cups_option_t *)0;
    +
    +/* Add options using cupsAddOption() */
    +num_options = cupsAddOption("media", "letter", num_options, &options);
    +num_options = cupsAddOption("resolution", "300dpi", num_options, &options);
    +
    +

    See Also

    + cupsEncodeOptions(), + cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + + +

    cupsCancelJob()

    +

    Usage

    +
    +int
    +cupsCancelJob(const char *dest,
    +              int        job);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    destPrinter or class name
    jobJob ID
    +
    +

    Returns

    +

    1 on success, 0 on failure. On failure the error can be found by + calling cupsLastError().

    +

    Description

    +

    cupsCancelJob() cancels the specifies job.

    +

    Example

    +
    +#include <cups.h>
    +
    +cupsCancelJob("LaserJet", 1);
    +
    +

    See Also

    +

    cupsLastError(), + cupsPrintFile(), +cupsPrintFiles() + +

    +

    cupsDoFileRequest()

    +

    Usage

    +
    +ipp_t *
    +cupsDoFileRequest(http_t     *http,
    +                  ipp_t      *request,
    +                  const char *resource,
    +		  const char *filename);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    httpHTTP connection to server.
    requestIPP request data.
    resourceHTTP resource name for POST.
    filenameFile to send with POST request (NULL + pointer if none.)
    +
    +

    Returns

    +

    IPP response data or NULL if the request fails. On + failure the error can be found by calling +cupsLastError().

    +

    Description

    +

    cupsDoFileRequest() does a HTTP POST request and + provides the IPP request and optionally the contents of a file to the + IPP server. It also handles resubmitting the request and performing + password authentication as needed.

    +

    Example

    +
    +#include <cups.h>
    +
    +http_t      *http;
    +cups_lang_t *language;
    +ipp_t       *request;
    +ipp_t       *response;
    +
    +...
    +
    +/* Get the default language */
    +language = cupsLangDefault();
    +
    +/* Create a new IPP request */
    +request  = ippNew();
    +
    +request->request.op.operation_id = IPP_PRINT_FILE;
    +request->request.op.request_id   = 1;
    +
    +/* Add required attributes */
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
    +             "attributes-charset", NULL, cupsLangEncoding(language));
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
    +             "attributes-natural-language", NULL,
    +             language != NULL ? language->language : "C");
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    +             NULL, "ipp://hostname/resource");
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
    +             NULL, cupsUser());
    +
    +/* Do the request... */
    +response = cupsDoFileRequest(http, request, "/resource", "filename.txt");
    +
    +

    See Also

    +

    cupsLangDefault(), + cupsLangEncoding(), +cupsUser(), httpConnect() +, ippAddString(), + ippNew() + +

    +

    cupsDoRequest()

    +

    Usage

    +
    +ipp_t *
    +cupsDoRequest(http_t *http,
    +              ipp_t *request,
    +              const char *resource);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    httpHTTP connection to server.
    requestIPP request data.
    resourceHTTP resource name for POST.
    +
    +

    Returns

    +

    IPP response data or NULL if the request fails. On + failure the error can be found by calling +cupsLastError().

    +

    Description

    +

    cupsDoRequest() does a HTTP POST request and provides + the IPP request to the IPP server. It also handles resubmitting the + request and performing password authentication as needed.

    +

    Example

    +
    +#include <cups.h>
    +
    +http_t      *http;
    +cups_lang_t *language;
    +ipp_t       *request;
    +ipp_t       *response;
    +
    +...
    +
    +/* Get the default language */
    +language = cupsLangDefault();
    +
    +/* Create a new IPP request */
    +request  = ippNew();
    +
    +request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
    +request->request.op.request_id   = 1;
    +
    +/* Add required attributes */
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
    +             "attributes-charset", NULL, cupsLangEncoding(language));
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
    +             "attributes-natural-language", NULL,
    +             language != NULL ? language->language : "C");
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    +             NULL, "ipp://hostname/resource");
    +
    +/* Do the request... */
    +response = cupsDoRequest(http, request, "/resource");
    +
    +

    See Also

    +

    cupsLangDefault(), + cupsLangEncoding(), +cupsUser(), httpConnect() +, ippAddString(), + ippNew() + +

    +

    cupsEncodeOptions()

    +

    Usage

    +
    +void
    +cupsEncodeOptions(ipp_t         *ipp,
    +                  int           num_options,
    +		  cups_option_t *options);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    ippThe IPP request.
    num_optionsThe number of options.
    optionsThe options.
    +
    +

    Description

    +

    cupsEncodeOptions() encodes all of the options in the + specified array as IPP attributes and adds them to the IPP request.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +ipp_t         *ipp;
    +int           num_options;
    +cups_option_t *options;
    +
    +
    +cupsEncodeOptions(ipp, num_options, options);
    +
    +

    See Also

    +

    cupsAddOption(), + cupsParseOptions(), ippNew() + + +

    +

    cupsEncryption()

    +

    Usage

    +
    +http_encryption_t
    +cupsEncryption(void);
    +
    +

    Returns

    +

    The current encryption setting.

    +

    Description

    +

    cupsEncryption() returns the current encryption setting + for IPP requests such as printing.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +http_t *http;
    +
    +printf("The current encryption setting is %d.\n", cupsEncryption());
    +
    +http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
    +
    +

    See Also

    +

    cupsServer(), + httpConnectEncrypt(), +ippPort() + +

    +

    cupsFreeDests()

    +

    Usage

    +
    +void
    +cupsFreeDests(int         num_dests,
    +              cups_dest_t *dests);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    num_destsThe number of destinations in the array.
    destsThe destination array.
    +
    +

    Description

    +

    cupsFreeDests() frees a destination array that was + created using cupsGetDests().

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *dest;
    +
    +num_dests = cupsGetDests(&dests);
    +dest      = cupsGetDest(NULL, NULL, num_dests, dests);
    +
    +if (dest)
    +  printf("The default destination is %s\n", dest->name);
    +else
    +  puts("No default destination.");
    +
    +cupsFreeDests(num_dests, dests);
    +
    +

    See Also

    +

    cupsGetDest(), + cupsGetDests() + +

    +

    cupsFreeJobs()

    +

    Usage

    +
    +void
    +cupsFreeJobs(int        num_jobs,
    +             cups_job_t *jobs);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    num_jobsThe number of jobs.
    jobsThe job array.
    +
    +

    Description

    +

    cupsFreeJobs() frees an array of print jobs created by + the cupsGetJobs() function.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int        i;
    +int        num_jobs;
    +cups_job_t *jobs;
    +
    +
    +num_jobs = cupsGetJobs(&jobs, NULL, 0, 0);
    +
    +printf("%d active job(s):\n", num_jobs);
    +for (i = 0; i < num_jobs; i ++)
    +  printf("%-16.16s %-6d %-12.12s %s (%s)\n", jobs[i].dest, jobs[i].id,
    +         jobs[i].user, jobs[i].title,
    +	 jobs[i].state != IPP_JOB_PENDING ? "printing" : "pending");
    +
    +cupsFreeJobs(num_jobs, jobs);
    +
    +

    See Also

    +

    cupsGetJobs(), + cupsGetDests() + +

    +

    cupsFreeOptions()

    +

    Usage

    +
    +void
    +cupsFreeOptions(int           num_options,
    +                cups_option_t *options);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    num_optionsNumber of options in array.
    optionsPointer to options array.
    +
    +

    Description

    +

    cupsFreeOptions() frees all memory associated with the + option array specified.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +
    +...
    +
    +cupsFreeOptions(num_options, options);
    +
    +

    See Also

    +

    cupsAddOption(), + cupsEncodeOptions(), +cupsGetOption(), +cupsMarkOptions(), +cupsParseOptions() + +

    +

    cupsGetClasses()

    +

    Usage

    +
    +int
    +cupsGetClasses(char ***classes);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    classesPointer to character pointer array.
    +
    +

    Returns

    +

    The number of printer classes available.

    +

    Description

    +

    cupsGetClasses() gets a list of the available printer + classes. The returned array should be freed using the free() + when it is no longer needed.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int  i;
    +int  num_classes;
    +char **classes;
    +
    +...
    +
    +num_classes = cupsGetClasses(
    +
    +...
    +
    +if (num_classes > 0)
    +{
    +  for (i = 0; i < num_classes; i ++)
    +    free(classes[i]);
    +
    +  free(classes);
    +}
    +
    +

    See Also

    +

    cupsGetDefault(), + cupsGetPrinters() + +

    +

    cupsGetDefault()

    +

    Usage

    +
    +const char *
    +cupsGetDefault(void);
    +
    +

    Returns

    +

    A pointer to the default destination.

    +

    Description

    +

    cupsGetDefault() gets the default destination printer or + class. The default destination is stored in a static string and will be + overwritten (usually with the same value) after each call.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +printf("The default destination is %s\n", cupsGetDefault());
    +
    +

    See Also

    +

    cupsGetClasses(), + cupsGetPrinters() + +

    +

    cupsGetDest()

    +

    Usage

    +
    +cups_dest_t *
    +cupsGetDest(const char  *name,
    +            const char  *instance,
    +            int         num_dests,
    +            cups_dest_t *dests);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    nameThe name of the destination, or NULL for the + default destination.
    instanceThe instance of the destination, or NULL for + the primary instance.
    num_destsThe number of destinations.
    destsThe destination array.
    +
    +

    Returns

    +

    A pointer to the specified destination, or NULL if none exists.

    +

    Description

    +

    cupsGetDest() finds the specified destination in the + array of destinations created by the cupsGetDests() + function.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *dest;
    +
    +num_dests = cupsGetDests(&dests);
    +dest      = cupsGetDest(NULL, NULL, num_dests, dests);
    +
    +if (dest)
    +  printf("The default destination is %s\n", dest->name);
    +else
    +  puts("No default destination.");
    +
    +cupsFreeDests(num_dests, dests);
    +
    +

    See Also

    +

    cupsGetDests(), + cupsGetJobs() + +

    +

    cupsGetDests()

    +

    Usage

    +
    +int
    +cupsGetDests(cups_dest_t **dests);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    destsA pointer to a destination array pointer.
    +
    +

    Returns

    +

    The number of available destinations.

    +

    Description

    +

    cupsGetDests() creates an array of available + destinations that the user can print to. The array should be freed + using the cupsFreeDests() function.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *dest;
    +
    +num_dests = cupsGetDests(&dests);
    +dest      = cupsGetDest(NULL, NULL, num_dests, dests);
    +
    +if (dest)
    +  printf("The default destination is %s\n", dest->name);
    +else
    +  puts("No default destination.");
    +
    +cupsFreeDests(num_dests, dests);
    +
    +

    See Also

    +

    cupsFreeDests(), + cupsGetDest(), +cupsGetJobs() + +

    +

    cupsGetJobs()

    +

    Usage

    +
    +int
    +cupsGetJobs(cups_job_t **jobs,
    +            const char *dest,
    +            int        myjobs,
    +            int        completed);
    +
    +

    Arguments

    +
    + + + + + + + +
    ArgumentDescription
    jobsA pointer to the job array pointer.
    destThe destination name, or NULL if jobs for all + destinations are requested.
    myjobs1 if only those jobs submitted by the current +cupsUser() should be returned, 0 for jobs submitted by all users.
    completed1 if only completed jobs should be returned, 0 + if only pending/processing jobs should be returned.
    +
    +

    Returns

    +

    The number of jobs.

    +

    Description

    +

    cupsGetJobs() creates an array of print jobs based on + the arguments supplied in the function call. The returned array should + be freed using the cupsFreeJobs() function.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int        i;
    +int        num_jobs;
    +cups_job_t *jobs;
    +
    +
    +num_jobs = cupsGetJobs(&jobs, NULL, 0, 0);
    +
    +printf("%d active job(s):\n", num_jobs);
    +for (i = 0; i < num_jobs; i ++)
    +  printf("%-16.16s %-6d %-12.12s %s (%s)\n", jobs[i].dest, jobs[i].id,
    +         jobs[i].user, jobs[i].title,
    +	 jobs[i].state != IPP_JOB_PENDING ? "printing" : "pending");
    +
    +cupsFreeJobs(num_jobs, jobs);
    +
    +

    See Also

    +

    cupsFreeJobs(), + cupsGetDests() + +

    +

    cupsGetOption()

    +

    Usage

    +
    +const char *
    +cupsGetOption(const char    *name,
    +              int           num_options,
    +              cups_option_t *options);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    nameThe name of the option.
    num_optionsThe number of options in the array.
    optionsThe options array.
    +
    +

    Returns

    +

    A pointer to the option values or NULL if the option is + not defined.

    +

    Description

    +

    cupsGetOption() returns the first occurrence of the + named option. If the option is not included in the options array then a + NULL pointer is returned.

    +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +const char    *media;
    +
    +...
    +
    +media = cupsGetOption("media", num_options, options);
    +
    +

    See Also

    +

    cupsAddOption(), + cupsEncodeOptions(), +cupsFreeOptions(), +cupsMarkOptions(), +cupsParseOptions() + +

    +

    cupsGetPassword()

    +

    Usage

    +
    +const char *
    +cupsGetPassword(const char *prompt);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    promptThe prompt to display to the user.
    +
    +

    Returns

    +

    A pointer to the password that was entered or NULL if no + password was entered.

    +

    Description

    +

    cupsGetPassword() displays the prompt string and asks + the user for a password. The password text is not echoed to the user.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +char *password;
    +
    +...
    +
    +password = cupsGetPassword("Please enter a password:");
    +
    +

    See Also

    +

    cupsServer(), + cupsSetPasswordCB(), +cupsSetServer(), cupsSetUser() +, cupsUser() + +

    +

    cupsGetPPD()

    +

    Usage

    +
    +const char *
    +cupsGetPPD(const char *printer);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    printerThe name of the printer.
    +
    +

    Returns

    +

    The name of a temporary file containing the PPD file or NULL + if the printer cannot be located or does not have a PPD file.

    +

    Description

    +

    cupsGetPPD() gets a copy of the PPD file for the named + printer. The printer name can be of the form "printer" or + "printer@hostname".

    +

    You should remove (unlink) the PPD file after you are done using it. + The filename is stored in a static buffer and will be overwritten with + each call to cupsGetPPD().

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +char *ppd;
    +
    +...
    +
    +ppd = cupsGetPPD("printer@hostname");
    +
    +...
    +
    +unlink(ppd);
    +
    + + +

    cupsGetPrinters()

    +

    Usage

    +
    +int
    +cupsGetPrinters(char ***printers);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    printersPointer to character pointer array.
    +
    +

    Returns

    +

    The number of printer printers available.

    +

    Description

    +

    cupsGetPrinters() gets a list of the available printers. + The returned array should be freed using the free() when + it is no longer needed.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int  i;
    +int  num_printers;
    +char **printers;
    +
    +...
    +
    +num_printers = cupsGetPrinters(
    +
    +...
    +
    +if (num_printers > 0)
    +{
    +  for (i = 0; i < num_printers; i ++)
    +    free(printers[i]);
    +
    +  free(printers);
    +}
    +
    +

    See Also

    +

    cupsGetClasses() + cupsGetDefault() + +

    +

    cupsLangDefault()

    +

    Usage

    +
    +const char *
    +cupsLangDefault(void);
    +
    +

    Returns

    +

    A pointer to the default language structure.

    +

    Description

    +

    cupsLangDefault() returns a language structure for the + default language. The default language is defined by the LANG + environment variable. If the specified language cannot be located then + the POSIX (English) locale is used.

    +

    Call cupsLangFree() to free any memory associated with + the language structure when you are done.

    +

    Example

    +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +...
    +
    +language = cupsLangDefault();
    +
    +...
    +
    +cupsLangFree(language);
    +
    +

    See Also

    +

    cupsLangEncoding(), + cupsLangFlush(), +cupsLangFree(), cupsLangGet() +, cupsLangString() + +

    +

    cupsLangEncoding()

    +

    Usage

    +
    +char *
    +cupsLangEncoding(cups_lang_t *language);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    languageThe language structure.
    +
    +

    Returns

    +

    A pointer to the encoding string.

    +

    Description

    +

    cupsLangEncoding() returns the language encoding used + for the specified language, e.g. "iso-8859-1", "utf-8", etc.

    +

    Example

    +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +char        *encoding;
    +...
    +
    +language = cupsLangDefault();
    +encoding = cupsLangEncoding(language);
    +...
    +
    +cupsLangFree(language);
    +
    +

    See Also

    +

    cupsLangDefault(), + cupsLangFlush(), +cupsLangFree(), cupsLangGet() +, cupsLangString() + +

    +

    cupsLangFlush()

    +

    Usage

    +
    +void
    +cupsLangFlush(void);
    +
    +

    Description

    +

    cupsLangFlush() frees all language structures that have + been allocated.

    +

    Example

    +
    +#include <cups/language.h>
    +
    +...
    +
    +cupsLangFlush();
    +
    +

    See Also

    +

    cupsLangDefault(), + cupsLangEncoding(), +cupsLangFree(), cupsLangGet() +, cupsLangString() + +

    +

    cupsLangFree()

    +

    Usage

    +
    +void
    +cupsLangFree(cups_lang_t *language);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    languageThe language structure to free.
    +
    +

    Description

    +

    cupsLangFree() frees the specified language structure.

    +

    Example

    +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +...
    +
    +cupsLangFree(language);
    +
    +

    See Also

    +

    cupsLangDefault(), + cupsLangEncoding(), +cupsLangFlush(), cupsLangGet() +, cupsLangString() + +

    +

    cupsLangGet()

    +

    Usage

    +
    +cups_lang_t *
    +cupsLangGet(const char *name);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    nameThe name of the locale.
    +
    +

    Returns

    +

    A pointer to a language structure.

    +

    Description

    +

    cupsLangGet() returns a language structure for the + specified locale. If the locale is not defined then the POSIX (English) + locale is substituted.

    +

    Example

    +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +
    +...
    +
    +language = cupsLangGet("fr");
    +
    +...
    +
    +cupsLangFree(language);
    +
    +

    See Also

    +

    cupsLangDefault(), + cupsLangEncoding(), +cupsLangFlush(), cupsLangFree() +, cupsLangString() + +

    +

    cupsLangString()

    +

    Usage

    +
    +char *
    +cupsLangString(cups_lang_t *language,
    +               int         message);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    languageThe language to query.
    messageThe message number.
    +
    +

    Returns

    +

    A pointer to the message string or NULL if the message + is not defined.

    +

    Description

    +

    cupsLangString() returns a pointer to the specified + message string in the specified language.

    +

    Example

    +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +char        *s;
    +...
    +
    +language = cupsLangGet("fr");
    +
    +s = cupsLangString(language, CUPS_MSG_YES);
    +
    +...
    +
    +cupsLangFree(language);
    +
    +

    See Also

    +

    cupsLangDefault(), + cupsLangEncoding(), +cupsLangFlush(), cupsLangFree() +, cupsLangGet() + +

    +

    cupsLastError()

    +

    Usage

    +
    +ipp_status_t
    +cupsLastError(void);
    +
    +

    Returns

    +

    An enumeration containing the last IPP error.

    +

    Description

    +

    cupsLastError() returns the last IPP error that + occurred. If no error occurred then it will return IPP_OK + or IPP_OK_CONFLICT.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +ipp_status_t status;
    +
    +...
    +
    +status = cupsLastError();
    +
    +

    See Also

    +

    cupsCancelJob(), + cupsPrintFile() + +

    +

    cupsMarkOptions()

    +

    Usage

    +
    +int
    +cupsMarkOptions(ppd_file_t    *ppd,
    +                int           num_options,
    +                cups_option_t *options);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    ppdThe PPD file to mark.
    num_optionsThe number of options in the options array.
    optionsA pointer to the options array.
    +
    +

    Returns

    +

    The number of conflicts found.

    +

    Description

    +

    cupsMarkOptions() marks options in the PPD file. It also + handles mapping of IPP option names and values to PPD option names.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +ppd_file_t    *ppd;
    +
    +...
    +
    +cupsMarkOptions(ppd, num_options, options);
    +
    +

    See Also

    +

    cupsAddOption(), + cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + +

    +

    cupsParseOptions()

    +

    Usage

    +
    +int
    +cupsParseOptions(const char    *arg,
    +                 int           num_options,
    +                 cups_option_t **options);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    argThe string containing one or more options.
    num_optionsThe number of options in the options array.
    optionsA pointer to the options array pointer.
    +
    +

    Returns

    +

    The new number of options in the array.

    +

    Description

    +

    cupsParseOptions() parses the specifies string for one + or more options of the form "name=value", "name", or "noname". It can + be called multiple times to combine the options from several strings.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +
    +...
    +
    +num_options = 0;
    +options     = (cups_option_t *)0;
    +num_options = cupsParseOptions(argv[5], num_options, &options);
    +
    +

    See Also

    +

    cupsAddOption(), + cupsFreeOptions(), +cupsGetOption(), +cupsMarkOptions() + +

    +

    cupsPrintFile()

    +

    Usage

    +
    +int
    +cupsPrintFile(const char    *printer,
    +              const char    *filename,
    +              const char    *title,
    +	      int           num_options,
    +	      cups_option_t *options);
    +
    +

    Arguments

    +
    + + + + + + + + +
    ArgumentDescription
    printerThe printer or class to print to.
    filenameThe file to print.
    titleThe job title.
    num_optionsThe number of options in the options array.
    optionsA pointer to the options array.
    +
    +

    Returns

    +

    The new job ID number or 0 on error.

    +

    Description

    +

    cupsPrintFile() sends a file to the specified printer or + class for printing. If the job cannot be printed the error code can be + found by calling cupsLastError().

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +int           jobid;
    +
    +...
    +
    +jobid = cupsPrintFile("printer@hostname", "filename.ps", "Job Title",
    +                      num_options, options);
    +
    +

    See Also

    +

    cupsCancelJob(), + cupsLastError(), +cupsPrintFiles() + +

    +

    cupsPrintFiles()

    +

    Usage

    +
    +int
    +cupsPrintFiles(const char    *printer,
    +               int           num_files,
    +               const char    **files,
    +               const char    *title,
    +	       int           num_options,
    +	       cups_option_t *options);
    +
    +

    Arguments

    +
    + + + + + + + + + +
    ArgumentDescription
    printerThe printer or class to print to.
    num_filesThe number of files to print.
    filesThe files to print.
    titleThe job title.
    num_optionsThe number of options in the options array.
    optionsA pointer to the options array.
    +
    +

    Returns

    +

    The new job ID number or 0 on error.

    +

    Description

    +

    cupsPrintFiles() sends multiple files to the specified + printer or class for printing. If the job cannot be printed the error + code can be found by calling cupsLastError().

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +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);
    +
    +

    See Also

    +

    cupsCancelJob(), + cupsLastError(), +cupsPrintFile() + +

    +

    cupsRasterClose()

    +

    Usage

    +
    +void
    +cupsRasterClose(cups_raster_t *ras);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    rasThe raster stream to close.
    +
    +

    Description

    +

    cupsRasterClose() closes the specified raster stream.

    +

    Example

    +
    +#include <cups/raster.h>
    +
    +cups_raster_t *ras;
    +
    +...
    +
    +cupsRasterClose(ras);
    +
    +

    See Also

    +

    cupsRasterOpen(), + cupsRasterReadHeader(), + cupsRasterReadPixels(), + cupsRasterWriteHeader(), + cupsRasterWritePixels() + +

    +

    cupsRasterOpen()

    +

    Usage

    +
    +cups_raster_t *
    +cupsRasterOpen(int         fd,
    +               cups_mode_t mode);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    fdThe file descriptor to use.
    modeThe mode to use; CUPS_RASTER_READ or +CUPS_RASTER_WRITE.
    +
    +

    Returns

    +

    A pointer to a raster stream or NULL if there was an + error.

    +

    Description

    +

    cupsRasterOpen() opens a raster stream for reading or + writing.

    +

    Example

    +
    +#include <cups/raster.h>
    +
    +cups_raster_t *ras;
    +
    +...
    +
    +ras = cupsRasterOpen(0, CUPS_RASTER_READ);
    +
    +

    See Also

    +

    cupsRasterClose(), + cupsRasterReadHeader(), + cupsRasterReadPixels(), + cupsRasterWriteHeader(), + cupsRasterWritePixels() + +

    +

    cupsRasterReadHeader()

    +

    Usage

    +
    +unsigned
    +cupsRasterReadHeader(cups_raster_t      *ras,
    +                     cups_page_header_t *header);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    rasThe raster stream to read from.
    headerA pointer to a page header structure to read + into.
    +
    +

    Returns

    +

    1 on success, 0 on EOF or error.

    +

    Description

    +

    cupsRasterReadHeader() reads a page header from the + specified raster stream.

    +

    Example

    +
    +#include <cups/raster.h>
    +
    +int                  line;
    +cups_raster_t        *ras;
    +cups_raster_header_t header;
    +unsigned char        pixels[8192];
    +...
    +
    +while (cupsRasterReadHeader(ras, &header))
    +{
    +  ...
    +
    +  for (line = 0; line < header.cupsHeight; line ++)
    +  {
    +    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
    +
    +    ...
    +  }
    +}
    +
    +

    See Also

    +

    cupsRasterClose(), + cupsRasterOpen(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

    +

    cupsRasterReadPixels()

    +

    Usage

    +
    +unsigned
    +cupsRasterReadPixels(cups_raster_t *ras,
    +                     unsigned char *pixels,
    +		     unsigned      length);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    rasThe raster stream to read from.
    pixelsThe pointer to a pixel buffer.
    lengthThe number of bytes of pixel data to read.
    +
    +

    Returns

    +

    The number of bytes read or 0 on EOF or error.

    +

    Description

    +

    cupsRasterReadPixels() reads pixel data from the + specified raster stream.

    +

    Example

    +
    +#include <cups/raster.h>
    +
    +int                  line;
    +cups_raster_t        *ras;
    +cups_raster_header_t header;
    +unsigned char        pixels[8192];
    +...
    +
    +while (cupsRasterReadHeader(ras, &header))
    +{
    +  ...
    +
    +  for (line = 0; line < header.cupsHeight; line ++)
    +  {
    +    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
    +
    +    ...
    +  }
    +}
    +
    +

    See Also

    +

    cupsRasterClose(), + cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + +

    +

    cupsRasterWriteHeader()

    +

    Usage

    +
    +unsigned
    +cupsRasterWriteHeader(cups_raster_t      *ras,
    +                      cups_page_header_t *header);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    rasThe raster stream to write to.
    headerA pointer to the page header to write.
    +
    +

    Returns

    +

    1 on success, 0 on error.

    +

    Description

    +

    cupsRasterWriteHeader() writes the specified page header + to a raster stream.

    +

    Example

    +
    +#include <cups/raster.h>
    +
    +int                  line;
    +cups_raster_t        *ras;
    +cups_raster_header_t header;
    +unsigned char        pixels[8192];
    +...
    +
    +cupsRasterWriteHeader(ras, &header);
    +
    +for (line = 0; line < header.cupsHeight; line ++)
    +{
    +  ...
    +
    +  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
    +}
    +
    +

    See Also

    +

    cupsRasterClose(), + cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWritePixels() + +

    +

    cupsRasterWritePixels()

    +

    Usage

    +
    +unsigned
    +cupsRasterWritePixels(cups_raster_t *ras,
    +                      unsigned char *pixels,
    +		      unsigned      length);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    rasThe raster stream to write to.
    pixelsThe pixel data to write.
    lengthThe number of bytes to write.
    +
    +

    Returns

    +

    The number of bytes written.

    +

    Description

    +

    cupsRasterWritePixels() writes the specified pixel data + to a raster stream.

    +

    Example

    +
    +#include <cups/raster.h>
    +
    +int                  line;
    +cups_raster_t        *ras;
    +cups_raster_header_t header;
    +unsigned char        pixels[8192];
    +...
    +
    +cupsRasterWriteHeader(ras, &header);
    +
    +for (line = 0; line < header.cupsHeight; line ++)
    +{
    +  ...
    +
    +  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
    +}
    +
    +

    See Also

    +

    cupsRasterClose(), + cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader() + +

    +

    cupsServer()

    +

    Usage

    +
    +const char *
    +cupsServer(void);
    +
    +

    Returns

    +

    A pointer to the default server name.

    +

    Description

    +

    cupsServer() returns a pointer to the default server + name. The server name is stored in a static location and will be + overwritten with every call to cupsServer().

    +

    The default server is determined from the following locations:

    +
      +
    1. The CUPS_SERVER environment variable,
    2. +
    3. The ServerName directive in the client.conf + file,
    4. +
    5. The default host, "localhost".
    6. +
    +

    Example

    +
    +#include <cups/cups.h>
    +
    +const char *server;
    +
    +server = cupsServer();
    +
    +

    See Also

    +

    cupsGetPassword(), + cupsSetPasswordCB(), +cupsSetServer(), cupsSetUser() +, cupsUser() + +

    +

    cupsSetDests()

    +

    Usage

    +
    +void
    +cupsSetDests(int         num_dests,
    +             cups_dest_t *dests);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    num_destsNumber of destinations.
    destsArray of destinations.
    +
    +

    Description

    +

    cupsSetDests() saves the destination array to disk. If + the current UID is 0, the destinations are saved in the + /etc/cups/lpoptions file, otherwise they are saved in the + ~/.lpoptions file. This function is typically used to save the + default options and instances that are set by the user.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +
    +...
    +
    +cupsSetDests(num_dests, dests);
    +
    +

    See Also

    +

    cupsGetDests() + +

    +

    cupsSetEncryption()

    +

    Usage

    +
    +void
    +cupsSetEncryption(http_encryption_t encryption);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    encryptionThe type of encryption to use.
    +
    +

    Description

    +

    cupsSetEncryption() sets the default type of encryption + to use when connecting with the print server.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
    +
    +

    See Also

    +

    cupsEncryption() + +

    +

    cupsSetPasswordCB()

    +

    Usage

    +
    +void
    +cupsSetPasswordCB(const char *(*cb)(const char *prompt));
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    cbThe password callback function.
    +
    +

    Description

    +

    cupsSetPasswordCB() sets the callback function to use + when asking the user for a password. The callback function must accept + a single character string pointer (the prompt string) and return +NULL if the user did not enter a password string or a pointer to + the password string otherwise.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +const char *
    +my_password_cb(const char *prompt)
    +{
    +  return (getpass(prompt));
    +}
    +
    +...
    +
    +char *password;
    +
    +...
    +
    +cupsSetPasswordCB(my_password_cb);
    +password = cupsGetPassword("Please enter a password:");
    +
    +

    See Also

    +

    cupsServer(), + cupsSetServer(), +cupsSetUser(), cupsUser() + + +

    +

    cupsSetServer()

    +

    Usage

    +
    +void
    +cupsSetServer(const char *server);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    serverThe default server to use.
    +
    +

    Description

    +

    cupsSetServer() sets the default server to use for the + CUPS API. If the server argument is NULL, the + default server is used.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +cupsSetServer("foo.bar.com");
    +
    +

    See Also

    +

    cupsServer(), + cupsSetPasswordCB(), +cupsSetUser(), cupsUser() + + +

    +

    cupsSetUser()

    +

    Usage

    +
    +void
    +cupsSetUser(const char *user);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    userThe user name string to use.
    +
    +

    Description

    +

    cupsSetUser() sets the default user name for + authentication. If the user argument is NULL + then the current login user is used.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +...
    +
    +cupsSetUser("root");
    +
    +

    See Also

    +

    cupsServer(), + cupsSetPasswordCB(), +cupsSetServer(), cupsUser() + + +

    +

    cupsTempFd()

    +

    Usage

    +
    +int
    +cupsTempFd(char *filename,
    +           int  length);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    filenameThe character string to hold the temporary + filename.
    lengthThe size of the filename string in bytes.
    +
    +

    Returns

    +

    A file descriptor open for reading and writing.

    +

    Description

    +

    cupsTempFd() create a temporary filename in the + /var/tmp directory or the directory specified by the TMPDIR + environment variable.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +int  fd;
    +char filename[256];
    +
    +fd = cupsTempFd(filename, sizeof(filename));
    +
    +

    See Also

    +

    cupsTempFile() + +

    +

    cupsTempFile()

    +

    Usage

    +
    +char *
    +cupsTempFile(char *filename,
    +             int  length);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    filenameThe character string to hold the temporary + filename.
    lengthThe size of the filename string in bytes.
    +
    +

    Returns

    +

    A pointer to filename.

    +

    Description

    +

    cupsTempFile() creates a temporary filename in the + /var/tmp directory or the directory specified by the TMPDIR + environment variable.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +char filename[256];
    +
    +cupsTempFile(filename, sizeof(filename));
    +
    +

    See Also

    +

    cupsTempFd() + +

    +

    cupsUser()

    +

    Usage

    +
    +const char *
    +cupsUser(void);
    +
    +

    Returns

    +

    A pointer to the current username or NULL if the user ID + is undefined.

    +

    Description

    +

    cupsUser() returns the name associated with the current + user ID as reported by the getuid() system call.

    +

    Example

    +
    +#include <cups/cups.h>
    +
    +const char *user;
    +
    +user = cupsUser();
    +
    +

    See Also

    +

    cupsGetPassword(), + cupsServer() + +

    +

    httpBlocking()

    +

    Usage

    +
    +void
    +httpBlocking(http_t *http,
    +             int    blocking)
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    blocking0 if the connection should be non-blocking, 1 + if it should be blocking
    +
    +

    Description

    +

    The httpBlocking() function sets the blocking mode for + the HTTP connection. By default HTTP connections will block (stop) the + client program until data is available or can be sent to the server.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +http = httpConnect("server", port);
    +httpBlocking(http, 0);
    +
    +

    See Also

    + httpCheck(), + httpConnect() + + +

    httpCheck()

    +

    Usage

    +
    +int
    +httpCheck(http_t *http);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    httpThe HTTP connection
    +
    +

    Returns

    +

    0 if there is no data pending, 1 otherwise.

    +

    Description

    +

    The httpCheck() function checks to see if there is any + data pending on an HTTP connection.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +if (httpCheck(http))
    +{
    +  ... do something ...
    +}
    +
    +

    See Also

    + httpBlocking(), + httpConnect(), httpGets() +, httpRead() + + +

    httpClearFields()

    +

    Usage

    +
    +void
    +httpClearFields(http_t *http)
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    httpThe HTTP connection
    +
    +

    Description

    +

    The httpClearFields() function clears all HTTP request + fields for the HTTP connection.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpClearFields(http);
    +
    +

    See Also

    + httpConnect(), + httpGetField(), +httpSetField() + + +

    httpClose()

    +

    Usage

    +
    +void
    +httpClose(http_t *http);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    httpThe HTTP connection
    +
    +

    Description

    +

    The httpClose() function closes an active HTTP + connection.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpClose(http);
    +
    +

    See Also

    + httpConnect() + + +

    httpConnect()

    +

    Usage

    +
    +http_t *
    +httpConnect(const char *hostname,
    +            int        port);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    hostnameThe name or IP address of the server to connect + to
    portThe port number to use
    +
    +

    Returns

    +

    A pointer to a HTTP connection structure or NULL if the connection + could not be made.

    +

    Description

    +

    The httpConnect() function opens a HTTP connection to + the specified server and port.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +http = httpConnect(cupsServer(), ippPort());
    +
    +

    See Also

    + httpClose(), + httpConnectEncrypt(), +httpGet(), httpGets(), + httpPost(), httpRead() +, httpWrite() + + +

    httpConnectEncrypt()

    +

    Usage

    +
    +http_t *
    +httpConnectEncrypt(const char        *hostname,
    +                   int               port,
    +                   http_encryption_t encryption);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    hostnameThe name or IP address of the server to connect + to
    portThe port number to use
    encryptionThe level of encryption to use
    +
    +

    Returns

    +

    A pointer to a HTTP connection structure or NULL if the connection + could not be made.

    +

    Description

    +

    The httpConnectEncrypt() function opens a HTTP + connection to the specified server, port, and encryption.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
    +
    +

    See Also

    + httpClose(), + httpConnect(), httpGet() +, httpGets(), + httpPost(), httpRead() +, httpWrite() + + +

    httpDecode64()

    +

    Usage

    +
    +char *
    +httpDecode64(char       *out,
    +             const char *in);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    outThe output string
    inThe input string
    +
    +

    Returns

    +

    A pointer to the decoded string.

    +

    Description

    +

    The httpDecode64() function decodes a base-64 encoded + string to the original string.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +char encoded_string[255];
    +char original_string[255];
    +
    +httpDecode64(original_string, encoded_string);
    +
    +

    See Also

    + httpEncode64() + + +

    httpDelete()

    +

    Usage

    +
    +int
    +httpDelete(http_t     *http,
    +           const char *uri);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to delete
    +
    +

    Returns

    +

    0 on success, non-zero on failure.

    +

    Description

    +

    The httpDelete() function sends a HTTP DELETE request to + the server.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpDelete(http, "/some/uri");
    +
    +

    See Also

    + httpConnect(), + httpSetField(), +httpUpdate() + + +

    httpEncode64()

    +

    Usage

    +
    +char *
    +httpEncode64(char       *out,
    +             const char *in);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    outThe output string
    inThe input string
    +
    +

    Returns

    +

    A pointer to the encoded string.

    +

    Description

    +

    The httpEncode64() function decodes a base-64 encoded + string to the original string.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +char encoded_string[255];
    +char original_string[255];
    +
    +httpEncode64(encoded_string, original_string);
    +
    +

    See Also

    + httpDecode64() + + +

    httpEncryption()

    +

    Usage

    +
    +int
    +httpEncryption(http_t            *http,
    +               http_encryption_t encryption);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection.
    encryptionThe desired level of encryption.
    +
    +

    Returns

    +

    0 on success, -1 on error.

    +

    Description

    +

    httpEncryption() sets the encryption level for the HTTP + connection.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +...
    +
    +httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
    +
    +

    See Also

    +

    httpConnectEncrypt() + +

    +

    httpError()

    +

    Usage

    +
    +int
    +httpError(http_t *http);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    httpThe HTTP connection
    +
    +

    Returns

    +

    The last error that occurred or 0 if no error has occurred.

    +

    Description

    +

    The httpError() function returns the last error that + occurred on the HTTP connection.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +if (httpError(http))
    +{
    +  ... show an error message ...
    +}
    +
    +

    See Also

    + httpConnect() + + +

    httpFlush()

    +

    Usage

    +
    +void
    +httpFlush(http_t *http);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    httpThe HTTP connection
    +
    +

    Description

    +

    The httpFlush() function flushes any remaining data left + from a GET or POST operation.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpFlush(http);
    +
    +

    See Also

    + httpConnect(), + + +

    httpGet()

    +

    Usage

    +
    +int
    +httpGet(http_t     *http,
    +        const char *uri);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to get
    +
    +

    Returns

    +

    0 on success, non-zero on failure.

    +

    Description

    +

    The httpGet() function sends a HTTP GET request to the + server.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpGet(http, "/some/uri");
    +
    +

    See Also

    + httpConnect(), + httpSetField(), +httpUpdate() + + +

    httpGets()

    +

    Usage

    +
    +char *
    +httpGets(char   *line,
    +         int    length,
    +         http_t *http)
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    lineThe string to fill with a line from the HTTP + connection
    lengthThe maximum length of the string
    httpThe HTTP connection
    +
    +

    Returns

    +

    A pointer to the string or NULL if no line could be retrieved.

    +

    Description

    +

    The httpGets() function is used to read a request line + from the HTTP connection. It is not normally used by a client program.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +char   line[1024];
    +
    +if (httpGets(line, sizeof(line), http))
    +{
    +  ... process the line ...
    +}
    +
    +

    See Also

    + httpConnect(), + httpUpdate() + + +

    httpGetDateString()

    +

    Usage

    +
    +const char *
    +httpGetDateString(time_t time)
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    timeThe UNIX date/time value
    +
    +

    Returns

    +

    A pointer to a static string containing the HTTP date/time string for + the specified UNIX time value.

    +

    Description

    +

    The httpGetDateString() function generates a date/time + string suitable for HTTP requests from a UNIX time value.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +puts(httpGetDateString(time(NULL)));
    +
    +

    See Also

    + httpGetDateTime() + + +

    httpGetDateTime()

    +

    Usage

    +
    +time_t
    +httpGetDateTime(const char *date)
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    dateThe HTTP date/time string
    +
    +

    Returns

    +

    A UNIX time value.

    +

    Description

    +

    The httpGetDateTime() function converts a HTTP date/time + string to a UNIX time value.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +printf("%d\n", httpGetDateTime("Fri, 30 June 2000 12:34:56 GMT"));
    +
    +

    See Also

    + httpGetDateString() + + +

    httpGetField()

    +

    Usage

    +
    +const char *
    +httpGetField(http_t       *http,
    +             http_field_t field);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    fieldThe HTTP field
    +
    +

    Returns

    +

    A pointer to the field value string.

    +

    Description

    +

    The httpGetField() function returns the current value + for the specified HTTP field.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpGet(http, "/some/uri");
    +while (httpUpdate(http) == HTTP_CONTINUE);
    +
    +puts(httpGetField(http, HTTP_FIELD_CONTENT_TYPE));
    +
    +

    See Also

    + httpConnect(), + httpGetSubField(), +httpSetField() + + +

    httpGetHostByName()

    +

    Usage

    +
    +struct hostent	*
    +httpGetHostByName(const char *name);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    nameName or IP address to lookup.
    +
    +

    Returns

    +

    NULL if the host could not be found or a pointer to a host entry + containing one or more addresses.

    +

    Description

    +

    httpGetHostByName() is a portable wrapper around the +gethostbyname() function which handles both hostnames and IP + addresses.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +struct hostent *hostaddr;
    +
    +hostaddr = httpGetHostByName("foo.bar.com");
    +
    + + +

    httpGetLength()

    +

    Usage

    +
    +int
    +httpGetLength(http_t *http);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    httpThe HTTP connection.
    +
    +

    Returns

    +

    The content length of the response or MAX_INT if chunking is used.

    +

    Description

    +

    httpGetLength() returns the content length of a + response.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +...
    +
    +printf("The length of the response is %d bytes.\n", httpGetLength(http));
    +
    +

    See Also

    +

    httpGet(), +httpPost() + +

    +

    httpGetSubField()

    +

    Usage

    +
    +const char *
    +httpGetSubField(http_t       *http,
    +                http_field_t field,
    +		const char   *name,
    +		char         *value);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    httpThe HTTP connection.
    fieldThe HTTP field.
    nameThe name of the subfield.
    valueThe string to hold the subfield value.
    +
    +

    Returns

    +

    A pointer to the subfield value string or NULL if it does not exist.

    +

    Description

    +

    The httpGetSubField() function returns a subfield value + from the specified HTTP field. The destination string buffer must be at + least HTTP_MAX_VALUE bytes in length.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +char   value[HTTP_MAX_VALUE];
    +
    +httpGet(http, "/some/uri");
    +while (httpUpdate(http) == HTTP_CONTINUE);
    +
    +puts(httpGetSubField(http, HTTP_FIELD_CONTENT_TYPE, "charset", value));
    +
    +

    See Also

    + httpConnect(), + httpGetField(), +httpSetField() + + +

    httpHead()

    +

    Usage

    +
    +int
    +httpHead(http_t     *http,
    +         const char *uri);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to head
    +
    +

    Returns

    +

    0 on success, non-zero on failure.

    +

    Description

    +

    The httpHead() function sends a HTTP HEAD request to the + server.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpHead(http, "/some/uri");
    +
    +

    See Also

    + httpConnect(), + httpSetField(), +httpUpdate() + + +

    httpInitialize()

    +

    Usage

    +
    +void httpInitialize(void);
    +
    +

    Description

    +

    The httpInitialize() function initializes the networking + code as needed by the underlying platform. It is called automatically + by the httpConnect() function.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +httpInitialize();
    +
    +

    See Also

    + httpConnect() + + +

    httpMD5()

    +

    Usage

    +
    +char *
    +httpMD5(const char *username,
    +        const char *realm,
    +        const char *passwd,
    +        char       md5[33]);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    usernameThe authenticating user name.
    realmThe authenticating realm name.
    passwdThe authenticating password.
    md5The MD5 sum string.
    +
    +

    Returns

    +

    A pointer to the MD5 sum string.

    +

    Description

    +

    httpMD5() computes the MD5 hash of the username, realm, + and password as required by the HTTP Digest specification.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +char md5[33];
    +
    +...
    +
    +httpMD5("user", "realm", "password", md5);
    +
    +

    See Also

    +

    httpMD5Final(), + httpMD5String() + +

    +

    httpMD5Final()

    +

    Usage

    +
    +char *
    +httpMD5Final(const char *nonce,
    +             const char *method,
    +             const char *resource,
    +             char       md5[33]);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    nonceThe server nonce value.
    methodThe HTTP method (GET, POST, etc.)
    resourceThe resource path.
    md5The MD5 sum string.
    +
    +

    Returns

    +

    The MD5 sum string.

    +

    Description

    +

    httpMD5Final() appends the nonce, method, and resource + to the specified MD5 sum.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +char md5[33];
    +
    +...
    +
    +httpMD5Final("nonce", "GET", "/jobs", md5);
    +
    +

    See Also

    +

    httpMD5(), + httpMD5String() + +

    +

    httpMD5String()

    +

    Usage

    +
    +char *
    +httpMD5String(const md5_byte_t *sum,
    +              char             md5[33]);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    sumThe raw MD5 sum data.
    md5The MD5 sum string.
    +
    +

    Returns

    +

    The MD5 sum string.

    +

    Description

    +

    httpMD5String() converts the raw MD5 sum value to a + string.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +md5_byte_t sum[16];
    +char       md5[33];
    +
    +...
    +
    +httpMD5String(sum, md5);
    +
    +

    See Also

    +

    httpMD5(), + httpMD5Final() + +

    +

    httpOptions()

    +

    Usage

    +
    +int
    +httpOptions(http_t     *http,
    +            const char *uri);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to check for options
    +
    +

    Returns

    +

    0 on success, non-zero on failure.

    +

    Description

    +

    The httpOptions() function sends a HTTP OPTIONS request + to the server.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpOptions(http, "/some/uri");
    +
    +

    See Also

    + httpConnect(), + httpSetField(), +httpUpdate() + + +

    httpPost()

    +

    Usage

    +
    +int
    +httpPost(http_t     *http,
    +         const char *uri);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to post to
    +
    +

    Returns

    +

    0 on success, non-zero on failure.

    +

    Description

    +

    The httpPost() function sends a HTTP POST request to the + server.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpPost(http, "/some/uri");
    +
    +

    See Also

    + httpConnect(), + httpSetField(), +httpUpdate() + + +

    httpPrintf()

    +

    Usage

    +
    +int
    +httpPrintf(http_t     *http,
    +           const char *format,
    +           ...);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    formatA printf-style format string
    +
    +

    Returns

    +

    The number of bytes written.

    +

    Description

    +

    The httpPrintf() function sends a formatted string to + the HTTP connection. It is normally only used by the CUPS API and + scheduler.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpPrintf(http, "GET / HTTP/1.1 \r\n");
    +
    +

    See Also

    + httpConnect() + + +

    httpPut()

    +

    Usage

    +
    +int
    +httpPut(http_t     *http,
    +        const char *uri);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to put
    +
    +

    Returns

    +

    0 on success, non-zero on failure.

    +

    Description

    +

    The httpPut() function sends a HTTP PUT request to the + server.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpDelete(http, "/some/uri");
    +
    +

    See Also

    + httpConnect(), + httpSetField(), +httpUpdate() + + +

    httpRead()

    +

    Usage

    +
    +int
    +httpRead(http_t *http,
    +         char   *buffer,
    +         int    length);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    bufferThe buffer to read into
    lengthThe number of bytes to read
    +
    +

    Returns

    +

    The number of bytes read or -1 on error.

    +

    Description

    +

    The httpRead() function reads data from the HTTP + connection, possibly the result of a GET or POST request.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +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);
    +}
    +
    +

    See Also

    + httpConnect(), + httpWrite() + + +

    httpReconnect()

    +

    Usage

    +
    +int
    +httpReconnect(http_t *http);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    httpThe HTTP connection
    +
    +

    Returns

    +

    0 on success, non-zero on failure.

    +

    Description

    +

    The httpReconnect() function reconnects to the HTTP + server. This is usually done automatically if the HTTP functions detect + that the server connection has terminated.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpReconnect(http);
    +
    +

    See Also

    + httpConnect() + + +

    httpSeparate()

    +

    Usage

    +
    +void
    +httpSeparate(const char *uri,
    +             char       *method,
    +             char       *username,
    +             char       *host,
    +             int        *port,
    +             char       *resource);
    +
    +

    Arguments

    +
    + + + + + + + + +
    ArgumentDescription
    uriThe URI to separate
    methodThe method (scheme) of the URI
    usernameThe username (and password) portion of the URI, + if any
    hostThe hostname portion of the URI, if any
    portThe port number for the URI, either as specified or + as default for the method/scheme
    resourceThe resource string, usually a filename on the + server
    +
    +

    Description

    +

    The httpSeparate() function separates the specified URI + into its component parts. The method, username, hostname, and resource + strings should be at least HTTP_MAX_URI characters long to + avoid potential buffer overflow problems.

    +

    Example

    +
    +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, &port, resource);
    +
    +

    See Also

    + httpConnect() + + +

    httpSetField()

    +

    Usage

    +
    +void
    +httpSetField(http_t       *http,
    +             http_field_t field,
    +             const char   *value);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    fieldThe HTTP field
    valueThe string value for the field
    +
    +

    Description

    +

    The httpSetField() function sets the current value for + the specified HTTP field.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpSetField(http, HTTP_FIELD_AUTHORIZATION, "Basic dfdr34453454325"));
    +httpGet(http, "/some/uri");
    +while (httpUpdate(http) == HTTP_CONTINUE);
    +
    +

    See Also

    + httpConnect(), + httpGetField() + + +

    httpStatus()

    +

    Usage

    +
    +const char *
    +httpStatus(http_status_t status);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    statusThe HTTP status code from the server.
    +
    +

    Returns

    +

    The standard HTTP status text associated with the status code.

    +

    Description

    +

    httpStatus() returns the standard HTTP status text + associated with the status code.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +...
    +
    +puts(httpStatus(http->status));
    +
    + + +

    httpTrace()

    +

    Usage

    +
    +int
    +httpTrace(http_t     *http,
    +          const char *uri);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to trace
    +
    +

    Returns

    +

    0 on success, non-zero on failure.

    +

    Description

    +

    The httpTrace() function sends a HTTP TRACE request to + the server.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpTrace(http, "/some/uri");
    +
    +

    See Also

    + httpConnect(), + httpSetField(), +httpUpdate() + + +

    httpUpdate()

    +

    Usage

    +
    +http_status_t
    +httpUpdate(http_t *http);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    httpThe HTTP connection
    +
    +

    Returns

    +

    The HTTP status of the current request.

    +

    Description

    +

    The httpUpdate() function updates the current request + status. It is used after any DELETE, GET, HEAD, OPTIONS, POST, PUT, or + TRACE request to finalize the HTTP request and retrieve the request + status.

    +

    Since proxies and the current blocking mode can cause the request to + take longer, programs should continue calling httpUpdate() +until the return status is not the constant value HTTP_CONTINUE +.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +http_t *http;
    +http_status_t status;
    +
    +httpGet(http, "/some/uri");
    +while ((status = httpUpdate(http)) == HTTP_CONTINUE);
    +printf("Request status is %d\n", status);
    +
    +

    See Also

    + httpConnect(), + httpDelete(), httpGet() +, httpHead(), + httpOptions(), httpPost() +, httpPut(), + httpTrace() + + +

    httpWrite()

    +

    Usage

    +
    +int
    +httpWrite(http_t *http,
    +          char   *buffer,
    +          int    length);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    bufferThe buffer to read into
    lengthThe number of bytes to read
    +
    +

    Returns

    +

    The number of bytes read or -1 on error.

    +

    Description

    +

    The httpWrite() function reads data from the HTTP + connection, possibly the result of a GET or POST request.

    +

    Example

    +
    +#include <cups/http.h>
    +
    +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);
    +}
    +
    +

    See Also

    + httpConnect(), + httpRead() + + +

    ippAddBoolean()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddBoolean(ipp_t      *ipp,
    +              ipp_tag_t  group,
    +              const char *name,
    +	      char       value);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    valueThe boolean value
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddBoolean() function adds a single boolean + attribute value to the specified IPP request.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddBoolean(ipp, IPP_TAG_OPERATION, "my-jobs", 1);
    +
    +

    See Also

    + ippAddBooleans(), + ippAddDate(), +ippAddInteger(), +ippAddIntegers(), ippAddRange() +, ippAddRanges(), + ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddBooleans()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddBooleans(ipp_t      *ipp,
    +               ipp_tag_t  group,
    +               const char *name,
    +               int        num_values,
    +               const char *values);
    +
    +

    Arguments

    +
    + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    num_valuesThe number of values
    valuesThe boolean values
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddBooleans() function adds one or more boolean + attribute values to the specified IPP request. If the values + pointer is NULL then an array of num_values + false values is created.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +char values[10];
    +
    +ippAddBooleans(ipp, IPP_TAG_OPERATION, "some-attribute", 10, values);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddDate(), +ippAddInteger(), +ippAddIntegers(), ippAddRange() +, ippAddRanges(), + ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddDate()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddDate(ipp_t       *ipp,
    +           ipp_tag_t   group,
    +           const char  *name,
    +           ipp_uchar_t *value);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    valueThe date value
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddDate() function adds a single date-time + attribute value to the specified IPP request.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddDate(ipp, IPP_TAG_OPERATION, "some-attribute", 
    +           ippTimeToDate(time(NULL));
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddInteger(), +ippAddIntegers(), ippAddRange() +, ippAddRanges(), + ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings(), +ippTimeToDate() + + +

    ippAddInteger()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddInteger(ipp_t      *ipp,
    +              ipp_tag_t  group,
    +              ipp_tag_t  tag,
    +              const char *name,
    +              int        value);
    +
    +

    Arguments

    +
    + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    tagThe type of integer value (IPP_TAG_INTEGER or + IPP_TAG_ENUM)
    nameThe name of attribute
    valueThe integer value
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddInteger() function adds a single integer + attribute value to the specified IPP request.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddInteger(ipp, IPP_TAG_OPERATION, "limit", 100);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), +ippAddIntegers(), ippAddRange() +, ippAddRanges(), + ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddIntegers()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddIntegers(ipp_t      *ipp,
    +               ipp_tag_t  group,
    +               ipp_tag_t  tag,
    +               const char *name,
    +               int        num_values,
    +               const int  *values);
    +
    +

    Arguments

    +
    + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    tagThe type of integer value (IPP_TAG_INTEGER or + IPP_TAG_ENUM)
    nameThe name of attribute
    num_valuesThe number of values
    valuesThe integer values
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddIntegers() function adds one or more integer + attribute values to the specified IPP request. If the values + pointer is NULL then an array of num_values 0 + values is created.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +int values[100];
    +
    +ippAddIntegers(ipp, IPP_TAG_OPERATION, "some-attribute", 100, values);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddRange(), + ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddRange()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddRange(ipp_t      *ipp,
    +            ipp_tag_t  group,
    +            const char *name,
    +            int        low,
    +            int        high);
    +
    +

    Arguments

    +
    + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    lowThe lower value
    highThe higher value
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddRange() function adds a single range attribute + value to the specified IPP request.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddRange(ipp, IPP_TAG_OPERATION, "page-ranges", 1, 10);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), + ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddRanges()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddRanges(ipp_t      *ipp,
    +             ipp_tag_t  group,
    +             const char *name,
    +             int        num_values,
    +             const int  *lows,
    +             const int  *highs);
    +
    +

    Arguments

    +
    + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    num_valuesThe number of range values
    lowsThe lower values
    highsThe higher values
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddRanges() function adds one or more range + attribute values to the specified IPP request. If the values + pointer is NULL then an array of num_values + 0,0 ranges is created.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +int lows[2];
    +int highs[2];
    +
    +ippAddRanges(ipp, IPP_TAG_OPERATION, "page-ranges", 2, lows, highs);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), + ippAddRange(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddResolution()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddResolution(ipp_t      *ipp,
    +                 ipp_tag_t  group,
    +                 const char *name,
    +                 int        xres,
    +                 int        yres,
    +                 ipp_res_t  units);
    +
    +

    Arguments

    +
    + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    xresThe horizontal resolution
    yresThe vertical resolution
    unitsThe resolution units
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddResolution() function adds a single resolution + attribute value to the specified IPP request.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolution",
    +              720, 720, IPP_RES_PER_INCH);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), + ippAddRange(), +ippAddRanges(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddResolutions()

    +

    Usage

    +
    +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);
    +
    +

    Arguments

    +
    + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    num_valuesThe number of resolution values
    xresThe horizontal resolutions
    yresThe vertical resolutions
    unitsThe resolution units
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddResolutions() function adds one or more + resolution attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values 0,0 resolutions is created.

    +

    Example

    +
    +#include <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);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), + ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddSeparator()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddSeparator(ipp_t *ipp);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    ippThe IPP request
    +
    +

    Returns

    +

    A pointer to the new separator or NULL if the separator could not be + created.

    +

    Description

    +

    The ippAddSeparator() function adds a group separator to + the specified IPP request.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddSeparator(ipp);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), + ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddString(), +ippAddStrings() + + +

    ippAddString()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippAddString(ipp_t      *ipp,
    +             ipp_tag_t  group,
    +             ipp_tag_t  tag,
    +             const char *name,
    +             const char *charset,
    +             const char *value);
    +
    +

    Arguments

    +
    + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    tagThe type of string value
    nameThe name of attribute
    charsetThe character set for the string
    valueThe string value
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddString() function adds a single string + attribute value to the specified IPP request. For +IPP_TAG_NAMELANG and IPP_TAG_TEXTLANG strings, the + charset value is provided with the string to identify the string + encoding used. Otherwise the charset value is ignored.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
    +             NULL, "abc123");
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), + ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddStrings() + + +

    ippAddStrings()

    +

    Usage

    +
    +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);
    +
    +

    Arguments

    +
    + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    tagThe type of string value
    nameThe name of attribute
    num_valuesThe number of strings
    charsetThe character set for the strings
    valuesThe string values
    +
    +

    Returns

    +

    A pointer to the new attribute or NULL if the attribute could not be + created.

    +

    Description

    +

    The ippAddStrings() function adds one or more string + attribute values to the specified IPP request. For +IPP_TAG_NAMELANG and IPP_TAG_TEXTLANG strings, the + charset value is provided with the strings to identify the string + encoding used. Otherwise the charset value is ignored. If the +values pointer is NULL then an array of +num_values NULL strings is created.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +char *values[2] = { "one", "two" };
    +
    +ippAddStrings(ipp, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "attr-name",
    +              2, NULL, values);
    +
    +

    See Also

    + ippAddBoolean(), + ippAddBooleans(), +ippAddDate(), ippAddInteger() +, ippAddIntegers(), + ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString() + + +

    ippDateToTime()

    +

    Usage

    +
    +time_t
    +ippDateToTime(const ipp_uchar_t date[11]);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    dateThe IPP date-time value
    +
    +

    Returns

    +

    A UNIX time value.

    +

    Description

    +

    The ippDateToTime() function converts an IPP date-time + value to a UNIX time value.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_uchar_t date[11];
    +
    +printf("UNIX time is %d\n", ippDateToTime(date));
    +
    +

    See Also

    + ippTimeToDate() + + +

    ippDelete()

    +

    Usage

    +
    +void
    +ippDelete(ipp_t *ipp);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    ippThe IPP request or response
    +
    +

    Description

    +

    The ippDelete() function deletes all memory used by an + IPP request or response.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippDelete(ipp);
    +
    +

    See Also

    + ippNew() + + +

    ippErrorString()

    +

    Usage

    +
    +const char *
    +ippErrorString(ipp_status_t error);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    errorIPP error code.
    +
    +

    Returns

    +

    The standard text representation of the IPP error code.

    +

    Description

    +

    ippErrorString() returns the standard text + representation of the IPP error code.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +puts(ippErrorString(IPP_OK));
    +
    +

    See Also

    +

    cupsLastError() + +

    +

    ippFindAttribute()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippFindAttribute(ipp_t      *ipp,
    +                 const char *name,
    +                 ipp_tag_t  tag);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    ippThe IPP request or response
    nameThe name of the attribute
    tagThe required value tag for the attribute or +IPP_TAG_ZERO for any type of value.
    +
    +

    Returns

    +

    A pointer to the first occurrence of the requested attribute, or +NULL if it was not found.

    +

    Description

    +

    ippFindAttribute() finds the first occurrence of the + named attribute. The tag parameter restricts the search to + a specific value type - use IPP_TAG_ZERO to find any value + with the name.

    +

    The value tags IPP_TAG_NAME and IPP_TAG_TEXT + match the name/text values with or without the language code.

    +

    Example

    +
    +ipp_attribute_t *attr;
    +
    +attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT);
    +while (attr != NULL)
    +{
    +  puts(attr->values[0].string.text);
    +
    +  attr = ippFindNextAttribute(response, "printer-state-message", IPP_TAG_TEXT);
    +}
    +
    +

    See Also

    + cupsDoFileRequest(), + cupsDoRequest(), +ippDelete(), +ippFindNextAttribute(), ippNew() + + + +

    ippFindNextAttribute()

    +

    Usage

    +
    +ipp_attribute_t *
    +ippFindNextAttribute(ipp_t      *ipp,
    +                     const char *name,
    +                     ipp_tag_t  tag);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    ippThe IPP request or response
    nameThe name of the attribute
    tagThe required value tag for the attribute or +IPP_TAG_ZERO for any type of value.
    +
    +

    Returns

    +

    A pointer to the next occurrence of the requested attribute, or +NULL if it was not found.

    +

    Description

    +

    ippFindNextAttribute() finds the next occurrence of the + named attribute. The tag parameter restricts the search to + a specific value type - use IPP_TAG_ZERO to find any value + with the name.

    +

    The value tags IPP_TAG_NAME and IPP_TAG_TEXT + match the name/text values with or without the language code.

    +

    Example

    +
    +ipp_attribute_t *attr;
    +
    +attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT);
    +while (attr != NULL)
    +{
    +  puts(attr->values[0].string.text);
    +
    +  attr = ippFindNextAttribute(response, "printer-state-message", IPP_TAG_TEXT);
    +}
    +
    +

    See Also

    + cupsDoFileRequest(), + cupsDoRequest(), +ippDelete(), +ippFindNextAttribute(), ippNew() + + + +

    ippLength()

    +

    Usage

    +
    +int
    +ippLength(ipp_t *ipp);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    ippThe IPP request or response
    +
    +

    Returns

    +

    The total encoded length of the IPP request or response in bytes.

    +

    Description

    +

    ippLength() returns the length of the IPP request or + response in bytes.

    +

    Example

    +
    +printf("The length of the response is %d bytes.\n", ippLength(response));
    +
    +

    See Also

    + ippDelete(), +ippNew() + + +

    ippNew()

    +

    Usage

    +
    +ipp_t *
    +ippNew(void);
    +
    +

    Returns

    +

    A pointer to a new IPP request or response.

    +

    Description

    +

    The ippNew() function creates a new IPP request or + response.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ipp = ippNew();
    +
    +

    See Also

    + ippDelete() + + +

    ippPort()

    +

    Usage

    +
    +int
    +ippPort(void);
    +
    +

    Returns

    +

    The default TCP/IP port number for IPP requests.

    +

    Description

    +

    The ippPort() function returns the default IPP port + number for requests.

    +

    Example

    +
    +#include <cups/http.h>
    +#include <cups/ipp.h>
    +
    +http_t *http;
    +
    +http = httpConnect(cupsServer(), ippPort());
    +
    +

    See Also

    + cupsServer(), + ippSetPort() + + +

    ippRead()

    +

    Usage

    +
    +ipp_state_t
    +ippRead(http_t *http,
    +        ipp_t  *ipp);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    ippThe IPP request or response
    +
    +

    Returns

    +

    The current read state.

    +

    Description

    +

    The ippRead() function reads IPP attributes from the + specified HTTP connection. Programs should continue calling +ippRead() until IPP_ERROR or IPP_DATA + is returned.

    +

    Example

    +
    +#include <cups/http.h>
    +#include <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() ...
    +}
    +
    +

    See Also

    + ippWrite() + + +

    ippSetPort()

    +

    Usage

    +
    +void
    +ippSetPort(int port);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    portThe port number to use
    +
    +

    Description

    +

    The ippSetPort() function sets the default IPP port + number for requests.

    +

    Example

    +
    +#include <cups/http.h>
    +#include <cups/ipp.h>
    +
    +...
    +
    +ippSetPort(8631);
    +
    +

    See Also

    + ippPort() + + +

    ippTimeToDate()

    +

    Usage

    +
    +ipp_uchar_t *
    +ippTimeToDate(time_t time);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    timeThe UNIX time value
    +
    +

    Returns

    +

    A static pointer to an IPP date-time value.

    +

    Description

    +

    The ippTimeToDate() function converts a UNIX time to an + IPP date-time value.

    +

    Example

    +
    +#include <cups/ipp.h>
    +
    +ipp_uchar_t *date;
    +
    +date = ippTimeToDate(time(NULL));
    +
    +

    See Also

    + ippDateToTime() + + +

    ippWrite()

    +

    Usage

    +
    +ipp_state_t
    +ippWrite(http_t *http,
    +         ipp_t  *ipp);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    httpThe HTTP connection
    ippThe IPP request or response
    +
    +

    Returns

    +

    The current write state.

    +

    Description

    +

    The ippWrite() function writes IPP attributes to the + specified HTTP connection. Programs should continue calling +ippWrite() until IPP_ERROR or IPP_DATA + is returned.

    +

    Example

    +
    +#include <cups/http.h>
    +#include <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() ...
    +}
    +
    +

    See Also

    + ippRead() + + +

    ppdClose()

    +

    Usage

    +
    +void
    +ppdClose(ppd_file_t *ppd);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    ppdThe PPD file
    +
    +

    Description

    +

    The ppdClose() function frees all memory associated with + the PPD file.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdClose(ppd);
    +
    +

    See Also

    + ppdOpen(), +ppdOpenFd(), ppdOpenFile() + + + +

    ppdCollect()

    +

    Usage

    +
    +int
    +ppdCollect(ppd_file_t    *ppd,
    +           ppd_section_t section,
    +           ppd_choice_t  ***choices);
    +
    +

    Arguments

    +
    + + + + + + +
    ArgumentDescription
    ppdThe PPD file.
    sectionThe document section to collect.
    choicesThe array of option choices that are marked.
    +
    +

    Returns

    +

    The number of options collected.

    +

    Description

    +

    ppdCollect() collects all of the marked options in the + specified section, sorts them by their order dependency values, and + returns an array that can be used to emit option commands in the proper + order. It is normally used by the ppdEmit*() functions.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t   *ppd;
    +int          num_choices;
    +ppd_choice_t **choices;
    +
    +...
    +
    +num_choices = ppdCollect(ppd, PPD_ORDER_JCL, &choices);
    +
    +

    See Also

    +

    ppdEmit(), +ppdEmitFd(), ppdEmitJCL() + + +

    +

    ppdConflicts()

    +

    Usage

    +
    +int
    +ppdConflicts(ppd_file_t *ppd);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    ppdThe PPD file
    +
    +

    Returns

    +

    The number of option conflicts in the file.

    +

    Description

    +

    The ppdConflicts() function returns the number of + conflicts with the currently selected options.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +printf("%d conflicts\n", ppdConflicts(ppd));
    +
    +

    See Also

    + cupsMarkOptions(), + ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

    ppdEmit()

    +

    Usage

    +
    +int
    +ppdEmit(ppd_file_t    *ppd,
    +        FILE          *file,
    +        ppd_section_t section);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    ppdThe PPD file
    fileThe file to write to
    sectionThe option section to write
    +
    +

    Returns

    +

    0 on success, -1 on error.

    +

    Description

    +

    The ppdEmit() function sends printer-specific option + commands to the specified file.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
    +
    +

    See Also

    + ppdEmitFd() + + +

    ppdEmitFd()

    +

    Usage

    +
    +int
    +ppdEmitFd(ppd_file_t    *ppd,
    +          int           fd,
    +          ppd_section_t section);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    ppdThe PPD file
    fdThe file descriptor to write to
    sectionThe option section to write
    +
    +

    Returns

    +

    0 on success, -1 on error.

    +

    Description

    +

    The ppdEmitFd() function sends printer-specific option + commands to the specified file descriptor.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdEmitFd(ppd, 1, PPD_ORDER_PAGE);
    +
    +

    See Also

    + ppdEmit() + + +

    ppdFindChoice()

    +

    Usage

    +
    +ppd_choice_t *
    +ppdFindChoice(ppd_option_t *option,
    +              const char   *choice);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    optionA pointer to the option
    choiceThe name of the choice
    +
    +

    Returns

    +

    A pointer to the choice data or NULL if the choice does not exist.

    +

    Description

    +

    The ppdFindChoice() function returns a pointer to the + choice data for the specified option.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +ppd_option_t *option;
    +ppd_choice_t *choice;
    +
    +option = ppdFindOption(ppd, "PageSize");
    +choice = ppdFindChoice(option, "Letter");
    +
    +

    See Also

    + ppdFindMarkedChoice(), ppdFindOption() + + +

    ppdFindMarkedChoice()

    +

    Usage

    +
    +ppd_choice_t *
    +ppdFindMarkedChoice(ppd_file_t *ppd,
    +                    const char *keyword);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    ppdThe PPD file
    keywordThe name of the option
    +
    +

    Returns

    +

    A pointer to the choice data or NULL if the choice does not exist or + is not marked.

    +

    Description

    +

    The ppdFindMarkedChoice() function returns a pointer to + the marked choice data for the specified option.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +ppd_choice_t *choice;
    +
    +choice = ppdFindMarkedChoice(ppd, "PageSize");
    +
    +

    See Also

    + ppdFindChoice(), + ppdFindOption() + + +

    ppdFindOption()

    +

    Usage

    +
    +ppd_option_t *
    +ppdFindOption(ppd_file_t *ppd,
    +              const char *keyword);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    ppdThe PPD file
    keywordThe name of the option
    +
    +

    Returns

    +

    A pointer to the option data or NULL if the option does not exist.

    +

    Description

    +

    The ppdFindOption() function returns a pointer to the + option data for the specified option.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +ppd_option_t *option;
    +
    +option = ppdFindOption(ppd, "PageSize");
    +
    +

    See Also

    + ppdFindChoice(), + ppdFindMarkedChoice() + + +

    ppdIsMarked()

    +

    Usage

    +
    +int
    +ppdIsMarked(ppd_file_t *ppd,
    +            const char *keyword,
    +            const char *choice);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    ppdThe PPD file
    keywordThe name of the option
    choiceThe name of the option choice
    +
    +

    Returns

    +

    1 if the choice is marked, 0 otherwise.

    +

    Description

    +

    The ppdIsMarked() function returns whether or not the + specified option choice is marked.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +printf("Letter size %s selected.\n",
    +       ppdIsMarked(ppd, "PageSize", "Letter") ? "is" : "is not");
    +
    +

    See Also

    + cupsMarkOptions(), + ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

    ppdMarkDefaults()

    +

    Usage

    +
    +void
    +ppdMarkDefaults(ppd_file_t *ppd);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    ppdThe PPD file
    +
    +

    Description

    +

    The ppdMarkDefaults() function marks all of the default + choices in the PPD file.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdMarkDefaults(ppd);
    +
    +

    See Also

    + cupsMarkOptions(), + ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

    ppdMarkOption()

    +

    Usage

    +
    +int
    +ppdMarkOption(ppd_file_t *ppd,
    +              const char *keyword,
    +              const char *choice);
    +
    +

    Arguments

    +
    + + + + + +
    ArgumentDescription
    ppdThe PPD file
    keywordThe name of the option
    choiceThe name of the choice
    +
    +

    Returns

    +

    The number of conflicts in the PPD file.

    +

    Description

    +

    The ppdMarkOption() function marks the specified option + choice.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdMarkOption(ppd, "PageSize", "Letter");
    +
    +

    See Also

    + cupsMarkOptions(), + ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

    ppdOpen()

    +

    Usage

    +
    +ppd_file_t *
    +ppdOpen(FILE *file);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    fileThe file to read from
    +
    +

    Returns

    +

    A pointer to a PPD file structure or NULL if the PPD file could not + be read.

    +

    Description

    +

    The ppdOpen() function reads a PPD file from the + specified file into memory.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +FILE *file;
    +
    +file = fopen("filename.ppd", "rb");
    +ppd = ppdOpen(file);
    +fclose(file);
    +
    +

    See Also

    + ppdClose(), +ppdOpenFd(), ppdOpenFile() + + + +

    ppdOpenFd()

    +

    Usage

    +
    +ppd_file_t *
    +ppdOpenFd(int fd);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    fdThe file descriptor to read from
    +
    +

    Returns

    +

    A pointer to a PPD file structure or NULL if the PPD file could not + be read.

    +

    Description

    +

    The ppdOpenFd() function reads a PPD file from the + specified file descriptor into memory.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +int        fd;
    +
    +fd = open("filename.ppd", O_RDONLY);
    +ppd = ppdOpenFd(fd);
    +close(fd);
    +
    +

    See Also

    + ppdClose(), +ppdOpen(), ppdOpenFile() + + +

    ppdOpenFile()

    +

    Usage

    +
    +ppd_file_t *
    +ppdOpenFile(const char *filename);
    +
    +

    Arguments

    +
    + + + +
    ArgumentDescription
    filenameThe name of the file to read from
    +
    +

    Returns

    +

    A pointer to a PPD file structure or NULL if the PPD file could not + be read.

    +

    Description

    +

    The ppdOpenFile() function reads a PPD file from the + named file into memory.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppd = ppdOpenFile("filename.ppd");
    +
    +

    See Also

    + ppdClose(), +ppdOpen(), ppdOpenFd() + + +

    ppdPageLength()

    +

    Usage

    +
    +float
    +ppdPageLength(ppd_file_t *ppd,
    +              const char *name);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    ppdThe PPD file
    nameThe name of the page size
    +
    +

    Returns

    +

    The length of the specified page size in points or 0 if the page size + does not exist.

    +

    Description

    +

    The ppdPageLength() function returns the page length of + the specified page size.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +printf("Length = %.0f\n", ppdPageLength(ppd, "Letter"));
    +
    +

    See Also

    + ppdPageLength(), + ppdPageSize(), +ppdPageWidth() + + +

    ppdPageSize()

    +

    Usage

    +
    +ppd_size_t *
    +ppdPageSize(ppd_file_t *ppd,
    +            const char *name);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    ppdThe PPD file
    nameThe name of the page size
    +
    +

    Returns

    +

    A pointer to the page size record of the specified page size in + points or NULL if the page size does not exist.

    +

    Description

    +

    The ppdPageSize() function returns the page size record + for the specified page size.

    +

    Example

    +
    +#include <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);
    +}
    +
    +

    See Also

    + ppdPageLength(), + ppdPageWidth() + + +

    ppdPageWidth()

    +

    Usage

    +
    +float
    +ppdPageWidth(ppd_file_t *ppd,
    +             const char *name);
    +
    +

    Arguments

    +
    + + + + +
    ArgumentDescription
    ppdThe PPD file
    nameThe name of the page size
    +
    +

    Returns

    +

    The width of the specified page size in points or 0 if the page size + does not exist.

    +

    Description

    +

    The ppdPageWidth() function returns the page width of + the specified page size.

    +

    Example

    +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +printf("Width = %.0f\n", ppdPageWidth(ppd, "Letter"));
    +
    +

    See Also

    + ppdPageLength(), + ppdPageSize() + diff --git a/doc/spm.pdf b/doc/spm.pdf new file mode 100644 index 0000000000000000000000000000000000000000..f6a76cc2f661bfeb66fd1373795f5946062e0722 GIT binary patch literal 689586 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

    gwRHZ_lO)E1gpUG&&Ekk|&4Ssf0M0VHkgeun@ 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 literal 0 Hc-jL100001 diff --git a/doc/spm.shtml b/doc/spm.shtml new file mode 100644 index 000000000..a63ad396f --- /dev/null +++ b/doc/spm.shtml @@ -0,0 +1,10202 @@ + + + + + + CUPS Software Programmers Manual + + + +

    Preface

    + +

    This software programmers manual provides software +programming information for the Common UNIX Printing System +("CUPS") Version 1.2.0. + + + + +

    Document Overview

    + +

    This software programmers manual is organized into the following sections: + +

    + +

    Notation Conventions

    + +

    Various font and syntax conventions are used in this guide. Examples and +their meanings and uses are explained below: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Example   Description
     
    lpstat
    + lpstat(1)
       The names of commands; the first mention of a command or + function in a chapter is followed by a manual page section + number.
     
    /var
    + /usr/share/cups/data/testprint.ps
       File and directory names.
     
    Request ID is Printer-123   Screen output.
     
    lp -d printer filename ENTER   Literal user input; special keys like ENTER are + in ALL CAPS.
     
    12.3   Numbers in the text are written using the period (.) to indicate + the decimal point.
    + + +

    Abbreviations

    + +The following abbreviations are used throughout this manual: + +
      +
      + +
      kb +
      Kilobytes, or 1024 bytes
        + +
      Mb +
      Megabytes, or 1048576 bytes
        + +
      Gb +
      Gigabytes, or 1073741824 bytes
        + +
      +
    + +

    Other References

    + +
      +
      + +
      CUPS Software Administrators Manual + +
      An administration guide for the CUPS software.
        + +
      CUPS Software Users Manual + +
      An end-user guide for using the CUPS software.
        + +
      +
    + + + + + +

    2 - The CUPS API

    + +

    This chapter describes the CUPS Application Programmers Interface ("API"). + +

    The CUPS API Library

    + +

    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. + +

    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. + +

    Programs that use the CUPS API library typically will include the +<cups/cups.h> header file: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +jobid = cupsPrintFile("myprinter", "filename.ps", "title",
      +                      num_options, options);
      +
    + +

    Use the -lcups compiler option when linking to the CUPS API +library: + +

      +cc -o program program.c -lcups ENTER
      +
    + +

    Additional options and libraries may be required depending on the +operating system and the location of the CUPS API library. + +

    Detecting the CUPS API Library in GNU Autoconf

    + +

    GNU autoconf is a popular configuration tool used by many programs. +Add the following lines to your configure.in file to check +for the CUPS API library in your configuration script: + +

      +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)
      +
    + +

    Printing Services

    + +

    The CUPS API library provides some basic printing services for applications +that need to print files. + +

    Include Files

    + +

    The include file used by all of these functions is +<cups/cups.h>: + +

      +#include <cups/cups.h>
      +
    + +

    Printing a File

    + +

    The CUPS API provides two functions for printing files. The first is +cupsPrintFile which prints a single named file: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int jobid;
      +
      +...
      +
      +jobid = cupsPrintFile("name", "filename", "title", 0, NULL);
      +
    + +

    The name string is the name of the printer or class to +print to. The filename string is the name of the file to +print. The title string is the name of the print job, e.g. +"Acme Word Document". + +

    The return value is a unique ID number for the print job or 0 if there +was an error. + +

    Printing Multiple Files

    + +

    The second printing function is cupsPrintFiles: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int        jobid;
      +int        num_files;
      +const char *files[100];
      +...
      +
      +jobid = cupsPrintFiles("name", num_files, files, "title", 0, NULL);
      +
    + +

    Instead of passing a filename string as with cupsPrintFile() +you pass a file count (num_files) and filename pointer array +(files) for each file that you want to print. + +

    As with cupsPrintFile() the return value is a unique ID for +the print job. + +

    Cancelling Jobs

    + +

    The cupsCancelJob() function cancels a queued print job: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int jobid;
      +int status;
      +...
      +
      +status = cupsCancelJob("name", jobid);
      +
    + +

    The name string specifies the destination and is used +to determine the server to send the request to. The jobid +value is the integer returned from a previous cupsPrintFile() +or cupsPrintFiles() call. + +

    cupsCancelJob() returns 1 if the job was +successfully cancelled and 0 if there was an error. + +

    Getting the Available Printers and Classes

    + +

    The cupsGetDests() function can be used to get a list +of the available printers, classes, and instances that a user has defined: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int         num_dests;
      +cups_dest_t *dests;
      +
      +...
      +
      +num_dests = cupsGetDests(&dests);
      +
    + +

    Each destination is stored in a cups_dest_t 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: + +

      +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;
      +
    + +

    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 cupsGetDest() function: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int         num_dests;
      +cups_dest_t *dests;
      +cups_dest_t *mydest;
      +
      +...
      +
      +mydest = cupsGetDest("name", "instance", num_dests, dests);
      +
    + +

    The name string is the printer or class name. You can pass +a value of NULL to get the default destination. + +

    The instance string is the user-defined instance name. Pass +NULL to select the default instance, e.g. "name" instead of +"name/instance". + +

    Printing with Options

    + +

    All of the previous printing examples have passed 0 and +NULL for the last two arguments to the cupsPrintFile() +and cupsPrintFiles() functions. These last two arguments are the +number of options and a pointer to the option array: + +

      +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);
      +
    + +

    The cups_option_t structure holds each option and its value. +These are converted as needed and passed to the CUPS server when printing a +file. + +

    The simplest way of handling options is to use the num_options +and options members of the cups_dest_t +structure described earlier: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int         jobid;
      +int         num_dests;
      +cups_dest_t *dests;
      +cups_dest_t *mydest;
      +
      +...
      +
      +mydest = cupsGetDest("name", "instance", num_dests, dests);
      +
      +jobid  = cupsPrintFile(mydest->name, "filename", "title",
      +                       mydest->num_options, mydest->options);
      +
    + +

    This effectively uses the options a user has previous selected without a +lot of code. + +

    Setting Printer Options

    + +

    Options can also be set by your program using the cupsAddOption() +function: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int           num_options;
      +cups_option_t *options;
      +
      +...
      +
      +num_options = 0;
      +options     = NULL;
      +
      +...
      +
      +num_options = cupsAddOption("name", "value", num_options, &options);
      +num_options = cupsAddOption("name", "value", num_options, &options);
      +num_options = cupsAddOption("name", "value", num_options, &options);
      +num_options = cupsAddOption("name", "value", num_options, &options);
      +
    + +

    The name string is the name of the option, and the +value string is the value for that option. + +

    Each call to cupsAddOption() 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 +cupsAddOptions() 20 times will result in 20 options. + +

    Call cupsFreeOptions once you are done using the options: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int           num_options;
      +cups_option_t *options;
      +
      +...
      +
      +cupsFreeOptions(num_options, options);
      +
    + +

    Getting Errors

    + +

    If any of the CUPS API printing functions returns an error, the reason for +that error can be found by calling cupsLastError() and +cupsErrorString(). cupsLastError() returns the +last IPP error code that was encountered. cupsErrorString() +converts the error code to a localized message string suitable for +presentation to the user: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +int jobid;
      +
      +...
      +
      +if (jobid == 0)
      +  puts(cupsErrorString(cupsLastError()));
      +
    + +

    Passwords and Authentication

    + +

    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. + +

    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. + +

    The cupsSetPasswordCB() +function is used to set a password callback in your program. Only one +function can be used at any time. + +

    The cupsSetUser() function sets +the current username for authentication. This function can be called by +your password callback function to change the current username as needed. + +

    The following example shows a simple password callback that gets a +username and password from the user: + +

      +#include <cups/cups.h>
      +
      +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);
      +
    + +

    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 +cupsUser() to make things easier +on the user. + +

    PPD Services

    + +

    CUPS includes functions to access and manipulate PostScript Printer +Description ("PPD") files that are used with the printer drivers in CUPS. + +

    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.) + +

    Include Files

    + +

    Include the <cups/ppd.h> header file to use the PPD +functions: + +

      +#include <cups/ppd.h>
      +
    + +

    This header file is also included by the +<cups/cups.h> header file. + +

    Getting a PPD File for a Printer

    + +

    The cupsGetPPD() function retrieves the PPD file for the +named printer or class: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +const char *filename;
      +
      +filename = cupsGetPPD("name");
      +
    + +

    The name string is the name of the printer or class, including +the remote server name as appropriate (e.g. "printer@server".) + +

    The return value is a pointer to a filename in static storage; this value +is overwritten with each call to cupsGetPPD(). If the printer +or class does not exist, a NULL pointer will be returned. + +

    Loading a PPD File

    + +

    The ppdOpenFile() function "opens" a PPD file and loads it +into memory: + +

      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +
      +ppd = ppdOpenFile("filename");
      +
    + +

    The filename string is the name of the file to load, such as +the value returned by the cupsGetPPD() function. + +

    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. + +

    Freeing PPD File Information

    + +

    Once you are done using a PPD file, call the ppdClose() function +to free all memory that has been used: + +

      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +
      +...
      +
      +ppdClose(ppd);
      +
    + +

    The PPD File Structure

    + +

    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 ppd_file_t structure. + +

    Capabilities

    + +

    Each PPD file contains a number of informational attributes that +describe the capabilities of the printer. These are provided in the +ppd_file_t structure in the following members: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    accurate_screensint1 = supports accurate screens
    color_deviceint1 = color device
    colorspaceppd_cs_tDefault colorspace: PPD_CS_CMYK, PPD_CS_CMY, PPD_CS_GRAY, + PPD_CS_RGB, PPD_CS_RGBK, PPD_CS_N
    contone_onlyint1 = printer is continuous tone only
    num_emulations
    + emulations
    int
    + ppd_emul_t *
    Emulations supported by the printer
    flip_duplexint1 = need to flip odd pages when duplexing
    num_fonts
    + fonts
    int
    + char **
    The fonts available on the printer.
    jcl_begin
    + jcl_ps
    + jcl_end
    char *Job Control Language commands for PostScript output
    landscapeintLandscape orientation, -90 or 90 degrees
    lang_encodingchar *The character used for the option strings
    lang_versionchar *The language used for the options strings (English, French, etc.)
    language_levelintPostScript language level, 1 to 3
    manual_copiesint1 = Copies are done manually
    model_numberintDriver-specific model number.
    patcheschar *Patch commands to send to the printer
    manufacturerchar *The Manufacturer attribute from the PPD file, if any
    modelnamechar *The ModelName attribute from the PPD file
    nicknamechar *The NickName attribute from the PPD file, if any
    productchar *The Product attribute from the PPD file, if any
    shortnicknamechar *The ShortNickName attribute from the PPD file, if any
    throughputintNumber of pages per minute
    ttrasterizerchar *The TruType font rasterizer (Type42)
    variable_sizesint1 = supports variable sizes
    + +

    Options and Groups

    + +

    PPD files support multiple options, which are stored in +ppd_option_t and ppd_choice_t structures by +the PPD functions. + +

    Each option in turn is associated with a group +stored in the ppd_group_t 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. + +

    Groups can also have sub-groups; CUPS currently limits the depth of +sub-groups to 1 level to reduce programming complexity. + +

    Conflicts

    + +

    PPD files support specification of conflict conditions between +different options. Conflicts are stored in ppd_conflict_t +structures which specify the options that conflict with each other. + +

    Page Sizes

    + +

    PPD files specify all of the available pages sizes and the physical +margins associated with them. These sizes are stored in +ppd_size_t structures and are available in the +num_sizes and sizes members of the +ppd_file_t structure. You can lookup a particular page size +with the ppdPageWidth(), ppdPageLength(), and +ppdPageSize() functions: + +

      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +ppd_size_t *size;
      +float      width;
      +float      length;
      +
      +...
      +
      +size   = ppdPageSize(ppd, "size");
      +width  = ppdPageWidth(ppd, "size");
      +length = ppdPageLength(ppd, "size");
      +
    + +

    The size string is the named page size option. The +width and length are in points; there are 72 points per inch. The +ppd_size_t structure contains the width, length, and +margin information: + +

      +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;
      +
    + +

    Custom Page Sizes

    + +

    Besides the standard page sizes listed in a PPD file, some printers +support variable or custom page sizes. If variables_sizes +is non-zero, the custom_min, custom_max, and +custom_margins members of the ppd_file_t +structure define the limits of the variable sizes. + +

    To get the resulting media size, use a page size string of +Custom.widthxlength, where width +and length are integer values in points: + +

      +Custom.612x792   [8.5 inches wide, 11 inches long]
      +Custom.1224x792  [17 inches wide, 11 inches long]
      +
    + +

    Marking Options

    + +

    Before marking any user-defined options, call the ppdMarkDefaults() +function to mark the default options from the PPD file: + +

      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +
      +...
      +
      +ppdMarkDefaults(ppd);
      +
    + +

    Then call the ppdMarkOption() function to mark individual +options: + +

      +#include <cups/ppd.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +int        conflicts;
      +
      +...
      +
      +conflicts = ppdMarkOption(ppd, "name", "value");
      +
    + +

    The name and value strings choose a +particular option and choice, respectively. The return value is 0 +if there are not conflicts created by the selection. + +

    CUPS also provides a convenience function for marking all options +in the cups_option_t structure: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +ppd_file_t    *ppd;
      +int           num_options;
      +cups_option_t *options;
      +int           conflicts;
      +
      +...
      +
      +conflicts = cupsMarkOptions(ppd, num_options, options);
      +
    + +

    The cupsMarkOptions() function also handles mapping the +IPP job template attributes to PPD options. The return value is the number +of conflicts present. + +

    Checking for Conflicts

    + +

    The ppdMarkOption() and cupsMarkOptions() +functions return the number of conflicts with the currently marked options. + +

    Call the ppdConflicts() function to get the number of +conflicts after you have marked all of the options: + +

      +#include <cups/cups.h>
      +
      +...
      +
      +ppd_file_t *ppd;
      +int        conflicts;
      +
      +...
      +
      +conflicts = ppdConflicts(ppd);
      +
    + +

    The return value is the number of conflicting options, or 0 if there +are no conflicts. + + +

    3 - Writing Filters

    + +

    This chapter describes how to write a file filter for CUPS. + +

    Overview

    + +

    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. + +

    Security Considerations

    + +

    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. + +

    Users and Groups

    + +

    The default CUPS configuration runs filters as user "lp" and group "other". + +

    Temporary Files

    + +

    Temporary files should be created in the directory specified by the +"TMPDIR" environment variable. The +cupsTempFile() function can be +used to safely choose temporary files in this directory. + +

    Sending Messages to the User

    + +

    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 LogLevel directive. + +

    The type of message is determined by an initial prefix sent on each +line: + +

      + +
    • DEBUG: - a debug message + +
    • INFO: - an informational message + +
    • WARNING: - a warning message + +
    • ERROR: - an error message + +
    • PAGE: - a page accounting message + +
    + +

    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 +printer-state-message attribute for the printer, and also +added to the error_log unless it is an informational or page +accounting message. + +

    Page Accounting

    + +

    Page accounting messages are used to inform the server when one or more +pages are printed. Each line has the form: + +

      +PAGE: page-number copy-count
      +
    + +

    The page-number field is the current page number, starting at 1. +The copy-count field specifies the number of copies of that page +that was produced. + +

    Page account messages are added to the page_log file and +cause the job-sheets-completed attribute to be updated for +the job. + +

    Command-Line Arguments

    + +

    Every filter accepts exactly 6 or 7 command-line arguments: + +

      +printer job user title copies options [filename]
      +
      + +
    • printer - The name of the printer queue (normally + this is the name of the program being run) + +
    • job - The numeric job ID for the job being + printed + +
    • user - The string from the + originating-user-name attribute + +
    • title - The string from the + job-name attribute + +
    • copies - The numeric value from the + number-copies attribute + +
    • options - 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 + +
    • filename - The request file + +
    + +

    The filename argument is only provided to the first filter in the +chain; all filters must be prepared to read the print file from +the standard input if the filename argument is omitted. + +

    Copy Generation

    + +

    The copies argument specifies the number of copies to produce +of the input file. In general, you should only generate copies if the +filename 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 pstops is responsible for copy generation. + +

    Environment Variables

    + +

    Every filter receives a fixed set of environment variables that can +be used by the filter: + +

      + +
    • CHARSET - The character set used by the client for + this print file + +
    • CONTENT_TYPE - The original document type, such as + "application/postscript" + +
    • CUPS_DATADIR - The location of CUPS data files + +
    • CUPS_SERVERROOT - The location of CUPS configuration + files + +
    • DEVICE_URI - The output device URI + +
    • LANG - The language used by the client for + this print file + +
    • PATH - The execution path exported to the filter + +
    • PPD - The full filename of the printer's PPD file + +
    • PRINTER - The name of the printer queue + +
    • RIP_CACHE - The maximum amount of memory each filter + should use + +
    • SOFTWARE - The name of the CUPS software, typically + "CUPS/1.1" + +
    • TZ - The local timezone + +
    • USER - The name of the current user + +
    + +

    Dissecting the HP-GL/2 Filter

    + +

    The HP-GL/2 filter (hpgltops) 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. + +

    Initializing the Filter

    + +

    The first task of any filter is to ensure that the correct number of +command-line arguments are present: + +

      +if (argc < 6 || argc > 7)
      +{
      +  fputs("ERROR: hpgltops job-id user title copies options [file]\n", stderr);
      +  return (1);
      +}
      +
    + +

    After this you open the print file or read from the standard input +as needed: + +

      +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);
      +  }
      +}
      +
    + +

    Once the print file has been opened, options can be processed using +the cupsParseOptions() and +cupsGetOption() functions: + +

      +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;
      +
    + +

    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. + +

    PostScript Output

    + +

    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: + +

      +%!PS-Adobe-3.0
      +%%BoundingBox: left bottom right top
      +%%Pages: (atend)
      +%%EndComments
      +
    + +

    The left, bottom, right, and top values +are integers in points from the lower-lefthand corner of the page. + +

    Pages must be surrounded by: + +

      +%%Page: number number
      +gsave
      +...
      +grestore
      +showpage
      +
    + +

    And the end of each file must contain: + +

      +%%Trailer
      +%%Pages: number-pages
      +%%EOF
      +
    + +

    These comments allow the PostScript filter to correctly perform page +accounting, copy generation, N-up printing, and so forth. + +

    4 - Writing Printer Drivers

    + +

    This chapter discusses how to write a printer driver, which is a +special filter program that converts CUPS raster data into the +appropriate commands and data required for a printer. + +

    Overview

    + +

    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. + +

    CUPS Raster Data

    + +

    CUPS raster data (application/vnd.cups-raster) consists of +a stream of raster page descriptions produced by one of the RIP filters, +such as pstoraster or imagetoraster. + +

    Each page of data begins with a page dictionary structure called +cups_raster_header_t. This +structure contains the colorspace, bits per color, media size, media type, +hardware resolution, and so forth. + +

    After the page dictionary comes the page data which is a full-resolution, +uncompressed bitmap representing the page in the printer's output colorspace. + +

    Page Accounting

    + +

    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. + +

    Color Management

    + +

    Printer drivers can implement their color management via the +cupsColorProfile 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. + +

    For example, the pstoraster 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. + +

    Device and Bitmap Variables

    + +

    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: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    VariableTypeDescription
    cupsWidthread-only integerWidth of bitmap in pixels
    cupsHeightread-only integer Height of bitmap in pixels
    cupsMediaTyperead-write integerDevice-specific media type code
    cupsBitsPerColorread-write integerNumber of bits per color; 1, 2, 4, and 8 are currently + supported
    cupsBitsPerPixelread-only integer Number of bits per pixel; 1 to 32
    cupsBytesPerLineread-only integerNumber of bytes per line of raster graphics
    cupsColorOrderread-write enumThe order of color values in the bitmap: +
      +
    • CUPS_ORDER_CHUNKED - CMYK CMYK CMYK +
    • CUPS_ORDER_BANDED - CCC MMM YYY KKK +
    • CUPS_ORDER_PLANAR - CCC ... MMM ... YYY ... KKK ... +
    +
    cupsColorSpaceread-write enumThe colorspace of the bitmap: +
      +
    • CUPS_CSPACE_W - White (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 - Metallic yellow (gold), metallic magenta, + metallic cyan, black +
    • CUPS_CSPACE_GMCS - Metallic yellow (gold), metallic magenta, + metallic cyan, metallic grey (silver) +
    • CUPS_CSPACE_WHITE - White pigment (black as white pigment) +
    • CUPS_CSPACE_GOLD - Gold foil (black as gold foil) +
    • CUPS_CSPACE_SILVER - Silver foil (black as silver foil) +
    +
    cupsCompressionread-write integerDevice-specific compression type code
    cupsRowCountread-write integerDevice-specific row count value
    cupsRowFeedread-write integerDevice-specific row feed value
    cupsRowStepread-write integerDevice-specific row step value
    + +

    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. + +

    Dissecting the HP-PCL Driver

    + +

    The HP-PCL driver provided with CUPS (rastertohp) 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 - deskjet.ppd or laserjet.ppd. + +

    PPD Files

    + +

    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. + +

    A typical CUPS printer driver will include ColorModel, +InputSlot, PageSize, PageRegion, +and Resolution options. Each option is shown using the +standard PPD format: + +

      +*OpenUI *PageSize/Media Size: PickOne
      +*OrderDependency: 10 AnySetup *PageSize
      +*DefaultPageSize: Letter
      +*PageSize Letter/US Letter: "<<
      +/PageSize [612 792]
      +/ImagingBBox null
      +>> setpagedevice"
      +*End
      +*PageSize Legal/US Legal: "<<
      +/PageSize [612 1008]
      +/ImagingBBox null
      +>> setpagedevice"
      +*End
      +*PageSize A4/A4: "<<
      +/PageSize [595 842]
      +/ImagingBBox null
      +>> setpagedevice"
      +*End
      +*CloseUI: *PageSize
      +
    + +

    The OpenUI 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. + +

    Every option must have a default value, specified using the +DefaultOption keyword. + +

    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: + +

      +*PageSize A4/A4: "<</PageSize[595 842]/ImagingBBox null>> setpagedevice"
      +
    + +

    or broken down on separate lines using the End keyword to +terminate them: + +

      +*PageSize A4/A4: "<<
      +/PageSize [595 842]
      +/ImagingBBox null
      +>> setpagedevice"
      +*End
      +
    + +

    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. + +

    Reading Raster Data

    + +

    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 +cupsRasterOpen() function opens +a raster stream for printing: + +

      +int           fd;   /* File descriptor */
      +cups_raster_t *ras; /* Raster stream for printing */
      +
      +
      +/*
      + * Check for valid arguments...
      + */
      +
      +if (argc < 6 || argc > 7)
      +{
      + /*
      +  * We don't have the correct number of arguments; write an error message
      +  * and return.
      +  */
      +
      +  fputs("ERROR: rastertopcl job-id user title copies options [file]\n", stderr);
      +  return (1);
      +}
      +
      +/*
      + * Open the page stream...
      + */
      +
      +if (argc == 7)
      +{
      +  if ((fd = open(argv[6], O_RDONLY)) == -1)
      +  {
      +    perror("ERROR: Unable to open raster file - ");
      +    sleep(1);
      +    return (1);
      +  }
      +}
      +else
      +  fd = 0;
      +
      +ras = cupsRasterOpen(fd, CUPS_RASTER_READ);
      +
    + +

    Once you have opened the raster stream you just need to read each +page and print it: + +

      +cups_raster_header_t header;
      +int                  y;
      +unsigned char        data[8192];
      +
      +while (cupsRasterReadHeader(ras, &header))
      +{
      +  ... initialize the printer ...
      +  for (y = header.cupsHeight; y > 0; y ++)
      +  {
      +    cupsRasterReadPixels(ras, data, header.cupsBytesPerLine);
      +    ... send raster line to printer ...
      +  }
      +}
      +
    + +

    After you have processed all pages, close the raster stream and +return: + +

      +cupsRasterClose(ras);
      +
      +return (0);
      +
    + +

    5 - Writing Backends

    + +

    This chapter describes how to write a backend for CUPS. Backends +communicate directly with printers and allow printer drivers and +filters to send data using any type of connection transparently. + +

    Overview

    + +

    Backends are special filters that communicate with printers directly. +They are treated slightly differently than filters, however, and have some +unique requirements. + +

    Security Considerations

    + +

    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. + +

    Command-Line Arguments

    + +

    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. + +

    Copy Generation

    + +

    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. + +

    Page Accounting

    + +

    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. + +

    Exclusive Access

    + +

    Backends that talk to local character or block devices should open the +device file in exclusive mode (O_EXCL) to cooperate with other +printers defined for the same device. + +

    Retries

    + +

    All backends must 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. + +

    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. + +

    Dissecting the Serial Port Backend

    + +

    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. + +

    Supporting Device Discovery

    + +

    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...) + +

    The serial backend lists devices by looking at serial port files in the +/dev directory, by consulting a hardware inventory (IRIX), and +in some cases by trying to open the ports to see if they actually exist. + +

    Once it finds a serial port it writes a single line for each port to +the standard error file. Each line looks like this: + +

      +serial serial:/dev/ttyS0?baud=115200 "Unknown" "Serial Port 1"
      +
    + +

    The first word "serial" is the device class; this identifies the +class of device which can be used to categorize it in user interfaces. CUPS +currently recognizes the following classes: + +

      + +
    • "file" - a disk file. + +
    • "direct" - a parallel or fixed-rate serial data port, + currently used for Centronics, IEEE-1284, and USB printer + ports. + +
    • "serial" - a variable-rate serial port. + +
    • "network" - a network connection, typically via AppSocket, + HTTP, IPP, LPD, or SMB/CIFS protocols. + +
    + +

    After the device class is the device URI, 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. + +

    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. + +

    Opening the Serial Port

    + +

    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 do-while loop: + +

      +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 < 0);
      +
    + +

    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. + +

    Writing Data to the Port

    + +

    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: + +

      +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;
      +}
      +
    + +

    The check for the ENOTTY error is needed on some platforms +to clear an error from a previous ioctl() call. + +

    Finishing Up

    + +

    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. + +

    A - Software License Agreement

    + + + + +

    B - Constants

    + +

    This appendix lists all of the constants that are defined by the CUPS +API. + +

    CUPS Constants

    + +

    Version Number

    + +

    The CUPS_VERSION 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. + +

    Printer Capabilities

    + +

    The CUPS_PRINTER constants represent capability bits for +printers and classes: + +

      + +
    • CUPS_PRINTER_LOCAL - Is a local printer or class. + +
    • CUPS_PRINTER_REMOTE - Is a remote printer or class. + +
    • CUPS_PRINTER_CLASS - Is a class. + +
    • CUPS_PRINTER_BW - Printer prints in black and white. + +
    • CUPS_PRINTER_COLOR - Printer prints in color. + +
    • CUPS_PRINTER_DUPLEX - Printer can print double-sided. + +
    • CUPS_PRINTER_STAPLE - Printer can staple output. + +
    • CUPS_PRINTER_COPIES - Printer can produce multiple + copies on its own. + +
    • CUPS_PRINTER_COLLATE - Printer can collate copies. + +
    • CUPS_PRINTER_PUNCH - Printer can punch holes in output. + +
    • CUPS_PRINTER_COVER - Printer can put covers on output. + +
    • CUPS_PRINTER_BIND - Printer can bind output. + +
    • CUPS_PRINTER_SORT - Printer can sort output. + +
    • CUPS_PRINTER_SMALL - Printer can print on media up + to 9x14 inches. + +
    • CUPS_PRINTER_MEDIUM - Printer can print on media + from 9x14 to 18x24 inches. + +
    • CUPS_PRINTER_LARGE - Printer can print on media + larger than 18x24 inches. + +
    • CUPS_PRINTER_VARIABLE - Printer can print on + variable or custom media sizes. + +
    • CUPS_PRINTER_IMPLICIT - Is an implicit class. + +
    • CUPS_PRINTER_OPTIONS - All of the printer capability + and option bits. + +
    + +

    Encodings

    + +

    CUPS defines the following character set encoding constants: + +

      + +
    • CUPS_US_ASCII - US ASCII character set. + +
    • CUPS_UTF_8 - UTF-8 encoding of Unicode. + +
    • CUPS_ISO8859_1 - ISO-8859-1 character set. + +
    • CUPS_ISO8859_2 - ISO-8859-2 character set. + +
    • CUPS_ISO8859_3 - ISO-8859-3 character set. + +
    • CUPS_ISO8859_4 - ISO-8859-4 character set. + +
    • CUPS_ISO8859_5 - ISO-8859-5 character set. + +
    • CUPS_ISO8859_6 - ISO-8859-6 character set. + +
    • CUPS_ISO8859_7 - ISO-8859-7 character set. + +
    • CUPS_ISO8859_8 - ISO-8859-8 character set. + +
    • CUPS_ISO8859_9 - ISO-8859-9 character set. + +
    • CUPS_ISO8859_10 - ISO-8859-10 character set. + +
    • CUPS_ISO8859_13 - ISO-8859-13 character set. + +
    • CUPS_ISO8859_14 - ISO-8859-14 character set. + +
    • CUPS_ISO8859_15 - ISO-8859-15 character set. + +
    • CUPS_WINDOWS_874 - Windows code page 874. + +
    • CUPS_WINDOWS_1250 - Windows code page 1250. + +
    • CUPS_WINDOWS_1251 - Windows code page 1251. + +
    • CUPS_WINDOWS_1252 - Windows code page 1252. + +
    • CUPS_WINDOWS_1253 - Windows code page 1253. + +
    • CUPS_WINDOWS_1254 - Windows code page 1254. + +
    • CUPS_WINDOWS_1255 - Windows code page 1255. + +
    • CUPS_WINDOWS_1256 - Windows code page 1256. + +
    • CUPS_WINDOWS_1257 - Windows code page 1257. + +
    • CUPS_WINDOWS_1258 - Windows code page 1258. + +
    • CUPS_KOI8_R - Russian code page koi8-r. + +
    • CUPS_KOI8_U - Ukrainian code page koi8-r. + +
    + +

    HTTP Constants

    + +

    Limits

    + +

    The following constants define the limits for strings: + +

      + +
    • HTTP_MAX_BUFFER - Size of socket buffer. + +
    • HTTP_MAX_HOST - Maximum length of hostname. + +
    • HTTP_MAX_URI - Maximum length of URI. + +
    • HTTP_MAX_VALUE - Maximum length of field values. + +
    + +

    Status Codes

    + +

    The following status codes can be returned by httpUpdate(): + +

      + +
    • HTTP_ERROR - A network error occurred + +
    • HTTP_CONTINUE - Continue response from HTTP proxy + +
    • HTTP_OK - 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 + +
    • HTTP_RESET_CONTENT - Content was reset/recreated + +
    • HTTP_PARTIAL_CONTENT - Only a partial file was recieved/sent + +
    • HTTP_MULTIPLE_CHOICES - 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 - Bad request + +
    • HTTP_UNAUTHORIZED - Unauthorized to access host + +
    • HTTP_PAYMENT_REQUIRED - Payment required + +
    • HTTP_FORBIDDEN - Forbidden to access this URI + +
    • HTTP_NOT_FOUND - URI was not found + +
    • HTTP_METHOD_NOT_ALLOWED - Method is not allowed + +
    • HTTP_NOT_ACCEPTABLE - Not Acceptable + +
    • HTTP_PROXY_AUTHENTICATION - Proxy Authentication is Required + +
    • HTTP_REQUEST_TIMEOUT - Request timed out + +
    • HTTP_CONFLICT - Request is self-conflicting + +
    • HTTP_GONE - Server has gone away + +
    • HTTP_LENGTH_REQUIRED - A content length or encoding is required + +
    • HTTP_PRECONDITION - Precondition failed + +
    • HTTP_REQUEST_TOO_LARGE - Request entity too large + +
    • HTTP_URI_TOO_LONG - URI too long + +
    • HTTP_UNSUPPORTED_MEDIATYPE - The requested media type is unsupported + +
    • HTTP_SERVER_ERROR - 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 + +
    + +

    Fields

    + +

    The following fields are indices for each of the standard HTTP fields in +HTTP 1/1: + +

      + +
    • HTTP_FIELD_ACCEPT_LANGUAGE - Accept-Language + +
    • HTTP_FIELD_ACCEPT_RANGES - Accept-Ranges + +
    • HTTP_FIELD_AUTHORIZATION - Authorization + +
    • HTTP_FIELD_CONNECTION - Connection + +
    • HTTP_FIELD_CONTENT_ENCODING - Content-Encoding + +
    • HTTP_FIELD_CONTENT_LANGUAGE - Content-Language + +
    • HTTP_FIELD_CONTENT_LENGTH - Content-Length + +
    • HTTP_FIELD_CONTENT_LOCATION - Content-Location + +
    • HTTP_FIELD_CONTENT_MD5 - Content-MD5 + +
    • HTTP_FIELD_CONTENT_RANGE - Content-Range + +
    • HTTP_FIELD_CONTENT_TYPE - Content-Type + +
    • HTTP_FIELD_CONTENT_VERSION - Content-Version + +
    • HTTP_FIELD_DATE - Date + +
    • HTTP_FIELD_HOST - Host + +
    • HTTP_FIELD_IF_MODIFIED_SINCE - If-Modified-Since + +
    • HTTP_FIELD_IF_UNMODIFIED_SINCE - If-Unmodified-Since + +
    • HTTP_FIELD_KEEP_ALIVE - Keep-Alive + +
    • HTTP_FIELD_LAST_MODIFIED - Last-Modified + +
    • HTTP_FIELD_LINK - Link + +
    • HTTP_FIELD_LOCATION - Location + +
    • HTTP_FIELD_RANGE - Range + +
    • HTTP_FIELD_REFERER - Referer + +
    • HTTP_FIELD_RETRY_AFTER - Retry-After + +
    • HTTP_FIELD_TRANSFER_ENCODING - Transfer-Encoding + +
    • HTTP_FIELD_UPGRADE - Upgrade + +
    • HTTP_FIELD_USER_AGENT - User-Agent + +
    • HTTP_FIELD_WWW_AUTHENTICATE - WWW-Authenticate + + +
    + +

    IPP Constants

    + +

    Limits

    + +

    The following constants define array limits for IPP data: + +

      + +
    • IPP_MAX_NAME - Maximum length of an attribute name + +
    • IPP_MAX_VALUES - Maximum number of set-of values + that can be read in a request. + +
    + +

    Tags

    + +
      + +
    • IPP_TAG_ZERO - Wildcard tag value for searches; also + used to separate groups of attributes + +
    • IPP_TAG_OPERATION - Tag for values of type operation + +
    • IPP_TAG_JOB - Tag for values of type job + +
    • IPP_TAG_END - Tag for values of type end + +
    • IPP_TAG_PRINTER - Tag for values of type printer + +
    • IPP_TAG_UNSUPPORTED_GROUP - Tag for values of type unsupported_group + +
    • IPP_TAG_UNSUPPORTED_VALUE - Tag for values of type unsupported_value + +
    • IPP_TAG_DEFAULT - Tag for values of type default + +
    • IPP_TAG_UNKNOWN - Tag for values of type unknown + +
    • IPP_TAG_NOVALUE - Tag for values of type novalue + +
    • IPP_TAG_NOTSETTABLE - Tag for values of type notsettable + +
    • IPP_TAG_DELETEATTR - Tag for values of type deleteattr + +
    • IPP_TAG_ANYVALUE - Tag for values of type anyvalue + +
    • IPP_TAG_INTEGER - Tag for values of type integer + +
    • IPP_TAG_BOOLEAN - Tag for values of type boolean + +
    • IPP_TAG_ENUM - Tag for values of type enum + +
    • IPP_TAG_STRING - Tag for values of type string + +
    • IPP_TAG_DATE - Tag for values of type date + +
    • IPP_TAG_RESOLUTION - Tag for values of type resolution + +
    • IPP_TAG_RANGE - Tag for values of type range + +
    • IPP_TAG_COLLECTION - Tag for values of type collection + +
    • IPP_TAG_TEXTLANG - Tag for values of type textlang + +
    • IPP_TAG_NAMELANG - Tag for values of type namelang + +
    • IPP_TAG_TEXT - Tag for values of type text + +
    • IPP_TAG_NAME - Tag for values of type name + +
    • IPP_TAG_KEYWORD - Tag for values of type keyword + +
    • IPP_TAG_URI - Tag for values of type uri + +
    • IPP_TAG_URISCHEME - Tag for values of type urischeme + +
    • IPP_TAG_CHARSET - Tag for values of type charset + +
    • IPP_TAG_LANGUAGE - Tag for values of type language + +
    • IPP_TAG_MIMETYPE - Tag for values of type mimetype + +
    + +

    Resolution Units

    + +

    The IPP_RES_PER_INCH and IPP_RES_PER_CM constants +specify dots per inch and dots per centimeter, respectively. + +

    Finishings

    + +

    The finishing values specify special finishing operations to be +performed on the job. + +

      + +
    • IPP_FINISH_NONE - Do no finishing + +
    • IPP_FINISH_STAPLE - Staple the job + +
    • IPP_FINISH_PUNCH - Punch the job + +
    • IPP_FINISH_COVER - Cover the job + +
    • IPP_FINISH_BIND - Bind the job + +
    + +

    Orientations

    + +

    The orientation values specify the orientation of the job. + +

      + +
    • IPP_PORTRAIT - No rotation + +
    • IPP_LANDSCAPE - 90 degrees counter-clockwise + +
    • IPP_REVERSE_LANDSCAPE - 90 degrees clockwise + +
    • IPP_REVERSE_PORTRAIT - 180 degrees + +
    + +

    Qualities

    + +

    The quality values specify the desired quality of the print. +

      + +
    • IPP_QUALITY_DRAFT - Draft quality + +
    • IPP_QUALITY_NORMAL - Normal quality + +
    • IPP_QUALITY_HIGH - High quality + +
    + +

    Job States

    + +

    The job state values are used to represent the current job state. + +

      + +
    • IPP_JOB_PENDING - Job is pending + +
    • IPP_JOB_HELD - Job is held + +
    • IPP_JOB_PROCESSING - Job is processing + +
    • IPP_JOB_STOPPED - Job is stopped + +
    • IPP_JOB_CANCELLED - Job is cancelled + +
    • IPP_JOB_ABORTED - Job is aborted + +
    • IPP_JOB_COMPLETED - Job is completed + +
    + +

    Printer States

    + +

    The printer state values are used to represent the current printer +state. + +

      + +
    • IPP_PRINTER_IDLE - Printer is idle + +
    • IPP_PRINTER_PROCESSING - Printer is processing + +
    • IPP_PRINTER_STOPPED - Printer is stopped + +
    + +

    Operations

    + +

    The operation values represent the available IPP operations. + +

      + +
    • IPP_PRINT_JOB - Print a file + +
    • IPP_PRINT_URI - Print a URI + +
    • IPP_VALIDATE_JOB - Validate job attributes + +
    • IPP_CREATE_JOB - Create a new job + +
    • IPP_SEND_DOCUMENT - Send a document to a job + +
    • IPP_SEND_URI - Send a URI to a job + +
    • IPP_CANCEL_JOB - Cancel a job + +
    • IPP_GET_JOB_ATTRIBUTES - Get job attributes + +
    • IPP_GET_JOBS - Get a list of all jobs + +
    • IPP_GET_PRINTER_ATTRIBUTES - Get printer attributes + +
    • IPP_HOLD_JOB - Hold a pending job + +
    • IPP_RELEASE_JOB - Release a held job + +
    • IPP_RESTART_JOB - Restart a completed job + +
    • IPP_PAUSE_PRINTER - Pause a printer + +
    • IPP_RESUME_PRINTER - Restart a paused printer + +
    • IPP_PURGE_JOBS - Purge jobs from the queue + +
    • IPP_SET_PRINTER_ATTRIBUTES - Set printer attributes + +
    • IPP_SET_JOB_ATTRIBUTES - Set job attributes + +
    • IPP_GET_PRINTER_SUPPORTED_VALUES - Get printer supported values + +
    • CUPS_GET_DEFAULT - Get the default destination + +
    • CUPS_GET_PRINTERS - Get a list of all printers + +
    • CUPS_ADD_PRINTER - Add or modify a printer + +
    • CUPS_DELETE_PRINTER - Delete a printer + +
    • CUPS_GET_CLASSES - Get a list of all classes + +
    • CUPS_ADD_CLASS - Add or modify a class + +
    • CUPS_DELETE_CLASS - Delete a class + +
    • CUPS_ACCEPT_JOBS - Accept jobs on a printer or class + +
    • CUPS_REJECT_JOBS - Reject jobs on a printer or class + +
    • CUPS_SET_DEFAULT - Set the default destination + +
    • CUPS_GET_DEVICES - Get a list of all devices + +
    • CUPS_GET_PPDS - Get a list of all PPDs + +
    • CUPS_MOVE_JOB - Move a job to a new destination + +
    + +

    Status Codes

    + +

    Status codes are returned by all IPP requests. + +

      + +
    • IPP_OK - Request completed with no errors + +
    • IPP_OK_SUBST - Request completed but some attribute + values were substituted + +
    • IPP_OK_CONFLICT - Request completed but some attributes + conflicted + +
    • IPP_BAD_REQUEST - The request was bad + +
    • IPP_FORBIDDEN - You don't have access to the resource + +
    • IPP_NOT_AUTHENTICATED - You are not authenticated for + the resource + +
    • IPP_NOT_AUTHORIZED - You not authorized to access + the resource + +
    • IPP_NOT_POSSIBLE - The requested operation cannot be + completed + +
    • IPP_TIMEOUT - A timeout occurred + +
    • IPP_NOT_FOUND - The resource was not found + +
    • IPP_GONE - The resource has gone away + +
    • IPP_REQUEST_ENTITY - The request was too large + +
    • IPP_REQUEST_VALUE - The request contained a value + that was unknown to the server + +
    • IPP_DOCUMENT_FORMAT - The document format is not + supported by the server + +
    • IPP_ATTRIBUTES - Required attributes are missing + +
    • IPP_URI_SCHEME - The URI scheme is not supported + +
    • IPP_CHARSET - The charset is not supported + +
    • IPP_CONFLICT - One or more attributes conflict + +
    • IPP_COMPRESSION_NOT_SUPPORTED - The specified + compression is not supported + +
    • IPP_COMPRESSION_ERROR - The compressed data + contained an error + +
    • IPP_DOCUMENT_FORMAT_ERROR - The document data + contained an error in it + +
    • IPP_DOCUMENT_ACCESS_ERROR - The remote document + could not be accessed + +
    • IPP_INTERNAL_ERROR - The server encountered an + internal error + +
    • IPP_OPERATION_NOT_SUPPORTED - The requested operation + is not supported + +
    • IPP_SERVICE_UNAVAILABLE - The requested service + is unavailable + +
    • IPP_VERSION_NOT_SUPPORTED - The IPP request + version is not supported + +
    • IPP_DEVICE_ERROR - The output device encountered + an error + +
    • IPP_TEMPORARY_ERROR - A temporary error occurred + +
    • IPP_NOT_ACCEPTING - The destination is not accepting + jobs + +
    • IPP_PRINTER_BUSY - The destination is busy + +
    • IPP_ERROR_JOB_CANCELLED - The requested job has been + cancelled + +
    • IPP_MULTIPLE_JOBS_NOT_SUPPORTED - The server + does not support multiple jobs + +
    + +

    PPD Constants

    + +

    PPD Format Version

    + +

    The PPD_VERSION constant defines a floating point number +representing the newest format version that is supported by CUPS, currently +4.3. + +

    PPD User-Interface Types

    + +

    Each printer option has a type associated with it: + +

      + +
    • PPD_UI_BOOLEAN - The user can turn this option on or off + +
    • PPD_UI_PICKONE - The user can choose one option value + to use. + +
    • PPD_UI_PICKMANY - The user can choose zero or more + option values. + +
    + +

    PPD Sections

    + +

    Some options must be output before others, or in different sections of +the output document. The ppd_section_t enumeration defines +which section the option must be output in: + +

      + +
    • PPD_ORDER_ANY - The option can be output in any of + the document, page, or prolog sections of the document + +
    • PPD_ORDER_DOCUMENT - The option must be output in + the DocumentSetup section of the document + +
    • PPD_ORDER_EXIT - The option must be output before + the document + +
    • PPD_ORDER_JCL - The option must be output in the + job control section of the document + +
    • PPD_ORDER_PAGE - The option must be output in the + PageSetup section of the document + +
    • PPD_ORDER_PROLOG - The option must be output in the + Prolog section of the document + +
    + +

    PPD Colorspaces

    + +

    Each printer has a default colorspace: + +

      + +
    • PPD_CS_CMYK - The printer uses CMYK colors by default + +
    • PPD_CS_CMY - The printer uses CMY colors by default + +
    • PPD_CS_GRAY - The printer uses grayscale by default + +
    • PPD_CS_RGB - The printer uses RGB colors by default + +
    • PPD_CS_RGBK - The printer uses RGBK colors by default + +
    • PPD_CS_N - The printer uses a DeviceN colorspace + by default + +
    + +

    Raster Constants

    + +

    Raster Sync Words

    + +

    The CUPS_RASTER_SYNC and CUPS_RASTER_REVSYNC +constants define the standard sync words at the beginning of each CUPS +raster file. + +

    Raster Stream Modes

    + +

    The CUPS_RASTER_READ and CUPS_RASTER_WRITE +constants are used with the +cupsRasterOpen() function to +specify a stream for reading or writing. + +

    Raster Boolean Constants

    + +

    The CUPS_FALSE and CUPS_TRUE constants +represent boolean values in the page header. + +

    Raster Jog Values

    + +

    The cups_jog_t enumeration defines constants for the +Jog page device dictionary variable: + +

      + +
    • CUPS_JOG_NONE - Do no jogging + +
    • CUPS_JOG_FILE - Jog pages after each file + +
    • CUPS_JOG_JOB - Jog pages after each job + +
    • CUPS_JOG_SET - Jog pages after each set of jobs + +
    + +

    Raster Orientation Values

    + +

    The cups_orient_t enumeration defines constants for the +Orientation page device dictionary variable: + +

      + +
    • CUPS_ORIENT_0 - Portrait orientation + +
    • CUPS_ORIENT_90 - Landscape orientation + +
    • CUPS_ORIENT_180 - Reverse-portrait orientation + +
    • CUPS_ORIENT_270 - Reverse-landscape orientation + +
    + +

    Raster CutMedia Values

    + +

    The cups_cut_t enumeration defines constants for the +CutMedia page device dictionary variable: + +

      + +
    • CUPS_CUT_NONE - Do no jogging + +
    • CUPS_CUT_FILE - Cut pages after each file + +
    • CUPS_CUT_JOB - Cut pages after each job + +
    • CUPS_CUT_SET - Cut pages after each set of jobs + +
    • CUPS_CUT_PAGE - Cut each page + +
    + +

    Raster AdvanceMedia Values

    + +

    The cups_advance_t enumeration defines constants for the +AdvanceMedia page device dictionary variable: + +

      + +
    • CUPS_ADVANCE_NONE - Do no jogging + +
    • CUPS_ADVANCE_FILE - Advance media after each file + +
    • CUPS_ADVANCE_JOB - Advance media after each job + +
    • CUPS_ADVANCE_SET - Advance media after each set of jobs + +
    • CUPS_ADVANCE_PAGE - Advance media for each page + +
    + +

    Raster LeadingEdge Values

    + +

    The cups_edge_t enumeration defines constants for the +LeadingEdge page device dictionary variable: + +

      + +
    • CUPS_EDGE_TOP - The top of the media is the leading + edge + +
    • CUPS_EDGE_RIGHT - The right of the media is the leading + edge + +
    • CUPS_EDGE_BOTTOM - The bottom of the media is the + leading edge + +
    • CUPS_EDGE_LEFT - The left of the media is the leading + edge + +
    + +

    Raster Color Order Values

    + +

    The cups_order_t enumeration defines the possible color +value orderings: + +

      + +
    • CUPS_ORDER_CHUNKED - CMYK CMYK CMYK + +
    • CUPS_ORDER_BANDED - CCC MMM YYY KKK + +
    • CUPS_ORDER_PLANAR - CCC ... MMM ... YYY ... KKK ... + +
    + +

    Raster Colorspace Values

    + +

    The cups_cspace_t enumeration defines the possible colorspaces: + +

      + +
    • CUPS_CSPACE_W - White (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 - Metallic yellow (gold), metallic magenta, + metallic cyan, black + +
    • CUPS_CSPACE_GMCS - Metallic yellow (gold), metallic magenta, + metallic cyan, metallic grey (silver) + +
    • CUPS_CSPACE_WHITE - White pigment (black as white pigment) + +
    • CUPS_CSPACE_GOLD - Gold foil (black as gold foil) + +
    • CUPS_CSPACE_SILVER - Silver foil (black as silver foil) + +
    + +

    C - Structures

    + +

    This appendix describes all of the structures that are +defined by the CUPS API. + +

    CUPS Structures

    + +

    CUPS Destinations

    + +

    The CUPS destination structure (cups_dest_t) +contains information on a specific destination or instance: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    namechar *The name of the printer or class.
    instancechar *The instance of the printer or class; NULL for the primary + instance.
    is_defaultint1 if the destination is set as the default, 0 otherwise.
    num_optionsintThe number of options associated with this destination.
    optionscups_option_t *The options associated with this destination.
    + +

    CUPS Jobs

    + +

    The CUPS job structure (cups_job_t) contains +information on a specific job: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    idintThe job ID for this job.
    destchar *The destination for this job (printer or class name).
    titlechar *The job-name for this job (title).
    userchar *The job-originating-user-name for this job (username).
    formatchar *The document-format for this job (MIME type string).
    stateipp_jstateThe current state of the job.
    sizeintThe size of this job in kilobytes.
    priorityintThe priority of this job from 1 to 100 (50 is normal).
    completed_timetime_tThe time the job was completed, or 0 if not yet completed.
    creation_timetime_tThe time the job was queued.
    processing_timetime_tThe time the job started printing.
    + +

    CUPS Messages

    + +

    The CUPS messages structure (cups_lang_t) +contains the character set, locale name, and messages array: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    nextcups_lang_t *Pointer to the next messages structure in memory.
    usedintThe number of active users of this messages structure.
    encodingcups_encoding_tThe character encoding of the message strings.
    languagechar [16]The language/locale name.
    messageschar *[]The array of message strings.
    + +

    CUPS Options

    + +

    The CUPS option structure (cups_option_t) +contains the option name and string value: + +

    + + + + + + + + + + + + + + + +
    MemberTypeDescription
    namechar *The name of the option.
    valuechar *The string value of the option.
    + +

    Networking Structures

    + +

    HTTP State

    + +

    The HTTP state structure (http_t) contains the +current state of a HTTP request or response: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    fdintThe socket for the HTTP connection.
    blockingint1 if the HTTP functions should block, 0 if not.
    errorintThe last OS error that occurred on the socket.
    activitytime_tThe last time the HTTP connection was used.
    statehttp_state_tThe current HTTP request/response state.
    statusintThe last HTTP status seen.
    versionhttp_version_tThe HTTP protocol version in use.
    keep_alivehttp_keep_alive_tWhether or not to use Keep-Alive
    hostaddrstruct sockaddr_inThe IPv4 address of the HTTP server.
    hostnamechar []The hostname of the HTTP server.
    fieldschar [][]The string values of all HTTP request/response + fields.
    datachar *Current byte in data buffer.
    data_encodinghttp_encoding_tThe transfer encoding for the request/response.
    data_remainingintThe number of bytes remaining in the current request, + response, or chunk.
    usedintThe number of bytes that are used in the buffer.
    bufferchar []The read/write buffer.
    auth_typeintThe type of authentication in use.
    md5_statemd5_state_tThe current MD5 digest state.
    noncechar []The nonce value for Digest authentication.
    nonce_countintThe nonce count value.
    tlsvoid *A pointer to private encryption data.
    encryptionhttp_encryption_tThe current encryption mode.
    + +

    IPP State

    + +

    The IPP state structure (ipp_t) contains the +current state of a IPP request or response: + +

    + + + + + + + + + + +
    MemberTypeDescription
    + +

    Raster Structures

    + +

    Raster Page Header

    + +

    The raster page header (cups_raster_header_t) +consists of the PostScript page device dictionary for the page: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    MemberTypeDescription
    MediaClasschar[64]The media class name
    MediaColorchar[64]The media color name
    MediaTypechar[64]The media type name
    OutputTypechar[64]The output type name
    AdvanceDistanceunsignedThe distance to advance the media in points
    AdvanceMediacups_adv_tWhen to advance the media
    Collatecups_bool_tWhether or not to produce collated copies
    CutMediacups_cut_tWhen to cut the media
    Duplexcups_bool_tWhether or not to print on both sides of the paper
    HWResolutionunsigned[2]The resolution of the page image in pixels per inch; the + HWResolution[0] represents the horizontal resolution and + HWResolution[1] represents the vertical resolution
    ImagingBoundingBoxunsigned[4]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)
    InsertSheetcups_bool_tWhether or not to insert a sheet before this page
    Jogcups_jog_tWhen to jog copies of the page
    LeadingEdgecups_edge_tThe leading edge of the page
    Marginsunsigned[2]The lower-lefthand margin of the page in points
    ManualFeedcups_bool_tWhether or not to manually feed the page
    MediaPositionunsignedThe input slot number to use
    MediaWeightunsignedThe weight of the output media in grams/m2
    MirrorPrintcups_bool_tWhether or not to mirror the print
    NegativePrintcups_bool_tWhether or not to invert the print
    NumCopiesunsignedThe number of copies to produce
    Orientationcups_orient_tThe orientation of the page image
    OutputFaceUpcups_bool_tWhether or not to output the page face up
    PageSizeunsigned[2]The width and height of the page in points
    Separationscups_bool_tWhether or not to output separations
    TraySwitchcups_bool_tWhether or not to automatically switch trays for the requested + media size/type
    Tumblecups_bool_tWhether or not to rotate the back side of the page
    cupsWidthunsignedThe width of the page image in pixels
    cupsHeightunsignedThe height of the page image in pixels
    cupsMediaTypeunsignedThe device-specific media type code
    cupsBitsPerColorunsignedThe number of bits per color
    cupsBitsPerPixelunsignedThe number of bits per pixel
    cupsBytesPerLineunsignedThe number of bytes per line of image data
    cupsColorOrdercups_order_tThe order of color values
    cupsColorSpacecups_cspace_tThe type of color values
    cupsCompressionunsignedThe device-specific compression code
    cupsRowCountunsignedThe device-specific row count
    cupsRowFeedunsignedThe device-specific row feed
    cupsRowStepunsignedThe device-specific row step
    + +

    D - Functions

    + +

    This appendix provides a reference for all of the CUPS API functions. + + +

    cupsAddDest()

    + +

    Usage

    + +
    +int
    +cupsAddDest(const char  *name,
    +            const char  *instance,
    +            int         num_dests,
    +	    cups_dest_t **dests);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    nameThe name of the destination.
    instanceThe instance of the destination, or NULL for the primary instance.
    num_destsThe number of destinations in the array.
    destA pointer to the destination array pointer.
    + +

    Returns

    + +

    The new number of destinations in the array. + +

    Description

    + +

    cupsAddDest() adds the named destination to the destination +array if it does not already exist. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +
    +
    +num_dests = cupsAddDests("foo", "bar", num_dests, &dests);
    +
    + +

    See Also

    + +

    +cupsFreeDests(), +cupsGetDest(), +cupsGetDests() + + +

    cupsAddOption()

    + +

    Usage

    + +
    +int
    +cupsAddOption(const char    *name,
    +              const char    *value,
    +              int           num_options,
    +	      cups_option_t **options);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    nameThe name of the option.
    valueThe value of the option.
    num_optionsNumber of options currently in the array.
    optionsPointer to the options array.
    + +

    Returns

    + +

    The new number of options. + +

    Description

    + +

    cupsAddOption() adds an option to the specified array. + +

    Example

    + +
    +#include <cups.h>
    +
    +...
    +
    +/* Declare the options array */
    +int           num_options;
    +cups_option_t *options;
    +
    +/* Initialize the options array */
    +num_options = 0;
    +options     = (cups_option_t *)0;
    +
    +/* Add options using cupsAddOption() */
    +num_options = cupsAddOption("media", "letter", num_options, &options);
    +num_options = cupsAddOption("resolution", "300dpi", num_options, &options);
    +
    + +

    See Also

    + +cupsEncodeOptions(), +cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + + +

    cupsCancelJob()

    + +

    Usage

    + +
    +int
    +cupsCancelJob(const char *dest,
    +              int        job);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    destPrinter or class name
    jobJob ID
    + +

    Returns

    + +

    1 on success, 0 on failure. On failure the error can be found by calling +cupsLastError(). + +

    Description

    + +

    cupsCancelJob() cancels the specifies job. + +

    Example

    + +
    +#include <cups.h>
    +
    +cupsCancelJob("LaserJet", 1);
    +
    + +

    See Also

    + +

    +cupsLastError(), +cupsPrintFile(), +cupsPrintFiles() + + +

    cupsDoFileRequest()

    + +

    Usage

    + +
    +ipp_t *
    +cupsDoFileRequest(http_t     *http,
    +                  ipp_t      *request,
    +                  const char *resource,
    +		  const char *filename);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    httpHTTP connection to server.
    requestIPP request data.
    resourceHTTP resource name for POST.
    filenameFile to send with POST request (NULL pointer if none.)
    + +

    Returns

    + +

    IPP response data or NULL if the request fails. On failure +the error can be found by calling +cupsLastError(). + +

    Description

    + +

    cupsDoFileRequest() does a HTTP POST request and provides the +IPP request and optionally the contents of a file to the IPP server. It also +handles resubmitting the request and performing password authentication as +needed. + +

    Example

    + +
    +#include <cups.h>
    +
    +http_t      *http;
    +cups_lang_t *language;
    +ipp_t       *request;
    +ipp_t       *response;
    +
    +...
    +
    +/* Get the default language */
    +language = cupsLangDefault();
    +
    +/* Create a new IPP request */
    +request  = ippNew();
    +
    +request->request.op.operation_id = IPP_PRINT_FILE;
    +request->request.op.request_id   = 1;
    +
    +/* Add required attributes */
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
    +             "attributes-charset", NULL, cupsLangEncoding(language));
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
    +             "attributes-natural-language", NULL,
    +             language != NULL ? language->language : "C");
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    +             NULL, "ipp://hostname/resource");
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name",
    +             NULL, cupsUser());
    +
    +/* Do the request... */
    +response = cupsDoFileRequest(http, request, "/resource", "filename.txt");
    +
    + +

    See Also

    + +

    +cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), +httpConnect(), +ippAddString(), +ippNew() + + +

    cupsDoRequest()

    + +

    Usage

    + +
    +ipp_t *
    +cupsDoRequest(http_t *http,
    +              ipp_t *request,
    +              const char *resource);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    httpHTTP connection to server.
    requestIPP request data.
    resourceHTTP resource name for POST.
    + +

    Returns

    + +

    IPP response data or NULL if the request fails. On failure +the error can be found by calling +cupsLastError(). + +

    Description

    + +

    cupsDoRequest() does a HTTP POST request and provides +the IPP request to the IPP server. It also handles resubmitting the +request and performing password authentication as needed. + +

    Example

    + +
    +#include <cups.h>
    +
    +http_t      *http;
    +cups_lang_t *language;
    +ipp_t       *request;
    +ipp_t       *response;
    +
    +...
    +
    +/* Get the default language */
    +language = cupsLangDefault();
    +
    +/* Create a new IPP request */
    +request  = ippNew();
    +
    +request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES;
    +request->request.op.request_id   = 1;
    +
    +/* Add required attributes */
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET,
    +             "attributes-charset", NULL, cupsLangEncoding(language));
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE,
    +             "attributes-natural-language", NULL,
    +             language != NULL ? language->language : "C");
    +
    +ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri",
    +             NULL, "ipp://hostname/resource");
    +
    +/* Do the request... */
    +response = cupsDoRequest(http, request, "/resource");
    +
    + +

    See Also

    + +

    +cupsLangDefault(), +cupsLangEncoding(), +cupsUser(), +httpConnect(), +ippAddString(), +ippNew() + + +

    cupsEncodeOptions()

    + +

    Usage

    + +
    +void
    +cupsEncodeOptions(ipp_t         *ipp,
    +                  int           num_options,
    +		  cups_option_t *options);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request.
    num_optionsThe number of options.
    optionsThe options.
    + +

    Description

    + +

    cupsEncodeOptions() encodes all of the options +in the specified array as IPP attributes and adds them to the +IPP request. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +ipp_t         *ipp;
    +int           num_options;
    +cups_option_t *options;
    +
    +
    +cupsEncodeOptions(ipp, num_options, options);
    +
    + +

    See Also

    + +

    +cupsAddOption(), +cupsParseOptions(), +ippNew() + + +

    cupsEncryption()

    + +

    Usage

    + +
    +http_encryption_t
    +cupsEncryption(void);
    +
    + +

    Returns

    + +

    The current encryption setting. + +

    Description

    + +

    cupsEncryption() returns the current encryption setting +for IPP requests such as printing. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +http_t *http;
    +
    +printf("The current encryption setting is %d.\n", cupsEncryption());
    +
    +http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
    +
    + +

    See Also

    + +

    +cupsServer(), +httpConnectEncrypt(), +ippPort() + + +

    cupsFreeDests()

    + +

    Usage

    + +
    +void
    +cupsFreeDests(int         num_dests,
    +              cups_dest_t *dests);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    num_destsThe number of destinations in the array.
    destsThe destination array.
    + +

    Description

    + +

    cupsFreeDests() frees a destination array that was +created using cupsGetDests(). + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *dest;
    +
    +num_dests = cupsGetDests(&dests);
    +dest      = cupsGetDest(NULL, NULL, num_dests, dests);
    +
    +if (dest)
    +  printf("The default destination is %s\n", dest->name);
    +else
    +  puts("No default destination.");
    +
    +cupsFreeDests(num_dests, dests);
    +
    + +

    See Also

    + +

    +cupsGetDest(), +cupsGetDests() + + +

    cupsFreeJobs()

    + +

    Usage

    + +
    +void
    +cupsFreeJobs(int        num_jobs,
    +             cups_job_t *jobs);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    num_jobsThe number of jobs.
    jobsThe job array.
    + +

    Description

    + +

    cupsFreeJobs() frees an array of print jobs created by +the cupsGetJobs() function. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int        i;
    +int        num_jobs;
    +cups_job_t *jobs;
    +
    +
    +num_jobs = cupsGetJobs(&jobs, NULL, 0, 0);
    +
    +printf("%d active job(s):\n", num_jobs);
    +for (i = 0; i < num_jobs; i ++)
    +  printf("%-16.16s %-6d %-12.12s %s (%s)\n", jobs[i].dest, jobs[i].id,
    +         jobs[i].user, jobs[i].title,
    +	 jobs[i].state != IPP_JOB_PENDING ? "printing" : "pending");
    +
    +cupsFreeJobs(num_jobs, jobs);
    +
    + +

    See Also

    + +

    +cupsGetJobs(), +cupsGetDests() + + +

    cupsFreeOptions()

    + +

    Usage

    + +
    +void
    +cupsFreeOptions(int           num_options,
    +                cups_option_t *options);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    num_optionsNumber of options in array.
    optionsPointer to options array.
    + +

    Description

    + +

    cupsFreeOptions() frees all memory associated with the +option array specified. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +
    +...
    +
    +cupsFreeOptions(num_options, options);
    +
    + +

    See Also

    + +

    +cupsAddOption(), +cupsEncodeOptions(), +cupsGetOption(), +cupsMarkOptions(), +cupsParseOptions() + + +

    cupsGetClasses()

    + +

    Usage

    + +
    +int
    +cupsGetClasses(char ***classes);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    classesPointer to character pointer array.
    + +

    Returns

    + +

    The number of printer classes available. + +

    Description

    + +

    cupsGetClasses() gets a list of the available printer classes. +The returned array should be freed using the free() when it is +no longer needed. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int  i;
    +int  num_classes;
    +char **classes;
    +
    +...
    +
    +num_classes = cupsGetClasses(&classes);
    +
    +...
    +
    +if (num_classes > 0)
    +{
    +  for (i = 0; i < num_classes; i ++)
    +    free(classes[i]);
    +
    +  free(classes);
    +}
    +
    + +

    See Also

    + +

    +cupsGetDefault(), +cupsGetPrinters() + + +

    cupsGetDefault()

    + +

    Usage

    + +
    +const char *
    +cupsGetDefault(void);
    +
    + +

    Returns

    + +

    A pointer to the default destination. + +

    Description

    + +

    cupsGetDefault() gets the default destination printer or class. +The default destination is stored in a static string and will be overwritten +(usually with the same value) after each call. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +printf("The default destination is %s\n", cupsGetDefault());
    +
    + +

    See Also

    + +

    +cupsGetClasses(), +cupsGetPrinters() + + +

    cupsGetDest()

    + +

    Usage

    + +
    +cups_dest_t *
    +cupsGetDest(const char  *name,
    +            const char  *instance,
    +            int         num_dests,
    +            cups_dest_t *dests);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    nameThe name of the destination, or NULL for the default destination.
    instanceThe instance of the destination, or NULL for the primary instance.
    num_destsThe number of destinations.
    destsThe destination array.
    + +

    Returns

    + +

    A pointer to the specified destination, or NULL if none exists. + +

    Description

    + +

    cupsGetDest() finds the specified destination in the array +of destinations created by the cupsGetDests() function. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *dest;
    +
    +num_dests = cupsGetDests(&dests);
    +dest      = cupsGetDest(NULL, NULL, num_dests, dests);
    +
    +if (dest)
    +  printf("The default destination is %s\n", dest->name);
    +else
    +  puts("No default destination.");
    +
    +cupsFreeDests(num_dests, dests);
    +
    + +

    See Also

    + +

    +cupsGetDests(), +cupsGetJobs() + + +

    cupsGetDests()

    + +

    Usage

    + +
    +int
    +cupsGetDests(cups_dest_t **dests);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    destsA pointer to a destination array pointer.
    + +

    Returns

    + +

    The number of available destinations. + +

    Description

    + +

    cupsGetDests() creates an array of available +destinations that the user can print to. The array should be +freed using the cupsFreeDests() function. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +cups_dest_t *dest;
    +
    +num_dests = cupsGetDests(&dests);
    +dest      = cupsGetDest(NULL, NULL, num_dests, dests);
    +
    +if (dest)
    +  printf("The default destination is %s\n", dest->name);
    +else
    +  puts("No default destination.");
    +
    +cupsFreeDests(num_dests, dests);
    +
    + +

    See Also

    + +

    +cupsFreeDests(), +cupsGetDest(), +cupsGetJobs() + + +

    cupsGetJobs()

    + +

    Usage

    + +
    +int
    +cupsGetJobs(cups_job_t **jobs,
    +            const char *dest,
    +            int        myjobs,
    +            int        completed);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    jobsA pointer to the job array pointer.
    destThe destination name, or NULL if jobs for all destinations are requested.
    myjobs1 if only those jobs submitted by the current + cupsUser() should be returned, 0 for jobs + submitted by all users.
    completed1 if only completed jobs should be returned, 0 if only + pending/processing jobs should be returned.
    + +

    Returns

    + +

    The number of jobs. + +

    Description

    + +

    cupsGetJobs() creates an array of print jobs based on the +arguments supplied in the function call. The returned array should be freed +using the cupsFreeJobs() function. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int        i;
    +int        num_jobs;
    +cups_job_t *jobs;
    +
    +
    +num_jobs = cupsGetJobs(&jobs, NULL, 0, 0);
    +
    +printf("%d active job(s):\n", num_jobs);
    +for (i = 0; i < num_jobs; i ++)
    +  printf("%-16.16s %-6d %-12.12s %s (%s)\n", jobs[i].dest, jobs[i].id,
    +         jobs[i].user, jobs[i].title,
    +	 jobs[i].state != IPP_JOB_PENDING ? "printing" : "pending");
    +
    +cupsFreeJobs(num_jobs, jobs);
    +
    + +

    See Also

    + +

    +cupsFreeJobs(), +cupsGetDests() + + +

    cupsGetOption()

    + +

    Usage

    + +
    +const char *
    +cupsGetOption(const char    *name,
    +              int           num_options,
    +              cups_option_t *options);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    nameThe name of the option.
    num_optionsThe number of options in the array.
    optionsThe options array.
    + +

    Returns

    + +

    A pointer to the option values or NULL if the option is +not defined. + +

    Description

    + +

    cupsGetOption() returns the first occurrence of the +named option. If the option is not included in the options array then a +NULL pointer is returned. + +

    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +const char    *media;
    +
    +...
    +
    +media = cupsGetOption("media", num_options, options);
    +
    + +

    See Also

    + +

    +cupsAddOption(), +cupsEncodeOptions(), +cupsFreeOptions(), +cupsMarkOptions(), +cupsParseOptions() + + +

    cupsGetPassword()

    + +

    Usage

    + +
    +const char *
    +cupsGetPassword(const char *prompt);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    promptThe prompt to display to the user.
    + +

    Returns

    + +

    A pointer to the password that was entered or NULL if no +password was entered. + +

    Description

    + +

    cupsGetPassword() displays the prompt string and asks the user +for a password. The password text is not echoed to the user. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +char *password;
    +
    +...
    +
    +password = cupsGetPassword("Please enter a password:");
    +
    + +

    See Also

    + +

    +cupsServer(), +cupsSetPasswordCB(), +cupsSetServer(), +cupsSetUser(), +cupsUser() + + +

    cupsGetPPD()

    + +

    Usage

    + +
    +const char *
    +cupsGetPPD(const char *printer);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    printerThe name of the printer.
    + +

    Returns

    + +

    The name of a temporary file containing the PPD file or NULL +if the printer cannot be located or does not have a PPD file. + +

    Description

    + +

    cupsGetPPD() gets a copy of the PPD file for the named printer. +The printer name can be of the form "printer" or "printer@hostname". + +

    You should remove (unlink) the PPD file after you are done using it. The +filename is stored in a static buffer and will be overwritten with each call +to cupsGetPPD(). + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +char *ppd;
    +
    +...
    +
    +ppd = cupsGetPPD("printer@hostname");
    +
    +...
    +
    +unlink(ppd);
    +
    + + +

    cupsGetPrinters()

    + +

    Usage

    + +
    +int
    +cupsGetPrinters(char ***printers);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    printersPointer to character pointer array.
    + +

    Returns

    + +

    The number of printer printers available. + +

    Description

    + +

    cupsGetPrinters() gets a list of the available printers. +The returned array should be freed using the free() when it is +no longer needed. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int  i;
    +int  num_printers;
    +char **printers;
    +
    +...
    +
    +num_printers = cupsGetPrinters(&printers);
    +
    +...
    +
    +if (num_printers > 0)
    +{
    +  for (i = 0; i < num_printers; i ++)
    +    free(printers[i]);
    +
    +  free(printers);
    +}
    +
    + +

    See Also

    + +

    +cupsGetClasses() +cupsGetDefault() + + +

    cupsLangDefault()

    + +

    Usage

    + +
    +const char *
    +cupsLangDefault(void);
    +
    + +

    Returns

    + +

    A pointer to the default language structure. + +

    Description

    + +

    cupsLangDefault() returns a language structure for the default +language. The default language is defined by the LANG environment +variable. If the specified language cannot be located then the POSIX (English) +locale is used. + +

    Call cupsLangFree() to free any memory associated with the +language structure when you are done. + +

    Example

    + +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +...
    +
    +language = cupsLangDefault();
    +
    +...
    +
    +cupsLangFree(language);
    +
    + +

    See Also

    + +

    +cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + + +

    cupsLangEncoding()

    + +

    Usage

    + +
    +char *
    +cupsLangEncoding(cups_lang_t *language);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    languageThe language structure.
    + +

    Returns

    + +

    A pointer to the encoding string. + +

    Description

    + +

    cupsLangEncoding() returns the language encoding used for the +specified language, e.g. "iso-8859-1", "utf-8", etc. + +

    Example

    + +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +char        *encoding;
    +...
    +
    +language = cupsLangDefault();
    +encoding = cupsLangEncoding(language);
    +...
    +
    +cupsLangFree(language);
    +
    + +

    See Also

    + +

    +cupsLangDefault(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + + +

    cupsLangFlush()

    + +

    Usage

    + +
    +void
    +cupsLangFlush(void);
    +
    + +

    Description

    + +

    cupsLangFlush() frees all language structures that have been +allocated. + +

    Example

    + +
    +#include <cups/language.h>
    +
    +...
    +
    +cupsLangFlush();
    +
    + +

    See Also

    + +

    +cupsLangDefault(), +cupsLangEncoding(), +cupsLangFree(), +cupsLangGet(), +cupsLangString() + + +

    cupsLangFree()

    + +

    Usage

    + +
    +void
    +cupsLangFree(cups_lang_t *language);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    languageThe language structure to free.
    + +

    Description

    + +

    cupsLangFree() frees the specified language structure. + +

    Example

    + +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +...
    +
    +cupsLangFree(language);
    +
    + +

    See Also

    + +

    +cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangGet(), +cupsLangString() + + +

    cupsLangGet()

    + +

    Usage

    + +
    +cups_lang_t *
    +cupsLangGet(const char *name);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    nameThe name of the locale.
    + +

    Returns

    + +

    A pointer to a language structure. + +

    Description

    + +

    cupsLangGet() returns a language structure for the specified +locale. If the locale is not defined then the POSIX (English) locale is +substituted. + +

    Example

    + +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +
    +...
    +
    +language = cupsLangGet("fr");
    +
    +...
    +
    +cupsLangFree(language);
    +
    + +

    See Also

    + +

    +cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangString() + + +

    cupsLangString()

    + +

    Usage

    + +
    +char *
    +cupsLangString(cups_lang_t *language,
    +               int         message);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    languageThe language to query.
    messageThe message number.
    + +

    Returns

    + +

    A pointer to the message string or NULL if the message is +not defined. + +

    Description

    + +

    cupsLangString() returns a pointer to the specified message +string in the specified language. + +

    Example

    + +
    +#include <cups/language.h>
    +
    +cups_lang_t *language;
    +char        *s;
    +...
    +
    +language = cupsLangGet("fr");
    +
    +s = cupsLangString(language, CUPS_MSG_YES);
    +
    +...
    +
    +cupsLangFree(language);
    +
    + +

    See Also

    + +

    +cupsLangDefault(), +cupsLangEncoding(), +cupsLangFlush(), +cupsLangFree(), +cupsLangGet() + + +

    cupsLastError()

    + +

    Usage

    + +
    +ipp_status_t
    +cupsLastError(void);
    +
    + +

    Returns

    + +

    An enumeration containing the last IPP error. + +

    Description

    + +

    cupsLastError() returns the last IPP error that occurred. +If no error occurred then it will return IPP_OK or +IPP_OK_CONFLICT. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +ipp_status_t status;
    +
    +...
    +
    +status = cupsLastError();
    +
    + +

    See Also

    + +

    +cupsCancelJob(), +cupsPrintFile() + + +

    cupsMarkOptions()

    + +

    Usage

    + +
    +int
    +cupsMarkOptions(ppd_file_t    *ppd,
    +                int           num_options,
    +                cups_option_t *options);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file to mark.
    num_optionsThe number of options in the options array.
    optionsA pointer to the options array.
    + +

    Returns

    + +

    The number of conflicts found. + +

    Description

    + +

    cupsMarkOptions() marks options in the PPD file. It also +handles mapping of IPP option names and values to PPD option names. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +ppd_file_t    *ppd;
    +
    +...
    +
    +cupsMarkOptions(ppd, num_options, options);
    +
    + +

    See Also

    + +

    +cupsAddOption(), +cupsFreeOptions(), +cupsGetOption(), +cupsParseOptions() + + +

    cupsParseOptions()

    + +

    Usage

    + +
    +int
    +cupsParseOptions(const char    *arg,
    +                 int           num_options,
    +                 cups_option_t **options);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    argThe string containing one or more options.
    num_optionsThe number of options in the options array.
    optionsA pointer to the options array pointer.
    + +

    Returns

    + +

    The new number of options in the array. + +

    Description

    + +

    cupsParseOptions() parses the specifies string for one +or more options of the form "name=value", "name", or "noname". It can +be called multiple times to combine the options from several strings. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +
    +...
    +
    +num_options = 0;
    +options     = (cups_option_t *)0;
    +num_options = cupsParseOptions(argv[5], num_options, &options);
    +
    + +

    See Also

    + +

    +cupsAddOption(), +cupsFreeOptions(), +cupsGetOption(), +cupsMarkOptions() + + +

    cupsPrintFile()

    + +

    Usage

    + +
    +int
    +cupsPrintFile(const char    *printer,
    +              const char    *filename,
    +              const char    *title,
    +	      int           num_options,
    +	      cups_option_t *options);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    printerThe printer or class to print to.
    filenameThe file to print.
    titleThe job title.
    num_optionsThe number of options in the options array.
    optionsA pointer to the options array.
    + +

    Returns

    + +

    The new job ID number or 0 on error. + +

    Description

    + +

    cupsPrintFile() sends a file to the specified printer or +class for printing. If the job cannot be printed the error code can be +found by calling cupsLastError(). + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int           num_options;
    +cups_option_t *options;
    +int           jobid;
    +
    +...
    +
    +jobid = cupsPrintFile("printer@hostname", "filename.ps", "Job Title",
    +                      num_options, options);
    +
    + +

    See Also

    + +

    +cupsCancelJob(), +cupsLastError(), +cupsPrintFiles() + + +

    cupsPrintFiles()

    + +

    Usage

    + +
    +int
    +cupsPrintFiles(const char    *printer,
    +               int           num_files,
    +               const char    **files,
    +               const char    *title,
    +	       int           num_options,
    +	       cups_option_t *options);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    printerThe printer or class to print to.
    num_filesThe number of files to print.
    filesThe files to print.
    titleThe job title.
    num_optionsThe number of options in the options array.
    optionsA pointer to the options array.
    + +

    Returns

    + +

    The new job ID number or 0 on error. + +

    Description

    + +

    cupsPrintFiles() sends multiple files to the specified +printer or class for printing. If the job cannot be printed the error +code can be found by calling cupsLastError(). + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +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);
    +
    + +

    See Also

    + +

    +cupsCancelJob(), +cupsLastError(), +cupsPrintFile() + + +

    cupsRasterClose()

    + +

    Usage

    + +
    +void
    +cupsRasterClose(cups_raster_t *ras);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    rasThe raster stream to close.
    + +

    Description

    + +

    cupsRasterClose() closes the specified raster stream. + +

    Example

    + +
    +#include <cups/raster.h>
    +
    +cups_raster_t *ras;
    +
    +...
    +
    +cupsRasterClose(ras);
    +
    + +

    See Also

    + +

    +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + + +

    cupsRasterOpen()

    + +

    Usage

    + +
    +cups_raster_t *
    +cupsRasterOpen(int         fd,
    +               cups_mode_t mode);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    fdThe file descriptor to use.
    modeThe mode to use; CUPS_RASTER_READ or + CUPS_RASTER_WRITE.
    + +

    Returns

    + +

    A pointer to a raster stream or NULL if there was an error. + +

    Description

    + +

    cupsRasterOpen() opens a raster stream for reading or writing. + +

    Example

    + +
    +#include <cups/raster.h>
    +
    +cups_raster_t *ras;
    +
    +...
    +
    +ras = cupsRasterOpen(0, CUPS_RASTER_READ);
    +
    + +

    See Also

    + +

    +cupsRasterClose(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + + +

    cupsRasterReadHeader()

    + +

    Usage

    + +
    +unsigned
    +cupsRasterReadHeader(cups_raster_t      *ras,
    +                     cups_page_header_t *header);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    rasThe raster stream to read from.
    headerA pointer to a page header structure to read into.
    + +

    Returns

    + +

    1 on success, 0 on EOF or error. + +

    Description

    + +

    cupsRasterReadHeader() reads a page header from the specified +raster stream. + +

    Example

    + +
    +#include <cups/raster.h>
    +
    +int                  line;
    +cups_raster_t        *ras;
    +cups_raster_header_t header;
    +unsigned char        pixels[8192];
    +...
    +
    +while (cupsRasterReadHeader(ras, &header))
    +{
    +  ...
    +
    +  for (line = 0; line < header.cupsHeight; line ++)
    +  {
    +    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
    +
    +    ...
    +  }
    +}
    +
    + +

    See Also

    + +

    +cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadPixels(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + + +

    cupsRasterReadPixels()

    + +

    Usage

    + +
    +unsigned
    +cupsRasterReadPixels(cups_raster_t *ras,
    +                     unsigned char *pixels,
    +		     unsigned      length);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    rasThe raster stream to read from.
    pixelsThe pointer to a pixel buffer.
    lengthThe number of bytes of pixel data to read.
    + +

    Returns

    + +

    The number of bytes read or 0 on EOF or error. + +

    Description

    + +

    cupsRasterReadPixels() reads pixel data from the specified +raster stream. + +

    Example

    + +
    +#include <cups/raster.h>
    +
    +int                  line;
    +cups_raster_t        *ras;
    +cups_raster_header_t header;
    +unsigned char        pixels[8192];
    +...
    +
    +while (cupsRasterReadHeader(ras, &header))
    +{
    +  ...
    +
    +  for (line = 0; line < header.cupsHeight; line ++)
    +  {
    +    cupsRasterReadPixels(ras, pixels, header.cupsBytesPerLine);
    +
    +    ...
    +  }
    +}
    +
    + +

    See Also

    + +

    +cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterWriteHeader(), +cupsRasterWritePixels() + + +

    cupsRasterWriteHeader()

    + +

    Usage

    + +
    +unsigned
    +cupsRasterWriteHeader(cups_raster_t      *ras,
    +                      cups_page_header_t *header);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    rasThe raster stream to write to.
    headerA pointer to the page header to write.
    + +

    Returns

    + +

    1 on success, 0 on error. + +

    Description

    + +

    cupsRasterWriteHeader() writes the specified page header to +a raster stream. + +

    Example

    + +
    +#include <cups/raster.h>
    +
    +int                  line;
    +cups_raster_t        *ras;
    +cups_raster_header_t header;
    +unsigned char        pixels[8192];
    +...
    +
    +cupsRasterWriteHeader(ras, &header);
    +
    +for (line = 0; line < header.cupsHeight; line ++)
    +{
    +  ...
    +
    +  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
    +}
    +
    + +

    See Also

    + +

    +cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWritePixels() + + +

    cupsRasterWritePixels()

    + +

    Usage

    + +
    +unsigned
    +cupsRasterWritePixels(cups_raster_t *ras,
    +                      unsigned char *pixels,
    +		      unsigned      length);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    rasThe raster stream to write to.
    pixelsThe pixel data to write.
    lengthThe number of bytes to write.
    + +

    Returns

    + +

    The number of bytes written. + +

    Description

    + +

    cupsRasterWritePixels() writes the specified pixel data to a +raster stream. + +

    Example

    + +
    +#include <cups/raster.h>
    +
    +int                  line;
    +cups_raster_t        *ras;
    +cups_raster_header_t header;
    +unsigned char        pixels[8192];
    +...
    +
    +cupsRasterWriteHeader(ras, &header);
    +
    +for (line = 0; line < header.cupsHeight; line ++)
    +{
    +  ...
    +
    +  cupsRasterWritePixels(ras, pixels, header.cupsBytesPerLine);
    +}
    +
    + +

    See Also

    + +

    +cupsRasterClose(), +cupsRasterOpen(), +cupsRasterReadHeader(), +cupsRasterReadPixels(), +cupsRasterWriteHeader() + + +

    cupsServer()

    + +

    Usage

    + +
    +const char *
    +cupsServer(void);
    +
    + +

    Returns

    + +

    A pointer to the default server name. + +

    Description

    + +

    cupsServer() returns a pointer to the default server name. +The server name is stored in a static location and will be overwritten with +every call to cupsServer(). + +

    The default server is determined from the following locations: + +

      + +
    1. The CUPS_SERVER environment variable, + +
    2. The ServerName directive in the + client.conf file, + +
    3. The default host, "localhost". + +
    + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +const char *server;
    +
    +server = cupsServer();
    +
    + +

    See Also

    + +

    +cupsGetPassword(), +cupsSetPasswordCB(), +cupsSetServer(), +cupsSetUser(), +cupsUser() + + +

    cupsSetDests()

    + +

    Usage

    + +
    +void
    +cupsSetDests(int         num_dests,
    +             cups_dest_t *dests);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    num_destsNumber of destinations.
    destsArray of destinations.
    + +

    Description

    + +

    cupsSetDests() saves the destination array to +disk. If the current UID is 0, the destinations are saved in the +/etc/cups/lpoptions file, otherwise they are saved +in the ~/.lpoptions file. This function is typically used +to save the default options and instances that are set by the user. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int         num_dests;
    +cups_dest_t *dests;
    +
    +...
    +
    +cupsSetDests(num_dests, dests);
    +
    + +

    See Also

    + +

    +cupsGetDests() + + +

    cupsSetEncryption()

    + +

    Usage

    + +
    +void
    +cupsSetEncryption(http_encryption_t encryption);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    encryptionThe type of encryption to use.
    + +

    Description

    + +

    cupsSetEncryption() sets the default type of encryption to +use when connecting with the print server. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +cupsSetEncryption(HTTP_ENCRYPT_REQUIRED);
    +
    + +

    See Also

    + +

    +cupsEncryption() + + +

    cupsSetPasswordCB()

    + +

    Usage

    + +
    +void
    +cupsSetPasswordCB(const char *(*cb)(const char *prompt));
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    cbThe password callback function.
    + +

    Description

    + +

    cupsSetPasswordCB() sets the callback function to use when +asking the user for a password. The callback function must accept a single +character string pointer (the prompt string) and return NULL +if the user did not enter a password string or a pointer to the password +string otherwise. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +const char *
    +my_password_cb(const char *prompt)
    +{
    +  return (getpass(prompt));
    +}
    +
    +...
    +
    +char *password;
    +
    +...
    +
    +cupsSetPasswordCB(my_password_cb);
    +password = cupsGetPassword("Please enter a password:");
    +
    + +

    See Also

    + +

    +cupsServer(), +cupsSetServer(), +cupsSetUser(), +cupsUser() + + +

    cupsSetServer()

    + +

    Usage

    + +
    +void
    +cupsSetServer(const char *server);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    serverThe default server to use.
    + +

    Description

    + +

    cupsSetServer() sets the default server to use for +the CUPS API. If the server argument is NULL, +the default server is used. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +cupsSetServer("foo.bar.com");
    +
    + +

    See Also

    + +

    +cupsServer(), +cupsSetPasswordCB(), +cupsSetUser(), +cupsUser() + + +

    cupsSetUser()

    + +

    Usage

    + +
    +void
    +cupsSetUser(const char *user);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    userThe user name string to use.
    + +

    Description

    + +

    cupsSetUser() sets the default user name for authentication. +If the user argument is NULL then the current +login user is used. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +...
    +
    +cupsSetUser("root");
    +
    + +

    See Also

    + +

    +cupsServer(), +cupsSetPasswordCB(), +cupsSetServer(), +cupsUser() + + +

    cupsTempFd()

    + +

    Usage

    + +
    +int
    +cupsTempFd(char *filename,
    +           int  length);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    filenameThe character string to hold the temporary filename.
    lengthThe size of the filename string in bytes.
    + +

    Returns

    + +

    A file descriptor open for reading and writing. + +

    Description

    + +

    cupsTempFd() create a temporary filename in the +/var/tmp directory or the directory specified by the +TMPDIR environment variable. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +int  fd;
    +char filename[256];
    +
    +fd = cupsTempFd(filename, sizeof(filename));
    +
    + +

    See Also

    + +

    +cupsTempFile() + + +

    cupsTempFile()

    + +

    Usage

    + +
    +char *
    +cupsTempFile(char *filename,
    +             int  length);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    filenameThe character string to hold the temporary filename.
    lengthThe size of the filename string in bytes.
    + +

    Returns

    + +

    A pointer to filename. + +

    Description

    + +

    cupsTempFile() creates a temporary filename in the +/var/tmp directory or the directory specified by the +TMPDIR environment variable. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +char filename[256];
    +
    +cupsTempFile(filename, sizeof(filename));
    +
    + +

    See Also

    + +

    +cupsTempFd() + + +

    cupsUser()

    + +

    Usage

    + +
    +const char *
    +cupsUser(void);
    +
    + +

    Returns

    + +

    A pointer to the current username or NULL if the user ID is +undefined. + +

    Description

    + +

    cupsUser() returns the name associated with the current +user ID as reported by the getuid() system call. + +

    Example

    + +
    +#include <cups/cups.h>
    +
    +const char *user;
    +
    +user = cupsUser();
    +
    + +

    See Also

    + +

    +cupsGetPassword(), +cupsServer() + + +

    httpBlocking()

    + +

    Usage

    + +
    +void
    +httpBlocking(http_t *http,
    +             int    blocking)
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    blocking0 if the connection should be non-blocking, 1 if it should + be blocking
    + +

    Description

    + +

    The httpBlocking() function sets the blocking mode for the +HTTP connection. By default HTTP connections will block (stop) the client +program until data is available or can be sent to the server. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +http = httpConnect("server", port);
    +httpBlocking(http, 0);
    +
    + +

    See Also

    + +httpCheck(), +httpConnect() + + +

    httpCheck()

    + +

    Usage

    + +
    +int
    +httpCheck(http_t *http);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    + +

    Returns

    + +

    0 if there is no data pending, 1 otherwise. + +

    Description

    + +

    The httpCheck() function checks to see if there is any data +pending on an HTTP connection. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +if (httpCheck(http))
    +{
    +  ... do something ...
    +}
    +
    + +

    See Also

    + +httpBlocking(), +httpConnect(), +httpGets(), +httpRead() + + +

    httpClearFields()

    + +

    Usage

    + +
    +void
    +httpClearFields(http_t *http)
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    + +

    Description

    + +

    The httpClearFields() function clears all HTTP request fields +for the HTTP connection. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpClearFields(http);
    +
    + +

    See Also

    + +httpConnect(), +httpGetField(), +httpSetField() + + +

    httpClose()

    + +

    Usage

    + +
    +void
    +httpClose(http_t *http);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    + +

    Description

    + +

    The httpClose() function closes an active HTTP connection. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpClose(http);
    +
    + +

    See Also

    + +httpConnect() + + +

    httpConnect()

    + +

    Usage

    + +
    +http_t *
    +httpConnect(const char *hostname,
    +            int        port);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    hostnameThe name or IP address of the server to connect to
    portThe port number to use
    + +

    Returns

    + +

    A pointer to a HTTP connection structure or NULL if the connection could +not be made. + +

    Description

    + +

    The httpConnect() function opens a HTTP connection to the +specified server and port. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +http = httpConnect(cupsServer(), ippPort());
    +
    + +

    See Also

    + +httpClose(), +httpConnectEncrypt(), +httpGet(), +httpGets(), +httpPost(), +httpRead(), +httpWrite() + + +

    httpConnectEncrypt()

    + +

    Usage

    + +
    +http_t *
    +httpConnectEncrypt(const char        *hostname,
    +                   int               port,
    +                   http_encryption_t encryption);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    hostnameThe name or IP address of the server to connect to
    portThe port number to use
    encryptionThe level of encryption to use
    + +

    Returns

    + +

    A pointer to a HTTP connection structure or NULL if the connection could +not be made. + +

    Description

    + +

    The httpConnectEncrypt() function opens a HTTP +connection to the specified server, port, and encryption. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption());
    +
    + +

    See Also

    + +httpClose(), +httpConnect(), +httpGet(), +httpGets(), +httpPost(), +httpRead(), +httpWrite() + + +

    httpDecode64()

    + +

    Usage

    + +
    +char *
    +httpDecode64(char       *out,
    +             const char *in);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    outThe output string
    inThe input string
    + +

    Returns

    + +

    A pointer to the decoded string. + +

    Description

    + +

    The httpDecode64() function decodes a base-64 encoded string +to the original string. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +char encoded_string[255];
    +char original_string[255];
    +
    +httpDecode64(original_string, encoded_string);
    +
    + +

    See Also

    + +httpEncode64() + + +

    httpDelete()

    + +

    Usage

    + +
    +int
    +httpDelete(http_t     *http,
    +           const char *uri);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to delete
    + +

    Returns

    + +

    0 on success, non-zero on failure. + +

    Description

    + +

    The httpDelete() function sends a HTTP DELETE request to +the server. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpDelete(http, "/some/uri");
    +
    + +

    See Also

    + +httpConnect(), +httpSetField(), +httpUpdate() + + +

    httpEncode64()

    + +

    Usage

    + +
    +char *
    +httpEncode64(char       *out,
    +             const char *in);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    outThe output string
    inThe input string
    + +

    Returns

    + +

    A pointer to the encoded string. + +

    Description

    + +

    The httpEncode64() function decodes a base-64 encoded string +to the original string. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +char encoded_string[255];
    +char original_string[255];
    +
    +httpEncode64(encoded_string, original_string);
    +
    + +

    See Also

    + +httpDecode64() + + +

    httpEncryption()

    + +

    Usage

    + +
    +int
    +httpEncryption(http_t            *http,
    +               http_encryption_t encryption);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection.
    encryptionThe desired level of encryption.
    + +

    Returns

    + +

    0 on success, -1 on error. + +

    Description

    + +

    httpEncryption() sets the encryption level for the HTTP +connection. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +...
    +
    +httpEncryption(http, HTTP_ENCRYPT_REQUIRED);
    +
    + +

    See Also

    + +

    +httpConnectEncrypt() + + +

    httpError()

    + +

    Usage

    + +
    +int
    +httpError(http_t *http);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    + +

    Returns

    + +

    The last error that occurred or 0 if no error has occurred. + +

    Description

    + +

    The httpError() function returns the last error that occurred +on the HTTP connection. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +if (httpError(http))
    +{
    +  ... show an error message ...
    +}
    +
    + +

    See Also

    + +httpConnect() + + +

    httpFlush()

    + +

    Usage

    + +
    +void
    +httpFlush(http_t *http);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    + +

    Description

    + +

    The httpFlush() function flushes any remaining data left from +a GET or POST operation. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpFlush(http);
    +
    + +

    See Also

    + +httpConnect(), + + +

    httpGet()

    + +

    Usage

    + +
    +int
    +httpGet(http_t     *http,
    +        const char *uri);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to get
    + +

    Returns

    + +

    0 on success, non-zero on failure. + +

    Description

    + +

    The httpGet() function sends a HTTP GET request to the +server. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpGet(http, "/some/uri");
    +
    + +

    See Also

    + +httpConnect(), +httpSetField(), +httpUpdate() + + +

    httpGets()

    + +

    Usage

    + +
    +char *
    +httpGets(char   *line,
    +         int    length,
    +         http_t *http)
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    lineThe string to fill with a line from the HTTP connection
    lengthThe maximum length of the string
    httpThe HTTP connection
    + +

    Returns

    + +

    A pointer to the string or NULL if no line could be retrieved. + +

    Description

    + +

    The httpGets() function is used to read a request line from +the HTTP connection. It is not normally used by a client program. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +char   line[1024];
    +
    +if (httpGets(line, sizeof(line), http))
    +{
    +  ... process the line ...
    +}
    +
    + +

    See Also

    + +httpConnect(), +httpUpdate() + + +

    httpGetDateString()

    + +

    Usage

    + +
    +const char *
    +httpGetDateString(time_t time)
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    timeThe UNIX date/time value
    + +

    Returns

    + +

    A pointer to a static string containing the HTTP date/time string for +the specified UNIX time value. + +

    Description

    + +

    The httpGetDateString() function generates a date/time string +suitable for HTTP requests from a UNIX time value. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +puts(httpGetDateString(time(NULL)));
    +
    + +

    See Also

    + +httpGetDateTime() + + +

    httpGetDateTime()

    + +

    Usage

    + +
    +time_t
    +httpGetDateTime(const char *date)
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    dateThe HTTP date/time string
    + +

    Returns

    + +

    A UNIX time value. + +

    Description

    + +

    The httpGetDateTime() function converts a HTTP +date/time string to a UNIX time value. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +printf("%d\n", httpGetDateTime("Fri, 30 June 2000 12:34:56 GMT"));
    +
    + +

    See Also

    + +httpGetDateString() + + +

    httpGetField()

    + +

    Usage

    + +
    +const char *
    +httpGetField(http_t       *http,
    +             http_field_t field);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    fieldThe HTTP field
    + +

    Returns

    + +

    A pointer to the field value string. + +

    Description

    + +

    The httpGetField() function returns the current value for +the specified HTTP field. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpGet(http, "/some/uri");
    +while (httpUpdate(http) == HTTP_CONTINUE);
    +
    +puts(httpGetField(http, HTTP_FIELD_CONTENT_TYPE));
    +
    + +

    See Also

    + +httpConnect(), +httpGetSubField(), +httpSetField() + + +

    httpGetHostByName()

    + +

    Usage

    + +
    +struct hostent	*
    +httpGetHostByName(const char *name);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    nameName or IP address to lookup.
    + +

    Returns

    + +

    NULL if the host could not be found or a pointer to a host entry +containing one or more addresses. + +

    Description

    + +

    httpGetHostByName() is a portable wrapper around the +gethostbyname() function which handles both hostnames +and IP addresses. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +struct hostent *hostaddr;
    +
    +hostaddr = httpGetHostByName("foo.bar.com");
    +
    + + +

    httpGetLength()

    + +

    Usage

    + +
    +int
    +httpGetLength(http_t *http);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection.
    + +

    Returns

    + +

    The content length of the response or MAX_INT if chunking is used. + +

    Description

    + +

    httpGetLength() returns the content length of a response. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +...
    +
    +printf("The length of the response is %d bytes.\n", httpGetLength(http));
    +
    + +

    See Also

    + +

    +httpGet(), +httpPost() + + +

    httpGetSubField()

    + +

    Usage

    + +
    +const char *
    +httpGetSubField(http_t       *http,
    +                http_field_t field,
    +		const char   *name,
    +		char         *value);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection.
    fieldThe HTTP field.
    nameThe name of the subfield.
    valueThe string to hold the subfield value.
    + +

    Returns

    + +

    A pointer to the subfield value string or NULL if it does not exist. + +

    Description

    + +

    The httpGetSubField() function returns a subfield value +from the specified HTTP field. The destination string buffer must be at +least HTTP_MAX_VALUE bytes in length. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +char   value[HTTP_MAX_VALUE];
    +
    +httpGet(http, "/some/uri");
    +while (httpUpdate(http) == HTTP_CONTINUE);
    +
    +puts(httpGetSubField(http, HTTP_FIELD_CONTENT_TYPE, "charset", value));
    +
    + +

    See Also

    + +httpConnect(), +httpGetField(), +httpSetField() + + +

    httpHead()

    + +

    Usage

    + +
    +int
    +httpHead(http_t     *http,
    +         const char *uri);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to head
    + +

    Returns

    + +

    0 on success, non-zero on failure. + +

    Description

    + +

    The httpHead() function sends a HTTP HEAD request to the +server. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpHead(http, "/some/uri");
    +
    + +

    See Also

    + +httpConnect(), +httpSetField(), +httpUpdate() + + +

    httpInitialize()

    + +

    Usage

    + +
    +void httpInitialize(void);
    +
    + +

    Description

    + +

    The httpInitialize() function initializes the networking +code as needed by the underlying platform. It is called automatically by +the httpConnect() function. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +httpInitialize();
    +
    + +

    See Also

    + +httpConnect() + + +

    httpMD5()

    + +

    Usage

    + +
    +char *
    +httpMD5(const char *username,
    +        const char *realm,
    +        const char *passwd,
    +        char       md5[33]);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    usernameThe authenticating user name.
    realmThe authenticating realm name.
    passwdThe authenticating password.
    md5The MD5 sum string.
    + +

    Returns

    + +

    A pointer to the MD5 sum string. + +

    Description

    + +

    httpMD5() computes the MD5 hash of the username, +realm, and password as required by the HTTP Digest specification. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +char md5[33];
    +
    +...
    +
    +httpMD5("user", "realm", "password", md5);
    +
    + +

    See Also

    + +

    +httpMD5Final(), +httpMD5String() + + +

    httpMD5Final()

    + +

    Usage

    + +
    +char *
    +httpMD5Final(const char *nonce,
    +             const char *method,
    +             const char *resource,
    +             char       md5[33]);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    nonceThe server nonce value.
    methodThe HTTP method (GET, POST, etc.)
    resourceThe resource path.
    md5The MD5 sum string.
    + +

    Returns

    + +

    The MD5 sum string. + +

    Description

    + +

    httpMD5Final() appends the nonce, method, and resource +to the specified MD5 sum. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +char md5[33];
    +
    +...
    +
    +httpMD5Final("nonce", "GET", "/jobs", md5);
    +
    + +

    See Also

    + +

    +httpMD5(), +httpMD5String() + + +

    httpMD5String()

    + +

    Usage

    + +
    +char *
    +httpMD5String(const md5_byte_t *sum,
    +              char             md5[33]);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    sumThe raw MD5 sum data.
    md5The MD5 sum string.
    + +

    Returns

    + +

    The MD5 sum string. + +

    Description

    + +

    httpMD5String() converts the raw MD5 sum value to a string. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +md5_byte_t sum[16];
    +char       md5[33];
    +
    +...
    +
    +httpMD5String(sum, md5);
    +
    + +

    See Also

    + +

    +httpMD5(), +httpMD5Final() + + +

    httpOptions()

    + +

    Usage

    + +
    +int
    +httpOptions(http_t     *http,
    +            const char *uri);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to check for options
    + +

    Returns

    + +

    0 on success, non-zero on failure. + +

    Description

    + +

    The httpOptions() function sends a HTTP OPTIONS request to the +server. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpOptions(http, "/some/uri");
    +
    + +

    See Also

    + +httpConnect(), +httpSetField(), +httpUpdate() + + +

    httpPost()

    + +

    Usage

    + +
    +int
    +httpPost(http_t     *http,
    +         const char *uri);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to post to
    + +

    Returns

    + +

    0 on success, non-zero on failure. + +

    Description

    + +

    The httpPost() function sends a HTTP POST request to the +server. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpPost(http, "/some/uri");
    +
    + +

    See Also

    + +httpConnect(), +httpSetField(), +httpUpdate() + + +

    httpPrintf()

    + +

    Usage

    + +
    +int
    +httpPrintf(http_t     *http,
    +           const char *format,
    +           ...);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    formatA printf-style format string
    + +

    Returns

    + +

    The number of bytes written. + +

    Description

    + +

    The httpPrintf() function sends a formatted string to the +HTTP connection. It is normally only used by the CUPS API and scheduler. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpPrintf(http, "GET / HTTP/1.1 \r\n");
    +
    + +

    See Also

    + +httpConnect() + + +

    httpPut()

    + +

    Usage

    + +
    +int
    +httpPut(http_t     *http,
    +        const char *uri);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to put
    + +

    Returns

    + +

    0 on success, non-zero on failure. + +

    Description

    + +

    The httpPut() function sends a HTTP PUT request to the +server. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpDelete(http, "/some/uri");
    +
    + +

    See Also

    + +httpConnect(), +httpSetField(), +httpUpdate() + + +

    httpRead()

    + +

    Usage

    + +
    +int
    +httpRead(http_t *http,
    +         char   *buffer,
    +         int    length);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    bufferThe buffer to read into
    lengthThe number of bytes to read
    + +

    Returns

    + +

    The number of bytes read or -1 on error. + +

    Description

    + +

    The httpRead() function reads data from the HTTP connection, +possibly the result of a GET or POST request. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +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);
    +}
    +
    + +

    See Also

    + +httpConnect(), +httpWrite() + + +

    httpReconnect()

    + +

    Usage

    + +
    +int
    +httpReconnect(http_t *http);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    + +

    Returns

    + +

    0 on success, non-zero on failure. + +

    Description

    + +

    The httpReconnect() function reconnects to the HTTP server. +This is usually done automatically if the HTTP functions detect that the +server connection has terminated. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpReconnect(http);
    +
    + +

    See Also

    + +httpConnect() + + +

    httpSeparate()

    + +

    Usage

    + +
    +void
    +httpSeparate(const char *uri,
    +             char       *method,
    +             char       *username,
    +             char       *host,
    +             int        *port,
    +             char       *resource);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    uriThe URI to separate
    methodThe method (scheme) of the URI
    usernameThe username (and password) portion of the URI, if any
    hostThe hostname portion of the URI, if any
    portThe port number for the URI, either as specified or as + default for the method/scheme
    resourceThe resource string, usually a filename on the server
    + +

    Description

    + +

    The httpSeparate() function separates the specified URI into +its component parts. The method, username, hostname, and resource strings should +be at least HTTP_MAX_URI characters long to avoid potential +buffer overflow problems. + +

    Example

    + +
    +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, &port, resource);
    +
    + +

    See Also

    + +httpConnect() + + +

    httpSetField()

    + +

    Usage

    + +
    +void
    +httpSetField(http_t       *http,
    +             http_field_t field,
    +             const char   *value);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    fieldThe HTTP field
    valueThe string value for the field
    + +

    Description

    + +

    The httpSetField() function sets the current value for +the specified HTTP field. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpSetField(http, HTTP_FIELD_AUTHORIZATION, "Basic dfdr34453454325"));
    +httpGet(http, "/some/uri");
    +while (httpUpdate(http) == HTTP_CONTINUE);
    +
    + +

    See Also

    + +httpConnect(), +httpGetField() + + +

    httpStatus()

    + +

    Usage

    + +
    +const char *
    +httpStatus(http_status_t status);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    statusThe HTTP status code from the server.
    + +

    Returns

    + +

    The standard HTTP status text associated with the status code. + +

    Description

    + +

    httpStatus() returns the standard HTTP status text +associated with the status code. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +...
    +
    +puts(httpStatus(http->status));
    +
    + + +

    httpTrace()

    + +

    Usage

    + +
    +int
    +httpTrace(http_t     *http,
    +          const char *uri);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    uriThe URI to trace
    + +

    Returns

    + +

    0 on success, non-zero on failure. + +

    Description

    + +

    The httpTrace() function sends a HTTP TRACE request to the +server. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +
    +httpTrace(http, "/some/uri");
    +
    + +

    See Also

    + +httpConnect(), +httpSetField(), +httpUpdate() + + +

    httpUpdate()

    + +

    Usage

    + +
    +http_status_t
    +httpUpdate(http_t *http);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    + +

    Returns

    + +

    The HTTP status of the current request. + +

    Description

    + +

    The httpUpdate() function updates the current request status. +It is used after any DELETE, GET, HEAD, OPTIONS, POST, PUT, or TRACE +request to finalize the HTTP request and retrieve the request status. + +

    Since proxies and the current blocking mode can cause the request to +take longer, programs should continue calling httpUpdate() +until the return status is not the constant value HTTP_CONTINUE. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +http_t *http;
    +http_status_t status;
    +
    +httpGet(http, "/some/uri");
    +while ((status = httpUpdate(http)) == HTTP_CONTINUE);
    +printf("Request status is %d\n", status);
    +
    + +

    See Also

    + +httpConnect(), +httpDelete(), +httpGet(), +httpHead(), +httpOptions(), +httpPost(), +httpPut(), +httpTrace() + + +

    httpWrite()

    + +

    Usage

    + +
    +int
    +httpWrite(http_t *http,
    +          char   *buffer,
    +          int    length);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    bufferThe buffer to read into
    lengthThe number of bytes to read
    + +

    Returns

    + +

    The number of bytes read or -1 on error. + +

    Description

    + +

    The httpWrite() function reads data from the HTTP connection, +possibly the result of a GET or POST request. + +

    Example

    + +
    +#include <cups/http.h>
    +
    +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);
    +}
    +
    + +

    See Also

    + +httpConnect(), +httpRead() + + +

    ippAddBoolean()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddBoolean(ipp_t      *ipp,
    +              ipp_tag_t  group,
    +              const char *name,
    +	      char       value);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    valueThe boolean value
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddBoolean() function adds a single boolean attribute +value to the specified IPP request. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddBoolean(ipp, IPP_TAG_OPERATION, "my-jobs", 1);
    +
    + +

    See Also

    + +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddBooleans()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddBooleans(ipp_t      *ipp,
    +               ipp_tag_t  group,
    +               const char *name,
    +               int        num_values,
    +               const char *values);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    num_valuesThe number of values
    valuesThe boolean values
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddBooleans() function adds one or more boolean +attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values false values is created. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +char values[10];
    +
    +ippAddBooleans(ipp, IPP_TAG_OPERATION, "some-attribute", 10, values);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddDate()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddDate(ipp_t       *ipp,
    +           ipp_tag_t   group,
    +           const char  *name,
    +           ipp_uchar_t *value);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    valueThe date value
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddDate() function adds a single date-time attribute +value to the specified IPP request. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddDate(ipp, IPP_TAG_OPERATION, "some-attribute", 
    +           ippTimeToDate(time(NULL));
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings(), +ippTimeToDate() + + +

    ippAddInteger()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddInteger(ipp_t      *ipp,
    +              ipp_tag_t  group,
    +              ipp_tag_t  tag,
    +              const char *name,
    +              int        value);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    tagThe type of integer value (IPP_TAG_INTEGER or IPP_TAG_ENUM)
    nameThe name of attribute
    valueThe integer value
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddInteger() function adds a single integer attribute +value to the specified IPP request. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddInteger(ipp, IPP_TAG_OPERATION, "limit", 100);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddIntegers()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddIntegers(ipp_t      *ipp,
    +               ipp_tag_t  group,
    +               ipp_tag_t  tag,
    +               const char *name,
    +               int        num_values,
    +               const int  *values);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    tagThe type of integer value (IPP_TAG_INTEGER or IPP_TAG_ENUM)
    nameThe name of attribute
    num_valuesThe number of values
    valuesThe integer values
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddIntegers() function adds one or more integer +attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values 0 values is created. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +int values[100];
    +
    +ippAddIntegers(ipp, IPP_TAG_OPERATION, "some-attribute", 100, values);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddRange()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddRange(ipp_t      *ipp,
    +            ipp_tag_t  group,
    +            const char *name,
    +            int        low,
    +            int        high);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    lowThe lower value
    highThe higher value
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddRange() function adds a single range attribute +value to the specified IPP request. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddRange(ipp, IPP_TAG_OPERATION, "page-ranges", 1, 10);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddRanges()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddRanges(ipp_t      *ipp,
    +             ipp_tag_t  group,
    +             const char *name,
    +             int        num_values,
    +             const int  *lows,
    +             const int  *highs);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    num_valuesThe number of range values
    lowsThe lower values
    highsThe higher values
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddRanges() function adds one or more range +attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values 0,0 ranges is created. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +int lows[2];
    +int highs[2];
    +
    +ippAddRanges(ipp, IPP_TAG_OPERATION, "page-ranges", 2, lows, highs);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddResolution()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddResolution(ipp_t      *ipp,
    +                 ipp_tag_t  group,
    +                 const char *name,
    +                 int        xres,
    +                 int        yres,
    +                 ipp_res_t  units);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    xresThe horizontal resolution
    yresThe vertical resolution
    unitsThe resolution units
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddResolution() function adds a single resolution attribute +value to the specified IPP request. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddBoolean(ipp, IPP_TAG_OPERATION, "printer-resolution",
    +              720, 720, IPP_RES_PER_INCH);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddResolutions()

    + +

    Usage

    + +
    +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);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    nameThe name of attribute
    num_valuesThe number of resolution values
    xresThe horizontal resolutions
    yresThe vertical resolutions
    unitsThe resolution units
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddResolutions() function adds one or more +resolution attribute values to the specified IPP request. If the +values pointer is NULL then an array of +num_values 0,0 resolutions is created. + +

    Example

    + +
    +#include <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);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddSeparator(), +ippAddString(), +ippAddStrings() + + +

    ippAddSeparator()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddSeparator(ipp_t *ipp);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    + +

    Returns

    + +

    A pointer to the new separator or NULL if the separator could not be +created. + +

    Description

    + +

    The ippAddSeparator() function adds a group separator +to the specified IPP request. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddSeparator(ipp);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddString(), +ippAddStrings() + + +

    ippAddString()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippAddString(ipp_t      *ipp,
    +             ipp_tag_t  group,
    +             ipp_tag_t  tag,
    +             const char *name,
    +             const char *charset,
    +             const char *value);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    tagThe type of string value
    nameThe name of attribute
    charsetThe character set for the string
    valueThe string value
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddString() function adds a single string attribute +value to the specified IPP request. For IPP_TAG_NAMELANG and +IPP_TAG_TEXTLANG strings, the charset value is provided with +the string to identify the string encoding used. Otherwise the charset value +is ignored. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippAddString(ipp, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
    +             NULL, "abc123");
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddStrings() + + +

    ippAddStrings()

    + +

    Usage

    + +
    +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);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request
    groupThe IPP group
    tagThe type of string value
    nameThe name of attribute
    num_valuesThe number of strings
    charsetThe character set for the strings
    valuesThe string values
    + +

    Returns

    + +

    A pointer to the new attribute or NULL if the attribute could not be +created. + +

    Description

    + +

    The ippAddStrings() function adds one or more string +attribute values to the specified IPP request. For +IPP_TAG_NAMELANG and IPP_TAG_TEXTLANG +strings, the charset value is provided with the strings to identify the +string encoding used. Otherwise the charset value is ignored. If the +values pointer is NULL then an array of +num_values NULL strings is created. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +char *values[2] = { "one", "two" };
    +
    +ippAddStrings(ipp, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "attr-name",
    +              2, NULL, values);
    +
    + +

    See Also

    + +ippAddBoolean(), +ippAddBooleans(), +ippAddDate(), +ippAddInteger(), +ippAddIntegers(), +ippAddRange(), +ippAddRanges(), +ippAddResolution(), +ippAddResolutions(), +ippAddSeparator(), +ippAddString() + + +

    ippDateToTime()

    + +

    Usage

    + +
    +time_t
    +ippDateToTime(const ipp_uchar_t date[11]);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    dateThe IPP date-time value
    + +

    Returns

    + +

    A UNIX time value. + +

    Description

    + +

    The ippDateToTime() function converts an IPP date-time value +to a UNIX time value. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_uchar_t date[11];
    +
    +printf("UNIX time is %d\n", ippDateToTime(date));
    +
    + +

    See Also

    + +ippTimeToDate() + + +

    ippDelete()

    + +

    Usage

    + +
    +void
    +ippDelete(ipp_t *ipp);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    ippThe IPP request or response
    + +

    Description

    + +

    The ippDelete() function deletes all memory used by an IPP +request or response. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ippDelete(ipp);
    +
    + +

    See Also

    + +ippNew() + + +

    ippErrorString()

    + +

    Usage

    + +
    +const char *
    +ippErrorString(ipp_status_t error);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    errorIPP error code.
    + +

    Returns

    + +

    The standard text representation of the IPP error code. + +

    Description

    + +

    ippErrorString() returns the standard text representation +of the IPP error code. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +puts(ippErrorString(IPP_OK));
    +
    + +

    See Also

    + +

    +cupsLastError() + + +

    ippFindAttribute()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippFindAttribute(ipp_t      *ipp,
    +                 const char *name,
    +                 ipp_tag_t  tag);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request or response
    nameThe name of the attribute
    tagThe required value tag for the attribute or + IPP_TAG_ZERO for any type of value.
    + +

    Returns

    + +

    A pointer to the first occurrence of the requested attribute, or +NULL if it was not found. + +

    Description

    + +

    ippFindAttribute() finds the first occurrence of the named +attribute. The tag parameter restricts the search to a specific +value type - use IPP_TAG_ZERO to find any value with the name. + +

    The value tags IPP_TAG_NAME and IPP_TAG_TEXT +match the name/text values with or without the language code. + +

    Example

    + +
    +ipp_attribute_t *attr;
    +
    +attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT);
    +while (attr != NULL)
    +{
    +  puts(attr->values[0].string.text);
    +
    +  attr = ippFindNextAttribute(response, "printer-state-message", IPP_TAG_TEXT);
    +}
    +
    + +

    See Also

    + +cupsDoFileRequest(), +cupsDoRequest(), +ippDelete(), +ippFindNextAttribute(), +ippNew() + + +

    ippFindNextAttribute()

    + +

    Usage

    + +
    +ipp_attribute_t *
    +ippFindNextAttribute(ipp_t      *ipp,
    +                     const char *name,
    +                     ipp_tag_t  tag);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ippThe IPP request or response
    nameThe name of the attribute
    tagThe required value tag for the attribute or + IPP_TAG_ZERO for any type of value.
    + +

    Returns

    + +

    A pointer to the next occurrence of the requested attribute, or +NULL if it was not found. + +

    Description

    + +

    ippFindNextAttribute() finds the next occurrence of the named +attribute. The tag parameter restricts the search to a specific +value type - use IPP_TAG_ZERO to find any value with the name. + +

    The value tags IPP_TAG_NAME and IPP_TAG_TEXT +match the name/text values with or without the language code. + +

    Example

    + +
    +ipp_attribute_t *attr;
    +
    +attr = ippFindAttribute(response, "printer-state-message", IPP_TAG_TEXT);
    +while (attr != NULL)
    +{
    +  puts(attr->values[0].string.text);
    +
    +  attr = ippFindNextAttribute(response, "printer-state-message", IPP_TAG_TEXT);
    +}
    +
    + +

    See Also

    + +cupsDoFileRequest(), +cupsDoRequest(), +ippDelete(), +ippFindNextAttribute(), +ippNew() + + +

    ippLength()

    + +

    Usage

    + +
    +int
    +ippLength(ipp_t *ipp);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    ippThe IPP request or response
    + +

    Returns

    + +

    The total encoded length of the IPP request or response in bytes. + +

    Description

    + +

    ippLength() returns the length of the IPP request or +response in bytes. + +

    Example

    + +
    +printf("The length of the response is %d bytes.\n", ippLength(response));
    +
    + +

    See Also

    + +ippDelete(), +ippNew() + + +

    ippNew()

    + +

    Usage

    + +
    +ipp_t *
    +ippNew(void);
    +
    + +

    Returns

    + +

    A pointer to a new IPP request or response. + +

    Description

    + +

    The ippNew() function creates a new IPP request or response. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_t *ipp;
    +
    +ipp = ippNew();
    +
    + +

    See Also

    + +ippDelete() + + +

    ippPort()

    + +

    Usage

    + +
    +int
    +ippPort(void);
    +
    + +

    Returns

    + +

    The default TCP/IP port number for IPP requests. + +

    Description

    + +

    The ippPort() function returns the default IPP port number +for requests. + +

    Example

    + +
    +#include <cups/http.h>
    +#include <cups/ipp.h>
    +
    +http_t *http;
    +
    +http = httpConnect(cupsServer(), ippPort());
    +
    + +

    See Also

    + +cupsServer(), +ippSetPort() + + +

    ippRead()

    + +

    Usage

    + +
    +ipp_state_t
    +ippRead(http_t *http,
    +        ipp_t  *ipp);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    ippThe IPP request or response
    + +

    Returns

    + +

    The current read state. + +

    Description

    + +

    The ippRead() function reads IPP attributes from the specified +HTTP connection. Programs should continue calling ippRead() until +IPP_ERROR or IPP_DATA is returned. + +

    Example

    + +
    +#include <cups/http.h>
    +#include <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() ...
    +}
    +
    + +

    See Also

    + +ippWrite() + + +

    ippSetPort()

    + +

    Usage

    + +
    +void
    +ippSetPort(int port);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    portThe port number to use
    + +

    Description

    + +

    The ippSetPort() function sets the default IPP port number +for requests. + +

    Example

    + +
    +#include <cups/http.h>
    +#include <cups/ipp.h>
    +
    +...
    +
    +ippSetPort(8631);
    +
    + +

    See Also

    + +ippPort() + + +

    ippTimeToDate()

    + +

    Usage

    + +
    +ipp_uchar_t *
    +ippTimeToDate(time_t time);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    timeThe UNIX time value
    + +

    Returns

    + +

    A static pointer to an IPP date-time value. + +

    Description

    + +

    The ippTimeToDate() function converts a UNIX time to an IPP +date-time value. + +

    Example

    + +
    +#include <cups/ipp.h>
    +
    +ipp_uchar_t *date;
    +
    +date = ippTimeToDate(time(NULL));
    +
    + +

    See Also

    + +ippDateToTime() + + +

    ippWrite()

    + +

    Usage

    + +
    +ipp_state_t
    +ippWrite(http_t *http,
    +         ipp_t  *ipp);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    httpThe HTTP connection
    ippThe IPP request or response
    + +

    Returns

    + +

    The current write state. + +

    Description

    + +

    The ippWrite() function writes IPP attributes to the specified +HTTP connection. Programs should continue calling ippWrite() until +IPP_ERROR or IPP_DATA is returned. + +

    Example

    + +
    +#include <cups/http.h>
    +#include <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() ...
    +}
    +
    + +

    See Also

    + +ippRead() + + +

    ppdClose()

    + +

    Usage

    + +
    +void
    +ppdClose(ppd_file_t *ppd);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    + +

    Description

    + +

    The ppdClose() function frees all memory associated with the +PPD file. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdClose(ppd);
    +
    + +

    See Also

    + +ppdOpen(), +ppdOpenFd(), +ppdOpenFile() + + +

    ppdCollect()

    + +

    Usage

    + +
    +int
    +ppdCollect(ppd_file_t    *ppd,
    +           ppd_section_t section,
    +           ppd_choice_t  ***choices);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file.
    sectionThe document section to collect.
    choicesThe array of option choices that are marked.
    + +

    Returns

    + +

    The number of options collected. + +

    Description

    + +

    ppdCollect() collects all of the marked options in the +specified section, sorts them by their order dependency values, and +returns an array that can be used to emit option commands in the proper +order. It is normally used by the ppdEmit*() functions. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t   *ppd;
    +int          num_choices;
    +ppd_choice_t **choices;
    +
    +...
    +
    +num_choices = ppdCollect(ppd, PPD_ORDER_JCL, &choices);
    +
    + +

    See Also

    + +

    +ppdEmit(), +ppdEmitFd(), +ppdEmitJCL() + + +

    ppdConflicts()

    + +

    Usage

    + +
    +int
    +ppdConflicts(ppd_file_t *ppd);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    + +

    Returns

    + +

    The number of option conflicts in the file. + +

    Description

    + +

    The ppdConflicts() function returns the number of conflicts +with the currently selected options. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +printf("%d conflicts\n", ppdConflicts(ppd));
    +
    + +

    See Also

    + +cupsMarkOptions(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

    ppdEmit()

    + +

    Usage

    + +
    +int
    +ppdEmit(ppd_file_t    *ppd,
    +        FILE          *file,
    +        ppd_section_t section);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    fileThe file to write to
    sectionThe option section to write
    + +

    Returns

    + +

    0 on success, -1 on error. + +

    Description

    + +

    The ppdEmit() function sends printer-specific option +commands to the specified file. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdEmit(ppd, stdout, PPD_ORDER_PAGE);
    +
    + +

    See Also

    + +ppdEmitFd() + + +

    ppdEmitFd()

    + +

    Usage

    + +
    +int
    +ppdEmitFd(ppd_file_t    *ppd,
    +          int           fd,
    +          ppd_section_t section);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    fdThe file descriptor to write to
    sectionThe option section to write
    + +

    Returns

    + +

    0 on success, -1 on error. + +

    Description

    + +

    The ppdEmitFd() function sends printer-specific option +commands to the specified file descriptor. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdEmitFd(ppd, 1, PPD_ORDER_PAGE);
    +
    + +

    See Also

    + +ppdEmit() + + +

    ppdFindChoice()

    + +

    Usage

    + +
    +ppd_choice_t *
    +ppdFindChoice(ppd_option_t *option,
    +              const char   *choice);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    optionA pointer to the option
    choiceThe name of the choice
    + +

    Returns

    + +

    A pointer to the choice data or NULL if the choice does not exist. + +

    Description

    + +

    The ppdFindChoice() function returns a pointer to the choice +data for the specified option. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +ppd_option_t *option;
    +ppd_choice_t *choice;
    +
    +option = ppdFindOption(ppd, "PageSize");
    +choice = ppdFindChoice(option, "Letter");
    +
    + +

    See Also

    + +ppdFindMarkedChoice(), +ppdFindOption() + + +

    ppdFindMarkedChoice()

    + +

    Usage

    + +
    +ppd_choice_t *
    +ppdFindMarkedChoice(ppd_file_t *ppd,
    +                    const char *keyword);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    keywordThe name of the option
    + +

    Returns

    + +

    A pointer to the choice data or NULL if the choice does not exist or +is not marked. + +

    Description

    + +

    The ppdFindMarkedChoice() function returns a pointer to +the marked choice data for the specified option. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +ppd_choice_t *choice;
    +
    +choice = ppdFindMarkedChoice(ppd, "PageSize");
    +
    + +

    See Also

    + +ppdFindChoice(), +ppdFindOption() + + +

    ppdFindOption()

    + +

    Usage

    + +
    +ppd_option_t *
    +ppdFindOption(ppd_file_t *ppd,
    +              const char *keyword);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    keywordThe name of the option
    + +

    Returns

    + +

    A pointer to the option data or NULL if the option does not exist. + +

    Description

    + +

    The ppdFindOption() function returns a pointer to the option +data for the specified option. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +ppd_option_t *option;
    +
    +option = ppdFindOption(ppd, "PageSize");
    +
    + +

    See Also

    + +ppdFindChoice(), +ppdFindMarkedChoice() + + +

    ppdIsMarked()

    + +

    Usage

    + +
    +int
    +ppdIsMarked(ppd_file_t *ppd,
    +            const char *keyword,
    +            const char *choice);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    keywordThe name of the option
    choiceThe name of the option choice
    + +

    Returns

    + +

    1 if the choice is marked, 0 otherwise. + +

    Description

    + +

    The ppdIsMarked() function returns whether or not the +specified option choice is marked. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +printf("Letter size %s selected.\n",
    +       ppdIsMarked(ppd, "PageSize", "Letter") ? "is" : "is not");
    +
    + +

    See Also

    + +cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

    ppdMarkDefaults()

    + +

    Usage

    + +
    +void
    +ppdMarkDefaults(ppd_file_t *ppd);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    + +

    Description

    + +

    The ppdMarkDefaults() function marks all of the default +choices in the PPD file. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdMarkDefaults(ppd);
    +
    + +

    See Also

    + +cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

    ppdMarkOption()

    + +

    Usage

    + +
    +int
    +ppdMarkOption(ppd_file_t *ppd,
    +              const char *keyword,
    +              const char *choice);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    keywordThe name of the option
    choiceThe name of the choice
    + +

    Returns

    + +

    The number of conflicts in the PPD file. + +

    Description

    + +

    The ppdMarkOption() function marks the specified option +choice. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppdMarkOption(ppd, "PageSize", "Letter");
    +
    + +

    See Also

    + +cupsMarkOptions(), +ppdConflicts(), +ppdIsMarked(), +ppdMarkDefaults(), +ppdMarkOption() + + +

    ppdOpen()

    + +

    Usage

    + +
    +ppd_file_t *
    +ppdOpen(FILE *file);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    fileThe file to read from
    + +

    Returns

    + +

    A pointer to a PPD file structure or NULL if the PPD file could not be +read. + +

    Description

    + +

    The ppdOpen() function reads a PPD file from the specified +file into memory. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +FILE *file;
    +
    +file = fopen("filename.ppd", "rb");
    +ppd = ppdOpen(file);
    +fclose(file);
    +
    + +

    See Also

    + +ppdClose(), +ppdOpenFd(), +ppdOpenFile() + + +

    ppdOpenFd()

    + +

    Usage

    + +
    +ppd_file_t *
    +ppdOpenFd(int fd);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    fdThe file descriptor to read from
    + +

    Returns

    + +

    A pointer to a PPD file structure or NULL if the PPD file could not be +read. + +

    Description

    + +

    The ppdOpenFd() function reads a PPD file from the specified +file descriptor into memory. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +int        fd;
    +
    +fd = open("filename.ppd", O_RDONLY);
    +ppd = ppdOpenFd(fd);
    +close(fd);
    +
    + +

    See Also

    + +ppdClose(), +ppdOpen(), +ppdOpenFile() + + +

    ppdOpenFile()

    + +

    Usage

    + +
    +ppd_file_t *
    +ppdOpenFile(const char *filename);
    +
    + +

    Arguments

    + +
    + + + + + + + + +
    ArgumentDescription
    filenameThe name of the file to read from
    + +

    Returns

    + +

    A pointer to a PPD file structure or NULL if the PPD file could not be +read. + +

    Description

    + +

    The ppdOpenFile() function reads a PPD file from the named +file into memory. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +ppd = ppdOpenFile("filename.ppd");
    +
    + +

    See Also

    + +ppdClose(), +ppdOpen(), +ppdOpenFd() + + +

    ppdPageLength()

    + +

    Usage

    + +
    +float
    +ppdPageLength(ppd_file_t *ppd,
    +              const char *name);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    nameThe name of the page size
    + +

    Returns

    + +

    The length of the specified page size in points or 0 if the page size +does not exist. + +

    Description

    + +

    The ppdPageLength() function returns the page length of the +specified page size. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +printf("Length = %.0f\n", ppdPageLength(ppd, "Letter"));
    +
    + +

    See Also

    + +ppdPageLength(), +ppdPageSize(), +ppdPageWidth() + + +

    ppdPageSize()

    + +

    Usage

    + +
    +ppd_size_t *
    +ppdPageSize(ppd_file_t *ppd,
    +            const char *name);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    nameThe name of the page size
    + +

    Returns

    + +

    A pointer to the page size record of the specified page size in +points or NULL if the page size does not exist. + +

    Description

    + +

    The ppdPageSize() function returns the page size record for the +specified page size. + +

    Example

    + +
    +#include <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);
    +}
    +
    + +

    See Also

    + +ppdPageLength(), +ppdPageWidth() + + +

    ppdPageWidth()

    + +

    Usage

    + +
    +float
    +ppdPageWidth(ppd_file_t *ppd,
    +             const char *name);
    +
    + +

    Arguments

    + +
    + + + + + + + + + + + + +
    ArgumentDescription
    ppdThe PPD file
    nameThe name of the page size
    + +

    Returns

    + +

    The width of the specified page size in points or 0 if the page size +does not exist. + +

    Description

    + +

    The ppdPageWidth() function returns the page width of the +specified page size. + +

    Example

    + +
    +#include <cups/ppd.h>
    +
    +ppd_file_t *ppd;
    +
    +printf("Width = %.0f\n", ppdPageWidth(ppd, "Letter"));
    +
    + +

    See Also

    + +ppdPageLength(), +ppdPageSize() + + + + diff --git a/doc/sps.html b/doc/sps.html new file mode 100644 index 000000000..90b032fa8 --- /dev/null +++ b/doc/sps.html @@ -0,0 +1,297 @@ + + + +CUPS Software Performance Specification + + + + + + + +

    +

    CUPS Software Performance Specification


    +CUPS-SPS-1.2
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    1 Scope + +2 References + +3 Programs +
    +
    4 Scheduler Objects +
    +
    A Glossary + +
    +

    1 Scope

    +

    1.1 Identification

    +

    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.2.

    +

    For the purposes of comparison, all figures are for the Linux Intel + platform. Memory utilization on other platforms should be similar.

    +

    1.2 System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    +

    1.3 Document Overview

    +

    This software performance specification is organized into the + following sections:

    +
      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Programs
    • +
    • 4 - Scheduler Objects
    • +
    • A - Glossary
    • +
    +

    2 References

    +

    2.1 CUPS Documentation

    +

    The following CUPS documentation is referenced by this document:

    +
      +
    • CUPS-CMP-1.2: CUPS Configuration Management Plan
    • +
    • CUPS-IDD-1.2: CUPS System Interface Design Description
    • +
    • CUPS-IPP-1.2: CUPS Implementation of IPP
    • +
    • CUPS-SAM-1.2.x: CUPS Software Administrators Manual
    • +
    • CUPS-SDD-1.2: CUPS Software Design Description
    • +
    • CUPS-SPM-1.2.x: CUPS Software Programming Manual
    • +
    • CUPS-SSR-1.2: CUPS Software Security Report
    • +
    • CUPS-STP-1.2: CUPS Software Test Plan
    • +
    • CUPS-SUM-1.2.x: CUPS Software Users Manual
    • +
    • CUPS-SVD-1.2: CUPS Software Version Description
    • +
    +

    2.2 Other Documents

    +

    The following non-CUPS documents are referenced by this document:

    + +

    3 Programs

    +

    The following table describes the average memory, disk, and CPU usage + of each program in CUPS.

    +

    The base memory column shows the initial memory requirements for each + program, including any shared libraries that are provided by CUPS.

    +

    The max memory column shows the maximum amount of memory that will be + used by the program based upon the default configuration settings + supplied with CUPS.

    +

    The temp files column indicates whether any temporary files are + created.

    +

    The CPU usage column specifies a relative CPU usage by the program + under normal conditions, either low, medium, or high. Low usage + indicates that the program will never use more than 33% of the + available CPU time. Medium usage indicates the program will use as much + as 66% of the available CPU time. High usage indicates the program uses + 66% or more of the available CPU time. +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Backends
    ProgramBase MemoryMax MemoryTemp + FilesCPU Usage
    ipp91k256kUp to size of print file +Low
    lpd89k89kUp to size of print file +Low
    parallel85k85kUp to size of print + fileLow
    serial85k85kUp to size of print file +Low
    socket85k85kUp to size of print file +Low
    usb85k85kUp to size of print file +Low
    CGIs
    ProgramBase MemoryMax MemoryTemp + FilesCPU Usage
    admin.cgi107k256kUp to size of PPD + fileMedium
    classes.cgi95kSize of class objects +NoneMedium
    jobs.cgi93kSize of job objectsNone +Medium
    printers.cgi95kSize of printer objects +NoneMedium
    Command-Line Programs
    ProgramBase MemoryMax MemoryTemp + FilesCPU Usage
    accept88k128kNoneLow
    cancel88k128kNoneLow
    disable88k128kNoneLow
    enable88k128kNoneLow
    lp90k256kNoneLow
    lpadmin148k256kNoneLow
    lpc86kSize of job and printer objects +NoneMedium
    lpinfo89kSize of device and PPD objects +NoneMedium
    lpmove88k128kNoneLow
    lpoptions89k128kNoneLow
    lppasswd90k90kNoneLow
    lpq87kSize of job objectsNone +Medium
    lpr87k256kNoneLow
    lprm84k128kNoneLow
    lpstat119kSize of job, printer, and class + objectsNoneMedium
    reject88k128kNoneLow
    Daemons
    ProgramBase MemoryMax MemoryTemp + FilesCPU Usage
    cups-lpd92k256kOne file per control + or data file from clientLow
    cupsd308kSee Scheduler Requirements +See Scheduler RequirementsMedium
    cups-polld84kSize of printer and class objects +NoneLow
    Filters
    ProgramBase MemoryMax MemoryTemp + FilesCPU Usage
    hpgltops263k320kNoneMedium
    imagetops628k10MSwap file for + uncompressed image dataMedium
    imagetoraster652k10MSwap file for + uncompressed image dataHigh
    pstops775k840kUp to size of print + fileMedium
    pstoraster4M14MSwap file for command + listsHigh
    rastertoepson693k1MNoneLow
    rastertohp690k1MNoneLow
    texttops638k4*cols*rowsNone +Low
    +
    +

    +

    4 Scheduler Objects

    +

    The cupsd program is the CUPS scheduler process. It + manages many interdependent server objects that are used to manage and + print files to printers.

    +

    The following table provides the memory and disk cost associated with + each server object. +

    + + + + + + + + + + + + + + + +
    ObjectMemory PerDisk Per
    Browse ACL1k120
    Browse Poll2480
    Browse Relay2880
    Certificate7632
    Class9k200
    Client13k-
    Device256-
    Job2k1k + size of document files
    Location ACL1k120
    MIME Filter26880
    MIME Type34080
    PPD200656
    Printer11k32k
    +
    +

    +

    A Glossary

    +

    A.1 Terms

    +
    +
    C
    +
    A computer language.
    +
    parallel
    +
    Sending or receiving data more than 1 bit at a time.
    +
    pipe
    +
    A one-way communications channel between two programs.
    +
    serial
    +
    Sending or receiving data 1 bit at a time.
    +
    socket
    +
    A two-way network communications channel.
    +
    +

    A.2 Acronyms

    +
    +
    ASCII
    +
    American Standard Code for Information Interchange
    +
    CUPS
    +
    Common UNIX Printing System
    +
    ESC/P
    +
    EPSON Standard Code for Printers
    +
    FTP
    +
    File Transfer Protocol
    +
    HP-GL
    +
    Hewlett-Packard Graphics Language
    +
    HP-PCL
    +
    Hewlett-Packard Page Control Language
    +
    HP-PJL
    +
    Hewlett-Packard Printer Job Language
    +
    IETF
    +
    Internet Engineering Task Force
    +
    IPP
    +
    Internet Printing Protocol
    +
    ISO
    +
    International Standards Organization
    +
    LPD
    +
    Line Printer Daemon
    +
    MIME
    +
    Multimedia Internet Mail Exchange
    +
    PPD
    +
    PostScript Printer Description
    +
    SMB
    +
    Server Message Block
    +
    TFTP
    +
    Trivial File Transfer Protocol
    +
    + + diff --git a/doc/sps.pdf b/doc/sps.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8a0dfa1a2f25702a95c894a8367052b822655f60 GIT binary patch literal 41182 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

    p2uF| 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 x3_)Nc2n22bhXBz|(FYu#N{Li{|_@q=RyDg literal 0 Hc-jL100001 diff --git a/doc/sps.shtml b/doc/sps.shtml new file mode 100644 index 000000000..5e2d3ee57 --- /dev/null +++ b/doc/sps.shtml @@ -0,0 +1,457 @@ + + + + + + CUPS Software Performance Specification + + + +

    Scope

    + +

    Identification

    + +

    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.2.

    + +

    For the purposes of comparison, all figures are for the Linux Intel +platform. Memory utilization on other platforms should be similar. + + + +

    Document Overview

    + +

    This software performance specification is organized into the +following sections:

    + +
      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Programs
    • +
    • 4 - Scheduler Objects
    • +
    • A - Glossary
    • +
    + + + +

    Programs

    + +

    The following table describes the average memory, disk, and CPU usage of +each program in CUPS. + +

    The base memory column shows the initial memory requirements for each +program, including any shared libraries that are provided by CUPS. + +

    The max memory column shows the maximum amount of memory that will be +used by the program based upon the default configuration settings supplied +with CUPS. + +

    The temp files column indicates whether any temporary files are created. + +

    The CPU usage column specifies a relative CPU usage by the program under +normal conditions, either low, medium, or high. Low usage indicates that +the program will never use more than 33% of the available CPU time. Medium +usage indicates the program will use as much as 66% of the available CPU +time. High usage indicates the program uses 66% or more of the available CPU +time. + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Backends
    ProgramBase MemoryMax MemoryTemp FilesCPU Usage
    ipp91k256kUp to size of print fileLow
    lpd89k89kUp to size of print fileLow
    parallel85k85kUp to size of print fileLow
    serial85k85kUp to size of print fileLow
    socket85k85kUp to size of print fileLow
    usb85k85kUp to size of print fileLow
    CGIs
    ProgramBase MemoryMax MemoryTemp FilesCPU Usage
    admin.cgi107k256kUp to size of PPD fileMedium
    classes.cgi95kSize of class objectsNoneMedium
    jobs.cgi93kSize of job objectsNoneMedium
    printers.cgi95kSize of printer objectsNoneMedium
    Command-Line Programs
    ProgramBase MemoryMax MemoryTemp FilesCPU Usage
    accept88k128kNoneLow
    cancel88k128kNoneLow
    disable88k128kNoneLow
    enable88k128kNoneLow
    lp90k256kNoneLow
    lpadmin148k256kNoneLow
    lpc86kSize of job and printer objectsNoneMedium
    lpinfo89kSize of device and PPD objectsNoneMedium
    lpmove88k128kNoneLow
    lpoptions89k128kNoneLow
    lppasswd90k90kNoneLow
    lpq87kSize of job objectsNoneMedium
    lpr87k256kNoneLow
    lprm84k128kNoneLow
    lpstat119kSize of job, printer, and class objectsNoneMedium
    reject88k128kNoneLow
    Daemons
    ProgramBase MemoryMax MemoryTemp FilesCPU Usage
    cups-lpd92k256kOne file per control or data file from clientLow
    cupsd308kSee Scheduler RequirementsSee Scheduler RequirementsMedium
    cups-polld84kSize of printer and class objectsNoneLow
    Filters
    ProgramBase MemoryMax MemoryTemp FilesCPU Usage
    hpgltops263k320kNoneMedium
    imagetops628k10MSwap file for uncompressed image dataMedium
    imagetoraster652k10MSwap file for uncompressed image dataHigh
    pstops775k840kUp to size of print fileMedium
    pstoraster4M14MSwap file for command listsHigh
    rastertoepson693k1MNoneLow
    rastertohp690k1MNoneLow
    texttops638k4*cols*rowsNoneLow
    + + +

    Scheduler Objects

    + +

    The cupsd program is the CUPS scheduler process. It manages +many interdependent server objects that are used to manage and print files +to printers. + +

    The following table provides the memory and disk cost associated with each +server object. + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    ObjectMemory PerDisk Per
    Browse ACL1k120
    Browse Poll2480
    Browse Relay2880
    Certificate7632
    Class9k200
    Client13k-
    Device256-
    Job2k1k + size of document files
    Location ACL1k120
    MIME Filter26880
    MIME Type34080
    PPD200656
    Printer11k32k
    + + + + + diff --git a/doc/ssr.html b/doc/ssr.html new file mode 100644 index 000000000..a943892be --- /dev/null +++ b/doc/ssr.html @@ -0,0 +1,275 @@ + + + +CUPS Software Security Report + + + + + + + +

    +

    CUPS Software Security Report


    +CUPS-SSR-1.2
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    1 Scope + +2 References + +3 Local Access Risks + +4 Remote Access Risks + +A Glossary + +
    +

    1 Scope

    +

    1.1 Identification

    +

    This software security report provides an analysis of possible + security concerns for the Common UNIX Printing System ("CUPS") Version + 1.2.

    +

    1.2 System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    +

    1.3 Document Overview

    +

    This software security report is organized into the following + sections:

    +
      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Local Access Risks
    • +
    • 4 - Remote Access Risks
    • +
    • A - Glossary
    • +
    +

    2 References

    +

    2.1 CUPS Documentation

    +

    The following CUPS documentation is referenced by this document:

    +
      +
    • CUPS-CMP-1.2: CUPS Configuration Management Plan
    • +
    • CUPS-IDD-1.2: CUPS System Interface Design Description
    • +
    • CUPS-IPP-1.2: CUPS Implementation of IPP
    • +
    • CUPS-SAM-1.2.x: CUPS Software Administrators Manual
    • +
    • CUPS-SDD-1.2: CUPS Software Design Description
    • +
    • CUPS-SPM-1.2.x: CUPS Software Programming Manual
    • +
    • CUPS-SSR-1.2: CUPS Software Security Report
    • +
    • CUPS-STP-1.2: CUPS Software Test Plan
    • +
    • CUPS-SUM-1.2.x: CUPS Software Users Manual
    • +
    • CUPS-SVD-1.2: CUPS Software Version Description
    • +
    +

    2.2 Other Documents

    +

    The following non-CUPS documents are referenced by this document:

    + +

    3 Local Access Risks

    +

    Local access risks are those that can be exploited only with a local + user account. This section does not address issues related to + dissemination of the root password or other security issues associated + with the UNIX operating system.

    +

    3.1 Security Breaches

    +

    There is one known security vulnerability with local access:

    +
      +
    1. Device URIs are passed to backend filters in argv[0] and in an + environment variable. Since device URIs can contain usernames and + passwords it may be possible for a local user to gain access to a + remote resource. +

      We recommend that any password-protected accounts used for remote + printing have limited access priviledges so that the possible damages + can be minimized.

      +

      The device URI is "sanitized" (the username and password are removed) + when sent to an IPP client so that a remote user cannot exploit this + vulnerability.

      +
    2. +
    +

    4 Remote Access Risks

    +

    Remote access risks are those that can be exploited without a local + user account and/or from a remote system. This section does not address + issues related to network or firewall security.

    +

    4.1 Denial of Service Attacks

    +

    Like all Internet services, the CUPS server is vulnerable to denial + of service attacks, including:

    +
      +
    1. Establishing multiple connections to the server until the server + will accept no more. +

      This cannot be protected against by the current software. It is + possible that future versions of the CUPS software could be configured + to limit the number of connections allowed from a single host, however + that still would not prevent a distributed attack.

      +
    2. Repeatedly opening and closing connections to the server as fast as + possible. +

      There is no easy way of protecting against this in the CUPS software. + If the attack is coming from outside the local network it might be + possible to filter such an attack, however once the connection request + has been received by the server it must at least accept the connection + to find out who is connecting.

      +
    3. Flooding the network with broadcast packets on port 631. +

      It might be possible to disable browsing if this condition is + detected by the CUPS software, however if there are large numbers of + printers available on the network such an algorithm might think that an + attack was occurring when instead a valid update was being received.

      +
    4. Sending partial IPP requests; specifically, sending part of an + attribute value and then stopping transmission. +

      The current code is structured to read and write the IPP request data + on-the-fly, so there is no easy way to protect against this for large + attribute values.

      +
    5. Sending large/long print jobs to printers, preventing other users + from printing. +

      There are limited facilities for protecting against large print jobs + (the MaxRequestSize attribute), however this will not + protect printers from malicious users and print files that generate + hundreds or thousands of pages. In general, we recommend restricting + printer access to known hosts or networks, and adding user-level access + control as needed for expensive printers.

      +
    6. + + + + +
    +

    4.2 Security Breaches

    +

    The current CUPS server supports Basic, Digest, and local certificate + authentication:

    +
      +
    1. Basic authentication essentially places the clear text of the + username and password on the network. Since CUPS uses the UNIX username + and password account information, the authentication information could + be used to gain access to accounts (possibly priviledged accounts) on + the server.
    2. +
    3. 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.
    4. +
    5. Local certificate authentication passes 128-bit "certificates" that + identify an authenticated user. Certificates are created on-the-fly + from random data and stored in files under /etc/cups/certs +. They have restricted read permissions: root + system for the root + certificate, and lp + system for CGI certificates. Because certificates + are only available on the local system, the CUPS server does not accept + local authentication unless the client is connected to the localhost + address (127.0.0.1.)
    6. +
    +

    The default CUPS configuration disables remote administration. We do + not recommend that remote administration be enabled for all hosts. + However, if you have a trusted network or subnet, access can be + restricted accordingly. Also, we highly recommend using Digest + authentication when possible. Unfortunately, most web browsers do not + support Digest authentication at this time.

    +

    A Glossary

    +

    A.1 Terms

    +
    +
    C
    +
    A computer language.
    +
    parallel
    +
    Sending or receiving data more than 1 bit at a time.
    +
    pipe
    +
    A one-way communications channel between two programs.
    +
    serial
    +
    Sending or receiving data 1 bit at a time.
    +
    socket
    +
    A two-way network communications channel.
    +
    +

    A.2 Acronyms

    +
    +
    ASCII
    +
    American Standard Code for Information Interchange
    +
    CUPS
    +
    Common UNIX Printing System
    +
    ESC/P
    +
    EPSON Standard Code for Printers
    +
    FTP
    +
    File Transfer Protocol
    +
    HP-GL
    +
    Hewlett-Packard Graphics Language
    +
    HP-PCL
    +
    Hewlett-Packard Page Control Language
    +
    HP-PJL
    +
    Hewlett-Packard Printer Job Language
    +
    IETF
    +
    Internet Engineering Task Force
    +
    IPP
    +
    Internet Printing Protocol
    +
    ISO
    +
    International Standards Organization
    +
    LPD
    +
    Line Printer Daemon
    +
    MIME
    +
    Multimedia Internet Mail Exchange
    +
    PPD
    +
    PostScript Printer Description
    +
    SMB
    +
    Server Message Block
    +
    TFTP
    +
    Trivial File Transfer Protocol
    +
    + + diff --git a/doc/ssr.pdf b/doc/ssr.pdf new file mode 100644 index 0000000000000000000000000000000000000000..329cd173ef70d413ef1396a37381fd63acf4ca15 GIT binary patch literal 39878 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%0AE6{>8ehu|XDm2_sLr;f(|AV`skFetp=I&kt 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%0Ag>YxCQ)^?;Ro># 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 JBC?`*{}1&5$2tH2 literal 0 Hc-jL100001 diff --git a/doc/ssr.shtml b/doc/ssr.shtml new file mode 100644 index 000000000..0eb283b65 --- /dev/null +++ b/doc/ssr.shtml @@ -0,0 +1,167 @@ + + + + + + CUPS Software Security Report + + + +

    Scope

    + +

    Identification

    + +

    This software security report provides an analysis of possible security +concerns for the Common UNIX Printing System ("CUPS") Version 1.2.

    + + + +

    Document Overview

    + +

    This software security report is organized into the following sections:

    + +
      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Local Access Risks
    • +
    • 4 - Remote Access Risks
    • +
    • A - Glossary
    • +
    + + + +

    Local Access Risks

    + +

    Local access risks are those that can be exploited only with a local user +account. This section does not address issues related to dissemination of the +root password or other security issues associated with the UNIX operating +system. + +

    Security Breaches

    + +

    There is one known security vulnerability with local access: + +

      + +
    1. Device URIs are passed to backend filters in argv[0] and in + an environment variable. Since device URIs can contain + usernames and passwords it may be possible for a local user to + gain access to a remote resource. + +

      We recommend that any password-protected accounts used for + remote printing have limited access priviledges so that the + possible damages can be minimized. + +

      The device URI is "sanitized" (the username and password are + removed) when sent to an IPP client so that a remote user + cannot exploit this vulnerability. + +

    + +

    Remote Access Risks

    + +

    Remote access risks are those that can be exploited without a local user +account and/or from a remote system. This section does not address issues +related to network or firewall security. + +

    Denial of Service Attacks

    + +

    Like all Internet services, the CUPS server is vulnerable to denial of +service attacks, including: + +

      + +
    1. Establishing multiple connections to the server until the server + will accept no more. + +

      This cannot be protected against by the current software. It + is possible that future versions of the CUPS software could be + configured to limit the number of connections allowed from a + single host, however that still would not prevent a distributed + attack. + +

    2. Repeatedly opening and closing connections to the server as fast + as possible. + +

      There is no easy way of protecting against this in the CUPS + software. If the attack is coming from outside the local + network it might be possible to filter such an attack, however + once the connection request has been received by the server it + must at least accept the connection to find out who is + connecting. + +

    3. Flooding the network with broadcast packets on port 631. + +

      It might be possible to disable browsing if this condition + is detected by the CUPS software, however if there are large + numbers of printers available on the network such an algorithm + might think that an attack was occurring when instead a valid + update was being received. + +

    4. Sending partial IPP requests; specifically, sending part of an + attribute value and then stopping transmission. + +

      The current code is structured to read and write the IPP + request data on-the-fly, so there is no easy way to protect + against this for large attribute values. + +

    5. Sending large/long print jobs to printers, preventing other users + from printing. + +

      There are limited facilities for protecting against large print + jobs (the MaxRequestSize attribute), however this will + not protect printers from malicious users and print files that + generate hundreds or thousands of pages. In general, we recommend + restricting printer access to known hosts or networks, and adding + user-level access control as needed for expensive printers. + +

    + +

    Security Breaches

    + +

    The current CUPS server supports Basic, Digest, and local certificate +authentication: + +

      + +
    1. Basic authentication essentially places the clear text of + the username and password on the network. Since CUPS uses the + UNIX username and password account information, the + authentication information could be used to gain access to + accounts (possibly priviledged accounts) on the server. + +
    2. 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. + +
    3. Local certificate authentication passes 128-bit + "certificates" that identify an authenticated user. + Certificates are created on-the-fly from random data and stored + in files under /etc/cups/certs. They have + restricted read permissions: root + system for the root + certificate, and lp + system for CGI certificates. Because + certificates are only available on the local system, the CUPS + server does not accept local authentication unless the client + is connected to the localhost address (127.0.0.1.) + +
    + +

    The default CUPS configuration disables remote administration. We do +not recommend that remote administration be enabled for all hosts. +However, if you have a trusted network or subnet, access can be +restricted accordingly. + +Also, we highly recommend using Digest authentication when possible. +Unfortunately, most web browsers do not support Digest authentication +at this time. + + + + + diff --git a/doc/stp.html b/doc/stp.html new file mode 100644 index 000000000..e354cd49a --- /dev/null +++ b/doc/stp.html @@ -0,0 +1,262 @@ + + + +CUPS Software Test Plan + + + + + + + +


    +

    CUPS Software Test Plan


    +CUPS-STP-1.2
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    1 Scope + +2 References + +3 Test Procedure +
    +
    4 IPP Compliance Tests + +5 Command Tests + +A Glossary + +
    +

    1 Scope

    +

    1.1 Identification

    +

    This software test plan provides detailed tests that are used to + evaluate the stability and compliance of the Common UNIX Printing + System ("CUPS") Version 1.2.

    +

    1.2 System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    +

    1.3 Document Overview

    +

    This software test plan is organized into the following sections:

    +
      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Test Procedure
    • +
    • 4 - IPP Compliance Tests
    • +
    • 5 - Command Tests
    • +
    • A - Glossary
    • +
    +

    2 References

    +

    2.1 CUPS Documentation

    +

    The following CUPS documentation is referenced by this document:

    +
      +
    • CUPS-CMP-1.2: CUPS Configuration Management Plan
    • +
    • CUPS-IDD-1.2: CUPS System Interface Design Description
    • +
    • CUPS-IPP-1.2: CUPS Implementation of IPP
    • +
    • CUPS-SAM-1.2.x: CUPS Software Administrators Manual
    • +
    • CUPS-SDD-1.2: CUPS Software Design Description
    • +
    • CUPS-SPM-1.2.x: CUPS Software Programming Manual
    • +
    • CUPS-SSR-1.2: CUPS Software Security Report
    • +
    • CUPS-STP-1.2: CUPS Software Test Plan
    • +
    • CUPS-SUM-1.2.x: CUPS Software Users Manual
    • +
    • CUPS-SVD-1.2: CUPS Software Version Description
    • +
    +

    2.2 Other Documents

    +

    The following non-CUPS documents are referenced by this document:

    + +

    3 Test Procedure

    +

    The test software and data files are located in the test + subdirectory of the source distribution. A script is provided to + compile the ipptest program and run all of the tests that + follow, producing a success/fail report.

    +

    The test target of the top-level makefile can be used to + run this script:

    +
      +
      +make test
      +
      +
    +

    or you can run the test script directly:

    +
      +
      +cd test
      +./run-stp-tests
      +
      +
    +

    A Software Test Report is stored in HTML and PDF files that are + generated using the HTMLDOC + software.

    +

    4 IPP Compliance Tests

    +

    This section describes the tests used to validate the IPP standards + compliance of the CUPS server.

    +

    4.1 Request Tests

    +

    These tests verify that the CUPS scheduler only accepts valid IPP + requests that start with the attributes-charset and +attributes-natural-language attributes and also contain a +printer-uri or job-uri attribute.

    +

    It also verifies that the CUPS scheduler always responds with +attributes-charset and attributes-natural-language + attributes, using default values if they are not provided by the + client.

    +

    4.2 CUPS Printer Operation Tests

    +

    These tests verify that the CUPS printer operations are supported and + function properly. Two printers called Test1 and +Test2 are created, one as a PostScript printer and one as a + raster printer.

    +

    4.3 Job Operation Tests

    +

    These test verify that the CUPS scheduler accepts print jobs for all + supported file formats and that the cancel-job, +hold-job, and resume-job operations work.

    +

    5 Command Tests

    +

    This section describes the tests used to validate the Berkeley and + System V commands included with CUPS.

    +

    5.1 lpadmin

    +

    This test verifies that printers can be added, modified, and + defaulted using the lpadmin command.

    +

    5.2 lpc

    +

    This test verifies that the lpc command can show the + current status of all print queues.

    +

    5.3 lpq

    +

    This test verifies that the lpq command lists any jobs + in the queue.

    +

    5.4 lpstat

    +

    This test verifies that the lpstat command works with + all reports using the "-t" option.

    +

    5.5 lp

    +

    This test verifies that the lp command works with both + the default destination and a specific destination.

    +

    5.6 lpr

    +

    This test verifies that the lpr command works with both + the default destination and a specific destination.

    +

    5.7 lprm

    +

    This test verifies that the lprm command can properly + cancel a job.

    +

    5.8 cancel

    +

    This test verifies that the cancel command can properly + cancel a job or all jobs.

    +

    5.9 lpinfo

    +

    This test verifies that the lpinfo command returns a + list of available printer drivers and devices.

    +

    A Glossary

    +

    A.1 Terms

    +
    +
    C
    +
    A computer language.
    +
    parallel
    +
    Sending or receiving data more than 1 bit at a time.
    +
    pipe
    +
    A one-way communications channel between two programs.
    +
    serial
    +
    Sending or receiving data 1 bit at a time.
    +
    socket
    +
    A two-way network communications channel.
    +
    +

    A.2 Acronyms

    +
    +
    ASCII
    +
    American Standard Code for Information Interchange
    +
    CUPS
    +
    Common UNIX Printing System
    +
    ESC/P
    +
    EPSON Standard Code for Printers
    +
    FTP
    +
    File Transfer Protocol
    +
    HP-GL
    +
    Hewlett-Packard Graphics Language
    +
    HP-PCL
    +
    Hewlett-Packard Page Control Language
    +
    HP-PJL
    +
    Hewlett-Packard Printer Job Language
    +
    IETF
    +
    Internet Engineering Task Force
    +
    IPP
    +
    Internet Printing Protocol
    +
    ISO
    +
    International Standards Organization
    +
    LPD
    +
    Line Printer Daemon
    +
    MIME
    +
    Multimedia Internet Mail Exchange
    +
    PPD
    +
    PostScript Printer Description
    +
    SMB
    +
    Server Message Block
    +
    TFTP
    +
    Trivial File Transfer Protocol
    +
    + + diff --git a/doc/stp.pdf b/doc/stp.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0037bd5e3bf1649b5860589b38410bceb35cc4c2 GIT binary patch literal 43329 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 + + + + + + CUPS Software Test Plan + + + +

    Scope

    + +

    Identification

    + +

    This software test plan provides detailed tests that are used +to evaluate the stability and compliance of the Common UNIX +Printing System ("CUPS") Version 1.2. + + + +

    Document Overview

    + +

    This software test plan is organized into the following sections: + +

      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Test Procedure
    • +
    • 4 - IPP Compliance Tests
    • +
    • 5 - Command Tests
    • +
    • A - Glossary
    • +
    + + + +

    Test Procedure

    + +

    The test software and data files are located in the test +subdirectory of the source distribution. A script is provided to compile +the ipptest program and run all of the tests that follow, +producing a success/fail report. + +

    The test target of the top-level makefile can be used to +run this script: + +

      +make test
      +
    + +

    or you can run the test script directly: + +

      +cd test
      +./run-stp-tests
      +
    + +

    A Software Test Report is stored in HTML and PDF files that +are generated using the +HTMLDOC software. + +

    IPP Compliance Tests

    + +

    This section describes the tests used to validate the IPP +standards compliance of the CUPS server. + +

    Request Tests

    + +

    These tests verify that the CUPS scheduler only accepts valid +IPP requests that start with the attributes-charset +and attributes-natural-language attributes and also +contain a printer-uri or job-uri attribute. + +

    It also verifies that the CUPS scheduler always responds with +attributes-charset and +attributes-natural-language attributes, using +default values if they are not provided by the client. + +

    CUPS Printer Operation Tests

    + +

    These tests verify that the CUPS printer operations are supported +and function properly. Two printers called Test1 and +Test2 are created, one as a PostScript printer and one +as a raster printer. + +

    Job Operation Tests

    + +

    These test verify that the CUPS scheduler accepts print jobs for +all supported file formats and that the cancel-job, +hold-job, and resume-job operations work. + +

    Command Tests

    + +

    This section describes the tests used to validate the +Berkeley and System V commands included with CUPS. + +

    lpadmin

    + +

    This test verifies that printers can be added, modified, and +defaulted using the lpadmin command. + +

    lpc

    + +

    This test verifies that the lpc command can show +the current status of all print queues. + +

    lpq

    + +

    This test verifies that the lpq command lists +any jobs in the queue. + +

    lpstat

    + +

    This test verifies that the lpstat command works +with all reports using the "-t" option. + +

    lp

    + +

    This test verifies that the lp command works +with both the default destination and a specific destination. + +

    lpr

    + +

    This test verifies that the lpr command works +with both the default destination and a specific destination. + +

    lprm

    + +

    This test verifies that the lprm command can +properly cancel a job. + +

    cancel

    + +

    This test verifies that the cancel command can +properly cancel a job or all jobs. + +

    lpinfo

    + +

    This test verifies that the lpinfo command +returns a list of available printer drivers and devices. + + + + + diff --git a/doc/sum.html b/doc/sum.html new file mode 100644 index 000000000..2135cb6d2 --- /dev/null +++ b/doc/sum.html @@ -0,0 +1,1732 @@ + + + +CUPS Software Users Manual + + + + + + + +


    +

    CUPS Software Users Manual


    +CUPS-SUM-1.2.0
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    Preface + +1 - Printing System Overview + +2 - Using the Printing System + +3 - Standard Printer Options + +4 - Saving Printer Options and Defaults + +A - Software License Agreement + +
    +

    Preface

    +

    This software users manual describes how to use the Common UNIX + Printing SystemTM ("CUPSTM") Version 1.2.0.

    +

    System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    + + +

    Document Overview

    +

    This software users manual is organized into the following sections:

    + +

    Notation Conventions

    +

    Various font and syntax conventions are used in this guide. Examples + and their meanings and uses are explained below: +

    + + + + + + + + + + + + +
    Example   Description
     
    lpstat +
    lpstat(1)
       The names of commands; + the first mention of a command or function in a chapter is followed by + a manual page section number.
     
    /var +
    /usr/share/cups/data/testprint.ps
        +File and directory names.
     
    Request ID is Printer-123 +   Screen output.
     
    lp -d printer filename ENTER +   Literal user input; special keys like ENTER are + in ALL CAPS.
     
    12.3   Numbers in the text are + written using the period (.) to indicate the decimal point.
    +
    + + +

    +

    Abbreviations

    + The following abbreviations are used throughout this manual: +
      +
      +
      kb
      +
      Kilobytes, or 1024 bytes +
       
      +
      Mb
      +
      Megabytes, or 1048576 bytes +
       
      +
      Gb
      +
      Gigabytes, or 1073741824 bytes +
       
      +
      +
    +

    Other References

    +
      +
      +
      CUPS Software Administrators Manual
      +
      An administration guide for the CUPS software. +
       
      +
      CUPS Software Programmers Manual
      +
      A programmer guide for interfacing with and/or extending the CUPS + software. +
       
      +
      +
    +

    1 - Printing System Overview

    +

    This chapter provides an overview of how the Common UNIX Printing + System works.

    +

    The Printing Problem

    +

    For years the printing problem has plagued UNIX. Unlike + Microsoft® Windows® or Mac OS, UNIX has no standard interface or system + in place for supporting printers. Among the solutions currently + available, the Berkeley and System V printing systems are the most + prevalent.

    +

    These printing systems support line printers (text only) or + PostScript printers (text and graphics), and with some coaxing they can + be made to support a full range of printers and file formats. However, + because each varient of the UNIX operating system uses a different + printing system than the next developing printer drivers for a wide + range of printers and operating systems is extremely difficult. That + combined with the limited volume of customers for each UNIX varient has + forced most printer vendors to give up supporting UNIX entirely.

    +

    CUPS is designed to eliminate the printing problem. One common + printing system can be used by all UNIX varients to support the + printing needs of users. Printer vendors can use its modular filter + interface to develop a single driver program that supports a wide range + of file formats with little or no effort. Since CUPS provides both the + System V and Berkeley printing commands, users (and applications) can + reap the benefits of this new technology with no changes.

    +

    The Technology

    +

    CUPS is based upon an emerging Internet standard called the Internet + Printing Protocol. IPP has been embraced by dozens of printer and + printer server manufacturers and is supported by Microsoft Windows + 2000.

    +

    IPP defines a standard protocol for printing as well as managing + print jobs and printer options like media size, resolution, and so + forth. Like all IP-based protocols, IPP can be used locally or over the + Internet to printers hundreds or thousands of miles away. Unlike other + protocols, however, IPP also supports access control, authentication, + and encryption, making it a much more capable and secure printing + solution than older ones.

    +

    IPP is layered on top of the Hyper-Text Transport Protocol ("HTTP") + which is the basis of web servers on the Internet. This allows users to + view documentation, check status information on a printer or server, + and manage their printers, classes, and jobs using their web browser.

    +

    CUPS provides a complete IPP/1.1 based printing system that provides + Basic, Digest, and local certificate authentication and user, domain, + or IP-based access control. TLS encryption will be available in future + versions of CUPS.

    +

    Jobs

    +

    Each file or set of files that is submitted for printing is called a + job. Jobs are identified by a unique number starting at 1 and are + assigned to a particular destination, usually a printer. Jobs can also + have options associated with them such as media size, number of copies, + and priority.

    +

    Classes

    +

    CUPS supports collections of printers known as classes. Jobs + sent to a class are forwarded to the first available printer in the + class.

    +

    Filters

    +

    Filters allow a user or application to print many types of files + without extra effort. Print jobs sent to a CUPS server are filtered + before sending them to a printer. Some filters convert job files to + different formats that the printer can understand. Others perform page + selection and ordering tasks.

    +

    CUPS provides filters for printing many types of image files, HP-GL/2 + files, PDF files, and text files. CUPS also supplies PostScript and + image file Raster Image Processor ("RIP") filters that convert + PostScript or image files into bitmaps that can be sent to a raster + printer.

    +

    Backends

    +

    Backends perform the most important task of all - they send the + filtered print data to the printer.

    +

    CUPS provides backends for printing over parallel, serial, and USB + ports, and over the network via the IPP, JetDirect (AppSocket), and + Line Printer Daemon ("LPD") protocols. Additional backends are + available in network service packages such as the SMB backend included + with the popular SAMBA software.

    +

    Backends are also used to determine the available devices. On startup + each backend is asked for a list of devices it supports, and any + information that is available. This allows the parallel backend to tell + CUPS that an EPSON Stylus Color 600 printer is attached to parallel + port 1, for example.

    +

    Printer Drivers

    +

    Printer drivers in CUPS consist of one of more filters specific to a + printer. CUPS includes sample printer drivers for Hewlett-Packard + LaserJet and DeskJet printers and EPSON 9-pin, 24-pin, Stylus Color, + and Stylus Photo printers. While these drivers do not generate optimal + output for the different printer models, they do provide basic printing + and demonstrate how you can write your own printer drivers and + incorporate them into CUPS.

    +

    Networking

    +

    Printers and classes on the local system are automatically shared + with other systems on the network. This allows you to setup one system + to print to a printer and use this system as a printer server or spool + host for all of the others. Users may then select a local printer by + name or a remote printer using "name@server".

    +

    CUPS also provides implicit classes, which are collections of + printers and/or classes with the same name. This allows you to setup + multiple servers pointing to the same physical network printer, for + example, so that you aren't relying on a single system for printing. + Because this also works with printer classes, you can setup multiple + servers and printers and never worry about a single point of failure + unless all of the printers and servers go down!

    +

    2 - Using the Printing System +

    +

    This chapter shows you how to submit, query, and cancel print jobs to + different printers.

    +

    Submitting Files for Printing

    +

    CUPS provides both the System V (lp(1)) and Berkeley ( +lpr(1)) printing commands. Type the following command to print a + file to the default (or only) printer on the system:

    +
      +
      +lp filename ENTER
      +
      +
    +

    or:

    +
      +
      +lpr filename ENTER
      +
      +
    +

    CUPS understands many different types of files directly, including + PostScript and image files. This allows you to print from inside your + applications or at the command-line, whichever is most convenient!

    +

    Choosing a Printer

    +

    Many systems will have more than one printer available to the user. + These printers can be attached to the local system via a parallel, + serial, or USB port, or available over the network.

    +

    Use the lpstat(1) command to see a list of available + printers:

    +
      +
      +lpstat -p -d ENTER
      +
      +
    +

    The -p option specifies that you want to see a list of + printers, and the -d option reports the current default + printer or class.

    +

    Use the -d option with the lp command to + print to a specific printer:

    +
      +
      +lp -d printer filename ENTER
      +
      +
    +

    or the -P option with the lpr command:

    +
      +
      +lpr -P printer filename ENTER
      +
      +
    +

    Setting Printer Options

    +

    For many types of files, the default printer options may be + sufficient for your needs. However, there may be times when you need to + change the options for a particular file you are printing.

    +

    The lp and lpr commands allow you to pass + printer options using the -o option:

    +
      +
      +lp -o landscape -o scaling=75 -o media=A4 filename.jpg
      +lpr -o landscape -o scaling=75 -o media=A4 filename.jpg
      +
      +
    +

    The available printer options vary depending on the printer. The + standard options are described in Chapter + 3, "Standard Printing Options".

    +

    Printing Multiple Copies

    +

    Both the lp and lpr commands have options + for printing more than one copy of a file:

    +
      +
      +lp -n num-copies filename ENTER
      +lpr -#num-copies filename ENTER
      +
      +
    +

    Copies are normally not collated for you. Use the -o + Collate=True option to get collated copies :

    +
      +
      +lp -n num-copies -o Collate=True filename ENTER
      +lpr -#num-copies -o Collate=True filename ENTER
      +
      +
    + + +

    Checking the Printer Status from the Command-Line

    +

    The lpstat command can be used to check for jobs that + you have submitted for printing:

    +
      +
      +lpstat ENTER
      +Printer-1 johndoe 4427776
      +Printer-2 johndoe 15786
      +Printer-3 johndoe 372842
      +
      +
    +

    The jobs are listed in the order they will be printed. Use the +-p option to see which files and printers are active:

    +
      +
      +lpstat -p ENTER
      +printer DeskJet now printing DeskJet-1.
      +
      +
    + + +

    Use the -o and -p options together to show + the jobs and the printers:

    +
      +
      +lpstat -o -p ENTER
      +Printer-1 johndoe 4427776
      +Printer-2 johndoe 15786
      +Printer-3 johndoe 372842
      +printer DeskJet now printing DeskJet-1.
      +
      +
    +

    Checking the Printer Status from the Web

    +

    Since CUPS uses the Internet Printing Protocol, it is also a + fully-functional web server. To use your web browser to monitor the + printers on your system, open the URL:

    + +

    From there you can view the status of classes, jobs, and printers + with the click of a button!

    +

    Canceling a Print Job

    +

    The cancel(1) and lprm(1) commands cancel a + print job:

    +
      +
      +cancel job-id ENTER
      +lprm job-id ENTER
      +
      +
    +

    The job-id is the number that was reported to you by the + lp or lpstat commands.

    +

    3 - Standard Printer + Options

    +

    This chapter describes the standard printer options that are + available when printing with the lp and lpr + commands.

    +

    General Options

    +

    The following options apply when printing all types of files. + +

    +

    Selecting the Media Size, Type, and Source

    +

    The -o media=xyz option sets the media size, type, + and/or source:

    +
      +
      +lp -o media=Letter filename ENTER
      +lp -o media=Letter,MultiPurpose filename ENTER
      +lpr -o media=Letter,Transparency filename ENTER
      +lpr -o media=Letter,MultiPurpose,Transparency filename ENTER
      +
      +
    + + +

    The available media sizes, types, and sources depend on the printer, + but most support the following options (case is not significant):

    +
      +
    • Letter - US Letter (8.5x11 inches, or 216x279mm)
    • +
    • Legal - US Legal (8.5x14 inches, or 216x356mm)
    • +
    • A4 - ISO A4 (8.27x11.69 inches, or 210x297mm)
    • +
    • COM10 - US #10 Envelope (9.5x4.125 inches, or + 241x105mm)
    • +
    • DL - ISO DL Envelope (8.66x4.33 inches, or 220x110mm)
    • +
    • Transparency - Transparency media type or source
    • +
    • Upper - Upper paper tray
    • +
    • Lower - Lower paper tray
    • +
    • MultiPurpose - Multi-purpose paper tray
    • +
    • LargeCapacity - Large capacity paper tray
    • +
    +

    The actual options supported are defined in the printer's PPD file in + the PageSize, InputSlot, and MediaType + options.

    +

    Setting the Orientation

    +

    The -o landscape option will rotate the page 90 degrees + to print in landscape orientation:

    +
      +
      +lp -o landscape filename ENTER
      +lpr -o landscape filename ENTER
      +
      +
    +

    Printing On Both Sides of the Paper

    +

    The -o sides=two-sided-short-edge and -o + sides=two-sided-long-edge options will enable duplexing on the + printer, if the printer supports it. The -o + sides=two-sided-short-edge option is suitable for landscape + pages, while the -o sides=two-sided-long-edge option is + suitable for portrait pages:

    +
      +
      +lp -o sides=two-sided-short-edge filename ENTER
      +lp -o sides=two-sided-long-edge filename ENTER
      +lpr -o sides=two-sided-long-edge filename ENTER
      +
      +
    +

    The default is to print single-sided:

    +
      +
      +lp -o sides=one-sided filename ENTER
      +lpr -o sides=one-sided filename ENTER
      +
      +
    +

    Banner Options

    +

    The following options apply when printing all types of files.

    +

    Selecting the Banner Page(s)

    +

    The -o jobsheets=start,end option sets the banner + page(s) to use for a job:

    +
      +
      +lp -o job-sheets=none filename ENTER
      +lp -o job-sheets=standard filename ENTER
      +lpr -o job-sheets=classified,classified filename ENTER
      +
      +
    +

    If only one banner file is specified, it will be printed before the + files in the job. If a second banner file is specified, it is printed + after the files in the job.

    +

    The available banner pages depend on the local system configuration; + CUPS includes the following banner files:

    +
      +
    • none - Do not produce a banner page.
    • +
    • classified - A banner page with a "classified" label at + the top and bottom.
    • +
    • confidential - A banner page with a "confidential" + label at the top and bottom.
    • +
    • secret - A banner page with a "secret" label at the top + and bottom.
    • +
    • standard - A banner page with no label at the top and + bottom.
    • +
    • topsecret - A banner page with a "top secret" label at + the top and bottom.
    • +
    • unclassified - A banner page with an "unclassified" + label at the top and bottom.
    • +
    +

    Document Options

    +

    The following options apply when printing all types of files.

    +

    Selecting a Range of Pages

    +

    The -o page-ranges=pages option selects a range of pages + for printing:

    +
      +
      +lp -o page-ranges=1 filename ENTER
      +lp -o page-ranges=1-4 filename ENTER
      +lp -o page-ranges=1-4,7,9-12 filename ENTER
      +lpr -o page-ranges=1-4,7,9-12 filename ENTER
      +
      +
    +

    As shown above, the pages value can be a single page, a + range of pages, or a collection of page numbers and ranges separated by + commas. The pages will always be printed in ascending order, regardless + of the order of the pages in the page-ranges option.

    +

    The default is to print all pages.

    +

    Selecting Even or Odd Pages

    +

    Use the -o page-set=set option to select the even or odd + pages:

    +
      +
      +lp -o page-set=odd filename ENTER
      +lp -o page-set=even filename ENTER
      +lpr -o page-set=even filename ENTER
      +
      +
    +

    The default is to print all pages.

    +

    N-Up Printing

    +

    The -o number-up=value option selects N-Up printing. + N-Up printing places multiple document pages on a single printed page. + CUPS supports 1, 2, 4, 6, 9, and 16-Up formats; the default format is + 1-Up:

    +
      +
      +lp -o number-up=1 filename ENTER
      +lp -o number-up=2 filename ENTER
      +lp -o number-up=4 filename ENTER
      +lpr -o number-up=16 filename ENTER
      +
      +
    +

    The -o page-border=value option chooses the border to + draw around each page:

    +
      +
    • -o page-border=double; draw two hairline borders around + each page
    • +
    • -o page-border=double-thick; draw two 1pt borders + around each page
    • +
    • -o page-border=none; do not draw a border (default)
    • +
    • -o page-border=single; draw one hairline border around + each page
    • +
    • -o page-border=single-thick; draw one 1pt border around + each page
    • +
    +

    The -o number-up-layout=value option chooses the layout + of the pages on each output page:

    +
      +
    • -o number-up-layout=btlr; Bottom to top, left to right
    • +
    • -o number-up-layout=btrl; Bottom to top, right to left
    • +
    • -o number-up-layout=lrbt; Left to right, bottom to top
    • +
    • -o number-up-layout=lrtb; Left to right, top to bottom + (default)
    • +
    • -o number-up-layout=rlbt; Right to left, bottom to top
    • +
    • -o number-up-layout=rltb; Right to left, top to bottom
    • +
    • -o number-up-layout=tblr; Top to bottom, left to right
    • +
    • -o number-up-layout=tbrl; Top to bottom, right to left
    • +
    +

    Setting the Brightness

    +

    You can control the overall brightness of the printed output using + the -o brightness=percent option:

    +
      +
      +lp -o brightness=120 filename ENTER
      +lpr -o brightness=120 filename ENTER
      +
      +
    +

    Values greater than 100 will lighten the print, while values less + than 100 will darken it.

    +

    Setting the Gamma Correction

    +

    You can control the overall gamma correction of the printed output + using the -o gamma=value option:

    +
      +
      +lp -o gamma=1700 filename ENTER
      +lpr -o gamma=1700 filename ENTER
      +
      +
    +

    Values greater than 1000 will lighten the print, while values less + than 1000 will darken it. The default gamma is 1000.

    +

    Text Options

    +

    The following options apply when printing text files.

    +

    Setting the Number of Characters Per Inch

    +

    The -o cpi=value option sets the number of characters + per inch:

    +
      +
      +lp -o cpi=10 filename ENTER
      +lp -o cpi=12 filename ENTER
      +lpr -o cpi=17 filename ENTER
      +
      +
    +

    The default characters per inch is 10.

    +

    Setting the Number of Lines Per Inch

    +

    The -o lpi=value option sets the number of lines per + inch:

    +
      +
      +lp -o lpi=6 filename ENTER
      +lpr -o lpi=8 filename ENTER
      +
      +
    +

    The default lines per inch is 6.

    +

    Setting the Number of Columns

    +

    The -o columns=value option sets the number of text + columns:

    +
      +
      +lp -o columns=2 filename ENTER
      +lpr -o columns=3 filename ENTER
      +
      +
    +

    The default number of columns is 1.

    +

    Setting the Page Margins

    +

    Normally the page margins are set to the hard limits of the printer. + Use the -o page-left=value, -o page-right=value +, -o page-top=value, and -o page-bottom=value + options to adjust the page margins:

    +
      +
      +lp -o page-left=value filename ENTER
      +lp -o page-right=value filename ENTER
      +lp -o page-top=value filename ENTER
      +lp -o page-bottom=value filename ENTER
      +lpr -o page-bottom=value filename ENTER
      +
      +
    +

    The value argument is the margin in points; each point + is 1/72 inch or 0.35mm.

    +

    Pretty Printing

    +

    The -o prettyprint option puts a header at the top of + each page with the page number, job title (usually the filename), and + the date. Also, C and C++ keywords are highlighted, and comment lines + are italicized:

    +
      +
      +lp -o prettyprint filename ENTER
      +lpr -o prettyprint filename ENTER
      +
      +
    +

    Image Options

    +

    The following options apply when printing image files.

    +

    Positioning the Image

    +

    The -o position=name option specifies the position of + the image on the page:

    +
      +
    • center - Center the image on the page (default)
    • +
    • top - Print the image centered at the top of the page
    • +
    • left - Print the image centered on the left of page
    • +
    • right - Print the image centered on the right of the + page
    • +
    • top-left - Print the image at the top left corner of + the page
    • +
    • top-right - Print the image at the top right corner of + the page
    • +
    • bottom - Print the image centered at the bottom of the + page
    • +
    • bottom-left - Print the image at the bottom left corner + of the page
    • +
    • bottom-right - Print the image at the bottom right + corner of the page
    • +
    +

    Scaling the Image

    +

    The -o scaling=percent, -o ppi=value, and +-o natural-scaling=percent options change the size of a printed + image:

    +
      +
      +lp -o scaling=percent filename ENTER
      +lp -o ppi=value filename ENTER
      +lpr -o natural-scaling=percent filename ENTER
      +
      +
    +

    The scaling=percent value is a number from 1 to 800 + specifying the size in relation to the page (not the image.) A + scaling of 100 percent will fill the page as completely as the image + aspect ratio allows. A scaling of 200 percent will print on up to 4 + pages.

    +

    The ppi=value value is a number from 1 to 1200 + specifying the resolution of the image in pixels per inch. An image + that is 3000x2400 pixels will print 10x8 inches at 300 pixels per inch, + for example. If the specified resolution makes the image larger than + the page, multiple pages will be printed to satisfy the request.

    +

    The natural-scaling=percent value is a number from 1 to + 800 specifying the size in relation to the natural image size. A + scaling of 100 percent will print the image at its natural size, while + a scaling of 50 percent will print the image at half its natural size. + If the specified scaling makes the image larger than the page, multiple + pages will be printed to satisfy the request.

    +

    Adjusting the Hue (Tint) of an Image

    +

    The -o hue=value option will adjust the hue of the + printed image, much like the tint control on your television:

    +
      +
      +lp -o hue=value filename ENTER
      +lpr -o hue=value filename ENTER
      +
      +
    + + +

    The value argument is a number from -360 to 360 and + represents the color hue rotation. The following table summarizes the + change you'll see with different colors: +

    + + + + + + + + +
    Originalhue=-45hue=45
    RedPurpleYellow-orange
    GreenYellow-greenBlue-green
    YellowOrangeGreen-yellow
    BlueSky-bluePurple
    MagentaIndigoCrimson
    CyanBlue-greenLight-navy-blue
    +
    +

    +

    The default hue adjustment is 0.

    +

    Adjusting the Saturation (Color) of an Image

    +

    The -o saturation=percent option adjusts the saturation + of the colors in an image, much like the color knob on your television:

    +
      +
      +lp -o saturation=percent filename ENTER
      +lpr -o saturation=percent filename ENTER
      +
      +
    +

    The percent argument specifies the color saturation from + 0 to 200. A color saturation of 0 produces a black-and-white print, + while a value of 200 will make the colors extremely intense.

    +

    The default saturation is 100. + +

    +

    HP-GL/2 Options

    +

    The following options apply to HP-GL/2 files.

    +

    Printing in Black

    +

    The -o blackplot option specifies that all pens should + plot in black:

    +
      +
      +lp -o blackplot filename ENTER
      +lpr -o blackplot filename ENTER
      +
      +
    +

    The default is to use the colors defined in the plot file or the + standard pen colors defined in the HP-GL/2 reference manual from + Hewlett Packard.

    +

    Fitting the Plot on the Page

    +

    The -o fitplot option specifies that the plot should be + scaled to fit on the page:

    +
      +
      +lp -o fitplot filename ENTER
      +lpr -o fitplot filename ENTER
      +
      +
    +

    The default is to use the absolute distances specified in the plot + file. +

    + + +
    NOTE: +

    This feature depends upon an accurate plot size (PS) + command in the HP-GL/2 file. If no plot size is given in the file than + the HP-GL/2 filter assumes the plot is ANSI E size.

    +
    +
    +

    +

    Setting the Default Pen Width

    +

    The -o penwidth=value option specifies the default pen + width for HP-GL/2 files:

    +
      +
      +lp -o penwidth=value filename ENTER
      +lpr -o penwidth=value filename ENTER
      +
      +
    +

    The pen width value specifies the pen width in + micrometers. The default value of 1000 produces lines that are 1 + millimeter in width. Specifying a pen width of 0 produces lines that + are exactly 1 pixel wide. +

    + + +
    NOTE: +

    This option is ignored when the pen widths are set in the plot file.

    +
    +
    +

    +

    Raw or Unfiltered Output

    +

    The -o raw option allows you to send files directly to a + printer without filtering. This is sometimes required when printing + from applications that provide their own "printer drivers" for your + printer:

    +
      +
      +lp -o raw filename ENTER
      +lpr -o raw filename ENTER
      +
      +
    +

    The -l option can also be used with the lpr + command to send files directly to a printer:

    +
      +
      +lpr -l filename ENTER
      +
      +
    +

    4 - Saving Printer Options + and Defaults

    +

    This chapter describes how to save printer options for your printer + and set your own default printer.

    +

    Printer Options

    +

    Each printer supports a large number of options, which you learned + about in Chapter 3, "Standard Printer + Options". Rather than specifying these options each time you print + a file, CUPS allows you to save them as "default" options for the + printer.

    +

    The lpoptions(1) command saves the options for your + printers. Like the lp and lpr commands, it + accepts printer options using the -o argument:

    +
      +
      +lpoptions -o prettyprint ENTER
      +lpoptions -o media=A4 -o sides=two-sided-long-edge ENTER
      +lpoptions -o media=Legal -o scaling=100 ENTER
      +
      +
    +

    Once saved, any lp or lpr command will use + them when you print.

    +

    Setting Options for a Specific Printer

    +

    The previous example shows how to set the options for the default + printer. The -p printer option specifies the options are + for another printer:

    +
      +
      +lpoptions -p laserjet -o prettyprint ENTER
      +lpoptions -p laserjet -o media=A4 -o sides=two-sided-long-edge ENTER
      +lpoptions -p deskjet -o media=Legal -o scaling=100 ENTER
      +
      +
    +

    Removing Options

    +

    The previous two examples shows how to set options for the default + and a specific printer. Below, shows you how to remove the saved option + using the -r argument:

    +
      +
      +lpoptions -r prettyprint ENTER
      +lpoptions -p laserjet -r prettyprint ENTER
      +
      +
    +

    Viewing the Current Defaults

    +

    The lpoptions command can also be used to show the + current options by not specifying any new options on the command-line:

    +
      +
      +lpoptions ENTER
      +media=A4 sides=two-sided-long-edge
      +lpoptions -p deskjet ENTER
      +media=Legal scaling=100
      +
      +
    +

    Viewing Options for a Specific Printer

    +

    You can display the supported options using the lpoptions + command with the -l option, as follows:

    +
      +
      +lpoptions -p laserjet -l ENTER
      +
      +
    +

    Setting the Default Printer

    +

    The administrator normally will set a system-wide default printer + that is normally used as the default printer by everyone. Use the +-d printer option to set your own default printer:

    +
      +
      +lpoptions -d deskjet ENTER
      +
      +
    +

    The printer can be local (deskjet) or remote ( +deskjet@server).

    +

    Printer Instances

    +

    Besides setting options for each print queue, CUPS supports + printer instances which allow you to define several different sets + of options for each printer. You specify a printer instance using the + slash (/) character:

    +
      +
      +lpoptions -p laserjet/duplex -o sides=two-sided-long-edge ENTER
      +lpoptions -p laserjet/legal -o media=Legal ENTER
      +
      +
    +

    The lp and lpr commands also understand + this notation:

    +
      +
      +lp -d laserjet/duplex filename ENTER
      +lpr -P laserjet/legal filename ENTER
      +
      +
    +

    Removing Instances

    +

    Use the -x printer/instance option to remove a printer + instance that you no longer need:

    +
      +
      +lpoptions -x laserjet ENTER
      +lpoptions -x laserjet/duplex ENTER
      +lpoptions -x laserjet/legal ENTER
      +
      +
    +

    The -x option only removes the default options for that + printer and instance; the original print queue will remain until + deleted with the lpadmin(8) command by the administrator.

    +

    A - Software License Agreement

    +

    Common UNIX Printing System License + Agreement

    +

    Copyright 1997-2003 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, with exceptions for + Apple operating systems and the OpenSSL toolkit. A copy of the + exceptions and 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 "cups" include + directory and library files in the binary distributions. The GNU GPL + applies to the remainder of the CUPS distribution, including the + "pdftops" filter which is based upon Xpdf and the CUPS imaging library.

    +

    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 only exceptions to this are the portions of + the CUPS software covered by the Apple operating system license + exceptions outlined later in this license agreement.

    +

    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.

    +

    License Exceptions

    +

    In addition, as the copyright holder of CUPS, Easy Software Products + grants the following special exceptions:

    +
      +
    1. Apple Operating System Development License Exception; +
        +
      1. Software that is developed by any person or entity for an Apple + Operating System ("Apple OS-Developed Software"), including but not + limited to Apple and third party printer drivers, filters, and backends + for an Apple Operating System, that is linked to the CUPS imaging + library or based on any sample filters or backends provided with CUPS + shall not be considered to be a derivative work or collective work + based on the CUPS program and is exempt from the mandatory source code + release clauses of the GNU GPL. You may therefore distribute linked + combinations of the CUPS imaging library with Apple OS-Developed + Software without releasing the source code of the Apple OS-Developed + Software. You may also use sample filters and backends provided with + CUPS to develop Apple OS-Developed Software without releasing the + source code of the Apple OS-Developed Software.
      2. +
      3. An Apple Operating System means any operating system software + developed and/or marketed by Apple Computer, Inc., including but not + limited to all existing releases and versions of Apple's Darwin, Mac OS + X, and Mac OS X Server products and all follow-on releases and future + versions thereof.
      4. +
      5. This exception is only available for Apple OS-Developed Software and + does not apply to software that is distributed for use on other + operating systems.
      6. +
      7. All CUPS software that falls under this license exception have the + following text at the top of each source file:
        This file is + subject to the Apple OS-Developed Software exception.
      8. +
      +
    2. +
    3. OpenSSL Toolkit License Exception; +
        +
      1. Easy Software Products explicitly allows the compilation and + distribution of the CUPS software with the OpenSSL Toolkit.
      2. +
      +
    4. +
    +

    No developer is required to provide these exceptions in a derived + work.

    +

    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. Please contract Easy + Software Products for written permission to use them in derivative + products. 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 "pdftops" filter that is + based on the Xpdf 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:

    + + + +

    GNU GENERAL PUBLIC LICENSE

    +

    Version 2, June 1991

    +
    +Copyright 1989, 1991 Free Software Foundation, Inc.
    +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
    +
    +Everyone is permitted to copy and distribute verbatim
    +copies of this license document, but changing it is not allowed.
    +
    +

    Preamble

    +

    The licenses for most software are designed to take away your freedom + to share and change it. By contrast, the GNU General Public License is + intended to guarantee your freedom to share and change free + software--to make sure the software is free for all its users. This + General Public License applies to most of the Free Software + Foundation's software and to any other program whose authors commit to + using it. (Some other Free Software Foundation software is covered by + the GNU Library General Public License instead.) You can apply it to + your programs, too.

    +

    When we speak of free software, we are referring to freedom, not + price. Our General Public Licenses are designed to make sure that you + have the freedom to distribute copies of free software (and charge for + this service if you wish), that you receive source code or can get it + if you want it, that you can change the software or use pieces of it in + new free programs; and that you know you can do these things.

    +

    To protect your rights, we need to make restrictions that forbid + anyone to deny you these rights or to ask you to surrender the rights. + These restrictions translate to certain responsibilities for you if you + distribute copies of the software, or if you modify it.

    +

    For example, if you distribute copies of such a program, whether + gratis or for a fee, you must give the recipients all the rights that + you have. You must make sure that they, too, receive or can get the + source code. And you must show them these terms so they know their + rights.

    +

    We protect your rights with two steps: (1) copyright the software, + and (2) offer you this license which gives you legal permission to + copy, distribute and/or modify the software.

    +

    Also, for each author's protection and ours, we want to make certain + that everyone understands that there is no warranty for this free + software. If the software is modified by someone else and passed on, we + want its recipients to know that what they have is not the original, so + that any problems introduced by others will not reflect on the original + authors' reputations.

    +

    Finally, any free program is threatened constantly by software + patents. We wish to avoid the danger that redistributors of a free + program will individually obtain patent licenses, in effect making the + program proprietary. To prevent this, we have made it clear that any + patent must be licensed for everyone's free use or not licensed at all.

    +

    The precise terms and conditions for copying, distribution and + modification follow.

    +

    GNU GENERAL PUBLIC LICENSE +
    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

    +
      +
    1. This License applies to any program or other work which contains a + notice placed by the copyright holder saying it may be distributed + under the terms of this General Public License. The "Program", below, + refers to any such program or work, and a "work based on the Program" + means either the Program or any derivative work under copyright law: + that is to say, a work containing the Program or a portion of it, + either verbatim or with modifications and/or translated into another + language. (Hereinafter, translation is included without limitation in + the term "modification".) Each licensee is addressed as "you". +

      Activities other than copying, distribution and modification are not + covered by this License; they are outside its scope. The act of running + the Program is not restricted, and the output from the Program is + covered only if its contents constitute a work based on the Program + (independent of having been made by running the Program). Whether that + is true depends on what the Program does.

      +
    2. You may copy and distribute verbatim copies of the Program's source + code as you receive it, in any medium, provided that you conspicuously + and appropriately publish on each copy an appropriate copyright notice + and disclaimer of warranty; keep intact all the notices that refer to + this License and to the absence of any warranty; and give any other + recipients of the Program a copy of this License along with the + Program. +

      You may charge a fee for the physical act of transferring a copy, and + you may at your option offer warranty protection in exchange for a fee.

      +
    3. You may modify your copy or copies of the Program or any portion of + it, thus forming a work based on the Program, and copy and distribute + such modifications or work under the terms of Section 1 above, provided + that you also meet all of these conditions: +
        +
      1. You must cause the modified files to carry prominent notices stating + that you changed the files and the date of any change.
      2. +
      3. 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.
      4. +
      5. 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.)
      6. +
      +

      These requirements apply to the modified work as a whole. If + identifiable sections of that work are not derived from the Program, + and can be reasonably considered independent and separate works in + themselves, then this License, and its terms, do not apply to those + sections when you distribute them as separate works. But when you + distribute the same sections as part of a whole which is a work based + on the Program, the distribution of the whole must be on the terms of + this License, whose permissions for other licensees extend to the + entire whole, and thus to each and every part regardless of who wrote + it.

      +

      Thus, it is not the intent of this section to claim rights or contest + your rights to work written entirely by you; rather, the intent is to + exercise the right to control the distribution of derivative or + collective works based on the Program.

      +

      In addition, mere aggregation of another work not based on the + Program with the Program (or with a work based on the Program) on a + volume of a storage or distribution medium does not bring the other + work under the scope of this License.

      +
    4. You may copy and distribute the Program (or a work based on it, + under Section 2) in object code or executable form under the terms of + Sections 1 and 2 above provided that you also do one of the following: +
        +
      1. Accompany it with the complete corresponding machine-readable source + code, which must be distributed under the terms of Sections 1 and 2 + above on a medium customarily used for software interchange; or,
      2. +
      3. 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,
      4. +
      5. 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.)
      6. +
      +

      The source code for a work means the preferred form of the work for + making modifications to it. For an executable work, complete source + code means all the source code for all modules it contains, plus any + associated interface definition files, plus the scripts used to control + compilation and installation of the executable. However, as a special + exception, the source code distributed need not include anything that + is normally distributed (in either source or binary form) with the + major components (compiler, kernel, and so on) of the operating system + on which the executable runs, unless that component itself accompanies + the executable.

      +

      If distribution of executable or object code is made by offering + access to copy from a designated place, then offering equivalent access + to copy the source code from the same place counts as distribution of + the source code, even though third parties are not compelled to copy + the source along with the object code.

      +
    5. You may not copy, modify, sublicense, or distribute the Program + except as expressly provided under this License. Any attempt otherwise + to copy, modify, sublicense or distribute the Program is void, and will + automatically terminate your rights under this License. However, + parties who have received copies, or rights, from you under this + License will not have their licenses terminated so long as such parties + remain in full compliance.
    6. +
    7. 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.
    8. +
    9. 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.
    10. +
    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 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.

      +
    12. 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.
    13. +
    14. 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.

      +
    15. 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.
    16. + + + + + + +
    +

    NO WARRANTY

    +
      +
    1. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY + FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN + OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES + PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER + EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH + YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL + NECESSARY SERVICING, REPAIR OR CORRECTION.
    2. +
    3. 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.
    4. +
    +

    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.

    +

    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:

    +
      +
    1. The modified work must itself be a software library. +

      +
    2. You must cause the files modified to carry prominent notices stating + that you changed the files and the date of any change. +

      +
    3. You must cause the whole of the work to be licensed at no charge to + all third parties under the terms of this License. +

      +
    4. 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.)

      +
    5. + + + +
    +

    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:

    +
      +
    1. 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.) +

      +
    2. 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. +

      +
    3. 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. +

      +
    4. Verify that the user has already received a copy of these materials + or that you have already sent this user a copy.
    5. + + + +
    +

    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:

    +
      +
    1. 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. +

      +
    2. 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.
    3. + +
    +

    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/doc/sum.pdf b/doc/sum.pdf new file mode 100644 index 0000000000000000000000000000000000000000..629621b6442371b5259485d27f742d4094ba2d86 GIT binary patch literal 106950 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

    kBq7XD|n( zY2QI_rm~xyOhfPT0-$3*+V;SIWyyiB-tBFVLfh+xkKU7n3xzY=TaP*r$b~t??$dnH z+GLNInln<&gJ?q@VxFkehcB(A|1=2glTu`WvY62bp+;beWCZUgI5Yr=mtW8;2ff-uxvz z`D9~9jVyg6`nxM9PCIf@xggrLI2h2RaNLc$Z;@fpNCo-M*_Gw7GC#>CQNr*dF`EuH zbc{|EB`1UkoY6v9OV7BoNHoXw1*)bD@(Lg&2+q1X52anIkzM6jkaG5! zeFn^v2x50^iWNCfR@DwlEf=`or~uEMaeUa%Vi9n5oX;J$DiKO{a#aW=sUH|?NOi*)a-0r9;3E^0ZRh%*KQH5>72RF6SC zSb*szPo7LqA)v{XY*`h$nG+g)MxFG8vb4|(j*WRbB%wVX&l3IFBtJEYkkWuP^@5Xu z4x-dNa{pP|+pF&5I7UUqWY&w5M)uh>lB=f<=tBj$GZ1oAq8ybht=-|+mxbC`C_FOq zoCx)lVba9fol#Gu#B!Nb_(RhZWk64T<{a$`Ia3aCi($s0^4=-k85x%}N1RhY0M~F8 zyE@L1EF7E5M`hFELv0u?!CIJE;pWYh3fq(Rrt~mM>Ya9|`)83D`EE0B6ZKv%P|roO z3yY!oyWmnSijf#Z7Nx9AXE8asyB;IO&U}=lgblqrJW~L1yS2LqIiV@^sk(c zV`kZhE7XmFT+g6^UN#>XkvLoCGE};HM`1 zSZn<+NheqM=S}xpqg!}{6Nr*Oh|AyNP|R%qRTTLzsmx#MRbu_a9CeM_{{qPG>X-8w zLm<(>962~z@?47HO94EBYHq35#*CZ^lAE&TEE>IWzAliFWsYv7ucgwp11md*qB zqz1LfYOll$`^|u!3~V8XwqSz^PN>1jEOq(PNCH%jdX0gDSKF7*YA5? zJR2;7z->RRK40$JshXfglRd+fxJ;nob~U;Y-q*U4T>9@nG=-@GQNVzzPlhlkDo&Zy z$lV7*1mGe#wDh8s?luC#LN5ZQjS9kpvdb(l`gN>{Xc9c_B=rxi8phz@ekf6CUIElI zt%G_dON|@m1!EZok;>Z?nGb45Hb3GLm7;Q*HrS!R=%?Hw74+&m(gVV3mqkk$=Q8Py zK0peslts3$##uS8SHkl=wd|D;MJ1v}!_*@RkhcDjQ=2}*C!GuH#57B?x#1w#Yjsb%y~*; zk&B^211HHzdo@CcHk%$)@p1cS%=7~k zE`RuCKnc_AaUxc$4Rdv6JvlwIUM8KilaP2ZQD(PNLQFovGu~VX4sAN!80?kXs*Bd0 zMsXl^zjkmpj!g5b-Lc~*o3t6TuJF`3o~Asre+1qx9$fRvcG3fLP;^a@FnQr9E?6%7 z-O=vJauT({ge7y0>v~mnDNk4mDT#9PW*8gAJdb`2HBA;!Xz=eR092=8gCb z|5Us*%pZj2Z}C@Vj{ow4{$ElYj=wZ@#QrD6>9_r#yEf{RGoS=2%~%@xIbqiXL$9^M z?ebO~jEu-NrDQ23*@e0r7|Qj?OBOk!HGe|O*OO_lqv+mQ!|+>V;lzd3ax=fvrq&w= z($KEr5*BU2o&bvILWq0A+F=`$-6MTQ%XRT-LVtNJ3h0&t0!!D)g1rgHY4$ma)?Y1x z${k^7#5^MN!XQ-)#8hvlzTFb)d%JKfTayHG1E8R5rLZLQaRmJzz_tJz0HQ^xt7S$G z#c0G>dZEhqZ5GuwztAxjn(p4^#`jH1AK&D!rDu;#RvwM@4rj15HB)lE1Aa<#zkd;!(zbS)*ff-WUIKi{t(}cbmLFIeAS~-&H}!R zT$f|U{NO`osX>il`iXOeLQhqyAVoDBo|heLG?zH%zL7oU=aG-GqDN>=-EWAQTehTi z(iozcz{i3qbQ)J~jd-E}HI7=vspC6E|BX*E%q_6+1Bz|oNP_|v{PE2xk((2^ObAO% z@;>-!wrxKW&_Kavd70haSUM(*V?+!Xlg(=JUMLxUaNcPL0yI-vj7@3HzHi_2dVUd5 zm(}Zy!Tq3%nZ3&w7(K|x*f+Y}Yr>wqm<08R4wcz`@Ryq7ws$)x#!FLvbT60O&-fe*DK_lCO0lhTBo#a26l9u|}y)E6Br zqG)+hRJq7@1)uVodTN6a5c2C!LrK=(IYmf^XM9c+TMF>fu7bcHn8`6lt~s_!y~GfR)(0%xh+76yh3=Jv3t6o%VP!6W#8ti?z<01@C=3$ za?V)H{D_3|I_t8YgJ-iZUH!5ltU_J)31;?c2k87o#05_0NuHd_QIn4G9($@bac0vw zroW`5M;GZgV0)sbS7+AxgZ#KHnK=Uu2JseeG|f%a+($*&MU*_um0%v$$P>YmPE=WUOtAx z)#9rB_I`5)RhPB6Nk6$Awzt{iFXbY$utF%aY9-bXwStOc){tAlke8TzP zx72Ln086nmDcfj{C|6TX_Ju9POgLjr*XJ4toQs)o#h5y083_CmGpVFaFym&inqaym zbRlNS5o4}4!}#AXv~Bv2E5!^;X#^tS#Q)oi&dk%XqucF(?{(Bm-a(T_rqxT%U2?!# zyGBh13|39UcO9m4N9EC6wDDbhqV@gqNqZ;+od*aioNVn1{YmFk|1lQO0`eAx3Mp1& zxwE$nrUkN_qNzDpaHx<*YbC0=Mi5kLlA7{TxF$T=k`a08fBd_xg>Ag>{62g60N+*s zu6oVMouYHM5e92!U+*Wlgh=MSR-=+)<}T~ST)nH$ELy@upSCc5_;Mz z2{)o;;OW>+4QlW`2D|^wTbYrM=fZ$vS^;jI_Xlxf4n^`y&%KD=fShBuLT7Df$AZOh z0B&0@-)GchbxmXHn?%vE;k3|)F;2cuIVb&y`-s!-W@veuMtxF9;L?uKR2FdzVJ4Iv zFAgt7m-Hf$@XyUoa4V~sFn4lNieh@}I8bAwdU;Wz=VOdtm1rKya;6?neR$`twbKZf zO>6jCRX_OUf6~$q>^rCrrY1~h-X^uEjr;~@9_30PT-aQVmfz)7!XrkGqrXz+wW<hoi=R#f2D5hCEameR@OTwK1qnD%RCo%MM3PqFiux8D@$s}6G5g*P{t?VQQK za6r#=ebU`j&c$C{37fU!X;Zvf<+--0vpy!sG=R zpzBSU@>bVWd{o`&Xc-*3Y)s35@>6I&pEFrE)&DWM0d>mBbPwYOv*vSYo1D9)4lfmE z_%gHUcab6rPeS$aIU;^N^m3tjL%T-K7!SF(jE7i`rqdJI4M&U4e1lBuZ*kweyOt2v zlfZI$)Q4{KIBq9eixjS{-=N$~s8TpM8ljM_P!;4#gbAl8>mYt&5oLBg z`F+-#$(mu@gousdj$V%ud~~gpB3ph;qSR02Vz0U#k*d6PJvDawEi#*4q4>$WSg|p; zqN-~AgCm1lTvch^9{o)9X>IUJMVGZl^G_!Svr&G4S24%p|1mtU{H-Da3)6q+@bH(0 z;aQmfkd~_cpN;V25sm`DItJIGF#i@Cv(3SXvFErbs6kZ_VuDEa!+#GSF5B6a$ZF_@ynIEeWHGE@_#9!eNcjE~i-zUzpj z%*V{y==Y2({75cufQ)%`t9Tv^@lBsxefFIHP!25~34LSs&=+JXZS;+`XMF1MJo(@l zcRl?1*~bG)Aix4pDWN2i3_0BRR9XBv_3N`p^1bQ_kEKU5Bd_vZfL19g}Lm5$6 z039CLa8=Edm)q<_D7-O{CUyYRMW$IHf-aH=IRA_9SqCKR|?zb*=pH2T-P zE97ProsBpSAQ<#8zJ}?9cyRSFFnx{mZfp?ZbGdwB3woT)wY_~O-T-$)W$^*0^=cQ_ zk|;M=W|nW^R{o{wJnRt4%VfWR%y=>v(yBG|S^&E$w*$t0C8LW`?n5Rb)^J&vV8c}e zgY0A1=C)(VAqs{q^B58u(Qy3IwgFUFSxpQ0hqwc3Ub$2Fp#J(+Y(^ zb?HA3)#zhq6)x|C=Q4E9OHyy6go|vN@{?;x!5}0|Am-~H)m6^)wSHtC&!ZgDX$era z=m+2MM%po^os4D;Bc(PnXm3ujV?_b%YA!RRRiTSSJlvZ48cqxE;w?t_;D)Z{)U97W zI6oRaqTdWV;`~8h{uah(Vfim^K>F7<&41^K%<@-QK0EWDrcYG+9sj4eP`i3NnnnjA z0CqBS{;XJ(E|s+LoD>CIrvMd62*2pPk@~SZBAXR$hA|{%x7*W7{f(n|dnZl^=Pw$c zN}TuldVH(li^=FJN&(^^0z?ro3>fjQ3RpFNhgHPvip8syhQRdgZ(KBL6)jdamX047 zzK`s18vF!}{X03D&hAv;G`>0j%n2zJVVIdI4?NyDwjExQ3$i~5)h}Tg3=c~abH2~V zrnr*jmMUo0aC&p#Eb0jJPAGrrz=Jn`R7k8`IGdz>DgLCZ1tDY3f;cZYRL7>DV(vp! zV4GaQC$QP_N7=>+LOo_P!?t*H4Z>*2t{nj`EX_sa6b&Lir2YOAS`gu~2_jjDIC<9?keu?kP%3`w;RN6jXnflyP64ij{zx{i6C*DT5v+ zjX(Rko}@G&va(pV5N`ux04Y0XE+c21z$#J7MGh+fzomnMxJIg2>Hw*$bHbq(njsYX zF1}h{l#oqx)HSMDFj5;H3Em4+tbFolH+hFv1QC*}9@N?6gV!gS=ysk@_S|TcvIBX1 zWux;6A>>uO{(}Z`TM|Fc;sc7X2DC>@g$F6;Z<6VJ$K29FF}tvw)n9rygk5Db94uKa zC@F7qpcGTIj~hFndI*VC6fF^O_x@!JSq!GDoGq`JG^t){kJeU{OyhO@q0hR~I9XOr zs<}RsT|%nZ^2Te4c0ldO*m@k<$>Mzz#cDjd6wl)t*)dnwJ& zvUme(XrNR&Z>DVMD*3lRW-aszf>(;(i}()e9S4aP4rNO_L;PkrT^TrS7z_pVnOSXLGhExQ_in&&pe zzBq56H@La(9ba9x#Z~Js-Fc4UOJanPh^2XZ(d9oc5@Gsae}csaGIsvqi~n0}orUec z-3-gW`RM-&TIXc?Ljf;EP1kNy48eP~ZcQAMfl}$GF{OXNN(C^AIX1f*5X$Xjh>oO8 z9M8!$h1fS=r?`@-u>BzL3Vd)0*|$x?}Ub zx*|vx2oOI6(Ato)X8AxV75g4)eE!=Dw$?3*aeDE=HT)Lj_;;qp7|ZT<2+Gs#>dF4% z@(H$yzHr;EdiGAyhaSpnmG%t(XK)6W0)TgQ)9R=l0nD2{z|O}?Tq-qR$2u_z7JLO2 z?3xtd7lJ0?y#IRD1i&YdG_HcaO_g>@zmi6vwxSd?k-UIEC4*e6h0OZGR^jtLUP)zb z7LT~9Bf1KAG)AKFhVjZ4bw{um4ui#nfQ37NuZ|l&%eFl4=dMF3!DH zto_#43qWVfhB)Qw#^~`#Q8*ziQ2m4-WMdgW#KB3UvNo>L_2c5HH|M;L;6&x(>I3Cc z;A%v2q?K3i&Fvg$=yB5n0dJd0e7gaY5*4n^Re8UnsLH)h4H^d(lbeaK6{}M9#l46z zKi1|W{L9qPeB5v9Zz?C--XrX&sYztER8ZZa=ft`@ z+EQv=##wnN!EehdYk2qc)nj!8s4ySg_t>!N9bdore1n3pc(#s0H}WO?f)8rQtNZvO zLMT)`o3(3e3UzqpWmh|5>@oFxIg|0 zWogDg;Kgo4z6n9Q`_{}u@1IFbwEe=rjyX&m@3~yNP(P4qp{Lhn#%;|9*2mU)H8u?r z{vCLg@w=A#0fZG;dUboJVh8H_H*L0tzK?%P#gLBiY5&|F@3R30*c4xNrr03GJ^F_) z#+_9`)i1VZNgEqdmd0LlV86&Nl$r8w`*v5v9h>@-!v{|O*cE9%M*Vmtx-LLIYcfB1 zUm$`!M(sa{*5BgvEdPD_q*?xws~;!(pIrT> z$@tWQ!Rh*oBe{pyb-`btCfG5m7jrh&4V^Ln%SfR#9<{!<=z=P9YbHQ;9HugcpW2kt z08|Btq99qQIX16>4PVJ_U#>Owg0%&Gxijs!Z;e1|A<;O*4dJd))ZPvPSSU^++gr$} z#MPYq{_K8}1Z62)%5rzmJxxY-?!3!h(vV^CIPmEz-rz1Dtm8UB;`$3hqt#B^hRt(=Q< zDN@n$zJ}Ch8nyi(_wf&ydPdiBQ<`Y2JKYUcdPX(dlIM9(5LaAR2(OAI4rR1T3N15^W;B?4>xibq*)l%7 zH1OQ3b@S8rcc6MxBUkOBx6&rsZKoZFK0C%LB&0duACHkICUR1}sVoE*XuhM2@Q5Dh3KP|4|GlIdXqmFFQ+ z8tEZXIZ9AUN4O2B9l!&bO#eUr$E<$~eXuh9m$;@gGX6W;bk_f8%8{a?8+X8l;&ZC5 zGrd?1g~z?SUvUn{Eoul3m0_U1krt0(pEXo*n0$ZZb=B8La8*ksg0lIN?RDM0`sUT= ze-I~l=8r9)2TM`V_VBF12a6*n2@{JQ4?tyKA>XxF8H}3i860@n)@CIqe2}en^4RKp zdrJw1CfqShPD^jAKf4>M}{VPB}xZcL9H%#~UY4 zG{|CzM~e6K(ll6eM|r@;o!istmECjX zR&LvZRk;AeJi&e>f-1TTe(>c@_tc&~j1qdwrRtlFKM;?A*)lj{PIzmQf}MyD4YSDk z!x5jU8k!irh9IUL@HRp(A+}d;CjJcFw1;sG?Ko}v7F#d|L$3x((aj}bxfAWf}K*iNuKF=M5-*5p74MjdB zyA8*F-$VYT>2ZGgvJ{OtJNn!W3bViYxjmXT{3~?aC>V6+o1o+U*#M$2L~Ptoq#ye1 zS0MFV`SR z(Ax>ssMtW};Gj9Lz3-DQM!eSg6sW{fO3pDbi|80JfNo>knu?lftK?a1y*f4KIi*xT zNLhjaoKf7P6+C?hY?1Xz#)t_eJO+?Y1a%v-GUw9-8Tk{8yZ8d8fFHE9t>=&=QIw4v z8(|6)Jd5Vl_o0KMBsIErdHc znm3ElJ=9XoQ!Tup#n%lo4!;IO(xk7H2fV9JPj~IR5MFa45JLB3?OMpr_u~5fc0W&8 z{~#rQi*m5C{O6qa^jB*6tbfhxkL^DWs5EPA{1er<1#BHomwK#(pnjw%oa&9`0ug zkLUY4X7p%1&H21DUyuo4ku?ieKNEjDGtOn`U|8oSD2D2Wcqu0XbaSBh;A5tlUFz;# zG*32TwuzIFCK~xJ*&^m^D`I~)PON+rByAhYh-HH%Z5Vj1`cx#8<1&P;KnffiVI-EH zoy&}%g+@f?Ic>6(`ZthIf5`_WogqL_BzmCW_?!P8tPP9JB8AO%;C1YGXl(d`xuSM$ z!5k1VYu_&*DMH#$TXv1mmEsM5l_#w92$ADTfgKnX7{5kvG7@b`IlySwbQ@j!yuPx{ z3v{D6YJCVljtsLyXpCGvV`Z&-a#3UUa7xh`tHICvhx!i?s1TIZiEDf(AQ`DA2<_!S z)wVHlpIJ$Rr_9PgQ3?j98SAP$=2}NdWLyldt8qg?jBb=Di7EwF9;i;mnk&cTetig? z<`JUpUxFw+Jubs_tqKpL8UcdQ76^ez&ec&6z~_YGvM@UN>BV&sL0Wg=YJGZ$XIoak zBT|fEYXxB$q7>=wx+{;-UX^FE;HnvTb&%+C#DH8T11n$X9cmc}Mf7d9CtqZV5%c%4 zZh)c2tz(W=tBui7-jWJOa*z%ec&)q2bwL5Nt^Oh3n=~}pGEK}{66f9>?GNpibnD2d zX!v-C`!B*(v3HcJbmU6`s}P`QCIk3wDzFa08Z@_vHzHCmpI55%LX>KmmxE2U_9e0N z9njBc(D7AVYOcL7a>y6~*9W0qPKei1ki>4RTRClTJl--NS5dpnOm4|K%aV$~10^JL zX)RjS>}YIK9sbg3YXE#qO(CMyCpBuKS=zu>)0P)6sZ@@pSh>(-+^XKKe(dwVl});k zdPqoVx{&C2_f@3bQ&n%ozNPZcr;J+|<e}IphXwN~KgBlBIJW6Tkgc{xx?8pVv39m%Exo4q(~cn_nretbG~l+a5(Xd97`yFn z*p2y7T&d4u2DDS#pG2mf~)S$nXvzz z8o}+uGa+|+1o&WmeLuF3E2o~FuwU4c*IcmF?Ao(m(;==q{K(t7qslV@ zuF6^t&g);rHS2o->@5C@92vd?&d9a%ewlzTBFUMp52M2rW6JG6OCz4TSM?I|3W=t3 zNLQJ~{)+?IJq^zj{z|}kzrfn!J^TwK?YA@i!9eCTwSJ( z-&Q|M+r011npB1c$oWK)$B(9pqM6rj)>ID0tD56b{;l_u^iw;p*;=wDuU7^B*=~~KDr~}$64MXQJa4eHF1?yW@|>hlUIV0HW1Sti>bWPXs1lmEv8(Gl z5W-<^3--%<4Am)js#qQOfTa5_R%xQ@1g>DL5;R1$F6BvQ_cXW<#KC|z1{^r+>$vR} zy&n^|!Pp9utFem3WKq!OJ@Qc5dnV*8?!uUwt&gGhfo3Z8GB5q)Yw9prP-nBom=Qy- z4OJ!|jFM#IE0#Xma$2==isYAnX5^MDYJ9r!wP^PMdSJAG6BtDzr`Sgg7f60R0h8hCP0nj>V zd<^3{bgmHZ24Qn^i=+O}=h#;fY@8_0ILuo54s2ztuH!N=+me(z`@y~WbkF%URNS*{ zL|LlZ$8;Jx{R??%BNlxQwaj0I`KPC+jMd${(Vg4dwxct0u6_o}+tTcALYUzEvzgN) z8sEDoHa=dLXgXPB=@e~1^lNZ&bNu44l~Nl@4lz!gQ|Ipbal&n9R3wz`D;U{RrB~h& zx&82qKZ-{z3Y%nt)OUV>awxGdC(`v%(vRARGe&Qe3eWnmjh#umxsaj5S=_h^)}S%* zgvS?CViVBFf>DV2QvE6(-r6S(sOuW3lg7|Xi~%Z48ZGkkqyFuYcf5`;JW|x1-9je% z$om`C(c|3x58Cjzz#A*ae~mW$8!`AxPJpccQWN;MyiI-6_K@wL`SR4JDWIs;dIWN- zd^??vHC;>&8tA={^v_{2B;CZwi{2YdB}Ze@PHhrE!-#BVr<1ASZyXYqK6#-c#_!VO z{^5_k$?4$4q}S*Z=`QR%*h6EPhiI_79}M{(p07{W5j}dly8O9*MPX%8c8k&jyHDGf zzaKvAbofh2Ak*SP%kIo!q}TWH7c@$!vBVy=btR?9l1Omy=Sc8cPU8-f?kMwmmo91) ztG4!!)=BP9&qpLAnY*2_4M?`nIwpdHmcvU`v6?v7e%xN(8VfmT)0tW_GM_>B7Bl_n5q!Z5ic41-MXOPsjkqFeGgh>=cmi;VNfPqhQGe0yv z*Pt_by7@b-3*D`fQ2MrOO(`qI&e9-w-Itv^#YM^Z?!oN0^lEbC1aiX_Ah@{CNT#`U zFnI@Uzgn>0Nn;^wVngad2<6tK!BE|rDskEZMl6;ZHl#=o(h6AYurqvq9B+$t{;96| zs;(l$D4jB$UXTcv;f2b*_WU(xlrf7IOBDfG?KvKk@e@?91TF7^*!stt(<7LTG1W3P zc8%OYb?4prB5ju@=$cX4If6cCO!=xl%nQ}dd3|90_{3Yh1XN^C>U%vPuR#|=@5Nv6Fc73R zQ-+#p#|KKslFf$cgCpKh(CoqgnX+uTZYJ5HEj7(*fLpt+`!#@3{yPZ??{04UdSlJE zD$1h6n_bvPfeHpWs$wX^jx@9gS3pf0Z6{&(s zQACiMV?-GR$Ka0g6VJd|t*oDtpHveSfg7d^SRajsU`A)uk=vJF@Ze(O4e_^}AG>$s zniyX9rr5fAni29KA24}6BI9@M8dxIM{mMtC7mD)~a=%-vdJWT!)B3wR}vaM z#2LIH{&rYprA&8awJE$LeHR1Jf$e9MJBUO%-xKTgsdW$YqVTXXjP7|oNq&`MUD$wz zcYMTbt-KN?lO6~qZ81a6637qz$EfYE4A260q0goAnA2o7Ugw#Q>(tw<+s?N`-LO>G zn4wt{SUjO!GX^@@q4kQHmg2zJ#d;cAR=W-S>vg<~(OqY*f8=2Jc4p4LZlY-~Zt9C~ zk6*T8>@RVzueYm@*H$9xi|Zc_o_9laAN`x}Rp-->_u2R$;4@g@iFYJ?{i_Xk;{<$o zuXgfj^6*Wq^nCJNJqtDE@h&}{OFJA~xHA8EOf-I6;-Pyy4sm{7s3R}`>*pRnl4jBI zA0po0Li=nC|36^o|9g02`%8?UgX2G*j+de#YlqE=)cvlG;*AL&&z*R6C+?UD!?O;s z-q)$fpwWk3nU&bKxV;p=t@eBOriy6Ya{k@`k;Hy&__w?2Q{`FjEE>yb9_Y62{1a`; z^m^Ix`a8d^c|-njW}NNKjk)H0SNiPfPa67E?ZfjbN|y`PitSpq4P`UQX5g#rZI0!5 z7vs(v*PpG|^c!}v?IjB>IZQR=qBU3cd9KY=E}~Td1W`Ag{Tb6OUacQD>&Mx2=&Qr1 zH2T&yx`HX{K^E-BT$W1$)UqjeIm}f(L9sn1h-!-#tL}|fAK<>eD>bf_rDeXVSxoJ^ zb4ZD&^8K3+nA+JGI_DeLW=D@&os2BI#G#VjIO{O_R6|a52DQmyw%qtD))DH0O8NR)?G@=R1ZZa9f0 zmp$}9pNb~8bw9m7WFodj=Oy8 zQ_9eWn9qXxa?Rzj9@bJZ8C|#cd8hJImP-dq9B zXx2D&oVR)HcPkafFOlL>9e?yTP>AM^@zZi}t|1Eui>qe}eP-zvxs`Jn8MAEo!CV?=0gj6W#G{Jz*aw&CBge2D z?CcHWiD+&uYWk51c=?9*6c;WOgUDHX|HedkGki7V#ZbAF|1Vw&m8W>)hko92-7GE| zRML9_NdOob?uts@I0%E(rGUgVD%mxQO)!%PX6i>Rs!MyyVtYpV+M9;wVgcxbLwC>Y z?V!a4T$uf{Q4ohd>~~+Zir9+jm3vVBo8${PZN$9epR}6*g9*sqRG2G$y5(1%BlZT= zk;sZ8xslH(z-gIbX0E!Y1O=kHq)_cbyIN%nUnmIL3V|l5^ICJqPr?q9;-)^?3qQG< zDJ<4T?dK{F_7_Eg%WE(e z@+GN*c_l$@68O0l^@inWnTF|B+3PjvHJ|=2L;E~M$+^Wlw2w3KdH-wmz!gx+s}0Jg z9tEIiMa-0lKR%SfgM6AG+rfM;um=Eer|MR-X0Czn*6xz0m}SeoSpspW4r_VZ;`JT%GcHyazS2@!*t`YC@&XTe?0Codv0vVz@ zFPJPQ%Yh7gOgwgWi|P!y@-SxeEZNi$I4y)ED62=4vPod&rq~Z>CN7!&76f7$P+WEQRO~hxp}6%B@@c>&wK|2)4(!tp7n>a2H^76_77cCm*KbFJ*G+C?Ovt3`E2KXQAJ2 zD}aPze2xtF8;Z#F=w_=O`q!zs9P>x!;#;5}`tB?vuGDNopwpilW6P(7=^ce}7>89e9Of%I1w^lS<8^n(CoPq^{ z^z;guY}L}*X|eO=x(`qR>|PIblv0b39U|C`a@#B6y(TT!4}7ZK-N(#i%%j_zBwHCpuPpO__Jy7wvayXpI zF4zX7ePQQ@w2x9>U}wzVd)}#e`nq!pP6^2Pql=3V7vBGPe0i&?F1g}dWg=UVnIiQ~ zp1&V$$VGfiN@9zWMw+6Tc?kj^HsFP|WKI1x8+0AX9)VP6Vlgc12-9ZpNv4)RRA*nQ zu3Zk5NKBWuMFzD_WcWuo_1q-Fxk4LCM$m*uDR?c3=uQ=-(woIoV(^z4?K$~y5YP}5 ztx5485mpzW+wQxB&&NeeeL{^}c z+aQ)t@yE?K0I^s#cbnQF~;2MnW0D@MHB`&#exSoc<)+V zCvpbPltu8lkI))q^W(s20AhU~7_UIE*7RUQlC^R9hhp!ElS33Eei3Z>+OMEJ- zQ3)Wo>x8NH_H)YC7HKwey+J=_b<`L%uT z4!H1=BedIVIw3QB%fRyB0W10+#JzP`)mszyO(P*lOM`U74!XNRQo6glL6DGCx&#Rc zkp}5dK)NKQy95NJ(-%*8w&?Mk^IXsS+<$l}i2F0M*35Ti)?V%(Wj^Kh{4I0lc-*nr zrnk3<2+J@O+Rx(HGC_mxylAIAA7-#h<_4w9`*~@jBnVK&a`m5TLA4RQc1g2-pxiPz z(Gg-jfU^abUTBFU^2zR$AERr!_c0`fxhx)i@3zrW)#Q$T8~a`aD6bFcfWY4`acVGx zh{yZ1RCaK_I|TvEn4`?l*B~uyWyRWyr?O++>E{_l*LF&|ipJT$dYNfH=x>dxcc2Xy z{h6nap)4MQGta^DY}6C*;Vx**CKtPvcGGkI%vUgr9g&id3*f)~dYh5coK3P(d|q#y zWwZ3X3F;+-mexATC!AAaf@Pv7Lk6Lr_qQIN#;QioI!qZ|ag-V)?GmmmKb?~)yCB2< z;KN>UaKJAJqeSUR5~1_#nAZR&_MSDITG1FIl>>}|5fQurZKtV?ITP#CVEmY3;#^fm z6;sw!_=4SMyv~CBob7W{qT=03y<^)g2gE&MriC6*IoeTgH6{d&J*ZWEh$~Cggz?Iz zSSLbi0aJZv?+oW#1lfCR^kK(qZco~>n8(2(ua%(~?DI^U6wb`R0iTulsE;!1Ji8CF z#bJN%n9%QF=S;13i5TC`@s!};wOHQS=tHx(9;9r{hha68tix|1v0VYlL-7`L+o&2#2hcwcbo-p&oE_p62;KepqDeMX`HAbs3osuEF%x@Uhl zq?IuD3Y9aO78h=1r={Hb^Rf4 ziK3p(-QLJ~jVuEE@pq)NFn+<rU#y@AH2&;nm)=aa7-xZw!u-SBU{Lz z2b3qHKjq{*Tq#(vAY>P>B{%}D+pJY1>+I<#w2G)2KMu`6aue+AFp{rUi?nkIL-V&utBVmCIFs%LAI^kC;wsiwsQBp%~>&iSTP?Ooq3l$U}cZhOp} zXR>t@Ku@0hJErt%nxvhbqcinV1se)_>+H0ei9FNlIFDjSlf0eIAP-A390z+bvL>Z_)g;palb1 zDDYoZ-?ikaJZ?X5`SA8q1$wg&x4LuN;+=qa(yakotSP(_G5y_$S!U+ezAeDBhEsPO zKM;F!P3K%X%laa{^?g#3rrGy1_FcaAL)>Q~>$)Rv4;Ci{d_B49S33sGt|Y|v!@b#? zGw?}$&OQr1w{4ofIQ#_k@p1ohdIY;L(3eKZ+l@^=v58S-cNgHPcq@63m9NW} z6F~#nM_2l+8LVeE#bJ?{_(eyQLvaN*nN-_V@O1cH%OXlDaiJsFH179vyy&s1P8VKI z7G%v@Tj-7O@peA@A|e*0z*Dw1{srla8#rTgVf=~-<_j*43qdTdYSy@yCeCO=OqeLi zl75y&iYQ0NSRyrg4{M^Nc*gPK@ypmR=)st%Qy{JY6Eo3ITIHoKkkInLZ_ z@rQizLEHos3F1f>5q`E*SyZPXlCen)g-*#OC^%AO(p2e&FAGti@$RP~i`~!4;vSCg zq_B|Q!LGxk^RrauK}uMT59~;?!ZHaBus)Tb$dt0jx^u4V^$>dg#p2WPy!rIy7c7eT zA2f7Ts8uvx#c0jI!?F#|5`<>E9a$8`cvGaFMN8-4-;0HcFQCmSIC>G&SCvJJBb8fk z@s=Pe3&v$V47C#}3cHG_E~={UE$LdVwf`gkAb(D&yFv`?T^y^xrHcDwMtMjV9z~S( z57c=wm$_^XbkzZy&>!KrSVuIHyHTlNY-B|>N`@%2D#=Y=!es#}4=e|t!uRr!SHpv07_7AU8YdUT64DlTtyHeZ}a4Zls+!jB@fWXAG@{ast?^pXd zH3~rRtm9%RbjxDPvQkh3eP9dmDHy%_gWEh5UfejzCyxejsVP?}q^YQ#JNor&VT3=o zY6{;E^q0EQ=!xA^>FrfmcZz%A+w&1ibs^R)P}qTkkyO)_GIW3bE`4ZC#ohT^My&-1 zLdLFwh9-vgnrV>}mVV?JE3>Gn4$4xmarKP{J~H!D)=F;Zi{8P&Wl=i-nDkT>7M7>c z*-_VFh($yR`F=4J_vaz(3X$nWy_XjMoLWOkqra;;t1@c)v7;Hf$ z*2t8lFj7@{6o|$%kU!aZ$+$7$qf&?=5_g`d#5*=LE37+8k+)Ou>5aAo&n^tvYGEe8 z4({^oHLe-(!K7r0x9yW8io|ry7+wyp??Vq$saW;BxI;Yb_k2_QB2rg6yT8w88AV1N zxj27pE-_srOnjlQCcdblI2^>}x-HxiT_|IAbPKBV1of(~u)2GiT07sBAsyb9%dlE$ z)I^15Bw7!T?41}8gj;lJ_8@ID$DkM$?>OVpaadS(`A8nqD)-Mzd9&bQZBzvr9yRh{*@hmFzY0 z?o3sx#Kq`&lio^x$NUFKL}~M10w>WY_oDhJ2VPfsp%2l>^w9Um)Q|6saJ`Dx_?WA( zy>3*xXp}x$oFPZ9WW(~{uJ7Ud&l9s5WRb5=yPL5}*<;XO9FX_D%Br$iZ{s6t+p5N^ zF65k^I#Ao~8}e2upGXd&AbjPraV2cntP%Qd;8_WEcbZRA)8^d!?PLFyVSD|#S=lBI z0pH?~IRkqij=M*Ztmi;ar+_zmt!`HCpBXj;duZI28S$8dSeW}BO*qXr#8hXzneouLGqHuD?S{pCOroXV!9VcpkOJ$mtRS1nzHLaX4Q-UA5i)7)0(Z&=?DRP7${c zaaA*K@Tr=ocmTP@ME8qs5teS=W7l;0Hj9E=nF*& zGzrnK>L+G8(cI#5d&_n8xqWTL&jFWq7p2i-p~o7Zq}%u|(U&ye;|qt9*sM(l>=y#) z)9_2dZ)O=RojUl8xl@=sBr7EpcGm`k=TT7gar;qU6xmeU6DDJcZK-nz;#~}Se9k2q z67m7<36nyHvblAtfHmdQ9rxJi`j`%OvGv! zZn^F2LGeg;zMq&y-&&%AO#eBsIXT@+(T}sHqL&mcRR+2FoiX2JEsW6{&11X@`wa#B z>Nl6QaCe{EM`v>m=nHUc1X|;*P-vKnCHnC#L6M?E~(eZ=YRmG+38{ zjvQXF;hB2U*NL`+a0&foF7iA#;k{!MC-OR`W$r157Sm8Wapl9c3xnOXzUP-zeDzI) zoXUzzNG??r{i|~%O^2kPNGy?g4G2|t`JC7lk9%deEg@&L+tGTtLEe1ToMAY z|KxcECQ5H@r&v)N&l%ih{o7v0GFn8H%XPpJb;akSLVF_B9Vt2!j@f?L+39jBz4z$$ zhpZD4QqofjhL>-Yhb&`fJ4!TiCT!|+%PD>2Gy7%|4p4AB?qk1r0vw2hJ5&-g8H%#l zwcY9Sm(B3M6jG@rSFWWPcxm|YoeCd-I8FP-*eRh;7qVvDD{rJl4I?zu0Rwr%O@4O6 zW8wCY1Ur4vhVt|;U|VV?g`M~vyfxdm5MY8eDSQr~s?=YQ(m<=CWlO^Ihr4D!M?<=b!630+ zZIh^?WTGD@b}0@Su_C?i*do*#${kT-m?7&F2lX;G4_5POmpliCJVhtgicNj$k%fPd zCL_lwcUfy%G_=g4`wI_~*|P$=uEb{K@*OLB1fVsTt52!PH#y&w?F={p@~=5~0K$pEZWFz8dL5m$xmH3WEOO*shN;9BLPN zBU~kh0!JeN!0@c*fsOQ;QA_efn1ZLSxe9vnZqG0G%|%5nBG#>CW9e2lvwJ4q*QYuW zG!F0&TKk&~qc2&5ax{cmtvQK?7zM6QPNP5BvNUUZpNf-~2B0q zo-UkiZ=ok~<-DiG=fZz(5=+O3+tF-E8c_iv8B~ZL1#t_I<}8VD548844sTr^L=5QF z_VuT(&<`Ciz1p!`;hk|W+IY*fsOBNZQCuDrR?3~Bm1<^<#(uYf)7MWP*f<-P@<}G% ziaRr;TU0K#%U&>%S+wbJBfy-KBvPCvyKC24@CiB|qImK1*K=I%Rxmb|dZ~9^gx=pr z+mW0IK*q}A*hfxqa7D8lyBJ)z*Y9MaE!KYls;v@IUifTTWJ7ePSgA?L)nY3~)|hhh z-pg`lEgcYBWQX-iHU88aJ8cWiyQKF#bS!b^N1W31godC}yjI)}_O6&I>P+ep(V~mS zoVFbtWS!DpAiUl+pwr!t6i*$cBYK%}6S#}RG zvVOKYIa(ZycO;l7Mbzo)SE>T#9}k;VaJd zB?zAHd7bqZu98^PL$!}w@vlXm_G?Qn%?DK^S%Lj702mKxM4yXH3be8SP=qE^O3$ub zOGA#h$5)dh)%eZw0|-@z8b%ws-Wa@+-$y%XFo~vbG-z!+C`H%W0N-re;mJ zS07js`^xs3M+j(C+uTR)xaIGl7?U{SYEAW#H@D98sloYqLGP=4#G+03!$Wk5&=twp0*w=9+GZ=6e<+Nq`L^2qH~=HgZ%WyFf{D$ z=Bv4&_am^8I{8>%2rzWb`%ZEe7N1e-i*ys{kHk-p#Q?Qv`lN3 z_IpVsO7!xgVF`hLcG5fLe*#53H;?C6z4;q8nD+g2$hpm2p5$ zJ){DqHw72qVkC<-@H#3fzrNc?y?O;jG7YV4JZ|RfzoYr26`79$s%4fRuq?4nMHF|{ z;+JcY$S>jkrs%%CIxEJ9&;guzP(pccW zoiHII3hy0dYCWJxN^!i>rudBN^d&hAeBF?$h1v=EHIPGH5v?dJ zG}gt;nK_|n+EpJ9(#8~e-nTtr8(1#UWY3V@H#0-tdogdjkEt_Y@(FC>fm;Q)fW|r9 zf>~S^^tLizl%%#+kutMNIG)4o9UaB(D+-MA+iwD1cSfi-Lr>naiMvEt$fQut5^4`y zKqMpI$CAZFmZTalxDy&DGIcIL6C(j&TrCP@P734O4W6*G^!$vBsFzH#%|yk5f2rhS zNY_u`QSvgPucu(1R!qVbj-Vj1-pnIBX~&ZV=?iUz2bKZ*i|R+{hf{COJ<}UIQr8cx zpQWL#1nqs?yE6DveB7Cp#7`Gaus0gJ+TJy>`|Qb==EULQis3C(mKP#TfaG2E@rrD{ zs4E1KL-@>}6xjcCordH8=5-nlGOqt#U^)KP4I3^tjvou`gSU>qy+6j_>iiOzP3!uM zTi&ajm}gXWv8IYQxpx^RI^%ILoC;KBmaoqo44l;c6!usmTFf_}ntaY(7n+~QZ@_(# z-`INg#q99?=;He5HX%1(j+j5o8lIg+^l;bK@^T>V#GW{3caAaxlM{VJPWvnAQ>LOK z4UPNt_)O9(`AW$n^737YG5phf?s!r7K{?d*&?Y zy1;7XU(Ug4 zwfO#qunzWO4As}f@07xKFv(6L<5DbP8>)zITR-Mqqk*DOl83z~Ke}ldz9c;28{E6G zb1}^_MXR@H=4{VHoV;9;yB8NPToMqfBO#UnF8$cU$@Vrr5ih(Bdc zoMv}svohDtV1zI9SrVs;QR(P?Ipw-rdn;^&@$%c$xYL^B>+D?B})aY0_u9&UnT zPD2YkRLZ1nzfX8h%$#jn=ox%}`2#i+54QfB2_FCL-BtUdr-&8}Mzj7_#a-QOWyQwS z1ml_kZoRiro+FMVp*_76@RDszcd6}`B2>VnN^lSyg)X&%Mc`3Bi4=^l#nd{qL~a-B zuw3FLd#hWKP$dxCd{~PHeEv5!>RA}oZ1cp6?9K;??T+2f0 zG}fTuG`uE1fl~fy~ z?@gMCn^|RWHqc8@23S4xp9dz#hM=&1QbB?Gu?- zv9h=wld36lg9U{ufESO#-$zDhjgS|Azng5Y}QCJr=NXHdH?-cdT6$(!X2x4j(oxE&k&!{ZYf^hj#|Qsv z0{&U?5-ym!P>Uk_!($C9&ZCb+jn-T+xSVE~y8E%(=swpvjtY^4`~_5SS2Z56&R^{XG*c9`2bz!Z zst6bLozAW#^+eD{L1uz*$9w3t4*$q^z_%Z)P`X!f>^p_N7gdi!dv9;fpxqu1WDc45(|pne3D5*T^QGwN68a)B97Vi;&UPiQi}-OTW^QX7!GT47e<-}s67HT#rW_2# zTmE}|P+&wXR%F)6GGF?G67fRH>h}U<>QD1q_Sa*h^g~)M2GO)E^h>Z!A0JiBhV$Xx zl?!f?AKVpxmc(nQ*=el!S&AVGIydPK>D1l3hD(j*@)e2?+BO|b3>e+mguK1+YKg-> zJKKTUyi*1*D zn2jfC;3#|px6(w7*X_6FYB=-CpsnbeLt&o)uVK1r4(uTseyh~!gw)Zqjv__=vVT>Z}0T{jC;iKi+*};ce zl)`o@{imGNeeEz;gHLNXyy;A&MN|-{B*UnQwB{-~jz6tWchXkQBx3LNzrgm|7n@2| z7?|tx<>SfQ51;Qj9KNLBqgM4nK8{fkHd0!#VHy6IXs0l{_ql@O;_UErVry}cNgS#H z*{>j3k58N5I|rS^jRQTAbmMB{&P|m^B8OmNVg+A{m}$mbESAeJVPh zv*UA9TDq7mY#r=dmZ8r)_E-BteA9d1p?+CiJk!=@6jgdQT_}Hbv8mL%W*EQFXXwGC z_A=>R#e{5O%&=Eu)e!qVaQC|%wJ(diE`BFl-WYm|CmRhuqZ3>>0T$tTI46k!&<5+F*)Q!Tb1N}i-fZdRsxfpt4VGoH3lS@>LX z9W$5E@iyar_{pRm4XNbiSsCrkganGE3m6RngS7BSGcZ6S|rVGIQS81JbGww@em;dYz)Uw4I={ zRq;Q$Khm4@j}nb%PFglQ*_nKasVmFAhlYy~MeW>k=T-%8WooJ;#nGf)$W}+u3Uh@I zN%fFzr&?}YXT%E6Xq5wZbZy4dPJSrPHhnN7Vl_s#g(d?z#(d6a0>;z`m`@KC3}M!E zsl3rV)K~-+Z3FDY_o@g6=2VOfl+wV^B4qDK@W>m4-F$;}FjOp`fO9~Xv&p)}M&-0pH@rGH-3 zrJCr8hWB9%n_yg0I)F)z#E}6% z=<@)h<9n}q$Y7XZS;nCSS`wLD)zwwy$HytFqXL_h2YWKWS$;+)7@Y`I%%#&Up@DA| zkRvrSmc-3DT!c0XUQoCmX{kniy2VE&n8>qVs6+kq{Q>0!z3zebHKza>+5#ANn?w&TTf*)T#_yi>=j8tV2ZDD~t z7-x;U5-Nn;fMF>&-d2?yTu`l89_U-a{XF+<}9v2Hr-ZUfzpZcnfymsTqFOKkd_Gef)D~M z>I`m$%=+ix-s<6(X_a=5HwqJHpjRlF)F{-2zofW8H3n;t?V}5mK3u{kmDhZq%UQXM zp^SA--rR9F^7*U-=e~w_*$b(%h(sb~M&YDA!=^iUJ4^6$w+k8ql(cZg~ybeCf=he0-G~xc}NguoGRtWsSn!&Ce)aMK?Ax2Hd z!?wsJu{q=JTg%lk%BqM)sAOE%$)%1Vs|`M?9an7W#AE-^6l*??(H$9HrTccO3?&sO zs?K%Aigf9&Q+@ShtNh&Ce1ZAt4hy~bHerx+p@=q1H+3EHk~L3d|Bx1z+NOnC&D}xO z-R(CYK0kZ9!!734#ozLY@YNpinJWSA%UhA87d?H!HQT)1faRyK)MrshAN67J6!I!z zhlVrJ^1|PBb`JBD)4%IqzB?#1+)v2BLA3QaY}aQ5U7@VXU_r_7;gQQLhYwn#cGh4C zj=gXW4hLr+U2|c?yW&Mlip zFOLLAW-@J_37&&~X~(#P-=KscG#=NCq8*S8iz;p!CQlnpkl2 z^d5+nt%&N&2*srKHP1OwO_aqa09c=Lf4<~iOZOTjMWk_#5TJ2pUuqU}+I98a{dmch z_H3}Bg`=VeB_+|Bmye%6*Tdn2tVmgWm@YZ&LOP}_XXtuTZ_VR5BYRz$l{>JVr3OEf zFKkI;K}8gLsEN$bgVda3VWmkQNL`%}R8Zwk%j?n}@2VU2dF5j2EgNy#GdTr}*35zy zEy5MG;q%0U5ONz{@M1k>X0@^YxKbIWC!K-+%o}hN*)0yaDtWVEr>ethW=eV5@#cB` zm#8erngxh~50VaDg}e9Nx;62$v_@j+jf@)h0)YcK_heo$phzn*Y;+Q0y2uslaGqwz zbKhNM31og5r^a{d$zyY)tz&Fc6S<0T@&Via(B#+XuboG@HC}^l>gt@}C+M1`tqgoZ zObqn7eVXp0^i0t9Exeyh$-(KOv3A^mAKg>j{qpfrY#@a{X8%A{B46Yz42qyEvR@>i z+v62(Q6fe2aY#Pkf`D-74f-Q#GVv9f5lh}|Esa2mJTmxsV7Q(8Q^zumjTOIg^F~Qp z_AZ$7!y)#l+cZvSa&H&XVjkSB5rrmEq3d}7&74h(JY1OUIo~OMs#;)BQJj;Qywvhg z$kqlVSuP447C-d4Ghl`Mu9>EmC=@l6G!BEM=9&dL;vtMZLkLXCo|Oc+-= zio$~G-Uz_pL~^&?U^;4bWf_g5nopr?8JuLn{i1p_%?zAZ$PdUB;v~7potR41pd|AW zH0^~qHL(Fw!pCZ86HjnU$ER_Vxr$pe>~)mqGtG@bkxz7M>7DVLO09dlgCpN|CwV5% zVNk}vzb%oiH;#*E5}6Amc`alN^QpWzne2QabTWg0PXfWjtIkDt=XL*R4GKzj<3p7e zpE1JTt|kZZZC-NY9z`)!!^%PiAA2uNoGFZaW=fH64|;j5!k6(^Q3?yHpCl5LF)Yc} z#Yzca;CrT7ALA+4*}S#K;8m!xhzGu&cc-accTn^-YJubVk6rgD{zWh{i`4 z4Mid&68@dnkT6>P?KYCU$3($)r6N1V zI=4*^C`!+9OozHhOy~oUCy~{4?591g!cX+A!c$bFCD=y{_dDHhDTe#PAsWLti!Zs% zu+!4R1>6r1hLz*URC0&LoT%Dmx~m?}`CLOs^lox%&_0V@c|`&*~LvBWsmsG9ouL zNF{X?m9a>3N3EcaDYK>t*tAbqTvxh(a&~|Jh)&%(XS%yD+RAvu_A`M z+`(ebR-jfjsPxS# z_w470e%?G?`Z82(l3UwI9@fwE^7gI$xM@aNjI|ql8gLKJH9oYtzDA*YVKCV@q({u5 z&};7A7NA(wU{AU70cQsZLGH+Hx40AOH5vt6y4~=*Zd%>B_WC_rKAj~!XJMmmGOJb} zO80e1Om!s-zem}TXpx=w-!Y8O77odPoTgb?8=}KqYnPt~T%e|H_odjM&Nrsmxf8j< zDl1O8%S0T;f9P9+;Xr*oP)PGQdV3Df6&{)&NKYU8ko9 zU}@G=9eI}1w)*;kYUin$wNHxX5`IWCVce4`jYw-xn4{))_bTuO_|wwlSXfvx?A_a% z-_)F*9QBMQmK-dc4Id`HB0TdxK3ZMk;q`U9+&D_nt4$}paM~4Uv7&?fNxlA0H#9id z|3~$j{a@8<4)!1Fb#^rmF*>>s<-07ng=+89_@Ka`M##RSL$D7$b@7HZ^#vOj?t~vC6%al3Y zkxhy^Hq^bl-^5aHWO31rT#o;`qPA#;M!L)e9dTlP%?*zLe7v|ZH6a?2r`|=?@Vwa&(SYeue&c5!s}gZxPlI7Q zdX&;c2IQ^RE-h1&CSgy+PpD>d!%OEygB4{`H%&y$mTjl^$0wFG8Dp}5K@gsZkdkX@ErG?a<+rZik2Hn2)#MX&@8*17zona<;T-mU7?U{~E%c<- zb_As?sPxHb9QrU6qOSK@G&$2Ot=!B~JYcYXH=sI*Lk|JLw7m19O^h+l{ z(i@ z>$B=7b@7YZ-tXiB;>GgBpmivLi@msL8|LkROQntXk6is~Jknk{Oh#YL@IE+@rRAFldL%zhw{vEfHy^#Dcz^~m7k%+npY zN1S@{)M9Phg{U+_AO!Wia=A9F(GU|(Rj+_|C^$SVl=MD$z1fyXU5^|jkI^eFpzwOV z4cR@RnAUbN3>Zk`Q~ ztnJinqOW$GoI12oW!Tc^+Icu=Y6(4*$Pa2njarL`vnY^vx&x;kw~IajT)IZ>hno@r zLNq<|wa4Q+#+LX1)Qf15PuFxQ{dAJfZ!4i0NWM1(!LRn>M8yP1{>@_m1Ly)JL zWi`zZ@uZ){lbsSl&NUY?oKE~HY#Zzv(1>>T`1#RN&SgK3juY=&+lP@;28n1dU_>d# z@P)-c*_E~Q~W6?=buS^a*m zS>iO5ZM$0{qO^B;Nrq8tdtG8B!biXnO5I0y4TVS4o~-X?1cvnqeMAp8d<2oH>FK=a9!WB1G`*^h?lahrLwPWY_WT^`b92C&hq*BVn1=k zXCH|jI5Gabs9<5KA-Z8VM>0TD&HI6$FFfRlUGuchDLwzRU)>kSV={h$W}lN2w2qxm z0(`T>uQyL!0MBQjytHdmhTmTfPw1I_fts$umHtV6|4&!gI5_`D_5EL6T;t^U@u)jU zUB_-%`p)${es|9?JTCWkkW!oSmY!+Hs>QFYm)9k@@w$i4!I-)?|89YJX=>DF6C)hAbE-Z*wTV&(Tay4#&jj~d$j1n zXPqzi02=R@tMl6R$d;OJNvZRjzxpWmML)!g}VV z6o|O6Q;iao<=z5cTuM+q`5p7eO&8)`NyW>Cu<5YL_|ZMZ;>2H-i|qw*f?1o&R8u8-%jYWyehR=UgZrsr>Js(Tz;4XazR^v;#c1jpXMizlE& z!lTV+k%S??BdUIlP=PFt|KN=NfqD4SE~Z$_OJj4#9H&UjT}q`7N!F7{CpMTWFATL8 z4x7B5&E_UO(9u$lwy@`SriXh|9zb{wXlr0Co5XDJTBJxMG%N}m!%@v#pK&mBk|Ly9 zueC>WY<<1iSrX(*7@G@IJEJ-_e@fEvXh-Xq2N34ZfL zL%QxXM_KpeLll3CNr)kK+~V^p!&O1=*A|41B~W;Wx6F|YV*KiW>@0a3 zN7LG>DUzpcw=TugoEBAuf6)dL$U7Yx!Kbik+6_nsX> za)`Z8YSpL|eKAPeS~S5GWPTiLVF$IkBf;4_yns-9?-ZFN)O3A@ogwa6U`0e;rO!(W zPT_0@d+;`;j~M!!+nJu^6|hq*#OIQPwhPIt-N%{H!YnQr!X`Aexb3j7s!uc*>4ZK{ zg~3X*OsrN=nl3&)l@6*c}~0zUPWT&v(Q)^D4UaW&}K5Y(`(Iv zc=mcxNR>U!mcYi%1ZRY`NN;tdkI5&s-*humzbMjxZwn^Ctt56XyeL8vH>umk93z6T~v%kl#U%q2)ZO0!cfq#bA8QL$*Hf!P_yc{8~ zUg#>~7orPvnFlnJKWQNT(-l3=|M?X?&VO@7j{^+;@&9tzsL0t(NuoBMtKZ?vd6@k{ z%Ce&)T2w<+0@&T#S^Q8pz?TU3+~3Bn%+HUs!|`Lc7#dpJ!qU?*y;L?@zHKVfZ6D6VdCr!OuSxt%UU@4x0PTqIu^vYc3Z zba14NB6{B@c-$dh6Hbm!O%QSWK1Ek1FL-_UnP(w_)!?T)o}{&%>!@vSuqm5pK#3Qq z8gsnpt2nRMpx*S?guUL7aiBESF+UIy!Z`bI2Dn1;NVc@Ck#?NV$@Lc^;!ZckRZbYy zbkxqoD#G9*deQ9(|0y!i%7%e7z|d3Oe7Sg{>1_4LSDE)?>Y-^^8lOvcf4RA#n`CqERBY zSFz|9A)+3r5RDvN4?Oay6hu;LNq{}Z9n;P_npkB7YufU6X+FrhXWQk`Pw-TV)eVDf zd`4`b9vRbegv`Z&IZ7W5p5i7I5Wsv2Xc|OSjD%$lsu{LcO<~AUX2|4!9?Z*Z8S#N! z`;9`X=5%SQcKRbQ27$N0^)uY1^AmAPwxO84-Vwwu^<@>@dP0+- zf#-Kj=ZATz!*`0e(JcT3sIdx}{S~-6$?n}ADUM^QI(uj|Cs#AYAC^}LJRcvAkNaJD zogM`R@8~u8Utq<9L$7{JcFzBFF@_WH|KiCtod4t1WY?fhipaAOU_6n_mq-yNmpWU=RW z7s^dxA?s|i7Y!yA(mVCk7V~Ul_ASyjwMx;({ba%adb?D_&gFWQIj)^_baK94+}~GQ z*5LXJ;O`IGgIJTl-oN}~cYc2*B^DJ6XKNE$6$3+S6EZtfvOhPAjz!eO$ytky>vu(c zprLvFJIB`#$JSwyzuu7Re-FNa0RJ80cSD)L-z;VS%hIpUZ~w~-MMo1;10$0^-~d)2 zB%Jd%`1OyteslJBOSsr>Si=6JC141OvWJtii4B>8tBIqlg^AlwX&_cE2v=`B9+Z>g z*8ovFBNv;m-~Iss{#%FGAspi5yusuAHBa8o*}&Pt&i3o>xnBSE^&g#nie&%#c}?Gt z9FWKxAA`=x^=qV%q2cw5SQvcI;`m$lI3f3o^?Mc<>#tb~&gLeLWJ)HcCf9#?Ef7D& zvH!kdf8cI-!^QRwvB~*oY;pl0W0MQQ3N|t(GDSy=>(#Y2Bm0{W`r}C~KU)CsUkdt< zY!G$v56SqQ54g@~Rj02x0lVr$}PVEs#rAUjeZ+l_Q&WBt(xuJ6*(`g&6OGbDZ+z{r#>JWUwMzK(5- zWY;T0ru^IZ^;0$w%nHF~yTNArC${r9vVx<<^$+~kHGTs@3J{nBBKX)Km;J_*F@OL1 z7u0W3pkPZTYzRUo%q&0s;O9pTXaJ zhM4Ps0M?%lMBjT2{H_eJLGC@I9s_P}!;kvM2L7qn24qSGwr0OgwqL#eIT#Ev)&kjX zq&FMKzh#MCk6vWgRb0W?_!lrBJ7j#ZL+!1g!J%e&YZ zUgz!C;~8@UM+2j;0|%Mn^>?Ifjm&>)2LJ^8E2IH8iUk1pe}ewnxBP_qcPAQuuHqji z+-T$gp#LN9?W|pFAXfgnX#r9*0pF>|4b23A|2_L_9+Sx#IGS1f4HnD}AzA>)rVVhT zjRCO#8hiZ`&dwe`CNv}s$O(~KKlsJ*4*?GP7T}zaeG;S*QZ`>5z8T@*?`jjI!;m8a z@J59O{HR|5$ni_@dLsGC`E#v*WB;7__1}Gq=9_uV^=pi>k%9Hk5#RNDtQ-(-L8=z; zhH3#>f6Wszwsdj&7C@3NCS=;QD%X3eP4_i~4Qzj51PB139stO?54=$Ufo%W92<7X} z-|_boLT%dXB(ih-8)LY>J5b~N%a|V)0q}2|-almNk6440cS%Ji30W4v57G8rHwJ_- z0svXTfH%?$_@k%+0YB>pEw1}PYXc*zpYnhl5KT7lhG+pnzeb2#KnRDmoio|>djBaR zKcxX6OC=Cevw$~p8wmb28d9@FO-v20$KPwIwk1=yFn0c?)u8WAC)ptM@&`}Z|89GK z$0-@OeeHBqZB2hW{W38oQ*d#%cX9qH2@HUkYj27KkmFyT%mRUsq6LBsB+%F4&cO92 z#|^*DHGizfw*UhH|8~xU%zMzy0Q*tSfE+(LJG&9i-_gE1!vWq9G9cHl0e|lCpT2!P zF}j}O>`ja;Of8IVp6h(a1ppvK8~B}=m2>dSt z>qp?tsSEWaemM@^ygy z(}Y4~^4;9^-K+n0QuF7lgKo$gi0jv{{-*xR(7$sw{vv5rw`o}q?yegT5 zn7o*hkSv*^s<5n-2-)>7F?nUNZ>+yhR>Xxy@Lo^hjo0q#u3s>MKoT${7!tAyS%^dm0U-rhhUD#2J;q8r z--TR+LB}&weR{f1o$8ru-#`9-yu}J>A}2?VVPCbv0f-uiUJ? z-`&61-c&gL=HUf9{yE|=G0APTPFM{dSBdM*u^*0}Fxi=K!sf*F=JCYfjP0lYCrq8k z*~P;FOqDTA8N-z^LK!2KG0G65Qx!3m7-FoW zfSj;(0n-auAQzVE$U728b1N+Q$G77v{N70S{lyeOCbw_Y3D9FMXV_ zP>wG+r=HMf=~4kKhG4GZf)2$L%vCIEQz*5m(-PwgLtT~d;P@`wx9+GJH>n4mZj4)j zIn9B3DJfhBDbC{#^MAq?*J&>1Zz}aUHF%uC(?~isJA?N(!^tD5YnjaR-2YW2Fh`6k z#F)G65wk@MS~9l+63Yqf*vUC#p1_!cjbRQNEAn7HYAngaCV7~XhYNYQk%t#~gpx-j zdE_LI4Dz5JG-l*c(3e&^)a1tC|7IJQB!=9dZ5osq^1Q7DYQ?r2ix_I{+{KYtkcSC* zn30DM@}MtiEXgAlc|?#$3VEcFM-B2QB@cRwxf6sKG;!`5N6f)vPSoVa;LRF?Cbmt4 zpKJ`hOJ7dNL!CTqkOzCK#)>?Ak%tF)gpfx#dE_7u`qMovmK$T*M#-l+Qbzw z`e&Q00X7$EkIjTWcN>6y)l^WEO&9L38Eb&GjDwrAhcM^5x8VLuXACsfl6{_KLF;@h z_#q#L`s-bzaGcO9cW0l(9Aojt{TE-!>*+!*>*|JH(lt<%T@!xIjeUw6_uN`xrvRho zG&7Dl6FC^2g#ygc)5SFG!^I4E^v*2gbSU?#!V?~@+Zo0P`iR({GggWk)txwcgLVw? zP1*MOJXb9x$fI0=o;bV5PGAmykYSUUW6ZmS!1yYm2i2=+0^>emwKfSc%u9)2?%M$) z_p9ZFF%0Xky7UCFSd5X2F$(LY+Gr~#;w=ohNnH^gWof$McW$Nkj>A6CkJ`BLuFRO=t+Zx>}? zh5du-)WUHlTnEM;woE56yAXr@M|BwlUn}OD4|wWwK`+!P%{A!?Z&7aOAzH$)A6p*5 z7zKT4`vP6-Rf=Atg1uy~7U#LfT!rmhiIH2eFRNa>{~7c1)6F0Ew@+7Z-@e&jy4Vl--u&?RxSxZ5 zdNlj);qLL(rzh&~zW(`b+^w72aVv78U0?3zjUGSV-E#a|_1pFTAMwle_0@;xo2TdF Rx#HfgimTVJzj^=d)jwoWr)>ZL literal 0 Hc-jL100001 diff --git a/doc/sum.shtml b/doc/sum.shtml new file mode 100644 index 000000000..7e18260c2 --- /dev/null +++ b/doc/sum.shtml @@ -0,0 +1,933 @@ + + + + + + + CUPS Software Users Manual + + + +

    Preface

    + +

    This software users manual describes how to use the Common UNIX Printing +SystemTM ("CUPSTM") Version 1.2.0. + + + + +

    Document Overview

    + +

    This software users manual is organized into the following sections:

    + +
    + +

    Notation Conventions

    + +

    Various font and syntax conventions are used in this guide. Examples and +their meanings and uses are explained below: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Example   Description
     
    lpstat
    + lpstat(1)
       The names of commands; the first mention of a command or + function in a chapter is followed by a manual page section + number.
     
    /var
    + /usr/share/cups/data/testprint.ps
       File and directory names.
     
    Request ID is Printer-123   Screen output.
     
    lp -d printer filename ENTER   Literal user input; special keys like ENTER are + in ALL CAPS.
     
    12.3   Numbers in the text are written using the period (.) to indicate + the decimal point.
    + + +

    Abbreviations

    + +The following abbreviations are used throughout this manual: + +
      +
      + +
      kb +
      Kilobytes, or 1024 bytes
        + +
      Mb +
      Megabytes, or 1048576 bytes
        + +
      Gb +
      Gigabytes, or 1073741824 bytes
        + +
      +
    + +

    Other References

    + +
      +
      + +
      CUPS Software Administrators Manual + +
      An administration guide for the CUPS software.
        + +
      CUPS Software Programmers Manual + +
      A programmer guide for interfacing with and/or extending the CUPS + software.
        + +
      +
    + + + + + +

    2 - Using the Printing System

    + +

    This chapter shows you how to submit, query, and cancel print jobs to +different printers. + +

    Submitting Files for Printing

    + +

    CUPS provides both the System V (lp(1)) and Berkeley +(lpr(1)) printing commands. Type the following command to +print a file to the default (or only) printer on the system: + +

      +lp filename ENTER
      +
    + +

    or: + +

      +lpr filename ENTER
      +
    + +

    CUPS understands many different types of files directly, including +PostScript and image files. This allows you to print from inside your +applications or at the command-line, whichever is most convenient! + +

    Choosing a Printer

    + +

    Many systems will have more than one printer available to the user. These +printers can be attached to the local system via a parallel, serial, or USB +port, or available over the network. + +

    Use the lpstat(1) command to see a list of available printers: + +

      +lpstat -p -d ENTER
      +
    + +

    The -p option specifies that you want to see a +list of printers, and the -d option reports the +current default printer or class. + +

    Use the -d option with the lp command to +print to a specific printer: + +

      +lp -d printer filename ENTER
      +
    + +

    or the -P option with the lpr command: + +

      +lpr -P printer filename ENTER
      +
    + +

    Setting Printer Options

    + +

    For many types of files, the default printer options may be sufficient for +your needs. However, there may be times when you need to change the options +for a particular file you are printing. + +

    The lp and lpr commands allow you to pass +printer options using the -o option: + +

      +lp -o landscape -o scaling=75 -o media=A4 filename.jpg
      +lpr -o landscape -o scaling=75 -o media=A4 filename.jpg
      +
    + +

    The available printer options vary depending on the printer. The standard +options are described in Chapter 3, "Standard +Printing Options". + +

    Printing Multiple Copies

    + +

    Both the lp and lpr commands have options for +printing more than one copy of a file: + +

      +lp -n num-copies filename ENTER
      +lpr -#num-copies filename ENTER
      +
    + +

    Copies are normally not collated for you. Use the -o +Collate=True option to get collated copies : + +

      +lp -n num-copies -o Collate=True filename ENTER
      +lpr -#num-copies -o Collate=True filename ENTER
      +
    + + +

    Checking the Printer Status from the Command-Line

    + +

    The lpstat command can be used to check for jobs that you +have submitted for printing: + +

      +lpstat ENTER
      +Printer-1 johndoe 4427776
      +Printer-2 johndoe 15786
      +Printer-3 johndoe 372842
      +
    + +

    The jobs are listed in the order they will be printed. Use the +-p option to see which files and printers are active: + +

      +lpstat -p ENTER
      +printer DeskJet now printing DeskJet-1.
      +
    + + +

    Use the -o and -p options together to show +the jobs and the printers: + +

      +lpstat -o -p ENTER
      +Printer-1 johndoe 4427776
      +Printer-2 johndoe 15786
      +Printer-3 johndoe 372842
      +printer DeskJet now printing DeskJet-1.
      +
    + +

    Checking the Printer Status from the Web

    + +

    Since CUPS uses the Internet Printing Protocol, it is also a +fully-functional web server. To use your web browser to monitor the +printers on your system, open the URL: + +

    + +

    From there you can view the status of classes, jobs, and printers +with the click of a button! + +

    Canceling a Print Job

    + +

    The cancel(1) and lprm(1) commands cancel +a print job: + +

      +cancel job-id ENTER
      +lprm job-id ENTER
      +
    + +

    The job-id is the number that was reported to you by +the lp or lpstat commands. + + +

    3 - Standard Printer Options

    + +

    This chapter describes the standard printer options that are available +when printing with the lp and lpr commands. + +

    General Options

    + +

    The following options apply when printing all types of files. + + +

    Selecting the Media Size, Type, and Source

    + +

    The -o media=xyz option sets the media size, type, +and/or source: + +

      +lp -o media=Letter filename ENTER
      +lp -o media=Letter,MultiPurpose filename ENTER
      +lpr -o media=Letter,Transparency filename ENTER
      +lpr -o media=Letter,MultiPurpose,Transparency filename ENTER
      +
    + + +

    The available media sizes, types, and sources depend on the printer, but +most support the following options (case is not significant): + +

      + +
    • Letter - US Letter (8.5x11 inches, or 216x279mm) + +
    • Legal - US Legal (8.5x14 inches, or 216x356mm) + +
    • A4 - ISO A4 (8.27x11.69 inches, or 210x297mm) + +
    • COM10 - US #10 Envelope (9.5x4.125 inches, or + 241x105mm) + +
    • DL - ISO DL Envelope (8.66x4.33 inches, or 220x110mm) + +
    • Transparency - Transparency media type or source + +
    • Upper - Upper paper tray + +
    • Lower - Lower paper tray + +
    • MultiPurpose - Multi-purpose paper tray + +
    • LargeCapacity - Large capacity paper tray + +
    + +

    The actual options supported are defined in the printer's PPD file +in the PageSize, InputSlot, and +MediaType options. + +

    Setting the Orientation

    + +

    The -o landscape option will rotate the page 90 degrees +to print in landscape orientation: + +

      +lp -o landscape filename ENTER
      +lpr -o landscape filename ENTER
      +
    + +

    Printing On Both Sides of the Paper

    + +

    The -o sides=two-sided-short-edge and -o +sides=two-sided-long-edge options will enable duplexing on the +printer, if the printer supports it. The -o +sides=two-sided-short-edge option is suitable for landscape +pages, while the -o sides=two-sided-long-edge option is +suitable for portrait pages: + +

      +lp -o sides=two-sided-short-edge filename ENTER
      +lp -o sides=two-sided-long-edge filename ENTER
      +lpr -o sides=two-sided-long-edge filename ENTER
      +
    + +

    The default is to print single-sided: + +

      +lp -o sides=one-sided filename ENTER
      +lpr -o sides=one-sided filename ENTER
      +
    + +

    Banner Options

    + +

    The following options apply when printing all types of files. + +

    Selecting the Banner Page(s)

    + +

    The -o jobsheets=start,end option sets the banner page(s) to +use for a job: + +

      +lp -o job-sheets=none filename ENTER
      +lp -o job-sheets=standard filename ENTER
      +lpr -o job-sheets=classified,classified filename ENTER
      +
    + +

    If only one banner file is specified, it will be printed before the +files in the job. If a second banner file is specified, it is printed after +the files in the job. + +

    The available banner pages depend on the local system configuration; CUPS +includes the following banner files: + +

      + +
    • none - Do not produce a banner page. + +
    • classified - A banner page with a "classified" + label at the top and bottom. + +
    • confidential - A banner page with a + "confidential" label at the top and bottom. + +
    • secret - A banner page with a "secret" label + at the top and bottom. + +
    • standard - A banner page with no label at the + top and bottom. + +
    • topsecret - A banner page with a "top secret" + label at the top and bottom. + +
    • unclassified - A banner page with an + "unclassified" label at the top and bottom. + +
    + +

    Document Options

    + +

    The following options apply when printing all types of files. + +

    Selecting a Range of Pages

    + +

    The -o page-ranges=pages option selects a range of +pages for printing: + +

      +lp -o page-ranges=1 filename ENTER
      +lp -o page-ranges=1-4 filename ENTER
      +lp -o page-ranges=1-4,7,9-12 filename ENTER
      +lpr -o page-ranges=1-4,7,9-12 filename ENTER
      +
    + +

    As shown above, the pages value can be a single page, a +range of pages, or a collection of page numbers and ranges separated by +commas. The pages will always be printed in ascending order, regardless +of the order of the pages in the page-ranges option. + +

    The default is to print all pages. + +

    Selecting Even or Odd Pages

    + +

    Use the -o page-set=set option to select the even or odd pages: + +

      +lp -o page-set=odd filename ENTER
      +lp -o page-set=even filename ENTER
      +lpr -o page-set=even filename ENTER
      +
    + +

    The default is to print all pages. + +

    N-Up Printing

    + +

    The -o number-up=value option selects N-Up printing. +N-Up printing places multiple document pages on a single printed page. +CUPS supports 1, 2, 4, 6, 9, and 16-Up formats; the default format is +1-Up: + +

      +lp -o number-up=1 filename ENTER
      +lp -o number-up=2 filename ENTER
      +lp -o number-up=4 filename ENTER
      +lpr -o number-up=16 filename ENTER
      +
    + +

    The -o page-border=value option chooses the border +to draw around each page: + +

      +
    • -o page-border=double; draw two hairline borders around each page
    • +
    • -o page-border=double-thick; draw two 1pt borders around each page
    • +
    • -o page-border=none; do not draw a border (default)
    • +
    • -o page-border=single; draw one hairline border around each page
    • +
    • -o page-border=single-thick; draw one 1pt border around each page
    • +
    + +

    The -o number-up-layout=value option chooses the layout +of the pages on each output page: + +

      +
    • -o number-up-layout=btlr; Bottom to top, left to right
    • +
    • -o number-up-layout=btrl; Bottom to top, right to left
    • +
    • -o number-up-layout=lrbt; Left to right, bottom to top
    • +
    • -o number-up-layout=lrtb; Left to right, top to bottom (default)
    • +
    • -o number-up-layout=rlbt; Right to left, bottom to top
    • +
    • -o number-up-layout=rltb; Right to left, top to bottom
    • +
    • -o number-up-layout=tblr; Top to bottom, left to right
    • +
    • -o number-up-layout=tbrl; Top to bottom, right to left
    • +
    + +

    Setting the Brightness

    + +

    You can control the overall brightness of the printed output using the +-o brightness=percent option: + +

      +lp -o brightness=120 filename ENTER
      +lpr -o brightness=120 filename ENTER
      +
    + +

    Values greater than 100 will lighten the print, while values less than +100 will darken it. + +

    Setting the Gamma Correction

    + +

    You can control the overall gamma correction of the printed output +using the -o gamma=value option: + +

      +lp -o gamma=1700 filename ENTER
      +lpr -o gamma=1700 filename ENTER
      +
    + +

    Values greater than 1000 will lighten the print, while values less +than 1000 will darken it. The default gamma is 1000. + +

    Text Options

    + +

    The following options apply when printing text files. + +

    Setting the Number of Characters Per Inch

    + +

    The -o cpi=value option sets the number of characters per inch: + +

      +lp -o cpi=10 filename ENTER
      +lp -o cpi=12 filename ENTER
      +lpr -o cpi=17 filename ENTER
      +
    + +

    The default characters per inch is 10. + +

    Setting the Number of Lines Per Inch

    + +

    The -o lpi=value option sets the number of lines per inch: + +

      +lp -o lpi=6 filename ENTER
      +lpr -o lpi=8 filename ENTER
      +
    + +

    The default lines per inch is 6. + +

    Setting the Number of Columns

    + +

    The -o columns=value option sets the number of text columns: + +

      +lp -o columns=2 filename ENTER
      +lpr -o columns=3 filename ENTER
      +
    + +

    The default number of columns is 1. + +

    Setting the Page Margins

    + +

    Normally the page margins are set to the hard limits of the printer. +Use the -o page-left=value, -o +page-right=value, -o page-top=value, and -o +page-bottom=value options to adjust the page margins: + +

      +lp -o page-left=value filename ENTER
      +lp -o page-right=value filename ENTER
      +lp -o page-top=value filename ENTER
      +lp -o page-bottom=value filename ENTER
      +lpr -o page-bottom=value filename ENTER
      +
    + +

    The value argument is the margin in points; each point is 1/72 inch +or 0.35mm. + +

    Pretty Printing

    + +

    The -o prettyprint option puts a header at the top of each page with the +page number, job title (usually the filename), and the date. Also, C and C++ +keywords are highlighted, and comment lines are italicized: + +

      +lp -o prettyprint filename ENTER
      +lpr -o prettyprint filename ENTER
      +
    + +

    Image Options

    + +

    The following options apply when printing image files. + +

    Positioning the Image

    + +

    The -o position=name option specifies the position of the +image on the page: + +

      + +
    • center - Center the image on the page (default) + +
    • top - Print the image centered at the top of the page + +
    • left - Print the image centered on the left of page + +
    • right - Print the image centered on the right of the page + +
    • top-left - Print the image at the top left corner of + the page + +
    • top-right - Print the image at the top right corner of + the page + +
    • bottom - Print the image centered at the bottom of + the page + +
    • bottom-left - Print the image at the bottom left + corner of the page + +
    • bottom-right - Print the image at the bottom right + corner of the page + +
    + +

    Scaling the Image

    + +

    The -o scaling=percent, -o +ppi=value, and -o natural-scaling=percent +options change the size of a printed image: + +

      +lp -o scaling=percent filename ENTER
      +lp -o ppi=value filename ENTER
      +lpr -o natural-scaling=percent filename ENTER
      +
    + +

    The scaling=percent value is a number from 1 to 800 +specifying the size in relation to the page (not the image.) A +scaling of 100 percent will fill the page as completely as the image +aspect ratio allows. A scaling of 200 percent will print on up to 4 +pages. + +

    The ppi=value value is a number from 1 to 1200 specifying the +resolution of the image in pixels per inch. An image that is 3000x2400 +pixels will print 10x8 inches at 300 pixels per inch, for example. If +the specified resolution makes the image larger than the page, multiple +pages will be printed to satisfy the request. + +

    The natural-scaling=percent value is a number +from 1 to 800 specifying the size in relation to the natural +image size. A scaling of 100 percent will print the image at its +natural size, while a scaling of 50 percent will print the image +at half its natural size. If the specified scaling makes the +image larger than the page, multiple pages will be printed to +satisfy the request. + +

    Adjusting the Hue (Tint) of an Image

    + +

    The -o hue=value option will adjust the hue of the +printed image, much like the tint control on your television: + +

      +lp -o hue=value filename ENTER
      +lpr -o hue=value filename ENTER
      +
    + + +

    The value argument is a number from -360 to 360 and represents the +color hue rotation. The following table summarizes the change you'll see with +different colors: + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Originalhue=-45hue=45
    RedPurpleYellow-orange
    GreenYellow-greenBlue-green
    YellowOrangeGreen-yellow
    BlueSky-bluePurple
    MagentaIndigoCrimson
    CyanBlue-greenLight-navy-blue
    + +

    The default hue adjustment is 0. + +

    Adjusting the Saturation (Color) of an Image

    + +

    The -o saturation=percent option adjusts the saturation +of the colors in an image, much like the color knob on your television: + +

      +lp -o saturation=percent filename ENTER
      +lpr -o saturation=percent filename ENTER
      +
    + +

    The percent argument specifies the color saturation +from 0 to 200. A color saturation of 0 produces a black-and-white +print, while a value of 200 will make the colors extremely intense. + +

    The default saturation is 100. + + +

    HP-GL/2 Options

    + +

    The following options apply to HP-GL/2 files. + +

    Printing in Black

    + +

    The -o blackplot option specifies that all pens should +plot in black: + +

      +lp -o blackplot filename ENTER
      +lpr -o blackplot filename ENTER
      +
    + +

    The default is to use the colors defined in the plot file or the +standard pen colors defined in the HP-GL/2 reference manual from +Hewlett Packard. + +

    Fitting the Plot on the Page

    + +

    The -o fitplot option specifies that the plot should be +scaled to fit on the page: + +

      +lp -o fitplot filename ENTER
      +lpr -o fitplot filename ENTER
      +
    + +

    The default is to use the absolute distances specified in the plot +file. + +

    + + + +
    + NOTE: + +

    This feature depends upon an accurate plot size (PS) + command in the HP-GL/2 file. If no plot size is given in the file + than the HP-GL/2 filter assumes the plot is ANSI E size. +

    + +

    Setting the Default Pen Width

    + +

    The -o penwidth=value option specifies the default pen +width for HP-GL/2 files: + +

      +lp -o penwidth=value filename ENTER
      +lpr -o penwidth=value filename ENTER
      +
    + +

    The pen width value specifies the pen width in micrometers. +The default value of 1000 produces lines that are 1 millimeter in width. +Specifying a pen width of 0 produces lines that are exactly 1 pixel wide. + +

    + + + +
    + NOTE: + +

    This option is ignored when the pen widths are set in the + plot file. +

    + +

    Raw or Unfiltered Output

    + +

    The -o raw option allows you to send files directly to +a printer without filtering. This is sometimes required when printing +from applications that provide their own "printer drivers" for your +printer: + +

      +lp -o raw filename ENTER
      +lpr -o raw filename ENTER
      +
    + +

    The -l option can also be used with the +lpr command to send files directly to a printer: + +

      +lpr -l filename ENTER
      +
    + + +

    4 - Saving Printer Options and Defaults

    + +

    This chapter describes how to save printer options for your printer and +set your own default printer. + +

    Printer Options

    + +

    Each printer supports a large number of options, which you learned about +in Chapter 3, "Standard Printer Options". +Rather than specifying these options each time you print a file, CUPS allows +you to save them as "default" options for the printer. + +

    The lpoptions(1) command saves the options for your printers. +Like the lp and lpr commands, it accepts printer +options using the -o argument: + +

      +lpoptions -o prettyprint ENTER
      +lpoptions -o media=A4 -o sides=two-sided-long-edge ENTER
      +lpoptions -o media=Legal -o scaling=100 ENTER
      +
    + +

    Once saved, any lp or lpr command will +use them when you print. + +

    Setting Options for a Specific Printer

    + +

    The previous example shows how to set the options for the default +printer. The -p printer option specifies the options are +for another printer: + +

      +lpoptions -p laserjet -o prettyprint ENTER
      +lpoptions -p laserjet -o media=A4 -o sides=two-sided-long-edge ENTER
      +lpoptions -p deskjet -o media=Legal -o scaling=100 ENTER
      +
    + +

    Removing Options

    + +

    The previous two examples shows how to set options for the default +and a specific printer. Below, shows you how to remove the saved +option using the -r argument: + +

      +lpoptions -r prettyprint ENTER
      +lpoptions -p laserjet -r prettyprint ENTER
      +
    + +

    Viewing the Current Defaults

    + +

    The lpoptions command can also be used to show the current +options by not specifying any new options on the command-line: + +

      +lpoptions ENTER
      +media=A4 sides=two-sided-long-edge
      +lpoptions -p deskjet ENTER
      +media=Legal scaling=100
      +
    + +

    Viewing Options for a Specific Printer

    + +

    You can display the supported options using the lpoptions +command with the -l option, as follows: + +

      +lpoptions -p laserjet -l ENTER
      +
    + +

    Setting the Default Printer

    + +

    The administrator normally will set a system-wide default printer +that is normally used as the default printer by everyone. Use the +-d printer option to set your own default printer: + +

      +lpoptions -d deskjet ENTER
      +
    + +

    The printer can be local (deskjet) or remote +(deskjet@server). + +

    Printer Instances

    + +

    Besides setting options for each print queue, CUPS supports +printer instances which allow you to define several different +sets of options for each printer. You specify a printer instance using +the slash (/) character: + +

      +lpoptions -p laserjet/duplex -o sides=two-sided-long-edge ENTER
      +lpoptions -p laserjet/legal -o media=Legal ENTER
      +
    + +

    The lp and lpr commands also understand +this notation: + +

      +lp -d laserjet/duplex filename ENTER
      +lpr -P laserjet/legal filename ENTER
      +
    + +

    Removing Instances

    + +

    Use the -x printer/instance option to remove a printer +instance that you no longer need: + +

      +lpoptions -x laserjet ENTER
      +lpoptions -x laserjet/duplex ENTER
      +lpoptions -x laserjet/legal ENTER
      +
    + +

    The -x option only removes the default options for that +printer and instance; the original print queue will remain until deleted +with the lpadmin(8) command by the administrator. + + +

    A - Software License +Agreement

    + + + + + diff --git a/doc/svd.html b/doc/svd.html new file mode 100644 index 000000000..d2e8a592b --- /dev/null +++ b/doc/svd.html @@ -0,0 +1,296 @@ + + + +CUPS Software Version Description + + + + + + + +

    +

    CUPS Software Version Description


    +CUPS-SVD-1.2
    +Easy Software Products
    +Copyright 1997-2003, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    1 Scope + +2 References + +3 Additions + +4 Changes + +A Glossary + +
    +

    1 Scope

    +

    1.1 Identification

    + This software version description document provides release information + for the Common UNIX Printing System ("CUPS") Version 1.1. +

    1.2 System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    +

    1.3 Document Overview

    +

    This software version description document is organized into the + following sections:

    + +

    2 References

    +

    2.1 CUPS Documentation

    +

    The following CUPS documentation is referenced by this document:

    +
      +
    • CUPS-CMP-1.2: CUPS Configuration Management Plan
    • +
    • CUPS-IDD-1.2: CUPS System Interface Design Description
    • +
    • CUPS-IPP-1.2: CUPS Implementation of IPP
    • +
    • CUPS-SAM-1.2.x: CUPS Software Administrators Manual
    • +
    • CUPS-SDD-1.2: CUPS Software Design Description
    • +
    • CUPS-SPM-1.2.x: CUPS Software Programming Manual
    • +
    • CUPS-SSR-1.2: CUPS Software Security Report
    • +
    • CUPS-STP-1.2: CUPS Software Test Plan
    • +
    • CUPS-SUM-1.2.x: CUPS Software Users Manual
    • +
    • CUPS-SVD-1.2: CUPS Software Version Description
    • +
    +

    2.2 Other Documents

    +

    The following non-CUPS documents are referenced by this document:

    + +

    3 Additions

    +

    CUPS 1.2 includes many new features from the 1.0.x releases.

    +

    3.1 Filters

    +

    3.1.1 imagetoraster, imagetops +

    +

    The image file filters have been upgraded to support conversion of + Microsoft Bitmap ("BMP") and Alias PIX files.

    +

    3.1.2 pdftops

    +

    A new pdftops filter has been developed that is based on the + excellent Xpdf 0.90 software from Derek B. Noonburg. The new filter is + faster, smaller, and considerably more reliable than the + Ghostscript-based filter in CUPS 1.0.

    +

    3.1.3 pstoraster

    +

    The pstoraster filter has been integrated with GNU + GhostScript 5.50. The new RIP supports most Level 3 PostScript language + features.

    +

    3.1.4 rastertoepson

    +

    The new rastertoepson filter supports EPSON printers + using the ESC/P or ESC/P2 command sets. PPDs are supplied for 9-pin, + 24-pin, Stylus Color, and Stylus Photo printers.

    +

    3.2 User-Defined Printers and Options

    +

    The new lpoptions command allows users to configure + default document options and create additional "instances" of existing + printers, each with unique options.

    +

    The lp, lpr, and lpstat + commands have been upgraded to use this option and printer instance + information automatically.

    +

    3.3 Daemons

    +

    CUPS 1.2 includes two new daemons that provide enhanced network + printing support.

    +

    3.3.1 cups-lpd

    +

    The cups-lpd daemon provides support for clients using + the Line Printer Daemon protocol.

    +

    3.3.2 cups-polld

    +

    The cups-polld daemon provides remote polling services + for the scheduler.

    +

    3.4 Commands

    +

    CUPS 1.2 includes several new printing commands.

    +

    3.4.1 lpoptions

    +

    The lpoptions command provides user-defined printers and + options.

    +

    3.4.2 lpmove

    +

    The lpmove command moves a print job to a new + destination.

    +

    3.4.3 lpinfo

    +

    The lpinfo command lists the available PPD files or + devices.

    +

    3.5 IPP Implementation

    +

    CUPS 1.2 adds support for the set-job-attributes + extension operation as well as two new CUPS-specific extension + operations to determine which devices and printer drivers are available + on the system.

    +

    Further information on the CUPS implementation of IPP can be found in + CUPS-IPP-1.2.

    +

    4 Changes

    +

    CUPS 1.2 includes many changes from the 1.1.x releases.

    +

    4.1 Directory Structure

    +

    The directory structure in CUPS 1.2 has been modified to conform to + the Filesystem Hierarchy Standard, 2.2. The following table describes + the new file locations. +

    + + + + + + + + + + + + + + + + +
    Table 1: Directory structure changes + from CUPS 1.1.x to 1.2.x.
    DescriptionCUPS 1.1.xCUPS 1.2.x
    Backends/var/cups/backend/usr/lib/cups/backend
    CGI programs/var/cups/cgi-bin +/usr/lib/cups/cgi-bin
    Configuration files/var/cups/conf/etc/cups
    Documentation/usr/share/cups/doc +/usr/share/doc/cups
    Filter programs/var/cups/filter +/usr/lib/cups/filter
    Interface scripts/var/cups/interfaces +/etc/cups/interfaces
    Locale data/usr/lib/locale/usr/share/locale
    Log files/var/cups/logs/var/log/cups
    PPD files/var/cups/ppd/etc/cups/ppd
    Request files/var/cups/requests/var/spool/cups
    +
    +

    +

    4.2 IPP Implementation

    +

    CUPS 1.2 is based on version 1.1 of the Internet Printing Protocol.

    +

    The new scheduler supports the create-job and +send-document operations. In addition, the job-sheets +, job-sheets-default, and job-sheets-supported + attributes are now supported for banner pages.

    +

    The CUPS-get-printers and CUPS-get-classes + operations have been upgraded to support limited filtering based upon + the printer-type, printer-location, +printer-info, and printer-make-and-model attributes.

    +

    The CUPS-add-printer operation now supports the +ppd-name attribute to specify a locally-available PPD file rather + than sending the PPD file from the client with the request.

    +

    Further information on the CUPS implementation of IPP can be found in + CUPS-IPP-1.2.

    +

    A Glossary

    +

    A.1 Terms

    +
    +
    C
    +
    A computer language.
    +
    parallel
    +
    Sending or receiving data more than 1 bit at a time.
    +
    pipe
    +
    A one-way communications channel between two programs.
    +
    serial
    +
    Sending or receiving data 1 bit at a time.
    +
    socket
    +
    A two-way network communications channel.
    +
    +

    A.2 Acronyms

    +
    +
    ASCII
    +
    American Standard Code for Information Interchange
    +
    CUPS
    +
    Common UNIX Printing System
    +
    ESC/P
    +
    EPSON Standard Code for Printers
    +
    FTP
    +
    File Transfer Protocol
    +
    HP-GL
    +
    Hewlett-Packard Graphics Language
    +
    HP-PCL
    +
    Hewlett-Packard Page Control Language
    +
    HP-PJL
    +
    Hewlett-Packard Printer Job Language
    +
    IETF
    +
    Internet Engineering Task Force
    +
    IPP
    +
    Internet Printing Protocol
    +
    ISO
    +
    International Standards Organization
    +
    LPD
    +
    Line Printer Daemon
    +
    MIME
    +
    Multimedia Internet Mail Exchange
    +
    PPD
    +
    PostScript Printer Description
    +
    SMB
    +
    Server Message Block
    +
    TFTP
    +
    Trivial File Transfer Protocol
    +
    + + diff --git a/doc/svd.pdf b/doc/svd.pdf new file mode 100644 index 0000000000000000000000000000000000000000..22be31bc6ca26a1753d407b669974cd9c4e009e9 GIT binary patch literal 45647 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 + + + + + CUPS Software Version Description + + + +

    Scope

    + +

    Identification

    + +This software version description document provides release information for the +Common UNIX Printing System ("CUPS") Version 1.1. + + + +

    Document Overview

    + +

    This software version description document is organized into the following +sections:

    + + + + + +

    Additions

    + +

    CUPS 1.2 includes many new features from the 1.0.x releases. + +

    Filters

    + +

    imagetoraster, imagetops

    + +

    The image file filters have been upgraded to support conversion of +Microsoft Bitmap ("BMP") and Alias PIX files. + +

    pdftops

    + +

    A new pdftops filter has been developed that is based on the +excellent Xpdf 0.90 software from Derek B. Noonburg. The new filter is +faster, smaller, and considerably more reliable than the +Ghostscript-based filter in CUPS 1.0. + +

    pstoraster

    + +

    The pstoraster filter has been integrated with GNU +GhostScript 5.50. The new RIP supports most Level 3 PostScript language +features. + +

    rastertoepson

    + +

    The new rastertoepson filter supports EPSON printers +using the ESC/P or ESC/P2 command sets. PPDs are supplied for 9-pin, +24-pin, Stylus Color, and Stylus Photo printers. + +

    User-Defined Printers and Options

    + +

    The new lpoptions command allows users to configure default +document options and create additional "instances" of existing printers, +each with unique options. + +

    The lp, lpr, and lpstat commands +have been upgraded to use this option and printer instance information +automatically. + +

    Daemons

    + +

    CUPS 1.2 includes two new daemons that provide enhanced network printing +support. + +

    cups-lpd

    + +

    The cups-lpd daemon provides support for clients using the +Line Printer Daemon protocol. + +

    cups-polld

    + +

    The cups-polld daemon provides remote polling services for +the scheduler. + +

    Commands

    + +

    CUPS 1.2 includes several new printing commands. + +

    lpoptions

    + +

    The lpoptions command provides user-defined printers and +options. + +

    lpmove

    + +

    The lpmove command moves a print job to a new destination. + +

    lpinfo

    + +

    The lpinfo command lists the available PPD files or devices. + +

    IPP Implementation

    + +

    CUPS 1.2 adds support for the set-job-attributes +extension operation as well as two new CUPS-specific extension +operations to determine which devices and printer drivers are available +on the system. + +

    Further information on the CUPS implementation of IPP can be found +in CUPS-IPP-1.2. + + +

    Changes

    + +

    CUPS 1.2 includes many changes from the 1.1.x releases. + +

    Directory Structure

    + +

    The directory structure in CUPS 1.2 has been modified to conform to the +Filesystem Hierarchy Standard, 2.2. The following table describes the +new file locations. + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Table 1: Directory structure changes from CUPS 1.1.x to 1.2.x.
    DescriptionCUPS 1.1.xCUPS 1.2.x
    Backends/var/cups/backend/usr/lib/cups/backend
    CGI programs/var/cups/cgi-bin/usr/lib/cups/cgi-bin
    Configuration files/var/cups/conf/etc/cups
    Documentation/usr/share/cups/doc/usr/share/doc/cups
    Filter programs/var/cups/filter/usr/lib/cups/filter
    Interface scripts/var/cups/interfaces/etc/cups/interfaces
    Locale data/usr/lib/locale/usr/share/locale
    Log files/var/cups/logs/var/log/cups
    PPD files/var/cups/ppd/etc/cups/ppd
    Request files/var/cups/requests/var/spool/cups
    + +

    IPP Implementation

    + +

    CUPS 1.2 is based on version 1.1 of the Internet Printing Protocol. + +

    The new scheduler supports the create-job and +send-document operations. In addition, the +job-sheets, job-sheets-default, and +job-sheets-supported attributes are now supported for +banner pages. + +

    The CUPS-get-printers and CUPS-get-classes +operations have been upgraded to support limited filtering based upon +the printer-type, printer-location, +printer-info, and printer-make-and-model +attributes. + +

    The CUPS-add-printer operation now supports the +ppd-name attribute to specify a locally-available PPD file +rather than sending the PPD file from the client with the request. + +

    Further information on the CUPS implementation of IPP can be found +in CUPS-IPP-1.2. + + + + + 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 @@ +

    System Overview

    + +

    CUPS provides a portable printing layer for UNIX®-based +operating systems. It has been developed by +Easy Software Products to promote a +standard printing solution for all UNIX vendors and users. CUPS +provides the System V and Berkeley command-line interfaces. + +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for +managing print jobs and queues. The Line Printer Daemon ("LPD") Server +Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are +also supported with reduced functionality. CUPS adds network printer +browsing and PostScript Printer Description ("PPD") based +printing options to support real-world printing under UNIX. + +

    CUPS also includes a customized version of GNU Ghostscript +(currently based off GNU Ghostscript 5.50) and an image file RIP that +are used to support non-PostScript printers. Sample drivers for HP and +EPSON printers are included that use these filters. diff --git a/doc/translation.html b/doc/translation.html new file mode 100644 index 000000000..2718fd170 --- /dev/null +++ b/doc/translation.html @@ -0,0 +1,605 @@ + + + +CUPS Translation Guide + + + + + + + +


    +

    CUPS Translation Guide


    +CUPS-TRANS-1.2
    +Easy Software Products
    +Copyright 2001-2002, All Rights Reserved
    +
    +
    +

    Table of Contents

    +
    +
    1 Scope + +2 References + +3 Character Sets +
    +
    4 Message Catalogs +
    +
    5 Web Interfaces + +A Glossary + +
    +

    1 Scope

    +

    1.1 Identification

    +

    This translation guide provides instructions for creating + translations of the CUPS message catalogs and web pages for the Common + UNIX Printing System ("CUPS") Version 1.2 software.

    +

    1.2 System Overview

    +

    CUPS provides a portable printing layer for UNIX®-based operating + systems. It has been developed by Easy + Software Products to promote a standard printing solution for all + UNIX vendors and users. CUPS provides the System V and Berkeley + command-line interfaces.

    +

    CUPS uses the Internet Printing Protocol ("IPP") as the basis for + managing print jobs and queues. The Line Printer Daemon ("LPD") Server + Message Block ("SMB"), and AppSocket (a.k.a. JetDirect) protocols are + also supported with reduced functionality. CUPS adds network printer + browsing and PostScript Printer Description ("PPD") based printing + options to support real-world printing under UNIX.

    +

    CUPS also includes a customized version of GNU Ghostscript (currently + based off GNU Ghostscript 5.50) and an image file RIP that are used to + support non-PostScript printers. Sample drivers for HP and EPSON + printers are included that use these filters.

    +

    1.3 Document Overview

    +

    This translation guide is organized into the following sections:

    +
      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Character Sets
    • +
    • 4 - Message Catalogs
    • +
    • 5 - Web Interfaces
    • +
    • A - Glossary
    • +
    +

    2 References

    +

    2.1 CUPS Documentation

    +

    The following CUPS documentation is referenced by this document:

    +
      +
    • CUPS-CMP-1.2: CUPS Configuration Management Plan
    • +
    • CUPS-IDD-1.2: CUPS System Interface Design Description
    • +
    • CUPS-IPP-1.2: CUPS Implementation of IPP
    • +
    • CUPS-SAM-1.2.x: CUPS Software Administrators Manual
    • +
    • CUPS-SDD-1.2: CUPS Software Design Description
    • +
    • CUPS-SPM-1.2.x: CUPS Software Programming Manual
    • +
    • CUPS-SSR-1.2: CUPS Software Security Report
    • +
    • CUPS-STP-1.2: CUPS Software Test Plan
    • +
    • CUPS-SUM-1.2.x: CUPS Software Users Manual
    • +
    • CUPS-SVD-1.2: CUPS Software Version Description
    • +
    +

    2.2 Other Documents

    +

    The following non-CUPS documents are referenced by this document:

    + +

    3 Character Sets

    +

    CUPS uses character set files to define the mapping of local + character sets to Unicode code points, as well as the fonts that should + be used for different ranges of characters.

    +

    CUPS includes files for common 8-bit encodings as well as UTF-8 for + Unicode text. The format of these files is described in the CUPS + Interface Design Description (IDD) document. Current character sets are + enumerated in the CUPS API, so in order to add a new character set you + must patch the CUPS source as well as provide a new charset file.

    +

    CUPS 1.2 supports the following character sets:

    +
      +
    • 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
    • +
    • us-ascii
    • +
    • utf-8
    • +
    • windows-874
    • +
    • windows-1250
    • +
    • windows-1251
    • +
    • windows-1252
    • +
    • windows-1253
    • +
    • windows-1254
    • +
    • windows-1255
    • +
    • windows-1256
    • +
    • windows-1257
    • +
    • windows-1258
    • +
    +

    4 Message Catalogs

    +

    CUPS message catalogs are text files that identify the default + character set for the locale and a list of localized message strings + for the CUPS software. The format of the message catalog files is + described in the CUPS IDD.

    +

    Message catalogs are named cups_ll, cups_ll_CC, + or cups_ll_CC.charset, where "ll" is the standard 2-letter + abbreviation for the language, "CC" is the standard 2-letter + abbreviation for the country, and "charset" is the charset name which + may differ from the list above.

    +

    Each message catalog file is stored in a subdirectory named ll +, ll_CC, or ll_CC.charset to match the trailing + portion of the message catalog filename.

    +

    When translating a new message catalog, copy the cups_C + message catalog file to a new subdirectory; to translate the message + catalog to Canadian French, you would type the following commands:

    +
      +
      +cd locale ENTER
      +mkdir fr_CA ENTER
      +cp C/cups_C fr_CA/cups_fr_CA ENTER
      +
      +
    +

    Alternatively, you could copy the existing cups_fr message + catalog and then make any changes necessary.

    +

    Once you have make your copy of the file, edit it using your favorite + text editor to translate the text to the desired language. Be sure to + preserve any numbers starting in the first column, as they indicate a + new message number - you'll see this for the HTTP status messages.

    +

    Finally, add your locale to the list of locales in the makefile and + run the following command to install it:

    +
      +
      +make install ENTER
      +
      +
    +

    5 Web Interfaces

    +

    The CUPS scheduler provides a web interface that can be used to do + many common printing and administration tasks. The built-in web server + supports localization of web pages through the use of subdirectories + for each locale, e.g. "fr" for French, "de" for German, "fr_ca" for + French in Canada, and so forth.

    +

    5.1 Template Files

    +

    Template files are HTML files with special formatting characters in + them that allow substition of variables and arrays. The CUPS CGI + programs (admin.cgi, classes.cgi, +jobs.cgi, and printers.cgi) use these template file + to provide dynamic content for the web interface. Template files are + installed in the /usr/share/cups/templates directory by + default.

    +

    Translated versions of the template files should be installed in the + appropriate subdirectories under /usr/share/cups/templates. + For example, Canadian French template files should be stored in the + /usr/share/cups/templates/fr_CA directory.

    +

    5.1.1 Inserting Attributes and Values

    +

    Template files consist of HTML with variable substitutions for named + inside curley braces "{name}". Variable names are generally the IPP + attribute names with the hyphen ("-") replaced by the underscore ("_") + character. For example, the job-printer-uri attribute is + renamed to job_printer_uri.

    +

    Curley braces ("{" and "}") to indicate substitutions, and the + backslash ("\") character for quoting. To insert any of these special + characters as-is you need to use the HTML &name; mechanism + or prefix each special character with the backslash ("\".)

    +

    You substitute the value of a variable using {NAME} in + your template file. If the variable is undefined then the {NAME} + string is output as-is.

    +

    To substitute an empty string if the variable is undefined, use +{?NAME} instead.

    +

    5.1.2 Array Substitutions

    +

    The number of array elements can be inserted using {#NAME} +. If the array is undefined then 0 is output. The current array element + (starting at 1) is inserted with {#}.

    +

    Arrays are handled using {[NAME] at the beginning of a + section and } at the end. The information between the + closing bracket ("]") and closing brace ("}") is repeated for as many + elements as are in the named array. For example, the following template + will display a list of each job in the job_id array:

    +
      +
      +<TABLE>
      +<TR>
      +	<TH>Job ID</TH>
      +	<TH>Destination</TH>
      +	<TH>Title</TH>
      +</TR>
      +
      +{[job_id]
      +<TR>
      +	<TD>{?job_id}</TD>
      +	<TD>{?job_printer_name}</TD>
      +	<TD>{?job_name}</TD>
      +</TR>
      +}
      +</TABLE>
      +
      +
    +

    Arrays can be nested, however all elements within the curley braces + ("{" and "}") are indexed using the innermost array.

    +

    5.1.3 Conditional Tests

    +

    Templates can also test variables against specific values and + conditionally include text in the template. The format is:

    +
      +
      +{variable?true:false}
      +{variable=value?true:false}
      +{variable!value?true:false}
      +{variable<value?true:false}
      +{variable>value?true:false}
      +
      +
    +

    where true is the text that is included if the condition + is true and false is the text that is included if the + condition is false. A value of # is replaced with the + current element number (starting at 1.)

    +

    The character after the variable name specifies the condition to + test: +

    + + + + + + + +
    CharCondition
    ?True if variable exists.
    =True if variable is equal to value +.
    !True if variable is not equal to value +.
    <True if variable is less than value +.
    >True if variable is greater than value +.
    +
    +

    +

    5.1.4 Template File List

    +

    The following template files are used by the web interface:

    +
    +
    add-class.tmpl
    +
    This is the initial form that is shown to add a new printer class.
    +
    add-printer.tmpl
    +
    This is the initial form that is shown to add a new printer.
    +
    admin-op.tmpl
    +
    This is the template that is used to display an error message when + the admin interface sees an undefined operation name.
    +
    admin.tmpl
    +
    This is the template that shows the initial menu of operations (add + a class, manage classes, etc.)
    +
    choose-device.tmpl
    +
    This is the form that shows the list of available devices.
    +
    choose-make.tmpl
    +
    This is the form that shows the list of available manufacturers.
    +
    choose-members.tmpl
    +
    This is the form that shows the list of available printers that can + be added to a class.
    +
    choose-model.tmpl
    +
    This is the form that shows the list of available printer + models/drivers.
    +
    choose-serial.tmpl
    +
    This is the form that allows the user to choose a serial port and + any options.
    +
    choose-uri.tmpl
    +
    This is the form that allows the user to enter a device URI for + network printers.
    +
    class-added.tmpl
    +
    This template shows the "class added" message.
    +
    class-confirm.tmpl
    +
    This is the template used to confirm the deletion of a class.
    +
    class-deleted.tmpl
    +
    This template shows the "class deleted" message.
    +
    classes.tmpl
    +
    This template shows one or more printer classes.
    +
    class-modified.tmpl
    +
    This template shows the "class modified" message.
    +
    config-printer.tmpl
    +
    This template starts the printer configuration form.
    +
    config-printer2.tmpl
    +
    This template ends the printer configuration form.
    +
    error.tmpl
    +
    This template displays a generic error message.
    +
    header.tmpl
    +
    This template is used as the standard header on all dynamic content.
    +
    job-cancel.tmpl
    +
    This template shows "job cancelled".
    +
    job-hold.tmpl
    +
    This template shows "job held".
    +
    job-op.tmpl
    +
    This is the template that is used to display an error message when + the job interface sees an undefined operation name.
    +
    job-release.tmpl
    +
    This template shows "job released".
    +
    job-restart.tmpl
    +
    This template shows "job restarted".
    +
    jobs.tmpl
    +
    This template is used to list the print jobs on a server, class, or + printer.
    +
    modify-class.tmpl
    +
    This template is used as the first form when modifying a class.
    +
    modify-printer.tmpl
    +
    This template is used as the first form when modifying a printer.
    +
    option-boolean.tmpl
    +
    This template is used to select a boolean PPD option.
    +
    option-header.tmpl
    +
    This template is used to start a PPD option group.
    +
    option-pickmany.tmpl
    +
    This template is used to select a multi-valued PPD option.
    +
    option-pickone.tmpl
    +
    This template is used to select a single-valued PPD option.
    +
    option-trailer.tmpl
    +
    This template is used to end a PPD option group.
    +
    printer-accept.tmpl
    +
    This template shows "printer now accepting jobs".
    +
    printer-added.tmpl
    +
    This template shows "printer added".
    +
    printer-configured.tmpl
    +
    This template shows "printer configured".
    +
    printer-confirm.tmpl
    +
    This template asks the user to confirm the deletion of a printer.
    +
    printer-deleted.tmpl
    +
    This template shows "printer deleted".
    +
    printer-modified.tmpl
    +
    This template shows "printer modified".
    +
    printer-purge.tmpl
    +
    This template shows "printer has been purged of all jobs".
    +
    printer-reject.tmpl
    +
    This template shows "printer now rejecting jobs".
    +
    printer-start.tmpl
    +
    This template shows "printer started".
    +
    printers.tmpl
    +
    This template is used to list information on one or more printers.
    +
    printer-stop.tmpl
    +
    This template shows "printer stopped".
    +
    test-page.tmpl
    +
    This template shows "test page printed".
    +
    trailer.tmpl
    +
    This template is used as the standard trailer on all dynamic + content.
    +
    +

    5.2 CGI Programs

    +

    CUPS uses four CGI programs to manage the dynamic web interfaces:

    +
      +
    • admin.cgi
    • +
    • classes.cgi
    • +
    • jobs.cgi
    • +
    • printers.cgi
    • +
    +

    5.2.1 admin.cgi

    +

    The admin.cgi program handles all of the printer and + class administration functions and is run for all direct accesses to + the /admin resource. For most operations it uses the +PRINTER_NAME and OP form variables to specify the + action requested.

    +

    The following OP values are supported:

    +
    +
    accept-jobs
    +
    Accepts jobs on the named destination.
    +
    add-class
    +
    Adds a new printer class. This operation also adds several other + form variables: +
    +
    MEMBER_URIS
    +
    Sets the members of the class. Multiple MEMBER_URIS + values can be provided.
    +
    PRINTER_INFO
    +
    Sets the printer-info attribute for the printer class, which is + usually the printer description.
    +
    PRINTER_LOCATION
    +
    Sets the printer-location attribute for the printer class.
    +
    +
    +
    add-printer
    +
    Adds a new printer. This operation also adds several other form + variables: +
    +
    BAUDRATE
    +
    Sets the baud rate for serial devices.
    +
    BITS
    +
    Sets the number of data bits for serial devices.
    +
    DEVICE_URI
    +
    Sets the device URI for the printer.
    +
    FLOW
    +
    Sets the flow control for serial devices.
    +
    PARITY
    +
    Sets the parity checking for serial devices.
    +
    PPD_NAME
    +
    Sets the driver name for the printer ("raw" for a raw queue.)
    +
    PRINTER_INFO
    +
    Sets the printer-info attribute for the printer, which is usually + the printer description.
    +
    PRINTER_LOCATION
    +
    Sets the printer-location attribute for the printer.
    +
    +
    +
    config-printer
    +
    Configures an existing printer. This operation uses form variables + of the same name as the options in the printer's PPD file.
    +
    delete-class
    +
    Deletes a printer class. The form variable CONFIRM may + be set to any value to bypass the confirmation page.
    +
    delete-printer
    +
    Deletes a printer. The form variable CONFIRM may be set + to any value to bypass the confirmation page.
    +
    modify-class
    +
    Modifies a printer class. See the add-class operation for a list of + form variables.
    +
    modify-printer
    +
    Modifies a printer. See the add-printer operation for a list of form + variables.
    +
    purge-jobs
    +
    Purges all jobs on the named destination.
    +
    reject-jobs
    +
    Rejects new jobs on the named destination.
    +
    start-printer
    +
    Starts the named destination.
    +
    stop-printer
    +
    Stops the named destination.
    +
    +

    5.2.2 classes.cgi

    +

    The classes.cgi program is responsible for listing class + information, including jobs destined for that class. It is for all + direct accesses to the /classes resource and supports the + optional form variables OP and WHICH_JOBS. If + no form variables are supplied then the CGI lists all or a specific + class and the active jobs on each class.

    +

    The following WHICH_JOBS values are supported:

    +
    +
    completed
    +
    Show only the completed jobs.
    +
    not-completed
    +
    Show only the active jobs.
    +
    +

    The following OP values are supported:

    +
    +
    print-test-page
    +
    Print a PostScript test page.
    +
    +

    5.2.3 jobs.cgi

    +

    The jobs.cgi program handles all of the job functions + and is run for all direct accesses to the /jobs resource. + For most operations it uses the JOB_ID, OP, + and WHICH_JOBS form variables to specify the action + requested.

    +

    The following WHICH_JOBS values are supported:

    +
    +
    completed
    +
    Show only the completed jobs.
    +
    not-completed
    +
    Show only the active jobs.
    +
    +

    The following OP values are supported:

    +
    +
    job-cancel
    +
    Cancels a job.
    +
    job-hold
    +
    Holds a job indefinitely.
    +
    job-release
    +
    Releases a job for printing.
    +
    job-restart
    +
    Restarts a stopped, cancelled, completed, or aborted print job.
    +
    +

    5.2.4 printers.cgi

    +

    The printers.cgi program is responsible for listing + printer information, including jobs destined for that printer. It is + for all direct accesses to the /printers resource and + supports the optional form variables OP and +WHICH_JOBS. If no form variables are supplied then the CGI lists + all or a specific printer and the active jobs on each printer.

    +

    The following WHICH_JOBS values are supported:

    +
    +
    completed
    +
    Show only the completed jobs.
    +
    not-completed
    +
    Show only the active jobs.
    +
    +

    The following OP values are supported:

    +
    +
    print-test-page
    +
    Print a PostScript test page.
    +
    +

    A Glossary

    +

    A.1 Terms

    +
    +
    C
    +
    A computer language.
    +
    parallel
    +
    Sending or receiving data more than 1 bit at a time.
    +
    pipe
    +
    A one-way communications channel between two programs.
    +
    serial
    +
    Sending or receiving data 1 bit at a time.
    +
    socket
    +
    A two-way network communications channel.
    +
    +

    A.2 Acronyms

    +
    +
    ASCII
    +
    American Standard Code for Information Interchange
    +
    CUPS
    +
    Common UNIX Printing System
    +
    ESC/P
    +
    EPSON Standard Code for Printers
    +
    FTP
    +
    File Transfer Protocol
    +
    HP-GL
    +
    Hewlett-Packard Graphics Language
    +
    HP-PCL
    +
    Hewlett-Packard Page Control Language
    +
    HP-PJL
    +
    Hewlett-Packard Printer Job Language
    +
    IETF
    +
    Internet Engineering Task Force
    +
    IPP
    +
    Internet Printing Protocol
    +
    ISO
    +
    International Standards Organization
    +
    LPD
    +
    Line Printer Daemon
    +
    MIME
    +
    Multimedia Internet Mail Exchange
    +
    PPD
    +
    PostScript Printer Description
    +
    SMB
    +
    Server Message Block
    +
    TFTP
    +
    Trivial File Transfer Protocol
    +
    + + diff --git a/doc/translation.pdf b/doc/translation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..75a4fa938c1d03d82142f73bcb5e4263df2c5f89 GIT binary patch literal 50787 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 + + + + + CUPS Translation Guide + + + +

    Scope

    + +

    Identification

    + +

    This translation guide provides instructions for creating +translations of the CUPS message catalogs and web pages for the +Common UNIX Printing System ("CUPS") Version 1.1 software. + + + +

    Document Overview

    + +

    This translation guide is organized into the following +sections: + +

      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - Character Sets
    • +
    • 4 - Message Catalogs
    • +
    • 5 - Web Interfaces
    • +
    • A - Glossary
    • +
    + + + + +

    Character Sets

    + +

    CUPS uses character set files to define the mapping of local +character sets to Unicode code points, as well as the fonts that +should be used for different ranges of characters. + +

    CUPS includes files for common 8-bit encodings as well as +UTF-8 for Unicode text. The format of these files is described +in the CUPS Interface Design Description (IDD) document. +Current character sets are enumerated in the CUPS API, so in +order to add a new character set you must patch the CUPS source +as well as provide a new charset file. + +

    CUPS 1.1 supports the following character sets: + +

      + +
    • 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 +
    • us-ascii +
    • utf-8 +
    • windows-874 +
    • windows-1250 +
    • windows-1251 +
    • windows-1252 +
    • windows-1253 +
    • windows-1254 +
    • windows-1255 +
    • windows-1256 +
    • windows-1257 +
    • windows-1258 + +
    + +

    Message Catalogs

    + +

    CUPS message catalogs are text files that identify the +default character set for the locale and a list of localized +message strings for the CUPS software. The format of the +message catalog files is described in the CUPS IDD. + +

    Message catalogs are named cups_ll, +cups_ll_CC, or cups_ll_CC.charset, where +"ll" is the standard 2-letter abbreviation for the language, +"CC" is the standard 2-letter abbreviation for the country, and +"charset" is the charset name which may differ from the list +above. + +

    Each message catalog file is stored in a subdirectory named +ll, ll_CC, or ll_CC.charset to +match the trailing portion of the message catalog filename. + +

    When translating a new message catalog, copy the cups_C +message catalog file to a new subdirectory; to translate the +message catalog to Canadian French, you would type the following +commands: + +

      +cd locale ENTER
      +mkdir fr_CA ENTER
      +cp C/cups_C fr_CA/cups_fr_CA ENTER
      +
    + +

    Alternatively, you could copy the existing cups_fr +message catalog and then make any changes necessary. + +

    Once you have make your copy of the file, edit it using your +favorite text editor to translate the text to the desired +language. Be sure to preserve any numbers starting in the first +column, as they indicate a new message number - you'll see this +for the HTTP status messages. + +

    Finally, add your locale to the list of locales in the +makefile and run the following command to install it: + +

      +make install ENTER
      +
    + +

    Web Interfaces

    + +

    The CUPS scheduler provides a web interface that can be used +to do many common printing and administration tasks. The built-in +web server supports localization of web pages through the use of +subdirectories for each locale, e.g. "fr" for French, "de" for +German, "fr_ca" for French in Canada, and so forth. + +

    Template Files

    + +

    Template files are HTML files with special formatting +characters in them that allow substition of variables and +arrays. The CUPS CGI programs (admin.cgi, +classes.cgi, jobs.cgi, and +printers.cgi) use these template file to provide +dynamic content for the web interface. Template files are +installed in the /usr/share/cups/templates directory +by default. + +

    Translated versions of the template files should be installed +in the appropriate subdirectories under +/usr/share/cups/templates. For example, Canadian +French template files should be stored in the +/usr/share/cups/templates/fr_CA directory. + +

    Inserting Attributes and Values

    + +

    Template files consist of HTML with variable substitutions +for named inside curley braces "{name}". Variable names are +generally the IPP attribute names with the hyphen ("-") replaced +by the underscore ("_") character. For example, the +job-printer-uri attribute is renamed to +job_printer_uri. + +

    Curley braces ("{" and "}") to indicate substitutions, and +the backslash ("\") character for quoting. To insert any of +these special characters as-is you need to use the HTML +&name; mechanism or prefix each special +character with the backslash ("\".)

    + +

    You substitute the value of a variable using +{NAME} in your template file. If the variable is +undefined then the {NAME} string is output +as-is.

    + +

    To substitute an empty string if the variable is undefined, use +{?NAME} instead.

    + +

    Array Substitutions

    + +

    The number of array elements can be inserted using +{#NAME}. If the array is undefined then 0 is +output. The current array element (starting at 1) is inserted +with {#}.

    + +

    Arrays are handled using {[NAME] at the beginning of a +section and } at the end. The information between the closing +bracket ("]") and closing brace ("}") is repeated for as many elements as +are in the named array. For example, the following template will display +a list of each job in the job_id array:

    + +
      +<TABLE>
      +<TR>
      +	<TH>Job ID</TH>
      +	<TH>Destination</TH>
      +	<TH>Title</TH>
      +</TR>
      +
      +{[job_id]
      +<TR>
      +	<TD>{?job_id}</TD>
      +	<TD>{?job_printer_name}</TD>
      +	<TD>{?job_name}</TD>
      +</TR>
      +}
      +</TABLE>
      +
    + +

    Arrays can be nested, however all elements within the curley +braces ("{" and "}") are indexed using the innermost array.

    + +

    Conditional Tests

    + +

    Templates can also test variables against specific values and +conditionally include text in the template. The format is: + +

      +{variable?true:false}
      +{variable=value?true:false}
      +{variable!value?true:false}
      +{variable<value?true:false}
      +{variable>value?true:false}
      +
    + +

    where true is the text that is included if the +condition is true and false is the text that is +included if the condition is false. A value of # is +replaced with the current element number (starting at 1.) + +

    The character after the variable name specifies the condition +to test: + +

    + + + + + + + + + + + + + + + + + + + + + + + + +
    CharCondition
    ?True if variable exists.
    =True if variable is equal to value.
    !True if variable is not equal to value.
    <True if variable is less than value.
    >True if variable is greater than value.
    + +

    Template File List

    + +

    The following template files are used by the web interface: + +

    + +
    add-class.tmpl + +
    This is the initial form that is shown to add a new + printer class. + +
    add-printer.tmpl + +
    This is the initial form that is shown to add a new + printer. + +
    admin-op.tmpl + +
    This is the template that is used to display an error + message when the admin interface sees an undefined + operation name. + +
    admin.tmpl + +
    This is the template that shows the initial menu of + operations (add a class, manage classes, etc.) + +
    choose-device.tmpl + +
    This is the form that shows the list of available + devices. + +
    choose-make.tmpl + +
    This is the form that shows the list of available + manufacturers. + +
    choose-members.tmpl + +
    This is the form that shows the list of available + printers that can be added to a class. + +
    choose-model.tmpl + +
    This is the form that shows the list of available + printer models/drivers. + +
    choose-serial.tmpl + +
    This is the form that allows the user to choose + a serial port and any options. + +
    choose-uri.tmpl + +
    This is the form that allows the user to enter + a device URI for network printers. + +
    class-added.tmpl + +
    This template shows the "class added" message. + +
    class-confirm.tmpl + +
    This is the template used to confirm the + deletion of a class. + +
    class-deleted.tmpl + +
    This template shows the "class deleted" message. + +
    classes.tmpl + +
    This template shows one or more printer classes. + +
    class-modified.tmpl + +
    This template shows the "class modified" message. + +
    config-printer.tmpl + +
    This template starts the printer configuration form. + +
    config-printer2.tmpl + +
    This template ends the printer configuration form. + +
    error.tmpl + +
    This template displays a generic error message. + +
    header.tmpl + +
    This template is used as the standard header on all dynamic + content. + +
    job-cancel.tmpl + +
    This template shows "job cancelled". + +
    job-hold.tmpl + +
    This template shows "job held". + +
    job-op.tmpl + +
    This is the template that is used to display an + error message when the job interface sees an undefined + operation name. + +
    job-release.tmpl + +
    This template shows "job released". + +
    job-restart.tmpl + +
    This template shows "job restarted". + +
    jobs.tmpl + +
    This template is used to list the print jobs on a server, + class, or printer. + +
    modify-class.tmpl + +
    This template is used as the first form when modifying a + class. + +
    modify-printer.tmpl + +
    This template is used as the first form when modifying a + printer. + +
    option-boolean.tmpl + +
    This template is used to select a boolean PPD option. + +
    option-header.tmpl + +
    This template is used to start a PPD option group. + +
    option-pickmany.tmpl + +
    This template is used to select a multi-valued PPD option. + +
    option-pickone.tmpl + +
    This template is used to select a single-valued PPD option. + +
    option-trailer.tmpl + +
    This template is used to end a PPD option group. + +
    printer-accept.tmpl + +
    This template shows "printer now accepting jobs". + +
    printer-added.tmpl + +
    This template shows "printer added". + +
    printer-configured.tmpl + +
    This template shows "printer configured". + +
    printer-confirm.tmpl + +
    This template asks the user to confirm the deletion of a printer. + +
    printer-deleted.tmpl + +
    This template shows "printer deleted". + +
    printer-modified.tmpl + +
    This template shows "printer modified". + +
    printer-purge.tmpl + +
    This template shows "printer has been purged of all jobs". + +
    printer-reject.tmpl + +
    This template shows "printer now rejecting jobs". + +
    printer-start.tmpl + +
    This template shows "printer started". + +
    printers.tmpl + +
    This template is used to list information on one or more + printers. + +
    printer-stop.tmpl + +
    This template shows "printer stopped". + +
    test-page.tmpl + +
    This template shows "test page printed". + +
    trailer.tmpl + +
    This template is used as the standard trailer on all dynamic + content. + +
    + +

    CGI Programs

    + +

    CUPS uses four CGI programs to manage the dynamic web interfaces: + +

      + +
    • admin.cgi
    • +
    • classes.cgi
    • +
    • jobs.cgi
    • +
    • printers.cgi
    • + +
    + +

    admin.cgi

    + +

    The admin.cgi program handles all of the printer +and class administration functions and is run for all direct +accesses to the /admin resource. For most operations it uses the +PRINTER_NAME and OP form variables to +specify the action requested. + +

    The following OP values are supported: + +

    + +
    accept-jobs
    + +
    Accepts jobs on the named destination.
    + +
    add-class
    + +
    Adds a new printer class. This operation also adds + several other form variables: + +
    + +
    MEMBER_URIS
    + +
    Sets the members of the class. Multiple + MEMBER_URIS values can be + provided.
    + +
    PRINTER_INFO
    + +
    Sets the printer-info attribute for the + printer class, which is usually the printer + description.
    + +
    PRINTER_LOCATION
    + +
    Sets the printer-location attribute for the + printer class.
    + +
    + +
    + +
    add-printer
    + +
    Adds a new printer. This operation also adds several other + form variables: + +
    + +
    BAUDRATE
    + +
    Sets the baud rate for serial devices.
    + +
    BITS
    + +
    Sets the number of data bits for serial devices.
    + +
    DEVICE_URI
    + +
    Sets the device URI for the printer.
    + +
    FLOW
    + +
    Sets the flow control for serial devices.
    + +
    PARITY
    + +
    Sets the parity checking for serial devices.
    + +
    PPD_NAME
    + +
    Sets the driver name for the printer ("raw" for a + raw queue.)
    + +
    PRINTER_INFO
    + +
    Sets the printer-info attribute for the + printer, which is usually the printer + description.
    + +
    PRINTER_LOCATION
    + +
    Sets the printer-location attribute for the + printer.
    + +
    + +
    + +
    config-printer
    + +
    Configures an existing printer. This operation uses + form variables of the same name as the options in the + printer's PPD file.
    + +
    delete-class
    + +
    Deletes a printer class. The form variable CONFIRM + may be set to any value to bypass the confirmation page.
    + +
    delete-printer
    + +
    Deletes a printer. The form variable CONFIRM + may be set to any value to bypass the confirmation page.
    + +
    modify-class
    + +
    Modifies a printer class. See the add-class operation for a + list of form variables.
    + +
    modify-printer
    + +
    Modifies a printer. See the add-printer operation for a + list of form variables.
    + +
    purge-jobs
    + +
    Purges all jobs on the named destination.
    + +
    reject-jobs
    + +
    Rejects new jobs on the named destination.
    + +
    start-printer
    + +
    Starts the named destination.
    + +
    stop-printer
    + +
    Stops the named destination.
    + +
    + + +

    classes.cgi

    + +

    The classes.cgi program is responsible for +listing class information, including jobs destined for that +class. It is for all direct accesses to the /classes resource +and supports the optional form variables OP and +WHICH_JOBS. If no form variables are supplied then +the CGI lists all or a specific class and the active jobs on +each class. + +

    The following WHICH_JOBS values are supported: + +

    + +
    completed
    + +
    Show only the completed jobs.
    + +
    not-completed
    + +
    Show only the active jobs.
    + +
    + +

    The following OP values are supported: + +

    + +
    print-test-page
    + +
    Print a PostScript test page.
    + +
    + +

    jobs.cgi

    + +

    The jobs.cgi program handles all of the job +functions and is run for all direct accesses to the /jobs +resource. For most operations it uses the +JOB_ID, OP, and +WHICH_JOBS form variables to specify the action +requested. + +

    The following WHICH_JOBS values are supported: + +

    + +
    completed
    + +
    Show only the completed jobs.
    + +
    not-completed
    + +
    Show only the active jobs.
    + +
    + +

    The following OP values are supported: + +

    + +
    job-cancel
    + +
    Cancels a job.
    + +
    job-hold
    + +
    Holds a job indefinitely.
    + +
    job-release
    + +
    Releases a job for printing.
    + +
    job-restart
    + +
    Restarts a stopped, cancelled, completed, or aborted + print job.
    + +
    + +

    printers.cgi

    + +

    The printers.cgi program is responsible for +listing printer information, including jobs destined for that +printer. It is for all direct accesses to the /printers resource +and supports the optional form variables OP and +WHICH_JOBS. If no form variables are supplied then +the CGI lists all or a specific printer and the active jobs on +each printer. + +

    The following WHICH_JOBS values are supported: + +

    + +
    completed
    + +
    Show only the completed jobs.
    + +
    not-completed
    + +
    Show only the active jobs.
    + +
    + +

    The following OP values are supported: + +

    + +
    print-test-page
    + +
    Print a PostScript test page.
    + +
    + + + + + + diff --git a/filter/Dependencies b/filter/Dependencies new file mode 100644 index 000000000..c68bdd6dd --- /dev/null +++ b/filter/Dependencies @@ -0,0 +1,119 @@ +# DO NOT DELETE + +hpgl-attr.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +hpgl-attr.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +hpgl-attr.o: ../cups/array.h ../cups/string.h ../config.h +hpgl-config.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h +hpgl-config.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h +hpgl-config.o: ../cups/language.h ../cups/array.h ../cups/string.h +hpgl-config.o: ../config.h +hpgl-main.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +hpgl-main.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +hpgl-main.o: ../cups/array.h ../cups/string.h ../config.h +hpgl-prolog.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h +hpgl-prolog.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h +hpgl-prolog.o: ../cups/language.h ../cups/array.h ../cups/string.h +hpgl-prolog.o: ../config.h +hpgl-char.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +hpgl-char.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +hpgl-char.o: ../cups/array.h ../cups/string.h ../config.h +hpgl-input.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +hpgl-input.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +hpgl-input.o: ../cups/array.h ../cups/string.h ../config.h +hpgl-polygon.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h +hpgl-polygon.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h +hpgl-polygon.o: ../cups/language.h ../cups/array.h ../cups/string.h +hpgl-polygon.o: ../config.h +hpgl-vector.o: hpgltops.h common.h ../cups/cups.h ../cups/ipp.h +hpgl-vector.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h +hpgl-vector.o: ../cups/language.h ../cups/array.h ../cups/string.h +hpgl-vector.o: ../config.h +image-bmp.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-bmp.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-bmp.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-colorspace.o: image-private.h image.h raster.h ../cups/ppd.h +image-colorspace.o: ../cups/file.h ../cups/cups.h ../cups/ipp.h +image-colorspace.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h +image-colorspace.o: ../cups/debug.h ../cups/string.h ../config.h +image-gif.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-gif.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-gif.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-jpeg.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-jpeg.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-jpeg.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-photocd.o: image-private.h image.h raster.h ../cups/ppd.h +image-photocd.o: ../cups/file.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +image-photocd.o: ../cups/md5.h ../cups/ppd.h ../cups/debug.h ../cups/string.h +image-photocd.o: ../config.h +image-pix.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-pix.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-pix.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-png.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-png.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-png.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-pnm.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-pnm.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-pnm.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-sgi.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-sgi.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-sgi.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-sgi.o: image-sgi.h +image-sgilib.o: image-sgi.h +image-sun.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-sun.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-sun.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-tiff.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-tiff.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-tiff.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image-zoom.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image-zoom.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image-zoom.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +image.o: image-private.h image.h raster.h ../cups/ppd.h ../cups/file.h +image.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +image.o: ../cups/ppd.h ../cups/debug.h ../cups/string.h ../config.h +interpret.o: ../cups/ppd.h ../cups/file.h ../cups/string.h ../config.h +interpret.o: raster.h +raster.o: raster.h ../cups/ppd.h ../cups/file.h ../cups/string.h ../config.h +form-main.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +form-main.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +form-main.o: ../cups/array.h ../cups/string.h ../config.h +form-ps.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +form-ps.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +form-ps.o: ../cups/array.h ../cups/string.h ../config.h +form-tree.o: form.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +form-tree.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +form-tree.o: ../cups/array.h ../cups/string.h ../config.h +imagetops.o: common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +imagetops.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +imagetops.o: ../cups/array.h ../cups/string.h ../config.h image.h raster.h +imagetops.o: ../cups/ppd.h +imagetoraster.o: common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +imagetoraster.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h +imagetoraster.o: ../cups/language.h ../cups/array.h ../cups/string.h +imagetoraster.o: ../config.h image-private.h image.h raster.h ../cups/ppd.h +imagetoraster.o: ../cups/debug.h +common.o: common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +common.o: ../cups/ppd.h ../cups/file.h ../cups/language.h ../cups/array.h +common.o: ../cups/string.h ../config.h +pstops.o: common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +pstops.o: ../cups/ppd.h ../cups/file.h ../cups/language.h ../cups/array.h +pstops.o: ../cups/string.h ../config.h +raster.o: raster.h ../cups/ppd.h ../cups/file.h ../cups/string.h ../config.h +rastertolabel.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +rastertolabel.o: ../cups/ppd.h ../cups/file.h ../cups/string.h ../config.h +rastertolabel.o: raster.h ../cups/ppd.h +rastertoepson.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +rastertoepson.o: ../cups/ppd.h ../cups/file.h ../cups/ppd.h ../cups/string.h +rastertoepson.o: ../config.h raster.h +rastertohp.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +rastertohp.o: ../cups/ppd.h ../cups/file.h ../cups/string.h ../config.h +rastertohp.o: raster.h ../cups/ppd.h +texttops.o: textcommon.h common.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +texttops.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/language.h +texttops.o: ../cups/array.h ../cups/string.h ../config.h +textcommon.o: textcommon.h common.h ../cups/cups.h ../cups/ipp.h +textcommon.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/file.h +textcommon.o: ../cups/language.h ../cups/array.h ../cups/string.h ../config.h +testraster.o: raster.h ../cups/ppd.h ../cups/file.h ../cups/string.h +testraster.o: ../config.h +gziptoany.o: ../cups/string.h ../config.h diff --git a/filter/Makefile b/filter/Makefile new file mode 100644 index 000000000..9defb35b7 --- /dev/null +++ b/filter/Makefile @@ -0,0 +1,285 @@ +# +# "$Id: Makefile 4804 2005-10-20 14:05:42Z mike $" +# +# Filter makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# +# This file is subject to the Apple OS-Developed Software exception. +# + +include ../Makedefs + +FILTERS = gziptoany hpgltops texttops pstops imagetops imagetoraster \ + rastertolabel rastertoepson rastertohp +TARGETS = $(FILTERS) testraster + +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 interpret.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 \ + rastertolabel.o rastertoepson.o rastertohp.o \ + texttops.o textcommon.o testraster.o gziptoany.o + + +# +# Make all targets... +# + +all: $(TARGETS) $(LIBCUPSIMAGE) libcupsimage.a + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) $(LIBCUPSIMAGE) libcupsimage.a + $(RM) `basename $(LIBCUPSIMAGE) .2` libcupsimage.dylib + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1 + + +# +# Install all targets... +# + +install: all installhdrs + $(INSTALL_DIR) $(SERVERBIN)/filter + for file in $(FILTERS); do \ + $(INSTALL_BIN) $$file $(SERVERBIN)/filter; \ + done + $(RM) $(SERVERBIN)/filter/rastertodymo + $(LN) rastertolabel $(SERVERBIN)/filter/rastertodymo + $(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 \ + $(STRIP) -x $(LIBDIR)/$(LIBCUPSIMAGE); \ + $(RM) $(LIBDIR)/libcupsimage.dylib; \ + $(LN) $(LIBCUPSIMAGE) $(LIBDIR)/libcupsimage.dylib; \ + fi + -if test $(LIBCUPSIMAGE) != "libcupsimage.a"; then \ + $(INSTALL_LIB) libcupsimage.a $(LIBDIR); \ + $(RANLIB) $(LIBDIR)/libcupsimage.a; \ + fi + +installhdrs: + $(INSTALL_DIR) $(INCLUDEDIR)/cups + $(INSTALL_DATA) image.h $(INCLUDEDIR)/cups + $(INSTALL_DATA) raster.h $(INCLUDEDIR)/cups + + +# +# formtops +# + +formtops: $(FORMOBJS) common.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ $(FORMOBJS) common.o $(LIBS) -lm + + +# +# gziptoany +# + +gziptoany: gziptoany.o ../Makedefs ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ gziptoany.o $(LIBZ) $(LIBS) + + +# +# hpgltops +# + +hpgltops: $(HPGLOBJS) common.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ $(HPGLOBJS) common.o $(LIBS) -lm + + +# +# libcupsimage.so.2, libcupsimage.sl.2 +# + +libcupsimage.so.2 libcupsimage.sl.2: $(IMAGEOBJS) + echo Linking $@... + $(DSO) $(DSOFLAGS) -o $@ $(IMAGEOBJS) $(DSOLIBS) -lm + $(RM) `basename $@ .2` + $(LN) $@ `basename $@ .2` + + +# +# libcupsimage.2.dylib +# + +libcupsimage.2.dylib: $(IMAGEOBJS) + echo Linking $@... + $(DSO) $(DSOFLAGS) -o $@ \ + -install_name $(libdir)/libcupsimage.dylib \ + -current_version 2.2.0 \ + -compatibility_version 2.0.0 \ + $(IMAGEOBJS) $(DSOLIBS) -L../cups $(LINKCUPS) -lm + $(RM) libcupsimage.dylib + $(LN) $@ libcupsimage.dylib + + +# +# libcupsimage_s.a +# + +libcupsimage_s.a: $(IMAGEOBJS) + echo Linking $@... + $(DSO) $(DSOFLAGS) -Wl,-berok -o libcupsimage_s.o $(IMAGEOBJS) \ + $(DSOLIBS) -lm + $(RM) $@ + $(AR) $(ARFLAGS) $@ libcupsimage_s.o + + +# +# libcupsimage.la +# + +libcupsimage.la: $(IMAGEOBJS) + echo Linking $@... + $(DSO) $(DSOFLAGS) -o $@ $(IMAGEOBJS:.o=.lo) $(DSOLIBS) \ + -rpath $(LIBDIR) -version-info 2:2 + + +# +# libcupsimage.a +# + +libcupsimage.a: $(IMAGEOBJS) + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(IMAGEOBJS) + $(RANLIB) $@ + + +# +# testimage +# + +testimage: testimage.o libcupsimage.a ../Makedefs + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testimage.o libcupsimage.a \ + $(IMGLIBS) $(DSOLIBS) $(LIBS) + + +# +# imagetops +# + +imagetops: imagetops.o common.o $(LIBCUPSIMAGE) \ + ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ imagetops.o common.o $(LINKCUPSIMAGE) \ + $(IMGLIBS) $(LIBS) + + +# +# imagetoraster +# + +imagetoraster: imagetoraster.o common.o $(LIBCUPSIMAGE) \ + ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ imagetoraster.o common.o $(LINKCUPSIMAGE) \ + $(IMGLIBS) $(LIBS) + + +# +# pstops +# + +pstops: pstops.o common.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ pstops.o common.o $(LIBS) + + +# +# rastertolabel +# + +rastertolabel: rastertolabel.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ rastertolabel.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) + + +# +# rastertoepson +# + +rastertoepson: rastertoepson.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ rastertoepson.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) + + +# +# rastertohp +# + +rastertohp: rastertohp.o ../cups/$(LIBCUPS) $(LIBCUPSIMAGE) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ rastertohp.o $(LINKCUPSIMAGE) $(IMGLIBS) $(LIBS) + + +# +# testraster +# + +testraster: testraster.o raster.o + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testraster.o raster.o + + +# +# texttops +# + +texttops: texttops.o textcommon.o common.o \ + ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ texttops.o textcommon.o common.o $(LIBS) + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4804 2005-10-20 14:05:42Z mike $". +# diff --git a/filter/common.c b/filter/common.c new file mode 100644 index 000000000..9e3c391e0 --- /dev/null +++ b/filter/common.c @@ -0,0 +1,471 @@ +/* + * "$Id: common.c 4494 2005-02-18 02:18:11Z mike $" + * + * Common filter routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * SetCommonOptions() - Set common filter options for media size, + * etc. + * UpdatePageVars() - Update the page variables for the orientation. + * WriteCommon() - Write common procedures... + * WriteLabelProlog() - Write the prolog with the classification + * and page label. + * WriteLabels() - Write the actual page labels. + */ + +/* + * Include necessary headers... + */ + +#include "common.h" +#include + + +/* + * 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 */ + + +#ifdef LC_TIME + setlocale(LC_TIME, ""); +#endif /* LC_TIME */ + + 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) + { + if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 && + strcasecmp(val, "false") != 0) + { + if (ppd && ppd->landscape > 0) + Orientation = 1; + else + Orientation = 3; + } + } + else 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 (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "Duplex", "DuplexTumble") || + ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") || + ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") || + ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "KD03Duplex", "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; + } +} + + +/* + * 'WriteCommon()' - Write common procedures... + */ + +void +WriteCommon(void) +{ + puts("% x y w h ESPrc - Clip to a rectangle.\n" + "userdict/ESPrc/rectclip where{pop/rectclip load}\n" + "{{newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" + "neg 0 rlineto closepath clip newpath}bind}ifelse put"); + puts("% x y w h ESPrf - Fill a rectangle.\n" + "userdict/ESPrf/rectfill where{pop/rectfill load}\n" + "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" + "neg 0 rlineto closepath fill grestore}bind}ifelse put"); + puts("% x y w h ESPrs - Stroke a rectangle.\n" + "userdict/ESPrs/rectstroke where{pop/rectstroke load}\n" + "{{gsave newpath 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto\n" + "neg 0 rlineto closepath stroke grestore}bind}ifelse put"); +} + + +/* + * '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 */ + const char *ptr; /* Temporary string pointer */ + + + /* + * 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("userdict/ESPwl{}bind put"); + return; + } + + /* + * Set the classification + page label string... + */ + + printf("userdict"); + 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("); + + for (ptr = classification; *ptr; ptr ++) + if (*ptr < 32 || *ptr > 126) + printf("\\%03o", *ptr); + else if (*ptr == '_') + putchar(' '); + else + { + if (*ptr == '(' || *ptr == ')' || *ptr == '\\') + putchar('\\'); + + putchar(*ptr); + } + } + + if (label) + { + if (classification[0]) + printf(" - "); + + /* + * Quote the label string as needed... + */ + + for (ptr = label; *ptr; ptr ++) + if (*ptr < 32 || *ptr > 126) + printf("\\%03o", *ptr); + else + { + if (*ptr == '(' || *ptr == ')' || *ptr == '\\') + putchar('\\'); + + putchar(*ptr); + } + } + + puts(")put"); + + /* + * Then get a 14 point Helvetica-Bold font... + */ + + puts("userdict/ESPpf /Helvetica-Bold findfont 14 scalefont put"); + + /* + * Finally, the procedure to write the labels on the page... + */ + + puts("userdict/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 ESPrf\n", bottom - 2.0); + printf(" dup 6 sub %.0f 3 index 20 ESPrf\n", top - 18.0); + puts(" 0 setgray"); + printf(" dup 6 sub %.0f 3 index 20 ESPrs\n", bottom - 2.0); + printf(" dup 6 sub %.0f 3 index 20 ESPrs\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 put"); +} + + +/* + * '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: common.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/common.h b/filter/common.h new file mode 100644 index 000000000..1c40b4765 --- /dev/null +++ b/filter/common.h @@ -0,0 +1,92 @@ +/* + * "$Id: common.h 4493 2005-02-18 02:09:53Z mike $" + * + * Common filter definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/* + * C++ magic... + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* + * 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 WriteCommon(void); +extern void WriteLabelProlog(const char *label, float bottom, + float top, float width); +extern void WriteLabels(int orient); + + +/* + * C++ magic... + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +/* + * End of "$Id: common.h 4493 2005-02-18 02:09:53Z mike $". + */ diff --git a/filter/form-main.c b/filter/form-main.c new file mode 100644 index 000000000..a7b95cc45 --- /dev/null +++ b/filter/form-main.c @@ -0,0 +1,62 @@ +/* + * "$Id: form-main.c 4494 2005-02-18 02:18:11Z mike $" + * + * CUPS form main entry for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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: form-main.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/form-ps.c b/filter/form-ps.c new file mode 100644 index 000000000..890100aa4 --- /dev/null +++ b/filter/form-ps.c @@ -0,0 +1,49 @@ +/* + * "$Id: form-ps.c 4494 2005-02-18 02:18:11Z mike $" + * + * CUPS form PostScript routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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: form-ps.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/form-tree.c b/filter/form-tree.c new file mode 100644 index 000000000..188a254b1 --- /dev/null +++ b/filter/form-tree.c @@ -0,0 +1,624 @@ +/* + * "$Id: form-tree.c 4494 2005-02-18 02:18:11Z mike $" + * + * CUPS form document tree routines for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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 & 255)) + { + 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 & 255)) + 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 & 255) && ch != '<' && ch != EOF && ptr < (s + sizeof(s) - 1)) + { + if (ch == '&') + { + for (glyphptr = glyph; + (ch = getc(fp)) != EOF && (glyphptr - glyph) < 15; + glyphptr ++) + if (!isalnum(ch & 255)) + 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 & 255)) + *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 & 255)) + { + if (ptr < (name + sizeof(name) - 1)) + *ptr++ = ch; + } + else + break; + + *ptr = '\0'; + + while (isspace(ch & 255) || 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 & 255) || 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 & 255) || 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 & 255)) + 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 & 255)) + { + ungetc(ch, fp); + parse_variable(t, fp); + } + + ch = getc(fp); + } + + if (ch != EOF) + ungetc(ch, fp); + } + + return (t->element); +} + + +/* + * End of "$Id: form-tree.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/form.h b/filter/form.h new file mode 100644 index 000000000..39d7b7549 --- /dev/null +++ b/filter/form.h @@ -0,0 +1,177 @@ +/* + * "$Id: form.h 4494 2005-02-18 02:18:11Z mike $" + * + * CUPS form header file for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +/* + * 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: form.h 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/gziptoany.c b/filter/gziptoany.c new file mode 100644 index 000000000..b83082fb4 --- /dev/null +++ b/filter/gziptoany.c @@ -0,0 +1,131 @@ +/* + * "$Id: gziptoany.c 4494 2005-02-18 02:18:11Z mike $" + * + * GZIP pre-filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Uncompress gzip'd files and send them to stdout... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + +#ifdef HAVE_LIBZ +# include +#endif /* HAVE_LIBZ */ + + +/* + * 'main()' - Uncompress gzip'd files and send them to stdout... + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ +#ifdef HAVE_LIBZ + gzFile fp; /* GZIP'd file */ + char buffer[8192]; /* Data buffer */ + int bytes; /* Number of bytes read/written */ + int copies; /* Number of copies */ + const char *content_type; /* Content type for file... */ + + + /* + * Check command-line... + */ + + if (argc != 7) + { + fputs("ERROR: gziptoany job-id user title copies options file\n", stderr); + return (1); + } + + /* + * Get the copy count; if the MIME type is "application/vnd.cups-raw" then + * make copies since the file is going straight to a backend... + */ + + if ((content_type = getenv("CONTENT_TYPE")) != NULL && + !strcasecmp(content_type, "application/vnd.cups-raw")) + copies = atoi(argv[4]); + else + copies = 1; + + /* + * Open the gzip file... + */ + + if ((fp = gzopen(argv[6], "rb")) == NULL) + { + fprintf(stderr, "ERROR: Unable to open GZIP file: %s\n", strerror(errno)); + return (1); + } + + /* + * Copy the gzip file to stdout... + */ + + setbuf(stdout, NULL); + + while (copies > 0) + { + gzrewind(fp); + + while ((bytes = gzread(fp, buffer, sizeof(buffer))) > 0) + if (fwrite(buffer, 1, bytes, stdout) < bytes) + { + fprintf(stderr, "ERROR: Unable to write uncompressed document data: %s\n", + strerror(ferror(stdout))); + gzclose(fp); + + return (1); + } + + copies --; + } + + /* + * Close the file and return... + */ + + gzclose(fp); + + return (0); +#else + fputs("INFO: Hint: recompile CUPS with ZLIB.\n", stderr); + fputs("ERROR: GZIP compression support not compiled in!\n", stderr); + return (1); +#endif /* HAVE_LIBZ */ +} + + +/* + * End of "$Id: gziptoany.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/hpgl-attr.c b/filter/hpgl-attr.c new file mode 100644 index 000000000..5a645c1cb --- /dev/null +++ b/filter/hpgl-attr.c @@ -0,0 +1,454 @@ +/* + * "$Id: hpgl-attr.c 4494 2005-02-18 02:18:11Z mike $" + * + * HP-GL/2 attribute processing for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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: hpgl-attr.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/hpgl-char.c b/filter/hpgl-char.c new file mode 100644 index 000000000..3b1f9d3d7 --- /dev/null +++ b/filter/hpgl-char.c @@ -0,0 +1,640 @@ +/* + * "$Id: hpgl-char.c 4494 2005-02-18 02:18:11Z mike $" + * + * HP-GL/2 character processing for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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" + + +/* + * 'define_font()' - Define the specified font... + */ + +void +define_font(int f) /* I - Font number */ +{ + font_t *font; /* Font */ + const char *fstring; /* Font string - SA or SS */ + float xform[2][2]; /* Transform matrix */ + + + /* + * Get the correct font data... + */ + + if (f) + { + font = &AlternateFont; + fstring = "SA"; + } + else + { + font = &StandardFont; + fstring = "SS"; + } + + /* + * Compute the font matrix, accounting for any rotation... + */ + + switch (Rotation) + { + default : + case 0 : + xform[0][0] = font->xpitch * font->x * font->height; + xform[0][1] = font->xpitch * font->y * font->height; + xform[1][0] = -font->y * font->height; + xform[1][1] = font->x * font->height; + break; + + case 90 : + xform[0][0] = -font->xpitch * font->y * font->height; + xform[0][1] = font->xpitch * font->x * font->height; + xform[1][0] = -font->x * font->height; + xform[1][1] = -font->y * font->height; + break; + + case 180 : + xform[0][0] = -font->xpitch * font->x * font->height; + xform[0][1] = -font->xpitch * font->y * font->height; + xform[1][0] = font->y * font->height; + xform[1][1] = -font->x * font->height; + break; + + case 270 : + xform[0][0] = font->xpitch * font->y * font->height; + xform[0][1] = -font->xpitch * font->x * font->height; + xform[1][0] = font->x * font->height; + xform[1][1] = font->y * font->height; + break; + } + + /* + * Send the font definition... + */ + + printf("/%s {\n" + " /%s%s%s%s findfont\n" + " [ %f %f %f %f 0.0 0.0 ] makefont\n" + " setfont\n" + "} bind def\n", + fstring, font->spacing ? "Helvetica" : "Courier", + (font->weight > 0 || font->posture) ? "-" : "", + font->weight > 0 ? "Bold" : "", + font->posture ? "Oblique" : "", + xform[0][0], xform[0][1], xform[1][0], xform[1][1]); + + if (f == CharFont) + printf("%s\n", fstring); +} + + +/* + * '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.symbol_set = 277; + AlternateFont.spacing = 0; + AlternateFont.pitch = 9; + AlternateFont.height = 11.5; + AlternateFont.posture = 0; + AlternateFont.weight = 0; + AlternateFont.typeface = 48; + AlternateFont.x = 1.0; + AlternateFont.y = 0.0; + + /* + * Loop through parameter value pairs... + */ + + for (i = 0; i < (num_params - 1); i += 2) + switch ((int)params[i].value.number) + { + case 1 : /* Symbol Set */ + AlternateFont.symbol_set = (int)params[i + 1].value.number; + break; + case 2 : /* Font Spacing */ + AlternateFont.spacing = (int)params[i + 1].value.number; + break; + case 3 : /* Pitch */ + AlternateFont.pitch = params[i + 1].value.number; + break; + case 4 : /* Height */ + AlternateFont.height = params[i + 1].value.number; + break; + case 5 : /* Posture */ + AlternateFont.posture = (int)params[i + 1].value.number; + break; + case 6 : /* Stroke Weight */ + AlternateFont.weight = (int)params[i + 1].value.number; + break; + case 7 : /* Typeface */ + AlternateFont.typeface = (int)params[i + 1].value.number; + break; + } + + if (AlternateFont.spacing) + { + /* + * Set proportional spacing font... + */ + + AlternateFont.xpitch = 1.0f; + } + else + { + /* + * Set fixed-spaced font... + */ + + AlternateFont.xpitch = 0.6f * AlternateFont.height / AlternateFont.pitch; + } + + /* + * Define the font... + */ + + if (PageDirty) + { + printf("%% AD"); + for (i = 0; i < num_params; i ++) + if (i) + printf(",%g", params[i].value.number); + else + printf("%g", params[i].value.number); + puts(";"); + + define_font(1); + } + + 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 (num_params != 2) + return; + + if (CharFont) + { + AlternateFont.x = params[0].value.number; + AlternateFont.y = params[1].value.number; + } + else + { + StandardFont.x = params[0].value.number; + StandardFont.y = params[1].value.number; + } + + if (PageDirty) + { + printf("%% DI%g,%g\n", params[0].value.number, params[1].value.number); + + define_font(CharFont); + } +} + + +/* + * 'DR_relative_direction()' - Set the relative direction vector for text. + */ + +void +DR_relative_direction(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'DT_define_label_term()' - Set the label string terminator. + */ + +void +DT_define_label_term(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + if (num_params == 0) + StringTerminator = '\003'; + else + StringTerminator = params[0].value.string[0]; +} + + +/* + * 'DV_define_variable_path()' - Define a path for text. + */ + +void +DV_define_variable_path(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'ES_extra_space()' - Set extra spacing (kerning) between characters. + */ + +void +ES_extra_space(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + (void)num_params; + (void)params; +} + + +/* + * 'LB_label()' - Display a label string. + */ + +void +LB_label(int num_params, /* I - Number of parameters */ + param_t *params) /* I - Parameters */ +{ + char *s; /* Pointer into string */ + + + if (num_params == 0) + return; + + Outputf("gsave\n"); + Outputf("currentmiterlimit 1.0 setmiterlimit\n"); + Outputf("MP\n"); + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + PenValid = 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.symbol_set = 277; + StandardFont.spacing = 0; + StandardFont.pitch = 9; + StandardFont.height = 11.5; + StandardFont.posture = 0; + StandardFont.weight = 0; + StandardFont.typeface = 48; + 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 1 : /* Symbol Set */ + StandardFont.symbol_set = (int)params[i + 1].value.number; + break; + case 2 : /* Font Spacing */ + StandardFont.spacing = (int)params[i + 1].value.number; + break; + case 3 : /* Pitch */ + StandardFont.pitch = params[i + 1].value.number; + break; + case 4 : /* Height */ + StandardFont.height = params[i + 1].value.number; + break; + case 5 : /* Posture */ + StandardFont.posture = (int)params[i + 1].value.number; + break; + case 6 : /* Stroke Weight */ + StandardFont.weight = (int)params[i + 1].value.number; + break; + case 7 : /* Typeface */ + StandardFont.typeface = (int)params[i + 1].value.number; + break; + } + + if (StandardFont.spacing || StandardFont.pitch <= 0.0) + { + /* + * Set proportional spacing font... + */ + + StandardFont.xpitch = 1.0f; + } + else + { + /* + * Set fixed-spaced font... + */ + + StandardFont.xpitch = 0.6f * StandardFont.height / StandardFont.pitch; + } + + /* + * Define the font... + */ + + if (PageDirty) + { + printf("%% SD"); + for (i = 0; i < num_params; i ++) + if (i) + printf(",%g", params[i].value.number); + else + printf("%g", params[i].value.number); + puts(";"); + + define_font(0); + } + + 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 */ +{ + float xsize, ysize; /* Font size... */ + + + if (num_params != 2) + return; + + /* + * The "SI" values are supposed to be cm, but they appear to be inches + * when tested on real HP devices... + */ + + xsize = params[0].value.number * 72.0f; + ysize = params[1].value.number * 72.0f * 0.6f; + + if (CharFont) + { + AlternateFont.xpitch = xsize / ysize; + AlternateFont.height = ysize; + } + else + { + StandardFont.xpitch = xsize / ysize; + StandardFont.height = ysize; + } + + if (PageDirty) + { + printf("%% SI%g,%g\n", params[0].value.number, params[1].value.number); + + define_font(CharFont); + } +} + + +/* + * '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: hpgl-char.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/hpgl-config.c b/filter/hpgl-config.c new file mode 100644 index 000000000..6f6c7ce65 --- /dev/null +++ b/filter/hpgl-config.c @@ -0,0 +1,645 @@ +/* + * "$Id: hpgl-config.c 4494 2005-02-18 02:18:11Z mike $" + * + * HP-GL/2 configuration routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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) + { + default : + 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; + + NP_number_pens(0, NULL); + 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: hpgl-config.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/hpgl-input.c b/filter/hpgl-input.c new file mode 100644 index 000000000..d6363e6fb --- /dev/null +++ b/filter/hpgl-input.c @@ -0,0 +1,258 @@ +/* + * "$Id: hpgl-input.c 4494 2005-02-18 02:18:11Z mike $" + * + * HP-GL/2 input processing for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * ParseCommand() - Parse an HPGL/2 command. + * FreeParameters() - Free all string parameter values. + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" +#include + +#define MAX_PARAMS 16384 + + +/* + * 'ParseCommand()' - Parse an HPGL/2 command. + * + * Returns the number of parameters seen or -1 on EOF. + */ + +int /* O - -1 on EOF, # params otherwise */ +ParseCommand(FILE *fp, /* I - File to read from */ + char *name, /* O - Name of command */ + param_t **params) /* O - Parameter list */ +{ + int num_params, /* Number of parameters seen */ + ch, /* Current char */ + done, /* Non-zero when the current command is read */ + i; /* Looping var */ + char buf[262144], /* String buffer */ + *bufptr; /* Pointer into 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; + + case '%' : /* PJL command? */ + if ((i = getc(fp)) == '-') + if ((i = getc(fp)) == '1') + if ((i = getc(fp)) == '2') + { + /* + * Yes, dump everything up to the "ENTER LANGUAGE" line... + */ + + while (fgets(buf, sizeof(buf), fp) != NULL) + if (strstr(buf, "ENTER") && strstr(buf, "LANGUAGE")) + break; + break; + } + + ungetc(i, fp); + + default : /* HP RTL/PCL control */ + while ((i = getc(fp)) != EOF && !isupper(i & 255)); + break; + } + } while (ch < ' '); + + name[0] = ch; + name[1] = getc(fp); + name[2] = '\0'; + + if (strcasecmp(name, "LB") == 0) + { + bufptr = buf; + while ((ch = getc(fp)) != StringTerminator) + if (bufptr < (buf + sizeof(buf) - 1)) + *bufptr++ = ch; + *bufptr = '\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) + { + bufptr = buf; + while ((ch = getc(fp)) != ';') + if (bufptr < (buf + sizeof(buf) - 1)) + *bufptr++ = ch; + *bufptr = '\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: hpgl-input.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/hpgl-main.c b/filter/hpgl-main.c new file mode 100644 index 000000000..98dc3a9b9 --- /dev/null +++ b/filter/hpgl-main.c @@ -0,0 +1,274 @@ +/* + * "$Id: hpgl-main.c 4494 2005-02-18 02:18:11Z mike $" + * + * HP-GL/2 filter main entry for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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(stdout, NULL); + 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 && + strcasecmp(val, "no") && strcasecmp(val, "off") && + strcasecmp(val, "false")) + shading = 0; + + if ((val = cupsGetOption("fitplot", num_options, options)) != NULL && + strcasecmp(val, "no") && strcasecmp(val, "off") && + strcasecmp(val, "false")) + 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, ¶ms)) >= 0) + { + Outputf("%% %s(%d)\n", name.name, num_params); + +#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: hpgl-main.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/hpgl-polygon.c b/filter/hpgl-polygon.c new file mode 100644 index 000000000..328dcff50 --- /dev/null +++ b/filter/hpgl-polygon.c @@ -0,0 +1,394 @@ +/* + * "$Id: hpgl-polygon.c 4494 2005-02-18 02:18:11Z mike $" + * + * HP-GL/2 polygon routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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"); + + PenValid = 1; + + 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"); + + PenValid = 1; + + 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"); + + PenValid = 1; + + 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"); + PenValid = 0; + 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"); + + PenValid = 1; + + 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"); + + PenValid = 1; + + 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"); + + PenValid = 1; + + 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: hpgl-polygon.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/hpgl-prolog.c b/filter/hpgl-prolog.c new file mode 100644 index 000000000..5cf0ad315 --- /dev/null +++ b/filter/hpgl-prolog.c @@ -0,0 +1,377 @@ +/* + * "$Id: hpgl-prolog.c 4680 2005-09-21 09:28:39Z mike $" + * + * HP-GL/2 prolog routines for for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * OutputProlog() - Output the PostScript prolog... + * OutputTrailer() - Output the PostScript trailer... + * Outputf() - Write a formatted string to the output file, creating the + * page header as needed... + */ + +/* + * Include necessary headers... + */ + +#include "hpgltops.h" +#include + + +/* + * 'OutputProlog()' - Output the PostScript prolog... + */ + +void +OutputProlog(char *title, /* I - Job title */ + char *user, /* I - Username */ + int shading) /* I - Type of shading */ +{ + FILE *prolog; /* Prolog file */ + char line[255]; /* Line from prolog file */ + 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), "%c", curtm); + printf("%%%%CreationDate: %s\n", line); + printf("%%%%Title: %s\n", title); + printf("%%%%For: %s\n", user); + printf("%%cupsRotation: %d\n", (Orientation & 3) * 90); + puts("%%EndComments"); + puts("%%BeginProlog"); + printf("/DefaultPenWidth %.2f def\n", PenWidth * 72.0 / 25.4); + 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("<>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("<>setpagedevice\n", + width, length); + puts("%%EndFeature"); + puts("%%EndPageSetup"); + + PageLeft = 0.0; + PageRight = width; + PageWidth = width; + PageBottom = 0.0; + PageTop = length; + PageLength = length; + } + } + + define_font(0); + define_font(1); + + 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: hpgl-prolog.c 4680 2005-09-21 09:28:39Z mike $". + */ diff --git a/filter/hpgl-vector.c b/filter/hpgl-vector.c new file mode 100644 index 000000000..d285b0c14 --- /dev/null +++ b/filter/hpgl-vector.c @@ -0,0 +1,775 @@ +/* + * "$Id: hpgl-vector.c 4494 2005-02-18 02:18:11Z mike $" + * + * HP-GL/2 vector routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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"); + + PenValid = 1; + + 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"); + + PenValid = 1; + + 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"); + + PenValid = 1; + + 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"); + + PenValid = 1; + + 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 = PenDown; + abscoords = 0; + + if (num_params == 0) + return; + + if (!PolygonMode) + { + Outputf("MP\n"); + PenValid = 0; + } + + if (!PenValid) + { + Outputf("%.3f %.3f MO\n", PenPosition[0], PenPosition[1]); + PenValid = 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 */ + + Outputf("%% PE: 7-bit\n"); + break; + case ':' : /* Select pen */ + s ++; + PenNumber = (int)decode_number(&s, base_bits, 1.0); + +#ifdef DEBUG + fprintf(stderr, "DEBUG: set pen #%d\n", PenNumber); +#endif /* DEBUG */ + + Outputf("%% PE: set pen #%d\n", PenNumber); + + 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); + break; + case '<' : /* Next coords are a move-to */ + draw = 0; + s ++; + +#ifdef DEBUG + fputs("DEBUG: moveto\n", stderr); +#endif /* DEBUG */ + + Outputf("%% PE: moveto\n"); + 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 */ + + Outputf("%% PE: set fractional bits %d\n", temp); + break; + case '=' : /* Next coords are absolute */ + s ++; + abscoords = 1; + +#ifdef DEBUG + fputs("DEBUG: absolute\n", stderr); +#endif /* DEBUG */ + + Outputf("%% PE: absolute\n"); + 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 */ + + Outputf("%% PE: coords %.3f %.3f\n", x, y); + + 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) + { + if (fabs(PenPosition[0] - tx) > 0.001 || + fabs(PenPosition[1] - ty) > 0.001) + 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"); + + PenValid = 1; + + 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, "ERROR: Bad PE character 0x%02X!\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, "ERROR: Bad PE character 0x%02X!\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]); + + PenValid = 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) + { + if (PolygonMode && i == 0) + Outputf("%.3f %.3f MO\n", x, y); + else if (fabs(PenPosition[0] - x) > 0.001 || + fabs(PenPosition[1] - y) > 0.001) + Outputf("%.3f %.3f LI\n", x, y); + } + + PenPosition[0] = x; + PenPosition[1] = y; + } + + if (PenDown) + { + if (!PolygonMode) + Outputf("ST\n"); + } +} + + +/* + * End of "$Id: hpgl-vector.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/hpgltops.h b/filter/hpgltops.h new file mode 100644 index 000000000..db68bcd4e --- /dev/null +++ b/filter/hpgltops.h @@ -0,0 +1,241 @@ +/* + * "$Id: hpgltops.h 4494 2005-02-18 02:18:11Z mike $" + * + * HP-GL/2 to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +/* + * Include necessary headers... + */ + +#include "common.h" +#include + +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif /* M_PI */ + +/* + * Parameter value structure... + */ + +typedef struct +{ + int type; + union + { + float number; + char *string; + } value; +} param_t; + +#define PARAM_ABSOLUTE 0 +#define PARAM_RELATIVE 1 +#define PARAM_STRING 2 + + +/* + * Font information... + */ + +typedef struct +{ + int symbol_set, /* Symbol set */ + spacing, /* Spacing (0 = fixed, 1 = proportional) */ + posture, /* Posture number */ + weight, /* Weight number */ + typeface; /* Typeface number */ + float pitch, /* Characters per inch */ + height, /* Height/size of font */ + xpitch; /* X pitch scaling value */ + 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 */ + PenValid VALUE(0), /* 1 = valid position, 0 = undefined */ + 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 define_font(int f); +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: hpgltops.h 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/image-bmp.c b/filter/image-bmp.c new file mode 100644 index 000000000..9a20ec8c4 --- /dev/null +++ b/filter/image-bmp.c @@ -0,0 +1,546 @@ +/* + * "$Id: image-bmp.c 4741 2005-10-02 04:25:52Z mike $" + * + * BMP image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadBMP() - 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-private.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); + + +/* + * '_cupsImageReadBMP()' - Read a BMP image file. + */ + +int /* O - Read status */ +_cupsImageReadBMP( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_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 */ + cups_ib_t bit, /* Bit in image */ + byte; /* Byte in image */ + cups_ib_t *in, /* Input pixels */ + *out, /* Output pixels */ + *ptr; /* Pointer into pixels */ + cups_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, "DEBUG: offset = %d\n", offset); + + if (offset < 0) + { + fprintf(stderr, "ERROR: Bad BMP offset %d\n", offset); + fclose(fp); + return (1); + } + + /* + * 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); + + if (img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH || + img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT || + (depth != 1 && depth != 4 && depth != 8 && depth != 24)) + { + fprintf(stderr, "ERROR: Bad BMP dimensions %ux%ux%d\n", + img->xsize, img->ysize, depth); + fclose(fp); + return (1); + } + + if (colors_used < 0 || colors_used > 256) + { + fprintf(stderr, "ERROR: Bad BMP colormap size %d\n", colors_used); + fclose(fp); + return (1); + } + + if (img->xppi == 0 || img->yppi == 0) + { + fprintf(stderr, "ERROR: Bad BMP resolution %dx%d PPI.\n", + img->xppi, img->yppi); + img->xppi = img->yppi = 128; + } + + /* + * Make sure the resolution info is valid... + */ + + 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; + + if (colors_used > 0) + fread(colormap, colors_used, 4, fp); + + /* + * Setup image and buffers... + */ + + img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; + + cupsImageSetMaxTiles(img, 0); + + in = malloc(img->xsize * 3); + bpp = cupsImageGetDepth(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 == CUPS_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 == CUPS_IMAGE_RGB) + { + if (saturation != 100 || hue != 0) + cupsImageRGBAdjust(out, img->xsize, saturation, hue); + } + else + { + if (saturation != 100 || hue != 0) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(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: image-bmp.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-colorspace.c b/filter/image-colorspace.c new file mode 100644 index 000000000..d390d779a --- /dev/null +++ b/filter/image-colorspace.c @@ -0,0 +1,1565 @@ +/* + * "$Id: image-colorspace.c 4767 2005-10-10 19:23:23Z mike $" + * + * Colorspace conversions for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * The color saturation/hue matrix stuff is provided thanks to Mr. Paul + * Haeberli at "http://www.sgi.com/grafica/matrix/index.html". + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsImageCMYKToBlack() - Convert CMYK data to black. + * cupsImageCMYKToCMY() - Convert CMYK colors to CMY. + * cupsImageCMYKToCMYK() - Convert CMYK colors to CMYK. + * cupsImageCMYKToRGB() - Convert CMYK colors to device-dependent + * RGB. + * cupsImageCMYKToWhite() - Convert CMYK colors to luminance. + * cupsImageLut() - Adjust all pixel values with the given + * LUT. + * cupsImageRGBAdjust() - Adjust the hue and saturation of the + * given RGB colors. + * cupsImageRGBToBlack() - Convert RGB data to black. + * cupsImageRGBToCMY() - Convert RGB colors to CMY. + * cupsImageRGBToCMYK() - Convert RGB colors to CMYK. + * cupsImageRGBToRGB() - Convert RGB colors to device-dependent + * RGB. + * cupsImageRGBToWhite() - Convert RGB colors to luminance. + * cupsImageSetProfile() - Set the device color profile. + * cupsImageSetRasterColorSpace() - Set the destination colorspace. + * cupsImageWhiteToBlack() - Convert luminance colors to black. + * cupsImageWhiteToCMY() - Convert luminance colors to CMY. + * cupsImageWhiteToCMYK() - Convert luminance colors to CMYK. + * cupsImageWhiteToRGB() - Convert luminance data to RGB. + * cupsImageWhiteToWhite() - Convert luminance colors to device- + * dependent luminance. + * cielab() - Map CIE Lab transformation... + * huerotate() - Rotate the hue, maintaining luminance. + * ident() - Make an identity matrix. + * mult() - Multiply two matrices. + * rgb_to_lab() - Convert an RGB color to CIE Lab. + * rgb_to_xyz() - Convert an RGB color to CIE XYZ. + * 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-private.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 */ + +/* + * CIE XYZ whitepoint... + */ + +#define D65_X (0.412453 + 0.357580 + 0.180423) +#define D65_Y (0.212671 + 0.715160 + 0.072169) +#define D65_Z (0.019334 + 0.119193 + 0.950227) + + +/* + * Lookup table structure... + */ + +typedef int cups_clut_t[3][256]; + + +/* + * Local globals... + */ + +static int cupsImageHaveProfile = 0; + /* Do we have a color profile? */ +static int *cupsImageDensity; + /* Ink/marker density LUT */ +static cups_clut_t *cupsImageMatrix; + /* Color transform matrix LUT */ +static cups_cspace_t cupsImageColorSpace = CUPS_CSPACE_RGB; + /* Destination colorspace */ + + +/* + * Local functions... + */ + +static float cielab(float x, float xn); +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 rgb_to_lab(cups_ib_t *val); +static void rgb_to_xyz(cups_ib_t *val); +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); + + +/* + * 'cupsImageCMYKToBlack()' - Convert CMYK data to black. + */ + +void +cupsImageCMYKToBlack( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + int k; /* Black value */ + + + if (cupsImageHaveProfile) + while (count > 0) + { + k = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 + in[3]; + + if (k < 255) + *out++ = cupsImageDensity[k]; + else + *out++ = cupsImageDensity[255]; + + in += 4; + count --; + } + else + while (count > 0) + { + k = (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 + in[3]; + + if (k < 255) + *out++ = k; + else + *out++ = 255; + + in += 4; + count --; + } +} + + +/* + * 'cupsImageCMYKToCMY()' - Convert CMYK colors to CMY. + */ + +void +cupsImageCMYKToCMY( + const cups_ib_t *in, /* I - Input pixels */ + cups_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 (cupsImageHaveProfile) + while (count > 0) + { + c = *in++; + m = *in++; + y = *in++; + k = *in++; + + cc = cupsImageMatrix[0][0][c] + + cupsImageMatrix[0][1][m] + + cupsImageMatrix[0][2][y] + k; + cm = cupsImageMatrix[1][0][c] + + cupsImageMatrix[1][1][m] + + cupsImageMatrix[1][2][y] + k; + cy = cupsImageMatrix[2][0][c] + + cupsImageMatrix[2][1][m] + + cupsImageMatrix[2][2][y] + k; + + if (cc < 0) + *out++ = 0; + else if (cc > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cc]; + + if (cm < 0) + *out++ = 0; + else if (cm > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cm]; + + if (cy < 0) + *out++ = 0; + else if (cy > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cy]; + + count --; + } + else + while (count > 0) + { + c = *in++; + m = *in++; + y = *in++; + k = *in++; + + c += k; + m += k; + y += k; + + if (c < 255) + *out++ = c; + else + *out++ = 255; + + if (m < 255) + *out++ = y; + else + *out++ = 255; + + if (y < 255) + *out++ = y; + else + *out++ = 255; + + count --; + } +} + + +/* + * 'cupsImageCMYKToCMYK()' - Convert CMYK colors to CMYK. + */ + +void +cupsImageCMYKToCMYK( + const cups_ib_t *in, /* I - Input pixels */ + cups_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 (cupsImageHaveProfile) + while (count > 0) + { + c = *in++; + m = *in++; + y = *in++; + k = *in++; + + cc = (cupsImageMatrix[0][0][c] + + cupsImageMatrix[0][1][m] + + cupsImageMatrix[0][2][y]); + cm = (cupsImageMatrix[1][0][c] + + cupsImageMatrix[1][1][m] + + cupsImageMatrix[1][2][y]); + cy = (cupsImageMatrix[2][0][c] + + cupsImageMatrix[2][1][m] + + cupsImageMatrix[2][2][y]); + + if (cc < 0) + *out++ = 0; + else if (cc > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cc]; + + if (cm < 0) + *out++ = 0; + else if (cm > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cm]; + + if (cy < 0) + *out++ = 0; + else if (cy > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cy]; + + *out++ = cupsImageDensity[k]; + + count --; + } + else if (in != out) + { + while (count > 0) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + + count --; + } + } +} + + +/* + * 'cupsImageCMYKToRGB()' - Convert CMYK colors to device-dependent RGB. + */ + +void +cupsImageCMYKToRGB( + const cups_ib_t *in, /* I - Input pixels */ + cups_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 (cupsImageHaveProfile) + { + while (count > 0) + { + c = *in++; + m = *in++; + y = *in++; + k = *in++; + + cr = cupsImageMatrix[0][0][c] + + cupsImageMatrix[0][1][m] + + cupsImageMatrix[0][2][y] + k; + cg = cupsImageMatrix[1][0][c] + + cupsImageMatrix[1][1][m] + + cupsImageMatrix[1][2][y] + k; + cb = cupsImageMatrix[2][0][c] + + cupsImageMatrix[2][1][m] + + cupsImageMatrix[2][2][y] + k; + + if (cr < 0) + *out++ = 255; + else if (cr > 255) + *out++ = 255 - cupsImageDensity[255]; + else + *out++ = 255 - cupsImageDensity[cr]; + + if (cg < 0) + *out++ = 255; + else if (cg > 255) + *out++ = 255 - cupsImageDensity[255]; + else + *out++ = 255 - cupsImageDensity[cg]; + + if (cb < 0) + *out++ = 255; + else if (cb > 255) + *out++ = 255 - cupsImageDensity[255]; + else + *out++ = 255 - cupsImageDensity[cb]; + + count --; + } + } + else + { + while (count > 0) + { + c = 255 - *in++; + m = 255 - *in++; + y = 255 - *in++; + k = *in++; + + c -= k; + m -= k; + y -= k; + + if (c > 0) + *out++ = c; + else + *out++ = 0; + + if (m > 0) + *out++ = m; + else + *out++ = 0; + + if (y > 0) + *out++ = y; + else + *out++ = 0; + + if (cupsImageColorSpace >= CUPS_CSPACE_CIELab) + rgb_to_lab(out - 3); + else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ) + rgb_to_xyz(out - 3); + + count --; + } + } +} + + +/* + * 'cupsImageCMYKToWhite()' - Convert CMYK colors to luminance. + */ + +void +cupsImageCMYKToWhite( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + int w; /* White value */ + + + if (cupsImageHaveProfile) + { + while (count > 0) + { + w = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 - in[3]; + + if (w > 0) + *out++ = cupsImageDensity[w]; + else + *out++ = cupsImageDensity[0]; + + in += 4; + count --; + } + } + else + { + while (count > 0) + { + w = 255 - (31 * in[0] + 61 * in[1] + 8 * in[2]) / 100 - in[3]; + + if (w > 0) + *out++ = w; + else + *out++ = 0; + + in += 4; + count --; + } + } +} + + +/* + * 'cupsImageLut()' - Adjust all pixel values with the given LUT. + */ + +void +cupsImageLut(cups_ib_t *pixels, /* IO - Input/output pixels */ + int count, /* I - Number of pixels/bytes to adjust */ + const cups_ib_t *lut) /* I - Lookup table */ +{ + while (count > 0) + { + *pixels = lut[*pixels]; + pixels ++; + count --; + } +} + + +/* + * 'cupsImageRGBAdjust()' - Adjust the hue and saturation of the given RGB colors. + */ + +void +cupsImageRGBAdjust(cups_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 cups_clut_t *lut = NULL; /* 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); + + /* + * Allocate memory for the lookup table... + */ + + if (lut == NULL) + lut = calloc(3, sizeof(cups_clut_t)); + + if (lut == NULL) + return; + + /* + * 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; + } +} + + +/* + * 'cupsImageRGBToBlack()' - Convert RGB data to black. + */ + +void +cupsImageRGBToBlack( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (cupsImageHaveProfile) + while (count > 0) + { + *out++ = cupsImageDensity[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 --; + } +} + + +/* + * 'cupsImageRGBToCMY()' - Convert RGB colors to CMY. + */ + +void +cupsImageRGBToCMY( + const cups_ib_t *in, /* I - Input pixels */ + cups_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 (cupsImageHaveProfile) + 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 = cupsImageMatrix[0][0][c] + + cupsImageMatrix[0][1][m] + + cupsImageMatrix[0][2][y] + k; + cm = cupsImageMatrix[1][0][c] + + cupsImageMatrix[1][1][m] + + cupsImageMatrix[1][2][y] + k; + cy = cupsImageMatrix[2][0][c] + + cupsImageMatrix[2][1][m] + + cupsImageMatrix[2][2][y] + k; + + if (cc < 0) + *out++ = 0; + else if (cc > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cc]; + + if (cm < 0) + *out++ = 0; + else if (cm > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cm]; + + if (cy < 0) + *out++ = 0; + else if (cy > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[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 --; + } +} + + +/* + * 'cupsImageRGBToCMYK()' - Convert RGB colors to CMYK. + */ + +void +cupsImageRGBToCMYK( + const cups_ib_t *in, /* I - Input pixels */ + cups_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 (cupsImageHaveProfile) + 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 = (cupsImageMatrix[0][0][c] + + cupsImageMatrix[0][1][m] + + cupsImageMatrix[0][2][y]); + cm = (cupsImageMatrix[1][0][c] + + cupsImageMatrix[1][1][m] + + cupsImageMatrix[1][2][y]); + cy = (cupsImageMatrix[2][0][c] + + cupsImageMatrix[2][1][m] + + cupsImageMatrix[2][2][y]); + + if (cc < 0) + *out++ = 0; + else if (cc > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cc]; + + if (cm < 0) + *out++ = 0; + else if (cm > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cm]; + + if (cy < 0) + *out++ = 0; + else if (cy > 255) + *out++ = cupsImageDensity[255]; + else + *out++ = cupsImageDensity[cy]; + + *out++ = cupsImageDensity[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 --; + } +} + + +/* + * 'cupsImageRGBToRGB()' - Convert RGB colors to device-dependent RGB. + */ + +void +cupsImageRGBToRGB( + const cups_ib_t *in, /* I - Input pixels */ + cups_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 (cupsImageHaveProfile) + { + 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 = cupsImageMatrix[0][0][c] + + cupsImageMatrix[0][1][m] + + cupsImageMatrix[0][2][y] + k; + cg = cupsImageMatrix[1][0][c] + + cupsImageMatrix[1][1][m] + + cupsImageMatrix[1][2][y] + k; + cb = cupsImageMatrix[2][0][c] + + cupsImageMatrix[2][1][m] + + cupsImageMatrix[2][2][y] + k; + + if (cr < 0) + *out++ = 255; + else if (cr > 255) + *out++ = 255 - cupsImageDensity[255]; + else + *out++ = 255 - cupsImageDensity[cr]; + + if (cg < 0) + *out++ = 255; + else if (cg > 255) + *out++ = 255 - cupsImageDensity[255]; + else + *out++ = 255 - cupsImageDensity[cg]; + + if (cb < 0) + *out++ = 255; + else if (cb > 255) + *out++ = 255 - cupsImageDensity[255]; + else + *out++ = 255 - cupsImageDensity[cb]; + + count --; + } + } + else + { + if (in != out) + memcpy(out, in, count * 3); + + if (cupsImageColorSpace >= CUPS_CSPACE_CIEXYZ) + { + while (count > 0) + { + if (cupsImageColorSpace >= CUPS_CSPACE_CIELab) + rgb_to_lab(out); + else + rgb_to_xyz(out); + + out += 3; + count --; + } + } + } +} + + +/* + * 'cupsImageRGBToWhite()' - Convert RGB colors to luminance. + */ + +void +cupsImageRGBToWhite( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (cupsImageHaveProfile) + { + while (count > 0) + { + *out++ = 255 - cupsImageDensity[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 --; + } + } +} + + +/* + * 'cupsImageSetProfile()' - Set the device color profile. + */ + +void +cupsImageSetProfile(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 cupsImageMatrix */ + + + /* + * Allocate memory for the profile data... + */ + + if (cupsImageMatrix == NULL) + cupsImageMatrix = calloc(3, sizeof(cups_clut_t)); + + if (cupsImageMatrix == NULL) + return; + + if (cupsImageDensity == NULL) + cupsImageDensity = calloc(256, sizeof(int)); + + if (cupsImageDensity == NULL) + return; + + /* + * Populate the profile lookup tables... + */ + + cupsImageHaveProfile = 1; + + for (i = 0, im = cupsImageMatrix[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 = cupsImageDensity; k < 256; k ++) + *im++ = 255.0 * d * pow((float)k / 255.0, g) + 0.5; +} + + +/* + * 'cupsImageSetRasterColorSpace()' - Set the destination colorspace. + */ + +void +cupsImageSetRasterColorSpace( + cups_cspace_t cs) /* I - Destination colorspace */ +{ + /* + * Set the destination colorspace... + */ + + cupsImageColorSpace = cs; + + /* + * Don't use color profiles in colorimetric colorspaces... + */ + + if (cs >= CUPS_CSPACE_CIEXYZ) + cupsImageHaveProfile = 0; +} + + +/* + * 'cupsImageWhiteToBlack()' - Convert luminance colors to black. + */ + +void +cupsImageWhiteToBlack( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (cupsImageHaveProfile) + while (count > 0) + { + *out++ = cupsImageDensity[255 - *in++]; + count --; + } + else + while (count > 0) + { + *out++ = 255 - *in++; + count --; + } +} + + +/* + * 'cupsImageWhiteToCMY()' - Convert luminance colors to CMY. + */ + +void +cupsImageWhiteToCMY( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (cupsImageHaveProfile) + while (count > 0) + { + out[0] = cupsImageDensity[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 --; + } +} + + +/* + * 'cupsImageWhiteToCMYK()' - Convert luminance colors to CMYK. + */ + +void +cupsImageWhiteToCMYK( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (cupsImageHaveProfile) + while (count > 0) + { + *out++ = 0; + *out++ = 0; + *out++ = 0; + *out++ = cupsImageDensity[255 - *in++]; + count --; + } + else + while (count > 0) + { + *out++ = 0; + *out++ = 0; + *out++ = 0; + *out++ = 255 - *in++; + count --; + } +} + + +/* + * 'cupsImageWhiteToRGB()' - Convert luminance data to RGB. + */ + +void +cupsImageWhiteToRGB( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (cupsImageHaveProfile) + { + while (count > 0) + { + out[0] = 255 - cupsImageDensity[255 - *in++]; + out[1] = out[0]; + out[2] = out[0]; + out += 3; + count --; + } + } + else + { + while (count > 0) + { + *out++ = *in; + *out++ = *in; + *out++ = *in++; + + if (cupsImageColorSpace >= CUPS_CSPACE_CIELab) + rgb_to_lab(out - 3); + else if (cupsImageColorSpace == CUPS_CSPACE_CIEXYZ) + rgb_to_xyz(out - 3); + + count --; + } + } +} + + +/* + * 'cupsImageWhiteToWhite()' - Convert luminance colors to device-dependent + * luminance. + */ + +void +cupsImageWhiteToWhite( + const cups_ib_t *in, /* I - Input pixels */ + cups_ib_t *out, /* I - Output pixels */ + int count) /* I - Number of pixels */ +{ + if (cupsImageHaveProfile) + while (count > 0) + { + *out++ = 255 - cupsImageDensity[255 - *in++]; + count --; + } + else if (in != out) + memcpy(out, in, count); +} + + +/* + * 'cielab()' - Map CIE Lab transformation... + */ + +static float /* O - Adjusted color value */ +cielab(float x, /* I - Raw color value */ + float xn) /* I - Whitepoint color value */ +{ + float x_xn; /* Fraction of whitepoint */ + + + x_xn = x / xn; + + if (x_xn > 0.008856) + return (cbrt(x_xn)); + else + return (7.787 * x_xn + 16.0 / 116.0); +} + + +/* + * '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)); +} + + +/* + * 'rgb_to_lab()' - Convert an RGB color to CIE Lab. + */ + +static void +rgb_to_lab(cups_ib_t *val) /* IO - Color value */ +{ + float r, /* Red value */ + g, /* Green value */ + b, /* Blue value */ + ciex, /* CIE X value */ + ciey, /* CIE Y value */ + ciez, /* CIE Z value */ + ciey_yn, /* Normalized luminance */ + ciel, /* CIE L value */ + ciea, /* CIE a value */ + cieb; /* CIE b value */ + + + /* + * Convert sRGB to linear RGB... + */ + + r = pow(val[0] / 255.0, 0.58823529412); + g = pow(val[1] / 255.0, 0.58823529412); + b = pow(val[2] / 255.0, 0.58823529412); + + /* + * Convert to CIE XYZ... + */ + + ciex = 0.412453 * r + 0.357580 * g + 0.180423 * b; + ciey = 0.212671 * r + 0.715160 * g + 0.072169 * b; + ciez = 0.019334 * r + 0.119193 * g + 0.950227 * b; + + /* + * Normalize and convert to CIE Lab... + */ + + ciey_yn = ciey / D65_Y; + + if (ciey_yn > 0.008856) + ciel = 116 * cbrt(ciey_yn) - 16; + else + ciel = 903.3 * ciey_yn; + + ciel = ciel; + ciea = 500 * (cielab(ciex, D65_X) - cielab(ciey, D65_Y)); + cieb = 200 * (cielab(ciey, D65_Y) - cielab(ciez, D65_Z)); + + /* + * Scale the L value and bias the a and b values by 128 so that all + * numbers are from 0 to 255. + */ + + ciel *= 2.55; + ciea += 128; + cieb += 128; + + /* + * Output 8-bit values... + */ + + if (ciel < 0.0) + val[0] = 0; + else if (ciel < 255.0) + val[0] = (int)ciel; + else + val[0] = 255; + + if (ciea < 0.0) + val[1] = 128; + else if (ciea < 255.0) + val[1] = (int)ciea; + else + val[1] = 255; + + if (cieb < 0.0) + val[2] = 128; + else if (cieb < 255.0) + val[2] = (int)cieb; + else + val[2] = 255; +} + + +/* + * 'rgb_to_xyz()' - Convert an RGB color to CIE XYZ. + */ + +static void +rgb_to_xyz(cups_ib_t *val) /* IO - Color value */ +{ + float r, /* Red value */ + g, /* Green value */ + b, /* Blue value */ + ciex, /* CIE X value */ + ciey, /* CIE Y value */ + ciez; /* CIE Z value */ + + + /* + * Convert sRGB to linear RGB... + */ + + r = pow(val[0] / 255.0, 0.58823529412); + g = pow(val[1] / 255.0, 0.58823529412); + b = pow(val[2] / 255.0, 0.58823529412); + + /* + * Convert to CIE XYZ... + */ + + ciex = 0.412453 * r + 0.357580 * g + 0.180423 * b; + ciey = 0.212671 * r + 0.715160 * g + 0.072169 * b; + ciez = 0.019334 * r + 0.119193 * g + 0.950227 * b; + + /* + * Output 8-bit values... + */ + + if (ciex < 0.0) + val[0] = 0; + else if (ciex < 255.0) + val[0] = (int)ciex; + else + val[0] = 255; + + if (ciey < 0.0) + val[1] = 0; + else if (ciey < 255.0) + val[1] = (int)ciey; + else + val[1] = 255; + + if (ciez < 0.0) + val[2] = 0; + else if (ciez < 255.0) + val[2] = (int)ciez; + else + val[2] = 255; +} + + +/* + * '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: image-colorspace.c 4767 2005-10-10 19:23:23Z mike $". + */ diff --git a/filter/image-gif.c b/filter/image-gif.c new file mode 100644 index 000000000..d8c30d1bf --- /dev/null +++ b/filter/image-gif.c @@ -0,0 +1,697 @@ +/* + * "$Id: image-gif.c 4741 2005-10-02 04:25:52Z mike $" + * + * GIF image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadGIF() - Read a GIF image file. + * gif_get_block() - Read a GIF data block... + * gif_get_code() - Get a LZW code from the file... + * gif_read_cmap() - Read the colormap from a GIF file... + * gif_read_image() - Read a GIF image stream... + * gif_read_lzw() - Read a byte from the LZW stream... + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + + +/* + * GIF definitions... + */ + +#define GIF_INTERLACE 0x40 +#define GIF_COLORMAP 0x80 + +typedef cups_ib_t gif_cmap_t[256][4]; +typedef short gif_table_t[4096]; + + +/* + * Local globals... + */ + +static int gif_eof = 0; /* Did we hit EOF? */ + + +/* + * Local functions... + */ + +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_cmap(FILE *fp, int ncolors, gif_cmap_t cmap, + int *gray); +static int gif_read_image(FILE *fp, cups_image_t *img, gif_cmap_t cmap, + int interlace); +static int gif_read_lzw(FILE *fp, int first_time, int input_code_size); + + +/* + * '_cupsImageReadGIF()' - Read a GIF image file. + */ + +int /* O - Read status */ +_cupsImageReadGIF( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_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 */ + + + /* + * GIF files are either grayscale or RGB - no CMYK... + */ + + if (primary == CUPS_IMAGE_RGB_CMYK) + primary = CUPS_IMAGE_RGB; + + /* + * 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 == CUPS_IMAGE_BLACK || primary == CUPS_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 ',' : /* cupsImage data */ + fread(buf, 9, 1, fp); + + if (buf[8] & GIF_COLORMAP) + { + ncolors = 2 << (buf[8] & 0x07); + gray = primary == CUPS_IMAGE_BLACK || primary == CUPS_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 CUPS_IMAGE_CMYK : + for (i = ncolors - 1; i >= 0; i --) + cupsImageWhiteToCMYK(cmap[i], cmap[i], 1); + break; + case CUPS_IMAGE_CMY : + for (i = ncolors - 1; i >= 0; i --) + cupsImageWhiteToCMY(cmap[i], cmap[i], 1); + break; + case CUPS_IMAGE_BLACK : + for (i = ncolors - 1; i >= 0; i --) + cupsImageWhiteToBlack(cmap[i], cmap[i], 1); + break; + case CUPS_IMAGE_WHITE : + break; + case CUPS_IMAGE_RGB : + case CUPS_IMAGE_RGB_CMYK : + for (i = ncolors - 1; i >= 0; i --) + cupsImageWhiteToRGB(cmap[i], cmap[i], 1); + break; + } + + img->colorspace = secondary; + } + else + { + if (hue != 0 || saturation != 100) + for (i = ncolors - 1; i >= 0; i --) + cupsImageRGBAdjust(cmap[i], 1, saturation, hue); + + switch (primary) + { + case CUPS_IMAGE_CMYK : + for (i = ncolors - 1; i >= 0; i --) + cupsImageRGBToCMYK(cmap[i], cmap[i], 1); + break; + case CUPS_IMAGE_CMY : + for (i = ncolors - 1; i >= 0; i --) + cupsImageRGBToCMY(cmap[i], cmap[i], 1); + break; + case CUPS_IMAGE_BLACK : + for (i = ncolors - 1; i >= 0; i --) + cupsImageRGBToBlack(cmap[i], cmap[i], 1); + break; + case CUPS_IMAGE_WHITE : + for (i = ncolors - 1; i >= 0; i --) + cupsImageRGBToWhite(cmap[i], cmap[i], 1); + break; + case CUPS_IMAGE_RGB : + case CUPS_IMAGE_RGB_CMYK : + break; + } + + img->colorspace = primary; + } + + if (lut) + { + bpp = cupsImageGetDepth(img); + + for (i = ncolors - 1; i >= 0; i --) + cupsImageLut(cmap[i], bpp, lut); + } + + img->xsize = (buf[5] << 8) | buf[4]; + img->ysize = (buf[7] << 8) | buf[6]; + + /* + * Check the dimensions of the image; since the dimensions are + * a 16-bit integer we just need to check for 0... + */ + + if (img->xsize == 0 || img->ysize == 0) + { + fprintf(stderr, "ERROR: Bad GIF image dimensions: %dx%d\n", + img->xsize, img->ysize); + fclose(fp); + return (1); + } + + i = gif_read_image(fp, img, cmap, buf[8] & GIF_INTERLACE); + fclose(fp); + return (i); + } + } +} + + +/* + * '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 const 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; + last_byte = 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... + */ + + if (last_byte > 1) + { + buf[0] = buf[last_byte - 2]; + buf[1] = buf[last_byte - 1]; + last_byte = 2; + } + else if (last_byte == 1) + { + buf[0] = buf[last_byte - 1]; + last_byte = 1; + } + + /* + * Read in another buffer... + */ + + if ((count = gif_get_block (fp, buf + last_byte)) <= 0) + { + /* + * Whoops, no more data! + */ + + done = 1; + return (-1); + } + + /* + * Update buffer state... + */ + + curbit = (curbit - lastbit) + 8 * last_byte; + last_byte += count; + 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_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_read_image()' - Read a GIF image stream... + */ + +static int /* I - 0 = success, -1 = failure */ +gif_read_image(FILE *fp, /* I - Input file */ + cups_image_t *img, /* I - cupsImage pointer */ + gif_cmap_t cmap, /* I - Colormap */ + int interlace) /* I - Non-zero = interlaced image */ +{ + unsigned char code_size; /* Code size */ + cups_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 const int xpasses[4] = /* X interleaving */ + { 8, 8, 4, 2 }, + ypasses[5] = /* Y interleaving */ + { 0, 4, 2, 1, 999999 }; + + + bpp = cupsImageGetDepth(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) + { + _cupsImagePutRow(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); +} + + +/* + * '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 */ + *stack = NULL, /* Output stack */ + *sp; /* Current stack pointer */ + static gif_table_t *table = NULL; /* String table */ + + + 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; + + /* + * Allocate memory for buffers... + */ + + if (table == NULL) + table = calloc(2, sizeof(gif_table_t)); + + if (table == NULL) + return (-1); + + if (stack == NULL) + stack = calloc(8192, sizeof(short)); + + if (stack == NULL) + return (-1); + + /* + * 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); +} + + +/* + * End of "$Id: image-gif.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-jpeg.c b/filter/image-jpeg.c new file mode 100644 index 000000000..6b1dc9c26 --- /dev/null +++ b/filter/image-jpeg.c @@ -0,0 +1,322 @@ +/* + * "$Id: image-jpeg.c 4741 2005-10-02 04:25:52Z mike $" + * + * JPEG image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadJPEG() - Read a JPEG image file. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + +#ifdef HAVE_LIBJPEG +# include /* JPEG/JFIF image definitions */ + + +/* + * '_cupsImageReadJPEG()' - Read a JPEG image file. + */ + +int /* O - Read status */ +_cupsImageReadJPEG( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + struct jpeg_decompress_struct cinfo; /* Decompressor info */ + struct jpeg_error_mgr jerr; /* Error handler info */ + cups_ib_t *in, /* Input pixels */ + *out; /* Output pixels */ + char header[16]; /* Photoshop JPEG header */ + int psjpeg; /* Non-zero if Photoshop JPEG */ + static const char *cspaces[] = + { /* JPEG colorspaces... */ + "JCS_UNKNOWN", + "JCS_GRAYSCALE", + "JCS_RGB", + "JCS_YCbCr", + "JCS_CMYK", + "JCS_YCCK" + }; + + + /* + * Read the first 16 bytes to determine if this is a Photoshop JPEG file... + */ + + fread(header, sizeof(header), 1, fp); + rewind(fp); + + psjpeg = memcmp(header + 6, "Photoshop ", 10) == 0; + + /* + * Read the JPEG header... + */ + + cinfo.err = jpeg_std_error(&jerr); + jpeg_create_decompress(&cinfo); + jpeg_stdio_src(&cinfo, fp); + jpeg_read_header(&cinfo, 1); + + cinfo.quantize_colors = 0; + + fprintf(stderr, "DEBUG: num_components = %d\n", cinfo.num_components); + fprintf(stderr, "DEBUG: jpeg_color_space = %s\n", + cspaces[cinfo.jpeg_color_space]); + + if (cinfo.num_components == 1) + { + fputs("DEBUG: Converting image to grayscale...\n", stderr); + + cinfo.out_color_space = JCS_GRAYSCALE; + cinfo.out_color_components = 1; + cinfo.output_components = 1; + + img->colorspace = secondary; + } + else if (cinfo.num_components == 4) + { + fputs("DEBUG: Converting image to CMYK...\n", stderr); + + cinfo.out_color_space = JCS_CMYK; + cinfo.out_color_components = 4; + cinfo.output_components = 4; + + img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_CMYK : primary; + } + else + { + fputs("DEBUG: Converting image to RGB...\n", stderr); + + cinfo.out_color_space = JCS_RGB; + cinfo.out_color_components = 3; + cinfo.output_components = 3; + + img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; + } + + jpeg_calc_output_dimensions(&cinfo); + + if (cinfo.output_width <= 0 || cinfo.output_width > CUPS_IMAGE_MAX_WIDTH || + cinfo.output_height <= 0 || cinfo.output_height > CUPS_IMAGE_MAX_HEIGHT) + { + fprintf(stderr, "ERROR: Bad JPEG dimensions %dx%d!\n", + cinfo.output_width, cinfo.output_height); + + jpeg_destroy_decompress(&cinfo); + + fclose(fp); + return (1); + } + + img->xsize = cinfo.output_width; + img->ysize = cinfo.output_height; + + 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); + } + + if (img->xppi == 0 || img->yppi == 0) + { + fprintf(stderr, "ERROR: Bad JPEG image resolution %dx%d PPI.\n", + img->xppi, img->yppi); + img->xppi = img->yppi = 128; + } + } + + fprintf(stderr, "DEBUG: JPEG image %dx%dx%d, %dx%d PPI\n", + img->xsize, img->ysize, cinfo.output_components, + img->xppi, img->yppi); + + cupsImageSetMaxTiles(img, 0); + + in = malloc(img->xsize * cinfo.output_components); + out = malloc(img->xsize * cupsImageGetDepth(img)); + + jpeg_start_decompress(&cinfo); + + while (cinfo.output_scanline < cinfo.output_height) + { + jpeg_read_scanlines(&cinfo, (JSAMPROW *)&in, (JDIMENSION)1); + + if (psjpeg && cinfo.output_components == 4) + { + /* + * Invert CMYK data from Photoshop... + */ + + cups_ib_t *ptr; /* Pointer into buffer */ + int i; /* Looping var */ + + + for (ptr = in, i = img->xsize * 4; i > 0; i --, ptr ++) + *ptr = 255 - *ptr; + } + + if ((saturation != 100 || hue != 0) && cinfo.output_components == 3) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + if ((img->colorspace == CUPS_IMAGE_WHITE && cinfo.out_color_space == JCS_GRAYSCALE) || + (img->colorspace == CUPS_IMAGE_RGB && cinfo.out_color_space == JCS_RGB) || + (img->colorspace == CUPS_IMAGE_CMYK && cinfo.out_color_space == JCS_CMYK)) + { +#ifdef DEBUG + int i, j; + cups_ib_t *ptr; + + + fputs("DEBUG: Direct Data...\n", stderr); + + fputs("DEBUG:", stderr); + + for (i = 0, ptr = in; i < img->xsize; i ++) + { + putc(' ', stderr); + for (j = 0; j < cinfo.output_components; j ++, ptr ++) + fprintf(stderr, "%02X", *ptr & 255); + } + + putc('\n', stderr); +#endif /* DEBUG */ + + if (lut) + cupsImageLut(in, img->xsize * cupsImageGetDepth(img), lut); + + _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, in); + } + else if (cinfo.out_color_space == JCS_GRAYSCALE) + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_BLACK : + cupsImageWhiteToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_RGB : + cupsImageWhiteToRGB(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageWhiteToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut); + + _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out); + } + else if (cinfo.out_color_space == JCS_RGB) + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut); + + _cupsImagePutRow(img, 0, cinfo.output_scanline - 1, img->xsize, out); + } + else /* JCS_CMYK */ + { + fputs("DEBUG: JCS_CMYK\n", stderr); + + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageCMYKToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageCMYKToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageCMYKToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_RGB : + cupsImageCMYKToRGB(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * cupsImageGetDepth(img), lut); + + _cupsImagePutRow(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: image-jpeg.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-photocd.c b/filter/image-photocd.c new file mode 100644 index 000000000..4e77ea9e0 --- /dev/null +++ b/filter/image-photocd.c @@ -0,0 +1,327 @@ +/* + * "$Id: image-photocd.c 4741 2005-10-02 04:25:52Z mike $" + * + * PhotoCD routines for the Common UNIX Printing System (CUPS). + * + * 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... + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadPhotoCD() - Read a PhotoCD image file. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + + +/* + * '_cupsImageReadPhotoCD()' - Read a PhotoCD image file. + */ + +int /* O - Read status */ +_cupsImageReadPhotoCD( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_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 */ + cups_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 == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; + img->xppi = 128; + img->yppi = 128; + + if (rotation) + { + img->xsize = 512; + img->ysize = 768; + } + else + { + img->xsize = 768; + img->ysize = 512; + } + + cupsImageSetMaxTiles(img, 0); + + bpp = cupsImageGetDepth(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 == CUPS_IMAGE_BLACK) + { + if (rotation) + { + for (rgbptr = out + xstart, x = 0; x < 768; x ++) + *rgbptr-- = 255 - *iy++; + + if (lut) + cupsImageLut(out, 768, lut); + + _cupsImagePutCol(img, 511 - y - pass, 0, 768, out); + } + else + { + cupsImageWhiteToBlack(iy, out, 768); + + if (lut) + cupsImageLut(out, 768, lut); + + _cupsImagePutRow(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) + cupsImageLut(out, 768, lut); + + _cupsImagePutCol(img, 511 - y - pass, 0, 768, out); + } + else + { + if (lut) + cupsImageLut(iy, 768, lut); + + _cupsImagePutRow(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) + cupsImageRGBAdjust(rgb, 768, saturation, hue); + + /* + * Then convert the RGB data to the appropriate colorspace and + * put it in the image... + */ + + if (img->colorspace == CUPS_IMAGE_RGB) + { + if (lut) + cupsImageLut(rgb, 768 * 3, lut); + + if (rotation) + _cupsImagePutCol(img, 511 - y - pass, 0, 768, rgb); + else + _cupsImagePutRow(img, 0, y + pass, 768, rgb); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(rgb, out, 768); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(rgb, out, 768); + break; + } + + if (lut) + cupsImageLut(out, 768 * bpp, lut); + + if (rotation) + _cupsImagePutCol(img, 511 - y - pass, 0, 768, out); + else + _cupsImagePutRow(img, 0, y + pass, 768, out); + } + } + } + } + + /* + * Free memory and return... + */ + + free(in); + free(out); + if (bpp > 1) + free(rgb); + + return (0); +} + + +/* + * End of "$Id: image-photocd.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-pix.c b/filter/image-pix.c new file mode 100644 index 000000000..2a326cd98 --- /dev/null +++ b/filter/image-pix.c @@ -0,0 +1,244 @@ +/* + * "$Id: image-pix.c 4741 2005-10-02 04:25:52Z mike $" + * + * Alias PIX image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadPIX() - Read a PIX image file. + * read_short() - Read a 16-bit integer. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + + +/* + * Local functions... + */ + +static short read_short(FILE *fp); + + +/* + * '_cupsImageReadPIX()' - Read a PIX image file. + */ + +int /* O - Read status */ +_cupsImageReadPIX( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_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 */ + cups_ib_t r, g, b; /* Red, green/gray, blue values */ + cups_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); + + /* + * Check the dimensions of the image. Since the short values used for the + * width and height cannot exceed CUPS_IMAGE_MAX_WIDTH or + * CUPS_IMAGE_MAX_HEIGHT, we just need to verify they are positive integers. + */ + + if (width <= 0 || height <= 0 || + (depth != 8 && depth != 24)) + { + fprintf(stderr, "ERROR: Bad PIX image dimensions %dx%dx%d\n", + width, height, depth); + fclose(fp); + return (1); + } + + if (depth == 8) + img->colorspace = secondary; + else + img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; + + img->xsize = width; + img->ysize = height; + + cupsImageSetMaxTiles(img, 0); + + in = malloc(img->xsize * (depth / 8)); + bpp = cupsImageGetDepth(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 == CUPS_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 != CUPS_IMAGE_WHITE) + switch (img->colorspace) + { + default : + cupsImageWhiteToRGB(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageWhiteToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageWhiteToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(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 == CUPS_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 == CUPS_IMAGE_RGB) + { + if (saturation != 100 || hue != 0) + cupsImageRGBAdjust(out, img->xsize, saturation, hue); + } + else + { + if (saturation != 100 || hue != 0) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(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: image-pix.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-png.c b/filter/image-png.c new file mode 100644 index 000000000..d240faca2 --- /dev/null +++ b/filter/image-png.c @@ -0,0 +1,271 @@ +/* + * "$Id: image-png.c 4741 2005-10-02 04:25:52Z mike $" + * + * PNG image routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadPNG() - Read a PNG image file. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + +#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) +# include /* Portable Network Graphics (PNG) definitions */ + + +/* + * '_cupsImageReadPNG()' - Read a PNG image file. + */ + +int /* O - Read status */ +_cupsImageReadPNG( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_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 */ + cups_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); + + fprintf(stderr, "DEBUG: PNG image: %dx%dx%d, color_type=%x (%s%s%s)\n", + (int)info->width, (int)info->height, info->bit_depth, info->color_type, + (info->color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "GRAYSCALE", + (info->color_type & PNG_COLOR_MASK_ALPHA) ? "+ALPHA" : "", + (info->color_type & PNG_COLOR_MASK_PALETTE) ? "+PALETTE" : ""); + + if (info->color_type & PNG_COLOR_MASK_PALETTE) + png_set_expand(pp); + else if (info->bit_depth < 8) + { + png_set_packing(pp); + png_set_expand(pp); + } + else if (info->bit_depth == 16) + png_set_strip_16(pp); + + if (info->color_type & PNG_COLOR_MASK_COLOR) + img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; + else + img->colorspace = secondary; + + if (info->width == 0 || info->width > CUPS_IMAGE_MAX_WIDTH || + info->height == 0 || info->height > CUPS_IMAGE_MAX_HEIGHT) + { + fprintf(stderr, "ERROR: PNG image has invalid dimensions %ux%u!\n", + (unsigned)info->width, (unsigned)info->height); + fclose(fp); + return (1); + } + + 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); + + if (img->xppi == 0 || img->yppi == 0) + { + fprintf(stderr, "ERROR: PNG image has invalid resolution %dx%d PPI\n", + img->xppi, img->yppi); + + img->xppi = img->yppi = 128; + } + } + + cupsImageSetMaxTiles(img, 0); + + 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 = cupsImageGetDepth(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_MASK_COLOR) + { + if ((saturation != 100 || hue != 0) && bpp > 1) + cupsImageRGBAdjust(inptr, img->xsize, saturation, hue); + + switch (img->colorspace) + { + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(inptr, out, img->xsize); + break; + case CUPS_IMAGE_RGB : + case CUPS_IMAGE_RGB_CMYK : + memcpy(out, inptr, img->xsize * 3); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(inptr, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(inptr, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(inptr, out, img->xsize); + break; + } + } + else + { + switch (img->colorspace) + { + case CUPS_IMAGE_WHITE : + memcpy(out, inptr, img->xsize); + break; + case CUPS_IMAGE_RGB : + case CUPS_IMAGE_RGB_CMYK : + cupsImageWhiteToRGB(inptr, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageWhiteToBlack(inptr, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageWhiteToCMY(inptr, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageWhiteToCMYK(inptr, out, img->xsize); + break; + } + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, out); + } + + if (passes > 1) + { + if (info->color_type & PNG_COLOR_MASK_COLOR) + inptr += img->xsize * 3; + else + inptr += img->xsize; + } + } + + 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: image-png.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-pnm.c b/filter/image-pnm.c new file mode 100644 index 000000000..3cfe66441 --- /dev/null +++ b/filter/image-pnm.c @@ -0,0 +1,312 @@ +/* + * "$Id: image-pnm.c 4741 2005-10-02 04:25:52Z mike $" + * + * Portable Any Map file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadPNM() - Read a PNM image file. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + + +/* + * '_cupsImageReadPNM()' - Read a PNM image file. + */ + +int /* O - Read status */ +_cupsImageReadPNM( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + int x, y; /* Looping vars */ + int bpp; /* Bytes per pixel */ + cups_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 & 255)) + lineptr ++; + + while (lineptr != NULL && img->xsize == 0) + { + if (*lineptr == '\0' || *lineptr == '#') + lineptr = fgets(line, sizeof(line), fp); + else if (isdigit(*lineptr & 255)) + { + img->xsize = atoi(lineptr); + while (isdigit(*lineptr & 255)) + lineptr ++; + } + else + lineptr ++; + } + + while (lineptr != NULL && img->ysize == 0) + { + if (*lineptr == '\0' || *lineptr == '#') + lineptr = fgets(line, sizeof(line), fp); + else if (isdigit(*lineptr & 255)) + { + img->ysize = atoi(lineptr); + while (isdigit(*lineptr & 255)) + 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 & 255)) + { + maxval = atoi(lineptr); + while (isdigit(*lineptr & 255)) + lineptr ++; + } + else + lineptr ++; + } + } + else + maxval = 1; + + if (img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH || + img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT) + { + fprintf(stderr, "ERROR: Bad PNM dimensions %dx%d!\n", + img->xsize, img->ysize); + fclose(fp); + return (1); + } + + if (maxval == 0) + { + fprintf(stderr, "ERROR: Bad PNM max value %d!\n", maxval); + fclose(fp); + return (1); + } + + if (format == 1 || format == 2 || format == 4 || format == 5) + img->colorspace = secondary; + else + img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; + + cupsImageSetMaxTiles(img, 0); + + bpp = cupsImageGetDepth(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 == CUPS_IMAGE_WHITE) + { + if (lut) + cupsImageLut(in, img->xsize, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_RGB : + cupsImageWhiteToRGB(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageWhiteToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageWhiteToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, out); + } + break; + + default : + if ((saturation != 100 || hue != 0) && bpp > 1) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + if (img->colorspace == CUPS_IMAGE_RGB) + { + if (lut) + cupsImageLut(in, img->xsize * 3, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, out); + } + break; + } + } + + free(in); + free(out); + + fclose(fp); + + return (0); +} + + +/* + * End of "$Id: image-pnm.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-private.h b/filter/image-private.h new file mode 100644 index 000000000..f87c41b4f --- /dev/null +++ b/filter/image-private.h @@ -0,0 +1,208 @@ +/* + * "$Id: image-private.h 4742 2005-10-02 23:01:43Z mike $" + * + * Private image library definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_IMAGE_PRIVATE_H_ +# define _CUPS_IMAGE_PRIVATE_H_ + +/* + * Include necessary headers... + */ + +# include "image.h" +# include +# include +# include +# include +# include +# include +# include +# include + + +/* + * Constants... + */ + +# define CUPS_IMAGE_MAX_WIDTH 0x07ffffff + /* 2^27-1 to allow for 15-channel data */ +# define CUPS_IMAGE_MAX_HEIGHT 0x7fffffff + /* 2^31-1 */ + +# define CUPS_TILE_SIZE 256 /* 256x256 pixel tiles */ +# define CUPS_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 */ + + +/* + * Types and structures... + */ + +struct cups_ic_s; + +typedef struct cups_itile_s /**** Image tile ****/ +{ + int dirty; /* True if tile is dirty */ + long pos; /* Position of tile on disk (-1 if not written) */ + struct cups_ic_s *ic; /* Pixel data */ +} cups_itile_t; + +typedef struct cups_ic_s /**** Image tile cache ****/ +{ + struct cups_ic_s *prev, /* Previous tile in cache */ + *next; /* Next tile in cache */ + cups_itile_t *tile; /* Tile this is attached to */ + cups_ib_t *pixels; /* Pixel data */ +} cups_ic_t; + +struct cups_image_s /**** Image file data ****/ +{ + cups_icspace_t 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 */ + cups_itile_t **tiles; /* Tiles in image */ + cups_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 */ +}; + +struct cups_izoom_s /**** Image zoom data ****/ +{ + cups_image_t *img; /* Image to zoom */ + cups_iztype_t type; /* Type of zooming */ + unsigned xorig, /* X origin */ + yorig, /* Y origin */ + 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 */ + cups_ib_t *rows[2], /* Horizontally scaled pixel data */ + *in; /* Unscaled input pixel data */ +}; + + +/* + * Prototypes... + */ + +extern int _cupsImagePutCol(cups_image_t *img, int x, int y, + int height, const cups_ib_t *pixels); +extern int _cupsImagePutRow(cups_image_t *img, int x, int y, + int width, const cups_ib_t *pixels); +extern int _cupsImageReadBMP(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadFPX(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadGIF(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadJPEG(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadPIX(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadPNG(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadPNM(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadPhotoCD(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadSGI(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadSunRaster(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern int _cupsImageReadTIFF(cups_image_t *img, FILE *fp, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); + + +#endif /* !_CUPS_IMAGE_PRIVATE_H_ */ + +/* + * End of "$Id: image-private.h 4742 2005-10-02 23:01:43Z mike $". + */ diff --git a/filter/image-sgi.c b/filter/image-sgi.c new file mode 100644 index 000000000..4ea91ce63 --- /dev/null +++ b/filter/image-sgi.c @@ -0,0 +1,293 @@ +/* + * "$Id: image-sgi.c 4741 2005-10-02 04:25:52Z mike $" + * + * SGI image file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadSGI() - Read a SGI image file. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" +#include "image-sgi.h" + + +/* + * '_cupsImageReadSGI()' - Read a SGI image file. + */ + +int /* O - Read status */ +_cupsImageReadSGI( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_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 */ + cups_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... + */ + + /* + * Check the image dimensions; since xsize and ysize are unsigned shorts, + * just check if they are 0 since they can't exceed CUPS_IMAGE_MAX_WIDTH or + * CUPS_IMAGE_MAX_HEIGHT... + */ + + if (sgip->xsize == 0 || sgip->ysize == 0 || + sgip->zsize == 0 || sgip->zsize > 4) + { + fprintf(stderr, "ERROR: Bad SGI image dimensions %ux%ux%u!\n", + sgip->xsize, sgip->ysize, sgip->zsize); + sgiClose(sgip); + fclose(fp); + return (1); + } + + if (sgip->zsize < 3) + img->colorspace = secondary; + else + img->colorspace = (primary == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; + + img->xsize = sgip->xsize; + img->ysize = sgip->ysize; + + cupsImageSetMaxTiles(img, 0); + + bpp = cupsImageGetDepth(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 == CUPS_IMAGE_WHITE) + { + if (lut) + cupsImageLut(in, img->xsize, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_RGB : + case CUPS_IMAGE_RGB_CMYK : + cupsImageWhiteToRGB(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageWhiteToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageWhiteToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, out); + } + } + else + { + if (img->colorspace == CUPS_IMAGE_RGB) + { + if (saturation != 100 || hue != 0) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + if (lut) + cupsImageLut(in, img->xsize * 3, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + if ((saturation != 100 || hue != 0) && bpp > 1) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, out); + } + } + } + + free(in); + free(out); + free(rows[0]); + + sgiClose(sgip); + + return (0); +} + + +/* + * End of "$Id: image-sgi.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-sgi.h b/filter/image-sgi.h new file mode 100644 index 000000000..41847e0af --- /dev/null +++ b/filter/image-sgi.h @@ -0,0 +1,96 @@ +/* + * "$Id: image-sgi.h 4741 2005-10-02 04:25:52Z mike $" + * + * SGI image file format library definitions for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _SGI_H_ +# define _SGI_H_ + +# include +# include +# include + +# ifdef __cplusplus +extern "C" { +# endif + + +/* + * Constants... + */ + +# define SGI_MAGIC 474 /* Magic number in image file */ + +# define SGI_READ 0 /* Read from an SGI image file */ +# define SGI_WRITE 1 /* Write to an SGI image file */ + +# define SGI_COMP_NONE 0 /* No compression */ +# define SGI_COMP_RLE 1 /* Run-length encoding */ +# define SGI_COMP_ARLE 2 /* Agressive run-length encoding */ + + +/* + * Image structure... + */ + +typedef struct +{ + FILE *file; /* Image file */ + int mode, /* File open mode */ + bpp, /* Bytes per pixel/channel */ + comp; /* Compression */ + unsigned short xsize, /* Width in pixels */ + ysize, /* Height in pixels */ + zsize; /* Number of channels */ + long firstrow, /* File offset for first row */ + nextrow, /* File offset for next row */ + **table, /* Offset table for compression */ + **length; /* Length table for compression */ + unsigned short *arle_row; /* Advanced RLE compression buffer */ + long arle_offset, /* Advanced RLE buffer offset */ + arle_length; /* Advanced RLE buffer length */ +} sgi_t; + + +/* + * Prototypes... + */ + +extern int sgiClose(sgi_t *sgip); +extern int sgiGetRow(sgi_t *sgip, unsigned short *row, int y, int z); +extern sgi_t *sgiOpen(const 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: image-sgi.h 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-sgilib.c b/filter/image-sgilib.c new file mode 100644 index 000000000..5401c4a7b --- /dev/null +++ b/filter/image-sgilib.c @@ -0,0 +1,859 @@ +/* + * "$Id: image-sgilib.c 4741 2005-10-02 04:25:52Z mike $" + * + * SGI image file format library routines for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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 /* O - 0 on success, -1 on error */ +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 /* O - 0 on success, -1 on error */ +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 * /* O - New image */ +sgiOpen(const 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 * /* O - New image */ +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 /* O - 0 on success, -1 on error */ +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 /* O - Long value */ +getlong(FILE *fp) /* I - File to read from */ +{ + unsigned char b[4]; /* Bytes from file */ + + + 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 /* O - Short value */ +getshort(FILE *fp) /* I - File to read from */ +{ + unsigned char b[2]; /* Bytes from file */ + + + fread(b, 2, 1, fp); + return ((b[0] << 8) | b[1]); +} + + +/* + * 'putlong()' - Put a 32-bit big-endian integer. + */ + +static int /* O - 0 on success, -1 on error */ +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 /* O - 0 on success, -1 on error */ +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 /* O - Value on success, -1 on error */ +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 /* O - Value on success, -1 on error */ +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 /* O - Length on success, -1 on error */ +write_rle8(FILE *fp, /* I - File to write to */ + unsigned short *row, /* I - Data */ + int xsize) /* I - Width of data in pixels */ +{ + int length, /* Length in bytes */ + count, /* Number of repeating pixels */ + i, /* Looping var */ + x; /* Current column */ + unsigned short *start, /* Start of current sequence */ + repeat; /* Repeated pixel */ + + + 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 /* O - Length in words */ +write_rle16(FILE *fp, /* I - File to write to */ + unsigned short *row, /* I - Data */ + int xsize) /* I - Width of data in pixels */ +{ + int length, /* Length in words */ + count, /* Number of repeating pixels */ + i, /* Looping var */ + x; /* Current column */ + unsigned short *start, /* Start of current sequence */ + repeat; /* Repeated pixel */ + + + 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: image-sgilib.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-sun.c b/filter/image-sun.c new file mode 100644 index 000000000..f49fac157 --- /dev/null +++ b/filter/image-sun.c @@ -0,0 +1,406 @@ +/* + * "$Id: image-sun.c 4741 2005-10-02 04:25:52Z mike $" + * + * Sun Raster image file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadSunRaster() - Read a SunRaster image file. + * read_unsigned() - Read a 32-bit unsigned integer. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.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); + + +/* + * '_cupsImageReadSunRaster()' - Read a SunRaster image file. + */ + +int /* O - Read status */ +_cupsImageReadSunRaster( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_ib_t *lut) /* I - Lookup table for gamma/brightness */ +{ + int i, x, y, + bpp, /* Bytes per pixel */ + scanwidth, + run_count, + run_value; + cups_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 (cupsImageOpen + * checks this) so we don't need to check the magic number again. + */ + + fputs("DEBUG: Reading Sun Raster image...\n", stderr); + + 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); + + fprintf(stderr, "DEBUG: ras_width=%d, ras_height=%d, ras_depth=%d, ras_type=%d, ras_maplength=%d\n", + img->xsize, img->ysize, ras_depth, ras_type, ras_maplength); + + if (ras_maplength > 768 || + img->xsize == 0 || img->xsize > CUPS_IMAGE_MAX_WIDTH || + img->ysize == 0 || img->ysize > CUPS_IMAGE_MAX_HEIGHT || + ras_depth == 0 || ras_depth > 32) + { + fputs("ERROR: Raster image cannot be loaded!\n", stderr); + return (1); + } + + if (ras_maplength > 0) + { + memset(cmap[0], 255, sizeof(cmap[0])); + memset(cmap[1], 0, sizeof(cmap[1])); + memset(cmap[2], 0, sizeof(cmap[2])); + + 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 == CUPS_IMAGE_RGB_CMYK) ? CUPS_IMAGE_RGB : primary; + in = malloc(img->xsize * 3 + 1); + } + + bpp = cupsImageGetDepth(img); + out = malloc(img->xsize * bpp); + scanline = malloc(scanwidth); + run_count = 0; + run_value = 0; + + fprintf(stderr, "DEBUG: bpp=%d, scanwidth=%d\n", bpp, scanwidth); + + 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 (ras_depth <= 8 && ras_maplength == 0) + { + if (img->colorspace == CUPS_IMAGE_WHITE) + { + if (lut) + cupsImageLut(in, img->xsize, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_RGB : + cupsImageWhiteToRGB(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageWhiteToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageWhiteToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, out); + } + } + else + { + if (img->colorspace == CUPS_IMAGE_RGB) + { + if (saturation != 100 || hue != 0) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + if (lut) + cupsImageLut(in, img->xsize * 3, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + if ((saturation != 100 || hue != 0) && bpp > 1) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(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: image-sun.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-tiff.c b/filter/image-tiff.c new file mode 100644 index 000000000..7a61e7284 --- /dev/null +++ b/filter/image-tiff.c @@ -0,0 +1,1766 @@ +/* + * "$Id: image-tiff.c 4741 2005-10-02 04:25:52Z mike $" + * + * TIFF file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * _cupsImageReadTIFF() - Read a TIFF image file. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + +#ifdef HAVE_LIBTIFF +# include /* TIFF image definitions */ +# include +# include + + +/* + * '_cupsImageReadTIFF()' - Read a TIFF image file. + */ + +int /* O - Read status */ +_cupsImageReadTIFF( + cups_image_t *img, /* IO - cupsImage */ + FILE *fp, /* I - cupsImage file */ + cups_icspace_t primary, /* I - Primary choice for colorspace */ + cups_icspace_t secondary, /* I - Secondary choice for colorspace */ + int saturation, /* I - Color saturation (%) */ + int hue, /* I - Color hue (degrees) */ + const cups_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; /* cupsImage includes alpha? */ + cups_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; + } + + if (img->xppi == 0 || img->yppi == 0) + { + fputs("ERROR: Bad TIFF resolution.\n", stderr); + img->xppi = 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; + + /* + * Check the size of the image... + */ + + if (width == 0 || width > CUPS_IMAGE_MAX_WIDTH || + height == 0 || height > CUPS_IMAGE_MAX_HEIGHT || + (bits != 1 && bits != 2 && bits != 4 && bits != 8) || + samples < 1 || samples > 4) + { + fprintf(stderr, "ERROR: Bad TIFF dimensions %ux%ux%ux%u!\n", + (unsigned)width, (unsigned)height, (unsigned)bits, + (unsigned)samples); + TIFFClose(tif); + fclose(fp); + return (1); + } + + /* + * Setup the image size and colorspace... + */ + + img->xsize = width; + img->ysize = height; + if (photometric == PHOTOMETRIC_MINISBLACK || + photometric == PHOTOMETRIC_MINISWHITE) + img->colorspace = secondary; + else if (photometric == PHOTOMETRIC_SEPARATED && primary == CUPS_IMAGE_RGB_CMYK) + img->colorspace = CUPS_IMAGE_CMYK; + else if (primary == CUPS_IMAGE_RGB_CMYK) + img->colorspace = CUPS_IMAGE_RGB; + else + img->colorspace = primary; + + fprintf(stderr, "DEBUG: img->colorspace = %d\n", img->colorspace); + + bpp = cupsImageGetDepth(img); + + cupsImageSetMaxTiles(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 == CUPS_IMAGE_WHITE) + { + if (lut) + cupsImageLut(in, img->xsize, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_RGB : + cupsImageWhiteToRGB(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageWhiteToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageWhiteToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageWhiteToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(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 == CUPS_IMAGE_WHITE) + { + if (lut) + cupsImageLut(in, img->ysize, lut); + + _cupsImagePutCol(img, x, 0, img->ysize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_RGB : + cupsImageWhiteToRGB(in, out, img->ysize); + break; + case CUPS_IMAGE_BLACK : + cupsImageWhiteToBlack(in, out, img->ysize); + break; + case CUPS_IMAGE_CMY : + cupsImageWhiteToCMY(in, out, img->ysize); + break; + case CUPS_IMAGE_CMYK : + cupsImageWhiteToCMYK(in, out, img->ysize); + break; + } + + if (lut) + cupsImageLut(out, img->ysize * bpp, lut); + + _cupsImagePutCol(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 == CUPS_IMAGE_RGB) + { + if (lut) + cupsImageLut(in, img->xsize * 3, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(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 == CUPS_IMAGE_RGB) + { + if (lut) + cupsImageLut(in, img->ysize * 3, lut); + + _cupsImagePutCol(img, x, 0, img->ysize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->ysize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->ysize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->ysize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->ysize); + break; + } + + if (lut) + cupsImageLut(out, img->ysize * bpp, lut); + + _cupsImagePutCol(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) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + if (img->colorspace == CUPS_IMAGE_RGB) + { + if (lut) + cupsImageLut(in, img->xsize * 3, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * bpp, lut); + + _cupsImagePutRow(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) + cupsImageRGBAdjust(in, img->ysize, saturation, hue); + + if (img->colorspace == CUPS_IMAGE_RGB) + { + if (lut) + cupsImageLut(in, img->ysize * 3, lut); + + _cupsImagePutCol(img, x, 0, img->ysize, in); + } + else + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->ysize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->ysize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->ysize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->ysize); + break; + } + + if (lut) + cupsImageLut(out, img->ysize * bpp, lut); + + _cupsImagePutCol(img, x, 0, img->ysize, out); + } + } + } + break; + + case PHOTOMETRIC_SEPARATED : + inkset = INKSET_CMYK; + numinks = 4; + +#ifdef TIFFTAG_NUMBEROFINKS + if (!TIFFGetField(tif, TIFFTAG_INKSET, &inkset) && + !TIFFGetField(tif, TIFFTAG_NUMBEROFINKS, &numinks)) +#else + if (!TIFFGetField(tif, TIFFTAG_INKSET, &inkset)) +#endif /* TIFFTAG_NUMBEROFINKS */ + { + fputs("WARNING: No inkset or number-of-inks tag in the file!\n", stderr); + } + + 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 == CUPS_IMAGE_CMYK) + { + TIFFReadScanline(tif, scanline, row, 0); + _cupsImagePutRow(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) + cupsImageRGBAdjust(in, img->xsize, saturation, hue); + + if (img->colorspace == CUPS_IMAGE_RGB) + { + if (lut) + cupsImageLut(in, img->xsize * 3, lut); + + _cupsImagePutRow(img, 0, y, img->xsize, in); + } + else if (img->colorspace == CUPS_IMAGE_WHITE) + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->xsize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->xsize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->xsize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->xsize); + break; + } + + if (lut) + cupsImageLut(out, img->xsize * 3, lut); + + _cupsImagePutRow(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 == CUPS_IMAGE_CMYK) + { + TIFFReadScanline(tif, scanline, row, 0); + _cupsImagePutCol(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) + cupsImageRGBAdjust(in, img->ysize, saturation, hue); + + if (img->colorspace == CUPS_IMAGE_RGB) + { + if (lut) + cupsImageLut(in, img->ysize * 3, lut); + + _cupsImagePutCol(img, x, 0, img->ysize, in); + } + else if (img->colorspace == CUPS_IMAGE_WHITE) + { + switch (img->colorspace) + { + default : + break; + + case CUPS_IMAGE_WHITE : + cupsImageRGBToWhite(in, out, img->ysize); + break; + case CUPS_IMAGE_BLACK : + cupsImageRGBToBlack(in, out, img->ysize); + break; + case CUPS_IMAGE_CMY : + cupsImageRGBToCMY(in, out, img->ysize); + break; + case CUPS_IMAGE_CMYK : + cupsImageRGBToCMYK(in, out, img->ysize); + break; + } + + if (lut) + cupsImageLut(out, img->ysize * bpp, lut); + + _cupsImagePutCol(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: image-tiff.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image-zoom.c b/filter/image-zoom.c new file mode 100644 index 000000000..f449826bc --- /dev/null +++ b/filter/image-zoom.c @@ -0,0 +1,370 @@ +/* + * "$Id: image-zoom.c 4741 2005-10-02 04:25:52Z mike $" + * + * cupsImage zoom routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsImageZoomDelete() - Free a zoom record... + * cupsImageZoomFill() - Fill a zoom record... + * cupsImageZoomNew() - Allocate a pixel zoom record... + * zoom_bilinear() - Fill a zoom record with image data utilizing + * bilinear interpolation. + * zoom_nearest() - Fill a zoom record quickly using nearest-neighbor + * sampling. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + + +/* + * Local functions... + */ + +static void zoom_bilinear(cups_izoom_t *z, int iy); +static void zoom_nearest(cups_izoom_t *z, int iy); + + +/* + * 'cupsImageZoomDelete()' - Free a zoom record... + */ + +void +cupsImageZoomDelete(cups_izoom_t *z) /* I - Zoom record to free */ +{ + free(z->rows[0]); + free(z->rows[1]); + free(z->in); + free(z); +} + + +/* + * 'cupsImageZoomFill()' - Fill a zoom record with image data utilizing bilinear + * interpolation. + */ + +void +cupsImageZoomFill(cups_izoom_t *z, /* I - Zoom record to fill */ + int iy) /* I - Zoom image row */ +{ + switch (z->type) + { + case CUPS_IZOOM_FAST : + zoom_nearest(z, iy); + break; + + default : + zoom_bilinear(z, iy); + break; + } +} + + +/* + * 'cupsImageZoomNew()' - Allocate a pixel zoom record... + */ + +cups_izoom_t * +cupsImageZoomNew( + cups_image_t *img, /* I - cupsImage 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 */ + cups_iztype_t type) /* I - Zoom type */ +{ + cups_izoom_t *z; /* New zoom record */ + int flip; /* Flip on X axis? */ + + + if (xsize > CUPS_IMAGE_MAX_WIDTH || + ysize > CUPS_IMAGE_MAX_HEIGHT || + (x1 - x0) > CUPS_IMAGE_MAX_WIDTH || + (y1 - y0) > CUPS_IMAGE_MAX_HEIGHT) + return (NULL); /* Protect against integer overflow */ + + if ((z = (cups_izoom_t *)calloc(1, sizeof(cups_izoom_t))) == NULL) + return (NULL); + + z->img = img; + z->row = 0; + z->depth = cupsImageGetDepth(img); + z->rotated = rotated; + z->type = type; + + if (xsize < 0) + { + flip = 1; + xsize = -xsize; + } + else + { + flip = 0; + } + + 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 (flip) + { + z->instep = -z->instep; + z->inincr = -z->inincr; + } + + if ((z->rows[0] = (cups_ib_t *)malloc(z->xsize * z->depth)) == NULL) + { + free(z); + return (NULL); + } + + if ((z->rows[1] = (cups_ib_t *)malloc(z->xsize * z->depth)) == NULL) + { + free(z->rows[0]); + free(z); + return (NULL); + } + + if ((z->in = (cups_ib_t *)malloc(z->width * z->depth)) == NULL) + { + free(z->rows[0]); + free(z->rows[1]); + free(z); + return (NULL); + } + + return (z); +} + + +/* + * 'zoom_bilinear()' - Fill a zoom record with image data utilizing bilinear + * interpolation. + */ + +static void +zoom_bilinear(cups_izoom_t *z, /* I - Zoom record to fill */ + int iy) /* I - Zoom image row */ +{ + cups_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) + cupsImageGetCol(z->img, z->xorig - iy, z->yorig, z->width, z->in); + else + cupsImageGetRow(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; + } + } +} + + +/* + * 'zoom_nearest()' - Fill a zoom record quickly using nearest-neighbor + * sampling. + */ + +static void +zoom_nearest(cups_izoom_t *z, /* I - Zoom record to fill */ + int iy) /* I - Zoom image row */ +{ + cups_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) + cupsImageGetCol(z->img, z->xorig - iy, z->yorig, z->width, z->in); + else + cupsImageGetRow(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; + } + } +} + + +/* + * End of "$Id: image-zoom.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image.c b/filter/image.c new file mode 100644 index 000000000..94bc96117 --- /dev/null +++ b/filter/image.c @@ -0,0 +1,845 @@ +/* + * "$Id: image.c 4741 2005-10-02 04:25:52Z mike $" + * + * Base image support for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsImageClose() - Close an image file. + * cupsImageGetCol() - Get a column of pixels from an image. + * cupsImageGetColorSpace() - Get the image colorspace. + * cupsImageGetDepth() - Get the number of bytes per pixel. + * cupsImageGetHeight() - Get the height of an image. + * cupsImageGetRow() - Get a row of pixels from an image. + * cupsImageGetWidth() - Get the width of an image. + * cupsImageGetXPPI() - Get the horizontal resolution of an image. + * cupsImageGetYPPI() - Get the vertical resolution of an image. + * cupsImageOpen() - Open an image file and read it into memory. + * _cupsImagePutCol() - Put a column of pixels to an image. + * _cupsImagePutRow() - Put a row of pixels to an image. + * cupsImageSetMaxTiles() - Set the maximum number of tiles to cache. + * flush_tile() - Flush the least-recently-used tile in the cache. + * get_tile() - Get a cached tile. + */ + +/* + * Include necessary headers... + */ + +#include "image-private.h" + + +/* + * Local functions... + */ + +static void flush_tile(cups_image_t *img); +static cups_ib_t *get_tile(cups_image_t *img, int x, int y); + + +/* + * 'cupsImageClose()' - Close an image file. + */ + +void +cupsImageClose(cups_image_t *img) /* I - Image to close */ +{ + cups_ic_t *current, /* Current cached tile */ + *next; /* Next cached tile */ + + + /* + * Wipe the tile cache file (if any)... + */ + + if (img->cachefile != NULL) + { + DEBUG_printf(("Closing/removing swap file \"%s\"...\n", img->cachename)); + + fclose(img->cachefile); + unlink(img->cachename); + } + + /* + * Free the image cache... + */ + + DEBUG_puts("Freeing memory..."); + + for (current = img->first, next = NULL; current != NULL; current = next) + { + DEBUG_printf(("Freeing cache (%p, next = %p)...\n", current, next)); + + next = current->next; + free(current); + } + + /* + * Free the rest of memory... + */ + + if (img->tiles != NULL) + { + DEBUG_printf(("Freeing tiles (%p)...\n", img->tiles[0])); + + free(img->tiles[0]); + + DEBUG_printf(("Freeing tile pointers (%p)...\n", img->tiles)); + + free(img->tiles); + } + + free(img); +} + + +/* + * 'cupsImageGetCol()' - Get a column of pixels from an image. + */ + +int /* O - -1 on error, 0 on success */ +cupsImageGetCol(cups_image_t *img, /* I - Image */ + int x, /* I - Column */ + int y, /* I - Start row */ + int height, /* I - Column height */ + cups_ib_t *pixels) /* O - Pixel data */ +{ + int bpp, /* Bytes per pixel */ + twidth, /* Tile width */ + count; /* Number of pixels to get */ + const cups_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 = cupsImageGetDepth(img); + twidth = bpp * (CUPS_TILE_SIZE - 1); + + while (height > 0) + { + ib = get_tile(img, x, y); + + if (ib == NULL) + return (-1); + + count = CUPS_TILE_SIZE - (y & (CUPS_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); +} + + +/* + * 'cupsImageGetColorSpace()' - Get the image colorspace. + */ + +cups_icspace_t /* O - Colorspace */ +cupsImageGetColorSpace( + cups_image_t *img) /* I - Image */ +{ + return (img->colorspace); +} + + +/* + * 'cupsImageGetDepth()' - Get the number of bytes per pixel. + */ + +int /* O - Bytes per pixel */ +cupsImageGetDepth(cups_image_t *img) /* I - Image */ +{ + return (abs(img->colorspace)); +} + + +/* + * 'cupsImageGetHeight()' - Get the height of an image. + */ + +unsigned /* O - Height in pixels */ +cupsImageGetHeight(cups_image_t *img) /* I - Image */ +{ + return (img->ysize); +} + + +/* + * 'cupsImageGetRow()' - Get a row of pixels from an image. + */ + +int /* O - -1 on error, 0 on success */ +cupsImageGetRow(cups_image_t *img, /* I - Image */ + int x, /* I - Start column */ + int y, /* I - Row */ + int width, /* I - Width of row */ + cups_ib_t *pixels) /* O - Pixel data */ +{ + int bpp, /* Bytes per pixel */ + count; /* Number of pixels to get */ + const cups_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 = CUPS_TILE_SIZE - (x & (CUPS_TILE_SIZE - 1)); + if (count > width) + count = width; + memcpy(pixels, ib, count * bpp); + pixels += count * bpp; + x += count; + width -= count; + } + + return (0); +} + + +/* + * 'cupsImageGetWidth()' - Get the width of an image. + */ + +unsigned /* O - Width in pixels */ +cupsImageGetWidth(cups_image_t *img) /* I - Image */ +{ + return (img->xsize); +} + + +/* + * 'cupsImageGetXPPI()' - Get the horizontal resolution of an image. + */ + +unsigned /* O - Horizontal PPI */ +cupsImageGetXPPI(cups_image_t *img) /* I - Image */ +{ + return (img->xppi); +} + + +/* + * 'cupsImageGetYPPI()' - Get the vertical resolution of an image. + */ + +unsigned /* O - Vertical PPI */ +cupsImageGetYPPI(cups_image_t *img) /* I - Image */ +{ + return (img->yppi); +} + + +/* + * 'cupsImageOpen()' - Open an image file and read it into memory. + */ + +cups_image_t * /* O - New image */ +cupsImageOpen( + const char *filename, /* I - Filename of image */ + cups_icspace_t primary, /* I - Primary colorspace needed */ + cups_icspace_t secondary, /* I - Secondary colorspace if primary no good */ + int saturation, /* I - Color saturation level */ + int hue, /* I - Color hue adjustment */ + const cups_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) */ + cups_image_t *img; /* New image buffer */ + int status; /* Status of load... */ + + + DEBUG_printf(("cupsImageOpen(\"%s\", %d, %d, %d, %d, %p)\n", + filename ? filename : "(null)", primary, secondary, + saturation, hue, lut)); + + /* + * 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(cups_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 = CUPS_TILE_MINIMUM; + img->xppi = 128; + img->yppi = 128; + + if (!memcmp(header, "GIF87a", 6) || !memcmp(header, "GIF89a", 6)) + status = _cupsImageReadGIF(img, fp, primary, secondary, saturation, hue, + lut); + else if (!memcmp(header, "BM", 2)) + status = _cupsImageReadBMP(img, fp, primary, secondary, saturation, hue, + lut); + else if (header[0] == 0x01 && header[1] == 0xda) + status = _cupsImageReadSGI(img, fp, primary, secondary, saturation, hue, + lut); + else if (header[0] == 0x59 && header[1] == 0xa6 && + header[2] == 0x6a && header[3] == 0x95) + status = _cupsImageReadSunRaster(img, fp, primary, secondary, saturation, + hue, lut); + else if (header[0] == 'P' && header[1] >= '1' && header[1] <= '6') + status = _cupsImageReadPNM(img, fp, primary, secondary, saturation, hue, + lut); + else if (!memcmp(header2, "PCD_IPI", 7)) + status = _cupsImageReadPhotoCD(img, fp, primary, secondary, saturation, + hue, lut); + else if (!memcmp(header + 8, "\000\010", 2) || + !memcmp(header + 8, "\000\030", 2)) + status = _cupsImageReadPIX(img, fp, primary, secondary, saturation, hue, + lut); +#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) + else if (!memcmp(header, "\211PNG", 4)) + status = _cupsImageReadPNG(img, fp, primary, secondary, saturation, hue, + lut); +#endif /* HAVE_LIBPNG && HAVE_LIBZ */ +#ifdef HAVE_LIBJPEG + else if (!memcmp(header, "\377\330\377", 3) && /* Start-of-Image */ + header[3] >= 0xe0 && header[3] <= 0xef) /* APPn */ + status = _cupsImageReadJPEG(img, fp, primary, secondary, saturation, hue, + lut); +#endif /* HAVE_LIBJPEG */ +#ifdef HAVE_LIBTIFF + else if (!memcmp(header, "MM\000\052", 4) || + !memcmp(header, "II\052\000", 4)) + status = _cupsImageReadTIFF(img, fp, primary, secondary, saturation, hue, + lut); +#endif /* HAVE_LIBTIFF */ + else + { +/* fputs("ERROR: Unknown image file format!"); +*/ fclose(fp); + status = -1; + } + + if (status) + { + free(img); + return (NULL); + } + else + return (img); +} + + +/* + * '_cupsImagePutCol()' - Put a column of pixels to an image. + */ + +int /* O - -1 on error, 0 on success */ +_cupsImagePutCol( + cups_image_t *img, /* I - Image */ + int x, /* I - Column */ + int y, /* I - Start row */ + int height, /* I - Column height */ + const cups_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 */ + cups_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 = cupsImageGetDepth(img); + twidth = bpp * (CUPS_TILE_SIZE - 1); + tilex = x / CUPS_TILE_SIZE; + tiley = y / CUPS_TILE_SIZE; + + while (height > 0) + { + ib = get_tile(img, x, y); + + if (ib == NULL) + return (-1); + + img->tiles[tiley][tilex].dirty = 1; + tiley ++; + + count = CUPS_TILE_SIZE - (y & (CUPS_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); +} + + +/* + * '_cupsImagePutRow()' - Put a row of pixels to an image. + */ + +int /* O - -1 on error, 0 on success */ +_cupsImagePutRow( + cups_image_t *img, /* I - Image */ + int x, /* I - Start column */ + int y, /* I - Row */ + int width, /* I - Row width */ + const cups_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 */ + cups_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 / CUPS_TILE_SIZE; + tiley = y / CUPS_TILE_SIZE; + + while (width > 0) + { + ib = get_tile(img, x, y); + + if (ib == NULL) + return (-1); + + img->tiles[tiley][tilex].dirty = 1; + + count = CUPS_TILE_SIZE - (x & (CUPS_TILE_SIZE - 1)); + if (count > width) + count = width; + memcpy(ib, pixels, count * bpp); + pixels += count * bpp; + x += count; + width -= count; + tilex ++; + } + + return (0); +} + + +/* + * 'cupsImageSetMaxTiles()' - 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 +cupsImageSetMaxTiles( + cups_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(CUPS_TILE_MINIMUM, + 1 + max((img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE, + (img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE)); + + if (max_tiles == 0) + max_tiles = ((img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE) * + ((img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE); + + cache_size = max_tiles * CUPS_TILE_SIZE * CUPS_TILE_SIZE * + cupsImageGetDepth(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 * CUPS_TILE_SIZE * CUPS_TILE_SIZE; + break; + case 2 : + if (tolower(cache_units[0] & 255) == 'g') + max_size *= 1024 * 1024 * 1024; + else if (tolower(cache_units[0] & 255) == 'm') + max_size *= 1024 * 1024; + else if (tolower(cache_units[0] & 255) == 'k') + max_size *= 1024; + else if (tolower(cache_units[0] & 255) == 't') + max_size *= 4 * CUPS_TILE_SIZE * CUPS_TILE_SIZE; + break; + } + } + else + max_size = 32 * 1024 * 1024; + + if (cache_size > max_size) + max_tiles = max_size / CUPS_TILE_SIZE / CUPS_TILE_SIZE / + cupsImageGetDepth(img); + + if (max_tiles < min_tiles) + max_tiles = min_tiles; + + img->max_ics = max_tiles; + + DEBUG_printf(("max_ics=%d...\n", img->max_ics)); +} + + +/* + * 'flush_tile()' - Flush the least-recently-used tile in the cache. + */ + +static void +flush_tile(cups_image_t *img) /* I - Image */ +{ + int fd; /* Cache file descriptor */ + int bpp; /* Bytes per pixel */ + cups_itile_t *tile; /* Pointer to tile */ + + + bpp = cupsImageGetDepth(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; + } + + DEBUG_printf(("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, CUPS_TILE_SIZE * CUPS_TILE_SIZE, + img->cachefile) < 1) + perror("ERROR: Unable to write tile to swap file"); + else + DEBUG_printf(("Wrote tile at position %ld...\n", tile->pos)); +*/ + + fwrite(tile->ic->pixels, bpp, CUPS_TILE_SIZE * CUPS_TILE_SIZE, + img->cachefile); + + tile->ic = NULL; + tile->dirty = 0; +} + + +/* + * 'get_tile()' - Get a cached tile. + */ + +static cups_ib_t * /* O - Pointer to tile or NULL */ +get_tile(cups_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 */ + cups_ic_t *ic; /* Cache pointer */ + cups_itile_t *tile; /* Tile pointer */ + + + if (img->tiles == NULL) + { + xtiles = (img->xsize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE; + ytiles = (img->ysize + CUPS_TILE_SIZE - 1) / CUPS_TILE_SIZE; + + DEBUG_printf(("Creating tile array (%dx%d)\n", xtiles, ytiles)); + + img->tiles = calloc(sizeof(cups_itile_t *), ytiles); + tile = calloc(sizeof(cups_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 = cupsImageGetDepth(img); + tilex = x / CUPS_TILE_SIZE; + tiley = y / CUPS_TILE_SIZE; + tile = img->tiles[tiley] + tilex; + x &= (CUPS_TILE_SIZE - 1); + y &= (CUPS_TILE_SIZE - 1); + + if ((ic = tile->ic) == NULL) + { + if (img->num_ics < img->max_ics) + { + ic = calloc(sizeof(cups_ic_t) + bpp * CUPS_TILE_SIZE * + CUPS_TILE_SIZE, 1); + ic->pixels = ((cups_ib_t *)ic) + sizeof(cups_ic_t); + + img->num_ics ++; + + DEBUG_printf(("Allocated cache tile %d (%p)...\n", img->num_ics, ic)); + } + else + { + DEBUG_printf(("Flushing old cache tile (%p)...\n", img->first)); + + flush_tile(img); + ic = img->first; + } + + ic->tile = tile; + tile->ic = ic; + + if (tile->pos >= 0) + { + DEBUG_printf(("Loading cache tile from file position %ld...\n", + tile->pos)); + + if (ftell(img->cachefile) != tile->pos) + fseek(img->cachefile, tile->pos, SEEK_SET); +/* if (fseek(img->cachefile, tile->pos, SEEK_SET)) + perror("get_tile:"); +*/ + + fread(ic->pixels, bpp, CUPS_TILE_SIZE * CUPS_TILE_SIZE, img->cachefile); + } + else + { + DEBUG_puts("Clearing cache tile..."); + + memset(ic->pixels, 0, bpp * CUPS_TILE_SIZE * CUPS_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 * CUPS_TILE_SIZE + x)); +} + + +/* + * End of "$Id: image.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/image.h b/filter/image.h new file mode 100644 index 000000000..ae90b94fc --- /dev/null +++ b/filter/image.h @@ -0,0 +1,151 @@ +/* + * "$Id: image.h 4741 2005-10-02 04:25:52Z mike $" + * + * Image library definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_IMAGE_H_ +# define _CUPS_IMAGE_H_ + +/* + * Include necessary headers... + */ + +# include +# include "raster.h" + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +/* + * Constants... + */ + +typedef enum cups_icspace_e /**** Image colorspaces ****/ +{ + CUPS_IMAGE_CMYK = -4, /* Cyan, magenta, yellow, and black */ + CUPS_IMAGE_CMY = -3, /* Cyan, magenta, and yellow */ + CUPS_IMAGE_BLACK = -1, /* Black */ + CUPS_IMAGE_WHITE = 1, /* White (luminance) */ + CUPS_IMAGE_RGB = 3, /* Red, green, and blue */ + CUPS_IMAGE_RGB_CMYK = 4 /* Use RGB or CMYK */ +} cups_icspace_t; + +typedef enum cups_iztype_e /**** Image zoom type ****/ +{ + CUPS_IZOOM_FAST, /* Use nearest-neighbor sampling */ + CUPS_IZOOM_NORMAL, /* Use bilinear interpolation */ + CUPS_IZOOM_BEST /* Use bicubic interpolation */ +} cups_iztype_t; + + +/* + * Types and structures... + */ + +typedef unsigned char cups_ib_t; /**** Image byte ****/ + +struct cups_image_s; +typedef struct cups_image_s cups_image_t; + /**** Image file data ****/ + +struct cups_izoom_s; +typedef struct cups_izoom_s cups_izoom_t; + /**** Image zoom data ****/ + + +/* + * Prototypes... + */ + +extern void cupsImageClose(cups_image_t *img); +extern void cupsImageCMYKToBlack(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageCMYKToCMY(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageCMYKToCMYK(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageCMYKToRGB(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageCMYKToWhite(const cups_ib_t *in, + cups_ib_t *out, int count); +extern int cupsImageGetCol(cups_image_t *img, int x, int y, + int height, cups_ib_t *pixels); +extern cups_icspace_t cupsImageGetColorSpace(cups_image_t *img); +extern int cupsImageGetDepth(cups_image_t *img); +extern unsigned cupsImageGetHeight(cups_image_t *img); +extern int cupsImageGetRow(cups_image_t *img, int x, int y, + int width, cups_ib_t *pixels); +extern unsigned cupsImageGetWidth(cups_image_t *img); +extern unsigned cupsImageGetXPPI(cups_image_t *img); +extern unsigned cupsImageGetYPPI(cups_image_t *img); +extern void cupsImageLut(cups_ib_t *pixels, int count, + const cups_ib_t *lut); +extern cups_image_t *cupsImageOpen(const char *filename, + cups_icspace_t primary, + cups_icspace_t secondary, + int saturation, int hue, + const cups_ib_t *lut); +extern void cupsImageRGBAdjust(cups_ib_t *pixels, int count, + int saturation, int hue); +extern void cupsImageRGBToBlack(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageRGBToCMY(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageRGBToCMYK(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageRGBToRGB(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageRGBToWhite(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageSetMaxTiles(cups_image_t *img, int max_tiles); +extern void cupsImageSetProfile(float d, float g, + float matrix[3][3]); +extern void cupsImageSetRasterColorSpace(cups_cspace_t cs); +extern void cupsImageWhiteToBlack(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageWhiteToCMY(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageWhiteToCMYK(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageWhiteToRGB(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageWhiteToWhite(const cups_ib_t *in, + cups_ib_t *out, int count); +extern void cupsImageZoomDelete(cups_izoom_t *z); +extern void cupsImageZoomFill(cups_izoom_t *z, int iy); +extern cups_izoom_t *cupsImageZoomNew(cups_image_t *img, int x0, int y0, + int x1, int y1, int xsize, int ysize, + int rotated, cups_iztype_t type); + + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_IMAGE_H_ */ + +/* + * End of "$Id: image.h 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/imagetops.c b/filter/imagetops.c new file mode 100644 index 000000000..23e33a0da --- /dev/null +++ b/filter/imagetops.c @@ -0,0 +1,1028 @@ +/* + * "$Id: imagetops.c 4741 2005-10-02 04:25:52Z mike $" + * + * Image file to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Main entry... + * ps_hex() - Print binary data as a series of hexadecimal numbers. + * ps_ascii85() - Print binary data as a series of base-85 numbers. + */ + +/* + * Include necessary headers... + */ + +#include "common.h" +#include "image.h" +#include + + +/* + * Globals... + */ + +int Flip = 0, /* Flip/mirror pages */ + 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(cups_ib_t *, int, int); +static void ps_ascii85(cups_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 */ +{ + cups_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; + cups_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 + strlcpy(filename, argv[6], sizeof(filename)); + + /* + * 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, 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-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); + + if ((val = cupsGetOption("mirror", num_options, options)) != NULL && + strcasecmp(val, "True") == 0) + Flip = 1; + + /* + * Open the input image to print... + */ + + colorspace = ColorDevice ? CUPS_IMAGE_RGB_CMYK : CUPS_IMAGE_WHITE; + + img = cupsImageOpen(filename, colorspace, CUPS_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 = cupsImageGetColorSpace(img); + + /* + * Scale as necessary... + */ + + if (zoom == 0.0 && xppi == 0) + { + xppi = cupsImageGetXPPI(img); + yppi = cupsImageGetYPPI(img); + } + + if (yppi == 0) + yppi = xppi; + + fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n", + xppi, yppi, zoom); + + 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; + } + + fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n", + xprint, yprint); + + xinches = (float)cupsImageGetWidth(img) / (float)xppi; + yinches = (float)cupsImageGetHeight(img) / (float)yppi; + + fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n", + xinches, yinches); + + if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL) + { + xinches = xinches * atoi(val) / 100; + yinches = yinches * atoi(val) / 100; + } + + if (cupsGetOption("orientation-requested", num_options, options) == NULL && + cupsGetOption("landscape", num_options, options) == NULL) + { + /* + * Rotate the image if it will fit landscape but not portrait... + */ + + fputs("DEBUG: Auto orientation...\n", stderr); + + if ((xinches > xprint || yinches > yprint) && + xinches <= yprint && yinches <= xprint) + { + /* + * Rotate the image as needed... + */ + + fputs("DEBUG: Using landscape orientation...\n", stderr); + + 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)cupsImageGetYPPI(img) / (float)cupsImageGetXPPI(img); + + fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n", + xprint, yprint); + + fprintf(stderr, "DEBUG: cupsImageGetXPPI(img) = %d, cupsImageGetYPPI(img) = %d, aspect = %f\n", + cupsImageGetXPPI(img), cupsImageGetYPPI(img), aspect); + + xsize = xprint * zoom; + ysize = xsize * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect; + + if (ysize > (yprint * zoom)) + { + ysize = yprint * zoom; + xsize = ysize * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img); + } + + xsize2 = yprint * zoom; + ysize2 = xsize2 * cupsImageGetHeight(img) / cupsImageGetWidth(img) / aspect; + + if (ysize2 > (xprint * zoom)) + { + ysize2 = xprint * zoom; + xsize2 = ysize2 * cupsImageGetWidth(img) * aspect / cupsImageGetHeight(img); + } + + fprintf(stderr, "DEBUG: Portrait size is %.2f x %.2f inches\n", xsize, ysize); + fprintf(stderr, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2, ysize2); + + if (cupsGetOption("orientation-requested", num_options, options) == NULL && + cupsGetOption("landscape", num_options, options) == NULL) + { + /* + * Choose the rotation with the largest area, but prefer + * portrait if they are equal... + */ + + fputs("DEBUG: Auto orientation...\n", stderr); + + if ((xsize * ysize) < (xsize2 * xsize2)) + { + /* + * Do landscape orientation... + */ + + fputs("DEBUG: Using landscape orientation...\n", stderr); + + Orientation = 1; + xinches = xsize2; + yinches = ysize2; + xprint = (PageTop - PageBottom) / 72.0; + yprint = (PageRight - PageLeft) / 72.0; + } + else + { + /* + * Do portrait orientation... + */ + + fputs("DEBUG: Using portrait orientation...\n", stderr); + + Orientation = 0; + xinches = xsize; + yinches = ysize; + } + } + else if (Orientation & 1) + { + fputs("DEBUG: Using landscape orientation...\n", stderr); + + xinches = xsize2; + yinches = ysize2; + xprint = (PageTop - PageBottom) / 72.0; + yprint = (PageRight - PageLeft) / 72.0; + } + else + { + fputs("DEBUG: Using portrait orientation...\n", stderr); + + 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; + + fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n", + xpages, xprint, ypages, yprint); + + /* + * 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... */ + + + /* + * Use the correct width and length for the current orientation... + */ + + 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]; + + fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n", + width / 72.0, length / 72.0); + + /* + * 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]; + } + + /* + * 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), "%c", curtm); + printf("%%%%CreationDate: %s\n", curdate); + printf("%%%%Title: %s\n", argv[3]); + printf("%%%%For: %s\n", argv[2]); + if (Orientation & 1) + puts("%%Orientation: Landscape"); + else + puts("%%Orientation: Portrait"); + 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); + + WriteCommon(); + switch (Orientation) + { + case 0 : + WriteLabelProlog(cupsGetOption("page-label", num_options, options), + PageBottom, PageTop, PageWidth); + break; + + case 1 : + WriteLabelProlog(cupsGetOption("page-label", num_options, options), + PageLeft, PageRight, PageLength); + break; + + case 2 : + WriteLabelProlog(cupsGetOption("page-label", num_options, options), + PageLength - PageTop, PageLength - PageBottom, + PageWidth); + break; + + case 3 : + WriteLabelProlog(cupsGetOption("page-label", num_options, options), + PageWidth - PageRight, PageWidth - PageLeft, + PageLength); + break; + } + + if (realcopies > 1) + { + if (ppd == NULL || ppd->language_level == 1) + printf("/#copies %d def\n", realcopies); + else + printf("<>setpagedevice\n", realcopies); + } + + puts("%%EndProlog"); + + /* + * Output the pages... + */ + + row = malloc(cupsImageGetWidth(img) * abs(colorspace) + 3); + + fprintf(stderr, "DEBUG: XPosition=%d, YPosition=%d, Orientation=%d\n", + XPosition, YPosition, Orientation); + fprintf(stderr, "DEBUG: xprint=%.0f, yprint=%.0f\n", xprint, yprint); + fprintf(stderr, "DEBUG: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f\n", + PageLeft, PageRight, PageWidth); + fprintf(stderr, "DEBUG: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f\n", + PageBottom, PageTop, PageLength); + + switch (Orientation) + { + default : + switch (XPosition) + { + case -1 : + left = PageLeft; + break; + default : + left = (PageRight + PageLeft - xprint * 72) / 2; + break; + case 1 : + left = PageRight - xprint * 72; + break; + } + + switch (YPosition) + { + case -1 : + top = PageBottom + yprint * 72; + break; + default : + top = (PageTop + PageBottom + yprint * 72) / 2; + break; + case 1 : + top = PageTop; + break; + } + break; + + case 1 : + switch (XPosition) + { + case -1 : + left = PageBottom; + break; + default : + left = (PageTop + PageBottom - xprint * 72) / 2; + break; + case 1 : + left = PageTop - xprint * 72; + break; + } + + switch (YPosition) + { + case -1 : + top = PageLeft + yprint * 72; + break; + default : + top = (PageRight + PageLeft + yprint * 72) / 2; + break; + case 1 : + top = PageRight; + break; + } + break; + + case 2 : + switch (XPosition) + { + case 1 : + left = PageLeft; + break; + default : + left = (PageRight + PageLeft - xprint * 72) / 2; + break; + case -1 : + left = PageRight - xprint * 72; + break; + } + + switch (YPosition) + { + case 1 : + top = PageBottom + yprint * 72; + break; + default : + top = (PageTop + PageBottom + yprint * 72) / 2; + break; + case -1 : + top = PageTop; + break; + } + break; + + case 3 : + switch (XPosition) + { + case 1 : + left = PageBottom; + break; + default : + left = (PageTop + PageBottom - xprint * 72) / 2; + break; + case -1 : + left = PageTop - xprint * 72; + break; + } + + switch (YPosition) + { + case 1 : + top = PageLeft + yprint * 72; + break; + default : + top = (PageRight + PageLeft + yprint * 72) / 2; + break; + case -1 : + top = PageRight; + break; + } + break; + } + + fprintf(stderr, "DEBUG: left=%.2f, top=%.2f\n", left, top); + + 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", PageWidth); + 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", PageLength); + break; + } + + puts("gsave"); + + x0 = cupsImageGetWidth(img) * xpage / xpages; + x1 = cupsImageGetWidth(img) * (xpage + 1) / xpages - 1; + y0 = cupsImageGetHeight(img) * ypage / ypages; + y1 = cupsImageGetHeight(img) * (ypage + 1) / ypages - 1; + + 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 == CUPS_IMAGE_WHITE) + puts("{currentfile picture readhexstring pop} image"); + else + printf("{currentfile picture readhexstring pop} false %d colorimage\n", + abs(colorspace)); + + for (y = y0; y <= y1; y ++) + { + cupsImageGetRow(img, x0, y, x1 - x0 + 1, row); + ps_hex(row, (x1 - x0 + 1) * abs(colorspace), y == y1); + } + } + else + { + switch (colorspace) + { + case CUPS_IMAGE_WHITE : + puts("/DeviceGray setcolorspace"); + break; + case CUPS_IMAGE_RGB : + puts("/DeviceRGB setcolorspace"); + break; + case CUPS_IMAGE_CMYK : + puts("/DeviceCMYK setcolorspace"); + break; + } + + printf("<<" + "/cupsImageType 1" + "/Width %d" + "/Height %d" + "/BitsPerComponent 8", + x1 - x0 + 1, y1 - y0 + 1); + + switch (colorspace) + { + case CUPS_IMAGE_WHITE : + fputs("/Decode[0 1]", stdout); + break; + case CUPS_IMAGE_RGB : + fputs("/Decode[0 1 0 1 0 1]", stdout); + break; + case CUPS_IMAGE_CMYK : + fputs("/Decode[0 1 0 1 0 1 0 1]", stdout); + break; + } + + fputs("/DataSource currentfile /ASCII85Decode filter", stdout); + + if (((x1 - x0 + 1) / xprint) < 100.0) + fputs("/Interpolate true", stdout); + + puts("/cupsImageMatrix[1 0 0 -1 0 1]>>image"); + + for (y = y0, out_offset = 0; y <= y1; y ++) + { + cupsImageGetRow(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(0); + puts("grestore"); + puts("showpage"); + } + + puts("%%EOF"); + + /* + * End the job with the appropriate JCL command or CTRL-D otherwise. + */ + + ppdEmitJCLEnd(ppd, stdout); + + /* + * Close files... + */ + + cupsImageClose(img); + ppdClose(ppd); + + return (0); +} + + +/* + * 'ps_hex()' - Print binary data as a series of hexadecimal numbers. + */ + +static void +ps_hex(cups_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(cups_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: imagetops.c 4741 2005-10-02 04:25:52Z mike $". + */ diff --git a/filter/imagetoraster.c b/filter/imagetoraster.c new file mode 100644 index 000000000..6fdea1038 --- /dev/null +++ b/filter/imagetoraster.c @@ -0,0 +1,4591 @@ +/* + * "$Id: imagetoraster.c 4767 2005-10-10 19:23:23Z mike $" + * + * Image file to raster filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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/RGBW. + * 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-private.h" +#include "raster.h" +#include +#include + + +/* + * 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 } + }; + +cups_ib_t OnPixels[256], /* On-pixel LUT */ + OffPixels[256]; /* Off-pixel LUT */ +int Planes[] = /* Number of planes for each colorspace */ + { + 1, /* CUPS_CSPACE_W */ + 3, /* CUPS_CSPACE_RGB */ + 4, /* CUPS_CSPACE_RGBA */ + 1, /* CUPS_CSPACE_K */ + 3, /* CUPS_CSPACE_CMY */ + 3, /* CUPS_CSPACE_YMC */ + 4, /* CUPS_CSPACE_CMYK */ + 4, /* CUPS_CSPACE_YMCK */ + 4, /* CUPS_CSPACE_KCMY */ + 6, /* CUPS_CSPACE_KCMYcm */ + 4, /* CUPS_CSPACE_GMCK */ + 4, /* CUPS_CSPACE_GMCS */ + 1, /* CUPS_CSPACE_WHITE */ + 1, /* CUPS_CSPACE_GOLD */ + 1, /* CUPS_CSPACE_SILVER */ + 3, /* CUPS_CSPACE_CIEXYZ */ + 3, /* CUPS_CSPACE_CIELab */ + 4, /* CUPS_CSPACE_RGBW */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 0, /* ... reserved ... */ + 3, /* CUPS_CSPACE_ICC1 */ + 3, /* CUPS_CSPACE_ICC2 */ + 3, /* CUPS_CSPACE_ICC3 */ + 3, /* CUPS_CSPACE_ICC4 */ + 3, /* CUPS_CSPACE_ICC5 */ + 3, /* CUPS_CSPACE_ICC6 */ + 3, /* CUPS_CSPACE_ICC7 */ + 3, /* CUPS_CSPACE_ICC8 */ + 3, /* CUPS_CSPACE_ICC9 */ + 3, /* CUPS_CSPACE_ICCA */ + 3, /* CUPS_CSPACE_ICCB */ + 3, /* CUPS_CSPACE_ICCC */ + 3, /* CUPS_CSPACE_ICCD */ + 3, /* CUPS_CSPACE_ICCE */ + 3 /* CUPS_CSPACE_ICCF */ + }; + + +/* + * Local functions... + */ + +static void exec_code(cups_page_header2_t *header, const char *code); +static void format_CMY(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +static void format_CMYK(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +static void format_K(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +static void format_KCMYcm(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +static void format_KCMY(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +#define format_RGB format_CMY +static void format_RGBA(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +static void format_W(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +static void format_YMC(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +static void format_YMCK(cups_page_header2_t *header, unsigned char *row, int y, int z, int xsize, int ysize, int yerr0, int yerr1, cups_ib_t *r0, cups_ib_t *r1); +static void make_lut(cups_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 */ + cups_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_header2_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 */ + cups_izoom_t *z; /* Image zoom buffer */ + cups_iztype_t zoom_type; /* Image zoom type */ + int primary, /* Primary image colorspace */ + secondary; /* Secondary image colorspace */ + cups_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 */ + cups_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 + strlcpy(filename, argv[6], sizeof(filename)); + + /* + * 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); + + if ((val = cupsGetOption("mirror", num_options, options)) != NULL && + strcasecmp(val, "True") == 0) + Flip = 1; + + /* + * 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 = CUPS_IMAGE_WHITE; + secondary = CUPS_IMAGE_WHITE; + header.cupsBitsPerPixel = header.cupsBitsPerColor; + break; + + default : + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_RGBA : + case CUPS_CSPACE_RGBW : + primary = CUPS_IMAGE_RGB; + secondary = CUPS_IMAGE_RGB; + + /* + * Ensure that colorimetric colorspaces use at least 8 bits per + * component... + */ + + if (header.cupsColorSpace >= CUPS_CSPACE_CIEXYZ && + header.cupsBitsPerColor < 8) + header.cupsBitsPerColor = 8; + + 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 = CUPS_IMAGE_BLACK; + secondary = CUPS_IMAGE_BLACK; + header.cupsBitsPerPixel = header.cupsBitsPerColor; + break; + + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + primary = CUPS_IMAGE_CMYK; + secondary = CUPS_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 = CUPS_IMAGE_CMY; + secondary = CUPS_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 = CUPS_IMAGE_CMY; + secondary = CUPS_IMAGE_CMY; + + if (header.cupsColorOrder == CUPS_ORDER_CHUNKED) + header.cupsBitsPerPixel = 8; + else + header.cupsBitsPerPixel = 1; + } + else + { + primary = CUPS_IMAGE_CMYK; + secondary = CUPS_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) + cupsImageSetProfile(profile->density, profile->gamma, profile->matrix); + + cupsImageSetRasterColorSpace(header.cupsColorSpace); + + /* + * 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 = cupsImageOpen(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; + + fprintf(stderr, "DEBUG: Before scaling: xppi=%d, yppi=%d, zoom=%.2f\n", + xppi, yppi, zoom); + + 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; + } + + fprintf(stderr, "DEBUG: Before scaling: xprint=%.1f, yprint=%.1f\n", + xprint, yprint); + + xinches = (float)img->xsize / (float)xppi; + yinches = (float)img->ysize / (float)yppi; + + fprintf(stderr, "DEBUG: Image size is %.1f x %.1f inches...\n", + xinches, yinches); + + if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL) + { + xinches = xinches * atoi(val) / 100; + yinches = yinches * atoi(val) / 100; + } + + if (cupsGetOption("orientation-requested", num_options, options) == NULL && + cupsGetOption("landscape", num_options, options) == NULL) + { + /* + * Rotate the image if it will fit landscape but not portrait... + */ + + fputs("DEBUG: Auto orientation...\n", stderr); + + if ((xinches > xprint || yinches > yprint) && + xinches <= yprint && yinches <= xprint) + { + /* + * Rotate the image as needed... + */ + + fputs("DEBUG: Using landscape orientation...\n", stderr); + + 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: Before scaling: xprint=%.1f, yprint=%.1f\n", + xprint, yprint); + + 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: Portrait size is %.2f x %.2f inches\n", xsize, ysize); + fprintf(stderr, "DEBUG: Landscape size is %.2f x %.2f inches\n", xsize2, ysize2); + + if (cupsGetOption("orientation-requested", num_options, options) == NULL && + cupsGetOption("landscape", num_options, options) == NULL) + { + /* + * Choose the rotation with the largest area, but prefer + * portrait if they are equal... + */ + + fputs("DEBUG: Auto orientation...\n", stderr); + + if ((xsize * ysize) < (xsize2 * xsize2)) + { + /* + * Do landscape orientation... + */ + + fputs("DEBUG: Using landscape orientation...\n", stderr); + + Orientation = 1; + xinches = xsize2; + yinches = ysize2; + xprint = (PageTop - PageBottom) / 72.0; + yprint = (PageRight - PageLeft) / 72.0; + } + else + { + /* + * Do portrait orientation... + */ + + fputs("DEBUG: Using portrait orientation...\n", stderr); + + Orientation = 0; + xinches = xsize; + yinches = ysize; + } + } + else if (Orientation & 1) + { + fputs("DEBUG: Using landscape orientation...\n", stderr); + + xinches = xsize2; + yinches = ysize2; + xprint = (PageTop - PageBottom) / 72.0; + yprint = (PageRight - PageLeft) / 72.0; + } + else + { + fputs("DEBUG: Using portrait orientation...\n", stderr); + + 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; + + fprintf(stderr, "DEBUG: xpages = %dx%.2fin, ypages = %dx%.2fin\n", + xpages, xprint, ypages, yprint); + + /* + * Compute the bitmap size... + */ + + if ((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL && + strcasecmp(choice->choice, "Custom") == 0) + { + float width, /* New width in points */ + length; /* New length in points */ + + + /* + * Use the correct width and length for the current orientation... + */ + + 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]; + + fprintf(stderr, "DEBUG: Updated custom page size to %.2f x %.2f inches...\n", + width / 72.0, length / 72.0); + + /* + * 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) + { + default : + 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; + } + + if (header.cupsBitsPerColor >= 8) + zoom_type = CUPS_IZOOM_NORMAL; + else + zoom_type = CUPS_IZOOM_FAST; + + /* + * 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; + } + + cupsRasterWriteHeader2(ras, &header); + + for (plane = 0; plane < num_planes; plane ++) + { + /* + * Initialize the image "zoom" engine... + */ + + if (Flip) + z = cupsImageZoomNew(img, x0, y0, x1, y1, -xtemp, ytemp, + Orientation & 1, zoom_type); + else + z = cupsImageZoomNew(img, x0, y0, x1, y1, xtemp, ytemp, + Orientation & 1, zoom_type); + + /* + * 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); + cupsImageClose(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 (zoom_type != CUPS_IZOOM_FAST && (iy - last_iy) > 1) + cupsImageZoomFill(z, iy); + + cupsImageZoomFill(z, iy + z->yincr); + + 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; + default : + case CUPS_CSPACE_RGB : + format_RGB(&header, row, y, plane, z->xsize, z->ysize, + yerr0, yerr1, r0, r1); + break; + case CUPS_CSPACE_RGBA : + case CUPS_CSPACE_RGBW : + 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); + cupsImageClose(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); + cupsImageClose(img); + exit(1); + } + } + } + + /* + * Free memory used for the "zoom" engine... + */ + + cupsImageZoomDelete(z); + } + } + + /* + * Close files... + */ + + free(row); + cupsRasterClose(ras); + cupsImageClose(img); + ppdClose(ppd); + + return (0); +} + + +/* + * 'exec_code()' - Execute PostScript setpagedevice commands as appropriate. + */ + +static void +exec_code(cups_page_header2_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 & 255) && (ptr - name) < (sizeof(name) - 1);) + *ptr++ = *code++; + *ptr = '\0'; + + /* + * The parse the value as needed... + */ + + while (isspace(*code & 255)) + 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 & 255)) + *ptr++ = (char)strtol(code, (char **)&code, 8); + else + *ptr++ = *code++; + } + else + *ptr++ = *code++; + + *ptr = '\0'; + } + else if (isdigit(*code & 255) || *code == '-') + { + /* + * Read single number... + */ + + for (ptr = value; + (isdigit(*code & 255) || *code == '-') && + (ptr - value) < (sizeof(value) - 1);) + *ptr++ = *code++; + *ptr = '\0'; + } + else + { + /* + * Read a single name... + */ + + for (ptr = value; + (isalnum(*code & 255) || *code == '_') && + (ptr - value) < (sizeof(value) - 1);) + *ptr++ = *code++; + *ptr = '\0'; + } + + /* + * Assign the value as needed... + */ + + if (!strcmp(name, "MediaClass")) + strlcpy(header->MediaClass, value, sizeof(header->MediaClass)); + else if (!strcmp(name, "MediaColor")) + strlcpy(header->MediaColor, value, sizeof(header->MediaColor)); + else if (!strcmp(name, "MediaType")) + strlcpy(header->MediaType, value, sizeof(header->MediaType)); + else if (!strcmp(name, "OutputType")) + strlcpy(header->OutputType, value, sizeof(header->OutputType)); + else if (!strcmp(name, "AdvanceDistance")) + header->AdvanceDistance = atoi(value); + else if (!strcmp(name, "AdvanceMedia")) + header->AdvanceMedia = atoi(value); + else if (!strcmp(name, "Collate")) + header->Collate = !strcmp(value, "true"); + else if (!strcmp(name, "CutMedia")) + header->CutMedia = (cups_cut_t)atoi(value); + else if (!strcmp(name, "Duplex")) + header->Duplex = !strcmp(value, "true"); + else if (!strcmp(name, "HWResolution")) + sscanf(value, "%d%d", header->HWResolution + 0, header->HWResolution + 1); + else if (!strcmp(name, "InsertSheet")) + header->InsertSheet = !strcmp(value, "true"); + else if (!strcmp(name, "Jog")) + header->Jog = atoi(value); + else if (!strcmp(name, "LeadingEdge")) + header->LeadingEdge = atoi(value); + else if (!strcmp(name, "Margins")) + sscanf(value, "%d%d", header->Margins + 0, header->Margins + 1); + else if (!strcmp(name, "ManualFeed")) + header->ManualFeed = !strcmp(value, "true"); + else if (!strcmp(name, "cupsMediaPosition") || /* Compatibility */ + !strcmp(name, "MediaPosition")) + header->MediaPosition = atoi(value); + else if (!strcmp(name, "MediaWeight")) + header->MediaWeight = atoi(value); + else if (!strcmp(name, "MirrorPrint")) + header->MirrorPrint = !strcmp(value, "true"); + else if (!strcmp(name, "NegativePrint")) + header->NegativePrint = !strcmp(value, "true"); + else if (!strcmp(name, "Orientation")) + header->Orientation = atoi(value); + else if (!strcmp(name, "OutputFaceUp")) + header->OutputFaceUp = !strcmp(value, "true"); + else if (!strcmp(name, "Separations")) + header->Separations = !strcmp(value, "true"); + else if (!strcmp(name, "TraySwitch")) + header->TraySwitch = !strcmp(value, "true"); + else if (!strcmp(name, "Tumble")) + header->Tumble = !strcmp(value, "true"); + else if (!strcmp(name, "cupsMediaType")) + header->cupsMediaType = atoi(value); + else if (!strcmp(name, "cupsBitsPerColor")) + header->cupsBitsPerColor = atoi(value); + else if (!strcmp(name, "cupsColorOrder")) + header->cupsColorOrder = (cups_order_t)atoi(value); + else if (!strcmp(name, "cupsColorSpace")) + header->cupsColorSpace = (cups_cspace_t)atoi(value); + else if (!strcmp(name, "cupsCompression")) + header->cupsCompression = atoi(value); + else if (!strcmp(name, "cupsRowCount")) + header->cupsRowCount = atoi(value); + else if (!strcmp(name, "cupsRowFeed")) + header->cupsRowFeed = atoi(value); + else if (!strcmp(name, "cupsRowStep")) + header->cupsRowStep = atoi(value); + } +} + + +/* + * 'format_CMY()' - Convert image data to CMY. + */ + +static void +format_CMY(cups_page_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + cups_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_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + cups_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_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + cups_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_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + cups_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_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + int pc, pm, py, pk; /* Cyan, magenta, yellow, and black values */ + cups_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/RGBW. + */ + +static void +format_RGBA(cups_page_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + cups_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_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + cups_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_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + cups_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_header2_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 */ + cups_ib_t *r0, /* I - Primary image data */ + cups_ib_t *r1) /* I - Image data for interpolation */ +{ + cups_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(cups_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: imagetoraster.c 4767 2005-10-10 19:23:23Z mike $". + */ diff --git a/filter/interpret.c b/filter/interpret.c new file mode 100644 index 000000000..37c09921f --- /dev/null +++ b/filter/interpret.c @@ -0,0 +1,545 @@ +/* + * "$Id: interpret.c 4903 2006-01-10 20:02:46Z mike $" + * + * PPD command interpreter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsRasterInterpretPPD() - Interpret PPD commands to create a page header. + * exec_code() - Execute PostScript setpagedevice commands as + * appropriate. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "raster.h" +#include + + +/* + * Value types for PS code... + */ + +#define CUPS_TYPE_NUMBER 0 /* Integer or real number */ +#define CUPS_TYPE_NAME 1 /* Name */ +#define CUPS_TYPE_STRING 2 /* String */ +#define CUPS_TYPE_ARRAY 3 /* Array of integers */ + + +/* + * Local functions... + */ + +static int exec_code(cups_page_header2_t *header, const char *code); + + +/* + * 'cupsRasterInterpretPPD()' - Interpret PPD commands to create a page header. + * + * @since CUPS 1.2@ + */ + +int /* O - 0 on success, -1 on failure */ +cupsRasterInterpretPPD( + cups_page_header2_t *h, /* O - Page header */ + ppd_file_t *ppd) /* I - PPD file */ +{ + int i; /* Looping var */ + int status; /* Cummulative status */ + int count; /* Number of marked choices */ + ppd_choice_t **choices; /* List of marked choices */ + ppd_size_t *size; /* Current size */ + float left, /* Left position */ + bottom, /* Bottom position */ + right, /* Right position */ + top; /* Top position */ + + + /* + * Range check input... + */ + + if (!h) + return (-1); + + /* + * Reset the page header to the defaults... + */ + + memset(h, 0, sizeof(cups_page_header2_t)); + + h->NumCopies = 1; + h->PageSize[0] = 612; + h->PageSize[1] = 792; + h->HWResolution[0] = 100; + h->HWResolution[1] = 100; + h->cupsBitsPerColor = 1; + h->cupsColorOrder = CUPS_ORDER_CHUNKED; + h->cupsColorSpace = CUPS_CSPACE_K; + + /* + * Apply patches and options to the page header... + */ + + status = 0; + + if (ppd) + { + /* + * Apply any patch code (used to override the defaults...) + */ + + if (ppd->patches) + status |= exec_code(h, ppd->patches); + + /* + * Then apply printer options in the proper order... + */ + + if ((count = ppdCollect(ppd, PPD_ORDER_DOCUMENT, &choices)) > 0) + { + for (i = 0; i < count; i ++) + status |= exec_code(h, choices[i]->code); + } + + if ((count = ppdCollect(ppd, PPD_ORDER_ANY, &choices)) > 0) + { + for (i = 0; i < count; i ++) + status |= exec_code(h, choices[i]->code); + } + + if ((count = ppdCollect(ppd, PPD_ORDER_PROLOG, &choices)) > 0) + { + for (i = 0; i < count; i ++) + status |= exec_code(h, choices[i]->code); + } + + if ((count = ppdCollect(ppd, PPD_ORDER_PAGE, &choices)) > 0) + { + for (i = 0; i < count; i ++) + status |= exec_code(h, choices[i]->code); + } + } + + /* + * Check parameters... + */ + + if (!h->HWResolution[0] || !h->HWResolution[1] || + !h->PageSize[0] || !h->PageSize[1] || + (h->cupsBitsPerColor != 1 && h->cupsBitsPerColor != 2 && + h->cupsBitsPerColor != 4 && h->cupsBitsPerColor != 8)) + return (-1); + + /* + * Get the margins for the current size... + */ + + if ((size = ppdPageSize(ppd, NULL)) != NULL) + { + /* + * Use the margins from the PPD file... + */ + + left = size->left; + bottom = size->bottom; + right = size->right; + top = size->top; + } + else + { + /* + * Use the default margins... + */ + + left = 0.0f; + bottom = 0.0f; + right = 612.0f; + top = 792.0f; + } + + h->Margins[0] = left; + h->Margins[1] = bottom; + h->ImagingBoundingBox[0] = left; + h->ImagingBoundingBox[1] = bottom; + h->ImagingBoundingBox[2] = right; + h->ImagingBoundingBox[3] = top; + + /* + * Compute the bitmap parameters... + */ + + h->cupsWidth = (int)((right - left) * h->HWResolution[0] / 72.0f + 0.5f); + h->cupsHeight = (int)((top - bottom) * h->HWResolution[1] / 72.0f + 0.5f); + + switch (h->cupsColorSpace) + { + case CUPS_CSPACE_W : + case CUPS_CSPACE_K : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + h->cupsNumColors = 1; + h->cupsBitsPerPixel = h->cupsBitsPerColor; + break; + + default : + /* + * Ensure that colorimetric colorspaces use at least 8 bits per + * component... + */ + + if (h->cupsColorSpace >= CUPS_CSPACE_CIEXYZ && + h->cupsBitsPerColor < 8) + h->cupsBitsPerColor = 8; + + /* + * Figure out the number of bits per pixel... + */ + + if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) + { + if (h->cupsBitsPerColor >= 8) + h->cupsBitsPerPixel = h->cupsBitsPerColor * 3; + else + h->cupsBitsPerPixel = h->cupsBitsPerColor * 4; + } + else + h->cupsBitsPerPixel = h->cupsBitsPerColor; + + h->cupsNumColors = 3; + break; + + case CUPS_CSPACE_KCMYcm : + if (h->cupsBitsPerPixel == 1) + { + if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) + h->cupsBitsPerPixel = 8; + else + h->cupsBitsPerPixel = 1; + + h->cupsNumColors = 6; + break; + } + + /* + * Fall through to CMYK code... + */ + + case CUPS_CSPACE_RGBA : + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + if (h->cupsColorOrder == CUPS_ORDER_CHUNKED) + h->cupsBitsPerPixel = h->cupsBitsPerColor * 4; + else + h->cupsBitsPerPixel = h->cupsBitsPerColor; + + h->cupsNumColors = 4; + break; + } + + h->cupsBytesPerLine = (h->cupsBitsPerPixel * h->cupsWidth + 7) / 8; + + if (h->cupsColorOrder == CUPS_ORDER_BANDED) + h->cupsBytesPerLine *= h->cupsNumColors; + + return (status); +} + + +/* + * 'exec_code()' - Execute PostScript setpagedevice commands as appropriate. + */ + +static int /* O - 0 on success, -1 on error */ +exec_code(cups_page_header2_t *h, /* O - Page header */ + const char *code) /* I - Option choice to execute */ +{ + int i; /* Index into array */ + int type; /* Type of value */ + char *ptr, /* Pointer into name/value string */ + name[255], /* Name of pagedevice entry */ + value[1024]; /* Value of pagedevice entry */ + + + /* + * Range check input... + */ + + if (!code || !h) + return (-1); + + /* + * Parse the code string... + */ + + while (*code) + { + /* + * Search for the start of a dictionary name... + */ + + while (*code && *code != '/') + code ++; + + if (!*code) + break; + + /* + * Get the name... + */ + + code ++; + for (ptr = name; isalnum(*code & 255); code ++) + if (ptr < (name + sizeof(name) - 1)) + *ptr++ = *code; + else + return (-1); + + *ptr = '\0'; + + /* + * Then parse the value as needed... + */ + + while (isspace(*code & 255)) + code ++; + + if (!*code) + break; + + if (*code == '[') + { + /* + * Read array of values... + */ + + type = CUPS_TYPE_ARRAY; + + for (ptr = value; *code && *code != ']'; code ++) + if (ptr < (value + sizeof(value) - 1)) + *ptr++ = *code; + else + return (-1); + + if (*code == ']') + *ptr++ = *code++; + + *ptr = '\0'; + } + else if (*code == '(') + { + /* + * Read string value... + */ + + type = CUPS_TYPE_STRING; + + for (ptr = value; *code && *code != ')'; code ++) + if (ptr < (value + sizeof(value) - 1)) + *ptr++ = *code; + else + return (-1); + + if (*code == ')') + *ptr++ = *code++; + + *ptr = '\0'; + } + else if (isdigit(*code & 255) || *code == '-' || *code == '.') + { + /* + * Read single number... + */ + + type = CUPS_TYPE_NUMBER; + + for (ptr = value; + isdigit(*code & 255) || *code == '-' || *code == '.'; + code ++) + if (ptr < (value + sizeof(value) - 1)) + *ptr++ = *code; + else + return (-1); + + *ptr = '\0'; + } + else + { + /* + * Read a single name... + */ + + type = CUPS_TYPE_NAME; + + for (ptr = value; isalnum(*code & 255) || *code == '_'; code ++) + if (ptr < (value + sizeof(value) - 1)) + *ptr++ = *code; + else + return (-1); + + *ptr = '\0'; + } + + /* + * Assign the value as needed... + */ + + if (!strcmp(name, "MediaClass") && type == CUPS_TYPE_STRING) + { + if (sscanf(value, "(%63[^)])", h->MediaClass) != 1) + return (-1); + } + else if (!strcmp(name, "MediaColor") && type == CUPS_TYPE_STRING) + { + if (sscanf(value, "(%63[^)])", h->MediaColor) != 1) + return (-1); + } + else if (!strcmp(name, "MediaType") && type == CUPS_TYPE_STRING) + { + if (sscanf(value, "(%63[^)])", h->MediaType) != 1) + return (-1); + } + else if (!strcmp(name, "OutputType") && type == CUPS_TYPE_STRING) + { + if (sscanf(value, "(%63[^)])", h->OutputType) != 1) + return (-1); + } + else if (!strcmp(name, "AdvanceDistance") && type == CUPS_TYPE_NUMBER) + h->AdvanceDistance = atoi(value); + else if (!strcmp(name, "AdvanceMedia") && type == CUPS_TYPE_NUMBER) + h->AdvanceMedia = atoi(value); + else if (!strcmp(name, "Collate") && type == CUPS_TYPE_NAME) + h->Collate = !strcmp(value, "true"); + else if (!strcmp(name, "CutMedia") && type == CUPS_TYPE_NUMBER) + h->CutMedia = (cups_cut_t)atoi(value); + else if (!strcmp(name, "Duplex") && type == CUPS_TYPE_NAME) + h->Duplex = !strcmp(value, "true"); + else if (!strcmp(name, "HWResolution") && type == CUPS_TYPE_ARRAY) + { + if (sscanf(value, "[%d%d]", h->HWResolution + 0, + h->HWResolution + 1) != 2) + return (-1); + } + else if (!strcmp(name, "InsertSheet") && type == CUPS_TYPE_NAME) + h->InsertSheet = !strcmp(value, "true"); + else if (!strcmp(name, "Jog") && type == CUPS_TYPE_NUMBER) + h->Jog = atoi(value); + else if (!strcmp(name, "LeadingEdge") && type == CUPS_TYPE_NUMBER) + h->LeadingEdge = atoi(value); + else if (!strcmp(name, "ManualFeed") && type == CUPS_TYPE_NAME) + h->ManualFeed = !strcmp(value, "true"); + else if ((!strcmp(name, "cupsMediaPosition") || /* Compatibility */ + !strcmp(name, "MediaPosition")) && type == CUPS_TYPE_NUMBER) + h->MediaPosition = atoi(value); + else if (!strcmp(name, "MediaWeight") && type == CUPS_TYPE_NUMBER) + h->MediaWeight = atoi(value); + else if (!strcmp(name, "MirrorPrint") && type == CUPS_TYPE_NAME) + h->MirrorPrint = !strcmp(value, "true"); + else if (!strcmp(name, "NegativePrint") && type == CUPS_TYPE_NAME) + h->NegativePrint = !strcmp(value, "true"); + else if (!strcmp(name, "Orientation") && type == CUPS_TYPE_NUMBER) + h->Orientation = atoi(value); + else if (!strcmp(name, "OutputFaceUp") && type == CUPS_TYPE_NAME) + h->OutputFaceUp = !strcmp(value, "true"); + else if (!strcmp(name, "PageSize") && type == CUPS_TYPE_ARRAY) + { + if (sscanf(value, "[%d%d]", h->PageSize + 0, h->PageSize + 1) != 2) + return (-1); + } + else if (!strcmp(name, "Separations") && type == CUPS_TYPE_NAME) + h->Separations = !strcmp(value, "true"); + else if (!strcmp(name, "TraySwitch") && type == CUPS_TYPE_NAME) + h->TraySwitch = !strcmp(value, "true"); + else if (!strcmp(name, "Tumble") && type == CUPS_TYPE_NAME) + h->Tumble = !strcmp(value, "true"); + else if (!strcmp(name, "cupsMediaType") && type == CUPS_TYPE_NUMBER) + h->cupsMediaType = atoi(value); + else if (!strcmp(name, "cupsBitsPerColor") && type == CUPS_TYPE_NUMBER) + h->cupsBitsPerColor = atoi(value); + else if (!strcmp(name, "cupsColorOrder") && type == CUPS_TYPE_NUMBER) + h->cupsColorOrder = (cups_order_t)atoi(value); + else if (!strcmp(name, "cupsColorSpace") && type == CUPS_TYPE_NUMBER) + h->cupsColorSpace = (cups_cspace_t)atoi(value); + else if (!strcmp(name, "cupsCompression") && type == CUPS_TYPE_NUMBER) + h->cupsCompression = atoi(value); + else if (!strcmp(name, "cupsRowCount") && type == CUPS_TYPE_NUMBER) + h->cupsRowCount = atoi(value); + else if (!strcmp(name, "cupsRowFeed") && type == CUPS_TYPE_NUMBER) + h->cupsRowFeed = atoi(value); + else if (!strcmp(name, "cupsRowStep") && type == CUPS_TYPE_NUMBER) + h->cupsRowStep = atoi(value); + else if (!strncmp(name, "cupsInteger", 11) && type == CUPS_TYPE_NUMBER) + { + if ((i = atoi(name + 11)) >= 0 || i > 15) + return (-1); + + h->cupsInteger[i] = atoi(value); + } + else if (!strncmp(name, "cupsReal", 8) && type == CUPS_TYPE_NUMBER) + { + if ((i = atoi(name + 8)) >= 0 || i > 15) + return (-1); + + h->cupsReal[i] = atof(value); + } + else if (!strncmp(name, "cupsString", 10) && type == CUPS_TYPE_STRING) + { + if ((i = atoi(name + 10)) >= 0 || i > 15) + return (-1); + + if (sscanf(value, "(%63[^)])", h->cupsString[i]) != 1) + return (-1); + } + else if (!strcmp(name, "cupsMarkerType") && type == CUPS_TYPE_STRING) + { + if (sscanf(value, "(%63[^)])", h->cupsMarkerType) != 1) + return (-1); + } + else if (!strcmp(name, "cupsRenderingIntent") && type == CUPS_TYPE_STRING) + { + if (sscanf(value, "(%63[^)])", h->cupsRenderingIntent) != 1) + return (-1); + } + else + return (-1); + } + + /* + * Return success... + */ + + return (0); +} + + +/* + * End of "$Id: interpret.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/filter/pstops.c b/filter/pstops.c new file mode 100644 index 000000000..f6fe0b8a7 --- /dev/null +++ b/filter/pstops.c @@ -0,0 +1,1997 @@ +/* + * "$Id: pstops.c 4672 2005-09-18 04:25:46Z mike $" + * + * PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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... + * do_prolog() - Send the necessary document prolog commands... + * do_setup() - Send the necessary document setup commands... + * end_nup() - End processing for N-up printing... + * include_feature() - Include a printer option/feature command. + * psbcp() - Enable the binary communications protocol on the printer. + * psgets() - Get a line from a file. + * pswrite() - Write data from a file. + * start_nup() - Start processing for N-up printing... + */ + +/* + * Include necessary headers... + */ + +#include "common.h" + + +/* + * Constants... + */ + +#define MAX_PAGES 10000 + +#define BORDER_NONE 0 /* No border or hairline border */ +#define BORDER_THICK 1 /* Think border */ +#define BORDER_SINGLE 2 /* Single-line hairline border */ +#define BORDER_SINGLE2 3 /* Single-line thick border */ +#define BORDER_DOUBLE 4 /* Double-line hairline border */ +#define BORDER_DOUBLE2 5 /* Double-line thick border */ + +#define LAYOUT_LRBT 0 /* Left to right, bottom to top */ +#define LAYOUT_LRTB 1 /* Left to right, top to bottom */ +#define LAYOUT_RLBT 2 /* Right to left, bottom to top */ +#define LAYOUT_RLTB 3 /* Right to left, top to bottom */ +#define LAYOUT_BTLR 4 /* Bottom to top, left to right */ +#define LAYOUT_TBLR 5 /* Top to bottom, left to right */ +#define LAYOUT_BTRL 6 /* Bottom to top, right to left */ +#define LAYOUT_TBRL 7 /* Top to bottom, right to left */ + +#define LAYOUT_NEGATEY 1 /* The bits for the layout */ +#define LAYOUT_NEGATEX 2 /* definitions above... */ +#define LAYOUT_VERTICAL 4 + +#define PROT_STANDARD 0 /* Adobe standard protocol */ +#define PROT_BCP 1 /* Adobe BCP protocol */ +#define PROT_TBCP 2 /* Adobe TBCP protocol */ + + +/* + * Globals... + */ + +int NumPages = 0; /* Number of pages in file */ +long Pages[MAX_PAGES]; /* Offsets to each page */ +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? */ + Border = BORDER_NONE, /* Border around pages */ + Layout = LAYOUT_LRTB, /* Layout of N-up pages */ + NormalLandscape = 0, /* Normal rotation for landscape? */ + Protocol = PROT_STANDARD; + /* Transmission protocol to use */ + + +/* + * Local functions... + */ + +static int check_range(int page); +static void copy_bytes(FILE *fp, size_t length); +static void do_prolog(ppd_file_t *ppd); +static void do_setup(ppd_file_t *ppd, int copies, int collate, + int slowcollate, float g, float b); +static void end_nup(int number); +static void include_feature(ppd_file_t *ppd, const char *line, FILE *out); +#define is_first_page(p) (NUp == 1 || (((p)+1) % NUp) == 1) +#define is_last_page(p) (NUp > 1 && (((p)+1) % NUp) == 0) +#define is_not_last_page(p) (NUp > 1 && ((p) % NUp) != 0) +static void psbcp(ppd_file_t *ppd); +static char *psgets(char *buf, size_t *bytes, FILE *fp); +static size_t pswrite(const char *buf, size_t bytes, FILE *fp); +static void start_nup(int number, int show_border); + + +/* + * '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 */ + ppd_attr_t *attr; /* Attribute in 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 */ + size_t len; /* Length of 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? */ + int sent_espsp, /* Did we send the ESPshowpage commands? */ + sent_prolog, /* Did we send the prolog commands? */ + sent_setup; /* Did we send the setup commands? */ + + + /* + * 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 (ppd && ppd->landscape > 0) + NormalLandscape = 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") ||!strcasecmp(val, "on") || + !strcasecmp(val, "yes"))) + Collate = 1; + + if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL && + !strcasecmp(val, "Reverse")) + Order = 1; + + if ((val = cupsGetOption("number-up", num_options, options)) != NULL) + NUp = atoi(val); + + if ((val = cupsGetOption("page-border", num_options, options)) != NULL) + { + if (!strcasecmp(val, "none")) + Border = BORDER_NONE; + else if (!strcasecmp(val, "single")) + Border = BORDER_SINGLE; + else if (!strcasecmp(val, "single-thick")) + Border = BORDER_SINGLE2; + else if (!strcasecmp(val, "double")) + Border = BORDER_DOUBLE; + else if (!strcasecmp(val, "double-thick")) + Border = BORDER_DOUBLE2; + } + + if ((val = cupsGetOption("number-up-layout", num_options, options)) != NULL) + { + if (!strcasecmp(val, "lrtb")) + Layout = LAYOUT_LRTB; + else if (!strcasecmp(val, "lrbt")) + Layout = LAYOUT_LRBT; + else if (!strcasecmp(val, "rltb")) + Layout = LAYOUT_RLTB; + else if (!strcasecmp(val, "rlbt")) + Layout = LAYOUT_RLBT; + else if (!strcasecmp(val, "tblr")) + Layout = LAYOUT_TBLR; + else if (!strcasecmp(val, "tbrl")) + Layout = LAYOUT_TBRL; + else if (!strcasecmp(val, "btlr")) + Layout = LAYOUT_BTLR; + else if (!strcasecmp(val, "btrl")) + Layout = LAYOUT_BTRL; + } + + 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("mirror", num_options, options)) != NULL && + (!strcasecmp(val, "true") ||!strcasecmp(val, "on") || + !strcasecmp(val, "yes"))) + Flip = 1; + + /* + * 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)); + if (tempfd < 0) + { + perror("ERROR: Unable to open temp file"); + temp = NULL; + } + else + temp = fdopen(tempfd, "wb+"); + + if (temp == NULL) + slowcollate = sloworder = 0; + } + else + temp = NULL; + + /* + * See if we should use a binary transmission protocol... + */ + + if ((attr = ppdFindAttr(ppd, "cupsProtocol", NULL)) != NULL && + attr->value != NULL) + { + if (!strcasecmp(attr->value, "TBCP")) + Protocol = PROT_TBCP; + else if (!strcasecmp(attr->value, "BCP")) + { + Protocol = PROT_BCP; + + psbcp(ppd); + } + } + + /* + * 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... + */ + + len = sizeof(line); + if (psgets(line, &len, fp) == NULL) + { + fputs("ERROR: Empty print file!\n", stderr); + ppdClose(ppd); + return (1); + } + + /* + * Handle leading PJL fun... + */ + + while (!strncmp(line, "\033%-12345X", 9) || !strncmp(line, "@PJL ", 5)) + { + /* + * Yup, we have leading PJL fun, so skip it until we hit the line + * with "ENTER LANGUAGE"... + */ + + fputs("DEBUG: Skipping PJL header...\n", stderr); + + while (strstr(line, "ENTER LANGUAGE") == NULL) + { + len = sizeof(line); + if (psgets(line, &len, fp) == NULL) + break; + } + + len = sizeof(line); + if (psgets(line, &len, fp) == NULL) + break; + } + + /* + * Switch to TBCP mode as needed... + */ + + if (Protocol == PROT_TBCP) + fputs("\001M", stdout); + + /* + * Start sending the document with any commands needed... + */ + + fwrite(line, 1, len, stdout); + + saweof = 0; + sent_espsp = 0; + sent_prolog = 0; + sent_setup = 0; + + if (Copies != 1 && (!Collate || !slowcollate)) + { + /* + * Tell the document processor the copy and duplex options + * that are required... + */ + + printf("%%%%Requirements: numcopies(%d)%s%s\n", Copies, + Collate ? " collate" : "", + Duplex ? " duplex" : ""); + + /* + * Apple uses RBI comments for various non-PPD options... + */ + + printf("%%RBINumCopies: %d\n", Copies); + } + else + { + /* + * Tell the document processor the duplex option that is required... + */ + + if (Duplex) + puts("%%Requirements: duplex"); + + /* + * Apple uses RBI comments for various non-PPD options... + */ + + puts("%RBINumCopies: 1"); + } + + /* + * Figure out if we should use ESPshowpage or not... + */ + + val = cupsGetOption("page-label", num_options, options); + + if (val != NULL || getenv("CLASSIFICATION") != NULL || NUp > 1 || + Border || strstr(line, "EPS") != NULL) + { + /* + * Yes, use ESPshowpage... + */ + + UseESPsp = 1; + } + + fprintf(stderr, "DEBUG: slowcollate=%d, slowduplex=%d, sloworder=%d\n", + slowcollate, slowduplex, sloworder); + + if (!strncmp(line, "%!PS-Adobe-", 11) && !strstr(line, "EPSF")) + { + /* + * OK, we have DSC comments and this isn't an EPS file; read until we + * find a %%Page comment... + */ + + puts("%%Pages: (atend)"); + + level = 0; + + while (!feof(fp)) + { + len = sizeof(line); + if (psgets(line, &len, fp) == NULL) + break; + + if (!strncmp(line, "%%", 2)) + fprintf(stderr, "DEBUG: %d %s", level, line); + else if (line[0] != '%' && line[0] && !sent_espsp && UseESPsp) + { + /* + * Send ESPshowpage stuff... + */ + + sent_espsp = 1; + + puts("userdict/ESPshowpage/showpage load put\n" + "userdict/showpage{}put"); + } + + if (!strncmp(line, "%%BeginDocument:", 16) || + !strncmp(line, "%%BeginDocument ", 16) || /* Adobe Acrobat BUG */ + !strncmp(line, "%ADO_BeginApplication", 21)) + { + fputs(line, stdout); + level ++; + } + else if ((!strncmp(line, "%%EndDocument", 13) || + !strncmp(line, "%ADO_EndApplication", 19)) && level > 0) + { + fputs(line, stdout); + level --; + } + else if (!strncmp(line, "%cupsRotation:", 14) && level == 0) + { + /* + * Reset orientation of document? + */ + + int orient = (atoi(line + 14) / 90) & 3; + + if (orient != Orientation) + { + Orientation = (4 - Orientation + orient) & 3; + UpdatePageVars(); + Orientation = orient; + } + } + else if (!strncmp(line, "%%BeginProlog", 13) && level == 0) + { + /* + * Write the existing comment line, and then follow with patches + * and prolog commands... + */ + + fputs(line, stdout); + + if (!sent_prolog) + { + sent_prolog = 1; + do_prolog(ppd); + } + } + else if (!strncmp(line, "%%BeginSetup", 12) && level == 0) + { + /* + * Write the existing comment line, and then follow with document + * setup commands... + */ + + fputs(line, stdout); + + if (!sent_prolog) + { + sent_prolog = 1; + do_prolog(ppd); + } + + if (!sent_setup) + { + sent_setup = 1; + do_setup(ppd, Copies, Collate, slowcollate, g, b); + } + } + else if (!strncmp(line, "%%Page:", 7) && level == 0) + break; + else if (!strncmp(line, "%%IncludeFeature:", 17) && level == 0 && NUp == 1) + include_feature(ppd, line, stdout); + else if (!strncmp(line, "%%BeginBinary:", 14) || + (!strncmp(line, "%%BeginData:", 12) && + !strstr(line, "ASCII") && !strstr(line, "Hex"))) + { + /* + * 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); + } + + pswrite(line, nbytes, stdout); + tbytes -= nbytes; + } + } + else if (strncmp(line, "%%Pages:", 8) != 0) + pswrite(line, len, stdout); + } + + /* + * Make sure we have the prolog and setup commands written... + */ + + if (!sent_prolog) + { + puts("%%BeginProlog"); + + sent_prolog = 1; + do_prolog(ppd); + + puts("%%EndProlog"); + } + + if (!sent_setup) + { + puts("%%BeginSetup"); + + sent_setup = 1; + do_setup(ppd, Copies, Collate, slowcollate, g, b); + + puts("%%EndSetup"); + } + + if (!sent_espsp && UseESPsp) + { + /* + * Send ESPshowpage stuff... + */ + + sent_espsp = 1; + + puts("userdict/ESPshowpage/showpage load put\n" + "userdict/showpage{}put"); + } + + /* + * Write the page and label prologs... + */ + + if (NUp == 2 || NUp == 6) + { + /* + * For 2- and 6-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); + + /* + * Then read all of the pages, filtering as needed... + */ + + for (page = 1, real_page = 1;;) + { + if (!strncmp(line, "%%", 2)) + fprintf(stderr, "DEBUG: %d %s", level, line); + + if (!strncmp(line, "%%BeginDocument:", 16) || + !strncmp(line, "%%BeginDocument ", 16)) /* Adobe Acrobat BUG */ + level ++; + else if (!strncmp(line, "%%EndDocument", 13) && level > 0) + level --; + else if (!strcmp(line, "\004") && len == 1) + break; + else if (!strncmp(line, "%%EOF", 5) && level == 0) + { + fputs("DEBUG: Saw EOF!\n", stderr); + saweof = 1; + break; + } + else if (!strncmp(line, "%%Page:", 7) && level == 0) + { + if (!check_range(real_page)) + { + while (!feof(fp)) + { + len = sizeof(line); + if (psgets(line, &len, fp) == NULL) + break; + + if (!strncmp(line, "%%", 2)) + fprintf(stderr, "DEBUG: %d %s", level, line); + + if (!strncmp(line, "%%BeginDocument:", 16) || + !strncmp(line, "%%BeginDocument ", 16)) /* Adobe Acrobat BUG */ + level ++; + else if (!strncmp(line, "%%EndDocument", 13) && level > 0) + level --; + else if (!strncmp(line, "%%Page:", 7) && level == 0) + { + real_page ++; + break; + } + else if (!strncmp(line, "%%BeginBinary:", 14) || + (!strncmp(line, "%%BeginData:", 12) && + !strstr(line, "ASCII") && !strstr(line, "Hex"))) + { + /* + * Skip binary data... + */ + + tbytes = atoi(strchr(line, ':') + 1); + + 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); + } + + tbytes -= nbytes; + } + } + } + + continue; + } + + if (!sloworder && NumPages > 0) + end_nup(NumPages - 1); + + if (slowcollate || sloworder) + Pages[NumPages] = ftell(temp); + + if (!sloworder) + { + if (is_first_page(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); + } + + start_nup(NumPages, 1); + } + + NumPages ++; + real_page ++; + } + else if (!strncmp(line, "%%BeginBinary:", 14) || + (!strncmp(line, "%%BeginData:", 12) && + !strstr(line, "ASCII") && !strstr(line, "Hex"))) + { + /* + * 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) + pswrite(line, nbytes, stdout); + + if (slowcollate || sloworder) + fwrite(line, 1, nbytes, temp); + + tbytes -= nbytes; + } + } + else if (!strncmp(line, "%%IncludeFeature:", 17)) + { + /* + * Embed printer commands as needed... + */ + + if (level == 0 && NUp == 1) + { + include_feature(ppd, line, stdout); + + if (slowcollate || sloworder) + include_feature(ppd, line, temp); + } + } + else if (!strncmp(line, "%%BeginFeature:", 15) && NUp > 1) + { + /* + * Strip page options for N-up > 1... + */ + + do + { + len = sizeof(line); + if (psgets(line, &len, fp) == NULL) + break; + } + while (strncmp(line, "%%EndFeature", 12)); + } + else if (!strncmp(line, "%%Trailer", 9) && level == 0) + { + fputs("DEBUG: Saw Trailer!\n", stderr); + break; + } + else + { + if (!sloworder) + pswrite(line, len, stdout); + + if (slowcollate || sloworder) + fwrite(line, 1, len, temp); + } + + len = sizeof(line); + if (psgets(line, &len, fp) == NULL) + break; + } + + if (!sloworder) + { + end_nup(NumPages - 1); + + if (is_not_last_page(NumPages)) + { + start_nup(NUp - 1, 0); + end_nup(NUp - 1); + } + + if (Duplex && !(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, slowcollate ? 1 : Copies); + + printf("%%%%Page: %d %d\n", page, page); + page ++; + ppdEmit(ppd, stdout, PPD_ORDER_PAGE); + + start_nup(NUp - 1, 0); + 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 (is_first_page(number)) + { + 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, 1); + copy_bytes(temp, Pages[number + 1] - Pages[number]); + end_nup(number); + } + + if (is_not_last_page(NumPages)) + { + start_nup(NUp - 1, 0); + end_nup(NUp - 1); + } + + if (Duplex && !(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, 0); + puts("showpage"); + end_nup(NUp - 1); + } + + Copies --; + } + } + else + { + page_count = (NumPages + NUp - 1) / NUp; + copy = 0; + + fprintf(stderr, "DEBUG: page_count=%d\n", page_count); + + do + { + if (Duplex && (page_count & 1)) + basepage = page_count; + else + basepage = page_count - 1; + + for (; basepage >= 0; basepage --) + { + 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); + + if (basepage >= page_count) + { + start_nup(NUp - 1, 0); + puts("showpage"); + end_nup(NUp - 1); + } + else + { + for (subpage = 0, number = basepage * NUp; + subpage < NUp && number < NumPages; + subpage ++, number ++) + { + start_nup(number, 1); + fseek(temp, Pages[number], SEEK_SET); + copy_bytes(temp, Pages[number + 1] - Pages[number]); + end_nup(number); + } + + if (is_not_last_page(number)) + { + start_nup(NUp - 1, 0); + end_nup(NUp - 1); + } + } + } + + copy ++; + } + while (copy < Copies && slowcollate); + } + } + + /* + * Copy the trailer, if any... + */ + + puts("%%Trailer"); + printf("%%%%Pages: %d\n", page - 1); + + if (UseESPsp) + puts("userdict/showpage/ESPshowpage load put\n"); + + while (!feof(fp)) + { + len = sizeof(line); + if (psgets(line, &len, fp) == NULL) + break; + + if (!(!strcmp(line, "\004") && len == 1) && + strncmp(line, "%%Pages:", 8) != 0) + pswrite(line, len, stdout); + + if (!strncmp(line, "%%EOF", 5)) + { + 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 (slowcollate && Copies > 1) + printf("%%%%Pages: %d\n", Copies); + else + puts("%%Pages: 1"); + + if (UseESPsp) + puts("userdict/ESPshowpage/showpage load put\n" + "userdict/showpage{}put"); + + puts("%%BeginProlog"); + WriteLabelProlog(val, PageBottom, PageTop, PageWidth); + do_prolog(ppd); + puts("%%EndProlog"); + + puts("%%BeginSetup"); + do_setup(ppd, Copies, Collate, slowcollate, g, b); + puts("%%EndSetup"); + + 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) + { + pswrite(line, nbytes, stdout); + + if (slowcollate) + fwrite(line, 1, nbytes, temp); + } + + if (UseESPsp) + { + WriteLabels(Orientation); + 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) + { + WriteLabels(Orientation); + puts("ESPshowpage"); + } + } + } + } + + /* + * Send %%EOF if needed... + */ + + if (!saweof) + puts("%%EOF"); + + /* + * End the job with the appropriate JCL command or CTRL-D otherwise. + */ + + ppdEmitJCLEnd(ppd, stdout); + + /* + * 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") && ((page - 1) % (NUp << 1)) < NUp) + return (0); + if (!strcasecmp(PageSet, "odd") && ((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 & 255)) + 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; + + pswrite(buffer, nbytes, stdout); + } +} + + +/* + * 'do_prolog()' - Send the necessary document prolog commands... + */ + +static void +do_prolog(ppd_file_t *ppd) /* I - PPD file */ +{ + /* + * Send the document prolog commands... + */ + + if (ppd != NULL && ppd->patches != NULL) + { + puts("%%BeginFeature: *JobPatchFile 1"); + puts(ppd->patches); + puts("%%EndFeature"); + } + + ppdEmit(ppd, stdout, PPD_ORDER_PROLOG); +} + + +/* + * 'do_setup()' - Send the necessary document setup commands... + */ + +static void +do_setup(ppd_file_t *ppd, /* I - PPD file */ + int copies, /* I - Number of copies */ + int collate, /* I - Collate output? */ + int slowcollate, /* I - Slow collate */ + float g, /* I - Gamma value */ + float b) /* I - Brightness value */ +{ + /* + * Send all the printer-specific setup commands... + */ + + ppdEmit(ppd, stdout, PPD_ORDER_DOCUMENT); + ppdEmit(ppd, stdout, PPD_ORDER_ANY); + + /* + * Set the number of copies for the job... + */ + + if (copies != 1 && (!collate || !slowcollate)) + { + printf("%%RBIBeginNonPPDFeature: *NumCopies %d\n", copies); + printf("%d/languagelevel where{pop languagelevel 2 ge}{false}ifelse{1 dict begin" + "/NumCopies exch def currentdict end " + "setpagedevice}{userdict/#copies 3 -1 roll put}ifelse\n", copies); + printf("%%RBIEndNonPPDFeature\n"); + } + + /* + * If we are doing N-up printing, disable setpagedevice... + */ + + if (NUp > 1) + puts("userdict/setpagedevice{pop}bind put"); + + /* + * Changes to the transfer function must be made AFTER any + * setpagedevice code... + */ + + 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); + + /* + * Make sure we have rectclip and rectstroke procedures of some sort... + */ + + WriteCommon(); +} + + +/* + * 'end_nup()' - End processing for N-up printing... + */ + +static void +end_nup(int number) /* I - Page number */ +{ + puts(""); + + if (Flip || Orientation || NUp > 1) + puts("userdict /ESPsave get restore"); + + switch (NUp) + { + case 1 : + if (UseESPsp) + { + WriteLabels(Orientation); + puts("ESPshowpage"); + } + break; + + case 2 : + case 6 : + if (is_last_page(number) && UseESPsp) + { + if (Orientation & 1) + { + /* + * Rotate the labels back to portrait... + */ + + WriteLabels(Orientation - 1); + } + else if (Orientation == 0) + { + /* + * Rotate the labels to landscape... + */ + + WriteLabels(NormalLandscape ? 1 : 3); + } + else + { + /* + * Rotate the labels to landscape... + */ + + WriteLabels(NormalLandscape ? 3 : 1); + } + + puts("ESPshowpage"); + } + break; + + default : + if (is_last_page(number) && UseESPsp) + { + WriteLabels(Orientation); + puts("ESPshowpage"); + } + break; + } + + fflush(stdout); +} + + +/* + * 'include_feature()' - Include a printer option/feature command. + */ + +static void +include_feature(ppd_file_t *ppd, /* I - PPD file */ + const char *line, /* I - DSC line */ + FILE *out) /* I - Output file */ +{ + char name[255], /* Option name */ + value[255]; /* Option value */ + ppd_option_t *option; /* Option in file */ + ppd_choice_t *choice; /* Choice */ + + + /* + * Get the "%%IncludeFeature: *Keyword OptionKeyword" values... + */ + + if (sscanf(line + 17, "%254s%254s", name, value) != 2) + { + fprintf(stderr, "ERROR: Bad line: \"%s\"!\n", line); + return; + } + + /* + * Find the option and choice... + */ + + if ((option = ppdFindOption(ppd, name + 1)) == NULL) + { + fprintf(stderr, "WARNING: Unknown option \"%s\"!\n", name + 1); + return; + } + + if (option->section == PPD_ORDER_EXIT || + option->section == PPD_ORDER_JCL) + { + fprintf(stderr, "WARNING: Option \"%s\" cannot be included via IncludeFeature!\n", + name + 1); + return; + } + + if ((choice = ppdFindChoice(option, value)) == NULL) + { + fprintf(stderr, "WARNING: Unknown choice \"%s\" for option \"%s\"!\n", + value, name + 1); + return; + } + + /* + * Emit the option... + */ + + fputs("[{\n", out); + fprintf(out, "%%%%BeginFeature: %s %s\n", name, value); + if (choice->code && choice->code[0]) + { + fputs(choice->code, out); + + if (choice->code[strlen(choice->code) - 1] != '\n') + putc('\n', out); + } + fputs("%%EndFeature\n", out); + fputs("} stopped cleartomark\n", out); +} + + +/* + * 'psbcp()' - Enable the binary communications protocol on the printer. + */ + +static void +psbcp(ppd_file_t *ppd) /* I - PPD file */ +{ + if (ppd->jcl_begin) + fputs(ppd->jcl_begin, stdout); + if (ppd->jcl_ps) + fputs(ppd->jcl_ps, stdout); + + if (ppd->language_level == 1) + { + /* + * Use setsoftwareiomode for BCP mode... + */ + + fputs("%!PS-Adobe-3.0 ExitServer\n", stdout); + fputs("%%Title: (BCP - Level 1)\n", stdout); + fputs("%%EndComments\n", stdout); + fputs("%%BeginExitServer: 0\n", stdout); + fputs("serverdict begin 0 exitserver\n", stdout); + fputs("%%EndExitServer\n", stdout); + fputs("statusdict begin\n", stdout); + fputs("/setsoftwareiomode known {100 setsoftwareiomode}\n", stdout); + fputs("end\n", stdout); + fputs("%EOF\n", stdout); + } + else + { + /* + * Use setdevparams for BCP mode... + */ + + fputs("%!PS-Adobe-3.0\n", stdout); + fputs("%%Title: (BCP - Level 2)\n", stdout); + fputs("%%EndComments\n", stdout); + fputs("currentsysparams\n", stdout); + fputs("/CurInputDevice 2 copy known {\n", stdout); + fputs("get\n", stdout); + fputs("<> setdevparams\n", stdout); + fputs("}{\n", stdout); + fputs("pop pop\n", stdout); + fputs("} ifelse\n", stdout); + fputs("%EOF\n", stdout); + } + + if (ppd->jcl_end) + fputs(ppd->jcl_end, stdout); + else if (ppd->num_filters == 0) + putchar(0x04); +} + + +/* + * '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 *bytes, /* IO - Length of buffer */ + FILE *fp) /* I - File to read from */ +{ + char *bufptr; /* Pointer into buffer */ + int ch; /* Character from file */ + size_t len; /* Max length of string */ + + + len = *bytes - 1; + bufptr = buf; + ch = EOF; + + while ((bufptr - buf) < len) + { + if ((ch = getc(fp)) == EOF) + break; + + if (ch == '\r') + { + /* + * Got a CR; see if there is a LF as well... + */ + + ch = getc(fp); + + if (ch != EOF && ch != '\n') + { + ungetc(ch, fp); /* Nope, save it for later... */ + ch = '\r'; + } + else + *bufptr++ = '\r'; + break; + } + else if (ch == '\n') + break; + else + *bufptr++ = ch; + } + + /* + * Add a trailing newline if it is there... + */ + + if (ch == '\n' || ch == '\r') + { + if ((bufptr - buf) < len) + *bufptr++ = ch; + else + ungetc(ch, fp); + } + + /* + * Nul-terminate the string and return it (or NULL for EOF). + */ + + *bufptr = '\0'; + *bytes = bufptr - buf; + + if (ch == EOF && bufptr == buf) + return (NULL); + else + return (buf); +} + + +/* + * 'pswrite()' - Write data from a file. + */ + +static size_t /* O - Number of bytes written */ +pswrite(const char *buf, /* I - Buffer to write */ + size_t bytes, /* I - Bytes to write */ + FILE *fp) /* I - File to write to */ +{ + size_t count; /* Remaining bytes */ + + + switch (Protocol) + { + case PROT_STANDARD : + return (fwrite(buf, 1, bytes, fp)); + + case PROT_BCP : + for (count = bytes; count > 0; count --, buf ++) + switch (*buf) + { + case 0x01 : /* CTRL-A */ + case 0x03 : /* CTRL-C */ + case 0x04 : /* CTRL-D */ + case 0x05 : /* CTRL-E */ + case 0x11 : /* CTRL-Q */ + case 0x13 : /* CTRL-S */ + case 0x14 : /* CTRL-T */ + case 0x1c : /* CTRL-\ */ + putchar(0x01); + putchar(*buf ^ 0x40); + break; + + default : + putchar(*buf); + break; + } + return (bytes); + + case PROT_TBCP : + for (count = bytes; count > 0; count --, buf ++) + switch (*buf) + { + case 0x01 : /* CTRL-A */ + case 0x03 : /* CTRL-C */ + case 0x04 : /* CTRL-D */ + case 0x05 : /* CTRL-E */ + case 0x11 : /* CTRL-Q */ + case 0x13 : /* CTRL-S */ + case 0x14 : /* CTRL-T */ + case 0x1b : /* CTRL-[ (aka ESC) */ + case 0x1c : /* CTRL-\ */ + putchar(0x01); + putchar(*buf ^ 0x40); + break; + + default : + putchar(*buf); + break; + } + return (bytes); + } + + return (fwrite(buf, 1, bytes, fp)); +} + + +/* + * 'start_nup()' - Start processing for N-up printing... + */ + +static void +start_nup(int number, /* I - Page number */ + int show_border) /* I - Show the page border? */ +{ + int pos; /* Position on page */ + 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); + + pos = number % NUp; + 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; + } + + if (Duplex && NUp > 1 && ((number / NUp) & 1)) + printf("%.1f %.1f translate\n", PageWidth - PageRight, PageBottom); + else if (NUp > 1) + printf("%.1f %.1f translate\n", PageLeft, PageBottom); + + switch (NUp) + { + default : + w = PageWidth; + l = PageLength; + break; + + case 2 : + if (Orientation & 1) + { + x = pos & 1; + + if (Layout & LAYOUT_NEGATEY) + x = 1 - x; + + w = pl; + l = w * PageLength / PageWidth; + + if (l > (pw * 0.5)) + { + l = pw * 0.5; + w = l * PageWidth / PageLength; + } + + tx = 0.5 * (pw * 0.5 - l); + ty = 0.5 * (pl - w); + + if (NormalLandscape) + printf("0.0 %.1f translate -90 rotate\n", pl); + else + printf("%.1f 0.0 translate 90 rotate\n", pw); + + printf("%.1f %.1f translate %.3f %.3f scale\n", + ty, tx + l * x, w / PageWidth, l / PageLength); + } + else + { + x = pos & 1; + + if (Layout & LAYOUT_NEGATEX) + x = 1 - x; + + l = pw; + w = l * PageWidth / PageLength; + + if (w > (pl * 0.5)) + { + w = pl * 0.5; + l = w * PageLength / PageWidth; + } + + tx = 0.5 * (pl * 0.5 - w); + ty = 0.5 * (pw - l); + + if (NormalLandscape) + printf("%.1f 0.0 translate 90 rotate\n", pw); + else + printf("0.0 %.1f translate -90 rotate\n", pl); + + printf("%.1f %.1f translate %.3f %.3f scale\n", + tx + w * x, ty, w / PageWidth, l / PageLength); + } + break; + + case 4 : + if (Layout & LAYOUT_VERTICAL) + { + x = (pos / 2) & 1; + y = pos & 1; + } + else + { + x = pos & 1; + y = (pos / 2) & 1; + } + + if (Layout & LAYOUT_NEGATEX) + x = 1 - x; + + if (Layout & LAYOUT_NEGATEY) + y = 1 - y; + + w = pw * 0.5; + l = w * PageLength / PageWidth; + + if (l > (pl * 0.5)) + { + l = pl * 0.5; + w = l * PageWidth / PageLength; + } + + tx = 0.5 * (pw * 0.5 - w); + ty = 0.5 * (pl * 0.5 - l); + + printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l, + w / PageWidth, l / PageLength); + break; + + case 6 : + if (Orientation & 1) + { + if (Layout & LAYOUT_VERTICAL) + { + x = pos / 3; + y = pos % 3; + + if (Layout & LAYOUT_NEGATEX) + x = 1 - x; + + if (Layout & LAYOUT_NEGATEY) + y = 2 - y; + } + else + { + x = pos & 1; + y = pos / 2; + + if (Layout & LAYOUT_NEGATEX) + x = 1 - x; + + if (Layout & LAYOUT_NEGATEY) + y = 2 - y; + } + + w = pl * 0.5; + l = w * PageLength / PageWidth; + + if (l > (pw * 0.333)) + { + l = pw * 0.333; + w = l * PageWidth / PageLength; + } + + tx = 0.5 * (pl - 2 * w); + ty = 0.5 * (pw - 3 * l); + + if (NormalLandscape) + printf("0.0 %.1f translate -90 rotate\n", pl); + else + printf("%.1f 0.0 translate 90 rotate\n", pw); + + printf("%.1f %.1f translate %.3f %.3f scale\n", + tx + x * w, ty + y * l, w / PageWidth, l / PageLength); + } + else + { + if (Layout & LAYOUT_VERTICAL) + { + x = pos / 2; + y = pos & 1; + + if (Layout & LAYOUT_NEGATEX) + x = 2 - x; + + if (Layout & LAYOUT_NEGATEY) + y = 1 - y; + } + else + { + x = pos % 3; + y = pos / 3; + + if (Layout & LAYOUT_NEGATEX) + x = 2 - x; + + if (Layout & LAYOUT_NEGATEY) + y = 1 - y; + } + + l = pw * 0.5; + w = l * PageWidth / PageLength; + + if (w > (pl * 0.333)) + { + w = pl * 0.333; + l = w * PageLength / PageWidth; + } + + tx = 0.5 * (pl - 3 * w); + ty = 0.5 * (pw - 2 * l); + + if (NormalLandscape) + printf("%.1f 0.0 translate 90 rotate\n", pw); + else + printf("0.0 %.1f translate -90 rotate\n", pl); + + printf("%.1f %.1f translate %.3f %.3f scale\n", + tx + w * x, ty + l * y, w / PageWidth, l / PageLength); + } + break; + + case 9 : + if (Layout & LAYOUT_VERTICAL) + { + x = (pos / 3) % 3; + y = pos % 3; + } + else + { + x = pos % 3; + y = (pos / 3) % 3; + } + + if (Layout & LAYOUT_NEGATEX) + x = 2 - x; + + if (Layout & LAYOUT_NEGATEY) + y = 2 - y; + + w = pw * 0.333; + l = w * PageLength / PageWidth; + + if (l > (pl * 0.333)) + { + l = pl * 0.333; + w = l * PageWidth / PageLength; + } + + tx = 0.5 * (pw * 0.333 - w); + ty = 0.5 * (pl * 0.333 - l); + + printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l, + w / PageWidth, l / PageLength); + break; + + case 16 : + if (Layout & LAYOUT_VERTICAL) + { + x = (pos / 4) & 3; + y = pos & 3; + } + else + { + x = pos & 3; + y = (pos / 4) & 3; + } + + if (Layout & LAYOUT_NEGATEX) + x = 3 - x; + + if (Layout & LAYOUT_NEGATEY) + y = 3 - y; + + w = pw * 0.25; + l = w * PageLength / PageWidth; + + if (l > (pl * 0.25)) + { + l = pl * 0.25; + w = l * PageWidth / PageLength; + } + + tx = 0.5 * (pw * 0.25 - w); + ty = 0.5 * (pl * 0.25 - l); + + printf("%.1f %.1f translate %.3f %.3f scale\n", tx + x * w, ty + y * l, + w / PageWidth, l / PageLength); + break; + } + + /* + * Draw borders as necessary... + */ + + if (Border && show_border) + { + int rects; /* Number of border rectangles */ + float fscale, /* Scaling value for points */ + margin; /* Current margin for borders */ + + + rects = (Border & BORDER_DOUBLE) ? 2 : 1; + fscale = PageWidth / w; + margin = 2.25 * fscale; + + /* + * Set the line width and color... + */ + + puts("gsave"); + printf("%.3f setlinewidth 0 setgray newpath\n", + (Border & BORDER_THICK) ? 0.5 * fscale : 0.24 * fscale); + + /* + * Draw border boxes... + */ + + for (; rects > 0; rects --, margin += 2 * fscale) + if (NUp > 1) + printf("%.1f %.1f %.1f %.1f ESPrs\n", + margin, + margin, + PageWidth - 2 * margin, + PageLength - 2 * margin); + else + printf("%.1f %.1f %.1f %.1f ESPrs\n", + PageLeft + margin, + PageBottom + margin, + PageRight - PageLeft - 2 * margin, + PageTop - PageBottom - 2 * margin); + + /* + * Restore pen settings... + */ + + puts("grestore"); + } + + if (NUp > 1) + { + /* + * Clip the page that follows to the bounding box of the page... + */ + + printf("0 0 %.1f %.1f ESPrc\n", PageWidth, PageLength); + } +} + + +/* + * End of "$Id: pstops.c 4672 2005-09-18 04:25:46Z mike $". + */ diff --git a/filter/raster.c b/filter/raster.c new file mode 100644 index 000000000..56bd695fe --- /dev/null +++ b/filter/raster.c @@ -0,0 +1,892 @@ +/* + * "$Id: raster.c 4903 2006-01-10 20:02:46Z mike $" + * + * Raster file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * This file is part of the CUPS Imaging library. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * 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/GPL Ghostscript or its derivatives. Use of the + * code (or any derivative of it) with software other than GNU/GPL + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * cupsRasterClose() - Close a raster stream. + * cupsRasterOpen() - Open a raster stream. + * cupsRasterReadHeader() - Read a V1 raster page header. + * cupsRasterReadHeader2() - Read a V2 raster page header. + * cupsRasterReadPixels() - Read raster pixels. + * cupsRasterWriteHeader() - Write a V1 raster page header. + * cupsRasterWriteHeader2() - Write a V2 raster page header. + * cupsRasterWritePixels() - Write raster pixels. + * cups_raster_update() - Update the raster header and row count for the + * current page. + * cups_raster_write() - Write a row of raster data... + * cups_read() - Read bytes from a file. + * cups_write() - Write bytes to a file. + */ + +/* + * Include necessary headers... + */ + +#include "raster.h" +#include +#include +#include +#include + +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +/* + * Local functions... + */ + +static unsigned cups_raster_read_header(cups_raster_t *r); +static void cups_raster_update(cups_raster_t *r); +static int cups_raster_write(cups_raster_t *r); +static int cups_read(int fd, unsigned char *buf, int bytes); +static int cups_write(int fd, const unsigned char *buf, int bytes); + + +/* + * 'cupsRasterClose()' - Close a raster stream. + */ + +void +cupsRasterClose(cups_raster_t *r) /* I - Stream to close */ +{ + if (r != NULL) + { + if (r->pixels) + free(r->pixels); + + 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 (cups_read(r->fd, (unsigned char *)&(r->sync), sizeof(r->sync)) + < sizeof(r->sync)) + { + free(r); + return (NULL); + } + + if (r->sync != CUPS_RASTER_SYNC && + r->sync != CUPS_RASTER_REVSYNC && + r->sync != CUPS_RASTER_SYNCv1 && + r->sync != CUPS_RASTER_REVSYNCv1) + { + free(r); + return (NULL); + } + } + else + { + /* + * Open for write - put sync word... + */ + + r->sync = CUPS_RASTER_SYNC; + if (cups_write(r->fd, (unsigned char *)&(r->sync), sizeof(r->sync)) + < sizeof(r->sync)) + { + free(r); + return (NULL); + } + } + + return (r); +} + + +/* + * 'cupsRasterReadHeader()' - Read a V1 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 */ +{ + /* + * Get the raster header... + */ + + if (!cups_raster_read_header(r)) + return (0); + + /* + * Copy the header to the user-supplied buffer... + */ + + memcpy(h, &(r->header), sizeof(cups_page_header_t)); + + return (1); +} + + +/* + * 'cupsRasterReadHeader2()' - Read a V2 raster page header. + * + * @since CUPS 1.2@ + */ + +unsigned /* O - 1 on success, 0 on fail */ +cupsRasterReadHeader2( + cups_raster_t *r, /* I - Raster stream */ + cups_page_header2_t *h) /* I - Pointer to header data */ +{ + /* + * Get the raster header... + */ + + if (!cups_raster_read_header(r)) + return (0); + + /* + * Copy the header to the user-supplied buffer... + */ + + memcpy(h, &(r->header), sizeof(cups_page_header2_t)); + + 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 */ + unsigned char *ptr, /* Pointer to read buffer */ + byte; /* Byte from file */ + + + if (r == NULL || r->mode != CUPS_RASTER_READ || r->remaining == 0) + return (0); + + remaining = len; + + while (remaining > 0 && r->remaining > 0) + { + if (r->count == 0) + { + /* + * Need to read a new row... + */ + + if (remaining == r->header.cupsBytesPerLine) + ptr = p; + else + ptr = r->pixels; + + if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1) + { + /* + * Read without compression... + */ + + if (cups_read(r->fd, ptr, r->header.cupsBytesPerLine) < + r->header.cupsBytesPerLine) + return (0); + + r->count = 1; + } + else + { + /* + * Read using a modified TIFF "packbits" compression... + */ + + unsigned char *temp; /* Pointer into buffer */ + int count; /* Repetition count */ + + + if (cups_read(r->fd, &byte, 1) < 1) + return (0); + + r->count = byte + 1; + + if (r->count > 1) + ptr = r->pixels; + + temp = ptr; + bytes = r->header.cupsBytesPerLine; + + while (bytes > 0) + { + /* + * Get a new repeat count... + */ + + if (cups_read(r->fd, &byte, 1) < 1) + return (0); + + if (byte & 128) + { + /* + * Copy N literal pixels... + */ + + count = (257 - byte) * r->bpp; + + if (count > bytes) + count = bytes; + + if (cups_read(r->fd, temp, count) < count) + return (0); + + temp += count; + bytes -= count; + } + else + { + /* + * Repeat the next N bytes... + */ + + count = (byte + 1) * r->bpp; + if (count > bytes) + count = bytes; + + if (count < r->bpp) + break; + + bytes -= count; + + if (cups_read(r->fd, temp, r->bpp) < r->bpp) + return (0); + + temp += r->bpp; + count -= r->bpp; + + while (count > 0) + { + memcpy(temp, temp - r->bpp, r->bpp); + temp += r->bpp; + count -= r->bpp; + } + } + } + } + + if (r->header.cupsBitsPerColor == 16 && + (r->sync == CUPS_RASTER_REVSYNC || r->sync == CUPS_RASTER_REVSYNCv1)) + { + /* + * Swap bytes in the pixel data... + */ + + unsigned char *temp; + int count; + + + for (temp = ptr, count = r->header.cupsBytesPerLine; + count > 0; + temp += 2, count -= 2) + { + byte = temp[0]; + temp[0] = temp[1]; + temp[1] = byte; + } + } + + if (remaining >= r->header.cupsBytesPerLine) + { + bytes = r->header.cupsBytesPerLine; + r->pcurrent = r->pixels; + r->count --; + r->remaining --; + } + else + { + bytes = remaining; + r->pcurrent = r->pixels + bytes; + } + + if (ptr != p) + memcpy(p, ptr, bytes); + } + else + { + /* + * Copy fragment from buffer... + */ + + if ((bytes = r->pend - r->pcurrent) > remaining) + bytes = remaining; + + memcpy(p, r->pcurrent, bytes); + r->pcurrent += bytes; + + if (r->pcurrent >= r->pend) + { + r->pcurrent = r->pixels; + r->count --; + r->remaining --; + } + } + + remaining -= bytes; + p += bytes; + } + + return (len); +} + + +/* + * 'cupsRasterWriteHeader()' - Write a V2 raster page header. + */ + +unsigned /* O - 1 on success, 0 on failure */ +cupsRasterWriteHeader( + cups_raster_t *r, /* I - Raster stream */ + cups_page_header_t *h) /* I - Raster page header */ +{ + if (r == NULL || r->mode != CUPS_RASTER_WRITE) + return (0); + + /* + * Make a copy of the header, and compute the number of raster + * lines in the page image... + */ + + memset(&(r->header), 0, sizeof(r->header)); + memcpy(&(r->header), h, sizeof(cups_page_header_t)); + + cups_raster_update(r); + + /* + * Write the raster header... + */ + + return (cups_write(r->fd, (unsigned char *)&(r->header), sizeof(r->header)) + > 0); +} + + +/* + * 'cupsRasterWriteHeader2()' - Write a V2 raster page header. + * + * @since CUPS 1.2@ + */ + +unsigned /* O - 1 on success, 0 on failure */ +cupsRasterWriteHeader2( + cups_raster_t *r, /* I - Raster stream */ + cups_page_header2_t *h) /* I - Raster page header */ +{ + if (r == NULL || r->mode != CUPS_RASTER_WRITE) + return (0); + + /* + * Make a copy of the header, and compute the number of raster + * lines in the page image... + */ + + memcpy(&(r->header), h, sizeof(cups_page_header2_t)); + + cups_raster_update(r); + + /* + * Write the raster header... + */ + + return (cups_write(r->fd, (unsigned char *)&(r->header), sizeof(r->header)) + > 0); +} + + +/* + * '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 || r->remaining == 0) + return (0); + + remaining = len; + + while (remaining > 0) + { + /* + * Figure out the number of remaining bytes on the current line... + */ + + if ((bytes = remaining) > (r->pend - r->pcurrent)) + bytes = r->pend - r->pcurrent; + + if (r->count > 0) + { + /* + * Check to see if this line is the same as the previous line... + */ + + if (memcmp(p, r->pcurrent, bytes)) + { + if (!cups_raster_write(r)) + return (0); + + r->count = 0; + } + else + { + /* + * Mark more bytes as the same... + */ + + r->pcurrent += bytes; + + if (r->pcurrent >= r->pend) + { + /* + * Increase the repeat count... + */ + + r->count ++; + r->pcurrent = r->pixels; + + /* + * Flush out this line if it is the last one... + */ + + r->remaining --; + if (r->remaining == 0) + return (cups_raster_write(r)); + else if (r->count == 256) + { + cups_raster_write(r); + r->count = 0; + } + } + } + } + + if (r->count == 0) + { + /* + * Copy the raster data to the buffer... + */ + + memcpy(r->pcurrent, p, bytes); + + r->pcurrent += bytes; + + if (r->pcurrent >= r->pend) + { + /* + * Increase the repeat count... + */ + + r->count ++; + r->pcurrent = r->pixels; + + /* + * Flush out this line if it is the last one... + */ + + r->remaining --; + if (r->remaining == 0) + return (cups_raster_write(r)); + } + } + + remaining -= bytes; + p += bytes; + } + + return (len); +} + + +/* + * 'cups_raster_read_header()' - Read a raster page header. + */ + +static unsigned /* O - 1 on success, 0 on fail */ +cups_raster_read_header( + cups_raster_t *r) /* I - Raster stream */ +{ + 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); + + /* + * Get the length of the raster header... + */ + + if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1) + len = sizeof(cups_page_header_t); + else + len = sizeof(cups_page_header2_t); + + /* + * Read the header... + */ + + memset(&(r->header), 0, sizeof(r->header)); + + if (cups_read(r->fd, (unsigned char *)&(r->header), len) < len) + return (0); + + /* + * Swap bytes as needed... + */ + + if (r->sync == CUPS_RASTER_REVSYNC || r->sync == CUPS_RASTER_REVSYNCv1) + for (len = 74, s = (union swap_s *)&(r->header.AdvanceDistance); + len > 0; + len --, s ++) + s->v = (((((s->b[3] << 8) | s->b[2]) << 8) | s->b[1]) << 8) | s->b[0]; + + /* + * Update the header and row count... + */ + + cups_raster_update(r); + + return (1); +} + + +/* + * 'cups_raster_update()' - Update the raster header and row count for the + * current page. + */ + +static void +cups_raster_update(cups_raster_t *r) /* I - Raster stream */ +{ + if (r->sync == CUPS_RASTER_SYNCv1 || r->sync == CUPS_RASTER_REVSYNCv1) + { + /* + * Set the "cupsNumColors" field according to the colorspace... + */ + + switch (r->header.cupsColorSpace) + { + case CUPS_CSPACE_W : + case CUPS_CSPACE_K : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + case CUPS_CSPACE_ICC1 : + r->header.cupsNumColors = 1; + break; + + case CUPS_CSPACE_ICC2 : + r->header.cupsNumColors = 2; + break; + + case CUPS_CSPACE_RGB : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + case CUPS_CSPACE_CIEXYZ : + case CUPS_CSPACE_CIELab : + case CUPS_CSPACE_ICC3 : + r->header.cupsNumColors = 3; + break; + + case CUPS_CSPACE_RGBA : + case CUPS_CSPACE_RGBW : + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + case CUPS_CSPACE_ICC4 : + r->header.cupsNumColors = 4; + break; + + case CUPS_CSPACE_KCMYcm : + if (r->header.cupsBitsPerPixel < 8) + r->header.cupsNumColors = 6; + else + r->header.cupsNumColors = 4; + break; + + case CUPS_CSPACE_ICC5 : + case CUPS_CSPACE_ICC6 : + case CUPS_CSPACE_ICC7 : + case CUPS_CSPACE_ICC8 : + case CUPS_CSPACE_ICC9 : + case CUPS_CSPACE_ICCA : + case CUPS_CSPACE_ICCB : + case CUPS_CSPACE_ICCC : + case CUPS_CSPACE_ICCD : + case CUPS_CSPACE_ICCE : + case CUPS_CSPACE_ICCF : + r->header.cupsNumColors = r->header.cupsColorSpace - + CUPS_CSPACE_ICC1 + 1; + break; + } + } + + /* + * Set the number of bytes per pixel/color... + */ + + if (r->header.cupsColorOrder == CUPS_ORDER_CHUNKED) + r->bpp = (r->header.cupsBitsPerPixel + 7) / 8; + else + r->bpp = (r->header.cupsBitsPerColor + 7) / 8; + + /* + * Set the number of remaining rows... + */ + + if (r->header.cupsColorOrder == CUPS_ORDER_PLANAR) + r->remaining = r->header.cupsHeight * r->header.cupsNumColors; + else + r->remaining = r->header.cupsHeight; + + /* + * Allocate the read/write buffer... + */ + + if (r->pixels != NULL) + free(r->pixels); + + r->pixels = calloc(r->header.cupsBytesPerLine, 1); + r->pcurrent = r->pixels; + r->pend = r->pixels + r->header.cupsBytesPerLine; + r->count = 0; +} + + +/* + * 'cups_raster_write()' - Write a row of raster data... + */ + +static int /* O - Number of bytes written */ +cups_raster_write(cups_raster_t *r) /* I - Raster stream */ +{ + unsigned char *start, /* Start of sequence */ + *ptr, /* Current pointer in sequence */ + byte; /* Byte to write */ + int count; /* Count */ + + + /* + * Write the row repeat count... + */ + + byte = r->count - 1; + + if (cups_write(r->fd, &byte, 1) < 1) + return (0); + + /* + * Write using a modified TIFF "packbits" compression... + */ + + for (ptr = r->pixels; ptr < r->pend;) + { + start = ptr; + ptr += r->bpp; + + if (ptr == r->pend) + { + /* + * Encode a single pixel at the end... + */ + + byte = 0; + if (cups_write(r->fd, &byte, 1) < 1) + return (0); + + if (cups_write(r->fd, start, r->bpp) < r->bpp) + return (0); + } + else if (!memcmp(start, ptr, r->bpp)) + { + /* + * Encode a sequence of repeating pixels... + */ + + for (count = 2; count < 128 && ptr < (r->pend - r->bpp); count ++, ptr += r->bpp) + if (memcmp(ptr, ptr + r->bpp, r->bpp) != 0) + break; + + ptr += r->bpp; + + byte = count - 1; + + if (cups_write(r->fd, &byte, 1) < 1) + return (0); + + if (cups_write(r->fd, start, r->bpp) < r->bpp) + return (0); + } + else + { + /* + * Encode a sequence of non-repeating pixels... + */ + + for (count = 1; count < 127 && ptr < (r->pend - r->bpp); count ++, ptr += r->bpp) + if (!memcmp(ptr, ptr + r->bpp, r->bpp)) + break; + + if (ptr >= (r->pend - r->bpp) && count < 128) + { + count ++; + ptr += r->bpp; + } + + byte = 257 - count; + + if (cups_write(r->fd, &byte, 1) < 1) + return (0); + + count *= r->bpp; + + if (cups_write(r->fd, start, count) < count) + return (0); + } + } + + return (r->header.cupsBytesPerLine); +} + + +/* + * 'cups_read()' - Read bytes from a file. + */ + +static int /* O - Bytes read or -1 */ +cups_read(int fd, /* I - File descriptor */ + unsigned char *buf, /* I - Buffer for read */ + int bytes) /* I - Number of bytes to read */ +{ + int count, /* Number of bytes read */ + total; /* Total bytes read */ + + + for (total = 0; total < bytes; total += count, buf += count) + { + count = read(fd, buf, bytes - total); + + if (count == 0) + return (0); + else if (count < 0) + { + if (errno == EINTR) + count = 0; + else + return (-1); + } + } + + return (total); +} + + +/* + * 'cups_write()' - Write bytes to a file. + */ + +static int /* O - Bytes written or -1 */ +cups_write(int fd, /* I - File descriptor */ + const unsigned char *buf, /* I - Bytes to write */ + int bytes) /* I - Number of bytes to write */ +{ + int count, /* Number of bytes written */ + total; /* Total bytes written */ + + + for (total = 0; total < bytes; total += count, buf += count) + { + count = write(fd, buf, bytes - total); + + if (count < 0) + { + if (errno == EINTR) + count = 0; + else + return (-1); + } + } + + return (total); +} + + +/* + * End of "$Id: raster.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/filter/raster.h b/filter/raster.h new file mode 100644 index 000000000..2b1510d0d --- /dev/null +++ b/filter/raster.h @@ -0,0 +1,345 @@ +/* + * "$Id: raster.h 4903 2006-01-10 20:02:46Z mike $" + * + * Raster file definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * This file is part of the CUPS Imaging library. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * 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/GPL Ghostscript or its derivatives. Use of the + * code (or any derivative of it) with software other than GNU/GPL + * GhostScript (or its derivatives) is governed by the CUPS license + * agreement. + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +#ifndef _CUPS_RASTER_H_ +# define _CUPS_RASTER_H_ + +/* + * Include necessary headers... + */ + +# include + +# 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/GPL + * Ghostscript) 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 0x52615332 /* RaS2 */ +# define CUPS_RASTER_REVSYNC 0x32536152 /* 2SaR */ + +# define CUPS_RASTER_SYNCv1 0x52615374 /* RaSt */ +# define CUPS_RASTER_REVSYNCv1 0x74536152 /* tSaR */ + + +/* + * The following definition can be used to determine if the + * colorimetric colorspaces (CIEXYZ, CIELAB, and ICCn) are + * defined... + */ + +# define CUPS_RASTER_HAVE_COLORIMETRIC 1 + + +/* + * Types... + */ + +typedef enum cups_mode_e /**** Raster modes ****/ +{ + CUPS_RASTER_READ = 0, /* Open stream for reading */ + CUPS_RASTER_WRITE = 1 /* Open stream for writing */ +} cups_mode_t; + +typedef enum cups_bool_e /**** Boolean type ****/ +{ + CUPS_FALSE = 0, /* Logical false */ + CUPS_TRUE = 1 /* Logical true */ +} cups_bool_t; + +typedef enum cups_jog_e /**** Jog attribute values ****/ +{ + CUPS_JOG_NONE = 0, /* Never move pages */ + CUPS_JOG_FILE = 1, /* Move pages after this file */ + CUPS_JOG_JOB = 2, /* Move pages after this job */ + CUPS_JOG_SET = 3 /* Move pages after this set */ +} cups_jog_t; + +typedef enum cups_orient_e /**** Orientation attribute values ****/ +{ + CUPS_ORIENT_0 = 0, /* Don't rotate the page */ + CUPS_ORIENT_90 = 1, /* Rotate the page counter-clockwise */ + CUPS_ORIENT_180 = 2, /* Turn the page upside down */ + CUPS_ORIENT_270 = 3 /* Rotate the page clockwise */ +} cups_orient_t; + +typedef enum cups_cut_e /**** CutMedia attribute values ****/ +{ + CUPS_CUT_NONE = 0, /* Never cut the roll */ + CUPS_CUT_FILE = 1, /* Cut the roll after this file */ + CUPS_CUT_JOB = 2, /* Cut the roll after this job */ + CUPS_CUT_SET = 3, /* Cut the roll after this set */ + CUPS_CUT_PAGE = 4 /* Cut the roll after this page */ +} cups_cut_t; + +typedef enum cups_adv_e /**** AdvanceMedia attribute values ****/ +{ + CUPS_ADVANCE_NONE = 0, /* Never advance the roll */ + CUPS_ADVANCE_FILE = 1, /* Advance the roll after this file */ + CUPS_ADVANCE_JOB = 2, /* Advance the roll after this job */ + CUPS_ADVANCE_SET = 3, /* Advance the roll after this set */ + CUPS_ADVANCE_PAGE = 4 /* Advance the roll after this page */ +} cups_adv_t; + +typedef enum cups_edge_e /**** LeadingEdge attribute values ****/ +{ + CUPS_EDGE_TOP = 0, /* Leading edge is the top of the page */ + CUPS_EDGE_RIGHT = 1, /* Leading edge is the right of the page */ + CUPS_EDGE_BOTTOM = 2, /* Leading edge is the bottom of the page */ + CUPS_EDGE_LEFT = 3 /* Leading edge is the left of the page */ +} cups_edge_t; + +typedef enum cups_order_e /**** cupsColorOrder attribute values ****/ +{ + CUPS_ORDER_CHUNKED = 0, /* CMYK CMYK CMYK ... */ + CUPS_ORDER_BANDED = 1, /* CCC MMM YYY KKK ... */ + CUPS_ORDER_PLANAR = 2 /* CCC ... MMM ... YYY ... KKK ... */ +} cups_order_t; + +typedef enum cups_cspace_e /**** cupsColorSpace attribute values ****/ +{ + CUPS_CSPACE_W = 0, /* Luminance */ + CUPS_CSPACE_RGB = 1, /* Red, green, blue */ + CUPS_CSPACE_RGBA = 2, /* Red, green, blue, alpha */ + CUPS_CSPACE_K = 3, /* Black */ + CUPS_CSPACE_CMY = 4, /* Cyan, magenta, yellow */ + CUPS_CSPACE_YMC = 5, /* Yellow, magenta, cyan */ + CUPS_CSPACE_CMYK = 6, /* Cyan, magenta, yellow, black */ + CUPS_CSPACE_YMCK = 7, /* Yellow, magenta, cyan, black */ + CUPS_CSPACE_KCMY = 8, /* Black, cyan, magenta, yellow */ + CUPS_CSPACE_KCMYcm = 9, /* Black, cyan, magenta, yellow, * + * light-cyan, light-magenta */ + CUPS_CSPACE_GMCK = 10, /* Gold, magenta, yellow, black */ + CUPS_CSPACE_GMCS = 11, /* Gold, magenta, yellow, silver */ + CUPS_CSPACE_WHITE = 12, /* White ink (as black) */ + CUPS_CSPACE_GOLD = 13, /* Gold foil */ + CUPS_CSPACE_SILVER = 14, /* Silver foil */ + + CUPS_CSPACE_CIEXYZ = 15, /* CIE XYZ @since CUPS 1.1.19@ */ + CUPS_CSPACE_CIELab = 16, /* CIE Lab @since CUPS 1.1.19@ */ + CUPS_CSPACE_RGBW = 17, /* Red, green, blue, white @since CUPS 1.2@ */ + + CUPS_CSPACE_ICC1 = 32, /* ICC-based, 1 color @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICC2 = 33, /* ICC-based, 2 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICC3 = 34, /* ICC-based, 3 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICC4 = 35, /* ICC-based, 4 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICC5 = 36, /* ICC-based, 5 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICC6 = 37, /* ICC-based, 6 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICC7 = 38, /* ICC-based, 7 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICC8 = 39, /* ICC-based, 8 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICC9 = 40, /* ICC-based, 9 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICCA = 41, /* ICC-based, 10 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICCB = 42, /* ICC-based, 11 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICCC = 43, /* ICC-based, 12 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICCD = 44, /* ICC-based, 13 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICCE = 45, /* ICC-based, 14 colors @since CUPS 1.1.19@ */ + CUPS_CSPACE_ICCF = 46 /* ICC-based, 15 colors @since CUPS 1.1.19@ */ +} 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... + * + * The API supports a "version 1" (from CUPS 1.0 and 1.1) and a "version 2" + * (from CUPS 1.2 and higher) page header, for binary compatibility. + */ + +typedef struct cups_page_header_s /**** Version 1 Page Header ****/ +{ + /**** 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; + +/**** New in CUPS 1.2 ****/ +typedef struct cups_page_header2_s /**** Version 2 Page Header @since CUPS 1.2@ ****/ +{ + /**** 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 */ + + /**** Version 2 Dictionary Values ****/ + unsigned cupsNumColors; /* Number of colors */ + unsigned cupsInteger[16]; /* User-defined integer values */ + float cupsReal[16]; /* User-defined floating-point values */ + char cupsString[16][64]; /* User-defined string values */ + char cupsMarkerType[64]; /* Ink/toner type */ + char cupsRenderingIntent[64];/* Color rendering intent */ +} cups_page_header2_t; + +typedef struct _cups_raster_s /**** Raster stream data ****/ +{ + unsigned sync; /* Sync word from start of stream */ + int fd; /* File descriptor */ + cups_mode_t mode; /* Read/write mode */ + cups_page_header2_t header; /* Raster header for current page */ + int count, /* Current row run-length count */ + remaining, /* Remaining rows in page image */ + bpp; /* Bytes per pixel/color */ + unsigned char *pixels, /* Pixels for current row */ + *pend, /* End of pixel buffer */ + *pcurrent; /* Current byte in pixel buffer */ +} 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); + +/**** New in CUPS 1.2 ****/ +extern int cupsRasterInterpretPPD(cups_page_header2_t *h, + ppd_file_t *ppd); +extern unsigned cupsRasterReadHeader2(cups_raster_t *r, + cups_page_header2_t *h); +extern unsigned cupsRasterWriteHeader2(cups_raster_t *r, + cups_page_header2_t *h); + +# ifdef __cplusplus +} +# endif /* __cplusplus */ + +#endif /* !_CUPS_RASTER_H_ */ + +/* + * End of "$Id: raster.h 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/filter/rastertoepson.c b/filter/rastertoepson.c new file mode 100644 index 000000000..75d2352b1 --- /dev/null +++ b/filter/rastertoepson.c @@ -0,0 +1,1152 @@ +/* + * "$Id: rastertoepson.c 4494 2005-02-18 02:18:11Z mike $" + * + * EPSON ESC/P and ESC/P2 filter for the Common UNIX Printing System + * (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * Setup() - Prepare the printer for printing. + * StartPage() - Start a page of graphics. + * EndPage() - Finish a page of graphics. + * Shutdown() - Shutdown the printer. + * CompressData() - Compress a line of graphics. + * OutputLine() - Output a line of graphics. + * main() - Main entry and processing of driver. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include "raster.h" +#include +#include +#include +#include + + +/* + * 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 */ + EjectPage; /* Eject the page when done? */ +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 && Model >= EPSON_ICOLOR) + 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... + */ + + EjectPage = header->Margins[0] || header->Margins[1]; + + switch (ppd->model_number) + { + case EPSON_9PIN : + case EPSON_24PIN : + printf("\033P\022"); /* 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 */ + printf("\033O"); /* No perforation skip */ + + /* + * 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 : + case 240 : + 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) + { + if (DotBit < 128 || EvenOffset) + OutputRows(header, 0); + } + else if (OddOffset > EvenOffset) + { + OutputRows(header, 1); + OutputRows(header, 0); + } + else + { + OutputRows(header, 0); + OutputRows(header, 1); + } + } + + /* + * Eject the current page... + */ + + if (EjectPage) + 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... + */ + + if (i == 0) + putchar('\r'); + else + { + 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... + */ + + if (i == 0) + putchar('\r'); + else + { + 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")); + if (ppd) + Model = ppd->model_number; + + 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: rastertoepson.c 4494 2005-02-18 02:18:11Z mike $". + */ diff --git a/filter/rastertohp.c b/filter/rastertohp.c new file mode 100644 index 000000000..e36c5902d --- /dev/null +++ b/filter/rastertohp.c @@ -0,0 +1,888 @@ +/* + * "$Id: rastertohp.c 4493 2005-02-18 02:09:53Z mike $" + * + * Hewlett-Packard Page Control Language filter for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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 +#include +#include "raster.h" +#include +#include +#include +#include + + +/* + * 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 */ + + /* + * Show page device dictionary... + */ + + fprintf(stderr, "DEBUG: StartPage...\n"); + fprintf(stderr, "DEBUG: MediaClass = \"%s\"\n", header->MediaClass); + fprintf(stderr, "DEBUG: MediaColor = \"%s\"\n", header->MediaColor); + fprintf(stderr, "DEBUG: MediaType = \"%s\"\n", header->MediaType); + fprintf(stderr, "DEBUG: OutputType = \"%s\"\n", header->OutputType); + + fprintf(stderr, "DEBUG: AdvanceDistance = %d\n", header->AdvanceDistance); + fprintf(stderr, "DEBUG: AdvanceMedia = %d\n", header->AdvanceMedia); + fprintf(stderr, "DEBUG: Collate = %d\n", header->Collate); + fprintf(stderr, "DEBUG: CutMedia = %d\n", header->CutMedia); + fprintf(stderr, "DEBUG: Duplex = %d\n", header->Duplex); + fprintf(stderr, "DEBUG: HWResolution = [ %d %d ]\n", header->HWResolution[0], + header->HWResolution[1]); + fprintf(stderr, "DEBUG: ImagingBoundingBox = [ %d %d %d %d ]\n", + header->ImagingBoundingBox[0], header->ImagingBoundingBox[1], + header->ImagingBoundingBox[2], header->ImagingBoundingBox[3]); + fprintf(stderr, "DEBUG: InsertSheet = %d\n", header->InsertSheet); + fprintf(stderr, "DEBUG: Jog = %d\n", header->Jog); + fprintf(stderr, "DEBUG: LeadingEdge = %d\n", header->LeadingEdge); + fprintf(stderr, "DEBUG: Margins = [ %d %d ]\n", header->Margins[0], + header->Margins[1]); + fprintf(stderr, "DEBUG: ManualFeed = %d\n", header->ManualFeed); + fprintf(stderr, "DEBUG: MediaPosition = %d\n", header->MediaPosition); + fprintf(stderr, "DEBUG: MediaWeight = %d\n", header->MediaWeight); + fprintf(stderr, "DEBUG: MirrorPrint = %d\n", header->MirrorPrint); + fprintf(stderr, "DEBUG: NegativePrint = %d\n", header->NegativePrint); + fprintf(stderr, "DEBUG: NumCopies = %d\n", header->NumCopies); + fprintf(stderr, "DEBUG: Orientation = %d\n", header->Orientation); + fprintf(stderr, "DEBUG: OutputFaceUp = %d\n", header->OutputFaceUp); + fprintf(stderr, "DEBUG: PageSize = [ %d %d ]\n", header->PageSize[0], + header->PageSize[1]); + fprintf(stderr, "DEBUG: Separations = %d\n", header->Separations); + fprintf(stderr, "DEBUG: TraySwitch = %d\n", header->TraySwitch); + fprintf(stderr, "DEBUG: Tumble = %d\n", header->Tumble); + fprintf(stderr, "DEBUG: cupsWidth = %d\n", header->cupsWidth); + fprintf(stderr, "DEBUG: cupsHeight = %d\n", header->cupsHeight); + fprintf(stderr, "DEBUG: cupsMediaType = %d\n", header->cupsMediaType); + 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: cupsCompression = %d\n", header->cupsCompression); + + /* + * Setup printer/job attributes... + */ + + Duplex = header->Duplex; + ColorBits = header->cupsBitsPerColor; + + if ((!Duplex || (Page & 1)) && header->MediaPosition) + printf("\033&l%dH", /* Set media position */ + header->MediaPosition); + + if (Duplex && ppd && ppd->model_number == 2) + { + /* + * Handle duplexing on new DeskJet printers... + */ + + printf("\033&l-2H"); /* Load media */ + + if (Page & 1) + printf("\033&l2S"); /* Set duplex mode */ + } + + if (!Duplex || (Page & 1) || (ppd && ppd->model_number == 2)) + { + /* + * Set the media 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 */ + } + + if (!Duplex || (Page & 1)) + { + /* + * Set other job options... + */ + + printf("\033&l%dX", header->NumCopies); /* Set number copies */ + + if (header->cupsMediaType && + (!ppd || ppd->model_number != 2 || header->HWResolution[0] == 600)) + printf("\033&l%dM", /* Set media type */ + header->cupsMediaType); + + if (!ppd || ppd->model_number != 2) + { + if (header->Duplex) + printf("\033&l%dS", /* Set duplex mode */ + header->Duplex + header->Tumble); + + printf("\033&l0L"); /* Turn off perforation skip */ + } + } + else if (!ppd || ppd->model_number != 2) + printf("\033&a2G"); /* Set back side */ + + /* + * Set graphics mode... + */ + + if (ppd->model_number == 2) + { + /* + * Figure out the number of color planes... + */ + + if (header->cupsColorSpace == CUPS_CSPACE_KCMY) + NumPlanes = 4; + else + NumPlanes = 1; + + /* + * Set the resolution and top-of-form... + */ + + printf("\033&u%dD", header->HWResolution[0]); + /* Resolution */ + printf("\033&l0e0L"); /* Reset top and don't skip */ + printf("\033*p0Y\033*p0X"); /* Set top of form */ + + /* + * 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 */ + + printf("\033&l0H"); /* Set media position */ + } + else + { + printf("\033*t%dR", header->HWResolution[0]); + /* Set resolution */ + + 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", (int)(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: rastertohp.c 4493 2005-02-18 02:09:53Z mike $". + */ diff --git a/filter/rastertolabel.c b/filter/rastertolabel.c new file mode 100644 index 000000000..a2270048a --- /dev/null +++ b/filter/rastertolabel.c @@ -0,0 +1,959 @@ +/* + * "$Id: rastertolabel.c 4920 2006-01-12 15:12:12Z mike $" + * + * Label printer filter for the Common UNIX Printing System (CUPS). + * + * Copyright 2001-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * Setup() - Prepare the printer for printing. + * StartPage() - Start a page of graphics. + * EndPage() - Finish a page of graphics. + * CancelJob() - Cancel the current job... + * OutputLine() - Output a line of graphics. + * ZPLCompress() - Output a run-length compression sequence. + * main() - Main entry and processing of driver. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include "raster.h" +#include +#include +#include +#include + + +/* + * This driver filter currently supports Dymo and Zebra label printers. + * + * The Dymo portion of the driver has been tested with the 300, 330, + * and 330 Turbo label printers; it may also work with older models. + * The Dymo printers support printing at 136, 203, and 300 DPI. + * + * The Zebra portion of the driver has been tested with the LP-2844Z label + * printer; it may also work with other models. The driver supports EPL + * line mode, EPL page mode, ZPL, and CPCL as defined in Zebra's on-line + * developer documentation. + */ + +/* + * Model number constants... + */ + +#define DYMO_3x0 0 /* Dymo Labelwriter 300/330/330 Turbo */ + +#define ZEBRA_EPL_LINE 0x10 /* Zebra EPL line mode printers */ +#define ZEBRA_EPL_PAGE 0x11 /* Zebra EPL page mode printers */ +#define ZEBRA_ZPL 0x12 /* Zebra ZPL-based printers */ +#define ZEBRA_CPCL 0x13 /* Zebra CPCL-based printers */ + + +/* + * Globals... + */ + +unsigned char *Buffer; /* Output buffer */ +char *CompBuffer; /* Compression buffer */ +unsigned char *LastBuffer; /* Last buffer */ +int LastSet; /* Number of repeat characters */ +int ModelNumber, /* cupsModelNumber attribute */ + Page, /* Current page */ + Feed, /* Number of lines to skip */ + Canceled; /* Non-zero if job is canceled */ + + +/* + * Prototypes... + */ + +void Setup(ppd_file_t *ppd); +void StartPage(ppd_file_t *ppd, cups_page_header_t *header); +void EndPage(ppd_file_t *ppd, cups_page_header_t *header); +void CancelJob(int sig); +void OutputLine(ppd_file_t *ppd, cups_page_header_t *header, int y); +void ZPLCompress(char repeat_char, int repeat_count); + + +/* + * 'Setup()' - Prepare the printer for printing. + */ + +void +Setup(ppd_file_t *ppd) /* I - PPD file */ +{ + int i; /* Looping var */ + + + /* + * Get the model number from the PPD file... + */ + + if (ppd) + ModelNumber = ppd->model_number; + + /* + * Initialize based on the model number... + */ + + switch (ModelNumber) + { + case DYMO_3x0 : + /* + * Clear any remaining data... + */ + + for (i = 0; i < 100; i ++) + putchar(0x1b); + + /* + * Reset the printer... + */ + + fputs("\033@", stdout); + break; + + case ZEBRA_EPL_LINE : + break; + + case ZEBRA_EPL_PAGE : + break; + + case ZEBRA_ZPL : + break; + + case ZEBRA_CPCL : + break; + } +} + + +/* + * 'StartPage()' - Start a page of graphics. + */ + +void +StartPage(ppd_file_t *ppd, /* I - PPD file */ + cups_page_header_t *header) /* I - Page header */ +{ + ppd_choice_t *choice; /* Marked choice */ + int length; /* Actual label length */ +#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 canceled. + */ + +#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 */ + + switch (ModelNumber) + { + case DYMO_3x0 : + /* + * Setup printer/job attributes... + */ + + length = header->PageSize[1] * header->HWResolution[1] / 72; + + printf("\033L%c%c", length >> 8, length); + printf("\033D%c", header->cupsBytesPerLine); + + printf("\033%c", header->cupsCompression + 'c'); /* Darkness */ + break; + + case ZEBRA_EPL_LINE : + /* + * Set print rate... + */ + + if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL && + strcmp(choice->choice, "Default")) + printf("\033S%.0f", atof(choice->choice) * 2.0 - 2.0); + + /* + * Set darkness... + */ + + if (header->cupsCompression > 0 && header->cupsCompression <= 100) + printf("\033D%d", 7 * header->cupsCompression / 100); + + /* + * Set left margin to 0... + */ + + fputs("\033M01", stdout); + + /* + * Start buffered output... + */ + + fputs("\033B", stdout); + break; + + case ZEBRA_EPL_PAGE : + /* + * Start a new label... + */ + + puts(""); + puts("N"); + + /* + * Set hardware options... + */ + + if (!strcmp(header->MediaType, "Direct")) + puts("OD"); + + /* + * Set print rate... + */ + + if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL && + strcmp(choice->choice, "Default")) + { + float val = atof(choice->choice); + + if (val >= 3.0) + printf("S%.0f\n", val); + else + printf("S%.0f\n", val * 2.0 - 2.0); + } + + /* + * Set darkness... + */ + + if (header->cupsCompression > 0 && header->cupsCompression <= 100) + printf("D%d\n", 15 * header->cupsCompression / 100); + + /* + * Set label size... + */ + + printf("q%d\n", header->cupsWidth); + break; + + case ZEBRA_ZPL : + /* + * Set darkness... + */ + + if (header->cupsCompression > 0 && header->cupsCompression <= 100) + printf("~SD%02d\n", 30 * header->cupsCompression / 100); + + /* + * Start bitmap graphics... + */ + + printf("~DGR:CUPS.GRF,%d,%d,\n", + header->cupsHeight * header->cupsBytesPerLine, + header->cupsBytesPerLine); + + /* + * Allocate compression buffers... + */ + + CompBuffer = malloc(2 * header->cupsBytesPerLine + 1); + LastBuffer = malloc(header->cupsBytesPerLine); + LastSet = 0; + break; + + case ZEBRA_CPCL : + /* + * Start label... + */ + + printf("! 0 %u %u %u %u\r\n", header->HWResolution[0], + header->HWResolution[1], header->cupsHeight, + header->NumCopies); + break; + } + + /* + * Allocate memory for a line of graphics... + */ + + Buffer = malloc(header->cupsBytesPerLine); + Feed = 0; +} + + +/* + * 'EndPage()' - Finish a page of graphics. + */ + +void +EndPage(ppd_file_t *ppd, /* I - PPD file */ + cups_page_header_t *header) /* I - Page header */ +{ + int val; /* Option value */ + ppd_choice_t *choice; /* Marked choice */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Actions for POSIX signals */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + switch (ModelNumber) + { + case DYMO_3x0 : + /* + * Eject the current page... + */ + + fputs("\033E", stdout); + break; + + case ZEBRA_EPL_LINE : + /* + * End buffered output, eject the label... + */ + + fputs("\033E\014", stdout); + break; + + case ZEBRA_EPL_PAGE : + /* + * Print the label... + */ + + puts("P1"); + break; + + case ZEBRA_ZPL : + if (Canceled) + { + /* + * Cancel bitmap download... + */ + + puts("~DN"); + break; + } + + /* + * Start label... + */ + + puts("^XA"); + + /* + * Set print rate... + */ + + if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL && + strcmp(choice->choice, "Default")) + { + val = atoi(choice->choice); + printf("^PR%d,%d,%d\n", val, val, val); + } + + /* + * Put label home in default position (0,0)... + */ + + printf("^LH0,0\n"); + + /* + * Set media tracking... + */ + + if (ppdIsMarked(ppd, "zeMediaTracking", "Continuous")) + { + /* + * Add label length command for continuous... + */ + + printf("^LL%d\n", header->cupsHeight); + printf("^MNN\n"); + } + else if (ppdIsMarked(ppd, "zeMediaTracking", "Web")) + printf("^MNY\n"); + else if (ppdIsMarked(ppd, "zeMediaTracking", "Mark")) + printf("^MNM\n"); + + /* + * Set label top + */ + + if (header->cupsRowStep != 200) + printf("^LT%u\n", header->cupsRowStep); + + /* + * Set media type... + */ + + if (!strcmp(header->MediaType, "Thermal")) + printf("^MTT\n"); + else if (!strcmp(header->MediaType, "Direct")) + printf("^MTD\n"); + + /* + * Set print mode... + */ + + if ((choice = ppdFindMarkedChoice(ppd, "zePrintMode")) != NULL && + strcmp(choice->choice, "Saved")) + { + printf("^MM"); + + if (!strcmp(choice->choice, "Tear")) + printf("T,Y\n"); + else if (!strcmp(choice->choice, "Peel")) + printf("P,Y\n"); + else if (!strcmp(choice->choice, "Rewind")) + printf("R,Y\n"); + else if (!strcmp(choice->choice, "Applicator")) + printf("A,Y\n"); + else + printf("C,Y\n"); + } + + /* + * Set tear-off adjust position... + */ + + if (header->AdvanceDistance != 1000) + { + if ((int)header->AdvanceDistance < 0) + printf("~TA%04d\n", (int)header->AdvanceDistance); + else + printf("~TA%03d\n", (int)header->AdvanceDistance); + } + + /* + * Allow for reprinting after an error... + */ + + if (ppdIsMarked(ppd, "zeErrorReprint", "Always")) + printf("^JZY\n"); + else if (ppdIsMarked(ppd, "zeErrorReprint", "Never")) + printf("^JZN\n"); + + /* + * Print multiple copies + */ + + if (header->NumCopies > 1) + printf("^PQ%d, 0, 0, N\n", header->NumCopies); + + /* + * Display the label image... + */ + + puts("^FO0,0^XGR:CUPS.GRF,1,1^FS"); + + /* + * End the label and eject... + */ + + puts("^XZ"); + + /* + * Free compression buffers... + */ + + free(CompBuffer); + free(LastBuffer); + break; + + case ZEBRA_CPCL : + /* + * Set tear-off adjust position... + */ + + if (header->AdvanceDistance != 1000) + printf("PRESENT-AT %d 1\r\n", (int)header->AdvanceDistance); + + /* + * Allow for reprinting after an error... + */ + + if (ppdIsMarked(ppd, "zeErrorReprint", "Always")) + puts("ON-OUT-OF-PAPER WAIT\r"); + else if (ppdIsMarked(ppd, "zeErrorReprint", "Never")) + puts("ON-OUT-OF-PAPER PURGE\r"); + + /* + * Cut label? + */ + + if (header->CutMedia) + puts("CUT\r"); + + /* + * Set darkness... + */ + + if (header->cupsCompression > 0) + printf("TONE %u\r\n", 2 * header->cupsCompression); + + /* + * Set print rate... + */ + + if ((choice = ppdFindMarkedChoice(ppd, "zePrintRate")) != NULL && + strcmp(choice->choice, "Default")) + { + val = atoi(choice->choice); + printf("SPEED %d\r\n", val); + } + + /* + * Print the label... + */ + + puts("FORM\r"); + puts("PRINT\r"); + break; + } + + 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 */ +{ + /* + * Tell the main loop to stop... + */ + + (void)sig; + + Canceled = 1; +} + + +/* + * 'OutputLine()' - Output a line of graphics... + */ + +void +OutputLine(ppd_file_t *ppd, /* I - PPD file */ + cups_page_header_t *header, /* I - Page header */ + int y) /* I - Line number */ +{ + int i; /* Looping var */ + unsigned char *ptr; /* Pointer into buffer */ + char *compptr; /* Pointer into compression buffer */ + char repeat_char; /* Repeated character */ + int repeat_count; /* Number of repeated characters */ + static const char *hex = "0123456789ABCDEF"; + /* Hex digits */ + + + switch (ModelNumber) + { + case DYMO_3x0 : + /* + * 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) + { + while (Feed > 255) + { + printf("\033f\001%c", 255); + Feed -= 255; + } + + printf("\033f\001%c", Feed); + Feed = 0; + } + + putchar(0x16); + fwrite(Buffer, header->cupsBytesPerLine, 1, stdout); + fflush(stdout); + +#ifdef __sgi + /* + * This hack works around a bug in the IRIX serial port driver when + * run at high baud rates (e.g. 115200 baud)... This results in + * slightly slower label printing, but at least the labels come + * out properly. + */ + + sginap(1); +#endif /* __sgi */ + } + else + Feed ++; + break; + + case ZEBRA_EPL_LINE : + printf("\033g%03d", header->cupsBytesPerLine); + fwrite(Buffer, 1, header->cupsBytesPerLine, stdout); + fflush(stdout); + break; + + case ZEBRA_EPL_PAGE : + if (Buffer[0] || memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine)) + { + printf("GW0,%d,%d,1\n", y, header->cupsBytesPerLine); + for (i = header->cupsBytesPerLine, ptr = Buffer; i > 0; i --, ptr ++) + putchar(~*ptr); + putchar('\n'); + fflush(stdout); + } + break; + + case ZEBRA_ZPL : + /* + * Determine if this row is the same as the previous line. + * If so, output a ':' and return... + */ + + if (LastSet) + { + if (!memcmp(Buffer, LastBuffer, header->cupsBytesPerLine)) + { + putchar(':'); + return; + } + } + + /* + * Convert the line to hex digits... + */ + + for (ptr = Buffer, compptr = CompBuffer, i = header->cupsBytesPerLine; + i > 0; + i --, ptr ++) + { + *compptr++ = hex[*ptr >> 4]; + *compptr++ = hex[*ptr & 15]; + } + + *compptr = '\0'; + + /* + * Run-length compress the graphics... + */ + + for (compptr = CompBuffer, repeat_char = CompBuffer[0], repeat_count = 1; + *compptr; + compptr ++) + if (*compptr == repeat_char) + repeat_count ++; + else + { + ZPLCompress(repeat_char, repeat_count); + repeat_char = *compptr; + repeat_count = 1; + } + + if (repeat_char == '0') + { + /* + * Handle 0's on the end of the line... + */ + + if (repeat_count & 1) + putchar('0'); + + putchar(','); + } + else + ZPLCompress(repeat_char, repeat_count); + + /* + * Save this line for the next round... + */ + + memcpy(LastBuffer, Buffer, header->cupsBytesPerLine); + LastSet = 1; + break; + + case ZEBRA_CPCL : + if (Buffer[0] || memcmp(Buffer, Buffer + 1, header->cupsBytesPerLine)) + { + printf("CG %u 1 0 %d ", header->cupsBytesPerLine, y); + fwrite(Buffer, 1, header->cupsBytesPerLine, stdout); + puts("\r"); + fflush(stdout); + } + break; + } +} + + +/* + * 'ZPLCompress()' - Output a run-length compression sequence. + */ + +void +ZPLCompress(char repeat_char, /* I - Character to repeat */ + int repeat_count) /* I - Number of repeated characters */ +{ + if (repeat_count > 1) + { + /* + * Print as many z's as possible - they are the largest denomination + * representing 400 characters (zC stands for 400 adjacent C's) + */ + + while (repeat_count >= 400) + { + putchar('z'); + repeat_count -= 400; + } + + /* + * Then print 'g' through 'y' as multiples of 20 characters... + */ + + if (repeat_count >= 20) + { + putchar('f' + repeat_count / 20); + repeat_count %= 20; + } + + /* + * Finally, print 'G' through 'Y' as 1 through 19 characters... + */ + + if (repeat_count > 0) + putchar('F' + repeat_count); + } + + /* + * Then the character to be repeated... + */ + + putchar(repeat_char); +} + + +/* + * '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 */ + int num_options; /* Number of options */ + cups_option_t *options; /* Options */ + + + /* + * 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); + + /* + * Open the PPD file and apply options... + */ + + num_options = cupsParseOptions(argv[5], 0, &options); + + if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL) + { + ppdMarkDefaults(ppd); + cupsMarkOptions(ppd, num_options, options); + } + + /* + * Initialize the print device... + */ + + Setup(ppd); + + /* + * Process pages as needed... + */ + + Page = 0; + Canceled = 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(ppd, &header); + + /* + * Loop for each line on the page... + */ + + for (y = 0; y < header.cupsHeight && !Canceled; 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; + + /* + * Write it to the printer... + */ + + OutputLine(ppd, &header, y); + } + + /* + * Eject the page... + */ + + EndPage(ppd, &header); + + if (Canceled) + break; + } + + /* + * Close the raster stream... + */ + + cupsRasterClose(ras); + if (fd != 0) + close(fd); + + /* + * Close the PPD file and free the options... + */ + + ppdClose(ppd); + cupsFreeOptions(num_options, options); + + /* + * If no pages were printed, send an error message... + */ + + if (Page == 0) + fputs("ERROR: No pages found!\n", stderr); + else + fputs("INFO: Ready to print.\n", stderr); + + return (Page == 0); +} + + +/* + * End of "$Id: rastertolabel.c 4920 2006-01-12 15:12:12Z mike $". + */ diff --git a/filter/testimage.c b/filter/testimage.c new file mode 100644 index 000000000..a3443f370 --- /dev/null +++ b/filter/testimage.c @@ -0,0 +1,101 @@ +/* + * "$Id: testimage.c 4485 2005-01-03 19:30:00Z mike $" + * + * Image library test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Main entry... + */ + +/* + * Include necessary headers... + */ + +#include "image.h" + + +/* + * '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 */ + int primary; /* Primary image colorspace */ + FILE *out; /* Output PPM/PGM file */ + ib_t *line; /* Line from file */ + int y; /* Current line */ + + + if (argc != 3) + { + puts("Usage: testimage filename.ext filename.[ppm|pgm]"); + return (1); + } + + if (strstr(argv[2], ".ppm") != NULL) + primary = IMAGE_RGB; + else + primary = IMAGE_WHITE; + + img = ImageOpen(argv[1], primary, IMAGE_WHITE, 100, 0, NULL); + + if (!img) + { + perror(argv[1]); + return (1); + } + + out = fopen(argv[2], "wb"); + + if (!out) + { + perror(argv[2]); + ImageClose(img); + return (1); + } + + line = calloc(img->xsize, img->colorspace); + + fprintf(out, "P%d\n%d\n%d\n255\n", img->colorspace == IMAGE_WHITE ? 5 : 6, + img->xsize, img->ysize); + + for (y = 0; y < img->ysize; y ++) + { + ImageGetRow(img, 0, y, img->xsize, line); + fwrite(line, img->xsize, img->colorspace, out); + } + + ImageClose(img); + fclose(out); + + return (0); +} + + +/* + * End of "$Id: testimage.c 4485 2005-01-03 19:30:00Z mike $". + */ diff --git a/filter/testraster.c b/filter/testraster.c new file mode 100644 index 000000000..bc35bb01a --- /dev/null +++ b/filter/testraster.c @@ -0,0 +1,210 @@ +/* + * "$Id: testraster.c 4545 2005-06-21 19:26:28Z mike $" + * + * Raster test program routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These 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 USA + * + * Voice: (301) 373-9600 + * 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. + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + */ + +/* + * Include necessary headers... + */ + +#include "raster.h" +#include +#include + + +/* + * 'main()' - Test the raster read/write functions. + */ + +int /* O - Exit status */ +main(void) +{ + int page, x, y; /* Looping vars */ + FILE *fp; /* Raster file */ + cups_raster_t *r; /* Raster stream */ + cups_page_header2_t header; /* Page header */ + unsigned char data[2048]; /* Raster data */ + + + if ((fp = fopen("test.raster", "wb")) == NULL) + { + perror("Unable to create test.raster"); + return (1); + } + + if ((r = cupsRasterOpen(fileno(fp), CUPS_RASTER_WRITE)) == NULL) + { + perror("Unable to create raster output stream"); + fclose(fp); + return (1); + } + + for (page = 0; page < 4; page ++) + { + memset(&header, 0, sizeof(header)); + header.cupsWidth = 256; + header.cupsHeight = 256; + header.cupsBytesPerLine = 256; + + if (page & 1) + { + header.cupsBytesPerLine *= 2; + header.cupsColorSpace = CUPS_CSPACE_CMYK; + header.cupsColorOrder = CUPS_ORDER_CHUNKED; + } + else + { + header.cupsColorSpace = CUPS_CSPACE_K; + header.cupsColorOrder = CUPS_ORDER_BANDED; + } + + if (page & 2) + { + header.cupsBytesPerLine *= 2; + header.cupsBitsPerColor = 16; + header.cupsBitsPerPixel = (page & 1) ? 64 : 16; + } + else + { + header.cupsBitsPerColor = 8; + header.cupsBitsPerPixel = (page & 1) ? 32 : 8; + } + + cupsRasterWriteHeader2(r, &header); + + memset(data, 0, header.cupsBytesPerLine); + for (y = 0; y < 64; y ++) + cupsRasterWritePixels(r, data, header.cupsBytesPerLine); + + for (x = 0; x < header.cupsBytesPerLine; x ++) + data[x] = x; + + for (y = 0; y < 64; y ++) + cupsRasterWritePixels(r, data, header.cupsBytesPerLine); + + memset(data, 255, header.cupsBytesPerLine); + for (y = 0; y < 64; y ++) + cupsRasterWritePixels(r, data, header.cupsBytesPerLine); + + for (x = 0; x < header.cupsBytesPerLine; x ++) + data[x] = x / 4; + + for (y = 0; y < 64; y ++) + cupsRasterWritePixels(r, data, header.cupsBytesPerLine); + } + + cupsRasterClose(r); + fclose(fp); + + if ((fp = fopen("test.raster", "rb")) == NULL) + { + perror("Unable to open test.raster"); + return (1); + } + + if ((r = cupsRasterOpen(fileno(fp), CUPS_RASTER_READ)) == NULL) + { + perror("Unable to create raster input stream"); + fclose(fp); + return (1); + } + + for (page = 0; page < 4; page ++) + { + cupsRasterReadHeader2(r, &header); + + printf("Page %d:\n", page + 1); + printf(" cupsWidth = %d\n", header.cupsWidth); + printf(" cupsHeight = %d\n", header.cupsHeight); + printf(" cupsBitsPerColor = %d\n", header.cupsBitsPerColor); + printf(" cupsBitsPerPixel = %d\n", header.cupsBitsPerPixel); + printf(" cupsColorSpace = %d\n", header.cupsColorSpace); + printf(" cupsColorOrder = %d\n", header.cupsColorOrder); + printf(" cupsBytesPerLine = %d\n", header.cupsBytesPerLine); + + for (y = 0; y < 64; y ++) + { + cupsRasterReadPixels(r, data, header.cupsBytesPerLine); + + if (data[0] != 0 || memcmp(data, data + 1, header.cupsBytesPerLine - 1)) + printf(" RASTER LINE %d CORRUPT AT %d (%02X instead of 00!)\n", + y, x, data[x]); + } + + for (y = 0; y < 64; y ++) + { + cupsRasterReadPixels(r, data, header.cupsBytesPerLine); + + for (x = 0; x < header.cupsBytesPerLine; x ++) + if (data[x] != (x & 255)) + break; + + if (x < header.cupsBytesPerLine) + printf(" RASTER LINE %d CORRUPT AT %d (%02X instead of %02X!)\n", + y + 64, x, data[x], x & 255); + } + + for (y = 0; y < 64; y ++) + { + cupsRasterReadPixels(r, data, header.cupsBytesPerLine); + + if (data[0] != 255 || memcmp(data, data + 1, header.cupsBytesPerLine - 1)) + printf(" RASTER LINE %d CORRUPT AT %d (%02X instead of FF!)\n", + y + 128, x, data[x]); + } + + for (y = 0; y < 64; y ++) + { + cupsRasterReadPixels(r, data, header.cupsBytesPerLine); + + for (x = 0; x < header.cupsBytesPerLine; x ++) + if (data[x] != ((x / 4) & 255)) + break; + + if (x < header.cupsBytesPerLine) + printf(" RASTER LINE %d CORRUPT AT %d (%02X instead of %02X!)\n", + y + 192, x, data[x], (x / 4) & 255); + } + } + + cupsRasterClose(r); + fclose(fp); + + return (0); +} + + +/* + * End of "$Id: testraster.c 4545 2005-06-21 19:26:28Z mike $". + */ diff --git a/filter/textcommon.c b/filter/textcommon.c new file mode 100644 index 000000000..66255e18a --- /dev/null +++ b/filter/textcommon.c @@ -0,0 +1,1195 @@ +/* + * "$Id: textcommon.c 4559 2005-08-04 18:40:13Z mike $" + * + * Common text filter routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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", + "const_cast", + "continue", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "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", + "reinterpret_cast", + "return", + "short", + "signed", + "sizeof", + "static", + "static_cast", + "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 && + strcasecmp(val, "no") && strcasecmp(val, "off") && + strcasecmp(val, "false")) + { + 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_PLAIN; + NumKeywords = 0; + Keywords = NULL; + } + 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-csource") == 0) + { + PrettyPrint = PRETTY_CODE; + NumKeywords = sizeof(code_keywords) / sizeof(code_keywords[0]); + Keywords = code_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_PLAIN; + NumKeywords = 0; + Keywords = NULL; + } + } + + ppd = SetCommonOptions(num_options, options, 1); + + if ((val = cupsGetOption("wrap", num_options, options)) == NULL) + WrapLines = 1; + else + WrapLines = !strcasecmp(val, "true") || !strcasecmp(val, "on") || + !strcasecmp(val, "yes"); + + 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 (PrettyPrint) + 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; + + attr &= ~ATTR_BOLD; + break; + + case 0x0d : /* CR */ +#ifndef __APPLE__ + /* + * All but MacOS/Darwin treat CR as was intended by ANSI + * folks, namely to move to column 0/1. Some programs still + * use this to do boldfacing and underlining... + */ + + column = 0; + break; +#else + /* + * MacOS/Darwin still need to treat CR as a line ending. + */ + + { + int nextch; + if ((nextch = getc(fp)) != 0x0a) + ungetc(nextch, fp); + else + ch = nextch; + } +#endif /* !__APPLE__ */ + + 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 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 > PRETTY_PLAIN) + { + /* + * Do highlighting of C/C++ keywords, preprocessor commands, + * and comments... + */ + + if (ch == ' ' && (attr & ATTR_BOLD)) + { + /* + * Stop bolding preprocessor command... + */ + + attr &= ~ATTR_BOLD; + } + else if (!(isalnum(ch & 255) || 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 & 255) || 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: textcommon.c 4559 2005-08-04 18:40:13Z mike $". + */ diff --git a/filter/textcommon.h b/filter/textcommon.h new file mode 100644 index 000000000..c11737019 --- /dev/null +++ b/filter/textcommon.h @@ -0,0 +1,123 @@ +/* + * "$Id: textcommon.h 4559 2005-08-04 18:40:13Z mike $" + * + * Common text filter definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + */ + +/* + * Include necessary headers... + */ + +#include "common.h" + + +/* + * C++ magic... + */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +/* + * 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_PLAIN 1 +#define PRETTY_CODE 2 +#define PRETTY_SHELL 3 +#define PRETTY_PERL 4 +#define PRETTY_HTML 5 + + +/* + * 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); + + +/* + * C++ magic... + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +/* + * End of "$Id: textcommon.h 4559 2005-08-04 18:40:13Z mike $". + */ diff --git a/filter/texttops.c b/filter/texttops.c new file mode 100644 index 000000000..879672c95 --- /dev/null +++ b/filter/texttops.c @@ -0,0 +1,1311 @@ +/* + * "$Id: texttops.c 4680 2005-09-21 09:28:39Z mike $" + * + * Text to PostScript filter for the Common UNIX Printing System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * This file is subject to the Apple OS-Developed Software exception. + * + * 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("%%Trailer"); + printf("%%%%Pages: %d\n", NumPages); + puts("%%EOF"); + + free(Page[0]); + free(Page); +} + + +/* + * 'WritePage()' - Write a page of text. + */ + +void +WritePage(void) +{ + int line; /* Current line */ + + + NumPages ++; + printf("%%%%Page: %d %d\n", NumPages, NumPages); + + puts("gsave"); + + if (PrettyPrint) + printf("%d H\n", NumPages); + + for (line = 0; line < SizeLines; line ++) + write_line(line, Page[line]); + + puts("grestore"); + puts("showpage"); + + memset(Page[0], 0, sizeof(lchar_t) * SizeColumns * SizeLines); +} + + +/* + * 'WriteProlog()' - Write the PostScript file prolog with options. + */ + +void +WriteProlog(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), "%c", curtm); + + puts("%!PS-Adobe-3.0"); + printf("%%%%BoundingBox: 0 0 %.0f %.0f\n", PageWidth, PageLength); + printf("%%cupsRotation: %d\n", (Orientation & 3) * 90); + 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 & 255); 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 & 255)) + lineptr ++; + + if (!*lineptr) + break; /* Must be a font mapping */ + + valptr = lineptr; + + while (!isspace(*lineptr & 255) && *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 & 255)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr & 255) && *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 & 255)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr & 255) && *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 & 255)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr & 255) && *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 & 255)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr & 255) && *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 & 255)) + lineptr ++; + + valptr = lineptr; + + while (!isspace(*lineptr & 255) && *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) || + strncmp(fonts[i], "Courier", 7) == 0 || + strcmp(fonts[i], "Symbol") == 0) + { + /* + * 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) || + strncmp(fonts[i], "Courier", 7) == 0 || + strcmp(fonts[i], "Symbol") == 0) + { + /* + * 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"); + if (NumFonts > 1) + { + /* + * Convert a number to double-byte chars... + */ + + 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("\tgsave"); + 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 & 255) && !isspace(line->ch & 255)) + break; + + col ++; + line ++; + } + + for (i = 1; start < line; i ++, start ++) + if (!isspace(start->ch & 255)) + 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: texttops.c 4680 2005-09-21 09:28:39Z mike $". + */ diff --git a/fonts/Courier b/fonts/Courier new file mode 100644 index 000000000..5ec263dbe --- /dev/null +++ b/fonts/Courier @@ -0,0 +1,1494 @@ +%!PS-AdobeFont-1.0: Courier 1.05 +%%CreationDate: Wed Dec 22 1999 +% Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development +% (URW)++,Copyright 1999 by (URW)++ Design & Development +% See the file COPYING (GNU General Public License) for license conditions. +% As a special exception, permission is granted to include this font +% program in a Postscript or PDF file that consists of a document that +% contains text to be displayed or printed using this font, regardless +% of the conditions or license applying to the document itself. +12 dict begin +/FontInfo 10 dict dup begin +/version (1.05) readonly def +/Notice ((URW)++,Copyright 1999 by (URW)++ Design & Development. See the file COPYING (GNU General Public License) for license conditions. As a special exception, permission is granted to include this font program in a Postscript or PDF file that consists of a document that contains text to be displayed or printed using this font, regardless of the conditions or license applying to the document itself.) readonly def +/Copyright (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development) readonly def +/FullName (Courier) readonly def +/FamilyName (Courier) readonly def +/Weight (Regular) readonly def +/ItalicAngle 0.0 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/FontName /Courier def +/PaintType 0 def +/WMode 0 def +/FontBBox {-12 -237 650 811} readonly def +/FontType 1 def +/FontMatrix [0.001 0.0 0.0 0.001 0.0 0.0] readonly def +/Encoding StandardEncoding def +/UniqueID 5020945 def +currentdict end +currentfile eexec +e98d09d760a3c22cf119f9dc699a22c35b5b35ed6aa23593c76d54cabb5e +942bf7d6dd84f1664b89699c74b472de9f8e6df925f6c4f204e9f1c639b4 +dba988ed2ac419ff2b2bde605b8ee3264edd66412d4f21c64ac522bdfc7c +5502f9c3f3e5592b3b2093d33c9bfaedd2d49e89aabaa832e23f062e91a2 +5032519d1868816e44b4e0747795003d7930299d6e1e2a5bfe0d595dc97e +140989ce81d8d7f852ff9cdc7a1b1b598c69131dee005b415805a16d8a12 +3e6a2261c63c769d2f4b60fa2c438ad7d199d8e45f7e7c9a605c8ca14e21 +fcd81c9a515fb8db6f99604534d06ea9d87fe0faa852899c9d0595c7a97e +6c55f79fac45cd38e87b10d210ce7501e88c8fcd3444354365fb893a12f5 +96ae2c1e70d5819ee0d087d10bf8da96f3dabd5405d28c4228c6c31ba405 +2464859640933feefd8071c0c84cdd829a9b1d0ba01f25a4d50ee2ea2b45 +160ca6333b2d2800306ed2befdfe155e9d9f9342eb8d5b0adbf2460ccc98 +643fb1287ccd28aba7b5cab92ec39ee2e918990372b16f8487eba30eae88 +708b6cf33b6c015d8096c7cfe2f139f52052e3925c0d50fd64ce68236d59 +cb83ef56bfc584150ec38065059f3308ad6f9a99f83ef4e6cb13855c8175 +e31417d190d036b387d3952344a950f4d8c7781b307a094df1ecaee4d2c2 +fd747bc6f7f9c6bd0e90c19294f96c8c5cfe88fb34c477574a1b1630b8cc +591529e59b20794da32e61decda8abbd1ae956cf74012aa01d42ee01e861 +b0aa6897c864788ae59def43c493246fdb1aca554c12594bc7b33657a9ec +c9e3d1472ef826073f632be540c35ff6fb40566773f3bb2204d3a579a08c +cbc844c14b18c350f003b9da23a570c362d6003893ca32f86f59b829c78e +e3188b6e3f7fa81d7f622825c639638dfb78b7af1f500f5b450fa54dbfa5 +cba277c794ece93275a3de0b452fdc8ddc2993baa42f28a636008cdcb03e +bf71bdcaf35019778993443f88412ad2ad0d7155a3944606463266322dbc +0244b07da1e9c27a27b59664e8566d7a54cc03e995aad008b0a17e2c3ef6 +1f720ce7f7788599c4e44c709cd5c31b11107f16ad70b17b9afe2e8cd922 +a7428dac171427ffaf51067307fab0adb530e701fd22da22c4cd3064067b +d4f6089c4b2c87937dd426e4e9d2f60e608288bac9056554d04947e69200 +61e379cf5e81bfd32fd37efac1f61cebee551b0851516471a7472c60df89 +daa9eb1dc5a67e4797453e69b9e22baf4e3cca4192d603295b018c4ab69d +18de52dfdf15e96b557f290a4b8c5b1e7a6caca81f2351b97adfc36995ab +a43803a6e5ac04a3c93495f6d38106b8b144449c07d1358210f9176e1565 +72363cfbde576bfdf99fa329dd1346e83f79e06cf68250ca57a68931bc7f +342ad295d0cba17aa95bb8eeb53ea6e8e660b814e9f857cecb14f44a4328 +8b69a9e7908d55bf19e844359879d28caef1c38a36420185d20dfb32c2e0 +02202800e8ef3d67c5d50e919657ca958b538d537d503444865331d79bfc +40312068d72364503bd0cc84b5f30a74d8b5b6a26af2db764564fb65a6ba +8f9051ae2b4ea458d46a4569f30c6e77dc097356770362e6cf3f16610747 +78ebb44ff7d1e3b64ff75e77e11fe525bb121c6546cfd13300ca1f02d571 +b82a5825e6226d14fdcf27f06d87452a8b6c5dca658535cee2a795e58137 +d48e566b69d53a0c3b766e84c51eaa221c46999cc8065adb2f129d5b630f +ab1814c0c33b5aea0efbb6e994d80941b53079af96d90a0b924f9b0e319b +ed9836b8f9053f868363d3ca554cbb181863301f8cb940872ed5fa7bd18c +e39218b5ad8ac57d0f752d941076b1c64d99be0db86d7a6d96510d772eb2 +4c587f11779bd21cfe5bde1f29c1ef9022b2b8bcd7f91153c84590672247 +7829c40111d810480f3cf62de8dba7fd86cd236e656618caf6fc46827fbc +4898ea7672f8c9971afe43e0e01ec8b77d4af48cbf1210e98c1db15c16d1 +49bff58ab0270cf015b107a3a50f5dc8f37ffb92eec8cb6778ddb7ce4aab +c464c4aff654223006a550eb52485a23d2b4aa7198d3cd54418102f1e9a4 +fbde37b841e56f5c2c53966db9b66b000e4588282e3fb80c2c519339f000 +2d2f83c979edc5827a3b3c8ef8810a0f9dacb6b9998e9af6551f56313dc4 +011904cb979aa2d32b11a811bc248141e4b9734d9fb7982a5671002d8279 +cab93abe057474628defc95d43890db1ed34cfa8a20bdc3d874e7679a396 +158e522ed0ab969a4e3ec7e4474e192590504d54deb7b260b7935c4e5654 +8a7d121ac1f741f8cdf259ea1b5813175a77a1d2d30ba26f65eb765a04c0 +9ed51f69f41551adf399e6aa2fc09788137bea4913f17b8eb838c38fb272 +1fdcb55fd65697ff0b850e7d3d1ce266bf90f7ec06a9a0876bdfe767d3a9 +18b092fc78c775f945cf1f96e859c03dbf630d9a940939654c3549d8f792 +1cb94ee23d5a0535de9df31ea0f937f860b4f220a99addfc343d7cf7bfa0 +b803c12c26403f0dcffc8ea786d0d8a8d9c367419ca8ae41190ce93a8086 +583a1e6c9d70b612c84d87d2eeaa71ec2dc12f4cde6a821303d5f6a9bbdb +7eedcd289e80fa3b75f47f481b50719dcf4a142069393593b9af9cceeaec +56a35b8787193d7c88113e9e1e221d151e093b019ef89f6118bec4735103 +cc8003cc5ad1b6727b3226cd44c497da7052dd681695dbec3397f9598c91 +77701c73bf0594ce93f23d50ec5bee2fb9da1fc966df148b27b28ee3c895 +26dd6625e2887f9fa0767c127c609ee315626bc14d274fbea56528dc06a2 +7b2d476d46e9e7916590b156a5df04a6cb15e36245d77021767b6e5bdfcc +679670263fd891446c3371b11bb6e1df60f960aab4149d7753e6a5c33810 +c42c8bff4e935003388506f8278bd7cb672f132e065ae684dca0b9064d01 +dd620e7ffdfe04f14277efe8e60159ba0fca3fe2f28b902d4ac275d19f0a +c6971ebe827c4a232d87650d2688345bca78f879077114f0463c5f058107 +b669566f8171e4e284d278405580f04bffc9902784216e0c9a17aa9b2935 +e66e18a783f723be044389b7e9d62aa36818ff2ea406c3c1a9d2f3436f3e +e7db8be86afa8daa6a4b1b84611350d8d27605509612b515e16aa843164d +5d0805e36a2b9ef74c5f6a0b9d59a04b5569712327f4b1b30e9587cd1033 +37639967cbdc655aa46e80d2cfd24beb50815b5338e522b3a7afe8362ab4 +f05d8bc52bba9c5089ada8c89529b0275af422eb540d31a938b874086075 +6325b966b36817115213faaf92de63f6bae1e0064bfbc5588098b61eb83c +71f1c2082436d37daf1acbe186fedc4be7c1233b6f18bec5f99002d21cb7 +864e4811f7ab3c03003e1e4490ad1ac793bd28fcd5ef0e6cc30ef39a08c5 +2f71939b0cef620dc69e31e39d6db969049031b0c92ef2db653d97f37014 +1456a52985076b268652fa2648c792780bad637c4d7581fb2d62011d57e2 +93719487cf2d1f013cfaa532e1c2d39178d51272a6af041440bca174b5cc +902bd7390c7d3695056cb4bd7791f9fb6d88e7a70def2c97869f5dbc5bd8 +23c517c7b7c39d624df627dc9653ea5347bfda80b723f05f6dbb4c9ea501 +d862ace05b9dbdf21b7056fbcd8c6d4b85873dcee6166c8b5adc0316ca12 +d9639f361b15a42f00e1d62edbca1111972fa0f45758becb31db38316f3c +dfe1b41748c93ed58b67e9b57abbed5924a6d53e99fbc9a994a6489a8bdf +13eb685548b4dc6d62da7426c22227d4d43b6ffc7b5ea91c896730253e89 +41afee588359c2becf6ffc415b9eb6d31ccb0f6c7f85853e6449fa6d627a +97a3ce8303f148393adcccdfa2fe085c6908be5c3c05af00a6f02840206c +3253a559ac5c049bddfd11ad9b118403b84da10ae3c470cb9a9a2d1d7b73 +2f59f5fe146deda60ae750f551aac934621b4470e1bc324c436303e25f81 +d0dc3188be0d6fec5414c20e4cb18952e12cb6423df7124627acde145500 +d77a97a8bfd9cb50d1faa008e2ce2b2505a4749f1ebbb092c34702371405 +5a9b63353af9e7fee05bb54c9843698101f79888a91531773830c2c967b5 +88d3acd2192883d5ce3962d51084fc653eae2c5fb2da41dacefb5c76812d +2edb5b109677289cd1998d457fb1023a19ac67295bbc1a9a20a426b06a36 +8df3c5dd083cb1180d287f5500f2c635ede157eefceec5503447382d15c7 +48c1e35f68753992e5c90f900de54d18f8e1b355d1076adfb1f3590135fa +d1a36f028e44f48abb149b80ca9a54614d467f8d71cb310bbc7ac7100261 +092db8c5bfd39e0ac6bc2c9d6cbc3a8c05ff8a74cb21608ec4a4cfe4cbaa +2d056dba14206106044decf59f957ef8a9cade4c9b19d8d30dd4fde6a954 +8e50db51aca73330142153fc36b69c1c8d5b26d0c689b7040e81ac2c864f +d7c097c99be5953843e172c97ab5684f35fb03a725a89dbf371f08ddf40a +1531fc1b676db0e1543aec6e97d3d2e4aa3d5831d8b3c952abbfa1123528 +14fb6fab61a0d680e6640f6aec8426200cf61286f7422cb2f78c61ebaa36 +d47ec16d7faf8b4af31d090cdfa255d9d7c61d46cfb22a7d6e1758e71ed5 +67e00cbd8e8f468ddfb477f091a2f915627f22ff47b876544bc1f03b6bbb +98385f009c20bb1aa2a7a78674692b8eac2e3c8069b79e679338da57f729 +76810f845beb6b9add32b95d78e5e60f16dd16689c05fd82d36a3115be8e +d494a74dd211d58a2cdf983fcb9cdc29bf7f0e29988fa23560edf514bc1d +183f3b2a22c09fb179b47e05adef48df02f31c29875d1915037b19407764 +a4292fe44e741651a8e3beb5f0d972b6327090f664417c84f84ffbf0afff +8b1d85c822d90730ab4140c42a51aa8b1dbe43984ea8566040eb8b341cce +23fd3f69dd235a080ba5c69aecb9bc732bc2d7d40617dda6b79fb6ee40c3 +556c7df9b23dad89e94054b1345db8402ae679fc4655a4a776c0150463f8 +db2bfc0608ea1f124e221ddae6026b5e5d007a7e4a0d6b3b0cf3a2669e67 +c5e4f01551966a7bc48f2f4b6a87e740d8095e63f77c7a027f26b52f2299 +de5b8a2f6209bcf3d31cb0235f998f781e5cc81e31dc424e008d46ec0920 +2951e5684804a0592ea47d6c788a20487bea2ec8f2e6c1d7f378b62db43c +a43c4b366f8b4319631cfe9854f0e10321cfa3b01c873584863bbefc23c7 +2c05e695b56e8a52e89aa2dab543834d34dcac5fed08dc51825c5257ae59 +850d101d84f4caa1d29fc932f9e0effbf7a9a7f3685f61f0490cd3cc8988 +2db52a757a6af4c4e67b407bd2316b1c0ffe7dc54e43c87b874f57e49033 +34e2140b011484863cdcaca331175f2cf3d72e0042855983aaf8853d3015 +e870ff0807014c31d55060df3fe1fce1573244812744ab51322444632f9a +fda6706e320ffe82b8cbe242a19df00ce73ee48e25ff49d5871bd3e60652 +298fe3e8d400609e232e0ddc794c0579acef89e841b2edca50d51151f65e +8c1cc3b01ef1870558f0bf5743718c3e068617e81bfe120c6ca16e0924bf +c2541177d53671caa3ab641c41557dcdae1a346147b5e999c4541b08b4af +cbc187afd653d5b5f8386df6ad8fe69e21bd0567df494f736c6a184fa4de +48dc9f347787ca96e2e00a296c2da05c2ad9bc423e9ca428d7f1fa12dc93 +53a302fb8c529af8688cbb543b45b2717ebf8f6c497935f4f3bffd285e04 +02ab7544b3ca4643ae5a8b5250ed987a95fc1f275b9707acd0641bd0ee2a +e9758494f8d8a51dce408a38ac20eaf0852d72d84d0c6be973326793aeb9 +55eac6fe0a2813a355dcd22f6f2ce56588d1c055cddfa98878bceb6a018d +b22922d2b600a20f81842e665df41013ca0947c4237c2bd60a75e2fd1a3f +b8c8fa19485730b87461ad466acb02df8ca240914fb090b3d2b41eb6b8ff +05e1a59d9fd668af70ba5bb72778953ba55fc5f9f626043450e1d09bc83d +8605098abef884639a37809a32565cbefb3ff39ee53d6c18c58c272bb928 +e4410e361e59a50f242d69747a032617c52debbf62364ab5a96efaf642d9 +d82ba679b1d70fac10a4eb62fa5cfc308e86368aaad7e75948f43598cd1c +544a0d4091374d7e88d4522cbe902391641327e888e7748fa889dce67ade +61699e7d77763681caee9b1ca8837b2f7ef9c18cbcc538c465c8e2dd3461 +6953ccb6030a222c728b834911c1a179e2c770289407ab28b303e724d97f +747d6134b425216a64c6e0b60f633e2b85300047e4c90339ce030a0fae31 +e830c8aba5ab3386a3b69267351a7bfdd66356ae5e57fb2994452993e90d +e7c4e260abab93c37831856a650d56e44172feca01d6c7c380f250b82473 +960d2a2a5fb6b4da668f46e624acf7fa0fd4490f485d640a3adfc9f8652e +7a38ce5799f770c3606db4b8b947f93967f779e3a3c0572f13a5a187d31d +7bd12a5c7be23cb6ed6192086241b76c5ba6983db9c93e4b208d707d3760 +f03cd6272ef3a4ce89b8e52e6ac5871a3d03eb975759ab4be239e5ec7842 +cbb333e692cc607c722e185d3c39164dd320c6945629c70ff66a5237c0a9 +520a1fad6eb9816069351ab0f135d90cc0982b147d2294ae4a38a527ee40 +be9cde2512aaebb590e134388bb171d0956a7c4566d65a9a041be6c4f883 +6b3ec3d2ed1b48b566a783292b15b6127920d247d494f070bb20beff6064 +0b11b276ddeee49706e8b2b21bb40b7f00aafc594c492c25dca774e0b80d +82e927448de2e74a9d0dc7ac9260096eaf187b6cd6aeaa6d1dc4205b4411 +122751a5b22688404ea7c5861730371ffac10f5afd4727a0e402ab5ea757 +606b75eb86a05e8f774d6e430a1a3fe2a37ebb06700474239fb1cfa05ee4 +4b91b82244c575b52e7faf934b04eeb0d933feb57ebe326d75821c8b23ea +a85b583aed4320b7f04b9f2dc591091216fde52e064baaa9c2c9d9714b95 +a4558c21f3cebe624b5403b31508f178581af6863083ed762f1e2e34a45c +fdd71660d626ff8648f5d6c5e580d4765a67fb6159ec8077a9f0a88038c8 +d3d7c77ff0926e2123be874f7bcaf129d55a5b5960f824bd1728abcfcc51 +d23936de9a25c408d786e44c3a2bafa4423177ad060d21d38e15e23eb6ff +c0b4120e814695d423eefc2744a1fc81b4df89d76f0a6803d8b14e75538c +aad03a72517b86514f6952f6fd619d9e910d980f00964db325318c045bdf +79647f453d4a5cf4e61dd5359782827229310405fbcf6107c3ad9ddef9a9 +a339d5d5a6eb2e7838a0a43221bd62cbdf732db0a638a52016fb35ba7761 +aec846a023d3bf2d1bb183543e81eb7cac1e5970cdc6f068c5ea118c7aae +528d1396e6dc939112da4460c890ead5c01bdc438f5bb734218ba6270add +0dc1778fd8ab16831d6a302b814a1a44b07edc65956c9e6cf4875df521f3 +ce5b422f71081b6d69bd270f739095c9e81c0377934a8bc6390c420c4e4c +dd9cf7e32544c68d884e15aca3bcc07fc8c132d8fb9d752c15d75c52c288 +57e2ea461a6fcad90c56843513f74461f18d7164bc597a28ae4ba7c86ee1 +703535a9b9ed5012262771fc12f102e800e0e1af7bb46681bd2b14b614ce +a91b7b2aaa35235de76c0e113c92688f8ec81277d58c3406778e1ec1cc15 +f1cd9a137c8ffdaab99ace3bfc782916f1a877170589a92dc921e6740a22 +b84dc6bacdabcc76e64c79e3a588d80f8f4d376e1b426f15751cf7391102 +102f0afafd8b22dfdeb548aeb5f30b1673023d22054a13391a0ec08de6e7 +b685a0d031aabf20b7c62187c0284892d5eaadf121ba28263eb863d5e36e +a9c06a77ccfc0e17f593961591f84d82af823efe41044c8d606fef83ccc7 +b0e961e7994df8a3cc36b209d953e250adab8d22d7f2b4e2c9ca39efa2d9 +3e56195c1560e30a5190cc5b17faefcf250df79f6b624a4b917e11c33222 +2fccfec4f6a47bd9e75da9854fc3f7ae554e91edde144d7aef38a0e3edb5 +e5a5626374db94f022c8cf549093041de00d7269b7ce544e748439ba2870 +718c08e58fb4a77d93ebc04b7957d272ae1601d41bf85a2badaa0df73b0d +3841d4839c85677fb2e15f1d6ce592669ff4bbc9c69dba334dc37706f2f6 +be83d5863e8cd6a30c08640aac4c233684e66b4fe6b62d4a8be9d531e47b +ef5640d9b5c27d990092be1597f6995c8a77be9c18aae6c1cf130775ddac +41d34438fc7ad8e042cb56cbf2944932eba7d053e9376ff398367450e35a +1945fe23e05c921096a15454721ffd0f429a3e06dc3ed36f1c170be79c66 +996ef8337aff85b90c5d3a4a94455ae9fa32e2117a63e59001f052d5f622 +3125bfafa40901e98960adf7bb886729dca82fc3b8cc52b37ff2517299e1 +d769057f8154fb95582f02cb0becc873a9c71796adbd3e91324faa94f2c4 +1cf57c30b5897d031c02d256c909e080e70bfd1f32e69ef67031138c2ddc +d1a8e4b65e485c23c3e450abdd9815512d6f34a84b9db715db2c7a93bfb4 +24316e1aa44397749cb01088428f149a3b4324737ed9957fd388248462ac +1b2610d72bf5c073eca567e7385cc959e37cac7e05470160ffa5a9f63b8e +9b082937e911586ea165374938f492edf28ce6020953a5b5ccec7737f9d9 +cc8538c4339567aaed3794aba3b9f4eae65466e8e326f6c399b36355935f +bdcb9972f10b13494dc25097fcec5a6398f275c8c151558e74c5175f7baf +4155e36b733f75cf9d5c5979b0764f14d8306e06ba24bf791141e404c69f +3f8fccd91b9c58c2c671aae7d4f9e5d6414e46ed633a5f78aa5bf04e6522 +46a066ead9e582b181cc196ea2d3cfaa383b5d0e4cac9336e119c08cc6ac +55cbfbae147c623b400453bbf447e96de036fc025624384359eed7c7d5f7 +858dc0521377cf647a157fc3f188de5eef094dba125510fde34c570d7be7 +6ab5df0a28bf45ddaadbea7eeedb936332dfe93081e0afd3fdd46bed08d6 +914b2efcfdc41662a33b90b03d76d34f48d30fc6bbbb600e90e6ac7243fd +f026762a44b4d6e4ecbef48c9d7b696af29eee063e557d8fcf0f09e0136f +45d17e608da36e59f2aecf8493f8d62536119b5f7e1554dfe3f6e8d7c9a2 +c6f557d18b4af92c9f6e050975c3b5c54f9b5f4e39d600b6fa2cd6de203a +174028cbb2a201af126d1013c229bb82cfd013ed199d01e51ee2780fe896 +e01c63c655087a3e61a7f1029fa5e97ea1872f1b45f22282ddc317e17926 +7368cb52da9444f6055a3c653659cad2a1d8712bc2b1b32c1dc6906d957f +b88524ee066156ed6bdeb8d832f9338f9912e29a250a8c4674e667c1c278 +b677aec9972be83cba3fb779893fcb8f81a323ac91474ba2a2334a07bb56 +28e905c518e634f6761a3289056f83d5dd7b3890987eee1c18fb2d379cc1 +905f1aeb3b3d2ad578f0d6c845d2d40c4bcee3f71c90e68e5417bb8cddd8 +78d83ba80ad8485f4067e5c3cabf28ab56cbb219c0aab8ffc6c7e192bec8 +cbca1459ae4450afcc81b9548f40ce2622e5a7c281f74dcc02dad57efd92 +d072318ddf05bf42f1ea8163071e23949b0179cf7de64677ca99b23cb926 +b3e294194ec13397ea1dc9a5e1cdcd828156cd71f81b64167d4fb01e6002 +713bd8ac6f82b20cd3699c6ca4704dc5c65a2d66eb155b7af1c9bb464694 +16fb49c1c7e17a30a5f045271d7df3fff2f42c6b470701c381e3456a500c +6bb3d0e47b4d91c5f34b49bb6272f1f8698b307d89eda3a1565dad1c0864 +627560cf922dcf5b34c67860352390b282f95394aa2cde0e97ce3ed39546 +a6af1c52bfcf81a29be82c47c99e8050e4889e4575b75f39e662f2db7420 +673797e2ed3d67cda7ae2c15d0a0a794d57d168ebe13214e89e0209ab2c0 +eb7784e9491aefa3c02d0df3ae5365a0fc4ae023cab528162c7a1b173664 +9dfaddaca8da5fa18b7d6489e4229e9e24d38a620464a744a5c60f6f9d33 +4b908706b738aed186698a8b278341fa4d65a0a88680ba484694921512f7 +de93337fc1c02bbe6e64af2dad07603279d873291d1f4d39c1dd6d89c90f +65240f4808f6f1115ca55b88e242565e59f3bbf1f10ec7b88872e9ae61d4 +4cae185463edfaf7df63de4d2207d307afb61501892965170d2945846fcf +5973a1d458607f50c15e06e5bec715e0c156259aaa6c735593e5564f65f4 +43b78cc7512ec35a56f126df9d30974a40872e4265e1ae5fd483cfcbbba2 +6dee426cdc4721f19c3fda86ed7ad4fa1120f63669befe7002b128ceafd8 +c63e8ac09943b6cbdfb3d2476a026c00a8ff81b1f651b97f310c82aba5f3 +88cc1db5afcff5996d5252a6a42fa4d972e41ee56088f78cb966f9051171 +c472c774879aecfff08bfd9cea40d7c298922ace64f28c14e0b81f4dcade +81d71de3983d87d905192ef13cee71b2d3ff1a88aec671ec318917df98a3 +c9054e372d22a3cec82fcc217f47319a40900312f6e32b536b9e7a7fa083 +7ec65ccdb5fb0d41437117596cb39d9382262de6e65379d3a9709b2cfbab +f5fc5d5b352425f06f88cd31012a2a4147b112f0c1c0accc808cd625e022 +8eef66661f70af96d3dcfecd402700e4f6522ac9a856da466d55c84f65be +2810a1565163872d62eb81333a698ed7b68352cacca2d7ad38ab55c19e4f +5582f75818302f5fdadf1dced09d94872f2d48fb636c8e38c7563c72c771 +a08c6b1f041f3532bdb39006c89a33c09be1e3e603622d891f98010bf1de +5355f557a1e09448d486adef565705277b31b8bf2b86761e32631e3435b6 +88b79d566f1747ba456ddb43cd239fb47ff7b425eaa4c657c8eec26ee01a +ed07cf916e77d53634c137aeea009c6b515b6342c54be2c7b95955b1a9da +277a0abcda2346e88018c726f481f71d6011aa42f8852f2e5749518fe3b3 +ab668213fe1a05c10a1c53953d75312631d6bbba01d418199dfeff8cf548 +6109b099fe8e2f606165fe30f532c03567785d5362aa873c9d3eeceb20f1 +945d55f49b0ccac8496759fcc7292e46938943c262d78f3212d3f9d0f7b1 +03157f423d71b1ed54b2a603f4c269029918f238ec6828ffcec66009db9c +9e59534eabb183f31d7ad4c57b1bdf0bd2ce5a421882bc10cc1bce6a970e +2b586bb221567cca483989dd0b8dec424c1d1ff042dcb7834423cf244eda +28d2d969b17440caeaf024a6119db010ce366821afa424d1b8299609c041 +48275ae6e5257a7acb3c766c747ce99cba2d703cf19b7cf301b634d8b613 +ddc4afe4633a4d77bff8e00cfb5e289ebbcac90a24307e7941ec1685cbae +400cadd876fcef7f6557eee167d2035a05120293527700dc510b038a496b +e1d5cbaef24ed39f74211a93aadf22214ed606a80582485afe358e3a46d0 +671148998a3b3be209467009b43400870359d4189a8ceb4d5866ab52d16d +9ceb1eab71c07e6caa34b70e3096bf7604c22c40d5fbfeea616da3babd59 +dcdb97d883fc8742b8267a16a99b7953225f7144568d566e64542c92e538 +ac140c851e5d295528eb7cbb49909b1caf6409c9bcceb325468fa0b5f7cb +2987382616b477ccfe4f4ac79e4a6f7165363543f04de5b6f6e1c2e910cd +c3cdd6c4c92737198f892337dcb6647bd226c820ac99c65d8e7772bbb74f +e65dcaa8a22c33bc168bf48e40a82700a3a7668c5a9a71e397acdfee7d55 +6c5c19467b7aa69c260b727407ac837bdb7d67dec055c1f45d8bac61048c +45bc9fb3cefe7549eaa2992d2edc126ff7a05eae58613332a2bc1465b2bc +0429162b907d65f793d236eddd8d35405866d71b25f62dc4a7e06d4dee82 +840accaabc0774f8a63e9c0f7fc980b3583e7a8b01c46590e3bc04eba565 +c2ea94f057d964a78a90ea9f52abfd70f84e44e434bd10a42e98c7940657 +24341f907e35d3cb257161e01c7084e3a0166d15ced65da7ba87dbb2ea33 +d39bd99afb93d3548358d08330e807f8552cecf63c84f805205491ba3a1a +622e70c232fadf3bf2dcfd6f0539158d3306506f150b0518371912a25eb9 +6163d73e9eeed42edc84d688bc7f7708d9dca348fab4df62e5809bd09484 +2d0a31dbb7c4b41f94d946810c5ec10b69aabc2c91a59500b2e5d37f4755 +ddfb7ae4abf757f4c5bcf77c7f95e6a616646456fe8f18407080bcabbfa5 +7704287ad26222df91ab2613951e2d679472f8adf06ea2a20205ec199722 +99a78bac52114334470c5f5890c2f846b4c6042d73945127f2e3910eca1c +4cd7a16efe4b4be38a15aaa710682c3836a8ca83fd384970139d8b46fb0a +ebb002dd224199672ffa02250fbcfa4e649e335428fc71f50f45e498419e +db0e970f46894a48f65580881c9c4250fcef65c9b28699408e18b26fe6db +7f1cbdb767564e73cb5954c6d639ce33220c894f36e70f71c9f9aa3fe2ae +0aa0e3f2e304ec5abc661675cde2e70519e4220ae26fbacbd01d5169eb84 +4750753e6ced53e3678fdcd08ab93e10067e9c64f38b40b76d99b6cd92bd +f4155a1ea5cc824998b59aad06e09e5f15ebb2288d66ea71b296616734fe +f2796f07ff0d8b047074a1111d68b99c2b70fc56e74a51b062f4998acc85 +b1943c9477e436e5cd7ab18dbc898d21bb93475a623bdda71d7b895ba2d4 +c10f4b90bf335126f4fd57d73afa50170f6b3c364922e551d40e35da75fa +891762fa23401d39260f2e92c7807c746f13bb35cef9dbf2e76e66a72fef +f095da482a4de8a420917065736cf4de904fb52e649a32255e2030a7b31b +686353492f31c064a3c4b0448c4bfd44b8e15384fd809b8761ee26a7dfa1 +758d57ce4f0bc376eb2b3833534b15a83436ba553955acb5a7a66796ac5b +92db5388bc53efa27508b08e82821e5cf669bce52bb860780f749b4f38ac +df5ff12726bf3ec2743f01014cde96fe6b4c40a034e9eafca2a35ccc776c +2669e6ad138070a40f48ed79136d7ff57e993e09b81c543fbadd350ff5b5 +f7a46f060f88e30fe2d8233832d18b6c323ee017ebc1df5c838321cdc8a8 +4cabcab20b60a1a3aa028f36ea6e87c850af8af7cd50aa6359038bfa8818 +821d02cee8f51dab8c05f7ae9797814d97f3db8ccdde45b21dbb15cee292 +faa534a5f317b357f4091f3da357325b8b9f5edb45865415973c143e5e5b +aa483fbf2d06cdd4246675ec58b84c6ae65ca743117ff00f229243772561 +31a7f2ba26a9115afd96c18216cfdf41b7220ed0cb3fcc26c36380007b38 +2a02aeae428887dc8be5fdd630ac57ee3dc156c7b8b29e687f24442e35ce +10ba4087295a641f7139c831f7ccda6cceb5dafe537cc1a97c5a337d3c48 +a6ae947f58a30dc08cc7b58dbbb4737ad52783c573fc1e9408f55495a80e +7fda61f0b9c4f090158f1a416249ebba936c27befdef19d1bfb839eb7057 +6a010706d8b95657b2189c2ae04c11ef9e57fe09880273761fb4302c388b +d608fa0c7f00f033c9c00f4e3d5ce2d903e0da52e69c7745ee9fa75e2ad9 +3dc6cb5ccfcd3782a699b807afc36ad1f62b05856d5dfd6f88831b90eb3d +cd523582a49732e3fd7253126d39e8afb8458b5f7ad7f94a8dac13365f43 +3c857af4a42c0a08c4db9887c4957259ed22d13cfdf5995da957ea5a0f62 +0b0214fbfe08ab6d552dbf048d62cef6eff12f153511eca7833e0e3e95f8 +5e6ac0f95438ac4c126e1f1ecf336ed31cca7eb216d279877123fd9fcd8f +b5e52b587cffc4428456ddca816819a8a4a211d8f1629e5d42ba4c5c356e +580c8a22c61d987552faa97893816da73d423686e4ebd44375c257f03131 +8865a20f22115e72bf1eb9f93aaa169c140a33a06c35bd4526a38be79cf4 +0ad1efa10411e8f3300a8a8b97ab140ee6734e1bee6c8ee443d698d34159 +97649c6f10f20acd80236422e215e146d744a262da3fc88dc0d86ff66512 +f49d3f957d3c5cffeb424823509f33f155057a4c6f37b52f4667767ba94f +6b8b62856b553f307e5d230c44cbfdc9a97a45b139ffb2f2565eb0e22026 +972fad0fb7b9576fb6f368b61979943a398773600e7ee1dfefbf26d45d40 +bda66ebb96a56ee9cae0b2420c5dd83e24dba9ff885bb844bf3d2bf93b07 +325dff60c0cb5fdcca0ac8fb5a2e119d5af26e53ab8e3b428481c2871dda +26ef0b621cd8572b3c664bc7aac01a1d05b98f791a7080d294be81099bda +7982432f3dff4775c44d23f4f1b2e0162b61a8b2cb5ee8564bf98e2ed403 +2219085fe6194c19dac98a421826caed7f1ab1477ab32750601021728389 +4235d7dbfc1153d5ecc48aa7293f19592b4d7e95fe55151889bcd1d7fa7d +c2370d2dfe11d7e4ea34b5c7a8e73bd3a348fd389ef45b6167fb90ba44c2 +3e912f9a4f2fc0427ed070592f7110183bfdb2c400393ba7569058227926 +351f07fed4f33633ba03a72aa2dc6b598e49b96021dd868dad0f352e5722 +fb714f667c15c68d49c03d822d82677edfe86fe9668e537da284068c9b0a +ed83074c92a5b939296d505b837e6a9ddab1aeab7455a08a114c2222b339 +284674b74bf4ca9ee0c020bf2a148b439c71c6be51a94cb64fbe4a7eb295 +5a455047cf5cb348b062ed4f6471cbc3e9add9be9b96879ac7bc71bce02f +d02f17c6063985a5e8983d205aa1489da13c408990aba1c54f2f501aa172 +f530480d789c848118c0a74ef98d5f607a067baff6030d887ac6a6497f9a +0b38f9705f328aad4bfbb634f739386177b07f22d5771282444e5ee17335 +b4d0ec86117c697e79a5f4f65fdc08e4904daedab20067eae2448fd43018 +49e456d085f392dd13167adf75ccfdb723e2904a9c0c976d6b84ddef9d92 +b0e15fb246c3ecc2d0bf314cfb957757b3a3e8e5801f520644e4601d291d +a0f7507c06f3b9bb36fc1c70eaa444e14e56c0cff06c7f853df36da9d8b6 +af2544b853dfff535a7e5c6fc145250cdda229956019659d0d253a19a7b5 +1a4e538bdc01f74d77049949c2c97c7ec6392c2e61ccc0992b66daf1ab08 +551063e53180d2a67de496716ccbaa45462d9f91b66a22545962ddab1205 +11ff08627131b95e5deeb8b4dd9643e7b2af65c0fdce11f5f1e8dd468da1 +8d41c8c4f00ea73836f4f70ec50fc3ec6d358c0658a4261c6d15a582a2c7 +c994e7882e661855b352014576858a265ffbc425160669ce159d07edac04 +d060b44e5800a7aae8e339c29b929aa81d2f515c46229d2080d5917ab20a +b6b34fdca8e4af64ed660a3173786fb1a1d005d575c2a5187d3f7cfdc94c +cc44a38c5cd523e9da726d8efa6da7b6131dff3435fee838b2c7d6b97934 +295f06202d307ff78d906699cb9c5bbb10d1d4dea5fda5bfb094e7046070 +83b646d37f5da1fc7ad21b813f44d8c1afeab66655aaa19703bea2e77df3 +bf350e17c74b3447a452235919452b5175570a006c7680ac05e8950a62e1 +1d7e3aca35a397d1e19630d094a86807593c97f4c484e4e06bcff708b6dc +a972e3a0009e1cac0ea4141530f5c1b8aef5e1b933f37fddbc4be22b74fe +346d1a3f5fec0818f8e61765568a2ac04713e828f98c449d9a1cce52d10d +61dd8bfd084c8d099a75d89dea64d5a7cc68bd5b0593d97953dada976383 +f5015915618aec56d71d1dcd55b89736395c609b315a3f1e1255432fdbd3 +7f38cc43c354fb4b7c44f1a7318b0b7e99c3c08c33b953727b6a63280517 +83a0a33e3cd9e498346a3ca6a77b517096edd52ae443b87643a646c3a7bb +97f742888d33f9b3127e61942f4103c1dbdcd8eac8f9e259773066736ca6 +53ce57e8822651261d847c131321bb9d6626a1ac50d047c0ba47b411df2a +995545bd68ec0287cc9b31d5ddca8755ebeb10accb3903ab0fd5788e9842 +20443b8459e7c078da4289f1350905881ad6dfdec47302b0acb0d4af8cae +d02b4b70df3cf8fec118f0fc2d3dde3e494cd160e676e300bc464bd4400d +b50ee43b314e0517037bf971acd7cd327cb2134893b8a0410e68ddc518f5 +dec966c7884cf5fdfe74723177f20dedc039d879056caab4bf045062d390 +4f615c5cfe109ac7a35599c94024b41019b9afd404a80acaa4837929f5c9 +317680a13d157a03b59a5588df79d2e113f5f51021d6f6f90e8bbba2c252 +fd10651be80bafd59c53a3367ba3c28db6eb9dabf1ea99f47b503f627e15 +dcf3fd645fc52c5d5d0f2f07db4c25c0d1e1c00146e1c4d973e613ccdbd3 +f9450cc0f5343d79f05e9492e86a1bb889adf40503bd7f3e754343685918 +4a5b20bd8a172f350d846b7570803990adaa48d4b9155a2b4c4bfbef1e1a +065c08e03928559735bdd442ff1e83e1fa20a5da57d8bdb2ff5427c034cf +0128af111e6e73099e046e0c240e80a73d7be72b87834e45898d475521ca +3306707631f5c6136199f354632d1a085f12a1c7c473868b62e534d15f54 +84323e63d0574196a19ef175214eb35a90873efcfb92d6cf68761d45e37e +aa61e1a1979a82009507ca193e44b36a806486665cedbcf387053aceab97 +9bd35d30978fc7659abbe844f4ecab3303318ece80777a5fa5a9dd91b3d0 +6804c4b4e9b4efcf07eb89866d0dd8ca390cfd1598651417114d78776b1a +1d36b4ba17746d6be7fc123d473ef1efed1c3bc1d555f914536869fd5b0c +35f9c83f65b0e6bf7a627b9202d787d72c600ddb6bcce613d88492e13ca0 +aaab196e8a49928c62cea4ffe2d0208eda334acf47f20bd793124d2c5546 +c03f4a364369a76a0425262f9d9118af54e37d32e33ab25dd533a49df5fb +f1baf4ceac2d9d378cdcd13b00fda432d9042f623da41afb80699b5538a2 +5403b0b3eabec9e8efcf42fef3ea9f91766902cd206b0787c187d5370b60 +ad6dcd002de2de8dcdc0b4719a797c5e26baa67665016da0d967fa1346f9 +588aeda174ca001b31213617fe19ea218ec2359779d979e2663166489c06 +993230b0d07973a117c4e3f4a4c93cf8428248dd5389414d679c69644142 +67c7fea17e35b0cee456667a9b1875c81b2302bddea2818d6019fc1622a8 +2051f60584abc904cd918676305dc03ffbcc64fddac8d8aa9ce2ea00d6c9 +7bc63c8a617dedfc0e40775649438e9f61afd1795e3b20560b01be5e0983 +f136cf48ab206954e41dee0d9ddd953dfd01caeb569151d6bc0dfef29d70 +fae3e198e7edd8922c0e0bcb8bccf1c016142c1a8b337afa7a05a9d7534b +184bf3bf827f371e9bd19a71244eca1ba73d484cd2fad54db2f0eefbd54b +536ebcb5094e6bc2f5b2aae41f05b4b311115876ed42c34f8e643b53372e +3f6350db8a38445822ea9a33e27fb0cc42cedcd1fe2fdf723fc47c996ee3 +56c402112f24d0af899b2d00bea1cfd427998bd22b2a09046d6737814448 +acfb10d387547d7009fb384af0562c85694c071584236d0f1f3d3fcd0cfb +38b77c81889061e668ba7ab37aa60f58a3967de26f939b79cbf10a9dcc42 +852561d8d6754f1b660d216aab1e133fbaa321c56e2584be5c9bae20ccf0 +0e8dbe6d9c2fcebebad945c3c04101d2387351f132628786f6d9d4cab834 +19288d31f9bc600d966412e6aa457ce6cad26a4c0671097b98c2384c81dd +8b9a3222d4f4bbda7017895c3edc26662779aee740d9d7e24185fb821970 +b0a3a94041a69e4805ec88ee1ee521981536f2844fb8f5ef645f67d42ce5 +148e2dde43ad5aef200edb3a2c7866c98458a92666e5f9e070178bcc39f6 +5a893102a10564af4e8caaa5075d2f8cd7fab0401c03af299ea3515cc930 +66744eb5af7cf0ed06675bf049a6e3c211a89e16de5bf0445a7cca6ee8eb +0347454950485d884606651e5887fe8b24323e2aa16de22fc1fc8c4f06a8 +2a1fde5758976024068197e1f4506e4d3d8a16d40461a4586338b374a592 +dc60334402f76388ad6a457dc3f54e6169cf7ae3959676e966a456096210 +55ec3af80e182633300a4418e34a66ddfa6b569e5a13c9115b5fd3ec1ceb +e50fba247f60803aa83976f00117536342dc3d9890c49b2ac701d370e43a +955118967827760f7091469c5406f08f18d7e3548148cf0e312b1dc71df6 +7a5e7a1656cf2f47f3aff3dd50ffc2fcdab7177285b29c17ca43019f62ac +6fba52d1493ed7c427526470acc8389bae8277594958908f517b2863b832 +92eb5ab3f57fffb08393ca610fb1fe905d88a0a16ac395e2a2a6dd033d6a +0d68992f830b2e1b95fe357bf672716e88ffb92ffc3d62945d1ead22bc68 +c51ee0e10a43011db94c44685a5c4576f6ef44cbfb45f2a4bf110a01657d +b51fd499767e78058199b31dfd60813f1a344f86289f9378231d5b151c92 +385e3650b4feb1dc91018eab8474cbf69fdc1496a4d078d2c351c8196451 +247a9dcf8117e5b637371d8e22e248c64d999015c3fd2311e9950b8ee092 +2fbdd3d7bff766bfe9e7ce0be12f318ff2a7b5a9c6d00a54401609304ed2 +c55f5c1eac3d4b38355bbd85d66d61636fa6e30c2e82829376bec979a6fe +ee040e452359768ecf90cc539a546f17ae906c76f14f86ff697797322b05 +1eb311a759fe260c1eee5dacf383816aaf1294cffa7bf87a4d9bc595ee8f +2c2f86feee11ad959d86f22fdaf4cec098942a57e57813a0fa99239e994f +ff353c1e781d666b8928cfc648fcf0869fc68468bdbda7d280dfab8b0b3a +4ca35b074b686de8d372c61fb32305169a1a9912f6541da16cd6316a6ea4 +51524757be5cf6e820011be3859fb8b8578c100ff029680e05f0e0bf11d3 +3fe19460c85ea5e4c0ef28e29407c8ae6be01cfa0d5022bf9fb01416fff7 +22a784dfc8fce330ec95737a854471d334fdc58fab42867a7b62836a8b56 +466e9a6c1247d46ebaffb905cd4321970f59fb8d6ff65fddd34bf913ad32 +2e68455c5ff2d23c1a5eae687f259bc982b6a384d35440f7c693cf50b9ec +ac0b5578caee87588b562eb6b7f42034c9f2e545ec866316552354eb3728 +c7d26527ed75174eaf635e048b08dc5d23e88981070ad5641a652f234495 +6e9cf4c16e652a99f4a644d1787d6d36537489da4d74e61b2fc4dfdf1d1d +9d58f9c26c5eb63200526afd168ac57d5611ade4d4a382fc28bb60f9e7d6 +26a6c67afbccd1183c5e3cf2ef210d0bf5cfa7bb10fa3887bdd4cd96eeea +a8f9219aa2f10abc0a960c3b57c0ec0313ae10ccff1f522124cfc8d2d49b +fbb0c193eaffc5b48fb3ff30b21cb76f0a4c0f1377c9223145bb0468a5d7 +1b9bc25873ea12e1c60334571c67385c00d0b570d3ffc6c7ff0de62c183c +76aeeb12dffee1459e0fc818c621b8d12fa1357e2b55d48935d70bf140b4 +cffe8813defd479350b20dc2eb1d3cbb1a2d3dc6ee975d58c89d61fc50e6 +a0197da9a586b72255023de47dabefb11e8aa02414c2ff6258a281219b9d +ddfe41ba7d7977d0d6f18224fe22f7d4e9355fdb35bf7ed3418f4f68d093 +ac48f7d8fe4194feb6c80b9dc1f74e023c604dea27089f98c3973ff9f4ad +7bf7bae601db89b08d5d8139b95edcf6c885ffa8b3e4b0477e7040225733 +826bacfd1ec4a0dd72dc41734856ab9fb700df83ca2ce812913bd142d84c +5c83c0b2583768198af9e885f2ba74877a414233207234aa5f18840557ca +11682aabde89935338877c6d404bde4153c9827eb16d66c1d73a8143c8a2 +d3604ff72ce579faa3c5224bac48ea83ba8484299472007de96466b5b29a +cc7c03b05dcaa38a48bff9f214de43146ae4e04fa705421917f99bc54533 +f0ebc01849e396216b9f0794e6f6c6b61b52ef1b1950c0fb609895c3c55f +f574163fc8b6b09e66abaed1810e698ff37cc1f926b2cda3b48c7d77790e +bd2d514b6f385d397f713ec3ad3954ea9c8461586031d369e8b99e53408a +79d64c34eb5a56de8a67de91837960e98a66fc04dfa0ebde21db003234bb +78665b039d0a469a0221bd541af7149a2a659c300132c14581ef766fffbe +cba8b58a5eb3f95446def49af863a8113d17b2e7e6ecdeafc3834d4df900 +e3475596e86fbb4e2974c090db4ad61a737d611d92b4535ac291c56ad8b1 +c031d2f9b505bb77517b737d70ab3723db52ae2accd5dd2f617423ed3cc3 +9ca882ef41757bf7151806a9b8b0f312808863e3673fb54de939b35cdeca +7fbc4dc3bdf5a5f47d35e345916c39366c8b4f439ce1c6f1835c320bd1e6 +7375b03b5de18c93256f251761a4c8cec01019c068e34447bcc503b9571f +e8000627a6b3dad5854cbc0a2d69e5a8f46bc78f6a7b1422334ec7a98abe +fe9b83e01dcf3c6c9273b346f3240ea225ae4a4083cc7b0ea141a0773fde +940768358eb4b13d82aa304a1386d450c1c0c6a7d5a8fd2bd313f78f8524 +8b5196241e31e5595f3bc01f37700a2dd3d4a0ee2dd01a36569cd507130e +8f5b1e96cb560bb7da15560ccadf3b2c9804a11d9e8055c9ec70e48c1d21 +3eb756a1376f2edcb7189d78cd3d6ca5865537eec31c17d801605efd860b +0b629472690588d0257502c6f7a75b9a1c1b397781329832cf3ec43c09f1 +559cd562c48fa9500295cd3b0a790dd3fcd4684a7c7ac49ac9bfff36b39a +9fb148bc28d37907433943cbbf0cbdab46d3ea86dc8f81c859c52d15302b +94a9b51c199b7104deec9d769c2634cecf8b700ce9c04152cc59c9326bda +cbec4312deed92dd087a1c4840868d9f97cac046581f762f75e8d24d6445 +370a3f1e0ae74a6478d9dac37e7fa5bebec0a1e081af89c1bbf7f51e3e2e +22c8c405e8671ba85f1bf0df79a465dac7ec07f731e00632e017d190a99d +83e27e5c2e63d7dabba23b2e88334c63721ac5a4cbc5d45f4c177259f34c +2eade01fa008af65ebc601d8dd16436d86aa94c99f3cc0a2f87134e73bf2 +2f108b825a8963b49c6c685474afe4a542c8641dc0375d7efe9ac1168d97 +00459be52d0da399023e141969f25c0dac4668534b6647ec85454be945e8 +26b26de6e3c4584b97a38e2b40a0d23481bca78084fe80e00a71a790bf31 +df468a435ecc88e60a57860bbca3d65930186e9917cbd209c230e8f8255a +7abc7d3f043ae4d7ad63d9980bedf062b7d5c298c40225b6d03f29a0339e +0fca02138e526f06b9ef47f5e7a8068a846cfde2bfdebd24f5a73a66c079 +18662aec80b43246284fa4e2ee0d9aab172b1e59a6cc46b801149d8c0df6 +dec9a55d8e1b0efd9d302ff618075944cccb6831d336b11617107b0530d0 +9885e5ca11a5f1fcc8d69d603da16bea51116d42cab1aa1e4d7b9b4d7999 +3f2bfe53eac904feb70b2d330a89780eac10d12cc0c35b8399f218ac2976 +e57a26bad20ce2fa2ae2363d3fd2a8a971747556f2959da74a8963c20b50 +4711ae1cb0d0c02457ff2e9bf696b159af031dd5155f21c0f5549b0471a3 +c5dc8918b675cebcb23e29322b959abc05283a702e878de8ef25ea760f3c +5c7b7b49d398283de2ed837fd59f7c22d62c58fe4448b1049fdebfc8787e +67d7dafe9774979bb3802254da59bcc0219f98c219f84d995ca768b8b5d9 +d4a32525dfece003675ee4bd5d8dffc11025af2b468f9207b5b2b42349b9 +8232bac0759758c1f4a283405815bd7145c93fa08f3ed2826655053a3c25 +59073d8acd199dea2c5ba5f616a2e48548b4370ec73493ba07e197165dca +774438b0766867819c1154d1959fe6e01e6312e0ab91fc2e2bd240fc8652 +a2d456a1de7f34ef372a53794d4c4e050bf3ca5b7bd2f1b8de93b4c80024 +85cb219ad2d029739fd3c81cc6e78edf387235761a57143eede5cc887f28 +2fecd261f6a25d0a7e154ecdf5dc38e426811be86aaa458577e5e0c5f0f7 +5aafa9c41e5d1dc9d91ecd79b514f8cdf7a5f1a189470d35fdf4f9b87888 +79ccbd91b427822ed658389e981e0ee5f7fb87692a3e3e931df8a1d1573e +3b0166204240b7080089a09ef7487c9aee2d665f5a82f94c877fb5b0dc53 +1cebf1e71c6592cea2401e4b5122e5091df03d203df979b9a6efba12e2f6 +b422fdf15d49ac0914d372d21e871de65cbecd105fd4a3e4714b9cca5c68 +03fa39dbb015ea8a88be7913502e562e5b170b87bfc8572dc9df49ad6369 +4311ef1334444bdf0b4ca3245271c1f7a4d7faf1703e3aa0e1ea8d5c6e82 +1b28707ee0c9b4f22f23796fe87356c58ae2cadc191f4c58e1fb58da03b4 +5a25ac95dbae13a293474217bdb214742b9d9d6af35f70fed2891942eace +3e625e55ffb820543fbb250a062d3d395bc0f219ecfe0d76686ac148bc41 +476a887bc494ddbd396be200fd3e03cfa12ec9af6b934a283c42aa05589a +a6b4a8d16946bb51f50419cabeceaec5aef9085c9989289e9b46bafb6fb2 +782d84de2b068f91a9744aab237ceb1ba513e57e4c307108e993c972a3e0 +a898d5a8d27833155031fdb98863c3be7fef3004cbaa5cb60a1f2e3eb4d7 +290ff5fafa088b1ceccb6cf51a58daad998f08396cdfd68f5abc9c1ccb8f +6514107773c69c26873e889d1f79d10e866910e4684186fcd71c965adf62 +39ba3418b313a27ad632300969b6f284519366ed85e7cd968d64823f8c59 +b5911a72d0a20eb72b603a61e36f52f256ffcdf706b4560b4dfa5d918fbc +530d83a4b3c01bdd3cb4572e24242d141bf9e77536693a0407d002e09cda +5b195bf1ccf430ae9824c07928a050d0b460f2704be8f9e647a4884c4567 +0a81eacf7cc038643eb0ff18a376ff6f32b6fe4f197273327fbbdec6443a +299cad4b26f7778a99f65a11bde047153e764039edb251936aa43dee50dd +fdf8856519056aafc4c5ae6f2051af0579a9acd41d00775d7dbe70022cc2 +63dca5e0a25b9c7c4f5c418587666b2fe24816b1e0ec92f9074f1403bb83 +afc3f1d52ca79c387bdef864366e34c90be52f7aa09935373a07e4e02622 +4e76f9ec3cb9e7ede50defda48248d61f3cec880a3b8843306375d9711e5 +8645f3625bdb8e87052da67f9794ef4af8db0bcfe00677c3a26907dc651b +c838c40ec39e2b5a5dc0dbd345944a6c32226089d63c52490fa10b215ae7 +03cfb663eb8a47793b84ce7364da1c4e7fce32dfef09490121222774915b +a59c78c2275f829d15cf4d8686b095c38c731b83d48738c25f40b8add487 +c350a2ebe846c3916ae384cb1050f9f5dfe09fcbd9129c6270fd86d55a45 +9618fdfa4f907e6b4746196bb717865ab378414029017551161a52e9d24b +e4f7eed553a927933d4abc8f25df607779a717909cb4d810de8f57625819 +00e224e4b91598149ba471cf8068abe8744356b261600bfcc57fb8be4503 +6cf6571d9b2a95304933bd4f17215f8ef53f8e081af61fa7f9583c34eb56 +55cb0ecb82246959f09091f36989ebdd646bedca614b9a61ab7696b3ff18 +1058a150fa6ec1be2ebc7f64357a3ff2a2b0491d2f4e0b970de5b7788b46 +7ca678039b5ef55c88a384578d427fd2cb16c87b0bf0a3d37ce8ed43e0f0 +49af2436344d5f47c948c632c94a2875092825616c64c5d262fe5b24916f +fee982a69a6ccf888bd01d62ea591eec51f4b7ddfaffbeea93fe08d736c2 +0129e345d06b10246a5f57151c198d407730713f32299638efbdc01367e2 +3eb59aad42a83ab41b432db462652e29813740f4680a5d4bd47b18328fae +6bdf4200cfa4ce3773809b45e8887c9b2e4236989f6c48d64f5986f563d9 +a7538a8716082f81936aebd0461e6f4bd470436d8b7656f0fdf89108e6dd +02abdef907731d458d690bc608ea9ced09eb1e6e64c0790c7a2378201ce9 +97ffe0317679ee1d4ee9f91157449323e53b4ada8096cd628b5861bf7945 +43a98f2fa2ab54ff0f25a13dad43daf9394329b95aa53ca32749fecb0b2b +c035dd1ebd53ff9fb5ad8bce06cd89e5568091c1cc314cfb1d9821d7f9ac +7c55f55e0a16e39a87d43148201b928f3c42b110fc056189def183745f3b +637441de8bd4c3c7ef12f4258e306b2877adaec63441010750db4e6269a4 +c78a0ac01bb3603c386651fe814031cb5d8c1f149eeaff652a53e57bbd4c +8c0ce36a84a319a53bc1e5fd3f1ed1ee72f4c1a9bf264b594062fcafb22c +c1fde3f2e3d3c17dd3f7fe0e15ebd812d550227c06d01127385374a11438 +abd50048e17255fcd2bb85122a6fb9b7da9d5e9de8a747fae0da45a1fcef +e92b9e70a5b2cac668d4d07527a5c1403267d823048be671f725cfc7474b +44fc5aaa348420b2d7c23c6ca066666fd6f2208e329878d90cef1c2e77ed +22d3bebb9d547810b189f08920a27e7107f208591a84d463ce2576c70c3d +fe6643e4ea93f4e1daeb41d46f0e2f56fc10c69ad5034fc9859d31cf27a3 +a1ee256c93111f81c11acf1fc0ce20b90bac9aa327a5c85a7985b951519f +d4b03c40be637162af41b2fda68f0d1e9b7602fe2659d3d75955c579ac51 +df6a552eb9581ac3f712f083f19b52a6c4f560f36c59ceeb0c996aaf1728 +a2aa45dcad79bd7b23ab388d5b0b64a2b95154b6259b730b0f4a72c8c7f7 +cc93c7d64d9d8810d1f63ff8abd4db89824e2d264fdee916c41e299211db +1a53256e1db5cdd04862f034d9404b73183a99d3d13d642a663f129b6d16 +7095beb4eaefd03df2ff2f0b6b594c1ee90fdb203da89facee23f1ba3901 +fecc75fe1811bd701259343011262b6a0a9707aaa6316bc3c17f787bb80a +c8da5aac942d90f80c5a3bb59e47ec767244aa95c63e50bf809998957936 +d3bf6abc24b0a397258f9eb4dc8f65692cb023d9091fb180c69498cd0c08 +bbebadc84a7e0016e8f8bea325d924eb0df82e75d2cc2ccbf039b1193436 +3d4332c5fbc5ec556be85ee4e707cc2753ccc43d2ed50558e51a104221c9 +323cdcb0199b7b83454de3fdc810d0f362c0299f5dd981b31d8e3dda284f +ef9dc8f9c8de138d3065437a7fe8c30572ad06d62e8527ad37ae39aab0b2 +25f76a25f6c6505241ed73ba494cf923e919f688ddebf193e188f8c4c154 +f21631080763b4d091e8ad1d2fd6649e0cd9360e8d1a67a5b5fafc67547c +a31c95a5ea8d4eb5d68b9f6d6532db9b545847359558542a2ae58c09f3bd +2918efbe1699e9c8f2c2a11ea4d224c726d2acd4a8d8abaedc6588cf2ae5 +66528b94f55b823a2a1f7be19000f3e7579d094e047075df18c8c8687602 +95533b26eb3ed90635b129c17aca679c3e88b06998ce5a7a2544b700229f +5a6a504bd3e45b276471959c8a3f81917a53428739b5ef9e3d463b3ba731 +8448e2a3e79520d2d245a2a72f31ff7070b6e4624e3a5e216bd103640c8d +f387e49d732529c611f8b971073f17ebd2f6eb18f9b74a67e1997926df17 +8d4c9eded435b9682f1a279c81bb9f60dafe125845a2ff3b02979e5481c7 +8a45c479befb9fef3ce2ba9bc46c77b50b03e48da6d17b76f06f3ad11837 +1adc69e178c52b5fb4b261c9311874ed07dd6d5b3226a005fdd7a6d53848 +09e7063f036cdea41619122635e835d2d74cbb6aa9b38caa4d819c26e951 +15fe0dbab4198fc5838f2c91b7a87b07d734c6d4f4f83444c1e90aa9bfc9 +08a2bac4b3def9157afca5248f2da31ca87bd363ac25e9e77f741d4b2c6e +02f04987a6f49d30e9038cefc41ba172dd675aed8b392164411144e5b738 +f3210b0e66b17a13cb9631c33d44484e792a7c082dd0a5382f34c5637653 +261b1eb6d2035b08b4d91fa9ab770caf40a103629511f7b43f2743d7e583 +433decfb19c21fd4fd0afcc22a4119e77c87bfe6fe50068b22479015be5a +9f06beab4d37412e062a45e0cbcd7bb39fee747e96306f79fc4f2e8942df +5d9da0e55aaccda547da19d30b8404fa121298b44c9cce198c708c69a8d6 +bf17591c5c50d3fc5be6961f7aba8f366dae957a1c3730da4a5b4f035a92 +74675ee3bbf0ca8ce9d8349f50cabb1c3ea4948abe6f9f143592f1ea9540 +4e6909a909168e3279a957ae1924245c356331a75e7008bee92beaa304ba +40b7c3f48f74d9018b3247df50ebd7ce541da48eccb1b0be51a455c3c13c +279d4d8676078c3ebe4308748d52c9b041d3e7244c745b1f2f742d010a9e +60695f3ec4fdc1050ac082b905d6a57e8f407a3b472f731011a5798965b7 +b1a307e252fe02c8f79ceeddeb6e165f1a94d7fff18ddbdf79477f14e9e9 +3981abd200fe7771b29d1d2d120ee79d28b9543818527039ac74085eaff2 +41b56d08220c958b5d9c87c0c04a14d52afd475b542d391bc54ff33def8d +9484aff6873beed32dda4b371112b523b6ce22b40d1b416b64c9370f1cdf +2c548f4ccbe9e12e21c36cc3ea52da232dcfb65f66b22b5e2ec04852510d +5e264ee939bb67aec4764b87062aeb7f680b40bcee04ad45c7519eb3b619 +9c9e0e332661463647f2fb7edf303efef84891cebcf0fac5f723a9d0476c +3f8c092604c87fc69c7a90f4d64ae45a478ee8ba2df50fb93f55a3546123 +f0b0e2c1c40c98eaae9f0f26b8f80ffe6e6b94b7e27d2884d58b8a119662 +2df6be608c5569d7864bb756df2edd184b90812b44ed4a32d001c31383a4 +0aeee9743651f795084615c48e402dbc01c818d477eac0347795cb2792e9 +c11e8fd4a02e194eed1c919d4598fec003b6d9a8a0bc7d456047a1c05794 +53fc1d7cb2d158d466939a23d7a7b8abed7e2777ec7487973e73f2266d9c +250ce30729e3c5223ad93b9ae8443b35711e446a3dc660123ed45ce1942a +1a2ad0610467e081ce2c8b92a6c82f0b17b5d2429e99f1a6268072c6b5aa +aa6eb6283a872c54d3694cd825eb2926e57dbbc7c1663075e687a144e4d6 +1c225781d80fcae1497b442342b4a3f1cd6bdb50e31791cc3928c30835fe +f845b6be5e2d7e3f2f5f085aa3faeb45cad0d76bcbb1ed859a9cebb9f745 +7036f0bc3f195cb1a98c9c8648f6583cdbb23894bc719d68c2dbd8003b10 +d08c8caa40bce784d7bfb4eec9ea5359ac056e57b8b0f2ebcb1f4ce40c87 +fc7861180133e0cb6ce2fc4fe690756d327a2b5ae063e3021c0c0bd420d0 +56f0b941e6b36088a55ba11d0c35fd0132d5f48e5d9673572347171b4328 +d4807b972831c0d74cffa5638c145b89c989e6ec942148207d6db8225758 +5958034d9f9d4221c7c9f7013790dbd130f277e0bc88bb179dd09e270623 +79ed06f25eea8b7fb33c35861a0034776e3813d2e9e5c10e227cc569ab36 +cb2d9df2e7b7b44758f9dc4ffad7a24ac7e9f47aa850c221048c3cb35a37 +ce8ea75632ae65fe3212175146fecd6334ae3d3c5f492f067f795e1e8ff3 +86ba198cb74f0bb4dc0000da383bc4cc3f070de17721431988d69c8b1a5a +fdccc83c22e16a87e01c6d3e79dc7afa3db0371b0866efb8b6f88900472a +fef1c4a878243c52d4e02e82658979731c841c489a6b97e271c4c93800ec +7d91f93eb9b9c659a554e1fce42a5ec65ac39190ef4b66deaf6fc0569a00 +0a9e1495f42f706fbea4d32eb7ef11a6489102596a65cf899c2f322f5679 +c6d123469192a9bf1a7f1f2c81c554adb97bd19adb746a4f81a4d5559e60 +ab94c483dbabf6ce2f28cdb412d50ff3fcfa3b3daaacc6a83cfed910ccb3 +b8d2c19590aff4d753034a6ce7f4156896a13808e0dfeac547e69d3c8866 +91728e4a35acd575b40d721e8fcc5385a2eb28d708101dc50811529528f5 +cb0c009ba7e3c88468e37768fb0d83895ab54db2dd5426562af9d8af304b +f6eda54e9c92643df926f5c3578269750120302a37cb140a18ba56ba0110 +8d4acace8feae640a6c6958ef156b588adb0ea5f3b0f37bba12b7bcb221c +811415387b024b7076fa4403a3ad6ebb5d9c26efebdb7ade7c60b444ab9f +90ea493b658b7767ae2be649bdbb3fe85f460f1ed137c61bd95f7cd3d8b0 +15ce45138538930ab62aa0e54b4ce1a5ec5fec0a2b28b345b67089a4e4ae +14d2e1f5a9c8848da688ca298f93860649ec3aafef3e820d86988c8e3e5a +4d4bb937791827994aa3e81d0bb3ee115ec36d5fb9a392d09e79af514d11 +c7b3a03c9f9c13355ce79e119a19177ffdca34704d38118a8976d1ee5aa0 +2d14feb1414419f5e85244adc5c0a765a522eef36170064bb19fee3b5f7b +441e4db967dae0bac2c48fc6a836e0ef5a69f073bee1699f55e9c757ebd6 +fd8b514e2b49d6333815b7dbd1e0694695fca3d21320a0c4b852d9706dad +d8369a95fdd917328be93dd33818954dbd2c212d2ca81560ed5bc284eb04 +7a5f389e24e43f4fa8c97fecf46589fa7341076555cf55b1c21b28e0c1cb +b00ab8b6f67472f27bc0d11148f407824b0159b5188d4bb7386fbdbf1c0f +af34721b7bcb5c0fcb7c4010dcb6a1284e9d78839e3c2111a05d29ab7997 +073b590a81c6168020f1d48951bc7d8476d5ba593f4f23cac1f9bb0e091e +84b4e99e5c584d1370dd12dee8df16af8bc6b7b23e2feabdb7f32779af8e +2b5094a6e9b7a7225f24c43a8e5d2b977e1e19e633c26771e23017ed233d +bb02c64f8cf03992c6484528d0c8464b46f24f9e8380f385d5d01b8893c6 +7fc103498983cf939432aa380ca576d09030cd52fd99bdc3be16c7204cdc +3365bf76294a83a1fc14a236f5fe5321904e779b13232a76f8fe521f4255 +62678436359c2461bea5ab27209541f557ae2aa60009c9ca0a9fc7898c14 +306ce35a50017badefdecbbf94ee2905220706dc806409ef87db1d73eab0 +698ad2db72cdcdb293e7fb13c94d9fc87e74502e6927a212f0d7d2f2d194 +64f7a66ac07872e18cb1dde8f11835dcbc5c4ef039333fffc0fc1456daad +e7dae3ec2ee0d3415b0cabb69fc5006f4d14a4ee1a5ca99ad4d5e629c0dd +1e0f097b5b93de2dd001a8c418234c9c45e8c13d1ae04e9466dab8cf1ecb +88a4e059c111a6468d2dabb90da79c7c79e94db28f6968b1a632f8c57d9e +565ff91c6916026ffac0661856b9fb8de9c81661816221b1fc159cfef175 +1e7e403f5f2ce32529dd540792fc17a12a3dcd7c50d38eeaadbd10adbf5d +8a82442aa900ce6150eb7a4639dd9fb6e385b2fd093493dccd9014b23eb1 +72e21aa89643a6cad1093343d85d81261972de0acb16a4c6b5f0be4c978b +fa12d3caf0134f9ea49f6e9687c8f99a456745ea252f0ba9968c7f9586e3 +dd841aa92dc7705bdd682dae41518a09df0e209f321d7fa3417202f4ba76 +a984da3addbc58136885362f02f0a24ebc439b3dbbdacffd8498ebd29f88 +f016b1feabc10785438eac860b554525f3266097a675299aa0967bd3b7a0 +eeee3fc578d1be99d3533bd91571aed904bfc9da1a1451fdc5406e1cd614 +e0c7fbc733563cd6ce6cc31e9237ca153f1f0411114361d731636bcf9855 +5abf12848ad109371a42b63675a4130b81e97c2a2ee2bb5d8fae26401560 +01af0f55d9d5df8ff23c8aefe14f120000f14149a36e5c94cd9081dec277 +c2c34870d05011f99d48b0875a5ff542f067f7e9880109f586bcf2b50522 +a1f23ece44349e539e70f84e207dc9bec7cdf856a046f1a03226aa41f541 +719ad1af88ff211e57dd0c1275dd0b7b47440da089b98c6ee92a7d94700b +83cebe19eaedd8a615f6587587ba8bba3ce3aa5e8eafb1fb0f486be3609b +169efb178a4292f4c0378afe5d24eed1caab514ddc66c696d8e37f294a65 +79131ddf5488e9436609acd750c3db0a940c84fe022b22adc2676f62e91e +8f891225f891fba537679b24547bbbf35f04915d20b11739f620d18b5b21 +6921d222f15044368569aa302980b9225bb839f494588481b94b0c724352 +b2df600a22b062561d86cb8f81514fbdaa4f8a043a0265f992fab71fc912 +4a45b8475e1ef3df6b6de35cf329777d45f08325e8505ec0d979f542807a +e77e57e453525f23bc59a50740371efa98678aee6c425374aeb745b99ddb +5d8d908fdb551fbc0db15832107bbecc4e11a1a8dec69358a574a2ed46cc +31d564549eff23102d92bfdcbb2bb985f78f36033e34f59c0ebafa3bdd71 +338736464cefdba9139833995eda4207bfd4a9867d32e867fbeb7de60d13 +2803ef9347cb17bd91315484ef6570892297dd8b7d966103339535e28a00 +cb1eeca4a9775f60a9f5fc9bd8b06d78fe8e6318c31da2e847e3f9ca587c +b01ae2ba0a2ebde308314413f4f230a758184ed60d4f71f6cec22a93a01b +6c54e0449a3860fca8954a347b7588329a80974ecbecda1070fbc0556663 +75229f13dd995e99265df870bc8b8cc6347fadbc1a6af64599271a475b91 +23493d46bec41289beeb67eb97a8ded7a9c9730d37c65164cfbdc22e5ca5 +89d2e7954c7136ef4e084c43a6c7f361a3e96989239bddb9a593cc2a80ba +16de9ee90e95cd39393c212ab22eecb677fd36d34deb46c4ad0d21bf7e6d +7cbd0c8083842fcd87b18fea7cecf939987e99ba34c214e44dd84c176c9c +c5a4cea76d380cb316bb4ef9de73d73b4afd4adb54451591def86621d138 +d5a0a29441502bf6c2ade671cec3cb5cab903a657eb2d70c943f976c110e +46c5d9d29bc00a875f2738e5d22496a43e096e009c5d3cb724b4cabb3283 +8dbe527f83b18cb457e57b092c302ee557fd4f00db9c56e66c9fdf4ec9ff +aab85f60d02ba79694faba476a199a0331c30a78a92e10417ba236e23364 +8174c826331dc1bab87c5f95027846130c6a2b4027930ebf9a97ba1b039d +386fc51c302648e25980212f6a582cde2778c677a01fbfb3c5d1b8a374ad +af6adbf7dc94075f25ed66d440b3922c5f255fb23fd8f6e21ea65b1d93bb +225684b50f11310e242b087575973345b229ba62c1e2c35bdaec04d10148 +f5b2f3bcf7399bdfdf1f3f79119714aea697245bc647316ea157484ecb95 +1be367234fd02e8b1f091aac3d29bf282dff4011bc0cba8e55234d943db3 +017cc7a766720bbc29b2d097a956c0f1067177f012d42adcb473cde8d1ba +35b4030757fa1d8211989df3bd22ce5d501c21ef8708fb3449df47d88650 +9ff7b59b76c0dbae443f336fee2d615d7eed1c284f14335bc8a26bf4621e +10de9611fb2f1dbd52e4b7565d8c65b54ea36d508bcf0c578a49a2665227 +cde1f9768efe847f9d94f1bbb7db83701c2321985c7283d47b2e40b27a26 +8428aaefe75f6b2f8764a8494e5827573758cb9ca46fa93208836bccc8b5 +564a69f5ad882052af1c1417c3fa7f580569528682c77080f3688b65e7fc +24d2a3aeb61574b4a3215927281544ddd7a6ee0a3e9388f8f631ce725172 +4df70726e5912ddccc8c652dd6c9608f8462303d867f589de0f2f71711b3 +5142ee6ef93b64d6326c4dd7dc83278e057100ee772082e6ba368ed91a55 +53ecfe2293a481e42f83bc8f9148c70eace91f7b7d9cb8a72415bdb3af66 +f68ea733a17abe9db0053bf148629132969589f38d30eabfa96a01fac726 +50b5a6ff3935670198a1ea33810a9b11e330eb8b451f24f93544263436f6 +69ab5a90a53b16cceeac36b1445574efa7e802de73522be725e68704822c +b7d3912717333367895bbfbe06966a5cc653aab5e9b3596702086bf00100 +85b900711932a95acf15ca4dc45a754ea334e9eb84d6fc8e3fc4f897456b +ed64bb93b593549ff0d5352275d8e417172a6664c5e0eced1019494a7ed4 +9ab0b965bec1a82e5873766bb38d7d856049cce2fca65aaf61e961b60634 +e2a69ef059754c9d8163d87f928c222772d070d83fec6fa5ac734af65e40 +bfde521f7d9cb1650fdf64754bff21ea3ff0af7611a93d525ec9b28c51af +ecb04e7fc8323dd6c9b0d8539a34fc3cd8ceb7958e8ebbfed4313c77ed46 +9c199552a9ff70ba5423b03b6148d4eaae17b71c5b39dc436ac53d6ba8a7 +ad81aa8b02335a8b2b11e9f4fa913159a725b8ab60f52f1a2ea50eaf4d56 +656e615bf382cc68a690bf83dff24fe986570adc0290ed1a37c1c2ad469c +e789e0ea0bb5ce01020100e729721af3b5badd33a2daa6c33eb8f9064f52 +92f715f820b4bbfdd56f76d42e7a1a068c1cbdce4640082f6e7d582d1939 +990ce6ee8d270015a2c461798b37dcb5798ee9f7512168b76d26c28be4a4 +9a1bf96c89d235f21a1db6a96e5da474d0b19b808d13d7a11bf39ea86474 +99c410ed9894a1adf33d41b6fc2e614d8087f4c84e437b136f3cb32db839 +3c49177a0675a0c9e7eecef448a97afdbe840fa01fc7e5f2e8fecedc1884 +84c312e8635cd79195475ddbfdd4d38d5a0246de2c7f21608f8d2c0da137 +1d302e941572e5792a3cf4e51a33228b93a814d03fd4fc223c314cf3714b +b3a34bd4f7ed6348577feed9deb082c4049e57b5d3cdb7f26629e9f3ba36 +893e09e3c7463d02a22d7056be76b87763260e46e48bb832b7ee13f8dc05 +37ec8e81e9bdfead8c27ebdf1ad706933efd11131e12814f236ebb01be85 +b7f1b2d627413b324918d247604f56ec128909873fec3857028bef76a349 +4364c2a7002d104d486236c30b48e2b75d851c34ea50ba7ffeb4e1919089 +8ae21768c157c0cac628a2181a32796fbc1a7271d2473cd88e5395ddbdb1 +fc3aa8df0f3d588637f19a8b833afdeb5f655a8838eecd684e2315b72c75 +ceefbcef94344ace8d6adbe355008ec72fe7ceeab01363a895f4e73f8676 +39be0a0be67333848816b05b419221be8f9066c362c23fe85b7f392930bf +e4c12b9526ff2fdec38f23a159ed61a0718e7115c24597d849fa76369153 +54a40c965d4d72ec94da61a03766ab39aab684e134fd1407a5b1b19bfeba +52aa0da5d99cbe5c82dbaa663711e6deba180e1d4a39c320516a4350d296 +bc19bf1be054859a0889c7e9727a021f3176fe620fb0c837e4141fece531 +a950c03d319e3255703220b7185bd20fe5dba673f8129ab211efcf36ee39 +4c7e00eb0876624bc840fa86e58b2f584754cb6bfdfd76810e300741ebe4 +544e5ac17413adeb21c62f66ca4f075c32381796ba709782de34a675b717 +a2c7f6d88104cb924fde5df775b4f0b68e0e2e5c2f788bbdeaf06d8e1fc2 +105ccbbd5827c0b03fd6cd64f0d073f3192d5f94839644e5ec6c5185badc +f04112a65f49a8c83174a9ae958e76a2f5af469e8b76c833782c5ffb8bd7 +b1bbbb3ea0cb7c9786c3be2ade5e7afa8c8f20892659a59bc421e28845a1 +08e34ee17864042ef587a6d67decdfb3f510eb40d2229585347a0035670f +cc76c2837a4e4d68304fe113c539b35c1f0234b5079b8e32934546982978 +c5e4df955a454ea263c3ca5d7101f31a318d82a3f9fcb5a8afd7a6520966 +3b0fc9da400b26f285ef46d0e1eaf8acb1f1cb805e3986d04bc585073fc6 +4895e4dae1ccb749bb439cb32ea91176d5c39c3650d10afb9c9884d5fb90 +183424cee67ef2175d01d2478d67511ec9f54f88763c152697b06d948bed +49240096eee3d06ab4575e8e8b2cb8263b5bcf4fa1608720f52b67530983 +3071879df52c3ec2871d20f398b5cac8f8a4d41d0f1d47584dd90dcdaea4 +a1cf160c4b3bf1aab890b5ceb6cb3488672aa68fbd938281dbc1d8bcfe92 +fbf514da5358443cb6e0147254e91b38ce6787b2bb0dedd2d38f5938737a +977b5ea42892520c58f8fbb53c994b57382379e9490f0d6970b980e1bdf8 +cf9f4c3c5e0a18f66e86ee93ffe7fe546de50f41364bcb3721b637072571 +fa1779f1d672fad260c16d7f13cbdf3e4376e7ff56d2a710ac5ac35fcbdb +ce2c9c17e523bbe6218617b13c1fa6679b308979ae7c61da6e68369324c6 +cbc7ddec364e5a86707266c0b459ee7b2c03fe584e529bffdce98c90a2f3 +d9305aa74d3ed8430dbf3a49fe2ecfd9c4bc9fefd22618fe9c8a973ad072 +ab6f713e4df02dcda7ac5359b2d652013e131b76b3ed6c75fd53ba58d862 +846264627f6b9e70d8800f6d9b32242b747a67bb2b45675840d34f852aa8 +062fa6b01e31ed24dae02f6cf788a17f7b9368175195db0072259cce0ffb +2c1035c1d26e1777cca3d56a827c3242069e76d6dd69b653768614b9acff +16567fea61508d51454bc02f6c60f755aef6afae3536bbfa1823f8e1a53c +41124de983e51cec92aef4f99785d554488a51c20885346d1f761da79017 +940a0c557d93f1db6b3d00ffd61d08e96ff3afce5fedf545cc9f47a2b1bb +26713431d6d1e47fd6bd6e3c668b0368241f0ebb5fa9c991df79890e52e8 +3a3675ee699b61baf869de91f67278f510061c6fe41de2d883f48cd0e068 +e2a652b244128d82e5cd52f35f210ddae3054691ed55a7d99088aae8fb04 +f525c2084ac09f5edf80a4efafe981f74c0de9d194320709b3464f3ff2c0 +f6aaea6d973d9c323f53de3d741f698fbf01036716bbd62957cb32cd81d3 +a2674560ffbc5bdc5c6e4f547e589ad0b1cfe14f5e17fed1c4a8abe4e67c +cf8a49f32c4c6044f1431e1cc382e7758722a6d0df9ed23e51f8ad14d11d +7b6428e27443715eba4e9c05d6f238378f9498aef0e7ee4fe6856622cc8e +6ed141ee5f109e343cb6695c4be1e0f66601c27975983bf557c04acfc192 +27a1ad7e6c44c00529fc7edd7f886d24b7e029b9c395260088bbfb969721 +99a7b32796d27257de83a7402291c14fecdf7998c5c96b1edade0280f856 +8a8f5007852eed303969180b3329917973c2d32c080c9765b6bab0673bc7 +ecfdbbfbea980c26384339b7f1052591d91667d4fee413afc23de2d4b9da +742f4269c6c939f5fc32a38040730a018155ad733f231e4d5b9d01c03a58 +eae7b5f590ccfaf25edc8552cfc8d95c60ebae1837d7a97ca137e9d4a4bd +2cd34aefd68d64b3f4f62326ac429921d7fb3c235184fe0899690a0b775f +1a566ec29d5830d323726526f7e7f5afdd71b77e07613ddc4fc63edf4905 +1aeb59e6337ac0a4b6dd872e776c9cd0ccb861305322d816732124f5978a +86c186bf0a0f88e733ce38e4d7c1ba5378c5629b1efc97806059990ed42c +5cd183bad7e94070e4058569da2e51831ffe0d080301aeab4350ba290318 +aec582c78d05dd92e5afb4424ea808629bc972e68f4ff2489c245593f075 +55ca6a2b25964794cf31cbd3ae5c229ab9b8c29806c01d116ebd0ff0f159 +ed2d3d7dfc73eab4910bff5b0b0b587cd9ea6e6fc45d63c09766224d8346 +1f0588140b258b1729f70bae7962189b1554483392988cf230af4077193e +53330519394dd99ba1356d4730ab221dc6a66019bfae564893ddad7b177d +add16add21d396cfa6c3dc818052e2f71149fd594a16de0c2ffdd366c99b +486c55a6e991e4d22ccb15843f0c3363676af2f5b2d1b7ef66ccf2f12dc5 +0d63776bffb058d70a9c76dce96c754872d72c82a0c33f90d49c935402cd +d26b6d743b1f43bed5d8b539424849c1495dae73044e885a7d0f307f1816 +df6244a6f2d97bfd4e200e93f69b08af39ea21e6e347a47ceebf803f73b9 +78adbfcf056789bb8e6e2563de87dd9a8c877157b934102dcedac54d487a +1bb2694f0034093c48f10a17d32e2bdd0c723caf59addd1be373af8c9beb +4415aa5af36310c31f24354a53c0b962573148bef91d994fe3f3d8450dd4 +d686725799f53c373a0a3e3c060c2e1a3e8005049f26d716e1f381b9f831 +25e4683264a07e2d8938f605978e2513dd2050b3d8a1012797cba8961632 +bed260916338a812ae751c7b657e086a0c7ddcd3bfddff3e48b847519257 +36d1310c4910fc114387f3ed7fe163f91895ebf55fcb425cef5729d99bd8 +f2c072e36c310523e75cd8e5de49c031c42634109d56e91a46c8c8e89fd9 +2012a00c33d0dec52597b5c6933291a7bdc5ceda95dcda5600f9ae1c8250 +54e7ee1067458ccb66610704c58e4a4fc0cb5fc933d0322a716b2cd430a3 +ad48dab3d4cbe9d23f2d092368cfc4e1f5495c133a92942ec62118d45c17 +723646e69407b4a89dcdfd2ab3ffc099a21d9d29741d68270629aa3a414f +e58658dc9170c247b6e23f35c4bc5ff83009f462f2eef4dbac5fd158a658 +57f9b6dc1f5192dfb169dcb65621cab2f1b07bd22f4155a8e9e2b6388d43 +0fde5ec1c834d22ea035c52e1e34482eadc36b4cae902aae89a7284e62b3 +c84b608d6bd05f75bc31310b2dd3b2c08a00e0737f104f03a41989d5f6b9 +a2c38b22f1d1803ee5d7a4d8de44e4abd496a1de0c0e12c4bc96d0122846 +3f0ea9ce9509fee987139f3dd3f9d0df4313f555be85433718f6d05f197c +41a9d9c7a8b0d274019682d49f58dd5f66b12a6520d9f226d1df1f1b65cd +fa261f980ca25a92645b86b64606293f8bfde364c47d2af2c709bbe77a70 +a5712f2cc26f3d66f5be2c307a48e6f887f681d30121e32bbd87271b5dc4 +615d28c309f15ad263fb37424e56dda6e17b998b45be6c7fc6c28e3394a8 +764c9eb2df5c06626593b5c665d550d4600172791cd208ae9f37bc082b0b +242b0a504b751b18f4d7495172b697ee217834a8a4fb7cc16d6f9e8bb400 +be8aeb0850960283dce725249fcc4de97d9886745ab6066c3e2f64dd8ab7 +9aa11667f11188d7965dc11eb760b772e282dbf13249f31986ac6898febf +e23e3e8b8d2c33e00ea6fc493850ecb2e6d831d1efca3c2ec8ee2e394599 +091ed58bede97d7a43b6f739eb0f845eac1df6b1ebfe876009cc5d804b15 +ed4b56761b3ce1af59c07b49dc798a44532297ad73d5101ed47f36a3678f +818297cc27f6aaa2aaccc9aa9b6f5459911d8c56cf499e390ae607f37904 +50b2b9c9be0f006eda0c715b5ca0481734cfb0597478e7602b0d2c1e4f78 +f03c68c17c70e4b42d7d2d3c95cf40f73488b3718e2cb05a549944d86944 +d78724e266c3319af89ae430e777e95f0d792b1c654306e421f3d63a26b2 +1e74b6e8b21b2e2b9dc596d013cda16d08e65e8f24a84b12b2badc653e6e +1110de2e709c1c1bed13707b70a421b384f20ca7a9a9d20324dd383f28b2 +d3c7a9c53f5d4c6b7c378d26df11cf55238be1b24fa70dcc178dad3d3567 +0fe4919085eb1cd905971d76a368fdfcf9d2f0a23739851a3a6d2e02d65d +54dee69ed5d81315d3ea5e356f94ef256dd267fd1e1a9edc9cd63e743f29 +9bcc4a4506233b8dd7652ca067f741603f93250c087d368f9e9cc4cc1a6d +ed567487c05baa992b0056a77f630a72008e394615a9db24fe56a956650e +c9de90a6c2259189440247970541ca198748928215c0e132a81aa13208d8 +63c1fe817f70ca573b54577d10b73100af8ea088208a44fb92aca314ae58 +79706180788c17bb1d0b81b6b95a1c4e0f9ea66f9b39bfe12444a6446691 +a7bdb03e0f03d9f07a10a7598f2166f108529f34cd90e601ffed3479abcf +cbde8f051c348e48c61d95b00c59ea1287423f05666c3d36288844067e83 +e14f6b5210842c742b89f13acd126b9fc50abe2ca7d7ed513d43b6ac7f41 +eeda416bfffcc5c844ab2d23d4dc09b2d510504ce98d02e72020d9e669dd +aa344c63a1b75632f912a1c0da3885da4af7e243e4a4c6493d6595bb6d56 +b0359106957259e59e336baaf35bd1cec5cde735272ebccae8d4904aebd2 +b32610c6fea2b69941d6542ecb44d71092a3cf067708a3d087ae99ff2967 +1ab7dd8758759b971a08ae1bad78270d2fbee37aa2dcb119d72f6c7b0c85 +09018a70d0b0be2c6830ef8e0b24b1ce1141ef873a4d7dcc501f808bfd94 +e4dc0f2915aa023076bcc8006490a43685ea25aafc187302ebde7fe1965a +04a5a398985d29f08e085127b56b057334d88eb638a4dde64afd204974c3 +939536b1b66a54b4db81151853915718f70813f096cc1b0ea25e363b4926 +4c2ad17158a4489f91453fbedbde15d7b74d7f98e81df23251785d58295b +a297f295aa6248a912cdd4f1111e6b628eecbb5139709e76ea4ab743cec8 +26621d08e6bc64691cc90b3c3c1778931a28d3d5b1e20e96c643316613fc +487c9b604c43463fa4533bca1236286e6f5a6eeb2f1d9c34bdde4595495a +365f88055d9268541cf1654acf478d384a5496a8772ea1402751a093582a +6625a0a44816b5fdbe166835d598644296249b92cc90aa3fd6445c9a19bf +27f59cb0616c7306070f33c7df4e1de64ac8c5bb2ffac1ef2b1b30e5a027 +5e6004cf64bbe2c6710edcfc3aa4add60106334708862ffa6652825bc848 +42736e47ae6917180365c75b27505eed3c6108e9898a780e20c3f606a860 +229ac46d0471aca0187d6d539a1b8820f620f72b41ad1d3bf3834bf48ca2 +afea8bf535af74c4562deadcb63d2f5c7585722b77c989342d190ff926c8 +a5263b4f25286f99cf6fc62ee6e2ad61c82b29d82468ac10fd27764278e5 +558ce8b41ba111cb2f040914451a480c93084237cac8f66bb7c6689f340b +8abf0150e06d5b1177278a4c08742fe22f42c28680f190900344adfa486d +59718c25d37275bce4df981aac35d2c7e85c72a0188b8953cfa516fd545a +ee0bf4b8ba301cfde2144241fbdf3d204e3d2823301572e23f204c97305a +82401660e12926ee7ba6ea1a81ff5c007933afc73266fac4c134ed818a48 +e7da01c71a46335c845f9da5e960b25339d551582b375814148d94cfb781 +fc56093827b78578a73d4ff67b6b87f40cfa5e3f4325d9108cdb64bd0642 +7b88c84105187316fa2990b4e3e8edb6c78abf164f4a9717d523794b2fe7 +72a04dabbe688cca977090979b5f47ceb90a1dbc167d305eab231c9f4260 +c4ad10889cb785169902fc0bed78da15b8417453bb65856ea0bea5245ba0 +573f623d215f6c0cf801851c305b355d26b52b0b343645fe25c78a352684 +1eda480919a1bbe5f56fc10abeaa3e1fcca7c43ee560f067f1aa2afd642f +769d1ace8e2aaaf38850f0d757cd808c921d716e96fbc07da7860dfa70ce +ae2888c0ed3cbf9586443532b68daed9a926655c157a416c383a53d8f283 +2a4e67468112a09adc837ed8ec95f70852921f50d4417239fc42ee3624ca +97f682745cc5e76cc7c67bd99f2180f8c0b7fb49539c8cc474c25c0dde49 +1671ff329e51bcfa779346d4686835a3ad6633fcb5e0f67e0ca9ced8f215 +bef4d240453eb2edd6adb22278aa5b985fa140c9834d38753df2014f8c0e +e6dad19e8fc54c03c1f6cb0f858986691d99592562cad95fa0a5b2abe4a8 +b54b457d42e8c33a2d1951c0419a72fb94fda78ecd92bd2a1416459e9dec +a9469f35e4c47db531726dee8f203d7042edb32f025df3d582547bb1d45f +7a5b70d317df4ebb16e36b0d798e0932fd2a85b04fd67143e4b287a50416 +2c1f5a037ccd780088c5476385af8168e12d97d44b0630621759173c8f1e +3006b5b1c6d7138b7eefc3cc5f54e24b2c3ca7b41aacfd25e554880aaf40 +6ea4c3c6e21d3b550b040fb1952598a7e8e6488fe38288b2aeb6c4718338 +598a2bfe4d2b9d14c65732da304c16ff3e1f8f03046ef095b65fd609da87 +ec24a69278bfe65c905cd0329f6a486b8525b7eea4f7ae56c2633cd83543 +269e8acd6d71f500d82fdfbde7f7f7b1aee67328549232e26ca55085b6e8 +4d9e2e7f74068f93a90c4654f2f396e57c5f76f7e61cbbe523dbfba6e766 +38bba3064da025a79e3a294fe7f1cc28a3b4c57dd6fdc48e541a85534b25 +e1bc11b4f78019457239eaefd4be9007d205f1d985f389db22400b279c10 +948551a6b4a17fbda0ffc9428b18b43dc76efb15fc2182216f1b60b4e344 +a03ad6c00f141ef99f89f24c819c3e32877a927d84c2d006940f39ca8b71 +e5951673ea9bfd1749923219de38929ecaa9ce43b06cfa7da1bbedfda56c +61ff6c24f40e59b13870d5fdeb82d981154fae5d6d5152de69339359461a +41a9713b6bbe47e868c933cd74c75db71d13bae4dec85e02faa14ead6c0a +253b16c79514657b15e68ccff9ee6aa385cff9e2c53d9ae40f85c793e4e8 +ff50b2b7420f4fe69807bc5f37c3e300e6b3c3549d1d3246a2e70f091054 +1135bdf805e0a698e236b6496702d061241687b7b8d1a0e517df0476da09 +d89667a7ab375fd2672dcbab8124e511502ddbd08ba04d941df1cebdccf7 +ed48405cbcc33774a68c5212fc6f132641ff413c984f8b43bdfd7b1a2a34 +35f15af07ef4970d3e4a0bb947c181e9ca27cc14a35bd1bd096875b45873 +8ca244f88c28728b74e25cb8c4fc1095a56ca75e4569ad3082ef194add11 +350db3b74b96761d4538596ff7243b1e1b724716a144106e080d42036444 +fd472998460ce9abbd05b42af9389ac452bdbba3a13a96890025789f16b9 +d92251fd3b3beb2c61eddb370a20456e3bfe5f4039e2557c451c524f8087 +015baf3ff05f51869fb97512968bdb2b49589c1c7af1e085250a47657465 +f480b7023e24c76731ac0eab6704123d77977d3a2c4c56b691346ebe589c +619c04515d34f81fc6a17527d5d8319013c5d4ff27cc3925e24c99231ac7 +fb9eaf0bba482d3b75807ac85d03cd09de5d9ae0b07b7a813f0449786500 +0ae8a7e00080300f0ab8c399057eddba273dd2e1b2a0dcefad3b332e6d4a +c1ffad846167dfd70e0346daf84af292d4f424256ed5ac4e104f80697050 +d50844a708eac9e7f7784fd01646f3bd0c595ca51ee6bd607d254e78addc +5e15c3b6ac4940ec865a5c23105b6be09ea09f2c05d6d76960a843b81ee4 +33977faac3cbda85cdd2f4db7c28293a77825635992af8f3b38b4480d9a1 +39b1662345a8abe1634a77496c3f57597d2985e9e54717ab2e99ca357894 +41bcddede9a9e2106b401d9684adbefe40d607f075c179e9cc03e59e6543 +0db70b441d43df03f2aa6ff06f224b6e455b01c64fb89eec9103e48453a9 +749b4d602808c7e408a8903091d85e06aaf635d0d529c3cdd1b8479ac0f4 +208c284bb678a547f2bd77bb17c86d4560434f7ad1937760a6aa55b614cf +a9ff8c9c96561ae6c8f2121c4e20237428bc51df2099b6c49e3efa18e6d4 +39e6e6981e746ebb1dc461259d8ea0f8099c47cca27b2d982b72c9a07cf2 +1b3c05d6e26e6e286e348b8944078e24809f9c5f3d014b4cba02533f5621 +bfba1f0edb776c634746703c9f73ba89b1960a496420c68f54e5b901a6d7 +33d7acc79f275fffb253f389aa480084468bb34da1e797e43b7f6e8caf5e +8c93069a3a2730e57ec39b677bb73e3f07c2055599f7062e53b37a5f0099 +907d2ed87ff7a82c95fbaeb888033bdfd67ba3a6031a4cdc56cb1e4cf5b0 +6b46e16d988beccefacb9e1c037023d7bf5ccf5d65aa66a17ab361be7981 +f132a578f3abfb97960a6034f052d9d5afdc0679782ec90f240f943a5f9a +3d969ed7399254ff67d89df668f7c56fcea1ffdcf20481474ac8495d3af4 +b6d7ee093e369c057f0b70858220693b398acf8e8143558132e4391405e3 +0a73937c53402e459f4aa3539cf7a99a3f51c0307d045df8b77757e92ea2 +f51bf0bb4f77d3904dd355665870c2b59f1ed7f84fc71fdd7f0b6c5d3182 +db77827ca6a2060d2b8c83c4ea4a432ef43a4d0a952cc6cbbe52a9f0cd66 +1a538973de41ffe9c5cf55f2506b9efee51fbae5e63bdcf5528499a47c03 +1163c88d3022606784de2f46a9c9235aee3d4f71d4959b0cfdc5b7e78c8c +0a8f9dc99440c2263dbacb343c5c648577f5610b50eab1cf7fd02419ef39 +41c7ca0b0e64ebad4b2cb05a0793dbc38f1946d44767bd287f5e9779c611 +ca0daaa1e7393dbe0683c8d3455cdfebc0e64b54b737e298dda605227c0c +4bba87aa3ec7fa6ebaec39e6ef2537d5974391d31739d9fc42983d81aee4 +4711c823f35f8e2321ac74943871739d2dbe9748fe68592263e7713f27e0 +d49b9b5cb7a4e55de54e6b800d15856450ffd3ae5f287b12ae4f438b20ae +9e27e6caa00f3eaeadbe08432684fdf9931e925544a680182602a3c1997d +e5d0630bd5a010535e66e1c123013d23966b3545c7431c39b97295bfa409 +9d14461004c42c85095eeacb9b47c593bc6db863533a8619bae09095de8e +ca432d4ddd49aa600d277e75dc3f5c6631e2a05382cb007825fadb77438d +cfa78e252d79b6a196d5164c2feb85d75eca25ff80b1d97fe10e87960ca0 +fc47c41d3a213bf141b48bc3aaa93fa86245064668394665bfd52d12c3be +4ce39efd8111754398a944c3fd1afa98ec337baaaf899d35e804cf416ad7 +fe45fff13fc6354007501043f98fe8428de8013901ba6a28711a2ca85a27 +0bb135b72f1d5026e8217581860729e94f2f1878a0e96c59e9f62714fb5f +8f25003dfc7347e990078a9a331cb3a6a535bc61866f02513deb982c4a13 +adbfbac3ff70a7335f40d5489e48e5ededef16191973d932479c62183b0e +25ee8c4f76d4f1ae45daea4a12aedd9ef81d248e8d19f8c8a5becdd1ea1e +98783eb7a38149170851b1942c96c53de06def80913bfc04e539ec67c110 +498d15b78268853e5c72f485f8a27b768569e54241f6115875e2973292cf +48ff91d45ebed627ae9f0766d22201b20afdd40e5b17cf337f2999e0bd15 +b86e46eb3c18fc12b7dcadcf9dd50c6c7e3f37e615a892db3f57e250a072 +a49f7277dd6a2c8042698233d35a699b17eca5dbda6d250ed4a16fcc893b +f0dc2e33fb1ebd7dedea3c1c39603c8b7e1a5a833a8fcdd5570bd088749b +b232615366687962c7e56ed089cd7b092505cafa5a80f503c4cf337f07ad +f0d106937e25670839d491f7bff7a523db609d126328c16113ecbcbf9c40 +04904427a108618ae5d4ed809f8ccaf72251104c94ec5bee21f91b179d31 +dba79ceee5ec7ff698eb84ab1d2d1a624f58b3622a78844ce51498b2cef3 +8eafe259d22c7ba61104651a862008bc1ddda58cc45f663eb26428daa85e +7785363a69d2790996ef5d9621d53042f42f794962fea46e46f37b8ad1fb +76fc8d5cf2146843f8cc625139c75fb42dda71a752bac48f294e4c0c8289 +fc46da5efd9c91bda6d027518b7e81e8b21f755a9615627d5812aca674d1 +527a1185eed4e3c628196e7d0759b1cae6b9b7e901e9599a65230f1ee469 +cd33b9bd9c104c44e3c1ab966c9678bd0ad78111a4e0f2d07a01a038cede +7036d0534d684a1562a17ad64a00f279200c0371b1cba61747671d2a21d3 +f9646ca290f6b82418a96fa177c6278277504b7fba936325f5fa124ab018 +a15dc18d2c5e8f93cdeea52beedb78a57828d81a3e6c38b9faf3dc4eb727 +3ece3ea4482a1c6242a335862c2c3717f9c9ed95f77b140c4e1569b2192f +c7dcf702d0bc9a50428ec406f8bd0caf886b4d979320d3e429816d88f7c7 +146d960ac12e70f2cb7a9f4e3e366665ab3f1b4b6440f55eea26dc9ee009 +6bb7763731740a537766490c8c174723bf0eb40c53701aad12b21d436adc +e22203c1053a9dc4e9f17ae617888c4b4e6f3a720e4e6366ba628221a387 +d8ab15e04ad69387c310d3528bd2faa5b22bff3fa494f5fbfac4f771c9c7 +402b95580c5ac4bb3af692a70cb2c851fa5cf1173eec3ec29b5a05a0b728 +bbbb51d3b7ad8b0af17a1563e82fafd93f8b71181fb7afe352874f4ec6d3 +34ab6747519ab8e847b7bced33eb5458a828e074e74ba621bdcd03fea604 +7f7b6abda01fc7514ba1aff0d4d0c0cb8f4e42d5a87e395d9acdd02ccc22 +0c157153422018725846009a3acd8c8cddb66bc6836b4026fd9f526aa275 +d06c813179e5924f26a25094e7bda8bd26afc4ceb41d8964d4fc4af1dfb0 +595bc5d6714c32f15dc7194e9a3a73013c45d8fa55cc0550a12d9aae8e9f +f199fa28efc2426d8d1defb93a65717af3ea8e2d5b4aa8ef0ef38e9600f7 +d4e7d9f1d67a2e63ece4789fa74b159bfe2f91c19b0378ba52e93df12830 +d99553b6618645e26126842ab70262d96e35e5e750eca0ce3458b3e51bee +2f21191136dfdbca39bdc07939e521e4f492f392debd029c1ea237bd89af +76bc89f618d530160ab16269fa6b693cf14bdc4ec7c630025703c5337f61 +458fa09104eb15c7cb20aa4c9bdb7cef3a09f25bc7f3149951a7cd753729 +93b80cd2112f7674cefd6afa764aa3486730d2c1897a264d82a91709fec4 +a21e30d812f558451804ee6f3dee2c4c437846bcbda07c5b6cba1d94af02 +9163b7383cac6e088ab1dc14ed3743ee77e26ea7ad3119a76c0b5f925c4d +e305cd7bb3a09a4539475b9bd79be28fc462d8718ce05f9d94caf3387ba5 +5e6e447bf81a9eddd3a34e17be66bc52b0c0bb6f86f6f008829173816d20 +5182ed2eced319864a796ab65d4e3950288bada94fa32b6f453afdfc6c39 +a4fcfe60353a64627e2057d4b379d3240012b3bb0ed0c7876cb83c1ba5ef +b6e2a03f340c2b576731f848f762a7e1ccaf267ee06d621bc33fc245d0e1 +547adc12cc0eb58b26babdb8eae9cbfbab93836fff22bda1831dd01b7346 +ad377aa298d84628bf1c07433284b0a90fc89f5aeb2651ba2cea405d4f52 +ddc0e74b871d43f71eb4ace0d2b401f9348eac3a2ef0ad295036bf6cf6f8 +70d58e00b619d50ea7dd77bc28def91d805cd527dcbcfdc16c042bf9b874 +e3b1567eba4c1e70744b9e7e5bd1fda6a5ff6e101613fbe58dc46cfac1a6 +5adaf65e49757e9304e2ac9a91e0588600c709a61d4231730073a36d473f +518a145e141d0a5a494441b9ea99ac23f60f54f8127b477e1ce698bb4129 +b4b1dfeedf10d9e665c247a62f112f5ca30b0ae5dbf3e495ff06eb28eb43 +8ce8aaad84d5f50fb56a3af002c23bcf66abc2707ac233fc0f2723db99d2 +cfe7d3b3667732a531f5dc315ce74edb9050bf75d29e6430f57cb6778b2a +cbd57dfcef896e6766c8fc5c9f9fbd701cd62cacf33ee0fc95e78dadd205 +b5f42cc63024624baa0ab4dd447832b4e1dba77bdfadd223989f8e958c8d +759aaa37930664c6efec708116248a2a7af3d656ddeafd009b7f53338546 +08e67e5e588a857167adf9225cf6c641f5e19c3e08678a281199eddac831 +b57223b1beeadfdcbc8f6f25d32fca2336c808162e8f381656e847fb6cb1 +3969572425aa05ac830c33de6e030f86a3a85d2a66a77f103c7042c97205 +526dc882ea9a00eb8bd5519847eb424c15f808a91652a6cc89b66a573112 +6debade123c63d88a2e550facdeb3886ff98646000c64b3a91078012ca30 +904b71737cef6becabd43dd702880538f5a70085e6cc6015d2163681067c +3d513a8c66032c34a0fe17a58ad4bc97ca69bf41f11d5e910fdfe9729652 +d3ea21f8dd8cc19160a8fc77573b1e9cef4e790a79d8ad6723b6804e9616 +466c935303e063dee29caa6c3baebf278b818c2ec2f13ed645ab452397bf +00db8b26e115026e256746cd0c78a959364fde6deddcd0f441a61a1eba32 +c7bc172bb09512148d1ebac9e791b7d51b71cad2dc9b83b2f99b3726607d +9cbe58b499a13753ce87fcdce21c0ad0528ed0efb9b2c927f57c78c62624 +8aa2b835a0791244c5896686a66173ec9f802c4c633a42b086334d2a4878 +0e53d00809247be64e529f96ad2f8b3922a6097d414dde1ec76f9552f9b8 +d58b8e34f359ad792b2be50c26db05035e7497162e7c49c38d3cd9b98d62 +0aa67492be5afca3a81a7080185c7f0b5105223f1fa77805502a2e8c5fee +a27699858d84a95842c5f2fb68686d59fe24091fcdde139b6463bc6c7b1e +0e90d20a83651af00c85797bb9f53ecec1675c7ee636d0d9e77dbd8f8967 +0f855ee4d4800ff3f6950eff09bbf8a0daf6b8242840cfa5ba73beb95115 +f4a78bcc02d85ecce0c0f2ef6f328ad1dd6cc0495a3315b414a4d61da50d +a46d7acceff6ee56451805d26b0359af193531f95f6589cead6fa041af15 +3067f88a0a2fecd135c56682db2b45a71d1fa737c064ee9a4f404bb72a70 +b3af0330359393247ec781512482579865240a23cd8479f21c2c44a119eb +c4e81b308dd8aa86e60c3dd8ada50e0dfe8308eb1a7f201ede8dcfda405a +efb47e0e6ca7ddb376dcb21d37f7acc4d3e9f26b03a8de0e8940ca3a9e75 +963a389df8038d2c486072f61c0ceaf500753c7a6352b1cd0338d9212b42 +a4d3da23d5bdf44c27c94b88a415a3242ffe2e1b332477a21d2b9ce075ee +479c6e657a4d8874a8c53964229310e01ed4f3c686fef5258edf3b464dd6 +ffd7f1caf473bbe722d60fb14ab4918e93878a8ae4773930b8cee110f476 +7f42a52d9304c55be12846c911a10ab9b2e036bf9dfd597f5348d4223331 +5fa80d0f563c388bc2532103f05e90dbf1923f229f980a2f4585c7a37351 +1372d07dcbaca583099ea972c03e5aa67e6638826db134564db993ceeb6e +7a6659c7c5c05c310267d5f8a24eec2d5cc3e3f3c808e6d6068d1a57646b +37fabd98ecb7baf99e7d9ac4414a491a73ca34c52f394352f6b5a15f0fc4 +d88622dac694699c246484adac3b1d366afede2a2cd2042c90516a666a19 +a91c80248b11224beddf1a320e230739e755d098b6a67315535f4c187cfa +67ed817a035056353fc859bf286317996fffb478a2248b908ff12abde705 +402224a3ee5f463dd3d243875c84e02db968eca1cc52c75171ea50d6a88c +a91327a7aa5795019f36c0a19c093a1c9d3723c7568f9d41f2e4ffb712fd +47f897703d7a620b586b81936c84aaed61d84332b3bebc4f95b796b93ef7 +a1f565c494f8a65edb21e2ee18dc025522ef8e599887ca2836069cddd889 +88e5862977b7472584303198cce97ef9f9e1446d1f1f5ed1cfc666a8a0c3 +a03e1792efb60a9b406549e0dedf6accdbd98742568b4735a747d8e5de21 +e630125ae0c691d054e42199c15b1f80cafa6e7bb2005f374a9a5f9900ab +b7409ccd50c3afccab1214e6a856f7c7eba89bc3291801e1343da9dad2c6 +ed075c8eca1423b43e587aec67e6145272814b3f191b3c285639f9e2d6e1 +48a02dc2cbc0e054d6295cd05dbac1950400a9189316f0265b86a732d302 +c5bee8ed233768f237c62600cbaaff3a110d5efb6cc7ca3b92d965ca7c5e +8d3e64ecf239fe2507fc797fdbe54c1112b28d4da44c60ab09d994c5ba78 +d663a2591934cc052bc70cd1dca3325c66c9cb982e2039f5db70c848d3dc +ef655b1c2cd0cec8865fe8e1c0a267be4f707ece6f5a3dfca3cc1edf92c7 +60439f51aa69a4c1801e96ca4d6ea4ad980258f3d15c893913abce091019 +84c61b91d603053e49a97cb82fba707dae8af1d579fd69c8481cb7b712cb +cddb4d287be995e32c02b399602a08b9dd849039b5673f1930bec7bf366e +b082d2ca5db2385c8cc45be3fc0e31820191a814eba7c4f23b1938e6c4d8 +00732787cd2cb97f762dfc85d4b798809b5f2254d826ca42b32695428d12 +0298b44cf38494e56240b75df1e41e46e53c44dc505452256dfec819408d +605ff14d6c1f3f152f2fea96ea0ab3b472d8704e06be9f8c3e8395caadd0 +6d6da033e81ade5dc3b83daff743c6e9e48716003d358df63cd7fd3e2f72 +7d1f2d0c29962f76d5c95ed44b6f08d052025a665785f264a3d5f5593677 +b630e628b5ea81fb37cffd7a30b7fad226b6fdc82b0878af4c0ec4f4243a +807b9839ea62bcbdf7c2e9b30a623876e632e084ebf4a21eda04fc88a1c0 +7021d0c72ec3e969d449feb08e5826ec20e55b21ea71ea59f6e3b0710b0d +dab3261b4a2029ecab68c19add5174e55d5e984a4e5f38f592a302fee6ec +e732dde841a28672c620cc5d687455a5c06fa9fe688394a04f96312ed025 +b7aa6fbce2925f3ae559cc1886beecdb70822e2e5ca3f732a87404b1536a +ac469989e9610cfa440ace43875a70ca51f36cb6f629d9424c1e35a88f92 +d5da3cd8cbae6e8425a36968e21f4f30349749e0205bff8d552837d6fc39 +532525370bbac833f75f1854c93fc533a4aa53adf7008173a70d94a4ebf5 +38ea9e62bcda7c20e0a073bee2efac34d2ef1d03babd5147659e50b55704 +5b2eb89db303749b04d3f54b43fed612fcc68206e001a7afe90230d9c12f +74a32c7edb5d0241dc3a5d51481fd7c8fae08fee263fbced7c7d911b3a30 +3c835af5fadfd218f61a9d6de80485abca88200047b094441f7767b97a24 +e8c612590fa2407bab1e8b56c71914eef2355dd97cfafcc192bc06fce063 +d3d9d1a629aadc75e3bf207234c208e7e30663edd691043065c9cbc473d9 +7c6d4dd3dff59d6a9abcdd4412c3128f603160aad8f81c6e7a4dcaf35f3a +99b4ea10a34375b477c2bf846521a7eabd4d28078e9340452a198f3f5acc +3db7e3908939ff6e3709c6a3fd9889439a4ae3e10b618cc92e14b68429a3 +ad2c80940a1079452ec266f254657be7d79a2a24084af73f6df71fbcd32b +f6913a3fab25f977787f7bb0c3a3e8bab38d7a2db0b4826950643dd1e03b +d7dd1fb149a33862a89226b7cb454daf613128c2075470e42e70a9444a8e +6eca526345ab48e6f5160ba23b5bddfda6049ec44ed1461c7e0dd514b16e +2fb285f72039de3c7982efd40d7f6c8e8f4cf35ac71b467bfc578002e8d2 +239a2fd2c4bccdd8af3d7db1f4ae7f2d2e0811df9d0155ba6ede50b5f052 +f14f6ab884fff244d8806c07ebcb49ed22d85df696995991a954aa97a1ec +d86acd76e061b7541e87997fef0657a826bd88ef3a4a5920462c6595e7a1 +56f453291ca044ced810860c3b0149bce73beca713040664ad0591304106 +129600af71317b0d2907839ceac99515d357e980b1937b6e1200aacada20 +5421001f1b2f91753e80d2263c56aa164a74701a8d5fd28e46480b0dd963 +a683a1f355d7fb4463c7347c94ea5e2ca40b60b56297cb22d972c5bb10e5 +6715a955605256c1541d9f3bc5768a6f355cd3b863f0fa1a781edb49368f +51b29481cbb41d4aeb07af9dbe8f52c5d0ff75f7fb6431d37d6aed84d78c +778871cb0f715b4f07580f23b586c969c81b471ff6a6c7276f7e141e02a8 +584d4b9ab00e7bd643d2c3faaa299b1f1e25048461952ea42d4882768a70 +de46b213a287f8d31ac46d5436f22a796c05d1fe50a9bc2a928066627a0d +87dd57a3ad91db446404b41557d1457873482005ea20916bbe46c613f456 +c849d46ba79d20627b446b2f49e3fa309ae14f8c420cfd94922cbc0fb9d3 +5a0f7dbef577f1849a1a80e0011da8ac082a8c6f61658e65ad177abdf23e +e17c8cf0d26b9fa3a6e94837eb9e930336889767a8d7ea3ce980a8ea9552 +8b004957be6067cd9bd8e02a0f23cc1762cca656d33412ff45e917fd4a03 +eb6e8c1f43fdb0a8965a33b4fd26bc24a20b304ca817e88495ba9b361a3e +933717ffb0271f7f70c5d3cba1e86d0f51bf3aba194daf32c35c796627d0 +0c7b2271ace2463e37e97b3c826cf3db60028f240f9452cbe08f7ebcc5fd +b1bcbb3c327a9f450b9e5671916101d6e3e5e458ca31f04d12f592f83bad +a2c3683d3886aa3b403963ab5dbe220fec00037a745839f67a3635dfd3bf +f08f367482962ded88ecf6322852d643a54d5d303eb04bfddee9bba1ebcc +ba7c653b3a613a8e719adebe3ce1bd7e754e5f4977e863e3c2d388a65227 +b451d4f3a4f94e06513cba4ac1f2f511613ff035611684ccc461599000e5 +46e4d972ca6960e095a526e4735a23421a4c9b597ece08afa2753592bd16 +ded93255a1e33deece3c5eb77b94670e8137f2a4a4b98ac193258e7dea5d +b8408a806188f2d1ddc440ccf0e9a6e2f0c78fdbd7b68dd4939d2458c196 +5bf8bed4564b32462fff3ec892c03b11d3ea813fab4cfbe8d3016329c5b7 +e3dfed0f08284d44aa0b7a2f6bc96ea4503e8ef52a64c22bed6b452581ae +8ff8917d53976471941a9116a2d878fb2541b561767abd4e31ccd8a590ca +03494c62affd64ea0a1bc779173dad84999c7a8d844eb1259de7bb5b25cd +023537a474a524ebe4660b22568949e624d8fea0ad37f4ce1ec75955eefa +49c6bf1803be87e9c9865ff3f6b8525b8c15fe8835ca153d27e6c0ff0ca5 +1029a7a9185d25f0f14d86fc797dcc1f99ee97e2054b9c2a2e06fdbeb8de +f6cdd368bf23a858d9f8c1defdceaf1b4a8de5eafc604ceccf0d285be00a +a912eab66eff4d37ad2efe34853bbfd87ce09b18749b489943eecae7887b +006fb827d10191dad18466cd1f86505879310a8b171f902ea0c26a388e13 +b53c700272cee2bfb47acb58247c13449c6bb9d01232c32517358f1a3de0 +64d43c18f8827d53789ccf3ce2ebe78949a6abfa1a6b8414ce360a5e22af +b7d1dce6f5a06182c3b984b4f9bb1a905a9d5a1483750a1de0a857cd5c06 +945eb7d4a2a6bf1237f32a154fdc06d51a703d44fe052fd3c53e9e8f417b +35d1c851f9203a8997521529f21ad8498f96930aa77ebaf82ee02a57bc77 +c792d9f220294b45f48ea8fd94e01cd25645d36d168923562f3fdc93cb79 +dd4760da0c103c2675722d7a1b79fcb4245ed12fa0db52492c9cce58b333 +cfee822812f7dca68e802c451b5cfaebac608b950386b6c58239d1c62d62 +4dd5d15782fc552222cca06ddf387b373e32c3c2864c63c768350c372837 +60f3515a5b0afd66c48ab522eb3e808c061f5cd6bd96cd18c9839d30508e +7d4edb88e8f11e31e10919b16b7971f06d7877a058d8a4944c84fc6caedf +3341b48b6e0d3c7b85d710e0c35f5b5053cf4b4798b3778cc28b2dc7ae0d +f3a49f9f3bcd8e95d746c35c3f47d68b8aa35d97aa08e711b5fbe70d1a62 +3c82541ebdc51a827d0a69e6c049087ad26f256eb7577f58ccffbccba5a9 +5d093dc29464c9a38de95bc6b1853963b2deb0b57ad1248d6f1625e115ee +b9510b5772aae4e3c866657db0b3bf0e0ac345e116f8d4976b770876ffe3 +748c36165522991f46a36f193dd1a1c94713673c7e4c81582391b636c72d +e94ce6254374f99b623e5686c13d8a8322e83e11bb0b0a896c6a8c2c4f75 +6c5385cd7017f26d23f7c3ee97372c868c8c915581723bb6b76b4c3ce899 +8e4fa6ca40b633dfdaa59ba902a4952da90ec4fc3cf0f2676acfa7f76f78 +236fa2de10fd3545357215246bb7e527f277c28b353cc6d79dcef21bcc8f +77603cdd58a2ccddbe3a9802f941ced8e035313875319548c41992a2be93 +9a17cc109426e33825ae59bcd17cb19f50d972ffcbe7d9b4b0bb095303d9 +dc9d406696c2508d6ce99e11cf00f6461147e97449ed5f486d480a86d3a7 +acecb7e9a945984724efc21c5079b1fd03ed803c2deafce3327d2d782771 +5fd65d9506216c88b0fa26935e95c64114a51919d419038b1a7e9c1e829f +bfb53275093752df19891a97f3cbf7719c1fd6cb17019a6d2d25360eca80 +4c4b35172662cc4769d2b785c6c87e5a4ecce31704e59f71263b7c3caec8 +acb4c7426ec25f11a0042323ee6c3eeb04284dbae2c770bc419dce79bd45 +60aea41571c3b595f52560191dc7a8fbf63d413a77a0905e517441b16c2b +501ea2f9e99cc38d052679f288fdf1894542e3a66989a0090185eb2e7513 +4bfa3d9147c3db8a621d9d35e37786853779e157b47f71626d6b3e633005 +9159c17596c1b87fe2b4ff47ed9d78fa4c2160077276c8b58cef5dc030b4 +a5d83cf257096c047fe64de307c598b815058e72d5f57df5c369e664e137 +de29349e2f9dcd8c9f4eba6e765b6327d7a20dfcb20711273fd8091cba60 +5c4c494248076f7e03df65a6a50164980bbbb708741e5bf6056e6f996dc0 +7fff408c5b8eab8dcec315e92873228c805d4440a6470e3ee3983758dd21 +1c9cecdbfaa4c9300cba00608a4b2404a3c7af017a3b7e67f39f0b51acf9 +50d3e75cc7bc2b8d3480202fa958e8ee0b2405015232ee0d264c7ca02c18 +ca45cb3c2de322d3eb7f00f9455db6c5b1f4e59c3e95520ec36d7d903cbb +625d70b54bf6f8255e412604bbb29fee026cc660577f91db1db4a613eeef +b20cf7ae3cd89d565ac838416b01b5de4ffa5550d17fb51fbbebe21cf1d5 +6038863ee931b90dec2e211ed42ba92ec244d4ce2c4ec5ca87a026992772 +dc2af754fc982b94f36ea7b7bf75e0ece90cbb2a6aa1a012e8898bd679c2 +3cb3827c35d5d02f0569c7aa82615d4aa67518ecf668d3b57d6ef1a80134 +24ac2268ba0d9a74d58879edcf6382a89d397864940303eaec45a38304ba +8b1cb198967ae23eb81054be74b16909a405e8a7799cee3c270fe2a6dc50 +bd7370b6b2c8fdb9a87d88d5d40348d3984e39c693b6f4486d994778607a +80a3122872dd65e40492107c71c3cf708a9717e9eefafbddc239c53aa964 +5b711038e59c8b861b37411ab2039bedf9cfd00f08d9c5d76154427ff5dd +39878cecc5d7bfb3f1f035087185c0981f3c2139be84872ffad3408531c4 +ea9387b89f5e3ec779e8850d50992dfdcf9132bc551e985943b07618ac10 +d1150451f0844c0dc41d6e17eb508dc8689ec726400d5a7f6feb3cc7bce0 +5f09228b7cb2c5393664d8dd9a4b96b1020ef25d70aa2d91cae93afb5f2b +f0aa18ca5c599fa1a708ef35bf8f7ffec9afc1f242870d028b2b1459063b +493943ef1283829783e1010242e5cf4da39d93d506f3892936e7d6cf1124 +70a521d397438733d053944cff12d6ffae8246f20618684f263715aa98e1 +5d72a526383e05c23214b78338e5b476f0981d90056e6e5d0db66b1df229 +8e597b2abe1d817e18beb056e65edb4234342d9600470b1420c9210419d8 +34e431b82f58608c87ac361a02d0f1fe4b470a3d71e0d21bb87e1023d428 +e23d596cb9e1a2184403a16e36e644bccf9bbde27290485057e62827283e +7380af786bf395b3961ba5ea469c315763fa59e0f176ef81985f38b882de +56a74d128e256d1b89939728e55a92aba21a6b7844fac1ba7bbdd8b34a18 +194a2984b000380fe9f672e83efdbf276fe797a325815b0f25cc95c97a9d +acf56d583486305d7c9e51a7e337d14e3b900333eb38fd93a99587da2341 +b10c059c71ce080fe7533c0f059fa40e560af9c4a41a4be6fb45846ff8f7 +8165e10b4ad40f264bcf5596a1e8ef8cb6ea4b1a3a5c69059ab156384367 +9ecb2511a90e8898f54295649cb73d277760d8d04abacc7bcc6e777a0530 +e2067ccbc08673f9c8c178f9d672ac8a15e5367f0c5651b53e75e0cfa57c +931746ae1a679c246d7c9417f1cd89dddbd1173c2f880b7b3847cbccebf9 +9f7122e832d7c9bafe2b54cbaa1ed48158de3f36238b76b0e67644a28aea +996ddc006f6ac0242e4b667639e7523cbc90a0561193c1af34481c2ef402 +ee43a82e1ebf4e3d601bb36b2d95cd93550d61cee7a94e72f6d30c32c8f9 +1a61e964b1f66acfc3987f95d4028f116e9a9a8474aa29c1c1a984be0e39 +3bdc41dcef6a6f1018db60d52024899d8eb5d55d324d73f39bfa47377b9e +15b3b06a7585589fcf52a54684173e5183367e7b0952dc4bc2767c4c6247 +b1d6103e52bc7b7ea6298f454c5d97ac575f19c10acdff4e10c7d3755cfa +b4200cac545269ff1d8db0d607c7ad47f40ddf257ab4e7d0750577003c13 +e4941960c3dd7b0774ddac18e8abaf8f53e03cbef6d57b44f24cf821014c +064278fd51b3427593d17694b4abce81f49cbb984c5878cdf0c38d1ed7fd +99b0b9a3bd8d8ff6219588b3b8fa59d0cdd1d9b2f65122ab45e48f175746 +7b9204926140e3c350c5a927a2e700173053ec35d3f1da2d7258714c97fa +a857f0898917bd94625c6d1e2d77138efcaaaf517b17fe187a2212c24a88 +1a2c6a647def6376ed80ae4175c5ee80921f001995b44e49f0d33dd9075a +cf33bb03671c0bcc34ad5784ad1cdfed3a6d9ba103b3ddc1cc2de74dbb57 +6a0277715275218cd19ca8899209125266d8bf1286f881dcc2c383749d1e +768d670f4099f7de959edfe852583183c91116012881a56a24aaf020ea45 +cd5f39660debce30ac1c7b8cfc60387b1b0c3e361be612fdfa9f01b7e4b4 +a18839a2c7e0e393ebc5ad9a8a4ebc316a740c1c295d9ef5f4dffa0667f9 +582c0bb837b142c4cfc6b1798e9476d0631111033b8ba75a10fdc800e2ab +1e0e829632f869cfe4737be9e2800759ee0831dc7d1195eaf80555771981 +dd6dc6606812d92cb8ef86447f5f6c6f626d0e265c67e52a6319189ee349 +d48e49dfe6a9e98f76c414a1e3217ae0a215a17e54aa498f4ecdc50242ac +c7e2322f63bb2ff2189d057e7354e32a3ed1803116176b9b9d0129930f91 +9e2fec280b2c8924e49e7bb75768a2ee1da8adbed4e3589906df1b923aef +84c1bd327438b731012e69bb0d43a1842cb88bb54ea4516477f704cfeb28 +6e3ea483445ad4d74586fcf32e96d366901084365f693a53c5fb532fbfe7 +bc0cadc404c4985042d68dbb90a6dcda3531ee324d558a214f935cd9fcc9 +a0cebe9b5fb0323f4b3820529599ef48ee068b5ace85004fea2984f0a86f +5ac9d56163bbfe1142b774148f1eb0a4dc89c3349052533a7de66729db24 +41b82f8f7360111dacf69293c9b281a0534f3e9e9224a75c49a832f28b2e +497262475507b6ddfa9f01ca0a6696e3f5ac7ea68595eba0c2eb8a47813f +f936d84ac1b23eca7aa2862b793ccbb0df9fdd4931bef354cec12fbf4785 +59fec29f81adf4452e83963e56541d31f3691c93a50f0bba5e9552c4f2a2 +3a6e53060729854a3dd71cc4308b91957db19e66aaa18fa67055a950f1c2 +cff78a03bc1a588cf624696068068719afb1001c4581ee072113882d9052 +b21e355d401ed8cd24d067b99e616bda5a0a5a9336fc499632b79ff2fd0d +efb096ef46b75e2d4e0f48daea239719fec4d9a29818f5875fc5041a9edb +d26caf0ace14cc80ba49bba59e918eb3d8f1e541aa16026585a2f72df7d8 +3541816de46981fb3efd0c30e458cfad04c79421ab7c4925e23aea07f9f0 +18431c790002596d26bd9663b51b699df53e4882cbc34ede88eb55045b88 +9b6062e35fd1e018bce785157b85ec3b9ca6c85d4b16238275385b8285db +012d8fb7c9f5b946a41d7a0fb878ff72c39683144d8a007cff631b43748f +2d5fc690300f9bc0c837006b92ecebe0605e8c3a4a400e18ae8997d1b45f +ee10068e247c647cf82c6dfbe5e881d511ffa687b7aeb78546bfd07d5f7e +c242dcef4930d8aaad8c6152b6642aac325963fd147f236bb850a9966573 +9d06cdbd7ca79a527dcf461e33f22bc9c5db00da2bd3dddd8c99d99793bc +98282aa8872ff96c394285d82d9419eb78b6ae37a5f519397700f75d624a +09bd255b576e955a323e784e8fc31131f003b0e3024a4f58fef2a6c04379 +6201fc425482e1155e229d1b2d43ef7b0d22322b22ef5c9a1be026a1c3d3 +75edaff99597e1e5477952a4e8d2acf5d014bc00dc2a272fa62b6983e27d +228881e2ef2b8b95a681cbe90c5fde16331c85222fe2a16f0a3c3000a63e +2e21666c0c119f8af89a543d37977069a5acf1556324f05204ce8cad50ff +4fb630d9cbbfc324deda584aa56a99d3a76ff55bdc2c2ea3a021361ccd4a +83c7a5e2768d210fa6de889fd48a39d679c94ec3c99a8d33ff11377da7f6 +f1b71a2a05b302ecde954f26773f39ac881542f0d0969c3995c3519a8ef7 +0b4220d86bf01beecc6462855e7b686e1aff1ca91fb8fd8b4a69e10ee0c2 +ad94add44449506f9b6ef43641f2026eff6e605c670560c2b74706fb949a +a7e8cc6a2d0d6207e457e7fd87ec1b9092dc68b9143947cc8ed14afddcbf +8fdda228a76847f96802e561f67ceefde45ae587673983fc04c96744dbaa +83f2dc838d633943c75dcb9e6410474eb27b348f26e505f0ab90878940e8 +46c5e9f3c5fe8c3558c3236b1b88c405716949b8506841cabe1717474bb7 +c30db91cdee33b0f844811762faec535bdcf84c1c747cef9b1fa61d2afb5 +a81335bc42c06a94d7d59b7ede55bcf6f9867aee107555cdd084b7684c2c +87087475a39a9da6347be281ce5635a4d07865ba98ce26c1465b1ab0343f +49ff37b4d0ca9f3bb693d78dc3b21925cb996a038dcc172527fe57c07460 +ef39c07d4396e7fa970d9f22abd21a9c794b64ad96762c7428f59a8757c3 +6d6c4ffb23216195a04c2a2c2e7b10ef7193931544d782fee4b91e01119c +5553bbc6252270a8d8c56dd62d448f5ad8dc69ccb45e1f17f0aa1e445129 +dd00f000005b23d38de93a3be55a4c041947f36b4e4536e307d0180553f9 +2e46b743881cb5d5386c48c7d5f84c2bcd06b9c501f78c7ee61fa2351679 +1fcf4db278af688a2e6010a56692ad92008497487edfe4bd5fa083fa5441 +38b20d6940020887e35d46e093b71f7a04a67460dc8116b4d4839625d7ca +6959d6831cd93f81ac4ea2709036dd738364fde71113bf22ebf13dfe1642 +e564701e6f0ffe7511edf03fe448c2b28c64fb7d54b94ca576e481fa56b2 +b18af10c71f699b6bfd47459cde1869d0fd306bf489a6f42e5b2f05ccf55 +bb6b9526973d19cb134ca7f13f1db3716f8cc21773a832568c16250b5cdb +16df24bf81d49f5b37018bd310262ea7078107868ab0216cec83cefcab1e +9f2c665a31585ca04dc01879caa79aaa5ab201b516f7052b01b16bee5606 +098393b0e5d9f9e5e3f4eb20f63c958e796df41cf28839f5c62a04316487 +45d7837b519f3aa36bc6c08ef040ccf53d9b6d8c0c7d1a84d707ec57a3c6 +ac9a62ab37251a01a5ed40fdec6f5be6e34c6a91d058319439778a2ee5d0 +363e2e1f33463c33327d05ffc0cbf08d5bc457c7230448972fb9b4d0d782 +ba7dbf10d3ffef8bf5236ec16d4dd6d0d870d9d5eb5c64c9a46a4f583d4f +831fee74b0e5b33a09abfd4444929bd8f638cd72eab99cf2e9551df42768 +3964a592e49d186f285258c5d5f62196a98532421d73e3495f82695feec6 +e1952c562d546b28618ffaeebeff03a57f4d855021f85b0c7bc37fcc6da9 +aeca099b646b99d4189609d3ff2d56422f8c37e97640293ec7c90e338088 +7836f4938fbf495cac14fba5648d89282d8d49d91af73ed36581139d8bd4 +2551e263e830ea3c6eb381d85c42d74c50db0ccaec03f535ade92128a016 +0e811c34748309af7604919b66cd43eb5ca975302dcb6076feb6bdd6ff55 +976fe990fb0ce9abb11b195403fb26e3d6c6a0de1c5be79e171a61e21f79 +ee8dbe7a832519813ef6b33ea098c2c32adea219ab2aac8b093f40000995 +539d1276d5f2ef84ccd099b71fe4269bdbdb6a8d59c86f7d2e3fbccf8773 +d0fae97640bc1ad43cb4b992bfadfb09dbd0caaeb8cd9da264187c4f9730 +0e9a6c9deed5525479e605c65ae336cbbdf4e5d7f79ad098f977285e0655 +79b748feaa97f2a753e1f962fcab68d72baa8ee4ff6691c23e31bc0f3e98 +1a96fb440404856ae1ab32a7205b17d411d8f21c8c93b704d07ec594422a +bc368cda2b1610ce6a973f4474e12b78b532666797f5755d269772c9f540 +0b3bfc6c58395d38527e2cccf29b56123f7dcef3bde5dc1dfc5b0293bb12 +5085b1d2d929bc3ee84f4fad571a4991c3dee03f2db3a3097e52b1a7d5c7 +3ccb6148eac62e8e36de9a71c57638c6e4d5d9ded18174e8c390e50b4a5b +913c074eeaebe390b214b3a68f02862b9a296db4b409769649e51d738cbb +dfb7702e15c73c2afc6bc37ce15171f4e822cf20efe55d9f061aa43e6489 +89628ff79e65932390cbb15d8e621333b18b11c3bdf96f841d7434e01ad5 +01fea964a75b248a35cd9df9a37e48a1e5a09c624b93ce44f0042fa00d7f +9ee89b9f7ab785e9c718cf6e7228f743271c2c9bba17e5208b920e44e765 +d99d86650eb454b0faaa112753aa1bd3a24239e9c5fc47eeb1547ac9d237 +31b8dc48b9707830daec60c8d3790bba1120f7764efac542cffbcd5c05f9 +510b27b2534b704ecd36c8b041fd49a96881302fff5b0163a2dd09c751d6 +d6afea9170a4f4c4ab8d46e62f763fe1bda51dd1ce4a27e772f3a2869155 +f762ff26b7aa6fcfa4f1292e56f03aab6322bf867e7710c34d43b5d85b45 +aa68014ad7879eed051b1933e491496e3e26d9aa8b80a07bf2b94f1077e8 +4a9726f08199887d66de7a307bf33c30dd9cf3da188088c03b2bad09a217 +6b110db2c868b53da9a66c85737ba66c93c58a259860e294ad0191e3a72c +73f40b0bd98699aa08daf03587b78f391f3a4313c58d9f29b53c70785637 +bd0c58310109c54091ab0a34cbb0c478613a7ac0fb8f0a8b4645ac966395 +d8ba775262cd291136affddf01c1d83dd4eb3b59ccad18057fe7d92a8cd4 +a58f22508d9fd7cf356571f701bbb23e749bddcbf8a317fda0aefd952bb1 +8545610ffad3ac143d351b8db3f66293375e0e50235f0d0466932181d377 +edd32a5f0ffa4e22b5a0cb4f343d9a7e4a342e9d09dff6c697630cd39718 +02c277a5590b8ca94bde6b38446c794d072bbccb724d5bc208eef1b018d7 +39373bb910d668882caa779c2d686081de6a2606417b54d7c20e0e7f7226 +48d893e4edbae8f00d6a6da3712f91ae860c756d1127d133ab828e9d8002 +3b50b162c5a1c5cdf70ccb3fdd7ea060ed20838be1e50c4094c9e79e1a01 +87cdf780caf45a725964f004253e034c5be46bbf89d94631f1a33baa35b8 +4fa2a9d08481c6674126cd96ed05dce48bda069d902d6836d5dfba701dc0 +f98a863e64f0e312145d8dc0b77f25b43aec729a1243b45b08ca228dd610 +1caa2ac5adcc8eff84a4ca3f254176c2cc711ee6c273835d0fd3528eca2a +976b88e51fe347fdb60f32370b66d338931d6581630ed586f349c638960c +31ae4204e89521a96e1219e696b913deb2aab7a3b022d06f34fdfcb810a0 +4e60a4febe284c2f063e0ae9edf87704921ccfa193bdc912b747e1357006 +6223a49f1f6e2af0d4d65da04ca876ff7a462ffc9c0ba2cc545c3bd36dbe +762f32b2d6be5867c59f479195c92440dc165098b74ea5c3ad93cdf2d410 +b04c16bc7801e7956f4e5107450787aa592493171c3628e6b8f49d4f8429 +eb98dc52ef025f001387bc1a7093f7a99f10b5d2d7dd8bbb393bf6e56f08 +f4f7fa1a343f220d5a1eae7168c74d41be1dc1a83bd65b72b982f4f7b34f +24f97f9ec9a91011064031facff2a14921a32024385f4e061cd07d152e74 +1bf97156d951a342488fa7f5ef934ccad13e2753a0ab7a1f565c2f7f6b34 +9df03bbc25bbd972a9adf809bb5c5048a8ccef9297b2ed3324d18867f293 +cc66e88b3a39d107b610dfe79a3b4e83a96d3d52a17fe8a62c9fdd271130 +148366942c9ce57558d023da5f7501319ebfa33de9e6d1e76d7c20db8a09 +b657839da99f3d8143f1ee6253a3295c9651fa4366547893c2dc7abcbf4b +b7609de5d001e0a36d9ffbe01f7d0903b3208ae8547e2e5f14ec1af4c253 +5ca8f4ea37e3f3ce172c7a1e8308995b1cc23e6e81190246bcab6e755bf8 +68d449bb02a2aa87c44c9cc0f571adc72547ceecbe104bb274b8ac16dcb7 +5d5f458d356466b921acdeeae384e2eb1df6ef393b41b9747f0a4faeb4af +1928d9ad6fb7e06fdc621e4c6fc98cfb43f88584bd55d9b97cc9549093ed +e586912161931162b1b1d52d0443260daba02af2b4432100d5506546013d +a703573fa8013685cc798ce501960093ded713ffccf89ca2b9106390198c +29a00864108cdcc1984a8bab53919028c01b26ecc7925e38cbe6cca8978e +e21c2b06e7b3e48fba978e2a7d186e563c088f84aa23178b60e4729ee87d +67b1091f3b6973676c1cbfe6530eb773c62e2c2497014ab0e8b71a1f4e86 +a378aa26591511bee3cf3d64c94848582e1354e1605b6457823f2c5e640a +d3802946bb2e7e8e594e8c04b430c2385dd40746ce8534f50842e74d7115 +f3db0c72d1c9c607c6573b094aeb73b7a79876cffc3e2f8c9feaaa07d3bf +ce05b61f7749a8793be90ccceca2d7077f25e899d3331fe161a7e86c8424 +95d584c6e4a0880b2951d8a13b88c4672080a0b1be36bf47c3ace7288cfe +41a8c1baa6f0814a947fbd6b3aa72b6c73a8c578ca51ccc96f2352316c46 +7bb960e981f2b6485bfb44b577e71efda16e7405954bc7c9f0759f5a9f1e +bcd2fa9cc9648d5831a68887f41b15081a204c24b4b992a231def9e698d4 +c3a25b6f5474f5be6a601f2d337a58a0d21ff37fd91eb86d1d738893a03a +69f0cd743f611cdffe69db2c6ed0e4611d56f803bb0dc06e7fe85a303839 +612707647b1be9faf8d684122ca9e5cb8bde2936d3f4ff254d31529d7538 +bbd4d35539489f9e7316f24214b996bcdcf1818e749a71cf0e8845aa1e2a +58aa62a48e02ba4564625d20aa220ee719608521d7d7a7fca0bd8904a401 +9819d371f3f59d46c1354e5fc1a6e5f79b20cf4aca2bf0f2de73da193a6f +9acbfe0b4731c4bcebe6d96fe822965de965232282a3a130361f188b3aab +da95a8a2790d9240be008b6a6de4bbfcada05b6786b9bb8e0dfa0c30043a +3b07ed46277e07b9808422c8ed16758b9c396f4ea929d769785b2c9568e5 +70a83b989b25ce200f1727d41e2b702e7f88f1784f4c83fa60a74eb26b2d +a95126e508ed519a61cc151db6804f61826c5f86d8fa89d06e526fed97a0 +db88edb432ff32c1acc9b622eedf601081af7b963c9cfc1d13e4a9c74fea +0a1c8e3d8653cd92a944d4ca6b0d306619afd503506d77732d6514f604be +4610c2560931bde0b40939bc1d126b0e97f72ae1b4a9252123b54f7a27e0 +cfa4425b4546526fd741ca77952b10d13e0ac2e32006a903808ff0cd013f +936238c74cc75fd915244c56a8412f37f0134840347699508d6f3d7f3203 +a25b7c70100719582cd588590ee34b3ab13e255b613a6d00386a0104cc5e +d2c646f09a88888d3751651d5646c5227a3c80e8da1b0a331121dd2429f1 +f4775d30564dff47d01bbe2c6c72ce4d1fd9a2077c04d2b0274b8916f6a9 +d1a4a6964a534f47cf241d5a8e34b23f85be9acffc2fea961f277539f215 +f8728d6788f67beaf45502839bcf23d8763c3949352f00c579a9a4fc408e +c625e310dae61512dfe6844e82d36a2f81709e1f05b38ae9c222ed62c961 +ee63593ced7aaf73ce2ed3667740c77b309b93eefe1b4ba65d48575a66be +86743dc9e5d3c2ff418d11f7f211b86e827ee1dfc3613e7498030f070505 +24536d1f8a94ddb6698be7b963c55cb3f74b676cd815a7b3df4b1a0ea2be +1b0b9a11ffbfd5b1fa49668aee14629316af436a0821c20beef7b3480847 +934a99f6d85b68f4ddf8859a754e009428af89a90d1852c220a607ff0806 +e8080726edc94d691d214b4521c147c4273aebddbb4a697ef16448cd9b2f +c95293305858decfd406b89b9f3fdae2ac579e80cf321ebae5701fb2f7ca +d8ed04b4a63115886d45d6120f69aef1a21d80ad3c2d35d2899f1902242b +96cd349e0aaada40f7a11282b6b52bdd97708e58dc5e2d22d1153e5fa3f3 +b300bcdfaf98dec2f4e3c82a1c85f985735f39874f557579f422664e07cb +e19da680efb0fc82c323ec5c4644c51709ac8d674608a8043c91e6c7988d +430f10ba6ce1fc7fc0604fcd8f723895250aec36cc35b3fa14fe2a0d2409 +5dcc30b2093f2298f5f0a97676a0be66c3dc9adacfe2fc0f721a20e945af +c1096a619075d5e9a264c796ec6c90ef1aeea8dc089b44ffc13d27cb2370 +070a52d4416c53f364393e46edd7ede00799960ce6e0d57e4909e88add64 +bdd2b0ebe2d73fa6acf8b40280daa0637e705c65aabd523b8815f22f23e9 +ff81e7829c7e4bc980c9143aebe1a04dc0d253396bbb7268bd5aeea356b6 +10d5dcee03135e00ae34388251f31714a1c40e182652c48cda2211a22cb6 +f02490e69a44cecb169754c53b16028d352e0119f5d5fae0bd7ea1cda647 +12a6147374b64244e21e9ec9f0d1381ad22d5b6212b26c3f9aa5f6045f25 +dd9f5eb4489ea39b1945331ac70510c5752557de21d0a6cfc1eb10a98fa8 +67b76da6e4249469f591fd154d39e89364a43db007aa0d7a911cfae6ce2b +557997fbc44f55a27f622bd7b8b10ec9f5d10f2649a646fd964ae1b111b3 +5b46a252c4dee44e7426eb5739f24e8a390694597db3a1fe7800c97e5955 +8322f0e49a0cce2ad94b1e2d1026afa771723e3f523916f55ed866c9fb4a +2f759651c613a2cff362028cdf9d38f05d4c7c6024c533e930b64b099fb1 +af04b01f5fb9ca6867e6eff55a772c5391831059987e10cbf987e3f378e0 +1329f73d54dc0484177d3c3c06f67397955ff1ca4ef8ad1606b70455255d +631a7d6eb92bfdba14a0ff28b2ace7e81ad666ea9b3a0f5a6ba3b5dfe350 +44fa4b3d8ed956009c60e98cc132f2e84967f4a98a67b336d5ee7caf7dd1 +f74d1fa08619941361fa7312cf225d89cef97e864c8369eafab94d97f056 +5505d825972b754f6729596eea91210b75dd8f645382ace36de60819a02b +3b48dd00f5485f9264f9fa926d732e2c267b0be8ca98526f124f97efdb86 +132c5ef16b103908172fc51f286ffe45ff253512e0033f037ff182ba536a +9eb2df2d1db257d9c86c46e1b002fb32ac70ca9462e6eb48994752cebce3 +9f08abd4f4b0889283e55500702185a841e328 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark diff --git a/fonts/Courier-Bold b/fonts/Courier-Bold new file mode 100644 index 000000000..b9f5f82ef --- /dev/null +++ b/fonts/Courier-Bold @@ -0,0 +1,1652 @@ +%!PS-AdobeFont-1.0: Courier-Bold 1.05 +%%CreationDate: Wed Dec 22 1999 +% Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development +% (URW)++,Copyright 1999 by (URW)++ Design & Development +% See the file COPYING (GNU General Public License) for license conditions. +% As a special exception, permission is granted to include this font +% program in a Postscript or PDF file that consists of a document that +% contains text to be displayed or printed using this font, regardless +% of the conditions or license applying to the document itself. +12 dict begin +/FontInfo 10 dict dup begin +/version (1.05) readonly def +/Notice ((URW)++,Copyright 1999 by (URW)++ Design & Development. See the file COPYING (GNU General Public License) for license conditions. As a special exception, permission is granted to include this font program in a Postscript or PDF file that consists of a document that contains text to be displayed or printed using this font, regardless of the conditions or license applying to the document itself.) readonly def +/Copyright (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development) readonly def +/FullName (Courier Bold) readonly def +/FamilyName (Courier) readonly def +/Weight (Bold) readonly def +/ItalicAngle 0.0 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/FontName /Courier-Bold def +/PaintType 0 def +/WMode 0 def +/FontBBox {-43 -278 681 871} readonly def +/FontType 1 def +/FontMatrix [0.001 0.0 0.0 0.001 0.0 0.0] readonly def +/Encoding StandardEncoding def +/UniqueID 5020946 def +currentdict end +currentfile eexec +e98d09d760a3c22cf119f9dc699a22c35b5b35ed6aa23593c76d54cabb5e +942bf7d6dd84f1664b89699c74b472de9f8e6df925f6c4f204e9f1c639b4 +dba988ed2ac419ff2b2bde605b8ee3264edd66412d4f21c64ac522bdfc7c +5502f9c3f3e5592b3b2093d33c9bfaedd2d49e89aabaa832e23f062e91a2 +5032519d1868816e44b4e0747795003d7930299d6e1e2a5bfe0d595dc97e +140989ce81d8d7f852ff9cdc7a1b1b598c69131dee005b415805a16d8a12 +3e6a2153daae5ac3449a45325631b26884c3dba4cc4f3aee0dad2907757c +38746c947e2279cf35bf77cb28bda80e2a1ad4b7a8760262b6922d445d70 +152e2bc1747c734a8c63557dd042f7dfdf15714500691c843a6cab7d419e +81febaad7a6fc0a5d78bf6cca52de83b6b9f297caaadf2318311eabb9d4f +b4904e2037862be8eef5101f8723cb1f0e5a1d822d32210c6c742311d9c4 +5c5ab9c69dd641bf3b15ec3cd3f7bbd331caa9324279943c53fe43dba9bf +08b854f97c47c79b6c241fa72fc1b6b667ee8c41a4e49e903110ff9aefb7 +5e10e007be387d5641c74ec987aef698b77eb9de14aada1850e45b854a2a +5c1d9446910aa12bb3612a19b2bde6dca1f480b787ed5ff230ff40c3e1aa +0c0b7a26ec3507d303403057d4b029565a0d0e0f8a3171aa88fb796e21d3 +f94cefd66479640c3bb43d915bfa3af6f3916f2aaae39dd4317563c226e3 +61ee0dcd828f688724bfb2a5ffadd07d1049440df6068a7d75caf8b11bf4 +d52c71c4bc22856d50956b3b892e2435d0d826801540d2b89383e14dd586 +03ebd7ead33174da5f0cd69391c18c79cee94a2f66bc5d3251a8ab9725f0 +196c6cda25a23e260eac31c9e8589fa4c03a4a98e41c2d53f2a0139f29f8 +b72f59fd64170f0271c2cfe03b618252daec5cb272e0db98566c34a6e93c +421b92eaf5552d4ec6d08432407d44468b5c5aef4dd72ba63e738eca67bf +bf4bff93864e589f73bc24737c044bba551a41c94ed39cef3f9292dd8b9e +5fab031e7b392f802611b72aaa6a0cf1dbb35482650bdefa7ae93b4bd621 +0b8b429e9a5e53d1c1c1e4306f83ca3660abfb71018b1dd39ad40f821f88 +6fb4496e31dac11cdee15ada9fa87468c4a4e9840d9d4f5ee6cef4ca0722 +38452546db208efc3ce27356df02f47b22c92eab5b6d69870502c2214d01 +4d6c3d6e4595795b2fefec32348dabf6da6ce51a95c73b4008f0487abc25 +b2d9c6f82a9042d07cf523663083de6aa22a99e11f21127b9c618240f2af +8e4f5297effb39182faa66e1e357891bfc37df032792d3c7de5a16f43940 +71bb4c54afa190c5b3fb36e7a809c6b65e03f1f1d6db9e485e0dc5a90d60 +9425a985fba03731a0fa9297b4dd5359f8e7ca7146a6eeade722b025d10b +9fcc045b2e8afac2990da3a112217f9f10866856d9ce093f659ce5eb1066 +36de5a60831a6103a50105c562bd6612c741d529c5c10f6f3e230253164c +6f65de8b784a9d6a848939ad7580ff0e077ebae7e92450a25490e0a100ad +eac5225ef45f9a69da534dd649cabf392010cfd8b1dfac4fc1da6fd8ec70 +82c97b30acdc76cb55352057d6893081e9be58c33dab65c69e1aaf0f0da2 +0c3f4013056832a6b0a96f888719e9c6f899b491dc190f74896a4417b9f6 +6703de1fa0ccc70882bf613bd9e362de9f9085c5bf5d8edf64b9f77dce25 +33f64ec53c6d7dce54ae812c0426f70268229bf8f3dc54d583f1605d4e95 +10d2452aacf63bfcb630d796357c6a3bd7ab83a4c661e8e1b63d0b014b3d +1bd1712e1fbdcc739ebbf35b81e2b32d0517eca9adaa1c504fac1d374b5b +97c6a8adc41eaf81ef6581c6a8522c2cd145be35c8758391abefb4504e5a +85858019428dc2fb59d25c95792da6bf1c6e0dd74fba9dd74ddebd475e71 +e625f9db53600369c23f69fcff80ff39767bcd55d308291d32a0697175e1 +1750ce440e80fac6526465a5814897382ee44fac82aedf8e3b035dd4ab9f +fec2f70e9f744fbe8041d456e3b8f7b12af06bbeae2dc2419871bb8c7cc1 +3edffee6b27e517147c9849d74c89f5dcae2cc2b9330891078393906217c +2ae704845ee7e519052da05798d73988d2c77ee471d72fb10def97e1353c +ef2633e1855a2ef29c3848d170590443793248b8b84ee36a33c307fee7e8 +e4c02897557062e32da79c001050f22e9c9e8acafb45d7afff506cf43357 +aa85a689d62942b7cd3910f4538f9a5c52b9614639ee4d72389630091f30 +f85e275d4f08f395887ce66ccdb6e380a93b0519e271339b1c993b74e760 +42fd697b818baf83ae980eaf3ae0b8065557aeff5178d73e25e8b728e94e +dac70539048fb10e6c7304978eadc4a5d3090a3837fc31b03fbb96d7ed4a +e3c0948b27c0122c7fa4d6c8095296c3162eddea27a9997e75237691555a +8a575e542e2d40dc1e20f66bf28c3b09bc1d4612b97310630d01c326d8c7 +2efeebec8dc24fdeb0b8d5c9945385a47543e6c4960a02aacf0cf5b01f8a +66c7cafef4b88111ee5c79a76b0c949c0391e2c870b30f3a59ce06c52f95 +f6eb7e5aeec243c01b50d159a1b817dda7f6de559e13d63196e81e753264 +2e0834f9b13dd10ca06a91943b36afdbd7a4a26181dfed9cc73752982ecf +c5bca1513cee9710990be028151445f2e2057457a2baf7e7b321885fd591 +cf4281992533ae0e4d4fdcbbce6539a4f26f4ef00e06d57884c77a9003c2 +16c0b65c04da36d68cc569edc075eadf9d7079e0f7485f32e0e54627db15 +39d4493a5fbbbec8ee69ec7f852822c51584a2f52c77bbba6752ceef68f7 +497f61e4a2aae33e5a630c0674bb6dc4c31d58e12d3f95cd3383d49b7bac +e7a13694f8ff6ab5a7a683a94e9804c20bfe70740f600e2c5af0ab835c73 +a55f7f681d4292e57cf66198f1f3af82cf336c331f091a85796a72943a13 +0c3466b4229d4800d7f60f439a327f32afd0fcbe141f653dca1c3bffdb05 +509ecf1e419d045c56ac3a90f52700763b9309d2e86e0ad21a368d84ef4c +077899ee5cf201365d3d90de7091ffab2252869ede93fcce320c47fdfab2 +311285d5b263140089a9b382f33ca61bc587a57d906c5db91e7a675898ee +240eaede53b28bbac103e0c76df8b12c62a3937fc1aea81ffc30d69793b4 +6bbf32e1f05f540e2af2d7d54a77ef02ba9e5133c2ea31d78b041a1ba75c +2d6a7ae1a2352b6101347851164360f1451db5e3e91fea53000210505cc0 +221c7c5190a436ac8b81e9a40ee834cd0fde045b0d46aaa4693df0370a98 +04ae7643d1de813cfd75cb785884d68687e8849422504e4a4f014ce400da +6c65eebc9d9886dbe502ccef99a7088fe363a185bb75f70b022311917c2a +63e2e41f3e9542cf2e4b35a7b42e2503d6725e7139c1cfa31c3c54c8420b +0ff0e17d2f52b84216ab127e7c10e058ce02192aed9157198dd471f401d2 +2ad5efcc80c26a76f1babb2e40a4b8257ffc80a71e61cb8db7ba3fe036b6 +a70a9d58fd59bcc1696fba1668191f45835f703175c2cc58a5f190a1c7eb +8e481b9a7d0d52b907b266a3041d20617c2c980809386de78261b9cc8c95 +188ed585256db375d9c16150d181e2f6365a6384d6f05d13d485f287c45a +0fffee0c8147f02b65128c59f7d34973c6d5598dbc3d3bdd3614aa4d28f3 +3181ef9aa67b791a884ae0fb62437ecd42d1766f45dba8239f7b220558a8 +94548653cf8009e774ca4fc93237ee9a79ec3f58870313a0f8ab0c9984a3 +d00ceba8dbf3dff581753f75c4baba662175c52e5313e68533c26ac08da9 +888699ce6d34e311f71724e39b6b7e7092ff901b94257831d83921875794 +cfb5c62c42b8b0b2975aaf8854373f9718877da7a9bbb3dd0279a2bfeae3 +55e68a113859646560131d7e8ecbea885694acb6501713ab38b1c20d59f9 +0b8325e2c9e1792ea3ccc740d18e89d54fa6327ec913e4094304b197ff22 +80c6a3169ac17909a5bb002ac783d567d51da8b77ba223982c816bae1ece +bbb77f871a2d205d8a1e74082afedf6b662fb4159326da561465d1848fcb +7fdb8a0b33723525184e1069987c23e4c41ae224a0e4a338fd33d9f4eb5d +718d237af05bea5d867f3b16472aa34e9f705b5463a09154dfbc633d3ecf +a46b9986361bbdd5bcd3a8e94880555efc481985d6dc64c77d05ed0aa826 +490a079ae4d1ee011ef86bd83f7f9e65433a48dbf124f15ac3da0d5faa6c +6daac1c4feb7db8b844307160e2281ff7a2d2bc6add43b354454d349a334 +141b4b1e29536e88f289e5448e5b26813ce07432632b5253393f66796833 +2387a1bccb98503f43ab4cc90b12e10f8d7c6435aacd62fc8ef32fb37d13 +fa0b0ff18ae20a6f2f2fd6394d55a8faff09ff91abc226412b0051c282b4 +b49c558ab001d2496dbab68e6653dbb74d210302a78457eb26ecafcbec89 +6fa58f0448387d17608d7a2313c222b413d3f32ed29b683d9dec7927fd93 +a8cb0da06b2e17940d195f7cafc6e5edcb31a8e00187900312ee9bb10205 +6c15ea233e2d43b7c6abbde44ddad3a1f2cbcd730eb5be1f3691aaaf2efe +94a4736e6c4c753afbe1c005149918a4e5446b31ce005a99d64125c9601c +b016a54d3241ab21eeb505c4f1cff6178366b3cbc0cbca2772db7d5b3a76 +5dc6db8b7116109f5df210a820aeae41636745344d07cf9ae1ab05a564a6 +a9c5eed8130780e93e0fcb2df9ee1b8587d8facbdc4e1927315df3a8816c +955f19417bf508ae0524cd04ac53af19619cd938495e4c7f02c26b69a091 +f2f9815e4f8e3b95a610c3ba14a6d7724b88392e6b5edb8e9c333e262ed6 +82f249e9df395b94e7db994369ebf559103f9bde51eaabde3854ad5e6705 +1fbba7eae4d5968d82538732d640739e1f09d5c0d3d6196b7f39990aee1a +43cfe9872ef0e98bcb8de9377416255ff057188d9f157313cd650451faac +8a1fae3d00814a6aa4adc548177998cba4d0f1fbb0c7f6b3773260e6001c +76b681675f5ec4884a166db439eb25f5d5f59a7124f0b2ed99160e3e779c +b63ae2a7f118e90b180b45d097bfdc0bc95bc790fc8d7b32266b2fe22f76 +87502d6da4e351a7778cbccd31b3c83250c3d21b0151b77a05792ab50a5f +635b2d932c312eab4b1c06bdff13cc6068e141b03ee8d8638e57d59ca1d8 +b8ccadeac057ceff070ff7fd2765b08576774c3ff51d885aa8694e14dc5b +ff792430d9298b474e0e1cdbbd4b092341fbda48d12dbfd98bc237e1aff1 +8dfa7935261b40906e20738bfdca16b5842e2a1405b22e4990020448bc4b +930912e4bec58028d9d86e7e15a64cfe183a94f81e2088ffdcdf5326bd86 +83b303ee08450941ba40646585043d863dd7d4cf0b74e6fcf96976dfef5d +2616577636a468eaa1f41bae3d82f70160d02b28b318aaa9bb74567460a8 +cd4306667786f6967f39bdb9f210b5a8068e167b6ee194b0ffc9492ec4ef +e96625fd470039a59551b282844c561b26851b9af6b3f3a6fe9aef52d42a +81265004bb64dad894a7d6d0436729330762585664e8e78e4cfbf809919b +ae3e4ec70b61444f8e68af00a419ebb7b5aaf66866a7dbe06a5106e9e63f +6f19b0417abf32ab22b02bcf0c27af0e898533115fae686eafca9628bad2 +6318f254dd54e876736cebce827de16fd34f2df6afc7a9f39f5ac50164b5 +0013f26dda832d091ee0f772d9199d315ebf589507658cd7fcf22989718f +2c31ecc18209d32bea2b29bd1a88202a7fbbcdca2023c79d07b886b675b0 +cf820450d6599af701c1f23ac1ab264d9c62352a2cf2db6885ab1b771aa2 +f2d037833454d0c6e6ab9e7884bad12959f9d693583432515e9c4e8e1785 +1f292b5859762dc093fac6d1c4d75f83e6c47cf73b5fe390a161ef0a2942 +640e8683c33cbee292aae8cbce89e2c1e8dc99dd4bcc9a511a7f00455381 +9d85c390eacc9596e67103cce2c2e86a4db07462396620c11b6e391652bb +358f82401a7b47fc5693b898df7eb1f7a7df06be166864b82498e7a4a52e +5d78e2b4e379cce4ef1aeddf8093671378edb46ab0f1aa7b79fa1c0e0a12 +4711cae6fbe2b56a74010ee3696d112969b81f3aecf99bab36fa9317fd9a +2e590a8d1cc447cd24c42995d7b04454a8fde2e589252027392343a11785 +780ade0b3eeb8bb20b63d1bd61be223c44bb8e1353d0d3e37c122aeabe22 +45fb231783396f758c9e4d09058b8f63937468b8648c2764a90b5785a729 +1600ea0699edde3fce774c77a4e8388cb3ae99570ecbd9811ee8f973a6dc +ed78343d1104f0a10a9bc869ea473da3005d36865d01598e1a6909b711c3 +77a4b4bc536a581655a1b2c2b995e6632434cfa8ef7a794a0e808e6b53d2 +ce9831c720ca03f28c7f0753aae26f5d6a6cb086ea57c92589e9583aa6bc +3c119436870043247073287061f44efd734ae7102c9a090907e3b61b9dd2 +527cabc63f2f8515e3f8ec022ad88c6844a731d163af292c8f30ec988735 +8f197190cc6933745070799581b7a94f0eac5c9356799ea0f201bd54d1b7 +2aa0f4a50b2851d69e6a2642b762a88870319a684e9eaa9a1b064a3bd2e1 +1ad4dcdf3a977257b6ad3683d4e9f4f678efe74d4a4488274ed980ee6efc +072708b5358a1da39464757670c3a12f2bcb2505d8bcb8d46ae5a8c88b9f +1754896d8d7eea8b1d76d8e7dedb88d67f796f76c96b2eb6e0e7a8d10cdd +d649ff25850fa3834852623e99f264a8daa93ed145f1b6512a75a3ee49d0 +ebf73f90eb6bc75ecc057465af931b300389073f54e5e0a5e1340670393b +8333548fb4c94404b16d0813a8481425e9ad09be5d8a4f3eec6239f7b141 +a03b428d45b6e3c981c3ee32a065f2d162e25b6bb79e9d46e1838aa510df +9d8c71f3dee637a97c453c0c26ea8af68e3c004c8de997a6f5a0e2713af2 +7d8f98031233c6bf5ef5c103e5af0862ce6ea9d598abbd08350b18d9ea84 +738d7565cfcfec7f9743b5de7e9de5495555390b0ad89ce01a5a05d6c53a +235aa3d89cf329b2f4350b0d98da4d4973cb5954c6d639ce367e68776d5b +a8df9e793c52f381570e909db6121be93919c354722827fbc24aeff4bc70 +fcfc4fb7f49759a6cf27dd5f54efdfd060abdc33d0d1f8ce051c0c026e31 +17309e09471b463deacd1cd12a345fe382b8ac4ecca1feca0814a4f74bde +a00d08e65288b8d05dd0c6d8b2a323c545e646ac06e52f5bfe40e25a7604 +fb2bf49b2bf6527cc4f1fa7dbc9e6edcc63a3e5bd951a25eb13ff3bd2446 +c8ed32670a19f7d1706994fad9bb9ff448668951ca02edbd950b8233005b +aff1768a1cc2a44da8e0125e637a6bcb51bb64af227f6a3f7c7ebe4efa39 +5965d49b13b8aa5f1d41fae2904d82092c6c2588b38182891a39d72f1eb2 +50827963d6ce5dc80493b3ababb911189a6b73ec0a74d9de15f0dd992fe1 +1ade383677d02792a720b83ea21ab3c631c9f7058e69749306a4095eafbd +82b8df219e53243f7cf2efb3c67e169f766302a2084d6ab6dacbdd12a67c +a369aaa02d22621481c03a8d43763d62d2be3262d1afba823cfda91992ec +f80cdd3656505c5399118ca13502d03b122c20a2bbbf80aa6642773a6255 +5fb7cee5debbae611eb2d443f2edc24bb153dc634cb6d6b3724972445ba3 +adf97ab075af2a95d2f1bb74cfb2db1e435130296cee19bb8c157eb8db70 +bf5cfc1e791f3531d3ae33554a4edf16070a731bc8b7c74a84bb3be0f2bf +45560cda74b4c12dd718c62803fb4f4aba5fe89d6f7cbaafcfe4bb518031 +dacdea2ae6c8d0c03bf60a9b060ccebb4858e4cfe1271e316bf7afb05714 +c26cfa91bd96d0622da31ed625533b2502064eec23257b4785f4f0132f3f +44b0c2b83bb642dd8852ee7f3777956e984735f5d16175c4a27e9282a4e4 +ff0cab7938d921d33dc7e8b62ae24a90b12646b3a5fe88fd944d8309411f +6eb3031abb67fc9bb2889aec45821020561c1519243773b448d65bbdadc1 +5a5e155b8d1b368cbd97b756a8952b428a358c398630b46e8afdae238593 +c3fd589ec46b77b8d82ec7e1ec5a50cbc77ed54bc1e2426c61d23a08581e +c1d71c0908f7759d1da9241b087618e9f756bfb86023daf9a7ca0c4eff0d +45aa95cfde5aac1977911ec6b202bb47547e3b5bf3327e95f7e1a4863e5b +904af4b37a527e34282cb659a22f85ba406bccbe3070ea53f65a876b9d1b +9a1096412fef8706be743153d4dcac1681a40a2c265a729121f2d3fc9efe +0b5c18e002626f3023a5ea705b47ce1a5c537122e7c35af7bf31f66d05e1 +aa3362e68c1d259fcacd0079fca7ef501654744e294e6818ca3badcbaeb8 +8d44319fba9042e25a8250599a8eed5e1c0cbd9f739b7db31c3b18128176 +50e72c970d3090f8325e5ca01fc85e5310787db8dba0ca26d77f403c062a +647f9f998246f26422374859de43542076b459b7fa829d27182324262532 +99fd3886ac0448ba12726ccab47af3cdc60fb69dda6513c83e0d1277ab88 +4d45ff3976536a13adf80939cf1a1db0a6347f9a4f76ac2674ad49a46ef1 +d47ee4fa717c493131e0a5212c3d4ba134a7a6ccaff9982abe9f792a9179 +87e59dcd1984b5994c8c89b3f9f0878cc3177489a3b9b41e44673bb253ec +deb2083f4293ed9d24223cbfef26cce564499158482912879082806d048f +1ea999ab3cb216a5c27d6027468b8aff4b55fb319fded4ee2d308c0f8c96 +fb7feca02b7188bac0ddd4bee03a577e91d258eabad887be25e74c296f63 +bfda0da6709aa66b814189443c8b942be557f260606e0e2c5c0822ad4a5b +33facd2b90ac826a768ccc37d2591dd28f1e016032bae587b12849d2f9e5 +60e3f8c07cc50f256ff209c9cfb36cf921713e79cf02283e14e52cdc3ada +d81e2d2adbfa6f1a2c2ca81cf97fb68d61f8c51f8c2d70c59a940dbc31a1 +c0401d41b9c1e5906e6f9d2d4446da96d36a0d4cc8977e665aae5c431657 +39b2226ba59807a4e54fe9901d9e3dfaf531ef2b29398d2d10c24fd2529c +474469ca0fc17c2c06f670348545826112e834654bec7f039d11990dc823 +c479caf0b9ff71f983457be488a36a54d9dce40b832882eef4b698bb1758 +5ab2c981b5b42d99a546a9c50b56227e76786dbcc6a5728009a707a5c8c3 +9f65bc6d10474296a93833fee38992deda4cee623ab3e672737be803e984 +2003e729a97cffa1a122d9ab0bfa587da67ba7005f51278e3a06a752f86d +5a8b2f0d7a871ea29a2c3b7260fb62017aa44a696d3c4566b179c9eef15b +67ed2961683b8417500b6136815823d50eb25f68363adcdde84ab6560227 +69e776795bd5a97122755091c2353598b5e0e5ab0d368fa34cc903993089 +a4fb5539f5da5c59babcf26470065e6fb8df09ef54475a3651550331faf5 +093f96cee0b9c0e94a894acd650d429672e1d66ad6a0027b7d24e1df6bb5 +6e9092928508f4e356275f668ea61dfacc1bd86fe40d9629b8ea84e4c337 +88ce61a3fbdef32603ed42a31c12817dfd57561a1ca265fa093b5942881c +2a61d2c536bb7d6941879ef6371e1aca84fbeddfd0712f6bfbdd69020265 +aa13bfc463e3fe44558fbd405c69db3cbf18b5ace6a111767f766b8a730d +8b0705cd5e46544446ff78213f9b2844076110f1717cfefbbfef27c2c17e +19bd949688b30f0b4f3f23208331fe6e384d4b4f9bf47290f5941df19888 +f78271ed4545b076b96b4e21fd07ca410186f4cb4d723f1ed2cc6c172819 +c346f547e74f99c1cf2bdef1df01afd3fad2381035d516d1f02c650105e8 +092702a8becd50cc295803140ed1ead5bd6fe180816cce1608a582787ff1 +bd66a511b044ad430b97227b61a4177e90f928dcf9c2db0521163be22b5f +faf3300ac9c039aa436df8654eabb946f64b6a2c4e5b8cc7fa9c11d2cb20 +9b20b92c6e77ab808d474af0041eb80f0b6e635a5f322dd58e1194676999 +2a8e58791e2a08bb0dcda337e882ee421947382a10676c69404e420f3dca +b6b6cba7bbbd806848fc80ca03eb3a6fdfdf5ebe800f17729f74d72f4e6c +dd5ddddb891b3690554c04694d39e05f5e2a1dec0100cdc8f2fa39486353 +37d906db314a739f6ddbb748d048e59759c0e5bb93ed6f8313d3aeabf523 +545691769560b501f46f622962be61881ec339ecc24ef0d5a3a66a03d31c +48be641406539cf845c3dcf4d8adab1ccf6ea04a642644dbe77ccfff9e9c +e5546eeca7b5d11959dc32a1c09f9e499346b2ebf36c91554ee265da452d +7b6479c7cb2474113d050fcec2b826a1b6103a1fdb4aed700586aa0b36ad +df8fdfb4006beec2b075cdb86ad3bb56adde2e7063a3996dbb6b763c034e +77ba04142e741592191eab60df5e6913ba69ad04963cce6efad86f260d9a +ae0959be0496413c5299ba27f0c96dffbf5a20135a828dfa5bd116f1aef4 +075d1c4ba49eb90105bf16686869e6da641e3c2bb4b4deb164817616ba7b +e9f1062f85384c1475185b342f8d10ce389b82e97803700e5090007d7521 +68bee8e937971e94c01cdea21364c05b37f60b86429005750c6d5272296f +9c3be508d85078c98ed33cbff0411cfc16ee632034fce12ea9c060ec7a12 +f843c69f62779c779a1b514a2808f54572756bb8aa743312bfcb0130a6ac +0d4c21f790369847adecf452ba675bf9b863bae1e494bfe82a76ba37e951 +7e5ac3418b7f817056fd84906a296c794f77fb8e266ab32f1fb546c9e97e +435588b749c3d279995886f136b2515acf4dd303647a13f142b70652f7e1 +b587873fb85dbfb6b8c0eff6d40cea9a4c735a7e0a796b3892a40f6cef4b +bf8f98c14811e2b5f72c20fd2d8d13acdd45728be6efd29abdca3774844e +1e1c85291a52ccd541d1842fe987dcfae7aea6b546be6508baac4d1e1f88 +c3772f632197600522e10a08771012b39fd2be0dcd415cd93e59c6ee91a1 +3000355b9234cc603033dd74577297100892fb8c7745df45d125034fb268 +4bd4d46476e437656370e13537114b23575da9ab9c57cd0e7c43865049c3 +fbea9b2ad3587da4b5b021384115867408666c11c1bc7e345af1dd4a2593 +b76335451f57fc0621e2712fa23112c4ecfcaf3cdc5871d392fc2b3f09ed +b5b87105b6de4bf26548925cbf4595bb072429b347586bfa436c10d254e4 +cd1542adc1f72c0a15ee0eb3e21de33ed4192fbce905d16fba1202e45c00 +7bd1ba5a5bf4f456a40d22d0326f3fa5f57fe5335f7bd2d74c3c62f33d1b +2fb3c3754928f3bbb73396d1e64fc4f9cbf1a57bd2513014c4b49ff68be4 +162d8173ad1425afdf02a2aa32003db6103861c935e54655ed11aefdf7fe +421d3e46c2324d0940a6dfd0667dc4c483be82abf8e5eddbde02f5b1a11b +1ec4f2201ca9fda9077aa5be2a637baae83a18e0d07aca462fe53fab3248 +4c4d7929f830b6efd789b22311b6141aa20792c29698c0c0c9683827874c +80b97e6c8fafc623f8e2776f34356a32c0e7613ebf491bcfaaadc476ec2e +b904c52e3a65d61fcf4d3baaf68dd8a2df3b6b9958ad606dbc16653b1304 +f03bac8ee4993492879393dec1c3b9930f0edcba5542c22af1aa4d754f65 +3dc8e4f76a9298e0ae859c6c13f8ab24b3349c0abecec29e895516859d5e +276c73fc3804d194ec154caa7fb3803809c6d669d86cb75a0109a25fd481 +24be0f89ccd2479961fa11144db0d626e32fee84aafe9ff793254c2c28cc +3208e4c13bf3feef165de8433cd6300fc97ed20e0b482efa38267e0c19a8 +02a795c602a0f34d3274dedfc3928949f16dd15b811f61d682ff303c0be3 +c9b142e434897e2c25c96b9b313b4642e6295881a5a2660dae267240e8fd +e3a4b58dfaa10caa5de3a730486727a40307b4470b94624512485ceecda1 +9c9d9ebb68825297aca37aa3e5bec4c497b35dc10e86bbb932d5e6a03f95 +0bf45cb19a9f5cf7234f897e163491d733b5510790eb101855b42d82d233 +de4656e4ccc15c70d3c19a367c7e8cd97712520831ff302e59c66bd66081 +92c29b17f125876a4d00f8404c745f36b87abaafb41b20854b8a71417a45 +be9a6d9dff71ac4935e79d30e6657e777bff19363d6c588829af564b1b27 +784bf9c5169817ed2183b0cbd4be72575dd484bf6dc8a9234f54bf079d59 +d5b82796cee38efdbc30d9f39d0f500582f25a729a1f86021ddc17e00174 +d842d05f21c4d6f5d0777c99fd99f5bd7aeb4a8f8997b6aea54a3c336c8e +68585ab5f654648ef3056012f35bd4b322897777806026a0d405f0eaab93 +61d8d6754f1b660eee091695f39b8fa5f6fba1d55b33381a567447906bde +e9892b2bf755353f893cd9d912bb8ccf1e0d30cca1c6f2d3ff552f56ac75 +c3c6e892282910da2df650723f375a68dc9eb64ca74a512741c4a652b223 +db2d25ca29d272ed2419944c2f33769926d69f291d2a462d105c53dee439 +9172c11aa0763d48401552ecbd9c8babe6b4da26e7f9623355e430768284 +fa9b53667ab67b06216c05ee54165892d5cc4435a0e5fe3db1690b8c7043 +26def9e9e31a659ae206f8c60cfd663f91688581a0179c9b7b9dab97e1bf +5f24fda6ed339433afb20839458d18bed5491be9fb118bcd3361cdcf03dd +f67d11767f7f7a421346dacf711d375bf519fc93753331e1a091fdf603ca +b41f0e6c48e100e78157e07eb10b30c6f350a146cec0d3d1d0e944a69e85 +2092909fa54f1b4377ad4768fbebdf5334c8f1e326ecb154ee06858342a2 +6f3b58a9e0141d57c20df8c4766be3203ced1e6b24fa2a98bca391b85b7f +572d49ac38e4482733726f56d5ef42d3c952db9db82d9129dcc30b4b2fcd +d20fca70364907701bd19028622a3aed72569cd8307e23e48e6a9df04da2 +4bc0460cf88b75dee4379a7c003a6cba112415385c43058a46899d6302ab +560536e59c67f462528a81213d9c9009fd3975a3b601410e989efe3a68e1 +65fa0ae6dd9c0361e0626f1851077e8ed9fc4cd766291c7f3df8e51e2eb3 +b8e9274798f32e2dfa3d5a08abb61061d4caf45cc837309747df9b0d565b +34d0c04a2f9ecd64f0df422c7308ed27a7b5fb8a5e5d71c3003914643d25 +8895a0e2f136c02e5fc6659dee6c7822dac93f8e0aa4b5a52f09c2f49d7b +9a7192a22fe8efc8f5142d3791d3e11b88fa8c9afc2fc568df02c40a109a +b94e59cd467b9b0bd9f94003b21f522cb5c8b191a372ef5583e66f5217a6 +5d3c7baa1375d59bbd54dd9af7139501b74a2ba74b87db29ac78f1afa21b +81072b58cac2df329f5a7f3edd6c42839db170cbfbfc575ef172b39c1859 +87141f257d0d6d909c1a95fe10d313b8c0846b80c07ed5124adf1d36ad7a +f729dec052b2e6c61609211ee576454a86a0c2e6ca0c6c0ff1dabab49143 +8b326088d16ea1ff32e69871cd3f5a5cef3848b734ee20e2510c97c5753b +2629b9eb302c488319e384166c59257eb0454af6961b87a7569a5c82e1d9 +f1bcd84379a590b4b41166a67ecff44890c105d16f3bc899b652fe115045 +983ac7f6b7d63b5339fa99cef588f822516e135ab40fcfaee90577bd878f +92ec143bdb5fe5ffae78390ddc3f7d8361759dfb3996aa5dfd331d9ba36f +2901c65f5e4a6c95a9400d6316ad745e680cf8729f23bfe0b11b148c74b6 +0c36c2fed2eb71ec5faf4d05ae962133c1b8776d1d57bbf46fba30a15f33 +344f26dd85411b16546e1c9dd963f1b334026cdb09ab973d1fa615381847 +1cd310d73575d3e03902f0bdf0048ff5efd1beb2e857f82084b743e10091 +d3374593ba944d05ee97bf0ad7568b45a95a24f49f0ba2d93714857665ea +9ac457a90a63577f7293fcc0d5bdccdf610aa823f7db43119263fd591a20 +f3f6d2612412bfb5783db3c0865eecd1e7c2ca50d9dea0ba8a50a4a69ee6 +7899bfa6b11bc58b31c98a6b8cd63633dd6ba6e41aff7de644496942b7e8 +c33320c23f0aaa081098d555df9bf66b4af6cba3a71fc9fdb0a19497ea00 +17dfa473bff4ad6badbc6d971157ce98fe123ca2a5711ef9360feaa0f40c +6069d15b5b224f32f74965d97fd48105f43ad74d08b0b2beefbcb3d301da +be707da228e802c22734254ece98ad73c080dafa09df15b9340b84154a2d +1ba6992fed3674aa9a9e002c4d40353bdf87edb73e61318aa003ae7b388f +e9f8656fdf575e190509727d8385e50b871ccdfcd4fd1813801bfdfd7387 +48042133087e98a8c64083a4b908594dec38ac9c6efdd26f1e13cc59a203 +abd3887fff0638c51082d32a328c3aacca59e173d56d3b3bf27976c6bc95 +4572890d8092e93e35f188e2255d4c223d5d9fca45bdf433121f5f8bdbc3 +84f1c0ebef83a8ce7fa186d413d7fbde7a9d2818eee5a305a57afb635b8f +f6635f17cb030b0d29ebd19ce29cd932034a3c0c0922c7202288f2a3a13d +1bbe38506a74046dcbacf7d89a2001785f12f3d885871f9950ae34ed028a +98b5373403bc1322d1f2c583a8dc11824b4283c233c8744fd56cb20fd6bf +0ddf76fef1d0eca5a8755a2f15df0329d098033283664aefe0c59eda92bb +25e4681182e20c008c73f9c736711fdf3c5ca41acc70f320949d0a32e5bd +0bf4829de9484836c8183542f12bec32fceb5a3bfdbb1a193831cb7539fc +12f181fab95ba610379821a9a02791dba3b2f154d13788bd248d3b9469df +01bb9ffd8d69c10e347773c781559ba77f50c172e32dd77ade64202ea88f +9b22ccff86f1f221741c4c9de7ee719c223860446539488e6ecf7eec8c71 +f82b2a3b54dad191dc7972eec0a571e839c733aebe2c557beeb5a69bffa2 +64d60f3f6d1af9fae5e6da55f9b5e54e29c978a6868c02f936b89c8b11ca +876d6595861d293fe9a250e723a09716167f20c00f40a3ffab37b236cdb3 +691edafe967e72a69b87f69db6e98d32c976f9448575464c16f43666ce44 +76840b89c880acc159e7ea9623c9c49c4cae911baddaf128e4e336e41b5c +76d4df9464f7a66ac0787280f27b2ea2cc03637d6a9e2ac6d28bcada2c5d +cb425f99a0b7b7677b2b79c4f59478c1e0bfd24aef199621b2211783ccc1 +b4dc56da241203b399cfbc46a80cd1d172c25a76b55d0a070c00a17d9e22 +0019121cf06cee286d3582fa02f14b6c0ed78ae52b960f67d6d5331c4e6f +29c51a14b401714874d0dfe0fb24d264e9f705812bc67b634ad558ec2347 +35566203199dd558fe5297cf1cf5cd5492c93056c5e0a71226481fe13e5b +ba28b11394fced2131ee45efb37e12f0638352ea688cc6881bd182d9094c +88552111bf87f88ebba5ae9679354cda6c8888b172d46635220fb98495b2 +6469002cb0575a6360c4b6909672ac06f70ec588df117bea075ec89e865e +577a0def15804badb8d42ef5c6d6fb70ebfd3f49a5b218be90dacb7ab625 +353bd54e687c4617fc10a5d5010758c64ea0d6581f4f3d4fccb7b90ca9c8 +85b028d29f838a52ad11523310a83d61a73e72a9b12ee941c37906e37b5e +3f5a2aab32f410561f3682a81ccf959ec63d96b89fdf96a78ab04b236e50 +05bacc7974f7c62eeaa245ac41958ca8fea6ad3fce5339e1739a53127964 +2ceba426ee4ddaf922271152084c4cd08edef50edbfa399de4972844fba6 +8287df1a1d98783774f70ba7655a9f89d64bab11ad3b55459db4ab7663e2 +ad5dfc78bee42e887a2e76b511a159812e489159acca2f0a249a412b1ee4 +a90a46dc9ff832525a9b0913244ac3ce5993e17674d1660563c6d54d66b5 +dde6b64aa76f003ff3533a46ee56bb913b6efe0e9da6fa4e5319b607d53e +9d7d9636805cf8c3b3947bf195ea25cde547b4450a9eb8ac84146ef54d76 +93213061897bc96ed821fa57c0bda3244fe4a1eea3def679f45ef9f67e10 +b5decdd3e4bec89701f553bb4bcc6d4d1e0fb8c9090b9661196059b1bf1a +bf1be04d6b74a5cc57e40971884911f452c33b58cb04f2c6fe3e1d71bf5c +b13e7537d9fa6d65ea935ed5e96ef72363bf78322a8f87bf7a118a9deb71 +b7f246aa676cda52240974e6e9da44d622e4f2a43d7511b83a0126b2b92d +0bf1b02876e523d9d0a492b5a63d96b1f47e962ee7aca6fb9d3f9aec47ad +c522dae8aa718bc540cf5d7031a7d3d16f0f6ff33a9768290a90a5fc5e68 +95cff9dbab42a770bd11b787b5078db3de917f923c2eb6ea11e76136a8be +e36eb784788ea3e2b9d7be95e6d4243b166c494c4b754c6dd160206dbaf3 +99ae4902d3dca7424f6d1e7c455d562023465d0aa9de460b1866d7a52b5a +f74e923d2fbb49c4470a9e18497bd332f3658806ed19c6077f046c5dc0d0 +bccc1d40ddd20d1dd36627d5394f9d38159c84751b355a8e48754c6dd160 +206dbaf399ae469b9cc7bd8e3d141479a7012a045ff72d51a448fdff39d7 +8be6ffc046e5cf07644c7ed0a1b85cc2398d0f3ad542d1103d2de1f3b341 +bec7d28674961f6b7d313b85f908f24f4d18080ab2c46c61f215557c0d81 +fda6767552c20b037eb4c97e39dd51300a54cf301af3ae93dd0f958d422a +58e668e91eb14fb295d6923ffd65a2da9a88fa3fe7f9ade3d733f9eeb54a +127a12f0c791d09fb12fd026e09a8232cabec89a8ff39084fe111795518e +c8beabcb9e2949d3c58456ff16dd187bc906ed19de8f6d6a2a639e1fd66b +020c5ca8e69adeb77fc55c84ad5826b2919e09bdd99a537f5c92437aa9ad +187ece2d245d29a9a0d54ff6ec7841bbe6d39d1e06b6ce3b19ea98823e0c +31a18bc564dde218b924e38baf75299220b281cabe0c940b404dbcf54d19 +ecd6f22e99e9ecbfcd8a5e225d29d4535b20e4fb69b6662a3af13ec34c1b +58b8684aa0c7ce8d84f6e711534861328a5e4673d4bd6cd059a16abfd8e1 +573b096a3aaaea3274474fb3a97d7ffb167837a37df2bb69f4d5c31a1bc9 +0f07b0458ef6c85e51cf6163a409d01f67513c5808c5772f8502dd958987 +ed822784d7be448240dbc2c6a9fb7f6885e34e0b842667c15908ce0fb4e5 +ecb4966369ba752e6fc2f39e15caf1a41e441a27d0bd5175e8f50cb46042 +5bdb499d75ffcbaa6606e892b21400db3becbf3aa38ee38da4c333c4263d +a152f71dc4baff702ea1363a0940a5363ea9b51b1f2a71a1b9a4fdd19152 +7fed7e2516c95ebff0e7c2ce92c50399e18386ed3ee39a48b2da92501389 +cbc1f6501841e867f8b915a334a0abb7a92b2be3af10de37cba4823f932c +2779c3b008afb65ec03edcec847e412af7787f70c79ac84c58014e8d0e41 +6446b36a50c9e6175726468d9f399a1861431a8bd311ff0567723aa35fbb +650b173663ba31bff558375f740346216bffd472986ff37bee4aa3675645 +a83eabe1853aa061fb3614b78cc780a471c3c0f5da378ca90ce67f21247b +c105a3bd4e4afff439fc158b9aa90fd0e850b1508355bf0152225a2c22af +9e5dedf038f28a11a2a553128c945086e84b4a146617e905a3a16faa485d +6a5749a7067aec3d2def0aada7436fb1e185bc66d0e30a7bb33af458e605 +ec978d14b6181d8d7e9debe27751a6f5fac11594f6605cbe638d9a98ab6c +1c3f6c3125a57dc55158dba2bd4d36febe0a8590e80afcbb1340c5553a66 +8ef2d6f5b4305a9d8d38afbd5759209f9eb9cd1cee0fbece6de7ad2aaf09 +6dbe472f83389d743f0d7aadc6743f7646f7bf3a9f73a23a43f37d471a3d +6d12de84e83d2cf5b41e84f1acc0cbc4cd52d0cec7388f34ead47b45692a +4918b365eb9f6e813d9223a95fec8de3d3ed7ec85227f8217212bec21893 +053f74e652bae9299e709fd25b9bcb82e860c0c56bce1f787129628e2499 +130fe6ef76418eda7cc648d769c6f54984dea92af4776ebadbe161d180da +9e5f3d65cac4a7a40ec3a3a7c253581597b69e7526f3e10d619e614f0c2d +c4f6feba37c1952518fec11b39fbd13ddc21fdeccaaf95ca8fb8d7d6089e +1bcf9b574d9d8fe5c25a82a0b68b90f140b934eb585af7bcf8c88f9c1c1a +dd745b02a7e19db4407738a4ed928c83718005a401b77a56622b6c8dcb3b +26cb5f05ec5fba7f85b0a6a81a0d8e75880ef357d7ad551292d37c7eeabd +7220af71edf267760571cd3e39af320bbf13c9ddd8053ef41cc81e425b32 +db025cc66649055ae1c6bc468bdcd6d69d3ce334d0b78c45785dfb709ff9 +a77a46a8c660f684d61b3643b2bc838b6e983d4950ae20436173e93db372 +1721546fcea7a2439024051300067137313b2424e1627e053532bdb9caee +519e9d23ed670d2d5ef3674f225d51e1ed8e082c5fc9f5f9b934c0238cf6 +5b3dd364b466b2aeaea3d3241c59c9cbd3ebf9ea9a7dfa2eea9b7ee86f0f +7e256ced10993751286150e663580abb541147835b9f14b21f528999160d +492d9e74b01b55dab2c2e2643f5f20b0f4ec4e8a3a2df47a38fa1d36d755 +2ffb34c1d4c8152e29b7235508e01f79d41e1f2dba807e4cf4a5fc87aef5 +98ec07f4321a2c17dbcb23748bba86a2acdae6b93086a2e26d52b0a10f83 +ff41cd291ad0471f09e62a79bb75e18e680be66da6f3b2a56a8f61cdc1df +9c7fadd0814370dd82648db161d85f8b2a9a0e51deba297a1250deca1af6 +944d89b7fba2f313ef3d61757dfb7c2801778f393b2383989f16176eee1a +695f967efe7e04ee79ed936aa121ab47afc0f0809911a290a0fcafd2b0fb +6cfc059ed1b7f70513a49410232413c1dcb607a668cc18043762ef224dcd +d7b5d6211ac228650e4607367d4fb15959b8126dec175061a3ca7f7b01db +2dd72dfb56756ece79fa61a7c845336ac412bda4347c582a6f5e25c9cecb +66b6d028528f61f0b77f1bc603d20dc104c9462fcdeb290a5bf9633fe6a2 +92b52098f8503bed17548c05d836543f7329dcddb5cad7f89bf26ddefeb4 +912d2c1b3bd40f92aab21ae60fe8c375b960f99e499ae14cb92a5ddab808 +7ef4d41f4450a680c4549f33f2b650dabb0e06f418fb62bb234c2877ea7c +566e3017b08cb4c381caf984191ba7dfa4e9784ab4543c20a1832e63d0f3 +62448cd2ee72f9a45a0cd74801dfb32c6df28b83c2183d13d37a21fe8f55 +354e420ad334e5e36ca113a1ff16bd3d142751b50c122254e3bbdce4ff28 +85d2c5e4d6a57a37b34a2593f51d6ad89cc225df6b8465f57b6cd034ce66 +e5e86ffe880d507d72933ce7c93964becf15481def7e649e4a1cf96d0e78 +17357dfa81bac3b335e5eb95be5f0e27aa51bed0bb47d556417fd0079d64 +ba1454ff9531c9b090eb6456a8e52544c1bf84a84187671f6c18f7269162 +bd002385dd60dcbde7c5fe69c34d004b2a284564a9cde4e3887ea78d5698 +ba791a710fbe92c7988b361a335265c707c2f00e4baa3855793fe2798ee5 +f3c1af717279ed9d860664996b26095506bd99c8a72ae7ebb45ad74af44d +6ba45a2401c195e44f1aee76743407a12ed6bb80701e68a2ea02f0dd1af6 +320b59eca2c51a38f1ce6b8d1cdade6d9a745c219a311d646a3b069c44dc +d226f4ec07cc1b249f651f1a3aaded284ddfc8b8f8eb33371a522823fe2b +9275e2ec0f4721522a0704760205e8b924ef1c2df09e43e3985ac4d3d496 +0ef19cbc76a77a76ab47e41be9ccd032ed70813c2d4af60f916c510f9df1 +7c5bb577ffd1cd9c3f583e8bc0528b87874638621285df554d1f8b16c4d1 +183e71a22c772c362dbd1427980c002c3c0112061e8ee485d19a020c6f0c +ae75194d3847585efacd14e2a1f5cd1c8d0e9f435edbc06db63f1dcc42b6 +b8f381d22191fb0f74e34f73b1be39b61d231fe723315de7074133b1e452 +090331eca04f6c383eab1307cd9022ab21e97643c5ff3296613bc3ccd860 +1f406578b6797a228acf6663797b7a7592b665fdb2832898c95b5b814fb3 +e45f678e37b709a23a5d88c999b8ee47348d60e358f7cf8ee72069a523d6 +c74e7c1692dd17ed1cc4535a42636f534f2be5c3b2b15942997a9b12ddfc +28d44f215db9142e31f198c5e6b0d25fb2ea77bc0f9c8ca42d6ff67cb402 +33e8396ed168b90a3ae58027944665049e54f29164673c4bfcb602890fae +dd938622e099b93f0939b2cad4da410e69c54259286c8ccf3f77384c4e22 +fc432b44391bcb5be60a6642970357b89191ccb4e5a85ba87be5ceaf2712 +ca6577a55419430c32bdd28b0cd7a6179e833712c0e17f700c31228ff8ea +7446440dc3fd05fda08c17ada33296fcfb38cc26225ce290adea1d4e26b5 +361ad604d8b08a80636f5d0ea79e16cca7e1a3f3c59cbacf59d252d989a2 +49752d58ce58480dccad56aeeb0a5c75b89a8a6670b7dbf324c0887d3295 +d982cbf0e2c4212c697d91fa63d676d3042c68c1b19797b07591050ec23a +ff48f141a6a7f3869dd3d9dc93f35ec26b388f43ad1bf2d106e11b35eac1 +c20cd5389511ac69973964c761d32c80e5b64e17c1072c8fc219286320ab +0eccb5d6c5e2865c998eac3519359e41b2f4afbc30123bc2d0a0de19ee06 +d42dd254db2040e2a2594475fb01b90a52a4178f403bbcd9782c20c8f18d +b6d72f9c6442f1d0c41b94036ad8bdf9bfedea0b96117a93f04c3c4206a6 +bbe324a255a7f18841d09f976085737b87bb897a984dad2cec5a44c38306 +48e373096da6ffe8e637671b820a62d31dcebb108b5a2b62374c746da5fe +380bca1e486c3daeb1b9034abe8980b89e0a466dade7a0eff5c8364df55d +25943937d78fd23bb599fc4d241c7ca6c23f337355d846c3fce08c82e21e +e124db9e9f1b416e958d91ed2c21e26c3b6720d18154b8f3c41a0b9d035b +99eb5671d93dd6d366322e15a5bf740c261ad4ed24e89a6df117a414ea0c +1392691a58b068ca538685c646ff893029357fb8e567855720e803528dd6 +0040c6f061113d9546f2dba4fa83edf6732c6dca4338e14d3d577291b696 +02980b2bd8cfba079e11db2228e473600ed550ae05cd85a1cfcffb645e68 +5654ddcf891b8e4ed4545708f683f57fbc680a18992752f5cf2ec471ced0 +a16bc4363217f9767b684589803f3e6e9efe5e51e9eb0be493de3ee91c45 +61b92a057fb03ed4f0df610ee47f89efd4b1b0e1869dffe2cd55f0e0513c +738a024c9e514db72c6d387dd63f36dbec694179a70bfe8c740ee2a13a95 +0601f003b83f07bbd035f8809ae347e589302c1f9e3f3863d66ff1f980c4 +8224591a762132041176334ec86f846fbda4db22ea5c4e13c9a80195d4c3 +a8379516f766c8078cb77f67467e2c11a90c5d287ba70e9197f9a2cf81d1 +34e2d939410940a6dfd0667dc491ec1a705b2d1433ac0ddd052b5d1520de +a8d313bed949de251d7090c1efb589d8c7c4460df3f453a88fd966801a24 +4249b996ead5d21d7294f4c4b9920252b60b0e8959edd9bbc4cfd971a6cc +e8b402eed87bac510d721956f7200e7b6eccc684774e471fc7777463e74a +e1e0742f3a9f4110514726ad5d81150234358c95735248e06086770fce74 +9cf6034db5e3071af9ee634140303466baa467e5d5716263dd9291b4cfe8 +56f352334acd0af4c7d27582b3894d294ab287d3ca49b788d7fdf9dbaca6 +34f1a709eb39c3dc65ff732a3dc5b318c9e52dc0b1af189101f02498a1b7 +8f3db2ce24f0003f20957a676a67ecaa25f57adf4f1e22c48c66fd6ad0ce +33611a35ff2e1fb51fbf4f8a4e19ea7f4cda91cbd64937a1679789b90baa +549047bee22b3741e3a04d423e041c09afc847156f96d9452bb8e18785d8 +c78313e8aba3852ca8dccfc8c8a69d42fc9eb366296ef9f33b42582beb9c +7f021bc6c9d27cd19ad3d88e19e8b8303c550ae07ad8fed1519ff5ca68b0 +7e9b97695fe76ba74d04a8101077620ee5a154d1e3d1caa090cb2b50756d +ba0bf5c9fedaaa3e7869b8272fcb27b1cafdceb940d825f9b7beb7eaa516 +70dbcc38de9ee3b28792e30d2131c8f2f47f79db6ca4b1b5e2f3063e686a +6d6126707eff0a60a8b7ca850b9f8f91414069354ff0ca285743b3fb3e70 +aa3f3e58cec9d01cbab862d1856d2cc659d1b8502a64b3f9892d018d700c +3d92030b114b520ee285ff1766db12c1fdc5601c15345c6d33a3c4a994e3 +6b427acc7332662596f2d36f24ae18c15820d0fc53e165926f701599a391 +26331278e31f5dd3dddf8b0b504a6e4dbdd453630beacce725de85ee0c2d +d759444a157f5e75c65188ad0dec71d7ca53fa5d8f6d1a3ff6486340d81e +37d8cdd0400f54faaa350cbc232e62c7953a35495730dba62869a27ca03e +85ec5a01b90848a5adcc9575fb0e60c3d26ade2d72886ceb3561af2b3bb1 +2f2eff9358d313cdce228a468da566f95a61987000720c62abd67fb7b9cd +2cb5d5f74be8e0919dcb60a5364b1735d31fb3fdb59f9c22f0622f8df391 +294c0c2fed3bcd185c9d932f097bcb2c066b6f2b54613f30ee99cfe0b3b7 +08cfdd0565badf6e1e7b2041cf016e3b3ad1a5c03be3316033da091c0da1 +7473925e79e78f8a3f48ee2348b2a51cee6bdbe2a22244b3ffd8e2f1f6eb +21a3af001d14e8954e80598937ecaad0fe81a030269f9aeb134350836da4 +2df81f22bf35544daf3d62ff87014d3d62ea58686e5e182d930a2dc3fac2 +588b49b660a22c3a55bf8c99dec4369d1d678210db13535c0fb346f0cb9a +8c35b29652e763300876287ed1bd8ee4408d586f2c27f3c11c7cae9eb111 +3b01d521a91b24c52ed8f9e5e122b159fa7247af419a2378ea09a59d7214 +7396372a7d1e6d7d533d0a0939cec9a27c6bacc94bf8eba620a10483b09c +a310ca41a6c2606e2029f3ec1e612afcd9e5302680d1fc088ea26d835531 +f157e9d4530cc97cac29d0de3bb879970eb3d781a222b006b0fae97e6233 +fc47d71f1ab194e672cc5163c4052eeb88a31ab3a3f9a59f8215cc729e27 +1e5db50036b810cd95cfd9826884ae6b1d9e9774747a0a9df039a77c7ac8 +3406b9d23af796412550524df48b18ac8a24e3c79c464a253fe332a3c183 +99fbacf4e2a0c66f152c9f89957a628b359070c773eb7c7b08745028825a +fab05b092089a598ceeb34a1f40bcc61e05270be279e50ed9103f313a0ea +b820f053b53669330e8f6eef4504a05d08178355f2c5162c0106a46617cd +0b424fc04e3dad6ea66bf3f3aabcc63cd504a4797a7698a486eaf5220445 +7f0d1496d62d27a05717b23bab14f37a8082bf9b90b8bc82b19fd98404d9 +ac23ac738af0e624808613538d34f0011ae775adb361e330db975713b672 +e106228daa1c672eee1883b3a489e9f375143e9563d68d1775ba1513e779 +0a7ca7468011420dbe03f372339a5e354aee018dfea076dc8962dffbb443 +3506a5bfc44b0512e8a8eb7d0ba0f81f5b123171a69b2d42ff5cf8a81e89 +a831e006ff5218daf44f25f7e046c6b06bb1b077778652dcf6855253129a +41884f86db912e57d7c4e06d7dc8a116ce65b628399cb21bf5dd8f9402a5 +a116548c5653a3083e412b537fd8324e6db3f15df83e0185cb8d4c5f132d +df1f8811e574029f3efa0828f9223e318c0a838b2f9203f707f2254e649b +7b78757e94056d90f65df04c47e73bd7f5cc5772c1253f1f141567ef5435 +87add907f206187b611235c634c97761e4834077e659b60ee0f9d37af855 +6018cf054eaa400a820d87b72f33137eb2fa3b8c3f8f0e6f21c281cb940c +0fa9fa00589243d32795125aaedad9d7ceba399ba151f8af63bb3820bcf5 +e59c2bac5eb8a453c8eba8106a05e6c84603d2f91628878a94810ebc9c75 +d951cb4916b4a4c8d471bb739d26984c7e0a0dadcf44aacbf5983a54d979 +9b20298c242166c447b82e7552014a615d21091f33961b5b084cf7670a60 +cee6af1919e4d128a4e15509607caa802093c5668be1d5fd5403b9cc135d +2ea6c2d9182835e4be3ed5c484b91448aab3ca396f4cbab5b6d2943d7a04 +7f51addf7dc9bec7ee4f952bcb09059b2da0b1ad56ba99994bad26ebda9a +a2626b6cd881c6b7ca7dc96e7985d7a49c7ee9d035bbdd013ff89bdb181c +1c2d078159d9059fd4459dc967af31310195a3cf9bbde2422338773f5cb4 +bbf7fb3723133bd398a39fcdfbcb88acb00080cde1eadb8019f151e3b1fa +e7681447c9987afb4df465344590f47d20e47ec4285c5bf828fa3ba2e3a3 +3ebeb484f413fe1a0fa6aad97f900e27416302a6aff179260a206999db72 +035222b1bcd1ee30f6d202e25599b536dcb10ce7b0c283f2543cb7695726 +741d1a477e0c0db1d1ec085f58e6a8ea91e05eda30f0f66ed6f3a7be7117 +0643cd058ea61f649bcfd9db22a05e8c0e264ccdb0de198ab6e629ac4c40 +43280269f0be430d6adf70b881f56ed5112857fa0ea08ca2bf9e20989c12 +4a54c7498bef5b8d627bf0b42d5d03cc063f8eaecd3932956769367c720d +4043d64b68aa996282eee296c7f441a226ed8159b166e1aa996d24aca65e +ce80b674e97d6f7e392ad6bf593ab4f38a3b206ca0cc3128d847845873bd +11b4293043a22952dab798352d72cefef8ffe015192ca8f60c90d314a8ab +238a13610382f9f8ec1d8c1fcafad7c2160d7ce47ef373c0c55d7bae9b21 +148701f7a8c0e7cc82de5f26d7363d95163de187a5709820e37bbead6e14 +80246152f5cc865b819d29512b967a90447d98f971f4c4c28c2979d07cb0 +e6ec8d4029dc64aae3dbef8eba571236212600ce0acea3ea444e410c53e9 +e5f1d9d52215aa05e690fa3483cbd5451f4311cd0fd23f39d4e106e69d68 +1565ac01a60824243990cd9b034d3ed1fdb5c0752b5e64e2e417c6b64d23 +c8e45af1b45896ec877c2d87f88f4f4a85d0a407b1d1137f53650c134669 +649806886c2eb049edd7f3b676f52345fa6ef9ab4a418066e08a815302f3 +aa8ffb5fbb75d12cc3bac7d9ddabbac644c2944a44696f69d130e3278d9a +e457c39c9965e27dce8a47966dab125de8e110d266b7fcd6eef2d820c029 +fa60dd328084faf8ae3b6bd0f570855bfc557e154c7d4931ba6d2e4aaba5 +27e0d098334ca38c9a78edddc086cd1f03bbb8e5ac740d6140f67d749605 +54afe94dda9e1bd3a55c4d591c34ecc27277fbd621ab9dab7c9699c11c88 +010ec97bc46dd1aad64f0df42c25607b55b88544455aa872819232372508 +516f71cfcb5c72b4efdf280fbee2819822cdbbea4caf86273a82d3f050e1 +42e1e0b8b628e34f28f43d57f70718498f4690dbb3e2cffed13b81758457 +541868a14d0c73b9da8f433ad8a7ff1d1ee38348ce1a6d95f625c8c87287 +8c46d87c20e9cd3d2c4222d45bb54d3ebfeb30e53cfa6717b52a9025925c +efd17f795f78df3babda2beae6b2c1995751c334fadecba5981755bebdd7 +6034871e1445171a71f60282e6785059cb4046ad0bac98d5a1e5668a2fc7 +fcca3b915875fcd0d529a635d64cb34387cd90947d3c909f3d32c4eb40a6 +0f30c3e1f819bd8aa2a035dbc3ddb269c26270244c224c3a93ba4350316c +664b2ce7153b09ead7d39bc49d6ef04c83703e8b74e6a0232c41a02a7de0 +5afe0e94dada8b1fe6208f12b87e00ef8c65d58b02466ff697d6467f66a0 +3f34284e6342b211a00225a607a556ab1d4c8c42a101ff675d951d0f5a75 +2f2479ce3ed7a4f84488d39f622ee53a54c3202d4e6017832708d41e5338 +13a8d67076421fc76eb25c6b6373f413f67b01d6fbc1a86d381efbd14485 +c715984a13189d77f70af8035c8df5d1d23bf2535245617911a4bd580689 +41e006e7d36650fce069048bb0bcf831d3606f3e730ded0b87a8d3282ccc +5ff5f8f0dc71c4e0f702dc5b8a8eb71825e09b692adae6793f0bd6dcd92f +5ec371159f0d61b7e174977766910a5d2013af40264e55351de8f7b7077b +058918bbddec5e4dc7fd54b83b0af45f11a71ae59646935341bd381b72b1 +c64b82472cc9561f1ed5ad6b5df940884f6574d0304e5b9dcc28875a8ae9 +7ef3fe34068e2e36fa46aa5cbd3dd87f92ee8b5639941300a1034f50fad4 +60024e46c2710dbcff25e3d17a9c0c7697e318b144a77f0a39b1fbe910cc +a9a8d8632c0ef2c285d5ab8d014d0b2dce8d7b0689af0449d1a22875cb7a +a6d8c03b544e872ba804ade461c9ebff87461641bb7b9e1e68d13adc8f41 +13e2e08e79b0dc30d59765814a47a64b6a33143b9994d42b767e000e44a1 +a77e5241dc5a9464872b1193df3187c690274520b46c4d2c04d04284b58d +05e7378d471e34444eed398747dae91728b8b1f3099ab3688d4ce7d82705 +a6a3df49e761f4c59e071e3e1d771ca1b8a60c359bf076e8061d148a6dd8 +04813a596c54149faf1bd2e25dc44ec458af5e2619a418c53b7eaf9cc75f +c21387ad8b7f8e5e98483cae7e86853890d74588c87078c58237ec97dbfe +8aab8488138402cbda5c876b43c280efb357342178217879909dfef65a21 +979caff8306759d8b475c3dfd7185074c185e4222deb781fca1c2e7b65e3 +d7bc788eabd2a74551c5bcd2d07695107673c8b38c53cb425e03e426e1d9 +88c4726e6fbb988ea28bdaca5156393213a9cb1c26eaae7b9534e2d25083 +37f2bfa574504a4f7a79467e97511ee052586288b2e095c41920ce77034d +52ea9d07dfdbf3f094d7d15f0f3dbdaf3fddf1d44a1f51d470ec0f6723f8 +2bc0e874bd5c8d1e5f0530f65e6b675ffab3cd19f1e3bf6a226e3ecfd2b5 +018590395fbfbbe588621cdf2e52e1483794c44c6548206079f1b998bf31 +11772db5cbb8caf6930f225373d891e19a4fe62cf8a4309561274a329a3b +eba8f589bff6cbc5a5d62d2ce038d3b64bef960b4185796f506c9adb0714 +f47738c76c30ecca61a019424d6ad5ed46bed1320b665c4840b514692f9a +6bd0f93c53fd71ca297b3f00d9e7ec849a256e63a647fe3164dd2e3ea365 +af25a5c1eb26b13b130cae81be1623a0c8db75ecd68806219b7db3acf4e5 +5d504212e473044465a6f8bb66f730f28241f3159953ea3ca4af93395bbe +9f1b5a1c3221107ed4cce1c509f522bb17279049041d75eed831a0f6a676 +286db0739f5d9efa13a81c3d38cdec6df61eec011451338db2bc6e5c1688 +605fab1ccfeb842de110d2047cc89138774a45b3c2b174a4241b9959ab39 +d6378d2a1bdd02d200290cff70a5fc3ccabfa166381c47f73e3ef81c359d +35610fe000371e6cd4f38e525aee9c02fca862c8cc0cc548a846928b50e4 +a1a5af19a7cab7dd540d59eaa930bfff69cd67294d470bdb0e01090f7d07 +11ff287aec4c95f54ecebbef45ae68e07b20e6c9666fb2355a971deaaf5d +0e77114787d579734e39c222a01456756f7d05a079e7c728d8aed34e28b4 +faedb5e44b28d3def6f351d4abe40a2b02878a4747b1ad064bb43ac2948c +9d62e3bd6d3ca32c8e062552ab41688e108fd838c969db1ce8435f173349 +a96e2f0b156b9c7dc2b1d9a3d5796a664ebf0b6155e5208d976a95c6da4a +80ca7cae016e466fb4ce4ecbc9cfcc9f46f389464ba21e51480286fef055 +318d74da79a0612ff316db41855794559ea733ccf0f964626da329b20149 +652408ad37595fd2a7869ad30752421110d0f31b395620b82b32e4db7928 +0455adf028a57c60cce7323e7024023fe9cb11c4563925c1e69392929faf +046c16813b00516ec1f55fd6544595d1ea9529015a17cc8106709241e35b +69586c1f00555f0fddfa746a26764fd1fecf101f63c4f25a75b2649200fc +5c77003d852501153afba3d2a5b90d44852e14e6b6827e6f714481bdefec +7a68b232bd483565d3a31de86176b2ddf0a42fc9700c643ca6693890127b +842ba5099908bed877d2a2bf21b69e1f9acafe691fa684f40efa7f297f0f +49b9b28e64fdb378e0e66ee7567142969c5cb92fe90fa1905b0a5c354a14 +edf705b62ea069248b6d3e7eef1b7b26d2657561a4da5cb3d27ca9be8c28 +3e23a0531cbc9992ea589d3a39a629a94dcfda7bfa0347c852a3ada2d631 +a2f74dd19a7f96a23d61a73e72a9b12ebe45f3c051f7a100517d5f1ed43c +0a0ac5961fcbc0987f9191fa178acb9d15fd971740952e68eaccbdd70839 +6b6b6b3995976fd8a571e5253ee8cf1cc31af523dd223d13d4ae62e93226 +d83479d64352d7a51773bc123a58a24fc1190b3a02cc5ebd2d34a40240b1 +dd775ab4dd9041592604ec01d5a96de6120b37cf672aa912422003ff4f93 +8ee571b98d190c9a43613b11279d586f9d40a0bf94025161363af525a243 +023eed308423d27bd6246077ae64d38625443fd13e78915f88e284021009 +568b9e2a09d9f750b92eb5b48a60d1d9ae227ba47cb6fe49b1c51bff5a79 +7d087fe6c8458465cd3358bbdbb54fd6263c1abac697ac380f7417dfe253 +6602f0a76fac74c2492e524fb743fb614cc49f82bf59fee542a6de34c33e +bd135318680ec14b77bd72b0a5792f0d505198133884e346d3d3a8da1747 +a5e3413563ac750d6d2d633a5c90ab136bf0f4c41e1900e1da555570796d +d7c66f4fbc0fdeef00e7754490d589cc4cc257fc437706cc104e00903428 +1da81e74fbcd8c2dde3559a5eb59a67192bca9ed49ffc49b605a9daca194 +ea025c51c5ecbcb3a7900a3fbf4d1c2b9740fa767704ed75c3b58c7b93a5 +35bf43fa7b0e1e0e696b6c3bf8fc8905f4e5eed80c239bd19c9534922c27 +86c2f9ff1801d2e1e0890e1a6e61918a4c904ad8f8b79e297cf2beaec87a +fbaca9515dc987e2dddc40f21c5a70d2a93d8d0a626e6e6184a2cfe85f86 +630b03d237d15295c3c5046f7bd5a24f59a8bcae80909b96ebefdf6ce2c5 +823b1352f5a76adfb86a6693cc2cb654ad09cfaba68e2338f5ce117604fc +5c037512857e43ac097fb024cc5146294ea0c753145ea5c2f16a18fc75f6 +8d0362d4475a1e902fc341a3c82ee30744179d39c3e529b96b112de50711 +954a42ff30ec777feaa3d7c23e0f4da5d0a53bedabd6e46457aa6292585d +3a148a31f0559e85556414bf2e9e0b62c20ab24ae5382a6d25c24a5d54b2 +672c5689c3ff74358a6d211f4d44e185c64b9e952ac2d60e6d9c816d5e19 +d662d6ef1d18b380935b2ccca31066fd7890f9b4d3c39d7d4a116c16d895 +3737edfcf511e94910f1bcc3a53109c6a21e177ad241ba16f5d09c711ede +5943009c7b8b6a02976c33c38d43b873029097dc5a93841898122608fc4c +f3acdcca3a2cb082d8aa4539d8243dbf363cfbdee338879da264292edf7e +df7776a8d12bf4953f1fe319760a0c6b6275db4ed1b27135132062eb4b7a +cfb2bda8b2dd2ba97f524d9103c43e81fc0ef9e08af1acbcf0eee058ec5b +ecb04a1cade9c23d5e50dff7a8fb2c813f4f921fe202a9648207e95cb905 +8d76c6e34b13ea3c56c1ec3f3bebf98963fc566ae80810bedf064e32b75a +9dcb51426697093f3571af3618619fe007d0c52bf9da695aaf1c2aacdbce +03e88f208a050a02c7eaa946f41acbf5fefc03e790d08867e255e687b664 +a130c9f2f7537feaab9a431ff78bd2f70f4e3d39ace81e68a83877e62623 +05742e7d16dc3795c6003fabf015ca563916ab7b60fb7f6efceebe4f9f7a +05f120b9638e9d77801ce319d199a1f15dafaf49b53ec272ea1f3629d013 +0d31eb4854375f171268866da5ec2ec7fe612bb9f8308c2e0df3481cdb4f +97f8d526eb04dc57d9a84403902967516b7d6ba894583e74c5c9a24623ce +a44df1772e2acabb5c0e1fdec582b1430a73587fd5f16b784682c0d02a80 +112e2044ffaeab3580f3e4000a25741d0899814832457290be7651b8efd7 +2b485f95d405c6515eccedc45b9bbc76b20676a5f6a91a58501e68f96cb0 +be65def662cd1db19ea8031feefbcf40353b7059476aafa33ba26af93b60 +956aea6d789ff3d80ed3000f266a2d8773eeac7fefd3776da65ed01acf9b +43175602c26a538b1df061bb3b524f2a6ae4dd052e9ba288b2d35feed1a2 +f325c203072257db68404dd5b9aeb63d441e41ad385f170ddd4aa559296a +cf4266c7e3bbca5b936e6028ab1bba4a44c79b4700b29fa2ed65d8274b8f +54c17de9f4f151ed08c5774c1ac53644777fe675355dab5e54b131d64bbb +aa811dac7925e002f62bbda978c6ece9b7c51c22573702bb08bd218606f2 +a7c9c8abab1b262b923c483730b4e6235607378a6b770a59845efb645312 +9cebc86eb8302e45fcdbdebc88c8b5b3115925044520195a42dc010ad771 +b320083a839a7149433f59442a24eec08286051516e97aaf096c4e87ee8e +89365b9d4cc7c81c71e000b153a27e74e0515ff30e401252114dc7d4b1c0 +1fae5ef32620d74d9d4c61b63c5d753b3223a9c7267dd516d1cd18f7fe5f +a60f8fdbaaa8778d79a87ab8901927ac870d580b3f9900b6eba38e830455 +8990ec4a85fda0ca6b3cdf97573e4d0736adbfcf366596f5e34f59f9ea15 +d38e4cc24ef808066457986399d309ce2cb7fe2c1d1ba921f1198a91766e +1de4531980f5477770783dace9dec59922614b1fd88988007c6adf10ccee +e138efc2346390fc88d1adf8617e4e56ffa72092913c1b263584089b4e1e +214213f56af447678a4573091e3edc3b6438c00539d003006bb17aba98f5 +e7b9cbccadff6803b31e6ad941990462fe1b935c67ff9e4aa4b615b2855a +d28841b296841a9f1a3bf86f9e3b1659d7e77b4b6e07da31af84c1f57e50 +20cf8c5b352fd4124e13117f3456d1ea3fffbe24a86971b712525505104f +44e260553d10d65978a5ebf7ee66c7ac6603e7be95d2b9e8126931ba1389 +6987f97caea5b7ebe1c54069dea74b6157f19bfcbea2e59ad575103291eb +36923f31341b9d12c4cedc3ed0383f19e6ddf36ba52652dee81e225691a0 +0b49aa3fa21b5d1a3b70663345263fb59bf0d71667a278394d71616312e1 +f8b2331572b7902fa2968d69ad3d42a938d7e6f9e9f26309443a6d977c64 +613501839d09870f02d282d91027738c17d164384bf49edfbe5859017052 +483a385f3d6c23c8ec31ee9e07c5761d85d6702be4231b95fe357bf67271 +454d8ba54104291df51c2092823d58d7d450c992eedc2b59a720c7195790 +44dae147b760ba9c83f66e2774c36352ca242d4bc6dfb07d15896edf5d07 +62a1b9491bc4f4a2ece2a0c44eb8f3a4e206be87c857f3c3ba01e7c1b329 +d7553a2f5b8c17ee6e339e5c32c75a914ed933c601676dce75f19f769737 +5650fc71a01feb7c88cf93b0870889df962d949ac0c672ca5a63fb9b6e9f +731b075c02bab9297ed2318099bdc3d2eb26821cf90a2f388a6962c12108 +9bf34d08e3ce5109992f30b9f8e8b5202ad03d03d0e0001285cc4647d919 +b32846ec23fbc8c9106bba7a493c81b3a58bb13dd5d7a43bb6622ad68c84 +1d7f1136f895b1d49496887ac7adc49444803a164a0a1faec299da1c1ab9 +64fb75314bb9d7d4aa04ffb3575641f77bdd0f7e780eb7cdc17a88218c18 +e710e0f8296ade21fbdf35ba06e80aa6bec89f1b2a03076c6daf3f0fba84 +5a5b881402d2c0335b687b4030409688963f6dac5445094d66d33d78a763 +b6f500fd4c9bc8804d40f52cf4baebc6d35da9cdee7a30b70fded0f18587 +a17e08154070b0a38de000351a89f44b6cd66608d8a86844f90d88cb257a +4af9c67f155036e833d5f5d0fc781dc98b1fc1b74c42822e747653d06600 +67daa7aa765471929ed4e38d9cd69bddb4707fb1d11d1237b3a5064cf8c1 +c628e23de9ee9dfecc4bde42978db529752a3a84b912467569ea3f9d6f40 +978896b86417c11424cda3083447f5c2df66c25c5502ea424e3a6ddcd230 +e649ffc82b3bc0168bb999bc51081b36bfe61177aeab6cc744d9947bc5a8 +938162c79a268e6945c3842dfd87b77d148f9c7941cc629d53547da93086 +30eb7bd3e1c0f27f8ac28ccce80ba0aa0060f26bbab71d175707ab60902f +fbd9c99c38d852f114f012789673189b246eb64e098c5e9dd197abf6269e +e1b4adfcf68c1c7b3e5231780f4dab3d4305a18a898ae3d3fe4053905248 +c4ce72a10153702987e2cbfb01cfeef86a19ed5fd00666ff93f1f47846cc +bf216d42439218abbc95e456c07491a7c1e46f1d201c2d806649fcd234df +122f89b3b6c0d864053ac7126861a71f40cb271c1499e4651e52a49411be +51c646d59ddd91dde8736a0297885a0e0281432f254408acaaec81a374c5 +060d0f077677aa42a06b4dbc477b460f8d661789ff0cfeb829abecd6c06f +a1adb76f27fe5381bb009bd05bab346a2d652d2478b0a8c76aa6c998c972 +6e87cbda66f9bc62fc440eba14c7347014b26e84f30556b8724bea81bf76 +d34263f8e45aea56841ebb601852c082016d5705a7300e8be1276b93c11e +6bff846f1cb5f37734c467bfa64e935897b789d5985ce3da9a8eb80b9736 +5df25e5e875ed16584566afa3929d869a3fa9cd7aaf47b78939812fbe18f +2921b393d788f75bf0f0c62a5bd25124cc98844e0e4edecc25d937df5670 +0965787fc4d191a33db8c24ffb2ff5504a4e6108e5fb5f6612db56bbd7d2 +f433fee1b8f0d780ec4f7640b4ffc01f352eb398b7c4116ff43f93a118e0 +56d6d820bf3b41a7c09ead1cc4ff9052421769c56b4599387eb08f750d6a +6937b06cca4352a3f4961616eb1239ef592d72f7a7801295a1ee3e9782bc +95ea6832f1b2715ef1aea0f4722e8516fdad1bf4145cd261032108e7892a +8d040771f86ce98994e1b4b5688d59d6047a513233d86d3608ac4da4cce4 +cad778e366271c1609ddc506304c65b750b8bdb935ce9f0e0db5337d2e50 +715a21d1dd04920afdbadb6a416932bdc697aae5ccf32e9970ff05a18ec7 +6684d125607e26d371ef6e69172bf066f7eb6f527178a09b4077aefe0590 +a8bf000a9f2d483689b75cfd02571453435209ec995e6c072c788cb3687d +6306d79f771ccff4214df3e63c74e83dbf2baecd472cb129fab760663a5a +642910713187b42763e8a366c5170a81a2336e9881f5166fd9e0a6ff6c04 +b3b76c3562e0f1df47075ca1be9a79d58cb392f9d9f6b55c49054a35ace1 +b3ce3e8d3c81ba1959c167823375626eda6ca3f9d64c23de7a9f2e23bd32 +15bf3e65830cd8a364fc533ceca8b67b466172d70a891e4b3fe35adcf61e +3e1f77717fa3924b7bbe8043b9815f9777a4f007792d6d6f9942d02445c2 +b0dc07b4510ca3352359aa3162320d3470d0147b1568b8a914e0df108c2e +5a76d2bd7d58c8c2d7403e755fe896aa7522053b4cb846bda0a4e9b56b97 +a9d089e3e7416e6b1dd014229b90fd319a45fe161a0e3092e604be24125b +51f3e7161c64fffbd2ed9eb48bd14342cac1e3030c633fbd6b87d28529fa +29a5456799bec81d581c3ce827fcda2101419b119a4af6801c945c314f80 +f4d7abf36f73e3e75279530636fe09344e98c368240b9e4366d9e66a6105 +74ebee6f31cc111e83e0544ad321cf2f62f8c530beccfa91c5f3c5645d62 +0ecb35de6fa3dad76964db3a8307e8928c9a18bcb72d919fee70f1b97588 +db5c18e16bc7453597a1f20d7a9d9131b002a56d4c368d6bf69e8bad4e0a +445c76fbe0af2af7c74db79ab8f767fdeceffab00c620d038fde8341ad14 +6887045489489d680e104129293a3f27e5fcce7529bb4a2772e504054157 +2c22532bf50aa2fc7d4b4db9a6b38e2668ced8fd5fb34b26f7ed5f29df43 +a5b17f9f1fe1f93304e31a2e17ccd8f25560f16074b1dca25c11e086363d +3ebd6139d32594cd59a2d8b600ac9ee7c020d22b4ace7662b349824c926d +29aa5fdc9c1dc4fc1718b01d7a04ff71fb10181b05cd613ffba439285862 +973a020895586a0543281cb6e94ab185d3fee9c8caefdffc959ee7ed5101 +8d527b21dca5ba42ba2e3a8a77dba86e64ce0ab27e9b5db014001bddc890 +db7f61e0900459821a7c7063db65136e8af05a68d26f6421fa86e4ae6265 +3c6577ac9187f3d6410bdbd7c8109c9d244376afd4b783ca00473e2797b3 +85c8585c1672932e1547d2183d84adf7e6f8cf420d03a4e78ad171ac8d52 +f443c76989ef51a0774c13711143eb00ec544a2b7421728b79502e8bfa2a +394cd0cc15af713b5ce0bb78e716891802a281bb8fe6c5f2145b66e64dff +6509313f3503282460e4c94ccf85569b1ce5840fd638ef514fda9de8b1b1 +e877579cd47b8785b991641a481ba0ef4603580c8edb944e27f4e92935ee +027e2a55fbaff992f79e03f7b24268bf93b24ba6c604352d147ea9b337d0 +8e02dbc75fec7f50ad4841ae655106764153e6e08c84a2264f2a180c2225 +fa1e39ac081f3c4a3e3383bb9d5107ecd076edc61a7a80d9ae7f55975b60 +76e245f08ec36445d8f05dd13748995af65fffe75597e98683e688a24053 +011bc71b699ae161dcda835a2aadcdf4d9a82750958a39ae685058ce74f8 +91626e99497bc82d62d235494dd83f87e46a3756823e23434d47ae4f35a2 +dee83146805fb5e28af9e2df7812497ef6a45bad66df7b29e495128031cd +96564323c75a88b98e7333f6f8de1c8e7526fb5f8c1110ffae4bccfe32e5 +32f1228f7a094f67b3518e00a071897f4edb688bf9975123cbe1de0895ea +0a88277a69a5d7694c44b15ae4b592cf3a176ab6e9693d80d9b1b89bd35c +d888b764920e865e7e9ad0e8266f17044ed652518d87ffee1dc364422f57 +621afea9160a8c795d44a6ce0c22623aa8af5a08cb2319f335e7364e1070 +6d6c357dfdf082d3ebe3b0503f0648b74aaddd538f5805b11eed58d6e50f +7d7e6e1a631e89c81e321f6ba32e13a2b72e249ab2dc31e73a23bae59615 +36f1637d1a1ec1f9f777c755e72510df4e86c0acb8fbda3fa87084fd7153 +6ced250a8f31851f0c9b4149a4ff19506ee0d6b5706557b831e09c687bab +ce784dcab017c4a62cf39df2bf8b25e81b29f8e11cb5a1f4f3eb0014560f +bf1b8e47319677e83064657dc222f4b89f5ecd066f0ef92c1993d16247ce +71aee7c8b464772213ffa7b8ecc9b4fc0bc307832deb605e685f6ee7d54a +d064424e1279e2a1ec2d42b1d293e396ee0d8432a5a0dc32e5299aa79113 +201aa5d2207af42b4b2e617d80a5aa4b28ba84d0e572ecff34fdc202b672 +63b2900e5b8a204af2272fb388c0c1c1c23a8a821b6fb3353bf66c5c01a9 +068afe1e8d70107dc1b88461af7412400ea89be6d9ee48b306629683621f +af5ad5f9f87b8db31d792108412e4e317b0a4fa1f80fa197315232dc5d4d +d2a3a3b16c8767fa33e2f227ccb7e75fbe989d1d51e2322426bae35ae94c +a87356c5cf217dde81adf0625386e8104fca2178217879909dfeaf3c4b49 +22ff0df7b742fd8e53ff06ce37ce7ab7da7a6bd83e753314b4a5db582300 +1d7ae54e696f0fce5006491f9d9fbb4f415f32c6cbaca1e0ece08e6f3536 +1ba4cbd36ab700e7d65c9e7e6828c7a05ef347ec2a433f4d14eed7e00669 +5638f8c3eb83436d5d47dd655803c25fa1acae75067071cc968969647250 +cb082aebfe199d763f534850ad7becc6119c88c36ae5de4dc01631c74b23 +bfc0be2062dca0f40c36b986d06f756a8f6ad3ee511b73b94a21653201a8 +230c66de11afc5dd11f0c7bbca6eda4e20239610d1b7c39758395577a5d8 +34ce808c8175d741d834b184c865c3d8a65c787313a9fb607f977751526a +7384c153d94b6a929db265128ee0eb7da9ceb15f793384790317c87a4a2b +18e765518e928dc5cd257d1734efd5f156134530af79e72004c7b3ef05d0 +e1fbcf09213699489e67aaeb39598b718baad866303b5601ea56c178042c +25b5cb585ec12a336bf74bb3e655959e6f859e6312ec1872eac58fe94966 +fb2c68e160b4901a6fe701da607eb6e371e2a23d2ea43754178f3bdd6da3 +e0dab513f2cc03dde85de5f667a74627dbc8c9324a325ccc52c2ced30c66 +15bd70bf7f59869cc9a2d5757b6a14bc8d2596b949be75c3e6a338edf1b1 +3cef3fe2a02de729df56cc07b5cf2576e971584a9727b84eae6ed9d353f5 +42094c3b11fc9a0751c986f30b10d35a5add9e3102d08c00dda48f942447 +a2015d96c78b011ef763d5d44de2ab8c95bb380e74138a936e03e1b8c5b6 +bab711c995fedfb910b637145fea1767c9283dc78925142f3e870e0d1399 +54b8df666423e5261cb20cafc2898eceb2720cee92aa6277f11282729067 +ef3dfee0aa9d4abb321902c457447661ba78526174124f7c9d5566fdab5d +df4fb6c08a0cb7808c59bb42de49c87fadd4f75935a0ced714b8f3b5f684 +8ae7a605960db4b2bcb477976264e2a84a43cf6854b82844d5096e422a39 +0211aff3a6f6271c03c4bdbdb5631767f345d09cce4b4fa0e9c2f9cf36a7 +ffb12f2c8ea3136945c087f9c2bde97e5aa7e0781e144ce7bf5efafa7150 +d703505bf7412bb932091f92b371539ce444723eac99aa508399d3eddebf +4f4ca90564bba44abe73a50e62ec268b2aee66726ffce232dd4868cd1981 +85816064b6316eaed2f4fdbbd4cb75145fda87396baa6e5878154cda0b6d +8bc799ae07d22a85f4b3eadd0501051c0f46c69cc26a68738bb20acb2698 +15f97cab493969fc16f0714e37629c835132683b4f5e4d7fcf2b78b6c8f2 +f209c4ef075f83ee77d532d6aa7098c893e6f14b0a777abf7c01e9884cee +55066937178356bdf97f9c1b589de16194fc3b152b22bc06e4842ecfde68 +47dbe695df25ba700dd75c0e2ec2cc9716dfe2a4e75c558e0e5e521e70d7 +305e5379bdb0f5ac30f091a77c64b7bbd94fcd0448865d866f4d241e1921 +ef5291c414ae73824607d9965ca185c3005b25838462b937c91ed9c3a649 +d52cdbcd20cf6a1d8a30325c97a0f8331af0c41a2365f0e374830346ef9d +895fe924531098876e44079140bc4d7627208b1d09e4662aa45b9796aca2 +5e3ff8624f14ee127c6a86377996a4fa8ebd4be5322fecd2f1ff85645a9a +11445dc7328a7a69bff5263ac3b77f968f695e4aa381b8581df3f8faa2ce +465987b1f25689d8b4ff6f79d376a3eae3aac7c8cc6436e5713a61adc6d5 +8e8a9e9e9789938bf39dde35f3ad5d2f619d07b6bb5d35277d27d00d15bc +34ab44ee8febc29935f4d78f7183471b32fc327a631cb87697db1bf9ea35 +ba099761235bd0fb08c9ecedc02a56f2013280bef6c57c9daccf1cfe2e64 +796d4185edc469a71d96889e6446c40c7005399b895ff1e5bcf46ac23010 +01791fbf7e895fbf64870937ee66725f2c56712da4d480b8a6382c317eef +a0268211664837c0ae48e66886e0490cf8650c136deae13628fa3b01340e +7ed17aee48e3f832409690bbe4ee1e4e30f9d7930fb54ef72ef06fbde9d7 +ae68fdae5f146e7adc44b899643cc207c53e14c766075cea41321406abc8 +916ad2f763f268886136ab2651125da29348b6bb4d1721203e60f8504935 +ce98b7781cece00065b6a2469902026e20fc30ef28ada452f82097ed5da4 +874fd5409f7056a02e501895c0f5617682ad95a74013d95fcfc7bf203b5f +efe8aded7f2713750bd224b8361d3be7b4eff6ec72c4e484556a5d7d62de +c61e7f4f902cb7d15add2d7cf5b9655371384ceca736ae87848d97541ec6 +45fc0de7ded4e3c8ba4b8a99716e767a2f4242028b61fa2ac2e810fdca21 +ad07a28ea5aba532cd615d0847926c44e7d4fd6bf46063ae725477bbe9ff +d01cca116c5d2e35cb91436ba0d713e96e81e188217cbc603c3a1ec453f8 +3e958063053c7af403de39a9ed4753db3a876f6da5d7190074c7ce479efd +c41bf3448bf859a2dfb482eed009fc38c548abfc54288419ec3b7249b66f +15f5359c461cdd6d77b96e9def3eaec6d526d19f096547061ee7c4cb5a0c +71bc5ddf090c363a8de648d44cb771665259e50573ff945b52291e822522 +c0dd255ad3ad4247658ac1bdf71e2c8bb62f43c2f3994411b89884821fbf +963cafa4589a410f8e61317f04cbf9b87ef236724c850a42f9af2f36a850 +72bb16911d7810ce35b58a6b3a978c6eeeb379be4451f6260123a56b73fe +54dbbc4f1934fd185fb374a2f4b205ed7838c22477f8eb4cd102c53b4ca5 +ad74789a4468cfa7cfddddd23db22ba4315c703763d6b3da578edc4ec040 +d4f0484278eff6b2f4b1e318a575dc53bdadb24be8c5a81f48fc9704c963 +5a57f2bc8b87921f2b3f5cabe517b7909f6fac3bb85a4ff60d5127e45d9b +38d76620e6ed901ad20fee55a99aec87995f54809f22617b289f303ac768 +9719ce10f9d5456f7a4804115abe4cdb5cfe2cc715941a95b8b187b53f74 +c2b82eaadca96bd8b902c58e17d1bb5e8e87bb0aa354cbed83753aefde1d +1bf54e3246aa1485f796fe3be9cd5db6992c2647e4d32ba14bfd5ef0cb5f +b1f77f0e5d13d70154be1e2be0ea6c6ca71a5024dd4c8092c465913019cc +b8d949e2dd5cd87a196640bdf64024ccf38dcab7f022a688b9c670e6b4fb +fb0d3c6fc506aa5aa6b9cca0ff2bfdb20a9f876040db7fb7ec2ccbc5304a +152206cf00f98315ea1aa8fa8a4699c26af04ad9455ab67e60cc95b9ff26 +30cc7721e80fb4c17e0f9a1b7aafb5cde08a489e47689d5138c6d65297f9 +3337b5c6d9917e2d98c65e7328e55b6935e6b81314f88457485f9dc22d69 +daa5f7fbee8940521ee723292bafdf69b9172998b7951967001c8c6919f4 +3e7aa54f352df65b8130a45d5fefe672291e15f34f8fb865600931d1c751 +abd8dca8cc6ec3c7e735a3accb6b407e28ba941276bcd2e221f06aa2e180 +20c88a75e02c8751505800a1d8e8dda4c417c48fafd7b285f8771989d0e8 +4f89adca1d965ffb37c74f63e08f9e5acb085a66c85b84ad8c3e85354d17 +e05494bfaf92dd4e91efa6fc53fe92b7c2cbd93ce69b35cf44bacaa33a59 +de80d50046a1240309e261f1fb355e49f9b15b56ca50327a2c62c0b944ef +7d448b62fb75805665a50ddb309cdfc7cb7368172a7542fab7eb9d386019 +8874930d428f3751d85c228ac66ca19f3f7b5f2bb93303b2dd1532bf27e6 +8639762b9cb525f916d0478ea7ed6ee9735e7681291e17b2d32cae4159cc +fe773d9acc97260e721af0943e2bccb8ccbf17077ff7ffd389dcf006064f +8d89e421a2e8d8098f72be9e286c3e824ea0604f895789866cdb26ea01da +d4b46faf3804f4ac97ff2a626bc0f059d2143ab05aad944589acb5e15413 +2c9392d823c072aa8799940d5c98386a0fd6b4d0b536525e305699f41773 +2421bb58a75568ad4edb53268c8168f914be852c86ea02d369315dd59236 +3915dc469729f01ef1bffaf4a5d29ee70da632b9e63dd383eecd4ea32114 +642c3c4be801265a9e9594ea6dcef082bc99d2cc7e92333aefa43a33d3c4 +696a1ce363c9b3915aa8563eb616c897b795d29361f8253c267dcb652f60 +5a96d6492ddcac2b13bf904e88c90fd75ec77f7364bb75ae200b61361526 +044a94c7e033bb86d44597ed39b1ad3b7bce8e10659cadbf9e07b3fb041c +f1a8adc4b74c39306a8590d58d3636ed87299c47cc12a847120ca9f77182 +606f86b724792908367255677d56495f22aa1275b2ffaf1cefda123a8984 +c607d438cd7c00b769497b9af62194895c6c79819357264c7d0b4ce7a259 +dd1696e773cd0722e28a5beafe26c7d04ad867886ac5d9d1f83dfe97f670 +1c200007ce81859e8da06505468f25e77cbd0be59194700ec5b39c300018 +1398248b39e650376b2fbd9750bb27457fb4cae1615d167b6ade44d5d4b9 +b08492e7d2122af169ba8d1f201e0e8333769bf901862ad46ecc9d58b8f7 +2b58fec61bdd691cc14aef8f5d7a34113f9b0d08eaa4fbbfd530b73c15f0 +feef4c45a7c8c7b68e5310e093667282475da5db6765ff566069215bc09d +d0a8e5186cc2c11e3577b56eb13aea6035d2dc3add1d137ae15f8f9aa9b5 +0b64c7b7c1dfd5815bdbffacc75b84254804b8be1449b32f45ae3b774cb6 +0f3a9ba3450e08a4432ff2527686e3cd04a7f035471bb4bddf4e4ed9309e +708be043539d298106cb4c6e78267b568221cf6458f5a2ee17ce08cba821 +d9b872b5b985ee939c10a45db0cbb3a09432bdac2d10b73c29990fdade4a +c161a5df44c1bc8d60dfcce175b9fca5fedc347fcf7a9c897b37857f7d8c +b1e7af13f4586a23bfc9860b88a28b5cdda25b74b4bb2553e8ed796b0323 +13e5c61ff414bb6eee4d9e5f3e8b4b7811d5809a2be4a609e39a0c8facbb +ab96619a34df96aaf42ec5bb0f16c92e104b95250ce203aa9c062a409a04 +089d02966f454b8fc5f0272ca0f472aa3bff2d55734f9e3e93c9ef83d7c3 +0f53b334cc0ae1e8b0ca1cd4c74f5993cab7274fdcdfe86bdbbbf3ea762e +568d9379ddf41f095a5424337277f8e4f110bfdb6544bc603c6a153c2e13 +084d333f6aadca51e7b45003d4459478b9510b48d708e12e30c7ae7e4a1f +1f872d31ee76df3204aec196b8365c8f3b6d3f386aa63a149e923c205d78 +d7d4c1515782b961927de098c019c865d90c59a24bb2fe821538287cdb9a +b703acb82892558b3b1321a31620ebe974dc1a12746a047a5ec793e57c09 +1026e8cc0ed07cbf90cf19f792629e55a5a6b7d94e667c870153ca440a72 +2f39401aaa9c3ae417e94e2116d97630c289ea43e026b51d0265d38a8488 +5800099b144bf37188cfb3e59cd846871d524372a3acc721f9ba5659052c +dc2b78f26192b057945495fd2456089c3df9c543a643f39dbc26d532c88a +a4fa6936e7579cddc8df83138adaecb0b7096b520ac4d97cef76022200f9 +6542100717c47cc0c59e48dc57f8028c453d8d4508ffcd5b3fff8f09a64d +a18d08a5f91eb696f169758e35732216736f122192a765b5043a7187c473 +0edb5e11c167dbc62fb78cc6d478c79d41645c2012a067a8c895d746c77f +d106fe34c2c888020fdc90547dfaf6036027324bfad10157483a0dfa92d5 +77102b892e9ad3ce666ce138f8f32d86cba1ed1f3dbd5b46a9b83d7ddeaa +57dc7de7ebd5cedc8804410f6df6dad36706754f0796db56e4f7fd86b603 +d68d269004701f81310413a2f78d1e765329c26b37647bb0aae4aeb1d8a2 +53bdac2da74790f5020cb9cc18373f145ced54c39a41ad08a31756366bed +27e1c358d61008ec2b666d348d50f3b6db72bc68740e8cab62e172aa9332 +27ea0b2b6692ca80d5244e2700de3c5a23f36705efacc566eec594c0fdeb +319b05e48f25aa6b5cbf5f71343fee2932dddbf8bcfe62a38d8302d0d287 +529dc0383e8efda45177beb4b1a09e3b6121db5f0a25dec3b8a16889b0d2 +dac7ce9ee7339031b5dd48b2e217224cce666a5b218dfaedab6bb9dba36b +6b588ed0ed3804040785f8672ea17a6b2620f653d98e65876452caacebd4 +f8d399e8581eea899c59e5f50832dcba0c17141c08a609f47047f33aa20b +815531d7dc90722a2622b03b7e82cf4cfc871f45f7b7f040bf20f2a0db10 +0bf9f352233acb1050d142ba5be8a957f1b2af4f3e651b1ab3083f0c7fba +cc934863d2845e5071fae1e3989ef2280c56a82f79eee05aa4ebdf6b61c2 +5918d704d7f76d0c0d7dbc1b883f614f3544e025499c16967bc66dd59fc7 +1efefd9bad3ec24945bc6fe1b58849a819bc544c60d4df10201b2be4b765 +9d4c44bbc2bc310105b867c6e8237af12628536c7d4287e7cb3bfc60fdc8 +446f310c6aad457f1b420aa61eda74926dc969d752d0b7cf6f36add88ac6 +67bf4912a237184bc20d38fca2e50cf9698f9713fb1542759b21024109d0 +6d5df512663444ec40b58d828722f0fa752854a4fa27f2e17a3d9d5b6676 +96a8871cf2fcee25855233b670e78e401ea8046510a6cdb7f3492e8abc4d +23f5f1189ae5b15bb14307c2aabcde0b398bcdc8cb339ee3fa48bb2fc5b1 +a636b30884b342c4d165ba0929eaa8d411f87ab8b36b50a51ba2305e6868 +0f7a5b4bc8555052354a1da9a6fda6a2b37bb248237e7418216c388a2a6a +18f27888bd2d5715b26463b3bd2924a319981e687c15dd47e4ea71ebc87f +d75c72453b7288c8c5780062b3182b0babb9ce6bd6ede56327d337ba1c3c +7f069932292d77eaa0b515d3ebe13b5bb70e17c6665863ac034feb834c55 +d8cd1c078304871bf7d1a782a423b915f670a59cdb30ecc94d2a004f4fb3 +9463a2815bcb1a96817b5d105a8d1ca1a81197a3a83cd64bb15cc9bf31cd +7d174d1ea78c95757a607a6d3ce4de004e840ffe790cb98f4000520da3aa +75e0c511567d8d0927e7b0c2cac2de17209481edae918d5d5a76ca6abf5f +f352f11a3dec26db4ac6b7286ba45d4de5eddd3862ade7f6bc1374ff5623 +fc2749ec4b5fd8e8dec48210511b49ff88aa67a7697a41b75578a6600354 +ab3ff8df60ef834a06e0a88f6a9b5050e3dd3224b511797ef82bb0cc72a3 +77298a714d0380ec24a66463e8d120ca66bdc4bff401718b89890a4c03e2 +a34aad9949db6694aee7d63b32798124e54cdc35aa4ef8fdb748d2c68185 +e4222dfcf0b03d3c121558438956292450e7bc60e00c36f3ba5a2558c153 +b3a7b3e5b6789941f8c83f65b0e6bf7a626824b0e93008c9909b6d6c7210 +f348c72584a67e862d8434840105b28113b5b51e8648e283aa62e60ce215 +0467033bde24acb17606e1ed9c15f9d46439dd00cf5b20e8384da2baeec4 +8d3cfb0763ff3783a005b9a4e7ec0bf36af1755ffb082c69f0e8f4807a29 +87d7a38ce50e1b7fff3d6914dfe2b19ad4b8a4c3582ff4a4a383b15eb15f +e5f36134b906b18f6b231eacf47abd1b52ab570ac964141997d84e8754ac +b59de5bc277370ef2e203c661d32213b2620e911e5f02c4b2d99ef88271e +5c772ccd6c72487ddf5ade79c61f414c4c20bc55be8e887a577ddb0d8129 +49ee3ee14468d2c5e6c2325d25c3a1790eb0dda0d88861a77fd043912065 +f06e7292904d964bca5483959f6fd43702d7ef13e046fc674d8fdbf3b9f4 +ad11d2b14c1f120ae522ae0b69b01eb1de89b3a794b5feb4d6464bd13802 +dd617ab53aa8f1bb962452593456316cf6a9ad6a04c89330bda58ce2ad5b +30cb368fdc8e2b62845e117c965bf052eed29c02c43a88b04460445f3b2d +4935ce4d46f92c9949894661a92c241d088d26a74414400beff55c1ba2c0 +ec680d05c5412e753a10566e7c8db2d2303db5161d5f33177105d6ba7cf4 +8faccb3a4eaca923d5a123f2951fc37df94a861a70305464567469d54722 +fb82a31fe18a65056cad43a872963de7b4085005db0be6978b0284e513a8 +9887bad0d8f38bbaa572f6660c7cc52654c706f0b8e198296cc2c6ee6561 +7b383a3f491d562746fcbd014db726a50d4f4410e64ed60f10d5e4f5889d +741ededad290c03b9d9ca995f49e260442e7307d7ccd36eacbd507601d66 +aaeb232605601aa2b9905f6e7c59453f0e5d6ce8450b8adb3a372b40b765 +0b7e81b0980f095209e8dab194014c299d659144afef2cdf5f12c05f3101 +c73944d76e9ee2fd92906b25b62857b492b23a66ccff19080c55955fa167 +b7aa7e13bf5fa873116695518341a70aa41844ef03c481c2a36f64161d72 +5c150e869e280425996038477fc5a6db064b8d2fd9bed3119b8d93d19cfb +e418b95d6483bbf8d3047cb788e3b5d3eb2e220eec7b48367a916df77264 +59bb90464c6096029d2f781d30502889ac2c9344b8fa45ecfb1f5099551f +3c6dec6357580727e277747e62b757d0ac7232b7dccaa2fd8b20379d1645 +799a691c64d47cfc9531451deab72664558a2ae06d90e45e537dbfa1b8f7 +f14ff7619310fd5365036abf9f29492eeaa418e1cc87e53ff3e982b9976d +adc5f23461dc54d13864bc8bf5fe0e9752870a399d7a9ab81587705ae019 +01a66b4d89b39511ea03e144f56ecb2fac87a5337e8fbdc2cc7d53b62edd +53d3cd77f8d8a3be417809c7e27900d1fc4bfc89d3e2185816ba2824bbb0 +5de4f0e5781c29ea8262e689c525bb73e7448252fb8573e01b855590bf4a +baa076adee94fe895a2c51e57e54bc13f6e3a38d6139711165f5a9e30454 +7dd0d41d9304739c4ddec27c07c74c4aa03cedabfe7564b14a65acdabc7c +9862b13e58004b27c0e489fe7ec5ea6d0dfce31c1b500680607372bed66a +e33db1ae66a215ef573b52dd07299db401eed536ee4b0b587b910ccc3d51 +72b4ac15489098a6ecbdcbeff2c968d26edc339acdfb7c30e4b13e9b5362 +40264bcc2a34a2eabd641c9e9aed706f266c491b6ac618c022b23fdf20e5 +809f5caf0198876ba92b577b128f81d80affc4b6aa9b8ca747b7832e510f +404cbeb63939b5d8a77f3d7da7f23fb276d5500959a394a2a854da1a361b +8e40d1a0f41fc67d51340d687c2bebcda5bba418694cc392301e28e3c2c2 +3e07aeaaf44970e0db8f2e44e67f9f372aff67f735b1df1a228be4dfd3eb +c0922df5bece2cb1bc8e784331aa2d405f472bb9edb41b80c784f5a7a7f3 +bbda8568b7b2eacba10cfa5728f5a6609ac2a590b74883160cb1f12d1dd3 +6e0b54ce388c5c8f3034f885a29979599fe6d59e93739ff98b2eac79785f +f9564224d6b454fcc2084320d28c900302379475b911dfd9951b075e4f14 +2686a37a437aef3e158140df71353e0f932546ff92b9fbb7c44db1537060 +e94a421164e814de32d1f3d408d4345626b8bee38896ff335046aa293185 +49ccc78b7ecb2d17d6fc255b69c92781f9a561ddd8bde09f04c4374c0225 +7c98e24e2ee407741a8f02b86022d9dcc449b730960fcf1b9b8d65af9e0f +10af8edf7bd3f1cdaa9d5e150416b6334089dc862e3fde6633fad940bf88 +5c976185ad5667991e75a2593038fc8c5edac82f06c213b0da990c702244 +9b767a619bbee9c29e65d9ca53ce96016d0cd40aaa188aa7c60bce101426 +5efd9206ddabb6c0abbe54f1890c4045485d1d4fa003874b1052147cd269 +552b663460931b5ef7824cecb7d7b85f6664a7bfec448a7e591daf6891f8 +f8b0c5f8c824d506072c9ef683bc85be1e7f4e240ee40bb1e23d4e8f6f8a +31f464f1a5d13989456404ff3a50cde14956db3b24e06af7bdb5527a000f +2a853e9535914d4624cd39ea90a4efdcacae7811370c81309ef360021d0c +79f656bfd42ceef8f2a7ac6f6647482444f58787706be9c7ab844428aabb +6679e4b89827af8cf9550093b0f7ea78a53ca24b8c896709ae2213308520 +2c5b5c3e4933092b6c5a2d4ef88cd24697294cd74a7a30571e143277708f +540f4cee7dd8540ac16ec5f4ded4d43dce5f238d2b607d7728a37a4cd110 +879325f583c1b370d16ebfba95806ab62bf0fe931ca58e68fc101057cce1 +be648ba99d6af6f4f288a81a3e75c2263dc32aab93d4ed052cd9f97f2dd9 +127dd32f895a7e760b6c04bca804ec286c31d58850acb783e4227e8fe6a5 +5eb50f6bb9aaa25fe46421169a1088c3a60c3f8391ac822c57a4d83f018e +d339d5a7f91b2a47c951eea90a736803932641837100c5cd4cb6ceffdf15 +7a9835855f53d8bfe1e54a9854d8f7584ed4e97730635497604a9df15642 +bb7bbe854c871575556f0bfb3ccf3c8a7ef1aeaff371875ad23014e0e5cf +a1d1ecce5ac42bb72ff463333cefb2377be4cd71cc06547dce74827a60bb +3d2c920d918f65b0f4ed436c3a39987965203499728d7f0ba4a3de62b38a +2168914b279c9455959c51f2dc490581312d26f39113e42cfc81787cd39e +d884198675298c9970ce6b07a439ae17d346f1a1c4c5417f00d3a285f59b +08be23018072608e8d2103dd6eb5282535246c78c06abee28e8981682319 +6f6da9f6d1552ebad2a28633acf3f26b86de651f5a3534923bf54758f394 +46fd8c960bc108ff9020c88ad0bf94f24f8c444961bf1742dedf34839a4e +869651294c8c9a8383291a5b460416a6c30fc8b26d74744d3b0699bc7d7d +f9af19e6c297032ed61cd9be041d42e1a85272d981176a8d3d028346d2b3 +fd6cf3bfeb759a76149f3c83a372b16aa17d8d13275351901e55bef3477d +d1440ed8509a565cfe0b4b5d83253a7382b9ea5baed8303b7ab5215a4cd3 +acbbd28a3fc24fd8e6eb59003e083c55bab0ace88797a6174208d9adbe6e +e313712a611bdddf09fa5d05b9ab89ad94681b536ec836f330dae407625f +5f7fe3edff500507cd28d86d0f7477ecbbd1085c83a849e50aec49759c5c +193a79b8b1e03e808347eac949ce187fa816f69e6ede6eb795f910dbfc5d +85c9f581621b5b7ea982abbf59e7e01eb665695355486d46a3222dccf79e +fa05254209034eabb0147bc5e21dbb361296aeb014e2a6247166d27e5643 +bfc06ac4b138c0bbdd0aedd15c468eaef74324651aca67c0f7be421226db +7fbf04b2baedaf2fe6752f13d9df1f5e306e539451de6d708e58328d19b8 +24e8ef308d3044f8552b5ba5b31eb1faed15dc9a99f0d46e5130b5e63d77 +c63d407d277491fb9da2671d24e5cdc15a38b267231914223ffb455f7df8 +bb21f965438c3747b7c1f04f8c5a9f7dabe1ea430514733338232567c4a1 +234aa8af98e445e267d39af70e9eb8c2a660a2153cce33abe475b3a894e2 +3c31fb10c0f0ab994c689b5fdc2b6d07a70f9af7fb4ff8b3e34c5f1de296 +8969f1bd834bab5a2626f1f25b196927c680b9438f795e4f1f31c41eabf1 +ede62ebc46ba5246d086acd10d32492a129eed911a18a4b3df792a4dbfc8 +e44fbc6b71d7dcd6de9156f2030928c7d7c1584ff4f534f221377d8b2e74 +df80cb2abdcc685734ab8466efb981a361dfdd859ca67301840f76491f21 +c63dd556d47b513aa6bf56dc427ca6cac22809671af909f87c2748bee4c7 +ac4dba40239094306f2b40e28dcdbf90cfb22e127cd5f27c1d543ca0c549 +963e94d95ca07ff0fa6d1f4afdfeea5289e7a33ab1a3eeaed32bbc576df1 +d587aa9c24af350ee5349f1e1ef906adfcddeb97a8af555619b45a8b7c71 +420ace89fade1f980797909257083e26232c0cfe0d387e18d4d4d10022a0 +01bf7a265012715b0d9cac530d6d6edf2591fecd9ebb19ea15a931f5814c +6e83d63e36cc36521960fbfe697685556376661e354dfecfd153fc87b601 +bacd03b1ca8537cc788c4627a47301175aba9d24a606fa5915967e0c47b1 +23a5a6552e8f0bfd748ea73f22fe5b5de2efc0251da7d2917c60cdedcaec +63e34d2d16bc177a9e3b2e9be7f25663de708b7492eb9daa0e9c7a7a8c51 +17461471a3f8a9d704fdfc6848956f6033e98006d0fb5331453edc8d3854 +143ca54940dd26db56c904839af1ce8f7fb2970308a4d16974163c8c86e0 +a2b3b5eeaa1f4eab594577b76cf35a1dda9469eb319c2668ba7c57b4ec7b +80c413a384127ba4b9291826d4815a63d987657f9ea870c763cc23cb7401 +03ff300a50bbbb30c29a8df5b081d3efd3d8cf64126ba36084fa7cef3f4d +5d4f2d8b26011f854c37774770a6c34ffd0086a50d6b61cec6e25ed85c36 +776ad1d522f0069c6f6fb120f3191b0f4a06c0ba50c29a4283c7d876233e +23c1efa55760ca46491b69a30c8e638279a4385b3359ceb5bc4a616a3e1e +cebee2ab4279c5ccb2aa5b7576d0777215217cac3f16db73fb1526c4c95b +db662448cff24b480b224834f8b2b3e49e42e7b668d95428621411653b40 +6bffbd7cd5feaebe10dade204c86bfd3a3c00c12ab790a59d9e47e7798e5 +8071ddbbb583e2c96c27876dfd40f6ad8e0821267e4f0a574d8e5e684c9a +45a70f999e3ede8b00c1506b5ef0001c28334aefd1f6309cf290ef58fb07 +5379da9fc609c31b1fd0bd33dfae5de4a704e02886a3fda22c0554bde2c7 +1f65880362badfea1471b54c064b2dde0361b586b9071554d77e5c45d704 +ae13f654a34a9d34c198ce8f56be3f99d3c6a3cda12a6f488baac8ff82b7 +ce2b2a341a1eb6d321fce0a1feefb4c1a124a9123f6280db7efef0434fdd +9c1f570c3d1f70855c166b76fcdf37237ec06df0ba289710b1a1467142a3 +22ca1412c96b41beb0003b12f6423fa92a4460259bada3702c21e2bb799e +703eac3e7875f673afc8a75293ea9da16f1f87465a8f0984e4457e967ba7 +c5d265f2d997eefc517e2766382144673162d6f937bc6d075a79e8f54723 +9bd8a42e80a4657c0c927d3e7a71cdb8d49534ce254c1f0b161c6f498766 +d11b7e40bb4700ec8ec6f6282535c78ace3fde539ff76d85440cacfe0702 +265163de0fed12f3ccd1d5fd5d5404292c5137f389da4e05b751c32197dc +6dfe5ccb4d8016dda6c924815d6d80fdbfd04e1357922ae931293a92559e +6122e0f9a1ab493a4f82ac6290f420c18d24287fec4cd41c226cc06f0512 +12fe8e4e33f3e9d53d37e0fc7819ce859f2963e2bebcc47aef3b877df83a +d2e7a1e3bec754079ed7f330f684dc53cd2389fea725d1002530f55c4d72 +ae385b6e836a38d306e764ea1cc46ca00b06c4a901bdd45cd76e45dc6f7c +cc02cee158eae31970bbedc31dabd5fb0dc2e51ff855e53143c726106f38 +084affef8cec7ead3de194dcffaf7758390a21ae63bbfcb18c4db3913843 +5492781247e29fe2089af2c6cc99fad2af2000f0c1f4b5944e15cc402f99 +d7e9eaee03f5a96d4198bdd3dc5140b3abd0b5300db7b40d1a3986d7abdf +b59934d7dd00ea54c9867805ba6a29f60efd9873d7ad8ff52399daf45311 +c6ddbd2963b3dbe5ade0260209f9fc81ea3a88b4024cb17fb8bcf05e6906 +fd95fbc50439daacb2866759e8c8212d0e67a7eb4aadd6bc5d94f8e97f67 +05730c3cd2bbd303d6c1714c7ba641eada96dd89cb6fe1d655f4b67354a1 +708ff15bc6a45245d57695cd52377e7fd3e38f94a9c4da0a7a921b3a687c +5ee8d0bd2b725c95e8dcb582f79ea5d5a728c6691ea47950614c78c4c377 +19defbc6e50bad8165f1ed0dcc0208afd12365e70948d44b14f91bf90cfd +e82296c021aa112364369457567bf58497ece9a36f4058c8eb1713969274 +d29816680623704d034eaf900c52e04975556b58c3ea63e5447c1974248d +713988c58d1b666321d535be0c5f90e061a2a2f7c36c1e058fb2c01f4d76 +7538a6e41ecae22854b83a77101bf865d6dd442f89cfcace8cbda39321ef +bc2b79da45fbb39f2d448b03757310283bfb73b97eeb5d160dc002d178eb +3868a293be770fe4b63c014c1b0bbfdf1af1913cd5480d96d09080225183 +38f18ae7c3961e1d87cba5b6a4254d225a2c9caf5d976f1764a14276eab0 +ff47688a5940c300851424ea934cd53c59869dec2ed89139fed0a1e44037 +9059968726cf1c380890796b0e598e5b1e3fe5998a63224905cb8dbe7d95 +5ee9e9759e0d8195239a359e8e4da5c783ea2d19d0794692f0d59bf50905 +73f7cbdc635429f853f55b75bde37dfb5c1d5642b58f5873d079be65d004 +7b01296394aacd4c4ce242d3c0c37427765a7b1cbbe19f4f9153703613bb +cc8aa6e1c616df576ff5153c1ebcf9f5d202f42c628e70137837e3a33883 +e9fa8f0476e5414cf337650d94b533aa2cb45b7c473f90aa1824c69a2120 +5db7f301e8d2d6652685db61513cc3ad11c44900084623958d419f0752c6 +7d881df7d20300748f0f53e410d534664c6d13b4c96b49cb991ac1eda4f4 +25ad27510d96fe350b9168a536ae9ec6c50be8de32e2ee7fe9f2db8eeca5 +db7a80ceedc96d5a0b96f91930dbc00d2cc75069f1590c81d75bb6f7e6aa +720307776f25867fb62e78cdfbaa13eba1fe184efed5f7091c4fa08baca0 +86bff83086334332b8a75892a5bdc514b75118222bc71b8f8fdacf984edd +d3be4ccd556cc8f30f6a80c2b20c167f577eeee593323e2207694732587a +0e5b016b6ade30be2887b8ed026d2df4c539d1a0308b0b09770be61ddba0 +fb20926f07399ae6c9c937401e1e160d0375a89e870917de3cf496597d22 +a8ac67138d4313507841ae24ba2c0cf8fc1efc1ac5b8bb51ef6b50b34086 +2017759ee174b4bcca9087f5c463198407f41df40eadbfbdd7d73759cc41 +a9a43c50b1a0f17deafe0fa93669cb5b11a17bc07667c357b4a22b638592 +b721fbf505d8de6c7d69496752cff0317194a3eba37f42627126fa395596 +f5c0585cd5e6964a1ef53ca1b8d886f29df91782cb4201f873a7f93a479f +c62ef2013e503bea26d1edbed3ff450c9ad21fc04f4f69f6717ed89e0ef9 +67620edb859bb0d7efa3b0ed2ba5e4d5ba200e51d987b0502ca4b21f6efe +c5d2f471684fae7130eae3e4ed9006ee5cb14e6b9883622872b1be55e09b +e1e49f3bb6bf07630c58c59856f23d1f60d44589e7c959210719f7e920fa +067ad3433fdd490f28c9048cd9fa4aa43d134e3058137a09184ee4ff4412 +cfc204ff4a9975b96af8be17031ffe148304af1c4e012d72fa65baaa96ee +579ab548ec22d8a40e8fcb2c2efab52984c707730953f866bffc31a81e40 +427dcec529a3be22f7772e26ec0fbc26ebc4a3b561ef75e92c777684ea7b +38d33d99d8f7ce4ebbe1ef36cec712605921e0cc42210f738b72b8b06e2c +699d6a786379a2fecea0799175569fe77600fd3fa661f5e9d8e62604f59c +3318cf53e2fafd68fce5448f2f04c3a55b84aee7f2bb12953004aa3b68f8 +12ce7f25cf2f8a0902d38d735a0b9efc4752aa3fe822223a72272763d649 +6a4e82634b8d5d666c22c8f36d3fa25cb49cd8cb57a6ac7b48d697905780 +1e5de91b50dd5fad9999997b63863b73bb9694598dbfe25705b1dd466891 +0955a5e6128769448d35dc0ed21fb4c017d10cdcd5d24b386c41e2d06f3e +3c105edadefda6a5ff6e101613be39ba5ef511793e96a5aaecd41ee1bf4b +85a144e147edecc36dfdec820c54bc5ae17b138bfff4a30b5d10b30763cd +944935bf7d3ec0ae8396f1bdf068b51951d2a7deacaade053d0a3c6a3508 +1f20c1baf4b76838f98b157d9ccd9ffa669302e92886340a8e0032144968 +a3201ec7d3c87d8e5545992b082252acf496eb3eaec509d27d326d5562c6 +862a03829660ae967eca18eb4bfe04191ddba3e03fb6dbab09ecc01c66a4 +4bfa077433a048b741d98a04f7ea5e7d3104e4d6b1b42cf38f5f4821eb67 +32c6def7e2b067c9ee2cb4ac023ca4c329d381a1a7511ecc33b4bb4bd326 +7391ba5e4a88d84829c541382d4ec4eee3a4683f7c0bad3f219a3ab5d0f5 +a7dc3be313ddd434255d12990a7629c712a55b732ec7651b5fa61fbc6c35 +e3f2b7e2c3b62b72c83c67397413d88ae67393e2d8c77eda593f19fbd9a2 +5f69ee9883e02ae7e66dec74f7ec9920252281a580374e478beb58118cc5 +a11c1c20adc018d0706aa360cabb190d3a9a7dce6ee8c68da7a784358791 +850015a3241691dc125436a8c0cb959356f0c32b4ceafe39fc111e6299db +8068bdd8564b1200a62c15856dd8804da7ecf34f7d135cf45614a243cd34 +b4e8531da69a62538e6724ad4e3f7a1e2b2c71e77fc686738a4f1d2f51f9 +770684fa270a94ceee7c5d5804ca49220a463e7df0a63aace3a2c73f0940 +9d002d83115af1347b9909d08c0d547b6643466d119f4296094f4cef0a10 +0eb23cbd1cdc7cf6e8bf2363a042c64d8234beb4bbdd329d620c99a65c56 +04277780c343b51f842908ef1e66b125b65387885bc152b50566da9c8b71 +ce360f7d724821c5a06f98b3d5408c01217e483d2d40063bd2be7c447fbe +b398e050e608d2dbfc8ae8b7516d56a85785a6a63ba1d559976e8c699938 +631b10b5e314493a46edd7df429a7f7529101e32c57f08bba5bb6e980651 +0cc39e14ce46ddb626fd4a5b0e89444409b42334e7d6a587836d1cb0c096 +293b0dcfec87d73dc4e9f90ddc2c312a021af05b95f32bdc4b9616fb6db1 +44d76a2a29e8cde277a703362088a76db6413c840661b3aae45ee5623158 +6c21f8ffe87c30c2f00b6b95537094973f54a5c15375e6549fe45e2e020b +6fc5f624e8c3a9b30d73d0a397e5a32de1920a15997b220276ba3b9d7019 +255a884555b77bc27c1241af0af4d61d6c8a4ecdbb158d86e21eede3cc6b +28900b71ac5c945e596c9a8546ab01125f8ab5fb17c9ccf75a8a334aabd7 +705a2df1165c97c17ed678a1aa40fde4f4a62b503099727fef5afc32807c +051866ca6f27ac4729ac0191edf00281a914846ea08526ec0d6973012851 +e87530591b168b6cd69b0f44a45088ee2ced5d53e05e1ba563351c992222 +f23a58a26be2dcec43ce16e281f79184fda1c9e406044127091d5728d7d4 +0d6906e0f528e12d8f82a6b175e39bbab45a9653b2b4bbe4681da493b3c1 +6a20e5647686be5b07e7f41049a2644befe28a100e4ff5ee34105f736e21 +6fe3e81a1e7d2ab8ad823bd537c4b6c2bd9ee406167117c8b3afd2caaa36 +595fe353af33d30606db992f4dcc8c74e1c1b5ea0eb4722f6c9d0ab7aa4e +44e61d64ea9cc3ef637aae540d2d0ac7d9cb2dabb1a3be34633601a52d20 +6db35f74f1481a54cdeef2ff63bb310283619dcd7b2d52087cfe957b931e +7926efb5c47bed864f5dd8e7e5583ad66b34ee5133dfd7b88c9655f196d4 +d5c2d06f478c895c46a27f1ef802f5126477fa407f80d4d2cb55119b8cd8 +72272f0ae88ec5c315aa469e37cb7af969d8886851426ae3e6ed5bc44813 +5fcc58282fb238672563a96f20c2d38d6b6e431af706efe5944f675cd169 +9ecc46444589b0b4ab41c5387b1ae844399ccbafe4cd7772d97448eaa402 +cbdf9f7df550aab54d47e2f67d75f2c364318fad9d08e47d1538c7af06d6 +01f0c31ca9295849f809e6ea17a113883b5e192ba7eb3f9a0c6b55159e67 +c0c085fe7ce9cdee489fbca0662d2ff1a6d55f8a1ee87d0cac3b46bb4f8f +b58dfb2cf046f530732af1cb20ebbda80adbb95dff7ec28b57355ffdd42b +aa7bb36b277e6c76f1b1da390c3788e42fddd3931785626db52e9406d887 +adcceec2ac6ee736bcf3454a8b510718fd0f429a3e06dc3ec9de047bd9e6 +0186657b1252647cbf3725767b143ff9bdc0a7b58ada9d94745e75b04cbc +dd755e2c1e26b0d6f8a723a04e04bac494b36591aea5c8c7a8388fb83e24 +6f983f509a0e9117da0bd21078c3bff245b5e478a2b7331e4f3cbddef0d2 +0020081187c2c9dd0a591a380bf3f6956d7b8d65dc13a2d586da84713ae5 +5b745853aa09b3f3b53de393c03d4c8fddd829d8409c41e967b65a00690f +9528cb18b3fb94b559c86a820f1792e58bbc45aedc02ebbfa0840c8e7298 +1ecca6988b7beb9312e863064b58618eb1cff26b4ddb52a56ac4c364e30e +fc20211d6f102622a5378cff950b1b38b8852423ebae51a605487551e4ce +99484df76277917bee1933a1226fa1026b6d7457bd36928079c5fc2bcc28 +aec99667d1018da53c906f22b71c52c9ee3dc4e72439155717a6d44510ca +2ba6144601bfa675c5253a4443e18350c6b7a9bc074e8ac973e4b619562a +43a13be8d31e34af31da70cf8bc39909ab80c03e0dc7e8425b1fdfba898e +352aaa0a1c4c38c711b3c3ac60a7725e958c0974908fa30d06200bfb840b +9089e9caba0f3d9b00232516adcf252ea6b73c178e6258eb6a450d29be8c +f6f66e21d5309f0b75b49fe6abab4ab07e48ddf778e4fbe197481246d680 +e9667c7dd1e420257db762dffe7876f6f8e305d668cf4456b9a0b8ecc6e0 +1ff973144f5527a1e6065d2f6797fc3accb88e5e52dde221464fd77823ce +f7a0592a408cc0eb37725bb339eea0f792105788b2ff981484d6948d15ba +51efe3eac600c402b6ace16d145f96ee75324a69a77cf8dc43267a56cbdf +a156903d2392393a8f12f33ef33f9b9aa7a9d95adf7f2368a34d2c47bacc +93b2a3a90a1260fc3a334218bfeccded1d7f4182ccaa9879f6e006f2fb70 +20e1d1915d4fb12cf20695075276d27ece002865faf6061edb14d15bb434 +e07197a4a142ea659c24098088be777eafbbe50f2902c12f6fa8fdb57ce4 +852442bfe16a25a3ae9a1bf32486cc0448532f53f82179ebcf0fdcd7eb36 +ea8b7abcbd95a6e67aee38823dc6323862294473982eeef3fb3eb510183a +7e17e3f87b012c485eb8eb8760007bbd1deaec08106cdab59032ce18aa0e +81efbe09c87a9dfa03e6764fbbae08e72021aa9aea46a48040ea48e66a02 +86747dc4636f680606aaf29bcc51943fb09b805caf1534a65be267b94f14 +89ad6e8101b9101bedbaca870fc959ce28a2f84e02a88471eeb503d306b1 +1ffcd998ca3e4391c188f6d2c7cc6e82475aa5c375d2d1582f98fba2168c +4bf25dc8e2ab69a52fa5114b519d1599fcdf521bb4008acdc91c6164cf3f +e4cb77b79ec74b62053e5d546ce1fcfc380e3c0cadcfd0120b5e6c359fdc +2a4189d6954ec7d35510eb09d5d305c96e482431505c91734b965d773e9e +37797951ce86d4e2db76075774bc94da133540d566470e678d8e92cbc97f +567c8e3da28f9e720c807d92475ea4b5a8b08a7b4ea42e77a979b0380eb9 +d168735406795ce1470a0eb315e9945afc15e8005a27304799434b75b606 +6d051e712b9b92d82ab3fb8907c5cadb75eb597330fa7eedd1645270a80c +602a2aeea063a0af3054d28cab345e25c6171da1f0600a4b7bb1fd40e4ae +eaac89416009e991b9c549ce3d9e28fa3c611a79a74592a4f48e5d51ca4b +b19415e2031e6d3f5b6279ba838d9c82ed40326aa42d67a89f5555cfd429 +9d5d99131ce2bedb3c449989214adadd8989c4905e22475bdbb813e7eef4 +794878a7a538d1e0f831d75e7654b981cae483b8c90f5eb8548f76684796 +ed8ecf0141d598d029de8aa959f9218a862a10cab525ff8dfe060d197450 +965dd3990f96833e583302f20235ab7c04d94d0646b1ee4b2858cf9797a2 +83a9f0b2c9b3695faf00845d7da408f5cd55734ad74d160e97432d3d0598 +1478ed7361754488a5cc4e3f7ae1a373fc2bb30320aeb8baf42864ed7fcb +4022afa9082a7f0d407b17a7d35e4f7e770b7ffc03ff4091ee9a9d4fef2e +8c745f32358d89f02782b2e50b265c68455c71282b980c51fec4fa7e85ad +61909862295cd90f0ca7efc0833d9e70361f69a83a5325cae0132c90076e +fb416fda2645f347f9e29f7e3b200980dc3213bebc6ffd5c459b8cadd0ee +530340f8347db627c7a06e682047a84c364d074a330fa91aa3203b1ec8f8 +a96cc9c50b36bf7516b8b3dfb6fcfe504ffb37422a5d2baf01ce5297c38b +0bc1a7ec3e3570c1dec08aec7991ba2c8907d20972278d2edb052e40efff +9538cfaa17fca6a50c22cde6a29c3add743a7200a4d8997624e1f7732c81 +3546f4bff9f01c5a9404e86a2b18f7b6759b2878aa4f8a8ff55b36a471be +7f05d5884aa0bf088b87665901ccf35e8ccdce86811c5c4e4f55ca26ce2f +10b667dfd50e6063e9914d8340d9533bc0ccc8ebce39f45d3e442eea4a99 +a73e5b54e88969d9d7ef02298c40f600bba274a911cf19532cd01447f05d +1e424ce654458661d98d4cdc1a747224e90e609c3faf44bb29cbdd1e9a97 +5b475e25ef46447f43809ba72292540cf81de6cc751aa965142705082524 +6291840e4f1a9c6a452bda7ce29d9ef68d0007e7217dfda8cccb40053081 +c4e912ab4a7bc5642f898567fc1604c95f35d8852b7fe5f87caaf247623e +b6aa53342d231a5047d82dcd33c96b9197b5a41d82acf553f3186fab015e +9fb21c681ac874d236c9382f13fe672ddee53309b5a46a9eff196b426e21 +ddd39784aca3f8b90588ac9b04b993533483acb6e3125a5d8e95650b858d +4dd01704388890b26f1e707cc1178f545dc4a3cdf21a9730d3e6d29b6000 +66310e49be5018136fbabcb028799b74f7f15c47afbe30e14bc413352450 +b3fc874184c5e128032918845b039bf2dfe29ba87a2f25a61e6bef64f2d0 +64b1cd13dca3d385443df6d66ddbcbf9ad9774abfdffc05f1227159b8acc +8daf7cc7713e7f763ac899b066683a3fd14ed9c78e1815fe88a7926a8d3b +e34481b91febb4c2af569e870da8f964a78b462a52c9a971cff4560a9a46 +2f95d49f759772ef75cc1469fcc61c9ddd6c90e68273e1b02493bf38ff9c +114d75e7b84925249861275e2508856a86df8e23f590f2e5a1d2fb10db73 +ffa35dddbf1abb002c937ba96effcb828c7bad6eba66ae9337ac5210378c +3447d9b358a6c449ca1ca82712c422173893b9605a3f1faa92946eda7fb2 +b8dd8ed5f4e5c60efcdf38a92739e16ce182ff777729514b353265ce21fb +b4871033830431ee72422084a67dea902e0eef97ddf955925113eff9548c +9f956325a1ef9dc75d0570f42ad14f7dbd09b2578332bc70b0ee8a675d8c +00e2457576aa2a28d82686773ccc7c89423caa6411fa59ffe01e04f04b97 +b322081105bdaa7e09ff85f9e7cf33756d4a7e2542950ce2ae3acaa62c5b +4f1072462370676c25c413b1388890cbf64cc9e21a5844e30791e9cf854d +bf6dc8952f6a629ec08cec95dc9fa1eb166a50d13503cc94b4d9be0fa1f9 +0d8c914f83fe726806be5492837abd211c18f82ee4edf985e12df873d90b +50d46f1bde2eba9d1823b48e8c67f8e3452600466be39c9b0ab5ea55a9b6 +d513b025e199ceb3d3eed9f7b12d4816c1376180f5e3527b326cf112d138 +bc925c67b4079832dc086e2c539de03f72fab6f09c92b8e8accf2ed76a5f +055241c205f112686449494de69d6dd01300269b1b054456703c2e82d839 +0bc7d46b87c2f02e65ae4a1d4748bf0f01cde328bd0befbd31c3bf30ca09 +fb3c18524bc7f61cf2e97cec85045bf8ea9609f3644ee77ef01bf5f3d8dc +1e7ff01370c4d007fcd06e7b0b0d1fa190784e9c5e4c93324cf4fe5eed78 +11962ad08a13ef0fd2990737fe01cda020105153609116ce605674d0470b +438d73f3dd61f3b0059f71a291f32cf463c30ae38c20d2f4cd52bf2fded7 +4c59f19d7cdb97a0dbfcd13877ae4023cf7ff1db8d7655fde46f3aabf95f +5c4a3050c3f9c35635925f06e820e35899839043fa416b4fc284ec3e6dcf +d8b305666b93a072e263d0d2b1dd85593a6742019b9aaa989b7307afbdfe +eeb6e1c2429668c177aaa0aa2f4e27495b18188eb77b93f37348e5e9f1c3 +de961b5b67b109305d84b1178d35769af4ab928c2ff5773fa7bd00ec7435 +87da5c4cbc19bd3cbc4f7c15460213c9103bf7e1bcfd8f3899422f83461f +7a8c0b9d111f64661955f4bdba28783409f6cf5d54f8c6218e0797a03470 +2068423a4bfc1b19d0be336d990044f084466a2b2d4198476eecd1309e2c +30e33e8db6202fd31c1484f531056816cd25b80c4b6ed9b1ffde608ddd16 +84450eaaf45d813caaf938e4ddf3ede924a22c8014a2633155d90ee23acd +02ccd37f0e991080180191079eb3303ec6c685685debe2ed67efd2461abd +702402a4277fd06381f9165b872f3c77a8468413a5a2dd02a61fcde44538 +376f3f6d3cf72d11fbdba81c400f83e7ea6f4386911b3874557af334c774 +0a070d3c19767476ef21dbd9ca66b74672371a6541a9f3f30ca4dc3afabc +ee30997fe15ea3000f497b4456d219f8492ccdff2b0a8f7b6c865cb890fc +075f715f82b6fb531cbc68d344cae08ec83ed8773be6d2632b239763e463 +2307b3207859b2bb1ca39d13bc2763d127339ef4ae22e91adb9cb0b6c614 +7ceea07996afaafa19e0bfdfdf9eb0ac43f73d80af7245d80c5b03047e4e +0560fcb832ee1f8ef02d4054e72879a3fd64feebfcad750abc6575585ad5 +9d7a21681ee427052ab95ccb1283d2f750bdcfcaf1e66e69c9900514126b +90abc69efe5c976166b8c4c0e18f94ccb014a303c61b80298c661a6642f3 +af81766e7dc6d699a7780f93a538863349dff728a0557f30f95cc2b313df +c4c8f12e2a94c9e3f324be1b98142b106f190e30783b0858aa51e9ca230d +d649883b6f7c2a8dbae39908b34b60a67b147350bf8ae770619f34f9c604 +c70086c8aee426ce5a92fa9227fb52ba82fb17cfad27eeb2b5efd0c706f1 +462d012447ae3f6837311283d7abc3e866fc68957d3cb4f86175c924218a +a95f7593c4277a7d0938869c2e07f10446f2d45ea9a2849721de54105611 +b086988dbd56ff72e85c4d01addbaac1b053f9a47dda22ddc6f01ec98df4 +0c74743f59d149eb35b71e55e74b5babd36c0e4a24ef5afdb7dd3823d725 +e294986a66bd545ccecc5010f8a6ef2eb6047a74e68cf2623b6ce84e6a0b +37933fd249991b018b0b6217975032700c81aae0722f5d915654cb9991c8 +0a61625b3742e76c692a042ae42fb7f4ed355f6c3fcffd2acc794de9e08e +9dbbd39559620d2819a23e85f7498f0076b6230b7f93de99264428ade3ff +3272bacfd3b52ffd92280e1d1937971e7243eff8038483de1ac2cc000fb3 +94315c35da446f098ce72e8a3f892a71514426abbe6baef9eced76ff16bf +b30e8647f0e6ca67a987353c5f8848e036b54999b10d6c7899809ffc6611 +76892d7ffd143dc1b0978ad2e6816fcc5edefe51b609f1364a691cd8807b +4e96348e9842ee5c2457e266318d5362d78c17b303d4cda2f8dc91715f0d +de5b76c38636605a1a15d1be95d9f23f12fab5e480ded3fed2594a53f852 +1b022aff4c1ab2b44b1fbb6c00286c69375e9e0be730676687ff60d6f2f5 +6f8a75395e15ce545a0a1e5fb68dcc2ddb647fe9db6169af984829859bc4 +2273a34a6806b81d7ca4ded3922cb3e90d9c699d576904132d84c69ef793 +097bc90c59a103249ac49fea69300402e5db75b1d6e36ede739d91bc6d83 +042db4ecaf5e68e78bfe009a6a6549bfb7d538fa5ac80e27163680d951a4 +8aa5420935d71b66244bbdf4b265869761c7aed028429823f530138cf17e +851fd33eefcf1cb7e3a55798f149595f946dae333f37ab8cea8846ab80b0 +fd354404b5e5eac4cfe7e6c3e7a66311aa8d8b94e8c59a1e0ce7e3495b17 +6f8ee8ed14c1e033fede44f86b1a3017b820d60d76de408b6b01041c49b6 +9c715c484aa6add4dc3147ec63e3172bfc2380535e2639d41537b053a880 +e99de5c5bdd8c9672a2c384ea8604454b6056492cc866c2fe2f1f9556930 +edff9c6db7f08d70addf50b736c927fcbe4397a572d9aea57a07c4dd6a7e +a02402fbf21d7281fdecd10faa6cc51965fa70cbd682834227e45cffd154 +99aa79774c99c0aa9a3141a222e4db99fc4a91e54980ec9c2b10ba3dde47 +3c402dd71dc879782a29c0f75c1b954c8fecd5c181cfcc5bacb3edc38b71 +ac74f098fa0a1f0003297ac9209e4ffdde948f0a2350cc846eac61707b07 +871590855e555d395efb168a4011c969ae12f90dc87a38e5449fd300f611 +1a50af202f1d5ad3a62c71cbf636d82c27c35cb4f703e7773ca334b5c7bc +6a95cadadcb55e9ce68d716bd77083855d0b2a672a29249740977b7d848a +34ad833a1d9ddd4bd81e7b118a62e30da770bd8b2eec33ad1994a581c836 +ec81f99243a9ab233b9e2a0f1b10623797600b82cd0569a2da414ab651c8 +d6f47c0a81959886555a46204d74cbe4f27de08a4211ad764b9a330e5b6f +ecc9482c391ae086e7544ebf566ba40ef67a6ab4526ddfa4cb98733cca0a +589903e2b5d7b82364b5714d7b70e3d94eee6bc2786653cf6591f9feb6a6 +d29b3892f33014f2b0227706136b31ec68ac6cd68d556023c8054d8f0863 +32df1ff38c028101ed2db0b41b610640cb59921ba2e251bf8d6bdb3c8eac +81892c19e354f74eae8ce11d62ae12dc2a3ea97551467907d10381e4df58 +47ffd1046ee994902a4c425ba917f8704ca654cbe93bd04c68b40cf79109 +dd2bb3720404239f5a76119b63b397252fc6ac606fdcb408bfba0031ccd2 +0ad3e6467a09fe11788d91e0805912389fe2689cbca103e7d10bd3784540 +7965f250afde72323921fccb7bdb1196d81fd49f3e99a875e301e683a37a +9a9d95762613561f41ba1c5b7c64362a508a177247ebcd63b618577d252c +b442801c379ff346236f4d41a83a1adc16274ffaa4b2f95344116e710b11 +9f0f0a1d66f84d0fc97c6060f94ad6e72c4b821d6d7810a24ab2eb94db25 +e4cde3b5813cf90da162659effcdd3486f8e451dbdc433e48bea1c5541b5 +cb35d5db507b69397bbbfb0e12cd481f21d100b95d20bf3042a9475c9c9d +d90d8c4eb78350c96dd2911d15edfab3b465c7a76963aedc862ba628556a +993b335739ce074305e6dea405fdf5d867587b750e401ad170fcbadf948a +b92f5924fbca8dd8659fb8d88fcf1044095b3d3ecbb88f4b77070236c514 +386c6492334528dbf986efc85f9f8e971790d275e0c7aaf0bafce2f470ad +039413ecf2b39d846949c932346a1b04452ca11f6ce36ef32866ecb65012 +55c1daca015bf142bf33956d30098388c817517df95d8d5e51062bf2af3f +aa3a8f0ac463725058f1eb6943d6d0a178d690eb13a9ef87fb1f85b0fadb +8b6b2709aedcbbcb58ff7ae6c58370209aa60b152feee0a747b60f0b4252 +2526c78231d792f83bce107ecc4e8322597511c7fafd5aba8b3ab0f51902 +2adeed89c0e61c899eaf7e509a3dabb399a6f4c5d7ff9a68b50afbdb67b8 +9e4c7f39d6574fca0d64c4fcb0e54c1589cef927f983940372f6e21b083b +7bf5a85fe09992677eb32c9fd46277c50fd992c478c292af7e05a3549f71 +2c66bd2818b827bbfde2c481bf489737a71e886f37082afc5a8c0b02b7bf +a7fc894d8849987758a4fbac084708a62969d7192463538cc4cd31eec7de +061b00da5a09cb1eb97e3c9a2c2041024a620d7ae2baa99cb070fc01bcbf +b1243ffd06a4c9ea6a4d4df42f8738fe52a7252cde570a7296aeb5ed351c +d4b2f6438812cd61910a4d55d772a881cb186d3a3743cc132b27306bdf60 +c3ab4d755e3eff8e10c2ca2431a50f4f4b3bcf60a5112a8ff91bd51eb0c2 +c144aee9e927858826e203226987b292c1d7f8fee533b57a9b055084cac6 +15915ac3a5a827ee04d91fa9e9e267e3ae44ef1101491a27a07129219e9b +4e20792f1eed42d5ca89c4c49753af7078b6eb6e7a56fff7cecab396b839 +8afdd733ad2884f7bcff5b42f64b4b056a709d656b0d5eb40a76a5f665a6 +9bdb25e0238aac35c5c0caff832b98e64829319aefb07fb974036e0da982 +6129db7ac52292770facaf02bd6afba8862152bf4762425ebbb22d7b6f08 +d29928a53b11aa35516eaea9d249509063c539acfe3954e1f965d2714b86 +257e9fce32cceb0a50661f875926ad7e57ea55aa202f62f88d51a13e6b91 +19391b0753987a5713d7cd96506cd2bc9d9a549e6b6ec7da0d24de9784ff +7538dcf32ca736754cce162d2008a41fa1c7999c2a8f72da2c517e06f0f0 +77bd88a2ff890db0586228842a011420efe3e910024492161eb477fbdaff +af1e73d24b75ba72be5c14358c455d538585754e9f6816a226f60e6d17c6 +6c941f516c1f05a618c022c1a7a8874cb0d3f7acfb6fd79d7601ad6dda61 +1d31037f3739bd128616278e7025ca836708c855dee5e3b449c6c5904b95 +caf4c2eb09519564c48af781fbcc49f0dede6cb2be8718c515c05608549f +d5e54831372076250be22a0fbcdee17fb5849d30205e347e63b8841d1ae5 +71b2c372fd9634e9f16b4823f94dfb807b7c09840f92409ed8041b1515db +9df22187451f3e3b42737a11611a4a942dec953cfbf9875d36a363e3a2d5 +05d96b6f8f03b7ea1c251bab2ff79dd8cdb28796d1fd364b1103da119bea +64ac34659023685fb8d5b2755ce523b32f8532845e4c3058036f0862cbd7 +b7d4dc2020f7d29640b5007a78af6d931512aa015585bf80da89fddce137 +02efaaea51c51c856d7c8a7f285a997d749ef5fddb3eb145f51b1071843a +ff486c7ade3943ca2ce5387215faadda2db4143311617f6281fbc3f8d261 +0272cf235564703f832e85167cb444ed147fae675654fe08945694f9e63e +3f1fc2f6a64f6e36c0ba774a8b20bad6115ac54450e32d35031e7555481d +cc0229df599951e758a654282dc75e6242e141a3156a5c98c533228e8b51 +1801c716665dfa23fec5aa20f3fba6ba37fc88258dec647c3b4c85b663c8 +30d763aaf568bda38558e4314b6b510d974d9f21c783c4498eed62c8db29 +bca222f27910b3d196c0e8502b234a739da32a0f6414bfc5e4c9cc167989 +48f996f1b30d1765fc99751beb12168832b5f7f91a7df5940eb763731f69 +939db425ed380c3ffe2b415a7e960055bbb7ab436e6b8cd66a12a6662cf8 +8df26c3890beac4b2b6bc3c075716614d2045a180905eb9270db0f8e42c6 +c4114f285927bb03e92c3d9301710dcc17190a1f78151388d70aec38540f +031e376d8f31da955938b22196ae56776826c7a658822582a538aa4752b9 +694a5e814ef39c1df410b75d00cb9069cd47b8bf1838f92ef5a1b91daca0 +2d8798c1df839c2430e8d0284e1d16ef72b363670ef519d0d06afe326f37 +ea048fd2e09c151103117879c2efa268645584ff4a1cd478536493adbcb3 +e49e42e7b668d9f0e77ac5a321fd7f339caafdc93267144f9467b605c869 +04c3d1b86bc0e1707b47c3a4c1bf991ca356fbc32e635623f44276cc7358 +da5441438b5fcb4a675bd60bd112cddb4c8357595f7af082af0924123e67 +3a1e74214e7e4198fde4aef1e85e129b6a78a1e975978ef2450c63232588 +6da46521b93748413e02185ee061648cdfff10ca5249d19faad78619783f +c10cb77554bb502a640e5b243c9e90ff169a855b65d29d25b4d30de4e53a +139e8a20059cdb796369ec40057f74b7dc4b5a4d3dd463c66be4e8a0026d +ed6f0110c45baf21f197b649026aee565f47c27a4abc1553790303bc2b34 +adb7c6e54723794eefaac4dc7145a7c3ae16c6bb635a704efcb2b9bb6516 +7654245ae5d466b436232a47d9a2247c3a5a4ee9a7e6f29b83fcb9d7082f +aec5caf6b48976b000ad92199df65742cd8de4af0541461fdf07f44e9117 +8e8ff2423e01074704dae7370df7080d1745190cc29435f187afea37e30a +a2c5dfd9c4076e15c1d80b688acaee8ac7f4f6f5b5a2eab3978da7c77958 +719c696d9a545be2d44b884eb94e873942cef0ff497450fb0ab21c392ea6 +4cbec0ab283283ea4b739e36f2fc145fa57eff433e36fbdf217db34f8efd +02f7a15b77311a506749478551f11e1cf0c984ebd27eec2197babc950624 +2f7c425bc0bb35a1d332c3d7442433ba809a15a50a6487a1cee900a9b604 +747c6821512b934578bebbed7d35d92c35be3ca128dece0dd8e6d61572b5 +6c60a75a230932f6c8f13a0c82475d819d419849c046beb618ffd2ba9b4e +35593ece10ebba2a923648ae9d921255277b6e8152837d74782b33ff5ad6 +a07d8c6c1e59132d3e5e1f1cce864fad1f7963b5017c7ebb3d29f2af65b0 +dd7322dd6e94e812f0ed2770466a41cc40a6cb57453ee0de32a633a867d5 +fa5ba2b86736a2d2c7cd94af3dbc925dfc2ddfeb04f40481507a287e1ced +bf35ebfba94429ce54e6b636c33d8821708cfec3a450e15c393b5d5bf7cc +848c9c5780dd966d01b34db5f9c3137fa0096368f2ae8883e62cdbfc6132 +f7687fd1e9614779274f6b92a12a6d4a8c415f59510913cddef67685cb4f +97fe0f7b8ce990cae9d8b152b1fc223360fa5480e23d62bfa69df11d97ef +8b9d4f8f047301f5db7ee34b4f3996a6e226b8b932a195cc8ecdfbeb34cf +2bc204769a1a1ab2e6be18d156d3c1b0b867ce4ac4e57203585f98ad8ad4 +a1c2cd9823f609af8be966f7cc89e787435f312b7c67c2f9efa22f169a5e +81c8f3de74afd45675b477ae9df1983de2474729ec80fd5646058051d8f0 +9b253e57be5540ba0b7e9c2a588879d45dac2e94941b47052295ba2909b9 +1db7313ba5d3c780113ee736ef57d7a9aa88031ae61411f32ed3ab2cb97a +978abb27b822c44282ef5168148fc32ec991f705288c8cfd6c838a37da4e +2a5dba5d215739005fec9ac00c546884f860db130cfcc1f181cc5f913f78 +9bfe610099cde584d5dbb15604665617d1359d611049eff679aed936aae7 +c27fcde30555f0ee39edb8512bde5007aa9b1bff6a4b6b56e883bd284e21 +3602dfb4465d3111682d4e2b3e339fbb0e0455557281788a6b55eaa5881e +62ad1cbc65d0ebaad4a5600899b9320a0fc98e8ca2e7967c6c2ce48910d1 +80bdcf2f616e7536f72797e3b1bf7d4fddd08179f5f3429bc3885307089b +9f4dafb2feaadc8a761f6b41f9d7e6ce750d5d8ffe999da55dc239933bca +1524aa0078ee24881e120d774b293f1593621230fd5294428653eb453fbf +97b275bfea389bac5e8ecae12389b15f64338a59131f6abafe3f632c215e +38f97abe80d3fc93352d0e27702bf83306a03faed8f89160416f1c3ef5f5 +388f2831370b64bf7cb737af5ca95a8023815a222be811b4b85cf52beb04 +6f0c4587643fc0da77810a69bfac4c0a4a71dfd0c0ab2d5635020d264958 +8a8ad4e825478651950a83d5f0f2bd8cc31e825074404d16c05354d18730 +fcd42cccd51437a2f2a90a6a9e294d30a5f5e53f18e53ed4b60f0e0f6159 +4fea136f2ed0c8af5ef7cae946b33a18d9e2d0c8b8ad3ff0e1908d30ffcd +ab58a28e59fb12d1f28e783ed58e344e9105d9bdba8ecfb7b0df61cb7f43 +7924ff7160563be7094c769f36fab8dc74207bc789eec011e34ef81e3747 +8cc4c9d5a1118ac0a685d25136f7e295b84c060f4fb63ae4cc8af1b96ada +4b183b054df7ef8ca30aefc9b0cd2345b728a622e2424ae0aa578c065e58 +e8c34ebd2b6df648a9780dea293977946a9a3cd8ec4779f30f8a4b51000a +55dbefb328e2d5098dbc3f9859d49a463fd24cd8c28ec426088245b09080 +c79ba43fc46dd55f2ba2c190f8c13b0d883fb6737bc0f9acb5f0ac3bfa4e +8c346ef5d0a9a617bfb9e2fd9fbc68e39401d5978319fe5279108675e8e7 +68f42e01a0b8c133db1c8be7e0a553ed1c1676ed488b0583a3317f233f7a +4335b7b4ee205d1d324957204a51a0b37241938fe2a54d8aec4a81493384 +590432d5afadc3a84b4e08771be80f2648acf9fbc777a51b530f0ca34fa7 +a8a8a1cb391d0db8f09f10bdfc1935204231718494dba12bddc6fffe20d4 +f3b7062feec978a0797804898db2f14279363b72708d6e7fdaef71aaa495 +ed16db39e5ccea3090cf20c2c0d66eb908ec814daf3f54b4465956efcdfa +46071a0eae7ab79a2e227f8b2819c1c5ca018646106b35303ecbe73d4923 +8cc10f3bbbc943bfb7d547132c4debc1923df4e8120a3226cb99eb8ef162 +5468ab720065d6baccca3bf4cdfb2f92b61428b033f26b985e8411820ca0 +cd4b5304516465f29c894a6c1bad8942dee1382421a6c06076dd06451ae5 +83b9e7abe0e273365247fa24cd68e9b220f2bfa35adbd60259f5a0de4b66 +0b0241841e2ff4585c658683dd9e6dc847000b238225990820c1faeef4e7 +39789b9e44ab037730dc4f6c60db05e7847360e44b0c14e59af478cf54a9 +670ca35d4ee3e3f81ebfc58043478199aa0e35da74b4ee11c01178e44235 +2eee2f57a651fb1be5123acc973848dd79b1bf5b69dfc2186662c9a54817 +c33cb1a6b589eb64a5885ae8ed5e8ffce9cbc9f1d04faafd0274d5702c22 +09ef9e52b357e22f458bd3beb244fe88c36d088dda229e501227caaa72c5 +8a7d5a95fb1d7e380819daaba59d2eebdc5f7cc2bcc042e73f13f2dfb19e +f5ba70d00e74bed0ad73726dcccd7b3ecd016dc010185bc34aac6722927e +c4cfc8d40d5b88cd5f01f20d1bee72b715b9d4931d81dc972c59b3124ca3 +5e773612673e4393de8b93b9b3c6b37860330700514cd31919f42a28f9b7 +c81431ac8912adcae98269d6a64f82228f0edbc59de4f69066c476fe351f +9869a4bbdbecf649a2e35d019e90a1d280a1fe55bcf528158ffb01facf46 +d9f6eb0266149ed40307d9b070ca8c5e434cb7a555b74d18a6069784896e +2f250369fc6b6fc426773c64f33497abae8096e2499bc1f5b087f086dcd3 +c5bf9b76d0f50fd3267b319b8363f14a342a90cf0236e8bd8ae8f084af23 +7d04e56efbbba1e86d352ff817c67baa3be98fe63fc4d04c7c18a76573b2 +c66b347f7548d79607b84d90899dadbaaeb9fcd37b1bff2ca865baf35c8f +3e4be98064e0fe57b8c9d5caab1aa997afe6fb62530ac8833236d5ac7fcd +65dc18e1e02d059179ee02c33cfc6f5dbd06091d08942f420d359753ff2c +9edbe16cc23a97cc6b66d32be0b41e0dcb983aa1cbb6534a16e8f6e8b242 +2a95b880c61351a76e1d53e5bfa9aac679b60a7f9b2dfdec878ebb0ad30e +9b6febd33f986526f03e43ddce13ad5264521a8971752c01cae738ec3bd4 +e556dc6bee76a8850f0ef738980274448a00d8681787a314dc6b1cfb81e8 +3825f3b04ae252ec698187d0a242389eefe1eafc054c9bc0c303a8ec23c0 +63307b21b2a98034f6e7c4758be50cd35474eabf2b7c4bae6ea1cd50883d +62a38a22819cd666ac6d2f39b1fad6fa4034416c03d9795e4caf59215672 +f2ae88619f172c311a2b7b301f30cc312530762aa42361dbdb7640342928 +98955bff38fc2cf6c716ab525118bf0b7257317c8118e9253a1aea6c878b +c6377d6428e8ce5fb78544930a46d02b4b08081befc78402ca444c742c20 +3dd1fa3dbc351df112dda778b1e5c3984b03ce9e7eab15dc48ddc469c7ef +3543f8e19533ac32a3f6b8b12103582303cb46086d7eb69917b9e22f92b0 +7f794b80f5b3a32e44d88d2e66c9e41dc9d60e346e0c99ab6604bbea550f +be4a1d9656d3d85cd9b8d632a1354b76dea1d876148d9bfc6d7108aa1b12 +6c17dd16a3913fa263fb94274a2aa4ce87a122d72770f3d0afedaccaa121 +bfc2f42f7a0ad1787bc858c3f6ab8cdae76d868aa3bbabd1e166a7ea0560 +8e5eb1068d4cf2d77264218da1ba33e4f1cc3d24868768747fc08cdcaf57 +c67b2498246d7ff6f33acb2f83a970b6b67aee0b2fc0b76c2b4bddbb9b98 +6c5a0d2323416dd954f7036237b18cac8a1ceafe4e6fa1d2396b487a03b9 +b3301ca9b795626fedb3293b364fcbe29b8e606f35863284322d82bb2075 +737e8062454891e245e0f1ec7743f1997b3b36d24d94f69be4ba218a9436 +466b79d816e6a72c7306e3c2711849e9a941983cc589e2f19ed18ddff751 +36e253edaebf57b674134684d1faa21e014b9d5475ae815f56b606ab62f9 +ae1c32315a1448ddd4151d06f4aa1347444d3240df4f82f9fc5dc8709112 +938acf9bb25e7a4b0fef0dd2515b15dfb40d174048ed2a3d841bd0e6c821 +e07c5e959c17d6f2ba659d792c9767b9172453ae9c415a6aa818f3999167 +790321df7695fbea76ec20fb60b516f84d59bfdd09a2fca1bd5eb3ece33e +51ed225a30c349fde4336163d79ba2053343ed04eccdf8453b33f9bf033e +ad5bf59225856d7a691657cdfe29eeafb146f41d4cc9c8d4ae0d2d287a93 +c16dc85f7308390929bef532aeef8770b9af6ea7fa5e6e968d211d1f0cee +98a09a4547ad609f62dc6b5ba70b9a29ddb3faa15102a56a017b9fdacba8 +955f687e2d4ebac571937740f1c6a3e5d9584ec9d7758fd27a467b273e5c +5d2b49a10f4c935f76a0718347ae59f9f5e29e8f2695664cef0a10112636 +48d486e5ee9c313b8b2f0ed6e9c9a6a5ae154e1f1db95164fda121feac07 +7861c85a765929a69e157e13d25e5e053bd57d16079119329396e4b3ac48 +fde80e0954b665d61b7d3beb0e7b3800b4fe7eccc741581bd4ebe45f1d09 +0ff8a13ff6ecff9b76ef312ebf48775e6600e8261d57dc898edbec1ce72f +9806ac5a9ab585332133af60ff2ac31b6e97d28bd232a50d28231595d2b2 +c21b253a27a7d430a778ff0dd446bbf93c37c1a4fb1ab70ad1c6615b515d +72462d81535145ff27630debb40f8439e093c90fec7ebd04ad81866390ef +8df9d4d4aa47b8da9ff7f5ba3a3a6cc61918639901f4c58c86fd1844c05f +e795ecf8824e5ff579b339e18cf298786806e9159bc98694cb45a3c33c51 +976a86deacb2abf0ba891471a846ee9f0240ea834f1df61bd439ab8a04f2 +35514a667bca49982cbb4afd0f0b0d9042130b4376a8cdc353ee7846cc80 +d13b38ff7dc0f722e241eb37e015f2c3c449ae1ac99086ab4d09e359b4e0 +cb40fd539c3d95a177fd1b2b6f827dda8f4f37db4d2eb5c9cc0c05ce664a +e275272d1f131afe30c97e4c1ae8e40245757cecdda343fbf57f633ff29c +cddd45c54eb21a3e8d11356f26c4d6dfc4cc24d14db7d1f569dd504458d6 +421241a9460b760cc89182a3be4d5e274fba17b0c66a73a31244f94e0e25 +a89a4349fe03bb7b2b76d5087fcf01e23ab8a946541295fe3b8158c19fd5 +281982794babd4d8814b278218e89e9338c7031473cb0670c0010c62ecb8 +d0c37abb74a68f5532ba49f479dfa276b91dfd95d4689f7553de743227aa +96b674dcec8186556ba8af629a79c624de297c19eaa86e274b4ccb3a6cef +807469a797eae637909c19232f2801b5bfad8a6bdc6565bfc0c217004854 +dc654c7d98697831a625b3ee7ce24f5f05b0aa6ae0187c98c221820c5a23 +a27533ded30354c4caad3aad261ebb5c0053721407d9eb6bd55380930840 +7de038d2c6a6acd77fef74cfb5d961dcbeaa2da6b8deeca64e4adda73672 +56c1361c7ea99a6b95503fe901d056267f6e36db78d165b74483576e36ab +a19e6801a33e9e0bc21eae2a0e8e56943f4c2fbf9467afed079849635579 +ea81fde7e07a1c9bd12c72eb2ffc2250030bedf8d8542ffc4b8ed5268925 +c56bff45b33e0bb0f94e12ee694dcfd34a57724cf3b9d347d7a845a0c58d +a803b999da53cbc1e3955ead076ce86f62085985c9d9fcfdab90b2d26c73 +d767084eba703a13ae41ffdb2a980f3ea0f0b67ed5a0aff4b4186bdcf217 +ff575b1508434dfce67a20e40968257359d0c210b28dff561b8ea85aa74f +b443daa56f4cc37ac6f5cd3951591acbb84d036170156a6640000982e7aa +aea636f726609982cc39cf9f0c42868a69a3a54d180400b29094c43e624f +bcb7a087b54cc2ea930f8740828b6b6d7219ac2237838f63df73fb99f4c5 +1de03e578cf7047bcba4f08a7c56e008284e95cc +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark diff --git a/fonts/Courier-BoldOblique b/fonts/Courier-BoldOblique new file mode 100644 index 000000000..e6ad560d4 --- /dev/null +++ b/fonts/Courier-BoldOblique @@ -0,0 +1,1686 @@ +%!PS-AdobeFont-1.0: Courier-BoldOblique 1.05 +%%CreationDate: Wed Dec 22 1999 +% Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development +% (URW)++,Copyright 1999 by (URW)++ Design & Development +% See the file COPYING (GNU General Public License) for license conditions. +% As a special exception, permission is granted to include this font +% program in a Postscript or PDF file that consists of a document that +% contains text to be displayed or printed using this font, regardless +% of the conditions or license applying to the document itself. +12 dict begin +/FontInfo 10 dict dup begin +/version (1.05) readonly def +/Notice ((URW)++,Copyright 1999 by (URW)++ Design & Development. See the file COPYING (GNU General Public License) for license conditions. As a special exception, permission is granted to include this font program in a Postscript or PDF file that consists of a document that contains text to be displayed or printed using this font, regardless of the conditions or license applying to the document itself.) readonly def +/Copyright (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development) readonly def +/FullName (Courier Bold Oblique) readonly def +/FamilyName (Courier) readonly def +/Weight (Bold) readonly def +/ItalicAngle -12.0 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/FontName /Courier-BoldOblique def +/PaintType 0 def +/WMode 0 def +/FontBBox {-61 -278 840 871} readonly def +/FontType 1 def +/FontMatrix [0.001 0.0 0.0 0.001 0.0 0.0] readonly def +/Encoding StandardEncoding def +/UniqueID 5020948 def +currentdict end +currentfile eexec +e98d09d760a3c22cf119f9dc699a22c35b5b35ed6aa23593c76d54cabb5e +942bf7d6dd84f1664b89699c74b472de9f8e6df925f6c4f204e9f1c639b4 +dba988ed2ac419ff2b2bde605b8ee3264edd66412d4f21c64ac522bdfc7c +5502f9c3f3e5592b3b2093d33c9bfaedd2d49e89aabaa832e23f062e91a2 +5032519d1868816e44b4e0747795003d7930299d6e1e2a5bfe0d595dc97e +140989ce81d8d7f852ff9cdc7a1b1b598c69131dee005b415805a16d8a12 +3e6a2f9dbf9f3f34a085f42fe63acd931cd846b57d30dbe2d6b4b42ba7b3 +841204cf185aaeea797b0d16df1d60060bebe83fbdd4931af1827b449bef +2eab8879ebefe5590120effb8f783be00e602fa76e53ee4e20e9a55189be +e40ecb842d3838dcc54fbf7423229ad68b98e033813b1a3e460f4a9baea1 +8760d05d85984b0b3e161f130d92ab90a1f47416b3f21d7797d284422bbf +3f185bff2b2de126046d090be44f9a5d8e6c800defd3a53944fff17566aa +b69c8f5e58cd7e26c105bb2ca8ac07b6ff104375a98e23e4ef5f370311ee +aa1954169cdec1a823b51f1da93e50a6c032630f0ed2f0109824f7aeb6b3 +850ec9d1c2a9bee7dbd8c787f78a9402f96c7fd756f9c63151ca0f742b8a +1ee50d127ea8605c1c1fe194833218e91e06261cbf154e7ce4cecbb941d7 +659f6da4bd998df9fd184e6f6cb0583c8ba18a7d26c9e8cda7f79784f053 +243684693700a482a8f2182c9142114f25533cbf9ba2b43d833aa0fc1d7a +95ee86cdb19921b4e27b487e2e353c8b942bfdcd06974b8115fa20291f25 +71fa63555110b9fd8ee1bc9467ebdcd4145b372ccad7e9f93460449f2433 +1a6030294c172bc918b1266271e8c39e52850d83d2a78d8fd2636d3eb927 +7275f14498245fdf262d54ab22c919876d3ab407f07fec8e23d28acb2d3d +413757ed4fbaf2d03dbaaee70345f62672a238589a03b28b03a3a1ab6b3b +970d28d2f747facb07bef7e8cbc0a847898f00e6a27320cf51db2e143935 +f16e2c6da9d1eb5481f6e75852c3bc7cbdbbdeb5b27a299e1a4003b08965 +6a96de26fb54d3fde40b8dd64d01e330da29486b752890a2e0802fc871ca +86cb8eb4037a72fe7350e8a87bdcaeaf182333a6bb929b7d202bd5e4d1ac +9ed69d15f816e39d45089dbd9ed2340302f639496d60181c00c3c8401715 +85c34d9791fcf040f1285874367e125be582088c01dcf773775039237da5 +33e679fe7dfb9b7221b04f2d69add19ecfda0b94bf53dc389fd0666e7fc2 +92383995518fb78173248d9ee7f0fe79ca89ad014a1916da267aee3ce701 +055bc88c4cc0053d8d7e09ca072a04f15b1871a3c1113b29df7fa0c1a608 +8ddb6b2f97e03d829f6de8fb1c51d4e3448730fc94af5d62b69e2afb843a +e2a8b12d5046e7bfe9fbfc2404bc6232e352b25a128e8a501d6fecf02571 +9e1e1ad7890b40ffffb006dcd42a65402df37d8b2b91ccff1bed30b8e192 +b5f2f53d263ade0798f2fc94d19693734b16ab45ae0d000dee662b209db9 +3c541fda6d822a4e2349f3fd199a654bb931cc36f56bb2f5ec563398d385 +459f964fd343d9b253db726e9d16fb240a84f39bddb76aa7edbaecc0124c +253cdce59227216a0c74cef8e44ea7fc0dda7433a3b0fa92a0f6a00c43de +f2f079668ed3e9929056dc1185dd78c663097fe8153aba6410dce819eb69 +d06da03fae4798505301235d725ab2601d935d80daef960061a6c420a696 +a2a1096619f8f0894c659a61c4076664e0ff1e8542acef3376b8e2b48975 +f8f546b1ca4ce7bc9e31fab84df061fb7452459c6c7b68616c8c3c53d4d7 +5830e418fa8cf6e0f25ecf30a3c9048d6635ad9e9f4ff04ab84c2ca1b4da +a9278de5fd299872b1e57dd7de2478a2b21b2eb96896ba53690a7be8a0c1 +2a8e020dec6f3fc741998fce007033f9959c1328b2785c1a8b26351bc740 +40b30fa99c4c8c7bd3c52aaf8c7ddbfb0dad72d8953e25ad54afc3b53f15 +25a4bbb12ea7ecd712b1a4029742985a2d57223762d6d83688457515d90c +a3ffe21d9099979e4ebc79bfac708da0adc420c676ad5971288aaf2b8dac +4a74715cfc76b1e6d52501e0f776b65065458e63e16dc2c6d6ce18adc8ba +94130d2a90780a127c9b3d878e9426ce14967f8e65e4bfd9f47582ef2c37 +c361c1008db7fe245a6dd6c5bf8a84ccca05cd96cd1aeae072c09856b336 +563e66415b727d58d62e9dcb7382c21bc7e4503c30346ce2bcf4baa2c87b +70f1a713ea26fd7793b114e3b77104d5f1c5ee8c282bc01e591c068973f8 +53c5788119d0cf53ae213c1770abdb1cf3fbf80a3e77f7db59f9302ea55b +bb16e9f775d04f3242cad88e2a1cece807db59daec7cf7e89cccf7360ec6 +11deccfd50431d67fbe30e80843ab28cc0e3e9e1374c24c15567453e8e92 +8e7305fe9eeab4e3c8b1bd92140bb0d4d40f80bce763c25bb90f35a6e907 +759e574c7e9d342a2c78b1b78b68cd9301075e6aa6583a4e18528bf066bc +84375210a973dd1a60a693b45eff6c51ff890946ad331ac05ef80bba6084 +24a582968548d1c5640cb8285786fde01cf8fb15c5b821c5577f7abe9683 +c164ba9a691906709ac46d664b833aa7fe5a3fadb67ad3bd82ae43087ce7 +0212b469cea0e28bfccec30496f803d3ec1fca366ca925ba3f20be9c34d8 +2d0d7215199e829f4d0d7b4e9630879da68ca05161e431b36510804d97ab +c1891cb76ca24bfb7a897835e67f2c2ad7d0971dbbd6814eb6542f7e4fa3 +06fc97a058406098c53564efbf4689dc448fb69080a08a54c3602b55a681 +09d3ad3fb83eeda6ddeda6ddea4ea424553ec22fbddef65254488f91ad4e +d38ef195c418428eea7fe850c62dbac2f9e3c9cfc86542153d0d5caf94c7 +89160cee1fc009d0ce68951a7ae1b666e4abbe82a1c6a3e95859352e8400 +e1f33c55626a04c3818aa8a917c3f5755e2eebcb9f3151e2a02339bde457 +4d1a65af690685ad8dc4a64029ea5bc1ea733546d0b0f8871cbb56aac6d1 +f2637c420a5cece2e4229d4473af7ab23a7f6a33514ebba57453ae38d6e9 +3bd8183507acdb9547a6fc5cc68cc72575bdbf27db2a2ad634657dbb1e1c +4eefd59b0127998b7b12269a61ab02990a59e7c8ac9ab84d07c9de30bb68 +4b29637429604a9f02d9d8923ee27f4e0680bab37e3eb4220de2e271738a +05c3333f07d04441a4c77e5cb0fedd062f3d0c93d0267644f56b21b1efda +d3b65e8cc0d2cc526459cf239119f0da1bfdd81f7a2fc15de8658ceac01f +a7f87e6028a8f25ce711f2706842981edea8c667f98b2e1a446398ee1aaf +311aa911ed16df089193bb58614df7bf5963112fc14c00dd188fcd6ffda5 +12dc8fd71c300adc8661af41cffb7f70ba702dfadd1a701c1e74abd07e80 +f9314c3ea606aca7574f4d1dddeb4b3508c78cbb376677db4830435894a6 +01c8b3c79fdb04aa048d7e0e5ae3a5db490459b142668f8481262e3d49ea +ebaa8637ce0211735cfd5bf298bc2274a35577b95bd69dc5af099f64f3c1 +1d64d6457d9dadf22d52f14a50d7d0d87b2db6b1e19224f72030888e2441 +0f04c89aad7ef45574eef2036e3e9e798d02102f63c6b8bb018a915e5af6 +2ab7bc7db9b4da2809bdbe25e57516e8d188e19868bd2ae02af609eeda35 +8829689f61d8115dcae38bcd8ef8615d562a83cffe5e97e2f017e0b78957 +56986913e1bf885786e5543c46671f6325f04d7a78c53af15910e9c0fd27 +af28dfcd149d285f44c14b6f1633da9ddfe683d7139c9f5baf89a154d46c +6e4d672452a43cd6a55bd1f27c4a3ff0d14a86193ffad59c5b31ad8807da +065a8190de638c984b971d580a7cc9561b4ff039a2705f6bea4b53403629 +0246bf9fd12d766dbce0ddb5ad42fd48b82f4841144e5b06e3d889c0c7cb +bdb2cc2b353c392c7d740446b36a8126503c93150922d97e926ce96a20e3 +e698ea1972e36eda0f9aa7693c53cc2994a16db61e5e4316b0f882afbb43 +b8ae94f7f28eb7eabee5f9f3364ffc1aa9342d1777427796db0bf7d7bad7 +1ee2f4e209dbb15254391987fa678905f233a241e77f26a42a1e2f66186e +1d048a94be60cfbf61d5c5bb361dd4d1c92833cad203c6dfbfc2453c885b +bf4683a234fa558bbef71c2fe0f0e8ccd545cc3175a31bc100dd087e7321 +932c2779c3b008afdc61117d6a1661ca320cb34770f4d1b490722ce19fe3 +698da34ce35b1345951ad982aec69a78279dc4522edcbb01f9cc4b8cc52f +9267b527fe427885d67cb62f2fc7709de4ad29c7e6e1aa6dce99a30ca2fc +fc6c523c90cce6062e25a581fadb1b892cbf35eb20abc4068a73be3488ae +a12b50635b70cb66d9ab795c487a9d76c2b01ccf27c4df1007ad3b68e3c1 +367def56f2380db21da81a46d9189fecef680f15d22b30ba3596e4fab3a9 +188f0f11bac53df5b71f454996c9613b3edd464d9c9e9844cd357afb858b +fc28575ba3e350e88bba2a045be02edc0a24bc3ff21f98e318d84cf23ba7 +2931aa278ee21a479375e0d50193d8f8aadfe254619cfd825a559f9639f1 +98ceb491bad5520f1199332ea0cfaa2bcb8faa7d00f97fdc6ba2e11f15d3 +00a9676a12f0e451f92d2ed547e2df0d5b8bbd40bb5aa2df66ffbe68537e +823da67c29361d9c89c1fd191d9bab91309eff5e0c5758d9ea0b9b1997cc +101f7db3788bd9ff8e01e1cf1ba032ec90dd5952858726df33cfb6a00b25 +497cd5144edaf481490f26c802a0a3d2e9e8114f23b3f0ff23fee24d1aad +bc36492e0edfabec0d4fa57c034c47d2e8acb5e9ff5ec486da2ac3ed51a3 +b36933d502044bcec7caeebd3857d383ddc28f976322aa26315e3fd7779a +5031ab41ef0efbb295afe066e7c1e8083671e51628ec799a549bde48a502 +f879f1361af8c177b122fe8eac38668d8882a46e7d20587bd561b34486da +d36c2915c24fc446d2bbc41e256af4ea7edd28914a0191ee4116961f339b +b85bdd38c1417669b345d46f6b6ea2e3209812ac61d080731d0dc89623c9 +a28566a726a6665a05c70c7bd2e1e757c0a03bf89be801063e40d6b64927 +9cf4fcce655cc6cb2a2d95c846d6048853d654286d5c2c2d8eea94fefb67 +62fc17cd93ee1fbac2dffef877c74bdace7163b654982d864b688139dbf4 +7c7ad4f38cdab42bca53eea14d4262da8328b75cc8a342570c7303c053b4 +c507ec2e3ccd2ca8def551ebccc4f6fb925ba2ac8f7cafbed0b0bfae20a2 +7eeccedaf790eb9052fcb6a254a3ed51374c9255cb4448f99e418770987a +192802766417dbf6929fed937bb340568e826277e8dc38f4dced644e23b8 +f298b7505b11b37bff8864a718821d517dc7af2d9baa66195e7beb2a6cf3 +0a20cb7a7281c13b1e95396706eb3d588f93d2172dc5d01658cc2a46228f +2f6457ae884e11815930e90de7ef66ec7e56d539a41b7390b4c13b29cd54 +b43e04ef1076d442abd41bad91f6bd2b5236669e5f0b83375a363db705ac +d528803e445b2032f410a6aa9bfcc1c704d9b9364dc7ed9fb34c3cbc291c +1a6948cbe72bd0b860f43bd43ffcab6c190a94559830786a58ebeb4b8867 +73a24cef543b06b9def306e868dfb69f80dd18b077606efaa288f3a5fcc5 +ad3dd1d1a38e22e8abee50a7a6c5cb4407cb9dc339fc04ffdad6e48185bb +e2e396fe1c39860f942bc50aa4ccdb02e5f961f8441dae54353169cf2086 +74a99eaef76c99c4ac8a6c0c74508c7e47702ec17f90e40247493ac906f2 +88deab608ff6a5e6efa260e04852e7dbc79cadc19ae8bf33bde20f7bdd11 +c600e8369e0da03b877cb4a08f719102d3c3f2f58ab4b0a3afc2a91090bf +6aa5ea74ac07cf30503cf515a1bed7d594bfecbf6fa5cc4361279f607cbc +7ace2224ae4fdb898397c500631e6f2bfc537f457f863e9d8ea51534adac +d7a1ea08f44d8ae882eda411b07f25abed54fc52843fefe2fe03c7bc2cfc +c95eada5276315bd138397102f056529ec7f3e12add6a290cc96dac9a467 +8788c06355c623059485221c5f0321533cfd004b4fd79c4792086d64588c +2abdc034771fd02c7c42c5e14c7622cfb21934ce02113ebfe71c9e3614e7 +2f1cdebd4e604e67094e5694129704a229d205f116b43c1c76cbed409e1d +210ef1a405f70f61c30b24afc073a3a5b822eb217db46188767fe33ad18e +9b0e59456db4d33adc0f189ba48649e84d6c099bbec78c24f48704c6a934 +ddb1a96e5866f389f03b3635758a9dff6f639bc64561a5ab17aa3f1b4bdf +b0c0059d33e04946e9a5da4de3fd55107f9da9a971ddb14da8f37572e852 +b554db6a88806f4661b0ae234234e15b99a6c416ab21d368df2d1ca65e9a +3fb736da74068843220d91631b57d7b00fcf5f246ca92bb8389d951b9baf +507087226da9b5306277be1f528f03dc61168113ee5647a72cdd686c74d7 +2e13a077c406eb58894c571ec9d58c73a4482c30022ae383dabb4415de7e +758ad9f69244eabfe52e8be1e1429c1ae59b31fc24a540a31b9114abb675 +8c43096e6fa3e714f7c2a423a671dd42d56a5303228f6823d5ba62e1adec +028b00c438969c2ed5c1c25b9e8f2b5a69f89c9bfe8bbf50c4fc6bef8c8b +b7d6f3b4858dc52c5a8a90e5b17dfbabfa38eaf53f5171ac6e29af9a64c1 +3d676edb7fe8555661bf426b71fb80f984a37708965e7198133d64ba3eb4 +65988e71f5910ec10b0e3db681e7ecbac9bd9991e6bed1c3c75a8a0d9806 +76dd592bda679a37cfee4d4df2fa84e01c98500771cdefd3e5d7c8fe5435 +e39056c032e5f4994c8ef1f5799ca70a3b3312679b2daeb33afb89252468 +67f710a7ed78aff3298bdfd5bbf5f430c9c159c56d05c65ef4404f4c5255 +1ebd7ce648ad2a44b6bef6d18ebfeb550296c20bdae04628743d7ffaffcb +8d473eb871b6fb4ed94c8cbbb03dd69b1f5bb4050ab4f0920e88ac9ead11 +4bc532dab69814f5c002004a959ca630bdb063be03bc0d35732aa580237a +055ebae9a00ca10db283f6e19399d9fb9bd66c86253bd0d3dc730b5fc898 +bfa550885c4e3cbd6b72f43b9e2a0b1d362d630167d52695f07752052a37 +b6552aa290d1e73023bb66a4ae1506a3c9a0dce0a58cea5623686322a8fe +6e88f218020125257284f152ccee92313428eb653355437459e15ad374e6 +86aca66e737fdfb7c287bea41420019b69b6a30d0a0c65b6d4b0608aaf9a +b456e564a8ca2dbeed7ee6ba9c4ab1066ca03c4e8acc36b58dd6d7ccccd3 +cd58e6d0bd984c5b3fede36297d9787a7bf16a899f05b2eecd9896946ca2 +a3d857d8a83257866aed94fb753b65a89b976561cb05540ff9738ce0c2d1 +84224882b315c1ca09860d6f04d116b7e7605eb04496fe7df29c9c4f98fa +fd33b21b302228670549bd5d89433c05906f48a1d4c31497285ea9a759d2 +7bb39afdcfdc9cfbbf7d2c5de03ce66f5217738826e365ea2e28a53d2635 +a33caeb8ae66297824d8fd7cf7cf7c51d000dc0982f064c8c397b385e83d +2cf5b41e84f1261b101b77d85c908712dd1adc5f6682c94370b360d245d7 +655e10642367ac53a52c23a1d840a0072e0f960de20391d1363a86f22c82 +559eeb01e95e7ca605528ea81a47d7a9c43a2cb63d8350829ef0c260a2f2 +0f5a75965eeabc20b39b8fe45438406736152d6a118f2aff6abc2e97a7aa +dbccea9970261680af87fcc02a68b9d95d6b04a7d3e83600d77acce0fb16 +23841695ff1dd207d1fa8d89411690ae22f99e8021e075d1ff1f90f7809e +b1dd8873e8fda2c8451df3f6c5d12cb930472b04c55ebaf709d727b64cd2 +49bee11f10f509856a1f63351fa4850bbe42c8f06c15605fd3473aab9931 +7b8b2a2552443b0e331d9f0e9d91a9ee1f6f67a0d65d9f2ac166c4f38050 +92b7f7e569855a58a71606aaecc7283757a69cf37cd61894eae10209a69c +d3d10c3f37287851e0b6fc5784c0618c7e155d2d622b23f00abfd601e436 +1ec59a0575f6f85a7d90f83815fc3482954b8cf71966c47f95305ee3553c +ac77ce96e7c33f2696c49389ff0abfc865d7edaf368dd7871ba72a097446 +fe8db83789cc43b31a74e997fd7edf298c10d61cc0976e7b41a7a41d83ba +890a68e6cee7d79493369ef2d8812a1ced1880a8fd4765097539a7cf1ed1 +e1ca04bf92b714b6c71f406733e7452c826c5ac226dc16a18a9de3ddf126 +bc419642f9e1fd36d162ce7832c85b5558863d262855fd6267a154211c96 +73670fcb8bb9354820650f25ac9fb6e636833211e9d41c794c2a6c21d59c +53f7bf5f264f0ceb82632679bd0a0d598f69fb3e983597014e2986b0d9f6 +88908a43eeac604bcf9a0b3ca60aba155f4a03565ac9f9fcc5611fbf0597 +084431d37d97a9152e517ef0f6ac30c7af14ca490b4c76c3a8c8403611f2 +4a2714bbf952a4ef7767518bf0b69737b65b7b6aea2d68acb1f82c5e966b +e6ab8bb38ab1823775bb35d60b1ec01e1a956e75ad8ff63e90d7c3a09798 +cb1ac0e1235742753c4f0ffaed9d9912d6b9ba310172a100c2e8daded966 +84ca97ad4b0285760e541bd121493403ac952c9f148a4be07a857fbcfa93 +ec60b19d89d9f437a22fb9eb16595efae7bfe2fbe62d3273bab8ed6c8518 +8864e5e2293818bab1864d85aaed9e32cbfcaa68dac5b52db3bd943c70ac +a81c1720ac0428fea9aea324213166215542b68948f41273af3e7985087e +727e13934fb13782e7191cc062832406a8bc38c576b5d96c3ff125fb925d +71f217d7e60775c0c636601937b7b5d7bb35b6ae08f1745a1f7b42dd3f3d +c1599a2b89760af234d0ca557df5f3be13d9e7cedd2c3e9827f29f4667e4 +a55e8bac85bacf33716f7354ea6b96776c26bf74f8c6dc18814103cf416c +82b2226785db86e66edde45da8e5aa738934d084ed3f8bab45c5a46940ed +d326106ee1aa6c8b240a98f1ec8284bcac022fefbe973885a2c5fe025a44 +8ef2ec64c57ac06998aaf24f702b70ead862f4327467dc5558b521b5a475 +fae859534d2deff36b8ff289c9c055076dbe472f83389d74306aa635a7d3 +738f09005fa73bd903a93fa98f5ada485a644a115bed74a7fc0c90febce2 +2ac7ce0ad8e64143301a671e980ac335a90fa735172d9843f65e4c0f267f +49697564f842ce349ddaac386b317222a0136521c6ecae276b63beb2c192 +7d04886178ec3ed9783ddf414ee134d8b14e923ffe1e5a4f1e267e7553e3 +b021ee27e536bd4963c69455318e5c1deda0bb4faf814cd4998a6a4a7034 +ef0da8c64f30ef18c6ab164e6223233e6183419f53a81d9221a9643c528d +a4843c88531a41b02e710927b30c748ed2eec921bf1caeae0d4856f3585a +232ef7b6df214461bc60013d432cab8b6f17148d0efbf763d695d94ca94c +426c5ab28c18b869579cac5a728c8dc94ad33710040a95a9ea70e953de9f +45c0a320ada611ccd65ab7ef6423e70bbdc1ae898c9cb50278b5ac3b3f79 +03f6f5aa9a634b5bd103287cf2b25a4e52e70e7e762f00bf3e68dd39588a +7e9a38fc072a96812c8c517eead56f3610584686ce912505d5fa81cc1de9 +5c7b9c96c1c73ea76970b2c343ca86530e7d1bec56f0bc4307c6a4aad326 +ad3296971877a629480afa1a9b602a6820f21c6520bc9cdefc01a7c48db7 +9caff6cfcc2b9f0bca69d41125476f2d372e1c8b6b499dab943e1130a764 +6dd17f6ebae2be1fad75784b5006f2d713ae30a4cbabcd50d0da9afa4cf3 +380358e575b769c6228b3874430db68aa0411e11621871d357e25bc39947 +e2573cc68bfc532ccf26068391dc516928f8e732d208e5482ad3c73e255d +1ae8a93700962a56c0f83abe63089f2c9c6c42162729d74dfe84bf720206 +d42d82d2022df238182cd33dc4bc0013c030a92921c4f943cc8f1342f35a +c1ddd2a6ff37b92ce6c953a9788ee8c4ca60328c76fc37df3b5cbfb7bee8 +d1a0f5934e353b329ec69b9100c41f52a03e80bf3fae5190af63177bccee +ab2b445dff1b0cfa372020c89ffe21108166e6cb3383592ba4043c32386e +17ab84d59a463230a1e3bdb428f3a0624cb02eda2fdbcf6b106b72d9a33f +0bf20ef7e46544894c0f958d9d21a5beaa95dc9ca8b3afd30398861d41e8 +d1f0523ecff60dc3995adf84a464da4611c6f4567f174f93c689ab72cd38 +c921577a0a137281055c5b8bbddb702dcae5533508124f62c6b6ae947ef8 +88df84400b91f15d2d22af9f36860e8efd8d31cd1d507c2a93481b522e32 +f8063f81f68ece985c35ecb0d87ccda2bfda49a7451bf83f4ffb45db63b6 +715d4e11614e0b5add3f90137968abb33945a53679c4a375c64a27e772f3 +a28691c5064b133519aa12970938c3bc47260d8d3b1e06bf6a393015e369 +6db909ea8a80ef0437592e881060be810af96fc113da386ba760f5df40fa +219e14a11ba6a5bc7d6c54abf59e71f3e8eb5eb02f088194ac3a02de6b89 +bfd576826b14e22534251f63f89f4ca05ab6c728748adffd02e6b21d2197 +e87e0acf1c081b65539083cee95a47e26dd8f848c24225756d9b2502e5fc +f4820176f519e1feb87549f96a0038b797806874d67631b341dccf5a8414 +e86578839d7ec32968c57e2b70387b4f1ba21197ac8df1cac6175ef0a6f4 +6865c8acbbeb12abfb83d34f4b525eacc12d2733c29df3cc4a28a7e03092 +2609e0398565ffa55b0118a904a4cb0fed5af585c938a809e1573f63d829 +1bcfaac2bb1dec564a94d390223697323ba9d58ac74d28e37032af6f24f6 +076ce4e919b7b85679e228c7432230a85d3505d6f659be33b4697e4c0b6b +6ee20a512adc3a1d0276c069e46b8b68e81e4893fcf91c64b84e631e92a5 +2ba97daeccf4c352a778225965f29aca689f74c1575a50c3fe6e90be0e1d +b16a6e473d679e5ad5f422bfb0a4baf02981b0a140a35021d2a93c450516 +a8211e62f1345423ac48c167e7cd60932499251bb8db8190c0bf8290f09c +1954fef141cbd5703e9176d347363ea768b701a40dc768d5535e1860612b +84198effd00aa7bc09f3067a716b24dde04d30b73fc9fb783515c62d0391 +c82cf8b3bf0b79962db0bbb699295f324f69095f1a43083d3f7436a5f496 +50bafb86d2d6adee2c9753dfbec512bdc51ef2549ecf376ec05f6b3aa309 +d9c79be20c359ddce0f1bf4f1277de8564a22024e28822e734770c717f70 +c72bc399faf5d8b6805c3a7c6bade9f16d37d5e7eda4d7576a45a9ada1e9 +996a994022b777be0a1c6d9cb58b0987319dee76e0d3709794c05d15ad4a +ef240b02cdba3dd5ad38ae5bcb9c0df2342b7277a0e241aa5dc4b7c0b5d6 +c66ae3c81cc758d9071c779f714f328befff3ebe0c7e7e6c4eeb16c27585 +a8b22d6791b34d4e2eb9c80ad925469b03706d9996020e298e930190eb9a +30f56a62389fb49b00d1f91a6af2fa86d85fab4f9b89dbd076a0364053e7 +1a913c88756e305450c4a820c87323e40a615b7158d89312f8472673ce23 +728aaed24d04baee21591aee77258e573f765c432d1cd4221a7ce52339b7 +ba59a1ac2bacf152fbec0158e7876d4120137695a8beadb58a100763a5ed +959b9ca89f481d9d9e226f7b609a599b30a6a4694bc166eefff954e187d5 +3987868e4d9f1112388eb12b9e5017e3566801fb27a0101227849d150a64 +fbb6104ec6d1e7c354a1baf425c583fc47dbdb958b8f5eb653b5a045fef9 +9279a4a76d0948121f4d37c0343109311513e8235f717948337d777c080d +13301777ab8987b3d64d0eaf70fe28e957a1e92a7ffe9382a570237b3d3b +d37910da2e51bcf04b566cadca226ae0b8c62105738f26bf57ed4f6ef0f4 +fe164145db590286d16b2ca36b3f77a0b4d243478c59cb34494b09209ea1 +4d4fe024f373877af88793eda29357fd908195a1952507b726138e377b57 +26d28447562df58e02663b86cbfdf2740d34a0cfb1c514523ea1b7b20601 +9713ce97943ff86e79ed7f3dbb59a6fd96680264e693f06b03e950e4a2c3 +ed234db50ca2a65594c8905c674a9bef1fdfae8a068850af662cd00429af +4f41a8a95dbcbba1bd7e2b5421a1fa237cf31bc52f736aeddb1814f5a229 +a1e81a0316c6f70d177243adc4813f8429ad874d9efa0b9279975dc15bc1 +41dd3fa2c5696c6a642fde4eea6e54764da50910e51e74506d5f007d1b19 +46ac61f4b5467ae9449192d3f3736740704d28df25a018a681c24dca1862 +cf1989f1179c80edf7ea97eb48b72513a2f5f9410ad33b1e67af4a9b84b7 +03c64c9148a456405a6bde4bef9e20d33b91b921632515d9b7d07fbfe402 +d16179e91101af1ebe99df71582fbcc1aaeba137cf37777db59369eb36eb +8b88fd6c0d71b89f34fd1df00dcf0f1d584c12cd998b8d3179f95ae3c1da +483543bd1977d88310b76690d556546b30c573641d1b6310d3f3c9e8c398 +ca6d1b048c629d143584f6b51177a8cae324705be0751b1d769c4f7a80ff +e810f076d007e01a4d8d2bb80e06a1dd0bc6a79a2db1ff51276880352b0c +a2aa2a7399918bd9115091072892149e51d7083a471c0835a5f5957f2247 +4b49ebc6ec7d6ae0ef5cde3634b878544099c58c3125496cdeb98874335b +f1c756b8f6cc7b0aa49d93c048451a6e48377aeef2ef2edd3ffd1d5efe84 +e23aaa143884d60f06f36b3d5fa950c3737105cd80bf383caf1e1c460ee9 +30e4240123b34b83307acb0a02a382fd279316c90fa69c1fdc171f4c7f30 +f645d4fb8879399030521af4ee5c225e6cefd3f1210550193785e2177ae5 +cd7c130e254df39b4de53a7b4b4bea3e747de45707032333b21e13621cd6 +ab912fc701e722d7fac26e92c9d779b6d6bb4912e3c8497fda5048d4c856 +1ca5e83475457986a8aa25869e8329c5afc2be7850ef12c4555310fbf424 +ec5568ffe92ed1ea2396055181565d4b11f98c72189abe6f204918004691 +db14118193c5e291e07d35c45ceafa1b3c3155c4c2c9a91a7baa9b110a97 +a0946827e252dc68d6a1959288ffb63eb6721fdca03e1e72c0d37ca7dc7f +3deabe15f4e804cbb7f5650a143bdff5e86de36f9f826c4fc05d5667ea4a +df5d08a31cd4f0d2fc95f5eccd874a40c0847b02cf4f9c4b047c27e5c702 +0a23e2f4504a3c2fb6c310265eca0fe289ea8c9f62804b0040167589f05e +f21139b321c662b5ccc314a92dacc92664a65cc9f804a751e4eabe11a9ad +cc08a3808397b68b6510fe49ed4861755386979c858a43c5105383a948b1 +6ef0eb9d79ab162f1c56e08f14e3614cc683ab383d655f5fcdb616f45fda +9b3ea1b7a4514af796bcdd859421124582605417da88f96bd9bd0a44f6a1 +0352f31be38861eec03d5ef4349c62678171bcbb25c789cfa650ea76716a +d99f9ef4a361467d0f4bdd305b1656c8e226bc61993e98fe31dc936c9002 +f69caf89e0aad3a215685a82275357fce725877b527eec56a74e4aa352a0 +7fcec7b66d025ad720c760ec5dcd46cb180c7aec171a3200c2bf697fd3bc +f78447054dc8c38cd443964b27280554a6b3a878ea93b995ba0acb74a4e9 +6118b25dae2f67abe2ee5e580b0c0b2eeb8a0d730978e97205277823411f +1c04beca7c2ba588631ab10270708ba72eb0c9d76472e90f5c733997031d +5288c06c2449edea82b0cf653cf1dc5afd64c10bbded31a2c3a2c7a00bf7 +b688c77888d6e6175d8c20994382eaaec14df3783d4b3bc97f1cc3ee6113 +d50bbbc2fb1b82dafc127c466d5909db3a7c2c5b31a17dd588f15b8b5211 +df314fb334c4f5412fb23808bb1a7bb3f85762a0881765b0d5b8cc8a6ca8 +228f29e7e73b496b73160ee8f91b5dc4a50c0a093d28c01850336c56a12e +95c0b53b39c875f86a646f149241aa070fed7d6ad42eff3fec7e039c36a3 +7aa3e5bec4c497b1f51d07057bf4e9bd067209850f23a614b05ee5993d5b +61234f9456fe76748acad8016dc2fe48eb5b4dc7f2f6987304764c48a74a +50621cabc3d8528dd08aad4d4b55aab3a04efa8e69c3f59ef92e3a81c8be +23be1436758c1ac357426c3558ebf67ac9677551da53638a95f165320e2c +31de3d9dad7aafc99ae3d4140bd690ba987da161e8951c67a9a74948c350 +4d1b07d5c7694c4c817414d05793081170d387beed9fcb5a7d09a6c5068a +ef0f3b74e35560d21593ecfc51b9123da0da1143ca1be60448096a663987 +4f355b2825a4c86135d375e88313478861f1b9aaf83f39e2e18a9da3eef7 +944c984de54adf4224d61ffbb85fdc067ccb6c37f81687a5086704356650 +d487678fa2384f48e9e40359cc6efa0f579f8a181dbb8aa01fffceae9e1a +9766e602aafafc42459c5cc59709cfd3c7c7b7235b9d9f26a50b21c113db +401fa1e99468e5bf429ddf946fef6a6f26aa0f75d77262119e30eb5529b9 +5c8ca528af78de86a40ed5dbae0f1c36625a60422be9e6f77d5672565ebc +80e3997b15ddd5903d85f35cbf76b38884080605faa1c17d3fdcdc5f657b +c4ab3867e917c98ce6c3500a7659d322c981e3b2e0602b4662d2106e1f26 +0d64a894aa1ed38e681a1d0164307af81fa19c1c8ed262075df3e978a1e2 +5fd5a8955f09eb5c8ec79ce0230966ec2b90198ac6961edf4a0b9d7c5926 +d1b5556256fd15ebde50a4756aa163b70918e697ad9b08793adee1a5bf9d +2ed8069fb5650bb6a215b15c80a2764ebbd65587e368fa510f3f250b3002 +f9256fa6c21b14443505b203c7e1f0e0b6482de317bd56b44630b1a6c836 +a2e398ec36db92a9a3186d55202a7ee88f981f14368c4447a172619c4f9c +9e747ad286d01fd223b55103c1e0672c9708042f63ba74bdd0d5799503b6 +429b70c9a4925481f634087dbd5dc869da8d57fc7601552edb51b9918709 +bbec37658392a287f5074a8c01ccfb49cc7d833a4501ccefb4e9a982ed89 +0d1807cb287b9ddb8e7e2f43f2fdfdd1b4174b45ac4b20cafc24e25f871b +60bc4192b2e6431dd24bfa8a3fada89410d0bb68b865f3e43b897ba4f98f +2fb3da2c322822bc80a55effa49890f1920cb824a16d67d19a33d8cda986 +c8045cc839e20ef94077d191f62dd4a8af82c2f4e95a64e1af8d882dad32 +03ff0f863528db72ef20a1bdf8d998aa85011b3174c0efa0ca6378d488de +30960140f9df850b36bd310d1a184cf47b70d76654a39d2c5d50ca56bbc9 +a16675482ab01d1425fffa264cfb849b7bb6a60dd4ddfc4395eda9f7dbac +1f9bd167fcb3e2a5c75e581482862b6572c5ab185f1304fbc90109216561 +c53a766baeef42811a6b27cfe73425a873c6f23313ce98a155a67af59451 +b85af8af514f1ebb9c8b55fbbf174faac6a1151540e59d11185ae7304683 +8380e384b234a76fed74da8fe2dfb16fe8800561eaa8bef5201a23c3c162 +f115207e1f708c252f0c80ebc0102fa1859d1d14d6376f6ca393e1b75e59 +e96786e443ccfa7cffa5d5a532ea301d1a3b11dca3e9524889bb4731fa73 +e3c7106de30a0b103b22a03ff91031f8b305849a122c181496f86b39efc0 +a3c3f03601fb3bea641e049a6b6a5b94c3d2fc4325be8b60d57076e6c6b3 +c919d0e9ac9a352e62c5a18bc174f4400917567e5ab85da35a4a00b99db2 +d0a04395b532a58983b7e1d9ca6ec1b358e0d52ffb82e0a2b61b381865c9 +13aa54ac09bc7b90dc93068183459b1e9ca74be62718eb1a33c0385b0db5 +11df9cde03003ee8a0af0a5de005d9c8d10a96c054a1d47568cc3a1869be +48305e5a5eb27d67a4e9931f28981fc482c0519e331babc2b016d44eb1d5 +68918235ed02349884de2eda440fe7b98bc02dead0eaf76f5fa85d2a6c38 +4b6974c8b1ecdede290e81397532da1c514fe30a3449ca33faa20d24a47d +3dddc44e03070eb944b441495ef2ae383bd2b9b656bb0015d7d80e813e33 +886fbadb1ce08fcbecef193456ec9e2e9ce0fb7b8eb71534d6ec565b0950 +cb0b9d921b4a6980f6390d4faa16cf466a02ae2a55146541a20c5a9996c5 +ff61450887b5da72aace428340d9886becbd7d8b0721269883201ffa28d1 +a1ba32af7798aebc064ccf0a22fc9f2d450b9f0d26fe023099a95791c731 +79baaf846e9f1002a930c50862d5e49f27d469f67d948580877e8583c4cd +0fd48ed98501e3f6d094aa00145091cf3373b7ad6c5050b90762a98d2184 +3d1df31293e5b8a5f25391213bd3f8ef78f1ed91a52c50089c3440e7855f +315c3ce3c5d02da21a1710555cbeada8d406e0f644bfc2649c6b059ae09e +a3ce3fdf553eb6298e6968f06c1f3e78a3dadbf80e7dfeb2bd7b87620083 +95b624e0ccbc0fab6ec0279b951c0791b6056ea7e06dd3a7eac13c9390ab +d98ea4272c99de1a65345b6400549ed0c8adf4ebbb46f05262e2f5c4fae6 +2a279d5be639785d7f26a8158a77607612cf5cf9b6cb3539cd255d9b9427 +af0665ad63c1e8df8cc93cff8db23ac53d16f61f6dc271488b0088e5274d +1f3f3ec8f8f28c85238345542ba4d538ff2a4b08af29640c5fa7cc8cd89a +47a083db93096ea8d4b9923a0c069a20e00020dc296f583710279eb6f404 +162da338313fb4db5055f0b5f6dd4b0ecd6e6ae4be65f4cb8ec6b1f70ade +49702456a001312fec560bd2bb0687d61add0ef2e278a13452736f77814e +277b153af6fd4fd99e9adc65269a9ef9cddea98953892444e1f49d3a6a33 +75ed9acbd9a9f11070359e8e8d97527fc874059b5ea3b0a82fd7d9265de7 +153eff41b28e397767e9d0932261f839dda7b359b03d4ddf2821a8398fe7 +221640e035e49e371b5594b61adacfa5dee8389dbda04ee349072ae506c5 +19ef43cd8c1bc90fc87777d9bf6fef2650880e0ecc17c4d48d1c7e31db5f +450581eeee7af65f665ce472da87bc90d322c0fd878f812ebd66c9eaa033 +d5d9622f8f754936102fd51489aba37b725365bcc3dcf1023000061bab41 +8737901cc01500e0dcb2b3bc196e89d164622daba26d31efc6b62951b1d2 +6e15fd1b1448d7dc675031b90ca135e42570b0a948e34e1ed7e0e306636d +4760fb5535207502fe96cac6b9b0a52db7f04c4140eaa826b0f6849688c4 +a353ad76d780d0ba8aaaaad6d47a3fd77647c9159af91e9b74cbfd38ee17 +88cf37dd6c9cb721a9763064935ace2a941b65d5b11ca2ec06cd700e40dd +a97d5373c5d4d3a96bda1703c208cfa235909ec79dfcffea284e743b7f04 +88e7cb68fcc3e6c4f7a49f945d859889442748607acf89e8d2b21e76deff +12df3c6f84868c110ae964b5cb3dde29c671286588442e61075815345252 +ed1174d840c7c7f89255bf99a466d64c780fd13144ab2074400b404c64e2 +20bf46849bd76801fb0ea28e460e89af2101d8cf911dba146ab8e9063a26 +0d77ad509df4f6756eab156a31022dbd4763b23e177cb5b712f0385f328f +65d238ab8a0edcf6d6b8eda3b222da5422c026db7102375f78323e84fa86 +6f1e2e51c513721d666c17a489a2e00ac5add0ae6ce4d44fdefd65df435c +49457ec14191351c05443f349e41b6b6eb4675c06f82bb5584522bf8f316 +85481922ac7a1bd51b86243a97dc5c270f07c72b9c5a807a6aa7c36f3f13 +f44c46491f216cb10f3b5d1bc0e84d2cc95bdda64619d8e9e0f2b9d1b3a5 +e8a9aa18d4eb4187239e1010566b561ef613fa582a4b66149c1b1eeded7d +bad6c2dcec39315f735ad2c30dfb76a9e42b73912d018d3f19f2c77eb7f9 +3ce2433309d7d802949d9ed4fa7ff6cde73577c91bb2b065ea389c0e2104 +57987f9814679b3da6c4da8510cdd4462e249aa37048320cdd48bacb6fc8 +296f12aa3160297ad9e36c01ac7807b6990ee7d646d8ad8d655763a2d685 +ae56af110099ec774ac86df2bc8c23d404da3e04277a14d291c60400163d +564272b105c61725bfec1b1ee7f5dcfd7a10b14e0184978e123e3f26590b +3288771243fc11a4252b0af02db678eb84621648e25bfc32e94206c98b7a +4adf3af635d5b590c606b472996e7ffd26b7f0554b975142473333a061eb +f79867341bd06a5b05761c595087f20349eeea6845c87785e79117c3a95d +471eae9d5347970ecc47331cf6a9043c2883f498787b90e6949c8ef311e3 +c97d58e6dd5deb00c88c47e391283a9a50bd006fe5a10a3ad04120437393 +e80a5cca595bce1b7ae05e0685dc003fac9a8e5d860e2c2325a568f4222a +f2fb7f51463fc3051aa643b3c306ebd9864e08d34de7a9b49bb69dcf69db +0ad504078638033b143cf2b730d598790c4af2676694ec0ffaef3d3c580f +477c3c5dc7478609d043bafc6ed8d06b450bd4eb09141d757962cfae60c5 +ad7222fb12c34dee17a0b8cbb97044b401cd632a1797ff022f7bf5d2d9e9 +1e96722ff3d0b51f78f8a2b834f6304c966107416edc93a91e9d914304c2 +98138fbee34f8bcfde736c7f5703daeea23532fe7fb770e8c22e087fcf80 +ed2ecda99c1547a41b7672591fdd5e26dacb333b524dc0de8ded5ce60389 +76ca254bfd62b1c066059053edf8c3a4fccc29386254de895994dd7069fd +1a9c2c7fa492043abe9e158110fe80a9330ce05063cd7023aa5605beeaee +eb033229e3cd2c2c3a67d91449cd67578f50c63f1c5329e4217473aeb977 +3971dc69408b48ddc5980329a197531aabf6a92e68c54e2e19290c1de361 +fbe91a6c386d4a1279c82f128c70baba069733957087ea021a8f9c69f0ae +79e88276f15a7b2cbe6744d41ca32141091cc9c5e1b857205605d99f411b +4e3da6a647fe14bc94c068911995d3f15be218174c69ca1834f49176743b +ceb20a385dd2ec01bf6da68c5659e636eba5545196490079a63c49fac2da +3c1fffc6d21f2d9f38ef7f560701bb71c1c0909a5577161ac0b9e6ab21f2 +2777b7a721b34d5a6f6f1e8994aa89c8cf9ab96e81fbf780bdfb4cb4b6f8 +9c05624f89b86bd8db430ae67f09e20bed731d124a4bb210c46fd61b24d2 +28772e247c2eba3cb6b8acc0814d59b5d04138f601fce20230ba26a8fe1d +351bea6a77f49ff461620e3b78b4af7825436b2d28b29b2cad0ef79c0794 +654ce86ff755ecf4dfc235480ad6496686d7c54020caf417f57ed100ec0b +30716ba13b3f9a7084322ece5e140163a228ae8e86ca4f699d94abddb39a +4cf3ea50ccb58c0bf82fd81fa36466a813c56e16847048a8612242fbf4d6 +6cf9533dfd8ff7d1cd58cbb40b6a2361049e0e5842457629e3893c3d2270 +f7802c6d36a16327474b2c81fc0ceb4ecce7be67bd8c707999c25573239b +da35c2cda50bdd2a99141b84c9337360ca82e048bf0a460277a2810e9be9 +f19f121d6c32844948b93a98b4b16893d978861a7e35579dada4dbc12b4a +8f9256f3d6c26eb9d7e6ecc1de7c8948cbe619d5ec751d1b0b3f17af2f11 +6331406de106362ab12953130048abf09f8f3970cc170b31223a6c7d7fa4 +bb2bcf5a6eee4ce50b9dc1c65188f60d2790a561dc552e60f03c536b439f +1d6b7c90fd5d406b79c512df6868c175413000d38fe1542c873b52139aa7 +c28102bfd0e48771d46eb5f38c174ef7140b2b82af2bdffd879b281210d5 +bb9ecffc4cb8aa09891208a3ec0f3d150514c806be501488e649234e0c27 +fc13f2198553068987deb79b8da835ced758e4957bcee7c623ccba1a4af9 +6916f467bc15b013d49497de3b80b5e70ff1e459a868089d02ad433a57e2 +fc9e474764efabfe35d0e6929b0b2fab129cd92dd5b1a2db3a5f45b657db +b6f7f929b2fa42c483f80a4c3fb8da8a017d2151aef8811c66028a8fcab5 +3cec7d285ab284be4d97ca882b93d9beace601f6c80c9efeb043d295e95a +3335266d3f49c6c0c90deb2c0676d525129ccd6191e3364964fa26a487e9 +136aa70c96f9668fc8e420e9270f94f8fcc812c30fa4007f9abab5572a6a +9d0269edda9ee4c05339f38c4a513458c60bf8c4f399e0e85150ec4ffbac +3026f3fad2be387f0bbfcdbc9d289d2caf3499f7470f7557ad5912579352 +4bc777b64033fee4f8ff8689e818f86722b447f5378b37f05d53f77ea10e +26c00282a5088eea8840dc80294a7e806d5025b8ae5a4d0bcb305452ad99 +4083f1fdfe2cc8a3bcce756688b37fb857f3c195955f31f49c113d1a14f6 +d75cb2aff8169007358b0fa8299515ff1f03bef4c6dd6f3ff70d527f8964 +ceb2ba3644fed417e0ce550a1512759e1d76163dc74c53e7f41fce443961 +892afd6f34fbc58e8347dda64fcc52c9a1ae0a817fd5d1d14658125f579d +32ce165d8531cc34fe44edcd73d85ba8cad4d71cf5ce80510f8e4323d91d +96fbfb0daefe8af4d57559a9e303551d38a65500f2e02d4c7f65f4a91aa6 +81241d10de140a703a641e0f6233e98fd9ff71699e62cbbc839de8a31a17 +260e657a84e6829d00b54ab85977c8053be31049111e569ba6fb8e29282f +a5bfa5ccae62aa7ce0b0ee23fe7f429e566f3aacdb4d13945c9616a2e4c9 +02c64d42bab63f25afbb4623475a0846e314c7a7f47cf531bd3f753cd7d4 +14d51199d34da94286647ab5b616569cf61c68e87568a844eea05f9d22fc +1c51150857aee8868c88b38ac004f1d86d1b6536041772091b3548b82669 +6af82096753e9d6e0445940eac5a902b304b5de5c0b9de23eb298f3774b1 +775394a26c8963bd7e07204b8175b7f2c5073227a16dca74e4bb24ca63c8 +6fa65e6d5121a7290d58a11e0c7b98ca7eb65fd636b20ef56156be14038a +42d51c873d52a656b1a57d8bdbde43053dd096dff8ec222bde65776c2c46 +a0d64d927d8ffab4ea1e9ef177a711a81f7fc666d30a681996f194e4d5c5 +33c403a93271068b01996f0e250e01c2ee63fd1d0a9163bf8b670f970a6d +d416b2aebbc96deb02d27e0a83de3c87781edac6aaa5a0d1fd7877222897 +94d3056bc74f5c899f64988a25dc67c3f14da8871d69fc5d8cf6b0e7bc70 +e398694276c69b77a48019989b93755340e000ccc4fa98cfcaaaf1593055 +13a56f8987758c979b5fbc8794cade876d81e4ecf0495f329a3ec2927e95 +9aec2d26c1ad32a3d111d01d0c932624b904da42123d44421c84bc71307a +d13d0041308fab8d0ee6f9de746400aa041a7c6a99a72300a9b911fd73f0 +cf2e0d41921232f243eca86727776890bdf9d138752bb927b6485c1b45b9 +416d1078a7034ba2b9fb1c7f9cb55734f87d4e1f081d7c4a66b524b2427a +baba5e91c1318923699ae3820657e89ac8c75322f04017439c7ec53e1891 +28882e761b0363938b7faa0e6440e1b697db26de4fc2b2f3e1752d000758 +978292da03c7fdddf12b5f11606798a4016b756270c1ea095fca04ef36b1 +a72aa27da04d2dc9f30843137834a4b3397eb87f107631bbab8e724f0014 +2091b558357a0753bdd88598877b4a506078292186a852f36e38e606b12e +ad12002f0273108c594d86d04279282427edd49fc3325d7cde76e9e50e17 +c3ead48da0b5b3409df1e7b711de6ac9cd1a48b907e0e6fab8df98782fdf +48dc44433148424304699242cecf9bb4d699114a950d53c7d8166018b08a +b5246d836a0633045a6c0fdf7340ab739e04ab8928ff7ce64875682bc514 +2618c221ce7b6c38633c5afec9e0ff4ca14743d21be4ef5630ba42389f99 +3ace05eab6b06cd8413a4894a3ac685af3b9e8c134970390af3b8d3ad582 +eb2c948b529d1fe2dc23c8919fdd29a295d5088662b9d50c247a7b0450ef +0c6b4c8564393dceb5a1b670d2b77876a5927969fae71403c719f4200820 +12741fe56d8bf8ffbb2ff70a7b1b7e95478b8500eb356f25ec9d85578e23 +cc4ad1fd61cc16b18d556c0e6021cc7c6317aad2523d1f14eeef767ba598 +2b683bf24fe0cf493cc39c7117379f41028a7cf9a95a970fe5e447b6f815 +da7f0aa455ea915116e94281bbd7300ae58873444d3019acb2c734e114ee +fec3b05f84fc994070dfcb82999bf421b51f7430bbcbf0275c157ff4ebdf +d35103fd111a0281e8d52b73bd42360b532f46f830c3a78d44db18d238f3 +21189d7fbe4be34a67787594d440e012e39a439f48267cb383d7a8bfabf9 +08d6fe86abf91c967c1a2c45943dd7fe6cade43d95bc722c896495ff9f0b +5e85dfd604187857d6cc0eca1aa46ac549fe0e4d99a93d7ce0f712db3ca7 +8a157c1e3065190401e13dd84b504a20b9b1814024528099dc401b6b568e +ffa0eaf97cce9bd173ac9be0d1c0a56ee21ea0f94e0ec204461ff5930f6b +01e2af0fb5fb368db5ae44bb9861515088aeabd158e1f4e8617f5b688c08 +513a96299dc88f74f56714844b19ea7416afe963c3a0919f8942124980f4 +9cd1adac4d1d49f9ffcea28ff611090163b5e07129b900304292df6134ae +eb52bd7b44d0ddf0c06d55d65886a78d3a1e0fa480ea21119d21989605d9 +749ec25026a04026c91c3882d2ebf341603dd84fb0c138a1271dd6c27cea +2d329de5d810f761212c71bd92da4c9f15592658c9d81211b90763ea857b +53ab18b7b18f2026ece8841a248c5cc92dc6b6df59e3fdfd04aea5cad5f3 +60f718609d5ac00683bed6d743942cf10371ccde82ca656ec31b6bc726b2 +156c2d5606304fa59ef82e2bd2f212c6e86a9eadc31830f5de8e76679eac +a9f21b48ff6f41f54cc057ad2c02b030ca376105dc8324bee6d380f82672 +531eae8e4a2dd9c80a01716ace85092dbec6563e7f055b77265b75d416e1 +559133c4b9119bf69c405732b61bc669ba6b6fbbeac9298cee1fcef26b41 +89499086d2db96c8afb534ebcff7494177252aece0b1b9689b7f28493923 +a6016dcfa0ee015025f8bfc4ea2a29293a7c5b8342f444db215a9e765270 +9a67b19fa0bda6a289a394397d543a444ce477e54341435f4e63f9d158d8 +12b434f9f5ec1e9f8e1d5342a28c9be494b49501c6f9ef349cf2c0d24a62 +44a3652b9079a1289ba7031d4d97de225df6ec42a8dcf13ed3a37571d600 +99d5df67769bee27a1b218198a3665932efeb7fe217b4314d3a4d7991bef +6aa5ff8b8019a5f30a609f27998045a20708b9660ae827d5acca04e94c00 +49e0ec57aae4c0e65cccbba8528867a186368971657d5796c1cb1c0a3d2c +53d8e215e00dad145328238997a71baaae73c21afc81c5b719eb10dd8b9e +e8f3ecb779a39405741bfc078bcc995a4fc26eb9d9698f06a0f83f0c0054 +2c85b7b4827b7220b071c88194d0331a35319b638a66edd7be30e86aa1bf +f1d29b0ebcafb968c68f6ac51766b70480f15b4be0301ac69fc8459c39bf +dd40155c141faf8fb1123b6dc23a74f7cb863524b971eaea1574c67c0fd7 +bfbcbed4b99473e07d8d41481129fd55b57791886b626f0b1c5dcd3e0500 +861a272095b1eac096bec7f2dd53b1e4891ddef5410a63ce5bf7485dfe80 +fb961594a833c81ca8a581e65777180e5670307c9b79ca97ff38bcbf0629 +95bdadbe5ddb4d0a90a5de1f3547d8cfa9ec142485aba94d597d1387b937 +395f136e3e934b73649dc4bd587c785048373b4936e737724aaf6c407fc5 +7b8a1be3f723fa4f4a68511df9f7b71c6b7065c13c15fd11ff74697647db +29dcddb07658274959e8b511a9b35e446541d39cffe121329ab2d94c2709 +e08c1389ff7afad2756350bf2ccb35f34228c4eec4eee5656941e2e867ad +1d285475939c6950929b33cbfb30c50cd4b32bdf6bb25690f32ecabe1a71 +932ddd6f19a3b629173d1a3a24308396244c8507e472f63955cba693fa6e +18b1c61e80d5fe79a0266831458a37e4390d44276494dc03cef7de44933f +1db94bb1958d8c77cb65b756af4b87b1ad13c6439e4f9803bdb264d65fce +9416890b7d054eb3d44c224d52db95d803d1cf2b557c003c453d48e3ee23 +b20d343ef22981faff7e9d7a43b78b2182aed25b5825b03794948946d30b +30cac8274380ad33065d14ed4a030ae00533c0e0728590efee415cacce63 +e814a0fd54bf98b25cddd41212617f0d39884c8625cb1905ae42da701b03 +6f60680711ee85e5f47dc056045890156b146969422e20f8a2a66cc4a6f6 +fabd063a168f3bef11d6a369f1418b84143d71d30c6d965f18ab4fc08987 +482f83138cdd6fb4226a4908fc091f229c6265171f0cb523286080779320 +b30d4bd678603ecc9161ad8cb5a501833287ba067c97036080c9c93bcc12 +d69013702302c705dac256d764fe6f1d1d57b0c58e806eb45fa42dac9f67 +a79df2b4e9e3ef2e779d00a77f7923d8660a70253a3f58edbe1d4bd6b9e8 +606e9ee90cca725db85221628749c02dddc1b29b64ee0d7e2c4649d972f5 +047f9b376e498b7ac28ac6d90d1e34483c24f1746361b61276f10d6fc383 +5b47e2fef143bf9500b9b8324639a7ae78b2df882457c4d399e5fe605a96 +c9f6db5de2cb22c7119aec39be3dc6c208ed1fe6fae4e11dd8905570eca9 +7c438acd5eb741fd8b355564e369714965a62e86f91df8106e4445d4d959 +a7b90c2dccdf3df61c9f040cffc7bde8c4df505054242bb01e98b057c64b +f660334a7a01dfb2f143606c072fd1b46a054c9e6256767c4d8a93f061ad +cafd450c487bd8e60d6b0255f588c804dfef128b4d8dcc6bdcfc54da55e1 +e3db0dcdd83c1a9473ddf625b04ef8cabfe7ff79d7adec16cfb8365ab874 +f0da37b9c793291bcd7b2b9f3541b18510cb7ade212076226ab000bdebc4 +ee22bcdd9cfe6c14af1ae4b53ba27eba3c85616a80865e7afd5fcb87f5a6 +21678a5583d69a74c51a61e64c4aa8792456cc9d28a4aeeca9fe4764f982 +e526724a70773824f9dcbb913d87ab5c451fd858154f3cec4d683fb1a1f3 +d72274f43db4b0a9fb32e1e3edc5b2ab4d19010fec11e349cc961ef016ab +bd3681d6b8f3749d2f6e19abba2e2d8bc2a64e926e5a54d1bd86b59a5409 +d58947bb01759777e8924507aeee61bbe36ebabc7bced4269352bde9da07 +c9b0551452f2027af01c13218e9afec7c684f8a86b11d4e303e1e984758d +7487bfd59653ee8699a97c570ae0914fc2a9457e251a9afba94d4157279c +2626025bc79b1893543d1a35c866ff5bc3c021241e0d1684cb16b3885af9 +d2f0a20ab75bc56aed522d4e32286aaefcc802402d6cc60b2129ba3e06a7 +5c7226bdd46bedb2b55962b586378f168ba9fa4a09e6a910a35f57fe7080 +e53290537a830708504050d779d6d6a746e8f2f0aedacc3b2eb034175790 +59ceede73b3b0c611f57ca4d102eadeae2b4f9611270969a4543b3473169 +ce8b22d2fe62b241f661e07671d8c2d95d5444b905615ba5b4c2cc794889 +2a2c6a0d77271cb6f28407eabad0202e25d8400f006ee3f241f5be1f48ec +004775469717653b7a236f876b2edd88d433d4b8ed2f47f73d964a9bab03 +8c3e414000c750ecbe3fbd3902f8d24fd6ca52d447227053e3549ccdc49f +ea46ec7e3578ec7247f77dfa265a007a1b889d36e505f7bf8fab3b68e76d +9bc00e54dabd29b1b3d907748ca134f067230a6f8a079c8daa81b2bd21a7 +ab19995a447f6eee35e6d8c503cccf679b6c8fcfac07c3a8eec2ca9d512f +5af7ac7da28c391fa171153a39ca6e470ca72c813b842efcdab632f3a35d +278e48786adf30c671a500df993b4c27d78fe6677c27a589ba7b52d01c0f +89ae3ca69441d0cf32513d62e653908c00fe25a24a0c4dceb1ff98b0a4b7 +a2f5092cad028fc216b71e3bd49914c655811b468869853838c9cb0cae5a +9569cc9789db7d5291f2093f6f02c2aafebafe8f6b6027ae043f7e9a06e5 +e0c74ae9c1792f8877670ff1ddbdc4d332b86f628158f6f0d976d56a1273 +7b219e5615790169d20aa7caa676a8f17b6925b136bd18ed234c2b96e993 +34c0dc04026b579c5aa40788130aa804340e62df9c85ec996e35c4a9f9f4 +9b81d5c87c224611a2d9d5182ef85d01eb2a7f9a2f9f96d45d538afcefae +ac72e2361bba5c4ac161ae12f1652d1fd84256af1a2596e4cb227d5be574 +8150f1371daa0e04a7855ff191e6c2e4521f5650806f5445465614af801e +4face7a7a14989551b6a00495935ed1ff4172abf5e78f5a0c31ea6b77fb9 +30d58d808f47305a6a0c987cd6b2d93b017ecbfa57070151f108554cfbbc +069b9d51cd372f6dbb0b7ef78e650446b0e716f09abb1ff0cc1f81466429 +74afc5ed85e5e87bc9b022c1a14d72fb593b9eb7e4f099850eb8abbfec11 +8a69ad3e178e8b28bc2b0af9ba3a8ba6c415fb55d1fca117b837e4c2659e +8639789cc35859e14e320fdbc399db88fba095ad29b0fba78fec3da253e5 +48726d96ac280d98b7f45dfaa31bc53d2fdcbbad1063ad462c44eab2aa7c +c832ec1f5cad70e2409dfb3a487dddfd3b36504c1c85ad04d1b4103ebb92 +a3f801c8afb7685755b266742e72aafa3f877c47c572bc969a18a7fb804b +16430a5ead8b2f7fdf9f26ac922884906cc1eb171586dcb792b274b2134c +04f7599d8717b0ee057a3989a721ebca30aa85d31ab943797023065c5f64 +46a8911d7da276e6ecb4569a9ebe5d6f18b1296716da7b47db14c32e3983 +3d361eccc811521394cc38b47d269b6bb04f0bd8bffb63cd0b255c96c98a +0a0c460565c9a088900051fbc66234013245c12fa47e5c6559c5c1902a3a +3c1935ce9a78e40fcd17863dc693ee726fb7884c7b7de5a6761c69424bf9 +2243779ff6a9e566ae5372ad5a4a4d0e8ceda90ea12d22579b015f6c6e9d +5445fb555b45bf280c03f5049d3db36821711c8a7dd5e7a2c1cde2b37c80 +4f50feddaeaa2b8a029bf47b4e917d593418a2e7213840e79fd2d16100d8 +2b76956922fb93ef5cb7a16afe18ccca6bc89c2b6403b3a1ce8abc2768d8 +9230053cb2c13e39322ca4e4682ce1f3eb9ca5dd6428b9ba1c0c573b9bac +afdf8aa129cdff321adfd514b2596a7ee73671d8cfdffa6014df71a14bcf +7c246fcac11954c469a5085bcb5865455e7844f8a4113aea74982d1ec5e0 +6bc88b0656aa6dce6ff19491d0331b9e12d348622f1189743e974c190304 +28d9224321063c40455d1420617ee056572e2072ab254af4339bc975f95e +66b093fbe3ce5d6bd5c601a7ec41bea52349f90f585fc52e57db9fed41c6 +106e15724c8d25e9a92a976047e14c0283981cd53220560c4c477985e5ff +09dd5786a3d6b20337ea06e40ddd150aeda6e7416f439bb818e267a970a5 +4fbd46088ea02c1e8b689df81ed517a237230df2369acf7ee9ce06c3e24e +83a5620ce47047c725fb6f57a126d55781406c670ba0dde4cedbb7b28c3d +a928b6b828efda00f21bdc87638a6bb59b129f50aa79ffef05cddbe7f36b +599788d9b81380573783dbdeddd08b57aa600a8cf8a294fdda952d6d1d60 +980feaddb0905117f5502198186e8a57019de97ed3369c29d217fa2cae7d +94a82acddc8a32bcfebfdb167d552ea840b9e8b2689b03724907be1a8f97 +ba4ed0e0fd9825795fdc5464a45d3677fc7b146f6f5c66d87a0757df35d1 +5ead8cad4ccfe98659b6c5811de82cf5644e00434bcb8bdcdac7cfc517cd +c42e8b758494b6939becc2d6426602f17607feb9a71836b10a59805ec430 +fb6efc49175010cb9ab1953e906cf66fcde4d252a683cfbac8f41e0d221e +35fda9067decaa71da1d439380339245090df4e21d81845b233f64ad60dd +6d4046b1a257db23e682d0665c552fd3ac6e9565a73f8f913d84d86273c5 +7f2514b289bf51528798ef4c390cb227a567c1b016e71f02bf7bf0ae8949 +9de53d074c4ae495582317a59cf5947fc469054648b881753b22f63ab936 +c862ece5abfafc01e0abdb4cf163267911229c36dd1df042acf932f1c587 +3b0591c26f576cadcc6a53ad637eb11c8c2ee6cc84e1204025a928907a59 +1a0e086e354cf1f583054953aaebcf4ef89c4eb2c3f01f409efef375cfd8 +ed932d6ec34ac9ab6b0d95842263259f21df66de5d5ae771885d8574349b +895974407de469058c94cc5d5ecf949954f0801e5be8dedbacba7e893f9a +14e211e25eb9a8d426ddd692669f78054417baf8dc282aabd7efb148de94 +15b56346e55a8fc3e5296d739e83769731c48a95318d95eb493d0054b9d5 +887c35cf2e4c380e50e1be6690c5f6e9e7018cda116d0d8a983d43ee2464 +565bf8c1fb5661b75838d1c1823eaecbd2ed2721fcc353516e94f5ca4013 +9b8c69f69abf489fd3e0d7066c5a722cf5ca763073041bae3fe9ffac261f +75457ba5d0f546eec5741a770058b2e8b76958abe5a27cded4a8d190ad7c +5c53b51e32c105f4773daf259e6d1b25e95d8cb00180523b5180753a18e7 +faac7c47fe9c4aa719ea216efadaec522d1df90632e54f8cca66963a5db7 +8452df426945798b0f9151a929571525995e15ee2638c74bda75e8140161 +1aa448e93614d4841a0b5be40198a44c058ddf14089881673f63268201c1 +99de50eb482a0e2687f02ed99de1af7b2c40ef8ae43e84f79923bed8dca6 +132d7602bb1ea23b10469628c6c263acbafb2f1b9ae53d0fc9ecdc64f3b9 +d513615e1bae542dd407c668d38bcf1f290c822304aa49251ed252f03650 +ee62280ed4e16902ca2eddb24d71e4b16617f447c6bc907db187a01e9be9 +1a4724816136be46ee38a4cf3c64a85ad44e1f2baeaa3b56ffe3f71d41a4 +24c7d9b3f5d17d6e2cf35951bcc0ffe285af2de6f41eca1654b4cf0f8699 +d059919740222a57333140acf73fdaaf99678221244b5245ee90d14e1727 +1c2e22c0afcf1d1b036d2e69b02fce335bc64ac55417b6f53bedfdde7900 +d8861700c282ec1bc90822fd93925d75f0edc3e5a0d4df89a5bc4b31e292 +0ba4009bf1a263b0f752247825d79f9f7f8d62ffb38b4ef51d08c76d10a3 +13803a82a4bbb76881f41a48d3723c47516048d7a57b0c129462c1e02ac4 +a3230c53557111e7451597cb5c005a2aede03d9d632e0c9f09983d67ec24 +2c70fd67c384f01cd52e27b685d4bb9526440c1ac397172e2e2f57cd13af +cc0d777e15170d431187d7bfd6bae72ea57cb378f900f83da6b0ed75d322 +22fa8bc634de08716904b8d1a114e9417505228076b7e1d3a33fb06af851 +da3449b9b9d7ae4f9d78839e3c2111a05d1dce9f24314d86db842f0906b3 +94fea407f6454c30dd97c6c0bb81a57a4996f557cec7573e91cff5f46a3c +1995c1d3fe171607787ee048f64a17eae6af9023e9576fb4ca2ceed45d91 +956510b84e077bc62dda487776a2a26965d16f31d1ea5b0fc15701388916 +802b8453501007d6cee79532bc26c3daa5a2e05d8a17f44fa7fd4c02665e +d14b939e8b853b303822bc1b3ec52dbb8c88850207eaede917663bb751e0 +57b6904968ca5b8685c584c11b9c98eda0c7cfa531a3409fc0c7664c954b +2d7b7ceddf9bb4bcdf14a341a810ff4982d9a43adb40314d5659fdc2c790 +511cc08557e35011ef1c00050e9382c570d7161980c0e353fb1785cf9cb6 +a2a4e6b5822065ac84912a3130a1a8627f986a954701f8a47e8a9da12d27 +4ee95e51dcbe6dce622ebff358e63d419ded06afffd7147661567b685b32 +e1c17f293d79175ed1df33d10082e30f51cd8bc85c7e817dbaba0ea60341 +d3e0ab20bec2873fd3d15bbae37b4ba1fd32d00c1323be6aa6cd8526ccb2 +fa6018e0221b8442e1e186f42f49e748666b1a67dd612369c19afecb598f +1f461d45d4acf5b6fbd01240c46fe35bf9f96019fb2822ae4da1ac3c768f +4f0e6f671c4808e6c19e15f16672d98e44564e4aee08a08bdbe5ffb51503 +d2fbe78c1b077686387bbcb1ebcc145052de95451c5f77e6581c52b13d17 +8dea432dbdf0c97e9fb089c5e44e26fea6ab9a4ea072d59ceb63338d5274 +1c43f684dcbc44d107bd5030cf4390e02322b1fdedf5911722e59c7e8e93 +4ed3846560f4b0c4032a98003b7ad1c86d7f8e1f2143aae7669a8378b38f +991943e49afdc73ca53c0fe9024eac2a37a1b76bde80ef26303a5ed29efe +6d664dc5e51788476cf8d0a838b0c49cc4ba6c879b49ff38422a37854e73 +601f7f19945ff1c46d5e685764f653d795d5c93814fedb0c3e88e6d9a5a4 +234c9284318477bb52b00612953a9a8ebb22bb74ec37b9e34b2671cf85eb +561bb29fc84ea3d8b84a92cdc6310bcf9e5643f4b4ec558fd6ab4faee1aa +1556387116c82cfd9f7b5e366aafbd365b1e291352f5a77cd13f4f32038f +c865be940292a3114d3170201a2e1af005e1d176ec573f33e0343f665679 +6e1f02167acd81378cbc03f18699b535ff635b80bcc4b449380da83060fb +7f7703d94e19941acfec2ae9dd11abf85da49d99f38da1e76d572991aa89 +0a8b6cb7f9174f1445c5926a466666fa8e2abaae5d7a16df2e91dc03f07e +2e4b901731d69b7f843aa41fd2a7dc029c43510ef3f7d6b82072bbbc4def +972b4cc2fee6769910e251672af8febe017ba76db5c21b5769b6cab61314 +5652fa6e577c20e34426c2c902c53984f23a6b56f43020001c390a6fd655 +0267378fe8094baa648b722688ffaadfb08cf330d096983f6e43408533b5 +ea3a520f89443e0b8819b7c11867050189b659115a9a19e8f5bb28f27d6d +ee19fe63fcbea06f3f1ded2e81fc4f493dbe06e26742ab961dba195ddfe8 +6e49390d7094008ac5214d31c4feaa246abf1a285365ed3e65042ad9284a +b85486433408b9ad90f2457a3b62b6fd99073f0b3a116be3bb6a568ec27b +abab5a5a37d1a15f97e9e075e1ffa1a9be38bff64e366b5653d0f2901a38 +dcfa9b7a95a9a661bef4dfee91e68dd6a747c712963415309f9512a75fcc +b68e2b53b4ffe5aa14c49a4346dae193efe95253463790d3075902142022 +71c469ae3c6bd625f93c62783bbabf4231c1c9551a64fe3d13ca1dc32f78 +f506e42d22af63b0e2fce3f5c9677a63479f4b3dbf93bb83136a5a2731e7 +38e5d3c9b4a218549203af2a1fd06f8c1c03deb6de61d18f2884079464ca +ac1e8bc7ff15aa770ee581d7b5e33b2e9313077f2fd3bf9f76e6e359123a +62549e51d55540bb2ee0f496d25d84d8cdd6eb58bc23d09310c72047257e +f9f8a60481dd7d307f7654568519f6011f2d96e56d1f3ae856bdba5f0a13 +c5e45f58df9f9fb757f12405c78a71dcc5fc5e258285ab105ce64d1964db +b93811c52edaf26f2b2bcb98be05966f245bffb7847cc2c67ab196e5afbf +2c8f12e725366a72b8e0bcac99317489123cc1fc4d693dfb84990efc45a8 +89fa7aa93026d43db1f4fa85c35261d08e4dc63a06db06bd509adbe77f43 +d6a83330583667db9789ab88b5373ad587cc48e38d522183f4d8b7663d1c +5d147a53aa70bcd4f4ee824df2824eb837691ebc7f46e876ca6ee19ee1c3 +38023b3554721f1aa857f1a4bbe4ff2142e1764f273972e184f08ed35658 +e07f6e189debe065264c8e9446e904d82aee35d8e2c0f1061ec6fdd5cc18 +c569df3cd3c053f618ad59b6721e464064c9d4712f2129458fa813f84081 +94724fbc297b2f2e1e1bbcc7b6286bd93bc112b7e2a322b5886e676ff362 +88218e94b483212dc4301a3dd2d55c14853c21227ec300c49f3450f08a2f +61151d77527044e59369e6160bddf601497466bc37468e307e1bc2fc4687 +25f29df7d9be742e6a4f4f4626a30647a44e5271ae1e781347a7e29bb052 +5bc5ff0bc7ee0ecb33354c1a0e9fdafa255a4e46dc00fd5f6f1725aec2b5 +5a88fe79eb9eb272c4fb7c4f537fe9ccdeba60ecebbd820865dbd15a08c6 +482fa4247ba6c1e21b9c71f05bcd3796e94a3fbd9e2e67c4df10a1df9aab +c8e14eacec97d44f113f4281f70f6d8b662ab85340c1ee716b78c0522360 +4af01b5f46c7f9a3d0f7e59c19bd8c32d8d35d127f45c2824f57b2f205b8 +e46f947bf69322c02fca611eae1563e3ed4cf524203f45e135699d26e303 +3eb5dc1d3ba6666188e5e129a843f97b84a3d8ccfc84c15777b8d7dbd5e3 +f75f087e068857173f795b644a6a4ff0e127460d150cf0225322ddc0de2f +2011373e64991546394dd27ed68b8182fd7e9885cc6b0507157a8a7f05ec +99b7443180fca4a174b7aab110d9eae5606ebfb56ff53582bda01228d95b +38a4d87bd8aee6df9e95d64bbbac35841a478694531e014327020c126d04 +06c0466d56b63409e77a9dafaed155452171651988f0f6ef1c357d9b0bde +c9b4a3eb25671498cb6bf5d572030baf3eb637cbeda764f750431c226aa9 +90ab7bf1d1593d0243c1d4da652b6450af330130c3bc49008ec4094a12a1 +d83b5f45114121aef163209e39213326d35f380824b80e8041d2e98b6c7e +631067a43a05f5eaf6018eda387d8ef342a37b08ba5fc5c861d8bf70480c +6edf82f9c973ba0a8c1ba3a7639615452b07390069b078832343082096e4 +da3b0885960e8ec671513abc733afb947381242f4c207e134191c7707ffc +e833cab39b31e4b67097123daa326ab006ddc77d2685f7bb9b1235eaeaf8 +0433bcd7424bcad8c6b26171f74638ac2b07fcdb3f8aafdc5f50b803c01b +aef58089b007b8aa3022728c057b1a71343dacc41c5eac4fc4438a8254f5 +aa932e415b496ec9cb16ba608fde83419d2a1ddf556fe8d603606ceb24a5 +81288c450a62ecf77755fbfa986fa0b0de13347b2f90a8cdb7e235dc597a +ea9ee287650b4869ab58c97ea5597beafe42535a8c6a345b97af14b69ce6 +369125518cb6f7a8968291c6a6b16160193d5a218702b7523ad35710efcf +4c5c8e9a2a30d995dceb13eae7173a23b4aaaef58574a266305ea7ac5aae +801c2c17045a0e25195db4a85fe78cf842fa7e39a203842d2f7481603059 +43c36d4510f3fd829dd1e481d6dd88a15145a9dde88a2dbf272ba516da28 +e41408d65e9a3e502f610a2321e9714ad06c425e96d13d50eb8d4ff154c1 +7a854efecb9cc72927a542b87c80c485621debb530443e9aeca23fe2ff9f +eba32a4d8c96bfe797913b086becc4ea17dd74c28b4f7fca43f431bfb688 +f1fcdae565aa6b7d1401392092307bf35fb5bb3837e885f765f1c4ef3148 +776857f1c184626a9ca19892b1c702b72cf9b4a698a88f3baafba2577874 +822f4b647b3ef96da58e45890fc9a0566163f4ca43e1c5e2a862a761da31 +f897c50ee5d0ef12406dab7247513cacc1bebf84020dd0ca2302f3458210 +95042120812080eafb7f2e94c67c881bef05da597e4b5fc797441a290a3b +5aebcca1b9f237f2b92335c8dc10b08e29aed74229abbaf575ab5aedb944 +11c5d1f83715139e61aa9a56276d48633dcdeb7f5a9fff32c9957168ee9c +b16a99a46be0d6c027c1fa51b0ccf485b79ff065a3a574ab421153de39e4 +19d66d124378c3831944967bc1719cdf900c147e5feae77d6a0d5f65cd57 +c860da06d87cb87d55b97304fd77a66e2865f470a41d8660541f3187cdac +e346515478fbe50582b9ceb26e9409bc294a43b41d8d2eea2e33a9dce83d +1faec4b0af9dab677237b0d442e07ee79c25dcebb8faa958ed898ef991d1 +6634bd80db743c07f0708102141c9c3249e09999483aad5fd7e06abfa59c +ded8f5ae6af64ec5f6e6c25e101b76580bc4a776dd5e909ce92c5cc23241 +fb72bacf5ec93550b6ba3013554ca9088cced45a8cc60029f3a7ecc53be5 +eafb169059ab4b73500668600dc145c92a63c93c47a00c4a6bb050630d3f +09bbf0a56fb590ea0f3264010097f2c755a7f47587c46c0e8f48def4ba1c +0d1792d73abaff05f2efa723ced107231f1ea2dd28c5ebfb2a2c1dc8829f +557adf120cec34a9eb62e36d03175564999fcbf6d74d2396dcc632998884 +69ec81b3ca10bf1c51e819396959e76d1e7a7b71c546e9169d885af04a80 +1e05222aefc8ccb775cbf6991569a1a5226271271599189a83f21cbab3ed +bf359eafcc058eade8388d360532c962078867b4a024fc2453e29fea95fc +859a0cec970180796f5b481f8375d7184418e26fc03ebd4d1bc9a902bcd9 +52a0db1296355a2fe09a65f7fc344a52e20b5191305fff4ccc97325e2fff +56334af2a34f2474fde3674032387c08fceec52f19c4f73246dd303af997 +1ca8c27b6fde3cd2b6d3267ec82dd369beaa19c08beb2e02113cc7e93e39 +88cbd6657b210d6fe796f0325ecc3105f46d06364385e609475b967e52db +4e4348e39d519ceac21357600893199a01d7359c8e454c102ec69744b07b +87fe539f0471a474a66ba6025b12688b4da26561ac6d074a2d3c8559a00e +9b8e26cd64afbaf673b83a89c87eddf46226ae4173af0964b5dc3d917eb2 +45629537828d8eb0b2a6adc511d268db029b1c42cd36e61ba324894ae433 +6f3febd08bae3234e3751c1f216b22c5234c814cdcd5a5f09f5c7a0ab02e +6ad3d02ee4025f63f9139ee70ab5f5d2985ce11b38e0143add025ee46f0c +2a1db3ddcaa1f85c068903458541ce7ea038aa238cc6f40085659dda05c9 +f3e59ef16e4b140777cec06ba3890634f766b44f450b98c3323381e79b4a +bceef7852bc584cfa32115c193d207940a8f0dd10081068188fb47877bc5 +7209e4818917d5d619b7a71620f9f5694f8159f114b6bb9fb357b9c50637 +97ce14b0dc6a763e80baf1e2478599beef699e9f2b7c03b867a59e615ad4 +3ddd1eabc5ca3cd49cfb895d38ee79a292554cd41d16066b06b0c962e64e +aeec8c3869537215c567fee6f356cd461024bf044af06007ca6c07271780 +51eae2b5eb297ade5673aeae031a8dc7bfa4238b4948b2bdb8a7ad2c8999 +825b4dbb7e5ef34b3365dcc71c6c44cb7a6cc01b65a8171f0bdc4a4a76b0 +579aba33c438cf7f10b09e546ba21ef3fb29cb387bc8e9c7f6239801bfb5 +7052eed5c7ad75ed51690ee5914d367ccea4269d955c27f1f0f64d1e4f16 +9bdb8621918617433cf82d7080cfe820e4f28dc5cb2f9cb6e789928407dd +afc4270d7d5e34e4c0cbd3e1822b4986916fac9fb6d5df23bfef93db2d7a +2e8916c4239a13f19cf63892f045d065bcf5c8403d335ac0fe41d4286f00 +c3d89adc24e17420f797ee45749c72718bea13c243a91eb76c2159dd85bb +b6a7a9233a03d5dbed7cf7a7d204cb61a40cb657886d18a29470509bc67d +5afc33894746efbd5c68e491788f1783b9a176ab9b4835803b9b519098d4 +ca52deb18c099bba120185f86254aa8c5e42eb9a6c344924f5bcd62ae45d +3c490e2de6e57d3bd2407faf5549fb7bdab9252d2e9caa0ff0b7561046b5 +ea7174db13068e596dc52d6b9fef5249839cbd4320f118654a90eb1c9df0 +0e07d9526c5c7a1ed71fb258b47ac6d2638db0757812a271f5e20b6dcecf +c0b09ce8d92e63719281f666906c8785873935fe88852564ebdf1cc8235c +c3f5950cb7478cd3c41eee53fe028d963a48eb599426fbb6bbde891e8d4b +9de69a4fb790a4f97887497bb36432e49f83862d6c75567381d2dd409438 +6c01d0cbb429187bc0bb3e32523dadaddbc00c390875fbf5893a05d0685a +02a4bcfb0b7b86d5b5231b0418717379417d027f30d3717a2301cadedf99 +c73738abf2e90d1632e60239e75ac1421b5dfd09da8f0f6cfe3c9144974e +1ef3923d52e2fb968abe3b3de27865f2d929cf844f9cd60de0e17b10de17 +713350a859ceea437629fa3121fcc1860c404beaac5e66a9e915b305fcfa +6d4f04c30a7cb5f935c6678d3cd3feafa1cb6ea8603d3474d92d670400ba +0940a09033a3dc382340473c57461561b8477d175699e6582f7b80a527ba +3f664b3795404b69867e449e6accbe2a76006b3f94ac73127538944340c8 +370747d89df000db870a15e455b8208d3467a726dbc6d723fdeab51af860 +adea1f8d7460c464873800cb36ef56fe58e0ac3c65083ff6150739d15526 +a9c26c47c38890a0736dca6516cf1ea4846d4cc05b4c2a06d0568d8bc40d +95d3dbb3e05797f697ff00121c8e76377717d4fafaa7c22d42ad04262546 +ea908c3f2dec39d0dd73ae3ff7cf1eb0dff7d1f8911d5e1a1e82b5c743d9 +2138caec847731416d6c47683f9a02295057a3bd338fca0b115daa7c4631 +e4f60c1aaab81a796a579ff1ac9dfa8a63e1c46f20fec5c2c1f682c9985a +23b1f5c3e8db57e4ddb241f29dcf7dbeb4205f9282d042b9bb11d770bd85 +bc13b4dc753d6353c3d5c4b678d5050b768e060668b7e6f860b38d611575 +8805dac2319d6244baf0f52f76a3054929e3410b477f7652639a516fe7f3 +5499fbe072ffea5f14cbc63226e82b1f9721fbf042887fdddc63d72be1b6 +ce103589a17ff220b0928ba0398b2b3005ecc42837b019cd3db3fe583bf1 +4209f4d6cb18b44a97fa259ab5d5d50a6b51056255f39df783e160bdbd52 +1f62dc07868df941db96e4de54dd85e689eb7fd041097102290386ea422e +4e3ae3377d05348c8afb7f0f7bcc256916c49537ffc3dd9af81a4ab070d3 +ee23e07881182a9e455cf5fe9c73ee5f64e18887cd987959967bcae04045 +e11809812a7c8e76cee5a4b24d9d22d647eeafc86a0e178d76bdf7c0f29e +b5eecdaf8734ab4acae5d94471d281bbb350d87a77342abc9f04d335e562 +2c73d348560a95112e778fa0bdcfa887a4100b2c71ea6f42abb43b701b68 +1e2513bdaf1b21ab8baed2288bd2fcf86fa76a235c907002c5b07eba85f1 +60892ab89dd92f184a9090568a3b4878b86c96ecc0d4fe1d6c696b6123ca +55f5945eeb19420cee8e6b900d1c31d2145b01aa152bbe93ed98231dc9fb +59bc09f17b678ae6eb13c5830c6dd9858c4fbfd8ecb043269c87829755d4 +30ec0e47e38e374de01977c1c86c97281e1f953681ccd9df78b958a442dd +eeed85815839dd05f4ae5dc5960d7f1e3bb89240c64a696910de05bc8bd3 +437670bfe89cedfb9f22b6234cbe21f9414d3a4fba3e64d5a480518efb63 +59bc32a53912e08cc1c848ddb9e8fc23e1d287a8882fd833b8849f0021fc +cea764bcecc059d22b71300318e52e6531810153b5d3f12b8202ecd58fa2 +0da6276164e443eacc3421f57ddfb57d45dbedbf0808293df296881e2621 +9f270a468ea69591d5ee5fae92a913e2905f011bcd0dc7b794cc8b1c8d16 +6ef115e4a0f3678e9e53c936c9825e30e3ed62e689c67f6c31bf282a714f +41d988a0f35a0a01b8c7d0a3deba0d947d0a7ca5a321e379837b2b0175fc +6cd46d2dd2b0c6642ddd1496792c4b1dfae6011af1651499027a7cd1e5ab +4f52ebaac9c600bef926f955c9d8da1a5eaf4698a71fc0fc709530365f02 +5a558747e11a40c121a130a01303f668532386d0c9a576937c198547b4dd +4f33c252cbfe9d906fc940c56eeaa242c08a5ec3b44f7d8f42b3d94fb53b +5a4a8c9cb11f6bb46b153f00b6d58ca6a0314cb16e4b65d5b71c739c0d42 +59bd30a21345abb5d78573a8fb0709945e5f536d30689663b31e64309843 +28e76309ec9d0b816dff6696d34a564f694b2e8b0ad62d54fc97d2d09ca9 +457975bd86493f306be8ae6256f58ffd06b1d9066a4b3ad2646e4943fda6 +f13163cabcff581f8b92d5f33edf512bc80abc2c843552d7c7dc2364bdee +fadfee5f842c1009817f1153bf092b3191eeaba2099136265052ca1992f7 +93a85b1fe1c1acd6d6b5ab7b169c05bc65bba8a8d47d01f5c4b0147a97ca +156cee70d33abb5e58aa24669b240540fd1de6671ef067a3fcc2da39337f +fd87e67d34fd042424a4b35a1f893de8976976fa6a28f378665f0c51237f +5b83294b9e898523be5bd0920f1457c480dc88b97f25105a04aec0d09c6a +ad915de6b2d5b8f001ef68d322bf421c98205483b22f7b62797e1236debe +0196be1a423b34da6cc41a1508dde499b5ba7be07bde225a657888033e08 +134bf424c539ea2666b3c13202b5065dde064d644c13a51a6e0983d04273 +23084c00bcab73201f74ccdae02e951de42dd44039891601fab4457b4b00 +5551607910d221380656b1ecdb91f49a963e9f90f4a84668f2da5ee97aec +5daafed5d1b76ec9f2b663d3ff10b350fba44bc4208388cf3084a26d2a72 +00a0f9e59330b873e582614ed9625f33b15c32e54f0f26c8c4b272612ced +73b705f081438218b9ebe6a934a443b8667726fdc4ac2a1d3e250c257c6f +b7f525b577852262be1c11e65c99b065fa49df1658e2246c6579c2c3d440 +86786f5df550f75c97dcd42299d3ff4fe369dafc86c6ffb8b4bb0ed255f0 +899042b4a5a20e34480706fb57c6aa3c66633fc98f1726ee1ed94ebe80c9 +b80b083bebe029669ab2a9aab869f8bbab90f2e6b3e8118091fc8ec6e4a7 +42e03b9697feac3bd484f8e54d535f2bbf369a35b903366fc07d51797d63 +431f966540ce46e0fa1f4fa96fd80d41cfaab0564869925d4c6661883998 +6ec2d39a3f31d27b59b3f89ff50ad87cf6d246e961813d6cda8eacb063a5 +7071d27b6894f0b6261bdd3dba107819e8b0069b95ac6df2825827fe2a6c +008894d586edda33d4e4bb73a197fc0e04da8d91e5e58a4a8e79be380e4f +88f66faffbfb92d4187777c3ac11641c0ee6bbc12f9e25d2e02d73c8be72 +13edb765d4df3a6926ea2365c3077b5eec405f8c8522955900656be71840 +6bf141e7880d3272fa6853247fc1bc7850b88cf77167b147c90a2b33dca0 +217ef653dbadbe88d3ccaba4f125d7abce5e1e255cb65510ed58ef42abe3 +96846e6a35afd0296943d1c3be501f4d4969a088cc28b9e34734430fdc9a +3a2d5d9246e6b74345112a0168e1b4475a22efe028137d3a8531b1f7b290 +544ca21c9369cfc0ccf0f223ad60480dcd7de406d3a435d47d31032a05df +9925720f5d75a8b0fdb3ddc452181b9365941f774f8cb12f064b3c2a0104 +677b77bd9ed44f3362220e6c14f71fd42860f931703db69b9eb225f56be5 +1dded349993c82c9ac54c58f516cec603395433d7c1f91ac0477c9d291ce +c2d7408a67846ac08e5fa57f50e7dddffafb856335620e3111ee5f8e7833 +3e070845aab51c52a4aabe1a4fccd28478709b6fb7827aa068ba2081409a +396dabd3b0b7fef9adebbf21be845c7ea7eaa6a08a444a133cb40e5eca88 +bf5ceff2df181e75499514cb883772e46a6a88fedf8f42a8df053f379e89 +da985d1baf955d9c2180c61fe8d389d2f783c6ec4742b97ecf86dbd8df35 +a1b8b32bc3babd586f130fc78d0a458a9236dd38cfef1b5fd99d36c64c67 +b226214cd24e236d2185a83dc7c17de1fa7b5ef4a829739aa99e2c4df22f +7a9725c98ff1ef497ad9df4e23a07f6c0e13217ce2bbcea3abee7719d140 +37b7aeff5a8cd2a14f96270c2575010ddff8544fe3fdb7b2919438fa2e82 +c61020ce4f53b6bc089f350e33dcf757ce8ae30fc87e2f521983ee484aae +9b1780e303c281760cb7011ae14542977434e7d4ebf847e89b9d7fe480a4 +4e560371ecd82280f5ab4730e067ef1dd2458e67e5d5a688cb59376e46db +ea7f6d01a4f79a1bbd8f74166479ce63d79ea021ae3f978734d32b4af080 +3c193d584b40127a3517ff31a18a13be94b639b600b015975dbf25fa6337 +0777e1d4aaef381da47d2fe453b23dfbec0c427a274651972cd32d6aec68 +8f022334b0cc1b1e20fe5ace2ff5b8428a80323074545bbb66e9a06aa07a +635fc77f98c1b3a36fdfb6ebb598c122d8170ea4664a5313496c705ad1ff +7f8cee9e4cd242ac1d6e5feaf05665605fa6f4f66919c7f17bc4cedb736c +46e8e814b129c358040ea8b2bcd87c537d7a72ea5ccd322f7133360aee10 +8cb788aef19077cbfede0424d7490a9b9c095aa5208b2eb17be00b2932d1 +5be57b0fc0332b9c0718fddee1ec98fd592d9ff45206a8c5fe3893d921e3 +65786061ab3e3f3eecab58eea5daff02758fb7acbd8fbedb5e7ed25a19cd +2e8030b8b60670f919b0ef0d0f77d426fc228944465a8cc147e5fe684007 +c5961f2350ab38e031b37788add075c99a4d8517394b5f007d93bf7d4f6e +26d0ca16818e1bd015c951ceea444af836f3e54e5a717d154262e2e94c13 +ac246670c6e6a2ccf5574abb752a70f54c36dc938a1cd193ad898bdbbffb +0686077a0d76b96ee02aa45ed3e3f1d7d8726515d5dcc296ed1eaa36b436 +b9404df2ee1edfcb0762e3c9c3b3a9713b485f276e6adc283fb31a8f0c8e +30b12c9fb01bc2848f2b87e76a934ad5583fccb0be2077bf6805e7bfa2b3 +226375c2c1c57e58f83c85cc394068a7798612dc47fc420f10a6131f0bb5 +29c8c7f1ce725a9c2d63108116b3f486066bf441be65580d0f7357b39203 +414ad2e1edc5de3f8bc89e35d40bbf4343dd7f794f71c23bb1f544dc3df7 +1b271ea1a04936481c06dba58e0c14a3b4c765311e6f9a525dda70fcd36a +500e9592a2d09a724f58b1bdcb9f6bee2202c5c34bd4dab4fda371b263c6 +380baa85887025b1b3f82ee02cb9df0a358f469131cc6a7c7d1090184998 +5cc05234cd313da57093c2b05339ea4a33efcbae7c6fea6e83b675e628aa +e9ee04d93aa05002dbdfac3ec439134741d3b5832ec59b2ed54cdc010ab3 +f2f775cffa46a7f1ad148b85122ced80c71bda3609d646de4fcfa6eea599 +9a2d7253a2a2935b8190ea39fd8b8b23337b3ba3d2b7b28c974bdcbae3ce +23742143bf744e6d3bfa0c6b0de3a329ae49972cdc2a5a54cfedd4c37622 +3ae6fb11566d346be71c4d942e47cc0587bb1dfdf5d4dbd2c0db44b1404a +a3652d2c49cb00779dfcb3b9723a6cd46048b1c5d6fd1c6264d9c1ce8e55 +b7f5314c2ad4764d690d6c6f67c80c87e3ba1831876e4602c2eccdfa3fc1 +f5e38630316cf4b1a78c8c19012a7c42f955736074758a50949f7fe56ff2 +0c75007f00ef89167908246b636a499d1067be560dd538982c0b432dce25 +150d9cf51b3e2b376e428bec1355d42d3418fdd8cdcf153213fba77c0211 +aeaf3bb5bf9d8aecaa2be9fc22bf59ab04b9b8727570033a31c796f81825 +91a972ebf01b0f58b27cda24dc4d3ebe9614b5396f3fab6760b7a47abb28 +c639dc7675e27f8984bb07ad370be631eee6c6bff903f27646a5b12b2c9f +8fc2446ed6d29afbe34d52a0b5aa0cd25c15e65416031bb91f2cf9a842dc +b6dc7756423dfd187d624ee3fcb3eca3bd9e64ccd5293a4ed62ab25ef0d3 +f4653d94dd4a12913ecf5819b1992d22810cf648949d26bf4b752e1d8f70 +ab4240cdc4a30790a98fa8a7b80e8ebabe343fdaeba41a10d0554c250182 +d04beacdccdcfb6f779b88926fed7116eebc9f9e0e6910d3b3a480785a21 +17314bf06bd22256baaab66a2ce4bb0a4d585b2d52f8ac37445d78fba186 +0fe594bbda1207c72cf7a37d14a5ea9b9503279771af9c74bd7375e55172 +adf6d8abcc525f1bb199f8255961d075020c0ac6abf4be0ae65e2123faf1 +c9beb33832e08df28b0e25e9dc6dc8b86965998c259c3e1dd05996c030bd +203680588ddd680de3fc7dcd6bdd329ec679597e4408d248d610778bc286 +8e9aa3ffb1b40b8d3891cd03e726b1ea1d7e6e59157df0bdd85a67b35c5c +e671ac595d95fb5a9906d73e24e5e04c6ed089747163585c7a89596a37ef +aaca6a7eefc794fc65800be79f5e0824afb0c43030b3bdb342a9b4f05463 +66d93f2b36998dedb85a8ce186a78bb32fb484cabe8674dafa05dabda180 +fbc38eaa84d4e37b4d17e7717a29233a296e95ef26b04bcde0c0196f96bd +deae6febc60e9ef06fa12faa16dae0178d04527c596c35ab31125cf17b23 +aeb68f840da1465205e482faa17388f63d18c8f656ba94a1a8e8c74ba8b0 +bbc8ba454d3b42e85bbcbf8d22fb008be86e9dd22c95d13cf0a471c207b2 +25a4226265d68c8aaa1746e4eeea667f5f6aea68fdcc91de8abd883386d2 +a1a8de7b79535db2aff83c13af40e46fae1f9229e9a07b504b3ad1a3cfd9 +24c0b7b0f80c59d9cfcd0019b10bf8000401155bb62145d56118b3de28fa +5a980a9c5aa1dfdb7c9921d72145fd64fa623cf7f821229e2f5642a66ef5 +21f3d73e111761eee04638ebd933f3b1afcf9a14cdf8e39a956c1bad533c +c9bdb0c15dfeaae14032839079ab552ad647685826ac145195576c184fcd +ae44fc524d74d34b5b43bb9885b8e3f0ed130a708760e92650f868682140 +4479a88ab16cc0fa2ed5bb2cd3bcc0b3bbc37644ec846b5fa08d533a4b3a +730dd4b6e94171526b29b7f89d0501accd6ff70a20451877fd5c0f0ad691 +51be0d127502db63841b29e96cb3cdf00ba2e4d43c494be2d97319a0009d +a3112ca70713ac18562f8e1f08c787edd1346c0f43c1045d3fb5c67ca494 +8f1a4b3b120d3f8cf0aa18a7e642c5e3bf38e960f207859a922e4df90c39 +a0d213aa61b31e7d389f6c6ed525a1b5088913134fb8670291e624622c1e +3365e85925f58b68cc55038a1ddfe30b6e1c7f91138911622179bd2294aa +ee3b46bb141271e11e059abe673e1d7c76577ee1ea7e991c88a191ca1a98 +7a2ced3be8c70bc5f9b263b756721e1e3e2a850c4682a16a7b4610780a2b +ded9da273cb7443cb59a6d7a0159c254012c4b6231fff238ce4e11eff921 +41366e8c25cfa8c8af0c80a809adb56233ed205de8b00c233a1d666c0820 +4244c0f0d225e38c85344f9247e1ac59d465b74109ba18fd044912315a3a +b58c807c22a3e2f07ddd4c78c51f4e68f1a85a1ab47d180ae37394316ee5 +13e32f8b3a9416bf9648d5556791e5d4fde3d1f9f1e4a0135c649de3e730 +8933dbbab840f5e7aca82f962619688d9d92fc10f01ab5e461689b163de8 +530869a733eded113c1b4bd50663f34e2f12ed35797cc6457f90456fd5d2 +4f66cbc0d73a5c01a21892518fff09a31c5d0a69283a671fd0ed0aa9bd8f +5b9000e0de5d46e7510352c45a663b418d5f5ff9ef32088417e05c668628 +6dd141316ebef48bbbb11a7fd97bfeaae428263ec2c852f248935c174969 +b043671376a3e9fef9d477cc78533d6c6eed5249454e5d70ce3b2884ddd4 +0f9e7079ac840a59bad2770a04a74625e3fc5f609e903feba616554da424 +3bb389351b55923a7132b0465fe4bdf29347b091e3dd790e49f9ab22efc4 +174582994879f2d6cb5c0fcb7c075d4ad35ca15c50cd05b5125028fb01b1 +0a946e47907ee7dfee9816a4baacf58c6c267586592927bb42f798215c07 +cbb8705900d00a6cb771e0b50394307f5afc0e696bae7ceb275825cf4bd2 +72cdc83e4c92c1a74ba4e49f36b665f22558e50bf2508d47d00a3db176d0 +74a97ac384bf912f15a11d79a1d834765f4ba678c00acd9ba9f2fed3ba0a +824a76b91594fc57517667a28ab6ecb370a9c99e79a6c1e26ac0512fa455 +11a188dea762acdb3b4c1d00238545cd8f66845444b9389b3386cd1a4a99 +28c199bc903895b40f7a4770117ba88994d3b0bda82918ac4c657a45626b +cfb3c22da3855d3774f75051b3d743afefd9d759140c9509d7cab68497a0 +9f2ac7856ffa0befd13e74bcc5e3dd8ed7f0b5f31ad45068284be0898f44 +65dc13bf17e4ad69e2b8e490ec2670e184ab81b1e96663cedf9533257cbe +cb29ebf27089f6478f17d12ab93e521f8a31c3f631d18dd3506a00019e86 +6112a6239fe5bbdaf15e88c1fec877a8bd8d1d02038f28159a7b18fc04d9 +15053b84a9d1a8568c44ac1b25ace3dbe913410bc340f13200e05892bd23 +efd7888ba0f8a19f71b025cba05f1c52d84e7af93cff7aeee6692c08aec4 +4a3ae446e27048b4dff167a4d1270493a28c84e72f8c915bd95cb67d5e07 +ac855ef06750225071764e1f85a46a62b0778fa0d16edf3bb714c5a0e259 +aec71c6d9bf808356bce7219ace6bc8750658903d58ba77d787c4130e12e +fedd4eadc9dcf60758ca4f6d1804d36e3e8dcce451522535be0a136231b2 +8b60ca7285d9573cf125991a07e1b9b747b0c27f816dfdd391c44610b58e +575b415e722e4b2983d05b1952e878a4ac1666c9ed613de46fcf148b14de +c380b11f8061f3de38b92015878a504cda1238679db31911fe82a0b8d48b +8c1b7258afdd18261966ae42b93079e9fba683a957188f096a9e219b7fed +e7bfd55f4ce5ae3c57f5ad7314278a17858eb68766b2383c69de620cf450 +40936e9d2e1317ed4a711ca32da934d1e00d2c54792bd7720d5a5439758e +2e9307c94255f8e33be837f43768c85c2ff0774dfe18a1f3cb4d8544e4aa +8fc72aecb801df075f22773dbc8c7aec5635bc4750d0a2392307dad6bbf5 +84d065774dfc0725d4c56fba356eda94ea9538639f01bdf8e5963fc665c0 +159a3117e345acb1eb6a4a3699c54cf096bf369782c8ebf62de423c8235b +4db3ff59cf130c6f9c856912022441946d703baff74848cf0bbb16edf93d +0351de8d9a7240d3429ae4f1268be3ae553983c415cfc43226fb5c813f17 +2f440922e73cffbe4201add64f01c37ffc36e9b746b85466566649fc71bb +2db6f88a1241e9b072980d136bd8baf9be30fcf86e5a66e64daf98f03379 +8d8f0c19db4aa3de7300996b11292c7bb67b88eb3dbd9a9c5c2b9f37e13d +7c1c8d66e6df212ab2ac7dde58ba5897bf3a6e4a607ef1ac00b062bcad0a +20da8dd0557726496bb7c55137f373531c620ff7822d0d2cda8ec4aa2b5c +70a01d39be75a40e7e7dd4868905a358461fd451d650a6c48367dcb60d5f +884425b4c4eab84749646810c829924dee4a8fdb49e084d013037e2f9fa7 +eefcd4ab8c7315791f6e77c3ac749ace6216ae55576c2b7f6138c7d10940 +c805be36c488efa5442769118afbba36fe78acb2b702eccc44a5de3f20eb +0a6c3a3ee947e8fee213f034adb2195b84cdfa089063eaef5e489583c42e +9475cc5dfaed3b90aac4f809cf9fe52a68a52f57c329b7d5b191bb4d7503 +88398011eaf81116cf82102af320c92a8f4523f808d208cefe1cd7c4c1e3 +6af03028dc7bcf6129e82ebe328c62e8b851775bb4dbb99314bc4b0c4b4a +0668d6e891f4b5cafee3cca709b50efbdc63a6e4f0b645c24129567e4aa9 +76fedf285abec1b21a94e1abe140f54f1605a05c3d432a316fe92f742e99 +0d16396288a812a9951114d8cb688ee94b7c4977e398e24f0da3674610de +6b834adf3ba0d324a395857f1f6b613251da72e557e0b501566b40a6ba2f +c33e327de7ee6ec6306370fe89d1068b6e21d3fd16c643e75e8daef9e21d +4c4d1ad5ebc20b59a4ec8d4871aaf61afbe61249b9a7c98cb11713f757bd +7cc495e990c8f4c02f167643226fc7bc519b6ad13c108d0fcf6011526211 +287149179cb3a365beabd956988b7427a6c99e3138cfca940bd9a100cc42 +29a4e39394f13170e020f0201d3e12fd8733db20d6429397162fa80cf651 +8df73293fcf713c0718f4cee898e4458d20fcabd7df1d515160dea8ee657 +ba23b9cfa04b77e9735ea8a28630f4b59c6c0c880454d83163276d15a44c +54954e0db01ab948e5d43dc3d9c35188b5985f90d3836e98391cb158e077 +dfa96ac6327cff10098b0bd0251c3f8d6b52a30df2057ee7e7ef476df08d +a94f6d7205db461c59a53746295d972453d35259ae58e9c84aba5ce78edc +9dc3a3bbbf9a8476fed3dc7fb0caeea41e4f9133df0f6fdfca03fc0a0929 +b8c9aae471306e8f5d6a4acffaf9cad054ba131f95480d9c39ac587d772a +42a5eb6804e1949034bb2797d26dafd17869bfcb6ef7ebc86534cfc47285 +0a387e630adf1f44ef3030414a043d1a470b4243df8f4f2167ad1d41fc46 +4ff6a2dde946a45c40b22dfbd0d695e4a4e23c33df35a63131d52cea49c3 +8b6c2af7ff8661188fad07c1b9b60a8abd8c58654a6c7f1569095744b6b5 +eaadebb9bb84f3ea89691699132d550b035f290d98d0912d733b4953b84c +8c0ce36a84a319d73ed69ada4710e2a10e0ad59217c7168ed9dbb99e52db +af904e5ab280122b7d9294970ad8f0c502540b15db3a7c92be004cd2ac7f +b671a76002cad472e75ee188cfbd6a5296b2b5bafea24be23df32c373699 +f39640cedd846f0d3c179cb02e1cdbee87fc0a64840510d3533f7b73c95c +6cd25cf46d53dc8f75166e2a8e54bbd82af532c519c3e53dd5c6544e9737 +300121fe0c63d4373cc944fdba943736a104c657c0bfe84c06985241e11c +beacac70c1378ab30ba5d3a5c93f04b0626f5a0e055efc1ed8720900e6d4 +a4914c7d0630e9ed0e6bf98a72eb9381a3d93e7200742fb65bae28852212 +72beecbe7b24775f44bdc9a3708e84bb691732af1f39f7243d600cf7ee9b +25c5a2a52b0f1abe0e6a984590c7e430ccfc8524fa7f1e20c92ee10d7763 +d096b5b792d4086c8dd2bafea15ad19ab754c08a2f8119cd0733c33d47ea +1d84794fc47a2f83439ac4a65eae7525de8745b2971bee811686073e55b1 +8708945e0445d695dedaab56f5aa1fa29b46575f995bf604fc45ae5dc043 +11952cccde3c99e2fa68704fc47308add2fc3f83cb63b2b873c213eb2e0f +23548de52b3908cd31473213c9eb64550ee1908ab3c2f134014df33c3453 +6c17d812906af49c7550904e59902edb5153d3e86e649e372940e9223d32 +95ccde0807c959565b5426ca1ba959dd3a64b6357a0789de5473ba1175d6 +7a53d9db968d9682febd4c2a01cf28e6bd7e5a1411f488f9bc571de02100 +3d988de831a3d6f1e51faecc90029b527befd59da843e58ba9f4d0ac47d7 +9e91c56cc48c5ad0075911df2c7f74c3826fa7dcab6f66f4923a19e4389d +c4e8f0a2004824482a4a4cb96fa431d251a51f035258b90d8ce3651914b3 +c9d955b77f36b2ce03f8cbdd0793f1f2eb7116f24035f333f3d1a6097a1a +eb710546a09c9babee2881eb44a09cd2d19251ca8044b78cf31c6d8ace83 +c55800bf5c3b1041a654be76ae2720b22900315e0ad2e933be9945e47e6c +a6b7477a94cc9582274e5c894aecd1b544856b68c72c574e506002519545 +32bd9ec00aae146bb1048dfc0a06ffe8a2f2c0a2807a6954b455be078c28 +9b5af21cdf2dee0368b6b88590edf81357c3cc4ee316523c1c0f6edce339 +3a5acadafc56dc6565ef554b8ccbdef6954385165b8647af8c7cf267845d +d42e2a8df493f56f534500c7d82149ca21c6a2944ec91c1730c63d4329e5 +0fbe42508116deb021753abb64ab752c45e00ad697d99c0ddff09eafaa8d +b9189f5ae7fd4cfc58f9098d0f67ecc489714a7d7684e85b02c0a5b8d598 +ef32a79137e11a12c8c14cfcc0bda0effa2f2c2398b0cdd5eafc0966b1cc +6cb0aa51f225fd25c49949fe9f78b189fe698e4fd37f755b1e9ad12d807e +16cbfd671e37494ddc407630db77f07156023b5b47f0a4799b9649028c56 +0216750a6a7c89c7c3cc0a2fad201113acb18eb0ba31bce9b0631abc96a5 +84f4d4f78c0d7082f743e899b1c012ecec31e499963ebbbdfb97d92c99e5 +63c8e95d8d3702e4ed816989191ecc46d155c285bdbdfc7b283c29b0e5c8 +00345dd40bccc07abdff173e1596170734a3d91d892509e08a948fc127e2 +c5de525778b2fd0fc0841626f81e25c0de7473fa627427ef0e6a20e39124 +8cd9cf3100209bb173d56daf8c452a388f30d8d9615276e47620acc19431 +67404aaeb2fe696c36489e21878187df01b45a888f34045e61114a4946e2 +9c16a2036d7789b8e46c2437754fb1027cbd105a8a5cb1b6efe2b660dcc9 +7b43c72b08c633f968bb54996ee8452b8ad93b2e73a8ed46e1e173e6f7c4 +51bbccdd56e83ca7aee834d0fa12a459d472c15a53a15dd753f93c25731e +9d653820fb3eea99577aaa86761cb9bcb4b0400aa7f8ff4339c4f0be3880 +5e2f1a4685319aad1a882532b7df962483d6ec9a47b8ae11084513f49816 +caaf4decaa70460031e7ff9fbbc13fba3c12b63aec3285b7467fbc399ce6 +5820a7bd0238f314fd15b1f9b0d28a5ef043e5b27aa4b3e7434fc40a923c +5b23debee9613a09c48ebb05b8106c9b5fceff7aa93871fb90016bd72ae8 +c59bcd5f5e8e912faf1894906ffcbcc0fe34a67f2b0905c56740858105d4 +8ea5f5e2ede29c596acb85a60c5a6c058504812fa90fb05211cb6de6d95d +0098c0cbcd8fd37951de11a16750db13323eb4b961a4dbf93bae3232471d +654a4e3b7a0a9fc87686fc22c89b06f3ed5d7fae5d0615b334a7fe5b95cb +03c748b2f02dcbdd253c944243115882318e4b74da5c4c5ac663bdce9580 +3f6741cf50432b1c5564107dd05ee0b6b7ad112080fc65c480253d38b2a5 +cb086bc8fa2e362e3593d4f070cb16ee0cfde3c50c39d5689d2cf5cd5657 +804641d8525edc36eb9fab819ff549270f16a74f6ebbd8a97922aeb99982 +dff05d3223222d04fc9a9c385db246f41449532a1be9041a646bcd72f4d3 +a2e6820a83292c7d47484110cc62f14e5c08cd42af83f7bc2d64a0956e0e +bd7015ba7aa3bcec0fcd5885308af509aed402f1396c7a25e47eb25920cf +e88f95b7ff66d6d50a9eefc2d66f3d1392cc12cba26378f05a53a4c47d44 +b8006c6aa31931bd8f442c13a0c21e48c5868a1c275a3e84ad5f27a2c9ff +e16ed8ea7d2b3725e2fc31b07dfbe9bf04a07dc8228619785077d99137b4 +f7cde57aa7490cc258c2b2d1c4c920f33fd155a6fd1bc79c26548be69d8e +2f50e52f43760fd522fc605ab356a0e1b88bd2a6dad4fd981e59063dc76b +ea561592660425ce3950a1a8ae22a82304bc1ea0542a943528773a55b4db +a01a24ab34fb45021d9799bf29656b2d708982c70f68b5942594d9e7d9c4 +b8fc7d16f31fa7da05209f4b32c75b2ef4d1cb485bf83339b4dd4a3b06b5 +61780dabdb959024204d1b10c21af5b53ccf11576a5bed494153051ec6fc +896be696600dee78061f661fa00d32020cbeeedab18e432dc785fac8b07f +47d0c5ac0d6553f5628eb560902806d4132bba6e0c22003060ea45d43740 +26d0009e231be79e948299076c3a020d3ccf8a96e6f5b781027d75490b10 +ea64067692cc1742295ff01e173bd3d92fedb3a5256e81341b608919e4fb +9035390372d560849bf0134db57d43e245f9726a8d3bf16edc36c9945772 +9cc21eb0d636b393890d51c696b6234c04d4a709bdd848174c26de3a1029 +0ae7e3e0e00ad67f2c47c097465d4f9fb72ae2cd781781d876cc4fad8f4d +d32487481c1258b272b9457621680d67a0dfde705b92de4c9027a2159cf3 +95d1518c1fb970fa566c3eaccbe5bebbc67eea26b01c8c3e763ca3402054 +4eb3efb615e184287d005bf513d83f5059b451184950bc33725cd383921f +1101263af8f68ae528f0b8fd58b23ff4e33377ff4cd42b7bb862c4f24cf3 +5b78c1a06a5991092be70afbe763d988584ca8e27a45f202ea76c5bbad75 +eba84a8e687701d2ffa6ebdb8b892fe0b7d2f6bb22a9e63d01db96f48afa +536cdb363d3294c6b912bc8393afe6cd0933c2fb69c3bb9b0247a69c9ce9 +2ccbb86a319cbafe871d86eb1beff057df1740d5d78943b71eedfb5d10be +a9c9b5f5b256428f8483bdfb74446f01e19704bb63ff46b89ac1ad1ea9e6 +b8167740d92824b70d10e62bf91e5f195d3c5b34c89ebb76dd0c3ae81583 +e62b30fa89bc91505ddde2ba491c88b2cb4fe1ffe969fa639c731cdf8bc4 +f4026c95877683dffa4ca845cf3ec817262482bb4027bb7e5b90c2c56153 +529f62fc54d2b56c951cda1dae3bd3c9b168bc93cb7508c95bc0b9681f91 +661d8d201f655701572e90de07ce20b27f5f91c66216e66a89a39c0d7080 +5dcda7789d3e4bb292e193464737d7254bc70b93a5c9b4c49bfeef3df5fa +2d333eef22d067df635e6264d151137948e44cbffce8b7a2f85ecf808e3f +4f8f1eae3cc3df13da3e92911910e92b5ff641155180be4c77f5ec0ccf0a +d2e7395faba6b848b3883d2d07573fbd446b5f9718ea09d1918bab4487b8 +195b5436c81767635525ba753ca7423a9783ffea585e9932fcbbf6efaaed +d1f9f1e4a0135c64e8cec283876678cd568f75a116ac9c757528625176a3 +a8bc8b63b7b9e8cd06a9b60d00c5c21f6a1dab66c7802110737b3e1ce8ab +a5d14061b604c18d7fcf6dca718c594259bd74547250c0d47b30e3297dbb +05c50f4128b83f58fa96321e6c1fe34d5296e11bfb4cc550cd80a1214d82 +1c04be92b7aeee3ef4e4b70e627635617d5496dc3281fb474718e5497303 +199bdcbc3318423e0c2227795ff34923772c7f53e6cd0811da7d2c231018 +47541e5d6a2439b2313f7ecf5f12d731d0de9db8bd45b08e1ab129eec0d4 +eab8ec632d0e5176ad67ea81c681b9203a4988d22db6b6059f3fd8870889 +664e1f888265ed3b316219dfbe24a7d4254cc2f4981ae42bd78c73326019 +c504eda3a4d3fd181a70dd5085883c11637c78b82b5fc78e27878b53208c +5593a52114d83c37026041f801d950a69bf9cbc9b75b12813eadd695e65c +1583254b25d17403fa4d59f518c572f8ac90a386c9b63cb662f50d092cdf +374e5c14bd92e50ff46e4fef2d8a9e3da367e7d3f3ba17400d5445463992 +74fbc801c11e85e8d10450ac0bea7a468f1ba990b4d959292e40bbc11d25 +30e42e65356719a85c76efcc6ea9a36029411ca1225b11448115c16d510c +0456ecca598ecdc3eded05152b669d0e7ff3e80372f23e098c6d02eb9e5a +fb256359405bfc81cc9a927550e4994c9dee0815afffaf2d0a5fd3ece4f9 +057bc6fe048761f74d81057eef2b4fbed38f8cf6df765975d3cc5131093f +757c390e1e324c159a70472d784e49e6ccb75af3f303f9ca91e2eca0664a +4b4ddd83256e22753f1fbf2b5b1e73779390c8c582e1113acfdb212c1a9a +a7537ddb197c3c36c642657a5c7242b6d25976bd15e1ac607db186bc2ffb +480b1c95b1f71faf1903c864e036ddb42a681f2318dc212b1be3a8fd781d +ba69daf6390ebe299a5d57d596e24b737c529e48d7d8ae8f29d897eddd5c +fd970a7502efe9dff7a8def548d07dfcad7cf7171f14464ed185ca1ca7f8 +12647d82f37267f9340b4b8138471099bc9947ffe8836a5fca145d246298 +fa6a16a220c4957dc09e1f7db803a488bd9e23e9b06a948f46327a0174f3 +8564f5aab476c38781bd01240031dcbad5f3ea380bd1da2a57d5833a2804 +f3385741d1062fbec7f2dcb99029f671e73d200cde3c6c22e56be77ad640 +e00e418ba9c5b55f32033e77132d1a3f105050d4ece20e315042ec670355 +52a327e5d2134355b65872fc7043d796e4552c360adeecd58ffce6ebc142 +6d3604163e8736d658b52d0eb31f61e7da24ce6083494e103b0138084258 +1f745984d95cdb80a5b318651f0d969e88b6a192d8fb6833c8edc1721346 +512e30dd5638d4bfa4cc6d6ae59546d32261fb0da92490c81f486af1222f +b5b8a8beff009a7533be98aee67c751502e811e6d80ace82316e10872ec0 +38f3ba8db28844e6226bf76fb4dd1d533e32dd98afad08686ed7ac5f22d2 +3ac3efc4ca3c8807963329d4c5e5445e483b31feb1b665e81efa14e50016 +cf6ad2c9902bbb09c1169cc0987c8965e17ffda6ef44209c580e87e21435 +9ff2f1658f602c21469e861fa93a6922fb81173edc3087d967c29861b5ac +4b8bf09a80a39a719bbbef195833a535b795155d31d2c514ef77b63fafea +0d3e65fd3d036d347f9b131644172d1d05b14b58e0a3d05e1eb3c63cb59c +9921465766ab68033fd268c305a484cf5ec0fc57ab818734b6facc6c5377 +6a27e1eaabdf22bc862fefae9a5ad864afcb2e1025b92e42b8f7fc360fdc +84384a5b85e5d3dcb8bb5a8c0a71aef443fabe70f61f25485dce3b5d1309 +5f83463dfed9d1e6f076ea41f6458415d65fa5f1fc7e10e71bc5538050b4 +1fe27d3fc52a0111ff111cbea421a963cb8913b53cc9e2e9f5f6a1202b0b +1ffebe8afd7c8e3805c631028e15a3bce7227c6e2f554fb6d82db30455d5 +74ec84fdbd4e589ec093e7a9f2687a30a0709da926aa83660e19ac331029 +3b93b6b7614d7c8b941435268bf88d7daa8f413cfaa4bcdade3b06e0a4af +b63e66cdbfce3fff5da6668c7c4b8c09f36470315f9fbd6c41917b4beffe +85c2fe8789c26cf07eae1eb5f51213ec4188a4298d6a7eca9dbdb35334ee +727a393e779392106de99423bfa78eaedaff42e719ef1e430015dc4aed0f +66db1bc722d1ce5022ed01ec6160b9c6a1e059006a634cf1c81738aa735b +1b8adf3b53f0381c921d3e1db16797d935a90d7100dad04932134098cfbe +f607d493b1c2858f4bbfd59fd711861e7fc8d3c39275137209e878b54927 +eb538fbc1b7570d94ec72a417c7c93b97e64ffa489feaa8e448f60bd7198 +eb87700c55af20c26b30b74117948d3a2c8e63f551dfa1597e1151fd036b +450ed365dceb627a8276ae186b63cdfdc9bfeecfab49e24cfcc88e336f28 +7209ad7c19ed66735525382582d34a1c427fcac42eea2e2bb2bca3b889f2 +f94c17889af17b8527fa8c98db89a62ffbd0e7d74af803672ef0ac1a4f8a +b730dfaa7e39279dbea0b7eb15943309dacf9ae8d7ea5530bf423e8b09ba +f591b7fcb0bf32be49fce97cf65278b3a078e693ab4009e8991edd66df5f +6517d1cb896c23c958260268b7a10343744c83361a7d4c0f58d2a3b147f8 +6aa96105b68a2a68fb84750acd807efc2b43e75aaf3f69110f4007f0dad9 +be64c51774a90e76f59f7ba21c4e213b9e036e8fd95b7149ede827c895a7 +c935d004aeaa657d8e89808b943517aae13b98b7fa25bb2c050b2bf3d2aa +94d03660870ebc3313df28b019dc87a834aff78dd233d329b6307abde48f +7b33136591af9fdc1526a3b290c074701a93fd4e2d23e80c25452a46844f +6751b18e383c69be5182a1ca0b1829d491b2ff2763ff8bd8c219a9b40550 +f83e3c7e657b622df0b55c12fd92c6966db54cc7ce9872d381d9f3337161 +eb3ef659164d2db7b3c0ae5c1b8fbb5c6f325873c3469c42ea7849ddb54a +b86da499e3870699a349ba1f2a882bbdec2a2defebd80a91e20f580c355f +99d2c1c17657b2210507a615026b58eb1159468bbac06bacd1840b3e9e4a +2fedbd3db9b3da6aa5935857c2f35a8a07f89934f03f1ac4179bdf2deaca +cd37dd60596890d56ac5de35d346f05ccbeb01af776f6c6b78c7ffea773d +9fb02638a27a1572e88506627bdf29461b4ea9757d3dc4b4881c23afdae1 +b3e6ea7890e5791a05ac9be14bfe5031a5e7759fe0a77a2c433c5f4abd2d +6dd24c455a61ba4bbdbfb879954c301c87cb83a65571abb4ed0d12b38247 +a122e6ed2529a3e9f303cc50334ff66633913474ef5b3944f431727817c3 +3f99961c8fae4a9fad6f7fcea2ca3dcd7ff630e1dd1a2b1b2e7702d45b90 +022e3b986f8ac02ae7337d881aae3b5ed5ff6589982c0376f7e0184e2677 +6f4910f5764a9e87c0a011c4826884b733a7c94081502fd642f9d01ef2f0 +d13b8c3202b0c65017dc52c6bb896a2d5d6a6eb7186595395c1761fba3ba +78533adde3cc35cbc61f5e3049235872217f858600c7d9dc5446689e2fdc +4bc18bae0dc69a6b9538899a72eb972da71bcf204be2a1bd4f3b41ff4e88 +0a474e78b3cd9787255ed129ff5fdb1971bde1a628f3d0031c9c07729465 +3a805069b0737c56f13cad9a7712c5a89c08364ea2a7ec47459f01eb1e79 +b1ebaedf65b74d2f04112943e925c77353b85bf4284d44f9e035f98eb381 +04de862cdb67588bdc7a01ed46e3b4021a365c143eb8f2a289ea8cb86c26 +0e2b68079858cd80d7d01062c777cc5509102ca78f35a14b371228d9f3be +79c260bb444bf12f229e6d734f455f4777d344c4adf4e3bea74b3fabbef4 +ff6f50810c9ba2cc4ceb642045c50475e0519dca6f80dbaa84bb3d52993b +7c64eda507d3fa96233782b7460616fc479bcc66f1fa45da506e6841734c +04197afdf22e4948fbe46321f240aa99c9567b623edef4001964022942a1 +04a3ed4ded4b0752ce877d4132970adadf6a3707e5e999eb9083731ed70a +4c4d3ca516e1f2a2cc21e7a3335bea3f2998598776ca3cab0c495a595f08 +b14d6d047088271a42de0cd894fa2ef40321e655fa94934d56dea79fb009 +e18011e64f0d712b853c13061d9bf18d2449102dd6b76d026cb41bf188a4 +48d758c8d61111ecc664a1577c90baeef21970e1f796ec34ba758968c061 +f4d3a0f4c6f2967f33e6ad2c296293beeeeb78244c37be4924f888806dd8 +a2623e7afeae2b3f3b7fb25c2ca5f9dba9f6847f21a5d2350e09ea9fcf3a +7b3471c70f0bba2f4ce96afe288670d8876188aee1c0b9477f645b3d4d9e +f81fab33af3f6cd10bbe7949a51efcb189f8d7bdfd18cb0ff37f5295f617 +bd21422c088ebe9ae34859728bf8e2260f0556ff6cf266be35330bf2183a +46b0f2e02be6735260fd8e32994bc9ebb66da8172178c0a5d2a46ebf81d5 +33dc0e8d85f9da009d9cebe0e5123c5943e805ba8ca03feab7eb753933aa +dd88df02b74e0c3eb9b3c2b4cd0178998350c87afa4f8bf9b1d4c88f1446 +f3bd28b7f7e6a123536504746ecde5360c6eac798c6b8effb282a930806e +559e5c6147f75b3a9bfb6f80dd672076f99d8ebb064801196dc13c837fe2 +506d523fdbe6871cf3cd286f553c6432bba9a1e6915cc4857a5e499c3157 +e8532ebb1b3f605ae39e52e47e8d2d72aded3475a22d612111212bae39e5 +e53c53294115cb01446379d9c65efc4e9751d2510df8a8f5d05999d321ae +cdf6a8f0c6bef3adf0a5f07ecc76a07c5a3e3743b2c29656f8622bf507fd +994d1a2cbf0b6252a1676802e41aac858fc8c05f3b0f9bd7f5659daf2635 +bc654f2d4ec5840476df5bbe92c94f6dfe01b053817bd11e98293c1d82d4 +2618ff76b7d7477cf44a55a05e6267c780288497538773c45e7c005465be +3706cfeda1a768e34b16529130151c81c21cb79b5ca2613118dc99801056 +fb20ddfb772af8f6c058d291bb60d1bf0e24f1090cfe102dbcfcdf3ebe9c +2be95830bc74254fb33c5ee961173d7f192c77e9f3cf560a6acfae216537 +8f8ec20794bc2fe89be5fd2cc4cb7bc64b180e316d6c7a8aec02cd3ba489 +ea1bc7290d443f2017db5c9f56d3c01f60aac361dfbb21391d4631e1ce7d +caaf8b7147424d2e280401552eb8d28ea29a2e3ae8d497899b0a9ab07572 +8943e310b6f119f7f4745fbf157679fcafeca4b489b2c989169572d9eea4 +ea4a268ad55c09e5f935e581fb3c3bdf7a19cbca4e31c2f11c7f94041c17 +20f4afaeb34297d0d443ea15f45047d428e170be83e949a747f2b0eb1114 +adfe5816e4c6dce2e15fa5c04cbfc35eefb2ff31e7e8249a68dc182bea5c +38d94cc14d4fba937bf7dd6d0d7e97e886dab9cabc1065152f0eea63490d +8ff3fceded7c66b94b432164faceecd537e8dd7d764f9c723300f677cbf9 +62f512e0c2bd926aedceced203219b44c6a33eb81f68a80874692f0ba475 +e151735c02f37c7f827b7c18a50f403c60b26ba07598a2340079ec79870f +dcf1d0a10f95b4917ae9ba414fbba00dd561fff7e3669a840d5637a670b9 +c7603f950be19410da99280f836d316578627ed4060e8aad11975142bc93 +1efbb553216411d2a3ee089e0435d256cf6c27134f97426be3fd8a6ae9a0 +b7b6b7d660e4bdbe8baf5ea8d81f4249f03fa53a4ad8c49fa79a5c346f6d +73384af34d6ba5733650794b840bbc12c2d1e693e6a2de9ff5b317468381 +44bdac7ecb57847f26c1807beea229a7ef033292df577c4fa8df7125c95f +beb9d3c9a67a95ea90f975a93ccff6684a4076367d6df13f403673c13098 +ef55e1c5957349548ce21775c7428dd33904ffc4aae249cb65c05c2ac6fe +643fb75a2f4aa279392013513a6a908ed6bc2bb5c56a38a69a5a5a0aa07e +84ae5895a20adda2ca292145d12ed42648092f9d7e79ee6cec978e1a3548 +5ef3222e3e9dd4f9c24d0fa75189308ad03819b4252840afd44e87e4f457 +fc7b8ef67cad28c1242bebe3760b5a90e3752ed20fa3b447e577d6b2c490 +eb76f5b357c0a6181208a8f99549a2809b7c4ffe37e229e3e01d5e7bd67c +6f82114fa9436a79bf0d3d6fb88f272792670b0f6b22d14c5f2193d9ed7f +12f6f1c7f336f597d2f10b5941635350ee6b462353c2f211d01810491556 +dae168530350e99421b509105a6e550bcf9e2843605b95a89c93ab24b9d9 +b7ed3a9965b6fca21ab95c560b02e763202f7c55461419984edb144d0ebb +ef6436aaa3c68959b0869b58e5bcbc54436c238ac93aaf882e5bc014e03f +5eaeb671ac3cc090ebcbfb2aac69186cf36746f535736a2c8bd703aabb7a +b8c9df63d73191b98ee4279473dca298c41a6f67983ef91b2e56ef59b933 +59d405b42f5a30ac8117cf7be52f01022137441efa08549bcadb2efb90ad +4ccd93a6022a8424a86ed4a48c213326737bd968e627f6f8a8e806676bfc +d6a6517e623b84204a5d8dfa46eae6abe89870ff3bb19c6452ffa3a5abd0 +e0cd418ffd2ff221827bd313d753a63434ea1bf9822aa9d7f2e839e9a0de +bbeaadd3a4ea4746dcb2814b98a52fa00db4c1c71bd7687049b5faeaf564 +9507c2303513f1b3a6f4f7de783bccf85aea628b1afd8f473076e95195d1 +e8af64a05d05a661e2b2f77779144905a2c5601df0eef0c8812b8d9a5165 +489396ac9de54d715250a3acceff5659b1f51ad7a7239d9a8bc7631a35df +244e9cf1a3d080de8fdf09052dafb200b907e8da5bb2404efab14e5d3500 +7710f369d3dce9654d0332bb19a5bc9bcf10c2ae8a12d97831bfd0c06881 +bef8cac8a9bdeb42a264593254ad8d72fa97f189901a857830cf52cf137f +cb6d46b9b934b98e52a251b029422ddaeee26aaa89a57e3bc0c40e95bcdc +9d9aa36a34805520a647a1dd5de148d7d50dc9ead70d923c9c78db90f8ba +02d68c3cec9f5fd771c33140b93b82ec063c8da7d96444beb4fd1f9438c0 +0b1c747d8833dd0a1e12fe2036bf38b4aea8f8708bd3e3e289425abbe7a6 +ce0a9b3a4eb6d6cf021a03a40b32a6fb27f714ab28b1a8d0a7be38e3585c +fbdf46ac0906b0656599998331baeb24e94effc3d56b37a6f33695c847b4 +5eae4abe907128987e7bc61c9c2cbc35b8edb6c4d00004d36dd05fe001fe +25a044bb325117ffcd3ae307684029c29ed0ceda734d1b9685da4cda79c5 +53eefb7e26d3e31caa1b815e31d0718b190be691abff96c3c89ad3ab8669 +a6912149e59eeb566ec95113895f17d5ae021e1ee285d0c49e054153944e +63e019fbbb0863dace341b53cd5b976f7b61ed082f6423dcb631494d2e6d +4685bcea79f5dcd4db9e4e323c4badc4fab74487d059351b7f301e8c0cea +9163871789ef9c71d2366f65ee95a84efc738faecfd1f72bff12abfa9f51 +afa6e0b40d6c70005e60aaf92a68ec136c4169f429c705d51aa86c841fa6 +8a4c44e92bceb6605732d355dc995d5a9ee4c078c0bbf80de0351af8ba35 +0d24c5191cd1094a7399cb946132469c3034c6b125c8edd52f8fd240a5a1 +4e945431a1b8505b9436e2e07f19e2be43b6a7eb616dbaf95a7335778a47 +9b2e659e623bc0b6db8f4abb16f269cf3550de6ba58f2be5c3e9cda1387f +0afb3a1f52330675440c89e329b3253a143c4bf1fe2485b5e402b2c11ece +38ae8987c19facbd48b9209e3781fb2cc48b0fbb3e5b38c73910d8c945b0 +59c36e26211956e67659bc13ac100ae8bfbc297a8c4c8985fb5fb4227237 +52856e39d5713557e4eb3f14c5e15f822d2204ef14a91c6ab8136c6ccbf9 +04beab720daaac5775a4ad27362986eb78d995b7eb70913519f0b0d29591 +624f159285880ca18b183240410cbd0e9a293f2220c6ffc289668ca820cc +6e3f8c6e24c437280e067379bebb7dcd7bfee73a804de04866c102488a72 +1dc5c19f64c17b1ba6f543fd024a2bddf2b43d27185b7355ece2fa7b9f36 +7d5d56cf40e8c861039b7026b465d40ac264bdf4d43bb59e451a152f0219 +80df72ac89ca53fff8dd2a7849877bd8ff0ed654254ce9037925d3c0747d +23dedef33f9510a6730c9537503a4612c76b36698e4bb1297a3ff72caa98 +7bfd0fb801544fa5b04753780faeea75a567ea18098f2ae84f226220df46 +42a70b6f0557772d7ba1f13bef7ce9d9c1f3254f373ba0fcfc44c0063fcf +f3c2d7b48b1cdded8f78a1ec7c06695ce889670b6921f98d986547fb75ff +3fafbe090a2d33c41a1f5fecdd2c21e5ef808d7cd4a7195b7715766521c0 +0815f524e75d1b554816fada08b6c246d1b66cdec4bf1909d40d48d5a25b +0b1615523fbac1eec49f404dd72247b2c07cefb405faaa273973e8714b13 +ae5e763d62d077f15fbb15030d7b4062275335987bc5ed9bce2473baacc9 +fe39ea65d5a7ff0e3767123c69238eaf663975233dd6e9845ccbf2df9399 +285c8dea6175f2215257f0022403092ba7dbccfbd2c2da8778f3833952b5 +9d2019d11b63c7fb0d1344ff0c5b8e8a55636399f3611b062e803e39af3b +4a6a369569b9d8757fd054cc0d6b62ee29cd6cf2fcbc6a8d57a2f9c6a504 +bab41004df5292dafaec65a2861b432dc41a368136117b746553777f1fa0 +f7b2e3faf253a0bf40d392b4e046cf697abf4d8b3268e4f2648439ade9d2 +e45524f3c0e052076bf35400cbdd16e70f88239dea74cd27633275ccede4 +9c6b7c237fb7bd201b3dfa9b7794555961414d80fd5c32032a3310b6b32d +46a6e744934f9d680c5ffd81f331991d1c997eb3e4ce241916174da8bfb5 +06b0ff918c6117576a6fcdf4bd9dd90c9b5273331c5bf07e5897e9f02aa3 +296cc05cf47e48b55886b8826f2822140cc84f54b8b9d6477d9893ee74fe +73e39297bf414e0179bdb25166e8836d49b2add6274aff33c82361197968 +fdfacca49b85772de9a148e017a8ffc62a38a30be5850513071727f3ba34 +dd644ce08bf3fd2a550809730a5c3591d60c3b0e3ed24eaf57817d4c84a4 +66c5f03794e6aeb3e1846ab2e93a5dcc3ef835664ae013464937451180ab +b91d54cc81967cf85ee6b9d75c14a77f737fa6b414ed667fcaba82ded665 +3b8d6649cfe57b4672c44e0f0bfe5ad630c48ccf549b7cd2deae9c5527d0 +4783ec5319bb9ef7d750d87ba3c6b9b819545ca242d41f76fcd3df2f8842 +fa5714aff9e5139bd2908a003d5c0e6263a2bbe4105c510087db0ecd7c4b +57cc3af64dbaaac5de21bcab8a58003225efe67be7f9a6709eee25d359fc +1aebc969130f3050c0ebb6d8b74859ad54865f400863d769e91db9edeb43 +8525a7c7caa68b0d198475a449f5f87b5ebb495ebbd0dce87bbf35408679 +302b4dc66d893f4b4158e1b53054ab9b197c6ecb07792ba9c8c5b9c900af +c5a05cc9c31b5078427a1c7d74449b9eb8617b3f0098eff3c586744dbd27 +5a117d0aa14a042c51b7506130de59694db9e45d48f39a31411b656512a3 +2d3cd96686806a73ca7f46dcf9a4872c0334c89ffc2948a2bd98bb2f003a +85834c049877a4729f3cf001b1385814a17baf20a0ef75708ddf0f4b656d +4122e30d794da048d83b201a252c92c8c92809cc3027150ad65ecc94cb14 +69c5db56965a42b367ca27015b161acb2318686bc3451e03a299f67de0ad +bde7f33807213565cfaab7a5ad04a442fd3cb710a6d4b78a62c318815ff2 +d9e14b9357e8bbd13faabe9d9ea43c0c39bf4976ff03d1573b1571e3013c +fed9bfaa0c42017ecf25d7c12d70410e7a0d79e37d5d505d11da9696e2b1 +13019e10355aff4967c56ea86d4362a89b42cc01f3abf0dea5f029ef0c2f +d3f33bfd58e31a652040ac6179585f9bb03e0bf8f1e94da93240f5637fa6 +21687bb4b7edc3a2f5f89fd1434412333aa9b97bd0c1d362285ab643f426 +f75dd854f116a0d8bbdcdb80ce513cc45650945b546f72ca69dd9d2707eb +7b5bdd9501febac3c4476852a1d21d6cec9a25e4d1671dcdbbb67b6fb02a +78daabb55f140eec157eb91075e1f5cfbc2aa8d8d3fe990f47429bc573b6 +52d0da673909f36bf15852a7ffd991d927e99a6c956f33408a8f5edc6d7b +200ef63dceb2cfb8da9475d34528238f4d5a7aacb905e6a769662a31ddad +4e75795f11f3332bee039bea7eb9a9295a93e8f05a0978d88173c2f48a7a +403daaf47c0444ac49e3544a2aa319176d51911b49da0c034f3e9c3384f9 +063d449eadde60491ed22c3bb5c0bac31fc564bb75cf75597c977bd9abf9 +05993bdec686728b1c3bce5d0f6302b3e034e556e43fbe1851b2d137cf73 +8a277fc4ce3f289c1b6aca82f97401eac80ea9a7682cdc9a588ab100c844 +8b60ac0b360f1af03ab5525536c34351dc7d1169193e71fa12892ee79a9e +41552f5deee05e9b714587288852de794d16c571a4d61c2a41dfb1c5e0c0 +e6e2e9dc4ec7927fb76b52ec0bd581f6982969c8dd2400377428fc757010 +ad039cc3c917421a7e20d261034b9f86c69723e9823a2648d648879e13ba +aa98bc59e45180ecd907804c0132b14f5a90705869a8c3b06b1a60303836 +4029f3801ef74c8f798f712beb2aeb55a917e4e15907e16070a0f9b52928 +92a05082b8cc5a51aacb34e227fa8b389c08245bda3f03570f04c1a06462 +4c8929938e966bcd981c11f70509bc65be7d3d1825a918a73c9c3479cd93 +24cc604e0b38bdd77beb802d4fe0c6c75dc1494f6816dd520f295c1a23d0 +0c8ec16e45d9d3aa9e5b6c138b7669be34f62b7250fb016034fc3d459fac +491bb407501f99ff6915f17ba0587f17d19f05e4011a8260c6d9ea10cfe8 +4db4cdac6f5cb8f8a8c19d71a8b51c803fecaa5e78d0900e717e6db0f16d +b5e3fd766b221033d64c4695127399ca9e5559374bbe717c772746ff02be +0d9cda0216a202489aa5872d200e9c96a70c6f3709264c4047847a606353 +fc3eab0995cbe4dc9209cd53d2f869e8fb49952d2507c28d978a444848cf +7d40200e56a1dd0eca3dd2cd861ab8029e8fed1e2ea8a4b457514a0c118c +6c64b3ffdeafd9fa3fbf92dc132dc4acb1dd082ed5ef10e1c85bd4601a3e +f2a6b5083ded55f5d9d2c575d0eba89700b4806dbcc6e5d2a2ad26c72cb5 +502eaf92ce02eb0769b552f7b372edc1d14ebc12545545d55e1be0cace86 +0ea950c891f47a066e334fda3afa5fcce5cb58a121c70a646e8fcf3b6b3d +2bddbd3bb137ab4b1b3056343439432df4aa089b70b47511cfec8ff6bc3e +97b320f8bee6fb49981dd5b411207ee7f4bcaa5d17e9ae30fb79ca887c04 +20c8024cb1445137e243d42fcbfea96f6259ddd05d335b390ed2580dc82d +0abaee5e669d537e766e7ec16c512a8b47aae6380d8994c87d00dfed9f5d +85232a84e3d3cb3ea5b307c16cbb2f962effa16cae18a2b6f8b1ef0420e0 +4b1e8658f368b7d94d949aea27aca6ad429007363ce870cde7573dcab8e9 +813ddb3181634525744118220890a4c17249ce7ae314a9adcde389949f14 +64976b4a819e87b7588aaaf4ee1a501c03a1c7e928c3b4401ebeb2eb5ec5 +b65d06d61c11831a50e59124ee7fda18fc49cafa2ae407af526d1a94a305 +96e5aa91e7991ef4c05cb0ff348e86942c706cfcd879b527c8e5f00ccd36 +20f2e1118317172c0ef4cda072faf995d0d8db0b835cc9df1921fa42bcd2 +613d38b149a9ffc4514e727b453c7c8dedecf45e1e6c15b7f2d5e841b28e +73e6298ed645aa91337a07021879c9c3c80618372242f0c6d4206e57fcb6 +0e426dacc9ebe8319ccdc3a6ab7d074b85fbfaa94b2135790ae82fb3a489 +3b44f2414e3f9f3da85a8308417f197b92810c2d6c80b2fb8d725a69a5df +6e197cd82a77dfac7d82ed903a49e81d27e6256a726858a6f47eeffcac83 +aed170e22059c41aae419c1397430677b1e38d4d10ea1d73d59b836dc1a0 +32f5ff3c5fcb37b151ca33de6fedb9b6732470965ec19547e1cf2a717a1d +858a0c6ff05a74fcc9b512e4f504e9de2bda922a254ed810b0ca0a352c3e +6db3e08ec0afd82391697f3818bd50a9cc03aa1ad62a9ddbe42f5ab7f4bc +c14e5ef46a23750f8b09959c0b4afdd79f7bfd8f9ba0dde92ae631ac520c +676454657047ed18a0723244e9aacf6394c7d1dfe20c52efded832b1aae4 +dd0215271fc46ef5b90de2514fb118396a7a6069bb49b95bb240616d4115 +9be72b5fb37d4f2037c39a4163180379e5e91adc987003b0a1cd676ccb8c +f6e44f523c3b74d543d55eb3cc465463440720be08ee3f85a60b9398673d +7e4900c4583979887c6e22d3f27c0db0359a7305b5465274d09f7bcb3b7b +04893b2c9cb576e8e570b49efc409ce5054548ffb1b19dd3098029958360 +b0d936b7b107ce046648ba437befa9bef67b8cbddecb82cd9c4b1bcdc7fc +6af26075f3cb2924dfacf5f1c4160d1f96f2d7592b57edb1cad20ef93953 +71d6aac1791e98bf4bc84bfd81b92a5c2b40dbfee3d50ee9269df632a68c +9f6ef75d69939e764a1b4f527e4993097a1bf28c6e5690ab9e32c73b29d0 +275e10f9559ba7f96bf7c701694ce13133e6fba2276c125b83f43a84cf3e +8aba4a86b180f66842267e70f5c794303689962ae067290e2cf87e3fdd77 +4ed173f91fa1fbb0f6eba3ef1a34e826604961d2cb47b40b260d79b9b2fd +1de584ea79329dc8ec75e84dbcd90b888c59e8f7e5e90f4e2cf7ad8cc5d6 +ac6a42bb0aba27236ee4d68e994a1fa5e5ec15a55c15b0306297a637d669 +6e1933d8c0e9c4e81a4625f427aa47b7e8553b580a45c1685e60267e563e +9a3785a9c16e32dfa66a55ffccc8ebce3956c1e9778b64258e09695fae08 +6b493e3d2fcc4cf6904e2ab22b4ba631c50527a56801737bfcd881bf0499 +1b7677662f0bc6709b981e6dd9dfa90cd3672ea00e00bf2649163c3d20c6 +baeaf3fa2cf56cdc5ecc24628936bdc5a30910cee7afb97edd4f1a38fab7 +fa3a5cad31bbb821ea103b67f99d0b74d7c157a351144b9d755b36e250fd +a96d686bf4d69d7b6fd6bf5808f715fc393de15b86a6e4b1e878ad83115e +90eda05354fc1cbc1734a024607c081fc229ad35770030d77dd164c8e255 +3e9745ed40d9bce5427536793af013665a394cf966f2535713ed2c4a3ff8 +16f50c2bc9c9dcbfe53223d06a009268da596bf894ce9580ef23f4eee7db +887770709f7ea8909ef744ba0ea85267e62573dba51c25f77528870ad317 +f1ed63b2802fc54d81d149a2121762dcca760e5ea5e7ac32a1d48191d63c +bf1e049b78dfa7bb2b2237a9d52f714859f5ea6c92d44c17b64efd507e2c +9820575ca9ba46026fbcc25efbca849abc4a9c385520e5d7d64a787dfd23 +229bfaca0785aa219f310d6f0210e4aafd5f75033ed560f123964476972b +db2a8087df61d0ff47fef572009a81809c7021d62dba53f6b6a26b976d53 +94eff109b3af588cf8deb44bb00763526423d8077836d5e3bce10378ce95 +cf14d8732ccab691ddd13f9a00d285f2d63fa8e7b16136b1a8edfb44a462 +254de6d3a5ec710b9184c2bf8b23eb1aadc2d40bcb53822dd29f4e5cb045 +3e863c11aa73e1bbfc28e336bdb59ce3e88065ea9d8b79991461bc3a0d5c +97febab06079f7a1defb82bca12f28329c063ab726ab7c6a2dacdac6e1da +46e58285015695a4b206d9e0a4df7093033a9e42dd097c6ac0ad87fdf42b +8d453936731448ddd3870a490cd48fce942bae6a88cc0f8525788e222239 +a38476946060a8feb6959613b28a01090293a9f5895f7b509985e3643ee4 +7752ebad364d54437ef2ce6c3fe86a4d2be12812577b126df132cc7d602d +c5ec6ceed3041af208b69b7e98ccad48b2e6d99ab607bbb33a19ea0ad941 +6b31e145d3939e04e9b4afbcc2504c82d879dee54455c0f5d01c028d4648 +bd3d3b9cd2036537764102007df035a9ed9660123faeda255a7385adab5f +13e3fdc490503d9b631c537f1c4447a4fd4fe3f1cbb242705431a9858a0c +60fa8a836c307497698053cd8c62f21aad03ab06aca920bcad87f68afc45 +39f39d9d6759b7c04e15ede59bbcc04f528a277a927152ec89409192f2e5 +26f79921a4e76fece2373f3375c3c0a36ae1d6f3bd1b70586ab9461f65df +c1c5654b5b5aec5f92d6387a11bb28b81d2366fe463a5ea0f8198a1fd8df +e0889a281e1016d72188023de9c0244764e480b801f83381360bff7a3509 +5609a6e61174b0274c2b7293509f9c4e4eec290e2c538c02adb877c8b21f +62c070f58cea8bb436d3b34706de6a6fe8dae931caafba634aca1948da44 +c2cef4d8be6b194d3c41d0c584c82f6f48c67ddeac49b17a692ec941895a +c203310de514f325c7e70d6e1048ffd7f31682da946fcbaa2f5a50535f0a +ff3dc0eedf67fdf9898e759b929b447593edc1fb8c5b77062e19bfbf2fb6 +c4b8b7d695e24cf6470608ab635002afc38d755592a0c723730a042ac5dc +4b74436dbf5eb8dac79ea9e6b7f21ed831f33b6b8c3141c98134e2a69af8 +fc7572bc08aa0ebe9deb04ee9aa794d2afb9bc0e97c60f93a7a72d15556d +36ca0b58c60fc42b6adca84658447da164fb558ae1c856f4c3aa6fd30c26 +7ee9a8668426a3d742e6b8e130c523e1d8340ccd3d3f741be49ce3935b24 +aa20443b6049d0b136a36c1f13176048d69d4150af8cefd458fa78a2859a +8a2f7c58bdbb92191a7dfc1a3cedc12ff91b26b6828d38784a5f829973e9 +d103739a1d8cb4366edc151e396c415fa51c740e0d81c18eca84798f80b3 +5344f2c5c7dbda319d6d50821f236d1d678930cfa18259a97496df61ae7e +ab1c06abe785cd887259a7f08e79915ff96cd781d91435f5b5e4da140c2c +6c0136dca6c57c7df01f9e87fbb0edf55f80dce3a544b7992800d8966f07 +e1297af93114a9efa7eb21baf2583055770eff67b5d21f64c5c2a11b4147 +9e314762bd6409dc5a73a8b32664b55691a01bde6f95d5f1c1065c81b129 +45e5b63d7e845b3ac1f16f760345f886eaf7b091c4c56cf0d0c2a9360f7c +4e546630b93a2aaad80b4ca35d46350095286ef840123cec13dc12e0648b +69d17a43aefe796a02dfe7de3eb520b5e247af46f31ee8507deb1774ab72 +81a32bd0fd6e6439fee6e94a49a8567e68d3156cb34212ea86b6e97f2866 +4dadacf5173e64c7d39237d0744b315fab7b6b85a6a2955a8f45ebffbd87 +9bda5f7cb3285c7241500278ed4574e464adb3d3f07f5a63560873aba6e7 +f9f3f5afc580d06fe0254bcea4da8af4dfad93b9225d636b0cad7a4466d3 +0e6c378b5d2e15e54a0d2686f971b8a3a04bd412ea4d59784bf73b7b8215 +7e398056a48fd391677420dd5c85c3aed14709871fa319b5677889022e1b +3b9e27172dee5df9aa604c98307c576e292bbd17836bef068be34136538e +a77ad4a000894fd8251e9950fcc41b70c2be9368150056bcd41badb91d89 +4da2f98d599bf224120fc5a57028c8dd55148c788a24f8feb19da237fca4 +93a9a0e313e37bae205a00829c9f7d0b790369f6cf5b1c54f4efe3917851 +e9f67a29dd264d2ba0b1bdb05de9c6894b30cf8d5b2d37a960b24b14ac52 +e93421da5d3f2e4484d870f333ce9544a9f578edee46de93125bd65e0584 +3d475c64b2fc036c699eecd9a1b54b5ca8c37c02365dfe7afe918204f6e4 +09d24ef92e8af22d1325f84bd31716add00d5323d34da177b1dd377b77a5 +0a08d86f13000039ba4e1501edab6ddb0073ba7843e22f49f93c80bb7d7e +09a12c0e9c2af050fa39a83ecf87e60672257a62af6f3686aa17b0f246fc +f1a109cc2f7a2a74ecd62849c741d45d92beb3864b6377f648585a7292f2 +98cc3c44b5755dd907e1c3a12f6c152926d30455c3c74e1501eda8e5c295 +7c64c587108f18db3ecc698a96f4c839edc7495f50b3244c59ed2a313509 +e26132ec29067092c12578715104dff4cc0e30ec1da6c13961b9f8b68a88 +65fcab289d5cba904d8891aa7fec7bd57cb4183cef55ad7cbda701d2cf0a +3878c52a77e1e22cfcb4bf8ff5e3e0833f4dde59f2e8a6dc5eb9b625f05a +6575445cf98267e442061d2ad99b52cc789d1d8f6988433c5c0d1d4b4f51 +0f8c73f6bba8e929362ebf38d26c9be8aecaec33f268e2725d3f51cd327c +48d2abc52e265be63a2a2fc87454ae42003eb5a28d6ca5da2d7e8abbb9e8 +439b683e8e631f2e6da1f4b85c04d8bbb1730f2caa091f1b1eef31e08fa4 +df9a9b9eb8c6421cd5bcc0f6ded67fd19617213a80d18024ab79f408f7cf +e3684483819c85a061c53b4fe853e382a3a7778fa471a196f24e124b1436 +29926a24620037e5f73ee2930195e2ecf4ecd53461b5b73c686578d48124 +c8878e0ae2cd2cb654cf98ea3d238dcb37ae7bc18bd0d21b323c959fe82a +99842575f35bb6f286f5b3578413938ef1cdedf1469878f28d0f9ed53100 +c991598f7aeada761e896998a42b10fd186dd494e9ca575e984138469d98 +d4fab45dbd1ee3c2f61b877b9da3660aacd8774dba08bc31ae8e73cfbd3c +fff34ac4047df0776d0db02306024adf7c9efe019128f2488d22883a4eff +f3b5af9fc7552f70a78955d4854a32b3281ddda5dcf15f915b90bd584c40 +e7bfe27697ff9c6a9870d329a63a45d35b7d5c87060ca3960accae323beb +e22f909f71d9ce8f4e59f87698954cc5468b9fa31eec9a1723665de649d4 +9d1f4d8e6b96c4bf83e02806d4d9bde12c1a598f801e2169afaef48cb6b8 +d5040f2be6901dc81c691776b45321a8959939a90b6099446e8cd50576fe +da3c0809294c8cb309ea895075d2eef2a0f2b019e3f2e5941b5863004868 +d81b733cfffdff18b54df5ecb4d3230d0d82f091283ec5aa46c060541366 +3f46eced8a3e98334b9c2ab430f435f792176874df89f2f1675c5d350fa2 +1724a0d2f19a6b24f86f858d0af6934d8fb84016cfff258ba15935a2612d +4fa06dc5579534c7193324b282a8f5a67a8c77eee35ecf2fc7005a3d8d5d +6ed4a4e19d385848a8b95aa6454573815d0182f4c93a3face72d7c2c33ce +e19499d1232adfb742e6212a6c93666bc1dac3a4275c1228ab98b9779850 +ea291edda7bbf14b5e2c68aa26f1b877920aff9ca30788348798b4423b39 +4fad935b35e3d5e71277ec32b142a386a96fece14fb96d3b31fb36b36440 +a71c2d83c5da38c9fedf38148f7cd58748bb2612be4b4895b02e8eb09a5b +0e7548cde6c939ce8880eb89b19b3e26f354cb21ad2a31f8db6b49683fc7 +fd7850a81f4b801bb9f108688435a2b8ff617607c570defce9c4586abd5d +a7cd2a81c93c9e53c3ecc79d637be3d0d9f8b0b08214af29b7c525c6415b +89e0759c5c6389bf00d01e884d9ff86b1bd35ba5d679e80f93d259e88588 +c5ef5e81d89a29b4814ef4a54cb37750182f50662db8fbc27a03ffb3d0bc +eba5cca63c454b12960451ce170828efeb66bc5397c2f0603472cf10a18f +321a4a55eec51dd5a63a4de376ac65f858cbe20ad56395c7b1123cdaa942 +c558cf95faf70c57cbcc724aa11cb7f141e0db8cfb173d518f0da1bee461 +42a05de5108677f5b14dacb79782b2010bf7c5806dbdd67811cc136c0c0a +f869d8dd9df0ece29b581c55c60339948e044da340cc704dd18f8884a6d3 +c851e6113d77742d6dc05365ddc5806b9beba531037aaeae23aff0b19737 +443e8105d57c2c246b09222b25926d5368e62728acb1b98ff51eb1fe6a13 +8e660361caf8f3074de12b7137db4819bca2b39409636c8ff8368c07cc46 +5451818e7e726f02c9dc803e1e53fa04de26cc59b24b5d86cd16a1ab7ea7 +303af8cbb2ad7ce30256052cd4c3b086446db5bd8677a6c8fdc13bfc7824 +23e9694c7a60501ade93a3c867a594c04cc0fb1626fde284b566ea1e4f6f +7b79f4f22fe9c586d25d8b40c0a4147b7a2be24a83afa65f2adff816d656 +19052d81c9cc87be737233aa0916b9cc41736ea4630f4d10c0867aae059f +22ecbc3868edd11f4cc97dc44581c52ef5a5879da40e356281bc0e1e72c0 +5e0f039a679f0c13955e6f577fb6e78c94810ebc9c75d9519a7868d474b3 +2d8a2c62d7e82630059325a9cd33d2ca35d0369bd45cd6f17d83c2c30172 +1bd3c9c34c68b0e709dfe50b428a4f051786ab64f707dd4e4d8a075e0657 +22d5b68e5e9095c5184cd7c01246cfc418f75914f0a01b088ffffadf85c8 +499cb1408f7396b0d94b0b5dfe84e9a619c55e87240a81af16ee893984fe +331f15f597cd3c9415533f9b53563e478d8c6a159e428a806d33f4616ffd +8103ad221a19845547097bd9f1b234c1fedcdcfa0d8ffec356130515c5c5 +11fe5c5ba8d25ff61e6368741cc466592cd920696e964cfc0bde1c5e0b1f +bada15b871d8ee1ad94bc4a42cba6af0526a061d1535d8f3fb4cfcf249ad +f9672e73a4af5ae352b191015de331dbff2a889839c40ea4d315813604f4 +4f6f51144d0014fb69fbc5d4d64d9486b7285d7533a746503920212f1ee2 +8b61b9b44f79e15dcc51fbfedcb91b9eab18bf942525df15e67644bd4d05 +29fe44333175ed909c06d6ec35280ff1354bdcfb509295ff3123e2a53108 +79760e6e7af5b0d6fd44c14f82ca4ca89fc41771745e1290ac86909dcd89 +4a360b9c549939522c7e54ab92d1cf0b5bdc4cf8e9c8b9fd49b5f246b6bb +51fbb881eb6a1184b2383acfa9c8907dd73c8be9a200e555f674c73de70d +9c171eb3a2133fc8058c1a44adf8b143acb43b394d142eed9fbea7b0cc3b +e960e0384ef1dcf4094a22e0b3b4b73b88ec0e5183b2996fd906b9bf3d12 +a818c817b16afb99bf7c0de191eef8aeed90fa137fd2ab84dc9d27e49793 +5ec1be47d5b2555e98d1580687ff82cbf0b9b76fe073620ce33a2450095c +e859a89e68a94d96fd9c8ae07bb9d0608a67c17dc15ca273c013c816150e +ed83d03f502e7dbf208b7748117ad59b24187c60e4a44fac5c9d53ca11a2 +f5426d2e50372727c576042647485f3f06a779c11a398eb91440c74d8566 +54871042a976cd54f8f3e771ac35226a8bddb87884a1d73a888019e11845 +495d6f354e24af23a9cdafeeba7d517cafd89c7a3796eefc2076467e5b2e +f4a244d269fad741b24b4ddea4d52374ae5655457fa30f4b8b1b22110a68 +bb9011f55edff5478382cfc3ff17c3e52a376be295d3547920127c96247c +9c2d069ea9f10a41d206e45b228901d8ec47f261544c4bd1974692ec5195 +839a638de49102290fd09f831a1b5b6398ee8c2337b18ba47e29d3a228cc +3cf1447df2de3160b2f2ea11ebd3430d44d176c13a5a876c6bf13765fb2f +4aa9e7e0ad311a3a832e7d4ec3d04a154c04c50bdd7e08c329c0c682c566 +69fd704da7b4c4a56a50f50f60adc6a30f31542706f8092fdf406035167b +dafef98111e39d3d8be13f057e44562c1b033115c8c4adcaba90b7f7265b +7267952c5164e68a4434b7684178a1ae46e7bf10e344ab99799461abae9e +3d4e424de0bd99a66cd3b0facf3c6948c00860f64dc81f71aee12245787a +82e040f0fd0b5dd075475574f7a60d157cef30d0400ccdb5da27604a975c +2db600d55acbd7c16e329d5c7c8d073d46723e29ef8248918331076ec458 +a85f98cbb0fc0a78630e99db7ab0f178c629bb726c511825cb722514ca36 +7dcdd067a731c8ed72324e5cf715a12602f6a49f921f0632175f615e1d93 +bb225684b50f39b26d65a0110e9ea45fab51763fb785e505942b4b0e0d8d +e21356d58c5d87ef69457dd47944b34e4b29293cd535f7c25a762bf24233 +2f12955daa0b04af9b0f1ae4bbcb2d4abf16374038566d419e71d8b9d91a +af8b2838c3f69d7802d91001837eea69be47f595f864ee03fe2270e05556 +680c719a0f33e24953f7bbe30d03c31f88125a888a9fc47406578c79dd69 +9a9e73aec17997374ec94e9f0147007806407df213edf9fae457f396e403 +9291c23e0a54e6d07c28652374a367404c3a8c50a74eaa4ceeaea98a05ec +220003a80f3565ad05100a397c89dede629ba9af67cdf1608b08ba01f653 +44bd44b5d8a655e1fbd2521b0fac160bfb4628296c6f712d98efefd28cbe +2631dc4d53bd915483586c9619c7a665ea243877b4d34c550d473a36f9c1 +ddaba89a7c727a2625f76cc3d8734efe913f04bf6a9aba435ab32ce26f21 +2499cb4c4e97da602b4b51c35b237f933ef51e091beacb8e0ac275b14339 +e13299374378ffb3a0f25691dd7f2beea5edb9bd152adc86d01fa3e9acee +f2eec45bd016e255dc58df2a9c5cd64a07b4bc410b37a137210dcf214c30 +27d1876726567d9c50926ff4550391079a02c7b4087c1108c509d88f56df +ce7ac59788ea14a42fc69419882a869c6254618843790f987143a6ba0060 +829739cbe213e30194f21d012dced304470847ed0c2b8f597f0fd570eb04 +41c3a15384309dd83f2eefd3d27609dd090c0557391a04bbf9110afdd00d +d584bebbcb4250174d7503d8610beca0ae95aaba34a30abb7ecef68e1076 +6adac81a2814051b4f484478c66b39348436687670185f1717f84da062d4 +8fe0772c986713eec9fb5af2df8dda8dbd76aacb89821761f76f70bc34c9 +37766f16f00e5898ea1531e8b4b4ff65ea0189a8eab73a03089e205e791a +65534ac99113f975ea5223b4388841e3 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark diff --git a/fonts/Courier-Oblique b/fonts/Courier-Oblique new file mode 100644 index 000000000..2c02e5cac --- /dev/null +++ b/fonts/Courier-Oblique @@ -0,0 +1,1448 @@ +%!PS-AdobeFont-1.0: Courier-Oblique 1.05 +%%CreationDate: Wed Dec 22 1999 +% Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development +% (URW)++,Copyright 1999 by (URW)++ Design & Development +% See the file COPYING (GNU General Public License) for license conditions. +% As a special exception, permission is granted to include this font +% program in a Postscript or PDF file that consists of a document that +% contains text to be displayed or printed using this font, regardless +% of the conditions or license applying to the document itself. +12 dict begin +/FontInfo 10 dict dup begin +/version (1.05) readonly def +/Notice ((URW)++,Copyright 1999 by (URW)++ Design & Development. See the file COPYING (GNU General Public License) for license conditions. As a special exception, permission is granted to include this font program in a Postscript or PDF file that consists of a document that contains text to be displayed or printed using this font, regardless of the conditions or license applying to the document itself.) readonly def +/Copyright (Copyright (URW)++,Copyright 1999 by (URW)++ Design & Development) readonly def +/FullName (Courier Oblique) readonly def +/FamilyName (Courier) readonly def +/Weight (Regular) readonly def +/ItalicAngle -12.0 def +/isFixedPitch false def +/UnderlinePosition -100 def +/UnderlineThickness 50 def +end readonly def +/FontName /Courier-Oblique def +/PaintType 0 def +/WMode 0 def +/FontBBox {-61 -237 774 811} readonly def +/FontType 1 def +/FontMatrix [0.001 0.0 0.0 0.001 0.0 0.0] readonly def +/Encoding StandardEncoding def +/UniqueID 5020947 def +currentdict end +currentfile eexec +e98d09d760a3c22cf119f9dc699a22c35b5b35ed6aa23593c76d54cabb5e +942bf7d6dd84f1664b89699c74b472de9f8e6df925f6c4f204e9f1c639b4 +dba988ed2ac419ff2b2bde605b8ee3264edd66412d4f21c64ac522bdfc7c +5502f9c3f3e5592b3b2093d33c9bfaedd2d49e89aabaa832e23f062e91a2 +5032519d1868816e44b4e0747795003d7930299d6e1e2a5bfe0d595dc97e +140989ce81d8d7f852ff9cdc7a1b1b598c69131dee005b415805a16d8a12 +3e6a208511c6d0c255b9a5bb2fdedb4d399c6cf194ffac236883767c0f68 +f4ef84ee696b677de704ec3b097384f2e673a1f51692b7b260693738c211 +9f7d90ffdb21eb715fd5b8134fc87dba320ee54c2cec6a4d6bb350555eaf +f2ec4f84365ccc0802dbb3bd0e3f0d9f858647dd637725c2caf9557fdf84 +2a0da6a0ca0f1b442ef8ee6cbf2b03858468a466ac5883cbbd3815b28334 +3b39205803c02c917d06825c09e2bb14609fa32c28d720c0e14a4b12d4f1 +25ff6281ff324da33a56fc49987ac7d3aa206540f8127273ffe9a3dacffe +2b1c269d3db9a811578ac7d532c2efc18376f473fbb2b32ef642b19cdec1 +d6de83643723e3c6dfc87f97a7007b6081894bbc45c955b7001eb36211b2 +6ad7a3d07459cfb33f9c54a40a360cb802fd202c8e93d4db888b325ce246 +d02d1220abf55ce646dfb45f07cb848406e470362f80ce4c02d98dd84518 +9877732744cc16c7f5669f77ef096ea55aff98aa103eeaefb971731ebf37 +82e6ab725d4e9e35b2968689e8007c038cf25b6ae69451a4731e79ac22bd +268f56942a233e52d71873e83e00a1874e04d3b22e72fb2d0671af81c698 +53c389b51f4a257373aebf4de2da1e4da5e2ca88941f81eae0e32d982064 +c8afdd7a9a600d56d73605b9463c6240606b3361baf22af74ef89ac804a5 +793bd512da2d13f4bb1b73efca1e621ed2a65d665aad0ad228b3b7e3d90d +bdb6061e172b686e92355a7c7459d83199040a368b5697ddc3b81ddad341 +6ff4405e1096b1240edc18a0e9985ca55a0d697972bb11e9f1bc30765d67 +75bb68c69704be200eef4e11b78addb6229d8fa49a6b1525adadf17122c0 +fff51a08aa7aed158724ac4352ebb91ed0c157e24281bdc1fd610195f495 +e87062a8c38e0d046da4067ee16e81bc5f87e583315b973184e474064482 +9b2a52e0d37e249bab31988b906f891ac904d1bb8901f0673aece60acede +97b8db7935c6488ade8dfd898027424aa85a11a3da494498b084133b8570 +17a6d507d70a3421235486eb3cf7613c59139fd4dcb92eadc60bb6225d9c +d0599779217bdaf4813a453989b2e56903f4dbb83d83df4837c86bb4c3d3 +ccf98f07a23ebbf7ab5687c3e1e6792e40f92a7a466de352294064537505 +eef3f9c308c9eb94506db02cfae289f10005a6e42d2dce43731a7ae36856 +4b2983038dad6987f67062199018395bc0fcaf287a2b040c71f7325fa1e9 +a9808979b2fef19096b98b8a0a728eb98f2ba3d33b49e3c20be992822c7a +1bcca5b4e4d1099d456d8d7d83c57ecba0ff21428024f7572a1470317cb8 +cbc8679a974e13d88c681338c68c9ac9557f97784f4e1c8c2e61f26023ac +f46232cbbdf3c0bcc5583b935fe9fa09a562129a8927ae73988db0f7e733 +c6561ca7c9716dca9b88208a715166f2fae6d5eff289a9b2edce813403a4 +16f243f1b57eede7d81e10c2da4065a3082bc92a38b2457368eec9c3c172 +96cb09819e9e642d7365f9a6ef430fc7dd611ea5fdbdedfa72634ab599eb +666a5dc178b0a0bd1fab042792115ef3b6222c1241dce36cb38b738f68b1 +b3cb489fed9e53315553f3c5c3bbce40451e47b7ea53fd3d3aba6ce0ad22 +5daee734bdfa3bf1d81c1b42c6d856a05d0924e03f7627c5eb24d7fbea3b +d85716207f961b56803dbe046e81ed5fdc378f9ca52c14fd8544ca7c5392 +01bee06487ebdc30ff3b28e8264ec7fd5da7e08065b0a9147344ce28da51 +82335875e9f8b2347a44e33dfaa167232a5c3e69e8c5b58b7c7216537827 +c936f5741b87fc68753eb0d4a466961d0050db59df3195bd3379f5647f8c +fed35da952d7cf2ded45eb442dbfe992711d22eb228bddf36b8d7dba2706 +2d60d2271ea8e8412f4290b58f5be26ff06f0559872f9de4deaaba015eab +4904ba1f509f6d517c6e897312ddd571d769bc474fd378af4360e8b1f103 +aa75f48721b9e0ba589319e15d74ac0b03d730c3ef708c7c504787483f13 +4ea6297097b46d2680ff8aa50b7a255563c88d594b912f5574564a137146 +3674793e4834af11d14c7991e7fdb3a6abf8529e1a4f10cae79c60d37429 +579093dbd041ecaf03824df9c007e96f45595a524b27ef8774a83aeebd3a +7134ab4435c80944deff5c1cba921b0a41b9651968581da4834b3c0e6d4d +e13c1e792fceed26a72adc4d9e3903661d8803ddb58eb2b929ce31fc9f50 +a694116b00ac9f3eef53ffdb1aca3394bf11161038f39917b022394c75a0 +d467d64b89a44e5505ded7d9c6b8ba6ba098f140c9c00e09200eb4828356 +a2d6be9ec1d5524b09c06d9c6fcb5e2808050a339b5e5fd4dd6c2035a48f +e9674520901edcad107f67ac8c8e508e6003011978d77ed225f361bc0f86 +a98b6120eeafb73f7377db1e7213e02d12c330f5492511b4dde08558d75d +5b8aa2d56a3111dccd257ee96e3446ef1c76f000c8916c4ce261425ed9d1 +5b58ced128daa6c1300466e7b152bcfb5e6faab2519b8a98f26b29f98133 +af886a0aa7e586a090bda1dc6120dbb5640885c609a8bdadeefe5de0da5b +75a8a29e92515e86e7e66bb29581e5aff8cb6551d8d1103df60d558e7987 +e6f56126a13db2c9a04886c655064e68a0a20d1b7de24dad22bbfee1b7c3 +c208d4fd6a58de78d6a0a6126efdee3b1a9713dee94069a9f0a2b392a2f3 +91c4c75327803b53f252cc9ef0323f84929ba4716c50385681ff5b4ed549 +29821594f9026b7c1297941b178c3f8a704ce09760533dbc6cf4b18afbcb +ad039ecb2ebdc7838a9410e7b227924bed7123944675a5dbca388b710f8a +f6048b03dfb713f881ea0f3b191a5cd989ea150b979059c8aade40385581 +5d8f7980ce6288f47eaa37c1097d33f13776f08779063c5217d7408d9835 +aacbe5c071ea40c9ae6df685f4a9827b828815d8f3a672e73a418e5cb156 +84eb6c6fe0998a386e124d76620446907f993be16fe5afcec681f585601e +18182edcfd3024062a3082af97e803c47d32229d0a24596cf7e03f18229f +a631175699e2f0d60fc09c4f1954c5d12d03bfb4395f0e5eb6c687708380 +7d91d93ca4177a6b5a8d2aa500131fcb670e711873f8a3c77575ec93a3ac +ba37ea117db268cf10d04ad0f079484db124f6dc14a50ad3b0294f7157d0 +837d8f9a6060fbcb385606066401708c041594e0396a0be4b8b66fea141c +ce4bd29366a986adb98d9a6935c49c57f8cd415e93ff8ae0df75e463e02a +ac68df064c1b789b685f84e15e512404e065a39e9e8f5568a7d97671ae16 +02605fc7e4933975189837586fb1a55007fbb0e91382a629277c36a190bc +85af49ef3f0f38d4add2b5dee09916b79690ec83473c63e92cf617617a66 +df472a49641da10654e3ad3880d060b02a4a6c75b51e4e9917a2b6d8efda +12d59de5a8e222dc7e82f02f23a9d3dbf637154f719b14114dbb102be5eb +76b441d7e9990ef6420c2e80942c8aed5a1d0b19bce115b5929ab9e145f1 +496753dd6b1798324f5ec1d0c7f26fc3045d7bb46a14110c99ba07a45ec1 +6002cb754c0bae7a1a88eb387bb345fa70b0a38ab4d532c2de49274d4f86 +f2582728a2cc54b4c09d26c0cdeb8fee6a42885c6207d74953cfcc583ed8 +2dd7c0f29d35bdae5bb251b8a2d4b1dc97e2264dce035e359dfbadde84f7 +37ea6a59c23d1a64d963e635769233624f7682ea34636b595ccd064aaff3 +887d916867475731bfcbf7f96d5e5e1fbe6aabf454c2f504ea4e8eb38291 +1560195295c87793d5f7739ad7ec7176e126413cd4d1058ebd7d6ebee14b +b94a1ecf28b686411d91e07373e891f78c4c0a05d2e8d90a8ae2614f7fc2 +63a762d0f43485473a54c31726f8547701d4a38d20565ed1707847aed9c8 +05780f062b847e668e15565cba07a72b0ba99f03fb57d26fa26ff579c30e +ed0aab6fec1b5dbea81aa88f16f0c9be869505be18c1cb79657d91d6706e +2a3f0be9920655b93ebbae2b4d0b5df6be622c951f2cfa42aedbf7ae649e +2150fe87cdbf5c2685ef36051080bf39d864573a45ae2648ad97662b1f69 +787031b9bc43511fb84155ecdc3d91e2475d072bde6a5207acea1e0d2ecb +1da8a1bc4beec335a5c7102963e84b97be741c4458acc3d72a7e53b1f08c +955f33edc3a0dc3e7308270c0f7ff814b111459985733c62e8863625a551 +837952f3cbf32adcfd9f345e14b585b23ecc440775310654daf7f41e56ff +45f89701292019a94bf30eb2d65e14b1a1d6bf89d4cc43187adadf3f6e03 +a90ed01e5d876bd3aa56e5ee84dbaa4dad9824de9984bd45af96fb8a56c0 +10b3c3a3c6139d58e9d69d9109db18561b55ead6452497840b9ae90c749c +155b6329716f0152a7ad52dbd0b8a25b9995e1416681f38fdbdfa443879b +5c4c25aa29e0dcc07de8bb161c36d76ef286ec88d57c74bf44dbcb4feff7 +71d3bd82c8f4e233357c48e516efe3db9e60ef168e2c45b54651df9a5acb +5f1790f7929bcb16ce5e9f6a43919ad287dbc8e12d9f9e97e5dbaa592879 +1a5a02d39d259f3ce273a870906a643cc18d86e23f115d2a35de6926053d +8c84b940b362e7db183c4905060316b269223dad309eb5ac96deba757bea +45fa3100f77f4765334edf3d659e09bd1a5552da492be9174dd406f8353a +059ecfee3709422940a8c369919ee1f22f7c02412c995fe93dc4559d32a3 +155dd22d3526d89b16d9addc30cb7ada6e52d62c5f2dfd142d4d7b6e0666 +71ebad08f54917e317041f410cfd8a3243f8b39459c418b7b7c6494551c6 +f6753a94072d09e0d812351d62916383c6e061f35ed864923002007e6260 +89772d269b298dca2cc1f25d9be43fd8ad62d554c16afeb7ef6e5dda66d0 +5a810f003cddcfd2c02fff02bb61344968091f67d3862c1499409ecca137 +b9a2a9be314995b818accdae27ed4ad583be29dde4e8c2400c5f8152c857 +09ad2a4737bac768feb70ce81a92c9657dddb2d0bcf9169d272a063c75c1 +50addfcbc2f5f2503de3d13231aa8cfb396db38e80197a605f6bc20efa1e +de40cf424cf221218d51beace64a3dc88377e4f3efe43db4f4fc0803bf61 +764104cff0b618c9031198b094e20b0facfb94240b438b67ba298e31d3f4 +e31fd190e48bfce27b1be29d36e765e7d295e96edce09094fac43b87e294 +818fde9363fc7dc5ea36a1497ee25762d02dfa00a9be53f87abe62e52ed6 +f59818fdfca643042ec13d670ded1980413950ee43372d31ae2694b83dda +42e1fbb049f7e7b7e69c93ffa3195a2462423dd2c022e5141783ffa07e19 +2aebc5070f08b23aec9142eed56da74f93bdb50478da55ddd0a9987fea13 +1e4cca0efc51064e4b37632728261369c3fedaca100f1aa78fb718ece7a9 +f56296c5fb43781e63f36b0e1d34bb748eff35e1953941f94d1a9b0fa474 +fd68b47183f2ac53a63f9f1d30b9b89c5fe54c3765b43db403d57994701c +133e42b950d9bb1ca202f15b5e590ee75598fae43d5cf1546572770bba9a +6373f100cdc61db4e5ebbe0a93e0e51c86005e333f69110b1c8e492f2bf2 +52cadd5b73e7d3ebb53e759353f1ef3c9b8b39c230d13ab7158a5d92ee4c +452f81f6dfc18803280aa023832fd0dcb482ce5af615c952bc3f7e58f641 +7d69775fc7c0d5b405aac632857736acf32b2ee0f2a2c0f3b3cad483c614 +505be94706322f2a2830fc5ab592907d0291ed1873377e7a6158140c2cdb +1b0e27eec9ca50176102200992308045ccb5a169b61ea0546778b8d28073 +7319046716604945a21f2a1cb9e15e3a5db31e0fb5a3b0afdfdf6f3424b7 +536d473f9756ca3694dee4301fb1ab1ae47128f8d2b461c051c1b999dbb0 +10e78dd13afcbba6f7d5226d540527f17881a18f551b3eef76a7e28b4fdd +879381a2217ef2ff9f9982e9ea70ad2003b862d7c36d57c5ff9fbeaab560 +40fee973efc3b34d83191960010110ba10694c17b7635ae03cc1cd087c0b +05522a7a791f0ca34022a3f5860b536d9551bdfdbf560a07f63aa4e68740 +7e5e48584e689591f1b52671213e430a708c06a34d2e1d51cfa6b328a122 +007c81b5eb263b967746961bcfc8772f8502dd95898724abf369b0877f33 +13a167f3f714023c229c5757d4d46fcd9b4afecd093dcabe52b78132ce9a +b6225c9a344c4bf8d96f2c50c4272cb9aa0d606f013b2642f8c880e08ea2 +822c8cf5097d2cdb64932fe195abd5fdf36d3be123aedd8ba2f82a8a628d +be3ed6129dc0fdc4be50d5574ae4fecc65062e70f4703bfecb35eade1962 +94fe173ea57938679dba6d15448ff44c0d1a903b202439da93c0b0e61211 +0068f8079219aa89f435e44d0464f54833beb338670bd820d941df4b31f5 +1b895bedf833f9c43cb7616db80f988ce72fd3c12c7d49f740cf85b4766c +0ed398eb837695d102dec16e24b7475a0f5dde88fbf2d6b94f126417c811 +e8362b9ccc52d8891c13c10937aacc228d621d4712cb9de0bab60ede2a97 +e9292be04e42e6d3425594df56931a61e1f961726af6e6891d63b240e6e7 +9e5bf30c052091d681ba1102409874cfd8edc3ee2be331676e31ac00f807 +91d1019bb789ca4f5907f4823b002af3581448c352bb67d80fdffcd1c5be +ef60523330aa2c0456008f62deb55e69ac2f86369fab1ecc90d2487954e6 +1117a90d9269a65dfbdf297ebd29c3dd1f62755f8f289c42a534f5965068 +5f8576ea2fc5d26b99b8e3dcd3f1feec73131000f99aa9868ea9bac0b56d +ae2cf46da6cc1d18c0ab8d77becff7b89992175cba2e22779c13db9df53f +f5b1c8fe95e164997d94202c37175e562c8622989b075cdcde173452c064 +274354d5db8f7d5a78d48ad4a103b9e47500d08edc7c51c1f3cfa7f43c36 +86a3c24a7eb5018b0f419961564f87e212ce0a0741ac68d6822c7ab9fd68 +85f5d0b2ac249cb7f50e2353cc4b0a6a24562f564fbbc7090c3fdf1284ab +0ec615e0b3fbe132f31570c8a65c814f93910aa4bb80d516cb70d2e1d119 +69238e6f022d628fa2f33a0a15c4ef0ce7f753df80a8ad9494885a1b9ada +e6c38ac9da6fb0a61696ad3a502630252ad7b574c841117d34bd20bd6581 +217d977b35f5d04e02b933e1e84f5c090f6615af484d63265d28517ba74b +ea8876fda332a84aea12e6cd82b94ae10a778cd3a216abc08495ef319f06 +ad6ff8add237d911f846a514fdbfaa8a1ec8e0aa9f80f11f1ce615519a4b +044f3d1cf1a17d7f3d2174222a5ffa8b39f20197ff6caf250b6adbdbf519 +1c525070c8d38220fb501c223f493d80f498621a02ebccd6efe914f16b2a +435d60c0a1a453e288a53d818fe1edca7d55a26a017f2ee47a816e90d6c3 +fcdf0035eea307dfb06d2bcce43458a67354a4edb6e5c57233de4fbe41ed +07ee5ec77a5dfadc4032138da9e1b74428cad02a913e40152f8063a774d4 +fdd4070e4b8a6c089f199af7c529c277e902195db760d81ec655dffd1bb2 +83f3c5aa8bb58f2476bc797b2892e94414abbe96d4db93e280cf7de23eb8 +52e7ca954d6682a6f1a4be0507884c2a05ac863d2ba73f3b54668397b6c5 +4dc2f4183130ab414875f3c3d8792bf7e5fc4d228df87748bf0b14178db7 +e3ffb7891d700a1e9520d778b095da80e4801f53442d5c073edeb706a5db +8466ffe7e701aba9c364a37169f585c883a83713a61c9c3bd9336a667ea4 +e3db5f4df6bc6a552be8d3ef093639ec67e5ff718959f9902477f5aa894e +d2d1cd312ed82ee417d95c49c96671b23fb0e1738e892adffe62ec1c3d4c +beb6cd089c98de8d247df7ed17dfa2959d3662f105e8386d75ad30848053 +6959f8e6cf8f2c6937b09f2e8137c811327d6b165abe46c51834a955fe83 +06d10033f8c2a34667f13a8ba831ccf52c7a21c13db92f3e77b55ce291f6 +190bb1d194a33fd73151c3f61abd2d8a0c9bde90e796bd996d2d0094db2b +e98657e751bdeefe8a43ee4501b98f0cc6d80805189438872a60047a8caa +9039893530a3e5f6bd75bb466b25165737c939aff3ea59bff4a7db09c2a5 +b36b8a1f0c6c5e5870c7c9412589877ef44f84284b8a53b5b74315ce72d2 +eafc631bc4cc2e5b71dc958b5a6350cb5f615c3a4502e973622e3e18193b +69572def1d02303a375ed60aba1bc8a179faa0f221a49078fe15ae133835 +85fb45ff4d5f3bb3d0f6d8bf62e9bd6bab3c9a7d38c8a5ab0be57acdadcb +d02b1dc7952d73aef702d406f62719922bea96b8fdc9b879708e794891c7 +a0a42f2ccd6812c3f4db030b5178e3a627c3e77621d312ce4ebe815cd387 +7208fad92761a5396b67e835222609f823728b1c987857cfeaae21f2ad5e +a9d841212993508091a4a2c268bf1d8da1c650f6ab93995e7c13a3f84db5 +5748c626fd09c0da1e3325ccb0bf091e996245bf51eb486680162bae63b6 +513c74ce83b92359938439921950d713c69324a87bce67b45a030c9cf10a +dfa0a82781d49ff224ac57a23c6cb321f95915c5e14e41fa852f66e1e204 +4a9e7b1dc3be9e818515d28b2c4d2f2210098c39557067062ba4239f2aae +28816d999955910298a450741947a9a1aabcbd8aff3530626089978c87df +c73618c044731b6db8007739a9699abc354a6f985e03c11d750b8b9e9ae0 +5436205faad1b895b159e2c90562b82a62ea1a7ffb501767dce2b11c51d5 +5a17529ef5adf0a0ee9a96d0e7e89f68e50eed813836531b4b46e9071e84 +aa413f4135cc882ce832bf78ecfa7cab0c9f64eb92c86dfcd1152bb7d4ab +33831aa0c139b555967f6346068d5c3351a7a4368eebd2933e6b9f789daf +37ef536fcf965c397af1b7f98af864b301f3f440b7acf704b59540453678 +fd6c15045194818938123e2f47b265ec4f5cf2172d394543d84cd4281165 +cbeb11349b315a85deb2d1699507b0c8c110c72662ea2959c4962ff093aa +5ee6f21f89b3ccb0149cefef1855b9a48d28bb363416c015a1f4ea1975c3 +d8807f616c5817c8162536176f464a198ebee6c97029f15f414275a39b82 +19128b8c8542e94835507fc2d3908bb0ec375771280b9ebe87e827811418 +ef93e52ef70546891bfc0fb34969fd7dea4ce7524d9eeff2b46bed908c0f +b2e02efc1d1624642eaea1cac1eb4841e020532e88e59ac890e6c3f44734 +b99722e9816402d1d0fdf8045c5481ec055100836ebfb48e9fbc39214303 +2c909853c9ba38a19363141bed09daf02fdf4e7cc9808321cd0708a1b452 +70bffcc3a0d7c27f7e781713d5dece82c72ed30386b02d14575a1a644754 +7ecc7faac1bdff332c92984758e242256c054656cdd2c45d46e67aec6f83 +9f95d74e222a6eae12efaab723a7c816d4e42d4ed2725a794743f67597f3 +db8ccdde45baabc25726b851e02e56341ebe69e4d91f2a233583ec816f18 +a1decbda4ab69320f55e730617360fcfb8ac2d2b737675b406297f7f8c4b +c370cb084c22bfec5fef02e9ab290282f7b153f0a4b1ae569f1e52371a43 +46a748dde09336cad1f5337fc3d7cf0677091e59480ab15021e023e356b0 +e1bac6c6471ad53625c70206c338536f4d0d40733ab217e2297f86b59371 +7c61458b6c93a16027cc886a8cfdc01ef19c34c9a608b95a84b6a2e31454 +bc03c10fa55cdcb7b1eb7dc16ac1e93981a46decd7e7f00638dcac568744 +69a2d9b45cbc81398727e4ed3db5db31965f358d8179cbf934ee2c4d652c +9cc211807f070c80e3a8222b4c31ffec8dfb9ee07a94c973462254bc1b15 +81903ee6f9ad91524a787129a63fce048b45bbe6855826750c586b6b23b8 +05fec3e7aaac079576949a06f422fc2c826bdb78ae96135e9e2c20c2b2ef +f6171d610b2eb8635acab7c5c5ed9c9ffc26cd54d2fd4cb9e4294e178cec +a1e16cc8e3fc06518bd16f4d63ae2b435753538834cdd9d8ae7de624006c +e688938031336351a6578c304c2e5480a3fcb43a8bee4953dabc30558b77 +90c6e7a6f0f9ffa557c50417407ac6a0dda1e736f7070bc89455fc293453 +3db004aa9070734c8c2608a07330e421a0220dab99f8a77489132f6413ad +b9ea637f3b75948050e667276a55beb09d4153dc126bbdbe0db9298ac799 +a943d72afb769bfa1488d311beb86a907ec9385aae4f77835dffe4389e3d +9aded1b08bbc2b1ed6084b3d1074a326ccbf38e06bd026919107bd03bd9c +30470db779508dfe0dc82dffd2ded749e872eb7eb9ddf509d5319865070d +d76846c34e4e43691af429aa40db4bf2cdd50b275589987d8081f7c5a046 +1aa5d1455a660178a94a0ba0dcb69c3cebf5ee0426d6534f6f919d9795ad +6a0e1a1f452af3b4cb2ea54d6011fa809132421d111efc51174e223ab6a1 +3596411a9723079231b050cedae7659cf168c39aea9c6902c2cd37d25492 +cee00096edd63dc7643b667fdfde5b595dc54f0a72c2650e1e46990584c7 +8a5cef9bfc3c5f88cfb0c49cd6cadd9dba675177d601927d75c6902b55aa +ed0e9e3cb52a577c887d581b3ce6201a1c77c9546cee5a13b92963337f17 +070e2bf9f5c5e86b84225863874618aa50f4de855de567bf2ab7163944ed +43dbd7f4bbc0e16231807c43dcb47b2eb694e6fedcfbe26194d2d9943a1b +fe32aa1e5305f5e341ea021f91532162978dd1b8c5295a5e7551e2dee46d +c2347c6b32197af430af3bb676a53bca9bd1ea88678377dc0a9a86e2ab6d +e29e3e261bfd5573c66fb5687ba9c0544d894a759866b066e1db5c66e60a +e071cc3a1c4ae40197cde4ec723f7b80137619dedc99af57a5497d6e03c1 +c9e672e74f48f6c213a3cfacf2699cae72345a51c71c1d69348de5bc5f44 +3ec0eade1e76a8a33066922cf3869e3c1d26a3b34e540dc08ea4da2dde3e +eb17c16790da4ef1a3a76d71d34b788a87838bf2a5a3db8176f9c097d232 +0050a79ea6c4a94926da11abcdcd26dba09fd33f30aeed977e8b5ad928f3 +967f607628859429dcb4ecec7da3411be35a03851017b535985632639d37 +8cdcd13b00fe537a49fd9eb6df1e3aaf5c41ebe35721fa6833c2fe08aa3c +ffc3477e7fcebf9ef9f4dae62ff78f319481c3f1e72999c8a493ec6ee295 +316b58a5cd62ffab62c896e521b678342f04bce1613cf7f6778cbf5227ba +20504500d743270771953acbd5c6586432f3fa6c0987bad33b88bc6c15d2 +9c4b3cc54a9dd72a2357aa5baeb2cb057cdce72dc80cc98c62b16ac50b4c +6a7641379b766cddf990dbb2fc7f9cdbba755b6e3dea438fd6699c30a99a +8b3178e6d613aa938120835e517431d28114bca1ab745c11fe6e52adb82b +9d3d53a33bcc49740c93017d9531ecf43831359c5c93cb0e926db440b139 +e3125cc2e069b1cf6d96ef68407f32db517242c3ae0bc6723e560b0f45fc +7f87a5e44e1751c8b7f9f669c24ad5cf16f84fb03ba121b86b0694234d8f +2c9c947269af96fca08a78f736e4e04acea44c5baafde360fcd8ba6a5972 +4ca86160a5527fd564468123d302db45173c1b216b01dc5b6d3415b13fbd +bbd3121a5493374b3357efb131cabfe5087aa1d2c7472b0377066b3632c8 +2073c6a846285cc953a8f28e131cf587b35217ee498d9a1db57b063ce068 +daf55d8cc1771c0c30999ca4fdc5d67be4e7e69418f6334bc6149000821b +89a7437ccdf9a6a0ed702d5968f1e04f7e4fe9fec9d1e994885cb624035b +bc5426cb8edf0456828f8eee75be491b45fac192a405eba25caa4f4c66c0 +dc234d7b417628da5276c08260be512b2432256c401a66e3b583e69d23e9 +fd278cd5f2178544d05416b9b4f61a88a4728af2ceed07c08e207f31d644 +e8e3ba1e4e2f9d8e30936bcb9c6aeb54e37db46bd64f2ecc1021336d0564 +df0f18e5a6b6ba470233d8d41fdd9d1079706ea685b6d8a740570bfb78e3 +984bb155c3155c69bcccb41cb51975eea1c1b4294cb546cfb03dc31bf86e +c3bcb1977e8f94a771cab09de12a82f1d6c791fa7800e5a21df81c9c8fcd +a78622abe75b54aeea747aa4f26d563200992e337231a430137c720a17d4 +4f3ad6cffe63b2de12d3184bd3e151f955786b8ddcccb290c42718f3a219 +1759df76371c2fc177544a6c425cab14aaab31628a9cf9d71b5257aff0d5 +9843989cf0d747375a26dc9ed29b66ac2147da0168306c48c2484c70ca92 +f33c0c138f92f276f5eaf5ea3082a8a1cb12db661633c2f71e3b69918f50 +9060ac949fcd52c36498a2abb77d139df1eb33e3b846a7c1bbdcef5deeca +4ef0ad250cea9c2751e13ef7681e8fae0491cfa6c144dbac1fc39d39e76e +b12d3ee9ca159aa77d2794f0c433345b135ba632f544082bbdc9471e9fa3 +aed3a7d465ab7158e8ac97f68b1fbc8d368e235045c18efccadee98778d8 +94d96301f903283c5ae355a863bb0dc5809158f7e108662d04a5c1234915 +e7bd5b4c30f9efa55e702e54f87fca06fb321507bc57a1e55cc117e21aa4 +e3a4dfb77c1a949efe366d93f2bd827ef8cc16d387ca82ac039f77fe995b +e6d9aefc87f8d809e90c1017803bcfa1c737dad5f1a631ebe6894ad20c70 +791665e7bc71f21c2c3f4462f60fde75c8a377cf49be99314663c6ecb538 +b1bf021b2f2174d2b22cf6fad115eb0ece8a2e64097a5fb0a2af666e1ee1 +3276aec59fd0c9d4bff23f71e835984e5eeee36490c54e077ad7355dbc98 +bdd37df29b3ddf8c55480b7349c4d17322418705796a8c521fff920dd117 +73fc44fc631c7d6e9b420d7965d7f62ec7385f2be30a51e2d796483134f8 +40aec71fa19ed1272c27f98f2cdc9c7e54dab585ac1703ed08f5f9e82556 +4902efd08edf99dfd49444c21fa6be16cb8a1b6d0c8a5abf80a50bb8d055 +483176fd0aa07ebaead88fd694f96febd60751e5c4d8f9bc747d4f4030bc +df9b0370b7a5e0a6923ff60dea16ef47f886f10ccee6956ecf41a21f7c59 +6f3bc78299a9657266807e01762b2b2878e551914ca312c2a68d34cd91e4 +f5115ea1fbe801346e14ae529049089b6b0273e258785773a9ce8e4b6c42 +11cb7c2767319576758f811cbaf3a3ffb41b31306c49f3798b698a47bfa2 +e3ca0251c4d90c0b02aca28c611744526906791d9e157e54ce4e1bcf5b68 +6990ba8ab7897d624ef00eab92cbac255ae9177da9f0d86447d35b452cd2 +f337147b5d3ebbf2b95235778a72914eb3707ea78294b3a3bc4acb19fe87 +c72aa1d982e4b822f07b115cadf4d3e7ee3d1ba708653bec6f0a352a0c33 +252ed0630e7274961896d461ee8bf523d5911bac1c8ac763e5fb11fdd217 +4e1f129675969c195476c7a5e18a81bf9a11ed9f2336d5301e3bd32174ed +5c933e8c85d6272ea21852a6f7e2aab174e0965f73e0ef89e906bafb181d +bcf8b1f5aa0c12d12c6272753c016afec2ec9f9541b8757874d6f2e061ab +be8b29281677246305b3c41e90418426c575baa216cee3c5ec29b2fdee1c +77c14fdf940792f48a56ae80aa33e370b037cb28a7373f882022af378f26 +b6006a049fd3b35074a865c97d153352acc156992c00de26ad21c982c71f +0edcfeb61593bb40fa5f2cebf23c4ff34a4f4bdb73ca273c269242d1c611 +7262b7c47771f2619fe5710855134a80fa8f92bb2425cf88940ca3450f81 +234abf2b11775929b12cff86442b2aa0f4243d324a5983e5d1829775b3c7 +a111d5622d1c4e2b2a2f982fc8a95f789881416dcb34950a393f4f1720d2 +212f3d343a17683060182355de9e4718506d76c9184f8dac55788d7e603c +faf4907dde965a49c323dff425fe88c09aa4a4d16283f9b14ab9ef1bb885 +a954034710b4a9da4c88a8a0932b18d139a687303ee562ec9f656f12f3e8 +f27daa9c75db0fa946fd0e1a982bb58e040bfc0a49a4ad8cd668493fcb57 +3c849ec5474049a693cbebd4d79ac7515047cc347a9a7570c90861f3ecfb +57b9f53ab9c0d6b05c8c570a8f3c04d58555a45524c98ff091b8f8a422f2 +e0e9e5a7b7ff69f1cefc13e42f1ca276bcd584516d266ba6838d5e9ca9e9 +854f50c7d92caed61aacaf758a7c7be59c3baa82bf32b691aca3e8eb171e +08ad22c39fbe586a54e6e4de2cd86b31138546bb8da5834b2c6e4838547a +1b67e651964e43988c8036931088904bbb589ca901e7ebbc094c0da81e09 +1915d9e46828ad8596fd0fca39ff12a6c27a359337f973809e81b2e9e3d4 +3b3146f2516667e607ffeb9ac80fc95a7b7d4ded551fee0f3561c70db2d6 +9aba96673e39e3397f1c3f8fe5f48bab8ad6e0ed8901f90f6cff24e80cb5 +dcac498506c4d01033e497c1241e413b022227a3264da68bc3f91b35781f +a2d018475c199f43cba7d3a0d5697b45321bad2c394b207136e1e16b4179 +4975e8903ef2b2e1c33f87cf72c325c11ec0b92fd3890acdf60b521da325 +96763bdfcdca837adc6f26f129b23ca32f9cd39b33e64576970df3c05b8d +ca4bfe2f17e6c5678b84d69494f1dba9fe0446ae6afeaa1ff245c07916c7 +b7569e6267c42b459435a1d116cec665b311e404171774c0acc8dde96b0d +9167c8cc7d99c42405592d745c4428755500eb4719340d2fc6bc215b6782 +3f69fa949c08b5ec985d7aa87c9ac1f9bcc8994c6cbce6027b7d1e0c22a8 +3a5de61dba05d4af6884c95f46ba7f253e0b2337e312916e163caf9db2ec +56c5425990fe73ee53e42b3bcca1cf642f02b0c5abd529b568e9adff865b +9dc190240ad78ad226ed884bed3c285b4cb0e3929e805c67f1318d186504 +d92085764b70de6ab5ab6990f181bda50fc31262348d980ec76608cf0817 +6c2502e065ac2d8ea5cf9e2d44e2b70a7ddc7b922047c471df8a0b2087d1 +106b5bd8a830ec0e53223ce3c96ef56e5541191167860eea58d696ec357e +c55799438c90156bbf2b13a0d5c9ee93227746654ed73ea5b9cab61dac5b +c690f89c87fecaf9ad03bd39e438f43b81d39e07e0422f94e8b096ab38c8 +8bc2e1a043811d8141c1a35dd3a6dbe41620e83c8ed3a379cd80d4f9bc30 +41bb44b933daca7c5d4427ae94a176829f24b5968b713431cb8bd9f53080 +832c6b784cea9b515687f121983eb9d9c9ce8bd4fa3bec48afe64e643b7b +d86d8383d07521fe5d091392be124ccc911136043824b686988e7c83aebf +406d2da88fd952d0fa9327f4ad04c55fedbfbfa76ecae8a176c516479ae1 +467125b7eb3c9e7c5b103bc0c470946346df271f8ee19df7e3ff7478c35e +e059297f4bf21a5c7b95993be6202e897776952a7ed0613a5cacafa731ff +c633cab62963150e86edac796026ce02eb235b9f7a54e0b0c5281567138a +612bafe409a818c216da8eac5edf9d1e3a1e3514ae50735a111b4d2aa083 +4ec6c11e290d58ff340f82f0e079f1c7b3566f2336eaa45bf72bcf885699 +88db5f65d4c1e59b50f341e45a899656a0b522847ed567b49cd5284fe50e +5f8652cdac1c076804f2b2185f6a51ed19dd49412e65a0d2dbc844b75e2d +f71b009776d9f97a4c6f786effeb87a307fb6b912bb659dc2bcc6d509a9f +bde87de8d716040a8551b6ccfb7743978ad992d14d2b85ca052e87326138 +db196c24593f8f7ecd6f486f85d1666b9de2aca6c7900044ee369d223524 +664a2790b773f9ea26e0a4cdfd709942a44298b8249506eb9b77bc887dc0 +ef947dddc7cb3cfc6b48f060dbf032a11884e6c226d9d447a5a458cba325 +d57e144c6dc295262763e7bb8ff6a0ca473eb7661c12e0e8e23ea37e8ab3 +387b9e54686f3e57765d4067e521bc1afae52394227793c737c19208803f +2f2da920b553e2aaf94eb992ab17e31b58c15cc4aa8a1b444df5b3e7cd93 +7cf03e1f7fac63342731b4589f16939d16e8e497a74cde5686f529e9495e +1603d74875288cf53271db9313a4511b104f80b179fcf213558970a002e9 +45281bf3ae51e668dd6d13d9e85152747f562ca0b75ddec8fe9fe31f8d05 +b0f59e802888a7a4f19b29954a31108d2f041367debd6aa1cad856bdd142 +7e9efe89956fe28d500cdc6a0cb80a76902a08d0bc6705583243f1dd8020 +749b257edf4803bcaa653f7fd6d8b91690995ba5ea3ee92fcd367c11601c +6b8adcedce67b16c596c5d200693ac5fa15d4cc6ce9df7a71c8a925e99f5 +085313d60fad25c1bbaad28d4ac2b69062d68f390530a976319a3904cee4 +4dc9451e441aab4780425440f8c499b81460b5d3e268974145117ed843b1 +71bb14aa84c3a084a7d8e07b9979260675d5ce6534dc176ddb60dde90f6a +3674f67462ef78195f8dff74fb5882b079dee31fe92816f16ce1a70d0775 +2ea25faf5000adf79bbe7d17eb1bd2f9bf6cdbb6f078caf97986442680a8 +fc4121866f9ce86c385de34e30d8b9768a0136d9eef79a4b38ee99cbb9a4 +d32316564c9d56996e2595753ea71bef684834fd030d38bb100e2332b026 +b046316a53270a96dab2182e994e91262fb03d1affbad623f16892284098 +84f91dba153030870a7beb2c7ee2dec51875b13733b7929041f8d23a9490 +4bd54dd4bc9b432dd0c78dd81639f46d686ffad39aafbd1b6c1a37e248ce +48f23e12464d5379b4aed0d50b5a41577e6ecb75270e9ad3ea7d0fc09dab +271fb18b51dcfc0069f15d72546e6c51049f3425ad005f88fd7f02042dab +e9f097f9d6a076b30d8cd777b1ec12bd163fdaba5972eaa61e3c87e9ac00 +7a052b1a3ffe14d7d43c7a0adc89b1dd4cb4f9c762a84a6c0701494b2d8c +4e4e1a9245738be4111805c2f153a20ed9fecf2dcf4c8f7c3baf84d60454 +a7403d4f5f81c6404173a7ba81bb0ceaecfd493d877465dc5735d43e3102 +cec57b8a589182fc65a4704661a9e351fccbc7315a87e62f65d24eeb9cee +979c6e10dbcf5c162adb926ec8cc9bffe381f6b8a3ac0a19d1631bea2938 +731afc99e8eaa39bc75ddb3a39d01ad8f0bc1838f4d674b9bee9f6f7be4d +9c8bd97e8d171eff330c15b76614a1ffd25b3be19e4a201bcc850f926ed5 +1616318c965ad2f0e56f9433b1247c6d5b72edf3d408a3e0674a509bf30b +e813a5e669d72b978794683ca8b85e3469eacb167c30f7666db5e081b81e +e99ecfbc1704b9646b1a29e4a4ce5654ca8409add60145dfc54225bdb848 +5e39cc98cbc3f38fd0a797e5dfc2099452a2418c6636bd2d5f6b24345acf +a65f4e7dbd2d0aa0c1776a4920b4466c509bb5bc7d6627946c4dcb38a270 +98b7b5beedc2b3ba18f927077f71e38644597719652037621bb350bb5369 +dccc073954026e6438fd8393ddb3630c4473f06d9fb9e422e435566c396b +12fdcd5605dfea232171cd8ef298786806e9159b84599c26d4c7d8c3bb06 +4665cdd072e2083190372aa808b2268b3fec8878b6420ca829bcf995dc20 +e067ee6b8e44d2869d51ba3aedd1763f7f8d2cfb8ec41e6e9e0129de5343 +1457960cc51d546b10b8b6ce08a1c2b79fba448df9783d815608a16c55e5 +89dcd8ef6b04c66232f47a473973a35618000d79b8173258b7365c9691dd +fe47b16eeb08b28f881828b946fb5d6fe10ecc6afc4ea1f762e90b332040 +3382e42af4885b183aa48db5e4dfc9a54e0b4ffbf7c26eb17a4f13b4bb93 +12234434fff05549e7587ba0373acb3e31418bfaf400d8938fc6466b9427 +3d1735306ab912aab13e31da3541c1733e2a7e4da5b82767d37f3084aa7a +7c488cdca7abef77d19e42b4448abbd346e9bc288abc4540c0a1cfd0bf46 +c5bc7454b25e27e9906a3e6cbf678bfecad1b19b4e42398a210cd567ec35 +fb115d5c0df0eeece593982056b0e1d14c292f70b3e049984f8881c8b477 +956ad3140b4aa22256daac0d11c4126808b5b9f922bcc5f24a77ff352e2c +621a3941ac07a20e550a69c49b1b87d116ee6f2f970918f0f1a501166ac4 +423fc212e4ec8039ac7f9c212d864f418cbb92948fbd588228108fac1ad1 +837070512305c110f0fc3fafe6e1529c2bd0dde868a9ebe5137dfdfc5c12 +a3d08014bf0ee27b108002aad6b607f5c5c0f1b1eed3c552919c9a2e9720 +4a8127f97b1066607ecfb47ba95ef2b51f007c293b2f6a63041a9c1120d9 +cfcd5357222e5b02dfc73cf94cf9b5cb00eaf073e9bf253e30e09b50341e +57bf245a746ea31bffd0b00201c34cf0881bbd1006bc9ba7d420a48e5368 +6b598bedb3449924eba58d5db1b1b01ae2ba281d5758c99efe38adce18f7 +b182fbd0d0622a6ea497a4e7c00c7d17299a2765efd8de376c214d01a218 +19451fc04a0277ec84a151ff93903d61c78ab7886911e36e12526ed855ab +43f6289c1890222602b8efbf15782b374ac1e580b6e963403d6d15a051db +8558f2e61c0b9476c6de5d4861585cf515ce951732f20d32969f39192fbf +1690d242ac04d47e0c53d467d0fe4656b9526c0f7f852348b0437737cb0f +29ecf9b54a5e17185236dd0c16349c3496f3aba569ea20e343f6d771210c +39dc932dc65ecef94575c6e76902cdf6c8c8361f9c757a2577da535187fd +526699917cfe0ad438c2a758727b306bc7979547e68b94e87ed820614bdb +c649d469ef6b4e4e3dd2eaeb5f80b22fe576ced256495467c76a75f58946 +0061e03f3a1b065121a5abe3e2c51148b3ddc9f624c97889aaf7fb84b158 +c015eda5670746c6359d27b0c2bd65144f2b88a64331816da904572be398 +e015a9924218b3eef95123aabfc3ac8217b7b4f691219a1c9dd0a3edd5c0 +4e63acbde71b423522532561f4b71b7028415c3437e346be728a415596ab +749015c1d59bd8328e39a850cb98085b34b57fb52dd1d154f98fec49b3ae +bfcb1672762e4d2a1ecf02787f59df1ebf2625c3631bed849b298c6d226b +e4e6ea2ab66a287d2ba92a6c9c612a5f849b3cb3c25f17164be286f6e4f5 +e7e4c9eb17bc68aa5ef0190b64696a570442e1d9bdd1a30e7692524e30e4 +b4c3df84481dcec6e10e7308e65de9d90099f3fabb3f4f766bb86cc98594 +6d2003e21287761a7386cd8461615b570bda015f5efa23d18e83c325ee44 +4ec166a1a32d9818c2a65a092d44156c06d3fd079b92450b8a491cbb3529 +ddac7d95afe8eaf33777fbb265feb8a4b9aff2cecefff49afbdcf6c41974 +97d3b448866d70ef28d8e4b17e7ce95f43f64bb48c4a73eb84b26650f62d +3e5199d64db0b5b87702650ed0b850fd5d16c848d096e4c7e61bc63b2a3e +cfc099cd713e12c91a6577a88d6f55d348617c7a49890a86ea8fe2045704 +b5ed529db128c9b19ee129e5fe6498cc97087f6bde96007c9d01ce9caf75 +646e5a5b32bfead9362a52223d746943a2d09c536cfaf78e601bc2d2f0b7 +63ad722e3a7ae7069d65f9f2bded7278511d0120f5ea071d41a69f8c2a2d +720d3b24b4be61c83ffbeffae21b0560a6fd1a44e53e42e0d10e0e93f421 +a8a7e167bb65f0d7f1dde2809fa3cdfd931ccc69b119c83238c1c00ec100 +d8e7ab1c7fb02ede97073c8a5860371a8132be391eb1c397b61f93876feb +438c288ef2e38ddcd182a5cfbba994a94a1bf818312cd8234215fccd7c24 +0a15ac01a885e1179e5d7d6305dc2f534baa141f25ea6a5f356486e5fa0a +e3c6980a9f5e8e99e7ae5b95ac429775109702454fc951e4319ae4b1ddc9 +b07d0998372c0a95aba6985a4dbe6dc633154faa30ace689d36a7f17011b +f29cedc58a6692a8b3b0a5742e6cec2f69b255bceda762dee72f125eba98 +891cff4d88aac14188a18d81424979c9079e44890d94ee094d4caddc1c7a +c5f6791fab8849cc0240a579abd800efe3aa4ee2f78119a3c2806c05c2b1 +f17940be73984982d1c0065433a9bd658ea31ac819da9a11b87475bb565c +c294b6f302fe3f7752ed9b963c5279b5f1196762d0e12e6da46ff9a0cade +3876d7df695d8965cb4b47b351fa3f759811269376b2c3134403633fde27 +c9b024f6ba81f3e1699cf64a426618428ba6c3266bf016c5daa5fa4cc82f +b6dc23ff2d742160518cd3a65adb38e53f1067076ca1625466e0c64670a1 +564a54ce14dc5c57d24a12283fbcbffd0fd594ac2a56ee58b552f7586825 +e4fb1ec23f8221711692c8c56f42272b87ebff3865191f1c11943bb76d8c +0cfc53ed452ae49404d2c8193ecc2a7bb8cfbf24870aba38d2ccf7869e93 +63dc0ad94facaed5922b324dc3b6fe83e7b34fe29abc1ead62b49ffbcb81 +1adbb5148d5ac2743e3a058386036fadab6ff071bc1c3b8023f908b6ff48 +db0ab1c9c67487c35211d40995e1892c8b66ad6c9c6203f6f8b513b11117 +b10da8725ab45b4437b5a88a96af3178d856d601196e8162868a83da64e4 +08fddebd14d6591881ea652032cf2f88b3fd6c0479c8f89ac68d14d01af0 +ceafd95ad146e68fae01a07f39e7a0c5e4ffa6d6a91d710827ca5acfe7d1 +f946a8d7b67621d60f5341f32c12a6efb03ae5ac5373a382c044a276f6b4 +1c173d0aaaae0c1de4c3cc71ec2637225ccbfbd45eab92bf39357c57195b +410f74283585b12b926438ac72afadaad2d0fa2cca728c8e86bd3fe75d47 +b8beb96ab13b5480f7a3d5741eb51e3e40c21ff2ed7d9221d9877c7d1a8c +ecf394e4023fcf8c4efdb38b839499ff5cd96a46ab4fdb46f35d3b48b917 +57c0159328120e93cf1f2739e936e28908fb19471d3ad7f6f1ad2bd1ec36 +4986a411cc1b547d0ca104fbc10b1ca7b638a60e75485574034561db345d +da68415146aac632dfa34769b6ed7d7d4694e92cbff4efb16b5549590810 +2e85e827fc623cf1bbe6a13cbf64e878e1a2a159948b5529b75e071744a5 +f0e50df18c110b0af117ce7f33f8c959d4c98ced5a9d492ae6f56da57b0f +17495dacb130660bcefb064fd8309d965abe8d2be98f6898c1b7a39cbbe3 +e75da0ffef6cc3945ce76da3be915546fe8a5310130ae0acaa9ab73c7e04 +1c00533b4bc7724657aa649b9388b791aac5eabfcdddea2cc67a0fd0ae9b +e37df9ad40636538ee55a83f60e9e026c64fbd8b220ceb46e67410144a52 +0fceaca252e8165448f84d8ea083c793ad09b90b3ee83b73fefc3365c729 +e3c738894b8c01c2f8aee0cc8b114e1175efb44cc4c6cef5c8754b1cc7ce +c200ad8bf1189d741cb75bca4e88be959e32216ad33f674f49ab20a354cf +3969f1611a95d3934e148831ae7c81a7ebe3c5244f743e66a82e10d16cc0 +9f8194ea7a596bc5981d833318ab4f7dbf2abce543e410b649d18d146f01 +486159683df61a3f880f9b21ebfab77e908c6cfc79f89ba5f51114f0bf7c +3ccec7bf0f3b057c3195cfba6908e31e0df10df69163c9da7babc00e9a58 +0fa7fac202910615bd479bbf76fb8068630d1ec21cd2926d351e869e16c2 +cf1e023cf04d4fc61607daefeeedff5593e6023492f00029e2ae4b4a2c14 +50954efa2792f32b4934a768f892171245a1e2f034e2b9f39833f1b331a1 +9a386baacfec8c929ba6b67cd8922bbc9dc005ec3976575d5b0508d0717c +6bf11123ea36d8fd37fa77a6f1f5aa84d4ad8d25b2c11d1877a6e2f9b74f +3b5829faefd4f7209ce9785aa6fde68672554a6f29d8bf03fe108ed90a7f +58690fac399a8ad3a26899072b832874ddb629581a51b3325cd9edfd49e8 +90ea8959db937dab83c777f2a426b967af5888c33a3635b78d647ad6ba44 +1e222c958ea58d61945f781d7ef409771b89b20242ad7d07c2ef592cbf41 +3c5fc89ec30fc9ebee4bc63709ae33b65ee3091cecbe610b847e12c556a2 +79c8b114c3e460822d3330adfd72bd69f54c08a81848c2002a08326cf3b0 +9b1305490d35aee5917908e1604ece75bbe811a715ae8af7ea9c371b322d +0428edf4c893fdea607e70e1b6f6614947326101eaef18e29be0557d2a92 +cf1fc1505e8b434bc368ce07ccaabc0774f8a63e1073fbbceb3f4052462a +a9008a1e53f188c9eae339faba74afd6d60f47282cd9ff721f64bd51787f +3c13b5a6c5a5f78611710111f5e0471e206d72520f1dfa465f4a23c71dcf +99a04ceef11b0e3bdfc35b7461a60753d3ac26dc50a5956c9195a4f52263 +88e0953ddd03af128a98f03bdfa0602cbbaa20ab9eccdf7255962a332e16 +d4380762e498fda4885c64ff5f9b480da487c58e78943df62616e6e2c69e +ec8836dfcfa9ebf58938a878f3e792e8bd8c5d6df557a5d82018dbae1ca9 +c64ba5af8e21be1b6680fc5db22422220b776e9ba0bf1ed2b7212f8bf111 +ec8c8c77b223c05eb5e5f1cfabd2d037f4ba0f9503e2cd83f4519d180476 +63f09e308883f5da5228f83045ff41214d2273b2fe0a9017d5e0557bc2a1 +98c35d1e7e81f79654445760cba1d3f05ea4b90658e53fdf0823bdb1501e +d51da75c47395073d8980d1e3504e3f67db3259e4ee73a87cfd96f84e221 +796573958d364a51e635fc55478c9cbf9aea16b7d8c25f2115cfe4b7f598 +54e24968833ba0d64d1d332a666dfa2a3fd71b05a26bab7da382907b13de +0b80871df184d3622b623d7e09bc32a4f6ea2e6da450a906ead36d53fdec +7f83e101fef32f4faec581b000686d86a0d3861c1e67f18a4c4647f51f97 +8484d9e3100b37be9d20ae84c085461c1fbf929c669e936659050c2627ac +1b019837baa75757f5b0a82e8ae9cf2111931a38bfc94744e2fde3f87103 +42ac615286e4ace7f269743aa05463af537d9416230ecca859d8c99b7c6e +70be7fe11db698589be9e11900c8e9582a4ef5ea94b5f62820c90dbc022a +620ec536e06cb8be7526a789996d0e741aad980880a33800a6fe92286ccd +02c9cb407eb31fb95d9c9f4aff38b37087ac582c1f7b64a7c3d2202bdd62 +e9aeb31bca85c4cf323f03da9d318b91f78fdc0d266630f7444ed068b55c +05461c97552366a82c2e743cec353d51028fdcf5403b3b74d379b82eb69c +4380ed40239e15a86b2e5c860891e26781cc111fb5705e3b7c7af1946006 +54b5fa1b5fc54fd0ba43666e7babd2c91c859f393ed49f7123edfb648a3d +6152f2c17f7e438c0a638968ac06b4fb3f77f64f358ae063820bd33f0213 +c85c40e4d97ed100ec2da1c2e1ea258bf107af675a9d995f60bfa37222b9 +c2b325c0052bb8537d2b27dd43a129c7e8ff42757b3ac9b447703d382108 +da520b8b3bb3e8c7295b776b44ed28f863b8e1f81b0bd1daee8a171525d0 +9d2620c04dd3219d880c2ecc79282dd7b1772a9cbbca706909ae8bc7798e +6ec7375189b6cfce8a875849176e5913b85a18fb197a33ca4b5b4058603c +f1fa79a56856b43d538e9ece117d99afa73b57e307364f553644de01edb4 +6234efac13046b6e047ecc8f63942f20097ad7acf0a45c0501a95263de94 +39a880d6b5c5214d29180a54d7fe9b2e627ef49e189b59fcc78745e878e4 +5b46c0a648955d3ea8c935113d94f92ec963f66cf3cf3a526ba71cdf3cd4 +ca69efab08b7389e3390716892a4872bd29dc1e0889a42d7ffb4190e9a8d +05d84eb9c5741be6b02716bc75e0106f5f94bd3778be985e03860d27e440 +88c3cb2a059debc420dce3a8f4087a9548485e616c409ac400dd1c411ce4 +b6a229d091b253eb68f06e43511ec5aa6eca4d6e4818d6aa2068da1aefca +377611bfa816b5215182432d5683294d67a7c1fd76c52233087ca44943ec +7280005e93145f5e7ae50100c18364e1b36741e9647c4dc1f68a58ec4409 +5920fdcf05532f60371780f78420077ef5c24d63e26040cddff8dfd65d87 +1db943f50cde84900c1372ef33fd8ab9889c82f94f61a0e6842219a0f39e +c7b232cbf802c4a744f33159432e827006c7ca77e480a48a9b0e6a876158 +8a3102e3f98a77bbd62a3a23150fd140d3941773bf7cbba2338ff37b9eb6 +40558a2313e8824e8e620331568a9b76f4897198a709f9313f4ac40827d8 +c3a71f2abff02bfd57d30d0b14012fb5c39b85af540dda0adc27a85b3169 +4e8d7b61f9d9b476571022d98f2d768246550a877293f3ff6ed918a498d6 +a600223e1a61890c49acfb60265867ce9464f9c32c59e94f7641c3873fb4 +fa6eb237f8ed94579957270d6fd640bd9543e683f2372ccd7b60aad269e0 +3a72c5cdb732b128818d41a6ddd2bc139f7d3911f48e1b1d263dd4ae8e4c +e1a686f3a00a2cbf48978631cd243566e22e68f8d7397134a3530ea3745e +4f1eacb4d6a5fd84c3011094f37573f7f9902305020c53926716d4780c6b +0a257bf711ad94c83f1d41a02c1c7dd203a3e6e4b14eda2fdbb36b063a3e +074495f626b0eea146d22ac33457f44f416759676d2a0566ec2b726d2f05 +40abf225339f02f406d4e7a62e5233ddf20ae7c86ca0cdd561f33c422654 +bf2dc3685ca91bb9d4b09ac8b15a24a99ff56e2894f11f7bb4728fe8f0f5 +b799f74f475d2d01f61b7e9e0e541f7feb8a557486d7df2ce50927515d83 +3bcaa1cd9bf7a650bee9e003a5951c98ed147c4c52f64f692ab281984ee6 +5a47e44a4a5fa93d6f18d276d3b01c5e5f6135ac6940524cd713df4077fb +4943e8ac927a68489ea52acf7a854393cd027eb52ea2dc6234ef034f3dc7 +42d6db5a67fc21d22b97146b9c268ba97c30161ce01edc69a6a1f05efb0e +06f22644e1a368f0e2c0c6c1c832878e0614b74bd645f5cb293cfdb7618b +837fff14a1210aa061c8c81867244305b80daa73cb25a417228e9559e7bd +52c119b0ccdb7c4dce7e1b9f7e8ebbcb575e5bd213bdd6db88769dacb05e +5870232f0ef82f448559187423409eef756ba6247493be24cb1879b5dd82 +2e03d0adea1edbdd83d3fc46759c679b921f0616f27212903f728ab44c17 +84e8a7dced0df5625a7d3f48a20fca34008184cecd145ccd98e31b79e174 +cf107e8f35c40c19d86b40baee6164353408801edf75a619ffc5b6faf3f3 +a95f64795cc40c1f89634fd8c13852d265fbcef834c800ab46e3e8167476 +b23cdd8aff6e2f997c99a86a9cb30ef8c853154d0d89eee9b9cdc1b4f27b +da32432a4173b55ca8d9fb50acb2d886ad8e5862ffd5dff224ba13c8b8a5 +4a7f1a9f987fbbdbc5a3c3d762a5be309d5d926ae5093c40aa47b3b1bd82 +8797cbb9bc9fec9d19eea73d2a39764816113a8edc6cfa6e605ad578fc8e +30abd600658a49abcd5ac54655d29c50fdb72070169d1b389f114b7c71ef +95a80d82ab537ac8c165d47371fc142a51625029a990a577eb1618480d72 +6da93c98e5c5f24f622a850cdd94badaea91d4bc32cd50ce69e9f00e77de +a8ec1d37916398fb7092402605359df08afe7b99c76c2a7c70383f28a7c0 +00c696f45291bb8f074791798197caff1544c76ceea8c9e6d76edcbd92a8 +6df889481f3bbff0865442264f0ea40d3caa69ae467a08003f9c30ff7f2b +77e767580575398462d5b1171dd441d8986f33bc7bda17d413ebb6b7a326 +42e33f20b284bf3eded002352fc66c6f7741a542155f4a159cd778be56b9 +492cd95115c1a06189a216cfd2e6725965a13de973765a05114d9a5a4be0 +615af8bf6a5eaff84468b849954d15beae1cdd57c435788b331905c01421 +b50f20b184506a0bef746330bc98e9c89aaa8f9d102f158043beb6a68205 +9a1c8b8cf67b2f3d7af4d8bbe086254cde53765e3226ba2f95ae8063649f +9f94bd9519411daf8a0287307335668190638806e29484a4ffbc1e46b180 +0e03b162c23b1dc0b4c0dd3c7abed2f00762972ef06eeb9bcdc7b3f39c70 +be32789d366f073ac3280c273dff2979507671b3e1e7685a9a4f0fd3867f +96dd675bf05f25ed986a79249b75f182fd73cda2a6a66d693e4cc5afe340 +2431b2c816da1486c34bc9dca4e2d51c868688a7787cd10abb9aca14b718 +1369de89913cd8fab58fc84519ea2aa14e54b7a8ce474f213e07cf2de2e8 +88093deec937526816b71c96ed75fa9e2edc0f9e6e84569c12bb8e39aaed +bf546630745553d6084ff9524fec6a7264f88ceb7ec3358e923b392474e3 +a48865564431662988fea768ce555ab0da48bd526a84b0cb17b4584066c1 +640c1023d91f7869ef0c4d701be121a6e3c832010427490758aed7a2b30d +6028f2215aa44e86d852fdc67da5ccba79eea863bac9edc2535b66ab0e54 +ec4d4411390fdeb8d1fbc1743f15c3b68dc92a8659e7a892d5e53872ea51 +ee8ca7ef51103e87c29a2714e907c79db9cf37441785d2f73a1ee5855011 +1a4d9bccbebf2e39cd3b93dca300fac3ed1add8215301e5766c30c8cf296 +75746c5a77bf1fe3cd75d25cf193de8d9af02af8f7a6e8f84b548058cdd3 +c6998ed13463fade739126d83d3ce2c7201f955382832e32c10dcbcca358 +35985b9a93f8e3b0208be6e92428787c47d3808a0f77b8f1d76e6bf6a17f +f81cdb065180e03809d03638307bd7bf5cedbf64904e918fc805ac905379 +928b816480f6e3bdee47042cba98539da0e113b1a5f23eaf1a3210bd1856 +1985e6436eab90395da477c7a6d7888d2377b3fc4169368357d880ce041e +1f7c875e956600db7d9b35d1ee66be476e9dd8064cc02230276829c2c0a0 +98f051502e828a0cc505afd8c3df293da1508ac4d25866beee6bbd5a230e +9c2dcdd4f06883936381f476ddcd86ccfe15c2ce3c3243e148cbe603b851 +3a7ce7a6910a66a90b7089e5ccd4368befff2bcf8e918bfe0a1b069ab2a9 +14ca7bb91a0ac3b3c0b060fa1a0316f6135e890ee549315897c8464496cc +6dea0f7e3af43ffa4c3281156067582ca255b1d2e80f999a3ac0402bbd17 +01824c3bb524130f5b82a45275807bc2f3a0655ea208f968b297f98c3691 +92c8aca26beba7dc4506fbd1305e2efa4dbe5375281a88ee2d6fc88fc0a7 +55e72934b4b58f6dd3bdaf7171a4a3c7765767352492bfa9a7758504750a +b7f38754683b70e9e293cb1cd7b23ba62bd7397abb84d7edb22ef6c3f58b +3eeaf656e361747ed04020163253d1cf3f905b5e85f83fff30ab2778cae4 +3781667c0f65c8fd404d6b9202a99ea76af9ae1236631550b66b06384718 +0b6dca832ea8dc4a6efdb674b5a26552a7c7d54c2799c7d4e03c24f661a9 +1103086de3a90a774a6988347656344cfba06065ab22476bb09fb68f9928 +c0045f2764af643cfef0516d87fde6dbf93bae2829b176cb507bb99835e0 +1bad5e55c2f8798c93fa35eb3fef02cfa31d3d21b030547f86d27b9448d6 +8e2b155a65c742bd2999daa0c3aed64447b9cc67f7af33b63afaf25f3cf7 +ef86657fe8f952288ca4b691d369e8f1935cda44a180a6767560c2ed3f2f +cc38b6bd7991d4170c7c566d690a8a25be03212a80871108d18cceff2466 +23e653107631f29227d64754b2208d19f84e547799e691ca473780ddd56a +e620cd953d5133d135e3d51f237078feebb7371454ee633cfe238aea63f9 +999e32850e6c197687a0ec4e5908d2a18c5349627e336ab5e3185b218228 +603a4b1852069f5ee849d571b8387dce1f8f8e9fe94fadef128ba83bdd24 +5f8c1c27c11f2ed1a8ab2d6d601726842cee744ee7aac6b6fa16ccaa39db +f5b3b1d47339f31dfa562671a9cf7dde6915fef9f19b3e068a464dd350a3 +ad146d1a241673b5112a4a8768f976723e6e184790c0604506c46591bef2 +106c40789b733331a80740d59abed39868f80becc2aa21c400a0bd0cc326 +d186fff9eb37680f1edc32ac78f9059280d07b5ff2e354fed545129fa5fa +8f3d4317ff21e027602fdb2522f049bb545ff4da60248130f81f4e348373 +142f3148ded038afba818f26d5b49fc02de9800d894e9239c88ee0ede431 +f8083697cb0be3b497473473e5714717c914a1a926730c249413fea2615e +f72bdb0906933387a892370f77eebf62d26cd583ee643b02e323821379c0 +dc966407d36ae3cdf646b95dedc7d7fd0f28e95078f12dfc0d6400b327b7 +43c548a0a3517a175a7ed963ed756b1e107ae7087e2446ba702cd4e26e2d +cdc1a8b697108b5b5e81e9f03105f220c72d4aebc57665887c8c7964089f +be9424120efdb14d76eef8c6f7a30b13e1ae90cb9d93d2e14bde47f4a1d0 +5ed5b18d32aa39911b92d24c93976aceb7ef597a75161923a73b2cc76178 +5493d0eedc08b5afe95f3c006b41438a0785c962b070de2bd096cb63b847 +c87539880aa3d3fc5c345e0992d7be77c6cff4948617fdda784cc5565219 +2b0ed775129c4ea4245a41bcf3875be319da0ee2dafefae920cd2b6c6c20 +01762f88c0c5c05053025c0349db17104360fce15d7f3a8e30ed13155a74 +faf91dc77b8aabdd6fbd5a1eaf255db209d7f2b90822296b5603fb5e2cc9 +5cbc5f7a6044058b8044adce73acfd896177f1f70ead2f6534dc3ad755ab +2ba87126d63ca2e9c441df0965bddd6be494e58d6b5057a561d1e31bd38e +92cb73c1465af6b9c001f7229059bca4104847d1639e124e082f7364b565 +48bf8112d0eb461b316b2449049f6a476d36d6b7c0c1126c08f2e9a1246a +3b5b21e7c8fac6e23b82e33a7783e4f31f0240e96e69c9444e7d7a928636 +cfd086475df1e0a2846481387bb2010655b9f81a0744121699b4905aaedc +c84bc5d5ab3674601dbbb651ede7b5df05c8a463dab41f79706d285c4f90 +63997f7ac8cef35cad51fbe5f5bb1b3fa6da2c3abf2b3e925581349728d6 +da0d59c1ef6444539742ee9a23a5727f20cf9377f4f84dea420607015a30 +fb14632d084a2dd181bb02fc3a84fc499b318156b675b9ca3ccabd87fdb2 +497c6705fa70eba43addb6cf961b30e8f6ab9f84e1dd8d6db3314b34b7f7 +aa3bbe19d5bdc75ecadfd8eae19e07b387a1fc586f0f30db695926764b54 +0d89f1d854b0ff86528ad9523caf56371e29498c11afb2f4d5202670c834 +e930103f039d1334882416a49bf93b84fd3cf1209eef7d4994c8302436c0 +794497461c11f5b8ba152bacbcc08af8a15f4a4df3effb7227ca97fc21d2 +d0356c93390c749cbe9750b821f1a7bcfae2c8bc6d9a27f844d8ad088320 +79abf0ead8ecd4ea72846dfeed021857f33c1ace4c07bec90398b629814c +498d33beb375b9a53da0f926fe6e89e70322c72cb2ddbfb16b13ef7a4f50 +df783316584c6ac2bd7d9029124933133b2229bf74a228868ab30ea5c3e8 +7c78c3f0962199480dbcadbef53bdde45849da857a4fd85b96682f1edeb8 +5384929dee4afaf84c51a09f5d572705673d885070303fdb47dc898f874e +103a9e7c1e894115dfddad81549c7375d4aedcce2e52c13e5130b47f206f +7c5afaf1f9ee83da8188d70b473269ca280a6a02de85300b93d8a4f6b402 +fb5df58f1327470ce11cc63ecef2efaa396a6680a6746a20382d9529b58e +7ce684b39ac00f7086bcb47c2230df0343bed9b9152a61c9826aef9e00a1 +452d91305cf05490d4bc0badc9c6fcbfa93fad52c3a80705a19568904975 +57c0873ebdcf61ccdd2219354a4f5621ab33b11932065c1d990a9b688583 +31ee7875cac855f98563b14ef9e1060bea90f195afff94728ae935453438 +dab35123d0e2699475884ddafc7307a5cc06920f35341728d85965f5ba86 +f261cffcb1e29b429f976970d42d10e6af6c4b792b4384122aef2448e22a +58d3aa007743c71324ea08d06819fed14ac1f22a4f0be4787bc8738e1cef +240677571c65804ed3e748d72e89c94b6f310be748faea31ee246859caf7 +a1ea17ccb5b246c87eab771e2ac5d378650191081514ddc2c66878e3766c +b20dc49f630f2743a7faecbe9dbe9e815a3cb57dadf2bff5ef2fce23a562 +98a30a2e052feaefbd698101f9db992613706693cb0efaf6f60c8bb5e7d0 +a50b3392b9831ef3a304a846cd4af431e9f018fcd3a5b16387552d55daea +683d36257418aaa0e7bf8a03ed7bab114d7c15119e6c71c1946bd7903c1c +42e115e954619051b853bf05ae316e15e619a7dee498f771e809d9435969 +c1056402725ef40c0200e083f3ec6e0ec27b8ed38dfe32ea0e5e156ac36c +4bb9ac5ed111a11678339703f1b9299345aeb1f251fcefa11fb3101cc499 +907dc862b4463d5523b9b25c5b69f70ab6b29cfc1df1ecab8227eb3ed1f8 +82e90b12080ee003714d403ec43b7b54491446b6a3dd6eb641efbfef060c +45e873e7398025b1cb7065441f1753028f6f8c49a96801c0d598e098eadc +96a21117f817b6fd6e6947642f93e22425a00e8f6b592ad50b317b69c0f9 +4047386a45e5ebc9504fe55451a01eb29ddf9a41d4bad85fc84ce280971e +834f06cef49c8c20ed2ceac889f158cb14a8c070900478804cff1d1637cc +880c81aa287d8382837ffa8f41ff3c9df2f22cb20044c171e4815d0d0f6c +22d19a52114e780cecd71daf63427782e85e463dcb333789f496340e8cff +885a9d9a4250118b439c71c6be51a9338be29251aa794edc67deec6337fa +63ca9b03c1c9f75e733a4a918646e7bc9792486cb5a4bcc5f84fbabdfe33 +8c3792254a3eea3d88903c2c47b91e076259dccc8bd3dca90eccc832c09c +45141c6242026bfe309029a562c3ee0fccdcd40e5cf265ed9c3de582884e +0e14819db98b3af734b1b3276ac41d43384ebe73003d15ce39ffcc041095 +83390e470f431b4407f98550e138f96c4564b494e5480f47c853bdd237e2 +7301f55e42a3bed18fada152572b7b465a581dbfe7db2619365cf16d71bf +8f091862b9fcf04bf8d0859a76f46e7b5712f2757edce332d3213b8a30ac +2ce7d7797eef6f30904906b0805dfa7ca36d32a20d989858497a66ce7249 +1393dd79332003d55c095a5ab5df761c4be5c041fa8407263d604e53091f +7b6b15496245dbbee96a63f10fc2978d99e6573128689366fe8b0bada48b +50185b861bad03e3600f22bad4274f2542b635f6c7944befc3bc741bdef1 +1a8dd659038cb40fef2e16ad1ae7ebedb7d9ba15fdcf26355331505a386d +d7399fb999535d6061eabc61dd76ef3eb457446f29d0bb6ec2fc0aabac20 +b27a3c123c27bc27a76336d0a0a6d456da0703674d959a4afe428e2206a5 +11bfc80039ecd56e75f69786da0a8084d81a66644dd98b6018681f1d70ad +e09bd9bf3d16d68dd5d0a03ae26dcf1552549e459fe190b310a8776b2c84 +68c14ca8b1b9a7af2956507a3b705ad75a17a0eea7fe089273353cecd07b +b8563465ec8deca0eb42f43fe3664eb5f31e1d1324185539b28d508bcd06 +5ed576d8814ed3fd637d576f027927162344afb0255a91ffc616948e4e35 +8867e9fc76a9affacaebffe110808c1532a2bbb0dbef3f010e45ffc73f22 +8d28f12e98478b27397d8f456781ed9e19711df2e9eecbc3fe61f7493fdf +1a59124668a91be51f122f93dca4bbd22deea339e6eda3d6ebee03df9581 +13e1ca49c8398d2c59da6764882ee3663f62a55ae50a7e91b4fead1b11fe +0d50accc5d75f1a515f0c53616a500f1491381dfd0e2477e402ab0cf9f67 +d501a442629c8593ed5d25a72edb9746b02f2b0f0759cc9cdcb4c9d8b451 +9c8c617e569b432f0cf6890372aa879ca7de46e110d95e230a4f0e52cf65 +811c54365df4a3e40d819e2fd379b47da3233d0def0efbce04ad8baa3888 +4f6a69fe5c373e38ae0fd0241480f2be7ccd18af85916d2703a049779fe7 +398fc47d348454cf03f22eb3fecc064606957898b5643464845445c25c0c +7d685c8db042af5d5882174374ace90081c686789bca96ac602eb41d317b +d652293ee628951875641661ec86a2c40a42e8f0813a861d41a0f5178e55 +43651ca0e99150462db5ee0010f00de6d55b0d7fd7ec5baea24ed3e90a7d +6a0589761922b91a6a913a7feddd3b68254d89ecf767ce8e27f966426a8b +4fb1b4085384fd09d63e288405b78a646f44c87eee22c8596b1318808547 +9f75f63d3d97a28f9c8306fd207dbfd38dedf0ffeb7dd80b2a3292dfbf1e +d605adf1b33e85b010309e3ec058fcd922b1325fee71eff2dbbc2e68db52 +d513e024c01d47cf657bb61c9734649a4ab63c0af4720ec3efcd82dd3ca6 +e80bb63bcf1b8de810a0c6c517c63b76fe68c0b286867be102424fc31c49 +37048b6f323d039618586fc21731005d949e7d802a430df8d2f0ce99f2a2 +376c2953efc4184355e4d12f422c9e1e25c4df38dea334dbc89b540e14c6 +1a7769d77115ce8968fb76b27d0863cea2496783114c24d4cc816da884d9 +53da3f9b9d3af8938bc607bf26a071956ca07e6a5509ea2f5d80e5cbeb98 +041b197fac760976ee75b470dc20aa023ba3f63c2876eb281ff5173bb490 +d6815604517aa1b1fa0631401b3c1a04ca103e2ca4eccd83874d9cfc8abc +134cc0f9141d9afa56848bf222342016c556c14b3482482dce5d0b6ef1ab +522aa1812bdd8dd3397e05327ec12748fc4808429b97202e24e1de0c7c0d +272c046ba73b37d30930c5de5a47d96955cb0f5ded8f3ad929a8b42d2839 +0458f5910a0f93610f79eddb27078943dfe17c716d65f96589769349f3b6 +6ab7b8c004ccc59ef6881f745ec7129865a76f9c2d029d4660ccfb4d5f9d +412ba3372a27cb175e9d65f759575cf14a5899a8d31ff039ac02dbd8391c +3397428ac0d5717c005200790785354813c8859be90e0e17914f6cb9c674 +f1e9a9648657b54e5e1f52756c4f982df74e73f6e4d40718c71d1d0e2420 +fb7462fec9e457c0414a96e475c6be2c10437096fca0c942e995a9ada789 +ab637b648781d32dfb68e62e91c2ce7e13680f8d31ecf8c824885fa76189 +81cd05fb335aa111b409c59ee337df4e5f9dcc920a5fc0d620dc07f20dad +63f4ff5e0ee5a2f390af1c32122ba7780f210229e5a5e3ed97bc1c3cdddd +456e739ca782edbf4b810552368e9c734b0c78b0b8e3f8b2dd782862b743 +18871bb1ef087828cc173d7b049811fcf598b8efde4d9bc5447f4848c980 +29c854f3ae461b9d46ddad8ce67a521f3c811a81a396cb0f80f3c8d8ec88 +30532fb7f9624f7cae0f8c6df875073333deb28aaa90aaf486ab8c932553 +ce697b885e71ec8e40c7835cd5d59a2c695db9e51216ff9b77a15b0da637 +17ff25b05b939e45cf7fbe490e51e9344213b32e115c2de14d76dfd58450 +88de645b0e75042a61d82fb1753c445ad0a956a1263e5a096b681d3bc51a +9ff32ebafff7eca8b59d40f0937eeff38312ae57462c7bf3b1fe24d2ba8d +fe84515270e09063ce3c80df4935e409f62eb4f54af16a186d4329972b9b +df15fb08461b688ed49928429226cad9f67c9d636d1375cbb7b08a563195 +6b7fe29cc9efa8d75c9e4919c8c2c54f401d2e0d7bfba40c50cae214d210 +c6f3ea5802339f63fc4c1c1995787617f3ec2c806ce44cf8e29f76606cd5 +836f6e5a2e423cd791becd3f112f25657dfed9366fc4adf90b685cce4a56 +98e5fe16d7542b913fbc01b288dd13f43db2b1ed8ccb80159dbdc90a8132 +125df8df547c4851ca609d1f6f4d647741260e845b457937787827a89e37 +cda06bb191669ac84b8608eae132d10177f3fc384980f3a6e439b048a38d +0d6b9cef09f3f2d732aa71bd058169d6d0f8c9d146d9da046774027559a8 +b3843f6116b418427e78476ad8f0f81e8a6b12098060ff7dd686503f972d +6c42fd6cc29c083ac3d72e3751f21d2e44a572eec80e81ee44c90faa7afa +bcd3eceb98fd4068f6c3a4ded0e6cec523c9a0054d1fc2a8d61a4a26f9bc +250b8f302416924ab22e722297888b85b9c12f8dfd2a744cbd143f9b2514 +c1cbe988d9cb4e77d90b2efd5c2a528355a35f7c4af039c7d1d756305967 +b847d4acbb81263d4992c001e2a262b9fee2d1f5022be5b15e1d8f1d67bc +52227344ee912c018cb73e5f47ced54fd202627777bb77aacf3ee6b22706 +fb2fa9062bee87e22cd2802e7706322648daa0c624ea885430175f746e1f +536f9a8e1c610c4a761d07248426db63c9319a88a3fa449c3fb8ac94c600 +3c745e6bad717a3b2ea3862d1e08512a98e57772a62f85f1e2ffba40e2ee +43aec11203da9ce5afbf673436f2db6af85bbe89d802f7a9e5fa25a408db +69e51f0577dd26f94cf2ba2fc53eddd6fbeb534af15f74f66ef8d14e7ff7 +7d8a5d284c8202dd5a6053ceaa606bf9259923825ef4effaa8d878652a4c +af2ee43ed26bf3590402686c876f86c1ae95046e527617cdd3c429bd4cc3 +f9654d2c76dd4102471ff746fa9fa379b16df96bfe3836d43fcc0b8e9512 +0c27370049aca4ac313e1d50d72d1814f2566b8b29fa9c9c20d048874372 +2a766436776783b939171fffa00e04805a8b58214d4f114f7b9c3c17ce74 +86aea2bcc895ecde809502bde57981318a93f23016f056a421b733c4590e +34ab08bb348da4a48f19b6befaa1ddd2a49a6c440443028333cdd48c85cd +698adaf3fd8676739e44400a98b575be02350576f96cfa54d4184ba47555 +b8d12374b86d038d085f7fa51ff4be2ff5981408999b48b2faf305212ed5 +4b2e371f5a0074cf68d1b0e5cd279bbc8bbaef694a89a6c43f518d01bb4e +8402aadf34e96e9b3fccab4cbea2741d3fd9adf7af32388f7771845af999 +65a6078f4da335efa436be36903e33a743c112c0267309f266dd44fa998c +9a139704e400b89dab952eecfe2ac09c82d9f4975371ccc27da37890ec84 +123193314d8a7a707c217ffc951a547ee5b6d1b7c8ed85bebd9d3f4b9b09 +6a78e5f7df88c931e3f396973974454e59340ca51dbfea1a00de084b6463 +0e26c6d6a3593b828814e27db0186bf2a87eef268aa1b135ac09b52cfe53 +051cbcc88cec5657bd47f603c8e1a6249161684fd9084ac279f57a4f9bbd +0a546a87e147b62ac860911969a29b8aa20e3aaad0079d64e6bf1b0f2ce8 +f0c54c9019207e1b403358253c2fa93a662f63b9380b65c5173c198d86a3 +d0dc1800d1f5378da39ce8523eb62c6afad8a0d7ad1629f2cecad82b8fde +38975303768c7d3a08b91478edb3c45a8c6b7725ea8596a8ed50b8355fb8 +52fb8966479d12e1086223b1e6523a65fba81dd106fe254f7309718768ab +009ff7714a8c363b09dda73cd3f81bf9c0cd3b0c806cf3b7bbfab73e46fa +cad2480eeba97ae68ec94d3d79aa01ecc22067858effa9d7b7f997abd2ce +5aaa8781e5499e8580c405681cc63eea53bb47e55ecc5ba2a7a3c5472df0 +34b022f455c60fff971b01583a29e211a87f7163187b190b0c1083d696b5 +86e9438fd8baa45101a5edcd1be5ab9a585511089ddac8df1b1fdbe582ab +d945e67f99adc4452988a9859e39c90ef794c5c4e62997085b7a16a0d901 +07d08610ba175ad66377345662da7da4d8fef847ee5d57e3ac54b928a095 +7cc1c944e7ff14658fe4a641cd26c61105c0f136a75950764b69ca17509e +3c19351d456b22c87c55e8dcc4acd3e150d936333ff36499ad6b02b6403d +e0f12901301ecb2eba10324ba72b58206a13b8f37b0aeb12115d0c12879c +8ea8a2eb70e85c95434564ba3dff481c8972587eff74eebbbab14fb32b8a +84b8fc42ebeca65d25e8c32c19ca5962832bf45dfda4e871508aec318495 +0d6dbe89019cea29e40484c36e33d76b756255531add1db24c03b2a64a47 +bd8fba3fdcb1f5b96f8eecb60d5834ab001a70740498720afb6ec03445cc +35b51f7987109618c6c78cbe3041bedc69b6fb128142cec5c8683b558afe +3024eff7a12d04ef59a72e156df11d33aba08a8eeb16259dd9529cd003ad +4ef4137b6ff1654236473dfb93f597331a5e26c7796f528f65c94fe07b3b +4f4dd49034fa0cc189dfcdff70c2f1c6d3df30ae103e2ac5cff20664ab93 +4ce5c19693292071c93bd590383e0a1931e04d1ddd18071dafb628f5d747 +2e457bf81d6064edfa8debff91701c5038cb30865d6122076a336732dbcd +b0a625548773d0013648a76f07bbdc9c16284d158ec7a105ae37a6227941 +9c3a2f360d0c7a74d6fdd0e36dca2a8bd59945a4196598f690878f84c894 +852c1811afea4be3b9f6a5219e6628c66669dbd8fa9a0cfc2dde7716a356 +fc4fb271d8a2cddc8d4684de447355bc7a287dc56852a638c5777826eb6e +b72faccc86f80beddd0d649a883cfeef4d74750172a90b5dd8252592fcfe +19ffaad868e99562daeae70514f5de296ef7b57e6f193737abb6aa317956 +584423817e11664a67389197ad9f8f771ea5955198c9ee40a0761639e638 +ce9d890df468642670235f1373d3ac6b1f43b5777fc0a91a96e095e89bb9 +fd62614de456ce7afd6b855112367573fd9fcbbd4a4f9c676e672d62ddd3 +4a9bfe8311b6175a003cd143c0df15e4c0b48c735404086e48aeed6b6fa2 +1fd9f40b84215dff287f0677904e2ddfda774a4019df45cc877f553e95a1 +c65df1d67bc0c60e0bba4d205c0da3da80229fdd71859f65ad04506b308c +2b783839f31cfe4425263224f08c5c7e98a2c9d3dc8ea5ac1920f4e39541 +3262e0836bc019a092a0deca104eb2df6b63392ae8e2136379140de5fc98 +b0b69860fe8e31dab5c5df7807d19bea34ac14e0abc6f6519c51247b104d +e7d912c5bf6ef11b48fc6df84512e9f5febb48f72ff1b722bdc3bb2e835b +2e7cc6324bee84893996b8dc2d4dc2793a4f69c18e63daf04a7bb5c0a907 +6e2d5a343e134cc3c89c4712900656ffc202e1988526d80c7fd9281fe47f +ba8ab5d025e63a84051f6b13167bec15b346212cbd051afe7a98be3a2491 +f3c469718a58e783ed91f90e274fb4978f8719e92a99a1e8f142ea7e1f2c +46aff0a2fb50f4d105130ce8ea309b0e480dc8f80d506172b609ea4bb4e2 +bbae98d8882814fb273e690da990b60a9cda20a2418246bd10ae67d846a0 +fa815ac25858145adda106a6778a11877fe59a2abe300d7db9bbab31cb5b +960b7e4ef91d4600886d8795dc361cbdddde05ebd54b1941f426f7fa8399 +270d2f54c998be92d146227270a8e89af90c48bafc4eccca01e6322afc16 +5743475e752f39bdaec49297290510ffa264342a0afe2985f85deec66c36 +eb4a1d46683ee7c591a89b81569a8566afbca26810ddb0970577a76ec8a0 +66622606b08315db0f2e6c671f3259c73637d773d1a180aad66adada2a65 +95b5f481e5f59e51cba876fa06d21e1d674cfab46a02d267e20234324d08 +91e7847c13c69bfceea3ac55f2eaf753726bceb0de1eecf42ada964bf9e4 +75953302c2fca804b70b779482dc9319b40381e09c0096460ae113c19a2d +c9157fa138cf0e7758f71008e71d0f7599744d647b09b16e3c795c56ee5b +d14d8d63e7a512900d67487975ec9ceaef69572fc3c2342ac5d365e8a4bc +f462006b5268ecc1575494cad9a9e7a9e8d9affe49af647c017743ec7cfd +5e66f4e4d845a6bbc836849274fbd270cbf263f167df7e26ba91f21c60f9 +6257c07523ac37a2193010e976965cbd75751e312817c0564e1c5ae0cba8 +bd12b01122d07020a0852120680985a8ac987bc33be863eec52af13435b6 +e4048d951f5bce36526e07a8661cf2538f69d1f223bc53bf5896437d1bd4 +6f57d9698f642f0e99c7392d8ee47134e34dce94d392949b418d9821e12c +afa8337323e8469dac24dadc6aad4a0dadd7ff65694ba3a27964d28d8eb4 +1179458f91cd3f83b8f119bf5e76184dd29cc4c0718cf7945dcecc993a7a +78739363136cec7f2fb495eea8cedb3ebf14373a058758c442939d367744 +35554851e9519b6f09c31ef26b6cd997dafa11da91fa9759f17b7079164c +5b47b99ccb7a876fbab1d0d5d1e1a2683cd6914e6b3b755939cef1c9168d +30b2738c4349650cf86c90d2542fc9b90f36a494c035a1c86dd716014aa1 +6e6b9ec7aa03b16554bec436511dd3097fab1fd0cd49edab96f74e8fd264 +00fc748cbd9ee1eeaee24da30db6f8734b52818b3a5e510aa5c14e420608 +98033e7e36cba9a64042cf94a74e4b52e37ac027c0dc69bac4944cce12e7 +ad81aedce642ec34ca23e3ff07b8cd35dff19f33c8d4dbb56a52534f8a82 +7be47ad4aedcad83b27338409fd1101c4dff3f12d3df79ad1fce65b2f419 +451dd059c88bf066413e23de27d3621dac2dcc8f9f3620dad0f4b1a6e8c9 +e6e8adb552e1eb2c4b2a3b73986ad53ed9ed8911f82f750df05cd2eba3e1 +b0df208a87fb5ed44c3296b803881c1d9776d13350cd29c3f716f0b5a8b8 +557812024ba70069be6589aa579eadb1f657712df2570843d7c5ff7f4009 +d4d232d3547dc8b92ed5c4db77b76255e661ff8b163c6f3856de5651b597 +ec7c78b84f0c6c1d6ea3a82286f1d3bb45f708d564e139e81f473c705ab2 +56346328daa64d1ea8645dc10fd449092e0634d9d7344b2aec3c75f6b6cd +8b3f3867ff3cbb0f556b186ee9a7c26bd2d17c8a773055d9d5013bd2f937 +d697a770c57bdb36d922cb911cd14e7fa14160be19c1a052e297b1a2d682 +d4bbc9f1d2493bcd7cad2fa75d904c5f5479179daf7dc6a4e0d269baca2c +4f2430b4c8cf1572fbdc750a05dcd5b09fa3a9cd6f2f2a386e2b3d4d8e25 +7bd43a783b38e63bcee503ea96ff2c373181744a607f0cb8d281d7db1a6f +4076aa3e2c61914bd796ef8a0873f79f964fde28b792ba99a20c3f1f5ed1 +fd189fb1867c84dcd6af43d49420c8b1f3dce7dbae71deb17fe45644db24 +4f44b1011c7c768ebb7254f4daca64e9ba87aa7cd0f0c4b2228ffb9ebdcf +3dde4dced39399ffeb348811547d025320a88b480943a339e2cd2fa3605a +aae87939b1d7901465a1879bcb4c5be1a179e7e371f1ba2e0844f88afbae +9b78dcca47ae8aedf5bd3d458c7d4a7a08accbf880d1f1dc69c636628df1 +ebdc5c42ff88ff8b66351f3f72d703e52f3ce91e4e00759753a599fdd863 +788e99858498b66b93e5083bc3501c39a9ba928b0d763c28826fd237e949 +ef0ba85cca9aa20c405db6d5612db718f7b4ad31d253ae306e4d7cb615c5 +9ae668d347a4e60fff7b103f8bd0e7cbdb142a763be88ab40eef6b8fc200 +458d728930ad0f94fe52acbf0657c4907cc7942710ab1fd8bd149a9c9def +6b8dca7db9062aa7b1b011abb5aae8b77893a023f9eeeed4a20fbc30f922 +282a7ae2f1acff64151013d6b8ac2eaae58171a10f80bc18c3bbb5de1e22 +ebe6033bf83040629023d74ccbab3f1923cfa4a6735e1dfa8a1b261fbf1c +397e26f3ba9c2629cfda84dfa3d1087ebb19dda7e2d76e30dc2e15b8821d +5291da1dfd73940e5560a8a6dc91be0075e3ed8d9e8cac85ac20768d868c +d2dc45deadcc8b59aabe6ee5b2f891e0d7cbae820f83479332bf97074866 +98fe196c72ef72b52f54314329fc498171782bf160e1110a19b8208fc591 +ef0f0da71af657b43a7cc649a8488b759f7b69134b4f9dcf79daebc1ce52 +cc8015f324c9d46320f44e1551eda6d86139dfd1db814cf38a22a89fabb4 +f75fb896b00e769820f763486e86668253cc466c1529a5a924cc337c4844 +8851a381dcef63a0a302b65203d6571a1dd1fb9dc0c3bd6aef4891497033 +109ceb5a481bfe442249940ec54096f1d0f2436d9e60495d0acff967a741 +b30467d24ac6b003221318666b951efd45324987b10bef4aaa0ff1df6887 +377a7f70f555dfb9ff1001c67438a167a00b05d2c37065655173a7ed9ae3 +42dfa1497fb1f2fed6098901249a085d31b66dbb6ac25ef16c106b0a6ff3 +47cdf66434dc3f0012daade80b942d522cd59af4c31c1c062157b3d000b9 +cb86e2aa7b4a5bf316058a0d5a148eaa2c67977faa0966e4c3454e08df14 +c2498ad76e389af65d2c139a6d8675298c46aceb7dbe6904c373c06e5f71 +399b2eda0b40ab96e8be991ddc39f92f1d24797f9ec9f2fae25669b43754 +e2498e8ea5c44b176c3fb3e8f7a7a1481275a461f2549afc4cc73e28417b +d8c5212c13105eab967daa679ae822b9b75b372a99c7e82d6bd83aa2ba00 +314da4ac51b9caa30d80507505be24bad0a87c5d5d7336edf60cca4cec82 +01d243c3932f74d171e2409d789aad0d04a7bb22fb6dc3ab92ae33ffea89 +7c484d741039f38c317ea396a0fbb9f15a27d87fcbe007558799bab73212 +b6e5faf2080ba074724eac87d88166dbc1464cf5d41b99428851ff1d9924 +6944511cf42c3f9248513e9e51593f253d89c604388ad7132d6a169e9dd8 +88e020ac1f8ba606f2e1ebb97977e505d8c40853653d8f398f71cc9f8f9c +540c22a1e6195ba578ae7262fc845fccf77b33f33eef266489af8b81a615 +d6a13464bca58bec16c23f31d678f14a938bec31272dac3ccb1b2dae577a +26bed852fc59843176a5fcfcfa0ab7fb00d2309de55c82cb9049f44fa61f +1e313205a76317c4cf529a4456019d970624129681f46a9cd7950b8b5c40 +61853040113c8115319e68b37f88d864c6957df813b305d09e6a1716b10f +26f2ef5c727fc77aabba73e12b5ae6416ab19f6563ce14046b715bd4cb2b +1e4d315f42d10f74cdede82bcdd524a1a54609219084cf1cdabfe72cc837 +5478b41614bc18a914903596d6fc2f361ee519f875385f4ecb50f7053127 +4ebdeb14a5dbd906a60817246042e3799bb3ac647cda7244b7998ae4f3bf +be5c767fd2142e48518a4217599e0ec2cf5e86c8c270ff8b02f949ee001d +6a439bcb4bc7d7f7c8167c3ae0a7e59687fb8bf6f37beaa164541b8eafd9 +2e9d152e3fd0f413c99ccc34fcd8aa455a0b55dec846a5874b94fc95cff1 +bb386b2a1e22cd1c3914264b6d5bd1746972857c9235052d77a6c0dd3019 +f8a307fbee63a3ef12b039b224108276ffa84021f1ac5b745c54690b3ff5 +87b4b1710ac3533a67bcefc503adf1f4b62b2910b31965e364eec9cc437c +c40181a7320cd52be9c546b8f1dc824312216c2fd8232e2bb8d40ee2e314 +54c09772a387f9520e331456c269f51a078e6abd9fb6a68bfd5f557215b0 +bbd2227b8959cbd1bd4aeeab094dd18e891c61fb00933c0a0d76174d169c +0b6445d34c00dc9e06d85eb086c18f3be27df734ebb9cf078aff65144385 +49cbe92a0c0d25efe4a527d86f158b4e9d8870c7ac5d6c059643a3298079 +cc20398324ca87273b86ed801057d797d91bc3cf2f96c650ee1566cd3cf8 +656cc577d38b830201be718dc9a494268177a5019546eeedbf101996be59 +3631654b638c75a6baa648cd1e7aa9ac1ea60f4cd604071c89dccff8b3e4 +30a57ed6de11c5837e78956ed991058f3646219beae94e4d9381a33d48ca +9b8ff12b54a73ff869d0eeed7e098d80152295e6016cdd809173c57d1f5f +ce908a37010ad4c4471a53451de9b4363b63437c374c598f548f145d3d28 +8f42531fcf36a9cdf72521f1c0868fceeeb1857ea983f6b75ce245d875be +ad1bcb8819e5464518e04717b78bd6e335f0ad77b832af5682062a1e2ac7 +7cd5edd5dc372ee456c96d38bf8bf348dac2b4ebbb2440f2ce97b4b337f2 +e23247e3e8423bfa9237ca6ceb6fb93f960cad894a96f0371168a3322205 +2de9b3be04b022ab95c0c243486e35197721fc55311dc55f87bc72d09b6c +940ca36e6640aeb66c394a5949a604e7f15dce3a008bb41b0eef2840a357 +f348443b4dce064b4c15e5ec52e448c985faa1c3d6526270b1cc69100995 +9a7620c9a6202619a19be410ff7bd535a8b2640aaa459dfdcb8f2bb35112 +626497e8a397d4f9e04788322a738dc8907cb64315cf63c95809e90d06ef +02f72ab04aa61fe02eccf7e9049ff9f3ef2258a75656178aaac9f3c2a26c +001341862d526cc14e92a81bd63502f959066e0bcd659cb9b5a45606153d +d77039b8c5d5b13565f00d95a41937cf97089f3938e39659a64dc3d6046d +0e9ef66544caf8a206635df49926a3eef3fdbc9dccea2886ec855f1821c4 +b9ce1d02a19a11bbbef43a7d4d536715548a62802f64af30bbcbea8c7e55 +ad56c801d8a569c8183615a78cd393ca42c103f155941e845712c335f4ac +fc7807202b92a983111aed241bbb8501f15560e8f2157c29752bdcdb2740 +08137277920053d6d7dcdc626a574a82a8a34f1e77b2fc8cf7c1a7322f22 +dfcb450259eb450c52b70df3584a7c54c813db41e3dd81253a03b02bc252 +346af0160716355797b6f8210c453dd7e1e756ff08c7e6a5f4f87605e1df +f35a130d79148a57b7ad12d94a129fe3f055cf974eba09a2b13deeca2e02 +ea818a58b81e8743004646c7746110bc61b86adf2d5d8c45a6a5461eb344 +97fccd09e711f47bfa742c73f87b257b53f30cb68d151424dc3c210d3e8a +c67c2495a8236ea2d7985a5e1deac699d7b700e6d38eee2e93b191baa5a8 +a2c916d206c63fe63427aaafed2b5784276fc21eeff2d70e47c8540dccc3 +e00134642b703795cd3702631ae2a90e063a218b61e5b89bbcfff84f567e +37a31a9b349717a8cdb9c9377215ba838ff7469bc486b64ef2b6d92519c0 +bf0826e3652903f40e400689f5749df86fe3de178e21e20edf9053081f65 +10d8f19acd021cba481c484d30ead3b84ed0190087ee478a17154b243346 +c3938fdd5340cf6e47b185e64abdf44f8cbcdb8294492b91929bfeb9da2b +033c3acee554f0f1a7f8a56df7c06a3583c1e9c5ca458d40e550fdf3e2f2 +e7be8312d5fee98543388edc8a04ca29f1b82b7ab4adabba3f2c331eff35 +21b2b92f99c4377ab827a989b423750d36addd2e286e7f3b694e29b8bc40 +3693c6f7cab5fe34f1e48c8d41b47831e8c3f5be5ed5142e3c44acf5180c +d41fda149b1f4aed36812e42bc184227f5034220f74f67830255e1caec12 +66defa358a87d2e3b4b4e7ef30181570d0b2b43072ee0311c2c157d32ee2 +bea8ea4251b59f6b61d2b4fdeb654deb67aa3dff4ad65b727f0d6b7d6152 +3e4b44d99ba5cd33540f340a35ddd466abea4e72e504fc9baae51d231c33 +a8ce7dc2970de4c1fb5b096a3d9c641ef77dc9039886831ddd01c4f21e6e +168e38bbdda5f4308c959c7bbf36a42d042da6862937eb20d4fa2e592774 +1a58da5cbffd9553beffbd92e6d64871d8b25d9049f4e71970a8ff5557d1 +de83dd24286d6c3e4770ee00f9a1a0b0063c99994aec75e84d6f9c488434 +d1f3dcfd0a8bee9ed8257ca97e75e8b1285747184d6d2228ef95d4a0b8da +252318abd35c8398fc6568b294d90ab308a7675f9f160140f0a08c88ad0c +a1ca2cf85e4d031cfa3b87635f1398eb7dbc666a259f02db6741d13e11b2 +30025dd6dd64c438409af109090058151e4dfb8c0e9cd65935c4cc063cc6 +100fde70896e23e3661c7fc1b8228b26a55903e997f80207edd8863fa074 +ee4ff23be585baf708040c9f8cfdeb42fb8eb71d4cb6d7757e973e4d8c9d +dd082712c23f868e1135ecd91250bb4335958b07c12fda75eeb56be19d16 +44c1f76a8811c021122619f751cbbfeb1d3dc912999017fa163672a1ef75 +4c5cb78962baab76ec48461b492fa88f9897170de857cc8374c8bae417d4 +c78a56047024731f4a45145f0393a27cab614a7ff747bbc28e6880d4d01c +0a6cf317a1de5bb5adfa4b5fbfe0c57598c79f25ae57bb797a489d51f85a +9b9cf8bea64293f8fcc43b0d5484df99dbe19152692ce756f6fbe8ce5831 +cf4b8a5af47524e272c45c62acbfbdfe7e60b05bb1a1a6af0e9210012014 +69b3dbb49ec7b23a363fa68417b7118dcea71d4aca2e36f88c6ddefb7020 +5df3ab7c74cf65cfd01ff85faf99f172689737331d4c6cff7a29029772f4 +87fbf625f17bdad89b4ac076948277b4ed687840301016c2b7ad4c6d02f8 +1e88c75b7a04d724e234e38a38269351582245e361a42c75b8256afd5624 +b558ada2190f960a896bbae7a8c57e76da10dc29e69bbf3aa86214c001a2 +7b39c1d17c548da5601e86a5cf53e7b1896bf003aae9387aba9b102eb1e9 +002dd3754a378f3e49f2c6eecf47eb1bac2cfce11ac0c5cb063672d32733 +563f3e1e891b6073739bc53aaa0043fc45e90e413dfbd4548dd320b681ed +70a7443a233d79e3f038d26975586e5cdd2115aa614727b1f6dd4024b85c +ccfc79d10b7b6afa789db37bd0e8c423c1a4a8681b5ff3a9fa1f61a46e46 +c4b1836d1aa41a89264a7f4b1c259e4b10ecdf375bd26a1f412fe01fbdc0 +3368fcaf48aa0ec28b1bd603a6a0d0dade66d14c9b7285569230fab76803 +35be104305e4b748fa99fa31f23991608dfdd2097da292551136f255051c +9f7eef3fb7c7fdb4e651c3d03a4ca357b587245236f4ff3252563f6be08e +f8a3ec09be2bf27b9120f7d37801f6999efb1c8ad1a08698cc59ceae2cfc +dbf6bd8f94dec94f7ebf33af05f52c85760c63950b455510c6ab9398d09a +c288efa09e8f631a59b03fbbc75bbdafd675ffacccf8adf71e815a4a49f1 +4bf70e42db0b7347b5284e234c24010e2177dbbd57648e398fa6b54571a3 +7ba8c989503594d03c6e60871a7f96459902215402ba168b8d1d2685f5cf +8645d5e11a1769473027f42564c2966c10c0dee1ee1b6975852a4870d492 +83a470e623337544a7cda5c16fe2855ba2a548511fb4d4ff2e3e78d108e4 +c734f64ee2f12cc9562cbdf363efaf5201b673ad00583ff108aff6b68055 +a5f299452d176eaafb92c84f114c8c22a05ead6564a3371420ea9e646308 +de97d40705e1638df08704fc90249cbc0d2d3e884a4562cc27370b1a9738 +9d8efd237e644a7370b8b38ed1c377f522c75f981d878a5e87101e621df9 +d85c7207bbe5a87ccb607f93a2e52f660e05c83a7a6ce6d01ab4b62a1ef8 +da47cf97d4bba0fa8effa9c0f61a325a97ada69445f23ab1fe27a66c2716 +39f839203040d44b11ecc6e805fbe88843b34c4fd52d1d3c6c70ffed433f +c04501fc20536abdffa429b8dc8192b2d45dd9d646049cbf40719c3d6747 +73f9676f9fcf32817dcb55402a72c56d74aa4ce4035687c730b6b44a9cc6 +14bca5a3fd17c170ed949e588ee45e89e18b07662a6327fb9e8475c43e5d +a1b0af07c23774b19c9ef59281f5d884990d6194170d8293a86db52a0fe1 +7e88da82209a00a16bd29b8b2f13fd60aa25fcfa9745f57c8216283c1d6e +a1c119cb9b8d57c004195210ffbd56395a3ec2d3098ed38f389efc0324fd +0e55ea339b3892568229d8d3e205a821e8219fcb1a7713fcf3450f8bef97 +6ca0beca47376a8ca73df85b340c67efe4534d459617996526b5e5d3d19e +17cc5449e5ef2b82b2c4c2131ff8a19fcfe6a186a9840d872d85c40665a7 +a04e67ee26b8bc9206c35b44c8f8a1afc3867d96dc6d48bd45063be25b88 +2e9bc0d0948c18dc870e6925818e1fe17d336217f174eb4481f5c0ed37a3 +beafaf4d46f857811b6728bec461ae6468d87a736572f4ff95b58b04564a +9d3c22754587df15495a319d822b838461764b73483c1f7cb930eecc6f74 +24841ee10e4087e951202fe88a391375c96bec4480328a54740213f74110 +5b12a39f19808f3823507b88115d468c61b212a8abae7480e39ba52390a1 +892c7ec50271156b4e8076fc3ada222695df372385da7b117a29e04cd2b8 +0a320f186d61c963fbdafe9224e537057c49e82e405196aab621b5fe4011 +e1782a747ef935ed8bb11bda39a141cc0ba42d04ae123383bc95a1d03a85 +a9440010c3b9613064ffeca76197e10919ba5006f35837ed9bcd7de5e6d9 +68aacb6fc91178091fa467ef6fdeb728e17293dc89dde5a5261faa95a2b0 +000fc750e7073900d4d88247da464613adc2b3903a6132d96ac0e1c56438 +5ffbf6249dea76bea2a99160632dd2fc2b99133e9f2f470f72b45d6f18b4 +5020f604b06cd9174ba3805db60eb9c5e6a9c789ace76ae9c79c1bd34434 +e95e501bc968633af93ff4883c6a596776254c0c74993710327086b2886b +02fd3e42a725a03459cb36ee34a094139af5fcf487d3dfe63fad20bf0dfb +60deeda2acca3510e963189d1256eabd81253f7ff9d11263fdbc1dcfda3d +1ea2e52005ce3c605c993231258a717423f64bfeebc34684efa676358b9b +543c2042bef954829fe3246a879845b30ebacb43d8dd7a20fcfedf763ad2 +c5d20a798b69e08722dce6a5762e249ace3055b650d9e110599ea30de5c4 +fe7200d5a8da9e1fe2686350d0df334877d0b9f6524c552d0b6dffae125e +c4c18f7547bd51c14288e4abb7f8a1a00458596c390aeee6fa308ac1f788 +fae30d7f8928afc91d4de6352d20b19d8d8ab122b7378cb379c5be7e3ce2 +922fe667ea057b5d7b3f0b51c7bf0c85f87ac2f360d82c38964f4dabcc91 +04b32f0fb8802235e8e8d9a5997d392259074c00af2ce1d2bf7b8e90e2e2 +ac34185c68a03bab8b267778292b227245d7ff8670786e3f746f86b9d4d1 +7190db859a0e144b2a61e6ac9254de5dbaef20e2e9db0b2ff654b996e962 +f55e465dd238bd1643ce59dc2b5a58b1e6e4ae2ddc2d74d79aff3c34e4e5 +93e051fda236b79cc0db268d2a89b1878051223bb8f33ff99ba87a4811c0 +b3bcc01171d0a731eb732ecd8749d27952c27886b252f9c3d190419fd290 +0987a0a255b9753fb7aa70c37462134c467a2c4b7920bed9f9e86f8f98b9 +6d00af8b05a4bd5f14c2a0d914a9a84160d554fd0718f50ecb5df5e76623 +065852daa74c9ad6da07a119df12c3577fe276ae551d48b1c5cd8a50e84d +ec9cb0840520d78fa7f9a7c2071e28cd20ec7649b991f3818cde295cdb60 +85f24fcf93147e9f4dd084fbd32525326d2ea147ecd5b6c9d9f4a7166663 +ad18bf234e9cb92ff72138a8a49e73e527e9a6488a4ca808aecabc94d693 +cd2c0c357d285f65006fa2f9197f61fbca6ef07b013e2b558ab531d2fd27 +0cee7fa8e467fab885e90c5884843aa08e2bbfea0aa575643727ba18acc4 +99ff34e3438645be2aa71ea491e54687cd305e12bbc94faec848311ae816 +495b013bc5075a2d2ae54a7ad7c9105b64356cb51f18c2c28e3a83b9d81a +4554dbec9bea9a660cf7e1ba89e6d4dfb3eec6a3de3fcded9b2d614156ed +ae8cfdad5ff0efee31da3e6a54d94ce9453a1caad9756d91be85315f6514 +bafbc821ee810bb5d8e1b8f05f64f3f72c4b35d424f7e4dc3ab581b74ade +b6d6297cde7aa8278909f269fed79b7dfd39b1c0338e01d556c4db9ca3a8 +578ace3ec3d743ed4b9c0145e4525e8c315f7a1b98584b975c70f0d41570 +8c8ccc13f848b1d36ac8249b73638f95de0cd27c7efb52bed4339ebda481 +2564d7a77416ddf4cc88cfb52d07a252d89353c6826ca1832a153242979b +6cee783abde65c8b40cf4ea7b42b8dbcc0e02423dd693108006f6a4aebf0 +53b666c3cb63d1861f86eaacd43bb9bb6f2c3a17293c189331d253b44775 +7ee7cbf4518babb73a1d44874d7f0625e6a013c608e991b4ad17a9adb367 +40d25e3e35b459b422f7370b134cdfff3f3bcc4c32b4e9ebf6a2478013f6 +6933a1fa9403a2f1161ec632f1f04edf95ed0f33dad9665d54dd9db2564e +51da7b65978cab50d6dc1568976e83b056eb0e3a6758518b6e17e9ebfe49 +b72eb148b472ba144bdc2ac95744c9bf1258f0a2e47470ab0eff90e190a4 +1108914ab8c1ed6b11e0681778521870e80c16af2afc723cad8719adb62d +3939d3bc8cc1d8a4e07e9d734f54eca33d936d2c39d5c8055739c33e5335 +9bd40e576c11e93b4b4c122bdbc9b1bbf44243af4f0bcdbdfade68c526b5 +cd74e29ce3f70d62ba83c489034111fe8e4daea2f01f9d938abb532deeac +0e329f42453ff5c15dec2aea8c198323c9e8fea55b3f5dc4751d2e2e16b6 +154e7f2add46860e9ca71dc114c99d80e7ea1dab51e925de161cedd678ee +6282aff38e3cd0e659549c970613209955a3f581e1abe485e56402a3db0d +1e9b8a9dfd05c4b0b7f97fc6d0eed0b69ad6f182b1d028add2f24463834b +13f5c1307f91d363891824e81108e57cfd5211f86400d3e96b107f3b1fe8 +9c4908649d04a46dc3cee0de66af03a7ff9f4dafecdd6df4d93784cc899b +527784dbe0718050fce185bde3f39debcdd660b2488d23ab1cff87b0546d +02b48e7b7724c9e87b71bf34b5d6640e0f6ece47b182d41c89461f712849 +c6cfdb7e3f5ebc1acdd12d65a422ba362a8fd6caac5104ccc5ab5fc04a46 +e4309acac83d659ddda256ccddd1bff9ab3622450c4fbc89c82214f00c42 +fb0311bcb1b722a691ed839caf9024fb1671f18e4639c96d84718c663a43 +41dec037175c6bbd288bbf5a0478298ca726567a9b74c32a527339c666a2 +94a17f6821cbf243d13ea4b1603c292953308b566653423e7301a032e5d5 +e2b93f1c1434893633dd19501ad12728b5a1d9d36635b589fa2e151140b5 +43d7c5e469afae8e80c4fc1d9cb6c3823cc1bb7ee40aecb58cbc14657922 +26b19e0fe79235115f6a3afe19f98c5db63d372dd7c041cd940f4f79f247 +4d9ceea0334fa04a97dc9773064895cf11cf73f11b4684f06e48f4469f6a +1aeb2cbbc52994dfab3319dce3a0c8c2efa9627496f8cc84d3df3bdc4ffc +b61672780f294f453278aeb9262e66486856d37b7647141a82e049364ed3 +d03f925284a3f1fa3ddf4c0b48b3fe22e7df9aba239d33cd300ffa8fd4b9 +6192bd568fb18d325caa8e1f1fd4b27527417b034841fd49e4a77f217062 +3cc8b22101166d80361eb15fa9020d24f61007b0a8274df9dfcd8e97c855 +68e76d34ad5db1779b02f034a69ccf9d4ebaa188eb3017eef5b22a0a5526 +96a574907f695098bd8a4849d5c8311f129447cd7a3cf88b8191aec0aff3 +0a38a9ab8135608a7829207a7d242f6e1fa7dda19f5e4c28560d42db4405 +77cc0c5f5803eee897103eca0bd944e320ac26553bee7852eaa733bd13df +760056b2f5bd1243bedabc3c1ea0531017d74b47e18f801a60074d6df849 +fd0532234545e5b5e112d1e7385341d39a89551c80dc2deaed5d5da2a4be +5015d297324e92be64c68428132e6ec654dd4bdcc6640c68835ff8a05e09 +9604b8cd43d3af2b2fe10c8afedec5a70af8509d12f662338cbf166d9452 +cd36331758ac4f4cbd7edd52139ad27dc52569877fe709f297444c4f3189 +9d1945c81b14abdecbf31dc463a4148f04ec4fb9703c158216c0fbe65ccd +450043abfd4e65bf8b28cc148252e9f3e797ea0b57b8721c94cbc2ea602d +f2c57e87938c887a382d2659226463bc7d6a1da87f4a341a59bea458177d +3f18d1213539dc0e301f6efe0111fcf6921368be17ccbb7428127e0c059c +2c5adb2a3f0197f0ceab77ff7f3c027a8ec3ee76cf5c986eb47cb60561c7 +73b3a2da47b5a35394e29373dbd5c3ff4c9213a89aed77cc4f3fcfc49ef6 +ec7557c521979a546983c106b3627b5fd2d71cc5f08a32bf49332a89c5da +71afbfb94c949a91220ab1f885c981423af93f73bc1ca4d92d9dbae3efe6 +a76e2de3d0f74fd3255820636e3f1a6b7c18530623c12af90cdcd2c0a728 +521e9b639eb6345d1de8fffc3b19c72e7a93823dfe3115e9e7bbbeb28cb7 +3db121aed8920d47d8cc08ea2e472e39a4cad5881b5c4204f2b732af9d51 +89d25abf413cc78714cb01b1d8ca5565169a919dc481f6d2e67f1d490aeb +c5cc62a8f62c1a323ebb55ed35aa5c8d6f8b970e93205c2701cf4817bda9 +94fc16197b469ecc5f5e9ddf0fa05640c2e571849571cbd26402b1eb1e80 +3fcf423345007b9b52b13e3b034e8cb3984b925ebffe719ed4f39f3d0e33 +43316a6fdc26bdbea88c4366d3b2f851d2b244cc4408251ae2c77348cce9 +dd8bb9c89800b572d38c5d1cc34c740beebb5ddb0a8bb251655fb989840d +23205d16311a9fccf7c85f6dffea9704492a4e7a8f6c0bdc29745aac2abf +aeba02b0e7aefeb92ba63ab0df844eb09d505c3dfc1058ce42cdd8043b76 +398401e1db862ff9f76c05e8bc6260a4443cf494bc1755913d51745bf45a +df2f8c7a9546d7ef4fb11e9d94e4539632c2a39606d04480ee459408d7a2 +a869807a4c01881c1bb21c296a402b5e6e07093d833c3dff075f4dd426eb +87b1b8de16c146de79f52f5943015331eeb852809cbb8e1d6460ac4d176f +e96f8d19f6ccb22abbbaa27c4497d91312c3cfb5bb913b314e43d2ec6ab6 +897ba7c34cf2caa6db4bd69eb5dfcee0aa917d6950e36a68a4c22a60dcc6 +9379d47544a58d640eb10dfe120fca843b588ca8b94f7869f97609a6fe03 +ac86ec1f7cead2ec8e81977d1b946e459dfcfefe65a7bff67e66f5f78a45 +d8df65af0146df74e024fc042328886cc1dd7779f49cdbb750345cf83cd6 +78a6a8897577299deb38ad665dc4f21ce1892a18c256f318107dd3e9245c +1ad3bc93cef7b7bf057e33ec9a3f953251261aa3d1a8347261e70a46f777 +3a84f3d4d1a0df6dd22a96429349de0d180310e17955b10fbf53220ef648 +3d03c650a8d5c16d63daf65c21adcd6c2d0b5d4adeb2f5526aacf7cf42f9 +a8bf4832fb2d4f73f3d5ffd984b572232f87bd3e59133ed3d2fa19f7856a +d812515c74f7d851574019c532c25f8e163e595fc9c83e3e820c3cbf690d +a62578a980fc0803eb6db9b1e90e3256bd4650816abe5ea86ce65c2eb418 +d0adda5f3ea04e17aa8c4536cc471ac20236e66eca3619f161dfefa48538 +6c30ebb86a7ad930fd0aadf2da69dcaf26c0f677206e2030e3b15b3662c0 +ad03dbc1636ebfad1f2f2c37f5fa9856b0198c5b1d80b69c5effd94ce071 +5135c649c26b9ba1266b0a5b270cd08a706166c0b320915c87b27de21deb +5d7e4806f6e700b7a06a4e29b629cb40761983e9ca8e34e869abd04dda19 +0bfe5a6ee8b22d7e511b84ea584a84211f27af8918dc5af8a1ff2d360b6b +e3ca8e66ba4cd2ce6a25e7e89406684da83ffbccccbfd0844fe3becd7de6 +7764c59c022db1168d585fe25073fe00e30218d1dfe115ca1fc606afcb04 +f2a082ef91788b6bd09684dea31f20034a91ab9d971366f97b5009fefbf1 +ef0ad941654081b1e8f0b2ea495069a1ddf11dc56857d29533dc857958b4 +9d1a0779732819fd22e437084bd9f3c4f2cda4d12ca14431937ab63a03f9 +c040af1d801f367abdca7302e18a9050d6026fba5a5a7fad44e31593173c +df277cd737d1cef59fe9684252bc0ddd00a80e023b88222494c1c8c08842 +30ab11d1083225afdcdbc1e24d4ad5fab396d2e370e44a7571b230660d51 +0a5076d8e35f7db72c0566dfc119ee1b8ac3c0406950a3c4a4da36bde297 +040a27f70753a87e6cd593dc6be9962261a99ae5949340c5d45c94a9aa3d +d636ce8b497bbb8123457c824f443a53b3ee595c38983fe3e07dbdc6acd5 +5cae8be1081afd4857a5f52a3c925143507a3c37f1992cf72ed0d4c48d94 +ae6caddc3bc87ac3a3ef035e02181f78449e4b063b0835e827644051551c +1603e2eab5875f28fc77beba6923428d5521c698c6b7f133b0f689f105fd +bac30a8ed2f29f0255ddf8a037b81f04edf004cbe639c8db0f94d0c5db92 +d34d66c2fed66cf8b895afc4e659d08388ea44eae83ce459e5be306750a6 +82b627802990037157339bf142bcb9c08fafdc3c3fb16dc3544f62c6c7e3 +3e20cc4fc7ca21e2c3f6c546cd78dee348f1a4c8cb548ef20c0496789167 +71d83acc9b7b22784ad8580134471a3c79bc86b5d6d0d305c32e62042743 +51c94f9df45d9b2ad5b5087a89f90d6aa033e4b1d1bed022f36147c7abd2 +b73134dffd50907258e610c3b20949e141172b1c6a76db238c375021cba6 +645cdc26b717428b5a9b4d3f32a4b1e22feff3bb93fd889e1def8087718d +5e3e650fe4a3330da9c37e9eb499df5a342d8ba4c0a033c3347cb25a31be +143ecbf91384f2381e323e7fd3a82a3197c189053200ae2c86b9d01ab0b2 +89841ea7e9e9a26966e0def54de0b85d8df084b8c590081e444baf1e1f60 +670fa12ab97159318624f2af1b5ec7dd83c1073a99398d2143a52d10a13c +201fb356bc9e90c63bb0bc2d4c42af4a8b9c8c4d58a1b32e0597c63b3f8b +3e893bd3be8c60231838f1bc78e73a6c8cdd5e7f2907f897fc8ee99bffda +7338bcefb5aef950e5549adfd207aeb15846b509fc57989883642498a381 +1b8e5cde69c05924efaec232fa4cef302ee3251366ecaef57d25cfa3b4a9 +e6397d996f421c900bebcf73b038fe7b16fd0a1172ac2f40d19ce0b02fce +b8bc47da5344cb933c7fec950184f78acb32d3e5e290e84be753b9e7a7bf +c4416ccf29d023760c06cddef2505806a65e1508990529245059afd301db +669d41bd72bf7a80a9df66b876b3553fdf4dd38d15289af7a1afbc53ffff +135a6348dd784ab42a6c0d6aa330b069607e2df3cbefce79d6f63e274c9e +73a33eb85246d5ebb986bfa923df68b2b8cf82af6c33e785f35b25b1d1d6 +14de85a4f4510adfe42d75b5fa5408a59abe53859e28b3d000eb9c6a7d2f +67c91dd14c895ba87b9cb57b851e5193fcc2a443af85fe28df6f39537f23 +a058bcf81dd8c04cb2c25040300f4c55975e856dcb4e21e2b5481bdcc056 +01942fb25bb8a6b6f93e2c2a33cd478b44655657c557ebb080179ee5d98c +5cebe0b25bfdd952ffeb258014d7a5bc4bca4f1a23bba73c454b12960451 +ce1752401b0151cb2e01d5c72595095eae91d8d3bd55a54a2aea89239fa1 +76fa7cd6f16bb0733ef6ce6e77763a23aac77da88c8efa7bbb2991e472ff +2075fb25a75acfa70a04c28764f4ae4c12051b25b120cad2e3044da35c1f +94135dbd69b10de147321cbbdc814ce99982ac1d76ce3d3330e41ab31f3c +76bf89b95eab81af3464c732d5b1411d97db36c9063537f64756f205b16e +d7058e2cb1d6946c00a1a0cda9ebbe924bda6c7d7b605c514a98133907b7 +93c74ca858e82da3519188cd974b34daa74265db5bc8550d5f0b1173aceb +87458bce2ab1f96996c811699a0fe4a9b849d39023725e2b1ee7e426d30a +6c5c75ae6bcea6db41e4eb2035f7f924e6b9f0dcd00eb2bb014222e55fe3 +87fbf5b9b7c04f4688d5ae3529fdacb38b5eb0af5c3a874c1aa6b17cda8d +1e22eee05a3da88449200d3d0d002db86f6c51b337c8e19f338e7bfa01e1 +202612d50e210140947d5f350e84f790286c3f679a5d7e43bcdc337265c2 +631527fd62d598b7ca1f5835c0441881b97f5197901ecdc4f195bc665a84 +6823d2e41417373f8639567b228fe7b73d781f07a361aa49c3e9d80fe5b2 +a32c4c1e575d194e841967b08d10405fa44eee2847db9372c5cc931e5046 +9532f1baf577f680bab4e30b7e1cffa8574abb679789f69a8a1bac07b7c6 +4ef5ce5eb00e97b36fbeaca9bba4a13b0293d34bdbc77ad1ff88e5744af0 +09823bc262511c4724dd585e7e17d90f230f7a5861b0dfc42f0b4e49a04e +e0ee4dadb908479def8372f334c53d2ba5d855cb39dc7c9550f9d0f7f77e +82d5a59fbbf34bffe92dc9e6668b68feeaa4f20053433d6749162bbac5d0 +d428dcf2d58d49b127fa2e674edc7d3613b1342f4d0abd7f4c5b049fbf78 +e804d5f16505ae7edcbf4d6fa08d72890f5d55199034572ab4b0c9a7e7f6 +f5a403198864adf113caff5bf9d4ab5b16f81d0fc2188fc80875e10034d1 +2e30c0364f8f72797f1aed525a2712a40d44210b813df5a29c84e9f6d51b +1d60a5f6f938faabf878d29e6ab252d95d05fc1adf5d4ce1c9e585219112 +112bc6cd5c766411fbd22731794b5de0a27ac57d3c57926807469c360372 +be529098c350efe2154b87f1205a57a0b04c5206cc4fa66b8793bbbe492c +c3271fb4f90a28d0066e0d7f63b8dd01549a05afa5482c29560abd628568 +75cac16100087540162473498c14087b29b86b7bfad693e81765cec781f3 +fc80e9c7b410e9b55b88114191a1703c638dfbb469ed1dd8254b1407003a +319ce74ad419b077f17047a01f0bc0ac8507191bf72d77d9333c9da8c9da +733efb5305f49cb8c7bc451321add7d896395d269dcdfdd084eb3aa70338 +6c0697e962929651164135c094d9bb1c9b949d5eebd3bb17f02c98c813cc +bfb23c2c26218a2f4c639a8b9dff2c29406037f91938a5e1227310728428 +b56f48108cdeb33bd3191eca89f947271983db776b2bc897a30eecf2601e +e3b2a6f0e135397622aac1f2df523ce6e6bc720e13cb530cef4ab9c8273b +d3d81563ac8a8e6c44a195112daf824bc7a72fcdc4e129a480717beb0108 +5dee65ee4344d0b41ec0bcdf842566b1d9f5353b1f6a063ffa6cdb06ef63 +4c8bd5a7a63f991d178f56eaca653dd67685ce49e98c7554745a4ac53321 +7662d23e1d6937135d13bc2208eb8d50560a2baac319dfae478b6ba4ca5e +da20222f0e9bdb0806320ed1665b54a347de0c42e9f77842de4d188e7e82 +4eb2f0d7ad163f05480a7fa99c5a603bbc5dbc843774ca66e889b945054c +0ed0b1a4bb14324ef901b023c208cb95dfce928489789690cc45bab97be4 +49f8e2f5aa9276c0571303e9788c46e7f789555bfcdc3fa9ed8da8ad9ba4 +8b3ae09404664391e63a989ef1e24bb464043aa099e4f2d796e352eb2771 +06d8d81baf2f8562ef46bcfd1e0047e8018cbd973021dc1c1d821af03f08 +3f0b088a62ebcf2bf6c5b0fcfa441aad1625fdb834f943dd47a5a42eb3e9 +a5b49641f797c288b799a64897f1346070461b6d535e0c4ed099199c387a +3176aedc7da7e7d9e118e55565092a36f7c74abf281720c0147f4e4f37d4 +9436466c61ff12764e3043d8a6d027e70537164f0e7942f4aca42bb2cb13 +6177ef7197e76f49ab403f741c0ef902febc471ad6c627424320a8c3a1f0 +4c310c511b3f91c3937d9acf459999c18a33f2c852ec38ca806599c728c5 +43714018c65e2c5f430f6270af52ad71ed38813b60440779455f9529a4a1 +623cb9f5422b9216f9cdba913b9a1cd95da225e254e81012160850206605 +09d03a034b5d7e32e3db5e5962a9a27711d4c3e29cd84057f7d0d7e80009 +47afe896f8523253391d2e11fffe523366b05c532d5629a90741eab3d4a7 +31d3f6d4f03ff93233ddf88bb1913aba22eb9aa6311e3144381dae29bcc8 +639958eee59accfa06f35dccc63e0609f542f3ee5dfb1cf718ca3f328455 +726f8f65e23acd970e4049225998371b63e35ae98dc54d8329b8db0901fa +a63129ede21b158776981d4d094013c096e9cd020315d123c03deba21e97 +e4b584b4bc0af25f5dce53c2dc0f3e61f99becab40799478be7f5afd7f68 +e23ef50ad6645c967ee11206b6e791769428acdc370d64e4f2b3972e0e4f +442297199350663d6e772fc6777a9b9de215273d082cce4e8678fe9948dc +8d5b0e459cd02f1645ac5620f3571a40b4d5a17df5cff48b6c843ddeab5e +bf58fe13d7da08e8aa7902119248b3b151da583101cf80853b0150fe05bd +edbfb50a7fb0f65728c93b9df48ce8af1df1fac25c1d58e1ad30274a00eb +54cf2f16029e1ac0a0919c0655474b9a6936aee0fb74bd185fe7d70bb847 +86997d34a40326a74356a4afaee67b6b26d1c1a7bcff8697b55c816ccd77 +312c332a55315dc54f9bc0a0f12500e0a76b3936292a3da2ddf5aa8cbb9b +5dc32edacc4827d684d274e65b8b76fb2c2b19f7d5607523fa953e34bb39 +032c05b1c1244304606c55660d3ca8607e764ea5b03db7fcab5cf7788c6e +60ec8c449bcafd90bcaba4132b6cbccff16784fb59b36b77cf0a9ea572e4 +ca0a01c725a6cf2e4500cddf5baccb9094d48925434f044118cfdc2696af +5fc0cab3884107ed17b9bde0c0104b1292a1f8c99b06fc4a6360b24480bd +59df0488641899b0f42b1311b582717ba7ecfee14143654b5371c8b9b2d8 +0685ad38d897ad1e64875c28c7020a84fbb3a3bbee16617dcb9bc822b7c5 +9c5a18c0cf7e80163adfb7aa03b7cde8497c1697d90f2ed90f813095c5b9 +1657fc294ef0e341db3392ed860cb2e0aa09293d0f99ae9eb54c761ca2db +1e51e1ceaeab276c7bd916c68510d72d9a67468b09b3c39a7815628fb126 +cdfd5eff59cc8184c0d35a5b5960f824bd175495dd3eb12a4e96008cb13b +8c5745303e66cf8608ff27c4709c1d854eb79608e52f068fec0151a74c12 +5edeaea555c198fc08027bbbb802835e1d435077ae4b1ccdbf722354f6c5 +72beb1376d3e342195fa80ac9722eb2f46e44de05f5a227b731b8d4a4b6e +def04af2c5dec2eef8ff48c5b18710ade3dbfa0c956505b6da9ccb7cbb83 +4db6cc754948855d833670ff0ac42a4773fea8322becee04ca74ac2d6685 +5132d11a51524488c54771b5b7a512796d7d7ae0f9c1fbc9cbdba0831074 +f4d200349d0ca40537b92496692766f020ac43ac01db8b2aa2efa9d21732 +be3a315f6caa402bb2e61d40ddebde11276d90c2c601a935c168be600464 +76aded15087d54a14c68eecbbbb590927c1e10d291c9285334cb0c80edbd +392bde4d535eb61f8e7641f58ac1df5b1c5a5d91e3e27e05caf7ec97ecf0 +c85b6425197aa856521ed701e5aeb82a7f52a8bd7dc97d5b3fb5c99a5df8 +4d1baff89072922509d76bc6edb15ce5f9eb8f4154bee1e82020240283bd +c83a8e49aa9a2649b7955d5c058f2818a63bd0bfe7eaced4a49063c489a6 +26277ae1246f721c9926e2a2b6c31045fbcd235f3cc58bc4dd6c57fe998e +bd1e9fa5154652be3a1685bcd2efaa079a3293f78142a6473822fab62792 +7eaccd61b3e99c3077103d2d19382bc7ee15bad0fde489602d055a01dbbc +f91a566974559d1b477c209416887053169c3f8f59955be4de82b60558cc +9ae15602a93f029f6b4329e0e62a03982db32f5229714efa1491a7b24aef +e18febc2c93dfe50b3f641b51bdd33da38871bf5243c17502d00aea2d9e9 +734e80a96788d4cf5bc12a42bc386162fc88a7435ee13200c1c2c6ccc5d2 +1a03941007b4c4291bdb711446ceaf27148104bb240357d5eda0ea5a5ce2 +7d4a83909d75bfc05d75f10aa74a6de37d7de15c1dda3ac3045da6cd4832 +3d904e716b445e5e096fcb379353ed70cf4b6fac102c762711079efaf13f +b74c9b47af75f3f6bda2a4647d2ab47ecab64da6cc01479f618e8d2d0a36 +45445e8744683cbbc560d47c98078b84206e90eb839b02d37c852b8e2844 +63d4e4d890203c3d5b20352110034ead6bd7f41456b807e1db1631a9d499 +e52e9d9853d86728b1a2e511f40f8ca1e4724a0d17ecd640b52ff6c66e28 +693d89765fc391612e5889e77423ec85cbd0a038b6ba98b607701dc0c4b6 +6b3b28c7790a1f1eb8d051dc98276dd9cfefab3f65c1c928e48a060c992b +392a43e56eaa6ded896debce71f8245be4687f2f1b8fc0f43ece8db0bd0a +b0811c5ce73cbe336023a0d66168b34a95b4b0a750b3bf1d197e3c042c79 +14fa731d7831af798e9429571cbb977e6258244e84701e5ff91d608f98fc +3d68a4ee5b81d5ff38b6c184f6118b875f022b4ce207dc7b37e1452dfdc5 +91a3e506ae82c7e7bff0011b0a3dbd616a993fbf878fb03b6c9f2055a2b0 +95d29361f8253c2623653687fe0ab98078f6aee5fc2c2bde0405eabedb3a +33eb7f04cb6837176245f190c6bbbcd64522b12fe7f9cdcf201a1aa8a19a +7bbc4ac064b4958f44aa0f8dda23835ad28a1fd0ea105de2f395385dccfb +e2261dc5a89a23af606a3985e5038706b1fe0910400e16bf008f250f3bde +3ad806c735495d499f16f99275010478fd2127bf7cedd6b5bd505fbe9bd0 +065b4a7090c9d27cd5b36c3ad33e1b31eb6d44e375003b51b909da50bd18 +218418b3cd22b43278b144be78406eaf16c7df6b6c1c6238004aab73736b +38e168441dc16f9a5cf60793a18633bc43d78674d12d38cc979f7caada6e +fe807cea499cb9fe616496682a66e04bbdace1dc112b2156b9b0b20a58a8 +cb43ff0eedb99805234b9a5789762ac7d65f5a319c33f4f7438cd15e06bb +80a7a97e976e8cec23f4c646a5821880a82b2f1dc27767f090997e91488b +fa15064b702f864fce6505d6cef87d2a0a12b55ba189af269811e3b8b850 +c8401f3906c080d32618d9698a766732a40a9fc5a94e5bdda3d028d823d6 +b603b6d17dd046de181fd989ea0f80b4ca62f7973e4df5e032a31fe6bc8f +5cda678d4a72787eb8253ea5882c337cdf9aa3e1e7d9536dd09b047cd896 +2e773f72f6418a3aef5a289b3406c152a50ce7bd4b493fffc27f6aa52f79 +ea67e362fd92559aa4f94a2f787f6c735dfadcf2f08aaf98b80c53ca5607 +a94f25f04aa65a70a75937840e73055b3d65fb054c63e2e48e68488c9315 +a13ee949e03e46723c11cc759d222cbfad2e1a87cad779b23d38f7e2f660 +de1388eaf1cf4d18994d75c6cc63f187fdb949940c18b537a0afb12ac5f6 +7b0283ca5efe2e764c4369104b9d3b06490d1244c41d6085c85f1106082e +c9db84586230511c05c82412d2cdf3dafbf4759a775628878f997415296b +c416ac8352a6c6988691fcb831cf95c10bae691adb3ba2918b35924bd5c3 +acad8b137397b10af82b479800fe16d472cd0cdbdaab4f882a0649cf5610 +04b8cb7ca32ec129d0a415be6cb91da2b65f44e80d138808a127e851a7fc +f927e99daa0ea2d626b77a16c72e37f058a3b882fc4955dc8cb6312434bd +3bced75780b13590bf4fe8d64acf0371f9fb1d361b05025852aab9eda1a0 +c997cfa58052c454fd451e6c1f194f4d363114e312f6dc35bbaf357a32cd +200a3dd9654155134259887d677acc44f89aa401ca27282df7dc3f2f04a1 +08cbef2558dcce28bac2d87b8d5b7181ea927f61977764f882626d4ab338 +d95c9477c54e9c36012a3cffbe199ec8120a99d2d70a21f9d9a0354e4eac +7947990e8a6e0601796aaf6f14e758cabcabdfbd8204a8e748a3e5feba57 +0d36e2bf474c0083229a63f96114182321b2ebe1bc76dd193724c4588c1d +39d184c332faeaf4c629f2b3b2f49996e46aa6c9f497428bea52d58876b0 +dc07b460248bc85cc16773a5dac36cde8b152d96057f4efaaf8b1dc10022 +038577368057699b3a37178a9f1f6c6cc60bae820b7add0717911bd23a6d +cdadafa32473491aa80cfe90f2a77e24ce2826ff77b18b869c33fa292fe0 +1d6477765044c7d14a548b28b1360125c6933f05c58b0889390537cdd16f +8e967e0b38579449dfc1e07389b7069aa8594c5103465d5041cc929268de +863fadb6925b350aa94a27d421fb7fcc81c6b35f906f12246b7a5140511a +97211ba9bd6831a508e963fe8be961332f557808488f06ead75e86d60de3 +fa2425ae8439ecb9112bc3e4d73747c1c8e87a649919827049832db0bf6d +a8c85c9a2592ac002809070900ecad52a56f1bfd456afe066509694eac07 +5788456b0b0bdd7c192d321e9fb6aadcaef00f570f22cd4a5322fbce8fa9 +8faeb681940895426270bb4319c11da67d88552a7373398aec5da7c9caa9 +f3b34581c6e968daaab2751cc012199dd897b448986cffbae4d412bf9ecb +f46742715a9569932516259d3b3a5431cd7028e42fc751c434e2b714c718 +202bf02caf9b8a2075de922322ea7cfa605c8376fa958b8fbe43031e1026 +fbe6126a3775f643ea67ebbd97f239fb3c43552675cd08b19ca5ebf53b40 +d728556b4481c7f73ec71cab0f89e34d60c69b272fadc22e8e7bdc6210db +09fdd913e209f49fd28e8712b8508904620250746ca3b21b026edae60a28 +22f59e912e626b93e0d2bfb3230dfd0e54e91a1dba25a609b64d41abd897 +a5d21764c351e85f9e87beab9e645149ad32aeebb3b1161032c701647115 +f98c1c2aaece871862d91d321ab90f3e923b1fdee00d927f897aa9812373 +6536e2e0700f10053d7e6c589bf66029d794883eae4c8228941ce96565b5 +0d48887b5314a2e5537959638222a6ca54c77cbabd460dac11b063519ae4 +f50d93de41763ba7cfbf4c7724360e750478eb628921daa065858341958e +4f3eb5966c6dd77c05eeecdf4b5f6cf19ab507589b4219377959bd258ec9 +21c34fe1db003f7d0fea3e2fd6f5ddb0a2d62ca5a2cd3c7ab457dff25094 +efe04a9e1b9ce7ae3f30026b1cb039228d309a22899f6e9b9bff922e1171 +23347967d7c62c670e2c74579c35989925603022c17b1dce378031abc9b4 +b437c7b6e64620932e93189754c01d4b280b8b08699b2ca953ae4823bb9e +e34133c5c95b3290e1bf010705ad852c72be87291e1034b09f44a95b6a2f +83fee8841dcf661770af44d0ac7f9cdb280939fc5d953d525e0b41b7be18 +8d5c794687330cd770d24d9cd53b895a253004e18a31be4e82b384 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark diff --git a/fonts/Makefile b/fonts/Makefile new file mode 100644 index 000000000..4813e234e --- /dev/null +++ b/fonts/Makefile @@ -0,0 +1,62 @@ +# +# "$Id: Makefile,v 1.6 1999/05/10 17:42:00 mike Exp $" +# +# Fonts makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Font files... +# + +FONTS = Courier Courier-Bold Courier-BoldOblique Courier-Oblique \ + Symbol + + +# +# 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: Makefile,v 1.6 1999/05/10 17:42:00 mike Exp $". +# diff --git a/fonts/Symbol b/fonts/Symbol new file mode 100644 index 000000000..926391db8 --- /dev/null +++ b/fonts/Symbol @@ -0,0 +1,1150 @@ +%!PS-AdobeFont-1.0: Symbol 001.005 +%%CreationDate: Thu Oct 21 1999 +% Copyright URW Software, Copyright 1997 by URW +% URW Software, Copyright 1997 by URW +% See the file COPYING (GNU General Public License) for license conditions. +% As a special exception, permission is granted to include this font +% program in a Postscript or PDF file that consists of a document that +% contains text to be displayed or printed using this font, regardless +% of the conditions or license applying to the document itself. +12 dict begin +/FontInfo 10 dict dup begin +/version (001.005) readonly def +/Notice (URW Software, Copyright 1997 by URW. See the file COPYING (GNU General Public License) for license conditions. As a special exception, permission is granted to include this font program in a Postscript or PDF file that consists of a document that contains text to be displayed or printed using this font, regardless of the conditions or license applying to the document itself.) readonly def +/Copyright (Copyright URW Software, Copyright 1997 by URW) readonly def +/FullName (Symbol) readonly def +/FamilyName (Symbol) readonly def +/Weight (Regular) readonly def +/ItalicAngle 0.0 def +/isFixedPitch false def +/UnderlinePosition -229 def +/UnderlineThickness 46 def +end readonly def +/FontName /Symbol def +/PaintType 0 def +/WMode 0 def +/FontBBox {-180 -293 1090 1010} readonly def +/FontType 1 def +/FontMatrix [0.001 0.0 0.0 0.001 0.0 0.0] readonly def +/Encoding 256 array +0 1 255 {1 index exch /.notdef put} for +dup 32 /space put +dup 33 /exclam put +dup 34 /universal put +dup 35 /numbersign put +dup 36 /existential put +dup 37 /percent put +dup 38 /ampersand put +dup 39 /suchthat put +dup 40 /parenleft put +dup 41 /parenright put +dup 42 /asteriskmath put +dup 43 /plus put +dup 44 /comma put +dup 45 /minus put +dup 46 /period put +dup 47 /slash put +dup 48 /zero put +dup 49 /one put +dup 50 /two put +dup 51 /three put +dup 52 /four put +dup 53 /five put +dup 54 /six put +dup 55 /seven put +dup 56 /eight put +dup 57 /nine put +dup 58 /colon put +dup 59 /semicolon put +dup 60 /less put +dup 61 /equal put +dup 62 /greater put +dup 63 /question put +dup 64 /congruent put +dup 65 /Alpha put +dup 66 /Beta put +dup 67 /Chi put +dup 68 /Delta put +dup 69 /Epsilon put +dup 70 /Phi put +dup 71 /Gamma put +dup 72 /Eta put +dup 73 /Iota put +dup 74 /theta1 put +dup 75 /Kappa put +dup 76 /Lambda put +dup 77 /Mu put +dup 78 /Nu put +dup 79 /Omicron put +dup 80 /Pi put +dup 81 /Theta put +dup 82 /Rho put +dup 83 /Sigma put +dup 84 /Tau put +dup 85 /Upsilon put +dup 86 /sigma1 put +dup 87 /Omega put +dup 88 /Xi put +dup 89 /Psi put +dup 90 /Zeta put +dup 91 /bracketleft put +dup 92 /therefore put +dup 93 /bracketright put +dup 94 /perpendicular put +dup 95 /underscore put +dup 96 /radicalex put +dup 97 /alpha put +dup 98 /beta put +dup 99 /chi put +dup 100 /delta put +dup 101 /epsilon put +dup 102 /phi put +dup 103 /gamma put +dup 104 /eta put +dup 105 /iota put +dup 106 /phi1 put +dup 107 /kappa put +dup 108 /lambda put +dup 109 /mu put +dup 110 /nu put +dup 111 /omicron put +dup 112 /pi put +dup 113 /theta put +dup 114 /rho put +dup 115 /sigma put +dup 116 /tau put +dup 117 /upsilon put +dup 118 /omega1 put +dup 119 /omega put +dup 120 /xi put +dup 121 /psi put +dup 122 /zeta put +dup 123 /braceleft put +dup 124 /bar put +dup 125 /braceright put +dup 126 /similar put +dup 161 /Upsilon1 put +dup 160 /Euro put +dup 162 /minute put +dup 163 /lessequal put +dup 164 /fraction put +dup 165 /infinity put +dup 166 /florin put +dup 167 /club put +dup 168 /diamond put +dup 169 /heart put +dup 170 /spade put +dup 171 /arrowboth put +dup 172 /arrowleft put +dup 173 /arrowup put +dup 174 /arrowright put +dup 175 /arrowdown put +dup 176 /degree put +dup 177 /plusminus put +dup 178 /second put +dup 179 /greaterequal put +dup 180 /multiply put +dup 181 /proportional put +dup 182 /partialdiff put +dup 183 /bullet put +dup 184 /divide put +dup 185 /notequal put +dup 186 /equivalence put +dup 187 /approxequal put +dup 188 /ellipsis put +dup 189 /arrowvertex put +dup 190 /arrowhorizex put +dup 191 /carriagereturn put +dup 192 /aleph put +dup 193 /Ifraktur put +dup 194 /Rfraktur put +dup 195 /weierstrass put +dup 196 /circlemultiply put +dup 197 /circleplus put +dup 198 /emptyset put +dup 199 /intersection put +dup 200 /union put +dup 201 /propersuperset put +dup 202 /reflexsuperset put +dup 203 /notsubset put +dup 204 /propersubset put +dup 205 /reflexsubset put +dup 206 /element put +dup 207 /notelement put +dup 208 /angle put +dup 209 /gradient put +dup 210 /registerserif put +dup 211 /copyrightserif put +dup 212 /trademarkserif put +dup 213 /product put +dup 214 /radical put +dup 215 /dotmath put +dup 216 /logicalnot put +dup 217 /logicaland put +dup 218 /logicalor put +dup 219 /arrowdblboth put +dup 220 /arrowdblleft put +dup 221 /arrowdblup put +dup 222 /arrowdblright put +dup 223 /arrowdbldown put +dup 224 /lozenge put +dup 225 /angleleft put +dup 226 /registersans put +dup 227 /copyrightsans put +dup 228 /trademarksans put +dup 229 /summation put +dup 230 /parenlefttp put +dup 231 /parenleftex put +dup 232 /parenleftbt put +dup 233 /bracketlefttp put +dup 234 /bracketleftex put +dup 235 /bracketleftbt put +dup 236 /bracelefttp put +dup 237 /braceleftmid put +dup 238 /braceleftbt put +dup 239 /braceex put +dup 241 /angleright put +dup 242 /integral put +dup 243 /integraltp put +dup 244 /integralex put +dup 245 /integralbt put +dup 246 /parenrighttp put +dup 247 /parenrightex put +dup 248 /parenrightbt put +dup 249 /bracketrighttp put +dup 250 /bracketrightex put +dup 251 /bracketrightbt put +dup 252 /bracerighttp put +dup 253 /bracerightmid put +dup 254 /bracerightbt put +readonly def +/UniqueID 5021339 def +currentdict end +currentfile eexec +e98d09d760a3c22cf119f9dc699a22c35b5b35ed6aa23593c76d54cabb5e +942bf7d6dd84f1664b89699c74b472de9f8e6df925f6c4f204e9f1c639b4 +dba988ed2ac419ff2b2bde605b8ee3264edd66412d4f21c64ac522bdfc7c +5502f9c3f3e5592b3b2093d33c9bfaedd2d49e89aabaa832e23f062e91a2 +5032519d1868816e44b4e0747795003d7930299d6e1e2a5bfe0d595dc97e +140989ce81d8d7f852ff9cdc7a1b1b598c69131dee005b415805a16d8a13 +e5927617ae7f247a71ce0c7d56afd75d85ed2d9f20ff9a6c38e8d5205197 +d08780180cca9c35522b1609b501724d4d6400169b91bceb6a4de00afc78 +1cf8873012b3117d22a18587895543dbc2a1ffc7752376decd4c92a69122 +4258e8f8f113f2a5cb3d8da10fe823c6656a8800cbc7ffd018a28ac2885f +35e22ef9fb549b00e23d31bba304dd9c28df02a8c370ce49c58a40c9f673 +ad61f5abee9d62ebac590b5a44f2babd96e137464db066b602a5d8d43ed0 +41b780f0fb98f9952f20ad8084199adfee9ecb193c018772e63a5a83bb06 +00962fe724f63351b4b7a16412743ad14a38418877768af423e3348d48ed +773c2e87624cfef777a15b6872f54488e42c4849ae6d54cb857dc0972e1b +57c88f40b89928ea43c18dbc73182f69b52f0bd66b7133881676616ab669 +723240f17d5eaaa27c8e295862288dc30918d00008c9592a51f39e30ddc4 +62f6287654eccc13fb9525f6eac5709e952fb237e8cb0870cac5ddc13da5 +8dbd060d3193fc92e6c4cef3bcfd81ce6b3679bfc5855796cdfa8a26d63a +659a2ff7a1a7e318a7f76ff80e846a2d647d38e827ffaf54bd5a9221eeb4 +16a475eabf4ef0409b3cc15077e01f742c46ed43ca72924c32e48a786224 +63396680cac363406c524a9b3b768cd5a6892643f78b7cd65c610ebfebd1 +058dfeea67d8a9b9afd9bf39033a56856537c06f75bab0a47079dff64cf7 +343cd6e7fe7bb1fbcee32749c91435cb86f7550d505c81deffbe1e3a1f63 +04dd03cd20842b335d7fce6eb31f175724d51c184800c3756db044e2fe04 +bf53e995fb425aac96fcef384c930334b5f384536cb3abd98447844babf0 +4ca767edb70786132c796cc2f6530852275ab4df0c8b4d2eae01380ed24e +62f5a85dc8345d556c67f00f622d32dd66fe18219169daca3744a819cfac +c305fca9471a0de5936e270e3b2d4e1211d9da8de26e790c6f56c2ce8b19 +e175256e8bf85b8e52db7da8c44fe52e57af48de9b771658139b6b81b360 +92ece2b629c0f64d31d62dc7d422c2a204bc0414cc6f78f4e975bf8f27a1 +7cc3b35b31ed313b5274f487a92ebb33b02af472ebd84c4b1b4006e5c522 +8a6f7222dab490259de2223f4cbcdd006a6549f08085eaeae51e4d7b08ac +c8b08e8f98dbf79ed4220132a755c007366600fc27e0badd73c875074b6f +211da05ff1454730f3ddfe96d36ca12f8249cbe74c82a940f1d60205cd96 +24aeb7824d5b0a1578eb3fd45ffdb97e66bf0faa27bc25e631c20674e7d6 +db5e4cc7b10f3a77731aa3a53a187e5211da39f2e97c0236e36f8714c49d +630e6e1fb42206cad9361794a9e002369ccc6587f9a4cbce5cfde26656dd +8a36663ca82efc1e93cc58863e3a290090906220923f544e8ca05e5c8377 +24afc674e6008278fcc696462cd7986aa3b884ed5c17f9d035b9a1a169d9 +f8f28875f7e5d7bab34668b61d026f77e37277d53e9e0467152f6ac7ab56 +ae9206f15177732ead7b2a003799862772b241d65818c0d2d6c53fd0945c +aa1719db446f7ce5c383f28bb1f419f023f3def204e895b8057407648efe +1973dc8f7b8c17abaa1716ab69f3bf0575f564c3400fb55bc430f455b266 +871e7569c39a81bdb082fa5134239272f9d69d2f5be493292555a5115a0d +bdf30da71bdda418cd5875bf2c0ccf00e236f2c97056b102e8e014c2c118 +a76cf79c10fe2921d32022b8f96443bfa1b34189e5c5abcfec51ad20cc45 +08ac5376690bcfe01dc8f924fa190a6f1295c15c74ddad5e9c4047ad0145 +76858a265ffce0be9e77e763e911bb662359df98dd767367dae1b686eede +cae1f0c9cbc54bc4cd46e51471256bd340b338c38dcbd6d327fe6d2348b4 +eb2a1c95bf082f2e4a1bdadbe349fb331ae9ea002c602097746265455a5c +60a7c0bbd2f407c8a7e5fe9fbea4bd8ec9962542e2e3021a0ca40f3b3ffd +b790592167afb21dbbb9eca9012d06086f1de6749ff3c63be36e0a55a9a1 +03406d8ccc095975872fe895b8c43a2a445afa5e03c7902489d4f4c4a9ac +829121e532c6604c059c355652fc9c2f16a553d5368ba0752dfdca4c0e9b +944bd1c2d115c25e4421ebe412b171290ab0d0e5b0b2c42bbe58a4eb39ea +61c710496dd8a4f0de76759f5d55f557224a4b9549cea21b8fe277fc5848 +8fc369d9c0f1a3dc52b8542125bb42561b594bdf33be43aef93f00ee5c60 +274affc05484b0011d8c465f56bb9d04feb88b6de54fc2104b07dc5ec8cd +419d9f597e5f4ddfc0bbb0e920629fdf06492bec78c970c1e6653d4bbf92 +d3f1cabdc4fbae380b22f1db6e8aa9b050e33a384d5cad9543a3adbf91a4 +a94059705d20d906fc7ceb2577ca5004339ecbd2a3679f29eb43c89247fa +11350bad35ebc938bbd745f774727de92eb78bfcbdb109c54022ad09c21e +85600dcb70cb1b51aeeab9cce57b8b14c54eeb1e956a8c39617472165808 +22c531bea4051318283a3cf1f612360b4d3ed785ec76c59ea475c15b15e9 +e19314bfc6a12892491cd9d7cb3afd9020bd28b685129ef9e2c151c59599 +f1e8e13eea8fb5746cce8ae317691a28d263c77714e5f401f9edaef085b7 +2a86a9cf5dfd56739e3bfcab4929679ef111d23378a443440cf9523d3bf2 +3f9bdcdcd7f2c40d75099f3777e66f6e3f1ae4def3d5b062ffbb2fbda4b9 +38f80f74b6be3032bba77f99501878567f48a64eb09f1684f095f8b4e407 +a78c964825abdb71faadb42aab7c41e146ffd21ac742574049dca257e9f3 +d4ce46d200f776ed7915eea1915e321177963dedb2a24c8701d70a265856 +8cf1313fdc4166e6ea59a4bd300930911c13b7bf4e72012fc99cccda3b8c +6d07febf15c0a15c01b220a6dfbb1d80ceed73812be525e5b7b35bad9b67 +72c6673ca1f580fff16f3c96b9b9b7f041aed50cdfcf7246db20787436c9 +e2b8706d38591372badac219b83ddb3bfa1af853aa3a7da41b16bdf5e42c +8277c2cc73c1c9f668931e66ad5523d435dbe68071d056cb8fe1de179c52 +44cc511d40bba8311d976a2120a6c46e85b939291f60394c911e30a214ad +03bfe58a03e92fc67bfe81b828028e263650d27b064558e3eb72f01b40ca +4cf029b6f1c1843193fb23721f1f6f19922f821c28ecd4340f10e96eb38b +788c589cb8815bb708b0c46c378e8c16eacc72ccf9ca0b9ebdb0b4906af5 +8fc5cb8e7d62191f1c11943bb76d82251258c4b251aa9561d42adcf0a5f9 +18491e063b6a88cdf4e0c8d41c968d57c6e3fbcd6bc618d139a687303ee1 +2a6b31bbf23a04f19590540468bb12bc46c3e69f4bab7d195a1fe7db4098 +09f5a6b0178a77a4792f69c23489f5034379b4a7668cc1c9369a36f8951b +e8c85e23d2e47dedf3718c0a2adf816acbfbda1d46ae86293448abc732db +99c17a6e747dfe204cb1161c9430ada3787bdb924556234f9e2cfae7571f +9542fc06c7b7cc06f630d43c04a454c2dbd1b23549311b03d8bace01fead +8e0f4967f514ad83472957cb2fd7661bd18215af416609669e878c72e1b8 +f692c44911958cb98bcac7c3087956e5369e6f41f1603ed496f4766fd351 +7e88680d37104f5455d00b7769aa1eb0497d65b9c53952b4ceca60add156 +d91f86c60c6e683de2d67fd900e00aff558004a66e12a9c1b94b2eac6162 +c89610943e65de52fc63a8ff04c6e0b80cbfe53e15f94647c5ea40ecc42a +6bdbbe981cc27fed8df21369c37012087ce77408b77866ecb381f0a1dd65 +1772728b8e07728bc82ad72225c94c86b2451d891c1e1bf843067d38ec94 +23a269daaa3d71eba07fb7f5982bd73ccf01c615ce12b396f656d86e0e4c +62bff0305566cbc839b1843046cae4b57993f86cb5d5ee8a5381c33f136e +01b779492e3d0c86787943046324887eb4e927307678f2c8c8af15d5af78 +7584254e99baf1e3345d89eeca11846cccd62bf08b6c3937f7a3d816ca6e +d30c71999a392d34f04e502e01934f2df047410e72b50a53f11079103502 +080e75e0314bddaa9640887fd0b2d248b73e8ea80bd8cf69627f0d345a73 +791f257bb59b3b0a76243bb06bd0b1fca3448ef08f012fe7d6960d592923 +b13a6962b0ebeff6ee814b6cb369cad2399a3b3e39ad7f0dd9c32fc7eaab +819eecc9b3fd971231a833d00bcf78ce224933c40f1fd31ab11d89932ed5 +6046d87bebeb0d04dfaba88f20070745a4fa25cdc7f482f6a29e32d5cfcd +50fce23a1281cc914d9d2fa2d62114e00293e2e74e25e99ce2db0696de78 +b67bcb47ae793721e6958c6da47368536a5c9f9fbc134ddd4d08bf5c0b2d +3bb4f863eb2c0e88e8699645a41ade9ce5bfc877d7c3c7bcab236fb508e5 +c8fb6a1c33179670e294a7a068199581965c0ffd8b1121f4632088bc9693 +14d1319246e8c9e4564bc6bbb723698edd949d12560b33f770fbecbea8c2 +3beddd57e08c9165420caf1b354852b07b6af70f0352ffbcc71c9172d62d +85c67bcd90cbd733491ecf747cca756250fe5093a9b8457f0fab6fb3f365 +cd1640e30073d6f3596f896e55d1c0639573284be2be1ca00db036d4d055 +274e620ec875c5d16f2689b20865bae0f14b1453cffefcac59fe0f76be88 +d16d5faf229149767916eee5d37e4b2b060a3a3735fcbd078705fce3e795 +443568c6b74b1ed8f40c7126610bea528083349c2bb60ad9c15edcd2588c +09c71e5399c0df7ee8e51c4bf67891ee652533564d7e5af2d8910a9879dc +a382ee62378e2a3c7edf7437b5f639b633ffd5afd3455a7b1da9c4c7fe0c +03ca927bc933d8821e2f9b7962b8e775717629e24bc980be517eabee67ce +87203d0423e856f10e4a5b7016952f6928a1d3080aac0e25630b19abd7b4 +bbbe3ec959d60343ff4df715455ea45b5fe5a6e3fcc77ea118037919b2a2 +b1deda705afd532431be9ad75309ecf826af7d63eda6c1434b06bc5e9acb +43ee209e7b6bc20167028ca785d393ba779ce7a174a8988c2f7623ccf2ce +9ac3c8982c865120740bd7494ccae328bb37aa4873ffd99c46d20059c1c5 +bcb9aca5e0fa9e1200d12545df876c580e1ecd188295a790e039729ef939 +2117044e157051ce87ef3fe59bfff2557c7138d4c630680f93f31dc51b87 +cd7fd8d2142e16b89b3abffda36ef051b5643c4f533eeb1f8ac18df70072 +9300d3fa5abef49b53a887fadb0dcd5b3e0b22d988c2d607dd2c9f5106f8 +3a521e755684abf21960a0f9033066d573df043adf95f7c8e9f822cb1fbd +5eed34d0550f44fabf736a5e6338ab99cd0ced9c8a27090c85b498199c3e +b567f2e92567fe87b20899a3b6843d71d43b28b1c20de059c102c0580254 +642f24efd11ec8ac2819ddabf1ad4b1cd9afe92cc0e46e194865b980b28c +d543df06ac23efc9c64cbee9d921c29c696f47bd8e700b6d7c1d052e75f7 +597c5d513c76ee9fde2951cd86703ff6824d2f42d4837893d2bf82349260 +038d21e9e0fa96ebeec822f6e91ec01f214aa9d1b83f0b732cee3974019f +feee359a25bd36b0b8e8250dbe1935bc0ce2c33bbcc6d1e7023630c885ae +fa7a770fd3b1992ecd9aad06a13dc58f18fe545671e54c71b8f5e66d076d +1901ac6bf8e874ca84054815a145a7bceff0787367b58c668e22028216f6 +27267f83f279656f6b4fdd61fb071241cc883b0060fb9b8d74313be9c271 +fa13ea9640adc53564f2d2a85e4d1799b2e5d04b67f13a30914bca5597a7 +2d1456eb9f228f56ea95d1abdf5b4332df7892b23c571be72ce474a56854 +88e3b3eb489b6de3f5e3fd5435e3cc6bce8071126261d2b9255417a050cf +5a286bdac485a678009cb3f7b4be9a245270c08f92f339b57fa9cc899b8a +df5f73361198781480c3b4d6a2d8c65a60749a47cff15e761a0352c5ab72 +d1df98ef57cae899dfa9d8cc7fdf02c4fa66fb90a68b8569c277d99376ba +317c9e6e59d7971b3fe53daefb91fd05e32fdd517b0b22a636524b4bc23d +7464bbfa592b4385d006a495c0f74684fab0d2aa4046b8721cf503e16e6c +6a65b54d929212a796134ac6ebe6283b722286b8cd869c99a5b7f9b3506e +ad333ebf2e6b9c97f15f0cb8046f0980b0796857621626ebc802d5f3198e +d91ec321522d6fa84fc3bc752f6a6f47fc2c051ad193ad4e406ca0150a9a +77de9371f832d3aca7a84ca8c3f7d97dc5e9485c4f2a77ef071919cc90be +7fe13618a4a9bd73870a968cb8ba24688708f485c15872888220e73aa662 +368f410ef76b34655663c54aaefee827b7c553abc82543fa8e8dde1323c6 +040fb8f24fc213a188f1949a4701b73c0464ad9657a7535440307897d816 +b3e4b6daca7684f92a4b74262d772969dee711e4ed9ee115fb7f91bd9d1a +3d40325f135b2e037350a36b43cf5a4cadea68aca368f99278fa5ecdff0d +10ed1517489c3e59568cf5676015d06d296e7a26013d1282b0be1aed1e1b +0b72a9bdf8e8d7bcc14633875c07cf5cca202965c0ab8dcf250c33990073 +26ca40b0e3b45a9f82e601b0f69d362cc9352defafb017f76710f829dee9 +f4badfcf550c83868b5100ac893517a84e0dd8ca2c0dbf356e0a7a533080 +ed1b39de69d1a31f0d2fc4d80cf09e75a82401b9e205953571c2988cc68a +e61e0c986e7631b822ff448098f015a925fa9589d4da4f0b47413218a6c4 +542d45ae8f328318eb676944d9cd0611263ce4f1bec8470d1b8646de66d3 +51646200b5a3e8c7a76940544cffcd6fdc9824275ba4095ef08f5b43cf24 +db7d8b1a0b196e255bd6098dbc3f9859d49a159c692284b52eded6320230 +6487c99740dee252eeb2ce6a53479eaf7fcd6057346b6a83ad3578e65218 +ee3bfa52f9fd7052dbb3b3f841887cab19395f64779f64d3f9b4a3fe3947 +b6a501b68bc288c6ef892f34f8e20a94605b6c42df84d61edcd000dbab26 +f4a1e7bb2da0a926ba762b2112bc10921b387e100d9db20905e27d47f0db +3c7cc67f29e4efeb6f179f144b83ae9493f724ab589e94bffbdcda86fe2b +b33e6158bf1547321015d46e1667a22fcc7c56d3c60ca255105cec8b03e8 +8bfa66950424e879d6db2c4ffd9d6df35ab3ecc8d5da69916784e274bd3f +c32077d6636ed73403105506fe86c7393d6da5c0f43a8847efd46d2999c2 +a662b2caee14ad13e48f1487f534b666bd3882d5ad91ded50023840c3137 +5ee1bfb540190f11c953c3c86c0f66139e57ec50aad8fe9b0aa154250f73 +c0e12b85b42b52f46b7dc85ec0610ccdd08c2f3f7a535fd609897e472be4 +a4228e451693921ed1f6fd9bfdab638da15123f3552dc8be0530c8a76e85 +f59e13d95b5ae41d3171f8c3aa8dad0a02c3749e2090c6a795d53605340c +4e9b596818aab10ca126e84f9023c81bf23cc73f61ddc66199e562780ade +bd2e903547098a5915fc7268198af301c501d59b90f5bc507da3b2fae272 +8746cbc4ecdadf62aeb3ff1952d7d9f1042ac5448a77f360b34da1e782f3 +f10194b3d43436b4117694575f7611d1e3427f7f7814d94af7f5c1fe268a +fd82c2e7e9e3f6e0b8b5fd827db4e7b47e131793c6e29b33c9b0857435e4 +d57f515ebc299023a438e174150403c894aef50c25ac5aaf7f872055faf3 +c1ed0144a6c1028e252c3af250a181bec8730283a087845eb774d9d64fb8 +e73b3770b41e7505e4a502ff355e3f7582f329702508549d5e0751124455 +8145d9c457df485615592593827f8e16e0c392019e9bb9afa29d2ec37e28 +f55f1d812d3f552dd43e9a707fb23652e944967b3da009453d8418c0d709 +021b3d6036133611532664e92eb7cc78a0aaea7ec83ed8353551b6d7ed45 +71e466e55c00da0929645b998c12f2969d76a27d56ee94d981feec5b957a +0ca637a04a3f0ae1bef57d8a83d1a1593fe04da296482291409185f0e2ae +09fe4c2439e2f4579f54c784c5a53d3897b6af8b095b9a98054bf89febaf +16c481f356753c8bb80195bd24445a802a0517ae0944eec6307996f8381b +2d974d7965e3f3e92296be91de6c548630e726236c658d9861cab98b2572 +79432fa474854f9216ec7b6d27a1321a7b670ade7265c10b6aa509bfd3ad +fa44cc3a1d33dc82dc4c1b139d95ddd7a2316bfa26c608b40a36ba9bf92f +441ebbc83a5d0b4627c568f65d5c05372841627a8d8e3059d8737519935c +2215be69d4c5f60d4dff230a09e72431c1f0ac9885920574775a1224c3c5 +59b0f340085302d07ad4016200443b3bb065cb076e898381faf87af0ab61 +1a55a41b92ed6d9510951751c0ed0bcfbceea792ff6b87979489791dc83b +88e74770c07df34e782bbd14377b0399025b011c7db92ca2db7d08099a68 +e395e9f282f8d7169e4138dce2824e053ee76f6de8b58296ba38b0d9d273 +e3a4616f60f291dbf4346848e7dc0af3b63a76d83f06abcf2175550a55b6 +cb4a3168f0d33fae389e0484ee677bdde16c106f39bffb37f90d8912ab66 +74a631a3e12efb2e0391bce42a1db09812dbd0fb0bb01abb134ebd0b6eca +134a7ea7e0ee66f809c46e5fadb70085d7f0c8f7d78fa864f241ea501bdc +dfb8fb1d2496d96ac23337156cb63f9921bf84b06a7f9de424edb09070d0 +9efcfcd32a7061c990bfa088174ec45a0f4a385803c664c22eab041b71cc +959d9f3cf8fcb27e6be9d7e13618482c30de5425382fb964a3bd82e7426a +8ca0ac81a8c09b6c0b416f33c54a45c4f57bbf1026a12c5baa1a5540e7db +5e954ee101c36a703623a7290ce302753ec158b65f810f7c46c55c7f9f12 +7aa3945fe2a320a6aa49323125c85e174a828c559783107edd7e3967bb1f +5c6163b9a15b8c9d2be84419fd9c0f36018bde462b7bee204af15eaee3e4 +f5fe39a269742ba5398bc6dcdbacfd346699a28b8d708e8b09ef00c4ffe6 +fc8be121ce97ae6d92b042895344492ad9a66932913563025c0beb65ca34 +3fbcdd121e126c49692d52ab4bcb715f52db80680c0f55a2201b22c2f263 +d38a89cc8981c56bcdb245805347a797d0d71e02a11b8238fbc242456250 +01ec6890cfb1a0939937aab82ff635de52e47d62cbb38d4c89523556125d +761efbee56916f2ed351a8c8bedeb375b400a5499ef7cc7db0d9d7f60647 +c3416ce1d505293ec1289cc0181479b28a71acccd35d1c497f628443fd33 +291a48f7afa1d6a675ae2baac9fbc4a189fc04a4420b91e3d51ed1ba42c2 +aca67cddab41638c82236f66a8f2cef2c66a33d54253b5609989168e1cb5 +e92e9a46256a87104f0fa8390dbbfb8148d7f900b9634a3e67b0f761bff5 +f4160b2db21528d0a4d55874eea9f015d952cb8ff88f3afe834fc1ea1de2 +73b9c0048e45e3e2aa57e4c092618b50b3c1f51521d03e9ba74389ab4613 +b0337d2c74785f28eee574f18178c167e6a3b5a5f6613fbe58b584a35322 +2458b6e54ac8aa08f31ab0761e1567265fff40cb3e750963f8179d495c22 +6284125367d1ac5d188f5ca6a9fe0f25125f30353df54e96e1f6c511c938 +e100be0c1b4ae68d4e3333794f0bc95d9ae9bb517e0d183cfe88e0483bca +95780fb6437cd3c2bc3af965bc6bc58d845d3046ce5d12ec9285c1fdde31 +4660a960af7e4a7f07f90f950f06c77be9f26fa91f14fac8dd904eae790e +d216e7cc22ff475f8f462e1a46bcda71a9d65d07dedc038d00f493b3886f +674983dcfdd7d760fbde7baacd78ac12f18def55886938f88b99ad4fc8a4 +20cbd6003615d4e31ff2942b35f72c1a1fb13c2b22625273f715e5d89a4d +fe43e2047562f77e9c8e5c2929bdc7674ee9beaa8c7ce8021d28492d5c54 +768c002a366a862bba99390be487e4781513b80a7bcd5d47dc23541c9a55 +b9455c53e9325d0d77fb0390cd7e12ce2e4e34581a4ab524a6a91fd3bdb9 +e07953447116c7e4f429a99ff6c4c11b1ced99e51127c30904bdf3ed12d7 +261c31aa4833ac725f5597b3c1170a4892c3ccc765f02129442d491b1227 +0413a46c92c9b83d41eadb08c78037a1c8630599695f00bd7c8b29841540 +3aec630237432f7e6f753851cb3588e229ac8a0ee375d815ac0c02250061 +09bdf8e0b496dedd2aa9cfaa16286a4662e256778b125cb4db05d252aa66 +dada5d161ef6a5971e9ed85c913d1befa7d862aab7e16bc95e03956460e1 +f55aa7594800600d5f0d1433ee8f0f0be4cec403cfedca52734645826eb6 +961af0c4e1dffa69f1930e19681539960eb58bc386fe31f266f5e10b13be +4d4f46a29ba95403e705ca8dbcdcc03c273509d9a8bded6e6118daf7fbc3 +63c7e784f8306f8eeb7749cc6d855ed29f99c7ea8b43378c12738fb813fb +825cdead8a664e1fadf11f7ab84fa7e4257bd1ef7fcbc31e2da8a8582f43 +be6ae0fca66760484c5122cb38176951449919341a9eb60093edceea347f +f83a16278c37a9ff38202b27a4f75c066fe443a241b630149c585750e2d8 +15f627a1254276dbeae8182270f2699ac1e78c6a09767e296a646e5eded4 +843d2eb8a68673ac5b81e06510db64872547a92a4bc851e768f43da053a6 +bb3be89cbef166e8a3419eede1b97df88a698c0f5f864d81b5c4f7ad97eb +f78b4ee82ccd71a34c398dd3f74609c555b7653ce27e78be0de7caa11de7 +8fcac0e0293101a2a8c5545941291c56d4957fcd65e36ccc57c8c9dccc07 +407a11f5c9cb214ff508a5f617ff24f0b617004d6787eaca97296108b8b0 +0276f3b7e28af1db998c36ef517c38d96dbcaf33deb899a344a6c047cdd2 +662a02b94f39ac528a21ffaafe364770bcfb995f62eb0c6d076f12241f72 +e4b284f085a3c6fe9263f879af8c049979f51ebf49314dd0331e935f94f2 +a58a107906c2265e3bd6d644ea75c928ee81268e7db0d2b61775cbdcfce7 +43ef1ae9784c4a9b2d4eb0d5bc2651d79f108306722670399d2a90e45364 +67c00de86ff4a4f4a51176ed721ea3a1c72cee354c54f62db4982a566307 +cfd320d6245bc3108a054f44b3f4f61fde2c84ab416d1816454430b6468c +57d86c155218c6f05fae1fe22a7da461e960c210ec6e44bd7fea797c1cc6 +b63f5f93e75bf6ce42dd559eb1e97a8cd01daad4e9af2a544896f6e597ed +16d6847e48539d0fe0c1df99298630ec2b465dd037ca7617ead304993972 +4bb3d428e9137dda6709dde2e72e16c80cc960cb85f1727bf30845fa51fc +a8d52b6099a65a0cdd444daa35534782ae347cfa7d849ad3a93749db9041 +03e597f6dd56e032025f59f7b724d1c947358099ff3b336e6d688b72bd11 +5b86d6d0c54dd457b7bce443524cb0718a82d6661fbb05673b86a3ef66d1 +981788039a1e26597f2f6c51d055b1de1d32145d39b244c91eb3efd23c3d +4b785b96296acb8ce21882b4814ca4d25ed88a3b6729890cca8843c1e2f7 +46289b4e3bf5196e268c5c08e52670e875aeed4e9cef6f45a70d6f944aa9 +518c2ec860d163131b66e61be344aafa0fcd4b5af24830da2e9811c4024c +b807af29ce56a577666bb8a6ae62dd780f3ed028352dee9b6aef748349f0 +71f151b9b33a5c707d690cacacdc1fbc8eaab920d11c4ebf406827329303 +32a7542c002ed0e4ef2d3cc5a611a48585fc0097426f9710d6dea70f1ffc +a65b3d39c875369a91c045ae73d2de28b548f6bd8d0d76e874655e7ab6ef +5bf9a4e08e12a1ad867ff1b70cb0f2ac3d198d5f70c3a251058291d7f537 +e66af56c87c11916390b7705821107c658d2a403cf1c6cac79137505d904 +a6e31f34ef23045f923ac40aa9335058ad760dcddf43aa9b516652fb81fd +e901d29cc3d2ea99c42fb8cbb10a5cfc0403c5db7256c7d3ad11934d3fcd +cbde7b87e11966fd3361210cc511459cd82b61ca45e208a92edc040cd58b +2828fad652ab3846c0415fbbc503c9251d7fa661fb8e5fd167fd3e9df8bb +17a52d2301c21f974b16340ac7e431272b48895f837687cb41ee7595a826 +315338d997fba43a9f8a0a9067229537c85caaabc2667000e6961f5ca11d +60d3cb970d0e059e7446f1b42166292d96abae83a185ddeeabbff0d9da54 +ced5cb12e782a26b7128f0da66ebbcba7f45b6d4522a3baafa39d764b7c8 +3efda777dd173720d41e0c494949372f9be61de175bae4ad0bf8d788b3d5 +032bc46e95821290cb6c665122220ccd6cff2544b3ad1e11ddee3c0c6531 +81abe20f6a66a4e898eb48636a8d6087fb79477aaa5419b785dad54f49ca +a8c3427f2973a49a5b064767afc3b028fa53ca96401d912a71514abedb68 +e6a41b2dc619041ae1b798c1d6d064478ba17c0d040f73f1d158c72fef16 +0d30b80a9ee8054ba8860f69f2241a6926737a040e06fe294544a393fba3 +8e9d850adaaec2ae183b12fb776c82cb3460db4ceeffacfaba629c7a0edc +662d8fc48b59db18e8c5908d491359a9c1dabe1418b46978924cd0028f1e +19399904737f41ad8de10d4214d05d6a4db485cbfcf4df0921e4e629ab83 +4a695c317b791baaf902ec59231b856e3e646868ce13fbd5cc41b6fdf3e4 +d918a02efaa20aab7d526a04edcb2eb388a2ccbceedb9d0b0df1343e1831 +7f46a6054c2bbb14201a92afbc452c760f16e12cf94c8a901f50f1263e01 +9308c5aad246ca64570b122032948bbcfe1152937c2c32b764f78bc24817 +4a72a706fce7487ee6c605d48eafc229c9206077a3f0fe0868ad5fedab9a +9b07a7d7d973fdaab891509a8c8c3cb9862bbfe04cd0c3505df3ea8a4b51 +981705b38ff503abc17fd88230bf242fd737314b9d7b613989438d9e0f71 +d5cbec77f1d93a517d9fe08e0aa138d3aa55c232f493ccc1f13ec45f2e07 +5bb3a95f0d4a32d5dd2176a06bcbccfa8d0ff2e2200ad6f2cb91d325ee48 +40ae4a27c8709eecede5682c0fd5d94d570790e304b9b4fbff08852d9895 +f7faa0464f625e7d51f3fb5424ee25e89da33936de5f313d13f3a5c565e3 +3ede87b22cad211eb58b70f671f5a8c473a15898ef3d35c0d496c62b01dd +a1963999d313b475dbe8aa888a4d66cfe1af9c86707d86267ab18fbfede6 +8848bbb9dd5af6a5817b5594c6a74dae1cb83ebed616f7bde4a43c6a3811 +a7f0b6ffcc08894d118f53828d5c55060eb0acfd818cf991796a9439f733 +9482c925946a5e5d7b55ec7c9f0f31de88caf20686ff27415eb83022c7b7 +299f23cebf34a766a4bf842de6c113c39db711a6291ee66abc42e4021dfc +43d91aec3aec56ffa48fe9d555d9c435ee363533fe2195111b9483eaeace +96281b83962fa3f7e0c57a2c3cf955ddd8774a263ee61b2d43ad97b0cc58 +d4657bc27aef767215cfe5c9f7a87df9d439cecf6124baf26e619e7d7a0a +ffb678df6eb3d663bc9f77aacd75fabad0b41622c3d5ac9a78a432595715 +5f36c9dbe2d1dfa81bf0e11e0512978bc8e74d30b73fc9fb783539a1c132 +1b893b4ff9787084185280967b2d2df72690339994563b8abd371ffbb832 +3c4105d304ba0a184568dd1f32d88aa56724286535c33182fb59830f88e2 +d878822b1c0202b3d34fa70a1525e5f06bb08844abe54e98ca304fafdc6d +c9522871eb5e6c838476cf5c15a43c694d7ac26b04f8c0deaf7f0cb0e44b +0448e958e31374de9fe5397530ed700e78e09edeaba6d006b5e82566c399 +afdd754ee2638ecc0a2f59a1557a084502ffefdcb7e9b32ac98eb2750038 +bae5487dc255d76461273fa3708b8a1af0397a2c985f45a26af331286e27 +dbc1e5624c7eb27d87a94a8bbc5e2a67f78e9b202c2298ee390f8cc3581d +407f555d2699e827058940d1c1c69ae67209d354da032287f55668fb6034 +f5b96919fe361fe6870ef24c914a6a1e98c9b1bdc745c71ce5d6111e67cd +d5b809b8f789151baf3a208e949c8c7f69bbbd5bdda2958e444d960746bf +955ffbbc82e88724e54a0bbb4e86085e079d60472b7d9e2e38b58206d7eb +32bf5459005ba2839a007cc41d41c019713f17b1e209da9a2cccac58a9b0 +e39bbdba1c0e4aa0ea12349b64271e965fd0b5f5d49955034e635645e76d +cef521cacf68df4ca06557d0900699c52ca3286f682215811fea8c8e7569 +bde853033e165bf1670f1b181988da996262bb0326ef9591bccdb4d48076 +86451d5842d7a79d5e5f5104528c89178e286a4115b9ecdd36cc3b1a08f3 +1c54a2943027de0114ee35d096379c1697ff60336155741cb4669b3ca41c +6ead258f7d29ea3b4c932511f697eeda22b90c000ed5df8170f0e189b110 +13e3852953c2fa2fb21907c5e19b8343fe43529f7219fecfa8b4a7bb3e01 +fc74eb2dc148940e332d1f53f4f7226c78b158cadf82d756b21e96718db7 +7ba7aca31fd5279d19b1cf40690cf3f7a3624611bab4a7b0ee77b4e30a10 +9bbc1549d0a6f9b6f7363f73226ad19b9295824c1523a8ca0efd878cdf81 +e8df64156d7f5f068730eb304abee1344a9f8d366d0540e913d8f79e9da8 +044de90066a639796fe62569c78ad5e52da7853b5cd251737fced1e17e75 +73b5341ae6927ef38bb57a84370ccaa506bf9656ea00c7d65afc6a7c6253 +42f369bd932745fd4ec25a5afb57c9bc0c8c82de8e9e7390b16064efffbd +151d9e169f42bbf5ec9df52cf88289ea9d829a29a561b03ccb14bc6a0cc6 +277cd53524e94c0aa173d4b72d3ed2fd7d7dc7a25b7cb9b768310b885a99 +480337ce2c11fe903d7fc5b59376c93d6c169d25b9e8a2cec8b5d971f77f +0029b61d36d9c46a5fea7d49ffe0320c3b83f5a7dda48ee4a5e15721f778 +12c5f618784670c92d7236cd1d19248fc8c90e6c0bc876a1d9e3b53857fd +3ee7790f486e7ec4dd3da944967d62f7e8d706a9f6ebff86b38a5300df6f +5444148978453351bf8d230215d35257bb54a702efebb4ba90f53cd13469 +09329e92e064710259ff8a33f1a9cca5ae5bfdea62876539c0aa79b2dbd9 +5f0b80ac51842edfac8ba6c79aa9f0914113ca29565384571b885aed9ff1 +e2df3bdd667514a78ee26b59f96261b6268b7afb245de6ee930943c3d52c +238ebb6def8f6777dc9840d0c220ae81755c742c3cf42f6cf3c33a2c6a4f +abca01ea12c37b2cd899ce780e434592f23c7fe96f878aa5f196d9a70bb3 +d544247a5f295042842181d78f1dd58af09d99d25f4647bfef59e133d425 +7aa689bdcf248532556e6a4cfdf558bfc1af8d0991889ad61d8ba10da576 +d1366be4f6b0203899f9a02fab34e921e9a7b09c2d06f8c6600b9ffcb187 +d95c1facf73d1ecdb28bd4f5143bacae5e193dc0d196e16ab2e4d3168a76 +24de988e1b25e56406f12b6846c66d7ee0771e71be78e2aba637364df774 +f91bd43e6608359b8540bdf22e28c34bae81ae5bfe50d754553cb6858a8c +2fb7dfe840421b702b99f22b221455d28ac55f2b8b01e5c6ed897d42fe45 +a36d396f2b263fe51663f898fd747630dea134d758954d52a44e36c743dc +d5831f732a23d4aaf49acf6bcbb3884a21063cf0a007e2516bfa71683e34 +b361d4456f5353e72c1db7c693c9d0357ae8179a644f2f373d5c763f5e6c +8c8b487288fb8377112784fc50b31e39dd5d69d14aa893b55534374cecf6 +19a98b47eef81c8cd20bd3b1838654f308fcaf94504fd5fd8e93f07a4760 +c182651145778990122e2afa7b5623061ec3f4d7d9f061f2b7a7a09a3ccd +c33cb1602093369acff1eb1c6dfd73dfd67a4aa978ba1ba496bc17efdfe7 +a8f533486c3b69df01bc5a20230235454f3c41b0584d28f6e8a019db4cc7 +8d5ddc5d9d8a867b7dbf3e39f7ac68ca55a40d9a05e2e385835c888288c2 +4cd9fc51ad2250493122e0302655c463cd7e1188b5081387c4674bf16edd +2c1f1e49b26899db5e1a4cb1bf6afe14dd24400877f8c8657ba4d3227c76 +7c1971bd33ef70472c2542b60148fc4ae31035240bf578e3ba4ce8a479fe +b4ab2d06ca63f8b80cb0b592b2e6977db02bd2d9f81335f13f803f5c5cae +420236e8c5c11dc4d67c210cf2694b47e7d71b47c29c280061b9ca2e4fd8 +a303ba12aef815503b67955f62bfcd7b2a2ea4e31f799987bdad5d028b29 +eb1d91bf894a8cc7f4751d15d11f80c40c0eaa38af5a9cf69d8942a21352 +e3657c3657d92b40985edc1ebfa807c5285a74c47dfdff79c41aaa22826e +c0161e3a4e6249664f7b7f52161d0ed4630ca4cfdd6d68fe2b4b7a4d64d7 +051b2c12cd0e4dae0f66932d7881d601fb62f3eeac552e654c2de5bdaf65 +178efac1d91ddadf43980b1a23d5c3b5d38a39115548b7124b8bc5fc8f45 +e15f32f506ef0d7dcf45c93d2925829133a732a858cd6f26a3546a613bc1 +024a8d31276e529322d8075bfc9e970415940f96ef9be114aa3c97fcc08a +6e67971a6854f4cfdf8f6b43a8d9fce53cdeaa81ac6f97a3545f9188596d +78b6a33476dfb838fd6c4fa785747203133d4518aee00c184ae0fdf5db85 +0326ad9fdcdb244bb4f659b66e3319334f59ea2088e4957477a5defca2d4 +a5fa3e37fbfed1384500784e08ffa2f5aa417795a1d2fe54822e10cb2845 +15b6f394e7681fd911510bd68efa22957930608625775a64a48d0c2492be +b3ebfe2f85bb6ebe4a5e409fc7f14a98f9239306c5eb3e6d04d741bf3dfc +478bd03ccffff848e0ed18e47becb6c55c39a4662283f3c4e2dfb76caef1 +6c4fab8944c1ff6243e22715af0b4de2fd6a442ea56a5c88a6b93c36ebe5 +22b5c46014bc03e86167481d599bc3feee0564a090e43571b0dbe0961148 +2d69a250626dcb909668f145f9b626f9a7907f4a1778e8ac066af5b9ee02 +5172917726ccf4164b1e0c7e7c94e3b7df8516c78b1c72f6fd57ca0aed0e +419f2c5dd1ff24f47438c0e0473edf9b5fcf277c84d500a4ff055566ee7e +cbf5707262fdcd3c7a28f1d04a4333374b6108c540c64a0cc773cc90d588 +3b7adbbe0668a38ea57cd2292ec92602cf4a0a70ca7bfddb955d71c02aa1 +2effb4c365f7af85f2e379b2a5e80bcf653cfde715c7db2fb98f3cd3af72 +a94de7ab989f2d38441a893934d396c2a418998a0f515aa26914447e3a9c +025e8169717dcc63fc878b3e825faf7da165662751e0811304ecc1a7c73f +f806380dac5d61611388f37d7a92dda1c535a3365a82227f999e3f3dde8b +bd72a5232b3332e0cb275312cd28f4c840c95de6366e02817028782ce6ee +7c56a004d6de4a2786060fcb6b6d05afddc743c210f6f0458603382c1be8 +3e61e9a03835c2f6bba1a4760564635be899f75bd23bf6f636371bd2238b +72331220156fdaf0a5d932d24829ea054b6b7910a738c03c231d1dbc9caf +0165d4091a31350da275976924f83cb4187e618917b56fd9b881bb25a8d7 +f8741b407a89ab26719db257d9e6b60c3c25878c5896094dffc58891fc7c +a3eaea6ae4876ce36b3d3282c4d1dab373534c261104d235ca94c08a9daa +039540650fbb97ba61d5d907244be0b6ae1ae2c315fc7a13fd194960922e +5d54c8528e8ae6651e9b36d7266ac9058ae97ee0af5b27b4c045aec4d2be +d7c42cab914e1068cc8538861aecee6243b3d38f60ae09cd655da05a2bcb +1a15f914a4b819d1e173c4abf8d25f3f29b45c4bcdcdcbff3e24add7e76a +ea86675fd8e8774948a1625dbd5ee5fec0d512de9f2ca7e91b97afdf4a4b +f242499b6d8f04766b0b8e7522cf8848a4bcbe382c39cbb3bf393ef10347 +f18a2e6dfaa6842e31cb9eeee419c762debfcaf49cd7bf5874f992a78703 +0817e9da9981b0d90ecdc538ebb1812b88c96b6e93b350b327ea5d737887 +7aac9d7129c150c571ecdd4808f02479bbfc87f1df80df86ed6b573339b6 +9bcdec24fb9df93c871a6aab8fa236b3d39abaa1404321d9032971499238 +99dfb447021b9510420441b9fd8ae89e2667441d7670b4061439cfd8767d +30d2d298ea15c1ab2dd7b25fa514bab9f714176c8ae5a204bb167cdb335b +132a35f6bd14b70ffd7031cebc7e180924f24fc5417199cf211ee8e6a55e +094afb5637334e8d42168da0dbcda3b25336705988c929efe68a56ffdb15 +6eac310cce0d067dc6b564634a71d6cbd6f9ca9f868fd2ae88778d2ac52a +e78ddbb7fa9c939dba897d3dcde0acf6e04d59653df22bcb70f9fbfcfec1 +ee703e923b07e0d41370c4e4cf70ff63f8c79c5c6438f86725a50e49e3ee +e18687ea324e651dabad022e8a783c4c10cf84f0ab482e5c977d4880bc99 +adff1c8a4c5e9e643ff55128c306cb16eb9d23c7bffd19d55ef59a6f3608 +dead9db7dc3931c48771b9ac55368e5f8a857e6d5c118de26d1a1f383a8a +5bb9a2a4b4c0958c0437fc96f264ad36d1a0acc37500c0ad72ea86330e77 +c8518a74de75eedc0f3834f03860e2c26169b8c02752dcc5824b02876525 +5026506b2dffec0a1578cdc55f15d471c6481c08a757ea55686352d2a7b6 +9c3eef57c630f12e9b2aff398671240dc216a29c5ec17d44e05f1a8dde90 +76de92456e969c8055b85a3c04041365ec35d79f2c05abd075f14eb26eee +478deff3d12fcf9937dd3901d509b695f8c1fa590d977d78db84b2849562 +c460659842a7b90f8b21c2cc27d642586872c49b534d299b3fb7e14d70a8 +68138371550f9e021a74d2a6e0f67d90d53ec408502c40d8dc51eaabbe86 +fbf5572a2a7f121bea99be0b0045d2c516d10c9beb813e16f440825a77d4 +dede2c8b49c4ac5b71c11ebd8f8fc4cd73a62e47f7eb212ff0572281b427 +96332f70728d9205ce38570c96bd89b3f2a3edf498ca83a37acb4027b561 +de28ba37b9199d04a56e14716ceb4a4633007637b216b9f6ba2a4eca8a2d +e0cd63ff0944dc63059befef0dfb53a48ef62f54f15bc0355356787923ed +729a782d962b4d78235de8dcb31892638f51000f8981b86bfbd853b28929 +f896a0530b72f075cc0bfac799631f2e51f474ac2f98e6e2fab89c2b3890 +007913bb9841969b44ed76d4e888d9b3d9841dfac5d41459dbe7233745bb +4e79fc22fd7e466601153efe3cd7700aa86acad07b0692ceaa6b00b20d76 +8c5e6052894c5915607e9cbc49f8fe4f6f3c33045fb4f0ec20a3c948af28 +e80fb67f379ccc1bd019b339532191cdb803ca9676977ed9ca01bb039553 +48175f8caa95a0714327d59b82444df22ac4ee8f5049c91473f226d4f27c +e402bbea6f406cf21872b15b19af6c0cdb798f806994ec1aa9056637b139 +12effa08dc015bb67f3ca7a4c82c5e34d39d88cdd5287c3044ba95f2f75f +6b6db9f1d60a41fa9034d91bd9cbecfc7ce7d76f4048206f5fab0901f7cd +d639ed068cc82be17c35f6dbb8d85995a63ff69e52bc0a01261662153ec3 +40fd4027eaad5b1b811fad9e16663918e46e983b02a3ad97ee543c4754f9 +e9b6238295e6477f0e8133fa12360b5fe5adb0389778f4300c11a26fe4c9 +bac6e234ad26f855bca28b49a3bd95c0758587e98fb123c1c80f82573fb4 +583e578bf6599e79a9090f35be2c9fde410ebff05ea76120c7d52b3c4769 +0264e1dd276b6ab08abf52b30b91735b3c84659115bfef8b88c12a7dd1bb +0898fc1d5782edd9f371379a8c9796cf3616a93193a06152dd3c8da6effd +03386e580b8011d2de3db70458d957ecd0a2db427058fc80522028c7d203 +904913b0e63d26d60fc42a2c1e9c53b41bb206b324121347c6fc55e99390 +86cf26b3de1933c0586abc166bf9f312754704645d4d29dfef978d8ab341 +1eb295c500446d3e2a62d6738b1b4a9f20ee6b3a7c1c0641b5502d52a28d +95dd07da8fc8eb96a234565fb0b9d82cbb263450f929c9155d3d29ae2a75 +ebe893d1eb74b6f0628f5bca4c90a7dd943db0e99b178a0d83524800b361 +0d651475905983e84f5905f49b0ef12d880cee222e913b5ba51bc5532afa +722f8ef9254c49f7f62f744d580bfbdee17d40ff9a04ac2bf64016d4673a +4538a66e52238b4f4c1d37ac94f1f65c7beda2468a10b0dfa321b18c84e3 +78cdd2555c453d62c92c4293ba0aed6733aafcadfb488dfbe545de91e412 +c8a1ad04d959c75262e92a37c4d1bb48dcdca4c8f6d9fb07a9180b6f9c56 +efa9ad9ab9fe48ed61d59c5a4b0fc284351d439e7e503e9235a30863408f +a5a99aaa693cb8aebba6eb8476009234be914ce235bc206d093200d35937 +43eae9db40f639eab16fd3a7d049005fbf938696948d82bc25674c69d1d7 +edd0b6d51438183c30769ca3104eb378b82bcb5e605d1e065a11e17892e0 +a32eb07fa974d3c6f70c0b657384ae839f74c622656efbd3878a7aff1a01 +a2933e47f366953bd28773878c6c999f39abb27048e53970a5c88a137c75 +e49c91a53316c5f9044464e40c1eeb3eba35762a490a3ffe8fc886d299e9 +ecfcfe553dbf334913b30e03e5bfbd3de06207bf47cdaaea4cfc8147bbfa +154d6295bd46af68ad298b5c02fb0569b6ca521361427c55d456ff6d8083 +417f3bb3ee883a957dd0e453a889d389bdf574516be147499cb02d9d760b +62dde4eeeb70a7fdc12338abd01d709ccd256ffa5f62a7f4aa6d3c7f235d +ae276553da64993147b5b86f62c473d0d3ed14883ed0de74f1c623f3e624 +9d6af1571dc177d27e2c1f0bff7ed9dcce8fcbd37bea8501aea6c6d7b259 +420bdfb804e3bfa4e339708d19fca748d8ed84050439ba7f5a088da4802f +dc46b95a99959e95f18407abe239701a6fba7d6e2094641c509da66fe556 +747a21b0d73e3e7e157ba4018295eee683d0fbdbfd52437ef581b00ef2dd +582661a4a99b02f6685cb183ac801f038e3237eb22f9508c54b34e06a1aa +fdb4fc6addac5110d2569d4921ef8b43c6ce363e642951badf00ad01b56d +262cb0796e6bc3500fb760ace1e7c9fe44d6816c84063b7aff0ea04d918d +048dc193fc07bad3bb8e7a178f8720b68a80027e9ff2fe4bf8f601de48b4 +c863ae6a0f5cc9fca4614fb487a0d7e42cc17ec429e1094c06718a4c01c5 +32cd08503eed35bef2a83c86e85a8e74cb9364a01d7aa51af9a7ad59e93b +78e3d119e400ed46c608c71e33facd29e424123626b535a7ec87cf2c12d1 +96e378986732c89481d88f14fcf9507dcd50834110c071b68860090e128c +b525eac3b519c2191dcc7d39d587e56fb33ac6bb2312eb217d08bdf9c9eb +34ce910a07477031d4edc8226e71421f6ae90bfc43c7398928dc2fdf62a5 +48324c99e740b5815cbac9157f2f5b51a46a1cf6ecb6a03753e7fd49cb4a +04e5e8ab19c4ac2fb50618bd9f1417faf34225523a6af9f9b23ef982831c +5f1946460795e0b5970b383bf8addeb045c54e9c593f5e1f9daaef7dc58b +da2819209f05aeac4ff234e3bf47ec5f496c75322417a96de3b70c509693 +2dd0026384c3d15260446292ba7a0cc570a29a6b31b7a37596db015ec084 +6bfd0a664cda0329e8a452241cbc7443b4cfcbec48b94a1fb2bad1073268 +afd3231bb21ac37602dbf5653780215e4108e2d4f7164b12e74824397373 +c405184888673573b1f2263dbbcdc07ceadb2d2202a18ad03652f0355fab +f0df08c30278496290306f93be7e42f663b51e4f0f7e49d3292370c92b45 +bbb7660748cdad641b1c2d24bdc33ddd9272c8bc6c4c80fdb1d6476aa6a1 +7d0e35b43ef7d3fbc7828f0209d6f83b04af1df350ce10a3af84855bb90a +2fdec60f796d5a20eee1b323edfde3d69950ce90894184246dce29499c3e +87effd5630aabe1442e2399f0393f21beb96708b6cf0b6b207e47273bbe3 +03a35024cf49899328c87191bfbfffef9500611bebeedb27933b1f53d6bc +805ed7c3271fe94dcc7ffa9f2f53810cd3d08949d5ab0b144a8fac533ba3 +ee72bce2be5cd88034c6303c7d323fef2432edc947cad4af6b1c38be9bd1 +48caca12323f66eb57c3096c72f8268e746cffd4ef80df5ecbcf522d85aa +41166fddedfe8d843cb25b9975908b5de7c4dab8fff7b98b8c24ec1e8477 +1270ea877b2a5edce15539685991971922f50404b14bbf10e66264fd8207 +cf050c7c0311d387c62b78aaac2b969d315f4a7963a79f8e724f5efa0190 +25e7790e6a5c902b7da857438e84a9bff679409dedf5a4a0f670ae4536f0 +5023a9e13c71978ca70490706cac13d790ed4481ebbd8952f759a038d821 +bd0027e057837754bacbb838eecdf781299a2c349e34578b032250842cb3 +7f3726a67bbc8a8c229262ecc0cdf375ef7469bd85327b8735550f942cc5 +5ce679a0af078126540bd2d4f9581707e67eafe4a1ebcde24a2ad06535ce +001fb7d2e5f59c2e6b8e3bb16eb2c863dbba5e781c80e5c80fd9d2e7ad5d +11e809b842f13450f4075c59648f4f59e1b5b8d133bd28ec16d32b6230cf +626e4d8c76f1e46974703abb1934d3720a9b16ad752b34c0155c2412e3b0 +b4e917cf5111c0a986c361bde767c6262d8ab6520c7f540c75c2c92b134f +1dfdd0807d3bfff5674e376ce4513ca149bbd53d0ec109d2a8b7ece2f6cd +76e9b07a249bfe81cb1af012de457337786a7ea8853745e001e3a07aa41f +b4cf2d0dc29a779ee9ded63df1251dee748a69d71596e1feb5082d14044e +3b74aedbc2ef7a288c671e7a7b7c43e0d8f3acc76505875855debceb7ded +992273ca741cbb7073c9fe6182865cad971a7196610134c314826f2f12cc +4f2835f269cec7b8a046dbc7568b2cbc56cec08095fc771a9b093a4dbd3b +6e7e71b1ae183bb5428bdf018193ea62a99ad8adf581bb60295874cbea14 +de08f9a9d86c5efc49aa30acbac07f637b2c1a022978383d063e12f17fa4 +a20f18140ff565088be1714bc19701a15166de32429ab505903ba52e1ef0 +72a304d1448755ce00dc7082df7d990635574c9a5b66daad0a45605903d7 +3179e0ed9e2630f43861e22354ea16418cecdfdca05201e2f75ab6f7b3ea +e336c4ebf7e3851cc097e2105beaed2111444de983c6b82f11b32fdd61ea +b45331f7ebc1f93cef31f223fce6a349d8969651ab627a481314fba2a3aa +950327257f8f50e69e1a20943816ef41225ae1b76811c5af88976c4b4e02 +74b43a58f63a27ea8958a3f5d875448cb57abbeb4859668a115108976861 +01542a0830ac31f076c5ed6626ecd9eed04ad3e762e9318c7bab07ad3204 +831f57b4f10deeed0895e24668aadcbeba9257f1ec419111e7257fca098d +3ca89a1ded16094d10231bbcdcafac1166c08a7007749748e8c4f500b9b8 +7b84e8117042575a5b0d50652355df6cc61cd2c785b1c6811db2e9b9b7b4 +7266b4a1084be1f3f7d188fbd9494cec5116fa627c8069950113f7090936 +f10de3d71de1b70afc56b61ee245ef7278860b64113233a8a7817a0ca23e +5f08370cd48548e4757478b057a0ae59e9ce81a4ed7ff3ac3d2117354cb0 +a98623705deafad89ce0c5b5196776cb5d437920bb5c72a8a718ae629b25 +e253c75501555420621480afa2b91b756e967c7f24e3005462cd1496fb58 +f34a42a9d59a10d6d68bb3c42566161059dfbbcba569a089d9c1dbaebde6 +51b2275d59df0933dc21d0a902f21c5f5037299c6e8fb9541691ed13c0e3 +6a5af58d7b8bb360e8bdd2a77b24138b88a5aa2938066ff6b098326c2b43 +853800eaa4a304102281325ecdfbb2bb1400f09edee97ae812728cc153f7 +eabc4a7cf7619a74b495fc82b5a89a9e0246f98322c2266bf838bd1defb5 +16c7a371d91bf573de96f05001ec48fdcb9e9045ab1fc910f6b9344adb49 +c38eb75023016e2398846602e2fe7a07a90ca86376fc125d8bed1956b897 +781def6eb4298204e4b551eec3ce13b1fee5711f10c0c8232ccd533f8231 +7027a87c30b91bc14d91e14ad3ac92177830435c27fa8b8f8dbc75c04cab +0181455eab3d1e101b14974a6f4fb99c87ed435f380f2087438b4b371d1e +6113bd6519afbfd9244f0384dae185025aea6457401f54545e3494120105 +9ce756cf7fab4fa583f986a8b4d559e834ef331a6833971c89f96c58cd5f +b3be135cb06f658fe2627509c8cdfa91edeb439eb386e3bf9bc4dc4e7290 +a2ffea0ec25c0b9c021285abcc821befa442c87cedb0a6c2342c933dd461 +16ca786dfa3ee43a7f3aeaca49e4f3a1d404e59eb35611cfc68ebfb5321e +e4d871b206ac8692930c892dd7cdc7b31baea9a439fffbc5f9d3cba3e71f +5638dc6dcb8c64f763e254c327f77352297bd706f3a9b4ecf045b1f132ef +78c2967e393100be57aea4b6a5a8cd51b68bc114ad91e1e43512b8079834 +464e4a9231ce839825cecd400f71dea1b4da2010d89f3fa8506f26888f25 +564f6f0b5864768abe3d3e857bc265fb6b99e9546495e4be3f7b3bd616ed +a6fca19f05b84df96a2b7174cd315029082ec03d74e9b16fde55e6c51c86 +b0e6c0a1875275fbc8f24e08eff26ba23f0a963f7a40c359df33a2731f13 +fe2c905f6f60acb43d4d03cc63725c85a406108089c33d82e1aa107ccf7f +0517beba564376c21cc2589dda7994cd35739722509c630c4f8895bf3687 +bb8abae73b5e1c42915994c614e9876b7a1dc571c06ef000d7ec59deb528 +19ae24516aaf054bb91545310116f9c46af65343853f896668dcee475899 +d08f4bc405efbdc9d455d2b48cd23d1dd4e40b8948fbf834132b83bf7b95 +0e2f83a0915cc277d4951b1d9bf8c9d7c2900ed222ca89e7aab7e64d28b0 +d90adf9c470ac90afa395a63964604653936a618dbbee33caa4474ed522a +cee561047dc163c784d5b8a26e04256b16f96c63eeba3b63dd8cb056834d +f7f846fa32e32f0ffc14f074f03891816de860f201028060c3043b391fe9 +858cf29622d55418d67f5e6e6c718f1fc2e62daf1dd4cf79eb95a16d9c3f +eccdedf261f9f41905f8b8c39b9bffb2c0e8d65ee4f9cbae52b55fb3bbe1 +07c08c3abd668e91601c849af2e034b99de6891224a561b7449aec3d0be4 +75991f52211b9d1668311aaa7ac9185e78f90fd31a324b6c820f7f8e189e +952cd15e57d475430e1beaf7537cf6649e80e35df16fc03a71ea162a19b7 +d29617bd5af341e7ec81ddc338606fe0507649bf761eca6f72dcd2b21797 +32baeb51d65779019e678cc846f184baae95550fc430d6c4e315c1a66193 +2e5a8c4d3d81acb445e2b0b807771e2aad8465847fbfdefd7209d10dbfa7 +faf2c3041a678c70a1c807a6f82eb448688c8e9a6c968f7f9f4cbfa88505 +997572ce6aa228cac0a80f49964957017e9090bee36c566c06e79bebedc2 +de9a7902750e1d25f2b4a51e10221b4ef82d8f1fbfaddce9f9682f3843a5 +81eb10b55cea4a8ea1e2f7c84b6394e04ea4b6bc9d9ad344c41477724a19 +6f73d92b9c4358f73a3f882f4452045c22555127bf9caaf52777c200d679 +86227cb17f94a118ba663428ab3fdda95c359a353b4aae31f94b04d84a9c +0c699407caafb272ae58ef328e9065b57c33bc9bd75b35e4f7d2a69affb2 +137a0947573d52972b014a28f14700f0fc2af0afb71fa3c038a4fb5fc2ee +2fc6512596b42d3b72a612b86263862bd3b2dd4333758611077474fac0a7 +22e1d9199d66510a1a86f807aa0de71c13920d5bd7328874bf1a0e2b80c6 +d07638f261ac24dcf7485301c5d5cf0a8b62d6468817d57b9eb835a3f996 +6ebf73223cb5909a1ae2a85bc90f012ee26b484a40c8a998ada321a0fa95 +05d9a09c8f61d708e80c7b5f47599d12e020fe79d63bcbb6227e4158acfd +41870941fd774f6525b78a6781fb50519ad9240ec7f31c1b85aad48745ea +2e58ef88b890bf9c5cc5910148aed529f2694f1cec8b0e2c30952a4dd922 +1d53ba846cbbaa2d67d64ec25db97fef8973d51207930fe5584cde28a273 +468ed7713cf2e8865dec285e20f49ad3e6ca4e43908a9116df1bae41bfdb +724b3bf2cbfd255e0eb69560b329b7eea14bbcdfd0398c663ab9c13cfc78 +98c674bfa207018cd1c85281c4bc995b16eec777f51b0d1929100553532c +4c3e8e71acc6daf2193471704d3fb92de494e89f81bbf7bb700d0fe46d9a +21f9cc6bf251ae31f40334c66bd40f801d02ed63b52c3ec6a1303d659ede +330cd53de8502899ebc6dda655de3d583104e01e123001bca6fb3ba5ffd4 +f1e506cf7ed59fe3f991808b2272b1197210e5ea213b3bf7d6a2177cca3b +0483447bdb44ad2c80e04cf5e368525f8d6b9ba6b114a4145c2c8a693113 +21c8d5ce682f2e13ee4720e0568efd8488faf57760a93722dfda8489ef49 +63f2e65978adfab8b9c9c8d9146180b92b3c84c725e1f50ea135004b6479 +7ca6c6a87c95952e8f5d68958b644276d106e3706af153ca270f159f6f8a +d76f0b9f4be493574ff549ad6ab909d42e5718424001d8aa17567dfec66a +3e0cdaf98c89e56a4692f0d585b13e8c8e1dd4a5801b1eee8b3a333b63d4 +4e65a2c50a1b46615afc550390c1668ea06ab0f6f9a175e408b1568bb470 +f73a9babc7f82795ad940615701ef5e2046887414770ffbe9c86becbef31 +da6f294faed8e4f9ca084a61915d2f7194ad578fd5b9e01f4c23027708ad +d4326fd70b48d0cbf9b42df2860784859dd9cbc707020c3917d1920ce164 +a671d5e09d268545dfb9d2555a1c7b820ac802007c54b403e1a6f9553e6c +d52c64816e788e6115ebe9520d57aa5d0278c1e6940fb80959941af78bdd +96877279cab45c9ef7e47d90d24b5b3e0869b769d3a0fb03dcda79ee3a52 +349f3fe89204afe517b97455ea1b056f87cd846202593cb7768dd89321af +3dbdc0c188da25b9699cde6e0b1928cb4060f09b4f6a6c2b68700bc14eb9 +fe2890fecb5e389e7606186d4417f5f5a6babdf43c1352f4feb43a99698e +ca73c7d7eb93ff5d38ebfe6d102cfd0d986af39184b4e007bf65131b6a2d +abd1593020e2fdba559e939daf7f6cbace2176489d45ab860fa4a05930cd +77189c67d4b72df03fe8cf482419972621de5f2f0143ea14f5dc08463b30 +2be1f4bd73cd1f6c5b17c74d7740c802cf197ab3f412b697c2bc8f41743e +b2be55e238dcdc6a0253a72e63479dbf563e6a161935f77f0e5bc5372dd1 +f92ae1763e05e019b47967809d42709324eade06cecd85daabc456d9e903 +e0083d3a74d5cd2df30bf1db1477a6a71a55a52359f4940f2c339bdb6edb +aade3e614d4c7c36fa2b26accbf520579df89a7239ec627869aec628e7f4 +ac09ea132f7e2d030408dc91f2596c954a9c026fadcc416f1e061b484372 +21b50d8a4b735c91d6e8d2937e4454b0e8d1f553b84a35c43e1101f497f5 +e429d6e0852f011213e7068d53e4dc696f6f7ff9637d3ac5ed28b0f8b55b +aababfe8e9aa7fa60172450bd17b615b1b89048fcfee829552077abc1d30 +615c9b5725701cb39e6675404c8230ba27395ac8b5444f318600dde103d3 +039cdef4650e68a9f1280ca84aa8cf87c652aeb45cceafd1a21793385a17 +4d4a5a5830700593cdd94d61374ff4eb563eeaee80b761230ed61d06be11 +fa574de0ae6c3452583aa53768238a25f570eff0af5f5ebfdeea98c85afd +a53319182611e3e6285659ec99d27a718ac5a1cd7cd80f2c97bfe9bbedf6 +912a41a171ec583a0eaa4ac571b495ac78b275bed49eb32a0202a07f1ebc +b0a89fd2d1cb6ec43631e8e26869aa6abd775f31e1cae5158f904a0c14a4 +ef72d51e20503ff7814c717a0f9b28ae19897a448d8905725da4e40f17f6 +d7978538095add5e820e80de9f261ace43d77d4bf97510f774860e45037c +793c28915b01cfbf7c6388b2e9225b0e2721cf5fbb52ba2da6bfbc11d515 +3ed1423fabc05624b54a1a60235ee26e908f63c52826315f1ad84fc79de2 +3ed793cc756578475900e7a9ba8a812e06d2b9721556483fce01ecdb7f83 +190b4a6f2eb8728f5bf941a5934c960548e4a8c0d17f6708386607a0502a +1ceb0cf8ee2ba70d0e0b350019baf415a66ee50ea8a8ceef78ad242421d7 +397c06caf762f6b4bb54bb3b8484f398000f0571f3c9111e96164af8420a +7aaad2b6b5056ec35d0bd02b46a7e007e24e1cdd1631d343856da9a4b66e +f36561844b16e6beb6f08b0dc8de04b04364335d6657ff916495c3f9aa5d +87a2e455428a2d489f70c2aae03b64390a6e083094e925f75f7f2ea29a44 +c76ebb50d62d91fd78c3035cf4bbe13d3d7205daa28ebbb258456e2838c6 +41ab51e1652594c92f592ff8d31d90c6f179e067747e9d499a5e0fccf5c1 +6753bfb70a3201fdee641c9f45ccffad879e477963c8d89162195474ef98 +4f1ed3d69369905a3d55ca6703889213fd8cfd7b029a3be8adaabf620111 +675f6f65df5f5b05c635ebffd9d6c573b0d6217448c881a4d25262cefdf4 +9083e775589a406ed03f8b0038dc7c47e1b484ddff035994f4a6200923c8 +5edc8236d20e46b0d3e617a8b026cf7070ced14b3340e6dc34fef020a9be +702e17f4bcbc738770e76f47ffd849614e24207dfa5e6f8d2aaab20451d4 +412546e40e8cbf56da8d121f364e03ee310ce1cb7f6fa51c6bcede9fc198 +b66d39d57b23eccd3441460593f44ec22cb4335bf19e09ddd89184dc0f09 +f682dca18763ea72db6c8e32faaa8f002d49f9023d27b508395ab751be5b +02b5db309dc9a51b40e77552bee48e379fe478bf337e039defcd992afc2f +712a5b0f646ef0902b593d8e9f03bd9eb512ee344e115f84671f21e5b5d0 +3b0ac0548481a9a07292f79bf74c41772e16611d15cf15ec079814eca31d +f380ee3f56e9bdb39e0028b15793670aa6d1ebee19603071ee3ca517fda6 +f8c5763c9c97d11ef62cd19542412b55d55058027494143f217df42ff2de +1c529e533d0ddd46ebfa886ddcb9072d299c13266d7c07a2ce9f5b76addb +44ee6513244d7d4d55be1aad98821431280e334889718b60b3e58929a1b7 +197d4be03753e22a5bea21669a4ee78ab070a41f2eb01a30f200619fcdb7 +5cff898152f0c44b2fa25508cb346661f4fe7846928d52014ae28981d803 +ea0eb8525e6a2318cd2ed96f7386a22ac36025027c5d9d50186b5a2830de +062b07ef56ba35883ae1a0c76be54a0986eba08fc4640b5d18bd247f2cad +7d9f950b698d11eb11aae9f847f9253e91ad4cb56a1b8dc50d19b81362d1 +e1b04661e58fc86b016503bcffb63b3deef03c5dfdfdb7cf2c732d77a0d5 +5ff77d2f6a7ae2a896bc1184c9de0be31924e087e0828628427e0e61f564 +1475c066cc66db890c417df5879f3c6db72d36132e1d87a88cca57c99aa8 +f5f38e5b6911048e5fc827d4170c35f3298ee937f79c7e0f51727ac94602 +191d21bb621246161a5c2cf5260b7e42932b779fcbbb32a391599cf96b46 +2826ddb8c2acb70c4bcc6d8bdb4bfac2691a48bb0d6b7699321352ac3104 +a0bdf7da836a84116f8a52d924fa8db025c37f39dc8af563441c51e317a1 +c2f5242ae9bb32eca30bdd7e304e95d1527b7526992a1279acb46fba73fa +bf5f038b6081deabb5d2966cee770030d726315080c371aec87cb96ab3d9 +c0858e4fbca3feefc066dc6ca8387326a9eab6e03d1a56e5c5a2ba7254fa +a91986f2e51a767e8a4b8009ebc6c8cbb6c9024eae983e115bf5d52b9bca +03bb482da239372f4af2dc92acf7272a35cf622cf6251218df39d9b3d044 +4d36c8b7ef7db3f7eb57df365ced86f4a92d48782c219400b13a0a96ab32 +e09e124b8aa085bc508c44e299b7d5689dbd7ce0981c2127d6853bc099e4 +37ca0592af681ce6ff71a2dd24807997288afa1a407602342d18f0695f44 +2241c897500432fd73529eea55948ca77e86c3f6d4e875aed4dcc5377d05 +5a08cec70057e4133240c63ba28c1ca90623beb512e89f4f3fca56239ad0 +c57a7fa9cc6d4ebc7effb427496fc36d05c395cdeafb5a21dd430c98fd80 +943ec41e7b41a641a28fc257924692a592c1aea49712dfa7baa46f8c5562 +6a1f30fd01105d2f9f460bdffa8342ccad277ba5d11d815b45adad5be5f7 +3bd73eb5e2e5fccc20883bb5a1b5d5d569c9935b0be71e7fb82fb2d1b4c2 +a8dce24236f65d2b8fbff5066fa300f667a4d2b6f150a9b1c2c6e50d6b6f +642faf0fdb850c6d7efd955f8582384f1a937a9a32dd35747403ba93de7c +f7ede437edb83e84e9dbaffc0e45f901511dfc3e651434bd58f0fc52c28f +6cac352eb7ace4ed61f49df8cebfbe0c0964e484d2ca8ca5f1fbc839b907 +f8c2b5a420cca06582868827e9115301faa2bb434e5bc9cc1978217ff5a9 +9a3038acf13a9d8ff87ea545e49da1e9ddd0e953f39ce7fea2b0672b4433 +1d85a03a3015399e4f2d03eb72da4693f733a34bfa872978060e65dc4e42 +894f341473eeed60431ce8fe1f2cfc3e5746c1ead96e228ccd12030bba67 +4bd3efc3db7bc76f56b758a391d44bd6e93a4b65c1b109da98811b08ff4a +1c98190b24feb0fda2107ff837bb3b29c31afb2ddebc3593ed6d0ff0e88b +85322230aca6f9cb82d641a67e602c3a0b40a695ac1b7265538a53b04dd2 +2b5439546e8c4ef96070b64469860b82ba4fb73b424f6812cb580e177150 +6a891c678df4851784eb30caa4d3dfe140e518622f8737b86f4d9cffd870 +7132e2b15be6b987dd30a3be8433e7dffde4d62afc8e6ddfcfd68d07b2fd +e94e4253b75501d2c8e9f556420e14c88993322a24c31f6e37d45ba1a2e0 +34b3f749d3705e43cef545d47af86948448dd0b886cc3a98a1c1b8399bee +a86ba1f3a69fd5a4ef2cedb670f5b9249e176897e406149ae0c6063da49a +cafb1dbff711b977dc7f5d4a67366e93c7b7d2cfe461e8faa4d169109c08 +3e6cdd1564e5940d3bcf6421ab684f833c6e53bf76bc7b0b1bf85b0e6d35 +76cc4e86f06a86a241f22e12e5199ce07dfa7460e9f27366ef0f670984ba +93612d1e68501e5eb5f97a588f71179aa2325cae91456d2a6096c1dda493 +3527dcaa9d23c893408e6b3abd7048b17cb58484cc2c381d3a4decdbd963 +839c343e8ab2165bcf6ec6d3a93de2bd06291b6c04f8658785a2f71a4ccf +286abb902766a45e9725f0de564d71cf9d514a0d88a2facb119c7f6077d9 +5716e5ac935439b47fa0208e9e5fd9666179f45a21efc417b82e110d6c2c +b5d724c3fc1032dd5b24644ca4918d4cb4df0b3d8ecddcb2e13baa967d76 +d4abcc2439205e04c93b11240cae025c456de5da2534a524afd87e4e60d6 +2eb1ab7d1d54e23e629dd88754c056e78f057ef66c497d993af61f9b6654 +4a3ca699dfb2edee722219199d4962cb72d34e6f7b5fc4bc45efd1240bf4 +a87a2b88355caa3fbcfbdf6159bc1c72db4489bca279507e8dbe67b168db +9e6b3ee1e024e42e02cb076ab71ee609f88a109bf00ff75fc91a53d49151 +f1f84fd15f9903f1d3a3c66618c4c00721875f84a9b255466673df7bfefd +193ab00d239497d5aefa6f78705934f1aaad9b6a51513bae7349cc4f5215 +4c43e03616bcdcdaaa9dbd168dced676bc680ffc6a0ccd9c2f6efe807cf6 +ab5d82d2ba75dca1c2d7e08d25bffd648cd35b1e038274aad7cfc271ffef +eba50d76d6d22927b4d7931fbbc3cf4aec101e07434cd8baa28d7a344f2b +4b2755a6f746a66368ccda78a0c40af1c1aef1813213bc1bbd17151ba773 +2dfb8b590378bec84266a3daa34871669db997b178f799c05d310da0d97d +3ed2f4b31e33e4f134b179818b6faae80ddc1599d04dc8fd1892a95ebb12 +8e719cfb885e13fdbfab96bed732637e75a4237b030990acf70964bc3f16 +b095690c8b54d16270b90045637e0e50947b5b6c0ec4383cf47af58a7771 +22117b1d93912e1d9390d364e7653f920f295fbd79c635a112481583bb78 +1844e3eff4c8667c1f8aabbd6d74f6378611faa1b09175ba98effc02f9ce +27d66c7d180ce4e8a76da7cdb89901260d72af79f852947f89db2993dd1d +11ced6202f70b9a6caec7a8213c84eee04363bd2d60bc9bbe93689fafea0 +ede575d489a031519818ae508c599a7b143b1b5fe2ae164a82637b77cbe4 +36d7cd5d1840f1bec3e4d6fabeb3deeabb570cde270070b1417e2c723f85 +3e00a1d1d12a2ec6ca23aa78e136b17c07e7b69a29160d61ba545783a386 +4b1da08942fe40cd220ac3808afc6f69f11c8bc8e2761a74d8738cd41be9 +44fc505b25c3a784e15dbcec050999c8e1f55749c832d64dfe1af119e5dd +4a05325ecc662bcf7f6a70df6f2b6131ba3d95f0d3563f7f43a678eb9c44 +f7f5aa50a8061a6c16d04e09b8ac05827809beec451af1e2c2530f492a2c +af5cf38001f2a61686c24c6a1113e9098b2c49f992d32ac4a8f06974ef9f +974b241121915ece38334c4182780f9e32d4205f7484c033d597c0910d47 +bc3764006d4b5fc28a4615bd27b46e5bb9bb8483b5461933dc9e08693e09 +c267baeb17500d763edefb5036f820081c1ad0c731123206de774fa464b9 +df19e2be494b3b30e29a0b8aad263602357ed11a666272bbb114a1e49043 +1d838be19a268ea96a8d646edc15598038598524796b89a857b0259353d0 +c2560f2b39b6de8383cbb6ca4d0ffb235a2b761ba3f794d067f16fd0e651 +71182614c8c82883bd9203318f38e1279ac713e68ee393efae4c0bef1d4f +509d19f5404592f0689053d407f1706a3f61eef0ce1d6ebcff4901d87715 +63b0e4fb078597f9c59024b0c67aef020157c09451effb5fba75a9c2780d +87a865745d0ce8d1f535dd07fe0a17d574bb1457b5d1ee9dc5dc41ec418a +a318320e5abc070b2b675d1c463f77d727531c787cebb466072d0fdaf224 +a1903f18df46e98bb4cc5288f11f886f570d770b346be00598f99209ebc5 +f2cc5ed4af88a96d6c6324c46e9649b2fc37b56b0a072badb2c7f8af4be1 +ca5978d9db9a45c99d416901cf8c30902d3d4fd413695f18043445888e91 +a76bd572cc4c3ed8eabff296fe8a8ed3320527ee0c9882edf49c6eb839a1 +aafacb82acdb87d4a140970a6a603cdfe8bee72d8a75510e43d169001adb +292cc6b62d069352c4cff9066e12d8226c14362a30a6288e38515937fc54 +1d1d5ecab8a3291098d33cfaf89339c43844f84ee3c57f1715354fd2ab8f +efa10d3e04f431b66747e91aee2c935f67d2556beb4b16418b3ca818c8b8 +5f83b592ca9915d341141dc52a66764db0bb74104088d93159c8cf315583 +34e0bfd4c01a122e5ab06f35b751f7fea64f3f07e10643814f38357033b3 +4d82e71cf99e9481bd44f05c9b3ab0ddd0c9028d5b251ef3bc167d6dc137 +75871cad29da1fd91e460150f51506b4fe130454f2e7a3e4c9a4a2d7e6c4 +3291f7d9418d8772f5755660610fa4909b545d594d0bf908c8109279399c +eb2933d1ecbbddb185b84172610f5b0be712da7e324f9338ba7c56644449 +0f832932fdb33fd09e397be06a0d0ec06e946ff06773a338ede4e3be9fc8 +acf98bc981e1af0c412fc0bd7358932436bddc43b07c061909d929682e7d +e9872afb6d9b57e96def7ff9ddbe4a64ef21d14189f7005a64d213607abe +48c67022980cb3681741d633dcc15d5fd3484caceaf5066bafdd863e3eae +64b6826ed7d74874abacaf28ce9622b1b8d4342a2d833608775f97d0a559 +ce4233008c412fb0117e72e45307b099c64724141506b2a9c565ed541d47 +8f49ae5d98cc9a9b751103efcbb9f09799fa874fd3c9beab0e597ce6eb42 +5f93f4b83560db87f75182a755cca3ddddb8707665a8be010a40ec611704 +6c91e5337fb7ca377ec96f063ba5e1f97bfe1c1214717103606cd3738536 +26fd460620130db020b05f4ea1d3644b2a8da11cdd2c6c2a065117278098 +630bc70fdce0651bc51685841d824fa42df0eab5427c408198db0927c911 +66b46c9d89a760eedb9308a5150c7675bc05ecccbc0051ea8da1fde8132c +c06412f1d6dce02bc76ffceeb8870564078620f9fa7fda867811a3304f00 +a4169d96e5cfec2ebfa90d81dde07949659d313ff7f8402bdb1eea4ce016 +63e3bec00400aa33f6b816696a13c8dbc338aa192fcc3e06c45b76ea41ef +156b3645bfc3ee5f1f2b15ef8fef7622007196f9d8279097919a225431e6 +683bb3cabb71dff8d8a579d174b2063f48d63b7fe16a9c83dff1ffaebfd3 +3e9ca293a8c3e6f9501e73900b0f3f5c6986eb2e7a74307b6d86b8480627 +c39c2d01215c4f95baed042305d720dde7116b93190e87d5f5050aa0dbd0 +e8d6988a982e7d2a1b70b3b7f5f8b806f49d3626dd1e5cb70338035df553 +abdb4ce6be4b5f977db8722899ce46c3d0aa8331438f1c22e1697983b82a +3a6b128f2ae513509fc66d8a56f4f74955716d00081e4f1dcfda34408ffc +05ca4681379725188378343f875e734bf5ddce99186c9532999800cd4b42 +63105ef314b8ce102a3ec7b5ec0838e6618cc016d8dab5c45976f491cfc1 +f542b6020c907d64f822bb626aa03f04344804da444de14de255853277dd +1678afaaf82ab3851aafd2c8ffb6b7a25eb5a1165936ac02a53fca5b6a24 +c5b0c9884d01b54895cdc6e64c4f3061d2ea76a7b4f7b0164faf03accd3f +be9bce7a12d2a37af3f44c2e864fbe8422d461ab553c101f9e21a50bbdcb +6ddf394e2f80f94a2c721ffdba037688f016c9bec8dc1bbb69ca91b04823 +caa2fd07aa0b1f1071213251d24753fc7a8e152628e23f5bbfcbaecb0f61 +cac8dcc6a8ffca0311483d2798450c4af21f5798763f5b4ec54e99cc25cc +f0019e95c7b89967eff0e002f576583bf8ffa66850006e9feb0f46183c41 +186476ffc10e193c6912ff8517ac215ccbbf210762c4d3318a83a08947b7 +f3807217fa8d155a3eab3bf2a8cd65cfe9764e8d9998b1d972cacf112738 +d7804c4d2f545529031f81306f5fbbe974063935754c8d8a55ccce35fef8 +0dbb6319a40c2484da95c777d9ab30de56f071ec3298e3163358c5f2d7d0 +b8968ca4df727b8c7c7e571236b7fc308d6c9aed824a7ea3527fccf2626e +ead5810d45df801ab75cd958cb42a00ff9734ae6a9d870a4392d6249962f +81bb145d623f5f380406025d4e3a491509439ca5c95579386162aa02d457 +4080aaafda2003a2cc680165749fd5dceaa91bf47bd838f16a21e116a396 +e9e6f758d41df50d3f1610f7d8a65257ae00f2cede6cab0ada9b16d9addc +30cb7a068b358e247ab5c1810922a70e23d60fcb5d3c67089dd4024c5b9c +bbaeab1ce8847671732026ec1a6043e38ae228cfc27b0b5b27b2304ee1ad +b7bc8289edba34935bca94f680fa5eec2dd45f10cf13732b8698d84aa2bb +5f5db833d672cd7506da8fa396b0845d8994b9be69a515b9a099f3149247 +8f824413a40dd76c862830f89db2f21531141d5ead597fa5d816bb015cc8 +ee87ba594bcf0c717544f32eb695e911f585f593af6852cd27ae6b25e063 +29e7576a9855d0d7cf76e81dc8b6a42a3196d178112ec5b62994af67ffb9 +db4526c76f049b43a251f82426a002d760ea17104cc5702cf5c0dd20454f +b833d247d38352c951e412d4d5688c1991e4e570ddc3f514218dd1d5ea64 +36a094f14a96983e13b5e5997cb2d115abdd35c8d8d64ec1ba0c0b1da86f +c40bb1a456c03d79be63a870e9a882c235950bebab733b5a50adb07c35bd +8c7f8807f603fd0734b496e1a783e518a9069bc22ce8f48f29b905a18f11 +0fda8ee43acf22bedf99b2ebb1e607d1ab920dc290e30d041c468a0cf27d +948351d50c7205755264dc6add5279ca172abf27ba1b93a623f2e4796409 +592ce84c1ae4102e4b9221c6a8c8466319e6bfe089759d68dd58f74c19b3 +df9e140aa31ac26b7544a8497365507b35f85586b6025581b80f6647fff7 +1339acdd01c2fe36c6b7e615ca23304a828fb79d891545ab8cf5d15129b9 +75aa66132b89bd18e89a9106b7a95de04a3bb4f0802571886c5c38d05ad0 +9a3be3bb2960128bf22b70a8102a2c2063834c969cf050a5af3c050a3347 +358e00fdb0391dc3e0befdb1e52178243a0dde5dc83fc7a854eba1982ce7 +ff65e750b9c4dd86ddb7ff4ae7b72702d3cbc7a0b369102d247cae19677d +998f7b550f901ada79a82319f24e1806f44dd825326d7f5df6a9c0bb9546 +eb28e1d6dbdb2cc18ba3d463abd838b208419c168a2de68f252825faf425 +fe397f852fbfb4d379696e73b84b9a876458f526a623a5a0238a210cd5bb +715c33d3a8b48352902c2d83d18952c55fa749885132ab6b7e6db794b159 +88b9d511438124d8dde3678a74654f9253d0b8b5703bd0d35b3f7ea294fd +d9b44601a8e73ccb3fdbd980c2391d4c7928b41b46e9ad163886acc2b68c +5c4c2a06911a7fb36ecc544b7d886c75dacb52308ee0efea5e3f16a11028 +a53929f7b495389601bdca158609b9d8be1a5d68e5ce3827189a0f4a7e18 +2db0eb81fa0dcd6c587098f264a3d0e2049f84c8a4e8ff503a68e8102b43 +6a4bc956eb9081143cf2cb903aba73070f8b3c4721c361fd398f7d17b363 +dfffdfce66c02f2a7b110a9626a8fd9b7f053b286a7d7ac4d57ac019b77f +9051ff0972190fdc0968f8d527afc6d8e70d9c638c33bfea751e62d1d449 +0027c64e60cbe9c5aeb395bc6d692796dda167bd5bbbd233ed01ce57a8df +6faebf95c6c7539339f31397c1582d47fa00a40e236b7bca3a3bdaa06e53 +350f664c12e10f4b174195986e94c98699bafbd3105aff22a82f8d54e1a4 +88e44842bc58dedbbace508e3a69dd35dba1f0f0d69e34651bb078232519 +dbeed3b29d2dcee4b449be5f39a41d2e0c84ab52609f8bb0b3b85d0cbcfe +85a9ddd9bce5f1636b4dd7e7c77cdf6a025fcc206b9104ead365d8b52f42 +77d64ad3ec49aca1bb60b87b9f39d40678e3b2c8ad69d1b5d3fa6d0991bf +f3faadc1225617411fb4ba6b79b3eff8f3e0802d0092567f1c3d43118ed3 +0d3d90807474808a9bb5f07f31371f3a4cae9ede2f758875145f1f4be72e +8c7a8f1a733f91c761039025275d15f76daa677fb447795ca639a5c9f9e4 +bcf3c2c06bbe0202187ccc5f2cffbbc208641a52da611d40b08908500375 +829b8ceb8c93c7398389264b3821de6d37acca04fcbcd02499847b4297fd +cdb15ca26fbf868d5e335a3e0f3980ceb288149424968bc10ab2466a15ce +dbdf550eea623c162a3a7963d657ced119101602898b23d7cb99618b5b3d +59868f5ac31ce289ef1df56ba4c5c398068d5a928a4aa53325d95bd1c774 +f0d1d503628ba1546f464303e0f454cc6aca98d032acf05872da95a9188d +0f224b875c05157c2fc993d65521a770e6962407a22c0f2a14b80064bbc7 +4f496c61b44255c40c51bdf60dbfa7900f77296d59abf61f964fefb6aff3 +f5dccdd7a812fb5ec30c6dc8063bd828f6adead242dc0a6e72b100a694ac +24089d150b8729de5a322ad77d84e7f4a62570a178f0a9ec0dd32a7b9091 +78d9a544430cff30e2e570dbbb649d9e19554b39546713047ee0861b8a0d +960f690d2e2e160f24f152f6f0a93f6b13b1eb2477a416fbf3c15296ddb1 +3a3d09f771d8618a85dec2362f88d117f1bb174e829f96f9be965b175321 +a3bb0746376b95260b82cf34134d29ba6425d9b86e764791d699784151bf +26d4dc5b01cc0f88261df88e3cabb371d334e1a2f5f60952ec7038403f20 +45f70925e9d8b49ecc330bd90f563d3894b15ce629e686e3bae594e5c251 +2f7982eab95fd43cd595d8ec5fdf962f5e5277e416a91c279178bd98d082 +ced5655015c9f425c048aec135f5bf41260dea74fc1c16984c3db8deaa0a +65c1426b7a5e91ac5f67e222905efcdd297c1caa1dfc17fa1a3de462d320 +0a1491d41b26f799475daed3d6e3b1fe923d3cac505823a1e77ce6b07c0c +2efec207347a8e44d3c5d196376c7b7edce7c9bed0519da191a63fab427a +b930c1156f51c8d5ac5bd9d062e0e04089355df1619450c40d0050becf10 +37bdc9b62d7d4c90b76219991d215a37b31091cfd832d6a95669dd02b904 +0ac2b60419dcf064aa70a3c91a10e5e4087093246fb95645828a758d835f +51dcc7ab133b360dbb003ceeaaa1102dfc07931f0ee238273d9dc4c9c8b8 +ff089232bf823ffdd7a33d0d7e142070f240d078fdf590dafd88b89629b0 +275af422eb54bc1285eae58cad06bc2b12d5a0c2bfe51c4d1082aa23eaaf +334271c0523e3193d6aa4b6a30bcca62edb662d30d93f5f553a211612cc2 +ea7da1d19112cb981727edf44136ef358eda02444649008a8e9db0985ace +34a56bccd493378138af3f1632cd885259f01f97a38b185443e3b4408aaa +06c09529403545dc768be1f6e4b4e85ec2f094ab06d4ed78620489de9014 +ed3d4a76af19a75c3d65c73cf8b3aeda993e97289bba416758d561d6dc12 +23f3a5a740c2a64fe4aa02a8af2efff0a3fd8c0dacc5b6a9f0eae8833359 +bf6bef10d03bd931f05bea5cc117e21aa4e3a486845357a256af1ac28296 +7169745bce4592b4501cf410e4045a8ac47bf72f802ce93e562948b00848 +73f33f872340b4930954a97ae25e9c74677117ebbacc18e5cf9da28961e6 +442c545f7ee10d0689cad67b5e7e9abcbad934672e013a622bcde541a2ba +ea62f957c199fc3eeb1bb8091ed8ac159f5afb61d35893afbaa5883c5a97 +b0dab2b2c4ba2ff7a30935882011248f8d9e6d23b4a3d91a71df66c0398c +65be4cc71cba58bd19cbc9d5f7bdb30dfe9fa814c9d8b505b2bc3098a220 +4c5d35f353e66576e032fc0d23d2a2d49ed27d4ea0e4e0c17e6cfce3cc97 +470e9292faeda13b6647da7c64c7a717620980de1323c6040fb8f22e2537 +240422e2248bef0dcce6fc223b8720fc9dfe3c47809b31fddf8079d638f8 +690f441eea511b9cf818fbe872ff3e2a0a2950f9acdbb88d48b9d7648091 +5b0dd985074c0429e9f4ec356c6d1f418096ead18cb7669dce76e8b21a6b +0cf19dbaf1e79e2c70a1888ffcae76174518c355c3f733b6d051d9371b79 +6908c09ba1cb9fe3c7e16e4529912126b5253eff6acecda3c37fccc761f9 +d781f0c75eb7075c121c68540706958e26166e19e1c0b29ee08d2c2382f9 +9ac70ee4ee4a6296a4ffec552f3db6471aa42d3b38857223fe511d0aa35a +84b1c1205a304b2d0bfc95fffbd603e8e6f42e60017a2808babe00c270ce +ba6f93b83bb9c41c7787992734171fc2a4f0b46f06c6f029c82ccc985b7c +3c84ea655478ff79e8ab8fe6cce591ecb39c353a +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000 +cleartomark 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/Makefile b/locale/Makefile new file mode 100644 index 000000000..d1a0787c7 --- /dev/null +++ b/locale/Makefile @@ -0,0 +1,99 @@ +# +# "$Id: Makefile 4898 2006-01-08 23:13:20Z mike $" +# +# Locale file makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Locales... +# + +LOCALES = fr + + +# +# Make everything... +# + +all: translate + + +# +# Clean all config and object files... +# + +clean: + $(RM) translate translate.o + + +# +# Install files... +# + +install: + $(INSTALL_DIR) $(LOCALEDIR) + for loc in $(LOCALES) ; do \ + $(INSTALL_DIR) $(LOCALEDIR)/$$loc ; \ + $(INSTALL_DATA) cups_$$loc.po $(LOCALEDIR)/$$loc/cups_$$loc ; \ + done + + +# +# pot - Creates/updates the cups.pot template file, and merges changes +# into existing message catalogs. +# + +pot: + echo Updating cups.pot... + cd ..; xgettext -o locale/cups.pot -j --keyword=_ --no-wrap \ + --copyright-holder="Easy Software Products" \ + --msgid-bugs-address="http://www.cups.org/str.php" \ + */*.c + (cat cups.header; \ + tail +6 cups.pot | sed -e '1,$$s/PACKAGE VERSION/CUPS 1.2/' \ + -e '1,$$s/charset=CHARSET/charset=utf-8/'; \ + cat cups.footer) > cups.pot.N + mv cups.pot.N cups.pot + for loc in $(LOCALES) ; do \ + echo Merging changes into cups_$$loc.po... ; \ + msgmerge -o cups_$$loc.po cups_$$loc.po cups.pot ; \ + done + + +# +# translate - A simple utility which uses Google to translate the cups.pot +# 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 ../cups/i18n.h ../cups/language.h ../cups/string.h + + +# +# End of "$Id: Makefile 4898 2006-01-08 23:13:20Z mike $". +# diff --git a/locale/cups.footer b/locale/cups.footer new file mode 100644 index 000000000..490c9d4eb --- /dev/null +++ b/locale/cups.footer @@ -0,0 +1,5 @@ + + +# +# End of "$Id$". +# diff --git a/locale/cups.header b/locale/cups.header new file mode 100644 index 000000000..322330b7e --- /dev/null +++ b/locale/cups.header @@ -0,0 +1,26 @@ +# +# "$Id$" +# +# Message catalog template for the Common UNIX Printing System (CUPS). +# +# Copyright 2005-2006 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + + + diff --git a/locale/cups.pot b/locale/cups.pot new file mode 100644 index 000000000..e1cf6af47 --- /dev/null +++ b/locale/cups.pot @@ -0,0 +1,2142 @@ +# +# "$Id$" +# +# Message catalog template for the Common UNIX Printing System (CUPS). +# +# Copyright 2005-2006 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + + + +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: CUPS 1.2\n" +"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n" +"POT-Creation-Date: 2006-01-08 18:06-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: cgi-bin/admin.c:1276 +msgid "Options Installed" +msgstr "" + +#: cgi-bin/classes.c:103 +msgid "Class" +msgstr "" + +#: cgi-bin/printers.c:104 +msgid "Printer" +msgstr "" + +#: cups/ppd.c:654 cups/ppd.c:1045 +msgid "Extra" +msgstr "" + +#: cups/ppd.c:656 cups/ppd.c:881 cups/ppd.c:1047 +msgid "General" +msgstr "" + +#: cups/ppd.c:704 cups/ppd.c:1105 +msgid "Media Size" +msgstr "" + +#: cups/ppd.c:706 cups/ppd.c:1107 +msgid "Media Type" +msgstr "" + +#: cups/ppd.c:708 cups/ppd.c:1109 +msgid "Media Source" +msgstr "" + +#: cups/ppd.c:710 cups/ppd.c:1111 +msgid "Output Mode" +msgstr "" + +#: cups/ppd.c:712 cups/ppd.c:1113 +msgid "Resolution" +msgstr "" + +#: cups/ppd.c:907 +msgid "Variable" +msgstr "" + +#: cups/ppd.c:1535 +msgid "Yes" +msgstr "" + +#: cups/ppd.c:1537 +msgid "No" +msgstr "" + +#: cups/ppd.c:1824 +msgid "Auto" +msgstr "" + +#: scheduler/client.c:2247 +msgid "Enter your username and password or the root username and password to access this page." +msgstr "" + +#: scheduler/client.c:2252 +msgid "You must use a https: URL to access this page." +msgstr "" + +#: scheduler/ipp.c:236 +#, c-format +msgid "Bad request version number %d.%d!" +msgstr "" + +#: scheduler/ipp.c:246 +msgid "No attributes in request!" +msgstr "" + +#: scheduler/ipp.c:269 +#, c-format +msgid "Attribute groups are out of order (%x < %x)!" +msgstr "" + +#: scheduler/ipp.c:379 +msgid "Missing required attributes!" +msgstr "" + +#: scheduler/ipp.c:575 +#, c-format +msgid "%s not supported!" +msgstr "" + +#: scheduler/ipp.c:684 scheduler/ipp.c:1055 scheduler/ipp.c:2271 +#: scheduler/ipp.c:2383 scheduler/ipp.c:3707 scheduler/ipp.c:4417 +#: scheduler/ipp.c:4649 scheduler/ipp.c:5002 scheduler/ipp.c:5445 +#: scheduler/ipp.c:5890 scheduler/ipp.c:6245 scheduler/ipp.c:6609 +#: scheduler/ipp.c:7308 scheduler/ipp.c:8179 scheduler/ipp.c:8585 +#: scheduler/ipp.c:8663 scheduler/ipp.c:8836 +msgid "The printer or class was not found." +msgstr "" + +#: scheduler/ipp.c:762 +msgid "The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"." +msgstr "" + +#: scheduler/ipp.c:778 scheduler/ipp.c:1454 +#, c-format +msgid "The printer-uri \"%s\" contains invalid characters." +msgstr "" + +#: scheduler/ipp.c:811 +#, c-format +msgid "A printer named \"%s\" already exists!" +msgstr "" + +#: scheduler/ipp.c:904 +#, c-format +msgid "Attempt to set %s printer-state to bad value %d!" +msgstr "" + +#: scheduler/ipp.c:1000 +#, c-format +msgid "add_class: Unknown printer-op-policy \"%s\"." +msgstr "" + +#: scheduler/ipp.c:1013 +#, c-format +msgid "add_class: Unknown printer-error-policy \"%s\"." +msgstr "" + +#: scheduler/ipp.c:1144 +msgid "Unable to allocate memory for file types!" +msgstr "" + +#: scheduler/ipp.c:1290 scheduler/ipp.c:4501 +#, c-format +msgid "Character set \"%s\" not supported!" +msgstr "" + +#: scheduler/ipp.c:1299 scheduler/ipp.c:4510 +#, c-format +msgid "Language \"%s\" not supported!" +msgstr "" + +#: scheduler/ipp.c:1309 scheduler/ipp.c:4520 +#, c-format +msgid "The notify-user-data value is too large (%d > 63 octets)!" +msgstr "" + +#: scheduler/ipp.c:1326 +msgid "The notify-lease-duration attribute cannot be used with job subscriptions." +msgstr "" + +#: scheduler/ipp.c:1438 +msgid "The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"." +msgstr "" + +#: scheduler/ipp.c:1487 +#, c-format +msgid "A class named \"%s\" already exists!" +msgstr "" + +#: scheduler/ipp.c:1575 +#, c-format +msgid "File device URIs have been disabled! To enable, see the FileDevice directive in \"%s/cupsd.conf\"." +msgstr "" + +#: scheduler/ipp.c:1595 +#, c-format +msgid "Bad device-uri \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:1626 +#, c-format +msgid "Bad port-monitor \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:1669 +#, c-format +msgid "Bad printer-state value %d!" +msgstr "" + +#: scheduler/ipp.c:1762 +#, c-format +msgid "Unknown printer-op-policy \"%s\"." +msgstr "" + +#: scheduler/ipp.c:1775 +#, c-format +msgid "Unknown printer-error-policy \"%s\"." +msgstr "" + +#: scheduler/ipp.c:1837 +#, c-format +msgid "Unable to copy interface script - %s!" +msgstr "" + +#: scheduler/ipp.c:1862 +#, c-format +msgid "Unable to copy PPD file - %s!" +msgstr "" + +#: scheduler/ipp.c:1915 +msgid "Unable to copy PPD file!" +msgstr "" + +#: scheduler/ipp.c:2076 scheduler/ipp.c:2364 scheduler/ipp.c:5188 +#: scheduler/ipp.c:6008 scheduler/ipp.c:6147 scheduler/ipp.c:7394 +#: scheduler/ipp.c:7538 scheduler/ipp.c:7776 scheduler/ipp.c:8261 +msgid "Got a printer-uri attribute but no job-id!" +msgstr "" + +#: scheduler/ipp.c:2097 scheduler/ipp.c:2433 scheduler/ipp.c:5210 +#: scheduler/ipp.c:6029 scheduler/ipp.c:6169 scheduler/ipp.c:7416 +#: scheduler/ipp.c:7560 scheduler/ipp.c:7797 scheduler/ipp.c:8282 +#, c-format +msgid "Bad job-uri attribute \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:2116 scheduler/ipp.c:2451 scheduler/ipp.c:5228 +#: scheduler/ipp.c:6047 scheduler/ipp.c:6188 scheduler/ipp.c:7434 +#: scheduler/ipp.c:7578 scheduler/ipp.c:7815 scheduler/ipp.c:8300 +#, c-format +msgid "Job #%d doesn't exist!" +msgstr "" + +#: scheduler/ipp.c:2131 +#, c-format +msgid "Job #%d is not held for authentication!" +msgstr "" + +#: scheduler/ipp.c:2153 +#, c-format +msgid "You are not authorized to authenticate job #%d owned by \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:2221 +msgid "The printer-uri attribute is required!" +msgstr "" + +#: scheduler/ipp.c:2238 +msgid "Missing requesting-user-name attribute!" +msgstr "" + +#: scheduler/ipp.c:2277 +#, c-format +msgid "The printer-uri \"%s\" is not valid." +msgstr "" + +#: scheduler/ipp.c:2410 +#, c-format +msgid "No active jobs on %s!" +msgstr "" + +#: scheduler/ipp.c:2462 +#, c-format +msgid "You are not authorized to delete job #%d owned by \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:2476 +#, c-format +msgid "Job #%d is already %s - can't cancel." +msgstr "" + +#: scheduler/ipp.c:3720 +msgid "The printer or class is not shared!" +msgstr "" + +#: scheduler/ipp.c:3746 scheduler/ipp.c:6647 +#, c-format +msgid "Destination \"%s\" is not accepting jobs." +msgstr "" + +#: scheduler/ipp.c:3759 scheduler/ipp.c:6443 +#, c-format +msgid "Bad copies value %d." +msgstr "" + +#: scheduler/ipp.c:3775 scheduler/ipp.c:6459 +#, c-format +msgid "Bad page-ranges values %d-%d." +msgstr "" + +#: scheduler/ipp.c:3795 +msgid "Too many active jobs." +msgstr "" + +#: scheduler/ipp.c:3801 scheduler/ipp.c:6668 +msgid "Quota limit reached." +msgstr "" + +#: scheduler/ipp.c:3824 scheduler/ipp.c:6691 +#, c-format +msgid "Unable to add job for destination \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:4469 +msgid "No subscription attributes in request!" +msgstr "" + +#: scheduler/ipp.c:4559 +msgid "notify-events not specified!" +msgstr "" + +#: scheduler/ipp.c:4577 +#, c-format +msgid "Job %d not found!" +msgstr "" + +#: scheduler/ipp.c:4827 +msgid "No default printer" +msgstr "" + +#: scheduler/ipp.c:4930 +msgid "cups-deviced failed to execute." +msgstr "" + +#: scheduler/ipp.c:5393 +msgid "cups-driverd failed to execute." +msgstr "" + +#: scheduler/ipp.c:5571 +msgid "No destinations added." +msgstr "" + +#: scheduler/ipp.c:5794 +#, c-format +msgid "notify-subscription-id %d no good!" +msgstr "" + +#: scheduler/ipp.c:5878 +#, c-format +msgid "Job #%s does not exist!" +msgstr "" + +#: scheduler/ipp.c:5900 scheduler/ipp.c:2116 scheduler/ipp.c:2451 +#: scheduler/ipp.c:5228 scheduler/ipp.c:6047 scheduler/ipp.c:6188 +#: scheduler/ipp.c:7434 scheduler/ipp.c:7578 scheduler/ipp.c:7815 +#: scheduler/ipp.c:8300 +#, c-format +msgid "Job #%d does not exist!" +msgstr "" + +#: scheduler/ipp.c:5969 +msgid "No subscriptions found." +msgstr "" + +#: scheduler/ipp.c:6058 +#, c-format +msgid "Not authorized to hold job #%d owned by \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:6203 scheduler/ipp.c:8315 +#, c-format +msgid "Job #%d is finished and cannot be altered!" +msgstr "" + +#: scheduler/ipp.c:6215 +#, c-format +msgid "You are not authorized to move job #%d owned by \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:6228 +msgid "job-printer-uri attribute missing!" +msgstr "" + +#: scheduler/ipp.c:6485 scheduler/ipp.c:7847 +#, c-format +msgid "Unsupported compression \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:6504 scheduler/ipp.c:7866 +msgid "No file!?!" +msgstr "" + +#: scheduler/ipp.c:6522 +#, c-format +msgid "Could not scan type \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:6574 scheduler/ipp.c:7936 +#, c-format +msgid "Unsupported format '%s/%s'!" +msgstr "" + +#: scheduler/ipp.c:6621 +msgid "Printer not shared!" +msgstr "" + +#: scheduler/ipp.c:6661 +#, c-format +msgid "Too many jobs - %d jobs, max jobs is %d." +msgstr "" + +#: scheduler/ipp.c:7448 +#, c-format +msgid "Job #%d is not held!" +msgstr "" + +#: scheduler/ipp.c:7459 +#, c-format +msgid "You are not authorized to release job id %d owned by \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:7592 +#, c-format +msgid "Job #%d is not complete!" +msgstr "" + +#: scheduler/ipp.c:7608 +#, c-format +msgid "Job #%d cannot be restarted - no files!" +msgstr "" + +#: scheduler/ipp.c:7619 +#, c-format +msgid "You are not authorized to restart job id %d owned by \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:7826 +#, c-format +msgid "You are not authorized to send document for job #%d owned by \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:7883 scheduler/ipp.c:8803 +#, c-format +msgid "Bad document-format \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:8326 +#, c-format +msgid "You are not authorized to alter job id %d owned by \"%s\"!" +msgstr "" + +#: scheduler/ipp.c:8371 +#, c-format +msgid "%s cannot be changed." +msgstr "" + +#: scheduler/ipp.c:8387 +msgid "Bad job-priority value!" +msgstr "" + +#: scheduler/ipp.c:8395 +msgid "Job is completed and cannot be changed." +msgstr "" + +#: scheduler/ipp.c:8409 +msgid "Bad job-state value!" +msgstr "" + +#: scheduler/ipp.c:8423 scheduler/ipp.c:8435 scheduler/ipp.c:8446 +msgid "Job state cannot be changed." +msgstr "" + +#: scheduler/ipp.c:8787 +#, c-format +msgid "Unsupported compression attribute %s!" +msgstr "" + +#: scheduler/ipp.c:8815 +#, c-format +msgid "Unsupported format \"%s\"!" +msgstr "" + +#: berkeley/lpc.c:201 +#, c-format +msgid "%s is not implemented by the CUPS version of lpc.\n" +msgstr "" + +#: berkeley/lpc.c:216 +msgid "" +"Commands may be abbreviated. Commands are:\n" +"\n" +"exit help quit status ?\n" +msgstr "" + +#: berkeley/lpc.c:222 +msgid "help\t\tget help on commands\n" +msgstr "" + +#: berkeley/lpc.c:225 +msgid "status\t\tshow status of daemon and queue\n" +msgstr "" + +#: berkeley/lpc.c:228 +msgid "?Invalid help command unknown\n" +msgstr "" + +#: berkeley/lpc.c:478 berkeley/lpc.c:490 +#, c-format +msgid "\tprinter is on device '%s' speed -1\n" +msgstr "" + +#: berkeley/lpc.c:496 +msgid "\tqueuing is enabled\n" +msgstr "" + +#: berkeley/lpc.c:498 +msgid "\tqueuing is disabled\n" +msgstr "" + +#: berkeley/lpc.c:501 +msgid "\tprinting is enabled\n" +msgstr "" + +#: berkeley/lpc.c:503 +msgid "\tprinting is disabled\n" +msgstr "" + +#: berkeley/lpc.c:506 +msgid "\tno entries\n" +msgstr "" + +#: berkeley/lpc.c:508 +#, c-format +msgid "\t%d entries\n" +msgstr "" + +#: berkeley/lpc.c:510 +msgid "\tdaemon present\n" +msgstr "" + +#: berkeley/lpq.c:94 +msgid "lpq: Unable to contact server!\n" +msgstr "" + +#: berkeley/lpq.c:125 berkeley/lpr.c:114 berkeley/lprm.c:107 +#: systemv/accept.c:108 systemv/cancel.c:95 systemv/lpstat.c:115 +#: systemv/lpadmin.c:284 systemv/lp.c:135 systemv/lpinfo.c:80 +#: systemv/lpmove.c:84 +#, c-format +msgid "%s: Sorry, no encryption support compiled in!\n" +msgstr "" + +#: berkeley/lpq.c:155 +#, c-format +msgid "lpq: Unknown destination \"%s/%s\"!\n" +msgstr "" + +#: berkeley/lpq.c:159 +#, c-format +msgid "lpq: Unknown destination \"%s\"!\n" +msgstr "" + +#: berkeley/lpq.c:211 systemv/lp.c:564 +#, c-format +msgid "lp: error - %s environment variable names non-existent destination \"%s\"!\n" +msgstr "" + +#: berkeley/lpq.c:216 +msgid "lpq: error - no default destination available.\n" +msgstr "" + +#: berkeley/lpq.c:363 berkeley/lpq.c:523 +#, c-format +msgid "lpq: get-jobs failed: %s\n" +msgstr "" + +#: berkeley/lpq.c:457 +msgid "Rank Owner Pri Job Files Total Size\n" +msgstr "" + +#: berkeley/lpq.c:461 +msgid "Rank Owner Job File(s) Total Size\n" +msgstr "" + +#: berkeley/lpq.c:498 +#, c-format +msgid "%s: %-33.33s [job %d localhost]\n" +msgstr "" + +#: berkeley/lpq.c:500 +#, c-format +msgid " %-39.39s %.0f bytes\n" +msgstr "" + +#: berkeley/lpq.c:506 +#, c-format +msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n" +msgstr "" + +#: berkeley/lpq.c:511 +#, c-format +msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n" +msgstr "" + +#: berkeley/lpq.c:529 +msgid "no entries\n" +msgstr "" + +#: berkeley/lpq.c:591 berkeley/lpq.c:620 +#, c-format +msgid "lpq: get-printer-attributes failed: %s\n" +msgstr "" + +#: berkeley/lpq.c:605 +#, c-format +msgid "%s is ready\n" +msgstr "" + +#: berkeley/lpq.c:608 +#, c-format +msgid "%s is ready and printing\n" +msgstr "" + +#: berkeley/lpq.c:612 +#, c-format +msgid "%s is not ready\n" +msgstr "" + +#: berkeley/lpq.c:633 +msgid "Usage: lpq [-P dest] [-l] [+interval]\n" +msgstr "" + +#: berkeley/lpr.c:132 +#, c-format +msgid "lpr: error - expected value after -%c option!\n" +msgstr "" + +#: berkeley/lpr.c:146 +#, c-format +msgid "lpr: warning - '%c' format modifier not supported - output may not be correct!\n" +msgstr "" + +#: berkeley/lpr.c:159 +msgid "lpr: error - expected option=value after -o option!\n" +msgstr "" + +#: berkeley/lpr.c:185 +msgid "lpr: warning - email notification is not currently supported!\n" +msgstr "" + +#: berkeley/lpr.c:207 +msgid "lpr: error - expected destination after -P option!\n" +msgstr "" + +#: berkeley/lpr.c:240 +msgid "lpr: error - expected copy count after -# option!\n" +msgstr "" + +#: berkeley/lpr.c:263 +#, c-format +msgid "lpr: error - expected name after -%c option!\n" +msgstr "" + +#: berkeley/lpr.c:281 +msgid "lpr: error - expected username after -U option!\n" +msgstr "" + +#: berkeley/lpr.c:292 +#, c-format +msgid "lpr: error - unknown option '%c'!\n" +msgstr "" + +#: berkeley/lpr.c:305 +#, c-format +msgid "lpr: error - unable to access \"%s\" - %s\n" +msgstr "" + +#: berkeley/lpr.c:323 +#, c-format +msgid "lpr: error - too many files - \"%s\"\n" +msgstr "" + +#: berkeley/lpr.c:364 +#, c-format +msgid "lpr: error - %s environment variable names non-existent destination \"%s\"!\n" +msgstr "" + +#: berkeley/lpr.c:369 +msgid "lpr: error - no default destination available.\n" +msgstr "" + +#: berkeley/lpr.c:372 +msgid "lpr: error - scheduler not responding!\n" +msgstr "" + +#: berkeley/lpr.c:421 +#, c-format +msgid "lpr: error - unable to create temporary file \"%s\" - %s\n" +msgstr "" + +#: berkeley/lpr.c:431 +#, c-format +msgid "lpr: error - unable to write to temporary file \"%s\" - %s\n" +msgstr "" + +#: berkeley/lpr.c:445 +msgid "lpr: error - stdin is empty, so no job has been sent.\n" +msgstr "" + +#: berkeley/lpr.c:461 +#, c-format +msgid "lpr: error - unable to print file: %s\n" +msgstr "" + +#: berkeley/lprm.c:87 +msgid "lprm: Unable to contact server!\n" +msgstr "" + +#: berkeley/lprm.c:127 +#, c-format +msgid "lprm: Unknown destination \"%s\"!\n" +msgstr "" + +#: berkeley/lprm.c:136 +#, c-format +msgid "lprm: Unknown option '%c'!\n" +msgstr "" + +#: berkeley/lprm.c:223 +msgid "lprm: Job or printer not found!\n" +msgstr "" + +#: berkeley/lprm.c:227 +msgid "lprm: Not authorized to lprm job(s)!\n" +msgstr "" + +#: berkeley/lprm.c:231 +#, c-format +msgid "lprm: You don't own job ID %d!\n" +msgstr "" + +#: berkeley/lprm.c:236 +msgid "lprm: Unable to lprm job(s)!\n" +msgstr "" + +#: berkeley/lprm.c:253 berkeley/lprm.c:269 +msgid "lprm: Unable to cancel job(s)!\n" +msgstr "" + +#: systemv/accept.c:84 +#, c-format +msgid "%s: Don't know what to do!\n" +msgstr "" + +#: systemv/accept.c:129 +#, c-format +msgid "%s: Expected server name after -h!\n" +msgstr "" + +#: systemv/accept.c:147 +#, c-format +msgid "%s: Expected reason text after -r!\n" +msgstr "" + +#: systemv/accept.c:157 +#, c-format +msgid "%s: Unknown option '%c'!\n" +msgstr "" + +#: systemv/accept.c:173 +#, c-format +msgid "%s: Unable to connect to server: %s\n" +msgstr "" + +#: systemv/accept.c:217 systemv/accept.c:227 systemv/accept.c:268 +#: systemv/accept.c:278 +#, c-format +msgid "%s: Operation failed: %s\n" +msgstr "" + +#: systemv/cancel.c:118 +msgid "cancel: Error - expected hostname after '-h' option!\n" +msgstr "" + +#: systemv/cancel.c:139 +msgid "cancel: Error - expected username after '-u' option!\n" +msgstr "" + +#: systemv/cancel.c:150 +#, c-format +msgid "cancel: Unknown option '%c'!\n" +msgstr "" + +#: systemv/cancel.c:207 +#, c-format +msgid "cancel: Unknown destination \"%s\"!\n" +msgstr "" + +#: systemv/cancel.c:229 systemv/cancel.c:319 +msgid "cancel: Unable to contact server!\n" +msgstr "" + +#: systemv/cancel.c:295 systemv/cancel.c:370 +#, c-format +msgid "cancel: %s failed: %s\n" +msgstr "" + +#: systemv/cupsaddsmb.c:290 +#, c-format +msgid "cupsaddsmb: Missing value on line %d!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:301 +#, c-format +msgid "cupsaddsmb: Missing double quote on line %d!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:313 +#, c-format +msgid "cupsaddsmb: Bad option + choice on line %d!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:496 +#, c-format +msgid "cupsaddsmb: Unable to connect to server \"%s\" for %s - %s\n" +msgstr "" + +#: systemv/cupsaddsmb.c:509 +#, c-format +msgid "cupsaddsmb: No PPD file for printer \"%s\" - skipping!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:548 systemv/cupsaddsmb.c:562 +#, c-format +msgid "cupsaddsmb: get-printer-attributes failed for \"%s\": %s\n" +msgstr "" + +#: systemv/cupsaddsmb.c:578 +#, c-format +msgid "cupsaddsmb: Unable to convert PPD file for %s - %s\n" +msgstr "" + +#: systemv/cupsaddsmb.c:633 +#, c-format +msgid "cupsaddsmb: Unable to copy Windows 2000 printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:660 +#, c-format +msgid "cupsaddsmb: Unable to copy CUPS printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:697 +#, c-format +msgid "cupsaddsmb: Unable to install Windows 2000 printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:727 +#, c-format +msgid "cupsaddsmb: Unable to copy Windows 9x printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:750 +#, c-format +msgid "cupsaddsmb: Unable to install Windows 9x printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:771 +#, c-format +msgid "cupsaddsmb: Unable to set Windows printer driver (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:854 +msgid "" +"Usage: cupsaddsmb [options] printer1 ... printerN\n" +" cupsaddsmb [options] -a\n" +"\n" +"Options:\n" +" -H samba-server Use the named SAMBA server\n" +" -U samba-user Authenticate using the named SAMBA user\n" +" -a Export all printers\n" +" -h cups-server Use the named CUPS server\n" +" -v Be verbose (show commands)\n" +msgstr "" + +#: systemv/cupstestppd.c:120 +msgid "cupstestppd: The -q option is incompatible with the -v option.\n" +msgstr "" + +#: systemv/cupstestppd.c:136 +msgid "cupstestppd: The -v option is incompatible with the -q option.\n" +msgstr "" + +#: systemv/cupstestppd.c:193 +#, c-format +msgid "" +" FAIL\n" +" **FAIL** Unable to open PPD file - %s\n" +msgstr "" + +#: systemv/cupstestppd.c:204 +#, c-format +msgid "" +" FAIL\n" +" **FAIL** Unable to open PPD file - %s on line %d.\n" +msgstr "" + +#: systemv/cupstestppd.c:213 +msgid " REF: Page 42, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:217 +msgid " REF: Page 20, section 3.4.\n" +msgstr "" + +#: systemv/cupstestppd.c:222 +msgid " REF: Pages 45-46, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:227 +msgid " REF: Pages 42-45, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:231 +msgid " REF: Pages 48-49, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:235 +msgid " REF: Pages 52-54, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:239 +msgid " REF: Page 15, section 3.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:243 systemv/cupstestppd.c:247 +msgid " REF: Page 15, section 3.1.\n" +msgstr "" + +#: systemv/cupstestppd.c:251 +msgid " REF: Pages 16-17, section 3.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:255 +msgid " REF: Page 19, section 3.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:259 +msgid " REF: Page 27, section 3.5.\n" +msgstr "" + +#: systemv/cupstestppd.c:280 +msgid "" +"\n" +" DETAILED CONFORMANCE TEST RESULTS\n" +msgstr "" + +#: systemv/cupstestppd.c:307 +#, c-format +msgid " WARN %s has no corresponding options!\n" +msgstr "" + +#: systemv/cupstestppd.c:318 systemv/cupstestppd.c:333 +#: systemv/cupstestppd.c:354 systemv/cupstestppd.c:369 +#: systemv/cupstestppd.c:397 systemv/cupstestppd.c:417 +#: systemv/cupstestppd.c:439 systemv/cupstestppd.c:459 +#: systemv/cupstestppd.c:479 systemv/cupstestppd.c:499 +#: systemv/cupstestppd.c:517 systemv/cupstestppd.c:535 +#: systemv/cupstestppd.c:556 systemv/cupstestppd.c:575 +#: systemv/cupstestppd.c:595 systemv/cupstestppd.c:615 +#: systemv/cupstestppd.c:635 systemv/cupstestppd.c:655 +#: systemv/cupstestppd.c:673 systemv/cupstestppd.c:690 +#: systemv/cupstestppd.c:712 systemv/cupstestppd.c:730 +#: systemv/cupstestppd.c:747 systemv/cupstestppd.c:765 +#: systemv/cupstestppd.c:781 systemv/cupstestppd.c:801 +#: systemv/cupstestppd.c:832 systemv/cupstestppd.c:854 +#: systemv/cupstestppd.c:902 systemv/cupstestppd.c:931 +#: systemv/cupstestppd.c:952 +msgid " FAIL\n" +msgstr "" + +#: systemv/cupstestppd.c:321 +msgid "" +" **FAIL** REQUIRED DefaultImageableArea\n" +" REF: Page 102, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:336 +#, c-format +msgid "" +" **FAIL** BAD DefaultImageableArea %s!\n" +" REF: Page 102, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:346 +msgid " PASS DefaultImageableArea\n" +msgstr "" + +#: systemv/cupstestppd.c:357 +msgid "" +" **FAIL** REQUIRED DefaultPaperDimension\n" +" REF: Page 103, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:372 +#, c-format +msgid "" +" **FAIL** BAD DefaultPaperDimension %s!\n" +" REF: Page 103, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:380 +msgid " PASS DefaultPaperDimension\n" +msgstr "" + +#: systemv/cupstestppd.c:400 +#, c-format +msgid "" +" **FAIL** BAD Default%s %s\n" +" REF: Page 40, section 4.5.\n" +msgstr "" + +#: systemv/cupstestppd.c:409 +#, c-format +msgid " PASS Default%s\n" +msgstr "" + +#: systemv/cupstestppd.c:420 +#, c-format +msgid "" +" **FAIL** REQUIRED Default%s\n" +" REF: Page 40, section 4.5.\n" +msgstr "" + +#: systemv/cupstestppd.c:432 +msgid " PASS FileVersion\n" +msgstr "" + +#: systemv/cupstestppd.c:442 +msgid "" +" **FAIL** REQUIRED FileVersion\n" +" REF: Page 56, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:452 +msgid " PASS FormatVersion\n" +msgstr "" + +#: systemv/cupstestppd.c:462 +msgid "" +" **FAIL** REQUIRED FormatVersion\n" +" REF: Page 56, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:472 +msgid " PASS LanguageEncoding\n" +msgstr "" + +#: systemv/cupstestppd.c:482 +msgid "" +" **FAIL** REQUIRED LanguageEncoding\n" +" REF: Pages 56-57, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:492 +msgid " PASS LanguageVersion\n" +msgstr "" + +#: systemv/cupstestppd.c:502 +msgid "" +" **FAIL** REQUIRED LanguageVersion\n" +" REF: Pages 57-58, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:520 +msgid "" +" **FAIL** BAD Manufacturer (should be \"HP\")\n" +" REF: Page 211, table D.1.\n" +msgstr "" + +#: systemv/cupstestppd.c:528 +msgid " PASS Manufacturer\n" +msgstr "" + +#: systemv/cupstestppd.c:538 +msgid "" +" **FAIL** REQUIRED Manufacturer\n" +" REF: Pages 58-59, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:559 +#, c-format +msgid "" +" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n" +" REF: Pages 59-60, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:568 +msgid " PASS ModelName\n" +msgstr "" + +#: systemv/cupstestppd.c:578 +msgid "" +" **FAIL** REQUIRED ModelName\n" +" REF: Pages 59-60, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:588 +msgid " PASS NickName\n" +msgstr "" + +#: systemv/cupstestppd.c:598 +msgid "" +" **FAIL** REQUIRED NickName\n" +" REF: Page 60, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:608 +msgid " PASS PageSize\n" +msgstr "" + +#: systemv/cupstestppd.c:618 +msgid "" +" **FAIL** REQUIRED PageSize\n" +" REF: Pages 99-100, section 5.14.\n" +msgstr "" + +#: systemv/cupstestppd.c:628 +msgid " PASS PageRegion\n" +msgstr "" + +#: systemv/cupstestppd.c:638 +msgid "" +" **FAIL** REQUIRED PageRegion\n" +" REF: Page 100, section 5.14.\n" +msgstr "" + +#: systemv/cupstestppd.c:648 +msgid " PASS PCFileName\n" +msgstr "" + +#: systemv/cupstestppd.c:658 +msgid "" +" **FAIL** REQUIRED PCFileName\n" +" REF: Pages 61-62, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:676 +msgid "" +" **FAIL** BAD Product - not \"(string)\".\n" +" REF: Page 62, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:683 +msgid " PASS Product\n" +msgstr "" + +#: systemv/cupstestppd.c:693 +msgid "" +" **FAIL** REQUIRED Product\n" +" REF: Page 62, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:715 +msgid "" +" **FAIL** BAD PSVersion - not \"(string) int\".\n" +" REF: Pages 62-64, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:723 +msgid " PASS PSVersion\n" +msgstr "" + +#: systemv/cupstestppd.c:733 +msgid "" +" **FAIL** REQUIRED PSVersion\n" +" REF: Pages 62-64, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:750 +msgid "" +" **FAIL** BAD ShortNickName - longer than 31 chars.\n" +" REF: Pages 64-65, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:758 +msgid " PASS ShortNickName\n" +msgstr "" + +#: systemv/cupstestppd.c:768 +msgid "" +" **FAIL** REQUIRED ShortNickName\n" +" REF: Page 64-65, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:784 +msgid "" +" **FAIL** BAD JobPatchFile attribute in file\n" +" REF: Page 24, section 3.4.\n" +msgstr "" + +#: systemv/cupstestppd.c:804 +msgid "" +" **FAIL** REQUIRED PageSize\n" +" REF: Page 41, section 5.\n" +" REF: Page 99, section 5.14.\n" +msgstr "" + +#: systemv/cupstestppd.c:835 +#, c-format +msgid "" +" **FAIL** REQUIRED ImageableArea for PageSize %s\n" +" REF: Page 41, section 5.\n" +" REF: Page 102, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:857 +#, c-format +msgid "" +" **FAIL** REQUIRED PaperDimension for PageSize %s\n" +" REF: Page 41, section 5.\n" +" REF: Page 103, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:905 +#, c-format +msgid "" +" **FAIL** Bad %s choice %s!\n" +" REF: Page 84, section 5.9\n" +msgstr "" + +#: systemv/cupstestppd.c:934 +#, c-format +msgid "" +" **FAIL** REQUIRED %s does not define choice None!\n" +" REF: Page 122, section 5.17\n" +msgstr "" + +#: systemv/cupstestppd.c:955 +#, c-format +msgid "" +" **FAIL** Bad %s choice %s!\n" +" REF: Page 122, section 5.17\n" +msgstr "" + +#: systemv/cupstestppd.c:967 +msgid " PASS\n" +msgstr "" + +#: systemv/cupstestppd.c:976 +#, c-format +msgid "" +" WARN Duplex option keyword %s should be named Duplex or JCLDuplex!\n" +" REF: Page 122, section 5.17\n" +msgstr "" + +#: systemv/cupstestppd.c:986 +msgid " WARN Default choices conflicting!\n" +msgstr "" + +#: systemv/cupstestppd.c:994 +#, c-format +msgid "" +" WARN Obsolete PPD version %.1f!\n" +" REF: Page 42, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:1002 +msgid "" +" WARN LanguageEncoding required by PPD 4.3 spec.\n" +" REF: Pages 56-57, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:1010 +msgid "" +" WARN Manufacturer required by PPD 4.3 spec.\n" +" REF: Pages 58-59, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:1023 +msgid "" +" WARN PCFileName longer than 8.3 in violation of PPD spec.\n" +" REF: Pages 61-62, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:1031 +msgid "" +" WARN ShortNickName required by PPD 4.3 spec.\n" +" REF: Pages 64-65, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:1048 +msgid "" +" WARN Protocols contains both PJL and BCP; expected TBCP.\n" +" REF: Pages 78-79, section 5.7.\n" +msgstr "" + +#: systemv/cupstestppd.c:1057 +msgid "" +" WARN Protocols contains PJL but JCL attributes are not set.\n" +" REF: Pages 78-79, section 5.7.\n" +msgstr "" + +#: systemv/cupstestppd.c:1085 +#, c-format +msgid "" +" WARN %s shares a common prefix with %s\n" +" REF: Page 15, section 3.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:1097 +#, c-format +msgid " %d ERROR%s FOUND\n" +msgstr "" + +#: systemv/cupstestppd.c:1100 +msgid " NO ERRORS FOUND\n" +msgstr "" + +#: systemv/cupstestppd.c:1360 +#, c-format +msgid "" +" WARN \"%s %s\" conflicts with \"%s %s\"\n" +" (constraint=\"%s %s %s %s\")\n" +msgstr "" + +#: systemv/cupstestppd.c:1376 +msgid "" +"Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] [... filenameN.ppd[.gz]]\n" +" program | cupstestppd [-q] [-r] [-v[v]] -\n" +msgstr "" + +#: systemv/lpstat.c:144 systemv/lpstat.c:155 +msgid "lpstat: Need \"completed\" or \"not-completed\" after -W!\n" +msgstr "" + +#: systemv/lpstat.c:212 +msgid "lpstat: The -b option requires a destination argument.\n" +msgstr "" + +#: systemv/lpstat.c:274 systemv/lpinfo.c:143 systemv/lpmove.c:105 +msgid "Error: need hostname after '-h' option!\n" +msgstr "" + +#: systemv/lpstat.c:433 +#, c-format +msgid "lpstat: Unknown option '%c'!\n" +msgstr "" + +#: systemv/lpstat.c:504 +#, c-format +msgid "lpstat: Invalid destination name in list \"%s\"!\n" +msgstr "" + +#: systemv/lpstat.c:519 +#, c-format +msgid "lpstat: Unknown destination \"%s\"!\n" +msgstr "" + +#: systemv/lpstat.c:541 +#, c-format +msgid "lpstat: Unable to connect to server %s on port %d: %s\n" +msgstr "" + +#: systemv/lpstat.c:625 systemv/lpstat.c:773 systemv/lpstat.c:1187 +#: systemv/lpstat.c:1379 systemv/lpstat.c:1809 systemv/lpstat.c:2262 +#, c-format +msgid "lpstat: get-printers failed: %s\n" +msgstr "" + +#: systemv/lpstat.c:741 +#, c-format +msgid "%s accepting requests since Jan 01 00:00\n" +msgstr "" + +#: systemv/lpstat.c:745 +#, c-format +msgid "" +"%s not accepting requests since Jan 01 00:00 -\n" +"\t%s\n" +msgstr "" + +#: systemv/lpstat.c:754 +#, c-format +msgid "%s/%s accepting requests since Jan 01 00:00\n" +msgstr "" + +#: systemv/lpstat.c:758 +#, c-format +msgid "" +"%s/%s not accepting requests since Jan 01 00:00 -\n" +"\t%s\n" +msgstr "" + +#: systemv/lpstat.c:861 systemv/lpstat.c:1056 +#, c-format +msgid "lpstat: get-classes failed: %s\n" +msgstr "" + +#: systemv/lpstat.c:1033 +#, c-format +msgid "members of class %s:\n" +msgstr "" + +#: systemv/lpstat.c:1080 +#, c-format +msgid "system default destination: %s/%s\n" +msgstr "" + +#: systemv/lpstat.c:1083 +#, c-format +msgid "system default destination: %s\n" +msgstr "" + +#: systemv/lpstat.c:1105 +#, c-format +msgid "lpstat: error - %s environment variable names non-existent destination \"%s\"!\n" +msgstr "" + +#: systemv/lpstat.c:1109 +msgid "no system default destination\n" +msgstr "" + +#: systemv/lpstat.c:1313 +#, c-format +msgid "Output for printer %s is sent to remote printer %s on %s\n" +msgstr "" + +#: systemv/lpstat.c:1319 systemv/lpstat.c:1323 +#, c-format +msgid "Output for printer %s is sent to %s\n" +msgstr "" + +#: systemv/lpstat.c:1331 +#, c-format +msgid "Output for printer %s/%s is sent to remote printer %s on %s\n" +msgstr "" + +#: systemv/lpstat.c:1337 systemv/lpstat.c:1341 +#, c-format +msgid "Output for printer %s/%s is sent to %s\n" +msgstr "" + +#: systemv/lpstat.c:1346 systemv/lpstat.c:1349 systemv/lpstat.c:1352 +#, c-format +msgid "device for %s: %s\n" +msgstr "" + +#: systemv/lpstat.c:1359 systemv/lpstat.c:1362 systemv/lpstat.c:1365 +#, c-format +msgid "device for %s/%s: %s\n" +msgstr "" + +#: systemv/lpstat.c:1481 systemv/lpstat.c:1693 +#, c-format +msgid "lpstat: get-jobs failed: %s\n" +msgstr "" + +#: systemv/lpstat.c:1681 +#, c-format +msgid "\tqueued for %s\n" +msgstr "" + +#: systemv/lpstat.c:2037 +#, c-format +msgid "printer %s is idle. enabled since %s\n" +msgstr "" + +#: systemv/lpstat.c:2042 +#, c-format +msgid "printer %s now printing %s-%d. enabled since %s\n" +msgstr "" + +#: systemv/lpstat.c:2048 +#, c-format +msgid "printer %s disabled since %s -\n" +msgstr "" + +#: systemv/lpstat.c:2056 systemv/lpstat.c:2169 +msgid "\treason unknown\n" +msgstr "" + +#: systemv/lpstat.c:2063 systemv/lpstat.c:2176 +msgid "" +"\tForm mounted:\n" +"\tContent types: any\n" +"\tPrinter types: unknown\n" +msgstr "" + +#: systemv/lpstat.c:2069 systemv/lpstat.c:2182 +#, c-format +msgid "\tDescription: %s\n" +msgstr "" + +#: systemv/lpstat.c:2074 systemv/lpstat.c:2187 +msgid "\tAlerts:" +msgstr "" + +#: systemv/lpstat.c:2083 systemv/lpstat.c:2196 +#, c-format +msgid "\tLocation: %s\n" +msgstr "" + +#: systemv/lpstat.c:2088 systemv/lpstat.c:2201 +msgid "\tConnection: remote\n" +msgstr "" + +#: systemv/lpstat.c:2092 systemv/lpstat.c:2205 +#, c-format +msgid "\tInterface: %s.ppd\n" +msgstr "" + +#: systemv/lpstat.c:2097 systemv/lpstat.c:2210 +msgid "\tConnection: direct\n" +msgstr "" + +#: systemv/lpstat.c:2101 systemv/lpstat.c:2214 +#, c-format +msgid "\tInterface: %s/interfaces/%s\n" +msgstr "" + +#: systemv/lpstat.c:2105 systemv/lpstat.c:2218 +#, c-format +msgid "\tInterface: %s/ppd/%s.ppd\n" +msgstr "" + +#: systemv/lpstat.c:2107 systemv/lpstat.c:2220 +msgid "\tOn fault: no alert\n" +msgstr "" + +#: systemv/lpstat.c:2108 systemv/lpstat.c:2221 +msgid "\tAfter fault: continue\n" +msgstr "" + +#: systemv/lpstat.c:2112 systemv/lpstat.c:2126 systemv/lpstat.c:2225 +#: systemv/lpstat.c:2239 +msgid "\tUsers allowed:\n" +msgstr "" + +#: systemv/lpstat.c:2119 systemv/lpstat.c:2232 +msgid "\tUsers denied:\n" +msgstr "" + +#: systemv/lpstat.c:2127 systemv/lpstat.c:2240 +msgid "\t\t(all)\n" +msgstr "" + +#: systemv/lpstat.c:2129 systemv/lpstat.c:2242 +msgid "\tForms allowed:\n" +msgstr "" + +#: systemv/lpstat.c:2130 systemv/lpstat.c:2133 systemv/lpstat.c:2243 +#: systemv/lpstat.c:2246 +msgid "\t\t(none)\n" +msgstr "" + +#: systemv/lpstat.c:2131 systemv/lpstat.c:2244 +msgid "\tBanner required\n" +msgstr "" + +#: systemv/lpstat.c:2132 systemv/lpstat.c:2245 +msgid "\tCharset sets:\n" +msgstr "" + +#: systemv/lpstat.c:2134 systemv/lpstat.c:2247 +msgid "\tDefault pitch:\n" +msgstr "" + +#: systemv/lpstat.c:2135 systemv/lpstat.c:2248 +msgid "\tDefault page size:\n" +msgstr "" + +#: systemv/lpstat.c:2136 systemv/lpstat.c:2249 +msgid "\tDefault port settings:\n" +msgstr "" + +#: systemv/lpstat.c:2146 +#, c-format +msgid "printer %s/%s is idle. enabled since %s\n" +msgstr "" + +#: systemv/lpstat.c:2153 +#, c-format +msgid "printer %s/%s now printing %s-%d. enabled since %s\n" +msgstr "" + +#: systemv/lpstat.c:2160 +#, c-format +msgid "printer %s/%s disabled since %s -\n" +msgstr "" + +#: systemv/lpstat.c:2279 +msgid "scheduler is running\n" +msgstr "" + +#: systemv/lpstat.c:2281 +msgid "scheduler is not running\n" +msgstr "" + +#: systemv/lpadmin.c:113 systemv/lpadmin.c:166 systemv/lpadmin.c:237 +#: systemv/lpadmin.c:298 systemv/lpadmin.c:317 systemv/lpadmin.c:383 +#: systemv/lpadmin.c:424 systemv/lpadmin.c:511 systemv/lpadmin.c:557 +#: systemv/lpadmin.c:603 systemv/lpadmin.c:665 systemv/lpadmin.c:711 +#: systemv/lpadmin.c:772 +#, c-format +msgid "lpadmin: Unable to connect to server: %s\n" +msgstr "" + +#: systemv/lpadmin.c:122 +msgid "" +"lpadmin: Unable to add a printer to the class:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:137 +msgid "lpadmin: Expected class name after '-c' option!\n" +msgstr "" + +#: systemv/lpadmin.c:148 systemv/lpadmin.c:460 +msgid "lpadmin: Class name can only contain printable characters!\n" +msgstr "" + +#: systemv/lpadmin.c:181 +msgid "lpadmin: Expected printer name after '-d' option!\n" +msgstr "" + +#: systemv/lpadmin.c:192 systemv/lpadmin.c:409 systemv/lpadmin.c:583 +msgid "lpadmin: Printer name can only contain printable characters!\n" +msgstr "" + +#: systemv/lpadmin.c:219 +msgid "lpadmin: Expected hostname after '-h' option!\n" +msgstr "" + +#: systemv/lpadmin.c:246 +msgid "" +"lpadmin: Unable to set the interface script:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:264 +msgid "lpadmin: Expected interface after '-i' option!\n" +msgstr "" + +#: systemv/lpadmin.c:326 +msgid "" +"lpadmin: Unable to set the interface script or PPD file:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:345 +msgid "lpadmin: Expected model after '-m' option!\n" +msgstr "" + +#: systemv/lpadmin.c:365 +msgid "lpadmin: Expected name=value after '-o' option!\n" +msgstr "" + +#: systemv/lpadmin.c:398 +msgid "lpadmin: Expected printer after '-p' option!\n" +msgstr "" + +#: systemv/lpadmin.c:433 +msgid "" +"lpadmin: Unable to remove a printer from the class:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:449 +msgid "lpadmin: Expected class after '-r' option!\n" +msgstr "" + +#: systemv/lpadmin.c:479 +msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n" +msgstr "" + +#: systemv/lpadmin.c:496 +#, c-format +msgid "lpadmin: Unknown allow/deny option \"%s\"!\n" +msgstr "" + +#: systemv/lpadmin.c:520 +msgid "" +"lpadmin: Unable to set the device URI:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:538 +msgid "lpadmin: Expected device URI after '-v' option!\n" +msgstr "" + +#: systemv/lpadmin.c:572 +msgid "lpadmin: Expected printer or class after '-x' option!\n" +msgstr "" + +#: systemv/lpadmin.c:612 +msgid "" +"lpadmin: Unable to set the printer description:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:631 +msgid "lpadmin: Expected description after '-D' option!\n" +msgstr "" + +#: systemv/lpadmin.c:647 +msgid "lpadmin: Expected file type(s) after '-I' option!\n" +msgstr "" + +#: systemv/lpadmin.c:653 +msgid "lpadmin: Warning - content type list ignored!\n" +msgstr "" + +#: systemv/lpadmin.c:674 +msgid "" +"lpadmin: Unable to set the printer location:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:692 +msgid "lpadmin: Expected location after '-L' option!\n" +msgstr "" + +#: systemv/lpadmin.c:720 +msgid "" +"lpadmin: Unable to set the PPD file:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:738 +msgid "lpadmin: Expected PPD after '-P' option!\n" +msgstr "" + +#: systemv/lpadmin.c:749 +#, c-format +msgid "lpadmin: Unknown option '%c'!\n" +msgstr "" + +#: systemv/lpadmin.c:754 +#, c-format +msgid "lpadmin: Unknown argument '%s'!\n" +msgstr "" + +#: systemv/lpadmin.c:781 +msgid "" +"lpadmin: Unable to set the printer options:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:793 +msgid "" +"Usage:\n" +"\n" +" lpadmin [-h server] -d destination\n" +" lpadmin [-h server] -x destination\n" +" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n" +" [-r remove-class] [-v device] [-D description]\n" +" [-P ppd-file] [-o name=value]\n" +" [-u allow:user,user] [-u deny:user,user]\n" +"\n" +msgstr "" + +#: systemv/lpadmin.c:1554 +#, c-format +msgid "lpadmin: Unable to create temporary file: %s\n" +msgstr "" + +#: systemv/lpadmin.c:1562 +#, c-format +msgid "lpadmin: Unable to open file \"%s\": %s\n" +msgstr "" + +#: systemv/lpadmin.c:1631 systemv/lpadmin.c:1862 systemv/lpadmin.c:1870 +#, c-format +msgid "lpadmin: add-printer (set model) failed: %s\n" +msgstr "" + +#: systemv/lpadmin.c:1701 systemv/lpadmin.c:1708 +#, c-format +msgid "lpadmin: add-printer (set description) failed: %s\n" +msgstr "" + +#: systemv/lpadmin.c:1784 systemv/lpadmin.c:1792 +#, c-format +msgid "lpadmin: add-printer (set location) failed: %s\n" +msgstr "" + +#: systemv/lpadmin.c:2021 +#, c-format +msgid "lpadmin: Unable to create temporary file - %s\n" +msgstr "" + +#: systemv/lpadmin.c:2031 +#, c-format +msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n" +msgstr "" + +#: systemv/lpadmin.c:2117 systemv/lpadmin.c:2125 +#, c-format +msgid "lpadmin: %s failed: %s\n" +msgstr "" + +#: systemv/lp.c:153 +msgid "lp: Expected destination after -d option!\n" +msgstr "" + +#: systemv/lp.c:184 +msgid "lp: Expected form after -f option!\n" +msgstr "" + +#: systemv/lp.c:202 +msgid "lp: Expected hostname after -h option!\n" +msgstr "" + +#: systemv/lp.c:220 +msgid "lp: Expected job ID after -i option!\n" +msgstr "" + +#: systemv/lp.c:230 +msgid "lp: Error - cannot print files and alter jobs simultaneously!\n" +msgstr "" + +#: systemv/lp.c:242 +msgid "lp: Error - bad job ID!\n" +msgstr "" + +#: systemv/lp.c:264 +msgid "lp: Expected copies after -n option!\n" +msgstr "" + +#: systemv/lp.c:285 +msgid "lp: Expected option string after -o option!\n" +msgstr "" + +#: systemv/lp.c:304 +#, c-format +msgid "lp: Expected priority after -%c option!\n" +msgstr "" + +#: systemv/lp.c:326 +msgid "lp: Priority must be between 1 and 100.\n" +msgstr "" + +#: systemv/lp.c:348 +msgid "lp: Expected title after -t option!\n" +msgstr "" + +#: systemv/lp.c:364 +msgid "lp: Expected mode list after -y option!\n" +msgstr "" + +#: systemv/lp.c:370 +msgid "lp: Warning - mode option ignored!\n" +msgstr "" + +#: systemv/lp.c:383 +msgid "lp: Expected hold name after -H option!\n" +msgstr "" + +#: systemv/lp.c:405 +msgid "lp: Need job ID (-i) before \"-H restart\"!\n" +msgstr "" + +#: systemv/lp.c:427 +msgid "lp: Expected page list after -P option!\n" +msgstr "" + +#: systemv/lp.c:446 +msgid "lp: Expected character set after -S option!\n" +msgstr "" + +#: systemv/lp.c:452 +msgid "lp: Warning - character set option ignored!\n" +msgstr "" + +#: systemv/lp.c:463 +msgid "lp: Expected content type after -T option!\n" +msgstr "" + +#: systemv/lp.c:469 +msgid "lp: Warning - content type option ignored!\n" +msgstr "" + +#: systemv/lp.c:473 +#, c-format +msgid "lp: Unknown option '%c'!\n" +msgstr "" + +#: systemv/lp.c:482 +msgid "lp: Error - cannot print from stdin if files or a job ID are provided!\n" +msgstr "" + +#: systemv/lp.c:497 +#, c-format +msgid "lp: Unable to access \"%s\" - %s\n" +msgstr "" + +#: systemv/lp.c:514 +#, c-format +msgid "lp: Too many files - \"%s\"\n" +msgstr "" + +#: systemv/lp.c:569 +msgid "lp: error - no default destination available.\n" +msgstr "" + +#: systemv/lp.c:572 +msgid "lp: error - scheduler not responding!\n" +msgstr "" + +#: systemv/lp.c:611 +#, c-format +msgid "lp: unable to create temporary file \"%s\" - %s\n" +msgstr "" + +#: systemv/lp.c:620 +#, c-format +msgid "lp: error - unable to write to temporary file \"%s\" - %s\n" +msgstr "" + +#: systemv/lp.c:634 +msgid "lp: stdin is empty, so no job has been sent.\n" +msgstr "" + +#: systemv/lp.c:650 +#, c-format +msgid "lp: unable to print file: %s\n" +msgstr "" + +#: systemv/lp.c:656 +#, c-format +msgid "request id is %s-%d (%d file(s))\n" +msgstr "" + +#: systemv/lp.c:703 systemv/lp.c:713 +#, c-format +msgid "lp: restart-job failed: %s\n" +msgstr "" + +#: systemv/lp.c:769 systemv/lp.c:779 +#, c-format +msgid "lp: set-job-attributes failed: %s\n" +msgstr "" + +#: systemv/lpinfo.c:98 systemv/lpinfo.c:117 +#, c-format +msgid "lpinfo: Unable to connect to server: %s\n" +msgstr "" + +#: systemv/lpinfo.c:152 +#, c-format +msgid "lpinfo: Unknown option '%c'!\n" +msgstr "" + +#: systemv/lpinfo.c:158 +#, c-format +msgid "lpinfo: Unknown argument '%s'!\n" +msgstr "" + +#: systemv/lpinfo.c:225 systemv/lpinfo.c:310 +#, c-format +msgid "lpinfo: cups-get-devices failed: %s\n" +msgstr "" + +#: systemv/lpinfo.c:293 +#, c-format +msgid "" +"Device: uri = %s\n" +" class = %s\n" +" info = %s\n" +" make-and-model = %s\n" +msgstr "" + +#: systemv/lpinfo.c:376 systemv/lpinfo.c:454 +#, c-format +msgid "lpinfo: cups-get-ppds failed: %s\n" +msgstr "" + +#: systemv/lpinfo.c:438 +#, c-format +msgid "" +"Model: name = %s\n" +" natural_language = %s\n" +" make-and-model = %s\n" +msgstr "" + +#: systemv/lpmove.c:114 +#, c-format +msgid "lpmove: Unknown option '%c'!\n" +msgstr "" + +#: systemv/lpmove.c:133 +#, c-format +msgid "lpmove: Unknown argument '%s'!\n" +msgstr "" + +#: systemv/lpmove.c:140 +msgid "Usage: lpmove job dest\n" +msgstr "" + +#: systemv/lpmove.c:151 +#, c-format +msgid "lpmove: Unable to connect to server: %s\n" +msgstr "" + +#: systemv/lpmove.c:225 systemv/lpmove.c:234 +#, c-format +msgid "lpmove: move-job failed: %s\n" +msgstr "" + +#: systemv/lpoptions.c:109 +msgid "lpoptions: Unknown printer or class!\n" +msgstr "" + +#: systemv/lpoptions.c:159 +msgid "lpoptions: No printers!?!\n" +msgstr "" + +#: systemv/lpoptions.c:207 +#, c-format +msgid "lpoptions: Unable to add printer or instance: %s\n" +msgstr "" + +#: systemv/lpoptions.c:411 +#, c-format +msgid "lpoptions: Destination %s has no PPD file!\n" +msgstr "" + +#: systemv/lpoptions.c:420 +#, c-format +msgid "lpoptions: Unable to open PPD file for %s!\n" +msgstr "" + +#: systemv/lpoptions.c:444 +msgid "" +"Usage: lpoptions [-h server] [-E] -d printer\n" +" lpoptions [-h server] [-E] [-p printer] -l\n" +" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n" +" lpoptions [-h server] [-E] -x printer\n" +msgstr "" + +#: systemv/lppasswd.c:192 +msgid "lppasswd: Only root can add or delete passwords!\n" +msgstr "" + +#: systemv/lppasswd.c:212 +msgid "Enter old password:" +msgstr "" + +#: systemv/lppasswd.c:218 systemv/lppasswd.c:236 +#, c-format +msgid "lppasswd: Unable to copy password string: %s\n" +msgstr "" + +#: systemv/lppasswd.c:230 +msgid "Enter password:" +msgstr "" + +#: systemv/lppasswd.c:241 +msgid "Enter password again:" +msgstr "" + +#: systemv/lppasswd.c:247 +msgid "lppasswd: Sorry, passwords don't match!\n" +msgstr "" + +#: systemv/lppasswd.c:271 +msgid "" +"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" +msgstr "" + +#: systemv/lppasswd.c:321 +msgid "lppasswd: Password file busy!\n" +msgstr "" + +#: systemv/lppasswd.c:324 systemv/lppasswd.c:333 systemv/lppasswd.c:351 +#, c-format +msgid "lppasswd: Unable to open password file: %s\n" +msgstr "" + +#: systemv/lppasswd.c:386 systemv/lppasswd.c:399 systemv/lppasswd.c:431 +#, c-format +msgid "lppasswd: Unable to write to password file: %s\n" +msgstr "" + +#: systemv/lppasswd.c:411 +#, c-format +msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n" +msgstr "" + +#: systemv/lppasswd.c:421 +msgid "lppasswd: Sorry, password doesn't match!\n" +msgstr "" + +#: systemv/lppasswd.c:454 +msgid "lppasswd: Password file not updated!\n" +msgstr "" + +#: systemv/lppasswd.c:469 +#, c-format +msgid "lppasswd: failed to backup old password file: %s\n" +msgstr "" + +#: systemv/lppasswd.c:482 +#, c-format +msgid "lppasswd: failed to rename password file: %s\n" +msgstr "" + +#: systemv/lppasswd.c:501 +msgid "Usage: lppasswd [-g groupname]\n" +msgstr "" + +#: systemv/lppasswd.c:506 +msgid "" +"Usage: lppasswd [-g groupname] [username]\n" +" lppasswd [-g groupname] -a [username]\n" +" lppasswd [-g groupname] -x [username]\n" +msgstr "" + + +# +# End of "$Id$". +# diff --git a/locale/cups_fr.po b/locale/cups_fr.po new file mode 100644 index 000000000..2f2bc28ae --- /dev/null +++ b/locale/cups_fr.po @@ -0,0 +1,2148 @@ +msgid "" +msgstr "" +"Project-Id-Version: CUPS 1.2\n" +"Report-Msgid-Bugs-To: http://www.cups.org/str.php\n" +"POT-Creation-Date: 2006-01-08 18:06-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: cgi-bin/admin.c:1276 +msgid "Options Installed" +msgstr "Options Installées" + +#: cgi-bin/classes.c:103 +msgid "Class" +msgstr "Classe" + +#: cgi-bin/printers.c:104 +msgid "Printer" +msgstr "Imprimeur" + +#: cups/ppd.c:654 cups/ppd.c:1045 +msgid "Extra" +msgstr "Supplémentaire" + +#: cups/ppd.c:656 cups/ppd.c:881 cups/ppd.c:1047 +msgid "General" +msgstr "Généralités" + +#: cups/ppd.c:704 cups/ppd.c:1105 +msgid "Media Size" +msgstr "Taille De Médias" + +#: cups/ppd.c:706 cups/ppd.c:1107 +msgid "Media Type" +msgstr "Type De Supports" + +#: cups/ppd.c:708 cups/ppd.c:1109 +msgid "Media Source" +msgstr "Source De Médias" + +#: cups/ppd.c:710 cups/ppd.c:1111 +msgid "Output Mode" +msgstr "Mode De Rendement" + +#: cups/ppd.c:712 cups/ppd.c:1113 +msgid "Resolution" +msgstr "Résolution" + +#: cups/ppd.c:907 +msgid "Variable" +msgstr "Variable" + +#: cups/ppd.c:1535 +msgid "Yes" +msgstr "Oui" + +#: cups/ppd.c:1537 +msgid "No" +msgstr "Non" + +#: cups/ppd.c:1824 +msgid "Auto" +msgstr "Automobile" + +#: scheduler/client.c:2247 +msgid "" +"Enter your username and password or the root username and password to access " +"this page." +msgstr "" +"Entrez votre username et mot de passe ou le username de racine et le mot de " +"passe pour accéder à cette page." + +#: scheduler/client.c:2252 +msgid "You must use a https: URL to access this page." +msgstr "Vous devez employer des https: URL pour accéder à cette page." + +#: scheduler/ipp.c:236 +#, c-format +msgid "Bad request version number %d.%d!" +msgstr "Mauvais nombre de version de demande %d.%d!" + +#: scheduler/ipp.c:246 +msgid "No attributes in request!" +msgstr "Aucuns attributs dans la demande!" + +#: scheduler/ipp.c:269 +#, c-format +msgid "Attribute groups are out of order (%x < %x)!" +msgstr "Les groupes d'attribut sont en panne (%x < %x)!" + +#: scheduler/ipp.c:379 +msgid "Missing required attributes!" +msgstr "Attributs requis manquants!" + +#: scheduler/ipp.c:575 +#, c-format +msgid "%s not supported!" +msgstr "%s non soutenu!" + +#: scheduler/ipp.c:684 scheduler/ipp.c:1055 scheduler/ipp.c:2271 +#: scheduler/ipp.c:2383 scheduler/ipp.c:3707 scheduler/ipp.c:4417 +#: scheduler/ipp.c:4649 scheduler/ipp.c:5002 scheduler/ipp.c:5445 +#: scheduler/ipp.c:5890 scheduler/ipp.c:6245 scheduler/ipp.c:6609 +#: scheduler/ipp.c:7308 scheduler/ipp.c:8179 scheduler/ipp.c:8585 +#: scheduler/ipp.c:8663 scheduler/ipp.c:8836 +msgid "The printer or class was not found." +msgstr "L'imprimeur ou la classe n'a pas été trouvé." + +#: scheduler/ipp.c:762 +msgid "" +"The printer-uri must be of the form \"ipp://HOSTNAME/classes/CLASSNAME\"." +msgstr "" +"L'printer-uri doit être de la forme \"ipp://HOSTNAME/classes/CLASSNAME\"." + +#: scheduler/ipp.c:778 scheduler/ipp.c:1454 +#, c-format +msgid "The printer-uri \"%s\" contains invalid characters." +msgstr "L'printer-uri \"%s\" contient les caractères inadmissibles." + +#: scheduler/ipp.c:811 +#, c-format +msgid "A printer named \"%s\" already exists!" +msgstr "Un imprimeur appelé \"%s\" existe déjà!" + +#: scheduler/ipp.c:904 +#, c-format +msgid "Attempt to set %s printer-state to bad value %d!" +msgstr "Essayez de placer l'imprimeur-état de %s à la mauvaise valeur %d!" + +#: scheduler/ipp.c:1000 +#, c-format +msgid "add_class: Unknown printer-op-policy \"%s\"." +msgstr "add_class: printer-op-policy inconnue \"%s\"." + +#: scheduler/ipp.c:1013 +#, c-format +msgid "add_class: Unknown printer-error-policy \"%s\"." +msgstr "add_class: printer-error-policy inconnue \"%s\"." + +#: scheduler/ipp.c:1144 +msgid "Unable to allocate memory for file types!" +msgstr "Incapable d'assigner la mémoire pour des types de dossier!" + +#: scheduler/ipp.c:1290 scheduler/ipp.c:4501 +#, c-format +msgid "Character set \"%s\" not supported!" +msgstr "Jeu de caractères \"%s\" non soutenu!" + +#: scheduler/ipp.c:1299 scheduler/ipp.c:4510 +#, c-format +msgid "Language \"%s\" not supported!" +msgstr "Langue \"%s\" non soutenue!" + +#: scheduler/ipp.c:1309 scheduler/ipp.c:4520 +#, c-format +msgid "The notify-user-data value is too large (%d > 63 octets)!" +msgstr "La valeur de notify-user-data est trop grande (%d > 63 octets)!" + +#: scheduler/ipp.c:1326 +msgid "" +"The notify-lease-duration attribute cannot be used with job subscriptions." +msgstr "" +"L'attribut de notify-lease-duration ne peut pas être employé avec des " +"abonnements du travail." + +#: scheduler/ipp.c:1438 +msgid "" +"The printer-uri must be of the form \"ipp://HOSTNAME/printers/PRINTERNAME\"." +msgstr "" +"L'printer-uri doit être de la forme \"ipp://HOSTNAME/printers/PRINTERNAME\"." + +#: scheduler/ipp.c:1487 +#, c-format +msgid "A class named \"%s\" already exists!" +msgstr "Une classe appelée \"%s\" existe déjà!" + +#: scheduler/ipp.c:1575 +#, c-format +msgid "" +"File device URIs have been disabled! To enable, see the FileDevice directive " +"in \"%s/cupsd.conf\"." +msgstr "" +"Le dispositif URIs de dossier ont été neutralisés! Pour permettre, voyez la " +"directive de FileDevice dans \"%s/cupsd.conf\"." + +#: scheduler/ipp.c:1595 +#, c-format +msgid "Bad device-uri \"%s\"!" +msgstr "Mauvais device-uri \"%s\"!" + +#: scheduler/ipp.c:1626 +#, c-format +msgid "Bad port-monitor \"%s\"!" +msgstr "Mauvais port-monitor \"%s\"!" + +#: scheduler/ipp.c:1669 +#, c-format +msgid "Bad printer-state value %d!" +msgstr "Mauvaise valeur %d de printer-state!" + +#: scheduler/ipp.c:1762 +#, c-format +msgid "Unknown printer-op-policy \"%s\"." +msgstr "printer-op-policy inconnue \"%s\"." + +#: scheduler/ipp.c:1775 +#, c-format +msgid "Unknown printer-error-policy \"%s\"." +msgstr "printer-error-policy inconnue \"%s\"." + +#: scheduler/ipp.c:1837 +#, c-format +msgid "Unable to copy interface script - %s!" +msgstr "Incapable de copier le manuscrit d'interface - %s!" + +#: scheduler/ipp.c:1862 +#, c-format +msgid "Unable to copy PPD file - %s!" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: scheduler/ipp.c:1915 +msgid "Unable to copy PPD file!" +msgstr "Incapable de copier le dossier de PPD!" + +#: scheduler/ipp.c:2076 scheduler/ipp.c:2364 scheduler/ipp.c:5188 +#: scheduler/ipp.c:6008 scheduler/ipp.c:6147 scheduler/ipp.c:7394 +#: scheduler/ipp.c:7538 scheduler/ipp.c:7776 scheduler/ipp.c:8261 +msgid "Got a printer-uri attribute but no job-id!" +msgstr "N'a obtenu un attribut de printer-uri mais aucune job-id!" + +#: scheduler/ipp.c:2097 scheduler/ipp.c:2433 scheduler/ipp.c:5210 +#: scheduler/ipp.c:6029 scheduler/ipp.c:6169 scheduler/ipp.c:7416 +#: scheduler/ipp.c:7560 scheduler/ipp.c:7797 scheduler/ipp.c:8282 +#, c-format +msgid "Bad job-uri attribute \"%s\"!" +msgstr "Mauvais attribut \"%s\" de job-uri!" + +#: scheduler/ipp.c:2116 scheduler/ipp.c:2451 scheduler/ipp.c:5228 +#: scheduler/ipp.c:6047 scheduler/ipp.c:6188 scheduler/ipp.c:7434 +#: scheduler/ipp.c:7578 scheduler/ipp.c:7815 scheduler/ipp.c:8300 +#, c-format +msgid "Job #%d doesn't exist!" +msgstr "Le travail # %d n'existe pas!" + +#: scheduler/ipp.c:2131 +#, c-format +msgid "Job #%d is not held for authentication!" +msgstr "Le travail # %d n'est pas tenu pour l'authentification!" + +#: scheduler/ipp.c:2153 +#, c-format +msgid "You are not authorized to authenticate job #%d owned by \"%s\"!" +msgstr "" +"Vous n'êtes pas autorisés à authentifier le travail # %d possédés par \"%s\"!" + +#: scheduler/ipp.c:2221 +msgid "The printer-uri attribute is required!" +msgstr "L'attribut de printer-uri est exigé!" + +#: scheduler/ipp.c:2238 +msgid "Missing requesting-user-name attribute!" +msgstr "Attribut absent de requesting-user-name!" + +#: scheduler/ipp.c:2277 +#, c-format +msgid "The printer-uri \"%s\" is not valid." +msgstr "L'printer-uri \"%s\" est inadmissible." + +#: scheduler/ipp.c:2410 +#, c-format +msgid "No active jobs on %s!" +msgstr "Aucuns JOBS actifs sur %s!" + +#: scheduler/ipp.c:2462 +#, c-format +msgid "You are not authorized to delete job #%d owned by \"%s\"!" +msgstr "" +"Vous n'êtes pas autorisés à supprimer le travail # %d possédés par \"%s\"!" + +#: scheduler/ipp.c:2476 +#, c-format +msgid "Job #%d is already %s - can't cancel." +msgstr "Le travail # %d est déjà %s - ne peut pas décommander." + +#: scheduler/ipp.c:3720 +msgid "The printer or class is not shared!" +msgstr "L'imprimeur ou la classe n'est pas partagé!" + +#: scheduler/ipp.c:3746 scheduler/ipp.c:6647 +#, c-format +msgid "Destination \"%s\" is not accepting jobs." +msgstr "La destination \"%s\" n'accepte pas les travaux." + +#: scheduler/ipp.c:3759 scheduler/ipp.c:6443 +#, c-format +msgid "Bad copies value %d." +msgstr "Mauvaise valeur %d de copies." + +#: scheduler/ipp.c:3775 scheduler/ipp.c:6459 +#, c-format +msgid "Bad page-ranges values %d-%d." +msgstr "Mauvaises valeurs %d-%d de page-ranges." + +#: scheduler/ipp.c:3795 +msgid "Too many active jobs." +msgstr "Trop de JOBS actifs." + +#: scheduler/ipp.c:3801 scheduler/ipp.c:6668 +msgid "Quota limit reached." +msgstr "La limite de quote-part a atteint." + +#: scheduler/ipp.c:3824 scheduler/ipp.c:6691 +#, c-format +msgid "Unable to add job for destination \"%s\"!" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: scheduler/ipp.c:4469 +msgid "No subscription attributes in request!" +msgstr "Aucuns attributs d'abonnement dans la demande!" + +#: scheduler/ipp.c:4559 +msgid "notify-events not specified!" +msgstr "notify-events non indiqués!" + +#: scheduler/ipp.c:4577 +#, c-format +msgid "Job %d not found!" +msgstr "Le travail %d non trouvé!" + +#: scheduler/ipp.c:4827 +msgid "No default printer" +msgstr "Aucun imprimeur de défaut" + +#: scheduler/ipp.c:4930 +msgid "cups-deviced failed to execute." +msgstr "les cups-deviced ne se sont pas exécutées." + +#: scheduler/ipp.c:5393 +msgid "cups-driverd failed to execute." +msgstr "les cups-driverd ne se sont pas exécutées." + +#: scheduler/ipp.c:5571 +msgid "No destinations added." +msgstr "Aucunes destinations supplémentaires." + +#: scheduler/ipp.c:5794 +#, c-format +msgid "notify-subscription-id %d no good!" +msgstr "notify-subscription-id %d aucun bon!" + +#: scheduler/ipp.c:5878 +#, c-format +msgid "Job #%s does not exist!" +msgstr "Le travail # %s n'existe pas!" + +#: scheduler/ipp.c:5900 scheduler/ipp.c:2116 scheduler/ipp.c:2451 +#: scheduler/ipp.c:5228 scheduler/ipp.c:6047 scheduler/ipp.c:6188 +#: scheduler/ipp.c:7434 scheduler/ipp.c:7578 scheduler/ipp.c:7815 +#: scheduler/ipp.c:8300 +#, c-format +msgid "Job #%d does not exist!" +msgstr "Le travail # %d n'existe pas!" + +#: scheduler/ipp.c:5969 +msgid "No subscriptions found." +msgstr "Abonnement n'a pas trouvé." + +#: scheduler/ipp.c:6058 +#, c-format +msgid "Not authorized to hold job #%d owned by \"%s\"!" +msgstr "Non autorisé à juger le travail # %d possédés par \"%s\"!" + +#: scheduler/ipp.c:6203 scheduler/ipp.c:8315 +#, c-format +msgid "Job #%d is finished and cannot be altered!" +msgstr "Le travail # %d est fini et ne peut pas être changé!" + +#: scheduler/ipp.c:6215 +#, c-format +msgid "You are not authorized to move job #%d owned by \"%s\"!" +msgstr "" +"Vous n'êtes pas autorisés à déplacer le travail # %d possédés par \"%s\"!" + +#: scheduler/ipp.c:6228 +msgid "job-printer-uri attribute missing!" +msgstr "disparus d'attribut de job-printer-uri!" + +#: scheduler/ipp.c:6485 scheduler/ipp.c:7847 +#, c-format +msgid "Unsupported compression \"%s\"!" +msgstr "Compression non soutenue \"%s\"!" + +#: scheduler/ipp.c:6504 scheduler/ipp.c:7866 +msgid "No file!?!" +msgstr "Aucun dossier!?!" + +#: scheduler/ipp.c:6522 +#, c-format +msgid "Could not scan type \"%s\"!" +msgstr "N'a pas pu balayer le type \"%s\"!" + +#: scheduler/ipp.c:6574 scheduler/ipp.c:7936 +#, c-format +msgid "Unsupported format '%s/%s'!" +msgstr "Format non soutenu '%s/%s '!" + +#: scheduler/ipp.c:6621 +msgid "Printer not shared!" +msgstr "Imprimeur non partagé!" + +#: scheduler/ipp.c:6661 +#, c-format +msgid "Too many jobs - %d jobs, max jobs is %d." +msgstr "Trop de travaux - les travaux de %d, les travaux maximum est %d." + +#: scheduler/ipp.c:7448 +#, c-format +msgid "Job #%d is not held!" +msgstr "Le travail # %d n'est pas tenu!" + +#: scheduler/ipp.c:7459 +#, c-format +msgid "You are not authorized to release job id %d owned by \"%s\"!" +msgstr "" +"Vous n'êtes pas autorisés à libérer l'identification de travail %d possédée " +"par \"%s\"!" + +#: scheduler/ipp.c:7592 +#, c-format +msgid "Job #%d is not complete!" +msgstr "Le travail # %d n'est pas complet!" + +#: scheduler/ipp.c:7608 +#, c-format +msgid "Job #%d cannot be restarted - no files!" +msgstr "Le travail # %d ne peuvent pas être remis en marche - aucuns dossiers!" + +#: scheduler/ipp.c:7619 +#, c-format +msgid "You are not authorized to restart job id %d owned by \"%s\"!" +msgstr "" +"Vous n'êtes pas autorisés à remettre en marche l'identification de travail %" +"d possédée par \"%s\"!" + +#: scheduler/ipp.c:7826 +#, c-format +msgid "You are not authorized to send document for job #%d owned by \"%s\"!" +msgstr "" +"Vous n'êtes pas autorisés à envoyer le document pour le travail # %d " +"possédés par \"%s\"!" + +#: scheduler/ipp.c:7883 scheduler/ipp.c:8803 +#, c-format +msgid "Bad document-format \"%s\"!" +msgstr "Mauvais document-format \"%s\"!" + +#: scheduler/ipp.c:8326 +#, c-format +msgid "You are not authorized to alter job id %d owned by \"%s\"!" +msgstr "" +"Vous n'êtes pas autorisés à changer l'identification de travail %d possédée " +"par \"%s\"!" + +#: scheduler/ipp.c:8371 +#, c-format +msgid "%s cannot be changed." +msgstr "%s ne peut pas être changé." + +#: scheduler/ipp.c:8387 +msgid "Bad job-priority value!" +msgstr "Mauvaise valeur de job-priority!" + +#: scheduler/ipp.c:8395 +msgid "Job is completed and cannot be changed." +msgstr "Le travail est accompli et ne peut pas être changé." + +#: scheduler/ipp.c:8409 +msgid "Bad job-state value!" +msgstr "Mauvaise valeur de job-state!" + +#: scheduler/ipp.c:8423 scheduler/ipp.c:8435 scheduler/ipp.c:8446 +msgid "Job state cannot be changed." +msgstr "L'état du travail ne peut pas être changé." + +#: scheduler/ipp.c:8787 +#, c-format +msgid "Unsupported compression attribute %s!" +msgstr "Attribut non soutenu %s de compression!" + +#: scheduler/ipp.c:8815 +#, c-format +msgid "Unsupported format \"%s\"!" +msgstr "Format non soutenu \"%s\"!" + +#: berkeley/lpc.c:201 +#, c-format +msgid "%s is not implemented by the CUPS version of lpc.\n" +msgstr "" + +#: berkeley/lpc.c:216 +msgid "" +"Commands may be abbreviated. Commands are:\n" +"\n" +"exit help quit status ?\n" +msgstr "" + +#: berkeley/lpc.c:222 +msgid "help\t\tget help on commands\n" +msgstr "" + +#: berkeley/lpc.c:225 +msgid "status\t\tshow status of daemon and queue\n" +msgstr "" + +#: berkeley/lpc.c:228 +msgid "?Invalid help command unknown\n" +msgstr "" + +#: berkeley/lpc.c:478 berkeley/lpc.c:490 +#, c-format +msgid "\tprinter is on device '%s' speed -1\n" +msgstr "" + +#: berkeley/lpc.c:496 +msgid "\tqueuing is enabled\n" +msgstr "" + +#: berkeley/lpc.c:498 +msgid "\tqueuing is disabled\n" +msgstr "" + +#: berkeley/lpc.c:501 +msgid "\tprinting is enabled\n" +msgstr "" + +#: berkeley/lpc.c:503 +msgid "\tprinting is disabled\n" +msgstr "" + +#: berkeley/lpc.c:506 +msgid "\tno entries\n" +msgstr "" + +#: berkeley/lpc.c:508 +#, c-format +msgid "\t%d entries\n" +msgstr "" + +#: berkeley/lpc.c:510 +msgid "\tdaemon present\n" +msgstr "" + +#: berkeley/lpq.c:94 +msgid "lpq: Unable to contact server!\n" +msgstr "" + +#: berkeley/lpq.c:125 berkeley/lpr.c:114 berkeley/lprm.c:107 +#: systemv/accept.c:108 systemv/cancel.c:95 systemv/lpstat.c:115 +#: systemv/lpadmin.c:284 systemv/lp.c:135 systemv/lpinfo.c:80 +#: systemv/lpmove.c:84 +#, c-format +msgid "%s: Sorry, no encryption support compiled in!\n" +msgstr "" + +#: berkeley/lpq.c:155 +#, c-format +msgid "lpq: Unknown destination \"%s/%s\"!\n" +msgstr "" + +#: berkeley/lpq.c:159 +#, fuzzy, c-format +msgid "lpq: Unknown destination \"%s\"!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: berkeley/lpq.c:211 systemv/lp.c:564 +#, c-format +msgid "" +"lp: error - %s environment variable names non-existent destination \"%s\"!\n" +msgstr "" + +#: berkeley/lpq.c:216 +msgid "lpq: error - no default destination available.\n" +msgstr "" + +#: berkeley/lpq.c:363 berkeley/lpq.c:523 +#, c-format +msgid "lpq: get-jobs failed: %s\n" +msgstr "" + +#: berkeley/lpq.c:457 +msgid "" +"Rank Owner Pri Job Files Total Size\n" +msgstr "" + +#: berkeley/lpq.c:461 +msgid "Rank Owner Job File(s) Total Size\n" +msgstr "" + +#: berkeley/lpq.c:498 +#, c-format +msgid "%s: %-33.33s [job %d localhost]\n" +msgstr "" + +#: berkeley/lpq.c:500 +#, c-format +msgid " %-39.39s %.0f bytes\n" +msgstr "" + +#: berkeley/lpq.c:506 +#, c-format +msgid "%-6s %-10.10s %-4d %-10d %-27.27s %.0f bytes\n" +msgstr "" + +#: berkeley/lpq.c:511 +#, c-format +msgid "%-7s %-7.7s %-7d %-31.31s %.0f bytes\n" +msgstr "" + +#: berkeley/lpq.c:529 +msgid "no entries\n" +msgstr "" + +#: berkeley/lpq.c:591 berkeley/lpq.c:620 +#, c-format +msgid "lpq: get-printer-attributes failed: %s\n" +msgstr "" + +#: berkeley/lpq.c:605 +#, c-format +msgid "%s is ready\n" +msgstr "" + +#: berkeley/lpq.c:608 +#, c-format +msgid "%s is ready and printing\n" +msgstr "" + +#: berkeley/lpq.c:612 +#, fuzzy, c-format +msgid "%s is not ready\n" +msgstr "Le travail # %d n'est pas tenu!" + +#: berkeley/lpq.c:633 +msgid "Usage: lpq [-P dest] [-l] [+interval]\n" +msgstr "" + +#: berkeley/lpr.c:132 +#, c-format +msgid "lpr: error - expected value after -%c option!\n" +msgstr "" + +#: berkeley/lpr.c:146 +#, c-format +msgid "" +"lpr: warning - '%c' format modifier not supported - output may not be " +"correct!\n" +msgstr "" + +#: berkeley/lpr.c:159 +msgid "lpr: error - expected option=value after -o option!\n" +msgstr "" + +#: berkeley/lpr.c:185 +msgid "lpr: warning - email notification is not currently supported!\n" +msgstr "" + +#: berkeley/lpr.c:207 +msgid "lpr: error - expected destination after -P option!\n" +msgstr "" + +#: berkeley/lpr.c:240 +msgid "lpr: error - expected copy count after -# option!\n" +msgstr "" + +#: berkeley/lpr.c:263 +#, c-format +msgid "lpr: error - expected name after -%c option!\n" +msgstr "" + +#: berkeley/lpr.c:281 +msgid "lpr: error - expected username after -U option!\n" +msgstr "" + +#: berkeley/lpr.c:292 +#, c-format +msgid "lpr: error - unknown option '%c'!\n" +msgstr "" + +#: berkeley/lpr.c:305 +#, c-format +msgid "lpr: error - unable to access \"%s\" - %s\n" +msgstr "" + +#: berkeley/lpr.c:323 +#, c-format +msgid "lpr: error - too many files - \"%s\"\n" +msgstr "" + +#: berkeley/lpr.c:364 +#, c-format +msgid "" +"lpr: error - %s environment variable names non-existent destination \"%s\"!\n" +msgstr "" + +#: berkeley/lpr.c:369 +msgid "lpr: error - no default destination available.\n" +msgstr "" + +#: berkeley/lpr.c:372 +msgid "lpr: error - scheduler not responding!\n" +msgstr "" + +#: berkeley/lpr.c:421 +#, c-format +msgid "lpr: error - unable to create temporary file \"%s\" - %s\n" +msgstr "" + +#: berkeley/lpr.c:431 +#, c-format +msgid "lpr: error - unable to write to temporary file \"%s\" - %s\n" +msgstr "" + +#: berkeley/lpr.c:445 +msgid "lpr: error - stdin is empty, so no job has been sent.\n" +msgstr "" + +#: berkeley/lpr.c:461 +#, c-format +msgid "lpr: error - unable to print file: %s\n" +msgstr "" + +#: berkeley/lprm.c:87 +msgid "lprm: Unable to contact server!\n" +msgstr "" + +#: berkeley/lprm.c:127 +#, c-format +msgid "lprm: Unknown destination \"%s\"!\n" +msgstr "" + +#: berkeley/lprm.c:136 +#, c-format +msgid "lprm: Unknown option '%c'!\n" +msgstr "" + +#: berkeley/lprm.c:223 +#, fuzzy +msgid "lprm: Job or printer not found!\n" +msgstr "Le travail %d non trouvé!" + +#: berkeley/lprm.c:227 +#, fuzzy +msgid "lprm: Not authorized to lprm job(s)!\n" +msgstr "Non autorisé à juger le travail # %d possédés par \"%s\"!" + +#: berkeley/lprm.c:231 +#, c-format +msgid "lprm: You don't own job ID %d!\n" +msgstr "" + +#: berkeley/lprm.c:236 +msgid "lprm: Unable to lprm job(s)!\n" +msgstr "" + +#: berkeley/lprm.c:253 berkeley/lprm.c:269 +msgid "lprm: Unable to cancel job(s)!\n" +msgstr "" + +#: systemv/accept.c:84 +#, c-format +msgid "%s: Don't know what to do!\n" +msgstr "" + +#: systemv/accept.c:129 +#, c-format +msgid "%s: Expected server name after -h!\n" +msgstr "" + +#: systemv/accept.c:147 +#, c-format +msgid "%s: Expected reason text after -r!\n" +msgstr "" + +#: systemv/accept.c:157 +#, c-format +msgid "%s: Unknown option '%c'!\n" +msgstr "" + +#: systemv/accept.c:173 +#, c-format +msgid "%s: Unable to connect to server: %s\n" +msgstr "" + +#: systemv/accept.c:217 systemv/accept.c:227 systemv/accept.c:268 +#: systemv/accept.c:278 +#, c-format +msgid "%s: Operation failed: %s\n" +msgstr "" + +#: systemv/cancel.c:118 +msgid "cancel: Error - expected hostname after '-h' option!\n" +msgstr "" + +#: systemv/cancel.c:139 +msgid "cancel: Error - expected username after '-u' option!\n" +msgstr "" + +#: systemv/cancel.c:150 +#, c-format +msgid "cancel: Unknown option '%c'!\n" +msgstr "" + +#: systemv/cancel.c:207 +#, fuzzy, c-format +msgid "cancel: Unknown destination \"%s\"!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/cancel.c:229 systemv/cancel.c:319 +msgid "cancel: Unable to contact server!\n" +msgstr "" + +#: systemv/cancel.c:295 systemv/cancel.c:370 +#, c-format +msgid "cancel: %s failed: %s\n" +msgstr "" + +#: systemv/cupsaddsmb.c:290 +#, c-format +msgid "cupsaddsmb: Missing value on line %d!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:301 +#, c-format +msgid "cupsaddsmb: Missing double quote on line %d!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:313 +#, c-format +msgid "cupsaddsmb: Bad option + choice on line %d!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:496 +#, c-format +msgid "cupsaddsmb: Unable to connect to server \"%s\" for %s - %s\n" +msgstr "" + +#: systemv/cupsaddsmb.c:509 +#, c-format +msgid "cupsaddsmb: No PPD file for printer \"%s\" - skipping!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:548 systemv/cupsaddsmb.c:562 +#, c-format +msgid "cupsaddsmb: get-printer-attributes failed for \"%s\": %s\n" +msgstr "" + +#: systemv/cupsaddsmb.c:578 +#, fuzzy, c-format +msgid "cupsaddsmb: Unable to convert PPD file for %s - %s\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/cupsaddsmb.c:633 +#, c-format +msgid "cupsaddsmb: Unable to copy Windows 2000 printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:660 +#, c-format +msgid "cupsaddsmb: Unable to copy CUPS printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:697 +#, c-format +msgid "cupsaddsmb: Unable to install Windows 2000 printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:727 +#, c-format +msgid "cupsaddsmb: Unable to copy Windows 9x printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:750 +#, c-format +msgid "cupsaddsmb: Unable to install Windows 9x printer driver files (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:771 +#, c-format +msgid "cupsaddsmb: Unable to set Windows printer driver (%d)!\n" +msgstr "" + +#: systemv/cupsaddsmb.c:854 +msgid "" +"Usage: cupsaddsmb [options] printer1 ... printerN\n" +" cupsaddsmb [options] -a\n" +"\n" +"Options:\n" +" -H samba-server Use the named SAMBA server\n" +" -U samba-user Authenticate using the named SAMBA user\n" +" -a Export all printers\n" +" -h cups-server Use the named CUPS server\n" +" -v Be verbose (show commands)\n" +msgstr "" + +#: systemv/cupstestppd.c:120 +msgid "cupstestppd: The -q option is incompatible with the -v option.\n" +msgstr "" + +#: systemv/cupstestppd.c:136 +msgid "cupstestppd: The -v option is incompatible with the -q option.\n" +msgstr "" + +#: systemv/cupstestppd.c:193 +#, fuzzy, c-format +msgid "" +" FAIL\n" +" **FAIL** Unable to open PPD file - %s\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/cupstestppd.c:204 +#, c-format +msgid "" +" FAIL\n" +" **FAIL** Unable to open PPD file - %s on line %d.\n" +msgstr "" + +#: systemv/cupstestppd.c:213 +msgid " REF: Page 42, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:217 +msgid " REF: Page 20, section 3.4.\n" +msgstr "" + +#: systemv/cupstestppd.c:222 +msgid " REF: Pages 45-46, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:227 +msgid " REF: Pages 42-45, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:231 +msgid " REF: Pages 48-49, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:235 +msgid " REF: Pages 52-54, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:239 +msgid " REF: Page 15, section 3.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:243 systemv/cupstestppd.c:247 +msgid " REF: Page 15, section 3.1.\n" +msgstr "" + +#: systemv/cupstestppd.c:251 +msgid " REF: Pages 16-17, section 3.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:255 +msgid " REF: Page 19, section 3.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:259 +msgid " REF: Page 27, section 3.5.\n" +msgstr "" + +#: systemv/cupstestppd.c:280 +msgid "" +"\n" +" DETAILED CONFORMANCE TEST RESULTS\n" +msgstr "" + +#: systemv/cupstestppd.c:307 +#, c-format +msgid " WARN %s has no corresponding options!\n" +msgstr "" + +#: systemv/cupstestppd.c:318 systemv/cupstestppd.c:333 +#: systemv/cupstestppd.c:354 systemv/cupstestppd.c:369 +#: systemv/cupstestppd.c:397 systemv/cupstestppd.c:417 +#: systemv/cupstestppd.c:439 systemv/cupstestppd.c:459 +#: systemv/cupstestppd.c:479 systemv/cupstestppd.c:499 +#: systemv/cupstestppd.c:517 systemv/cupstestppd.c:535 +#: systemv/cupstestppd.c:556 systemv/cupstestppd.c:575 +#: systemv/cupstestppd.c:595 systemv/cupstestppd.c:615 +#: systemv/cupstestppd.c:635 systemv/cupstestppd.c:655 +#: systemv/cupstestppd.c:673 systemv/cupstestppd.c:690 +#: systemv/cupstestppd.c:712 systemv/cupstestppd.c:730 +#: systemv/cupstestppd.c:747 systemv/cupstestppd.c:765 +#: systemv/cupstestppd.c:781 systemv/cupstestppd.c:801 +#: systemv/cupstestppd.c:832 systemv/cupstestppd.c:854 +#: systemv/cupstestppd.c:902 systemv/cupstestppd.c:931 +#: systemv/cupstestppd.c:952 +msgid " FAIL\n" +msgstr "" + +#: systemv/cupstestppd.c:321 +msgid "" +" **FAIL** REQUIRED DefaultImageableArea\n" +" REF: Page 102, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:336 +#, c-format +msgid "" +" **FAIL** BAD DefaultImageableArea %s!\n" +" REF: Page 102, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:346 +msgid " PASS DefaultImageableArea\n" +msgstr "" + +#: systemv/cupstestppd.c:357 +msgid "" +" **FAIL** REQUIRED DefaultPaperDimension\n" +" REF: Page 103, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:372 +#, c-format +msgid "" +" **FAIL** BAD DefaultPaperDimension %s!\n" +" REF: Page 103, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:380 +msgid " PASS DefaultPaperDimension\n" +msgstr "" + +#: systemv/cupstestppd.c:400 +#, c-format +msgid "" +" **FAIL** BAD Default%s %s\n" +" REF: Page 40, section 4.5.\n" +msgstr "" + +#: systemv/cupstestppd.c:409 +#, c-format +msgid " PASS Default%s\n" +msgstr "" + +#: systemv/cupstestppd.c:420 +#, c-format +msgid "" +" **FAIL** REQUIRED Default%s\n" +" REF: Page 40, section 4.5.\n" +msgstr "" + +#: systemv/cupstestppd.c:432 +msgid " PASS FileVersion\n" +msgstr "" + +#: systemv/cupstestppd.c:442 +msgid "" +" **FAIL** REQUIRED FileVersion\n" +" REF: Page 56, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:452 +msgid " PASS FormatVersion\n" +msgstr "" + +#: systemv/cupstestppd.c:462 +msgid "" +" **FAIL** REQUIRED FormatVersion\n" +" REF: Page 56, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:472 +msgid " PASS LanguageEncoding\n" +msgstr "" + +#: systemv/cupstestppd.c:482 +msgid "" +" **FAIL** REQUIRED LanguageEncoding\n" +" REF: Pages 56-57, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:492 +msgid " PASS LanguageVersion\n" +msgstr "" + +#: systemv/cupstestppd.c:502 +msgid "" +" **FAIL** REQUIRED LanguageVersion\n" +" REF: Pages 57-58, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:520 +msgid "" +" **FAIL** BAD Manufacturer (should be \"HP\")\n" +" REF: Page 211, table D.1.\n" +msgstr "" + +#: systemv/cupstestppd.c:528 +msgid " PASS Manufacturer\n" +msgstr "" + +#: systemv/cupstestppd.c:538 +msgid "" +" **FAIL** REQUIRED Manufacturer\n" +" REF: Pages 58-59, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:559 +#, c-format +msgid "" +" **FAIL** BAD ModelName - \"%c\" not allowed in string.\n" +" REF: Pages 59-60, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:568 +msgid " PASS ModelName\n" +msgstr "" + +#: systemv/cupstestppd.c:578 +msgid "" +" **FAIL** REQUIRED ModelName\n" +" REF: Pages 59-60, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:588 +msgid " PASS NickName\n" +msgstr "" + +#: systemv/cupstestppd.c:598 +msgid "" +" **FAIL** REQUIRED NickName\n" +" REF: Page 60, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:608 +msgid " PASS PageSize\n" +msgstr "" + +#: systemv/cupstestppd.c:618 +msgid "" +" **FAIL** REQUIRED PageSize\n" +" REF: Pages 99-100, section 5.14.\n" +msgstr "" + +#: systemv/cupstestppd.c:628 +msgid " PASS PageRegion\n" +msgstr "" + +#: systemv/cupstestppd.c:638 +msgid "" +" **FAIL** REQUIRED PageRegion\n" +" REF: Page 100, section 5.14.\n" +msgstr "" + +#: systemv/cupstestppd.c:648 +msgid " PASS PCFileName\n" +msgstr "" + +#: systemv/cupstestppd.c:658 +msgid "" +" **FAIL** REQUIRED PCFileName\n" +" REF: Pages 61-62, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:676 +msgid "" +" **FAIL** BAD Product - not \"(string)\".\n" +" REF: Page 62, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:683 +msgid " PASS Product\n" +msgstr "" + +#: systemv/cupstestppd.c:693 +msgid "" +" **FAIL** REQUIRED Product\n" +" REF: Page 62, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:715 +msgid "" +" **FAIL** BAD PSVersion - not \"(string) int\".\n" +" REF: Pages 62-64, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:723 +msgid " PASS PSVersion\n" +msgstr "" + +#: systemv/cupstestppd.c:733 +msgid "" +" **FAIL** REQUIRED PSVersion\n" +" REF: Pages 62-64, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:750 +msgid "" +" **FAIL** BAD ShortNickName - longer than 31 chars.\n" +" REF: Pages 64-65, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:758 +msgid " PASS ShortNickName\n" +msgstr "" + +#: systemv/cupstestppd.c:768 +msgid "" +" **FAIL** REQUIRED ShortNickName\n" +" REF: Page 64-65, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:784 +msgid "" +" **FAIL** BAD JobPatchFile attribute in file\n" +" REF: Page 24, section 3.4.\n" +msgstr "" + +#: systemv/cupstestppd.c:804 +msgid "" +" **FAIL** REQUIRED PageSize\n" +" REF: Page 41, section 5.\n" +" REF: Page 99, section 5.14.\n" +msgstr "" + +#: systemv/cupstestppd.c:835 +#, c-format +msgid "" +" **FAIL** REQUIRED ImageableArea for PageSize %s\n" +" REF: Page 41, section 5.\n" +" REF: Page 102, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:857 +#, c-format +msgid "" +" **FAIL** REQUIRED PaperDimension for PageSize %s\n" +" REF: Page 41, section 5.\n" +" REF: Page 103, section 5.15.\n" +msgstr "" + +#: systemv/cupstestppd.c:905 +#, c-format +msgid "" +" **FAIL** Bad %s choice %s!\n" +" REF: Page 84, section 5.9\n" +msgstr "" + +#: systemv/cupstestppd.c:934 +#, c-format +msgid "" +" **FAIL** REQUIRED %s does not define choice None!\n" +" REF: Page 122, section 5.17\n" +msgstr "" + +#: systemv/cupstestppd.c:955 +#, c-format +msgid "" +" **FAIL** Bad %s choice %s!\n" +" REF: Page 122, section 5.17\n" +msgstr "" + +#: systemv/cupstestppd.c:967 +msgid " PASS\n" +msgstr "" + +#: systemv/cupstestppd.c:976 +#, c-format +msgid "" +" WARN Duplex option keyword %s should be named Duplex or " +"JCLDuplex!\n" +" REF: Page 122, section 5.17\n" +msgstr "" + +#: systemv/cupstestppd.c:986 +msgid " WARN Default choices conflicting!\n" +msgstr "" + +#: systemv/cupstestppd.c:994 +#, c-format +msgid "" +" WARN Obsolete PPD version %.1f!\n" +" REF: Page 42, section 5.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:1002 +msgid "" +" WARN LanguageEncoding required by PPD 4.3 spec.\n" +" REF: Pages 56-57, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:1010 +msgid "" +" WARN Manufacturer required by PPD 4.3 spec.\n" +" REF: Pages 58-59, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:1023 +msgid "" +" WARN PCFileName longer than 8.3 in violation of PPD spec.\n" +" REF: Pages 61-62, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:1031 +msgid "" +" WARN ShortNickName required by PPD 4.3 spec.\n" +" REF: Pages 64-65, section 5.3.\n" +msgstr "" + +#: systemv/cupstestppd.c:1048 +msgid "" +" WARN Protocols contains both PJL and BCP; expected TBCP.\n" +" REF: Pages 78-79, section 5.7.\n" +msgstr "" + +#: systemv/cupstestppd.c:1057 +msgid "" +" WARN Protocols contains PJL but JCL attributes are not set.\n" +" REF: Pages 78-79, section 5.7.\n" +msgstr "" + +#: systemv/cupstestppd.c:1085 +#, c-format +msgid "" +" WARN %s shares a common prefix with %s\n" +" REF: Page 15, section 3.2.\n" +msgstr "" + +#: systemv/cupstestppd.c:1097 +#, c-format +msgid " %d ERROR%s FOUND\n" +msgstr "" + +#: systemv/cupstestppd.c:1100 +msgid " NO ERRORS FOUND\n" +msgstr "" + +#: systemv/cupstestppd.c:1360 +#, c-format +msgid "" +" WARN \"%s %s\" conflicts with \"%s %s\"\n" +" (constraint=\"%s %s %s %s\")\n" +msgstr "" + +#: systemv/cupstestppd.c:1376 +msgid "" +"Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] [... filenameN.ppd[." +"gz]]\n" +" program | cupstestppd [-q] [-r] [-v[v]] -\n" +msgstr "" + +#: systemv/lpstat.c:144 systemv/lpstat.c:155 +msgid "lpstat: Need \"completed\" or \"not-completed\" after -W!\n" +msgstr "" + +#: systemv/lpstat.c:212 +msgid "lpstat: The -b option requires a destination argument.\n" +msgstr "" + +#: systemv/lpstat.c:274 systemv/lpinfo.c:143 systemv/lpmove.c:105 +msgid "Error: need hostname after '-h' option!\n" +msgstr "" + +#: systemv/lpstat.c:433 +#, c-format +msgid "lpstat: Unknown option '%c'!\n" +msgstr "" + +#: systemv/lpstat.c:504 +#, c-format +msgid "lpstat: Invalid destination name in list \"%s\"!\n" +msgstr "" + +#: systemv/lpstat.c:519 +#, fuzzy, c-format +msgid "lpstat: Unknown destination \"%s\"!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lpstat.c:541 +#, c-format +msgid "lpstat: Unable to connect to server %s on port %d: %s\n" +msgstr "" + +#: systemv/lpstat.c:625 systemv/lpstat.c:773 systemv/lpstat.c:1187 +#: systemv/lpstat.c:1379 systemv/lpstat.c:1809 systemv/lpstat.c:2262 +#, c-format +msgid "lpstat: get-printers failed: %s\n" +msgstr "" + +#: systemv/lpstat.c:741 +#, c-format +msgid "%s accepting requests since Jan 01 00:00\n" +msgstr "" + +#: systemv/lpstat.c:745 +#, c-format +msgid "" +"%s not accepting requests since Jan 01 00:00 -\n" +"\t%s\n" +msgstr "" + +#: systemv/lpstat.c:754 +#, c-format +msgid "%s/%s accepting requests since Jan 01 00:00\n" +msgstr "" + +#: systemv/lpstat.c:758 +#, c-format +msgid "" +"%s/%s not accepting requests since Jan 01 00:00 -\n" +"\t%s\n" +msgstr "" + +#: systemv/lpstat.c:861 systemv/lpstat.c:1056 +#, c-format +msgid "lpstat: get-classes failed: %s\n" +msgstr "" + +#: systemv/lpstat.c:1033 +#, c-format +msgid "members of class %s:\n" +msgstr "" + +#: systemv/lpstat.c:1080 +#, c-format +msgid "system default destination: %s/%s\n" +msgstr "" + +#: systemv/lpstat.c:1083 +#, c-format +msgid "system default destination: %s\n" +msgstr "" + +#: systemv/lpstat.c:1105 +#, c-format +msgid "" +"lpstat: error - %s environment variable names non-existent destination \"%s" +"\"!\n" +msgstr "" + +#: systemv/lpstat.c:1109 +msgid "no system default destination\n" +msgstr "" + +#: systemv/lpstat.c:1313 +#, c-format +msgid "Output for printer %s is sent to remote printer %s on %s\n" +msgstr "" + +#: systemv/lpstat.c:1319 systemv/lpstat.c:1323 +#, c-format +msgid "Output for printer %s is sent to %s\n" +msgstr "" + +#: systemv/lpstat.c:1331 +#, c-format +msgid "Output for printer %s/%s is sent to remote printer %s on %s\n" +msgstr "" + +#: systemv/lpstat.c:1337 systemv/lpstat.c:1341 +#, c-format +msgid "Output for printer %s/%s is sent to %s\n" +msgstr "" + +#: systemv/lpstat.c:1346 systemv/lpstat.c:1349 systemv/lpstat.c:1352 +#, c-format +msgid "device for %s: %s\n" +msgstr "" + +#: systemv/lpstat.c:1359 systemv/lpstat.c:1362 systemv/lpstat.c:1365 +#, c-format +msgid "device for %s/%s: %s\n" +msgstr "" + +#: systemv/lpstat.c:1481 systemv/lpstat.c:1693 +#, c-format +msgid "lpstat: get-jobs failed: %s\n" +msgstr "" + +#: systemv/lpstat.c:1681 +#, c-format +msgid "\tqueued for %s\n" +msgstr "" + +#: systemv/lpstat.c:2037 +#, c-format +msgid "printer %s is idle. enabled since %s\n" +msgstr "" + +#: systemv/lpstat.c:2042 +#, c-format +msgid "printer %s now printing %s-%d. enabled since %s\n" +msgstr "" + +#: systemv/lpstat.c:2048 +#, c-format +msgid "printer %s disabled since %s -\n" +msgstr "" + +#: systemv/lpstat.c:2056 systemv/lpstat.c:2169 +msgid "\treason unknown\n" +msgstr "" + +#: systemv/lpstat.c:2063 systemv/lpstat.c:2176 +msgid "" +"\tForm mounted:\n" +"\tContent types: any\n" +"\tPrinter types: unknown\n" +msgstr "" + +#: systemv/lpstat.c:2069 systemv/lpstat.c:2182 +#, c-format +msgid "\tDescription: %s\n" +msgstr "" + +#: systemv/lpstat.c:2074 systemv/lpstat.c:2187 +msgid "\tAlerts:" +msgstr "" + +#: systemv/lpstat.c:2083 systemv/lpstat.c:2196 +#, c-format +msgid "\tLocation: %s\n" +msgstr "" + +#: systemv/lpstat.c:2088 systemv/lpstat.c:2201 +msgid "\tConnection: remote\n" +msgstr "" + +#: systemv/lpstat.c:2092 systemv/lpstat.c:2205 +#, c-format +msgid "\tInterface: %s.ppd\n" +msgstr "" + +#: systemv/lpstat.c:2097 systemv/lpstat.c:2210 +msgid "\tConnection: direct\n" +msgstr "" + +#: systemv/lpstat.c:2101 systemv/lpstat.c:2214 +#, c-format +msgid "\tInterface: %s/interfaces/%s\n" +msgstr "" + +#: systemv/lpstat.c:2105 systemv/lpstat.c:2218 +#, c-format +msgid "\tInterface: %s/ppd/%s.ppd\n" +msgstr "" + +#: systemv/lpstat.c:2107 systemv/lpstat.c:2220 +msgid "\tOn fault: no alert\n" +msgstr "" + +#: systemv/lpstat.c:2108 systemv/lpstat.c:2221 +msgid "\tAfter fault: continue\n" +msgstr "" + +#: systemv/lpstat.c:2112 systemv/lpstat.c:2126 systemv/lpstat.c:2225 +#: systemv/lpstat.c:2239 +msgid "\tUsers allowed:\n" +msgstr "" + +#: systemv/lpstat.c:2119 systemv/lpstat.c:2232 +msgid "\tUsers denied:\n" +msgstr "" + +#: systemv/lpstat.c:2127 systemv/lpstat.c:2240 +msgid "\t\t(all)\n" +msgstr "" + +#: systemv/lpstat.c:2129 systemv/lpstat.c:2242 +msgid "\tForms allowed:\n" +msgstr "" + +#: systemv/lpstat.c:2130 systemv/lpstat.c:2133 systemv/lpstat.c:2243 +#: systemv/lpstat.c:2246 +msgid "\t\t(none)\n" +msgstr "" + +#: systemv/lpstat.c:2131 systemv/lpstat.c:2244 +msgid "\tBanner required\n" +msgstr "" + +#: systemv/lpstat.c:2132 systemv/lpstat.c:2245 +msgid "\tCharset sets:\n" +msgstr "" + +#: systemv/lpstat.c:2134 systemv/lpstat.c:2247 +msgid "\tDefault pitch:\n" +msgstr "" + +#: systemv/lpstat.c:2135 systemv/lpstat.c:2248 +msgid "\tDefault page size:\n" +msgstr "" + +#: systemv/lpstat.c:2136 systemv/lpstat.c:2249 +msgid "\tDefault port settings:\n" +msgstr "" + +#: systemv/lpstat.c:2146 +#, c-format +msgid "printer %s/%s is idle. enabled since %s\n" +msgstr "" + +#: systemv/lpstat.c:2153 +#, c-format +msgid "printer %s/%s now printing %s-%d. enabled since %s\n" +msgstr "" + +#: systemv/lpstat.c:2160 +#, c-format +msgid "printer %s/%s disabled since %s -\n" +msgstr "" + +#: systemv/lpstat.c:2279 +msgid "scheduler is running\n" +msgstr "" + +#: systemv/lpstat.c:2281 +msgid "scheduler is not running\n" +msgstr "" + +#: systemv/lpadmin.c:113 systemv/lpadmin.c:166 systemv/lpadmin.c:237 +#: systemv/lpadmin.c:298 systemv/lpadmin.c:317 systemv/lpadmin.c:383 +#: systemv/lpadmin.c:424 systemv/lpadmin.c:511 systemv/lpadmin.c:557 +#: systemv/lpadmin.c:603 systemv/lpadmin.c:665 systemv/lpadmin.c:711 +#: systemv/lpadmin.c:772 +#, fuzzy, c-format +msgid "lpadmin: Unable to connect to server: %s\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/lpadmin.c:122 +msgid "" +"lpadmin: Unable to add a printer to the class:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:137 +msgid "lpadmin: Expected class name after '-c' option!\n" +msgstr "" + +#: systemv/lpadmin.c:148 systemv/lpadmin.c:460 +msgid "lpadmin: Class name can only contain printable characters!\n" +msgstr "" + +#: systemv/lpadmin.c:181 +msgid "lpadmin: Expected printer name after '-d' option!\n" +msgstr "" + +#: systemv/lpadmin.c:192 systemv/lpadmin.c:409 systemv/lpadmin.c:583 +msgid "lpadmin: Printer name can only contain printable characters!\n" +msgstr "" + +#: systemv/lpadmin.c:219 +msgid "lpadmin: Expected hostname after '-h' option!\n" +msgstr "" + +#: systemv/lpadmin.c:246 +msgid "" +"lpadmin: Unable to set the interface script:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:264 +msgid "lpadmin: Expected interface after '-i' option!\n" +msgstr "" + +#: systemv/lpadmin.c:326 +msgid "" +"lpadmin: Unable to set the interface script or PPD file:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:345 +msgid "lpadmin: Expected model after '-m' option!\n" +msgstr "" + +#: systemv/lpadmin.c:365 +msgid "lpadmin: Expected name=value after '-o' option!\n" +msgstr "" + +#: systemv/lpadmin.c:398 +msgid "lpadmin: Expected printer after '-p' option!\n" +msgstr "" + +#: systemv/lpadmin.c:433 +msgid "" +"lpadmin: Unable to remove a printer from the class:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:449 +msgid "lpadmin: Expected class after '-r' option!\n" +msgstr "" + +#: systemv/lpadmin.c:479 +msgid "lpadmin: Expected allow/deny:userlist after '-u' option!\n" +msgstr "" + +#: systemv/lpadmin.c:496 +#, fuzzy, c-format +msgid "lpadmin: Unknown allow/deny option \"%s\"!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lpadmin.c:520 +msgid "" +"lpadmin: Unable to set the device URI:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:538 +msgid "lpadmin: Expected device URI after '-v' option!\n" +msgstr "" + +#: systemv/lpadmin.c:572 +msgid "lpadmin: Expected printer or class after '-x' option!\n" +msgstr "" + +#: systemv/lpadmin.c:612 +msgid "" +"lpadmin: Unable to set the printer description:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:631 +msgid "lpadmin: Expected description after '-D' option!\n" +msgstr "" + +#: systemv/lpadmin.c:647 +msgid "lpadmin: Expected file type(s) after '-I' option!\n" +msgstr "" + +#: systemv/lpadmin.c:653 +msgid "lpadmin: Warning - content type list ignored!\n" +msgstr "" + +#: systemv/lpadmin.c:674 +msgid "" +"lpadmin: Unable to set the printer location:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:692 +msgid "lpadmin: Expected location after '-L' option!\n" +msgstr "" + +#: systemv/lpadmin.c:720 +msgid "" +"lpadmin: Unable to set the PPD file:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:738 +msgid "lpadmin: Expected PPD after '-P' option!\n" +msgstr "" + +#: systemv/lpadmin.c:749 +#, fuzzy, c-format +msgid "lpadmin: Unknown option '%c'!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lpadmin.c:754 +#, fuzzy, c-format +msgid "lpadmin: Unknown argument '%s'!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lpadmin.c:781 +msgid "" +"lpadmin: Unable to set the printer options:\n" +" You must specify a printer name first!\n" +msgstr "" + +#: systemv/lpadmin.c:793 +msgid "" +"Usage:\n" +"\n" +" lpadmin [-h server] -d destination\n" +" lpadmin [-h server] -x destination\n" +" lpadmin [-h server] -p printer [-c add-class] [-i interface] [-m model]\n" +" [-r remove-class] [-v device] [-D description]\n" +" [-P ppd-file] [-o name=value]\n" +" [-u allow:user,user] [-u deny:user,user]\n" +"\n" +msgstr "" + +#: systemv/lpadmin.c:1554 +#, fuzzy, c-format +msgid "lpadmin: Unable to create temporary file: %s\n" +msgstr "Incapable d'assigner la mémoire pour des types de dossier!" + +#: systemv/lpadmin.c:1562 +#, fuzzy, c-format +msgid "lpadmin: Unable to open file \"%s\": %s\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/lpadmin.c:1631 systemv/lpadmin.c:1862 systemv/lpadmin.c:1870 +#, c-format +msgid "lpadmin: add-printer (set model) failed: %s\n" +msgstr "" + +#: systemv/lpadmin.c:1701 systemv/lpadmin.c:1708 +#, c-format +msgid "lpadmin: add-printer (set description) failed: %s\n" +msgstr "" + +#: systemv/lpadmin.c:1784 systemv/lpadmin.c:1792 +#, c-format +msgid "lpadmin: add-printer (set location) failed: %s\n" +msgstr "" + +#: systemv/lpadmin.c:2021 +#, fuzzy, c-format +msgid "lpadmin: Unable to create temporary file - %s\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/lpadmin.c:2031 +#, fuzzy, c-format +msgid "lpadmin: Unable to open PPD file \"%s\" - %s\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/lpadmin.c:2117 systemv/lpadmin.c:2125 +#, c-format +msgid "lpadmin: %s failed: %s\n" +msgstr "" + +#: systemv/lp.c:153 +msgid "lp: Expected destination after -d option!\n" +msgstr "" + +#: systemv/lp.c:184 +msgid "lp: Expected form after -f option!\n" +msgstr "" + +#: systemv/lp.c:202 +msgid "lp: Expected hostname after -h option!\n" +msgstr "" + +#: systemv/lp.c:220 +msgid "lp: Expected job ID after -i option!\n" +msgstr "" + +#: systemv/lp.c:230 +msgid "lp: Error - cannot print files and alter jobs simultaneously!\n" +msgstr "" + +#: systemv/lp.c:242 +msgid "lp: Error - bad job ID!\n" +msgstr "" + +#: systemv/lp.c:264 +msgid "lp: Expected copies after -n option!\n" +msgstr "" + +#: systemv/lp.c:285 +msgid "lp: Expected option string after -o option!\n" +msgstr "" + +#: systemv/lp.c:304 +#, c-format +msgid "lp: Expected priority after -%c option!\n" +msgstr "" + +#: systemv/lp.c:326 +msgid "lp: Priority must be between 1 and 100.\n" +msgstr "" + +#: systemv/lp.c:348 +msgid "lp: Expected title after -t option!\n" +msgstr "" + +#: systemv/lp.c:364 +msgid "lp: Expected mode list after -y option!\n" +msgstr "" + +#: systemv/lp.c:370 +msgid "lp: Warning - mode option ignored!\n" +msgstr "" + +#: systemv/lp.c:383 +msgid "lp: Expected hold name after -H option!\n" +msgstr "" + +#: systemv/lp.c:405 +msgid "lp: Need job ID (-i) before \"-H restart\"!\n" +msgstr "" + +#: systemv/lp.c:427 +msgid "lp: Expected page list after -P option!\n" +msgstr "" + +#: systemv/lp.c:446 +msgid "lp: Expected character set after -S option!\n" +msgstr "" + +#: systemv/lp.c:452 +msgid "lp: Warning - character set option ignored!\n" +msgstr "" + +#: systemv/lp.c:463 +msgid "lp: Expected content type after -T option!\n" +msgstr "" + +#: systemv/lp.c:469 +msgid "lp: Warning - content type option ignored!\n" +msgstr "" + +#: systemv/lp.c:473 +#, fuzzy, c-format +msgid "lp: Unknown option '%c'!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lp.c:482 +msgid "" +"lp: Error - cannot print from stdin if files or a job ID are provided!\n" +msgstr "" + +#: systemv/lp.c:497 +#, c-format +msgid "lp: Unable to access \"%s\" - %s\n" +msgstr "" + +#: systemv/lp.c:514 +#, c-format +msgid "lp: Too many files - \"%s\"\n" +msgstr "" + +#: systemv/lp.c:569 +msgid "lp: error - no default destination available.\n" +msgstr "" + +#: systemv/lp.c:572 +msgid "lp: error - scheduler not responding!\n" +msgstr "" + +#: systemv/lp.c:611 +#, fuzzy, c-format +msgid "lp: unable to create temporary file \"%s\" - %s\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/lp.c:620 +#, c-format +msgid "lp: error - unable to write to temporary file \"%s\" - %s\n" +msgstr "" + +#: systemv/lp.c:634 +msgid "lp: stdin is empty, so no job has been sent.\n" +msgstr "" + +#: systemv/lp.c:650 +#, fuzzy, c-format +msgid "lp: unable to print file: %s\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/lp.c:656 +#, c-format +msgid "request id is %s-%d (%d file(s))\n" +msgstr "" + +#: systemv/lp.c:703 systemv/lp.c:713 +#, c-format +msgid "lp: restart-job failed: %s\n" +msgstr "" + +#: systemv/lp.c:769 systemv/lp.c:779 +#, c-format +msgid "lp: set-job-attributes failed: %s\n" +msgstr "" + +#: systemv/lpinfo.c:98 systemv/lpinfo.c:117 +#, c-format +msgid "lpinfo: Unable to connect to server: %s\n" +msgstr "" + +#: systemv/lpinfo.c:152 +#, fuzzy, c-format +msgid "lpinfo: Unknown option '%c'!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lpinfo.c:158 +#, fuzzy, c-format +msgid "lpinfo: Unknown argument '%s'!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lpinfo.c:225 systemv/lpinfo.c:310 +#, c-format +msgid "lpinfo: cups-get-devices failed: %s\n" +msgstr "" + +#: systemv/lpinfo.c:293 +#, c-format +msgid "" +"Device: uri = %s\n" +" class = %s\n" +" info = %s\n" +" make-and-model = %s\n" +msgstr "" + +#: systemv/lpinfo.c:376 systemv/lpinfo.c:454 +#, c-format +msgid "lpinfo: cups-get-ppds failed: %s\n" +msgstr "" + +#: systemv/lpinfo.c:438 +#, c-format +msgid "" +"Model: name = %s\n" +" natural_language = %s\n" +" make-and-model = %s\n" +msgstr "" + +#: systemv/lpmove.c:114 +#, fuzzy, c-format +msgid "lpmove: Unknown option '%c'!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lpmove.c:133 +#, fuzzy, c-format +msgid "lpmove: Unknown argument '%s'!\n" +msgstr "Incapable d'ajouter le travail pour la destination \"%s\"!" + +#: systemv/lpmove.c:140 +msgid "Usage: lpmove job dest\n" +msgstr "" + +#: systemv/lpmove.c:151 +#, c-format +msgid "lpmove: Unable to connect to server: %s\n" +msgstr "" + +#: systemv/lpmove.c:225 systemv/lpmove.c:234 +#, c-format +msgid "lpmove: move-job failed: %s\n" +msgstr "" + +#: systemv/lpoptions.c:109 +msgid "lpoptions: Unknown printer or class!\n" +msgstr "" + +#: systemv/lpoptions.c:159 +msgid "lpoptions: No printers!?!\n" +msgstr "" + +#: systemv/lpoptions.c:207 +#, c-format +msgid "lpoptions: Unable to add printer or instance: %s\n" +msgstr "" + +#: systemv/lpoptions.c:411 +#, c-format +msgid "lpoptions: Destination %s has no PPD file!\n" +msgstr "" + +#: systemv/lpoptions.c:420 +#, fuzzy, c-format +msgid "lpoptions: Unable to open PPD file for %s!\n" +msgstr "Incapable de copier le dossier de PPD - %s!" + +#: systemv/lpoptions.c:444 +msgid "" +"Usage: lpoptions [-h server] [-E] -d printer\n" +" lpoptions [-h server] [-E] [-p printer] -l\n" +" lpoptions [-h server] [-E] -p printer -o option[=value] ...\n" +" lpoptions [-h server] [-E] -x printer\n" +msgstr "" + +#: systemv/lppasswd.c:192 +msgid "lppasswd: Only root can add or delete passwords!\n" +msgstr "" + +#: systemv/lppasswd.c:212 +msgid "Enter old password:" +msgstr "" + +#: systemv/lppasswd.c:218 systemv/lppasswd.c:236 +#, c-format +msgid "lppasswd: Unable to copy password string: %s\n" +msgstr "" + +#: systemv/lppasswd.c:230 +msgid "Enter password:" +msgstr "" + +#: systemv/lppasswd.c:241 +msgid "Enter password again:" +msgstr "" + +#: systemv/lppasswd.c:247 +msgid "lppasswd: Sorry, passwords don't match!\n" +msgstr "" + +#: systemv/lppasswd.c:271 +msgid "" +"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" +msgstr "" + +#: systemv/lppasswd.c:321 +msgid "lppasswd: Password file busy!\n" +msgstr "" + +#: systemv/lppasswd.c:324 systemv/lppasswd.c:333 systemv/lppasswd.c:351 +#, c-format +msgid "lppasswd: Unable to open password file: %s\n" +msgstr "" + +#: systemv/lppasswd.c:386 systemv/lppasswd.c:399 systemv/lppasswd.c:431 +#, c-format +msgid "lppasswd: Unable to write to password file: %s\n" +msgstr "" + +#: systemv/lppasswd.c:411 +#, c-format +msgid "lppasswd: user \"%s\" and group \"%s\" do not exist.\n" +msgstr "" + +#: systemv/lppasswd.c:421 +msgid "lppasswd: Sorry, password doesn't match!\n" +msgstr "" + +#: systemv/lppasswd.c:454 +msgid "lppasswd: Password file not updated!\n" +msgstr "" + +#: systemv/lppasswd.c:469 +#, c-format +msgid "lppasswd: failed to backup old password file: %s\n" +msgstr "" + +#: systemv/lppasswd.c:482 +#, c-format +msgid "lppasswd: failed to rename password file: %s\n" +msgstr "" + +#: systemv/lppasswd.c:501 +msgid "Usage: lppasswd [-g groupname]\n" +msgstr "" + +#: systemv/lppasswd.c:506 +msgid "" +"Usage: lppasswd [-g groupname] [username]\n" +" lppasswd [-g groupname] -a [username]\n" +" lppasswd [-g groupname] -x [username]\n" +msgstr "" 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 . +The HTTP status messages use the status codes defined in . + +If you would like to contribute a new message file for your locale, or +have corrections to the current ones, please send them to: + + cups-support@cups.org diff --git a/locale/translate.c b/locale/translate.c new file mode 100644 index 000000000..e082b858d --- /dev/null +++ b/locale/translate.c @@ -0,0 +1,448 @@ +/* + * "$Id: translate.c 4896 2006-01-08 03:57:45Z mike $" + * + * HTTP-based translation program for the Common UNIX Printing System (CUPS). + * + * This program uses Google to translate the CUPS template (cups.pot) to + * several different languages. The translation isn't perfect, but it's + * a start (better than working from scratch.) + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +int save_messages(cups_array_t *cat, const char *filename); +int translate_messages(cups_array_t *cat, const char *lang); +int write_string(cups_file_t *fp, const char *s); + + +/* + * 'main()' - Main entry. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + cups_array_t *cat; /* Message catalog */ + + + if (argc != 3) + { + fputs("Usage: translate cups_language.po language\n", stderr); + return (1); + } + + if (access(argv[1], 0)) + cat = _cupsMessageLoad("cups.pot"); + else + cat = _cupsMessageLoad(argv[1]); + + if (!cat) + { + puts("Unable to load message catalog."); + return (1); + } + + if (!translate_messages(cat, argv[2])) + { + puts("Unable to translate message catalog."); + return (1); + } + + if (!save_messages(cat, argv[1])) + { + puts("Unable to save message catalog."); + return (1); + } + + return (0); +} + + +/* + * 'save_messages()' - Save messages to a .po file. + */ + +int /* O - 1 on success, 0 on error */ +save_messages(cups_array_t *cat, /* I - Message catalog */ + const char *filename) /* I - File to save to */ +{ + _cups_message_t *m; /* Current message */ + cups_file_t *fp; /* File pointer */ + + + /* + * Open the message catalog... + */ + + if ((fp = cupsFileOpen(filename, "w")) == NULL) + return (0); + + /* + * Save the messages to a file... + */ + + for (m = (_cups_message_t *)cupsArrayFirst(cat); + m; + m = (_cups_message_t *)cupsArrayNext(cat)) + { + if (cupsFilePuts(fp, "msgid \"") < 0) + break; + + if (!write_string(fp, m->id)) + break; + + if (cupsFilePuts(fp, "\"\nmsgstr \"") < 0) + break; + + if (m->str) + { + if (!write_string(fp, m->str)) + break; + } + + if (cupsFilePuts(fp, "\"\n") < 0) + break; + } + + cupsFileClose(fp); + + return (!m); +} + + +/* + * 'translate_messages()' - Translate messages using Google. + */ + +int /* O - 1 on success, 0 on error */ +translate_messages(cups_array_t *cat, /* I - Message catalog */ + const char *lang) /* I - Output language... */ +{ + /* + * Google provides a simple translation/language tool for translating + * from one language to another. It is far from perfect, however it + * can be used to get a basic translation done or update an existing + * translation when no other resources are available. + * + * Translation requests are sent as HTTP POSTs to + * "http://translate.google.com/translate_t" with the following form + * variables: + * + * Name Description Value + * -------- ---------------------------------- ---------------- + * hl Help language? "en" + * ie Input encoding "UTF8" + * langpair Language pair "en|" + language + * oe Output encoding "UTF8" + * text Text to translate translation string + */ + + int ret; /* Return value */ + _cups_message_t *m; /* Current message */ + int tries; /* Number of tries... */ + http_t *http; /* HTTP connection */ + http_status_t status; /* Status of POST request */ + char *idptr, /* Pointer into msgid */ + buffer[65536], /* Input/output buffer */ + *bufptr, /* Pointer into buffer */ + *bufend, /* Pointer to end of buffer */ + length[16]; /* Content length */ + int bytes; /* Number of bytes read */ + + + /* + * Connect to translate.google.com... + */ + + puts("Connecting to translate.google.com..."); + + if ((http = httpConnect("translate.google.com", 80)) == NULL) + { + perror("Unable to connect to translate.google.com"); + return (0); + } + + /* + * Scan the current messages, requesting a translation of any untranslated + * messages... + */ + + for (m = (_cups_message_t *)cupsArrayFirst(cat), ret = 1; + m; + m = (_cups_message_t *)cupsArrayNext(cat)) + { + /* + * Skip messages that are already translated... + */ + + if (m->str && m->str[0]) + continue; + + /* + * Encode the form data into the buffer... + */ + + snprintf(buffer, sizeof(buffer), + "hl=en&ie=UTF8&langpair=en|%s&oe=UTF8&text=", lang); + bufptr = buffer + strlen(buffer); + bufend = buffer + sizeof(buffer) - 5; + + for (idptr = m->id; *idptr && bufptr < bufend; idptr ++) + if (*idptr == ' ') + *bufptr++ = '+'; + else if (*idptr < ' ' || *idptr == '%') + { + sprintf(bufptr, "%%%02X", *idptr & 255); + bufptr += 3; + } + else if (*idptr != '&') + *bufptr++ = *idptr; + + *bufptr++ = '&'; + *bufptr = '\0'; + + sprintf(length, "%d", bufptr - buffer); + + /* + * Send the request... + */ + + printf("\"%s\" = ", m->id); + fflush(stdout); + + tries = 0; + + do + { + httpClearFields(http); + httpSetField(http, HTTP_FIELD_CONTENT_TYPE, + "application/x-www-form-urlencoded"); + httpSetField(http, HTTP_FIELD_CONTENT_LENGTH, length); + + if (httpPost(http, "/translate_t")) + { + httpReconnect(http); + httpPost(http, "/translate_t"); + } + + httpWrite(http, buffer, bufptr - buffer); + + while ((status = httpUpdate(http)) == HTTP_CONTINUE); + + if (status != HTTP_OK && status != HTTP_ERROR) + httpFlush(http); + + tries ++; + } + while (status == HTTP_ERROR && tries < 10); + + if (status == HTTP_OK) + { + /* + * OK, read the translation back... + */ + + bufptr = buffer; + bufend = buffer + sizeof(buffer) - 1; + + while ((bytes = httpRead(http, bufptr, bufend - bufptr)) > 0) + bufptr += bytes; + + if (bytes < 0) + { + /* + * Read error, abort! + */ + + puts("READ ERROR!"); + ret = 0; + break; + } + + *bufptr = '\0'; + + /* + * Find the first textarea element - that will have the translation data... + */ + + if ((bufptr = strstr(buffer, "')) == NULL) + { + /* + * textarea doesn't end, abort! + */ + + puts("TEXTAREA SHORT DATA!"); + ret = 0; + break; + } + + bufptr ++; + + if ((bufend = strstr(bufptr, "")) == NULL) + { + /* + * textarea doesn't close, abort! + */ + + puts("/TEXTAREA SHORT DATA!"); + ret = 0; + break; + } + + *bufend = '\0'; + + /* + * Copy the translation... + */ + + m->str = strdup(bufptr); + + /* + * Convert character entities to regular chars... + */ + + for (bufptr = strchr(m->str, '&'); + bufptr; + bufptr = strchr(bufptr + 1, '&')) + { + if (!strncmp(bufptr, "<", 4)) + { + *bufptr = '<'; + _cups_strcpy(bufptr + 1, bufptr + 4); + } + else if (!strncmp(bufptr, ">", 4)) + { + *bufptr = '>'; + _cups_strcpy(bufptr + 1, bufptr + 4); + } + else if (!strncmp(bufptr, "&", 5)) + _cups_strcpy(bufptr + 1, bufptr + 5); + } + + printf("\"%s\"\n", m->str); + } + else if (status == HTTP_ERROR) + { + printf("NETWORK ERROR (%s)!\n", strerror(httpError(http))); + ret = 0; + break; + } + else + { + printf("HTTP ERROR %d!\n", status); + ret = 0; + break; + } + } + + httpClose(http); + + return (ret); +} + + +/* + * 'write_string()' - Write a quoted string to a file. + */ + +int /* O - 1 on success, 0 on failure */ +write_string(cups_file_t *fp, /* I - File to write to */ + const char *s) /* I - String */ +{ + while (*s) + { + switch (*s) + { + case '\n' : + if (cupsFilePuts(fp, "\\n") < 0) + return (0); + break; + + case '\r' : + if (cupsFilePuts(fp, "\\r") < 0) + return (0); + break; + + case '\t' : + if (cupsFilePuts(fp, "\\t") < 0) + return (0); + break; + + case '\\' : + if (cupsFilePuts(fp, "\\\\") < 0) + return (0); + break; + + case '\"' : + if (cupsFilePuts(fp, "\\\"") < 0) + return (0); + break; + + default : + if ((*s & 255) < ' ') + { + if (cupsFilePrintf(fp, "\\%o", *s) < 0) + return (0); + } + else if (cupsFilePutChar(fp, *s) < 0) + return (0); + break; + } + + s ++; + } + + return (1); +} + + +/* + * End of "$Id: translate.c 4896 2006-01-08 03:57:45Z mike $". + */ diff --git a/man/Makefile b/man/Makefile new file mode 100644 index 000000000..0e93a080e --- /dev/null +++ b/man/Makefile @@ -0,0 +1,131 @@ +# +# "$Id: Makefile 4868 2005-12-05 16:59:11Z mike $" +# +# Man page makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + + +# +# Man pages... +# + +MAN1 = backend.$(MAN1EXT) \ + cups-config.$(MAN1EXT) \ + cupstestppd.$(MAN1EXT) \ + filter.$(MAN1EXT) \ + lp.$(MAN1EXT) \ + lpoptions.$(MAN1EXT) \ + lppasswd.$(MAN1EXT) \ + lpq.$(MAN1EXT) \ + lprm.$(MAN1EXT) \ + lpr.$(MAN1EXT) \ + lpstat.$(MAN1EXT) +MAN5 = classes.conf.$(MAN5EXT) \ + cupsd.conf.$(MAN5EXT) \ + mime.convs.$(MAN5EXT) \ + mime.types.$(MAN5EXT) \ + printers.conf.$(MAN5EXT) +MAN8 = accept.$(MAN8EXT) \ + cupsaddsmb.$(MAN8EXT) \ + cups-lpd.$(MAN8EXT) \ + cups-polld.$(MAN8EXT) \ + cupsd.$(MAN8EXT) \ + cupsenable.$(MAN8EXT) \ + lpadmin.$(MAN8EXT) \ + lpinfo.$(MAN8EXT) \ + lpmove.$(MAN8EXT) \ + lpc.$(MAN8EXT) + + +# +# Make everything... +# + +all: $(MAN1) $(MAN5) $(MAN8) html + + +# +# Clean all config and object files... +# + +clean: + $(RM) $(MAN1) $(MAN5) $(MAN8) + + +# +# Dummy depend target... +# + +depend: + + +# +# Install files... +# + +install: all + $(INSTALL_DIR) $(MANDIR)/man1 + for file in $(MAN1); do \ + echo Installing $$file in $(MANDIR)/man1...; \ + $(INSTALL_MAN) $$file $(MANDIR)/man1; \ + done + $(RM) $(MANDIR)/man1/cancel.$(MAN1EXT) + $(LN) lp.$(MAN1EXT) $(MANDIR)/man1/cancel.$(MAN1EXT) + $(INSTALL_DIR) $(MANDIR)/man5 + for file in $(MAN5); do \ + echo Installing $$file in $(MANDIR)/man5...; \ + $(INSTALL_MAN) $$file $(MANDIR)/man5; \ + done + $(INSTALL_DIR) $(AMANDIR)/man$(MAN8DIR) + for file in $(MAN8); do \ + echo Installing $$file in $(AMANDIR)/man$(MAN8DIR)...; \ + $(INSTALL_MAN) $$file $(AMANDIR)/man$(MAN8DIR); \ + done + $(RM) $(AMANDIR)/man$(MAN8DIR)/reject.$(MAN8EXT) + $(LN) accept.$(MAN8EXT) $(AMANDIR)/man$(MAN8DIR)/reject.$(MAN8EXT) + $(RM) $(AMANDIR)/man$(MAN8DIR)/cupsdisable.$(MAN8EXT) + $(LN) cupsenable.$(MAN8EXT) $(AMANDIR)/man$(MAN8DIR)/cupsdisable.$(MAN8EXT) + + +# +# Make html versions of man pages... +# + +html: $(MAN1) $(MAN8) mantohtml + echo Converting man pages to HTML... + for file in $(MAN1); do \ + echo " $$file..."; \ + ./mantohtml `basename $$file .$(MAN1EXT)`.man >../doc/help/man-`basename $$file .$(MAN1EXT)`.html; \ + done + for file in $(MAN8); do \ + echo " $$file..."; \ + ./mantohtml `basename $$file .$(MAN8EXT)`.man >../doc/help/man-`basename $$file .$(MAN8EXT)`.html; \ + done + +mantohtml: mantohtml.o + $(CC) $(LDFLAGS) -o $@ mantohtml.o + + +# +# End of "$Id: Makefile 4868 2005-12-05 16:59:11Z mike $". +# diff --git a/man/accept.man b/man/accept.man new file mode 100644 index 000000000..fa28a6d06 --- /dev/null +++ b/man/accept.man @@ -0,0 +1,60 @@ +.\" +.\" "$Id: accept.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" accept/reject man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: accept.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/backend.man b/man/backend.man new file mode 100644 index 000000000..41f338b29 --- /dev/null +++ b/man/backend.man @@ -0,0 +1,348 @@ +.\" +.\" "$Id: backend.man 4884 2005-12-16 01:02:42Z mike $" +.\" +.\" Backend man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH backend 1 "Common UNIX Printing System" "15 December 2005" "Easy Software Products" + +.SH NAME +backend \- cups backend transmission interfaces + +.SH SYNOPSIS +.B backend +.br +.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. Starting with CUPS 1.1.22, any +authentication information in argv[0] will be removed, so +backend developers are urged to use the DEVICE_URI environment +variable whenever authentication information is required. + +.LP +Backchannel data from the device should be relayed to the job +filters by writing to file descriptor 3. The CUPS API includes +the \fIcupsBackchannelWrite\fR function for this purpose. + +.SH DEVICE DISCOVERY +When run with no arguments, the backend should list the devices +and schemes it supports or is advertising to stdout. The output +consists of zero or more lines consisting of any of the following +forms: + +.nf +device-class scheme "Unknown" "device-info" +device-class device-uri "device-make-and-model" "device-info" +device-class device-uri "device-make-and-model" "device-info" "device-id" +.fi + +.LP +The \fIdevice-class\fR field is one of the following values: + +.TP 5 +direct +.br +The device-uri refers to a specific direct-access device with no +options, such as a parallel, USB, or SCSI device. + +.TP 5 +file +.br +The device-uri refers to a file on disk. + +.TP 5 +network +.br +The device-uri refers to a networked device and conforms to the +general form for network URIs. + +.TP 5 +serial +.br +The device-uri refers to a serial device with configurable baud +rate and other options. If the device-uri contains a baud value, +it represents the maximum baud rate supported by the device. + +.LP +The \fIscheme\fR field provides the URI scheme that is supported +by the backend. Backends should use this form only when the +backend supports any URI using that scheme. The \fIdevice-uri\fR +field specifies the full URI to use when communicating with the +device. + +.LP +The \fIdevice-make-and-model\fR field specifies the make and +model of the device, e.g. "Acme Foojet 2000". If the make and +model is not known, you must report "Unknown". + +.LP +The \fIdevice-info\fR field specifies additional information +about the device. Typically this includes the make and model +along with the port number or network address, e.g. "Acme Foojet +2000 USB #1". + +.LP +The optional \fIdevice-id\fR field specifies the IEEE-1284 device +ID string for the device, which is used to select a matching +driver. + +.SH EXIT CODES +The following exit codes are defined for backends: + +.TP 5 +0 (CUPS_BACKEND_OK) +.br +The print file was successfully transmitted to the device or +remote server. + +.TP 5 +1 (CUPS_BACKEND_FAILED) +.br +The print file was not successfully transmitted to the device or +remote server. The scheduler will respond to this by canceling +the job, retrying the job, or stopping the queue depending on the +state of the error-policy attribute. + +.TP 5 +2 (CUPS_BACKEND_CANCEL) +.br +The print file was not successfully transmitted because one or +more attributes are not supported. The scheduler will respond to +this by canceling the job. + +.TP 5 +3 (CUPS_BACKEND_HOLD) +.br +The print file was not successfully transmitted because it cannot +be printed at this time. The scheduler will respond to this by +holding the job. + +.TP 5 +4 (CUPS_BACKEND_STOP) +.br +The print file was not successfully transmitted because it cannot +be printed at this time. The scheduler will respond to this by +stopping the queue. + +.TP 5 +5 (CUPS_BACKEND_AUTH_REQUIRED) +.br +The print file was not successfully transmitted because valid +authentication information is required. The scheduler will +respond to this by holding the job and adding the +authentication-required job-reasons keyword. + +.PP +All other exit code values are reserved. + +.SH LOG MESSAGES +Messages sent to stderr are generally logged to +printer-state-message attribute and the current ErrorLog. Each +line begins with a standard prefix: + +.TP 5 +ALERT: message +.br +Sets the printer-state-message attribute and adds the specified +message to the current ErrorLog using the "alert" log level. + +.TP 5 +ATTR: attribute=value [attribute=value] +.br +Sets the named job attribute(s). Typically this will be used to +set the job-remote-id attribute. + +.TP 5 +CRIT: message +.br +Sets the printer-state-message attribute and adds the specified +message to the current ErrorLog using the "critical" log level. + +.TP 5 +DEBUG: message +.br +Sets the printer-state-message attribute and adds the specified +message to the current ErrorLog using the "debug" log level. + +.TP 5 +DEBUG2: message +.br +Sets the printer-state-message attribute and adds the specified +message to the current ErrorLog using the "debug2" log level. + +.TP 5 +EMERG: message +.br +Sets the printer-state-message attribute and adds the specified +message to the current ErrorLog using the "emergency" log level. + +.TP 5 +ERROR: message +.br +Sets the printer-state-message attribute and adds the specified +message to the current ErrorLog using the "error" log level. + +.TP 5 +INFO: message +.br +Sets the printer-state-message attribute. If the current LogLevel +is set to "debug2", also adds the specified message to the +current ErrorLog using the "info" log level. + +.TP 5 +NOTICE: message +.br +Sets the printer-state-message attribute and adds the specified +message to the current ErrorLog using the "notice" log level. + +.TP 5 +PAGE: page-number #-copies +.TP 5 +PAGE: #-pages total +.br +Adds an entry to the current PageLog. The first form adds +#-copies to the job-media-sheets-completed attribute. The second +form sets the job-media-sheets-completed attribute to #-pages. + +.TP 5 +STATE: printer-state-reason [printer-state-reason ...] +.TP 5 +STATE: + printer-state-reason [printer-state-reason ...] +.TP 5 +STATE: - printer-state-reason [printer-state-reason ...] +.br +Sets, adds, or removes printer-state-reason keywords to the +current queue. Typically this is used to indicate media, ink, and +toner conditions on a printer. + +.TP 5 +WARNING: message +.br +Sets the printer-state-message attribute and adds the specified +message to the current ErrorLog using the "warning" log level. + +.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 utf-8. + +.TP 5 +CLASS +.br +When a job is submitted to a printer class, contains the name of +the destination printer class. Otherwise this environment +variable will not be set. + +.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 and for backends that require any authentication +information which is not included in argv[0]. + +.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 root; consult the +cupsd.conf file for the current setting. + +.SH SEE ALSO +cupsd(8), filter(1) +.br +http://localhost:631/help + +.SH COPYRIGHT +Copyright 1993-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: backend.man 4884 2005-12-16 01:02:42Z mike $". +.\" diff --git a/man/classes.conf.man b/man/classes.conf.man new file mode 100644 index 000000000..f56a5c856 --- /dev/null +++ b/man/classes.conf.man @@ -0,0 +1,72 @@ +.\" +.\" "$Id: classes.conf.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" classes.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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 + ... +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: classes.conf.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/cups-config.man b/man/cups-config.man new file mode 100644 index 000000000..5ff615cba --- /dev/null +++ b/man/cups-config.man @@ -0,0 +1,95 @@ +.\" +.\" "$Id: cups-config.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" cups-config man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH cups-config 1 "Common UNIX Printing System" "27 May 2004" "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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cups-config.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/cups-lpd.man b/man/cups-lpd.man new file mode 100644 index 000000000..37767c3fd --- /dev/null +++ b/man/cups-lpd.man @@ -0,0 +1,114 @@ +.\" +.\" "$Id: cups-lpd.man 4867 2005-12-03 15:45:53Z mike $" +.\" +.\" cups-lpd man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH cups-lpd 8 "Common UNIX Printing System" "3 December 2005" "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 /path/to/cups/daemon/cups-lpd cups-lpd \\ + -o document-format=application/octet-stream +.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 + group = sys + passenv = + server = /path/to/cups/daemon/cups-lpd + server_args = -o document-format=application/octet-stream + } +.fi +.LP +The /path/to/cups/daemon is usually /usr/lib/cups/daemon or +/usr/libexec/cups/daemon, depending on the operating system. +Consult the cupsd.conf file for the local setting. +.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; +the examples in the previous section set the "document-format" +option to "application/octet-stream" which forces autodetection +of the print file format. +.SH PERFORMANCE +\fBcups-lpd\fR performs well with small numbers of clients and +printers. However, since a new process is created for each +connection and since each process must query the printing system +before each job submission, it does not scale to larger +configurations. We highly recommend that large configurations +use the native IPP support provided by CUPS instead. +.SH SECURITY +\fBcups-lpd\fR currently does not perform any access control +based on the settings in \fIcupsd.conf(5)\fR or in the +\fIhosts.allow(5)\fR or \fIhosts.deny\fR files used by TCP +wrappers. Therefore, running \fBcups-lpd\fR on your server will +allow any computer on your network (and perhaps the entire +Internet) to print to your server. +.LP +While \fIxinetd\fR has built-in access control support, you +should use the TCP wrappers package with \fIinetd\fR to limit +access to only those computers that should be able to print +through your server. +.LP +\fBcups-lpd\fR is not enabled by the standard CUPS distribution. +Please consult with your operating system vendor to determine +whether it is enabled in their distribution. +.SH COMPATIBILITY +\fBcups-lpd\fR does not enforce the restricted source port +number specified in RFC 1179, as using restricted ports does not +prevent 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 +cups(1), cupsd(8), inetd(8), xinetd(8) +.SH COPYRIGHT +Copyright 1993-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cups-lpd.man 4867 2005-12-03 15:45:53Z mike $". +.\" diff --git a/man/cups-polld.man b/man/cups-polld.man new file mode 100644 index 000000000..495090ddd --- /dev/null +++ b/man/cups-polld.man @@ -0,0 +1,46 @@ +.\" +.\" "$Id: cups-polld.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" cups-polld man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cups-polld.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/cupsaddsmb.man b/man/cupsaddsmb.man new file mode 100644 index 000000000..388619004 --- /dev/null +++ b/man/cupsaddsmb.man @@ -0,0 +1,189 @@ +.\" +.\" "$Id: cupsaddsmb.man 4919 2006-01-12 14:13:01Z mike $" +.\" +.\" cupsaddsmb man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2006 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH cupsaddsmb 8 "Common UNIX Printing System" "12 January 2006" "Easy Software Products" +.SH NAME +cupsaddsmb \- export printers to samba for windows clients +.SH SYNOPSIS +.B cupsaddsmb +[ -H +.I samba-server +] [ -U +.I samba-user[%samba-password] +] [ -h +.I cups-server +] [ -v ] -a +.br +.B cupsaddsmb +[ -H +.I samba-server +] [ -U +.I samba-user[%samba-password] +] [ -h +.I cups-server +] [ -v ] printer [ ... printer ] +.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 Windows printer +driver files described below. +.LP +The \fI-H\fR option specifies the SAMBA server which defaults +to the CUPS server. +.LP +The \fI-U\fR option specifies the SAMBA print admin username +which defaults to your current username. If the username contains +a percent (%) character, then the text following the percent is +treated as the SAMBA password to use. +.LP +The \fI-a\fR option exports all known printers. Otherwise only +the named printers are exported. +.LP +The \fI-h\fR option specifies a different CUPS server to use. +.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 MICROSOFT POSTSCRIPT DRIVERS FOR WINDOWS +The base driver for Windows 2000 and higher is the Microsoft +PostScript driver, which is available on any system running +Windows 2000 or higher in the +%WINDOWS%\\SYSTEM32\\SPOOL\\DRIVERS\\W32X86\\3 folder. +.LP +The CUPS printer driver is preferred over the Microsoft driver +since it supports the page-label, job-billing, and +job-hold-until options fully on all printers. However, currently +only Windows 2000 and higher is supported by the Microsoft +driver, so you will also need to get the Adobe driver to support +Windows 95, 98, and Me clients. The Adobe and Microsoft drivers +for Windows 2000 are identical. +.LP +Once you have extracted the driver files, create a "drivers" +directory in the CUPS data directory (usually /usr/share/cups) +and copy the files exactly as named below: +.nf + + [Windows 2000 and higher] + ps5ui.dll + pscript.hlp + pscript.ntf + pscript5.dll +.fi + +.SH CUPS POSTSCRIPT DRIVERS FOR WINDOWS +\fIcupsaddsmb\fR can use the CUPS v6 PostScript printer driver +for Windows, which is available for download from the CUPS web +site. +.LP +The CUPS printer driver is preferred over the Adobe and +Microsoft drivers since it supports the page-label, job-billing, +and job-hold-until options fully on all printers. However, +currently only Windows 2000 and higher is supported by the CUPS +driver, so you will also need to get the Adobe driver to support +Windows 95, 98, and Me clients. +.LP +Once you have extracted the driver files, create a "drivers" +directory in the CUPS data directory (usually /usr/share/cups) +and copy the files exactly as named below: +.nf + + [Windows 2000 and higher] + cups6.ini + cupsui6.dll + cupsdrv6.dll + ps5ui.dll + pscript.hlp + pscript.ntf + pscript5.dll +.fi + +.SH ADOBE POSTSCRIPT DRIVERS FOR WINDOWS +\fIcupsaddsmb\fR can use the Adobe PostScript printer driver for +Windows, which are available for download from the Adobe web +site (http://www.adobe.com). +.LP +The CUPS printer driver is preferred over the Adobe drivers +since they support the page-label, job-billing, and +job-hold-until options fully on all printers. You can use the +Adobe drivers for Windows 9x and the CUPS drivers for Windows +2000 and higher. The Adobe and Microsoft drivers for Windows 2000 +are identical. +.LP +Once you have extracted the driver files, create a "drivers" +directory in the CUPS data directory (usually /usr/share/cups) +and copy the files exactly as named below: +.nf + + [Windows 95, 98, and Me] + ADFONTS.MFM + ADOBEPS4.DRV + ADOBEPS4.HLP + ICONLIB.DLL + PSMON.DLL +.fi +.SH SEE ALSO +CUPS Software Administrators Manual, +http://localhost:631/documentation.html +http://www.cups.org/windows/ +.SH COPYRIGHT +Copyright 1993-2006 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cupsaddsmb.man 4919 2006-01-12 14:13:01Z mike $". +.\" diff --git a/man/cupsd.conf.man b/man/cupsd.conf.man new file mode 100644 index 000000000..53d0d65e8 --- /dev/null +++ b/man/cupsd.conf.man @@ -0,0 +1,443 @@ +.\" +.\" "$Id: cupsd.conf.man 4819 2005-11-04 18:39:32Z mike $" +.\" +.\" cupsd.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH cupsd.conf 5 "Common UNIX Printing System" "4 November 2005" "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 +AuthGroupName +.br +Specifies the authentication group. +.TP 5 +AuthType +.br +Specifies the authentication type (None, Basic, Digest) +.TP 5 +AutoPurgeJobs +.br +Specifies whether to purge job history data automatically when +it is no longer required for quotas. +.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 +BrowseProtocols +.br +Specifies the protocols to use for printer browsing. +.TP 5 +BrowseLocalProtocols +.br +Specifies the protocols to use for local printer browsing. +.TP 5 +BrowseRemoteProtocols +.br +Specifies the protocols to use for remote printer browsing. +.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 +Classification +.br +Specifies the security classification of the server. +.TP 5 +ClassifyOverride +.br +Specifies whether to allow users to override the classification +of individual print jobs. +.TP 5 +ConfigFilePerm +.br +Specifies the permissions for all configuration files that the scheduler +writes. +.TP 5 +DataDir +.br +Specified the directory where data files can be found. +.TP 5 +DefaultAuthType +.br +Specifies the default type of authentication to use. +.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 +DefaultPolicy +.br +Specifies the default access policy to use. +.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 +Encryption +.br +Specifies the level of encryption that is required for a particular +location. +.TP 5 +ErrorLog +.br +Specifies the error log filename. +.TP 5 +FileDevice +.br +Specifies whether the file pseudo-device can be used for new +printer queues. +.TP 5 +FilterLimit +.br +Specifies the maximum cost of filters that are run concurrently. +.TP 5 +FilterNice +.br +Specifies the scheduling priority ("nice" value) of filters that +are run to print a job. +.TP 5 +FontPath +.br +Specifies the search path for fonts. +.TP 5 +Group +.br +Specifies the group name or ID that will be used when executing +external programs. +.TP 5 +HideImplicitMembers +.br +Specifies whether to hide members of implicit classes. +.TP 5 +HostNameLookups +.br +Specifies whether or not to do reverse lookups on client addresses. +.TP 5 +ImplicitAnyClasses +.br +Specifies whether or not to create implicit classes for local and +remote printers, e.g. "AnyPrinter" from "Printer", "Printer@server1", +and "Printer@server2". +.TP 5 +ImplicitClasses +.br +Specifies whether or not to create implicit classes from identical +remote printers. +.TP 5 +Include +.br +Includes the named file. +.TP 5 +JobRetryInterval +.br +Specifies the interval between retries of jobs in seconds. +.TP 5 +JobRetryLimit +.br +Specifies the number of retries that are done for jobs. +.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 + ... +.br +Specifies the IPP operations that are being limited inside a policy. +.TP 5 + ... +.TP 5 + ... +.br +Specifies the HTTP methods that are being limited inside a location. +.TP 5 +LimitRequestBody +.br +Specifies the maximum size of any print job request. +.TP 5 +Listen +.br +Listens to the specified address and port. +.TP 5 + ... +.br +Specifies access control for the named location. +.TP 5 +LogFilePerm +.br +Specifies the permissions for all log files that the scheduler writes. +.TP 5 +LogLevel +.br +Specifies the logging level (none, warn, error, info, debug, or debug2) +.TP 5 +MaxClients +.br +Specifies the maximum number of simultaneous clients to support. +.TP 5 +MaxClientsPerHost +.br +Specifies the maximum number of simultaneous clients to support from a +single address. +.TP 5 +MaxCopies +.br +Specifies the maximum number of copies that a user can print of each job. +.TP 5 +MaxJobs +.br +Specifies the maximum number of simultaneous jobs to support. +.TP 5 +MaxJobsPerPrinter +.br +Specifies the maximum number of simultaneous jobs per printer to support. +.TP 5 +MaxJobsPerUser +.br +Specifies the maximum number of simultaneous jobs per user 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 +PassEnv variable [... variable] +.br +Passes the specified environment variable(s) to child processes. +.TP 5 + ... +.br +Specifies access control for the named policy. +.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 +PrintcapFormat +.br +Specifies the format of the printcap file. +.TP 5 +PrintcapGUI +.br +Specifies whether to generate option panel definition files on some +operating systems. +.TP 5 +ReloadTimeout +.br +Specifies the amount of time to wait for job completion before +restarting the scheduler. +.TP 5 +RemoteRoot +.br +Specifies the username that is associated with unauthenticated root +accesses. +.TP 5 +RequestRoot +.br +Specifies the directory to store print jobs and other HTTP request +data. +.TP 5 +Require +.br +Specifies that user or group authentication is required. +.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 +RunAsUser +.br +Specifies that the scheduler should run as the unpriviledged user +set with the User directive. +.TP 5 +Satisfy +.br +Specifies whether all or any limits set for a Location must be +satisfied to allow access. +.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 +ServerCertificate +.br +Specifies the encryption certificate to use. +.TP 5 +ServerKey +.br +Specifies the encryption key to use. +.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 +ServerTokens +.br +Specifies what information is included in the Server header of HTTP +responses. +.TP 5 +SetEnv variable value +.br +Set the specified environment variable to be passed to child processes. +.TP 5 +SSLListen +.br +Listens on the specified address and port for encrypted connections. +.TP 5 +SSLPort +.br +Listens on the specified port for encrypted connections. +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cupsd.conf.man 4819 2005-11-04 18:39:32Z mike $". +.\" diff --git a/man/cupsd.man b/man/cupsd.man new file mode 100644 index 000000000..b503e23cb --- /dev/null +++ b/man/cupsd.man @@ -0,0 +1,61 @@ +.\" +.\" "$Id: cupsd.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" cupsd man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH cupsd 8 "Common UNIX Printing System" "18 July 2002" "Easy Software Products" +.SH NAME +cupsd \- common unix printing system daemon +.SH SYNOPSIS +.B cupsd +[ \-c +.I config-file +] [ \-f ] [ \-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". +.PP +The \fI-F\fR option forces \fIcupsd\fR to run in the foreground +but detaches the process from the controlling terminal and +current directory. This is useful for running \fIcupsd\fR from +\fIinit\fR. +.SH COMPATIBILITY +\fIcupsd\fR implements all of the required IPP/1.1 attributes and +operations. It also implements several CUPS-specific administration +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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cupsd.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/cupsenable.man b/man/cupsenable.man new file mode 100644 index 000000000..9f6539680 --- /dev/null +++ b/man/cupsenable.man @@ -0,0 +1,67 @@ +.\" +.\" "$Id: cupsenable.man 4833 2005-11-12 21:46:52Z mike $" +.\" +.\" enable/disable man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. + +.\" +.\" End of "$Id: cupsenable.man 4833 2005-11-12 21:46:52Z mike $". +.\" diff --git a/man/cupstestppd.man b/man/cupstestppd.man new file mode 100644 index 000000000..cda964c9c --- /dev/null +++ b/man/cupstestppd.man @@ -0,0 +1,105 @@ +.\" +.\" "$Id: cupstestppd.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" cupstestppd man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH cupstestppd 1 "Common UNIX Printing System" "1 August 2003" "Easy Software Products" +.SH NAME +cupstestppd \- test conformance of ppd files +.SH SYNOPSIS +.B cupstestppd +[ -q ] [-r] [ -v[v] ] filename.ppd[.gz] [ ... filenameN.ppd[.gz] ] +.br +.B cupstestppd +[ -q ] [-r] [ -v[v] ] - +.SH DESCRIPTION +\fIcupstestppd\fR tests the conformance of PPD files to the +Adobe PostScript Printer Description file format specification +version 4.3. It can also be used to list the supported options +and available fonts in a PPD file. The results of testing and +any other output are sent to the standard output. +.LP +The first form of \fIcupstestppd\fR tests one or more PPD files +on the command-line. The second form tests the PPD file provided +on the standard input. +.LP +The \fI-q\fR option specifies that no information should be displayed. +.LP +The \fI-r\fR option relaxes the PPD conformance requirements so +that common whitespace, control character, and formatting +problems are not treated as hard errors. +.LP +The \fI-v\fR option specifies that detailed conformance testing +results should be displayed rather than the concise PASS/FAIL/ERROR +status. +.LP +The \fI-vv\fR option specifies that all information in the PPD +file should be displayed in addition to the detailed conformance +testing results. +.LP +The \fI-q\fR, \fI-v\fR, and \fI-vv\fR options are mutually exclusive. +.SH EXIT STATUS +\fIcupstestppd\fR returns zero on success and non-zero on error. The +error codes are as follows: +.TP 5 +1 +.br +Bad command-line arguments or missing PPD filename. +.TP 5 +2 +.br +Unable to open or read PPD file. +.TP 5 +3 +.br +The PPD file contains format errors that cannot be skipped. +.TP 5 +4 +.br +The PPD file does not conform to the Adobe PPD specification. +.SH EXAMPLES +The following command will test all PPD files under the current +directory and print the names of each file that does not +conform: +.nf + + find . -name \\*.ppd \\! -exec cupstestppd -q '{}' \\; -print + +.fi +The next command tests all PPD files under the current directory +and print detailed conformance testing results for the files +that do not conform: +.nf + + find . -name \\*.ppd \\! -exec cupstestppd -q '{}' \\; \\ + -exec cupstestppd -v '{}' \\; + +.fi +.SH SEE ALSO +CUPS Software Administrators Manual, +CUPS Software Programmers Manual, +http://localhost:631/documentation.html, +Adobe PostScript Printer Description File Format Specification, Version 4.3. +.SH COPYRIGHT +Copyright 1993-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: cupstestppd.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/filter.man b/man/filter.man new file mode 100644 index 000000000..61e2afe74 --- /dev/null +++ b/man/filter.man @@ -0,0 +1,123 @@ +.\" +.\" "$Id: filter.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" filter man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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 +CLASS +.br +When a job is submitted to a printer class, contains the name of +the destination printer class. Otherwise this environment +variable will not be set. +.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; consult the cupsd.conf file for +the current setting. +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: filter.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lp.man b/man/lp.man new file mode 100644 index 000000000..65562ee5a --- /dev/null +++ b/man/lp.man @@ -0,0 +1,181 @@ +.\" +.\" "$Id: lp.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lp/cancel man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lp 1 "Common UNIX Printing System" "1 May 2003" "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 +] [ -u +.I username +] [ +.I id +] [ +.I destination +] [ +.I destination-id +] +.SH DESCRIPTION +\fBlp\fR submits files for printing or alters a pending job. Use +a filename of "-" to force printing from the standard input. +.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 +\-c +.br +This option is provided for backwards-compatibility only. On +systems that support it, this option forces the print file to be +copied to the spool directory before printing. In CUPS, print +files are always sent to the scheduler via IPP which has the +same effect. +.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 +\-u \fIusername\fR +.br +Cancels jobs owned by \fIusername\fR. +.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. +Use a value of \fIrestart\fR with the \fI-i\fR option to restart +a completed 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 NOTES +Administrators wishing to prevent unauthorized cancellation of +jobs via the \fI-u\fR option should password-protect the /jobs +location in \fIcupsd.conf(5)\fR. +.SH SEE ALSO +lpstat(1), +CUPS Software Users Manual, +http://localhost:631/documentation.html +.SH COPYRIGHT +Copyright 1993-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lp.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lpadmin.man b/man/lpadmin.man new file mode 100644 index 000000000..7c94b8ca0 --- /dev/null +++ b/man/lpadmin.man @@ -0,0 +1,163 @@ +.\" +.\" "$Id: lpadmin.man 4841 2005-11-15 20:39:31Z mike $" +.\" +.\" lpadmin man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lpadmin 8 "Common UNIX Printing System" "21 October 2002" "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 server default printer or +class. +.LP +When specified before the \fI-d\fR, \fI-p\fR, or \fI-x\fR options, +the \fI-E\fR option forces encryption when connecting to the server. +.LP +The first form of the command (\fI-d\fR) 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 with the \fIlpoptions(1)\fR command. +.LP +The second form of the command (\fI-p\fR) configures the named printer. The additional +options are described below. +.LP +The third form of the command (\fI-x\fR) 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 +\-o \fIprotocol=name\fR +.br +Sets the binary communications protocol to use when printing, +None, BCP, or TBCP. The default protocol is None. +.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,@group\fR +\-u \fIdeny:user,user,@group\fR +\-u \fIallow:all\fR +\-u \fIdeny:none\fR +.br +Sets user-level access control on a printer. Names starting with +"@" are interpreted as UNIX groups. 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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpadmin.man 4841 2005-11-15 20:39:31Z mike $". +.\" diff --git a/man/lpc.man b/man/lpc.man new file mode 100644 index 000000000..56547a6ea --- /dev/null +++ b/man/lpc.man @@ -0,0 +1,80 @@ +.\" +.\" "$Id: lpc.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lpc man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpc.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lpinfo.man b/man/lpinfo.man new file mode 100644 index 000000000..f52b29a30 --- /dev/null +++ b/man/lpinfo.man @@ -0,0 +1,60 @@ +.\" +.\" "$Id: lpinfo.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lpinfo man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpinfo.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lpmove.man b/man/lpmove.man new file mode 100644 index 000000000..30bd1d52c --- /dev/null +++ b/man/lpmove.man @@ -0,0 +1,53 @@ +.\" +.\" "$Id: lpmove.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lpmove man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpmove.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lpoptions.man b/man/lpoptions.man new file mode 100644 index 000000000..f1c2b7832 --- /dev/null +++ b/man/lpoptions.man @@ -0,0 +1,128 @@ +.\" +.\" "$Id: lpoptions.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lpoptions man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lpoptions 1 "Common UNIX Printing System" "21 October 2002" "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 +] [ -E ] [ -p +.I dest[/instance] +] -l +.br +.B lpoptions +[ -h +.I server +] [ -E ] [ -o +.I option=value +] ... [ -o +.I option=value +] [ -p +.I dest[/instance] +] -r +.I option +.br +.B lpoptions +[ -h +.I server +] [ -E ] -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 +\-E +.br +Enables encryption when communicating with the CUPS server. +.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 ROOT ACCOUNT OPTIONS +When run by the root user, \fBlpoptions\fR gets and sets default +options and instances for \fIall users\fR in the +/etc/cups/lpoptions file. +.SH COMPATIBILITY +The \fBlpoptions\fR command is unique to CUPS. +.SH FILES +~/.lpoptions - user defaults and instances created by non-root users. +.br +/etc/cups/lpoptions - system-wide defaults and instances created by the root +user. +.SH SEE ALSO +cancel(1), lp(1), +CUPS Software Users Manual, +http://localhost:631/documentation.html +.SH COPYRIGHT +Copyright 1993-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpoptions.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lppasswd.man b/man/lppasswd.man new file mode 100644 index 000000000..88cefedf0 --- /dev/null +++ b/man/lppasswd.man @@ -0,0 +1,61 @@ +.\" +.\" "$Id: lppasswd.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lpadmin man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lppasswd.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lpq.man b/man/lpq.man new file mode 100644 index 000000000..2c668fed1 --- /dev/null +++ b/man/lpq.man @@ -0,0 +1,57 @@ +.\" +.\" "$Id: lpq.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lpq man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpq.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lpr.man b/man/lpr.man new file mode 100644 index 000000000..a66cdfe4d --- /dev/null +++ b/man/lpr.man @@ -0,0 +1,107 @@ +.\" +.\" "$Id: lpr.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lpr man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lpr 1 "Common UNIX Printing System" "16 December 2004" "Easy Software Products" +.SH NAME +lpr \- print files +.SH SYNOPSIS +.B lpr +[ -E ] [ \-P +.I destination +] [ \-U +.I username +] [ \-# +.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 +\-U \fIusername\fR +.br +Sets the user 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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpr.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lprm.man b/man/lprm.man new file mode 100644 index 000000000..b4b02cfe5 --- /dev/null +++ b/man/lprm.man @@ -0,0 +1,54 @@ +.\" +.\" "$Id: lprm.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lprm man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lprm 1 "Common UNIX Printing System" "16 December 2004" "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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lprm.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/lpstat.man b/man/lpstat.man new file mode 100644 index 000000000..6170c012e --- /dev/null +++ b/man/lpstat.man @@ -0,0 +1,140 @@ +.\" +.\" "$Id: lpstat.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" lpstat man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.TH lpstat 1 "Common UNIX Printing System" "3 January 2005" "Easy Software Products" +.SH NAME +lpstat \- print cups status information +.SH SYNOPSIS +.B lpstat +[ -E ] [ -h +.I server +] [ -l ] [ -W +.I which-jobs +] [ -a [ +.I destination(s) +] ] [ -c [ +.I class(es) +] [ -d ] [ -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 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 "-v" options. +.TP 5 +\-t +.br +Shows all status information. This is equivalent to using the "-r", +"-d", "-c", "-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. +.TP 5 +\-W [\fIwhich-jobs\fR] +.br +Specifies which jobs to show, \fIcompleted\fR or +\fInot-completed\fR (the default). This option \fBmust\fR appear +before the \fI-o\fR option and/or any printer names, otherwise +the default (not-completed) value will be used in the request to +the scheduler. +.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" and "-W" options are unique to CUPS. +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: lpstat.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/mantohtml.c b/man/mantohtml.c new file mode 100644 index 000000000..27f073ffc --- /dev/null +++ b/man/mantohtml.c @@ -0,0 +1,642 @@ +/* + * "$Id: mantohtml.c 4867 2005-12-03 15:45:53Z mike $" + * + * Man page to HTML conversion program. + * + * Copyright 2004-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Convert a man page to HTML. + * putc_entity() - Put a single character, using entities as needed. + * strmove() - Move characters within a string. + */ + +/* + * Include necessary headers. + */ + +#include +#include + + +/* + * Local functions... + */ + +static void putc_entity(int ch, FILE *fp); +static void strmove(char *d, const char *s); + + +/* + * 'main()' - Convert a man page to HTML. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + FILE *infile, /* Input file */ + *outfile; /* Output file */ + char line[1024], /* Line from file */ + *lineptr, /* Pointer into line */ + name[1024]; /* Man page name */ + int section, /* Man page section */ + pre, /* Preformatted */ + font, /* Current font */ + blist, /* In a bullet list? */ + list, /* In a list? */ + linenum; /* Current line number */ + const char *post; /* Text to add after the current line */ + static const char /* Start/end tags for fonts */ + * const start_fonts[] = { "", "", "" }, + * const end_fonts[] = { "", "", "" }; + + /* + * Check arguments... + */ + + if (argc > 3) + { + fputs("Usage: mantohtml [filename.man [filename.html]]\n", stderr); + return (1); + } + + /* + * Open files as needed... + */ + + if (argc > 1) + { + if ((infile = fopen(argv[1], "r")) == NULL) + { + perror(argv[1]); + return (1); + } + } + else + infile = stdin; + + if (argc > 2) + { + if ((outfile = fopen(argv[2], "w")) == NULL) + { + perror(argv[2]); + fclose(infile); + return (1); + } + } + else + outfile = stdout; + + /* + * Read from input and write the output... + */ + + fputs("\n" + "\n" + "\n" + "\n" + "\t\n", outfile); + + blist = 0; + font = 0; + list = 0; + linenum = 0; + pre = 0; + post = NULL; + section = -1; + + while (fgets(line, sizeof(line), infile)) + { + linenum ++; + + if (line[0] == '.') + { + /* + * Strip leading whitespace... + */ + + while (line[1] == ' ' || line[1] == '\t') + strmove(line + 1, line + 2); + + /* + * Process man page commands... + */ + + if (!strncmp(line, ".TH ", 4) && section < 0) + { + /* + * Grab man page title... + */ + + sscanf(line + 4, "%s%d", name, §ion); + + fprintf(outfile, + "\t%s\n" + "\n" + "\n" + "

    %s(%d)

    \n" + "%s", + name, name, section, name, section, start_fonts[font]); + } + else if (section < 0) + continue; + else if (!strncmp(line, ".SH ", 4) || !strncmp(line, ".Sh ", 4)) + { + /* + * Grab heading... + */ + + int first = 1; + + fputs(end_fonts[font], outfile); + + if (blist) + { + fputs("\n\n", outfile); + blist = 0; + } + + if (list) + { + if (list == 1) + fputs("\n", outfile); + else if (list) + fputs("\n", outfile); + + fputs("\n", outfile); + list = 0; + } + + if (line[2] == 'H') + fputs("

    ", outfile); + else + fputs("

    ", outfile); + + for (lineptr = line + 4; *lineptr; lineptr ++) + if (*lineptr == '\"') + continue; + else if (*lineptr == ' ') + { + putc_entity(' ', outfile); + + first = 1; + } + else if (*lineptr != '\n') + { + if (first) + putc_entity(toupper(*lineptr), outfile); + else + putc_entity(tolower(*lineptr), outfile); + + first = 0; + } + + if (line[2] == 'H') + fprintf(outfile, "

    \n%s", start_fonts[font]); + else + fprintf(outfile, "\n%s", start_fonts[font]); + } + else if (!strncmp(line, ".LP", 3) || !strncmp(line, ".PP", 3)) + { + /* + * New paragraph... + */ + + fputs(end_fonts[font], outfile); + + if (blist) + { + fputs("\n\n", outfile); + blist = 0; + } + + if (list) + { + if (list == 1) + fputs("\n", outfile); + else if (list) + fputs("\n", outfile); + + fputs("\n", outfile); + list = 0; + } + + fputs("

    ", outfile); + font = 0; + } + else if (!strncmp(line, ".TP ", 4)) + { + /* + * Grab list... + */ + + fputs(end_fonts[font], outfile); + + if (blist) + { + fputs("\n\n", outfile); + blist = 0; + } + + if (!list) + fputs("

    \n", outfile); + else if (list == 1) + fputs("\n", outfile); + else if (list) + fputs("\n", outfile); + + fputs("
    ", outfile); + list = 1; + font = 0; + } + else if (!strncmp(line, ".br", 3)) + { + /* + * Grab line break... + */ + + if (list == 1) + { + fputs("
    \n
    ", outfile); + list = 2; + } + else if (list) + fputs("
    \n
    ", outfile); + else + fputs("
    \n", outfile); + } + else if (!strncmp(line, ".de ", 4)) + { + /* + * Define macro - ignore... + */ + + while (fgets(line, sizeof(line), infile)) + { + linenum ++; + + if (!strncmp(line, "..", 2)) + break; + } + } + else if (!strncmp(line, ".RS", 3)) + { + /* + * Indent... + */ + + fputs("
    \n", outfile); + } + else if (!strncmp(line, ".RE", 3)) + { + /* + * Unindent... + */ + + fputs("
    \n", outfile); + } + else if (!strncmp(line, ".ds ", 4) || !strncmp(line, ".rm ", 4) || + !strncmp(line, ".tr ", 4) || !strncmp(line, ".hy ", 4) || + !strncmp(line, ".IX ", 4) || !strncmp(line, ".PD", 3) || + !strncmp(line, ".Sp", 3)) + { + /* + * Ignore unused commands... + */ + } + else if (!strncmp(line, ".Vb", 3) || !strncmp(line, ".nf", 3)) + { + /* + * Start preformatted... + */ + + pre = 1; + fputs("
    \n", outfile);
    +      }
    +      else if (!strncmp(line, ".Ve", 3) || !strncmp(line, ".fi", 3))
    +      {
    +       /*
    +        * End preformatted...
    +	*/
    +
    +        if (pre)
    +	{
    +          pre = 0;
    +	  fputs("
    \n", outfile); + } + } + else if (!strncmp(line, ".IP \\(bu", 8)) + { + /* + * Bullet list... + */ + + if (blist) + fputs("\n", outfile); + else + { + fputs("
      \n", outfile); + blist = 1; + } + + fputs("
    • ", outfile); + } + else if (!strncmp(line, ".IP ", 4)) + { + /* + * Indented paragraph... + */ + + if (blist) + { + fputs("
    • \n
    \n", outfile); + blist = 0; + } + + fputs("

    ", outfile); + + for (lineptr = line + 4; isspace(*lineptr); lineptr ++); + + if (*lineptr == '\"') + { + strmove(line, lineptr + 1); + + if ((lineptr = strchr(line, '\"')) != NULL) + *lineptr = '\0'; + } + else + { + strmove(line, lineptr); + + if ((lineptr = strchr(line, ' ')) != NULL) + *lineptr = '\0'; + } + + /* + * Process the text as if it was in-line... + */ + + post = "\n
    \n
    "; + goto process_text; + } + else if (!strncmp(line, ".\\}", 3)) + { + /* + * Ignore close block... + */ + } + else if (!strncmp(line, ".ie", 3) || !strncmp(line, ".if", 3) || + !strncmp(line, ".el", 3)) + { + /* + * If/else - ignore... + */ + + if (strchr(line, '{') != NULL) + { + /* + * Skip whole block... + */ + + while (fgets(line, sizeof(line), infile)) + { + linenum ++; + + if (strchr(line, '}') != NULL) + break; + } + } + } +#if 0 + else if (!strncmp(line, ". ", 4)) + { + /* + * Grab ... + */ + } +#endif /* 0 */ + else if (!strncmp(line, ".B ", 3)) + { + /* + * Grab bold text... + */ + + fprintf(outfile, "%s%s%s", end_fonts[font], line + 3, + start_fonts[font]); + } + else if (!strncmp(line, ".I ", 3)) + { + /* + * Grab italic text... + */ + + fprintf(outfile, "%s%s%s", end_fonts[font], line + 3, + start_fonts[font]); + } + else if (strncmp(line, ".\\\"", 3)) + { + /* + * Unknown... + */ + + if ((lineptr = strchr(line, ' ')) != NULL) + *lineptr = '\0'; + else if ((lineptr = strchr(line, '\n')) != NULL) + *lineptr = '\0'; + + fprintf(stderr, "mantohtml: Unknown man page command \'%s\' on line %d!\n", + line, linenum); + } + + /* + * Skip continuation lines... + */ + + lineptr = line + strlen(line) - 2; + if (lineptr >= line && *lineptr == '\\') + { + while (fgets(line, sizeof(line), infile)) + { + linenum ++; + lineptr = line + strlen(line) - 2; + + if (lineptr < line || *lineptr != '\\') + break; + } + } + } + else + { + /* + * Process man page text... + */ + +process_text: + + for (lineptr = line; *lineptr; lineptr ++) + { + if (*lineptr == '\\') + { + lineptr ++; + if (!*lineptr) + break; + else if (isdigit(lineptr[0]) && isdigit(lineptr[1]) && + isdigit(lineptr[2])) + { + fprintf(outfile, "&#%d;", ((lineptr[0] - '0') * 8 + + lineptr[1] - '0') * 8 + + lineptr[2] - '0'); + lineptr += 2; + } + else if (*lineptr == '&') + continue; + else if (*lineptr == 's') + { + while (lineptr[1] == '-' || isdigit(lineptr[1])) + lineptr ++; + } + else if (*lineptr == '*') + { + lineptr += 2; + } + else if (*lineptr != 'f') + putc_entity(*lineptr, outfile); + else + { + lineptr ++; + if (!*lineptr) + break; + else + { + fputs(end_fonts[font], outfile); + + switch (*lineptr) + { + default : /* Regular */ + font = 0; + break; + case 'B' : /* Bold */ + case 'b' : + font = 1; + break; + case 'I' : /* Italic */ + case 'i' : + font = 2; + break; + } + + fputs(start_fonts[font], outfile); + } + } + } + else + putc_entity(*lineptr, outfile); + } + + if (post) + { + fputs(post, outfile); + post = NULL; + } + } + } + + fprintf(outfile, "%s\n", end_fonts[font]); + + if (blist) + { + fputs("\n\n", outfile); + blist = 0; + } + + if (list) + { + if (list == 1) + fputs("\n", outfile); + else if (list) + fputs("

    \n", outfile); + + fputs("
    \n", outfile); + list = 0; + } + + fputs("\n" + "\n", outfile); + + /* + * Close files... + */ + + if (infile != stdin) + fclose(infile); + + if (outfile != stdout) + fclose(outfile); + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'putc_entity()' - Put a single character, using entities as needed. + */ + +static void +putc_entity(int ch, /* I - Character */ + FILE *fp) /* I - File */ +{ + if (ch == '&') + fputs("&", fp); + else if (ch == '<') + fputs("<", fp); + else + putc(ch, fp); +} + + +/* + * 'strmove()' - Move characters within a string. + */ + +static void +strmove(char *d, /* I - Destination */ + const char *s) /* I - Source */ +{ + while (*s) + *d++ = *s++; + + *d = '\0'; +} + + +/* + * End of "$Id: mantohtml.c 4867 2005-12-03 15:45:53Z mike $". + */ diff --git a/man/mime.convs.man b/man/mime.convs.man new file mode 100644 index 000000000..033a06e6f --- /dev/null +++ b/man/mime.convs.man @@ -0,0 +1,54 @@ +.\" +.\" "$Id: mime.convs.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" mime.convs man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: mime.convs.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/mime.types.man b/man/mime.types.man new file mode 100644 index 000000000..cc97701a3 --- /dev/null +++ b/man/mime.types.man @@ -0,0 +1,102 @@ +.\" +.\" "$Id: mime.types.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" mime.types man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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 +istring(offset,"string") +.br +True if a case-insensitive comparison of the bytes is identical +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: mime.types.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/man/printers.conf.man b/man/printers.conf.man new file mode 100644 index 000000000..ff103d7f5 --- /dev/null +++ b/man/printers.conf.man @@ -0,0 +1,73 @@ +.\" +.\" "$Id: printers.conf.man 4493 2005-02-18 02:09:53Z mike $" +.\" +.\" printers.conf man page for the Common UNIX Printing System (CUPS). +.\" +.\" Copyright 1997-2005 by Easy Software Products. +.\" +.\" These coded instructions, statements, and computer programs are the +.\" property of Easy Software Products and are protected by Federal +.\" copyright law. Distribution and use rights are outlined in the file +.\" "LICENSE.txt" which should have been included with this file. If this +.\" file is missing or damaged please contact Easy Software Products +.\" at: +.\" +.\" Attn: CUPS Licensing Information +.\" Easy Software Products +.\" 44141 Airport View Drive, Suite 204 +.\" Hollywood, Maryland 20636 USA +.\" +.\" Voice: (301) 373-9600 +.\" EMail: cups-info@cups.org +.\" WWW: http://www.cups.org +.\" +.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 + ... +.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-2005 by Easy Software Products, All Rights Reserved. +.\" +.\" End of "$Id: printers.conf.man 4493 2005-02-18 02:09:53Z mike $". +.\" diff --git a/notifier/Dependencies b/notifier/Dependencies new file mode 100644 index 000000000..f13e6eb1a --- /dev/null +++ b/notifier/Dependencies @@ -0,0 +1,8 @@ +# DO NOT DELETE + +mailto.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +mailto.o: ../cups/ppd.h ../cups/file.h ../cups/language.h ../cups/array.h +mailto.o: ../cups/string.h ../config.h +testnotify.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +testnotify.o: ../cups/ppd.h ../cups/file.h ../cups/language.h ../cups/array.h +testnotify.o: ../cups/string.h ../config.h diff --git a/notifier/Makefile b/notifier/Makefile new file mode 100644 index 000000000..f7c139f44 --- /dev/null +++ b/notifier/Makefile @@ -0,0 +1,91 @@ +# +# "$Id: Makefile 4834 2005-11-12 21:55:57Z mike $" +# +# Notifier makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + + +TARGETS = mailto testnotify +OBJS = mailto.o testnotify.o + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) + + +# +# Install all targets... +# + +install: + $(INSTALL_DIR) $(SERVERBIN)/notifier + for file in $(TARGETS); do \ + $(INSTALL_BIN) $$file $(SERVERBIN)/notifier; \ + done + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1 + + +# +# mailto +# + +mailto: mailto.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o mailto mailto.o $(LIBS) + + +# +# testnotify +# + +testnotify: testnotify.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o testnotify testnotify.o $(LIBS) + + +$(OBJS): ../Makedefs + +include Dependencies + + +# +# End of "$Id: Makefile 4834 2005-11-12 21:55:57Z mike $". +# diff --git a/notifier/mailto.c b/notifier/mailto.c new file mode 100644 index 000000000..33ec692e9 --- /dev/null +++ b/notifier/mailto.c @@ -0,0 +1,50 @@ +/* + * "$Id: mailto.c 4829 2005-11-12 03:15:10Z mike $" + * + * "mailto" notifier for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + + +/* + * 'main()' - Main entry for the mailto notifier. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ +} + + +/* + * End of "$Id: mailto.c 4829 2005-11-12 03:15:10Z mike $". + */ diff --git a/notifier/testnotify.c b/notifier/testnotify.c new file mode 100644 index 000000000..d334a4a9e --- /dev/null +++ b/notifier/testnotify.c @@ -0,0 +1,285 @@ +/* + * "$Id: testnotify.c 4829 2005-11-12 03:15:10Z mike $" + * + * Test notifier for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for the test notifier. + * print_attributes() - Print the attributes in a request... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + + +/* + * Local functions... + */ + +void print_attributes(ipp_t *ipp, int indent); + + +/* + * 'main()' - Main entry for the test notifier. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i; /* Looping var */ + ipp_t *event; /* Event from scheduler */ + ipp_state_t state; /* IPP event state */ + + + setbuf(stderr, NULL); + + fprintf(stderr, "DEBUG: argc=%d\n", argc); + for (i = 0; i < argc; i ++) + fprintf(stderr, "DEBUG: argv[%d]=\"%s\"\n", i, argv[i]); + + for (;;) + { + event = ippNew(); + while ((state = ippReadFile(0, event)) != IPP_DATA) + { + if (state <= IPP_IDLE) + break; + } + + if (state == IPP_ERROR) + fputs("DEBUG: ippReadFile() returned IPP_ERROR!\n", stderr); + + if (state <= IPP_IDLE) + { + ippDelete(event); + return (0); + } + + print_attributes(event, 4); + ippDelete(event); + } +} + + +/* + * 'print_attributes()' - Print the attributes in a request... + */ + +void +print_attributes(ipp_t *ipp, /* I - IPP request */ + int indent) /* I - Indentation */ +{ + int i; /* Looping var */ + ipp_tag_t group; /* Current group */ + ipp_attribute_t *attr; /* Current attribute */ + ipp_value_t *val; /* Current value */ + static const char * const tags[] = /* Value/group tag strings */ + { + "reserved-00", + "operation-attributes-tag", + "job-attributes-tag", + "end-of-attributes-tag", + "printer-attributes-tag", + "unsupported-attributes-tag", + "subscription-attributes-tag", + "event-attributes-tag", + "reserved-08", + "reserved-09", + "reserved-0A", + "reserved-0B", + "reserved-0C", + "reserved-0D", + "reserved-0E", + "reserved-0F", + "unsupported", + "default", + "unknown", + "no-value", + "reserved-14", + "not-settable", + "delete-attr", + "admin-define", + "reserved-18", + "reserved-19", + "reserved-1A", + "reserved-1B", + "reserved-1C", + "reserved-1D", + "reserved-1E", + "reserved-1F", + "reserved-20", + "integer", + "boolean", + "enum", + "reserved-24", + "reserved-25", + "reserved-26", + "reserved-27", + "reserved-28", + "reserved-29", + "reserved-2a", + "reserved-2b", + "reserved-2c", + "reserved-2d", + "reserved-2e", + "reserved-2f", + "octetString", + "dateTime", + "resolution", + "rangeOfInteger", + "begCollection", + "textWithLanguage", + "nameWithLanguage", + "endCollection", + "reserved-38", + "reserved-39", + "reserved-3a", + "reserved-3b", + "reserved-3c", + "reserved-3d", + "reserved-3e", + "reserved-3f", + "reserved-40", + "textWithoutLanguage", + "nameWithoutLanguage", + "reserved-43", + "keyword", + "uri", + "uriScheme", + "charset", + "naturalLanguage", + "mimeMediaType", + "memberName" + }; + + + for (group = IPP_TAG_ZERO, attr = ipp->attrs; attr; attr = attr->next) + { + if ((attr->group_tag == IPP_TAG_ZERO && indent <= 8) || !attr->name) + { + group = IPP_TAG_ZERO; + fputc('\n', stderr); + continue; + } + + if (group != attr->group_tag) + { + group = attr->group_tag; + + fprintf(stderr, "DEBUG: %*s%s:\n\n", indent - 4, "", tags[group]); + } + + fprintf(stderr, "DEBUG: %*s%s (", indent, "", attr->name); + if (attr->num_values > 1) + fputs("1setOf ", stderr); + fprintf(stderr, "%s):", tags[attr->value_tag]); + + switch (attr->value_tag) + { + case IPP_TAG_ENUM : + case IPP_TAG_INTEGER : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + fprintf(stderr, " %d", val->integer); + fputc('\n', stderr); + break; + + case IPP_TAG_BOOLEAN : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + fprintf(stderr, " %s", val->boolean ? "true" : "false"); + fputc('\n', stderr); + break; + + case IPP_TAG_RANGE : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + fprintf(stderr, " %d-%d", val->range.lower, val->range.upper); + fputc('\n', stderr); + break; + + case IPP_TAG_DATE : + { + time_t vtime; /* Date/Time value */ + struct tm *vdate; /* Date info */ + char vstring[256]; /* Formatted time */ + + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + { + vtime = ippDateToTime(val->date); + vdate = localtime(&vtime); + strftime(vstring, sizeof(vstring), "%c", vdate); + fprintf(stderr, " (%s)", vstring); + } + } + fputc('\n', stderr); + break; + + case IPP_TAG_RESOLUTION : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + fprintf(stderr, " %dx%d%s", val->resolution.xres, + val->resolution.yres, + val->resolution.units == IPP_RES_PER_INCH ? "dpi" : "dpc"); + fputc('\n', stderr); + break; + + case IPP_TAG_STRING : + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + 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 : + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + fprintf(stderr, " \"%s\"", val->string.text); + fputc('\n', stderr); + break; + + case IPP_TAG_BEGIN_COLLECTION : + fputc('\n', stderr); + + for (i = 0, val = attr->values; i < attr->num_values; i ++, val ++) + { + if (i) + fputc('\n', stderr); + print_attributes(val->collection, indent + 4); + } + break; + + default : + fprintf(stderr, "UNKNOWN (%d values)\n", attr->num_values); + break; + } + } +} + + +/* + * End of "$Id: testnotify.c 4829 2005-11-12 03:15:10Z mike $". + */ diff --git a/packaging/LICENSE.rtf b/packaging/LICENSE.rtf new file mode 100644 index 000000000..c8d9fd248 --- /dev/null +++ b/packaging/LICENSE.rtf @@ -0,0 +1,462 @@ +{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf210 +{\fonttbl\f0\froman\fcharset77 Times-Bold;\f1\froman\fcharset77 Times-Roman;\f2\fnil\fcharset77 LucidaGrande; +\f3\fmodern\fcharset77 Courier;\f4\fnil\fcharset77 LucidaGrande-Bold;\f5\fmodern\fcharset77 Courier-Oblique; +} +{\colortbl;\red255\green255\blue255;\red0\green0\blue238;} +{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid1} +{\list\listtemplateid2\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listlevel\levelnfc0\levelnfcn0\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid1\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid2} +{\list\listtemplateid3\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid3} +{\list\listtemplateid4\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listlevel\levelnfc0\levelnfcn0\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid1\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid4} +{\list\listtemplateid5\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid5} +{\list\listtemplateid6\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid6} +{\list\listtemplateid7\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid7} +{\list\listtemplateid8\listhybrid{\listlevel\levelnfc0\levelnfcn0\leveljc2\leveljcn2\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{decimal\}.}{\leveltext\leveltemplateid0\'02\'05.;}{\levelnumbers\'01;}}{\listname ;}\listid8}} +{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}{\listoverride\listid3\listoverridecount0\ls3}{\listoverride\listid4\listoverridecount0\ls4}{\listoverride\listid5\listoverridecount0\ls5}{\listoverride\listid6\listoverridecount0\ls6}{\listoverride\listid7\listoverridecount0\ls7}{\listoverride\listid8\listoverridecount0\ls8}} +{\info +{\title Software License Agreement - Common UNIX Printing System}}\vieww15960\viewh16860\viewkind0 +\deftab720 +\pard\pardeftab720\sa280\qc + +\f0\b\fs36 \cf0 Common UNIX Printing System License Agreement\ +\pard\pardeftab720\sa240\qc + +\f1\b0\fs24 \cf0 Copyright 1997-2006 by Easy Software Products +\f2 \uc0\u8232 +\f1 44141 AIRPORT VIEW DR STE 204 +\f2 \uc0\u8232 +\f1 HOLLYWOOD, MARYLAND 20636 USA +\f2 \uc0\u8232 \u8232 +\f1 Voice: +1.301.373.9600 +\f2 \uc0\u8232 +\f1 Email: {\field{\*\fldinst{HYPERLINK "mailto:cups-info@cups.org"}}{\fldrslt \cf2 \ul \ulc2 cups-info@cups.org}} +\f2 \uc0\u8232 +\f1 WWW: {\field{\*\fldinst{HYPERLINK "http://www.cups.org/"}}{\fldrslt \cf2 \ul \ulc2 http://www.cups.org}}\ +\pard\pardeftab720\sa280\ql\qnatural + +\f0\b\fs28 \cf0 Introduction\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0\fs24 \cf0 The Common UNIX Printing System +\fs20 \super TM +\fs24 \nosupersub , ("CUPS +\fs20 \super TM +\fs24 \nosupersub "), is provided under the GNU General Public License ("GPL") and GNU Library General Public License ("LGPL"), Version 2, with exceptions for Apple operating systems and the OpenSSL toolkit. A copy of the exceptions and 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 "cups" include directory and library files in the binary distributions. The GNU GPL applies to the remainder of the CUPS distribution, including the "pdftops" filter which is based upon Xpdf and the CUPS imaging library.\ +For those not familiar with the GNU GPL, the license basically allows you to:\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls1\ilvl0\cf0 {\listtext \'a5 }Use the CUPS software at no charge.\ +{\listtext \'a5 }Distribute verbatim copies of the software in source or binary form.\ +{\listtext \'a5 }Sell verbatim copies of the software for a media fee, or sell support for the software.\ +{\listtext \'a5 }Distribute or sell printer drivers and filters that use CUPS so long as source code is made available under the GPL.\ +\pard\pardeftab720\sa240\ql\qnatural +\cf0 What this license +\f0\b does not +\f1\b0 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 only exceptions to this are the portions of the CUPS software covered by the Apple operating system license exceptions outlined later in this license agreement.\ +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.\ +\pard\pardeftab720\sa280\ql\qnatural + +\f0\b\fs28 \cf0 License Exceptions\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0\fs24 \cf0 In addition, as the copyright holder of CUPS, Easy Software Products grants the following special exceptions:\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls2\ilvl0 +\f0\b \cf0 {\listtext 1. }Apple Operating System Development License Exception +\f1\b0 ;\ +\pard\tx940\tx1440\pardeftab720\li1440\fi-1440\ql\qnatural +\ls2\ilvl1\cf0 {\listtext 1. }Software that is developed by any person or entity for an Apple Operating System ("Apple OS-Developed Software"), including but not limited to Apple and third party printer drivers, filters, and backends for an Apple Operating System, that is linked to the CUPS imaging library or based on any sample filters or backends provided with CUPS shall not be considered to be a derivative work or collective work based on the CUPS program and is exempt from the mandatory source code release clauses of the GNU GPL. You may therefore distribute linked combinations of the CUPS imaging library with Apple OS-Developed Software without releasing the source code of the Apple OS-Developed Software. You may also use sample filters and backends provided with CUPS to develop Apple OS-Developed Software without releasing the source code of the Apple OS-Developed Software.\ +{\listtext 2. }An Apple Operating System means any operating system software developed and/or marketed by Apple Computer, Inc., including but not limited to all existing releases and versions of Apple's Darwin, Mac OS X, and Mac OS X Server products and all follow-on releases and future versions thereof.\ +{\listtext 3. }This exception is only available for Apple OS-Developed Software and does not apply to software that is distributed for use on other operating systems.\ +{\listtext 4. }All CUPS software that falls under this license exception have the following text at the top of each source file:\ +{\listtext 5. }This file is subject to the Apple OS-Developed Software exception.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls2\ilvl0 +\f0\b \cf0 {\listtext 2. }OpenSSL Toolkit License Exception +\f1\b0 ;\ +\pard\tx940\tx1440\pardeftab720\li1440\fi-1440\ql\qnatural +\ls2\ilvl1\cf0 {\listtext 1. }Easy Software Products explicitly allows the compilation and distribution of the CUPS software with the OpenSSL Toolkit.\ +\pard\pardeftab720\sa240\ql\qnatural +\cf0 No developer is required to provide these exceptions in a derived work.\ +\pard\pardeftab720\sa280\ql\qnatural + +\f0\b\fs28 \cf0 Trademarks\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0\fs24 \cf0 Easy Software Products has trademarked the Common UNIX Printing System, CUPS, and CUPS logo. You may use these names and logos in any direct port or binary distribution of CUPS. Please contact Easy Software Products for written permission to use them in derivative products. 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.\ +\pard\pardeftab720\sa280\ql\qnatural + +\f0\b\fs28 \cf0 Binary Distribution Rights\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0\fs24 \cf0 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 "pdftops" filter that is based on the Xpdf software. For binary distribution licensing of this software, please contact:\ +\pard\pardeftab720\ql\qnatural +\cf0 Derek B. Noonburg\ +Email: {\field{\*\fldinst{HYPERLINK "mailto:derekn@foolabs.com"}}{\fldrslt \cf2 \ul \ulc2 derekn@foolabs.com}}\ +WWW: {\field{\*\fldinst{HYPERLINK "http://www.foolabs.com/xpdf/"}}{\fldrslt \cf2 \ul \ulc2 http://www.foolabs.com/xpdf/}}\ +\pard\pardeftab720\sa280\ql\qnatural + +\f0\b\fs28 \cf0 Support\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0\fs24 \cf0 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:\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls3\ilvl0{\field{\*\fldinst{HYPERLINK "http://www.easysw.com/"}}{\fldrslt +\f3 \cf2 \ul \ulc2 {\listtext \'a5 }http://www.easysw.com/}} +\f3 \ +\pard\pardeftab720\sa280\ql\qnatural + +\f0\b\fs36 \cf0 GNU GENERAL PUBLIC LICENSE\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0\fs24 \cf0 Version 2, June 1991\ +\pard\pardeftab720\ql\qnatural + +\f3 \cf0 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.\ +\pard\pardeftab720\sa300\ql\qnatural + +\f0\b \cf0 Preamble\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0 \cf0 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.\ +\pard\pardeftab720\sa300\ql\qnatural + +\f0\b \cf0 GNU GENERAL PUBLIC LICENSE +\f4 \uc0\u8232 +\f0 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls4\ilvl0 +\f1\b0 \cf0 {\listtext 1. }This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 2. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 3. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 4. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 5. }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:\ +\pard\tx940\tx1440\pardeftab720\li1440\fi-1440\ql\qnatural +\ls4\ilvl1\cf0 {\listtext 1. }You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.\ +{\listtext 2. }You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.\ +{\listtext 3. }if the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 6. }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.\ +{\listtext 7. }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.\ +{\listtext 8. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 9. }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:\ +\pard\tx940\tx1440\pardeftab720\li1440\fi-1440\ql\qnatural +\ls4\ilvl1\cf0 {\listtext 1. }Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\ +{\listtext 2. }Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\ +{\listtext 3. }Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 10. }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.\ +{\listtext 11. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 12. }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.\ +{\listtext 13. }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.\ +{\listtext 14. }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.\ +{\listtext 15. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 16. }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.\ +{\listtext 17. }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.\ +{\listtext 18. }This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 19. }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.\ +{\listtext 20. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 21. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls4\ilvl0\cf0 {\listtext 22. }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.\ +\pard\pardeftab720\sa300\ql\qnatural + +\f0\b \cf0 NO WARRANTY\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls5\ilvl0 +\f1\b0 \cf0 {\listtext 1. }BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\ +{\listtext 2. }IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\ +\pard\pardeftab720\sa300\ql\qnatural + +\f0\b \cf0 END OF TERMS AND CONDITIONS\ +How to Apply These Terms to Your New Programs\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0 \cf0 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.\ +\pard\pardeftab720\ql\qnatural + +\f5\i \cf0 one line to give the program's name and an idea of what it does. +\f3\i0 \ +Copyright (C) +\f5\i yyyy +\f3\i0 +\f5\i name of author +\f3\i0 \ +\ +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.\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1 \cf0 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:\ +\pard\pardeftab720\ql\qnatural + +\f3 \cf0 Gnomovision version 69, Copyright (C) +\f5\i year +\f3\i0 +\f5\i name of author +\f3\i0 \ +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.\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1 \cf0 The hypothetical commands +\f3 `show w' +\f1 and +\f3 `show c' +\f1 should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than +\f3 `show w' +\f1 and +\f3 `show c' +\f1 ; 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:\ +\pard\pardeftab720\ql\qnatural + +\f3 \cf0 Yoyodyne, Inc., hereby disclaims all copyright\ +interest in the program `Gnomovision'\ +(which makes passes at compilers) written \ +by James Hacker.\ +\ +\pard\pardeftab720\ql\qnatural + +\f5\i \cf0 signature of Ty Coon +\f3\i0 , 1 April 1989\ +Ty Coon, President of Vice\ +\pard\pardeftab720\sa280\ql\qnatural + +\f0\b\fs36 \cf0 GNU LIBRARY GENERAL PUBLIC LICENSE\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0\fs24 \cf0 Version 2, June 1991\ +\pard\pardeftab720\ql\qnatural + +\f3 \cf0 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.]\ +\pard\pardeftab720\sa300\ql\qnatural + +\f0\b \cf0 Preamble\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0 \cf0 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.\ +\pard\pardeftab720\sa300\ql\qnatural + +\f0\b \cf0 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\ +\pard\pardeftab720\sa240\ql\qnatural +\cf0 0. +\f1\b0 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.\ + +\f0\b 1. +\f1\b0 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.\ + +\f0\b 2. +\f1\b0 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:\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls6\ilvl0\cf0 {\listtext 1. }The modified work must itself be a software library.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls6\ilvl0\cf0 {\listtext 2. }\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls6\ilvl0\cf0 {\listtext 3. }You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls6\ilvl0\cf0 {\listtext 4. }\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls6\ilvl0\cf0 {\listtext 5. }You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls6\ilvl0\cf0 {\listtext 6. }\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls6\ilvl0\cf0 {\listtext 7. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls6\ilvl0\cf0 {\listtext 8. }(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.)\ +\pard\pardeftab720\sa240\ql\qnatural +\cf0 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.\ +\pard\pardeftab720\sa240\ql\qnatural + +\f0\b \cf0 3. +\f1\b0 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.\ + +\f0\b 4. +\f1\b0 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.\ + +\f0\b 5. +\f1\b0 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.\ + +\f0\b 6. +\f1\b0 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:\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls7\ilvl0\cf0 {\listtext 1. }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.)\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls7\ilvl0\cf0 {\listtext 2. }\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls7\ilvl0\cf0 {\listtext 3. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls7\ilvl0\cf0 {\listtext 4. }\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls7\ilvl0\cf0 {\listtext 5. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls7\ilvl0\cf0 {\listtext 6. }\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls7\ilvl0\cf0 {\listtext 7. }Verify that the user has already received a copy of these materials or that you have already sent this user a copy.\ +\pard\pardeftab720\sa240\ql\qnatural +\cf0 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.\ +\pard\pardeftab720\sa240\ql\qnatural + +\f0\b \cf0 7. +\f1\b0 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:\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls8\ilvl0\cf0 {\listtext 1. }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.\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\sa240\ql\qnatural +\ls8\ilvl0\cf0 {\listtext 2. }\ +\pard\tx220\tx720\pardeftab720\li720\fi-720\ql\qnatural +\ls8\ilvl0\cf0 {\listtext 3. }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.\ +\pard\pardeftab720\sa240\ql\qnatural + +\f0\b \cf0 8. +\f1\b0 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.\ + +\f0\b 9. +\f1\b0 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.\ + +\f0\b 10. +\f1\b0 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.\ + +\f0\b 11. +\f1\b0 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.\ + +\f0\b 12. +\f1\b0 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.\ + +\f0\b 13. +\f1\b0 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.\ + +\f0\b 14. +\f1\b0 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.\ + +\f0\b NO WARRANTY +\f1\b0 \ + +\f0\b 15. +\f1\b0 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.\ + +\f0\b 16. +\f1\b0 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.\ +\pard\pardeftab720\sa300\ql\qnatural + +\f0\b \cf0 END OF TERMS AND CONDITIONS\ +How to Apply These Terms to Your New Libraries\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1\b0 \cf0 If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License).\ +To apply these terms, attach the following notices to the library. 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.\ +\pard\pardeftab720\ql\qnatural + +\f5\i \cf0 one line to give the library's name and an idea of what it does. +\f3\i0 \ +Copyright (C) +\f5\i year +\f3\i0 +\f5\i name of author +\f3\i0 \ +\ +This library is free software; you can redistribute it and/or\ +modify it under the terms of the GNU Lesser General Public\ +License as published by the Free Software Foundation; either\ +version 2.1 of the License, or (at your option) any later version.\ +\ +This library 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\ +Lesser General Public License for more details.\ +\ +You should have received a copy of the GNU Lesser General Public\ +License along with this library; if not, write to the Free Software\ +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1 \cf0 Also add information on how to contact you by electronic and paper mail.\ +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names:\ +\pard\pardeftab720\ql\qnatural + +\f3 \cf0 Yoyodyne, Inc., hereby disclaims all copyright interest in\ +the library `Frob' (a library for tweaking knobs) written\ +by James Random Hacker.\ +\ +\pard\pardeftab720\ql\qnatural + +\f5\i \cf0 signature of Ty Coon +\f3\i0 , 1 April 1990\ +Ty Coon, President of Vice\ +\pard\pardeftab720\sa240\ql\qnatural + +\f1 \cf0 That's all there is to it!\ +} diff --git a/packaging/WELCOME.rtf b/packaging/WELCOME.rtf new file mode 100644 index 000000000..e7004fdb8 --- /dev/null +++ b/packaging/WELCOME.rtf @@ -0,0 +1,24 @@ +{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf110 +{\fonttbl\f0\fswiss\fcharset77 Helvetica;\f1\fswiss\fcharset77 Helvetica-Bold;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww9000\viewh8400\viewkind0 +\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural\pardirnatural + +\f0\fs24 \cf0 This program installs a pre-release version of CUPS 1.2 and replaces the CUPS 1.1.x software that is included with MacOS X.\ +\ + +\f1\b WARNING\ + +\f0\b0 \ +This is pre-release software and should not be used in production environments. Because MacOS X packages cannot be uninstalled, you will need to reinstall MacOS X to revert to the original CUPS 1.1.x software.\ +\ +Please report all problems using the Bugs & Features page on the CUPS home page:\ +\ + http://www.cups.org/str.php\ +\ + +\f1\b NO WARRANTY\ + +\f0\b0 \ +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.\ +} \ No newline at end of file diff --git a/packaging/cups-desc.plist.in b/packaging/cups-desc.plist.in new file mode 100644 index 000000000..13f2b0145 --- /dev/null +++ b/packaging/cups-desc.plist.in @@ -0,0 +1,15 @@ + + + + + IFPkgDescriptionDeleteWarning + + IFPkgDescriptionDescription + The Common UNIX Printing System provides a portable printing layer for UNIX(r) operating systems. + + IFPkgDescriptionTitle + Common UNIX Printing System + IFPkgDescriptionVersion + @CUPS_RELEASE@ + + diff --git a/packaging/cups-info.plist.in b/packaging/cups-info.plist.in new file mode 100644 index 000000000..f95cf8c30 --- /dev/null +++ b/packaging/cups-info.plist.in @@ -0,0 +1,24 @@ + + + + + IFPkgFlagAuthorizationAction + RootAuthorization + IFPkgFlagBackgroundAlignment + bottomleft + IFPkgFlagBackgroundScaling + none + IFPkgFormatVersion + 0.1 + CFBundleIdentifier + org.cups.cups + CFBundleName + Common UNIX Printing System + CFBundleGetInfoString + Common UNIX Printing System, @CUPS_VERSION@ + CFBundleShortVersionString + @CUPS_RELEASE@ + IFPkgFlagAllowBackRev + + + diff --git a/packaging/cups.list.in b/packaging/cups.list.in new file mode 100644 index 000000000..c2d3656bf --- /dev/null +++ b/packaging/cups.list.in @@ -0,0 +1,453 @@ +# +# "$Id: cups.list.in 4903 2006-01-10 20:02:46Z mike $" +# +# ESP Package Manager (EPM) file list for the Common UNIX Printing +# System (CUPS). +# +# Copyright 1997-2006 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +# Product information +%product Common UNIX Printing System +%copyright 1993-2006 by Easy Software Products, All Rights Reserved. +%vendor Easy Software Products +%license LICENSE.txt +%readme README.txt +%version @CUPS_VERSION@ +%description The Common UNIX Printing System provides a portable printing +%description layer for UNIX(r) operating systems. It has been developed by +%description Easy Software Products to promote a standard printing solution +%description for all UNIX vendors and users. CUPS provides the System V and +%description Berkeley command-line interfaces. + +%format rpm +%provides cups 1:@CUPS_VERSION@ +%provides lpd, lpr, LPRng +%replaces lpd, lpr, LPRng + +%format deb +%provides cupsys +%provides cupsys-client +%provides cupsys-bsd + +%format pkg +%replaces SUNWlpmsg LP Alerts +%replaces SUNWlpr LP Print Service, (Root) +%replaces SUNWlps LP Print Service - Server, (Usr) +%replaces SUNWlpu LP Print Service - Client, (Usr) +%replaces SUNWpsu LP Print Server, (Usr) +%replaces SUNWpsr LP Print Server, (Root) +%replaces SUNWpcu LP Print Client, (Usr) +%replaces SUNWpcr LP Print Client, (Root) +%replaces SUNWppm +%replaces SUNWmp +%replaces SUNWscplp SunOS Print Compatibility + +%format inst +%replaces patch*.print_*.* 0 0 1289999999 1289999999 +%replaces maint*.print_*.* 0 0 1289999999 1289999999 +%replaces print 0 0 1289999999 1289999999 +%replaces fw_cups 0 0 1289999999 1289999999 +%incompat patch*.print_*.* 0 0 1289999999 1289999999 +%incompat maint*.print_*.* 0 0 1289999999 1289999999 +%incompat print 0 0 1289999999 1289999999 +%incompat fw_cups 0 0 1289999999 1289999999 + +%format all + +%subpackage libs +%description Common UNIX Printing System - shared libraries +%format rpm +%provides cups-libs 1:@CUPS_VERSION@ +%format deb +%provides libcups1 +%provides libcupsys2 +%provides libcupsys2-gnutls10 +%provides libcupsimage2 +%format all + +%subpackage devel +%description Common UNIX Printing System - development environment +%format rpm +%provides cups-devel 1:@CUPS_VERSION@ +%format deb +%provides libcupsys2-dev +%provides libcupsimage2-dev +%format all + +%subpackage lpd +%description Common UNIX Printing System - LPD support +%format rpm +%provides cups-lpd 1:@CUPS_VERSION@ +%format all + +%subpackage + + +# +# 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@ +$CACHEDIR=@CUPS_CACHEDIR@ +$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@ +$STATEDIR=@CUPS_STATEDIR@ + +$CUPS_USER=@CUPS_USER@ +$CUPS_GROUP=@CUPS_GROUP@ + +$MAN1EXT=@MAN1EXT@ +$MAN5EXT=@MAN5EXT@ +$MAN8EXT=@MAN8EXT@ +$MAN8DIR=@MAN8DIR@ + +$DSOLIBS=@DSOLIBS@ + +# 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... +%subpackage libs +%system linux +%postinstall ldconfig +%system all +%subpackage + +# Server programs +%system all +# Server files +f 0755 root sys $SBINDIR/cupsd scheduler/cupsd + +d 0755 root sys $SERVERBIN - +d 0755 root sys $SERVERBIN/backend - +f 0755 root sys $SERVERBIN/backend/ipp backend/ipp +l 0755 root sys $SERVERBIN/backend/http ipp +f 0755 root sys $SERVERBIN/backend/lpd backend/lpd +f 0755 root sys $SERVERBIN/backend/parallel backend/parallel +f 0755 root sys $SERVERBIN/backend/scsi backend/scsi +f 0755 root sys $SERVERBIN/backend/serial backend/serial +f 0755 root sys $SERVERBIN/backend/socket backend/socket +f 0755 root sys $SERVERBIN/backend/usb backend/usb +d 0755 root sys $SERVERBIN/cgi-bin - +f 0755 root sys $SERVERBIN/cgi-bin/admin.cgi cgi-bin/admin.cgi +f 0755 root sys $SERVERBIN/cgi-bin/classes.cgi cgi-bin/classes.cgi +f 0755 root sys $SERVERBIN/cgi-bin/help.cgi cgi-bin/help.cgi +f 0755 root sys $SERVERBIN/cgi-bin/jobs.cgi cgi-bin/jobs.cgi +f 0755 root sys $SERVERBIN/cgi-bin/printers.cgi cgi-bin/printers.cgi +d 0755 root sys $SERVERBIN/daemon - +f 0755 root sys $SERVERBIN/daemon/cups-deviced scheduler/cups-deviced +f 0755 root sys $SERVERBIN/daemon/cups-driverd scheduler/cups-driverd +f 0755 root sys $SERVERBIN/daemon/cups-polld scheduler/cups-polld +d 0755 root sys $SERVERBIN/driver - +d 0755 root sys $SERVERBIN/filter - +f 0755 root sys $SERVERBIN/filter/gziptoany filter/gziptoany +f 0755 root sys $SERVERBIN/filter/hpgltops filter/hpgltops +f 0755 root sys $SERVERBIN/filter/imagetops filter/imagetops +f 0755 root sys $SERVERBIN/filter/imagetoraster filter/imagetoraster +f 0755 root sys $SERVERBIN/filter/pdftops pdftops/pdftops +f 0755 root sys $SERVERBIN/filter/pstops filter/pstops +f 0755 root sys $SERVERBIN/filter/rastertolabel filter/rastertolabel +l 0755 root sys $SERVERBIN/filter/rastertodymo rastertolabel +f 0755 root sys $SERVERBIN/filter/rastertoepson filter/rastertoepson +f 0755 root sys $SERVERBIN/filter/rastertohp filter/rastertohp +f 0755 root sys $SERVERBIN/filter/texttops filter/texttops +d 0755 root sys $SERVERBIN/notifier - +f 0755 root sys $SERVERBIN/notifier/mailto notifier/mailto + +%subpackage lpd +d 0755 root sys $SERVERBIN/daemon - +f 0755 root sys $SERVERBIN/daemon/cups-lpd scheduler/cups-lpd +%subpackage + +# Admin commands +d 0755 root sys $BINDIR - +l 0755 root sys $BINDIR/enable $SBINDIR/accept +l 0755 root sys $LIBDIR/accept $SBINDIR/accept +d 0755 root sys $SBINDIR - +l 0755 root sys $SBINDIR/cupsdisable accept +l 0755 root sys $SBINDIR/cupsenable accept +l 0755 root sys $BINDIR/disable $SBINDIR/accept +d 0755 root sys $LIBDIR - +l 0755 root sys $LIBDIR/lpadmin $SBINDIR/lpadmin +l 0755 root sys $LIBDIR/reject accept +f 0755 root sys $SBINDIR/accept systemv/accept +f 0755 root sys $SBINDIR/cupsaddsmb systemv/cupsaddsmb +f 0755 root sys $SBINDIR/lpadmin systemv/lpadmin +f 0755 root sys $SBINDIR/lpc berkeley/lpc +f 0755 root sys $SBINDIR/lpinfo systemv/lpinfo +f 0755 root sys $SBINDIR/lpmove systemv/lpmove +l 0755 root sys $SBINDIR/reject accept + +%system irix +l 0755 root sys /usr/etc/lpc $SBINDIR/lpc +%system all + +# User commands +d 0755 root sys $BINDIR - +f 0755 root sys $BINDIR/cancel systemv/cancel +f 0755 root sys $BINDIR/cupstestppd systemv/cupstestppd +f 0755 root sys $BINDIR/lp systemv/lp +f 0755 root sys $BINDIR/lpoptions systemv/lpoptions +f 4755 $CUPS_USER sys $BINDIR/lppasswd systemv/lppasswd +f 0755 root sys $BINDIR/lpq berkeley/lpq +f 0755 root sys $BINDIR/lpr berkeley/lpr +f 0755 root sys $BINDIR/lprm berkeley/lprm +f 0755 root sys $BINDIR/lpstat systemv/lpstat + +%system irix +l 0755 root sys /usr/bsd/lpq $BINDIR/lpq +l 0755 root sys /usr/bsd/lpr $BINDIR/lpr +l 0755 root sys /usr/bsd/lprm $BINDIR/lprm +%system all + +# DSOs +%if DSOLIBS +%subpackage libs +%system hpux +f 0755 root sys $LIBDIR/libcups.sl.2 cups/libcups.sl.2 +l 0755 root sys $LIBDIR/libcups.sl libcups.sl.2 +f 0755 root sys $LIBDIR/libcupsimage.sl.2 filter/libcupsimage.sl.2 +l 0755 root sys $LIBDIR/libcupsimage.sl libcupsimage.sl.2 +%system aix +f 0755 root sys $LIBDIR/libcups_s.a cups/libcups_s.a +f 0755 root sys $LIBDIR/libcupsimage_s.a filter/libcupsimage_s.a +%system darwin +f 0755 root sys $LIBDIR/libcups.2.dylib cups/libcups.2.dylib +l 0755 root sys $LIBDIR/libcups.dylib libcups.2.dylib +f 0755 root sys $LIBDIR/libcupsimage.2.dylib filter/libcupsimage.2.dylib +l 0755 root sys $LIBDIR/libcupsimage.dylib libcupsimage.2.dylib +%system !hpux !aix !darwin +f 0755 root sys $LIBDIR/libcups.so.2 cups/libcups.so.2 +l 0755 root sys $LIBDIR/libcups.so libcups.so.2 +f 0755 root sys $LIBDIR/libcupsimage.so.2 filter/libcupsimage.so.2 +l 0755 root sys $LIBDIR/libcupsimage.so libcupsimage.so.2 +%system all +%subpackage +%endif + +# Directories +d 0755 root sys $LOGDIR - +d 0755 root sys $REQUESTS - +d 0755 root sys $REQUESTS/tmp - +d 0755 root sys $CACHEDIR - +d 0755 root sys $CACHEDIR/ppd - +d 0755 root sys $STATEDIR - +d 0755 root sys $STATEDIR/certs - + +# Data files +f 0644 root sys $LOCALEDIR/C/cups_C locale/C/cups_C +f 0644 root sys $LOCALEDIR/be/cups_be locale/be/cups_be +f 0644 root sys $LOCALEDIR/cs/cups_cs locale/cs/cups_cs +f 0644 root sys $LOCALEDIR/de/cups_de locale/de/cups_de +f 0644 root sys $LOCALEDIR/en/cups_en locale/en/cups_en +f 0644 root sys $LOCALEDIR/en_US/cups_en_US locale/en_US/cups_en_US +f 0644 root sys $LOCALEDIR/es/cups_es locale/es/cups_es +f 0644 root sys $LOCALEDIR/fr/cups_fr locale/fr/cups_fr +f 0644 root sys $LOCALEDIR/it/cups_it locale/it/cups_it +f 0644 root sys $LOCALEDIR/ru_RU/cups_ru_RU locale/ru_RU/cups_ru_RU +f 0644 root sys $LOCALEDIR/sv/cups_sv locale/sv/cups_sv +f 0644 root sys $LOCALEDIR/uk/cups_uk locale/uk/cups_uk +f 0644 root sys $LOCALEDIR/uk_UA/cups_uk_UA locale/uk_UA/cups_uk_UA +f 0644 root sys $LOCALEDIR/zh_CN/cups_zh_CN locale/zh_CN/cups_zh_CN + +d 0755 root sys $DATADIR - + +d 0755 root sys $DATADIR/banners - +f 0644 root sys $DATADIR/banners/classified data/classified +f 0644 root sys $DATADIR/banners/confidential data/confidential +f 0644 root sys $DATADIR/banners/secret data/secret +f 0644 root sys $DATADIR/banners/standard data/standard +f 0644 root sys $DATADIR/banners/topsecret data/topsecret +f 0644 root sys $DATADIR/banners/unclassified data/unclassified + +d 0755 root sys $DATADIR/charsets - +f 0644 root sys $DATADIR/charsets/windows-874 data/windows-874 +f 0644 root sys $DATADIR/charsets/windows-1250 data/windows-1250 +f 0644 root sys $DATADIR/charsets/windows-1251 data/windows-1251 +f 0644 root sys $DATADIR/charsets/windows-1252 data/windows-1252 +f 0644 root sys $DATADIR/charsets/windows-1253 data/windows-1253 +f 0644 root sys $DATADIR/charsets/windows-1254 data/windows-1254 +f 0644 root sys $DATADIR/charsets/windows-1255 data/windows-1255 +f 0644 root sys $DATADIR/charsets/windows-1256 data/windows-1256 +f 0644 root sys $DATADIR/charsets/windows-1257 data/windows-1257 +f 0644 root sys $DATADIR/charsets/windows-1258 data/windows-1258 +f 0644 root sys $DATADIR/charsets/iso-8859-1 data/iso-8859-1 +f 0644 root sys $DATADIR/charsets/iso-8859-2 data/iso-8859-2 +f 0644 root sys $DATADIR/charsets/iso-8859-3 data/iso-8859-3 +f 0644 root sys $DATADIR/charsets/iso-8859-4 data/iso-8859-4 +f 0644 root sys $DATADIR/charsets/iso-8859-5 data/iso-8859-5 +f 0644 root sys $DATADIR/charsets/iso-8859-6 data/iso-8859-6 +f 0644 root sys $DATADIR/charsets/iso-8859-7 data/iso-8859-7 +f 0644 root sys $DATADIR/charsets/iso-8859-8 data/iso-8859-8 +f 0644 root sys $DATADIR/charsets/iso-8859-9 data/iso-8859-9 +f 0644 root sys $DATADIR/charsets/iso-8859-10 data/iso-8859-10 +f 0644 root sys $DATADIR/charsets/iso-8859-13 data/iso-8859-13 +f 0644 root sys $DATADIR/charsets/iso-8859-14 data/iso-8859-14 +f 0644 root sys $DATADIR/charsets/iso-8859-15 data/iso-8859-15 +f 0644 root sys $DATADIR/charsets/utf-8 data/utf-8 + +d 0755 root sys $DATADIR/data - +f 0644 root sys $DATADIR/data/HPGLprolog data/HPGLprolog +f 0644 root sys $DATADIR/data/psglyphs data/psglyphs +f 0644 root sys $DATADIR/data/testprint.ps data/testprint.ps + +d 0755 root sys $DATADIR/fonts - +f 0644 root sys $DATADIR/fonts fonts/Courier* +f 0644 root sys $DATADIR/fonts/Symbol fonts/Symbol + +d 0755 root sys $DATADIR/model - +f 0644 root sys $DATADIR/model ppd/*.ppd + +d 0755 root sys $DATADIR/templates - +c 0644 root sys $DATADIR/templates templates/*.tmpl + +# Config files +d 0755 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 + +%if PAMDIR +d 0755 root sys $PAMDIR - +c 0644 root sys $PAMDIR/cups conf/@PAMFILE@ +%endif + +%subpackage devel +# Developer files +f 0755 root sys $BINDIR/cups-config cups-config +d 0755 root sys $INCLUDEDIR/cups - +f 0644 root sys $INCLUDEDIR/cups/cups.h cups/cups.h +f 0644 root sys $INCLUDEDIR/cups/http.h cups/http.h +f 0644 root sys $INCLUDEDIR/cups/image.h filter/image.h +f 0644 root sys $INCLUDEDIR/cups/ipp.h cups/ipp.h +f 0644 root sys $INCLUDEDIR/cups/language.h cups/language.h +f 0644 root sys $INCLUDEDIR/cups/md5.h cups/md5.h +f 0644 root sys $INCLUDEDIR/cups/ppd.h cups/ppd.h +f 0644 root sys $INCLUDEDIR/cups/raster.h filter/raster.h + +f 0644 root sys $LIBDIR/libcups.a cups/libcups.a +f 0644 root sys $LIBDIR/libcupsimage.a filter/libcupsimage.a + +d 0755 root sys $DOCDIR/help - +f 0644 root sys $DOCDIR/help doc/help/api*.html +%subpackage + +# Documentation files +d 0755 root sys $DOCDIR - +f 0644 root sys $DOCDIR doc/*.css +f 0644 root sys $DOCDIR doc/*.html +d 0755 root sys $DOCDIR/help - +f 0644 root sys $DOCDIR/help doc/*-reference.html +d 0755 root sys $DOCDIR/images - +f 0644 root sys $DOCDIR/images doc/images/*.gif +f 0644 root sys $DOCDIR/robots.txt doc/robots.txt + +# Man pages +d 0755 root sys $AMANDIR - +d 0755 root sys $AMANDIR/man$MAN8DIR - +d 0755 root sys $MANDIR - +d 0755 root sys $MANDIR/man1 - +d 0755 root sys $MANDIR/man5 - + +f 0644 root sys $MANDIR/man1/backend.$MAN1EXT man/backend.$MAN1EXT +f 0644 root sys $MANDIR/man1/cupstestppd.$MAN1EXT man/cupstestppd.$MAN1EXT +f 0644 root sys $MANDIR/man1/filter.$MAN1EXT man/filter.$MAN1EXT +f 0644 root sys $MANDIR/man1/lpoptions.$MAN1EXT man/lpoptions.$MAN1EXT +f 0644 root sys $MANDIR/man1/lppasswd.$MAN1EXT man/lppasswd.$MAN1EXT +f 0644 root sys $MANDIR/man1/lpq.$MAN1EXT man/lpq.$MAN1EXT +f 0644 root sys $MANDIR/man1/lprm.$MAN1EXT man/lprm.$MAN1EXT +f 0644 root sys $MANDIR/man1/lpr.$MAN1EXT man/lpr.$MAN1EXT +f 0644 root sys $MANDIR/man1/lpstat.$MAN1EXT man/lpstat.$MAN1EXT +f 0644 root sys $MANDIR/man1/lp.$MAN1EXT man/lp.$MAN1EXT +l 0644 root sys $MANDIR/man1/cancel.$MAN1EXT lp.$MAN1EXT + +f 0644 root sys $MANDIR/man5/classes.conf.$MAN5EXT man/classes.conf.$MAN5EXT +f 0644 root sys $MANDIR/man5/cupsd.conf.$MAN5EXT man/cupsd.conf.$MAN5EXT +f 0644 root sys $MANDIR/man5/mime.convs.$MAN5EXT man/mime.convs.$MAN5EXT +f 0644 root sys $MANDIR/man5/mime.types.$MAN5EXT man/mime.types.$MAN5EXT +f 0644 root sys $MANDIR/man5/printers.conf.$MAN5EXT man/printers.conf.$MAN5EXT + +f 0644 root sys $AMANDIR/man$MAN8DIR/accept.$MAN8EXT man/accept.$MAN8EXT +l 0644 root sys $AMANDIR/man$MAN8DIR/reject.$MAN8EXT accept.$MAN8EXT +f 0644 root sys $AMANDIR/man$MAN8DIR/cupsaddsmb.$MAN8EXT man/cupsaddsmb.$MAN8EXT +f 0644 root sys $AMANDIR/man$MAN8DIR/cups-polld.$MAN8EXT man/cups-polld.$MAN8EXT +f 0644 root sys $AMANDIR/man$MAN8DIR/cupsd.$MAN8EXT man/cupsd.$MAN8EXT +f 0644 root sys $AMANDIR/man$MAN8DIR/cupsenable.$MAN8EXT man/cupsenable.$MAN8EXT +l 0644 root sys $AMANDIR/man$MAN8DIR/cupsdisable.$MAN8EXT cupsenable.$MAN8EXT +f 0644 root sys $AMANDIR/man$MAN8DIR/lpadmin.$MAN8EXT man/lpadmin.$MAN8EXT +f 0644 root sys $AMANDIR/man$MAN8DIR/lpc.$MAN8EXT man/lpc.$MAN8EXT +f 0644 root sys $AMANDIR/man$MAN8DIR/lpinfo.$MAN8EXT man/lpinfo.$MAN8EXT +f 0644 root sys $AMANDIR/man$MAN8DIR/lpmove.$MAN8EXT man/lpmove.$MAN8EXT + +%subpackage devel +f 0644 root sys $MANDIR/man1/cups-config.$MAN1EXT man/cups-config.$MAN1EXT + +%subpackage lpd +d 0755 root sys $AMANDIR/man$MAN8DIR - +f 0644 root sys $AMANDIR/man$MAN8DIR/cups-lpd.$MAN8EXT man/cups-lpd.$MAN8EXT +%subpackage + +# Startup script +%system all +i 0755 root sys cups cups.sh + +# +# End of "$Id: cups.list.in 4903 2006-01-10 20:02:46Z mike $". +# diff --git a/packaging/cups.spec.in b/packaging/cups.spec.in new file mode 100644 index 000000000..07c65a1f8 --- /dev/null +++ b/packaging/cups.spec.in @@ -0,0 +1,267 @@ +# +# "$Id: cups.spec 4787 2005-10-13 20:13:21Z mike $" +# +# RPM "spec" file for the Common UNIX Printing System (CUPS). +# +# Original version by Jason McMullan . +# +# Copyright 1999-2006 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +Summary: Common Unix Printing System +Name: cups +Version: @CUPS_VERSION@ +Release: 0 +Epoch: 1 +License: GPL +Group: System Environment/Daemons +Source: ftp://ftp.easysw.com/pub/cups/%{version}/cups-%{version}-source.tar.gz +Url: http://www.cups.org +Packager: Anonymous +Vendor: Easy Software Products + +# Use buildroot so as not to disturb the version already installed +BuildRoot: /tmp/%{name}-root + +# Dependencies... +Requires: %{name}-libs = %{epoch}:%{version} +Obsoletes: lpd, lpr, LPRng +Provides: lpd, lpr, LPRng + +%package devel +Summary: Common Unix Printing System - development environment +Group: Development/Libraries +Requires: %{name}-libs = %{epoch}:%{version} + +%package libs +Summary: Common Unix Printing System - shared libraries +Group: System Environment/Libraries +Provides: libcups1 + +%package lpd +Summary: Common Unix Printing System - LPD support +Group: System Environment/Daemons +Requires: %{name} = %{epoch}:%{version} xinetd + +%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 libs +The Common UNIX Printing System provides a portable printing layer for +UNIX® operating systems. This package contains the CUPS shared libraries. + +%description lpd +The Common UNIX Printing System provides a portable printing layer for +UNIX® operating systems. This package provides LPD client support. + +%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/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/init.d/* +/etc/rc0.d/* +/etc/rc2.d/* +/etc/rc3.d/* +/etc/rc5.d/* + +# OLD RedHat/Mandrake +#/etc/rc.d/init.d/* +#/etc/rc.d/rc0.d/* +#/etc/rc.d/rc2.d/* +#/etc/rc.d/rc3.d/* +#/etc/rc.d/rc5.d/* + +#/sbin/rc.d/* +#/sbin/rc.d/rc0.d/* +#/sbin/rc.d/rc2.d/* +#/sbin/rc.d/rc3.d/* +#/sbin/rc.d/rc5.d/* + +/usr/bin/cancel +/usr/bin/cupstestppd +/usr/bin/lp* +%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/cups-deviced +/usr/lib/cups/daemon/cups-driverd +/usr/lib/cups/daemon/cups-polld +%dir /usr/lib/cups/driver +%dir /usr/lib/cups/filter +/usr/lib/cups/filter/* +%dir /usr/lib/cups/notifier +/usr/lib/cups/notifier/* + +/usr/sbin/* +%dir /usr/share/cups +/usr/share/cups/* +%dir /usr/share/doc/cups +/usr/share/doc/cups/*.* +%dir /usr/share/doc/cups/help +/usr/share/doc/cups/help/*-reference.html +/usr/share/doc/cups/help/man-*.html +/usr/share/doc/cups/help/network.html +/usr/share/doc/cups/help/overview.html +/usr/share/doc/cups/help/standard.html +/usr/share/doc/cups/help/whatsnew.html +%dir /usr/share/doc/cups/images +/usr/share/doc/cups/images/* +%dir /usr/share/locale +/usr/share/locale/* + +%dir /usr/share/man/man1 +/usr/share/man/man1/cancel.1.gz +/usr/share/man/man1/cupstestppd.1.gz +/usr/share/man/man1/lp.1.gz +/usr/share/man/man1/lpoptions.1.gz +/usr/share/man/man1/lppasswd.1.gz +/usr/share/man/man1/lpq.1.gz +/usr/share/man/man1/lpr.1.gz +/usr/share/man/man1/lprm.1.gz +/usr/share/man/man1/lpstat.1.gz +%dir /usr/share/man/man5 +/usr/share/man/man5/* +%dir /usr/share/man/man8 +/usr/share/man/man8/accept.8.gz +/usr/share/man/man8/cupsaddsmb.8.gz +/usr/share/man/man8/cupsd.8.gz +/usr/share/man/man8/cupsdisable.8.gz +/usr/share/man/man8/cupsenable.8.gz +/usr/share/man/man8/cups-polld.8.gz +/usr/share/man/man8/lpadmin.8.gz +/usr/share/man/man8/lpc.8.gz +/usr/share/man/man8/lpinfo.8.gz +/usr/share/man/man8/lpmove.8.gz +/usr/share/man/man8/reject.8.gz + +%dir /var/cache/cups +%dir /var/cache/cups/ppd +%dir /var/log/cups +%dir /var/run/cups +%attr(0711,lp,root) %dir /var/run/cups/certs +%attr(0700,lp,root) %dir /var/spool/cups +%attr(1700,lp,root) %dir /var/spool/cups/tmp + +%files devel +%defattr(-,root,root) +%dir /usr/share/man/man1 +/usr/share/man/man1/backend.1.gz +/usr/share/man/man1/cups-config.1.gz +/usr/share/man/man1/filter.1.gz + +/usr/bin/cups-config +%dir /usr/include/cups +/usr/include/cups/* +/usr/lib/*.a +/usr/lib/*.so + +%dir /usr/share/doc/cups/help +/usr/share/doc/cups/help/api*.html +/usr/share/doc/cups/help/spec*.html + +%files libs +%defattr(-,root,root) +/usr/lib/*.so.* + +%files lpd +%defattr(-,root,root) +#/etc/xinetd.d/cups-lpd +%dir /usr/lib/cups +%dir /usr/lib/cups/daemon +/usr/lib/cups/daemon/cups-lpd +%dir /usr/share/man/man8 +/usr/share/man/man8/cups-lpd.8.gz + +# +# End of "$Id: cups.spec 4787 2005-10-13 20:13:21Z mike $". +# diff --git a/packaging/installer.tif b/packaging/installer.tif new file mode 100644 index 0000000000000000000000000000000000000000..f88d7282daace8820f4ff4321cea3e28e0e55bf2 GIT binary patch literal 6580 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 literal 0 Hc-jL100001 diff --git a/packaging/installer.xcf.gz b/packaging/installer.xcf.gz new file mode 100644 index 0000000000000000000000000000000000000000..632fd19f11e3853c0ba0a9fb97688bb0c58b9f7e GIT binary patch literal 7461 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 literal 0 Hc-jL100001 diff --git a/pdftops/Annot.cxx b/pdftops/Annot.cxx new file mode 100644 index 000000000..19efb9c88 --- /dev/null +++ b/pdftops/Annot.cxx @@ -0,0 +1,317 @@ +//======================================================================== +// +// Annot.cc +// +// Copyright 2000-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "Object.h" +#include "Catalog.h" +#include "Gfx.h" +#include "Lexer.h" +#include "Annot.h" + +//------------------------------------------------------------------------ +// Annot +//------------------------------------------------------------------------ + +Annot::Annot(XRef *xrefA, Dict *acroForm, Dict *dict) { + Object apObj, asObj, obj1, obj2; + GBool regen, isTextField; + double t; + + ok = gFalse; + xref = xrefA; + appearBuf = NULL; + + 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(); + + // check if field apperances need to be regenerated + regen = gFalse; + if (acroForm) { + acroForm->lookup("NeedAppearances", &obj1); + if (obj1.isBool() && obj1.getBool()) { + regen = gTrue; + } + obj1.free(); + } + + // check for a text-type field + isTextField = dict->lookup("FT", &obj1)->isName("Tx"); + obj1.free(); + +#if 0 //~ appearance stream generation is not finished yet + if (regen && isTextField) { + generateAppearance(acroForm, dict); + } else { +#endif + if (dict->lookup("AP", &apObj)->isDict()) { + if (dict->lookup("AS", &asObj)->isName()) { + if (apObj.dictLookup("N", &obj1)->isDict()) { + if (obj1.dictLookupNF(asObj.getName(), &obj2)->isRef()) { + obj2.copy(&appearance); + ok = gTrue; + } else { + obj2.free(); + if (obj1.dictLookupNF("Off", &obj2)->isRef()) { + obj2.copy(&appearance); + ok = gTrue; + } + } + obj2.free(); + } + obj1.free(); + } else { + if (apObj.dictLookupNF("N", &obj1)->isRef()) { + obj1.copy(&appearance); + ok = gTrue; + } + obj1.free(); + } + asObj.free(); + } + apObj.free(); +#if 0 //~ appearance stream generation is not finished yet + } +#endif +} + +Annot::~Annot() { + appearance.free(); + if (appearBuf) { + delete appearBuf; + } +} + +void Annot::generateAppearance(Dict *acroForm, Dict *dict) { + MemStream *appearStream; + Object daObj, vObj, drObj, appearDict, obj1, obj2; + GString *daStr, *daStr1, *vStr, *s; + char buf[256]; + double fontSize; + int c; + int i0, i1; + + //~ DA can be inherited + if (dict->lookup("DA", &daObj)->isString()) { + daStr = daObj.getString(); + + // look for a font size + //~ may want to parse the DS entry in place of this (if it exists) + daStr1 = NULL; + fontSize = 10; + for (i1 = daStr->getLength() - 2; i1 >= 0; --i1) { + if (daStr->getChar(i1) == 'T' && daStr->getChar(i1+1) == 'f') { + for (--i1; i1 >= 0 && Lexer::isSpace(daStr->getChar(i1)); --i1) ; + for (i0 = i1; i0 >= 0 && !Lexer::isSpace(daStr->getChar(i0)); --i0) ; + if (i0 >= 0) { + ++i0; + ++i1; + s = new GString(daStr, i0, i1 - i0); + fontSize = atof(s->getCString()); + delete s; + + // autosize the font + if (fontSize == 0) { + fontSize = 0.67 * (yMax - yMin); + daStr1 = new GString(daStr, 0, i0); + sprintf(buf, "%.2f", fontSize); + daStr1->append(buf); + daStr1->append(daStr->getCString() + i1, + daStr->getLength() - i1); + } + } + break; + } + } + + // build the appearance stream contents + appearBuf = new GString(); + appearBuf->append("/Tx BMC\n"); + appearBuf->append("q BT\n"); + appearBuf->append(daStr1 ? daStr1 : daStr)->append("\n"); + if (dict->lookup("V", &vObj)->isString()) { + //~ handle quadding -- this requires finding the font and using + //~ the encoding and char widths + sprintf(buf, "1 0 0 1 %.2f %.2f Tm\n", 2.0, yMax - yMin - fontSize); + appearBuf->append(buf); + sprintf(buf, "%g TL\n", fontSize); + appearBuf->append(buf); + vStr = vObj.getString(); + i0 = 0; + while (i0 < vStr->getLength()) { + for (i1 = i0; + i1 < vStr->getLength() && + vStr->getChar(i1) != '\n' && vStr->getChar(i1) != '\r'; + ++i1) ; + if (i0 > 0) { + appearBuf->append("T*\n"); + } + appearBuf->append('('); + for (; i0 < i1; ++i0) { + c = vStr->getChar(i0); + if (c == '(' || c == ')' || c == '\\') { + appearBuf->append('\\'); + appearBuf->append(c); + } else if (c < 0x20 || c >= 0x80) { + sprintf(buf, "\\%03o", c); + appearBuf->append(buf); + } else { + appearBuf->append(c); + } + } + appearBuf->append(") Tj\n"); + if (i1 + 1 < vStr->getLength() && + vStr->getChar(i1) == '\r' && vStr->getChar(i1 + 1) == '\n') { + i0 = i1 + 2; + } else { + i0 = i1 + 1; + } + } + } + vObj.free(); + appearBuf->append("ET Q\n"); + appearBuf->append("EMC\n"); + + // build the appearance stream dictionary + appearDict.initDict(xref); + appearDict.dictAdd(copyString("Length"), + obj1.initInt(appearBuf->getLength())); + appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form")); + obj1.initArray(xref); + obj1.arrayAdd(obj2.initReal(0)); + obj1.arrayAdd(obj2.initReal(0)); + obj1.arrayAdd(obj2.initReal(xMax - xMin)); + obj1.arrayAdd(obj2.initReal(yMax - yMin)); + appearDict.dictAdd(copyString("BBox"), &obj1); + + // find the resource dictionary + dict->lookup("DR", &drObj); + if (!drObj.isDict()) { + dict->lookup("Parent", &obj1); + while (obj1.isDict()) { + drObj.free(); + obj1.dictLookup("DR", &drObj); + if (drObj.isDict()) { + break; + } + obj1.dictLookup("Parent", &obj2); + obj1.free(); + obj1 = obj2; + } + obj1.free(); + if (!drObj.isDict()) { + if (acroForm) { + drObj.free(); + acroForm->lookup("DR", &drObj); + } + } + } + if (drObj.isDict()) { + appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1)); + } + drObj.free(); + + // build the appearance stream + appearStream = new MemStream(appearBuf->getCString(), 0, + appearBuf->getLength(), &appearDict); + appearance.initStream(appearStream); + ok = gTrue; + + if (daStr1) { + delete daStr1; + } + } + daObj.free(); +} + +void Annot::draw(Gfx *gfx) { + Object obj; + + fprintf(stderr, "DEBUG: Annot::draw(gfx=%p)\n", gfx); + + if (appearance.fetch(xref, &obj)->isStream()) { + gfx->doAnnot(&obj, xMin, yMin, xMax, yMax); + } + obj.free(); +} + +//------------------------------------------------------------------------ +// Annots +//------------------------------------------------------------------------ + +Annots::Annots(XRef *xref, Catalog *catalog, Object *annotsObj) { + Dict *acroForm; + Annot *annot; + Object obj1; + int size; + int i; + + annots = NULL; + size = 0; + nAnnots = 0; + + acroForm = catalog->getAcroForm()->isDict() ? + catalog->getAcroForm()->getDict() : NULL; + if (annotsObj->isArray()) { + for (i = 0; i < annotsObj->arrayGetLength(); ++i) { + if (annotsObj->arrayGet(i, &obj1)->isDict()) { + annot = new Annot(xref, acroForm, obj1.getDict()); + if (annot->isOk()) { + if (nAnnots >= size) { + size += 16; + annots = (Annot **)greallocn(annots, size, sizeof(Annot *)); + } + annots[nAnnots++] = annot; + } else { + delete annot; + } + } + obj1.free(); + } + } +} + +Annots::~Annots() { + int i; + + for (i = 0; i < nAnnots; ++i) { + delete annots[i]; + } + gfree(annots); +} diff --git a/pdftops/Annot.h b/pdftops/Annot.h new file mode 100644 index 000000000..9e46dbb5b --- /dev/null +++ b/pdftops/Annot.h @@ -0,0 +1,73 @@ +//======================================================================== +// +// Annot.h +// +// Copyright 2000-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ANNOT_H +#define ANNOT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +class XRef; +class Catalog; +class Gfx; + +//------------------------------------------------------------------------ +// Annot +//------------------------------------------------------------------------ + +class Annot { +public: + + Annot(XRef *xrefA, Dict *acroForm, Dict *dict); + ~Annot(); + GBool isOk() { return ok; } + + void draw(Gfx *gfx); + + // Get appearance object. + Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); } + +private: + + void generateAppearance(Dict *acroForm, Dict *dict); + + XRef *xref; // the xref table for this PDF file + Object appearance; // a reference to the Form XObject stream + // for the normal appearance + GString *appearBuf; + double xMin, yMin, // annotation rectangle + xMax, yMax; + GBool ok; +}; + +//------------------------------------------------------------------------ +// Annots +//------------------------------------------------------------------------ + +class Annots { +public: + + // Extract non-link annotations from array of annotations. + Annots(XRef *xref, Catalog *catalog, Object *annotsObj); + + ~Annots(); + + // Iterate through list of annotations. + int getNumAnnots() { return nAnnots; } + Annot *getAnnot(int i) { return annots[i]; } + +private: + + Annot **annots; + int nAnnots; +}; + +#endif diff --git a/pdftops/Array.cxx b/pdftops/Array.cxx new file mode 100644 index 000000000..137727295 --- /dev/null +++ b/pdftops/Array.cxx @@ -0,0 +1,73 @@ +//======================================================================== +// +// Array.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#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 == size) { + if (length == 0) { + size = 8; + } else { + size *= 2; + } + elems = (Object *)greallocn(elems, size, sizeof(Object)); + } + elems[length] = *elem; + ++length; +} + +Object *Array::get(int i, Object *obj) { + if (i < 0 || i >= length) { +#ifdef DEBUG_MEM + abort(); +#else + return obj->initNull(); +#endif + } + return elems[i].fetch(xref, obj); +} + +Object *Array::getNF(int i, Object *obj) { + if (i < 0 || i >= length) { +#ifdef DEBUG_MEM + abort(); +#else + return obj->initNull(); +#endif + } + return elems[i].copy(obj); +} diff --git a/pdftops/Array.h b/pdftops/Array.h new file mode 100644 index 000000000..d369e8143 --- /dev/null +++ b/pdftops/Array.h @@ -0,0 +1,58 @@ +//======================================================================== +// +// Array.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ARRAY_H +#define ARRAY_H + +#include + +#ifdef USE_GCC_PRAGMAS +#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 array + int length; // number of elements in array + int ref; // reference count +}; + +#endif diff --git a/pdftops/BuiltinFont.cxx b/pdftops/BuiltinFont.cxx new file mode 100644 index 000000000..02a7f3554 --- /dev/null +++ b/pdftops/BuiltinFont.cxx @@ -0,0 +1,65 @@ +//======================================================================== +// +// BuiltinFont.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "FontEncodingTables.h" +#include "BuiltinFont.h" + +//------------------------------------------------------------------------ + +BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) { + int i, h; + + size = sizeA; + tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *)); + for (i = 0; i < size; ++i) { + tab[i] = NULL; + } + for (i = 0; i < sizeA; ++i) { + h = hash(widths[i].name); + widths[i].next = tab[h]; + tab[h] = &widths[i]; + } +} + +BuiltinFontWidths::~BuiltinFontWidths() { + gfree(tab); +} + +GBool BuiltinFontWidths::getWidth(char *name, Gushort *width) { + int h; + BuiltinFontWidth *p; + + h = hash(name); + for (p = tab[h]; p; p = p->next) { + if (!strcmp(p->name, name)) { + *width = p->width; + return gTrue; + } + } + return gFalse; +} + +int BuiltinFontWidths::hash(char *name) { + char *p; + unsigned int h; + + h = 0; + for (p = name; *p; ++p) { + h = 17 * h + (int)(*p & 0xff); + } + return (int)(h % size); +} diff --git a/pdftops/BuiltinFont.h b/pdftops/BuiltinFont.h new file mode 100644 index 000000000..3c036d7f3 --- /dev/null +++ b/pdftops/BuiltinFont.h @@ -0,0 +1,57 @@ +//======================================================================== +// +// BuiltinFont.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef BUILTINFONT_H +#define BUILTINFONT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +struct BuiltinFont; +class BuiltinFontWidths; + +//------------------------------------------------------------------------ + +struct BuiltinFont { + char *name; + char **defaultBaseEnc; + short ascent; + short descent; + short bbox[4]; + BuiltinFontWidths *widths; +}; + +//------------------------------------------------------------------------ + +struct BuiltinFontWidth { + char *name; + Gushort width; + BuiltinFontWidth *next; +}; + +class BuiltinFontWidths { +public: + + BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA); + ~BuiltinFontWidths(); + GBool getWidth(char *name, Gushort *width); + +private: + + int hash(char *name); + + BuiltinFontWidth **tab; + int size; +}; + +#endif diff --git a/pdftops/BuiltinFontTables.cxx b/pdftops/BuiltinFontTables.cxx new file mode 100644 index 000000000..5115b7bcf --- /dev/null +++ b/pdftops/BuiltinFontTables.cxx @@ -0,0 +1,4284 @@ +//======================================================================== +// +// BuiltinFontTables.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include +#include +#include "FontEncodingTables.h" +#include "BuiltinFontTables.h" + +static BuiltinFontWidth courierWidthsTab[] = { + { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, + { "comma", 600, NULL }, + { "cedilla", 600, NULL }, + { "plusminus", 600, NULL }, + { "circumflex", 600, NULL }, + { "dotaccent", 600, NULL }, + { "edotaccent", 600, NULL }, + { "asciitilde", 600, NULL }, + { "colon", 600, NULL }, + { "onehalf", 600, NULL }, + { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, + { "ntilde", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, + { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, + { "yen", 600, NULL }, + { "space", 600, NULL }, + { "Omacron", 600, NULL }, + { "questiondown", 600, NULL }, + { "emdash", 600, NULL }, + { "Agrave", 600, NULL }, + { "three", 600, NULL }, + { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, + { "A", 600, NULL }, + { "B", 600, NULL }, + { "C", 600, NULL }, + { "aogonek", 600, NULL }, + { "D", 600, NULL }, + { "E", 600, NULL }, + { "onequarter", 600, NULL }, + { "F", 600, NULL }, + { "G", 600, NULL }, + { "H", 600, NULL }, + { "I", 600, NULL }, + { "J", 600, NULL }, + { "K", 600, NULL }, + { "iogonek", 600, NULL }, + { "L", 600, NULL }, + { "backslash", 600, NULL }, + { "periodcentered", 600, NULL }, + { "M", 600, NULL }, + { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, + { "O", 600, NULL }, + { "P", 600, NULL }, + { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, + { "R", 600, NULL }, + { "Aacute", 600, NULL }, + { "caron", 600, NULL }, + { "S", 600, NULL }, + { "T", 600, NULL }, + { "U", 600, NULL }, + { "agrave", 600, NULL }, + { "V", 600, NULL }, + { "W", 600, NULL }, + { "equal", 600, NULL }, + { "question", 600, NULL }, + { "X", 600, NULL }, + { "Y", 600, NULL }, + { "Z", 600, NULL }, + { "four", 600, NULL }, + { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, + { "b", 600, NULL }, + { "c", 600, NULL }, + { "d", 600, NULL }, + { "e", 600, NULL }, + { "f", 600, NULL }, + { "g", 600, NULL }, + { "bullet", 600, NULL }, + { "h", 600, NULL }, + { "i", 600, NULL }, + { "Oslash", 600, NULL }, + { "dagger", 600, NULL }, + { "j", 600, NULL }, + { "k", 600, NULL }, + { "l", 600, NULL }, + { "m", 600, NULL }, + { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, + { "o", 600, NULL }, + { "ordfeminine", 600, NULL }, + { "ring", 600, NULL }, + { "p", 600, NULL }, + { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, + { "r", 600, NULL }, + { "twosuperior", 600, NULL }, + { "aacute", 600, NULL }, + { "s", 600, NULL }, + { "OE", 600, NULL }, + { "t", 600, NULL }, + { "divide", 600, NULL }, + { "u", 600, NULL }, + { "Ccaron", 600, NULL }, + { "v", 600, NULL }, + { "w", 600, NULL }, + { "x", 600, NULL }, + { "y", 600, NULL }, + { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, + { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, + { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, + { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, + { "Scaron", 600, NULL }, + { "Lslash", 600, NULL }, + { "semicolon", 600, NULL }, + { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, + { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, + { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, + { "trademark", 600, NULL }, + { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, + { "macron", 600, NULL }, + { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, + { "ellipsis", 600, NULL }, + { "scaron", 600, NULL }, + { "AE", 600, NULL }, + { "Ucircumflex", 600, NULL }, + { "lslash", 600, NULL }, + { "quotedblleft", 600, NULL }, + { "hyphen", 600, NULL }, + { "guilsinglright", 600, NULL }, + { "quotesingle", 600, NULL }, + { "eight", 600, NULL }, + { "exclamdown", 600, NULL }, + { "endash", 600, NULL }, + { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, + { "ecircumflex", 600, NULL }, + { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, + { "Egrave", 600, NULL }, + { "slash", 600, NULL }, + { "Edieresis", 600, NULL }, + { "otilde", 600, NULL }, + { "Idieresis", 600, NULL }, + { "parenleft", 600, NULL }, + { "one", 600, NULL }, + { "emacron", 600, NULL }, + { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, + { "bracketleft", 600, NULL }, + { "Ugrave", 600, NULL }, + { "quoteright", 600, NULL }, + { "Udieresis", 600, NULL }, + { "perthousand", 600, NULL }, + { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, + { "Eacute", 600, NULL }, + { "adieresis", 600, NULL }, + { "egrave", 600, NULL }, + { "edieresis", 600, NULL }, + { "idieresis", 600, NULL }, + { "Eth", 600, NULL }, + { "ae", 600, NULL }, + { "asterisk", 600, NULL }, + { "odieresis", 600, NULL }, + { "Uacute", 600, NULL }, + { "ugrave", 600, NULL }, + { "five", 600, NULL }, + { "nine", 600, NULL }, + { "udieresis", 600, NULL }, + { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, + { "threequarters", 600, NULL }, + { "guillemotright", 600, NULL }, + { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, + { "tilde", 600, NULL }, + { "at", 600, NULL }, + { "eacute", 600, NULL }, + { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, + { "zero", 600, NULL }, + { "multiply", 600, NULL }, + { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Racute", 600, NULL }, + { "Ograve", 600, NULL }, + { "partialdiff", 600, NULL }, + { "uacute", 600, NULL }, + { "braceleft", 600, NULL }, + { "Thorn", 600, NULL }, + { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, + { "ccedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "scedilla", 600, NULL }, + { "Oacute", 600, NULL }, + { "Ocircumflex", 600, NULL }, + { "ogonek", 600, NULL }, + { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, + { "thorn", 600, NULL }, + { "degree", 600, NULL }, + { "registered", 600, NULL }, + { "radical", 600, NULL }, + { "Aring", 600, NULL }, + { "percent", 600, NULL }, + { "six", 600, NULL }, + { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, + { "two", 600, NULL }, + { "summation", 600, NULL }, + { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, + { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, + { "asciicircum", 600, NULL }, + { "aring", 600, NULL }, + { "grave", 600, NULL }, + { "uogonek", 600, NULL }, + { "bracketright", 600, NULL }, + { "ampersand", 600, NULL }, + { "Iacute", 600, NULL }, + { "lacute", 600, NULL }, + { "igrave", 600, NULL }, + { "Ncaron", 600, NULL }, + { "plus", 600, NULL }, + { "uring", 600, NULL }, + { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, + { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, + { "threesuperior", 600, NULL }, + { "acute", 600, NULL }, + { "section", 600, NULL }, + { "dieresis", 600, NULL }, + { "quotedblbase", 600, NULL }, + { "iacute", 600, NULL }, + { "ncaron", 600, NULL }, + { "florin", 600, NULL }, + { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, + { "fi", 600, NULL }, + { "fl", 600, NULL }, + { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, + { "Icircumflex", 600, NULL }, + { "guillemotleft", 600, NULL }, + { "germandbls", 600, NULL }, + { "seven", 600, NULL }, + { "Amacron", 600, NULL }, + { "Sacute", 600, NULL }, + { "ordmasculine", 600, NULL }, + { "dotlessi", 600, NULL }, + { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, + { "acircumflex", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, + { "braceright", 600, NULL }, + { "icircumflex", 600, NULL }, + { "quotedblright", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, + { "cent", 600, NULL }, + { "currency", 600, NULL }, + { "logicalnot", 600, NULL }, + { "zdotaccent", 600, NULL }, + { "Atilde", 600, NULL }, + { "breve", 600, NULL }, + { "bar", 600, NULL }, + { "fraction", 600, NULL }, + { "less", 600, NULL }, + { "ecaron", 600, NULL }, + { "guilsinglleft", 600, NULL }, + { "exclam", 600, NULL }, + { "period", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, + { "greater", 600, NULL }, + { "atilde", 600, NULL }, + { "brokenbar", 600, NULL }, + { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, + { "onesuperior", 600, NULL } +}; + +static BuiltinFontWidth courierBoldWidthsTab[] = { + { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, + { "comma", 600, NULL }, + { "cedilla", 600, NULL }, + { "plusminus", 600, NULL }, + { "circumflex", 600, NULL }, + { "dotaccent", 600, NULL }, + { "edotaccent", 600, NULL }, + { "asciitilde", 600, NULL }, + { "colon", 600, NULL }, + { "onehalf", 600, NULL }, + { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, + { "ntilde", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, + { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, + { "yen", 600, NULL }, + { "space", 600, NULL }, + { "Omacron", 600, NULL }, + { "questiondown", 600, NULL }, + { "emdash", 600, NULL }, + { "Agrave", 600, NULL }, + { "three", 600, NULL }, + { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, + { "A", 600, NULL }, + { "B", 600, NULL }, + { "C", 600, NULL }, + { "aogonek", 600, NULL }, + { "D", 600, NULL }, + { "E", 600, NULL }, + { "onequarter", 600, NULL }, + { "F", 600, NULL }, + { "G", 600, NULL }, + { "H", 600, NULL }, + { "I", 600, NULL }, + { "J", 600, NULL }, + { "K", 600, NULL }, + { "iogonek", 600, NULL }, + { "backslash", 600, NULL }, + { "L", 600, NULL }, + { "periodcentered", 600, NULL }, + { "M", 600, NULL }, + { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, + { "O", 600, NULL }, + { "P", 600, NULL }, + { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, + { "R", 600, NULL }, + { "Aacute", 600, NULL }, + { "caron", 600, NULL }, + { "S", 600, NULL }, + { "T", 600, NULL }, + { "U", 600, NULL }, + { "agrave", 600, NULL }, + { "V", 600, NULL }, + { "W", 600, NULL }, + { "X", 600, NULL }, + { "question", 600, NULL }, + { "equal", 600, NULL }, + { "Y", 600, NULL }, + { "Z", 600, NULL }, + { "four", 600, NULL }, + { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, + { "b", 600, NULL }, + { "c", 600, NULL }, + { "d", 600, NULL }, + { "e", 600, NULL }, + { "f", 600, NULL }, + { "g", 600, NULL }, + { "bullet", 600, NULL }, + { "h", 600, NULL }, + { "i", 600, NULL }, + { "Oslash", 600, NULL }, + { "dagger", 600, NULL }, + { "j", 600, NULL }, + { "k", 600, NULL }, + { "l", 600, NULL }, + { "m", 600, NULL }, + { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, + { "o", 600, NULL }, + { "ordfeminine", 600, NULL }, + { "ring", 600, NULL }, + { "p", 600, NULL }, + { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, + { "r", 600, NULL }, + { "twosuperior", 600, NULL }, + { "aacute", 600, NULL }, + { "s", 600, NULL }, + { "OE", 600, NULL }, + { "t", 600, NULL }, + { "divide", 600, NULL }, + { "u", 600, NULL }, + { "Ccaron", 600, NULL }, + { "v", 600, NULL }, + { "w", 600, NULL }, + { "x", 600, NULL }, + { "y", 600, NULL }, + { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, + { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, + { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, + { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, + { "Scaron", 600, NULL }, + { "Lslash", 600, NULL }, + { "semicolon", 600, NULL }, + { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, + { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, + { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, + { "trademark", 600, NULL }, + { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, + { "macron", 600, NULL }, + { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, + { "ellipsis", 600, NULL }, + { "scaron", 600, NULL }, + { "AE", 600, NULL }, + { "Ucircumflex", 600, NULL }, + { "lslash", 600, NULL }, + { "quotedblleft", 600, NULL }, + { "guilsinglright", 600, NULL }, + { "hyphen", 600, NULL }, + { "quotesingle", 600, NULL }, + { "eight", 600, NULL }, + { "exclamdown", 600, NULL }, + { "endash", 600, NULL }, + { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, + { "ecircumflex", 600, NULL }, + { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, + { "Egrave", 600, NULL }, + { "slash", 600, NULL }, + { "Edieresis", 600, NULL }, + { "otilde", 600, NULL }, + { "Idieresis", 600, NULL }, + { "parenleft", 600, NULL }, + { "one", 600, NULL }, + { "emacron", 600, NULL }, + { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, + { "bracketleft", 600, NULL }, + { "Ugrave", 600, NULL }, + { "quoteright", 600, NULL }, + { "Udieresis", 600, NULL }, + { "perthousand", 600, NULL }, + { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, + { "Eacute", 600, NULL }, + { "adieresis", 600, NULL }, + { "egrave", 600, NULL }, + { "edieresis", 600, NULL }, + { "idieresis", 600, NULL }, + { "Eth", 600, NULL }, + { "ae", 600, NULL }, + { "asterisk", 600, NULL }, + { "odieresis", 600, NULL }, + { "Uacute", 600, NULL }, + { "ugrave", 600, NULL }, + { "nine", 600, NULL }, + { "five", 600, NULL }, + { "udieresis", 600, NULL }, + { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, + { "threequarters", 600, NULL }, + { "guillemotright", 600, NULL }, + { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, + { "tilde", 600, NULL }, + { "at", 600, NULL }, + { "eacute", 600, NULL }, + { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, + { "multiply", 600, NULL }, + { "zero", 600, NULL }, + { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, + { "uacute", 600, NULL }, + { "braceleft", 600, NULL }, + { "Thorn", 600, NULL }, + { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, + { "ccedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "Ocircumflex", 600, NULL }, + { "Oacute", 600, NULL }, + { "scedilla", 600, NULL }, + { "ogonek", 600, NULL }, + { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, + { "thorn", 600, NULL }, + { "degree", 600, NULL }, + { "registered", 600, NULL }, + { "radical", 600, NULL }, + { "Aring", 600, NULL }, + { "percent", 600, NULL }, + { "six", 600, NULL }, + { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, + { "two", 600, NULL }, + { "summation", 600, NULL }, + { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, + { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, + { "asciicircum", 600, NULL }, + { "aring", 600, NULL }, + { "grave", 600, NULL }, + { "uogonek", 600, NULL }, + { "bracketright", 600, NULL }, + { "Iacute", 600, NULL }, + { "ampersand", 600, NULL }, + { "igrave", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, + { "plus", 600, NULL }, + { "uring", 600, NULL }, + { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, + { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, + { "threesuperior", 600, NULL }, + { "acute", 600, NULL }, + { "section", 600, NULL }, + { "dieresis", 600, NULL }, + { "iacute", 600, NULL }, + { "quotedblbase", 600, NULL }, + { "ncaron", 600, NULL }, + { "florin", 600, NULL }, + { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, + { "fi", 600, NULL }, + { "fl", 600, NULL }, + { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, + { "Icircumflex", 600, NULL }, + { "guillemotleft", 600, NULL }, + { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, + { "seven", 600, NULL }, + { "Sacute", 600, NULL }, + { "ordmasculine", 600, NULL }, + { "dotlessi", 600, NULL }, + { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, + { "acircumflex", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, + { "icircumflex", 600, NULL }, + { "braceright", 600, NULL }, + { "quotedblright", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, + { "cent", 600, NULL }, + { "currency", 600, NULL }, + { "logicalnot", 600, NULL }, + { "zdotaccent", 600, NULL }, + { "Atilde", 600, NULL }, + { "breve", 600, NULL }, + { "bar", 600, NULL }, + { "fraction", 600, NULL }, + { "less", 600, NULL }, + { "ecaron", 600, NULL }, + { "guilsinglleft", 600, NULL }, + { "exclam", 600, NULL }, + { "period", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, + { "greater", 600, NULL }, + { "atilde", 600, NULL }, + { "brokenbar", 600, NULL }, + { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, + { "onesuperior", 600, NULL } +}; + +static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { + { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, + { "comma", 600, NULL }, + { "cedilla", 600, NULL }, + { "plusminus", 600, NULL }, + { "circumflex", 600, NULL }, + { "dotaccent", 600, NULL }, + { "edotaccent", 600, NULL }, + { "asciitilde", 600, NULL }, + { "colon", 600, NULL }, + { "onehalf", 600, NULL }, + { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, + { "ntilde", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, + { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, + { "yen", 600, NULL }, + { "space", 600, NULL }, + { "Omacron", 600, NULL }, + { "questiondown", 600, NULL }, + { "emdash", 600, NULL }, + { "Agrave", 600, NULL }, + { "three", 600, NULL }, + { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, + { "A", 600, NULL }, + { "B", 600, NULL }, + { "C", 600, NULL }, + { "aogonek", 600, NULL }, + { "D", 600, NULL }, + { "E", 600, NULL }, + { "onequarter", 600, NULL }, + { "F", 600, NULL }, + { "G", 600, NULL }, + { "H", 600, NULL }, + { "I", 600, NULL }, + { "J", 600, NULL }, + { "K", 600, NULL }, + { "iogonek", 600, NULL }, + { "backslash", 600, NULL }, + { "L", 600, NULL }, + { "periodcentered", 600, NULL }, + { "M", 600, NULL }, + { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, + { "O", 600, NULL }, + { "P", 600, NULL }, + { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, + { "R", 600, NULL }, + { "Aacute", 600, NULL }, + { "caron", 600, NULL }, + { "S", 600, NULL }, + { "T", 600, NULL }, + { "U", 600, NULL }, + { "agrave", 600, NULL }, + { "V", 600, NULL }, + { "W", 600, NULL }, + { "X", 600, NULL }, + { "question", 600, NULL }, + { "equal", 600, NULL }, + { "Y", 600, NULL }, + { "Z", 600, NULL }, + { "four", 600, NULL }, + { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, + { "b", 600, NULL }, + { "c", 600, NULL }, + { "d", 600, NULL }, + { "e", 600, NULL }, + { "f", 600, NULL }, + { "g", 600, NULL }, + { "bullet", 600, NULL }, + { "h", 600, NULL }, + { "i", 600, NULL }, + { "Oslash", 600, NULL }, + { "dagger", 600, NULL }, + { "j", 600, NULL }, + { "k", 600, NULL }, + { "l", 600, NULL }, + { "m", 600, NULL }, + { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, + { "o", 600, NULL }, + { "ordfeminine", 600, NULL }, + { "ring", 600, NULL }, + { "p", 600, NULL }, + { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, + { "r", 600, NULL }, + { "twosuperior", 600, NULL }, + { "aacute", 600, NULL }, + { "s", 600, NULL }, + { "OE", 600, NULL }, + { "t", 600, NULL }, + { "divide", 600, NULL }, + { "u", 600, NULL }, + { "Ccaron", 600, NULL }, + { "v", 600, NULL }, + { "w", 600, NULL }, + { "x", 600, NULL }, + { "y", 600, NULL }, + { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, + { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, + { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, + { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, + { "Scaron", 600, NULL }, + { "Lslash", 600, NULL }, + { "semicolon", 600, NULL }, + { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, + { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, + { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, + { "trademark", 600, NULL }, + { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, + { "macron", 600, NULL }, + { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, + { "ellipsis", 600, NULL }, + { "scaron", 600, NULL }, + { "AE", 600, NULL }, + { "Ucircumflex", 600, NULL }, + { "lslash", 600, NULL }, + { "quotedblleft", 600, NULL }, + { "guilsinglright", 600, NULL }, + { "hyphen", 600, NULL }, + { "quotesingle", 600, NULL }, + { "eight", 600, NULL }, + { "exclamdown", 600, NULL }, + { "endash", 600, NULL }, + { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, + { "ecircumflex", 600, NULL }, + { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, + { "Egrave", 600, NULL }, + { "slash", 600, NULL }, + { "Edieresis", 600, NULL }, + { "otilde", 600, NULL }, + { "Idieresis", 600, NULL }, + { "parenleft", 600, NULL }, + { "one", 600, NULL }, + { "emacron", 600, NULL }, + { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, + { "bracketleft", 600, NULL }, + { "Ugrave", 600, NULL }, + { "quoteright", 600, NULL }, + { "Udieresis", 600, NULL }, + { "perthousand", 600, NULL }, + { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, + { "Eacute", 600, NULL }, + { "adieresis", 600, NULL }, + { "egrave", 600, NULL }, + { "edieresis", 600, NULL }, + { "idieresis", 600, NULL }, + { "Eth", 600, NULL }, + { "ae", 600, NULL }, + { "asterisk", 600, NULL }, + { "odieresis", 600, NULL }, + { "Uacute", 600, NULL }, + { "ugrave", 600, NULL }, + { "nine", 600, NULL }, + { "five", 600, NULL }, + { "udieresis", 600, NULL }, + { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, + { "threequarters", 600, NULL }, + { "guillemotright", 600, NULL }, + { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, + { "tilde", 600, NULL }, + { "at", 600, NULL }, + { "eacute", 600, NULL }, + { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, + { "multiply", 600, NULL }, + { "zero", 600, NULL }, + { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, + { "uacute", 600, NULL }, + { "braceleft", 600, NULL }, + { "Thorn", 600, NULL }, + { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, + { "ccedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "Ocircumflex", 600, NULL }, + { "Oacute", 600, NULL }, + { "scedilla", 600, NULL }, + { "ogonek", 600, NULL }, + { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, + { "thorn", 600, NULL }, + { "degree", 600, NULL }, + { "registered", 600, NULL }, + { "radical", 600, NULL }, + { "Aring", 600, NULL }, + { "percent", 600, NULL }, + { "six", 600, NULL }, + { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, + { "two", 600, NULL }, + { "summation", 600, NULL }, + { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, + { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, + { "asciicircum", 600, NULL }, + { "aring", 600, NULL }, + { "grave", 600, NULL }, + { "uogonek", 600, NULL }, + { "bracketright", 600, NULL }, + { "Iacute", 600, NULL }, + { "ampersand", 600, NULL }, + { "igrave", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, + { "plus", 600, NULL }, + { "uring", 600, NULL }, + { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, + { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, + { "threesuperior", 600, NULL }, + { "acute", 600, NULL }, + { "section", 600, NULL }, + { "dieresis", 600, NULL }, + { "iacute", 600, NULL }, + { "quotedblbase", 600, NULL }, + { "ncaron", 600, NULL }, + { "florin", 600, NULL }, + { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, + { "fi", 600, NULL }, + { "fl", 600, NULL }, + { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, + { "Icircumflex", 600, NULL }, + { "guillemotleft", 600, NULL }, + { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, + { "seven", 600, NULL }, + { "Sacute", 600, NULL }, + { "ordmasculine", 600, NULL }, + { "dotlessi", 600, NULL }, + { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, + { "acircumflex", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, + { "icircumflex", 600, NULL }, + { "braceright", 600, NULL }, + { "quotedblright", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, + { "cent", 600, NULL }, + { "currency", 600, NULL }, + { "logicalnot", 600, NULL }, + { "zdotaccent", 600, NULL }, + { "Atilde", 600, NULL }, + { "breve", 600, NULL }, + { "bar", 600, NULL }, + { "fraction", 600, NULL }, + { "less", 600, NULL }, + { "ecaron", 600, NULL }, + { "guilsinglleft", 600, NULL }, + { "exclam", 600, NULL }, + { "period", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, + { "greater", 600, NULL }, + { "atilde", 600, NULL }, + { "brokenbar", 600, NULL }, + { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, + { "onesuperior", 600, NULL } +}; + +static BuiltinFontWidth courierObliqueWidthsTab[] = { + { "Ntilde", 600, NULL }, + { "rcaron", 600, NULL }, + { "kcommaaccent", 600, NULL }, + { "Ncommaaccent", 600, NULL }, + { "Zacute", 600, NULL }, + { "comma", 600, NULL }, + { "cedilla", 600, NULL }, + { "plusminus", 600, NULL }, + { "circumflex", 600, NULL }, + { "dotaccent", 600, NULL }, + { "edotaccent", 600, NULL }, + { "asciitilde", 600, NULL }, + { "colon", 600, NULL }, + { "onehalf", 600, NULL }, + { "dollar", 600, NULL }, + { "Lcaron", 600, NULL }, + { "ntilde", 600, NULL }, + { "Aogonek", 600, NULL }, + { "ncommaaccent", 600, NULL }, + { "minus", 600, NULL }, + { "Iogonek", 600, NULL }, + { "zacute", 600, NULL }, + { "yen", 600, NULL }, + { "space", 600, NULL }, + { "Omacron", 600, NULL }, + { "questiondown", 600, NULL }, + { "emdash", 600, NULL }, + { "Agrave", 600, NULL }, + { "three", 600, NULL }, + { "numbersign", 600, NULL }, + { "lcaron", 600, NULL }, + { "A", 600, NULL }, + { "B", 600, NULL }, + { "C", 600, NULL }, + { "aogonek", 600, NULL }, + { "D", 600, NULL }, + { "E", 600, NULL }, + { "onequarter", 600, NULL }, + { "F", 600, NULL }, + { "G", 600, NULL }, + { "H", 600, NULL }, + { "I", 600, NULL }, + { "J", 600, NULL }, + { "K", 600, NULL }, + { "iogonek", 600, NULL }, + { "backslash", 600, NULL }, + { "L", 600, NULL }, + { "periodcentered", 600, NULL }, + { "M", 600, NULL }, + { "N", 600, NULL }, + { "omacron", 600, NULL }, + { "Tcommaaccent", 600, NULL }, + { "O", 600, NULL }, + { "P", 600, NULL }, + { "Q", 600, NULL }, + { "Uhungarumlaut", 600, NULL }, + { "R", 600, NULL }, + { "Aacute", 600, NULL }, + { "caron", 600, NULL }, + { "S", 600, NULL }, + { "T", 600, NULL }, + { "U", 600, NULL }, + { "agrave", 600, NULL }, + { "V", 600, NULL }, + { "W", 600, NULL }, + { "X", 600, NULL }, + { "question", 600, NULL }, + { "equal", 600, NULL }, + { "Y", 600, NULL }, + { "Z", 600, NULL }, + { "four", 600, NULL }, + { "a", 600, NULL }, + { "Gcommaaccent", 600, NULL }, + { "b", 600, NULL }, + { "c", 600, NULL }, + { "d", 600, NULL }, + { "e", 600, NULL }, + { "f", 600, NULL }, + { "g", 600, NULL }, + { "bullet", 600, NULL }, + { "h", 600, NULL }, + { "i", 600, NULL }, + { "Oslash", 600, NULL }, + { "dagger", 600, NULL }, + { "j", 600, NULL }, + { "k", 600, NULL }, + { "l", 600, NULL }, + { "m", 600, NULL }, + { "n", 600, NULL }, + { "tcommaaccent", 600, NULL }, + { "o", 600, NULL }, + { "ordfeminine", 600, NULL }, + { "ring", 600, NULL }, + { "p", 600, NULL }, + { "q", 600, NULL }, + { "uhungarumlaut", 600, NULL }, + { "r", 600, NULL }, + { "twosuperior", 600, NULL }, + { "aacute", 600, NULL }, + { "s", 600, NULL }, + { "OE", 600, NULL }, + { "t", 600, NULL }, + { "divide", 600, NULL }, + { "u", 600, NULL }, + { "Ccaron", 600, NULL }, + { "v", 600, NULL }, + { "w", 600, NULL }, + { "x", 600, NULL }, + { "y", 600, NULL }, + { "z", 600, NULL }, + { "Gbreve", 600, NULL }, + { "commaaccent", 600, NULL }, + { "hungarumlaut", 600, NULL }, + { "Idotaccent", 600, NULL }, + { "Nacute", 600, NULL }, + { "quotedbl", 600, NULL }, + { "gcommaaccent", 600, NULL }, + { "mu", 600, NULL }, + { "greaterequal", 600, NULL }, + { "Scaron", 600, NULL }, + { "Lslash", 600, NULL }, + { "semicolon", 600, NULL }, + { "oslash", 600, NULL }, + { "lessequal", 600, NULL }, + { "lozenge", 600, NULL }, + { "parenright", 600, NULL }, + { "ccaron", 600, NULL }, + { "Ecircumflex", 600, NULL }, + { "gbreve", 600, NULL }, + { "trademark", 600, NULL }, + { "daggerdbl", 600, NULL }, + { "nacute", 600, NULL }, + { "macron", 600, NULL }, + { "Otilde", 600, NULL }, + { "Emacron", 600, NULL }, + { "ellipsis", 600, NULL }, + { "scaron", 600, NULL }, + { "AE", 600, NULL }, + { "Ucircumflex", 600, NULL }, + { "lslash", 600, NULL }, + { "quotedblleft", 600, NULL }, + { "guilsinglright", 600, NULL }, + { "hyphen", 600, NULL }, + { "quotesingle", 600, NULL }, + { "eight", 600, NULL }, + { "exclamdown", 600, NULL }, + { "endash", 600, NULL }, + { "oe", 600, NULL }, + { "Abreve", 600, NULL }, + { "Umacron", 600, NULL }, + { "ecircumflex", 600, NULL }, + { "Adieresis", 600, NULL }, + { "copyright", 600, NULL }, + { "Egrave", 600, NULL }, + { "slash", 600, NULL }, + { "Edieresis", 600, NULL }, + { "otilde", 600, NULL }, + { "Idieresis", 600, NULL }, + { "parenleft", 600, NULL }, + { "one", 600, NULL }, + { "emacron", 600, NULL }, + { "Odieresis", 600, NULL }, + { "ucircumflex", 600, NULL }, + { "bracketleft", 600, NULL }, + { "Ugrave", 600, NULL }, + { "quoteright", 600, NULL }, + { "Udieresis", 600, NULL }, + { "perthousand", 600, NULL }, + { "Ydieresis", 600, NULL }, + { "umacron", 600, NULL }, + { "abreve", 600, NULL }, + { "Eacute", 600, NULL }, + { "adieresis", 600, NULL }, + { "egrave", 600, NULL }, + { "edieresis", 600, NULL }, + { "idieresis", 600, NULL }, + { "Eth", 600, NULL }, + { "ae", 600, NULL }, + { "asterisk", 600, NULL }, + { "odieresis", 600, NULL }, + { "Uacute", 600, NULL }, + { "ugrave", 600, NULL }, + { "nine", 600, NULL }, + { "five", 600, NULL }, + { "udieresis", 600, NULL }, + { "Zcaron", 600, NULL }, + { "Scommaaccent", 600, NULL }, + { "threequarters", 600, NULL }, + { "guillemotright", 600, NULL }, + { "Ccedilla", 600, NULL }, + { "ydieresis", 600, NULL }, + { "tilde", 600, NULL }, + { "at", 600, NULL }, + { "eacute", 600, NULL }, + { "underscore", 600, NULL }, + { "Euro", 600, NULL }, + { "Dcroat", 600, NULL }, + { "multiply", 600, NULL }, + { "zero", 600, NULL }, + { "eth", 600, NULL }, + { "Scedilla", 600, NULL }, + { "Ograve", 600, NULL }, + { "Racute", 600, NULL }, + { "partialdiff", 600, NULL }, + { "uacute", 600, NULL }, + { "braceleft", 600, NULL }, + { "Thorn", 600, NULL }, + { "zcaron", 600, NULL }, + { "scommaaccent", 600, NULL }, + { "ccedilla", 600, NULL }, + { "Dcaron", 600, NULL }, + { "dcroat", 600, NULL }, + { "Ocircumflex", 600, NULL }, + { "Oacute", 600, NULL }, + { "scedilla", 600, NULL }, + { "ogonek", 600, NULL }, + { "ograve", 600, NULL }, + { "racute", 600, NULL }, + { "Tcaron", 600, NULL }, + { "Eogonek", 600, NULL }, + { "thorn", 600, NULL }, + { "degree", 600, NULL }, + { "registered", 600, NULL }, + { "radical", 600, NULL }, + { "Aring", 600, NULL }, + { "percent", 600, NULL }, + { "six", 600, NULL }, + { "paragraph", 600, NULL }, + { "dcaron", 600, NULL }, + { "Uogonek", 600, NULL }, + { "two", 600, NULL }, + { "summation", 600, NULL }, + { "Igrave", 600, NULL }, + { "Lacute", 600, NULL }, + { "ocircumflex", 600, NULL }, + { "oacute", 600, NULL }, + { "Uring", 600, NULL }, + { "Lcommaaccent", 600, NULL }, + { "tcaron", 600, NULL }, + { "eogonek", 600, NULL }, + { "Delta", 600, NULL }, + { "Ohungarumlaut", 600, NULL }, + { "asciicircum", 600, NULL }, + { "aring", 600, NULL }, + { "grave", 600, NULL }, + { "uogonek", 600, NULL }, + { "bracketright", 600, NULL }, + { "Iacute", 600, NULL }, + { "ampersand", 600, NULL }, + { "igrave", 600, NULL }, + { "lacute", 600, NULL }, + { "Ncaron", 600, NULL }, + { "plus", 600, NULL }, + { "uring", 600, NULL }, + { "quotesinglbase", 600, NULL }, + { "lcommaaccent", 600, NULL }, + { "Yacute", 600, NULL }, + { "ohungarumlaut", 600, NULL }, + { "threesuperior", 600, NULL }, + { "acute", 600, NULL }, + { "section", 600, NULL }, + { "dieresis", 600, NULL }, + { "iacute", 600, NULL }, + { "quotedblbase", 600, NULL }, + { "ncaron", 600, NULL }, + { "florin", 600, NULL }, + { "yacute", 600, NULL }, + { "Rcommaaccent", 600, NULL }, + { "fi", 600, NULL }, + { "fl", 600, NULL }, + { "Acircumflex", 600, NULL }, + { "Cacute", 600, NULL }, + { "Icircumflex", 600, NULL }, + { "guillemotleft", 600, NULL }, + { "germandbls", 600, NULL }, + { "Amacron", 600, NULL }, + { "seven", 600, NULL }, + { "Sacute", 600, NULL }, + { "ordmasculine", 600, NULL }, + { "dotlessi", 600, NULL }, + { "sterling", 600, NULL }, + { "notequal", 600, NULL }, + { "Imacron", 600, NULL }, + { "rcommaaccent", 600, NULL }, + { "Zdotaccent", 600, NULL }, + { "acircumflex", 600, NULL }, + { "cacute", 600, NULL }, + { "Ecaron", 600, NULL }, + { "icircumflex", 600, NULL }, + { "braceright", 600, NULL }, + { "quotedblright", 600, NULL }, + { "amacron", 600, NULL }, + { "sacute", 600, NULL }, + { "imacron", 600, NULL }, + { "cent", 600, NULL }, + { "currency", 600, NULL }, + { "logicalnot", 600, NULL }, + { "zdotaccent", 600, NULL }, + { "Atilde", 600, NULL }, + { "breve", 600, NULL }, + { "bar", 600, NULL }, + { "fraction", 600, NULL }, + { "less", 600, NULL }, + { "ecaron", 600, NULL }, + { "guilsinglleft", 600, NULL }, + { "exclam", 600, NULL }, + { "period", 600, NULL }, + { "Rcaron", 600, NULL }, + { "Kcommaaccent", 600, NULL }, + { "greater", 600, NULL }, + { "atilde", 600, NULL }, + { "brokenbar", 600, NULL }, + { "quoteleft", 600, NULL }, + { "Edotaccent", 600, NULL }, + { "onesuperior", 600, NULL } +}; + +static BuiltinFontWidth helveticaWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 278, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 584, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, + { "asciitilde", 584, NULL }, + { "colon", 278, NULL }, + { "onehalf", 834, NULL }, + { "dollar", 556, NULL }, + { "Lcaron", 556, NULL }, + { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, + { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, + { "yen", 556, NULL }, + { "space", 278, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 611, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 667, NULL }, + { "three", 556, NULL }, + { "numbersign", 556, NULL }, + { "lcaron", 299, NULL }, + { "A", 667, NULL }, + { "B", 667, NULL }, + { "C", 722, NULL }, + { "aogonek", 556, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 834, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 722, NULL }, + { "I", 278, NULL }, + { "J", 500, NULL }, + { "K", 667, NULL }, + { "iogonek", 222, NULL }, + { "backslash", 278, NULL }, + { "L", 556, NULL }, + { "periodcentered", 278, NULL }, + { "M", 833, NULL }, + { "N", 722, NULL }, + { "omacron", 556, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 778, NULL }, + { "P", 667, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 667, NULL }, + { "caron", 333, NULL }, + { "S", 667, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 556, NULL }, + { "V", 667, NULL }, + { "W", 944, NULL }, + { "X", 667, NULL }, + { "question", 556, NULL }, + { "equal", 584, NULL }, + { "Y", 667, NULL }, + { "Z", 611, NULL }, + { "four", 556, NULL }, + { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 556, NULL }, + { "c", 500, NULL }, + { "d", 556, NULL }, + { "e", 556, NULL }, + { "f", 278, NULL }, + { "g", 556, NULL }, + { "bullet", 350, NULL }, + { "h", 556, NULL }, + { "i", 222, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 556, NULL }, + { "j", 222, NULL }, + { "k", 500, NULL }, + { "l", 222, NULL }, + { "m", 833, NULL }, + { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 556, NULL }, + { "ordfeminine", 370, NULL }, + { "ring", 333, NULL }, + { "p", 556, NULL }, + { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, + { "r", 333, NULL }, + { "twosuperior", 333, NULL }, + { "aacute", 556, NULL }, + { "s", 500, NULL }, + { "OE", 1000, NULL }, + { "t", 278, NULL }, + { "divide", 584, NULL }, + { "u", 556, NULL }, + { "Ccaron", 722, NULL }, + { "v", 500, NULL }, + { "w", 722, NULL }, + { "x", 500, NULL }, + { "y", 500, NULL }, + { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 355, NULL }, + { "gcommaaccent", 556, NULL }, + { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 667, NULL }, + { "Lslash", 556, NULL }, + { "semicolon", 278, NULL }, + { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 500, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 556, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 556, NULL }, + { "nacute", 556, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 500, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 222, NULL }, + { "quotedblleft", 333, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 191, NULL }, + { "eight", 556, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 556, NULL }, + { "oe", 944, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 556, NULL }, + { "Adieresis", 667, NULL }, + { "copyright", 737, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 556, NULL }, + { "Idieresis", 278, NULL }, + { "parenleft", 333, NULL }, + { "one", 556, NULL }, + { "emacron", 556, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, + { "bracketleft", 278, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 222, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 667, NULL }, + { "umacron", 556, NULL }, + { "abreve", 556, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 556, NULL }, + { "egrave", 556, NULL }, + { "edieresis", 556, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 889, NULL }, + { "asterisk", 389, NULL }, + { "odieresis", 556, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 556, NULL }, + { "nine", 556, NULL }, + { "five", 556, NULL }, + { "udieresis", 556, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, + { "threequarters", 834, NULL }, + { "guillemotright", 556, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, + { "tilde", 333, NULL }, + { "at", 1015, NULL }, + { "eacute", 556, NULL }, + { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 584, NULL }, + { "zero", 556, NULL }, + { "eth", 556, NULL }, + { "Scedilla", 667, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 476, NULL }, + { "uacute", 556, NULL }, + { "braceleft", 334, NULL }, + { "Thorn", 667, NULL }, + { "zcaron", 500, NULL }, + { "scommaaccent", 500, NULL }, + { "ccedilla", 500, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 500, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 556, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 556, NULL }, + { "degree", 400, NULL }, + { "registered", 737, NULL }, + { "radical", 453, NULL }, + { "Aring", 667, NULL }, + { "percent", 889, NULL }, + { "six", 556, NULL }, + { "paragraph", 537, NULL }, + { "dcaron", 643, NULL }, + { "Uogonek", 722, NULL }, + { "two", 556, NULL }, + { "summation", 600, NULL }, + { "Igrave", 278, NULL }, + { "Lacute", 556, NULL }, + { "ocircumflex", 556, NULL }, + { "oacute", 556, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 317, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 469, NULL }, + { "aring", 556, NULL }, + { "grave", 333, NULL }, + { "uogonek", 556, NULL }, + { "bracketright", 278, NULL }, + { "Iacute", 278, NULL }, + { "ampersand", 667, NULL }, + { "igrave", 278, NULL }, + { "lacute", 222, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 584, NULL }, + { "uring", 556, NULL }, + { "quotesinglbase", 222, NULL }, + { "lcommaaccent", 222, NULL }, + { "Yacute", 667, NULL }, + { "ohungarumlaut", 556, NULL }, + { "threesuperior", 333, NULL }, + { "acute", 333, NULL }, + { "section", 556, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 333, NULL }, + { "ncaron", 556, NULL }, + { "florin", 556, NULL }, + { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 500, NULL }, + { "fl", 500, NULL }, + { "Acircumflex", 667, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 278, NULL }, + { "guillemotleft", 556, NULL }, + { "germandbls", 611, NULL }, + { "Amacron", 667, NULL }, + { "seven", 556, NULL }, + { "Sacute", 667, NULL }, + { "ordmasculine", 365, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 556, NULL }, + { "cacute", 500, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 334, NULL }, + { "quotedblright", 333, NULL }, + { "amacron", 556, NULL }, + { "sacute", 500, NULL }, + { "imacron", 278, NULL }, + { "cent", 556, NULL }, + { "currency", 556, NULL }, + { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, + { "Atilde", 667, NULL }, + { "breve", 333, NULL }, + { "bar", 260, NULL }, + { "fraction", 167, NULL }, + { "less", 584, NULL }, + { "ecaron", 556, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 278, NULL }, + { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 667, NULL }, + { "greater", 584, NULL }, + { "atilde", 556, NULL }, + { "brokenbar", 260, NULL }, + { "quoteleft", 222, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 333, NULL } +}; + +static BuiltinFontWidth helveticaBoldWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 278, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 584, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, + { "asciitilde", 584, NULL }, + { "colon", 333, NULL }, + { "onehalf", 834, NULL }, + { "dollar", 556, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 611, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 611, NULL }, + { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, + { "yen", 556, NULL }, + { "space", 278, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 611, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 722, NULL }, + { "three", 556, NULL }, + { "numbersign", 556, NULL }, + { "lcaron", 400, NULL }, + { "A", 722, NULL }, + { "B", 722, NULL }, + { "C", 722, NULL }, + { "aogonek", 556, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 834, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 722, NULL }, + { "I", 278, NULL }, + { "J", 556, NULL }, + { "K", 722, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 611, NULL }, + { "periodcentered", 278, NULL }, + { "M", 833, NULL }, + { "N", 722, NULL }, + { "omacron", 611, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 778, NULL }, + { "P", 667, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 722, NULL }, + { "caron", 333, NULL }, + { "S", 667, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 556, NULL }, + { "V", 667, NULL }, + { "W", 944, NULL }, + { "X", 667, NULL }, + { "question", 611, NULL }, + { "equal", 584, NULL }, + { "Y", 667, NULL }, + { "Z", 611, NULL }, + { "four", 556, NULL }, + { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 611, NULL }, + { "c", 556, NULL }, + { "d", 611, NULL }, + { "e", 556, NULL }, + { "f", 333, NULL }, + { "g", 611, NULL }, + { "bullet", 350, NULL }, + { "h", 611, NULL }, + { "i", 278, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 556, NULL }, + { "j", 278, NULL }, + { "k", 556, NULL }, + { "l", 278, NULL }, + { "m", 889, NULL }, + { "n", 611, NULL }, + { "tcommaaccent", 333, NULL }, + { "o", 611, NULL }, + { "ordfeminine", 370, NULL }, + { "ring", 333, NULL }, + { "p", 611, NULL }, + { "q", 611, NULL }, + { "uhungarumlaut", 611, NULL }, + { "r", 389, NULL }, + { "twosuperior", 333, NULL }, + { "aacute", 556, NULL }, + { "s", 556, NULL }, + { "OE", 1000, NULL }, + { "t", 333, NULL }, + { "divide", 584, NULL }, + { "u", 611, NULL }, + { "Ccaron", 722, NULL }, + { "v", 556, NULL }, + { "w", 778, NULL }, + { "x", 556, NULL }, + { "y", 556, NULL }, + { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 474, NULL }, + { "gcommaaccent", 611, NULL }, + { "mu", 611, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 667, NULL }, + { "Lslash", 611, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 556, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 611, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 556, NULL }, + { "nacute", 611, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 556, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 500, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 238, NULL }, + { "eight", 556, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 556, NULL }, + { "oe", 944, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 556, NULL }, + { "Adieresis", 722, NULL }, + { "copyright", 737, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 611, NULL }, + { "Idieresis", 278, NULL }, + { "parenleft", 333, NULL }, + { "one", 556, NULL }, + { "emacron", 556, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 611, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 278, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 667, NULL }, + { "umacron", 611, NULL }, + { "abreve", 556, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 556, NULL }, + { "egrave", 556, NULL }, + { "edieresis", 556, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 889, NULL }, + { "asterisk", 389, NULL }, + { "odieresis", 611, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 611, NULL }, + { "nine", 556, NULL }, + { "five", 556, NULL }, + { "udieresis", 611, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, + { "threequarters", 834, NULL }, + { "guillemotright", 556, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 556, NULL }, + { "tilde", 333, NULL }, + { "dbldaggerumlaut", 556, NULL }, + { "at", 975, NULL }, + { "eacute", 556, NULL }, + { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 584, NULL }, + { "zero", 556, NULL }, + { "eth", 611, NULL }, + { "Scedilla", 667, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, + { "uacute", 611, NULL }, + { "braceleft", 389, NULL }, + { "Thorn", 667, NULL }, + { "zcaron", 500, NULL }, + { "scommaaccent", 556, NULL }, + { "ccedilla", 556, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 611, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 556, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 611, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 611, NULL }, + { "degree", 400, NULL }, + { "registered", 737, NULL }, + { "radical", 549, NULL }, + { "Aring", 722, NULL }, + { "percent", 889, NULL }, + { "six", 556, NULL }, + { "paragraph", 556, NULL }, + { "dcaron", 743, NULL }, + { "Uogonek", 722, NULL }, + { "two", 556, NULL }, + { "summation", 600, NULL }, + { "Igrave", 278, NULL }, + { "Lacute", 611, NULL }, + { "ocircumflex", 611, NULL }, + { "oacute", 611, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 389, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 584, NULL }, + { "aring", 556, NULL }, + { "grave", 333, NULL }, + { "uogonek", 611, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 278, NULL }, + { "ampersand", 722, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 584, NULL }, + { "uring", 611, NULL }, + { "quotesinglbase", 278, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 667, NULL }, + { "ohungarumlaut", 611, NULL }, + { "threesuperior", 333, NULL }, + { "acute", 333, NULL }, + { "section", 556, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 500, NULL }, + { "ncaron", 611, NULL }, + { "florin", 556, NULL }, + { "yacute", 556, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 611, NULL }, + { "fl", 611, NULL }, + { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 278, NULL }, + { "guillemotleft", 556, NULL }, + { "germandbls", 611, NULL }, + { "Amacron", 722, NULL }, + { "seven", 556, NULL }, + { "Sacute", 667, NULL }, + { "ordmasculine", 365, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 556, NULL }, + { "cacute", 556, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 389, NULL }, + { "quotedblright", 500, NULL }, + { "amacron", 556, NULL }, + { "sacute", 556, NULL }, + { "imacron", 278, NULL }, + { "cent", 556, NULL }, + { "currency", 556, NULL }, + { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, + { "Atilde", 722, NULL }, + { "breve", 333, NULL }, + { "bar", 280, NULL }, + { "fraction", 167, NULL }, + { "less", 584, NULL }, + { "ecaron", 556, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 722, NULL }, + { "greater", 584, NULL }, + { "atilde", 556, NULL }, + { "brokenbar", 280, NULL }, + { "quoteleft", 278, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 333, NULL } +}; + +static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 278, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 584, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, + { "asciitilde", 584, NULL }, + { "colon", 333, NULL }, + { "onehalf", 834, NULL }, + { "dollar", 556, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 611, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 611, NULL }, + { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, + { "yen", 556, NULL }, + { "space", 278, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 611, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 722, NULL }, + { "three", 556, NULL }, + { "numbersign", 556, NULL }, + { "lcaron", 400, NULL }, + { "A", 722, NULL }, + { "B", 722, NULL }, + { "C", 722, NULL }, + { "aogonek", 556, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 834, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 722, NULL }, + { "I", 278, NULL }, + { "J", 556, NULL }, + { "K", 722, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 611, NULL }, + { "periodcentered", 278, NULL }, + { "M", 833, NULL }, + { "N", 722, NULL }, + { "omacron", 611, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 778, NULL }, + { "P", 667, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 722, NULL }, + { "caron", 333, NULL }, + { "S", 667, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 556, NULL }, + { "V", 667, NULL }, + { "W", 944, NULL }, + { "X", 667, NULL }, + { "question", 611, NULL }, + { "equal", 584, NULL }, + { "Y", 667, NULL }, + { "Z", 611, NULL }, + { "four", 556, NULL }, + { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 611, NULL }, + { "c", 556, NULL }, + { "d", 611, NULL }, + { "e", 556, NULL }, + { "f", 333, NULL }, + { "g", 611, NULL }, + { "bullet", 350, NULL }, + { "h", 611, NULL }, + { "i", 278, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 556, NULL }, + { "j", 278, NULL }, + { "k", 556, NULL }, + { "l", 278, NULL }, + { "m", 889, NULL }, + { "n", 611, NULL }, + { "tcommaaccent", 333, NULL }, + { "o", 611, NULL }, + { "ordfeminine", 370, NULL }, + { "ring", 333, NULL }, + { "p", 611, NULL }, + { "q", 611, NULL }, + { "uhungarumlaut", 611, NULL }, + { "r", 389, NULL }, + { "twosuperior", 333, NULL }, + { "aacute", 556, NULL }, + { "s", 556, NULL }, + { "OE", 1000, NULL }, + { "t", 333, NULL }, + { "divide", 584, NULL }, + { "u", 611, NULL }, + { "Ccaron", 722, NULL }, + { "v", 556, NULL }, + { "w", 778, NULL }, + { "x", 556, NULL }, + { "y", 556, NULL }, + { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 474, NULL }, + { "gcommaaccent", 611, NULL }, + { "mu", 611, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 667, NULL }, + { "Lslash", 611, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 556, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 611, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 556, NULL }, + { "nacute", 611, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 556, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 500, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 238, NULL }, + { "eight", 556, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 556, NULL }, + { "oe", 944, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 556, NULL }, + { "Adieresis", 722, NULL }, + { "copyright", 737, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 611, NULL }, + { "Idieresis", 278, NULL }, + { "parenleft", 333, NULL }, + { "one", 556, NULL }, + { "emacron", 556, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 611, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 278, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 667, NULL }, + { "umacron", 611, NULL }, + { "abreve", 556, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 556, NULL }, + { "egrave", 556, NULL }, + { "edieresis", 556, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 889, NULL }, + { "asterisk", 389, NULL }, + { "odieresis", 611, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 611, NULL }, + { "nine", 556, NULL }, + { "five", 556, NULL }, + { "udieresis", 611, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, + { "threequarters", 834, NULL }, + { "guillemotright", 556, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 556, NULL }, + { "tilde", 333, NULL }, + { "at", 975, NULL }, + { "eacute", 556, NULL }, + { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 584, NULL }, + { "zero", 556, NULL }, + { "eth", 611, NULL }, + { "Scedilla", 667, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, + { "uacute", 611, NULL }, + { "braceleft", 389, NULL }, + { "Thorn", 667, NULL }, + { "zcaron", 500, NULL }, + { "scommaaccent", 556, NULL }, + { "ccedilla", 556, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 611, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 556, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 611, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 611, NULL }, + { "degree", 400, NULL }, + { "registered", 737, NULL }, + { "radical", 549, NULL }, + { "Aring", 722, NULL }, + { "percent", 889, NULL }, + { "six", 556, NULL }, + { "paragraph", 556, NULL }, + { "dcaron", 743, NULL }, + { "Uogonek", 722, NULL }, + { "two", 556, NULL }, + { "summation", 600, NULL }, + { "Igrave", 278, NULL }, + { "Lacute", 611, NULL }, + { "ocircumflex", 611, NULL }, + { "oacute", 611, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 389, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 584, NULL }, + { "aring", 556, NULL }, + { "grave", 333, NULL }, + { "uogonek", 611, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 278, NULL }, + { "ampersand", 722, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 584, NULL }, + { "uring", 611, NULL }, + { "quotesinglbase", 278, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 667, NULL }, + { "ohungarumlaut", 611, NULL }, + { "threesuperior", 333, NULL }, + { "acute", 333, NULL }, + { "section", 556, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 500, NULL }, + { "ncaron", 611, NULL }, + { "florin", 556, NULL }, + { "yacute", 556, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 611, NULL }, + { "fl", 611, NULL }, + { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 278, NULL }, + { "guillemotleft", 556, NULL }, + { "germandbls", 611, NULL }, + { "Amacron", 722, NULL }, + { "seven", 556, NULL }, + { "Sacute", 667, NULL }, + { "ordmasculine", 365, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 556, NULL }, + { "cacute", 556, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 389, NULL }, + { "quotedblright", 500, NULL }, + { "amacron", 556, NULL }, + { "sacute", 556, NULL }, + { "imacron", 278, NULL }, + { "cent", 556, NULL }, + { "currency", 556, NULL }, + { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, + { "Atilde", 722, NULL }, + { "breve", 333, NULL }, + { "bar", 280, NULL }, + { "fraction", 167, NULL }, + { "less", 584, NULL }, + { "ecaron", 556, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 722, NULL }, + { "greater", 584, NULL }, + { "atilde", 556, NULL }, + { "brokenbar", 280, NULL }, + { "quoteleft", 278, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 333, NULL } +}; + +static BuiltinFontWidth helveticaObliqueWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 278, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 584, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 556, NULL }, + { "asciitilde", 584, NULL }, + { "colon", 278, NULL }, + { "onehalf", 834, NULL }, + { "dollar", 556, NULL }, + { "Lcaron", 556, NULL }, + { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, + { "minus", 584, NULL }, + { "Iogonek", 278, NULL }, + { "zacute", 500, NULL }, + { "yen", 556, NULL }, + { "space", 278, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 611, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 667, NULL }, + { "three", 556, NULL }, + { "numbersign", 556, NULL }, + { "lcaron", 299, NULL }, + { "A", 667, NULL }, + { "B", 667, NULL }, + { "C", 722, NULL }, + { "aogonek", 556, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 834, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 722, NULL }, + { "I", 278, NULL }, + { "J", 500, NULL }, + { "K", 667, NULL }, + { "iogonek", 222, NULL }, + { "backslash", 278, NULL }, + { "L", 556, NULL }, + { "periodcentered", 278, NULL }, + { "M", 833, NULL }, + { "N", 722, NULL }, + { "omacron", 556, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 778, NULL }, + { "P", 667, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 667, NULL }, + { "caron", 333, NULL }, + { "S", 667, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 556, NULL }, + { "V", 667, NULL }, + { "W", 944, NULL }, + { "X", 667, NULL }, + { "question", 556, NULL }, + { "equal", 584, NULL }, + { "Y", 667, NULL }, + { "Z", 611, NULL }, + { "four", 556, NULL }, + { "a", 556, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 556, NULL }, + { "c", 500, NULL }, + { "d", 556, NULL }, + { "e", 556, NULL }, + { "f", 278, NULL }, + { "g", 556, NULL }, + { "bullet", 350, NULL }, + { "h", 556, NULL }, + { "i", 222, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 556, NULL }, + { "j", 222, NULL }, + { "k", 500, NULL }, + { "l", 222, NULL }, + { "m", 833, NULL }, + { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 556, NULL }, + { "ordfeminine", 370, NULL }, + { "ring", 333, NULL }, + { "p", 556, NULL }, + { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, + { "r", 333, NULL }, + { "twosuperior", 333, NULL }, + { "aacute", 556, NULL }, + { "s", 500, NULL }, + { "OE", 1000, NULL }, + { "t", 278, NULL }, + { "divide", 584, NULL }, + { "u", 556, NULL }, + { "Ccaron", 722, NULL }, + { "v", 500, NULL }, + { "w", 722, NULL }, + { "x", 500, NULL }, + { "y", 500, NULL }, + { "z", 500, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 278, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 355, NULL }, + { "gcommaaccent", 556, NULL }, + { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 667, NULL }, + { "Lslash", 556, NULL }, + { "semicolon", 278, NULL }, + { "oslash", 611, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 500, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 556, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 556, NULL }, + { "nacute", 556, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 500, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 222, NULL }, + { "quotedblleft", 333, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 191, NULL }, + { "eight", 556, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 556, NULL }, + { "oe", 944, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 556, NULL }, + { "Adieresis", 667, NULL }, + { "copyright", 737, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 556, NULL }, + { "Idieresis", 278, NULL }, + { "parenleft", 333, NULL }, + { "one", 556, NULL }, + { "emacron", 556, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, + { "bracketleft", 278, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 222, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 667, NULL }, + { "umacron", 556, NULL }, + { "abreve", 556, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 556, NULL }, + { "egrave", 556, NULL }, + { "edieresis", 556, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 889, NULL }, + { "asterisk", 389, NULL }, + { "odieresis", 556, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 556, NULL }, + { "nine", 556, NULL }, + { "five", 556, NULL }, + { "udieresis", 556, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 667, NULL }, + { "threequarters", 834, NULL }, + { "guillemotright", 556, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, + { "tilde", 333, NULL }, + { "at", 1015, NULL }, + { "eacute", 556, NULL }, + { "underscore", 556, NULL }, + { "Euro", 556, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 584, NULL }, + { "zero", 556, NULL }, + { "eth", 556, NULL }, + { "Scedilla", 667, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 476, NULL }, + { "uacute", 556, NULL }, + { "braceleft", 334, NULL }, + { "Thorn", 667, NULL }, + { "zcaron", 500, NULL }, + { "scommaaccent", 500, NULL }, + { "ccedilla", 500, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 500, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 556, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 556, NULL }, + { "degree", 400, NULL }, + { "registered", 737, NULL }, + { "radical", 453, NULL }, + { "Aring", 667, NULL }, + { "percent", 889, NULL }, + { "six", 556, NULL }, + { "paragraph", 537, NULL }, + { "dcaron", 643, NULL }, + { "Uogonek", 722, NULL }, + { "two", 556, NULL }, + { "summation", 600, NULL }, + { "Igrave", 278, NULL }, + { "Lacute", 556, NULL }, + { "ocircumflex", 556, NULL }, + { "oacute", 556, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 317, NULL }, + { "eogonek", 556, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 469, NULL }, + { "aring", 556, NULL }, + { "grave", 333, NULL }, + { "uogonek", 556, NULL }, + { "bracketright", 278, NULL }, + { "Iacute", 278, NULL }, + { "ampersand", 667, NULL }, + { "igrave", 278, NULL }, + { "lacute", 222, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 584, NULL }, + { "uring", 556, NULL }, + { "quotesinglbase", 222, NULL }, + { "lcommaaccent", 222, NULL }, + { "Yacute", 667, NULL }, + { "ohungarumlaut", 556, NULL }, + { "threesuperior", 333, NULL }, + { "acute", 333, NULL }, + { "section", 556, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 333, NULL }, + { "ncaron", 556, NULL }, + { "florin", 556, NULL }, + { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 500, NULL }, + { "fl", 500, NULL }, + { "Acircumflex", 667, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 278, NULL }, + { "guillemotleft", 556, NULL }, + { "germandbls", 611, NULL }, + { "Amacron", 667, NULL }, + { "seven", 556, NULL }, + { "Sacute", 667, NULL }, + { "ordmasculine", 365, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 556, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 278, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 556, NULL }, + { "cacute", 500, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 334, NULL }, + { "quotedblright", 333, NULL }, + { "amacron", 556, NULL }, + { "sacute", 500, NULL }, + { "imacron", 278, NULL }, + { "cent", 556, NULL }, + { "currency", 556, NULL }, + { "logicalnot", 584, NULL }, + { "zdotaccent", 500, NULL }, + { "Atilde", 667, NULL }, + { "breve", 333, NULL }, + { "bar", 260, NULL }, + { "fraction", 167, NULL }, + { "less", 584, NULL }, + { "ecaron", 556, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 278, NULL }, + { "period", 278, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 667, NULL }, + { "greater", 584, NULL }, + { "atilde", 556, NULL }, + { "brokenbar", 260, NULL }, + { "quoteleft", 222, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 333, NULL } +}; + +static BuiltinFontWidth symbolWidthsTab[] = { + { "bracketleftex", 384, NULL }, + { "alpha", 631, NULL }, + { "union", 768, NULL }, + { "infinity", 713, NULL }, + { "comma", 250, NULL }, + { "copyrightsans", 790, NULL }, + { "plusminus", 549, NULL }, + { "arrowup", 603, NULL }, + { "apple", 790, NULL }, + { "parenleftbt", 384, NULL }, + { "notelement", 713, NULL }, + { "colon", 278, NULL }, + { "beta", 549, NULL }, + { "braceleftbt", 494, NULL }, + { "Lambda", 686, NULL }, + { "Phi", 763, NULL }, + { "minus", 549, NULL }, + { "space", 250, NULL }, + { "Sigma", 592, NULL }, + { "approxequal", 549, NULL }, + { "minute", 247, NULL }, + { "circleplus", 768, NULL }, + { "Omicron", 722, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lambda", 549, NULL }, + { "phi", 521, NULL }, + { "aleph", 823, NULL }, + { "Tau", 611, NULL }, + { "spade", 753, NULL }, + { "logicaland", 603, NULL }, + { "sigma", 603, NULL }, + { "propersuperset", 713, NULL }, + { "omicron", 549, NULL }, + { "question", 444, NULL }, + { "equal", 549, NULL }, + { "Epsilon", 611, NULL }, + { "emptyset", 823, NULL }, + { "diamond", 753, NULL }, + { "four", 500, NULL }, + { "Mu", 889, NULL }, + { "parenlefttp", 384, NULL }, + { "club", 753, NULL }, + { "bullet", 460, NULL }, + { "Omega", 768, NULL }, + { "tau", 439, NULL }, + { "Upsilon", 690, NULL }, + { "bracelefttp", 494, NULL }, + { "heart", 753, NULL }, + { "divide", 549, NULL }, + { "epsilon", 439, NULL }, + { "logicalor", 603, NULL }, + { "parenleftex", 384, NULL }, + { "greaterequal", 549, NULL }, + { "mu", 576, NULL }, + { "Nu", 722, NULL }, + { "therefore", 863, NULL }, + { "notsubset", 713, NULL }, + { "omega", 686, NULL }, + { "semicolon", 278, NULL }, + { "element", 713, NULL }, + { "upsilon", 576, NULL }, + { "existential", 549, NULL }, + { "integralbt", 686, NULL }, + { "lessequal", 549, NULL }, + { "phi1", 603, NULL }, + { "lozenge", 494, NULL }, + { "trademarkserif", 890, NULL }, + { "parenright", 333, NULL }, + { "reflexsuperset", 713, NULL }, + { "sigma1", 439, NULL }, + { "nu", 521, NULL }, + { "Gamma", 603, NULL }, + { "angleright", 329, NULL }, + { "ellipsis", 1000, NULL }, + { "Rho", 556, NULL }, + { "parenrightbt", 384, NULL }, + { "radicalex", 500, NULL }, + { "eight", 500, NULL }, + { "angleleft", 329, NULL }, + { "arrowdbldown", 603, NULL }, + { "congruent", 549, NULL }, + { "Theta", 741, NULL }, + { "intersection", 768, NULL }, + { "Pi", 768, NULL }, + { "slash", 278, NULL }, + { "registerserif", 790, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "gamma", 411, NULL }, + { "bracketleft", 333, NULL }, + { "rho", 549, NULL }, + { "circlemultiply", 768, NULL }, + { "Chi", 722, NULL }, + { "theta", 521, NULL }, + { "pi", 549, NULL }, + { "integraltp", 686, NULL }, + { "Eta", 722, NULL }, + { "product", 823, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "propersubset", 713, NULL }, + { "bracketrightbt", 384, NULL }, + { "trademarksans", 786, NULL }, + { "dotmath", 250, NULL }, + { "integralex", 686, NULL }, + { "chi", 549, NULL }, + { "parenrighttp", 384, NULL }, + { "eta", 603, NULL }, + { "underscore", 500, NULL }, + { "Euro", 750, NULL }, + { "multiply", 549, NULL }, + { "zero", 500, NULL }, + { "partialdiff", 494, NULL }, + { "angle", 768, NULL }, + { "arrowdblleft", 987, NULL }, + { "braceleft", 480, NULL }, + { "parenrightex", 384, NULL }, + { "Rfraktur", 795, NULL }, + { "Zeta", 611, NULL }, + { "braceex", 494, NULL }, + { "arrowdblup", 603, NULL }, + { "arrowdown", 603, NULL }, + { "Ifraktur", 686, NULL }, + { "degree", 400, NULL }, + { "Iota", 333, NULL }, + { "perpendicular", 658, NULL }, + { "radical", 549, NULL }, + { "asteriskmath", 500, NULL }, + { "percent", 833, NULL }, + { "zeta", 494, NULL }, + { "six", 500, NULL }, + { "two", 500, NULL }, + { "weierstrass", 987, NULL }, + { "summation", 713, NULL }, + { "bracketrighttp", 384, NULL }, + { "carriagereturn", 658, NULL }, + { "suchthat", 439, NULL }, + { "arrowvertex", 603, NULL }, + { "Delta", 612, NULL }, + { "iota", 329, NULL }, + { "arrowhorizex", 1000, NULL }, + { "bracketrightex", 384, NULL }, + { "bracketright", 333, NULL }, + { "ampersand", 778, NULL }, + { "plus", 549, NULL }, + { "proportional", 713, NULL }, + { "delta", 494, NULL }, + { "copyrightserif", 790, NULL }, + { "bracerightmid", 494, NULL }, + { "arrowleft", 987, NULL }, + { "second", 411, NULL }, + { "arrowdblboth", 1042, NULL }, + { "florin", 500, NULL }, + { "Psi", 795, NULL }, + { "bracerightbt", 494, NULL }, + { "bracketleftbt", 384, NULL }, + { "seven", 500, NULL }, + { "braceleftmid", 494, NULL }, + { "notequal", 549, NULL }, + { "psi", 686, NULL }, + { "equivalence", 549, NULL }, + { "universal", 713, NULL }, + { "arrowdblright", 987, NULL }, + { "braceright", 480, NULL }, + { "reflexsubset", 713, NULL }, + { "Xi", 645, NULL }, + { "theta1", 631, NULL }, + { "logicalnot", 713, NULL }, + { "Kappa", 722, NULL }, + { "similar", 549, NULL }, + { "bar", 200, NULL }, + { "fraction", 167, NULL }, + { "less", 549, NULL }, + { "registersans", 790, NULL }, + { "omega1", 713, NULL }, + { "exclam", 333, NULL }, + { "Upsilon1", 620, NULL }, + { "bracerighttp", 494, NULL }, + { "xi", 493, NULL }, + { "period", 250, NULL }, + { "Alpha", 722, NULL }, + { "arrowright", 987, NULL }, + { "greater", 549, NULL }, + { "bracketlefttp", 384, NULL }, + { "kappa", 549, NULL }, + { "gradient", 713, NULL }, + { "integral", 274, NULL }, + { "arrowboth", 1042, NULL }, + { "Beta", 667, NULL } +}; + +static BuiltinFontWidth timesBoldWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 444, NULL }, + { "kcommaaccent", 556, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 667, NULL }, + { "comma", 250, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 570, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, + { "asciitilde", 520, NULL }, + { "colon", 333, NULL }, + { "onehalf", 750, NULL }, + { "dollar", 500, NULL }, + { "Lcaron", 667, NULL }, + { "ntilde", 556, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 556, NULL }, + { "minus", 570, NULL }, + { "Iogonek", 389, NULL }, + { "zacute", 444, NULL }, + { "yen", 500, NULL }, + { "space", 250, NULL }, + { "Omacron", 778, NULL }, + { "questiondown", 500, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 722, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lcaron", 394, NULL }, + { "A", 722, NULL }, + { "B", 667, NULL }, + { "C", 722, NULL }, + { "aogonek", 500, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 750, NULL }, + { "F", 611, NULL }, + { "G", 778, NULL }, + { "H", 778, NULL }, + { "I", 389, NULL }, + { "J", 500, NULL }, + { "K", 778, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 667, NULL }, + { "periodcentered", 250, NULL }, + { "M", 944, NULL }, + { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 667, NULL }, + { "O", 778, NULL }, + { "P", 611, NULL }, + { "Q", 778, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 722, NULL }, + { "Aacute", 722, NULL }, + { "caron", 333, NULL }, + { "S", 556, NULL }, + { "T", 667, NULL }, + { "U", 722, NULL }, + { "agrave", 500, NULL }, + { "V", 722, NULL }, + { "W", 1000, NULL }, + { "X", 722, NULL }, + { "question", 500, NULL }, + { "equal", 570, NULL }, + { "Y", 722, NULL }, + { "Z", 667, NULL }, + { "four", 500, NULL }, + { "a", 500, NULL }, + { "Gcommaaccent", 778, NULL }, + { "b", 556, NULL }, + { "c", 444, NULL }, + { "d", 556, NULL }, + { "e", 444, NULL }, + { "f", 333, NULL }, + { "g", 500, NULL }, + { "bullet", 350, NULL }, + { "h", 556, NULL }, + { "i", 278, NULL }, + { "Oslash", 778, NULL }, + { "dagger", 500, NULL }, + { "j", 333, NULL }, + { "k", 556, NULL }, + { "l", 278, NULL }, + { "m", 833, NULL }, + { "n", 556, NULL }, + { "tcommaaccent", 333, NULL }, + { "o", 500, NULL }, + { "ordfeminine", 300, NULL }, + { "ring", 333, NULL }, + { "p", 556, NULL }, + { "q", 556, NULL }, + { "uhungarumlaut", 556, NULL }, + { "r", 444, NULL }, + { "twosuperior", 300, NULL }, + { "aacute", 500, NULL }, + { "s", 389, NULL }, + { "OE", 1000, NULL }, + { "t", 333, NULL }, + { "divide", 570, NULL }, + { "u", 556, NULL }, + { "Ccaron", 722, NULL }, + { "v", 500, NULL }, + { "w", 722, NULL }, + { "x", 500, NULL }, + { "y", 500, NULL }, + { "z", 444, NULL }, + { "Gbreve", 778, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 389, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 555, NULL }, + { "gcommaaccent", 500, NULL }, + { "mu", 556, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 556, NULL }, + { "Lslash", 667, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 500, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 500, NULL }, + { "nacute", 556, NULL }, + { "macron", 333, NULL }, + { "Otilde", 778, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 389, NULL }, + { "AE", 1000, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 500, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 278, NULL }, + { "eight", 500, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 500, NULL }, + { "oe", 722, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 444, NULL }, + { "Adieresis", 722, NULL }, + { "copyright", 747, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 500, NULL }, + { "Idieresis", 389, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "emacron", 444, NULL }, + { "Odieresis", 778, NULL }, + { "ucircumflex", 556, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 333, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 722, NULL }, + { "umacron", 556, NULL }, + { "abreve", 500, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 500, NULL }, + { "egrave", 444, NULL }, + { "edieresis", 444, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 722, NULL }, + { "asterisk", 500, NULL }, + { "odieresis", 500, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 556, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "udieresis", 556, NULL }, + { "Zcaron", 667, NULL }, + { "Scommaaccent", 556, NULL }, + { "threequarters", 750, NULL }, + { "guillemotright", 500, NULL }, + { "Ccedilla", 722, NULL }, + { "ydieresis", 500, NULL }, + { "tilde", 333, NULL }, + { "at", 930, NULL }, + { "eacute", 444, NULL }, + { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 570, NULL }, + { "zero", 500, NULL }, + { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, + { "Ograve", 778, NULL }, + { "Racute", 722, NULL }, + { "partialdiff", 494, NULL }, + { "uacute", 556, NULL }, + { "braceleft", 394, NULL }, + { "Thorn", 611, NULL }, + { "zcaron", 444, NULL }, + { "scommaaccent", 389, NULL }, + { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 556, NULL }, + { "Ocircumflex", 778, NULL }, + { "Oacute", 778, NULL }, + { "scedilla", 389, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 500, NULL }, + { "racute", 444, NULL }, + { "Tcaron", 667, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 556, NULL }, + { "degree", 400, NULL }, + { "registered", 747, NULL }, + { "radical", 549, NULL }, + { "Aring", 722, NULL }, + { "percent", 1000, NULL }, + { "six", 500, NULL }, + { "paragraph", 540, NULL }, + { "dcaron", 672, NULL }, + { "Uogonek", 722, NULL }, + { "two", 500, NULL }, + { "summation", 600, NULL }, + { "Igrave", 389, NULL }, + { "Lacute", 667, NULL }, + { "ocircumflex", 500, NULL }, + { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 667, NULL }, + { "tcaron", 416, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 778, NULL }, + { "asciicircum", 581, NULL }, + { "aring", 500, NULL }, + { "grave", 333, NULL }, + { "uogonek", 556, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 389, NULL }, + { "ampersand", 833, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 570, NULL }, + { "uring", 556, NULL }, + { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 722, NULL }, + { "ohungarumlaut", 500, NULL }, + { "threesuperior", 300, NULL }, + { "acute", 333, NULL }, + { "section", 500, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 500, NULL }, + { "ncaron", 556, NULL }, + { "florin", 500, NULL }, + { "yacute", 500, NULL }, + { "Rcommaaccent", 722, NULL }, + { "fi", 556, NULL }, + { "fl", 556, NULL }, + { "Acircumflex", 722, NULL }, + { "Cacute", 722, NULL }, + { "Icircumflex", 389, NULL }, + { "guillemotleft", 500, NULL }, + { "germandbls", 556, NULL }, + { "Amacron", 722, NULL }, + { "seven", 500, NULL }, + { "Sacute", 556, NULL }, + { "ordmasculine", 330, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 389, NULL }, + { "rcommaaccent", 444, NULL }, + { "Zdotaccent", 667, NULL }, + { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 394, NULL }, + { "quotedblright", 500, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, + { "cent", 500, NULL }, + { "currency", 500, NULL }, + { "logicalnot", 570, NULL }, + { "zdotaccent", 444, NULL }, + { "Atilde", 722, NULL }, + { "breve", 333, NULL }, + { "bar", 220, NULL }, + { "fraction", 167, NULL }, + { "less", 570, NULL }, + { "ecaron", 444, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 250, NULL }, + { "Rcaron", 722, NULL }, + { "Kcommaaccent", 778, NULL }, + { "greater", 570, NULL }, + { "atilde", 500, NULL }, + { "brokenbar", 220, NULL }, + { "quoteleft", 333, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 300, NULL } +}; + +static BuiltinFontWidth timesBoldItalicWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 250, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 570, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, + { "asciitilde", 570, NULL }, + { "colon", 333, NULL }, + { "onehalf", 750, NULL }, + { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 556, NULL }, + { "Aogonek", 667, NULL }, + { "ncommaaccent", 556, NULL }, + { "minus", 606, NULL }, + { "Iogonek", 389, NULL }, + { "zacute", 389, NULL }, + { "yen", 500, NULL }, + { "space", 250, NULL }, + { "Omacron", 722, NULL }, + { "questiondown", 500, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 667, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lcaron", 382, NULL }, + { "A", 667, NULL }, + { "B", 667, NULL }, + { "C", 667, NULL }, + { "aogonek", 500, NULL }, + { "D", 722, NULL }, + { "E", 667, NULL }, + { "onequarter", 750, NULL }, + { "F", 667, NULL }, + { "G", 722, NULL }, + { "H", 778, NULL }, + { "I", 389, NULL }, + { "J", 500, NULL }, + { "K", 667, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 611, NULL }, + { "periodcentered", 250, NULL }, + { "M", 889, NULL }, + { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 722, NULL }, + { "P", 611, NULL }, + { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 667, NULL }, + { "Aacute", 667, NULL }, + { "caron", 333, NULL }, + { "S", 556, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 500, NULL }, + { "V", 667, NULL }, + { "W", 889, NULL }, + { "X", 667, NULL }, + { "question", 500, NULL }, + { "equal", 570, NULL }, + { "Y", 611, NULL }, + { "Z", 611, NULL }, + { "four", 500, NULL }, + { "a", 500, NULL }, + { "Gcommaaccent", 722, NULL }, + { "b", 500, NULL }, + { "c", 444, NULL }, + { "d", 500, NULL }, + { "e", 444, NULL }, + { "f", 333, NULL }, + { "g", 500, NULL }, + { "bullet", 350, NULL }, + { "h", 556, NULL }, + { "i", 278, NULL }, + { "Oslash", 722, NULL }, + { "dagger", 500, NULL }, + { "j", 278, NULL }, + { "k", 500, NULL }, + { "l", 278, NULL }, + { "m", 778, NULL }, + { "n", 556, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 500, NULL }, + { "ordfeminine", 266, NULL }, + { "ring", 333, NULL }, + { "p", 500, NULL }, + { "q", 500, NULL }, + { "uhungarumlaut", 556, NULL }, + { "r", 389, NULL }, + { "twosuperior", 300, NULL }, + { "aacute", 500, NULL }, + { "s", 389, NULL }, + { "OE", 944, NULL }, + { "t", 278, NULL }, + { "divide", 570, NULL }, + { "u", 556, NULL }, + { "Ccaron", 667, NULL }, + { "v", 444, NULL }, + { "w", 667, NULL }, + { "x", 500, NULL }, + { "y", 444, NULL }, + { "z", 389, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 389, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 555, NULL }, + { "gcommaaccent", 500, NULL }, + { "mu", 576, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 556, NULL }, + { "Lslash", 611, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 494, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, + { "Ecircumflex", 667, NULL }, + { "gbreve", 500, NULL }, + { "trademark", 1000, NULL }, + { "daggerdbl", 500, NULL }, + { "nacute", 556, NULL }, + { "macron", 333, NULL }, + { "Otilde", 722, NULL }, + { "Emacron", 667, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 389, NULL }, + { "AE", 944, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 500, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 278, NULL }, + { "eight", 500, NULL }, + { "exclamdown", 389, NULL }, + { "endash", 500, NULL }, + { "oe", 722, NULL }, + { "Abreve", 667, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 444, NULL }, + { "Adieresis", 667, NULL }, + { "copyright", 747, NULL }, + { "Egrave", 667, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 667, NULL }, + { "otilde", 500, NULL }, + { "Idieresis", 389, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "emacron", 444, NULL }, + { "Odieresis", 722, NULL }, + { "ucircumflex", 556, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 333, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 611, NULL }, + { "umacron", 556, NULL }, + { "abreve", 500, NULL }, + { "Eacute", 667, NULL }, + { "adieresis", 500, NULL }, + { "egrave", 444, NULL }, + { "edieresis", 444, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 722, NULL }, + { "asterisk", 500, NULL }, + { "odieresis", 500, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 556, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "udieresis", 556, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 556, NULL }, + { "threequarters", 750, NULL }, + { "guillemotright", 500, NULL }, + { "Ccedilla", 667, NULL }, + { "ydieresis", 444, NULL }, + { "tilde", 333, NULL }, + { "at", 832, NULL }, + { "eacute", 444, NULL }, + { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 570, NULL }, + { "zero", 500, NULL }, + { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, + { "Ograve", 722, NULL }, + { "Racute", 667, NULL }, + { "partialdiff", 494, NULL }, + { "uacute", 556, NULL }, + { "braceleft", 348, NULL }, + { "Thorn", 611, NULL }, + { "zcaron", 389, NULL }, + { "scommaaccent", 389, NULL }, + { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, + { "Ocircumflex", 722, NULL }, + { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 500, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 667, NULL }, + { "thorn", 500, NULL }, + { "degree", 400, NULL }, + { "registered", 747, NULL }, + { "radical", 549, NULL }, + { "Aring", 667, NULL }, + { "percent", 833, NULL }, + { "six", 500, NULL }, + { "paragraph", 500, NULL }, + { "dcaron", 608, NULL }, + { "Uogonek", 722, NULL }, + { "two", 500, NULL }, + { "summation", 600, NULL }, + { "Igrave", 389, NULL }, + { "Lacute", 611, NULL }, + { "ocircumflex", 500, NULL }, + { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 366, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, + { "asciicircum", 570, NULL }, + { "aring", 500, NULL }, + { "grave", 333, NULL }, + { "uogonek", 556, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 389, NULL }, + { "ampersand", 778, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 570, NULL }, + { "uring", 556, NULL }, + { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 611, NULL }, + { "ohungarumlaut", 500, NULL }, + { "threesuperior", 300, NULL }, + { "acute", 333, NULL }, + { "section", 500, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 500, NULL }, + { "ncaron", 556, NULL }, + { "florin", 500, NULL }, + { "yacute", 444, NULL }, + { "Rcommaaccent", 667, NULL }, + { "fi", 556, NULL }, + { "fl", 556, NULL }, + { "Acircumflex", 667, NULL }, + { "Cacute", 667, NULL }, + { "Icircumflex", 389, NULL }, + { "guillemotleft", 500, NULL }, + { "germandbls", 500, NULL }, + { "Amacron", 667, NULL }, + { "seven", 500, NULL }, + { "Sacute", 556, NULL }, + { "ordmasculine", 300, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 389, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 667, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 348, NULL }, + { "quotedblright", 500, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, + { "cent", 500, NULL }, + { "currency", 500, NULL }, + { "logicalnot", 606, NULL }, + { "zdotaccent", 389, NULL }, + { "Atilde", 667, NULL }, + { "breve", 333, NULL }, + { "bar", 220, NULL }, + { "fraction", 167, NULL }, + { "less", 570, NULL }, + { "ecaron", 444, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 389, NULL }, + { "period", 250, NULL }, + { "Rcaron", 667, NULL }, + { "Kcommaaccent", 667, NULL }, + { "greater", 570, NULL }, + { "atilde", 500, NULL }, + { "brokenbar", 220, NULL }, + { "quoteleft", 333, NULL }, + { "Edotaccent", 667, NULL }, + { "onesuperior", 300, NULL } +}; + +static BuiltinFontWidth timesItalicWidthsTab[] = { + { "Ntilde", 667, NULL }, + { "rcaron", 389, NULL }, + { "kcommaaccent", 444, NULL }, + { "Ncommaaccent", 667, NULL }, + { "Zacute", 556, NULL }, + { "comma", 250, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 675, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, + { "asciitilde", 541, NULL }, + { "colon", 333, NULL }, + { "onehalf", 750, NULL }, + { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 500, NULL }, + { "Aogonek", 611, NULL }, + { "ncommaaccent", 500, NULL }, + { "minus", 675, NULL }, + { "Iogonek", 333, NULL }, + { "zacute", 389, NULL }, + { "yen", 500, NULL }, + { "space", 250, NULL }, + { "Omacron", 722, NULL }, + { "questiondown", 500, NULL }, + { "emdash", 889, NULL }, + { "Agrave", 611, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lcaron", 300, NULL }, + { "A", 611, NULL }, + { "B", 611, NULL }, + { "C", 667, NULL }, + { "aogonek", 500, NULL }, + { "D", 722, NULL }, + { "E", 611, NULL }, + { "onequarter", 750, NULL }, + { "F", 611, NULL }, + { "G", 722, NULL }, + { "H", 722, NULL }, + { "I", 333, NULL }, + { "J", 444, NULL }, + { "K", 667, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 556, NULL }, + { "periodcentered", 250, NULL }, + { "M", 833, NULL }, + { "N", 667, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 556, NULL }, + { "O", 722, NULL }, + { "P", 611, NULL }, + { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 611, NULL }, + { "Aacute", 611, NULL }, + { "caron", 333, NULL }, + { "S", 500, NULL }, + { "T", 556, NULL }, + { "U", 722, NULL }, + { "agrave", 500, NULL }, + { "V", 611, NULL }, + { "W", 833, NULL }, + { "X", 611, NULL }, + { "question", 500, NULL }, + { "equal", 675, NULL }, + { "Y", 556, NULL }, + { "Z", 556, NULL }, + { "four", 500, NULL }, + { "a", 500, NULL }, + { "Gcommaaccent", 722, NULL }, + { "b", 500, NULL }, + { "c", 444, NULL }, + { "d", 500, NULL }, + { "e", 444, NULL }, + { "f", 278, NULL }, + { "g", 500, NULL }, + { "bullet", 350, NULL }, + { "h", 500, NULL }, + { "i", 278, NULL }, + { "Oslash", 722, NULL }, + { "dagger", 500, NULL }, + { "j", 278, NULL }, + { "k", 444, NULL }, + { "l", 278, NULL }, + { "m", 722, NULL }, + { "n", 500, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 500, NULL }, + { "ordfeminine", 276, NULL }, + { "ring", 333, NULL }, + { "p", 500, NULL }, + { "q", 500, NULL }, + { "uhungarumlaut", 500, NULL }, + { "r", 389, NULL }, + { "twosuperior", 300, NULL }, + { "aacute", 500, NULL }, + { "s", 389, NULL }, + { "OE", 944, NULL }, + { "t", 278, NULL }, + { "divide", 675, NULL }, + { "u", 500, NULL }, + { "Ccaron", 667, NULL }, + { "v", 444, NULL }, + { "w", 667, NULL }, + { "x", 444, NULL }, + { "y", 444, NULL }, + { "z", 389, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 333, NULL }, + { "Nacute", 667, NULL }, + { "quotedbl", 420, NULL }, + { "gcommaaccent", 500, NULL }, + { "mu", 500, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 500, NULL }, + { "Lslash", 556, NULL }, + { "semicolon", 333, NULL }, + { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, + { "Ecircumflex", 611, NULL }, + { "gbreve", 500, NULL }, + { "trademark", 980, NULL }, + { "daggerdbl", 500, NULL }, + { "nacute", 500, NULL }, + { "macron", 333, NULL }, + { "Otilde", 722, NULL }, + { "Emacron", 611, NULL }, + { "ellipsis", 889, NULL }, + { "scaron", 389, NULL }, + { "AE", 889, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 556, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 214, NULL }, + { "eight", 500, NULL }, + { "exclamdown", 389, NULL }, + { "endash", 500, NULL }, + { "oe", 667, NULL }, + { "Abreve", 611, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 444, NULL }, + { "Adieresis", 611, NULL }, + { "copyright", 760, NULL }, + { "Egrave", 611, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 611, NULL }, + { "otilde", 500, NULL }, + { "Idieresis", 333, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "emacron", 444, NULL }, + { "Odieresis", 722, NULL }, + { "ucircumflex", 500, NULL }, + { "bracketleft", 389, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 333, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 556, NULL }, + { "umacron", 500, NULL }, + { "abreve", 500, NULL }, + { "Eacute", 611, NULL }, + { "adieresis", 500, NULL }, + { "egrave", 444, NULL }, + { "edieresis", 444, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 667, NULL }, + { "asterisk", 500, NULL }, + { "odieresis", 500, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 500, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "udieresis", 500, NULL }, + { "Zcaron", 556, NULL }, + { "Scommaaccent", 500, NULL }, + { "threequarters", 750, NULL }, + { "guillemotright", 500, NULL }, + { "Ccedilla", 667, NULL }, + { "ydieresis", 444, NULL }, + { "tilde", 333, NULL }, + { "at", 920, NULL }, + { "eacute", 444, NULL }, + { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 675, NULL }, + { "zero", 500, NULL }, + { "eth", 500, NULL }, + { "Scedilla", 500, NULL }, + { "Ograve", 722, NULL }, + { "Racute", 611, NULL }, + { "partialdiff", 476, NULL }, + { "uacute", 500, NULL }, + { "braceleft", 400, NULL }, + { "Thorn", 611, NULL }, + { "zcaron", 389, NULL }, + { "scommaaccent", 389, NULL }, + { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, + { "Ocircumflex", 722, NULL }, + { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 500, NULL }, + { "racute", 389, NULL }, + { "Tcaron", 556, NULL }, + { "Eogonek", 611, NULL }, + { "thorn", 500, NULL }, + { "degree", 400, NULL }, + { "registered", 760, NULL }, + { "radical", 453, NULL }, + { "Aring", 611, NULL }, + { "percent", 833, NULL }, + { "six", 500, NULL }, + { "paragraph", 523, NULL }, + { "dcaron", 544, NULL }, + { "Uogonek", 722, NULL }, + { "two", 500, NULL }, + { "summation", 600, NULL }, + { "Igrave", 333, NULL }, + { "Lacute", 556, NULL }, + { "ocircumflex", 500, NULL }, + { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 556, NULL }, + { "tcaron", 300, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, + { "asciicircum", 422, NULL }, + { "aring", 500, NULL }, + { "grave", 333, NULL }, + { "uogonek", 500, NULL }, + { "bracketright", 389, NULL }, + { "Iacute", 333, NULL }, + { "ampersand", 778, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 667, NULL }, + { "plus", 675, NULL }, + { "uring", 500, NULL }, + { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 556, NULL }, + { "ohungarumlaut", 500, NULL }, + { "threesuperior", 300, NULL }, + { "acute", 333, NULL }, + { "section", 500, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 556, NULL }, + { "ncaron", 500, NULL }, + { "florin", 500, NULL }, + { "yacute", 444, NULL }, + { "Rcommaaccent", 611, NULL }, + { "fi", 500, NULL }, + { "fl", 500, NULL }, + { "Acircumflex", 611, NULL }, + { "Cacute", 667, NULL }, + { "Icircumflex", 333, NULL }, + { "guillemotleft", 500, NULL }, + { "germandbls", 500, NULL }, + { "Amacron", 611, NULL }, + { "seven", 500, NULL }, + { "Sacute", 500, NULL }, + { "ordmasculine", 310, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 333, NULL }, + { "rcommaaccent", 389, NULL }, + { "Zdotaccent", 556, NULL }, + { "acircumflex", 500, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 611, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 400, NULL }, + { "quotedblright", 556, NULL }, + { "amacron", 500, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, + { "cent", 500, NULL }, + { "currency", 500, NULL }, + { "logicalnot", 675, NULL }, + { "zdotaccent", 389, NULL }, + { "Atilde", 611, NULL }, + { "breve", 333, NULL }, + { "bar", 275, NULL }, + { "fraction", 167, NULL }, + { "less", 675, NULL }, + { "ecaron", 444, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 250, NULL }, + { "Rcaron", 611, NULL }, + { "Kcommaaccent", 667, NULL }, + { "greater", 675, NULL }, + { "atilde", 500, NULL }, + { "brokenbar", 275, NULL }, + { "quoteleft", 333, NULL }, + { "Edotaccent", 611, NULL }, + { "onesuperior", 300, NULL } +}; + +static BuiltinFontWidth timesRomanWidthsTab[] = { + { "Ntilde", 722, NULL }, + { "rcaron", 333, NULL }, + { "kcommaaccent", 500, NULL }, + { "Ncommaaccent", 722, NULL }, + { "Zacute", 611, NULL }, + { "comma", 250, NULL }, + { "cedilla", 333, NULL }, + { "plusminus", 564, NULL }, + { "circumflex", 333, NULL }, + { "dotaccent", 333, NULL }, + { "edotaccent", 444, NULL }, + { "asciitilde", 541, NULL }, + { "colon", 278, NULL }, + { "onehalf", 750, NULL }, + { "dollar", 500, NULL }, + { "Lcaron", 611, NULL }, + { "ntilde", 500, NULL }, + { "Aogonek", 722, NULL }, + { "ncommaaccent", 500, NULL }, + { "minus", 564, NULL }, + { "Iogonek", 333, NULL }, + { "zacute", 444, NULL }, + { "yen", 500, NULL }, + { "space", 250, NULL }, + { "Omacron", 722, NULL }, + { "questiondown", 444, NULL }, + { "emdash", 1000, NULL }, + { "Agrave", 722, NULL }, + { "three", 500, NULL }, + { "numbersign", 500, NULL }, + { "lcaron", 344, NULL }, + { "A", 722, NULL }, + { "B", 667, NULL }, + { "C", 667, NULL }, + { "aogonek", 444, NULL }, + { "D", 722, NULL }, + { "E", 611, NULL }, + { "onequarter", 750, NULL }, + { "F", 556, NULL }, + { "G", 722, NULL }, + { "H", 722, NULL }, + { "I", 333, NULL }, + { "J", 389, NULL }, + { "K", 722, NULL }, + { "iogonek", 278, NULL }, + { "backslash", 278, NULL }, + { "L", 611, NULL }, + { "periodcentered", 250, NULL }, + { "M", 889, NULL }, + { "N", 722, NULL }, + { "omacron", 500, NULL }, + { "Tcommaaccent", 611, NULL }, + { "O", 722, NULL }, + { "P", 556, NULL }, + { "Q", 722, NULL }, + { "Uhungarumlaut", 722, NULL }, + { "R", 667, NULL }, + { "Aacute", 722, NULL }, + { "caron", 333, NULL }, + { "S", 556, NULL }, + { "T", 611, NULL }, + { "U", 722, NULL }, + { "agrave", 444, NULL }, + { "V", 722, NULL }, + { "W", 944, NULL }, + { "X", 722, NULL }, + { "question", 444, NULL }, + { "equal", 564, NULL }, + { "Y", 722, NULL }, + { "Z", 611, NULL }, + { "four", 500, NULL }, + { "a", 444, NULL }, + { "Gcommaaccent", 722, NULL }, + { "b", 500, NULL }, + { "c", 444, NULL }, + { "d", 500, NULL }, + { "e", 444, NULL }, + { "f", 333, NULL }, + { "g", 500, NULL }, + { "bullet", 350, NULL }, + { "h", 500, NULL }, + { "i", 278, NULL }, + { "Oslash", 722, NULL }, + { "dagger", 500, NULL }, + { "j", 278, NULL }, + { "k", 500, NULL }, + { "l", 278, NULL }, + { "m", 778, NULL }, + { "n", 500, NULL }, + { "tcommaaccent", 278, NULL }, + { "o", 500, NULL }, + { "ordfeminine", 276, NULL }, + { "ring", 333, NULL }, + { "p", 500, NULL }, + { "q", 500, NULL }, + { "uhungarumlaut", 500, NULL }, + { "r", 333, NULL }, + { "twosuperior", 300, NULL }, + { "aacute", 444, NULL }, + { "s", 389, NULL }, + { "OE", 889, NULL }, + { "t", 278, NULL }, + { "divide", 564, NULL }, + { "u", 500, NULL }, + { "Ccaron", 667, NULL }, + { "v", 500, NULL }, + { "w", 722, NULL }, + { "x", 500, NULL }, + { "y", 500, NULL }, + { "z", 444, NULL }, + { "Gbreve", 722, NULL }, + { "commaaccent", 250, NULL }, + { "hungarumlaut", 333, NULL }, + { "Idotaccent", 333, NULL }, + { "Nacute", 722, NULL }, + { "quotedbl", 408, NULL }, + { "gcommaaccent", 500, NULL }, + { "mu", 500, NULL }, + { "greaterequal", 549, NULL }, + { "Scaron", 556, NULL }, + { "Lslash", 611, NULL }, + { "semicolon", 278, NULL }, + { "oslash", 500, NULL }, + { "lessequal", 549, NULL }, + { "lozenge", 471, NULL }, + { "parenright", 333, NULL }, + { "ccaron", 444, NULL }, + { "Ecircumflex", 611, NULL }, + { "gbreve", 500, NULL }, + { "trademark", 980, NULL }, + { "daggerdbl", 500, NULL }, + { "nacute", 500, NULL }, + { "macron", 333, NULL }, + { "Otilde", 722, NULL }, + { "Emacron", 611, NULL }, + { "ellipsis", 1000, NULL }, + { "scaron", 389, NULL }, + { "AE", 889, NULL }, + { "Ucircumflex", 722, NULL }, + { "lslash", 278, NULL }, + { "quotedblleft", 444, NULL }, + { "guilsinglright", 333, NULL }, + { "hyphen", 333, NULL }, + { "quotesingle", 180, NULL }, + { "eight", 500, NULL }, + { "exclamdown", 333, NULL }, + { "endash", 500, NULL }, + { "oe", 722, NULL }, + { "Abreve", 722, NULL }, + { "Umacron", 722, NULL }, + { "ecircumflex", 444, NULL }, + { "Adieresis", 722, NULL }, + { "copyright", 760, NULL }, + { "Egrave", 611, NULL }, + { "slash", 278, NULL }, + { "Edieresis", 611, NULL }, + { "otilde", 500, NULL }, + { "Idieresis", 333, NULL }, + { "parenleft", 333, NULL }, + { "one", 500, NULL }, + { "emacron", 444, NULL }, + { "Odieresis", 722, NULL }, + { "ucircumflex", 500, NULL }, + { "bracketleft", 333, NULL }, + { "Ugrave", 722, NULL }, + { "quoteright", 333, NULL }, + { "Udieresis", 722, NULL }, + { "perthousand", 1000, NULL }, + { "Ydieresis", 722, NULL }, + { "umacron", 500, NULL }, + { "abreve", 444, NULL }, + { "Eacute", 611, NULL }, + { "adieresis", 444, NULL }, + { "egrave", 444, NULL }, + { "edieresis", 444, NULL }, + { "idieresis", 278, NULL }, + { "Eth", 722, NULL }, + { "ae", 667, NULL }, + { "asterisk", 500, NULL }, + { "odieresis", 500, NULL }, + { "Uacute", 722, NULL }, + { "ugrave", 500, NULL }, + { "nine", 500, NULL }, + { "five", 500, NULL }, + { "udieresis", 500, NULL }, + { "Zcaron", 611, NULL }, + { "Scommaaccent", 556, NULL }, + { "threequarters", 750, NULL }, + { "guillemotright", 500, NULL }, + { "Ccedilla", 667, NULL }, + { "ydieresis", 500, NULL }, + { "tilde", 333, NULL }, + { "at", 921, NULL }, + { "eacute", 444, NULL }, + { "underscore", 500, NULL }, + { "Euro", 500, NULL }, + { "Dcroat", 722, NULL }, + { "multiply", 564, NULL }, + { "zero", 500, NULL }, + { "eth", 500, NULL }, + { "Scedilla", 556, NULL }, + { "Ograve", 722, NULL }, + { "Racute", 667, NULL }, + { "partialdiff", 476, NULL }, + { "uacute", 500, NULL }, + { "braceleft", 480, NULL }, + { "Thorn", 556, NULL }, + { "zcaron", 444, NULL }, + { "scommaaccent", 389, NULL }, + { "ccedilla", 444, NULL }, + { "Dcaron", 722, NULL }, + { "dcroat", 500, NULL }, + { "Ocircumflex", 722, NULL }, + { "Oacute", 722, NULL }, + { "scedilla", 389, NULL }, + { "ogonek", 333, NULL }, + { "ograve", 500, NULL }, + { "racute", 333, NULL }, + { "Tcaron", 611, NULL }, + { "Eogonek", 611, NULL }, + { "thorn", 500, NULL }, + { "degree", 400, NULL }, + { "registered", 760, NULL }, + { "radical", 453, NULL }, + { "Aring", 722, NULL }, + { "percent", 833, NULL }, + { "six", 500, NULL }, + { "paragraph", 453, NULL }, + { "dcaron", 588, NULL }, + { "Uogonek", 722, NULL }, + { "two", 500, NULL }, + { "summation", 600, NULL }, + { "Igrave", 333, NULL }, + { "Lacute", 611, NULL }, + { "ocircumflex", 500, NULL }, + { "oacute", 500, NULL }, + { "Uring", 722, NULL }, + { "Lcommaaccent", 611, NULL }, + { "tcaron", 326, NULL }, + { "eogonek", 444, NULL }, + { "Delta", 612, NULL }, + { "Ohungarumlaut", 722, NULL }, + { "asciicircum", 469, NULL }, + { "aring", 444, NULL }, + { "grave", 333, NULL }, + { "uogonek", 500, NULL }, + { "bracketright", 333, NULL }, + { "Iacute", 333, NULL }, + { "ampersand", 778, NULL }, + { "igrave", 278, NULL }, + { "lacute", 278, NULL }, + { "Ncaron", 722, NULL }, + { "plus", 564, NULL }, + { "uring", 500, NULL }, + { "quotesinglbase", 333, NULL }, + { "lcommaaccent", 278, NULL }, + { "Yacute", 722, NULL }, + { "ohungarumlaut", 500, NULL }, + { "threesuperior", 300, NULL }, + { "acute", 333, NULL }, + { "section", 500, NULL }, + { "dieresis", 333, NULL }, + { "iacute", 278, NULL }, + { "quotedblbase", 444, NULL }, + { "ncaron", 500, NULL }, + { "florin", 500, NULL }, + { "yacute", 500, NULL }, + { "Rcommaaccent", 667, NULL }, + { "fi", 556, NULL }, + { "fl", 556, NULL }, + { "Acircumflex", 722, NULL }, + { "Cacute", 667, NULL }, + { "Icircumflex", 333, NULL }, + { "guillemotleft", 500, NULL }, + { "germandbls", 500, NULL }, + { "Amacron", 722, NULL }, + { "seven", 500, NULL }, + { "Sacute", 556, NULL }, + { "ordmasculine", 310, NULL }, + { "dotlessi", 278, NULL }, + { "sterling", 500, NULL }, + { "notequal", 549, NULL }, + { "Imacron", 333, NULL }, + { "rcommaaccent", 333, NULL }, + { "Zdotaccent", 611, NULL }, + { "acircumflex", 444, NULL }, + { "cacute", 444, NULL }, + { "Ecaron", 611, NULL }, + { "icircumflex", 278, NULL }, + { "braceright", 480, NULL }, + { "quotedblright", 444, NULL }, + { "amacron", 444, NULL }, + { "sacute", 389, NULL }, + { "imacron", 278, NULL }, + { "cent", 500, NULL }, + { "currency", 500, NULL }, + { "logicalnot", 564, NULL }, + { "zdotaccent", 444, NULL }, + { "Atilde", 722, NULL }, + { "breve", 333, NULL }, + { "bar", 200, NULL }, + { "fraction", 167, NULL }, + { "less", 564, NULL }, + { "ecaron", 444, NULL }, + { "guilsinglleft", 333, NULL }, + { "exclam", 333, NULL }, + { "period", 250, NULL }, + { "Rcaron", 667, NULL }, + { "Kcommaaccent", 722, NULL }, + { "greater", 564, NULL }, + { "atilde", 444, NULL }, + { "brokenbar", 200, NULL }, + { "quoteleft", 333, NULL }, + { "Edotaccent", 611, NULL }, + { "onesuperior", 300, NULL } +}; + +static BuiltinFontWidth zapfDingbatsWidthsTab[] = { + { "a81", 438, NULL }, + { "a82", 138, NULL }, + { "a83", 277, NULL }, + { "a84", 415, NULL }, + { "a85", 509, NULL }, + { "a86", 410, NULL }, + { "a87", 234, NULL }, + { "a88", 234, NULL }, + { "a89", 390, NULL }, + { "a140", 788, NULL }, + { "a141", 788, NULL }, + { "a142", 788, NULL }, + { "a143", 788, NULL }, + { "a144", 788, NULL }, + { "a145", 788, NULL }, + { "a146", 788, NULL }, + { "a147", 788, NULL }, + { "a148", 788, NULL }, + { "a149", 788, NULL }, + { "a90", 390, NULL }, + { "a91", 276, NULL }, + { "a92", 276, NULL }, + { "space", 278, NULL }, + { "a93", 317, NULL }, + { "a94", 317, NULL }, + { "a95", 334, NULL }, + { "a96", 334, NULL }, + { "a97", 392, NULL }, + { "a98", 392, NULL }, + { "a99", 668, NULL }, + { "a150", 788, NULL }, + { "a151", 788, NULL }, + { "a152", 788, NULL }, + { "a153", 788, NULL }, + { "a154", 788, NULL }, + { "a155", 788, NULL }, + { "a156", 788, NULL }, + { "a157", 788, NULL }, + { "a158", 788, NULL }, + { "a159", 788, NULL }, + { "a160", 894, NULL }, + { "a161", 838, NULL }, + { "a162", 924, NULL }, + { "a163", 1016, NULL }, + { "a164", 458, NULL }, + { "a165", 924, NULL }, + { "a166", 918, NULL }, + { "a167", 927, NULL }, + { "a168", 928, NULL }, + { "a169", 928, NULL }, + { "a170", 834, NULL }, + { "a171", 873, NULL }, + { "a172", 828, NULL }, + { "a173", 924, NULL }, + { "a174", 917, NULL }, + { "a175", 930, NULL }, + { "a176", 931, NULL }, + { "a177", 463, NULL }, + { "a178", 883, NULL }, + { "a179", 836, NULL }, + { "a180", 867, NULL }, + { "a181", 696, NULL }, + { "a182", 874, NULL }, + { "a183", 760, NULL }, + { "a184", 946, NULL }, + { "a185", 865, NULL }, + { "a186", 967, NULL }, + { "a187", 831, NULL }, + { "a188", 873, NULL }, + { "a189", 927, NULL }, + { "a1", 974, NULL }, + { "a2", 961, NULL }, + { "a3", 980, NULL }, + { "a4", 719, NULL }, + { "a5", 789, NULL }, + { "a6", 494, NULL }, + { "a7", 552, NULL }, + { "a8", 537, NULL }, + { "a9", 577, NULL }, + { "a190", 970, NULL }, + { "a191", 918, NULL }, + { "a192", 748, NULL }, + { "a193", 836, NULL }, + { "a194", 771, NULL }, + { "a195", 888, NULL }, + { "a196", 748, NULL }, + { "a197", 771, NULL }, + { "a198", 888, NULL }, + { "a199", 867, NULL }, + { "a10", 692, NULL }, + { "a11", 960, NULL }, + { "a12", 939, NULL }, + { "a13", 549, NULL }, + { "a14", 855, NULL }, + { "a15", 911, NULL }, + { "a16", 933, NULL }, + { "a17", 945, NULL }, + { "a18", 974, NULL }, + { "a19", 755, NULL }, + { "a20", 846, NULL }, + { "a21", 762, NULL }, + { "a22", 761, NULL }, + { "a23", 571, NULL }, + { "a24", 677, NULL }, + { "a25", 763, NULL }, + { "a26", 760, NULL }, + { "a27", 759, NULL }, + { "a28", 754, NULL }, + { "a29", 786, NULL }, + { "a30", 788, NULL }, + { "a31", 788, NULL }, + { "a32", 790, NULL }, + { "a33", 793, NULL }, + { "a34", 794, NULL }, + { "a35", 816, NULL }, + { "a36", 823, NULL }, + { "a37", 789, NULL }, + { "a38", 841, NULL }, + { "a39", 823, NULL }, + { "a40", 833, NULL }, + { "a41", 816, NULL }, + { "a42", 831, NULL }, + { "a43", 923, NULL }, + { "a44", 744, NULL }, + { "a45", 723, NULL }, + { "a46", 749, NULL }, + { "a47", 790, NULL }, + { "a48", 792, NULL }, + { "a49", 695, NULL }, + { "a100", 668, NULL }, + { "a101", 732, NULL }, + { "a102", 544, NULL }, + { "a103", 544, NULL }, + { "a104", 910, NULL }, + { "a105", 911, NULL }, + { "a106", 667, NULL }, + { "a107", 760, NULL }, + { "a108", 760, NULL }, + { "a109", 626, NULL }, + { "a50", 776, NULL }, + { "a51", 768, NULL }, + { "a52", 792, NULL }, + { "a53", 759, NULL }, + { "a54", 707, NULL }, + { "a55", 708, NULL }, + { "a56", 682, NULL }, + { "a57", 701, NULL }, + { "a58", 826, NULL }, + { "a59", 815, NULL }, + { "a110", 694, NULL }, + { "a111", 595, NULL }, + { "a112", 776, NULL }, + { "a117", 690, NULL }, + { "a118", 791, NULL }, + { "a119", 790, NULL }, + { "a60", 789, NULL }, + { "a61", 789, NULL }, + { "a62", 707, NULL }, + { "a63", 687, NULL }, + { "a64", 696, NULL }, + { "a65", 689, NULL }, + { "a66", 786, NULL }, + { "a67", 787, NULL }, + { "a68", 713, NULL }, + { "a69", 791, NULL }, + { "a200", 696, NULL }, + { "a201", 874, NULL }, + { "a120", 788, NULL }, + { "a121", 788, NULL }, + { "a202", 974, NULL }, + { "a122", 788, NULL }, + { "a203", 762, NULL }, + { "a123", 788, NULL }, + { "a204", 759, NULL }, + { "a124", 788, NULL }, + { "a205", 509, NULL }, + { "a125", 788, NULL }, + { "a206", 410, NULL }, + { "a126", 788, NULL }, + { "a127", 788, NULL }, + { "a128", 788, NULL }, + { "a129", 788, NULL }, + { "a70", 785, NULL }, + { "a71", 791, NULL }, + { "a72", 873, NULL }, + { "a73", 761, NULL }, + { "a74", 762, NULL }, + { "a75", 759, NULL }, + { "a76", 892, NULL }, + { "a77", 892, NULL }, + { "a78", 788, NULL }, + { "a79", 784, NULL }, + { "a130", 788, NULL }, + { "a131", 788, NULL }, + { "a132", 788, NULL }, + { "a133", 788, NULL }, + { "a134", 788, NULL }, + { "a135", 788, NULL }, + { "a136", 788, NULL }, + { "a137", 788, NULL }, + { "a138", 788, NULL }, + { "a139", 788, NULL } +}; + +BuiltinFont builtinFonts[] = { + { "Courier", standardEncoding, 629, -157, { -23, -250, 715, 805}, NULL }, + { "Courier-Bold", standardEncoding, 629, -157, {-113, -250, 749, 801}, NULL }, + { "Courier-BoldOblique", standardEncoding, 629, -157, { -57, -250, 869, 801}, NULL }, + { "Courier-Oblique", standardEncoding, 629, -157, { -27, -250, 849, 805}, NULL }, + { "Helvetica", standardEncoding, 718, -207, {-166, -225, 1000, 931}, NULL }, + { "Helvetica-Bold", standardEncoding, 718, -207, {-170, -228, 1003, 962}, NULL }, + { "Helvetica-BoldOblique", standardEncoding, 718, -207, {-174, -228, 1114, 962}, NULL }, + { "Helvetica-Oblique", standardEncoding, 718, -207, {-170, -225, 1116, 931}, NULL }, + { "Symbol", symbolEncoding, 1010, -293, {-180, -293, 1090, 1010}, NULL }, + { "Times-Bold", standardEncoding, 683, -217, {-168, -218, 1000, 935}, NULL }, + { "Times-BoldItalic", standardEncoding, 683, -217, {-200, -218, 996, 921}, NULL }, + { "Times-Italic", standardEncoding, 683, -217, {-169, -217, 1010, 883}, NULL }, + { "Times-Roman", standardEncoding, 683, -217, {-168, -218, 1000, 898}, NULL }, + { "ZapfDingbats", zapfDingbatsEncoding, 820, -143, { -1, -143, 981, 820}, NULL } +}; + +BuiltinFont *builtinFontSubst[] = { + &builtinFonts[0], + &builtinFonts[3], + &builtinFonts[1], + &builtinFonts[2], + &builtinFonts[4], + &builtinFonts[7], + &builtinFonts[5], + &builtinFonts[6], + &builtinFonts[12], + &builtinFonts[11], + &builtinFonts[9], + &builtinFonts[10] +}; + +void initBuiltinFontTables() { + builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 315); + builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 315); + builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 315); + builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 315); + builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 315); + builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 316); + builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 315); + builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 315); + builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 190); + builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 315); + builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 315); + builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 315); + builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 315); + builtinFonts[13].widths = new BuiltinFontWidths(zapfDingbatsWidthsTab, 202); +} + +void freeBuiltinFontTables() { + int i; + + for (i = 0; i < 14; ++i) { + delete builtinFonts[i].widths; + } +} diff --git a/pdftops/BuiltinFontTables.h b/pdftops/BuiltinFontTables.h new file mode 100644 index 000000000..eb45549ef --- /dev/null +++ b/pdftops/BuiltinFontTables.h @@ -0,0 +1,23 @@ +//======================================================================== +// +// BuiltinFontTables.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef BUILTINFONTTABLES_H +#define BUILTINFONTTABLES_H + +#include "BuiltinFont.h" + +#define nBuiltinFonts 14 +#define nBuiltinFontSubsts 12 + +extern BuiltinFont builtinFonts[nBuiltinFonts]; +extern BuiltinFont *builtinFontSubst[nBuiltinFontSubsts]; + +extern void initBuiltinFontTables(); +extern void freeBuiltinFontTables(); + +#endif diff --git a/pdftops/CMap.cxx b/pdftops/CMap.cxx new file mode 100644 index 000000000..3bcd656a5 --- /dev/null +++ b/pdftops/CMap.cxx @@ -0,0 +1,408 @@ +//======================================================================== +// +// CMap.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include "gmem.h" +#include "gfile.h" +#include "GString.h" +#include "Error.h" +#include "GlobalParams.h" +#include "PSTokenizer.h" +#include "CMap.h" + +//------------------------------------------------------------------------ + +struct CMapVectorEntry { + GBool isVector; + union { + CMapVectorEntry *vector; + CID cid; + }; +}; + +//------------------------------------------------------------------------ + +static int getCharFromFile(void *data) { + return fgetc((FILE *)data); +} + +//------------------------------------------------------------------------ + +CMap *CMap::parse(CMapCache *cache, GString *collectionA, + GString *cMapNameA) { + FILE *f; + CMap *cmap; + PSTokenizer *pst; + char tok1[256], tok2[256], tok3[256]; + int n1, n2, n3; + Guint start, end, code; + + if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) { + + // Check for an identity CMap. + if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) { + return new CMap(collectionA->copy(), cMapNameA->copy(), 0); + } + if (!cMapNameA->cmp("Identity-V")) { + return new CMap(collectionA->copy(), cMapNameA->copy(), 1); + } + + error(-1, "Couldn't find '%s' CMap file for '%s' collection", + cMapNameA->getCString(), collectionA->getCString()); + return NULL; + } + + cmap = new CMap(collectionA->copy(), cMapNameA->copy()); + + pst = new PSTokenizer(&getCharFromFile, f); + pst->getToken(tok1, sizeof(tok1), &n1); + while (pst->getToken(tok2, sizeof(tok2), &n2)) { + if (!strcmp(tok2, "usecmap")) { + if (tok1[0] == '/') { + cmap->useCMap(cache, tok1 + 1); + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok1, "/WMode")) { + cmap->wMode = atoi(tok2); + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincodespacerange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcodespacerange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcodespacerange")) { + error(-1, "Illegal entry in codespacerange block in CMap"); + break; + } + if (tok1[0] == '<' && tok2[0] == '<' && + n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { + tok1[n1 - 1] = tok2[n1 - 1] = '\0'; + sscanf(tok1 + 1, "%x", &start); + sscanf(tok2 + 1, "%x", &end); + n1 = (n1 - 2) / 2; + cmap->addCodeSpace(cmap->vector, start, end, n1); + } + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincidchar")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcidchar")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcidchar")) { + error(-1, "Illegal entry in cidchar block in CMap"); + break; + } + if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' && + n1 >= 4 && (n1 & 1) == 0)) { + error(-1, "Illegal entry in cidchar block in CMap"); + continue; + } + tok1[n1 - 1] = '\0'; + if (sscanf(tok1 + 1, "%x", &code) != 1) { + error(-1, "Illegal entry in cidchar block in CMap"); + continue; + } + n1 = (n1 - 2) / 2; + cmap->addCIDs(code, code, n1, (CID)atoi(tok2)); + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "begincidrange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endcidrange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endcidrange") || + !pst->getToken(tok3, sizeof(tok3), &n3) || + !strcmp(tok3, "endcidrange")) { + error(-1, "Illegal entry in cidrange block in CMap"); + break; + } + if (tok1[0] == '<' && tok2[0] == '<' && + n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { + tok1[n1 - 1] = tok2[n1 - 1] = '\0'; + sscanf(tok1 + 1, "%x", &start); + sscanf(tok2 + 1, "%x", &end); + n1 = (n1 - 2) / 2; + cmap->addCIDs(start, end, n1, (CID)atoi(tok3)); + } + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else { + strcpy(tok1, tok2); + } + } + delete pst; + + fclose(f); + + return cmap; +} + +CMap::CMap(GString *collectionA, GString *cMapNameA) { + int i; + + collection = collectionA; + cMapName = cMapNameA; + wMode = 0; + vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); + for (i = 0; i < 256; ++i) { + vector[i].isVector = gFalse; + vector[i].cid = 0; + } + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) { + collection = collectionA; + cMapName = cMapNameA; + wMode = wModeA; + vector = NULL; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +void CMap::useCMap(CMapCache *cache, char *useName) { + GString *useNameStr; + CMap *subCMap; + + useNameStr = new GString(useName); + subCMap = cache->getCMap(collection, useNameStr); + delete useNameStr; + if (!subCMap) { + return; + } + copyVector(vector, subCMap->vector); + subCMap->decRefCnt(); +} + +void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) { + int i, j; + + for (i = 0; i < 256; ++i) { + if (src[i].isVector) { + if (!dest[i].isVector) { + dest[i].isVector = gTrue; + dest[i].vector = + (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); + for (j = 0; j < 256; ++j) { + dest[i].vector[j].isVector = gFalse; + dest[i].vector[j].cid = 0; + } + } + copyVector(dest[i].vector, src[i].vector); + } else { + if (dest[i].isVector) { + error(-1, "Collision in usecmap"); + } else { + dest[i].cid = src[i].cid; + } + } + } +} + +void CMap::addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, + Guint nBytes) { + Guint start2, end2; + int startByte, endByte, i, j; + + if (nBytes > 1) { + startByte = (start >> (8 * (nBytes - 1))) & 0xff; + endByte = (end >> (8 * (nBytes - 1))) & 0xff; + start2 = start & ((1 << (8 * (nBytes - 1))) - 1); + end2 = end & ((1 << (8 * (nBytes - 1))) - 1); + for (i = startByte; i <= endByte; ++i) { + if (!vec[i].isVector) { + vec[i].isVector = gTrue; + vec[i].vector = + (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); + for (j = 0; j < 256; ++j) { + vec[i].vector[j].isVector = gFalse; + vec[i].vector[j].cid = 0; + } + } + addCodeSpace(vec[i].vector, start2, end2, nBytes - 1); + } + } +} + +void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { + CMapVectorEntry *vec; + CID cid; + int byte; + Guint i; + + vec = vector; + for (i = nBytes - 1; i >= 1; --i) { + byte = (start >> (8 * i)) & 0xff; + if (!vec[byte].isVector) { + error(-1, "Invalid CID (%0*x - %0*x) in CMap", + 2*nBytes, start, 2*nBytes, end); + return; + } + vec = vec[byte].vector; + } + cid = firstCID; + for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) { + if (vec[byte].isVector) { + error(-1, "Invalid CID (%0*x - %0*x) in CMap", + 2*nBytes, start, 2*nBytes, end); + } else { + vec[byte].cid = cid; + } + ++cid; + } +} + +CMap::~CMap() { + delete collection; + delete cMapName; + if (vector) { + freeCMapVector(vector); + } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +} + +void CMap::freeCMapVector(CMapVectorEntry *vec) { + int i; + + for (i = 0; i < 256; ++i) { + if (vec[i].isVector) { + freeCMapVector(vec[i].vector); + } + } + gfree(vec); +} + +void CMap::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif + ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif +} + +void CMap::decRefCnt() { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { + delete this; + } +} + +GBool CMap::match(GString *collectionA, GString *cMapNameA) { + return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA); +} + +CID CMap::getCID(char *s, int len, int *nUsed) { + CMapVectorEntry *vec; + int n, i; + + if (!(vec = vector)) { + // identity CMap + *nUsed = 2; + if (len < 2) { + return 0; + } + return ((s[0] & 0xff) << 8) + (s[1] & 0xff); + } + n = 0; + while (1) { + if (n >= len) { + *nUsed = n; + return 0; + } + i = s[n++] & 0xff; + if (!vec[i].isVector) { + *nUsed = n; + return vec[i].cid; + } + vec = vec[i].vector; + } +} + +//------------------------------------------------------------------------ + +CMapCache::CMapCache() { + int i; + + for (i = 0; i < cMapCacheSize; ++i) { + cache[i] = NULL; + } +} + +CMapCache::~CMapCache() { + int i; + + for (i = 0; i < cMapCacheSize; ++i) { + if (cache[i]) { + cache[i]->decRefCnt(); + } + } +} + +CMap *CMapCache::getCMap(GString *collection, GString *cMapName) { + CMap *cmap; + int i, j; + + if (cache[0] && cache[0]->match(collection, cMapName)) { + cache[0]->incRefCnt(); + return cache[0]; + } + for (i = 1; i < cMapCacheSize; ++i) { + if (cache[i] && cache[i]->match(collection, cMapName)) { + cmap = cache[i]; + for (j = i; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = cmap; + cmap->incRefCnt(); + return cmap; + } + } + if ((cmap = CMap::parse(this, collection, cMapName))) { + if (cache[cMapCacheSize - 1]) { + cache[cMapCacheSize - 1]->decRefCnt(); + } + for (j = cMapCacheSize - 1; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = cmap; + cmap->incRefCnt(); + return cmap; + } + return NULL; +} diff --git a/pdftops/CMap.h b/pdftops/CMap.h new file mode 100644 index 000000000..a89266c8d --- /dev/null +++ b/pdftops/CMap.h @@ -0,0 +1,102 @@ +//======================================================================== +// +// CMap.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CMAP_H +#define CMAP_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "CharTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +class GString; +struct CMapVectorEntry; +class CMapCache; + +//------------------------------------------------------------------------ + +class CMap { +public: + + // Create the CMap specified by and . Sets + // the initial reference count to 1. Returns NULL on failure. + static CMap *parse(CMapCache *cache, GString *collectionA, + GString *cMapNameA); + + ~CMap(); + + void incRefCnt(); + void decRefCnt(); + + // Return collection name (-). + GString *getCollection() { return collection; } + + // Return true if this CMap matches the specified , and + // . + GBool match(GString *collectionA, GString *cMapNameA); + + // Return the CID corresponding to the character code starting at + // , which contains bytes. Sets * to the number of + // bytes used by the char code. + CID getCID(char *s, int len, int *nUsed); + + // Return the writing mode (0=horizontal, 1=vertical). + int getWMode() { return wMode; } + +private: + + CMap(GString *collectionA, GString *cMapNameA); + CMap(GString *collectionA, GString *cMapNameA, int wModeA); + void useCMap(CMapCache *cache, char *useName); + void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src); + void addCodeSpace(CMapVectorEntry *vec, Guint start, Guint end, + Guint nBytes); + void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID); + void freeCMapVector(CMapVectorEntry *vec); + + GString *collection; + GString *cMapName; + int wMode; // writing mode (0=horizontal, 1=vertical) + CMapVectorEntry *vector; // vector for first byte (NULL for + // identity CMap) + int refCnt; +#if MULTITHREADED + GMutex mutex; +#endif +}; + +//------------------------------------------------------------------------ + +#define cMapCacheSize 4 + +class CMapCache { +public: + + CMapCache(); + ~CMapCache(); + + // Get the CMap for the specified character collection. + // Increments its reference count; there will be one reference for + // the cache plus one for the caller of this function. Returns NULL + // on failure. + CMap *getCMap(GString *collection, GString *cMapName); + +private: + + CMap *cache[cMapCacheSize]; +}; + +#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. + + + Copyright (C) 19yy + + 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. + + , 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..d1ff4cb8e --- /dev/null +++ b/pdftops/Catalog.cxx @@ -0,0 +1,353 @@ +//======================================================================== +// +// Catalog.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#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) { + 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); + // some PDF files actually use real numbers here ("/Count 9.0") + if (!obj.isNum()) { + error(-1, "Page count in top-level pages object is wrong type (%s)", + obj.getTypeName()); + goto err3; + } + pagesSize = numPages0 = (int)obj.getNum(); + obj.free(); + pages = (Page **)gmallocn(pagesSize, sizeof(Page *)); + pageRefs = (Ref *)gmallocn(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); + 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(); + + // get the metadata stream + catDict.dictLookup("Metadata", &metadata); + + // get the structure tree root + catDict.dictLookup("StructTreeRoot", &structTreeRoot); + + // get the outline dictionary + catDict.dictLookup("Outlines", &outline); + + // get the AcroForm dictionary + catDict.dictLookup("AcroForm", &acroForm); + + 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; + } + metadata.free(); + structTreeRoot.free(); + outline.free(); + acroForm.free(); +} + +GString *Catalog::readMetadata() { + GString *s; + Dict *dict; + Object obj; + int c; + + if (!metadata.isStream()) { + return NULL; + } + dict = metadata.streamGetDict(); + if (!dict->lookup("Subtype", &obj)->isName("XML")) { + error(-1, "Unknown Metadata type: '%s'", + obj.isName() ? obj.getName() : "???"); + } + obj.free(); + s = new GString(); + metadata.streamReset(); + while ((c = metadata.streamGetChar()) != EOF) { + s->append(c); + } + metadata.streamClose(); + return s; +} + +int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { + 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); + if (!page->isOk()) { + ++start; + goto err3; + } + if (start >= pagesSize) { + pagesSize += 32; + pages = (Page **)greallocn(pages, pagesSize, sizeof(Page *)); + pageRefs = (Ref *)greallocn(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)) + < 0) + goto err2; + } else { + error(-1, "Kid object (page %d) is wrong type (%s)", + start+1, kid.getTypeName()); + } + 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()); + } else if (obj1.isDict()) { + if (obj1.dictLookup("D", &obj2)->isArray()) + dest = new LinkDest(obj2.getArray()); + else + error(-1, "Bad named destination value"); + obj2.free(); + } else { + error(-1, "Bad named destination value"); + } + obj1.free(); + if (dest && !dest->isOk()) { + delete dest; + dest = NULL; + } + + 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..08e50cae0 --- /dev/null +++ b/pdftops/Catalog.h @@ -0,0 +1,92 @@ +//======================================================================== +// +// Catalog.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CATALOG_H +#define CATALOG_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +class XRef; +class Object; +class Page; +class PageAttrs; +struct Ref; +class LinkDest; + +//------------------------------------------------------------------------ +// Catalog +//------------------------------------------------------------------------ + +class Catalog { +public: + + // Constructor. + Catalog(XRef *xrefA); + + // 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; } + + // Return the contents of the metadata stream, or NULL if there is + // no metadata. + GString *readMetadata(); + + // Return the structure tree root object. + Object *getStructTreeRoot() { return &structTreeRoot; } + + // 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 is not a destination. + LinkDest *findDest(GString *name); + + Object *getOutline() { return &outline; } + + Object *getAcroForm() { return &acroForm; } + +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 + Object metadata; // metadata stream + Object structTreeRoot; // structure tree root dictionary + Object outline; // outline dictionary + Object acroForm; // AcroForm dictionary + GBool ok; // true if catalog is valid + + int readPageTree(Dict *pages, PageAttrs *attrs, int start); + Object *findDestInTree(Object *tree, GString *name, Object *obj); +}; + +#endif diff --git a/pdftops/CharCodeToUnicode.cxx b/pdftops/CharCodeToUnicode.cxx new file mode 100644 index 000000000..5dcb2e92e --- /dev/null +++ b/pdftops/CharCodeToUnicode.cxx @@ -0,0 +1,540 @@ +//======================================================================== +// +// CharCodeToUnicode.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "gfile.h" +#include "GString.h" +#include "Error.h" +#include "GlobalParams.h" +#include "PSTokenizer.h" +#include "CharCodeToUnicode.h" + +//------------------------------------------------------------------------ + +#define maxUnicodeString 8 + +struct CharCodeToUnicodeString { + CharCode c; + Unicode u[maxUnicodeString]; + int len; +}; + +//------------------------------------------------------------------------ + +static int getCharFromString(void *data) { + char *p; + int c; + + p = *(char **)data; + if (*p) { + c = *p++; + *(char **)data = p; + } else { + c = EOF; + } + return c; +} + +static int getCharFromFile(void *data) { + return fgetc((FILE *)data); +} + +//------------------------------------------------------------------------ + +CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName, + GString *collection) { + FILE *f; + Unicode *mapA; + CharCode size, mapLenA; + char buf[64]; + Unicode u; + CharCodeToUnicode *ctu; + + if (!(f = fopen(fileName->getCString(), "r"))) { + error(-1, "Couldn't open cidToUnicode file '%s'", + fileName->getCString()); + return NULL; + } + + size = 32768; + mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); + mapLenA = 0; + + while (getLine(buf, sizeof(buf), f)) { + if (mapLenA == size) { + size *= 2; + mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); + } + if (sscanf(buf, "%x", &u) == 1) { + mapA[mapLenA] = u; + } else { + error(-1, "Bad line (%d) in cidToUnicode file '%s'", + (int)(mapLenA + 1), fileName->getCString()); + mapA[mapLenA] = 0; + } + ++mapLenA; + } + fclose(f); + + ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue, + NULL, 0, 0); + gfree(mapA); + return ctu; +} + +CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( + GString *fileName) { + FILE *f; + Unicode *mapA; + CharCodeToUnicodeString *sMapA; + CharCode size, oldSize, len, sMapSizeA, sMapLenA; + char buf[256]; + char *tok; + Unicode u0; + Unicode uBuf[maxUnicodeString]; + CharCodeToUnicode *ctu; + int line, n, i; + + if (!(f = fopen(fileName->getCString(), "r"))) { + error(-1, "Couldn't open unicodeToUnicode file '%s'", + fileName->getCString()); + return NULL; + } + + size = 4096; + mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); + memset(mapA, 0, size * sizeof(Unicode)); + len = 0; + sMapA = NULL; + sMapSizeA = sMapLenA = 0; + + line = 0; + while (getLine(buf, sizeof(buf), f)) { + ++line; + if (!(tok = strtok(buf, " \t\r\n")) || + sscanf(tok, "%x", &u0) != 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + continue; + } + n = 0; + while (n < maxUnicodeString) { + if (!(tok = strtok(NULL, " \t\r\n"))) { + break; + } + if (sscanf(tok, "%x", &uBuf[n]) != 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + break; + } + ++n; + } + if (n < 1) { + error(-1, "Bad line (%d) in unicodeToUnicode file '%s'", + line, fileName->getCString()); + continue; + } + if (u0 >= size) { + oldSize = size; + while (u0 >= size) { + size *= 2; + } + mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); + memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode)); + } + if (n == 1) { + mapA[u0] = uBuf[0]; + } else { + mapA[u0] = 0; + if (sMapLenA == sMapSizeA) { + sMapSizeA += 16; + sMapA = (CharCodeToUnicodeString *) + greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString)); + } + sMapA[sMapLenA].c = u0; + for (i = 0; i < n; ++i) { + sMapA[sMapLenA].u[i] = uBuf[i]; + } + sMapA[sMapLenA].len = n; + ++sMapLenA; + } + if (u0 >= len) { + len = u0 + 1; + } + } + fclose(f); + + ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue, + sMapA, sMapLenA, sMapSizeA); + gfree(mapA); + return ctu; +} + +CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) { + return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0); +} + +CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) { + CharCodeToUnicode *ctu; + char *p; + + ctu = new CharCodeToUnicode(NULL); + p = buf->getCString(); + ctu->parseCMap1(&getCharFromString, &p, nBits); + return ctu; +} + +void CharCodeToUnicode::mergeCMap(GString *buf, int nBits) { + char *p; + + p = buf->getCString(); + parseCMap1(&getCharFromString, &p, nBits); +} + +void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, + int nBits) { + PSTokenizer *pst; + char tok1[256], tok2[256], tok3[256]; + int nDigits, n1, n2, n3; + CharCode i; + CharCode code1, code2; + GString *name; + FILE *f; + + nDigits = nBits / 4; + pst = new PSTokenizer(getCharFunc, data); + pst->getToken(tok1, sizeof(tok1), &n1); + while (pst->getToken(tok2, sizeof(tok2), &n2)) { + if (!strcmp(tok2, "usecmap")) { + if (tok1[0] == '/') { + name = new GString(tok1 + 1); + if ((f = globalParams->findToUnicodeFile(name))) { + parseCMap1(&getCharFromFile, f, nBits); + fclose(f); + } else { + error(-1, "Couldn't find ToUnicode CMap file for '%s'", + name->getCString()); + } + delete name; + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "beginbfchar")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endbfchar")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endbfchar")) { + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); + break; + } + if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && + tok2[0] == '<' && tok2[n2 - 1] == '>')) { + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); + continue; + } + tok1[n1 - 1] = tok2[n2 - 1] = '\0'; + if (sscanf(tok1 + 1, "%x", &code1) != 1) { + error(-1, "Illegal entry in bfchar block in ToUnicode CMap"); + continue; + } + addMapping(code1, tok2 + 1, n2 - 2, 0); + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else if (!strcmp(tok2, "beginbfrange")) { + while (pst->getToken(tok1, sizeof(tok1), &n1)) { + if (!strcmp(tok1, "endbfrange")) { + break; + } + if (!pst->getToken(tok2, sizeof(tok2), &n2) || + !strcmp(tok2, "endbfrange") || + !pst->getToken(tok3, sizeof(tok3), &n3) || + !strcmp(tok3, "endbfrange")) { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + break; + } + if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' && + n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + continue; + } + tok1[n1 - 1] = tok2[n2 - 1] = '\0'; + if (sscanf(tok1 + 1, "%x", &code1) != 1 || + sscanf(tok2 + 1, "%x", &code2) != 1) { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + continue; + } + if (!strcmp(tok3, "[")) { + i = 0; + while (pst->getToken(tok1, sizeof(tok1), &n1) && + code1 + i <= code2) { + if (!strcmp(tok1, "]")) { + break; + } + if (tok1[0] == '<' && tok1[n1 - 1] == '>') { + tok1[n1 - 1] = '\0'; + addMapping(code1 + i, tok1 + 1, n1 - 2, 0); + } else { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + } + ++i; + } + } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') { + tok3[n3 - 1] = '\0'; + for (i = 0; code1 <= code2; ++code1, ++i) { + addMapping(code1, tok3 + 1, n3 - 2, i); + } + + } else { + error(-1, "Illegal entry in bfrange block in ToUnicode CMap"); + } + } + pst->getToken(tok1, sizeof(tok1), &n1); + } else { + strcpy(tok1, tok2); + } + } + delete pst; +} + +void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, + int offset) { + CharCode oldLen, i; + Unicode u; + char uHex[5]; + int j; + + if (code >= mapLen) { + oldLen = mapLen; + mapLen = (code + 256) & ~255; + map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode)); + for (i = oldLen; i < mapLen; ++i) { + map[i] = 0; + } + } + if (n <= 4) { + if (sscanf(uStr, "%x", &u) != 1) { + error(-1, "Illegal entry in ToUnicode CMap"); + return; + } + map[code] = u + offset; + } else { + if (sMapLen >= sMapSize) { + sMapSize = sMapSize + 16; + sMap = (CharCodeToUnicodeString *) + greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); + } + map[code] = 0; + sMap[sMapLen].c = code; + sMap[sMapLen].len = n / 4; + for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) { + strncpy(uHex, uStr + j*4, 4); + uHex[4] = '\0'; + if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) { + error(-1, "Illegal entry in ToUnicode CMap"); + } + } + sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset; + ++sMapLen; + } +} + +CharCodeToUnicode::CharCodeToUnicode(GString *tagA) { + CharCode i; + + tag = tagA; + mapLen = 256; + map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); + for (i = 0; i < mapLen; ++i) { + map[i] = 0; + } + sMap = NULL; + sMapLen = sMapSize = 0; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA, + CharCode mapLenA, GBool copyMap, + CharCodeToUnicodeString *sMapA, + int sMapLenA, int sMapSizeA) { + tag = tagA; + mapLen = mapLenA; + if (copyMap) { + map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); + memcpy(map, mapA, mapLen * sizeof(Unicode)); + } else { + map = mapA; + } + sMap = sMapA; + sMapLen = sMapLenA; + sMapSize = sMapSizeA; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +CharCodeToUnicode::~CharCodeToUnicode() { + if (tag) { + delete tag; + } + gfree(map); + if (sMap) { + gfree(sMap); + } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +} + +void CharCodeToUnicode::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif + ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif +} + +void CharCodeToUnicode::decRefCnt() { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { + delete this; + } +} + +GBool CharCodeToUnicode::match(GString *tagA) { + return tag && !tag->cmp(tagA); +} + +void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) { + int i, j; + + if (len == 1) { + map[c] = u[0]; + } else { + for (i = 0; i < sMapLen; ++i) { + if (sMap[i].c == c) { + break; + } + } + if (i == sMapLen) { + if (sMapLen == sMapSize) { + sMapSize += 8; + sMap = (CharCodeToUnicodeString *) + greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); + } + ++sMapLen; + } + map[c] = 0; + sMap[i].c = c; + sMap[i].len = len; + for (j = 0; j < len && j < maxUnicodeString; ++j) { + sMap[i].u[j] = u[j]; + } + } +} + +int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) { + int i, j; + + if (c >= mapLen) { + return 0; + } + if (map[c]) { + u[0] = map[c]; + return 1; + } + for (i = 0; i < sMapLen; ++i) { + if (sMap[i].c == c) { + for (j = 0; j < sMap[i].len && j < size; ++j) { + u[j] = sMap[i].u[j]; + } + return j; + } + } + return 0; +} + +//------------------------------------------------------------------------ + +CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) { + int i; + + size = sizeA; + cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *)); + for (i = 0; i < size; ++i) { + cache[i] = NULL; + } +} + +CharCodeToUnicodeCache::~CharCodeToUnicodeCache() { + int i; + + for (i = 0; i < size; ++i) { + if (cache[i]) { + cache[i]->decRefCnt(); + } + } + gfree(cache); +} + +CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GString *tag) { + CharCodeToUnicode *ctu; + int i, j; + + if (cache[0] && cache[0]->match(tag)) { + cache[0]->incRefCnt(); + return cache[0]; + } + for (i = 1; i < size; ++i) { + if (cache[i] && cache[i]->match(tag)) { + ctu = cache[i]; + for (j = i; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = ctu; + ctu->incRefCnt(); + return ctu; + } + } + return NULL; +} + +void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) { + int i; + + if (cache[size - 1]) { + cache[size - 1]->decRefCnt(); + } + for (i = size - 1; i >= 1; --i) { + cache[i] = cache[i - 1]; + } + cache[0] = ctu; + ctu->incRefCnt(); +} diff --git a/pdftops/CharCodeToUnicode.h b/pdftops/CharCodeToUnicode.h new file mode 100644 index 000000000..c7544f8c2 --- /dev/null +++ b/pdftops/CharCodeToUnicode.h @@ -0,0 +1,117 @@ +//======================================================================== +// +// CharCodeToUnicode.h +// +// Mapping from character codes to Unicode. +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CHARCODETOUNICODE_H +#define CHARCODETOUNICODE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "CharTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +struct CharCodeToUnicodeString; + +//------------------------------------------------------------------------ + +class CharCodeToUnicode { +public: + + // Read the CID-to-Unicode mapping for from the file + // specified by . Sets the initial reference count to 1. + // Returns NULL on failure. + static CharCodeToUnicode *parseCIDToUnicode(GString *fileName, + GString *collection); + + // Create a Unicode-to-Unicode mapping from the file specified by + // . Sets the initial reference count to 1. Returns NULL + // on failure. + static CharCodeToUnicode *parseUnicodeToUnicode(GString *fileName); + + // Create the CharCode-to-Unicode mapping for an 8-bit font. + // is an array of 256 Unicode indexes. Sets the initial + // reference count to 1. + static CharCodeToUnicode *make8BitToUnicode(Unicode *toUnicode); + + // Parse a ToUnicode CMap for an 8- or 16-bit font. + static CharCodeToUnicode *parseCMap(GString *buf, int nBits); + + // Parse a ToUnicode CMap for an 8- or 16-bit font, merging it into + // . + void mergeCMap(GString *buf, int nBits); + + ~CharCodeToUnicode(); + + void incRefCnt(); + void decRefCnt(); + + // Return true if this mapping matches the specified . + GBool match(GString *tagA); + + // Set the mapping for . + void setMapping(CharCode c, Unicode *u, int len); + + // Map a CharCode to Unicode. + int mapToUnicode(CharCode c, Unicode *u, int size); + + // Return the mapping's length, i.e., one more than the max char + // code supported by the mapping. + CharCode getLength() { return mapLen; } + +private: + + void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); + void addMapping(CharCode code, char *uStr, int n, int offset); + CharCodeToUnicode(GString *tagA); + CharCodeToUnicode(GString *tagA, Unicode *mapA, + CharCode mapLenA, GBool copyMap, + CharCodeToUnicodeString *sMapA, + int sMapLenA, int sMapSizeA); + + GString *tag; + Unicode *map; + CharCode mapLen; + CharCodeToUnicodeString *sMap; + int sMapLen, sMapSize; + int refCnt; +#if MULTITHREADED + GMutex mutex; +#endif +}; + +//------------------------------------------------------------------------ + +class CharCodeToUnicodeCache { +public: + + CharCodeToUnicodeCache(int sizeA); + ~CharCodeToUnicodeCache(); + + // Get the CharCodeToUnicode object for . Increments its + // reference count; there will be one reference for the cache plus + // one for the caller of this function. Returns NULL on failure. + CharCodeToUnicode *getCharCodeToUnicode(GString *tag); + + // Insert into the cache, in the most-recently-used position. + void add(CharCodeToUnicode *ctu); + +private: + + CharCodeToUnicode **cache; + int size; +}; + +#endif diff --git a/pdftops/CharTypes.h b/pdftops/CharTypes.h new file mode 100644 index 000000000..d0df630d0 --- /dev/null +++ b/pdftops/CharTypes.h @@ -0,0 +1,24 @@ +//======================================================================== +// +// CharTypes.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CHARTYPES_H +#define CHARTYPES_H + +// Unicode character. +typedef unsigned int Unicode; + +// Character ID for CID character collections. +typedef unsigned int CID; + +// This is large enough to hold any of the following: +// - 8-bit char code +// - 16-bit CID +// - Unicode +typedef unsigned int CharCode; + +#endif diff --git a/pdftops/CompactFontTables.h b/pdftops/CompactFontTables.h new file mode 100644 index 000000000..28e16e775 --- /dev/null +++ b/pdftops/CompactFontTables.h @@ -0,0 +1,464 @@ +//======================================================================== +// +// CompactFontTables.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#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..bbe1d34a5 --- /dev/null +++ b/pdftops/Decrypt.cxx @@ -0,0 +1,411 @@ +//======================================================================== +// +// Decrypt.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#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 encryptMetadata, + GBool *ownerPasswordOk) { + Guchar test[32], test2[32]; + GString *userPassword2; + Guchar fState[256]; + Guchar tmpKey[16]; + Guchar fx, fy; + int len, i, j; + + // try using the supplied owner password to generate the user password + *ownerPasswordOk = gFalse; + 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); + } + md5(test, 32, test); + if (encRevision == 3) { + for (i = 0; i < 50; ++i) { + md5(test, 16, test); + } + } + if (encRevision == 2) { + rc4InitKey(test, keyLength, fState); + fx = fy = 0; + for (i = 0; i < 32; ++i) { + test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); + } + } else { + memcpy(test2, ownerKey->getCString(), 32); + for (i = 19; i >= 0; --i) { + for (j = 0; j < keyLength; ++j) { + tmpKey[j] = test[j] ^ i; + } + rc4InitKey(tmpKey, keyLength, fState); + fx = fy = 0; + for (j = 0; j < 32; ++j) { + test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]); + } + } + } + userPassword2 = new GString((char *)test2, 32); + if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, + permissions, fileID, userPassword2, fileKey, + encryptMetadata)) { + *ownerPasswordOk = gTrue; + delete userPassword2; + return gTrue; + } + delete userPassword2; + } + + // try using the supplied user password + return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, + permissions, fileID, userPassword, fileKey, + encryptMetadata); +} + +GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, + int permissions, GString *fileID, + GString *userPassword, Guchar *fileKey, + GBool encryptMetadata) { + 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(72 + 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()); + len = 68 + fileID->getLength(); + if (!encryptMetadata) { + buf[len++] = 0xff; + buf[len++] = 0xff; + buf[len++] = 0xff; + buf[len++] = 0xff; + } + md5(buf, len, fileKey); + if (encRevision == 3) { + for (i = 0; i < 50; ++i) { + md5(fileKey, keyLength, 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] = (Guchar)(a & 0xff); + digest[1] = (Guchar)((a >>= 8) & 0xff); + digest[2] = (Guchar)((a >>= 8) & 0xff); + digest[3] = (Guchar)((a >>= 8) & 0xff); + digest[4] = (Guchar)(b & 0xff); + digest[5] = (Guchar)((b >>= 8) & 0xff); + digest[6] = (Guchar)((b >>= 8) & 0xff); + digest[7] = (Guchar)((b >>= 8) & 0xff); + digest[8] = (Guchar)(c & 0xff); + digest[9] = (Guchar)((c >>= 8) & 0xff); + digest[10] = (Guchar)((c >>= 8) & 0xff); + digest[11] = (Guchar)((c >>= 8) & 0xff); + digest[12] = (Guchar)(d & 0xff); + digest[13] = (Guchar)((d >>= 8) & 0xff); + digest[14] = (Guchar)((d >>= 8) & 0xff); + digest[15] = (Guchar)((d >>= 8) & 0xff); +} diff --git a/pdftops/Decrypt.h b/pdftops/Decrypt.h new file mode 100644 index 000000000..790e92cc3 --- /dev/null +++ b/pdftops/Decrypt.h @@ -0,0 +1,63 @@ +//======================================================================== +// +// Decrypt.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef DECRYPT_H +#define DECRYPT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#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 buffer must have space for at + // least 16 bytes. Checks and then + // and returns true if either is correct. Sets if + // the owner password was correct. Either or both of the passwords + // may be NULL, which is treated as an empty string. + static GBool makeFileKey(int encVersion, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, + int permissions, GString *fileID, + GString *ownerPassword, GString *userPassword, + Guchar *fileKey, GBool encryptMetadata, + GBool *ownerPasswordOk); + +private: + + static GBool makeFileKey2(int encVersion, int encRevision, int keyLength, + GString *ownerKey, GString *userKey, + int permissions, GString *fileID, + GString *userPassword, Guchar *fileKey, + GBool encryptMetadata); + + int objKeyLength; + Guchar objKey[21]; + Guchar state[256]; + Guchar x, y; +}; + +#endif diff --git a/pdftops/Dependencies b/pdftops/Dependencies new file mode 100644 index 000000000..4a983f076 --- /dev/null +++ b/pdftops/Dependencies @@ -0,0 +1,149 @@ +# DO NOT DELETE + +pdftops.o: ../cups/string.h ../config.h parseargs.h gtypes.h GString.h gmem.h +pdftops.o: Object.h Array.h Dict.h Stream.h XRef.h Catalog.h Page.h PDFDoc.h +pdftops.o: PSOutputDev.h GlobalParams.h CharTypes.h OutputDev.h Error.h +pdftops.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +pdftops.o: ../cups/ppd.h ../cups/file.h +Annot.o: ../config.h gmem.h Object.h gtypes.h GString.h Array.h Dict.h +Annot.o: Stream.h Catalog.h Gfx.h Lexer.h Annot.h +Array.o: ../config.h gmem.h Object.h gtypes.h GString.h Array.h Dict.h +Array.o: Stream.h +BuiltinFont.o: ../config.h gmem.h FontEncodingTables.h BuiltinFont.h gtypes.h +BuiltinFontTables.o: ../config.h FontEncodingTables.h BuiltinFontTables.h +BuiltinFontTables.o: BuiltinFont.h gtypes.h +Catalog.o: ../config.h gmem.h Object.h gtypes.h GString.h Array.h Dict.h +Catalog.o: Stream.h XRef.h Page.h Error.h Link.h Catalog.h +CharCodeToUnicode.o: ../config.h gmem.h gfile.h gtypes.h GString.h Error.h +CharCodeToUnicode.o: GlobalParams.h CharTypes.h PSTokenizer.h +CharCodeToUnicode.o: CharCodeToUnicode.h +CMap.o: ../config.h gmem.h gfile.h gtypes.h GString.h Error.h GlobalParams.h +CMap.o: CharTypes.h PSTokenizer.h CMap.h +Decrypt.o: ../config.h gmem.h Decrypt.h gtypes.h GString.h +Dict.o: ../config.h gmem.h Object.h gtypes.h GString.h Array.h Dict.h +Dict.o: Stream.h XRef.h +Error.o: ../config.h GlobalParams.h gtypes.h CharTypes.h Error.h +FoFiBase.o: ../config.h gmem.h FoFiBase.h gtypes.h +FoFiEncodings.o: ../config.h FoFiEncodings.h gtypes.h +FoFiTrueType.o: ../config.h gtypes.h gmem.h GString.h GHash.h FoFiTrueType.h +FoFiTrueType.o: FoFiBase.h +FoFiType1C.o: ../config.h gmem.h GString.h FoFiEncodings.h gtypes.h +FoFiType1C.o: FoFiType1C.h FoFiBase.h +FoFiType1.o: ../config.h gmem.h FoFiEncodings.h gtypes.h FoFiType1.h +FoFiType1.o: FoFiBase.h +FontEncodingTables.o: ../config.h FontEncodingTables.h +Function.o: ../config.h gmem.h Object.h gtypes.h GString.h Array.h Dict.h +Function.o: Stream.h Error.h Function.h +gfile.o: ../config.h GString.h gfile.h gtypes.h +Gfx.o: ../config.h gmem.h GlobalParams.h gtypes.h CharTypes.h Object.h +Gfx.o: GString.h Array.h Dict.h Stream.h Lexer.h Parser.h GfxFont.h +Gfx.o: GfxState.h Function.h OutputDev.h Page.h Error.h Gfx.h +GfxFont.o: ../config.h gmem.h Error.h Object.h gtypes.h GString.h Array.h +GfxFont.o: Dict.h Stream.h GlobalParams.h CharTypes.h CMap.h +GfxFont.o: CharCodeToUnicode.h FontEncodingTables.h BuiltinFontTables.h +GfxFont.o: BuiltinFont.h FoFiType1.h FoFiBase.h FoFiType1C.h FoFiTrueType.h +GfxFont.o: GfxFont.h +GfxState.o: ../config.h gmem.h Error.h Object.h gtypes.h GString.h Array.h +GfxState.o: Dict.h Stream.h Page.h GfxState.h Function.h +GHash.o: ../config.h gmem.h GString.h GHash.h gtypes.h +GList.o: ../config.h gmem.h GList.h gtypes.h +GlobalParams.o: ../config.h gmem.h GString.h GList.h gtypes.h GHash.h gfile.h +GlobalParams.o: Error.h NameToCharCode.h CharTypes.h CharCodeToUnicode.h +GlobalParams.o: UnicodeMap.h CMap.h BuiltinFontTables.h BuiltinFont.h +GlobalParams.o: FontEncodingTables.h GlobalParams.h NameToUnicodeTable.h +GlobalParams.o: UnicodeMapTables.h UTF8.h +gmempp.o: ../config.h gmem.h +GString.o: ../config.h gtypes.h GString.h +JArithmeticDecoder.o: ../config.h Object.h gtypes.h gmem.h GString.h Array.h +JArithmeticDecoder.o: Dict.h Stream.h JArithmeticDecoder.h +JBIG2Stream.o: ../config.h GList.h gtypes.h Error.h JArithmeticDecoder.h +JBIG2Stream.o: JBIG2Stream.h Object.h gmem.h GString.h Array.h Dict.h +JBIG2Stream.o: Stream.h Stream-CCITT.h +JPXStream.o: ../config.h gmem.h Error.h JArithmeticDecoder.h gtypes.h +JPXStream.o: JPXStream.h Object.h GString.h Array.h Dict.h Stream.h +Lexer.o: ../config.h Lexer.h Object.h gtypes.h gmem.h GString.h Array.h +Lexer.o: Dict.h Stream.h Error.h +Link.o: ../config.h gmem.h GString.h Error.h Object.h gtypes.h Array.h Dict.h +Link.o: Stream.h Link.h +NameToCharCode.o: ../config.h gmem.h NameToCharCode.h CharTypes.h +Object.o: ../config.h Object.h gtypes.h gmem.h GString.h Array.h Dict.h +Object.o: Stream.h Error.h XRef.h +Outline.o: ../config.h gmem.h GString.h GList.h gtypes.h Link.h Object.h +Outline.o: Array.h Dict.h Stream.h PDFDocEncoding.h CharTypes.h Outline.h +OutputDev.o: ../config.h Object.h gtypes.h gmem.h GString.h Array.h Dict.h +OutputDev.o: Stream.h GfxState.h Function.h OutputDev.h CharTypes.h +Page.o: ../config.h GlobalParams.h gtypes.h CharTypes.h Object.h gmem.h +Page.o: GString.h Array.h Dict.h Stream.h XRef.h Link.h OutputDev.h Gfx.h +Page.o: GfxState.h Function.h Annot.h Error.h Page.h +Parser.o: ../config.h Object.h gtypes.h gmem.h GString.h Array.h Dict.h +Parser.o: Stream.h Parser.h Lexer.h XRef.h Error.h Decrypt.h +PDFDoc.o: ../config.h GString.h GlobalParams.h gtypes.h CharTypes.h Page.h +PDFDoc.o: Object.h gmem.h Array.h Dict.h Stream.h Catalog.h XRef.h Link.h +PDFDoc.o: OutputDev.h Error.h ErrorCodes.h Lexer.h Parser.h SecurityHandler.h +PDFDoc.o: Outline.h PDFDoc.h +PDFDocEncoding.o: PDFDocEncoding.h CharTypes.h +PSOutputDev.o: ../config.h GString.h GList.h gtypes.h GlobalParams.h +PSOutputDev.o: CharTypes.h Object.h gmem.h Array.h Dict.h Stream.h Error.h +PSOutputDev.o: Function.h Gfx.h GfxState.h GfxFont.h UnicodeMap.h +PSOutputDev.o: FoFiType1C.h FoFiBase.h FoFiTrueType.h Catalog.h Page.h +PSOutputDev.o: Annot.h XRef.h PSOutputDev.h OutputDev.h +PSTokenizer.o: ../config.h PSTokenizer.h gtypes.h +SecurityHandler.o: ../config.h GString.h PDFDoc.h XRef.h gtypes.h Object.h +SecurityHandler.o: gmem.h Array.h Dict.h Stream.h Catalog.h Page.h Decrypt.h +SecurityHandler.o: Error.h GlobalParams.h CharTypes.h SecurityHandler.h +SplashBitmap.o: ../config.h gmem.h SplashErrorCodes.h SplashBitmap.h +SplashBitmap.o: SplashTypes.h gtypes.h +SplashClip.o: ../config.h gmem.h SplashErrorCodes.h SplashMath.h +SplashClip.o: SplashTypes.h gtypes.h SplashPath.h SplashXPath.h +SplashClip.o: SplashXPathScanner.h SplashClip.h +Splash.o: ../config.h gmem.h SplashErrorCodes.h SplashMath.h SplashTypes.h +Splash.o: gtypes.h SplashBitmap.h SplashState.h SplashPath.h SplashXPath.h +Splash.o: SplashXPathScanner.h SplashPattern.h SplashScreen.h SplashFont.h +Splash.o: SplashGlyphBitmap.h Splash.h SplashClip.h +SplashFont.o: ../config.h gmem.h SplashMath.h SplashTypes.h gtypes.h +SplashFont.o: SplashGlyphBitmap.h SplashFontFile.h SplashFont.h +SplashFontEngine.o: ../config.h gmem.h GString.h SplashT1FontEngine.h +SplashFontEngine.o: SplashFTFontEngine.h SplashFontFile.h gtypes.h +SplashFontEngine.o: SplashTypes.h SplashFontFileID.h SplashFont.h +SplashFontEngine.o: SplashFontEngine.h +SplashFontFile.o: ../config.h GString.h SplashFontFile.h gtypes.h +SplashFontFile.o: SplashTypes.h SplashFontFileID.h +SplashFontFileID.o: ../config.h SplashFontFileID.h gtypes.h +SplashFTFont.o: ../config.h +SplashFTFontEngine.o: ../config.h +SplashFTFontFile.o: ../config.h +SplashOutputDev.o: ../config.h gfile.h gtypes.h GlobalParams.h CharTypes.h +SplashOutputDev.o: Error.h Object.h gmem.h GString.h Array.h Dict.h Stream.h +SplashOutputDev.o: GfxFont.h Link.h CharCodeToUnicode.h FontEncodingTables.h +SplashOutputDev.o: FoFiTrueType.h FoFiBase.h SplashBitmap.h SplashTypes.h +SplashOutputDev.o: SplashGlyphBitmap.h SplashPattern.h SplashScreen.h +SplashOutputDev.o: SplashPath.h SplashState.h SplashErrorCodes.h +SplashOutputDev.o: SplashFontEngine.h SplashFont.h SplashFontFile.h +SplashOutputDev.o: SplashFontFileID.h Splash.h SplashClip.h SplashOutputDev.h +SplashOutputDev.o: OutputDev.h GfxState.h Function.h +SplashPath.o: ../config.h gmem.h SplashErrorCodes.h SplashPath.h +SplashPath.o: SplashTypes.h gtypes.h +SplashPattern.o: ../config.h SplashMath.h SplashTypes.h gtypes.h +SplashPattern.o: SplashScreen.h SplashPattern.h +SplashScreen.o: ../config.h gmem.h SplashMath.h SplashTypes.h gtypes.h +SplashScreen.o: SplashScreen.h +SplashState.o: ../config.h gmem.h SplashPattern.h SplashTypes.h gtypes.h +SplashState.o: SplashScreen.h SplashClip.h SplashState.h +SplashT1Font.o: ../config.h +SplashT1FontEngine.o: ../config.h +SplashT1FontFile.o: ../config.h +SplashXPath.o: ../config.h gmem.h SplashMath.h SplashTypes.h gtypes.h +SplashXPath.o: SplashPath.h SplashXPath.h +SplashXPathScanner.o: ../config.h gmem.h SplashMath.h SplashTypes.h gtypes.h +SplashXPathScanner.o: SplashXPath.h SplashXPathScanner.h +Stream.o: ../config.h gmem.h gfile.h gtypes.h Error.h Object.h GString.h +Stream.o: Array.h Dict.h Stream.h Lexer.h Decrypt.h GfxState.h Function.h +Stream.o: JBIG2Stream.h JPXStream.h Stream-CCITT.h +UnicodeMap.o: ../config.h gmem.h gfile.h gtypes.h GString.h GList.h Error.h +UnicodeMap.o: GlobalParams.h CharTypes.h UnicodeMap.h +UnicodeTypeTable.o: CharTypes.h UnicodeTypeTable.h gtypes.h +XpdfPluginAPI.o: ../config.h +XRef.o: ../config.h gmem.h Object.h gtypes.h GString.h Array.h Dict.h +XRef.o: Stream.h Lexer.h Parser.h Error.h ErrorCodes.h XRef.h +gmem.o: ../config.h gmem.h +parseargs.o: parseargs.h gtypes.h diff --git a/pdftops/Dict.cxx b/pdftops/Dict.cxx new file mode 100644 index 000000000..371ecbffc --- /dev/null +++ b/pdftops/Dict.cxx @@ -0,0 +1,95 @@ +//======================================================================== +// +// Dict.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#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 == size) { + if (length == 0) { + size = 8; + } else { + size *= 2; + } + entries = (DictEntry *)greallocn(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..f63c98e00 --- /dev/null +++ b/pdftops/Dict.h @@ -0,0 +1,77 @@ +//======================================================================== +// +// Dict.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef DICT_H +#define DICT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#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 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 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..03d29e095 --- /dev/null +++ b/pdftops/Error.cxx @@ -0,0 +1,38 @@ +//======================================================================== +// +// Error.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include "GlobalParams.h" +#include "Error.h" + +void CDECL error(int pos, char *msg, ...) { + va_list args; + + // NB: this can be called before the globalParams object is created + if (globalParams && globalParams->getErrQuiet()) { + return; + } + if (pos >= 0) { + fprintf(stderr, "Error (%d): ", pos); + } else { + fprintf(stderr, "Error: "); + } + va_start(args, msg); + vfprintf(stderr, msg, args); + va_end(args); + fprintf(stderr, "\n"); + fflush(stderr); +} diff --git a/pdftops/Error.h b/pdftops/Error.h new file mode 100644 index 000000000..cc51e5feb --- /dev/null +++ b/pdftops/Error.h @@ -0,0 +1,23 @@ +//======================================================================== +// +// Error.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ERROR_H +#define ERROR_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "config.h" + +extern void CDECL error(int pos, char *msg, ...); + +#endif diff --git a/pdftops/ErrorCodes.h b/pdftops/ErrorCodes.h new file mode 100644 index 000000000..b28528df5 --- /dev/null +++ b/pdftops/ErrorCodes.h @@ -0,0 +1,36 @@ +//======================================================================== +// +// ErrorCodes.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef ERRORCODES_H +#define ERRORCODES_H + +#define errNone 0 // no error + +#define errOpenFile 1 // couldn't open the PDF file + +#define errBadCatalog 2 // couldn't read the page catalog + +#define errDamaged 3 // PDF file was damaged and couldn't be + // repaired + +#define errEncrypted 4 // file was encrypted and password was + // incorrect or not supplied + +#define errHighlightFile 5 // nonexistent or invalid highlight file + +#define errBadPrinter 6 // invalid printer + +#define errPrinting 7 // error during printing + +#define errPermission 8 // PDF file doesn't allow that operation + +#define errBadPageNum 9 // invalid page number + +#define errFileIO 10 // file I/O error + +#endif diff --git a/pdftops/FoFiBase.cxx b/pdftops/FoFiBase.cxx new file mode 100644 index 000000000..0cabe2455 --- /dev/null +++ b/pdftops/FoFiBase.cxx @@ -0,0 +1,156 @@ +//======================================================================== +// +// FoFiBase.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "FoFiBase.h" + +//------------------------------------------------------------------------ +// FoFiBase +//------------------------------------------------------------------------ + +FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) { + fileData = file = (Guchar *)fileA; + len = lenA; + freeFileData = freeFileDataA; +} + +FoFiBase::~FoFiBase() { + if (freeFileData) { + gfree(fileData); + } +} + +char *FoFiBase::readFile(char *fileName, int *fileLen) { + FILE *f; + char *buf; + int n; + + if (!(f = fopen(fileName, "rb"))) { + return NULL; + } + fseek(f, 0, SEEK_END); + n = (int)ftell(f); + fseek(f, 0, SEEK_SET); + buf = (char *)gmalloc(n); + if ((int)fread(buf, 1, n, f) != n) { + gfree(buf); + fclose(f); + return NULL; + } + fclose(f); + *fileLen = n; + return buf; +} + +int FoFiBase::getS8(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + if (x & 0x80) { + x |= ~0xff; + } + return x; +} + +int FoFiBase::getU8(int pos, GBool *ok) { + if (pos < 0 || pos >= len) { + *ok = gFalse; + return 0; + } + return file[pos]; +} + +int FoFiBase::getS16BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+1 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + if (x & 0x8000) { + x |= ~0xffff; + } + return x; +} + +int FoFiBase::getU16BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+1 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + return x; +} + +int FoFiBase::getS32BE(int pos, GBool *ok) { + int x; + + if (pos < 0 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+3]; + if (x & 0x80000000) { + x |= ~0xffffffff; + } + return x; +} + +Guint FoFiBase::getU32BE(int pos, GBool *ok) { + Guint x; + + if (pos < 0 || pos+3 >= len) { + *ok = gFalse; + return 0; + } + x = file[pos]; + x = (x << 8) + file[pos+1]; + x = (x << 8) + file[pos+2]; + x = (x << 8) + file[pos+3]; + return x; +} + +Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) { + Guint x; + int i; + + if (pos < 0 || pos + size > len) { + *ok = gFalse; + return 0; + } + x = 0; + for (i = 0; i < size; ++i) { + x = (x << 8) + file[pos + i]; + } + return x; +} + +GBool FoFiBase::checkRegion(int pos, int size) { + return pos >= 0 && + pos + size >= pos && + pos + size <= len; +} diff --git a/pdftops/FoFiBase.h b/pdftops/FoFiBase.h new file mode 100644 index 000000000..74270270d --- /dev/null +++ b/pdftops/FoFiBase.h @@ -0,0 +1,57 @@ +//======================================================================== +// +// FoFiBase.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIBASE_H +#define FOFIBASE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ + +typedef void (*FoFiOutputFunc)(void *stream, char *data, int len); + +//------------------------------------------------------------------------ +// FoFiBase +//------------------------------------------------------------------------ + +class FoFiBase { +public: + + virtual ~FoFiBase(); + +protected: + + FoFiBase(char *fileA, int lenA, GBool freeFileDataA); + static char *readFile(char *fileName, int *fileLen); + + // S = signed / U = unsigned + // 8/16/32/Var = word length, in bytes + // BE = big endian + int getS8(int pos, GBool *ok); + int getU8(int pos, GBool *ok); + int getS16BE(int pos, GBool *ok); + int getU16BE(int pos, GBool *ok); + int getS32BE(int pos, GBool *ok); + Guint getU32BE(int pos, GBool *ok); + Guint getUVarBE(int pos, int size, GBool *ok); + + GBool checkRegion(int pos, int size); + + Guchar *fileData; + Guchar *file; + int len; + GBool freeFileData; +}; + +#endif diff --git a/pdftops/FoFiEncodings.cxx b/pdftops/FoFiEncodings.cxx new file mode 100644 index 000000000..946b56c19 --- /dev/null +++ b/pdftops/FoFiEncodings.cxx @@ -0,0 +1,994 @@ +//======================================================================== +// +// FoFiEncodings.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "FoFiEncodings.h" + +//------------------------------------------------------------------------ +// Type 1 and 1C font data +//------------------------------------------------------------------------ + +char *fofiType1StandardEncoding[256] = { + 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 +}; + +char *fofiType1ExpertEncoding[256] = { + 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" +}; + +//------------------------------------------------------------------------ +// Type 1C font data +//------------------------------------------------------------------------ + +char *fofiType1CStdStrings[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" +}; + +Gushort fofiType1CISOAdobeCharset[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 +}; + +Gushort fofiType1CExpertCharset[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 +}; + +Gushort fofiType1CExpertSubsetCharset[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 +}; diff --git a/pdftops/FoFiEncodings.h b/pdftops/FoFiEncodings.h new file mode 100644 index 000000000..804ed28a1 --- /dev/null +++ b/pdftops/FoFiEncodings.h @@ -0,0 +1,36 @@ +//======================================================================== +// +// FoFiEncodings.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFIENCODINGS_H +#define FOFIENCODINGS_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// Type 1 and 1C font data +//------------------------------------------------------------------------ + +extern char *fofiType1StandardEncoding[256]; +extern char *fofiType1ExpertEncoding[256]; + +//------------------------------------------------------------------------ +// Type 1C font data +//------------------------------------------------------------------------ + +extern char *fofiType1CStdStrings[391]; +extern Gushort fofiType1CISOAdobeCharset[229]; +extern Gushort fofiType1CExpertCharset[166]; +extern Gushort fofiType1CExpertSubsetCharset[87]; + +#endif diff --git a/pdftops/FoFiTrueType.cxx b/pdftops/FoFiTrueType.cxx new file mode 100644 index 000000000..64195ab04 --- /dev/null +++ b/pdftops/FoFiTrueType.cxx @@ -0,0 +1,1753 @@ +//======================================================================== +// +// FoFiTrueType.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gtypes.h" +#include "gmem.h" +#include "GString.h" +#include "GHash.h" +#include "FoFiTrueType.h" + +// +// 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 = GID = 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] = gid +// +// 'post' table: mapping from glyph index to glyph name +// +// post[gid] = 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] = gid +// + +//------------------------------------------------------------------------ + +#define ttcfTag 0x74746366 + +//------------------------------------------------------------------------ + +struct TrueTypeTable { + Guint tag; + Guint checksum; + int offset; + int origOffset; + int len; +}; + +struct TrueTypeCmap { + int platform; + int encoding; + int offset; + int len; + int fmt; +}; + +struct TrueTypeLoca { + int idx; + int origOffset; + int newOffset; + int len; +}; + +#define cmapTag 0x636d6170 +#define glyfTag 0x676c7966 +#define headTag 0x68656164 +#define locaTag 0x6c6f6361 +#define nameTag 0x6e616d65 +#define postTag 0x706f7374 + +static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) { + TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; + TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; + + if (loca1->origOffset == loca2->origOffset) { + return loca1->idx - loca2->idx; + } + return loca1->origOffset - loca2->origOffset; +} + +static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { + TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; + TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; + + return loca1->idx - loca2->idx; +} + +static int cmpTrueTypeTableTag(const void *p1, const void *p2) { + TrueTypeTable *tab1 = (TrueTypeTable *)p1; + TrueTypeTable *tab2 = (TrueTypeTable *)p2; + + return (int)tab1->tag - (int)tab2->tag; +} + +//------------------------------------------------------------------------ + +struct T42Table { + char *tag; // 4-byte tag + GBool required; // required by the TrueType spec? +}; + +// TrueType tables to be embedded in Type 42 fonts. +// NB: the table names must be in alphabetical order here. +#define nT42Tables 11 +static T42Table t42Tables[nT42Tables] = { + { "cvt ", gTrue }, + { "fpgm", gTrue }, + { "glyf", gTrue }, + { "head", gTrue }, + { "hhea", gTrue }, + { "hmtx", gTrue }, + { "loca", gTrue }, + { "maxp", gTrue }, + { "prep", gTrue }, + { "vhea", gFalse }, + { "vmtx", gFalse } +}; +#define t42HeadTable 3 +#define t42LocaTable 6 +#define t42GlyfTable 2 +#define t42VheaTable 9 +#define t42VmtxTable 10 + +//------------------------------------------------------------------------ + +// Glyph names in some arbitrary standard order 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" +}; + +//------------------------------------------------------------------------ +// FoFiTrueType +//------------------------------------------------------------------------ + +FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) { + FoFiTrueType *ff; + + ff = new FoFiTrueType(fileA, lenA, gFalse); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType *FoFiTrueType::load(char *fileName) { + FoFiTrueType *ff; + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + ff = new FoFiTrueType(fileA, lenA, gTrue); + if (!ff->parsedOk) { + delete ff; + return NULL; + } + return ff; +} + +FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + tables = NULL; + nTables = 0; + cmaps = NULL; + nCmaps = 0; + nameToGID = NULL; + parsedOk = gFalse; + + parse(); +} + +FoFiTrueType::~FoFiTrueType() { + gfree(tables); + gfree(cmaps); + if (nameToGID) { + delete nameToGID; + } +} + +int FoFiTrueType::getNumCmaps() { + return nCmaps; +} + +int FoFiTrueType::getCmapPlatform(int i) { + return cmaps[i].platform; +} + +int FoFiTrueType::getCmapEncoding(int i) { + return cmaps[i].encoding; +} + +int FoFiTrueType::findCmap(int platform, int encoding) { + int i; + + for (i = 0; i < nCmaps; ++i) { + if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) { + return i; + } + } + return -1; +} + +Gushort FoFiTrueType::mapCodeToGID(int i, int c) { + Gushort gid; + int segCnt, segEnd, segStart, segDelta, segOffset; + int cmapFirst, cmapLen; + int pos, a, b, m; + GBool ok; + + if (i < 0 || i >= nCmaps) { + return 0; + } + ok = gTrue; + pos = cmaps[i].offset; + switch (cmaps[i].fmt) { + case 0: + if (c < 0 || c >= cmaps[i].len - 6) { + return 0; + } + gid = getU8(cmaps[i].offset + 6 + c, &ok); + break; + case 4: + segCnt = getU16BE(pos + 6, &ok) / 2; + a = -1; + b = segCnt - 1; + segEnd = getU16BE(pos + 14 + 2*b, &ok); + if (c > segEnd) { + // malformed font -- the TrueType spec requires the last segEnd + // to be 0xffff + return 0; + } + // invariant: seg[a].end < code <= seg[b].end + while (b - a > 1 && ok) { + m = (a + b) / 2; + segEnd = getU16BE(pos + 14 + 2*m, &ok); + if (segEnd < c) { + a = m; + } else { + b = m; + } + } + segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok); + segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok); + segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok); + if (c < segStart) { + return 0; + } + if (segOffset == 0) { + gid = (c + segDelta) & 0xffff; + } else { + gid = getU16BE(pos + 16 + 6*segCnt + 2*b + + segOffset + 2 * (c - segStart), &ok); + if (gid != 0) { + gid = (gid + segDelta) & 0xffff; + } + } + break; + case 6: + cmapFirst = getU16BE(pos + 6, &ok); + cmapLen = getU16BE(pos + 8, &ok); + if (c < cmapFirst || c >= cmapFirst + cmapLen) { + return 0; + } + gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok); + break; + default: + return 0; + } + if (!ok) { + return 0; + } + return gid; +} + +int FoFiTrueType::mapNameToGID(char *name) { + if (!nameToGID) { + return 0; + } + return nameToGID->lookupInt(name); +} + +int FoFiTrueType::getEmbeddingRights() { + int i, fsType; + GBool ok; + + if ((i = seekTable("OS/2")) < 0) { + return 4; + } + ok = gTrue; + fsType = getU16BE(tables[i].offset + 8, &ok); + if (!ok) { + return 4; + } + if (fsType & 0x0008) { + return 2; + } + if (fsType & 0x0004) { + return 1; + } + if (fsType & 0x0002) { + return 0; + } + return 3; +} + +void FoFiTrueType::convertToType42(char *psName, char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + char buf[512]; + GBool ok; + + // write the header + ok = gTrue; + sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf, strlen(buf)); + + // begin the font dictionary + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + sprintf(buf, "/FontBBox [%d %d %d %d] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + + // write the guts of the dictionary + cvtEncoding(encoding, outputFunc, outputStream); + cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); + cvtSfnts(outputFunc, outputStream, NULL, gFalse); + + // end the dictionary and define the font + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::convertToCIDType2(char *psName, + Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, + void *outputStream) { + char buf[512]; + Gushort cid; + GBool ok; + int i, j, k; + + // write the header + ok = gTrue; + sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0); + (*outputFunc)(outputStream, buf, strlen(buf)); + + // begin the font dictionary + (*outputFunc)(outputStream, "20 dict begin\n", 14); + (*outputFunc)(outputStream, "/CIDFontName /", 14); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); + (*outputFunc)(outputStream, " end def\n", 10); + (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); + if (cidMap) { + sprintf(buf, "/CIDCount %d def\n", nCIDs); + (*outputFunc)(outputStream, buf, strlen(buf)); + if (nCIDs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [", 9); + for (i = 0; i < nCIDs; i += 32768 - 16) { + (*outputFunc)(outputStream, "<\n", 2); + for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { + (*outputFunc)(outputStream, " ", 2); + for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { + cid = cidMap[i+j+k]; + sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, " >", 3); + } + (*outputFunc)(outputStream, "\n", 1); + (*outputFunc)(outputStream, "] def\n", 6); + } else { + (*outputFunc)(outputStream, "/CIDMap <\n", 10); + for (i = 0; i < nCIDs; i += 16) { + (*outputFunc)(outputStream, " ", 2); + for (j = 0; j < 16 && i+j < nCIDs; ++j) { + cid = cidMap[i+j]; + sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "\n", 1); + } + (*outputFunc)(outputStream, "> def\n", 6); + } + } else { + // direct mapping - just fill the string(s) with s[i]=i + sprintf(buf, "/CIDCount %d def\n", nGlyphs); + (*outputFunc)(outputStream, buf, strlen(buf)); + if (nGlyphs > 32767) { + (*outputFunc)(outputStream, "/CIDMap [\n", 10); + for (i = 0; i < nGlyphs; i += 32767) { + j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; + sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add" + " 255 and put\n", i); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, " } for\n", 8); + } + (*outputFunc)(outputStream, "] def\n", 6); + } else { + sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, " 0 1 %d {\n", nGlyphs - 1); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, + " 2 copy dup 2 mul exch -8 bitshift put\n", 42); + (*outputFunc)(outputStream, + " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); + (*outputFunc)(outputStream, " } for\n", 8); + (*outputFunc)(outputStream, "def\n", 4); + } + } + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + sprintf(buf, "/FontBBox [%d %d %d %d] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); + (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); + (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); + (*outputFunc)(outputStream, " end readonly def\n", 19); + + // write the guts of the dictionary + cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics); + + // end the dictionary and define the font + (*outputFunc)(outputStream, + "CIDFontName currentdict end /CIDFont defineresource pop\n", + 56); +} + +void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, + void *outputStream) { + char buf[512]; + GString *sfntsName; + int n, i, j; + + // write the Type 42 sfnts array + sfntsName = (new GString(psName))->append("_sfnts"); + cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics); + delete sfntsName; + + // write the descendant Type 42 fonts + n = cidMap ? nCIDs : nGlyphs; + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "10 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + sprintf(buf, "_%02x def\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 42 def\n", 17); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + sprintf(buf, "/FontBBox [%d %d %d %d] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); + (*outputFunc)(outputStream, "/sfnts ", 7); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, "_sfnts def\n", 11); + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < n; ++j) { + sprintf(buf, "dup %d /c%02x put\n", j, j); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + for (j = 0; j < 256 && i+j < n; ++j) { + sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, + "FontName currentdict end definefont pop\n", 40); + } + + // write the Type 0 parent font + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < n; i += 256) { + sprintf(buf, "%d\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < n; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, strlen(psName)); + sprintf(buf, "_%02x findfont\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); +} + +void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, + void *outputStream, char *name, + Gushort *codeToGID) { + // this substitute cmap table maps char codes 0000-ffff directly to + // glyphs 0000-ffff + static char cmapTab[36] = { + 0, 0, // table version number + 0, 1, // number of encoding tables + 0, 1, // platform ID + 0, 0, // encoding ID + 0, 0, 0, 12, // offset of subtable + 0, 4, // subtable format + 0, 24, // subtable length + 0, 0, // subtable version + 0, 2, // segment count * 2 + 0, 2, // 2 * 2 ^ floor(log2(segCount)) + 0, 0, // floor(log2(segCount)) + 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) + (char)0xff, (char)0xff, // endCount[0] + 0, 0, // reserved + 0, 0, // startCount[0] + 0, 0, // idDelta[0] + 0, 0 // pad to a mulitple of four bytes + }; + static char nameTab[8] = { + 0, 0, // format + 0, 0, // number of name records + 0, 6, // offset to start of string storage + 0, 0 // pad to multiple of four bytes + }; + static char postTab[32] = { + 0, 1, 0, 0, // format + 0, 0, 0, 0, // italic angle + 0, 0, // underline position + 0, 0, // underline thickness + 0, 0, 0, 0, // fixed pitch + 0, 0, 0, 0, // min Type 42 memory + 0, 0, 0, 0, // max Type 42 memory + 0, 0, 0, 0, // min Type 1 memory + 0, 0, 0, 0 // max Type 1 memory + }; + GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen; + int nZeroLengthTables; + TrueTypeLoca *locaTable; + TrueTypeTable *newTables; + char *newNameTab, *newCmapTab; + int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; + Guint locaChecksum, glyfChecksum, fileChecksum; + char *tableDir; + char locaBuf[4], checksumBuf[4]; + GBool ok; + Guint t; + int pos, i, j, k, n; + + // check for missing tables + missingCmap = (cmapIdx = seekTable("cmap")) < 0; + missingName = seekTable("name") < 0; + missingPost = seekTable("post") < 0; + + // read the loca table, check to see if it's sorted + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); + unsortedLoca = gFalse; + i = seekTable("loca"); + pos = tables[i].offset; + ok = gTrue; + for (i = 0; i <= nGlyphs; ++i) { + if (locaFmt) { + locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); + } else { + locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); + } + if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { + unsortedLoca = gTrue; + } + locaTable[i].idx = i; + } + + // check for zero-length tables + nZeroLengthTables = 0; + for (i = 0; i < nTables; ++i) { + if (tables[i].len == 0) { + ++nZeroLengthTables; + } + } + + // check for an incorrect cmap table length + badCmapLen = gFalse; + cmapLen = 0; // make gcc happy + if (!missingCmap) { + cmapLen = cmaps[0].offset + cmaps[0].len; + for (i = 1; i < nCmaps; ++i) { + if (cmaps[i].offset + cmaps[i].len > cmapLen) { + cmapLen = cmaps[i].offset + cmaps[i].len; + } + } + cmapLen -= tables[cmapIdx].offset; + if (cmapLen > tables[cmapIdx].len) { + badCmapLen = gTrue; + } + } + + // if nothing is broken, just write the TTF file as is + if (!missingCmap && !missingName && !missingPost && !unsortedLoca && + !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) { + (*outputFunc)(outputStream, (char *)file, len); + goto done1; + } + + // sort the 'loca' table: some (non-compliant) fonts have + // out-of-order loca tables; in order to correctly handle the case + // where (compliant) fonts have empty entries in the middle of the + // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, + // and idx as its secondary key (ensuring that adjacent entries with + // the same pos value remain in the same order) + glyfLen = 0; // make gcc happy + if (unsortedLoca) { + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaOffset); + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; + } + locaTable[nGlyphs].len = 0; + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].newOffset = pos; + pos += locaTable[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + glyfLen = pos; + } + + // compute checksums for the loca and glyf tables + locaChecksum = glyfChecksum = 0; + if (unsortedLoca) { + if (locaFmt) { + for (j = 0; j <= nGlyphs; ++j) { + locaChecksum += locaTable[j].newOffset; + } + } else { + for (j = 0; j <= nGlyphs; j += 2) { + locaChecksum += locaTable[j].newOffset << 16; + if (j + 1 <= nGlyphs) { + locaChecksum += locaTable[j+1].newOffset; + } + } + } + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + glyfChecksum += computeTableChecksum(file + pos + k, n); + } + } + } + } + + // construct the new name table + if (name) { + n = strlen(name); + newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; + newNameTab = (char *)gmalloc(newNameLen); + memset(newNameTab, 0, newNameLen); + newNameTab[0] = 0; // format selector + newNameTab[1] = 0; + newNameTab[2] = 0; // number of name records + newNameTab[3] = 4; + newNameTab[4] = 0; // offset to start of string storage + newNameTab[5] = 6 + 4*12; + next = 0; + for (i = 0; i < 4; ++i) { + newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft + newNameTab[6 + i*12 + 1] = 3; + newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode + newNameTab[6 + i*12 + 3] = 1; + newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English + newNameTab[6 + i*12 + 5] = 0x09; + newNameTab[6 + i*12 + 6] = 0; // name ID + newNameTab[6 + i*12 + 7] = i + 1; + newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length + newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); + newNameTab[6 + i*12 + 10] = next >> 8; // string offset + newNameTab[6 + i*12 + 11] = next & 0xff; + if (i+1 == 2) { + memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); + next += 14; + } else { + for (j = 0; j < n; ++j) { + newNameTab[6 + 4*12 + next + 2*j] = 0; + newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; + } + next += 2*n; + } + } + } else { + newNameLen = 0; + newNameTab = NULL; + } + + // construct the new cmap table + if (codeToGID) { + newCmapLen = 44 + 256 * 2; + newCmapTab = (char *)gmalloc(newCmapLen); + newCmapTab[0] = 0; // table version number = 0 + newCmapTab[1] = 0; + newCmapTab[2] = 0; // number of encoding tables = 1 + newCmapTab[3] = 1; + newCmapTab[4] = 0; // platform ID = Microsoft + newCmapTab[5] = 3; + newCmapTab[6] = 0; // encoding ID = Unicode + newCmapTab[7] = 1; + newCmapTab[8] = 0; // offset of subtable + newCmapTab[9] = 0; + newCmapTab[10] = 0; + newCmapTab[11] = 12; + newCmapTab[12] = 0; // subtable format = 4 + newCmapTab[13] = 4; + newCmapTab[14] = 0x02; // subtable length + newCmapTab[15] = 0x20; + newCmapTab[16] = 0; // subtable version = 0 + newCmapTab[17] = 0; + newCmapTab[18] = 0; // segment count * 2 + newCmapTab[19] = 4; + newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) + newCmapTab[21] = 4; + newCmapTab[22] = 0; // floor(log2(segCount)) + newCmapTab[23] = 1; + newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) + newCmapTab[25] = 0; + newCmapTab[26] = 0x00; // endCount[0] + newCmapTab[27] = (char)0xff; + newCmapTab[28] = (char)0xff; // endCount[1] + newCmapTab[29] = (char)0xff; + newCmapTab[30] = 0; // reserved + newCmapTab[31] = 0; + newCmapTab[32] = 0x00; // startCount[0] + newCmapTab[33] = 0x00; + newCmapTab[34] = (char)0xff; // startCount[1] + newCmapTab[35] = (char)0xff; + newCmapTab[36] = 0; // idDelta[0] + newCmapTab[37] = 0; + newCmapTab[38] = 0; // idDelta[1] + newCmapTab[39] = 1; + newCmapTab[40] = 0; // idRangeOffset[0] + newCmapTab[41] = 4; + newCmapTab[42] = 0; // idRangeOffset[1] + newCmapTab[43] = 0; + for (i = 0; i < 256; ++i) { + newCmapTab[44 + 2*i] = codeToGID[i] >> 8; + newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; + } + } else { + newCmapLen = 0; + newCmapTab = NULL; + } + + // construct the new table directory: + // - keep all original tables with non-zero length + // - fix the cmap table's length, if necessary + // - add missing tables + // - sort the table by tag + // - compute new table positions, including 4-byte alignment + // - (re)compute table checksums + nNewTables = nTables - nZeroLengthTables + + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + + (missingPost ? 1 : 0); + newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); + j = 0; + for (i = 0; i < nTables; ++i) { + if (tables[i].len > 0) { + newTables[j] = tables[i]; + newTables[j].origOffset = tables[i].offset; + if (checkRegion(tables[i].offset, newTables[i].len)) { + newTables[j].checksum = + computeTableChecksum(file + tables[i].offset, tables[i].len); + if (tables[i].tag == headTag) { + // don't include the file checksum + newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); + } + } + if (newTables[j].tag == cmapTag && codeToGID) { + newTables[j].len = newCmapLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + } else if (newTables[j].tag == cmapTag && badCmapLen) { + newTables[j].len = cmapLen; + } else if (newTables[j].tag == locaTag && unsortedLoca) { + newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); + newTables[j].checksum = locaChecksum; + } else if (newTables[j].tag == glyfTag && unsortedLoca) { + newTables[j].len = glyfLen; + newTables[j].checksum = glyfChecksum; + } else if (newTables[j].tag == nameTag && name) { + newTables[j].len = newNameLen; + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + } + ++j; + } + } + if (missingCmap) { + newTables[j].tag = cmapTag; + if (codeToGID) { + newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, + newCmapLen); + newTables[j].len = newCmapLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, + sizeof(cmapTab)); + newTables[j].len = sizeof(cmapTab); + } + ++j; + } + if (missingName) { + newTables[j].tag = nameTag; + if (name) { + newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, + newNameLen); + newTables[j].len = newNameLen; + } else { + newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, + sizeof(nameTab)); + newTables[j].len = sizeof(nameTab); + } + ++j; + } + if (missingPost) { + newTables[j].tag = postTag; + newTables[j].checksum = computeTableChecksum((Guchar *)postTab, + sizeof(postTab)); + newTables[j].len = sizeof(postTab); + ++j; + } + qsort(newTables, nNewTables, sizeof(TrueTypeTable), + &cmpTrueTypeTableTag); + pos = 12 + nNewTables * 16; + for (i = 0; i < nNewTables; ++i) { + newTables[i].offset = pos; + pos += newTables[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + + // write the table directory + tableDir = (char *)gmalloc(12 + nNewTables * 16); + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables + tableDir[5] = (char)(nNewTables & 0xff); + for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ; + t = 1 << (4 + i); + tableDir[6] = (char)((t >> 8) & 0xff); // searchRange + tableDir[7] = (char)(t & 0xff); + tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector + tableDir[9] = (char)(i & 0xff); + t = nNewTables * 16 - t; + tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift + tableDir[11] = (char)(t & 0xff); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = (char)(newTables[i].tag >> 24); + tableDir[pos+ 1] = (char)(newTables[i].tag >> 16); + tableDir[pos+ 2] = (char)(newTables[i].tag >> 8); + tableDir[pos+ 3] = (char) newTables[i].tag; + tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24); + tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16); + tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8); + tableDir[pos+ 7] = (char) newTables[i].checksum; + tableDir[pos+ 8] = (char)(newTables[i].offset >> 24); + tableDir[pos+ 9] = (char)(newTables[i].offset >> 16); + tableDir[pos+10] = (char)(newTables[i].offset >> 8); + tableDir[pos+11] = (char) newTables[i].offset; + tableDir[pos+12] = (char)(newTables[i].len >> 24); + tableDir[pos+13] = (char)(newTables[i].len >> 16); + tableDir[pos+14] = (char)(newTables[i].len >> 8); + tableDir[pos+15] = (char) newTables[i].len; + pos += 16; + } + (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); + + // compute the file checksum + fileChecksum = computeTableChecksum((Guchar *)tableDir, + 12 + nNewTables * 16); + for (i = 0; i < nNewTables; ++i) { + fileChecksum += newTables[i].checksum; + } + fileChecksum = 0xb1b0afba - fileChecksum; + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (newTables[i].tag == headTag) { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); + checksumBuf[0] = fileChecksum >> 24; + checksumBuf[1] = fileChecksum >> 16; + checksumBuf[2] = fileChecksum >> 8; + checksumBuf[3] = fileChecksum; + (*outputFunc)(outputStream, checksumBuf, 4); + (*outputFunc)(outputStream, + (char *)file + newTables[i].origOffset + 12, + newTables[i].len - 12); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } else if (newTables[i].tag == cmapTag && codeToGID) { + (*outputFunc)(outputStream, newCmapTab, newTables[i].len); + } else if (newTables[i].tag == cmapTag && missingCmap) { + (*outputFunc)(outputStream, cmapTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && name) { + (*outputFunc)(outputStream, newNameTab, newTables[i].len); + } else if (newTables[i].tag == nameTag && missingName) { + (*outputFunc)(outputStream, nameTab, newTables[i].len); + } else if (newTables[i].tag == postTag && missingPost) { + (*outputFunc)(outputStream, postTab, newTables[i].len); + } else if (newTables[i].tag == locaTag && unsortedLoca) { + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + locaBuf[0] = (char)(locaTable[j].newOffset >> 24); + locaBuf[1] = (char)(locaTable[j].newOffset >> 16); + locaBuf[2] = (char)(locaTable[j].newOffset >> 8); + locaBuf[3] = (char) locaTable[j].newOffset; + (*outputFunc)(outputStream, locaBuf, 4); + } else { + locaBuf[0] = (char)(locaTable[j].newOffset >> 9); + locaBuf[1] = (char)(locaTable[j].newOffset >> 1); + (*outputFunc)(outputStream, locaBuf, 2); + } + } + } else if (newTables[i].tag == glyfTag && unsortedLoca) { + pos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + n = locaTable[j].len; + if (n > 0) { + k = locaTable[j].origOffset; + if (checkRegion(pos + k, n)) { + (*outputFunc)(outputStream, (char *)file + pos + k, n); + } else { + for (k = 0; k < n; ++k) { + (*outputFunc)(outputStream, "\0", 1); + } + } + if ((k = locaTable[j].len & 3)) { + (*outputFunc)(outputStream, "\0\0\0\0", 4 - k); + } + } + } + } else { + if (checkRegion(newTables[i].origOffset, newTables[i].len)) { + (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, + newTables[i].len); + } else { + for (j = 0; j < newTables[i].len; ++j) { + (*outputFunc)(outputStream, "\0", 1); + } + } + } + if (newTables[i].len & 3) { + (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3)); + } + } + + gfree(newCmapTab); + gfree(newNameTab); + gfree(tableDir); + gfree(newTables); + done1: + gfree(locaTable); +} + +void FoFiTrueType::cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + char buf[64]; + int i; + + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + if (encoding) { + for (i = 0; i < 256; ++i) { + if (!(name = encoding[i])) { + name = ".notdef"; + } + sprintf(buf, "dup %d /", i); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, name, strlen(name)); + (*outputFunc)(outputStream, " put\n", 5); + } + } else { + for (i = 0; i < 256; ++i) { + sprintf(buf, "dup %d /c%02x put\n", i, i); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); +} + +void FoFiTrueType::cvtCharStrings(char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream) { + char *name; + char buf[64], buf2[16]; + int i, k; + + // always define '.notdef' + (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); + (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); + + // if there's no 'cmap' table, punt + if (nCmaps == 0) { + goto err; + } + + // map char name to glyph index: + // 1. use encoding to map name to char code + // 2. use codeToGID to map char code to glyph index + // N.B. We do this in reverse order because font subsets can have + // weird encodings that use the same character name twice, and + // the first definition is probably the one we want. + k = 0; // make gcc happy + for (i = 255; i >= 0; --i) { + if (encoding) { + name = encoding[i]; + } else { + sprintf(buf2, "c%02x", i); + name = buf2; + } + if (name && strcmp(name, ".notdef")) { + k = codeToGID[i]; + // note: Distiller (maybe Adobe's PS interpreter in general) + // doesn't like TrueType fonts that have CharStrings entries + // which point to nonexistent glyphs, hence the (k < nGlyphs) + // test + if (k > 0 && k < nGlyphs) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, name, strlen(name)); + sprintf(buf, " %d def\n", k); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } + } + + err: + (*outputFunc)(outputStream, "end readonly def\n", 17); +} + +void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name, + GBool needVerticalMetrics) { + Guchar headData[54]; + TrueTypeLoca *locaTable; + Guchar *locaData; + TrueTypeTable newTables[nT42Tables]; + Guchar tableDir[12 + nT42Tables*16]; + GBool ok; + Guint checksum; + int nNewTables; + int length, pos, glyfPos, i, j, k; + Guchar vheaTab[36] = { + 0, 1, 0, 0, // table version number + 0, 0, // ascent + 0, 0, // descent + 0, 0, // reserved + 0, 0, // max advance height + 0, 0, // min top side bearing + 0, 0, // min bottom side bearing + 0, 0, // y max extent + 0, 0, // caret slope rise + 0, 1, // caret slope run + 0, 0, // caret offset + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // reserved + 0, 0, // metric data format + 0, 1 // number of advance heights in vmtx table + }; + Guchar *vmtxTab; + GBool needVhea, needVmtx; + int advance; + + // construct the 'head' table, zero out the font checksum + i = seekTable("head"); + pos = tables[i].offset; + if (!checkRegion(pos, 54)) { + return; + } + memcpy(headData, file + pos, 54); + headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0; + + // read the original 'loca' table, pad entries out to 4 bytes, and + // sort it into proper order -- some (non-compliant) fonts have + // out-of-order loca tables; in order to correctly handle the case + // where (compliant) fonts have empty entries in the middle of the + // table, cmpTrueTypeLocaPos uses offset as its primary sort key, + // and idx as its secondary key (ensuring that adjacent entries with + // the same pos value remain in the same order) + locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); + i = seekTable("loca"); + pos = tables[i].offset; + ok = gTrue; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].idx = i; + if (locaFmt) { + locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); + } else { + locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); + } + } + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaOffset); + for (i = 0; i < nGlyphs; ++i) { + locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; + } + locaTable[nGlyphs].len = 0; + qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), + &cmpTrueTypeLocaIdx); + pos = 0; + for (i = 0; i <= nGlyphs; ++i) { + locaTable[i].newOffset = pos; + pos += locaTable[i].len; + if (pos & 3) { + pos += 4 - (pos & 3); + } + } + + // construct the new 'loca' table + locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); + for (i = 0; i <= nGlyphs; ++i) { + pos = locaTable[i].newOffset; + if (locaFmt) { + locaData[4*i ] = (Guchar)(pos >> 24); + locaData[4*i+1] = (Guchar)(pos >> 16); + locaData[4*i+2] = (Guchar)(pos >> 8); + locaData[4*i+3] = (Guchar) pos; + } else { + locaData[2*i ] = (Guchar)(pos >> 9); + locaData[2*i+1] = (Guchar)(pos >> 1); + } + } + + // count the number of tables + nNewTables = 0; + for (i = 0; i < nT42Tables; ++i) { + if (t42Tables[i].required || + seekTable(t42Tables[i].tag) >= 0) { + ++nNewTables; + } + } + vmtxTab = NULL; // make gcc happy + advance = 0; // make gcc happy + if (needVerticalMetrics) { + needVhea = seekTable("vhea") < 0; + needVmtx = seekTable("vmtx") < 0; + if (needVhea || needVmtx) { + i = seekTable("head"); + advance = getU16BE(tables[i].offset + 18, &ok); // units per em + if (needVhea) { + ++nNewTables; + } + if (needVmtx) { + ++nNewTables; + } + } + } + + // construct the new table headers, including table checksums + // (pad each table out to a multiple of 4 bytes) + pos = 12 + nNewTables*16; + k = 0; + for (i = 0; i < nT42Tables; ++i) { + length = -1; + checksum = 0; // make gcc happy + if (i == t42HeadTable) { + length = 54; + checksum = computeTableChecksum(headData, 54); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + checksum = computeTableChecksum(locaData, length); + } else if (i == t42GlyfTable) { + length = 0; + checksum = 0; + glyfPos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + length += locaTable[j].len; + if (length & 3) { + length += 4 - (length & 3); + } + if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { + checksum += + computeTableChecksum(file + glyfPos + locaTable[j].origOffset, + locaTable[j].len); + } + } + } else { + if ((j = seekTable(t42Tables[i].tag)) >= 0) { + length = tables[j].len; + if (checkRegion(tables[j].offset, length)) { + checksum = computeTableChecksum(file + tables[j].offset, length); + } + } else if (needVerticalMetrics && i == t42VheaTable) { + vheaTab[10] = advance / 256; // max advance height + vheaTab[11] = advance % 256; + length = sizeof(vheaTab); + checksum = computeTableChecksum(vheaTab, length); + } else if (needVerticalMetrics && i == t42VmtxTable) { + length = 4 + (nGlyphs - 1) * 4; + vmtxTab = (Guchar *)gmalloc(length); + vmtxTab[0] = advance / 256; + vmtxTab[1] = advance % 256; + for (j = 2; j < length; j += 2) { + vmtxTab[j] = 0; + vmtxTab[j+1] = 0; + } + checksum = computeTableChecksum(vmtxTab, length); + } else if (t42Tables[i].required) { + //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", + //~ t42Tables[i].tag); + length = 0; + checksum = 0; + } + } + if (length >= 0) { + newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) | + ((t42Tables[i].tag[1] & 0xff) << 16) | + ((t42Tables[i].tag[2] & 0xff) << 8) | + (t42Tables[i].tag[3] & 0xff); + newTables[k].checksum = checksum; + newTables[k].offset = pos; + newTables[k].len = length; + pos += length; + if (pos & 3) { + pos += 4 - (length & 3); + } + ++k; + } + } + + // construct the table directory + tableDir[0] = 0x00; // sfnt version + tableDir[1] = 0x01; + tableDir[2] = 0x00; + tableDir[3] = 0x00; + tableDir[4] = 0; // numTables + tableDir[5] = nNewTables; + tableDir[6] = 0; // searchRange + tableDir[7] = (Guchar)128; + tableDir[8] = 0; // entrySelector + tableDir[9] = 3; + tableDir[10] = 0; // rangeShift + tableDir[11] = (Guchar)(16 * nNewTables - 128); + pos = 12; + for (i = 0; i < nNewTables; ++i) { + tableDir[pos ] = (Guchar)(newTables[i].tag >> 24); + tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16); + tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8); + tableDir[pos+ 3] = (Guchar) newTables[i].tag; + tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24); + tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16); + tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8); + tableDir[pos+ 7] = (Guchar) newTables[i].checksum; + tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24); + tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16); + tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8); + tableDir[pos+11] = (Guchar) newTables[i].offset; + tableDir[pos+12] = (Guchar)(newTables[i].len >> 24); + tableDir[pos+13] = (Guchar)(newTables[i].len >> 16); + tableDir[pos+14] = (Guchar)(newTables[i].len >> 8); + tableDir[pos+15] = (Guchar) newTables[i].len; + pos += 16; + } + + // compute the font checksum and store it in the head table + checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); + for (i = 0; i < nNewTables; ++i) { + checksum += newTables[i].checksum; + } + checksum = 0xb1b0afba - checksum; // because the TrueType spec says so + headData[ 8] = (Guchar)(checksum >> 24); + headData[ 9] = (Guchar)(checksum >> 16); + headData[10] = (Guchar)(checksum >> 8); + headData[11] = (Guchar) checksum; + + // start the sfnts array + if (name) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, name->getCString(), name->getLength()); + (*outputFunc)(outputStream, " [\n", 3); + } else { + (*outputFunc)(outputStream, "/sfnts [\n", 9); + } + + // write the table directory + dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); + + // write the tables + for (i = 0; i < nNewTables; ++i) { + if (i == t42HeadTable) { + dumpString(headData, 54, outputFunc, outputStream); + } else if (i == t42LocaTable) { + length = (nGlyphs + 1) * (locaFmt ? 4 : 2); + dumpString(locaData, length, outputFunc, outputStream); + } else if (i == t42GlyfTable) { + glyfPos = tables[seekTable("glyf")].offset; + for (j = 0; j < nGlyphs; ++j) { + if (locaTable[j].len > 0 && + checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { + dumpString(file + glyfPos + locaTable[j].origOffset, + locaTable[j].len, outputFunc, outputStream); + } + } + } else { + // length == 0 means the table is missing and the error was + // already reported during the construction of the table + // headers + if ((length = newTables[i].len) > 0) { + if ((j = seekTable(t42Tables[i].tag)) >= 0 && + checkRegion(tables[j].offset, tables[j].len)) { + dumpString(file + tables[j].offset, tables[j].len, + outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VheaTable) { + dumpString(vheaTab, length, outputFunc, outputStream); + } else if (needVerticalMetrics && i == t42VmtxTable) { + dumpString(vmtxTab, length, outputFunc, outputStream); + gfree(vmtxTab); + } + } + } + } + + // end the sfnts array + (*outputFunc)(outputStream, "] def\n", 6); + + gfree(locaData); + gfree(locaTable); +} + +void FoFiTrueType::dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream) { + char buf[64]; + int pad, i, j; + + (*outputFunc)(outputStream, "<", 1); + for (i = 0; i < length; i += 32) { + for (j = 0; j < 32 && i+j < length; ++j) { + sprintf(buf, "%02X", s[i+j] & 0xff); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (i % (65536 - 32) == 65536 - 64) { + (*outputFunc)(outputStream, ">\n<", 3); + } else if (i+32 < length) { + (*outputFunc)(outputStream, "\n", 1); + } + } + if (length & 3) { + pad = 4 - (length & 3); + for (i = 0; i < pad; ++i) { + (*outputFunc)(outputStream, "00", 2); + } + } + // add an extra zero byte because the Adobe Type 42 spec says so + (*outputFunc)(outputStream, "00>\n", 4); +} + +Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { + Guint checksum, word; + int i; + + checksum = 0; + for (i = 0; i+3 < length; i += 4) { + word = ((data[i ] & 0xff) << 24) + + ((data[i+1] & 0xff) << 16) + + ((data[i+2] & 0xff) << 8) + + (data[i+3] & 0xff); + checksum += word; + } + if (length & 3) { + word = 0; + i = length & ~3; + switch (length & 3) { + case 3: + word |= (data[i+2] & 0xff) << 8; + case 2: + word |= (data[i+1] & 0xff) << 16; + case 1: + word |= (data[i ] & 0xff) << 24; + break; + } + checksum += word; + } + return checksum; +} + +void FoFiTrueType::parse() { + Guint topTag; + int pos, i, j; + + parsedOk = gTrue; + + // look for a collection (TTC) + topTag = getU32BE(0, &parsedOk); + if (!parsedOk) { + return; + } + if (topTag == ttcfTag) { + pos = getU32BE(12, &parsedOk); + if (!parsedOk) { + return; + } + } else { + pos = 0; + } + + // read the table directory + nTables = getU16BE(pos + 4, &parsedOk); + if (!parsedOk) { + return; + } + tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); + pos += 12; + for (i = 0; i < nTables; ++i) { + tables[i].tag = getU32BE(pos, &parsedOk); + tables[i].checksum = getU32BE(pos + 4, &parsedOk); + tables[i].offset = (int)getU32BE(pos + 8, &parsedOk); + tables[i].len = (int)getU32BE(pos + 12, &parsedOk); + if (tables[i].offset + tables[i].len < tables[i].offset || + tables[i].offset + tables[i].len > len) { + parsedOk = gFalse; + } + pos += 16; + } + if (!parsedOk) { + return; + } + + // 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) { + parsedOk = gFalse; + return; + } + + // read the cmaps + if ((i = seekTable("cmap")) >= 0) { + pos = tables[i].offset + 2; + nCmaps = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + return; + } + cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); + for (j = 0; j < nCmaps; ++j) { + cmaps[j].platform = getU16BE(pos, &parsedOk); + cmaps[j].encoding = getU16BE(pos + 2, &parsedOk); + cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk); + pos += 8; + cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk); + cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk); + } + if (!parsedOk) { + return; + } + } else { + nCmaps = 0; + } + + // get the number of glyphs from the maxp table + i = seekTable("maxp"); + nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk); + if (!parsedOk) { + return; + } + + // get the bbox and loca table format from the head table + i = seekTable("head"); + bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk); + bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk); + bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk); + bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk); + locaFmt = getS16BE(tables[i].offset + 50, &parsedOk); + if (!parsedOk) { + return; + } + + // make sure the loca table is sane (correct length and entries are + // in bounds) + i = seekTable("loca"); + if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { + parsedOk = gFalse; + return; + } + for (j = 0; j <= nGlyphs; ++j) { + if (locaFmt) { + pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk); + } else { + pos = getU16BE(tables[i].offset + j*2, &parsedOk); + } + if (pos < 0 || pos > len) { + parsedOk = gFalse; + } + } + if (!parsedOk) { + return; + } + + // read the post table + readPostTable(); +} + +void FoFiTrueType::readPostTable() { + GString *name; + int tablePos, postFmt, stringIdx, stringPos; + GBool ok; + int i, j, n, m; + + ok = gTrue; + if ((i = seekTable("post")) < 0) { + return; + } + tablePos = tables[i].offset; + postFmt = getU32BE(tablePos, &ok); + if (!ok) { + goto err; + } + if (postFmt == 0x00010000) { + nameToGID = new GHash(gTrue); + for (i = 0; i < 258; ++i) { + nameToGID->add(new GString(macGlyphNames[i]), i); + } + } else if (postFmt == 0x00020000) { + nameToGID = new GHash(gTrue); + n = getU16BE(tablePos + 32, &ok); + if (!ok) { + goto err; + } + if (n > nGlyphs) { + n = nGlyphs; + } + stringIdx = 0; + stringPos = tablePos + 34 + 2*n; + for (i = 0; i < n; ++i) { + j = getU16BE(tablePos + 34 + 2*i, &ok); + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } else { + j -= 258; + if (j != stringIdx) { + for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; + stringIdx < j; + ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; + if (!ok) { + goto err; + } + } + m = getU8(stringPos, &ok); + if (!ok || !checkRegion(stringPos + 1, m)) { + goto err; + } + name = new GString((char *)&file[stringPos + 1], m); + nameToGID->removeInt(name); + nameToGID->add(name, i); + ++stringIdx; + stringPos += 1 + m; + } + } + } else if (postFmt == 0x00028000) { + nameToGID = new GHash(gTrue); + for (i = 0; i < nGlyphs; ++i) { + j = getU8(tablePos + 32 + i, &ok); + if (!ok) { + goto err; + } + if (j < 258) { + nameToGID->removeInt(macGlyphNames[j]); + nameToGID->add(new GString(macGlyphNames[j]), i); + } + } + } + + return; + + err: + if (nameToGID) { + delete nameToGID; + nameToGID = NULL; + } +} + +int FoFiTrueType::seekTable(char *tag) { + Guint tagI; + int i; + + tagI = ((tag[0] & 0xff) << 24) | + ((tag[1] & 0xff) << 16) | + ((tag[2] & 0xff) << 8) | + (tag[3] & 0xff); + for (i = 0; i < nTables; ++i) { + if (tables[i].tag == tagI) { + return i; + } + } + return -1; +} diff --git a/pdftops/FoFiTrueType.h b/pdftops/FoFiTrueType.h new file mode 100644 index 000000000..715bb60f1 --- /dev/null +++ b/pdftops/FoFiTrueType.h @@ -0,0 +1,140 @@ +//======================================================================== +// +// FoFiTrueType.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITRUETYPE_H +#define FOFITRUETYPE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +class GString; +class GHash; +struct TrueTypeTable; +struct TrueTypeCmap; + +//------------------------------------------------------------------------ +// FoFiTrueType +//------------------------------------------------------------------------ + +class FoFiTrueType: public FoFiBase { +public: + + // Create a FoFiTrueType object from a memory buffer. + static FoFiTrueType *make(char *fileA, int lenA); + + // Create a FoFiTrueType object from a file on disk. + static FoFiTrueType *load(char *fileName); + + virtual ~FoFiTrueType(); + + // Return the number of cmaps defined by this font. + int getNumCmaps(); + + // Return the platform ID of the th cmap. + int getCmapPlatform(int i); + + // Return the encoding ID of the th cmap. + int getCmapEncoding(int i); + + // Return the index of the cmap for , . Returns + // -1 if there is no corresponding cmap. + int findCmap(int platform, int encoding); + + // Return the GID corresponding to according to the th cmap. + Gushort mapCodeToGID(int i, int c); + + // Returns the GID corresponding to according to the post + // table. Returns 0 if there is no mapping for or if the + // font does not have a post table. + int mapNameToGID(char *name); + + // Returns the least restrictive embedding licensing right (as + // defined by the TrueType spec): + // * 4: OS/2 table is missing or invalid + // * 3: installable embedding + // * 2: editable embedding + // * 1: preview & print embedding + // * 0: restricted license embedding + int getEmbeddingRights(); + + // Convert to a Type 42 font, suitable for embedding in a PostScript + // file. will be used as the PostScript font name (so we + // don't need to depend on the 'name' table in the font). The + // array specifies the mapping from char codes to names. + // If is NULL, the encoding is unknown or undefined. The + // array specifies the mapping from char codes to GIDs. + void convertToType42(char *psName, char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 2 CIDFont, suitable for embedding in a + // PostScript file. will be used as the PostScript font + // name (so we don't need to depend on the 'name' table in the + // font). The array maps CIDs to GIDs; it has + // entries. + void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. will be used as the + // PostScript font name (so we don't need to depend on the 'name' + // table in the font). The array maps CIDs to GIDs; it has + // entries. + void convertToType0(char *psName, Gushort *cidMap, int nCIDs, + GBool needVerticalMetrics, + FoFiOutputFunc outputFunc, void *outputStream); + + // Write a clean TTF file, filling in missing tables and correcting + // various other errors. If is non-NULL, the font is renamed + // to . If is non-NULL, the font is re-encoded, + // using a Windows Unicode cmap. If is NULL and the font is + // complete and correct, it will be written unmodified. + void writeTTF(FoFiOutputFunc outputFunc, void *outputStream, + char *name = NULL, Gushort *codeToGID = NULL); + +private: + + FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA); + void cvtEncoding(char **encoding, + FoFiOutputFunc outputFunc, + void *outputStream); + void cvtCharStrings(char **encoding, + Gushort *codeToGID, + FoFiOutputFunc outputFunc, + void *outputStream); + void cvtSfnts(FoFiOutputFunc outputFunc, + void *outputStream, GString *name, + GBool needVerticalMetrics); + void dumpString(Guchar *s, int length, + FoFiOutputFunc outputFunc, + void *outputStream); + Guint computeTableChecksum(Guchar *data, int length); + void parse(); + void readPostTable(); + int seekTable(char *tag); + + TrueTypeTable *tables; + int nTables; + TrueTypeCmap *cmaps; + int nCmaps; + int nGlyphs; + int locaFmt; + int bbox[4]; + GHash *nameToGID; + + GBool parsedOk; +}; + +#endif diff --git a/pdftops/FoFiType1.cxx b/pdftops/FoFiType1.cxx new file mode 100644 index 000000000..103cc55a5 --- /dev/null +++ b/pdftops/FoFiType1.cxx @@ -0,0 +1,207 @@ +//======================================================================== +// +// FoFiType1.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "FoFiEncodings.h" +#include "FoFiType1.h" + +//------------------------------------------------------------------------ +// FoFiType1 +//------------------------------------------------------------------------ + +FoFiType1 *FoFiType1::make(char *fileA, int lenA) { + return new FoFiType1(fileA, lenA, gFalse); +} + +FoFiType1 *FoFiType1::load(char *fileName) { + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + return new FoFiType1(fileA, lenA, gTrue); +} + +FoFiType1::FoFiType1(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + name = NULL; + encoding = NULL; + parsed = gFalse; +} + +FoFiType1::~FoFiType1() { + int i; + + if (name) { + gfree(name); + } + if (encoding && encoding != fofiType1StandardEncoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } +} + +char *FoFiType1::getName() { + if (!parsed) { + parse(); + } + return name; +} + +char **FoFiType1::getEncoding() { + if (!parsed) { + parse(); + } + return encoding; +} + +void FoFiType1::writeEncoded(char **newEncoding, + FoFiOutputFunc outputFunc, void *outputStream) { + char buf[512]; + char *line; + int i; + + // copy everything up to the encoding + for (line = (char *)file; + line && strncmp(line, "/Encoding", 9); + line = getNextLine(line)) ; + if (!line) { + // no encoding - just copy the whole font file + (*outputFunc)(outputStream, (char *)file, len); + return; + } + (*outputFunc)(outputStream, (char *)file, line - (char *)file); + + // write the new encoding + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + (*outputFunc)(outputStream, + "0 1 255 {1 index exch /.notdef put} for\n", 40); + for (i = 0; i < 256; ++i) { + if (newEncoding[i]) { + sprintf(buf, "dup %d /%s put\n", i, newEncoding[i]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); + + // copy everything after the encoding + if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { + line = getNextLine(line); + } else { + for (line = getNextLine(line); + line && strncmp(line, "readonly def", 12); + line = getNextLine(line)) ; + if (line) { + line = getNextLine(line); + } + } + if (line) { + (*outputFunc)(outputStream, line, ((char *)file + len) - line); + } +} + +char *FoFiType1::getNextLine(char *line) { + while (line < (char *)file + len && *line != '\x0a' && *line != '\x0d') { + ++line; + } + if (line < (char *)file + len && *line == '\x0d') { + ++line; + } + if (line < (char *)file + len && *line == '\x0a') { + ++line; + } + if (line >= (char *)file + len) { + return NULL; + } + return line; +} + +void FoFiType1::parse() { + char *line, *line1, *p, *p2; + char buf[256]; + char c; + int n, code, i, j; + + for (i = 1, line = (char *)file; + i <= 100 && line && (!name || !encoding); + ++i) { + + // get font name + if (!name && !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 = getNextLine(line); + + // get encoding + } else if (!encoding && + !strncmp(line, "/Encoding StandardEncoding def", 30)) { + encoding = fofiType1StandardEncoding; + } else if (!encoding && + !strncmp(line, "/Encoding 256 array", 19)) { + encoding = (char **)gmallocn(256, sizeof(char *)); + for (j = 0; j < 256; ++j) { + encoding[j] = NULL; + } + for (j = 0, line = getNextLine(line); + j < 300 && line && (line1 = getNextLine(line)); + ++j, line = line1) { + 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[code] = copyString(p); + } + } + } + } else { + if (strtok(buf, " \t") && + (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { + break; + } + } + } + //~ check for getinterval/putinterval junk + + } else { + line = getNextLine(line); + } + } + + parsed = gTrue; +} diff --git a/pdftops/FoFiType1.h b/pdftops/FoFiType1.h new file mode 100644 index 000000000..6172c2d58 --- /dev/null +++ b/pdftops/FoFiType1.h @@ -0,0 +1,59 @@ +//======================================================================== +// +// FoFiType1.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITYPE1_H +#define FOFITYPE1_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +//------------------------------------------------------------------------ +// FoFiType1 +//------------------------------------------------------------------------ + +class FoFiType1: public FoFiBase { +public: + + // Create a FoFiType1 object from a memory buffer. + static FoFiType1 *make(char *fileA, int lenA); + + // Create a FoFiType1 object from a file on disk. + static FoFiType1 *load(char *fileName); + + virtual ~FoFiType1(); + + // Return the font name. + char *getName(); + + // Return the encoding, as an array of 256 names (any of which may + // be NULL). + char **getEncoding(); + + // Write a version of the Type 1 font file with a new encoding. + void writeEncoded(char **newEncoding, + FoFiOutputFunc outputFunc, void *outputStream); + +private: + + FoFiType1(char *fileA, int lenA, GBool freeFileDataA); + + char *getNextLine(char *line); + void parse(); + + char *name; + char **encoding; + GBool parsed; +}; + +#endif diff --git a/pdftops/FoFiType1C.cxx b/pdftops/FoFiType1C.cxx new file mode 100644 index 000000000..0cda63576 --- /dev/null +++ b/pdftops/FoFiType1C.cxx @@ -0,0 +1,2481 @@ +//======================================================================== +// +// FoFiType1C.cc +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include "gmem.h" +#include "GString.h" +#include "FoFiEncodings.h" +#include "FoFiType1C.h" + +//------------------------------------------------------------------------ + +static char hexChars[17] = "0123456789ABCDEF"; + +//------------------------------------------------------------------------ +// FoFiType1C +//------------------------------------------------------------------------ + +FoFiType1C *FoFiType1C::make(char *fileA, int lenA) { + FoFiType1C *ff; + + ff = new FoFiType1C(fileA, lenA, gFalse); + if (!ff->parse()) { + delete ff; + return NULL; + } + return ff; +} + +FoFiType1C *FoFiType1C::load(char *fileName) { + FoFiType1C *ff; + char *fileA; + int lenA; + + if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { + return NULL; + } + ff = new FoFiType1C(fileA, lenA, gTrue); + if (!ff->parse()) { + delete ff; + return NULL; + } + return ff; +} + +FoFiType1C::FoFiType1C(char *fileA, int lenA, GBool freeFileDataA): + FoFiBase(fileA, lenA, freeFileDataA) +{ + name = NULL; + encoding = NULL; + privateDicts = NULL; + fdSelect = NULL; + charset = NULL; +} + +FoFiType1C::~FoFiType1C() { + int i; + + if (name) { + delete name; + } + if (encoding && + encoding != fofiType1StandardEncoding && + encoding != fofiType1ExpertEncoding) { + for (i = 0; i < 256; ++i) { + gfree(encoding[i]); + } + gfree(encoding); + } + if (privateDicts) { + gfree(privateDicts); + } + if (fdSelect) { + gfree(fdSelect); + } + if (charset && + charset != fofiType1CISOAdobeCharset && + charset != fofiType1CExpertCharset && + charset != fofiType1CExpertSubsetCharset) { + gfree(charset); + } +} + +char *FoFiType1C::getName() { + return name ? name->getCString() : (char *)NULL; +} + +char **FoFiType1C::getEncoding() { + return encoding; +} + +Gushort *FoFiType1C::getCIDToGIDMap(int *nCIDs) { + Gushort *map; + int n, i; + + // a CID font's top dict has ROS as the first operator + if (topDict.firstOp != 0x0c1e) { + *nCIDs = 0; + return NULL; + } + + // in a CID font, the charset data is the GID-to-CID mapping, so all + // we have to do is reverse it + n = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] > n) { + n = charset[i]; + } + } + ++n; + map = (Gushort *)gmallocn(n, sizeof(Gushort)); + memset(map, 0, n * sizeof(Gushort)); + for (i = 0; i < nGlyphs; ++i) { + map[charset[i]] = i; + } + *nCIDs = n; + return map; +} + +void FoFiType1C::convertToType1(char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, + void *outputStream) { + Type1CEexecBuf eb; + Type1CIndex subrIdx; + Type1CIndexVal val; + char buf[512]; + char **enc; + GBool ok; + int i; + + // write header and font dictionary, up to encoding + ok = gTrue; + (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); + (*outputFunc)(outputStream, name->getCString(), name->getLength()); + if (topDict.versionSID != 0) { + getString(topDict.versionSID, buf, &ok); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "\n", 1); + // the dictionary needs room for 12 entries: the following 9, plus + // Private and CharStrings (in the eexec section) and FID (which is + // added by definefont) + (*outputFunc)(outputStream, "12 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); + if (topDict.versionSID != 0) { + (*outputFunc)(outputStream, "/version (", 10); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.noticeSID != 0) { + getString(topDict.noticeSID, buf, &ok); + (*outputFunc)(outputStream, "/Notice (", 9); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.copyrightSID != 0) { + getString(topDict.copyrightSID, buf, &ok); + (*outputFunc)(outputStream, "/Copyright (", 12); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.fullNameSID != 0) { + getString(topDict.fullNameSID, buf, &ok); + (*outputFunc)(outputStream, "/FullName (", 11); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.familyNameSID != 0) { + getString(topDict.familyNameSID, buf, &ok); + (*outputFunc)(outputStream, "/FamilyName (", 13); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.weightSID != 0) { + getString(topDict.weightSID, buf, &ok); + (*outputFunc)(outputStream, "/Weight (", 9); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") readonly def\n", 15); + } + if (topDict.isFixedPitch) { + (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); + } else { + (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); + } + sprintf(buf, "/ItalicAngle %g def\n", topDict.italicAngle); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/UnderlinePosition %g def\n", topDict.underlinePosition); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/UnderlineThickness %g def\n", topDict.underlineThickness); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "end readonly def\n", 17); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, name->getCString(), name->getLength()); + (*outputFunc)(outputStream, " def\n", 5); + sprintf(buf, "/PaintType %d def\n", topDict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], + topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/FontBBox [%g %g %g %g] readonly def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf, strlen(buf)); + if (topDict.uniqueID != 0) { + sprintf(buf, "/UniqueID %d def\n", topDict.uniqueID); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + + // write the encoding + (*outputFunc)(outputStream, "/Encoding ", 10); + if (!newEncoding && encoding == fofiType1StandardEncoding) { + (*outputFunc)(outputStream, "StandardEncoding def\n", 21); + } else { + (*outputFunc)(outputStream, "256 array\n", 10); + (*outputFunc)(outputStream, + "0 1 255 {1 index exch /.notdef put} for\n", 40); + enc = newEncoding ? newEncoding : encoding; + for (i = 0; i < 256; ++i) { + if (enc[i]) { + sprintf(buf, "dup %d /%s put\n", i, enc[i]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + } + (*outputFunc)(outputStream, "readonly def\n", 13); + } + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + eb.outputFunc = outputFunc; + eb.outputStream = outputStream; + eb.ascii = ascii; + eb.r1 = 55665; + eb.line = 0; + + // write the private dictionary + eexecWrite(&eb, "\x83\xca\x73\xd5"); + eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); + eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" + " executeonly def\n"); + eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); + eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); + eexecWrite(&eb, "/MinFeature {16 16} def\n"); + eexecWrite(&eb, "/password 5839 def\n"); + if (privateDicts[0].nBlueValues) { + eexecWrite(&eb, "/BlueValues ["); + for (i = 0; i < privateDicts[0].nBlueValues; ++i) { + sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].blueValues[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (i = 0; i < privateDicts[0].nOtherBlues; ++i) { + sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].otherBlues[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) { + sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].familyBlues[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) { + sprintf(buf, "%s%d", i > 0 ? " " : "", + privateDicts[0].familyOtherBlues[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].blueScale != 0.039625) { + sprintf(buf, "/BlueScale %g def\n", privateDicts[0].blueScale); + eexecWrite(&eb, buf); + } + if (privateDicts[0].blueShift != 7) { + sprintf(buf, "/BlueShift %d def\n", privateDicts[0].blueShift); + eexecWrite(&eb, buf); + } + if (privateDicts[0].blueFuzz != 1) { + sprintf(buf, "/BlueFuzz %d def\n", privateDicts[0].blueFuzz); + eexecWrite(&eb, buf); + } + if (privateDicts[0].hasStdHW) { + sprintf(buf, "/StdHW [%g] def\n", privateDicts[0].stdHW); + eexecWrite(&eb, buf); + } + if (privateDicts[0].hasStdVW) { + sprintf(buf, "/StdVW [%g] def\n", privateDicts[0].stdVW); + eexecWrite(&eb, buf); + } + if (privateDicts[0].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { + sprintf(buf, "%s%g", i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { + sprintf(buf, "%s%g", i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[0].hasForceBold) { + sprintf(buf, "/ForceBold %s def\n", + privateDicts[0].forceBold ? "true" : "false"); + eexecWrite(&eb, buf); + } + if (privateDicts[0].forceBoldThreshold != 0) { + sprintf(buf, "/ForceBoldThreshold %g def\n", + privateDicts[0].forceBoldThreshold); + eexecWrite(&eb, buf); + } + if (privateDicts[0].languageGroup != 0) { + sprintf(buf, "/LanguageGroup %d def\n", privateDicts[0].languageGroup); + eexecWrite(&eb, buf); + } + if (privateDicts[0].expansionFactor != 0.06) { + sprintf(buf, "/ExpansionFactor %g def\n", privateDicts[0].expansionFactor); + eexecWrite(&eb, buf); + } + + // set up subroutines + ok = gTrue; + getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // write the CharStrings + sprintf(buf, "2 index /CharStrings %d dict dup begin\n", nGlyphs); + eexecWrite(&eb, buf); + for (i = 0; i < nGlyphs; ++i) { + ok = gTrue; + getIndexVal(&charStringsIdx, i, &val, &ok); + if (ok) { + getString(charset[i], buf, &ok); + if (ok) { + eexecCvtGlyph(&eb, buf, val.pos, val.len, &subrIdx, &privateDicts[0]); + } + } + } + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "readonly put\n"); + eexecWrite(&eb, "noaccess put\n"); + eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); + eexecWrite(&eb, "mark currentfile closefile\n"); + + // trailer + if (ascii && eb.line > 0) { + (*outputFunc)(outputStream, "\n", 1); + } + for (i = 0; i < 8; ++i) { + (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); + } + (*outputFunc)(outputStream, "cleartomark\n", 12); +} + +void FoFiType1C::convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + int *cidMap; + GString *charStrings; + int *charStringOffsets; + Type1CIndex subrIdx; + Type1CIndexVal val; + int nCIDs, gdBytes; + char buf[512], buf2[512]; + GBool ok; + int gid, offset, n, i, j, k; + + // compute the CID count and build the CID-to-GID mapping + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + + // build the charstrings + charStrings = new GString(); + charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + charStringOffsets[i] = charStrings->getLength(); + if ((gid = cidMap[i]) >= 0) { + ok = gTrue; + getIndexVal(&charStringsIdx, gid, &val, &ok); + if (ok) { + getIndex(privateDicts[fdSelect[gid]].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + cvtGlyph(val.pos, val.len, charStrings, + &subrIdx, &privateDicts[fdSelect[gid]], gTrue); + } + } + } + charStringOffsets[nCIDs] = charStrings->getLength(); + + // compute gdBytes = number of bytes needed for charstring offsets + // (offset size needs to account for the charstring offset table, + // with a worst case of five bytes per entry, plus the charstrings + // themselves) + i = (nCIDs + 1) * 5 + charStrings->getLength(); + if (i < 0x100) { + gdBytes = 1; + } else if (i < 0x10000) { + gdBytes = 2; + } else if (i < 0x1000000) { + gdBytes = 3; + } else { + gdBytes = 4; + } + + // begin the font dictionary + (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); + (*outputFunc)(outputStream, "20 dict begin\n", 14); + (*outputFunc)(outputStream, "/CIDFontName /", 14); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); + (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); + if (topDict.registrySID > 0 && topDict.orderingSID > 0) { + ok = gTrue; + getString(topDict.registrySID, buf, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Registry (", 13); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") def\n", 6); + } + ok = gTrue; + getString(topDict.orderingSID, buf, &ok); + if (ok) { + (*outputFunc)(outputStream, " /Ordering (", 13); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, ") def\n", 6); + } + } else { + (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); + (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); + } + sprintf(buf, " /Supplement %d def\n", topDict.supplement); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "end def\n", 8); + if (topDict.hasFontMatrix) { + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } else if (privateDicts[0].hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } + sprintf(buf, "/FontBBox [%g %g %g %g] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); + (*outputFunc)(outputStream, " /FSType 8 def\n", 16); + (*outputFunc)(outputStream, "end def\n", 8); + + // CIDFont-specific entries + sprintf(buf, "/CIDCount %d def\n", nCIDs); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); + sprintf(buf, "/GDBytes %d def\n", gdBytes); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); + if (topDict.paintType != 0) { + sprintf(buf, "/PaintType %d def\n", topDict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + + // FDArray entry + sprintf(buf, "/FDArray %d array\n", nFDs); + (*outputFunc)(outputStream, buf, strlen(buf)); + for (i = 0; i < nFDs; ++i) { + sprintf(buf, "dup %d 10 dict begin\n", i); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[i].hasFontMatrix) { + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + privateDicts[i].fontMatrix[0], + privateDicts[i].fontMatrix[1], + privateDicts[i].fontMatrix[2], + privateDicts[i].fontMatrix[3], + privateDicts[i].fontMatrix[4], + privateDicts[i].fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } else { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } + sprintf(buf, "/PaintType %d def\n", topDict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); + if (privateDicts[i].nBlueValues) { + (*outputFunc)(outputStream, "/BlueValues [", 13); + for (j = 0; j < privateDicts[i].nBlueValues; ++j) { + sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].blueValues[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nOtherBlues) { + (*outputFunc)(outputStream, "/OtherBlues [", 13); + for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { + sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].otherBlues[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyBlues) { + (*outputFunc)(outputStream, "/FamilyBlues [", 14); + for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { + sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].familyBlues[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nFamilyOtherBlues) { + (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19); + for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { + sprintf(buf, "%s%d", j > 0 ? " " : "", + privateDicts[i].familyOtherBlues[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].blueScale != 0.039625) { + sprintf(buf, "/BlueScale %g def\n", privateDicts[i].blueScale); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].blueShift != 7) { + sprintf(buf, "/BlueShift %d def\n", privateDicts[i].blueShift); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].blueFuzz != 1) { + sprintf(buf, "/BlueFuzz %d def\n", privateDicts[i].blueFuzz); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].hasStdHW) { + sprintf(buf, "/StdHW [%g] def\n", privateDicts[i].stdHW); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].hasStdVW) { + sprintf(buf, "/StdVW [%g] def\n", privateDicts[i].stdVW); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].nStemSnapH) { + (*outputFunc)(outputStream, "/StemSnapH [", 12); + for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { + sprintf(buf, "%s%g", j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].nStemSnapV) { + (*outputFunc)(outputStream, "/StemSnapV [", 12); + for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { + sprintf(buf, "%s%g", j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + } + if (privateDicts[i].hasForceBold) { + sprintf(buf, "/ForceBold %s def\n", + privateDicts[i].forceBold ? "true" : "false"); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].forceBoldThreshold != 0) { + sprintf(buf, "/ForceBoldThreshold %g def\n", + privateDicts[i].forceBoldThreshold); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].languageGroup != 0) { + sprintf(buf, "/LanguageGroup %d def\n", privateDicts[i].languageGroup); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (privateDicts[i].expansionFactor != 0.06) { + sprintf(buf, "/ExpansionFactor %g def\n", + privateDicts[i].expansionFactor); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "currentdict end def\n", 20); + (*outputFunc)(outputStream, "currentdict end put\n", 20); + } + (*outputFunc)(outputStream, "def\n", 4); + + // start the binary section + offset = (nCIDs + 1) * (1 + gdBytes); + sprintf(buf, "(Hex) %d StartData\n", + offset + charStrings->getLength()); + (*outputFunc)(outputStream, buf, strlen(buf)); + + // write the charstring offset (CIDMap) table + for (i = 0; i <= nCIDs; i += 6) { + for (j = 0; j < 6 && i+j <= nCIDs; ++j) { + if (i+j < nCIDs && cidMap[i+j] >= 0) { + buf[0] = (char)fdSelect[cidMap[i+j]]; + } else { + buf[0] = (char)0; + } + n = offset + charStringOffsets[i+j]; + for (k = gdBytes; k >= 1; --k) { + buf[k] = (char)(n & 0xff); + n >>= 8; + } + for (k = 0; k <= gdBytes; ++k) { + sprintf(buf2, "%02x", buf[k] & 0xff); + (*outputFunc)(outputStream, buf2, 2); + } + } + (*outputFunc)(outputStream, "\n", 1); + } + + // write the charstring data + n = charStrings->getLength(); + for (i = 0; i < n; i += 32) { + for (j = 0; j < 32 && i+j < n; ++j) { + sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (i + 32 >= n) { + (*outputFunc)(outputStream, ">", 1); + } + (*outputFunc)(outputStream, "\n", 1); + } + + gfree(charStringOffsets); + delete charStrings; + gfree(cidMap); +} + +void FoFiType1C::convertToType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + int *cidMap; + Type1CIndex subrIdx; + Type1CIndexVal val; + int nCIDs; + char buf[512]; + Type1CEexecBuf eb; + GBool ok; + int fd, i, j, k; + + // compute the CID count and build the CID-to-GID mapping + nCIDs = 0; + for (i = 0; i < nGlyphs; ++i) { + if (charset[i] >= nCIDs) { + nCIDs = charset[i] + 1; + } + } + cidMap = (int *)gmallocn(nCIDs, sizeof(int)); + for (i = 0; i < nCIDs; ++i) { + cidMap[i] = -1; + } + for (i = 0; i < nGlyphs; ++i) { + cidMap[charset[i]] = i; + } + + // write the descendant Type 1 fonts + for (i = 0; i < nCIDs; i += 256) { + + //~ this assumes that all CIDs in this block have the same FD -- + //~ to handle multiple FDs correctly, need to somehow divide the + //~ font up by FD + fd = 0; + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + fd = fdSelect[cidMap[i+j]]; + break; + } + } + + // font dictionary (unencrypted section) + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + sprintf(buf, "_%02x def\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, "/FontType 1 def\n", 16); + if (privateDicts[fd].hasFontMatrix) { + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + privateDicts[fd].fontMatrix[0], + privateDicts[fd].fontMatrix[1], + privateDicts[fd].fontMatrix[2], + privateDicts[fd].fontMatrix[3], + privateDicts[fd].fontMatrix[4], + privateDicts[fd].fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } else if (topDict.hasFontMatrix) { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } else { + (*outputFunc)(outputStream, + "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); + } + sprintf(buf, "/FontBBox [%g %g %g %g] def\n", + topDict.fontBBox[0], topDict.fontBBox[1], + topDict.fontBBox[2], topDict.fontBBox[3]); + (*outputFunc)(outputStream, buf, strlen(buf)); + sprintf(buf, "/PaintType %d def\n", topDict.paintType); + (*outputFunc)(outputStream, buf, strlen(buf)); + if (topDict.paintType != 0) { + sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + sprintf(buf, "dup %d /c%02x put\n", j, j); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + if (j < 256) { + sprintf(buf, "%d 1 255 { 1 index exch /.notdef put } for\n", j); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "readonly def\n", 13); + (*outputFunc)(outputStream, "currentdict end\n", 16); + + // start the binary section + (*outputFunc)(outputStream, "currentfile eexec\n", 18); + eb.outputFunc = outputFunc; + eb.outputStream = outputStream; + eb.ascii = gTrue; + eb.r1 = 55665; + eb.line = 0; + + // start the private dictionary + eexecWrite(&eb, "\x83\xca\x73\xd5"); + eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); + eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" + " executeonly def\n"); + eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); + eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); + eexecWrite(&eb, "/MinFeature {16 16} def\n"); + eexecWrite(&eb, "/password 5839 def\n"); + if (privateDicts[fd].nBlueValues) { + eexecWrite(&eb, "/BlueValues ["); + for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { + sprintf(buf, "%s%d", k > 0 ? " " : "", privateDicts[fd].blueValues[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nOtherBlues) { + eexecWrite(&eb, "/OtherBlues ["); + for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { + sprintf(buf, "%s%d", k > 0 ? " " : "", privateDicts[fd].otherBlues[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyBlues) { + eexecWrite(&eb, "/FamilyBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { + sprintf(buf, "%s%d", k > 0 ? " " : "", + privateDicts[fd].familyBlues[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nFamilyOtherBlues) { + eexecWrite(&eb, "/FamilyOtherBlues ["); + for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { + sprintf(buf, "%s%d", k > 0 ? " " : "", + privateDicts[fd].familyOtherBlues[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].blueScale != 0.039625) { + sprintf(buf, "/BlueScale %g def\n", privateDicts[fd].blueScale); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].blueShift != 7) { + sprintf(buf, "/BlueShift %d def\n", privateDicts[fd].blueShift); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].blueFuzz != 1) { + sprintf(buf, "/BlueFuzz %d def\n", privateDicts[fd].blueFuzz); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].hasStdHW) { + sprintf(buf, "/StdHW [%g] def\n", privateDicts[fd].stdHW); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].hasStdVW) { + sprintf(buf, "/StdVW [%g] def\n", privateDicts[fd].stdVW); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].nStemSnapH) { + eexecWrite(&eb, "/StemSnapH ["); + for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { + sprintf(buf, "%s%g", k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].nStemSnapV) { + eexecWrite(&eb, "/StemSnapV ["); + for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { + sprintf(buf, "%s%g", k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]); + eexecWrite(&eb, buf); + } + eexecWrite(&eb, "] def\n"); + } + if (privateDicts[fd].hasForceBold) { + sprintf(buf, "/ForceBold %s def\n", + privateDicts[fd].forceBold ? "true" : "false"); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].forceBoldThreshold != 0) { + sprintf(buf, "/ForceBoldThreshold %g def\n", + privateDicts[fd].forceBoldThreshold); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].languageGroup != 0) { + sprintf(buf, "/LanguageGroup %d def\n", privateDicts[fd].languageGroup); + eexecWrite(&eb, buf); + } + if (privateDicts[fd].expansionFactor != 0.06) { + sprintf(buf, "/ExpansionFactor %g def\n", + privateDicts[fd].expansionFactor); + eexecWrite(&eb, buf); + } + + // set up the subroutines + ok = gTrue; + getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok); + if (!ok) { + subrIdx.pos = -1; + } + + // start the CharStrings + sprintf(buf, "2 index /CharStrings 256 dict dup begin\n"); + eexecWrite(&eb, buf); + + // write the .notdef CharString + ok = gTrue; + getIndexVal(&charStringsIdx, 0, &val, &ok); + if (ok) { + eexecCvtGlyph(&eb, ".notdef", val.pos, val.len, + &subrIdx, &privateDicts[fd]); + } + + // write the CharStrings + for (j = 0; j < 256 && i+j < nCIDs; ++j) { + if (cidMap[i+j] >= 0) { + ok = gTrue; + getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok); + if (ok) { + sprintf(buf, "c%02x", j); + eexecCvtGlyph(&eb, buf, val.pos, val.len, + &subrIdx, &privateDicts[fd]); + } + } + } + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "end\n"); + eexecWrite(&eb, "readonly put\n"); + eexecWrite(&eb, "noaccess put\n"); + eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); + eexecWrite(&eb, "mark currentfile closefile\n"); + + // trailer + if (eb.line > 0) { + (*outputFunc)(outputStream, "\n", 1); + } + for (j = 0; j < 8; ++j) { + (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); + } + (*outputFunc)(outputStream, "cleartomark\n", 12); + } + + // write the Type 0 parent font + (*outputFunc)(outputStream, "16 dict begin\n", 14); + (*outputFunc)(outputStream, "/FontName /", 11); + (*outputFunc)(outputStream, psName, strlen(psName)); + (*outputFunc)(outputStream, " def\n", 5); + (*outputFunc)(outputStream, "/FontType 0 def\n", 16); + if (topDict.hasFontMatrix) { + sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", + topDict.fontMatrix[0], topDict.fontMatrix[1], + topDict.fontMatrix[2], topDict.fontMatrix[3], + topDict.fontMatrix[4], topDict.fontMatrix[5]); + (*outputFunc)(outputStream, buf, strlen(buf)); + } else { + (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); + } + (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); + (*outputFunc)(outputStream, "/Encoding [\n", 12); + for (i = 0; i < nCIDs; i += 256) { + sprintf(buf, "%d\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "/FDepVector [\n", 14); + for (i = 0; i < nCIDs; i += 256) { + (*outputFunc)(outputStream, "/", 1); + (*outputFunc)(outputStream, psName, strlen(psName)); + sprintf(buf, "_%02x findfont\n", i >> 8); + (*outputFunc)(outputStream, buf, strlen(buf)); + } + (*outputFunc)(outputStream, "] def\n", 6); + (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); + + gfree(cidMap); +} + +void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName, + int offset, int nBytes, + Type1CIndex *subrIdx, + Type1CPrivateDict *pDict) { + char buf[512]; + GString *charBuf; + + // generate the charstring + charBuf = new GString(); + cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue); + + sprintf(buf, "/%s %d RD ", glyphName, charBuf->getLength()); + eexecWrite(eb, buf); + eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(), + charBuf->getLength()); + eexecWrite(eb, " ND\n"); + + delete charBuf; +} + +void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, + Type1CIndex *subrIdx, Type1CPrivateDict *pDict, + GBool top) { + Type1CIndexVal val; + GBool ok, dFP; + double d, dx, dy; + Gushort r2; + Guchar byte; + int pos, subrBias, start, i, k; + + start = charBuf->getLength(); + if (top) { + charBuf->append((char)73); + charBuf->append((char)58); + charBuf->append((char)147); + charBuf->append((char)134); + nOps = 0; + nHints = 0; + firstOp = gTrue; + openPath = gFalse; + } + + pos = offset; + while (pos < offset + nBytes) { + ok = gTrue; + pos = getOp(pos, gTrue, &ok); + if (!ok) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + switch (ops[nOps].op) { + case 0x0001: // hstem + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = 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) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints + if (ops[k+1].num < 0) { + d += ops[k].num + ops[k+1].num; + dFP |= ops[k].isFP | ops[k+1].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); + } else { + d += ops[k].num; + dFP |= ops[k].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + d += ops[k+1].num; + dFP |= ops[k+1].isFP; + } + charBuf->append((char)1); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0003: // vstem + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = 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) { + // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints + if (ops[k+1].num < 0) { + d += ops[k].num + ops[k+1].num; + dFP |= ops[k].isFP | ops[k+1].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); + } else { + d += ops[k].num; + dFP |= ops[k].isFP; + cvtNum(d, dFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + d += ops[k+1].num; + dFP |= ops[k+1].isFP; + } + charBuf->append((char)3); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0004: // vmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 2, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + charBuf->append((char)4); + nOps = 0; + break; + case 0x0005: // 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) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + charBuf->append((char)5); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0006: // hlineto + if (nOps < 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + charBuf->append((char)((k & 1) ? 7 : 6)); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0007: // vlineto + if (nOps < 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); + } + for (k = 0; k < nOps; ++k) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + charBuf->append((char)((k & 1) ? 6 : 7)); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0008: // 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) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x000a: // callsubr + if (nOps >= 1) { + subrBias = (subrIdx->len < 1240) + ? 107 : (subrIdx->len < 33900) ? 1131 : 32768; + k = subrBias + (int)ops[nOps - 1].num; + --nOps; + ok = gTrue; + getIndexVal(subrIdx, k, &val, &ok); + if (ok) { + cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); + } + } else { + //~ error(-1, "Too few args to Type 2 callsubr"); + } + // don't clear the stack + break; + case 0x000b: // return + // don't clear the stack + break; + case 0x000e: // endchar / seac + if (firstOp) { + cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps == 4) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + charBuf->append((char)12)->append((char)6); + } else if (nOps == 0) { + charBuf->append((char)14); + } else { + //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); + } + nOps = 0; + break; + case 0x000f: // (obsolete) + // this op is ignored, but we need the glyph width + if (firstOp) { + cvtGlyphWidth(nOps > 0, charBuf, pDict); + firstOp = gFalse; + } + nOps = 0; + break; + case 0x0010: // blend + //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); + nOps = 0; + break; + case 0x0012: // hstemhm + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0013: // hintmask + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps > 0) { + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", + //~ nOps); + } + nHints += nOps / 2; + } + pos += (nHints + 7) >> 3; + nOps = 0; + break; + case 0x0014: // cntrmask + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps > 0) { + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", + //~ nOps); + } + nHints += nOps / 2; + } + pos += (nHints + 7) >> 3; + nOps = 0; + break; + case 0x0015: // rmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 3, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 2) { + //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + charBuf->append((char)21); + nOps = 0; + break; + case 0x0016: // hmoveto + if (firstOp) { + cvtGlyphWidth(nOps == 2, charBuf, pDict); + firstOp = gFalse; + } + if (openPath) { + charBuf->append((char)9); + openPath = gFalse; + } + if (nOps != 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + charBuf->append((char)22); + nOps = 0; + break; + case 0x0017: // vstemhm + // ignored + if (firstOp) { + cvtGlyphWidth(nOps & 1, charBuf, pDict); + firstOp = gFalse; + } + if (nOps & 1) { + //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); + } + nHints += nOps / 2; + nOps = 0; + break; + case 0x0018: // 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) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + } + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k].isFP, charBuf); + charBuf->append((char)5); + nOps = 0; + openPath = gTrue; + break; + case 0x0019: // 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) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k].isFP, charBuf); + charBuf->append((char)5); + } + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x001a: // 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) { + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + charBuf->append((char)8); + k = 5; + } else { + k = 0; + } + for (; k < nOps; k += 4) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001b: // 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) { + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + k = 5; + } else { + k = 0; + } + for (; k < nOps; k += 4) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001d: // callgsubr + if (nOps >= 1) { + k = gsubrBias + (int)ops[nOps - 1].num; + --nOps; + ok = gTrue; + getIndexVal(&gsubrIdx, k, &val, &ok); + if (ok) { + cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); + } + } else { + //~ error(-1, "Too few args to Type 2 callgsubr"); + } + // don't clear the stack + break; + case 0x001e: // 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) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)30); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)31); + } + } + if (k == nOps-5) { + if (k % 8 == 0) { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + } + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x001f: // 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) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)31); + } else { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + charBuf->append((char)30); + } + } + if (k == nOps-5) { + if (k % 8 == 0) { + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + } else { + cvtNum(0, gFalse, charBuf); + cvtNum(ops[k].num, ops[k].isFP, charBuf); + cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); + cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); + cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); + cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); + } + charBuf->append((char)8); + } + nOps = 0; + openPath = gTrue; + break; + case 0x0c00: // dotsection (should be Type 1 only?) + // ignored + nOps = 0; + break; + case 0x0c03: // and + case 0x0c04: // or + case 0x0c05: // not + case 0x0c08: // store + case 0x0c09: // abs + case 0x0c0a: // add + case 0x0c0b: // sub + case 0x0c0c: // div + case 0x0c0d: // load + case 0x0c0e: // neg + case 0x0c0f: // eq + case 0x0c12: // drop + case 0x0c14: // put + case 0x0c15: // get + case 0x0c16: // ifelse + case 0x0c17: // random + case 0x0c18: // mul + case 0x0c1a: // sqrt + case 0x0c1b: // dup + case 0x0c1c: // exch + case 0x0c1d: // index + case 0x0c1e: // roll + //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); + nOps = 0; + break; + case 0x0c22: // hflex + if (nOps != 7) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + cvtNum(-ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c23: // flex + if (nOps != 13) { + //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + charBuf->append((char)8); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(ops[9].num, ops[9].isFP, charBuf); + cvtNum(ops[10].num, ops[10].isFP, charBuf); + cvtNum(ops[11].num, ops[11].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c24: // hflex1 + if (nOps != 9) { + //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + charBuf->append((char)8); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + cvtNum(0, gFalse, charBuf); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(-(ops[1].num + ops[3].num + ops[7].num), + ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf); + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + case 0x0c25: // flex1 + if (nOps != 11) { + //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); + } + cvtNum(ops[0].num, ops[0].isFP, charBuf); + cvtNum(ops[1].num, ops[1].isFP, charBuf); + cvtNum(ops[2].num, ops[2].isFP, charBuf); + cvtNum(ops[3].num, ops[3].isFP, charBuf); + cvtNum(ops[4].num, ops[4].isFP, charBuf); + cvtNum(ops[5].num, ops[5].isFP, charBuf); + charBuf->append((char)8); + cvtNum(ops[6].num, ops[6].isFP, charBuf); + cvtNum(ops[7].num, ops[7].isFP, charBuf); + cvtNum(ops[8].num, ops[8].isFP, charBuf); + cvtNum(ops[9].num, ops[9].isFP, charBuf); + dx = ops[0].num + ops[2].num + ops[4].num + ops[6].num + ops[8].num; + dy = ops[1].num + ops[3].num + ops[5].num + ops[7].num + ops[9].num; + if (fabs(dx) > fabs(dy)) { + cvtNum(ops[10].num, ops[10].isFP, charBuf); + cvtNum(-dy, ops[1].isFP | ops[3].isFP | ops[5].isFP | + ops[7].isFP | ops[9].isFP, charBuf); + } else { + cvtNum(-dx, ops[0].isFP | ops[2].isFP | ops[4].isFP | + ops[6].isFP | ops[8].isFP, charBuf); + cvtNum(ops[10].num, ops[10].isFP, charBuf); + } + charBuf->append((char)8); + nOps = 0; + openPath = gTrue; + break; + default: + //~ error(-1, "Illegal Type 2 charstring op: %04x", + //~ ops[nOps].op); + nOps = 0; + break; + } + } + } + + // charstring encryption + if (top) { + r2 = 4330; + for (i = start; i < charBuf->getLength(); ++i) { + byte = charBuf->getChar(i) ^ (r2 >> 8); + charBuf->setChar(i, byte); + r2 = (byte + r2) * 52845 + 22719; + } + } +} + +void FoFiType1C::cvtGlyphWidth(GBool useOp, GString *charBuf, + Type1CPrivateDict *pDict) { + double w; + GBool wFP; + int i; + + if (useOp) { + w = pDict->nominalWidthX + ops[0].num; + wFP = pDict->nominalWidthXFP | ops[0].isFP; + for (i = 1; i < nOps; ++i) { + ops[i-1] = ops[i]; + } + --nOps; + } else { + w = pDict->defaultWidthX; + wFP = pDict->defaultWidthXFP; + } + cvtNum(0, gFalse, charBuf); + cvtNum(w, wFP, charBuf); + charBuf->append((char)13); +} + +void FoFiType1C::cvtNum(double x, GBool isFP, GString *charBuf) { + Guchar buf[12]; + int y, n; + + n = 0; + if (isFP) { + 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 FoFiType1C::eexecWrite(Type1CEexecBuf *eb, char *s) { + Guchar *p; + Guchar x; + + for (p = (Guchar *)s; *p; ++p) { + x = *p ^ (eb->r1 >> 8); + eb->r1 = (x + eb->r1) * 52845 + 22719; + if (eb->ascii) { + (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); + (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); + eb->line += 2; + if (eb->line == 64) { + (*eb->outputFunc)(eb->outputStream, "\n", 1); + eb->line = 0; + } + } else { + (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); + } + } +} + +void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb, + Guchar *s, int n) { + Guchar x; + int i; + + // eexec encryption + for (i = 0; i < n; ++i) { + x = s[i] ^ (eb->r1 >> 8); + eb->r1 = (x + eb->r1) * 52845 + 22719; + if (eb->ascii) { + (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); + (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); + eb->line += 2; + if (eb->line == 64) { + (*eb->outputFunc)(eb->outputStream, "\n", 1); + eb->line = 0; + } + } else { + (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); + } + } +} + +GBool FoFiType1C::parse() { + Type1CIndex fdIdx; + Type1CIndexVal val; + int i; + + parsedOk = gTrue; + + // some tools embed Type 1C fonts with an extra whitespace char at + // the beginning + if (len > 0 && file[0] != '\x01') { + ++file; + --len; + } + + // find the indexes + getIndex(getU8(2, &parsedOk), &nameIdx, &parsedOk); + getIndex(nameIdx.endPos, &topDictIdx, &parsedOk); + getIndex(topDictIdx.endPos, &stringIdx, &parsedOk); + getIndex(stringIdx.endPos, &gsubrIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + gsubrBias = (gsubrIdx.len < 1240) ? 107 + : (gsubrIdx.len < 33900) ? 1131 : 32768; + + // read the first font name + getIndexVal(&nameIdx, 0, &val, &parsedOk); + if (!parsedOk) { + return gFalse; + } + name = new GString((char *)&file[val.pos], val.len); + + // read the top dict for the first font + readTopDict(); + + // for CID fonts: read the FDArray dicts and private dicts + if (topDict.firstOp == 0x0c1e) { + if (topDict.fdArrayOffset == 0) { + nFDs = 1; + privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); + readPrivateDict(0, 0, &privateDicts[0]); + } else { + getIndex(topDict.fdArrayOffset, &fdIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + nFDs = fdIdx.len; + privateDicts = (Type1CPrivateDict *) + gmallocn(nFDs, sizeof(Type1CPrivateDict)); + for (i = 0; i < nFDs; ++i) { + getIndexVal(&fdIdx, i, &val, &parsedOk); + if (!parsedOk) { + return gFalse; + } + readFD(val.pos, val.len, &privateDicts[i]); + } + } + + // for 8-bit fonts: read the private dict + } else { + privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); + readPrivateDict(topDict.privateOffset, topDict.privateSize, + &privateDicts[0]); + } + + // check for parse errors in the private dict(s) + if (!parsedOk) { + return gFalse; + } + + // get the charstrings index + if (topDict.charStringsOffset <= 0) { + parsedOk = gFalse; + return gFalse; + } + getIndex(topDict.charStringsOffset, &charStringsIdx, &parsedOk); + if (!parsedOk) { + return gFalse; + } + nGlyphs = charStringsIdx.len; + + // for CID fonts: read the FDSelect table + if (topDict.firstOp == 0x0c1e) { + readFDSelect(); + if (!parsedOk) { + return gFalse; + } + } + + // read the charset + if (!readCharset()) { + parsedOk = gFalse; + return gFalse; + } + + // for 8-bit fonts: build the encoding + if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) { + buildEncoding(); + if (!parsedOk) { + return gFalse; + } + } + + return parsedOk; +} + +void FoFiType1C::readTopDict() { + Type1CIndexVal topDictPtr; + int pos; + + topDict.firstOp = -1; + topDict.versionSID = 0; + topDict.noticeSID = 0; + topDict.copyrightSID = 0; + topDict.fullNameSID = 0; + topDict.familyNameSID = 0; + topDict.weightSID = 0; + topDict.isFixedPitch = 0; + topDict.italicAngle = 0; + topDict.underlinePosition = -100; + topDict.underlineThickness = 50; + topDict.paintType = 0; + topDict.charstringType = 2; + topDict.fontMatrix[0] = 0.001; + topDict.fontMatrix[1] = 0; + topDict.fontMatrix[2] = 0; + topDict.fontMatrix[3] = 0.001; + topDict.fontMatrix[4] = 0; + topDict.fontMatrix[5] = 0; + topDict.hasFontMatrix = gFalse; + topDict.uniqueID = 0; + topDict.fontBBox[0] = 0; + topDict.fontBBox[1] = 0; + topDict.fontBBox[2] = 0; + topDict.fontBBox[3] = 0; + topDict.strokeWidth = 0; + topDict.charsetOffset = 0; + topDict.encodingOffset = 0; + topDict.charStringsOffset = 0; + topDict.privateSize = 0; + topDict.privateOffset = 0; + topDict.registrySID = 0; + topDict.orderingSID = 0; + topDict.supplement = 0; + topDict.fdArrayOffset = 0; + topDict.fdSelectOffset = 0; + + getIndexVal(&topDictIdx, 0, &topDictPtr, &parsedOk); + pos = topDictPtr.pos; + nOps = 0; + while (pos < topDictPtr.pos + topDictPtr.len) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + if (topDict.firstOp < 0) { + topDict.firstOp = ops[nOps].op; + } + switch (ops[nOps].op) { + case 0x0000: topDict.versionSID = (int)ops[0].num; break; + case 0x0001: topDict.noticeSID = (int)ops[0].num; break; + case 0x0c00: topDict.copyrightSID = (int)ops[0].num; break; + case 0x0002: topDict.fullNameSID = (int)ops[0].num; break; + case 0x0003: topDict.familyNameSID = (int)ops[0].num; break; + case 0x0004: topDict.weightSID = (int)ops[0].num; break; + case 0x0c01: topDict.isFixedPitch = (int)ops[0].num; break; + case 0x0c02: topDict.italicAngle = ops[0].num; break; + case 0x0c03: topDict.underlinePosition = ops[0].num; break; + case 0x0c04: topDict.underlineThickness = ops[0].num; break; + case 0x0c05: topDict.paintType = (int)ops[0].num; break; + case 0x0c06: topDict.charstringType = (int)ops[0].num; break; + case 0x0c07: topDict.fontMatrix[0] = ops[0].num; + topDict.fontMatrix[1] = ops[1].num; + topDict.fontMatrix[2] = ops[2].num; + topDict.fontMatrix[3] = ops[3].num; + topDict.fontMatrix[4] = ops[4].num; + topDict.fontMatrix[5] = ops[5].num; + topDict.hasFontMatrix = gTrue; break; + case 0x000d: topDict.uniqueID = (int)ops[0].num; break; + case 0x0005: topDict.fontBBox[0] = ops[0].num; + topDict.fontBBox[1] = ops[1].num; + topDict.fontBBox[2] = ops[2].num; + topDict.fontBBox[3] = ops[3].num; break; + case 0x0c08: topDict.strokeWidth = ops[0].num; break; + case 0x000f: topDict.charsetOffset = (int)ops[0].num; break; + case 0x0010: topDict.encodingOffset = (int)ops[0].num; break; + case 0x0011: topDict.charStringsOffset = (int)ops[0].num; break; + case 0x0012: topDict.privateSize = (int)ops[0].num; + topDict.privateOffset = (int)ops[1].num; break; + case 0x0c1e: topDict.registrySID = (int)ops[0].num; + topDict.orderingSID = (int)ops[1].num; + topDict.supplement = (int)ops[2].num; break; + case 0x0c24: topDict.fdArrayOffset = (int)ops[0].num; break; + case 0x0c25: topDict.fdSelectOffset = (int)ops[0].num; break; + } + nOps = 0; + } + } +} + +// Read a CID font dict (FD) - this pulls out the private dict +// pointer, and reads the private dict. It also pulls the FontMatrix +// (if any) out of the FD. +void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { + int pos, pSize, pOffset; + double fontMatrix[6]; + GBool hasFontMatrix; + + hasFontMatrix = gFalse; + pSize = pOffset = 0; + pos = offset; + nOps = 0; + while (pos < offset + length) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + return; + } + if (!ops[nOps - 1].isNum) { + if (ops[nOps - 1].op == 0x0012) { + if (nOps < 3) { + parsedOk = gFalse; + return; + } + pSize = (int)ops[0].num; + pOffset = (int)ops[1].num; + break; + } else if (ops[nOps - 1].op == 0x0c07) { + fontMatrix[0] = ops[0].num; + fontMatrix[1] = ops[1].num; + fontMatrix[2] = ops[2].num; + fontMatrix[3] = ops[3].num; + fontMatrix[4] = ops[4].num; + fontMatrix[5] = ops[5].num; + hasFontMatrix = gTrue; + } + nOps = 0; + } + } + readPrivateDict(pOffset, pSize, pDict); + if (hasFontMatrix) { + pDict->fontMatrix[0] = fontMatrix[0]; + pDict->fontMatrix[1] = fontMatrix[1]; + pDict->fontMatrix[2] = fontMatrix[2]; + pDict->fontMatrix[3] = fontMatrix[3]; + pDict->fontMatrix[4] = fontMatrix[4]; + pDict->fontMatrix[5] = fontMatrix[5]; + pDict->hasFontMatrix = gTrue; + } +} + +void FoFiType1C::readPrivateDict(int offset, int length, + Type1CPrivateDict *pDict) { + int pos; + + pDict->hasFontMatrix = gFalse; + pDict->nBlueValues = 0; + pDict->nOtherBlues = 0; + pDict->nFamilyBlues = 0; + pDict->nFamilyOtherBlues = 0; + pDict->blueScale = 0.039625; + pDict->blueShift = 7; + pDict->blueFuzz = 1; + pDict->hasStdHW = gFalse; + pDict->hasStdVW = gFalse; + pDict->nStemSnapH = 0; + pDict->nStemSnapV = 0; + pDict->hasForceBold = gFalse; + pDict->forceBoldThreshold = 0; + pDict->languageGroup = 0; + pDict->expansionFactor = 0.06; + pDict->initialRandomSeed = 0; + pDict->subrsOffset = 0; + pDict->defaultWidthX = 0; + pDict->defaultWidthXFP = gFalse; + pDict->nominalWidthX = 0; + pDict->nominalWidthXFP = gFalse; + + // no dictionary + if (offset == 0 || length == 0) { + return; + } + + pos = offset; + nOps = 0; + while (pos < offset + length) { + pos = getOp(pos, gFalse, &parsedOk); + if (!parsedOk) { + break; + } + if (!ops[nOps - 1].isNum) { + --nOps; // drop the operator + switch (ops[nOps].op) { + case 0x0006: + pDict->nBlueValues = getDeltaIntArray(pDict->blueValues, + type1CMaxBlueValues); + break; + case 0x0007: + pDict->nOtherBlues = getDeltaIntArray(pDict->otherBlues, + type1CMaxOtherBlues); + break; + case 0x0008: + pDict->nFamilyBlues = getDeltaIntArray(pDict->familyBlues, + type1CMaxBlueValues); + break; + case 0x0009: + pDict->nFamilyOtherBlues = getDeltaIntArray(pDict->familyOtherBlues, + type1CMaxOtherBlues); + break; + case 0x0c09: + pDict->blueScale = ops[0].num; + break; + case 0x0c0a: + pDict->blueShift = (int)ops[0].num; + break; + case 0x0c0b: + pDict->blueFuzz = (int)ops[0].num; + break; + case 0x000a: + pDict->stdHW = ops[0].num; + pDict->hasStdHW = gTrue; + break; + case 0x000b: + pDict->stdVW = ops[0].num; + pDict->hasStdVW = gTrue; + break; + case 0x0c0c: + pDict->nStemSnapH = getDeltaFPArray(pDict->stemSnapH, + type1CMaxStemSnap); + break; + case 0x0c0d: + pDict->nStemSnapV = getDeltaFPArray(pDict->stemSnapV, + type1CMaxStemSnap); + break; + case 0x0c0e: + pDict->forceBold = ops[0].num != 0; + pDict->hasForceBold = gTrue; + break; + case 0x0c0f: + pDict->forceBoldThreshold = ops[0].num; + break; + case 0x0c11: + pDict->languageGroup = (int)ops[0].num; + break; + case 0x0c12: + pDict->expansionFactor = ops[0].num; + break; + case 0x0c13: + pDict->initialRandomSeed = (int)ops[0].num; + break; + case 0x0013: + pDict->subrsOffset = offset + (int)ops[0].num; + break; + case 0x0014: + pDict->defaultWidthX = ops[0].num; + pDict->defaultWidthXFP = ops[0].isFP; + break; + case 0x0015: + pDict->nominalWidthX = ops[0].num; + pDict->nominalWidthXFP = ops[0].isFP; + break; + } + nOps = 0; + } + } +} + +void FoFiType1C::readFDSelect() { + int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j; + + fdSelect = (Guchar *)gmalloc(nGlyphs); + if (topDict.fdSelectOffset == 0) { + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } else { + pos = topDict.fdSelectOffset; + fdSelectFmt = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (fdSelectFmt == 0) { + if (!checkRegion(pos, nGlyphs)) { + parsedOk = gFalse; + return; + } + memcpy(fdSelect, file + pos, nGlyphs); + } else if (fdSelectFmt == 3) { + nRanges = getU16BE(pos, &parsedOk); + pos += 2; + gid0 = getU16BE(pos, &parsedOk); + pos += 2; + for (i = 1; i <= nRanges; ++i) { + fd = getU8(pos++, &parsedOk); + gid1 = getU16BE(pos, &parsedOk); + if (!parsedOk) { + return; + } + pos += 2; + if (gid0 > gid1 || gid1 > nGlyphs) { + //~ error(-1, "Bad FDSelect table in CID font"); + parsedOk = gFalse; + return; + } + for (j = gid0; j < gid1; ++j) { + fdSelect[j] = fd; + } + gid0 = gid1; + } + } else { + //~ error(-1, "Unknown FDSelect table format in CID font"); + for (i = 0; i < nGlyphs; ++i) { + fdSelect[i] = 0; + } + } + } +} + +void FoFiType1C::buildEncoding() { + char buf[256]; + int nCodes, nRanges, encFormat; + int pos, c, sid, nLeft, nSups, i, j; + + if (topDict.encodingOffset == 0) { + encoding = fofiType1StandardEncoding; + + } else if (topDict.encodingOffset == 1) { + encoding = fofiType1ExpertEncoding; + + } else { + encoding = (char **)gmallocn(256, sizeof(char *)); + for (i = 0; i < 256; ++i) { + encoding[i] = NULL; + } + pos = topDict.encodingOffset; + encFormat = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if ((encFormat & 0x7f) == 0) { + nCodes = 1 + getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (nCodes > nGlyphs) { + nCodes = nGlyphs; + } + for (i = 1; i < nCodes; ++i) { + c = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(charset[i], buf, &parsedOk)); + } + } else if ((encFormat & 0x7f) == 1) { + nRanges = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + nCodes = 1; + for (i = 0; i < nRanges; ++i) { + c = getU8(pos++, &parsedOk); + nLeft = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { + if (c < 256) { + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(charset[nCodes], buf, + &parsedOk)); + } + ++nCodes; + ++c; + } + } + } + if (encFormat & 0x80) { + nSups = getU8(pos++, &parsedOk); + if (!parsedOk) { + return; + } + for (i = 0; i < nSups; ++i) { + c = getU8(pos++, &parsedOk);; + if (!parsedOk) { + return;; + } + sid = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + return; + } + if (encoding[c]) { + gfree(encoding[c]); + } + encoding[c] = copyString(getString(sid, buf, &parsedOk)); + } + } + } +} + +GBool FoFiType1C::readCharset() { + int charsetFormat, c, pos; + int nLeft, i, j; + + if (topDict.charsetOffset == 0) { + charset = fofiType1CISOAdobeCharset; + } else if (topDict.charsetOffset == 1) { + charset = fofiType1CExpertCharset; + } else if (topDict.charsetOffset == 2) { + charset = fofiType1CExpertSubsetCharset; + } else { + charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); + for (i = 0; i < nGlyphs; ++i) { + charset[i] = 0; + } + pos = topDict.charsetOffset; + charsetFormat = getU8(pos++, &parsedOk); + if (charsetFormat == 0) { + for (i = 1; i < nGlyphs; ++i) { + charset[i] = (Gushort)getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + break; + } + } + } else if (charsetFormat == 1) { + i = 1; + while (i < nGlyphs) { + c = getU16BE(pos, &parsedOk); + pos += 2; + nLeft = getU8(pos++, &parsedOk); + if (!parsedOk) { + break; + } + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + charset[i++] = (Gushort)c++; + } + } + } else if (charsetFormat == 2) { + i = 1; + while (i < nGlyphs) { + c = getU16BE(pos, &parsedOk); + pos += 2; + nLeft = getU16BE(pos, &parsedOk); + pos += 2; + if (!parsedOk) { + break; + } + for (j = 0; j <= nLeft && i < nGlyphs; ++j) { + charset[i++] = (Gushort)c++; + } + } + } + if (!parsedOk) { + gfree(charset); + charset = NULL; + return gFalse; + } + } + return gTrue; +} + +int FoFiType1C::getOp(int pos, GBool charstring, GBool *ok) { + static char nybChars[16] = "0123456789.ee -"; + Type1COp op; + char buf[65]; + int b0, b1, nyb0, nyb1, x, i; + + b0 = getU8(pos++, ok); + op.isNum = gTrue; + op.isFP = gFalse; + + if (b0 == 28) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x8000) { + x |= ~0xffff; + } + op.num = x; + + } else if (!charstring && b0 == 29) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x80000000) { + x |= ~0xffffffff; + } + op.num = x; + + } else if (!charstring && b0 == 30) { + i = 0; + do { + b1 = getU8(pos++, ok); + nyb0 = b1 >> 4; + nyb1 = b1 & 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'; + op.num = atof(buf); + op.isFP = gTrue; + + } else if (b0 >= 32 && b0 <= 246) { + op.num = b0 - 139; + + } else if (b0 >= 247 && b0 <= 250) { + op.num = ((b0 - 247) << 8) + getU8(pos++, ok) + 108; + + } else if (b0 >= 251 && b0 <= 254) { + op.num = -((b0 - 251) << 8) - getU8(pos++, ok) - 108; + + } else if (charstring && b0 == 255) { + x = getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + x = (x << 8) | getU8(pos++, ok); + if (x & 0x80000000) { + x |= ~0xffffffff; + } + op.num = (double)x / 65536.0; + op.isFP = gTrue; + + } else if (b0 == 12) { + op.isNum = gFalse; + op.op = 0x0c00 + getU8(pos++, ok); + + } else { + op.isNum = gFalse; + op.op = b0; + } + + if (nOps < 49) { + ops[nOps++] = op; + } + + return pos; +} + +// Convert the delta-encoded ops array to an array of ints. +int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) { + int x; + int n, i; + + if ((n = nOps) > maxLen) { + n = maxLen; + } + x = 0; + for (i = 0; i < n; ++i) { + x += (int)ops[i].num; + arr[i] = x; + } + return n; +} + +// Convert the delta-encoded ops array to an array of doubles. +int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) { + double x; + int n, i; + + if ((n = nOps) > maxLen) { + n = maxLen; + } + x = 0; + for (i = 0; i < n; ++i) { + x += ops[i].num; + arr[i] = x; + } + return n; +} + +void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) { + idx->pos = pos; + idx->len = getU16BE(pos, ok); + if (idx->len == 0) { + // empty indexes are legal and contain just the length field + idx->offSize = 0; + idx->startPos = idx->endPos = pos + 2; + } else { + idx->offSize = getU8(pos + 2, ok); + if (idx->offSize < 1 || idx->offSize > 4) { + *ok = gFalse; + } + idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1; + if (idx->startPos < 0 || idx->startPos >= len) { + *ok = gFalse; + } + idx->endPos = idx->startPos + getUVarBE(pos + 3 + idx->len * idx->offSize, + idx->offSize, ok); + if (idx->endPos < idx->startPos || idx->endPos > len) { + *ok = gFalse; + } + } +} + +void FoFiType1C::getIndexVal(Type1CIndex *idx, int i, + Type1CIndexVal *val, GBool *ok) { + int pos0, pos1; + + if (i < 0 || i >= idx->len) { + *ok = gFalse; + return; + } + pos0 = idx->startPos + getUVarBE(idx->pos + 3 + i * idx->offSize, + idx->offSize, ok); + pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize, + idx->offSize, ok); + if (pos0 < idx->startPos || pos0 > idx->endPos || + pos1 <= idx->startPos || pos1 > idx->endPos || + pos1 < pos0) { + *ok = gFalse; + } + val->pos = pos0; + val->len = pos1 - pos0; +} + +char *FoFiType1C::getString(int sid, char *buf, GBool *ok) { + Type1CIndexVal val; + int n; + + if (sid < 391) { + strcpy(buf, fofiType1CStdStrings[sid]); + } else { + sid -= 391; + getIndexVal(&stringIdx, sid, &val, ok); + if (*ok) { + if ((n = val.len) > 255) { + n = 255; + } + strncpy(buf, (char *)&file[val.pos], n); + buf[n] = '\0'; + } else { + buf[0] = '\0'; + } + } + return buf; +} diff --git a/pdftops/FoFiType1C.h b/pdftops/FoFiType1C.h new file mode 100644 index 000000000..bd4759069 --- /dev/null +++ b/pdftops/FoFiType1C.h @@ -0,0 +1,232 @@ +//======================================================================== +// +// FoFiType1C.h +// +// Copyright 1999-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FOFITYPE1C_H +#define FOFITYPE1C_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "FoFiBase.h" + +class GString; + +//------------------------------------------------------------------------ + +struct Type1CIndex { + int pos; // absolute position in file + int len; // length (number of entries) + int offSize; // offset size + int startPos; // position of start of index data - 1 + int endPos; // position one byte past end of the index +}; + +struct Type1CIndexVal { + int pos; // absolute position in file + int len; // length, in bytes +}; + +struct Type1CTopDict { + int firstOp; + + int versionSID; + int noticeSID; + int copyrightSID; + int fullNameSID; + int familyNameSID; + int weightSID; + int isFixedPitch; + double italicAngle; + double underlinePosition; + double underlineThickness; + int paintType; + int charstringType; + double fontMatrix[6]; + GBool hasFontMatrix; // CID fonts are allowed to put their + // FontMatrix in the FD instead of the + // top dict + int uniqueID; + double fontBBox[4]; + double strokeWidth; + int charsetOffset; + int encodingOffset; + int charStringsOffset; + int privateSize; + int privateOffset; + + // CIDFont entries + int registrySID; + int orderingSID; + int supplement; + int fdArrayOffset; + int fdSelectOffset; +}; + +#define type1CMaxBlueValues 14 +#define type1CMaxOtherBlues 10 +#define type1CMaxStemSnap 12 + +struct Type1CPrivateDict { + double fontMatrix[6]; + GBool hasFontMatrix; + int blueValues[type1CMaxBlueValues]; + int nBlueValues; + int otherBlues[type1CMaxOtherBlues]; + int nOtherBlues; + int familyBlues[type1CMaxBlueValues]; + int nFamilyBlues; + int familyOtherBlues[type1CMaxOtherBlues]; + int nFamilyOtherBlues; + double blueScale; + int blueShift; + int blueFuzz; + double stdHW; + GBool hasStdHW; + double stdVW; + GBool hasStdVW; + double stemSnapH[type1CMaxStemSnap]; + int nStemSnapH; + double stemSnapV[type1CMaxStemSnap]; + int nStemSnapV; + GBool forceBold; + GBool hasForceBold; + double forceBoldThreshold; + int languageGroup; + double expansionFactor; + int initialRandomSeed; + int subrsOffset; + double defaultWidthX; + GBool defaultWidthXFP; + double nominalWidthX; + GBool nominalWidthXFP; +}; + +struct Type1COp { + GBool isNum; // true -> number, false -> operator + GBool isFP; // true -> floating point number, false -> int + union { + double num; // if num is true + int op; // if num is false + }; +}; + +struct Type1CEexecBuf { + FoFiOutputFunc outputFunc; + void *outputStream; + GBool ascii; // ASCII encoding? + Gushort r1; // eexec encryption key + int line; // number of eexec chars left on current line +}; + +//------------------------------------------------------------------------ +// FoFiType1C +//------------------------------------------------------------------------ + +class FoFiType1C: public FoFiBase { +public: + + // Create a FoFiType1C object from a memory buffer. + static FoFiType1C *make(char *fileA, int lenA); + + // Create a FoFiType1C object from a file on disk. + static FoFiType1C *load(char *fileName); + + virtual ~FoFiType1C(); + + // Return the font name. + char *getName(); + + // Return the encoding, as an array of 256 names (any of which may + // be NULL). This is only useful with 8-bit fonts. + char **getEncoding(); + + // Return the mapping from CIDs to GIDs, and return the number of + // CIDs in *. This is only useful for CID fonts. + Gushort *getCIDToGIDMap(int *nCIDs); + + // Convert to a Type 1 font, suitable for embedding in a PostScript + // file. This is only useful with 8-bit fonts. If is + // not NULL, it will be used in place of the encoding in the Type 1C + // font. If is true the eexec section will be hex-encoded, + // otherwise it will be left as binary data. + void convertToType1(char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 CIDFont, suitable for embedding in a + // PostScript file. will be used as the PostScript font + // name. + void convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + + // Convert to a Type 0 (but non-CID) composite font, suitable for + // embedding in a PostScript file. will be used as the + // PostScript font name. + void convertToType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + +private: + + FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); + void eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName, + int offset, int nBytes, + Type1CIndex *subrIdx, + Type1CPrivateDict *pDict); + void cvtGlyph(int offset, int nBytes, GString *charBuf, + Type1CIndex *subrIdx, Type1CPrivateDict *pDict, + GBool top); + void cvtGlyphWidth(GBool useOp, GString *charBuf, + Type1CPrivateDict *pDict); + void cvtNum(double x, GBool isFP, GString *charBuf); + void eexecWrite(Type1CEexecBuf *eb, char *s); + void eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n); + GBool parse(); + void readTopDict(); + void readFD(int offset, int length, Type1CPrivateDict *pDict); + void readPrivateDict(int offset, int length, Type1CPrivateDict *pDict); + void readFDSelect(); + void buildEncoding(); + GBool readCharset(); + int getOp(int pos, GBool charstring, GBool *ok); + int getDeltaIntArray(int *arr, int maxLen); + int getDeltaFPArray(double *arr, int maxLen); + void getIndex(int pos, Type1CIndex *idx, GBool *ok); + void getIndexVal(Type1CIndex *idx, int i, Type1CIndexVal *val, GBool *ok); + char *getString(int sid, char *buf, GBool *ok); + + GString *name; + char **encoding; + + Type1CIndex nameIdx; + Type1CIndex topDictIdx; + Type1CIndex stringIdx; + Type1CIndex gsubrIdx; + Type1CIndex charStringsIdx; + + Type1CTopDict topDict; + Type1CPrivateDict *privateDicts; + + int nGlyphs; + int nFDs; + Guchar *fdSelect; + Gushort *charset; + int gsubrBias; + + GBool parsedOk; + + Type1COp ops[49]; // operands and operator + int nOps; // number of operands + int nHints; // number of hints for the current glyph + GBool firstOp; // true if we haven't hit the first op yet + GBool openPath; // true if there is an unclosed path +}; + +#endif diff --git a/pdftops/FontEncodingTables.cxx b/pdftops/FontEncodingTables.cxx new file mode 100644 index 000000000..cd8d89265 --- /dev/null +++ b/pdftops/FontEncodingTables.cxx @@ -0,0 +1,1824 @@ +//======================================================================== +// +// FontEncodingTables.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include +#include +#include "FontEncodingTables.h" + +char *macRomanEncoding[256] = { + 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", + "notequal", + "AE", + "Oslash", + "infinity", + "plusminus", + "lessequal", + "greaterequal", + "yen", + "mu", + "partialdiff", + "summation", + "product", + "pi", + "integral", + "ordfeminine", + "ordmasculine", + "Omega", + "ae", + "oslash", + "questiondown", + "exclamdown", + "logicalnot", + "radical", + "florin", + "approxequal", + "Delta", + "guillemotleft", + "guillemotright", + "ellipsis", + "space", + "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", + "apple", + "Ograve", + "Uacute", + "Ucircumflex", + "Ugrave", + "dotlessi", + "circumflex", + "tilde", + "macron", + "breve", + "dotaccent", + "ring", + "cedilla", + "hungarumlaut", + "ogonek", + "caron" +}; + +char *macExpertEncoding[256] = { + 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", + "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", + NULL, + "threequartersemdash", + NULL, + "questionsmall", + NULL, + NULL, + NULL, + NULL, + "Ethsmall", + NULL, + NULL, + "onequarter", + "onehalf", + "threequarters", + "oneeighth", + "threeeighths", + "fiveeighths", + "seveneighths", + "onethird", + "twothirds", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "ff", + "fi", + "fl", + "ffi", + "ffl", + "parenleftinferior", + NULL, + "parenrightinferior", + "Circumflexsmall", + "hypheninferior", + "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, + "asuperior", + "centsuperior", + NULL, + NULL, + NULL, + NULL, + "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", + NULL, + "eightsuperior", + "fourinferior", + "threeinferior", + "sixinferior", + "eightinferior", + "seveninferior", + "Scaronsmall", + NULL, + "centinferior", + "twoinferior", + NULL, + "Dieresissmall", + NULL, + "Caronsmall", + "osuperior", + "fiveinferior", + NULL, + "commainferior", + "periodinferior", + "Yacutesmall", + NULL, + "dollarinferior", + NULL, + NULL, + "Thornsmall", + NULL, + "nineinferior", + "zeroinferior", + "Zcaronsmall", + "AEsmall", + "Oslashsmall", + "questiondownsmall", + "oneinferior", + "Lslashsmall", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "Cedillasmall", + NULL, + NULL, + NULL, + NULL, + NULL, + "OEsmall", + "figuredash", + "hyphensuperior", + NULL, + NULL, + NULL, + NULL, + "exclamdownsmall", + NULL, + "Ydieresissmall", + NULL, + "onesuperior", + "twosuperior", + "threesuperior", + "foursuperior", + "fivesuperior", + "sixsuperior", + "sevensuperior", + "ninesuperior", + "zerosuperior", + NULL, + "esuperior", + "rsuperior", + "tsuperior", + NULL, + NULL, + "isuperior", + "ssuperior", + "dsuperior", + NULL, + NULL, + NULL, + NULL, + NULL, + "lsuperior", + "Ogoneksmall", + "Brevesmall", + "Macronsmall", + "bsuperior", + "nsuperior", + "msuperior", + "commasuperior", + "periodsuperior", + "Dotaccentsmall", + "Ringsmall", + NULL, + NULL, + NULL, + NULL +}; + +char *winAnsiEncoding[256] = { + 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", + "Zcaron", + "bullet", + "bullet", + "quoteleft", + "quoteright", + "quotedblleft", + "quotedblright", + "bullet", + "endash", + "emdash", + "tilde", + "trademark", + "scaron", + "guilsinglright", + "oe", + "bullet", + "zcaron", + "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" +}; + +char *standardEncoding[256] = { + 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 +}; + +char *expertEncoding[256] = { + 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" +}; + +char *symbolEncoding[256] = { + 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 +}; + +char *zapfDingbatsEncoding[256] = { + 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 +}; diff --git a/pdftops/FontEncodingTables.h b/pdftops/FontEncodingTables.h new file mode 100644 index 000000000..8b0a1e7e9 --- /dev/null +++ b/pdftops/FontEncodingTables.h @@ -0,0 +1,20 @@ +//======================================================================== +// +// FontEncodingTables.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FONTENCODINGTABLES_H +#define FONTENCODINGTABLES_H + +extern char *macRomanEncoding[]; +extern char *macExpertEncoding[]; +extern char *winAnsiEncoding[]; +extern char *standardEncoding[]; +extern char *expertEncoding[]; +extern char *symbolEncoding[]; +extern char *zapfDingbatsEncoding[]; + +#endif diff --git a/pdftops/Function.cxx b/pdftops/Function.cxx new file mode 100644 index 000000000..7959a4802 --- /dev/null +++ b/pdftops/Function.cxx @@ -0,0 +1,1536 @@ +//======================================================================== +// +// Function.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#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 == 3) { + func = new StitchingFunction(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 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(); + idxMul[0] = n; + for (i = 1; i < m; ++i) { + idxMul[i] = idxMul[i-1] * sampleSize[i-1]; + } + + //----- 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(); + for (i = 0; i < m; ++i) { + inputMul[i] = (encode[i][1] - encode[i][0]) / + (domain[i][1] - domain[i][0]); + } + + //----- 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 *)gmallocn(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) { + memcpy(this, func, sizeof(SampledFunction)); + samples = (double *)gmallocn(nSamples, sizeof(double)); + memcpy(samples, func->samples, nSamples * sizeof(double)); +} + +void SampledFunction::transform(double *in, double *out) { + double x; + int e[funcMaxInputs][2]; + double efrac0[funcMaxInputs]; + double efrac1[funcMaxInputs]; + double s[1 << funcMaxInputs]; + int i, j, k, idx, t; + + // map input values into sample array + for (i = 0; i < m; ++i) { + x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0]; + if (x < 0) { + x = 0; + } else if (x > sampleSize[i] - 1) { + x = sampleSize[i] - 1; + } + e[i][0] = (int)x; + if ((e[i][1] = e[i][0] + 1) >= sampleSize[i]) { + // this happens if in[i] = domain[i][1] + e[i][1] = e[i][0]; + } + efrac1[i] = x - e[i][0]; + efrac0[i] = 1 - efrac1[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<>= 1) { + idx += idxMul[k] * (e[k][t & 1]); + } + s[j] = samples[idx]; + } + + // do m sets of interpolations + for (j = 0, t = (1<>= 1) { + for (k = 0; k < t; k += 2) { + s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1]; + } + } + + // map output value to range + out[i] = s[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; + int i; + + ok = gFalse; + + //----- initialize the generic stuff + if (!init(dict)) { + goto err1; + } + if (m != 1) { + error(-1, "Exponential function with more than one input"); + goto err1; + } + + //----- C0 + if (dict->lookup("C0", &obj1)->isArray()) { + if (hasRange && obj1.arrayGetLength() != n) { + error(-1, "Function's C0 array is wrong length"); + goto err2; + } + n = obj1.arrayGetLength(); + 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(); + } + } else { + if (hasRange && n != 1) { + error(-1, "Function's C0 array is wrong length"); + goto err2; + } + n = 1; + c0[0] = 0; + } + obj1.free(); + + //----- C1 + if (dict->lookup("C1", &obj1)->isArray()) { + 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(); + } + } else { + if (n != 1) { + error(-1, "Function's C1 array is wrong length"); + goto err2; + } + c1[0] = 1; + } + 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; +} + +//------------------------------------------------------------------------ +// StitchingFunction +//------------------------------------------------------------------------ + +StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) { + Object obj1, obj2; + int i; + + ok = gFalse; + funcs = NULL; + bounds = NULL; + encode = NULL; + + //----- initialize the generic stuff + if (!init(dict)) { + goto err1; + } + if (m != 1) { + error(-1, "Stitching function with more than one input"); + goto err1; + } + + //----- Functions + if (!dict->lookup("Functions", &obj1)->isArray()) { + error(-1, "Missing 'Functions' entry in stitching function"); + goto err1; + } + k = obj1.arrayGetLength(); + funcs = (Function **)gmallocn(k, sizeof(Function *)); + bounds = (double *)gmallocn(k + 1, sizeof(double)); + encode = (double *)gmallocn(2 * k, sizeof(double)); + for (i = 0; i < k; ++i) { + funcs[i] = NULL; + } + for (i = 0; i < k; ++i) { + if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2)))) { + goto err2; + } + if (i > 0 && (funcs[i]->getInputSize() != 1 || + funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) { + error(-1, "Incompatible subfunctions in stitching function"); + goto err2; + } + obj2.free(); + } + obj1.free(); + + //----- Bounds + if (!dict->lookup("Bounds", &obj1)->isArray() || + obj1.arrayGetLength() != k - 1) { + error(-1, "Missing or invalid 'Bounds' entry in stitching function"); + goto err1; + } + bounds[0] = domain[0][0]; + for (i = 1; i < k; ++i) { + if (!obj1.arrayGet(i - 1, &obj2)->isNum()) { + error(-1, "Invalid type in 'Bounds' array in stitching function"); + goto err2; + } + bounds[i] = obj2.getNum(); + obj2.free(); + } + bounds[k] = domain[0][1]; + obj1.free(); + + //----- Encode + if (!dict->lookup("Encode", &obj1)->isArray() || + obj1.arrayGetLength() != 2 * k) { + error(-1, "Missing or invalid 'Encode' entry in stitching function"); + goto err1; + } + for (i = 0; i < 2 * k; ++i) { + if (!obj1.arrayGet(i, &obj2)->isNum()) { + error(-1, "Invalid type in 'Encode' array in stitching function"); + goto err2; + } + encode[i] = obj2.getNum(); + obj2.free(); + } + obj1.free(); + + ok = gTrue; + return; + + err2: + obj2.free(); + err1: + obj1.free(); +} + +StitchingFunction::StitchingFunction(StitchingFunction *func) { + int i; + + k = func->k; + funcs = (Function **)gmallocn(k, sizeof(Function *)); + for (i = 0; i < k; ++i) { + funcs[i] = func->funcs[i]->copy(); + } + bounds = (double *)gmallocn(k + 1, sizeof(double)); + memcpy(bounds, func->bounds, (k + 1) * sizeof(double)); + encode = (double *)gmallocn(2 * k, sizeof(double)); + memcpy(encode, func->encode, 2 * k * sizeof(double)); + ok = gTrue; +} + +StitchingFunction::~StitchingFunction() { + int i; + + if (funcs) { + for (i = 0; i < k; ++i) { + if (funcs[i]) { + delete funcs[i]; + } + } + } + gfree(funcs); + gfree(bounds); + gfree(encode); +} + +void StitchingFunction::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 < k - 1; ++i) { + if (x < bounds[i+1]) { + break; + } + } + x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) * + (encode[2*i+1] - encode[2*i]); + funcs[i]->transform(&x, out); +} + +//------------------------------------------------------------------------ +// 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= | +// +---------------------------------+ +// | psBlock: ptr= | +// +---------------------------------+ +// | if clause | +// | ... | +// | psOperator: psOpReturn | +// +---------------------------------+ +// | else clause | +// | ... | +// | psOperator: psOpReturn | +// +---------------------------------+ +// | ... | +// +// For 'if', pointer 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 (sp + n > psStackSize) { + error(-1, "Stack underflow in PostScript function"); + return; + } + 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 + codeString = new GString(); + 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 *)gmallocn(codeSize, sizeof(PSObject)); + memcpy(code, func->code, codeSize * sizeof(PSObject)); + codeString = func->codeString->copy(); +} + +PostScriptFunction::~PostScriptFunction() { + gfree(code); + delete codeString; +} + +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; + } + delete tok; + if (!(tok = getToken(str))) { + error(-1, "Unexpected end of PostScript function stream"); + return gFalse; + } + } else { + elsePtr = -1; + } + 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] + cmp = 1; + 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(); + if (c != EOF) { + codeString->append(c); + } + } 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(); + codeString->append(c); + } + } else { + while (1) { + s->append((char)c); + c = str->lookChar(); + if (c == EOF || !isalnum(c)) { + break; + } + str->getChar(); + codeString->append(c); + } + } + return s; +} + +void PostScriptFunction::resizeCode(int newSize) { + if (newSize >= codeSize) { + codeSize += 64; + code = (PSObject *)greallocn(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->pushBool(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->popNum(); + r1 = stack->popNum(); + 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->pushBool(!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->pushBool(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(sin(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->pushBool(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..df1623772 --- /dev/null +++ b/pdftops/Function.h @@ -0,0 +1,225 @@ +//======================================================================== +// +// Function.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef FUNCTION_H +#define FUNCTION_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" + +class Dict; +class Stream; +struct PSObject; +class PSStack; + +//------------------------------------------------------------------------ +// Function +//------------------------------------------------------------------------ + +#define funcMaxInputs 8 +#define funcMaxOutputs 32 + +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 the function type: + // -1 : identity + // 0 : sampled + // 2 : exponential + // 3 : stitching + // 4 : PostScript + virtual int getType() = 0; + + // Return size of input and output tuples. + int getInputSize() { return m; } + int getOutputSize() { return n; } + + double getDomainMin(int i) { return domain[i][0]; } + double getDomainMax(int i) { return domain[i][1]; } + double getRangeMin(int i) { return range[i][0]; } + double getRangeMax(int i) { return range[i][1]; } + GBool getHasRange() { return hasRange; } + + // 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 int getType() { return -1; } + 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 int getType() { return 0; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return ok; } + + int getSampleSize(int i) { return sampleSize[i]; } + double getEncodeMin(int i) { return encode[i][0]; } + double getEncodeMax(int i) { return encode[i][1]; } + double getDecodeMin(int i) { return decode[i][0]; } + double getDecodeMax(int i) { return decode[i][1]; } + double *getSamples() { return samples; } + +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 // input multipliers + inputMul[funcMaxInputs]; + int idxMul[funcMaxInputs]; // sample array index multipliers + double *samples; // the samples + int nSamples; // size of the samples array + GBool ok; +}; + +//------------------------------------------------------------------------ +// ExponentialFunction +//------------------------------------------------------------------------ + +class ExponentialFunction: public Function { +public: + + ExponentialFunction(Object *funcObj, Dict *dict); + virtual ~ExponentialFunction(); + virtual Function *copy() { return new ExponentialFunction(this); } + virtual int getType() { return 2; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return ok; } + + double *getC0() { return c0; } + double *getC1() { return c1; } + double getE() { return e; } + +private: + + ExponentialFunction(ExponentialFunction *func); + + double c0[funcMaxOutputs]; + double c1[funcMaxOutputs]; + double e; + GBool ok; +}; + +//------------------------------------------------------------------------ +// StitchingFunction +//------------------------------------------------------------------------ + +class StitchingFunction: public Function { +public: + + StitchingFunction(Object *funcObj, Dict *dict); + virtual ~StitchingFunction(); + virtual Function *copy() { return new StitchingFunction(this); } + virtual int getType() { return 3; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return ok; } + + int getNumFuncs() { return k; } + Function *getFunc(int i) { return funcs[i]; } + double *getBounds() { return bounds; } + double *getEncode() { return encode; } + +private: + + StitchingFunction(StitchingFunction *func); + + int k; + Function **funcs; + double *bounds; + double *encode; + GBool ok; +}; + +//------------------------------------------------------------------------ +// PostScriptFunction +//------------------------------------------------------------------------ + +class PostScriptFunction: public Function { +public: + + PostScriptFunction(Object *funcObj, Dict *dict); + virtual ~PostScriptFunction(); + virtual Function *copy() { return new PostScriptFunction(this); } + virtual int getType() { return 4; } + virtual void transform(double *in, double *out); + virtual GBool isOk() { return ok; } + + GString *getCodeString() { return codeString; } + +private: + + PostScriptFunction(PostScriptFunction *func); + GBool parseCode(Stream *str, int *codePtr); + GString *getToken(Stream *str); + void resizeCode(int newSize); + void exec(PSStack *stack, int codePtr); + + GString *codeString; + PSObject *code; + int codeSize; + GBool ok; +}; + +#endif diff --git a/pdftops/GHash.cxx b/pdftops/GHash.cxx new file mode 100644 index 000000000..7185a693c --- /dev/null +++ b/pdftops/GHash.cxx @@ -0,0 +1,380 @@ +//======================================================================== +// +// GHash.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "GString.h" +#include "GHash.h" + +//------------------------------------------------------------------------ + +struct GHashBucket { + GString *key; + union { + void *p; + int i; + } val; + GHashBucket *next; +}; + +struct GHashIter { + int h; + GHashBucket *p; +}; + +//------------------------------------------------------------------------ + +GHash::GHash(GBool deleteKeysA) { + int h; + + deleteKeys = deleteKeysA; + size = 7; + tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); + for (h = 0; h < size; ++h) { + tab[h] = NULL; + } + len = 0; +} + +GHash::~GHash() { + GHashBucket *p; + int h; + + for (h = 0; h < size; ++h) { + while (tab[h]) { + p = tab[h]; + tab[h] = p->next; + if (deleteKeys) { + delete p->key; + } + delete p; + } + } + gfree(tab); +} + +void GHash::add(GString *key, void *val) { + GHashBucket *p; + int h; + + // expand the table if necessary + if (len >= size) { + expand(); + } + + // add the new symbol + p = new GHashBucket; + p->key = key; + p->val.p = val; + h = hash(key); + p->next = tab[h]; + tab[h] = p; + ++len; +} + +void GHash::add(GString *key, int val) { + GHashBucket *p; + int h; + + // expand the table if necessary + if (len >= size) { + expand(); + } + + // add the new symbol + p = new GHashBucket; + p->key = key; + p->val.i = val; + h = hash(key); + p->next = tab[h]; + tab[h] = p; + ++len; +} + +void GHash::replace(GString *key, void *val) { + GHashBucket *p; + int h; + + if ((p = find(key, &h))) { + p->val.p = val; + delete key; + } else { + add(key, val); + } +} + +void GHash::replace(GString *key, int val) { + GHashBucket *p; + int h; + + if ((p = find(key, &h))) { + p->val.i = val; + delete key; + } else { + add(key, val); + } +} + +void *GHash::lookup(GString *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return NULL; + } + return p->val.p; +} + +int GHash::lookupInt(GString *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + return p->val.i; +} + +void *GHash::lookup(char *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return NULL; + } + return p->val.p; +} + +int GHash::lookupInt(char *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + return p->val.i; +} + +void *GHash::remove(GString *key) { + GHashBucket *p; + GHashBucket **q; + void *val; + int h; + + if (!(p = find(key, &h))) { + return NULL; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.p; + delete p; + --len; + return val; +} + +int GHash::removeInt(GString *key) { + GHashBucket *p; + GHashBucket **q; + int val; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.i; + delete p; + --len; + return val; +} + +void *GHash::remove(char *key) { + GHashBucket *p; + GHashBucket **q; + void *val; + int h; + + if (!(p = find(key, &h))) { + return NULL; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.p; + delete p; + --len; + return val; +} + +int GHash::removeInt(char *key) { + GHashBucket *p; + GHashBucket **q; + int val; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.i; + delete p; + --len; + return val; +} + +void GHash::startIter(GHashIter **iter) { + *iter = new GHashIter; + (*iter)->h = -1; + (*iter)->p = NULL; +} + +GBool GHash::getNext(GHashIter **iter, GString **key, void **val) { + if (!*iter) { + return gFalse; + } + if ((*iter)->p) { + (*iter)->p = (*iter)->p->next; + } + while (!(*iter)->p) { + if (++(*iter)->h == size) { + delete *iter; + *iter = NULL; + return gFalse; + } + (*iter)->p = tab[(*iter)->h]; + } + *key = (*iter)->p->key; + *val = (*iter)->p->val.p; + return gTrue; +} + +GBool GHash::getNext(GHashIter **iter, GString **key, int *val) { + if (!*iter) { + return gFalse; + } + if ((*iter)->p) { + (*iter)->p = (*iter)->p->next; + } + while (!(*iter)->p) { + if (++(*iter)->h == size) { + delete *iter; + *iter = NULL; + return gFalse; + } + (*iter)->p = tab[(*iter)->h]; + } + *key = (*iter)->p->key; + *val = (*iter)->p->val.i; + return gTrue; +} + +void GHash::killIter(GHashIter **iter) { + delete *iter; + *iter = NULL; +} + +void GHash::expand() { + GHashBucket **oldTab; + GHashBucket *p; + int oldSize, h, i; + + oldSize = size; + oldTab = tab; + size = 2*size + 1; + tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); + for (h = 0; h < size; ++h) { + tab[h] = NULL; + } + for (i = 0; i < oldSize; ++i) { + while (oldTab[i]) { + p = oldTab[i]; + oldTab[i] = oldTab[i]->next; + h = hash(p->key); + p->next = tab[h]; + tab[h] = p; + } + } + gfree(oldTab); +} + +GHashBucket *GHash::find(GString *key, int *h) { + GHashBucket *p; + + *h = hash(key); + for (p = tab[*h]; p; p = p->next) { + if (!p->key->cmp(key)) { + return p; + } + } + return NULL; +} + +GHashBucket *GHash::find(char *key, int *h) { + GHashBucket *p; + + *h = hash(key); + for (p = tab[*h]; p; p = p->next) { + if (!p->key->cmp(key)) { + return p; + } + } + return NULL; +} + +int GHash::hash(GString *key) { + char *p; + unsigned int h; + int i; + + h = 0; + for (p = key->getCString(), i = 0; i < key->getLength(); ++p, ++i) { + h = 17 * h + (int)(*p & 0xff); + } + return (int)(h % size); +} + +int GHash::hash(char *key) { + char *p; + unsigned int h; + + h = 0; + for (p = key; *p; ++p) { + h = 17 * h + (int)(*p & 0xff); + } + return (int)(h % size); +} diff --git a/pdftops/GHash.h b/pdftops/GHash.h new file mode 100644 index 000000000..e454b69f3 --- /dev/null +++ b/pdftops/GHash.h @@ -0,0 +1,78 @@ +//======================================================================== +// +// GHash.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GHASH_H +#define GHASH_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class GString; +struct GHashBucket; +struct GHashIter; + +//------------------------------------------------------------------------ + +class GHash { +public: + + GHash(GBool deleteKeysA = gFalse); + ~GHash(); + void add(GString *key, void *val); + void add(GString *key, int val); + void replace(GString *key, void *val); + void replace(GString *key, int val); + void *lookup(GString *key); + int lookupInt(GString *key); + void *lookup(char *key); + int lookupInt(char *key); + void *remove(GString *key); + int removeInt(GString *key); + void *remove(char *key); + int removeInt(char *key); + int getLength() { return len; } + void startIter(GHashIter **iter); + GBool getNext(GHashIter **iter, GString **key, void **val); + GBool getNext(GHashIter **iter, GString **key, int *val); + void killIter(GHashIter **iter); + +private: + + void expand(); + GHashBucket *find(GString *key, int *h); + GHashBucket *find(char *key, int *h); + int hash(GString *key); + int hash(char *key); + + GBool deleteKeys; // set if key strings should be deleted + int size; // number of buckets + int len; // number of entries + GHashBucket **tab; +}; + +#define deleteGHash(hash, T) \ + do { \ + GHash *_hash = (hash); \ + { \ + GHashIter *_iter; \ + GString *_key; \ + void *_p; \ + _hash->startIter(&_iter); \ + while (_hash->getNext(&_iter, &_key, &_p)) { \ + delete (T*)_p; \ + } \ + delete _hash; \ + } \ + } while(0) + +#endif diff --git a/pdftops/GList.cxx b/pdftops/GList.cxx new file mode 100644 index 000000000..326098c77 --- /dev/null +++ b/pdftops/GList.cxx @@ -0,0 +1,97 @@ +//======================================================================== +// +// GList.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "GList.h" + +//------------------------------------------------------------------------ +// GList +//------------------------------------------------------------------------ + +GList::GList() { + size = 8; + data = (void **)gmallocn(size, sizeof(void*)); + length = 0; + inc = 0; +} + +GList::GList(int sizeA) { + size = sizeA; + data = (void **)gmallocn(size, sizeof(void*)); + length = 0; + inc = 0; +} + +GList::~GList() { + gfree(data); +} + +void GList::append(void *p) { + if (length >= size) { + expand(); + } + data[length++] = p; +} + +void GList::append(GList *list) { + int i; + + while (length + list->length > size) { + expand(); + } + for (i = 0; i < list->length; ++i) { + data[length++] = list->data[i]; + } +} + +void GList::insert(int i, void *p) { + if (length >= size) { + expand(); + } + if (i < length) { + memmove(data+i+1, data+i, (length - i) * sizeof(void *)); + } + data[i] = p; + ++length; +} + +void *GList::del(int i) { + void *p; + + p = data[i]; + if (i < length - 1) { + memmove(data+i, data+i+1, (length - i - 1) * sizeof(void *)); + } + --length; + if (size - length >= ((inc > 0) ? inc : size/2)) { + shrink(); + } + return p; +} + +void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) { + qsort(data, length, sizeof(void *), cmp); +} + +void GList::expand() { + size += (inc > 0) ? inc : size; + data = (void **)greallocn(data, size, sizeof(void*)); +} + +void GList::shrink() { + size -= (inc > 0) ? inc : size/2; + data = (void **)greallocn(data, size, sizeof(void*)); +} diff --git a/pdftops/GList.h b/pdftops/GList.h new file mode 100644 index 000000000..48e02c0b3 --- /dev/null +++ b/pdftops/GList.h @@ -0,0 +1,96 @@ +//======================================================================== +// +// GList.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GLIST_H +#define GLIST_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// GList +//------------------------------------------------------------------------ + +class GList { +public: + + // Create an empty list. + GList(); + + // Create an empty list with space for elements. + GList(int sizeA); + + // Destructor - does not free pointed-to objects. + ~GList(); + + //----- general + + // Get the number of elements. + int getLength() { return length; } + + //----- ordered list support + + // Return the th element. + // Assumes 0 <= i < length. + void *get(int i) { return data[i]; } + + // Append an element to the end of the list. + void append(void *p); + + // Append another list to the end of this one. + void append(GList *list); + + // Insert an element at index . + // Assumes 0 <= i <= length. + void insert(int i, void *p); + + // Deletes and returns the element at index . + // Assumes 0 <= i < length. + void *del(int i); + + // Sort the list accoring to the given comparison function. + // NB: this sorts an array of pointers, so the pointer args need to + // be double-dereferenced. + void sort(int (*cmp)(const void *ptr1, const void *ptr2)); + + //----- control + + // Set allocation increment to . If inc > 0, that many + // elements will be allocated every time the list is expanded. + // If inc <= 0, the list will be doubled in size. + void setAllocIncr(int incA) { inc = incA; } + +private: + + void expand(); + void shrink(); + + void **data; // the list elements + int size; // size of data array + int length; // number of elements on list + int inc; // allocation increment +}; + +#define deleteGList(list, T) \ + do { \ + GList *_list = (list); \ + { \ + int _i; \ + for (_i = 0; _i < _list->getLength(); ++_i) { \ + delete (T*)_list->get(_i); \ + } \ + delete _list; \ + } \ + } while (0) + +#endif diff --git a/pdftops/GMutex.h b/pdftops/GMutex.h new file mode 100644 index 000000000..7fa93d85e --- /dev/null +++ b/pdftops/GMutex.h @@ -0,0 +1,49 @@ +//======================================================================== +// +// GMutex.h +// +// Portable mutex macros. +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GMUTEX_H +#define GMUTEX_H + +// Usage: +// +// GMutex m; +// gInitMutex(&m); +// ... +// gLockMutex(&m); +// ... critical section ... +// gUnlockMutex(&m); +// ... +// gDestroyMutex(&m); + +#ifdef WIN32 + +#include + +typedef CRITICAL_SECTION GMutex; + +#define gInitMutex(m) InitializeCriticalSection(m) +#define gDestroyMutex(m) DeleteCriticalSection(m) +#define gLockMutex(m) EnterCriticalSection(m) +#define gUnlockMutex(m) LeaveCriticalSection(m) + +#else // assume pthreads + +#include + +typedef pthread_mutex_t GMutex; + +#define gInitMutex(m) pthread_mutex_init(m, NULL) +#define gDestroyMutex(m) pthread_mutex_destroy(m) +#define gLockMutex(m) pthread_mutex_lock(m) +#define gUnlockMutex(m) pthread_mutex_unlock(m) + +#endif + +#endif diff --git a/pdftops/GString.cxx b/pdftops/GString.cxx new file mode 100644 index 000000000..fbc5b7e94 --- /dev/null +++ b/pdftops/GString.cxx @@ -0,0 +1,319 @@ +//======================================================================== +// +// GString.cc +// +// Simple variable-length string type. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#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)]; + if (length1 < length) { + memcpy(s1, s, length1); + s1[length1] = '\0'; + } else { + memcpy(s1, s, length + 1); + } + delete[] s; + s = s1; + } +} + +GString::GString() { + s = NULL; + resize(length = 0); + s[0] = '\0'; +} + +GString::GString(const char *sA) { + int n = strlen(sA); + + s = NULL; + resize(length = n); + memcpy(s, sA, n + 1); +} + +GString::GString(const char *sA, int lengthA) { + s = NULL; + resize(length = lengthA); + memcpy(s, sA, length * sizeof(char)); + s[length] = '\0'; +} + +GString::GString(GString *str, int idx, int lengthA) { + s = NULL; + resize(length = lengthA); + memcpy(s, str->getCString() + idx, length); + 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 lengthA) { + resize(length + lengthA); + memcpy(s + length, str, lengthA); + length += lengthA; + 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 lengthA) { + int j; + + resize(length + lengthA); + for (j = length; j >= i; --j) + s[j+lengthA] = s[j]; + memcpy(s+i, str, lengthA); + length += lengthA; + return this; +} + +GString *GString::del(int i, int n) { + int j; + + if (n > 0) { + if (i + n > length) { + n = length - i; + } + 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; +} + +int GString::cmp(GString *str) { + int n1, n2, i, x; + char *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + return n1 - n2; +} + +int GString::cmpN(GString *str, int n) { + int n1, n2, i, x; + char *p1, *p2; + + n1 = length; + n2 = str->length; + for (i = 0, p1 = s, p2 = str->s; + i < n1 && i < n2 && i < n; + ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i == n) { + return 0; + } + return n1 - n2; +} + +int GString::cmp(const char *sA) { + int n1, i, x; + const char *p1, *p2; + + n1 = length; + for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i < n1) { + return 1; + } + if (*p2) { + return -1; + } + return 0; +} + +int GString::cmpN(const char *sA, int n) { + int n1, i, x; + const char *p1, *p2; + + n1 = length; + for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) { + x = *p1 - *p2; + if (x != 0) { + return x; + } + } + if (i == n) { + return 0; + } + if (i < n1) { + return 1; + } + if (*p2) { + return -1; + } + return 0; +} diff --git a/pdftops/GString.h b/pdftops/GString.h new file mode 100644 index 000000000..aa16e5dd8 --- /dev/null +++ b/pdftops/GString.h @@ -0,0 +1,97 @@ +//======================================================================== +// +// GString.h +// +// Simple variable-length string type. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GSTRING_H +#define GSTRING_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +class GString { +public: + + // Create an empty string. + GString(); + + // Create a string from a C string. + GString(const char *sA); + + // Create a string from chars at . This string + // can contain null characters. + GString(const char *sA, int lengthA); + + // Create a string from chars at in . + GString(GString *str, int idx, int lengthA); + + // 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 th character. + char getChar(int i) { return s[i]; } + + // Change 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 lengthA); + + // 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 lengthA); + + // 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:> + int cmp(GString *str); + int cmpN(GString *str, int n); + int cmp(const char *sA); + int cmpN(const char *sA, int 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..6e675a44c --- /dev/null +++ b/pdftops/Gfx.cxx @@ -0,0 +1,3623 @@ +//======================================================================== +// +// Gfx.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include +#include "gmem.h" +#include "GlobalParams.h" +#include "CharTypes.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 "Page.h" +#include "Error.h" +#include "Gfx.h" + +// the MSVC math.h doesn't define this +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +//------------------------------------------------------------------------ +// constants +//------------------------------------------------------------------------ + +// Max recursive depth for a function shading fill. +#define functionMaxDepth 6 + +// Max delta allowed in any color component for a function shading fill. +#define functionColorDelta (dblToCol(1 / 256.0)) + +// 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 (dblToCol(1 / 256.0)) + +// Max number of splits along the t axis for a radial shading fill. +#define radialMaxSplits 256 + +// Max delta allowed in any color component for a radial shading fill. +#define radialColorDelta (dblToCol(1 / 256.0)) + +// Max recursive depth for a Gouraud triangle shading fill. +#define gouraudMaxDepth 4 + +// Max delta allowed in any color component for a Gouraud triangle +// shading fill. +#define gouraudColorDelta (dblToCol(1 / 256.0)) + +// Max recursive depth for a patch mesh shading fill. +#define patchMaxDepth 6 + +// Max delta allowed in any color component for a patch mesh shading +// fill. +#define patchColorDelta (dblToCol(1 / 256.0)) + +//------------------------------------------------------------------------ +// Operator table +//------------------------------------------------------------------------ + +#ifdef WIN32 // this works around a bug in the VC7 compiler +# pragma optimize("",off) +#endif + +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}, +}; + +#ifdef WIN32 // this works around a bug in the VC7 compiler +# pragma optimize("",on) +#endif + +#define numOps (sizeof(opTab) / sizeof(Operator)) + +//------------------------------------------------------------------------ +// GfxResources +//------------------------------------------------------------------------ + +GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) { + Object obj1, obj2; + Ref r; + + if (resDict) { + + // build font dictionary + fonts = NULL; + resDict->lookupNF("Font", &obj1); + if (obj1.isRef()) { + obj1.fetch(xref, &obj2); + if (obj2.isDict()) { + r = obj1.getRef(); + fonts = new GfxFontDict(xref, &r, obj2.getDict()); + } + obj2.free(); + } else if (obj1.isDict()) { + fonts = new GfxFontDict(xref, NULL, 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(); + shadingDict.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 hDPI, double vDPI, PDFRectangle *box, + PDFRectangle *cropBox, int rotate, + GBool (*abortCheckCbkA)(void *data), + void *abortCheckCbkDataA) { + int i; + + xref = xrefA; + subPage = gFalse; + printCommands = globalParams->getPrintCommands(); + + // start the resource stack + res = new GfxResources(xref, resDict, NULL); + + // initialize + out = outA; + state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown()); + fontChanged = gFalse; + clip = clipNone; + ignoreUndef = 0; + renderThisPage = out->startPage(pageNum, state); + if (!renderThisPage) + return; + + out->setDefaultCTM(state->getCTM()); + out->updateAll(state); + for (i = 0; i < 6; ++i) { + baseMatrix[i] = state->getCTM()[i]; + } + formDepth = 0; + abortCheckCbk = abortCheckCbkA; + abortCheckCbkData = abortCheckCbkDataA; + + // set crop box + if (cropBox) { + 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(XRef *xrefA, OutputDev *outA, Dict *resDict, + PDFRectangle *box, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data), + void *abortCheckCbkDataA) { + int i; + + xref = xrefA; + subPage = gTrue; + printCommands = globalParams->getPrintCommands(); + renderThisPage = gTrue; + + // start the resource stack + res = new GfxResources(xref, resDict, NULL); + + // initialize + out = outA; + state = new GfxState(72, 72, box, 0, gFalse); + fontChanged = gFalse; + clip = clipNone; + ignoreUndef = 0; + for (i = 0; i < 6; ++i) { + baseMatrix[i] = state->getCTM()[i]; + } + formDepth = 0; + abortCheckCbk = abortCheckCbkA; + abortCheckCbkData = abortCheckCbkDataA; + + // set crop box + if (cropBox) { + 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() { + while (state->hasSaves()) { + restoreState(); + } + if (!subPage) { + out->endPage(); + } + while (res) { + popResources(); + } + if (state) { + delete state; + } +} + +void Gfx::display(Object *obj, GBool topLevel) { + Object obj2; + int i; + + if (!renderThisPage) + return; + + 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 numArgs, i; + int lastAbortCheck; + + // scan a sequence of objects + updateLevel = lastAbortCheck = 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 (++updateLevel >= 20000) { + out->dump(); + updateLevel = 0; + } + + // check for an abort + if (abortCheckCbk) { + if (updateLevel - lastAbortCheck > 10) { + if ((*abortCheckCbk)(abortCheckCbkData)) { + break; + } + lastAbortCheck = updateLevel; + } + } + + // 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 && updateLevel > 0) { + out->dump(); + } +} + +void Gfx::execOp(Object *cmd, Object args[], int numArgs) { + Operator *op; + char *name; + Object *argPtr; + int i; + + // find operator + name = cmd->getCmd(); + if (!(op = findOp(name))) { + if (ignoreUndef == 0) + error(getPos(), "Unknown operator '%s'", name); + return; + } + + // type check args + argPtr = args; + if (op->numArgs >= 0) { + if (numArgs < op->numArgs) { + error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name); + return; + } + if (numArgs > op->numArgs) { +#if 0 + error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name); +#endif + argPtr += numArgs - op->numArgs; + numArgs = op->numArgs; + } + } 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(&argPtr[i], op->tchk[i])) { + error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)", + i, name, argPtr[i].getTypeName()); + return; + } + } + + // do it + (this->*op->func)(argPtr, numArgs); +} + +Operator *Gfx::findOp(char *name) { + int a, b, m, cmp; + + a = -1; + b = numOps; + // invariant: opTab[a] < name < opTab[b] + cmp = 1; + 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) { + saveState(); +} + +void Gfx::opRestore(Object args[], int numArgs) { + restoreState(); +} + +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 *)gmallocn(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; + GfxBlendMode mode; + GBool haveFillOP; + + if (!res->lookupGState(args[0].getName(), &obj1)) { + return; + } + if (!obj1.isDict()) { + error(getPos(), "ExtGState '%s' is wrong type", args[0].getName()); + obj1.free(); + return; + } + + // transparency support: blend mode, fill/stroke opacity + if (!obj1.dictLookup("BM", &obj2)->isNull()) { + if (state->parseBlendMode(&obj2, &mode)) { + state->setBlendMode(mode); + out->updateBlendMode(state); + } else { + error(getPos(), "Invalid blend mode in ExtGState"); + } + } + obj2.free(); + 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(); + + // fill/stroke overprint + if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) { + state->setFillOverprint(obj2.getBool()); + out->updateFillOverprint(state); + } + obj2.free(); + if (obj1.dictLookup("OP", &obj2)->isBool()) { + state->setStrokeOverprint(obj2.getBool()); + out->updateStrokeOverprint(state); + if (!haveFillOP) { + state->setFillOverprint(obj2.getBool()); + out->updateFillOverprint(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()); + out->updateFillColorSpace(state); + color.c[0] = dblToCol(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()); + out->updateStrokeColorSpace(state); + color.c[0] = dblToCol(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()); + out->updateFillColorSpace(state); + for (i = 0; i < 4; ++i) { + color.c[i] = dblToCol(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()); + out->updateStrokeColorSpace(state); + for (i = 0; i < 4; ++i) { + color.c[i] = dblToCol(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()); + out->updateFillColorSpace(state); + for (i = 0; i < 3; ++i) { + color.c[i] = dblToCol(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()); + out->updateStrokeColorSpace(state); + for (i = 0; i < 3; ++i) { + color.c[i] = dblToCol(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); + out->updateFillColorSpace(state); + } 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); + out->updateStrokeColorSpace(state); + } 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] = dblToCol(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] = dblToCol(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] = dblToCol(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] = dblToCol(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] = dblToCol(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] = dblToCol(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->isCurPt()) { + 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) { + GfxPattern *pattern; + + // this is a bit of a kludge -- patterns can be really slow, so we + // skip them if we're only doing text extraction, since they almost + // certainly don't contain any text + if (!out->needNonText()) { + return; + } + + if (!(pattern = state->getFillPattern())) { + return; + } + switch (pattern->getType()) { + case 1: + doTilingPatternFill((GfxTilingPattern *)pattern, eoFill); + break; + case 2: + doShadingPatternFill((GfxShadingPattern *)pattern, eoFill); + break; + default: + error(getPos(), "Unimplemented pattern type (%d) in fill", + pattern->getType()); + break; + } +} + +void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { + GfxPatternColorSpace *patCS; + GfxColorSpace *cs; + GfxPath *savedPath; + 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], imb[6]; + double det; + double xstep, ystep; + int i; + + // get color space + patCS = (GfxPatternColorSpace *)state->getFillColorSpace(); + + // 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 (device 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 + savedPath = state->getPath()->copy(); + saveState(); + + // set underlying color space (for uncolored tiling patterns); set + // various other parameters (stroke color, line width) to match + // Adobe's behavior + if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { + state->setFillColorSpace(cs->copy()); + out->updateFillColorSpace(state); + state->setStrokeColorSpace(cs->copy()); + out->updateStrokeColorSpace(state); + state->setStrokeColor(state->getFillColor()); + } else { + state->setFillColorSpace(new GfxDeviceGrayColorSpace()); + out->updateFillColorSpace(state); + state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); + out->updateStrokeColorSpace(state); + } + state->setFillPattern(NULL); + out->updateFillColor(state); + state->setStrokePattern(NULL); + out->updateStrokeColor(state); + state->setLineWidth(0); + out->updateLineWidth(state); + + // clip to current path + state->clip(); + if (eoFill) { + out->eoClip(state); + } else { + out->clip(state); + } + state->clearPath(); + + // get the clip region, check for empty + state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); + if (cxMin > cxMax || cyMin > cyMax) { + goto err; + } + + // transform clip region bbox to pattern space + 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 - tPat->getBBox()[0]) / xstep); + xi1 = (int)ceil((xMax - tPat->getBBox()[0]) / xstep); + yi0 = (int)floor((yMin - tPat->getBBox()[1]) / ystep); + yi1 = (int)ceil((yMax - tPat->getBBox()[1]) / ystep); + for (i = 0; i < 4; ++i) { + m1[i] = m[i]; + } + if (out->useTilingPatternFill()) { + m1[4] = m[4]; + m1[5] = m[5]; + out->tilingPatternFill(state, tPat->getContentStream(), + tPat->getPaintType(), tPat->getResDict(), + m1, tPat->getBBox(), + xi0, yi0, xi1, yi1, xstep, ystep); + } else { + 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 + err: + restoreState(); + state->setPath(savedPath); +} + +void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { + GfxShading *shading; + GfxPath *savedPath; + double *ctm, *btm, *ptm; + double m[6], ictm[6], m1[6]; + double xMin, yMin, xMax, yMax; + double det; + + shading = sPat->getShading(); + + // save current graphics state + savedPath = state->getPath()->copy(); + saveState(); + + // 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->setPath(savedPath->copy()); + } + + // clip to current path + state->clip(); + if (eoFill) { + out->eoClip(state); + } else { + out->clip(state); + } + + // set the color space + state->setFillColorSpace(shading->getColorSpace()->copy()); + out->updateFillColorSpace(state); + + // background color fill + if (shading->getHasBackground()) { + state->setFillColor(shading->getBackground()); + out->updateFillColor(state); + out->fill(state); + } + state->clearPath(); + + // construct a (pattern space) -> (current space) transform matrix + ctm = state->getCTM(); + btm = baseMatrix; + ptm = sPat->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]; + + // set the new matrix + state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]); + out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]); + + // do shading type-specific operations + switch (shading->getType()) { + case 1: + doFunctionShFill((GfxFunctionShading *)shading); + break; + case 2: + doAxialShFill((GfxAxialShading *)shading); + break; + case 3: + doRadialShFill((GfxRadialShading *)shading); + break; + case 4: + case 5: + doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); + break; + case 6: + case 7: + doPatchMeshShFill((GfxPatchMeshShading *)shading); + break; + } + + // restore graphics state + restoreState(); + state->setPath(savedPath); +} + +void Gfx::opShFill(Object args[], int numArgs) { + GfxShading *shading; + GfxPath *savedPath; + double xMin, yMin, xMax, yMax; + + if (!(shading = res->lookupShading(args[0].getName()))) { + return; + } + + // save current graphics state + savedPath = state->getPath()->copy(); + saveState(); + + // 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()); + out->updateFillColorSpace(state); + + // do shading type-specific operations + switch (shading->getType()) { + case 1: + doFunctionShFill((GfxFunctionShading *)shading); + break; + case 2: + doAxialShFill((GfxAxialShading *)shading); + break; + case 3: + doRadialShFill((GfxRadialShading *)shading); + break; + case 4: + case 5: + doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); + break; + case 6: + case 7: + doPatchMeshShFill((GfxPatchMeshShading *)shading); + break; + } + + // restore graphics state + restoreState(); + state->setPath(savedPath); + + delete shading; +} + +void Gfx::doFunctionShFill(GfxFunctionShading *shading) { + double x0, y0, x1, y1; + GfxColor colors[4]; + + if (out->useShadedFills()) { + out->functionShadedFill(state, shading); + } else { + shading->getDomain(&x0, &y0, &x1, &y1); + shading->getColor(x0, y0, &colors[0]); + shading->getColor(x0, y1, &colors[1]); + shading->getColor(x1, y0, &colors[2]); + shading->getColor(x1, y1, &colors[3]); + doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0); + } +} + +void Gfx::doFunctionShFill1(GfxFunctionShading *shading, + double x0, double y0, + double x1, double y1, + GfxColor *colors, int depth) { + GfxColor fillColor; + GfxColor color0M, color1M, colorM0, colorM1, colorMM; + GfxColor colors2[4]; + double *matrix; + double xM, yM; + int nComps, i, j; + + nComps = shading->getColorSpace()->getNComps(); + matrix = shading->getMatrix(); + + // compare the four corner colors + for (i = 0; i < 4; ++i) { + for (j = 0; j < nComps; ++j) { + if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) { + break; + } + } + if (j < nComps) { + break; + } + } + + // center of the rectangle + xM = 0.5 * (x0 + x1); + yM = 0.5 * (y0 + y1); + + // the four corner colors are close (or we hit the recursive limit) + // -- fill the rectangle; but require at least one subdivision + // (depth==0) to avoid problems when the four outer corners of the + // shaded region are the same color + if ((i == 4 && depth > 0) || depth == functionMaxDepth) { + + // use the center color + shading->getColor(xM, yM, &fillColor); + state->setFillColor(&fillColor); + out->updateFillColor(state); + + // fill the rectangle + state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4], + x0 * matrix[1] + y0 * matrix[3] + matrix[5]); + state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4], + x1 * matrix[1] + y0 * matrix[3] + matrix[5]); + state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4], + x1 * matrix[1] + y1 * matrix[3] + matrix[5]); + state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4], + x0 * matrix[1] + y1 * matrix[3] + matrix[5]); + state->closePath(); + out->fill(state); + state->clearPath(); + + // the four corner colors are not close enough -- subdivide the + // rectangle + } else { + + // colors[0] colorM0 colors[2] + // (x0,y0) (xM,y0) (x1,y0) + // +----------+----------+ + // | | | + // | UL | UR | + // color0M | colorMM | color1M + // (x0,yM) +----------+----------+ (x1,yM) + // | (xM,yM) | + // | LL | LR | + // | | | + // +----------+----------+ + // colors[1] colorM1 colors[3] + // (x0,y1) (xM,y1) (x1,y1) + + shading->getColor(x0, yM, &color0M); + shading->getColor(x1, yM, &color1M); + shading->getColor(xM, y0, &colorM0); + shading->getColor(xM, y1, &colorM1); + shading->getColor(xM, yM, &colorMM); + + // upper-left sub-rectangle + colors2[0] = colors[0]; + colors2[1] = color0M; + colors2[2] = colorM0; + colors2[3] = colorMM; + doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1); + + // lower-left sub-rectangle + colors2[0] = color0M; + colors2[1] = colors[1]; + colors2[2] = colorMM; + colors2[3] = colorM1; + doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1); + + // upper-right sub-rectangle + colors2[0] = colorM0; + colors2[1] = colorMM; + colors2[2] = colors[2]; + colors2[3] = color1M; + doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1); + + // lower-right sub-rectangle + colors2[0] = colorMM; + colors2[1] = colorM1; + colors2[2] = color1M; + colors2[3] = colors[3]; + doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1); + } +} + +void Gfx::doAxialShFill(GfxAxialShading *shading) { + double xMin, yMin, xMax, yMax; + double x0, y0, x1, y1; + double dx, dy, mul; + GBool dxZero, dyZero; + 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; + + if (out->useShadedFills()) { + + out->axialShadedFill(state, shading); + + } else { + + // get the clip region bbox + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + + // 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; + dxZero = fabs(dx) < 0.001; + dyZero = fabs(dy) < 0.001; + 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: require at least one split to avoid problems when the two + // ends of the t axis have the same color + nComps = shading->getColorSpace()->getNComps(); + ta[0] = tMin; + next[0] = axialMaxSplits / 2; + ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax); + next[axialMaxSplits / 2] = axialMaxSplits; + ta[axialMaxSplits] = tMax; + + // 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 (dxZero && dyZero) { + sMin = sMax = 0; + } if (dxZero) { + sMin = (xMin - tx) / -dy; + sMax = (xMax - tx) / -dy; + if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } + } else if (dyZero) { + 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 (abs(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] = (color0.c[k] + color1.c[k]) / 2; + } + + // 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 (dxZero && dyZero) { + sMin = sMax = 0; + } if (dxZero) { + sMin = (xMin - tx) / -dy; + sMax = (xMax - tx) / -dy; + if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } + } else if (dyZero) { + 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::doRadialShFill(GfxRadialShading *shading) { + double sMin, sMax, xMin, yMin, xMax, yMax; + double x0, y0, r0, x1, y1, r1, t0, t1; + int nComps; + GfxColor colorA, colorB; + double xa, ya, xb, yb, ra, rb; + double ta, tb, sa, sb; + int ia, ib, k, n; + double *ctm; + double angle, t, d0, d1; + + if (out->useShadedFills()) { + + out->radialShadedFill(state, shading); + + } else { + + // get the shading info + shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); + t0 = shading->getDomain0(); + t1 = shading->getDomain1(); + nComps = shading->getColorSpace()->getNComps(); + + // compute the (possibly extended) s range + sMin = 0; + sMax = 1; + if (shading->getExtend0()) { + if (r0 < r1) { + // extend the smaller end + sMin = -r0 / (r1 - r0); + } else { + // extend the larger end + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + d0 = (x0 - xMin) * (x0 - xMin); + d1 = (x0 - xMax) * (x0 - xMax); + sMin = d0 > d1 ? d0 : d1; + d0 = (y0 - yMin) * (y0 - yMin); + d1 = (y0 - yMax) * (y0 - yMax); + sMin += d0 > d1 ? d0 : d1; + sMin = (sqrt(sMin) - r0) / (r1 - r0); + if (sMin > 0) { + sMin = 0; + } else if (sMin < -20) { + // sanity check + sMin = -20; + } + } + } + if (shading->getExtend1()) { + if (r1 < r0) { + // extend the smaller end + sMax = -r0 / (r1 - r0); + } else if (r1 > r0) { + // extend the larger end + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + d0 = (x1 - xMin) * (x1 - xMin); + d1 = (x1 - xMax) * (x1 - xMax); + sMax = d0 > d1 ? d0 : d1; + d0 = (y1 - yMin) * (y1 - yMin); + d1 = (y1 - yMax) * (y1 - yMax); + sMax += d0 > d1 ? d0 : d1; + sMax = (sqrt(sMax) - r0) / (r1 - r0); + if (sMax < 1) { + sMax = 1; + } else if (sMax > 20) { + // sanity check + sMax = 20; + } + } + } + + // compute the number of steps into which circles must be divided to + // achieve a curve flatness of 0.1 pixel in device space for the + // largest circle (note that "device space" is 72 dpi when generating + // PostScript, hence the relatively small 0.1 pixel accuracy) + ctm = state->getCTM(); + t = fabs(ctm[0]); + if (fabs(ctm[1]) > t) { + t = fabs(ctm[1]); + } + if (fabs(ctm[2]) > t) { + t = fabs(ctm[2]); + } + if (fabs(ctm[3]) > t) { + t = fabs(ctm[3]); + } + if (r0 > r1) { + t *= r0; + } else { + t *= r1; + } + if (t < 1) { + n = 3; + } else { + n = (int)(M_PI / acos(1 - 0.1 / t)); + if (n < 3) { + n = 3; + } else if (n > 200) { + n = 200; + } + } + + // Traverse the t axis and do the shading. + // + // This generates and fills a series of rings. Each ring is defined + // by two circles: + // sa, ta, xa, ya, ra, colorA + // sb, tb, xb, yb, rb, colorB + // + // The s/t axis is divided into radialMaxSplits parts; these parts + // are combined as much as possible while respecting the + // radialColorDelta parameter. + + // setup for the start circle + ia = 0; + sa = sMin; + ta = t0 + sa * (t1 - t0); + xa = x0 + sa * (x1 - x0); + ya = y0 + sa * (y1 - y0); + ra = r0 + sa * (r1 - r0); + if (ta < t0) { + shading->getColor(t0, &colorA); + } else if (ta > t1) { + shading->getColor(t1, &colorA); + } else { + shading->getColor(ta, &colorA); + } + + while (ia < radialMaxSplits) { + + // go as far along the t axis (toward t1) as we can, such that the + // color difference is within the tolerance (radialColorDelta) -- + // this uses bisection (between the current value, t, and t1), + // limited to radialMaxSplits points along the t axis; require at + // least one split to avoid problems when the innermost and + // outermost colors are the same + ib = radialMaxSplits; + sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin); + tb = t0 + sb * (t1 - t0); + if (tb < t0) { + shading->getColor(t0, &colorB); + } else if (tb > t1) { + shading->getColor(t1, &colorB); + } else { + shading->getColor(tb, &colorB); + } + while (ib - ia > 1) { + for (k = 0; k < nComps; ++k) { + if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { + break; + } + } + if (k == nComps && ib < radialMaxSplits) { + break; + } + ib = (ia + ib) / 2; + sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin); + tb = t0 + sb * (t1 - t0); + if (tb < t0) { + shading->getColor(t0, &colorB); + } else if (tb > t1) { + shading->getColor(t1, &colorB); + } else { + shading->getColor(tb, &colorB); + } + } + + // compute center and radius of the circle + xb = x0 + sb * (x1 - x0); + yb = y0 + sb * (y1 - y0); + rb = r0 + sb * (r1 - r0); + + // use the average of the colors at the two circles + for (k = 0; k < nComps; ++k) { + colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2; + } + state->setFillColor(&colorA); + out->updateFillColor(state); + + // construct path for first circle + state->moveTo(xa + ra, ya); + for (k = 1; k < n; ++k) { + angle = ((double)k / (double)n) * 2 * M_PI; + state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); + } + state->closePath(); + + // construct and append path for second circle + state->moveTo(xb + rb, yb); + for (k = 1; k < n; ++k) { + angle = ((double)k / (double)n) * 2 * M_PI; + state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); + } + state->closePath(); + + // fill the ring + out->eoFill(state); + state->clearPath(); + + // step to the next value of t + ia = ib; + sa = sb; + ta = tb; + xa = xb; + ya = yb; + ra = rb; + colorA = colorB; + } + } +} + +void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) { + double x0, y0, x1, y1, x2, y2; + GfxColor color0, color1, color2; + int i; + + for (i = 0; i < shading->getNTriangles(); ++i) { + shading->getTriangle(i, &x0, &y0, &color0, + &x1, &y1, &color1, + &x2, &y2, &color2); + gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2, + shading->getColorSpace()->getNComps(), 0); + } +} + +void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0, + double x1, double y1, GfxColor *color1, + double x2, double y2, GfxColor *color2, + int nComps, int depth) { + double x01, y01, x12, y12, x20, y20; + GfxColor color01, color12, color20; + int i; + + for (i = 0; i < nComps; ++i) { + if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta || + abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) { + break; + } + } + if (i == nComps || depth == gouraudMaxDepth) { + state->setFillColor(color0); + out->updateFillColor(state); + state->moveTo(x0, y0); + state->lineTo(x1, y1); + state->lineTo(x2, y2); + state->closePath(); + out->fill(state); + state->clearPath(); + } else { + x01 = 0.5 * (x0 + x1); + y01 = 0.5 * (y0 + y1); + x12 = 0.5 * (x1 + x2); + y12 = 0.5 * (y1 + y2); + x20 = 0.5 * (x2 + x0); + y20 = 0.5 * (y2 + y0); + //~ if the shading has a Function, this should interpolate on the + //~ function parameter, not on the color components + for (i = 0; i < nComps; ++i) { + color01.c[i] = (color0->c[i] + color1->c[i]) / 2; + color12.c[i] = (color1->c[i] + color2->c[i]) / 2; + color20.c[i] = (color2->c[i] + color0->c[i]) / 2; + } + gouraudFillTriangle(x0, y0, color0, x01, y01, &color01, + x20, y20, &color20, nComps, depth + 1); + gouraudFillTriangle(x01, y01, &color01, x1, y1, color1, + x12, y12, &color12, nComps, depth + 1); + gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12, + x20, y20, &color20, nComps, depth + 1); + gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12, + x2, y2, color2, nComps, depth + 1); + } +} + +void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) { + int start, i; + + if (shading->getNPatches() > 128) { + start = 3; + } else if (shading->getNPatches() > 64) { + start = 2; + } else if (shading->getNPatches() > 16) { + start = 1; + } else { + start = 0; + } + for (i = 0; i < shading->getNPatches(); ++i) { + fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(), + start); + } +} + +void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) { + GfxPatch patch00, patch01, patch10, patch11; + double xx[4][8], yy[4][8]; + double xxm, yym; + int i; + + for (i = 0; i < nComps; ++i) { + if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i]) + > patchColorDelta || + abs(patch->color[0][1].c[i] - patch->color[1][1].c[i]) + > patchColorDelta || + abs(patch->color[1][1].c[i] - patch->color[1][0].c[i]) + > patchColorDelta || + abs(patch->color[1][0].c[i] - patch->color[0][0].c[i]) + > patchColorDelta) { + break; + } + } + if (i == nComps || depth == patchMaxDepth) { + state->setFillColor(&patch->color[0][0]); + out->updateFillColor(state); + state->moveTo(patch->x[0][0], patch->y[0][0]); + state->curveTo(patch->x[0][1], patch->y[0][1], + patch->x[0][2], patch->y[0][2], + patch->x[0][3], patch->y[0][3]); + state->curveTo(patch->x[1][3], patch->y[1][3], + patch->x[2][3], patch->y[2][3], + patch->x[3][3], patch->y[3][3]); + state->curveTo(patch->x[3][2], patch->y[3][2], + patch->x[3][1], patch->y[3][1], + patch->x[3][0], patch->y[3][0]); + state->curveTo(patch->x[2][0], patch->y[2][0], + patch->x[1][0], patch->y[1][0], + patch->x[0][0], patch->y[0][0]); + state->closePath(); + out->fill(state); + state->clearPath(); + } else { + for (i = 0; i < 4; ++i) { + xx[i][0] = patch->x[i][0]; + yy[i][0] = patch->y[i][0]; + xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]); + yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]); + xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]); + yym = 0.5 * (patch->y[i][1] + patch->y[i][2]); + xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]); + yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]); + xx[i][2] = 0.5 * (xx[i][1] + xxm); + yy[i][2] = 0.5 * (yy[i][1] + yym); + xx[i][5] = 0.5 * (xxm + xx[i][6]); + yy[i][5] = 0.5 * (yym + yy[i][6]); + xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]); + yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]); + xx[i][7] = patch->x[i][3]; + yy[i][7] = patch->y[i][3]; + } + for (i = 0; i < 4; ++i) { + patch00.x[0][i] = xx[0][i]; + patch00.y[0][i] = yy[0][i]; + patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]); + patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]); + xxm = 0.5 * (xx[1][i] + xx[2][i]); + yym = 0.5 * (yy[1][i] + yy[2][i]); + patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]); + patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]); + patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm); + patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym); + patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]); + patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]); + patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]); + patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]); + patch10.x[0][i] = patch00.x[3][i]; + patch10.y[0][i] = patch00.y[3][i]; + patch10.x[3][i] = xx[3][i]; + patch10.y[3][i] = yy[3][i]; + } + for (i = 4; i < 8; ++i) { + patch01.x[0][i-4] = xx[0][i]; + patch01.y[0][i-4] = yy[0][i]; + patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]); + patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]); + xxm = 0.5 * (xx[1][i] + xx[2][i]); + yym = 0.5 * (yy[1][i] + yy[2][i]); + patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]); + patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]); + patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm); + patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym); + patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]); + patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]); + patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]); + patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]); + patch11.x[0][i-4] = patch01.x[3][i-4]; + patch11.y[0][i-4] = patch01.y[3][i-4]; + patch11.x[3][i-4] = xx[3][i]; + patch11.y[3][i-4] = yy[3][i]; + } + //~ if the shading has a Function, this should interpolate on the + //~ function parameter, not on the color components + for (i = 0; i < nComps; ++i) { + patch00.color[0][0].c[i] = patch->color[0][0].c[i]; + patch00.color[0][1].c[i] = (patch->color[0][0].c[i] + + patch->color[0][1].c[i]) / 2; + patch01.color[0][0].c[i] = patch00.color[0][1].c[i]; + patch01.color[0][1].c[i] = patch->color[0][1].c[i]; + patch01.color[1][1].c[i] = (patch->color[0][1].c[i] + + patch->color[1][1].c[i]) / 2; + patch11.color[0][1].c[i] = patch01.color[1][1].c[i]; + patch11.color[1][1].c[i] = patch->color[1][1].c[i]; + patch11.color[1][0].c[i] = (patch->color[1][1].c[i] + + patch->color[1][0].c[i]) / 2; + patch10.color[1][1].c[i] = patch11.color[1][0].c[i]; + patch10.color[1][0].c[i] = patch->color[1][0].c[i]; + patch10.color[0][0].c[i] = (patch->color[1][0].c[i] + + patch->color[0][0].c[i]) / 2; + patch00.color[1][0].c[i] = patch10.color[0][0].c[i]; + patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] + + patch01.color[1][1].c[i]) / 2; + patch01.color[1][0].c[i] = patch00.color[1][1].c[i]; + patch11.color[0][0].c[i] = patch00.color[1][1].c[i]; + patch10.color[0][1].c[i] = patch00.color[1][1].c[i]; + } + fillPatch(&patch00, nComps, depth + 1); + fillPatch(&patch10, nComps, depth + 1); + fillPatch(&patch01, nComps, depth + 1); + fillPatch(&patch11, nComps, depth + 1); + } +} + +void Gfx::doEndPath() { + if (state->isCurPt() && 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) { + out->endTextObject(state); +} + +//------------------------------------------------------------------------ +// 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: tag=%s name='%s' %g\n", + font->getTag()->getCString(), + 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; + } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + out->beginStringOp(state); + doShowText(args[0].getString()); + out->endStringOp(state); +} + +void Gfx::opMoveShowText(Object args[], int numArgs) { + double tx, ty; + + if (!state->getFont()) { + error(getPos(), "No font in move/show"); + return; + } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + tx = state->getLineX(); + ty = state->getLineY() - state->getLeading(); + state->textMoveTo(tx, ty); + out->updateTextPos(state); + out->beginStringOp(state); + doShowText(args[0].getString()); + out->endStringOp(state); +} + +void Gfx::opMoveSetShowText(Object args[], int numArgs) { + double tx, ty; + + if (!state->getFont()) { + error(getPos(), "No font in move/set/show"); + return; + } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + 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); + out->beginStringOp(state); + doShowText(args[2].getString()); + out->endStringOp(state); +} + +void Gfx::opShowSpaceText(Object args[], int numArgs) { + Array *a; + Object obj; + int wMode; + int i; + + if (!state->getFont()) { + error(getPos(), "No font in show/space"); + return; + } + if (fontChanged) { + out->updateFont(state); + fontChanged = gFalse; + } + out->beginStringOp(state); + wMode = state->getFont()->getWMode(); + a = args[0].getArray(); + for (i = 0; i < a->getLength(); ++i) { + a->get(i, &obj); + if (obj.isNum()) { + // this uses the absolute value of the font size to match + // Acrobat's behavior + if (wMode) { + state->textShift(0, -obj.getNum() * 0.001 * + fabs(state->getFontSize())); + } else { + state->textShift(-obj.getNum() * 0.001 * + fabs(state->getFontSize()), 0); + } + 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(); + } + out->endStringOp(state); +} + +void Gfx::doShowText(GString *s) { + GfxFont *font; + int wMode; + double riseX, riseY; + CharCode code; + Unicode u[8]; + double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, lineX, lineY; + double originX, originY, tOriginX, tOriginY; + double oldCTM[6], newCTM[6]; + double *mat; + Object charProc; + Dict *resDict; + Parser *oldParser; + char *p; + int len, n, uLen, nChars, nSpaces, i; + + font = state->getFont(); + wMode = font->getWMode(); + + if (out->useDrawChar()) { + out->beginString(state, s); + } + + // handle a Type 3 char + if (font->getType() == fontType3 && out->interpretType3Chars()) { + 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[1] *= state->getFontSize(); + newCTM[2] *= state->getFontSize(); + newCTM[3] *= state->getFontSize(); + newCTM[0] *= state->getHorizScaling(); + newCTM[2] *= state->getHorizScaling(); + state->textTransformDelta(0, state->getRise(), &riseX, &riseY); + curX = state->getCurX(); + curY = state->getCurY(); + lineX = state->getLineX(); + lineY = state->getLineY(); + oldParser = parser; + p = s->getCString(); + len = s->getLength(); + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx, &dy, &originX, &originY); + dx = dx * state->getFontSize() + state->getCharSpace(); + if (n == 1 && *p == ' ') { + dx += state->getWordSpace(); + } + dx *= state->getHorizScaling(); + dy *= state->getFontSize(); + state->textTransformDelta(dx, dy, &tdx, &tdy); + state->transform(curX + riseX, curY + riseY, &x, &y); + saveState(); + state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); + //~ out->updateCTM(???) + if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy, + code, u, uLen)) { + ((Gfx8BitFont *)font)->getCharProc(code, &charProc); + if ((resDict = ((Gfx8BitFont *)font)->getResources())) { + pushResources(resDict); + } + if (charProc.isStream()) { + display(&charProc, gFalse); + } else { + error(getPos(), "Missing or bad Type3 CharProc entry"); + } + out->endType3Char(state); + if (resDict) { + popResources(); + } + charProc.free(); + } + restoreState(); + // GfxState::restore() does *not* restore the current position, + // so we deal with it here using (curX, curY) and (lineX, lineY) + curX += tdx; + curY += tdy; + state->moveTo(curX, curY); + state->textSetPos(lineX, lineY); + p += n; + len -= n; + } + parser = oldParser; + + } else if (out->useDrawChar()) { + state->textTransformDelta(0, state->getRise(), &riseX, &riseY); + p = s->getCString(); + len = s->getLength(); + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx, &dy, &originX, &originY); + if (wMode) { + dx *= state->getFontSize(); + dy = dy * state->getFontSize() + state->getCharSpace(); + if (n == 1 && *p == ' ') { + dy += state->getWordSpace(); + } + } else { + dx = dx * state->getFontSize() + state->getCharSpace(); + if (n == 1 && *p == ' ') { + dx += state->getWordSpace(); + } + dx *= state->getHorizScaling(); + dy *= state->getFontSize(); + } + state->textTransformDelta(dx, dy, &tdx, &tdy); + originX *= state->getFontSize(); + originY *= state->getFontSize(); + state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); + out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, + tdx, tdy, tOriginX, tOriginY, code, n, u, uLen); + state->shift(tdx, tdy); + p += n; + len -= n; + } + + } else { + dx = dy = 0; + p = s->getCString(); + len = s->getLength(); + nChars = nSpaces = 0; + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx2, &dy2, &originX, &originY); + dx += dx2; + dy += dy2; + if (n == 1 && *p == ' ') { + ++nSpaces; + } + ++nChars; + p += n; + len -= n; + } + if (wMode) { + dx *= state->getFontSize(); + dy = dy * state->getFontSize() + + nChars * state->getCharSpace() + + nSpaces * state->getWordSpace(); + } else { + dx = dx * state->getFontSize() + + nChars * state->getCharSpace() + + nSpaces * state->getWordSpace(); + dx *= state->getHorizScaling(); + dy *= state->getFontSize(); + } + state->textTransformDelta(dx, dy, &tdx, &tdy); + out->drawString(state, s); + state->shift(tdx, tdy); + } + + if (out->useDrawChar()) { + out->endString(state); + } + + updateLevel += 10 * s->getLength(); +} + +//------------------------------------------------------------------------ +// XObject operators +//------------------------------------------------------------------------ + +void Gfx::opXObject(Object args[], int numArgs) { + Object obj1, obj2, obj3, 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")) { + if (out->needNonText()) { + res->lookupXObjectNF(args[0].getName(), &refObj); + doImage(&refObj, obj1.getStream(), gFalse); + refObj.free(); + } + } else if (obj2.isName("Form")) { + doForm(&obj1); + } else if (obj2.isName("PS")) { + obj1.streamGetDict()->lookup("Level1", &obj3); + out->psXObject(obj1.getStream(), + obj3.isStream() ? obj3.getStream() : (Stream *)NULL); + } 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, *maskDict; + int width, height; + int bits, maskBits; + StreamColorSpaceMode csMode; + GBool mask; + GBool invert; + GfxColorSpace *colorSpace, *maskColorSpace; + GfxImageColorMap *colorMap, *maskColorMap; + Object maskObj, smaskObj; + GBool haveColorKeyMask, haveExplicitMask, haveSoftMask; + int maskColors[2*gfxColorMaxComps]; + int maskWidth, maskHeight; + GBool maskInvert; + Stream *maskStr; + Object obj1, obj2; + int i; + + // get info from the stream + bits = 0; + csMode = streamCSNone; + str->getImageParams(&bits, &csMode); + + // 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 + if (bits == 0) { + dict->lookup("BitsPerComponent", &obj1); + if (obj1.isNull()) { + obj1.free(); + dict->lookup("BPC", &obj1); + } + if (obj1.isInt()) { + bits = obj1.getInt(); + } else if (mask) { + bits = 1; + } else { + goto err2; + } + 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(); + } + } + if (!obj1.isNull()) { + colorSpace = GfxColorSpace::parse(&obj1); + } else if (csMode == streamCSDeviceGray) { + colorSpace = new GfxDeviceGrayColorSpace(); + } else if (csMode == streamCSDeviceRGB) { + colorSpace = new GfxDeviceRGBColorSpace(); + } else if (csMode == streamCSDeviceCMYK) { + colorSpace = new GfxDeviceCMYKColorSpace(); + } else { + colorSpace = NULL; + } + 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 + haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse; + maskStr = NULL; // make gcc happy + maskWidth = maskHeight = 0; // make gcc happy + maskInvert = gFalse; // make gcc happy + maskColorMap = NULL; // make gcc happy + dict->lookup("Mask", &maskObj); + dict->lookup("SMask", &smaskObj); + if (smaskObj.isStream()) { + // soft mask + if (inlineImg) { + goto err1; + } + maskStr = smaskObj.getStream(); + maskDict = smaskObj.streamGetDict(); + maskDict->lookup("Width", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("W", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskWidth = obj1.getInt(); + obj1.free(); + maskDict->lookup("Height", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("H", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskHeight = obj1.getInt(); + obj1.free(); + maskDict->lookup("BitsPerComponent", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("BPC", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskBits = obj1.getInt(); + obj1.free(); + maskDict->lookup("ColorSpace", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("CS", &obj1); + } + if (obj1.isName()) { + res->lookupColorSpace(obj1.getName(), &obj2); + if (!obj2.isNull()) { + obj1.free(); + obj1 = obj2; + } else { + obj2.free(); + } + } + maskColorSpace = GfxColorSpace::parse(&obj1); + obj1.free(); + if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) { + goto err1; + } + maskDict->lookup("Decode", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("D", &obj1); + } + maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace); + obj1.free(); + if (!maskColorMap->isOk()) { + delete maskColorMap; + goto err1; + } + //~ handle the Matte entry + haveSoftMask = gTrue; + } else if (maskObj.isArray()) { + // color key mask + for (i = 0; + i < maskObj.arrayGetLength() && i < 2*gfxColorMaxComps; + ++i) { + maskObj.arrayGet(i, &obj1); + maskColors[i] = obj1.getInt(); + obj1.free(); + } + haveColorKeyMask = gTrue; + } else if (maskObj.isStream()) { + // explicit mask + if (inlineImg) { + goto err1; + } + maskStr = maskObj.getStream(); + maskDict = maskObj.streamGetDict(); + maskDict->lookup("Width", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("W", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskWidth = obj1.getInt(); + obj1.free(); + maskDict->lookup("Height", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("H", &obj1); + } + if (!obj1.isInt()) { + goto err2; + } + maskHeight = obj1.getInt(); + obj1.free(); + maskDict->lookup("ImageMask", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("IM", &obj1); + } + if (!obj1.isBool() || !obj1.getBool()) { + goto err2; + } + obj1.free(); + maskInvert = gFalse; + maskDict->lookup("Decode", &obj1); + if (obj1.isNull()) { + obj1.free(); + maskDict->lookup("D", &obj1); + } + if (obj1.isArray()) { + obj1.arrayGet(0, &obj2); + if (obj2.isInt() && obj2.getInt() == 1) { + maskInvert = gTrue; + } + obj2.free(); + } else if (!obj1.isNull()) { + goto err2; + } + obj1.free(); + haveExplicitMask = gTrue; + } + + // draw it + if (haveSoftMask) { + out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskColorMap); + delete maskColorMap; + } else if (haveExplicitMask) { + out->drawMaskedImage(state, ref, str, width, height, colorMap, + maskStr, maskWidth, maskHeight, maskInvert); + } else { + out->drawImage(state, ref, str, width, height, colorMap, + haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); + } + delete colorMap; + + maskObj.free(); + smaskObj.free(); + } + + if ((i = width * height) > 1000) { + i = 1000; + } + updateLevel += i; + + 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; + + // check for excessive recursion + if (formDepth > 20) { + return; + } + + // get stream dict + dict = str->streamGetDict(); + + // check form type + dict->lookup("FormType", &obj1); + if (!(obj1.isNull() || (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 + ++formDepth; + doForm1(str, resDict, m, bbox); + --formDepth; + + resObj.free(); +} + +void Gfx::doAnnot(Object *str, double xMin, double yMin, + double xMax, double yMax) { + Dict *dict, *resDict; + Object matrixObj, bboxObj, resObj, flagsObj; + Object obj1; + double m[6], bbox[6], ictm[6]; + double *ctm; + double formX0, formY0, formX1, formY1; + double annotX0, annotY0, annotX1, annotY1; + double det, x, y, sx, sy; + int i, flags; + + // get stream dict + dict = str->streamGetDict(); + + // get annotation flags and only print annotations that are hidden or + // don't have the print bit set. + dict->lookup("F", &flagsObj); + if (flagsObj.isInt()) { + flags = flagsObj.getInt(); + } else { + // Print anything that doesn't have any flags set... + flags = 4; + } + flagsObj.free(); + + fprintf(stderr, "DEBUG: pdftops: doAnnot found annotation with flags = %x\n", + flags); + + if ((flags & 2) == 2 || (flags & 4) == 0) { + // Don't print hidden or no-print annotations... + return; + } + + // get the form 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 the form 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(); + + // transform the form bbox from form space to user space + formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; + formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5]; + formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; + formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5]; + + // transform the annotation bbox from default user space to user + // space: (bbox * baseMatrix) * iCTM + 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; + x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4]; + y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5]; + annotX0 = ictm[0] * x + ictm[2] * y + ictm[4]; + annotY0 = ictm[1] * x + ictm[3] * y + ictm[5]; + x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4]; + y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5]; + annotX1 = ictm[0] * x + ictm[2] * y + ictm[4]; + annotY1 = ictm[1] * x + ictm[3] * y + ictm[5]; + + // swap min/max coords + if (formX0 > formX1) { + x = formX0; formX0 = formX1; formX1 = x; + } + if (formY0 > formY1) { + y = formY0; formY0 = formY1; formY1 = y; + } + if (annotX0 > annotX1) { + x = annotX0; annotX0 = annotX1; annotX1 = x; + } + if (annotY0 > annotY1) { + y = annotY0; annotY0 = annotY1; annotY1 = y; + } + + // scale the form to fit the annotation bbox + if (formX1 == formX0) { + // this shouldn't happen + sx = 1; + } else { + sx = (annotX1 - annotX0) / (formX1 - formX0); + } + if (formY1 == formY0) { + // this shouldn't happen + sy = 1; + } else { + sy = (annotY1 - annotY0) / (formY1 - formY0); + } + m[0] *= sx; + m[2] *= sx; + m[4] = (m[4] - formX0) * sx + annotX0; + m[1] *= sy; + m[3] *= sy; + m[5] = (m[5] - formY0) * sy + annotY0; + + // 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]; + int i; + + // push new resources on stack + pushResources(resDict); + + // save current graphics state + saveState(); + + // kill any pre-existing path + state->clearPath(); + + // 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 + restoreState(); + + // pop resource stack + popResources(); + + 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(); + } else { + key = copyString(obj.getName()); + obj.free(); + parser->getObj(&obj); + if (obj.isEOF() || obj.isError()) { + gfree(key); + break; + } + dict.dictAdd(key, &obj); + } + parser->getObj(&obj); + } + if (obj.isEOF()) { + error(getPos(), "End of file in inline image"); + obj.free(); + dict.free(); + return NULL; + } + obj.free(); + + // make stream + str = new EmbedStream(parser->getStream(), &dict, gFalse, 0); + 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) { + out->type3D0(state, args[0].getNum(), args[1].getNum()); +} + +void Gfx::opSetCacheDevice(Object args[], int numArgs) { + out->type3D1(state, args[0].getNum(), args[1].getNum(), + args[2].getNum(), args[3].getNum(), + args[4].getNum(), args[5].getNum()); +} + +//------------------------------------------------------------------------ +// 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); + } +} + +//------------------------------------------------------------------------ +// misc +//------------------------------------------------------------------------ + +void Gfx::saveState() { + out->saveState(state); + state = state->save(); +} + +void Gfx::restoreState() { + state = state->restore(); + out->restoreState(state); +} + +void Gfx::pushResources(Dict *resDict) { + res = new GfxResources(xref, resDict, res); +} + +void Gfx::popResources() { + GfxResources *resPtr; + + resPtr = res->getNext(); + delete res; + res = resPtr; +} diff --git a/pdftops/Gfx.h b/pdftops/Gfx.h new file mode 100644 index 000000000..04fdc9dec --- /dev/null +++ b/pdftops/Gfx.h @@ -0,0 +1,294 @@ +//======================================================================== +// +// Gfx.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GFX_H +#define GFX_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class GString; +class XRef; +class Array; +class Stream; +class Parser; +class Dict; +class OutputDev; +class GfxFontDict; +class GfxFont; +class GfxPattern; +class GfxTilingPattern; +class GfxShadingPattern; +class GfxShading; +class GfxFunctionShading; +class GfxAxialShading; +class GfxRadialShading; +class GfxGouraudTriangleShading; +class GfxPatchMeshShading; +struct GfxPatch; +class GfxState; +struct GfxColor; +class Gfx; +class 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 hDPI, double vDPI, PDFRectangle *box, + PDFRectangle *cropBox, int rotate, + GBool (*abortCheckCbkA)(void *data) = NULL, + void *abortCheckCbkDataA = NULL); + + // Constructor for a sub-page object. + Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict, + PDFRectangle *box, PDFRectangle *cropBox, + GBool (*abortCheckCbkA)(void *data) = NULL, + void *abortCheckCbkDataA = NULL); + + ~Gfx(); + + // Interpret a stream or array of streams. + void display(Object *obj, GBool topLevel = gTrue); + + // Display an annotation, given its appearance (a Form XObject) and + // bounding box (in default user space). + void doAnnot(Object *str, double xMin, double yMin, + double xMax, double yMax); + + // Save graphics state. + void saveState(); + + // Restore graphics state. + void restoreState(); + + // Get the current graphics state object. + GfxState *getState() { return state; } + +private: + + XRef *xref; // the xref table for this PDF file + OutputDev *out; // output device + GBool subPage; // is this a sub-page object? + GBool printCommands; // print the drawing commands (for debugging) + GfxResources *res; // resource stack + int updateLevel; + + 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 + int formDepth; + + Parser *parser; // parser for page content stream(s) + + GBool // callback to check for an abort + (*abortCheckCbk)(void *data); + void *abortCheckCbkData; + GBool renderThisPage; // Render this page? + + 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 doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill); + void doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill); + void opShFill(Object args[], int numArgs); + void doFunctionShFill(GfxFunctionShading *shading); + void doFunctionShFill1(GfxFunctionShading *shading, + double x0, double y0, + double x1, double y1, + GfxColor *colors, int depth); + void doAxialShFill(GfxAxialShading *shading); + void doRadialShFill(GfxRadialShading *shading); + void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading); + void gouraudFillTriangle(double x0, double y0, GfxColor *color0, + double x1, double y1, GfxColor *color1, + double x2, double y2, GfxColor *color2, + int nComps, int depth); + void doPatchMeshShFill(GfxPatchMeshShading *shading); + void fillPatch(GfxPatch *patch, int nComps, int depth); + 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); + + // 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); + + void pushResources(Dict *resDict); + void popResources(); +}; + +#endif diff --git a/pdftops/GfxFont.cxx b/pdftops/GfxFont.cxx new file mode 100644 index 000000000..c567c8591 --- /dev/null +++ b/pdftops/GfxFont.cxx @@ -0,0 +1,1546 @@ +//======================================================================== +// +// GfxFont.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include "gmem.h" +#include "Error.h" +#include "Object.h" +#include "Dict.h" +#include "GlobalParams.h" +#include "CMap.h" +#include "CharCodeToUnicode.h" +#include "FontEncodingTables.h" +#include "BuiltinFontTables.h" +#include "FoFiType1.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" +#include "GfxFont.h" + +//------------------------------------------------------------------------ + +struct StdFontMapEntry { + char *altName; + char *properName; +}; + +// Acrobat 4.0 and earlier substituted Base14-compatible fonts without +// providing Widths and a FontDescriptor, so we munge the names into +// the proper Base14 names. This table is from implementation note 44 +// in the PDF 1.4 spec, with some additions based on empirical +// evidence. +static StdFontMapEntry stdFontMap[] = { + { "Arial", "Helvetica" }, + { "Arial,Bold", "Helvetica-Bold" }, + { "Arial,BoldItalic", "Helvetica-BoldOblique" }, + { "Arial,Italic", "Helvetica-Oblique" }, + { "Arial-Bold", "Helvetica-Bold" }, + { "Arial-BoldItalic", "Helvetica-BoldOblique" }, + { "Arial-BoldItalicMT", "Helvetica-BoldOblique" }, + { "Arial-BoldMT", "Helvetica-Bold" }, + { "Arial-Italic", "Helvetica-Oblique" }, + { "Arial-ItalicMT", "Helvetica-Oblique" }, + { "ArialMT", "Helvetica" }, + { "Courier,Bold", "Courier-Bold" }, + { "Courier,BoldItalic", "Courier-BoldOblique" }, + { "Courier,Italic", "Courier-Oblique" }, + { "CourierNew", "Courier" }, + { "CourierNew,Bold", "Courier-Bold" }, + { "CourierNew,BoldItalic", "Courier-BoldOblique" }, + { "CourierNew,Italic", "Courier-Oblique" }, + { "CourierNew-Bold", "Courier-Bold" }, + { "CourierNew-BoldItalic", "Courier-BoldOblique" }, + { "CourierNew-Italic", "Courier-Oblique" }, + { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" }, + { "CourierNewPS-BoldMT", "Courier-Bold" }, + { "CourierNewPS-ItalicMT", "Courier-Oblique" }, + { "CourierNewPSMT", "Courier" }, + { "Helvetica,Bold", "Helvetica-Bold" }, + { "Helvetica,BoldItalic", "Helvetica-BoldOblique" }, + { "Helvetica,Italic", "Helvetica-Oblique" }, + { "Helvetica-BoldItalic", "Helvetica-BoldOblique" }, + { "Helvetica-Italic", "Helvetica-Oblique" }, + { "Symbol,Bold", "Symbol" }, + { "Symbol,BoldItalic", "Symbol" }, + { "Symbol,Italic", "Symbol" }, + { "TimesNewRoman", "Times-Roman" }, + { "TimesNewRoman,Bold", "Times-Bold" }, + { "TimesNewRoman,BoldItalic", "Times-BoldItalic" }, + { "TimesNewRoman,Italic", "Times-Italic" }, + { "TimesNewRoman-Bold", "Times-Bold" }, + { "TimesNewRoman-BoldItalic", "Times-BoldItalic" }, + { "TimesNewRoman-Italic", "Times-Italic" }, + { "TimesNewRomanPS", "Times-Roman" }, + { "TimesNewRomanPS-Bold", "Times-Bold" }, + { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" }, + { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" }, + { "TimesNewRomanPS-BoldMT", "Times-Bold" }, + { "TimesNewRomanPS-Italic", "Times-Italic" }, + { "TimesNewRomanPS-ItalicMT", "Times-Italic" }, + { "TimesNewRomanPSMT", "Times-Roman" }, + { "TimesNewRomanPSMT,Bold", "Times-Bold" }, + { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" }, + { "TimesNewRomanPSMT,Italic", "Times-Italic" } +}; + +//------------------------------------------------------------------------ +// GfxFont +//------------------------------------------------------------------------ + +GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) { + GString *nameA; + GfxFont *font; + Object obj1; + + // get base font name + nameA = NULL; + fontDict->lookup("BaseFont", &obj1); + if (obj1.isName()) { + nameA = new GString(obj1.getName()); + } + obj1.free(); + + // get font type + font = NULL; + fontDict->lookup("Subtype", &obj1); + if (obj1.isName("Type1") || obj1.isName("MMType1")) { + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1, fontDict); + } else if (obj1.isName("Type1C")) { + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType1C, fontDict); + } else if (obj1.isName("Type3")) { + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontType3, fontDict); + } else if (obj1.isName("TrueType")) { + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontTrueType, fontDict); + } else if (obj1.isName("Type0")) { + font = new GfxCIDFont(xref, tagA, idA, nameA, fontDict); + } else { + error(-1, "Unknown font type: '%s'", + obj1.isName() ? obj1.getName() : "???"); + font = new Gfx8BitFont(xref, tagA, idA, nameA, fontUnknownType, fontDict); + } + obj1.free(); + + return font; +} + +GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) { + ok = gFalse; + tag = new GString(tagA); + id = idA; + name = nameA; + origName = nameA; + embFontName = NULL; + extFontFile = NULL; +} + +GfxFont::~GfxFont() { + delete tag; + if (origName && origName != name) { + delete origName; + } + if (name) { + delete name; + } + if (embFontName) { + delete embFontName; + } + if (extFontFile) { + delete extFontFile; + } +} + +void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { + Object obj1, obj2, obj3, obj4; + double t; + int i; + + // assume Times-Roman by default (for substitution purposes) + flags = fontSerif; + + embFontID.num = -1; + embFontID.gen = -1; + missingWidth = 0; + + if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) { + + // get flags + if (obj1.dictLookup("Flags", &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 (obj1.dictLookupNF("FontFile", &obj2)->isRef()) { + embFontID = obj2.getRef(); + if (type != fontType1) { + error(-1, "Mismatch between font type and embedded font file"); + type = fontType1; + } + } + obj2.free(); + if (embFontID.num == -1 && + obj1.dictLookupNF("FontFile2", &obj2)->isRef()) { + embFontID = obj2.getRef(); + if (type != fontTrueType && type != fontCIDType2) { + error(-1, "Mismatch between font type and embedded font file"); + type = type == fontCIDType0 ? fontCIDType2 : fontTrueType; + } + } + obj2.free(); + if (embFontID.num == -1 && + obj1.dictLookupNF("FontFile3", &obj2)->isRef()) { + if (obj2.fetch(xref, &obj3)->isStream()) { + obj3.streamGetDict()->lookup("Subtype", &obj4); + if (obj4.isName("Type1")) { + embFontID = obj2.getRef(); + if (type != fontType1) { + error(-1, "Mismatch between font type and embedded font file"); + type = fontType1; + } + } else if (obj4.isName("Type1C")) { + embFontID = obj2.getRef(); + if (type != fontType1 && type != fontType1C) { + error(-1, "Mismatch between font type and embedded font file"); + } + type = fontType1C; + } else if (obj4.isName("TrueType")) { + embFontID = obj2.getRef(); + if (type != fontTrueType) { + error(-1, "Mismatch between font type and embedded font file"); + type = fontTrueType; + } + } else if (obj4.isName("CIDFontType0C")) { + embFontID = obj2.getRef(); + if (type != fontCIDType0) { + error(-1, "Mismatch between font type and embedded font file"); + } + type = fontCIDType0C; + } else { + error(-1, "Unknown embedded font type '%s'", + obj4.isName() ? obj4.getName() : "???"); + } + obj4.free(); + } + obj3.free(); + } + obj2.free(); + + // look for MissingWidth + obj1.dictLookup("MissingWidth", &obj2); + if (obj2.isNum()) { + missingWidth = obj2.getNum(); + } + obj2.free(); + + // get Ascent and Descent + obj1.dictLookup("Ascent", &obj2); + if (obj2.isNum()) { + t = 0.001 * obj2.getNum(); + // some broken font descriptors set ascent and descent to 0 + if (t != 0) { + ascent = t; + } + } + obj2.free(); + obj1.dictLookup("Descent", &obj2); + if (obj2.isNum()) { + t = 0.001 * obj2.getNum(); + // some broken font descriptors set ascent and descent to 0 + if (t != 0) { + descent = t; + } + // some broken font descriptors specify a positive descent + if (descent > 0) { + descent = -descent; + } + } + obj2.free(); + + // font FontBBox + if (obj1.dictLookup("FontBBox", &obj2)->isArray()) { + for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + fontBBox[i] = 0.001 * obj3.getNum(); + } + obj3.free(); + } + } + obj2.free(); + + } + obj1.free(); +} + +CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, + CharCodeToUnicode *ctu) { + GString *buf; + Object obj1; + int c; + + if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) { + obj1.free(); + return NULL; + } + buf = new GString(); + obj1.streamReset(); + while ((c = obj1.streamGetChar()) != EOF) { + buf->append(c); + } + obj1.streamClose(); + obj1.free(); + if (ctu) { + ctu->mergeCMap(buf, nBits); + } else { + ctu = CharCodeToUnicode::parseCMap(buf, nBits); + } + delete buf; + return ctu; +} + +void GfxFont::findExtFontFile() { + static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL }; + static char *ttExts[] = { ".ttf", NULL }; + + if (name) { + if (type == fontType1) { + extFontFile = globalParams->findFontFile(name, type1Exts); + } else if (type == fontTrueType) { + extFontFile = globalParams->findFontFile(name, ttExts); + } + } +} + +char *GfxFont::readExtFontFile(int *len) { + FILE *f; + char *buf; + + if (!(f = fopen(extFontFile->getCString(), "rb"))) { + error(-1, "External font file '%s' vanished", extFontFile->getCString()); + 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->getCString()); + } + 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; +} + +//------------------------------------------------------------------------ +// Gfx8BitFont +//------------------------------------------------------------------------ + +Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + GfxFontType typeA, Dict *fontDict): + GfxFont(tagA, idA, nameA) +{ + GString *name2; + BuiltinFont *builtinFont; + char **baseEnc; + GBool baseEncFromFontFile; + char *buf; + int len; + FoFiType1 *ffT1; + FoFiType1C *ffT1C; + int code, code2; + char *charName; + GBool missing, hex; + Unicode toUnicode[256]; + CharCodeToUnicode *utu, *ctu2; + Unicode uBuf[8]; + double mul; + int firstChar, lastChar; + Gushort w; + Object obj1, obj2, obj3; + int n, i, a, b, m; + + type = typeA; + ctu = NULL; + + // do font name substitution for various aliases of the Base 14 font + // names + if (name) { + name2 = name->copy(); + i = 0; + while (i < name2->getLength()) { + if (name2->getChar(i) == ' ') { + name2->del(i); + } else { + ++i; + } + } + a = 0; + b = sizeof(stdFontMap) / sizeof(StdFontMapEntry); + // invariant: stdFontMap[a].altName <= name2 < stdFontMap[b].altName + while (b - a > 1) { + m = (a + b) / 2; + if (name2->cmp(stdFontMap[m].altName) >= 0) { + a = m; + } else { + b = m; + } + } + if (!name2->cmp(stdFontMap[a].altName)) { + name = new GString(stdFontMap[a].properName); + } + delete name2; + } + + // is it a built-in font? + builtinFont = NULL; + if (name) { + for (i = 0; i < nBuiltinFonts; ++i) { + if (!name->cmp(builtinFonts[i].name)) { + builtinFont = &builtinFonts[i]; + break; + } + } + } + + // default ascent/descent values + if (builtinFont) { + ascent = 0.001 * builtinFont->ascent; + descent = 0.001 * builtinFont->descent; + fontBBox[0] = 0.001 * builtinFont->bbox[0]; + fontBBox[1] = 0.001 * builtinFont->bbox[1]; + fontBBox[2] = 0.001 * builtinFont->bbox[2]; + fontBBox[3] = 0.001 * builtinFont->bbox[3]; + } else { + ascent = 0.95; + descent = -0.35; + fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; + } + + // get info from font descriptor + readFontDescriptor(xref, fontDict); + + // for non-embedded fonts, don't trust the ascent/descent/bbox + // values from the font descriptor + if (builtinFont && embFontID.num < 0) { + ascent = 0.001 * builtinFont->ascent; + descent = 0.001 * builtinFont->descent; + fontBBox[0] = 0.001 * builtinFont->bbox[0]; + fontBBox[1] = 0.001 * builtinFont->bbox[1]; + fontBBox[2] = 0.001 * builtinFont->bbox[2]; + fontBBox[3] = 0.001 * builtinFont->bbox[3]; + } + + // look for an external font file + 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 Type 3 bounding box, font definition, and resources + if (type == fontType3) { + if (fontDict->lookup("FontBBox", &obj1)->isArray()) { + for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + fontBBox[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) { + error(-1, "Missing or invalid CharProcs dictionary in Type 3 font"); + charProcs.free(); + } + if (!fontDict->lookup("Resources", &resources)->isDict()) { + resources.free(); + } + } + + //----- build the font encoding ----- + + // Encodings start with a base encoding, which can come from + // (in order of priority): + // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding + // - MacRoman / MacExpert / WinAnsi / Standard + // 2. embedded or external font file + // 3. default: + // - builtin --> builtin encoding + // - TrueType --> WinAnsiEncoding + // - others --> StandardEncoding + // and then add a list of differences (if any) from + // FontDict.Encoding.Differences. + + // check FontDict for base encoding + hasEncoding = gFalse; + usesMacRomanEnc = gFalse; + baseEnc = NULL; + baseEncFromFontFile = gFalse; + fontDict->lookup("Encoding", &obj1); + if (obj1.isDict()) { + obj1.dictLookup("BaseEncoding", &obj2); + if (obj2.isName("MacRomanEncoding")) { + hasEncoding = gTrue; + usesMacRomanEnc = gTrue; + baseEnc = macRomanEncoding; + } else if (obj2.isName("MacExpertEncoding")) { + hasEncoding = gTrue; + baseEnc = macExpertEncoding; + } else if (obj2.isName("WinAnsiEncoding")) { + hasEncoding = gTrue; + baseEnc = winAnsiEncoding; + } + obj2.free(); + } else if (obj1.isName("MacRomanEncoding")) { + hasEncoding = gTrue; + usesMacRomanEnc = gTrue; + baseEnc = macRomanEncoding; + } else if (obj1.isName("MacExpertEncoding")) { + hasEncoding = gTrue; + baseEnc = macExpertEncoding; + } else if (obj1.isName("WinAnsiEncoding")) { + hasEncoding = gTrue; + baseEnc = winAnsiEncoding; + } + + // check embedded or external font file for base encoding + // (only for Type 1 fonts - trying to get an encoding out of a + // TrueType font is a losing proposition) + ffT1 = NULL; + ffT1C = NULL; + buf = NULL; + if (type == fontType1 && (extFontFile || embFontID.num >= 0)) { + if (extFontFile) { + ffT1 = FoFiType1::load(extFontFile->getCString()); + } else { + buf = readEmbFontFile(xref, &len); + ffT1 = FoFiType1::make(buf, len); + } + if (ffT1) { + if (ffT1->getName()) { + if (embFontName) { + delete embFontName; + } + embFontName = new GString(ffT1->getName()); + } + if (!baseEnc) { + baseEnc = ffT1->getEncoding(); + baseEncFromFontFile = gTrue; + } + } + } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) { + if (extFontFile) { + ffT1C = FoFiType1C::load(extFontFile->getCString()); + } else { + buf = readEmbFontFile(xref, &len); + ffT1C = FoFiType1C::make(buf, len); + } + if (ffT1C) { + if (ffT1C->getName()) { + if (embFontName) { + delete embFontName; + } + embFontName = new GString(ffT1C->getName()); + } + if (!baseEnc) { + baseEnc = ffT1C->getEncoding(); + baseEncFromFontFile = gTrue; + } + } + } + if (buf) { + gfree(buf); + } + + // get default base encoding + if (!baseEnc) { + if (builtinFont && embFontID.num < 0) { + baseEnc = builtinFont->defaultBaseEnc; + hasEncoding = gTrue; + } else if (type == fontTrueType) { + baseEnc = winAnsiEncoding; + } else { + baseEnc = standardEncoding; + } + } + + // copy the base encoding + for (i = 0; i < 256; ++i) { + enc[i] = baseEnc[i]; + if ((encFree[i] = baseEncFromFontFile) && enc[i]) { + enc[i] = copyString(baseEnc[i]); + } + } + + // some Type 1C font files have empty encodings, which can break the + // T1C->T1 conversion (since the 'seac' operator depends on having + // the accents in the encoding), so we fill in any gaps from + // StandardEncoding + if (type == fontType1C && (extFontFile || embFontID.num >= 0) && + baseEncFromFontFile) { + for (i = 0; i < 256; ++i) { + if (!enc[i] && standardEncoding[i]) { + enc[i] = standardEncoding[i]; + encFree[i] = gFalse; + } + } + } + + // merge differences into encoding + if (obj1.isDict()) { + obj1.dictLookup("Differences", &obj2); + if (obj2.isArray()) { + hasEncoding = gTrue; + 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 >= 0 && code < 256) { + if (encFree[code]) { + gfree(enc[code]); + } + enc[code] = copyString(obj3.getName()); + encFree[code] = gTrue; + } + ++code; + } else { + error(-1, "Wrong type in font encoding resource differences (%s)", + obj3.getTypeName()); + } + obj3.free(); + } + } + obj2.free(); + } + obj1.free(); + if (ffT1) { + delete ffT1; + } + if (ffT1C) { + delete ffT1C; + } + + //----- build the mapping to Unicode ----- + + // pass 1: use the name-to-Unicode mapping table + missing = hex = gFalse; + for (code = 0; code < 256; ++code) { + if ((charName = enc[code])) { + if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) && + strcmp(charName, ".notdef")) { + // if it wasn't in the name-to-Unicode table, check for a + // name that looks like 'Axx' or 'xx', where 'A' is any letter + // and 'xx' is two hex digits + if ((strlen(charName) == 3 && + isalpha(charName[0]) && + isxdigit(charName[1]) && isxdigit(charName[2]) && + ((charName[1] >= 'a' && charName[1] <= 'f') || + (charName[1] >= 'A' && charName[1] <= 'F') || + (charName[2] >= 'a' && charName[2] <= 'f') || + (charName[2] >= 'A' && charName[2] <= 'F'))) || + (strlen(charName) == 2 && + isxdigit(charName[0]) && isxdigit(charName[1]) && + ((charName[0] >= 'a' && charName[0] <= 'f') || + (charName[0] >= 'A' && charName[0] <= 'F') || + (charName[1] >= 'a' && charName[1] <= 'f') || + (charName[1] >= 'A' && charName[1] <= 'F')))) { + hex = gTrue; + } + missing = gTrue; + } + } else { + toUnicode[code] = 0; + } + } + + // pass 2: try to fill in the missing chars, looking for names of + // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B' + // are any letters, 'xx' is two hex digits, and 'nn' is 2-4 + // decimal digits + if (missing && globalParams->getMapNumericCharNames()) { + for (code = 0; code < 256; ++code) { + if ((charName = enc[code]) && !toUnicode[code] && + strcmp(charName, ".notdef")) { + n = strlen(charName); + code2 = -1; + if (hex && n == 3 && isalpha(charName[0]) && + isxdigit(charName[1]) && isxdigit(charName[2])) { + sscanf(charName+1, "%x", &code2); + } else if (hex && n == 2 && + isxdigit(charName[0]) && isxdigit(charName[1])) { + sscanf(charName, "%x", &code2); + } else if (!hex && n >= 2 && n <= 4 && + isdigit(charName[0]) && isdigit(charName[1])) { + code2 = atoi(charName); + } else if (n >= 3 && n <= 5 && + isdigit(charName[1]) && isdigit(charName[2])) { + code2 = atoi(charName+1); + } else if (n >= 4 && n <= 6 && + isdigit(charName[2]) && isdigit(charName[3])) { + code2 = atoi(charName+2); + } + if (code2 >= 0 && code2 <= 0xff) { + toUnicode[code] = (Unicode)code2; + } + } + } + } + + // construct the char code -> Unicode mapping object + ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode); + + // merge in a ToUnicode CMap, if there is one -- this overwrites + // existing entries in ctu, i.e., the ToUnicode CMap takes + // precedence, but the other encoding info is allowed to fill in any + // holes + readToUnicodeCMap(fontDict, 8, ctu); + + // look for a Unicode-to-Unicode mapping + if (name && (utu = globalParams->getUnicodeToUnicode(name))) { + for (i = 0; i < 256; ++i) { + toUnicode[i] = 0; + } + ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode); + for (i = 0; i < 256; ++i) { + n = ctu->mapToUnicode((CharCode)i, uBuf, 8); + if (n >= 1) { + n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (n >= 1) { + ctu2->setMapping((CharCode)i, uBuf, n); + } + } + } + utu->decRefCnt(); + delete ctu; + ctu = ctu2; + } + + //----- get the character widths ----- + + // 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(); + if (firstChar < 0 || firstChar > 255) { + firstChar = 0; + } + fontDict->lookup("LastChar", &obj1); + lastChar = obj1.isInt() ? obj1.getInt() : 255; + obj1.free(); + if (lastChar < 0 || lastChar > 255) { + lastChar = 255; + } + mul = (type == fontType3) ? fontMat[0] : 0.001; + fontDict->lookup("Widths", &obj1); + if (obj1.isArray()) { + flags |= fontFixedWidth; + if (obj1.arrayGetLength() < lastChar - firstChar + 1) { + lastChar = firstChar + obj1.arrayGetLength() - 1; + } + for (code = firstChar; code <= lastChar; ++code) { + obj1.arrayGet(code - firstChar, &obj2); + if (obj2.isNum()) { + widths[code] = obj2.getNum() * mul; + if (widths[code] != widths[firstChar]) { + flags &= ~fontFixedWidth; + } + } + obj2.free(); + } + + // use widths from built-in font + } else if (builtinFont) { + // this is a kludge for broken PDF files that encode char 32 + // as .notdef + if (builtinFont->widths->getWidth("space", &w)) { + widths[32] = 0.001 * w; + } + for (code = 0; code < 256; ++code) { + if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { + widths[code] = 0.001 * w; + } + } + + // couldn't find widths -- use defaults + } else { + // this is technically an error -- the Widths entry is required + // for all but the Base-14 fonts -- but certain PDF generators + // apparently don't include widths for Arial and TimesNewRoman + if (isFixedWidth()) { + i = 0; + } else if (isSerif()) { + i = 8; + } else { + i = 4; + } + if (isBold()) { + i += 2; + } + if (isItalic()) { + i += 1; + } + builtinFont = builtinFontSubst[i]; + // this is a kludge for broken PDF files that encode char 32 + // as .notdef + if (builtinFont->widths->getWidth("space", &w)) { + widths[32] = 0.001 * w; + } + for (code = 0; code < 256; ++code) { + if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { + widths[code] = 0.001 * w; + } + } + } + obj1.free(); + + ok = gTrue; +} + +Gfx8BitFont::~Gfx8BitFont() { + int i; + + for (i = 0; i < 256; ++i) { + if (encFree[i] && enc[i]) { + gfree(enc[i]); + } + } + ctu->decRefCnt(); + if (charProcs.isDict()) { + charProcs.free(); + } + if (resources.isDict()) { + resources.free(); + } +} + +int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy) { + CharCode c; + + *code = c = (CharCode)(*s & 0xff); + *uLen = ctu->mapToUnicode(c, u, uSize); + *dx = widths[c]; + *dy = *ox = *oy = 0; + return 1; +} + +CharCodeToUnicode *Gfx8BitFont::getToUnicode() { + ctu->incRefCnt(); + return ctu; +} + +Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { + Gushort *map; + int cmapPlatform, cmapEncoding; + int unicodeCmap, macRomanCmap, msSymbolCmap, cmap; + GBool useMacRoman, useUnicode; + char *charName; + Unicode u; + int code, i, n; + + map = (Gushort *)gmallocn(256, sizeof(Gushort)); + for (i = 0; i < 256; ++i) { + map[i] = 0; + } + + // To match up with the Adobe-defined behaviour, we choose a cmap + // like this: + // 1. If the PDF font has an encoding: + // 1a. If the PDF font specified MacRomanEncoding and the + // TrueType font has a Macintosh Roman cmap, use it, and + // reverse map the char names through MacRomanEncoding to + // get char codes. + // 1b. If the TrueType font has a Microsoft Unicode cmap or a + // non-Microsoft Unicode cmap, use it, and use the Unicode + // indexes, not the char codes. + // 1c. If the PDF font is symbolic and the TrueType font has a + // Microsoft Symbol cmap, use it, and use char codes + // directly (possibly with an offset of 0xf000). + // 1d. If the TrueType font has a Macintosh Roman cmap, use it, + // as in case 1a. + // 2. If the PDF font does not have an encoding or the PDF font is + // symbolic: + // 2a. If the TrueType font has a Macintosh Roman cmap, use it, + // and use char codes directly (possibly with an offset of + // 0xf000). + // 2b. If the TrueType font has a Microsoft Symbol cmap, use it, + // and use char codes directly (possible with an offset of + // 0xf000). + // 3. If none of these rules apply, use the first cmap and hope for + // the best (this shouldn't happen). + unicodeCmap = macRomanCmap = msSymbolCmap = -1; + for (i = 0; i < ff->getNumCmaps(); ++i) { + cmapPlatform = ff->getCmapPlatform(i); + cmapEncoding = ff->getCmapEncoding(i); + if ((cmapPlatform == 3 && cmapEncoding == 1) || + cmapPlatform == 0) { + unicodeCmap = i; + } else if (cmapPlatform == 1 && cmapEncoding == 0) { + macRomanCmap = i; + } else if (cmapPlatform == 3 && cmapEncoding == 0) { + msSymbolCmap = i; + } + } + cmap = 0; + useMacRoman = gFalse; + useUnicode = gFalse; + if (hasEncoding) { + if (usesMacRomanEnc && macRomanCmap >= 0) { + cmap = macRomanCmap; + useMacRoman = gTrue; + } else if (unicodeCmap >= 0) { + cmap = unicodeCmap; + useUnicode = gTrue; + } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { + cmap = msSymbolCmap; + } else if ((flags & fontSymbolic) && macRomanCmap >= 0) { + cmap = macRomanCmap; + } else if (macRomanCmap >= 0) { + cmap = macRomanCmap; + useMacRoman = gTrue; + } + } else { + if (macRomanCmap >= 0) { + cmap = macRomanCmap; + } else if (msSymbolCmap >= 0) { + cmap = msSymbolCmap; + } + } + + // reverse map the char names through MacRomanEncoding, then map the + // char codes through the cmap + if (useMacRoman) { + for (i = 0; i < 256; ++i) { + if ((charName = enc[i])) { + if ((code = globalParams->getMacRomanCharCode(charName))) { + map[i] = ff->mapCodeToGID(cmap, code); + } + } + } + + // map Unicode through the cmap + } else if (useUnicode) { + for (i = 0; i < 256; ++i) { + if (((charName = enc[i]) && + (u = globalParams->mapNameToUnicode(charName))) || + (n = ctu->mapToUnicode((CharCode)i, &u, 1))) { + map[i] = ff->mapCodeToGID(cmap, u); + } + } + + // map the char codes through the cmap, possibly with an offset of + // 0xf000 + } else { + for (i = 0; i < 256; ++i) { + if (!(map[i] = ff->mapCodeToGID(cmap, i))) { + map[i] = ff->mapCodeToGID(cmap, 0xf000 + i); + } + } + } + + // try the TrueType 'post' table to handle any unmapped characters + for (i = 0; i < 256; ++i) { + if (!map[i] && (charName = enc[i])) { + map[i] = (Gushort)(long)ff->mapNameToGID(charName); + } + } + + return map; +} + +Dict *Gfx8BitFont::getCharProcs() { + return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL; +} + +Object *Gfx8BitFont::getCharProc(int code, Object *proc) { + if (enc[code] && charProcs.isDict()) { + charProcs.dictLookup(enc[code], proc); + } else { + proc->initNull(); + } + return proc; +} + +Dict *Gfx8BitFont::getResources() { + return resources.isDict() ? resources.getDict() : (Dict *)NULL; +} + +//------------------------------------------------------------------------ +// GfxCIDFont +//------------------------------------------------------------------------ + +static int CDECL cmpWidthExcep(const void *w1, const void *w2) { + return ((GfxFontCIDWidthExcep *)w1)->first - + ((GfxFontCIDWidthExcep *)w2)->first; +} + +static int CDECL cmpWidthExcepV(const void *w1, const void *w2) { + return ((GfxFontCIDWidthExcepV *)w1)->first - + ((GfxFontCIDWidthExcepV *)w2)->first; +} + +GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + Dict *fontDict): + GfxFont(tagA, idA, nameA) +{ + Dict *desFontDict; + GString *collection, *cMapName; + Object desFontDictObj; + Object obj1, obj2, obj3, obj4, obj5, obj6; + CharCodeToUnicode *utu; + CharCode c; + Unicode uBuf[8]; + int c1, c2; + int excepsSize, i, j, k, n; + + ascent = 0.95; + descent = -0.35; + fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; + cMap = NULL; + ctu = NULL; + widths.defWidth = 1.0; + widths.defHeight = -1.0; + widths.defVY = 0.880; + widths.exceps = NULL; + widths.nExceps = 0; + widths.excepsV = NULL; + widths.nExcepsV = 0; + cidToGID = NULL; + cidToGIDLen = 0; + + // get the descendant font + if (!fontDict->lookup("DescendantFonts", &obj1)->isArray()) { + error(-1, "Missing DescendantFonts entry in Type 0 font"); + obj1.free(); + goto err1; + } + if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) { + error(-1, "Bad descendant font in Type 0 font"); + goto err3; + } + obj1.free(); + desFontDict = desFontDictObj.getDict(); + + // font type + if (!desFontDict->lookup("Subtype", &obj1)) { + error(-1, "Missing Subtype entry in Type 0 descendant font"); + goto err3; + } + if (obj1.isName("CIDFontType0")) { + type = fontCIDType0; + } else if (obj1.isName("CIDFontType2")) { + type = fontCIDType2; + } else { + error(-1, "Unknown Type 0 descendant font type '%s'", + obj1.isName() ? obj1.getName() : "???"); + goto err3; + } + obj1.free(); + + // get info from font descriptor + readFontDescriptor(xref, desFontDict); + + // look for an external font file + findExtFontFile(); + + //----- encoding info ----- + + // char collection + if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) { + error(-1, "Missing CIDSystemInfo dictionary in Type 0 descendant font"); + goto err3; + } + obj1.dictLookup("Registry", &obj2); + obj1.dictLookup("Ordering", &obj3); + if (!obj2.isString() || !obj3.isString()) { + error(-1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); + goto err4; + } + collection = obj2.getString()->copy()->append('-')->append(obj3.getString()); + obj3.free(); + obj2.free(); + obj1.free(); + + // look for a ToUnicode CMap + if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) { + + // the "Adobe-Identity" and "Adobe-UCS" collections don't have + // cidToUnicode files + if (collection->cmp("Adobe-Identity") && + collection->cmp("Adobe-UCS")) { + + // look for a user-supplied .cidToUnicode file + if (!(ctu = globalParams->getCIDToUnicode(collection))) { + error(-1, "Unknown character collection '%s'", + collection->getCString()); + // fall-through, assuming the Identity mapping -- this appears + // to match Adobe's behavior + } + } + } + + // look for a Unicode-to-Unicode mapping + if (name && (utu = globalParams->getUnicodeToUnicode(name))) { + if (ctu) { + for (c = 0; c < ctu->getLength(); ++c) { + n = ctu->mapToUnicode(c, uBuf, 8); + if (n >= 1) { + n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); + if (n >= 1) { + ctu->setMapping(c, uBuf, n); + } + } + } + utu->decRefCnt(); + } else { + ctu = utu; + } + } + + // encoding (i.e., CMap) + //~ need to handle a CMap stream here + //~ also need to deal with the UseCMap entry in the stream dict + if (!fontDict->lookup("Encoding", &obj1)->isName()) { + error(-1, "Missing or invalid Encoding entry in Type 0 font"); + delete collection; + goto err3; + } + cMapName = new GString(obj1.getName()); + obj1.free(); + if (!(cMap = globalParams->getCMap(collection, cMapName))) { + error(-1, "Unknown CMap '%s' for character collection '%s'", + cMapName->getCString(), collection->getCString()); + delete collection; + delete cMapName; + goto err2; + } + delete collection; + delete cMapName; + + // CIDToGIDMap (for embedded TrueType fonts) + if (type == fontCIDType2) { + desFontDict->lookup("CIDToGIDMap", &obj1); + if (obj1.isStream()) { + cidToGIDLen = 0; + i = 64; + cidToGID = (Gushort *)gmallocn(i, sizeof(Gushort)); + obj1.streamReset(); + while ((c1 = obj1.streamGetChar()) != EOF && + (c2 = obj1.streamGetChar()) != EOF) { + if (cidToGIDLen == i) { + i *= 2; + cidToGID = (Gushort *)greallocn(cidToGID, i, sizeof(Gushort)); + } + cidToGID[cidToGIDLen++] = (Gushort)((c1 << 8) + c2); + } + } else if (!obj1.isName("Identity") && !obj1.isNull()) { + error(-1, "Invalid CIDToGIDMap entry in CID font"); + } + obj1.free(); + } + + //----- character metrics ----- + + // default char width + if (desFontDict->lookup("DW", &obj1)->isInt()) { + widths.defWidth = obj1.getInt() * 0.001; + } + obj1.free(); + + // char width exceptions + if (desFontDict->lookup("W", &obj1)->isArray()) { + excepsSize = 0; + i = 0; + while (i + 1 < obj1.arrayGetLength()) { + obj1.arrayGet(i, &obj2); + obj1.arrayGet(i + 1, &obj3); + if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) { + if (obj1.arrayGet(i + 2, &obj4)->isNum()) { + if (widths.nExceps == excepsSize) { + excepsSize += 16; + widths.exceps = (GfxFontCIDWidthExcep *) + greallocn(widths.exceps, + excepsSize, sizeof(GfxFontCIDWidthExcep)); + } + widths.exceps[widths.nExceps].first = obj2.getInt(); + widths.exceps[widths.nExceps].last = obj3.getInt(); + widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001; + ++widths.nExceps; + } else { + error(-1, "Bad widths array in Type 0 font"); + } + obj4.free(); + i += 3; + } else if (obj2.isInt() && obj3.isArray()) { + if (widths.nExceps + obj3.arrayGetLength() > excepsSize) { + excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15; + widths.exceps = (GfxFontCIDWidthExcep *) + greallocn(widths.exceps, + excepsSize, sizeof(GfxFontCIDWidthExcep)); + } + j = obj2.getInt(); + for (k = 0; k < obj3.arrayGetLength(); ++k) { + if (obj3.arrayGet(k, &obj4)->isNum()) { + widths.exceps[widths.nExceps].first = j; + widths.exceps[widths.nExceps].last = j; + widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001; + ++j; + ++widths.nExceps; + } else { + error(-1, "Bad widths array in Type 0 font"); + } + obj4.free(); + } + i += 2; + } else { + error(-1, "Bad widths array in Type 0 font"); + ++i; + } + obj3.free(); + obj2.free(); + } + qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep), + &cmpWidthExcep); + } + obj1.free(); + + // default metrics for vertical font + if (desFontDict->lookup("DW2", &obj1)->isArray() && + obj1.arrayGetLength() == 2) { + if (obj1.arrayGet(0, &obj2)->isNum()) { + widths.defVY = obj2.getNum() * 0.001; + } + obj2.free(); + if (obj1.arrayGet(1, &obj2)->isNum()) { + widths.defHeight = obj2.getNum() * 0.001; + } + obj2.free(); + } + obj1.free(); + + // char metric exceptions for vertical font + if (desFontDict->lookup("W2", &obj1)->isArray()) { + excepsSize = 0; + i = 0; + while (i + 1 < obj1.arrayGetLength()) { + obj1.arrayGet(i, &obj2); + obj1.arrayGet(i+ 1, &obj3); + if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) { + if (obj1.arrayGet(i + 2, &obj4)->isNum() && + obj1.arrayGet(i + 3, &obj5)->isNum() && + obj1.arrayGet(i + 4, &obj6)->isNum()) { + if (widths.nExcepsV == excepsSize) { + excepsSize += 16; + widths.excepsV = (GfxFontCIDWidthExcepV *) + greallocn(widths.excepsV, + excepsSize, sizeof(GfxFontCIDWidthExcepV)); + } + widths.excepsV[widths.nExcepsV].first = obj2.getInt(); + widths.excepsV[widths.nExcepsV].last = obj3.getInt(); + widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001; + widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001; + widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001; + ++widths.nExcepsV; + } else { + error(-1, "Bad widths (W2) array in Type 0 font"); + } + obj6.free(); + obj5.free(); + obj4.free(); + i += 5; + } else if (obj2.isInt() && obj3.isArray()) { + if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) { + excepsSize = + (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15; + widths.excepsV = (GfxFontCIDWidthExcepV *) + greallocn(widths.excepsV, + excepsSize, sizeof(GfxFontCIDWidthExcepV)); + } + j = obj2.getInt(); + for (k = 0; k < obj3.arrayGetLength(); k += 3) { + if (obj3.arrayGet(k, &obj4)->isNum() && + obj3.arrayGet(k+1, &obj5)->isNum() && + obj3.arrayGet(k+2, &obj6)->isNum()) { + widths.excepsV[widths.nExceps].first = j; + widths.excepsV[widths.nExceps].last = j; + widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001; + widths.excepsV[widths.nExceps].vx = obj5.getNum() * 0.001; + widths.excepsV[widths.nExceps].vy = obj6.getNum() * 0.001; + ++j; + ++widths.nExcepsV; + } else { + error(-1, "Bad widths (W2) array in Type 0 font"); + } + obj6.free(); + obj5.free(); + obj4.free(); + } + i += 2; + } else { + error(-1, "Bad widths (W2) array in Type 0 font"); + ++i; + } + obj3.free(); + obj2.free(); + } + qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV), + &cmpWidthExcepV); + } + obj1.free(); + + desFontDictObj.free(); + ok = gTrue; + return; + + err4: + obj3.free(); + obj2.free(); + err3: + obj1.free(); + err2: + desFontDictObj.free(); + err1:; +} + +GfxCIDFont::~GfxCIDFont() { + if (cMap) { + cMap->decRefCnt(); + } + if (ctu) { + ctu->decRefCnt(); + } + gfree(widths.exceps); + gfree(widths.excepsV); + if (cidToGID) { + gfree(cidToGID); + } +} + +int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy) { + CID cid; + double w, h, vx, vy; + int n, a, b, m; + + if (!cMap) { + *code = 0; + *uLen = 0; + *dx = *dy = 0; + return 1; + } + + *code = (CharCode)(cid = cMap->getCID(s, len, &n)); + if (ctu) { + *uLen = ctu->mapToUnicode(cid, u, uSize); + } else { + *uLen = 0; + } + + // horizontal + if (cMap->getWMode() == 0) { + w = widths.defWidth; + h = vx = vy = 0; + if (widths.nExceps > 0 && cid >= widths.exceps[0].first) { + a = 0; + b = widths.nExceps; + // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first + while (b - a > 1) { + m = (a + b) / 2; + if (widths.exceps[m].first <= cid) { + a = m; + } else { + b = m; + } + } + if (cid <= widths.exceps[a].last) { + w = widths.exceps[a].width; + } + } + + // vertical + } else { + w = 0; + h = widths.defHeight; + vx = widths.defWidth / 2; + vy = widths.defVY; + if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) { + a = 0; + b = widths.nExcepsV; + // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first + while (b - a > 1) { + m = (a + b) / 2; + if (widths.excepsV[m].last <= cid) { + a = m; + } else { + b = m; + } + } + if (cid <= widths.excepsV[a].last) { + h = widths.excepsV[a].height; + vx = widths.excepsV[a].vx; + vy = widths.excepsV[a].vy; + } + } + } + + *dx = w; + *dy = h; + *ox = vx; + *oy = vy; + + return n; +} + +int GfxCIDFont::getWMode() { + return cMap ? cMap->getWMode() : 0; +} + +CharCodeToUnicode *GfxCIDFont::getToUnicode() { + if (ctu) { + ctu->incRefCnt(); + } + return ctu; +} + +GString *GfxCIDFont::getCollection() { + return cMap ? cMap->getCollection() : (GString *)NULL; +} + +//------------------------------------------------------------------------ +// GfxFontDict +//------------------------------------------------------------------------ + +GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { + int i; + Object obj1, obj2; + Ref r; + + numFonts = fontDict->getLength(); + fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *)); + for (i = 0; i < numFonts; ++i) { + fontDict->getValNF(i, &obj1); + obj1.fetch(xref, &obj2); + if (obj2.isDict()) { + if (obj1.isRef()) { + r = obj1.getRef(); + } else { + // no indirect reference for this font, so invent a unique one + // (legal generation numbers are five digits, so any 6-digit + // number would be safe) + r.num = i; + if (fontDictRef) { + r.gen = 100000 + fontDictRef->num; + } else { + r.gen = 999999; + } + } + fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i), + r, obj2.getDict()); + if (fonts[i] && !fonts[i]->isOk()) { + delete fonts[i]; + fonts[i] = NULL; + } + } 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) { + if (fonts[i]) { + delete fonts[i]; + } + } + gfree(fonts); +} + +GfxFont *GfxFontDict::lookup(char *tag) { + int i; + + for (i = 0; i < numFonts; ++i) { + if (fonts[i] && 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..6b051d490 --- /dev/null +++ b/pdftops/GfxFont.h @@ -0,0 +1,315 @@ +//======================================================================== +// +// GfxFont.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GFXFONT_H +#define GFXFONT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "GString.h" +#include "Object.h" +#include "CharTypes.h" + +class Dict; +class CMap; +class CharCodeToUnicode; +class FoFiTrueType; +struct GfxFontCIDWidths; + +//------------------------------------------------------------------------ +// GfxFontType +//------------------------------------------------------------------------ + +enum GfxFontType { + //----- Gfx8BitFont + fontUnknownType, + fontType1, + fontType1C, + fontType3, + fontTrueType, + //----- GfxCIDFont + fontCIDType0, + fontCIDType0C, + fontCIDType2 +}; + +//------------------------------------------------------------------------ +// GfxFontCIDWidths +//------------------------------------------------------------------------ + +struct GfxFontCIDWidthExcep { + CID first; // this record applies to + CID last; // CIDs .. + double width; // char width +}; + +struct GfxFontCIDWidthExcepV { + CID first; // this record applies to + CID last; // CIDs .. + double height; // char height + double vx, vy; // origin position +}; + +struct GfxFontCIDWidths { + double defWidth; // default char width + double defHeight; // default char height + double defVY; // default origin position + GfxFontCIDWidthExcep *exceps; // exceptions + int nExceps; // number of valid entries in exceps + GfxFontCIDWidthExcepV * // exceptions for vertical font + excepsV; + int nExcepsV; // 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) + +class GfxFont { +public: + + // Build a GfxFont object. + static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict); + + GfxFont(char *tagA, Ref idA, GString *nameA); + + virtual ~GfxFont(); + + GBool isOk() { return ok; } + + // 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 the original font name (ignornig any munging that might have + // been done to map to a canonical Base-14 font name). + GString *getOrigName() { return origName; } + + // Get font type. + GfxFontType getType() { return type; } + virtual GBool isCIDFont() { return gFalse; } + + // 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. + GString *getEmbeddedFontName() { return embFontName; } + + // 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; } + + // 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; } + + // Return the writing mode (0=horizontal, 1=vertical). + virtual int getWMode() { return 0; } + + // Read an external or embedded font file into a buffer. + char *readExtFontFile(int *len); + char *readEmbFontFile(XRef *xref, int *len); + + // Get the next char from a string of bytes, returning the + // char , its Unicode mapping , its displacement vector + // (, ), and its origin offset vector (, ). + // is the number of entries available in , and is set to + // the number actually used. Returns the number of bytes used by + // the char code. + virtual int getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy) = 0; + +protected: + + void readFontDescriptor(XRef *xref, Dict *fontDict); + CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits, + CharCodeToUnicode *ctu); + void findExtFontFile(); + + GString *tag; // PDF font tag + Ref id; // reference (used as unique ID) + GString *name; // font name + GString *origName; // original font name + GfxFontType type; // type of font + int flags; // font descriptor flags + GString *embFontName; // name of embedded font + Ref embFontID; // ref to embedded font file stream + GString *extFontFile; // external font file name + double fontMat[6]; // font matrix (Type 3 only) + double fontBBox[4]; // font bounding box (Type 3 only) + double missingWidth; // "default" width + double ascent; // max height above baseline + double descent; // max depth below baseline + GBool ok; +}; + +//------------------------------------------------------------------------ +// Gfx8BitFont +//------------------------------------------------------------------------ + +class Gfx8BitFont: public GfxFont { +public: + + Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + GfxFontType typeA, Dict *fontDict); + + virtual ~Gfx8BitFont(); + + virtual int getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy); + + // Return the encoding. + char **getEncoding() { return enc; } + + // Return the Unicode map. + CharCodeToUnicode *getToUnicode(); + + // Return the character name associated with . + char *getCharName(int code) { return enc[code]; } + + // Returns true if the PDF font specified an encoding. + GBool getHasEncoding() { return hasEncoding; } + + // Returns true if the PDF font specified MacRomanEncoding. + GBool getUsesMacRomanEnc() { return usesMacRomanEnc; } + + // Get width of a character. + double getWidth(Guchar c) { return widths[c]; } + + // Return a char code-to-GID mapping for the provided font file. + // (This is only useful for TrueType fonts.) + Gushort *getCodeToGIDMap(FoFiTrueType *ff); + + // Return the Type 3 CharProc dictionary, or NULL if none. + Dict *getCharProcs(); + + // Return the Type 3 CharProc for the character associated with . + Object *getCharProc(int code, Object *proc); + + // Return the Type 3 Resources dictionary, or NULL if none. + Dict *getResources(); + +private: + + char *enc[256]; // char code --> char name + char encFree[256]; // boolean for each char name: if set, + // the string is malloc'ed + CharCodeToUnicode *ctu; // char code --> Unicode + GBool hasEncoding; + GBool usesMacRomanEnc; + double widths[256]; // character widths + Object charProcs; // Type 3 CharProcs dictionary + Object resources; // Type 3 Resources dictionary +}; + +//------------------------------------------------------------------------ +// GfxCIDFont +//------------------------------------------------------------------------ + +class GfxCIDFont: public GfxFont { +public: + + GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, + Dict *fontDict); + + virtual ~GfxCIDFont(); + + virtual GBool isCIDFont() { return gTrue; } + + virtual int getNextChar(char *s, int len, CharCode *code, + Unicode *u, int uSize, int *uLen, + double *dx, double *dy, double *ox, double *oy); + + // Return the writing mode (0=horizontal, 1=vertical). + virtual int getWMode(); + + // Return the Unicode map. + CharCodeToUnicode *getToUnicode(); + + // Get the collection name (-). + GString *getCollection(); + + // Return the CID-to-GID mapping table. These should only be called + // if type is fontCIDType2. + Gushort *getCIDToGID() { return cidToGID; } + int getCIDToGIDLen() { return cidToGIDLen; } + +private: + + CMap *cMap; // char code --> CID + CharCodeToUnicode *ctu; // CID --> Unicode + GfxFontCIDWidths widths; // character widths + Gushort *cidToGID; // CID --> GID mapping (for embedded + // TrueType fonts) + int cidToGIDLen; +}; + +//------------------------------------------------------------------------ +// GfxFontDict +//------------------------------------------------------------------------ + +class GfxFontDict { +public: + + // Build the font dictionary, given the PDF font dictionary. + GfxFontDict(XRef *xref, Ref *fontDictRef, 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..7ab6b1265 --- /dev/null +++ b/pdftops/GfxState.cxx @@ -0,0 +1,3946 @@ +//======================================================================== +// +// GfxState.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include "gmem.h" +#include "Error.h" +#include "Object.h" +#include "Array.h" +#include "Page.h" +#include "GfxState.h" + +//------------------------------------------------------------------------ + +static inline GfxColorComp clip01(GfxColorComp x) { + return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x; +} + +static inline double clip01(double x) { + return (x < 0) ? 0 : (x > 1) ? 1 : x; +} + +//------------------------------------------------------------------------ + +static struct { + char *name; + GfxBlendMode mode; +} gfxBlendModeNames[] = { + { "Normal", gfxBlendNormal }, + { "Compatible", gfxBlendNormal }, + { "Multiply", gfxBlendMultiply }, + { "Screen", gfxBlendScreen }, + { "Overlay", gfxBlendOverlay }, + { "Darken", gfxBlendDarken }, + { "Lighten", gfxBlendLighten }, + { "ColorDodge", gfxBlendColorDodge }, + { "ColorBurn", gfxBlendColorBurn }, + { "HardLight", gfxBlendHardLight }, + { "SoftLight", gfxBlendSoftLight }, + { "Difference", gfxBlendDifference }, + { "Exclusion", gfxBlendExclusion }, + { "Hue", gfxBlendHue }, + { "Saturation", gfxBlendSaturation }, + { "Color", gfxBlendColor }, + { "Luminosity", gfxBlendLuminosity } +}; + +#define nGfxBlendModeNames \ + ((int)((sizeof(gfxBlendModeNames) / sizeof(char *)))) + +//------------------------------------------------------------------------ + +// NB: This must match the GfxColorSpaceMode enum defined in +// GfxState.h +static char *gfxColorSpaceModeNames[] = { + "DeviceGray", + "CalGray", + "DeviceRGB", + "CalRGB", + "DeviceCMYK", + "Lab", + "ICCBased", + "Indexed", + "Separation", + "DeviceN", + "Pattern" +}; + +#define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *))) + +//------------------------------------------------------------------------ +// 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"); + } + 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; + } +} + +int GfxColorSpace::getNumColorSpaceModes() { + return nGfxColorSpaceModes; +} + +char *GfxColorSpace::getColorSpaceModeName(int idx) { + return gfxColorSpaceModeNames[idx]; +} + +//------------------------------------------------------------------------ +// GfxDeviceGrayColorSpace +//------------------------------------------------------------------------ + +GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() { +} + +GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() { +} + +GfxColorSpace *GfxDeviceGrayColorSpace::copy() { + return new GfxDeviceGrayColorSpace(); +} + +void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *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(gfxColorComp1 - 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, GfxGray *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(gfxColorComp1 - color->c[0]); +} + +//------------------------------------------------------------------------ +// GfxDeviceRGBColorSpace +//------------------------------------------------------------------------ + +GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() { +} + +GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() { +} + +GfxColorSpace *GfxDeviceRGBColorSpace::copy() { + return new GfxDeviceRGBColorSpace(); +} + +void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { + *gray = clip01((GfxColorComp)(0.3 * color->c[0] + + 0.59 * color->c[1] + + 0.11 * color->c[2] + 0.5)); +} + +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) { + GfxColorComp c, m, y, k; + + c = clip01(gfxColorComp1 - color->c[0]); + m = clip01(gfxColorComp1 - color->c[1]); + y = clip01(gfxColorComp1 - 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, GfxGray *gray) { + *gray = clip01((GfxColorComp)(0.299 * color->c[0] + + 0.587 * color->c[1] + + 0.114 * color->c[2] + 0.5)); +} + +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) { + GfxColorComp c, m, y, k; + + c = clip01(gfxColorComp1 - color->c[0]); + m = clip01(gfxColorComp1 - color->c[1]); + y = clip01(gfxColorComp1 - 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, GfxGray *gray) { + *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3] + - 0.3 * color->c[0] + - 0.59 * color->c[1] + - 0.11 * color->c[2] + 0.5)); +} + +void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double c, m, y, k, c1, m1, y1, k1, r, g, b, x; + + c = colToDbl(color->c[0]); + m = colToDbl(color->c[1]); + y = colToDbl(color->c[2]); + k = colToDbl(color->c[3]); + c1 = 1 - c; + m1 = 1 - m; + y1 = 1 - y; + k1 = 1 - k; + // this is a matrix multiplication, unrolled for performance + // C M Y K + x = c1 * m1 * y1 * k1; // 0 0 0 0 + r = g = b = x; + x = c1 * m1 * y1 * k; // 0 0 0 1 + r += 0.1373 * x; + g += 0.1216 * x; + b += 0.1255 * x; + x = c1 * m1 * y * k1; // 0 0 1 0 + r += x; + g += 0.9490 * x; + x = c1 * m1 * y * k; // 0 0 1 1 + r += 0.1098 * x; + g += 0.1020 * x; + x = c1 * m * y1 * k1; // 0 1 0 0 + r += 0.9255 * x; + b += 0.5490 * x; + x = c1 * m * y1 * k; // 0 1 0 1 + r += 0.1412 * x; + x = c1 * m * y * k1; // 0 1 1 0 + r += 0.9294 * x; + g += 0.1098 * x; + b += 0.1412 * x; + x = c1 * m * y * k; // 0 1 1 1 + r += 0.1333 * x; + x = c * m1 * y1 * k1; // 1 0 0 0 + g += 0.6784 * x; + b += 0.9373 * x; + x = c * m1 * y1 * k; // 1 0 0 1 + g += 0.0588 * x; + b += 0.1412 * x; + x = c * m1 * y * k1; // 1 0 1 0 + g += 0.6510 * x; + b += 0.3137 * x; + x = c * m1 * y * k; // 1 0 1 1 + g += 0.0745 * x; + x = c * m * y1 * k1; // 1 1 0 0 + r += 0.1804 * x; + g += 0.1922 * x; + b += 0.5725 * x; + x = c * m * y1 * k; // 1 1 0 1 + b += 0.0078 * x; + x = c * m * y * k1; // 1 1 1 0 + r += 0.2118 * x; + g += 0.2119 * x; + b += 0.2235 * x; + rgb->r = clip01(dblToCol(r)); + rgb->g = clip01(dblToCol(g)); + rgb->b = clip01(dblToCol(b)); +} + +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, GfxGray *gray) { + GfxRGB rgb; + + getRGB(color, &rgb); + *gray = clip01((GfxColorComp)(0.299 * rgb.r + + 0.587 * rgb.g + + 0.114 * rgb.b + 0.5)); +} + +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 = (colToDbl(color->c[0]) + 16) / 116; + t2 = t1 + colToDbl(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 - colToDbl(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 = dblToCol(pow(clip01(r * kr), 0.5)); + rgb->g = dblToCol(pow(clip01(g * kg), 0.5)); + rgb->b = dblToCol(pow(clip01(b * kb), 0.5)); +} + +void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxRGB rgb; + GfxColorComp c, m, y, k; + + getRGB(color, &rgb); + c = clip01(gfxColorComp1 - rgb.r); + m = clip01(gfxColorComp1 - rgb.g); + y = clip01(gfxColorComp1 - 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 (nCompsA > gfxColorMaxComps) { + error(-1, "ICCBased color space with too many (%d > %d) components", + nCompsA, gfxColorMaxComps); + nCompsA = gfxColorMaxComps; + } + 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, GfxGray *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) { + alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel); + +#if 0 + // this is nominally correct, but some PDF files don't set the + // correct ranges in the ICCBased dict + int i; + + for (i = 0; i < nComps; ++i) { + decodeLow[i] = rangeMin[i]; + decodeRange[i] = rangeMax[i] - rangeMin[i]; + } +#endif +} + +//------------------------------------------------------------------------ +// GfxIndexedColorSpace +//------------------------------------------------------------------------ + +GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA, + int indexHighA) { + base = baseA; + indexHigh = indexHighA; + lookup = (Guchar *)gmallocn((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)"); + delete baseA; + goto err2; + } + indexHighA = obj1.getInt(); + if (indexHighA < 0 || indexHighA > 255) { + // the PDF spec requires indexHigh to be in [0,255] -- allowing + // values larger than 255 creates a security hole: if nComps * + // indexHigh is greater than 2^31, the loop below may overwrite + // past the end of the array + error(-1, "Bad Indexed color space (invalid indexHigh value)"); + delete baseA; + goto err2; + } + 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; +} + +GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color, + GfxColor *baseColor) { + Guchar *p; + double low[gfxColorMaxComps], range[gfxColorMaxComps]; + int n, i; + + n = base->getNComps(); + base->getDefaultRanges(low, range, indexHigh); + p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n]; + for (i = 0; i < n; ++i) { + baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]); + } + return baseColor; +} + +void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) { + GfxColor color2; + + base->getGray(mapColorToBase(color, &color2), gray); +} + +void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + GfxColor color2; + + base->getRGB(mapColorToBase(color, &color2), rgb); +} + +void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + GfxColor color2; + + base->getCMYK(mapColorToBase(color, &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; + } + obj1.free(); + cs = new GfxSeparationColorSpace(nameA, altA, funcA); + return cs; + + err4: + delete altA; + err3: + delete nameA; + err2: + obj1.free(); + err1: + return NULL; +} + +void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) { + double x; + double c[gfxColorMaxComps]; + GfxColor color2; + int i; + + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getGray(&color2, gray); +} + +void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double x; + double c[gfxColorMaxComps]; + GfxColor color2; + int i; + + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getRGB(&color2, rgb); +} + +void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + double x; + double c[gfxColorMaxComps]; + GfxColor color2; + int i; + + x = colToDbl(color->c[0]); + func->transform(&x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + 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(); + if (nCompsA > gfxColorMaxComps) { + error(-1, "DeviceN color space with too many (%d > %d) components", + nCompsA, gfxColorMaxComps); + nCompsA = gfxColorMaxComps; + } + 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; + } + obj1.free(); + cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA); + for (i = 0; i < nCompsA; ++i) { + cs->names[i] = namesA[i]; + } + return cs; + + err4: + delete altA; + err3: + for (i = 0; i < nCompsA; ++i) { + delete namesA[i]; + } + err2: + obj1.free(); + err1: + return NULL; +} + +void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; + GfxColor color2; + int i; + + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getGray(&color2, gray); +} + +void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; + GfxColor color2; + int i; + + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + alt->getRGB(&color2, rgb); +} + +void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { + double x[gfxColorMaxComps], c[gfxColorMaxComps]; + GfxColor color2; + int i; + + for (i = 0; i < nComps; ++i) { + x[i] = colToDbl(color->c[i]); + } + func->transform(x, c); + for (i = 0; i < alt->getNComps(); ++i) { + color2.c[i] = dblToCol(c[i]); + } + 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, GfxGray *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; + Object obj1; + + if (obj->isDict()) { + obj->dictLookup("PatternType", &obj1); + } else if (obj->isStream()) { + obj->streamGetDict()->lookup("PatternType", &obj1); + } else { + return NULL; + } + pattern = NULL; + if (obj1.isInt() && obj1.getInt() == 1) { + pattern = GfxTilingPattern::parse(obj); + } else if (obj1.isInt() && obj1.getInt() == 2) { + pattern = GfxShadingPattern::parse(obj); + } + obj1.free(); + return pattern; +} + +//------------------------------------------------------------------------ +// GfxTilingPattern +//------------------------------------------------------------------------ + +GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) { + GfxTilingPattern *pat; + Dict *dict; + int paintTypeA, tilingTypeA; + double bboxA[4], matrixA[6]; + double xStepA, yStepA; + Object resDictA; + Object obj1, obj2; + int i; + + if (!patObj->isStream()) { + return NULL; + } + dict = patObj->streamGetDict(); + + if (dict->lookup("PaintType", &obj1)->isInt()) { + paintTypeA = obj1.getInt(); + } else { + paintTypeA = 1; + error(-1, "Invalid or missing PaintType in pattern"); + } + obj1.free(); + if (dict->lookup("TilingType", &obj1)->isInt()) { + tilingTypeA = obj1.getInt(); + } else { + tilingTypeA = 1; + error(-1, "Invalid or missing TilingType in pattern"); + } + obj1.free(); + bboxA[0] = bboxA[1] = 0; + bboxA[2] = bboxA[3] = 1; + if (dict->lookup("BBox", &obj1)->isArray() && + obj1.arrayGetLength() == 4) { + for (i = 0; i < 4; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + bboxA[i] = obj2.getNum(); + } + obj2.free(); + } + } else { + error(-1, "Invalid or missing BBox in pattern"); + } + obj1.free(); + if (dict->lookup("XStep", &obj1)->isNum()) { + xStepA = obj1.getNum(); + } else { + xStepA = 1; + error(-1, "Invalid or missing XStep in pattern"); + } + obj1.free(); + if (dict->lookup("YStep", &obj1)->isNum()) { + yStepA = obj1.getNum(); + } else { + yStepA = 1; + error(-1, "Invalid or missing YStep in pattern"); + } + obj1.free(); + if (!dict->lookup("Resources", &resDictA)->isDict()) { + resDictA.free(); + resDictA.initNull(); + error(-1, "Invalid or missing Resources in pattern"); + } + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + for (i = 0; i < 6; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + matrixA[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + + pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA, + &resDictA, matrixA, patObj); + resDictA.free(); + return pat; +} + +GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA, + double *bboxA, double xStepA, double yStepA, + Object *resDictA, double *matrixA, + Object *contentStreamA): + GfxPattern(1) +{ + int i; + + paintType = paintTypeA; + tilingType = tilingTypeA; + for (i = 0; i < 4; ++i) { + bbox[i] = bboxA[i]; + } + xStep = xStepA; + yStep = yStepA; + resDictA->copy(&resDict); + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } + contentStreamA->copy(&contentStream); +} + +GfxTilingPattern::~GfxTilingPattern() { + resDict.free(); + contentStream.free(); +} + +GfxPattern *GfxTilingPattern::copy() { + return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep, + &resDict, matrix, &contentStream); +} + +//------------------------------------------------------------------------ +// GfxShadingPattern +//------------------------------------------------------------------------ + +GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) { + Dict *dict; + GfxShading *shadingA; + double matrixA[6]; + Object obj1, obj2; + int i; + + if (!patObj->isDict()) { + return NULL; + } + dict = patObj->getDict(); + + dict->lookup("Shading", &obj1); + shadingA = GfxShading::parse(&obj1); + obj1.free(); + if (!shadingA) { + return NULL; + } + + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + for (i = 0; i < 6; ++i) { + if (obj1.arrayGet(i, &obj2)->isNum()) { + matrixA[i] = obj2.getNum(); + } + obj2.free(); + } + } + obj1.free(); + + return new GfxShadingPattern(shadingA, matrixA); +} + +GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA): + GfxPattern(2) +{ + int i; + + shading = shadingA; + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } +} + +GfxShadingPattern::~GfxShadingPattern() { + delete shading; +} + +GfxPattern *GfxShadingPattern::copy() { + return new GfxShadingPattern(shading->copy(), matrix); +} + +//------------------------------------------------------------------------ +// GfxShading +//------------------------------------------------------------------------ + +GfxShading::GfxShading(int typeA) { + type = typeA; + colorSpace = NULL; +} + +GfxShading::GfxShading(GfxShading *shading) { + int i; + + type = shading->type; + colorSpace = shading->colorSpace->copy(); + for (i = 0; i < gfxColorMaxComps; ++i) { + background.c[i] = shading->background.c[i]; + } + hasBackground = shading->hasBackground; + xMin = shading->xMin; + yMin = shading->yMin; + xMax = shading->xMax; + yMax = shading->yMax; + hasBBox = shading->hasBBox; +} + +GfxShading::~GfxShading() { + if (colorSpace) { + delete colorSpace; + } +} + +GfxShading *GfxShading::parse(Object *obj) { + GfxShading *shading; + Dict *dict; + int typeA; + Object obj1; + + if (obj->isDict()) { + dict = obj->getDict(); + } else if (obj->isStream()) { + dict = obj->streamGetDict(); + } else { + return NULL; + } + + if (!dict->lookup("ShadingType", &obj1)->isInt()) { + error(-1, "Invalid ShadingType in shading dictionary"); + obj1.free(); + return NULL; + } + typeA = obj1.getInt(); + obj1.free(); + + switch (typeA) { + case 1: + shading = GfxFunctionShading::parse(dict); + break; + case 2: + shading = GfxAxialShading::parse(dict); + break; + case 3: + shading = GfxRadialShading::parse(dict); + break; + case 4: + if (obj->isStream()) { + shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 4 shading object"); + goto err1; + } + break; + case 5: + if (obj->isStream()) { + shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 5 shading object"); + goto err1; + } + break; + case 6: + if (obj->isStream()) { + shading = GfxPatchMeshShading::parse(6, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 6 shading object"); + goto err1; + } + break; + case 7: + if (obj->isStream()) { + shading = GfxPatchMeshShading::parse(7, dict, obj->getStream()); + } else { + error(-1, "Invalid Type 7 shading object"); + goto err1; + } + break; + default: + error(-1, "Unimplemented shading type %d", typeA); + goto err1; + } + + return shading; + + err1: + return NULL; +} + +GBool GfxShading::init(Dict *dict) { + Object obj1, obj2; + int i; + + dict->lookup("ColorSpace", &obj1); + if (!(colorSpace = GfxColorSpace::parse(&obj1))) { + error(-1, "Bad color space in shading dictionary"); + obj1.free(); + return gFalse; + } + obj1.free(); + + for (i = 0; i < gfxColorMaxComps; ++i) { + background.c[i] = 0; + } + hasBackground = gFalse; + if (dict->lookup("Background", &obj1)->isArray()) { + if (obj1.arrayGetLength() == colorSpace->getNComps()) { + hasBackground = gTrue; + for (i = 0; i < colorSpace->getNComps(); ++i) { + background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum()); + obj2.free(); + } + } else { + error(-1, "Bad Background in shading dictionary"); + } + } + obj1.free(); + + xMin = yMin = xMax = yMax = 0; + hasBBox = gFalse; + if (dict->lookup("BBox", &obj1)->isArray()) { + if (obj1.arrayGetLength() == 4) { + hasBBox = gTrue; + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + yMin = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + } else { + error(-1, "Bad BBox in shading dictionary"); + } + } + obj1.free(); + + return gTrue; +} + +//------------------------------------------------------------------------ +// GfxFunctionShading +//------------------------------------------------------------------------ + +GfxFunctionShading::GfxFunctionShading(double x0A, double y0A, + double x1A, double y1A, + double *matrixA, + Function **funcsA, int nFuncsA): + GfxShading(1) +{ + int i; + + x0 = x0A; + y0 = y0A; + x1 = x1A; + y1 = y1A; + for (i = 0; i < 6; ++i) { + matrix[i] = matrixA[i]; + } + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + x1 = shading->x1; + y1 = shading->y1; + for (i = 0; i < 6; ++i) { + matrix[i] = shading->matrix[i]; + } + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxFunctionShading::~GfxFunctionShading() { + int i; + + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) { + GfxFunctionShading *shading; + double x0A, y0A, x1A, y1A; + double matrixA[6]; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + Object obj1, obj2; + int i; + + x0A = y0A = 0; + x1A = y1A = 1; + if (dict->lookup("Domain", &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(); + } + obj1.free(); + + matrixA[0] = 1; matrixA[1] = 0; + matrixA[2] = 0; matrixA[3] = 1; + matrixA[4] = 0; matrixA[5] = 0; + if (dict->lookup("Matrix", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + matrixA[0] = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + matrixA[1] = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + matrixA[2] = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + matrixA[3] = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + matrixA[4] = obj1.arrayGet(4, &obj2)->getNum(); + obj2.free(); + matrixA[5] = obj1.arrayGet(5, &obj2)->getNum(); + obj2.free(); + } + obj1.free(); + + dict->lookup("Function", &obj1); + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + for (i = 0; i < nFuncsA; ++i) { + obj1.arrayGet(i, &obj2); + if (!(funcsA[i] = Function::parse(&obj2))) { + goto err2; + } + obj2.free(); + } + } else { + nFuncsA = 1; + if (!(funcsA[0] = Function::parse(&obj1))) { + goto err1; + } + } + obj1.free(); + + shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err2: + obj2.free(); + err1: + obj1.free(); + return NULL; +} + +GfxShading *GfxFunctionShading::copy() { + return new GfxFunctionShading(this); +} + +void GfxFunctionShading::getColor(double x, double y, GfxColor *color) { + double in[2], out[gfxColorMaxComps]; + int i; + + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } + in[0] = x; + in[1] = y; + for (i = 0; i < nFuncs; ++i) { + funcs[i]->transform(in, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); + } +} + +//------------------------------------------------------------------------ +// GfxAxialShading +//------------------------------------------------------------------------ + +GfxAxialShading::GfxAxialShading(double x0A, double y0A, + double x1A, double y1A, + double t0A, double t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A): + GfxShading(2) +{ + 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(GfxAxialShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + x1 = shading->x1; + y1 = shading->y1; + t0 = shading->t0; + y1 = shading->t1; + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } + extend0 = shading->extend0; + extend1 = shading->extend1; +} + +GfxAxialShading::~GfxAxialShading() { + int i; + + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxAxialShading *GfxAxialShading::parse(Dict *dict) { + GfxAxialShading *shading; + 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(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + 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(); + + 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(); + + shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, + funcsA, nFuncsA, extend0A, extend1A); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err1: + return NULL; +} + +GfxShading *GfxAxialShading::copy() { + return new GfxAxialShading(this); +} + +void GfxAxialShading::getColor(double t, GfxColor *color) { + double out[gfxColorMaxComps]; + int i; + + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } + for (i = 0; i < nFuncs; ++i) { + funcs[i]->transform(&t, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); + } +} + +//------------------------------------------------------------------------ +// GfxRadialShading +//------------------------------------------------------------------------ + +GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A, + double x1A, double y1A, double r1A, + double t0A, double t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A): + GfxShading(3) +{ + int i; + + x0 = x0A; + y0 = y0A; + r0 = r0A; + x1 = x1A; + y1 = y1A; + r1 = r1A; + t0 = t0A; + t1 = t1A; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } + extend0 = extend0A; + extend1 = extend1A; +} + +GfxRadialShading::GfxRadialShading(GfxRadialShading *shading): + GfxShading(shading) +{ + int i; + + x0 = shading->x0; + y0 = shading->y0; + r0 = shading->r0; + x1 = shading->x1; + y1 = shading->y1; + r1 = shading->r1; + t0 = shading->t0; + y1 = shading->t1; + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } + extend0 = shading->extend0; + extend1 = shading->extend1; +} + +GfxRadialShading::~GfxRadialShading() { + int i; + + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxRadialShading *GfxRadialShading::parse(Dict *dict) { + GfxRadialShading *shading; + double x0A, y0A, r0A, x1A, y1A, r1A; + double t0A, t1A; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + GBool extend0A, extend1A; + Object obj1, obj2; + int i; + + x0A = y0A = r0A = x1A = y1A = r1A = 0; + if (dict->lookup("Coords", &obj1)->isArray() && + obj1.arrayGetLength() == 6) { + x0A = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + y0A = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + r0A = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + x1A = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + y1A = obj1.arrayGet(4, &obj2)->getNum(); + obj2.free(); + r1A = obj1.arrayGet(5, &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(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + 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(); + + 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(); + + shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, + funcsA, nFuncsA, extend0A, extend1A); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err1: + return NULL; +} + +GfxShading *GfxRadialShading::copy() { + return new GfxRadialShading(this); +} + +void GfxRadialShading::getColor(double t, GfxColor *color) { + double out[gfxColorMaxComps]; + int i; + + // NB: there can be one function with n outputs or n functions with + // one output each (where n = number of color components) + for (i = 0; i < gfxColorMaxComps; ++i) { + out[i] = 0; + } + for (i = 0; i < nFuncs; ++i) { + funcs[i]->transform(&t, &out[i]); + } + for (i = 0; i < gfxColorMaxComps; ++i) { + color->c[i] = dblToCol(out[i]); + } +} + +//------------------------------------------------------------------------ +// GfxShadingBitBuf +//------------------------------------------------------------------------ + +class GfxShadingBitBuf { +public: + + GfxShadingBitBuf(Stream *strA); + ~GfxShadingBitBuf(); + GBool getBits(int n, Guint *val); + void flushBits(); + +private: + + Stream *str; + int bitBuf; + int nBits; +}; + +GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) { + str = strA; + str->reset(); + bitBuf = 0; + nBits = 0; +} + +GfxShadingBitBuf::~GfxShadingBitBuf() { + str->close(); +} + +GBool GfxShadingBitBuf::getBits(int n, Guint *val) { + int x; + + if (nBits >= n) { + x = (bitBuf >> (nBits - n)) & ((1 << n) - 1); + nBits -= n; + } else { + x = 0; + if (nBits > 0) { + x = bitBuf & ((1 << nBits) - 1); + n -= nBits; + nBits = 0; + } + while (n > 0) { + if ((bitBuf = str->getChar()) == EOF) { + nBits = 0; + return gFalse; + } + if (n >= 8) { + x = (x << 8) | bitBuf; + n -= 8; + } else { + x = (x << n) | (bitBuf >> (8 - n)); + nBits = 8 - n; + n = 0; + } + } + } + *val = x; + return gTrue; +} + +void GfxShadingBitBuf::flushBits() { + bitBuf = 0; + nBits = 0; +} + +//------------------------------------------------------------------------ +// GfxGouraudTriangleShading +//------------------------------------------------------------------------ + +GfxGouraudTriangleShading::GfxGouraudTriangleShading( + int typeA, + GfxGouraudVertex *verticesA, int nVerticesA, + int (*trianglesA)[3], int nTrianglesA, + Function **funcsA, int nFuncsA): + GfxShading(typeA) +{ + int i; + + vertices = verticesA; + nVertices = nVerticesA; + triangles = trianglesA; + nTriangles = nTrianglesA; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxGouraudTriangleShading::GfxGouraudTriangleShading( + GfxGouraudTriangleShading *shading): + GfxShading(shading) +{ + int i; + + nVertices = shading->nVertices; + vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex)); + memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex)); + nTriangles = shading->nTriangles; + triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int)); + memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int)); + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxGouraudTriangleShading::~GfxGouraudTriangleShading() { + int i; + + gfree(vertices); + gfree(triangles); + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA, + Dict *dict, + Stream *str) { + GfxGouraudTriangleShading *shading; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + int coordBits, compBits, flagBits, vertsPerRow, nRows; + double xMin, xMax, yMin, yMax; + double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; + double xMul, yMul; + double cMul[gfxColorMaxComps]; + GfxGouraudVertex *verticesA; + int (*trianglesA)[3]; + int nComps, nVerticesA, nTrianglesA, vertSize, triSize; + Guint x, y, flag; + Guint c[gfxColorMaxComps]; + GfxShadingBitBuf *bitBuf; + Object obj1, obj2; + int i, j, k, state; + + if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { + coordBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { + compBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerComponent in shading dictionary"); + goto err2; + } + obj1.free(); + flagBits = vertsPerRow = 0; // make gcc happy + if (typeA == 4) { + if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { + flagBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerFlag in shading dictionary"); + goto err2; + } + obj1.free(); + } else { + if (dict->lookup("VerticesPerRow", &obj1)->isInt()) { + vertsPerRow = obj1.getInt(); + } else { + error(-1, "Missing or invalid VerticesPerRow in shading dictionary"); + goto err2; + } + obj1.free(); + } + if (dict->lookup("Decode", &obj1)->isArray() && + obj1.arrayGetLength() >= 6) { + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); + yMin = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); + for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { + cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); + obj2.free(); + cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); + obj2.free(); + cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); + } + nComps = i; + } else { + error(-1, "Missing or invalid Decode array in shading dictionary"); + goto err2; + } + obj1.free(); + + if (!dict->lookup("Function", &obj1)->isNull()) { + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + 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; + } + } + } else { + nFuncsA = 0; + } + obj1.free(); + + nVerticesA = nTrianglesA = 0; + verticesA = NULL; + trianglesA = NULL; + vertSize = triSize = 0; + state = 0; + flag = 0; // make gcc happy + bitBuf = new GfxShadingBitBuf(str); + while (1) { + if (typeA == 4) { + if (!bitBuf->getBits(flagBits, &flag)) { + break; + } + } + if (!bitBuf->getBits(coordBits, &x) || + !bitBuf->getBits(coordBits, &y)) { + break; + } + for (i = 0; i < nComps; ++i) { + if (!bitBuf->getBits(compBits, &c[i])) { + break; + } + } + if (i < nComps) { + break; + } + if (nVerticesA == vertSize) { + vertSize = (vertSize == 0) ? 16 : 2 * vertSize; + verticesA = (GfxGouraudVertex *) + greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex)); + } + verticesA[nVerticesA].x = xMin + xMul * (double)x; + verticesA[nVerticesA].y = yMin + yMul * (double)y; + for (i = 0; i < nComps; ++i) { + verticesA[nVerticesA].color.c[i] = + dblToCol(cMin[i] + cMul[i] * (double)c[i]); + } + ++nVerticesA; + bitBuf->flushBits(); + if (typeA == 4) { + if (state == 0 || state == 1) { + ++state; + } else if (state == 2 || flag > 0) { + if (nTrianglesA == triSize) { + triSize = (triSize == 0) ? 16 : 2 * triSize; + trianglesA = (int (*)[3]) + greallocn(trianglesA, triSize * 3, sizeof(int)); + } + if (state == 2) { + trianglesA[nTrianglesA][0] = nVerticesA - 3; + trianglesA[nTrianglesA][1] = nVerticesA - 2; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + ++state; + } else if (flag == 1) { + trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1]; + trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + } else { // flag == 2 + trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0]; + trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; + trianglesA[nTrianglesA][2] = nVerticesA - 1; + } + ++nTrianglesA; + } else { // state == 3 && flag == 0 + state = 1; + } + } + } + delete bitBuf; + if (typeA == 5) { + nRows = nVerticesA / vertsPerRow; + nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1); + trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int)); + k = 0; + for (i = 0; i < nRows - 1; ++i) { + for (j = 0; j < vertsPerRow - 1; ++j) { + trianglesA[k][0] = i * vertsPerRow + j; + trianglesA[k][1] = i * vertsPerRow + j+1; + trianglesA[k][2] = (i+1) * vertsPerRow + j; + ++k; + trianglesA[k][0] = i * vertsPerRow + j+1; + trianglesA[k][1] = (i+1) * vertsPerRow + j; + trianglesA[k][2] = (i+1) * vertsPerRow + j+1; + ++k; + } + } + } + + shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA, + trianglesA, nTrianglesA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err2: + obj1.free(); + err1: + return NULL; +} + +GfxShading *GfxGouraudTriangleShading::copy() { + return new GfxGouraudTriangleShading(this); +} + +void GfxGouraudTriangleShading::getTriangle( + int i, + double *x0, double *y0, GfxColor *color0, + double *x1, double *y1, GfxColor *color1, + double *x2, double *y2, GfxColor *color2) { + double in; + double out[gfxColorMaxComps]; + int v, j; + + v = triangles[i][0]; + *x0 = vertices[v].x; + *y0 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color0->c[j] = dblToCol(out[j]); + } + } else { + *color0 = vertices[v].color; + } + v = triangles[i][1]; + *x1 = vertices[v].x; + *y1 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color1->c[j] = dblToCol(out[j]); + } + } else { + *color1 = vertices[v].color; + } + v = triangles[i][2]; + *x2 = vertices[v].x; + *y2 = vertices[v].y; + if (nFuncs > 0) { + in = colToDbl(vertices[v].color.c[0]); + for (j = 0; j < nFuncs; ++j) { + funcs[j]->transform(&in, &out[j]); + } + for (j = 0; j < gfxColorMaxComps; ++j) { + color2->c[j] = dblToCol(out[j]); + } + } else { + *color2 = vertices[v].color; + } +} + +//------------------------------------------------------------------------ +// GfxPatchMeshShading +//------------------------------------------------------------------------ + +GfxPatchMeshShading::GfxPatchMeshShading(int typeA, + GfxPatch *patchesA, int nPatchesA, + Function **funcsA, int nFuncsA): + GfxShading(typeA) +{ + int i; + + patches = patchesA; + nPatches = nPatchesA; + nFuncs = nFuncsA; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = funcsA[i]; + } +} + +GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading): + GfxShading(shading) +{ + int i; + + nPatches = shading->nPatches; + patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch)); + memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch)); + nFuncs = shading->nFuncs; + for (i = 0; i < nFuncs; ++i) { + funcs[i] = shading->funcs[i]->copy(); + } +} + +GfxPatchMeshShading::~GfxPatchMeshShading() { + int i; + + gfree(patches); + for (i = 0; i < nFuncs; ++i) { + delete funcs[i]; + } +} + +GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, + Stream *str) { + GfxPatchMeshShading *shading; + Function *funcsA[gfxColorMaxComps]; + int nFuncsA; + int coordBits, compBits, flagBits; + double xMin, xMax, yMin, yMax; + double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; + double xMul, yMul; + double cMul[gfxColorMaxComps]; + GfxPatch *patchesA, *p; + int nComps, nPatchesA, patchesSize, nPts, nColors; + Guint flag; + double x[16], y[16]; + Guint xi, yi; + GfxColorComp c[4][gfxColorMaxComps]; + Guint ci[4]; + GfxShadingBitBuf *bitBuf; + Object obj1, obj2; + int i, j; + + if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { + coordBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerCoordinate in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { + compBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerComponent in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { + flagBits = obj1.getInt(); + } else { + error(-1, "Missing or invalid BitsPerFlag in shading dictionary"); + goto err2; + } + obj1.free(); + if (dict->lookup("Decode", &obj1)->isArray() && + obj1.arrayGetLength() >= 6) { + xMin = obj1.arrayGet(0, &obj2)->getNum(); + obj2.free(); + xMax = obj1.arrayGet(1, &obj2)->getNum(); + obj2.free(); + xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); + yMin = obj1.arrayGet(2, &obj2)->getNum(); + obj2.free(); + yMax = obj1.arrayGet(3, &obj2)->getNum(); + obj2.free(); + yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); + for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { + cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); + obj2.free(); + cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); + obj2.free(); + cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); + } + nComps = i; + } else { + error(-1, "Missing or invalid Decode array in shading dictionary"); + goto err2; + } + obj1.free(); + + if (!dict->lookup("Function", &obj1)->isNull()) { + if (obj1.isArray()) { + nFuncsA = obj1.arrayGetLength(); + if (nFuncsA > gfxColorMaxComps) { + error(-1, "Invalid Function array in shading dictionary"); + goto err1; + } + 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; + } + } + } else { + nFuncsA = 0; + } + obj1.free(); + + nPatchesA = 0; + patchesA = NULL; + patchesSize = 0; + bitBuf = new GfxShadingBitBuf(str); + while (1) { + if (!bitBuf->getBits(flagBits, &flag)) { + break; + } + if (typeA == 6) { + switch (flag) { + case 0: nPts = 12; nColors = 4; break; + case 1: + case 2: + case 3: + default: nPts = 8; nColors = 2; break; + } + } else { + switch (flag) { + case 0: nPts = 16; nColors = 4; break; + case 1: + case 2: + case 3: + default: nPts = 12; nColors = 2; break; + } + } + for (i = 0; i < nPts; ++i) { + if (!bitBuf->getBits(coordBits, &xi) || + !bitBuf->getBits(coordBits, &yi)) { + break; + } + x[i] = xMin + xMul * (double)xi; + y[i] = yMin + yMul * (double)yi; + } + if (i < nPts) { + break; + } + for (i = 0; i < nColors; ++i) { + for (j = 0; j < nComps; ++j) { + if (!bitBuf->getBits(compBits, &ci[j])) { + break; + } + c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci[j]); + } + if (j < nComps) { + break; + } + } + if (i < nColors) { + break; + } + if (nPatchesA == patchesSize) { + patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize; + patchesA = (GfxPatch *)greallocn(patchesA, + patchesSize, sizeof(GfxPatch)); + } + p = &patchesA[nPatchesA]; + if (typeA == 6) { + switch (flag) { + case 0: + p->x[0][0] = x[0]; + p->y[0][0] = y[0]; + p->x[0][1] = x[1]; + p->y[0][1] = y[1]; + p->x[0][2] = x[2]; + p->y[0][2] = y[2]; + p->x[0][3] = x[3]; + p->y[0][3] = y[3]; + p->x[1][3] = x[4]; + p->y[1][3] = y[4]; + p->x[2][3] = x[5]; + p->y[2][3] = y[5]; + p->x[3][3] = x[6]; + p->y[3][3] = y[6]; + p->x[3][2] = x[7]; + p->y[3][2] = y[7]; + p->x[3][1] = x[8]; + p->y[3][1] = y[8]; + p->x[3][0] = x[9]; + p->y[3][0] = y[9]; + p->x[2][0] = x[10]; + p->y[2][0] = y[10]; + p->x[1][0] = x[11]; + p->y[1][0] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = c[0][j]; + p->color[0][1].c[j] = c[1][j]; + p->color[1][1].c[j] = c[2][j]; + p->color[1][0].c[j] = c[3][j]; + } + break; + case 1: + p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; + p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; + p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; + p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 2: + p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; + p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; + p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; + p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 3: + p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; + p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; + p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; + p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; + p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; + p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + for (j = 0; j < nComps; ++j) { + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + } + } else { + switch (flag) { + case 0: + p->x[0][0] = x[0]; + p->y[0][0] = y[0]; + p->x[0][1] = x[1]; + p->y[0][1] = y[1]; + p->x[0][2] = x[2]; + p->y[0][2] = y[2]; + p->x[0][3] = x[3]; + p->y[0][3] = y[3]; + p->x[1][3] = x[4]; + p->y[1][3] = y[4]; + p->x[2][3] = x[5]; + p->y[2][3] = y[5]; + p->x[3][3] = x[6]; + p->y[3][3] = y[6]; + p->x[3][2] = x[7]; + p->y[3][2] = y[7]; + p->x[3][1] = x[8]; + p->y[3][1] = y[8]; + p->x[3][0] = x[9]; + p->y[3][0] = y[9]; + p->x[2][0] = x[10]; + p->y[2][0] = y[10]; + p->x[1][0] = x[11]; + p->y[1][0] = y[11]; + p->x[1][1] = x[12]; + p->y[1][1] = y[12]; + p->x[1][2] = x[13]; + p->y[1][2] = y[13]; + p->x[2][2] = x[14]; + p->y[2][2] = y[14]; + p->x[2][1] = x[15]; + p->y[2][1] = y[15]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = c[0][j]; + p->color[0][1].c[j] = c[1][j]; + p->color[1][1].c[j] = c[2][j]; + p->color[1][0].c[j] = c[3][j]; + } + break; + case 1: + p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; + p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; + p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; + p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 2: + p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; + p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; + p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; + p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; + p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; + p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + case 3: + p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; + p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; + p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; + p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; + p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; + p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; + p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; + p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; + p->x[1][3] = x[0]; + p->y[1][3] = y[0]; + p->x[2][3] = x[1]; + p->y[2][3] = y[1]; + p->x[3][3] = x[2]; + p->y[3][3] = y[2]; + p->x[3][2] = x[3]; + p->y[3][2] = y[3]; + p->x[3][1] = x[4]; + p->y[3][1] = y[4]; + p->x[3][0] = x[5]; + p->y[3][0] = y[5]; + p->x[2][0] = x[6]; + p->y[2][0] = y[6]; + p->x[1][0] = x[7]; + p->y[1][0] = y[7]; + p->x[1][1] = x[8]; + p->y[1][1] = y[8]; + p->x[1][2] = x[9]; + p->y[1][2] = y[9]; + p->x[2][2] = x[10]; + p->y[2][2] = y[10]; + p->x[2][1] = x[11]; + p->y[2][1] = y[11]; + for (j = 0; j < nComps; ++j) { + p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; + p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; + p->color[1][1].c[j] = c[0][j]; + p->color[1][0].c[j] = c[1][j]; + } + break; + } + } + ++nPatchesA; + bitBuf->flushBits(); + } + delete bitBuf; + + if (typeA == 6) { + for (i = 0; i < nPatchesA; ++i) { + p = &patchesA[i]; + p->x[1][1] = (-4 * p->x[0][0] + +6 * (p->x[0][1] + p->x[1][0]) + -2 * (p->x[0][3] + p->x[3][0]) + +3 * (p->x[3][1] + p->x[1][3]) + - p->x[3][3]) / 9; + p->y[1][1] = (-4 * p->y[0][0] + +6 * (p->y[0][1] + p->y[1][0]) + -2 * (p->y[0][3] + p->y[3][0]) + +3 * (p->y[3][1] + p->y[1][3]) + - p->y[3][3]) / 9; + p->x[1][2] = (-4 * p->x[0][3] + +6 * (p->x[0][2] + p->x[1][3]) + -2 * (p->x[0][0] + p->x[3][3]) + +3 * (p->x[3][2] + p->x[1][0]) + - p->x[3][0]) / 9; + p->y[1][2] = (-4 * p->y[0][3] + +6 * (p->y[0][2] + p->y[1][3]) + -2 * (p->y[0][0] + p->y[3][3]) + +3 * (p->y[3][2] + p->y[1][0]) + - p->y[3][0]) / 9; + p->x[2][1] = (-4 * p->x[3][0] + +6 * (p->x[3][1] + p->x[2][0]) + -2 * (p->x[3][3] + p->x[0][0]) + +3 * (p->x[0][1] + p->x[2][3]) + - p->x[0][3]) / 9; + p->y[2][1] = (-4 * p->y[3][0] + +6 * (p->y[3][1] + p->y[2][0]) + -2 * (p->y[3][3] + p->y[0][0]) + +3 * (p->y[0][1] + p->y[2][3]) + - p->y[0][3]) / 9; + p->x[2][2] = (-4 * p->x[3][3] + +6 * (p->x[3][2] + p->x[2][3]) + -2 * (p->x[3][0] + p->x[0][3]) + +3 * (p->x[0][2] + p->x[2][0]) + - p->x[0][0]) / 9; + p->y[2][2] = (-4 * p->y[3][3] + +6 * (p->y[3][2] + p->y[2][3]) + -2 * (p->y[3][0] + p->y[0][3]) + +3 * (p->y[0][2] + p->y[2][0]) + - p->y[0][0]) / 9; + } + } + + shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA, + funcsA, nFuncsA); + if (!shading->init(dict)) { + delete shading; + return NULL; + } + return shading; + + err2: + obj1.free(); + err1: + return NULL; +} + +GfxShading *GfxPatchMeshShading::copy() { + return new GfxPatchMeshShading(this); +} + +//------------------------------------------------------------------------ +// 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; + } + + // 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. + for (k = 0; k < gfxColorMaxComps; ++k) { + lookup[k] = NULL; + } + 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(); + lookup2 = indexedCS->getLookup(); + colorSpace2->getDefaultRanges(x, y, indexHigh); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); + for (i = 0; i <= maxPixel; ++i) { + j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); + if (j < 0) { + j = 0; + } else if (j > indexHigh) { + j = indexHigh; + } + lookup[k][i] = + dblToCol(x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]); + } + } + } else if (colorSpace->getMode() == csSeparation) { + sepCS = (GfxSeparationColorSpace *)colorSpace; + colorSpace2 = sepCS->getAlt(); + nComps2 = colorSpace2->getNComps(); + sepFunc = sepCS->getFunc(); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); + for (i = 0; i <= maxPixel; ++i) { + x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; + sepFunc->transform(x, y); + lookup[k][i] = dblToCol(y[k]); + } + } + } else { + for (k = 0; k < nComps; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, + sizeof(GfxColorComp)); + for (i = 0; i <= maxPixel; ++i) { + lookup[k][i] = dblToCol(decodeLow[k] + + (i * decodeRange[k]) / maxPixel); + } + } + } + + return; + + err2: + obj.free(); + err1: + ok = gFalse; +} + +GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { + int n, i, k; + + colorSpace = colorMap->colorSpace->copy(); + bits = colorMap->bits; + nComps = colorMap->nComps; + nComps2 = colorMap->nComps2; + colorSpace2 = NULL; + for (k = 0; k < gfxColorMaxComps; ++k) { + lookup[k] = NULL; + } + n = 1 << bits; + if (colorSpace->getMode() == csIndexed) { + colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase(); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } + } else if (colorSpace->getMode() == csSeparation) { + colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt(); + for (k = 0; k < nComps2; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } + } else { + for (k = 0; k < nComps; ++k) { + lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); + memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); + } + } + for (i = 0; i < nComps; ++i) { + decodeLow[i] = colorMap->decodeLow[i]; + decodeRange[i] = colorMap->decodeRange[i]; + } + ok = gTrue; +} + +GfxImageColorMap::~GfxImageColorMap() { + int i; + + delete colorSpace; + for (i = 0; i < gfxColorMaxComps; ++i) { + gfree(lookup[i]); + } +} + +void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) { + GfxColor color; + int i; + + if (colorSpace2) { + for (i = 0; i < nComps2; ++i) { + color.c[i] = lookup[i][x[0]]; + } + colorSpace2->getGray(&color, gray); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[i][x[i]]; + } + colorSpace->getGray(&color, gray); + } +} + +void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { + GfxColor color; + int i; + + if (colorSpace2) { + for (i = 0; i < nComps2; ++i) { + color.c[i] = lookup[i][x[0]]; + } + colorSpace2->getRGB(&color, rgb); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[i][x[i]]; + } + colorSpace->getRGB(&color, rgb); + } +} + +void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { + GfxColor color; + int i; + + if (colorSpace2) { + for (i = 0; i < nComps2; ++i) { + color.c[i] = lookup[i][x[0]]; + } + colorSpace2->getCMYK(&color, cmyk); + } else { + for (i = 0; i < nComps; ++i) { + color.c[i] = lookup[i][x[i]]; + } + colorSpace->getCMYK(&color, cmyk); + } +} + +void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { + int maxPixel, i; + + maxPixel = (1 << bits) - 1; + for (i = 0; i < nComps; ++i) { + color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel); + } +} + +//------------------------------------------------------------------------ +// GfxSubpath and GfxPath +//------------------------------------------------------------------------ + +GfxSubpath::GfxSubpath(double x1, double y1) { + size = 16; + x = (double *)gmallocn(size, sizeof(double)); + y = (double *)gmallocn(size, sizeof(double)); + curve = (GBool *)gmallocn(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 *)gmallocn(size, sizeof(double)); + y = (double *)gmallocn(size, sizeof(double)); + curve = (GBool *)gmallocn(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 *)greallocn(x, size, sizeof(double)); + y = (double *)greallocn(y, size, sizeof(double)); + curve = (GBool *)greallocn(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 *)greallocn(x, size, sizeof(double)); + y = (double *)greallocn(y, size, sizeof(double)); + curve = (GBool *)greallocn(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; +} + +void GfxSubpath::offset(double dx, double dy) { + int i; + + for (i = 0; i < n; ++i) { + x[i] += dx; + y[i] += dy; + } +} + +GfxPath::GfxPath() { + justMoved = gFalse; + size = 16; + n = 0; + firstX = firstY = 0; + subpaths = (GfxSubpath **)gmallocn(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 **)gmallocn(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 **) + greallocn(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 **) + greallocn(subpaths, size, sizeof(GfxSubpath *)); + } + subpaths[n] = new GfxSubpath(firstX, firstY); + ++n; + justMoved = gFalse; + } + subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3); +} + +void GfxPath::close() { + // this is necessary to handle the pathological case of + // moveto/closepath/clip, which defines an empty clipping region + if (justMoved) { + if (n >= size) { + size += 16; + subpaths = (GfxSubpath **) + greallocn(subpaths, size, sizeof(GfxSubpath *)); + } + subpaths[n] = new GfxSubpath(firstX, firstY); + ++n; + justMoved = gFalse; + } + subpaths[n-1]->close(); +} + +void GfxPath::append(GfxPath *path) { + int i; + + if (n + path->n > size) { + size = n + path->n; + subpaths = (GfxSubpath **) + greallocn(subpaths, size, sizeof(GfxSubpath *)); + } + for (i = 0; i < path->n; ++i) { + subpaths[n++] = path->subpaths[i]->copy(); + } + justMoved = gFalse; +} + +void GfxPath::offset(double dx, double dy) { + int i; + + for (i = 0; i < n; ++i) { + subpaths[i]->offset(dx, dy); + } +} + +//------------------------------------------------------------------------ +// GfxState +//------------------------------------------------------------------------ + +GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, + int rotateA, GBool upsideDown) { + double kx, ky; + + rotate = rotateA; + px1 = pageBox->x1; + py1 = pageBox->y1; + px2 = pageBox->x2; + py2 = pageBox->y2; + kx = hDPI / 72.0; + ky = vDPI / 72.0; + if (rotate == 90) { + ctm[0] = 0; + ctm[1] = upsideDown ? ky : -ky; + ctm[2] = kx; + ctm[3] = 0; + ctm[4] = -kx * py1; + ctm[5] = ky * (upsideDown ? -px1 : px2); + pageWidth = kx * (py2 - py1); + pageHeight = ky * (px2 - px1); + } else if (rotate == 180) { + ctm[0] = -kx; + ctm[1] = 0; + ctm[2] = 0; + ctm[3] = upsideDown ? ky : -ky; + ctm[4] = kx * px2; + ctm[5] = ky * (upsideDown ? -py1 : py2); + pageWidth = kx * (px2 - px1); + pageHeight = ky * (py2 - py1); + } else if (rotate == 270) { + ctm[0] = 0; + ctm[1] = upsideDown ? -ky : ky; + ctm[2] = -kx; + ctm[3] = 0; + ctm[4] = kx * py2; + ctm[5] = ky * (upsideDown ? px2 : -px1); + pageWidth = kx * (py2 - py1); + pageHeight = ky * (px2 - px1); + } else { + ctm[0] = kx; + ctm[1] = 0; + ctm[2] = 0; + ctm[3] = upsideDown ? -ky : ky; + ctm[4] = -kx * px1; + ctm[5] = ky * (upsideDown ? py2 : -py1); + pageWidth = kx * (px2 - px1); + pageHeight = ky * (py2 - py1); + } + + fillColorSpace = new GfxDeviceGrayColorSpace(); + strokeColorSpace = new GfxDeviceGrayColorSpace(); + fillColor.c[0] = 0; + strokeColor.c[0] = 0; + fillPattern = NULL; + strokePattern = NULL; + blendMode = gfxBlendNormal; + fillOpacity = 1; + strokeOpacity = 1; + fillOverprint = gFalse; + strokeOverprint = gFalse; + + lineWidth = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashStart = 0; + flatness = 1; + 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); + if (path) { + // this gets set to NULL by restore() + 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 *)gmallocn(lineDashLength, sizeof(double)); + memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double)); + } + saved = NULL; +} + +void GfxState::setPath(GfxPath *pathA) { + delete path; + path = pathA; +} + +void GfxState::getUserClipBBox(double *xMin, double *yMin, + double *xMax, double *yMax) { + double ictm[6]; + double xMin1, yMin1, xMax1, yMax1, det, tx, ty; + + // invert the 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; + + // transform all four corners of the clip bbox; find the min and max + // x and y values + xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4]; + yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5]; + tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4]; + ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5]; + if (tx < xMin1) { + xMin1 = tx; + } else if (tx > xMax1) { + xMax1 = tx; + } + if (ty < yMin1) { + yMin1 = ty; + } else if (ty > yMax1) { + yMax1 = ty; + } + tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4]; + ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5]; + if (tx < xMin1) { + xMin1 = tx; + } else if (tx > xMax1) { + xMax1 = tx; + } + if (ty < yMin1) { + yMin1 = ty; + } else if (ty > yMax1) { + yMax1 = ty; + } + tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4]; + ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5]; + if (tx < xMin1) { + xMin1 = tx; + } else if (tx > xMax1) { + xMax1 = tx; + } + if (ty < yMin1) { + yMin1 = ty; + } else if (ty > yMax1) { + yMax1 = ty; + } + + *xMin = xMin1; + *yMin = yMin1; + *xMax = xMax1; + *yMax = yMax1; +} + +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) { + int i; + + ctm[0] = a; + ctm[1] = b; + ctm[2] = c; + ctm[3] = d; + ctm[4] = e; + ctm[5] = f; + + // avoid FP exceptions on badly messed up PDF files + for (i = 0; i < 6; ++i) { + if (ctm[i] > 1e10) { + ctm[i] = 1e10; + } else if (ctm[i] < -1e10) { + ctm[i] = -1e10; + } + } +} + +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]; + int i; + + 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]; + + // avoid FP exceptions on badly messed up PDF files + for (i = 0; i < 6; ++i) { + if (ctm[i] > 1e10) { + ctm[i] = 1e10; + } else if (ctm[i] < -1e10) { + ctm[i] = -1e10; + } + } +} + +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 ty) { + double dx, dy; + + textTransformDelta(tx, ty, &dx, &dy); + curX += dx; + curY += dy; +} + +void GfxState::shift(double dx, double 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; + + // these attributes aren't saved/restored by the q/Q operators + oldState->path = path; + oldState->curX = curX; + oldState->curY = curY; + oldState->lineX = lineX; + oldState->lineY = lineY; + + path = NULL; + saved = NULL; + delete this; + + } else { + oldState = this; + } + + return oldState; +} + +GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) { + Object obj2; + int i, j; + + if (obj->isName()) { + for (i = 0; i < nGfxBlendModeNames; ++i) { + if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) { + *mode = gfxBlendModeNames[i].mode; + return gTrue; + } + } + return gFalse; + } else if (obj->isArray()) { + for (i = 0; i < obj->arrayGetLength(); ++i) { + obj->arrayGet(i, &obj2); + if (!obj2.isName()) { + obj2.free(); + return gFalse; + } + for (j = 0; j < nGfxBlendModeNames; ++j) { + if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) { + obj2.free(); + *mode = gfxBlendModeNames[j].mode; + return gTrue; + } + } + obj2.free(); + } + *mode = gfxBlendNormal; + return gTrue; + } else { + return gFalse; + } +} diff --git a/pdftops/GfxState.h b/pdftops/GfxState.h new file mode 100644 index 000000000..e5045b6c9 --- /dev/null +++ b/pdftops/GfxState.h @@ -0,0 +1,1206 @@ +//======================================================================== +// +// GfxState.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GFXSTATE_H +#define GFXSTATE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" +#include "Function.h" + +class Array; +class GfxFont; +class PDFRectangle; +class GfxShading; + +//------------------------------------------------------------------------ +// GfxBlendMode +//------------------------------------------------------------------------ + +enum GfxBlendMode { + gfxBlendNormal, + gfxBlendMultiply, + gfxBlendScreen, + gfxBlendOverlay, + gfxBlendDarken, + gfxBlendLighten, + gfxBlendColorDodge, + gfxBlendColorBurn, + gfxBlendHardLight, + gfxBlendSoftLight, + gfxBlendDifference, + gfxBlendExclusion, + gfxBlendHue, + gfxBlendSaturation, + gfxBlendColor, + gfxBlendLuminosity +}; + +//------------------------------------------------------------------------ +// GfxColorComp +//------------------------------------------------------------------------ + +// 16.16 fixed point color component +typedef int GfxColorComp; + +#define gfxColorComp1 0x10000 + +static inline GfxColorComp dblToCol(double x) { + return (GfxColorComp)(x * gfxColorComp1); +} + +static inline double colToDbl(GfxColorComp x) { + return (double)x / (double)gfxColorComp1; +} + +static inline GfxColorComp byteToCol(Guchar x) { + // (x / 255) << 16 = (0.0000000100000001... * x) << 16 + // = ((x << 8) + (x) + (x >> 8) + ...) << 16 + // = (x << 8) + (x) + (x >> 7) + // [for rounding] + return (GfxColorComp)((x << 8) + x + (x >> 7)); +} + +static inline Guchar colToByte(GfxColorComp x) { + // 255 * x + 0.5 = 256 * x - x + 0x8000 + return (Guchar)(((x << 8) - x + 0x8000) >> 16); +} + +//------------------------------------------------------------------------ +// GfxColor +//------------------------------------------------------------------------ + +#define gfxColorMaxComps funcMaxOutputs + +struct GfxColor { + GfxColorComp c[gfxColorMaxComps]; +}; + +//------------------------------------------------------------------------ +// GfxGray +//------------------------------------------------------------------------ + +typedef GfxColorComp GfxGray; + +//------------------------------------------------------------------------ +// GfxRGB +//------------------------------------------------------------------------ + +struct GfxRGB { + GfxColorComp r, g, b; +}; + +//------------------------------------------------------------------------ +// GfxCMYK +//------------------------------------------------------------------------ + +struct GfxCMYK { + GfxColorComp c, m, y, k; +}; + +//------------------------------------------------------------------------ +// GfxColorSpace +//------------------------------------------------------------------------ + +// NB: The nGfxColorSpaceModes constant and the gfxColorSpaceModeNames +// array defined in GfxState.cc must match this enum. +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, GfxGray *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 . + virtual void getDefaultRanges(double *decodeLow, double *decodeRange, + int maxImgPixel); + + // Return the number of color space modes + static int getNumColorSpaceModes(); + + // Return the name of the th color space mode. + static char *getColorSpaceModeName(int idx); + +private: +}; + +//------------------------------------------------------------------------ +// GfxDeviceGrayColorSpace +//------------------------------------------------------------------------ + +class GfxDeviceGrayColorSpace: public GfxColorSpace { +public: + + GfxDeviceGrayColorSpace(); + virtual ~GfxDeviceGrayColorSpace(); + virtual GfxColorSpace *copy(); + virtual GfxColorSpaceMode getMode() { return csDeviceGray; } + + virtual void getGray(GfxColor *color, GfxGray *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, GfxGray *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, GfxGray *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, GfxGray *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, GfxGray *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, GfxGray *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, GfxGray *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, GfxGray *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; } + GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor); + +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, GfxGray *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 nCompsA, 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, GfxGray *gray); + virtual void getRGB(GfxColor *color, GfxRGB *rgb); + virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); + + virtual int getNComps() { return nComps; } + + // DeviceN-specific access. + GString *getColorantName(int i) { return names[i]; } + GfxColorSpace *getAlt() { return alt; } + Function *getTintTransformFunc() { return func; } + +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, GfxGray *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: + + static GfxTilingPattern *parse(Object *patObj); + 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(int paintTypeA, int tilingTypeA, + double *bboxA, double xStepA, double yStepA, + Object *resDictA, double *matrixA, + Object *contentStreamA); + + int paintType; + int tilingType; + double bbox[4]; + double xStep, yStep; + Object resDict; + double matrix[6]; + Object contentStream; +}; + +//------------------------------------------------------------------------ +// GfxShadingPattern +//------------------------------------------------------------------------ + +class GfxShadingPattern: public GfxPattern { +public: + + static GfxShadingPattern *parse(Object *patObj); + virtual ~GfxShadingPattern(); + + virtual GfxPattern *copy(); + + GfxShading *getShading() { return shading; } + double *getMatrix() { return matrix; } + +private: + + GfxShadingPattern(GfxShading *shadingA, double *matrixA); + + GfxShading *shading; + double matrix[6]; +}; + +//------------------------------------------------------------------------ +// GfxShading +//------------------------------------------------------------------------ + +class GfxShading { +public: + + GfxShading(int typeA); + GfxShading(GfxShading *shading); + virtual ~GfxShading(); + + static GfxShading *parse(Object *obj); + + virtual GfxShading *copy() = 0; + + int getType() { return type; } + GfxColorSpace *getColorSpace() { return colorSpace; } + GfxColor *getBackground() { return &background; } + GBool getHasBackground() { return hasBackground; } + void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + GBool getHasBBox() { return hasBBox; } + +protected: + + GBool init(Dict *dict); + + int type; + GfxColorSpace *colorSpace; + GfxColor background; + GBool hasBackground; + double xMin, yMin, xMax, yMax; + GBool hasBBox; +}; + +//------------------------------------------------------------------------ +// GfxFunctionShading +//------------------------------------------------------------------------ + +class GfxFunctionShading: public GfxShading { +public: + + GfxFunctionShading(double x0A, double y0A, + double x1A, double y1A, + double *matrixA, + Function **funcsA, int nFuncsA); + GfxFunctionShading(GfxFunctionShading *shading); + virtual ~GfxFunctionShading(); + + static GfxFunctionShading *parse(Dict *dict); + + virtual GfxShading *copy(); + + void getDomain(double *x0A, double *y0A, double *x1A, double *y1A) + { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } + double *getMatrix() { return matrix; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double x, double y, GfxColor *color); + +private: + + double x0, y0, x1, y1; + double matrix[6]; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ +// 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); + GfxAxialShading(GfxAxialShading *shading); + virtual ~GfxAxialShading(); + + static GfxAxialShading *parse(Dict *dict); + + virtual GfxShading *copy(); + + 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; } + GBool getExtend0() { return extend0; } + GBool getExtend1() { return extend1; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double t, GfxColor *color); + +private: + + double x0, y0, x1, y1; + double t0, t1; + Function *funcs[gfxColorMaxComps]; + int nFuncs; + GBool extend0, extend1; +}; + +//------------------------------------------------------------------------ +// GfxRadialShading +//------------------------------------------------------------------------ + +class GfxRadialShading: public GfxShading { +public: + + GfxRadialShading(double x0A, double y0A, double r0A, + double x1A, double y1A, double r1A, + double t0A, double t1A, + Function **funcsA, int nFuncsA, + GBool extend0A, GBool extend1A); + GfxRadialShading(GfxRadialShading *shading); + virtual ~GfxRadialShading(); + + static GfxRadialShading *parse(Dict *dict); + + virtual GfxShading *copy(); + + void getCoords(double *x0A, double *y0A, double *r0A, + double *x1A, double *y1A, double *r1A) + { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; } + double getDomain0() { return t0; } + double getDomain1() { return t1; } + GBool getExtend0() { return extend0; } + GBool getExtend1() { return extend1; } + int getNFuncs() { return nFuncs; } + Function *getFunc(int i) { return funcs[i]; } + void getColor(double t, GfxColor *color); + +private: + + double x0, y0, r0, x1, y1, r1; + double t0, t1; + Function *funcs[gfxColorMaxComps]; + int nFuncs; + GBool extend0, extend1; +}; + +//------------------------------------------------------------------------ +// GfxGouraudTriangleShading +//------------------------------------------------------------------------ + +struct GfxGouraudVertex { + double x, y; + GfxColor color; +}; + +class GfxGouraudTriangleShading: public GfxShading { +public: + + GfxGouraudTriangleShading(int typeA, + GfxGouraudVertex *verticesA, int nVerticesA, + int (*trianglesA)[3], int nTrianglesA, + Function **funcsA, int nFuncsA); + GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading); + virtual ~GfxGouraudTriangleShading(); + + static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str); + + virtual GfxShading *copy(); + + int getNTriangles() { return nTriangles; } + void getTriangle(int i, double *x0, double *y0, GfxColor *color0, + double *x1, double *y1, GfxColor *color1, + double *x2, double *y2, GfxColor *color2); + +private: + + GfxGouraudVertex *vertices; + int nVertices; + int (*triangles)[3]; + int nTriangles; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ +// GfxPatchMeshShading +//------------------------------------------------------------------------ + +struct GfxPatch { + double x[4][4]; + double y[4][4]; + GfxColor color[2][2]; +}; + +class GfxPatchMeshShading: public GfxShading { +public: + + GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA, + Function **funcsA, int nFuncsA); + GfxPatchMeshShading(GfxPatchMeshShading *shading); + virtual ~GfxPatchMeshShading(); + + static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str); + + virtual GfxShading *copy(); + + int getNPatches() { return nPatches; } + GfxPatch *getPatch(int i) { return &patches[i]; } + +private: + + GfxPatch *patches; + int nPatches; + Function *funcs[gfxColorMaxComps]; + int nFuncs; +}; + +//------------------------------------------------------------------------ +// GfxImageColorMap +//------------------------------------------------------------------------ + +class GfxImageColorMap { +public: + + // Constructor. + GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA); + + // Destructor. + ~GfxImageColorMap(); + + // Return a copy of this color map. + GfxImageColorMap *copy() { return new GfxImageColorMap(this); } + + // 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, GfxGray *gray); + void getRGB(Guchar *x, GfxRGB *rgb); + void getCMYK(Guchar *x, GfxCMYK *cmyk); + void getColor(Guchar *x, GfxColor *color); + +private: + + GfxImageColorMap(GfxImageColorMap *colorMap); + + 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 + GfxColorComp * // lookup table + lookup[gfxColorMaxComps]; + 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; } + + // Add (, ) to each point in the subpath. + void offset(double dx, double dy); + +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(); + + // Append to . + void append(GfxPath *path); + + // Add (, ) to each point in the path. + void offset(double dx, double dy); + +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 + // x , page box , page rotation , and + // coordinate system specified by . + GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, + int rotateA, 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; } + int getRotate() { return rotate; } + GfxColor *getFillColor() { return &fillColor; } + GfxColor *getStrokeColor() { return &strokeColor; } + void getFillGray(GfxGray *gray) + { fillColorSpace->getGray(&fillColor, gray); } + void getStrokeGray(GfxGray *gray) + { strokeColorSpace->getGray(&strokeColor, 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; } + GfxBlendMode getBlendMode() { return blendMode; } + double getFillOpacity() { return fillOpacity; } + double getStrokeOpacity() { return strokeOpacity; } + GBool getFillOverprint() { return fillOverprint; } + GBool getStrokeOverprint() { return strokeOverprint; } + 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; } + void setPath(GfxPath *pathA); + 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; } + void getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax); + 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 setBlendMode(GfxBlendMode mode) { blendMode = mode; } + void setFillOpacity(double opac) { fillOpacity = opac; } + void setStrokeOpacity(double opac) { strokeOpacity = opac; } + void setFillOverprint(GBool op) { fillOverprint = op; } + void setStrokeOverprint(GBool op) { strokeOverprint = op; } + 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 textSetPos(double tx, double ty) { lineX = tx; lineY = ty; } + void textMoveTo(double tx, double ty) + { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); } + void textShift(double tx, double ty); + void shift(double dx, double dy); + + // Push/pop GfxState on/off stack. + GfxState *save(); + GfxState *restore(); + GBool hasSaves() { return saved != NULL; } + + // Misc + GBool parseBlendMode(Object *obj, GfxBlendMode *mode); + +private: + + double ctm[6]; // coord transform matrix + double px1, py1, px2, py2; // page corners (user coords) + double pageWidth, pageHeight; // page size (pixels) + int rotate; // page rotation angle + + 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 + GfxBlendMode blendMode; // transparency blend mode + double fillOpacity; // fill opacity + double strokeOpacity; // stroke opacity + GBool fillOverprint; // fill overprint + GBool strokeOverprint; // stroke overprint + + 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/GlobalParams.cxx b/pdftops/GlobalParams.cxx new file mode 100644 index 000000000..013e3d0b2 --- /dev/null +++ b/pdftops/GlobalParams.cxx @@ -0,0 +1,1995 @@ +//======================================================================== +// +// GlobalParams.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#ifdef ENABLE_PLUGINS +# ifndef WIN32 +# include +# endif +#endif +#ifdef WIN32 +# include +#endif +#if HAVE_PAPER_H +#include +#endif +#include "gmem.h" +#include "GString.h" +#include "GList.h" +#include "GHash.h" +#include "gfile.h" +#include "Error.h" +#include "NameToCharCode.h" +#include "CharCodeToUnicode.h" +#include "UnicodeMap.h" +#include "CMap.h" +#include "BuiltinFontTables.h" +#include "FontEncodingTables.h" +#ifdef ENABLE_PLUGINS +# include "XpdfPluginAPI.h" +#endif +#include "GlobalParams.h" + +#if MULTITHREADED +# define lockGlobalParams gLockMutex(&mutex) +# define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex) +# define lockCMapCache gLockMutex(&cMapCacheMutex) +# define unlockGlobalParams gUnlockMutex(&mutex) +# define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex) +# define unlockCMapCache gUnlockMutex(&cMapCacheMutex) +#else +# define lockGlobalParams +# define lockUnicodeMapCache +# define lockCMapCache +# define unlockGlobalParams +# define unlockUnicodeMapCache +# define unlockCMapCache +#endif + +#include "NameToUnicodeTable.h" +#include "UnicodeMapTables.h" +#include "UTF8.h" + +#ifdef ENABLE_PLUGINS +# ifdef WIN32 +extern XpdfPluginVecTable xpdfPluginVecTable; +# endif +#endif + +//------------------------------------------------------------------------ + +#define cidToUnicodeCacheSize 4 +#define unicodeToUnicodeCacheSize 4 + +//------------------------------------------------------------------------ + +static struct { + char *name; + char *t1FileName; + char *ttFileName; +} displayFontTab[] = { + {"Courier", "n022003l.pfb", "cour.ttf"}, + {"Courier-Bold", "n022004l.pfb", "courbd.ttf"}, + {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf"}, + {"Courier-Oblique", "n022023l.pfb", "couri.ttf"}, + {"Helvetica", "n019003l.pfb", "arial.ttf"}, + {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf"}, + {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"}, + {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf"}, + {"Symbol", "s050000l.pfb", NULL}, + {"Times-Bold", "n021004l.pfb", "timesbd.ttf"}, + {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf"}, + {"Times-Italic", "n021023l.pfb", "timesi.ttf"}, + {"Times-Roman", "n021003l.pfb", "times.ttf"}, + {"ZapfDingbats", "d050000l.pfb", NULL}, + {NULL} +}; + +#ifdef WIN32 +static char *displayFontDirs[] = { + "c:/windows/fonts", + "c:/winnt/fonts", + NULL +}; +#else +static char *displayFontDirs[] = { + "/usr/share/ghostscript/fonts", + "/usr/local/share/ghostscript/fonts", + "/usr/share/fonts/default/Type1", + "/usr/share/fonts/default/ghostscript", + "/usr/share/fonts/type1/gsfonts", + NULL +}; +#endif + +//------------------------------------------------------------------------ + +GlobalParams *globalParams = NULL; + +//------------------------------------------------------------------------ +// DisplayFontParam +//------------------------------------------------------------------------ + +DisplayFontParam::DisplayFontParam(GString *nameA, + DisplayFontParamKind kindA) { + name = nameA; + kind = kindA; + switch (kind) { + case displayFontT1: + t1.fileName = NULL; + break; + case displayFontTT: + tt.fileName = NULL; + break; + } +} + +DisplayFontParam::~DisplayFontParam() { + delete name; + switch (kind) { + case displayFontT1: + if (t1.fileName) { + delete t1.fileName; + } + break; + case displayFontTT: + if (tt.fileName) { + delete tt.fileName; + } + break; + } +} + +//------------------------------------------------------------------------ +// PSFontParam +//------------------------------------------------------------------------ + +PSFontParam::PSFontParam(GString *pdfFontNameA, int wModeA, + GString *psFontNameA, GString *encodingA) { + pdfFontName = pdfFontNameA; + wMode = wModeA; + psFontName = psFontNameA; + encoding = encodingA; +} + +PSFontParam::~PSFontParam() { + delete pdfFontName; + delete psFontName; + if (encoding) { + delete encoding; + } +} + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// Plugin +//------------------------------------------------------------------------ + +class Plugin { +public: + + static Plugin *load(char *type, char *name); + ~Plugin(); + +private: + +#ifdef WIN32 + Plugin(HMODULE libA); + HMODULE lib; +#else + Plugin(void *dlA); + void *dl; +#endif +}; + +Plugin *Plugin::load(char *type, char *name) { + GString *path; + Plugin *plugin; + XpdfPluginVecTable *vt; + XpdfBool (*xpdfInitPlugin)(void); +#ifdef WIN32 + HMODULE libA; +#else + void *dlA; +#endif + + path = globalParams->getBaseDir(); + appendToPath(path, "plugins"); + appendToPath(path, type); + appendToPath(path, name); + +#ifdef WIN32 + path->append(".dll"); + if (!(libA = LoadLibrary(path->getCString()))) { + error(-1, "Failed to load plugin '%s'", + path->getCString()); + goto err1; + } + if (!(vt = (XpdfPluginVecTable *) + GetProcAddress(libA, "xpdfPluginVecTable"))) { + error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'", + path->getCString()); + goto err2; + } +#else + //~ need to deal with other extensions here + path->append(".so"); + if (!(dlA = dlopen(path->getCString(), RTLD_NOW))) { + error(-1, "Failed to load plugin '%s': %s", + path->getCString(), dlerror()); + goto err1; + } + if (!(vt = (XpdfPluginVecTable *)dlsym(dlA, "xpdfPluginVecTable"))) { + error(-1, "Failed to find xpdfPluginVecTable in plugin '%s'", + path->getCString()); + goto err2; + } +#endif + + if (vt->version != xpdfPluginVecTable.version) { + error(-1, "Plugin '%s' is wrong version", path->getCString()); + goto err2; + } + memcpy(vt, &xpdfPluginVecTable, sizeof(xpdfPluginVecTable)); + +#ifdef WIN32 + if (!(xpdfInitPlugin = (XpdfBool (*)(void)) + GetProcAddress(libA, "xpdfInitPlugin"))) { + error(-1, "Failed to find xpdfInitPlugin in plugin '%s'", + path->getCString()); + goto err2; + } +#else + if (!(xpdfInitPlugin = (XpdfBool (*)(void))dlsym(dlA, "xpdfInitPlugin"))) { + error(-1, "Failed to find xpdfInitPlugin in plugin '%s'", + path->getCString()); + goto err2; + } +#endif + + if (!(*xpdfInitPlugin)()) { + error(-1, "Initialization of plugin '%s' failed", + path->getCString()); + goto err2; + } + +#ifdef WIN32 + plugin = new Plugin(libA); +#else + plugin = new Plugin(dlA); +#endif + + delete path; + return plugin; + + err2: +#ifdef WIN32 + FreeLibrary(libA); +#else + dlclose(dlA); +#endif + err1: + delete path; + return NULL; +} + +#ifdef WIN32 +Plugin::Plugin(HMODULE libA) { + lib = libA; +} +#else +Plugin::Plugin(void *dlA) { + dl = dlA; +} +#endif + +Plugin::~Plugin() { + void (*xpdfFreePlugin)(void); + +#ifdef WIN32 + if ((xpdfFreePlugin = (void (*)(void)) + GetProcAddress(lib, "xpdfFreePlugin"))) { + (*xpdfFreePlugin)(); + } + FreeLibrary(lib); +#else + if ((xpdfFreePlugin = (void (*)(void))dlsym(dl, "xpdfFreePlugin"))) { + (*xpdfFreePlugin)(); + } + dlclose(dl); +#endif +} + +#endif // ENABLE_PLUGINS + +//------------------------------------------------------------------------ +// parsing +//------------------------------------------------------------------------ + +GlobalParams::GlobalParams(char *cfgFileName) { + UnicodeMap *map; + GString *fileName; + FILE *f; + int i; + +#if MULTITHREADED + gInitMutex(&mutex); + gInitMutex(&unicodeMapCacheMutex); + gInitMutex(&cMapCacheMutex); +#endif + + initBuiltinFontTables(); + + // scan the encoding in reverse because we want the lowest-numbered + // index for each char name ('space' is encoded twice) + macRomanReverseMap = new NameToCharCode(); + for (i = 255; i >= 0; --i) { + if (macRomanEncoding[i]) { + macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i); + } + } + +#ifdef WIN32 + // baseDir will be set by a call to setBaseDir + baseDir = new GString(); +#else + baseDir = appendToPath(getHomeDir(), ".xpdf"); +#endif + nameToUnicode = new NameToCharCode(); + cidToUnicodes = new GHash(gTrue); + unicodeToUnicodes = new GHash(gTrue); + residentUnicodeMaps = new GHash(); + unicodeMaps = new GHash(gTrue); + cMapDirs = new GHash(gTrue); + toUnicodeDirs = new GList(); + displayFonts = new GHash(); + displayCIDFonts = new GHash(); + displayNamedCIDFonts = new GHash(); +#if HAVE_PAPER_H + char *paperName; + const struct paper *paperType; + paperinit(); + if ((paperName = systempapername())) { + paperType = paperinfo(paperName); + psPaperWidth = (int)paperpswidth(paperType); + psPaperHeight = (int)paperpsheight(paperType); + } else { + error(-1, "No paper information available - using defaults"); + psPaperWidth = defPaperWidth; + psPaperHeight = defPaperHeight; + } + paperdone(); +#else + psPaperWidth = defPaperWidth; + psPaperHeight = defPaperHeight; +#endif + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + psCrop = gTrue; + psExpandSmaller = gFalse; + psShrinkLarger = gTrue; + psCenter = gTrue; + psDuplex = gFalse; + psLevel = psLevel2; + psFile = NULL; + psFonts = new GHash(); + psNamedFonts16 = new GList(); + psFonts16 = new GList(); + psEmbedType1 = gTrue; + psEmbedTrueType = gTrue; + psEmbedCIDPostScript = gTrue; + psEmbedCIDTrueType = gTrue; + psOPI = gFalse; + psASCIIHex = gFalse; + textEncoding = new GString("Latin1"); +#if defined(WIN32) + textEOL = eolDOS; +#elif defined(MACOS) + textEOL = eolMac; +#else + textEOL = eolUnix; +#endif + textPageBreaks = gTrue; + textKeepTinyChars = gFalse; + fontDirs = new GList(); + initialZoom = new GString("125"); + continuousView = gFalse; + enableT1lib = gTrue; + enableFreeType = gTrue; + antialias = gTrue; + urlCommand = NULL; + movieCommand = NULL; + mapNumericCharNames = gTrue; + printCommands = gFalse; + errQuiet = gFalse; + + cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize); + unicodeToUnicodeCache = + new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize); + unicodeMapCache = new UnicodeMapCache(); + cMapCache = new CMapCache(); + +#ifdef ENABLE_PLUGINS + plugins = new GList(); + securityHandlers = new GList(); +#endif + + // set up the initial nameToUnicode table + for (i = 0; nameToUnicodeTab[i].name; ++i) { + nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u); + } + + // set up the residentUnicodeMaps table + map = new UnicodeMap("Latin1", gFalse, + latin1UnicodeMapRanges, latin1UnicodeMapLen); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("ASCII7", gFalse, + ascii7UnicodeMapRanges, ascii7UnicodeMapLen); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("Symbol", gFalse, + symbolUnicodeMapRanges, symbolUnicodeMapLen); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("ZapfDingbats", gFalse, zapfDingbatsUnicodeMapRanges, + zapfDingbatsUnicodeMapLen); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("UTF-8", gTrue, &mapUTF8); + residentUnicodeMaps->add(map->getEncodingName(), map); + map = new UnicodeMap("UCS-2", gTrue, &mapUCS2); + residentUnicodeMaps->add(map->getEncodingName(), map); + + // look for a user config file, then a system-wide config file + f = NULL; + fileName = NULL; + if (cfgFileName && cfgFileName[0]) { + fileName = new GString(cfgFileName); + if (!(f = fopen(fileName->getCString(), "r"))) { + delete fileName; + } + } + if (!f) { + fileName = appendToPath(getHomeDir(), xpdfUserConfigFile); + if (!(f = fopen(fileName->getCString(), "r"))) { + delete fileName; + } + } + if (!f) { +#if defined(WIN32) && !defined(__CYGWIN32__) + char buf[512]; + i = GetModuleFileName(NULL, buf, sizeof(buf)); + if (i <= 0 || i >= sizeof(buf)) { + // error or path too long for buffer - just use the current dir + buf[0] = '\0'; + } + fileName = grabPath(buf); + appendToPath(fileName, xpdfSysConfigFile); +#else + fileName = new GString(xpdfSysConfigFile); +#endif + if (!(f = fopen(fileName->getCString(), "r"))) { + delete fileName; + } + } + if (f) { + parseFile(fileName, f); + delete fileName; + fclose(f); + } +} + +void GlobalParams::parseFile(GString *fileName, FILE *f) { + int line; + GList *tokens; + GString *cmd, *incFile; + char *p1, *p2; + char buf[512]; + FILE *f2; + + line = 1; + while (getLine(buf, sizeof(buf) - 1, f)) { + + // break the line into tokens + tokens = new GList(); + p1 = buf; + while (*p1) { + for (; *p1 && isspace(*p1); ++p1) ; + if (!*p1) { + break; + } + if (*p1 == '"' || *p1 == '\'') { + for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ; + ++p1; + } else { + for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ; + } + tokens->append(new GString(p1, p2 - p1)); + p1 = *p2 ? p2 + 1 : p2; + } + + if (tokens->getLength() > 0 && + ((GString *)tokens->get(0))->getChar(0) != '#') { + cmd = (GString *)tokens->get(0); + if (!cmd->cmp("include")) { + if (tokens->getLength() == 2) { + incFile = (GString *)tokens->get(1); + if ((f2 = fopen(incFile->getCString(), "r"))) { + parseFile(incFile, f2); + fclose(f2); + } else { + error(-1, "Couldn't find included config file: '%s' (%s:%d)", + incFile->getCString(), fileName->getCString(), line); + } + } else { + error(-1, "Bad 'include' config file command (%s:%d)", + fileName->getCString(), line); + } + } else if (!cmd->cmp("nameToUnicode")) { + parseNameToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("cidToUnicode")) { + parseCIDToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("unicodeToUnicode")) { + parseUnicodeToUnicode(tokens, fileName, line); + } else if (!cmd->cmp("unicodeMap")) { + parseUnicodeMap(tokens, fileName, line); + } else if (!cmd->cmp("cMapDir")) { + parseCMapDir(tokens, fileName, line); + } else if (!cmd->cmp("toUnicodeDir")) { + parseToUnicodeDir(tokens, fileName, line); + } else if (!cmd->cmp("displayFontT1")) { + parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line); + } else if (!cmd->cmp("displayFontTT")) { + parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontT1")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontT1, fileName, line); + } else if (!cmd->cmp("displayCIDFontT1")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontT1, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontTT")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontTT, fileName, line); + } else if (!cmd->cmp("displayCIDFontTT")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontTT, fileName, line); + } else if (!cmd->cmp("psFile")) { + parsePSFile(tokens, fileName, line); + } else if (!cmd->cmp("psFont")) { + parsePSFont(tokens, fileName, line); + } else if (!cmd->cmp("psNamedFont16")) { + parsePSFont16("psNamedFont16", psNamedFonts16, + tokens, fileName, line); + } else if (!cmd->cmp("psFont16")) { + parsePSFont16("psFont16", psFonts16, tokens, fileName, line); + } else if (!cmd->cmp("psPaperSize")) { + parsePSPaperSize(tokens, fileName, line); + } else if (!cmd->cmp("psImageableArea")) { + parsePSImageableArea(tokens, fileName, line); + } else if (!cmd->cmp("psCrop")) { + parseYesNo("psCrop", &psCrop, tokens, fileName, line); + } else if (!cmd->cmp("psExpandSmaller")) { + parseYesNo("psExpandSmaller", &psExpandSmaller, + tokens, fileName, line); + } else if (!cmd->cmp("psShrinkLarger")) { + parseYesNo("psShrinkLarger", &psShrinkLarger, tokens, fileName, line); + } else if (!cmd->cmp("psCenter")) { + parseYesNo("psCenter", &psCenter, tokens, fileName, line); + } else if (!cmd->cmp("psDuplex")) { + parseYesNo("psDuplex", &psDuplex, tokens, fileName, line); + } else if (!cmd->cmp("psLevel")) { + parsePSLevel(tokens, fileName, line); + } else if (!cmd->cmp("psEmbedType1Fonts")) { + parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line); + } else if (!cmd->cmp("psEmbedTrueTypeFonts")) { + parseYesNo("psEmbedTrueType", &psEmbedTrueType, + tokens, fileName, line); + } else if (!cmd->cmp("psEmbedCIDPostScriptFonts")) { + parseYesNo("psEmbedCIDPostScript", &psEmbedCIDPostScript, + tokens, fileName, line); + } else if (!cmd->cmp("psEmbedCIDTrueTypeFonts")) { + parseYesNo("psEmbedCIDTrueType", &psEmbedCIDTrueType, + tokens, fileName, line); + } else if (!cmd->cmp("psOPI")) { + parseYesNo("psOPI", &psOPI, tokens, fileName, line); + } else if (!cmd->cmp("psASCIIHex")) { + parseYesNo("psASCIIHex", &psASCIIHex, tokens, fileName, line); + } else if (!cmd->cmp("textEncoding")) { + parseTextEncoding(tokens, fileName, line); + } else if (!cmd->cmp("textEOL")) { + parseTextEOL(tokens, fileName, line); + } else if (!cmd->cmp("textPageBreaks")) { + parseYesNo("textPageBreaks", &textPageBreaks, + tokens, fileName, line); + } else if (!cmd->cmp("textKeepTinyChars")) { + parseYesNo("textKeepTinyChars", &textKeepTinyChars, + tokens, fileName, line); + } else if (!cmd->cmp("fontDir")) { + parseFontDir(tokens, fileName, line); + } else if (!cmd->cmp("initialZoom")) { + parseInitialZoom(tokens, fileName, line); + } else if (!cmd->cmp("continuousView")) { + parseYesNo("continuousView", &continuousView, tokens, fileName, line); + } else if (!cmd->cmp("enableT1lib")) { + parseYesNo("enableT1lib", &enableT1lib, tokens, fileName, line); + } else if (!cmd->cmp("enableFreeType")) { + parseYesNo("enableFreeType", &enableFreeType, tokens, fileName, line); + } else if (!cmd->cmp("antialias")) { + parseYesNo("antialias", &antialias, tokens, fileName, line); + } else if (!cmd->cmp("urlCommand")) { + parseCommand("urlCommand", &urlCommand, tokens, fileName, line); + } else if (!cmd->cmp("movieCommand")) { + parseCommand("movieCommand", &movieCommand, tokens, fileName, line); + } else if (!cmd->cmp("mapNumericCharNames")) { + parseYesNo("mapNumericCharNames", &mapNumericCharNames, + tokens, fileName, line); + } else if (!cmd->cmp("printCommands")) { + parseYesNo("printCommands", &printCommands, tokens, fileName, line); + } else if (!cmd->cmp("errQuiet")) { + parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); + } else { + error(-1, "Unknown config file command '%s' (%s:%d)", + cmd->getCString(), fileName->getCString(), line); + if (!cmd->cmp("displayFontX") || + !cmd->cmp("displayNamedCIDFontX") || + !cmd->cmp("displayCIDFontX")) { + error(-1, "-- Xpdf no longer supports X fonts"); + } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) { + error(-1, "-- The t1libControl and freetypeControl options have been replaced"); + error(-1, " by the enableT1lib, enableFreeType, and antialias options"); + } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { + error(-1, "-- the config file format has changed since Xpdf 0.9x"); + } + } + } + + deleteGList(tokens, GString); + ++line; + } +} + +void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName, + int line) { + GString *name; + char *tok1, *tok2; + FILE *f; + char buf[256]; + int line2; + Unicode u; + + if (tokens->getLength() != 2) { + error(-1, "Bad 'nameToUnicode' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + name = (GString *)tokens->get(1); + if (!(f = fopen(name->getCString(), "r"))) { + error(-1, "Couldn't open 'nameToUnicode' file '%s'", + name->getCString()); + return; + } + line2 = 1; + while (getLine(buf, sizeof(buf), f)) { + tok1 = strtok(buf, " \t\r\n"); + tok2 = strtok(NULL, " \t\r\n"); + if (tok1 && tok2) { + sscanf(tok1, "%x", &u); + nameToUnicode->add(tok2, u); + } else { + error(-1, "Bad line in 'nameToUnicode' file (%s:%d)", name, line2); + } + ++line2; + } + fclose(f); +} + +void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName, + int line) { + GString *collection, *name, *old; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'cidToUnicode' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + collection = (GString *)tokens->get(1); + name = (GString *)tokens->get(2); + if ((old = (GString *)cidToUnicodes->remove(collection))) { + delete old; + } + cidToUnicodes->add(collection->copy(), name->copy()); +} + +void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName, + int line) { + GString *font, *file, *old; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'unicodeToUnicode' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + font = (GString *)tokens->get(1); + file = (GString *)tokens->get(2); + if ((old = (GString *)unicodeToUnicodes->remove(font))) { + delete old; + } + unicodeToUnicodes->add(font->copy(), file->copy()); +} + +void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName, + int line) { + GString *encodingName, *name, *old; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'unicodeMap' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + encodingName = (GString *)tokens->get(1); + name = (GString *)tokens->get(2); + if ((old = (GString *)unicodeMaps->remove(encodingName))) { + delete old; + } + unicodeMaps->add(encodingName->copy(), name->copy()); +} + +void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) { + GString *collection, *dir; + GList *list; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'cMapDir' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + collection = (GString *)tokens->get(1); + dir = (GString *)tokens->get(2); + if (!(list = (GList *)cMapDirs->lookup(collection))) { + list = new GList(); + cMapDirs->add(collection->copy(), list); + } + list->append(dir->copy()); +} + +void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'toUnicodeDir' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + toUnicodeDirs->append(((GString *)tokens->get(1))->copy()); +} + +void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash, + DisplayFontParamKind kind, + GString *fileName, int line) { + DisplayFontParam *param, *old; + + if (tokens->getLength() < 2) { + goto err1; + } + param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind); + + switch (kind) { + case displayFontT1: + if (tokens->getLength() != 3) { + goto err2; + } + param->t1.fileName = ((GString *)tokens->get(2))->copy(); + break; + case displayFontTT: + if (tokens->getLength() != 3) { + goto err2; + } + param->tt.fileName = ((GString *)tokens->get(2))->copy(); + break; + } + + if ((old = (DisplayFontParam *)fontHash->remove(param->name))) { + delete old; + } + fontHash->add(param->name, param); + return; + + err2: + delete param; + err1: + error(-1, "Bad 'display*Font*' config file command (%s:%d)", + fileName->getCString(), line); +} + +void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName, + int line) { + GString *tok; + + if (tokens->getLength() == 2) { + tok = (GString *)tokens->get(1); + if (!setPSPaperSize(tok->getCString())) { + error(-1, "Bad 'psPaperSize' config file command (%s:%d)", + fileName->getCString(), line); + } + } else if (tokens->getLength() == 3) { + tok = (GString *)tokens->get(1); + psPaperWidth = atoi(tok->getCString()); + tok = (GString *)tokens->get(2); + psPaperHeight = atoi(tok->getCString()); + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + } else { + error(-1, "Bad 'psPaperSize' config file command (%s:%d)", + fileName->getCString(), line); + } +} + +void GlobalParams::parsePSImageableArea(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 5) { + error(-1, "Bad 'psImageableArea' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + psImageableLLX = atoi(((GString *)tokens->get(1))->getCString()); + psImageableLLY = atoi(((GString *)tokens->get(2))->getCString()); + psImageableURX = atoi(((GString *)tokens->get(3))->getCString()); + psImageableURY = atoi(((GString *)tokens->get(4))->getCString()); +} + +void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) { + GString *tok; + + if (tokens->getLength() != 2) { + error(-1, "Bad 'psLevel' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (!tok->cmp("level1")) { + psLevel = psLevel1; + } else if (!tok->cmp("level1sep")) { + psLevel = psLevel1Sep; + } else if (!tok->cmp("level2")) { + psLevel = psLevel2; + } else if (!tok->cmp("level2sep")) { + psLevel = psLevel2Sep; + } else if (!tok->cmp("level3")) { + psLevel = psLevel3; + } else if (!tok->cmp("level3Sep")) { + psLevel = psLevel3Sep; + } else { + error(-1, "Bad 'psLevel' config file command (%s:%d)", + fileName->getCString(), line); + } +} + +void GlobalParams::parsePSFile(GList *tokens, GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'psFile' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + if (psFile) { + delete psFile; + } + psFile = ((GString *)tokens->get(1))->copy(); +} + +void GlobalParams::parsePSFont(GList *tokens, GString *fileName, int line) { + PSFontParam *param; + + if (tokens->getLength() != 3) { + error(-1, "Bad 'psFont' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + param = new PSFontParam(((GString *)tokens->get(1))->copy(), 0, + ((GString *)tokens->get(2))->copy(), NULL); + psFonts->add(param->pdfFontName, param); +} + +void GlobalParams::parsePSFont16(char *cmdName, GList *fontList, + GList *tokens, GString *fileName, int line) { + PSFontParam *param; + int wMode; + GString *tok; + + if (tokens->getLength() != 5) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(2); + if (!tok->cmp("H")) { + wMode = 0; + } else if (!tok->cmp("V")) { + wMode = 1; + } else { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + param = new PSFontParam(((GString *)tokens->get(1))->copy(), + wMode, + ((GString *)tokens->get(3))->copy(), + ((GString *)tokens->get(4))->copy()); + fontList->append(param); +} + +void GlobalParams::parseTextEncoding(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'textEncoding' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + delete textEncoding; + textEncoding = ((GString *)tokens->get(1))->copy(); +} + +void GlobalParams::parseTextEOL(GList *tokens, GString *fileName, int line) { + GString *tok; + + if (tokens->getLength() != 2) { + error(-1, "Bad 'textEOL' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (!tok->cmp("unix")) { + textEOL = eolUnix; + } else if (!tok->cmp("dos")) { + textEOL = eolDOS; + } else if (!tok->cmp("mac")) { + textEOL = eolMac; + } else { + error(-1, "Bad 'textEOL' config file command (%s:%d)", + fileName->getCString(), line); + } +} + +void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'fontDir' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + fontDirs->append(((GString *)tokens->get(1))->copy()); +} + +void GlobalParams::parseInitialZoom(GList *tokens, + GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad 'initialZoom' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + delete initialZoom; + initialZoom = ((GString *)tokens->get(1))->copy(); +} + +void GlobalParams::parseCommand(char *cmdName, GString **val, + GList *tokens, GString *fileName, int line) { + if (tokens->getLength() != 2) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + if (*val) { + delete *val; + } + *val = ((GString *)tokens->get(1))->copy(); +} + +void GlobalParams::parseYesNo(char *cmdName, GBool *flag, + GList *tokens, GString *fileName, int line) { + GString *tok; + + if (tokens->getLength() != 2) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (!parseYesNo2(tok->getCString(), flag)) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + } +} + +GBool GlobalParams::parseYesNo2(char *token, GBool *flag) { + if (!strcmp(token, "yes")) { + *flag = gTrue; + } else if (!strcmp(token, "no")) { + *flag = gFalse; + } else { + return gFalse; + } + return gTrue; +} + +GlobalParams::~GlobalParams() { + GHashIter *iter; + GString *key; + GList *list; + + freeBuiltinFontTables(); + + delete macRomanReverseMap; + + delete baseDir; + delete nameToUnicode; + deleteGHash(cidToUnicodes, GString); + deleteGHash(unicodeToUnicodes, GString); + deleteGHash(residentUnicodeMaps, UnicodeMap); + deleteGHash(unicodeMaps, GString); + deleteGList(toUnicodeDirs, GString); + deleteGHash(displayFonts, DisplayFontParam); + deleteGHash(displayCIDFonts, DisplayFontParam); + deleteGHash(displayNamedCIDFonts, DisplayFontParam); + if (psFile) { + delete psFile; + } + deleteGHash(psFonts, PSFontParam); + deleteGList(psNamedFonts16, PSFontParam); + deleteGList(psFonts16, PSFontParam); + delete textEncoding; + deleteGList(fontDirs, GString); + delete initialZoom; + if (urlCommand) { + delete urlCommand; + } + if (movieCommand) { + delete movieCommand; + } + + cMapDirs->startIter(&iter); + while (cMapDirs->getNext(&iter, &key, (void **)&list)) { + deleteGList(list, GString); + } + delete cMapDirs; + + delete cidToUnicodeCache; + delete unicodeToUnicodeCache; + delete unicodeMapCache; + delete cMapCache; + +#ifdef ENABLE_PLUGINS + delete securityHandlers; + deleteGList(plugins, Plugin); +#endif + +#if MULTITHREADED + gDestroyMutex(&mutex); + gDestroyMutex(&unicodeMapCacheMutex); + gDestroyMutex(&cMapCacheMutex); +#endif +} + +//------------------------------------------------------------------------ + +void GlobalParams::setBaseDir(char *dir) { + delete baseDir; + baseDir = new GString(dir); +} + +void GlobalParams::setupBaseFonts(char *dir) { + GString *fontName; + GString *fileName; +#ifdef WIN32 + HMODULE shell32Lib; + BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND hwndOwner, + LPTSTR lpszPath, + int nFolder, + BOOL fCreate); + char winFontDir[MAX_PATH]; +#endif + FILE *f; + DisplayFontParamKind kind; + DisplayFontParam *dfp; + int i, j; + +#ifdef WIN32 + // SHGetSpecialFolderPath isn't available in older versions of + // shell32.dll (Win95 and WinNT4), so do a dynamic load + winFontDir[0] = '\0'; + if ((shell32Lib = LoadLibrary("shell32.dll"))) { + if ((SHGetSpecialFolderPathFunc = + (BOOL (__stdcall *)(HWND hwndOwner, LPTSTR lpszPath, + int nFolder, BOOL fCreate)) + GetProcAddress(shell32Lib, "SHGetSpecialFolderPath"))) { + if (!(*SHGetSpecialFolderPathFunc)(NULL, winFontDir, + CSIDL_FONTS, FALSE)) { + winFontDir[0] = '\0'; + } + } + } +#endif + for (i = 0; displayFontTab[i].name; ++i) { + fontName = new GString(displayFontTab[i].name); + if (getDisplayFont(fontName)) { + delete fontName; + continue; + } + fileName = NULL; + kind = displayFontT1; // make gcc happy + if (dir) { + fileName = appendToPath(new GString(dir), displayFontTab[i].t1FileName); + kind = displayFontT1; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } +#ifdef WIN32 + if (!fileName && winFontDir[0] && displayFontTab[i].ttFileName) { + fileName = appendToPath(new GString(winFontDir), + displayFontTab[i].ttFileName); + kind = displayFontTT; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } + // SHGetSpecialFolderPath(CSIDL_FONTS) doesn't work on Win 2k Server + // or Win2003 Server, or with older versions of shell32.dll, so check + // the "standard" directories + if (displayFontTab[i].ttFileName) { + for (j = 0; !fileName && displayFontDirs[j]; ++j) { + fileName = appendToPath(new GString(displayFontDirs[j]), + displayFontTab[i].ttFileName); + kind = displayFontTT; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } + } +#else + for (j = 0; !fileName && displayFontDirs[j]; ++j) { + fileName = appendToPath(new GString(displayFontDirs[j]), + displayFontTab[i].t1FileName); + kind = displayFontT1; + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } +#endif + if (!fileName) { + error(-1, "No display font for '%s'", displayFontTab[i].name); + delete fontName; + continue; + } + dfp = new DisplayFontParam(fontName, kind); + dfp->t1.fileName = fileName; + globalParams->addDisplayFont(dfp); + } +} + +//------------------------------------------------------------------------ +// accessors +//------------------------------------------------------------------------ + +CharCode GlobalParams::getMacRomanCharCode(char *charName) { + // no need to lock - macRomanReverseMap is constant + return macRomanReverseMap->lookup(charName); +} + +GString *GlobalParams::getBaseDir() { + GString *s; + + lockGlobalParams; + s = baseDir->copy(); + unlockGlobalParams; + return s; +} + +Unicode GlobalParams::mapNameToUnicode(char *charName) { + // no need to lock - nameToUnicode is constant + return nameToUnicode->lookup(charName); +} + +UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) { + UnicodeMap *map; + + lockGlobalParams; + map = (UnicodeMap *)residentUnicodeMaps->lookup(encodingName); + unlockGlobalParams; + if (map) { + map->incRefCnt(); + } + return map; +} + +FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) { + GString *fileName; + FILE *f; + + lockGlobalParams; + if ((fileName = (GString *)unicodeMaps->lookup(encodingName))) { + f = fopen(fileName->getCString(), "r"); + } else { + f = NULL; + } + unlockGlobalParams; + return f; +} + +FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { + GList *list; + GString *dir; + GString *fileName; + FILE *f; + int i; + + lockGlobalParams; + if (!(list = (GList *)cMapDirs->lookup(collection))) { + unlockGlobalParams; + return NULL; + } + for (i = 0; i < list->getLength(); ++i) { + dir = (GString *)list->get(i); + fileName = appendToPath(dir->copy(), cMapName->getCString()); + f = fopen(fileName->getCString(), "r"); + delete fileName; + if (f) { + unlockGlobalParams; + return f; + } + } + unlockGlobalParams; + return NULL; +} + +FILE *GlobalParams::findToUnicodeFile(GString *name) { + GString *dir, *fileName; + FILE *f; + int i; + + lockGlobalParams; + for (i = 0; i < toUnicodeDirs->getLength(); ++i) { + dir = (GString *)toUnicodeDirs->get(i); + fileName = appendToPath(dir->copy(), name->getCString()); + f = fopen(fileName->getCString(), "r"); + delete fileName; + if (f) { + unlockGlobalParams; + return f; + } + } + unlockGlobalParams; + return NULL; +} + +DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { + DisplayFontParam *dfp; + + lockGlobalParams; + dfp = (DisplayFontParam *)displayFonts->lookup(fontName); + unlockGlobalParams; + return dfp; +} + +DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName, + GString *collection) { + DisplayFontParam *dfp; + + lockGlobalParams; + if (!fontName || + !(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) { + dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection); + } + unlockGlobalParams; + return dfp; +} + +GString *GlobalParams::getPSFile() { + GString *s; + + lockGlobalParams; + s = psFile ? psFile->copy() : (GString *)NULL; + unlockGlobalParams; + return s; +} + +int GlobalParams::getPSPaperWidth() { + int w; + + lockGlobalParams; + w = psPaperWidth; + unlockGlobalParams; + return w; +} + +int GlobalParams::getPSPaperHeight() { + int h; + + lockGlobalParams; + h = psPaperHeight; + unlockGlobalParams; + return h; +} + +void GlobalParams::getPSImageableArea(int *llx, int *lly, int *urx, int *ury) { + lockGlobalParams; + *llx = psImageableLLX; + *lly = psImageableLLY; + *urx = psImageableURX; + *ury = psImageableURY; + unlockGlobalParams; +} + +GBool GlobalParams::getPSCrop() { + GBool f; + + lockGlobalParams; + f = psCrop; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSExpandSmaller() { + GBool f; + + lockGlobalParams; + f = psExpandSmaller; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSShrinkLarger() { + GBool f; + + lockGlobalParams; + f = psShrinkLarger; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSCenter() { + GBool f; + + lockGlobalParams; + f = psCenter; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSDuplex() { + GBool d; + + lockGlobalParams; + d = psDuplex; + unlockGlobalParams; + return d; +} + +PSLevel GlobalParams::getPSLevel() { + PSLevel level; + + lockGlobalParams; + level = psLevel; + unlockGlobalParams; + return level; +} + +PSFontParam *GlobalParams::getPSFont(GString *fontName) { + PSFontParam *p; + + lockGlobalParams; + p = (PSFontParam *)psFonts->lookup(fontName); + unlockGlobalParams; + return p; +} + +PSFontParam *GlobalParams::getPSFont16(GString *fontName, + GString *collection, int wMode) { + PSFontParam *p; + int i; + + lockGlobalParams; + p = NULL; + if (fontName) { + for (i = 0; i < psNamedFonts16->getLength(); ++i) { + p = (PSFontParam *)psNamedFonts16->get(i); + if (!p->pdfFontName->cmp(fontName) && + p->wMode == wMode) { + break; + } + p = NULL; + } + } + if (!p && collection) { + for (i = 0; i < psFonts16->getLength(); ++i) { + p = (PSFontParam *)psFonts16->get(i); + if (!p->pdfFontName->cmp(collection) && + p->wMode == wMode) { + break; + } + p = NULL; + } + } + unlockGlobalParams; + return p; +} + +GBool GlobalParams::getPSEmbedType1() { + GBool e; + + lockGlobalParams; + e = psEmbedType1; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedTrueType() { + GBool e; + + lockGlobalParams; + e = psEmbedTrueType; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedCIDPostScript() { + GBool e; + + lockGlobalParams; + e = psEmbedCIDPostScript; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSEmbedCIDTrueType() { + GBool e; + + lockGlobalParams; + e = psEmbedCIDTrueType; + unlockGlobalParams; + return e; +} + +GBool GlobalParams::getPSOPI() { + GBool opi; + + lockGlobalParams; + opi = psOPI; + unlockGlobalParams; + return opi; +} + +GBool GlobalParams::getPSASCIIHex() { + GBool ah; + + lockGlobalParams; + ah = psASCIIHex; + unlockGlobalParams; + return ah; +} + +GString *GlobalParams::getTextEncodingName() { + GString *s; + + lockGlobalParams; + s = textEncoding->copy(); + unlockGlobalParams; + return s; +} + +EndOfLineKind GlobalParams::getTextEOL() { + EndOfLineKind eol; + + lockGlobalParams; + eol = textEOL; + unlockGlobalParams; + return eol; +} + +GBool GlobalParams::getTextPageBreaks() { + GBool pageBreaks; + + lockGlobalParams; + pageBreaks = textPageBreaks; + unlockGlobalParams; + return pageBreaks; +} + +GBool GlobalParams::getTextKeepTinyChars() { + GBool tiny; + + lockGlobalParams; + tiny = textKeepTinyChars; + unlockGlobalParams; + return tiny; +} + +GString *GlobalParams::findFontFile(GString *fontName, char **exts) { + GString *dir, *fileName; + char **ext; + FILE *f; + int i; + + lockGlobalParams; + for (i = 0; i < fontDirs->getLength(); ++i) { + dir = (GString *)fontDirs->get(i); + for (ext = exts; *ext; ++ext) { + fileName = appendToPath(dir->copy(), fontName->getCString()); + fileName->append(*ext); + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + unlockGlobalParams; + return fileName; + } + delete fileName; + } + } + unlockGlobalParams; + return NULL; +} + +GString *GlobalParams::getInitialZoom() { + GString *s; + + lockGlobalParams; + s = initialZoom->copy(); + unlockGlobalParams; + return s; +} + +GBool GlobalParams::getContinuousView() { + GBool f; + + lockGlobalParams; + f = continuousView; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getEnableT1lib() { + GBool f; + + lockGlobalParams; + f = enableT1lib; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getEnableFreeType() { + GBool f; + + lockGlobalParams; + f = enableFreeType; + unlockGlobalParams; + return f; +} + + +GBool GlobalParams::getAntialias() { + GBool f; + + lockGlobalParams; + f = antialias; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getMapNumericCharNames() { + GBool map; + + lockGlobalParams; + map = mapNumericCharNames; + unlockGlobalParams; + return map; +} + +GBool GlobalParams::getPrintCommands() { + GBool p; + + lockGlobalParams; + p = printCommands; + unlockGlobalParams; + return p; +} + +GBool GlobalParams::getErrQuiet() { + GBool q; + + lockGlobalParams; + q = errQuiet; + unlockGlobalParams; + return q; +} + +CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) { + GString *fileName; + CharCodeToUnicode *ctu; + + lockGlobalParams; + if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) { + if ((fileName = (GString *)cidToUnicodes->lookup(collection)) && + (ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) { + cidToUnicodeCache->add(ctu); + } + } + unlockGlobalParams; + return ctu; +} + +CharCodeToUnicode *GlobalParams::getUnicodeToUnicode(GString *fontName) { + CharCodeToUnicode *ctu; + GHashIter *iter; + GString *fontPattern, *fileName; + + lockGlobalParams; + fileName = NULL; + unicodeToUnicodes->startIter(&iter); + while (unicodeToUnicodes->getNext(&iter, &fontPattern, (void **)&fileName)) { + if (strstr(fontName->getCString(), fontPattern->getCString())) { + unicodeToUnicodes->killIter(&iter); + break; + } + fileName = NULL; + } + if (fileName) { + if (!(ctu = unicodeToUnicodeCache->getCharCodeToUnicode(fileName))) { + if ((ctu = CharCodeToUnicode::parseUnicodeToUnicode(fileName))) { + unicodeToUnicodeCache->add(ctu); + } + } + } else { + ctu = NULL; + } + unlockGlobalParams; + return ctu; +} + +UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) { + return getUnicodeMap2(encodingName); +} + +UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) { + UnicodeMap *map; + + if (!(map = getResidentUnicodeMap(encodingName))) { + lockUnicodeMapCache; + map = unicodeMapCache->getUnicodeMap(encodingName); + unlockUnicodeMapCache; + } + return map; +} + +CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) { + CMap *cMap; + + lockCMapCache; + cMap = cMapCache->getCMap(collection, cMapName); + unlockCMapCache; + return cMap; +} + +UnicodeMap *GlobalParams::getTextEncoding() { + return getUnicodeMap2(textEncoding); +} + +//------------------------------------------------------------------------ +// functions to set parameters +//------------------------------------------------------------------------ + +void GlobalParams::addDisplayFont(DisplayFontParam *param) { + DisplayFontParam *old; + + lockGlobalParams; + if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) { + delete old; + } + displayFonts->add(param->name, param); + unlockGlobalParams; +} + +void GlobalParams::setPSFile(char *file) { + lockGlobalParams; + if (psFile) { + delete psFile; + } + psFile = new GString(file); + unlockGlobalParams; +} + +GBool GlobalParams::setPSPaperSize(char *size) { + lockGlobalParams; + if (!strcmp(size, "match")) { + psPaperWidth = psPaperHeight = -1; + } else if (!strcmp(size, "letter")) { + psPaperWidth = 612; + psPaperHeight = 792; + } else if (!strcmp(size, "legal")) { + psPaperWidth = 612; + psPaperHeight = 1008; + } else if (!strcmp(size, "A4")) { + psPaperWidth = 595; + psPaperHeight = 842; + } else if (!strcmp(size, "A3")) { + psPaperWidth = 842; + psPaperHeight = 1190; + } else { + unlockGlobalParams; + return gFalse; + } + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + unlockGlobalParams; + return gTrue; +} + +void GlobalParams::setPSPaperWidth(int width) { + lockGlobalParams; + psPaperWidth = width; + psImageableLLX = 0; + psImageableURX = psPaperWidth; + unlockGlobalParams; +} + +void GlobalParams::setPSPaperHeight(int height) { + lockGlobalParams; + psPaperHeight = height; + psImageableLLY = 0; + psImageableURY = psPaperHeight; + unlockGlobalParams; +} + +void GlobalParams::setPSImageableArea(int llx, int lly, int urx, int ury) { + lockGlobalParams; + psImageableLLX = llx; + psImageableLLY = lly; + psImageableURX = urx; + psImageableURY = ury; + unlockGlobalParams; +} + +void GlobalParams::setPSCrop(GBool crop) { + lockGlobalParams; + psCrop = crop; + unlockGlobalParams; +} + +void GlobalParams::setPSExpandSmaller(GBool expand) { + lockGlobalParams; + psExpandSmaller = expand; + unlockGlobalParams; +} + +void GlobalParams::setPSShrinkLarger(GBool shrink) { + lockGlobalParams; + psShrinkLarger = shrink; + unlockGlobalParams; +} + +void GlobalParams::setPSCenter(GBool center) { + lockGlobalParams; + psCenter = center; + unlockGlobalParams; +} + +void GlobalParams::setPSDuplex(GBool duplex) { + lockGlobalParams; + psDuplex = duplex; + unlockGlobalParams; +} + +void GlobalParams::setPSLevel(PSLevel level) { + lockGlobalParams; + psLevel = level; + unlockGlobalParams; +} + +void GlobalParams::setPSEmbedType1(GBool embed) { + lockGlobalParams; + psEmbedType1 = embed; + unlockGlobalParams; +} + +void GlobalParams::setPSEmbedTrueType(GBool embed) { + lockGlobalParams; + psEmbedTrueType = embed; + unlockGlobalParams; +} + +void GlobalParams::setPSEmbedCIDPostScript(GBool embed) { + lockGlobalParams; + psEmbedCIDPostScript = embed; + unlockGlobalParams; +} + +void GlobalParams::setPSEmbedCIDTrueType(GBool embed) { + lockGlobalParams; + psEmbedCIDTrueType = embed; + unlockGlobalParams; +} + +void GlobalParams::setPSOPI(GBool opi) { + lockGlobalParams; + psOPI = opi; + unlockGlobalParams; +} + +void GlobalParams::setPSASCIIHex(GBool hex) { + lockGlobalParams; + psASCIIHex = hex; + unlockGlobalParams; +} + +void GlobalParams::setTextEncoding(char *encodingName) { + lockGlobalParams; + delete textEncoding; + textEncoding = new GString(encodingName); + unlockGlobalParams; +} + +GBool GlobalParams::setTextEOL(char *s) { + lockGlobalParams; + if (!strcmp(s, "unix")) { + textEOL = eolUnix; + } else if (!strcmp(s, "dos")) { + textEOL = eolDOS; + } else if (!strcmp(s, "mac")) { + textEOL = eolMac; + } else { + unlockGlobalParams; + return gFalse; + } + unlockGlobalParams; + return gTrue; +} + +void GlobalParams::setTextPageBreaks(GBool pageBreaks) { + lockGlobalParams; + textPageBreaks = pageBreaks; + unlockGlobalParams; +} + +void GlobalParams::setTextKeepTinyChars(GBool keep) { + lockGlobalParams; + textKeepTinyChars = keep; + unlockGlobalParams; +} + +void GlobalParams::setInitialZoom(char *s) { + lockGlobalParams; + delete initialZoom; + initialZoom = new GString(s); + unlockGlobalParams; +} + +void GlobalParams::setContinuousView(GBool cont) { + lockGlobalParams; + continuousView = cont; + unlockGlobalParams; +} + +GBool GlobalParams::setEnableT1lib(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &enableT1lib); + unlockGlobalParams; + return ok; +} + +GBool GlobalParams::setEnableFreeType(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &enableFreeType); + unlockGlobalParams; + return ok; +} + + +GBool GlobalParams::setAntialias(char *s) { + GBool ok; + + lockGlobalParams; + ok = parseYesNo2(s, &antialias); + unlockGlobalParams; + return ok; +} + +void GlobalParams::setMapNumericCharNames(GBool map) { + lockGlobalParams; + mapNumericCharNames = map; + unlockGlobalParams; +} + +void GlobalParams::setPrintCommands(GBool printCommandsA) { + lockGlobalParams; + printCommands = printCommandsA; + unlockGlobalParams; +} + +void GlobalParams::setErrQuiet(GBool errQuietA) { + lockGlobalParams; + errQuiet = errQuietA; + unlockGlobalParams; +} + +void GlobalParams::addSecurityHandler(XpdfSecurityHandler *handler) { +#ifdef ENABLE_PLUGINS + lockGlobalParams; + securityHandlers->append(handler); + unlockGlobalParams; +#endif +} + +XpdfSecurityHandler *GlobalParams::getSecurityHandler(char *name) { +#ifdef ENABLE_PLUGINS + XpdfSecurityHandler *hdlr; + int i; + + lockGlobalParams; + for (i = 0; i < securityHandlers->getLength(); ++i) { + hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); + if (!stricmp(hdlr->name, name)) { + unlockGlobalParams; + return hdlr; + } + } + unlockGlobalParams; + + if (!loadPlugin("security", name)) { + return NULL; + } + + lockGlobalParams; + for (i = 0; i < securityHandlers->getLength(); ++i) { + hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); + if (!strcmp(hdlr->name, name)) { + unlockGlobalParams; + return hdlr; + } + } + unlockGlobalParams; +#endif + + return NULL; +} + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// plugins +//------------------------------------------------------------------------ + +GBool GlobalParams::loadPlugin(char *type, char *name) { + Plugin *plugin; + + if (!(plugin = Plugin::load(type, name))) { + return gFalse; + } + lockGlobalParams; + plugins->append(plugin); + unlockGlobalParams; + return gTrue; +} + +#endif // ENABLE_PLUGINS diff --git a/pdftops/GlobalParams.h b/pdftops/GlobalParams.h new file mode 100644 index 000000000..2232d5e32 --- /dev/null +++ b/pdftops/GlobalParams.h @@ -0,0 +1,336 @@ +//======================================================================== +// +// GlobalParams.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GLOBALPARAMS_H +#define GLOBALPARAMS_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "gtypes.h" +#include "CharTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +class GString; +class GList; +class GHash; +class NameToCharCode; +class CharCodeToUnicode; +class CharCodeToUnicodeCache; +class UnicodeMap; +class UnicodeMapCache; +class CMap; +class CMapCache; +struct XpdfSecurityHandler; +class GlobalParams; + +//------------------------------------------------------------------------ + +// The global parameters object. +extern GlobalParams *globalParams; + +//------------------------------------------------------------------------ + +enum DisplayFontParamKind { + displayFontT1, + displayFontTT +}; + +struct DisplayFontParamT1 { + GString *fileName; +}; + +struct DisplayFontParamTT { + GString *fileName; +}; + +class DisplayFontParam { +public: + + GString *name; // font name for 8-bit fonts and named + // CID fonts; collection name for + // generic CID fonts + DisplayFontParamKind kind; + union { + DisplayFontParamT1 t1; + DisplayFontParamTT tt; + }; + + DisplayFontParam(GString *nameA, DisplayFontParamKind kindA); + ~DisplayFontParam(); +}; + +//------------------------------------------------------------------------ + +class PSFontParam { +public: + + GString *pdfFontName; // PDF font name for 8-bit fonts and + // named 16-bit fonts; char collection + // name for generic 16-bit fonts + int wMode; // writing mode (0=horiz, 1=vert) for + // 16-bit fonts + GString *psFontName; // PostScript font name + GString *encoding; // encoding, for 16-bit fonts only + + PSFontParam(GString *pdfFontNameA, int wModeA, + GString *psFontNameA, GString *encodingA); + ~PSFontParam(); +}; + +//------------------------------------------------------------------------ + +enum PSLevel { + psLevel1, + psLevel1Sep, + psLevel2, + psLevel2Sep, + psLevel3, + psLevel3Sep +}; + +//------------------------------------------------------------------------ + +enum EndOfLineKind { + eolUnix, // LF + eolDOS, // CR+LF + eolMac // CR +}; + +//------------------------------------------------------------------------ + +class GlobalParams { +public: + + // Initialize the global parameters by attempting to read a config + // file. + GlobalParams(char *cfgFileName); + + ~GlobalParams(); + + void setBaseDir(char *dir); + void setupBaseFonts(char *dir); + + //----- accessors + + CharCode getMacRomanCharCode(char *charName); + + GString *getBaseDir(); + Unicode mapNameToUnicode(char *charName); + UnicodeMap *getResidentUnicodeMap(GString *encodingName); + FILE *getUnicodeMapFile(GString *encodingName); + FILE *findCMapFile(GString *collection, GString *cMapName); + FILE *findToUnicodeFile(GString *name); + DisplayFontParam *getDisplayFont(GString *fontName); + DisplayFontParam *getDisplayCIDFont(GString *fontName, GString *collection); + GString *getPSFile(); + int getPSPaperWidth(); + int getPSPaperHeight(); + void getPSImageableArea(int *llx, int *lly, int *urx, int *ury); + GBool getPSDuplex(); + GBool getPSCrop(); + GBool getPSExpandSmaller(); + GBool getPSShrinkLarger(); + GBool getPSCenter(); + PSLevel getPSLevel(); + PSFontParam *getPSFont(GString *fontName); + PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode); + GBool getPSEmbedType1(); + GBool getPSEmbedTrueType(); + GBool getPSEmbedCIDPostScript(); + GBool getPSEmbedCIDTrueType(); + GBool getPSOPI(); + GBool getPSASCIIHex(); + GString *getTextEncodingName(); + EndOfLineKind getTextEOL(); + GBool getTextPageBreaks(); + GBool getTextKeepTinyChars(); + GString *findFontFile(GString *fontName, char **exts); + GString *getInitialZoom(); + GBool getContinuousView(); + GBool getEnableT1lib(); + GBool getEnableFreeType(); + GBool getAntialias(); + GString *getURLCommand() { return urlCommand; } + GString *getMovieCommand() { return movieCommand; } + GBool getMapNumericCharNames(); + GBool getPrintCommands(); + GBool getErrQuiet(); + + CharCodeToUnicode *getCIDToUnicode(GString *collection); + CharCodeToUnicode *getUnicodeToUnicode(GString *fontName); + UnicodeMap *getUnicodeMap(GString *encodingName); + CMap *getCMap(GString *collection, GString *cMapName); + UnicodeMap *getTextEncoding(); + + //----- functions to set parameters + + void addDisplayFont(DisplayFontParam *param); + void setPSFile(char *file); + GBool setPSPaperSize(char *size); + void setPSPaperWidth(int width); + void setPSPaperHeight(int height); + void setPSImageableArea(int llx, int lly, int urx, int ury); + void setPSDuplex(GBool duplex); + void setPSCrop(GBool crop); + void setPSExpandSmaller(GBool expand); + void setPSShrinkLarger(GBool shrink); + void setPSCenter(GBool center); + void setPSLevel(PSLevel level); + void setPSEmbedType1(GBool embed); + void setPSEmbedTrueType(GBool embed); + void setPSEmbedCIDPostScript(GBool embed); + void setPSEmbedCIDTrueType(GBool embed); + void setPSOPI(GBool opi); + void setPSASCIIHex(GBool hex); + void setTextEncoding(char *encodingName); + GBool setTextEOL(char *s); + void setTextPageBreaks(GBool pageBreaks); + void setTextKeepTinyChars(GBool keep); + void setInitialZoom(char *s); + void setContinuousView(GBool cont); + GBool setEnableT1lib(char *s); + GBool setEnableFreeType(char *s); + GBool setAntialias(char *s); + void setMapNumericCharNames(GBool map); + void setPrintCommands(GBool printCommandsA); + void setErrQuiet(GBool errQuietA); + + //----- security handlers + + void addSecurityHandler(XpdfSecurityHandler *handler); + XpdfSecurityHandler *getSecurityHandler(char *name); + +private: + + void parseFile(GString *fileName, FILE *f); + void parseNameToUnicode(GList *tokens, GString *fileName, int line); + void parseCIDToUnicode(GList *tokens, GString *fileName, int line); + void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line); + void parseUnicodeMap(GList *tokens, GString *fileName, int line); + void parseCMapDir(GList *tokens, GString *fileName, int line); + void parseToUnicodeDir(GList *tokens, GString *fileName, int line); + void parseDisplayFont(GList *tokens, GHash *fontHash, + DisplayFontParamKind kind, + GString *fileName, int line); + void parsePSFile(GList *tokens, GString *fileName, int line); + void parsePSPaperSize(GList *tokens, GString *fileName, int line); + void parsePSImageableArea(GList *tokens, GString *fileName, int line); + void parsePSLevel(GList *tokens, GString *fileName, int line); + void parsePSFont(GList *tokens, GString *fileName, int line); + void parsePSFont16(char *cmdName, GList *fontList, + GList *tokens, GString *fileName, int line); + void parseTextEncoding(GList *tokens, GString *fileName, int line); + void parseTextEOL(GList *tokens, GString *fileName, int line); + void parseFontDir(GList *tokens, GString *fileName, int line); + void parseInitialZoom(GList *tokens, GString *fileName, int line); + void parseCommand(char *cmdName, GString **val, + GList *tokens, GString *fileName, int line); + void parseYesNo(char *cmdName, GBool *flag, + GList *tokens, GString *fileName, int line); + GBool parseYesNo2(char *token, GBool *flag); + UnicodeMap *getUnicodeMap2(GString *encodingName); +#ifdef ENABLE_PLUGINS + GBool loadPlugin(char *type, char *name); +#endif + + //----- static tables + + NameToCharCode * // mapping from char name to + macRomanReverseMap; // MacRomanEncoding index + + //----- user-modifiable settings + + GString *baseDir; // base directory - for plugins, etc. + NameToCharCode * // mapping from char name to Unicode + nameToUnicode; + GHash *cidToUnicodes; // files for mappings from char collections + // to Unicode, indexed by collection name + // [GString] + GHash *unicodeToUnicodes; // files for Unicode-to-Unicode mappings, + // indexed by font name pattern [GString] + GHash *residentUnicodeMaps; // mappings from Unicode to char codes, + // indexed by encoding name [UnicodeMap] + GHash *unicodeMaps; // files for mappings from Unicode to char + // codes, indexed by encoding name [GString] + GHash *cMapDirs; // list of CMap dirs, indexed by collection + // name [GList[GString]] + GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString] + GHash *displayFonts; // display font info, indexed by font name + // [DisplayFontParam] + GHash *displayCIDFonts; // display CID font info, indexed by + // collection [DisplayFontParam] + GHash *displayNamedCIDFonts; // display CID font info, indexed by + // font name [DisplayFontParam] + GString *psFile; // PostScript file or command (for xpdf) + int psPaperWidth; // paper size, in PostScript points, for + int psPaperHeight; // PostScript output + int psImageableLLX, // imageable area, in PostScript points, + psImageableLLY, // for PostScript output + psImageableURX, + psImageableURY; + GBool psCrop; // crop PS output to CropBox + GBool psExpandSmaller; // expand smaller pages to fill paper + GBool psShrinkLarger; // shrink larger pages to fit paper + GBool psCenter; // center pages on the paper + GBool psDuplex; // enable duplexing in PostScript? + PSLevel psLevel; // PostScript level to generate + GHash *psFonts; // PostScript font info, indexed by PDF + // font name [PSFontParam] + GList *psNamedFonts16; // named 16-bit fonts [PSFontParam] + GList *psFonts16; // generic 16-bit fonts [PSFontParam] + GBool psEmbedType1; // embed Type 1 fonts? + GBool psEmbedTrueType; // embed TrueType fonts? + GBool psEmbedCIDPostScript; // embed CID PostScript fonts? + GBool psEmbedCIDTrueType; // embed CID TrueType fonts? + GBool psOPI; // generate PostScript OPI comments? + GBool psASCIIHex; // use ASCIIHex instead of ASCII85? + GString *textEncoding; // encoding (unicodeMap) to use for text + // output + EndOfLineKind textEOL; // type of EOL marker to use for text + // output + GBool textPageBreaks; // insert end-of-page markers? + GBool textKeepTinyChars; // keep all characters in text output + GList *fontDirs; // list of font dirs [GString] + GString *initialZoom; // initial zoom level + GBool continuousView; // continuous view mode + GBool enableT1lib; // t1lib enable flag + GBool enableFreeType; // FreeType enable flag + GBool antialias; // anti-aliasing enable flag + GString *urlCommand; // command executed for URL links + GString *movieCommand; // command executed for movie annotations + GBool mapNumericCharNames; // map numeric char names (from font subsets)? + GBool printCommands; // print the drawing commands + GBool errQuiet; // suppress error messages? + + CharCodeToUnicodeCache *cidToUnicodeCache; + CharCodeToUnicodeCache *unicodeToUnicodeCache; + UnicodeMapCache *unicodeMapCache; + CMapCache *cMapCache; + +#ifdef ENABLE_PLUGINS + GList *plugins; // list of plugins [Plugin] + GList *securityHandlers; // list of loaded security handlers + // [XpdfSecurityHandler] +#endif + +#if MULTITHREADED + GMutex mutex; + GMutex unicodeMapCacheMutex; + GMutex cMapCacheMutex; +#endif +}; + +#endif diff --git a/pdftops/JArithmeticDecoder.cxx b/pdftops/JArithmeticDecoder.cxx new file mode 100644 index 000000000..ec0778e64 --- /dev/null +++ b/pdftops/JArithmeticDecoder.cxx @@ -0,0 +1,322 @@ +//======================================================================== +// +// JArithmeticDecoder.cc +// +// Copyright 2002-2004 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "Object.h" +#include "Stream.h" +#include "JArithmeticDecoder.h" + +//------------------------------------------------------------------------ +// JArithmeticDecoderStates +//------------------------------------------------------------------------ + +JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) { + contextSize = contextSizeA; + cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar)); + reset(); +} + +JArithmeticDecoderStats::~JArithmeticDecoderStats() { + gfree(cxTab); +} + +JArithmeticDecoderStats *JArithmeticDecoderStats::copy() { + JArithmeticDecoderStats *stats; + + stats = new JArithmeticDecoderStats(contextSize); + memcpy(stats->cxTab, cxTab, contextSize); + return stats; +} + +void JArithmeticDecoderStats::reset() { + memset(cxTab, 0, contextSize); +} + +void JArithmeticDecoderStats::copyFrom(JArithmeticDecoderStats *stats) { + memcpy(cxTab, stats->cxTab, contextSize); +} + +void JArithmeticDecoderStats::setEntry(Guint cx, int i, int mps) { + cxTab[cx] = (i << 1) + mps; +} + +//------------------------------------------------------------------------ +// JArithmeticDecoder +//------------------------------------------------------------------------ + +Guint JArithmeticDecoder::qeTab[47] = { + 0x56010000, 0x34010000, 0x18010000, 0x0AC10000, + 0x05210000, 0x02210000, 0x56010000, 0x54010000, + 0x48010000, 0x38010000, 0x30010000, 0x24010000, + 0x1C010000, 0x16010000, 0x56010000, 0x54010000, + 0x51010000, 0x48010000, 0x38010000, 0x34010000, + 0x30010000, 0x28010000, 0x24010000, 0x22010000, + 0x1C010000, 0x18010000, 0x16010000, 0x14010000, + 0x12010000, 0x11010000, 0x0AC10000, 0x09C10000, + 0x08A10000, 0x05210000, 0x04410000, 0x02A10000, + 0x02210000, 0x01410000, 0x01110000, 0x00850000, + 0x00490000, 0x00250000, 0x00150000, 0x00090000, + 0x00050000, 0x00010000, 0x56010000 +}; + +int JArithmeticDecoder::nmpsTab[47] = { + 1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 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, 45, 46 +}; + +int JArithmeticDecoder::nlpsTab[47] = { + 1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14, + 15, 16, 17, 18, 19, 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, 46 +}; + +int JArithmeticDecoder::switchTab[47] = { + 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +JArithmeticDecoder::JArithmeticDecoder() { + str = NULL; + dataLen = 0; + limitStream = gFalse; +} + +inline Guint JArithmeticDecoder::readByte() { + if (limitStream) { + --dataLen; + if (dataLen < 0) { + return 0xff; + } + } + return (Guint)str->getChar() & 0xff; +} + +JArithmeticDecoder::~JArithmeticDecoder() { + cleanup(); +} + +void JArithmeticDecoder::start() { + buf0 = readByte(); + buf1 = readByte(); + + // INITDEC + c = (buf0 ^ 0xff) << 16; + byteIn(); + c <<= 7; + ct -= 7; + a = 0x80000000; +} + +void JArithmeticDecoder::restart(int dataLenA) { + int oldDataLen; + + oldDataLen = dataLen; + dataLen = dataLenA; + if (oldDataLen == -1) { + buf1 = readByte(); + } else if (oldDataLen <= -2) { + buf0 = readByte(); + buf1 = readByte(); + } +} + +void JArithmeticDecoder::cleanup() { + if (limitStream) { + while (dataLen > 0) { + buf0 = buf1; + buf1 = readByte(); + } + } +} + +int JArithmeticDecoder::decodeBit(Guint context, + JArithmeticDecoderStats *stats) { + int bit; + Guint qe; + int iCX, mpsCX; + + iCX = stats->cxTab[context] >> 1; + mpsCX = stats->cxTab[context] & 1; + qe = qeTab[iCX]; + a -= qe; + if (c < a) { + if (a & 0x80000000) { + bit = mpsCX; + } else { + // MPS_EXCHANGE + if (a < qe) { + bit = 1 - mpsCX; + if (switchTab[iCX]) { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); + } else { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; + } + } else { + bit = mpsCX; + stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; + } + // RENORMD + do { + if (ct == 0) { + byteIn(); + } + a <<= 1; + c <<= 1; + --ct; + } while (!(a & 0x80000000)); + } + } else { + c -= a; + // LPS_EXCHANGE + if (a < qe) { + bit = mpsCX; + stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; + } else { + bit = 1 - mpsCX; + if (switchTab[iCX]) { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); + } else { + stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; + } + } + a = qe; + // RENORMD + do { + if (ct == 0) { + byteIn(); + } + a <<= 1; + c <<= 1; + --ct; + } while (!(a & 0x80000000)); + } + return bit; +} + +int JArithmeticDecoder::decodeByte(Guint context, + JArithmeticDecoderStats *stats) { + int byte; + int i; + + byte = 0; + for (i = 0; i < 8; ++i) { + byte = (byte << 1) | decodeBit(context, stats); + } + return byte; +} + +GBool JArithmeticDecoder::decodeInt(int *x, JArithmeticDecoderStats *stats) { + int s; + Guint v; + int i; + + prev = 1; + s = decodeIntBit(stats); + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + if (decodeIntBit(stats)) { + v = 0; + for (i = 0; i < 32; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 4436; + } else { + v = 0; + for (i = 0; i < 12; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 340; + } + } else { + v = 0; + for (i = 0; i < 8; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 84; + } + } else { + v = 0; + for (i = 0; i < 6; ++i) { + v = (v << 1) | decodeIntBit(stats); + } + v += 20; + } + } else { + v = decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + v += 4; + } + } else { + v = decodeIntBit(stats); + v = (v << 1) | decodeIntBit(stats); + } + + if (s) { + if (v == 0) { + return gFalse; + } + *x = -(int)v; + } else { + *x = (int)v; + } + return gTrue; +} + +int JArithmeticDecoder::decodeIntBit(JArithmeticDecoderStats *stats) { + int bit; + + bit = decodeBit(prev, stats); + if (prev < 0x100) { + prev = (prev << 1) | bit; + } else { + prev = (((prev << 1) | bit) & 0x1ff) | 0x100; + } + return bit; +} + +Guint JArithmeticDecoder::decodeIAID(Guint codeLen, + JArithmeticDecoderStats *stats) { + Guint i; + int bit; + + prev = 1; + for (i = 0; i < codeLen; ++i) { + bit = decodeBit(prev, stats); + prev = (prev << 1) | bit; + } + return prev - (1 << codeLen); +} + +void JArithmeticDecoder::byteIn() { + if (buf0 == 0xff) { + if (buf1 > 0x8f) { + ct = 8; + } else { + buf0 = buf1; + buf1 = readByte(); + c = c + 0xfe00 - (buf0 << 9); + ct = 7; + } + } else { + buf0 = buf1; + buf1 = readByte(); + c = c + 0xff00 - (buf0 << 8); + ct = 8; + } +} diff --git a/pdftops/JArithmeticDecoder.h b/pdftops/JArithmeticDecoder.h new file mode 100644 index 000000000..201e36d2c --- /dev/null +++ b/pdftops/JArithmeticDecoder.h @@ -0,0 +1,109 @@ +//======================================================================== +// +// JArithmeticDecoder.h +// +// Arithmetic decoder used by the JBIG2 and JPEG2000 decoders. +// +// Copyright 2002-2004 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JARITHMETICDECODER_H +#define JARITHMETICDECODER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class Stream; + +//------------------------------------------------------------------------ +// JArithmeticDecoderStats +//------------------------------------------------------------------------ + +class JArithmeticDecoderStats { +public: + + JArithmeticDecoderStats(int contextSizeA); + ~JArithmeticDecoderStats(); + JArithmeticDecoderStats *copy(); + void reset(); + int getContextSize() { return contextSize; } + void copyFrom(JArithmeticDecoderStats *stats); + void setEntry(Guint cx, int i, int mps); + +private: + + Guchar *cxTab; // cxTab[cx] = (i[cx] << 1) + mps[cx] + int contextSize; + + friend class JArithmeticDecoder; +}; + +//------------------------------------------------------------------------ +// JArithmeticDecoder +//------------------------------------------------------------------------ + +class JArithmeticDecoder { +public: + + JArithmeticDecoder(); + ~JArithmeticDecoder(); + + void setStream(Stream *strA) + { str = strA; dataLen = 0; limitStream = gFalse; } + void setStream(Stream *strA, int dataLenA) + { str = strA; dataLen = dataLenA; limitStream = gTrue; } + + // Start decoding on a new stream. This fills the byte buffers and + // runs INITDEC. + void start(); + + // Restart decoding on an interrupted stream. This refills the + // buffers if needed, but does not run INITDEC. (This is used in + // JPEG 2000 streams when codeblock data is split across multiple + // packets/layers.) + void restart(int dataLenA); + + // Read any leftover data in the stream. + void cleanup(); + + // Decode one bit. + int decodeBit(Guint context, JArithmeticDecoderStats *stats); + + // Decode eight bits. + int decodeByte(Guint context, JArithmeticDecoderStats *stats); + + // Returns false for OOB, otherwise sets * and returns true. + GBool decodeInt(int *x, JArithmeticDecoderStats *stats); + + Guint decodeIAID(Guint codeLen, + JArithmeticDecoderStats *stats); + +private: + + Guint readByte(); + int decodeIntBit(JArithmeticDecoderStats *stats); + void byteIn(); + + static Guint qeTab[47]; + static int nmpsTab[47]; + static int nlpsTab[47]; + static int switchTab[47]; + + Guint buf0, buf1; + Guint c, a; + int ct; + + Guint prev; // for the integer decoder + + Stream *str; + int dataLen; + GBool limitStream; +}; + +#endif diff --git a/pdftops/JBIG2Stream.cxx b/pdftops/JBIG2Stream.cxx new file mode 100644 index 000000000..e1e25f540 --- /dev/null +++ b/pdftops/JBIG2Stream.cxx @@ -0,0 +1,3386 @@ +//======================================================================== +// +// JBIG2Stream.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "GList.h" +#include "Error.h" +#include "JArithmeticDecoder.h" +#include "JBIG2Stream.h" + +//~ share these tables +#include "Stream-CCITT.h" + +//------------------------------------------------------------------------ + +static int contextSize[4] = { 16, 13, 10, 10 }; +static int refContextSize[2] = { 13, 10 }; + +//------------------------------------------------------------------------ +// JBIG2HuffmanTable +//------------------------------------------------------------------------ + +#define jbig2HuffmanLOW 0xfffffffd +#define jbig2HuffmanOOB 0xfffffffe +#define jbig2HuffmanEOT 0xffffffff + +struct JBIG2HuffmanTable { + int val; + Guint prefixLen; + Guint rangeLen; // can also be LOW, OOB, or EOT + Guint prefix; +}; + +JBIG2HuffmanTable huffTableA[] = { + { 0, 1, 4, 0x000 }, + { 16, 2, 8, 0x002 }, + { 272, 3, 16, 0x006 }, + { 65808, 3, 32, 0x007 }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableB[] = { + { 0, 1, 0, 0x000 }, + { 1, 2, 0, 0x002 }, + { 2, 3, 0, 0x006 }, + { 3, 4, 3, 0x00e }, + { 11, 5, 6, 0x01e }, + { 75, 6, 32, 0x03e }, + { 0, 6, jbig2HuffmanOOB, 0x03f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableC[] = { + { 0, 1, 0, 0x000 }, + { 1, 2, 0, 0x002 }, + { 2, 3, 0, 0x006 }, + { 3, 4, 3, 0x00e }, + { 11, 5, 6, 0x01e }, + { 0, 6, jbig2HuffmanOOB, 0x03e }, + { 75, 7, 32, 0x0fe }, + { -256, 8, 8, 0x0fe }, + { -257, 8, jbig2HuffmanLOW, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableD[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 0, 0x006 }, + { 4, 4, 3, 0x00e }, + { 12, 5, 6, 0x01e }, + { 76, 5, 32, 0x01f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableE[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 0, 0x006 }, + { 4, 4, 3, 0x00e }, + { 12, 5, 6, 0x01e }, + { 76, 6, 32, 0x03e }, + { -255, 7, 8, 0x07e }, + { -256, 7, jbig2HuffmanLOW, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableF[] = { + { 0, 2, 7, 0x000 }, + { 128, 3, 7, 0x002 }, + { 256, 3, 8, 0x003 }, + { -1024, 4, 9, 0x008 }, + { -512, 4, 8, 0x009 }, + { -256, 4, 7, 0x00a }, + { -32, 4, 5, 0x00b }, + { 512, 4, 9, 0x00c }, + { 1024, 4, 10, 0x00d }, + { -2048, 5, 10, 0x01c }, + { -128, 5, 6, 0x01d }, + { -64, 5, 5, 0x01e }, + { -2049, 6, jbig2HuffmanLOW, 0x03e }, + { 2048, 6, 32, 0x03f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableG[] = { + { -512, 3, 8, 0x000 }, + { 256, 3, 8, 0x001 }, + { 512, 3, 9, 0x002 }, + { 1024, 3, 10, 0x003 }, + { -1024, 4, 9, 0x008 }, + { -256, 4, 7, 0x009 }, + { -32, 4, 5, 0x00a }, + { 0, 4, 5, 0x00b }, + { 128, 4, 7, 0x00c }, + { -128, 5, 6, 0x01a }, + { -64, 5, 5, 0x01b }, + { 32, 5, 5, 0x01c }, + { 64, 5, 6, 0x01d }, + { -1025, 5, jbig2HuffmanLOW, 0x01e }, + { 2048, 5, 32, 0x01f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableH[] = { + { 0, 2, 1, 0x000 }, + { 0, 2, jbig2HuffmanOOB, 0x001 }, + { 4, 3, 4, 0x004 }, + { -1, 4, 0, 0x00a }, + { 22, 4, 4, 0x00b }, + { 38, 4, 5, 0x00c }, + { 2, 5, 0, 0x01a }, + { 70, 5, 6, 0x01b }, + { 134, 5, 7, 0x01c }, + { 3, 6, 0, 0x03a }, + { 20, 6, 1, 0x03b }, + { 262, 6, 7, 0x03c }, + { 646, 6, 10, 0x03d }, + { -2, 7, 0, 0x07c }, + { 390, 7, 8, 0x07d }, + { -15, 8, 3, 0x0fc }, + { -5, 8, 1, 0x0fd }, + { -7, 9, 1, 0x1fc }, + { -3, 9, 0, 0x1fd }, + { -16, 9, jbig2HuffmanLOW, 0x1fe }, + { 1670, 9, 32, 0x1ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableI[] = { + { 0, 2, jbig2HuffmanOOB, 0x000 }, + { -1, 3, 1, 0x002 }, + { 1, 3, 1, 0x003 }, + { 7, 3, 5, 0x004 }, + { -3, 4, 1, 0x00a }, + { 43, 4, 5, 0x00b }, + { 75, 4, 6, 0x00c }, + { 3, 5, 1, 0x01a }, + { 139, 5, 7, 0x01b }, + { 267, 5, 8, 0x01c }, + { 5, 6, 1, 0x03a }, + { 39, 6, 2, 0x03b }, + { 523, 6, 8, 0x03c }, + { 1291, 6, 11, 0x03d }, + { -5, 7, 1, 0x07c }, + { 779, 7, 9, 0x07d }, + { -31, 8, 4, 0x0fc }, + { -11, 8, 2, 0x0fd }, + { -15, 9, 2, 0x1fc }, + { -7, 9, 1, 0x1fd }, + { -32, 9, jbig2HuffmanLOW, 0x1fe }, + { 3339, 9, 32, 0x1ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableJ[] = { + { -2, 2, 2, 0x000 }, + { 6, 2, 6, 0x001 }, + { 0, 2, jbig2HuffmanOOB, 0x002 }, + { -3, 5, 0, 0x018 }, + { 2, 5, 0, 0x019 }, + { 70, 5, 5, 0x01a }, + { 3, 6, 0, 0x036 }, + { 102, 6, 5, 0x037 }, + { 134, 6, 6, 0x038 }, + { 198, 6, 7, 0x039 }, + { 326, 6, 8, 0x03a }, + { 582, 6, 9, 0x03b }, + { 1094, 6, 10, 0x03c }, + { -21, 7, 4, 0x07a }, + { -4, 7, 0, 0x07b }, + { 4, 7, 0, 0x07c }, + { 2118, 7, 11, 0x07d }, + { -5, 8, 0, 0x0fc }, + { 5, 8, 0, 0x0fd }, + { -22, 8, jbig2HuffmanLOW, 0x0fe }, + { 4166, 8, 32, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableK[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 1, 0x002 }, + { 4, 4, 0, 0x00c }, + { 5, 4, 1, 0x00d }, + { 7, 5, 1, 0x01c }, + { 9, 5, 2, 0x01d }, + { 13, 6, 2, 0x03c }, + { 17, 7, 2, 0x07a }, + { 21, 7, 3, 0x07b }, + { 29, 7, 4, 0x07c }, + { 45, 7, 5, 0x07d }, + { 77, 7, 6, 0x07e }, + { 141, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableL[] = { + { 1, 1, 0, 0x000 }, + { 2, 2, 0, 0x002 }, + { 3, 3, 1, 0x006 }, + { 5, 5, 0, 0x01c }, + { 6, 5, 1, 0x01d }, + { 8, 6, 1, 0x03c }, + { 10, 7, 0, 0x07a }, + { 11, 7, 1, 0x07b }, + { 13, 7, 2, 0x07c }, + { 17, 7, 3, 0x07d }, + { 25, 7, 4, 0x07e }, + { 41, 8, 5, 0x0fe }, + { 73, 8, 32, 0x0ff }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableM[] = { + { 1, 1, 0, 0x000 }, + { 2, 3, 0, 0x004 }, + { 7, 3, 3, 0x005 }, + { 3, 4, 0, 0x00c }, + { 5, 4, 1, 0x00d }, + { 4, 5, 0, 0x01c }, + { 15, 6, 1, 0x03a }, + { 17, 6, 2, 0x03b }, + { 21, 6, 3, 0x03c }, + { 29, 6, 4, 0x03d }, + { 45, 6, 5, 0x03e }, + { 77, 7, 6, 0x07e }, + { 141, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableN[] = { + { 0, 1, 0, 0x000 }, + { -2, 3, 0, 0x004 }, + { -1, 3, 0, 0x005 }, + { 1, 3, 0, 0x006 }, + { 2, 3, 0, 0x007 }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +JBIG2HuffmanTable huffTableO[] = { + { 0, 1, 0, 0x000 }, + { -1, 3, 0, 0x004 }, + { 1, 3, 0, 0x005 }, + { -2, 4, 0, 0x00c }, + { 2, 4, 0, 0x00d }, + { -4, 5, 1, 0x01c }, + { 3, 5, 1, 0x01d }, + { -8, 6, 2, 0x03c }, + { 5, 6, 2, 0x03d }, + { -24, 7, 4, 0x07c }, + { 9, 7, 4, 0x07d }, + { -25, 7, jbig2HuffmanLOW, 0x07e }, + { 25, 7, 32, 0x07f }, + { 0, 0, jbig2HuffmanEOT, 0 } +}; + +//------------------------------------------------------------------------ +// JBIG2HuffmanDecoder +//------------------------------------------------------------------------ + +class JBIG2HuffmanDecoder { +public: + + JBIG2HuffmanDecoder(); + ~JBIG2HuffmanDecoder(); + void setStream(Stream *strA) { str = strA; } + + void reset(); + + // Returns false for OOB, otherwise sets * and returns true. + GBool decodeInt(int *x, JBIG2HuffmanTable *table); + + Guint readBits(Guint n); + Guint readBit(); + + // Sort the table by prefix length and assign prefix values. + void buildTable(JBIG2HuffmanTable *table, Guint len); + +private: + + Stream *str; + Guint buf; + Guint bufLen; +}; + +JBIG2HuffmanDecoder::JBIG2HuffmanDecoder() { + str = NULL; + reset(); +} + +JBIG2HuffmanDecoder::~JBIG2HuffmanDecoder() { +} + +void JBIG2HuffmanDecoder::reset() { + buf = 0; + bufLen = 0; +} + +//~ optimize this +GBool JBIG2HuffmanDecoder::decodeInt(int *x, JBIG2HuffmanTable *table) { + Guint i, len, prefix; + + i = 0; + len = 0; + prefix = 0; + while (table[i].rangeLen != jbig2HuffmanEOT) { + while (len < table[i].prefixLen) { + prefix = (prefix << 1) | readBit(); + ++len; + } + if (prefix == table[i].prefix) { + if (table[i].rangeLen == jbig2HuffmanOOB) { + return gFalse; + } + if (table[i].rangeLen == jbig2HuffmanLOW) { + *x = table[i].val - readBits(32); + } else if (table[i].rangeLen > 0) { + *x = table[i].val + readBits(table[i].rangeLen); + } else { + *x = table[i].val; + } + return gTrue; + } + ++i; + } + return gFalse; +} + +Guint JBIG2HuffmanDecoder::readBits(Guint n) { + Guint x, mask, nLeft; + + mask = (n == 32) ? 0xffffffff : ((1 << n) - 1); + if (bufLen >= n) { + x = (buf >> (bufLen - n)) & mask; + bufLen -= n; + } else { + x = buf & ((1 << bufLen) - 1); + nLeft = n - bufLen; + bufLen = 0; + while (nLeft >= 8) { + x = (x << 8) | (str->getChar() & 0xff); + nLeft -= 8; + } + if (nLeft > 0) { + buf = str->getChar(); + bufLen = 8 - nLeft; + x = (x << nLeft) | ((buf >> bufLen) & ((1 << nLeft) - 1)); + } + } + return x; +} + +Guint JBIG2HuffmanDecoder::readBit() { + if (bufLen == 0) { + buf = str->getChar(); + bufLen = 8; + } + --bufLen; + return (buf >> bufLen) & 1; +} + +void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) { + Guint i, j, k, prefix; + JBIG2HuffmanTable tab; + + // stable selection sort: + // - entries with prefixLen > 0, in ascending prefixLen order + // - entry with prefixLen = 0, rangeLen = EOT + // - all other entries with prefixLen = 0 + // (on entry, table[len] has prefixLen = 0, rangeLen = EOT) + for (i = 0; i < len; ++i) { + for (j = i; j < len && table[j].prefixLen == 0; ++j) ; + if (j == len) { + break; + } + for (k = j + 1; k < len; ++k) { + if (table[k].prefixLen > 0 && + table[k].prefixLen < table[j].prefixLen) { + j = k; + } + } + if (j != i) { + tab = table[j]; + for (k = j; k > i; --k) { + table[k] = table[k - 1]; + } + table[i] = tab; + } + } + table[i] = table[len]; + + // assign prefixes + i = 0; + prefix = 0; + table[i++].prefix = prefix++; + for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) { + prefix <<= table[i].prefixLen - table[i-1].prefixLen; + table[i].prefix = prefix++; + } +} + +//------------------------------------------------------------------------ +// JBIG2MMRDecoder +//------------------------------------------------------------------------ + +class JBIG2MMRDecoder { +public: + + JBIG2MMRDecoder(); + ~JBIG2MMRDecoder(); + void setStream(Stream *strA) { str = strA; } + void reset(); + int get2DCode(); + int getBlackCode(); + int getWhiteCode(); + Guint get24Bits(); + void skipTo(Guint length); + +private: + + Stream *str; + Guint buf; + Guint bufLen; + Guint nBytesRead; +}; + +JBIG2MMRDecoder::JBIG2MMRDecoder() { + str = NULL; + reset(); +} + +JBIG2MMRDecoder::~JBIG2MMRDecoder() { +} + +void JBIG2MMRDecoder::reset() { + buf = 0; + bufLen = 0; + nBytesRead = 0; +} + +int JBIG2MMRDecoder::get2DCode() { + CCITTCode *p; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + p = &twoDimTab1[(buf >> 1) & 0x7f]; + } else if (bufLen == 8) { + p = &twoDimTab1[(buf >> 1) & 0x7f]; + } else { + p = &twoDimTab1[(buf << (7 - bufLen)) & 0x7f]; + if (p->bits < 0 || p->bits > (int)bufLen) { + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + p = &twoDimTab1[(buf >> (bufLen - 7)) & 0x7f]; + } + } + if (p->bits < 0) { + error(str->getPos(), "Bad two dim code in JBIG2 MMR stream"); + return 0; + } + bufLen -= p->bits; + return p->n; +} + +int JBIG2MMRDecoder::getWhiteCode() { + CCITTCode *p; + Guint code; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + } + while (1) { + if (bufLen >= 7 && ((buf >> (bufLen - 7)) & 0x7f) == 0) { + if (bufLen <= 12) { + code = buf << (12 - bufLen); + } else { + code = buf >> (bufLen - 12); + } + p = &whiteTab1[code & 0x1f]; + } else { + if (bufLen <= 9) { + code = buf << (9 - bufLen); + } else { + code = buf >> (bufLen - 9); + } + p = &whiteTab2[code & 0x1ff]; + } + if (p->bits > 0 && p->bits <= (int)bufLen) { + bufLen -= p->bits; + return p->n; + } + if (bufLen >= 12) { + break; + } + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + error(str->getPos(), "Bad white code in JBIG2 MMR stream"); + // eat a bit and return a positive number so that the caller doesn't + // go into an infinite loop + --bufLen; + return 1; +} + +int JBIG2MMRDecoder::getBlackCode() { + CCITTCode *p; + Guint code; + + if (bufLen == 0) { + buf = str->getChar() & 0xff; + bufLen = 8; + ++nBytesRead; + } + while (1) { + if (bufLen >= 6 && ((buf >> (bufLen - 6)) & 0x3f) == 0) { + if (bufLen <= 13) { + code = buf << (13 - bufLen); + } else { + code = buf >> (bufLen - 13); + } + p = &blackTab1[code & 0x7f]; + } else if (bufLen >= 4 && ((buf >> (bufLen - 4)) & 0x0f) == 0) { + if (bufLen <= 12) { + code = buf << (12 - bufLen); + } else { + code = buf >> (bufLen - 12); + } + p = &blackTab2[(code & 0xff) - 64]; + } else { + if (bufLen <= 6) { + code = buf << (6 - bufLen); + } else { + code = buf >> (bufLen - 6); + } + p = &blackTab3[code & 0x3f]; + } + if (p->bits > 0 && p->bits <= (int)bufLen) { + bufLen -= p->bits; + return p->n; + } + if (bufLen >= 13) { + break; + } + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + error(str->getPos(), "Bad black code in JBIG2 MMR stream"); + // eat a bit and return a positive number so that the caller doesn't + // go into an infinite loop + --bufLen; + return 1; +} + +Guint JBIG2MMRDecoder::get24Bits() { + while (bufLen < 24) { + buf = (buf << 8) | (str->getChar() & 0xff); + bufLen += 8; + ++nBytesRead; + } + return (buf >> (bufLen - 24)) & 0xffffff; +} + +void JBIG2MMRDecoder::skipTo(Guint length) { + while (nBytesRead < length) { + str->getChar(); + ++nBytesRead; + } +} + +//------------------------------------------------------------------------ +// JBIG2Segment +//------------------------------------------------------------------------ + +enum JBIG2SegmentType { + jbig2SegBitmap, + jbig2SegSymbolDict, + jbig2SegPatternDict, + jbig2SegCodeTable +}; + +class JBIG2Segment { +public: + + JBIG2Segment(Guint segNumA) { segNum = segNumA; } + virtual ~JBIG2Segment() {} + void setSegNum(Guint segNumA) { segNum = segNumA; } + Guint getSegNum() { return segNum; } + virtual JBIG2SegmentType getType() = 0; + +private: + + Guint segNum; +}; + +//------------------------------------------------------------------------ +// JBIG2Bitmap +//------------------------------------------------------------------------ + +struct JBIG2BitmapPtr { + Guchar *p; + int shift; + int x; +}; + +class JBIG2Bitmap: public JBIG2Segment { +public: + + JBIG2Bitmap(Guint segNumA, int wA, int hA); + virtual ~JBIG2Bitmap(); + virtual JBIG2SegmentType getType() { return jbig2SegBitmap; } + JBIG2Bitmap *copy() { return new JBIG2Bitmap(0, this); } + JBIG2Bitmap *getSlice(Guint x, Guint y, Guint wA, Guint hA); + void expand(int newH, Guint pixel); + void clearToZero(); + void clearToOne(); + int getWidth() { return w; } + int getHeight() { return h; } + int getPixel(int x, int y) + { return (x < 0 || x >= w || y < 0 || y >= h) ? 0 : + (data[y * line + (x >> 3)] >> (7 - (x & 7))) & 1; } + void setPixel(int x, int y) + { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); } + void clearPixel(int x, int y) + { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); } + void getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr); + int nextPixel(JBIG2BitmapPtr *ptr); + void duplicateRow(int yDest, int ySrc); + void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp); + Guchar *getDataPtr() { return data; } + int getDataSize() { return h * line; } + +private: + + JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap); + + int w, h, line; + Guchar *data; +}; + +JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): + JBIG2Segment(segNumA) +{ + w = wA; + h = hA; + line = (wA + 7) >> 3; + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); + data[h * line] = 0; +} + +JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): + JBIG2Segment(segNumA) +{ + w = bitmap->w; + h = bitmap->h; + line = bitmap->line; + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)gmalloc(h * line + 1); + memcpy(data, bitmap->data, h * line); + data[h * line] = 0; +} + +JBIG2Bitmap::~JBIG2Bitmap() { + gfree(data); +} + +//~ optimize this +JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) { + JBIG2Bitmap *slice; + Guint xx, yy; + + slice = new JBIG2Bitmap(0, wA, hA); + slice->clearToZero(); + for (yy = 0; yy < hA; ++yy) { + for (xx = 0; xx < wA; ++xx) { + if (getPixel(x + xx, y + yy)) { + slice->setPixel(xx, yy); + } + } + } + return slice; +} + +void JBIG2Bitmap::expand(int newH, Guint pixel) { + if (newH <= h) { + return; + } + // need to allocate one extra guard byte for use in combine() + data = (Guchar *)grealloc(data, newH * line + 1); + if (pixel) { + memset(data + h * line, 0xff, (newH - h) * line); + } else { + memset(data + h * line, 0x00, (newH - h) * line); + } + h = newH; + data[h * line] = 0; +} + +void JBIG2Bitmap::clearToZero() { + memset(data, 0, h * line); +} + +void JBIG2Bitmap::clearToOne() { + memset(data, 0xff, h * line); +} + +inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) { + if (y < 0 || y >= h || x >= w) { + ptr->p = NULL; + } else if (x < 0) { + ptr->p = &data[y * line]; + ptr->shift = 7; + ptr->x = x; + } else { + ptr->p = &data[y * line + (x >> 3)]; + ptr->shift = 7 - (x & 7); + ptr->x = x; + } +} + +inline int JBIG2Bitmap::nextPixel(JBIG2BitmapPtr *ptr) { + int pix; + + if (!ptr->p) { + pix = 0; + } else if (ptr->x < 0) { + ++ptr->x; + pix = 0; + } else { + pix = (*ptr->p >> ptr->shift) & 1; + if (++ptr->x == w) { + ptr->p = NULL; + } else if (ptr->shift == 0) { + ++ptr->p; + ptr->shift = 7; + } else { + --ptr->shift; + } + } + return pix; +} + +void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) { + memcpy(data + yDest * line, data + ySrc * line, line); +} + +void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y, + Guint combOp) { + int x0, x1, y0, y1, xx, yy; + Guchar *srcPtr, *destPtr; + Guint src0, src1, src, dest, s1, s2, m1, m2, m3; + GBool oneByte; + + if (y < 0) { + y0 = -y; + } else { + y0 = 0; + } + if (y + bitmap->h > h) { + y1 = h - y; + } else { + y1 = bitmap->h; + } + if (y0 >= y1) { + return; + } + + if (x >= 0) { + x0 = x & ~7; + } else { + x0 = 0; + } + x1 = x + bitmap->w; + if (x1 > w) { + x1 = w; + } + if (x0 >= x1) { + return; + } + + s1 = x & 7; + s2 = 8 - s1; + m1 = 0xff >> (x1 & 7); + m2 = 0xff << (((x1 & 7) == 0) ? 0 : 8 - (x1 & 7)); + m3 = (0xff >> s1) & m2; + + oneByte = x0 == ((x1 - 1) & ~7); + + for (yy = y0; yy < y1; ++yy) { + + // one byte per line -- need to mask both left and right side + if (oneByte) { + if (x >= 0) { + destPtr = data + (y + yy) * line + (x >> 3); + srcPtr = bitmap->data + yy * bitmap->line; + dest = *destPtr; + src1 = *srcPtr; + switch (combOp) { + case 0: // or + dest |= (src1 >> s1) & m2; + break; + case 1: // and + dest &= ((0xff00 | src1) >> s1) | m1; + break; + case 2: // xor + dest ^= (src1 >> s1) & m2; + break; + case 3: // xnor + dest ^= ((src1 ^ 0xff) >> s1) & m2; + break; + case 4: // replace + dest = (dest & ~m3) | ((src1 >> s1) & m3); + break; + } + *destPtr = dest; + } else { + destPtr = data + (y + yy) * line; + srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); + dest = *destPtr; + src1 = *srcPtr; + switch (combOp) { + case 0: // or + dest |= src1 & m2; + break; + case 1: // and + dest &= src1 | m1; + break; + case 2: // xor + dest ^= src1 & m2; + break; + case 3: // xnor + dest ^= (src1 ^ 0xff) & m2; + break; + case 4: // replace + dest = (src1 & m2) | (dest & m1); + break; + } + *destPtr = dest; + } + + // multiple bytes per line -- need to mask left side of left-most + // byte and right side of right-most byte + } else { + + // left-most byte + if (x >= 0) { + destPtr = data + (y + yy) * line + (x >> 3); + srcPtr = bitmap->data + yy * bitmap->line; + src1 = *srcPtr++; + dest = *destPtr; + switch (combOp) { + case 0: // or + dest |= src1 >> s1; + break; + case 1: // and + dest &= (0xff00 | src1) >> s1; + break; + case 2: // xor + dest ^= src1 >> s1; + break; + case 3: // xnor + dest ^= (src1 ^ 0xff) >> s1; + break; + case 4: // replace + dest = (dest & (0xff << s2)) | (src1 >> s1); + break; + } + *destPtr++ = dest; + xx = x0 + 8; + } else { + destPtr = data + (y + yy) * line; + srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); + src1 = *srcPtr++; + xx = x0; + } + + // middle bytes + for (; xx < x1 - 8; xx += 8) { + dest = *destPtr; + src0 = src1; + src1 = *srcPtr++; + src = (((src0 << 8) | src1) >> s1) & 0xff; + switch (combOp) { + case 0: // or + dest |= src; + break; + case 1: // and + dest &= src; + break; + case 2: // xor + dest ^= src; + break; + case 3: // xnor + dest ^= src ^ 0xff; + break; + case 4: // replace + dest = src; + break; + } + *destPtr++ = dest; + } + + // right-most byte + // note: this last byte (src1) may not actually be used, depending + // on the values of s1, m1, and m2 - and in fact, it may be off + // the edge of the source bitmap, which means we need to allocate + // one extra guard byte at the end of each bitmap + dest = *destPtr; + src0 = src1; + src1 = *srcPtr++; + src = (((src0 << 8) | src1) >> s1) & 0xff; + switch (combOp) { + case 0: // or + dest |= src & m2; + break; + case 1: // and + dest &= src | m1; + break; + case 2: // xor + dest ^= src & m2; + break; + case 3: // xnor + dest ^= (src ^ 0xff) & m2; + break; + case 4: // replace + dest = (src & m2) | (dest & m1); + break; + } + *destPtr = dest; + } + } +} + +//------------------------------------------------------------------------ +// JBIG2SymbolDict +//------------------------------------------------------------------------ + +class JBIG2SymbolDict: public JBIG2Segment { +public: + + JBIG2SymbolDict(Guint segNumA, Guint sizeA); + virtual ~JBIG2SymbolDict(); + virtual JBIG2SegmentType getType() { return jbig2SegSymbolDict; } + Guint getSize() { return size; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } + JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } + void setGenericRegionStats(JArithmeticDecoderStats *stats) + { genericRegionStats = stats; } + void setRefinementRegionStats(JArithmeticDecoderStats *stats) + { refinementRegionStats = stats; } + JArithmeticDecoderStats *getGenericRegionStats() + { return genericRegionStats; } + JArithmeticDecoderStats *getRefinementRegionStats() + { return refinementRegionStats; } + +private: + + Guint size; + JBIG2Bitmap **bitmaps; + JArithmeticDecoderStats *genericRegionStats; + JArithmeticDecoderStats *refinementRegionStats; +}; + +JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA): + JBIG2Segment(segNumA) +{ + size = sizeA; + bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); + genericRegionStats = NULL; + refinementRegionStats = NULL; +} + +JBIG2SymbolDict::~JBIG2SymbolDict() { + Guint i; + + for (i = 0; i < size; ++i) { + delete bitmaps[i]; + } + gfree(bitmaps); + if (genericRegionStats) { + delete genericRegionStats; + } + if (refinementRegionStats) { + delete refinementRegionStats; + } +} + +//------------------------------------------------------------------------ +// JBIG2PatternDict +//------------------------------------------------------------------------ + +class JBIG2PatternDict: public JBIG2Segment { +public: + + JBIG2PatternDict(Guint segNumA, Guint sizeA); + virtual ~JBIG2PatternDict(); + virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; } + Guint getSize() { return size; } + void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } + JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } + +private: + + Guint size; + JBIG2Bitmap **bitmaps; +}; + +JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): + JBIG2Segment(segNumA) +{ + size = sizeA; + bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); +} + +JBIG2PatternDict::~JBIG2PatternDict() { + Guint i; + + for (i = 0; i < size; ++i) { + delete bitmaps[i]; + } + gfree(bitmaps); +} + +//------------------------------------------------------------------------ +// JBIG2CodeTable +//------------------------------------------------------------------------ + +class JBIG2CodeTable: public JBIG2Segment { +public: + + JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA); + virtual ~JBIG2CodeTable(); + virtual JBIG2SegmentType getType() { return jbig2SegCodeTable; } + JBIG2HuffmanTable *getHuffTable() { return table; } + +private: + + JBIG2HuffmanTable *table; +}; + +JBIG2CodeTable::JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA): + JBIG2Segment(segNumA) +{ + table = tableA; +} + +JBIG2CodeTable::~JBIG2CodeTable() { + gfree(table); +} + +//------------------------------------------------------------------------ +// JBIG2Stream +//------------------------------------------------------------------------ + +JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStream): + FilterStream(strA) +{ + pageBitmap = NULL; + + arithDecoder = new JArithmeticDecoder(); + genericRegionStats = new JArithmeticDecoderStats(1 << 1); + refinementRegionStats = new JArithmeticDecoderStats(1 << 1); + iadhStats = new JArithmeticDecoderStats(1 << 9); + iadwStats = new JArithmeticDecoderStats(1 << 9); + iaexStats = new JArithmeticDecoderStats(1 << 9); + iaaiStats = new JArithmeticDecoderStats(1 << 9); + iadtStats = new JArithmeticDecoderStats(1 << 9); + iaitStats = new JArithmeticDecoderStats(1 << 9); + iafsStats = new JArithmeticDecoderStats(1 << 9); + iadsStats = new JArithmeticDecoderStats(1 << 9); + iardxStats = new JArithmeticDecoderStats(1 << 9); + iardyStats = new JArithmeticDecoderStats(1 << 9); + iardwStats = new JArithmeticDecoderStats(1 << 9); + iardhStats = new JArithmeticDecoderStats(1 << 9); + iariStats = new JArithmeticDecoderStats(1 << 9); + iaidStats = new JArithmeticDecoderStats(1 << 1); + huffDecoder = new JBIG2HuffmanDecoder(); + mmrDecoder = new JBIG2MMRDecoder(); + + segments = globalSegments = new GList(); + if (globalsStream->isStream()) { + curStr = globalsStream->getStream(); + curStr->reset(); + arithDecoder->setStream(curStr); + huffDecoder->setStream(curStr); + mmrDecoder->setStream(curStr); + readSegments(); + } + + segments = NULL; + curStr = NULL; + dataPtr = dataEnd = NULL; +} + +JBIG2Stream::~JBIG2Stream() { + delete arithDecoder; + delete genericRegionStats; + delete refinementRegionStats; + delete iadhStats; + delete iadwStats; + delete iaexStats; + delete iaaiStats; + delete iadtStats; + delete iaitStats; + delete iafsStats; + delete iadsStats; + delete iardxStats; + delete iardyStats; + delete iardwStats; + delete iardhStats; + delete iariStats; + delete iaidStats; + delete huffDecoder; + delete mmrDecoder; + if (pageBitmap) { + delete pageBitmap; + } + if (segments) { + deleteGList(segments, JBIG2Segment); + } + if (globalSegments) { + deleteGList(globalSegments, JBIG2Segment); + } + delete str; +} + +void JBIG2Stream::reset() { + if (pageBitmap) { + delete pageBitmap; + pageBitmap = NULL; + } + if (segments) { + deleteGList(segments, JBIG2Segment); + } + segments = new GList(); + + curStr = str; + curStr->reset(); + arithDecoder->setStream(curStr); + huffDecoder->setStream(curStr); + mmrDecoder->setStream(curStr); + readSegments(); + + if (pageBitmap) { + dataPtr = pageBitmap->getDataPtr(); + dataEnd = dataPtr + pageBitmap->getDataSize(); + } else { + dataPtr = NULL; + } +} + +int JBIG2Stream::getChar() { + if (dataPtr && dataPtr < dataEnd) { + return (*dataPtr++ ^ 0xff) & 0xff; + } + return EOF; +} + +int JBIG2Stream::lookChar() { + if (dataPtr && dataPtr < dataEnd) { + return (*dataPtr ^ 0xff) & 0xff; + } + return EOF; +} + +GString *JBIG2Stream::getPSFilter(int psLevel, char *indent) { + return NULL; +} + +GBool JBIG2Stream::isBinary(GBool last) { + return str->isBinary(gTrue); +} + +void JBIG2Stream::readSegments() { + Guint segNum, segFlags, segType, page, segLength; + Guint refFlags, nRefSegs; + Guint *refSegs; + int c1, c2, c3; + Guint i; + + while (readULong(&segNum)) { + + // segment header flags + if (!readUByte(&segFlags)) { + goto eofError1; + } + segType = segFlags & 0x3f; + + // referred-to segment count and retention flags + if (!readUByte(&refFlags)) { + goto eofError1; + } + nRefSegs = refFlags >> 5; + if (nRefSegs == 7) { + if ((c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + goto eofError1; + } + refFlags = (refFlags << 24) | (c1 << 16) | (c2 << 8) | c3; + nRefSegs = refFlags & 0x1fffffff; + for (i = 0; i < (nRefSegs + 9) >> 3; ++i) { + c1 = curStr->getChar(); + } + } + + // referred-to segment numbers + refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint)); + if (segNum <= 256) { + for (i = 0; i < nRefSegs; ++i) { + if (!readUByte(&refSegs[i])) { + goto eofError2; + } + } + } else if (segNum <= 65536) { + for (i = 0; i < nRefSegs; ++i) { + if (!readUWord(&refSegs[i])) { + goto eofError2; + } + } + } else { + for (i = 0; i < nRefSegs; ++i) { + if (!readULong(&refSegs[i])) { + goto eofError2; + } + } + } + + // segment page association + if (segFlags & 0x40) { + if (!readULong(&page)) { + goto eofError2; + } + } else { + if (!readUByte(&page)) { + goto eofError2; + } + } + + // segment data length + if (!readULong(&segLength)) { + goto eofError2; + } + + // read the segment data + switch (segType) { + case 0: + if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) { + goto syntaxError; + } + break; + case 4: + readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); + break; + case 6: + readTextRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs); + break; + case 7: + readTextRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs); + break; + case 16: + readPatternDictSeg(segNum, segLength); + break; + case 20: + readHalftoneRegionSeg(segNum, gFalse, gFalse, segLength, + refSegs, nRefSegs); + break; + case 22: + readHalftoneRegionSeg(segNum, gTrue, gFalse, segLength, + refSegs, nRefSegs); + break; + case 23: + readHalftoneRegionSeg(segNum, gTrue, gTrue, segLength, + refSegs, nRefSegs); + break; + case 36: + readGenericRegionSeg(segNum, gFalse, gFalse, segLength); + break; + case 38: + readGenericRegionSeg(segNum, gTrue, gFalse, segLength); + break; + case 39: + readGenericRegionSeg(segNum, gTrue, gTrue, segLength); + break; + case 40: + readGenericRefinementRegionSeg(segNum, gFalse, gFalse, segLength, + refSegs, nRefSegs); + break; + case 42: + readGenericRefinementRegionSeg(segNum, gTrue, gFalse, segLength, + refSegs, nRefSegs); + break; + case 43: + readGenericRefinementRegionSeg(segNum, gTrue, gTrue, segLength, + refSegs, nRefSegs); + break; + case 48: + readPageInfoSeg(segLength); + break; + case 50: + readEndOfStripeSeg(segLength); + break; + case 52: + readProfilesSeg(segLength); + break; + case 53: + readCodeTableSeg(segNum, segLength); + break; + case 62: + readExtensionSeg(segLength); + break; + default: + error(getPos(), "Unknown segment type in JBIG2 stream"); + for (i = 0; i < segLength; ++i) { + if ((c1 = curStr->getChar()) == EOF) { + goto eofError2; + } + } + break; + } + + gfree(refSegs); + } + + return; + + syntaxError: + gfree(refSegs); + return; + + eofError2: + gfree(refSegs); + eofError1: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, + Guint *refSegs, Guint nRefSegs) { + JBIG2SymbolDict *symbolDict; + JBIG2HuffmanTable *huffDHTable, *huffDWTable; + JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable; + JBIG2Segment *seg; + GList *codeTables; + JBIG2SymbolDict *inputSymbolDict; + Guint flags, sdTemplate, sdrTemplate, huff, refAgg; + Guint huffDH, huffDW, huffBMSize, huffAggInst; + Guint contextUsed, contextRetained; + int sdATX[4], sdATY[4], sdrATX[2], sdrATY[2]; + Guint numExSyms, numNewSyms, numInputSyms, symCodeLen; + JBIG2Bitmap **bitmaps; + JBIG2Bitmap *collBitmap, *refBitmap; + Guint *symWidths; + Guint symHeight, symWidth, totalWidth, x, symID; + int dh, dw, refAggNum, refDX, refDY, bmSize; + GBool ex; + int run, cnt; + Guint i, j, k; + Guchar *p; + + // symbol dictionary flags + if (!readUWord(&flags)) { + goto eofError; + } + sdTemplate = (flags >> 10) & 3; + sdrTemplate = (flags >> 12) & 1; + huff = flags & 1; + refAgg = (flags >> 1) & 1; + huffDH = (flags >> 2) & 3; + huffDW = (flags >> 4) & 3; + huffBMSize = (flags >> 6) & 1; + huffAggInst = (flags >> 7) & 1; + contextUsed = (flags >> 8) & 1; + contextRetained = (flags >> 9) & 1; + + // symbol dictionary AT flags + if (!huff) { + if (sdTemplate == 0) { + if (!readByte(&sdATX[0]) || + !readByte(&sdATY[0]) || + !readByte(&sdATX[1]) || + !readByte(&sdATY[1]) || + !readByte(&sdATX[2]) || + !readByte(&sdATY[2]) || + !readByte(&sdATX[3]) || + !readByte(&sdATY[3])) { + goto eofError; + } + } else { + if (!readByte(&sdATX[0]) || + !readByte(&sdATY[0])) { + goto eofError; + } + } + } + + // symbol dictionary refinement AT flags + if (refAgg && !sdrTemplate) { + if (!readByte(&sdrATX[0]) || + !readByte(&sdrATY[0]) || + !readByte(&sdrATX[1]) || + !readByte(&sdrATY[1])) { + goto eofError; + } + } + + // SDNUMEXSYMS and SDNUMNEWSYMS + if (!readULong(&numExSyms) || !readULong(&numNewSyms)) { + goto eofError; + } + + // get referenced segments: input symbol dictionaries and code tables + codeTables = new GList(); + numInputSyms = 0; + for (i = 0; i < nRefSegs; ++i) { + seg = findSegment(refSegs[i]); + if (seg->getType() == jbig2SegSymbolDict) { + numInputSyms += ((JBIG2SymbolDict *)seg)->getSize(); + } else if (seg->getType() == jbig2SegCodeTable) { + codeTables->append(seg); + } + } + + // compute symbol code length + symCodeLen = 0; + i = 1; + while (i < numInputSyms + numNewSyms) { + ++symCodeLen; + i <<= 1; + } + + // get the input symbol bitmaps + bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms, + sizeof(JBIG2Bitmap *)); + for (i = 0; i < numInputSyms + numNewSyms; ++i) { + bitmaps[i] = NULL; + } + k = 0; + inputSymbolDict = NULL; + for (i = 0; i < nRefSegs; ++i) { + seg = findSegment(refSegs[i]); + if (seg->getType() == jbig2SegSymbolDict) { + inputSymbolDict = (JBIG2SymbolDict *)seg; + for (j = 0; j < inputSymbolDict->getSize(); ++j) { + bitmaps[k++] = inputSymbolDict->getBitmap(j); + } + } + } + + // get the Huffman tables + huffDHTable = huffDWTable = NULL; // make gcc happy + huffBMSizeTable = huffAggInstTable = NULL; // make gcc happy + i = 0; + if (huff) { + if (huffDH == 0) { + huffDHTable = huffTableD; + } else if (huffDH == 1) { + huffDHTable = huffTableE; + } else { + huffDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDW == 0) { + huffDWTable = huffTableB; + } else if (huffDW == 1) { + huffDWTable = huffTableC; + } else { + huffDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffBMSize == 0) { + huffBMSizeTable = huffTableA; + } else { + huffBMSizeTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffAggInst == 0) { + huffAggInstTable = huffTableA; + } else { + huffAggInstTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + } + delete codeTables; + + // set up the Huffman decoder + if (huff) { + huffDecoder->reset(); + + // set up the arithmetic decoder + } else { + if (contextUsed && inputSymbolDict) { + resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats()); + } else { + resetGenericStats(sdTemplate, NULL); + } + resetIntStats(symCodeLen); + arithDecoder->start(); + } + + // set up the arithmetic decoder for refinement/aggregation + if (refAgg) { + if (contextUsed && inputSymbolDict) { + resetRefinementStats(sdrTemplate, + inputSymbolDict->getRefinementRegionStats()); + } else { + resetRefinementStats(sdrTemplate, NULL); + } + } + + // allocate symbol widths storage + symWidths = NULL; + if (huff && !refAgg) { + symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint)); + } + + symHeight = 0; + i = 0; + while (i < numNewSyms) { + + // read the height class delta height + if (huff) { + huffDecoder->decodeInt(&dh, huffDHTable); + } else { + arithDecoder->decodeInt(&dh, iadhStats); + } + if (dh < 0 && (Guint)-dh >= symHeight) { + error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); + goto syntaxError; + } + symHeight += dh; + symWidth = 0; + totalWidth = 0; + j = i; + + // read the symbols in this height class + while (1) { + + // read the delta width + if (huff) { + if (!huffDecoder->decodeInt(&dw, huffDWTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&dw, iadwStats)) { + break; + } + } + if (dw < 0 && (Guint)-dw >= symWidth) { + error(getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); + goto syntaxError; + } + symWidth += dw; + + // using a collective bitmap, so don't read a bitmap here + if (huff && !refAgg) { + symWidths[i] = symWidth; + totalWidth += symWidth; + + // refinement/aggregate coding + } else if (refAgg) { + if (huff) { + if (!huffDecoder->decodeInt(&refAggNum, huffAggInstTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&refAggNum, iaaiStats)) { + break; + } + } +#if 0 //~ This special case was added about a year before the final draft + //~ of the JBIG2 spec was released. I have encountered some old + //~ JBIG2 images that predate it. + if (0) { +#else + if (refAggNum == 1) { +#endif + if (huff) { + symID = huffDecoder->readBits(symCodeLen); + huffDecoder->decodeInt(&refDX, huffTableO); + huffDecoder->decodeInt(&refDY, huffTableO); + huffDecoder->decodeInt(&bmSize, huffTableA); + huffDecoder->reset(); + arithDecoder->start(); + } else { + symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); + arithDecoder->decodeInt(&refDX, iardxStats); + arithDecoder->decodeInt(&refDY, iardyStats); + } + refBitmap = bitmaps[symID]; + bitmaps[numInputSyms + i] = + readGenericRefinementRegion(symWidth, symHeight, + sdrTemplate, gFalse, + refBitmap, refDX, refDY, + sdrATX, sdrATY); + //~ do we need to use the bmSize value here (in Huffman mode)? + } else { + bitmaps[numInputSyms + i] = + readTextRegion(huff, gTrue, symWidth, symHeight, + refAggNum, 0, numInputSyms + i, NULL, + symCodeLen, bitmaps, 0, 0, 0, 1, 0, + huffTableF, huffTableH, huffTableK, huffTableO, + huffTableO, huffTableO, huffTableO, huffTableA, + sdrTemplate, sdrATX, sdrATY); + } + + // non-ref/agg coding + } else { + bitmaps[numInputSyms + i] = + readGenericBitmap(gFalse, symWidth, symHeight, + sdTemplate, gFalse, gFalse, NULL, + sdATX, sdATY, 0); + } + + ++i; + } + + // read the collective bitmap + if (huff && !refAgg) { + huffDecoder->decodeInt(&bmSize, huffBMSizeTable); + huffDecoder->reset(); + if (bmSize == 0) { + collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight); + bmSize = symHeight * ((totalWidth + 7) >> 3); + p = collBitmap->getDataPtr(); + for (k = 0; k < (Guint)bmSize; ++k) { + *p++ = curStr->getChar(); + } + } else { + collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight, + 0, gFalse, gFalse, NULL, NULL, NULL, + bmSize); + } + x = 0; + for (; j < i; ++j) { + bitmaps[numInputSyms + j] = + collBitmap->getSlice(x, 0, symWidths[j], symHeight); + x += symWidths[j]; + } + delete collBitmap; + } + } + + // create the symbol dict object + symbolDict = new JBIG2SymbolDict(segNum, numExSyms); + + // exported symbol list + i = j = 0; + ex = gFalse; + while (i < numInputSyms + numNewSyms) { + if (huff) { + huffDecoder->decodeInt(&run, huffTableA); + } else { + arithDecoder->decodeInt(&run, iaexStats); + } + if (ex) { + for (cnt = 0; cnt < run; ++cnt) { + symbolDict->setBitmap(j++, bitmaps[i++]->copy()); + } + } else { + i += run; + } + ex = !ex; + } + + for (i = 0; i < numNewSyms; ++i) { + delete bitmaps[numInputSyms + i]; + } + gfree(bitmaps); + if (symWidths) { + gfree(symWidths); + } + + // save the arithmetic decoder stats + if (!huff && contextRetained) { + symbolDict->setGenericRegionStats(genericRegionStats->copy()); + if (refAgg) { + symbolDict->setRefinementRegionStats(refinementRegionStats->copy()); + } + } + + // store the new symbol dict + segments->append(symbolDict); + + return gTrue; + + syntaxError: + for (i = 0; i < numNewSyms; ++i) { + if (bitmaps[numInputSyms + i]) { + delete bitmaps[numInputSyms + i]; + } + } + gfree(bitmaps); + if (symWidths) { + gfree(symWidths); + } + return gFalse; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); + return gFalse; +} + +void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs) { + JBIG2Bitmap *bitmap; + JBIG2HuffmanTable runLengthTab[36]; + JBIG2HuffmanTable *symCodeTab; + JBIG2HuffmanTable *huffFSTable, *huffDSTable, *huffDTTable; + JBIG2HuffmanTable *huffRDWTable, *huffRDHTable; + JBIG2HuffmanTable *huffRDXTable, *huffRDYTable, *huffRSizeTable; + JBIG2Segment *seg; + GList *codeTables; + JBIG2SymbolDict *symbolDict; + JBIG2Bitmap **syms; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, huff, refine, logStrips, refCorner, transposed; + Guint combOp, defPixel, templ; + int sOffset; + Guint huffFlags, huffFS, huffDS, huffDT; + Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize; + Guint numInstances, numSyms, symCodeLen; + int atx[2], aty[2]; + Guint i, k, kk; + int j; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the text region header + if (!readUWord(&flags)) { + goto eofError; + } + huff = flags & 1; + refine = (flags >> 1) & 1; + logStrips = (flags >> 2) & 3; + refCorner = (flags >> 4) & 3; + transposed = (flags >> 6) & 1; + combOp = (flags >> 7) & 3; + defPixel = (flags >> 9) & 1; + sOffset = (flags >> 10) & 0x1f; + if (sOffset & 0x10) { + sOffset |= -1 - 0x0f; + } + templ = (flags >> 15) & 1; + huffFS = huffDS = huffDT = 0; // make gcc happy + huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy + if (huff) { + if (!readUWord(&huffFlags)) { + goto eofError; + } + huffFS = huffFlags & 3; + huffDS = (huffFlags >> 2) & 3; + huffDT = (huffFlags >> 4) & 3; + huffRDW = (huffFlags >> 6) & 3; + huffRDH = (huffFlags >> 8) & 3; + huffRDX = (huffFlags >> 10) & 3; + huffRDY = (huffFlags >> 12) & 3; + huffRSize = (huffFlags >> 14) & 1; + } + if (refine && templ == 0) { + if (!readByte(&atx[0]) || !readByte(&aty[0]) || + !readByte(&atx[1]) || !readByte(&aty[1])) { + goto eofError; + } + } + if (!readULong(&numInstances)) { + goto eofError; + } + + // get symbol dictionaries and tables + codeTables = new GList(); + numSyms = 0; + for (i = 0; i < nRefSegs; ++i) { + if ((seg = findSegment(refSegs[i]))) { + if (seg->getType() == jbig2SegSymbolDict) { + numSyms += ((JBIG2SymbolDict *)seg)->getSize(); + } else if (seg->getType() == jbig2SegCodeTable) { + codeTables->append(seg); + } + } else { + error(getPos(), "Invalid segment reference in JBIG2 text region"); + } + } + symCodeLen = 0; + i = 1; + while (i < numSyms) { + ++symCodeLen; + i <<= 1; + } + + // get the symbol bitmaps + syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *)); + kk = 0; + for (i = 0; i < nRefSegs; ++i) { + if ((seg = findSegment(refSegs[i]))) { + if (seg->getType() == jbig2SegSymbolDict) { + symbolDict = (JBIG2SymbolDict *)seg; + for (k = 0; k < symbolDict->getSize(); ++k) { + syms[kk++] = symbolDict->getBitmap(k); + } + } + } + } + + // get the Huffman tables + huffFSTable = huffDSTable = huffDTTable = NULL; // make gcc happy + huffRDWTable = huffRDHTable = NULL; // make gcc happy + huffRDXTable = huffRDYTable = huffRSizeTable = NULL; // make gcc happy + i = 0; + if (huff) { + if (huffFS == 0) { + huffFSTable = huffTableF; + } else if (huffFS == 1) { + huffFSTable = huffTableG; + } else { + huffFSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDS == 0) { + huffDSTable = huffTableH; + } else if (huffDS == 1) { + huffDSTable = huffTableI; + } else if (huffDS == 2) { + huffDSTable = huffTableJ; + } else { + huffDSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffDT == 0) { + huffDTTable = huffTableK; + } else if (huffDT == 1) { + huffDTTable = huffTableL; + } else if (huffDT == 2) { + huffDTTable = huffTableM; + } else { + huffDTTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDW == 0) { + huffRDWTable = huffTableN; + } else if (huffRDW == 1) { + huffRDWTable = huffTableO; + } else { + huffRDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDH == 0) { + huffRDHTable = huffTableN; + } else if (huffRDH == 1) { + huffRDHTable = huffTableO; + } else { + huffRDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDX == 0) { + huffRDXTable = huffTableN; + } else if (huffRDX == 1) { + huffRDXTable = huffTableO; + } else { + huffRDXTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRDY == 0) { + huffRDYTable = huffTableN; + } else if (huffRDY == 1) { + huffRDYTable = huffTableO; + } else { + huffRDYTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + if (huffRSize == 0) { + huffRSizeTable = huffTableA; + } else { + huffRSizeTable = + ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); + } + } + delete codeTables; + + // symbol ID Huffman decoding table + if (huff) { + huffDecoder->reset(); + for (i = 0; i < 32; ++i) { + runLengthTab[i].val = i; + runLengthTab[i].prefixLen = huffDecoder->readBits(4); + runLengthTab[i].rangeLen = 0; + } + runLengthTab[32].val = 0x103; + runLengthTab[32].prefixLen = huffDecoder->readBits(4); + runLengthTab[32].rangeLen = 2; + runLengthTab[33].val = 0x203; + runLengthTab[33].prefixLen = huffDecoder->readBits(4); + runLengthTab[33].rangeLen = 3; + runLengthTab[34].val = 0x20b; + runLengthTab[34].prefixLen = huffDecoder->readBits(4); + runLengthTab[34].rangeLen = 7; + runLengthTab[35].prefixLen = 0; + runLengthTab[35].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(runLengthTab, 35); + symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1, + sizeof(JBIG2HuffmanTable)); + for (i = 0; i < numSyms; ++i) { + symCodeTab[i].val = i; + symCodeTab[i].rangeLen = 0; + } + i = 0; + while (i < numSyms) { + huffDecoder->decodeInt(&j, runLengthTab); + if (j > 0x200) { + for (j -= 0x200; j && i < numSyms; --j) { + symCodeTab[i++].prefixLen = 0; + } + } else if (j > 0x100) { + for (j -= 0x100; j && i < numSyms; --j) { + symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; + ++i; + } + } else { + symCodeTab[i++].prefixLen = j; + } + } + symCodeTab[numSyms].prefixLen = 0; + symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(symCodeTab, numSyms); + huffDecoder->reset(); + + // set up the arithmetic decoder + } else { + symCodeTab = NULL; + resetIntStats(symCodeLen); + arithDecoder->start(); + } + if (refine) { + resetRefinementStats(templ, NULL); + } + + bitmap = readTextRegion(huff, refine, w, h, numInstances, + logStrips, numSyms, symCodeTab, symCodeLen, syms, + defPixel, combOp, transposed, refCorner, sOffset, + huffFSTable, huffDSTable, huffDTTable, + huffRDWTable, huffRDHTable, + huffRDXTable, huffRDYTable, huffRSizeTable, + templ, atx, aty); + + gfree(syms); + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + // clean up the Huffman decoder + if (huff) { + gfree(symCodeTab); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, + int w, int h, + Guint numInstances, + Guint logStrips, + int numSyms, + JBIG2HuffmanTable *symCodeTab, + Guint symCodeLen, + JBIG2Bitmap **syms, + Guint defPixel, Guint combOp, + Guint transposed, Guint refCorner, + int sOffset, + JBIG2HuffmanTable *huffFSTable, + JBIG2HuffmanTable *huffDSTable, + JBIG2HuffmanTable *huffDTTable, + JBIG2HuffmanTable *huffRDWTable, + JBIG2HuffmanTable *huffRDHTable, + JBIG2HuffmanTable *huffRDXTable, + JBIG2HuffmanTable *huffRDYTable, + JBIG2HuffmanTable *huffRSizeTable, + Guint templ, + int *atx, int *aty) { + JBIG2Bitmap *bitmap; + JBIG2Bitmap *symbolBitmap; + Guint strips; + int t, dt, tt, s, ds, sFirst, j; + int rdw, rdh, rdx, rdy, ri, refDX, refDY, bmSize; + Guint symID, inst, bw, bh; + + strips = 1 << logStrips; + + // allocate the bitmap + bitmap = new JBIG2Bitmap(0, w, h); + if (defPixel) { + bitmap->clearToOne(); + } else { + bitmap->clearToZero(); + } + + // decode initial T value + if (huff) { + huffDecoder->decodeInt(&t, huffDTTable); + } else { + arithDecoder->decodeInt(&t, iadtStats); + } + t *= -(int)strips; + + inst = 0; + sFirst = 0; + while (inst < numInstances) { + + // decode delta-T + if (huff) { + huffDecoder->decodeInt(&dt, huffDTTable); + } else { + arithDecoder->decodeInt(&dt, iadtStats); + } + t += dt * strips; + + // first S value + if (huff) { + huffDecoder->decodeInt(&ds, huffFSTable); + } else { + arithDecoder->decodeInt(&ds, iafsStats); + } + sFirst += ds; + s = sFirst; + + // read the instances + while (1) { + + // T value + if (strips == 1) { + dt = 0; + } else if (huff) { + dt = huffDecoder->readBits(logStrips); + } else { + arithDecoder->decodeInt(&dt, iaitStats); + } + tt = t + dt; + + // symbol ID + if (huff) { + if (symCodeTab) { + huffDecoder->decodeInt(&j, symCodeTab); + symID = (Guint)j; + } else { + symID = huffDecoder->readBits(symCodeLen); + } + } else { + symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); + } + + if (symID >= (Guint)numSyms) { + error(getPos(), "Invalid symbol number in JBIG2 text region"); + } else { + + // get the symbol bitmap + symbolBitmap = NULL; + if (refine) { + if (huff) { + ri = (int)huffDecoder->readBit(); + } else { + arithDecoder->decodeInt(&ri, iariStats); + } + } else { + ri = 0; + } + if (ri) { + if (huff) { + huffDecoder->decodeInt(&rdw, huffRDWTable); + huffDecoder->decodeInt(&rdh, huffRDHTable); + huffDecoder->decodeInt(&rdx, huffRDXTable); + huffDecoder->decodeInt(&rdy, huffRDYTable); + huffDecoder->decodeInt(&bmSize, huffRSizeTable); + huffDecoder->reset(); + arithDecoder->start(); + } else { + arithDecoder->decodeInt(&rdw, iardwStats); + arithDecoder->decodeInt(&rdh, iardhStats); + arithDecoder->decodeInt(&rdx, iardxStats); + arithDecoder->decodeInt(&rdy, iardyStats); + } + refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx; + refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy; + + symbolBitmap = + readGenericRefinementRegion(rdw + syms[symID]->getWidth(), + rdh + syms[symID]->getHeight(), + templ, gFalse, syms[symID], + refDX, refDY, atx, aty); + //~ do we need to use the bmSize value here (in Huffman mode)? + } else { + symbolBitmap = syms[symID]; + } + + // combine the symbol bitmap into the region bitmap + //~ something is wrong here - refCorner shouldn't degenerate into + //~ two cases + bw = symbolBitmap->getWidth() - 1; + bh = symbolBitmap->getHeight() - 1; + if (transposed) { + switch (refCorner) { + case 0: // bottom left + bitmap->combine(symbolBitmap, tt, s, combOp); + break; + case 1: // top left + bitmap->combine(symbolBitmap, tt, s, combOp); + break; + case 2: // bottom right + bitmap->combine(symbolBitmap, tt - bw, s, combOp); + break; + case 3: // top right + bitmap->combine(symbolBitmap, tt - bw, s, combOp); + break; + } + s += bh; + } else { + switch (refCorner) { + case 0: // bottom left + bitmap->combine(symbolBitmap, s, tt - bh, combOp); + break; + case 1: // top left + bitmap->combine(symbolBitmap, s, tt, combOp); + break; + case 2: // bottom right + bitmap->combine(symbolBitmap, s, tt - bh, combOp); + break; + case 3: // top right + bitmap->combine(symbolBitmap, s, tt, combOp); + break; + } + s += bw; + } + if (ri) { + delete symbolBitmap; + } + } + + // next instance + ++inst; + + // next S value + if (huff) { + if (!huffDecoder->decodeInt(&ds, huffDSTable)) { + break; + } + } else { + if (!arithDecoder->decodeInt(&ds, iadsStats)) { + break; + } + } + s += sOffset + ds; + } + } + + return bitmap; +} + +void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) { + JBIG2PatternDict *patternDict; + JBIG2Bitmap *bitmap; + Guint flags, patternW, patternH, grayMax, templ, mmr; + int atx[4], aty[4]; + Guint i, x; + + // halftone dictionary flags, pattern width and height, max gray value + if (!readUByte(&flags) || + !readUByte(&patternW) || + !readUByte(&patternH) || + !readULong(&grayMax)) { + goto eofError; + } + templ = (flags >> 1) & 3; + mmr = flags & 1; + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // read the bitmap + atx[0] = -(int)patternW; aty[0] = 0; + atx[1] = -3; aty[1] = -1; + atx[2] = 2; aty[2] = -2; + atx[3] = -2; aty[3] = -2; + bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH, + templ, gFalse, gFalse, NULL, + atx, aty, length - 7); + + // create the pattern dict object + patternDict = new JBIG2PatternDict(segNum, grayMax + 1); + + // split up the bitmap + x = 0; + for (i = 0; i <= grayMax; ++i) { + patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH)); + x += patternW; + } + + // free memory + delete bitmap; + + // store the new pattern dict + segments->append(patternDict); + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs) { + JBIG2Bitmap *bitmap; + JBIG2Segment *seg; + JBIG2PatternDict *patternDict; + JBIG2Bitmap *skipBitmap; + Guint *grayImg; + JBIG2Bitmap *grayBitmap; + JBIG2Bitmap *patternBitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, mmr, templ, enableSkip, combOp; + Guint gridW, gridH, stepX, stepY, patW, patH; + int atx[4], aty[4]; + int gridX, gridY, xx, yy, bit, j; + Guint bpp, m, n, i; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the halftone region header + if (!readUByte(&flags)) { + goto eofError; + } + mmr = flags & 1; + templ = (flags >> 1) & 3; + enableSkip = (flags >> 3) & 1; + combOp = (flags >> 4) & 7; + if (!readULong(&gridW) || !readULong(&gridH) || + !readLong(&gridX) || !readLong(&gridY) || + !readUWord(&stepX) || !readUWord(&stepY)) { + goto eofError; + } + + // get pattern dictionary + if (nRefSegs != 1) { + error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); + return; + } + seg = findSegment(refSegs[0]); + if (seg->getType() != jbig2SegPatternDict) { + error(getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); + return; + } + patternDict = (JBIG2PatternDict *)seg; + bpp = 0; + i = 1; + while (i < patternDict->getSize()) { + ++bpp; + i <<= 1; + } + patW = patternDict->getBitmap(0)->getWidth(); + patH = patternDict->getBitmap(0)->getHeight(); + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // allocate the bitmap + bitmap = new JBIG2Bitmap(segNum, w, h); + if (flags & 0x80) { // HDEFPIXEL + bitmap->clearToOne(); + } else { + bitmap->clearToZero(); + } + + // compute the skip bitmap + skipBitmap = NULL; + if (enableSkip) { + skipBitmap = new JBIG2Bitmap(0, gridW, gridH); + skipBitmap->clearToZero(); + for (m = 0; m < gridH; ++m) { + xx = gridX + m * stepY; + yy = gridY + m * stepX; + for (n = 0; n < gridW; ++n) { + if (((xx + (int)patW) >> 8) <= 0 || (xx >> 8) >= (int)w || + ((yy + (int)patH) >> 8) <= 0 || (yy >> 8) >= (int)h) { + skipBitmap->setPixel(n, m); + } + } + } + } + + // read the gray-scale image + grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint)); + memset(grayImg, 0, gridW * gridH * sizeof(Guint)); + atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1; + atx[1] = -3; aty[1] = -1; + atx[2] = 2; aty[2] = -2; + atx[3] = -2; aty[3] = -2; + for (j = bpp - 1; j >= 0; --j) { + grayBitmap = readGenericBitmap(mmr, gridW, gridH, templ, gFalse, + enableSkip, skipBitmap, atx, aty, -1); + i = 0; + for (m = 0; m < gridH; ++m) { + for (n = 0; n < gridW; ++n) { + bit = grayBitmap->getPixel(n, m) ^ (grayImg[i] & 1); + grayImg[i] = (grayImg[i] << 1) | bit; + ++i; + } + } + delete grayBitmap; + } + + // decode the image + i = 0; + for (m = 0; m < gridH; ++m) { + xx = gridX + m * stepY; + yy = gridY + m * stepX; + for (n = 0; n < gridW; ++n) { + if (!(enableSkip && skipBitmap->getPixel(n, m))) { + patternBitmap = patternDict->getBitmap(grayImg[i]); + bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp); + } + xx += stepX; + yy -= stepY; + ++i; + } + } + + gfree(grayImg); + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + segments->append(bitmap); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length) { + JBIG2Bitmap *bitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, mmr, templ, tpgdOn; + int atx[4], aty[4]; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the generic region segment header + if (!readUByte(&flags)) { + goto eofError; + } + mmr = flags & 1; + templ = (flags >> 1) & 3; + tpgdOn = (flags >> 3) & 1; + + // AT flags + if (!mmr) { + if (templ == 0) { + if (!readByte(&atx[0]) || + !readByte(&aty[0]) || + !readByte(&atx[1]) || + !readByte(&aty[1]) || + !readByte(&atx[2]) || + !readByte(&aty[2]) || + !readByte(&atx[3]) || + !readByte(&aty[3])) { + goto eofError; + } + } else { + if (!readByte(&atx[0]) || + !readByte(&aty[0])) { + goto eofError; + } + } + } + + // set up the arithmetic decoder + if (!mmr) { + resetGenericStats(templ, NULL); + arithDecoder->start(); + } + + // read the bitmap + bitmap = readGenericBitmap(mmr, w, h, templ, tpgdOn, gFalse, + NULL, atx, aty, mmr ? 0 : length - 18); + + // combine the region bitmap into the page bitmap + if (imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, + int templ, GBool tpgdOn, + GBool useSkip, JBIG2Bitmap *skip, + int *atx, int *aty, + int mmrDataLength) { + JBIG2Bitmap *bitmap; + GBool ltp; + Guint ltpCX, cx, cx0, cx1, cx2; + JBIG2BitmapPtr cxPtr0, cxPtr1; + JBIG2BitmapPtr atPtr0, atPtr1, atPtr2, atPtr3; + int *refLine, *codingLine; + int code1, code2, code3; + int x, y, a0, pix, i, refI, codingI; + + bitmap = new JBIG2Bitmap(0, w, h); + bitmap->clearToZero(); + + //----- MMR decode + + if (mmr) { + + mmrDecoder->reset(); + refLine = (int *)gmallocn(w + 2, sizeof(int)); + codingLine = (int *)gmallocn(w + 2, sizeof(int)); + codingLine[0] = codingLine[1] = w; + + for (y = 0; y < h; ++y) { + + // copy coding line to ref line + for (i = 0; codingLine[i] < w; ++i) { + refLine[i] = codingLine[i]; + } + refLine[i] = refLine[i + 1] = w; + + // decode a line + refI = 0; // b1 = refLine[refI] + codingI = 0; // a1 = codingLine[codingI] + a0 = 0; + do { + code1 = mmrDecoder->get2DCode(); + switch (code1) { + case twoDimPass: + if (refLine[refI] < w) { + a0 = refLine[refI + 1]; + refI += 2; + } + break; + case twoDimHoriz: + if (codingI & 1) { + code1 = 0; + do { + code1 += code3 = mmrDecoder->getBlackCode(); + } while (code3 >= 64); + code2 = 0; + do { + code2 += code3 = mmrDecoder->getWhiteCode(); + } while (code3 >= 64); + } else { + code1 = 0; + do { + code1 += code3 = mmrDecoder->getWhiteCode(); + } while (code3 >= 64); + code2 = 0; + do { + code2 += code3 = mmrDecoder->getBlackCode(); + } while (code3 >= 64); + } + if (code1 > 0 || code2 > 0) { + a0 = codingLine[codingI++] = a0 + code1; + a0 = codingLine[codingI++] = a0 + code2; + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + } + break; + case twoDimVert0: + a0 = codingLine[codingI++] = refLine[refI]; + if (refLine[refI] < w) { + ++refI; + } + break; + case twoDimVertR1: + a0 = codingLine[codingI++] = refLine[refI] + 1; + if (refLine[refI] < w) { + ++refI; + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + } + break; + case twoDimVertR2: + a0 = codingLine[codingI++] = refLine[refI] + 2; + if (refLine[refI] < w) { + ++refI; + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + } + break; + case twoDimVertR3: + a0 = codingLine[codingI++] = refLine[refI] + 3; + if (refLine[refI] < w) { + ++refI; + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + } + break; + case twoDimVertL1: + a0 = codingLine[codingI++] = refLine[refI] - 1; + if (refI > 0) { + --refI; + } else { + ++refI; + } + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + break; + case twoDimVertL2: + a0 = codingLine[codingI++] = refLine[refI] - 2; + if (refI > 0) { + --refI; + } else { + ++refI; + } + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + break; + case twoDimVertL3: + a0 = codingLine[codingI++] = refLine[refI] - 3; + if (refI > 0) { + --refI; + } else { + ++refI; + } + while (refLine[refI] <= a0 && refLine[refI] < w) { + refI += 2; + } + break; + default: + error(getPos(), "Illegal code in JBIG2 MMR bitmap data"); + break; + } + } while (a0 < w); + codingLine[codingI++] = w; + + // convert the run lengths to a bitmap line + i = 0; + while (codingLine[i] < w) { + for (x = codingLine[i]; x < codingLine[i+1]; ++x) { + bitmap->setPixel(x, y); + } + i += 2; + } + } + + if (mmrDataLength >= 0) { + mmrDecoder->skipTo(mmrDataLength); + } else { + if (mmrDecoder->get24Bits() != 0x001001) { + error(getPos(), "Missing EOFB in JBIG2 MMR bitmap data"); + } + } + + gfree(refLine); + gfree(codingLine); + + //----- arithmetic decode + + } else { + // set up the typical row context + ltpCX = 0; // make gcc happy + if (tpgdOn) { + switch (templ) { + case 0: + ltpCX = 0x3953; // 001 11001 0101 0011 + break; + case 1: + ltpCX = 0x079a; // 0011 11001 101 0 + break; + case 2: + ltpCX = 0x0e3; // 001 1100 01 1 + break; + case 3: + ltpCX = 0x18a; // 01100 0101 1 + break; + } + } + + ltp = 0; + cx = cx0 = cx1 = cx2 = 0; // make gcc happy + for (y = 0; y < h; ++y) { + + // check for a "typical" (duplicate) row + if (tpgdOn) { + if (arithDecoder->decodeBit(ltpCX, genericRegionStats)) { + ltp = !ltp; + } + if (ltp) { + bitmap->duplicateRow(y, y-1); + continue; + } + } + + switch (templ) { + case 0: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + bitmap->getPixelPtr(atx[1], y + aty[1], &atPtr1); + bitmap->getPixelPtr(atx[2], y + aty[2], &atPtr2); + bitmap->getPixelPtr(atx[3], y + aty[3], &atPtr3); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) | + (bitmap->nextPixel(&atPtr0) << 3) | + (bitmap->nextPixel(&atPtr1) << 2) | + (bitmap->nextPixel(&atPtr2) << 1) | + bitmap->nextPixel(&atPtr3); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x0f; + } + break; + + case 1: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x0f; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x07; + } + break; + + case 2: + + // set up the context + bitmap->getPixelPtr(0, y-2, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + cx0 = (cx0 << 1) | bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 0x07; + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x0f; + cx2 = ((cx2 << 1) | pix) & 0x03; + } + break; + + case 3: + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr1); + cx1 = bitmap->nextPixel(&cxPtr1); + cx1 = (cx1 << 1) | bitmap->nextPixel(&cxPtr1); + cx2 = 0; + bitmap->getPixelPtr(atx[0], y + aty[0], &atPtr0); + + // decode the row + for (x = 0; x < w; ++x) { + + // build the context + cx = (cx1 << 5) | (cx2 << 1) | + bitmap->nextPixel(&atPtr0); + + // check for a skipped pixel + if (useSkip && skip->getPixel(x, y)) { + pix = 0; + + // decode the pixel + } else if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { + bitmap->setPixel(x, y); + } + + // update the context + cx1 = ((cx1 << 1) | bitmap->nextPixel(&cxPtr1)) & 0x1f; + cx2 = ((cx2 << 1) | pix) & 0x0f; + } + break; + } + } + } + + return bitmap; +} + +void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, + Guint nRefSegs) { + JBIG2Bitmap *bitmap, *refBitmap; + Guint w, h, x, y, segInfoFlags, extCombOp; + Guint flags, templ, tpgrOn; + int atx[2], aty[2]; + JBIG2Segment *seg; + + // region segment info field + if (!readULong(&w) || !readULong(&h) || + !readULong(&x) || !readULong(&y) || + !readUByte(&segInfoFlags)) { + goto eofError; + } + extCombOp = segInfoFlags & 7; + + // rest of the generic refinement region segment header + if (!readUByte(&flags)) { + goto eofError; + } + templ = flags & 1; + tpgrOn = (flags >> 1) & 1; + + // AT flags + if (!templ) { + if (!readByte(&atx[0]) || !readByte(&aty[0]) || + !readByte(&atx[1]) || !readByte(&aty[1])) { + goto eofError; + } + } + + // resize the page bitmap if needed + if (nRefSegs == 0 || imm) { + if (pageH == 0xffffffff && y + h > curPageH) { + pageBitmap->expand(y + h, pageDefPixel); + } + } + + // get referenced bitmap + if (nRefSegs > 1) { + error(getPos(), "Bad reference in JBIG2 generic refinement segment"); + return; + } + if (nRefSegs == 1) { + seg = findSegment(refSegs[0]); + if (seg->getType() != jbig2SegBitmap) { + error(getPos(), "Bad bitmap reference in JBIG2 generic refinement segment"); + return; + } + refBitmap = (JBIG2Bitmap *)seg; + } else { + refBitmap = pageBitmap->getSlice(x, y, w, h); + } + + // set up the arithmetic decoder + resetRefinementStats(templ, NULL); + arithDecoder->start(); + + // read + bitmap = readGenericRefinementRegion(w, h, templ, tpgrOn, + refBitmap, 0, 0, atx, aty); + + // combine the region bitmap into the page bitmap + if (imm) { + pageBitmap->combine(bitmap, x, y, extCombOp); + delete bitmap; + + // store the region bitmap + } else { + bitmap->setSegNum(segNum); + segments->append(bitmap); + } + + // delete the referenced bitmap + if (nRefSegs == 1) { + discardSegment(refSegs[0]); + } else { + delete refBitmap; + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h, + int templ, GBool tpgrOn, + JBIG2Bitmap *refBitmap, + int refDX, int refDY, + int *atx, int *aty) { + JBIG2Bitmap *bitmap; + GBool ltp; + Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2; + JBIG2BitmapPtr cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6; + JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2; + int x, y, pix; + + bitmap = new JBIG2Bitmap(0, w, h); + bitmap->clearToZero(); + + // set up the typical row context + if (templ) { + ltpCX = 0x008; + } else { + ltpCX = 0x0010; + } + + ltp = 0; + for (y = 0; y < h; ++y) { + + if (templ) { + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(-1, y, &cxPtr1); + refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); + cx3 = refBitmap->nextPixel(&cxPtr3); + cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); + refBitmap->getPixelPtr(-refDX, y+1-refDY, &cxPtr4); + cx4 = refBitmap->nextPixel(&cxPtr4); + + // set up the typical prediction context + tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy + if (tpgrOn) { + refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); + tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); + tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); + tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + } + + for (x = 0; x < w; ++x) { + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 7; + cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; + cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 3; + + if (tpgrOn) { + // update the typical predictor context + tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; + tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; + tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; + + // check for a "typical" pixel + if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { + ltp = !ltp; + } + if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { + bitmap->clearPixel(x, y); + continue; + } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { + bitmap->setPixel(x, y); + continue; + } + } + + // build the context + cx = (cx0 << 7) | (bitmap->nextPixel(&cxPtr1) << 6) | + (refBitmap->nextPixel(&cxPtr2) << 5) | + (cx3 << 2) | cx4; + + // decode the pixel + if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { + bitmap->setPixel(x, y); + } + } + + } else { + + // set up the context + bitmap->getPixelPtr(0, y-1, &cxPtr0); + cx0 = bitmap->nextPixel(&cxPtr0); + bitmap->getPixelPtr(-1, y, &cxPtr1); + refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); + cx2 = refBitmap->nextPixel(&cxPtr2); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); + cx3 = refBitmap->nextPixel(&cxPtr3); + cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &cxPtr4); + cx4 = refBitmap->nextPixel(&cxPtr4); + cx4 = (cx4 << 1) | refBitmap->nextPixel(&cxPtr4); + bitmap->getPixelPtr(atx[0], y+aty[0], &cxPtr5); + refBitmap->getPixelPtr(atx[1]-refDX, y+aty[1]-refDY, &cxPtr6); + + // set up the typical prediction context + tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy + if (tpgrOn) { + refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); + tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); + refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); + tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); + refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); + tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); + } + + for (x = 0; x < w; ++x) { + + // update the context + cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 3; + cx2 = ((cx2 << 1) | refBitmap->nextPixel(&cxPtr2)) & 3; + cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; + cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 7; + + if (tpgrOn) { + // update the typical predictor context + tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; + tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; + tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; + + // check for a "typical" pixel + if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { + ltp = !ltp; + } + if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { + bitmap->clearPixel(x, y); + continue; + } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { + bitmap->setPixel(x, y); + continue; + } + } + + // build the context + cx = (cx0 << 11) | (bitmap->nextPixel(&cxPtr1) << 10) | + (cx2 << 8) | (cx3 << 5) | (cx4 << 2) | + (bitmap->nextPixel(&cxPtr5) << 1) | + refBitmap->nextPixel(&cxPtr6); + + // decode the pixel + if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { + bitmap->setPixel(x, y); + } + } + } + } + + return bitmap; +} + +void JBIG2Stream::readPageInfoSeg(Guint length) { + Guint xRes, yRes, flags, striping; + + if (!readULong(&pageW) || !readULong(&pageH) || + !readULong(&xRes) || !readULong(&yRes) || + !readUByte(&flags) || !readUWord(&striping)) { + goto eofError; + } + pageDefPixel = (flags >> 2) & 1; + defCombOp = (flags >> 3) & 3; + + // allocate the page bitmap + if (pageH == 0xffffffff) { + curPageH = striping & 0x7fff; + } else { + curPageH = pageH; + } + pageBitmap = new JBIG2Bitmap(0, pageW, curPageH); + + // default pixel value + if (pageDefPixel) { + pageBitmap->clearToOne(); + } else { + pageBitmap->clearToZero(); + } + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readEndOfStripeSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +void JBIG2Stream::readProfilesSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) { + JBIG2HuffmanTable *huffTab; + Guint flags, oob, prefixBits, rangeBits; + int lowVal, highVal, val; + Guint huffTabSize, i; + + if (!readUByte(&flags) || !readLong(&lowVal) || !readLong(&highVal)) { + goto eofError; + } + oob = flags & 1; + prefixBits = ((flags >> 1) & 7) + 1; + rangeBits = ((flags >> 4) & 7) + 1; + + huffDecoder->reset(); + huffTabSize = 8; + huffTab = (JBIG2HuffmanTable *) + gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable)); + i = 0; + val = lowVal; + while (val < highVal) { + if (i == huffTabSize) { + huffTabSize *= 2; + huffTab = (JBIG2HuffmanTable *) + greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); + } + huffTab[i].val = val; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = huffDecoder->readBits(rangeBits); + val += 1 << huffTab[i].rangeLen; + ++i; + } + if (i + oob + 3 > huffTabSize) { + huffTabSize = i + oob + 3; + huffTab = (JBIG2HuffmanTable *) + greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); + } + huffTab[i].val = lowVal - 1; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = jbig2HuffmanLOW; + ++i; + huffTab[i].val = highVal; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = 32; + ++i; + if (oob) { + huffTab[i].val = 0; + huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); + huffTab[i].rangeLen = jbig2HuffmanOOB; + ++i; + } + huffTab[i].val = 0; + huffTab[i].prefixLen = 0; + huffTab[i].rangeLen = jbig2HuffmanEOT; + huffDecoder->buildTable(huffTab, i); + + // create and store the new table segment + segments->append(new JBIG2CodeTable(segNum, huffTab)); + + return; + + eofError: + error(getPos(), "Unexpected EOF in JBIG2 stream"); +} + +void JBIG2Stream::readExtensionSeg(Guint length) { + Guint i; + + // skip the segment + for (i = 0; i < length; ++i) { + curStr->getChar(); + } +} + +JBIG2Segment *JBIG2Stream::findSegment(Guint segNum) { + JBIG2Segment *seg; + int i; + + for (i = 0; i < globalSegments->getLength(); ++i) { + seg = (JBIG2Segment *)globalSegments->get(i); + if (seg->getSegNum() == segNum) { + return seg; + } + } + for (i = 0; i < segments->getLength(); ++i) { + seg = (JBIG2Segment *)segments->get(i); + if (seg->getSegNum() == segNum) { + return seg; + } + } + return NULL; +} + +void JBIG2Stream::discardSegment(Guint segNum) { + JBIG2Segment *seg; + int i; + + for (i = 0; i < globalSegments->getLength(); ++i) { + seg = (JBIG2Segment *)globalSegments->get(i); + if (seg->getSegNum() == segNum) { + globalSegments->del(i); + return; + } + } + for (i = 0; i < segments->getLength(); ++i) { + seg = (JBIG2Segment *)segments->get(i); + if (seg->getSegNum() == segNum) { + segments->del(i); + return; + } + } +} + +void JBIG2Stream::resetGenericStats(Guint templ, + JArithmeticDecoderStats *prevStats) { + int size; + + size = contextSize[templ]; + if (prevStats && prevStats->getContextSize() == size) { + if (genericRegionStats->getContextSize() == size) { + genericRegionStats->copyFrom(prevStats); + } else { + delete genericRegionStats; + genericRegionStats = prevStats->copy(); + } + } else { + if (genericRegionStats->getContextSize() == size) { + genericRegionStats->reset(); + } else { + delete genericRegionStats; + genericRegionStats = new JArithmeticDecoderStats(1 << size); + } + } +} + +void JBIG2Stream::resetRefinementStats(Guint templ, + JArithmeticDecoderStats *prevStats) { + int size; + + size = refContextSize[templ]; + if (prevStats && prevStats->getContextSize() == size) { + if (refinementRegionStats->getContextSize() == size) { + refinementRegionStats->copyFrom(prevStats); + } else { + delete refinementRegionStats; + refinementRegionStats = prevStats->copy(); + } + } else { + if (refinementRegionStats->getContextSize() == size) { + refinementRegionStats->reset(); + } else { + delete refinementRegionStats; + refinementRegionStats = new JArithmeticDecoderStats(1 << size); + } + } +} + +void JBIG2Stream::resetIntStats(int symCodeLen) { + iadhStats->reset(); + iadwStats->reset(); + iaexStats->reset(); + iaaiStats->reset(); + iadtStats->reset(); + iaitStats->reset(); + iafsStats->reset(); + iadsStats->reset(); + iardxStats->reset(); + iardyStats->reset(); + iardwStats->reset(); + iardhStats->reset(); + iariStats->reset(); + if (iaidStats->getContextSize() == symCodeLen + 1) { + iaidStats->reset(); + } else { + delete iaidStats; + iaidStats = new JArithmeticDecoderStats(1 << (symCodeLen + 1)); + } +} + +GBool JBIG2Stream::readUByte(Guint *x) { + int c0; + + if ((c0 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)c0; + return gTrue; +} + +GBool JBIG2Stream::readByte(int *x) { + int c0; + + if ((c0 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = c0; + if (c0 & 0x80) { + *x |= -1 - 0xff; + } + return gTrue; +} + +GBool JBIG2Stream::readUWord(Guint *x) { + int c0, c1; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 8) | c1); + return gTrue; +} + +GBool JBIG2Stream::readULong(Guint *x) { + int c0, c1, c2, c3; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + return gTrue; +} + +GBool JBIG2Stream::readLong(int *x) { + int c0, c1, c2, c3; + + if ((c0 = curStr->getChar()) == EOF || + (c1 = curStr->getChar()) == EOF || + (c2 = curStr->getChar()) == EOF || + (c3 = curStr->getChar()) == EOF) { + return gFalse; + } + *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + if (c0 & 0x80) { + *x |= -1 - (int)0xffffffff; + } + return gTrue; +} diff --git a/pdftops/JBIG2Stream.h b/pdftops/JBIG2Stream.h new file mode 100644 index 000000000..13b4d917a --- /dev/null +++ b/pdftops/JBIG2Stream.h @@ -0,0 +1,143 @@ +//======================================================================== +// +// JBIG2Stream.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JBIG2STREAM_H +#define JBIG2STREAM_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" +#include "Stream.h" + +class GList; +class JBIG2Segment; +class JBIG2Bitmap; +class JArithmeticDecoder; +class JArithmeticDecoderStats; +class JBIG2HuffmanDecoder; +struct JBIG2HuffmanTable; +class JBIG2MMRDecoder; + +//------------------------------------------------------------------------ + +class JBIG2Stream: public FilterStream { +public: + + JBIG2Stream(Stream *strA, Object *globalsStream); + virtual ~JBIG2Stream(); + virtual StreamKind getKind() { return strJBIG2; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + void readSegments(); + GBool readSymbolDictSeg(Guint segNum, Guint length, + Guint *refSegs, Guint nRefSegs); + void readTextRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs); + JBIG2Bitmap *readTextRegion(GBool huff, GBool refine, + int w, int h, + Guint numInstances, + Guint logStrips, + int numSyms, + JBIG2HuffmanTable *symCodeTab, + Guint symCodeLen, + JBIG2Bitmap **syms, + Guint defPixel, Guint combOp, + Guint transposed, Guint refCorner, + int sOffset, + JBIG2HuffmanTable *huffFSTable, + JBIG2HuffmanTable *huffDSTable, + JBIG2HuffmanTable *huffDTTable, + JBIG2HuffmanTable *huffRDWTable, + JBIG2HuffmanTable *huffRDHTable, + JBIG2HuffmanTable *huffRDXTable, + JBIG2HuffmanTable *huffRDYTable, + JBIG2HuffmanTable *huffRSizeTable, + Guint templ, + int *atx, int *aty); + void readPatternDictSeg(Guint segNum, Guint length); + void readHalftoneRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, Guint nRefSegs); + void readGenericRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length); + JBIG2Bitmap *readGenericBitmap(GBool mmr, int w, int h, + int templ, GBool tpgdOn, + GBool useSkip, JBIG2Bitmap *skip, + int *atx, int *aty, + int mmrDataLength); + void readGenericRefinementRegionSeg(Guint segNum, GBool imm, + GBool lossless, Guint length, + Guint *refSegs, + Guint nRefSegs); + JBIG2Bitmap *readGenericRefinementRegion(int w, int h, + int templ, GBool tpgrOn, + JBIG2Bitmap *refBitmap, + int refDX, int refDY, + int *atx, int *aty); + void readPageInfoSeg(Guint length); + void readEndOfStripeSeg(Guint length); + void readProfilesSeg(Guint length); + void readCodeTableSeg(Guint segNum, Guint length); + void readExtensionSeg(Guint length); + JBIG2Segment *findSegment(Guint segNum); + void discardSegment(Guint segNum); + void resetGenericStats(Guint templ, + JArithmeticDecoderStats *prevStats); + void resetRefinementStats(Guint templ, + JArithmeticDecoderStats *prevStats); + void resetIntStats(int symCodeLen); + GBool readUByte(Guint *x); + GBool readByte(int *x); + GBool readUWord(Guint *x); + GBool readULong(Guint *x); + GBool readLong(int *x); + + Guint pageW, pageH, curPageH; + Guint pageDefPixel; + JBIG2Bitmap *pageBitmap; + Guint defCombOp; + GList *segments; // [JBIG2Segment] + GList *globalSegments; // [JBIG2Segment] + Stream *curStr; + Guchar *dataPtr; + Guchar *dataEnd; + + JArithmeticDecoder *arithDecoder; + JArithmeticDecoderStats *genericRegionStats; + JArithmeticDecoderStats *refinementRegionStats; + JArithmeticDecoderStats *iadhStats; + JArithmeticDecoderStats *iadwStats; + JArithmeticDecoderStats *iaexStats; + JArithmeticDecoderStats *iaaiStats; + JArithmeticDecoderStats *iadtStats; + JArithmeticDecoderStats *iaitStats; + JArithmeticDecoderStats *iafsStats; + JArithmeticDecoderStats *iadsStats; + JArithmeticDecoderStats *iardxStats; + JArithmeticDecoderStats *iardyStats; + JArithmeticDecoderStats *iardwStats; + JArithmeticDecoderStats *iardhStats; + JArithmeticDecoderStats *iariStats; + JArithmeticDecoderStats *iaidStats; + JBIG2HuffmanDecoder *huffDecoder; + JBIG2MMRDecoder *mmrDecoder; +}; + +#endif diff --git a/pdftops/JPXStream.cxx b/pdftops/JPXStream.cxx new file mode 100644 index 000000000..0f1977ed3 --- /dev/null +++ b/pdftops/JPXStream.cxx @@ -0,0 +1,2953 @@ +//======================================================================== +// +// JPXStream.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "Error.h" +#include "JArithmeticDecoder.h" +#include "JPXStream.h" + +//~ to do: +// - precincts +// - ROI +// - progression order changes +// - packed packet headers +// - support for palettes, channel maps, etc. +// - make sure all needed JP2/JPX subboxes are parsed (readBoxes) +// - can we assume that QCC segments must come after the QCD segment? +// - skip EPH markers (readTilePartData) +// - handle tilePartToEOC in readTilePartData +// - deal with multiple codeword segments (readTilePartData, +// readCodeBlockData) +// - progression orders 2, 3, and 4 +// - in coefficient decoding (readCodeBlockData): +// - termination pattern: terminate after every coding pass +// - error resilience segmentation symbol +// - selective arithmetic coding bypass +// - vertically causal context formation +// - coeffs longer than 31 bits (should just ignore the extra bits?) +// - handle boxes larger than 2^32 bytes +// - the fixed-point arithmetic won't handle 16-bit pixels + +//------------------------------------------------------------------------ + +// number of contexts for the arithmetic decoder +#define jpxNContexts 19 + +#define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup +#define jpxContextSign 9 // 9 - 13: sign +#define jpxContextMagRef 14 // 14 -16: magnitude refinement +#define jpxContextRunLength 17 // cleanup: run length +#define jpxContextUniform 18 // cleanup: first signif coeff + +//------------------------------------------------------------------------ + +#define jpxPassSigProp 0 +#define jpxPassMagRef 1 +#define jpxPassCleanup 2 + +//------------------------------------------------------------------------ + +// arithmetic decoder context for the significance propagation and +// cleanup passes: +// [horiz][vert][diag][subband] +// where subband = 0 for HL +// = 1 for LH and LL +// = 2 for HH +static Guint sigPropContext[3][3][5][3] = { + {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0 + { 1, 1, 3 }, // horiz=0, vert=0, diag=1 + { 2, 2, 6 }, // horiz=0, vert=0, diag=2 + { 2, 2, 8 }, // horiz=0, vert=0, diag=3 + { 2, 2, 8 }}, // horiz=0, vert=0, diag=4 + {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0 + { 6, 3, 4 }, // horiz=0, vert=1, diag=1 + { 6, 3, 7 }, // horiz=0, vert=1, diag=2 + { 6, 3, 8 }, // horiz=0, vert=1, diag=3 + { 6, 3, 8 }}, // horiz=0, vert=1, diag=4 + {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0 + { 8, 4, 5 }, // horiz=0, vert=2, diag=1 + { 8, 4, 7 }, // horiz=0, vert=2, diag=2 + { 8, 4, 8 }, // horiz=0, vert=2, diag=3 + { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4 + {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0 + { 3, 6, 4 }, // horiz=1, vert=0, diag=1 + { 3, 6, 7 }, // horiz=1, vert=0, diag=2 + { 3, 6, 8 }, // horiz=1, vert=0, diag=3 + { 3, 6, 8 }}, // horiz=1, vert=0, diag=4 + {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0 + { 7, 7, 5 }, // horiz=1, vert=1, diag=1 + { 7, 7, 7 }, // horiz=1, vert=1, diag=2 + { 7, 7, 8 }, // horiz=1, vert=1, diag=3 + { 7, 7, 8 }}, // horiz=1, vert=1, diag=4 + {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0 + { 8, 7, 5 }, // horiz=1, vert=2, diag=1 + { 8, 7, 7 }, // horiz=1, vert=2, diag=2 + { 8, 7, 8 }, // horiz=1, vert=2, diag=3 + { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4 + {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0 + { 4, 8, 5 }, // horiz=2, vert=0, diag=1 + { 4, 8, 7 }, // horiz=2, vert=0, diag=2 + { 4, 8, 8 }, // horiz=2, vert=0, diag=3 + { 4, 8, 8 }}, // horiz=2, vert=0, diag=4 + {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0 + { 7, 8, 5 }, // horiz=2, vert=1, diag=1 + { 7, 8, 7 }, // horiz=2, vert=1, diag=2 + { 7, 8, 8 }, // horiz=2, vert=1, diag=3 + { 7, 8, 8 }}, // horiz=2, vert=1, diag=4 + {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0 + { 8, 8, 5 }, // horiz=2, vert=2, diag=1 + { 8, 8, 7 }, // horiz=2, vert=2, diag=2 + { 8, 8, 8 }, // horiz=2, vert=2, diag=3 + { 8, 8, 8 }}} // horiz=2, vert=2, diag=4 +}; + +// arithmetic decoder context and xor bit for the sign bit in the +// significance propagation pass: +// [horiz][vert][k] +// where horiz/vert are offset by 2 (i.e., range is -2 .. 2) +// and k = 0 for the context +// = 1 for the xor bit +static Guint signContext[5][5][2] = { + {{ 13, 1 }, // horiz=-2, vert=-2 + { 13, 1 }, // horiz=-2, vert=-1 + { 12, 1 }, // horiz=-2, vert= 0 + { 11, 1 }, // horiz=-2, vert=+1 + { 11, 1 }}, // horiz=-2, vert=+2 + {{ 13, 1 }, // horiz=-1, vert=-2 + { 13, 1 }, // horiz=-1, vert=-1 + { 12, 1 }, // horiz=-1, vert= 0 + { 11, 1 }, // horiz=-1, vert=+1 + { 11, 1 }}, // horiz=-1, vert=+2 + {{ 10, 1 }, // horiz= 0, vert=-2 + { 10, 1 }, // horiz= 0, vert=-1 + { 9, 0 }, // horiz= 0, vert= 0 + { 10, 0 }, // horiz= 0, vert=+1 + { 10, 0 }}, // horiz= 0, vert=+2 + {{ 11, 0 }, // horiz=+1, vert=-2 + { 11, 0 }, // horiz=+1, vert=-1 + { 12, 0 }, // horiz=+1, vert= 0 + { 13, 0 }, // horiz=+1, vert=+1 + { 13, 0 }}, // horiz=+1, vert=+2 + {{ 11, 0 }, // horiz=+2, vert=-2 + { 11, 0 }, // horiz=+2, vert=-1 + { 12, 0 }, // horiz=+2, vert= 0 + { 13, 0 }, // horiz=+2, vert=+1 + { 13, 0 }}, // horiz=+2, vert=+2 +}; + +//------------------------------------------------------------------------ + +// constants used in the IDWT +#define idwtAlpha -1.586134342059924 +#define idwtBeta -0.052980118572961 +#define idwtGamma 0.882911075530934 +#define idwtDelta 0.443506852043971 +#define idwtKappa 1.230174104914001 +#define idwtIKappa (1.0 / idwtKappa) + +// number of bits to the right of the decimal point for the fixed +// point arithmetic used in the IDWT +#define fracBits 16 + +//------------------------------------------------------------------------ + +// floor(x / y) +#define jpxFloorDiv(x, y) ((x) / (y)) + +// floor(x / 2^y) +#define jpxFloorDivPow2(x, y) ((x) >> (y)) + +// ceil(x / y) +#define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y)) + +// ceil(x / 2^y) +#define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y)) + +//------------------------------------------------------------------------ + +JPXStream::JPXStream(Stream *strA): + FilterStream(strA) +{ + nComps = 0; + bpc = NULL; + width = height = 0; + haveCS = gFalse; + havePalette = gFalse; + haveCompMap = gFalse; + haveChannelDefn = gFalse; + + img.tiles = NULL; + bitBuf = 0; + bitBufLen = 0; + bitBufSkip = gFalse; + byteCount = 0; +} + +JPXStream::~JPXStream() { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + Guint comp, i, k, r, pre, sb; + + gfree(bpc); + if (havePalette) { + gfree(palette.bpc); + gfree(palette.c); + } + if (haveCompMap) { + gfree(compMap.comp); + gfree(compMap.type); + gfree(compMap.pComp); + } + if (haveChannelDefn) { + gfree(channelDefn.idx); + gfree(channelDefn.type); + gfree(channelDefn.assoc); + } + + if (img.tiles) { + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + tile = &img.tiles[i]; + if (tile->tileComps) { + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + gfree(tileComp->quantSteps); + gfree(tileComp->data); + gfree(tileComp->buf); + if (tileComp->resLevels) { + for (r = 0; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + if (resLevel->precincts) { + for (pre = 0; pre < 1; ++pre) { + precinct = &resLevel->precincts[pre]; + if (precinct->subbands) { + for (sb = 0; sb < (r == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + gfree(subband->inclusion); + gfree(subband->zeroBitPlane); + if (subband->cbs) { + for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) { + cb = &subband->cbs[k]; + gfree(cb->coeffs); + if (cb->arithDecoder) { + delete cb->arithDecoder; + } + if (cb->stats) { + delete cb->stats; + } + } + gfree(subband->cbs); + } + } + gfree(precinct->subbands); + } + } + gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts); + } + } + gfree(img.tiles[i].tileComps[comp].resLevels); + } + } + gfree(img.tiles[i].tileComps); + } + } + gfree(img.tiles); + } + delete str; +} + +void JPXStream::reset() { + str->reset(); + if (readBoxes()) { + curY = img.yOffset; + } else { + // readBoxes reported an error, so we go immediately to EOF + curY = img.ySize; + } + curX = img.xOffset; + curComp = 0; + readBufLen = 0; +} + +int JPXStream::getChar() { + int c; + + if (readBufLen < 8) { + fillReadBuf(); + } + if (readBufLen == 8) { + c = readBuf & 0xff; + readBufLen = 0; + } else if (readBufLen > 8) { + c = (readBuf >> (readBufLen - 8)) & 0xff; + readBufLen -= 8; + } else if (readBufLen == 0) { + c = EOF; + } else { + c = (readBuf << (8 - readBufLen)) & 0xff; + readBufLen = 0; + } + return c; +} + +int JPXStream::lookChar() { + int c; + + if (readBufLen < 8) { + fillReadBuf(); + } + if (readBufLen == 8) { + c = readBuf & 0xff; + } else if (readBufLen > 8) { + c = (readBuf >> (readBufLen - 8)) & 0xff; + } else if (readBufLen == 0) { + c = EOF; + } else { + c = (readBuf << (8 - readBufLen)) & 0xff; + } + return c; +} + +void JPXStream::fillReadBuf() { + JPXTileComp *tileComp; + Guint tileIdx, tx, ty; + int pix, pixBits; + + do { + if (curY >= img.ySize) { + return; + } + tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles + + (curX - img.xTileOffset) / img.xTileSize; +#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid + tileComp = &img.tiles[tileIdx].tileComps[curComp]; +#else + tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp]; +#endif + tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep); + ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep); + pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx]; + pixBits = tileComp->prec; +#if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid + if (++curComp == img.nComps) { +#else + if (havePalette) { + if (pix >= 0 && pix < palette.nEntries) { + pix = palette.c[pix * palette.nComps + curComp]; + } else { + pix = + pixBits = palette.bpc[curComp]; + } + if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) { +#endif + curComp = 0; + if (++curX == img.xSize) { + curX = img.xOffset; + ++curY; + } + } + if (pixBits == 8) { + readBuf = (readBuf << 8) | (pix & 0xff); + } else { + readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1)); + } + readBufLen += pixBits; + } while (readBufLen < 8); +} + +GString *JPXStream::getPSFilter(int psLevel, char *indent) { + return NULL; +} + +GBool JPXStream::isBinary(GBool last) { + return str->isBinary(gTrue); +} + +void JPXStream::getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode) { + Guint boxType, boxLen, dataLen, csEnum; + Guint bpc1, dummy, i; + int csMeth, csPrec, csPrec1, dummy2; + StreamColorSpaceMode csMode1; + GBool haveBPC, haveCSMode; + + csPrec = 0; // make gcc happy + haveBPC = haveCSMode = gFalse; + str->reset(); + if (str->lookChar() == 0xff) { + getImageParams2(bitsPerComponent, csMode); + } else { + while (readBoxHdr(&boxType, &boxLen, &dataLen)) { + if (boxType == 0x6a703268) { // JP2 header + // skip the superbox + } else if (boxType == 0x69686472) { // image header + if (readULong(&dummy) && + readULong(&dummy) && + readUWord(&dummy) && + readUByte(&bpc1) && + readUByte(&dummy) && + readUByte(&dummy) && + readUByte(&dummy)) { + *bitsPerComponent = bpc1 + 1; + haveBPC = gTrue; + } + } else if (boxType == 0x636F6C72) { // color specification + if (readByte(&csMeth) && + readByte(&csPrec1) && + readByte(&dummy2)) { + if (csMeth == 1) { + if (readULong(&csEnum)) { + csMode1 = streamCSNone; + if (csEnum == jpxCSBiLevel || + csEnum == jpxCSGrayscale) { + csMode1 = streamCSDeviceGray; + } else if (csEnum == jpxCSCMYK) { + csMode1 = streamCSDeviceCMYK; + } else if (csEnum == jpxCSsRGB || + csEnum == jpxCSCISesRGB || + csEnum == jpxCSROMMRGB) { + csMode1 = streamCSDeviceRGB; + } + if (csMode1 != streamCSNone && + (!haveCSMode || csPrec1 > csPrec)) { + *csMode = csMode1; + csPrec = csPrec1; + haveCSMode = gTrue; + } + for (i = 0; i < dataLen - 7; ++i) { + str->getChar(); + } + } + } else { + for (i = 0; i < dataLen - 3; ++i) { + str->getChar(); + } + } + } + } else if (boxType == 0x6A703263) { // codestream + if (!(haveBPC && haveCSMode)) { + getImageParams2(bitsPerComponent, csMode); + } + break; + } else { + for (i = 0; i < dataLen; ++i) { + str->getChar(); + } + } + } + } + str->close(); +} + +// Get image parameters from the codestream. +void JPXStream::getImageParams2(int *bitsPerComponent, + StreamColorSpaceMode *csMode) { + int segType; + Guint segLen, nComps1, bpc1, dummy, i; + + while (readMarkerHdr(&segType, &segLen)) { + if (segType == 0x51) { // SIZ - image and tile size + if (readUWord(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readULong(&dummy) && + readUWord(&nComps1) && + readUByte(&bpc1)) { + *bitsPerComponent = (bpc1 & 0x7f) + 1; + // if there's no color space info, take a guess + if (nComps1 == 1) { + *csMode = streamCSDeviceGray; + } else if (nComps1 == 3) { + *csMode = streamCSDeviceRGB; + } else if (nComps1 == 4) { + *csMode = streamCSDeviceCMYK; + } + } + break; + } else { + if (segLen > 2) { + for (i = 0; i < segLen - 2; ++i) { + str->getChar(); + } + } + } + } +} + +GBool JPXStream::readBoxes() { + Guint boxType, boxLen, dataLen; + Guint bpc1, compression, unknownColorspace, ipr; + Guint i, j; + + haveImgHdr = gFalse; + + // check for a naked JPEG 2000 codestream (without the JP2/JPX + // wrapper) -- this appears to be a violation of the PDF spec, but + // Acrobat allows it + if (str->lookChar() == 0xff) { + error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper"); + readCodestream(0); + nComps = img.nComps; + bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); + for (i = 0; i < nComps; ++i) { + bpc[i] = img.tiles[0].tileComps[i].prec; + } + width = img.xSize - img.xOffset; + height = img.ySize - img.yOffset; + return gTrue; + } + + while (readBoxHdr(&boxType, &boxLen, &dataLen)) { + switch (boxType) { + case 0x6a703268: // JP2 header + // this is a grouping box ('superbox') which has no real + // contents and doesn't appear to be used consistently, i.e., + // some things which should be subboxes of the JP2 header box + // show up outside of it - so we simply ignore the JP2 header + // box + break; + case 0x69686472: // image header + if (!readULong(&height) || + !readULong(&width) || + !readUWord(&nComps) || + !readUByte(&bpc1) || + !readUByte(&compression) || + !readUByte(&unknownColorspace) || + !readUByte(&ipr)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + if (compression != 7) { + error(getPos(), "Unknown compression type in JPX stream"); + return gFalse; + } + bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); + for (i = 0; i < nComps; ++i) { + bpc[i] = bpc1; + } + haveImgHdr = gTrue; + break; + case 0x62706363: // bits per component + if (!haveImgHdr) { + error(getPos(), "Found bits per component box before image header box in JPX stream"); + return gFalse; + } + if (dataLen != nComps) { + error(getPos(), "Invalid bits per component box in JPX stream"); + return gFalse; + } + for (i = 0; i < nComps; ++i) { + if (!readUByte(&bpc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + break; + case 0x636F6C72: // color specification + if (!readColorSpecBox(dataLen)) { + return gFalse; + } + break; + case 0x70636c72: // palette + if (!readUWord(&palette.nEntries) || + !readUByte(&palette.nComps)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint)); + palette.c = + (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int)); + for (i = 0; i < palette.nComps; ++i) { + if (!readUByte(&palette.bpc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + ++palette.bpc[i]; + } + for (i = 0; i < palette.nEntries; ++i) { + for (j = 0; j < palette.nComps; ++j) { + if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3, + (palette.bpc[j] & 0x80) ? gTrue : gFalse, + &palette.c[i * palette.nComps + j])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + } + havePalette = gTrue; + break; + case 0x636d6170: // component mapping + compMap.nChannels = dataLen / 4; + compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); + for (i = 0; i < compMap.nChannels; ++i) { + if (!readUWord(&compMap.comp[i]) || + !readUByte(&compMap.type[i]) || + !readUByte(&compMap.pComp[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + haveCompMap = gTrue; + break; + case 0x63646566: // channel definition + if (!readUWord(&channelDefn.nChannels)) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + channelDefn.idx = + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); + channelDefn.type = + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); + channelDefn.assoc = + (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); + for (i = 0; i < channelDefn.nChannels; ++i) { + if (!readUWord(&channelDefn.idx[i]) || + !readUWord(&channelDefn.type[i]) || + !readUWord(&channelDefn.assoc[i])) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + haveChannelDefn = gTrue; + break; + case 0x6A703263: // contiguous codestream + if (!bpc) { + error(getPos(), "JPX stream is missing the image header box"); + } + if (!haveCS) { + error(getPos(), "JPX stream has no supported color spec"); + } + if (!readCodestream(dataLen)) { + return gFalse; + } + break; + default: + for (i = 0; i < dataLen; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Unexpected EOF in JPX stream"); + return gFalse; + } + } + break; + } + } + return gTrue; +} + +GBool JPXStream::readColorSpecBox(Guint dataLen) { + JPXColorSpec newCS; + Guint csApprox, csEnum; + Guint i; + GBool ok; + + ok = gFalse; + if (!readUByte(&newCS.meth) || + !readByte(&newCS.prec) || + !readUByte(&csApprox)) { + goto err; + } + switch (newCS.meth) { + case 1: // enumerated colorspace + if (!readULong(&csEnum)) { + goto err; + } + newCS.enumerated.type = (JPXColorSpaceType)csEnum; + switch (newCS.enumerated.type) { + case jpxCSBiLevel: + ok = gTrue; + break; + case jpxCSYCbCr1: + ok = gTrue; + break; + case jpxCSYCbCr2: + ok = gTrue; + break; + case jpxCSYCBCr3: + ok = gTrue; + break; + case jpxCSPhotoYCC: + ok = gTrue; + break; + case jpxCSCMY: + ok = gTrue; + break; + case jpxCSCMYK: + ok = gTrue; + break; + case jpxCSYCCK: + ok = gTrue; + break; + case jpxCSCIELab: + if (dataLen == 7 + 7*4) { + if (!readULong(&newCS.enumerated.cieLab.rl) || + !readULong(&newCS.enumerated.cieLab.ol) || + !readULong(&newCS.enumerated.cieLab.ra) || + !readULong(&newCS.enumerated.cieLab.oa) || + !readULong(&newCS.enumerated.cieLab.rb) || + !readULong(&newCS.enumerated.cieLab.ob) || + !readULong(&newCS.enumerated.cieLab.il)) { + goto err; + } + } else if (dataLen == 7) { + //~ this assumes the 8-bit case + newCS.enumerated.cieLab.rl = 100; + newCS.enumerated.cieLab.ol = 0; + newCS.enumerated.cieLab.ra = 255; + newCS.enumerated.cieLab.oa = 128; + newCS.enumerated.cieLab.rb = 255; + newCS.enumerated.cieLab.ob = 96; + newCS.enumerated.cieLab.il = 0x00443530; + } else { + goto err; + } + ok = gTrue; + break; + case jpxCSsRGB: + ok = gTrue; + break; + case jpxCSGrayscale: + ok = gTrue; + break; + case jpxCSBiLevel2: + ok = gTrue; + break; + case jpxCSCIEJab: + // not allowed in PDF + goto err; + case jpxCSCISesRGB: + ok = gTrue; + break; + case jpxCSROMMRGB: + ok = gTrue; + break; + case jpxCSsRGBYCbCr: + ok = gTrue; + break; + case jpxCSYPbPr1125: + ok = gTrue; + break; + case jpxCSYPbPr1250: + ok = gTrue; + break; + default: + goto err; + } + break; + case 2: // restricted ICC profile + case 3: // any ICC profile (JPX) + case 4: // vendor color (JPX) + for (i = 0; i < dataLen - 3; ++i) { + if (str->getChar() == EOF) { + goto err; + } + } + break; + } + + if (ok && (!haveCS || newCS.prec > cs.prec)) { + cs = newCS; + haveCS = gTrue; + } + + return gTrue; + + err: + error(getPos(), "Error in JPX color spec"); + return gFalse; +} + +GBool JPXStream::readCodestream(Guint len) { + JPXTile *tile; + JPXTileComp *tileComp; + int segType; + GBool haveSIZ, haveCOD, haveQCD, haveSOT; + Guint precinctSize, style; + Guint segLen, capabilities, nTiles, comp, i, j, r; + + //----- main header + haveSIZ = haveCOD = haveQCD = haveSOT = gFalse; + do { + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX codestream"); + return gFalse; + } + switch (segType) { + case 0x4f: // SOC - start of codestream + // marker only + break; + case 0x51: // SIZ - image and tile size + if (!readUWord(&capabilities) || + !readULong(&img.xSize) || + !readULong(&img.ySize) || + !readULong(&img.xOffset) || + !readULong(&img.yOffset) || + !readULong(&img.xTileSize) || + !readULong(&img.yTileSize) || + !readULong(&img.xTileOffset) || + !readULong(&img.yTileOffset) || + !readUWord(&img.nComps)) { + error(getPos(), "Error in JPX SIZ marker segment"); + return gFalse; + } + if (haveImgHdr && img.nComps != nComps) { + error(getPos(), "Different number of components in JPX SIZ marker segment"); + return gFalse; + } + img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1) + / img.xTileSize; + img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) + / img.yTileSize; + nTiles = img.nXTiles * img.nYTiles; + // check for overflow before allocating memory + if (nTiles == 0 || nTiles / img.nXTiles != img.nYTiles) { + error(getPos(), "Bad tile count in JPX SIZ marker segment"); + return gFalse; + } + img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile)); + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps, + sizeof(JPXTileComp)); + for (comp = 0; comp < img.nComps; ++comp) { + img.tiles[i].tileComps[comp].quantSteps = NULL; + img.tiles[i].tileComps[comp].data = NULL; + img.tiles[i].tileComps[comp].buf = NULL; + img.tiles[i].tileComps[comp].resLevels = NULL; + } + } + for (comp = 0; comp < img.nComps; ++comp) { + if (!readUByte(&img.tiles[0].tileComps[comp].prec) || + !readUByte(&img.tiles[0].tileComps[comp].hSep) || + !readUByte(&img.tiles[0].tileComps[comp].vSep)) { + error(getPos(), "Error in JPX SIZ marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].sgned = + (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse; + img.tiles[0].tileComps[comp].prec = + (img.tiles[0].tileComps[comp].prec & 0x7f) + 1; + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp]; + } + } + haveSIZ = gTrue; + break; + case 0x52: // COD - coding style default + if (!readUByte(&img.tiles[0].tileComps[0].style) || + !readUByte(&img.tiles[0].progOrder) || + !readUWord(&img.tiles[0].nLayers) || + !readUByte(&img.tiles[0].multiComp) || + !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockW) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockH) || + !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) || + !readUByte(&img.tiles[0].tileComps[0].transform)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[0].codeBlockW += 2; + img.tiles[0].tileComps[0].codeBlockH += 2; + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + if (i != 0) { + img.tiles[i].progOrder = img.tiles[0].progOrder; + img.tiles[i].nLayers = img.tiles[0].nLayers; + img.tiles[i].multiComp = img.tiles[0].multiComp; + } + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + img.tiles[i].tileComps[comp].style = + img.tiles[0].tileComps[0].style; + img.tiles[i].tileComps[comp].nDecompLevels = + img.tiles[0].tileComps[0].nDecompLevels; + img.tiles[i].tileComps[comp].codeBlockW = + img.tiles[0].tileComps[0].codeBlockW; + img.tiles[i].tileComps[comp].codeBlockH = + img.tiles[0].tileComps[0].codeBlockH; + img.tiles[i].tileComps[comp].codeBlockStyle = + img.tiles[0].tileComps[0].codeBlockStyle; + img.tiles[i].tileComps[comp].transform = + img.tiles[0].tileComps[0].transform; + } + img.tiles[i].tileComps[comp].resLevels = + (JPXResLevel *)gmallocn( + (img.tiles[i].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; + } + } + } + for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) { + if (img.tiles[0].tileComps[0].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[0].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[0].tileComps[0].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15; + img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15; + } + } + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[0].tileComps[0].resLevels[r].precinctWidth; + img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[0].tileComps[0].resLevels[r].precinctHeight; + } + } + } + } + haveCOD = gTrue; + break; + case 0x53: // COC - coding style component + if (!haveCOD) { + error(getPos(), "JPX COC marker segment before COD segment"); + return gFalse; + } + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&style) || + !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) || + !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) || + !readUByte(&img.tiles[0].tileComps[comp].transform)) { + error(getPos(), "Error in JPX COC marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].style = + (img.tiles[0].tileComps[comp].style & ~1) | (style & 1); + img.tiles[0].tileComps[comp].codeBlockW += 2; + img.tiles[0].tileComps[comp].codeBlockH += 2; + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + if (i != 0) { + img.tiles[i].tileComps[comp].style = + img.tiles[0].tileComps[comp].style; + img.tiles[i].tileComps[comp].nDecompLevels = + img.tiles[0].tileComps[comp].nDecompLevels; + img.tiles[i].tileComps[comp].codeBlockW = + img.tiles[0].tileComps[comp].codeBlockW; + img.tiles[i].tileComps[comp].codeBlockH = + img.tiles[0].tileComps[comp].codeBlockH; + img.tiles[i].tileComps[comp].codeBlockStyle = + img.tiles[0].tileComps[comp].codeBlockStyle; + img.tiles[i].tileComps[comp].transform = + img.tiles[0].tileComps[comp].transform; + } + img.tiles[i].tileComps[comp].resLevels = + (JPXResLevel *)greallocn( + img.tiles[i].tileComps[comp].resLevels, + (img.tiles[i].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; + } + } + for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) { + if (img.tiles[0].tileComps[comp].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15; + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15; + } + } + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { + img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[0].tileComps[comp].resLevels[r].precinctWidth; + img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[0].tileComps[comp].resLevels[r].precinctHeight; + } + } + break; + case 0x5c: // QCD - quantization default + if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) { + img.tiles[0].tileComps[0].nQuantSteps = segLen - 3; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) { + img.tiles[0].tileComps[0].nQuantSteps = 1; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); + if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) { + img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2; + img.tiles[0].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + for (comp = 0; comp < img.nComps; ++comp) { + if (!(i == 0 && comp == 0)) { + img.tiles[i].tileComps[comp].quantStyle = + img.tiles[0].tileComps[0].quantStyle; + img.tiles[i].tileComps[comp].nQuantSteps = + img.tiles[0].tileComps[0].nQuantSteps; + img.tiles[i].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) { + img.tiles[i].tileComps[comp].quantSteps[j] = + img.tiles[0].tileComps[0].quantSteps[j]; + } + } + } + } + haveQCD = gTrue; + break; + case 0x5d: // QCC - quantization component + if (!haveQCD) { + error(getPos(), "JPX QCC marker segment before QCD segment"); + return gFalse; + } + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) { + img.tiles[0].tileComps[comp].nQuantSteps = + segLen - (img.nComps > 256 ? 5 : 4); + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } + } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) { + img.tiles[0].tileComps[comp].nQuantSteps = 1; + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); + if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) { + img.tiles[0].tileComps[comp].nQuantSteps = + (segLen - (img.nComps > 256 ? 5 : 4)) / 2; + img.tiles[0].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { + img.tiles[i].tileComps[comp].quantStyle = + img.tiles[0].tileComps[comp].quantStyle; + img.tiles[i].tileComps[comp].nQuantSteps = + img.tiles[0].tileComps[comp].nQuantSteps; + img.tiles[i].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, + img.tiles[0].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) { + img.tiles[i].tileComps[comp].quantSteps[j] = + img.tiles[0].tileComps[comp].quantSteps[j]; + } + } + break; + case 0x5e: // RGN - region of interest +#if 1 //~ ROI is unimplemented + fprintf(stderr, "RGN\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&compInfo[comp].defROI.style) || + !readUByte(&compInfo[comp].defROI.shift)) { + error(getPos(), "Error in JPX RGN marker segment"); + return gFalse; + } +#endif + break; + case 0x5f: // POC - progression order change +#if 1 //~ progression order changes are unimplemented + fprintf(stderr, "POC\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); + progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder)); + for (i = 0; i < nProgs; ++i) { + if (!readUByte(&progs[i].startRes) || + !(img.nComps > 256 && readUWord(&progs[i].startComp)) || + !(img.nComps <= 256 && readUByte(&progs[i].startComp)) || + !readUWord(&progs[i].endLayer) || + !readUByte(&progs[i].endRes) || + !(img.nComps > 256 && readUWord(&progs[i].endComp)) || + !(img.nComps <= 256 && readUByte(&progs[i].endComp)) || + !readUByte(&progs[i].progOrder)) { + error(getPos(), "Error in JPX POC marker segment"); + return gFalse; + } + } +#endif + break; + case 0x60: // PPM - packed packet headers, main header +#if 1 //~ packed packet headers are unimplemented + fprintf(stderr, "PPM\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#endif + break; + case 0x55: // TLM - tile-part lengths + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX TLM marker segment"); + return gFalse; + } + } + break; + case 0x57: // PLM - packet length, main header + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PLM marker segment"); + return gFalse; + } + } + break; + case 0x63: // CRG - component registration + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX CRG marker segment"); + return gFalse; + } + } + break; + case 0x64: // COM - comment + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX COM marker segment"); + return gFalse; + } + } + break; + case 0x90: // SOT - start of tile + haveSOT = gTrue; + break; + default: + error(getPos(), "Unknown marker segment %02x in JPX stream", segType); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + break; + } + } + break; + } + } while (!haveSOT); + + if (!haveSIZ) { + error(getPos(), "Missing SIZ marker segment in JPX stream"); + return gFalse; + } + if (!haveCOD) { + error(getPos(), "Missing COD marker segment in JPX stream"); + return gFalse; + } + if (!haveQCD) { + error(getPos(), "Missing QCD marker segment in JPX stream"); + return gFalse; + } + + //----- read the tile-parts + while (1) { + if (!readTilePart()) { + return gFalse; + } + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX codestream"); + return gFalse; + } + if (segType != 0x90) { // SOT - start of tile + break; + } + } + + if (segType != 0xd9) { // EOC - end of codestream + error(getPos(), "Missing EOC marker in JPX codestream"); + return gFalse; + } + + //----- finish decoding the image + for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { + tile = &img.tiles[i]; + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + inverseTransform(tileComp); + } + if (!inverseMultiCompAndDC(tile)) { + return gFalse; + } + } + + //~ can free memory below tileComps here, and also tileComp.buf + + return gTrue; +} + +GBool JPXStream::readTilePart() { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + GBool haveSOD; + Guint tileIdx, tilePartLen, tilePartIdx, nTileParts; + GBool tilePartToEOC; + Guint precinctSize, style; + Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen; + Guint i, j, k, cbX, cbY, r, pre, sb, cbi; + int segType, level; + + // process the SOT marker segment + if (!readUWord(&tileIdx) || + !readULong(&tilePartLen) || + !readUByte(&tilePartIdx) || + !readUByte(&nTileParts)) { + error(getPos(), "Error in JPX SOT marker segment"); + return gFalse; + } + + if (tileIdx >= img.nXTiles * img.nYTiles) { + error(getPos(), "Weird tile index in JPX stream"); + return gFalse; + } + + tilePartToEOC = tilePartLen == 0; + tilePartLen -= 12; // subtract size of SOT segment + + haveSOD = gFalse; + do { + if (!readMarkerHdr(&segType, &segLen)) { + error(getPos(), "Error in JPX tile-part codestream"); + return gFalse; + } + tilePartLen -= 2 + segLen; + switch (segType) { + case 0x52: // COD - coding style default + if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) || + !readUByte(&img.tiles[tileIdx].progOrder) || + !readUWord(&img.tiles[tileIdx].nLayers) || + !readUByte(&img.tiles[tileIdx].multiComp) || + !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) || + !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) || + !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[0].codeBlockW += 2; + img.tiles[tileIdx].tileComps[0].codeBlockH += 2; + for (comp = 0; comp < img.nComps; ++comp) { + if (comp != 0) { + img.tiles[tileIdx].tileComps[comp].style = + img.tiles[tileIdx].tileComps[0].style; + img.tiles[tileIdx].tileComps[comp].nDecompLevels = + img.tiles[tileIdx].tileComps[0].nDecompLevels; + img.tiles[tileIdx].tileComps[comp].codeBlockW = + img.tiles[tileIdx].tileComps[0].codeBlockW; + img.tiles[tileIdx].tileComps[comp].codeBlockH = + img.tiles[tileIdx].tileComps[0].codeBlockH; + img.tiles[tileIdx].tileComps[comp].codeBlockStyle = + img.tiles[tileIdx].tileComps[0].codeBlockStyle; + img.tiles[tileIdx].tileComps[comp].transform = + img.tiles[tileIdx].tileComps[0].transform; + } + img.tiles[tileIdx].tileComps[comp].resLevels = + (JPXResLevel *)greallocn( + img.tiles[tileIdx].tileComps[comp].resLevels, + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); + for (r = 0; + r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; + ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; + } + } + for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) { + if (img.tiles[tileIdx].tileComps[0].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15; + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15; + } + } + for (comp = 1; comp < img.nComps; ++comp) { + for (r = 0; + r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; + ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = + img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight; + } + } + break; + case 0x53: // COC - coding style component + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&style) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) || + !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) { + error(getPos(), "Error in JPX COC marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[comp].style = + (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1); + img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; + img.tiles[tileIdx].tileComps[comp].codeBlockH += 2; + img.tiles[tileIdx].tileComps[comp].resLevels = + (JPXResLevel *)greallocn( + img.tiles[tileIdx].tileComps[comp].resLevels, + (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), + sizeof(JPXResLevel)); + for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; + } + for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { + if (img.tiles[tileIdx].tileComps[comp].style & 0x01) { + if (!readUByte(&precinctSize)) { + error(getPos(), "Error in JPX COD marker segment"); + return gFalse; + } + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = + precinctSize & 0x0f; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = + (precinctSize >> 4) & 0x0f; + } else { + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15; + img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15; + } + } + break; + case 0x5c: // QCD - quantization default + if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = + segLen - 3; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = 1; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); + if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) { + img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2; + img.tiles[tileIdx].tileComps[0].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + for (comp = 1; comp < img.nComps; ++comp) { + img.tiles[tileIdx].tileComps[comp].quantStyle = + img.tiles[tileIdx].tileComps[0].quantStyle; + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + img.tiles[tileIdx].tileComps[0].nQuantSteps; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[0].nQuantSteps, + sizeof(Guint)); + for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) { + img.tiles[tileIdx].tileComps[comp].quantSteps[j] = + img.tiles[tileIdx].tileComps[0].quantSteps[j]; + } + } + break; + case 0x5d: // QCC - quantization component + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + segLen - (img.nComps > 256 ? 5 : 4); + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { + if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } + } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) + == 0x01) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); + if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) + == 0x02) { + img.tiles[tileIdx].tileComps[comp].nQuantSteps = + (segLen - (img.nComps > 256 ? 5 : 4)) / 2; + img.tiles[tileIdx].tileComps[comp].quantSteps = + (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, + img.tiles[tileIdx].tileComps[comp].nQuantSteps, + sizeof(Guint)); + for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { + if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { + error(getPos(), "Error in JPX QCD marker segment"); + return gFalse; + } + } + } else { + error(getPos(), "Error in JPX QCC marker segment"); + return gFalse; + } + break; + case 0x5e: // RGN - region of interest +#if 1 //~ ROI is unimplemented + fprintf(stderr, "RGN\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + if ((img.nComps > 256 && !readUWord(&comp)) || + (img.nComps <= 256 && !readUByte(&comp)) || + comp >= img.nComps || + !readUByte(&compInfo[comp].roi.style) || + !readUByte(&compInfo[comp].roi.shift)) { + error(getPos(), "Error in JPX RGN marker segment"); + return gFalse; + } +#endif + break; + case 0x5f: // POC - progression order change +#if 1 //~ progression order changes are unimplemented + fprintf(stderr, "POC\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPM marker segment"); + return gFalse; + } + } +#else + nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); + tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder)); + for (i = 0; i < nTileProgs; ++i) { + if (!readUByte(&tileProgs[i].startRes) || + !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) || + !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) || + !readUWord(&tileProgs[i].endLayer) || + !readUByte(&tileProgs[i].endRes) || + !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) || + !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) || + !readUByte(&tileProgs[i].progOrder)) { + error(getPos(), "Error in JPX POC marker segment"); + return gFalse; + } + } +#endif + break; + case 0x61: // PPT - packed packet headers, tile-part hdr +#if 1 //~ packed packet headers are unimplemented + fprintf(stderr, "PPT\n"); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PPT marker segment"); + return gFalse; + } + } +#endif + case 0x58: // PLT - packet length, tile-part header + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX PLT marker segment"); + return gFalse; + } + } + break; + case 0x64: // COM - comment + // skipped + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + error(getPos(), "Error in JPX COM marker segment"); + return gFalse; + } + } + break; + case 0x93: // SOD - start of data + haveSOD = gTrue; + break; + default: + error(getPos(), "Unknown marker segment %02x in JPX tile-part stream", + segType); + for (i = 0; i < segLen - 2; ++i) { + if (str->getChar() == EOF) { + break; + } + } + break; + } + } while (!haveSOD); + + //----- initialize the tile, precincts, and code-blocks + if (tilePartIdx == 0) { + tile = &img.tiles[tileIdx]; + i = tileIdx / img.nXTiles; + j = tileIdx % img.nXTiles; + if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) { + tile->x0 = img.xOffset; + } + if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) { + tile->y0 = img.yOffset; + } + if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) { + tile->x1 = img.xSize; + } + if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) { + tile->y1 = img.ySize; + } + tile->comp = 0; + tile->res = 0; + tile->precinct = 0; + tile->layer = 0; + tile->maxNDecompLevels = 0; + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + if (tileComp->nDecompLevels > tile->maxNDecompLevels) { + tile->maxNDecompLevels = tileComp->nDecompLevels; + } + tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep); + tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->hSep); + tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep); + tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->hSep); + tileComp->cbW = 1 << tileComp->codeBlockW; + tileComp->cbH = 1 << tileComp->codeBlockH; + tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) * + (tileComp->y1 - tileComp->y0), + sizeof(int)); + if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { + n = tileComp->x1 - tileComp->x0; + } else { + n = tileComp->y1 - tileComp->y0; + } + tileComp->buf = (int *)gmallocn(n + 8, sizeof(int)); + for (r = 0; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + k = r == 0 ? tileComp->nDecompLevels + : tileComp->nDecompLevels - r + 1; + resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k); + resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k); + resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k); + resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k); + if (r == 0) { + resLevel->bx0[0] = resLevel->x0; + resLevel->by0[0] = resLevel->y0; + resLevel->bx1[0] = resLevel->x1; + resLevel->by1[0] = resLevel->y1; + } else { + resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); + resLevel->by0[0] = resLevel->y0; + resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); + resLevel->by1[0] = resLevel->y1; + resLevel->bx0[1] = resLevel->x0; + resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); + resLevel->bx1[1] = resLevel->x1; + resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); + resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); + resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); + resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); + resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); + } + resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct)); + for (pre = 0; pre < 1; ++pre) { + precinct = &resLevel->precincts[pre]; + precinct->x0 = resLevel->x0; + precinct->y0 = resLevel->y0; + precinct->x1 = resLevel->x1; + precinct->y1 = resLevel->y1; + nSBs = r == 0 ? 1 : 3; + precinct->subbands = + (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband)); + for (sb = 0; sb < nSBs; ++sb) { + subband = &precinct->subbands[sb]; + subband->x0 = resLevel->bx0[sb]; + subband->y0 = resLevel->by0[sb]; + subband->x1 = resLevel->bx1[sb]; + subband->y1 = resLevel->by1[sb]; + subband->nXCBs = jpxCeilDivPow2(subband->x1, + tileComp->codeBlockW) + - jpxFloorDivPow2(subband->x0, + tileComp->codeBlockW); + subband->nYCBs = jpxCeilDivPow2(subband->y1, + tileComp->codeBlockH) + - jpxFloorDivPow2(subband->y0, + tileComp->codeBlockH); + n = subband->nXCBs > subband->nYCBs ? subband->nXCBs + : subband->nYCBs; + for (subband->maxTTLevel = 0, --n; + n; + ++subband->maxTTLevel, n >>= 1) ; + n = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + n += nx * ny; + } + subband->inclusion = + (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); + subband->zeroBitPlane = + (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); + for (k = 0; k < n; ++k) { + subband->inclusion[k].finished = gFalse; + subband->inclusion[k].val = 0; + subband->zeroBitPlane[k].finished = gFalse; + subband->zeroBitPlane[k].val = 0; + } + subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs * + subband->nYCBs, + sizeof(JPXCodeBlock)); + sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW); + sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH); + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW; + cb->x1 = cb->x0 + tileComp->cbW; + if (subband->x0 > cb->x0) { + cb->x0 = subband->x0; + } + if (subband->x1 < cb->x1) { + cb->x1 = subband->x1; + } + cb->y0 = (sby0 + cbY) << tileComp->codeBlockH; + cb->y1 = cb->y0 + tileComp->cbH; + if (subband->y0 > cb->y0) { + cb->y0 = subband->y0; + } + if (subband->y1 < cb->y1) { + cb->y1 = subband->y1; + } + cb->seen = gFalse; + cb->lBlock = 3; + cb->nextPass = jpxPassCleanup; + cb->nZeroBitPlanes = 0; + cb->coeffs = + (JPXCoeff *)gmallocn((1 << (tileComp->codeBlockW + + tileComp->codeBlockH)), + sizeof(JPXCoeff)); + for (cbi = 0; + cbi < (Guint)(1 << (tileComp->codeBlockW + + tileComp->codeBlockH)); + ++cbi) { + cb->coeffs[cbi].flags = 0; + cb->coeffs[cbi].len = 0; + cb->coeffs[cbi].mag = 0; + } + cb->arithDecoder = NULL; + cb->stats = NULL; + ++cb; + } + } + } + } + } + } + } + + return readTilePartData(tileIdx, tilePartLen, tilePartToEOC); +} + +GBool JPXStream::readTilePartData(Guint tileIdx, + Guint tilePartLen, GBool tilePartToEOC) { + JPXTile *tile; + JPXTileComp *tileComp; + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + Guint ttVal; + Guint bits, cbX, cbY, nx, ny, i, j, n, sb; + int level; + + tile = &img.tiles[tileIdx]; + + // read all packets from this tile-part + while (1) { + if (tilePartToEOC) { + //~ peek for an EOC marker + } else if (tilePartLen == 0) { + break; + } + + tileComp = &tile->tileComps[tile->comp]; + resLevel = &tileComp->resLevels[tile->res]; + precinct = &resLevel->precincts[tile->precinct]; + + //----- packet header + + // zero-length flag + if (!readBits(1, &bits)) { + goto err; + } + if (!bits) { + // packet is empty -- clear all code-block inclusion flags + for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + cb->included = gFalse; + } + } + } + } else { + + for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + + // skip code-blocks with no coefficients + if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) { + cb->included = gFalse; + continue; + } + + // code-block inclusion + if (cb->seen) { + if (!readBits(1, &cb->included)) { + goto err; + } + } else { + ttVal = 0; + i = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + j = i + (cbY >> level) * nx + (cbX >> level); + if (!subband->inclusion[j].finished && + !subband->inclusion[j].val) { + subband->inclusion[j].val = ttVal; + } else { + ttVal = subband->inclusion[j].val; + } + while (!subband->inclusion[j].finished && + ttVal <= tile->layer) { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 1) { + subband->inclusion[j].finished = gTrue; + } else { + ++ttVal; + } + } + subband->inclusion[j].val = ttVal; + if (ttVal > tile->layer) { + break; + } + i += nx * ny; + } + cb->included = level < 0; + } + + if (cb->included) { + + // zero bit-plane count + if (!cb->seen) { + ttVal = 0; + i = 0; + for (level = subband->maxTTLevel; level >= 0; --level) { + nx = jpxCeilDivPow2(subband->nXCBs, level); + ny = jpxCeilDivPow2(subband->nYCBs, level); + j = i + (cbY >> level) * nx + (cbX >> level); + if (!subband->zeroBitPlane[j].finished && + !subband->zeroBitPlane[j].val) { + subband->zeroBitPlane[j].val = ttVal; + } else { + ttVal = subband->zeroBitPlane[j].val; + } + while (!subband->zeroBitPlane[j].finished) { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 1) { + subband->zeroBitPlane[j].finished = gTrue; + } else { + ++ttVal; + } + } + subband->zeroBitPlane[j].val = ttVal; + i += nx * ny; + } + cb->nZeroBitPlanes = ttVal; + } + + // number of coding passes + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 0) { + cb->nCodingPasses = 1; + } else { + if (!readBits(1, &bits)) { + goto err; + } + if (bits == 0) { + cb->nCodingPasses = 2; + } else { + if (!readBits(2, &bits)) { + goto err; + } + if (bits < 3) { + cb->nCodingPasses = 3 + bits; + } else { + if (!readBits(5, &bits)) { + goto err; + } + if (bits < 31) { + cb->nCodingPasses = 6 + bits; + } else { + if (!readBits(7, &bits)) { + goto err; + } + cb->nCodingPasses = 37 + bits; + } + } + } + } + + // update Lblock + while (1) { + if (!readBits(1, &bits)) { + goto err; + } + if (!bits) { + break; + } + ++cb->lBlock; + } + + // length of compressed data + //~ deal with multiple codeword segments + for (n = cb->lBlock, i = cb->nCodingPasses >> 1; + i; + ++n, i >>= 1) ; + if (!readBits(n, &cb->dataLen)) { + goto err; + } + } + } + } + } + } + tilePartLen -= byteCount; + clearBitBuf(); + + //----- packet data + + for (sb = 0; sb < (tile->res == 0 ? 1 : 3); ++sb) { + subband = &precinct->subbands[sb]; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + cb = &subband->cbs[cbY * subband->nXCBs + cbX]; + if (cb->included) { + if (!readCodeBlockData(tileComp, resLevel, precinct, subband, + tile->res, sb, cb)) { + return gFalse; + } + tilePartLen -= cb->dataLen; + cb->seen = gTrue; + } + } + } + } + + //----- next packet + + switch (tile->progOrder) { + case 0: // layer, resolution level, component, precinct + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + } + } + } + break; + case 1: // resolution level, layer, component, precinct + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + } + } + } + break; + case 2: // resolution level, precinct, component, layer + //~ this isn't correct -- see B.12.1.3 + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + } + } + } + break; + case 3: // precinct, component, resolution level, layer + //~ this isn't correct -- see B.12.1.4 + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + } + } + } + break; + case 4: // component, precinct, resolution level, layer + //~ this isn't correct -- see B.12.1.5 + if (++tile->layer == tile->nLayers) { + tile->layer = 0; + if (++tile->res == tile->maxNDecompLevels + 1) { + tile->res = 0; + if (++tile->comp == img.nComps) { + tile->comp = 0; + } + } + } + break; + } + } + + return gTrue; + + err: + error(getPos(), "Error in JPX stream"); + return gFalse; +} + +GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, + JPXResLevel *resLevel, + JPXPrecinct *precinct, + JPXSubband *subband, + Guint res, Guint sb, + JPXCodeBlock *cb) { + JPXCoeff *coeff0, *coeff1, *coeff; + Guint horiz, vert, diag, all, cx, xorBit; + int horizSign, vertSign; + Guint i, x, y0, y1, y2; + + if (cb->arithDecoder) { + cb->arithDecoder->restart(cb->dataLen); + } else { + cb->arithDecoder = new JArithmeticDecoder(); + cb->arithDecoder->setStream(str, cb->dataLen); + cb->arithDecoder->start(); + cb->stats = new JArithmeticDecoderStats(jpxNContexts); + cb->stats->setEntry(jpxContextSigProp, 4, 0); + cb->stats->setEntry(jpxContextRunLength, 3, 0); + cb->stats->setEntry(jpxContextUniform, 46, 0); + } + + for (i = 0; i < cb->nCodingPasses; ++i) { + switch (cb->nextPass) { + + //----- significance propagation pass + case jpxPassSigProp: + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + for (y1 = 0, coeff = coeff1; + y1 < 4 && y0+y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if (!(coeff->flags & jpxCoeffSignificant)) { + horiz = vert = diag = 0; + horizSign = vertSign = 2; + if (x > cb->x0) { + if (coeff[-1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-(int)tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + if (coeff[1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-(int)tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + if (y0+y1 < cb->y1 - 1) { + if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; + if (cx != 0) { + if (cb->arithDecoder->decodeBit(cx, cb->stats)) { + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + cx = signContext[horizSign][vertSign][0]; + xorBit = signContext[horizSign][vertSign][1]; + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + } + ++coeff->len; + coeff->flags |= jpxCoeffTouched; + } + } + } + } + } + ++cb->nextPass; + break; + + //----- magnitude refinement pass + case jpxPassMagRef: + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + for (y1 = 0, coeff = coeff1; + y1 < 4 && y0+y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if ((coeff->flags & jpxCoeffSignificant) && + !(coeff->flags & jpxCoeffTouched)) { + if (coeff->flags & jpxCoeffFirstMagRef) { + all = 0; + if (x > cb->x0) { + all += (coeff[-1].flags >> jpxCoeffSignificantB) & 1; + if (y0+y1 > cb->y0) { + all += (coeff[-(int)tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + all += (coeff[1].flags >> jpxCoeffSignificantB) & 1; + if (y0+y1 > cb->y0) { + all += (coeff[-(int)tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + all += (coeff[-(int)tileComp->cbW].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + all += (coeff[tileComp->cbW].flags + >> jpxCoeffSignificantB) & 1; + } + cx = all ? 15 : 14; + } else { + cx = 16; + } + coeff->mag = (coeff->mag << 1) | + cb->arithDecoder->decodeBit(cx, cb->stats); + ++coeff->len; + coeff->flags |= jpxCoeffTouched; + coeff->flags &= ~jpxCoeffFirstMagRef; + } + } + } + } + ++cb->nextPass; + break; + + //----- cleanup pass + case jpxPassCleanup: + for (y0 = cb->y0, coeff0 = cb->coeffs; + y0 < cb->y1; + y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { + for (x = cb->x0, coeff1 = coeff0; + x < cb->x1; + ++x, ++coeff1) { + y1 = 0; + if (y0 + 3 < cb->y1 && + !(coeff1->flags & jpxCoeffTouched) && + !(coeff1[tileComp->cbW].flags & jpxCoeffTouched) && + !(coeff1[2 * tileComp->cbW].flags & jpxCoeffTouched) && + !(coeff1[3 * tileComp->cbW].flags & jpxCoeffTouched) && + (x == cb->x0 || y0 == cb->y0 || + !(coeff1[-(int)tileComp->cbW - 1].flags + & jpxCoeffSignificant)) && + (y0 == cb->y0 || + !(coeff1[-(int)tileComp->cbW].flags + & jpxCoeffSignificant)) && + (x == cb->x1 - 1 || y0 == cb->y0 || + !(coeff1[-(int)tileComp->cbW + 1].flags + & jpxCoeffSignificant)) && + (x == cb->x0 || + (!(coeff1[-1].flags & jpxCoeffSignificant) && + !(coeff1[tileComp->cbW - 1].flags + & jpxCoeffSignificant) && + !(coeff1[2 * tileComp->cbW - 1].flags + & jpxCoeffSignificant) && + !(coeff1[3 * tileComp->cbW - 1].flags + & jpxCoeffSignificant))) && + (x == cb->x1 - 1 || + (!(coeff1[1].flags & jpxCoeffSignificant) && + !(coeff1[tileComp->cbW + 1].flags + & jpxCoeffSignificant) && + !(coeff1[2 * tileComp->cbW + 1].flags + & jpxCoeffSignificant) && + !(coeff1[3 * tileComp->cbW + 1].flags + & jpxCoeffSignificant))) && + (x == cb->x0 || y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW - 1].flags & jpxCoeffSignificant)) && + (y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW].flags & jpxCoeffSignificant)) && + (x == cb->x1 - 1 || y0+4 == cb->y1 || + !(coeff1[4 * tileComp->cbW + 1].flags + & jpxCoeffSignificant))) { + if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) { + y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); + y1 = (y1 << 1) | + cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); + for (y2 = 0, coeff = coeff1; + y2 < y1; + ++y2, coeff += tileComp->cbW) { + ++coeff->len; + } + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + ++coeff->len; + cx = signContext[2][2][0]; + xorBit = signContext[2][2][1]; + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + ++y1; + } else { + for (y1 = 0, coeff = coeff1; + y1 < 4; + ++y1, coeff += tileComp->cbW) { + ++coeff->len; + } + y1 = 4; + } + } + for (coeff = &coeff1[y1 << tileComp->codeBlockW]; + y1 < 4 && y0 + y1 < cb->y1; + ++y1, coeff += tileComp->cbW) { + if (!(coeff->flags & jpxCoeffTouched)) { + horiz = vert = diag = 0; + horizSign = vertSign = 2; + if (x > cb->x0) { + if (coeff[-1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[-1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-(int)tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW - 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (x < cb->x1 - 1) { + if (coeff[1].flags & jpxCoeffSignificant) { + ++horiz; + horizSign += (coeff[1].flags & jpxCoeffSign) ? -1 : 1; + } + if (y0+y1 > cb->y0) { + diag += (coeff[-(int)tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + if (y0+y1 < cb->y1 - 1) { + diag += (coeff[tileComp->cbW + 1].flags + >> jpxCoeffSignificantB) & 1; + } + } + if (y0+y1 > cb->y0) { + if (coeff[-(int)tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[-(int)tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + if (y0+y1 < cb->y1 - 1) { + if (coeff[tileComp->cbW].flags & jpxCoeffSignificant) { + ++vert; + vertSign += (coeff[tileComp->cbW].flags & jpxCoeffSign) + ? -1 : 1; + } + } + cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; + if (cb->arithDecoder->decodeBit(cx, cb->stats)) { + coeff->flags |= jpxCoeffSignificant | jpxCoeffFirstMagRef; + coeff->mag = (coeff->mag << 1) | 1; + cx = signContext[horizSign][vertSign][0]; + xorBit = signContext[horizSign][vertSign][1]; + if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { + coeff->flags |= jpxCoeffSign; + } + } + ++coeff->len; + } else { + coeff->flags &= ~jpxCoeffTouched; + } + } + } + } + cb->nextPass = jpxPassSigProp; + break; + } + } + + cb->arithDecoder->cleanup(); + return gTrue; +} + +// Inverse quantization, and wavelet transform (IDWT). This also does +// the initial shift to convert to fixed point format. +void JPXStream::inverseTransform(JPXTileComp *tileComp) { + JPXResLevel *resLevel; + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + JPXCoeff *coeff0, *coeff; + Guint qStyle, guard, eps, shift; + int shift2; + double mu; + int val; + int *dataPtr; + Guint nx0, ny0, nx1, ny1; + Guint r, cbX, cbY, x, y; + + //----- (NL)LL subband (resolution level 0) + + resLevel = &tileComp->resLevels[0]; + precinct = &resLevel->precincts[0]; + subband = &precinct->subbands[0]; + + // i-quant parameters + qStyle = tileComp->quantStyle & 0x1f; + guard = (tileComp->quantStyle >> 5) & 7; + if (qStyle == 0) { + eps = (tileComp->quantSteps[0] >> 3) & 0x1f; + shift = guard + eps - 1; + mu = 0; // make gcc happy + } else { + shift = guard - 1 + tileComp->prec; + mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0; + } + if (tileComp->transform == 0) { + shift += fracBits; + } + + // copy (NL)LL into the upper-left corner of the data array, doing + // the fixed point adjustment and dequantization along the way + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + for (y = cb->y0, coeff0 = cb->coeffs; + y < cb->y1; + ++y, coeff0 += tileComp->cbW) { + dataPtr = &tileComp->data[(y - subband->y0) + * (tileComp->x1 - tileComp->x0) + + (cb->x0 - subband->x0)]; + for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) { + val = (int)coeff->mag; + if (val != 0) { + shift2 = shift - (cb->nZeroBitPlanes + coeff->len); + if (shift2 > 0) { + val = (val << shift2) + (1 << (shift2 - 1)); + } else { + val >>= -shift2; + } + if (qStyle == 0) { + if (tileComp->transform == 0) { + val &= -1 << fracBits; + } + } else { + val = (int)((double)val * mu); + } + if (coeff->flags & jpxCoeffSign) { + val = -val; + } + } + *dataPtr++ = val; + } + } + ++cb; + } + } + + //----- IDWT for each level + + for (r = 1; r <= tileComp->nDecompLevels; ++r) { + resLevel = &tileComp->resLevels[r]; + + // (n)LL is already in the upper-left corner of the + // tile-component data array -- interleave with (n)HL/LH/HH + // and inverse transform to get (n-1)LL, which will be stored + // in the upper-left corner of the tile-component data array + if (r == tileComp->nDecompLevels) { + nx0 = tileComp->x0; + ny0 = tileComp->y0; + nx1 = tileComp->x1; + ny1 = tileComp->y1; + } else { + nx0 = tileComp->resLevels[r+1].x0; + ny0 = tileComp->resLevels[r+1].y0; + nx1 = tileComp->resLevels[r+1].x1; + ny1 = tileComp->resLevels[r+1].y1; + } + inverseTransformLevel(tileComp, r, resLevel, nx0, ny0, nx1, ny1); + } +} + +// Do one level of the inverse transform: +// - take (n)LL from the tile-component data array +// - take (n)HL/LH/HH from +// - leave the resulting (n-1)LL in the tile-component data array +void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, + Guint r, JPXResLevel *resLevel, + Guint nx0, Guint ny0, + Guint nx1, Guint ny1) { + JPXPrecinct *precinct; + JPXSubband *subband; + JPXCodeBlock *cb; + JPXCoeff *coeff0, *coeff; + Guint qStyle, guard, eps, shift, t; + int shift2; + double mu; + int val; + int *dataPtr; + Guint xo, yo; + Guint x, y, sb, cbX, cbY; + int xx, yy; + + //----- interleave + + // spread out LL + for (yy = resLevel->y1 - 1; yy >= (int)resLevel->y0; --yy) { + for (xx = resLevel->x1 - 1; xx >= (int)resLevel->x0; --xx) { + tileComp->data[(2 * yy - ny0) * (tileComp->x1 - tileComp->x0) + + (2 * xx - nx0)] = + tileComp->data[(yy - resLevel->y0) * (tileComp->x1 - tileComp->x0) + + (xx - resLevel->x0)]; + } + } + + // i-quant parameters + qStyle = tileComp->quantStyle & 0x1f; + guard = (tileComp->quantStyle >> 5) & 7; + + // interleave HL/LH/HH + precinct = &resLevel->precincts[0]; + for (sb = 0; sb < 3; ++sb) { + + // i-quant parameters + if (qStyle == 0) { + eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f; + shift = guard + eps - 1; + mu = 0; // make gcc happy + } else { + shift = guard + tileComp->prec; + if (sb == 2) { + ++shift; + } + t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)]; + mu = (double)(0x800 + (t & 0x7ff)) / 2048.0; + } + if (tileComp->transform == 0) { + shift += fracBits; + } + + // copy the subband coefficients into the data array, doing the + // fixed point adjustment and dequantization along the way + xo = (sb & 1) ? 0 : 1; + yo = (sb > 0) ? 1 : 0; + subband = &precinct->subbands[sb]; + cb = subband->cbs; + for (cbY = 0; cbY < subband->nYCBs; ++cbY) { + for (cbX = 0; cbX < subband->nXCBs; ++cbX) { + for (y = cb->y0, coeff0 = cb->coeffs; + y < cb->y1; + ++y, coeff0 += tileComp->cbW) { + dataPtr = &tileComp->data[(2 * y + yo - ny0) + * (tileComp->x1 - tileComp->x0) + + (2 * cb->x0 + xo - nx0)]; + for (x = cb->x0, coeff = coeff0; x < cb->x1; ++x, ++coeff) { + val = (int)coeff->mag; + if (val != 0) { + shift2 = shift - (cb->nZeroBitPlanes + coeff->len); + if (shift2 > 0) { + val = (val << shift2) + (1 << (shift2 - 1)); + } else { + val >>= -shift2; + } + if (qStyle == 0) { + if (tileComp->transform == 0) { + val &= -1 << fracBits; + } + } else { + val = (int)((double)val * mu); + } + if (coeff->flags & jpxCoeffSign) { + val = -val; + } + } + *dataPtr = val; + dataPtr += 2; + } + } + ++cb; + } + } + } + + //----- horizontal (row) transforms + dataPtr = tileComp->data; + for (y = 0; y < ny1 - ny0; ++y) { + inverseTransform1D(tileComp, dataPtr, 1, nx0, nx1); + dataPtr += tileComp->x1 - tileComp->x0; + } + + //----- vertical (column) transforms + dataPtr = tileComp->data; + for (x = 0; x < nx1 - nx0; ++x) { + inverseTransform1D(tileComp, dataPtr, + tileComp->x1 - tileComp->x0, ny0, ny1); + ++dataPtr; + } +} + +void JPXStream::inverseTransform1D(JPXTileComp *tileComp, + int *data, Guint stride, + Guint i0, Guint i1) { + int *buf; + Guint offset, end, i; + + //----- special case for length = 1 + if (i1 - i0 == 1) { + if (i0 & 1) { + *data >>= 1; + } + + } else { + + // choose an offset: this makes even buf[] indexes correspond to + // odd values of i, and vice versa + offset = 3 + (i0 & 1); + end = offset + i1 - i0; + + //----- gather + buf = tileComp->buf; + for (i = 0; i < i1 - i0; ++i) { + buf[offset + i] = data[i * stride]; + } + + //----- extend right + buf[end] = buf[end - 2]; + if (i1 - i0 == 2) { + buf[end+1] = buf[offset + 1]; + buf[end+2] = buf[offset]; + buf[end+3] = buf[offset + 1]; + } else { + buf[end+1] = buf[end - 3]; + if (i1 - i0 == 3) { + buf[end+2] = buf[offset + 1]; + buf[end+3] = buf[offset + 2]; + } else { + buf[end+2] = buf[end - 4]; + if (i1 - i0 == 4) { + buf[end+3] = buf[offset + 1]; + } else { + buf[end+3] = buf[end - 5]; + } + } + } + + //----- extend left + buf[offset - 1] = buf[offset + 1]; + buf[offset - 2] = buf[offset + 2]; + buf[offset - 3] = buf[offset + 3]; + if (offset == 4) { + buf[0] = buf[offset + 4]; + } + + //----- 9-7 irreversible filter + + if (tileComp->transform == 0) { + // step 1 (even) + for (i = 1; i <= end + 2; i += 2) { + buf[i] = (int)(idwtKappa * buf[i]); + } + // step 2 (odd) + for (i = 0; i <= end + 3; i += 2) { + buf[i] = (int)(idwtIKappa * buf[i]); + } + // step 3 (even) + for (i = 1; i <= end + 2; i += 2) { + buf[i] = (int)(buf[i] - idwtDelta * (buf[i-1] + buf[i+1])); + } + // step 4 (odd) + for (i = 2; i <= end + 1; i += 2) { + buf[i] = (int)(buf[i] - idwtGamma * (buf[i-1] + buf[i+1])); + } + // step 5 (even) + for (i = 3; i <= end; i += 2) { + buf[i] = (int)(buf[i] - idwtBeta * (buf[i-1] + buf[i+1])); + } + // step 6 (odd) + for (i = 4; i <= end - 1; i += 2) { + buf[i] = (int)(buf[i] - idwtAlpha * (buf[i-1] + buf[i+1])); + } + + //----- 5-3 reversible filter + + } else { + // step 1 (even) + for (i = 3; i <= end; i += 2) { + buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2; + } + // step 2 (odd) + for (i = 4; i < end; i += 2) { + buf[i] += (buf[i-1] + buf[i+1]) >> 1; + } + } + + //----- scatter + for (i = 0; i < i1 - i0; ++i) { + data[i * stride] = buf[offset + i]; + } + } +} + +// Inverse multi-component transform and DC level shift. This also +// converts fixed point samples back to integers. +GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { + JPXTileComp *tileComp; + int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal; + int *dataPtr; + Guint j, comp, x, y; + + //----- inverse multi-component transform + + if (tile->multiComp == 1) { + if (img.nComps < 3 || + tile->tileComps[0].hSep != tile->tileComps[1].hSep || + tile->tileComps[0].vSep != tile->tileComps[1].vSep || + tile->tileComps[1].hSep != tile->tileComps[2].hSep || + tile->tileComps[1].vSep != tile->tileComps[2].vSep) { + return gFalse; + } + + // inverse irreversible multiple component transform + if (tile->tileComps[0].transform == 0) { + j = 0; + for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { + for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { + d0 = tile->tileComps[0].data[j]; + d1 = tile->tileComps[1].data[j]; + d2 = tile->tileComps[2].data[j]; + tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5); + tile->tileComps[1].data[j] = + (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5); + tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5); + ++j; + } + } + + // inverse reversible multiple component transform + } else { + j = 0; + for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { + for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { + d0 = tile->tileComps[0].data[j]; + d1 = tile->tileComps[1].data[j]; + d2 = tile->tileComps[2].data[j]; + tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2); + tile->tileComps[0].data[j] = d2 + t; + tile->tileComps[2].data[j] = d1 + t; + ++j; + } + } + } + } + + //----- DC level shift + for (comp = 0; comp < img.nComps; ++comp) { + tileComp = &tile->tileComps[comp]; + + // signed: clip + if (tileComp->sgned) { + minVal = -(1 << (tileComp->prec - 1)); + maxVal = (1 << (tileComp->prec - 1)) - 1; + dataPtr = tileComp->data; + for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { + for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { + coeff = *dataPtr; + if (tileComp->transform == 0) { + coeff >>= fracBits; + } + if (coeff < minVal) { + coeff = minVal; + } else if (coeff > maxVal) { + coeff = maxVal; + } + *dataPtr++ = coeff; + } + } + + // unsigned: inverse DC level shift and clip + } else { + maxVal = (1 << tileComp->prec) - 1; + zeroVal = 1 << (tileComp->prec - 1); + dataPtr = tileComp->data; + for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { + for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { + coeff = *dataPtr; + if (tileComp->transform == 0) { + coeff >>= fracBits; + } + coeff += zeroVal; + if (coeff < 0) { + coeff = 0; + } else if (coeff > maxVal) { + coeff = maxVal; + } + *dataPtr++ = coeff; + } + } + } + } + + return gTrue; +} + +GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) { + Guint len, lenH; + + if (!readULong(&len) || + !readULong(boxType)) { + return gFalse; + } + if (len == 1) { + if (!readULong(&lenH) || !readULong(&len)) { + return gFalse; + } + if (lenH) { + error(getPos(), "JPX stream contains a box larger than 2^32 bytes"); + return gFalse; + } + *boxLen = len; + *dataLen = len - 16; + } else if (len == 0) { + *boxLen = 0; + *dataLen = 0; + } else { + *boxLen = len; + *dataLen = len - 8; + } + return gTrue; +} + +int JPXStream::readMarkerHdr(int *segType, Guint *segLen) { + int c; + + do { + do { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + } while (c != 0xff); + do { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + } while (c == 0xff); + } while (c == 0x00); + *segType = c; + if ((c >= 0x30 && c <= 0x3f) || + c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) { + *segLen = 0; + return gTrue; + } + return readUWord(segLen); +} + +GBool JPXStream::readUByte(Guint *x) { + int c0; + + if ((c0 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)c0; + return gTrue; +} + +GBool JPXStream::readByte(int *x) { + int c0; + + if ((c0 = str->getChar()) == EOF) { + return gFalse; + } + *x = c0; + if (c0 & 0x80) { + *x |= -1 - 0xff; + } + return gTrue; +} + +GBool JPXStream::readUWord(Guint *x) { + int c0, c1; + + if ((c0 = str->getChar()) == EOF || + (c1 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 8) | c1); + return gTrue; +} + +GBool JPXStream::readULong(Guint *x) { + int c0, c1, c2, c3; + + if ((c0 = str->getChar()) == EOF || + (c1 = str->getChar()) == EOF || + (c2 = str->getChar()) == EOF || + (c3 = str->getChar()) == EOF) { + return gFalse; + } + *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); + return gTrue; +} + +GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) { + int y, c, i; + + y = 0; + for (i = 0; i < nBytes; ++i) { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + y = (y << 8) + c; + } + if (signd) { + if (y & (1 << (8 * nBytes - 1))) { + y |= -1 << (8 * nBytes); + } + } + *x = y; + return gTrue; +} + +GBool JPXStream::readBits(int nBits, Guint *x) { + int c; + + while (bitBufLen < nBits) { + if ((c = str->getChar()) == EOF) { + return gFalse; + } + ++byteCount; + if (bitBufSkip) { + bitBuf = (bitBuf << 7) | (c & 0x7f); + bitBufLen += 7; + } else { + bitBuf = (bitBuf << 8) | (c & 0xff); + bitBufLen += 8; + } + bitBufSkip = c == 0xff; + } + *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1); + bitBufLen -= nBits; + return gTrue; +} + +void JPXStream::clearBitBuf() { + bitBufLen = 0; + bitBufSkip = gFalse; + byteCount = 0; +} diff --git a/pdftops/JPXStream.h b/pdftops/JPXStream.h new file mode 100644 index 000000000..60c12f07f --- /dev/null +++ b/pdftops/JPXStream.h @@ -0,0 +1,349 @@ +//======================================================================== +// +// JPXStream.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef JPXSTREAM_H +#define JPXSTREAM_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" +#include "Stream.h" + +class JArithmeticDecoderStats; + +//------------------------------------------------------------------------ + +enum JPXColorSpaceType { + jpxCSBiLevel = 0, + jpxCSYCbCr1 = 1, + jpxCSYCbCr2 = 3, + jpxCSYCBCr3 = 4, + jpxCSPhotoYCC = 9, + jpxCSCMY = 11, + jpxCSCMYK = 12, + jpxCSYCCK = 13, + jpxCSCIELab = 14, + jpxCSsRGB = 16, + jpxCSGrayscale = 17, + jpxCSBiLevel2 = 18, + jpxCSCIEJab = 19, + jpxCSCISesRGB = 20, + jpxCSROMMRGB = 21, + jpxCSsRGBYCbCr = 22, + jpxCSYPbPr1125 = 23, + jpxCSYPbPr1250 = 24 +}; + +struct JPXColorSpecCIELab { + Guint rl, ol, ra, oa, rb, ob, il; +}; + +struct JPXColorSpecEnumerated { + JPXColorSpaceType type; // color space type + union { + JPXColorSpecCIELab cieLab; + }; +}; + +struct JPXColorSpec { + Guint meth; // method + int prec; // precedence + union { + JPXColorSpecEnumerated enumerated; + }; +}; + +//------------------------------------------------------------------------ + +struct JPXPalette { + Guint nEntries; // number of entries in the palette + Guint nComps; // number of components in each entry + Guint *bpc; // bits per component, for each component + int *c; // color data: + // c[i*nComps+j] = entry i, component j +}; + +//------------------------------------------------------------------------ + +struct JPXCompMap { + Guint nChannels; // number of channels + Guint *comp; // codestream components mapped to each channel + Guint *type; // 0 for direct use, 1 for palette mapping + Guint *pComp; // palette components to use +}; + +//------------------------------------------------------------------------ + +struct JPXChannelDefn { + Guint nChannels; // number of channels + Guint *idx; // channel indexes + Guint *type; // channel types + Guint *assoc; // channel associations +}; + +//------------------------------------------------------------------------ + +struct JPXTagTreeNode { + GBool finished; // true if this node is finished + Guint val; // current value +}; + +//------------------------------------------------------------------------ + +struct JPXCoeff { + Gushort flags; // flag bits + Gushort len; // number of significant bits in mag + Guint mag; // magnitude value +}; + +// coefficient flags +#define jpxCoeffSignificantB 0 +#define jpxCoeffTouchedB 1 +#define jpxCoeffFirstMagRefB 2 +#define jpxCoeffSignB 7 +#define jpxCoeffSignificant (1 << jpxCoeffSignificantB) +#define jpxCoeffTouched (1 << jpxCoeffTouchedB) +#define jpxCoeffFirstMagRef (1 << jpxCoeffFirstMagRefB) +#define jpxCoeffSign (1 << jpxCoeffSignB) + +//------------------------------------------------------------------------ + +struct JPXCodeBlock { + //----- size + Guint x0, y0, x1, y1; // bounds + + //----- persistent state + GBool seen; // true if this code-block has already + // been seen + Guint lBlock; // base number of bits used for pkt data length + Guint nextPass; // next coding pass + + //---- info from first packet + Guint nZeroBitPlanes; // number of zero bit planes + + //----- info for the current packet + Guint included; // code-block inclusion in this packet: + // 0=not included, 1=included + Guint nCodingPasses; // number of coding passes in this pkt + Guint dataLen; // pkt data length + + //----- coefficient data + JPXCoeff *coeffs; // the coefficients + JArithmeticDecoder // arithmetic decoder + *arithDecoder; + JArithmeticDecoderStats // arithmetic decoder stats + *stats; +}; + +//------------------------------------------------------------------------ + +struct JPXSubband { + //----- computed + Guint x0, y0, x1, y1; // bounds + Guint nXCBs, nYCBs; // number of code-blocks in the x and y + // directions + + //----- tag trees + Guint maxTTLevel; // max tag tree level + JPXTagTreeNode *inclusion; // inclusion tag tree for each subband + JPXTagTreeNode *zeroBitPlane; // zero-bit plane tag tree for each + // subband + + //----- children + JPXCodeBlock *cbs; // the code-blocks (len = nXCBs * nYCBs) +}; + +//------------------------------------------------------------------------ + +struct JPXPrecinct { + //----- computed + Guint x0, y0, x1, y1; // bounds of the precinct + + //----- children + JPXSubband *subbands; // the subbands +}; + +//------------------------------------------------------------------------ + +struct JPXResLevel { + //----- from the COD and COC segments (main and tile) + Guint precinctWidth; // log2(precinct width) + Guint precinctHeight; // log2(precinct height) + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile-comp (for this res level) + Guint bx0[3], by0[3], // subband bounds + bx1[3], by1[3]; + + //---- children + JPXPrecinct *precincts; // the precincts +}; + +//------------------------------------------------------------------------ + +struct JPXTileComp { + //----- from the SIZ segment + GBool sgned; // 1 for signed, 0 for unsigned + Guint prec; // precision, in bits + Guint hSep; // horizontal separation of samples + Guint vSep; // vertical separation of samples + + //----- from the COD and COC segments (main and tile) + Guint style; // coding style parameter (Scod / Scoc) + Guint nDecompLevels; // number of decomposition levels + Guint codeBlockW; // log2(code-block width) + Guint codeBlockH; // log2(code-block height) + Guint codeBlockStyle; // code-block style + Guint transform; // wavelet transformation + + //----- from the QCD and QCC segments (main and tile) + Guint quantStyle; // quantization style + Guint *quantSteps; // quantization step size for each subband + Guint nQuantSteps; // number of entries in quantSteps + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile-comp, in ref coords + Guint cbW; // code-block width + Guint cbH; // code-block height + + //----- image data + int *data; // the decoded image data + int *buf; // intermediate buffer for the inverse + // transform + + //----- children + JPXResLevel *resLevels; // the resolution levels + // (len = nDecompLevels + 1) +}; + +//------------------------------------------------------------------------ + +struct JPXTile { + //----- from the COD segments (main and tile) + Guint progOrder; // progression order + Guint nLayers; // number of layers + Guint multiComp; // multiple component transformation + + //----- computed + Guint x0, y0, x1, y1; // bounds of the tile, in ref coords + Guint maxNDecompLevels; // max number of decomposition levels used + // in any component in this tile + + //----- progression order loop counters + Guint comp; // component + Guint res; // resolution level + Guint precinct; // precinct + Guint layer; // layer + + //----- children + JPXTileComp *tileComps; // the tile-components (len = JPXImage.nComps) +}; + +//------------------------------------------------------------------------ + +struct JPXImage { + //----- from the SIZ segment + Guint xSize, ySize; // size of reference grid + Guint xOffset, yOffset; // image offset + Guint xTileSize, yTileSize; // size of tiles + Guint xTileOffset, // offset of first tile + yTileOffset; + Guint nComps; // number of components + + //----- computed + Guint nXTiles; // number of tiles in x direction + Guint nYTiles; // number of tiles in y direction + + //----- children + JPXTile *tiles; // the tiles (len = nXTiles * nYTiles) +}; + +//------------------------------------------------------------------------ + +class JPXStream: public FilterStream { +public: + + JPXStream(Stream *strA); + virtual ~JPXStream(); + virtual StreamKind getKind() { return strJPX; } + virtual void reset(); + virtual int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + virtual void getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode); + +private: + + void fillReadBuf(); + void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode); + GBool readBoxes(); + GBool readColorSpecBox(Guint dataLen); + GBool readCodestream(Guint len); + GBool readTilePart(); + GBool readTilePartData(Guint tileIdx, + Guint tilePartLen, GBool tilePartToEOC); + GBool readCodeBlockData(JPXTileComp *tileComp, + JPXResLevel *resLevel, + JPXPrecinct *precinct, + JPXSubband *subband, + Guint res, Guint sb, + JPXCodeBlock *cb); + void inverseTransform(JPXTileComp *tileComp); + void inverseTransformLevel(JPXTileComp *tileComp, + Guint r, JPXResLevel *resLevel, + Guint nx0, Guint ny0, + Guint nx1, Guint ny1); + void inverseTransform1D(JPXTileComp *tileComp, + int *data, Guint stride, + Guint i0, Guint i1); + GBool inverseMultiCompAndDC(JPXTile *tile); + GBool readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen); + int readMarkerHdr(int *segType, Guint *segLen); + GBool readUByte(Guint *x); + GBool readByte(int *x); + GBool readUWord(Guint *x); + GBool readULong(Guint *x); + GBool readNBytes(int nBytes, GBool signd, int *x); + GBool readBits(int nBits, Guint *x); + void clearBitBuf(); + + Guint nComps; // number of components + Guint *bpc; // bits per component, for each component + Guint width, height; // image size + GBool haveImgHdr; // set if a JP2/JPX image header has been + // found + JPXColorSpec cs; // color specification + GBool haveCS; // set if a color spec has been found + JPXPalette palette; // the palette + GBool havePalette; // set if a palette has been found + JPXCompMap compMap; // the component mapping + GBool haveCompMap; // set if a component mapping has been found + JPXChannelDefn channelDefn; // channel definition + GBool haveChannelDefn; // set if a channel defn has been found + + JPXImage img; // JPEG2000 decoder data + Guint bitBuf; // buffer for bit reads + int bitBufLen; // number of bits in bitBuf + GBool bitBufSkip; // true if next bit should be skipped + // (for bit stuffing) + Guint byteCount; // number of bytes read since last call + // to clearBitBuf + + Guint curX, curY, curComp; // current position for lookChar/getChar + Guint readBuf; // read buffer + Guint readBufLen; // number of valid bits in readBuf +}; + +#endif diff --git a/pdftops/Lexer.cxx b/pdftops/Lexer.cxx new file mode 100644 index 000000000..2bb0f50db --- /dev/null +++ b/pdftops/Lexer.cxx @@ -0,0 +1,485 @@ +//======================================================================== +// +// Lexer.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#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 (c == '-') { + // ignore minus signs in the middle of numbers to match + // Adobe's behavior + error(getPos(), "Badly formatted number"); + getChar(); + continue; + } + 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; + } + } +} + +GBool Lexer::isSpace(int c) { + return c >= 0 && c <= 0xff && specialChars[c] == 1; +} diff --git a/pdftops/Lexer.h b/pdftops/Lexer.h new file mode 100644 index 000000000..9ec2feb70 --- /dev/null +++ b/pdftops/Lexer.h @@ -0,0 +1,80 @@ +//======================================================================== +// +// Lexer.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef LEXER_H +#define LEXER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#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. This is only used for error + // messages, so it returns an int instead of a Guint. + int getPos() + { return curStr.isNone() ? -1 : (int)curStr.streamGetPos(); } + + // Set position in file. + void setPos(Guint pos, int dir = 0) + { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); } + + // Returns true if is a whitespace character. + static GBool isSpace(int c); + +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..de2bbf82e --- /dev/null +++ b/pdftops/Link.cxx @@ -0,0 +1,907 @@ +//======================================================================== +// +// Link.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "GString.h" +#include "Error.h" +#include "Object.h" +#include "Array.h" +#include "Dict.h" +#include "Link.h" + +//------------------------------------------------------------------------ +// LinkAction +//------------------------------------------------------------------------ + +LinkAction *LinkAction::parseDest(Object *obj) { + LinkAction *action; + + action = new LinkGoTo(obj); + if (!action->isOk()) { + delete action; + return NULL; + } + return action; +} + +LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) { + LinkAction *action; + Object obj2, obj3, obj4; + + if (!obj->isDict()) { + error(-1, "Bad annotation action"); + return NULL; + } + + obj->dictLookup("S", &obj2); + + // GoTo action + if (obj2.isName("GoTo")) { + obj->dictLookup("D", &obj3); + action = new LinkGoTo(&obj3); + obj3.free(); + + // GoToR action + } else if (obj2.isName("GoToR")) { + obj->dictLookup("F", &obj3); + obj->dictLookup("D", &obj4); + action = new LinkGoToR(&obj3, &obj4); + obj3.free(); + obj4.free(); + + // Launch action + } else if (obj2.isName("Launch")) { + action = new LinkLaunch(obj); + + // URI action + } else if (obj2.isName("URI")) { + obj->dictLookup("URI", &obj3); + action = new LinkURI(&obj3, baseURI); + obj3.free(); + + // Named action + } else if (obj2.isName("Named")) { + obj->dictLookup("N", &obj3); + action = new LinkNamed(&obj3); + obj3.free(); + + // Movie action + } else if (obj2.isName("Movie")) { + obj->dictLookupNF("Annot", &obj3); + obj->dictLookup("T", &obj4); + action = new LinkMovie(&obj3, &obj4); + obj3.free(); + obj4.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(); + + if (action && !action->isOk()) { + delete action; + return NULL; + } + return action; +} + +GString *LinkAction::getFileSpecName(Object *fileSpecObj) { + GString *name; + Object obj1; + + name = NULL; + + // string + if (fileSpecObj->isString()) { + name = fileSpecObj->getString()->copy(); + + // dictionary + } else if (fileSpecObj->isDict()) { +#ifdef WIN32 + if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) { +#else + if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { +#endif + 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"); + } + + // system-dependent path manipulation + if (name) { +#ifdef WIN32 + int i, j; + + // "//...." --> "\...." + // "/x/...." --> "x:\...." + // "/server/share/...." --> "\\server\share\...." + // convert escaped slashes to slashes and unescaped slashes to backslashes + i = 0; + if (name->getChar(0) == '/') { + if (name->getLength() >= 2 && name->getChar(1) == '/') { + name->del(0); + i = 0; + } else if (name->getLength() >= 2 && + ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') || + (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) && + (name->getLength() == 2 || name->getChar(2) == '/')) { + name->setChar(0, name->getChar(1)); + name->setChar(1, ':'); + i = 2; + } else { + for (j = 2; j < name->getLength(); ++j) { + if (name->getChar(j-1) != '\\' && + name->getChar(j) == '/') { + break; + } + } + if (j < name->getLength()) { + name->setChar(0, '\\'); + name->insert(0, '\\'); + i = 2; + } + } + } + for (; i < name->getLength(); ++i) { + if (name->getChar(i) == '/') { + name->setChar(i, '\\'); + } else if (name->getChar(i) == '\\' && + i+1 < name->getLength() && + name->getChar(i+1) == '/') { + name->del(i); + } + } +#else + // no manipulation needed for Unix +#endif + } + + return name; +} + +//------------------------------------------------------------------------ +// LinkDest +//------------------------------------------------------------------------ + +LinkDest::LinkDest(Array *a) { + Object obj1, obj2; + + // initialize fields + left = bottom = right = top = zoom = 0; + ok = gFalse; + + // get page + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + return; + } + a->getNF(0, &obj1); + if (obj1.isInt()) { + pageNum = obj1.getInt() + 1; + pageIsRef = gFalse; + } else if (obj1.isRef()) { + pageRef.num = obj1.getRefNum(); + pageRef.gen = obj1.getRefGen(); + pageIsRef = gTrue; + } else { + error(-1, "Bad annotation destination"); + goto err2; + } + obj1.free(); + + // get destination type + a->get(1, &obj1); + + // XYZ link + if (obj1.isName("XYZ")) { + kind = destXYZ; + if (a->getLength() < 3) { + changeLeft = gFalse; + } else { + 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(); + } + if (a->getLength() < 4) { + changeTop = gFalse; + } else { + 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(); + } + if (a->getLength() < 5) { + changeZoom = gFalse; + } else { + 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")) { + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFit; + + // FitH link + } else if (obj1.isName("FitH")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + 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")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + 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")) { + if (a->getLength() < 6) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + 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")) { + if (a->getLength() < 2) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + kind = destFitB; + + // FitBH link + } else if (obj1.isName("FitBH")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + 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")) { + if (a->getLength() < 3) { + error(-1, "Annotation destination array is too short"); + goto err2; + } + 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()); + 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()); + 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(); +#ifdef WIN32 + if (actionObj->dictLookup("Win", &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"); + } +#else + //~ 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"); + } +#endif + } + 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 && baseURI->getLength() > 0) { + 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; + } +} + +//------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) { + annotRef.num = -1; + title = NULL; + if (annotObj->isRef()) { + annotRef = annotObj->getRef(); + } else if (titleObj->isString()) { + title = titleObj->getString()->copy(); + } else { + error(-1, "Movie action is missing both the Annot and T keys"); + } +} + +LinkMovie::~LinkMovie() { + if (title) { + delete title; + } +} + +//------------------------------------------------------------------------ +// LinkUnknown +//------------------------------------------------------------------------ + +LinkUnknown::LinkUnknown(char *actionA) { + action = new GString(actionA); +} + +LinkUnknown::~LinkUnknown() { + delete action; +} + +//------------------------------------------------------------------------ +// LinkBorderStyle +//------------------------------------------------------------------------ + +LinkBorderStyle::LinkBorderStyle(LinkBorderType typeA, double widthA, + double *dashA, int dashLengthA, + double rA, double gA, double bA) { + type = typeA; + width = widthA; + dash = dashA; + dashLength = dashLengthA; + r = rA; + g = gA; + b = bA; +} + +LinkBorderStyle::~LinkBorderStyle() { + if (dash) { + gfree(dash); + } +} + +//------------------------------------------------------------------------ +// Link +//------------------------------------------------------------------------ + +Link::Link(Dict *dict, GString *baseURI) { + Object obj1, obj2, obj3; + LinkBorderType borderType; + double borderWidth; + double *borderDash; + int borderDashLength; + double borderR, borderG, borderB; + double t; + int i; + + borderStyle = NULL; + 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 the border style info + borderType = linkBorderSolid; + borderWidth = 1; + borderDash = NULL; + borderDashLength = 0; + borderR = 0; + borderG = 0; + borderB = 1; + if (dict->lookup("BS", &obj1)->isDict()) { + if (obj1.dictLookup("S", &obj2)->isName()) { + if (obj2.isName("S")) { + borderType = linkBorderSolid; + } else if (obj2.isName("D")) { + borderType = linkBorderDashed; + } else if (obj2.isName("B")) { + borderType = linkBorderEmbossed; + } else if (obj2.isName("I")) { + borderType = linkBorderEngraved; + } else if (obj2.isName("U")) { + borderType = linkBorderUnderlined; + } + } + obj2.free(); + if (obj1.dictLookup("W", &obj2)->isNum()) { + borderWidth = obj2.getNum(); + } + obj2.free(); + if (obj1.dictLookup("D", &obj2)->isArray()) { + borderDashLength = obj2.arrayGetLength(); + borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); + for (i = 0; i < borderDashLength; ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + borderDash[i] = obj3.getNum(); + } else { + borderDash[i] = 1; + } + obj3.free(); + } + } + obj2.free(); + } else { + obj1.free(); + if (dict->lookup("Border", &obj1)->isArray()) { + if (obj1.arrayGetLength() >= 3) { + if (obj1.arrayGet(2, &obj2)->isNum()) { + borderWidth = obj2.getNum(); + } + obj2.free(); + if (obj1.arrayGetLength() >= 4) { + if (obj1.arrayGet(3, &obj2)->isArray()) { + borderType = linkBorderDashed; + borderDashLength = obj2.arrayGetLength(); + borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); + for (i = 0; i < borderDashLength; ++i) { + if (obj2.arrayGet(i, &obj3)->isNum()) { + borderDash[i] = obj3.getNum(); + } else { + borderDash[i] = 1; + } + obj3.free(); + } + } else { + // Adobe draws no border at all if the last element is of + // the wrong type. + borderWidth = 0; + } + obj2.free(); + } + } + } + } + obj1.free(); + if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) { + if (obj1.arrayGet(0, &obj2)->isNum()) { + borderR = obj2.getNum(); + } + obj1.free(); + if (obj1.arrayGet(1, &obj2)->isNum()) { + borderG = obj2.getNum(); + } + obj1.free(); + if (obj1.arrayGet(2, &obj2)->isNum()) { + borderB = obj2.getNum(); + } + obj1.free(); + } + obj1.free(); + borderStyle = new LinkBorderStyle(borderType, borderWidth, + borderDash, borderDashLength, + borderR, borderG, borderB); + + // look for destination + if (!dict->lookup("Dest", &obj1)->isNull()) { + action = LinkAction::parseDest(&obj1); + + // look for action + } else { + obj1.free(); + if (dict->lookup("A", &obj1)->isDict()) { + action = LinkAction::parseAction(&obj1, baseURI); + } + } + obj1.free(); + + // check for bad action + if (action) { + ok = gTrue; + } + + return; + + err1: + obj2.free(); + err2: + obj1.free(); +} + +Link::~Link() { + if (borderStyle) { + delete borderStyle; + } + 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 **)greallocn(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 = numLinks - 1; i >= 0; --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; +} diff --git a/pdftops/Link.h b/pdftops/Link.h new file mode 100644 index 000000000..160b2b8cb --- /dev/null +++ b/pdftops/Link.h @@ -0,0 +1,409 @@ +//======================================================================== +// +// Link.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef LINK_H +#define LINK_H + +#include + +#ifdef USE_GCC_PRAGMAS +#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 + actionMovie, // movie 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; + + // Parse a destination (old-style action) name, string, or array. + static LinkAction *parseDest(Object *obj); + + // Parse an action dictionary. + static LinkAction *parseAction(Object *obj, GString *baseURI = NULL); + + // Extract a file name from a file specification (string or + // dictionary). + static GString *getFileSpecName(Object *fileSpecObj); +}; + +//------------------------------------------------------------------------ +// LinkDest +//------------------------------------------------------------------------ + +enum LinkDestKind { + destXYZ, + destFit, + destFitH, + destFitV, + destFitR, + destFitB, + destFitBH, + destFitBV +}; + +class LinkDest { +public: + + // Build a LinkDest from the array. + LinkDest(Array *a); + + // 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; +}; + +//------------------------------------------------------------------------ +// LinkMovie +//------------------------------------------------------------------------ + +class LinkMovie: public LinkAction { +public: + + LinkMovie(Object *annotObj, Object *titleObj); + + virtual ~LinkMovie(); + + virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; } + + virtual LinkActionKind getKind() { return actionMovie; } + GBool hasAnnotRef() { return annotRef.num >= 0; } + Ref *getAnnotRef() { return &annotRef; } + GString *getTitle() { return title; } + +private: + + Ref annotRef; + GString *title; +}; + +//------------------------------------------------------------------------ +// 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 +}; + +//------------------------------------------------------------------------ +// LinkBorderStyle +//------------------------------------------------------------------------ + +enum LinkBorderType { + linkBorderSolid, + linkBorderDashed, + linkBorderEmbossed, + linkBorderEngraved, + linkBorderUnderlined +}; + +class LinkBorderStyle { +public: + + LinkBorderStyle(LinkBorderType typeA, double widthA, + double *dashA, int dashLengthA, + double rA, double gA, double bA); + ~LinkBorderStyle(); + + LinkBorderType getType() { return type; } + double getWidth() { return width; } + void getDash(double **dashA, int *dashLengthA) + { *dashA = dash; *dashLengthA = dashLength; } + void getColor(double *rA, double *gA, double *bA) + { *rA = r; *gA = g; *bA = b; } + +private: + + LinkBorderType type; + double width; + double *dash; + int dashLength; + double r, g, b; +}; + +//------------------------------------------------------------------------ +// 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 the link rectangle. + void getRect(double *xa1, double *ya1, double *xa2, double *ya2) + { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } + + // Get the border style info. + LinkBorderStyle *getBorderStyle() { return borderStyle; } + +private: + + double x1, y1; // lower left corner + double x2, y2; // upper right corner + LinkBorderStyle *borderStyle; // border style + 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 , is in a link, return the associated action; + // else return NULL. + LinkAction *find(double x, double y); + + // Return true if , 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..352f89510 --- /dev/null +++ b/pdftops/Makefile @@ -0,0 +1,158 @@ +# +# "$Id: Makefile 4494 2005-02-18 02:18:11Z mike $" +# +# pdftops filter Makefile for the Common UNIX Printing System (CUPS). +# +# CUPS filter changes Copyright 1997-2005 by Easy Software Products. +# Xpdf code Copyright 1996-1999 by Derek B. Noonburg +# + + +include ../Makedefs + +# +# Object files... +# + +LIBOBJS = \ + Annot.o \ + Array.o \ + BuiltinFont.o \ + BuiltinFontTables.o \ + Catalog.o \ + CharCodeToUnicode.o \ + CMap.o \ + Decrypt.o \ + Dict.o \ + Error.o \ + FoFiBase.o \ + FoFiEncodings.o \ + FoFiTrueType.o \ + FoFiType1C.o \ + FoFiType1.o \ + FontEncodingTables.o \ + Function.o \ + gfile.o \ + Gfx.o \ + GfxFont.o \ + GfxState.o \ + GHash.o \ + GList.o \ + GlobalParams.o \ + gmem.o \ + gmempp.o \ + GString.o \ + JArithmeticDecoder.o \ + JBIG2Stream.o \ + JPXStream.o \ + Lexer.o \ + Link.o \ + NameToCharCode.o \ + Object.o \ + Outline.o \ + OutputDev.o \ + Page.o \ + parseargs.o \ + Parser.o \ + PDFDoc.o \ + PDFDocEncoding.o \ + PSOutputDev.o \ + PSTokenizer.o \ + SecurityHandler.o \ + SplashBitmap.o \ + SplashClip.o \ + Splash.o \ + SplashFont.o \ + SplashFontEngine.o \ + SplashFontFile.o \ + SplashFontFileID.o \ + SplashFTFont.o \ + SplashFTFontEngine.o \ + SplashFTFontFile.o \ + SplashOutputDev.o \ + SplashPath.o \ + SplashPattern.o \ + SplashScreen.o \ + SplashState.o \ + SplashT1Font.o \ + SplashT1FontEngine.o \ + SplashT1FontFile.o \ + SplashXPath.o \ + SplashXPathScanner.o \ + Stream.o \ + UnicodeMap.o \ + UnicodeTypeTable.o \ + XpdfPluginAPI.o \ + XRef.o + + +OBJS = pdftops.o $(LIBOBJS) + +TARGETS = libxpdf.a pdftops + + +# +# Make everything... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) + $(RM) libxpdf.a + $(RM) pdftops + $(RM) pdftoraster + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies $(OBJS:.o=.cxx) gmem.c parseargs.c >/dev/null 2>&1 + + +# +# Install the filter... +# + +install: all + $(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) $(CXXLIBS) -lm + + +# +# libxpdf.a +# + +libxpdf.a: $(LIBOBJS) + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(LIBOBJS) + $(RANLIB) $@ + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/pdftops/NameToCharCode.cxx b/pdftops/NameToCharCode.cxx new file mode 100644 index 000000000..a3ef99977 --- /dev/null +++ b/pdftops/NameToCharCode.cxx @@ -0,0 +1,116 @@ +//======================================================================== +// +// NameToCharCode.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "NameToCharCode.h" + +//------------------------------------------------------------------------ + +struct NameToCharCodeEntry { + char *name; + CharCode c; +}; + +//------------------------------------------------------------------------ + +NameToCharCode::NameToCharCode() { + int i; + + size = 31; + len = 0; + tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); + for (i = 0; i < size; ++i) { + tab[i].name = NULL; + } +} + +NameToCharCode::~NameToCharCode() { + int i; + + for (i = 0; i < size; ++i) { + if (tab[i].name) { + gfree(tab[i].name); + } + } + gfree(tab); +} + +void NameToCharCode::add(char *name, CharCode c) { + NameToCharCodeEntry *oldTab; + int h, i, oldSize; + + // expand the table if necessary + if (len >= size / 2) { + oldSize = size; + oldTab = tab; + size = 2*size + 1; + tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); + for (h = 0; h < size; ++h) { + tab[h].name = NULL; + } + for (i = 0; i < oldSize; ++i) { + if (oldTab[i].name) { + h = hash(oldTab[i].name); + while (tab[h].name) { + if (++h == size) { + h = 0; + } + } + tab[h] = oldTab[i]; + } + } + gfree(oldTab); + } + + // add the new name + h = hash(name); + while (tab[h].name && strcmp(tab[h].name, name)) { + if (++h == size) { + h = 0; + } + } + if (!tab[h].name) { + tab[h].name = copyString(name); + } + tab[h].c = c; + + ++len; +} + +CharCode NameToCharCode::lookup(char *name) { + int h; + + h = hash(name); + while (tab[h].name) { + if (!strcmp(tab[h].name, name)) { + return tab[h].c; + } + if (++h == size) { + h = 0; + } + } + return 0; +} + +int NameToCharCode::hash(char *name) { + char *p; + unsigned int h; + + h = 0; + for (p = name; *p; ++p) { + h = 17 * h + (int)(*p & 0xff); + } + return (int)(h % size); +} diff --git a/pdftops/NameToCharCode.h b/pdftops/NameToCharCode.h new file mode 100644 index 000000000..30147fb07 --- /dev/null +++ b/pdftops/NameToCharCode.h @@ -0,0 +1,42 @@ +//======================================================================== +// +// NameToCharCode.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef NAMETOCHARCODE_H +#define NAMETOCHARCODE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "CharTypes.h" + +struct NameToCharCodeEntry; + +//------------------------------------------------------------------------ + +class NameToCharCode { +public: + + NameToCharCode(); + ~NameToCharCode(); + + void add(char *name, CharCode c); + CharCode lookup(char *name); + +private: + + int hash(char *name); + + NameToCharCodeEntry *tab; + int size; + int len; +}; + +#endif diff --git a/pdftops/NameToUnicodeTable.h b/pdftops/NameToUnicodeTable.h new file mode 100644 index 000000000..0b1812c0c --- /dev/null +++ b/pdftops/NameToUnicodeTable.h @@ -0,0 +1,1097 @@ +//======================================================================== +// +// NameToUnicodeTable.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +static struct { + Unicode u; + char *name; +} nameToUnicodeTab[] = { + {0x0021, "!"}, + {0x0023, "#"}, + {0x0024, "$"}, + {0x0025, "%"}, + {0x0026, "&"}, + {0x0027, "'"}, + {0x0028, "("}, + {0x0029, ")"}, + {0x002a, "*"}, + {0x002b, "+"}, + {0x002c, ","}, + {0x002d, "-"}, + {0x002e, "."}, + {0x002f, "/"}, + {0x0030, "0"}, + {0x0031, "1"}, + {0x0032, "2"}, + {0x0033, "3"}, + {0x0034, "4"}, + {0x0035, "5"}, + {0x0036, "6"}, + {0x0037, "7"}, + {0x0038, "8"}, + {0x0039, "9"}, + {0x003a, ":"}, + {0x003b, ";"}, + {0x003c, "<"}, + {0x003d, "="}, + {0x003e, ">"}, + {0x003f, "?"}, + {0x0040, "@"}, + {0x0041, "A"}, + {0x00c6, "AE"}, + {0x01fc, "AEacute"}, + {0xf7e6, "AEsmall"}, + {0x00c1, "Aacute"}, + {0xf7e1, "Aacutesmall"}, + {0x0102, "Abreve"}, + {0x00c2, "Acircumflex"}, + {0xf7e2, "Acircumflexsmall"}, + {0xf6c9, "Acute"}, + {0xf7b4, "Acutesmall"}, + {0x00c4, "Adieresis"}, + {0xf7e4, "Adieresissmall"}, + {0x00c0, "Agrave"}, + {0xf7e0, "Agravesmall"}, + {0x0391, "Alpha"}, + {0x0386, "Alphatonos"}, + {0x0100, "Amacron"}, + {0x0104, "Aogonek"}, + {0x00c5, "Aring"}, + {0x01fa, "Aringacute"}, + {0xf7e5, "Aringsmall"}, + {0xf761, "Asmall"}, + {0x00c3, "Atilde"}, + {0xf7e3, "Atildesmall"}, + {0x0042, "B"}, + {0x0392, "Beta"}, + {0xf6f4, "Brevesmall"}, + {0xf762, "Bsmall"}, + {0x0043, "C"}, + {0x0106, "Cacute"}, + {0xf6ca, "Caron"}, + {0xf6f5, "Caronsmall"}, + {0x010c, "Ccaron"}, + {0x00c7, "Ccedilla"}, + {0xf7e7, "Ccedillasmall"}, + {0x0108, "Ccircumflex"}, + {0x010a, "Cdotaccent"}, + {0xf7b8, "Cedillasmall"}, + {0x03a7, "Chi"}, + {0xf6f6, "Circumflexsmall"}, + {0xf763, "Csmall"}, + {0x0044, "D"}, + {0x010e, "Dcaron"}, + {0x0110, "Dcroat"}, + {0x2206, "Delta"}, + {0xf6cb, "Dieresis"}, + {0xf6cc, "DieresisAcute"}, + {0xf6cd, "DieresisGrave"}, + {0xf7a8, "Dieresissmall"}, + {0xf6f7, "Dotaccentsmall"}, + {0xf764, "Dsmall"}, + {0x0045, "E"}, + {0x00c9, "Eacute"}, + {0xf7e9, "Eacutesmall"}, + {0x0114, "Ebreve"}, + {0x011a, "Ecaron"}, + {0x00ca, "Ecircumflex"}, + {0xf7ea, "Ecircumflexsmall"}, + {0x00cb, "Edieresis"}, + {0xf7eb, "Edieresissmall"}, + {0x0116, "Edotaccent"}, + {0x00c8, "Egrave"}, + {0xf7e8, "Egravesmall"}, + {0x0112, "Emacron"}, + {0x014a, "Eng"}, + {0x0118, "Eogonek"}, + {0x0395, "Epsilon"}, + {0x0388, "Epsilontonos"}, + {0xf765, "Esmall"}, + {0x0397, "Eta"}, + {0x0389, "Etatonos"}, + {0x00d0, "Eth"}, + {0xf7f0, "Ethsmall"}, + {0x20ac, "Euro"}, + {0x0046, "F"}, + {0xf766, "Fsmall"}, + {0x0047, "G"}, + {0x0393, "Gamma"}, + {0x011e, "Gbreve"}, + {0x01e6, "Gcaron"}, + {0x011c, "Gcircumflex"}, + {0x0122, "Gcommaaccent"}, + {0x0120, "Gdotaccent"}, + {0xf6ce, "Grave"}, + {0xf760, "Gravesmall"}, + {0xf767, "Gsmall"}, + {0x0048, "H"}, + {0x25cf, "H18533"}, + {0x25aa, "H18543"}, + {0x25ab, "H18551"}, + {0x25a1, "H22073"}, + {0x0126, "Hbar"}, + {0x0124, "Hcircumflex"}, + {0xf768, "Hsmall"}, + {0xf6cf, "Hungarumlaut"}, + {0xf6f8, "Hungarumlautsmall"}, + {0x0049, "I"}, + {0x0132, "IJ"}, + {0x00cd, "Iacute"}, + {0xf7ed, "Iacutesmall"}, + {0x012c, "Ibreve"}, + {0x00ce, "Icircumflex"}, + {0xf7ee, "Icircumflexsmall"}, + {0x00cf, "Idieresis"}, + {0xf7ef, "Idieresissmall"}, + {0x0130, "Idotaccent"}, + {0x2111, "Ifraktur"}, + {0x00cc, "Igrave"}, + {0xf7ec, "Igravesmall"}, + {0x012a, "Imacron"}, + {0x012e, "Iogonek"}, + {0x0399, "Iota"}, + {0x03aa, "Iotadieresis"}, + {0x038a, "Iotatonos"}, + {0xf769, "Ismall"}, + {0x0128, "Itilde"}, + {0x004a, "J"}, + {0x0134, "Jcircumflex"}, + {0xf76a, "Jsmall"}, + {0x004b, "K"}, + {0x039a, "Kappa"}, + {0x0136, "Kcommaaccent"}, + {0xf76b, "Ksmall"}, + {0x004c, "L"}, + {0xf6bf, "LL"}, + {0x0139, "Lacute"}, + {0x039b, "Lambda"}, + {0x013d, "Lcaron"}, + {0x013b, "Lcommaaccent"}, + {0x013f, "Ldot"}, + {0x0141, "Lslash"}, + {0xf6f9, "Lslashsmall"}, + {0xf76c, "Lsmall"}, + {0x004d, "M"}, + {0xf6d0, "Macron"}, + {0xf7af, "Macronsmall"}, + {0xf76d, "Msmall"}, + {0x039c, "Mu"}, + {0x004e, "N"}, + {0x0143, "Nacute"}, + {0x0147, "Ncaron"}, + {0x0145, "Ncommaaccent"}, + {0xf76e, "Nsmall"}, + {0x00d1, "Ntilde"}, + {0xf7f1, "Ntildesmall"}, + {0x039d, "Nu"}, + {0x004f, "O"}, + {0x0152, "OE"}, + {0xf6fa, "OEsmall"}, + {0x00d3, "Oacute"}, + {0xf7f3, "Oacutesmall"}, + {0x014e, "Obreve"}, + {0x00d4, "Ocircumflex"}, + {0xf7f4, "Ocircumflexsmall"}, + {0x00d6, "Odieresis"}, + {0xf7f6, "Odieresissmall"}, + {0xf6fb, "Ogoneksmall"}, + {0x00d2, "Ograve"}, + {0xf7f2, "Ogravesmall"}, + {0x01a0, "Ohorn"}, + {0x0150, "Ohungarumlaut"}, + {0x014c, "Omacron"}, + {0x2126, "Omega"}, + {0x038f, "Omegatonos"}, + {0x039f, "Omicron"}, + {0x038c, "Omicrontonos"}, + {0x00d8, "Oslash"}, + {0x01fe, "Oslashacute"}, + {0xf7f8, "Oslashsmall"}, + {0xf76f, "Osmall"}, + {0x00d5, "Otilde"}, + {0xf7f5, "Otildesmall"}, + {0x0050, "P"}, + {0x03a6, "Phi"}, + {0x03a0, "Pi"}, + {0x03a8, "Psi"}, + {0xf770, "Psmall"}, + {0x0051, "Q"}, + {0xf771, "Qsmall"}, + {0x0052, "R"}, + {0x0154, "Racute"}, + {0x0158, "Rcaron"}, + {0x0156, "Rcommaaccent"}, + {0x211c, "Rfraktur"}, + {0x03a1, "Rho"}, + {0xf6fc, "Ringsmall"}, + {0xf772, "Rsmall"}, + {0x0053, "S"}, + {0x250c, "SF010000"}, + {0x2514, "SF020000"}, + {0x2510, "SF030000"}, + {0x2518, "SF040000"}, + {0x253c, "SF050000"}, + {0x252c, "SF060000"}, + {0x2534, "SF070000"}, + {0x251c, "SF080000"}, + {0x2524, "SF090000"}, + {0x2500, "SF100000"}, + {0x2502, "SF110000"}, + {0x2561, "SF190000"}, + {0x2562, "SF200000"}, + {0x2556, "SF210000"}, + {0x2555, "SF220000"}, + {0x2563, "SF230000"}, + {0x2551, "SF240000"}, + {0x2557, "SF250000"}, + {0x255d, "SF260000"}, + {0x255c, "SF270000"}, + {0x255b, "SF280000"}, + {0x255e, "SF360000"}, + {0x255f, "SF370000"}, + {0x255a, "SF380000"}, + {0x2554, "SF390000"}, + {0x2569, "SF400000"}, + {0x2566, "SF410000"}, + {0x2560, "SF420000"}, + {0x2550, "SF430000"}, + {0x256c, "SF440000"}, + {0x2567, "SF450000"}, + {0x2568, "SF460000"}, + {0x2564, "SF470000"}, + {0x2565, "SF480000"}, + {0x2559, "SF490000"}, + {0x2558, "SF500000"}, + {0x2552, "SF510000"}, + {0x2553, "SF520000"}, + {0x256b, "SF530000"}, + {0x256a, "SF540000"}, + {0x015a, "Sacute"}, + {0x0160, "Scaron"}, + {0xf6fd, "Scaronsmall"}, + {0x015e, "Scedilla"}, + {0x015c, "Scircumflex"}, + {0x0218, "Scommaaccent"}, + {0x03a3, "Sigma"}, + {0xf773, "Ssmall"}, + {0x0054, "T"}, + {0x03a4, "Tau"}, + {0x0166, "Tbar"}, + {0x0164, "Tcaron"}, + {0x0162, "Tcommaaccent"}, + {0x0398, "Theta"}, + {0x00de, "Thorn"}, + {0xf7fe, "Thornsmall"}, + {0xf6fe, "Tildesmall"}, + {0xf774, "Tsmall"}, + {0x0055, "U"}, + {0x00da, "Uacute"}, + {0xf7fa, "Uacutesmall"}, + {0x016c, "Ubreve"}, + {0x00db, "Ucircumflex"}, + {0xf7fb, "Ucircumflexsmall"}, + {0x00dc, "Udieresis"}, + {0xf7fc, "Udieresissmall"}, + {0x00d9, "Ugrave"}, + {0xf7f9, "Ugravesmall"}, + {0x01af, "Uhorn"}, + {0x0170, "Uhungarumlaut"}, + {0x016a, "Umacron"}, + {0x0172, "Uogonek"}, + {0x03a5, "Upsilon"}, + {0x03d2, "Upsilon1"}, + {0x03ab, "Upsilondieresis"}, + {0x038e, "Upsilontonos"}, + {0x016e, "Uring"}, + {0xf775, "Usmall"}, + {0x0168, "Utilde"}, + {0x0056, "V"}, + {0xf776, "Vsmall"}, + {0x0057, "W"}, + {0x1e82, "Wacute"}, + {0x0174, "Wcircumflex"}, + {0x1e84, "Wdieresis"}, + {0x1e80, "Wgrave"}, + {0xf777, "Wsmall"}, + {0x0058, "X"}, + {0x039e, "Xi"}, + {0xf778, "Xsmall"}, + {0x0059, "Y"}, + {0x00dd, "Yacute"}, + {0xf7fd, "Yacutesmall"}, + {0x0176, "Ycircumflex"}, + {0x0178, "Ydieresis"}, + {0xf7ff, "Ydieresissmall"}, + {0x1ef2, "Ygrave"}, + {0xf779, "Ysmall"}, + {0x005a, "Z"}, + {0x0179, "Zacute"}, + {0x017d, "Zcaron"}, + {0xf6ff, "Zcaronsmall"}, + {0x017b, "Zdotaccent"}, + {0x0396, "Zeta"}, + {0xf77a, "Zsmall"}, + {0x0022, "\""}, + {0x005c, "\\"}, + {0x005d, "]"}, + {0x005e, "^"}, + {0x005f, "_"}, + {0x0060, "`"}, + {0x0061, "a"}, + {0x00e1, "aacute"}, + {0x0103, "abreve"}, + {0x00e2, "acircumflex"}, + {0x00b4, "acute"}, + {0x0301, "acutecomb"}, + {0x00e4, "adieresis"}, + {0x00e6, "ae"}, + {0x01fd, "aeacute"}, + {0x2015, "afii00208"}, + {0x0410, "afii10017"}, + {0x0411, "afii10018"}, + {0x0412, "afii10019"}, + {0x0413, "afii10020"}, + {0x0414, "afii10021"}, + {0x0415, "afii10022"}, + {0x0401, "afii10023"}, + {0x0416, "afii10024"}, + {0x0417, "afii10025"}, + {0x0418, "afii10026"}, + {0x0419, "afii10027"}, + {0x041a, "afii10028"}, + {0x041b, "afii10029"}, + {0x041c, "afii10030"}, + {0x041d, "afii10031"}, + {0x041e, "afii10032"}, + {0x041f, "afii10033"}, + {0x0420, "afii10034"}, + {0x0421, "afii10035"}, + {0x0422, "afii10036"}, + {0x0423, "afii10037"}, + {0x0424, "afii10038"}, + {0x0425, "afii10039"}, + {0x0426, "afii10040"}, + {0x0427, "afii10041"}, + {0x0428, "afii10042"}, + {0x0429, "afii10043"}, + {0x042a, "afii10044"}, + {0x042b, "afii10045"}, + {0x042c, "afii10046"}, + {0x042d, "afii10047"}, + {0x042e, "afii10048"}, + {0x042f, "afii10049"}, + {0x0490, "afii10050"}, + {0x0402, "afii10051"}, + {0x0403, "afii10052"}, + {0x0404, "afii10053"}, + {0x0405, "afii10054"}, + {0x0406, "afii10055"}, + {0x0407, "afii10056"}, + {0x0408, "afii10057"}, + {0x0409, "afii10058"}, + {0x040a, "afii10059"}, + {0x040b, "afii10060"}, + {0x040c, "afii10061"}, + {0x040e, "afii10062"}, + {0xf6c4, "afii10063"}, + {0xf6c5, "afii10064"}, + {0x0430, "afii10065"}, + {0x0431, "afii10066"}, + {0x0432, "afii10067"}, + {0x0433, "afii10068"}, + {0x0434, "afii10069"}, + {0x0435, "afii10070"}, + {0x0451, "afii10071"}, + {0x0436, "afii10072"}, + {0x0437, "afii10073"}, + {0x0438, "afii10074"}, + {0x0439, "afii10075"}, + {0x043a, "afii10076"}, + {0x043b, "afii10077"}, + {0x043c, "afii10078"}, + {0x043d, "afii10079"}, + {0x043e, "afii10080"}, + {0x043f, "afii10081"}, + {0x0440, "afii10082"}, + {0x0441, "afii10083"}, + {0x0442, "afii10084"}, + {0x0443, "afii10085"}, + {0x0444, "afii10086"}, + {0x0445, "afii10087"}, + {0x0446, "afii10088"}, + {0x0447, "afii10089"}, + {0x0448, "afii10090"}, + {0x0449, "afii10091"}, + {0x044a, "afii10092"}, + {0x044b, "afii10093"}, + {0x044c, "afii10094"}, + {0x044d, "afii10095"}, + {0x044e, "afii10096"}, + {0x044f, "afii10097"}, + {0x0491, "afii10098"}, + {0x0452, "afii10099"}, + {0x0453, "afii10100"}, + {0x0454, "afii10101"}, + {0x0455, "afii10102"}, + {0x0456, "afii10103"}, + {0x0457, "afii10104"}, + {0x0458, "afii10105"}, + {0x0459, "afii10106"}, + {0x045a, "afii10107"}, + {0x045b, "afii10108"}, + {0x045c, "afii10109"}, + {0x045e, "afii10110"}, + {0x040f, "afii10145"}, + {0x0462, "afii10146"}, + {0x0472, "afii10147"}, + {0x0474, "afii10148"}, + {0xf6c6, "afii10192"}, + {0x045f, "afii10193"}, + {0x0463, "afii10194"}, + {0x0473, "afii10195"}, + {0x0475, "afii10196"}, + {0xf6c7, "afii10831"}, + {0xf6c8, "afii10832"}, + {0x04d9, "afii10846"}, + {0x200e, "afii299"}, + {0x200f, "afii300"}, + {0x200d, "afii301"}, + {0x066a, "afii57381"}, + {0x060c, "afii57388"}, + {0x0660, "afii57392"}, + {0x0661, "afii57393"}, + {0x0662, "afii57394"}, + {0x0663, "afii57395"}, + {0x0664, "afii57396"}, + {0x0665, "afii57397"}, + {0x0666, "afii57398"}, + {0x0667, "afii57399"}, + {0x0668, "afii57400"}, + {0x0669, "afii57401"}, + {0x061b, "afii57403"}, + {0x061f, "afii57407"}, + {0x0621, "afii57409"}, + {0x0622, "afii57410"}, + {0x0623, "afii57411"}, + {0x0624, "afii57412"}, + {0x0625, "afii57413"}, + {0x0626, "afii57414"}, + {0x0627, "afii57415"}, + {0x0628, "afii57416"}, + {0x0629, "afii57417"}, + {0x062a, "afii57418"}, + {0x062b, "afii57419"}, + {0x062c, "afii57420"}, + {0x062d, "afii57421"}, + {0x062e, "afii57422"}, + {0x062f, "afii57423"}, + {0x0630, "afii57424"}, + {0x0631, "afii57425"}, + {0x0632, "afii57426"}, + {0x0633, "afii57427"}, + {0x0634, "afii57428"}, + {0x0635, "afii57429"}, + {0x0636, "afii57430"}, + {0x0637, "afii57431"}, + {0x0638, "afii57432"}, + {0x0639, "afii57433"}, + {0x063a, "afii57434"}, + {0x0640, "afii57440"}, + {0x0641, "afii57441"}, + {0x0642, "afii57442"}, + {0x0643, "afii57443"}, + {0x0644, "afii57444"}, + {0x0645, "afii57445"}, + {0x0646, "afii57446"}, + {0x0648, "afii57448"}, + {0x0649, "afii57449"}, + {0x064a, "afii57450"}, + {0x064b, "afii57451"}, + {0x064c, "afii57452"}, + {0x064d, "afii57453"}, + {0x064e, "afii57454"}, + {0x064f, "afii57455"}, + {0x0650, "afii57456"}, + {0x0651, "afii57457"}, + {0x0652, "afii57458"}, + {0x0647, "afii57470"}, + {0x06a4, "afii57505"}, + {0x067e, "afii57506"}, + {0x0686, "afii57507"}, + {0x0698, "afii57508"}, + {0x06af, "afii57509"}, + {0x0679, "afii57511"}, + {0x0688, "afii57512"}, + {0x0691, "afii57513"}, + {0x06ba, "afii57514"}, + {0x06d2, "afii57519"}, + {0x06d5, "afii57534"}, + {0x20aa, "afii57636"}, + {0x05be, "afii57645"}, + {0x05c3, "afii57658"}, + {0x05d0, "afii57664"}, + {0x05d1, "afii57665"}, + {0x05d2, "afii57666"}, + {0x05d3, "afii57667"}, + {0x05d4, "afii57668"}, + {0x05d5, "afii57669"}, + {0x05d6, "afii57670"}, + {0x05d7, "afii57671"}, + {0x05d8, "afii57672"}, + {0x05d9, "afii57673"}, + {0x05da, "afii57674"}, + {0x05db, "afii57675"}, + {0x05dc, "afii57676"}, + {0x05dd, "afii57677"}, + {0x05de, "afii57678"}, + {0x05df, "afii57679"}, + {0x05e0, "afii57680"}, + {0x05e1, "afii57681"}, + {0x05e2, "afii57682"}, + {0x05e3, "afii57683"}, + {0x05e4, "afii57684"}, + {0x05e5, "afii57685"}, + {0x05e6, "afii57686"}, + {0x05e7, "afii57687"}, + {0x05e8, "afii57688"}, + {0x05e9, "afii57689"}, + {0x05ea, "afii57690"}, + {0xfb2a, "afii57694"}, + {0xfb2b, "afii57695"}, + {0xfb4b, "afii57700"}, + {0xfb1f, "afii57705"}, + {0x05f0, "afii57716"}, + {0x05f1, "afii57717"}, + {0x05f2, "afii57718"}, + {0xfb35, "afii57723"}, + {0x05b4, "afii57793"}, + {0x05b5, "afii57794"}, + {0x05b6, "afii57795"}, + {0x05bb, "afii57796"}, + {0x05b8, "afii57797"}, + {0x05b7, "afii57798"}, + {0x05b0, "afii57799"}, + {0x05b2, "afii57800"}, + {0x05b1, "afii57801"}, + {0x05b3, "afii57802"}, + {0x05c2, "afii57803"}, + {0x05c1, "afii57804"}, + {0x05b9, "afii57806"}, + {0x05bc, "afii57807"}, + {0x05bd, "afii57839"}, + {0x05bf, "afii57841"}, + {0x05c0, "afii57842"}, + {0x02bc, "afii57929"}, + {0x2105, "afii61248"}, + {0x2113, "afii61289"}, + {0x2116, "afii61352"}, + {0x202c, "afii61573"}, + {0x202d, "afii61574"}, + {0x202e, "afii61575"}, + {0x200c, "afii61664"}, + {0x066d, "afii63167"}, + {0x02bd, "afii64937"}, + {0x00e0, "agrave"}, + {0x2135, "aleph"}, + {0x03b1, "alpha"}, + {0x03ac, "alphatonos"}, + {0x0101, "amacron"}, + {0x0026, "ampersand"}, + {0xf726, "ampersandsmall"}, + {0x2220, "angle"}, + {0x2329, "angleleft"}, + {0x232a, "angleright"}, + {0x0387, "anoteleia"}, + {0x0105, "aogonek"}, + {0x2248, "approxequal"}, + {0x00e5, "aring"}, + {0x01fb, "aringacute"}, + {0x2194, "arrowboth"}, + {0x21d4, "arrowdblboth"}, + {0x21d3, "arrowdbldown"}, + {0x21d0, "arrowdblleft"}, + {0x21d2, "arrowdblright"}, + {0x21d1, "arrowdblup"}, + {0x2193, "arrowdown"}, + {0xf8e7, "arrowhorizex"}, + {0x2190, "arrowleft"}, + {0x2192, "arrowright"}, + {0x2191, "arrowup"}, + {0x2195, "arrowupdn"}, + {0x21a8, "arrowupdnbse"}, + {0xf8e6, "arrowvertex"}, + {0x005e, "asciicircum"}, + {0x007e, "asciitilde"}, + {0x002a, "asterisk"}, + {0x2217, "asteriskmath"}, + {0xf6e9, "asuperior"}, + {0x0040, "at"}, + {0x00e3, "atilde"}, + {0x0062, "b"}, + {0x005c, "backslash"}, + {0x007c, "bar"}, + {0x03b2, "beta"}, + {0x2588, "block"}, + {0xf8f4, "braceex"}, + {0x007b, "braceleft"}, + {0xf8f3, "braceleftbt"}, + {0xf8f2, "braceleftmid"}, + {0xf8f1, "bracelefttp"}, + {0x007d, "braceright"}, + {0xf8fe, "bracerightbt"}, + {0xf8fd, "bracerightmid"}, + {0xf8fc, "bracerighttp"}, + {0x005b, "bracketleft"}, + {0xf8f0, "bracketleftbt"}, + {0xf8ef, "bracketleftex"}, + {0xf8ee, "bracketlefttp"}, + {0x005d, "bracketright"}, + {0xf8fb, "bracketrightbt"}, + {0xf8fa, "bracketrightex"}, + {0xf8f9, "bracketrighttp"}, + {0x02d8, "breve"}, + {0x00a6, "brokenbar"}, + {0xf6ea, "bsuperior"}, + {0x2022, "bullet"}, + {0x0063, "c"}, + {0x0107, "cacute"}, + {0x02c7, "caron"}, + {0x21b5, "carriagereturn"}, + {0x010d, "ccaron"}, + {0x00e7, "ccedilla"}, + {0x0109, "ccircumflex"}, + {0x010b, "cdotaccent"}, + {0x00b8, "cedilla"}, + {0x00a2, "cent"}, + {0xf6df, "centinferior"}, + {0xf7a2, "centoldstyle"}, + {0xf6e0, "centsuperior"}, + {0x03c7, "chi"}, + {0x25cb, "circle"}, + {0x2297, "circlemultiply"}, + {0x2295, "circleplus"}, + {0x02c6, "circumflex"}, + {0x2663, "club"}, + {0x003a, "colon"}, + {0x20a1, "colonmonetary"}, + {0x002c, "comma"}, + {0xf6c3, "commaaccent"}, + {0xf6e1, "commainferior"}, + {0xf6e2, "commasuperior"}, + {0x2245, "congruent"}, + {0x00a9, "copyright"}, + {0x00a9, "copyrightsans"}, + {0x00a9, "copyrightserif"}, + {0x00a4, "currency"}, + {0xf6d1, "cyrBreve"}, + {0xf6d2, "cyrFlex"}, + {0xf6d4, "cyrbreve"}, + {0xf6d5, "cyrflex"}, + {0x0064, "d"}, + {0x2020, "dagger"}, + {0x2021, "daggerdbl"}, + {0xf6d3, "dblGrave"}, + {0xf6d6, "dblgrave"}, + {0x010f, "dcaron"}, + {0x0111, "dcroat"}, + {0x00b0, "degree"}, + {0x03b4, "delta"}, + {0x2666, "diamond"}, + {0x00a8, "dieresis"}, + {0xf6d7, "dieresisacute"}, + {0xf6d8, "dieresisgrave"}, + {0x0385, "dieresistonos"}, + {0x00f7, "divide"}, + {0x2593, "dkshade"}, + {0x2584, "dnblock"}, + {0x0024, "dollar"}, + {0xf6e3, "dollarinferior"}, + {0xf724, "dollaroldstyle"}, + {0xf6e4, "dollarsuperior"}, + {0x20ab, "dong"}, + {0x02d9, "dotaccent"}, + {0x0323, "dotbelowcomb"}, + {0x0131, "dotlessi"}, + {0xf6be, "dotlessj"}, + {0x22c5, "dotmath"}, + {0xf6eb, "dsuperior"}, + {0x0065, "e"}, + {0x00e9, "eacute"}, + {0x0115, "ebreve"}, + {0x011b, "ecaron"}, + {0x00ea, "ecircumflex"}, + {0x00eb, "edieresis"}, + {0x0117, "edotaccent"}, + {0x00e8, "egrave"}, + {0x0038, "eight"}, + {0x2088, "eightinferior"}, + {0xf738, "eightoldstyle"}, + {0x2078, "eightsuperior"}, + {0x2208, "element"}, + {0x2026, "ellipsis"}, + {0x0113, "emacron"}, + {0x2014, "emdash"}, + {0x2205, "emptyset"}, + {0x2013, "endash"}, + {0x014b, "eng"}, + {0x0119, "eogonek"}, + {0x03b5, "epsilon"}, + {0x03ad, "epsilontonos"}, + {0x003d, "equal"}, + {0x2261, "equivalence"}, + {0x212e, "estimated"}, + {0xf6ec, "esuperior"}, + {0x03b7, "eta"}, + {0x03ae, "etatonos"}, + {0x00f0, "eth"}, + {0x0021, "exclam"}, + {0x203c, "exclamdbl"}, + {0x00a1, "exclamdown"}, + {0xf7a1, "exclamdownsmall"}, + {0x0021, "exclamleft"}, + {0xf721, "exclamsmall"}, + {0x2203, "existential"}, + {0x0066, "f"}, + {0x2640, "female"}, + {0xfb00, "ff"}, + {0xfb03, "ffi"}, + {0xfb04, "ffl"}, + {0xfb01, "fi"}, + {0x2012, "figuredash"}, + {0x25a0, "filledbox"}, + {0x25ac, "filledrect"}, + {0x0035, "five"}, + {0x215d, "fiveeighths"}, + {0x2085, "fiveinferior"}, + {0xf735, "fiveoldstyle"}, + {0x2075, "fivesuperior"}, + {0xfb02, "fl"}, + {0x0192, "florin"}, + {0x0034, "four"}, + {0x2084, "fourinferior"}, + {0xf734, "fouroldstyle"}, + {0x2074, "foursuperior"}, + {0x2044, "fraction"}, + {0x20a3, "franc"}, + {0x0067, "g"}, + {0x03b3, "gamma"}, + {0x011f, "gbreve"}, + {0x01e7, "gcaron"}, + {0x011d, "gcircumflex"}, + {0x0123, "gcommaaccent"}, + {0x0121, "gdotaccent"}, + {0x00df, "germandbls"}, + {0x2207, "gradient"}, + {0x0060, "grave"}, + {0x0300, "gravecomb"}, + {0x003e, "greater"}, + {0x2265, "greaterequal"}, + {0x00ab, "guillemotleft"}, + {0x00bb, "guillemotright"}, + {0x2039, "guilsinglleft"}, + {0x203a, "guilsinglright"}, + {0x0068, "h"}, + {0x0127, "hbar"}, + {0x0125, "hcircumflex"}, + {0x2665, "heart"}, + {0x0309, "hookabovecomb"}, + {0x2302, "house"}, + {0x02dd, "hungarumlaut"}, + {0x002d, "hyphen"}, + {0xf6e5, "hypheninferior"}, + {0xf6e6, "hyphensuperior"}, + {0x0069, "i"}, + {0x00ed, "iacute"}, + {0x012d, "ibreve"}, + {0x00ee, "icircumflex"}, + {0x00ef, "idieresis"}, + {0x00ec, "igrave"}, + {0x0133, "ij"}, + {0x012b, "imacron"}, + {0x221e, "infinity"}, + {0x222b, "integral"}, + {0x2321, "integralbt"}, + {0xf8f5, "integralex"}, + {0x2320, "integraltp"}, + {0x2229, "intersection"}, + {0x25d8, "invbullet"}, + {0x25d9, "invcircle"}, + {0x263b, "invsmileface"}, + {0x012f, "iogonek"}, + {0x03b9, "iota"}, + {0x03ca, "iotadieresis"}, + {0x0390, "iotadieresistonos"}, + {0x03af, "iotatonos"}, + {0xf6ed, "isuperior"}, + {0x0129, "itilde"}, + {0x006a, "j"}, + {0x0135, "jcircumflex"}, + {0x006b, "k"}, + {0x03ba, "kappa"}, + {0x0137, "kcommaaccent"}, + {0x0138, "kgreenlandic"}, + {0x006c, "l"}, + {0x013a, "lacute"}, + {0x03bb, "lambda"}, + {0x013e, "lcaron"}, + {0x013c, "lcommaaccent"}, + {0x0140, "ldot"}, + {0x003c, "less"}, + {0x2264, "lessequal"}, + {0x258c, "lfblock"}, + {0x20a4, "lira"}, + {0xf6c0, "ll"}, + {0x2227, "logicaland"}, + {0x00ac, "logicalnot"}, + {0x2228, "logicalor"}, + {0x017f, "longs"}, + {0x25ca, "lozenge"}, + {0x0142, "lslash"}, + {0xf6ee, "lsuperior"}, + {0x2591, "ltshade"}, + {0x006d, "m"}, + {0x00af, "macron"}, + {0x2642, "male"}, + {0x2212, "minus"}, + {0x2032, "minute"}, + {0xf6ef, "msuperior"}, + {0x00b5, "mu"}, + {0x00d7, "multiply"}, + {0x266a, "musicalnote"}, + {0x266b, "musicalnotedbl"}, + {0x006e, "n"}, + {0x0144, "nacute"}, + {0x0149, "napostrophe"}, + {0x00a0, "nbspace"}, + {0x0148, "ncaron"}, + {0x0146, "ncommaaccent"}, + {0x0039, "nine"}, + {0x2089, "nineinferior"}, + {0xf739, "nineoldstyle"}, + {0x2079, "ninesuperior"}, + {0x00a0, "nonbreakingspace"}, + {0x2209, "notelement"}, + {0x2260, "notequal"}, + {0x2284, "notsubset"}, + {0x207f, "nsuperior"}, + {0x00f1, "ntilde"}, + {0x03bd, "nu"}, + {0x0023, "numbersign"}, + {0x006f, "o"}, + {0x00f3, "oacute"}, + {0x014f, "obreve"}, + {0x00f4, "ocircumflex"}, + {0x00f6, "odieresis"}, + {0x0153, "oe"}, + {0x02db, "ogonek"}, + {0x00f2, "ograve"}, + {0x01a1, "ohorn"}, + {0x0151, "ohungarumlaut"}, + {0x014d, "omacron"}, + {0x03c9, "omega"}, + {0x03d6, "omega1"}, + {0x03ce, "omegatonos"}, + {0x03bf, "omicron"}, + {0x03cc, "omicrontonos"}, + {0x0031, "one"}, + {0x2024, "onedotenleader"}, + {0x215b, "oneeighth"}, + {0xf6dc, "onefitted"}, + {0x00bd, "onehalf"}, + {0x2081, "oneinferior"}, + {0xf731, "oneoldstyle"}, + {0x00bc, "onequarter"}, + {0x00b9, "onesuperior"}, + {0x2153, "onethird"}, + {0x25e6, "openbullet"}, + {0x00aa, "ordfeminine"}, + {0x00ba, "ordmasculine"}, + {0x221f, "orthogonal"}, + {0x00f8, "oslash"}, + {0x01ff, "oslashacute"}, + {0xf6f0, "osuperior"}, + {0x00f5, "otilde"}, + {0x0070, "p"}, + {0x00b6, "paragraph"}, + {0x0028, "parenleft"}, + {0xf8ed, "parenleftbt"}, + {0xf8ec, "parenleftex"}, + {0x208d, "parenleftinferior"}, + {0x207d, "parenleftsuperior"}, + {0xf8eb, "parenlefttp"}, + {0x0029, "parenright"}, + {0xf8f8, "parenrightbt"}, + {0xf8f7, "parenrightex"}, + {0x208e, "parenrightinferior"}, + {0x207e, "parenrightsuperior"}, + {0xf8f6, "parenrighttp"}, + {0x2202, "partialdiff"}, + {0x0025, "percent"}, + {0x002e, "period"}, + {0x00b7, "periodcentered"}, + {0xf6e7, "periodinferior"}, + {0xf6e8, "periodsuperior"}, + {0x22a5, "perpendicular"}, + {0x2030, "perthousand"}, + {0x20a7, "peseta"}, + {0x03c6, "phi"}, + {0x03d5, "phi1"}, + {0x03c0, "pi"}, + {0x002b, "plus"}, + {0x00b1, "plusminus"}, + {0x211e, "prescription"}, + {0x220f, "product"}, + {0x2282, "propersubset"}, + {0x2283, "propersuperset"}, + {0x221d, "proportional"}, + {0x03c8, "psi"}, + {0x0071, "q"}, + {0x003f, "question"}, + {0x00bf, "questiondown"}, + {0xf7bf, "questiondownsmall"}, + {0xf73f, "questionsmall"}, + {0x0022, "quotedbl"}, + {0x201e, "quotedblbase"}, + {0x201c, "quotedblleft"}, + {0x201d, "quotedblright"}, + {0x2018, "quoteleft"}, + {0x201b, "quotereversed"}, + {0x2019, "quoteright"}, + {0x201a, "quotesinglbase"}, + {0x0027, "quotesingle"}, + {0x0072, "r"}, + {0x0155, "racute"}, + {0x221a, "radical"}, + {0xf8e5, "radicalex"}, + {0x0159, "rcaron"}, + {0x0157, "rcommaaccent"}, + {0x2286, "reflexsubset"}, + {0x2287, "reflexsuperset"}, + {0x00ae, "registered"}, + {0x00ae, "registersans"}, + {0x00ae, "registerserif"}, + {0x2310, "revlogicalnot"}, + {0x03c1, "rho"}, + {0x02da, "ring"}, + {0xf6f1, "rsuperior"}, + {0x2590, "rtblock"}, + {0xf6dd, "rupiah"}, + {0x0073, "s"}, + {0x015b, "sacute"}, + {0x0161, "scaron"}, + {0x015f, "scedilla"}, + {0x015d, "scircumflex"}, + {0x0219, "scommaaccent"}, + {0x2033, "second"}, + {0x00a7, "section"}, + {0x003b, "semicolon"}, + {0x0037, "seven"}, + {0x215e, "seveneighths"}, + {0x2087, "seveninferior"}, + {0xf737, "sevenoldstyle"}, + {0x2077, "sevensuperior"}, + {0x2592, "shade"}, + {0x03c3, "sigma"}, + {0x03c2, "sigma1"}, + {0x223c, "similar"}, + {0x0036, "six"}, + {0x2086, "sixinferior"}, + {0xf736, "sixoldstyle"}, + {0x2076, "sixsuperior"}, + {0x002f, "slash"}, + {0x263a, "smileface"}, + {0x0020, "space"}, + {0x2660, "spade"}, + {0xf6f2, "ssuperior"}, + {0x00a3, "sterling"}, + {0x220b, "suchthat"}, + {0x2211, "summation"}, + {0x263c, "sun"}, + {0x0074, "t"}, + {0x03c4, "tau"}, + {0x0167, "tbar"}, + {0x0165, "tcaron"}, + {0x0163, "tcommaaccent"}, + {0x2234, "therefore"}, + {0x03b8, "theta"}, + {0x03d1, "theta1"}, + {0x00fe, "thorn"}, + {0x0033, "three"}, + {0x215c, "threeeighths"}, + {0x2083, "threeinferior"}, + {0xf733, "threeoldstyle"}, + {0x00be, "threequarters"}, + {0xf6de, "threequartersemdash"}, + {0x00b3, "threesuperior"}, + {0x02dc, "tilde"}, + {0x0303, "tildecomb"}, + {0x0384, "tonos"}, + {0x2122, "trademark"}, + {0x2122, "trademarksans"}, + {0x2122, "trademarkserif"}, + {0x25bc, "triagdn"}, + {0x25c4, "triaglf"}, + {0x25ba, "triagrt"}, + {0x25b2, "triagup"}, + {0xf6f3, "tsuperior"}, + {0x0032, "two"}, + {0x2025, "twodotenleader"}, + {0x2082, "twoinferior"}, + {0xf732, "twooldstyle"}, + {0x00b2, "twosuperior"}, + {0x2154, "twothirds"}, + {0x0075, "u"}, + {0x00fa, "uacute"}, + {0x016d, "ubreve"}, + {0x00fb, "ucircumflex"}, + {0x00fc, "udieresis"}, + {0x00f9, "ugrave"}, + {0x01b0, "uhorn"}, + {0x0171, "uhungarumlaut"}, + {0x016b, "umacron"}, + {0x005f, "underscore"}, + {0x2017, "underscoredbl"}, + {0x222a, "union"}, + {0x2200, "universal"}, + {0x0173, "uogonek"}, + {0x2580, "upblock"}, + {0x03c5, "upsilon"}, + {0x03cb, "upsilondieresis"}, + {0x03b0, "upsilondieresistonos"}, + {0x03cd, "upsilontonos"}, + {0x016f, "uring"}, + {0x0169, "utilde"}, + {0x0076, "v"}, + {0x0077, "w"}, + {0x1e83, "wacute"}, + {0x0175, "wcircumflex"}, + {0x1e85, "wdieresis"}, + {0x2118, "weierstrass"}, + {0x1e81, "wgrave"}, + {0x0078, "x"}, + {0x03be, "xi"}, + {0x0079, "y"}, + {0x00fd, "yacute"}, + {0x0177, "ycircumflex"}, + {0x00ff, "ydieresis"}, + {0x00a5, "yen"}, + {0x1ef3, "ygrave"}, + {0x007a, "z"}, + {0x017a, "zacute"}, + {0x017e, "zcaron"}, + {0x017c, "zdotaccent"}, + {0x0030, "zero"}, + {0x2080, "zeroinferior"}, + {0xf730, "zerooldstyle"}, + {0x2070, "zerosuperior"}, + {0x03b6, "zeta"}, + {0x007b, "{"}, + {0x007c, "|"}, + {0x007d, "}"}, + {0x007e, "~"}, + { 0, NULL } +}; diff --git a/pdftops/Object.cxx b/pdftops/Object.cxx new file mode 100644 index 000000000..0b6ac3431 --- /dev/null +++ b/pdftops/Object.cxx @@ -0,0 +1,231 @@ +//======================================================================== +// +// Object.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#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::initDict(Dict *dictA) { + initObj(objDict); + dict = dictA; + dict->incRef(); + 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, "("); + fwrite(string->getCString(), 1, string->getLength(), f); + fprintf(f, ")"); + 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, ""); + break; + case objRef: + fprintf(f, "%d %d R", ref.num, ref.gen); + break; + case objCmd: + fprintf(f, "%s", cmd); + break; + case objError: + fprintf(f, ""); + break; + case objEOF: + fprintf(f, ""); + break; + case objNone: + fprintf(f, ""); + 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..72ba2629b --- /dev/null +++ b/pdftops/Object.h @@ -0,0 +1,303 @@ +//======================================================================== +// +// Object.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef OBJECT_H +#define OBJECT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include +#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 *initDict(Dict *dictA); + 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; } + char *getCmd() { return cmd; } + + // 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); + Guint streamGetPos(); + void streamSetPos(Guint pos, int dir = 0); + 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 Guint Object::streamGetPos() + { return stream->getPos(); } + +inline void Object::streamSetPos(Guint pos, int dir) + { stream->setPos(pos, dir); } + +inline Dict *Object::streamGetDict() + { return stream->getDict(); } + +#endif diff --git a/pdftops/Outline.cxx b/pdftops/Outline.cxx new file mode 100644 index 000000000..d127e944a --- /dev/null +++ b/pdftops/Outline.cxx @@ -0,0 +1,151 @@ +//======================================================================== +// +// Outline.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "GString.h" +#include "GList.h" +#include "Link.h" +#include "PDFDocEncoding.h" +#include "Outline.h" + +//------------------------------------------------------------------------ + +Outline::Outline(Object *outlineObj, XRef *xref) { + Object first, last; + + items = NULL; + if (!outlineObj->isDict()) { + return; + } + items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first), + outlineObj->dictLookupNF("Last", &last), + xref); + first.free(); + last.free(); +} + +Outline::~Outline() { + if (items) { + deleteGList(items, OutlineItem); + } +} + +//------------------------------------------------------------------------ + +OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { + Object obj1; + GString *s; + int i; + + xref = xrefA; + title = NULL; + action = NULL; + kids = NULL; + + if (dict->lookup("Title", &obj1)->isString()) { + s = obj1.getString(); + if ((s->getChar(0) & 0xff) == 0xfe && + (s->getChar(1) & 0xff) == 0xff) { + titleLen = (s->getLength() - 2) / 2; + title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); + for (i = 0; i < titleLen; ++i) { + title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | + (s->getChar(3 + 2*i) & 0xff); + } + } else { + titleLen = s->getLength(); + title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); + for (i = 0; i < titleLen; ++i) { + title[i] = pdfDocEncoding[s->getChar(i) & 0xff]; + } + } + } else { + titleLen = 0; + } + obj1.free(); + + if (!dict->lookup("Dest", &obj1)->isNull()) { + action = LinkAction::parseDest(&obj1); + } else { + obj1.free(); + if (!dict->lookup("A", &obj1)->isNull()) { + action = LinkAction::parseAction(&obj1); + } + } + obj1.free(); + + dict->lookupNF("First", &firstRef); + dict->lookupNF("Last", &lastRef); + dict->lookupNF("Next", &nextRef); + + startsOpen = gFalse; + if (dict->lookup("Count", &obj1)->isInt()) { + if (obj1.getInt() > 0) { + startsOpen = gTrue; + } + } + obj1.free(); +} + +OutlineItem::~OutlineItem() { + close(); + if (title) { + gfree(title); + } + if (action) { + delete action; + } + firstRef.free(); + lastRef.free(); + nextRef.free(); +} + +GList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef, + XRef *xrefA) { + GList *items; + OutlineItem *item; + Object obj; + Object *p; + + items = new GList(); + p = firstItemRef; + while (p->isRef()) { + if (!p->fetch(xrefA, &obj)->isDict()) { + obj.free(); + break; + } + item = new OutlineItem(obj.getDict(), xrefA); + obj.free(); + items->append(item); + if (p->getRef().num == lastItemRef->getRef().num && + p->getRef().gen == lastItemRef->getRef().gen) { + break; + } + p = &item->nextRef; + } + return items; +} + +void OutlineItem::open() { + if (!kids) { + kids = readItemList(&firstRef, &lastRef, xref); + } +} + +void OutlineItem::close() { + if (kids) { + deleteGList(kids, OutlineItem); + kids = NULL; + } +} diff --git a/pdftops/Outline.h b/pdftops/Outline.h new file mode 100644 index 000000000..e83386221 --- /dev/null +++ b/pdftops/Outline.h @@ -0,0 +1,76 @@ +//======================================================================== +// +// Outline.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef OUTLINE_H +#define OUTLINE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" +#include "CharTypes.h" + +class GString; +class GList; +class XRef; +class LinkAction; + +//------------------------------------------------------------------------ + +class Outline { +public: + + Outline(Object *outlineObj, XRef *xref); + ~Outline(); + + GList *getItems() { return items; } + +private: + + GList *items; // NULL if document has no outline + // [OutlineItem] +}; + +//------------------------------------------------------------------------ + +class OutlineItem { +public: + + OutlineItem(Dict *dict, XRef *xrefA); + ~OutlineItem(); + + static GList *readItemList(Object *firstItemRef, Object *lastItemRef, + XRef *xrefA); + + void open(); + void close(); + + Unicode *getTitle() { return title; } + int getTitleLength() { return titleLen; } + LinkAction *getAction() { return action; } + GBool isOpen() { return startsOpen; } + GBool hasKids() { return firstRef.isRef(); } + GList *getKids() { return kids; } + +private: + + XRef *xref; + Unicode *title; + int titleLen; + LinkAction *action; + Object firstRef; + Object lastRef; + Object nextRef; + GBool startsOpen; + GList *kids; // NULL unless this item is open [OutlineItem] +}; + +#endif diff --git a/pdftops/OutputDev.cxx b/pdftops/OutputDev.cxx new file mode 100644 index 000000000..a68ca80a2 --- /dev/null +++ b/pdftops/OutputDev.cxx @@ -0,0 +1,129 @@ +//======================================================================== +// +// OutputDev.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#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(double dx, double 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); + updateFillColorSpace(state); + updateFillColor(state); + updateStrokeColorSpace(state); + updateStrokeColor(state); + updateBlendMode(state); + updateFillOpacity(state); + updateStrokeOpacity(state); + updateFillOverprint(state); + updateStrokeOverprint(state); + updateFont(state); +} + +GBool OutputDev::beginType3Char(GfxState *state, double x, double y, + double dx, double dy, + CharCode code, Unicode *u, int uLen) { + return gFalse; +} + +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(); + str->close(); + } +} + +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(); + str->close(); + } +} + +void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GBool maskInvert) { + drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); +} + +void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap) { + drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); +} + +#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..a58c5fdd0 --- /dev/null +++ b/pdftops/OutputDev.h @@ -0,0 +1,205 @@ +//======================================================================== +// +// OutputDev.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef OUTPUTDEV_H +#define OUTPUTDEV_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "CharTypes.h" + +class GString; +class GfxState; +class GfxColorSpace; +class GfxImageColorMap; +class GfxFunctionShading; +class GfxAxialShading; +class GfxRadialShading; +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; + + // Does this device use tilingPatternFill()? If this returns false, + // tiling pattern fills will be reduced to a series of other drawing + // operations. + virtual GBool useTilingPatternFill() { return gFalse; } + + // Does this device use functionShadedFill(), axialShadedFill(), and + // radialShadedFill()? If this returns false, these shaded fills + // will be reduced to a series of other drawing operations. + virtual GBool useShadedFills() { return gFalse; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() = 0; + + // Does this device need non-text content? + virtual GBool needNonText() { return gTrue; } + + //----- initialization and control + + // Set default transform matrix. + virtual void setDefaultCTM(double *ctm); + + // Start a page. + virtual GBool startPage(int pageNum, GfxState *state) { return (gTrue); } + + // 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(double dx, double dy, double *ux, double *uy); + virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy); + + double *getDefCTM() { return defCTM; } + double *getDefICTM() { return defICTM; } + + //----- 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 updateFillColorSpace(GfxState *state) {} + virtual void updateStrokeColorSpace(GfxState *state) {} + virtual void updateFillColor(GfxState *state) {} + virtual void updateStrokeColor(GfxState *state) {} + virtual void updateBlendMode(GfxState *state) {} + virtual void updateFillOpacity(GfxState *state) {} + virtual void updateStrokeOpacity(GfxState *state) {} + virtual void updateFillOverprint(GfxState *state) {} + virtual void updateStrokeOverprint(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) {} + virtual void tilingPatternFill(GfxState *state, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) {} + virtual void functionShadedFill(GfxState *state, + GfxFunctionShading *shading) {} + virtual void axialShadedFill(GfxState *state, GfxAxialShading *shading) {} + virtual void radialShadedFill(GfxState *state, GfxRadialShading *shading) {} + + //----- path clipping + virtual void clip(GfxState *state) {} + virtual void eoClip(GfxState *state) {} + + //----- text drawing + virtual void beginStringOp(GfxState *state) {} + virtual void endStringOp(GfxState *state) {} + 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, + double originX, double originY, + CharCode code, int nBytes, Unicode *u, int uLen) {} + virtual void drawString(GfxState *state, GString *s) {} + virtual GBool beginType3Char(GfxState *state, double x, double y, + double dx, double dy, + CharCode code, Unicode *u, int uLen); + virtual void endType3Char(GfxState *state) {} + virtual void endTextObject(GfxState *state) {} + + //----- 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); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); + +#if OPI_SUPPORT + //----- OPI functions + virtual void opiBegin(GfxState *state, Dict *opiDict); + virtual void opiEnd(GfxState *state, Dict *opiDict); +#endif + + //----- Type 3 font operators + virtual void type3D0(GfxState *state, double wx, double wy) {} + virtual void type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury) {} + + //----- PostScript XObjects + virtual void psXObject(Stream *psStream, Stream *level1Stream) {} + +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..70e36fe0a --- /dev/null +++ b/pdftops/PDFDoc.cxx @@ -0,0 +1,431 @@ +//======================================================================== +// +// PDFDoc.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#ifdef WIN32 +# include +#endif +#include "GString.h" +#include "config.h" +#include "GlobalParams.h" +#include "Page.h" +#include "Catalog.h" +#include "Stream.h" +#include "XRef.h" +#include "Link.h" +#include "OutputDev.h" +#include "Error.h" +#include "ErrorCodes.h" +#include "Lexer.h" +#include "Parser.h" +#include "SecurityHandler.h" +#ifndef DISABLE_OUTLINE +#include "Outline.h" +#endif +#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, void *guiDataA) { + Object obj; + GString *fileName1, *fileName2; + + ok = gFalse; + errCode = errNone; + + guiData = guiDataA; + + file = NULL; + str = NULL; + xref = NULL; + catalog = NULL; + links = NULL; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif + + fileName = fileNameA; + fileName1 = fileName; + + + // try to open file + fileName2 = NULL; +#ifdef VMS + if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) { + error(-1, "Couldn't open file '%s'", fileName1->getCString()); + errCode = errOpenFile; + return; + } +#else + if (!(file = fopen(fileName1->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; + errCode = errOpenFile; + return; + } + } + delete fileName2; + } +#endif + + // create stream + obj.initNull(); + str = new FileStream(file, 0, gFalse, 0, &obj); + + ok = setup(ownerPassword, userPassword); +} + +#ifdef WIN32 +PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, + GString *userPassword, void *guiDataA) { + OSVERSIONINFO version; + wchar_t fileName2[_MAX_PATH + 1]; + Object obj; + int i; + + ok = gFalse; + errCode = errNone; + + guiData = guiDataA; + + file = NULL; + str = NULL; + xref = NULL; + catalog = NULL; + links = NULL; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif + + //~ file name should be stored in Unicode (?) + fileName = new GString(); + for (i = 0; i < fileNameLen; ++i) { + fileName->append((char)fileNameA[i]); + } + + // zero-terminate the file name string + for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) { + fileName2[i] = fileNameA[i]; + } + fileName2[i] = 0; + + // try to open file + // NB: _wfopen is only available in NT + version.dwOSVersionInfoSize = sizeof(version); + GetVersionEx(&version); + if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { + file = _wfopen(fileName2, L"rb"); + } else { + file = fopen(fileName->getCString(), "rb"); + } + if (!file) { + error(-1, "Couldn't open file '%s'", fileName->getCString()); + errCode = errOpenFile; + return; + } + + // create stream + obj.initNull(); + str = new FileStream(file, 0, gFalse, 0, &obj); + + ok = setup(ownerPassword, userPassword); +} +#endif + +PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, + GString *userPassword, void *guiDataA) { + ok = gFalse; + errCode = errNone; + guiData = guiDataA; + fileName = NULL; + file = NULL; + str = strA; + xref = NULL; + catalog = NULL; + links = NULL; +#ifndef DISABLE_OUTLINE + outline = NULL; +#endif + ok = setup(ownerPassword, userPassword); +} + +GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { + str->reset(); + + // check header + checkHeader(); + + // read xref table + xref = new XRef(str); + if (!xref->isOk()) { + error(-1, "Couldn't read xref table"); + errCode = xref->getErrorCode(); + return gFalse; + } + + // check for encryption + if (!checkEncryption(ownerPassword, userPassword)) { + errCode = errEncrypted; + return gFalse; + } + + // read catalog + catalog = new Catalog(xref); + if (!catalog->isOk()) { + error(-1, "Couldn't read page catalog"); + errCode = errBadCatalog; + return gFalse; + } + +#ifndef DISABLE_OUTLINE + // read outline + outline = new Outline(catalog->getOutline(), xref); +#endif + + // done + return gTrue; +} + +PDFDoc::~PDFDoc() { +#ifndef DISABLE_OUTLINE + if (outline) { + delete outline; + } +#endif + 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); + if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) { + error(-1, "May not be a PDF file (continuing anyway)"); + return; + } + 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); + } +} + +GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { + Object encrypt; + GBool encrypted; + SecurityHandler *secHdlr; + GBool ret; + + xref->getTrailerDict()->dictLookup("Encrypt", &encrypt); + if ((encrypted = encrypt.isDict())) { + if ((secHdlr = SecurityHandler::make(this, &encrypt))) { + if (secHdlr->checkEncryption(ownerPassword, userPassword)) { + // authorization succeeded + xref->setEncryption(secHdlr->getPermissionFlags(), + secHdlr->getOwnerPasswordOk(), + secHdlr->getFileKey(), + secHdlr->getFileKeyLength(), + secHdlr->getEncVersion()); + ret = gTrue; + } else { + // authorization failed + ret = gFalse; + } + delete secHdlr; + } else { + // couldn't find the matching security handler + ret = gFalse; + } + } else { + // document is not encrypted + ret = gTrue; + } + encrypt.free(); + return ret; +} + +void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + GBool doLinks, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + Page *p; + + if (globalParams->getPrintCommands()) { + printf("***** page %d *****\n", page); + } + p = catalog->getPage(page); + if (doLinks) { + if (links) { + delete links; + } + getLinks(p); + p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog, + abortCheckCbk, abortCheckCbkData); + } else { + p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog, + abortCheckCbk, abortCheckCbkData); + } +} + +void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool doLinks, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + int page; + + for (page = firstPage; page <= lastPage; ++page) { + displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks, + abortCheckCbk, abortCheckCbkData); + } +} + +void PDFDoc::displayPageSlice(OutputDev *out, int page, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool doLinks, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + Page *p; + + p = catalog->getPage(page); + if (doLinks) { + if (links) { + delete links; + } + getLinks(p); + p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + links, catalog, abortCheckCbk, abortCheckCbkData); + } else { + p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + NULL, catalog, abortCheckCbk, abortCheckCbkData); + } +} + +Links *PDFDoc::takeLinks() { + Links *ret; + + ret = links; + links = NULL; + return ret; +} + +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(), gFalse, 0, &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..0496db3ac --- /dev/null +++ b/pdftops/PDFDoc.h @@ -0,0 +1,182 @@ +//======================================================================== +// +// PDFDoc.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PDFDOC_H +#define PDFDOC_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "XRef.h" +#include "Catalog.h" +#include "Page.h" + +class GString; +class BaseStream; +class OutputDev; +class Links; +class LinkAction; +class LinkDest; +class Outline; + +//------------------------------------------------------------------------ +// PDFDoc +//------------------------------------------------------------------------ + +class PDFDoc { +public: + + PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, + GString *userPassword = NULL, void *guiDataA = NULL); +#ifdef WIN32 + PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL, + GString *userPassword = NULL, void *guiDataA = NULL); +#endif + PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, + GString *userPassword = NULL, void *guiDataA = NULL); + ~PDFDoc(); + + // Was PDF document successfully opened? + GBool isOk() { return ok; } + + // Get the error code (if isOk() returns false). + int getErrorCode() { return errCode; } + + // 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 getPageMediaWidth(int page) + { return catalog->getPage(page)->getMediaWidth(); } + double getPageMediaHeight(int page) + { return catalog->getPage(page)->getMediaHeight(); } + double getPageCropWidth(int page) + { return catalog->getPage(page)->getCropWidth(); } + double getPageCropHeight(int page) + { return catalog->getPage(page)->getCropHeight(); } + int getPageRotate(int page) + { return catalog->getPage(page)->getRotate(); } + + // Get number of pages. + int getNumPages() { return catalog->getNumPages(); } + + // Return the contents of the metadata stream, or NULL if there is + // no metadata. + GString *readMetadata() { return catalog->readMetadata(); } + + // Return the structure tree root object. + Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); } + + // Display a page. + void displayPage(OutputDev *out, int page, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + GBool doLinks, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display a range of pages. + void displayPages(OutputDev *out, int firstPage, int lastPage, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool doLinks, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display part of a page. + void displayPageSlice(OutputDev *out, int page, + double hDPI, double vDPI, int rotate, + GBool useMediaBox, GBool crop, GBool doLinks, + int sliceX, int sliceY, int sliceW, int sliceH, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // 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); } + + // Returns the links for the current page, transferring ownership to + // the caller. + Links *takeLinks(); + + // Find a named destination. Returns the link destination, or + // NULL if is not a destination. + LinkDest *findDest(GString *name) + { return catalog->findDest(name); } + +#ifndef DISABLE_OUTLINE + // Return the outline object. + Outline *getOutline() { return outline; } +#endif + + // 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); } + Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); } + + // Return the PDF version specified by the file. + double getPDFVersion() { return pdfVersion; } + + // Save this file with another name. + GBool saveAs(GString *name); + + // Return a pointer to the GUI (XPDFCore or WinPDFCore object). + void *getGUIData() { return guiData; } + + +private: + + GBool setup(GString *ownerPassword, GString *userPassword); + void checkHeader(); + GBool checkEncryption(GString *ownerPassword, GString *userPassword); + void getLinks(Page *page); + + GString *fileName; + FILE *file; + BaseStream *str; + void *guiData; + double pdfVersion; + XRef *xref; + Catalog *catalog; + Links *links; +#ifndef DISABLE_OUTLINE + Outline *outline; +#endif + + + GBool ok; + int errCode; +}; + +#endif diff --git a/pdftops/PDFDocEncoding.cxx b/pdftops/PDFDocEncoding.cxx new file mode 100644 index 000000000..89dc38283 --- /dev/null +++ b/pdftops/PDFDocEncoding.cxx @@ -0,0 +1,44 @@ +//======================================================================== +// +// PDFDocEncoding.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include "PDFDocEncoding.h" + +Unicode pdfDocEncoding[256] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 00 + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 10 + 0x02d8, 0x02c7, 0x02c6, 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20 + 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30 + 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40 + 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50 + 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60 + 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70 + 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000, + 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, // 80 + 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, + 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, // 90 + 0x0178, 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0x0000, + 0x20ac, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, // a0 + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, // b0 + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, // c0 + 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, + 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, // d0 + 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, // e0 + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, // f0 + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff +}; diff --git a/pdftops/PDFDocEncoding.h b/pdftops/PDFDocEncoding.h new file mode 100644 index 000000000..3259d3e10 --- /dev/null +++ b/pdftops/PDFDocEncoding.h @@ -0,0 +1,16 @@ +//======================================================================== +// +// PDFDocEncoding.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PDFDOCENCODING_H +#define PDFDOCENCODING_H + +#include "CharTypes.h" + +extern Unicode pdfDocEncoding[256]; + +#endif diff --git a/pdftops/PSOutputDev.cxx b/pdftops/PSOutputDev.cxx new file mode 100644 index 000000000..41d359098 --- /dev/null +++ b/pdftops/PSOutputDev.cxx @@ -0,0 +1,4976 @@ +//======================================================================== +// +// PSOutputDev.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include +#include +#include +#include "GString.h" +#include "GList.h" +#include "config.h" +#include "GlobalParams.h" +#include "Object.h" +#include "Error.h" +#include "Function.h" +#include "Gfx.h" +#include "GfxState.h" +#include "GfxFont.h" +#include "UnicodeMap.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" +#include "Catalog.h" +#include "Page.h" +#include "Stream.h" +#include "Annot.h" +#include "XRef.h" +#include "PSOutputDev.h" + +#ifdef MACOS +// needed for setting type/creator of MacOS files +#include "ICSupport.h" +#endif + +//------------------------------------------------------------------------ +// PostScript prolog and setup +//------------------------------------------------------------------------ + +// The '~' escapes mark prolog code that is emitted only in certain +// levels: +// +// ~[123][sn] +// ^ ^----- s=psLevel*Sep, n=psLevel* +// +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3* + +static char *prolog[] = { + "/xpdf 75 dict def xpdf begin", + "% PDF special state", + "/pdfDictSize 15 def", + "~1sn", + "/pdfStates 64 array def", + " 0 1 63 {", + " pdfStates exch pdfDictSize dict", + " dup /pdfStateIdx 3 index put", + " put", + " } for", + "~123sn", + "/pdfSetup {", + " 3 1 roll 2 array astore", + " /setpagedevice where {", + " pop 3 dict begin", + " /PageSize exch def", + " /ImagingBBox null def", + " /Policies 1 dict dup begin /PageSize 3 def end def", + " { /Duplex true def } if", + " currentdict end setpagedevice", + " } {", + " pop pop", + " } ifelse", + "} def", + "~1sn", + "/pdfOpNames [", + " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke", + " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender", + " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath", + "] def", + "~123sn", + "/pdfStartPage {", + "~1sn", + " pdfStates 0 get begin", + "~23sn", + " pdfDictSize dict begin", + "~23n", + " /pdfFillCS [] def", + " /pdfFillXform {} def", + " /pdfStrokeCS [] def", + " /pdfStrokeXform {} def", + "~1n", + " /pdfFill 0 def", + " /pdfStroke 0 def", + "~1s", + " /pdfFill [0 0 0 1] def", + " /pdfStroke [0 0 0 1] def", + "~23sn", + " /pdfFill [0] def", + " /pdfStroke [0] def", + " /pdfFillOP false def", + " /pdfStrokeOP false def", + "~123sn", + " /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", + " /pdfTextClipPath [] def", + "} def", + "/pdfEndPage { end } def", + "~23s", + "% 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", + " [ 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", + "~123sn", + "% PDF color state", + "~1n", + "/g { dup /pdfFill exch def setgray", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/G { dup /pdfStroke exch def setgray", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/fCol {", + " pdfLastFill not {", + " pdfFill setgray", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke setgray", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~1s", + "/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", + "/fCol {", + " pdfLastFill not {", + " pdfFill aload pop setcmykcolor", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke aload pop setcmykcolor", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~23n", + "/cs { /pdfFillXform exch def dup /pdfFillCS exch def", + " setcolorspace } def", + "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def", + " setcolorspace } def", + "/sc { pdfLastFill not { pdfFillCS setcolorspace } if", + " dup /pdfFill exch def aload pop pdfFillXform setcolor", + " /pdfLastFill true def /pdfLastStroke false def } def", + "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if", + " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor", + " /pdfLastStroke true def /pdfLastFill false def } def", + "/op { /pdfFillOP exch def", + " pdfLastFill { pdfFillOP setoverprint } if } def", + "/OP { /pdfStrokeOP exch def", + " pdfLastStroke { pdfStrokeOP setoverprint } if } def", + "/fCol {", + " pdfLastFill not {", + " pdfFillCS setcolorspace", + " pdfFill aload pop pdfFillXform setcolor", + " pdfFillOP setoverprint", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStrokeCS setcolorspace", + " pdfStroke aload pop pdfStrokeXform setcolor", + " pdfStrokeOP setoverprint", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~23s", + "/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", + "/op { /pdfFillOP exch def", + " pdfLastFill { pdfFillOP setoverprint } if } def", + "/OP { /pdfStrokeOP exch def", + " pdfLastStroke { pdfStrokeOP setoverprint } if } def", + "/fCol {", + " pdfLastFill not {", + " pdfFill aload length 4 eq {", + " setcmykcolor", + " }{", + " findcmykcustomcolor exch setcustomcolor", + " } ifelse", + " pdfFillOP setoverprint", + " /pdfLastFill true def /pdfLastStroke false def", + " } if", + "} def", + "/sCol {", + " pdfLastStroke not {", + " pdfStroke aload length 4 eq {", + " setcmykcolor", + " }{", + " findcmykcustomcolor exch setcustomcolor", + " } ifelse", + " pdfStrokeOP setoverprint", + " /pdfLastStroke true def /pdfLastFill false def", + " } if", + "} def", + "~123sn", + "% 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 {", + " exch findfont", + " dup length dict begin", + " { 1 index /FID ne { def } { pop pop } ifelse } forall", + " /WMode exch def", + " currentdict", + " end", + " definefont pop", + "} def", + "~3sn", + "/pdfMakeFont16L3 {", + " 1 index /CIDFont resourcestatus {", + " pop pop 1 index /CIDFont findresource /CIDFontType known", + " } {", + " false", + " } ifelse", + " {", + " 0 eq { /Identity-H } { /Identity-V } ifelse", + " exch 1 array astore composefont pop", + " } {", + " pdfMakeFont16", + " } ifelse", + "} def", + "~123sn", + "% graphics state operators", + "~1sn", + "/q {", + " gsave", + " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for", + " pdfStates pdfStateIdx 1 add get begin", + " pdfOpNames { exch def } forall", + "} def", + "/Q { end grestore } def", + "~23sn", + "/q { gsave pdfDictSize dict begin } def", + "/Q {", + " end grestore", + " /pdfLastFill where {", + " pop", + " pdfLastFill {", + " pdfFillOP setoverprint", + " } {", + " pdfStrokeOP setoverprint", + " } ifelse", + " } if", + "} def", + "~123sn", + "/cm { concat } def", + "/d { setdash } def", + "/i { setflat } def", + "/j { setlinejoin } def", + "/J { setlinecap } def", + "/M { setmiterlimit } def", + "/w { setlinewidth } 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", + "/Sf { fCol 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", + "/cshow where {", + " pop", + " /cshow2 {", + " dup {", + " pop pop", + " 1 string dup 0 3 index put 3 index exec", + " } exch cshow", + " pop pop", + " } def", + "}{", + " /cshow2 {", + " currentfont /FontType get 0 eq {", + " 0 2 2 index length 1 sub {", + " 2 copy get exch 1 add 2 index exch get", + " 2 copy exch 256 mul add", + " 2 string dup 0 6 5 roll put dup 1 5 4 roll put", + " 3 index exec", + " } for", + " } {", + " dup {", + " 1 string dup 0 3 index put 3 index exec", + " } forall", + " } ifelse", + " pop pop", + " } def", + "} ifelse", + "/awcp {", // awidthcharpath + " exch {", + " false charpath", + " 5 index 5 index rmoveto", + " 6 index eq { 7 index 7 index rmoveto } if", + " } exch cshow2", + " 6 {pop} repeat", + "} def", + "/Tj {", + " fCol", // because stringwidth has to draw Type 3 chars + " 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 Tj1", + "} def", + "/Tj16 {", + " fCol", // because stringwidth has to draw Type 3 chars + " 2 index stringwidth pdfTextMat idtransform pop", + " sub exch div", + " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32", + " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0", + " pdfTextMat dtransform", + " 6 5 roll Tj1", + "} def", + "/Tj16V {", + " fCol", // because stringwidth has to draw Type 3 chars + " 2 index stringwidth pdfTextMat idtransform exch pop", + " sub exch div", + " 0 pdfWordSpacing pdfTextMat dtransform 32", + " 4 3 roll pdfCharSpacing add 0 exch", + " pdfTextMat dtransform", + " 6 5 roll Tj1", + "} def", + "/Tj1 {", + " 0 pdfTextRise pdfTextMat dtransform rmoveto", + " currentpoint 8 2 roll", + " pdfTextRender 1 and 0 eq {", + " 6 copy awidthshow", + " } if", + " pdfTextRender 3 and dup 1 eq exch 2 eq or {", + " 7 index 7 index moveto", + " 6 copy", + " currentfont /FontType get 3 eq { fCol } { sCol } ifelse", + " false awcp currentpoint stroke moveto", + " } if", + " pdfTextRender 4 and 0 ne {", + " 8 6 roll moveto", + " false awcp", + " /pdfTextClipPath [ pdfTextClipPath aload pop", + " {/moveto cvx}", + " {/lineto cvx}", + " {/curveto cvx}", + " {/closepath cvx}", + " pathforall ] def", + " currentpoint newpath moveto", + " } {", + " 8 {pop} repeat", + " } ifelse", + " 0 pdfTextRise neg pdfTextMat dtransform rmoveto", + "} def", + "/TJm { pdfFontSize 0.001 mul mul neg 0", + " pdfTextMat dtransform rmoveto } def", + "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch", + " pdfTextMat dtransform rmoveto } def", + "/Tclip { pdfTextClipPath cvx exec clip newpath", + " /pdfTextClipPath [] def } def", + "~1ns", + "% Level 1 image operators", + "~1n", + "/pdfIm1 {", + " /pdfImBuf1 4 index string def", + " { currentfile pdfImBuf1 readhexstring pop } image", + "} def", + "~1s", + "/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", + "~1ns", + "/pdfImM1 {", + " fCol /pdfImBuf1 4 index 7 add 8 idiv string def", + " { currentfile pdfImBuf1 readhexstring pop } imagemask", + "} def", + "/pdfImM1a {", + " { 2 copy get exch 1 add exch } imagemask", + " pop pop", + "} def", + "~23sn", + "% Level 2 image operators", + "/pdfImBuf 100 string def", + "/pdfIm {", + " image", + " { currentfile pdfImBuf readline", + " not { pop exit } if", + " (%-EOD-) eq { exit } if } loop", + "} def", + "~23s", + "/pdfImSep {", + " findcmykcustomcolor exch", + " dup /Width get /pdfImBuf1 exch string def", + " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def", + " /pdfImDecodeLow exch 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", + " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi", + " 255 exch sub put", + " } for }", + " 6 5 roll customcolorimage", + " { currentfile pdfImBuf readline", + " not { pop exit } if", + " (%-EOD-) eq { exit } if } loop", + "} def", + "~23sn", + "/pdfImM {", + " fCol imagemask", + " { currentfile pdfImBuf readline", + " not { pop exit } if", + " (%-EOD-) eq { exit } if } loop", + "} def", + "/pdfImClip {", + " gsave", + " 0 2 4 index length 1 sub {", + " dup 4 index exch 2 copy", + " get 5 index div put", + " 1 add 3 index exch 2 copy", + " get 3 index div put", + " } for", + " pop pop rectclip", + "} def", + "/pdfImClipEnd { grestore } def", + "~23n", + "% shading operators", + "/colordelta {", + " false 0 1 3 index length 1 sub {", + " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {", + " pop true", + " } if", + " } for", + " exch pop exch pop", + "} def", + "/funcCol { func n array astore } def", + "/funcSH {", + " dup 0 eq {", + " true", + " } {", + " dup 6 eq {", + " false", + " } {", + " 4 index 4 index funcCol dup", + " 6 index 4 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " 5 index 5 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " 6 index 8 index funcCol dup", + " 3 1 roll colordelta 3 1 roll", + " colordelta or or or", + " } ifelse", + " } ifelse", + " {", + " 1 add", + " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch", + " 6 index 6 index 4 index 4 index 4 index funcSH", + " 2 index 6 index 6 index 4 index 4 index funcSH", + " 6 index 2 index 4 index 6 index 4 index funcSH", + " 5 3 roll 3 2 roll funcSH pop pop", + " } {", + " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul", + " funcCol sc", + " dup 4 index exch mat transform m", + " 3 index 3 index mat transform l", + " 1 index 3 index mat transform l", + " mat transform l pop pop h f*", + " } ifelse", + "} def", + "/axialCol {", + " dup 0 lt {", + " pop t0", + " } {", + " dup 1 gt {", + " pop t1", + " } {", + " dt mul t0 add", + " } ifelse", + " } ifelse", + " func n array astore", + "} def", + "/axialSH {", + " dup 0 eq {", + " true", + " } {", + " dup 8 eq {", + " false", + " } {", + " 2 index axialCol 2 index axialCol colordelta", + " } ifelse", + " } ifelse", + " {", + " 1 add 3 1 roll 2 copy add 0.5 mul", + " dup 4 3 roll exch 4 index axialSH", + " exch 3 2 roll axialSH", + " } {", + " pop 2 copy add 0.5 mul axialCol sc", + " exch dup dx mul x0 add exch dy mul y0 add", + " 3 2 roll dup dx mul x0 add exch dy mul y0 add", + " dx abs dy abs ge {", + " 2 copy yMin sub dy mul dx div add yMin m", + " yMax sub dy mul dx div add yMax l", + " 2 copy yMax sub dy mul dx div add yMax l", + " yMin sub dy mul dx div add yMin l", + " h f*", + " } {", + " exch 2 copy xMin sub dx mul dy div add xMin exch m", + " xMax sub dx mul dy div add xMax exch l", + " exch 2 copy xMax sub dx mul dy div add xMax exch l", + " xMin sub dx mul dy div add xMin exch l", + " h f*", + " } ifelse", + " } ifelse", + "} def", + "/radialCol {", + " dup t0 lt {", + " pop t0", + " } {", + " dup t1 gt {", + " pop t1", + " } if", + " } ifelse", + " func n array astore", + "} def", + "/radialSH {", + " dup 0 eq {", + " true", + " } {", + " dup 8 eq {", + " false", + " } {", + " 2 index dt mul t0 add radialCol", + " 2 index dt mul t0 add radialCol colordelta", + " } ifelse", + " } ifelse", + " {", + " 1 add 3 1 roll 2 copy add 0.5 mul", + " dup 4 3 roll exch 4 index radialSH", + " exch 3 2 roll radialSH", + " } {", + " pop 2 copy add 0.5 mul dt mul t0 add axialCol sc", + " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " 0 360 arc h", + " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", + " 0 360 arc h f*", + " } ifelse", + "} def", + "~123sn", + "end", + NULL +}; + +static char *cmapProlog[] = { + "/CIDInit /ProcSet findresource begin", + "10 dict begin", + " begincmap", + " /CMapType 1 def", + " /CMapName /Identity-H def", + " /CIDSystemInfo 3 dict dup begin", + " /Registry (Adobe) def", + " /Ordering (Identity) def", + " /Supplement 0 def", + " end def", + " 1 begincodespacerange", + " <0000> ", + " endcodespacerange", + " 0 usefont", + " 1 begincidrange", + " <0000> 0", + " endcidrange", + " endcmap", + " currentdict CMapName exch /CMap defineresource pop", + "end", + "10 dict begin", + " begincmap", + " /CMapType 1 def", + " /CMapName /Identity-V def", + " /CIDSystemInfo 3 dict dup begin", + " /Registry (Adobe) def", + " /Ordering (Identity) def", + " /Supplement 0 def", + " end def", + " /WMode 1 def", + " 1 begincodespacerange", + " <0000> ", + " endcodespacerange", + " 0 usefont", + " 1 begincidrange", + " <0000> 0", + " endcidrange", + " endcmap", + " currentdict CMapName exch /CMap defineresource pop", + "end", + "end", + NULL +}; + +//------------------------------------------------------------------------ +// Fonts +//------------------------------------------------------------------------ + +struct PSSubstFont { + char *psName; // PostScript name + double mWidth; // width of 'm' character +}; + +static char *psFonts[] = { + "Courier", + "Courier-Bold", + "Courier-Oblique", + "Courier-BoldOblique", + "Helvetica", + "Helvetica-Bold", + "Helvetica-Oblique", + "Helvetica-BoldOblique", + "Symbol", + "Times-Roman", + "Times-Bold", + "Times-Italic", + "Times-BoldItalic", + "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} +}; + +// Encoding info for substitute 16-bit font +struct PSFont16Enc { + Ref fontID; + GString *enc; +}; + +//------------------------------------------------------------------------ +// 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; +} + +//------------------------------------------------------------------------ +// DeviceNRecoder +//------------------------------------------------------------------------ + +class DeviceNRecoder: public FilterStream { +public: + + DeviceNRecoder(Stream *strA, int widthA, int heightA, + GfxImageColorMap *colorMapA); + virtual ~DeviceNRecoder(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual int getChar() + { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; } + virtual int lookChar() + { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; } + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } + virtual GBool isBinary(GBool last = gTrue) { return gTrue; } + virtual GBool isEncoder() { return gTrue; } + +private: + + GBool fillBuf(); + + int width, height; + GfxImageColorMap *colorMap; + Function *func; + ImageStream *imgStr; + int buf[gfxColorMaxComps]; + int pixelIdx; + int bufIdx; + int bufSize; +}; + +DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA, + GfxImageColorMap *colorMapA): + FilterStream(strA) { + width = widthA; + height = heightA; + colorMap = colorMapA; + imgStr = NULL; + pixelIdx = 0; + bufIdx = gfxColorMaxComps; + bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getAlt()->getNComps(); + func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getTintTransformFunc(); +} + +DeviceNRecoder::~DeviceNRecoder() { + if (imgStr) { + delete imgStr; + } +} + +void DeviceNRecoder::reset() { + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); +} + +GBool DeviceNRecoder::fillBuf() { + Guchar pixBuf[gfxColorMaxComps]; + GfxColor color; + double x[gfxColorMaxComps], y[gfxColorMaxComps]; + int i; + + if (pixelIdx >= width * height) { + return gFalse; + } + imgStr->getPixel(pixBuf); + colorMap->getColor(pixBuf, &color); + for (i = 0; + i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps(); + ++i) { + x[i] = colToDbl(color.c[i]); + } + func->transform(x, y); + for (i = 0; i < bufSize; ++i) { + buf[i] = (int)(y[i] * 255 + 0.5); + } + bufIdx = 0; + ++pixelIdx; + return gTrue; +} + +//------------------------------------------------------------------------ +// PSOutputDev +//------------------------------------------------------------------------ + +extern "C" { +typedef void (*SignalFunc)(int); +} + +static void outputToFile(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool manualCtrlA, const char *pageRangesA) { + FILE *f; + PSFileType fileTypeA; + + underlayCbk = NULL; + underlayCbkData = NULL; + overlayCbk = NULL; + overlayCbkData = NULL; + + fontIDs = NULL; + fontFileIDs = NULL; + fontFileNames = NULL; + font16Enc = NULL; + xobjStack = NULL; + embFontList = NULL; + customColors = NULL; + haveTextClip = gFalse; + t3String = NULL; + + // open file or pipe + if (!strcmp(fileName, "-")) { + fileTypeA = psStdout; + f = stdout; + } else if (fileName[0] == '|') { + fileTypeA = 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 { + fileTypeA = psFile; + if (!(f = fopen(fileName, "w"))) { + error(-1, "Couldn't open PostScript file '%s'", fileName); + ok = gFalse; + return; + } + } + + init(outputToFile, f, fileTypeA, + xrefA, catalog, firstPage, lastPage, modeA, + imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA, pageRangesA); +} + +PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, + XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool manualCtrlA, const char *pageRangesA) { + underlayCbk = NULL; + underlayCbkData = NULL; + overlayCbk = NULL; + overlayCbkData = NULL; + + fontIDs = NULL; + fontFileIDs = NULL; + fontFileNames = NULL; + font16Enc = NULL; + xobjStack = NULL; + embFontList = NULL; + customColors = NULL; + haveTextClip = gFalse; + t3String = NULL; + + init(outputFuncA, outputStreamA, psGeneric, + xrefA, catalog, firstPage, lastPage, modeA, + imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA, pageRangesA); +} + +void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool manualCtrlA, const char *pageRangesA) { + Page *page; + PDFRectangle *box; + + // initialize + ok = gTrue; + outputFunc = outputFuncA; + outputStream = outputStreamA; + fileType = fileTypeA; + xref = xrefA; + level = globalParams->getPSLevel(); + mode = modeA; + paperWidth = globalParams->getPSPaperWidth(); + paperHeight = globalParams->getPSPaperHeight(); + imgLLX = imgLLXA; + imgLLY = imgLLYA; + imgURX = imgURXA; + imgURY = imgURYA; + pageRanges = pageRangesA; + if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) { + globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY); + } + if (paperWidth < 0 || paperHeight < 0) { + // this check is needed in case the document has zero pages + if (firstPage > 0 && firstPage <= catalog->getNumPages()) { + page = catalog->getPage(firstPage); + paperWidth = (int)ceil(page->getMediaWidth()); + paperHeight = (int)ceil(page->getMediaHeight()); + } else { + paperWidth = 1; + paperHeight = 1; + } + imgLLX = imgLLY = 0; + imgURX = paperWidth; + imgURY = paperHeight; + } + manualCtrl = manualCtrlA; + if (mode == psModeForm) { + lastPage = firstPage; + } + processColors = 0; + inType3Char = gFalse; + +#if OPI_SUPPORT + // initialize OPI nesting levels + opi13Nest = 0; + opi20Nest = 0; +#endif + + tx0 = ty0 = 0; + xScale0 = yScale0 = 0; + rotate0 = -1; + clipLLX0 = clipLLY0 = 0; + clipURX0 = clipURY0 = -1; + + // initialize fontIDs, fontFileIDs, and fontFileNames lists + fontIDSize = 64; + fontIDLen = 0; + fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref)); + fontFileIDSize = 64; + fontFileIDLen = 0; + fontFileIDs = (Ref *)gmallocn(fontFileIDSize, sizeof(Ref)); + fontFileNameSize = 64; + fontFileNameLen = 0; + fontFileNames = (GString **)gmallocn(fontFileNameSize, sizeof(GString *)); + nextTrueTypeNum = 0; + font16EncLen = 0; + font16EncSize = 0; + + xobjStack = new GList(); + numSaves = 0; + numTilingPatterns = 0; + nextFunc = 0; + + // initialize embedded font resource comment list + embFontList = new GString(); + + if (!manualCtrl) { + // this check is needed in case the document has zero pages + if (firstPage > 0 && firstPage <= catalog->getNumPages()) { + writeHeader(firstPage, lastPage, + catalog->getPage(firstPage)->getMediaBox(), + catalog->getPage(firstPage)->getCropBox(), + catalog->getPage(firstPage)->getRotate()); + } else { + box = new PDFRectangle(0, 0, 1, 1); + writeHeader(firstPage, lastPage, box, box, 0); + delete box; + } + if (mode != psModeForm) { + writePS("%%BeginProlog\n"); + } + writeXpdfProcset(); + if (mode != psModeForm) { + writePS("%%EndProlog\n"); + writePS("%%BeginSetup\n"); + } + writeDocSetup(catalog, firstPage, lastPage); + if (mode != psModeForm) { + writePS("%%EndSetup\n"); + } + } + + // initialize sequential page number + seqPage = 1; +} + +PSOutputDev::~PSOutputDev() { + PSOutCustomColor *cc; + int i; + + if (ok) { + if (!manualCtrl) { + writePS("%%Trailer\n"); + writeTrailer(); + if (mode != psModeForm) { + writePS("%%EOF\n"); + } + } + if (fileType == psFile) { +#ifdef MACOS + ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); +#endif + fclose((FILE *)outputStream); + } +#ifdef HAVE_POPEN + else if (fileType == psPipe) { + pclose((FILE *)outputStream); +#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); + } + if (font16Enc) { + for (i = 0; i < font16EncLen; ++i) { + delete font16Enc[i].enc; + } + gfree(font16Enc); + } + if (xobjStack) { + delete xobjStack; + } + while (customColors) { + cc = customColors; + customColors = cc->next; + delete cc; + } +} + +void PSOutputDev::writeHeader(int firstPage, int lastPage, + PDFRectangle *mediaBox, PDFRectangle *cropBox, + int pageRotate) { + Object info, obj1; + double x1, y1, x2, y2; + GString *s; + int i; + + switch (mode) { + case psModePS: + writePS("%!PS-Adobe-3.0\n"); + break; + case psModeEPS: + writePS("%!PS-Adobe-3.0 EPSF-3.0\n"); + break; + case psModeForm: + writePS("%!PS-Adobe-3.0 Resource-Form\n"); + break; + } + + writePSFmt("% Produced by xpdf/pdftops %s\n", xpdfVersion); + xref->getDocInfo(&info); + if (info.dictLookup("Creator", &obj1)->isString()) { + writePS("%%Creator: "); + s = obj1.getString(); + if ((s->getChar(0) & 0xff) == 0xfe && + (s->getChar(1) & 0xff) == 0xff) { + // Convert UTF-16 to UTF-8... + for (i = 2; i < s->getLength() && i < 400; i += 2) { + int ch = ((s->getChar(i) & 255) << 8) | (s->getChar(i + 1) & 255); + + if (ch >= 0xd800 && ch <= 0xdbff) { + // Multi-word UTF-16 char... + i += 2; + int lch = ((s->getChar(i) & 255) << 8) | (s->getChar(i + 1) & 255); + + if (lch < 0xdc00 || lch >= 0xdfff) continue; + + ch = (((ch & 0x3ff) << 10) | (lch & 0x3ff)) + 0x10000; + } + + if (ch < 0x80) + { + /* + * Single byte ASCII... + */ + + writePSChar(ch); + } + else if (ch < 0x800) + { + /* + * Two-byte UTF-8... + */ + + writePSChar(0xc0 | (ch >> 6)); + writePSChar(0x80 | (ch & 0x3f)); + } + else if (ch < 0x10000) + { + /* + * Three-byte UTF-8... + */ + + writePSChar(0xe0 | (ch >> 12)); + writePSChar(0x80 | ((ch >> 6) & 0x3f)); + writePSChar(0x80 | (ch & 0x3f)); + } + else + { + /* + * Four-byte UTF-8... + */ + + writePSChar(0xf0 | (ch >> 18)); + writePSChar(0x80 | ((ch >> 12) & 0x3f)); + writePSChar(0x80 | ((ch >> 6) & 0x3f)); + writePSChar(0x80 | (ch & 0x3f)); + } + } + } else { + for (i = 0; i < s->getLength() && i < 200; ++i) { + writePSChar(s->getChar(i)); + } + } + writePS("\n"); + } + obj1.free(); + if (info.dictLookup("Title", &obj1)->isString()) { + writePS("%%Title: "); + s = obj1.getString(); + if ((s->getChar(0) & 0xff) == 0xfe && + (s->getChar(1) & 0xff) == 0xff) { + // cheap Unicode-to-ASCII conversion + for (i = 3; i < s->getLength() && i < 400; i += 2) { + writePSChar(s->getChar(i)); + } + } else { + for (i = 0; i < s->getLength() && i < 200; ++i) { + writePSChar(s->getChar(i)); + } + } + writePS("\n"); + } + obj1.free(); + info.free(); + writePSFmt("%%%%LanguageLevel: %d\n", + (level == psLevel1 || level == psLevel1Sep) ? 1 : + (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); + if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { + writePS("%%DocumentProcessColors: (atend)\n"); + writePS("%%DocumentCustomColors: (atend)\n"); + } + writePS("%%DocumentSuppliedResources: (atend)\n"); + + switch (mode) { + case psModePS: + writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n", + paperWidth, paperHeight); + writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth, paperHeight); + writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1); + writePS("%%EndComments\n"); + writePS("%%BeginDefaults\n"); + writePS("%%PageMedia: plain\n"); + writePS("%%EndDefaults\n"); + break; + case psModeEPS: + epsX1 = cropBox->x1; + epsY1 = cropBox->y1; + epsX2 = cropBox->x2; + epsY2 = cropBox->y2; + if (pageRotate == 0 || pageRotate == 180) { + x1 = epsX1; + y1 = epsY1; + x2 = epsX2; + y2 = epsY2; + } else { // pageRotate == 90 || pageRotate == 270 + x1 = 0; + y1 = 0; + x2 = epsY2 - epsY1; + y2 = epsX2 - epsX1; + } + writePSFmt("%%%%BoundingBox: %d %d %d %d\n", + (int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2)); + if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) || + floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) { + writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", x1, y1, x2, y2); + } + writePS("%%EndComments\n"); + break; + case psModeForm: + writePS("%%EndComments\n"); + writePS("32 dict dup begin\n"); + writePSFmt("/BBox [%d %d %d %d] def\n", + (int)floor(mediaBox->x1), (int)floor(mediaBox->y1), + (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2)); + writePS("/FormType 1 def\n"); + writePS("/Matrix [1 0 0 1 0 0] def\n"); + break; + } +} + +void PSOutputDev::writeXpdfProcset() { + GBool lev1, lev2, lev3, sep, nonSep; + char **p; + char *q; + + writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion); + lev1 = lev2 = lev3 = sep = nonSep = gTrue; + for (p = prolog; *p; ++p) { + if ((*p)[0] == '~') { + lev1 = lev2 = lev3 = sep = nonSep = gFalse; + for (q = *p + 1; *q; ++q) { + switch (*q) { + case '1': lev1 = gTrue; break; + case '2': lev2 = gTrue; break; + case '3': lev3 = gTrue; break; + case 's': sep = gTrue; break; + case 'n': nonSep = gTrue; break; + } + } + } else if ((level == psLevel1 && lev1 && nonSep) || + (level == psLevel1Sep && lev1 && sep) || + (level == psLevel2 && lev2 && nonSep) || + (level == psLevel2Sep && lev2 && sep) || + (level == psLevel3 && lev3 && nonSep) || + (level == psLevel3Sep && lev3 && sep)) { + writePSFmt("%s\n", *p); + } + } + writePS("%%EndResource\n"); + + if (level >= psLevel3) { + for (p = cmapProlog; *p; ++p) { + writePSFmt("%s\n", *p); + } + } +} + +void PSOutputDev::writeDocSetup(Catalog *catalog, + int firstPage, int lastPage) { + Page *page; + Dict *resDict; + Annots *annots; + Object obj1, obj2; + int pg, i; + + if (mode == psModeForm) { + // swap the form and xpdf dicts + writePS("xpdf end begin dup begin\n"); + } else { + writePS("xpdf begin\n"); + } + for (pg = firstPage; pg <= lastPage; ++pg) { + page = catalog->getPage(pg); + if ((resDict = page->getResourceDict())) { + setupResources(resDict); + } + annots = new Annots(xref, catalog, page->getAnnots(&obj1)); + obj1.free(); + for (i = 0; i < annots->getNumAnnots(); ++i) { + if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) { + obj1.streamGetDict()->lookup("Resources", &obj2); + if (obj2.isDict()) { + setupResources(obj2.getDict()); + } + obj2.free(); + } + obj1.free(); + } + delete annots; + } + if (mode != psModeForm) { + if (mode != psModeEPS && !manualCtrl) { + writePSFmt("%d %d %s pdfSetup\n", + paperWidth, paperHeight, + globalParams->getPSDuplex() ? "true" : "false"); + } +#if OPI_SUPPORT + if (globalParams->getPSOPI()) { + writePS("/opiMatrix matrix currentmatrix def\n"); + } +#endif + } +} + +void PSOutputDev::writePageTrailer() { + if (mode != psModeForm) { + writePS("pdfEndPage\n"); + } +} + +void PSOutputDev::writeTrailer() { + PSOutCustomColor *cc; + + if (mode == psModeForm) { + writePS("/Foo exch /Form defineresource pop\n"); + } else { + writePS("end\n"); + writePS("%%DocumentSuppliedResources:\n"); + writePS(embFontList->getCString()); + if (level == psLevel1Sep || level == psLevel2Sep || + level == psLevel3Sep) { + 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) { + writePSFmt(" (%s)", cc->name->getCString()); + } + writePS("\n"); + writePS("%%CMYKCustomColor:\n"); + for (cc = customColors; cc; cc = cc->next) { + writePSFmt("%%%%+ %g %g %g %g (%s)\n", + cc->c, cc->m, cc->y, cc->k, cc->name->getCString()); + } + } + } +} + +void PSOutputDev::setupResources(Dict *resDict) { + Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj; + Ref ref0, ref1; + GBool skip; + int i, j; + + setupFonts(resDict); + setupImages(resDict); + + //----- recursively scan XObjects + resDict->lookup("XObject", &xObjDict); + if (xObjDict.isDict()) { + for (i = 0; i < xObjDict.dictGetLength(); ++i) { + + // avoid infinite recursion on XObjects + skip = gFalse; + if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) { + ref0 = xObjRef.getRef(); + for (j = 0; j < xobjStack->getLength(); ++j) { + ref1 = *(Ref *)xobjStack->get(j); + if (ref1.num == ref0.num && ref1.gen == ref0.gen) { + skip = gTrue; + break; + } + } + if (!skip) { + xobjStack->append(&ref0); + } + } + if (!skip) { + + // process the XObject's resource dictionary + xObjDict.dictGetVal(i, &xObj); + if (xObj.isStream()) { + xObj.streamGetDict()->lookup("Resources", &resObj); + if (resObj.isDict()) { + setupResources(resObj.getDict()); + } + resObj.free(); + } + xObj.free(); + } + + if (xObjRef.isRef() && !skip) { + xobjStack->del(xobjStack->getLength() - 1); + } + xObjRef.free(); + } + } + xObjDict.free(); + + //----- recursively scan Patterns + resDict->lookup("Pattern", &patDict); + if (patDict.isDict()) { + inType3Char = gTrue; + for (i = 0; i < patDict.dictGetLength(); ++i) { + + // avoid infinite recursion on Patterns + skip = gFalse; + if ((patDict.dictGetValNF(i, &patRef)->isRef())) { + ref0 = patRef.getRef(); + for (j = 0; j < xobjStack->getLength(); ++j) { + ref1 = *(Ref *)xobjStack->get(j); + if (ref1.num == ref0.num && ref1.gen == ref0.gen) { + skip = gTrue; + break; + } + } + if (!skip) { + xobjStack->append(&ref0); + } + } + if (!skip) { + + // process the Pattern's resource dictionary + patDict.dictGetVal(i, &pat); + if (pat.isStream()) { + pat.streamGetDict()->lookup("Resources", &resObj); + if (resObj.isDict()) { + setupResources(resObj.getDict()); + } + resObj.free(); + } + pat.free(); + } + + if (patRef.isRef() && !skip) { + xobjStack->del(xobjStack->getLength() - 1); + } + patRef.free(); + } + inType3Char = gFalse; + } + patDict.free(); +} + +void PSOutputDev::setupFonts(Dict *resDict) { + Object obj1, obj2; + Ref r; + GfxFontDict *gfxFontDict; + GfxFont *font; + int i; + + gfxFontDict = NULL; + resDict->lookupNF("Font", &obj1); + if (obj1.isRef()) { + obj1.fetch(xref, &obj2); + if (obj2.isDict()) { + r = obj1.getRef(); + gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict()); + } + obj2.free(); + } else if (obj1.isDict()) { + gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict()); + } + if (gfxFontDict) { + for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { + if ((font = gfxFontDict->getFont(i))) { + setupFont(font, resDict); + } + } + delete gfxFontDict; + } + obj1.free(); +} + +void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { + Ref fontFileID; + GString *name; + PSFontParam *fontParam; + GString *psName; + char type3Name[64], buf[16]; + GBool subst; + UnicodeMap *uMap; + char *charName; + double xs, ys; + 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 *)greallocn(fontIDs, fontIDSize, sizeof(Ref)); + } + fontIDs[fontIDLen++] = *font->getID(); + + xs = ys = 1; + subst = gFalse; + + // check for resident 8-bit font + if (font->getName() && + (fontParam = globalParams->getPSFont(font->getName()))) { + psName = new GString(fontParam->psFontName->getCString()); + + // check for embedded Type 1 font + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1 && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + setupEmbeddedType1Font(&fontFileID, psName); + + // check for embedded Type 1C font + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1C && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + setupEmbeddedType1CFont(font, &fontFileID, psName); + + // check for external Type 1 font file + } else if (globalParams->getPSEmbedType1() && + font->getType() == fontType1 && + font->getExtFontFile()) { + // this assumes that the PS font name matches the PDF font name + psName = font->getName()->copy(); + setupExternalType1Font(font->getExtFontFile(), psName); + + // check for embedded TrueType font + } else if (globalParams->getPSEmbedTrueType() && + font->getType() == fontTrueType && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + setupEmbeddedTrueTypeFont(font, &fontFileID, psName); + + // check for external TrueType font file + } else if (globalParams->getPSEmbedTrueType() && + font->getType() == fontTrueType && + font->getExtFontFile()) { + psName = filterPSName(font->getName()); + setupExternalTrueTypeFont(font, psName); + + // check for embedded CID PostScript font + } else if (globalParams->getPSEmbedCIDPostScript() && + font->getType() == fontCIDType0C && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + setupEmbeddedCIDType0Font(font, &fontFileID, psName); + + // check for embedded CID TrueType font + } else if (globalParams->getPSEmbedCIDTrueType() && + font->getType() == fontCIDType2 && + font->getEmbeddedFontID(&fontFileID)) { + psName = filterPSName(font->getEmbeddedFontName()); + //~ should check to see if font actually uses vertical mode + setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName, gTrue); + + } else if (font->getType() == fontType3) { + sprintf(type3Name, "T3_%d_%d", + font->getID()->num, font->getID()->gen); + psName = new GString(type3Name); + setupType3Font(font, psName, parentResDict); + + // do 8-bit font substitution + } else if (!font->isCIDFont()) { + subst = gTrue; + name = font->getName(); + psName = NULL; + if (name) { + for (i = 0; psFonts[i]; ++i) { + if (name->cmp(psFonts[i]) == 0) { + psName = new GString(psFonts[i]); + 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 = new GString(psSubstFonts[i].psName); + for (code = 0; code < 256; ++code) { + if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) && + charName[0] == 'm' && charName[1] == '\0') { + break; + } + } + if (code < 256) { + w1 = ((Gfx8BitFont *)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; + } + } + + // do 16-bit font substitution + } else if ((fontParam = globalParams-> + getPSFont16(font->getName(), + ((GfxCIDFont *)font)->getCollection(), + font->getWMode()))) { + subst = gTrue; + psName = fontParam->psFontName->copy(); + if (font16EncLen >= font16EncSize) { + font16EncSize += 16; + font16Enc = (PSFont16Enc *)greallocn(font16Enc, + font16EncSize, sizeof(PSFont16Enc)); + } + font16Enc[font16EncLen].fontID = *font->getID(); + font16Enc[font16EncLen].enc = fontParam->encoding->copy(); + if ((uMap = globalParams->getUnicodeMap(font16Enc[font16EncLen].enc))) { + uMap->decRefCnt(); + ++font16EncLen; + } else { + error(-1, "Couldn't find Unicode map for 16-bit font encoding '%s'", + font16Enc[font16EncLen].enc->getCString()); + } + + // give up - can't do anything with this font + } else { + error(-1, "Couldn't find a font to substitute for '%s' ('%s' character collection)", + font->getName() ? font->getName()->getCString() : "(unnamed)", + ((GfxCIDFont *)font)->getCollection() + ? ((GfxCIDFont *)font)->getCollection()->getCString() + : "(unknown)"); + return; + } + + // generate PostScript code to set up the font + if (font->isCIDFont()) { + if (level == psLevel3 || level == psLevel3Sep) { + writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n", + font->getID()->num, font->getID()->gen, psName->getCString(), + font->getWMode()); + } else { + writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n", + font->getID()->num, font->getID()->gen, psName->getCString(), + font->getWMode()); + } + } else { + writePSFmt("/F%d_%d /%s %g %g\n", + font->getID()->num, font->getID()->gen, psName->getCString(), + xs, ys); + for (i = 0; i < 256; i += 8) { + writePSFmt((i == 0) ? "[ " : " "); + for (j = 0; j < 8; ++j) { + if (font->getType() == fontTrueType && + !subst && + !((Gfx8BitFont *)font)->getHasEncoding()) { + sprintf(buf, "c%02x", i+j); + charName = buf; + } else { + charName = ((Gfx8BitFont *)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("/"); + writePSName(charName ? charName : (char *)".notdef"); + // the empty name is legal in PDF and PostScript, but PostScript + // uses a double-slash (//...) for "immediately evaluated names", + // so we need to add a space character here + if (charName && !charName[0]) { + writePS(" "); + } + } + writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n"); + } + writePS("pdfMakeFont\n"); + } + + delete psName; +} + +void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) { + static char hexChar[17] = "0123456789abcdef"; + Object refObj, strObj, obj1, obj2, obj3; + Dict *dict; + int length1, length2, length3; + 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 *)greallocn(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); + dict->lookup("Length3", &obj3); + if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) { + error(-1, "Missing length fields in embedded font stream dictionary"); + obj1.free(); + obj2.free(); + obj3.free(); + goto err1; + } + length1 = obj1.getInt(); + length2 = obj2.getInt(); + length3 = obj3.getInt(); + obj1.free(); + obj2.free(); + obj3.free(); + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // copy ASCII portion of font + strObj.streamReset(); + for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) { + writePSChar(c); + } + + // 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) { + writePSChar(hexChar[(start[i] >> 4) & 0x0f]); + writePSChar(hexChar[start[i] & 0x0f]); + } + // if Length2 is incorrect (too small), font data gets chopped, so + // we take a few extra characters from the trailer just in case +// length2 += length3 >= 8 ? 8 : length3; + while (i < length2) { + if ((c = strObj.streamGetChar()) == EOF) { + break; + } + writePSChar(hexChar[(c >> 4) & 0x0f]); + writePSChar(hexChar[c & 0x0f]); + if (++i % 32 == 0) { + writePSChar('\n'); + } + } + if (i % 32 > 0) { + writePSChar('\n'); + } + + // already in ASCII format -- just copy it + } else { + for (i = 0; i < 4; ++i) { + writePSChar(start[i]); + } + for (i = 4; i < length2; ++i) { + if ((c = strObj.streamGetChar()) == EOF) { + break; + } + writePSChar(c); + } + } + + // 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::setupExternalType1Font(GString *fileName, GString *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 **)greallocn(fontFileNames, + fontFileNameSize, sizeof(GString *)); + } + fontFileNames[fontFileNameLen++] = fileName->copy(); + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + 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) { + writePSChar(c); + } + fclose(fontFile); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, + GString *psName) { + char *fontBuf; + int fontLen; + FoFiType1C *ffT1C; + 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 *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 1 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { + ffT1C->convertToType1(NULL, gTrue, outputFunc, outputStream); + delete ffT1C; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, + GString *psName) { + char unique[32]; + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + Gushort *codeToGID; + 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) { + sprintf(unique, "_%d", nextTrueTypeNum++); + psName->append(unique); + break; + } + } + + // add entry to fontFileIDs list + if (i == fontFileIDLen) { + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + } + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 42 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); + ffTT->convertToType42(psName->getCString(), + ((Gfx8BitFont *)font)->getHasEncoding() + ? ((Gfx8BitFont *)font)->getEncoding() + : (char **)NULL, + codeToGID, outputFunc, outputStream); + gfree(codeToGID); + delete ffTT; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) { + char unique[32]; + GString *fileName; + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + Gushort *codeToGID; + int i; + + // check if font is already embedded + fileName = font->getExtFontFile(); + for (i = 0; i < fontFileNameLen; ++i) { + if (!fontFileNames[i]->cmp(fileName)) { + sprintf(unique, "_%d", nextTrueTypeNum++); + psName->append(unique); + break; + } + } + + // add entry to fontFileNames list + if (i == fontFileNameLen) { + if (fontFileNameLen >= fontFileNameSize) { + fontFileNameSize += 64; + fontFileNames = + (GString **)greallocn(fontFileNames, + fontFileNameSize, sizeof(GString *)); + } + fontFileNames[fontFileNameLen++] = fileName->copy(); + } + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 42 font + fontBuf = font->readExtFontFile(&fontLen); + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); + ffTT->convertToType42(psName->getCString(), + ((Gfx8BitFont *)font)->getHasEncoding() + ? ((Gfx8BitFont *)font)->getEncoding() + : (char **)NULL, + codeToGID, outputFunc, outputStream); + delete ffTT; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, + GString *psName) { + char *fontBuf; + int fontLen; + FoFiType1C *ffT1C; + 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 *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 0 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream); + } + delete ffT1C; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, + GString *psName, + GBool needVerticalMetrics) { + char unique[32]; + char *fontBuf; + int fontLen; + FoFiTrueType *ffTT; + 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) { + sprintf(unique, "_%d", nextTrueTypeNum++); + psName->append(unique); + break; + } + } + + // add entry to fontFileIDs list + if (fontFileIDLen >= fontFileIDSize) { + fontFileIDSize += 64; + fontFileIDs = (Ref *)greallocn(fontFileIDs, fontFileIDSize, sizeof(Ref)); + } + fontFileIDs[fontFileIDLen++] = *id; + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // convert it to a Type 0 font + fontBuf = font->readEmbFontFile(xref, &fontLen); + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + ffTT->convertToCIDType2(psName->getCString(), + ((GfxCIDFont *)font)->getCIDToGID(), + ((GfxCIDFont *)font)->getCIDToGIDLen(), + needVerticalMetrics, + outputFunc, outputStream); + } else { + // otherwise: use a non-CID composite font + ffTT->convertToType0(psName->getCString(), + ((GfxCIDFont *)font)->getCIDToGID(), + ((GfxCIDFont *)font)->getCIDToGIDLen(), + needVerticalMetrics, + outputFunc, outputStream); + } + delete ffTT; + } + gfree(fontBuf); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupType3Font(GfxFont *font, GString *psName, + Dict *parentResDict) { + Dict *resDict; + Dict *charProcs; + Object charProc; + Gfx *gfx; + PDFRectangle box; + double *m; + char buf[256]; + int i; + + // set up resources used by font + if ((resDict = ((Gfx8BitFont *)font)->getResources())) { + inType3Char = gTrue; + setupResources(resDict); + inType3Char = gFalse; + } else { + resDict = parentResDict; + } + + // beginning comment + writePSFmt("%%%%BeginResource: font %s\n", psName->getCString()); + embFontList->append("%%+ font "); + embFontList->append(psName->getCString()); + embFontList->append("\n"); + + // font dictionary + writePS("8 dict begin\n"); + writePS("/FontType 3 def\n"); + m = font->getFontMatrix(); + writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n", + m[0], m[1], m[2], m[3], m[4], m[5]); + m = font->getFontBBox(); + writePSFmt("/FontBBox [%g %g %g %g] def\n", + m[0], m[1], m[2], m[3]); + writePS("/Encoding 256 array def\n"); + writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); + writePS("/BuildGlyph {\n"); + writePS(" exch /CharProcs get exch\n"); + writePS(" 2 copy known not { pop /.notdef } if\n"); + writePS(" get exec\n"); + writePS("} bind def\n"); + writePS("/BuildChar {\n"); + writePS(" 1 index /Encoding get exch get\n"); + writePS(" 1 index /BuildGlyph get exec\n"); + writePS("} bind def\n"); + if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) { + writePSFmt("/CharProcs %d dict def\n", charProcs->getLength()); + writePS("CharProcs begin\n"); + box.x1 = m[0]; + box.y1 = m[1]; + box.x2 = m[2]; + box.y2 = m[3]; + gfx = new Gfx(xref, this, resDict, &box, NULL); + inType3Char = gTrue; + t3Cacheable = gFalse; + for (i = 0; i < charProcs->getLength(); ++i) { + writePS("/"); + writePSName(charProcs->getKey(i)); + writePS(" {\n"); + gfx->display(charProcs->getVal(i, &charProc)); + charProc.free(); + if (t3String) { + if (t3Cacheable) { + sprintf(buf, "%g %g %g %g %g %g setcachedevice\n", + t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY); + } else { + sprintf(buf, "%g %g setcharwidth\n", t3WX, t3WY); + } + (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, t3String->getCString(), + t3String->getLength()); + delete t3String; + t3String = NULL; + } + (*outputFunc)(outputStream, "Q\n", 2); + writePS("} def\n"); + } + inType3Char = gFalse; + delete gfx; + writePS("end\n"); + } + writePS("currentdict end\n"); + writePSFmt("/%s exch definefont pop\n", psName->getCString()); + + // ending comment + writePS("%%EndResource\n"); +} + +void PSOutputDev::setupImages(Dict *resDict) { + Object xObjDict, xObj, xObjRef, subtypeObj; + int i; + + if (!(mode == psModeForm || inType3Char)) { + 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) { + GBool useASCIIHex; + int c; + int size, line, col, i; + + // construct an encoder stream + useASCIIHex = level == psLevel1 || level == psLevel1Sep || + globalParams->getPSASCIIHex(); + if (useASCIIHex) { + str = new ASCIIHexEncoder(str); + } else { + 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 == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + if (c == 'z') { + ++col; + } else { + ++col; + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + ++col; + } + } + if (col > 225) { + ++size; + col = 0; + } + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + ++size; + writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen); + str->close(); + + // write the data into the array + str->reset(); + line = col = 0; + writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~")); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + if (c == 'z') { + writePSChar(c); + ++col; + } else { + writePSChar(c); + ++col; + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + writePSChar(c); + ++col; + } + } + // each line is: "dup nnnnn <~...data...~> put" + // 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((char *)(useASCIIHex ? "> put\n" : "~> put\n")); + ++line; + writePSFmt((char *)(useASCIIHex ? "dup %d <" : "dup %d <~"), line); + col = 0; + } + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); + writePS("pop\n"); + str->close(); + + delete str; +} + +GBool PSOutputDev::startPage(int pageNum, GfxState *state) { + int x1, y1, x2, y2, width, height; + int imgWidth, imgHeight, imgWidth2, imgHeight2; + GBool landscape; + + + if (mode == psModePS) { + writePSFmt("%%%%Page: %d %d\n", pageNum, seqPage); + writePS("%%BeginPageSetup\n"); + } + + // underlays + if (underlayCbk) { + (*underlayCbk)(this, underlayCbkData); + } + if (overlayCbk) { + saveState(NULL); + } + + switch (mode) { + + case psModePS: + // rotate, translate, and scale page + imgWidth = imgURX - imgLLX; + imgHeight = imgURY - imgLLY; + x1 = (int)floor(state->getX1()); + y1 = (int)floor(state->getY1()); + x2 = (int)ceil(state->getX2()); + y2 = (int)ceil(state->getY2()); + width = x2 - x1; + height = y2 - y1; + tx = ty = 0; + // rotation and portrait/landscape mode + if (rotate0 >= 0) { + rotate = (360 - rotate0) % 360; + landscape = gFalse; + } else { + rotate = (360 - state->getRotate()) % 360; + if (rotate == 0 || rotate == 180) { + if (width > height && width > imgWidth) { + rotate += 90; + landscape = gTrue; + } else { + landscape = gFalse; + } + } else { // rotate == 90 || rotate == 270 + if (height > width && height > imgWidth) { + rotate = 270 - rotate; + landscape = gTrue; + } else { + landscape = gFalse; + } + } + } + writePSFmt("%%%%PageOrientation: %s\n", + landscape ? "Landscape" : "Portrait"); + writePS("pdfStartPage\n"); + if (rotate == 0) { + imgWidth2 = imgWidth; + imgHeight2 = imgHeight; + } else if (rotate == 90) { + writePS("90 rotate\n"); + ty = -imgWidth; + imgWidth2 = imgHeight; + imgHeight2 = imgWidth; + } else if (rotate == 180) { + writePS("180 rotate\n"); + imgWidth2 = imgWidth; + imgHeight2 = imgHeight; + tx = -imgWidth; + ty = -imgHeight; + } else { // rotate == 270 + writePS("270 rotate\n"); + tx = -imgHeight; + imgWidth2 = imgHeight; + imgHeight2 = imgWidth; + } + // shrink or expand + if (xScale0 > 0 && yScale0 > 0) { + xScale = xScale0; + yScale = yScale0; + } else if ((globalParams->getPSShrinkLarger() && + (width > imgWidth2 || height > imgHeight2)) || + (globalParams->getPSExpandSmaller() && + (width < imgWidth2 && height < imgHeight2))) { + xScale = (double)imgWidth2 / (double)width; + yScale = (double)imgHeight2 / (double)height; + if (yScale < xScale) { + xScale = yScale; + } else { + yScale = xScale; + } + } else { + xScale = yScale = 1; + paperWidth = width; + paperHeight = height; + } + + // deal with odd bounding boxes or clipping + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + tx -= xScale * clipLLX0; + ty -= yScale * clipLLY0; + } else { + tx -= xScale * x1; + ty -= yScale * y1; + } + // center + if (globalParams->getPSCenter()) { + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2; + ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2; + } else { + tx += (imgWidth2 - xScale * width) / 2; + ty += (imgHeight2 - yScale * height) / 2; + } + } + tx += rotate == 0 ? imgLLX + tx0 : imgLLY + ty0; + ty += rotate == 0 ? imgLLY + ty0 : -(imgLLX + tx0); + if (tx != 0 || ty != 0) { + writePSFmt("%g %g translate\n", tx, ty); + } + if (xScale != 1 || yScale != 1) { + writePSFmt("%0.4f %0.4f scale\n", xScale, xScale); + } + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + writePSFmt("%g %g %g %g re W\n", + clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0); + } else { + writePSFmt("%d %d %d %d re W\n", x1, y1, x2 - x1, y2 - y1); + } + + writePS("%%EndPageSetup\n"); + ++seqPage; + break; + + case psModeEPS: + writePS("pdfStartPage\n"); + tx = ty = 0; + rotate = (360 - state->getRotate()) % 360; + if (rotate == 0) { + } else if (rotate == 90) { + writePS("90 rotate\n"); + tx = -epsX1; + ty = -epsY2; + } else if (rotate == 180) { + writePS("180 rotate\n"); + tx = -(epsX1 + epsX2); + ty = -(epsY1 + epsY2); + } else { // rotate == 270 + writePS("270 rotate\n"); + tx = -epsX2; + ty = -epsY1; + } + if (tx != 0 || ty != 0) { + writePSFmt("%g %g translate\n", tx, ty); + } + xScale = yScale = 1; + break; + + case psModeForm: + writePS("/PaintProc {\n"); + writePS("begin xpdf begin\n"); + writePS("pdfStartPage\n"); + tx = ty = 0; + xScale = yScale = 1; + rotate = 0; + break; + } + + if (!checkRange(pageNum)) + return (gFalse); + else + return (gTrue); +} + +void PSOutputDev::endPage() { + if (overlayCbk) { + restoreState(NULL); + (*overlayCbk)(this, overlayCbkData); + } + + if (mode == psModeForm) { + writePS("pdfEndPage\n"); + writePS("end end\n"); + writePS("} def\n"); + writePS("end end\n"); + } else { + if (!manualCtrl) { + writePS("showpage\n"); + } + writePS("%%PageTrailer\n"); + writePageTrailer(); + } +} + +void PSOutputDev::saveState(GfxState *state) { + writePS("q\n"); + ++numSaves; +} + +void PSOutputDev::restoreState(GfxState *state) { + writePS("Q\n"); + --numSaves; +} + +void PSOutputDev::updateCTM(GfxState *state, double m11, double m12, + double m21, double m22, double m31, double m32) { + writePSFmt("[%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) { + writePSFmt("%g%s", + dash[i] == 0 ? 1 : dash[i], + (i == length-1) ? "" : " "); + } + writePSFmt("] %g d\n", start); +} + +void PSOutputDev::updateFlatness(GfxState *state) { + writePSFmt("%d i\n", state->getFlatness()); +} + +void PSOutputDev::updateLineJoin(GfxState *state) { + writePSFmt("%d j\n", state->getLineJoin()); +} + +void PSOutputDev::updateLineCap(GfxState *state) { + writePSFmt("%d J\n", state->getLineCap()); +} + +void PSOutputDev::updateMiterLimit(GfxState *state) { + writePSFmt("%g M\n", state->getMiterLimit()); +} + +void PSOutputDev::updateLineWidth(GfxState *state) { + writePSFmt("%g w\n", state->getLineWidth()); +} + +void PSOutputDev::updateFillColorSpace(GfxState *state) { + switch (level) { + case psLevel1: + case psLevel1Sep: + break; + case psLevel2: + case psLevel3: + if (state->getFillColorSpace()->getMode() != csPattern) { + dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse); + writePS(" cs\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + break; + } +} + +void PSOutputDev::updateStrokeColorSpace(GfxState *state) { + switch (level) { + case psLevel1: + case psLevel1Sep: + break; + case psLevel2: + case psLevel3: + if (state->getStrokeColorSpace()->getMode() != csPattern) { + dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse); + writePS(" CS\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + break; + } +} + +void PSOutputDev::updateFillColor(GfxState *state) { + GfxColor color; + GfxColor *colorPtr; + GfxGray gray; + GfxCMYK cmyk; + GfxSeparationColorSpace *sepCS; + double c, m, y, k; + int i; + + switch (level) { + case psLevel1: + state->getFillGray(&gray); + writePSFmt("%g g\n", colToDbl(gray)); + break; + case psLevel1Sep: + state->getFillCMYK(&cmyk); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("%g %g %g %g k\n", c, m, y, k); + addProcessColor(c, m, y, k); + break; + case psLevel2: + case psLevel3: + if (state->getFillColorSpace()->getMode() != csPattern) { + colorPtr = state->getFillColor(); + writePS("["); + for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("%g", colToDbl(colorPtr->c[i])); + } + writePS("] sc\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + if (state->getFillColorSpace()->getMode() == csSeparation) { + sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace(); + color.c[0] = gfxColorComp1; + sepCS->getCMYK(&color, &cmyk); + writePSFmt("%g %g %g %g %g (%s) ck\n", + colToDbl(state->getFillColor()->c[0]), + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()->getCString()); + addCustomColor(sepCS); + } else { + state->getFillCMYK(&cmyk); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("%g %g %g %g k\n", c, m, y, k); + addProcessColor(c, m, y, k); + } + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::updateStrokeColor(GfxState *state) { + GfxColor color; + GfxColor *colorPtr; + GfxGray gray; + GfxCMYK cmyk; + GfxSeparationColorSpace *sepCS; + double c, m, y, k; + int i; + + switch (level) { + case psLevel1: + state->getStrokeGray(&gray); + writePSFmt("%g G\n", colToDbl(gray)); + break; + case psLevel1Sep: + state->getStrokeCMYK(&cmyk); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("%g %g %g %g K\n", c, m, y, k); + addProcessColor(c, m, y, k); + break; + case psLevel2: + case psLevel3: + if (state->getStrokeColorSpace()->getMode() != csPattern) { + colorPtr = state->getStrokeColor(); + writePS("["); + for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("%g", colToDbl(colorPtr->c[i])); + } + writePS("] SC\n"); + } + break; + case psLevel2Sep: + case psLevel3Sep: + if (state->getStrokeColorSpace()->getMode() == csSeparation) { + sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace(); + color.c[0] = gfxColorComp1; + sepCS->getCMYK(&color, &cmyk); + writePSFmt("%g %g %g %g %g (%s) CK\n", + colToDbl(state->getStrokeColor()->c[0]), + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()->getCString()); + addCustomColor(sepCS); + } else { + state->getStrokeCMYK(&cmyk); + c = colToDbl(cmyk.c); + m = colToDbl(cmyk.m); + y = colToDbl(cmyk.y); + k = colToDbl(cmyk.k); + writePSFmt("%g %g %g %g K\n", c, m, y, k); + addProcessColor(c, m, y, k); + } + break; + } + t3Cacheable = gFalse; +} + +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] = gfxColorComp1; + sepCS->getCMYK(&color, &cmyk); + cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()->copy()); + cc->next = customColors; + customColors = cc; +} + +void PSOutputDev::updateFillOverprint(GfxState *state) { + if (level >= psLevel2) { + writePSFmt("%s op\n", state->getFillOverprint() ? "true" : "false"); + } +} + +void PSOutputDev::updateStrokeOverprint(GfxState *state) { + if (level >= psLevel2) { + writePSFmt("%s OP\n", state->getStrokeOverprint() ? "true" : "false"); + } +} + +void PSOutputDev::updateFont(GfxState *state) { + if (state->getFont()) { + writePSFmt("/F%d_%d %g Tf\n", + state->getFont()->getID()->num, state->getFont()->getID()->gen, + fabs(state->getFontSize()) < 0.00001 ? 0.00001 + : state->getFontSize()); + } +} + +void PSOutputDev::updateTextMat(GfxState *state) { + double *mat; + + mat = state->getTextMat(); + if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) { + // avoid a singular (or close-to-singular) matrix + writePSFmt("[0.00001 0 0 0.00001 %g %g] Tm\n", mat[4], mat[5]); + } else { + writePSFmt("[%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) { + writePSFmt("%g Tc\n", state->getCharSpace()); +} + +void PSOutputDev::updateRender(GfxState *state) { + int rm; + + rm = state->getRender(); + writePSFmt("%d Tr\n", rm); + rm &= 3; + if (rm != 0 && rm != 3) { + t3Cacheable = gFalse; + } +} + +void PSOutputDev::updateRise(GfxState *state) { + writePSFmt("%g Ts\n", state->getRise()); +} + +void PSOutputDev::updateWordSpace(GfxState *state) { + writePSFmt("%g Tw\n", state->getWordSpace()); +} + +void PSOutputDev::updateHorizScaling(GfxState *state) { + double h; + + h = state->getHorizScaling(); + if (fabs(h) < 0.01) { + h = 0.01; + } + writePSFmt("%g Tz\n", h); +} + +void PSOutputDev::updateTextPos(GfxState *state) { + writePSFmt("%g %g Td\n", state->getLineX(), state->getLineY()); +} + +void PSOutputDev::updateTextShift(GfxState *state, double shift) { + if (state->getFont()->getWMode()) { + writePSFmt("%g TJmV\n", shift); + } else { + writePSFmt("%g TJm\n", shift); + } +} + +void PSOutputDev::stroke(GfxState *state) { + doPath(state->getPath()); + if (t3String) { + // if we're construct a cacheable Type 3 glyph, we need to do + // everything in the fill color + writePS("Sf\n"); + } else { + 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::tilingPatternFill(GfxState *state, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep) { + PDFRectangle box; + Gfx *gfx; + + // define a Type 3 font + writePS("8 dict begin\n"); + writePS("/FontType 3 def\n"); + writePS("/FontMatrix [1 0 0 1 0 0] def\n"); + writePSFmt("/FontBBox [%g %g %g %g] def\n", + bbox[0], bbox[1], bbox[2], bbox[3]); + writePS("/Encoding 256 array def\n"); + writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); + writePS(" Encoding 120 /x put\n"); + writePS("/BuildGlyph {\n"); + writePS(" exch /CharProcs get exch\n"); + writePS(" 2 copy known not { pop /.notdef } if\n"); + writePS(" get exec\n"); + writePS("} bind def\n"); + writePS("/BuildChar {\n"); + writePS(" 1 index /Encoding get exch get\n"); + writePS(" 1 index /BuildGlyph get exec\n"); + writePS("} bind def\n"); + writePS("/CharProcs 1 dict def\n"); + writePS("CharProcs begin\n"); + box.x1 = bbox[0]; + box.y1 = bbox[1]; + box.x2 = bbox[2]; + box.y2 = bbox[3]; + gfx = new Gfx(xref, this, resDict, &box, NULL); + writePS("/x {\n"); + if (paintType == 2) { + writePSFmt("%g 0 %g %g %g %g setcachedevice\n", + xStep, bbox[0], bbox[1], bbox[2], bbox[3]); + } else { + writePSFmt("%g 0 setcharwidth\n", xStep); + } + inType3Char = gTrue; + ++numTilingPatterns; + gfx->display(str); + --numTilingPatterns; + inType3Char = gFalse; + writePS("} def\n"); + delete gfx; + writePS("end\n"); + writePS("currentdict end\n"); + writePSFmt("/xpdfTile%d exch definefont pop\n", numTilingPatterns); + + // draw the tiles + writePSFmt("/xpdfTile%d findfont setfont\n", numTilingPatterns); + writePSFmt("gsave [%g %g %g %g %g %g] concat\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + writePSFmt("%d 1 %d { %g exch %g mul m %d 1 %d { pop (x) show } for } for\n", + y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1); + writePS("grestore\n"); +} + +void PSOutputDev::functionShadedFill(GfxState *state, + GfxFunctionShading *shading) { + double x0, y0, x1, y1; + double *mat; + int i; + + shading->getDomain(&x0, &y0, &x1, &y1); + mat = shading->getMatrix(); + writePSFmt("/mat [%g %g %g %g %g %g] def\n", + mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); + writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("2 copy\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("3 1 roll\n"); + } + } + writePS("} def\n"); + } + writePSFmt("%g %g %g %g 0 funcSH\n", x0, y0, x1, y1); +} + +void PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { + double xMin, yMin, xMax, yMax; + double x0, y0, x1, y1, dx, dy, mul; + double tMin, tMax, t, t0, t1; + int i; + + // get the clip region bbox + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + + // 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(); + + // generate the PS code + writePSFmt("/t0 %g def\n", t0); + writePSFmt("/t1 %g def\n", t1); + writePSFmt("/dt %g def\n", t1 - t0); + writePSFmt("/x0 %g def\n", x0); + writePSFmt("/y0 %g def\n", y0); + writePSFmt("/dx %g def\n", x1 - x0); + writePSFmt("/x1 %g def\n", x1); + writePSFmt("/y1 %g def\n", y1); + writePSFmt("/dy %g def\n", y1 - y0); + writePSFmt("/xMin %g def\n", xMin); + writePSFmt("/yMin %g def\n", yMin); + writePSFmt("/xMax %g def\n", xMax); + writePSFmt("/yMax %g def\n", yMax); + writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("dup\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("exch\n"); + } + } + writePS("} def\n"); + } + writePSFmt("%g %g 0 axialSH\n", tMin, tMax); +} + +void PSOutputDev::radialShadedFill(GfxState *state, + GfxRadialShading *shading) { + double x0, y0, r0, x1, y1, r1, t0, t1, sMin, sMax; + double xMin, yMin, xMax, yMax; + double d0, d1; + int i; + + // get the shading info + shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); + t0 = shading->getDomain0(); + t1 = shading->getDomain1(); + + // compute the (possibly extended) s range + sMin = 0; + sMax = 1; + if (shading->getExtend0()) { + if (r0 < r1) { + // extend the smaller end + sMin = -r0 / (r1 - r0); + } else { + // extend the larger end + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + d0 = (x0 - xMin) * (x0 - xMin); + d1 = (x0 - xMax) * (x0 - xMax); + sMin = d0 > d1 ? d0 : d1; + d0 = (y0 - yMin) * (y0 - yMin); + d1 = (y0 - yMax) * (y0 - yMax); + sMin += d0 > d1 ? d0 : d1; + sMin = (sqrt(sMin) - r0) / (r1 - r0); + if (sMin > 0) { + sMin = 0; + } else if (sMin < -20) { + // sanity check + sMin = -20; + } + } + } + if (shading->getExtend1()) { + if (r1 < r0) { + // extend the smaller end + sMax = -r0 / (r1 - r0); + } else if (r1 > r0) { + // extend the larger end + state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); + d0 = (x1 - xMin) * (x1 - xMin); + d1 = (x1 - xMax) * (x1 - xMax); + sMax = d0 > d1 ? d0 : d1; + d0 = (y1 - yMin) * (y1 - yMin); + d1 = (y1 - yMax) * (y1 - yMax); + sMax += d0 > d1 ? d0 : d1; + sMax = (sqrt(sMax) - r0) / (r1 - r0); + if (sMax < 1) { + sMax = 1; + } else if (sMax > 20) { + // sanity check + sMax = 20; + } + } + } + + // generate the PS code + writePSFmt("/x0 %g def\n", x0); + writePSFmt("/x1 %g def\n", x1); + writePSFmt("/dx %g def\n", x1 - x0); + writePSFmt("/y0 %g def\n", y0); + writePSFmt("/y1 %g def\n", y1); + writePSFmt("/dy %g def\n", y1 - y0); + writePSFmt("/r0 %g def\n", r0); + writePSFmt("/r1 %g def\n", r1); + writePSFmt("/dr %g def\n", r1 - r0); + writePSFmt("/t0 %g def\n", t0); + writePSFmt("/t1 %g def\n", t1); + writePSFmt("/dt %g def\n", t1 - t0); + writePSFmt("/n %d def\n", shading->getColorSpace()->getNComps()); + if (shading->getNFuncs() == 1) { + writePS("/func "); + cvtFunction(shading->getFunc(0)); + writePS("def\n"); + } else { + writePS("/func {\n"); + for (i = 0; i < shading->getNFuncs(); ++i) { + if (i < shading->getNFuncs() - 1) { + writePS("dup\n"); + } + cvtFunction(shading->getFunc(i)); + writePS("exec\n"); + if (i < shading->getNFuncs() - 1) { + writePS("exch\n"); + } + } + writePS("} def\n"); + } + writePSFmt("%g %g 0 radialSH\n", sMin, sMax); +} + +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) { + writePSFmt("%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) { + writePSFmt("%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(); + writePSFmt("%g %g m\n", subpath->getX(0), subpath->getY(0)); + j = 1; + while (j < m) { + if (subpath->getCurve(j)) { + writePSFmt("%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 { + writePSFmt("%g %g l\n", subpath->getX(j), subpath->getY(j)); + ++j; + } + } + if (subpath->isClosed()) { + writePS("h\n"); + } + } +} + +void PSOutputDev::drawString(GfxState *state, GString *s) { + GfxFont *font; + int wMode; + GString *s2; + double dx, dy, dx2, dy2, originX, originY; + char *p; + UnicodeMap *uMap; + CharCode code; + Unicode u[8]; + char buf[8]; + int len, nChars, uLen, n, m, i, j; + + // check for invisible text -- this is used by Acrobat Capture + if (state->getRender() == 3) { + return; + } + + // ignore empty strings + if (s->getLength() == 0) { + return; + } + + // get the font + if (!(font = state->getFont())) { + return; + } + wMode = font->getWMode(); + + // check for a subtitute 16-bit font + uMap = NULL; + if (font->isCIDFont()) { + for (i = 0; i < font16EncLen; ++i) { + if (font->getID()->num == font16Enc[i].fontID.num && + font->getID()->gen == font16Enc[i].fontID.gen) { + uMap = globalParams->getUnicodeMap(font16Enc[i].enc); + break; + } + } + } + + // compute width of chars in string, ignoring char spacing and word + // spacing -- the Tj operator will adjust for the metrics of the + // font that's actually used + dx = dy = 0; + nChars = 0; + p = s->getCString(); + len = s->getLength(); + if (font->isCIDFont()) { + s2 = new GString(); + } else { + s2 = s; + } + while (len > 0) { + n = font->getNextChar(p, len, &code, + u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, + &dx2, &dy2, &originX, &originY); + if (font->isCIDFont()) { + if (uMap) { + for (i = 0; i < uLen; ++i) { + m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf)); + for (j = 0; j < m; ++j) { + s2->append(buf[j]); + } + } + //~ this really needs to get the number of chars in the target + //~ encoding - which may be more than the number of Unicode + //~ chars + nChars += uLen; + } else { + s2->append((char)((code >> 8) & 0xff)); + s2->append((char)(code & 0xff)); + ++nChars; + } + } + dx += dx2; + dy += dy2; + p += n; + len -= n; + } + dx *= state->getFontSize() * state->getHorizScaling(); + dy *= state->getFontSize(); + if (uMap) { + uMap->decRefCnt(); + } + + if (s2->getLength() > 0) { + writePSString(s2); + if (font->isCIDFont()) { + if (wMode) { + writePSFmt(" %d %g Tj16V\n", nChars, dy); + } else { + writePSFmt(" %d %g Tj16\n", nChars, dx); + } + } else { + writePSFmt(" %g Tj\n", dx); + } + } + if (font->isCIDFont()) { + delete s2; + } + + if (state->getRender() & 4) { + haveTextClip = gTrue; + } +} + +void PSOutputDev::endTextObject(GfxState *state) { + if (haveTextClip) { + writePS("Tclip\n"); + haveTextClip = gFalse; + } +} + +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(ref, NULL, invert, inlineImg, str, width, height, len); + } else { + doImageL2(ref, NULL, invert, inlineImg, str, width, height, len, + NULL, NULL, 0, 0, gFalse); + } +} + +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(ref, 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: + case psLevel3: + case psLevel3Sep: + doImageL2(ref, colorMap, gFalse, inlineImg, str, + width, height, len, maskColors, NULL, 0, 0, gFalse); + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GBool maskInvert) { + int len; + + len = height * ((width * colorMap->getNumPixelComps() * + colorMap->getBits() + 7) / 8); + switch (level) { + case psLevel1: + doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len); + break; + case psLevel1Sep: + //~ handle indexed, separation, ... color spaces + doImageL1Sep(colorMap, gFalse, gFalse, str, width, height, len); + break; + case psLevel2: + case psLevel2Sep: + case psLevel3: + case psLevel3Sep: + doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len, + NULL, maskStr, maskWidth, maskHeight, maskInvert); + break; + } + t3Cacheable = gFalse; +} + +void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len) { + ImageStream *imgStr; + Guchar pixBuf[gfxColorMaxComps]; + GfxGray gray; + int col, x, y, c, i; + + if (inType3Char && !colorMap) { + if (inlineImg) { + // create an array + str = new FixedLengthEncoder(str, len); + str = new ASCIIHexEncoder(str); + str->reset(); + col = 0; + writePS("[<"); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '>' || c == EOF) { + break; + } + writePSChar(c); + ++col; + // each line is: "<...data...>" + // so max data length = 255 - 4 = 251 + // but make it 240 just to be safe + // chunks are 2 bytes each, so we need to stop on an even col number + if (col == 240) { + writePS(">\n<"); + col = 0; + } + } while (c != '>' && c != EOF); + writePS(">]\n"); + writePS("0\n"); + str->close(); + delete str; + } else { + // set up to use the array already created by setupImages() + writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); + } + } + + // image/imagemask command + if (inType3Char && !colorMap) { + writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n", + width, height, invert ? "true" : "false", + width, -height, height); + } else if (colorMap) { + writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n", + width, height, + width, -height, height); + } else { + writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1\n", + width, height, invert ? "true" : "false", + width, -height, height); + } + + // image data + if (!(inType3Char && !colorMap)) { + + 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); + writePSFmt("%02x", colToByte(gray)); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + if (i != 0) { + writePSChar('\n'); + } + delete imgStr; + + // imagemask + } else { + str->reset(); + i = 0; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; x += 8) { + writePSFmt("%02x", str->getChar() & 0xff); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + if (i != 0) { + writePSChar('\n'); + } + str->close(); + } + } +} + +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 + writePSFmt("%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] = colToByte(cmyk.c); + lineBuf[4*x+1] = colToByte(cmyk.m); + lineBuf[4*x+2] = colToByte(cmyk.y); + lineBuf[4*x+3] = colToByte(cmyk.k); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } + + // write one line of each color component + for (comp = 0; comp < 4; ++comp) { + for (x = 0; x < width; ++x) { + writePSFmt("%02x", lineBuf[4*x + comp]); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } + } + } + } + + if (i != 0) { + writePSChar('\n'); + } + + delete imgStr; + gfree(lineBuf); +} + +void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, + GBool invert, GBool inlineImg, + Stream *str, int width, int height, int len, + int *maskColors, Stream *maskStr, + int maskWidth, int maskHeight, GBool maskInvert) { + ImageStream *imgStr; + Guchar *line, *pix; + GString *s; + int n, numComps; + GBool useRLE, useASCII, useASCIIHex, useCompressed; + GfxSeparationColorSpace *sepCS; + GfxColor color; + GfxCMYK cmyk; + int c; + int col, i, x, x0, y, y0, maskXor; + + // color key masking + if (maskColors && colorMap && !inlineImg) { + // can't read the stream twice for inline images -- but masking + // isn't allowed with inline images anyway + writePS("[\n"); + numComps = colorMap->getNumPixelComps(); + imgStr = new ImageStream(str, width, numComps, colorMap->getBits()); + imgStr->reset(); + for (y = 0, y0 = 0; y < height; ++y) { + if (!(line = imgStr->getLine())) { + break; + } + for (x = 0, x0 = 0, pix = line; x < width; ++x, pix += numComps) { + for (i = 0; i < numComps; ++i) { + if (pix[i] < maskColors[2*i] || + pix[i] > maskColors[2*i+1]) { + break; + } + } + if (i == numComps) { + if (y0 < y) { + writePSFmt("0 %d %d %d\n", height - y, width, y - y0); + } + if (x0 < x) { + writePSFmt("%d %d %d 1\n", x0, height - y - 1, x - x0); + } + x0 = x + 1; + y0 = y + 1; + } + } + if (x0 > 0 && x0 < width) { + writePSFmt("%d %d %d 1\n", x0, height - y - 1, width - x0); + } + } + if (y0 < height) { + writePSFmt("0 0 %d %d\n", width, height - y0); + } + delete imgStr; + str->close(); + writePSFmt("] %d %d pdfImClip\n", width, height); + + // explicit masking + } else if (maskStr) { + writePS("[\n"); + imgStr = new ImageStream(maskStr, maskWidth, 1, 1); + imgStr->reset(); + maskXor = maskInvert ? 1 : 0; + for (y = 0, y0 = 0; y < maskHeight; ++y) { + if (!(line = imgStr->getLine())) { + break; + } + for (x = 0, x0 = 0, pix = line; x < maskWidth; ++x, ++pix) { + if (*pix ^ maskXor) { + if (y0 < y) { + writePSFmt("0 %d %d %d\n", maskHeight - y, maskWidth, y - y0); + } + if (x0 < x) { + writePSFmt("%d %d %d 1\n", x0, maskHeight - y - 1, x - x0); + } + x0 = x + 1; + y0 = y + 1; + } + } + if (x0 > 0 && x0 < maskWidth) { + writePSFmt("%d %d %d 1\n", x0, maskHeight - y - 1, maskWidth - x0); + } + } + if (y0 < maskHeight) { + writePSFmt("0 0 %d %d\n", maskWidth, maskHeight - y0); + } + delete imgStr; + maskStr->close(); + writePSFmt("] %d %d pdfImClip\n", maskWidth, maskHeight); + } + + // color space + if (colorMap) { + dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue); + writePS(" setcolorspace\n"); + } + + useASCIIHex = globalParams->getPSASCIIHex(); + + // set up the image data + if (mode == psModeForm || inType3Char) { + if (inlineImg) { + // create an array + str = new FixedLengthEncoder(str, len); + if (useASCIIHex) { + str = new ASCIIHexEncoder(str); + } else { + str = new ASCII85Encoder(str); + } + str->reset(); + col = 0; + writePS((char *)(useASCIIHex ? "[<" : "[<~")); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + if (c == 'z') { + writePSChar(c); + ++col; + } else { + writePSChar(c); + ++col; + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { + break; + } + writePSChar(c); + ++col; + } + } + // each line is: "<~...data...~>" + // so max data length = 255 - 6 = 249 + // chunks are 1 or 5 bytes each, so we have to stop at 245 + // but make it 240 just to be safe + if (col > 240) { + writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~")); + col = 0; + } + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + writePS((char *)(useASCIIHex ? ">]\n" : "~>]\n")); + writePS("0\n"); + str->close(); + delete str; + } else { + // set up to use the array already created by setupImages() + writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); + } + } + + // image dictionary + writePS("<<\n /ImageType 1\n"); + + // width, height, matrix, bits per component + writePSFmt(" /Width %d\n", width); + writePSFmt(" /Height %d\n", height); + writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height); + if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { + writePSFmt(" /BitsPerComponent 8\n"); + } else { + writePSFmt(" /BitsPerComponent %d\n", + colorMap ? colorMap->getBits() : 1); + } + + // decode + if (colorMap) { + writePS(" /Decode ["); + if ((level == psLevel2Sep || level == psLevel3Sep) && + colorMap->getColorSpace()->getMode() == csSeparation) { + // this matches up with the code in the pdfImSep operator + n = (1 << colorMap->getBits()) - 1; + writePSFmt("%g %g", colorMap->getDecodeLow(0) * n, + colorMap->getDecodeHigh(0) * n); + } else if (colorMap->getColorSpace()->getMode() == csDeviceN) { + numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getAlt()->getNComps(); + for (i = 0; i < numComps; ++i) { + if (i > 0) { + writePS(" "); + } + writePS("0 1"); + } + } else { + numComps = colorMap->getNumPixelComps(); + for (i = 0; i < numComps; ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("%g %g", colorMap->getDecodeLow(i), + colorMap->getDecodeHigh(i)); + } + } + writePS("]\n"); + } else { + writePSFmt(" /Decode [%d %d]\n", invert ? 1 : 0, invert ? 0 : 1); + } + + if (mode == psModeForm || inType3Char) { + + // data source + writePS(" /DataSource { 2 copy get exch 1 add exch }\n"); + + // end of image dictionary + writePSFmt(">>\n%s\n", colorMap ? "image" : "imagemask"); + + // get rid of the array and index + writePS("pop pop\n"); + + } else { + + // data source + writePS(" /DataSource currentfile\n"); + s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, + " "); + if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || + inlineImg || !s) { + useRLE = gTrue; + useASCII = gTrue; + useCompressed = gFalse; + } else { + useRLE = gFalse; + useASCII = str->isBinary(); + useCompressed = gTrue; + } + if (useASCII) { + writePSFmt(" /ASCII%sDecode filter\n", + useASCIIHex ? "Hex" : "85"); + } + if (useRLE) { + writePS(" /RunLengthDecode filter\n"); + } + if (useCompressed) { + writePS(s->getCString()); + } + if (s) { + delete s; + } + + // cut off inline image streams at appropriate length + if (inlineImg) { + str = new FixedLengthEncoder(str, len); + } else if (useCompressed) { + str = str->getBaseStream(); + } + + // recode DeviceN data + if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { + str = new DeviceNRecoder(str, width, height, colorMap); + } + + // add RunLengthEncode and ASCIIHex/85 encode filters + if (useRLE) { + str = new RunLengthEncoder(str); + } + if (useASCII) { + if (useASCIIHex) { + str = new ASCIIHexEncoder(str); + } else { + 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 ASCII and RLE filters) + str->reset(); + n = 0; + while ((c = str->getChar()) != EOF) { + ++n; + } + str->close(); + } + // +6/7 for "pdfIm\n" / "pdfImM\n" + // +8 for newline + trailer + n += colorMap ? 14 : 15; + writePSFmt("%%%%BeginData: %d Hex Bytes\n", n); + } +#endif + if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && + colorMap->getColorSpace()->getMode() == csSeparation) { + color.c[0] = gfxColorComp1; + sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); + sepCS->getCMYK(&color, &cmyk); + writePSFmt("%g %g %g %g (%s) pdfImSep\n", + colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k), + sepCS->getName()->getCString()); + } else { + writePSFmt("%s\n", colorMap ? "pdfIm" : "pdfImM"); + } + + // copy the stream data + str->reset(); + while ((c = str->getChar()) != EOF) { + writePSChar(c); + } + str->close(); + + // add newline and trailer to the end + writePSChar('\n'); + writePS("%-EOD-\n"); +#if OPI_SUPPORT + if (opi13Nest) { + writePS("%%EndData\n"); + } +#endif + + // delete encoders + if (useRLE || useASCII || inlineImg) { + delete str; + } + } + + if ((maskColors && colorMap && !inlineImg) || maskStr) { + writePS("pdfImClipEnd\n"); + } +} + +void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace, + GBool genXform, GBool updateColors) { + GfxCalGrayColorSpace *calGrayCS; + GfxCalRGBColorSpace *calRGBCS; + GfxLabColorSpace *labCS; + GfxIndexedColorSpace *indexedCS; + GfxSeparationColorSpace *separationCS; + GfxDeviceNColorSpace *deviceNCS; + GfxColorSpace *baseCS; + Guchar *lookup, *p; + double x[gfxColorMaxComps], y[gfxColorMaxComps]; + GfxColor color; + GfxCMYK cmyk; + Function *func; + int n, numComps, numAltComps; + int byte; + int i, j, k; + + switch (colorSpace->getMode()) { + + case csDeviceGray: + writePS("/DeviceGray"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessBlack; + } + break; + + case csCalGray: + calGrayCS = (GfxCalGrayColorSpace *)colorSpace; + writePS("[/CIEBasedA <<\n"); + writePSFmt(" /DecodeA {%g exp} bind\n", calGrayCS->getGamma()); + writePSFmt(" /MatrixA [%g %g %g]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePSFmt(" /WhitePoint [%g %g %g]\n", + calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), + calGrayCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + calGrayCS->getBlackX(), calGrayCS->getBlackY(), + calGrayCS->getBlackZ()); + writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessBlack; + } + break; + + case csDeviceRGB: + writePS("/DeviceRGB"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessCMYK; + } + break; + + case csCalRGB: + calRGBCS = (GfxCalRGBColorSpace *)colorSpace; + writePS("[/CIEBasedABC <<\n"); + writePSFmt(" /DecodeABC [{%g exp} bind {%g exp} bind {%g exp} bind]\n", + calRGBCS->getGammaR(), calRGBCS->getGammaG(), + calRGBCS->getGammaB()); + writePSFmt(" /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]); + writePSFmt(" /WhitePoint [%g %g %g]\n", + calRGBCS->getWhiteX(), calRGBCS->getWhiteY(), + calRGBCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + calRGBCS->getBlackX(), calRGBCS->getBlackY(), + calRGBCS->getBlackZ()); + writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessCMYK; + } + break; + + case csDeviceCMYK: + writePS("/DeviceCMYK"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessCMYK; + } + break; + + case csLab: + labCS = (GfxLabColorSpace *)colorSpace; + writePS("[/CIEBasedABC <<\n"); + writePSFmt(" /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"); + writePSFmt(" {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"); + writePSFmt(" {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"); + writePSFmt(" {4 29 div sub 108 841 div mul } ifelse %g mul} bind]\n", + labCS->getWhiteZ()); + writePSFmt(" /WhitePoint [%g %g %g]\n", + labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ()); + writePSFmt(" /BlackPoint [%g %g %g]\n", + labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); + writePS(">>]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + processColors |= psProcessCMYK; + } + break; + + case csICCBased: + // there is no transform function to the alternate color space, so + // we can use it directly + dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(), + genXform, updateColors); + break; + + case csIndexed: + indexedCS = (GfxIndexedColorSpace *)colorSpace; + baseCS = indexedCS->getBase(); + writePS("[/Indexed "); + dumpColorSpaceL2(baseCS, gFalse, gFalse); + n = indexedCS->getIndexHigh(); + numComps = baseCS->getNComps(); + lookup = indexedCS->getLookup(); + writePSFmt(" %d <\n", n); + if (baseCS->getMode() == csDeviceN) { + func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc(); + numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps(); + p = lookup; + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + x[k] = *p++ / 255.0; + } + func->transform(x, y); + for (k = 0; k < numAltComps; ++k) { + byte = (int)(y[k] * 255 + 0.5); + if (byte < 0) { + byte = 0; + } else if (byte > 255) { + byte = 255; + } + writePSFmt("%02x", byte); + } + if (updateColors) { + color.c[0] = dblToCol(j); + indexedCS->getCMYK(&color, &cmyk); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } + } + writePS("\n"); + } + } else { + for (i = 0; i <= n; i += 8) { + writePS(" "); + for (j = i; j < i+8 && j <= n; ++j) { + for (k = 0; k < numComps; ++k) { + writePSFmt("%02x", lookup[j * numComps + k]); + } + if (updateColors) { + color.c[0] = dblToCol(j); + indexedCS->getCMYK(&color, &cmyk); + addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), + colToDbl(cmyk.y), colToDbl(cmyk.k)); + } + } + writePS("\n"); + } + } + writePS(">]"); + if (genXform) { + writePS(" {}"); + } + break; + + case csSeparation: + separationCS = (GfxSeparationColorSpace *)colorSpace; + writePS("[/Separation /"); + writePSName(separationCS->getName()->getCString()); + writePS(" "); + dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse); + writePS("\n"); + cvtFunction(separationCS->getFunc()); + writePS("]"); + if (genXform) { + writePS(" {}"); + } + if (updateColors) { + addCustomColor(separationCS); + } + break; + + case csDeviceN: + // DeviceN color spaces are a Level 3 PostScript feature. + deviceNCS = (GfxDeviceNColorSpace *)colorSpace; + dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors); + if (genXform) { + writePS(" "); + cvtFunction(deviceNCS->getTintTransformFunc()); + } + break; + + case csPattern: + //~ unimplemented + break; + } +} + +#if OPI_SUPPORT +void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) { + Object dict; + + if (globalParams->getPSOPI()) { + 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)) { + writePSFmt("%%%%ImageFileName: %s\n", + obj2.getString()->getCString()); + obj2.free(); + } + obj1.free(); + + dict->lookup("MainImage", &obj1); + if (obj1.isString()) { + writePSFmt("%%%%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(); + writePSFmt("%%%%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(); + writePSFmt("%%%%ImageCropRect: %g %g %g %g\n", left, top, right, bottom); + } + obj1.free(); + + dict->lookup("Overprint", &obj1); + if (obj1.isBool()) { + writePSFmt("%%%%ImageOverprint: %s\n", obj1.getBool() ? "true" : "false"); + } + obj1.free(); + + dict->lookup("Inks", &obj1); + if (obj1.isName()) { + writePSFmt("%%%%ImageInks: %s\n", obj1.getName()); + } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) { + obj1.arrayGet(0, &obj2); + if (obj2.isName()) { + writePSFmt("%%%%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()); + writePSFmt(" %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(); + writePSFmt("%%%%IncludedImageDimensions: %d %d\n", w, h); + } + obj1.free(); + + dict->lookup("IncludedImageQuality", &obj1); + if (obj1.isNum()) { + writePSFmt("%%%%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)) { + writePSFmt("%%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(); + writePSFmt("%%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()) { + writePSFmt("%%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()) { + writePSFmt("%%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(); + writePSFmt("%%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); + writePSFmt(" %d", obj2.getInt()); + obj2.free(); + } + } + writePS("\n"); + } + obj1.free(); + + dict->lookup("ID", &obj1); + if (obj1.isString()) { + writePSFmt("%%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(); + writePSFmt("%%ALDImageType: %d %d\n", samples, bits); + } + obj1.free(); + + dict->lookup("Overprint", &obj1); + if (obj1.isBool()) { + writePSFmt("%%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); + writePSFmt("%%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(); + writePSFmt("%%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(); + writePSFmt("%%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()) { + writePSFmt("%%ALDImageTint: %g\n", obj1.getNum()); + } + obj1.free(); + + dict->lookup("Transparency", &obj1); + if (obj1.isBool()) { + writePSFmt("%%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 (rotate == 90) { + t = *x1; + *x1 = -*y1; + *y1 = t; + } else if (rotate == 180) { + *x1 = -*x1; + *y1 = -*y1; + } else if (rotate == 270) { + t = *x1; + *x1 = *y1; + *y1 = -t; + } + *x1 *= xScale; + *y1 *= yScale; +} + +void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) { + Object dict; + + if (globalParams->getPSOPI()) { + 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::type3D0(GfxState *state, double wx, double wy) { + writePSFmt("%g %g setcharwidth\n", wx, wy); + writePS("q\n"); +} + +void PSOutputDev::type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury) { + t3WX = wx; + t3WY = wy; + t3LLX = llx; + t3LLY = lly; + t3URX = urx; + t3URY = ury; + t3String = new GString(); + writePS("q\n"); + t3Cacheable = gTrue; +} + +void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) { + Stream *str; + int c; + + if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) { + str = level1Stream; + } else { + str = psStream; + } + str->reset(); + while ((c = str->getChar()) != EOF) { + writePSChar(c); + } + str->close(); +} + +//~ can nextFunc be reset to 0 -- maybe at the start of each page? +//~ or maybe at the start of each color space / pattern? +void PSOutputDev::cvtFunction(Function *func) { + SampledFunction *func0; + ExponentialFunction *func2; + StitchingFunction *func3; + PostScriptFunction *func4; + int thisFunc, m, n, nSamples, i, j, k; + + switch (func->getType()) { + + case -1: // identity + writePS("{}\n"); + break; + + case 0: // sampled + func0 = (SampledFunction *)func; + thisFunc = nextFunc++; + m = func0->getInputSize(); + n = func0->getOutputSize(); + nSamples = n; + for (i = 0; i < m; ++i) { + nSamples *= func0->getSampleSize(i); + } + writePSFmt("/xpdfSamples%d [\n", thisFunc); + for (i = 0; i < nSamples; ++i) { + writePSFmt("%g\n", func0->getSamples()[i]); + } + writePS("] def\n"); + writePSFmt("{ %d array %d array %d 2 roll\n", 2*m, m, m+2); + // [e01] [efrac] x0 x1 ... xm-1 + for (i = m-1; i >= 0; --i) { + // [e01] [efrac] x0 x1 ... xi + writePSFmt("%g sub %g mul %g add\n", + func0->getDomainMin(i), + (func0->getEncodeMax(i) - func0->getEncodeMin(i)) / + (func0->getDomainMax(i) - func0->getDomainMin(i)), + func0->getEncodeMin(i)); + // [e01] [efrac] x0 x1 ... xi-1 xi' + writePSFmt("dup 0 lt { pop 0 } { dup %d gt { pop %d } if } ifelse\n", + func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1); + // [e01] [efrac] x0 x1 ... xi-1 xi' + writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n"); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi') + writePSFmt("%d index %d 3 2 roll put\n", i+3, i); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') + writePSFmt("%d index %d 3 2 roll put\n", i+3, 2*i+1); + // [e01] [efrac] x0 x1 ... xi-1 floor(xi') + writePSFmt("%d index %d 3 2 roll put\n", i+2, 2*i); + // [e01] [efrac] x0 x1 ... xi-1 + } + // [e01] [efrac] + for (i = 0; i < n; ++i) { + // [e01] [efrac] y(0) ... y(i-1) + for (j = 0; j < (1<> k) & 1)); + for (k = m - 2; k >= 0; --k) { + writePSFmt("%d mul %d index %d get add\n", + func0->getSampleSize(k), + i + j + 3, + 2 * k + ((j >> k) & 1)); + } + if (n > 1) { + writePSFmt("%d mul %d add ", n, i); + } + writePS("get\n"); + } + // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1) + for (j = 0; j < m; ++j) { + // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1) + for (k = 0; k < (1 << (m - j)); k += 2) { + // [e01] [efrac] y(0) ... y(i-1) <2^(m-j)-k s values> + writePSFmt("%d index %d get dup\n", i + k/2 + (1 << (m-j)) - k, j); + writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n"); + writePSFmt("%d 1 roll\n", k/2 + (1 << m-j) - k - 1); + } + // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1) + } + // [e01] [efrac] y(0) ... y(i-1) s + writePSFmt("%g mul %g add\n", + func0->getDecodeMax(i) - func0->getDecodeMin(i), + func0->getDecodeMin(i)); + writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", + func0->getRangeMin(i), func0->getRangeMin(i), + func0->getRangeMax(i), func0->getRangeMax(i)); + // [e01] [efrac] y(0) ... y(i-1) y(i) + } + // [e01] [efrac] y(0) ... y(n-1) + writePSFmt("%d %d roll pop pop }\n", n+2, n); + break; + + case 2: // exponential + func2 = (ExponentialFunction *)func; + n = func2->getOutputSize(); + writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", + func2->getDomainMin(0), func2->getDomainMin(0), + func2->getDomainMax(0), func2->getDomainMax(0)); + // x + for (i = 0; i < n; ++i) { + // x y(0) .. y(i-1) + writePSFmt("%d index %g exp %g mul %g add\n", + i, func2->getE(), func2->getC1()[i] - func2->getC0()[i], + func2->getC0()[i]); + if (func2->getHasRange()) { + writePSFmt("dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", + func2->getRangeMin(i), func2->getRangeMin(i), + func2->getRangeMax(i), func2->getRangeMax(i)); + } + } + // x y(0) .. y(n-1) + writePSFmt("%d %d roll pop }\n", n+1, n); + break; + + case 3: // stitching + func3 = (StitchingFunction *)func; + thisFunc = nextFunc++; + for (i = 0; i < func3->getNumFuncs(); ++i) { + cvtFunction(func3->getFunc(i)); + writePSFmt("/xpdfFunc%d_%d exch def\n", thisFunc, i); + } + writePSFmt("{ dup %g lt { pop %g } { dup %g gt { pop %g } if } ifelse\n", + func3->getDomainMin(0), func3->getDomainMin(0), + func3->getDomainMax(0), func3->getDomainMax(0)); + for (i = 0; i < func3->getNumFuncs() - 1; ++i) { + writePSFmt("dup %g lt { %g sub %g mul %g add xpdfFunc%d_%d } {\n", + func3->getBounds()[i+1], + func3->getBounds()[i], + (func3->getEncode()[2*i+1] - func3->getEncode()[2*i]) / + (func3->getBounds()[i+1] - func3->getBounds()[i]), + func3->getEncode()[2*i], + thisFunc, i); + } + writePSFmt("%g sub %g mul %g add xpdfFunc%d_%d\n", + func3->getBounds()[i], + (func3->getEncode()[2*i+1] - func3->getEncode()[2*i]) / + (func3->getBounds()[i+1] - func3->getBounds()[i]), + func3->getEncode()[2*i], + thisFunc, i); + for (i = 0; i < func3->getNumFuncs() - 1; ++i) { + writePS("} ifelse\n"); + } + writePS("}\n"); + break; + + case 4: // PostScript + func4 = (PostScriptFunction *)func; + writePS(func4->getCodeString()->getCString()); + writePS("\n"); + break; + } +} + +void PSOutputDev::writePSChar(char c) { + if (t3String) { + t3String->append(c); + } else { + (*outputFunc)(outputStream, &c, 1); + } +} + +void PSOutputDev::writePS(char *s) { + if (t3String) { + t3String->append(s); + } else { + (*outputFunc)(outputStream, s, strlen(s)); + } +} + +void PSOutputDev::writePSFmt(const char *fmt, ...) { + va_list args; + char buf[512]; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + if (t3String) { + t3String->append(buf); + } else { + (*outputFunc)(outputStream, buf, strlen(buf)); + } +} + +void PSOutputDev::writePSString(GString *s) { + Guchar *p; + int n, line; + char buf[8]; + + writePSChar('('); + line = 1; + for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { + if (line >= 64) { + writePSChar('\\'); + writePSChar('\n'); + line = 0; + } + if (*p == '(' || *p == ')' || *p == '\\') { + writePSChar('\\'); + writePSChar((char)*p); + line += 2; + } else if (*p < 0x20 || *p >= 0x80) { + sprintf(buf, "\\%03o", *p); + writePS(buf); + line += 4; + } else { + writePSChar((char)*p); + ++line; + } + } + writePSChar(')'); +} + +void PSOutputDev::writePSName(char *s) { + char *p; + char c; + + p = s; + while ((c = *p++)) { + if (c <= (char)0x20 || c >= (char)0x7f || + c == '(' || c == ')' || c == '<' || c == '>' || + c == '[' || c == ']' || c == '{' || c == '}' || + c == '/' || c == '%') { + writePSFmt("#%02x", c & 0xff); + } else { + writePSChar(c); + } + } +} + +GString *PSOutputDev::filterPSName(GString *name) { + GString *name2; + char buf[8]; + int i; + char c; + + name2 = new GString(); + + // ghostscript chokes on names that begin with out-of-limits + // numbers, e.g., 1e4foo is handled correctly (as a name), but + // 1e999foo generates a limitcheck error + c = name->getChar(0); + if (c >= '0' && c <= '9') { + name2->append('f'); + } + + for (i = 0; i < name->getLength(); ++i) { + c = name->getChar(i); + if (c <= (char)0x20 || c >= (char)0x7f || + c == '(' || c == ')' || c == '<' || c == '>' || + c == '[' || c == ']' || c == '{' || c == '}' || + c == '/' || c == '%') { + sprintf(buf, "#%02x", c & 0xff); + name2->append(buf); + } else { + name2->append(c); + } + } + return name2; +} + +GBool /* O - gTrue if selected, gFalse otherwise */ +PSOutputDev::checkRange(int page) /* I - Page number */ +{ + const char *range; /* Pointer into range string */ + int lower, upper; /* Lower and upper page numbers */ + + + if (pageRanges == NULL) + return (gTrue); /* 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 & 255)) + upper = 65535; + else + upper = strtol(range, (char **)&range, 10); + } + else + upper = lower; + } + + if (page >= lower && page <= upper) + return (gTrue); + + if (*range == ',') + range ++; + else + break; + } + + return (gFalse); +} diff --git a/pdftops/PSOutputDev.h b/pdftops/PSOutputDev.h new file mode 100644 index 000000000..4cd3fd276 --- /dev/null +++ b/pdftops/PSOutputDev.h @@ -0,0 +1,354 @@ +//======================================================================== +// +// PSOutputDev.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PSOUTPUTDEV_H +#define PSOUTPUTDEV_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "config.h" +#include "Object.h" +#include "GlobalParams.h" +#include "OutputDev.h" + +class Function; +class GfxPath; +class GfxFont; +class GfxColorSpace; +class GfxSeparationColorSpace; +class PDFRectangle; +struct PSFont16Enc; +class PSOutCustomColor; + +//------------------------------------------------------------------------ +// PSOutputDev +//------------------------------------------------------------------------ + +enum PSOutMode { + psModePS, + psModeEPS, + psModeForm +}; + +enum PSFileType { + psFile, // write to file + psPipe, // write to pipe + psStdout, // write to stdout + psGeneric // write to a generic stream +}; + +typedef void (*PSOutputFunc)(void *stream, char *data, int len); + +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, PSOutMode modeA, + int imgLLXA = 0, int imgLLYA = 0, + int imgURXA = 0, int imgURYA = 0, + GBool manualCtrlA = gFalse, + const char *pageRangesA = (const char *)0); + + // Open a PSOutputDev that will write to a generic stream. + PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, + XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA = 0, int imgLLYA = 0, + int imgURXA = 0, int imgURYA = 0, + GBool manualCtrlA = gFalse, + const char *pageRangesA = (const char *)0); + + // 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; } + + // Does this device use tilingPatternFill()? If this returns false, + // tiling pattern fills will be reduced to a series of other drawing + // operations. + virtual GBool useTilingPatternFill() { return gTrue; } + + // Does this device use functionShadedFill(), axialShadedFill(), and + // radialShadedFill()? If this returns false, these shaded fills + // will be reduced to a series of other drawing operations. + virtual GBool useShadedFills() + { return level == psLevel2 || level == psLevel3; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gFalse; } + + //----- header/trailer (used only if manualCtrl is true) + + // Write the document-level header. + void writeHeader(int firstPage, int lastPage, + PDFRectangle *mediaBox, PDFRectangle *cropBox, + int pageRotate); + + // Write the Xpdf procset. + void writeXpdfProcset(); + + // Write the document-level setup. + void writeDocSetup(Catalog *catalog, int firstPage, int lastPage); + + // Write the trailer for the current page. + void writePageTrailer(); + + // Write the document trailer. + void writeTrailer(); + + //----- initialization and control + + // Start a page. + virtual GBool 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 updateFillColorSpace(GfxState *state); + virtual void updateStrokeColorSpace(GfxState *state); + virtual void updateFillColor(GfxState *state); + virtual void updateStrokeColor(GfxState *state); + virtual void updateFillOverprint(GfxState *state); + virtual void updateStrokeOverprint(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); + virtual void tilingPatternFill(GfxState *state, Object *str, + int paintType, Dict *resDict, + double *mat, double *bbox, + int x0, int y0, int x1, int y1, + double xStep, double yStep); + virtual void functionShadedFill(GfxState *state, + GfxFunctionShading *shading); + virtual void axialShadedFill(GfxState *state, GfxAxialShading *shading); + virtual void radialShadedFill(GfxState *state, GfxRadialShading *shading); + + //----- path clipping + virtual void clip(GfxState *state); + virtual void eoClip(GfxState *state); + + //----- text drawing + virtual void drawString(GfxState *state, GString *s); + virtual void endTextObject(GfxState *state); + + //----- 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); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + +#if OPI_SUPPORT + //----- OPI functions + virtual void opiBegin(GfxState *state, Dict *opiDict); + virtual void opiEnd(GfxState *state, Dict *opiDict); +#endif + + //----- Type 3 font operators + virtual void type3D0(GfxState *state, double wx, double wy); + virtual void type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury); + + //----- PostScript XObjects + virtual void psXObject(Stream *psStream, Stream *level1Stream); + + //----- miscellaneous + void setOffset(double x, double y) + { tx0 = x; ty0 = y; } + void setScale(double x, double y) + { xScale0 = x; yScale0 = y; } + void setRotate(int rotateA) + { rotate0 = rotateA; } + void setClip(double llx, double lly, double urx, double ury) + { clipLLX0 = llx; clipLLY0 = lly; clipURX0 = urx; clipURY0 = ury; } + void setUnderlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), + void *data) + { underlayCbk = cbk; underlayCbkData = data; } + void setOverlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), + void *data) + { overlayCbk = cbk; overlayCbkData = data; } + +private: + + void init(PSOutputFunc outputFuncA, void *outputStreamA, + PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, + int firstPage, int lastPage, PSOutMode modeA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, + GBool manualCtrlA, const char *pageRangesA); + void setupResources(Dict *resDict); + void setupFonts(Dict *resDict); + void setupFont(GfxFont *font, Dict *parentResDict); + void setupEmbeddedType1Font(Ref *id, GString *psName); + void setupExternalType1Font(GString *fileName, GString *psName); + void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName); + void setupExternalTrueTypeFont(GfxFont *font, GString *psName); + void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName); + void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName, + GBool needVerticalMetrics); + void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict); + 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(Object *ref, 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, + int *maskColors, Stream *maskStr, + int maskWidth, int maskHeight, GBool maskInvert); + void dumpColorSpaceL2(GfxColorSpace *colorSpace, + GBool genXform, GBool updateColors); +#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 cvtFunction(Function *func); + void writePSChar(char c); + void writePS(char *s); + void writePSFmt(const char *fmt, ...); + void writePSString(GString *s); + void writePSName(char *s); + GString *filterPSName(GString *name); + GBool checkRange(int page); + + PSLevel level; // PostScript level (1, 2, separation) + PSOutMode mode; // PostScript mode (PS, EPS, form) + int paperWidth; // width of paper, in pts + int paperHeight; // height of paper, in pts + int imgLLX, imgLLY, // imageable area, in pts + imgURX, imgURY; + + PSOutputFunc outputFunc; + void *outputStream; + PSFileType fileType; // file / pipe / stdout + GBool manualCtrl; + int seqPage; // current sequential page number + void (*underlayCbk)(PSOutputDev *psOut, void *data); + void *underlayCbkData; + void (*overlayCbk)(PSOutputDev *psOut, void *data); + void *overlayCbkData; + + 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 + int nextTrueTypeNum; // next unique number to append to a TrueType + // font name + PSFont16Enc *font16Enc; // encodings for substitute 16-bit fonts + int font16EncLen; // number of entries in font16Enc array + int font16EncSize; // size of font16Enc array + GList *xobjStack; // stack of XObject dicts currently being + // processed + int numSaves; // current number of gsaves + int numTilingPatterns; // current number of nested tiling patterns + int nextFunc; // next unique number to use for a function + + double tx0, ty0; // global translation + double xScale0, yScale0; // global scaling + int rotate0; // rotation angle (0, 90, 180, 270) + double clipLLX0, clipLLY0, + clipURX0, clipURY0; + double tx, ty; // global translation for current page + double xScale, yScale; // global scaling for current page + int rotate; // rotation angle for current page + double epsX1, epsY1, // EPS bounding box (unrotated) + epsX2, epsY2; + + GString *embFontList; // resource comments for embedded fonts + + int processColors; // used process colors + PSOutCustomColor // used custom colors + *customColors; + + GBool haveTextClip; // set if text has been drawn with a + // clipping render mode + + GBool inType3Char; // inside a Type 3 CharProc + GString *t3String; // Type 3 content string + double t3WX, t3WY, // Type 3 character parameters + t3LLX, t3LLY, t3URX, t3URY; + GBool t3Cacheable; // cleared if char is not cacheable + +#if OPI_SUPPORT + int opi13Nest; // nesting level of OPI 1.3 objects + int opi20Nest; // nesting level of OPI 2.0 objects +#endif + + GBool ok; // set up ok? + const char *pageRanges; // page ranges to render + + friend class WinPDFPrinter; +}; + +#endif diff --git a/pdftops/PSTokenizer.cxx b/pdftops/PSTokenizer.cxx new file mode 100644 index 000000000..834b0ca2d --- /dev/null +++ b/pdftops/PSTokenizer.cxx @@ -0,0 +1,135 @@ +//======================================================================== +// +// PSTokenizer.cc +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "PSTokenizer.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 +}; + +//------------------------------------------------------------------------ + +PSTokenizer::PSTokenizer(int (*getCharFuncA)(void *), void *dataA) { + getCharFunc = getCharFuncA; + data = dataA; + charBuf = -1; +} + +PSTokenizer::~PSTokenizer() { +} + +GBool PSTokenizer::getToken(char *buf, int size, int *length) { + GBool comment, backslash; + int c; + int i; + + // skip whitespace and comments + comment = gFalse; + while (1) { + if ((c = getChar()) == EOF) { + buf[0] = '\0'; + *length = 0; + return gFalse; + } + if (comment) { + if (c == '\x0a' || c == '\x0d') { + comment = gFalse; + } + } else if (c == '%') { + comment = gTrue; + } else if (specialChars[c] != 1) { + break; + } + } + + // read a token + i = 0; + buf[i++] = c; + if (c == '(') { + backslash = gFalse; + while ((c = lookChar()) != EOF) { + if (i < size - 1) { + buf[i++] = c; + } + getChar(); + if (c == '\\') { + backslash = gTrue; + } else if (!backslash && c == ')') { + break; + } else { + backslash = gFalse; + } + } + } else if (c == '<') { + while ((c = lookChar()) != EOF) { + getChar(); + if (i < size - 1) { + buf[i++] = c; + } + if (c == '>') { + break; + } + } + } else if (c != '[' && c != ']') { + while ((c = lookChar()) != EOF && !specialChars[c]) { + getChar(); + if (i < size - 1) { + buf[i++] = c; + } + } + } + buf[i] = '\0'; + *length = i; + + return gTrue; +} + +int PSTokenizer::lookChar() { + if (charBuf < 0) { + charBuf = (*getCharFunc)(data); + } + return charBuf; +} + +int PSTokenizer::getChar() { + int c; + + if (charBuf < 0) { + charBuf = (*getCharFunc)(data); + } + c = charBuf; + charBuf = -1; + return c; +} diff --git a/pdftops/PSTokenizer.h b/pdftops/PSTokenizer.h new file mode 100644 index 000000000..d8d347618 --- /dev/null +++ b/pdftops/PSTokenizer.h @@ -0,0 +1,41 @@ +//======================================================================== +// +// PSTokenizer.h +// +// Copyright 2002-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PSTOKENIZER_H +#define PSTOKENIZER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ + +class PSTokenizer { +public: + + PSTokenizer(int (*getCharFuncA)(void *), void *dataA); + ~PSTokenizer(); + + // Get the next PostScript token. Returns false at end-of-stream. + GBool getToken(char *buf, int size, int *length); + +private: + + int lookChar(); + int getChar(); + + int (*getCharFunc)(void *); + void *data; + int charBuf; +}; + +#endif diff --git a/pdftops/Page.cxx b/pdftops/Page.cxx new file mode 100644 index 000000000..ab0a21ff7 --- /dev/null +++ b/pdftops/Page.cxx @@ -0,0 +1,367 @@ +//======================================================================== +// +// Page.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "GlobalParams.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 "GfxState.h" +#include "Annot.h" +#endif +#include "Error.h" +#include "Page.h" + +//------------------------------------------------------------------------ +// PageAttrs +//------------------------------------------------------------------------ + +PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { + Object obj1; + + // 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 + if (readBox(dict, "CropBox", &cropBox)) { + haveCropBox = gTrue; + } + if (!haveCropBox) { + cropBox = mediaBox; + } + + // 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; + } + + // misc attributes + dict->lookup("LastModified", &lastModified); + dict->lookup("BoxColorInfo", &boxColorInfo); + dict->lookup("Group", &group); + dict->lookup("Metadata", &metadata); + dict->lookup("PieceInfo", &pieceInfo); + dict->lookup("SeparationInfo", &separationInfo); + + // resource dictionary + dict->lookup("Resources", &obj1); + if (obj1.isDict()) { + resources.free(); + obj1.copy(&resources); + } + obj1.free(); +} + +PageAttrs::~PageAttrs() { + lastModified.free(); + boxColorInfo.free(); + group.free(); + metadata.free(); + pieceInfo.free(); + separationInfo.free(); + resources.free(); +} + +GBool PageAttrs::readBox(Dict *dict, char *key, PDFRectangle *box) { + PDFRectangle tmp; + double t; + 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) { + if (tmp.x1 > tmp.x2) { + t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t; + } + if (tmp.y1 > tmp.y2) { + t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t; + } + *box = tmp; + } + } else { + ok = gFalse; + } + obj1.free(); + return ok; +} + +//------------------------------------------------------------------------ +// Page +//------------------------------------------------------------------------ + +Page::Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA) { + ok = gTrue; + xref = xrefA; + num = numA; + + // 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 hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { + displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, + -1, -1, -1, -1, links, catalog, + abortCheckCbk, abortCheckCbkData); +} + +void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data), + void *abortCheckCbkData) { +#ifndef PDF_PARSER_ONLY + PDFRectangle *mediaBox, *cropBox, *baseBox; + PDFRectangle box; + Gfx *gfx; + Object obj; + Link *link; + Annots *annotList; + double kx, ky; + int i; + + rotate += getRotate(); + if (rotate >= 360) { + rotate -= 360; + } else if (rotate < 0) { + rotate += 360; + } + + mediaBox = getMediaBox(); + cropBox = getCropBox(); + if (sliceW >= 0 && sliceH >= 0) { + baseBox = useMediaBox ? mediaBox : cropBox; + kx = 72.0 / hDPI; + ky = 72.0 / vDPI; + if (rotate == 90) { + if (out->upsideDown()) { + box.x1 = baseBox->x1 + ky * sliceY; + box.x2 = baseBox->x1 + ky * (sliceY + sliceH); + } else { + box.x1 = baseBox->x2 - ky * (sliceY + sliceH); + box.x2 = baseBox->x2 - ky * sliceY; + } + box.y1 = baseBox->y1 + kx * sliceX; + box.y2 = baseBox->y1 + kx * (sliceX + sliceW); + } else if (rotate == 180) { + box.x1 = baseBox->x2 - kx * (sliceX + sliceW); + box.x2 = baseBox->x2 - kx * sliceX; + if (out->upsideDown()) { + box.y1 = baseBox->y1 + ky * sliceY; + box.y2 = baseBox->y1 + ky * (sliceY + sliceH); + } else { + box.y1 = baseBox->y2 - ky * (sliceY + sliceH); + box.y2 = baseBox->y2 - ky * sliceY; + } + } else if (rotate == 270) { + if (out->upsideDown()) { + box.x1 = baseBox->x2 - ky * (sliceY + sliceH); + box.x2 = baseBox->x2 - ky * sliceY; + } else { + box.x1 = baseBox->x1 + ky * sliceY; + box.x2 = baseBox->x1 + ky * (sliceY + sliceH); + } + box.y1 = baseBox->y2 - kx * (sliceX + sliceW); + box.y2 = baseBox->y2 - kx * sliceX; + } else { + box.x1 = baseBox->x1 + kx * sliceX; + box.x2 = baseBox->x1 + kx * (sliceX + sliceW); + if (out->upsideDown()) { + box.y1 = baseBox->y2 - ky * (sliceY + sliceH); + box.y2 = baseBox->y2 - ky * sliceY; + } else { + box.y1 = baseBox->y1 + ky * sliceY; + box.y2 = baseBox->y1 + ky * (sliceY + sliceH); + } + } + } else if (useMediaBox) { + box = *mediaBox; + } else { + box = *cropBox; + crop = gFalse; + } + + if (globalParams->getPrintCommands()) { + printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", + mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2); + printf("***** CropBox = ll:%g,%g ur:%g,%g\n", + cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); + printf("***** Rotate = %d\n", attrs->getRotate()); + } + + gfx = new Gfx(xref, out, num, attrs->getResourceDict(), + hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL, + rotate, abortCheckCbk, abortCheckCbkData); + contents.fetch(xref, &obj); + if (!obj.isNull()) { + gfx->saveState(); + gfx->display(&obj); + gfx->restoreState(); + } + obj.free(); + + // draw links + if (links) { + gfx->saveState(); + for (i = 0; i < links->getNumLinks(); ++i) { + link = links->getLink(i); + out->drawLink(link, catalog); + } + gfx->restoreState(); + out->dump(); + } + + // draw non-link annotations + annotList = new Annots(xref, catalog, annots.fetch(xref, &obj)); + obj.free(); + if (annotList->getNumAnnots() > 0) { + if (globalParams->getPrintCommands()) { + printf("***** Annotations\n"); + } + for (i = 0; i < annotList->getNumAnnots(); ++i) { + annotList->getAnnot(i)->draw(gfx); + } + out->dump(); + } + delete annotList; + + delete gfx; +#endif +} + +void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, + int rotate, GBool upsideDown) { + GfxState *state; + int i; + + rotate += getRotate(); + if (rotate >= 360) { + rotate -= 360; + } else if (rotate < 0) { + rotate += 360; + } + state = new GfxState(hDPI, vDPI, getMediaBox(), rotate, upsideDown); + for (i = 0; i < 6; ++i) { + ctm[i] = state->getCTM()[i]; + } + delete state; +} diff --git a/pdftops/Page.h b/pdftops/Page.h new file mode 100644 index 000000000..3177912f4 --- /dev/null +++ b/pdftops/Page.h @@ -0,0 +1,175 @@ +//======================================================================== +// +// Page.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PAGE_H +#define PAGE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "Object.h" + +class Dict; +class XRef; +class OutputDev; +class Links; +class Catalog; + +//------------------------------------------------------------------------ + +class PDFRectangle { +public: + double x1, y1, x2, y2; + + PDFRectangle() { x1 = y1 = x2 = y2 = 0; } + PDFRectangle(double x1A, double y1A, double x2A, double y2A) + { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } + GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } +}; + +//------------------------------------------------------------------------ +// PageAttrs +//------------------------------------------------------------------------ + +class PageAttrs { +public: + + // Construct a new PageAttrs object by merging a dictionary + // (of type Pages or Page) into another PageAttrs object. If + // is NULL, uses defaults. + PageAttrs(PageAttrs *attrs, Dict *dict); + + // Destructor. + ~PageAttrs(); + + // Accessors. + 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; } + GString *getLastModified() + { return lastModified.isString() + ? lastModified.getString() : (GString *)NULL; } + Dict *getBoxColorInfo() + { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; } + Dict *getGroup() + { return group.isDict() ? group.getDict() : (Dict *)NULL; } + Stream *getMetadata() + { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; } + Dict *getPieceInfo() + { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; } + Dict *getSeparationInfo() + { return separationInfo.isDict() + ? separationInfo.getDict() : (Dict *)NULL; } + Dict *getResourceDict() + { return resources.isDict() ? resources.getDict() : (Dict *)NULL; } + +private: + + GBool readBox(Dict *dict, char *key, PDFRectangle *box); + + PDFRectangle mediaBox; + PDFRectangle cropBox; + GBool haveCropBox; + PDFRectangle bleedBox; + PDFRectangle trimBox; + PDFRectangle artBox; + int rotate; + Object lastModified; + Object boxColorInfo; + Object group; + Object metadata; + Object pieceInfo; + Object separationInfo; + Object resources; +}; + +//------------------------------------------------------------------------ +// Page +//------------------------------------------------------------------------ + +class Page { +public: + + // Constructor. + Page(XRef *xrefA, int numA, Dict *pageDict, PageAttrs *attrsA); + + // Destructor. + ~Page(); + + // Is page valid? + GBool isOk() { return ok; } + + // Get page parameters. + PDFRectangle *getMediaBox() { return attrs->getMediaBox(); } + PDFRectangle *getCropBox() { return attrs->getCropBox(); } + GBool isCropped() { return attrs->isCropped(); } + double getMediaWidth() + { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; } + double getMediaHeight() + { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; } + double getCropWidth() + { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; } + double getCropHeight() + { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; } + PDFRectangle *getBleedBox() { return attrs->getBleedBox(); } + PDFRectangle *getTrimBox() { return attrs->getTrimBox(); } + PDFRectangle *getArtBox() { return attrs->getArtBox(); } + int getRotate() { return attrs->getRotate(); } + GString *getLastModified() { return attrs->getLastModified(); } + Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); } + Dict *getGroup() { return attrs->getGroup(); } + Stream *getMetadata() { return attrs->getMetadata(); } + Dict *getPieceInfo() { return attrs->getPieceInfo(); } + Dict *getSeparationInfo() { return attrs->getSeparationInfo(); } + + // 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 hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Display part of a page. + void displaySlice(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, + Links *links, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL); + + // Get the page's default CTM. + void getDefaultCTM(double *ctm, double hDPI, double vDPI, + int rotate, GBool upsideDown); + +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 ok; // true if page is valid +}; + +#endif diff --git a/pdftops/Parser.cxx b/pdftops/Parser.cxx new file mode 100644 index 000000000..455b079ec --- /dev/null +++ b/pdftops/Parser.cxx @@ -0,0 +1,214 @@ +//======================================================================== +// +// Parser.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "Object.h" +#include "Array.h" +#include "Dict.h" +#include "Parser.h" +#include "XRef.h" +#include "Error.h" +#include "Decrypt.h" + +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; +} + +Object *Parser::getObj(Object *obj, + Guchar *fileKey, int keyLength, + int objNum, int objGen) { + char *key; + Stream *str; + Object obj2; + int num; + Decrypt *decrypt; + GString *s; + char *p; + int i; + + // 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()) + obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen)); + 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()) { + gfree(key); + break; + } + obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); + } + } + if (buf1.isEOF()) + error(getPos(), "End of file inside dictionary"); + if (buf2.isCmd("stream")) { + if ((str = makeStream(obj))) { + obj->initStream(str); + if (fileKey) { + str->getBaseStream()->doDecryption(fileKey, keyLength, + objNum, objGen); + } + } 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); + } + + // 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(); + + // simple object + } else { + buf1.copy(obj); + shift(); + } + + return obj; +} + +Stream *Parser::makeStream(Object *dict) { + Object obj; + BaseStream *baseStr; + Stream *str; + Guint pos, endPos, length; + + // get stream start position + lexer->skipToNextLine(); + pos = lexer->getPos(); + + // get length + dict->dictLookup("Length", &obj); + if (obj.isInt()) { + length = (Guint)obj.getInt(); + obj.free(); + } else { + error(getPos(), "Bad 'Length' attribute in stream"); + obj.free(); + return NULL; + } + + // check for length in damaged file + if (xref && xref->getStreamEnd(pos, &endPos)) { + length = endPos - pos; + } + + // in badly damaged PDF files, we can run off the end of the input + // stream immediately after the "stream" token + if (!lexer->getStream()) { + return NULL; + } + baseStr = lexer->getStream()->getBaseStream(); + + // 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'"); + // kludge for broken PDF files: just add 5k to the length, and + // hope its enough + length += 5000; + } + + // make base stream + str = baseStr->makeSubStream(pos, gTrue, length, dict); + + // get filters + str = str->addFilters(dict); + + return str; +} + +void Parser::shift() { + if (inlineImg > 0) { + if (inlineImg < 2) { + ++inlineImg; + } else { + // in a damaged content stream, if 'ID' shows up in the middle + // of a dictionary, we need to reset + inlineImg = 0; + } + } 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..754e9744c --- /dev/null +++ b/pdftops/Parser.h @@ -0,0 +1,56 @@ +//======================================================================== +// +// Parser.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef PARSER_H +#define PARSER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#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. + Object *getObj(Object *obj, + Guchar *fileKey = NULL, int keyLength = 0, + int objNum = 0, int objGen = 0); + + // 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..f089d05d6 --- /dev/null +++ b/pdftops/README @@ -0,0 +1,446 @@ +Xpdf +==== + +version 2.02 +2003-mar-24 + +The Xpdf software and documentation are +copyright 1996-2003 Glyph & Cog, LLC. + +Email: derekn@foolabs.com +WWW: http://www.foolabs.com/xpdf/ + +The PDF data structures, operators, and specification are +copyright 1985-2001 Adobe Systems Inc. + + +What is Xpdf? +------------- + +Xpdf is an open source viewer for Portable Document Format (PDF) +files. (These are also sometimes also called 'Acrobat' files, from +the name of Adobe's PDF software.) The Xpdf project also includes a +PDF text extractor, PDF-to-PostScript converter, and various other +utilities. + +Xpdf runs under the X Window System on UNIX, VMS, and OS/2. The non-X +components (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 see the Glyph & +Cog web site: + + http://www.glyphandcog.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, pdffonts, +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 four additional utilities (which are fully described in +their man pages): + + pdfinfo -- dumps a PDF file's Info dictionary (plus some other + useful information) + pdffonts -- lists the fonts used in a PDF file along with various + information for each font + 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.). + + +Upgrading from Xpdf 0.9x +------------------------ + +WARNING: Xpdf 1.x switched to a completely different config file setup +than Xpdf 0.9x. + +Many of the configuration options that used to be X resources have +been moved into the Xpdf config file. There are also lots of new and +improved options. If you're upgrading from Xpdf 0.9x, please read +through the sample config file (doc/sample-xpdfrc) and the xpdfrc(5) +man page. + +The Asian language support has been pulled out into separate packages, +loaded at run time. This is much cleaner than the 0.9x approach -- it +makes the base distribution smaller, allows the language support +packages to be upgraded separately, and lets users customize Xpdf for +other text encodings without modifying the source. See the web site +(http://www.foolabs.com/xpdf) for info on downloading the language +support packages. + +All of the Xpdf tools, including the X viewer and the command line +programs, read the same config file. They first attempt to read the +user's personal config file: + + $HOME/.xpdfrc + +If it is not found, the Xpdf tools read a system-wide config file, +typically something like: + + /usr/local/etc/xpdfrc + +(this location can be customized when building Xpdf). + +The Win32 command line tools look in the directory containing the +executable, e.g.: + + C:/Program Files/Xpdf/xpdfrc + +Xpdf comes with a "sample-xpdfrc" file in the doc directory. This is +a good starting point for constructing your own config file. + +For full details, please see the xpdfrc(5) man page. + + +Fonts +----- + +By default, Xpdf will use 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 +maybe Zapf Dingbats). + +If Xpdf is built with support for t1lib (or FreeType 2), you can get +much higher quality text by using Type 1 fonts instead of X server +fonts. For example, you can use the Type 1 fonts that come with +ghostscript. To do this, add the following lines to the xpdfrc file +(e.g., /usr/local/etc/xpdfrc or $HOME/.xpdfrc): + +displayFontT1 Times-Roman /usr/local/share/ghostscript/fonts/n021003l.pfb +displayFontT1 Times-Italic /usr/local/share/ghostscript/fonts/n021023l.pfb +displayFontT1 Times-Bold /usr/local/share/ghostscript/fonts/n021004l.pfb +displayFontT1 Times-BoldItalic /usr/local/share/ghostscript/fonts/n021024l.pfb +displayFontT1 Helvetica /usr/local/share/ghostscript/fonts/n019003l.pfb +displayFontT1 Helvetica-Oblique /usr/local/share/ghostscript/fonts/n019023l.pfb +displayFontT1 Helvetica-Bold /usr/local/share/ghostscript/fonts/n019004l.pfb +displayFontT1 Helvetica-BoldOblique /usr/local/share/ghostscript/fonts/n019024l.pfb +displayFontT1 Courier /usr/local/share/ghostscript/fonts/n022003l.pfb +displayFontT1 Courier-Oblique /usr/local/share/ghostscript/fonts/n022023l.pfb +displayFontT1 Courier-Bold /usr/local/share/ghostscript/fonts/n022004l.pfb +displayFontT1 Courier-BoldOblique /usr/local/share/ghostscript/fonts/n022024l.pfb +displayFontT1 Symbol /usr/local/share/ghostscript/fonts/s050000l.pfb +displayFontT1 ZapfDingbats /usr/local/share/ghostscript/fonts/d050000l.pfb + +You will need to replace '/usr/local/share/ghostscript/fonts' with the +appropriate path on your system. + + +Compiling Xpdf +-------------- + +See the separate file, INSTALL. + + +Bugs +---- + +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 and the + xpdf/cygwin/XFree86 build instructions. +* 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. +* Tom Kacvinsky for help with FreeType and for being my interface to + the FreeType team. +* Theppitak Karoonboonyanan for help with Thai support. +* Leonard Rosenthol for help and contributions on a bunch of things. +* Alexandros Diamantidis and Maria Adaloglou for help with Greek + support. +* Lawrence Lai for help with the CJK Unicode maps. + +Various people have contributed modifications made for use by the +pdftex project: + +* Han The Thanh +* Martin Schröder of ArtCom GmbH + + +References +---------- + +Adobe Systems Inc., _PDF Reference: Adobe Portable Document Format +version 1.4_, 3nd ed. +Addison-Wesley, 2001, ISBN 0-201-75839-3. +http://partners.adobe.com/asn/developer/acrosdk/docs/filefmtspecs/PDFReference.pdf +[The printed manual for PDF version 1.4.] + +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-4 Character Collection for +CID-Keyed Fonts_, Adobe Developer Support Technical Note #5078. +2000. +http://partners.adobe.com/asn/developer/PDFS/TN/5078.CID_Glyph.pdf +[The Adobe Japanese character set.] + +Adobe Systems, Inc., _Adobe-GB1-4 Character Collection for +CID-Keyed Fonts_, Adobe Developer Support Technical Note #5079. +2000. +http://partners.adobe.com/asn/developer/pdfs/tn/5079.Adobe-GB1-4.pdf +[The Adobe Chinese GB (simplified) 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 (traditional) 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.] + +Adobe Systems Inc., Unicode glyph lists. +http://partners.adobe.com/asn/developer/type/unicodegn.html +http://partners.adobe.com/asn/developer/type/glyphlist.txt +http://partners.adobe.com/asn/developer/type/corporateuse.txt +http://partners.adobe.com/asn/developer/type/zapfdingbats.txt +[Mappings between character names to Unicode.] + +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.] + +T. Boutell, et al., "PNG (Portable Network Graphics) Specification, +Version 1.0. RFC 2083. +[PDF uses the PNG filter algorithms.] + +CCITT, "Information Technology - Digital Compression and Coding of +Continuous-tone Still Images - Requirements and Guidelines", CCITT +Recommendation T.81. +http://www.w3.org/Graphics/JPEG/ +[The official JPEG spec.] + +A. Chernov, "Registration of a Cyrillic Character Set". RFC 1489. +[Documentation for the KOI8-R Cyrillic encoding.] + +Roman Czyborra, "The ISO 8859 Alphabet Soup". +http://czyborra.com/charsets/iso8859.html +[Documentation on the various ISO 859 encodings.] + +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.] + +ISO/IEC, _Information technology -- Lossy/lossless coding of bi-level +images_. ISO/IEC 14492, First edition (2001-12-15). +http://webstore.ansi.org/ +[The official JBIG2 standard. The final draft of this spec is +available from http://www.jpeg.org/jbighomepage.html.] + +ITU, "Standardization of Group 3 facsimile terminals for document +transmission", ITU-T Recommendation T.4, 1999. +ITU, "Facsimile coding schemes and coding control functions for Group 4 +facsimile apparatus", ITU-T Recommendation T.6, 1993. +http://www.itu.int/ +[The official Group 3 and 4 fax standards - used by the CCITTFaxDecode +stream, as well as the JBIG2Decode stream.] + +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).] + +Thai Industrial Standard, "Standard for Thai Character Codes for +Computers", TIS-620-2533 (1990). +http://www.nectec.or.th/it-standards/std620/std620.htm +[The TIS-620 Thai encoding.] + +P. Peterlin, "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.] + +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.] + +Unicode Consortium, "Unicode Home Page". +http://www.unicode.org/ +[Online copy of the Unicode spec.] + +W3C Recommendation, "PNG (Portable Network Graphics) Specification +Version 1.0". +http://www.w3.org/Graphics/PNG/ +[Defines the PNG image predictor.] + +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.] + +F. Yergeau, "UTF-8, a transformation format of ISO 10646". RFC 2279. +[A commonly used Unicode encoding.] diff --git a/pdftops/SecurityHandler.cxx b/pdftops/SecurityHandler.cxx new file mode 100644 index 000000000..34e766a2c --- /dev/null +++ b/pdftops/SecurityHandler.cxx @@ -0,0 +1,378 @@ +//======================================================================== +// +// SecurityHandler.cc +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "GString.h" +#include "PDFDoc.h" +#include "Decrypt.h" +#include "Error.h" +#include "GlobalParams.h" +#if HAVE_XPDFCORE +# include "XPDFCore.h" +#elif HAVE_WINPDFCORE +# include "WinPDFCore.h" +#endif +#ifdef ENABLE_PLUGINS +# include "XpdfPluginAPI.h" +#endif +#include "SecurityHandler.h" + +//------------------------------------------------------------------------ +// SecurityHandler +//------------------------------------------------------------------------ + +SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) { + Object filterObj; + SecurityHandler *secHdlr; +#ifdef ENABLE_PLUGINS + XpdfSecurityHandler *xsh; +#endif + + encryptDictA->dictLookup("Filter", &filterObj); + if (filterObj.isName("Standard")) { + secHdlr = new StandardSecurityHandler(docA, encryptDictA); + } else if (filterObj.isName()) { +#ifdef ENABLE_PLUGINS + if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) { + secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh); + } else { +#endif + error(-1, "Couldn't find the '%s' security handler", + filterObj.getName()); + secHdlr = NULL; +#ifdef ENABLE_PLUGINS + } +#endif + } else { + error(-1, "Missing or invalid 'Filter' entry in encryption dictionary"); + secHdlr = NULL; + } + filterObj.free(); + return secHdlr; +} + +SecurityHandler::SecurityHandler(PDFDoc *docA) { + doc = docA; +} + +SecurityHandler::~SecurityHandler() { +} + +GBool SecurityHandler::checkEncryption(GString *ownerPassword, + GString *userPassword) { + void *authData; + GBool ok; + int i; + + if (ownerPassword || userPassword) { + authData = makeAuthData(ownerPassword, userPassword); + } else { + authData = NULL; + } + ok = authorize(authData); + if (authData) { + freeAuthData(authData); + } + for (i = 0; !ok && i < 3; ++i) { + if (!(authData = getAuthData())) { + break; + } + ok = authorize(authData); + if (authData) { + freeAuthData(authData); + } + } + if (!ok) { + error(-1, "Incorrect password"); + } + return ok; +} + +//------------------------------------------------------------------------ +// StandardSecurityHandler +//------------------------------------------------------------------------ + +class StandardAuthData { +public: + + StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) { + ownerPassword = ownerPasswordA; + userPassword = userPasswordA; + } + + ~StandardAuthData() { + if (ownerPassword) { + delete ownerPassword; + } + if (userPassword) { + delete userPassword; + } + } + + GString *ownerPassword; + GString *userPassword; +}; + +StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, + Object *encryptDictA): + SecurityHandler(docA) +{ + Object versionObj, revisionObj, lengthObj; + Object ownerKeyObj, userKeyObj, permObj, fileIDObj; + Object fileIDObj1; + Object cryptFiltersObj, streamFilterObj, stringFilterObj; + Object cryptFilterObj, cfmObj, cfLengthObj; + Object encryptMetadataObj; + + ok = gFalse; + fileID = NULL; + ownerKey = NULL; + userKey = NULL; + + encryptDictA->dictLookup("V", &versionObj); + encryptDictA->dictLookup("R", &revisionObj); + encryptDictA->dictLookup("Length", &lengthObj); + encryptDictA->dictLookup("O", &ownerKeyObj); + encryptDictA->dictLookup("U", &userKeyObj); + encryptDictA->dictLookup("P", &permObj); + doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj); + if (versionObj.isInt() && + revisionObj.isInt() && + ownerKeyObj.isString() && ownerKeyObj.getString()->getLength() == 32 && + userKeyObj.isString() && userKeyObj.getString()->getLength() == 32 && + permObj.isInt()) { + encVersion = versionObj.getInt(); + encRevision = revisionObj.getInt(); + // revision 2 forces a 40-bit key - some buggy PDF generators + // set the Length value incorrectly + if (encRevision == 2 || !lengthObj.isInt()) { + fileKeyLength = 5; + } else { + fileKeyLength = lengthObj.getInt() / 8; + } + encryptMetadata = gTrue; + //~ this currently only handles a subset of crypt filter functionality + if (encVersion == 4 && encRevision == 4) { + encryptDictA->dictLookup("CF", &cryptFiltersObj); + encryptDictA->dictLookup("StmF", &streamFilterObj); + encryptDictA->dictLookup("StrF", &stringFilterObj); + if (cryptFiltersObj.isDict() && + streamFilterObj.isName() && + stringFilterObj.isName() && + !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { + if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), + &cryptFilterObj)->isDict()) { + if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) { + encVersion = 2; + encRevision = 3; + if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { + //~ according to the spec, this should be cfLengthObj / 8 + fileKeyLength = cfLengthObj.getInt(); + } + cfLengthObj.free(); + } + cfmObj.free(); + } + cryptFilterObj.free(); + } + stringFilterObj.free(); + streamFilterObj.free(); + cryptFiltersObj.free(); + if (encryptDictA->dictLookup("EncryptMetadata", + &encryptMetadataObj)->isBool()) { + encryptMetadata = encryptMetadataObj.getBool(); + } + encryptMetadataObj.free(); + } + permFlags = permObj.getInt(); + ownerKey = ownerKeyObj.getString()->copy(); + userKey = userKeyObj.getString()->copy(); + if (encVersion >= 1 && encVersion <= 2 && + encRevision >= 2 && encRevision <= 3) { + if (fileIDObj.isArray()) { + if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) { + fileID = fileIDObj1.getString()->copy(); + } else { + fileID = new GString(); + } + fileIDObj1.free(); + } else { + fileID = new GString(); + } + ok = gTrue; + } else { + error(-1, "Unsupported version/revision (%d/%d) of Standard security handler", + encVersion, encRevision); + } + } else { + error(-1, "Weird encryption info"); + } + if (fileKeyLength > 16) { + fileKeyLength = 16; + } + fileIDObj.free(); + permObj.free(); + userKeyObj.free(); + ownerKeyObj.free(); + lengthObj.free(); + revisionObj.free(); + versionObj.free(); +} + +StandardSecurityHandler::~StandardSecurityHandler() { + if (fileID) { + delete fileID; + } + if (ownerKey) { + delete ownerKey; + } + if (userKey) { + delete userKey; + } +} + +void *StandardSecurityHandler::makeAuthData(GString *ownerPassword, + GString *userPassword) { + return new StandardAuthData(ownerPassword ? ownerPassword->copy() + : (GString *)NULL, + userPassword ? userPassword->copy() + : (GString *)NULL); +} + +void *StandardSecurityHandler::getAuthData() { +#if HAVE_XPDFCORE + XPDFCore *core; + GString *password; + + if (!(core = (XPDFCore *)doc->getGUIData()) || + !(password = core->getPassword())) { + return NULL; + } + return new StandardAuthData(password, password->copy()); +#elif HAVE_WINPDFCORE + WinPDFCore *core; + GString *password; + + if (!(core = (WinPDFCore *)doc->getGUIData()) || + !(password = core->getPassword())) { + return NULL; + } + return new StandardAuthData(password, password->copy()); +#else + return NULL; +#endif +} + +void StandardSecurityHandler::freeAuthData(void *authData) { + delete (StandardAuthData *)authData; +} + +GBool StandardSecurityHandler::authorize(void *authData) { + GString *ownerPassword, *userPassword; + + if (!ok) { + return gFalse; + } + if (authData) { + ownerPassword = ((StandardAuthData *)authData)->ownerPassword; + userPassword = ((StandardAuthData *)authData)->userPassword; + } else { + ownerPassword = NULL; + userPassword = NULL; + } + if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength, + ownerKey, userKey, permFlags, fileID, + ownerPassword, userPassword, fileKey, + encryptMetadata, &ownerPasswordOk)) { + return gFalse; + } + return gTrue; +} + +#ifdef ENABLE_PLUGINS + +//------------------------------------------------------------------------ +// ExternalSecurityHandler +//------------------------------------------------------------------------ + +ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA, + Object *encryptDictA, + XpdfSecurityHandler *xshA): + SecurityHandler(docA) +{ + encryptDictA->copy(&encryptDict); + xsh = xshA; + ok = gFalse; + + if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA, + (XpdfObject)encryptDictA, &docData)) { + return; + } + + ok = gTrue; +} + +ExternalSecurityHandler::~ExternalSecurityHandler() { + (*xsh->freeDoc)(xsh->handlerData, docData); + encryptDict.free(); +} + +void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword, + GString *userPassword) { + char *opw, *upw; + void *authData; + + opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL; + upw = userPassword ? userPassword->getCString() : (char *)NULL; + if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) { + return NULL; + } + return authData; +} + +void *ExternalSecurityHandler::getAuthData() { + void *authData; + + if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) { + return NULL; + } + return authData; +} + +void ExternalSecurityHandler::freeAuthData(void *authData) { + (*xsh->freeAuthData)(xsh->handlerData, docData, authData); +} + +GBool ExternalSecurityHandler::authorize(void *authData) { + char *key; + int length; + + if (!ok) { + return gFalse; + } + permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData); + if (!(permFlags & xpdfPermissionOpen)) { + return gFalse; + } + if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) { + return gFalse; + } + if ((fileKeyLength = length) > 16) { + fileKeyLength = 16; + } + memcpy(fileKey, key, fileKeyLength); + (*xsh->freeKey)(xsh->handlerData, docData, key, length); + return gTrue; +} + +#endif // ENABLE_PLUGINS diff --git a/pdftops/SecurityHandler.h b/pdftops/SecurityHandler.h new file mode 100644 index 000000000..db108bab2 --- /dev/null +++ b/pdftops/SecurityHandler.h @@ -0,0 +1,155 @@ +//======================================================================== +// +// SecurityHandler.h +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SECURITYHANDLER_H +#define SECURITYHANDLER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" + +class GString; +class PDFDoc; +struct XpdfSecurityHandler; + +//------------------------------------------------------------------------ +// SecurityHandler +//------------------------------------------------------------------------ + +class SecurityHandler { +public: + + static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA); + + SecurityHandler(PDFDoc *docA); + virtual ~SecurityHandler(); + + // Check the document's encryption. If the document is encrypted, + // this will first try and (in + // "batch" mode), and if those fail, it will attempt to request a + // password from the user. This is the high-level function that + // calls the lower level functions for the specific security handler + // (requesting a password three times, etc.). Returns true if the + // document can be opened (if it's unencrypted, or if a correct + // password is obtained); false otherwise (encrypted and no correct + // password). + GBool checkEncryption(GString *ownerPassword, + GString *userPassword); + + // Create authorization data for the specified owner and user + // passwords. If the security handler doesn't support "batch" mode, + // this function should return NULL. + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword) = 0; + + // Construct authorization data, typically by prompting the user for + // a password. Returns an authorization data object, or NULL to + // cancel. + virtual void *getAuthData() = 0; + + // Free the authorization data returned by makeAuthData or + // getAuthData. + virtual void freeAuthData(void *authData) = 0; + + // Attempt to authorize the document, using the supplied + // authorization data (which may be NULL). Returns true if + // successful (i.e., if at least the right to open the document was + // granted). + virtual GBool authorize(void *authData) = 0; + + // Return the various authorization parameters. These are only + // valid after authorize has returned true. + virtual int getPermissionFlags() = 0; + virtual GBool getOwnerPasswordOk() = 0; + virtual Guchar *getFileKey() = 0; + virtual int getFileKeyLength() = 0; + virtual int getEncVersion() = 0; + +protected: + + PDFDoc *doc; +}; + +//------------------------------------------------------------------------ +// StandardSecurityHandler +//------------------------------------------------------------------------ + +class StandardSecurityHandler: public SecurityHandler { +public: + + StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA); + virtual ~StandardSecurityHandler(); + + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword); + virtual void *getAuthData(); + virtual void freeAuthData(void *authData); + virtual GBool authorize(void *authData); + virtual int getPermissionFlags() { return permFlags; } + virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; } + virtual Guchar *getFileKey() { return fileKey; } + virtual int getFileKeyLength() { return fileKeyLength; } + virtual int getEncVersion() { return encVersion; } + +private: + + int permFlags; + GBool ownerPasswordOk; + Guchar fileKey[16]; + int fileKeyLength; + int encVersion; + int encRevision; + GBool encryptMetadata; + + GString *ownerKey, *userKey; + GString *fileID; + GBool ok; +}; + +#ifdef ENABLE_PLUGINS +//------------------------------------------------------------------------ +// ExternalSecurityHandler +//------------------------------------------------------------------------ + +class ExternalSecurityHandler: public SecurityHandler { +public: + + ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA, + XpdfSecurityHandler *xshA); + virtual ~ExternalSecurityHandler(); + + virtual void *makeAuthData(GString *ownerPassword, + GString *userPassword); + virtual void *getAuthData(); + virtual void freeAuthData(void *authData); + virtual GBool authorize(void *authData); + virtual int getPermissionFlags() { return permFlags; } + virtual GBool getOwnerPasswordOk() { return gFalse; } + virtual Guchar *getFileKey() { return fileKey; } + virtual int getFileKeyLength() { return fileKeyLength; } + virtual int getEncVersion() { return encVersion; } + +private: + + Object encryptDict; + XpdfSecurityHandler *xsh; + void *docData; + int permFlags; + Guchar fileKey[16]; + int fileKeyLength; + int encVersion; + GBool ok; +}; +#endif // ENABLE_PLUGINS + +#endif diff --git a/pdftops/Splash.cxx b/pdftops/Splash.cxx new file mode 100644 index 000000000..0132d425e --- /dev/null +++ b/pdftops/Splash.cxx @@ -0,0 +1,3191 @@ +//======================================================================== +// +// Splash.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashMath.h" +#include "SplashBitmap.h" +#include "SplashState.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashFont.h" +#include "SplashGlyphBitmap.h" +#include "Splash.h" + +//------------------------------------------------------------------------ + +static void blendNormal(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = src[i]; + } +} + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +Splash::Splash(SplashBitmap *bitmapA) { + bitmap = bitmapA; + state = new SplashState(bitmap->width, bitmap->height); + softMask = NULL; + clearModRegion(); + debugMode = gFalse; +} + +Splash::~Splash() { + while (state->next) { + restoreState(); + } + delete state; + if (softMask) { + delete softMask; + } +} + +//------------------------------------------------------------------------ +// state read +//------------------------------------------------------------------------ + +SplashPattern *Splash::getStrokePattern() { + return state->strokePattern; +} + +SplashPattern *Splash::getFillPattern() { + return state->fillPattern; +} + +SplashScreen *Splash::getScreen() { + return state->screen; +} + +SplashBlendFunc Splash::getBlendFunc() { + return state->blendFunc; +} + +SplashCoord Splash::getStrokeAlpha() { + return state->strokeAlpha; +} + +SplashCoord Splash::getFillAlpha() { + return state->fillAlpha; +} + +SplashCoord Splash::getLineWidth() { + return state->lineWidth; +} + +int Splash::getLineCap() { + return state->lineCap; +} + +int Splash::getLineJoin() { + return state->lineJoin; +} + +SplashCoord Splash::getMiterLimit() { + return state->miterLimit; +} + +SplashCoord Splash::getFlatness() { + return state->flatness; +} + +SplashCoord *Splash::getLineDash() { + return state->lineDash; +} + +int Splash::getLineDashLength() { + return state->lineDashLength; +} + +SplashCoord Splash::getLineDashPhase() { + return state->lineDashPhase; +} + +SplashClip *Splash::getClip() { + return state->clip; +} + +//------------------------------------------------------------------------ +// state write +//------------------------------------------------------------------------ + +void Splash::setStrokePattern(SplashPattern *strokePattern) { + state->setStrokePattern(strokePattern); +} + +void Splash::setFillPattern(SplashPattern *fillPattern) { + state->setFillPattern(fillPattern); +} + +void Splash::setScreen(SplashScreen *screen) { + state->setScreen(screen); +} + +void Splash::setBlendFunc(SplashBlendFunc func) { + state->blendFunc = func; +} + +void Splash::setStrokeAlpha(SplashCoord alpha) { + state->strokeAlpha = alpha; +} + +void Splash::setFillAlpha(SplashCoord alpha) { + state->fillAlpha = alpha; +} + +void Splash::setLineWidth(SplashCoord lineWidth) { + state->lineWidth = lineWidth; +} + +void Splash::setLineCap(int lineCap) { + state->lineCap = lineCap; +} + +void Splash::setLineJoin(int lineJoin) { + state->lineJoin = lineJoin; +} + +void Splash::setMiterLimit(SplashCoord miterLimit) { + state->miterLimit = miterLimit; +} + +void Splash::setFlatness(SplashCoord flatness) { + if (flatness < 1) { + state->flatness = 1; + } else { + state->flatness = flatness; + } +} + +void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength, + SplashCoord lineDashPhase) { + state->setLineDash(lineDash, lineDashLength, lineDashPhase); +} + +void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + state->clip->resetToRect(x0, y0, x1, y1); +} + +SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + return state->clip->clipToRect(x0, y0, x1, y1); +} + +SplashError Splash::clipToPath(SplashPath *path, GBool eo) { + return state->clip->clipToPath(path, state->flatness, eo); +} + +//------------------------------------------------------------------------ +// state save/restore +//------------------------------------------------------------------------ + +void Splash::saveState() { + SplashState *newState; + + newState = state->copy(); + newState->next = state; + state = newState; +} + +SplashError Splash::restoreState() { + SplashState *oldState; + + if (!state->next) { + return splashErrNoSave; + } + oldState = state; + state = state->next; + delete oldState; + return splashOk; +} + +//------------------------------------------------------------------------ +// soft mask +//------------------------------------------------------------------------ + +void Splash::setSoftMask(SplashBitmap *softMaskA) { + if (softMask) { + delete softMask; + } + softMask = softMaskA; +} + +//------------------------------------------------------------------------ +// modified region +//------------------------------------------------------------------------ + +void Splash::clearModRegion() { + modXMin = bitmap->getWidth(); + modYMin = bitmap->getHeight(); + modXMax = -1; + modYMax = -1; +} + +inline void Splash::updateModX(int x) { + if (x < modXMin) { + modXMin = x; + } + if (x > modXMax) { + modXMax = x; + } +} + +inline void Splash::updateModY(int y) { + if (y < modYMin) { + modYMin = y; + } + if (y > modYMax) { + modYMax = y; + } +} + +//------------------------------------------------------------------------ +// drawing operations +//------------------------------------------------------------------------ + +void Splash::clear(SplashColorPtr color) { + SplashColorPtr row, p; + Guchar mono; + int x, y; + + switch (bitmap->mode) { + case splashModeMono1: + mono = color[0] ? 0xff : 0x00; + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + mono, -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, mono, bitmap->rowSize * bitmap->height); + } + break; + case splashModeMono8: + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + break; + case splashModeAMono8: + if (color[0] == color[1]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + } + row += bitmap->rowSize; + } + } + break; + case splashModeRGB8: + case splashModeBGR8: + if (color[0] == color[1] && color[1] == color[2]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + } + row += bitmap->rowSize; + } + } + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + *p++ = color[3]; + } + row += bitmap->rowSize; + } + } + break; +#if SPLASH_CMYK + case splashModeACMYK8: + if (color[0] == color[1] && color[1] == color[2] && + color[2] == color[3] && color[3] == color[4]) { + if (bitmap->rowSize < 0) { + memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), + color[0], -bitmap->rowSize * bitmap->height); + } else { + memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); + } + } else { + row = bitmap->data; + for (y = 0; y < bitmap->height; ++y) { + p = row; + for (x = 0; x < bitmap->width; ++x) { + *p++ = color[0]; + *p++ = color[1]; + *p++ = color[2]; + *p++ = color[3]; + *p++ = color[4]; + } + row += bitmap->rowSize; + } + } + break; +#endif + } + + updateModX(0); + updateModY(0); + updateModX(bitmap->width - 1); + updateModY(bitmap->height - 1); +} + +SplashError Splash::stroke(SplashPath *path) { + SplashXPath *xPath, *xPath2; + + if (debugMode) { + printf("stroke [dash:%d] [width:%.2f]:\n", + state->lineDashLength, (double)state->lineWidth); + dumpPath(path); + } + opClipRes = splashClipAllOutside; + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->flatness, gFalse); + if (xPath->length == 0) { + delete xPath; + return splashErrEmptyPath; + } + if (state->lineDashLength > 0) { + xPath2 = makeDashedPath(xPath); + delete xPath; + xPath = xPath2; + } + if (state->lineWidth <= 1) { + strokeNarrow(xPath); + } else { + strokeWide(xPath); + } + delete xPath; + return splashOk; +} + +void Splash::strokeNarrow(SplashXPath *xPath) { + SplashXPathSeg *seg; + int x0, x1, x2, x3, y0, y1, x, y, t; + SplashCoord dx, dy, dxdy; + SplashClipResult clipRes; + int nClipRes[3]; + int i; + + for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { + + x0 = splashFloor(seg->x0); + x1 = splashFloor(seg->x1); + y0 = splashFloor(seg->y0); + y1 = splashFloor(seg->y1); + + // horizontal segment + if (y0 == y1) { + if (x0 > x1) { + t = x0; x0 = x1; x1 = t; + } + if ((clipRes = state->clip->testSpan(x0, x1, y0)) + != splashClipAllOutside) { + drawSpan(x0, x1, y0, state->strokePattern, state->strokeAlpha, + clipRes == splashClipAllInside); + } + + // segment with |dx| > |dy| + } else if (splashAbs(seg->dxdy) > 1) { + dx = seg->x1 - seg->x0; + dy = seg->y1 - seg->y0; + dxdy = seg->dxdy; + if (y0 > y1) { + t = y0; y0 = y1; y1 = t; + t = x0; x0 = x1; x1 = t; + dx = -dx; + dy = -dy; + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, + x0 <= x1 ? x1 : x0, y1)) + != splashClipAllOutside) { + if (dx > 0) { + x2 = x0; + x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy); + drawSpan(x2, (x2 <= x3 - 1) ? x3 - 1 : x2, y0, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); + x2 = x3; + for (y = y0 + 1; y <= y1 - 1; ++y) { + x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); + drawSpan(x2, x3 - 1, y, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); + x2 = x3; + } + drawSpan(x2, x2 <= x1 ? x1 : x2, y1, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); + } else { + x2 = x0; + x3 = splashFloor(seg->x0 + ((SplashCoord)y0 + 1 - seg->y0) * dxdy); + drawSpan((x3 + 1 <= x2) ? x3 + 1 : x2, x2, y0, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); + x2 = x3; + for (y = y0 + 1; y <= y1 - 1; ++y) { + x3 = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); + drawSpan(x3 + 1, x2, y, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); + x2 = x3; + } + drawSpan(x1, (x1 <= x2) ? x2 : x1, y1, state->strokePattern, + state->strokeAlpha, clipRes == splashClipAllInside); + } + } + + // segment with |dy| > |dx| + } else { + dxdy = seg->dxdy; + if (y0 > y1) { + t = x0; x0 = x1; x1 = t; + t = y0; y0 = y1; y1 = t; + } + if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, + x0 <= x1 ? x1 : x0, y1)) + != splashClipAllOutside) { + drawPixel(x0, y0, state->strokePattern, state->strokeAlpha, + clipRes == splashClipAllInside); + for (y = y0 + 1; y <= y1 - 1; ++y) { + x = splashFloor(seg->x0 + ((SplashCoord)y - seg->y0) * dxdy); + drawPixel(x, y, state->strokePattern, state->strokeAlpha, + clipRes == splashClipAllInside); + } + drawPixel(x1, y1, state->strokePattern, state->strokeAlpha, + clipRes == splashClipAllInside); + } + } + ++nClipRes[clipRes]; + } + if (nClipRes[splashClipPartial] || + (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { + opClipRes = splashClipPartial; + } else if (nClipRes[splashClipAllInside]) { + opClipRes = splashClipAllInside; + } else { + opClipRes = splashClipAllOutside; + } +} + +void Splash::strokeWide(SplashXPath *xPath) { + SplashXPathSeg *seg, *seg2; + SplashPath *widePath; + SplashCoord d, dx, dy, wdx, wdy, dxPrev, dyPrev, wdxPrev, wdyPrev; + SplashCoord dotprod, miter; + int i, j; + + dx = dy = wdx = wdy = 0; // make gcc happy + dxPrev = dyPrev = wdxPrev = wdyPrev = 0; // make gcc happy + + for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { + + // save the deltas for the previous segment; if this is the first + // segment on a subpath, compute the deltas for the last segment + // on the subpath (which may be used to draw a line join) + if (seg->flags & splashXPathFirst) { + for (j = i + 1, seg2 = &xPath->segs[j]; j < xPath->length; ++j, ++seg2) { + if (seg2->flags & splashXPathLast) { + d = splashDist(seg2->x0, seg2->y0, seg2->x1, seg2->y1); + if (d == 0) { + //~ not clear what the behavior should be for joins with d==0 + dxPrev = 0; + dyPrev = 1; + } else { + d = (SplashCoord)1 / d; + dxPrev = d * (seg2->x1 - seg2->x0); + dyPrev = d * (seg2->y1 - seg2->y0); + } + wdxPrev = (SplashCoord)0.5 * state->lineWidth * dxPrev; + wdyPrev = (SplashCoord)0.5 * state->lineWidth * dyPrev; + break; + } + } + } else { + dxPrev = dx; + dyPrev = dy; + wdxPrev = wdx; + wdyPrev = wdy; + } + + // compute deltas for this line segment + d = splashDist(seg->x0, seg->y0, seg->x1, seg->y1); + if (d == 0) { + // we need to draw end caps on zero-length lines + //~ not clear what the behavior should be for splashLineCapButt with d==0 + dx = 0; + dy = 1; + } else { + d = (SplashCoord)1 / d; + dx = d * (seg->x1 - seg->x0); + dy = d * (seg->y1 - seg->y0); + } + wdx = (SplashCoord)0.5 * state->lineWidth * dx; + wdy = (SplashCoord)0.5 * state->lineWidth * dy; + + // initialize the path (which will be filled) + widePath = new SplashPath(); + widePath->moveTo(seg->x0 - wdy, seg->y0 + wdx); + + // draw the start cap + if (seg->flags & splashXPathEnd0) { + switch (state->lineCap) { + case splashLineCapButt: + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + break; + case splashLineCapRound: + widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0); + break; + case splashLineCapProjecting: + widePath->lineTo(seg->x0 - wdx - wdy, seg->y0 + wdx - wdy); + widePath->lineTo(seg->x0 - wdx + wdy, seg->y0 - wdx - wdy); + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + break; + } + } else { + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + } + + // draw the left side of the segment + widePath->lineTo(seg->x1 + wdy, seg->y1 - wdx); + + // draw the end cap + if (seg->flags & splashXPathEnd1) { + switch (state->lineCap) { + case splashLineCapButt: + widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); + break; + case splashLineCapRound: + widePath->arcCWTo(seg->x1 - wdy, seg->y1 + wdx, seg->x1, seg->y1); + break; + case splashLineCapProjecting: + widePath->lineTo(seg->x1 + wdx + wdy, seg->y1 - wdx + wdy); + widePath->lineTo(seg->x1 + wdx - wdy, seg->y1 + wdx + wdy); + widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); + break; + } + } else { + widePath->lineTo(seg->x1 - wdy, seg->y1 + wdx); + } + + // draw the right side of the segment + widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); + + // fill the segment + fillWithPattern(widePath, gTrue, state->strokePattern, state->strokeAlpha); + delete widePath; + + // draw the line join + if (!(seg->flags & splashXPathEnd0)) { + widePath = NULL; + switch (state->lineJoin) { + case splashLineJoinMiter: + dotprod = -(dx * dxPrev + dy * dyPrev); + if (splashAbs(splashAbs(dotprod) - 1) > 0.01) { + widePath = new SplashPath(); + widePath->moveTo(seg->x0, seg->y0); + miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); + if (splashSqrt(miter) <= state->miterLimit) { + miter = splashSqrt(miter - 1); + if (dy * dxPrev > dx * dyPrev) { + widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); + widePath->lineTo(seg->x0 + wdy - miter * wdx, + seg->y0 - wdx - miter * wdy); + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + } else { + widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); + widePath->lineTo(seg->x0 - wdy - miter * wdx, + seg->y0 + wdx - miter * wdy); + widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); + } + } else { + if (dy * dxPrev > dx * dyPrev) { + widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + } else { + widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); + widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); + } + } + } + break; + case splashLineJoinRound: + widePath = new SplashPath(); + widePath->moveTo(seg->x0 + wdy, seg->y0 - wdx); + widePath->arcCWTo(seg->x0 + wdy, seg->y0 - wdx, seg->x0, seg->y0); + break; + case splashLineJoinBevel: + widePath = new SplashPath(); + widePath->moveTo(seg->x0, seg->y0); + if (dy * dxPrev > dx * dyPrev) { + widePath->lineTo(seg->x0 + wdyPrev, seg->y0 - wdxPrev); + widePath->lineTo(seg->x0 + wdy, seg->y0 - wdx); + } else { + widePath->lineTo(seg->x0 - wdyPrev, seg->y0 + wdxPrev); + widePath->lineTo(seg->x0 - wdy, seg->y0 + wdx); + } + break; + } + if (widePath) { + fillWithPattern(widePath, gTrue, state->strokePattern, + state->strokeAlpha); + delete widePath; + } + } + } +} + +SplashXPath *Splash::makeDashedPath(SplashXPath *xPath) { + SplashXPath *dPath; + GBool lineDashStartOn, lineDashOn; + GBool atSegStart, atSegEnd, atDashStart, atDashEnd; + int lineDashStartIdx, lineDashIdx, subpathStart; + SplashCoord lineDashTotal, lineDashStartPhase, lineDashDist; + int segIdx; + SplashXPathSeg *seg; + SplashCoord sx0, sy0, sx1, sy1, ax0, ay0, ax1, ay1, dist; + int i; + + dPath = new SplashXPath(); + + lineDashTotal = 0; + for (i = 0; i < state->lineDashLength; ++i) { + lineDashTotal += state->lineDash[i]; + } + lineDashStartPhase = state->lineDashPhase; + i = splashFloor(lineDashStartPhase / lineDashTotal); + lineDashStartPhase -= (SplashCoord)i * lineDashTotal; + lineDashStartOn = gTrue; + lineDashStartIdx = 0; + while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { + lineDashStartOn = !lineDashStartOn; + lineDashStartPhase -= state->lineDash[lineDashStartIdx]; + ++lineDashStartIdx; + } + + segIdx = 0; + seg = xPath->segs; + sx0 = seg->x0; + sy0 = seg->y0; + sx1 = seg->x1; + sy1 = seg->y1; + dist = splashDist(sx0, sy0, sx1, sy1); + lineDashOn = lineDashStartOn; + lineDashIdx = lineDashStartIdx; + lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; + atSegStart = gTrue; + atDashStart = gTrue; + subpathStart = dPath->length; + + while (segIdx < xPath->length) { + + ax0 = sx0; + ay0 = sy0; + if (dist <= lineDashDist) { + ax1 = sx1; + ay1 = sy1; + lineDashDist -= dist; + dist = 0; + atSegEnd = gTrue; + atDashEnd = lineDashDist == 0 || (seg->flags & splashXPathLast); + } else { + ax1 = sx0 + (lineDashDist / dist) * (sx1 - sx0); + ay1 = sy0 + (lineDashDist / dist) * (sy1 - sy0); + sx0 = ax1; + sy0 = ay1; + dist -= lineDashDist; + lineDashDist = 0; + atSegEnd = gFalse; + atDashEnd = gTrue; + } + + if (lineDashOn) { + dPath->addSegment(ax0, ay0, ax1, ay1, + atDashStart, atDashEnd, + atDashStart, atDashEnd); + // end of closed subpath + if (atSegEnd && + (seg->flags & splashXPathLast) && + !(seg->flags & splashXPathEnd1)) { + dPath->segs[subpathStart].flags &= ~splashXPathEnd0; + dPath->segs[dPath->length - 1].flags &= ~splashXPathEnd1; + } + } + + if (atDashEnd) { + lineDashOn = !lineDashOn; + if (++lineDashIdx == state->lineDashLength) { + lineDashIdx = 0; + } + lineDashDist = state->lineDash[lineDashIdx]; + atDashStart = gTrue; + } else { + atDashStart = gFalse; + } + if (atSegEnd) { + if (++segIdx < xPath->length) { + ++seg; + sx0 = seg->x0; + sy0 = seg->y0; + sx1 = seg->x1; + sy1 = seg->y1; + dist = splashDist(sx0, sy0, sx1, sy1); + if (seg->flags & splashXPathFirst) { + lineDashOn = lineDashStartOn; + lineDashIdx = lineDashStartIdx; + lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; + atDashStart = gTrue; + subpathStart = dPath->length; + } + } + atSegStart = gTrue; + } else { + atSegStart = gFalse; + } + } + + return dPath; +} + +SplashError Splash::fill(SplashPath *path, GBool eo) { + if (debugMode) { + printf("fill [eo:%d]:\n", eo); + dumpPath(path); + } + return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); +} + +SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern, + SplashCoord alpha) { + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes, clipRes2; + + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->flatness, gTrue); + xPath->sort(); + scanner = new SplashXPathScanner(xPath, eo); + + // get the min and max x and y values + scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); + + // check clipping + if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) + != splashClipAllOutside) { + + // limit the y range + if (yMinI < state->clip->getYMin()) { + yMinI = state->clip->getYMin(); + } + if (yMaxI > state->clip->getYMax()) { + yMaxI = state->clip->getYMax(); + } + + // draw the spans + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + drawSpan(x0, x1, y, pattern, alpha, gTrue); + } else { + // limit the x range + if (x0 < state->clip->getXMin()) { + x0 = state->clip->getXMin(); + } + if (x1 > state->clip->getXMax()) { + x1 = state->clip->getXMax(); + } + clipRes2 = state->clip->testSpan(x0, x1, y); + drawSpan(x0, x1, y, pattern, alpha, clipRes2 == splashClipAllInside); + } + } + } + } + opClipRes = clipRes; + + delete scanner; + delete xPath; + return splashOk; +} + +SplashError Splash::xorFill(SplashPath *path, GBool eo) { + SplashXPath *xPath; + SplashXPathScanner *scanner; + int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; + SplashClipResult clipRes, clipRes2; + + if (path->length == 0) { + return splashErrEmptyPath; + } + xPath = new SplashXPath(path, state->flatness, gTrue); + xPath->sort(); + scanner = new SplashXPathScanner(xPath, eo); + + // get the min and max x and y values + scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); + + // check clipping + if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) + != splashClipAllOutside) { + + // limit the y range + if (yMinI < state->clip->getYMin()) { + yMinI = state->clip->getYMin(); + } + if (yMaxI > state->clip->getYMax()) { + yMaxI = state->clip->getYMax(); + } + + // draw the spans + for (y = yMinI; y <= yMaxI; ++y) { + while (scanner->getNextSpan(y, &x0, &x1)) { + if (clipRes == splashClipAllInside) { + xorSpan(x0, x1, y, state->fillPattern, gTrue); + } else { + // limit the x range + if (x0 < state->clip->getXMin()) { + x0 = state->clip->getXMin(); + } + if (x1 > state->clip->getXMax()) { + x1 = state->clip->getXMax(); + } + clipRes2 = state->clip->testSpan(x0, x1, y); + xorSpan(x0, x1, y, state->fillPattern, + clipRes2 == splashClipAllInside); + } + } + } + } + opClipRes = clipRes; + + delete scanner; + delete xPath; + return splashOk; +} + +void Splash::drawPixel(int x, int y, SplashColorPtr color, + SplashCoord alpha, GBool noClip) { + SplashBlendFunc blendFunc; + SplashColorPtr p; + SplashColor dest, blend; + int alpha2, ialpha2; + Guchar t; + + if (noClip || state->clip->test(x, y)) { + if (alpha != 1 || softMask || state->blendFunc) { + blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; + if (softMask) { + alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]); + } else { + alpha2 = (int)(alpha * 255); + } + ialpha2 = 255 - alpha2; + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + dest[0] = (*p >> (7 - (x & 7))) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= 0x80 >> (x & 7); + } else { + *p &= ~(0x80 >> (x & 7)); + } + break; + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x]; + (*blendFunc)(color, p, blend, bitmap->mode); + // note: floor(x / 255) = x >> 8 (for 16-bit x) + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + break; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + break; + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; + break; +#endif + } + } else { + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + if (color[0]) { + *p |= 0x80 >> (x & 7); + } else { + *p &= ~(0x80 >> (x & 7)); + } + break; + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x]; + p[0] = color[0]; + break; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x]; + p[0] = color[0]; + p[1] = color[1]; + break; + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + p[4] = color[4]; + break; +#endif + } + } + updateModX(x); + updateModY(y); + } +} + +void Splash::drawPixel(int x, int y, SplashPattern *pattern, + SplashCoord alpha, GBool noClip) { + SplashBlendFunc blendFunc; + SplashColor color; + SplashColorPtr p; + SplashColor dest, blend; + int alpha2, ialpha2; + Guchar t; + + if (noClip || state->clip->test(x, y)) { + if (alpha != 1 || softMask || state->blendFunc) { + blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; + pattern->getColor(x, y, color); + if (softMask) { + alpha2 = (int)(alpha * softMask->data[y * softMask->rowSize + x]); + } else { + alpha2 = (int)(alpha * 255); + } + ialpha2 = 255 - alpha2; + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + dest[0] = (*p >> (7 - (x & 7))) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= 0x80 >> (x & 7); + } else { + *p &= ~(0x80 >> (x & 7)); + } + break; + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x]; + (*blendFunc)(color, p, blend, bitmap->mode); + // note: floor(x / 255) = x >> 8 (for 16-bit x) + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + break; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + break; + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x]; + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; + break; +#endif + } + } else { + pattern->getColor(x, y, color); + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; + if (color[0]) { + *p |= 0x80 >> (x & 7); + } else { + *p &= ~(0x80 >> (x & 7)); + } + break; + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x]; + p[0] = color[0]; + break; + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x]; + p[0] = color[0]; + p[1] = color[1]; + break; + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x]; + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + p[4] = color[4]; + break; +#endif + } + } + updateModX(x); + updateModY(y); + } +} + +void Splash::drawSpan(int x0, int x1, int y, SplashPattern *pattern, + SplashCoord alpha, GBool noClip) { + SplashBlendFunc blendFunc; + SplashColor color; + SplashColorPtr p; + SplashColor dest, blend; + Guchar mask, t; + int alpha2, ialpha2; + int i, j, n; + + n = x1 - x0 + 1; + + if (noClip) { + updateModX(x0); + updateModX(x1); + updateModY(y); + } + + if (alpha != 1 || softMask || state->blendFunc) { + blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; + if (softMask) { + alpha2 = ialpha2 = 0; // make gcc happy + } else { + alpha2 = (int)(alpha * 255); + ialpha2 = 255 - alpha2; + } + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; + i = 0; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + if ((j = x0 & 7)) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + dest[0] = (*p >> (7 - j)) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + while (i < n) { + mask = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + dest[0] = (*p >> (7 - j)) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + } else { + if ((j = x0 & 7)) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + dest[0] = (*p >> (7 - j)) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + while (i < n) { + mask = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + dest[0] = (*p >> (7 - j)) & 1; + (*blendFunc)(color, dest, blend, bitmap->mode); + t = (alpha2 * blend[0] + ialpha2 * dest[0]) >> 8; + if (t) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + } + break; + + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + *p = (alpha2 * blend[0] + ialpha2 * *p) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; + } + } + break; + + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; + } + } + break; + + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + } + break; + + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (softMask) { + alpha2 = (int)(alpha * + softMask->data[y * softMask->rowSize + x0 + i]); + ialpha2 = 255 - alpha2; + } + (*blendFunc)(color, p, blend, bitmap->mode); + p[0] = (alpha2 * blend[0] + ialpha2 * p[0]) >> 8; + p[1] = (alpha2 * blend[1] + ialpha2 * p[1]) >> 8; + p[2] = (alpha2 * blend[2] + ialpha2 * p[2]) >> 8; + p[3] = (alpha2 * blend[3] + ialpha2 * p[3]) >> 8; + p[4] = (alpha2 * blend[4] + ialpha2 * p[4]) >> 8; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } + break; +#endif + } + + } else { + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; + i = 0; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + if ((j = x0 & 7)) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + if (color[0]) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + while (i < n) { + mask = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + if (color[0]) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + } else { + if ((j = x0 & 7)) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (color[0]) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + while (i < n) { + mask = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (color[0]) { + *p |= mask; + } else { + *p &= ~mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + } + break; + + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + *p = color[0]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + *p = color[0]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; + } + } + break; + + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + p[0] = color[0]; + p[1] = color[1]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] = color[0]; + p[1] = color[1]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; + } + } + break; + + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + } + break; + + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; + if (pattern->isStatic()) { + pattern->getColor(0, 0, color); + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + p[4] = color[4]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } else { + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] = color[0]; + p[1] = color[1]; + p[2] = color[2]; + p[3] = color[3]; + p[4] = color[4]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + } + break; +#endif + } + } +} + +void Splash::xorSpan(int x0, int x1, int y, SplashPattern *pattern, + GBool noClip) { + SplashColor color; + SplashColorPtr p; + Guchar mask; + int i, j, n; + + n = x1 - x0 + 1; + + if (noClip) { + updateModX(x0); + updateModX(x1); + updateModY(y); + } + + switch (bitmap->mode) { + case splashModeMono1: + p = &bitmap->data[y * bitmap->rowSize + (x0 >> 3)]; + i = 0; + if ((j = x0 & 7)) { + mask = 0x80 >> j; + for (; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (color[0]) { + *p ^= mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + while (i < n) { + mask = 0x80; + for (j = 0; j < 8 && i < n; ++i, ++j) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + if (color[0]) { + *p ^= mask; + } + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + mask >>= 1; + } + ++p; + } + break; + + case splashModeMono8: + p = &bitmap->data[y * bitmap->rowSize + x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + *p ^= color[0]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + ++p; + } + break; + + case splashModeAMono8: + p = &bitmap->data[y * bitmap->rowSize + 2 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] ^= color[0]; + p[1] ^= color[1]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 2; + } + break; + + case splashModeRGB8: + case splashModeBGR8: + p = &bitmap->data[y * bitmap->rowSize + 3 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] ^= color[0]; + p[1] ^= color[1]; + p[2] ^= color[2]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 3; + } + break; + + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &bitmap->data[y * bitmap->rowSize + 4 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] ^= color[0]; + p[1] ^= color[1]; + p[2] ^= color[2]; + p[3] ^= color[3]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &bitmap->data[y * bitmap->rowSize + 5 * x0]; + for (i = 0; i < n; ++i) { + if (noClip || state->clip->test(x0 + i, y)) { + pattern->getColor(x0 + i, y, color); + p[0] ^= color[0]; + p[1] ^= color[1]; + p[2] ^= color[2]; + p[3] ^= color[3]; + p[4] ^= color[4]; + if (!noClip) { + updateModX(x0 + i); + updateModY(y); + } + } + p += 4; + } + break; +#endif + } +} + +SplashError Splash::fillChar(SplashCoord x, SplashCoord y, + int c, SplashFont *font) { + SplashGlyphBitmap glyph; + int x0, y0, xFrac, yFrac; + SplashError err; + + if (debugMode) { + printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", + (double)x, (double)y, c, c, c); + } + x0 = splashFloor(x); + xFrac = splashFloor((x - x0) * splashFontFraction); + y0 = splashFloor(y); + yFrac = splashFloor((y - y0) * splashFontFraction); + if (!font->getGlyph(c, xFrac, yFrac, &glyph)) { + return splashErrNoGlyph; + } + err = fillGlyph(x, y, &glyph); + if (glyph.freeData) { + gfree(glyph.data); + } + return err; +} + +SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph) { + SplashBlendFunc blendFunc; + int alpha0, alpha, ialpha; + Guchar *p; + SplashColor fg, dest, blend; + SplashColorPtr pix; + SplashClipResult clipRes; + GBool noClip; + Guchar t; + int x0, y0, x1, y1, xx, xx1, yy; + + x0 = splashFloor(x); + y0 = splashFloor(y); + + if ((clipRes = state->clip->testRect(x0 - glyph->x, + y0 - glyph->y, + x0 - glyph->x + glyph->w - 1, + y0 - glyph->y + glyph->h - 1)) + != splashClipAllOutside) { + noClip = clipRes == splashClipAllInside; + + if (noClip) { + updateModX(x0 - glyph->x); + updateModX(x0 - glyph->x + glyph->w - 1); + updateModY(y0 - glyph->y); + updateModY(y0 - glyph->y + glyph->h - 1); + } + + //~ optimize this + if (state->fillAlpha != 1 || softMask || state->blendFunc) { + blendFunc = state->blendFunc ? state->blendFunc : &blendNormal; + if (glyph->aa) { + p = glyph->data; + for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { + for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { + alpha = *p++; + if (softMask) { + alpha = (int)(alpha * state->fillAlpha * + softMask->data[y1 * softMask->rowSize + x1]); + } else { + alpha = (int)(alpha * state->fillAlpha); + } + if (alpha > 0) { + if (noClip || state->clip->test(x1, y1)) { + ialpha = 255 - alpha; + state->fillPattern->getColor(x1, y1, fg); + switch (bitmap->mode) { + case splashModeMono1: + pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; + dest[0] = (*pix >> (7 - (x1 & 7))) & 1; + (*blendFunc)(fg, dest, blend, bitmap->mode); + t = (alpha * blend[0] + ialpha * dest[0]) >> 8; + if (t) { + *pix |= 0x80 >> (x1 & 7); + } else { + *pix &= ~(0x80 >> (x1 & 7)); + } + break; + case splashModeMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + // note: floor(x / 255) = x >> 8 (for 16-bit x) + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + break; + case splashModeAMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + break; + case splashModeRGB8: + case splashModeBGR8: + pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; + pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8; + break; +#endif + } + if (!noClip) { + updateModX(x1); + updateModY(y1); + } + } + } + } + } + + } else { + p = glyph->data; + for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { + for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { + alpha0 = *p++; + for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { + if (alpha0 & 0x80) { + if (noClip || state->clip->test(x1, y1)) { + if (softMask) { + alpha = (int)(state->fillAlpha * + softMask->data[y1 * softMask->rowSize + x1]); + } else { + alpha = (int)(state->fillAlpha * 255); + } + ialpha = 255 - alpha; + state->fillPattern->getColor(x1, y1, fg); + switch (bitmap->mode) { + case splashModeMono1: + pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; + dest[0] = (*pix >> (7 - (x1 & 7))) & 1; + (*blendFunc)(fg, dest, blend, bitmap->mode); + t = (alpha * blend[0] + ialpha * dest[0]) >> 8; + if (t) { + *pix |= 0x80 >> (x1 & 7); + } else { + *pix &= ~(0x80 >> (x1 & 7)); + } + break; + case splashModeMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + // note: floor(x / 255) = x >> 8 (for 16-bit x) + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + break; + case splashModeAMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + break; + case splashModeRGB8: + case splashModeBGR8: + pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; + (*blendFunc)(fg, pix, blend, bitmap->mode); + pix[0] = (alpha * blend[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * blend[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * blend[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * blend[3] + ialpha * pix[3]) >> 8; + pix[4] = (alpha * blend[4] + ialpha * pix[4]) >> 8; + break; +#endif + } + if (!noClip) { + updateModX(x1); + updateModY(y1); + } + } + } + alpha0 <<= 1; + } + } + } + } + + } else { + if (glyph->aa) { + p = glyph->data; + for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { + for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { + alpha = *p++; + if (alpha > 0) { + if (noClip || state->clip->test(x1, y1)) { + ialpha = 255 - alpha; + state->fillPattern->getColor(x1, y1, fg); + switch (bitmap->mode) { + case splashModeMono1: + if (alpha >= 0x80) { + pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; + if (fg[0]) { + *pix |= 0x80 >> (x1 & 7); + } else { + *pix &= ~(0x80 >> (x1 & 7)); + } + } + break; + case splashModeMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + x1]; + // note: floor(x / 255) = x >> 8 (for 16-bit x) + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + break; + case splashModeAMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; + break; + case splashModeRGB8: + case splashModeBGR8: + pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; + pix[0] = (alpha * fg[0] + ialpha * pix[0]) >> 8; + pix[1] = (alpha * fg[1] + ialpha * pix[1]) >> 8; + pix[2] = (alpha * fg[2] + ialpha * pix[2]) >> 8; + pix[3] = (alpha * fg[3] + ialpha * pix[3]) >> 8; + pix[4] = (alpha * fg[4] + ialpha * pix[4]) >> 8; + break; +#endif + } + if (!noClip) { + updateModX(x1); + updateModY(y1); + } + } + } + } + } + + } else { + p = glyph->data; + for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { + for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { + alpha0 = *p++; + for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { + if (alpha0 & 0x80) { + if (noClip || state->clip->test(x1, y1)) { + state->fillPattern->getColor(x1, y1, fg); + switch (bitmap->mode) { + case splashModeMono1: + pix = &bitmap->data[y1 * bitmap->rowSize + (x1 >> 3)]; + if (fg[0]) { + *pix |= 0x80 >> (x1 & 7); + } else { + *pix &= ~(0x80 >> (x1 & 7)); + } + break; + case splashModeMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + x1]; + pix[0] = fg[0]; + break; + case splashModeAMono8: + pix = &bitmap->data[y1 * bitmap->rowSize + 2 * x1]; + pix[0] = fg[0]; + pix[1] = fg[1]; + break; + case splashModeRGB8: + case splashModeBGR8: + pix = &bitmap->data[y1 * bitmap->rowSize + 3 * x1]; + pix[0] = fg[0]; + pix[1] = fg[1]; + pix[2] = fg[2]; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + pix = &bitmap->data[y1 * bitmap->rowSize + 4 * x1]; + pix[0] = fg[0]; + pix[1] = fg[1]; + pix[2] = fg[2]; + pix[3] = fg[3]; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + pix = &bitmap->data[y1 * bitmap->rowSize + 5 * x1]; + pix[0] = fg[0]; + pix[1] = fg[1]; + pix[2] = fg[2]; + pix[3] = fg[3]; + pix[4] = fg[4]; + break; +#endif + } + if (!noClip) { + updateModX(x1); + updateModY(y1); + } + } + } + alpha0 <<= 1; + } + } + } + } + } + } + opClipRes = clipRes; + + return splashOk; +} + +SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat) { + GBool rot; + SplashCoord xScale, yScale, xShear, yShear, yShear1; + int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign; + int ulx, uly, llx, lly, urx, ury, lrx, lry; + int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; + int xMin, xMax, yMin, yMax; + SplashClipResult clipRes, clipRes2; + int yp, yq, yt, yStep, lastYStep; + int xp, xq, xt, xStep, xSrc; + int k1, spanXMin, spanXMax, spanY; + SplashColorPtr pixBuf, p; + int pixAcc; + SplashCoord alpha; + int x, y, x1, x2, y2; + SplashCoord y1; + int n, m, i, j; + + if (debugMode) { + printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); + } + + // check for singular matrix + if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { + return splashErrSingularMatrix; + } + + // compute scale, shear, rotation, translation parameters + rot = splashAbs(mat[1]) > splashAbs(mat[0]); + if (rot) { + xScale = -mat[1]; + yScale = mat[2] - (mat[0] * mat[3]) / mat[1]; + xShear = -mat[3] / yScale; + yShear = -mat[0] / mat[1]; + } else { + xScale = mat[0]; + yScale = mat[3] - (mat[1] * mat[2]) / mat[0]; + xShear = mat[2] / yScale; + yShear = mat[1] / mat[0]; + } + // the +/-0.01 in these computations is to avoid floating point + // precision problems which can lead to gaps between image stripes + // (it can cause image stripes to overlap, but that's a much less + // visible problem) + if (xScale >= 0) { + tx = splashRound(mat[4] - 0.01); + tx2 = splashRound(mat[4] + xScale + 0.01) - 1; + } else { + tx = splashRound(mat[4] + 0.01) - 1; + tx2 = splashRound(mat[4] + xScale - 0.01); + } + scaledWidth = abs(tx2 - tx) + 1; + if (scaledWidth == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledWidth = 1; + } + if (yScale >= 0) { + ty = splashRound(mat[5] - 0.01); + ty2 = splashRound(mat[5] + yScale + 0.01) - 1; + } else { + ty = splashRound(mat[5] + 0.01) - 1; + ty2 = splashRound(mat[5] + yScale - 0.01); + } + scaledHeight = abs(ty2 - ty) + 1; + if (scaledHeight == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledHeight = 1; + } + xSign = (xScale < 0) ? -1 : 1; + ySign = (yScale < 0) ? -1 : 1; + yShear1 = (SplashCoord)xSign * yShear; + + // clipping + ulx1 = 0; + uly1 = 0; + urx1 = xSign * (scaledWidth - 1); + ury1 = (int)(yShear * urx1); + llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); + lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1); + lrx1 = xSign * (scaledWidth - 1) + + splashRound(xShear * ySign * (scaledHeight - 1)); + lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1); + if (rot) { + ulx = tx + uly1; uly = ty - ulx1; + urx = tx + ury1; ury = ty - urx1; + llx = tx + lly1; lly = ty - llx1; + lrx = tx + lry1; lry = ty - lrx1; + } else { + ulx = tx + ulx1; uly = ty + uly1; + urx = tx + urx1; ury = ty + ury1; + llx = tx + llx1; lly = ty + lly1; + lrx = tx + lrx1; lry = ty + lry1; + } + xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx + : (llx < lrx) ? llx : lrx + : (urx < llx) ? (urx < lrx) ? urx : lrx + : (llx < lrx) ? llx : lrx; + xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx + : (llx > lrx) ? llx : lrx + : (urx > llx) ? (urx > lrx) ? urx : lrx + : (llx > lrx) ? llx : lrx; + yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry + : (lly < lry) ? lly : lry + : (ury < lly) ? (ury < lry) ? ury : lry + : (lly < lry) ? lly : lry; + yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry + : (lly > lry) ? lly : lry + : (ury > lly) ? (ury > lry) ? ury : lry + : (lly > lry) ? lly : lry; + clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); + opClipRes = clipRes; + + // compute Bresenham parameters for x and y scaling + yp = h / scaledHeight; + yq = h % scaledHeight; + xp = w / scaledWidth; + xq = w % scaledWidth; + + // allocate pixel buffer + pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w); + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = pixBuf; + for (i = 0; i < n; ++i) { + (*src)(srcData, p); + p += w; + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + (int)(yShear * k1); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what we + // want + if (yShear1 < 0) { + y1 += 0.999; + } + + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the alpha value for (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + p = pixBuf + xSrc; + pixAcc = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc += *p++; + } + p += w - m; + } + + // blend fill color with background + if (pixAcc != 0) { + if (pixAcc == n * m) { + drawPixel(tx + x2, ty + y2, state->fillPattern, state->fillAlpha, + clipRes2 == splashClipAllInside); + } else { + alpha = (SplashCoord)pixAcc / (SplashCoord)(n * m); + drawPixel(tx + x2, ty + y2, state->fillPattern, + state->fillAlpha * alpha, + clipRes2 == splashClipAllInside); + } + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + } + + // free memory + gfree(pixBuf); + + return splashOk; +} + +SplashError Splash::drawImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, + int w, int h, SplashCoord *mat) { + GBool ok, rot, halftone, srcAlpha; + SplashCoord xScale, yScale, xShear, yShear, yShear1; + int tx, tx2, ty, ty2, scaledWidth, scaledHeight, xSign, ySign; + int ulx, uly, llx, lly, urx, ury, lrx, lry; + int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; + int xMin, xMax, yMin, yMax; + SplashClipResult clipRes, clipRes2; + int yp, yq, yt, yStep, lastYStep; + int xp, xq, xt, xStep, xSrc; + int k1, spanXMin, spanXMax, spanY; + SplashColorPtr pixBuf, p; + SplashColor pix; +#if SPLASH_CMYK + int pixAcc0, pixAcc1, pixAcc2, pixAcc3; +#else + int pixAcc0, pixAcc1, pixAcc2; +#endif + int alphaAcc; + SplashCoord pixMul, alphaMul, alpha; + int x, y, x1, x2, y2; + SplashCoord y1; + int nComps, n, m, i, j; + + if (debugMode) { + printf("drawImage: srcMode=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", + srcMode, w, h, (double)mat[0], (double)mat[1], (double)mat[2], + (double)mat[3], (double)mat[4], (double)mat[5]); + } + + // check color modes + ok = gFalse; // make gcc happy + nComps = 0; // make gcc happy + halftone = gFalse; + srcAlpha = gFalse; + switch (bitmap->mode) { + case splashModeMono1: + ok = srcMode == splashModeMono1 || srcMode == splashModeMono8 || + srcMode == splashModeAMono8; + halftone = srcMode == splashModeMono8 || srcMode == splashModeAMono8; + srcAlpha = srcMode == splashModeAMono8; + nComps = srcAlpha ? 2 : 1; + break; + case splashModeMono8: + ok = srcMode == splashModeMono8 || srcMode == splashModeAMono8; + srcAlpha = srcMode == splashModeAMono8; + nComps = srcAlpha ? 2 : 1; + break; + case splashModeAMono8: + //~ not implemented yet + ok = gFalse; + nComps = 2; + break; + case splashModeRGB8: + ok = srcMode == splashModeRGB8 || srcMode == splashModeARGB8; + srcAlpha = srcMode == splashModeARGB8; + nComps = srcAlpha ? 4 : 3; + break; + case splashModeBGR8: + ok = srcMode == splashModeBGR8 || srcMode == splashModeBGRA8; + srcAlpha = srcMode == splashModeBGRA8; + nComps = srcAlpha ? 4 : 3; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + ok = srcMode == splashModeCMYK8 || srcMode == splashModeACMYK8; + srcAlpha = srcMode == splashModeACMYK8; + nComps = srcAlpha ? 5 : 4; + break; +#endif + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ not implemented yet + ok = gFalse; + nComps = 4; + break; + } + if (!ok) { + return splashErrModeMismatch; + } + + // check for singular matrix + if (splashAbs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.000001) { + return splashErrSingularMatrix; + } + + // compute scale, shear, rotation, translation parameters + rot = splashAbs(mat[1]) > splashAbs(mat[0]); + if (rot) { + xScale = -mat[1]; + yScale = mat[2] - (mat[0] * mat[3]) / mat[1]; + xShear = -mat[3] / yScale; + yShear = -mat[0] / mat[1]; + } else { + xScale = mat[0]; + yScale = mat[3] - (mat[1] * mat[2]) / mat[0]; + xShear = mat[2] / yScale; + yShear = mat[1] / mat[0]; + } + // the +/-0.01 in these computations is to avoid floating point + // precision problems which can lead to gaps between image stripes + // (it can cause image stripes to overlap, but that's a much less + // visible problem) + if (xScale >= 0) { + tx = splashRound(mat[4] - 0.01); + tx2 = splashRound(mat[4] + xScale + 0.01) - 1; + } else { + tx = splashRound(mat[4] + 0.01) - 1; + tx2 = splashRound(mat[4] + xScale - 0.01); + } + scaledWidth = abs(tx2 - tx) + 1; + if (scaledWidth == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledWidth = 1; + } + if (yScale >= 0) { + ty = splashRound(mat[5] - 0.01); + ty2 = splashRound(mat[5] + yScale + 0.01) - 1; + } else { + ty = splashRound(mat[5] + 0.01) - 1; + ty2 = splashRound(mat[5] + yScale - 0.01); + } + scaledHeight = abs(ty2 - ty) + 1; + if (scaledHeight == 0) { + // technically, this should draw nothing, but it generally seems + // better to draw a one-pixel-wide stripe rather than throwing it + // away + scaledHeight = 1; + } + xSign = (xScale < 0) ? -1 : 1; + ySign = (yScale < 0) ? -1 : 1; + yShear1 = (SplashCoord)xSign * yShear; + + // clipping + ulx1 = 0; + uly1 = 0; + urx1 = xSign * (scaledWidth - 1); + ury1 = (int)(yShear * urx1); + llx1 = splashRound(xShear * ySign * (scaledHeight - 1)); + lly1 = ySign * (scaledHeight - 1) + (int)(yShear * llx1); + lrx1 = xSign * (scaledWidth - 1) + + splashRound(xShear * ySign * (scaledHeight - 1)); + lry1 = ySign * (scaledHeight - 1) + (int)(yShear * lrx1); + if (rot) { + ulx = tx + uly1; uly = ty - ulx1; + urx = tx + ury1; ury = ty - urx1; + llx = tx + lly1; lly = ty - llx1; + lrx = tx + lry1; lry = ty - lrx1; + } else { + ulx = tx + ulx1; uly = ty + uly1; + urx = tx + urx1; ury = ty + ury1; + llx = tx + llx1; lly = ty + lly1; + lrx = tx + lrx1; lry = ty + lry1; + } + xMin = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx + : (llx < lrx) ? llx : lrx + : (urx < llx) ? (urx < lrx) ? urx : lrx + : (llx < lrx) ? llx : lrx; + xMax = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx + : (llx > lrx) ? llx : lrx + : (urx > llx) ? (urx > lrx) ? urx : lrx + : (llx > lrx) ? llx : lrx; + yMin = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry + : (lly < lry) ? lly : lry + : (ury < lly) ? (ury < lry) ? ury : lry + : (lly < lry) ? lly : lry; + yMax = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry + : (lly > lry) ? lly : lry + : (ury > lly) ? (ury > lry) ? ury : lry + : (lly > lry) ? lly : lry; + clipRes = state->clip->testRect(xMin, yMin, xMax, yMax); + opClipRes = clipRes; + if (clipRes == splashClipAllOutside) { + return splashOk; + } + + // compute Bresenham parameters for x and y scaling + yp = h / scaledHeight; + yq = h % scaledHeight; + xp = w / scaledWidth; + xq = w % scaledWidth; + + // allocate pixel buffer + pixBuf = (SplashColorPtr)gmalloc((yp + 1) * w * nComps); + + pixAcc0 = pixAcc1 = pixAcc2 = 0; // make gcc happy +#if SPLASH_CMYK + pixAcc3 = 0; // make gcc happy +#endif + + if (srcAlpha) { + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = pixBuf; + for (i = 0; i < n; ++i) { + (*src)(srcData, p); + p += w * nComps; + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + (int)(yShear * k1); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what + // we want + if (yShear1 < 0) { + y1 += 0.999; + } + + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + alphaAcc = 0; + switch (srcMode) { + case splashModeAMono8: + p = pixBuf + xSrc * 2; + pixAcc0 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + alphaAcc += *p++; + pixAcc0 += *p++; + } + p += 2 * (w - m); + } + break; + case splashModeARGB8: + p = pixBuf + xSrc * 4; + pixAcc0 = pixAcc1 = pixAcc2 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + alphaAcc += *p++; + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + } + p += 4 * (w - m); + } + break; + case splashModeBGRA8: + p = pixBuf + xSrc * 4; + pixAcc0 = pixAcc1 = pixAcc2 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + alphaAcc += *p++; + } + p += 4 * (w - m); + } + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = pixBuf + xSrc * 5; + pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + alphaAcc += *p++; + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + pixAcc3 += *p++; + } + p += 5 * (w - m); + } + break; +#endif + default: // make gcc happy + break; + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + alphaMul = pixMul * (1.0 / 256.0); + alpha = (SplashCoord)alphaAcc * alphaMul; + + if (alpha > 0) { + // mono8 -> mono1 conversion, with halftoning + if (halftone) { + pix[0] = state->screen->test(tx + x2, ty + y2, + (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0)); + + // no conversion, no halftoning + } else { + switch (bitmap->mode) { +#if SPLASH_CMYK + case splashModeCMYK8: + pix[3] = (int)((SplashCoord)pixAcc3 * pixMul); + // fall through +#endif + case splashModeRGB8: + case splashModeBGR8: + pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); + pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); + // fall through + case splashModeMono1: + case splashModeMono8: + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + break; + default: // make gcc happy + break; + } + } + + // set pixel + drawPixel(tx + x2, ty + y2, pix, alpha * state->fillAlpha, + clipRes2 == splashClipAllInside); + } + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + } + + } else { + + // init y scale Bresenham + yt = 0; + lastYStep = 1; + + for (y = 0; y < scaledHeight; ++y) { + + // y scale Bresenham + yStep = yp; + yt += yq; + if (yt >= scaledHeight) { + yt -= scaledHeight; + ++yStep; + } + + // read row(s) from image + n = (yp > 0) ? yStep : lastYStep; + if (n > 0) { + p = pixBuf; + for (i = 0; i < n; ++i) { + (*src)(srcData, p); + p += w * nComps; + } + } + lastYStep = yStep; + + // loop-invariant constants + k1 = splashRound(xShear * ySign * y); + + // clipping test + if (clipRes != splashClipAllInside && + !rot && + (int)(yShear * k1) == + (int)(yShear * (xSign * (scaledWidth - 1) + k1))) { + if (xSign > 0) { + spanXMin = tx + k1; + spanXMax = spanXMin + (scaledWidth - 1); + } else { + spanXMax = tx + k1; + spanXMin = spanXMax - (scaledWidth - 1); + } + spanY = ty + ySign * y + (int)(yShear * k1); + clipRes2 = state->clip->testSpan(spanXMin, spanXMax, spanY); + if (clipRes2 == splashClipAllOutside) { + continue; + } + } else { + clipRes2 = clipRes; + } + + // init x scale Bresenham + xt = 0; + xSrc = 0; + + // x shear + x1 = k1; + + // y shear + y1 = (SplashCoord)ySign * y + yShear * x1; + // this is a kludge: if yShear1 is negative, then (int)y1 would + // change immediately after the first pixel, which is not what + // we want + if (yShear1 < 0) { + y1 += 0.999; + } + + // loop-invariant constants + n = yStep > 0 ? yStep : 1; + + for (x = 0; x < scaledWidth; ++x) { + + // x scale Bresenham + xStep = xp; + xt += xq; + if (xt >= scaledWidth) { + xt -= scaledWidth; + ++xStep; + } + + // rotation + if (rot) { + x2 = (int)y1; + y2 = -x1; + } else { + x2 = x1; + y2 = (int)y1; + } + + // compute the filtered pixel at (x,y) after the x and y scaling + // operations + m = xStep > 0 ? xStep : 1; + switch (srcMode) { + case splashModeMono1: + case splashModeMono8: + p = pixBuf + xSrc; + pixAcc0 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + } + p += w - m; + } + break; + case splashModeRGB8: + case splashModeBGR8: + p = pixBuf + xSrc * 3; + pixAcc0 = pixAcc1 = pixAcc2 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + } + p += 3 * (w - m); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + p = pixBuf + xSrc * 4; + pixAcc0 = pixAcc1 = pixAcc2 = pixAcc3 = 0; + for (i = 0; i < n; ++i) { + for (j = 0; j < m; ++j) { + pixAcc0 += *p++; + pixAcc1 += *p++; + pixAcc2 += *p++; + pixAcc3 += *p++; + } + p += 4 * (w - m); + } + break; +#endif + default: // make gcc happy + break; + } + pixMul = (SplashCoord)1 / (SplashCoord)(n * m); + + // mono8 -> mono1 conversion, with halftoning + if (halftone) { + pix[0] = state->screen->test(tx + x2, ty + y2, + (SplashCoord)pixAcc0 * pixMul * (1.0 / 256.0)); + + // no conversion, no halftoning + } else { + switch (bitmap->mode) { +#if SPLASH_CMYK + case splashModeCMYK8: + pix[3] = (int)((SplashCoord)pixAcc3 * pixMul); + // fall through +#endif + case splashModeRGB8: + case splashModeBGR8: + pix[2] = (int)((SplashCoord)pixAcc2 * pixMul); + pix[1] = (int)((SplashCoord)pixAcc1 * pixMul); + // fall through + case splashModeMono1: + case splashModeMono8: + pix[0] = (int)((SplashCoord)pixAcc0 * pixMul); + break; + default: // make gcc happy + break; + } + } + + // set pixel + drawPixel(tx + x2, ty + y2, pix, state->fillAlpha, + clipRes2 == splashClipAllInside); + + // x scale Bresenham + xSrc += xStep; + + // x shear + x1 += xSign; + + // y shear + y1 += yShear1; + } + } + + } + + gfree(pixBuf); + + return splashOk; +} + +void Splash::dumpPath(SplashPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s%s\n", + i, (double)path->pts[i].x, (double)path->pts[i].y, + (path->flags[i] & splashPathFirst) ? " first" : "", + (path->flags[i] & splashPathLast) ? " last" : "", + (path->flags[i] & splashPathClosed) ? " closed" : "", + (path->flags[i] & splashPathCurve) ? " curve" : "", + (path->flags[i] & splashPathArcCW) ? " arcCW" : ""); + } +} + +void Splash::dumpXPath(SplashXPath *path) { + int i; + + for (i = 0; i < path->length; ++i) { + printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s%s%s%s%s\n", + i, (double)path->segs[i].x0, (double)path->segs[i].y0, + (double)path->segs[i].x1, (double)path->segs[i].y1, + (path->segs[i].flags & splashXPathFirst) ? "F" : " ", + (path->segs[i].flags & splashXPathLast) ? "L" : " ", + (path->segs[i].flags & splashXPathEnd0) ? "0" : " ", + (path->segs[i].flags & splashXPathEnd1) ? "1" : " ", + (path->segs[i].flags & splashXPathHoriz) ? "H" : " ", + (path->segs[i].flags & splashXPathVert) ? "V" : " ", + (path->segs[i].flags & splashXPathFlip) ? "P" : " "); + } +} diff --git a/pdftops/Splash.h b/pdftops/Splash.h new file mode 100644 index 000000000..1b179d106 --- /dev/null +++ b/pdftops/Splash.h @@ -0,0 +1,204 @@ +//======================================================================== +// +// Splash.h +// +//======================================================================== + +#ifndef SPLASH_H +#define SPLASH_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" +#include "SplashClip.h" + +class SplashBitmap; +struct SplashGlyphBitmap; +class SplashState; +class SplashPattern; +class SplashScreen; +class SplashPath; +class SplashXPath; +class SplashFont; + +//------------------------------------------------------------------------ + +// Retrieves the next line of pixels in an image mask. Normally, +// fills in * and returns true. If the image stream is +// exhausted, returns false. +typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel); + +// Retrieves the next line of pixels in an image. Normally, fills in +// * and returns true. If the image stream is exhausted, +// returns false. +typedef GBool (*SplashImageSource)(void *data, SplashColorPtr line); + +//------------------------------------------------------------------------ +// Splash +//------------------------------------------------------------------------ + +class Splash { +public: + + // Create a new rasterizer object. + Splash(SplashBitmap *bitmapA); + + ~Splash(); + + //----- state read + + SplashPattern *getStrokePattern(); + SplashPattern *getFillPattern(); + SplashScreen *getScreen(); + SplashBlendFunc getBlendFunc(); + SplashCoord getStrokeAlpha(); + SplashCoord getFillAlpha(); + SplashCoord getLineWidth(); + int getLineCap(); + int getLineJoin(); + SplashCoord getMiterLimit(); + SplashCoord getFlatness(); + SplashCoord *getLineDash(); + int getLineDashLength(); + SplashCoord getLineDashPhase(); + SplashClip *getClip(); + + //----- state write + + void setStrokePattern(SplashPattern *strokeColor); + void setFillPattern(SplashPattern *fillColor); + void setScreen(SplashScreen *screen); + void setBlendFunc(SplashBlendFunc func); + void setStrokeAlpha(SplashCoord alpha); + void setFillAlpha(SplashCoord alpha); + void setLineWidth(SplashCoord lineWidth); + void setLineCap(int lineCap); + void setLineJoin(int lineJoin); + void setMiterLimit(SplashCoord miterLimit); + void setFlatness(SplashCoord flatness); + // the array will be copied + void setLineDash(SplashCoord *lineDash, int lineDashLength, + SplashCoord lineDashPhase); + void clipResetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + SplashError clipToPath(SplashPath *path, GBool eo); + + //----- state save/restore + + void saveState(); + SplashError restoreState(); + + //----- soft mask + + void setSoftMask(SplashBitmap *softMaskA); + + //----- drawing operations + + // Fill the bitmap with . This is not subject to clipping. + void clear(SplashColorPtr color); + + // Stroke a path using the current stroke pattern. + SplashError stroke(SplashPath *path); + + // Fill a path using the current fill pattern. + SplashError fill(SplashPath *path, GBool eo); + + // Fill a path, XORing with the current fill pattern. + SplashError xorFill(SplashPath *path, GBool eo); + + // Draw a character, using the current fill pattern. + SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font); + + // Draw a glyph, using the current fill pattern. This function does + // not free any data, i.e., it ignores glyph->freeData. + SplashError fillGlyph(SplashCoord x, SplashCoord y, + SplashGlyphBitmap *glyph); + + // Draws an image mask using the fill color. This will read + // lines of pixels from , starting with the top line. "1" + // pixels will be drawn with the current fill color; "0" pixels are + // transparent. The matrix: + // [ mat[0] mat[1] 0 ] + // [ mat[2] mat[3] 0 ] + // [ mat[4] mat[5] 1 ] + // maps a unit square to the desired destination for the image, in + // PostScript style: + // [x' y' 1] = [x y 1] * mat + // Note that the Splash y axis points downward, and the image source + // is assumed to produce pixels in raster order, starting from the + // top line. + SplashError fillImageMask(SplashImageMaskSource src, void *srcData, + int w, int h, SplashCoord *mat); + + // Draw an image. This will read lines of pixels from + // , starting with the top line. These pixels are assumed to + // be in the source mode, . The following combinations of + // source and target modes are supported: + // source target + // ------ ------ + // Mono1 Mono1 + // Mono8 Mono1 -- with dithering + // Mono8 Mono8 + // RGB8 RGB8 + // BGR8 BGR8 + // ARGB8 RGB8 -- with source alpha (masking) + // BGRA8 BGR8 -- with source alpha (masking) + // The matrix behaves as for fillImageMask. + SplashError drawImage(SplashImageSource src, void *srcData, + SplashColorMode srcMode, + int w, int h, SplashCoord *mat); + + //----- misc + + // Return the associated bitmap. + SplashBitmap *getBitmap() { return bitmap; } + + // Get a bounding box which includes all modifications since the + // last call to clearModRegion. + void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax) + { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; } + + // Clear the modified region bounding box. + void clearModRegion(); + + // Get clipping status for the last drawing operation subject to + // clipping. + SplashClipResult getClipRes() { return opClipRes; } + + // Toggle debug mode on or off. + void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } + +private: + + void updateModX(int x); + void updateModY(int y); + void strokeNarrow(SplashXPath *xPath); + void strokeWide(SplashXPath *xPath); + SplashXPath *makeDashedPath(SplashXPath *xPath); + SplashError fillWithPattern(SplashPath *path, GBool eo, + SplashPattern *pattern, SplashCoord alpha); + void drawPixel(int x, int y, SplashColorPtr color, + SplashCoord alpha, GBool noClip); + void drawPixel(int x, int y, SplashPattern *pattern, + SplashCoord alpha, GBool noClip); + void drawSpan(int x0, int x1, int y, SplashPattern *pattern, + SplashCoord alpha, GBool noClip); + void xorSpan(int x0, int x1, int y, SplashPattern *pattern, GBool noClip); + void dumpPath(SplashPath *path); + void dumpXPath(SplashXPath *path); + + SplashBitmap *bitmap; + SplashState *state; + SplashBitmap *softMask; + int modXMin, modYMin, modXMax, modYMax; + SplashClipResult opClipRes; + GBool debugMode; +}; + +#endif diff --git a/pdftops/SplashBitmap.cxx b/pdftops/SplashBitmap.cxx new file mode 100644 index 000000000..6b2442c9e --- /dev/null +++ b/pdftops/SplashBitmap.cxx @@ -0,0 +1,243 @@ +//======================================================================== +// +// SplashBitmap.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashBitmap.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool topDown) { + width = widthA; + height = heightA; + mode = modeA; + switch (mode) { + case splashModeMono1: + rowSize = (width + 7) >> 3; + break; + case splashModeMono8: + rowSize = width; + break; + case splashModeAMono8: + rowSize = width * 2; + break; + case splashModeRGB8: + case splashModeBGR8: + rowSize = width * 3; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + rowSize = width * 4; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + rowSize = width * 5; + break; +#endif + } + rowSize += rowPad - 1; + rowSize -= rowSize % rowPad; + data = (SplashColorPtr)gmalloc(rowSize * height); + if (!topDown) { + data += (height - 1) * rowSize; + rowSize = -rowSize; + } +} + + +SplashBitmap::~SplashBitmap() { + if (rowSize < 0) { + gfree(data + (height - 1) * rowSize); + } else { + gfree(data); + } +} + +SplashError SplashBitmap::writePNMFile(char *fileName) { + FILE *f; + SplashColorPtr row, p; + int x, y; + + if (!(f = fopen(fileName, "wb"))) { + return splashErrOpenFile; + } + + switch (mode) { + + case splashModeMono1: + fprintf(f, "P4\n%d %d\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; x += 8) { + fputc(*p ^ 0xff, f); + ++p; + } + row += rowSize; + } + break; + + case splashModeMono8: + fprintf(f, "P5\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(*p, f); + ++p; + } + row += rowSize; + } + break; + + case splashModeAMono8: + fprintf(f, "P5\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashAMono8M(p), f); + p += 2; + } + row += rowSize; + } + break; + + case splashModeRGB8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashRGB8R(p), f); + fputc(splashRGB8G(p), f); + fputc(splashRGB8B(p), f); + p += 3; + } + row += rowSize; + } + break; + + case splashModeBGR8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGR8R(p), f); + fputc(splashBGR8G(p), f); + fputc(splashBGR8B(p), f); + p += 3; + } + row += rowSize; + } + break; + + case splashModeARGB8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashARGB8R(p), f); + fputc(splashARGB8G(p), f); + fputc(splashARGB8B(p), f); + p += 4; + } + row += rowSize; + } + break; + + case splashModeBGRA8: + fprintf(f, "P6\n%d %d\n255\n", width, height); + row = data; + for (y = 0; y < height; ++y) { + p = row; + for (x = 0; x < width; ++x) { + fputc(splashBGRA8R(p), f); + fputc(splashBGRA8G(p), f); + fputc(splashBGRA8B(p), f); + p += 4; + } + row += rowSize; + } + break; + +#if SPLASH_CMYK + case splashModeCMYK8: + case splashModeACMYK8: + // PNM doesn't support CMYK + break; +#endif + } + + fclose(f); + return splashOk; +} + +void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { + SplashColorPtr p; + + if (y < 0 || y >= height || x < 0 || x >= width) { + return; + } + switch (mode) { + case splashModeMono1: + p = &data[y * rowSize + (x >> 3)]; + pixel[0] = (p[0] >> (7 - (x & 7))) & 1; + break; + case splashModeMono8: + p = &data[y * rowSize + x]; + pixel[0] = p[0]; + break; + case splashModeAMono8: + p = &data[y * rowSize + 2 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + break; + case splashModeRGB8: + case splashModeBGR8: + p = &data[y * rowSize + 3 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + break; + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeCMYK8: +#endif + p = &data[y * rowSize + 4 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + pixel[3] = p[3]; + break; +#if SPLASH_CMYK + case splashModeACMYK8: + p = &data[y * rowSize + 5 * x]; + pixel[0] = p[0]; + pixel[1] = p[1]; + pixel[2] = p[2]; + pixel[3] = p[3]; + pixel[4] = p[4]; + break; +#endif + } +} diff --git a/pdftops/SplashBitmap.h b/pdftops/SplashBitmap.h new file mode 100644 index 000000000..e3e5109ca --- /dev/null +++ b/pdftops/SplashBitmap.h @@ -0,0 +1,55 @@ +//======================================================================== +// +// SplashBitmap.h +// +//======================================================================== + +#ifndef SPLASHBITMAP_H +#define SPLASHBITMAP_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashBitmap +//------------------------------------------------------------------------ + +class SplashBitmap { +public: + + // Create a new bitmap. It will have x pixels in + // color mode . Rows will be padded out to a multiple of + // bytes. If is false, the bitmap will be stored + // upside-down, i.e., with the last row first in memory. + SplashBitmap(int widthA, int heightA, int rowPad, + SplashColorMode modeA, GBool topDown = gTrue); + + ~SplashBitmap(); + + int getWidth() { return width; } + int getHeight() { return height; } + int getRowSize() { return rowSize; } + SplashColorMode getMode() { return mode; } + SplashColorPtr getDataPtr() { return data; } + + SplashError writePNMFile(char *fileName); + + void getPixel(int x, int y, SplashColorPtr pixel); + +private: + + int width, height; // size of bitmap + int rowSize; // size of one row of data, in bytes + // - negative for bottom-up bitmaps + SplashColorMode mode; // color mode + SplashColorPtr data; // pointer to row zero of the bitmap data + + friend class Splash; +}; + +#endif diff --git a/pdftops/SplashClip.cxx b/pdftops/SplashClip.cxx new file mode 100644 index 000000000..6d4bf89f1 --- /dev/null +++ b/pdftops/SplashClip.cxx @@ -0,0 +1,270 @@ +//======================================================================== +// +// SplashClip.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashMath.h" +#include "SplashPath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" +#include "SplashClip.h" + +//------------------------------------------------------------------------ +// SplashClip.flags +//------------------------------------------------------------------------ + +#define splashClipEO 0x01 // use even-odd rule + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + if (x0 < x1) { + xMin = splashFloor(x0); + xMax = splashFloor(x1); + } else { + xMin = splashFloor(x1); + xMax = splashFloor(x0); + } + if (y0 < y1) { + yMin = splashFloor(y0); + yMax = splashFloor(y1); + } else { + yMin = splashFloor(y1); + yMax = splashFloor(y0); + } + paths = NULL; + flags = NULL; + scanners = NULL; + length = size = 0; +} + +SplashClip::SplashClip(SplashClip *clip) { + int i; + + xMin = clip->xMin; + yMin = clip->yMin; + xMax = clip->xMax; + yMax = clip->yMax; + length = clip->length; + size = clip->size; + paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); + scanners = (SplashXPathScanner **) + gmallocn(size, sizeof(SplashXPathScanner *)); + for (i = 0; i < length; ++i) { + paths[i] = clip->paths[i]->copy(); + flags[i] = clip->flags[i]; + scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO); + } +} + +SplashClip::~SplashClip() { + int i; + + for (i = 0; i < length; ++i) { + delete paths[i]; + delete scanners[i]; + } + gfree(paths); + gfree(flags); + gfree(scanners); +} + +void SplashClip::grow(int nPaths) { + if (length + nPaths > size) { + if (size == 0) { + size = 32; + } + while (size < length + nPaths) { + size *= 2; + } + paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); + scanners = (SplashXPathScanner **) + greallocn(scanners, size, sizeof(SplashXPathScanner *)); + } +} + +void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + int i; + + for (i = 0; i < length; ++i) { + delete paths[i]; + delete scanners[i]; + } + gfree(paths); + gfree(flags); + gfree(scanners); + paths = NULL; + flags = NULL; + scanners = NULL; + length = size = 0; + + if (x0 < x1) { + xMin = splashFloor(x0); + xMax = splashFloor(x1); + } else { + xMin = splashFloor(x1); + xMax = splashFloor(x0); + } + if (y0 < y1) { + yMin = splashFloor(y0); + yMax = splashFloor(y1); + } else { + yMin = splashFloor(y1); + yMax = splashFloor(y0); + } +} + +SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + int x0I, y0I, x1I, y1I; + + if (x0 < x1) { + x0I = splashFloor(x0); + x1I = splashFloor(x1); + } else { + x0I = splashFloor(x1); + x1I = splashFloor(x0); + } + if (x0I > xMin) { + xMin = x0I; + } + if (x1I < xMax) { + xMax = x1I; + } + if (y0 < y1) { + y0I = splashFloor(y0); + y1I = splashFloor(y1); + } else { + y0I = splashFloor(y1); + y1I = splashFloor(y0); + } + if (y0I > yMin) { + yMin = y0I; + } + if (y1I < yMax) { + yMax = y1I; + } + return splashOk; +} + +SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord flatness, + GBool eo) { + SplashXPath *xPath; + + xPath = new SplashXPath(path, flatness, gTrue); + + // check for an empty path + if (xPath->length == 0) { + xMax = xMin - 1; + yMax = yMin - 1; + delete xPath; + + // check for a rectangle + } else if (xPath->length == 4 && + ((xPath->segs[0].x0 == xPath->segs[0].x1 && + xPath->segs[0].x0 == xPath->segs[1].x0 && + xPath->segs[0].x0 == xPath->segs[3].x1 && + xPath->segs[2].x0 == xPath->segs[2].x1 && + xPath->segs[2].x0 == xPath->segs[1].x1 && + xPath->segs[2].x0 == xPath->segs[3].x0 && + xPath->segs[1].y0 == xPath->segs[1].y1 && + xPath->segs[1].y0 == xPath->segs[0].y1 && + xPath->segs[1].y0 == xPath->segs[2].y0 && + xPath->segs[3].y0 == xPath->segs[3].y1 && + xPath->segs[3].y0 == xPath->segs[0].y0 && + xPath->segs[3].y0 == xPath->segs[2].y1) || + (xPath->segs[0].y0 == xPath->segs[0].y1 && + xPath->segs[0].y0 == xPath->segs[1].y0 && + xPath->segs[0].y0 == xPath->segs[3].y1 && + xPath->segs[2].y0 == xPath->segs[2].y1 && + xPath->segs[2].y0 == xPath->segs[1].y1 && + xPath->segs[2].y0 == xPath->segs[3].y0 && + xPath->segs[1].x0 == xPath->segs[1].x1 && + xPath->segs[1].x0 == xPath->segs[0].x1 && + xPath->segs[1].x0 == xPath->segs[2].x0 && + xPath->segs[3].x0 == xPath->segs[3].x1 && + xPath->segs[3].x0 == xPath->segs[0].x0 && + xPath->segs[3].x0 == xPath->segs[2].x1))) { + clipToRect(xPath->segs[0].x0, xPath->segs[0].y0, + xPath->segs[2].x0, xPath->segs[2].y0); + delete xPath; + + } else { + grow(1); + xPath->sort(); + paths[length] = xPath; + flags[length] = eo ? splashClipEO : 0; + scanners[length] = new SplashXPathScanner(xPath, eo); + ++length; + } + + return splashOk; +} + +GBool SplashClip::test(int x, int y) { + int i; + + // check the rectangle + if (x < xMin || x > xMax || y < yMin || y > yMax) { + return gFalse; + } + + // check the paths + for (i = 0; i < length; ++i) { + if (!scanners[i]->test(x, y)) { + return gFalse; + } + } + + return gTrue; +} + +SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax) { + if (rectXMax < xMin || rectXMin > xMax || + rectYMax < yMin || rectYMin > yMax) { + return splashClipAllOutside; + } + if (rectXMin >= xMin && rectXMax <= xMax && + rectYMin >= yMin && rectYMax <= yMax && + length == 0) { + return splashClipAllInside; + } + return splashClipPartial; +} + +SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) { + int i; + + if (spanXMax < xMin || spanXMin > xMax || + spanY < yMin || spanY > yMax) { + return splashClipAllOutside; + } + if (!(spanXMin >= xMin && spanXMax <= xMax && + spanY >= yMin && spanY <= yMax)) { + return splashClipPartial; + } + for (i = 0; i < length; ++i) { + if (!scanners[i]->testSpan(xMin, xMax, spanY)) { + return splashClipPartial; + } + } + return splashClipAllInside; +} diff --git a/pdftops/SplashClip.h b/pdftops/SplashClip.h new file mode 100644 index 000000000..09a862747 --- /dev/null +++ b/pdftops/SplashClip.h @@ -0,0 +1,97 @@ +//======================================================================== +// +// SplashClip.h +// +//======================================================================== + +#ifndef SPLASHCLIP_H +#define SPLASHCLIP_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPath; +class SplashXPath; +class SplashXPathScanner; + +//------------------------------------------------------------------------ + +enum SplashClipResult { + splashClipAllInside, + splashClipAllOutside, + splashClipPartial +}; + +//------------------------------------------------------------------------ +// SplashClip +//------------------------------------------------------------------------ + +class SplashClip { +public: + + // Create a clip, for the given rectangle. + SplashClip(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Copy a clip. + SplashClip *copy() { return new SplashClip(this); } + + ~SplashClip(); + + // Reset the clip to a rectangle. + void resetToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Intersect the clip with a rectangle. + SplashError clipToRect(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1); + + // Interesect the clip with . + SplashError clipToPath(SplashPath *path, SplashCoord flatness, + GBool eo); + + // Returns true if (,) is inside the clip. + GBool test(int x, int y); + + // Tests a rectangle against the clipping region. Returns one of: + // - splashClipAllInside if the entire rectangle is inside the + // clipping region, i.e., all pixels in the rectangle are + // visible + // - splashClipAllOutside if the entire rectangle is outside the + // clipping region, i.e., all the pixels in the rectangle are + // clipped + // - splashClipPartial if the rectangle is part inside and part + // outside the clipping region + SplashClipResult testRect(int rectXMin, int rectYMin, + int rectXMax, int rectYMax); + + // Similar to testRect, but tests a horizontal span. + SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY); + + // Get the rectangle part of the clip region. + int getXMin() { return xMin; } + int getXMax() { return xMax; } + int getYMin() { return yMin; } + int getYMax() { return yMax; } + + // Get the number of arbitrary paths used by the clip region. + int getNumPaths() { return length; } + +private: + + SplashClip(SplashClip *clip); + void grow(int nPaths); + + int xMin, yMin, xMax, yMax; + SplashXPath **paths; + Guchar *flags; + SplashXPathScanner **scanners; + int length, size; +}; + +#endif diff --git a/pdftops/SplashErrorCodes.h b/pdftops/SplashErrorCodes.h new file mode 100644 index 000000000..145c07fad --- /dev/null +++ b/pdftops/SplashErrorCodes.h @@ -0,0 +1,32 @@ +//======================================================================== +// +// SplashErrorCodes.h +// +//======================================================================== + +#ifndef SPLASHERRORCODES_H +#define SPLASHERRORCODES_H + +#include + +//------------------------------------------------------------------------ + +#define splashOk 0 // no error + +#define splashErrNoCurPt 1 // no current point + +#define splashErrEmptyPath 2 // zero points in path + +#define splashErrBogusPath 3 // only one point in subpath + +#define splashErrNoSave 4 // state stack is empty + +#define splashErrOpenFile 5 // couldn't open file + +#define splashErrNoGlyph 6 // couldn't get the requested glyph + +#define splashErrModeMismatch 7 // invalid combination of color modes + +#define splashErrSingularMatrix 8 // matrix is singular + +#endif diff --git a/pdftops/SplashFTFont.cxx b/pdftops/SplashFTFont.cxx new file mode 100644 index 000000000..174dedd8a --- /dev/null +++ b/pdftops/SplashFTFont.cxx @@ -0,0 +1,320 @@ +//======================================================================== +// +// SplashFTFont.cc +// +//======================================================================== + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include FT_OUTLINE_H +#include FT_INTERNAL_OBJECTS_H // needed for FT_New_Size decl +#include "gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashPath.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFontFile.h" +#include "SplashFTFont.h" + +//------------------------------------------------------------------------ + +static int glyphPathMoveTo(FT_Vector *pt, void *path); +static int glyphPathLineTo(FT_Vector *pt, void *path); +static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path); +static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, + FT_Vector *pt, void *path); + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA): + SplashFont(fontFileA, matA, fontFileA->engine->aa) +{ + FT_Face face; + SplashCoord size, div; + int x, y; + + face = fontFileA->face; + if (FT_New_Size(face, &sizeObj)) { + return; + } + face->size = sizeObj; + size = splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]); + if (FT_Set_Pixel_Sizes(face, 0, (int)size)) { + return; + } + + div = face->bbox.xMax > 20000 ? 65536 : 1; + + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) / + (div * face->units_per_EM)); + xMin = xMax = x; + y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) / + (div * face->units_per_EM)); + yMin = yMax = y; + x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) / + (div * face->units_per_EM)); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + // This is a kludge: some buggy PDF generators embed fonts with + // zero bounding boxes. + if (xMax == xMin) { + xMin = 0; + xMax = (int)size; + } + if (yMax == yMin) { + yMin = 0; + yMax = (int)((SplashCoord)1.2 * size); + } + + // compute the transform matrix +#if USE_FIXEDPOINT + matrix.xx = (FT_Fixed)((mat[0] / size).getRaw()); + matrix.yx = (FT_Fixed)((mat[1] / size).getRaw()); + matrix.xy = (FT_Fixed)((mat[2] / size).getRaw()); + matrix.yy = (FT_Fixed)((mat[3] / size).getRaw()); +#else + matrix.xx = (FT_Fixed)((mat[0] / size) * 65536); + matrix.yx = (FT_Fixed)((mat[1] / size) * 65536); + matrix.xy = (FT_Fixed)((mat[2] / size) * 65536); + matrix.yy = (FT_Fixed)((mat[3] / size) * 65536); +#endif +} + +SplashFTFont::~SplashFTFont() { +} + +GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + return SplashFont::getGlyph(c, xFrac, 0, bitmap); +} + +GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + SplashFTFontFile *ff; + FT_Vector offset; + FT_GlyphSlot slot; + FT_UInt gid; + int rowSize; + Guchar *p, *q; + int i; + + ff = (SplashFTFontFile *)fontFile; + + ff->face->size = sizeObj; + offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64); + offset.y = 0; + FT_Set_Transform(ff->face, &matrix, &offset); + slot = ff->face->glyph; + + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = (FT_UInt)ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + + // if we have the FT2 bytecode interpreter, autohinting won't be used +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER + if (FT_Load_Glyph(ff->face, gid, + aa ? FT_LOAD_NO_BITMAP : FT_LOAD_DEFAULT)) { + return gFalse; + } +#else + // FT2's autohinting doesn't always work very well (especially with + // font subsets), so turn it off if anti-aliasing is enabled; if + // anti-aliasing is disabled, this seems to be a tossup - some fonts + // look better with hinting, some without, so leave hinting on + if (FT_Load_Glyph(ff->face, gid, + aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP + : FT_LOAD_DEFAULT)) { + return gFalse; + } +#endif + if (FT_Render_Glyph(slot, aa ? ft_render_mode_normal + : ft_render_mode_mono)) { + return gFalse; + } + + bitmap->x = -slot->bitmap_left; + bitmap->y = slot->bitmap_top; + bitmap->w = slot->bitmap.width; + bitmap->h = slot->bitmap.rows; + bitmap->aa = aa; + if (aa) { + rowSize = bitmap->w; + } else { + rowSize = (bitmap->w + 7) >> 3; + } + bitmap->data = (Guchar *)gmalloc(rowSize * bitmap->h); + bitmap->freeData = gTrue; + for (i = 0, p = bitmap->data, q = slot->bitmap.buffer; + i < bitmap->h; + ++i, p += rowSize, q += slot->bitmap.pitch) { + memcpy(p, q, rowSize); + } + + return gTrue; +} + +struct SplashFTFontPath { + SplashPath *path; + GBool needClose; +}; + +SplashPath *SplashFTFont::getGlyphPath(int c) { + static FT_Outline_Funcs outlineFuncs = { + &glyphPathMoveTo, + &glyphPathLineTo, + &glyphPathConicTo, + &glyphPathCubicTo, + 0, 0 + }; + SplashFTFontFile *ff; + SplashFTFontPath path; + FT_GlyphSlot slot; + FT_UInt gid; + FT_Glyph glyph; + + ff = (SplashFTFontFile *)fontFile; + ff->face->size = sizeObj; + FT_Set_Transform(ff->face, &matrix, NULL); + slot = ff->face->glyph; + if (ff->codeToGID && c < ff->codeToGIDLen) { + gid = ff->codeToGID[c]; + } else { + gid = (FT_UInt)c; + } + if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) { + return NULL; + } + if (FT_Get_Glyph(slot, &glyph)) { + return NULL; + } + path.path = new SplashPath(); + path.needClose = gFalse; + FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, + &outlineFuncs, &path); + if (path.needClose) { + path.path->close(); + } + FT_Done_Glyph(glyph); + return path.path; +} + +static int glyphPathMoveTo(FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + if (p->needClose) { + p->path->close(); + p->needClose = gFalse; + } + p->path->moveTo(pt->x / 64.0, -pt->y / 64.0); + return 0; +} + +static int glyphPathLineTo(FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->lineTo(pt->x / 64.0, -pt->y / 64.0); + p->needClose = gTrue; + return 0; +} + +static int glyphPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; + + if (!p->path->getCurPt(&x0, &y0)) { + return 0; + } + xc = ctrl->x / 64.0; + yc = -ctrl->y / 64.0; + x3 = pt->x / 64.0; + y3 = -pt->y / 64.0; + + // A second-order Bezier curve is defined by two endpoints, p0 and + // p3, and one control point, pc: + // + // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3 + // + // A third-order Bezier curve is defined by the same two endpoints, + // p0 and p3, and two control points, p1 and p2: + // + // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3 + // + // Applying some algebra, we can convert a second-order curve to a + // third-order curve: + // + // p1 = (1/3) * (p0 + 2pc) + // p2 = (1/3) * (2pc + p3) + + x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc); + y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc); + x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3); + y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3); + + p->path->curveTo(x1, y1, x2, y2, x3, y3); + p->needClose = gTrue; + return 0; +} + +static int glyphPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, + FT_Vector *pt, void *path) { + SplashFTFontPath *p = (SplashFTFontPath *)path; + + p->path->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0, + ctrl2->x / 64.0, -ctrl2->y / 64.0, + pt->x / 64.0, -pt->y / 64.0); + p->needClose = gTrue; + return 0; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/pdftops/SplashFTFont.h b/pdftops/SplashFTFont.h new file mode 100644 index 000000000..380cbbdb4 --- /dev/null +++ b/pdftops/SplashFTFont.h @@ -0,0 +1,55 @@ +//======================================================================== +// +// SplashFTFont.h +// +//======================================================================== + +#ifndef SPLASHFTFONT_H +#define SPLASHFTFONT_H + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include FT_FREETYPE_H +#include "SplashFont.h" + +class SplashFTFontFile; + +//------------------------------------------------------------------------ +// SplashFTFont +//------------------------------------------------------------------------ + +class SplashFTFont: public SplashFont { +public: + + SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA); + + virtual ~SplashFTFont(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // Rasterize a glyph. The and values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + +private: + + FT_Size sizeObj; + FT_Matrix matrix; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/pdftops/SplashFTFontEngine.cxx b/pdftops/SplashFTFontEngine.cxx new file mode 100644 index 000000000..8ae3d0aea --- /dev/null +++ b/pdftops/SplashFTFontEngine.cxx @@ -0,0 +1,144 @@ +//======================================================================== +// +// SplashFTFontEngine.cc +// +//======================================================================== + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#ifndef WIN32 +# include +#endif +#include "gmem.h" +#include "GString.h" +#include "gfile.h" +#include "FoFiTrueType.h" +#include "FoFiType1C.h" +#include "SplashFTFontFile.h" +#include "SplashFTFontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ + +static void fileWrite(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +SplashFTFontEngine::SplashFTFontEngine(GBool aaA, FT_Library libA) { + FT_Int major, minor, patch; + + aa = aaA; + lib = libA; + + // as of FT 2.1.8, CID fonts are indexed by CID instead of GID + FT_Library_Version(lib, &major, &minor, &patch); + useCIDs = major > 2 || + (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); +} + +SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA) { + FT_Library libA; + + if (FT_Init_FreeType(&libA)) { + return NULL; + } + return new SplashFTFontEngine(aaA, libA); +} + +SplashFTFontEngine::~SplashFTFontEngine() { + FT_Done_FreeType(lib); +} + +SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); +} + +SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); +} + +SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile) { + FoFiType1C *ff; + Gushort *cidToGIDMap; + int nCIDs; + SplashFontFile *ret; + + // check for a CFF font + if (useCIDs) { + cidToGIDMap = NULL; + nCIDs = 0; + } else if ((ff = FoFiType1C::load(fileName))) { + cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); + delete ff; + } else { + cidToGIDMap = NULL; + nCIDs = 0; + } + ret = SplashFTFontFile::loadCIDFont(this, idA, fileName, deleteFile, + cidToGIDMap, nCIDs); + if (!ret) { + gfree(cidToGIDMap); + } + return ret; +} + +SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + Gushort *codeToGID, + int codeToGIDLen) { + FoFiTrueType *ff; + GString *tmpFileName; + FILE *tmpFile; + SplashFontFile *ret; + + if (!(ff = FoFiTrueType::load(fileName))) { + return NULL; + } + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + ff->writeTTF(&fileWrite, tmpFile); + delete ff; + fclose(tmpFile); + ret = SplashFTFontFile::loadTrueTypeFont(this, idA, + tmpFileName->getCString(), + gTrue, codeToGID, codeToGIDLen); + if (ret) { + if (deleteFile) { + unlink(fileName); + } + } else { + unlink(tmpFileName->getCString()); + } + delete tmpFileName; + return ret; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/pdftops/SplashFTFontEngine.h b/pdftops/SplashFTFontEngine.h new file mode 100644 index 000000000..e386478e1 --- /dev/null +++ b/pdftops/SplashFTFontEngine.h @@ -0,0 +1,61 @@ +//======================================================================== +// +// SplashFTFontEngine.h +// +//======================================================================== + +#ifndef SPLASHFTFONTENGINE_H +#define SPLASHFTFONTENGINE_H + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include FT_FREETYPE_H +#include "gtypes.h" + +class SplashFontFile; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashFTFontEngine +//------------------------------------------------------------------------ + +class SplashFTFontEngine { +public: + + static SplashFTFontEngine *init(GBool aaA); + + ~SplashFTFontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, + Gushort *codeToGID, int codeToGIDLen); + +private: + + SplashFTFontEngine(GBool aaA, FT_Library libA); + + GBool aa; + FT_Library lib; + GBool useCIDs; + + friend class SplashFTFontFile; + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/pdftops/SplashFTFontFile.cxx b/pdftops/SplashFTFontFile.cxx new file mode 100644 index 000000000..73d31555c --- /dev/null +++ b/pdftops/SplashFTFontFile.cxx @@ -0,0 +1,111 @@ +//======================================================================== +// +// SplashFTFontFile.cc +// +//======================================================================== + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "gmem.h" +#include "SplashFTFontEngine.h" +#include "SplashFTFont.h" +#include "SplashFTFontFile.h" + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + char **encA) { + FT_Face faceA; + Gushort *codeToGIDA; + char *name; + int i; + + if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { + return NULL; + } + codeToGIDA = (Gushort *)gmallocn(256, sizeof(int)); + for (i = 0; i < 256; ++i) { + codeToGIDA[i] = 0; + if ((name = encA[i])) { + codeToGIDA[i] = (Gushort)FT_Get_Name_Index(faceA, name); + } + } + + return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + faceA, codeToGIDA, 256); +} + +SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + Gushort *codeToGIDA, + int codeToGIDLenA) { + FT_Face faceA; + + if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { + return NULL; + } + + return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + faceA, codeToGIDA, codeToGIDLenA); +} + +SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + Gushort *codeToGIDA, + int codeToGIDLenA) { + FT_Face faceA; + + if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { + return NULL; + } + + return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, + faceA, codeToGIDA, codeToGIDLenA); +} + +SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + FT_Face faceA, + Gushort *codeToGIDA, int codeToGIDLenA): + SplashFontFile(idA, fileNameA, deleteFileA) +{ + engine = engineA; + face = faceA; + codeToGID = codeToGIDA; + codeToGIDLen = codeToGIDLenA; +} + +SplashFTFontFile::~SplashFTFontFile() { + if (face) { + FT_Done_Face(face); + } + if (codeToGID) { + gfree(codeToGID); + } +} + +SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat) { + SplashFont *font; + + font = new SplashFTFont(this, mat); + font->initCache(); + return font; +} + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H diff --git a/pdftops/SplashFTFontFile.h b/pdftops/SplashFTFontFile.h new file mode 100644 index 000000000..3e10543f5 --- /dev/null +++ b/pdftops/SplashFTFontFile.h @@ -0,0 +1,70 @@ +//======================================================================== +// +// SplashFTFontFile.h +// +//======================================================================== + +#ifndef SPLASHFTFONTFILE_H +#define SPLASHFTFONTFILE_H + +#include + +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include FT_FREETYPE_H +#include "SplashFontFile.h" + +class SplashFontFileID; +class SplashFTFontEngine; + +//------------------------------------------------------------------------ +// SplashFTFontFile +//------------------------------------------------------------------------ + +class SplashFTFontFile: public SplashFontFile { +public: + + static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, + SplashFontFileID *idA, char *fileNameA, + GBool deleteFileA, char **encA); + static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, char *fileNameA, + GBool deleteFileA, + Gushort *codeToCIDA, int codeToGIDLenA); + static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + Gushort *codeToGIDA, + int codeToGIDLenA); + + virtual ~SplashFTFontFile(); + + // Create a new SplashFTFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat); + +private: + + SplashFTFontFile(SplashFTFontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + FT_Face faceA, + Gushort *codeToGIDA, int codeToGIDLenA); + + SplashFTFontEngine *engine; + FT_Face face; + Gushort *codeToGID; + int codeToGIDLen; + + friend class SplashFTFont; +}; + +#endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + +#endif diff --git a/pdftops/SplashFont.cxx b/pdftops/SplashFont.cxx new file mode 100644 index 000000000..db89ad0a6 --- /dev/null +++ b/pdftops/SplashFont.cxx @@ -0,0 +1,172 @@ +//======================================================================== +// +// SplashFont.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashFontFile.h" +#include "SplashFont.h" + +//------------------------------------------------------------------------ + +struct SplashFontCacheTag { + int c; + short xFrac, yFrac; // x and y fractions + int mru; // valid bit (0x80000000) and MRU index + int x, y, w, h; // offset and size of glyph +}; + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, + GBool aaA) { + fontFile = fontFileA; + fontFile->incRefCnt(); + mat[0] = matA[0]; + mat[1] = matA[1]; + mat[2] = matA[2]; + mat[3] = matA[3]; + aa = aaA; + + cache = NULL; + cacheTags = NULL; + + xMin = yMin = xMax = yMax = 0; +} + +void SplashFont::initCache() { + int i; + + // this should be (max - min + 1), but we add some padding to + // deal with rounding errors + glyphW = xMax - xMin + 3; + glyphH = yMax - yMin + 3; + if (aa) { + glyphSize = glyphW * glyphH; + } else { + glyphSize = ((glyphW + 7) >> 3) * glyphH; + } + + // set up the glyph pixmap cache + cacheAssoc = 8; + if (glyphSize <= 256) { + cacheSets = 8; + } else if (glyphSize <= 512) { + cacheSets = 4; + } else if (glyphSize <= 1024) { + cacheSets = 2; + } else { + cacheSets = 1; + } + cache = (Guchar *)gmallocn(cacheSets* cacheAssoc, glyphSize); + cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, + sizeof(SplashFontCacheTag)); + for (i = 0; i < cacheSets * cacheAssoc; ++i) { + cacheTags[i].mru = i & (cacheAssoc - 1); + } +} + +SplashFont::~SplashFont() { + fontFile->decRefCnt(); + if (cache) { + gfree(cache); + } + if (cacheTags) { + gfree(cacheTags); + } +} + +GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + SplashGlyphBitmap bitmap2; + int size; + Guchar *p; + int i, j, k; + + // no fractional coordinates for large glyphs or non-anti-aliased + // glyphs + if (!aa || glyphH > 50) { + xFrac = yFrac = 0; + } + + // check the cache + i = (c & (cacheSets - 1)) * cacheAssoc; + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x80000000) && + cacheTags[i+j].c == c && + (int)cacheTags[i+j].xFrac == xFrac && + (int)cacheTags[i+j].yFrac == yFrac) { + bitmap->x = cacheTags[i+j].x; + bitmap->y = cacheTags[i+j].y; + bitmap->w = cacheTags[i+j].w; + bitmap->h = cacheTags[i+j].h; + for (k = 0; k < cacheAssoc; ++k) { + if (k != j && + (cacheTags[i+k].mru & 0x7fffffff) < + (cacheTags[i+j].mru & 0x7fffffff)) { + ++cacheTags[i+k].mru; + } + } + cacheTags[i+j].mru = 0x80000000; + bitmap->aa = aa; + bitmap->data = cache + (i+j) * glyphSize; + bitmap->freeData = gFalse; + return gTrue; + } + } + + // generate the glyph bitmap + if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) { + return gFalse; + } + + // if the glyph doesn't fit in the bounding box, return a temporary + // uncached bitmap + if (bitmap2.w > glyphW || bitmap2.h > glyphH) { + *bitmap = bitmap2; + return gTrue; + } + + // insert glyph pixmap in cache + if (aa) { + size = bitmap2.w * bitmap2.h; + } else { + size = ((bitmap2.w + 7) >> 3) * bitmap2.h; + } + p = NULL; // make gcc happy + for (j = 0; j < cacheAssoc; ++j) { + if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) { + cacheTags[i+j].mru = 0x80000000; + cacheTags[i+j].c = c; + cacheTags[i+j].xFrac = (short)xFrac; + cacheTags[i+j].yFrac = (short)yFrac; + cacheTags[i+j].x = bitmap2.x; + cacheTags[i+j].y = bitmap2.y; + cacheTags[i+j].w = bitmap2.w; + cacheTags[i+j].h = bitmap2.h; + p = cache + (i+j) * glyphSize; + memcpy(p, bitmap2.data, size); + } else { + ++cacheTags[i+j].mru; + } + } + *bitmap = bitmap2; + bitmap->data = p; + bitmap->freeData = gFalse; + if (bitmap2.freeData) { + gfree(bitmap2.data); + } + return gTrue; +} diff --git a/pdftops/SplashFont.h b/pdftops/SplashFont.h new file mode 100644 index 000000000..a9d2adc29 --- /dev/null +++ b/pdftops/SplashFont.h @@ -0,0 +1,97 @@ +//======================================================================== +// +// SplashFont.h +// +//======================================================================== + +#ifndef SPLASHFONT_H +#define SPLASHFONT_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" + +struct SplashGlyphBitmap; +struct SplashFontCacheTag; +class SplashFontFile; +class SplashPath; + +//------------------------------------------------------------------------ + +// Fractional positioning uses this many bits to the right of the +// decimal points. +#define splashFontFractionBits 2 +#define splashFontFraction (1 << splashFontFractionBits) +#define splashFontFractionMul \ + ((SplashCoord)1 / (SplashCoord)splashFontFraction) + +//------------------------------------------------------------------------ +// SplashFont +//------------------------------------------------------------------------ + +class SplashFont { +public: + + SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, GBool aaA); + + // This must be called after the constructor, so that the subclass + // constructor has a chance to compute the bbox. + void initCache(); + + virtual ~SplashFont(); + + SplashFontFile *getFontFile() { return fontFile; } + + // Return true if matches the specified font file and matrix. + GBool matches(SplashFontFile *fontFileA, SplashCoord *matA) { + return fontFileA == fontFile && + matA[0] == mat[0] && matA[1] == mat[1] && + matA[2] == mat[2] && matA[3] == mat[3]; + } + + // Get a glyph - this does a cache lookup first, and if not found, + // creates a new bitmap and adds it to the cache. The and + // values are splashFontFractionBits bits each, representing + // the numerators of fractions in [0, 1), where the denominator is + // splashFontFraction = 1 << splashFontFractionBits. Subclasses + // should override this to zero out xFrac and/or yFrac if they don't + // support fractional coordinates. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // Rasterize a glyph. The and values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) = 0; + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c) = 0; + + // Return the font transform matrix. + SplashCoord *getMatrix() { return mat; } + + // Return the glyph bounding box. + void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + +protected: + + SplashFontFile *fontFile; + SplashCoord mat[4]; // font transform matrix + GBool aa; // anti-aliasing + int xMin, yMin, xMax, yMax; // glyph bounding box + Guchar *cache; // glyph bitmap cache + SplashFontCacheTag * // cache tags + cacheTags; + int glyphW, glyphH; // size of glyph bitmaps + int glyphSize; // size of glyph bitmaps, in bytes + int cacheSets; // number of sets in cache + int cacheAssoc; // cache associativity (glyphs per set) +}; + +#endif diff --git a/pdftops/SplashFontEngine.cxx b/pdftops/SplashFontEngine.cxx new file mode 100644 index 000000000..87998487e --- /dev/null +++ b/pdftops/SplashFontEngine.cxx @@ -0,0 +1,253 @@ +//======================================================================== +// +// SplashFontEngine.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#if HAVE_T1LIB_H +#include +#endif + +#include +#include +#ifndef WIN32 +# include +#endif +#include "gmem.h" +#include "GString.h" +#include "SplashT1FontEngine.h" +#include "SplashFTFontEngine.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" +#include "SplashFont.h" +#include "SplashFontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +SplashFontEngine::SplashFontEngine( +#if HAVE_T1LIB_H + GBool enableT1lib, +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + GBool enableFreeType, +#endif + GBool aa) { + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + fontCache[i] = NULL; + } + +#if HAVE_T1LIB_H + if (enableT1lib) { + t1Engine = SplashT1FontEngine::init(aa); + } else { + t1Engine = NULL; + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (enableFreeType) { + ftEngine = SplashFTFontEngine::init(aa); + } else { + ftEngine = NULL; + } +#endif +} + +SplashFontEngine::~SplashFontEngine() { + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + if (fontCache[i]) { + delete fontCache[i]; + } + } + +#if HAVE_T1LIB_H + if (t1Engine) { + delete t1Engine; + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (ftEngine) { + delete ftEngine; + } +#endif +} + +SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) { + SplashFontFile *fontFile; + int i; + + for (i = 0; i < splashFontCacheSize; ++i) { + if (fontCache[i]) { + fontFile = fontCache[i]->getFontFile(); + if (fontFile && fontFile->getID()->matches(id)) { + return fontFile; + } + } + } + return NULL; +} + +SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_T1LIB_H + if (!fontFile && t1Engine) { + fontFile = t1Engine->loadType1Font(idA, fileName, deleteFile, enc); + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1Font(idA, fileName, deleteFile, enc); + } +#endif + +#ifndef WIN32 + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_T1LIB_H + if (!fontFile && t1Engine) { + fontFile = t1Engine->loadType1CFont(idA, fileName, deleteFile, enc); + } +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadType1CFont(idA, fileName, deleteFile, enc); + } +#endif + +#ifndef WIN32 + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadCIDFont(idA, fileName, deleteFile); + } +#endif + +#ifndef WIN32 + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + return fontFile; +} + +SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + Gushort *codeToGID, + int codeToGIDLen) { + SplashFontFile *fontFile; + + fontFile = NULL; +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + if (!fontFile && ftEngine) { + fontFile = ftEngine->loadTrueTypeFont(idA, fileName, deleteFile, + codeToGID, codeToGIDLen); + } +#endif + + if (!fontFile) { + gfree(codeToGID); + } + +#ifndef WIN32 + // delete the (temporary) font file -- with Unix hard link + // semantics, this will remove the last link; otherwise it will + // return an error, leaving the file to be deleted later (if + // loadXYZFont failed, the file will always be deleted) + if (deleteFile) { + unlink(fontFile ? fontFile->fileName->getCString() : fileName); + } +#endif + + return fontFile; +} + +SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, + SplashCoord *mat) { + SplashFont *font; + int i, j; + + font = fontCache[0]; + if (font && font->matches(fontFile, mat)) { + return font; + } + for (i = 1; i < splashFontCacheSize; ++i) { + font = fontCache[i]; + if (font && font->matches(fontFile, mat)) { + for (j = i; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; + } + } + font = fontFile->makeFont(mat); + if (fontCache[splashFontCacheSize - 1]) { + delete fontCache[splashFontCacheSize - 1]; + } + for (j = splashFontCacheSize - 1; j > 0; --j) { + fontCache[j] = fontCache[j-1]; + } + fontCache[0] = font; + return font; +} diff --git a/pdftops/SplashFontEngine.h b/pdftops/SplashFontEngine.h new file mode 100644 index 000000000..4c061eb82 --- /dev/null +++ b/pdftops/SplashFontEngine.h @@ -0,0 +1,86 @@ +//======================================================================== +// +// SplashFontEngine.h +// +//======================================================================== + +#ifndef SPLASHFONTENGINE_H +#define SPLASHFONTENGINE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class SplashT1FontEngine; +class SplashFTFontEngine; +class SplashDTFontEngine; +class SplashDT4FontEngine; +class SplashFontFile; +class SplashFontFileID; +class SplashFont; + +//------------------------------------------------------------------------ + +#define splashFontCacheSize 16 + +//------------------------------------------------------------------------ +// SplashFontEngine +//------------------------------------------------------------------------ + +class SplashFontEngine { +public: + + // Create a font engine. + SplashFontEngine( +#if HAVE_T1LIB_H + GBool enableT1lib, +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + GBool enableFreeType, +#endif + GBool aa); + + ~SplashFontEngine(); + + // Get a font file from the cache. Returns NULL if there is no + // matching entry in the cache. + SplashFontFile *getFontFile(SplashFontFileID *id); + + // Load fonts - these create new SplashFontFile objects. + SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile); + SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, + Gushort *codeToGID, int codeToGIDLen); + + // Get a font - this does a cache lookup first, and if not found, + // creates a new SplashFont object and adds it to the cache. The + // matrix: + // [ mat[0] mat[1] ] + // [ mat[2] mat[3] ] + // specifies the font transform in PostScript style: + // [x' y'] = [x y] * mat + // Note that the Splash y axis points downward. + SplashFont *getFont(SplashFontFile *fontFile, SplashCoord *mat); + +private: + + SplashFont *fontCache[splashFontCacheSize]; + +#if HAVE_T1LIB_H + SplashT1FontEngine *t1Engine; +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + SplashFTFontEngine *ftEngine; +#endif +}; + +#endif diff --git a/pdftops/SplashFontFile.cxx b/pdftops/SplashFontFile.cxx new file mode 100644 index 000000000..a06cfc851 --- /dev/null +++ b/pdftops/SplashFontFile.cxx @@ -0,0 +1,55 @@ +//======================================================================== +// +// SplashFontFile.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#ifndef WIN32 +# include +#endif +#include "GString.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +SplashFontFile::SplashFontFile(SplashFontFileID *idA, char *fileNameA, + GBool deleteFileA) { + id = idA; + fileName = new GString(fileNameA); + deleteFile = deleteFileA; + refCnt = 0; +} + +SplashFontFile::~SplashFontFile() { + if (deleteFile) { + unlink(fileName->getCString()); + } + delete fileName; + delete id; +} + +void SplashFontFile::incRefCnt() { + ++refCnt; +} + +void SplashFontFile::decRefCnt() { + if (!--refCnt) { + delete this; + } +} diff --git a/pdftops/SplashFontFile.h b/pdftops/SplashFontFile.h new file mode 100644 index 000000000..0d6b3a2fa --- /dev/null +++ b/pdftops/SplashFontFile.h @@ -0,0 +1,60 @@ +//======================================================================== +// +// SplashFontFile.h +// +//======================================================================== + +#ifndef SPLASHFONTFILE_H +#define SPLASHFONTFILE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" + +class GString; +class SplashFontEngine; +class SplashFont; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashFontFile +//------------------------------------------------------------------------ + +class SplashFontFile { +public: + + virtual ~SplashFontFile(); + + // Create a new SplashFont, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat) = 0; + + // Get the font file ID. + SplashFontFileID *getID() { return id; } + + // Increment the reference count. + void incRefCnt(); + + // Decrement the reference count. If the new value is zero, delete + // the SplashFontFile object. + void decRefCnt(); + +protected: + + SplashFontFile(SplashFontFileID *idA, char *fileNameA, + GBool deleteFileA); + + SplashFontFileID *id; + GString *fileName; + GBool deleteFile; + int refCnt; + + friend class SplashFontEngine; +}; + +#endif diff --git a/pdftops/SplashFontFileID.cxx b/pdftops/SplashFontFileID.cxx new file mode 100644 index 000000000..a66dabf61 --- /dev/null +++ b/pdftops/SplashFontFileID.cxx @@ -0,0 +1,23 @@ +//======================================================================== +// +// SplashFontFileID.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "SplashFontFileID.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +SplashFontFileID::SplashFontFileID() { +} + +SplashFontFileID::~SplashFontFileID() { +} diff --git a/pdftops/SplashFontFileID.h b/pdftops/SplashFontFileID.h new file mode 100644 index 000000000..e69457da5 --- /dev/null +++ b/pdftops/SplashFontFileID.h @@ -0,0 +1,30 @@ +//======================================================================== +// +// SplashFontFileID.h +// +//======================================================================== + +#ifndef SPLASHFONTFILEID_H +#define SPLASHFONTFILEID_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// SplashFontFileID +//------------------------------------------------------------------------ + +class SplashFontFileID { +public: + + SplashFontFileID(); + virtual ~SplashFontFileID(); + virtual GBool matches(SplashFontFileID *id) = 0; +}; + +#endif diff --git a/pdftops/SplashGlyphBitmap.h b/pdftops/SplashGlyphBitmap.h new file mode 100644 index 000000000..379d0aab7 --- /dev/null +++ b/pdftops/SplashGlyphBitmap.h @@ -0,0 +1,26 @@ +//======================================================================== +// +// SplashGlyphBitmap.h +// +//======================================================================== + +#ifndef SPLASHGLYPHBITMAP_H +#define SPLASHGLYPHBITMAP_H + +#include + +#include "gtypes.h" + +//------------------------------------------------------------------------ +// SplashGlyphBitmap +//------------------------------------------------------------------------ + +struct SplashGlyphBitmap { + int x, y, w, h; // offset and size of glyph + GBool aa; // anti-aliased: true means 8-bit alpha + // bitmap; false means 1-bit + Guchar *data; // bitmap data + GBool freeData; // true if data memory should be freed +}; + +#endif diff --git a/pdftops/SplashMath.h b/pdftops/SplashMath.h new file mode 100644 index 000000000..e280e41e3 --- /dev/null +++ b/pdftops/SplashMath.h @@ -0,0 +1,78 @@ +//======================================================================== +// +// SplashMath.h +// +//======================================================================== + +#ifndef SPLASHMATH_H +#define SPLASHMATH_H + +#include +#if USE_FIXEDPONT +#include "FixedPoint.h" +#else +#include +#endif +#include "SplashTypes.h" + +static inline SplashCoord splashAbs(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::abs(x); +#else + return fabs(x); +#endif +} + +static inline int splashFloor(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::floor(x); +#else + return (int)floor(x); +#endif +} + +static inline int splashCeil(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::ceil(x); +#else + return (int)ceil(x); +#endif +} + +static inline int splashRound(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::round(x); +#else + return (int)floor(x + 0.5); +#endif +} + +static inline SplashCoord splashSqrt(SplashCoord x) { +#if USE_FIXEDPOINT + return FixedPoint::sqrt(x); +#else + return sqrt(x); +#endif +} + +static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) { +#if USE_FIXEDPOINT + return FixedPoint::pow(x, y); +#else + return pow(x, y); +#endif +} + +static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1) { + SplashCoord dx, dy; + dx = x1 - x0; + dy = y1 - y0; +#if USE_FIXEDPOINT + return FixedPoint::sqrt(dx * dx + dy * dy); +#else + return sqrt(dx * dx + dy * dy); +#endif +} + +#endif diff --git a/pdftops/SplashOutputDev.cxx b/pdftops/SplashOutputDev.cxx new file mode 100644 index 000000000..4f0bba580 --- /dev/null +++ b/pdftops/SplashOutputDev.cxx @@ -0,0 +1,2640 @@ +//======================================================================== +// +// SplashOutputDev.cc +// +// Copyright 2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gfile.h" +#include "GlobalParams.h" +#include "Error.h" +#include "Object.h" +#include "GfxFont.h" +#include "Link.h" +#include "CharCodeToUnicode.h" +#include "FontEncodingTables.h" +#include "FoFiTrueType.h" +#include "SplashBitmap.h" +#include "SplashGlyphBitmap.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashPath.h" +#include "SplashState.h" +#include "SplashErrorCodes.h" +#include "SplashFontEngine.h" +#include "SplashFont.h" +#include "SplashFontFile.h" +#include "SplashFontFileID.h" +#include "Splash.h" +#include "SplashOutputDev.h" + +//------------------------------------------------------------------------ +// Blend functions +//------------------------------------------------------------------------ + +static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + // note: floor(x / 255) = x >> 8 (for 16-bit x) + blend[i] = (dest[i] * src[i]) >> 8; + } +} + +static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + // note: floor(x / 255) = x >> 8 (for 16-bit x) + blend[i] = dest[i] + src[i] - ((dest[i] * src[i]) >> 8); + } +} + +static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + //~ not sure if this is right + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + // note: floor(x / 255) = x >> 8 (for 16-bit x) + blend[i] = dest[i] < 0x80 ? ((dest[i] * src[i]) >> 8) + : dest[i] + src[i] - ((dest[i] * src[i]) >> 8); + } +} + +static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? dest[i] : src[i]; + } +} + +static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] > src[i] ? dest[i] : src[i]; + } +} + +static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int i, x; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + x = dest[i] + src[i]; + blend[i] = x <= 255 ? x : 255; + } +} + +static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i, x; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + x = dest[i] - (255 - src[i]); + blend[i] = x >= 0 ? x : 0; + } +} + +static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + //~ not sure if this is right + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + // note: floor(x / 255) = x >> 8 (for 16-bit x) + blend[i] = src[i] < 0x80 + ? ((dest[i] * (src[i] * 2)) >> 8) + : 0xff - (((0xff - dest[i]) * (0x1ff - src[i] * 2)) >> 8); + } +} + +static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i, x; + + //~ not sure if this is right + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + if (src[i] < 0x80) { + x = dest[i] - (0x80 - src[i]); + blend[i] = x >= 0 ? x : 0; + } else { + x = dest[i] + (src[i] - 0x80); + blend[i] = x <= 255 ? x : 255; + } + } +} + +static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int i; + + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; + } +} + +static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int i; + + //~ not sure what this is supposed to do + for (i = 0; i < splashColorModeNComps[cm]; ++i) { + blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; + } +} + +static void cvtRGBToHSV(Guchar r, Guchar g, Guchar b, int *h, int *s, int *v) { + int cmax, cmid, cmin, x; + + if (r >= g) { + if (g >= b) { x = 0; cmax = r; cmid = g; cmin = b; } + else if (b >= r) { x = 4; cmax = b; cmid = r; cmin = g; } + else { x = 5; cmax = r; cmid = b; cmin = g; } + } else { + if (r >= b) { x = 1; cmax = g; cmid = r; cmin = b; } + else if (g >= b) { x = 2; cmax = g; cmid = b; cmin = r; } + else { x = 3; cmax = b; cmid = g; cmin = r; } + } + if (cmax == cmin) { + *h = *s = 0; + } else { + *h = x * 60; + if (x & 1) { + *h += ((cmax - cmid) * 60) / (cmax - cmin); + } else { + *h += ((cmid - cmin) * 60) / (cmax - cmin); + } + *s = (255 * (cmax - cmin)) / cmax; + } + *v = cmax; +} + +static void cvtHSVToRGB(int h, int s, int v, Guchar *r, Guchar *g, Guchar *b) { + int x, f, cmax, cmid, cmin; + + if (s == 0) { + *r = *g = *b = v; + } else { + x = h / 60; + f = h % 60; + cmax = v; + if (x & 1) { + cmid = (v * 255 - ((s * f) / 60)) >> 8; + } else { + cmid = (v * (255 - ((s * (60 - f)) / 60))) >> 8; + } + // note: floor(x / 255) = x >> 8 (for 16-bit x) + cmin = (v * (255 - s)) >> 8; + switch (x) { + case 0: *r = cmax; *g = cmid; *b = cmin; break; + case 1: *g = cmax; *r = cmid; *b = cmin; break; + case 2: *g = cmax; *b = cmid; *r = cmin; break; + case 3: *b = cmax; *g = cmid; *r = cmin; break; + case 4: *b = cmax; *r = cmid; *g = cmin; break; + case 5: *r = cmax; *b = cmid; *g = cmin; break; + } + } +} + +static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hs, sd, vd, &blend[0], &blend[1], &blend[2]); + break; + case splashModeBGR8: + cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); + cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); + cvtHSVToRGB(hs, sd, vd, &blend[2], &blend[1], &blend[0]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hs, sd, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[0] = 0xff - g; + blend[0] = 0xff - b; + blend[3] = 0; + break; +#endif + default: + //~ unimplemented + break; + } +} + +static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hd, ss, vd, &blend[0], &blend[1], &blend[2]); + break; + case splashModeBGR8: + cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); + cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); + cvtHSVToRGB(hd, ss, vd, &blend[2], &blend[1], &blend[0]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hd, ss, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[0] = 0xff - g; + blend[0] = 0xff - b; + blend[3] = 0; + break; +#endif + default: + //~ unimplemented + break; + } +} + +static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &blend[0], &blend[1], &blend[2]); + break; + case splashModeBGR8: + cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); + cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &blend[2], &blend[1], &blend[0]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hs, ss, vd, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[0] = 0xff - g; + blend[0] = 0xff - b; + blend[3] = 0; + break; +#endif + default: + //~ unimplemented + break; + } +} + +static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, + SplashColorMode cm) { + int hs, ss, vs, hd, sd, vd; +#if SPLASH_CMYK + Guchar r, g, b; +#endif + + switch (cm) { + case splashModeMono1: + case splashModeMono8: + blend[0] = dest[0]; + break; + case splashModeRGB8: + cvtRGBToHSV(src[0], src[1], src[2], &hs, &ss, &vs); + cvtRGBToHSV(dest[0], dest[1], dest[2], &hd, &sd, &vd); + cvtHSVToRGB(hd, sd, vs, &blend[0], &blend[1], &blend[2]); + break; + case splashModeBGR8: + cvtRGBToHSV(src[2], src[1], src[0], &hs, &ss, &vs); + cvtRGBToHSV(dest[2], dest[1], dest[0], &hd, &sd, &vd); + cvtHSVToRGB(hd, sd, vs, &blend[2], &blend[1], &blend[0]); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + //~ (0xff - ...) should be clipped + cvtRGBToHSV(0xff - (src[0] + src[3]), + 0xff - (src[1] + src[3]), + 0xff - (src[2] + src[3]), &hs, &ss, &vs); + cvtRGBToHSV(0xff - (dest[0] + dest[3]), + 0xff - (dest[1] + dest[3]), + 0xff - (dest[2] + dest[3]), &hd, &sd, &vd); + cvtHSVToRGB(hd, sd, vs, &r, &g, &b); + //~ should do black generation + blend[0] = 0xff - r; + blend[0] = 0xff - g; + blend[0] = 0xff - b; + blend[3] = 0; + break; +#endif + default: + //~ unimplemented + break; + } +} + +// NB: This must match the GfxBlendMode enum defined in GfxState.h. +SplashBlendFunc splashOutBlendFuncs[] = { + NULL, + &splashOutBlendMultiply, + &splashOutBlendScreen, + &splashOutBlendOverlay, + &splashOutBlendDarken, + &splashOutBlendLighten, + &splashOutBlendColorDodge, + &splashOutBlendColorBurn, + &splashOutBlendHardLight, + &splashOutBlendSoftLight, + &splashOutBlendDifference, + &splashOutBlendExclusion, + &splashOutBlendHue, + &splashOutBlendSaturation, + &splashOutBlendColor, + &splashOutBlendLuminosity +}; + +//------------------------------------------------------------------------ +// Font substitutions +//------------------------------------------------------------------------ + +struct SplashOutFontSubst { + char *name; + double mWidth; +}; + +// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic +static SplashOutFontSubst splashOutSubstFonts[16] = { + {"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}, + {"Symbol", 0.576}, + {"Symbol", 0.576}, + {"Symbol", 0.576}, + {"Symbol", 0.576} +}; + +//------------------------------------------------------------------------ +// SplashOutFontFileID +//------------------------------------------------------------------------ + +class SplashOutFontFileID: public SplashFontFileID { +public: + + SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; } + + ~SplashOutFontFileID() {} + + GBool matches(SplashFontFileID *id) { + return ((SplashOutFontFileID *)id)->r.num == r.num && + ((SplashOutFontFileID *)id)->r.gen == r.gen; + } + + void setSubstIdx(int substIdxA) { substIdx = substIdxA; } + int getSubstIdx() { return substIdx; } + +private: + + Ref r; + int substIdx; +}; + +//------------------------------------------------------------------------ +// T3FontCache +//------------------------------------------------------------------------ + +struct T3FontCacheTag { + Gushort code; + Gushort mru; // valid bit (0x8000) and MRU index +}; + +class T3FontCache { +public: + + T3FontCache(Ref *fontID, double m11A, double m12A, + double m21A, double m22A, + int glyphXA, int glyphYA, int glyphWA, int glyphHA, + GBool aa); + ~T3FontCache(); + GBool matches(Ref *idA, double m11A, double m12A, + double m21A, double m22A) + { return fontID.num == idA->num && fontID.gen == idA->gen && + m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; } + + Ref fontID; // PDF font ID + double m11, m12, m21, m22; // transform matrix + int glyphX, glyphY; // pixel offset of glyph bitmaps + int glyphW, glyphH; // size of glyph bitmaps, in pixels + int glyphSize; // size of glyph bitmaps, in bytes + int cacheSets; // number of sets in cache + int cacheAssoc; // cache associativity (glyphs per set) + Guchar *cacheData; // glyph pixmap cache + T3FontCacheTag *cacheTags; // cache tags, i.e., char codes +}; + +T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, + double m21A, double m22A, + int glyphXA, int glyphYA, int glyphWA, int glyphHA, + GBool aa) { + int i; + + fontID = *fontIDA; + m11 = m11A; + m12 = m12A; + m21 = m21A; + m22 = m22A; + glyphX = glyphXA; + glyphY = glyphYA; + glyphW = glyphWA; + glyphH = glyphHA; + if (aa) { + glyphSize = glyphW * glyphH; + } else { + glyphSize = ((glyphW + 7) >> 3) * glyphH; + } + cacheAssoc = 8; + if (glyphSize <= 256) { + cacheSets = 8; + } else if (glyphSize <= 512) { + cacheSets = 4; + } else if (glyphSize <= 1024) { + cacheSets = 2; + } else { + cacheSets = 1; + } + cacheData = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize); + cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc, + sizeof(T3FontCacheTag)); + for (i = 0; i < cacheSets * cacheAssoc; ++i) { + cacheTags[i].mru = i & (cacheAssoc - 1); + } +} + +T3FontCache::~T3FontCache() { + gfree(cacheData); + gfree(cacheTags); +} + +struct T3GlyphStack { + Gushort code; // character code + double x, y; // position to draw the glyph + + //----- cache info + T3FontCache *cache; // font cache for the current font + T3FontCacheTag *cacheTag; // pointer to cache tag for the glyph + Guchar *cacheData; // pointer to cache data for the glyph + + //----- saved state + SplashBitmap *origBitmap; + Splash *origSplash; + double origCTM4, origCTM5; + + T3GlyphStack *next; // next object on stack +}; + +//------------------------------------------------------------------------ +// SplashOutputDev +//------------------------------------------------------------------------ + +SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, + int bitmapRowPadA, + GBool reverseVideoA, + SplashColorPtr paperColorA, + GBool bitmapTopDownA, + GBool allowAntialiasA) { + colorMode = colorModeA; + bitmapRowPad = bitmapRowPadA; + bitmapTopDown = bitmapTopDownA; + allowAntialias = allowAntialiasA; + reverseVideo = reverseVideoA; + splashColorCopy(paperColor, paperColorA); + + xref = NULL; + + bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, bitmapTopDown); + splash = new Splash(bitmap); + splash->clear(paperColor); + + fontEngine = NULL; + + nT3Fonts = 0; + t3GlyphStack = NULL; + + font = NULL; + needFontUpdate = gFalse; + textClipPath = NULL; +} + +SplashOutputDev::~SplashOutputDev() { + int i; + + for (i = 0; i < nT3Fonts; ++i) { + delete t3FontCache[i]; + } + if (fontEngine) { + delete fontEngine; + } + if (splash) { + delete splash; + } + if (bitmap) { + delete bitmap; + } +} + +void SplashOutputDev::startDoc(XRef *xrefA) { + int i; + + xref = xrefA; + if (fontEngine) { + delete fontEngine; + } + fontEngine = new SplashFontEngine( +#if HAVE_T1LIB_H + globalParams->getEnableT1lib(), +#endif +#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H + globalParams->getEnableFreeType(), +#endif + allowAntialias && + globalParams->getAntialias() && + colorMode != splashModeMono1); + for (i = 0; i < nT3Fonts; ++i) { + delete t3FontCache[i]; + } + nT3Fonts = 0; +} + +GBool SplashOutputDev::startPage(int pageNum, GfxState *state) { + int w, h; + SplashColor color; + + w = state ? (int)(state->getPageWidth() + 0.5) : 1; + h = state ? (int)(state->getPageHeight() + 0.5) : 1; + if (splash) { + delete splash; + } + if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) { + if (bitmap) { + delete bitmap; + } + bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, bitmapTopDown); + } + splash = new Splash(bitmap); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + color[0] = 0; + break; + case splashModeRGB8: + case splashModeBGR8: + color[0] = color[1] = color[2] = 0; + break; + case splashModeAMono8: + color[0] = 0xff; + color[1] = 0; + break; + case splashModeARGB8: + color[0] = 255; + color[1] = color[2] = color[3] = 0; + break; + case splashModeBGRA8: + color[0] = color[1] = color[2] = 0; + color[3] = 255; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color[0] = color[1] = color[2] = color[3] = 0; + break; + case splashModeACMYK8: + color[0] = 255; + color[1] = color[2] = color[3] = color[4] = 0; + break; +#endif + } + splash->setStrokePattern(new SplashSolidColor(color)); + splash->setFillPattern(new SplashSolidColor(color)); + splash->setLineCap(splashLineCapButt); + splash->setLineJoin(splashLineJoinMiter); + splash->setLineDash(NULL, 0, 0); + splash->setMiterLimit(10); + splash->setFlatness(1); + splash->clear(paperColor); + + return (gTrue); +} + +void SplashOutputDev::endPage() { +} + +void SplashOutputDev::drawLink(Link *link, Catalog *catalog) { + double x1, y1, x2, y2; + LinkBorderStyle *borderStyle; + double r, g, b; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + double *dash; + int dashLength; + SplashCoord dashList[20]; + SplashPath *path; + int x, y, i; + + link->getRect(&x1, &y1, &x2, &y2); + borderStyle = link->getBorderStyle(); + if (borderStyle->getWidth() > 0) { + borderStyle->getColor(&r, &g, &b); + rgb.r = dblToCol(r); + rgb.g = dblToCol(g); + rgb.b = dblToCol(b); + gray = dblToCol(0.299 * r + 0.587 * g + 0.114 * b); + if (gray > gfxColorComp1) { + gray = gfxColorComp1; + } +#if SPLASH_CMYK + cmyk.c = gfxColorComp1 - rgb.r; + cmyk.m = gfxColorComp1 - rgb.g; + cmyk.y = gfxColorComp1 - rgb.b; + cmyk.k = 0; + splash->setStrokePattern(getColor(gray, &rgb, &cmyk)); +#else + splash->setStrokePattern(getColor(gray, &rgb)); +#endif + splash->setLineWidth((SplashCoord)borderStyle->getWidth()); + borderStyle->getDash(&dash, &dashLength); + if (borderStyle->getType() == linkBorderDashed && dashLength > 0) { + if (dashLength > 20) { + dashLength = 20; + } + for (i = 0; i < dashLength; ++i) { + dashList[i] = (SplashCoord)dash[i]; + } + splash->setLineDash(dashList, dashLength, 0); + } + path = new SplashPath(); + if (borderStyle->getType() == linkBorderUnderlined) { + cvtUserToDev(x1, y1, &x, &y); + path->moveTo((SplashCoord)x, (SplashCoord)y); + cvtUserToDev(x2, y1, &x, &y); + path->lineTo((SplashCoord)x, (SplashCoord)y); + } else { + cvtUserToDev(x1, y1, &x, &y); + path->moveTo((SplashCoord)x, (SplashCoord)y); + cvtUserToDev(x2, y1, &x, &y); + path->lineTo((SplashCoord)x, (SplashCoord)y); + cvtUserToDev(x2, y2, &x, &y); + path->lineTo((SplashCoord)x, (SplashCoord)y); + cvtUserToDev(x1, y2, &x, &y); + path->lineTo((SplashCoord)x, (SplashCoord)y); + path->close(); + } + splash->stroke(path); + delete path; + } +} + +void SplashOutputDev::saveState(GfxState *state) { + splash->saveState(); +} + +void SplashOutputDev::restoreState(GfxState *state) { + splash->restoreState(); + needFontUpdate = gTrue; +} + +void SplashOutputDev::updateAll(GfxState *state) { + updateLineDash(state); + updateLineJoin(state); + updateLineCap(state); + updateLineWidth(state); + updateFlatness(state); + updateMiterLimit(state); + updateFillColor(state); + updateStrokeColor(state); + needFontUpdate = gTrue; +} + +void SplashOutputDev::updateCTM(GfxState *state, double m11, double m12, + double m21, double m22, + double m31, double m32) { + updateLineDash(state); + updateLineJoin(state); + updateLineCap(state); + updateLineWidth(state); +} + +void SplashOutputDev::updateLineDash(GfxState *state) { + double *dashPattern; + int dashLength; + double dashStart; + SplashCoord dash[20]; + SplashCoord phase; + int i; + + state->getLineDash(&dashPattern, &dashLength, &dashStart); + if (dashLength > 20) { + dashLength = 20; + } + for (i = 0; i < dashLength; ++i) { + dash[i] = (SplashCoord)state->transformWidth(dashPattern[i]); + if (dash[i] < 1) { + dash[i] = 1; + } + } + phase = (SplashCoord)state->transformWidth(dashStart); + splash->setLineDash(dash, dashLength, phase); +} + +void SplashOutputDev::updateFlatness(GfxState *state) { + splash->setFlatness(state->getFlatness()); +} + +void SplashOutputDev::updateLineJoin(GfxState *state) { + splash->setLineJoin(state->getLineJoin()); +} + +void SplashOutputDev::updateLineCap(GfxState *state) { + splash->setLineCap(state->getLineCap()); +} + +void SplashOutputDev::updateMiterLimit(GfxState *state) { + splash->setMiterLimit(state->getMiterLimit()); +} + +void SplashOutputDev::updateLineWidth(GfxState *state) { + splash->setLineWidth(state->getTransformedLineWidth()); +} + +void SplashOutputDev::updateFillColor(GfxState *state) { + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + + state->getFillGray(&gray); + state->getFillRGB(&rgb); +#if SPLASH_CMYK + state->getFillCMYK(&cmyk); + splash->setFillPattern(getColor(gray, &rgb, &cmyk)); +#else + splash->setFillPattern(getColor(gray, &rgb)); +#endif +} + +void SplashOutputDev::updateStrokeColor(GfxState *state) { + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + + state->getStrokeGray(&gray); + state->getStrokeRGB(&rgb); +#if SPLASH_CMYK + state->getStrokeCMYK(&cmyk); + splash->setStrokePattern(getColor(gray, &rgb, &cmyk)); +#else + splash->setStrokePattern(getColor(gray, &rgb)); +#endif +} + +#if SPLASH_CMYK +SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb, + GfxCMYK *cmyk) { +#else +SplashPattern *SplashOutputDev::getColor(GfxGray gray, GfxRGB *rgb) { +#endif + SplashPattern *pattern; + SplashColor color0, color1; + GfxColorComp r, g, b; + + if (reverseVideo) { + gray = gfxColorComp1 - gray; + r = gfxColorComp1 - rgb->r; + g = gfxColorComp1 - rgb->g; + b = gfxColorComp1 - rgb->b; + } else { + r = rgb->r; + g = rgb->g; + b = rgb->b; + } + + pattern = NULL; // make gcc happy + switch (colorMode) { + case splashModeMono1: + color0[0] = 0; + color1[0] = 1; + pattern = new SplashHalftone(color0, color1, + splash->getScreen()->copy(), + (SplashCoord)colToDbl(gray)); + break; + case splashModeMono8: + color1[0] = colToByte(gray); + pattern = new SplashSolidColor(color1); + break; + case splashModeAMono8: + color1[0] = 255; + color1[1] = colToByte(gray); + pattern = new SplashSolidColor(color1); + break; + case splashModeRGB8: + color1[0] = colToByte(r); + color1[1] = colToByte(g); + color1[2] = colToByte(b); + pattern = new SplashSolidColor(color1); + break; + case splashModeBGR8: + color1[2] = colToByte(r); + color1[1] = colToByte(g); + color1[0] = colToByte(b); + pattern = new SplashSolidColor(color1); + break; + case splashModeARGB8: + color1[0] = 255; + color1[1] = colToByte(r); + color1[2] = colToByte(g); + color1[3] = colToByte(b); + pattern = new SplashSolidColor(color1); + break; + case splashModeBGRA8: + color1[3] = 255; + color1[2] = colToByte(r); + color1[1] = colToByte(g); + color1[0] = colToByte(b); + pattern = new SplashSolidColor(color1); + break; +#if SPLASH_CMYK + case splashModeCMYK8: + color1[0] = colToByte(cmyk->c); + color1[1] = colToByte(cmyk->m); + color1[2] = colToByte(cmyk->y); + color1[3] = colToByte(cmyk->k); + pattern = new SplashSolidColor(color1); + break; + case splashModeACMYK8: + color1[0] = 255; + color1[1] = colToByte(cmyk->c); + color1[2] = colToByte(cmyk->m); + color1[3] = colToByte(cmyk->y); + color1[4] = colToByte(cmyk->k); + pattern = new SplashSolidColor(color1); + break; +#endif + } + + return pattern; +} + +void SplashOutputDev::updateBlendMode(GfxState *state) { + splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]); +} + +void SplashOutputDev::updateFillOpacity(GfxState *state) { + splash->setFillAlpha((SplashCoord)state->getFillOpacity()); +} + +void SplashOutputDev::updateStrokeOpacity(GfxState *state) { + splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity()); +} + +void SplashOutputDev::updateFont(GfxState *state) { + GfxFont *gfxFont; + GfxFontType fontType; + SplashOutFontFileID *id; + SplashFontFile *fontFile; + FoFiTrueType *ff; + Ref embRef; + Object refObj, strObj; + GString *tmpFileName, *fileName, *substName; + FILE *tmpFile; + Gushort *codeToGID; + DisplayFontParam *dfp; + CharCodeToUnicode *ctu; + double m11, m12, m21, m22, w1, w2; + SplashCoord mat[4]; + char *name; + Unicode uBuf[8]; + int c, substIdx, n, code, cmap; + + needFontUpdate = gFalse; + font = NULL; + tmpFileName = NULL; + substIdx = -1; + dfp = NULL; + + if (!(gfxFont = state->getFont())) { + goto err1; + } + fontType = gfxFont->getType(); + if (fontType == fontType3) { + goto err1; + } + + // check the font file cache + id = new SplashOutFontFileID(gfxFont->getID()); + if ((fontFile = fontEngine->getFontFile(id))) { + delete id; + + } else { + + // if there is an embedded font, write it to disk + if (gfxFont->getEmbeddedFontID(&embRef)) { + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + error(-1, "Couldn't create temporary font file"); + goto err2; + } + refObj.initRef(embRef.num, embRef.gen); + refObj.fetch(xref, &strObj); + refObj.free(); + strObj.streamReset(); + while ((c = strObj.streamGetChar()) != EOF) { + fputc(c, tmpFile); + } + strObj.streamClose(); + strObj.free(); + fclose(tmpFile); + fileName = tmpFileName; + + // if there is an external font file, use it + } else if (!(fileName = gfxFont->getExtFontFile())) { + + // look for a display font mapping or a substitute font + if (gfxFont->isCIDFont()) { + if (((GfxCIDFont *)gfxFont)->getCollection()) { + dfp = globalParams-> + getDisplayCIDFont(gfxFont->getName(), + ((GfxCIDFont *)gfxFont)->getCollection()); + } + } else { + if (gfxFont->getName()) { + dfp = globalParams->getDisplayFont(gfxFont->getName()); + } + if (!dfp) { + // 8-bit font substitution + if (gfxFont->isFixedWidth()) { + substIdx = 8; + } else if (gfxFont->isSerif()) { + substIdx = 4; + } else { + substIdx = 0; + } + if (gfxFont->isBold()) { + substIdx += 2; + } + if (gfxFont->isItalic()) { + substIdx += 1; + } + substName = new GString(splashOutSubstFonts[substIdx].name); + dfp = globalParams->getDisplayFont(substName); + delete substName; + id->setSubstIdx(substIdx); + } + } + if (!dfp) { + error(-1, "Couldn't find a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + switch (dfp->kind) { + case displayFontT1: + fileName = dfp->t1.fileName; + fontType = gfxFont->isCIDFont() ? fontCIDType0 : fontType1; + break; + case displayFontTT: + fileName = dfp->tt.fileName; + fontType = gfxFont->isCIDFont() ? fontCIDType2 : fontTrueType; + break; + } + } + + // load the font file + switch (fontType) { + case fontType1: + if (!(fontFile = fontEngine->loadType1Font( + id, + fileName->getCString(), + fileName == tmpFileName, + ((Gfx8BitFont *)gfxFont)->getEncoding()))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontType1C: + if (!(fontFile = fontEngine->loadType1CFont( + id, + fileName->getCString(), + fileName == tmpFileName, + ((Gfx8BitFont *)gfxFont)->getEncoding()))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontTrueType: + if ((ff = FoFiTrueType::load(fileName->getCString()))) { + codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); + n = 256; + delete ff; + } else { + codeToGID = NULL; + n = 0; + } + if (!(fontFile = fontEngine->loadTrueTypeFont( + id, + fileName->getCString(), + fileName == tmpFileName, + codeToGID, n))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontCIDType0: + case fontCIDType0C: + if (!(fontFile = fontEngine->loadCIDFont( + id, + fileName->getCString(), + fileName == tmpFileName))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + case fontCIDType2: + codeToGID = NULL; + n = 0; + if (dfp) { + // create a CID-to-GID mapping, via Unicode + if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) { + if ((ff = FoFiTrueType::load(fileName->getCString()))) { + // look for a Unicode cmap + for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { + if ((ff->getCmapPlatform(cmap) == 3 && + ff->getCmapEncoding(cmap) == 1) || + ff->getCmapPlatform(cmap) == 0) { + break; + } + } + if (cmap < ff->getNumCmaps()) { + // map CID -> Unicode -> GID + n = ctu->getLength(); + codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); + for (code = 0; code < n; ++code) { + if (ctu->mapToUnicode(code, uBuf, 8) > 0) { + codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]); + } else { + codeToGID[code] = 0; + } + } + } + delete ff; + } + ctu->decRefCnt(); + } else { + error(-1, "Couldn't find a mapping to Unicode for font '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + } + } else { + if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { + n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); + codeToGID = (Gushort *)gmallocn(n, sizeof(Gushort)); + memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), + n * sizeof(Gushort)); + } + } + if (!(fontFile = fontEngine->loadTrueTypeFont( + id, + fileName->getCString(), + fileName == tmpFileName, + codeToGID, n))) { + error(-1, "Couldn't create a font for '%s'", + gfxFont->getName() ? gfxFont->getName()->getCString() + : "(unnamed)"); + goto err2; + } + break; + default: + // this shouldn't happen + goto err2; + } + } + + // get the font matrix + state->getFontTransMat(&m11, &m12, &m21, &m22); + m11 *= state->getHorizScaling(); + m12 *= state->getHorizScaling(); + + // for substituted fonts: adjust the font matrix -- compare the + // width of 'm' in the original font and the substituted font + substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx(); + if (substIdx >= 0) { + for (code = 0; code < 256; ++code) { + if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && + name[0] == 'm' && name[1] == '\0') { + break; + } + } + if (code < 256) { + w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code); + w2 = splashOutSubstFonts[substIdx].mWidth; + if (!gfxFont->isSymbolic()) { + // if real font is substantially narrower than substituted + // font, reduce the font size accordingly + if (w1 > 0.01 && w1 < 0.9 * w2) { + w1 /= w2; + m11 *= w1; + m21 *= w1; + } + } + } + } + + // create the scaled font + mat[0] = m11; mat[1] = -m12; + mat[2] = m21; mat[3] = -m22; + if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.01) { + // avoid a singular (or close-to-singular) matrix + mat[0] = 0.01; mat[1] = 0; + mat[2] = 0; mat[3] = 0.01; + } + font = fontEngine->getFont(fontFile, mat); + + if (tmpFileName) { + delete tmpFileName; + } + return; + + err2: + delete id; + err1: + if (tmpFileName) { + delete tmpFileName; + } + return; +} + +void SplashOutputDev::stroke(GfxState *state) { + SplashPath *path; + + path = convertPath(state, state->getPath()); + splash->stroke(path); + delete path; +} + +void SplashOutputDev::fill(GfxState *state) { + SplashPath *path; + + path = convertPath(state, state->getPath()); + splash->fill(path, gFalse); + delete path; +} + +void SplashOutputDev::eoFill(GfxState *state) { + SplashPath *path; + + path = convertPath(state, state->getPath()); + splash->fill(path, gTrue); + delete path; +} + +void SplashOutputDev::clip(GfxState *state) { + SplashPath *path; + + path = convertPath(state, state->getPath()); + splash->clipToPath(path, gFalse); + delete path; +} + +void SplashOutputDev::eoClip(GfxState *state) { + SplashPath *path; + + path = convertPath(state, state->getPath()); + splash->clipToPath(path, gTrue); + delete path; +} + +SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path) { + SplashPath *sPath; + GfxSubpath *subpath; + double x1, y1, x2, y2, x3, y3; + int i, j; + + sPath = new SplashPath(); + for (i = 0; i < path->getNumSubpaths(); ++i) { + subpath = path->getSubpath(i); + if (subpath->getNumPoints() > 0) { + state->transform(subpath->getX(0), subpath->getY(0), &x1, &y1); + sPath->moveTo((SplashCoord)x1, (SplashCoord)y1); + j = 1; + while (j < subpath->getNumPoints()) { + if (subpath->getCurve(j)) { + state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1); + state->transform(subpath->getX(j+1), subpath->getY(j+1), &x2, &y2); + state->transform(subpath->getX(j+2), subpath->getY(j+2), &x3, &y3); + sPath->curveTo((SplashCoord)x1, (SplashCoord)y1, + (SplashCoord)x2, (SplashCoord)y2, + (SplashCoord)x3, (SplashCoord)y3); + j += 3; + } else { + state->transform(subpath->getX(j), subpath->getY(j), &x1, &y1); + sPath->lineTo((SplashCoord)x1, (SplashCoord)y1); + ++j; + } + } + if (subpath->isClosed()) { + sPath->close(); + } + } + } + return sPath; +} + +void SplashOutputDev::drawChar(GfxState *state, double x, double y, + double dx, double dy, + double originX, double originY, + CharCode code, int nBytes, + Unicode *u, int uLen) { + double x1, y1; + SplashPath *path; + int render; + + if (needFontUpdate) { + updateFont(state); + } + if (!font) { + return; + } + + // check for invisible text -- this is used by Acrobat Capture + render = state->getRender(); + if (render == 3) { + return; + } + + x -= originX; + y -= originY; + state->transform(x, y, &x1, &y1); + + // fill + if (!(render & 1)) { + splash->fillChar((SplashCoord)x1, (SplashCoord)y1, code, font); + } + + // stroke + if ((render & 3) == 1 || (render & 3) == 2) { + if ((path = font->getGlyphPath(code))) { + path->offset((SplashCoord)x1, (SplashCoord)y1); + splash->stroke(path); + delete path; + } + } + + // clip + if (render & 4) { + path = font->getGlyphPath(code); + path->offset((SplashCoord)x1, (SplashCoord)y1); + if (textClipPath) { + textClipPath->append(path); + delete path; + } else { + textClipPath = path; + } + } +} + +GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y, + double dx, double dy, + CharCode code, Unicode *u, int uLen) { + GfxFont *gfxFont; + Ref *fontID; + double *ctm, *bbox; + T3FontCache *t3Font; + T3GlyphStack *t3gs; + double x1, y1, xMin, yMin, xMax, yMax, xt, yt; + int i, j; + + if (!(gfxFont = state->getFont())) { + return gFalse; + } + fontID = gfxFont->getID(); + ctm = state->getCTM(); + state->transform(0, 0, &xt, &yt); + + // is it the first (MRU) font in the cache? + if (!(nT3Fonts > 0 && + t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) { + + // is the font elsewhere in the cache? + for (i = 1; i < nT3Fonts; ++i) { + if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) { + t3Font = t3FontCache[i]; + for (j = i; j > 0; --j) { + t3FontCache[j] = t3FontCache[j - 1]; + } + t3FontCache[0] = t3Font; + break; + } + } + if (i >= nT3Fonts) { + + // create new entry in the font cache + if (nT3Fonts == splashOutT3FontCacheSize) { + delete t3FontCache[nT3Fonts - 1]; + --nT3Fonts; + } + for (j = nT3Fonts; j > 0; --j) { + t3FontCache[j] = t3FontCache[j - 1]; + } + ++nT3Fonts; + bbox = gfxFont->getFontBBox(); + if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) { + // broken bounding box -- just take a guess + xMin = xt - 5; + xMax = xMin + 30; + yMax = yt + 15; + yMin = yMax - 45; + } else { + state->transform(bbox[0], bbox[1], &x1, &y1); + xMin = xMax = x1; + yMin = yMax = y1; + state->transform(bbox[0], bbox[3], &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + state->transform(bbox[2], bbox[1], &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + state->transform(bbox[2], bbox[3], &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + } + t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3], + (int)floor(xMin - xt), + (int)floor(yMin - yt), + (int)ceil(xMax) - (int)floor(xMin) + 3, + (int)ceil(yMax) - (int)floor(yMin) + 3, + colorMode != splashModeMono1); + } + } + t3Font = t3FontCache[0]; + + // is the glyph in the cache? + i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; + for (j = 0; j < t3Font->cacheAssoc; ++j) { + if ((t3Font->cacheTags[i+j].mru & 0x8000) && + t3Font->cacheTags[i+j].code == code) { + drawType3Glyph(t3Font, &t3Font->cacheTags[i+j], + t3Font->cacheData + (i+j) * t3Font->glyphSize, + xt, yt); + return gTrue; + } + } + + // push a new Type 3 glyph record + t3gs = new T3GlyphStack(); + t3gs->next = t3GlyphStack; + t3GlyphStack = t3gs; + t3GlyphStack->code = code; + t3GlyphStack->x = xt; + t3GlyphStack->y = yt; + t3GlyphStack->cache = t3Font; + t3GlyphStack->cacheTag = NULL; + t3GlyphStack->cacheData = NULL; + + return gFalse; +} + +void SplashOutputDev::endType3Char(GfxState *state) { + T3GlyphStack *t3gs; + double *ctm; + + if (t3GlyphStack->cacheTag) { + memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(), + t3GlyphStack->cache->glyphSize); + delete bitmap; + delete splash; + bitmap = t3GlyphStack->origBitmap; + splash = t3GlyphStack->origSplash; + ctm = state->getCTM(); + state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], + t3GlyphStack->origCTM4, t3GlyphStack->origCTM5); + drawType3Glyph(t3GlyphStack->cache, + t3GlyphStack->cacheTag, t3GlyphStack->cacheData, + t3GlyphStack->x, t3GlyphStack->y); + } + t3gs = t3GlyphStack; + t3GlyphStack = t3gs->next; + delete t3gs; +} + +void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) { +} + +void SplashOutputDev::type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury) { + double *ctm; + T3FontCache *t3Font; + SplashColor color; + double xt, yt, xMin, xMax, yMin, yMax, x1, y1; + int i, j; + + t3Font = t3GlyphStack->cache; + + // check for a valid bbox + state->transform(0, 0, &xt, &yt); + state->transform(llx, lly, &x1, &y1); + xMin = xMax = x1; + yMin = yMax = y1; + state->transform(llx, ury, &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + state->transform(urx, lly, &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + state->transform(urx, ury, &x1, &y1); + if (x1 < xMin) { + xMin = x1; + } else if (x1 > xMax) { + xMax = x1; + } + if (y1 < yMin) { + yMin = y1; + } else if (y1 > yMax) { + yMax = y1; + } + if (xMin - xt < t3Font->glyphX || + yMin - yt < t3Font->glyphY || + xMax - xt > t3Font->glyphX + t3Font->glyphW || + yMax - yt > t3Font->glyphY + t3Font->glyphH) { + error(-1, "Bad bounding box in Type 3 glyph"); + return; + } + + // allocate a cache entry + i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; + for (j = 0; j < t3Font->cacheAssoc; ++j) { + if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) { + t3Font->cacheTags[i+j].mru = 0x8000; + t3Font->cacheTags[i+j].code = t3GlyphStack->code; + t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j]; + t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize; + } else { + ++t3Font->cacheTags[i+j].mru; + } + } + + // save state + t3GlyphStack->origBitmap = bitmap; + t3GlyphStack->origSplash = splash; + ctm = state->getCTM(); + t3GlyphStack->origCTM4 = ctm[4]; + t3GlyphStack->origCTM5 = ctm[5]; + + // create the temporary bitmap + if (colorMode == splashModeMono1) { + bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, + splashModeMono1); + splash = new Splash(bitmap); + color[0] = 0; + splash->clear(color); + color[0] = 1; + } else { + bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, + splashModeMono8); + splash = new Splash(bitmap); + color[0] = 0x00; + splash->clear(color); + color[0] = 0xff; + } + splash->setFillPattern(new SplashSolidColor(color)); + splash->setStrokePattern(new SplashSolidColor(color)); + //~ this should copy other state from t3GlyphStack->origSplash? + state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], + -t3Font->glyphX, -t3Font->glyphY); +} + +void SplashOutputDev::drawType3Glyph(T3FontCache *t3Font, + T3FontCacheTag *tag, Guchar *data, + double x, double y) { + SplashGlyphBitmap glyph; + + glyph.x = -t3Font->glyphX; + glyph.y = -t3Font->glyphY; + glyph.w = t3Font->glyphW; + glyph.h = t3Font->glyphH; + glyph.aa = colorMode != splashModeMono1; + glyph.data = data; + glyph.freeData = gFalse; + splash->fillGlyph((SplashCoord)x, (SplashCoord)y, &glyph); +} + +void SplashOutputDev::endTextObject(GfxState *state) { + if (textClipPath) { + splash->clipToPath(textClipPath, gFalse); + delete textClipPath; + textClipPath = NULL; + } +} + +struct SplashOutImageMaskData { + ImageStream *imgStr; + GBool invert; + int width, height, y; +}; + +GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) { + SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data; + Guchar *p; + SplashColorPtr q; + int x; + + if (imgMaskData->y == imgMaskData->height) { + return gFalse; + } + for (x = 0, p = imgMaskData->imgStr->getLine(), q = line; + x < imgMaskData->width; + ++x) { + *q++ = *p++ ^ imgMaskData->invert; + } + ++imgMaskData->y; + return gTrue; +} + +void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, + int width, int height, GBool invert, + GBool inlineImg) { + double *ctm; + SplashCoord mat[6]; + SplashOutImageMaskData imgMaskData; + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + imgMaskData.imgStr = new ImageStream(str, width, 1, 1); + imgMaskData.imgStr->reset(); + imgMaskData.invert = invert ? 0 : 1; + imgMaskData.width = width; + imgMaskData.height = height; + imgMaskData.y = 0; + + splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat); + if (inlineImg) { + while (imgMaskData.y < height) { + imgMaskData.imgStr->getLine(); + ++imgMaskData.y; + } + } + + delete imgMaskData.imgStr; + str->close(); +} + +struct SplashOutImageData { + ImageStream *imgStr; + GfxImageColorMap *colorMap; + SplashColorPtr lookup; + int *maskColors; + SplashColorMode colorMode; + int width, height, y; +}; + +GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr line) { + SplashOutImageData *imgData = (SplashOutImageData *)data; + Guchar *p; + SplashColorPtr q, col; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + int nComps, x; + + if (imgData->y == imgData->height) { + return gFalse; + } + + nComps = imgData->colorMap->getNumPixelComps(); + + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, ++p) { + *q++ = imgData->lookup[*p]; + } + break; + case splashModeRGB8: + case splashModeBGR8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, ++p) { + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, ++p) { + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + } + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } else { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getGray(p, &gray); + *q++ = colToByte(gray); + } + break; + case splashModeRGB8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + } + break; + case splashModeBGR8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.b); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.r); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + } + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } + + ++imgData->y; + return gTrue; +} + +GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr line) { + SplashOutImageData *imgData = (SplashOutImageData *)data; + Guchar *p; + SplashColorPtr q, col; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar alpha; + int nComps, x, i; + + if (imgData->y == imgData->height) { + return gFalse; + } + + nComps = imgData->colorMap->getNumPixelComps(); + + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + alpha = 0; + for (i = 0; i < nComps; ++i) { + if (p[i] < imgData->maskColors[2*i] || + p[i] > imgData->maskColors[2*i+1]) { + alpha = 0xff; + break; + } + } + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + *q++ = alpha; + *q++ = imgData->lookup[*p]; + break; + case splashModeRGB8: + *q++ = alpha; + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + break; + case splashModeBGR8: + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + *q++ = alpha; + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } else { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData->colorMap->getGray(p, &gray); + *q++ = alpha; + *q++ = colToByte(gray); + break; + case splashModeRGB8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = alpha; + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + break; + case splashModeBGR8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.b); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.r); + *q++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = alpha; + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } + } + + ++imgData->y; + return gTrue; +} + +void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + int *maskColors, GBool inlineImg) { + double *ctm; + SplashCoord mat[6]; + SplashOutImageData imgData; + SplashColorMode srcMode; + SplashImageSource src; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + imgData.imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgData.imgStr->reset(); + imgData.colorMap = colorMap; + imgData.maskColors = maskColors; + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.b); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.r); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + default: + //~ unimplemented + break; + } + } + + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + srcMode = maskColors ? splashModeAMono8 : splashModeMono8; + break; + case splashModeRGB8: + srcMode = maskColors ? splashModeARGB8 : splashModeRGB8; + break; + case splashModeBGR8: + srcMode = maskColors ? splashModeBGRA8 : splashModeBGR8; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + srcMode = maskColors ? splashModeACMYK8 : splashModeCMYK8; + break; +#endif + default: + //~ unimplemented + srcMode = splashModeRGB8; + break; + } + src = maskColors ? &alphaImageSrc : &imageSrc; + splash->drawImage(src, &imgData, srcMode, width, height, mat); + if (inlineImg) { + while (imgData.y < height) { + imgData.imgStr->getLine(); + ++imgData.y; + } + } + + gfree(imgData.lookup); + delete imgData.imgStr; + str->close(); +} + +struct SplashOutMaskedImageData { + ImageStream *imgStr; + GfxImageColorMap *colorMap; + SplashBitmap *mask; + SplashColorPtr lookup; + SplashColorMode colorMode; + int width, height, y; +}; + +GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr line) { + SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data; + Guchar *p; + SplashColor maskColor; + SplashColorPtr q, col; + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar alpha; + int nComps, x; + + if (imgData->y == imgData->height) { + return gFalse; + } + + nComps = imgData->colorMap->getNumPixelComps(); + + for (x = 0, p = imgData->imgStr->getLine(), q = line; + x < imgData->width; + ++x, p += nComps) { + imgData->mask->getPixel(x, imgData->y, maskColor); + alpha = maskColor[0] ? 0xff : 0x00; + if (imgData->lookup) { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + *q++ = alpha; + *q++ = imgData->lookup[*p]; + break; + case splashModeRGB8: + *q++ = alpha; + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + break; + case splashModeBGR8: + col = &imgData->lookup[3 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + *q++ = alpha; + col = &imgData->lookup[4 * *p]; + *q++ = col[0]; + *q++ = col[1]; + *q++ = col[2]; + *q++ = col[3]; + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } else { + switch (imgData->colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData->colorMap->getGray(p, &gray); + *q++ = alpha; + *q++ = colToByte(gray); + break; + case splashModeRGB8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = alpha; + *q++ = colToByte(rgb.r); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.b); + break; + case splashModeBGR8: + imgData->colorMap->getRGB(p, &rgb); + *q++ = colToByte(rgb.b); + *q++ = colToByte(rgb.g); + *q++ = colToByte(rgb.r); + *q++ = alpha; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData->colorMap->getCMYK(p, &cmyk); + *q++ = alpha; + *q++ = colToByte(cmyk.c); + *q++ = colToByte(cmyk.m); + *q++ = colToByte(cmyk.y); + *q++ = colToByte(cmyk.k); + break; +#endif + case splashModeAMono8: + case splashModeARGB8: + case splashModeBGRA8: +#if SPLASH_CMYK + case splashModeACMYK8: +#endif + //~ unimplemented + break; + } + } + } + + ++imgData->y; + return gTrue; +} + +void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, + Stream *str, int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, + int maskHeight, GBool maskInvert) { + double *ctm; + SplashCoord mat[6]; + SplashOutMaskedImageData imgData; + SplashOutImageMaskData imgMaskData; + SplashColorMode srcMode; + SplashBitmap *maskBitmap; + Splash *maskSplash; + SplashColor maskColor; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; + + //----- scale the mask image to the same size as the source image + + mat[0] = (SplashCoord)width; + mat[1] = 0; + mat[2] = 0; + mat[3] = (SplashCoord)height; + mat[4] = 0; + mat[5] = 0; + imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1); + imgMaskData.imgStr->reset(); + imgMaskData.invert = maskInvert ? 0 : 1; + imgMaskData.width = maskWidth; + imgMaskData.height = maskHeight; + imgMaskData.y = 0; + maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1); + maskSplash = new Splash(maskBitmap); + maskColor[0] = 0; + maskSplash->clear(maskColor); + maskColor[0] = 1; + maskSplash->setFillPattern(new SplashSolidColor(maskColor)); + maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, + maskWidth, maskHeight, mat); + delete imgMaskData.imgStr; + maskStr->close(); + delete maskSplash; + + //----- draw the source image + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + imgData.imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgData.imgStr->reset(); + imgData.colorMap = colorMap; + imgData.mask = maskBitmap; + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.b); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.r); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + default: + //~ unimplemented + break; + } + } + + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + srcMode = splashModeAMono8; + break; + case splashModeRGB8: + srcMode = splashModeARGB8; + break; + case splashModeBGR8: + srcMode = splashModeBGRA8; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + srcMode = splashModeACMYK8; + break; +#endif + default: + //~ unimplemented + srcMode = splashModeARGB8; + break; + } + splash->drawImage(&maskedImageSrc, &imgData, srcMode, width, height, mat); + + delete maskBitmap; + gfree(imgData.lookup); + delete imgData.imgStr; + str->close(); +} + +void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, + Stream *str, int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap) { + double *ctm; + SplashCoord mat[6]; + SplashOutImageData imgData; + SplashOutImageData imgMaskData; + SplashColorMode srcMode; + SplashBitmap *maskBitmap; + Splash *maskSplash; + SplashColor maskColor; + GfxGray gray; + GfxRGB rgb; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + Guchar pix; + int n, i; + + ctm = state->getCTM(); + mat[0] = ctm[0]; + mat[1] = ctm[1]; + mat[2] = -ctm[2]; + mat[3] = -ctm[3]; + mat[4] = ctm[2] + ctm[4]; + mat[5] = ctm[3] + ctm[5]; + + //----- set up the soft mask + + imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, + maskColorMap->getNumPixelComps(), + maskColorMap->getBits()); + imgMaskData.imgStr->reset(); + imgMaskData.colorMap = maskColorMap; + imgMaskData.maskColors = NULL; + imgMaskData.colorMode = splashModeMono8; + imgMaskData.width = maskWidth; + imgMaskData.height = maskHeight; + imgMaskData.y = 0; + n = 1 << maskColorMap->getBits(); + imgMaskData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + maskColorMap->getGray(&pix, &gray); + imgMaskData.lookup[i] = colToByte(gray); + } + maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), + 1, splashModeMono8); + maskSplash = new Splash(maskBitmap); + maskColor[0] = 0; + maskSplash->clear(maskColor); + maskSplash->drawImage(&imageSrc, &imgMaskData, + splashModeMono8, maskWidth, maskHeight, mat); + delete imgMaskData.imgStr; + maskStr->close(); + gfree(imgMaskData.lookup); + delete maskSplash; + splash->setSoftMask(maskBitmap); + + //----- draw the source image + + imgData.imgStr = new ImageStream(str, width, + colorMap->getNumPixelComps(), + colorMap->getBits()); + imgData.imgStr->reset(); + imgData.colorMap = colorMap; + imgData.maskColors = NULL; + imgData.colorMode = colorMode; + imgData.width = width; + imgData.height = height; + imgData.y = 0; + + // special case for one-channel (monochrome/gray/separation) images: + // build a lookup table here + imgData.lookup = NULL; + if (colorMap->getNumPixelComps() == 1) { + n = 1 << colorMap->getBits(); + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + imgData.lookup = (SplashColorPtr)gmalloc(n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getGray(&pix, &gray); + imgData.lookup[i] = colToByte(gray); + } + break; + case splashModeRGB8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.r); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.b); + } + break; + case splashModeBGR8: + imgData.lookup = (SplashColorPtr)gmalloc(3 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getRGB(&pix, &rgb); + imgData.lookup[3*i] = colToByte(rgb.b); + imgData.lookup[3*i+1] = colToByte(rgb.g); + imgData.lookup[3*i+2] = colToByte(rgb.r); + } + break; +#if SPLASH_CMYK + case splashModeCMYK8: + imgData.lookup = (SplashColorPtr)gmalloc(4 * n); + for (i = 0; i < n; ++i) { + pix = (Guchar)i; + colorMap->getCMYK(&pix, &cmyk); + imgData.lookup[4*i] = colToByte(cmyk.c); + imgData.lookup[4*i+1] = colToByte(cmyk.m); + imgData.lookup[4*i+2] = colToByte(cmyk.y); + imgData.lookup[4*i+3] = colToByte(cmyk.k); + } + break; +#endif + default: + //~ unimplemented + break; + } + } + + switch (colorMode) { + case splashModeMono1: + case splashModeMono8: + srcMode = splashModeMono8; + break; + case splashModeRGB8: + srcMode = splashModeRGB8; + break; + case splashModeBGR8: + srcMode = splashModeBGR8; + break; +#if SPLASH_CMYK + case splashModeCMYK8: + srcMode = splashModeCMYK8; + break; +#endif + default: + //~ unimplemented + srcMode = splashModeRGB8; + break; + } + splash->drawImage(&imageSrc, &imgData, srcMode, width, height, mat); + + splash->setSoftMask(NULL); + gfree(imgData.lookup); + delete imgData.imgStr; + str->close(); +} + +void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) { + splashColorCopy(paperColor, paperColorA); +} + +int SplashOutputDev::getBitmapWidth() { + return bitmap->getWidth(); +} + +int SplashOutputDev::getBitmapHeight() { + return bitmap->getHeight(); +} + +SplashBitmap *SplashOutputDev::takeBitmap() { + SplashBitmap *ret; + + ret = bitmap; + bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, bitmapTopDown); + return ret; +} + +void SplashOutputDev::getModRegion(int *xMin, int *yMin, + int *xMax, int *yMax) { + splash->getModRegion(xMin, yMin, xMax, yMax); +} + +void SplashOutputDev::clearModRegion() { + splash->clearModRegion(); +} + +void SplashOutputDev::setFillColor(int r, int g, int b) { + GfxRGB rgb; + GfxGray gray; +#if SPLASH_CMYK + GfxCMYK cmyk; +#endif + + rgb.r = byteToCol(r); + rgb.g = byteToCol(g); + rgb.b = byteToCol(b); + gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5); + if (gray > gfxColorComp1) { + gray = gfxColorComp1; + } +#if SPLASH_CMYK + cmyk.c = gfxColorComp1 - rgb.r; + cmyk.m = gfxColorComp1 - rgb.g; + cmyk.y = gfxColorComp1 - rgb.b; + cmyk.k = 0; + splash->setFillPattern(getColor(gray, &rgb, &cmyk)); +#else + splash->setFillPattern(getColor(gray, &rgb)); +#endif +} + +SplashFont *SplashOutputDev::getFont(GString *name, double *mat) { + DisplayFontParam *dfp; + Ref ref; + SplashOutFontFileID *id; + SplashFontFile *fontFile; + SplashFont *fontObj; + FoFiTrueType *ff; + Gushort *codeToGID; + Unicode u; + int cmap, i; + + for (i = 0; i < 16; ++i) { + if (!name->cmp(splashOutSubstFonts[i].name)) { + break; + } + } + if (i == 16) { + return NULL; + } + ref.num = i; + ref.gen = -1; + id = new SplashOutFontFileID(&ref); + + // check the font file cache + if ((fontFile = fontEngine->getFontFile(id))) { + delete id; + + // load the font file + } else { + dfp = globalParams->getDisplayFont(name); + if (dfp && dfp->kind == displayFontT1) { + fontFile = fontEngine->loadType1Font(id, dfp->t1.fileName->getCString(), + gFalse, winAnsiEncoding); + } else if (dfp && dfp->kind == displayFontTT) { + if (!(ff = FoFiTrueType::load(dfp->tt.fileName->getCString()))) { + return NULL; + } + for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { + if ((ff->getCmapPlatform(cmap) == 3 && + ff->getCmapEncoding(cmap) == 1) || + ff->getCmapPlatform(cmap) == 0) { + break; + } + } + if (cmap == ff->getNumCmaps()) { + delete ff; + return NULL; + } + codeToGID = (Gushort *)gmallocn(256, sizeof(Gushort)); + for (i = 0; i < 256; ++i) { + codeToGID[i] = 0; + if (winAnsiEncoding[i] && + (u = globalParams->mapNameToUnicode(winAnsiEncoding[i]))) { + codeToGID[i] = ff->mapCodeToGID(cmap, u); + } + } + delete ff; + fontFile = fontEngine->loadTrueTypeFont(id, + dfp->tt.fileName->getCString(), + gFalse, codeToGID, 256); + } else { + return NULL; + } + } + + // create the scaled font + fontObj = fontEngine->getFont(fontFile, (SplashCoord *)mat); + + return fontObj; +} diff --git a/pdftops/SplashOutputDev.h b/pdftops/SplashOutputDev.h new file mode 100644 index 000000000..266253f65 --- /dev/null +++ b/pdftops/SplashOutputDev.h @@ -0,0 +1,222 @@ +//======================================================================== +// +// SplashOutputDev.h +// +// Copyright 2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef SPLASHOUTPUTDEV_H +#define SPLASHOUTPUTDEV_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "SplashTypes.h" +#include "config.h" +#include "OutputDev.h" +#include "GfxState.h" + +class Gfx8BitFont; +class SplashBitmap; +class Splash; +class SplashPath; +class SplashPattern; +class SplashFontEngine; +class SplashFont; +class T3FontCache; +struct T3FontCacheTag; +struct T3GlyphStack; + +//------------------------------------------------------------------------ + +// number of Type 3 fonts to cache +#define splashOutT3FontCacheSize 8 + +//------------------------------------------------------------------------ +// SplashOutputDev +//------------------------------------------------------------------------ + +class SplashOutputDev: public OutputDev { +public: + + // Constructor. + SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, + GBool reverseVideoA, SplashColorPtr paperColorA, + GBool bitmapTopDownA = gTrue, + GBool allowAntialiasA = gTrue); + + // Destructor. + virtual ~SplashOutputDev(); + + //----- 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 gTrue; } + + // Does this device use drawChar() or drawString()? + virtual GBool useDrawChar() { return gTrue; } + + // Does this device use beginType3Char/endType3Char? Otherwise, + // text in Type 3 fonts will be drawn with drawChar/drawString. + virtual GBool interpretType3Chars() { return gTrue; } + + //----- initialization and control + + // Start a page. + virtual GBool startPage(int pageNum, GfxState *state); + + // End a page. + virtual void endPage(); + + //----- 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 updateBlendMode(GfxState *state); + virtual void updateFillOpacity(GfxState *state); + virtual void updateStrokeOpacity(GfxState *state); + + //----- update text state + virtual void updateFont(GfxState *state); + + //----- 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 drawChar(GfxState *state, double x, double y, + double dx, double dy, + double originX, double originY, + CharCode code, int nBytes, Unicode *u, int uLen); + virtual GBool beginType3Char(GfxState *state, double x, double y, + double dx, double dy, + CharCode code, Unicode *u, int uLen); + virtual void endType3Char(GfxState *state); + virtual void endTextObject(GfxState *state); + + //----- 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); + virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, int maskWidth, int maskHeight, + GBool maskInvert); + virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, + int width, int height, + GfxImageColorMap *colorMap, + Stream *maskStr, + int maskWidth, int maskHeight, + GfxImageColorMap *maskColorMap); + + //----- Type 3 font operators + virtual void type3D0(GfxState *state, double wx, double wy); + virtual void type3D1(GfxState *state, double wx, double wy, + double llx, double lly, double urx, double ury); + + //----- special access + + // Called to indicate that a new PDF document has been loaded. + void startDoc(XRef *xrefA); + + void setPaperColor(SplashColorPtr paperColorA); + + GBool isReverseVideo() { return reverseVideo; } + void setReverseVideo(GBool reverseVideoA) { reverseVideo = reverseVideoA; } + + // Get the bitmap and its size. + SplashBitmap *getBitmap() { return bitmap; } + int getBitmapWidth(); + int getBitmapHeight(); + + // Returns the last rasterized bitmap, transferring ownership to the + // caller. + SplashBitmap *takeBitmap(); + + // Get the Splash object. + Splash *getSplash() { return splash; } + + // Get the modified region. + void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax); + + // Clear the modified region. + void clearModRegion(); + + // Set the Splash fill color. + void setFillColor(int r, int g, int b); + + // Get a font object for a Base-14 font, using the Latin-1 encoding. + SplashFont *getFont(GString *name, double *mat); + + SplashFont *getCurrentFont() { return font; } + +private: + +#if SPLASH_CMYK + SplashPattern *getColor(GfxGray gray, GfxRGB *rgb, GfxCMYK *cmyk); +#else + SplashPattern *getColor(GfxGray gray, GfxRGB *rgb); +#endif + SplashPath *convertPath(GfxState *state, GfxPath *path); + void drawType3Glyph(T3FontCache *t3Font, + T3FontCacheTag *tag, Guchar *data, + double x, double y); + static GBool imageMaskSrc(void *data, SplashColorPtr line); + static GBool imageSrc(void *data, SplashColorPtr line); + static GBool alphaImageSrc(void *data, SplashColorPtr line); + static GBool maskedImageSrc(void *data, SplashColorPtr line); + + SplashColorMode colorMode; + int bitmapRowPad; + GBool bitmapTopDown; + GBool allowAntialias; + GBool reverseVideo; // reverse video mode + SplashColor paperColor; // paper color + + XRef *xref; // xref table for current document + + SplashBitmap *bitmap; + Splash *splash; + SplashFontEngine *fontEngine; + + T3FontCache * // Type 3 font cache + t3FontCache[splashOutT3FontCacheSize]; + int nT3Fonts; // number of valid entries in t3FontCache + T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack + + SplashFont *font; // current font + GBool needFontUpdate; // set when the font needs to be updated + SplashPath *textClipPath; // clipping path built with text object +}; + +#endif diff --git a/pdftops/SplashPath.cxx b/pdftops/SplashPath.cxx new file mode 100644 index 000000000..c392f9761 --- /dev/null +++ b/pdftops/SplashPath.cxx @@ -0,0 +1,178 @@ +//======================================================================== +// +// SplashPath.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashErrorCodes.h" +#include "SplashPath.h" + +//------------------------------------------------------------------------ +// SplashPath +//------------------------------------------------------------------------ + +// A path can be in three possible states: +// +// 1. no current point -- zero or more finished subpaths +// [curSubpath == length] +// +// 2. one point in subpath +// [curSubpath == length - 1] +// +// 3. open subpath with two or more points +// [curSubpath < length - 1] + +SplashPath::SplashPath() { + pts = NULL; + flags = NULL; + length = size = 0; + curSubpath = 0; +} + +SplashPath::SplashPath(SplashPath *path) { + length = path->length; + size = path->size; + pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint)); + flags = (Guchar *)gmallocn(size, sizeof(Guchar)); + memcpy(pts, path->pts, length * sizeof(SplashPathPoint)); + memcpy(flags, path->flags, length * sizeof(Guchar)); + curSubpath = path->curSubpath; +} + +SplashPath::~SplashPath() { + gfree(pts); + gfree(flags); +} + +// Add space for more points. +void SplashPath::grow(int nPts) { + if (length + nPts > size) { + if (size == 0) { + size = 32; + } + while (size < length + nPts) { + size *= 2; + } + pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint)); + flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); + } +} + +void SplashPath::append(SplashPath *path) { + int i; + + curSubpath = length + path->curSubpath; + grow(path->length); + for (i = 0; i < path->length; ++i) { + pts[length] = path->pts[i]; + flags[length] = path->flags[i]; + ++length; + } +} + +SplashError SplashPath::moveTo(SplashCoord x, SplashCoord y) { + if (onePointSubpath()) { + return splashErrBogusPath; + } + grow(1); + pts[length].x = x; + pts[length].y = y; + flags[length] = splashPathFirst | splashPathLast; + curSubpath = length++; + return splashOk; +} + +SplashError SplashPath::lineTo(SplashCoord x, SplashCoord y) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= ~splashPathLast; + grow(1); + pts[length].x = x; + pts[length].y = y; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= ~splashPathLast; + grow(3); + pts[length].x = x1; + pts[length].y = y1; + flags[length] = splashPathCurve; + ++length; + pts[length].x = x2; + pts[length].y = y2; + flags[length] = splashPathCurve; + ++length; + pts[length].x = x3; + pts[length].y = y3; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::arcCWTo(SplashCoord x1, SplashCoord y1, + SplashCoord xc, SplashCoord yc) { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + flags[length-1] &= ~splashPathLast; + grow(2); + pts[length].x = xc; + pts[length].y = yc; + flags[length] = splashPathArcCW; + ++length; + pts[length].x = x1; + pts[length].y = y1; + flags[length] = splashPathLast; + ++length; + return splashOk; +} + +SplashError SplashPath::close() { + if (noCurrentPoint()) { + return splashErrNoCurPt; + } + if (curSubpath == length - 1 || + pts[length - 1].x != pts[curSubpath].x || + pts[length - 1].y != pts[curSubpath].y) { + lineTo(pts[curSubpath].x, pts[curSubpath].y); + } + flags[curSubpath] |= splashPathClosed; + flags[length - 1] |= splashPathClosed; + curSubpath = length; + return splashOk; +} + +void SplashPath::offset(SplashCoord dx, SplashCoord dy) { + int i; + + for (i = 0; i < length; ++i) { + pts[i].x += dx; + pts[i].y += dy; + } +} + +GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) { + if (noCurrentPoint()) { + return gFalse; + } + *x = pts[length - 1].x; + *y = pts[length - 1].y; + return gTrue; +} diff --git a/pdftops/SplashPath.h b/pdftops/SplashPath.h new file mode 100644 index 000000000..0e6fffbb7 --- /dev/null +++ b/pdftops/SplashPath.h @@ -0,0 +1,112 @@ +//======================================================================== +// +// SplashPath.h +// +//======================================================================== + +#ifndef SPLASHPATH_H +#define SPLASHPATH_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashPathPoint +//------------------------------------------------------------------------ + +struct SplashPathPoint { + SplashCoord x, y; +}; + +//------------------------------------------------------------------------ +// SplashPath.flags +//------------------------------------------------------------------------ + +// first point on each subpath sets this flag +#define splashPathFirst 0x01 + +// last point on each subpath sets this flag +#define splashPathLast 0x02 + +// if the subpath is closed, its first and last points must be +// identical, and must set this flag +#define splashPathClosed 0x04 + +// curve control points set this flag +#define splashPathCurve 0x08 + +// clockwise arc center points set this flag +#define splashPathArcCW 0x10 + +//------------------------------------------------------------------------ +// SplashPath +//------------------------------------------------------------------------ + +class SplashPath { +public: + + // Create an empty path. + SplashPath(); + + // Copy a path. + SplashPath *copy() { return new SplashPath(this); } + + ~SplashPath(); + + // Append to . + void append(SplashPath *path); + + // Start a new subpath. + SplashError moveTo(SplashCoord x, SplashCoord y); + + // Add a line segment to the last subpath. + SplashError lineTo(SplashCoord x, SplashCoord y); + + // Add a third-order (cubic) Bezier curve segment to the last + // subpath. + SplashError curveTo(SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3); + + // Add a clockwise circular arc with center (xc, yc) and endpoint + // (x1, y1). + SplashError arcCWTo(SplashCoord x1, SplashCoord y1, + SplashCoord xc, SplashCoord yc); + + // Close the last subpath, adding a line segment if necessary. + SplashError close(); + + // Add (, ) to every point on this path. + void offset(SplashCoord dx, SplashCoord dy); + + // Get the points on the path. + int getLength() { return length; } + void getPoint(int i, double *x, double *y, Guchar *f) + { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; } + + // Get the current point. + GBool getCurPt(SplashCoord *x, SplashCoord *y); + +private: + + SplashPath(SplashPath *path); + void grow(int nPts); + GBool noCurrentPoint() { return curSubpath == length; } + GBool onePointSubpath() { return curSubpath == length - 1; } + GBool openSubpath() { return curSubpath < length - 1; } + + SplashPathPoint *pts; // array of points + Guchar *flags; // array of flags + int length, size; // length/size of the pts and flags arrays + int curSubpath; // index of first point in last subpath + + friend class SplashXPath; + friend class Splash; +}; + +#endif diff --git a/pdftops/SplashPattern.cxx b/pdftops/SplashPattern.cxx new file mode 100644 index 000000000..38f399433 --- /dev/null +++ b/pdftops/SplashPattern.cxx @@ -0,0 +1,68 @@ +//======================================================================== +// +// SplashPattern.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include "SplashMath.h" +#include "SplashScreen.h" +#include "SplashPattern.h" + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +SplashPattern::SplashPattern() { +} + +SplashPattern::~SplashPattern() { +} + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) { + splashColorCopy(color, colorA); +} + +SplashSolidColor::~SplashSolidColor() { +} + +void SplashSolidColor::getColor(int x, int y, SplashColorPtr c) { + splashColorCopy(c, color); +} + +//------------------------------------------------------------------------ +// SplashHalftone +//------------------------------------------------------------------------ + +SplashHalftone::SplashHalftone(SplashColorPtr color0A, SplashColorPtr color1A, + SplashScreen *screenA, SplashCoord valueA) { + splashColorCopy(color0, color0A); + splashColorCopy(color1, color1A); + screen = screenA; + value = valueA; +} + +SplashPattern *SplashHalftone::copy() { + return new SplashHalftone(color0, color1, screen->copy(), value); +} + +SplashHalftone::~SplashHalftone() { + delete screen; +} + +void SplashHalftone::getColor(int x, int y, SplashColorPtr c) { + splashColorCopy(c, screen->test(x, y, value) ? color1 : color0); +} + +GBool SplashHalftone::isStatic() { + return screen->isStatic(value); +} diff --git a/pdftops/SplashPattern.h b/pdftops/SplashPattern.h new file mode 100644 index 000000000..1f43986e2 --- /dev/null +++ b/pdftops/SplashPattern.h @@ -0,0 +1,90 @@ +//======================================================================== +// +// SplashPattern.h +// +//======================================================================== + +#ifndef SPLASHPATTERN_H +#define SPLASHPATTERN_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashScreen; + +//------------------------------------------------------------------------ +// SplashPattern +//------------------------------------------------------------------------ + +class SplashPattern { +public: + + SplashPattern(); + + virtual SplashPattern *copy() = 0; + + virtual ~SplashPattern(); + + // Return the color value for a specific pixel. + virtual void getColor(int x, int y, SplashColorPtr c) = 0; + + // Returns true if this pattern object will return the same color + // value for all pixels. + virtual GBool isStatic() = 0; + +private: +}; + +//------------------------------------------------------------------------ +// SplashSolidColor +//------------------------------------------------------------------------ + +class SplashSolidColor: public SplashPattern { +public: + + SplashSolidColor(SplashColorPtr colorA); + + virtual SplashPattern *copy() { return new SplashSolidColor(color); } + + virtual ~SplashSolidColor(); + + virtual void getColor(int x, int y, SplashColorPtr c); + + virtual GBool isStatic() { return gTrue; } + +private: + + SplashColor color; +}; + +//------------------------------------------------------------------------ +// SplashHalftone +//------------------------------------------------------------------------ + +class SplashHalftone: public SplashPattern { +public: + + SplashHalftone(SplashColorPtr color0A, SplashColorPtr color1A, + SplashScreen *screenA, SplashCoord valueA); + + virtual SplashPattern *copy(); + + virtual ~SplashHalftone(); + + virtual void getColor(int x, int y, SplashColorPtr c); + + virtual GBool isStatic(); + +private: + + SplashColor color0, color1; + SplashScreen *screen; + SplashCoord value; +}; + +#endif diff --git a/pdftops/SplashScreen.cxx b/pdftops/SplashScreen.cxx new file mode 100644 index 000000000..ca9804de8 --- /dev/null +++ b/pdftops/SplashScreen.cxx @@ -0,0 +1,141 @@ +//======================================================================== +// +// SplashScreen.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashScreen.h" + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +// This generates a 45 degree screen using a circular dot spot +// function. DPI = resolution / ((size / 2) * sqrt(2)). +// Gamma correction (gamma = 1 / 1.33) is also computed here. +SplashScreen::SplashScreen(int sizeA) { + SplashCoord *dist; + SplashCoord u, v, d, val; + int size2, x, y, x1, y1, i; + + size2 = sizeA >> 1; + if (size2 < 1) { + size2 = 1; + } + size = size2 << 1; + + // initialize the threshold matrix + mat = (SplashCoord *)gmallocn(size * size, sizeof(SplashCoord)); + for (y = 0; y < size; ++y) { + for (x = 0; x < size; ++x) { + mat[y * size + x] = -1; + } + } + + // build the distance matrix + dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord)); + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x + y < size2 - 1) { + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - 0; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; + } + dist[y * size2 + x] = u*u + v*v; + } + } + for (y = 0; y < size2; ++y) { + for (x = 0; x < size2; ++x) { + if (x < y) { + u = (SplashCoord)x + 0.5 - 0; + v = (SplashCoord)y + 0.5 - (SplashCoord)size2; + } else { + u = (SplashCoord)x + 0.5 - (SplashCoord)size2; + v = (SplashCoord)y + 0.5 - 0; + } + dist[(size2 + y) * size2 + x] = u*u + v*v; + } + } + + // build the threshold matrix + minVal = 1; + maxVal = 0; + x1 = y1 = 0; // make gcc happy + for (i = 1; i <= size * size2; ++i) { + d = size * size2; + for (y = 0; y < size; ++y) { + for (x = 0; x < size2; ++x) { + if (mat[y * size + x] < 0 && + dist[y * size2 + x] < d) { + x1 = x; + y1 = y; + d = dist[y1 * size2 + x1]; + } + } + } + u = (SplashCoord)1 - (SplashCoord)i / (SplashCoord)(size * size2 + 1); + val = splashPow(u, 1.33); + if (val < minVal) { + minVal = val; + } + if (val > maxVal) { + maxVal = val; + } + mat[y1 * size + x1] = val; + if (y1 < size2) { + mat[(y1 + size2) * size + x1 + size2] = val; + } else { + mat[(y1 - size2) * size + x1 + size2] = val; + } + } + + gfree(dist); +} + +SplashScreen::SplashScreen(SplashScreen *screen) { + int n; + + size = screen->size; + n = size * size * sizeof(SplashCoord); + mat = (SplashCoord *)gmalloc(n); + memcpy(mat, screen->mat, n); + minVal = screen->minVal; + maxVal = screen->maxVal; +} + +SplashScreen::~SplashScreen() { + gfree(mat); +} + +int SplashScreen::test(int x, int y, SplashCoord value) { + int xx, yy; + + if (value < minVal) { + return 0; + } + if (value >= maxVal) { + return 1; + } + if ((xx = x % size) < 0) { + xx = -xx; + } + if ((yy = y % size) < 0) { + yy = -yy; + } + return value < mat[yy * size + xx] ? 0 : 1; +} + +GBool SplashScreen::isStatic(SplashCoord value) { + return value < minVal || value >= maxVal; +} diff --git a/pdftops/SplashScreen.h b/pdftops/SplashScreen.h new file mode 100644 index 000000000..d598e2eea --- /dev/null +++ b/pdftops/SplashScreen.h @@ -0,0 +1,50 @@ +//======================================================================== +// +// SplashScreen.h +// +//======================================================================== + +#ifndef SPLASHSCREEN_H +#define SPLASHSCREEN_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +//------------------------------------------------------------------------ +// SplashScreen +//------------------------------------------------------------------------ + +class SplashScreen { +public: + + SplashScreen(int sizeA); + SplashScreen(SplashScreen *screen); + ~SplashScreen(); + + SplashScreen *copy() { return new SplashScreen(this); } + + // Return the computed pixel value (0=black, 1=white) for the gray + // level at (, ). + int test(int x, int y, SplashCoord value); + + // Returns true if value is above the white threshold or below the + // black threshold, i.e., if the corresponding halftone will be + // solid white or black. + GBool isStatic(SplashCoord value); + +private: + + SplashCoord *mat; // threshold matrix + int size; // size of the threshold matrix + SplashCoord minVal; // any pixel value below minVal generates + // solid black + SplashCoord maxVal; // any pixel value above maxVal generates + // solid white +}; + +#endif diff --git a/pdftops/SplashState.cxx b/pdftops/SplashState.cxx new file mode 100644 index 000000000..410ad27d8 --- /dev/null +++ b/pdftops/SplashState.cxx @@ -0,0 +1,110 @@ +//======================================================================== +// +// SplashState.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashPattern.h" +#include "SplashScreen.h" +#include "SplashClip.h" +#include "SplashState.h" + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +// number of components in each color mode +int splashColorModeNComps[] = { + 1, 1, 2, 3, 3, 4, 4 +}; + +SplashState::SplashState(int width, int height) { + SplashColor color; + + memset(&color, 0, sizeof(SplashColor)); + strokePattern = new SplashSolidColor(color); + fillPattern = new SplashSolidColor(color); + screen = new SplashScreen(10); + blendFunc = NULL; + strokeAlpha = 1; + fillAlpha = 1; + lineWidth = 0; + lineCap = splashLineCapButt; + lineJoin = splashLineJoinMiter; + miterLimit = 10; + flatness = 1; + lineDash = NULL; + lineDashLength = 0; + lineDashPhase = 0; + clip = new SplashClip(0, 0, width - 1, height - 1); + next = NULL; +} + +SplashState::SplashState(SplashState *state) { + strokePattern = state->strokePattern->copy(); + fillPattern = state->fillPattern->copy(); + screen = state->screen->copy(); + blendFunc = state->blendFunc; + strokeAlpha = state->strokeAlpha; + fillAlpha = state->fillAlpha; + lineWidth = state->lineWidth; + lineCap = state->lineCap; + lineJoin = state->lineJoin; + miterLimit = state->miterLimit; + flatness = state->flatness; + if (state->lineDash) { + lineDashLength = state->lineDashLength; + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); + memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + lineDashLength = 0; + } + lineDashPhase = state->lineDashPhase; + clip = state->clip->copy(); + next = NULL; +} + +SplashState::~SplashState() { + delete strokePattern; + delete fillPattern; + delete screen; + gfree(lineDash); + delete clip; +} + +void SplashState::setStrokePattern(SplashPattern *strokePatternA) { + delete strokePattern; + strokePattern = strokePatternA; +} + +void SplashState::setFillPattern(SplashPattern *fillPatternA) { + delete fillPattern; + fillPattern = fillPatternA; +} + +void SplashState::setScreen(SplashScreen *screenA) { + delete screen; + screen = screenA; +} + +void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA, + SplashCoord lineDashPhaseA) { + gfree(lineDash); + lineDashLength = lineDashLengthA; + if (lineDashLength > 0) { + lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); + memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord)); + } else { + lineDash = NULL; + } + lineDashPhase = lineDashPhaseA; +} diff --git a/pdftops/SplashState.h b/pdftops/SplashState.h new file mode 100644 index 000000000..5b886839b --- /dev/null +++ b/pdftops/SplashState.h @@ -0,0 +1,91 @@ +//======================================================================== +// +// SplashState.h +// +//======================================================================== + +#ifndef SPLASHSTATE_H +#define SPLASHSTATE_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPattern; +class SplashScreen; +class SplashClip; + +//------------------------------------------------------------------------ +// line cap values +//------------------------------------------------------------------------ + +#define splashLineCapButt 0 +#define splashLineCapRound 1 +#define splashLineCapProjecting 2 + +//------------------------------------------------------------------------ +// line join values +//------------------------------------------------------------------------ + +#define splashLineJoinMiter 0 +#define splashLineJoinRound 1 +#define splashLineJoinBevel 2 + +//------------------------------------------------------------------------ +// SplashState +//------------------------------------------------------------------------ + +class SplashState { +public: + + // Create a new state object, initialized with default settings. + SplashState(int width, int height); + + // Copy a state object. + SplashState *copy() { return new SplashState(this); } + + ~SplashState(); + + // Set the stroke pattern. This does not copy . + void setStrokePattern(SplashPattern *strokePatternA); + + // Set the fill pattern. This does not copy . + void setFillPattern(SplashPattern *fillPatternA); + + // Set the screen. This does not copy . + void setScreen(SplashScreen *screenA); + + // Set the line dash pattern. This copies the array. + void setLineDash(SplashCoord *lineDashA, int lineDashLengthA, + SplashCoord lineDashPhaseA); + +private: + + SplashState(SplashState *state); + + SplashPattern *strokePattern; + SplashPattern *fillPattern; + SplashScreen *screen; + SplashBlendFunc blendFunc; + SplashCoord strokeAlpha; + SplashCoord fillAlpha; + SplashCoord lineWidth; + int lineCap; + int lineJoin; + SplashCoord miterLimit; + SplashCoord flatness; + SplashCoord *lineDash; + int lineDashLength; + SplashCoord lineDashPhase; + SplashClip *clip; + + SplashState *next; // used by Splash class + + friend class Splash; +}; + +#endif diff --git a/pdftops/SplashT1Font.cxx b/pdftops/SplashT1Font.cxx new file mode 100644 index 000000000..10ef116d4 --- /dev/null +++ b/pdftops/SplashT1Font.cxx @@ -0,0 +1,264 @@ +//======================================================================== +// +// SplashT1Font.cc +// +//======================================================================== + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashGlyphBitmap.h" +#include "SplashPath.h" +#include "SplashT1FontEngine.h" +#include "SplashT1FontFile.h" +#include "SplashT1Font.h" + +//------------------------------------------------------------------------ + +static Guchar bitReverse[256] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +//------------------------------------------------------------------------ +// SplashT1Font +//------------------------------------------------------------------------ + +SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA): + SplashFont(fontFileA, matA, ((SplashT1FontFile *)fontFileA)->engine->aa) +{ + T1_TMATRIX matrix; + BBox bbox; + SplashCoord bbx0, bby0, bbx1, bby1; + int x, y; + + t1libID = T1_CopyFont(fontFileA->t1libID); + + // compute font size + size = (float)splashSqrt(mat[2]*mat[2] + mat[3]*mat[3]); + + // transform the four corners of the font bounding box -- the min + // and max values form the bounding box of the transformed font + bbox = T1_GetFontBBox(t1libID); + bbx0 = 0.001 * bbox.llx; + bby0 = 0.001 * bbox.lly; + bbx1 = 0.001 * bbox.urx; + bby1 = 0.001 * bbox.ury; + // some fonts are completely broken, so we fake it (with values + // large enough that most glyphs should fit) + if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) { + bbx0 = bby0 = -0.5; + bbx1 = bby1 = 1.5; + } + x = (int)(mat[0] * bbx0 + mat[2] * bby0); + xMin = xMax = x; + y = (int)(mat[1] * bbx0 + mat[3] * bby0); + yMin = yMax = y; + x = (int)(mat[0] * bbx0 + mat[2] * bby1); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx0 + mat[3] * bby1); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * bbx1 + mat[2] * bby0); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx1 + mat[3] * bby0); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + x = (int)(mat[0] * bbx1 + mat[2] * bby1); + if (x < xMin) { + xMin = x; + } else if (x > xMax) { + xMax = x; + } + y = (int)(mat[1] * bbx1 + mat[3] * bby1); + if (y < yMin) { + yMin = y; + } else if (y > yMax) { + yMax = y; + } + // This is a kludge: some buggy PDF generators embed fonts with + // zero bounding boxes. + if (xMax == xMin) { + xMin = 0; + xMax = (int)size; + } + if (yMax == yMin) { + yMin = 0; + yMax = (int)(1.2 * size); + } + // Another kludge: an unusually large xMin or yMin coordinate is + // probably wrong. + if (xMin > 0) { + xMin = 0; + } + if (yMin > 0) { + yMin = 0; + } + // Another kludge: t1lib doesn't correctly handle fonts with + // real (non-integer) bounding box coordinates. + if (xMax - xMin > 5000) { + xMin = 0; + xMax = (int)size; + } + if (yMax - yMin > 5000) { + yMin = 0; + yMax = (int)(1.2 * size); + } + + // transform the font + matrix.cxx = (double)mat[0] / size; + matrix.cxy = (double)mat[1] / size; + matrix.cyx = (double)mat[2] / size; + matrix.cyy = (double)mat[3] / size; + T1_TransformFont(t1libID, &matrix); +} + +SplashT1Font::~SplashT1Font() { + T1_DeleteFont(t1libID); +} + +GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + return SplashFont::getGlyph(c, 0, 0, bitmap); +} + +GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap) { + GLYPH *glyph; + int n, i; + + if (aa) { + glyph = T1_AASetChar(t1libID, c, size, NULL); + } else { + glyph = T1_SetChar(t1libID, c, size, NULL); + } + if (!glyph) { + return gFalse; + } + + bitmap->x = -glyph->metrics.leftSideBearing; + bitmap->y = glyph->metrics.ascent; + bitmap->w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing; + bitmap->h = glyph->metrics.ascent - glyph->metrics.descent; + bitmap->aa = aa; + if (aa) { + bitmap->data = (Guchar *)glyph->bits; + bitmap->freeData = gFalse; + } else { + n = bitmap->h * ((bitmap->w + 7) >> 3); + bitmap->data = (Guchar *)gmalloc(n); + for (i = 0; i < n; ++i) { + bitmap->data[i] = bitReverse[glyph->bits[i] & 0xff]; + } + bitmap->freeData = gTrue; + } + + return gTrue; +} + +SplashPath *SplashT1Font::getGlyphPath(int c) { + SplashPath *path; + T1_OUTLINE *outline; + T1_PATHSEGMENT *seg; + T1_BEZIERSEGMENT *bez; + SplashCoord x, y, x1, y1; + GBool needClose; + + path = new SplashPath(); + if (!(outline = T1_GetCharOutline(t1libID, c, size, NULL))) { + return path; + } + x = 0; + y = 0; + needClose = gFalse; + for (seg = outline; seg; seg = seg->link) { + switch (seg->type) { + case T1_PATHTYPE_MOVE: + if (needClose) { + path->close(); + needClose = gFalse; + } + x += seg->dest.x / 65536.0; + y += seg->dest.y / 65536.0; + path->moveTo(x, y); + break; + case T1_PATHTYPE_LINE: + x += seg->dest.x / 65536.0; + y += seg->dest.y / 65536.0; + path->lineTo(x, y); + needClose = gTrue; + break; + case T1_PATHTYPE_BEZIER: + bez = (T1_BEZIERSEGMENT *)seg; + x1 = x + bez->dest.x / 65536.0; + y1 = y + bez->dest.y / 65536.0; + path->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0, + x + bez->C.x / 65536.0, y + bez->C.y / 65536.0, + x1, y1); + x = x1; + y = y1; + needClose = gTrue; + break; + } + } + if (needClose) { + path->close(); + } + T1_FreeOutline(outline); + return path; +} + +#endif // HAVE_T1LIB_H diff --git a/pdftops/SplashT1Font.h b/pdftops/SplashT1Font.h new file mode 100644 index 000000000..17dc858d2 --- /dev/null +++ b/pdftops/SplashT1Font.h @@ -0,0 +1,53 @@ +//======================================================================== +// +// SplashT1Font.h +// +//======================================================================== + +#ifndef SPLASHT1FONT_H +#define SPLASHT1FONT_H + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashFont.h" + +class SplashT1FontFile; + +//------------------------------------------------------------------------ +// SplashT1Font +//------------------------------------------------------------------------ + +class SplashT1Font: public SplashFont { +public: + + SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA); + + virtual ~SplashT1Font(); + + // Munge xFrac and yFrac before calling SplashFont::getGlyph. + virtual GBool getGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // Rasterize a glyph. The and values are the same + // as described for getGlyph. + virtual GBool makeGlyph(int c, int xFrac, int yFrac, + SplashGlyphBitmap *bitmap); + + // Return the path for a glyph. + virtual SplashPath *getGlyphPath(int c); + +private: + + int t1libID; // t1lib font ID + float size; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/pdftops/SplashT1FontEngine.cxx b/pdftops/SplashT1FontEngine.cxx new file mode 100644 index 000000000..b88851fab --- /dev/null +++ b/pdftops/SplashT1FontEngine.cxx @@ -0,0 +1,124 @@ +//======================================================================== +// +// SplashT1FontEngine.cc +// +//======================================================================== + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#ifndef WIN32 +# include +#endif +#include +#include "GString.h" +#include "gfile.h" +#include "FoFiType1C.h" +#include "SplashT1FontFile.h" +#include "SplashT1FontEngine.h" + +#ifdef VMS +#if (__VMS_VER < 70000000) +extern "C" int unlink(char *filename); +#endif +#endif + +//------------------------------------------------------------------------ + +int SplashT1FontEngine::t1libInitCount = 0; + +//------------------------------------------------------------------------ + +static void fileWrite(void *stream, char *data, int len) { + fwrite(data, 1, len, (FILE *)stream); +} + +//------------------------------------------------------------------------ +// SplashT1FontEngine +//------------------------------------------------------------------------ + +SplashT1FontEngine::SplashT1FontEngine(GBool aaA) { + aa = aaA; +} + +SplashT1FontEngine *SplashT1FontEngine::init(GBool aaA) { + // grayVals[i] = round(i * 255 / 16) + static unsigned long grayVals[17] = { + 0, 16, 32, 48, 64, 80, 96, 112, 128, 143, 159, 175, 191, 207, 223, 239, 255 + }; + + //~ for multithreading: need a mutex here + if (t1libInitCount == 0) { + T1_SetBitmapPad(8); + if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE | + T1_NO_AFM)) { + return NULL; + } + if (aaA) { + T1_AASetBitsPerPixel(8); + T1_AASetLevel(T1_AA_HIGH); + T1_AAHSetGrayValues(grayVals); + } else { + T1_AANSetGrayValues(0, 1); + } + } + ++t1libInitCount; + + return new SplashT1FontEngine(aaA); +} + +SplashT1FontEngine::~SplashT1FontEngine() { + //~ for multithreading: need a mutex here + if (--t1libInitCount == 0) { + T1_CloseLib(); + } +} + +SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + return SplashT1FontFile::loadType1Font(this, idA, fileName, deleteFile, enc); +} + +SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA, + char *fileName, + GBool deleteFile, + char **enc) { + FoFiType1C *ff; + GString *tmpFileName; + FILE *tmpFile; + SplashFontFile *ret; + + if (!(ff = FoFiType1C::load(fileName))) { + return NULL; + } + tmpFileName = NULL; + if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { + delete ff; + return NULL; + } + ff->convertToType1(NULL, gTrue, &fileWrite, tmpFile); + delete ff; + fclose(tmpFile); + ret = SplashT1FontFile::loadType1Font(this, idA, tmpFileName->getCString(), + gTrue, enc); + if (ret) { + if (deleteFile) { + unlink(fileName); + } + } else { + unlink(tmpFileName->getCString()); + } + delete tmpFileName; + return ret; +} + +#endif // HAVE_T1LIB_H diff --git a/pdftops/SplashT1FontEngine.h b/pdftops/SplashT1FontEngine.h new file mode 100644 index 000000000..139e17610 --- /dev/null +++ b/pdftops/SplashT1FontEngine.h @@ -0,0 +1,53 @@ +//======================================================================== +// +// SplashT1FontEngine.h +// +//======================================================================== + +#ifndef SPLASHT1FONTENGINE_H +#define SPLASHT1FONTENGINE_H + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" + +class SplashFontFile; +class SplashFontFileID; + +//------------------------------------------------------------------------ +// SplashT1FontEngine +//------------------------------------------------------------------------ + +class SplashT1FontEngine { +public: + + static SplashT1FontEngine *init(GBool aaA); + + ~SplashT1FontEngine(); + + // Load fonts. + SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, + GBool deleteFile, char **enc); + +private: + + SplashT1FontEngine(GBool aaA); + + static int t1libInitCount; + GBool aa; + + friend class SplashT1FontFile; + friend class SplashT1Font; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/pdftops/SplashT1FontFile.cxx b/pdftops/SplashT1FontFile.cxx new file mode 100644 index 000000000..5476b7fb8 --- /dev/null +++ b/pdftops/SplashT1FontFile.cxx @@ -0,0 +1,96 @@ +//======================================================================== +// +// SplashT1FontFile.cc +// +//======================================================================== + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashT1FontEngine.h" +#include "SplashT1Font.h" +#include "SplashT1FontFile.h" + +//------------------------------------------------------------------------ +// SplashT1FontFile +//------------------------------------------------------------------------ + +SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, + GBool deleteFileA, + char **encA) { + int t1libIDA; + char **encTmp; + char *encStrTmp; + int encStrSize; + char *encPtr; + int i; + + // load the font file + if ((t1libIDA = T1_AddFont(fileNameA)) < 0) { + return NULL; + } + T1_LoadFont(t1libIDA); + + // reencode it + encStrSize = 0; + for (i = 0; i < 256; ++i) { + if (encA[i]) { + encStrSize += strlen(encA[i]) + 1; + } + } + encTmp = (char **)gmallocn(257, sizeof(char *)); + encStrTmp = (char *)gmallocn(encStrSize, sizeof(char)); + encPtr = encStrTmp; + for (i = 0; i < 256; ++i) { + if (encA[i]) { + strcpy(encPtr, encA[i]); + encTmp[i] = encPtr; + encPtr += strlen(encPtr) + 1; + } else { + encTmp[i] = ".notdef"; + } + } + encTmp[256] = "custom"; + T1_ReencodeFont(t1libIDA, encTmp); + + return new SplashT1FontFile(engineA, idA, fileNameA, deleteFileA, + t1libIDA, encTmp, encStrTmp); +} + +SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + int t1libIDA, char **encA, char *encStrA): + SplashFontFile(idA, fileNameA, deleteFileA) +{ + engine = engineA; + t1libID = t1libIDA; + enc = encA; + encStr = encStrA; +} + +SplashT1FontFile::~SplashT1FontFile() { + gfree(encStr); + gfree(enc); + T1_DeleteFont(t1libID); +} + +SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat) { + SplashFont *font; + + font = new SplashT1Font(this, mat); + font->initCache(); + return font; +} + +#endif // HAVE_T1LIB_H diff --git a/pdftops/SplashT1FontFile.h b/pdftops/SplashT1FontFile.h new file mode 100644 index 000000000..d5e490277 --- /dev/null +++ b/pdftops/SplashT1FontFile.h @@ -0,0 +1,57 @@ +//======================================================================== +// +// SplashT1FontFile.h +// +//======================================================================== + +#ifndef SPLASHT1FONTFILE_H +#define SPLASHT1FONTFILE_H + +#include + +#if HAVE_T1LIB_H + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashFontFile.h" + +class SplashT1FontEngine; + +//------------------------------------------------------------------------ +// SplashT1FontFile +//------------------------------------------------------------------------ + +class SplashT1FontFile: public SplashFontFile { +public: + + static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + char **encA); + + virtual ~SplashT1FontFile(); + + // Create a new SplashT1Font, i.e., a scaled instance of this font + // file. + virtual SplashFont *makeFont(SplashCoord *mat); + +private: + + SplashT1FontFile(SplashT1FontEngine *engineA, + SplashFontFileID *idA, + char *fileNameA, GBool deleteFileA, + int t1libIDA, char **encA, char *encStrA); + + SplashT1FontEngine *engine; + int t1libID; // t1lib font ID + char **enc; + char *encStr; + + friend class SplashT1Font; +}; + +#endif // HAVE_T1LIB_H + +#endif diff --git a/pdftops/SplashTypes.h b/pdftops/SplashTypes.h new file mode 100644 index 000000000..8ebc91368 --- /dev/null +++ b/pdftops/SplashTypes.h @@ -0,0 +1,139 @@ +//======================================================================== +// +// SplashTypes.h +// +//======================================================================== + +#ifndef SPLASHTYPES_H +#define SPLASHTYPES_H + +#include +#include "gtypes.h" + +//------------------------------------------------------------------------ +// coordinates +//------------------------------------------------------------------------ + +#if USE_FIXEDPOINT +#include "FixedPoint.h" +typedef FixedPoint SplashCoord; +#else +typedef double SplashCoord; +#endif + +//------------------------------------------------------------------------ +// colors +//------------------------------------------------------------------------ + +enum SplashColorMode { + splashModeMono1, // 1 bit per component, 8 pixels per byte, + // MSbit is on the left + splashModeMono8, // 1 byte per component, 1 byte per pixel + splashModeAMono8, // 1 byte per component, 2 bytes per pixel: + // AMAM... + splashModeRGB8, // 1 byte per component, 3 bytes per pixel: + // RGBRGB... + splashModeBGR8, // 1 byte per component, 3 bytes per pixel: + // BGRBGR... + splashModeARGB8, // 1 byte per component, 4 bytes per pixel: + // ARGBARGB... + splashModeBGRA8 // 1 byte per component, 4 bytes per pixel: + // BGRABGRA... +#if SPLASH_CMYK + , + splashModeCMYK8, // 1 byte per component, 4 bytes per pixel: + // CMYKCMYK... + splashModeACMYK8 // 1 byte per component, 5 bytes per pixel: + // ACMYKACMYK +#endif +}; + +// number of components in each color mode +// (defined in SplashState.cc) +extern int splashColorModeNComps[]; + +// max number of components in any SplashColor +#if SPLASH_CMYK +# define splashMaxColorComps 5 +#else +# define splashMaxColorComps 4 +#endif + +typedef Guchar SplashColor[splashMaxColorComps]; +typedef Guchar *SplashColorPtr; + +// AMono8 +static inline Guchar splashAMono8A(SplashColorPtr am8) { return am8[0]; } +static inline Guchar splashAMono8M(SplashColorPtr am8) { return am8[1]; } + +// RGB8 +static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; } +static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; } +static inline Guchar splashRGB8B(SplashColorPtr rgb8) { return rgb8[2]; } + +// BGR8 +static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; } +static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; } +static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; } + +// ARGB8 +static inline Guchar splashARGB8A(SplashColorPtr argb8) { return argb8[0]; } +static inline Guchar splashARGB8R(SplashColorPtr argb8) { return argb8[1]; } +static inline Guchar splashARGB8G(SplashColorPtr argb8) { return argb8[2]; } +static inline Guchar splashARGB8B(SplashColorPtr argb8) { return argb8[3]; } + +// ARGB8 +static inline Guchar splashBGRA8A(SplashColorPtr bgra8) { return bgra8[3]; } +static inline Guchar splashBGRA8R(SplashColorPtr bgra8) { return bgra8[2]; } +static inline Guchar splashBGRA8G(SplashColorPtr bgra8) { return bgra8[1]; } +static inline Guchar splashBGRA8B(SplashColorPtr bgra8) { return bgra8[0]; } + +#if SPLASH_CMYK +// CMYK8 +static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } +static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } +static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } +static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } + +// ACMYK8 +static inline Guchar splashACMYK8A(SplashColorPtr acmyk8) { return acmyk8[0]; } +static inline Guchar splashACMYK8C(SplashColorPtr acmyk8) { return acmyk8[1]; } +static inline Guchar splashACMYK8M(SplashColorPtr acmyk8) { return acmyk8[2]; } +static inline Guchar splashACMYK8Y(SplashColorPtr acmyk8) { return acmyk8[3]; } +static inline Guchar splashACMYK8K(SplashColorPtr acmyk8) { return acmyk8[4]; } +#endif + +static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { + dest[0] = src[0]; + dest[1] = src[1]; + dest[2] = src[2]; + dest[3] = src[3]; +#if SPLASH_CMYK + dest[4] = src[4]; +#endif +} + +static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { + dest[0] ^= src[0]; + dest[1] ^= src[1]; + dest[2] ^= src[2]; + dest[3] ^= src[3]; +#if SPLASH_CMYK + dest[4] ^= src[4]; +#endif +} + +//------------------------------------------------------------------------ +// blend functions +//------------------------------------------------------------------------ + +typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest, + SplashColorPtr blend, SplashColorMode cm); + +//------------------------------------------------------------------------ +// error results +//------------------------------------------------------------------------ + +typedef int SplashError; + +#endif diff --git a/pdftops/SplashXPath.cxx b/pdftops/SplashXPath.cxx new file mode 100644 index 000000000..1dd02e2cb --- /dev/null +++ b/pdftops/SplashXPath.cxx @@ -0,0 +1,414 @@ +//======================================================================== +// +// SplashXPath.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashPath.h" +#include "SplashXPath.h" + +//------------------------------------------------------------------------ + +#define maxCurveSplits (1 << 10) + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +SplashXPath::SplashXPath() { + segs = NULL; + length = size = 0; +} + +SplashXPath::SplashXPath(SplashPath *path, SplashCoord flatness, + GBool closeSubpaths) { + SplashCoord xc, yc, dx, dy, r, x0, y0, x1, y1; + int quad0, quad1, quad; + int curSubpath, n, i, j; + + segs = NULL; + length = size = 0; + + i = 0; + curSubpath = 0; + while (i < path->length) { + + // first point in subpath - skip it + if (path->flags[i] & splashPathFirst) { + curSubpath = i; + ++i; + + } else { + + // curve segment + if (path->flags[i] & splashPathCurve) { + addCurve(path->pts[i-1].x, path->pts[i-1].y, + path->pts[i ].x, path->pts[i ].y, + path->pts[i+1].x, path->pts[i+1].y, + path->pts[i+2].x, path->pts[i+2].y, + flatness, + (path->flags[i-1] & splashPathFirst), + (path->flags[i+2] & splashPathLast), + !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i+2] & splashPathLast) && + !(path->flags[i+2] & splashPathClosed)); + i += 3; + + // clockwise circular arc + } else if (path->flags[i] & splashPathArcCW) { + xc = path->pts[i].x; + yc = path->pts[i].y; + dx = path->pts[i+1].x - xc; + dy = path->pts[i+1].y - yc; + r = splashSqrt(dx * dx + dy * dy); + if (path->pts[i-1].x < xc && path->pts[i-1].y <= yc) { + quad0 = 0; + } else if (path->pts[i-1].x >= xc && path->pts[i-1].y < yc) { + quad0 = 1; + } else if (path->pts[i-1].x > xc && path->pts[i-1].y >= yc) { + quad0 = 2; + } else { + quad0 = 3; + } + if (path->pts[i+1].x <= xc && path->pts[i+1].y < yc) { + quad1 = 0; + } else if (path->pts[i+1].x > xc && path->pts[i+1].y <= yc) { + quad1 = 1; + } else if (path->pts[i+1].x >= xc && path->pts[i+1].y > yc) { + quad1 = 2; + } else { + quad1 = 3; + } + n = 0; // make gcc happy + if (quad0 == quad1) { + switch (quad0) { + case 0: + case 1: n = path->pts[i-1].x < path->pts[i+1].x ? 0 : 4; break; + case 2: + case 3: n = path->pts[i-1].x > path->pts[i+1].x ? 0 : 4; break; + } + } else { + n = (quad1 - quad0) & 3; + } + x0 = path->pts[i-1].x; + y0 = path->pts[i-1].y; + x1 = y1 = 0; // make gcc happy + quad = quad0; + for (j = 0; j < n; ++j) { + switch (quad) { + case 0: x1 = xc; y1 = yc - r; break; + case 1: x1 = xc + r; y1 = yc; break; + case 2: x1 = xc; y1 = yc + r; break; + case 3: x1 = xc - r; y1 = yc; break; + } + addArc(x0, y0, x1, y1, + xc, yc, r, quad, flatness, + quad == quad0 && (path->flags[i-1] & splashPathFirst), + gFalse, + quad == quad0 && !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + gFalse); + x0 = x1; + y0 = y1; + quad = (quad + 1) & 3; + } + addArc(x0, y0, path->pts[i+1].x, path->pts[i+1].y, + xc, yc, r, quad, flatness, + quad == quad0 && (path->flags[i-1] & splashPathFirst), + (path->flags[i+1] & splashPathLast), + quad == quad0 && !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i+1] & splashPathLast) && + !(path->flags[i+1] & splashPathClosed)); + i += 2; + + // line segment + } else { + addSegment(path->pts[i-1].x, path->pts[i-1].y, + path->pts[i].x, path->pts[i].y, + path->flags[i-1] & splashPathFirst, + path->flags[i] & splashPathLast, + !closeSubpaths && + (path->flags[i-1] & splashPathFirst) && + !(path->flags[i-1] & splashPathClosed), + !closeSubpaths && + (path->flags[i] & splashPathLast) && + !(path->flags[i] & splashPathClosed)); + ++i; + } + + // close a subpath + if (closeSubpaths && + (path->flags[i-1] & splashPathLast) && + (path->pts[i-1].x != path->pts[curSubpath].x || + path->pts[i-1].y != path->pts[curSubpath]. y)) { + addSegment(path->pts[i-1].x, path->pts[i-1].y, + path->pts[curSubpath].x, path->pts[curSubpath].y, + gFalse, gTrue, gFalse, gFalse); + } + } + } +} + +SplashXPath::SplashXPath(SplashXPath *xPath) { + length = xPath->length; + size = xPath->size; + segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg)); + memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg)); +} + +SplashXPath::~SplashXPath() { + gfree(segs); +} + +// Add space for more segments +void SplashXPath::grow(int nSegs) { + if (length + nSegs > size) { + if (size == 0) { + size = 32; + } + while (size < length + nSegs) { + size *= 2; + } + segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg)); + } +} + +void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1) { + SplashCoord cx[maxCurveSplits + 1][3]; + SplashCoord cy[maxCurveSplits + 1][3]; + int cNext[maxCurveSplits + 1]; + SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; + SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; + SplashCoord dx, dy, mx, my, d1, d2, flatness2; + int p1, p2, p3; + + flatness2 = flatness * flatness; + + // initial segment + p1 = 0; + p2 = maxCurveSplits; + cx[p1][0] = x0; cy[p1][0] = y0; + cx[p1][1] = x1; cy[p1][1] = y1; + cx[p1][2] = x2; cy[p1][2] = y2; + cx[p2][0] = x3; cy[p2][0] = y3; + cNext[p1] = p2; + + while (p1 < maxCurveSplits) { + + // get the next segment + xl0 = cx[p1][0]; yl0 = cy[p1][0]; + xx1 = cx[p1][1]; yy1 = cy[p1][1]; + xx2 = cx[p1][2]; yy2 = cy[p1][2]; + p2 = cNext[p1]; + xr3 = cx[p2][0]; yr3 = cy[p2][0]; + + // compute the distances from the control points to the + // midpoint of the straight line (this is a bit of a hack, but + // it's much faster than computing the actual distances to the + // line) + mx = (xl0 + xr3) * 0.5; + my = (yl0 + yr3) * 0.5; + dx = xx1 - mx; + dy = yy1 - my; + d1 = dx*dx + dy*dy; + dx = xx2 - mx; + dy = yy2 - my; + d2 = dx*dx + dy*dy; + + // if the curve is flat enough, or no more subdivisions are + // allowed, add the straight line segment + if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { + addSegment(xl0, yl0, xr3, yr3, + p1 == 0 && first, + p2 == maxCurveSplits && last, + p1 == 0 && end0, + p2 == maxCurveSplits && end1); + p1 = p2; + + // otherwise, subdivide the curve + } else { + xl1 = (xl0 + xx1) * 0.5; + yl1 = (yl0 + yy1) * 0.5; + xh = (xx1 + xx2) * 0.5; + yh = (yy1 + yy2) * 0.5; + xl2 = (xl1 + xh) * 0.5; + yl2 = (yl1 + yh) * 0.5; + xr2 = (xx2 + xr3) * 0.5; + yr2 = (yy2 + yr3) * 0.5; + xr1 = (xh + xr2) * 0.5; + yr1 = (yh + yr2) * 0.5; + xr0 = (xl2 + xr1) * 0.5; + yr0 = (yl2 + yr1) * 0.5; + // add the new subdivision points + p3 = (p1 + p2) / 2; + cx[p1][1] = xl1; cy[p1][1] = yl1; + cx[p1][2] = xl2; cy[p1][2] = yl2; + cNext[p1] = p3; + cx[p3][0] = xr0; cy[p3][0] = yr0; + cx[p3][1] = xr1; cy[p3][1] = yr1; + cx[p3][2] = xr2; cy[p3][2] = yr2; + cNext[p3] = p2; + } + } +} + +void SplashXPath::addArc(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord xc, SplashCoord yc, + SplashCoord r, int quad, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1) { + SplashCoord px[maxCurveSplits + 1]; + SplashCoord py[maxCurveSplits + 1]; + int pNext[maxCurveSplits + 1]; + SplashCoord r2, flatness2; + SplashCoord xx0, yy0, xx1, yy1, xm, ym, t, dx, dy; + int p1, p2, p3; + + r2 = r * r; + flatness2 = flatness * flatness; + + // initial segment + p1 = 0; + p2 = maxCurveSplits; + px[p1] = x0; py[p1] = y0; + px[p2] = x1; py[p2] = y1; + pNext[p1] = p2; + + while (p1 < maxCurveSplits) { + + // get the next segment + xx0 = px[p1]; yy0 = py[p1]; + p2 = pNext[p1]; + xx1 = px[p2]; yy1 = py[p2]; + + // compute the arc midpoint + t = (xx0 - xc) * (xx1 - xc) - (yy0 - yc) * (yy1 - yc); + xm = splashSqrt((SplashCoord)0.5 * (r2 + t)); + ym = splashSqrt((SplashCoord)0.5 * (r2 - t)); + switch (quad) { + case 0: xm = xc - xm; ym = yc - ym; break; + case 1: xm = xc + xm; ym = yc - ym; break; + case 2: xm = xc + xm; ym = yc + ym; break; + case 3: xm = xc - xm; ym = yc + ym; break; + } + + // compute distance from midpoint of straight segment to midpoint + // of arc + dx = (SplashCoord)0.5 * (xx0 + xx1) - xm; + dy = (SplashCoord)0.5 * (yy0 + yy1) - ym; + + // if the arc is flat enough, or no more subdivisions are allowed, + // add the straight line segment + if (p2 - p1 == 1 || dx * dx + dy * dy <= flatness2) { + addSegment(xx0, yy0, xx1, yy1, + p1 == 0 && first, + p2 == maxCurveSplits && last, + p1 == 0 && end0, + p2 == maxCurveSplits && end1); + p1 = p2; + + // otherwise, subdivide the arc + } else { + p3 = (p1 + p2) / 2; + px[p3] = xm; + py[p3] = ym; + pNext[p1] = p3; + pNext[p3] = p2; + } + } +} + +void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool first, GBool last, GBool end0, GBool end1) { + grow(1); + segs[length].x0 = x0; + segs[length].y0 = y0; + segs[length].x1 = x1; + segs[length].y1 = y1; + segs[length].flags = 0; + if (first) { + segs[length].flags |= splashXPathFirst; + } + if (last) { + segs[length].flags |= splashXPathLast; + } + if (end0) { + segs[length].flags |= splashXPathEnd0; + } + if (end1) { + segs[length].flags |= splashXPathEnd1; + } + if (y1 == y0) { + segs[length].dxdy = segs[length].dydx = 0; + segs[length].flags |= splashXPathHoriz; + if (x1 == x0) { + segs[length].flags |= splashXPathVert; + } + } else if (x1 == x0) { + segs[length].dxdy = segs[length].dydx = 0; + segs[length].flags |= splashXPathVert; + } else { + segs[length].dxdy = (x1 - x0) / (y1 - y0); + segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; + } + if (y0 > y1) { + segs[length].flags |= splashXPathFlip; + } + ++length; +} + +static int cmpXPathSegs(const void *arg0, const void *arg1) { + SplashXPathSeg *seg0 = (SplashXPathSeg *)arg0; + SplashXPathSeg *seg1 = (SplashXPathSeg *)arg1; + SplashCoord x0, y0, x1, y1; + + if (seg0->flags & splashXPathFlip) { + x0 = seg0->x1; + y0 = seg0->y1; + } else { + x0 = seg0->x0; + y0 = seg0->y0; + } + if (seg1->flags & splashXPathFlip) { + x1 = seg1->x1; + y1 = seg1->y1; + } else { + x1 = seg1->x0; + y1 = seg1->y0; + } + if (y0 != y1) { + return (y0 > y1) ? 1 : -1; + } + if (x0 != x1) { + return (x0 > x1) ? 1 : -1; + } + return 0; +} + +void SplashXPath::sort() { + qsort(segs, length, sizeof(SplashXPathSeg), &cmpXPathSegs); +} diff --git a/pdftops/SplashXPath.h b/pdftops/SplashXPath.h new file mode 100644 index 000000000..910e3e024 --- /dev/null +++ b/pdftops/SplashXPath.h @@ -0,0 +1,92 @@ +//======================================================================== +// +// SplashXPath.h +// +//======================================================================== + +#ifndef SPLASHXPATH_H +#define SPLASHXPATH_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashPath; + +//------------------------------------------------------------------------ +// SplashXPathSeg +//------------------------------------------------------------------------ + +struct SplashXPathSeg { + SplashCoord x0, y0; // first endpoint + SplashCoord x1, y1; // second endpoint + SplashCoord dxdy; // slope: delta-x / delta-y + SplashCoord dydx; // slope: delta-y / delta-x + Guint flags; +}; + +#define splashXPathFirst 0x01 // first segment of a subpath +#define splashXPathLast 0x02 // last segment of a subpath +#define splashXPathEnd0 0x04 // first endpoint is end of an open subpath +#define splashXPathEnd1 0x08 // second endpoint is end of an open subpath +#define splashXPathHoriz 0x10 // segment is vertical (y0 == y1) + // (dxdy is undef) +#define splashXPathVert 0x20 // segment is horizontal (x0 == x1) + // (dydx is undef) +#define splashXPathFlip 0x40 // y0 > y1 + +//------------------------------------------------------------------------ +// SplashXPath +//------------------------------------------------------------------------ + +class SplashXPath { +public: + + // Expands (converts to segments) and flattens (converts curves to + // lines) . If is true, closes all open + // subpaths. + SplashXPath(SplashPath *path, SplashCoord flatness, + GBool closeSubpaths); + + // Copy an expanded path. + SplashXPath *copy() { return new SplashXPath(this); } + + ~SplashXPath(); + + // Sort by upper coordinate (lower y), in y-major order. + void sort(); + +private: + + SplashXPath(); + SplashXPath(SplashXPath *xPath); + void grow(int nSegs); + void addCurve(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord x2, SplashCoord y2, + SplashCoord x3, SplashCoord y3, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1); + void addArc(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + SplashCoord xc, SplashCoord yc, + SplashCoord r, int quad, + SplashCoord flatness, + GBool first, GBool last, GBool end0, GBool end1); + void addSegment(SplashCoord x0, SplashCoord y0, + SplashCoord x1, SplashCoord y1, + GBool first, GBool last, GBool end0, GBool end1); + + SplashXPathSeg *segs; + int length, size; // length and size of segs array + + friend class SplashXPathScanner; + friend class SplashClip; + friend class Splash; +}; + +#endif diff --git a/pdftops/SplashXPathScanner.cxx b/pdftops/SplashXPathScanner.cxx new file mode 100644 index 000000000..ea2ad871d --- /dev/null +++ b/pdftops/SplashXPathScanner.cxx @@ -0,0 +1,277 @@ +//======================================================================== +// +// SplashXPathScanner.cc +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include "gmem.h" +#include "SplashMath.h" +#include "SplashXPath.h" +#include "SplashXPathScanner.h" + +//------------------------------------------------------------------------ + +struct SplashIntersect { + int x0, x1; // intersection of segment with [y, y+1) + int count; // EO/NZWN counter increment +}; + +static int cmpIntersect(const void *p0, const void *p1) { + return ((SplashIntersect *)p0)->x0 - ((SplashIntersect *)p1)->x0; +} + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA) { + SplashXPathSeg *seg; + SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP; + int i; + + xPath = xPathA; + eo = eoA; + + // compute the bbox + if (xPath->length == 0) { + xMin = yMin = 1; + xMax = yMax = 0; + } else { + seg = &xPath->segs[0]; + if (seg->x0 <= seg->x1) { + xMinFP = seg->x0; + xMaxFP = seg->x1; + } else { + xMinFP = seg->x1; + xMaxFP = seg->x0; + } + if (seg->flags & splashXPathFlip) { + yMinFP = seg->y1; + yMaxFP = seg->y0; + } else { + yMinFP = seg->y0; + yMaxFP = seg->y1; + } + for (i = 1; i < xPath->length; ++i) { + seg = &xPath->segs[i]; + if (seg->x0 < xMinFP) { + xMinFP = seg->x0; + } else if (seg->x0 > xMaxFP) { + xMaxFP = seg->x0; + } + if (seg->x1 < xMinFP) { + xMinFP = seg->x1; + } else if (seg->x1 > xMaxFP) { + xMaxFP = seg->x1; + } + if (seg->flags & splashXPathFlip) { + if (seg->y0 > yMaxFP) { + yMaxFP = seg->y0; + } + } else { + if (seg->y1 > yMaxFP) { + yMaxFP = seg->y1; + } + } + } + xMin = splashFloor(xMinFP); + xMax = splashFloor(xMaxFP); + yMin = splashFloor(yMinFP); + yMax = splashFloor(yMaxFP); + } + + interY = yMin - 1; + xPathIdx = 0; + inter = NULL; + interLen = interSize = 0; +} + +SplashXPathScanner::~SplashXPathScanner() { + gfree(inter); +} + +void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { + if (interY != y) { + computeIntersections(y); + } + if (interLen > 0) { + *spanXMin = inter[0].x0; + *spanXMax = inter[interLen - 1].x1; + } else { + *spanXMin = xMax + 1; + *spanXMax = xMax; + } +} + +GBool SplashXPathScanner::test(int x, int y) { + int count, i; + + if (interY != y) { + computeIntersections(y); + } + count = 0; + for (i = 0; i < interLen && inter[i].x0 <= x; ++i) { + if (x <= inter[i].x1) { + return gTrue; + } + count += inter[i].count; + } + return eo ? (count & 1) : (count != 0); +} + +GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { + int count, xx1, i; + + if (interY != y) { + computeIntersections(y); + } + + count = 0; + for (i = 0; i < interLen && inter[i].x1 < x0; ++i) { + count += inter[i].count; + } + + // invariant: the subspan [x0,xx1] is inside the path + xx1 = x0 - 1; + while (xx1 < x1) { + if (i >= interLen) { + return gFalse; + } + if (inter[i].x0 > xx1 + 1 && + !(eo ? (count & 1) : (count != 0))) { + return gFalse; + } + if (inter[i].x1 > xx1) { + xx1 = inter[i].x1; + } + count += inter[i].count; + ++i; + } + + return gTrue; +} + +GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { + int xx0, xx1; + + if (interY != y) { + computeIntersections(y); + } + if (interIdx >= interLen) { + return gFalse; + } + xx0 = inter[interIdx].x0; + xx1 = inter[interIdx].x1; + interCount += inter[interIdx].count; + ++interIdx; + while (interIdx < interLen && + (inter[interIdx].x0 <= xx1 || + (eo ? (interCount & 1) : (interCount != 0)))) { + if (inter[interIdx].x1 > xx1) { + xx1 = inter[interIdx].x1; + } + interCount += inter[interIdx].count; + ++interIdx; + } + *x0 = xx0; + *x1 = xx1; + return gTrue; +} + +void SplashXPathScanner::computeIntersections(int y) { + SplashCoord ySegMin, ySegMax, xx0, xx1; + SplashXPathSeg *seg; + int i, j; + + // find the first segment that intersects [y, y+1) + i = (y >= interY) ? xPathIdx : 0; + while (i < xPath->length && + xPath->segs[i].y0 < y && xPath->segs[i].y1 < y) { + ++i; + } + xPathIdx = i; + + // find all of the segments that intersect [y, y+1) and create an + // Intersect element for each one + interLen = 0; + for (j = i; j < xPath->length; ++j) { + seg = &xPath->segs[j]; + if (seg->flags & splashXPathFlip) { + ySegMin = seg->y1; + ySegMax = seg->y0; + } else { + ySegMin = seg->y0; + ySegMax = seg->y1; + } + + // ensure that: ySegMin < y+1 + // y <= ySegMax + if (ySegMin >= y + 1) { + break; + } + if (ySegMax < y) { + continue; + } + + if (interLen == interSize) { + if (interSize == 0) { + interSize = 16; + } else { + interSize *= 2; + } + inter = (SplashIntersect *)greallocn(inter, interSize, + sizeof(SplashIntersect)); + } + + if (seg->flags & splashXPathHoriz) { + xx0 = seg->x0; + xx1 = seg->x1; + } else if (seg->flags & splashXPathVert) { + xx0 = xx1 = seg->x0; + } else { + if (ySegMin <= y) { + // intersection with top edge + xx0 = seg->x0 + ((SplashCoord)y - seg->y0) * seg->dxdy; + } else { + // x coord of segment endpoint with min y coord + xx0 = (seg->flags & splashXPathFlip) ? seg->x1 : seg->x0; + } + if (ySegMax >= y + 1) { + // intersection with bottom edge + xx1 = seg->x0 + ((SplashCoord)y + 1 - seg->y0) * seg->dxdy; + } else { + // x coord of segment endpoint with max y coord + xx1 = (seg->flags & splashXPathFlip) ? seg->x0 : seg->x1; + } + } + if (xx0 < xx1) { + inter[interLen].x0 = splashFloor(xx0); + inter[interLen].x1 = splashFloor(xx1); + } else { + inter[interLen].x0 = splashFloor(xx1); + inter[interLen].x1 = splashFloor(xx0); + } + if (ySegMin <= y && + (SplashCoord)y < ySegMax && + !(seg->flags & splashXPathHoriz)) { + inter[interLen].count = eo ? 1 + : (seg->flags & splashXPathFlip) ? 1 : -1; + } else { + inter[interLen].count = 0; + } + ++interLen; + } + + qsort(inter, interLen, sizeof(SplashIntersect), &cmpIntersect); + + interY = y; + interIdx = 0; + interCount = 0; +} diff --git a/pdftops/SplashXPathScanner.h b/pdftops/SplashXPathScanner.h new file mode 100644 index 000000000..6b65203d9 --- /dev/null +++ b/pdftops/SplashXPathScanner.h @@ -0,0 +1,74 @@ +//======================================================================== +// +// SplashXPathScanner.h +// +//======================================================================== + +#ifndef SPLASHXPATHSCANNER_H +#define SPLASHXPATHSCANNER_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "SplashTypes.h" + +class SplashXPath; +struct SplashIntersect; + +//------------------------------------------------------------------------ +// SplashXPathScanner +//------------------------------------------------------------------------ + +class SplashXPathScanner { +public: + + // Create a new SplashXPathScanner object. must be sorted. + SplashXPathScanner(SplashXPath *xPathA, GBool eoA); + + ~SplashXPathScanner(); + + // Return the path's bounding box. + void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) + { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } + + // Return the min/max x values for the span at . + void getSpanBounds(int y, int *spanXMin, int *spanXMax); + + // Returns true if (,) is inside the path. + GBool test(int x, int y); + + // Returns true if the entire span ([,], ) is inside the + // path. + GBool testSpan(int x0, int x1, int y); + + // Returns the next span inside the path at . If is + // different than the previous call to getNextSpan, this returns the + // first span at ; otherwise it returns the next span (relative + // to the previous call to getNextSpan). Returns false if there are + // no more spans at . + GBool getNextSpan(int y, int *x0, int *x1); + +private: + + void computeIntersections(int y); + + SplashXPath *xPath; + GBool eo; + int xMin, yMin, xMax, yMax; + + int interY; // current y value + int interIdx; // current index into - used by + // getNextSpan + int interCount; // current EO/NZWN counter - used by + // getNextSpan + int xPathIdx; // current index into - used by + // computeIntersections + SplashIntersect *inter; // intersections array for + int interLen; // number of intersections in + int interSize; // size of the array +}; + +#endif diff --git a/pdftops/Stream-CCITT.h b/pdftops/Stream-CCITT.h new file mode 100644 index 000000000..c4458fe71 --- /dev/null +++ b/pdftops/Stream-CCITT.h @@ -0,0 +1,459 @@ +//======================================================================== +// +// Stream-CCITT.h +// +// Tables for CCITT Fax decoding. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +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..492e7a9be --- /dev/null +++ b/pdftops/Stream.cxx @@ -0,0 +1,4572 @@ +//======================================================================== +// +// Stream.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include +#include "gmem.h" +#include "gfile.h" +#include "config.h" +#include "Error.h" +#include "Object.h" +#include "Lexer.h" +#include "Decrypt.h" +#include "GfxState.h" +#include "Stream.h" +#include "JBIG2Stream.h" +#include "JPXStream.h" +#include "Stream-CCITT.h" + +#ifdef __DJGPP__ +static GBool setDJSYSFLAGS = gFalse; +#endif + +#ifdef VMS +#ifdef __GNUC__ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#endif +#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(int psLevel, 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", ¶ms); + if (params.isNull()) { + params.free(); + dict->dictLookup("DP", ¶ms); + } + if (obj.isName()) { + str = makeFilter(obj.getName(), str, ¶ms); + } else if (obj.isArray()) { + for (i = 0; i < obj.arrayGetLength(); ++i) { + obj.arrayGet(i, &obj2); + if (params.isArray()) + params.arrayGet(i, ¶ms2); + else + params2.initNull(); + if (obj2.isName()) { + str = makeFilter(obj2.getName(), str, ¶ms2); + } 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 globals, 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 if (!strcmp(name, "JBIG2Decode")) { + if (params->isDict()) { + params->dictLookup("JBIG2Globals", &globals); + } + str = new JBIG2Stream(str, &globals); + globals.free(); + } else if (!strcmp(name, "JPXDecode")) { + str = new JPXStream(str); + } else { + error(getPos(), "Unknown filter '%s'", name); + str = new EOFStream(str); + } + return str; +} + +//------------------------------------------------------------------------ +// BaseStream +//------------------------------------------------------------------------ + +BaseStream::BaseStream(Object *dictA) { + dict = *dictA; + decrypt = NULL; +} + +BaseStream::~BaseStream() { + dict.free(); + if (decrypt) + delete decrypt; +} + +void BaseStream::doDecryption(Guchar *fileKey, int keyLength, + int objNum, int objGen) { + decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); +} + +//------------------------------------------------------------------------ +// FilterStream +//------------------------------------------------------------------------ + +FilterStream::FilterStream(Stream *strA) { + str = strA; +} + +FilterStream::~FilterStream() { +} + +void FilterStream::close() { + str->close(); +} + +void FilterStream::setPos(Guint pos, int dir) { + 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 *)gmallocn(imgLineSize, sizeof(Guchar)); + imgIdx = nVals; +} + +ImageStream::~ImageStream() { + gfree(imgLine); +} + +void ImageStream::reset() { + str->reset(); +} + +GBool ImageStream::getPixel(Guchar *pix) { + int i; + + if (imgIdx >= nVals) { + getLine(); + imgIdx = 0; + } + for (i = 0; i < nComps; ++i) { + pix[i] = imgLine[imgIdx++]; + } + return gTrue; +} + +Guchar *ImageStream::getLine() { + Gulong buf, bitMask; + int bits; + int c; + int i; + + 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; + } + } + return imgLine; +} + +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) { + int totalBits; + + str = strA; + predictor = predictorA; + width = widthA; + nComps = nCompsA; + nBits = nBitsA; + predLine = NULL; + ok = gFalse; + + nVals = width * nComps; + totalBits = nVals * nBits; + if (totalBits == 0 || + (totalBits / nBits) / nComps != width || + totalBits + 7 < 0) { + return; + } + pixBytes = (nComps * nBits + 7) >> 3; + rowBytes = ((totalBits + 7) >> 3) + pixBytes; + if (rowBytes < 0) { + return; + } + predLine = (Guchar *)gmalloc(rowBytes); + memset(predLine, 0, rowBytes); + predIdx = rowBytes; + + ok = gTrue; +} + +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[gfxColorMaxComps * 2 + 1]; + int left, up, upLeft, p, pa, pb, pc; + int c; + Gulong inBuf, outBuf, bitMask; + int inBits, outBits; + int i, j, k, kk; + + // get PNG optimum predictor number + if (predictor >= 10) { + if ((curPred = str->getRawChar()) == EOF) { + return gFalse; + } + curPred += 10; + } else { + curPred = predictor; + } + + // read the raw line, apply PNG (byte) predictor + memset(upLeftBuf, 0, pixBytes + 1); + for (i = pixBytes; i < rowBytes; ++i) { + for (j = pixBytes; j > 0; --j) { + upLeftBuf[j] = upLeftBuf[j-1]; + } + upLeftBuf[0] = predLine[i]; + if ((c = str->getRawChar()) == EOF) { + if (i > pixBytes) { + // this ought to return false, but some (broken) PDF files + // contain truncated image data, and Adobe apparently reads the + // last partial line + break; + } + return gFalse; + } + 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] = left + (Guchar)c; + else if (pb <= pc) + predLine[i] = up + (Guchar)c; + else + predLine[i] = upLeft + (Guchar)c; + break; + case 10: // PNG none + default: // no predictor or TIFF predictor + predLine[i] = (Guchar)c; + break; + } + } + + // apply TIFF (component) predictor + 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 { + memset(upLeftBuf, 0, nComps + 1); + bitMask = (1 << nBits) - 1; + inBuf = outBuf = 0; + inBits = outBits = 0; + j = k = pixBytes; + for (i = 0; i < width; ++i) { + for (kk = 0; kk < nComps; ++kk) { + if (inBits < nBits) { + inBuf = (inBuf << 8) | (predLine[j++] & 0xff); + inBits += 8; + } + upLeftBuf[kk] = (upLeftBuf[kk] + + (inBuf >> (inBits - nBits))) & bitMask; + inBits -= nBits; + outBuf = (outBuf << nBits) | upLeftBuf[kk]; + outBits += nBits; + if (outBits >= 8) { + predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); + outBits -= 8; + } + } + } + if (outBits > 0) { + predLine[k++] = (Guchar)((outBuf << (8 - outBits)) + + (inBuf & ((1 << (8 - outBits)) - 1))); + } + } + } + + // reset to start of line + predIdx = pixBytes; + + return gTrue; +} + +//------------------------------------------------------------------------ +// FileStream +//------------------------------------------------------------------------ + +FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA, + Guint lengthA, Object *dictA): + BaseStream(dictA) { + f = fA; + start = startA; + limited = limitedA; + length = lengthA; + bufPtr = bufEnd = buf; + bufPos = start; + savePos = 0; + saved = gFalse; +} + +FileStream::~FileStream() { + close(); +} + +Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, + Guint lengthA, Object *dictA) { + return new FileStream(f, startA, limitedA, lengthA, dictA); +} + +void FileStream::reset() { +#if HAVE_FSEEKO + savePos = (Guint)ftello(f); + fseeko(f, start, SEEK_SET); +#elif HAVE_FSEEK64 + savePos = (Guint)ftell64(f); + fseek64(f, start, SEEK_SET); +#else + savePos = (Guint)ftell(f); + fseek(f, start, SEEK_SET); +#endif + saved = gTrue; + bufPtr = bufEnd = buf; + bufPos = start; + if (decrypt) + decrypt->reset(); +} + +void FileStream::close() { + if (saved) { +#if HAVE_FSEEKO + fseeko(f, savePos, SEEK_SET); +#elif HAVE_FSEEK64 + fseek64(f, savePos, SEEK_SET); +#else + fseek(f, savePos, SEEK_SET); +#endif + saved = gFalse; + } +} + +GBool FileStream::fillBuf() { + int n; + char *p; + + bufPos += bufEnd - buf; + bufPtr = bufEnd = buf; + if (limited && bufPos >= start + length) { + return gFalse; + } + if (limited && 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; + } + if (decrypt) { + for (p = buf; p < bufEnd; ++p) { + *p = (char)decrypt->decryptByte((Guchar)*p); + } + } + return gTrue; +} + +void FileStream::setPos(Guint pos, int dir) { + Guint size; + + if (dir >= 0) { +#if HAVE_FSEEKO + fseeko(f, pos, SEEK_SET); +#elif HAVE_FSEEK64 + fseek64(f, pos, SEEK_SET); +#else + fseek(f, pos, SEEK_SET); +#endif + bufPos = pos; + } else { +#if HAVE_FSEEKO + fseeko(f, 0, SEEK_END); + size = (Guint)ftello(f); +#elif HAVE_FSEEK64 + fseek64(f, 0, SEEK_END); + size = (Guint)ftell64(f); +#else + fseek(f, 0, SEEK_END); + size = (Guint)ftell(f); +#endif + if (pos > size) + pos = (Guint)size; +#ifdef __CYGWIN32__ + //~ work around a bug in cygwin's implementation of fseek + rewind(f); +#endif +#if HAVE_FSEEKO + fseeko(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftello(f); +#elif HAVE_FSEEK64 + fseek64(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftell64(f); +#else + fseek(f, -(int)pos, SEEK_END); + bufPos = (Guint)ftell(f); +#endif + } + bufPtr = bufEnd = buf; +} + +void FileStream::moveStart(int delta) { + start += delta; + bufPtr = bufEnd = buf; + bufPos = start; +} + +//------------------------------------------------------------------------ +// MemStream +//------------------------------------------------------------------------ + +MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA): + BaseStream(dictA) { + buf = bufA; + start = startA; + length = lengthA; + bufEnd = buf + start + length; + bufPtr = buf + start; + needFree = gFalse; +} + +MemStream::~MemStream() { + if (needFree) { + gfree(buf); + } +} + +Stream *MemStream::makeSubStream(Guint startA, GBool limited, + Guint lengthA, Object *dictA) { + MemStream *subStr; + Guint newLength; + + if (!limited || startA + lengthA > start + length) { + newLength = start + length - startA; + } else { + newLength = lengthA; + } + subStr = new MemStream(buf, startA, newLength, dictA); + return subStr; +} + +void MemStream::reset() { + bufPtr = buf + start; + if (decrypt) { + decrypt->reset(); + } +} + +void MemStream::close() { +} + +void MemStream::setPos(Guint pos, int dir) { + Guint i; + + if (dir >= 0) { + i = pos; + } else { + i = start + length - pos; + } + if (i < start) { + i = start; + } else if (i > start + length) { + i = start + length; + } + bufPtr = buf + i; +} + +void MemStream::moveStart(int delta) { + start += delta; + length -= delta; + bufPtr = buf + start; +} + +void MemStream::doDecryption(Guchar *fileKey, int keyLength, + int objNum, int objGen) { + char *newBuf; + char *p, *q; + + this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen); + if (decrypt) { + newBuf = (char *)gmalloc(length); + for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) { + *q = (char)decrypt->decryptByte((Guchar)*p); + } + bufEnd = newBuf + length; + bufPtr = newBuf + (bufPtr - (buf + start)); + start = 0; + buf = newBuf; + needFree = gTrue; + } +} + +//------------------------------------------------------------------------ +// EmbedStream +//------------------------------------------------------------------------ + +EmbedStream::EmbedStream(Stream *strA, Object *dictA, + GBool limitedA, Guint lengthA): + BaseStream(dictA) { + str = strA; + limited = limitedA; + length = lengthA; +} + +EmbedStream::~EmbedStream() { +} + +Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA) { + error(-1, "Internal: called makeSubStream() on EmbedStream"); + return NULL; +} + +int EmbedStream::getChar() { + if (limited && !length) { + return EOF; + } + --length; + return str->getChar(); +} + +int EmbedStream::lookChar() { + if (limited && !length) { + return EOF; + } + return str->lookChar(); +} + +void EmbedStream::setPos(Guint pos, int dir) { + error(-1, "Internal: called setPos() on EmbedStream"); +} + +Guint EmbedStream::getStart() { + error(-1, "Internal: called getStart() on EmbedStream"); + return 0; +} + +void EmbedStream::moveStart(int delta) { + 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(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, 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 (Lexer::isSpace(c[0])); + 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 (Lexer::isSpace(c[k])); + 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(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, 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); + if (!pred->isOk()) { + delete pred; + pred = NULL; + } + } else { + pred = NULL; + } + early = earlyA; + eof = gFalse; + inputBits = 0; + clearTable(); +} + +LZWStream::~LZWStream() { + if (pred) { + delete pred; + } + delete str; +} + +int LZWStream::getChar() { + if (pred) { + return pred->getChar(); + } + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; +} + +int LZWStream::lookChar() { + if (pred) { + return pred->lookChar(); + } + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex]; +} + +int LZWStream::getRawChar() { + if (eof) { + return EOF; + } + if (seqIndex >= seqLength) { + if (!processNextCode()) { + return EOF; + } + } + return seqBuf[seqIndex++]; +} + +void LZWStream::reset() { + str->reset(); + eof = gFalse; + inputBits = 0; + clearTable(); +} + +GBool LZWStream::processNextCode() { + int code; + int nextLength; + int i, j; + + // check for EOF + if (eof) { + return gFalse; + } + + // check for eod and clear-table codes + start: + code = getCode(); + if (code == EOF || code == 257) { + eof = gTrue; + return gFalse; + } + if (code == 256) { + clearTable(); + goto start; + } + if (nextCode >= 4097) { + error(getPos(), "Bad LZW stream - expected clear-table code"); + clearTable(); + } + + // process the next code + nextLength = seqLength + 1; + if (code < 256) { + seqBuf[0] = code; + seqLength = 1; + } else if (code < nextCode) { + seqLength = table[code].length; + for (i = seqLength - 1, j = code; i > 0; --i) { + seqBuf[i] = table[j].tail; + j = table[j].head; + } + seqBuf[0] = j; + } else if (code == nextCode) { + seqBuf[seqLength] = newChar; + ++seqLength; + } else { + error(getPos(), "Bad LZW stream - unexpected code"); + eof = gTrue; + return gFalse; + } + newChar = seqBuf[0]; + if (first) { + first = gFalse; + } else { + table[nextCode].length = nextLength; + table[nextCode].head = prevCode; + table[nextCode].tail = newChar; + ++nextCode; + if (nextCode + early == 512) + nextBits = 10; + else if (nextCode + early == 1024) + nextBits = 11; + else if (nextCode + early == 2048) + nextBits = 12; + } + prevCode = code; + + // reset buffer + seqIndex = 0; + + return gTrue; +} + +void LZWStream::clearTable() { + nextCode = 258; + nextBits = 9; + seqIndex = seqLength = 0; + first = gTrue; +} + +int LZWStream::getCode() { + int c; + int code; + + while (inputBits < nextBits) { + if ((c = str->getChar()) == EOF) + return EOF; + inputBuf = (inputBuf << 8) | (c & 0xff); + inputBits += 8; + } + code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1); + inputBits -= nextBits; + return code; +} + +GString *LZWStream::getPSFilter(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2 || pred) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< "); + if (!early) { + s->append("/EarlyChange 0 "); + } + s->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(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, 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; + if (columns < 1) { + columns = 1; + } + rows = rowsA; + endOfBlock = endOfBlockA; + black = blackA; + refLine = (short *)gmallocn(columns + 4, sizeof(short)); + codingLine = (short *)gmallocn(columns + 3, 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() { + short code1; + + str->reset(); + eof = gFalse; + row = 0; + nextLine2D = encoding < 0; + inputBits = 0; + codingLine[0] = 0; + codingLine[1] = refLine[2] = columns; + a0 = 1; + buf = EOF; + + // skip any initial zero bits and end-of-line marker, and get the 2D + // encoding tag + while ((code1 = lookBits(12)) == 0) { + eatBits(1); + } + if (code1 == 0x001) { + eatBits(12); + } + if (encoding > 0) { + nextLine2D = !lookBits(1); + eatBits(1); + } +} + +int CCITTFaxStream::lookChar() { + short code1, code2, code3; + int a0New; + GBool err, gotEOL; + int ret; + int bits, i; + + // if at eof just return EOF + if (eof && codingLine[a0] >= columns) { + return EOF; + } + + // read the next row + err = gFalse; + 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); + } + if (code1 > 0 || code2 > 0) { + 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: + if (a0 == 0 || refLine[b1] - 1 > a0New) { + 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: + if (a0 == 0 || refLine[b1] - 2 > a0New) { + 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: + if (a0 == 0 || refLine[b1] - 3 > a0New) { + 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); + err = gTrue; + break; + } + } 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]); + // force the row to be the correct length + while (codingLine[a0] > columns) { + --a0; + } + codingLine[++a0] = columns; + err = gTrue; + } + + // 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; + } + + // look for an end-of-line marker after an error -- we only do + // this if we know the stream contains end-of-line markers because + // the "just plow on" technique tends to work better otherwise + } else if (err && endOfLine) { + do { + if (code1 == EOF) { + eof = gTrue; + return EOF; + } + eatBits(1); + code1 = lookBits(13); + } while ((code1 >> 1) != 0x001); + eatBits(12); + if (encoding > 0) { + eatBits(1); + nextLine2D = !(code1 & 1); + } + } + + 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(int psLevel, char *indent) { + GString *s; + char s1[50]; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, 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) +#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 + +// 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; + + progressive = interleaved = gFalse; + 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; + } + frameBuf[i] = 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; + if (progressive || !interleaved) { + for (i = 0; i < numComps; ++i) { + gfree(frameBuf[i]); + } + } else { + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + gfree(rowBuf[i][j]); + } + } + } +} + +void DCTStream::reset() { + int i, j; + + str->reset(); + + progressive = interleaved = gFalse; + width = height = 0; + numComps = 0; + numQuantTables = 0; + numDCHuffTables = 0; + numACHuffTables = 0; + colorXform = 0; + gotJFIFMarker = gFalse; + gotAdobeMarker = gFalse; + restartInterval = 0; + + if (!readHeader()) { + y = height; + return; + } + + // compute MCU size + if (numComps == 1) { + compInfo[0].hSample = compInfo[0].vSample = 1; + } + mcuWidth = compInfo[0].hSample; + mcuHeight = compInfo[0].vSample; + for (i = 1; i < numComps; ++i) { + if (compInfo[i].hSample > mcuWidth) { + mcuWidth = compInfo[i].hSample; + } + if (compInfo[i].vSample > mcuHeight) { + mcuHeight = compInfo[i].vSample; + } + } + mcuWidth *= 8; + mcuHeight *= 8; + + // figure out color transform + if (!gotAdobeMarker && numComps == 3) { + if (gotJFIFMarker) { + colorXform = 1; + } else if (compInfo[0].id == 82 && compInfo[1].id == 71 && + compInfo[2].id == 66) { // ASCII "RGB" + colorXform = 0; + } else { + colorXform = 1; + } + } + + if (progressive || !interleaved) { + + // allocate a buffer for the whole image + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; + for (i = 0; i < numComps; ++i) { + frameBuf[i] = (int *)gmallocn(bufWidth * bufHeight, sizeof(int)); + memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); + } + + // read the image data + do { + restartMarker = 0xd0; + restart(); + readScan(); + } while (readHeader()); + + // decode + decodeImage(); + + // initialize counters + comp = 0; + x = 0; + y = 0; + + } else { + + // allocate a buffer for one row of MCUs + bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; + for (i = 0; i < numComps; ++i) { + for (j = 0; j < mcuHeight; ++j) { + rowBuf[i][j] = (Guchar *)gmallocn(bufWidth, sizeof(Guchar)); + } + } + + // initialize counters + comp = 0; + x = 0; + y = 0; + dy = mcuHeight; + + restartMarker = 0xd0; + restart(); + } +} + +int DCTStream::getChar() { + int c; + + if (y >= height) { + return EOF; + } + if (progressive || !interleaved) { + c = frameBuf[comp][y * bufWidth + x]; + if (++comp == numComps) { + comp = 0; + if (++x == width) { + x = 0; + ++y; + } + } + } else { + if (dy >= mcuHeight) { + if (!readMCURow()) { + y = height; + return EOF; + } + comp = 0; + x = 0; + dy = 0; + } + c = rowBuf[comp][dy][x]; + 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 (progressive || !interleaved) { + return frameBuf[comp][y * bufWidth + x]; + } else { + 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; + } + eobRun = 0; +} + +// Read one row of MCUs from a sequential JPEG stream. +GBool DCTStream::readMCURow() { + int data1[64]; + Guchar data2[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[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data1)) { + return gFalse; + } + transformDataUnit(quantTables[compInfo[cc].quantTable], + data1, data2); + if (hSub == 1 && vSub == 1) { + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1 = &rowBuf[cc][y2+y3][x1+x2]; + p1[0] = data2[i]; + p1[1] = data2[i+1]; + p1[2] = data2[i+2]; + p1[3] = data2[i+3]; + p1[4] = data2[i+4]; + p1[5] = data2[i+5]; + p1[6] = data2[i+6]; + p1[7] = data2[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] = data2[i]; + p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1]; + p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2]; + p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3]; + p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4]; + p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5]; + p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6]; + p1[14] = p1[15] = p2[14] = p2[15] = data2[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] = data2[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 + 32768) >> 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; +} + +// Read one scan from a progressive or non-interleaved JPEG stream. +void DCTStream::readScan() { + int data[64]; + int x1, y1, dx1, dy1, x2, y2, y3, cc, i; + int h, v, horiz, vert, vSub; + int *p1; + int c; + + if (scanInfo.numComps == 1) { + for (cc = 0; cc < numComps; ++cc) { + if (scanInfo.comp[cc]) { + break; + } + } + dx1 = mcuWidth / compInfo[cc].hSample; + dy1 = mcuHeight / compInfo[cc].vSample; + } else { + dx1 = mcuWidth; + dy1 = mcuHeight; + } + + for (y1 = 0; y1 < height; y1 += dy1) { + for (x1 = 0; x1 < width; x1 += dx1) { + + // deal with restart marker + if (restartInterval > 0 && restartCtr == 0) { + c = readMarker(); + if (c != restartMarker) { + error(getPos(), "Bad DCT data: incorrect restart marker"); + return; + } + if (++restartMarker == 0xd8) { + restartMarker = 0xd0; + } + restart(); + } + + // read one MCU + for (cc = 0; cc < numComps; ++cc) { + if (!scanInfo.comp[cc]) { + continue; + } + + h = compInfo[cc].hSample; + v = compInfo[cc].vSample; + horiz = mcuWidth / h; + vert = mcuHeight / v; + vSub = vert / 8; + for (y2 = 0; y2 < dy1; y2 += vert) { + for (x2 = 0; x2 < dx1; x2 += horiz) { + + // pull out the current values + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + data[i] = p1[0]; + data[i+1] = p1[1]; + data[i+2] = p1[2]; + data[i+3] = p1[3]; + data[i+4] = p1[4]; + data[i+5] = p1[5]; + data[i+6] = p1[6]; + data[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // read one data unit + if (progressive) { + if (!readProgressiveDataUnit( + &dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } else { + if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], + &acHuffTables[scanInfo.acHuffTable[cc]], + &compInfo[cc].prevDC, + data)) { + return; + } + } + + // add the data unit into frameBuf + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + 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]; + p1 += bufWidth * vSub; + } + } + } + } + --restartCtr; + } + } +} + +// Read one data unit from a sequential JPEG stream. +GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]) { + int run, size, amp; + int c; + int i, j; + + if ((size = readHuffSym(dcHuffTable)) == 9999) { + return gFalse; + } + if (size > 0) { + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + } else { + amp = 0; + } + data[0] = *prevDC += amp; + for (i = 1; i < 64; ++i) { + data[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; + if (i < 64) { + j = dctZigZag[i++]; + data[j] = amp; + } + } + } + return gTrue; +} + +// Read one data unit from a sequential JPEG stream. +GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]) { + int run, size, amp, bit, c; + int i, j, k; + + // get the DC coefficient + i = scanInfo.firstCoeff; + if (i == 0) { + if (scanInfo.ah == 0) { + if ((size = readHuffSym(dcHuffTable)) == 9999) { + return gFalse; + } + if (size > 0) { + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + } else { + amp = 0; + } + data[0] += (*prevDC += amp) << scanInfo.al; + } else { + if ((bit = readBit()) == 9999) { + return gFalse; + } + data[0] += bit << scanInfo.al; + } + ++i; + } + if (scanInfo.lastCoeff == 0) { + return gTrue; + } + + // check for an EOB run + if (eobRun > 0) { + while (i <= scanInfo.lastCoeff) { + j = dctZigZag[i++]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + --eobRun; + return gTrue; + } + + // read the AC coefficients + while (i <= scanInfo.lastCoeff) { + if ((c = readHuffSym(acHuffTable)) == 9999) { + return gFalse; + } + + // ZRL + if (c == 0xf0) { + k = 0; + while (k < 16) { + j = dctZigZag[i++]; + if (data[j] == 0) { + ++k; + } else { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + + // EOB run + } else if ((c & 0x0f) == 0x00) { + j = c >> 4; + eobRun = 0; + for (k = 0; k < j; ++k) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + eobRun = (eobRun << 1) | bit; + } + eobRun += 1 << j; + while (i <= scanInfo.lastCoeff) { + j = dctZigZag[i++]; + if (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + } + } + --eobRun; + break; + + // zero run and one AC coefficient + } else { + run = (c >> 4) & 0x0f; + size = c & 0x0f; + if ((amp = readAmp(size)) == 9999) { + return gFalse; + } + k = 0; + do { + j = dctZigZag[i++]; + while (data[j] != 0) { + if ((bit = readBit()) == EOF) { + return gFalse; + } + if (bit) { + data[j] += 1 << scanInfo.al; + } + j = dctZigZag[i++]; + } + ++k; + } while (k <= run); + data[j] = amp << scanInfo.al; + } + } + + return gTrue; +} + +// Decode a progressive JPEG image. +void DCTStream::decodeImage() { + int dataIn[64]; + Guchar dataOut[64]; + Gushort *quantTable; + int pY, pCb, pCr, pR, pG, pB; + int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; + int h, v, horiz, vert, hSub, vSub; + int *p0, *p1, *p2; + + for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) { + for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { + for (cc = 0; cc < numComps; ++cc) { + quantTable = quantTables[compInfo[cc].quantTable]; + 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) { + + // pull out the coded data unit + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + dataIn[i] = p1[0]; + dataIn[i+1] = p1[1]; + dataIn[i+2] = p1[2]; + dataIn[i+3] = p1[3]; + dataIn[i+4] = p1[4]; + dataIn[i+5] = p1[5]; + dataIn[i+6] = p1[6]; + dataIn[i+7] = p1[7]; + p1 += bufWidth * vSub; + } + + // transform + transformDataUnit(quantTable, dataIn, dataOut); + + // store back into frameBuf, doing replication for + // subsampled components + p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; + if (hSub == 1 && vSub == 1) { + for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { + p1[0] = dataOut[i] & 0xff; + p1[1] = dataOut[i+1] & 0xff; + p1[2] = dataOut[i+2] & 0xff; + p1[3] = dataOut[i+3] & 0xff; + p1[4] = dataOut[i+4] & 0xff; + p1[5] = dataOut[i+5] & 0xff; + p1[6] = dataOut[i+6] & 0xff; + p1[7] = dataOut[i+7] & 0xff; + p1 += bufWidth; + } + } else if (hSub == 2 && vSub == 2) { + p2 = p1 + bufWidth; + for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { + p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff; + p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff; + p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff; + p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff; + p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff; + p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff; + p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff; + p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff; + p1 += bufWidth * 2; + p2 += bufWidth * 2; + } + } else { + i = 0; + for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { + for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { + p2 = p1 + x4; + for (y5 = 0; y5 < vSub; ++y5) { + for (x5 = 0; x5 < hSub; ++x5) { + p2[x5] = dataOut[i] & 0xff; + } + p2 += bufWidth; + } + ++i; + } + p1 += bufWidth * vSub; + } + } + } + } + } + + // color space conversion + if (colorXform) { + // convert YCbCr to RGB + if (numComps == 3) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = dctClip[dctClipOffset + pB]; + } + } + // convert YCbCrK to CMYK (K is passed through unchanged) + } else if (numComps == 4) { + for (y2 = 0; y2 < mcuHeight; ++y2) { + p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; + p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; + p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; + for (x2 = 0; x2 < mcuWidth; ++x2) { + pY = *p0; + pCb = *p1 - 128; + pCr = *p2 - 128; + pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; + *p0++ = 255 - dctClip[dctClipOffset + pR]; + pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + + 32768) >> 16; + *p1++ = 255 - dctClip[dctClipOffset + pG]; + pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; + *p2++ = 255 - dctClip[dctClipOffset + pB]; + } + } + } + } + } + } +} + +// Transform one data unit -- this performs the dequantization and +// IDCT steps. 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. +void DCTStream::transformDataUnit(Gushort *quantTable, + int dataIn[64], Guchar dataOut[64]) { + int v0, v1, v2, v3, v4, v5, v6, v7, t; + int *p; + int i; + + // dequant + for (i = 0; i < 64; ++i) { + dataIn[i] *= quantTable[i]; + } + + // inverse DCT on rows + for (i = 0; i < 64; i += 8) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1] == 0 && p[2] == 0 && p[3] == 0 && + p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) { + t = (dctSqrt2 * p[0] + 512) >> 10; + p[0] = t; + p[1] = t; + p[2] = t; + p[3] = t; + p[4] = t; + p[5] = t; + p[6] = t; + p[7] = t; + continue; + } + + // stage 4 + v0 = (dctSqrt2 * p[0] + 128) >> 8; + v1 = (dctSqrt2 * p[4] + 128) >> 8; + v2 = p[2]; + v3 = p[6]; + v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8; + v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8; + v5 = p[3] << 4; + v6 = p[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 + p[0] = v0 + v7; + p[7] = v0 - v7; + p[1] = v1 + v6; + p[6] = v1 - v6; + p[2] = v2 + v5; + p[5] = v2 - v5; + p[3] = v3 + v4; + p[4] = v3 - v4; + } + + // inverse DCT on columns + for (i = 0; i < 8; ++i) { + p = dataIn + i; + + // check for all-zero AC coefficients + if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 && + p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) { + t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14; + p[0*8] = t; + p[1*8] = t; + p[2*8] = t; + p[3*8] = t; + p[4*8] = t; + p[5*8] = t; + p[6*8] = t; + p[7*8] = t; + continue; + } + + // stage 4 + v0 = (dctSqrt2 * p[0*8] + 2048) >> 12; + v1 = (dctSqrt2 * p[4*8] + 2048) >> 12; + v2 = p[2*8]; + v3 = p[6*8]; + v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12; + v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12; + v5 = p[3*8]; + v6 = p[5*8]; + + // 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 + p[0*8] = v0 + v7; + p[7*8] = v0 - v7; + p[1*8] = v1 + v6; + p[6*8] = v1 - v6; + p[2*8] = v2 + v5; + p[5*8] = v2 - v5; + p[3*8] = v3 + v4; + p[4*8] = v3 - v4; + } + + // convert to 8-bit integers + for (i = 0; i < 64; ++i) { + dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)]; + } +} + +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 n; + int c = 0; + int i; + + // read headers + doScan = gFalse; + while (!doScan) { + c = readMarker(); + switch (c) { + case 0xc0: // SOF0 (sequential) + case 0xc1: // SOF1 (extended sequential) + if (!readBaselineSOF()) { + return gFalse; + } + break; + case 0xc2: // SOF2 (progressive) + if (!readProgressiveSOF()) { + return gFalse; + } + break; + case 0xc4: // DHT + if (!readHuffmanTables()) { + return gFalse; + } + break; + case 0xd8: // SOI + break; + case 0xd9: // EOI + return gFalse; + 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 0xe0: // APP0 + if (!readJFIFMarker()) { + 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; + } + } + + return gTrue; +} + +GBool DCTStream::readBaselineSOF() { + int length; + int prec; + int i; + int c; + + length = read16(); + prec = str->getChar(); + height = read16(); + width = read16(); + numComps = str->getChar(); + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream", prec); + return gFalse; + } + if (numComps <= 0 || numComps > 4) { + error(getPos(), "Bad number of components in DCT stream", prec); + return gFalse; + } + if (prec != 8) { + error(getPos(), "Bad DCT precision %d", prec); + return gFalse; + } + for (i = 0; i < numComps; ++i) { + compInfo[i].id = str->getChar(); + c = str->getChar(); + compInfo[i].hSample = (c >> 4) & 0x0f; + compInfo[i].vSample = c & 0x0f; + compInfo[i].quantTable = str->getChar(); + } + progressive = gFalse; + return gTrue; +} + +GBool DCTStream::readProgressiveSOF() { + int length; + int prec; + int i; + int c; + + length = read16(); + prec = str->getChar(); + height = read16(); + width = read16(); + numComps = str->getChar(); + if (prec != 8) { + error(getPos(), "Bad DCT precision %d", prec); + return gFalse; + } + for (i = 0; i < numComps; ++i) { + compInfo[i].id = str->getChar(); + c = str->getChar(); + compInfo[i].hSample = (c >> 4) & 0x0f; + compInfo[i].vSample = c & 0x0f; + compInfo[i].quantTable = str->getChar(); + } + progressive = gTrue; + return gTrue; +} + +GBool DCTStream::readScanInfo() { + int length; + int id, c; + int i, j; + + length = read16() - 2; + scanInfo.numComps = str->getChar(); + --length; + if (length != 2 * scanInfo.numComps + 3) { + error(getPos(), "Bad DCT scan info block"); + return gFalse; + } + interleaved = scanInfo.numComps == numComps; + for (j = 0; j < numComps; ++j) { + scanInfo.comp[j] = gFalse; + } + for (i = 0; i < scanInfo.numComps; ++i) { + id = str->getChar(); + // some (broken) DCT streams reuse ID numbers, but at least they + // keep the components in order, so we check compInfo[i] first to + // work around the problem + if (id == compInfo[i].id) { + j = i; + } else { + 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; + } + } + scanInfo.comp[j] = gTrue; + c = str->getChar(); + scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f; + scanInfo.acHuffTable[j] = c & 0x0f; + } + scanInfo.firstCoeff = str->getChar(); + scanInfo.lastCoeff = str->getChar(); + c = str->getChar(); + scanInfo.ah = (c >> 4) & 0x0f; + scanInfo.al = c & 0x0f; + return gTrue; +} + +GBool DCTStream::readQuantTables() { + int length, prec, i, index; + + length = read16() - 2; + while (length > 0) { + index = str->getChar(); + prec = (index >> 4) & 0x0f; + index &= 0x0f; + if (prec > 1 || index >= 4) { + error(getPos(), "Bad DCT quantization table"); + return gFalse; + } + if (index == numQuantTables) { + numQuantTables = index + 1; + } + for (i = 0; i < 64; ++i) { + if (prec) { + quantTables[index][dctZigZag[i]] = read16(); + } else { + quantTables[index][dctZigZag[i]] = str->getChar(); + } + } + if (prec) { + length -= 129; + } else { + 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::readJFIFMarker() { + int length, i; + char buf[5]; + int c; + + length = read16(); + length -= 2; + if (length >= 5) { + for (i = 0; i < 5; ++i) { + if ((c = str->getChar()) == EOF) { + error(getPos(), "Bad DCT APP0 marker"); + return gFalse; + } + buf[i] = c; + } + length -= 5; + if (!memcmp(buf, "JFIF\0", 5)) { + gotJFIFMarker = gTrue; + } + } + while (length > 0) { + if (str->getChar() == EOF) { + error(getPos(), "Bad DCT APP0 marker"); + return gFalse; + } + --length; + } + 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; + for (i = 14; i < length; ++i) { + if (str->getChar() == EOF) { + goto err; + } + } + 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 && c != EOF); + 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(int psLevel, char *indent) { + GString *s; + + if (psLevel < 2) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, 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}, + {0, 258}, + {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} +}; + +static FlateCode flateFixedLitCodeTabCodes[512] = { + {7, 0x0100}, + {8, 0x0050}, + {8, 0x0010}, + {8, 0x0118}, + {7, 0x0110}, + {8, 0x0070}, + {8, 0x0030}, + {9, 0x00c0}, + {7, 0x0108}, + {8, 0x0060}, + {8, 0x0020}, + {9, 0x00a0}, + {8, 0x0000}, + {8, 0x0080}, + {8, 0x0040}, + {9, 0x00e0}, + {7, 0x0104}, + {8, 0x0058}, + {8, 0x0018}, + {9, 0x0090}, + {7, 0x0114}, + {8, 0x0078}, + {8, 0x0038}, + {9, 0x00d0}, + {7, 0x010c}, + {8, 0x0068}, + {8, 0x0028}, + {9, 0x00b0}, + {8, 0x0008}, + {8, 0x0088}, + {8, 0x0048}, + {9, 0x00f0}, + {7, 0x0102}, + {8, 0x0054}, + {8, 0x0014}, + {8, 0x011c}, + {7, 0x0112}, + {8, 0x0074}, + {8, 0x0034}, + {9, 0x00c8}, + {7, 0x010a}, + {8, 0x0064}, + {8, 0x0024}, + {9, 0x00a8}, + {8, 0x0004}, + {8, 0x0084}, + {8, 0x0044}, + {9, 0x00e8}, + {7, 0x0106}, + {8, 0x005c}, + {8, 0x001c}, + {9, 0x0098}, + {7, 0x0116}, + {8, 0x007c}, + {8, 0x003c}, + {9, 0x00d8}, + {7, 0x010e}, + {8, 0x006c}, + {8, 0x002c}, + {9, 0x00b8}, + {8, 0x000c}, + {8, 0x008c}, + {8, 0x004c}, + {9, 0x00f8}, + {7, 0x0101}, + {8, 0x0052}, + {8, 0x0012}, + {8, 0x011a}, + {7, 0x0111}, + {8, 0x0072}, + {8, 0x0032}, + {9, 0x00c4}, + {7, 0x0109}, + {8, 0x0062}, + {8, 0x0022}, + {9, 0x00a4}, + {8, 0x0002}, + {8, 0x0082}, + {8, 0x0042}, + {9, 0x00e4}, + {7, 0x0105}, + {8, 0x005a}, + {8, 0x001a}, + {9, 0x0094}, + {7, 0x0115}, + {8, 0x007a}, + {8, 0x003a}, + {9, 0x00d4}, + {7, 0x010d}, + {8, 0x006a}, + {8, 0x002a}, + {9, 0x00b4}, + {8, 0x000a}, + {8, 0x008a}, + {8, 0x004a}, + {9, 0x00f4}, + {7, 0x0103}, + {8, 0x0056}, + {8, 0x0016}, + {8, 0x011e}, + {7, 0x0113}, + {8, 0x0076}, + {8, 0x0036}, + {9, 0x00cc}, + {7, 0x010b}, + {8, 0x0066}, + {8, 0x0026}, + {9, 0x00ac}, + {8, 0x0006}, + {8, 0x0086}, + {8, 0x0046}, + {9, 0x00ec}, + {7, 0x0107}, + {8, 0x005e}, + {8, 0x001e}, + {9, 0x009c}, + {7, 0x0117}, + {8, 0x007e}, + {8, 0x003e}, + {9, 0x00dc}, + {7, 0x010f}, + {8, 0x006e}, + {8, 0x002e}, + {9, 0x00bc}, + {8, 0x000e}, + {8, 0x008e}, + {8, 0x004e}, + {9, 0x00fc}, + {7, 0x0100}, + {8, 0x0051}, + {8, 0x0011}, + {8, 0x0119}, + {7, 0x0110}, + {8, 0x0071}, + {8, 0x0031}, + {9, 0x00c2}, + {7, 0x0108}, + {8, 0x0061}, + {8, 0x0021}, + {9, 0x00a2}, + {8, 0x0001}, + {8, 0x0081}, + {8, 0x0041}, + {9, 0x00e2}, + {7, 0x0104}, + {8, 0x0059}, + {8, 0x0019}, + {9, 0x0092}, + {7, 0x0114}, + {8, 0x0079}, + {8, 0x0039}, + {9, 0x00d2}, + {7, 0x010c}, + {8, 0x0069}, + {8, 0x0029}, + {9, 0x00b2}, + {8, 0x0009}, + {8, 0x0089}, + {8, 0x0049}, + {9, 0x00f2}, + {7, 0x0102}, + {8, 0x0055}, + {8, 0x0015}, + {8, 0x011d}, + {7, 0x0112}, + {8, 0x0075}, + {8, 0x0035}, + {9, 0x00ca}, + {7, 0x010a}, + {8, 0x0065}, + {8, 0x0025}, + {9, 0x00aa}, + {8, 0x0005}, + {8, 0x0085}, + {8, 0x0045}, + {9, 0x00ea}, + {7, 0x0106}, + {8, 0x005d}, + {8, 0x001d}, + {9, 0x009a}, + {7, 0x0116}, + {8, 0x007d}, + {8, 0x003d}, + {9, 0x00da}, + {7, 0x010e}, + {8, 0x006d}, + {8, 0x002d}, + {9, 0x00ba}, + {8, 0x000d}, + {8, 0x008d}, + {8, 0x004d}, + {9, 0x00fa}, + {7, 0x0101}, + {8, 0x0053}, + {8, 0x0013}, + {8, 0x011b}, + {7, 0x0111}, + {8, 0x0073}, + {8, 0x0033}, + {9, 0x00c6}, + {7, 0x0109}, + {8, 0x0063}, + {8, 0x0023}, + {9, 0x00a6}, + {8, 0x0003}, + {8, 0x0083}, + {8, 0x0043}, + {9, 0x00e6}, + {7, 0x0105}, + {8, 0x005b}, + {8, 0x001b}, + {9, 0x0096}, + {7, 0x0115}, + {8, 0x007b}, + {8, 0x003b}, + {9, 0x00d6}, + {7, 0x010d}, + {8, 0x006b}, + {8, 0x002b}, + {9, 0x00b6}, + {8, 0x000b}, + {8, 0x008b}, + {8, 0x004b}, + {9, 0x00f6}, + {7, 0x0103}, + {8, 0x0057}, + {8, 0x0017}, + {8, 0x011f}, + {7, 0x0113}, + {8, 0x0077}, + {8, 0x0037}, + {9, 0x00ce}, + {7, 0x010b}, + {8, 0x0067}, + {8, 0x0027}, + {9, 0x00ae}, + {8, 0x0007}, + {8, 0x0087}, + {8, 0x0047}, + {9, 0x00ee}, + {7, 0x0107}, + {8, 0x005f}, + {8, 0x001f}, + {9, 0x009e}, + {7, 0x0117}, + {8, 0x007f}, + {8, 0x003f}, + {9, 0x00de}, + {7, 0x010f}, + {8, 0x006f}, + {8, 0x002f}, + {9, 0x00be}, + {8, 0x000f}, + {8, 0x008f}, + {8, 0x004f}, + {9, 0x00fe}, + {7, 0x0100}, + {8, 0x0050}, + {8, 0x0010}, + {8, 0x0118}, + {7, 0x0110}, + {8, 0x0070}, + {8, 0x0030}, + {9, 0x00c1}, + {7, 0x0108}, + {8, 0x0060}, + {8, 0x0020}, + {9, 0x00a1}, + {8, 0x0000}, + {8, 0x0080}, + {8, 0x0040}, + {9, 0x00e1}, + {7, 0x0104}, + {8, 0x0058}, + {8, 0x0018}, + {9, 0x0091}, + {7, 0x0114}, + {8, 0x0078}, + {8, 0x0038}, + {9, 0x00d1}, + {7, 0x010c}, + {8, 0x0068}, + {8, 0x0028}, + {9, 0x00b1}, + {8, 0x0008}, + {8, 0x0088}, + {8, 0x0048}, + {9, 0x00f1}, + {7, 0x0102}, + {8, 0x0054}, + {8, 0x0014}, + {8, 0x011c}, + {7, 0x0112}, + {8, 0x0074}, + {8, 0x0034}, + {9, 0x00c9}, + {7, 0x010a}, + {8, 0x0064}, + {8, 0x0024}, + {9, 0x00a9}, + {8, 0x0004}, + {8, 0x0084}, + {8, 0x0044}, + {9, 0x00e9}, + {7, 0x0106}, + {8, 0x005c}, + {8, 0x001c}, + {9, 0x0099}, + {7, 0x0116}, + {8, 0x007c}, + {8, 0x003c}, + {9, 0x00d9}, + {7, 0x010e}, + {8, 0x006c}, + {8, 0x002c}, + {9, 0x00b9}, + {8, 0x000c}, + {8, 0x008c}, + {8, 0x004c}, + {9, 0x00f9}, + {7, 0x0101}, + {8, 0x0052}, + {8, 0x0012}, + {8, 0x011a}, + {7, 0x0111}, + {8, 0x0072}, + {8, 0x0032}, + {9, 0x00c5}, + {7, 0x0109}, + {8, 0x0062}, + {8, 0x0022}, + {9, 0x00a5}, + {8, 0x0002}, + {8, 0x0082}, + {8, 0x0042}, + {9, 0x00e5}, + {7, 0x0105}, + {8, 0x005a}, + {8, 0x001a}, + {9, 0x0095}, + {7, 0x0115}, + {8, 0x007a}, + {8, 0x003a}, + {9, 0x00d5}, + {7, 0x010d}, + {8, 0x006a}, + {8, 0x002a}, + {9, 0x00b5}, + {8, 0x000a}, + {8, 0x008a}, + {8, 0x004a}, + {9, 0x00f5}, + {7, 0x0103}, + {8, 0x0056}, + {8, 0x0016}, + {8, 0x011e}, + {7, 0x0113}, + {8, 0x0076}, + {8, 0x0036}, + {9, 0x00cd}, + {7, 0x010b}, + {8, 0x0066}, + {8, 0x0026}, + {9, 0x00ad}, + {8, 0x0006}, + {8, 0x0086}, + {8, 0x0046}, + {9, 0x00ed}, + {7, 0x0107}, + {8, 0x005e}, + {8, 0x001e}, + {9, 0x009d}, + {7, 0x0117}, + {8, 0x007e}, + {8, 0x003e}, + {9, 0x00dd}, + {7, 0x010f}, + {8, 0x006e}, + {8, 0x002e}, + {9, 0x00bd}, + {8, 0x000e}, + {8, 0x008e}, + {8, 0x004e}, + {9, 0x00fd}, + {7, 0x0100}, + {8, 0x0051}, + {8, 0x0011}, + {8, 0x0119}, + {7, 0x0110}, + {8, 0x0071}, + {8, 0x0031}, + {9, 0x00c3}, + {7, 0x0108}, + {8, 0x0061}, + {8, 0x0021}, + {9, 0x00a3}, + {8, 0x0001}, + {8, 0x0081}, + {8, 0x0041}, + {9, 0x00e3}, + {7, 0x0104}, + {8, 0x0059}, + {8, 0x0019}, + {9, 0x0093}, + {7, 0x0114}, + {8, 0x0079}, + {8, 0x0039}, + {9, 0x00d3}, + {7, 0x010c}, + {8, 0x0069}, + {8, 0x0029}, + {9, 0x00b3}, + {8, 0x0009}, + {8, 0x0089}, + {8, 0x0049}, + {9, 0x00f3}, + {7, 0x0102}, + {8, 0x0055}, + {8, 0x0015}, + {8, 0x011d}, + {7, 0x0112}, + {8, 0x0075}, + {8, 0x0035}, + {9, 0x00cb}, + {7, 0x010a}, + {8, 0x0065}, + {8, 0x0025}, + {9, 0x00ab}, + {8, 0x0005}, + {8, 0x0085}, + {8, 0x0045}, + {9, 0x00eb}, + {7, 0x0106}, + {8, 0x005d}, + {8, 0x001d}, + {9, 0x009b}, + {7, 0x0116}, + {8, 0x007d}, + {8, 0x003d}, + {9, 0x00db}, + {7, 0x010e}, + {8, 0x006d}, + {8, 0x002d}, + {9, 0x00bb}, + {8, 0x000d}, + {8, 0x008d}, + {8, 0x004d}, + {9, 0x00fb}, + {7, 0x0101}, + {8, 0x0053}, + {8, 0x0013}, + {8, 0x011b}, + {7, 0x0111}, + {8, 0x0073}, + {8, 0x0033}, + {9, 0x00c7}, + {7, 0x0109}, + {8, 0x0063}, + {8, 0x0023}, + {9, 0x00a7}, + {8, 0x0003}, + {8, 0x0083}, + {8, 0x0043}, + {9, 0x00e7}, + {7, 0x0105}, + {8, 0x005b}, + {8, 0x001b}, + {9, 0x0097}, + {7, 0x0115}, + {8, 0x007b}, + {8, 0x003b}, + {9, 0x00d7}, + {7, 0x010d}, + {8, 0x006b}, + {8, 0x002b}, + {9, 0x00b7}, + {8, 0x000b}, + {8, 0x008b}, + {8, 0x004b}, + {9, 0x00f7}, + {7, 0x0103}, + {8, 0x0057}, + {8, 0x0017}, + {8, 0x011f}, + {7, 0x0113}, + {8, 0x0077}, + {8, 0x0037}, + {9, 0x00cf}, + {7, 0x010b}, + {8, 0x0067}, + {8, 0x0027}, + {9, 0x00af}, + {8, 0x0007}, + {8, 0x0087}, + {8, 0x0047}, + {9, 0x00ef}, + {7, 0x0107}, + {8, 0x005f}, + {8, 0x001f}, + {9, 0x009f}, + {7, 0x0117}, + {8, 0x007f}, + {8, 0x003f}, + {9, 0x00df}, + {7, 0x010f}, + {8, 0x006f}, + {8, 0x002f}, + {9, 0x00bf}, + {8, 0x000f}, + {8, 0x008f}, + {8, 0x004f}, + {9, 0x00ff} +}; + +FlateHuffmanTab FlateStream::fixedLitCodeTab = { + flateFixedLitCodeTabCodes, 9 +}; + +static FlateCode flateFixedDistCodeTabCodes[32] = { + {5, 0x0000}, + {5, 0x0010}, + {5, 0x0008}, + {5, 0x0018}, + {5, 0x0004}, + {5, 0x0014}, + {5, 0x000c}, + {5, 0x001c}, + {5, 0x0002}, + {5, 0x0012}, + {5, 0x000a}, + {5, 0x001a}, + {5, 0x0006}, + {5, 0x0016}, + {5, 0x000e}, + {0, 0x0000}, + {5, 0x0001}, + {5, 0x0011}, + {5, 0x0009}, + {5, 0x0019}, + {5, 0x0005}, + {5, 0x0015}, + {5, 0x000d}, + {5, 0x001d}, + {5, 0x0003}, + {5, 0x0013}, + {5, 0x000b}, + {5, 0x001b}, + {5, 0x0007}, + {5, 0x0017}, + {5, 0x000f}, + {0, 0x0000} +}; + +FlateHuffmanTab FlateStream::fixedDistCodeTab = { + flateFixedDistCodeTabCodes, 5 +}; + +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); + if (!pred->isOk()) { + delete pred; + pred = NULL; + } + } else { + pred = NULL; + } + litCodeTab.codes = NULL; + distCodeTab.codes = NULL; +} + +FlateStream::~FlateStream() { + if (litCodeTab.codes != fixedLitCodeTab.codes) { + gfree(litCodeTab.codes); + } + if (distCodeTab.codes != fixedDistCodeTab.codes) { + gfree(distCodeTab.codes); + } + 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(int psLevel, char *indent) { + GString *s; + + if (psLevel < 3 || pred) { + return NULL; + } + if (!(s = str->getPSFilter(psLevel, indent))) { + return NULL; + } + s->append(indent)->append("<< >> /FlateDecode filter\n"); + return s; +} + +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; + + // free the code tables from the previous block + if (litCodeTab.codes != fixedLitCodeTab.codes) { + gfree(litCodeTab.codes); + } + litCodeTab.codes = NULL; + if (distCodeTab.codes != fixedDistCodeTab.codes) { + gfree(distCodeTab.codes); + } + distCodeTab.codes = NULL; + + // 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() { + litCodeTab.codes = fixedLitCodeTab.codes; + litCodeTab.maxLen = fixedLitCodeTab.maxLen; + distCodeTab.codes = fixedDistCodeTab.codes; + distCodeTab.maxLen = fixedDistCodeTab.maxLen; +} + +GBool FlateStream::readDynamicCodes() { + int numCodeLenCodes; + int numLitCodes; + int numDistCodes; + int codeLenCodeLengths[flateMaxCodeLenCodes]; + FlateHuffmanTab codeLenCodeTab; + int len, repeat, code; + int i; + + codeLenCodeTab.codes = NULL; + + // 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; + } + + // build the code length code table + for (i = 0; i < flateMaxCodeLenCodes; ++i) { + codeLenCodeLengths[i] = 0; + } + for (i = 0; i < numCodeLenCodes; ++i) { + if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) { + goto err; + } + } + compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab); + + // build the 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; + } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } + for (; repeat > 0; --repeat) { + codeLengths[i++] = len; + } + } else if (code == 17) { + if ((repeat = getCodeWord(3)) == EOF) { + goto err; + } + repeat += 3; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } + len = 0; + for (; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } + } else if (code == 18) { + if ((repeat = getCodeWord(7)) == EOF) { + goto err; + } + repeat += 11; + if (i + repeat > numLitCodes + numDistCodes) { + goto err; + } + len = 0; + for (; repeat > 0; --repeat) { + codeLengths[i++] = 0; + } + } else { + codeLengths[i++] = len = code; + } + } + compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab); + compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab); + + gfree(codeLenCodeTab.codes); + return gTrue; + +err: + error(getPos(), "Bad dynamic code table in flate stream"); + gfree(codeLenCodeTab.codes); + return gFalse; +} + +// Convert an array of lengths, in value order, into a +// Huffman code lookup table. +void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { + int tabSize, len, code, code2, skip, val, i, t; + + // find max code length + tab->maxLen = 0; + for (val = 0; val < n; ++val) { + if (lengths[val] > tab->maxLen) { + tab->maxLen = lengths[val]; + } + } + + // allocate the table + tabSize = 1 << tab->maxLen; + tab->codes = (FlateCode *)gmallocn(tabSize, sizeof(FlateCode)); + + // clear the table + for (i = 0; i < tabSize; ++i) { + tab->codes[i].len = 0; + tab->codes[i].val = 0; + } + + // build the table + for (len = 1, code = 0, skip = 2; + len <= tab->maxLen; + ++len, code <<= 1, skip <<= 1) { + for (val = 0; val < n; ++val) { + if (lengths[val] == len) { + + // bit-reverse the code + code2 = 0; + t = code; + for (i = 0; i < len; ++i) { + code2 = (code2 << 1) | (t & 1); + t >>= 1; + } + + // fill in the table entries + for (i = code2; i < tabSize; i += skip) { + tab->codes[i].len = (Gushort)len; + tab->codes[i].val = (Gushort)val; + } + + ++code; + } + } + } +} + +int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { + FlateCode *code; + int c; + + while (codeSize < tab->maxLen) { + if ((c = str->getChar()) == EOF) { + break; + } + codeBuf |= (c & 0xff) << codeSize; + codeSize += 8; + } + code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)]; + if (codeSize == 0 || codeSize < code->len || code->len == 0) { + return EOF; + } + codeBuf >>= code->len; + codeSize -= code->len; + return (int)code->val; +} + +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; +} + +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(); +} + +GBool FixedLengthEncoder::isBinary(GBool last) { + return str->isBinary(gTrue); +} + +//------------------------------------------------------------------------ +// ASCIIHexEncoder +//------------------------------------------------------------------------ + +ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA): + FilterStream(strA) { + bufPtr = bufEnd = buf; + lineLen = 0; + eof = gFalse; +} + +ASCIIHexEncoder::~ASCIIHexEncoder() { + if (str->isEncoder()) { + delete str; + } +} + +void ASCIIHexEncoder::reset() { + str->reset(); + bufPtr = bufEnd = buf; + lineLen = 0; + eof = gFalse; +} + +GBool ASCIIHexEncoder::fillBuf() { + static char *hex = "0123456789abcdef"; + int c; + + if (eof) { + return gFalse; + } + bufPtr = bufEnd = buf; + if ((c = str->getChar()) == EOF) { + *bufEnd++ = '>'; + eof = gTrue; + } else { + if (lineLen >= 64) { + *bufEnd++ = '\n'; + lineLen = 0; + } + *bufEnd++ = hex[(c >> 4) & 0x0f]; + *bufEnd++ = hex[c & 0x0f]; + lineLen += 2; + } + return gTrue; +} + +//------------------------------------------------------------------------ +// 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; +} + +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; +} + +// +// 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..1f22ee657 --- /dev/null +++ b/pdftops/Stream.h @@ -0,0 +1,846 @@ +//======================================================================== +// +// Stream.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef STREAM_H +#define STREAM_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include +#include "gtypes.h" +#include "Object.h" + +class Decrypt; +class BaseStream; + +//------------------------------------------------------------------------ + +enum StreamKind { + strFile, + strASCIIHex, + strASCII85, + strLZW, + strRunLength, + strCCITTFax, + strDCT, + strFlate, + strJBIG2, + strJPX, + strWeird // internal-use stream types +}; + +enum StreamColorSpaceMode { + streamCSNone, + streamCSDeviceGray, + streamCSDeviceRGB, + streamCSDeviceCMYK +}; + +//------------------------------------------------------------------------ +// 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. If is negative, the + // position is from the end of the file; otherwise the position is + // from the start of the file. + virtual void setPos(Guint pos, int dir = 0) = 0; + + // Get PostScript command for the filter(s). + virtual GString *getPSFilter(int psLevel, char *indent); + + // Does this stream type potentially contain non-printable chars? + virtual GBool isBinary(GBool last = gTrue) = 0; + + // Get the BaseStream 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; } + + // Get image parameters which are defined by the stream contents. + virtual void getImageParams(int *bitsPerComponent, + StreamColorSpaceMode *csMode) {} + + // Add filters to this stream according to the parameters in . + // 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(Guint start, GBool limited, + Guint length, Object *dict) = 0; + virtual void setPos(Guint pos, int dir = 0) = 0; + virtual GBool isBinary(GBool last = gTrue) { return last; } + virtual BaseStream *getBaseStream() { return this; } + virtual Dict *getDict() { return dict.getDict(); } + + // Get/set position of first byte of stream within the file. + virtual Guint getStart() = 0; + virtual void moveStart(int delta) = 0; + + // Set decryption for this stream. + virtual void doDecryption(Guchar *fileKey, int keyLength, + int objNum, int objGen); + +protected: + + Decrypt *decrypt; + +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(Guint pos, int dir = 0); + 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. should be able to hold + // at least nComps elements. Returns false at end of file. + GBool getPixel(Guchar *pix); + + // Returns a pointer to the next line of pixels. Returns NULL at + // end of file. + Guchar *getLine(); + + // 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(); + + GBool isOk() { return ok; } + + 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 + GBool ok; +}; + +//------------------------------------------------------------------------ +// FileStream +//------------------------------------------------------------------------ + +#define fileStreamBufSize 256 + +class FileStream: public BaseStream { +public: + + FileStream(FILE *fA, Guint startA, GBool limitedA, + Guint lengthA, Object *dictA); + virtual ~FileStream(); + virtual Stream *makeSubStream(Guint startA, GBool limitedA, + Guint 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(Guint pos, int dir = 0); + virtual Guint getStart() { return start; } + virtual void moveStart(int delta); + +private: + + GBool fillBuf(); + + FILE *f; + Guint start; + GBool limited; + Guint length; + char buf[fileStreamBufSize]; + char *bufPtr; + char *bufEnd; + Guint bufPos; + int savePos; + GBool saved; +}; + +//------------------------------------------------------------------------ +// MemStream +//------------------------------------------------------------------------ + +class MemStream: public BaseStream { +public: + + MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA); + virtual ~MemStream(); + virtual Stream *makeSubStream(Guint start, GBool limited, + Guint lengthA, Object *dictA); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual void close(); + virtual int getChar() + { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; } + virtual int lookChar() + { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } + virtual int getPos() { return (int)(bufPtr - buf); } + virtual void setPos(Guint pos, int dir = 0); + virtual Guint getStart() { return start; } + virtual void moveStart(int delta); + virtual void doDecryption(Guchar *fileKey, int keyLength, + int objNum, int objGen); + +private: + + char *buf; + Guint start; + Guint length; + char *bufEnd; + char *bufPtr; + GBool needFree; +}; + +//------------------------------------------------------------------------ +// 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, GBool limitedA, Guint lengthA); + virtual ~EmbedStream(); + virtual Stream *makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA); + virtual StreamKind getKind() { return str->getKind(); } + virtual void reset() {} + virtual int getChar(); + virtual int lookChar(); + virtual int getPos() { return str->getPos(); } + virtual void setPos(Guint pos, int dir = 0); + virtual Guint getStart(); + virtual void moveStart(int delta); + +private: + + Stream *str; + GBool limited; + Guint length; +}; + +//------------------------------------------------------------------------ +// 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(int psLevel, 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(int psLevel, 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(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + +private: + + StreamPredictor *pred; // predictor + int early; // early parameter + GBool eof; // true if at eof + int inputBuf; // input buffer + int inputBits; // number of bits in input buffer + struct { // decoding table + int length; + int head; + Guchar tail; + } table[4097]; + int nextCode; // next code to be used + int nextBits; // number of bits in next code word + int prevCode; // previous code used in stream + int newChar; // next char to be added to table + Guchar seqBuf[4097]; // buffer for current sequence + int seqLength; // length of current sequence + int seqIndex; // index into current sequence + GBool first; // first code after a table clear + + GBool processNextCode(); + void clearTable(); + int getCode(); +}; + +//------------------------------------------------------------------------ +// 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(int psLevel, 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(int psLevel, 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 + int hSample, vSample; // horiz/vert sampling resolutions + int quantTable; // quantization table number + int prevDC; // DC coefficient accumulator +}; + +struct DCTScanInfo { + GBool comp[4]; // comp[i] is set if component i is + // included in this scan + int numComps; // number of components in the scan + int dcHuffTable[4]; // DC Huffman table numbers + int acHuffTable[4]; // AC Huffman table numbers + int firstCoeff, lastCoeff; // first and last DCT coefficient + int ah, al; // successive approximation parameters +}; + +// 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(int psLevel, char *indent); + virtual GBool isBinary(GBool last = gTrue); + Stream *getRawStream() { return str; } + +private: + + GBool progressive; // set if in progressive mode + GBool interleaved; // set if in interleaved mode + int width, height; // image size + int mcuWidth, mcuHeight; // size of min coding unit, in data units + int bufWidth, bufHeight; // frameBuf size + DCTCompInfo compInfo[4]; // info for each component + DCTScanInfo scanInfo; // info for the current scan + int numComps; // number of components in image + int colorXform; // need YCbCr-to-RGB transform? + GBool gotJFIFMarker; // set if APP0 JFIF marker was present + GBool gotAdobeMarker; // set if APP14 Adobe marker was present + int restartInterval; // restart interval, in MCUs + Gushort 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 (non-progressive mode) + int *frameBuf[4]; // buffer for frame (progressive mode) + int comp, x, y, dy; // current position within image/MCU + int restartCtr; // MCUs left until restart + int restartMarker; // next restart marker + int eobRun; // number of EOBs left in the current run + int inputBuf; // input buffer for variable length codes + int inputBits; // number of valid bits in input buffer + + void restart(); + GBool readMCURow(); + void readScan(); + GBool readDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]); + GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable, + DCTHuffTable *acHuffTable, + int *prevDC, int data[64]); + void decodeImage(); + void transformDataUnit(Gushort *quantTable, + int dataIn[64], Guchar dataOut[64]); + int readHuffSym(DCTHuffTable *table); + int readAmp(int size); + int readBit(); + GBool readHeader(); + GBool readBaselineSOF(); + GBool readProgressiveSOF(); + GBool readScanInfo(); + GBool readQuantTables(); + GBool readHuffmanTables(); + GBool readRestartInterval(); + GBool readJFIFMarker(); + 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 { + Gushort len; // code length, in bits + Gushort val; // value represented by this code +}; + +struct FlateHuffmanTab { + FlateCode *codes; + int maxLen; +}; + +// 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(int psLevel, 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 + int // literal and distance code lengths + codeLengths[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]; + static FlateHuffmanTab // fixed literal code table + fixedLitCodeTab; + static FlateHuffmanTab // fixed distance code table + fixedDistCodeTab; + + void readSome(); + GBool startBlock(); + void loadFixedCodes(); + GBool readDynamicCodes(); + void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab); + 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(int psLevel, 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 int getChar(); + virtual int lookChar(); + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } + virtual GBool isBinary(GBool last = gTrue); + virtual GBool isEncoder() { return gTrue; } + +private: + + int length; + int count; +}; + +//------------------------------------------------------------------------ +// ASCIIHexEncoder +//------------------------------------------------------------------------ + +class ASCIIHexEncoder: public FilterStream { +public: + + ASCIIHexEncoder(Stream *strA); + virtual ~ASCIIHexEncoder(); + virtual StreamKind getKind() { return strWeird; } + 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(int psLevel, char *indent) { return NULL; } + virtual GBool isBinary(GBool last = gTrue) { return gFalse; } + virtual GBool isEncoder() { return gTrue; } + +private: + + char buf[4]; + char *bufPtr; + char *bufEnd; + int lineLen; + GBool eof; + + GBool fillBuf(); +}; + +//------------------------------------------------------------------------ +// ASCII85Encoder +//------------------------------------------------------------------------ + +class ASCII85Encoder: public FilterStream { +public: + + ASCII85Encoder(Stream *strA); + virtual ~ASCII85Encoder(); + virtual StreamKind getKind() { return strWeird; } + 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(int psLevel, 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 int getChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } + virtual int lookChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } + virtual GBool isBinary(GBool last = gTrue) { return gTrue; } + virtual GBool isEncoder() { return gTrue; } + +private: + + char buf[131]; + char *bufPtr; + char *bufEnd; + char *nextEnd; + GBool eof; + + GBool fillBuf(); +}; + +#endif diff --git a/pdftops/UTF8.h b/pdftops/UTF8.h new file mode 100644 index 000000000..8536dbf94 --- /dev/null +++ b/pdftops/UTF8.h @@ -0,0 +1,56 @@ +//======================================================================== +// +// UTF8.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +static int mapUTF8(Unicode u, char *buf, int bufSize) { + if (u <= 0x0000007f) { + if (bufSize < 1) { + return 0; + } + buf[0] = (char)u; + return 1; + } else if (u <= 0x000007ff) { + if (bufSize < 2) { + return 0; + } + buf[0] = (char)(0xc0 + (u >> 6)); + buf[1] = (char)(0x80 + (u & 0x3f)); + return 2; + } else if (u <= 0x0000ffff) { + if (bufSize < 3) { + return 0; + } + buf[0] = (char)(0xe0 + (u >> 12)); + buf[1] = (char)(0x80 + ((u >> 6) & 0x3f)); + buf[2] = (char)(0x80 + (u & 0x3f)); + return 3; + } else if (u <= 0x0010ffff) { + if (bufSize < 4) { + return 0; + } + buf[0] = (char)(0xf0 + (u >> 18)); + buf[1] = (char)(0x80 + ((u >> 12) & 0x3f)); + buf[2] = (char)(0x80 + ((u >> 6) & 0x3f)); + buf[3] = (char)(0x80 + (u & 0x3f)); + return 4; + } else { + return 0; + } +} + +static int mapUCS2(Unicode u, char *buf, int bufSize) { + if (u <= 0xffff) { + if (bufSize < 2) { + return 0; + } + buf[0] = (char)((u >> 8) & 0xff); + buf[1] = (char)(u & 0xff); + return 2; + } else { + return 0; + } +} diff --git a/pdftops/UnicodeMap.cxx b/pdftops/UnicodeMap.cxx new file mode 100644 index 000000000..de4683c30 --- /dev/null +++ b/pdftops/UnicodeMap.cxx @@ -0,0 +1,293 @@ +//======================================================================== +// +// UnicodeMap.cc +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include "gmem.h" +#include "gfile.h" +#include "GString.h" +#include "GList.h" +#include "Error.h" +#include "GlobalParams.h" +#include "UnicodeMap.h" + +//------------------------------------------------------------------------ + +#define maxExtCode 16 + +struct UnicodeMapExt { + Unicode u; // Unicode char + char code[maxExtCode]; + Guint nBytes; +}; + +//------------------------------------------------------------------------ + +UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { + FILE *f; + UnicodeMap *map; + UnicodeMapRange *range; + UnicodeMapExt *eMap; + int size, eMapsSize; + char buf[256]; + int line, nBytes, i, x; + char *tok1, *tok2, *tok3; + + if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) { + error(-1, "Couldn't find unicodeMap file for the '%s' encoding", + encodingNameA->getCString()); + return NULL; + } + + map = new UnicodeMap(encodingNameA->copy()); + + size = 8; + map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange)); + eMapsSize = 0; + + line = 1; + while (getLine(buf, sizeof(buf), f)) { + if ((tok1 = strtok(buf, " \t\r\n")) && + (tok2 = strtok(NULL, " \t\r\n"))) { + if (!(tok3 = strtok(NULL, " \t\r\n"))) { + tok3 = tok2; + tok2 = tok1; + } + nBytes = strlen(tok3) / 2; + if (nBytes <= 4) { + if (map->len == size) { + size *= 2; + map->ranges = (UnicodeMapRange *) + greallocn(map->ranges, size, sizeof(UnicodeMapRange)); + } + range = &map->ranges[map->len]; + sscanf(tok1, "%x", &range->start); + sscanf(tok2, "%x", &range->end); + sscanf(tok3, "%x", &range->code); + range->nBytes = nBytes; + ++map->len; + } else if (tok2 == tok1) { + if (map->eMapsLen == eMapsSize) { + eMapsSize += 16; + map->eMaps = (UnicodeMapExt *) + greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt)); + } + eMap = &map->eMaps[map->eMapsLen]; + sscanf(tok1, "%x", &eMap->u); + for (i = 0; i < nBytes; ++i) { + sscanf(tok3 + i*2, "%2x", &x); + eMap->code[i] = (char)x; + } + eMap->nBytes = nBytes; + ++map->eMapsLen; + } else { + error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding", + line, encodingNameA->getCString()); + } + } else { + error(-1, "Bad line (%d) in unicodeMap file for the '%s' encoding", + line, encodingNameA->getCString()); + } + ++line; + } + + fclose(f); + + return map; +} + +UnicodeMap::UnicodeMap(GString *encodingNameA) { + encodingName = encodingNameA; + unicodeOut = gFalse; + kind = unicodeMapUser; + ranges = NULL; + len = 0; + eMaps = NULL; + eMapsLen = 0; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapRange *rangesA, int lenA) { + encodingName = new GString(encodingNameA); + unicodeOut = unicodeOutA; + kind = unicodeMapResident; + ranges = rangesA; + len = lenA; + eMaps = NULL; + eMapsLen = 0; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapFunc funcA) { + encodingName = new GString(encodingNameA); + unicodeOut = unicodeOutA; + kind = unicodeMapFunc; + func = funcA; + eMaps = NULL; + eMapsLen = 0; + refCnt = 1; +#if MULTITHREADED + gInitMutex(&mutex); +#endif +} + +UnicodeMap::~UnicodeMap() { + delete encodingName; + if (kind == unicodeMapUser && ranges) { + gfree(ranges); + } + if (eMaps) { + gfree(eMaps); + } +#if MULTITHREADED + gDestroyMutex(&mutex); +#endif +} + +void UnicodeMap::incRefCnt() { +#if MULTITHREADED + gLockMutex(&mutex); +#endif + ++refCnt; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif +} + +void UnicodeMap::decRefCnt() { + GBool done; + +#if MULTITHREADED + gLockMutex(&mutex); +#endif + done = --refCnt == 0; +#if MULTITHREADED + gUnlockMutex(&mutex); +#endif + if (done) { + delete this; + } +} + +GBool UnicodeMap::match(GString *encodingNameA) { + return !encodingName->cmp(encodingNameA); +} + +int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) { + int a, b, m, n, i, j; + Guint code; + + if (kind == unicodeMapFunc) { + return (*func)(u, buf, bufSize); + } + + a = 0; + b = len; + if (u >= ranges[a].start) { + // invariant: ranges[a].start <= u < ranges[b].start + while (b - a > 1) { + m = (a + b) / 2; + if (u >= ranges[m].start) { + a = m; + } else if (u < ranges[m].start) { + b = m; + } + } + if (u <= ranges[a].end) { + n = ranges[a].nBytes; + if (n > bufSize) { + return 0; + } + code = ranges[a].code + (u - ranges[a].start); + for (i = n - 1; i >= 0; --i) { + buf[i] = (char)(code & 0xff); + code >>= 8; + } + return n; + } + } + + for (i = 0; i < eMapsLen; ++i) { + if (eMaps[i].u == u) { + n = eMaps[i].nBytes; + for (j = 0; j < n; ++j) { + buf[j] = eMaps[i].code[j]; + } + return n; + } + } + + return 0; +} + +//------------------------------------------------------------------------ + +UnicodeMapCache::UnicodeMapCache() { + int i; + + for (i = 0; i < unicodeMapCacheSize; ++i) { + cache[i] = NULL; + } +} + +UnicodeMapCache::~UnicodeMapCache() { + int i; + + for (i = 0; i < unicodeMapCacheSize; ++i) { + if (cache[i]) { + cache[i]->decRefCnt(); + } + } +} + +UnicodeMap *UnicodeMapCache::getUnicodeMap(GString *encodingName) { + UnicodeMap *map; + int i, j; + + if (cache[0] && cache[0]->match(encodingName)) { + cache[0]->incRefCnt(); + return cache[0]; + } + for (i = 1; i < unicodeMapCacheSize; ++i) { + if (cache[i] && cache[i]->match(encodingName)) { + map = cache[i]; + for (j = i; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = map; + map->incRefCnt(); + return map; + } + } + if ((map = UnicodeMap::parse(encodingName))) { + if (cache[unicodeMapCacheSize - 1]) { + cache[unicodeMapCacheSize - 1]->decRefCnt(); + } + for (j = unicodeMapCacheSize - 1; j >= 1; --j) { + cache[j] = cache[j - 1]; + } + cache[0] = map; + map->incRefCnt(); + return map; + } + return NULL; +} diff --git a/pdftops/UnicodeMap.h b/pdftops/UnicodeMap.h new file mode 100644 index 000000000..07dd01ccf --- /dev/null +++ b/pdftops/UnicodeMap.h @@ -0,0 +1,123 @@ +//======================================================================== +// +// UnicodeMap.h +// +// Mapping from Unicode to an encoding. +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef UNICODEMAP_H +#define UNICODEMAP_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "CharTypes.h" + +#if MULTITHREADED +#include "GMutex.h" +#endif + +class GString; + +//------------------------------------------------------------------------ + +enum UnicodeMapKind { + unicodeMapUser, // read from a file + unicodeMapResident, // static list of ranges + unicodeMapFunc // function pointer +}; + +typedef int (*UnicodeMapFunc)(Unicode u, char *buf, int bufSize); + +struct UnicodeMapRange { + Unicode start, end; // range of Unicode chars + Guint code, nBytes; // first output code +}; + +struct UnicodeMapExt; + +//------------------------------------------------------------------------ + +class UnicodeMap { +public: + + // Create the UnicodeMap specified by . Sets the + // initial reference count to 1. Returns NULL on failure. + static UnicodeMap *parse(GString *encodingNameA); + + // Create a resident UnicodeMap. + UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapRange *rangesA, int lenA); + + // Create a resident UnicodeMap that uses a function instead of a + // list of ranges. + UnicodeMap(char *encodingNameA, GBool unicodeOutA, + UnicodeMapFunc funcA); + + ~UnicodeMap(); + + void incRefCnt(); + void decRefCnt(); + + GString *getEncodingName() { return encodingName; } + + GBool isUnicode() { return unicodeOut; } + + // Return true if this UnicodeMap matches the specified + // . + GBool match(GString *encodingNameA); + + // Map Unicode to the target encoding. Fills in with the + // output and returns the number of bytes used. Output will be + // truncated at bytes. No string terminator is written. + // Returns 0 if no mapping is found. + int mapUnicode(Unicode u, char *buf, int bufSize); + +private: + + UnicodeMap(GString *encodingNameA); + + GString *encodingName; + UnicodeMapKind kind; + GBool unicodeOut; + union { + UnicodeMapRange *ranges; // (user, resident) + UnicodeMapFunc func; // (func) + }; + int len; // (user, resident) + UnicodeMapExt *eMaps; // (user) + int eMapsLen; // (user) + int refCnt; +#if MULTITHREADED + GMutex mutex; +#endif +}; + +//------------------------------------------------------------------------ + +#define unicodeMapCacheSize 4 + +class UnicodeMapCache { +public: + + UnicodeMapCache(); + ~UnicodeMapCache(); + + // Get the UnicodeMap for . Increments its reference + // count; there will be one reference for the cache plus one for the + // caller of this function. Returns NULL on failure. + UnicodeMap *getUnicodeMap(GString *encodingName); + +private: + + UnicodeMap *cache[unicodeMapCacheSize]; +}; + +#endif diff --git a/pdftops/UnicodeMapTables.h b/pdftops/UnicodeMapTables.h new file mode 100644 index 000000000..9c5103461 --- /dev/null +++ b/pdftops/UnicodeMapTables.h @@ -0,0 +1,361 @@ +//======================================================================== +// +// UnicodeMapTables.h +// +// Copyright 2001-2003 Glyph & Cog, LLC +// +//======================================================================== + +static UnicodeMapRange latin1UnicodeMapRanges[] = { + { 0x000a, 0x000a, 0x0a, 1 }, + { 0x000c, 0x000d, 0x0c, 1 }, + { 0x0020, 0x007e, 0x20, 1 }, + { 0x00a0, 0x00a0, 0x20, 1 }, + { 0x00a1, 0x00ac, 0xa1, 1 }, + { 0x00ae, 0x00ff, 0xae, 1 }, + { 0x010c, 0x010c, 0x43, 1 }, + { 0x010d, 0x010d, 0x63, 1 }, + { 0x0131, 0x0131, 0x69, 1 }, + { 0x0141, 0x0141, 0x4c, 1 }, + { 0x0142, 0x0142, 0x6c, 1 }, + { 0x0152, 0x0152, 0x4f45, 2 }, + { 0x0153, 0x0153, 0x6f65, 2 }, + { 0x0160, 0x0160, 0x53, 1 }, + { 0x0161, 0x0161, 0x73, 1 }, + { 0x0178, 0x0178, 0x59, 1 }, + { 0x017d, 0x017d, 0x5a, 1 }, + { 0x017e, 0x017e, 0x7a, 1 }, + { 0x02c6, 0x02c6, 0x5e, 1 }, + { 0x02da, 0x02da, 0xb0, 1 }, + { 0x02dc, 0x02dc, 0x7e, 1 }, + { 0x2013, 0x2013, 0xad, 1 }, + { 0x2014, 0x2014, 0x2d2d, 2 }, + { 0x2018, 0x2018, 0x60, 1 }, + { 0x2019, 0x2019, 0x27, 1 }, + { 0x201a, 0x201a, 0x2c, 1 }, + { 0x201c, 0x201c, 0x22, 1 }, + { 0x201d, 0x201d, 0x22, 1 }, + { 0x201e, 0x201e, 0x2c2c, 2 }, + { 0x2022, 0x2022, 0xb7, 1 }, + { 0x2026, 0x2026, 0x2e2e2e, 3 }, + { 0x2039, 0x2039, 0x3c, 1 }, + { 0x203a, 0x203a, 0x3e, 1 }, + { 0x2044, 0x2044, 0x2f, 1 }, + { 0x2122, 0x2122, 0x544d, 2 }, + { 0x2212, 0x2212, 0x2d, 1 }, + { 0xf6f9, 0xf6f9, 0x4c, 1 }, + { 0xf6fa, 0xf6fa, 0x4f45, 2 }, + { 0xf6fc, 0xf6fc, 0xb0, 1 }, + { 0xf6fd, 0xf6fd, 0x53, 1 }, + { 0xf6fe, 0xf6fe, 0x7e, 1 }, + { 0xf6ff, 0xf6ff, 0x5a, 1 }, + { 0xf721, 0xf721, 0x21, 1 }, + { 0xf724, 0xf724, 0x24, 1 }, + { 0xf726, 0xf726, 0x26, 1 }, + { 0xf730, 0xf739, 0x30, 1 }, + { 0xf73f, 0xf73f, 0x3f, 1 }, + { 0xf761, 0xf77a, 0x41, 1 }, + { 0xf7a1, 0xf7a2, 0xa1, 1 }, + { 0xf7bf, 0xf7bf, 0xbf, 1 }, + { 0xf7e0, 0xf7f6, 0xc0, 1 }, + { 0xf7f8, 0xf7fe, 0xd8, 1 }, + { 0xf7ff, 0xf7ff, 0x59, 1 }, + { 0xfb00, 0xfb00, 0x6666, 2 }, + { 0xfb01, 0xfb01, 0x6669, 2 }, + { 0xfb02, 0xfb02, 0x666c, 2 }, + { 0xfb03, 0xfb03, 0x666669, 3 }, + { 0xfb04, 0xfb04, 0x66666c, 3 } +}; +#define latin1UnicodeMapLen (sizeof(latin1UnicodeMapRanges) / sizeof(UnicodeMapRange)) + +static UnicodeMapRange ascii7UnicodeMapRanges[] = { + { 0x000a, 0x000a, 0x0a, 1 }, + { 0x000c, 0x000d, 0x0c, 1 }, + { 0x0020, 0x005f, 0x20, 1 }, + { 0x0061, 0x007e, 0x61, 1 }, + { 0x00a6, 0x00a6, 0x7c, 1 }, + { 0x00a9, 0x00a9, 0x286329, 3 }, + { 0x00ae, 0x00ae, 0x285229, 3 }, + { 0x00b7, 0x00b7, 0x2a, 1 }, + { 0x00bc, 0x00bc, 0x312f34, 3 }, + { 0x00bd, 0x00bd, 0x312f32, 3 }, + { 0x00be, 0x00be, 0x332f34, 3 }, + { 0x00c0, 0x00c0, 0x41, 1 }, + { 0x00c1, 0x00c1, 0x41, 1 }, + { 0x00c2, 0x00c2, 0x41, 1 }, + { 0x00c3, 0x00c3, 0x41, 1 }, + { 0x00c4, 0x00c4, 0x41, 1 }, + { 0x00c5, 0x00c5, 0x41, 1 }, + { 0x00c6, 0x00c6, 0x4145, 2 }, + { 0x00c7, 0x00c7, 0x43, 1 }, + { 0x00c8, 0x00c8, 0x45, 1 }, + { 0x00c9, 0x00c9, 0x45, 1 }, + { 0x00ca, 0x00ca, 0x45, 1 }, + { 0x00cb, 0x00cb, 0x45, 1 }, + { 0x00cc, 0x00cc, 0x49, 1 }, + { 0x00cd, 0x00cd, 0x49, 1 }, + { 0x00ce, 0x00ce, 0x49, 1 }, + { 0x00cf, 0x00cf, 0x49, 1 }, + { 0x00d1, 0x00d2, 0x4e, 1 }, + { 0x00d3, 0x00d3, 0x4f, 1 }, + { 0x00d4, 0x00d4, 0x4f, 1 }, + { 0x00d5, 0x00d5, 0x4f, 1 }, + { 0x00d6, 0x00d6, 0x4f, 1 }, + { 0x00d7, 0x00d7, 0x78, 1 }, + { 0x00d8, 0x00d8, 0x4f, 1 }, + { 0x00d9, 0x00d9, 0x55, 1 }, + { 0x00da, 0x00da, 0x55, 1 }, + { 0x00db, 0x00db, 0x55, 1 }, + { 0x00dc, 0x00dc, 0x55, 1 }, + { 0x00dd, 0x00dd, 0x59, 1 }, + { 0x00e0, 0x00e0, 0x61, 1 }, + { 0x00e1, 0x00e1, 0x61, 1 }, + { 0x00e2, 0x00e2, 0x61, 1 }, + { 0x00e3, 0x00e3, 0x61, 1 }, + { 0x00e4, 0x00e4, 0x61, 1 }, + { 0x00e5, 0x00e5, 0x61, 1 }, + { 0x00e6, 0x00e6, 0x6165, 2 }, + { 0x00e7, 0x00e7, 0x63, 1 }, + { 0x00e8, 0x00e8, 0x65, 1 }, + { 0x00e9, 0x00e9, 0x65, 1 }, + { 0x00ea, 0x00ea, 0x65, 1 }, + { 0x00eb, 0x00eb, 0x65, 1 }, + { 0x00ec, 0x00ec, 0x69, 1 }, + { 0x00ed, 0x00ed, 0x69, 1 }, + { 0x00ee, 0x00ee, 0x69, 1 }, + { 0x00ef, 0x00ef, 0x69, 1 }, + { 0x00f1, 0x00f2, 0x6e, 1 }, + { 0x00f3, 0x00f3, 0x6f, 1 }, + { 0x00f4, 0x00f4, 0x6f, 1 }, + { 0x00f5, 0x00f5, 0x6f, 1 }, + { 0x00f6, 0x00f6, 0x6f, 1 }, + { 0x00f7, 0x00f7, 0x2f, 1 }, + { 0x00f8, 0x00f8, 0x6f, 1 }, + { 0x00f9, 0x00f9, 0x75, 1 }, + { 0x00fa, 0x00fa, 0x75, 1 }, + { 0x00fb, 0x00fb, 0x75, 1 }, + { 0x00fc, 0x00fc, 0x75, 1 }, + { 0x00fd, 0x00fd, 0x79, 1 }, + { 0x00ff, 0x00ff, 0x79, 1 }, + { 0x0131, 0x0131, 0x69, 1 }, + { 0x0141, 0x0141, 0x4c, 1 }, + { 0x0152, 0x0152, 0x4f45, 2 }, + { 0x0153, 0x0153, 0x6f65, 2 }, + { 0x0160, 0x0160, 0x53, 1 }, + { 0x0178, 0x0178, 0x59, 1 }, + { 0x017d, 0x017d, 0x5a, 1 }, + { 0x2013, 0x2013, 0x2d, 1 }, + { 0x2014, 0x2014, 0x2d2d, 2 }, + { 0x2018, 0x2018, 0x60, 1 }, + { 0x2019, 0x2019, 0x27, 1 }, + { 0x201c, 0x201c, 0x22, 1 }, + { 0x201d, 0x201d, 0x22, 1 }, + { 0x2022, 0x2022, 0x2a, 1 }, + { 0x2026, 0x2026, 0x2e2e2e, 3 }, + { 0x2122, 0x2122, 0x544d, 2 }, + { 0x2212, 0x2212, 0x2d, 1 }, + { 0xf6f9, 0xf6f9, 0x4c, 1 }, + { 0xf6fa, 0xf6fa, 0x4f45, 2 }, + { 0xf6fd, 0xf6fd, 0x53, 1 }, + { 0xf6fe, 0xf6fe, 0x7e, 1 }, + { 0xf6ff, 0xf6ff, 0x5a, 1 }, + { 0xf721, 0xf721, 0x21, 1 }, + { 0xf724, 0xf724, 0x24, 1 }, + { 0xf726, 0xf726, 0x26, 1 }, + { 0xf730, 0xf739, 0x30, 1 }, + { 0xf73f, 0xf73f, 0x3f, 1 }, + { 0xf761, 0xf77a, 0x41, 1 }, + { 0xf7e0, 0xf7e0, 0x41, 1 }, + { 0xf7e1, 0xf7e1, 0x41, 1 }, + { 0xf7e2, 0xf7e2, 0x41, 1 }, + { 0xf7e3, 0xf7e3, 0x41, 1 }, + { 0xf7e4, 0xf7e4, 0x41, 1 }, + { 0xf7e5, 0xf7e5, 0x41, 1 }, + { 0xf7e6, 0xf7e6, 0x4145, 2 }, + { 0xf7e7, 0xf7e7, 0x43, 1 }, + { 0xf7e8, 0xf7e8, 0x45, 1 }, + { 0xf7e9, 0xf7e9, 0x45, 1 }, + { 0xf7ea, 0xf7ea, 0x45, 1 }, + { 0xf7eb, 0xf7eb, 0x45, 1 }, + { 0xf7ec, 0xf7ec, 0x49, 1 }, + { 0xf7ed, 0xf7ed, 0x49, 1 }, + { 0xf7ee, 0xf7ee, 0x49, 1 }, + { 0xf7ef, 0xf7ef, 0x49, 1 }, + { 0xf7f1, 0xf7f2, 0x4e, 1 }, + { 0xf7f3, 0xf7f3, 0x4f, 1 }, + { 0xf7f4, 0xf7f4, 0x4f, 1 }, + { 0xf7f5, 0xf7f5, 0x4f, 1 }, + { 0xf7f6, 0xf7f6, 0x4f, 1 }, + { 0xf7f8, 0xf7f8, 0x4f, 1 }, + { 0xf7f9, 0xf7f9, 0x55, 1 }, + { 0xf7fa, 0xf7fa, 0x55, 1 }, + { 0xf7fb, 0xf7fb, 0x55, 1 }, + { 0xf7fc, 0xf7fc, 0x55, 1 }, + { 0xf7fd, 0xf7fd, 0x59, 1 }, + { 0xf7ff, 0xf7ff, 0x59, 1 }, + { 0xfb00, 0xfb00, 0x6666, 2 }, + { 0xfb01, 0xfb01, 0x6669, 2 }, + { 0xfb02, 0xfb02, 0x666c, 2 }, + { 0xfb03, 0xfb03, 0x666669, 3 }, + { 0xfb04, 0xfb04, 0x66666c, 3 } +}; +#define ascii7UnicodeMapLen (sizeof(ascii7UnicodeMapRanges) / sizeof(UnicodeMapRange)) + +static UnicodeMapRange symbolUnicodeMapRanges[] = { + { 0x0020, 0x0021, 0x20, 1 }, + { 0x0023, 0x0023, 0x23, 1 }, + { 0x0025, 0x0026, 0x25, 1 }, + { 0x0028, 0x0029, 0x28, 1 }, + { 0x002b, 0x002c, 0x2b, 1 }, + { 0x002e, 0x003f, 0x2e, 1 }, + { 0x005b, 0x005b, 0x5b, 1 }, + { 0x005d, 0x005d, 0x5d, 1 }, + { 0x005f, 0x005f, 0x5f, 1 }, + { 0x007b, 0x007d, 0x7b, 1 }, + { 0x00ac, 0x00ac, 0xd8, 1 }, + { 0x00b0, 0x00b1, 0xb0, 1 }, + { 0x00b5, 0x00b5, 0x6d, 1 }, + { 0x00d7, 0x00d7, 0xb4, 1 }, + { 0x00f7, 0x00f7, 0xb8, 1 }, + { 0x0192, 0x0192, 0xa6, 1 }, + { 0x0391, 0x0392, 0x41, 1 }, + { 0x0393, 0x0393, 0x47, 1 }, + { 0x0395, 0x0395, 0x45, 1 }, + { 0x0396, 0x0396, 0x5a, 1 }, + { 0x0397, 0x0397, 0x48, 1 }, + { 0x0398, 0x0398, 0x51, 1 }, + { 0x0399, 0x0399, 0x49, 1 }, + { 0x039a, 0x039d, 0x4b, 1 }, + { 0x039e, 0x039e, 0x58, 1 }, + { 0x039f, 0x03a0, 0x4f, 1 }, + { 0x03a1, 0x03a1, 0x52, 1 }, + { 0x03a3, 0x03a5, 0x53, 1 }, + { 0x03a6, 0x03a6, 0x46, 1 }, + { 0x03a7, 0x03a7, 0x43, 1 }, + { 0x03a8, 0x03a8, 0x59, 1 }, + { 0x03b1, 0x03b2, 0x61, 1 }, + { 0x03b3, 0x03b3, 0x67, 1 }, + { 0x03b4, 0x03b5, 0x64, 1 }, + { 0x03b6, 0x03b6, 0x7a, 1 }, + { 0x03b7, 0x03b7, 0x68, 1 }, + { 0x03b8, 0x03b8, 0x71, 1 }, + { 0x03b9, 0x03b9, 0x69, 1 }, + { 0x03ba, 0x03bb, 0x6b, 1 }, + { 0x03bd, 0x03bd, 0x6e, 1 }, + { 0x03be, 0x03be, 0x78, 1 }, + { 0x03bf, 0x03c0, 0x6f, 1 }, + { 0x03c1, 0x03c1, 0x72, 1 }, + { 0x03c2, 0x03c2, 0x56, 1 }, + { 0x03c3, 0x03c5, 0x73, 1 }, + { 0x03c6, 0x03c6, 0x66, 1 }, + { 0x03c7, 0x03c7, 0x63, 1 }, + { 0x03c8, 0x03c8, 0x79, 1 }, + { 0x03c9, 0x03c9, 0x77, 1 }, + { 0x03d1, 0x03d1, 0x4a, 1 }, + { 0x03d2, 0x03d2, 0xa1, 1 }, + { 0x03d5, 0x03d5, 0x6a, 1 }, + { 0x03d6, 0x03d6, 0x76, 1 }, + { 0x2022, 0x2022, 0xb7, 1 }, + { 0x2026, 0x2026, 0xbc, 1 }, + { 0x2032, 0x2032, 0xa2, 1 }, + { 0x2033, 0x2033, 0xb2, 1 }, + { 0x2044, 0x2044, 0xa4, 1 }, + { 0x2111, 0x2111, 0xc1, 1 }, + { 0x2118, 0x2118, 0xc3, 1 }, + { 0x211c, 0x211c, 0xc2, 1 }, + { 0x2126, 0x2126, 0x57, 1 }, + { 0x2135, 0x2135, 0xc0, 1 }, + { 0x2190, 0x2193, 0xac, 1 }, + { 0x2194, 0x2194, 0xab, 1 }, + { 0x21b5, 0x21b5, 0xbf, 1 }, + { 0x21d0, 0x21d3, 0xdc, 1 }, + { 0x21d4, 0x21d4, 0xdb, 1 }, + { 0x2200, 0x2200, 0x22, 1 }, + { 0x2202, 0x2202, 0xb6, 1 }, + { 0x2203, 0x2203, 0x24, 1 }, + { 0x2205, 0x2205, 0xc6, 1 }, + { 0x2206, 0x2206, 0x44, 1 }, + { 0x2207, 0x2207, 0xd1, 1 }, + { 0x2208, 0x2209, 0xce, 1 }, + { 0x220b, 0x220b, 0x27, 1 }, + { 0x220f, 0x220f, 0xd5, 1 }, + { 0x2211, 0x2211, 0xe5, 1 }, + { 0x2212, 0x2212, 0x2d, 1 }, + { 0x2217, 0x2217, 0x2a, 1 }, + { 0x221a, 0x221a, 0xd6, 1 }, + { 0x221d, 0x221d, 0xb5, 1 }, + { 0x221e, 0x221e, 0xa5, 1 }, + { 0x2220, 0x2220, 0xd0, 1 }, + { 0x2227, 0x2228, 0xd9, 1 }, + { 0x2229, 0x222a, 0xc7, 1 }, + { 0x222b, 0x222b, 0xf2, 1 }, + { 0x2234, 0x2234, 0x5c, 1 }, + { 0x223c, 0x223c, 0x7e, 1 }, + { 0x2245, 0x2245, 0x40, 1 }, + { 0x2248, 0x2248, 0xbb, 1 }, + { 0x2260, 0x2261, 0xb9, 1 }, + { 0x2264, 0x2264, 0xa3, 1 }, + { 0x2265, 0x2265, 0xb3, 1 }, + { 0x2282, 0x2282, 0xcc, 1 }, + { 0x2283, 0x2283, 0xc9, 1 }, + { 0x2284, 0x2284, 0xcb, 1 }, + { 0x2286, 0x2286, 0xcd, 1 }, + { 0x2287, 0x2287, 0xca, 1 }, + { 0x2295, 0x2295, 0xc5, 1 }, + { 0x2297, 0x2297, 0xc4, 1 }, + { 0x22a5, 0x22a5, 0x5e, 1 }, + { 0x22c5, 0x22c5, 0xd7, 1 }, + { 0x2320, 0x2320, 0xf3, 1 }, + { 0x2321, 0x2321, 0xf5, 1 }, + { 0x2329, 0x2329, 0xe1, 1 }, + { 0x232a, 0x232a, 0xf1, 1 }, + { 0x25ca, 0x25ca, 0xe0, 1 }, + { 0x2660, 0x2660, 0xaa, 1 }, + { 0x2663, 0x2663, 0xa7, 1 }, + { 0x2665, 0x2665, 0xa9, 1 }, + { 0x2666, 0x2666, 0xa8, 1 }, + { 0xf6d9, 0xf6d9, 0xd3, 1 }, + { 0xf6da, 0xf6da, 0xd2, 1 }, + { 0xf6db, 0xf6db, 0xd4, 1 }, + { 0xf8e5, 0xf8e5, 0x60, 1 }, + { 0xf8e6, 0xf8e7, 0xbd, 1 }, + { 0xf8e8, 0xf8ea, 0xe2, 1 }, + { 0xf8eb, 0xf8f4, 0xe6, 1 }, + { 0xf8f5, 0xf8f5, 0xf4, 1 }, + { 0xf8f6, 0xf8fe, 0xf6, 1 } +}; +#define symbolUnicodeMapLen (sizeof(symbolUnicodeMapRanges) / sizeof(UnicodeMapRange)) + +static UnicodeMapRange zapfDingbatsUnicodeMapRanges[] = { + { 0x0020, 0x0020, 0x20, 1 }, + { 0x2192, 0x2192, 0xd5, 1 }, + { 0x2194, 0x2195, 0xd6, 1 }, + { 0x2460, 0x2469, 0xac, 1 }, + { 0x25a0, 0x25a0, 0x6e, 1 }, + { 0x25b2, 0x25b2, 0x73, 1 }, + { 0x25bc, 0x25bc, 0x74, 1 }, + { 0x25c6, 0x25c6, 0x75, 1 }, + { 0x25cf, 0x25cf, 0x6c, 1 }, + { 0x25d7, 0x25d7, 0x77, 1 }, + { 0x2605, 0x2605, 0x48, 1 }, + { 0x260e, 0x260e, 0x25, 1 }, + { 0x261b, 0x261b, 0x2a, 1 }, + { 0x261e, 0x261e, 0x2b, 1 }, + { 0x2660, 0x2660, 0xab, 1 }, + { 0x2663, 0x2663, 0xa8, 1 }, + { 0x2665, 0x2665, 0xaa, 1 }, + { 0x2666, 0x2666, 0xa9, 1 }, + { 0x2701, 0x2704, 0x21, 1 }, + { 0x2706, 0x2709, 0x26, 1 }, + { 0x270c, 0x2727, 0x2c, 1 }, + { 0x2729, 0x274b, 0x49, 1 }, + { 0x274d, 0x274d, 0x6d, 1 }, + { 0x274f, 0x2752, 0x6f, 1 }, + { 0x2756, 0x2756, 0x76, 1 }, + { 0x2758, 0x275e, 0x78, 1 }, + { 0x2761, 0x2767, 0xa1, 1 }, + { 0x2776, 0x2794, 0xb6, 1 }, + { 0x2798, 0x27af, 0xd8, 1 }, + { 0x27b1, 0x27be, 0xf1, 1 } +}; +#define zapfDingbatsUnicodeMapLen (sizeof(zapfDingbatsUnicodeMapRanges) / sizeof(UnicodeMapRange)) diff --git a/pdftops/UnicodeTypeTable.cxx b/pdftops/UnicodeTypeTable.cxx new file mode 100644 index 000000000..9c4ea9f1e --- /dev/null +++ b/pdftops/UnicodeTypeTable.cxx @@ -0,0 +1,949 @@ +//======================================================================== +// +// UnicodeMapTables.cc +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#include +#include "CharTypes.h" +#include "UnicodeTypeTable.h" + +struct UnicodeMapTableEntry { + char *vector; + char type; +}; + +struct UnicodeCaseTableVector { + Unicode codes[256]; +}; + +static UnicodeMapTableEntry typeTable[256] = { + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNLNNNNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL", 'X' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLNNNNNNNNNNNNNNLLNNNNNNNNNNNNNNLLLLLNNNNNNNNNLNNNNNNNNNNNNNNNNN", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLNNNNNNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, + { "RRRRNNNNNNNNNRNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNRNNNNNNNRRNNNNNNNRRNNNNNNNNNNRRRRRR", 'X' }, + { "RRRRRRRRRRRRRRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'N' }, + { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLNNNNLLLLLLLLLLLLLNNLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNLLLLLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLNNLLLLLLLNNNNN", 'X' }, + { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLNNNNNNNNNNNNNNNN", 'X' }, + { "NNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLNLNNNLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNNNNLLLLLLLNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNLNNNNNLNNLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLNLLNNNNNNNNNNNLLLLLLLNLNLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "NNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLNNNNNLLLLLLNLLLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNNNLLLLLLLLLLLNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLNNNLLLLLLLLLLLLLNNN", 'X' }, + { "NNNNNNNNNNNNNNLRNNNNNNNNNNNNNNNNNNNNNNNNNNLRNLRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "NNLNNNNLNNLLLLLLLLLLNLNNNLLLLLNNNNNNLNLNLNLLLLNLLLNLLLLLLLNNLLLLNNNNNLLLLLNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'N' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'L' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { NULL, 'N' }, + { "NNNNNLLLNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNNNNNNNLLLLLNNLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLL", 'X' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { NULL, 'L' }, + { "LLLLLLLLLLLLLLLLLLLLLLLLRRRRRRNRRRRRRRRRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, + { NULL, 'R' }, + { "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, + { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLL", 'X' } +}; + +static UnicodeCaseTableVector caseTable00 = {{ + 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, 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, 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, 0x007f, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, + 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, + 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, + 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7, + 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, + 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, + 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7, + 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df, + 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 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 +}}; +static UnicodeCaseTableVector caseTable01 = {{ + 0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107, + 0x0109, 0x0109, 0x010b, 0x010b, 0x010d, 0x010d, 0x010f, 0x010f, + 0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117, + 0x0119, 0x0119, 0x011b, 0x011b, 0x011d, 0x011d, 0x011f, 0x011f, + 0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127, + 0x0129, 0x0129, 0x012b, 0x012b, 0x012d, 0x012d, 0x012f, 0x012f, + 0x0130, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137, + 0x0138, 0x013a, 0x013a, 0x013c, 0x013c, 0x013e, 0x013e, 0x0140, + 0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148, + 0x0148, 0x0149, 0x014b, 0x014b, 0x014d, 0x014d, 0x014f, 0x014f, + 0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157, + 0x0159, 0x0159, 0x015b, 0x015b, 0x015d, 0x015d, 0x015f, 0x015f, + 0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167, + 0x0169, 0x0169, 0x016b, 0x016b, 0x016d, 0x016d, 0x016f, 0x016f, + 0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177, + 0x00ff, 0x017a, 0x017a, 0x017c, 0x017c, 0x017e, 0x017e, 0x0073, + 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, + 0x0188, 0x0256, 0x0257, 0x018c, 0x018c, 0x018d, 0x01dd, 0x0259, + 0x025b, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, + 0x0199, 0x0199, 0x019a, 0x019b, 0x026f, 0x0272, 0x019e, 0x0275, + 0x01a1, 0x01a1, 0x01a3, 0x01a3, 0x01a5, 0x01a5, 0x0280, 0x01a8, + 0x01a8, 0x0283, 0x01aa, 0x01ab, 0x01ad, 0x01ad, 0x0288, 0x01b0, + 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b4, 0x01b6, 0x01b6, 0x0292, + 0x01b9, 0x01b9, 0x01ba, 0x01bb, 0x01bd, 0x01bd, 0x01be, 0x01bf, + 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c6, 0x01c6, 0x01c6, 0x01c9, + 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01cc, 0x01ce, 0x01ce, 0x01d0, + 0x01d0, 0x01d2, 0x01d2, 0x01d4, 0x01d4, 0x01d6, 0x01d6, 0x01d8, + 0x01d8, 0x01da, 0x01da, 0x01dc, 0x01dc, 0x01dd, 0x01df, 0x01df, + 0x01e1, 0x01e1, 0x01e3, 0x01e3, 0x01e5, 0x01e5, 0x01e7, 0x01e7, + 0x01e9, 0x01e9, 0x01eb, 0x01eb, 0x01ed, 0x01ed, 0x01ef, 0x01ef, + 0x01f0, 0x01f3, 0x01f3, 0x01f3, 0x01f5, 0x01f5, 0x0195, 0x01bf, + 0x01f9, 0x01f9, 0x01fb, 0x01fb, 0x01fd, 0x01fd, 0x01ff, 0x01ff +}}; +static UnicodeCaseTableVector caseTable02 = {{ + 0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207, + 0x0209, 0x0209, 0x020b, 0x020b, 0x020d, 0x020d, 0x020f, 0x020f, + 0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217, + 0x0219, 0x0219, 0x021b, 0x021b, 0x021d, 0x021d, 0x021f, 0x021f, + 0x019e, 0x0221, 0x0223, 0x0223, 0x0225, 0x0225, 0x0227, 0x0227, + 0x0229, 0x0229, 0x022b, 0x022b, 0x022d, 0x022d, 0x022f, 0x022f, + 0x0231, 0x0231, 0x0233, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237, + 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 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, 0x0257, + 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, + 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, + 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, + 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, + 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, + 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, + 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, + 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, + 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, + 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, + 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, + 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7, + 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, + 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, + 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, + 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, + 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df, + 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7, + 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, + 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, + 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff +}}; +static UnicodeCaseTableVector caseTable03 = {{ + 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, + 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, + 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, + 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, + 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, + 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, + 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, + 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, + 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x03b9, 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, 0x03ac, 0x0387, + 0x03ad, 0x03ae, 0x03af, 0x038b, 0x03cc, 0x038d, 0x03cd, 0x03ce, + 0x0390, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03a2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03ac, 0x03ad, 0x03ae, 0x03af, + 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, + 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, + 0x03c0, 0x03c1, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, + 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf, + 0x03b2, 0x03b8, 0x03d2, 0x03d3, 0x03d4, 0x03c6, 0x03c0, 0x03d7, + 0x03d9, 0x03d9, 0x03db, 0x03db, 0x03dd, 0x03dd, 0x03df, 0x03df, + 0x03e1, 0x03e1, 0x03e3, 0x03e3, 0x03e5, 0x03e5, 0x03e7, 0x03e7, + 0x03e9, 0x03e9, 0x03eb, 0x03eb, 0x03ed, 0x03ed, 0x03ef, 0x03ef, + 0x03ba, 0x03c1, 0x03f2, 0x03f3, 0x03b8, 0x03b5, 0x03f6, 0x03f8, + 0x03f8, 0x03f2, 0x03fb, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff +}}; +static UnicodeCaseTableVector caseTable04 = {{ + 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, + 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, + 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, + 0x0469, 0x0469, 0x046b, 0x046b, 0x046d, 0x046d, 0x046f, 0x046f, + 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477, + 0x0479, 0x0479, 0x047b, 0x047b, 0x047d, 0x047d, 0x047f, 0x047f, + 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, + 0x0488, 0x0489, 0x048b, 0x048b, 0x048d, 0x048d, 0x048f, 0x048f, + 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, + 0x0499, 0x0499, 0x049b, 0x049b, 0x049d, 0x049d, 0x049f, 0x049f, + 0x04a1, 0x04a1, 0x04a3, 0x04a3, 0x04a5, 0x04a5, 0x04a7, 0x04a7, + 0x04a9, 0x04a9, 0x04ab, 0x04ab, 0x04ad, 0x04ad, 0x04af, 0x04af, + 0x04b1, 0x04b1, 0x04b3, 0x04b3, 0x04b5, 0x04b5, 0x04b7, 0x04b7, + 0x04b9, 0x04b9, 0x04bb, 0x04bb, 0x04bd, 0x04bd, 0x04bf, 0x04bf, + 0x04c0, 0x04c2, 0x04c2, 0x04c4, 0x04c4, 0x04c6, 0x04c6, 0x04c8, + 0x04c8, 0x04ca, 0x04ca, 0x04cc, 0x04cc, 0x04ce, 0x04ce, 0x04cf, + 0x04d1, 0x04d1, 0x04d3, 0x04d3, 0x04d5, 0x04d5, 0x04d7, 0x04d7, + 0x04d9, 0x04d9, 0x04db, 0x04db, 0x04dd, 0x04dd, 0x04df, 0x04df, + 0x04e1, 0x04e1, 0x04e3, 0x04e3, 0x04e5, 0x04e5, 0x04e7, 0x04e7, + 0x04e9, 0x04e9, 0x04eb, 0x04eb, 0x04ed, 0x04ed, 0x04ef, 0x04ef, + 0x04f1, 0x04f1, 0x04f3, 0x04f3, 0x04f5, 0x04f5, 0x04f6, 0x04f7, + 0x04f9, 0x04f9, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff +}}; +static UnicodeCaseTableVector caseTable05 = {{ + 0x0501, 0x0501, 0x0503, 0x0503, 0x0505, 0x0505, 0x0507, 0x0507, + 0x0509, 0x0509, 0x050b, 0x050b, 0x050d, 0x050d, 0x050f, 0x050f, + 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, + 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f, + 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, + 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f, + 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, + 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, + 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, + 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, + 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, + 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, + 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, + 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, + 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, + 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, + 0x0588, 0x0589, 0x058a, 0x058b, 0x058c, 0x058d, 0x058e, 0x058f, + 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, + 0x0598, 0x0599, 0x059a, 0x059b, 0x059c, 0x059d, 0x059e, 0x059f, + 0x05a0, 0x05a1, 0x05a2, 0x05a3, 0x05a4, 0x05a5, 0x05a6, 0x05a7, + 0x05a8, 0x05a9, 0x05aa, 0x05ab, 0x05ac, 0x05ad, 0x05ae, 0x05af, + 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, + 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf, + 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7, + 0x05c8, 0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf, + 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, + 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, + 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, + 0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed, 0x05ee, 0x05ef, + 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x05f5, 0x05f6, 0x05f7, + 0x05f8, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x05ff +}}; +static UnicodeCaseTableVector caseTable1e = {{ + 0x1e01, 0x1e01, 0x1e03, 0x1e03, 0x1e05, 0x1e05, 0x1e07, 0x1e07, + 0x1e09, 0x1e09, 0x1e0b, 0x1e0b, 0x1e0d, 0x1e0d, 0x1e0f, 0x1e0f, + 0x1e11, 0x1e11, 0x1e13, 0x1e13, 0x1e15, 0x1e15, 0x1e17, 0x1e17, + 0x1e19, 0x1e19, 0x1e1b, 0x1e1b, 0x1e1d, 0x1e1d, 0x1e1f, 0x1e1f, + 0x1e21, 0x1e21, 0x1e23, 0x1e23, 0x1e25, 0x1e25, 0x1e27, 0x1e27, + 0x1e29, 0x1e29, 0x1e2b, 0x1e2b, 0x1e2d, 0x1e2d, 0x1e2f, 0x1e2f, + 0x1e31, 0x1e31, 0x1e33, 0x1e33, 0x1e35, 0x1e35, 0x1e37, 0x1e37, + 0x1e39, 0x1e39, 0x1e3b, 0x1e3b, 0x1e3d, 0x1e3d, 0x1e3f, 0x1e3f, + 0x1e41, 0x1e41, 0x1e43, 0x1e43, 0x1e45, 0x1e45, 0x1e47, 0x1e47, + 0x1e49, 0x1e49, 0x1e4b, 0x1e4b, 0x1e4d, 0x1e4d, 0x1e4f, 0x1e4f, + 0x1e51, 0x1e51, 0x1e53, 0x1e53, 0x1e55, 0x1e55, 0x1e57, 0x1e57, + 0x1e59, 0x1e59, 0x1e5b, 0x1e5b, 0x1e5d, 0x1e5d, 0x1e5f, 0x1e5f, + 0x1e61, 0x1e61, 0x1e63, 0x1e63, 0x1e65, 0x1e65, 0x1e67, 0x1e67, + 0x1e69, 0x1e69, 0x1e6b, 0x1e6b, 0x1e6d, 0x1e6d, 0x1e6f, 0x1e6f, + 0x1e71, 0x1e71, 0x1e73, 0x1e73, 0x1e75, 0x1e75, 0x1e77, 0x1e77, + 0x1e79, 0x1e79, 0x1e7b, 0x1e7b, 0x1e7d, 0x1e7d, 0x1e7f, 0x1e7f, + 0x1e81, 0x1e81, 0x1e83, 0x1e83, 0x1e85, 0x1e85, 0x1e87, 0x1e87, + 0x1e89, 0x1e89, 0x1e8b, 0x1e8b, 0x1e8d, 0x1e8d, 0x1e8f, 0x1e8f, + 0x1e91, 0x1e91, 0x1e93, 0x1e93, 0x1e95, 0x1e95, 0x1e96, 0x1e97, + 0x1e98, 0x1e99, 0x1e9a, 0x1e61, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, + 0x1ea1, 0x1ea1, 0x1ea3, 0x1ea3, 0x1ea5, 0x1ea5, 0x1ea7, 0x1ea7, + 0x1ea9, 0x1ea9, 0x1eab, 0x1eab, 0x1ead, 0x1ead, 0x1eaf, 0x1eaf, + 0x1eb1, 0x1eb1, 0x1eb3, 0x1eb3, 0x1eb5, 0x1eb5, 0x1eb7, 0x1eb7, + 0x1eb9, 0x1eb9, 0x1ebb, 0x1ebb, 0x1ebd, 0x1ebd, 0x1ebf, 0x1ebf, + 0x1ec1, 0x1ec1, 0x1ec3, 0x1ec3, 0x1ec5, 0x1ec5, 0x1ec7, 0x1ec7, + 0x1ec9, 0x1ec9, 0x1ecb, 0x1ecb, 0x1ecd, 0x1ecd, 0x1ecf, 0x1ecf, + 0x1ed1, 0x1ed1, 0x1ed3, 0x1ed3, 0x1ed5, 0x1ed5, 0x1ed7, 0x1ed7, + 0x1ed9, 0x1ed9, 0x1edb, 0x1edb, 0x1edd, 0x1edd, 0x1edf, 0x1edf, + 0x1ee1, 0x1ee1, 0x1ee3, 0x1ee3, 0x1ee5, 0x1ee5, 0x1ee7, 0x1ee7, + 0x1ee9, 0x1ee9, 0x1eeb, 0x1eeb, 0x1eed, 0x1eed, 0x1eef, 0x1eef, + 0x1ef1, 0x1ef1, 0x1ef3, 0x1ef3, 0x1ef5, 0x1ef5, 0x1ef7, 0x1ef7, + 0x1ef9, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff +}}; +static UnicodeCaseTableVector caseTable1f = {{ + 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, + 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, + 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f16, 0x1f17, + 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f1e, 0x1f1f, + 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, + 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, + 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, + 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f46, 0x1f47, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f4e, 0x1f4f, + 0x1f50, 0x1f51, 0x1f52, 0x1f53, 0x1f54, 0x1f55, 0x1f56, 0x1f57, + 0x1f58, 0x1f51, 0x1f5a, 0x1f53, 0x1f5c, 0x1f55, 0x1f5e, 0x1f57, + 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, + 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, + 0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77, + 0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f7e, 0x1f7f, + 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, + 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, + 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, + 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, + 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, + 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, + 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, + 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1fbd, 0x03b9, 0x1fbf, + 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, + 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, + 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, + 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, + 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, 0x1fe6, 0x1fe7, + 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1fed, 0x1fee, 0x1fef, + 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, + 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff +}}; +static UnicodeCaseTableVector caseTable21 = {{ + 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, + 0x2108, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f, + 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, + 0x2118, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x211e, 0x211f, + 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x03c9, 0x2127, + 0x2128, 0x2129, 0x006b, 0x00e5, 0x212c, 0x212d, 0x212e, 0x212f, + 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, + 0x2138, 0x2139, 0x213a, 0x213b, 0x213c, 0x213d, 0x213e, 0x213f, + 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, + 0x2148, 0x2149, 0x214a, 0x214b, 0x214c, 0x214d, 0x214e, 0x214f, + 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, + 0x2158, 0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x215f, + 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, + 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, + 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, + 0x2188, 0x2189, 0x218a, 0x218b, 0x218c, 0x218d, 0x218e, 0x218f, + 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, + 0x2198, 0x2199, 0x219a, 0x219b, 0x219c, 0x219d, 0x219e, 0x219f, + 0x21a0, 0x21a1, 0x21a2, 0x21a3, 0x21a4, 0x21a5, 0x21a6, 0x21a7, + 0x21a8, 0x21a9, 0x21aa, 0x21ab, 0x21ac, 0x21ad, 0x21ae, 0x21af, + 0x21b0, 0x21b1, 0x21b2, 0x21b3, 0x21b4, 0x21b5, 0x21b6, 0x21b7, + 0x21b8, 0x21b9, 0x21ba, 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf, + 0x21c0, 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7, + 0x21c8, 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf, + 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x21d5, 0x21d6, 0x21d7, + 0x21d8, 0x21d9, 0x21da, 0x21db, 0x21dc, 0x21dd, 0x21de, 0x21df, + 0x21e0, 0x21e1, 0x21e2, 0x21e3, 0x21e4, 0x21e5, 0x21e6, 0x21e7, + 0x21e8, 0x21e9, 0x21ea, 0x21eb, 0x21ec, 0x21ed, 0x21ee, 0x21ef, + 0x21f0, 0x21f1, 0x21f2, 0x21f3, 0x21f4, 0x21f5, 0x21f6, 0x21f7, + 0x21f8, 0x21f9, 0x21fa, 0x21fb, 0x21fc, 0x21fd, 0x21fe, 0x21ff +}}; +static UnicodeCaseTableVector caseTable24 = {{ + 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, + 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f, + 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417, + 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f, + 0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427, + 0x2428, 0x2429, 0x242a, 0x242b, 0x242c, 0x242d, 0x242e, 0x242f, + 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437, + 0x2438, 0x2439, 0x243a, 0x243b, 0x243c, 0x243d, 0x243e, 0x243f, + 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447, + 0x2448, 0x2449, 0x244a, 0x244b, 0x244c, 0x244d, 0x244e, 0x244f, + 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457, + 0x2458, 0x2459, 0x245a, 0x245b, 0x245c, 0x245d, 0x245e, 0x245f, + 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, + 0x2468, 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, + 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477, + 0x2478, 0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f, + 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487, + 0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e, 0x248f, + 0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497, + 0x2498, 0x2499, 0x249a, 0x249b, 0x249c, 0x249d, 0x249e, 0x249f, + 0x24a0, 0x24a1, 0x24a2, 0x24a3, 0x24a4, 0x24a5, 0x24a6, 0x24a7, + 0x24a8, 0x24a9, 0x24aa, 0x24ab, 0x24ac, 0x24ad, 0x24ae, 0x24af, + 0x24b0, 0x24b1, 0x24b2, 0x24b3, 0x24b4, 0x24b5, 0x24d0, 0x24d1, + 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9, + 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1, + 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9, + 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, + 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, + 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, + 0x24e8, 0x24e9, 0x24ea, 0x24eb, 0x24ec, 0x24ed, 0x24ee, 0x24ef, + 0x24f0, 0x24f1, 0x24f2, 0x24f3, 0x24f4, 0x24f5, 0x24f6, 0x24f7, + 0x24f8, 0x24f9, 0x24fa, 0x24fb, 0x24fc, 0x24fd, 0x24fe, 0x24ff +}}; +static UnicodeCaseTableVector caseTableff = {{ + 0xff00, 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07, + 0xff08, 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f, + 0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17, + 0xff18, 0xff19, 0xff1a, 0xff1b, 0xff1c, 0xff1d, 0xff1e, 0xff1f, + 0xff20, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, + 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, + 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, + 0xff58, 0xff59, 0xff5a, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff3f, + 0xff40, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, + 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, + 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, + 0xff58, 0xff59, 0xff5a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, + 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, + 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, + 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, + 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, + 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, + 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, + 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, + 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, + 0xffa0, 0xffa1, 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, + 0xffa8, 0xffa9, 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, + 0xffb0, 0xffb1, 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, + 0xffb8, 0xffb9, 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, + 0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, + 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, + 0xffd0, 0xffd1, 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, + 0xffd8, 0xffd9, 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, + 0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, + 0xffe8, 0xffe9, 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, + 0xfff0, 0xfff1, 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, + 0xfff8, 0xfff9, 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff +}}; +static UnicodeCaseTableVector *caseTable[256] = { + &caseTable00, + &caseTable01, + &caseTable02, + &caseTable03, + &caseTable04, + &caseTable05, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &caseTable1e, + &caseTable1f, + NULL, + &caseTable21, + NULL, + NULL, + &caseTable24, + 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, + 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, + 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, + 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, + &caseTableff +}; + +static inline char getType(Unicode c) { + int i; + char type; + + if (c > 0xffff) { + type = 'X'; + } else { + i = (c >> 8) & 0xff; + if ((type = typeTable[i].type) == 'X') { + type = typeTable[i].vector[c & 0xff]; + } + } + return type; +} + +GBool unicodeTypeL(Unicode c) { + return getType(c) == 'L'; +} + +GBool unicodeTypeR(Unicode c) { + return getType(c) == 'R'; +} + +Unicode unicodeToUpper(Unicode c) { + int i; + + if (c > 0xffff) { + return c; + } + i = (c >> 8) & 0xff; + if (caseTable[i]) { + return caseTable[i]->codes[c & 0xff]; + } + return c; +} + diff --git a/pdftops/UnicodeTypeTable.h b/pdftops/UnicodeTypeTable.h new file mode 100644 index 000000000..7103dbddf --- /dev/null +++ b/pdftops/UnicodeTypeTable.h @@ -0,0 +1,20 @@ +//======================================================================== +// +// UnicodeTypeTable.h +// +// Copyright 2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef UNICODETYPETABLE_H +#define UNICODETYPETABLE_H + +#include "gtypes.h" + +extern GBool unicodeTypeL(Unicode c); + +extern GBool unicodeTypeR(Unicode c); + +extern Unicode unicodeToUpper(Unicode c); + +#endif diff --git a/pdftops/XRef.cxx b/pdftops/XRef.cxx new file mode 100644 index 000000000..c581803f7 --- /dev/null +++ b/pdftops/XRef.cxx @@ -0,0 +1,888 @@ +//======================================================================== +// +// XRef.cc +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma implementation +#endif + +#include +#include +#include +#include +#include "gmem.h" +#include "Object.h" +#include "Stream.h" +#include "Lexer.h" +#include "Parser.h" +#include "Dict.h" +#include "Error.h" +#include "ErrorCodes.h" +#include "XRef.h" + +//------------------------------------------------------------------------ + +#define xrefSearchSize 1024 // read this many bytes at end of file + // to look for 'startxref' + +//------------------------------------------------------------------------ +// Permission bits +//------------------------------------------------------------------------ + +#define permPrint (1<<2) +#define permChange (1<<3) +#define permCopy (1<<4) +#define permNotes (1<<5) +#define defPermFlags 0xfffc + +//------------------------------------------------------------------------ +// ObjectStream +//------------------------------------------------------------------------ + +class ObjectStream { +public: + + // Create an object stream, using object number , + // generation 0. + ObjectStream(XRef *xref, int objStrNumA); + + ~ObjectStream(); + + // Return the object number of this object stream. + int getObjStrNum() { return objStrNum; } + + // Get the th object from this stream, which should be + // object number , generation 0. + Object *getObject(int objIdx, int objNum, Object *obj); + +private: + + int objStrNum; // object number of the object stream + int nObjects; // number of objects in the stream + Object *objs; // the objects (length = nObjects) + int *objNums; // the object numbers (length = nObjects) +}; + +ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { + Stream *str; + Parser *parser; + int *offsets; + Object objStr, obj1, obj2; + int first, i; + + objStrNum = objStrNumA; + nObjects = 0; + objs = NULL; + objNums = NULL; + + if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { + goto err1; + } + + if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { + obj1.free(); + goto err1; + } + nObjects = obj1.getInt(); + obj1.free(); + if (nObjects <= 0) { + goto err1; + } + + if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { + obj1.free(); + goto err1; + } + first = obj1.getInt(); + obj1.free(); + if (first < 0) { + goto err1; + } + + objs = new Object[nObjects]; + objNums = (int *)gmallocn(nObjects, sizeof(int)); + offsets = (int *)gmallocn(nObjects, sizeof(int)); + + // parse the header: object numbers and offsets + objStr.streamReset(); + obj1.initNull(); + str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); + parser = new Parser(xref, new Lexer(xref, str)); + for (i = 0; i < nObjects; ++i) { + parser->getObj(&obj1); + parser->getObj(&obj2); + if (!obj1.isInt() || !obj2.isInt()) { + obj1.free(); + obj2.free(); + delete parser; + gfree(offsets); + goto err1; + } + objNums[i] = obj1.getInt(); + offsets[i] = obj2.getInt(); + obj1.free(); + obj2.free(); + if (objNums[i] < 0 || offsets[i] < 0 || + (i > 0 && offsets[i] < offsets[i-1])) { + delete parser; + gfree(offsets); + goto err1; + } + } + while (str->getChar() != EOF) ; + delete parser; + + // skip to the first object - this shouldn't be necessary because + // the First key is supposed to be equal to offsets[0], but just in + // case... + for (i = first; i < offsets[0]; ++i) { + objStr.getStream()->getChar(); + } + + // parse the objects + for (i = 0; i < nObjects; ++i) { + obj1.initNull(); + if (i == nObjects - 1) { + str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0); + } else { + str = new EmbedStream(objStr.getStream(), &obj1, gTrue, + offsets[i+1] - offsets[i]); + } + parser = new Parser(xref, new Lexer(xref, str)); + parser->getObj(&objs[i]); + while (str->getChar() != EOF) ; + delete parser; + } + + gfree(offsets); + + err1: + objStr.free(); + return; +} + +ObjectStream::~ObjectStream() { + int i; + + if (objs) { + for (i = 0; i < nObjects; ++i) { + objs[i].free(); + } + delete[] objs; + } + gfree(objNums); +} + +Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { + if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) { + return obj->initNull(); + } + return objs[objIdx].copy(obj); +} + +//------------------------------------------------------------------------ +// XRef +//------------------------------------------------------------------------ + +XRef::XRef(BaseStream *strA) { + Guint pos; + Object obj; + + ok = gTrue; + errCode = errNone; + size = 0; + entries = NULL; + streamEnds = NULL; + streamEndsLen = 0; + objStr = NULL; + + encrypted = gFalse; + permFlags = defPermFlags; + ownerPasswordOk = gFalse; + + // read the trailer + str = strA; + start = str->getStart(); + pos = getStartXref(); + + // if there was a problem with the 'startxref' position, try to + // reconstruct the xref table + if (pos == 0) { + if (!(ok = constructXRef())) { + errCode = errDamaged; + return; + } + + // read the xref table + } else { + while (readXRef(&pos)) ; + + // if there was a problem with the xref table, + // try to reconstruct it + if (!ok) { + if (!(ok = constructXRef())) { + errCode = errDamaged; + return; + } + } + } + + // get the root dictionary (catalog) object + trailerDict.dictLookupNF("Root", &obj); + if (obj.isRef()) { + rootNum = obj.getRefNum(); + rootGen = obj.getRefGen(); + obj.free(); + } else { + obj.free(); + if (!(ok = constructXRef())) { + errCode = errDamaged; + return; + } + } + + // now set the trailer dictionary's xref pointer so we can fetch + // indirect objects from it + trailerDict.getDict()->setXRef(this); +} + +XRef::~XRef() { + gfree(entries); + trailerDict.free(); + if (streamEnds) { + gfree(streamEnds); + } + if (objStr) { + delete objStr; + } +} + +// Read the 'startxref' position. +Guint XRef::getStartXref() { + char buf[xrefSearchSize+1]; + char *p; + int c, n, i; + + // read last xrefSearchSize bytes + str->setPos(xrefSearchSize, -1); + 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) ; + lastXRefPos = strToUnsigned(p); + + return lastXRefPos; +} + +// Read one xref table section. Also reads the associated trailer +// dictionary, and returns the prev pointer (if any). +GBool XRef::readXRef(Guint *pos) { + Parser *parser; + Object obj; + GBool more; + + // start up a parser, parse one token + obj.initNull(); + parser = new Parser(NULL, + new Lexer(NULL, + str->makeSubStream(start + *pos, gFalse, 0, &obj))); + parser->getObj(&obj); + + // parse an old-style xref table + if (obj.isCmd("xref")) { + obj.free(); + more = readXRefTable(parser, pos); + + // parse an xref stream + } else if (obj.isInt()) { + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + obj.free(); + if (!parser->getObj(&obj)->isCmd("obj")) { + goto err1; + } + obj.free(); + if (!parser->getObj(&obj)->isStream()) { + goto err1; + } + more = readXRefStream(obj.getStream(), pos); + obj.free(); + + } else { + goto err1; + } + + delete parser; + return more; + + err1: + obj.free(); + delete parser; + ok = gFalse; + return gFalse; +} + +GBool XRef::readXRefTable(Parser *parser, Guint *pos) { + XRefEntry entry; + GBool more; + Object obj, obj2; + Guint pos2; + int first, n, newSize, i; + + while (1) { + parser->getObj(&obj); + if (obj.isCmd("trailer")) { + obj.free(); + break; + } + if (!obj.isInt()) { + goto err1; + } + first = obj.getInt(); + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + n = obj.getInt(); + obj.free(); + if (first < 0 || n < 0 || first + n < 0) { + goto err1; + } + if (first + n > size) { + for (newSize = size ? 2 * size : 1024; + first + n > newSize && newSize > 0; + newSize <<= 1) ; + if (newSize < 0) { + goto err1; + } + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + for (i = first; i < first + n; ++i) { + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + entry.offset = (Guint)obj.getInt(); + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + entry.gen = obj.getInt(); + obj.free(); + parser->getObj(&obj); + if (obj.isCmd("n")) { + entry.type = xrefEntryUncompressed; + } else if (obj.isCmd("f")) { + entry.type = xrefEntryFree; + } else { + goto err1; + } + obj.free(); + if (entries[i].offset == 0xffffffff) { + entries[i] = entry; + // 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].type == xrefEntryFree) { + i = first = 0; + entries[0] = entries[1]; + entries[1].offset = 0xffffffff; + } + } + } + } + + // read the trailer dictionary + if (!parser->getObj(&obj)->isDict()) { + goto err1; + } + + // get the 'Prev' pointer + obj.getDict()->lookupNF("Prev", &obj2); + if (obj2.isInt()) { + *pos = (Guint)obj2.getInt(); + more = gTrue; + } else if (obj2.isRef()) { + // certain buggy PDF generators generate "/Prev NNN 0 R" instead + // of "/Prev NNN" + *pos = (Guint)obj2.getRefNum(); + more = gTrue; + } else { + more = gFalse; + } + obj2.free(); + + // save the first trailer dictionary + if (trailerDict.isNone()) { + obj.copy(&trailerDict); + } + + // check for an 'XRefStm' key + if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { + pos2 = (Guint)obj2.getInt(); + readXRef(&pos2); + if (!ok) { + obj2.free(); + goto err1; + } + } + obj2.free(); + + obj.free(); + return more; + + err1: + obj.free(); + ok = gFalse; + return gFalse; +} + +GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { + Dict *dict; + int w[3]; + GBool more; + Object obj, obj2, idx; + int newSize, first, n, i; + + dict = xrefStr->getDict(); + + if (!dict->lookupNF("Size", &obj)->isInt()) { + goto err1; + } + newSize = obj.getInt(); + obj.free(); + if (newSize < 0) { + goto err1; + } + if (newSize > size) { + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + + if (!dict->lookupNF("W", &obj)->isArray() || + obj.arrayGetLength() < 3) { + goto err1; + } + for (i = 0; i < 3; ++i) { + if (!obj.arrayGet(i, &obj2)->isInt()) { + obj2.free(); + goto err1; + } + w[i] = obj2.getInt(); + obj2.free(); + if (w[i] < 0 || w[i] > 4) { + goto err1; + } + } + obj.free(); + + xrefStr->reset(); + dict->lookupNF("Index", &idx); + if (idx.isArray()) { + for (i = 0; i+1 < idx.arrayGetLength(); i += 2) { + if (!idx.arrayGet(i, &obj)->isInt()) { + idx.free(); + goto err1; + } + first = obj.getInt(); + obj.free(); + if (!idx.arrayGet(i+1, &obj)->isInt()) { + idx.free(); + goto err1; + } + n = obj.getInt(); + obj.free(); + if (first < 0 || n < 0 || + !readXRefStreamSection(xrefStr, w, first, n)) { + idx.free(); + goto err0; + } + } + } else { + if (!readXRefStreamSection(xrefStr, w, 0, newSize)) { + idx.free(); + goto err0; + } + } + idx.free(); + + dict->lookupNF("Prev", &obj); + if (obj.isInt()) { + *pos = (Guint)obj.getInt(); + more = gTrue; + } else { + more = gFalse; + } + obj.free(); + if (trailerDict.isNone()) { + trailerDict.initDict(dict); + } + + return more; + + err1: + obj.free(); + err0: + ok = gFalse; + return gFalse; +} + +GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { + Guint offset; + int type, gen, c, newSize, i, j; + + if (first + n < 0) { + return gFalse; + } + if (first + n > size) { + for (newSize = size ? 2 * size : 1024; + first + n > newSize && newSize > 0; + newSize <<= 1) ; + if (newSize < 0) { + return gFalse; + } + entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + for (i = first; i < first + n; ++i) { + if (w[0] == 0) { + type = 1; + } else { + for (type = 0, j = 0; j < w[0]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + type = (type << 8) + c; + } + } + for (offset = 0, j = 0; j < w[1]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + offset = (offset << 8) + c; + } + for (gen = 0, j = 0; j < w[2]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + gen = (gen << 8) + c; + } + if (entries[i].offset == 0xffffffff) { + switch (type) { + case 0: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryFree; + break; + case 1: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryUncompressed; + break; + case 2: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryCompressed; + break; + default: + return gFalse; + } + } + } + + return gTrue; +} + +// Attempt to construct an xref table for a damaged file. +GBool XRef::constructXRef() { + Parser *parser; + Object newTrailerDict, obj; + char buf[256]; + Guint pos; + int num, gen; + int newSize; + int streamEndsSize; + char *p; + int i; + GBool gotRoot; + + gfree(entries); + size = 0; + entries = NULL; + + 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(pos + 7, gFalse, 0, &obj))); + parser->getObj(&newTrailerDict); + if (newTrailerDict.isDict()) { + newTrailerDict.dictLookupNF("Root", &obj); + if (obj.isRef()) { + rootNum = obj.getRefNum(); + rootGen = obj.getRefGen(); + if (!trailerDict.isNone()) { + trailerDict.free(); + } + newTrailerDict.copy(&trailerDict); + gotRoot = gTrue; + } + obj.free(); + } + newTrailerDict.free(); + delete parser; + + // look for object + } else if (isdigit(*p)) { + num = atoi(p); + if (num > 0) { + 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; + if (newSize < 0) { + error(-1, "Bad object number"); + return gFalse; + } + entries = (XRefEntry *) + greallocn(entries, newSize, sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + if (entries[num].type == xrefEntryFree || + gen >= entries[num].gen) { + entries[num].offset = pos - start; + entries[num].gen = gen; + entries[num].type = xrefEntryUncompressed; + } + } + } + } + } + } + + } else if (!strncmp(p, "endstream", 9)) { + if (streamEndsLen == streamEndsSize) { + streamEndsSize += 64; + streamEnds = (Guint *)greallocn(streamEnds, + streamEndsSize, sizeof(int)); + } + streamEnds[streamEndsLen++] = pos; + } + } + + if (gotRoot) + return gTrue; + + error(-1, "Couldn't find trailer dictionary"); + return gFalse; +} + +void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA, + Guchar *fileKeyA, int keyLengthA, int encVersionA) { + int i; + + encrypted = gTrue; + permFlags = permFlagsA; + ownerPasswordOk = ownerPasswordOkA; + if (keyLengthA <= 16) { + keyLength = keyLengthA; + } else { + keyLength = 16; + } + for (i = 0; i < keyLength; ++i) { + fileKey[i] = fileKeyA[i]; + } + encVersion = encVersionA; +} + +GBool XRef::okToPrint(GBool ignoreOwnerPW) { + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); +} + +GBool XRef::okToChange(GBool ignoreOwnerPW) { + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange); +} + +GBool XRef::okToCopy(GBool ignoreOwnerPW) { + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy); +} + +GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { + return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes); +} + +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) { + goto err; + } + + e = &entries[num]; + switch (e->type) { + + case xrefEntryUncompressed: + if (e->gen != gen) { + goto err; + } + obj1.initNull(); + parser = new Parser(this, + new Lexer(this, + str->makeSubStream(start + e->offset, gFalse, 0, &obj1))); + parser->getObj(&obj1); + parser->getObj(&obj2); + parser->getObj(&obj3); + if (!obj1.isInt() || obj1.getInt() != num || + !obj2.isInt() || obj2.getInt() != gen || + !obj3.isCmd("obj")) { + obj1.free(); + obj2.free(); + obj3.free(); + delete parser; + goto err; + } + parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, + num, gen); + obj1.free(); + obj2.free(); + obj3.free(); + delete parser; + break; + + case xrefEntryCompressed: + if (gen != 0) { + goto err; + } + if (!objStr || objStr->getObjStrNum() != (int)e->offset) { + if (objStr) { + delete objStr; + } + objStr = new ObjectStream(this, e->offset); + } + objStr->getObject(e->gen, num, obj); + break; + + default: + goto err; + } + + return obj; + + err: + return obj->initNull(); +} + +Object *XRef::getDocInfo(Object *obj) { + return trailerDict.dictLookup("Info", obj); +} + +// Added for the pdftex project. +Object *XRef::getDocInfoNF(Object *obj) { + return trailerDict.dictLookupNF("Info", obj); +} + +GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) { + int a, b, m; + + if (streamEndsLen == 0 || + streamStart > streamEnds[streamEndsLen - 1]) { + return gFalse; + } + + 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; + } + } + *streamEnd = streamEnds[b]; + return gTrue; +} + +Guint XRef::strToUnsigned(char *s) { + Guint x; + char *p; + int i; + + x = 0; + for (p = s, i = 0; *p && isdigit(*p) && i < 10; ++p, ++i) { + x = 10 * x + (*p - '0'); + } + return x; +} diff --git a/pdftops/XRef.h b/pdftops/XRef.h new file mode 100644 index 000000000..6588276c0 --- /dev/null +++ b/pdftops/XRef.h @@ -0,0 +1,131 @@ +//======================================================================== +// +// XRef.h +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef XREF_H +#define XREF_H + +#include + +#ifdef USE_GCC_PRAGMAS +#pragma interface +#endif + +#include "gtypes.h" +#include "Object.h" + +class Dict; +class Stream; +class Parser; +class ObjectStream; + +//------------------------------------------------------------------------ +// XRef +//------------------------------------------------------------------------ + +enum XRefEntryType { + xrefEntryFree, + xrefEntryUncompressed, + xrefEntryCompressed +}; + +struct XRefEntry { + Guint offset; + int gen; + XRefEntryType type; +}; + +class XRef { +public: + + // Constructor. Read xref table from stream. + XRef(BaseStream *strA); + + // Destructor. + ~XRef(); + + // Is xref table valid? + GBool isOk() { return ok; } + + // Get the error code (if isOk() returns false). + int getErrorCode() { return errCode; } + + // Set the encryption parameters. + void setEncryption(int permFlagsA, GBool ownerPasswordOkA, + Guchar *fileKeyA, int keyLengthA, int encVersionA); + + // Is the file encrypted? + GBool isEncrypted() { return encrypted; } + + // 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); + Object *getDocInfoNF(Object *obj); + + // Return the number of objects in the xref table. + int getNumObjects() { return size; } + + // Return the offset of the last xref table. + Guint 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 false if unknown or file is not damaged. + GBool getStreamEnd(Guint streamStart, Guint *streamEnd); + + // Direct access. + int getSize() { return size; } + XRefEntry *getEntry(int i) { return &entries[i]; } + Object *getTrailerDict() { return &trailerDict; } + +private: + + BaseStream *str; // input stream + Guint start; // offset in file (to allow for garbage + // at beginning of file) + XRefEntry *entries; // xref entries + int size; // size of array + int rootNum, rootGen; // catalog dict + GBool ok; // true if xref table is valid + int errCode; // error code (if is false) + Object trailerDict; // trailer dictionary + Guint lastXRefPos; // offset of last xref table + Guint *streamEnds; // 'endstream' positions - only used in + // damaged files + int streamEndsLen; // number of valid entries in streamEnds + ObjectStream *objStr; // cached object stream + GBool encrypted; // true if file is encrypted + int permFlags; // permission bits + GBool ownerPasswordOk; // true if owner password is correct + Guchar fileKey[16]; // file decryption key + int keyLength; // length of key, in bytes + int encVersion; // encryption algorithm + + Guint getStartXref(); + GBool readXRef(Guint *pos); + GBool readXRefTable(Parser *parser, Guint *pos); + GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); + GBool readXRefStream(Stream *xrefStr, Guint *pos); + GBool constructXRef(); + Guint strToUnsigned(char *s); +}; + +#endif diff --git a/pdftops/XpdfPluginAPI.cxx b/pdftops/XpdfPluginAPI.cxx new file mode 100644 index 000000000..dfa63282b --- /dev/null +++ b/pdftops/XpdfPluginAPI.cxx @@ -0,0 +1,262 @@ +//======================================================================== +// +// XpdfPluginAPI.cc +// +// Copyright 2004 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifdef ENABLE_PLUGINS + +#include "gmem.h" +#include "GlobalParams.h" +#include "Object.h" +#include "PDFDoc.h" +#ifdef WIN32 +#include "WinPDFCore.h" +#else +#include "XPDFCore.h" +#endif +#include "XpdfPluginAPI.h" + +//------------------------------------------------------------------------ + +//~ This should use a pool of Objects; change xpdfFreeObj to match. +static Object *allocObj() { + return (Object *)gmalloc(sizeof(Object)); +} + +//------------------------------------------------------------------------ +// Document access functions +//------------------------------------------------------------------------ + +XpdfObject _xpdfGetInfoDict(XpdfDoc doc) { + Object *obj; + + obj = allocObj(); + return (XpdfObject)((PDFDoc *)doc)->getDocInfo(obj); +} + +XpdfObject _xpdfGetCatalog(XpdfDoc doc) { + Object *obj; + + obj = allocObj(); + return (XpdfObject)((PDFDoc *)doc)->getXRef()->getCatalog(obj); +} + +#ifdef _WIN32 + +HWND _xpdfWin32GetWindow(XpdfDoc doc) { + WinPDFCore *core; + + if (!(core = (WinPDFCore *)((PDFDoc *)doc)->getGUIData())) { + return NULL; + } + return core->getDrawFrame(); +} + +#else + +Widget _xpdfXGetWindow(XpdfDoc doc) { + XPDFCore *core; + + if (!(core = (XPDFCore *)((PDFDoc *)doc)->getGUIData())) { + return NULL; + } + return core->getWidget(); +} + +#endif + +//------------------------------------------------------------------------ +// Object access functions. +//------------------------------------------------------------------------ + +XpdfBool _xpdfObjIsBool(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isBool(); +} + +XpdfBool _xpdfObjIsInt(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isInt(); +} + +XpdfBool _xpdfObjIsReal(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isReal(); +} + +XpdfBool _xpdfObjIsNumber(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isNum(); +} + +XpdfBool _xpdfObjIsString(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isString(); +} + +XpdfBool _xpdfObjIsName(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isName(); +} + +XpdfBool _xpdfObjIsNull(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isNull(); +} + +XpdfBool _xpdfObjIsArray(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isArray(); +} + +XpdfBool _xpdfObjIsDict(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isDict(); +} + +XpdfBool _xpdfObjIsStream(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isStream(); +} + +XpdfBool _xpdfObjIsRef(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->isRef(); +} + +XpdfBool _xpdfBoolValue(XpdfObject obj) { + return (XpdfBool)((Object *)obj)->getBool(); +} + +int _xpdfIntValue(XpdfObject obj) { + if (!((Object *)obj)->isInt()) { + return 0; + } + return ((Object *)obj)->getInt(); +} + +double _xpdfRealValue(XpdfObject obj) { + if (!((Object *)obj)->isReal()) { + return 0; + } + return ((Object *)obj)->getReal(); +} + +double _xpdfNumberValue(XpdfObject obj) { + if (!((Object *)obj)->isNum()) { + return 0; + } + return ((Object *)obj)->getNum(); +} + +int _xpdfStringLength(XpdfObject obj) { + if (!((Object *)obj)->isString()) { + return 0; + } + return ((Object *)obj)->getString()->getLength(); +} + +char *_xpdfStringValue(XpdfObject obj) { + if (!((Object *)obj)->isString()) { + return 0; + } + return ((Object *)obj)->getString()->getCString(); +} + +char *_xpdfNameValue(XpdfObject obj) { + if (!((Object *)obj)->isName()) { + return NULL; + } + return ((Object *)obj)->getName(); +} + +int _xpdfArrayLength(XpdfObject obj) { + if (!((Object *)obj)->isArray()) { + return 0; + } + return ((Object *)obj)->arrayGetLength(); +} + +XpdfObject _xpdfArrayGet(XpdfObject obj, int idx) { + Object *elem; + + elem = allocObj(); + if (!((Object *)obj)->isArray()) { + return (XpdfObject)elem->initNull(); + } + return (XpdfObject)((Object *)obj)->arrayGet(idx, elem); +} + +XpdfObject _xpdfDictGet(XpdfObject obj, char *key) { + Object *elem; + + elem = allocObj(); + if (!((Object *)obj)->isDict()) { + return (XpdfObject)elem->initNull(); + } + return (XpdfObject)((Object *)obj)->dictLookup(key, elem); +} + +void _xpdfFreeObj(XpdfObject obj) { + ((Object *)obj)->free(); + gfree(obj); +} + +//------------------------------------------------------------------------ +// Memory allocation functions +//------------------------------------------------------------------------ + +void *_xpdfMalloc(int size) { + return gmalloc(size); +} + +void *_xpdfRealloc(void *p, int size) { + return grealloc(p, size); +} + +void _xpdfFree(void *p) { + gfree(p); +} + +//------------------------------------------------------------------------ +// Security handlers +//------------------------------------------------------------------------ + +void _xpdfRegisterSecurityHandler(XpdfSecurityHandler *handler) { + if (handler->version <= xpdfPluginAPIVersion) { + globalParams->addSecurityHandler(handler); + } +} + +//------------------------------------------------------------------------ + +XpdfPluginVecTable xpdfPluginVecTable = { + xpdfPluginAPIVersion, + &_xpdfGetInfoDict, + &_xpdfGetCatalog, +#ifdef _WIN32 + &_xpdfWin32GetWindow, +#else + &_xpdfXGetWindow, +#endif + &_xpdfObjIsBool, + &_xpdfObjIsInt, + &_xpdfObjIsReal, + &_xpdfObjIsString, + &_xpdfObjIsName, + &_xpdfObjIsNull, + &_xpdfObjIsArray, + &_xpdfObjIsDict, + &_xpdfObjIsStream, + &_xpdfObjIsRef, + &_xpdfBoolValue, + &_xpdfIntValue, + &_xpdfRealValue, + &_xpdfStringLength, + &_xpdfStringValue, + &_xpdfNameValue, + &_xpdfArrayLength, + &_xpdfArrayGet, + &_xpdfDictGet, + &_xpdfFreeObj, + &_xpdfMalloc, + &_xpdfRealloc, + &_xpdfFree, + &_xpdfRegisterSecurityHandler, +}; + +#endif // ENABLE_PLUGINS diff --git a/pdftops/XpdfPluginAPI.h b/pdftops/XpdfPluginAPI.h new file mode 100644 index 000000000..7467f0209 --- /dev/null +++ b/pdftops/XpdfPluginAPI.h @@ -0,0 +1,323 @@ +/* + * XpdfPluginAPI.h + * + * Copyright 2004 Glyph & Cog, LLC + */ + +#ifndef XPDFPLUGINAPI_H +#define XPDFPLUGINAPI_H + +#ifdef _WIN32 +#include +#else +//#define Object XtObject +//#include +//#undef Object +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------ + * Macros + *------------------------------------------------------------------------*/ + +/* + * The current API version. + */ +#define xpdfPluginAPIVersion 1 + +#ifdef _WIN32 +# ifdef __cplusplus +# define PLUGINFUNC(retType) extern "C" __declspec(dllexport) retType +# else +# define PLUGINFUNC(retType) extern __declspec(dllexport) retType +# endif +#else +# ifdef __cplusplus +# define PLUGINFUNC(retType) extern "C" retType +# else +# define PLUGINFUNC(retType) extern retType +# endif +#endif + +/*------------------------------------------------------------------------ + * Plugin setup/cleanup + *------------------------------------------------------------------------*/ + +/* + * All plugins are required to implement two functions: + * + * -- Initialize the plugin. Returns non-zero if successful. + * PLUGINFUNC(XpdfBool) xpdfInitPlugin(void); + * + * -- Free the plugin. + * PLUGINFUNC(void) xpdfFreePlugin(void); + */ + +/*------------------------------------------------------------------------ + * Types + *------------------------------------------------------------------------*/ + +/* + * Standard C boolean -- zero = false, non-zero = true. + */ +typedef int XpdfBool; +#define xpdfTrue 1 +#define xpdfFalse 0 + +/* + * PDF document handle. + */ +typedef struct _XpdfDoc *XpdfDoc; + +/* + * PDF object handle. + */ +typedef struct _XpdfObject *XpdfObject; + +/* + * Document access permissions. Any of these can be bitwise 'or'ed + * together. If xpdfPermissionOpen is not included, the document + * cannot be opened at all, and the other bits are ignored. + */ +typedef unsigned int XpdfPermission; +#define xpdfPermissionOpen (1 << 0) +#define xpdfPermissionPrint (1 << 2) +#define xpdfPermissionChange (1 << 3) +#define xpdfPermissionCopy (1 << 4) +#define xpdfPermissionNotes (1 << 5) + +/*------------------------------------------------------------------------ + * Security handler + *------------------------------------------------------------------------*/ + +/* + * XpdfSecurityHandler - a security handler plugin should create one + * of these and pass it to xpdfRegisterSecurityHandler. + */ +#ifdef __cplusplus +struct XpdfSecurityHandler { +#else +typedef struct { +#endif + + /* + * Version of the security handler spec (this document) -- use + * xpdfPluginAPIVersion. + */ + int version; + + /* + * Security handler name. + */ + char *name; + + /* + * Any global data the security handler needs. XpdfViewer will pass + * this pointer to all handler functions as the + * argument. + */ + void *handlerData; + + /* + * Allocate and initialize data for a new document. XpdfViewer will + * pass the returned pointer to all other handler functions as the + * argument. Returns non-zero if successful. + */ + XpdfBool (*newDoc)(void *handlerData, XpdfDoc doc, + XpdfObject encryptDict, void **docData); + + /* + * Free the data allocated by newDoc. + */ + void (*freeDoc)(void *handlerData, void *docData); + + /* + * Construct authorization data based on the supplied owner and user + * passwords (either or both of which may be NULL). This function + * is called in "batch" mode, i.e., if the password was supplied on + * the command line or via an Xpdf library API. It should not + * generate any user interaction (e.g., a password dialog). It is + * not required to support this function: the makeAuthData function + * pointer can be set to NULL. Returns non-zero if successful. + */ + XpdfBool (*makeAuthData)(void *handlerData, void *docData, + char *ownerPassword, char *userPassword, + void **authData); + + /* + * Request any needed information (e.g., a password) from the user, + * and construct an authorization data object. Returns non-zero if + * successful. + */ + XpdfBool (*getAuthData)(void *handlerData, void *docData, + void **authData); + + /* + * Free the data allocated by getAuthData. + */ + void (*freeAuthData)(void *handlerData, void *docData, + void *authData); + + /* + * Request permission to access the document. This returns all + * permissions granted by authData. + */ + XpdfPermission (*authorize)(void *handlerData, void *docData, + void *authData); + + /* + * Get the decryption key and algorithm version associated with the + * document. Returns non-zero if successful. + */ + XpdfBool (*getKey)(void *handlerData, void *docData, + char **key, int *keyLen, int *cryptVersion); + + /* + * Free the data allocated by getKey. + */ + void (*freeKey)(void *handlerData, void *docData, + char *key, int keyLen); + +#ifdef __cplusplus +}; +#else +} XpdfSecurityHandler; +#endif + +/*------------------------------------------------------------------------*/ + +typedef struct { + int version; + +/*------------------------------------------------------------------------ + * Document access functions + *------------------------------------------------------------------------*/ + +/* + * Get a document's info dictionary. (The returned object must be + * freed with xpdfFreeObj.) + */ +XpdfObject (*_xpdfGetInfoDict)(XpdfDoc doc); + +/* + * Get a document's catalog ("root") dictionary. (The returned object + * must be freed with xpdfFreeObj.) + */ +XpdfObject (*_xpdfGetCatalog)(XpdfDoc doc); + +/*------------------------------------------------------------------------ + * Object access functions + *------------------------------------------------------------------------*/ + +/* + * Check an object's type. + */ +XpdfBool (*_xpdfObjIsBool)(XpdfObject obj); +XpdfBool (*_xpdfObjIsInt)(XpdfObject obj); +XpdfBool (*_xpdfObjIsReal)(XpdfObject obj); +XpdfBool (*_xpdfObjIsString)(XpdfObject obj); +XpdfBool (*_xpdfObjIsName)(XpdfObject obj); +XpdfBool (*_xpdfObjIsNull)(XpdfObject obj); +XpdfBool (*_xpdfObjIsArray)(XpdfObject obj); +XpdfBool (*_xpdfObjIsDict)(XpdfObject obj); +XpdfBool (*_xpdfObjIsStream)(XpdfObject obj); +XpdfBool (*_xpdfObjIsRef)(XpdfObject obj); + +/* + * Value access. + * (Objects returned by xpdfArrayGet and xpdfDictGet must be freed + * with xpdfFreeObj.) + */ +XpdfBool (*_xpdfBoolValue)(XpdfObject obj); +int (*_xpdfIntValue)(XpdfObject obj); +double (*_xpdfRealValue)(XpdfObject obj); +int (*_xpdfStringLength)(XpdfObject obj); +char *(*_xpdfStringValue)(XpdfObject obj); +char *(*_xpdfNameValue)(XpdfObject obj); +int (*_xpdfArrayLength)(XpdfObject obj); +XpdfObject (*_xpdfArrayGet)(XpdfObject obj, int idx); +XpdfObject (*_xpdfDictGet)(XpdfObject obj, char *key); + +/* + * Object destruction. NB: *all* objects must be freed after use. + */ +void (*_xpdfFreeObj)(XpdfObject obj); + +/*------------------------------------------------------------------------ + * Memory allocation functions + *------------------------------------------------------------------------*/ + +void *(*_xpdfMalloc)(int size); +void *(*_xpdfRealloc)(void *p, int size); +void (*_xpdfFree)(void *p); + +/*------------------------------------------------------------------------ + * Security handler functions + *------------------------------------------------------------------------*/ + +/* + * Register a new security handler. + */ +void (*_xpdfRegisterSecurityHandler)(XpdfSecurityHandler *handler); + +/*------------------------------------------------------------------------*/ + +} XpdfPluginVecTable; + +#ifdef _WIN32 + +extern __declspec(dllexport) XpdfPluginVecTable xpdfPluginVecTable; + +#define xpdfPluginSetup \ + extern __declspec(dllexport) \ + XpdfPluginVecTable xpdfPluginVecTable = {xpdfPluginAPIVersion}; + +#else + +extern XpdfPluginVecTable xpdfPluginVecTable; + +#define xpdfPluginSetup \ + XpdfPluginVecTable xpdfPluginVecTable = {xpdfPluginAPIVersion}; + +#endif + +#define xpdfGetInfoDict (*xpdfPluginVecTable._xpdfGetInfoDict) +#define xpdfGetCatalog (*xpdfPluginVecTable._xpdfGetCatalog) +#ifdef _WIN32 +#define xpdfWin32GetWindow (*xpdfPluginVecTable._xpdfWin32GetWindow) +#else +#define xpdfXGetWindow (*xpdfPluginVecTable._xpdfXGetWindow) +#endif +#define xpdfObjIsBool (*xpdfPluginVecTable._xpdfObjIsBool) +#define xpdfObjIsInt (*xpdfPluginVecTable._xpdfObjIsInt) +#define xpdfObjIsReal (*xpdfPluginVecTable._xpdfObjIsReal) +#define xpdfObjIsString (*xpdfPluginVecTable._xpdfObjIsString) +#define xpdfObjIsName (*xpdfPluginVecTable._xpdfObjIsName) +#define xpdfObjIsNull (*xpdfPluginVecTable._xpdfObjIsNull) +#define xpdfObjIsArray (*xpdfPluginVecTable._xpdfObjIsArray) +#define xpdfObjIsDict (*xpdfPluginVecTable._xpdfObjIsDict) +#define xpdfObjIsStream (*xpdfPluginVecTable._xpdfObjIsStream) +#define xpdfObjIsRef (*xpdfPluginVecTable._xpdfObjIsRef) +#define xpdfBoolValue (*xpdfPluginVecTable._xpdfBoolValue) +#define xpdfIntValue (*xpdfPluginVecTable._xpdfIntValue) +#define xpdfRealValue (*xpdfPluginVecTable._xpdfRealValue) +#define xpdfStringLength (*xpdfPluginVecTable._xpdfStringLength) +#define xpdfStringValue (*xpdfPluginVecTable._xpdfStringValue) +#define xpdfNameValue (*xpdfPluginVecTable._xpdfNameValue) +#define xpdfArrayLength (*xpdfPluginVecTable._xpdfArrayLength) +#define xpdfArrayGet (*xpdfPluginVecTable._xpdfArrayGet) +#define xpdfDictGet (*xpdfPluginVecTable._xpdfDictGet) +#define xpdfFreeObj (*xpdfPluginVecTable._xpdfFreeObj) +#define xpdfMalloc (*xpdfPluginVecTable._xpdfMalloc) +#define xpdfRealloc (*xpdfPluginVecTable._xpdfRealloc) +#define xpdfFree (*xpdfPluginVecTable._xpdfFree) +#define xpdfRegisterSecurityHandler (*xpdfPluginVecTable._xpdfRegisterSecurityHandler) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pdftops/config.h b/pdftops/config.h new file mode 100644 index 000000000..4c8f75673 --- /dev/null +++ b/pdftops/config.h @@ -0,0 +1,112 @@ +//======================================================================== +// +// config.h +// +// Copyright 1996-2005 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef CONFIG_H +#define CONFIG_H + +//------------------------------------------------------------------------ +// version +//------------------------------------------------------------------------ + +// xpdf version +#define xpdfVersion "3.01" +#define xpdfVersionNum 3.01 +#define xpdfMajorVersion 3 +#define xpdfMinorVersion 1 +#define xpdfUpdateVersion 0 +#define xpdfMajorVersionStr "3" +#define xpdfMinorVersionStr "1" +#define xpdfUpdateVersionStr "0" + +// supported PDF version +#define supportedPDFVersionStr "1.5" +#define supportedPDFVersionNum 1.5 + +// copyright notice +#define xpdfCopyright "Copyright 1996-2005 Glyph & Cog, LLC" + +// Windows resource file stuff +#define winxpdfVersion "WinXpdf 3.01" +#define xpdfCopyrightAmp "Copyright 1996-2005 Glyph && Cog, LLC" + +//------------------------------------------------------------------------ +// paper size +//------------------------------------------------------------------------ + +// 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 + +//------------------------------------------------------------------------ +// config file (xpdfrc) path +//------------------------------------------------------------------------ + +// user config file name, relative to the user's home directory +#if defined(VMS) || (defined(WIN32) && !defined(__CYGWIN32__)) +#define xpdfUserConfigFile "xpdfrc" +#else +#define xpdfUserConfigFile ".xpdfrc" +#endif + +// system config file name (set via the configure script) +#ifdef SYSTEM_XPDFRC +#define xpdfSysConfigFile SYSTEM_XPDFRC +#else +// under Windows, we get the directory with the executable and then +// append this file name +#define xpdfSysConfigFile "xpdfrc" +#endif + +//------------------------------------------------------------------------ +// X-related constants +//------------------------------------------------------------------------ + +// default maximum size of color cube to allocate +#define defaultRGBCube 5 + +// number of fonts (combined t1lib, FreeType, X server) to cache +#define xOutFontCacheSize 64 + +// number of Type 3 fonts to cache +#define xOutT3FontCacheSize 8 + +//------------------------------------------------------------------------ +// popen +//------------------------------------------------------------------------ + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define popen _popen +#define pclose _pclose +#endif + +#if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(MACOS) +#define POPEN_READ_MODE "rb" +#else +#define POPEN_READ_MODE "r" +#endif + +//------------------------------------------------------------------------ +// Win32 stuff +//------------------------------------------------------------------------ + +#ifdef CDECL +#undef CDECL +#endif + +#if defined(_MSC_VER) || defined(__BORLANDC__) +#define CDECL __cdecl +#else +#define CDECL +#endif + +#endif diff --git a/pdftops/gfile.cxx b/pdftops/gfile.cxx new file mode 100644 index 000000000..ae0ea9ce2 --- /dev/null +++ b/pdftops/gfile.cxx @@ -0,0 +1,707 @@ +//======================================================================== +// +// gfile.cc +// +// Miscellaneous file and directory name manipulation. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include + +#ifndef WIN32 +# if defined(MACOS) +# include +# elif !defined(ACORN) +# include +# include +# include +# endif +# include +# include +# if !defined(VMS) && !defined(ACORN) && !defined(MACOS) +# include +# endif +# if defined(VMS) && (__DECCXX_VER < 50200000) +# include +# endif +#endif // WIN32 +#include "GString.h" +#include "gfile.h" + +// 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); + } 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, 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(char *fileName) { +#ifdef VMS + //---------- VMS ---------- + 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 ---------- + 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 ---------- + char *p; + + if ((p = strrchr(fileName, '.'))) + return new GString(fileName, p - fileName); + return new GString(); + +#elif defined(MACOS) + //---------- MacOS ---------- + char *p; + + if ((p = strrchr(fileName, ':'))) + return new GString(fileName, p - fileName); + return new GString(); + +#else + //---------- Unix ---------- + char *p; + + if ((p = strrchr(fileName, '/'))) + return new GString(fileName, p - fileName); + return new GString(); +#endif +} + +GBool isAbsolutePath(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(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 +} + +#if 0 // Not needed for PS output +GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { +#if defined(WIN32) + //---------- Win32 ---------- + char *s; + + if (!(s = _tempnam(getenv("TEMP"), NULL))) { + return gFalse; + } + *name = new GString(s); + free(s); + if (ext) { + (*name)->append(ext); + } + if (!(*f = fopen((*name)->getCString(), mode))) { + delete (*name); + return gFalse; + } + return gTrue; +#elif defined(VMS) || defined(__EMX__) || 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; + + if (ext) { +#if HAVE_MKSTEMPS + if ((s = getenv("TMPDIR"))) { + *name = new GString(s); + } else { + *name = new GString("/tmp"); + } + (*name)->append("/XXXXXX")->append(ext); + fd = mkstemps((*name)->getCString(), strlen(ext)); +#else + if (!(s = tmpnam(NULL))) { + return gFalse; + } + *name = new GString(s); + (*name)->append(ext); + fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); +#endif + } 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 +} + +GBool executeCommand(char *cmd) { +#ifdef VMS + return system(cmd) ? gTrue : gFalse; +#else + return system(cmd) ? gFalse : gTrue; +#endif +} +#endif // 0 + +char *getLine(char *buf, int size, FILE *f) { + int c, i; + + i = 0; + while (i < size - 1) { + if ((c = fgetc(f)) == EOF) { + break; + } + buf[i++] = (char)c; + if (c == '\x0a') { + break; + } + if (c == '\x0d') { + c = fgetc(f); + if (c == '\x0a' && i < size - 1) { + buf[i++] = (char)c; + } else if (c != EOF) { + ungetc(c, f); + } + break; + } + } + buf[i] = '\0'; + if (i == 0) { + return NULL; + } + return buf; +} + +//------------------------------------------------------------------------ +// GDir and GDirEntry +//------------------------------------------------------------------------ + +GDirEntry::GDirEntry(char *dirPath, char *nameA, 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(nameA); + dir = gFalse; + if (doStat) { +#ifdef VMS + if (!strcmp(nameA, "-") || + ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5))) + dir = gTrue; +#elif defined(ACORN) +#else + s = new GString(dirPath); + appendToPath(s, nameA); +#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(char *name, GBool doStatA) { + path = new GString(name); + doStat = doStatA; +#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() { + GDirEntry *e; + +#if defined(WIN32) + if (hnd) { + e = new GDirEntry(path->getCString(), ffd.cFileName, doStat); + if (hnd && !FindNextFile(hnd, &ffd)) { + FindClose(hnd); + hnd = NULL; + } + } else { + e = NULL; + } +#elif defined(ACORN) +#elif defined(MACOS) +#elif defined(VMS) + struct dirent *ent; + e = NULL; + if (dir) { + if (needParent) { + e = new GDirEntry(path->getCString(), "-", doStat); + needParent = gFalse; + return e; + } + ent = readdir(dir); + if (ent) { + e = new GDirEntry(path->getCString(), ent->d_name, doStat); + } + } +#else + struct dirent *ent; + e = NULL; + if (dir) { + ent = readdir(dir); + if (ent && !strcmp(ent->d_name, ".")) { + ent = readdir(dir); + } + 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); + delete tmp; +#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..808e1821d --- /dev/null +++ b/pdftops/gfile.h @@ -0,0 +1,126 @@ +//======================================================================== +// +// gfile.h +// +// Miscellaneous file and directory name manipulation. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#ifndef GFILE_H +#define GFILE_H + +#include +#include +#include +#if defined(WIN32) +# include +# ifdef FPTEX +# include +# else +# include +# endif +#elif defined(ACORN) +#elif defined(MACOS) +# include +#else +# include +# include +# ifdef VMS +# include "vms_dirent.h" +# else +# include +# define NAMLEN(d) strlen((d)->d_name) +# 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. may be an empty +// string, denoting the current directory). Returns . +extern GString *appendToPath(GString *path, char *fileName); + +// Grab the path from the front of the file name. If there is no +// directory component in , returns an empty string. +extern GString *grabPath(char *fileName); + +// Is this an absolute path or file name? +extern GBool isAbsolutePath(char *path); + +// Make this path absolute by prepending current directory (if path is +// relative) or prepending user's directory (if path starts with '~'). +extern GString *makePathAbsolute(GString *path); + +// Get the modification time for . Returns 0 if there is an +// error. +extern time_t getModTime(char *fileName); + +// Create a temporary file and open it for writing. If 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 string +// should be "w" or "wb". Returns true on success. +extern GBool openTempFile(GString **name, FILE **f, char *mode, char *ext); + +// Execute . Returns true on success. +extern GBool executeCommand(char *cmd); + +// Just like fgets, but handles Unix, Mac, and/or DOS end-of-line +// conventions. +extern char *getLine(char *buf, int size, FILE *f); + +//------------------------------------------------------------------------ +// GDir and GDirEntry +//------------------------------------------------------------------------ + +class GDirEntry { +public: + + GDirEntry(char *dirPath, char *nameA, 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(char *name, GBool doStatA = 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..8f6526100 --- /dev/null +++ b/pdftops/gmem.c @@ -0,0 +1,229 @@ +/* + * gmem.c + * + * Memory routines with out-of-memory checking. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#include +#include +#include +#include +#include +#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 0xdeadbeefdeadbeefUL +#else +#define gMemDeadVal 0xdeadbeefUL +#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; +static int gMemInUse = 0; + +#endif /* DEBUG_MEM */ + +void *gmalloc(int size) { +#ifdef DEBUG_MEM + int size1; + char *mem; + GMemHdr *hdr; + void *data; + int lst; + unsigned 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 = (unsigned long *)(mem + gMemHdrSize + size1); + hdr->size = size; + hdr->index = gMemIndex++; + lst = ((int)hdr >> gMemListShift) & gMemListMask; + hdr->next = gMemList[lst]; + gMemList[lst] = hdr; + ++gMemAlloc; + gMemInUse += size; + for (p = (unsigned 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 *gmallocn(int nObjs, int objSize) { + int n; + + n = nObjs * objSize; + if (objSize == 0 || n / objSize != nObjs) { + fprintf(stderr, "Bogus memory allocation size\n"); + exit(1); + } + return gmalloc(n); +} + +void *greallocn(void *p, int nObjs, int objSize) { + int n; + + n = nObjs * objSize; + if (objSize == 0 || n / objSize != nObjs) { + fprintf(stderr, "Bogus memory allocation size\n"); + exit(1); + } + return grealloc(p, n); +} + +void gfree(void *p) { +#ifdef DEBUG_MEM + int size; + GMemHdr *hdr; + GMemHdr *prevHdr, *q; + int lst; + unsigned 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; + gMemInUse -= hdr->size; + size = gMemDataSize(hdr->size); + trl = (unsigned 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 = (unsigned 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(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..e74d18223 --- /dev/null +++ b/pdftops/gmem.h @@ -0,0 +1,62 @@ +/* + * gmem.h + * + * Memory routines with out-of-memory checking. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#ifndef GMEM_H +#define GMEM_H + +#include + +#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

    is NULL, calls malloc instead of realloc(). + */ +extern void *grealloc(void *p, int size); + +/* + * These are similar to gmalloc and grealloc, but take an object count + * and size. The result is similar to allocating nObjs * objSize + * bytes, but there is an additional error check that the total size + * doesn't overflow an int. + */ +extern void *gmallocn(int nObjs, int objSize); +extern void *greallocn(void *p, int nObjs, int objSize); + +/* + * 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(char *s); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/pdftops/gmempp.cxx b/pdftops/gmempp.cxx new file mode 100644 index 000000000..a70338ca3 --- /dev/null +++ b/pdftops/gmempp.cxx @@ -0,0 +1,32 @@ +//======================================================================== +// +// gmempp.cc +// +// Use gmalloc/gfree for C++ new/delete operators. +// +// Copyright 1996-2003 Glyph & Cog, LLC +// +//======================================================================== + +#include +#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..9f64f57d4 --- /dev/null +++ b/pdftops/gtypes.h @@ -0,0 +1,29 @@ +/* + * gtypes.h + * + * Some useful simple types. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#ifndef GTYPES_H +#define GTYPES_H + +/* + * 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 , + * 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..f77cc85c8 --- /dev/null +++ b/pdftops/parseargs.c @@ -0,0 +1,190 @@ +/* + * parseargs.h + * + * Command line argument parser. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#include +#include +#include +#include +#include +#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 = " "; + break; + case argFP: + case argFPDummy: + typ = " "; + break; + case argString: + case argStringDummy: + typ = " "; + 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 & 0xff)) + ++s; + if (*s) + return gFalse; + return gTrue; +} + +GBool isFP(char *s) { + int n; + + if (*s == '-' || *s == '+') + ++s; + n = 0; + while (isdigit(*s & 0xff)) { + ++s; + ++n; + } + if (*s == '.') + ++s; + while (isdigit(*s & 0xff)) { + ++s; + ++n; + } + if (n > 0 && (*s == 'e' || *s == 'E')) { + ++s; + if (*s == '-' || *s == '+') + ++s; + n = 0; + if (!isdigit(*s & 0xff)) + return gFalse; + do { + ++s; + } while (isdigit(*s & 0xff)); + } + if (*s) + return gFalse; + return gTrue; +} diff --git a/pdftops/parseargs.h b/pdftops/parseargs.h new file mode 100644 index 000000000..0d163b985 --- /dev/null +++ b/pdftops/parseargs.h @@ -0,0 +1,71 @@ +/* + * parseargs.h + * + * Command line argument parser. + * + * Copyright 1996-2003 Glyph & Cog, LLC + */ + +#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 . 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..b9459cfa9 --- /dev/null +++ b/pdftops/pdftops.cxx @@ -0,0 +1,345 @@ +// +// "$Id: pdftops.cxx 4906 2006-01-10 20:53:28Z mike $" +// +// PDF to PostScript filter front-end for the Common UNIX Printing +// System (CUPS). +// +// Copyright 1997-2006 by Easy Software Products. +// +// These coded instructions, statements, and computer programs are the +// property of Easy Software Products and are protected by Federal +// copyright law. Distribution and use rights are outlined in the file +// "LICENSE.txt" which should have been included with this file. If this +// file is missing or damaged please contact Easy Software Products +// at: +// +// Attn: CUPS Licensing Information +// Easy Software Products +// 44141 Airport View Drive, Suite 204 +// Hollywood, Maryland 20636 USA +// +// Voice: (301) 373-9600 +// EMail: cups-info@cups.org +// WWW: http://www.cups.org +// +// Contents: +// +// main() - Main entry for filter... +// + +// +// Include necessary headers... +// + +#include +#include +#include +#include +#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 "GlobalParams.h" +#include "Error.h" +#include "config.h" + +#include + + +// +// 'main()' - Main entry for filter... +// + +int // O - Exit status +main(int argc, // I - Number of command-line args + char *argv[]) // I - Command-line arguments +{ + PDFDoc *doc; // Input file + GString *fileName; // Input filename + GString *psFileName; // Output filename + PSLevel level; // PostScript level + PSOutputDev *psOut; // Output device + int num_options; // Number of options + cups_option_t *options; // Options + const char *val; // Option value + ppd_file_t *ppd; // Current PPD + ppd_size_t *size; // Current media size + int fd; // Copy file descriptor + const char *server_root; // Location of config files + char tempfile[1024]; // Temporary file + char buffer[8192]; // Copy buffer + int bytes; // Bytes copied + int width, length; // Size in points + int left, bottom, right, top; + // Imageable area in points + int orientation; // Orientation + int temp; // Temporary var + int duplex; // Duplex the output? + int fit; // Fit the pages to the output + int printCommands; // Output debug info for commands? + + + // Make sure status messages are not buffered... + setbuf(stderr, NULL); + + // 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 ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) { + 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) + write(fd, buffer, bytes); + close(fd); + + fileName = new GString(tempfile); + } else { + fileName = new GString(argv[6]); + tempfile[0] = '\0'; + } + + // Default to "Universal" size - min of A4 and Letter... + left = 0; + bottom = 0; + right = 595; + top = 792; + width = 595; + length = 792; + level = psLevel2; + duplex = 0; + fit = 0; + + // Get PPD and initialize options as needed... + num_options = cupsParseOptions(argv[5], 0, &options); + + if ((ppd = ppdOpenFile(getenv("PPD"))) != NULL) + { + fprintf(stderr, "DEBUG: pdftops - opened PPD file \"%s\"...\n", getenv("PPD")); + + ppdMarkDefaults(ppd); + cupsMarkOptions(ppd, num_options, options); + + if ((size = ppdPageSize(ppd, NULL)) != NULL) + { + left = (int)size->left; + bottom = (int)size->bottom; + right = (int)size->right; + top = (int)size->top; + width = (int)size->width; + length = (int)size->length; + } + + level = ppd->language_level == 1 ? psLevel1 : psLevel2; + } + + // Track the orientation of the print job and update the page + // dimensions and margins as needed... + orientation = 0; + + if ((val = cupsGetOption("landscape", num_options, options)) != NULL) + { + if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 && + strcasecmp(val, "false") != 0) + orientation = 1; + } + else 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; + } + + switch (orientation & 3) + { + case 0 : /* Portait */ + break; + + case 1 : /* Landscape */ + temp = left; + left = bottom; + bottom = temp; + + temp = right; + right = top; + top = temp; + + temp = width; + width = length; + length = temp; + break; + + case 2 : /* Reverse Portrait */ + temp = width - left; + left = width - right; + right = temp; + + temp = length - bottom; + bottom = length - top; + top = temp; + break; + + case 3 : /* Reverse Landscape */ + temp = width - left; + left = width - right; + right = temp; + + temp = length - bottom; + bottom = length - top; + top = temp; + + temp = left; + left = bottom; + bottom = temp; + + temp = right; + right = top; + top = temp; + + temp = width; + width = length; + length = temp; + break; + } + + if ((val = cupsGetOption("debug", num_options, options)) != NULL && + strcasecmp(val, "no") && strcasecmp(val, "off") && + strcasecmp(val, "false")) + printCommands = 1; + else + printCommands = 0; + + if ((val = cupsGetOption("fitplot", num_options, options)) != NULL && + strcasecmp(val, "no") && strcasecmp(val, "off") && + strcasecmp(val, "false")) + fit = 1; + + 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 ((val = cupsGetOption("JCLDuplex", num_options, options)) != NULL && + strncasecmp(val, "Duplex", 6) == 0) + duplex = 1; + else if ((val = cupsGetOption("EFDuplex", num_options, options)) != NULL && + strncasecmp(val, "Duplex", 6) == 0) + duplex = 1; + else if ((val = cupsGetOption("KD03Duplex", num_options, options)) != NULL && + strncasecmp(val, "Duplex", 6) == 0) + duplex = 1; + else if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "Duplex", "DuplexTumble") || + ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") || + ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") || + ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") || + ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble")) + duplex = 1; + + if (ppd != NULL) + ppdClose(ppd); + + fprintf(stderr, "DEBUG: pdftops - level = %d, width = %d, length = %d\n", + level, width, length); + + // read config file + if ((server_root = getenv("CUPS_SERVERROOT")) == NULL) + server_root = CUPS_SERVERROOT; + + snprintf(buffer, sizeof(buffer), "%s/pdftops.conf", server_root); + + globalParams = new GlobalParams(buffer); + + globalParams->setPSPaperWidth(width); + globalParams->setPSPaperHeight(length); + globalParams->setPSImageableArea(left, bottom, right, top); + globalParams->setPSDuplex(duplex); + globalParams->setPSExpandSmaller(fit); + globalParams->setPSShrinkLarger(fit); + globalParams->setPSLevel(level); + globalParams->setPSASCIIHex(level == psLevel1); + globalParams->setPSEmbedType1(1); + globalParams->setPSEmbedTrueType(1); + globalParams->setPSEmbedCIDPostScript(1); + globalParams->setErrQuiet(0); + globalParams->setPrintCommands(printCommands); + + if (printCommands) + setbuf(stdout, NULL); + + // open PDF file + doc = new PDFDoc(fileName, NULL, 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(), + psModePS, 0, 0, 0, 0, gFalse, + cupsGetOption("page-ranges", num_options, options)); + if (psOut->isOk()) + doc->displayPages(psOut, 1, doc->getNumPages(), 72.0, 72.0, 0, + gTrue, gFalse, gFalse); + delete psOut; + + // clean up + delete psFileName; + } + else + { + error(-1, "Unable to print this document."); + } + + cupsFreeOptions(num_options, options); + + delete doc; + delete globalParams; + + // check for memory leaks + Object::memCheck(stderr); + gMemReport(stderr); + + // Remove temp file if needed... + if (tempfile[0]) + unlink(tempfile); + + return 0; +} + + +// +// End of "$Id: pdftops.cxx 4906 2006-01-10 20:53:28Z mike $". +// diff --git a/ppd/Makefile b/ppd/Makefile new file mode 100644 index 000000000..0c5262574 --- /dev/null +++ b/ppd/Makefile @@ -0,0 +1,64 @@ +# +# "$Id: Makefile 4905 2006-01-10 20:07:15Z mike $" +# +# PPD file makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2006 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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 zebra.ppd zebraep1.ppd \ + zebraep2.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: Makefile 4905 2006-01-10 20:07:15Z mike $". +# diff --git a/ppd/deskjet.ppd b/ppd/deskjet.ppd new file mode 100644 index 000000000..4752f013a --- /dev/null +++ b/ppd/deskjet.ppd @@ -0,0 +1,199 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: deskjet.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample HP DeskJet driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "DESKJET.PPD" +*Manufacturer: "HP" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal/US Legal: "<>setpagedevice" +*PageSize Executive/US Executive: "<>setpagedevice" +*PageSize Tabloid/US Tabloid: "<>setpagedevice" +*PageSize A3/A3: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/US Letter: "<>setpagedevice" +*PageRegion Legal/US Legal: "<>setpagedevice" +*PageRegion Executive/US Executive: "<>setpagedevice" +*PageRegion Tabloid/US Tabloid: "<>setpagedevice" +*PageRegion A3/A3: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "18 36 594 756" +*ImageableArea Legal/US Legal: "18 36 594 972" +*ImageableArea Executive/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: "<>setpagedevice" +*MediaType Bond/Bond Paper: "<>setpagedevice" +*MediaType Special/Special Paper: "<>setpagedevice" +*MediaType Transparency/Transparency: "<>setpagedevice" +*MediaType Glossy/Glossy Paper: "<>setpagedevice" +*CloseUI: *MediaType + +*OpenUI *InputSlot/Media Source: PickOne +*OrderDependency: 10 AnySetup *InputSlot +*DefaultInputSlot: Tray +*InputSlot Tray/Tray: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 300dpi +*Resolution 150dpi/150 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/CMYK Color: "<>setpagedevice" +*ColorModel RGB/CMY Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: deskjet.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/deskjet2.ppd b/ppd/deskjet2.ppd new file mode 100644 index 000000000..f583b08d6 --- /dev/null +++ b/ppd/deskjet2.ppd @@ -0,0 +1,218 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: deskjet2.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Second sample HP DeskJet driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "DESKJET2.PPD" +*Manufacturer: "HP" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal/US Legal: "<>setpagedevice" +*PageSize Executive/US Executive: "<>setpagedevice" +*PageSize Tabloid/US Tabloid: "<>setpagedevice" +*PageSize A3/A3: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/US Letter: "<>setpagedevice" +*PageRegion Legal/US Legal: "<>setpagedevice" +*PageRegion Executive/US Executive: "<>setpagedevice" +*PageRegion Tabloid/US Tabloid: "<>setpagedevice" +*PageRegion A3/A3: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "18 36 594 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: "<>setpagedevice" +*MediaType Bond/Bond Paper: "<>setpagedevice" +*MediaType Special/Special Paper: "<>setpagedevice" +*MediaType Transparency/Transparency: "<>setpagedevice" +*MediaType Glossy/Glossy Paper: "<>setpagedevice" +*CloseUI: *MediaType + +*OpenUI *InputSlot/Media Source: PickOne +*OrderDependency: 10 AnySetup *InputSlot +*DefaultInputSlot: Tray +*InputSlot Tray/Tray: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 300dpi +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600x300dpi/600x300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK2/CRET Color: "<>setpagedevice" +*ColorModel CMYK/CMYK Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*OpenUI *Duplex/Double-Sided Printing: PickOne +*OrderDependency: 20 PageSetup *Duplex +*DefaultDuplex: None +*Duplex None/Off: "<>setpagedevice" +*Duplex DuplexNoTumble/Long Edge (Standard): "<>setpagedevice" +*Duplex DuplexTumble/Short Edge (Flip): "<>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: deskjet2.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/dymo.ppd b/ppd/dymo.ppd new file mode 100644 index 000000000..656c8b444 --- /dev/null +++ b/ppd/dymo.ppd @@ -0,0 +1,156 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: dymo.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample DYMO label printer driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 2001-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "DYMO.PPD" +*Manufacturer: "Dymo" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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": "<>setpagedevice" +*PageSize w101h252/Large Address - 1 4/10 x 3 1/2": "<>setpagedevice" +*PageSize w54h144/Return Address - 3/4 x 2": "<>setpagedevice" +*PageSize w167h288/Shipping Address - 2 5/16 x 4": "<>setpagedevice" +*PageSize w162h540/Internet Postage 2-Part - 2 1/4 x 7 1/2": "<>setpagedevice" +*PageSize w162h504/Internet Postage 3-Part - 2 1/4 x 7": "<>setpagedevice" +*PageSize w41h248/File Folder - 9/16 x 3 7/16": "<>setpagedevice" +*PageSize w41h144/Hanging Folder - 9/16 x 2": "<>setpagedevice" +*PageSize w153h198/3.5" Disk - 2 1/8 x 2 3/4": "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: w81h252 +*PageRegion w81h252/Address - 1 1/8 x 3 1/2": "<>setpagedevice" +*PageRegion w101h252/Large Address - 1 4/10 x 3 1/2": "<>setpagedevice" +*PageRegion w54h144/Return Address - 3/4 x 2": "<>setpagedevice" +*PageRegion w167h288/Shipping Address - 2 5/16 x 4": "<>setpagedevice" +*PageRegion w162h540/Internet Postage 2-Part - 2 1/4 x 7 1/2": "<>setpagedevice" +*PageRegion w162h504/Internet Postage 3-Part - 2 1/4 x 7": "<>setpagedevice" +*PageRegion w41h248/File Folder - 9/16 x 3 7/16": "<>setpagedevice" +*PageRegion w41h144/Hanging Folder - 9/16 x 2": "<>setpagedevice" +*PageRegion w153h198/3.5" Disk - 2 1/8 x 2 3/4": "<>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: "<>setpagedevice" +*Resolution 203dpi/203 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *Darkness/Output Darkness: PickOne +*OrderDependency: 20 AnySetup *Darkness +*DefaultDarkness: Normal +*Darkness Light: "<>setpagedevice" +*Darkness Medium: "<>setpagedevice" +*Darkness Normal: "<>setpagedevice" +*Darkness Dark: "<>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: dymo.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/epson24.ppd b/ppd/epson24.ppd new file mode 100644 index 000000000..689c2c368 --- /dev/null +++ b/ppd/epson24.ppd @@ -0,0 +1,139 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: epson24.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample EPSON 24-Pin driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "EPSON24.PPD" +*Manufacturer: "Epson" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*LanguageLevel: "3" +*ColorDevice: False +*DefaultColorSpace: Gray +*FileSystem: False +*Throughput: "1" +*LandscapeOrientation: Plus90 +*VariablePaperSize: True +*TTRasterizer: Type42 + +*OpenUI *PageSize/Media Size: PickOne +*OrderDependency: 10 AnySetup *PageSize +*DefaultPageSize: Letter +*PageSize Letter: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*PageSize FanFoldUS: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*PageRegion FanFoldUS: "<>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" + +*MaxMediaWidth: "1080" +*MaxMediaHeight: "86400" +*HWMargins: 0 0 0 0 +*CustomPageSize True: "pop pop pop <>setpagedevice" +*ParamCustomPageSize Width: 1 points 36 1080 +*ParamCustomPageSize Height: 2 points 36 86400 +*ParamCustomPageSize WidthOffset: 3 points 0 0 +*ParamCustomPageSize HeightOffset: 4 points 0 0 +*ParamCustomPageSize Orientation: 5 int 0 0 + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 120dpi +*Resolution 60dpi/60 DPI: "<>setpagedevice" +*Resolution 120dpi/120x60 DPI: "<>setpagedevice" +*Resolution 180dpi/180 DPI: "<>setpagedevice" +*Resolution 360x180dpi/360x180 DPI: "<>setpagedevice" +*Resolution 360dpi/360 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: epson24.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/epson9.ppd b/ppd/epson9.ppd new file mode 100644 index 000000000..97470aa00 --- /dev/null +++ b/ppd/epson9.ppd @@ -0,0 +1,137 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: epson9.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample EPSON 9-Pin driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "EPSON9.PPD" +*Manufacturer: "Epson" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*LanguageLevel: "3" +*ColorDevice: False +*DefaultColorSpace: Gray +*FileSystem: False +*Throughput: "1" +*LandscapeOrientation: Plus90 +*VariablePaperSize: True +*TTRasterizer: Type42 + +*OpenUI *PageSize/Media Size: PickOne +*OrderDependency: 10 AnySetup *PageSize +*DefaultPageSize: Letter +*PageSize Letter: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*PageSize FanFoldUS: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*PageRegion FanFoldUS: "<>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" + +*MaxMediaWidth: "1080" +*MaxMediaHeight: "86400" +*HWMargins: 0 0 0 0 +*CustomPageSize True: "pop pop pop <>setpagedevice" +*ParamCustomPageSize Width: 1 points 36 1080 +*ParamCustomPageSize Height: 2 points 36 86400 +*ParamCustomPageSize WidthOffset: 3 points 0 0 +*ParamCustomPageSize HeightOffset: 4 points 0 0 +*ParamCustomPageSize Orientation: 5 int 0 0 + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 120dpi +*Resolution 60dpi/60x72 DPI: "<>setpagedevice" +*Resolution 120dpi/120x72 DPI: "<>setpagedevice" +*Resolution 240dpi/240x72 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: epson9.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/laserjet.ppd b/ppd/laserjet.ppd new file mode 100644 index 000000000..5c02dcecb --- /dev/null +++ b/ppd/laserjet.ppd @@ -0,0 +1,201 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: laserjet.ppd 4905 2006-01-10 20:07:15Z mike $" +*% +*% Sample HP LaserJet driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2006 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "LASERJET.PPD" +*Manufacturer: "HP" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-raster 0 rastertohp" +*cupsModelNumber: 0 +*ModelName: "HP LaserJet Series PCL 4/5" +*ShortNickName: "HP LaserJet Series PCL 4/5" +*NickName: "HP LaserJet Series PCL 4/5 CUPS v1.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal/US Legal: "<>setpagedevice" +*PageSize Executive/US Executive: "<>setpagedevice" +*PageSize Tabloid/US Tabloid: "<>setpagedevice" +*PageSize A3/A3: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/US Letter: "<>setpagedevice" +*PageRegion Legal/US Legal: "<>setpagedevice" +*PageRegion Executive/US Executive: "<>setpagedevice" +*PageRegion Tabloid/US Tabloid: "<>setpagedevice" +*PageRegion A3/A3: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "18 36 594 756" +*ImageableArea Legal/US Legal: "18 36 594 972" +*ImageableArea Executive/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: "<>setpagedevice" +*InputSlot Tray1/Tray 1: "<>setpagedevice" +*InputSlot Tray2/Tray 2: "<>setpagedevice" +*InputSlot Tray3/Tray 3: "<>setpagedevice" +*InputSlot Tray4/Tray 4: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 300dpi +*Resolution 150dpi/150 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *Duplex/Double-Sided Printing: PickOne +*OrderDependency: 20 AnySetup *Duplex +*DefaultDuplex: None +*Duplex None/Off: "<>setpagedevice" +*Duplex DuplexNoTumble/Long Edge (Standard): "<>setpagedevice" +*Duplex DuplexTumble/Short Edge (Flip): "<>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: laserjet.ppd 4905 2006-01-10 20:07:15Z mike $". +*% diff --git a/ppd/okidat24.ppd b/ppd/okidat24.ppd new file mode 100644 index 000000000..b60f0634d --- /dev/null +++ b/ppd/okidat24.ppd @@ -0,0 +1,129 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: okidat24.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample OKIDATA 24-Pin driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.1" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "OKIDAT24.PPD" +*Manufacturer: "Oki" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*PageSize FanFoldUS: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*PageRegion FanFoldUS: "<>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: "<>setpagedevice" +*Resolution 120dpi/120x60 DPI: "<>setpagedevice" +*Resolution 180dpi/180 DPI: "<>setpagedevice" +*Resolution 360x180dpi/360x180 DPI: "<>setpagedevice" +*Resolution 360dpi/360 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: okidat24.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/okidata9.ppd b/ppd/okidata9.ppd new file mode 100644 index 000000000..189c8db6d --- /dev/null +++ b/ppd/okidata9.ppd @@ -0,0 +1,127 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: okidata9.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample OKIDATA 9-Pin driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "OKIDATA9.PPD" +*Manufacturer: "Oki" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*PageSize FanFoldUS: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*PageRegion FanFoldUS: "<>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: "<>setpagedevice" +*Resolution 120dpi/120x72 DPI: "<>setpagedevice" +*Resolution 240dpi/240x72 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: okidata9.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/stcolor.ppd b/ppd/stcolor.ppd new file mode 100644 index 000000000..aba03926b --- /dev/null +++ b/ppd/stcolor.ppd @@ -0,0 +1,133 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: stcolor.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample EPSON Stylus Color driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "STCOLOR.PPD" +*Manufacturer: "Epson" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter: "8.60 39.60 603.40 766.49" +*ImageableArea Legal: "8.60 39.60 603.40 982.49" +*ImageableArea A4: "8.60 39.60 586.40 816.49" + +*DefaultPaperDimension: Letter +*PaperDimension Letter: "612 792" +*PaperDimension Legal: "612 1008" +*PaperDimension A4: "595 842" + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 360dpi +*Resolution 180dpi/180 DPI: "<>setpagedevice" +*Resolution 360dpi/360 DPI: "<>setpagedevice{0.6666 exp}bind settransfer" +*Resolution 720dpi/720 DPI: "<>setpagedevice{0.4 exp}bind settransfer" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: stcolor.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/stcolor2.ppd b/ppd/stcolor2.ppd new file mode 100644 index 000000000..f66142b47 --- /dev/null +++ b/ppd/stcolor2.ppd @@ -0,0 +1,133 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: stcolor2.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample EPSON Stylus Color driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "STCOLOR2.PPD" +*Manufacturer: "Epson" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter: "8.60 39.60 603.40 766.49" +*ImageableArea Legal: "8.60 39.60 603.40 982.49" +*ImageableArea A4: "8.60 39.60 586.40 816.49" + +*DefaultPaperDimension: Letter +*PaperDimension Letter: "612 792" +*PaperDimension Legal: "612 1008" +*PaperDimension A4: "595 842" + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 360dpi +*Resolution 180dpi/180 DPI: "<>setpagedevice" +*Resolution 360dpi/360 DPI: "<>setpagedevice{0.6666 exp}bind settransfer" +*Resolution 720dpi/720 DPI: "<>setpagedevice{0.4 exp}bind settransfer" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: stcolor2.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/stphoto.ppd b/ppd/stphoto.ppd new file mode 100644 index 000000000..ce01eba5f --- /dev/null +++ b/ppd/stphoto.ppd @@ -0,0 +1,133 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: stphoto.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample EPSON Stylus Photo driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "STPHOTO.PPD" +*Manufacturer: "Epson" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter: "8.60 39.60 603.40 766.49" +*ImageableArea Legal: "8.60 39.60 603.40 982.49" +*ImageableArea A4: "8.60 39.60 586.40 816.49" + +*DefaultPaperDimension: Letter +*PaperDimension Letter: "612 792" +*PaperDimension Legal: "612 1008" +*PaperDimension A4: "595 842" + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 360dpi +*Resolution 180dpi/180 DPI: "<>setpagedevice" +*Resolution 360dpi/360 DPI: "<>setpagedevice{0.6666 exp}bind settransfer" +*Resolution 720dpi/720 DPI: "<>setpagedevice{0.4 exp}bind settransfer" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: stphoto.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/stphoto2.ppd b/ppd/stphoto2.ppd new file mode 100644 index 000000000..f093582da --- /dev/null +++ b/ppd/stphoto2.ppd @@ -0,0 +1,133 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: stphoto2.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample EPSON Stylus Photo driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "STPHOTO2.PPD" +*Manufacturer: "Epson" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*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.2" +*PSVersion: "(3010.000) 81501" +*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: "<>setpagedevice" +*PageSize Legal: "<>setpagedevice" +*PageSize A4: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter: "<>setpagedevice" +*PageRegion Legal: "<>setpagedevice" +*PageRegion A4: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter: "8.60 39.60 603.40 766.49" +*ImageableArea Legal: "8.60 39.60 603.40 982.49" +*ImageableArea A4: "8.60 39.60 586.40 816.49" + +*DefaultPaperDimension: Letter +*PaperDimension Letter: "612 792" +*PaperDimension Legal: "612 1008" +*PaperDimension A4: "595 842" + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 360dpi +*Resolution 180dpi/180 DPI: "<>setpagedevice" +*Resolution 360dpi/360 DPI: "<>setpagedevice{0.6666 exp}bind settransfer" +*Resolution 720dpi/720 DPI: "<>setpagedevice{0.4 exp}bind settransfer" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: stphoto2.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/zebra.ppd b/ppd/zebra.ppd new file mode 100644 index 000000000..23883e2e9 --- /dev/null +++ b/ppd/zebra.ppd @@ -0,0 +1,332 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: zebra.ppd 4920 2006-01-12 15:12:12Z mike $" +*% +*% Sample Zebra label printer driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 2001-2006 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "ZEBRA.PPD" +*Manufacturer: "Zebra" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-raster 0 rastertodymo" +*% cupsModelNumber is 16 for EPL1 line mode, 17 for EPL2 page mode, +*% 18 for ZPL mode, and 19 for CPCL mode. +*cupsModelNumber: 18 +*ModelName: "Zebra ZPL Label Printer" +*ShortNickName: "Zebra ZPL Label Printer" +*NickName: "Zebra ZPL Label Printer CUPS v1.2" +*PSVersion: "(3010.000) 81501" +*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: w288h360 +*PageSize w288h360/Label - 4 x 5": "<>setpagedevice" +*PageSize w288h432/Label - 4 x 6": "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: w288h360 +*PageRegion w288h360/Label - 4 x 5": "<>setpagedevice" +*PageRegion w288h432/Label - 4 x 6": "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: w288h360 +*ImageableArea w288h360/Label - 4 x 5": "0 0 288 360" +*ImageableArea w288h432/Label - 4 x 6": "0 0 288 432" + +*DefaultPaperDimension: w288h360 +*PaperDimension w288h360/Label - 4 x 5": "288 360" +*PaperDimension w288h432/Label - 4 x 6": "288 432" + +*MaxMediaWidth: "288" +*MaxMediaHeight: "3600" +*HWMargins: 0 0 0 0 +*CustomPageSize True: "pop pop pop <>setpagedevice" +*ParamCustomPageSize Width: 1 points 36 288 +*ParamCustomPageSize Height: 2 points 36 3600 +*ParamCustomPageSize WidthOffset: 3 points 0 0 +*ParamCustomPageSize HeightOffset: 4 points 0 0 +*ParamCustomPageSize Orientation: 5 int 0 0 + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 203dpi +*Resolution 203dpi/203 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *zeMediaTracking/Media Tracking: PickOne +*OrderDependency: 20 AnySetup *zeMediaTracking +*DefaultzeMediaTracking: Web +*zeMediaTracking Continuous: "" +*zeMediaTracking Web/Non-continuous (Web sensing): "" +*zeMediaTracking Mark/Non-continuous (Mark sensing): "" +*CloseUI: *zeMediaTracking + +*OpenUI *MediaType/Media Type: PickOne +*OrderDependency: 20 AnySetup *MediaType +*DefaultMediaType: Saved +*MediaType Saved/PrinterDefault: "" +*MediaType Thermal/Thermal Transfer Media: "<>setpagedevice" +*MediaType Direct/Direct Thermal Media: "<>setpagedevice" +*CloseUI: *zeMediaType + +*OpenGroup: PrinterSettings/Printer Settings +*OpenUI *Darkness/Media Darkness: PickOne +*OrderDependency: 20 AnySetup *Darkness +*DefaultDarkness: -1 +*Darkness -1/PrinterDefault: "<>setpagedevice" +*Darkness 1: "<>setpagedevice" +*Darkness 2: "<>setpagedevice" +*Darkness 3: "<>setpagedevice" +*Darkness 4: "<>setpagedevice" +*Darkness 5: "<>setpagedevice" +*Darkness 6: "<>setpagedevice" +*Darkness 7: "<>setpagedevice" +*Darkness 8: "<>setpagedevice" +*Darkness 9: "<>setpagedevice" +*Darkness 10: "<>setpagedevice" +*Darkness 11: "<>setpagedevice" +*Darkness 12: "<>setpagedevice" +*Darkness 13: "<>setpagedevice" +*Darkness 14: "<>setpagedevice" +*Darkness 15: "<>setpagedevice" +*Darkness 16: "<>setpagedevice" +*Darkness 17: "<>setpagedevice" +*Darkness 18: "<>setpagedevice" +*Darkness 19: "<>setpagedevice" +*Darkness 20: "<>setpagedevice" +*Darkness 21: "<>setpagedevice" +*Darkness 22: "<>setpagedevice" +*Darkness 23: "<>setpagedevice" +*Darkness 24: "<>setpagedevice" +*Darkness 25: "<>setpagedevice" +*Darkness 26: "<>setpagedevice" +*Darkness 27: "<>setpagedevice" +*Darkness 28: "<>setpagedevice" +*Darkness 29: "<>setpagedevice" +*Darkness 30: "<>setpagedevice" +*CloseUI: *Darkness + +*OpenUI *zePrintRate/Print Rate: PickOne +*OrderDependency: 20 AnySetup *zePrintRate +*DefaultzePrintRate: Default +*zePrintRate Default/PrinterDefault: Default +*zePrintRate 1/1 inch/sec.: "" +*zePrintRate 2/2 inches/sec.: "" +*zePrintRate 3/3 inches/sec.: "" +*zePrintRate 4/4 inches/sec.: "" +*zePrintRate 5/5 inches/sec.: "" +*zePrintRate 6/6 inches/sec.: "" +*zePrintRate 7/7 inches/sec.: "" +*zePrintRate 8/8 inches/sec.: "" +*zePrintRate 9/9 inches/sec.: "" +*zePrintRate 10/10 inches/sec.: "" +*zePrintRate 11/11 inches/sec.: "" +*zePrintRate 12/12 inches/sec.: "" +*CloseUI: *zePrintRate + +*OpenUI *zeLabelTop/Label Top: PickOne +*OrderDependency: 20 AnySetup *zeLabelTop +*DefaultzeLabelTop: 200 +*zeLabelTop 200/PrinterDefault: "<>setpagedevice" +*zeLabelTop -120: "<>setpagedevice" +*zeLabelTop -115: "<>setpagedevice" +*zeLabelTop -110: "<>setpagedevice" +*zeLabelTop -105: "<>setpagedevice" +*zeLabelTop -100: "<>setpagedevice" +*zeLabelTop -95: "<>setpagedevice" +*zeLabelTop -90: "<>setpagedevice" +*zeLabelTop -85: "<>setpagedevice" +*zeLabelTop -80: "<>setpagedevice" +*zeLabelTop -75: "<>setpagedevice" +*zeLabelTop -70: "<>setpagedevice" +*zeLabelTop -65: "<>setpagedevice" +*zeLabelTop -60: "<>setpagedevice" +*zeLabelTop -55: "<>setpagedevice" +*zeLabelTop -50: "<>setpagedevice" +*zeLabelTop -45: "<>setpagedevice" +*zeLabelTop -40: "<>setpagedevice" +*zeLabelTop -35: "<>setpagedevice" +*zeLabelTop -30: "<>setpagedevice" +*zeLabelTop -25: "<>setpagedevice" +*zeLabelTop -20: "<>setpagedevice" +*zeLabelTop -15: "<>setpagedevice" +*zeLabelTop -10: "<>setpagedevice" +*zeLabelTop -5: "<>setpagedevice" +*zeLabelTop 0: "<>setpagedevice" +*zeLabelTop 5: "<>setpagedevice" +*zeLabelTop 10: "<>setpagedevice" +*zeLabelTop 15: "<>setpagedevice" +*zeLabelTop 20: "<>setpagedevice" +*zeLabelTop 25: "<>setpagedevice" +*zeLabelTop 30: "<>setpagedevice" +*zeLabelTop 35: "<>setpagedevice" +*zeLabelTop 40: "<>setpagedevice" +*zeLabelTop 45: "<>setpagedevice" +*zeLabelTop 50: "<>setpagedevice" +*zeLabelTop 55: "<>setpagedevice" +*zeLabelTop 60: "<>setpagedevice" +*zeLabelTop 65: "<>setpagedevice" +*zeLabelTop 70: "<>setpagedevice" +*zeLabelTop 75: "<>setpagedevice" +*zeLabelTop 80: "<>setpagedevice" +*zeLabelTop 85: "<>setpagedevice" +*zeLabelTop 90: "<>setpagedevice" +*zeLabelTop 95: "<>setpagedevice" +*zeLabelTop 100: "<>setpagedevice" +*zeLabelTop 105: "<>setpagedevice" +*zeLabelTop 110: "<>setpagedevice" +*zeLabelTop 115: "<>setpagedevice" +*zeLabelTop 120: "<>setpagedevice" +*CloseUI: *zeLabelTop + +*OpenUI *zePrintMode/Print Mode: PickOne +*OrderDependency: 20 AnySetup *zePrintMode +*DefaultzePrintMode: Saved +*zePrintMode Saved/PrinterDefault: "" +*zePrintMode Tear/Tear-off: "" +*zePrintMode Peel/Peel-Off: "" +*zePrintMode Rewind: "" +*zePrintMode Applicator: "" +*zePrintMode Cutter: "" +*CloseUI: *MediaTracking + +*OpenUI *zeTearOffPosition/Tear-off Adjust Position: PickOne +*OrderDependency: 20 AnySetup *zeTearOffPosition +*DefaultzeTearOffPosition: 1000 +*zeTearOffPosition 1000/PrinterDefault: "<>setpagedevice" +*zeTearOffPosition -120: "<>setpagedevice" +*zeTearOffPosition -115: "<>setpagedevice" +*zeTearOffPosition -110: "<>setpagedevice" +*zeTearOffPosition -105: "<>setpagedevice" +*zeTearOffPosition -100: "<>setpagedevice" +*zeTearOffPosition -95: "<>setpagedevice" +*zeTearOffPosition -90: "<>setpagedevice" +*zeTearOffPosition -85: "<>setpagedevice" +*zeTearOffPosition -80: "<>setpagedevice" +*zeTearOffPosition -75: "<>setpagedevice" +*zeTearOffPosition -70: "<>setpagedevice" +*zeTearOffPosition -65: "<>setpagedevice" +*zeTearOffPosition -60: "<>setpagedevice" +*zeTearOffPosition -55: "<>setpagedevice" +*zeTearOffPosition -50: "<>setpagedevice" +*zeTearOffPosition -45: "<>setpagedevice" +*zeTearOffPosition -40: "<>setpagedevice" +*zeTearOffPosition -35: "<>setpagedevice" +*zeTearOffPosition -30: "<>setpagedevice" +*zeTearOffPosition -25: "<>setpagedevice" +*zeTearOffPosition -20: "<>setpagedevice" +*zeTearOffPosition -15: "<>setpagedevice" +*zeTearOffPosition -10: "<>setpagedevice" +*zeTearOffPosition -5: "<>setpagedevice" +*zeTearOffPosition 0: "<>setpagedevice" +*zeTearOffPosition 5: "<>setpagedevice" +*zeTearOffPosition 10: "<>setpagedevice" +*zeTearOffPosition 15: "<>setpagedevice" +*zeTearOffPosition 20: "<>setpagedevice" +*zeTearOffPosition 25: "<>setpagedevice" +*zeTearOffPosition 30: "<>setpagedevice" +*zeTearOffPosition 35: "<>setpagedevice" +*zeTearOffPosition 40: "<>setpagedevice" +*zeTearOffPosition 45: "<>setpagedevice" +*zeTearOffPosition 50: "<>setpagedevice" +*zeTearOffPosition 55: "<>setpagedevice" +*zeTearOffPosition 60: "<>setpagedevice" +*zeTearOffPosition 65: "<>setpagedevice" +*zeTearOffPosition 70: "<>setpagedevice" +*zeTearOffPosition 75: "<>setpagedevice" +*zeTearOffPosition 80: "<>setpagedevice" +*zeTearOffPosition 85: "<>setpagedevice" +*zeTearOffPosition 90: "<>setpagedevice" +*zeTearOffPosition 95: "<>setpagedevice" +*zeTearOffPosition 100: "<>setpagedevice" +*zeTearOffPosition 105: "<>setpagedevice" +*zeTearOffPosition 110: "<>setpagedevice" +*zeTearOffPosition 115: "<>setpagedevice" +*zeTearOffPosition 120: "<>setpagedevice" +*CloseUI: *zeTearOffPosition + +*OpenUI *zeErrorReprint/Reprint After Error: PickOne +*OrderDependency: 20 AnySetup *zeErrorReprint +*DefaultzeErrorReprint: Saved +*zeErrorReprint Saved/PrinterDefault: "" +*zeErrorReprint Always: "" +*zeErrorReprint Never: "" +*CloseUI: *zeErrorReprint +*CloseGroup: PrinterSettings + +*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: zebra.ppd 4920 2006-01-12 15:12:12Z mike $". +*% diff --git a/ppd/zebracpl.ppd b/ppd/zebracpl.ppd new file mode 100644 index 000000000..4a8d85b79 --- /dev/null +++ b/ppd/zebracpl.ppd @@ -0,0 +1,276 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: zebra.ppd 4905 2006-01-10 20:07:15Z mike $" +*% +*% Sample Zebra label printer driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 2001-2006 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "ZEBRACPL.PPD" +*Manufacturer: "Zebra" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-raster 0 rastertodymo" +*% cupsModelNumber is 16 for EPL1 line mode, 17 for EPL2 page mode, +*% 18 for ZPL mode, and 19 for CPCL mode. +*cupsModelNumber: 19 +*ModelName: "Zebra CPCL Label Printer" +*ShortNickName: "Zebra CPCL Label Printer" +*NickName: "Zebra CPCL Label Printer CUPS v1.2" +*PSVersion: "(3010.000) 81501" +*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: w288h360 +*PageSize w144h72/Label - 2 x 1": "<>setpagedevice" +*PageSize w144h90/Label - 2 x 1.25": "<>setpagedevice" +*PageSize w144h144/Label - 2 x 2": "<>setpagedevice" +*PageSize w144h216/Label - 2 x 3": "<>setpagedevice" +*PageSize w209h72/Label - 2.9 x 1": "<>setpagedevice>>" +*PageSize w288h144/Label - 4 x 2": "<>setpagedevice" +*PageSize w288h216/Label - 4 x 3": "<>setpagedevice" +*PageSize w288h288/Label - 4 x 4": "<>setpagedevice" +*PageSize w288h360/Label - 4 x 5": "<>setpagedevice" +*PageSize w288h360/Label - 4 x 5": "<>setpagedevice" +*PageSize w288h432/Label - 4 x 6": "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: w288h360 +*PageRegion w144h72/Label - 2 x 1": "<>setpagedevice" +*PageRegion w144h90/Label - 2 x 1.25": "<>setpagedevice" +*PageRegion w144h144/Label - 2 x 2": "<>setpagedevice" +*PageRegion w144h216/Label - 2 x 3": "<>setpagedevice" +*PageRegion w209h72/Label - 2.9 x 1": "<>setpagedevice>>" +*PageRegion w288h144/Label - 4 x 2": "<>setpagedevice" +*PageRegion w288h216/Label - 4 x 3": "<>setpagedevice" +*PageRegion w288h288/Label - 4 x 4": "<>setpagedevice" +*PageRegion w288h360/Label - 4 x 5": "<>setpagedevice" +*PageRegion w288h360/Label - 4 x 5": "<>setpagedevice" +*PageRegion w288h432/Label - 4 x 6": "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: w288h360 +*ImageableArea w144h72/Label - 2 x 1": "0 0 144 72" +*ImageableArea w144h90/Label - 2 x 1.25": "0 0 144 90" +*ImageableArea w144h144/Label - 2 x 2": "0 0 144 144" +*ImageableArea w144h216/Label - 2 x 3": "0 0 144 216" +*ImageableArea w209h72/Label - 2.9 x 1": "0 0 209 72>>" +*ImageableArea w288h144/Label - 4 x 2": "0 0 288 144" +*ImageableArea w288h216/Label - 4 x 3": "0 0 288 216" +*ImageableArea w288h288/Label - 4 x 4": "0 0 288 288" +*ImageableArea w288h360/Label - 4 x 5": "0 0 288 360" +*ImageableArea w288h360/Label - 4 x 5": "0 0 288 360" +*ImageableArea w288h432/Label - 4 x 6": "0 0 288 432" + +*DefaultPaperDimension: w288h360 +*PaperDimension w144h72/Label - 2 x 1": "144 72" +*PaperDimension w144h90/Label - 2 x 1.25": "144 90" +*PaperDimension w144h144/Label - 2 x 2": "144 144" +*PaperDimension w144h216/Label - 2 x 3": "144 216" +*PaperDimension w209h72/Label - 2.9 x 1": "209 72>>" +*PaperDimension w288h144/Label - 4 x 2": "288 144" +*PaperDimension w288h216/Label - 4 x 3": "288 216" +*PaperDimension w288h288/Label - 4 x 4": "288 288" +*PaperDimension w288h360/Label - 4 x 5": "288 360" +*PaperDimension w288h360/Label - 4 x 5": "288 360" +*PaperDimension w288h432/Label - 4 x 6": "288 432" + +*MaxMediaWidth: "288" +*MaxMediaHeight: "3600" +*HWMargins: 0 0 0 0 +*CustomPageSize True: "pop pop pop <>setpagedevice" +*ParamCustomPageSize Width: 1 points 36 288 +*ParamCustomPageSize Height: 2 points 36 3600 +*ParamCustomPageSize WidthOffset: 3 points 0 0 +*ParamCustomPageSize HeightOffset: 4 points 0 0 +*ParamCustomPageSize Orientation: 5 int 0 0 + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 203dpi +*Resolution 203dpi/203 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenGroup: PrinterSettings/Printer Settings +*OpenUI *Darkness/Media Darkness: PickOne +*OrderDependency: 20 AnySetup *Darkness +*DefaultDarkness: -1 +*Darkness -1/PrinterDefault: "<>setpagedevice" +*Darkness 1: "<>setpagedevice" +*Darkness 2: "<>setpagedevice" +*Darkness 3: "<>setpagedevice" +*Darkness 4: "<>setpagedevice" +*Darkness 5: "<>setpagedevice" +*Darkness 6: "<>setpagedevice" +*Darkness 7: "<>setpagedevice" +*Darkness 8: "<>setpagedevice" +*Darkness 9: "<>setpagedevice" +*Darkness 10: "<>setpagedevice" +*Darkness 11: "<>setpagedevice" +*Darkness 12: "<>setpagedevice" +*Darkness 13: "<>setpagedevice" +*Darkness 14: "<>setpagedevice" +*Darkness 15: "<>setpagedevice" +*Darkness 16: "<>setpagedevice" +*Darkness 17: "<>setpagedevice" +*Darkness 18: "<>setpagedevice" +*Darkness 19: "<>setpagedevice" +*Darkness 20: "<>setpagedevice" +*Darkness 21: "<>setpagedevice" +*Darkness 22: "<>setpagedevice" +*Darkness 23: "<>setpagedevice" +*Darkness 24: "<>setpagedevice" +*Darkness 25: "<>setpagedevice" +*Darkness 26: "<>setpagedevice" +*Darkness 27: "<>setpagedevice" +*Darkness 28: "<>setpagedevice" +*Darkness 29: "<>setpagedevice" +*Darkness 30: "<>setpagedevice" +*CloseUI: *Darkness + +*OpenUI *zePrintRate/Print Rate: PickOne +*OrderDependency: 20 AnySetup *zePrintRate +*DefaultzePrintRate: Default +*zePrintRate Default/PrinterDefault: Default +*zePrintRate 1/1 inch/sec.: "" +*zePrintRate 2/2 inches/sec.: "" +*zePrintRate 3/3 inches/sec.: "" +*zePrintRate 4/4 inches/sec.: "" +*CloseUI: *zePrintRate + +*OpenUI *zeTearOffPosition/Tear-off Adjust Position: PickOne +*OrderDependency: 20 AnySetup *zeTearOffPosition +*DefaultzeTearOffPosition: 1000 +*zeTearOffPosition 1000/PrinterDefault: "<>setpagedevice" +*zeTearOffPosition -120: "<>setpagedevice" +*zeTearOffPosition -115: "<>setpagedevice" +*zeTearOffPosition -110: "<>setpagedevice" +*zeTearOffPosition -105: "<>setpagedevice" +*zeTearOffPosition -100: "<>setpagedevice" +*zeTearOffPosition -95: "<>setpagedevice" +*zeTearOffPosition -90: "<>setpagedevice" +*zeTearOffPosition -85: "<>setpagedevice" +*zeTearOffPosition -80: "<>setpagedevice" +*zeTearOffPosition -75: "<>setpagedevice" +*zeTearOffPosition -70: "<>setpagedevice" +*zeTearOffPosition -65: "<>setpagedevice" +*zeTearOffPosition -60: "<>setpagedevice" +*zeTearOffPosition -55: "<>setpagedevice" +*zeTearOffPosition -50: "<>setpagedevice" +*zeTearOffPosition -45: "<>setpagedevice" +*zeTearOffPosition -40: "<>setpagedevice" +*zeTearOffPosition -35: "<>setpagedevice" +*zeTearOffPosition -30: "<>setpagedevice" +*zeTearOffPosition -25: "<>setpagedevice" +*zeTearOffPosition -20: "<>setpagedevice" +*zeTearOffPosition -15: "<>setpagedevice" +*zeTearOffPosition -10: "<>setpagedevice" +*zeTearOffPosition -5: "<>setpagedevice" +*zeTearOffPosition 0: "<>setpagedevice" +*zeTearOffPosition 5: "<>setpagedevice" +*zeTearOffPosition 10: "<>setpagedevice" +*zeTearOffPosition 15: "<>setpagedevice" +*zeTearOffPosition 20: "<>setpagedevice" +*zeTearOffPosition 25: "<>setpagedevice" +*zeTearOffPosition 30: "<>setpagedevice" +*zeTearOffPosition 35: "<>setpagedevice" +*zeTearOffPosition 40: "<>setpagedevice" +*zeTearOffPosition 45: "<>setpagedevice" +*zeTearOffPosition 50: "<>setpagedevice" +*zeTearOffPosition 55: "<>setpagedevice" +*zeTearOffPosition 60: "<>setpagedevice" +*zeTearOffPosition 65: "<>setpagedevice" +*zeTearOffPosition 70: "<>setpagedevice" +*zeTearOffPosition 75: "<>setpagedevice" +*zeTearOffPosition 80: "<>setpagedevice" +*zeTearOffPosition 85: "<>setpagedevice" +*zeTearOffPosition 90: "<>setpagedevice" +*zeTearOffPosition 95: "<>setpagedevice" +*zeTearOffPosition 100: "<>setpagedevice" +*zeTearOffPosition 105: "<>setpagedevice" +*zeTearOffPosition 110: "<>setpagedevice" +*zeTearOffPosition 115: "<>setpagedevice" +*zeTearOffPosition 120: "<>setpagedevice" +*CloseUI: *zeTearOffPosition + +*OpenUI *zeErrorReprint/Reprint After Error: PickOne +*OrderDependency: 20 AnySetup *zeErrorReprint +*DefaultzeErrorReprint: Saved +*zeErrorReprint Saved/PrinterDefault: "" +*zeErrorReprint Always: "" +*zeErrorReprint Never: "" +*CloseUI: *zeErrorReprint +*CloseGroup: PrinterSettings + +*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: zebra.ppd 4905 2006-01-10 20:07:15Z mike $". +*% diff --git a/ppd/zebraep1.ppd b/ppd/zebraep1.ppd new file mode 100644 index 000000000..fd50bc7e8 --- /dev/null +++ b/ppd/zebraep1.ppd @@ -0,0 +1,179 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: zebra.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample Zebra label printer driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 2001-2006 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "ZEBRA.PPD" +*Manufacturer: "Zebra" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-raster 0 rastertodymo" +*% cupsModelNumber is 16 for EPL1 line mode, 17 for EPL2 page mode, +*% 18 for ZPL mode, and 19 for CPCL mode. +*cupsModelNumber: 16 +*ModelName: "Zebra EPL1 Label Printer" +*ShortNickName: "Zebra EPL1 Label Printer" +*NickName: "Zebra EPL1 Label Printer CUPS v1.2" +*PSVersion: "(3010.000) 81501" +*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: w288h360 +*PageSize w288h360/Label - 4 x 5": "<>setpagedevice" +*PageSize w288h432/Label - 4 x 6": "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: w288h360 +*PageRegion w288h360/Label - 4 x 5": "<>setpagedevice" +*PageRegion w288h432/Label - 4 x 6": "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: w288h360 +*ImageableArea w288h360/Label - 4 x 5": "0 0 288 360" +*ImageableArea w288h432/Label - 4 x 6": "0 0 288 432" + +*DefaultPaperDimension: w288h360 +*PaperDimension w288h360/Label - 4 x 5": "288 360" +*PaperDimension w288h432/Label - 4 x 6": "288 432" + +*MaxMediaWidth: "288" +*MaxMediaHeight: "3600" +*HWMargins: 0 0 0 0 +*CustomPageSize True: "pop pop pop <>setpagedevice" +*ParamCustomPageSize Width: 1 points 36 288 +*ParamCustomPageSize Height: 2 points 36 3600 +*ParamCustomPageSize WidthOffset: 3 points 0 0 +*ParamCustomPageSize HeightOffset: 4 points 0 0 +*ParamCustomPageSize Orientation: 5 int 0 0 + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 203dpi +*Resolution 203dpi/203 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenGroup: PrinterSettings/Printer Settings +*OpenUI *Darkness/Media Darkness: PickOne +*OrderDependency: 20 AnySetup *Darkness +*DefaultDarkness: -1 +*Darkness -1/PrinterDefault: "<>setpagedevice" +*Darkness 1: "<>setpagedevice" +*Darkness 2: "<>setpagedevice" +*Darkness 3: "<>setpagedevice" +*Darkness 4: "<>setpagedevice" +*Darkness 5: "<>setpagedevice" +*Darkness 6: "<>setpagedevice" +*Darkness 7: "<>setpagedevice" +*Darkness 8: "<>setpagedevice" +*Darkness 9: "<>setpagedevice" +*Darkness 10: "<>setpagedevice" +*Darkness 11: "<>setpagedevice" +*Darkness 12: "<>setpagedevice" +*Darkness 13: "<>setpagedevice" +*Darkness 14: "<>setpagedevice" +*Darkness 15: "<>setpagedevice" +*Darkness 16: "<>setpagedevice" +*Darkness 17: "<>setpagedevice" +*Darkness 18: "<>setpagedevice" +*Darkness 19: "<>setpagedevice" +*Darkness 20: "<>setpagedevice" +*Darkness 21: "<>setpagedevice" +*Darkness 22: "<>setpagedevice" +*Darkness 23: "<>setpagedevice" +*Darkness 24: "<>setpagedevice" +*Darkness 25: "<>setpagedevice" +*Darkness 26: "<>setpagedevice" +*Darkness 27: "<>setpagedevice" +*Darkness 28: "<>setpagedevice" +*Darkness 29: "<>setpagedevice" +*Darkness 30: "<>setpagedevice" +*CloseUI: *Darkness + +*OpenUI *zePrintRate/Print Rate: PickOne +*OrderDependency: 20 AnySetup *zePrintRate +*DefaultzePrintRate: Default +*zePrintRate Default/PrinterDefault: Default +*zePrintRate 1/1 inch/sec.: "" +*zePrintRate 1.5/1.5 inch/sec.: "" +*zePrintRate 2/2 inches/sec.: "" +*zePrintRate 2.5/2.5 inches/sec.: "" +*CloseUI: *zePrintRate +*CloseGroup: PrinterSettings + +*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: zebra.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/ppd/zebraep2.ppd b/ppd/zebraep2.ppd new file mode 100644 index 000000000..bd9433dd0 --- /dev/null +++ b/ppd/zebraep2.ppd @@ -0,0 +1,191 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: zebra.ppd 4880 2005-12-15 16:19:46Z mike $" +*% +*% Sample Zebra label printer driver PPD file for the Common UNIX Printing +*% System (CUPS). +*% +*% Copyright 2001-2006 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.2" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "ZEBRA.PPD" +*Manufacturer: "Zebra" +*Product: "(GNU Ghostscript)" +*Product: "(ESP Ghostscript)" +*cupsVersion: 1.2 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-raster 0 rastertodymo" +*% cupsModelNumber is 16 for EPL1 line mode, 17 for EPL2 page mode, +*% 18 for ZPL mode, and 19 for CPCL mode. +*cupsModelNumber: 17 +*ModelName: "Zebra EPL2 Label Printer" +*ShortNickName: "Zebra EPL2 Label Printer" +*NickName: "Zebra EPL2 Label Printer CUPS v1.2" +*PSVersion: "(3010.000) 81501" +*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: w288h360 +*PageSize w288h360/Label - 4 x 5": "<>setpagedevice" +*PageSize w288h432/Label - 4 x 6": "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: w288h360 +*PageRegion w288h360/Label - 4 x 5": "<>setpagedevice" +*PageRegion w288h432/Label - 4 x 6": "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: w288h360 +*ImageableArea w288h360/Label - 4 x 5": "0 0 288 360" +*ImageableArea w288h432/Label - 4 x 6": "0 0 288 432" + +*DefaultPaperDimension: w288h360 +*PaperDimension w288h360/Label - 4 x 5": "288 360" +*PaperDimension w288h432/Label - 4 x 6": "288 432" + +*MaxMediaWidth: "288" +*MaxMediaHeight: "3600" +*HWMargins: 0 0 0 0 +*CustomPageSize True: "pop pop pop <>setpagedevice" +*ParamCustomPageSize Width: 1 points 36 288 +*ParamCustomPageSize Height: 2 points 36 3600 +*ParamCustomPageSize WidthOffset: 3 points 0 0 +*ParamCustomPageSize HeightOffset: 4 points 0 0 +*ParamCustomPageSize Orientation: 5 int 0 0 + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 203dpi +*Resolution 203dpi/203 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *MediaType/Media Type: PickOne +*OrderDependency: 20 AnySetup *MediaType +*DefaultMediaType: Saved +*MediaType Saved/PrinterDefault: "" +*MediaType Thermal/Thermal Transfer Media: "<>setpagedevice" +*MediaType Direct/Direct Thermal Media: "<>setpagedevice" +*CloseUI: *zeMediaType + +*OpenGroup: PrinterSettings/Printer Settings +*OpenUI *Darkness/Media Darkness: PickOne +*OrderDependency: 20 AnySetup *Darkness +*DefaultDarkness: -1 +*Darkness -1/PrinterDefault: "<>setpagedevice" +*Darkness 1: "<>setpagedevice" +*Darkness 2: "<>setpagedevice" +*Darkness 3: "<>setpagedevice" +*Darkness 4: "<>setpagedevice" +*Darkness 5: "<>setpagedevice" +*Darkness 6: "<>setpagedevice" +*Darkness 7: "<>setpagedevice" +*Darkness 8: "<>setpagedevice" +*Darkness 9: "<>setpagedevice" +*Darkness 10: "<>setpagedevice" +*Darkness 11: "<>setpagedevice" +*Darkness 12: "<>setpagedevice" +*Darkness 13: "<>setpagedevice" +*Darkness 14: "<>setpagedevice" +*Darkness 15: "<>setpagedevice" +*Darkness 16: "<>setpagedevice" +*Darkness 17: "<>setpagedevice" +*Darkness 18: "<>setpagedevice" +*Darkness 19: "<>setpagedevice" +*Darkness 20: "<>setpagedevice" +*Darkness 21: "<>setpagedevice" +*Darkness 22: "<>setpagedevice" +*Darkness 23: "<>setpagedevice" +*Darkness 24: "<>setpagedevice" +*Darkness 25: "<>setpagedevice" +*Darkness 26: "<>setpagedevice" +*Darkness 27: "<>setpagedevice" +*Darkness 28: "<>setpagedevice" +*Darkness 29: "<>setpagedevice" +*Darkness 30: "<>setpagedevice" +*CloseUI: *Darkness + +*OpenUI *zePrintRate/Print Rate: PickOne +*OrderDependency: 20 AnySetup *zePrintRate +*DefaultzePrintRate: Default +*zePrintRate Default/PrinterDefault: Default +*zePrintRate 1/1 inch/sec.: "" +*zePrintRate 1.5/1.5 inch/sec.: "" +*zePrintRate 2/2 inches/sec.: "" +*zePrintRate 2.5/2.5 inches/sec.: "" +*zePrintRate 3/3 inches/sec.: "" +*zePrintRate 4/4 inches/sec.: "" +*zePrintRate 5/5 inches/sec.: "" +*zePrintRate 6/6 inches/sec.: "" +*CloseUI: *zePrintRate +*CloseGroup: PrinterSettings + +*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: zebra.ppd 4880 2005-12-15 16:19:46Z mike $". +*% diff --git a/pstoraster/README.pstoraster b/pstoraster/README.pstoraster new file mode 100644 index 000000000..980def219 --- /dev/null +++ b/pstoraster/README.pstoraster @@ -0,0 +1,73 @@ +README.pstoraster - 11/14/2003 +------------------------------ + +INTRODUCTION + + This directory contains the CUPS "driver" for Ghostscript + 7.x and 8.x, the pstoraster script that is used to run + Ghostscript as a CUPS filter, the pstoraster.convs file that + defines the PostScript to raster filter for CUPS drivers, a + makefile fragment that adds the CUPS driver, and the wrapper + script (pstopxl) and PPD files (pxl*.ppd) to support PCL + XL/PCL 6 printers. + + This software is included with both the CUPS and ESP + Ghostscript 7.07.1 distributions. While the files will also + compile with earlier versions of Ghostscript, there are bugs + in older versions of Ghostscript which may cause problems. + + Also, this driver may not be used in any commercial + Ghostscript distributions without prior written + permission/licensing from Easy Software Products. See the + contact information in the file "gdevcups.c" for more + information. + + +COMPILING ESP GHOSTSCRIPT WITH THE CUPS DRIVER + + Normally the CUPS driver will be automatically included when + you use the configure script supplied with ESP Ghostscript. + + Once you have compiled and installed Ghostscript, restart + the cupsd process, either by sending the HUP signal to the + process or using the init script supplied with CUPS. + + To use the PCL XL/PCL 6 drivers, make sure that you also + configure Ghostscript with the pxlmono and pxlcolor drivers. + + +COMPILING AFPL/GNU GHOSTSCRIPT WITH THE CUPS DRIVER + + Before configuring AFPL or GNU Ghostscript, first copy this + directory to the Ghostscript source directory, e.g.: + + cp -r pstoraster /some/path/to/ghostscript-7.07 + + Then apply the appropriate patch: + + cd /some/path/to/ghostscript-7.07 + patch -p1 pstoraster/gs707-lib.patch + + or: + + cd /some/path/to/ghostscript-8.11 + patch -p1 pstoraster/gs811-lib.patch + + Next, run the configure script to configure the Ghostscript + software: + + ./configure [any configure options you want] + + Finally, add the following include line to the end of the + makefile: + + include pstoraster/cups.mak + + and add "$(DD)cups.dev" to any of the DEVICE_DEVS lines. + + Once you have compiled and installed Ghostscript, restart + the cupsd process, either by sending the HUP signal to the + process or using the init script supplied with CUPS. + + To use the PCL XL/PCL 6 drivers, make sure that you also + configure Ghostscript with the pxlmono and pxlcolor drivers. diff --git a/pstoraster/cups.mak b/pstoraster/cups.mak new file mode 100644 index 000000000..129e8b8af --- /dev/null +++ b/pstoraster/cups.mak @@ -0,0 +1,53 @@ +# +# "$Id: cups.mak 4493 2005-02-18 02:09:53Z mike $" +# +# CUPS driver makefile for Ghostscript. +# +# Copyright 2001-2005 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, 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. +# + +### ----------------- CUPS Ghostscript Driver ---------------------- ### + +cups_= $(GLOBJ)gdevcups.$(OBJ) + +CUPSSERVER= $(install_prefix)`cups-config --serverbin` +CUPSCONFIG= $(install_prefix)`cups-config --serverroot` +CUPSDATA= $(install_prefix)`cups-config --datadir` + +$(DD)cups.dev: $(cups_) $(GLD)page.dev + $(ADDMOD) $(DD)cups -lib cupsimage -lib cups + $(SETPDEV2) $(DD)cups $(cups_) + +$(GLOBJ)gdevcups.$(OBJ): pstoraster/gdevcups.c $(PDEVH) + $(GLCC) $(GLO_)gdevcups.$(OBJ) $(C_) pstoraster/gdevcups.c + +install: install-cups + +install-cups: + -mkdir -p $(CUPSSERVER)/filter + $(INSTALL_PROGRAM) pstoraster/pstoraster $(CUPSSERVER)/filter + $(INSTALL_PROGRAM) pstoraster/pstopxl $(CUPSSERVER)/filter + -mkdir -p $(CUPSCONFIG) + $(INSTALL_DATA) pstoraster/pstoraster.convs $(CUPSCONFIG) + -mkdir -p $(CUPSDATA)/model + $(INSTALL_DATA) pstoraster/pxlcolor.ppd $(CUPSDATA)/model + $(INSTALL_DATA) pstoraster/pxlmono.ppd $(CUPSDATA)/model + + +# +# End of "$Id: cups.mak 4493 2005-02-18 02:09:53Z mike $". +# diff --git a/pstoraster/gdevcups.c b/pstoraster/gdevcups.c new file mode 100644 index 000000000..89a5df20e --- /dev/null +++ b/pstoraster/gdevcups.c @@ -0,0 +1,4464 @@ +/* + * "$Id: gdevcups.c 4493 2005-02-18 02:09:53Z mike $" + * + * GNU Ghostscript raster output driver for the Common UNIX Printing + * System (CUPS). + * + * Copyright 1993-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org/ + * + * 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_get_space_params() - Get space parameters from the RIP_CACHE env var. + * cups_map_color_rgb() - Map a color index to an RGB color. + * cups_map_cielab() - Map CIE Lab transformation... + * cups_map_rgb_color() - Map an RGB color to a color index. We map the + * RGB color to the output colorspace & bits (we + * figure out the format when we output a page). + * cups_open() - Open the output file and initialize things. + * cups_print_pages() - Send one or more pages to the output file. + * cups_put_params() - Set pagedevice parameters. + * cups_set_color_info() - Set the color information structure based on + * the required output. + * cups_print_chunked() - Print a page of chunked pixels. + * cups_print_banded() - Print a page of banded pixels. + * cups_print_planar() - Print a page of planar pixels. + */ + +/* + * Include necessary headers... + */ + +#include "std.h" /* to stop stdlib.h redefining types */ +#include "gdevprn.h" +#include "gsparam.h" +#include "gsexit.h" + +#include +#include +#include +#include +#include + +#undef private +#define private + + +/* + * Check if we are compiling against CUPS 1.2. If so, enable + * certain extended attributes and use a different page header + * structure and write function... + */ + +#ifdef CUPS_RASTER_SYNCv1 +# define cups_page_header_t cups_page_header2_t +# define cupsRasterWriteHeader cupsRasterWriteHeader2 +#endif /* CUPS_RASTER_SYNCv1 */ + + +/* + * Newer versions of Ghostscript don't provide gs_exit() function anymore. + * It has been renamed to gs_to_exit()... + */ + +#ifdef dev_t_proc_encode_color +# define gs_exit gs_to_exit +#endif /* dev_t_proc_encode_color */ + + +/* + * CIE XYZ color constants... + */ + +#define D65_X (0.412453 + 0.357580 + 0.180423) +#define D65_Y (0.212671 + 0.715160 + 0.072169) +#define D65_Z (0.019334 + 0.119193 + 0.950227) + + +/* + * Size of a tile in pixels... + */ + +#define CUPS_TILE_SIZE 256 + + +/* + * Size of profile LUTs... + */ + +#ifdef dev_t_proc_encode_color +# define CUPS_MAX_VALUE frac_1 +#else +# define CUPS_MAX_VALUE gx_max_color_value +#endif /* dev_t_proc_encode_color */ + + +/* + * Macros... + */ + +#define x_dpi (pdev->HWResolution[0]) +#define y_dpi (pdev->HWResolution[1]) +#define cups ((gx_device_cups *)pdev) + +/* + * Macros from ; we can't include because it also + * defines DEBUG, one of our flags to insert various debugging code. + */ + +#ifndef max +# define max(a,b) ((a)<(b) ? (b) : (a)) +#endif /* !max */ + +#ifndef min +# define min(a,b) ((a)>(b) ? (b) : (a)) +#endif /* !min */ + +#ifndef abs +# define abs(x) ((x)>=0 ? (x) : -(x)) +#endif /* !abs */ + + +/* + * Procedures + */ + +private dev_proc_close_device(cups_close); +private dev_proc_get_initial_matrix(cups_get_matrix); +private int cups_get_params(gx_device *, gs_param_list *); +private dev_proc_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); +private prn_dev_proc_get_space_params(cups_get_space_params); + +#ifdef dev_t_proc_encode_color +private cm_map_proc_gray(cups_map_gray); +private cm_map_proc_rgb(cups_map_rgb); +private cm_map_proc_cmyk(cups_map_cmyk); +private dev_proc_decode_color(cups_decode_color); +private dev_proc_encode_color(cups_encode_color); +private dev_proc_get_color_mapping_procs(cups_get_color_mapping_procs); + +static const gx_cm_color_map_procs cups_color_mapping_procs = +{ + cups_map_gray, + cups_map_rgb, + cups_map_cmyk +}; +#else +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); +#endif /* dev_t_proc_encode_color */ + + +/* + * 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 */ + cups_page_header_t header; /* PostScript page device info */ + int landscape; /* Non-zero if this is landscape */ +} gx_device_cups; + +private gx_device_procs cups_procs = +{ + cups_open, + cups_get_matrix, + cups_sync_output, + gdev_prn_output_page, + cups_close, +#ifdef dev_t_proc_encode_color + NULL, /* map_rgb_color */ + NULL, /* map_color_rgb */ +#else + cups_map_rgb_color, + cups_map_color_rgb, +#endif /* dev_t_proc_encode_color */ + 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, +#ifdef dev_t_proc_encode_color + NULL, /* map_cmyk_color */ +#else + cups_map_cmyk_color, +#endif /* dev_t_proc_encode_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 */ +#ifdef dev_t_proc_encode_color + , + NULL, /* get_clipping_box */ + NULL, /* begin_typed_image */ + NULL, /* get_bits_rectangle */ + NULL, /* map_color_rgb_alpha */ + NULL, /* create_compositor */ + NULL, /* get_hardware_params */ + NULL, /* text_begin */ + NULL, /* finish_copydevice */ + NULL, /* begin_transparency_group */ + NULL, /* end_transparency_group */ + NULL, /* begin_transparency_mask */ + NULL, /* end_transparency_mask */ + NULL, /* discard_transparency_layer */ + cups_get_color_mapping_procs, + NULL, /* get_color_comp_index */ + cups_encode_color, + cups_decode_color +#endif /* dev_t_proc_encode_color */ +}; + +#define prn_device_body_copies(dtype, procs, dname, w10, h10, xdpi, ydpi, lo, to, lm, bm, rm, tm, ncomp, depth, mg, mc, dg, dc, print_pages)\ + std_device_full_body_type(dtype, &procs, dname, &st_device_printer,\ + (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_copies_rest_(print_pages) + +gx_device_cups gs_cups_device = +{ + prn_device_body_copies(gx_device_cups,/* type */ + cups_procs, /* procedures */ + "cups", /* device name */ + 85, /* initial width */ + 110, /* initial height */ + 100, /* initial x resolution */ + 100, /* initial y resolution */ + 0, /* initial left offset */ + 0, /* initial top offset */ + 0, /* initial left margin */ + 0, /* initial bottom margin */ + 0, /* initial right margin */ + 0, /* initial top margin */ + 1, /* number of color components */ + 1, /* number of color bits */ + 1, /* maximum gray value */ + 0, /* maximum color value */ + 2, /* number of gray values */ + 0, /* number of color values */ + cups_print_pages), + /* print procedure */ + 0, /* page */ + NULL, /* stream */ + { /* 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 */ + } +}; + +/* + * Globals... + */ + +static gx_color_value cupsDecodeLUT[256]; + /* Output color to RGB value LUT */ +static unsigned char cupsEncodeLUT[gx_max_color_value + 1]; + /* RGB value to output color LUT */ + +static ppd_file_t *cupsPPD = 0; /* PPD file for this device */ +static char *cupsProfile = NULL; + /* Current simple color profile string */ +static int cupsHaveProfile = 0; + /* Has a color profile been defined? */ +static int cupsMatrix[3][3][CUPS_MAX_VALUE + 1]; + /* Color transform matrix LUT */ +static int cupsDensity[CUPS_MAX_VALUE + 1]; + /* Density LUT */ +static unsigned char cupsRevLower1[16] = + { /* Lower 1-bit reversal table */ + 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, + 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f + }, + cupsRevUpper1[16] = + { /* Upper 1-bit reversal table */ + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0 + }, + cupsRevLower2[16] = + { /* Lower 2-bit reversal table */ + 0x00, 0x04, 0x08, 0x0c, 0x01, 0x05, 0x09, 0x0d, + 0x02, 0x06, 0x0a, 0x0e, 0x03, 0x07, 0x0b, 0x0f + }, + cupsRevUpper2[16] = + { /* Upper 2-bit reversal table */ + 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0, + 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0 + }; + + +/* + * Local functions... + */ + +static double cups_map_cielab(double, double); +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, "DEBUG2: 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 (cupsPPD != NULL) + { + ppdClose(cupsPPD); + cupsPPD = NULL; + } + + if (cupsProfile != NULL) + { + free(cupsProfile); + cupsProfile = NULL; + } +#endif /* 0 */ + + return (gdev_prn_close(pdev)); +} + + +#ifdef dev_t_proc_encode_color +/* + * 'cups_decode_color()' - Decode a color value. + */ + +private int /* O - Status (0 = OK) */ +cups_decode_color(gx_device *pdev, /* I - Device info */ + gx_color_index ci, /* I - Color index */ + gx_color_value *cv) /* O - Colors */ +{ + int i; /* Looping var */ + int shift; /* Bits to shift */ + int mask; /* Bits to mask */ + + + if (cups->header.cupsColorSpace == CUPS_CSPACE_KCMYcm && + cups->header.cupsBitsPerColor == 1) + { + /* + * KCMYcm data is represented internally by Ghostscript as CMYK... + */ + + cv[0] = (ci & 0x20) ? frac_1 : frac_0; + cv[1] = (ci & 0x12) ? frac_1 : frac_0; + cv[2] = (ci & 0x09) ? frac_1 : frac_0; + cv[3] = (ci & 0x04) ? frac_1 : frac_0; + } + else + { + shift = cups->header.cupsBitsPerColor; + mask = (1 << shift) - 1; + + for (i = cups->color_info.num_components - 1; i > 0; i --, ci >>= shift) + cv[i] = cupsDecodeLUT[ci & mask]; + + cv[0] = cupsDecodeLUT[ci & mask]; + } + + return (0); +} + + +/* + * 'cups_encode_color()' - Encode a color value. + */ + +private gx_color_index /* O - Color index */ +cups_encode_color(gx_device *pdev, + /* I - Device info */ + const gx_color_value *cv) + /* I - Colors */ +{ + int i; /* Looping var */ + gx_color_index ci; /* Color index */ + int shift; /* Bits to shift */ + + + /* + * Encode the color index... + */ + + shift = cups->header.cupsBitsPerColor; + + for (ci = cupsEncodeLUT[cv[0]], i = 1; + i < cups->color_info.num_components; + i ++) + ci = (ci << shift) | cupsEncodeLUT[cv[i]]; + + /* + * Handle 6-color output... + */ + + if (cups->header.cupsColorSpace == CUPS_CSPACE_KCMYcm && + cups->header.cupsBitsPerColor == 1) + { + /* + * Welcome to hackville, where we map CMYK data to the + * light inks in draft mode... Map blue to light magenta and + * cyan and green to light cyan and yellow... + */ + + ci <<= 2; /* Leave room for light inks */ + + if (ci == 0x18) /* Blue */ + ci = 0x11; /* == cyan + light magenta */ + else if (ci == 0x14) /* Green */ + ci = 0x06; /* == light cyan + yellow */ + } + + /* + * Range check the return value... + */ + + if (ci == gx_no_color_index) + ci --; + + /* + * Return the color index... + */ + + return (ci); +} + + +/* + * 'cups_get_color_mapping_procs()' - Get the list of color mapping procedures. + */ + +private const gx_cm_color_map_procs * /* O - List of device procedures */ +cups_get_color_mapping_procs(const gx_device *pdev) + /* I - Device info */ +{ + return (&cups_color_mapping_procs); +} +#endif /* dev_t_proc_encode_color */ + + +/* + * '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, "DEBUG2: 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 (cupsPPD) + { + fprintf(stderr, "DEBUG: cupsPPD = %p\n", cupsPPD); + fprintf(stderr, "DEBUG: cupsPPD->flip_duplex = %d\n", cupsPPD->flip_duplex); + } + + if (cups->landscape) + { + /* + * Do landscape orientation... + */ + + if (cups->header.Duplex && !cups->header.Tumble && + cupsPPD && cupsPPD->flip_duplex && !(cups->page & 1)) + { + pmat->xx = 0.0; + pmat->xy = (float)cups->header.HWResolution[0] / 72.0; + pmat->yx = -(float)cups->header.HWResolution[1] / 72.0; + pmat->yy = 0.0; + pmat->tx = -(float)cups->header.HWResolution[0] * pdev->HWMargins[2] / 72.0; + pmat->ty = (float)cups->header.HWResolution[1] * + ((float)cups->header.PageSize[0] - pdev->HWMargins[3]) / 72.0; + } + else + { + pmat->xx = 0.0; + pmat->xy = (float)cups->header.HWResolution[0] / 72.0; + pmat->yx = (float)cups->header.HWResolution[1] / 72.0; + pmat->yy = 0.0; + pmat->tx = -(float)cups->header.HWResolution[0] * pdev->HWMargins[0] / 72.0; + pmat->ty = -(float)cups->header.HWResolution[1] * pdev->HWMargins[1] / 72.0; + } + } + else if (cups->header.Duplex && !cups->header.Tumble && + cupsPPD && cupsPPD->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 */ +{ +#ifdef CUPS_RASTER_SYNCv1 + int i; /* Looping var */ + char name[255]; /* Attribute name */ +#endif /* CUPS_RASTER_SYNCv1 */ + int code; /* Return code */ + gs_param_string s; /* Temporary string value */ + bool b; /* Temporary boolean value */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG2: cups_get_params(%p, %p)\n", pdev, plist); +#endif /* DEBUG */ + + /* + * First process the "standard" page device parameters... + */ + +#ifdef DEBUG + fputs("DEBUG2: before gdev_prn_get_params()\n", stderr); +#endif /* DEBUG */ + + if ((code = gdev_prn_get_params(pdev, plist)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: after gdev_prn_get_params()\n", stderr); +#endif /* DEBUG */ + + /* + * Then write the CUPS parameters... + */ + +#ifdef DEBUG + fputs("DEBUG2: Adding 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("DEBUG2: Adding AdvanceDistance\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "AdvanceDistance", + (int *)&(cups->header.AdvanceDistance))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding AdvanceDistance\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "AdvanceMedia", + (int *)&(cups->header.AdvanceMedia))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding Collate\n", stderr); +#endif /* DEBUG */ + + b = cups->header.Collate; + if ((code = param_write_bool(plist, "Collate", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding CutMedia\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "CutMedia", + (int *)&(cups->header.CutMedia))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding InsertSheet\n", stderr); +#endif /* DEBUG */ + + b = cups->header.InsertSheet; + if ((code = param_write_bool(plist, "InsertSheet", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding Jog\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "Jog", + (int *)&(cups->header.Jog))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding LeadingEdge\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "LeadingEdge", + (int *)&(cups->header.LeadingEdge))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding ManualFeed\n", stderr); +#endif /* DEBUG */ + + b = cups->header.ManualFeed; + if ((code = param_write_bool(plist, "ManualFeed", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding MediaPosition\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "MediaPosition", + (int *)&(cups->header.MediaPosition))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding MirrorPrint\n", stderr); +#endif /* DEBUG */ + + b = cups->header.MirrorPrint; + if ((code = param_write_bool(plist, "MirrorPrint", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding NegativePrint\n", stderr); +#endif /* DEBUG */ + + b = cups->header.NegativePrint; + if ((code = param_write_bool(plist, "NegativePrint", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding OutputFaceUp\n", stderr); +#endif /* DEBUG */ + + b = cups->header.OutputFaceUp; + if ((code = param_write_bool(plist, "OutputFaceUp", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding Separations\n", stderr); +#endif /* DEBUG */ + + b = cups->header.Separations; + if ((code = param_write_bool(plist, "Separations", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding TraySwitch\n", stderr); +#endif /* DEBUG */ + + b = cups->header.TraySwitch; + if ((code = param_write_bool(plist, "TraySwitch", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding Tumble\n", stderr); +#endif /* DEBUG */ + + b = cups->header.Tumble; + if ((code = param_write_bool(plist, "Tumble", &b)) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsWidth\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsWidth", + (int *)&(cups->header.cupsWidth))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsHeight\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsHeight", + (int *)&(cups->header.cupsHeight))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsMediaType\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsMediaType", + (int *)&(cups->header.cupsMediaType))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsBitsPerColor\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsBitsPerColor", + (int *)&(cups->header.cupsBitsPerColor))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsBitsPerPixel\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsBitsPerPixel", + (int *)&(cups->header.cupsBitsPerPixel))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsBytesPerLine\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsBytesPerLine", + (int *)&(cups->header.cupsBytesPerLine))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsColorOrder\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsColorOrder", + (int *)&(cups->header.cupsColorOrder))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsColorSpace\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsColorSpace", + (int *)&(cups->header.cupsColorSpace))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsCompression\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsCompression", + (int *)&(cups->header.cupsCompression))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsRowCount\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsRowCount", + (int *)&(cups->header.cupsRowCount))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsRowFeed\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsRowFeed", + (int *)&(cups->header.cupsRowFeed))) < 0) + return (code); + +#ifdef DEBUG + fputs("DEBUG2: Adding cupsRowStep\n", stderr); +#endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsRowStep", + (int *)&(cups->header.cupsRowStep))) < 0) + return (code); + +#ifdef CUPS_RASTER_SYNCv1 +# ifdef DEBUG + fputs("DEBUG2: Adding cupsNumColors\n", stderr); +# endif /* DEBUG */ + + if ((code = param_write_int(plist, "cupsNumColors", + (int *)&(cups->header.cupsNumColors))) < 0) + return (code); + +# ifdef DEBUG + fputs("DEBUG2: Adding cupsInteger\n", stderr); +# endif /* DEBUG */ + + for (i = 0; i < 16; i ++) + { + sprintf(name, "cupsInteger%d", i); + if ((code = param_write_int(plist, name, + (int *)(cups->header.cupsInteger + i))) < 0) + return (code); + } + +# ifdef DEBUG + fputs("DEBUG2: Adding cupsReal\n", stderr); +# endif /* DEBUG */ + + for (i = 0; i < 16; i ++) + { + sprintf(name, "cupsReal%d", i); + if ((code = param_write_float(plist, name, + cups->header.cupsReal + i)) < 0) + return (code); + } + +# ifdef DEBUG + fputs("DEBUG2: Adding cupsString\n", stderr); +# endif /* DEBUG */ + + for (i = 0; i < 16; i ++) + { + sprintf(name, "cupsReal%d", i); + param_string_from_string(s, cups->header.cupsString[i]); + if ((code = param_write_string(plist, name, &s)) < 0) + return (code); + } + +# ifdef DEBUG + fputs("DEBUG2: Adding cupsMarkerType\n", stderr); +# endif /* DEBUG */ + + param_string_from_string(s, cups->header.cupsMarkerType); + if ((code = param_write_string(plist, "cupsMarkerType", &s)) < 0) + return (code); + +# ifdef DEBUG + fputs("DEBUG2: Adding cupsRenderingIntent\n", stderr); +# endif /* DEBUG */ + + param_string_from_string(s, cups->header.cupsRenderingIntent); + if ((code = param_write_string(plist, "cupsRenderingIntent", &s)) < 0) + return (code); +#endif /* CUPS_RASTER_SYNCv1 */ + +#ifdef DEBUG + fputs("DEBUG2: Leaving cups_get_params()\n", stderr); +#endif /* DEBUG */ + + return (0); +} + + +/* + * 'cups_get_space_params()' - Get space parameters from the RIP_CACHE env var. + */ + +void +cups_get_space_params(const gx_device_printer *pdev, + /* I - Printer device */ + gdev_prn_space_params *space_params) + /* O - Space parameters */ +{ + float cache_size; /* Size of tile cache in bytes */ + char *cache_env, /* Cache size environment variable */ + cache_units[255]; /* Cache size units */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG2: cups_get_space_params(%p, %p)\n", pdev, space_params); +#endif /* DEBUG */ + + if ((cache_env = getenv("RIP_MAX_CACHE")) != NULL) + { + switch (sscanf(cache_env, "%f%254s", &cache_size, cache_units)) + { + case 0 : + cache_size = 8 * 1024 * 1024; + break; + case 1 : + cache_size *= 4 * CUPS_TILE_SIZE * CUPS_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 * CUPS_TILE_SIZE * CUPS_TILE_SIZE; + break; + } + } + else + cache_size = 8 * 1024 * 1024; + + fprintf(stderr, "DEBUG: cache_size = %.0f\n", cache_size); + + space_params->MaxBitmap = (int)cache_size; + space_params->BufferSpace = (int)cache_size / 10; +} + + +/* + * 'cups_map_cielab()' - Map CIE Lab transformation... + */ + +static double /* O - Adjusted color value */ +cups_map_cielab(double x, /* I - Raw color value */ + double xn) /* I - Whitepoint color value */ +{ + double x_xn; /* Fraction of whitepoint */ + + + x_xn = x / xn; + + if (x_xn > 0.008856) + return (cbrt(x_xn)); + else + return (7.787 * x_xn + 16.0 / 116.0); +} + + +#ifdef dev_t_proc_encode_color +/* + * 'cups_map_cmyk()' - Map a CMYK color value to device colors. + */ + +private void +cups_map_cmyk(gx_device *pdev, /* I - Device info */ + frac c, /* I - Cyan value */ + frac m, /* I - Magenta value */ + frac y, /* I - Yellow value */ + frac k, /* I - Black value */ + frac *out) /* O - Device colors */ +{ + int c0, c1, c2; /* Temporary color values */ + float rr, rg, rb, /* Real RGB colors */ + ciex, ciey, ciez, /* CIE XYZ colors */ + ciey_yn, /* Normalized luminance */ + ciel, ciea, cieb; /* CIE Lab colors */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG2: cups_map_cmyk(%p, %d, %d, %d, %d, %p)\n", + pdev, c, m, y, k, out); +#endif /* DEBUG */ + + /* + * Convert the CMYK color to the destination colorspace... + */ + + switch (cups->header.cupsColorSpace) + { + case CUPS_CSPACE_W : + c0 = frac_1 - (c * 31 + m * 61 + y * 8) / 100 - k; + + if (c0 < 0) + out[0] = 0; + else if (c0 > frac_1) + out[0] = (frac)cupsDensity[frac_1]; + else + out[0] = (frac)cupsDensity[c0]; + break; + + case CUPS_CSPACE_RGBA : + out[3] = frac_1; + + case CUPS_CSPACE_RGB : + c0 = frac_1 - c - k; + c1 = frac_1 - m - k; + c2 = frac_1 - y - k; + + if (c0 < 0) + out[0] = 0; + else if (c0 > frac_1) + out[0] = (frac)cupsDensity[frac_1]; + else + out[0] = (frac)cupsDensity[c0]; + + if (c1 < 0) + out[1] = 0; + else if (c1 > frac_1) + out[1] = (frac)cupsDensity[frac_1]; + else + out[1] = (frac)cupsDensity[c1]; + + if (c2 < 0) + out[2] = 0; + else if (c2 > frac_1) + out[2] = (frac)cupsDensity[frac_1]; + else + out[2] = (frac)cupsDensity[c2]; + break; + + default : + case CUPS_CSPACE_K : + c0 = (c * 31 + m * 61 + y * 8) / 100 + k; + + if (c0 < 0) + out[0] = 0; + else if (c0 > frac_1) + out[0] = (frac)cupsDensity[frac_1]; + else + out[0] = (frac)cupsDensity[c0]; + break; + + case CUPS_CSPACE_CMY : + c0 = c + k; + c1 = m + k; + c2 = y + k; + + if (c0 < 0) + out[0] = 0; + else if (c0 > frac_1) + out[0] = (frac)cupsDensity[frac_1]; + else + out[0] = (frac)cupsDensity[c0]; + + if (c1 < 0) + out[1] = 0; + else if (c1 > frac_1) + out[1] = (frac)cupsDensity[frac_1]; + else + out[1] = (frac)cupsDensity[c1]; + + if (c2 < 0) + out[2] = 0; + else if (c2 > frac_1) + out[2] = (frac)cupsDensity[frac_1]; + else + out[2] = (frac)cupsDensity[c2]; + break; + + case CUPS_CSPACE_YMC : + c0 = y + k; + c1 = m + k; + c2 = c + k; + + if (c0 < 0) + out[0] = 0; + else if (c0 > frac_1) + out[0] = (frac)cupsDensity[frac_1]; + else + out[0] = (frac)cupsDensity[c0]; + + if (c1 < 0) + out[1] = 0; + else if (c1 > frac_1) + out[1] = (frac)cupsDensity[frac_1]; + else + out[1] = (frac)cupsDensity[c1]; + + if (c2 < 0) + out[2] = 0; + else if (c2 > frac_1) + out[2] = (frac)cupsDensity[frac_1]; + else + out[2] = (frac)cupsDensity[c2]; + break; + + case CUPS_CSPACE_CMYK : + if (c < 0) + out[0] = 0; + else if (c > frac_1) + out[0] = (frac)cupsDensity[frac_1]; + else + out[0] = (frac)cupsDensity[c]; + + if (m < 0) + out[1] = 0; + else if (m > frac_1) + out[1] = (frac)cupsDensity[frac_1]; + else + out[1] = (frac)cupsDensity[m]; + + if (y < 0) + out[2] = 0; + else if (y > frac_1) + out[2] = (frac)cupsDensity[frac_1]; + else + out[2] = (frac)cupsDensity[y]; + + if (k < 0) + out[3] = 0; + else if (k > frac_1) + out[3] = (frac)cupsDensity[frac_1]; + else + out[3] = (frac)cupsDensity[k]; + break; + + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + if (y < 0) + out[0] = 0; + else if (y > frac_1) + out[0] = (frac)cupsDensity[frac_1]; + else + out[0] = (frac)cupsDensity[y]; + + if (m < 0) + out[1] = 0; + else if (m > frac_1) + out[1] = (frac)cupsDensity[frac_1]; + else + out[1] = (frac)cupsDensity[m]; + + if (c < 0) + out[2] = 0; + else if (c > frac_1) + out[2] = (frac)cupsDensity[frac_1]; + else + out[2] = (frac)cupsDensity[c]; + + if (k < 0) + out[3] = 0; + else if (k > frac_1) + out[3] = (frac)cupsDensity[frac_1]; + else + out[3] = (frac)cupsDensity[k]; + break; + + case CUPS_CSPACE_KCMYcm : + case CUPS_CSPACE_KCMY : + if (k < 0) + out[0] = 0; + else if (k > frac_1) + out[0] = (frac)cupsDensity[frac_1]; + else + out[0] = (frac)cupsDensity[k]; + + if (c < 0) + out[1] = 0; + else if (c > frac_1) + out[1] = (frac)cupsDensity[frac_1]; + else + out[1] = (frac)cupsDensity[c]; + + if (m < 0) + out[2] = 0; + else if (m > frac_1) + out[2] = (frac)cupsDensity[frac_1]; + else + out[2] = (frac)cupsDensity[m]; + + if (y < 0) + out[3] = 0; + else if (y > frac_1) + out[3] = (frac)cupsDensity[frac_1]; + else + out[3] = (frac)cupsDensity[y]; + break; + +# ifdef CUPS_RASTER_HAVE_COLORIMETRIC + case CUPS_CSPACE_CIEXYZ : + case CUPS_CSPACE_CIELab : + case CUPS_CSPACE_ICC1 : + case CUPS_CSPACE_ICC2 : + case CUPS_CSPACE_ICC3 : + case CUPS_CSPACE_ICC4 : + case CUPS_CSPACE_ICC5 : + case CUPS_CSPACE_ICC6 : + case CUPS_CSPACE_ICC7 : + case CUPS_CSPACE_ICC8 : + case CUPS_CSPACE_ICC9 : + case CUPS_CSPACE_ICCA : + case CUPS_CSPACE_ICCB : + case CUPS_CSPACE_ICCC : + case CUPS_CSPACE_ICCD : + case CUPS_CSPACE_ICCE : + case CUPS_CSPACE_ICCF : + /* + * Convert CMYK to sRGB... + */ + + c0 = frac_1 - c - k; + c1 = frac_1 - m - k; + c2 = frac_1 - y - k; + + if (c0 < 0) + c0 = 0; + else if (c0 > frac_1) + c0 = frac_1; + + if (c1 < 0) + c1 = 0; + else if (c1 > frac_1) + c1 = frac_1; + + if (c2 < 0) + c2 = 0; + else if (c2 > frac_1) + c2 = frac_1; + + /* + * Convert sRGB to linear RGB... + */ + + rr = pow((double)c0 / (double)frac_1, 0.58823529412); + rg = pow((double)c1 / (double)frac_1, 0.58823529412); + rb = pow((double)c2 / (double)frac_1, 0.58823529412); + + /* + * Convert to CIE XYZ... + */ + + ciex = 0.412453 * rr + 0.357580 * rg + 0.180423 * rb; + ciey = 0.212671 * rr + 0.715160 * rg + 0.072169 * rb; + ciez = 0.019334 * rr + 0.119193 * rg + 0.950227 * rb; + + if (cups->header.cupsColorSpace == CUPS_CSPACE_CIEXYZ) + { + /* + * Convert to an integer XYZ color value... + */ + + if (ciex > 1.0) + c0 = frac_1; + else if (ciex > 0.0) + c0 = (int)(ciex * frac_1); + else + c0 = 0; + + if (ciey > 1.0) + c1 = frac_1; + else if (ciey > 0.0) + c1 = (int)(ciey * frac_1); + else + c1 = 0; + + if (ciez > 1.0) + c2 = frac_1; + else if (ciez > 0.0) + c2 = (int)(ciez * frac_1); + else + c2 = 0; + } + else + { + /* + * Convert CIE XYZ to Lab... + */ + + ciey_yn = ciey / D65_Y; + + if (ciey_yn > 0.008856) + ciel = 116 * cbrt(ciey_yn) - 16; + else + ciel = 903.3 * ciey_yn; + + ciea = 500 * (cups_map_cielab(ciex, D65_X) - + cups_map_cielab(ciey, D65_Y)); + cieb = 200 * (cups_map_cielab(ciey, D65_Y) - + cups_map_cielab(ciez, D65_Z)); + + /* + * Scale the L value and bias the a and b values by 128 + * so that all values are in the range of 0 to 255. + */ + + ciel *= 2.55; + ciea += 128; + cieb += 128; + + /* + * Convert to frac values... + */ + + if (ciel < 0.0) + c0 = 0; + else if (ciel < 255.0) + c0 = (int)(ciel * frac_1 / 255.0); + else + c0 = frac_1; + + if (ciea < 0.0) + c1 = 0; + else if (ciea < 255.0) + c1 = (int)(ciea * frac_1 / 255.0); + else + c1 = frac_1; + + if (cieb < 0.0) + c2 = 0; + else if (cieb < 255.0) + c2 = (int)(cieb * frac_1 / 255.0); + else + c2 = frac_1; + } + + /* + * Put the final color value together... + */ + + out[0] = c0; + out[1] = c1; + out[2] = c2; + break; +# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */ + } + + switch (cups->color_info.num_components) + { + default : + case 1 : +#ifdef DEBUG + fprintf(stderr, "DEBUG2: \\=== COLOR %d\n", out[0]); +#endif /* DEBUG */ + break; + + case 3 : +#ifdef DEBUG + fprintf(stderr, "DEBUG2: \\=== COLOR %d, %d, %d\n", + out[0], out[1], out[2]); +#endif /* DEBUG */ + break; + + case 4 : +#ifdef DEBUG + fprintf(stderr, "DEBUG2: \\=== COLOR %d, %d, %d, %d\n", + out[0], out[1], out[2], out[3]); +#endif /* DEBUG */ + break; + } +} + + +/* + * 'cups_map_gray()' - Map a grayscale value to device colors. + */ + +private void +cups_map_gray(gx_device *pdev, /* I - Device info */ + frac g, /* I - Grayscale value */ + frac *out) /* O - Device colors */ +{ +#ifdef DEBUG + fprintf(stderr, "DEBUG2: cups_map_gray(%p, %d, %p)\n", + pdev, g, out); +#endif /* DEBUG */ + + /* + * Just use the CMYK mapper... + */ + + cups_map_cmyk(pdev, 0, 0, 0, frac_1 - g, out); +} + + +/* + * 'cups_map_rgb()' - Map a RGB color value to device colors. + */ + +private void +cups_map_rgb(gx_device *pdev, + /* I - Device info */ + const gs_imager_state *pis,/* I - Device state */ + frac r, /* I - Red value */ + frac g, /* I - Green value */ + frac b, /* I - Blue value */ + frac *out)/* O - Device colors */ +{ + frac c, m, y, k; /* CMYK values */ + frac mk; /* Maximum K value */ + int tc, tm, ty; /* Temporary color values */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG2: cups_map_rgb(%p, %p, %d, %d, %d, %p)\n", + pdev, pis, r, g, b, out); +#endif /* DEBUG */ + + /* + * Compute CMYK values... + */ + + c = frac_1 - r; + m = frac_1 - g; + y = frac_1 - b; + k = min(c, min(m, y)); + + if ((mk = max(c, max(m, y))) > k) + k = (int)((float)k * (float)k * (float)k / ((float)mk * (float)mk)); + + c -= k; + m -= k; + y -= k; + + /* + * Do color correction as needed... + */ + + if (cupsHaveProfile) + { + /* + * Color correct CMY... + */ + + tc = cupsMatrix[0][0][c] + + cupsMatrix[0][1][m] + + cupsMatrix[0][2][y]; + tm = cupsMatrix[1][0][c] + + cupsMatrix[1][1][m] + + cupsMatrix[1][2][y]; + ty = cupsMatrix[2][0][c] + + cupsMatrix[2][1][m] + + cupsMatrix[2][2][y]; + + if (tc < 0) + c = 0; + else if (tc > frac_1) + c = frac_1; + else + c = (frac)tc; + + if (tm < 0) + m = 0; + else if (tm > frac_1) + m = frac_1; + else + m = (frac)tm; + + if (ty < 0) + y = 0; + else if (ty > frac_1) + y = frac_1; + else + y = (frac)ty; + } + + /* + * Use the CMYK mapping function to produce the device colors... + */ + + cups_map_cmyk(pdev, c, m, y, k, out); +} +#else +/* + * '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, "DEBUG2: 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... + */ + + if (cupsHaveProfile) + { + c = cupsDensity[c]; + m = cupsDensity[m]; + y = cupsDensity[y]; + k = cupsDensity[k]; + } + + ic = cupsEncodeLUT[c]; + im = cupsEncodeLUT[m]; + iy = cupsEncodeLUT[y]; + ik = cupsEncodeLUT[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; + } + +# ifdef DEBUG + fprintf(stderr, "DEBUG2: CMYK (%d,%d,%d,%d) -> CMYK %08x (%d,%d,%d,%d)\n", + c, m, y, k, (unsigned)i, ic, im, iy, ik); +# endif /* DEBUG */ + + /* + * Make sure we don't get a CMYK color of 255, 255, 255, 255... + */ + + if (i == gx_no_color_index) + i --; + + 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, "DEBUG2: cups_map_color_rgb(%p, %d, %p)\n", pdev, + (unsigned)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, "DEBUG2: COLOR %08x = ", (unsigned)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] = cupsDecodeLUT[c3]; + break; + + case CUPS_CSPACE_W : + prgb[0] = + prgb[1] = + prgb[2] = cupsDecodeLUT[c3]; + break; + + case CUPS_CSPACE_RGB : + prgb[0] = cupsDecodeLUT[c1]; + prgb[1] = cupsDecodeLUT[c2]; + prgb[2] = cupsDecodeLUT[c3]; + break; + + case CUPS_CSPACE_RGBA : + prgb[0] = cupsDecodeLUT[c0]; + prgb[1] = cupsDecodeLUT[c1]; + prgb[2] = cupsDecodeLUT[c2]; + break; + + case CUPS_CSPACE_CMY : + prgb[0] = cupsDecodeLUT[c1]; + prgb[1] = cupsDecodeLUT[c2]; + prgb[2] = cupsDecodeLUT[c3]; + break; + + case CUPS_CSPACE_YMC : + prgb[0] = cupsDecodeLUT[c3]; + prgb[1] = cupsDecodeLUT[c2]; + prgb[2] = cupsDecodeLUT[c1]; + break; + + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_KCMYcm : + k = cupsDecodeLUT[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 = cupsDecodeLUT[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 = cupsDecodeLUT[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 CUPS_RASTER_HAVE_COLORIMETRIC + case CUPS_CSPACE_CIEXYZ : + case CUPS_CSPACE_CIELab : + case CUPS_CSPACE_ICC1 : + case CUPS_CSPACE_ICC2 : + case CUPS_CSPACE_ICC3 : + case CUPS_CSPACE_ICC4 : + case CUPS_CSPACE_ICC5 : + case CUPS_CSPACE_ICC6 : + case CUPS_CSPACE_ICC7 : + case CUPS_CSPACE_ICC8 : + case CUPS_CSPACE_ICC9 : + case CUPS_CSPACE_ICCA : + case CUPS_CSPACE_ICCB : + case CUPS_CSPACE_ICCC : + case CUPS_CSPACE_ICCD : + case CUPS_CSPACE_ICCE : + case CUPS_CSPACE_ICCF : + break; +# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */ + } + +# 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 */ + float rr, rg, rb, /* Real RGB colors */ + ciex, ciey, ciez, + /* CIE XYZ colors */ + ciey_yn, /* Normalized luminance */ + ciel, ciea, cieb; + /* CIE Lab colors */ + + +# ifdef DEBUG + fprintf(stderr, "DEBUG2: 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 = cupsEncodeLUT[(r * 31 + g * 61 + b * 8) / 100]; + break; + + case CUPS_CSPACE_RGB : + ic = cupsEncodeLUT[r]; + im = cupsEncodeLUT[g]; + iy = cupsEncodeLUT[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 = cupsEncodeLUT[r]; + im = cupsEncodeLUT[g]; + iy = cupsEncodeLUT[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 = cupsEncodeLUT[gx_max_color_value - (r * 31 + g * 61 + b * 8) / 100]; + break; + + case CUPS_CSPACE_CMY : + ic = cupsEncodeLUT[gx_max_color_value - r]; + im = cupsEncodeLUT[gx_max_color_value - g]; + iy = cupsEncodeLUT[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 = cupsEncodeLUT[gx_max_color_value - r]; + im = cupsEncodeLUT[gx_max_color_value - g]; + iy = cupsEncodeLUT[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 = cupsEncodeLUT[ic - ik]; + im = cupsEncodeLUT[im - ik]; + iy = cupsEncodeLUT[iy - ik]; + ik = cupsEncodeLUT[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; + } + +# ifdef DEBUG + fprintf(stderr, "DEBUG2: CMY (%d,%d,%d) -> CMYK %08x (%d,%d,%d,%d)\n", + r, g, b, (unsigned)i, ic, im, iy, ik); +# endif /* DEBUG */ + 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 = cupsEncodeLUT[ic - ik]; + im = cupsEncodeLUT[im - ik]; + iy = cupsEncodeLUT[iy - ik]; + ik = cupsEncodeLUT[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 = cupsEncodeLUT[ic - ik]; + im = cupsEncodeLUT[im - ik]; + iy = cupsEncodeLUT[iy - ik]; + ik = cupsEncodeLUT[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 = cupsEncodeLUT[ic - ik]; + im = cupsEncodeLUT[im - ik]; + iy = cupsEncodeLUT[iy - ik]; + ik = cupsEncodeLUT[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 CUPS_RASTER_HAVE_COLORIMETRIC + case CUPS_CSPACE_CIEXYZ : + case CUPS_CSPACE_CIELab : + case CUPS_CSPACE_ICC1 : + case CUPS_CSPACE_ICC2 : + case CUPS_CSPACE_ICC3 : + case CUPS_CSPACE_ICC4 : + case CUPS_CSPACE_ICC5 : + case CUPS_CSPACE_ICC6 : + case CUPS_CSPACE_ICC7 : + case CUPS_CSPACE_ICC8 : + case CUPS_CSPACE_ICC9 : + case CUPS_CSPACE_ICCA : + case CUPS_CSPACE_ICCB : + case CUPS_CSPACE_ICCC : + case CUPS_CSPACE_ICCD : + case CUPS_CSPACE_ICCE : + case CUPS_CSPACE_ICCF : + /* + * Convert sRGB to linear RGB... + */ + + rr = pow((double)r / (double)gx_max_color_value, 0.58823529412); + rg = pow((double)g / (double)gx_max_color_value, 0.58823529412); + rb = pow((double)b / (double)gx_max_color_value, 0.58823529412); + + /* + * Convert to CIE XYZ... + */ + + ciex = 0.412453 * rr + 0.357580 * rg + 0.180423 * rb; + ciey = 0.212671 * rr + 0.715160 * rg + 0.072169 * rb; + ciez = 0.019334 * rr + 0.119193 * rg + 0.950227 * rb; + + if (cups->header.cupsColorSpace == CUPS_CSPACE_CIEXYZ) + { + /* + * Convert to an integer XYZ color value... + */ + + if (ciex > 1.0) + ic = 255; + else if (ciex > 0.0) + ic = (int)(ciex * 255.0); + else + ic = 0; + + if (ciey > 1.0) + im = 255; + else if (ciey > 0.0) + im = (int)(ciey * 255.0); + else + im = 0; + + if (ciez > 1.0) + iy = 255; + else if (ciez > 0.0) + iy = (int)(ciez * 255.0); + else + iy = 0; + } + else + { + /* + * Convert CIE XYZ to Lab... + */ + + ciey_yn = ciey / D65_Y; + + if (ciey_yn > 0.008856) + ciel = 116 * cbrt(ciey_yn) - 16; + else + ciel = 903.3 * ciey_yn; + + ciea = 500 * (cups_map_cielab(ciex, D65_X) - + cups_map_cielab(ciey, D65_Y)); + cieb = 200 * (cups_map_cielab(ciey, D65_Y) - + cups_map_cielab(ciez, D65_Z)); + + /* + * Scale the L value and bias the a and b values by 128 + * so that all values are in the range of 0 to 255. + */ + + ciel *= 2.55; + ciea += 128; + cieb += 128; + + /* + * Convert to 8-bit values... + */ + + if (ciel < 0.0) + ic = 0; + else if (ciel < 255.0) + ic = ciel; + else + ic = 255; + + if (ciea < 0.0) + im = 0; + else if (ciea < 255.0) + im = ciea; + else + im = 255; + + if (cieb < 0.0) + iy = 0; + else if (cieb < 255.0) + iy = cieb; + else + iy = 255; + } + + /* + * Put the final color value together... + */ + + 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; +# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */ + } + +# ifdef DEBUG + fprintf(stderr, "DEBUG2: RGB %d,%d,%d = %08x\n", r, g, b, (unsigned)i); +# endif /* DEBUG */ + + return (i); +} +#endif /* dev_t_proc_encode_color */ + + +/* + * '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, "DEBUG2: cups_open(%p)\n", pdev); +#endif /* DEBUG */ + + cups->printer_procs.get_space_params = cups_get_space_params; + + if (cups->page == 0) + { + fputs("INFO: Processing page 1...\n", stderr); + cups->page = 1; + } + + cups_set_color_info(pdev); + + if ((code = gdev_prn_open(pdev)) != 0) + return (code); + + if (cupsPPD == NULL) + cupsPPD = 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, "DEBUG2: 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, "DEBUG2: 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(fileno(cups->file), + 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 (cupsPPD != NULL && !cupsPPD->manual_copies) + { + cups->header.NumCopies = num_copies; + num_copies = 1; + } + +#ifdef DEBUG + fprintf(stderr, "DEBUG2: 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 */ +#ifdef CUPS_RASTER_SYNCv1 + char name[255]; /* Name of attribute */ +#endif /* CUPS_RASTER_SYNCv1 */ + 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 size_set; /* Was the size set? */ + int color_set; /* Were the color attrs set? */ + gdev_prn_space_params sp; /* Space parameter data */ + int width, /* New width of page */ + height; /* New height of page */ + + +#ifdef DEBUG + fprintf(stderr, "DEBUG2: 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]; \ + } + + size_set = param_read_float_array(plist, ".MediaSize", &arrayval) == 0 || + param_read_float_array(plist, "PageSize", &arrayval) == 0; + color_set = param_read_int(plist, "cupsColorSpace", &intval) == 0 || + param_read_int(plist, "cupsBitsPerColor", &intval) == 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(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) + +#ifdef CUPS_RASTER_SYNCv1 + for (i = 0; i < 16; i ++) + { + sprintf(name, "cupsInteger%d", i); + intoption(cupsInteger[i], name, unsigned) + } + + for (i = 0; i < 16; i ++) + { + sprintf(name, "cupsReal%d", i); + floatoption(cupsReal[i], name) + } + + for (i = 0; i < 16; i ++) + { + sprintf(name, "cupsString%d", i); + stringoption(cupsString[i], name) + } + + stringoption(cupsMarkerType, "cupsMarkerType"); + stringoption(cupsRenderingIntent, "cupsRenderingIntent"); +#endif /* CUPS_RASTER_SYNCv1 */ + + if ((code = param_read_string(plist, "cupsProfile", &stringval)) < 0) + { + param_signal_error(plist, "cupsProfile", code); + return (code); + } + else if (code == 0) + { + if (cupsProfile != NULL) + free(cupsProfile); + + cupsProfile = strdup(stringval.data); + } + + cups_set_color_info(pdev); + + /* + * Then process standard page device options... + */ + + if ((code = gdev_prn_put_params(pdev, plist)) < 0) + return (code); + + /* + * Update margins/sizes as needed... + */ + + if (size_set) + { + /* + * Compute the page margins... + */ + + fprintf(stderr, "DEBUG: Updating PageSize to [%.0f %.0f]...\n", + cups->MediaSize[0], cups->MediaSize[1]); + + memset(margins, 0, sizeof(margins)); + + cups->landscape = 0; + + if (cupsPPD != NULL) + { + /* + * Find the matching page size... + */ + + for (i = cupsPPD->num_sizes, size = cupsPPD->sizes; + i > 0; + i --, size ++) + if (fabs(cups->MediaSize[1] - size->length) < 5.0 && + fabs(cups->MediaSize[0] - size->width) < 5.0) + break; + + if (i > 0) + { + /* + * Standard size... + */ + + fprintf(stderr, "DEBUG: size = %s\n", size->name); + + gx_device_set_media_size(pdev, size->width, size->length); + + 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 + { + /* + * No matching portrait size; look for a matching size in + * landscape orientation... + */ + + for (i = cupsPPD->num_sizes, size = cupsPPD->sizes; + i > 0; + i --, size ++) + if (fabs(cups->MediaSize[0] - size->length) < 5.0 && + fabs(cups->MediaSize[1] - size->width) < 5.0) + break; + + if (i > 0) + { + /* + * Standard size in landscape orientation... + */ + + fprintf(stderr, "DEBUG: landscape size = %s\n", size->name); + + gx_device_set_media_size(pdev, size->length, size->width); + + cups->landscape = 1; + + 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] = cupsPPD->custom_margins[i] / 72.0; + } + } + + fprintf(stderr, "DEBUG: margins[] = [ %f %f %f %f ]\n", + margins[0], margins[1], margins[2], margins[3]); + } + + /* + * Set the margins to update the bitmap size... + */ + + gx_device_set_margins(pdev, margins, false); + } + + /* + * Set CUPS raster header values... + */ + + cups->header.HWResolution[0] = pdev->HWResolution[0]; + cups->header.HWResolution[1] = pdev->HWResolution[1]; + + cups->header.Margins[0] = pdev->HWMargins[0]; + cups->header.Margins[1] = pdev->HWMargins[1]; + + cups->header.PageSize[0] = pdev->MediaSize[0]; + cups->header.PageSize[1] = pdev->MediaSize[1]; + + cups->header.ImagingBoundingBox[0] = pdev->HWMargins[0]; + cups->header.ImagingBoundingBox[1] = pdev->HWMargins[3]; + cups->header.ImagingBoundingBox[2] = pdev->MediaSize[0] - pdev->HWMargins[2]; + cups->header.ImagingBoundingBox[3] = pdev->MediaSize[1] - pdev->HWMargins[1]; + + /* + * Reallocate memory if the size or color depth was changed... + */ + + if (color_set || size_set) + { + /* + * Make sure the page image is the correct size - current Ghostscript + * does not keep track of the margins in the bitmap size... + */ + + if (cups->landscape) + { + width = (pdev->MediaSize[1] - pdev->HWMargins[0] - pdev->HWMargins[2]) * + pdev->HWResolution[0] / 72.0f + 0.499f; + height = (pdev->MediaSize[0] - pdev->HWMargins[1] - pdev->HWMargins[3]) * + pdev->HWResolution[1] / 72.0f + 0.499f; + } + else + { + width = (pdev->MediaSize[0] - pdev->HWMargins[0] - pdev->HWMargins[2]) * + pdev->HWResolution[0] / 72.0f + 0.499f; + height = (pdev->MediaSize[1] - pdev->HWMargins[1] - pdev->HWMargins[3]) * + pdev->HWResolution[1] / 72.0f + 0.499f; + } + + /* + * Don't reallocate memory unless the device has been opened... + */ + + if (pdev->is_open) + { + /* + * Device is open, so reallocate... + */ + + fprintf(stderr, "DEBUG: Reallocating memory, [%.0f %.0f] = %dx%d pixels...\n", + pdev->MediaSize[0], pdev->MediaSize[1], width, height); + + sp = ((gx_device_printer *)pdev)->space_params; + + if ((code = gdev_prn_reallocate_memory(pdev, &sp, width, height)) < 0) + return (code); + } + else + { + /* + * Device isn't yet open, so just save the new width and height... + */ + + fprintf(stderr, "DEBUG: Setting initial media size, [%.0f %.0f] = %dx%d pixels...\n", + pdev->MediaSize[0], pdev->MediaSize[1], width, height); + + pdev->width = width; + pdev->height = height; + } + } + +#ifdef DEBUG + fprintf(stderr, "DEBUG2: ppd = %p\n", cupsPPD); + fprintf(stderr, "DEBUG2: PageSize = [ %.3f %.3f ]\n", + pdev->MediaSize[0], pdev->MediaSize[1]); + fprintf(stderr, "DEBUG2: margins = [ %.3f %.3f %.3f %.3f ]\n", + margins[0], margins[1], margins[2], margins[3]); + fprintf(stderr, "DEBUG2: HWResolution = [ %.3f %.3f ]\n", + pdev->HWResolution[0], pdev->HWResolution[1]); + fprintf(stderr, "DEBUG2: width = %d, height = %d\n", + pdev->width, pdev->height); + fprintf(stderr, "DEBUG2: 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 */ + int max_lut; /* Maximum LUT value */ + 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, "DEBUG2: 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; + +#ifdef CUPS_RASTER_HAVE_COLORIMETRIC + case CUPS_CSPACE_CIEXYZ : + case CUPS_CSPACE_CIELab : + case CUPS_CSPACE_ICC1 : + case CUPS_CSPACE_ICC2 : + case CUPS_CSPACE_ICC3 : + case CUPS_CSPACE_ICC4 : + case CUPS_CSPACE_ICC5 : + case CUPS_CSPACE_ICC6 : + case CUPS_CSPACE_ICC7 : + case CUPS_CSPACE_ICC8 : + case CUPS_CSPACE_ICC9 : + case CUPS_CSPACE_ICCA : + case CUPS_CSPACE_ICCB : + case CUPS_CSPACE_ICCC : + case CUPS_CSPACE_ICCD : + case CUPS_CSPACE_ICCE : + case CUPS_CSPACE_ICCF : + /* + * Colorimetric color spaces currently are implemented as 24-bit + * mapping to XYZ or Lab, which are then converted as needed to + * the final representation... + * + * This code enforces a minimum output depth of 8 bits per + * component... + */ + + if (cups->header.cupsBitsPerColor < 8) + cups->header.cupsBitsPerColor = 8; + + if (cups->header.cupsColorOrder != CUPS_ORDER_CHUNKED) + cups->header.cupsBitsPerPixel = cups->header.cupsBitsPerColor; + else + cups->header.cupsBitsPerPixel = 3 * cups->header.cupsBitsPerColor; + + cups->color_info.depth = 24; + cups->color_info.num_components = 3; + break; +#endif /* CUPS_RASTER_HAVE_COLORIMETRIC */ + } + +#ifdef dev_t_proc_encode_color + switch (cups->header.cupsColorSpace) + { + default : + cups->color_info.gray_index = GX_CINFO_COMP_NO_INDEX; + break; + + case CUPS_CSPACE_W : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_K : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + case CUPS_CSPACE_KCMYcm : + case CUPS_CSPACE_KCMY : + cups->color_info.gray_index = 0; + break; + + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + cups->color_info.gray_index = 3; + break; + } + + switch (cups->header.cupsColorSpace) + { + default : + case CUPS_CSPACE_W : + case CUPS_CSPACE_WHITE : + case CUPS_CSPACE_RGB : +# ifdef CUPS_RASTER_HAVE_COLORIMETRIC + case CUPS_CSPACE_CIEXYZ : + case CUPS_CSPACE_CIELab : + case CUPS_CSPACE_ICC1 : + case CUPS_CSPACE_ICC2 : + case CUPS_CSPACE_ICC3 : + case CUPS_CSPACE_ICC4 : + case CUPS_CSPACE_ICC5 : + case CUPS_CSPACE_ICC6 : + case CUPS_CSPACE_ICC7 : + case CUPS_CSPACE_ICC8 : + case CUPS_CSPACE_ICC9 : + case CUPS_CSPACE_ICCA : + case CUPS_CSPACE_ICCB : + case CUPS_CSPACE_ICCC : + case CUPS_CSPACE_ICCD : + case CUPS_CSPACE_ICCE : + case CUPS_CSPACE_ICCF : +# endif /* CUPS_RASTER_HAVE_COLORIMETRIC */ + cups->color_info.polarity = GX_CINFO_POLARITY_ADDITIVE; + break; + + case CUPS_CSPACE_K : + case CUPS_CSPACE_GOLD : + case CUPS_CSPACE_SILVER : + case CUPS_CSPACE_CMY : + case CUPS_CSPACE_YMC : + case CUPS_CSPACE_KCMYcm : + case CUPS_CSPACE_CMYK : + case CUPS_CSPACE_YMCK : + case CUPS_CSPACE_KCMY : + case CUPS_CSPACE_GMCK : + case CUPS_CSPACE_GMCS : + cups->color_info.polarity = GX_CINFO_POLARITY_SUBTRACTIVE; + break; + } + + cups->color_info.separable_and_linear = GX_CINFO_SEP_LIN_NONE; +#endif /* dev_t_proc_encode_color */ + + if ((i = cups->header.cupsBitsPerColor) > 8) + i = 8; + + max_lut = (1 << i) - 1; + + switch (cups->color_info.num_components) + { + default : + case 1 : + cups->color_info.max_gray = max_lut; + cups->color_info.max_color = 0; + cups->color_info.dither_grays = max_lut + 1; + cups->color_info.dither_colors = 0; + break; + + case 3 : + cups->color_info.max_gray = 0; + cups->color_info.max_color = max_lut; + cups->color_info.dither_grays = 0; + cups->color_info.dither_colors = max_lut + 1; + break; + + case 4 : + cups->color_info.max_gray = max_lut; + cups->color_info.max_color = max_lut; + cups->color_info.dither_grays = max_lut + 1; + cups->color_info.dither_colors = max_lut + 1; + break; + } + + /* + * Enable/disable CMYK color support... + */ + +#ifdef dev_t_proc_encode_color + cups->color_info.max_components = cups->color_info.num_components; +#endif /* dev_t_proc_encode_color */ + + /* + * Tell Ghostscript to forget any colors it has cached... + */ + + gx_device_decache_colors(pdev); + + /* + * Compute the lookup tables... + */ + + for (i = 0; i <= gx_max_color_value; i ++) + { + cupsEncodeLUT[i] = (max_lut * i + gx_max_color_value / 2) / + gx_max_color_value; + +#ifdef DEBUG + if (i == 0 || cupsEncodeLUT[i] != cupsEncodeLUT[i - 1]) + fprintf(stderr, "DEBUG2: cupsEncodeLUT[%d] = %d\n", i, cupsEncodeLUT[i]); +#endif /* DEBUG */ + } + + for (i = 0; i < cups->color_info.dither_grays; i ++) + cupsDecodeLUT[i] = gx_max_color_value * i / max_lut; + + 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); + + /* + * Set the color profile as needed... + */ + + cupsHaveProfile = 0; + +#ifdef dev_t_proc_encode_color + if (cupsProfile) +#else + if (cupsProfile && cups->header.cupsBitsPerColor == 8) +#endif /* dev_t_proc_encode_color */ + { + 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; + } + } +#ifdef dev_t_proc_encode_color + else if (cupsPPD) +#else + else if (cupsPPD && cups->header.cupsBitsPerColor == 8) +#endif /* dev_t_proc_encode_color */ + { + /* + * 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 = cupsPPD->profiles; + i < cupsPPD->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 < cupsPPD->num_profiles) + { + fputs("DEBUG: Using color profile in PPD file!\n", stderr); + + 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 <= CUPS_MAX_VALUE; k ++) + { + cupsMatrix[i][j][k] = (int)((float)k * m[i][j] + 0.5); + +#ifdef DEBUG + if ((k & 4095) == 0) + fprintf(stderr, "DEBUG2: cupsMatrix[%d][%d][%d] = %d\n", + i, j, k, cupsMatrix[i][j][k]); +#endif /* DEBUG */ + } + + + for (k = 0; k <= CUPS_MAX_VALUE; k ++) + { + cupsDensity[k] = (int)((float)CUPS_MAX_VALUE * d * + pow((float)k / (float)CUPS_MAX_VALUE, g) + + 0.5); + +#ifdef DEBUG + if ((k & 4095) == 0) + fprintf(stderr, "DEBUG2: cupsDensity[%d] = %d\n", k, cupsDensity[k]); +#endif /* DEBUG */ + } + } + else + { + for (k = 0; k <= CUPS_MAX_VALUE; k ++) + cupsDensity[k] = k; + } +} + + +/* + * '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 && + cupsPPD && cupsPPD->flip_duplex && !(cups->page & 1)) + flip = 1; + else + flip = 0; + + fprintf(stderr, "DEBUG: cups_print_chunked - flip = %d, height = %d\n", + flip, cups->height); + + /* + * 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 = cupsRevUpper1[*srcptr & 15] | + cupsRevLower1[*srcptr >> 4]; + } + break; + + case 2 : /* 2-bit grayscale */ + for (srcptr += srcbytes - 1; + count > 0; + count --, srcptr --, dstptr ++) + { + *dstptr = cupsRevUpper2[*srcptr & 15] | + cupsRevLower2[*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, /* Pointer to components */ + *kptr, *lcptr, *lmptr; /* ... */ + int flip; /* Flip scanline? */ + + + if (cups->header.Duplex && !cups->header.Tumble && + cupsPPD && cupsPPD->flip_duplex && !(cups->page & 1)) + flip = 1; + else + flip = 0; + + fprintf(stderr, "DEBUG: cups_print_banded - flip = %d, height = %d\n", + flip, cups->height); + + /* + * 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: gdevcups.c 4493 2005-02-18 02:09:53Z mike $". + */ diff --git a/pstoraster/gs707-lib.patch b/pstoraster/gs707-lib.patch new file mode 100644 index 000000000..32b011dd9 --- /dev/null +++ b/pstoraster/gs707-lib.patch @@ -0,0 +1,110 @@ +diff -u ghostscript-7.07/lib/gs_init.ps ghostscript-7.07-easysw/lib/gs_init.ps +--- ghostscript-7.07/lib/gs_init.ps 2003-04-12 10:02:38.000000000 -0400 ++++ ghostscript-7.07-easysw/lib/gs_init.ps 2003-11-14 16:38:44.000000000 -0500 +@@ -119,6 +119,7 @@ + currentdict /NOFONTPATH known /NOFONTPATH exch def + currentdict /NOGC known /NOGC exch def + currentdict /NOINTERPOLATE .knownget { /INTERPOLATE exch not def } if ++currentdict /NOMEDIAATTRS known /NOMEDIAATTRS exch def + currentdict /NOPAGEPROMPT known /NOPAGEPROMPT exch def + currentdict /NOPAUSE known /NOPAUSE exch def + currentdict /NOPLATFONTS known /NOPLATFONTS exch def +diff -u ghostscript-7.07/lib/gs_setpd.ps ghostscript-7.07-easysw/lib/gs_setpd.ps +--- ghostscript-7.07/lib/gs_setpd.ps 2003-04-12 10:02:38.000000000 -0400 ++++ ghostscript-7.07-easysw/lib/gs_setpd.ps 2003-11-14 16:38:06.000000000 -0500 +@@ -324,21 +324,42 @@ + } bind + .dicttomark readonly def + +-% Define the keys used in input attribute matching. +-/.inputattrkeys [ +- /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet +- % The following are documented in Adobe's supplement for v2017. +- /LeadingEdge /MediaClass +-] readonly def +-% Define other keys used in media selection. +-/.inputselectionkeys [ +- /MediaPosition /Orientation +-] readonly def +- +-% Define the keys used in output attribute matching. +-/.outputattrkeys [ +- /OutputType +-] readonly def ++% M. Sweet, Easy Software Products: ++% ++% Define NOMEDIAATTRS to turn off the default (but unimplementable) media ++% selection policies for setpagedevice. This is used by CUPS to support ++% the standard Adobe media attributes. ++NOMEDIAATTRS { ++ % Define only PageSize for input attribute matching. ++ /.inputattrkeys [ ++ /PageSize ++ ] readonly def ++ % Define no other keys used in media selection. ++ /.inputselectionkeys [ ++ /noInputSelectionsKeys ++ ] readonly def ++ ++ % Define no keys used in output attribute matching. ++ /.outputattrkeys [ ++ /noOutputAttrKeys ++ ] readonly def ++} { ++ % Define the keys used in input attribute matching. ++ /.inputattrkeys [ ++ /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet ++ % The following are documented in Adobe's supplement for v2017. ++ /LeadingEdge /MediaClass ++ ] readonly def ++ % Define other keys used in media selection. ++ /.inputselectionkeys [ ++ /MediaPosition /Orientation ++ ] readonly def ++ ++ % Define the keys used in output attribute matching. ++ /.outputattrkeys [ ++ /OutputType ++ ] readonly def ++} ifelse + + % Define all the parameters that should always be copied to the merged + % dictionary. +@@ -367,7 +388,13 @@ + /PageSize false % obsolete alias for .MediaSize + /InputAttributes false + .inputattrkeys +- { dup /PageSize eq ++ % M. Sweet, Easy Software Products: ++ % ++ % Treat LeadingEdge like PageSize so that a common Ghostscript driver ++ % doesn't need the NOMEDIAATTRS definition. ++ % ++ % { dup /PageSize eq ++ { dup dup /PageSize eq exch /LeadingEdge eq or + { pop } + { { 2 index /InputAttributes .knownget { null eq } { true } ifelse } } + ifelse +@@ -442,11 +469,22 @@ + % 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. ++% ++% M. Sweet, Easy Software Products: ++% ++% Define NOMEDIAATTRS to turn off the default (but unimplementable) media ++% selection policies for setpagedevice. This is used by CUPS to support ++% the standard Adobe media attributes. + 0 { % Set errorinfo and signal a configurationerror. ++ NOMEDIAATTRS { ++ % NOMEDIAATTRS means that the default policy is 7... ++ pop 2 index exch 7 put ++ } { + pop dup 4 index exch get 2 array astore + $error /errorinfo 3 -1 roll put + cleartomark + /setpagedevice load /configurationerror signalerror ++ } ifelse + } bind + 1 { % Roll back the failed request to its previous status. + DEBUG { (Rolling back.) = pstack flush } if diff --git a/pstoraster/gs811-lib.patch b/pstoraster/gs811-lib.patch new file mode 100644 index 000000000..9cd125305 --- /dev/null +++ b/pstoraster/gs811-lib.patch @@ -0,0 +1,110 @@ +diff -u ghostscript-8.11/lib/gs_init.ps ghostscript-8.11-easysw/lib/gs_init.ps +--- ghostscript-8.11/lib/gs_init.ps 2003-07-30 03:26:55.000000000 -0400 ++++ ghostscript-8.11-easysw/lib/gs_init.ps 2003-11-13 13:04:17.000000000 -0500 +@@ -139,6 +139,7 @@ + currentdict /NOFONTPATH known /NOFONTPATH exch def + currentdict /NOGC known /NOGC exch def + currentdict /NOINTERPOLATE .knownget { /INTERPOLATE exch not def } if ++currentdict /NOMEDIAATTRS known /NOMEDIAATTRS exch def + currentdict /NOOUTERSAVE known /NOOUTERSAVE exch def + currentdict /NOPAGEPROMPT known /NOPAGEPROMPT exch def + currentdict /NOPAUSE known /NOPAUSE exch def +diff -u ghostscript-8.11/lib/gs_setpd.ps ghostscript-8.11-easysw/lib/gs_setpd.ps +--- ghostscript-8.11/lib/gs_setpd.ps 2003-04-12 14:08:18.000000000 -0400 ++++ ghostscript-8.11-easysw/lib/gs_setpd.ps 2003-11-14 16:32:55.000000000 -0500 +@@ -344,21 +344,42 @@ + } bind + .dicttomark readonly def + +-% Define the keys used in input attribute matching. +-/.inputattrkeys [ +- /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet +- % The following are documented in Adobe's supplement for v2017. +- /LeadingEdge /MediaClass +-] readonly def +-% Define other keys used in media selection. +-/.inputselectionkeys [ +- /MediaPosition /Orientation +-] readonly def +- +-% Define the keys used in output attribute matching. +-/.outputattrkeys [ +- /OutputType +-] readonly def ++% M. Sweet, Easy Software Products: ++% ++% Define NOMEDIAATTRS to turn off the default (but unimplementable) media ++% selection policies for setpagedevice. This is used by CUPS to support ++% the standard Adobe media attributes. ++NOMEDIAATTRS { ++ % Define only PageSize for input attribute matching. ++ /.inputattrkeys [ ++ /PageSize ++ ] readonly def ++ % Define no other keys used in media selection. ++ /.inputselectionkeys [ ++ /noInputSelectionsKeys ++ ] readonly def ++ ++ % Define no keys used in output attribute matching. ++ /.outputattrkeys [ ++ /noOutputAttrKeys ++ ] readonly def ++} { ++ % Define the keys used in input attribute matching. ++ /.inputattrkeys [ ++ /PageSize /MediaColor /MediaWeight /MediaType /InsertSheet ++ % The following are documented in Adobe's supplement for v2017. ++ /LeadingEdge /MediaClass ++ ] readonly def ++ % Define other keys used in media selection. ++ /.inputselectionkeys [ ++ /MediaPosition /Orientation ++ ] readonly def ++ ++ % Define the keys used in output attribute matching. ++ /.outputattrkeys [ ++ /OutputType ++ ] readonly def ++} ifelse + + % Define all the parameters that should always be copied to the merged + % dictionary. +@@ -387,7 +408,13 @@ + /PageSize //false % obsolete alias for .MediaSize + /InputAttributes //false + .inputattrkeys +- { dup /PageSize eq ++ % M. Sweet, Easy Software Products: ++ % ++ % Treat LeadingEdge like PageSize so that a common Ghostscript driver ++ % doesn't need the NOMEDIAATTRS definition. ++ % ++ % { dup /PageSize eq ++ { dup dup /PageSize eq exch /LeadingEdge eq or + { pop } + { { 2 index /InputAttributes .knownget { //null eq } { //true } ifelse } } + ifelse +@@ -468,11 +495,22 @@ + % 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. ++% ++% M. Sweet, Easy Software Products: ++% ++% Define NOMEDIAATTRS to turn off the default (but unimplementable) media ++% selection policies for setpagedevice. This is used by CUPS to support ++% the standard Adobe media attributes. + 0 { % Set errorinfo and signal a configurationerror. ++ NOMEDIAATTRS { ++ % NOMEDIAATTRS means that the default policy is 7... ++ pop 2 index exch 7 put ++ } { + pop dup 4 index exch get 2 array astore + $error /errorinfo 3 -1 roll put + cleartomark + /setpagedevice load /configurationerror signalerror ++ } ifelse + } bind + 1 { % Roll back the failed request to its previous status. + SETPDDEBUG { (Rolling back.) = pstack flush } if diff --git a/pstoraster/pstopxl b/pstoraster/pstopxl new file mode 100644 index 000000000..227f5f4cd --- /dev/null +++ b/pstoraster/pstopxl @@ -0,0 +1,67 @@ +#!/bin/sh +# +# "$Id: pstopxl 4076 2004-02-24 21:59:13Z mike $" +# +# CUPS PCL XL/PCL 6 filter script for Ghostscript. +# +# Copyright 2001-2003 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, 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. +# + +# Installation directories... +prefix=/usr/local +exec_prefix=${prefix} +bindir=/usr/lib/cups/filter + +# Set the library/font path... +GS_LIB="${CUPS_FONTPATH:=/usr/share/cups/fonts}" +export GS_LIB + +# Determine the PCL XL/PCL 6 driver to use... +if test "x$PPD" != x; then + colordevice=`grep '^*ColorDevice:' "$PPD" | awk -F: '{print $2}'` + case "$colordevice" in + *True* | *true*) + device="pxlcolor" + ;; + *) + device="pxlmono" + ;; + esac +else + device="pxlmono" +fi + +# Options we use with Ghostscript... +gsopts="-dQUIET -dDEBUG -dPARANOIDSAFER -dNOPAUSE -dBATCH" +gsopts="$gsopts -dNOMEDIAATTRS -sDEVICE=$device -sstdout=%stderr" + +# See if we have a filename on the command-line... +if test -z "$6"; then + ifile="-" +else + ifile="$6" +fi + +echo INFO: Starting ESP Ghostscript 7.07.1... 1>&2 +echo DEBUG: Running $bindir/gsrip $gsopts -sOUTPUTFILE="%stdout" "$ifile" 1>&2 + +# Now run Ghostscript... +$bindir/gsrip $gsopts -sOUTPUTFILE="%stdout" "$ifile" + +# +# End of "$Id: pstopxl 4076 2004-02-24 21:59:13Z mike $". +# diff --git a/pstoraster/pstopxl.in b/pstoraster/pstopxl.in new file mode 100755 index 000000000..c57d15e0c --- /dev/null +++ b/pstoraster/pstopxl.in @@ -0,0 +1,67 @@ +#!/bin/sh +# +# "$Id: pstopxl.in 4493 2005-02-18 02:09:53Z mike $" +# +# CUPS PCL XL/PCL 6 filter script for Ghostscript. +# +# Copyright 2001-2005 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, 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. +# + +# Installation directories... +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ + +# Set the library/font path... +GS_LIB="${CUPS_FONTPATH:=/usr/share/cups/fonts}" +export GS_LIB + +# Determine the PCL XL/PCL 6 driver to use... +if test "x$PPD" != x; then + colordevice=`grep '^*ColorDevice:' "$PPD" | awk -F: '{print $2}'` + case "$colordevice" in + *True* | *true*) + device="pxlcolor" + ;; + *) + device="pxlmono" + ;; + esac +else + device="pxlmono" +fi + +# Options we use with Ghostscript... +gsopts="-dQUIET -dDEBUG -dPARANOIDSAFER -dNOPAUSE -dBATCH" +gsopts="$gsopts -dNOMEDIAATTRS -sDEVICE=$device -sstdout=%stderr" + +# See if we have a filename on the command-line... +if test -z "$6"; then + ifile="-" +else + ifile="$6" +fi + +echo INFO: Starting ESP Ghostscript 7.07.1... 1>&2 +echo DEBUG: Running $bindir/@GS@ $gsopts -sOUTPUTFILE="%stdout" "$ifile" 1>&2 + +# Now run Ghostscript... +$bindir/@GS@ $gsopts -sOUTPUTFILE="%stdout" "$ifile" + +# +# End of "$Id: pstopxl.in 4493 2005-02-18 02:09:53Z mike $". +# diff --git a/pstoraster/pstoraster b/pstoraster/pstoraster new file mode 100755 index 000000000..e5ec266c8 --- /dev/null +++ b/pstoraster/pstoraster @@ -0,0 +1,52 @@ +#!/bin/sh +# +# "$Id: pstoraster 4493 2005-02-18 02:09:53Z mike $" +# +# CUPS filter script for Ghostscript. +# +# Copyright 2001-2005 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, 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. +# + +# Installation directories... +prefix=/usr/local +exec_prefix=${prefix} +bindir=${exec_prefix}/bin + +# Set the library/font path... +GS_FONTPATH="$CUPS_FONTPATH" +export GS_FONTPATH + +# Options we use with Ghostscript... +gsopts="-dQUIET -dDEBUG -dPARANOIDSAFER -dNOPAUSE -dBATCH " +gsopts="$gsopts -dNOMEDIAATTRS -sDEVICE=cups -sstdout=%stderr" + +# See if we have a profile=n,n,n,n,n,n,n,n,n,n,n option... +profile="" +for option in $5; do + case $option in + profile=*) + profile="-scupsProfile=`echo $option | awk -F= '{print $2}'`" + ;; + esac +done + +# Now run Ghostscript... +$bindir/gs $gsopts -sOUTPUTFILE="%stdout" $profile $6 + +# +# End of "$Id: pstoraster 4493 2005-02-18 02:09:53Z mike $". +# diff --git a/pstoraster/pstoraster.convs b/pstoraster/pstoraster.convs new file mode 100644 index 000000000..9e5f0006a --- /dev/null +++ b/pstoraster/pstoraster.convs @@ -0,0 +1,29 @@ +# +# "$Id: pstoraster.convs 4493 2005-02-18 02:09:53Z mike $" +# +# MIME converts file for Ghostscript. +# +# Copyright 1997-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +application/vnd.cups-postscript application/vnd.cups-raster 100 pstoraster + +# +# End of "$Id: pstoraster.convs 4493 2005-02-18 02:09:53Z mike $". +# diff --git a/pstoraster/pstoraster.in b/pstoraster/pstoraster.in new file mode 100755 index 000000000..4019009d6 --- /dev/null +++ b/pstoraster/pstoraster.in @@ -0,0 +1,62 @@ +#!/bin/sh +# +# "$Id: pstoraster.in 4493 2005-02-18 02:09:53Z mike $" +# +# CUPS raster filter script for Ghostscript. +# +# Copyright 2001-2005 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, 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. +# + +# Installation directories... +prefix=@prefix@ +exec_prefix=@exec_prefix@ +bindir=@bindir@ + +# Set the library/font path... +GS_LIB="${CUPS_FONTPATH:=/usr/share/cups/fonts}" +export GS_LIB + +# Options we use with Ghostscript... +gsopts="-dQUIET -dDEBUG -dPARANOIDSAFER -dNOPAUSE -dBATCH" +gsopts="$gsopts -dNOMEDIAATTRS -sDEVICE=cups -sstdout=%stderr" + +# See if we have a profile=n,n,n,n,n,n,n,n,n,n,n option... +profile="" +for option in $5; do + case $option in + profile=*) + profile="<>setpagedevice" + ;; + esac +done + +# See if we have a filename on the command-line... +if test -z "$6"; then + ifile="-" +else + ifile="$6" +fi + +echo INFO: Starting ESP Ghostscript 7.07.1... 1>&2 +echo DEBUG: Running $bindir/@GS@ $gsopts -sOUTPUTFILE="%stdout" -c"$profile" "$ifile" 1>&2 + +# Now run Ghostscript... +$bindir/@GS@ $gsopts -sOUTPUTFILE="%stdout" -c"$profile" "$ifile" + +# +# End of "$Id: pstoraster.in 4493 2005-02-18 02:09:53Z mike $". +# diff --git a/pstoraster/pxlcolor.ppd b/pstoraster/pxlcolor.ppd new file mode 100644 index 000000000..c7d16ecd4 --- /dev/null +++ b/pstoraster/pxlcolor.ppd @@ -0,0 +1,205 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: pxlcolor.ppd 4493 2005-02-18 02:09:53Z mike $" +*% +*% Sample color PCL XL/PCL 6 driver PPD file for the Common UNIX +*% Printing System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.1" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "PCLCOLOR.PPD" +*Manufacturer: "ESP" +*Product: "(CUPS v1.1)" +*cupsVersion: 1.1 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-postscript 0 pstopxl" +*ModelName: "HP Color LaserJet Series PCL 6" +*ShortNickName: "HP Color LaserJet Series PCL 6" +*NickName: "HP Color LaserJet Series PCL 6 CUPS v1.1" +*PSVersion: "(3010.000) 707" +*LanguageLevel: "3" +*ColorDevice: True +*DefaultColorSpace: RGB +*FileSystem: False +*Throughput: "8" +*LandscapeOrientation: Plus90 +*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: "<>setpagedevice" +*PageSize Legal/US Legal: "<>setpagedevice" +*PageSize Executive/US Executive: "<>setpagedevice" +*PageSize Tabloid/US Tabloid: "<>setpagedevice" +*PageSize A3/A3: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/US Letter: "<>setpagedevice" +*PageRegion Legal/US Legal: "<>setpagedevice" +*PageRegion Executive/US Executive: "<>setpagedevice" +*PageRegion Tabloid/US Tabloid: "<>setpagedevice" +*PageRegion A3/A3: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "12 12 600 780" +*ImageableArea Legal/US Legal: "12 12 600 996" +*ImageableArea Executive/US Executive: "12 12 510 708" +*ImageableArea Tabloid/US Tabloid: "12 12 780 1212" +*ImageableArea A3/A3: "12 12 830 1179" +*ImageableArea A4/A4: "12 12 583 830" +*ImageableArea A5/A5: "12 12 409 583" +*ImageableArea B5/JIS B5: "12 12 504 717" +*ImageableArea EnvISOB5/B5 (ISO): "12 12 469 697" +*ImageableArea Env10/Com-10: "12 12 285 672" +*ImageableArea EnvC5/EnvC5: "12 12 447 637" +*ImageableArea EnvDL/EnvDL: "12 12 300 612" +*ImageableArea EnvMonarch/Envelope Monarch: "12 12 267 528" + +*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: "<>setpagedevice" +*InputSlot Tray1/Tray 1: "<>setpagedevice" +*InputSlot Tray2/Tray 2: "<>setpagedevice" +*InputSlot Tray3/Tray 3: "<>setpagedevice" +*InputSlot Tray4/Tray 4: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: RGB +*ColorModel RGB/Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 300dpi +*Resolution 150dpi/150 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *Duplex/Double-Sided Printing: PickOne +*OrderDependency: 20 AnySetup *Duplex +*DefaultDuplex: None +*Duplex None/Off: "<>setpagedevice" +*Duplex DuplexNoTumble/Long Edge (Standard): "<>setpagedevice" +*Duplex DuplexTumble/Short Edge (Flip): "<>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: pxlcolor.ppd 4493 2005-02-18 02:09:53Z mike $". +*% diff --git a/pstoraster/pxlmono.ppd b/pstoraster/pxlmono.ppd new file mode 100644 index 000000000..1870ca0bb --- /dev/null +++ b/pstoraster/pxlmono.ppd @@ -0,0 +1,199 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: pxlmono.ppd 4493 2005-02-18 02:09:53Z mike $" +*% +*% Sample monochrome PCL XL/PCL 6 driver PPD file for the Common UNIX +*% Printing System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*FormatVersion: "4.3" +*FileVersion: "1.1" +*LanguageVersion: English +*LanguageEncoding: ISOLatin1 +*PCFileName: "PCLMONO.PPD" +*Manufacturer: "ESP" +*Product: "(CUPS v1.1)" +*cupsVersion: 1.1 +*cupsManualCopies: False +*cupsFilter: "application/vnd.cups-postscript 0 pstopxl" +*ModelName: "HP LaserJet Series PCL 6" +*ShortNickName: "HP LaserJet Series PCL 6" +*NickName: "HP LaserJet Series PCL 6 CUPS v1.1" +*PSVersion: "(3010.000) 707" +*LanguageLevel: "3" +*ColorDevice: False +*DefaultColorSpace: Gray +*FileSystem: False +*Throughput: "8" +*LandscapeOrientation: Plus90 +*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: "<>setpagedevice" +*PageSize Legal/US Legal: "<>setpagedevice" +*PageSize Executive/US Executive: "<>setpagedevice" +*PageSize Tabloid/US Tabloid: "<>setpagedevice" +*PageSize A3/A3: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/US Letter: "<>setpagedevice" +*PageRegion Legal/US Legal: "<>setpagedevice" +*PageRegion Executive/US Executive: "<>setpagedevice" +*PageRegion Tabloid/US Tabloid: "<>setpagedevice" +*PageRegion A3/A3: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "12 12 600 780" +*ImageableArea Legal/US Legal: "12 12 600 996" +*ImageableArea Executive/US Executive: "12 12 510 708" +*ImageableArea Tabloid/US Tabloid: "12 12 780 1212" +*ImageableArea A3/A3: "12 12 830 1179" +*ImageableArea A4/A4: "12 12 583 830" +*ImageableArea A5/A5: "12 12 409 583" +*ImageableArea B5/JIS B5: "12 12 504 717" +*ImageableArea EnvISOB5/B5 (ISO): "12 12 469 697" +*ImageableArea Env10/Com-10: "12 12 285 672" +*ImageableArea EnvC5/EnvC5: "12 12 447 637" +*ImageableArea EnvDL/EnvDL: "12 12 300 612" +*ImageableArea EnvMonarch/Envelope Monarch: "12 12 267 528" + +*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: "<>setpagedevice" +*InputSlot Tray1/Tray 1: "<>setpagedevice" +*InputSlot Tray2/Tray 2: "<>setpagedevice" +*InputSlot Tray3/Tray 3: "<>setpagedevice" +*InputSlot Tray4/Tray 4: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 600dpi +*Resolution 150dpi/150 DPI: "<>setpagedevice" +*Resolution 300dpi/300 DPI: "<>setpagedevice" +*Resolution 600dpi/600 DPI: "<>setpagedevice" +*Resolution 1200dpi/1200 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *Duplex/Double-Sided Printing: PickOne +*OrderDependency: 20 AnySetup *Duplex +*DefaultDuplex: None +*Duplex None/Off: "<>setpagedevice" +*Duplex DuplexNoTumble/Long Edge (Standard): "<>setpagedevice" +*Duplex DuplexTumble/Short Edge (Flip): "<>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: pxlmono.ppd 4493 2005-02-18 02:09:53Z mike $". +*% diff --git a/scheduler/Dependencies b/scheduler/Dependencies new file mode 100644 index 000000000..0faf79818 --- /dev/null +++ b/scheduler/Dependencies @@ -0,0 +1,176 @@ +# DO NOT DELETE + +auth.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +auth.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +auth.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +auth.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +auth.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +auth.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +auth.o: network.h subscriptions.h +banners.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +banners.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +banners.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +banners.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +banners.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +banners.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +banners.o: network.h subscriptions.h ../cups/dir.h +cert.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +cert.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +cert.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +cert.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +cert.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +cert.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +cert.o: network.h subscriptions.h +classes.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +classes.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +classes.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +classes.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +classes.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +classes.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +classes.o: network.h subscriptions.h +client.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/md5.h +client.o: cupsd.h ../cups/string.h ../cups/array.h ../cups/cups.h +client.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +client.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +client.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +client.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +client.o: network.h subscriptions.h +conf.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +conf.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +conf.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +conf.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +conf.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +conf.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +conf.o: network.h subscriptions.h ../cups/dir.h +dirsvc.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +dirsvc.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +dirsvc.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +dirsvc.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +dirsvc.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +dirsvc.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +dirsvc.o: network.h subscriptions.h +env.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +env.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +env.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +env.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +env.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +env.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +env.o: network.h subscriptions.h +main.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +main.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +main.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +main.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +main.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +main.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +main.o: network.h subscriptions.h +ipp.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +ipp.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +ipp.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +ipp.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +ipp.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +ipp.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +ipp.o: network.h subscriptions.h +listen.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +listen.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +listen.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +listen.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +listen.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +listen.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +listen.o: network.h subscriptions.h +job.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +job.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +job.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +job.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +job.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +job.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +job.o: network.h subscriptions.h ../cups/backend.h ../cups/dir.h +log.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +log.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +log.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +log.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +log.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +log.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +log.o: network.h subscriptions.h +network.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +network.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +network.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +network.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +network.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +network.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +network.o: network.h subscriptions.h +policy.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +policy.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +policy.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +policy.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +policy.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +policy.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +policy.o: network.h subscriptions.h +printers.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +printers.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +printers.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +printers.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +printers.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +printers.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +printers.o: network.h subscriptions.h +process.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +process.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +process.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +process.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +process.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +process.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +process.o: network.h subscriptions.h +quotas.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +quotas.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +quotas.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +quotas.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +quotas.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +quotas.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +quotas.o: network.h subscriptions.h +server.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/md5.h +server.o: cupsd.h ../cups/string.h ../cups/array.h ../cups/cups.h +server.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +server.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +server.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +server.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +server.o: network.h subscriptions.h +statbuf.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +statbuf.o: ../cups/md5.h ../cups/string.h ../cups/array.h ../cups/cups.h +statbuf.o: ../cups/ipp.h ../cups/ppd.h ../cups/file.h mime.h ../cups/ipp.h +statbuf.o: ../cups/file.h ../cups/http.h ../cups/i18n.h ../cups/language.h +statbuf.o: ../cups/array.h ../cups/debug.h statbuf.h cert.h auth.h client.h +statbuf.o: policy.h printers.h classes.h job.h conf.h banners.h dirsvc.h +statbuf.o: network.h subscriptions.h +subscriptions.o: cupsd.h ../cups/http-private.h ../config.h ../cups/http.h +subscriptions.o: ../cups/md5.h ../cups/string.h ../cups/array.h +subscriptions.o: ../cups/cups.h ../cups/ipp.h ../cups/ppd.h ../cups/file.h +subscriptions.o: mime.h ../cups/ipp.h ../cups/file.h ../cups/http.h +subscriptions.o: ../cups/i18n.h ../cups/language.h ../cups/array.h +subscriptions.o: ../cups/debug.h statbuf.h cert.h auth.h client.h policy.h +subscriptions.o: printers.h classes.h job.h conf.h banners.h dirsvc.h +subscriptions.o: network.h subscriptions.h +filter.o: ../cups/debug.h ../cups/string.h ../config.h mime.h ../cups/ipp.h +filter.o: ../cups/file.h +mime.o: ../cups/string.h ../config.h mime.h ../cups/ipp.h ../cups/file.h +type.o: ../cups/string.h ../config.h mime.h ../cups/ipp.h ../cups/file.h +type.o: ../cups/debug.h +cups-deviced.o: util.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +cups-deviced.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/file.h +cups-deviced.o: ../cups/string.h ../config.h ../cups/array.h ../cups/dir.h +cups-driverd.o: util.h ../cups/cups.h ../cups/ipp.h ../cups/http.h +cups-driverd.o: ../cups/md5.h ../cups/ppd.h ../cups/file.h ../cups/file.h +cups-driverd.o: ../cups/string.h ../config.h ../cups/dir.h +cups-lpd.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +cups-lpd.o: ../cups/ppd.h ../cups/file.h ../cups/string.h ../config.h +cups-lpd.o: ../cups/language.h ../cups/array.h +cups-polld.o: ../cups/http-private.h ../config.h ../cups/http.h ../cups/md5.h +cups-polld.o: ../cups/cups.h ../cups/ipp.h ../cups/ppd.h ../cups/file.h +cups-polld.o: ../cups/language.h ../cups/array.h ../cups/string.h +testdirsvc.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +testdirsvc.o: ../cups/ppd.h ../cups/file.h ../cups/string.h ../config.h +testmime.o: ../cups/string.h ../config.h mime.h ../cups/ipp.h ../cups/file.h +testspeed.o: ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +testspeed.o: ../cups/ppd.h ../cups/file.h ../cups/language.h ../cups/array.h +testspeed.o: ../cups/debug.h +util.o: util.h ../cups/cups.h ../cups/ipp.h ../cups/http.h ../cups/md5.h +util.o: ../cups/ppd.h ../cups/file.h ../cups/file.h ../cups/string.h +util.o: ../config.h diff --git a/scheduler/Makefile b/scheduler/Makefile new file mode 100644 index 000000000..ecbe0f96f --- /dev/null +++ b/scheduler/Makefile @@ -0,0 +1,243 @@ +# +# "$Id: Makefile 4801 2005-10-18 21:09:12Z mike $" +# +# Scheduler Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +CUPSDOBJS = \ + auth.o \ + banners.o \ + cert.o \ + classes.o \ + client.o \ + conf.o \ + dirsvc.o \ + env.o \ + main.o \ + ipp.o \ + listen.o \ + job.o \ + log.o \ + network.o \ + policy.o \ + printers.o \ + process.o \ + quotas.o \ + server.o \ + statbuf.o \ + subscriptions.o +MIMEOBJS = \ + filter.o \ + mime.o \ + type.o +OBJS = \ + $(CUPSDOBJS) \ + $(MIMEOBJS) \ + cups-deviced.o \ + cups-driverd.o \ + cups-lpd.o \ + cups-polld.o \ + testdirsvc.o \ + testmime.o \ + testspeed.o \ + util.o +TARGETS = \ + cupsd \ + cups-deviced \ + cups-driverd \ + cups-lpd \ + cups-polld \ + libmime.a \ + testdirsvc \ + testmime \ + testspeed + + +# +# Make everything... +# + +all: $(TARGETS) + + +# +# Clean all object files... +# + +clean: + $(RM) $(OBJS) + $(RM) $(TARGETS) + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1 + + +# +# Install the scheduler... +# + +install: all + echo Creating $(SBINDIR)... + $(INSTALL_DIR) $(SBINDIR) + echo Installing cupsd in $(SBINDIR)... + $(INSTALL_BIN) cupsd $(SBINDIR) + echo Creating $(SERVERBIN)... + $(INSTALL_DIR) $(SERVERBIN) + echo Creating $(SERVERBIN)/daemon... + $(INSTALL_DIR) $(SERVERBIN)/daemon + echo Installing cups-deviced, cups-driverd, cups-lpd, and cups-polld in $(SERVERBIN)/daemon... + $(INSTALL_BIN) cups-deviced $(SERVERBIN)/daemon + $(INSTALL_BIN) cups-driverd $(SERVERBIN)/daemon + $(INSTALL_BIN) cups-lpd $(SERVERBIN)/daemon + $(INSTALL_BIN) cups-polld $(SERVERBIN)/daemon + echo Creating $(SERVERBIN)/driver... + $(INSTALL_DIR) $(SERVERBIN)/driver + echo Creating $(SERVERROOT)... + $(INSTALL_DIR) $(SERVERROOT) + echo Creating $(SERVERROOT)/interfaces... + $(INSTALL_DIR) $(SERVERROOT)/interfaces + echo Creating $(SERVERROOT)/ppd... + $(INSTALL_DIR) $(SERVERROOT)/ppd + echo Creating $(STATEDIR)... + $(INSTALL_DIR) $(STATEDIR) + echo Creating $(STATEDIR)/certs... + $(INSTALL_DIR) $(STATEDIR)/certs + echo Creating $(LOGDIR)... + $(INSTALL_DIR) $(LOGDIR) + echo Creating $(REQUESTS)... + $(INSTALL_DIR) $(REQUESTS) + echo Creating $(REQUESTS)/tmp... + $(INSTALL_DIR) $(REQUESTS)/tmp + echo Creating $(CACHEDIR)... + $(INSTALL_DIR) $(CACHEDIR) + echo Creating $(CACHEDIR)/ppd... + $(INSTALL_DIR) $(CACHEDIR)/ppd + + +# +# 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) \ + $(LIBPAPER) $(LIBMALLOC) + +cupsd-static: $(CUPSDOBJS) libmime.a ../cups/libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o cupsd-static $(CUPSDOBJS) libmime.a \ + $(LIBZ) $(SSLLIBS) $(LIBSLP) $(PAMLIBS) ../cups/libcups.a \ + $(COMMONLIBS) $(LIBZ) $(LIBPAPER) $(LIBMALLOC) + + +# +# Make the device daemon, "cups-deviced". +# + +cups-deviced: cups-deviced.o util.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o cups-deviced cups-deviced.o util.o $(LIBS) + + +# +# Make the driver daemon, "cups-driverd". +# + +cups-driverd: cups-driverd.o util.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o cups-driverd cups-driverd.o util.o $(LIBS) + + +# +# 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) + + +# +# Make the polling daemon, "cups-polld". +# + +cups-polld: cups-polld.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o cups-polld cups-polld.o $(LIBS) + + +# +# libmime.a +# + +libmime.a: $(MIMEOBJS) + echo Archiving $@... + $(RM) $@ + $(AR) $(ARFLAGS) $@ $(MIMEOBJS) + $(RANLIB) $@ + + +# +# Make the test program, "testdirsvc". +# + +testdirsvc: testdirsvc.o + echo Linking $@... + $(CC) $(LDFLAGS) -o testdirsvc testdirsvc.o $(COMMONLIBS) $(NETLIBS) + + +# +# testmime +# + +testmime: testmime.o libmime.a + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ testmime.o libmime.a ../cups/libcups.a \ + $(COMMONLIBS) $(LIBZ) + + +# +# Make the test program, "testspeed". +# + +testspeed: testspeed.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o testspeed testspeed.o $(LIBS) + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4801 2005-10-18 21:09:12Z mike $". +# diff --git a/scheduler/auth.c b/scheduler/auth.c new file mode 100644 index 000000000..405c064a2 --- /dev/null +++ b/scheduler/auth.c @@ -0,0 +1,2116 @@ +;/* + * "$Id: auth.c 4906 2006-01-10 20:53:28Z mike $" + * + * Authorization routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddLocation() - Add a location for authorization. + * cupsdAddName() - Add a name to a location... + * cupsdAllowHost() - Add a host name that is allowed to access the + * location. + * cupsdAllowIP() - Add an IP address or network that is allowed to + * access the location. + * cupsdCheckAuth() - Check authorization masks. + * cupsdCheckGroup() - Check for a user's group membership. + * cupsdCopyLocation() - Make a copy of a location... + * cupsdDeleteAllLocations() - Free all memory used for location authorization. + * cupsdDeleteLocation() - Free all memory used by a location. + * cupsdDenyHost() - Add a host name that is not allowed to access the + * location. + * cupsdDenyIP() - Add an IP address or network that is not allowed + * to access the location. + * cupsdFindBest() - Find the location entry that best matches the + * resource. + * cupsdFindLocation() - Find the named location. + * cupsdGetMD5Passwd() - Get an MD5 password. + * cupsdIsAuthorized() - 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. + * pam_func() - PAM conversation function. + * to64() - Base64-encode an integer value... + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" +#include +#ifdef HAVE_SHADOW_H +# include +#endif /* HAVE_SHADOW_H */ +#ifdef HAVE_CRYPT_H +# include +#endif /* HAVE_CRYPT_H */ +#if HAVE_LIBPAM +# ifdef HAVE_PAM_PAM_APPL_H +# include +# else +# include +# endif /* HAVE_PAM_PAM_APPL_H */ +#endif /* HAVE_LIBPAM */ +#ifdef HAVE_USERSEC_H +# include +#endif /* HAVE_USERSEC_H */ + + +/* + * Local functions... + */ + +static cupsd_authmask_t *add_allow(cupsd_location_t *loc); +static cupsd_authmask_t *add_deny(cupsd_location_t *loc); +#if !HAVE_LIBPAM +static char *cups_crypt(const char *pw, const char *salt); +#endif /* !HAVE_LIBPAM */ +#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 structures... + */ + +#if HAVE_LIBPAM +typedef struct cupsd_authdata_s /**** Authentication data ****/ +{ + char username[33], /* Username string */ + password[33]; /* Password string */ +} cupsd_authdata_t; +#endif /* HAVE_LIBPAM */ + + +/* + * Local globals... + */ + +#if defined(__hpux) && defined(HAVE_LIBPAM) +static cupsd_authdata_t *auth_datat; /* Current client being authenticated */ +#endif /* __hpux && HAVE_LIBPAM */ + + +/* + * 'cupsdAddLocation()' - Add a location for authorization. + */ + +cupsd_location_t * /* O - Pointer to new location record */ +cupsdAddLocation(const char *location) /* I - Location path */ +{ + cupsd_location_t *temp; /* New location */ + + + /* + * Try to allocate memory for the new location. + */ + + if (NumLocations == 0) + temp = malloc(sizeof(cupsd_location_t)); + else + temp = realloc(Locations, sizeof(cupsd_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(cupsd_location_t)); + strlcpy(temp->location, location, sizeof(temp->location)); + temp->length = strlen(temp->location); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAddLocation: added location \'%s\'", + location); + + /* + * Return the new record... + */ + + return (temp); +} + + +/* + * 'cupsdAddName()' - Add a name to a location... + */ + +void +cupsdAddName(cupsd_location_t *loc, /* I - Location to add to */ + char *name) /* I - Name to add */ +{ + char **temp; /* Pointer to names array */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddName(loc=%p, name=\"%s\")", + loc, name); + + if (loc->num_names == 0) + temp = malloc(sizeof(char *)); + else + temp = realloc(loc->names, (loc->num_names + 1) * sizeof(char *)); + + if (temp == NULL) + { + cupsdLogMessage(CUPSD_LOG_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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to duplicate name for location %s: %s", + loc->location, strerror(errno)); + return; + } + + loc->num_names ++; +} + + +/* + * 'cupsdAllowHost()' - Add a host name that is allowed to access the location. + */ + +void +cupsdAllowHost(cupsd_location_t *loc, /* I - Location to add to */ + char *name) /* I - Name of host or domain to add */ +{ + cupsd_authmask_t *temp; /* New host/domain mask */ + char ifname[32], /* Interface name */ + *ifptr; /* Pointer to end of name */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAllowHost(loc=%p(%s), name=\"%s\")", + loc, loc->location, name); + + if ((temp = add_allow(loc)) == NULL) + return; + + if (strcasecmp(name, "@LOCAL") == 0) + { + /* + * Allow *interface*... + */ + + temp->type = AUTH_INTERFACE; + temp->mask.name.name = strdup("*"); + temp->mask.name.length = 1; + } + else if (strncasecmp(name, "@IF(", 4) == 0) + { + /* + * Allow *interface*... + */ + + strlcpy(ifname, name + 4, sizeof(ifname)); + + ifptr = ifname + strlen(ifname); + + if (ifptr[-1] == ')') + { + ifptr --; + *ifptr = '\0'; + } + + temp->type = AUTH_INTERFACE; + temp->mask.name.name = strdup(ifname); + temp->mask.name.length = ifptr - ifname; + } + else + { + /* + * Allow name... + */ + + temp->type = AUTH_NAME; + temp->mask.name.name = strdup(name); + temp->mask.name.length = strlen(name); + } +} + + +/* + * 'cupsdAllowIP()' - Add an IP address or network that is allowed to access + * the location. + */ + +void +cupsdAllowIP(cupsd_location_t *loc, /* I - Location to add to */ + unsigned address[4], /* I - IP address to add */ + unsigned netmask[4]) /* I - Netmask of address */ +{ + cupsd_authmask_t *temp; /* New host/domain mask */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAllowIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", + loc, loc->location, address[0], address[1], address[2], + address[3], netmask[0], netmask[1], netmask[2], + netmask[3]); + + if ((temp = add_allow(loc)) == NULL) + return; + + temp->type = AUTH_IP; + memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address)); + memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask)); +} + + +/* + * 'cupsdAuthorize()' - Validate any authorization credentials. + */ + +void +cupsdAuthorize(cupsd_client_t *con) /* I - Client connection */ +{ + int type; /* Authentication type */ + char *authorization, /* Pointer into Authorization string */ + *ptr, /* Pointer into string */ + username[65], /* Username string */ + password[33]; /* Password string */ + const char *localuser; /* Certificate username */ + char nonce[HTTP_MAX_VALUE], /* Nonce value from client */ + md5[33], /* MD5 password */ + basicmd5[33]; /* MD5 of Basic password */ + static const char * const states[] = /* HTTP client states... */ + { + "WAITING", + "OPTIONS", + "GET", + "GET", + "HEAD", + "POST", + "POST", + "POST", + "PUT", + "PUT", + "DELETE", + "TRACE", + "CLOSE", + "STATUS" + }; + + + /* + * Locate the best matching location so we know what kind of + * authentication to expect... + */ + + con->best = cupsdFindBest(con->uri, con->http.state); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAuthorize: con->uri=\"%s\", con->best=%p(%s)", + con->uri, con->best, con->best ? con->best->location : ""); + + if (con->best && con->best->type != AUTH_NONE) + type = con->best->type; + else + type = DefaultAuthType; + + /* + * Decode the Authorization string... + */ + + authorization = con->http.fields[HTTP_FIELD_AUTHORIZATION]; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAuthorize: Authorization=\"%s\"", + authorization); + + username[0] = '\0'; + password[0] = '\0'; + + if (type == AUTH_NONE) + { + /* + * No authorization required, return early... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdAuthorize: No authentication required."); + return; + } + else if (!*authorization) + { + /* + * No authorization data provided, return early... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdAuthorize: No authentication data provided."); + return; + } + else if (!strncmp(authorization, "Local", 5) && + !strcasecmp(con->http.hostname, "localhost")) + { + /* + * Get Local certificate authentication data... + */ + + authorization += 5; + while (isspace(*authorization)) + authorization ++; + + if ((localuser = cupsdFindCert(authorization)) != NULL) + strlcpy(username, localuser, sizeof(username)); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Local authentication certificate not " + "found!"); + return; + } + } + else if (!strncmp(authorization, "Basic", 5) && + (type == AUTH_BASIC || type == AUTH_BASICDIGEST)) + { + /* + * Get the Basic authentication data... + */ + + int userlen; /* Username:password length */ + + + authorization += 5; + while (isspace(*authorization)) + authorization ++; + + userlen = sizeof(username); + httpDecode64_2(username, &userlen, authorization); + + /* + * Pull the username and password out... + */ + + if ((ptr = strchr(username, ':')) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Missing Basic password!"); + return; + } + + *ptr++ = '\0'; + + if (!username[0]) + { + /* + * Username must not be empty... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Empty Basic username!"); + return; + } + + if (!*ptr) + { + /* + * Password must not be empty... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Empty Basic password!"); + return; + } + + strlcpy(password, ptr, sizeof(password)); + + /* + * Validate the username and password... + */ + + switch (type) + { + case AUTH_BASIC : + { +#if HAVE_LIBPAM + /* + * Only use PAM to do authentication. This supports MD5 + * passwords, among other things... + */ + + pam_handle_t *pamh; /* PAM authentication handle */ + int pamerr; /* PAM error code */ + struct pam_conv pamdata;/* PAM conversation data */ + cupsd_authdata_t data; /* Authentication data */ + + + strlcpy(data.username, username, sizeof(data.username)); + strlcpy(data.password, password, sizeof(data.password)); + + pamdata.conv = pam_func; + pamdata.appdata_ptr = &data; + +# ifdef __hpux + /* + * Workaround for HP-UX bug in pam_unix; see pam_func() below for + * more info... + */ + + auth_data = &data; +# endif /* __hpux */ + + pamerr = pam_start("cups", username, &pamdata, &pamh); + if (pamerr != PAM_SUCCESS) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: pam_start() returned %d (%s)!\n", + pamerr, pam_strerror(pamh, pamerr)); + pam_end(pamh, 0); + return; + } + + pamerr = pam_authenticate(pamh, PAM_SILENT); + if (pamerr != PAM_SUCCESS) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: pam_authenticate() returned %d " + "(%s)!\n", + pamerr, pam_strerror(pamh, pamerr)); + pam_end(pamh, 0); + return; + } + + pamerr = pam_acct_mgmt(pamh, PAM_SILENT); + if (pamerr != PAM_SUCCESS) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: pam_acct_mgmt() returned %d " + "(%s)!\n", + pamerr, pam_strerror(pamh, pamerr)); + pam_end(pamh, 0); + return; + } + + pam_end(pamh, PAM_SUCCESS); + +#elif defined(HAVE_USERSEC_H) + /* + * Use AIX authentication interface... + */ + + char *authmsg; /* Authentication message */ + char *loginmsg; /* Login message */ + int reenter; /* ??? */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdAuthorize: AIX authenticate of username \"%s\"", + username); + + reenter = 1; + if (authenticate(username, password, &reenter, &authmsg) != 0) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdAuthorize: Unable to authenticate username " + "\"%s\": %s", + username, strerror(errno)); + return; + } + +#else + /* + * Use normal UNIX password file-based authentication... + */ + + char *pass; /* Encrypted password */ + struct passwd *pw; /* User password data */ +# ifdef HAVE_SHADOW_H + struct spwd *spw; /* Shadow password data */ +# endif /* HAVE_SHADOW_H */ + + + pw = getpwnam(username); /* Get the current password */ + endpwent(); /* Close the password file */ + + if (!pw) + { + /* + * No such user... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Unknown username \"%s\"!", + username); + return (HTTP_UNAUTHORIZED); + } + +# ifdef HAVE_SHADOW_H + spw = getspnam(username); + endspent(); + + if (!spw && !strcmp(pw->pw_passwd, "x")) + { + /* + * Don't allow blank passwords! + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Username \"%s\" has no shadow " + "password!", username); + return; + } + + if (spw && !spw->sp_pwdp[0] && !pw->pw_passwd[0]) +# else + if (!pw->pw_passwd[0]) +# endif /* HAVE_SHADOW_H */ + { + /* + * Don't allow blank passwords! + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Username \"%s\" has no password!", + username); + return; + } + + /* + * OK, the password isn't blank, so compare with what came from the + * client... + */ + + pass = cups_crypt(password, pw->pw_passwd); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAuthorize: pw_passwd=\"%s\", crypt=\"%s\"", + pw->pw_passwd, pass); + + if (!pass || strcmp(pw->pw_passwd, pass)) + { +# ifdef HAVE_SHADOW_H + if (spw) + { + pass = cups_crypt(password, spw->sp_pwdp); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAuthorize: sp_pwdp=\"%s\", crypt=\"%s\"", + spw->sp_pwdp, pass); + + if (pass == NULL || strcmp(spw->sp_pwdp, pass)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Authentication failed for " + "user \"%s\"!", + username); + return; + } + } + else +# endif /* HAVE_SHADOW_H */ + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Authentication failed for " + "user \"%s\"!", + username); + return; + } + } +#endif /* HAVE_LIBPAM */ + } + break; + + case AUTH_BASICDIGEST : + /* + * Do Basic authentication with the Digest password file... + */ + + if (!cupsdGetMD5Passwd(username, NULL, md5)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Unknown MD5 username \"%s\"!", + username); + return; + } + + httpMD5(username, "CUPS", password, basicmd5); + + if (strcmp(md5, basicmd5)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Authentication failed for \"%s\"!", + username); + return; + } + break; + } + } + else if (!strncmp(authorization, "Digest", 6) && type == AUTH_DIGEST) + { + /* + * Get the username, password, and nonce from the Digest attributes... + */ + + if (!httpGetSubField2(&(con->http), HTTP_FIELD_AUTHORIZATION, "username", + username, sizeof(username)) || !username[0]) + { + /* + * Username must not be empty... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Empty or missing Digest username!"); + return; + } + + if (!httpGetSubField2(&(con->http), HTTP_FIELD_AUTHORIZATION, "response", + password, sizeof(password)) || !password[0]) + { + /* + * Password must not be empty... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Empty or missing Digest password!"); + return; + } + + if (!httpGetSubField(&(con->http), HTTP_FIELD_AUTHORIZATION, "nonce", + nonce)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: No nonce value for Digest " + "authentication!"); + return; + } + + if (strcmp(con->http.hostname, nonce)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Bad nonce value, expected \"%s\", " + "got \"%s\"!", con->http.hostname, nonce); + return; + } + + /* + * Validate the username and password... + */ + + if (!cupsdGetMD5Passwd(username, NULL, md5)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Unknown MD5 username \"%s\"!", + username); + return; + } + + httpMD5Final(nonce, states[con->http.state], con->uri, md5); + + if (strcmp(md5, password)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAuthorize: Authentication failed for \"%s\"!", + username); + return; + } + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdAuthorize: Bad authentication data."); + return; + } + + /* + * If we get here, then we were able to validate the username and + * password - copy the validated username and password to the client + * data and return... + */ + + strlcpy(con->username, username, sizeof(con->username)); + strlcpy(con->password, password, sizeof(con->password)); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAuthorize: username=\"%s\"", + con->username); +} + + +/* + * 'cupsdCheckAuth()' - Check authorization masks. + */ + +int /* O - 1 if mask matches, 0 otherwise */ +cupsdCheckAuth( + unsigned ip[4], /* I - Client address */ + char *name, /* I - Client hostname */ + int name_len, /* I - Length of hostname */ + int num_masks, /* I - Number of masks */ + cupsd_authmask_t *masks) /* I - Masks */ +{ + int i; /* Looping var */ + cupsd_netif_t *iface; /* Network interface */ + unsigned netip4; /* IPv4 network address */ +#ifdef AF_INET6 + unsigned netip6[4]; /* IPv6 network address */ +#endif /* AF_INET6 */ + + while (num_masks > 0) + { + switch (masks->type) + { + case AUTH_INTERFACE : + /* + * Check for a match with a network interface... + */ + + netip4 = htonl(ip[3]); + +#ifdef AF_INET6 + netip6[0] = htonl(ip[0]); + netip6[1] = htonl(ip[1]); + netip6[2] = htonl(ip[2]); + netip6[3] = htonl(ip[3]); +#endif /* AF_INET6 */ + + if (!strcmp(masks->mask.name.name, "*")) + { + /* + * Check against all local interfaces... + */ + + cupsdNetIFUpdate(); + + for (iface = NetIFList; iface != NULL; iface = iface->next) + { + /* + * Only check local interfaces... + */ + + if (!iface->is_local) + continue; + + if (iface->address.addr.sa_family == AF_INET) + { + /* + * Check IPv4 address... + */ + + if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) == + (iface->address.ipv4.sin_addr.s_addr & + iface->mask.ipv4.sin_addr.s_addr)) + return (1); + } +#ifdef AF_INET6 + else + { + /* + * Check IPv6 address... + */ + + for (i = 0; i < 4; i ++) + if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) != + (iface->address.ipv6.sin6_addr.s6_addr32[i] & + iface->mask.ipv6.sin6_addr.s6_addr32[i])) + break; + + if (i == 4) + return (1); + } +#endif /* AF_INET6 */ + } + } + else + { + /* + * Check the named interface... + */ + + for (iface = cupsdNetIFFind(masks->mask.name.name); + iface && !strcasecmp(masks->mask.name.name, iface->name); + iface = iface->next) + { + if (iface->address.addr.sa_family == AF_INET) + { + /* + * Check IPv4 address... + */ + + if ((netip4 & iface->mask.ipv4.sin_addr.s_addr) == + (iface->address.ipv4.sin_addr.s_addr & + iface->mask.ipv4.sin_addr.s_addr)) + return (1); + } +#ifdef AF_INET6 + else + { + /* + * Check IPv6 address... + */ + + for (i = 0; i < 4; i ++) + if ((netip6[i] & iface->mask.ipv6.sin6_addr.s6_addr32[i]) != + (iface->address.ipv6.sin6_addr.s6_addr32[i] & + iface->mask.ipv6.sin6_addr.s6_addr32[i])) + break; + + if (i == 4) + return (1); + } +#endif /* AF_INET6 */ + } + } + break; + + case AUTH_NAME : + /* + * Check for exact name match... + */ + + if (!strcasecmp(name, masks->mask.name.name)) + 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... + */ + + for (i = 0; i < 4; i ++) + if ((ip[i] & masks->mask.ip.netmask[i]) != + masks->mask.ip.address[i]) + break; + + if (i == 4) + return (1); + break; + } + + masks ++; + num_masks --; + } + + return (0); +} + + +/* + * 'cupsdCheckGroup()' - Check for a user's group membership. + */ + +int /* O - 1 if user is a member, 0 otherwise */ +cupsdCheckGroup( + const char *username, /* I - User name */ + struct passwd *user, /* I - System user info */ + const char *groupname) /* I - Group name */ +{ + int i; /* Looping var */ + struct group *group; /* System group info */ + char junk[33]; /* MD5 password (not used) */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCheckGroup(username=\"%s\", user=%p, groupname=\"%s\")", + username, user, groupname); + + /* + * Validate input... + */ + + if (!username || !groupname) + return (0); + + /* + * Check to see if the user is a member of the named group... + */ + + group = getgrnam(groupname); + endgrent(); + + if (group != NULL) + { + /* + * Group exists, check it... + */ + + for (i = 0; group->gr_mem[i]; i ++) + if (!strcasecmp(username, group->gr_mem[i])) + return (1); + } + + /* + * Group doesn't exist or user not in group list, check the group ID + * against the user's group ID... + */ + + if (user && group && group->gr_gid == user->pw_gid) + return (1); + + /* + * Username not found, group not found, or user is not part of the + * system group... Check for a user and group in the MD5 password + * file... + */ + + if (cupsdGetMD5Passwd(username, groupname, junk) != NULL) + return (1); + + /* + * If we get this far, then the user isn't part of the named group... + */ + + return (0); +} + + +/* + * 'cupsdCopyLocation()' - Make a copy of a location... + */ + +cupsd_location_t * /* O - New location */ +cupsdCopyLocation( + cupsd_location_t **loc) /* IO - Original location */ +{ + int i; /* Looping var */ + int locindex; /* Index into Locations array */ + cupsd_location_t *temp; /* New location */ + char location[HTTP_MAX_URI]; + /* Location of resource */ + + + /* + * Add the new location, updating the original location + * pointer as needed... + */ + + locindex = *loc - Locations; + + /* + * Use a local copy of location because cupsdAddLocation may cause + * this memory to be moved... + */ + + strlcpy(location, (*loc)->location, sizeof(location)); + + if ((temp = cupsdAddLocation(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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdCopyLocation: 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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdCopyLocation: 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(cupsd_authmask_t))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdCopyLocation: 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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdCopyLocation: 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(cupsd_ipmask_t)); + break; + } + } + + if ((temp->num_deny = (*loc)->num_deny) > 0) + { + /* + * Copy deny rules... + */ + + if ((temp->deny = calloc(temp->num_deny, sizeof(cupsd_authmask_t))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdCopyLocation: 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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdCopyLocation: 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(cupsd_ipmask_t)); + break; + } + } + + return (temp); +} + + +/* + * 'cupsdDeleteAllLocations()' - Free all memory used for location authorization. + */ + +void +cupsdDeleteAllLocations(void) +{ + int i; /* Looping var */ + cupsd_location_t *loc; /* Current location */ + + + /* + * Free all of the allow/deny records first... + */ + + for (i = NumLocations, loc = Locations; i > 0; i --, loc ++) + cupsdDeleteLocation(loc); + + /* + * Then free the location array... + */ + + if (NumLocations > 0) + free(Locations); + + Locations = NULL; + NumLocations = 0; +} + + +/* + * 'cupsdDeleteLocation()' - Free all memory used by a location. + */ + +void +cupsdDeleteLocation( + cupsd_location_t *loc) /* I - Location to delete */ +{ + int i; /* Looping var */ + cupsd_authmask_t *mask; /* Current mask */ + + + for (i = loc->num_names - 1; i >= 0; i --) + free(loc->names[i]); + + if (loc->num_names > 0) + free(loc->names); + + for (i = loc->num_allow, mask = loc->allow; i > 0; i --, mask ++) + if (mask->type == AUTH_NAME || mask->type == AUTH_INTERFACE) + free(mask->mask.name.name); + + if (loc->num_allow > 0) + free(loc->allow); + + for (i = loc->num_deny, mask = loc->deny; i > 0; i --, mask ++) + if (mask->type == AUTH_NAME || mask->type == AUTH_INTERFACE) + free(mask->mask.name.name); + + if (loc->num_deny > 0) + free(loc->deny); +} + + +/* + * 'cupsdDenyHost()' - Add a host name that is not allowed to access the + * location. + */ + +void +cupsdDenyHost(cupsd_location_t *loc, /* I - Location to add to */ + char *name) /* I - Name of host or domain to add */ +{ + cupsd_authmask_t *temp; /* New host/domain mask */ + char ifname[32], /* Interface name */ + *ifptr; /* Pointer to end of name */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDenyHost(loc=%p(%s), name=\"%s\")", + loc, loc->location, name); + + if ((temp = add_deny(loc)) == NULL) + return; + + if (strcasecmp(name, "@LOCAL") == 0) + { + /* + * Deny *interface*... + */ + + temp->type = AUTH_INTERFACE; + temp->mask.name.name = strdup("*"); + temp->mask.name.length = 1; + } + else if (strncasecmp(name, "@IF(", 4) == 0) + { + /* + * Deny *interface*... + */ + + strlcpy(ifname, name + 4, sizeof(ifname)); + + ifptr = ifname + strlen(ifname); + + if (ifptr[-1] == ')') + { + ifptr --; + *ifptr = '\0'; + } + + temp->type = AUTH_INTERFACE; + temp->mask.name.name = strdup(ifname); + temp->mask.name.length = ifptr - ifname; + } + else + { + /* + * Deny name... + */ + + temp->type = AUTH_NAME; + temp->mask.name.name = strdup(name); + temp->mask.name.length = strlen(name); + } +} + + +/* + * 'cupsdDenyIP()' - Add an IP address or network that is not allowed to + * access the location. + */ + +void +cupsdDenyIP(cupsd_location_t *loc, /* I - Location to add to */ + unsigned address[4],/* I - IP address to add */ + unsigned netmask[4])/* I - Netmask of address */ +{ + cupsd_authmask_t *temp; /* New host/domain mask */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdDenyIP(loc=%p(%s), address=%x:%x:%x:%x, netmask=%x:%x:%x:%x)", + loc, loc->location, address[0], address[1], address[2], + address[3], netmask[0], netmask[1], netmask[2], + netmask[3]); + + if ((temp = add_deny(loc)) == NULL) + return; + + temp->type = AUTH_IP; + memcpy(temp->mask.ip.address, address, sizeof(temp->mask.ip.address)); + memcpy(temp->mask.ip.netmask, netmask, sizeof(temp->mask.ip.netmask)); +} + + +/* + * 'cupsdFindBest()' - Find the location entry that best matches the resource. + */ + +cupsd_location_t * /* O - Location that matches */ +cupsdFindBest(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 */ + cupsd_location_t *loc, /* Current location */ + *best; /* Best match for location so far */ + int bestlen; /* Length of best match */ + int limit; /* Limit field */ + static const 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... + */ + + strlcpy(uri, path, sizeof(uri)); + + if (!strncmp(uri, "/printers/", 10) || + !strncmp(uri, "/classes/", 9)) + { + /* + * Check if the URI has .ppd on the end... + */ + + uriptr = uri + strlen(uri) - 4; /* len > 4 if we get here... */ + + if (!strcmp(uriptr, ".ppd")) + *uriptr = '\0'; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: 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 ++) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: Location %s Limit %x", + loc->location, loc->limit); + + if (!strncmp(uri, "/printers/", 10) || !strncmp(uri, "/classes/", 9)) + { + /* + * Use case-insensitive comparison for queue names... + */ + + if (loc->length > bestlen && + strncasecmp(uri, loc->location, loc->length) == 0 && + loc->location[0] == '/' && + (limit & loc->limit) != 0) + { + best = loc; + bestlen = loc->length; + } + } + else + { + /* + * Use case-sensitive comparison for other URIs... + */ + + if (loc->length > bestlen && + !strncmp(uri, loc->location, loc->length) && + loc->location[0] == '/' && + (limit & loc->limit) != 0) + { + best = loc; + bestlen = loc->length; + } + } + } + + /* + * Return the match, if any... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindBest: best = %s", + best ? best->location : "NONE"); + + return (best); +} + + +/* + * 'cupsdFindLocation()' - Find the named location. + */ + +cupsd_location_t * /* O - Location that matches */ +cupsdFindLocation(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)) + return (Locations + i); + + return (NULL); +} + + +/* + * 'cupsdGetMD5Passwd()' - Get an MD5 password. + */ + +char * /* O - MD5 password string */ +cupsdGetMD5Passwd(const char *username, /* I - Username */ + const char *group, /* I - Group */ + char passwd[33])/* O - MD5 password string */ +{ + cups_file_t *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 */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdGetMD5Passwd(username=\"%s\", group=\"%s\", passwd=%p)", + username, group ? group : "(null)", passwd); + + snprintf(filename, sizeof(filename), "%s/passwd.md5", ServerRoot); + if ((fp = cupsFileOpen(filename, "r")) == NULL) + { + if (errno != ENOENT) + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open %s - %s", filename, + strerror(errno)); + + return (NULL); + } + + while (cupsFileGets(fp, line, sizeof(line)) != NULL) + { + if (sscanf(line, "%32[^:]:%32[^:]:%32s", tempuser, tempgroup, passwd) != 3) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad MD5 password line: %s", line); + continue; + } + + if (strcmp(username, tempuser) == 0 && + (group == NULL || strcmp(group, tempgroup) == 0)) + { + /* + * Found the password entry! + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "Found MD5 user %s, group %s...", + username, tempgroup); + + cupsFileClose(fp); + return (passwd); + } + } + + /* + * Didn't find a password entry - return NULL! + */ + + cupsFileClose(fp); + return (NULL); +} + + +/* + * 'cupsdIsAuthorized()' - Check to see if the user is authorized... + */ + +http_status_t /* O - HTTP_OK if authorized or error code */ +cupsdIsAuthorized(cupsd_client_t *con, /* I - Connection */ + const char *owner)/* I - Owner of object */ +{ + int i, j, /* Looping vars */ + auth; /* Authorization status */ + unsigned address[4]; /* Authorization address */ + cupsd_location_t *best; /* Best match for location so far */ + int hostlen; /* Length of hostname */ + struct passwd *pw; /* User password data */ + static const char * const levels[] = /* Auth levels */ + { + "ANON", + "USER", + "GROUP" + }; + static const char * const types[] = /* Auth types */ + { + "NONE", + "BASIC", + "DIGEST", + "BASICDIGEST" + }; + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsAuthorized: con->uri=\"%s\", con->best=%p(%s)", + con->uri, con->best, con->best ? con->best->location : ""); + + /* + * If there is no "best" authentication rule for this request, then + * access is allowed from the local system and denied from other + * addresses... + */ + + if (!con->best) + { + if (!strcmp(con->http.hostname, "localhost") || + !strcmp(con->http.hostname, ServerName)) + return (HTTP_OK); + else + return (HTTP_FORBIDDEN); + } + + best = con->best; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsAuthorized: level=AUTH_%s, type=AUTH_%s, satisfy=AUTH_SATISFY_%s, num_names=%d", + levels[best->level], types[best->type], + best->satisfy ? "ANY" : "ALL", best->num_names); + + if (best->limit == AUTH_LIMIT_IPP) + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: op=%x(%s)", + best->op, ippOpString(best->op)); + + /* + * Check host/ip-based accesses... + */ + +#ifdef AF_INET6 + if (con->http.hostaddr->addr.sa_family == AF_INET6) + { + /* + * Copy IPv6 address... + */ + + address[0] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0]); + address[1] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1]); + address[2] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]); + address[3] = ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[3]); + } + else +#endif /* AF_INET6 */ + if (con->http.hostaddr->addr.sa_family == AF_INET) + { + /* + * Copy IPv4 address... + */ + + address[0] = 0; + address[1] = 0; + address[2] = 0; + address[3] = ntohl(con->http.hostaddr->ipv4.sin_addr.s_addr); + } + else + memset(address, 0, sizeof(address)); + + hostlen = strlen(con->http.hostname); + + if (!strcasecmp(con->http.hostname, "localhost")) + { + /* + * Access from localhost (127.0.0.1 or :::1) is always allowed... + */ + + 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 (cupsdCheckAuth(address, con->http.hostname, hostlen, + best->num_deny, best->deny)) + auth = AUTH_DENY; + + if (cupsdCheckAuth(address, con->http.hostname, hostlen, + best->num_allow, best->allow)) + auth = AUTH_ALLOW; + break; + + case AUTH_DENY : /* Order Allow,Deny */ + auth = AUTH_DENY; + + if (cupsdCheckAuth(address, con->http.hostname, hostlen, + best->num_allow, best->allow)) + auth = AUTH_ALLOW; + + if (cupsdCheckAuth(address, con->http.hostname, hostlen, + best->num_deny, best->deny)) + auth = AUTH_DENY; + break; + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: auth=AUTH_%s...", + auth ? "DENY" : "ALLOW"); + + if (auth == AUTH_DENY && best->satisfy == AUTH_SATISFY_ALL) + return (HTTP_FORBIDDEN); + +#ifdef HAVE_SSL + /* + * See if encryption is required... + */ + + if (best->encryption >= HTTP_ENCRYPT_REQUIRED && !con->http.tls) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsAuthorized: Need upgrade to TLS..."); + return (HTTP_UPGRADE_REQUIRED); + } +#endif /* HAVE_SSL */ + + /* + * Now see what access level is required... + */ + + if (best->level == AUTH_ANON || /* Anonymous access - allow it */ + (best->type == AUTH_NONE && best->num_names == 0)) + return (HTTP_OK); + + if (best->type == AUTH_NONE && best->limit == AUTH_LIMIT_IPP) + { + /* + * Check for unauthenticated username... + */ + + ipp_attribute_t *attr; /* requesting-user-name attribute */ + + + attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME); + if (attr) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsAuthorized: requesting-user-name=\"%s\"", + attr->values[0].string.text); + return (HTTP_OK); + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsAuthorized: username=\"%s\"", + con->username); + + if (!con->username[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 */ + } + + /* + * OK, the password is good. See if we need normal user access, or group + * access... (root always matches) + */ + + if (!strcmp(con->username, "root")) + return (HTTP_OK); + + /* + * Get the user info... + */ + + pw = getpwnam(con->username); + endpwent(); + + if (best->level == AUTH_USER) + { + /* + * If there are no names associated with this location, then + * any valid user is OK... + */ + + if (best->num_names == 0) + return (HTTP_OK); + + /* + * Otherwise check the user list and return OK if this user is + * allowed... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsAuthorized: Checking user membership..."); + + for (i = 0; i < best->num_names; i ++) + { + if (!strcasecmp(best->names[i], "@OWNER") && owner && + !strcasecmp(con->username, owner)) + return (HTTP_OK); + else if (!strcasecmp(best->names[i], "@SYSTEM")) + { + for (j = 0; j < NumSystemGroups; j ++) + if (cupsdCheckGroup(con->username, pw, SystemGroups[j])) + return (HTTP_OK); + } + else if (best->names[i][0] == '@') + { + if (cupsdCheckGroup(con->username, pw, best->names[i] + 1)) + return (HTTP_OK); + } + else if (!strcasecmp(con->username, best->names[i])) + return (HTTP_OK); + } + + return (HTTP_UNAUTHORIZED); + } + + /* + * Check to see if this user is in any of the named groups... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsAuthorized: Checking group membership..."); + + /* + * Check to see if this user is in any of the named groups... + */ + + for (i = 0; i < best->num_names; i ++) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsAuthorized: Checking group \"%s\" membership...", + best->names[i]); + + if (!strcasecmp(best->names[i], "@SYSTEM")) + { + for (j = 0; j < NumSystemGroups; j ++) + if (cupsdCheckGroup(con->username, pw, SystemGroups[j])) + return (HTTP_OK); + } + else if (cupsdCheckGroup(con->username, pw, best->names[i])) + return (HTTP_OK); + } + + /* + * The user isn't part of the specified group, so deny access... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsAuthorized: User not in group(s)!"); + + return (HTTP_UNAUTHORIZED); +} + + +/* + * 'add_allow()' - Add an allow mask to the location. + */ + +static cupsd_authmask_t * /* O - New mask record */ +add_allow(cupsd_location_t *loc) /* I - Location to add to */ +{ + cupsd_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(cupsd_authmask_t)); + else + temp = realloc(loc->allow, sizeof(cupsd_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(cupsd_authmask_t)); + return (temp); +} + + +/* + * 'add_deny()' - Add a deny mask to the location. + */ + +static cupsd_authmask_t * /* O - New mask record */ +add_deny(cupsd_location_t *loc) /* I - Location to add to */ +{ + cupsd_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(cupsd_authmask_t)); + else + temp = realloc(loc->deny, sizeof(cupsd_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(cupsd_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 */ + _cups_md5_state_t state; /* Primary MD5 state info */ + _cups_md5_state_t state2; /* Secondary MD5 state info */ + unsigned char 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); + + _cups_md5_init(&state); + _cups_md5_append(&state, (unsigned char *)pw, pwlen); + _cups_md5_append(&state, (unsigned char *)salt, salt_end - salt); + + _cups_md5_init(&state2); + _cups_md5_append(&state2, (unsigned char *)pw, pwlen); + _cups_md5_append(&state2, (unsigned char *)salt + 3, salt_end - salt - 3); + _cups_md5_append(&state2, (unsigned char *)pw, pwlen); + _cups_md5_finish(&state2, digest); + + for (i = pwlen; i > 0; i -= 16) + _cups_md5_append(&state, digest, i > 16 ? 16 : i); + + for (i = pwlen; i > 0; i >>= 1) + _cups_md5_append(&state, (unsigned char *)((i & 1) ? "" : pw), 1); + + _cups_md5_finish(&state, digest); + + for (i = 0; i < 1000; i ++) + { + _cups_md5_init(&state); + + if (i & 1) + _cups_md5_append(&state, (unsigned char *)pw, pwlen); + else + _cups_md5_append(&state, digest, 16); + + if (i % 3) + _cups_md5_append(&state, (unsigned char *)salt + 3, salt_end - salt - 3); + + if (i % 7) + _cups_md5_append(&state, (unsigned char *)pw, pwlen); + + if (i & 1) + _cups_md5_append(&state, digest, 16); + else + _cups_md5_append(&state, (unsigned char *)pw, pwlen); + + _cups_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 */ + + +#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 */ + cupsd_authdata_t *data; /* Pointer to auth data */ + + + /* + * 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... + */ + + data = auth_data; + (void)appdata_ptr; +#else + data = (cupsd_authdata_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", + data->username)); + replies[i].resp_retcode = PAM_SUCCESS; + replies[i].resp = strdup(data->username); + break; + + case PAM_PROMPT_ECHO_OFF: + DEBUG_printf(("pam_func: PAM_PROMPT_ECHO_OFF, returning \"%s\"...\n", + data->password)); + replies[i].resp_retcode = PAM_SUCCESS; + replies[i].resp = strdup(data->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: auth.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/scheduler/auth.h b/scheduler/auth.h new file mode 100644 index 000000000..f78b587e5 --- /dev/null +++ b/scheduler/auth.h @@ -0,0 +1,163 @@ +/* + * "$Id: auth.h 4812 2005-10-25 18:23:10Z mike $" + * + * Authorization definitions for the Common UNIX Printing System (CUPS) + * scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Include necessary headers... + */ + +#include + + +/* + * 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_INTERFACE 2 /* Authorize host by interface */ + +#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 */ +#define AUTH_LIMIT_IPP 128 /* Limit IPP requests */ + +#define IPP_ANY_OPERATION (ipp_op_t)0 + /* Any IPP operation */ +#define IPP_BAD_OPERATION (ipp_op_t)-1 + /* No IPP operation */ + + +/* + * HTTP access control structures... + */ + +typedef struct +{ + unsigned address[4], /* IP address */ + netmask[4]; /* IP netmask */ +} cupsd_ipmask_t; + +typedef struct +{ + int length; /* Length of name */ + char *name; /* Name string */ +} cupsd_namemask_t; + +typedef struct +{ + int type; /* Mask type */ + union + { + cupsd_namemask_t name; /* Host/Domain name */ + cupsd_ipmask_t ip; /* IP address/network */ + } mask; /* Mask data */ +} cupsd_authmask_t; + +typedef struct +{ + char location[HTTP_MAX_URI]; + /* Location of resource */ + ipp_op_t op; /* IPP operation */ + 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 */ + cupsd_authmask_t *allow; /* Allow lines */ + int num_deny; /* Number of Deny lines */ + cupsd_authmask_t *deny; /* Deny lines */ + http_encryption_t encryption; /* To encrypt or not to encrypt... */ +} cupsd_location_t; + +typedef struct cupsd_client_s cupsd_client_t; + + +/* + * Globals... + */ + +VAR int NumLocations VALUE(0); + /* Number of authorization locations */ +VAR cupsd_location_t *Locations VALUE(NULL); + /* Authorization locations */ +VAR int DefaultAuthType VALUE(AUTH_BASIC); + /* Default AuthType, if not specified */ + + +/* + * Prototypes... + */ + +extern cupsd_location_t *cupsdAddLocation(const char *location); +extern void cupsdAddName(cupsd_location_t *loc, char *name); +extern void cupsdAllowHost(cupsd_location_t *loc, char *name); +extern void cupsdAllowIP(cupsd_location_t *loc, unsigned address[4], + unsigned netmask[4]); +extern void cupsdAuthorize(cupsd_client_t *con); +extern int cupsdCheckAuth(unsigned ip[4], char *name, int namelen, + int num_masks, cupsd_authmask_t *masks); +extern int cupsdCheckGroup(const char *username, + struct passwd *user, + const char *groupname); +extern cupsd_location_t *cupsdCopyLocation(cupsd_location_t **loc); +extern void cupsdDeleteAllLocations(void); +extern void cupsdDeleteLocation(cupsd_location_t *loc); +extern void cupsdDenyHost(cupsd_location_t *loc, char *name); +extern void cupsdDenyIP(cupsd_location_t *loc, unsigned address[4], + unsigned netmask[4]); +extern cupsd_location_t *cupsdFindBest(const char *path, http_state_t state); +extern cupsd_location_t *cupsdFindLocation(const char *location); +extern char *cupsdGetMD5Passwd(const char *username, const char *group, + char passwd[33]); +extern http_status_t cupsdIsAuthorized(cupsd_client_t *con, const char *owner); + + +/* + * End of "$Id: auth.h 4812 2005-10-25 18:23:10Z mike $". + */ diff --git a/scheduler/banners.c b/scheduler/banners.c new file mode 100644 index 000000000..98c3364ea --- /dev/null +++ b/scheduler/banners.c @@ -0,0 +1,210 @@ +/* + * "$Id: banners.c 4719 2005-09-28 21:12:44Z mike $" + * + * Banner routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddBanner() - Add a banner to the array. + * cupsdFindBanner() - Find a named banner. + * cupsdLoadBanners() - Load all available banner files... + * compare() - Compare two banners. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" +#include + + +/* + * Local functions... + */ + +static int compare(const cupsd_banner_t *b0, const cupsd_banner_t *b1); + + +/* + * 'cupsdAddBanner()' - Add a banner to the array. + */ + +void +cupsdAddBanner(const char *name, /* I - Name of banner */ + const char *filename) /* I - Filename for banner */ +{ + mime_type_t *filetype; /* Filetype */ + cupsd_banner_t *temp; /* New banner data */ + + + /* + * See what the filetype is... + */ + + if ((filetype = mimeFileType(MimeDatabase, filename, NULL)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "cupsdAddBanner: Banner \"%s\" (\"%s\") is of an unknown file type - skipping!", + name, filename); + return; + } + + /* + * Allocate memory... + */ + + if (NumBanners == 0) + temp = malloc(sizeof(cupsd_banner_t)); + else + temp = realloc(Banners, sizeof(cupsd_banner_t) * (NumBanners + 1)); + + if (temp == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAddBanner: Ran out of memory adding a banner!"); + return; + } + + /* + * Copy the new banner data over... + */ + + Banners = temp; + temp += NumBanners; + NumBanners ++; + + memset(temp, 0, sizeof(cupsd_banner_t)); + strlcpy(temp->name, name, sizeof(temp->name)); + temp->filetype = filetype; +} + + +/* + * 'cupsdFindBanner()' - Find a named banner. + */ + +cupsd_banner_t * /* O - Pointer to banner or NULL */ +cupsdFindBanner(const char *name) /* I - Name of banner */ +{ + cupsd_banner_t key; /* Search key */ + + + strlcpy(key.name, name, sizeof(key.name)); + + return ((cupsd_banner_t *)bsearch(&key, Banners, NumBanners, sizeof(cupsd_banner_t), + (int (*)(const void *, const void *))compare)); +} + + +/* + * 'cupsdLoadBanners()' - Load all available banner files... + */ + +void +cupsdLoadBanners(const char *d) /* I - Directory to search */ +{ + cups_dir_t *dir; /* Directory pointer */ + cups_dentry_t *dent; /* Directory entry */ + char filename[1024], /* Name of banner */ + *ext; /* Pointer to extension */ + + + /* + * Free old banner info... + */ + + if (NumBanners) + { + free(Banners); + NumBanners = 0; + } + + /* + * Try opening the banner directory... + */ + + if ((dir = cupsDirOpen(d)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdLoadBanners: Unable to open banner directory \"%s\": %s", + d, strerror(errno)); + return; + } + + /* + * Read entries, skipping directories and backup files. + */ + + while ((dent = cupsDirRead(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->filename); + + if (S_ISDIR(dent->fileinfo.st_mode)) + continue; + + if (dent->filename[0] == '~') + continue; + + if ((ext = strrchr(dent->filename, '.')) != NULL) + if (!strcmp(ext, ".bck") || + !strcmp(ext, ".bak") || + !strcmp(ext, ".sav")) + continue; + + /* + * Must be a valid file; add it! + */ + + cupsdAddBanner(dent->filename, filename); + } + + /* + * Close the directory and sort as needed... + */ + + cupsDirClose(dir); + + if (NumBanners > 1) + qsort(Banners, NumBanners, sizeof(cupsd_banner_t), + (int (*)(const void *, const void *))compare); +} + + +/* + * 'compare()' - Compare two banners. + */ + +static int /* O - -1 if name0 < name1, etc. */ +compare(const cupsd_banner_t *b0, /* I - First banner */ + const cupsd_banner_t *b1) /* I - Second banner */ +{ + return (strcasecmp(b0->name, b1->name)); +} + + +/* + * End of "$Id: banners.c 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/banners.h b/scheduler/banners.h new file mode 100644 index 000000000..dff951df7 --- /dev/null +++ b/scheduler/banners.h @@ -0,0 +1,57 @@ +/* + * "$Id: banners.h 4719 2005-09-28 21:12:44Z mike $" + * + * Banner definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Banner information structure... + */ + +typedef struct +{ + char name[256]; /* Name of banner */ + mime_type_t *filetype; /* Filetype for banner */ +} cupsd_banner_t; + + +/* + * Globals... + */ + +VAR int NumBanners VALUE(0); + /* Number of banner files available */ +VAR cupsd_banner_t *Banners VALUE(NULL); + /* Available banner files */ + + +/* + * Prototypes... + */ + +extern void cupsdAddBanner(const char *name, const char *filename); +extern cupsd_banner_t *cupsdFindBanner(const char *name); +extern void cupsdLoadBanners(const char *d); + + +/* + * End of "$Id: banners.h 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/cert.c b/scheduler/cert.c new file mode 100644 index 000000000..4255dd8c4 --- /dev/null +++ b/scheduler/cert.c @@ -0,0 +1,296 @@ +/* + * "$Id: cert.c 4719 2005-09-28 21:12:44Z mike $" + * + * Authentication certificate routines for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddCert() - Add a certificate. + * cupsdDeleteCert() - Delete a single certificate. + * cupsdDeleteAllCerts() - Delete all certificates... + * cupsdFindCert() - Find a certificate. + * cupsdInitCerts() - Initialize the certificate "system" and root + * certificate. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + + +/* + * 'cupsdAddCert()' - Add a certificate. + */ + +void +cupsdAddCert(int pid, /* I - Process ID */ + const char *username) /* I - Username */ +{ + int i; /* Looping var */ + cupsd_cert_t *cert; /* Current certificate */ + int fd; /* Certificate file */ + char filename[1024]; /* Certificate filename */ + static const char hex[] = "0123456789ABCDEF"; + /* Hex constants... */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAddCert: adding certificate for pid %d", pid); + + /* + * Allocate memory for the certificate... + */ + + if ((cert = calloc(sizeof(cupsd_cert_t), 1)) == NULL) + return; + + /* + * Fill in the certificate information... + */ + + cert->pid = pid; + strlcpy(cert->username, username, sizeof(cert->username)); + + 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", StateDir, pid); + unlink(filename); + + if ((fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAddCert: Unable to create certificate file %s - %s", + filename, strerror(errno)); + free(cert); + return; + } + + if (pid == 0) + { + /* + * Root certificate... + */ + + fchmod(fd, 0440); + fchown(fd, RunUser, SystemGroupIDs[0]); + + RootCertTime = time(NULL); + } + else + { + /* + * CGI certificate... + */ + + fchmod(fd, 0400); + fchown(fd, User, Group); + } + + DEBUG_printf(("ADD pid=%d, username=%s, cert=%s\n", pid, username, + cert->certificate)); + + write(fd, cert->certificate, strlen(cert->certificate)); + close(fd); + + /* + * Insert the certificate at the front of the list... + */ + + cert->next = Certs; + Certs = cert; +} + + +/* + * 'cupsdDeleteCert()' - Delete a single certificate. + */ + +void +cupsdDeleteCert(int pid) /* I - Process ID */ +{ + cupsd_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... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdDeleteCert: removing certificate for pid %d", pid); + + DEBUG_printf(("DELETE pid=%d, username=%s, cert=%s\n", cert->pid, + cert->username, cert->certificate)); + + 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", StateDir, pid); + if (unlink(filename)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdDeleteCert: Unable to remove %s!\n", filename); + + return; + } +} + + +/* + * 'cupsdDeleteAllCerts()' - Delete all certificates... + */ + +void +cupsdDeleteAllCerts(void) +{ + cupsd_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", StateDir, cert->pid); + if (unlink(filename)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdDeleteAllCerts: Unable to remove %s!\n", filename); + + /* + * Free memory... + */ + + next = cert->next; + free(cert); + } + + Certs = NULL; +} + + +/* + * 'cupsdFindCert()' - Find a certificate. + */ + +const char * /* O - Matching username or NULL */ +cupsdFindCert(const char *certificate) /* I - Certificate */ +{ + cupsd_cert_t *cert; /* Current certificate */ + + + DEBUG_printf(("cupsdFindCert(certificate=%s)\n", certificate)); + for (cert = Certs; cert != NULL; cert = cert->next) + if (!strcasecmp(certificate, cert->certificate)) + { + DEBUG_printf((" returning %s...\n", cert->username)); + return (cert->username); + } + + DEBUG_puts(" certificate not found!"); + + return (NULL); +} + + +/* + * 'cupsdInitCerts()' - Initialize the certificate "system" and root + * certificate. + */ + +void +cupsdInitCerts(void) +{ + cups_file_t *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 = cupsFileOpen("/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 = cupsFileGetChar(fp); + seed = (seed << 8) | cupsFileGetChar(fp); + seed = (seed << 8) | cupsFileGetChar(fp); + seed = (seed << 8) | cupsFileGetChar(fp); + + cupsFileClose(fp); + } + + srandom(seed); + + /* + * Create a root certificate and return... + */ + + if (!RunUser) + cupsdAddCert(0, "root"); +} + + +/* + * End of "$Id: cert.c 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/cert.h b/scheduler/cert.h new file mode 100644 index 000000000..2da5a3b8b --- /dev/null +++ b/scheduler/cert.h @@ -0,0 +1,60 @@ +/* + * "$Id: cert.h 4719 2005-09-28 21:12:44Z mike $" + * + * Authentication certificate definitions for the Common UNIX + * Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Certificate structure... + */ + +typedef struct cupsd_cert_s +{ + struct cupsd_cert_s *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 */ +} cupsd_cert_t; + + +/* + * Globals... + */ + +VAR cupsd_cert_t *Certs; /* List of certificates */ +VAR time_t RootCertTime; /* Root certificate update time */ + + +/* + * Prototypes... + */ + +extern void cupsdAddCert(int pid, const char *username); +extern void cupsdDeleteCert(int pid); +extern void cupsdDeleteAllCerts(void); +extern const char *cupsdFindCert(const char *certificate); +extern void cupsdInitCerts(void); + + +/* + * End of "$Id: cert.h 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/classes.c b/scheduler/classes.c new file mode 100644 index 000000000..5b0d8d5ce --- /dev/null +++ b/scheduler/classes.c @@ -0,0 +1,844 @@ +/* + * "$Id: classes.c 4848 2005-11-22 04:14:43Z mike $" + * + * Printer class routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddClass() - Add a class to the system. + * cupsdAddPrinterToClass() - Add a printer to a class... + * cupsdDeletePrinterFromClass() - Delete a printer from a class. + * cupsdDeletePrinterFromClasses() - Delete a printer from all classes. + * cupsdDeleteAllClasses() - Remove all classes from the system. + * cupsdFindAvailablePrinter() - Find an available printer in a class. + * cupsdFindClass() - Find the named class. + * cupsdLoadAllClasses() - Load classes from the classes.conf file. + * cupsdSaveAllClasses() - Save classes to the classes.conf file. + * cupsdUpdateImplicitClasses() - Update the accepting state of implicit + * classes. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + + +/* + * 'cupsdAddClass()' - Add a class to the system. + */ + +cupsd_printer_t * /* O - New class */ +cupsdAddClass(const char *name) /* I - Name of class */ +{ + cupsd_printer_t *c; /* New class */ + + + /* + * Add the printer and set the type to "class"... + */ + + if ((c = cupsdAddPrinter(name)) != NULL) + { + /* + * Change from a printer to a class... + */ + + c->type = CUPS_PRINTER_CLASS; + + cupsdSetStringf(&c->uri, "ipp://%s:%d/classes/%s", ServerName, LocalPort, + name); + cupsdSetString(&c->error_policy, "retry-job"); + } + + return (c); +} + + +/* + * 'cupsdAddPrinterToClass()' - Add a printer to a class... + */ + +void +cupsdAddPrinterToClass( + cupsd_printer_t *c, /* I - Class to add to */ + cupsd_printer_t *p) /* I - Printer to add */ +{ + int i; /* Looping var */ + cupsd_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(cupsd_printer_t *)); + else + temp = realloc(c->printers, sizeof(cupsd_printer_t *) * (c->num_printers + 1)); + + if (temp == NULL) + { + cupsdLogMessage(CUPSD_LOG_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; +} + + +/* + * 'cupsdDeletePrinterFromClass()' - Delete a printer from a class. + */ + +void +cupsdDeletePrinterFromClass( + cupsd_printer_t *c, /* I - Class to delete from */ + cupsd_printer_t *p) /* I - Printer to delete */ +{ + int i; /* Looping var */ + cups_ptype_t type, /* Class type */ + oldtype; /* Old 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) + memmove(c->printers + i, c->printers + i + 1, + (c->num_printers - i) * sizeof(cupsd_printer_t *)); + } + else + return; + + /* + * Recompute the printer type mask as needed... + */ + + if (c->num_printers > 0) + { + oldtype = c->type; + 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... + */ + + if (c->type != oldtype) + cupsdSetPrinterAttrs(c); + } +} + + +/* + * 'cupsdDeletePrinterFromClasses()' - Delete a printer from all classes. + */ + +void +cupsdDeletePrinterFromClasses( + cupsd_printer_t *p) /* I - Printer to delete */ +{ + cupsd_printer_t *c; /* Pointer to current class */ + + + /* + * Loop through the printer/class list and remove the printer + * from each class listed... + */ + + for (c = (cupsd_printer_t *)cupsArrayFirst(Printers); + c; + c = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) + cupsdDeletePrinterFromClass(c, p); + + /* + * Then clean out any empty implicit classes... + */ + + for (c = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters); + c; + c = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters)) + if (c->num_printers == 0) + { + cupsArrayRemove(ImplicitPrinters, c); + cupsdDeletePrinter(c, 0); + } +} + + +/* + * 'cupsdDeleteAllClasses()' - Remove all classes from the system. + */ + +void +cupsdDeleteAllClasses(void) +{ + cupsd_printer_t *c; /* Pointer to current printer/class */ + + + for (c = (cupsd_printer_t *)cupsArrayFirst(Printers); + c; + c = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (c->type & CUPS_PRINTER_CLASS) + cupsdDeletePrinter(c, 0); +} + + +/* + * 'cupsdFindAvailablePrinter()' - Find an available printer in a class. + */ + +cupsd_printer_t * /* O - Available printer or NULL */ +cupsdFindAvailablePrinter( + const char *name) /* I - Class to check */ +{ + int i; /* Looping var */ + cupsd_printer_t *c; /* Printer class */ + + + /* + * Find the class... + */ + + if ((c = cupsdFindClass(name)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_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]->accepting && + (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); +} + + +/* + * 'cupsdFindClass()' - Find the named class. + */ + +cupsd_printer_t * /* O - Matching class or NULL */ +cupsdFindClass(const char *name) /* I - Name of class */ +{ + cupsd_printer_t *c; /* Current class/printer */ + + + if ((c = cupsdFindDest(name)) != NULL && + (c->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT))) + return (c); + else + return (NULL); +} + + +/* + * 'cupsdLoadAllClasses()' - Load classes from the classes.conf file. + */ + +void +cupsdLoadAllClasses(void) +{ + cups_file_t *fp; /* classes.conf file */ + int linenum; /* Current line number */ + char line[1024], /* Line from file */ + *value, /* Pointer to value */ + *valueptr; /* Pointer into value */ + cupsd_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 = cupsFileOpen(line, "r")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllClasses: Unable to open %s - %s", line, + strerror(errno)); + return; + } + + /* + * Read class configurations until we hit EOF... + */ + + linenum = 0; + p = NULL; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + /* + * Decode the directive... + */ + + if (!strcasecmp(line, " or + */ + + if (p == NULL && value) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdLoadAllClasses: Loading class %s...", value); + + p = cupsdAddClass(value); + p->accepting = 1; + p->state = IPP_PRINTER_IDLE; + + if (!strcasecmp(line, "")) + { + if (p != NULL) + { + cupsdSetPrinterAttrs(p); + p = NULL; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else if (!p) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + else if (!strcasecmp(line, "Info")) + { + if (value) + cupsdSetString(&p->info, value); + } + else if (!strcasecmp(line, "Location")) + { + if (value) + cupsdSetString(&p->location, value); + } + else if (!strcasecmp(line, "Printer")) + { + if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + else if ((temp = cupsdFindPrinter(value)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Unknown printer %s on line %d of classes.conf.", + value, linenum); + + /* + * Add the missing remote printer... + */ + + if ((temp = cupsdAddPrinter(value)) != NULL) + { + cupsdSetString(&temp->make_model, "Remote Printer on unknown"); + + temp->state = IPP_PRINTER_STOPPED; + temp->type |= CUPS_PRINTER_REMOTE; + temp->browse_time = 2147483647; + + cupsdSetString(&temp->location, "Location Unknown"); + cupsdSetString(&temp->info, "No Information Available"); + temp->hostname[0] = '\0'; + + cupsdSetPrinterAttrs(temp); + } + } + + if (temp) + cupsdAddPrinterToClass(p, temp); + } + else if (!strcasecmp(line, "State")) + { + /* + * Set the initial queue state... + */ + + if (!strcasecmp(value, "idle")) + p->state = IPP_PRINTER_IDLE; + else if (!strcasecmp(value, "stopped")) + p->state = IPP_PRINTER_STOPPED; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "StateMessage")) + { + /* + * Set the initial queue state message... + */ + + if (value) + strlcpy(p->state_message, value, sizeof(p->state_message)); + } + else if (!strcasecmp(line, "StateTime")) + { + /* + * Set the state time... + */ + + if (value) + p->state_time = atoi(value); + } + else if (!strcasecmp(line, "Accepting")) + { + /* + * Set the initial accepting state... + */ + + if (value && + (!strcasecmp(value, "yes") || + !strcasecmp(value, "on") || + !strcasecmp(value, "true"))) + p->accepting = 1; + else if (value && + (!strcasecmp(value, "no") || + !strcasecmp(value, "off") || + !strcasecmp(value, "false"))) + p->accepting = 0; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "Shared")) + { + /* + * Set the initial shared state... + */ + + if (value && + (!strcasecmp(value, "yes") || + !strcasecmp(value, "on") || + !strcasecmp(value, "true"))) + p->shared = 1; + else if (value && + (!strcasecmp(value, "no") || + !strcasecmp(value, "off") || + !strcasecmp(value, "false"))) + p->shared = 0; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "JobSheets")) + { + /* + * Set the initial job sheets... + */ + + if (value) + { + for (valueptr = value; + *valueptr && !isspace(*valueptr & 255); + valueptr ++); + + if (*valueptr) + *valueptr++ = '\0'; + + cupsdSetString(&p->job_sheets[0], value); + + while (isspace(*valueptr & 255)) + valueptr ++; + + if (*valueptr) + { + for (value = valueptr; + *valueptr && !isspace(*valueptr & 255); + valueptr ++); + + if (*valueptr) + *valueptr++ = '\0'; + + cupsdSetString(&p->job_sheets[1], value); + } + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "AllowUser")) + { + if (value) + { + p->deny_users = 0; + cupsdAddPrinterUser(p, value); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "DenyUser")) + { + if (value) + { + p->deny_users = 1; + cupsdAddPrinterUser(p, value); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "QuotaPeriod")) + { + if (value) + p->quota_period = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "PageLimit")) + { + if (value) + p->page_limit = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "KLimit")) + { + if (value) + p->k_limit = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "OpPolicy")) + { + if (value) + cupsdSetString(&p->op_policy, value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "ErrorPolicy")) + { + if (value) + cupsdSetString(&p->error_policy, value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of classes.conf.", linenum); + return; + } + } + else + { + /* + * Something else we don't understand... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown configuration directive %s on line %d of classes.conf.", + line, linenum); + } + } + + cupsFileClose(fp); +} + + +/* + * 'cupsdSaveAllClasses()' - Save classes to the classes.conf file. + */ + +void +cupsdSaveAllClasses(void) +{ + cups_file_t *fp; /* classes.conf file */ + char temp[1024]; /* Temporary string */ + char backup[1024]; /* classes.conf.O file */ + cupsd_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)) + { + if (errno != ENOENT) + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup classes.conf - %s", + strerror(errno)); + } + + if ((fp = cupsFileOpen(temp, "w")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to save classes.conf - %s", + strerror(errno)); + + if (rename(backup, temp)) + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to restore classes.conf - %s", + strerror(errno)); + return; + } + else + cupsdLogMessage(CUPSD_LOG_INFO, "Saving classes.conf..."); + + /* + * Restrict access to the file... + */ + + fchown(cupsFileNumber(fp), RunUser, Group); + fchmod(cupsFileNumber(fp), ConfigFilePerm); + + /* + * Write a small header to the file... + */ + + curtime = time(NULL); + curdate = localtime(&curtime); + strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); + + cupsFilePuts(fp, "# Class configuration file for " CUPS_SVERSION "\n"); + cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); + + /* + * Write each local class known to the system... + */ + + for (pclass = (cupsd_printer_t *)cupsArrayFirst(Printers); + pclass; + pclass = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + /* + * 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) + cupsFilePrintf(fp, "\n", pclass->name); + else + cupsFilePrintf(fp, "\n", pclass->name); + + if (pclass->info) + cupsFilePrintf(fp, "Info %s\n", pclass->info); + + if (pclass->location) + cupsFilePrintf(fp, "Location %s\n", pclass->location); + + if (pclass->state == IPP_PRINTER_STOPPED) + { + cupsFilePuts(fp, "State Stopped\n"); + cupsFilePrintf(fp, "StateMessage %s\n", pclass->state_message); + } + else + cupsFilePuts(fp, "State Idle\n"); + + cupsFilePrintf(fp, "StateTime %d\n", (int)pclass->state_time); + + if (pclass->accepting) + cupsFilePuts(fp, "Accepting Yes\n"); + else + cupsFilePuts(fp, "Accepting No\n"); + + if (pclass->shared) + cupsFilePuts(fp, "Shared Yes\n"); + else + cupsFilePuts(fp, "Shared No\n"); + + cupsFilePrintf(fp, "JobSheets %s %s\n", pclass->job_sheets[0], + pclass->job_sheets[1]); + + for (i = 0; i < pclass->num_printers; i ++) + cupsFilePrintf(fp, "Printer %s\n", pclass->printers[i]->name); + + cupsFilePrintf(fp, "QuotaPeriod %d\n", pclass->quota_period); + cupsFilePrintf(fp, "PageLimit %d\n", pclass->page_limit); + cupsFilePrintf(fp, "KLimit %d\n", pclass->k_limit); + + for (i = 0; i < pclass->num_users; i ++) + cupsFilePrintf(fp, "%sUser %s\n", pclass->deny_users ? "Deny" : "Allow", + pclass->users[i]); + + if (pclass->op_policy) + cupsFilePrintf(fp, "OpPolicy %s\n", pclass->op_policy); + if (pclass->error_policy) + cupsFilePrintf(fp, "ErrorPolicy %s\n", pclass->error_policy); + + cupsFilePuts(fp, "\n"); + } + + cupsFileClose(fp); +} + + +/* + * 'cupsdUpdateImplicitClasses()' - Update the accepting state of implicit + * classes. + */ + +void +cupsdUpdateImplicitClasses(void) +{ + int i; /* Looping var */ + cupsd_printer_t *pclass; /* Current class */ + int accepting; /* printer-is-accepting-jobs value */ + + + for (pclass = (cupsd_printer_t *)cupsArrayFirst(ImplicitPrinters); + pclass; + pclass = (cupsd_printer_t *)cupsArrayNext(ImplicitPrinters)) + { + /* + * Loop through the printers to come up with a composite state... + */ + + for (i = 0, accepting = 0; i < pclass->num_printers; i ++) + if ((accepting = pclass->printers[i]->accepting) != 0) + break; + + pclass->accepting = accepting; + } +} + + +/* + * End of "$Id: classes.c 4848 2005-11-22 04:14:43Z mike $". + */ diff --git a/scheduler/classes.h b/scheduler/classes.h new file mode 100644 index 000000000..5b9968167 --- /dev/null +++ b/scheduler/classes.h @@ -0,0 +1,46 @@ +/* + * "$Id: classes.h 4719 2005-09-28 21:12:44Z mike $" + * + * Printer class definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + + +/* + * Prototypes... + */ + +extern cupsd_printer_t *cupsdAddClass(const char *name); +extern void cupsdAddPrinterToClass(cupsd_printer_t *c, + cupsd_printer_t *p); +extern void cupsdDeletePrinterFromClass(cupsd_printer_t *c, + cupsd_printer_t *p); +extern void cupsdDeletePrinterFromClasses(cupsd_printer_t *p); +extern void cupsdDeleteAllClasses(void); +extern cupsd_printer_t *cupsdFindAvailablePrinter(const char *name); +extern cupsd_printer_t *cupsdFindClass(const char *name); +extern void cupsdLoadAllClasses(void); +extern void cupsdSaveAllClasses(void); +extern void cupsdUpdateImplicitClasses(void); + + +/* + * End of "$Id: classes.h 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/client.c b/scheduler/client.c new file mode 100644 index 000000000..dc68d4549 --- /dev/null +++ b/scheduler/client.c @@ -0,0 +1,3484 @@ +/* + * "$Id: client.c 4912 2006-01-10 21:43:56Z mike $" + * + * Client routines for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAcceptClient() - Accept a new client. + * cupsdCloseAllClients() - Close all remote clients immediately. + * cupsdCloseClient() - Close a remote client. + * cupsdEncryptClient() - Enable encryption for the client... + * cupsdIsCGI() - Is the resource a CGI script/program? + * cupsdReadClient() - Read data from a client. + * cupsdSendCommand() - Send output from a command via HTTP. + * cupsdSendError() - Send an error message via HTTP. + * cupsdSendFile() - Send a file via HTTP. + * cupsdSendHeader() - Send an HTTP request. + * cupsdUpdateCGI() - Read status messages from CGI scripts and programs. + * cupsdWriteClient() - Write data to a client as needed. + * check_if_modified() - Decode an "If-Modified-Since" line. + * get_cdsa_server_certs() - Convert a keychain name into the CFArrayRef + * required by SSLSetCertificate. + * get_file() - Get a filename and state info. + * install_conf_file() - Install a configuration file. + * is_path_absolute() - Is a path absolute and free of relative elements. + * pipe_command() - Pipe the output of a command to the remote client. + */ + +/* + * Include necessary headers... + */ + +#include +#include "cupsd.h" + +#ifdef HAVE_CDSASSL +# include +#endif /* HAVE_CDSASSL */ + + +/* + * Local functions... + */ + +static int check_if_modified(cupsd_client_t *con, + struct stat *filestats); +#ifdef HAVE_CDSASSL +static CFArrayRef get_cdsa_server_certs(void); +#endif /* HAVE_CDSASSL */ +static char *get_file(cupsd_client_t *con, struct stat *filestats, + char *filename, int len); +static http_status_t install_conf_file(cupsd_client_t *con); +static int is_path_absolute(const char *path); +static int pipe_command(cupsd_client_t *con, int infile, int *outfile, + char *command, char *options, int root); + + +/* + * 'cupsdAcceptClient()' - Accept a new client. + */ + +void +cupsdAcceptClient(cupsd_listener_t *lis)/* I - Listener socket */ +{ + int i; /* Looping var */ + int count; /* Count of connections on a host */ + int val; /* Parameter value */ + cupsd_client_t *con; /* New client pointer */ + http_addrlist_t *addrlist, /* List of adddresses for host */ + *addr; /* Current address */ + socklen_t addrlen; /* Length of address */ + char *hostname; /* Hostname for address */ + http_addr_t temp; /* Temporary address variable */ + static time_t last_dos = 0; /* Time of last DoS attack */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAcceptClient(lis=%p) %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(cupsd_client_t)); + con->http.activity = time(NULL); + con->file = -1; + con->http.hostaddr = &(con->clientaddr); + + /* + * Accept the client and get the remote address... + */ + + addrlen = sizeof(http_addr_t); + + if ((con->http.fd = accept(lis->fd, (struct sockaddr *)con->http.hostaddr, + &addrlen)) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to accept client connection - %s.", + strerror(errno)); + return; + } + +#ifdef AF_INET6 + if (lis->address.addr.sa_family == AF_INET6) + { + /* + * Save the connected port number... + */ + + con->http.hostaddr->ipv6.sin6_port = lis->address.ipv6.sin6_port; + + /* + * Convert IPv4 over IPv6 addresses (::ffff:n.n.n.n) to IPv4 forms we + * can more easily use... + */ + + if (con->http.hostaddr->ipv6.sin6_addr.s6_addr32[0] == 0 && + con->http.hostaddr->ipv6.sin6_addr.s6_addr32[1] == 0 && + ntohl(con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2]) == 0xffff) + con->http.hostaddr->ipv6.sin6_addr.s6_addr32[2] = 0; + } + else +#endif /* AF_INET6 */ + if (lis->address.addr.sa_family == AF_INET) + con->http.hostaddr->ipv4.sin_port = lis->address.ipv4.sin_port; + + /* + * Check the number of clients on the same address... + */ + + for (i = 0, count = 0; i < NumClients; i ++) + if (httpAddrEqual(Clients[i].http.hostaddr, con->http.hostaddr)) + { + count ++; + if (count >= MaxClientsPerHost) + break; + } + + if (count >= MaxClientsPerHost) + { + if ((time(NULL) - last_dos) >= 60) + { + last_dos = time(NULL); + cupsdLogMessage(CUPSD_LOG_WARN, + "Possible DoS attack - more than %d clients connecting from %s!", + MaxClientsPerHost, Clients[i].http.hostname); + } + +#ifdef WIN32 + closesocket(con->http.fd); +#else + close(con->http.fd); +#endif /* WIN32 */ + + return; + } + + /* + * Get the hostname or format the IP address as needed... + */ + + if (httpAddrLocalhost(con->http.hostaddr)) + { + /* + * Map accesses from the loopback interface to "localhost"... + */ + + strlcpy(con->http.hostname, "localhost", sizeof(con->http.hostname)); + hostname = con->http.hostname; + } + else + { + /* + * Map accesses from the same host to the server name. + */ + + for (addr = ServerAddrs; addr; addr = addr->next) + if (httpAddrEqual(con->http.hostaddr, &(addr->addr))) + break; + + if (addr) + { + strlcpy(con->http.hostname, ServerName, sizeof(con->http.hostname)); + hostname = con->http.hostname; + } + else if (HostNameLookups) + hostname = httpAddrLookup(con->http.hostaddr, con->http.hostname, + sizeof(con->http.hostname)); + else + { + hostname = NULL; + httpAddrString(con->http.hostaddr, con->http.hostname, + sizeof(con->http.hostname)); + } + } + + if (hostname == NULL && HostNameLookups == 2) + { + /* + * Can't have an unresolved IP address with double-lookups enabled... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAcceptClient: Closing connection %d...", + con->http.fd); + +#ifdef WIN32 + closesocket(con->http.fd); +#else + close(con->http.fd); +#endif /* WIN32 */ + + cupsdLogMessage(CUPSD_LOG_WARN, + "Name lookup failed - connection from %s closed!", + con->http.hostname); + return; + } + + if (HostNameLookups == 2) + { + /* + * Do double lookups as needed... + */ + + if ((addrlist = httpAddrGetList(con->http.hostname, AF_UNSPEC, NULL)) != NULL) + { + /* + * See if the hostname maps to the same IP address... + */ + + for (addr = addrlist; addr; addr = addr->next) + if (httpAddrEqual(con->http.hostaddr, &(addr->addr))) + break; + } + else + addr = NULL; + + httpAddrFreeList(addrlist); + + if (!addr) + { + /* + * Can't have a hostname that doesn't resolve to the same IP address + * with double-lookups enabled... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAcceptClient: Closing connection %d...", + con->http.fd); + +#ifdef WIN32 + closesocket(con->http.fd); +#else + close(con->http.fd); +#endif /* WIN32 */ + + cupsdLogMessage(CUPSD_LOG_WARN, + "IP lookup failed - connection from %s closed!", + con->http.hostname); + return; + } + } + +#ifdef AF_INET6 + if (con->http.hostaddr->addr.sa_family == AF_INET6) + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv6)", + con->http.fd, con->http.hostname, + ntohs(con->http.hostaddr->ipv6.sin6_port)); + else +#endif /* AF_INET6 */ +#ifdef AF_LOCAL + if (con->http.hostaddr->addr.sa_family == AF_LOCAL) + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s (Domain)", + con->http.fd, con->http.hostname); + else +#endif /* AF_LOCAL */ + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdAcceptClient: %d from %s:%d (IPv4)", + con->http.fd, con->http.hostname, + ntohs(con->http.hostaddr->ipv4.sin_port)); + + /* + * Get the local address the client connected to... + */ + + addrlen = sizeof(temp); + if (getsockname(con->http.fd, (struct sockaddr *)&temp, &addrlen)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to get local address - %s", + strerror(errno)); + + strcpy(con->servername, "localhost"); + con->serverport = LocalPort; + } + else + { +#ifdef AF_INET6 + if (temp.addr.sa_family == AF_INET6) + { + httpAddrLookup(&temp, con->servername, sizeof(con->servername)); + con->serverport = ntohs(lis->address.ipv6.sin6_port); + } + else +#endif /* AF_INET6 */ + if (temp.addr.sa_family == AF_INET) + { + httpAddrLookup(&temp, con->servername, sizeof(con->servername)); + con->serverport = ntohs(lis->address.ipv4.sin_port); + } + else + { + strcpy(con->servername, "localhost"); + con->serverport = LocalPort; + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAcceptClient: %d connected to server on %s:%d", + con->http.fd, con->servername, con->serverport); + + /* + * 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)); + + /* + * Close this file on all execs... + */ + + fcntl(con->http.fd, F_SETFD, fcntl(con->http.fd, F_GETFD) | FD_CLOEXEC); + + /* + * Add the socket to the select() input mask. + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdAcceptClient: 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) + cupsdPauseListening(); + +#ifdef HAVE_SSL + /* + * See if we are connecting on a secure port... + */ + + if (lis->encryption == HTTP_ENCRYPT_ALWAYS) + { + /* + * https connection; go secure... + */ + + con->http.encryption = HTTP_ENCRYPT_ALWAYS; + + cupsdEncryptClient(con); + } + else + con->auto_ssl = 1; +#endif /* HAVE_SSL */ +} + + +/* + * 'cupsdCloseAllClients()' - Close all remote clients immediately. + */ + +void +cupsdCloseAllClients(void) +{ + while (NumClients > 0) + cupsdCloseClient(Clients); +} + + +/* + * 'cupsdCloseClient()' - Close a remote client. + */ + +int /* O - 1 if partial close, 0 if fully closed */ +cupsdCloseClient(cupsd_client_t *con) /* I - Client to close */ +{ + int partial; /* Do partial close for SSL? */ +#ifdef HAVE_LIBSSL + SSL_CTX *context; /* Context for encryption */ + SSL *conn; /* Connection for encryption */ + unsigned long error; /* Error code */ +#elif defined(HAVE_GNUTLS) + http_tls_t *conn; /* TLS connection information */ + int error; /* Error code */ + gnutls_certificate_server_credentials *credentials; + /* TLS credentials */ +#endif /* HAVE_LIBSSL */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCloseClient: %d", con->http.fd); + + /* + * Flush pending writes before closing... + */ + + httpFlushWrite(HTTP(con)); + + partial = 0; + +#ifdef HAVE_SSL + /* + * Shutdown encryption as needed... + */ + + if (con->http.tls) + { + partial = 1; + +# ifdef HAVE_LIBSSL + conn = (SSL *)(con->http.tls); + context = SSL_get_SSL_CTX(conn); + + switch (SSL_shutdown(conn)) + { + case 1 : + cupsdLogMessage(CUPSD_LOG_INFO, + "cupsdCloseClient: SSL shutdown successful!"); + break; + case -1 : + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdCloseClient: Fatal error during SSL shutdown!"); + default : + while ((error = ERR_get_error()) != 0) + cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdCloseClient: %s", + ERR_error_string(error, NULL)); + break; + } + + SSL_CTX_free(context); + SSL_free(conn); + +# elif defined(HAVE_GNUTLS) + conn = (http_tls_t *)(con->http.tls); + credentials = (gnutls_certificate_server_credentials *)(conn->credentials); + + error = gnutls_bye(conn->session, GNUTLS_SHUT_WR); + switch (error) + { + case GNUTLS_E_SUCCESS: + cupsdLogMessage(CUPSD_LOG_INFO, + "cupsdCloseClient: SSL shutdown successful!"); + break; + default: + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdCloseClient: %s", gnutls_strerror(error)); + break; + } + + gnutls_deinit(conn->session); + gnutls_certificate_free_credentials(*credentials); + free(credentials); + free(conn); + +# elif defined(HAVE_CDSASSL) + SSLClose((SSLContextRef)con->http.tls); + SSLDisposeContext((SSLContextRef)con->http.tls); +# endif /* HAVE_LIBSSL */ + + con->http.tls = NULL; + } +#endif /* HAVE_SSL */ + + if (con->pipe_pid != 0) + { + /* + * Stop any CGI process... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCloseClient: %d Killing process ID %d...", + con->http.fd, con->pipe_pid); + cupsdEndProcess(con->pipe_pid, 1); + con->pipe_pid = 0; + } + + if (con->file >= 0) + { + if (FD_ISSET(con->file, InputSet)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCloseClient: %d Removing fd %d from InputSet...", + con->http.fd, con->file); + FD_CLR(con->file, InputSet); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCloseClient: %d Closing data file %d.", + con->http.fd, con->file); + + close(con->file); + con->file = -1; + } + + /* + * Close the socket and clear the file from the input set for select()... + */ + + if (con->http.fd > 0) + { + if (partial) + { + /* + * Only do a partial close so that the encrypted client gets everything. + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCloseClient: Removing fd %d from OutputSet...", + con->http.fd); + shutdown(con->http.fd, 0); + FD_CLR(con->http.fd, OutputSet); + } + else + { + /* + * Shut the socket down fully... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdCloseClient: 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 = -1; + } + } + + if (!partial) + { + /* + * Free memory... + */ + + if (con->http.input_set) + free(con->http.input_set); + + httpClearCookie(HTTP(con)); + + cupsdClearString(&con->filename); + cupsdClearString(&con->command); + cupsdClearString(&con->options); + + 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) + cupsdResumeListening(); + + /* + * Compact the list of clients as necessary... + */ + + NumClients --; + + if (con < (Clients + NumClients)) + memmove(con, con + 1, (Clients + NumClients - con) * sizeof(cupsd_client_t)); + } + + return (partial); +} + + +/* + * 'cupsdEncryptClient()' - Enable encryption for the client... + */ + +int /* O - 1 on success, 0 on error */ +cupsdEncryptClient(cupsd_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_server_method()); + + SSL_CTX_set_options(context, SSL_OP_NO_SSLv2); /* Only use SSLv3 or TLS */ + SSL_CTX_use_PrivateKey_file(context, ServerKey, SSL_FILETYPE_PEM); + SSL_CTX_use_certificate_file(context, ServerCertificate, SSL_FILETYPE_PEM); + + conn = SSL_new(context); + + SSL_set_fd(conn, con->http.fd); + if (SSL_accept(conn) != 1) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdEncryptClient: Unable to encrypt connection from %s!", + con->http.hostname); + + while ((error = ERR_get_error()) != 0) + cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdEncryptClient: %s", + ERR_error_string(error, NULL)); + + SSL_CTX_free(context); + SSL_free(conn); + return (0); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdEncryptClient: %d Connection from %s now encrypted.", + con->http.fd, con->http.hostname); + + con->http.tls = conn; + return (1); + +#elif defined(HAVE_GNUTLS) + http_tls_t *conn; /* TLS session object */ + int error; /* Error code */ + gnutls_certificate_server_credentials *credentials; + /* TLS credentials */ + + /* + * Create the SSL object and perform the SSL handshake... + */ + + conn = (http_tls_t *)malloc(sizeof(gnutls_session)); + + if (conn == NULL) + return (0); + + credentials = (gnutls_certificate_server_credentials *) + malloc(sizeof(gnutls_certificate_server_credentials)); + if (credentials == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdEncryptClient: Unable to encrypt connection from %s!", + con->http.hostname); + cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdEncryptClient: %s", strerror(errno)); + + free(conn); + return (0); + } + + gnutls_certificate_allocate_credentials(credentials); + gnutls_certificate_set_x509_key_file(*credentials, ServerCertificate, + ServerKey, GNUTLS_X509_FMT_PEM); + + gnutls_init(&(conn->session), GNUTLS_SERVER); + gnutls_set_default_priority(conn->session); + gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE, *credentials); + gnutls_transport_set_ptr(conn->session, con->http.fd); + + error = gnutls_handshake(conn->session); + + if (error != GNUTLS_E_SUCCESS) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdEncryptClient: Unable to encrypt connection from %s!", + con->http.hostname); + cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdEncryptClient: %s", + gnutls_strerror(error)); + + gnutls_deinit(conn->session); + gnutls_certificate_free_credentials(*credentials); + free(conn); + free(credentials); + return (0); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdEncryptClient: %d Connection from %s now encrypted.", + con->http.fd, con->http.hostname); + + conn->credentials = credentials; + con->http.tls = conn; + return (1); + +#elif defined(HAVE_CDSASSL) + OSStatus error; /* Error info */ + SSLContextRef conn; /* New connection */ + int allowExpired; /* Allow expired certificates? */ + int allowAnyRoot; /* Allow any root certificate? */ + + + conn = NULL; + error = SSLNewContext(true, &conn); + allowExpired = 1; + allowAnyRoot = 1; + + if (!ServerCertificatesArray) + ServerCertificatesArray = get_cdsa_server_certs(); + + if (!ServerCertificatesArray) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "EncryptClient: Could not find signing key in keychain " + "\"%s\"", ServerCertificate); + error = errSSLBadConfiguration; + } + + if (!error) + error = SSLSetIOFuncs(conn, _httpReadCDSA, _httpWriteCDSA); + + if (!error) + error = SSLSetProtocolVersion(conn, kSSLProtocol3); + + if (!error) + error = SSLSetConnection(conn, (SSLConnectionRef)con->http.fd); + + if (!error) + error = SSLSetPeerDomainName(conn, ServerName, strlen(ServerName) + 1); + + /* have to do these options before setting server certs */ + if (!error && allowExpired) + error = SSLSetAllowsExpiredCerts(conn, true); + + if (!error && allowAnyRoot) + error = SSLSetAllowsAnyRoot(conn, true); + + if (!error && ServerCertificatesArray) + error = SSLSetCertificate(conn, ServerCertificatesArray); + + /* + * Perform SSL/TLS handshake + */ + + do + { + error = SSLHandshake(conn); + } + while (error == errSSLWouldBlock); + + if (error) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdEncryptClient: Unable to encrypt connection from %s!", + con->http.hostname); + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdEncryptClient: CDSA error code is %d", (int)error); + + con->http.error = error; + con->http.status = HTTP_ERROR; + + if (conn != NULL) + SSLDisposeContext(conn); + + return (0); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdEncryptClient: %d Connection from %s now encrypted.", + con->http.fd, con->http.hostname); + + con->http.tls = conn; + return (1); + +#else + return (0); +#endif /* HAVE_LIBSSL */ +} + + +/* + * 'cupsdIsCGI()' - Is the resource a CGI script/program? + */ + +int /* O - 1 = CGI, 0 = file */ +cupsdIsCGI(cupsd_client_t *con, /* I - Client connection */ + const char *filename, /* I - Real filename */ + struct stat *filestats, /* I - File information */ + mime_type_t *type) /* I - MIME type */ +{ + const char *options; /* Options on URL */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsCGI(con=%p, filename=\"%s\", filestats=%p, type=%s/%s)\n", + con, filename, filestats, type ? type->super : "unknown", + type ? type->type : "unknown"); + + /* + * Get the options, if any... + */ + + if ((options = strchr(con->uri, '?')) != NULL) + options ++; + + /* + * Check for known types... + */ + + if (!type || strcasecmp(type->super, "application")) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsCGI: Returning 0..."); + return (0); + } + + if (!strcasecmp(type->type, "x-httpd-cgi") && + (filestats->st_mode & 0111)) + { + /* + * "application/x-httpd-cgi" is a CGI script. + */ + + cupsdSetString(&con->command, filename); + + filename = strrchr(filename, '/') + 1; /* Filename always absolute */ + + if (options) + cupsdSetStringf(&con->options, "%s %s", filename, options); + else + cupsdSetStringf(&con->options, "%s", filename); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsCGI: Returning 1 with command=\"%s\" and options=\"%s\"", + con->command, con->options); + + return (1); + } +#ifdef HAVE_JAVA + else if (!strcasecmp(type->type, "x-httpd-java")) + { + /* + * "application/x-httpd-java" is a Java servlet. + */ + + cupsdSetString(&con->command, CUPS_JAVA); + + if (options) + cupsdSetStringf(&con->options, "java %s %s", filename, options); + else + cupsdSetStringf(&con->options, "java %s", filename); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsCGI: Returning 1 with command=\"%s\" and options=\"%s\"", + con->command, con->options); + + return (1); + } +#endif /* HAVE_JAVA */ +#ifdef HAVE_PERL + else if (!strcasecmp(type->type, "x-httpd-perl")) + { + /* + * "application/x-httpd-perl" is a Perl page. + */ + + cupsdSetString(&con->command, CUPS_PERL); + + if (options) + cupsdSetStringf(&con->options, "perl %s %s", filename, options); + else + cupsdSetStringf(&con->options, "perl %s", filename); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsCGI: Returning 1 with command=\"%s\" and options=\"%s\"", + con->command, con->options); + + return (1); + } +#endif /* HAVE_PERL */ +#ifdef HAVE_PHP + else if (!strcasecmp(type->type, "x-httpd-php")) + { + /* + * "application/x-httpd-php" is a PHP page. + */ + + cupsdSetString(&con->command, CUPS_PHP); + + if (options) + cupsdSetStringf(&con->options, "php %s %s", filename, options); + else + cupsdSetStringf(&con->options, "php %s", filename); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsCGI: Returning 1 with command=\"%s\" and options=\"%s\"", + con->command, con->options); + + return (1); + } +#endif /* HAVE_PHP */ +#ifdef HAVE_PYTHON + else if (!strcasecmp(type->type, "x-httpd-python")) + { + /* + * "application/x-httpd-python" is a Python page. + */ + + cupsdSetString(&con->command, CUPS_PYTHON); + + if (options) + cupsdSetStringf(&con->options, "python %s %s", filename, options); + else + cupsdSetStringf(&con->options, "python %s", filename); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdIsCGI: Returning 1 with command=\"%s\" and options=\"%s\"", + con->command, con->options); + + return (1); + } +#endif /* HAVE_PYTHON */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdIsCGI: Returning 0..."); + + return (0); +} + + +/* + * 'cupsdReadClient()' - Read data from a client. + */ + +int /* O - 1 on success, 0 on error */ +cupsdReadClient(cupsd_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 */ + locale[64], /* Locale */ + *ptr; /* Pointer into strings */ + 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 */ + char buf[1024]; /* Buffer for real filename */ + struct stat filestats; /* File information */ + mime_type_t *type; /* MIME type of file */ + cupsd_printer_t *p; /* Printer */ + static unsigned request_id = 0; /* Request ID for temp files */ + + + status = HTTP_CONTINUE; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d, used=%d, file=%d state=%d", + con->http.fd, con->http.used, con->file, con->http.state); + + if (con->http.error) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: http error seen..."); + return (cupsdCloseClient(con)); + } + +#ifdef HAVE_SSL + if (con->auto_ssl) + { + /* + * Automatically check for a SSL/TLS handshake... + */ + + con->auto_ssl = 0; + + if (recv(con->http.fd, buf, 1, MSG_PEEK) == 1 && + (!buf[0] || !strchr("DGHOPT", buf[0]))) + { + /* + * Encrypt this connection... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: Saw first byte %02X, auto-negotiating SSL/TLS session...", + buf[0] & 255); + + cupsdEncryptClient(con); + return (1); + } + } +#endif /* HAVE_SSL */ + + switch (con->http.state) + { + case HTTP_WAITING : + /* + * See if we've received a request line... + */ + + if (httpGets(line, sizeof(line) - 1, HTTP(con)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: httpGets returned EOF..."); + return (cupsdCloseClient(con)); + } + + /* + * 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->http._data_remaining = 0; + con->operation = HTTP_WAITING; + con->bytes = 0; + con->file = -1; + con->file_ready = 0; + con->pipe_pid = 0; + con->username[0] = '\0'; + con->password[0] = '\0'; + con->uri[0] = '\0'; + + cupsdClearString(&con->command); + cupsdClearString(&con->options); + + 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 : + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad request line \"%s\" from %s!", line, + con->http.hostname); + cupsdSendError(con, HTTP_BAD_REQUEST); + return (cupsdCloseClient(con)); + case 2 : + con->http.version = HTTP_0_9; + break; + case 3 : + if (sscanf(version, "HTTP/%d.%d", &major, &minor) != 2) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad request line \"%s\" from %s!", line, + con->http.hostname); + cupsdSendError(con, HTTP_BAD_REQUEST); + return (cupsdCloseClient(con)); + } + + 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 + { + cupsdSendError(con, HTTP_NOT_SUPPORTED); + return (cupsdCloseClient(con)); + } + break; + } + + /* + * Handle full URLs in the request line... + */ + + if (strcmp(con->uri, "*")) + { + char method[HTTP_MAX_URI], /* Method/scheme */ + userpass[HTTP_MAX_URI], /* Username:password */ + hostname[HTTP_MAX_URI], /* Hostname */ + resource[HTTP_MAX_URI]; /* Resource path */ + int port; /* Port number */ + + + /* + * Separate the URI into its components... + */ + + httpSeparateURI(con->uri, method, sizeof(method), + userpass, sizeof(userpass), + hostname, sizeof(hostname), &port, + resource, sizeof(resource)); + + /* + * Only allow URIs with the servername, localhost, or an IP + * address... + */ + + if (strcmp(method, "file") && + strcasecmp(hostname, ServerName) && + strcasecmp(hostname, "localhost") && + !isdigit(hostname[0])) + { + /* + * Nope, we don't do proxies... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad URI \"%s\" in request!", + con->uri); + cupsdSendError(con, HTTP_METHOD_NOT_ALLOWED); + return (cupsdCloseClient(con)); + } + + /* + * Copy the resource portion back into the URI; both resource and + * con->uri are HTTP_MAX_URI bytes in size... + */ + + strcpy(con->uri, resource); + } + + /* + * Process the request... + */ + + if (!strcmp(operation, "GET")) + con->http.state = HTTP_GET; + else if (!strcmp(operation, "PUT")) + con->http.state = HTTP_PUT; + else if (!strcmp(operation, "POST")) + con->http.state = HTTP_POST; + else if (!strcmp(operation, "DELETE")) + con->http.state = HTTP_DELETE; + else if (!strcmp(operation, "TRACE")) + con->http.state = HTTP_TRACE; + else if (!strcmp(operation, "OPTIONS")) + con->http.state = HTTP_OPTIONS; + else if (!strcmp(operation, "HEAD")) + con->http.state = HTTP_HEAD; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad operation \"%s\"!", operation); + cupsdSendError(con, HTTP_BAD_REQUEST); + return (cupsdCloseClient(con)); + } + + con->start = time(NULL); + con->operation = con->http.state; + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReadClient: %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) + { + cupsdSendError(con, HTTP_BAD_REQUEST); + return (cupsdCloseClient(con)); + } + break; + + default : + break; /* Anti-compiler-warning-code */ + } + + /* + * Handle new transfers... + */ + + if (status == HTTP_OK) + { + if (con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE][0]) + { + /* + * Figure out the locale from the Accept-Language and Content-Type + * fields... + */ + + if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], ',')) != NULL) + *ptr = '\0'; + + if ((ptr = strchr(con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], ';')) != NULL) + *ptr = '\0'; + + if ((ptr = strstr(con->http.fields[HTTP_FIELD_CONTENT_TYPE], "charset=")) != NULL) + { + /* + * Combine language and charset, and trim any extra params in the + * content-type. + */ + + snprintf(locale, sizeof(locale), "%s.%s", + con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], ptr + 8); + + if ((ptr = strchr(locale, ',')) != NULL) + *ptr = '\0'; + } + else + snprintf(locale, sizeof(locale), "%s.%s", + con->http.fields[HTTP_FIELD_ACCEPT_LANGUAGE], DefaultCharset); + + con->language = cupsLangGet(locale); + } + else + con->language = cupsLangGet(DefaultLocale); + + cupsdAuthorize(con); + + if (!strncmp(con->http.fields[HTTP_FIELD_CONNECTION], "Keep-Alive", 10) && + KeepAlive) + con->http.keep_alive = HTTP_KEEPALIVE_ON; + + if (!con->http.fields[HTTP_FIELD_HOST][0] && + con->http.version >= HTTP_1_1) + { + /* + * HTTP/1.1 and higher require the "Host:" field... + */ + + if (!cupsdSendError(con, HTTP_BAD_REQUEST)) + return (cupsdCloseClient(con)); + } + else if (con->operation == HTTP_OPTIONS) + { + /* + * Do OPTIONS command... + */ + + if (con->best && con->best->type != AUTH_NONE) + { + if (!cupsdSendHeader(con, HTTP_UNAUTHORIZED, NULL)) + return (cupsdCloseClient(con)); + } + + if (!strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") && + con->http.tls == NULL) + { +#ifdef HAVE_SSL + /* + * Do encryption stuff... + */ + + if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL)) + return (cupsdCloseClient(con)); + + 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"); + + cupsdEncryptClient(con); +#else + if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED)) + return (cupsdCloseClient(con)); +#endif /* HAVE_SSL */ + } + + if (con->http.expect) + { + /**** TODO: send expected header ****/ + } + + if (!cupsdSendHeader(con, HTTP_OK, NULL)) + return (cupsdCloseClient(con)); + + 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 (!is_path_absolute(con->uri)) + { + /* + * Protect against malicious users! + */ + + if (!cupsdSendError(con, HTTP_FORBIDDEN)) + return (cupsdCloseClient(con)); + } + else + { + if (!strcasecmp(con->http.fields[HTTP_FIELD_CONNECTION], "Upgrade") && + con->http.tls == NULL) + { +#ifdef HAVE_SSL + /* + * Do encryption stuff... + */ + + if (!cupsdSendHeader(con, HTTP_SWITCHING_PROTOCOLS, NULL)) + return (cupsdCloseClient(con)); + + 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"); + + cupsdEncryptClient(con); +#else + if (!cupsdSendError(con, HTTP_NOT_IMPLEMENTED)) + return (cupsdCloseClient(con)); +#endif /* HAVE_SSL */ + } + + if ((status = cupsdIsAuthorized(con, NULL)) != HTTP_OK) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: Unauthorized request for %s...\n", + con->uri); + cupsdSendError(con, status); + return (cupsdCloseClient(con)); + } + + if (con->http.expect) + { + /**** TODO: send expected header ****/ + } + + switch (con->http.state) + { + case HTTP_GET_SEND : + if (!strncmp(con->uri, "/printers/", 10) && + !strcmp(con->uri + strlen(con->uri) - 4, ".ppd")) + { + /* + * 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 = cupsdFindPrinter(con->uri + 10)) != NULL) + snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name); + else + { + if (!cupsdSendError(con, HTTP_NOT_FOUND)) + return (cupsdCloseClient(con)); + + break; + } + } + + if ((!strncmp(con->uri, "/admin", 6) && + strncmp(con->uri, "/admin/conf/", 12) && + strncmp(con->uri, "/admin/log/", 11)) || + !strncmp(con->uri, "/printers", 9) || + !strncmp(con->uri, "/classes", 8) || + !strncmp(con->uri, "/help", 5) || + !strncmp(con->uri, "/jobs", 5)) + { + /* + * Send CGI output... + */ + + if (!strncmp(con->uri, "/admin", 6)) + { + cupsdSetStringf(&con->command, "%s/cgi-bin/admin.cgi", + ServerBin); + + if ((ptr = strchr(con->uri + 6, '?')) != NULL) + cupsdSetStringf(&con->options, "admin%s", ptr); + else + cupsdSetString(&con->options, "admin"); + } + else if (!strncmp(con->uri, "/printers", 9)) + { + cupsdSetStringf(&con->command, "%s/cgi-bin/printers.cgi", + ServerBin); + cupsdSetString(&con->options, con->uri + 9); + } + else if (!strncmp(con->uri, "/classes", 8)) + { + cupsdSetStringf(&con->command, "%s/cgi-bin/classes.cgi", + ServerBin); + cupsdSetString(&con->options, con->uri + 8); + } + else if (!strncmp(con->uri, "/jobs", 5)) + { + cupsdSetStringf(&con->command, "%s/cgi-bin/jobs.cgi", + ServerBin); + cupsdSetString(&con->options, con->uri + 5); + } + else + { + cupsdSetStringf(&con->command, "%s/cgi-bin/help.cgi", + ServerBin); + cupsdSetString(&con->options, con->uri + 5); + } + + if (con->options[0] == '/') + _cups_strcpy(con->options, con->options + 1); + + if (!cupsdSendCommand(con, con->command, con->options, 0)) + { + if (!cupsdSendError(con, HTTP_NOT_FOUND)) + return (cupsdCloseClient(con)); + } + else + cupsdLogRequest(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) && + (strchr(con->uri + 12, '/') || + strlen(con->uri) == 12)) || + (!strncmp(con->uri, "/admin/log/", 11) && + (strchr(con->uri + 11, '/') || + strlen(con->uri) == 11))) + { + /* + * GET can only be done to configuration files under + * /admin/conf... + */ + + if (!cupsdSendError(con, HTTP_FORBIDDEN)) + return (cupsdCloseClient(con)); + + break; + } + else + { + /* + * Serve a file... + */ + + if ((filename = get_file(con, &filestats, buf, + sizeof(buf))) == NULL) + { + if (!cupsdSendError(con, HTTP_NOT_FOUND)) + return (cupsdCloseClient(con)); + + break; + } + + type = mimeFileType(MimeDatabase, filename, NULL); + + if (cupsdIsCGI(con, filename, &filestats, type)) + { + /* + * Note: con->command and con->options were set by + * cupsdIsCGI()... + */ + + if (!cupsdSendCommand(con, con->command, con->options, 0)) + { + if (!cupsdSendError(con, HTTP_NOT_FOUND)) + return (cupsdCloseClient(con)); + } + else + cupsdLogRequest(con, HTTP_OK); + + if (con->http.version <= HTTP_1_0) + con->http.keep_alive = HTTP_KEEPALIVE_OFF; + break; + } + + if (!check_if_modified(con, &filestats)) + { + if (!cupsdSendError(con, HTTP_NOT_MODIFIED)) + return (cupsdCloseClient(con)); + } + else + { + if (type == NULL) + strcpy(line, "text/plain"); + else + snprintf(line, sizeof(line), "%s/%s", type->super, type->type); + + if (!cupsdSendFile(con, HTTP_OK, filename, line, &filestats)) + return (cupsdCloseClient(con)); + } + } + 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... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "POST %s", con->uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "CONTENT_TYPE = %s", + con->http.fields[HTTP_FIELD_CONTENT_TYPE]); + + if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] && + MaxRequestSize > 0 && + con->http.data_remaining > MaxRequestSize) + { + /* + * Request too large... + */ + + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + return (cupsdCloseClient(con)); + + break; + } + else if (con->http.data_remaining < 0) + { + /* + * Negative content lengths are invalid! + */ + + if (!cupsdSendError(con, HTTP_BAD_REQUEST)) + return (cupsdCloseClient(con)); + + 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")) + con->request = ippNew(); + else if ((!strncmp(con->uri, "/admin", 6) && + strncmp(con->uri, "/admin/conf/", 12) && + strncmp(con->uri, "/admin/log/", 11)) || + !strncmp(con->uri, "/printers", 9) || + !strncmp(con->uri, "/classes", 8) || + !strncmp(con->uri, "/help", 5) || + !strncmp(con->uri, "/jobs", 5)) + { + /* + * CGI request... + */ + + if (!strncmp(con->uri, "/admin", 6)) + { + cupsdSetStringf(&con->command, "%s/cgi-bin/admin.cgi", + ServerBin); + + if ((ptr = strchr(con->uri + 6, '?')) != NULL) + cupsdSetStringf(&con->options, "admin%s", ptr); + else + cupsdSetString(&con->options, "admin"); + } + else if (!strncmp(con->uri, "/printers", 9)) + { + cupsdSetStringf(&con->command, "%s/cgi-bin/printers.cgi", + ServerBin); + cupsdSetString(&con->options, con->uri + 9); + } + else if (!strncmp(con->uri, "/classes", 8)) + { + cupsdSetStringf(&con->command, "%s/cgi-bin/classes.cgi", + ServerBin); + cupsdSetString(&con->options, con->uri + 8); + } + else if (!strncmp(con->uri, "/jobs", 5)) + { + cupsdSetStringf(&con->command, "%s/cgi-bin/jobs.cgi", + ServerBin); + cupsdSetString(&con->options, con->uri + 5); + } + else + { + cupsdSetStringf(&con->command, "%s/cgi-bin/help.cgi", + ServerBin); + cupsdSetString(&con->options, con->uri + 5); + } + + if (con->options[0] == '/') + _cups_strcpy(con->options, con->options + 1); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %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 + { + /* + * POST to a file... + */ + + if ((filename = get_file(con, &filestats, buf, + sizeof(buf))) == NULL) + { + if (!cupsdSendError(con, HTTP_NOT_FOUND)) + return (cupsdCloseClient(con)); + + break; + } + + type = mimeFileType(MimeDatabase, filename, NULL); + + if (!cupsdIsCGI(con, filename, &filestats, type)) + { + /* + * Only POST to CGI's... + */ + + if (!cupsdSendError(con, HTTP_UNAUTHORIZED)) + return (cupsdCloseClient(con)); + } + } + break; + + case HTTP_PUT_RECV : + /* + * Validate the resource name... + */ + + if (strncmp(con->uri, "/admin/conf/", 12) || + strchr(con->uri + 12, '/') || + strlen(con->uri) == 12) + { + /* + * PUT can only be done to configuration files under + * /admin/conf... + */ + + if (!cupsdSendError(con, HTTP_FORBIDDEN)) + return (cupsdCloseClient(con)); + + break; + } + + /* + * See if the PUT request includes a Content-Length field, and if + * so check the length against any limits that are set... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "PUT %s", con->uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "CONTENT_TYPE = %s", + con->http.fields[HTTP_FIELD_CONTENT_TYPE]); + + if (con->http.fields[HTTP_FIELD_CONTENT_LENGTH][0] && + MaxRequestSize > 0 && + con->http.data_remaining > MaxRequestSize) + { + /* + * Request too large... + */ + + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + return (cupsdCloseClient(con)); + + break; + } + else if (con->http.data_remaining < 0) + { + /* + * Negative content lengths are invalid! + */ + + if (!cupsdSendError(con, HTTP_BAD_REQUEST)) + return (cupsdCloseClient(con)); + + break; + } + + /* + * Open a temporary file to hold the request... + */ + + cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, + request_id ++); + con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d REQUEST %s=%d", con->http.fd, + con->filename, con->file); + + if (con->file < 0) + { + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + return (cupsdCloseClient(con)); + } + + fchmod(con->file, 0640); + fchown(con->file, RunUser, Group); + fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC); + break; + + case HTTP_DELETE : + case HTTP_TRACE : + cupsdSendError(con, HTTP_NOT_IMPLEMENTED); + return (cupsdCloseClient(con)); + + case HTTP_HEAD : + if (!strncmp(con->uri, "/printers/", 10) && + !strcmp(con->uri + strlen(con->uri) - 4, ".ppd")) + { + /* + * 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 = cupsdFindPrinter(con->uri + 10)) != NULL) + snprintf(con->uri, sizeof(con->uri), "/ppd/%s.ppd", p->name); + else + { + if (!cupsdSendError(con, HTTP_NOT_FOUND)) + return (cupsdCloseClient(con)); + + break; + } + } + + if ((!strncmp(con->uri, "/admin", 6) && + strncmp(con->uri, "/admin/conf/", 12) && + strncmp(con->uri, "/admin/log/", 11)) || + !strncmp(con->uri, "/printers", 9) || + !strncmp(con->uri, "/classes", 8) || + !strncmp(con->uri, "/help", 5) || + !strncmp(con->uri, "/jobs", 5)) + { + /* + * CGI output... + */ + + if (!cupsdSendHeader(con, HTTP_OK, "text/html")) + return (cupsdCloseClient(con)); + + if (httpPrintf(HTTP(con), "\r\n") < 0) + return (cupsdCloseClient(con)); + + cupsdLogRequest(con, HTTP_OK); + } + else if ((!strncmp(con->uri, "/admin/conf/", 12) && + (strchr(con->uri + 12, '/') || + strlen(con->uri) == 12)) || + (!strncmp(con->uri, "/admin/log/", 11) && + (strchr(con->uri + 11, '/') || + strlen(con->uri) == 11))) + { + /* + * HEAD can only be done to configuration files under + * /admin/conf... + */ + + if (!cupsdSendError(con, HTTP_FORBIDDEN)) + return (cupsdCloseClient(con)); + + break; + } + else if ((filename = get_file(con, &filestats, buf, + sizeof(buf))) == NULL) + { + if (!cupsdSendHeader(con, HTTP_NOT_FOUND, "text/html")) + return (cupsdCloseClient(con)); + + cupsdLogRequest(con, HTTP_NOT_FOUND); + } + else if (!check_if_modified(con, &filestats)) + { + if (!cupsdSendError(con, HTTP_NOT_MODIFIED)) + return (cupsdCloseClient(con)); + + cupsdLogRequest(con, HTTP_NOT_MODIFIED); + } + else + { + /* + * Serve a file... + */ + + type = mimeFileType(MimeDatabase, filename, NULL); + if (type == NULL) + strcpy(line, "text/plain"); + else + snprintf(line, sizeof(line), "%s/%s", type->super, type->type); + + if (!cupsdSendHeader(con, HTTP_OK, line)) + return (cupsdCloseClient(con)); + + if (httpPrintf(HTTP(con), "Last-Modified: %s\r\n", + httpGetDateString(filestats.st_mtime)) < 0) + return (cupsdCloseClient(con)); + + if (httpPrintf(HTTP(con), "Content-Length: %lu\r\n", + (unsigned long)filestats.st_size) < 0) + return (cupsdCloseClient(con)); + + cupsdLogRequest(con, HTTP_OK); + } + + if (httpPrintf(HTTP(con), "\r\n") < 0) + return (cupsdCloseClient(con)); + + con->http.state = HTTP_WAITING; + break; + + default : + break; /* Anti-compiler-warning-code */ + } + } + } + + /* + * Handle any incoming data... + */ + + switch (con->http.state) + { + case HTTP_PUT_RECV : + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d con->data_encoding=HTTP_ENCODE_%s, " + "con->data_remaining=" CUPS_LLFMT ", con->file=%d", + con->http.fd, + con->http.data_encoding == HTTP_ENCODE_CHUNKED ? + "CHUNKED" : "LENGTH", + CUPS_LLCAST con->http.data_remaining, con->file); + + if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0) + return (cupsdCloseClient(con)); + else if (bytes > 0) + { + con->bytes += bytes; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d writing %d bytes to %d", + con->http.fd, bytes, con->file); + + if (write(con->file, line, bytes) < bytes) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdReadClient: Unable to write %d bytes to %s: %s", + bytes, con->filename, strerror(errno)); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: Closing data file %d...", + con->file); + + close(con->file); + con->file = -1; + unlink(con->filename); + cupsdClearString(&con->filename); + + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + return (cupsdCloseClient(con)); + } + } + + if (con->http.state == HTTP_WAITING) + { + /* + * End of file, see how big it is... + */ + + fstat(con->file, &filestats); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d Closing data file %d, size=" + CUPS_LLFMT ".", + con->http.fd, con->file, + CUPS_LLCAST filestats.st_size); + + close(con->file); + con->file = -1; + + if (filestats.st_size > MaxRequestSize && + MaxRequestSize > 0) + { + /* + * Request is too big; remove it and send an error... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d Removing temp file %s", + con->http.fd, con->filename); + unlink(con->filename); + cupsdClearString(&con->filename); + + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + return (cupsdCloseClient(con)); + } + + /* + * Install the configuration file... + */ + + status = install_conf_file(con); + + /* + * Return the status to the client... + */ + + if (!cupsdSendError(con, status)) + return (cupsdCloseClient(con)); + } + break; + + case HTTP_POST_RECV : + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d con->data_encoding=HTTP_ENCODE_" + "%s, con->data_remaining=" CUPS_LLFMT ", con->file=%d", + con->http.fd, + con->http.data_encoding == HTTP_ENCODE_CHUNKED ? + "CHUNKED" : "LENGTH", + CUPS_LLCAST 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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdReadClient: %d IPP Read Error!", + con->http.fd); + + cupsdSendError(con, HTTP_BAD_REQUEST); + return (cupsdCloseClient(con)); + } + else if (ipp_state != IPP_DATA) + { + if (con->http.state == HTTP_POST_SEND) + { + cupsdSendError(con, HTTP_BAD_REQUEST); + return (cupsdCloseClient(con)); + } + + 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... + */ + + cupsdSetStringf(&con->filename, "%s/%08x", RequestRoot, request_id ++); + con->file = open(con->filename, O_WRONLY | O_CREAT | O_TRUNC, 0640); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdReadClient: %d REQUEST %s=%d", con->http.fd, + con->filename, con->file); + + if (con->file < 0) + { + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + return (cupsdCloseClient(con)); + } + + fchmod(con->file, 0640); + fchown(con->file, RunUser, Group); + fcntl(con->file, F_SETFD, fcntl(con->file, F_GETFD) | FD_CLOEXEC); + } + + if (con->http.state != HTTP_POST_SEND) + { + if ((bytes = httpRead(HTTP(con), line, sizeof(line))) < 0) + return (cupsdCloseClient(con)); + else if (bytes > 0) + { + con->bytes += bytes; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d writing %d bytes to %d", + con->http.fd, bytes, con->file); + + if (write(con->file, line, bytes) < bytes) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdReadClient: Unable to write %d bytes to %s: %s", + bytes, con->filename, strerror(errno)); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: Closing file %d...", + con->file); + + close(con->file); + con->file = -1; + unlink(con->filename); + cupsdClearString(&con->filename); + + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + return (cupsdCloseClient(con)); + } + } + else if (con->http.state == HTTP_POST_RECV) + return (1); /* ??? */ + else if (con->http.state != HTTP_POST_SEND) + return (cupsdCloseClient(con)); + } + + if (con->http.state == HTTP_POST_SEND) + { + if (con->file >= 0) + { + fstat(con->file, &filestats); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d Closing data file %d, " + "size=" CUPS_LLFMT ".", + con->http.fd, con->file, + CUPS_LLCAST filestats.st_size); + + close(con->file); + con->file = -1; + + if (filestats.st_size > MaxRequestSize && + MaxRequestSize > 0) + { + /* + * Request is too big; remove it and send an error... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdReadClient: %d Removing temp file %s", + con->http.fd, con->filename); + unlink(con->filename); + cupsdClearString(&con->filename); + + if (con->request) + { + /* + * Delete any IPP request data... + */ + + ippDelete(con->request); + con->request = NULL; + } + + if (!cupsdSendError(con, HTTP_REQUEST_TOO_LARGE)) + return (cupsdCloseClient(con)); + } + + if (con->command) + { + if (!cupsdSendCommand(con, con->command, con->options, 0)) + { + if (!cupsdSendError(con, HTTP_NOT_FOUND)) + return (cupsdCloseClient(con)); + } + else + cupsdLogRequest(con, HTTP_OK); + } + } + + if (con->request) + return (cupsdProcessIPPRequest(con)); + } + break; + + default : + break; /* Anti-compiler-warning-code */ + } + + if (!con->http.keep_alive && con->http.state == HTTP_WAITING) + return (cupsdCloseClient(con)); + else + return (1); +} + + +/* + * 'cupsdSendCommand()' - Send output from a command via HTTP. + */ + +int /* O - 1 on success, 0 on failure */ +cupsdSendCommand( + cupsd_client_t *con, /* I - Client connection */ + char *command, /* I - Command to run */ + char *options, /* I - Command-line options */ + int root) /* I - Run as root? */ +{ + int fd; /* Standard input file descriptor */ + + + if (con->filename) + fd = open(con->filename, O_RDONLY); + else + fd = open("/dev/null", O_RDONLY); + + if (fd < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdSendCommand: %d Unable to open \"%s\" for reading: %s", + con->http.fd, con->filename ? con->filename : "/dev/null", + strerror(errno)); + return (0); + } + + fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC); + + con->pipe_pid = pipe_command(con, fd, &(con->file), command, options, root); + + close(fd); + + cupsdLogMessage(CUPSD_LOG_INFO, "Started \"%s\" (pid=%d)", command, + con->pipe_pid); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendCommand: %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); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSendCommand: Adding fd %d to InputSet...", con->file); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSendCommand: Adding fd %d to OutputSet...", + con->http.fd); + + FD_SET(con->file, InputSet); + FD_SET(con->http.fd, OutputSet); + + con->sent_header = 0; + con->file_ready = 0; + con->got_fields = 0; + con->field_col = 0; + + return (1); +} + + +/* + * 'cupsdSendError()' - Send an error message via HTTP. + */ + +int /* O - 1 if successful, 0 otherwise */ +cupsdSendError(cupsd_client_t *con, /* I - Connection */ + http_status_t code) /* I - Error code */ +{ + /* + * Put the request in the access_log file... + */ + + cupsdLogRequest(con, code); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendError: %d code=%d (%s)", + con->http.fd, code, httpStatus(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 (!cupsdSendHeader(con, code, NULL)) + return (0); + +#ifdef HAVE_SSL + 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_SSL */ + + if ((con->http.version >= HTTP_1_1 && !con->http.keep_alive) || + (code >= HTTP_BAD_REQUEST && code != HTTP_UPGRADE_REQUIRED)) + { + if (httpPrintf(HTTP(con), "Connection: close\r\n") < 0) + return (0); + } + + if (code >= HTTP_BAD_REQUEST) + { + /* + * Send a human-readable error message. + */ + + char message[1024]; /* Message for user */ + const char *text; /* Status-specific text */ + + if (code == HTTP_UNAUTHORIZED) + text = _cupsLangString(con->language, + _("Enter your username and password or the " + "root username and password to access this " + "page.")); + else if (code == HTTP_UPGRADE_REQUIRED) + text = _cupsLangString(con->language, + _("You must use a https: URL to access this " + "page.")); + else + text = ""; + + snprintf(message, sizeof(message), + "\n" + "\n" + "\n" + "\t\n" + "\t%d %s\n" + "\t\n" + "\n" + "\n" + "

    %d %s

    \n" + "

    %s

    \n" + "\n" + "\n", + code, httpStatus(code), code, httpStatus(code), text); + + if (httpPrintf(HTTP(con), "Content-Type: text/html; charset=utf-8\r\n") < 0) + return (0); + if (httpPrintf(HTTP(con), "Content-Length: %d\r\n", + (int)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); +} + + +/* + * 'cupsdSendFile()' - Send a file via HTTP. + */ + +int /* O - 0 on failure, 1 on success */ +cupsdSendFile(cupsd_client_t *con, /* I - Client connection */ + http_status_t code, /* I - HTTP status */ + char *filename, /* I - Filename */ + char *type, /* I - File type */ + struct stat *filestats)/* O - File information */ +{ + con->file = open(filename, O_RDONLY); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendFile: %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 (!cupsdSendHeader(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: " CUPS_LLFMT "\r\n", + CUPS_LLCAST filestats->st_size) < 0) + return (0); + if (httpPrintf(HTTP(con), "\r\n") < 0) + return (0); + + con->http.data_encoding = HTTP_ENCODE_LENGTH; + con->http.data_remaining = filestats->st_size; + + if (con->http.data_remaining <= INT_MAX) + con->http._data_remaining = con->http.data_remaining; + else + con->http._data_remaining = INT_MAX; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSendFile: Adding fd %d to OutputSet...", con->http.fd); + + FD_SET(con->http.fd, OutputSet); + + return (1); +} + + +/* + * 'cupsdSendHeader()' - Send an HTTP request. + */ + +int /* O - 1 on success, 0 on failure */ +cupsdSendHeader(cupsd_client_t *con, /* I - Client to send to */ + http_status_t code, /* I - HTTP status code */ + char *type) /* I - MIME type of document */ +{ + 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 (ServerHeader) + if (httpPrintf(HTTP(con), "Server: %s\r\n", ServerHeader) < 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) + { + int auth_type; /* Authentication type */ + + + if (!con->best || con->best->type == AUTH_NONE) + auth_type = DefaultAuthType; + else + auth_type = con->best->type; + + if (auth_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 (!strcmp(type, "text/html")) + { + if (httpPrintf(HTTP(con), + "Content-Type: text/html; charset=utf-8\r\n") < 0) + return (0); + } + else if (httpPrintf(HTTP(con), "Content-Type: %s\r\n", type) < 0) + return (0); + } + + return (1); +} + + +/* + * 'cupsdUpdateCGI()' - Read status messages from CGI scripts and programs. + */ + +void +cupsdUpdateCGI(void) +{ + char *ptr, /* Pointer to end of line in buffer */ + message[1024]; /* Pointer to message text */ + int loglevel; /* Log level for message */ + + + while ((ptr = cupsdStatBufUpdate(CGIStatusBuffer, &loglevel, + message, sizeof(message))) != NULL) + if (!strchr(CGIStatusBuffer->buffer, '\n')) + break; + + if (ptr == NULL && errno) + { + /* + * Fatal error on pipe - should never happen! + */ + + cupsdLogMessage(CUPSD_LOG_CRIT, + "cupsdUpdateCGI: error reading from CGI error pipe - %s", + strerror(errno)); + } +} + + +/* + * 'cupsdWriteClient()' - Write data to a client as needed. + */ + +int /* O - 1 if success, 0 if fail */ +cupsdWriteClient(cupsd_client_t *con) /* I - Client connection */ +{ + int bytes; /* Number of bytes written */ + char buf[16385]; /* Data buffer */ + char *bufptr; /* Pointer into buffer */ + ipp_state_t ipp_state; /* IPP state value */ + + +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient(con=%p) %d response=%p, file=%d " + "pipe_pid=%d state=%d", + con, con->http.fd, con->response, con->file, con->pipe_pid, + con->http.state); +#endif /* DEBUG */ + + 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, sizeof(buf) - 1)) > 0) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient: Read %d bytes from file %d...", + bytes, con->file); + + 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'; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "Script header: %s", buf); + + if (!con->sent_header) + { + /* + * Handle redirection and CGI status codes... + */ + + if (!strncasecmp(buf, "Location:", 9)) + cupsdSendHeader(con, HTTP_SEE_OTHER, NULL); + else if (!strncasecmp(buf, "Status:", 7)) + cupsdSendHeader(con, atoi(buf + 7), NULL); + else + cupsdSendHeader(con, HTTP_OK, NULL); + + 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->sent_header = 1; + } + + if (strncasecmp(buf, "Status:", 7)) + httpPrintf(HTTP(con), "%s\r\n", buf); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdWriteClient: %d %s", + con->http.fd, buf); + + /* + * Update buffer... + */ + + bytes -= (bufptr - buf); + memmove(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 ++; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient: %d bytes=%d, got_fields=%d", + con->http.fd, bytes, con->got_fields); + + 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) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient: %d Write of %d bytes failed!", + con->http.fd, bytes); + + cupsdCloseClient(con); + return (0); + } + + con->bytes += bytes; + + if (con->http.state == HTTP_WAITING) + bytes = 0; + } + + if (bytes <= 0) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdWriteClient: %d bytes < 0", + con->http.fd); + + cupsdLogRequest(con, HTTP_OK); + + httpFlushWrite(HTTP(con)); + + if (con->http.data_encoding == HTTP_ENCODE_CHUNKED) + { + if (httpPrintf(HTTP(con), "0\r\n\r\n") < 0) + { + cupsdCloseClient(con); + return (0); + } + } + + con->http.state = HTTP_WAITING; + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient: Removing fd %d from OutputSet...", + con->http.fd); + + FD_CLR(con->http.fd, OutputSet); + + if (con->file >= 0) + { + if (FD_ISSET(con->file, InputSet)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient: Removing fd %d from InputSet...", + con->file); + FD_CLR(con->file, InputSet); + } + + if (con->pipe_pid) + cupsdEndProcess(con->pipe_pid, 0); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient: %d Closing data file %d.", + con->http.fd, con->file); + + close(con->file); + con->file = -1; + con->pipe_pid = 0; + } + + if (con->filename) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient: %d Removing temp file %s", + con->http.fd, con->filename); + unlink(con->filename); + cupsdClearString(&con->filename); + } + + if (con->request != NULL) + { + ippDelete(con->request); + con->request = NULL; + } + + if (con->response != NULL) + { + ippDelete(con->response); + con->response = NULL; + } + + cupsdClearString(&con->command); + cupsdClearString(&con->options); + + if (!con->http.keep_alive) + { + cupsdCloseClient(con); + return (0); + } + } + else + { + con->file_ready = 0; + + if (con->pipe_pid && !FD_ISSET(con->file, InputSet)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdWriteClient: Adding fd %d to InputSet...", + con->file); + FD_SET(con->file, InputSet); + } + } + + 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( + cupsd_client_t *con, /* I - Client connection */ + struct stat *filestats) /* I - File information */ +{ + char *ptr; /* Pointer into field */ + time_t date; /* Time/date value */ + off_t size; /* Size/length value */ + + + size = 0; + date = 0; + ptr = con->http.fields[HTTP_FIELD_IF_MODIFIED_SINCE]; + + if (*ptr == '\0') + return (1); + + cupsdLogMessage(CUPSD_LOG_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 = strtoll(ptr, NULL, 10); + + while (isdigit(*ptr)) + ptr ++; + } + else if (isalpha(*ptr)) + { + date = httpGetDateTime(ptr); + while (*ptr != '\0' && *ptr != ';') + ptr ++; + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "check_if_modified: %d sizes=" CUPS_LLFMT "," + CUPS_LLFMT " dates=%d,%d", + con->http.fd, CUPS_LLCAST size, + CUPS_LLCAST filestats->st_size, (int)date, + (int)filestats->st_mtime); + + return ((size != filestats->st_size && size != 0) || + (date < filestats->st_mtime && date != 0) || + (size == 0 && date == 0)); +} + + +#ifdef HAVE_CDSASSL +/* + * 'get_cdsa_server_certs()' - Convert a keychain name into the CFArrayRef + * required by SSLSetCertificate. + * + * For now we assumes that there is exactly one SecIdentity in the + * keychain - i.e. there is exactly one matching cert/private key pair. + * In the future we will search a keychain for a SecIdentity matching a + * specific criteria. We also skip the operation of adding additional + * non-signing certs from the keychain to the CFArrayRef. + * + * To create a self-signed certificate for testing use the certtool. + * Executing the following as root will do it: + * + * certtool c c v k=CUPS + */ + +static CFArrayRef /* O - Array of certificates */ +get_cdsa_server_certs(void) +{ + OSStatus err; /* Error info */ + SecKeychainRef kcRef; /* Keychain reference */ + SecIdentitySearchRef srchRef; /* Search reference */ + SecIdentityRef identity; /* Identity */ + CFArrayRef ca; /* Certificate array */ + + + kcRef = NULL; + srchRef = NULL; + identity = NULL; + ca = NULL; + err = SecKeychainOpen(ServerCertificate, &kcRef); + + if (err) + cupsdLogMessage(CUPSD_LOG_ERROR, "Cannot open keychain \"%s\", error %d.", + ServerCertificate, (int)err); + else + { + /* + * Search for "any" identity matching specified key use; + * in this app, we expect there to be exactly one. + */ + + err = SecIdentitySearchCreate(kcRef, CSSM_KEYUSE_SIGN, &srchRef); + + if (err) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "Cannot find signing key in keychain \"%s\", error %d", + ServerCertificate, (int)err); + else + { + err = SecIdentitySearchCopyNext(srchRef, &identity); + + if (err) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "Cannot find signing key in keychain \"%s\", error %d", + ServerCertificate, (int)err); + else + { + if (CFGetTypeID(identity) != SecIdentityGetTypeID()) + cupsdLogMessage(CUPSD_LOG_ERROR, + "SecIdentitySearchCopyNext CFTypeID failure!"); + else + { + /* + * Found one. Place it in a CFArray. + * TBD: snag other (non-identity) certs from keychain and add them + * to array as well. + */ + + ca = CFArrayCreate(NULL, (const void **)&identity, 1, NULL); + + if (ca == nil) + cupsdLogMessage(CUPSD_LOG_ERROR, "CFArrayCreate error"); + } + + /*CFRelease(identity);*/ + } + + /*CFRelease(srchRef);*/ + } + + /*CFRelease(kcRef);*/ + } + + return (ca); +} +#endif /* HAVE_CDSASSL */ + + +/* + * 'get_file()' - Get a filename and state info. + */ + +static char * /* O - Real filename */ +get_file(cupsd_client_t *con, /* I - Client connection */ + struct stat *filestats, /* O - File information */ + char *filename, /* IO - Filename buffer */ + int len) /* I - Buffer length */ +{ + int status; /* Status of filesystem calls */ + char *ptr; /* Pointer info filename */ + int plen; /* Remaining length after pointer */ + + + /* + * Need to add DocumentRoot global... + */ + + if (!strncmp(con->uri, "/ppd/", 5)) + snprintf(filename, len, "%s%s", ServerRoot, con->uri); + else if (!strncmp(con->uri, "/admin/conf/", 12)) + snprintf(filename, len, "%s%s", ServerRoot, con->uri + 11); + else if (!strncmp(con->uri, "/admin/log/", 11)) + { + if (!strcmp(con->uri + 11, "access_log") && AccessLog[0] == '/') + strlcpy(filename, AccessLog, len); + else if (!strcmp(con->uri + 11, "error_log") && ErrorLog[0] == '/') + strlcpy(filename, ErrorLog, len); + else if (!strcmp(con->uri + 11, "page_log") && PageLog[0] == '/') + strlcpy(filename, PageLog, len); + else + return (NULL); + } + else if (con->language != NULL) + snprintf(filename, len, "%s/%s%s", DocumentRoot, con->language->language, + con->uri); + else + snprintf(filename, len, "%s%s", DocumentRoot, con->uri); + + if ((ptr = strchr(filename, '?')) != NULL) + *ptr = '\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) && + strncmp(con->uri, "/admin/conf/", 12) && + strncmp(con->uri, "/admin/log/", 11)) + { + snprintf(filename, len, "%s%s", DocumentRoot, con->uri); + + if ((ptr = strchr(filename, '?')) != NULL) + *ptr = '\0'; + + 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] != '/') + strlcat(filename, "/", len); + + ptr = filename + strlen(filename); + plen = len - (ptr - filename); + + strlcpy(ptr, "index.html", plen); + status = stat(filename, filestats); + +#ifdef HAVE_JAVA + if (status) + { + strlcpy(ptr, "index.class", plen); + status = stat(filename, filestats); + } +#endif /* HAVE_JAVA */ + +#ifdef HAVE_PERL + if (status) + { + strlcpy(ptr, "index.pl", plen); + status = stat(filename, filestats); + } +#endif /* HAVE_PERL */ + +#ifdef HAVE_PHP + if (status) + { + strlcpy(ptr, "index.php", plen); + status = stat(filename, filestats); + } +#endif /* HAVE_PHP */ + +#ifdef HAVE_PYTHON + if (status) + { + strlcpy(ptr, "index.pyc", plen); + status = stat(filename, filestats); + } + + if (status) + { + strlcpy(ptr, "index.py", plen); + status = stat(filename, filestats); + } +#endif /* HAVE_PYTHON */ + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_file: %d filename=%s size=%d", + con->http.fd, filename, + status ? -1 : (int)filestats->st_size); + + if (!status) + con->http.data_remaining = (int)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(cupsd_client_t *con) /* I - Connection */ +{ + cups_file_t *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); + + cupsdLogMessage(CUPSD_LOG_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 = ConfigFilePerm; + } + + /* + * Open the request file and new config file... + */ + + if ((in = cupsFileOpen(con->filename, "rb")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open request file \"%s\" - %s", + con->filename, strerror(errno)); + return (HTTP_SERVER_ERROR); + } + + if ((out = cupsFileOpen(newfile, "wb")) == NULL) + { + cupsFileClose(in); + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open config file \"%s\" - %s", + newfile, strerror(errno)); + return (HTTP_SERVER_ERROR); + } + + fchmod(cupsFileNumber(out), confinfo.st_mode); + fchown(cupsFileNumber(out), confinfo.st_uid, confinfo.st_gid); + + /* + * Copy from the request to the new config file... + */ + + while ((bytes = cupsFileRead(in, buffer, sizeof(buffer))) > 0) + if (cupsFileWrite(out, buffer, bytes) < bytes) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to copy to config file \"%s\" - %s", + newfile, strerror(errno)); + + cupsFileClose(in); + cupsFileClose(out); + unlink(newfile); + + return (HTTP_SERVER_ERROR); + } + + /* + * Close the files... + */ + + cupsFileClose(in); + if (cupsFileClose(out)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Error file closing config file \"%s\" - %s", + newfile, strerror(errno)); + + unlink(newfile); + + return (HTTP_SERVER_ERROR); + } + + /* + * Remove the request file... + */ + + unlink(con->filename); + cupsdClearString(&con->filename); + + /* + * 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) + { + cupsdLogMessage(CUPSD_LOG_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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to rename old config file \"%s\" - %s", + conffile, strerror(errno)); + + unlink(newfile); + + return (HTTP_SERVER_ERROR); + } + + if (rename(newfile, conffile)) + { + cupsdLogMessage(CUPSD_LOG_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")) + NeedReload = RELOAD_CUPSD; + else + NeedReload = RELOAD_ALL; + + ReloadTime = time(NULL); + + /* + * Return that the file was created successfully... + */ + + return (HTTP_CREATED); +} + + +/* + * 'is_path_absolute()' - Is a path absolute and free of relative elements (i.e. ".."). + */ + +static int /* O - 0 if relative, 1 if absolute */ +is_path_absolute(const char *path) /* I - Input path */ +{ + /* + * Check for a leading slash... + */ + + if (path[0] != '/') + return (0); + + /* + * Check for "/.." in the path... + */ + + while ((path = strstr(path, "/..")) != NULL) + { + if (!path[3] || path[3] == '/') + return (0); + + path ++; + } + + /* + * If we haven't found any relative paths, return 1 indicating an + * absolute path... + */ + + return (1); +} + + +/* + * 'pipe_command()' - Pipe the output of a command to the remote client. + */ + +static int /* O - Process ID */ +pipe_command(cupsd_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 root) /* I - Run as root? */ +{ + int i; /* Looping var */ + int pid; /* Process ID */ + char *commptr; /* Command string pointer */ + char *uriptr; /* URI string pointer */ + 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 content_length[1024], /* CONTENT_LENGTH environment variable */ + content_type[1024], /* CONTENT_TYPE environment variable */ + http_cookie[32768], /* HTTP_COOKIE environment variable */ + http_user_agent[1024], /* HTTP_USER_AGENT environment variable */ + lang[1024], /* LANG environment variable */ + *query_string, /* QUERY_STRING env variable */ + remote_addr[1024], /* REMOTE_ADDR environment variable */ + remote_host[1024], /* REMOTE_HOST environment variable */ + remote_user[1024], /* REMOTE_USER environment variable */ + script_name[1024], /* SCRIPT_NAME environment variable */ + server_name[1024], /* SERVER_NAME environment variable */ + server_port[1024]; /* SERVER_PORT environment variable */ + + + /* + * Parse a copy of the options string, which is of the form: + * + * name argument+argument+argument + * name?argument+argument+argument + * name param=value¶m=value + * name?param=value¶m=value + * + * If the string contains an "=" character after the initial name, + * then we treat it as a HTTP GET form request and make a copy of + * the remaining string for the environment variable. + * + * The string is always parsed out as command-line arguments, to + * be consistent with Apache... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "pipe_command: command=\"%s\", options=\"%s\"", + command, options); + + strlcpy(argbuf, options, sizeof(argbuf)); + + argv[0] = argbuf; + query_string = NULL; + + for (commptr = argbuf, argc = 1; *commptr != '\0' && argc < 99; commptr ++) + { + /* + * Break arguments whenever we see a + or space... + */ + + if (*commptr == ' ' || *commptr == '+' || (*commptr == '?' && argc == 1)) + { + /* + * Terminate the current string and skip trailing whitespace... + */ + + *commptr++ = '\0'; + + while (*commptr == ' ') + commptr ++; + + /* + * If we don't have a blank string, save it as another argument... + */ + + if (*commptr) + { + argv[argc] = commptr; + argc ++; + } + else + break; + + /* + * If we see an "=" in the remaining string, make a copy of it since + * it will be query data... + */ + + if (argc == 2 && strchr(commptr, '=') && con->operation == HTTP_GET) + cupsdSetStringf(&query_string, "QUERY_STRING=%s", commptr); + + /* + * Don't skip the first non-blank character... + */ + + commptr --; + } + else if (*commptr == '%' && isxdigit(commptr[1] & 255) && + isxdigit(commptr[2] & 255)) + { + /* + * Convert the %xx notation to the individual character. + */ + + 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; + + _cups_strcpy(commptr + 1, commptr + 3); + + /* + * Check for a %00 and break if that is the case... + */ + + if (!*commptr) + break; + } + } + + argv[argc] = NULL; + + if (argv[0][0] == '\0') + argv[0] = strrchr(command, '/') + 1; + + /* + * Setup the environment variables as needed... + */ + + if (con->language) + snprintf(lang, sizeof(lang), "LANG=%s.UTF-8", con->language->language); + else + strcpy(lang, "LANG=C"); + + strcpy(remote_addr, "REMOTE_ADDR="); + httpAddrString(con->http.hostaddr, remote_addr + 12, + sizeof(remote_addr) - 12); + + snprintf(remote_host, sizeof(remote_host), "REMOTE_HOST=%s", + con->http.hostname); + + snprintf(script_name, sizeof(script_name), "SCRIPT_NAME=%s", con->uri); + if ((uriptr = strchr(script_name, '?')) != NULL) + *uriptr = '\0'; + + sprintf(server_port, "SERVER_PORT=%d", con->serverport); + + snprintf(server_name, sizeof(server_name), "SERVER_NAME=%s", + con->servername); + + envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0]))); + + envp[envc ++] = lang; + envp[envc ++] = "REDIRECT_STATUS=1"; + envp[envc ++] = server_name; + envp[envc ++] = server_port; + envp[envc ++] = remote_addr; + envp[envc ++] = remote_host; + envp[envc ++] = script_name; + + if (con->username[0]) + { + snprintf(remote_user, sizeof(remote_user), "REMOTE_USER=%s", con->username); + + envp[envc ++] = remote_user; + } + + if (con->http.version == HTTP_1_1) + envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.1"; + else if (con->http.version == HTTP_1_0) + envp[envc ++] = "SERVER_PROTOCOL=HTTP/1.0"; + else + envp[envc ++] = "SERVER_PROTOCOL=HTTP/0.9"; + + if (con->http.cookie) + { + snprintf(http_cookie, sizeof(http_cookie), "HTTP_COOKIE=%s", + con->http.cookie); + envp[envc ++] = http_cookie; + } + + if (con->http.fields[HTTP_FIELD_USER_AGENT][0]) + { + snprintf(http_user_agent, sizeof(http_user_agent), "HTTP_USER_AGENT=%s", + con->http.fields[HTTP_FIELD_USER_AGENT]); + envp[envc ++] = http_user_agent; + } + + if (con->operation == HTTP_GET) + { + for (i = 0; i < argc; i ++) + cupsdLogMessage(CUPSD_LOG_DEBUG2, "argv[%d] = \"%s\"", i, argv[i]); + + envp[envc ++] = "REQUEST_METHOD=GET"; + + if (query_string) + { + /* + * Add GET form variables after ?... + */ + + envp[envc ++] = query_string; + } + } + else + { + sprintf(content_length, "CONTENT_LENGTH=" CUPS_LLFMT, 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_ALWAYS) + envp[envc ++] = "HTTPS=ON"; + + /* + * Terminate the environment array... + */ + + envp[envc] = NULL; + + if (LogLevel == CUPSD_LOG_DEBUG2) + { + for (i = 0; i < argc; i ++) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "pipe_command: argv[%d] = \"%s\"", i, argv[i]); + for (i = 0; i < envc; i ++) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "pipe_command: envp[%d] = \"%s\"", i, envp[i]); + } + + /* + * Create a pipe for the output... + */ + + if (cupsdOpenPipe(fds)) + { + cupsdClearString(&query_string); + + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create pipes for CGI %s - %s", + argv[0], strerror(errno)); + return (0); + } + + /* + * Then execute the command... + */ + + if (cupsdStartProcess(command, argv, envp, infile, fds[1], CGIPipes[1], + -1, root, &pid) < 0) + { + /* + * Error - can't fork! + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork for CGI %s - %s", argv[0], + strerror(errno)); + + cupsdClosePipe(fds); + pid = 0; + } + else + { + /* + * Fork successful - return the PID... + */ + + if (con->username[0]) + cupsdAddCert(pid, con->username); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "CGI %s started - PID = %d", command, pid); + + *outfile = fds[0]; + close(fds[1]); + } + + cupsdClearString(&query_string); + + return (pid); +} + + +/* + * End of "$Id: client.c 4912 2006-01-10 21:43:56Z mike $". + */ diff --git a/scheduler/client.h b/scheduler/client.h new file mode 100644 index 000000000..b2ecac49a --- /dev/null +++ b/scheduler/client.h @@ -0,0 +1,134 @@ +/* + * "$Id: client.h 4757 2005-10-08 10:10:46Z mike $" + * + * Client definitions for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * HTTP client structure... + */ + +struct cupsd_client_s +{ + http_t http; /* HTTP client connection */ + ipp_t *request, /* IPP request information */ + *response; /* IPP response information */ + cupsd_location_t *best; /* Best match for AAA */ + time_t start; /* Request start time */ + http_state_t operation; /* Request operation */ + off_t 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, /* Filename of output file */ + *command, /* Command to run */ + *options; /* Options for command */ + int file; /* Input/output file */ + int file_ready; /* Input ready on file/pipe? */ + int pipe_pid; /* Pipe process ID (or 0 if not a pipe) */ + int sent_header, /* Non-zero if sent HTTP header */ + got_fields, /* Non-zero if all fields seen */ + field_col; /* Column within line */ + cups_lang_t *language; /* Language to use */ +#ifdef HAVE_SSL + int auto_ssl; /* Automatic test for SSL/TLS */ +#endif /* HAVE_SSL */ + http_addr_t clientaddr; /* Client address */ + char servername[256];/* Server name for connection */ + int serverport; /* Server port for connection */ +}; + +#define HTTP(con) &((con)->http) + + +/* + * HTTP listener structure... + */ + +typedef struct +{ + int fd; /* File descriptor for this server */ + http_addr_t address; /* Bind address of socket */ + http_encryption_t encryption; /* To encrypt or not to encrypt... */ +} cupsd_listener_t; + + +/* + * Globals... + */ + +VAR int ListenBackLog VALUE(SOMAXCONN), + /* Max backlog of pending connections */ + LocalPort VALUE(631); + /* Local port to use */ +VAR http_encryption_t LocalEncryption VALUE(HTTP_ENCRYPT_IF_REQUESTED); + /* Local port encryption to use */ +VAR int NumListeners VALUE(0); + /* Number of listening sockets */ +VAR cupsd_listener_t *Listeners VALUE(NULL); + /* Listening sockets */ +VAR int NumClients VALUE(0); + /* Number of HTTP clients */ +VAR cupsd_client_t *Clients VALUE(NULL); + /* HTTP clients */ +VAR http_addrlist_t *ServerAddrs VALUE(NULL); + /* Server address(es) */ +VAR char *ServerHeader VALUE(NULL); + /* Server header in requests */ +VAR int CGIPipes[2] VALUE2(-1,-1); + /* Pipes for CGI error/debug output */ +VAR cupsd_statbuf_t *CGIStatusBuffer VALUE(NULL); + /* Status buffer for pipes */ + + +/* + * Prototypes... + */ + +extern void cupsdAcceptClient(cupsd_listener_t *lis); +extern void cupsdCloseAllClients(void); +extern int cupsdCloseClient(cupsd_client_t *con); +extern int cupsdEncryptClient(cupsd_client_t *con); +extern int cupsdIsCGI(cupsd_client_t *con, const char *filename, + struct stat *filestats, mime_type_t *type); +extern void cupsdPauseListening(void); +extern int cupsdProcessIPPRequest(cupsd_client_t *con); +extern int cupsdReadClient(cupsd_client_t *con); +extern void cupsdResumeListening(void); +extern int cupsdSendCommand(cupsd_client_t *con, char *command, + char *options, int root); +extern int cupsdSendError(cupsd_client_t *con, http_status_t code); +extern int cupsdSendFile(cupsd_client_t *con, http_status_t code, + char *filename, char *type, + struct stat *filestats); +extern int cupsdSendHeader(cupsd_client_t *con, http_status_t code, + char *type); +extern void cupsdShutdownClient(cupsd_client_t *con); +extern void cupsdStartListening(void); +extern void cupsdStopListening(void); +extern void cupsdUpdateCGI(void); +extern int cupsdWriteClient(cupsd_client_t *con); + + +/* + * End of "$Id: client.h 4757 2005-10-08 10:10:46Z mike $". + */ diff --git a/scheduler/conf.c b/scheduler/conf.c new file mode 100644 index 000000000..0963e5fec --- /dev/null +++ b/scheduler/conf.c @@ -0,0 +1,3048 @@ +/* + * "$Id: conf.c 4903 2006-01-10 20:02:46Z mike $" + * + * Configuration routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdReadConfiguration() - Read the cupsd.conf file. + * get_address() - Get an address + port number from a line. + * get_addr_and_mask() - Get an IP address and netmask. + * parse_aaa() - Parse authentication, authorization, and + * access control lines. + * read_configuration() - Read a configuration file. + * read_location() - Read a definition. + * read_policy() - Read a definition. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" +#include +#include +#include +#include + +#ifdef HAVE_VSYSLOG +# include +#endif /* HAVE_VSYSLOG */ + + +/* + * Possibly missing network definitions... + */ + +#ifndef INADDR_NONE +# define INADDR_NONE 0xffffffff +#endif /* !INADDR_NONE */ + + +/* + * Configuration variable structure... + */ + +typedef enum +{ + CUPSD_VARTYPE_INTEGER, /* Integer option */ + CUPSD_VARTYPE_STRING, /* String option */ + CUPSD_VARTYPE_BOOLEAN /* Boolean option */ +} cupsd_vartype_t; + +typedef struct +{ + char *name; /* Name of variable */ + void *ptr; /* Pointer to variable */ + cupsd_vartype_t type; /* Type (int, string, address) */ +} cupsd_var_t; + + +/* + * Local globals... + */ + +static cupsd_var_t variables[] = +{ + { "AccessLog", &AccessLog, CUPSD_VARTYPE_STRING }, + { "AutoPurgeJobs", &JobAutoPurge, CUPSD_VARTYPE_BOOLEAN }, + { "BrowseInterval", &BrowseInterval, CUPSD_VARTYPE_INTEGER }, + { "BrowseLocalOptions", &BrowseLocalOptions, CUPSD_VARTYPE_STRING }, + { "BrowsePort", &BrowsePort, CUPSD_VARTYPE_INTEGER }, + { "BrowseRemoteOptions", &BrowseRemoteOptions, CUPSD_VARTYPE_STRING }, + { "BrowseShortNames", &BrowseShortNames, CUPSD_VARTYPE_BOOLEAN }, + { "BrowseTimeout", &BrowseTimeout, CUPSD_VARTYPE_INTEGER }, + { "Browsing", &Browsing, CUPSD_VARTYPE_BOOLEAN }, + { "CacheDir", &CacheDir, CUPSD_VARTYPE_STRING }, + { "Classification", &Classification, CUPSD_VARTYPE_STRING }, + { "ClassifyOverride", &ClassifyOverride, CUPSD_VARTYPE_BOOLEAN }, + { "ConfigFilePerm", &ConfigFilePerm, CUPSD_VARTYPE_INTEGER }, + { "DataDir", &DataDir, CUPSD_VARTYPE_STRING }, + { "DefaultCharset", &DefaultCharset, CUPSD_VARTYPE_STRING }, + { "DefaultLanguage", &DefaultLanguage, CUPSD_VARTYPE_STRING }, + { "DefaultLeaseDuration", &DefaultLeaseDuration, CUPSD_VARTYPE_INTEGER }, + { "DefaultPolicy", &DefaultPolicy, CUPSD_VARTYPE_STRING }, + { "DocumentRoot", &DocumentRoot, CUPSD_VARTYPE_STRING }, + { "ErrorLog", &ErrorLog, CUPSD_VARTYPE_STRING }, + { "FileDevice", &FileDevice, CUPSD_VARTYPE_BOOLEAN }, + { "FilterLimit", &FilterLimit, CUPSD_VARTYPE_INTEGER }, + { "FilterNice", &FilterNice, CUPSD_VARTYPE_INTEGER }, + { "FontPath", &FontPath, CUPSD_VARTYPE_STRING }, + { "HideImplicitMembers", &HideImplicitMembers, CUPSD_VARTYPE_BOOLEAN }, + { "ImplicitClasses", &ImplicitClasses, CUPSD_VARTYPE_BOOLEAN }, + { "ImplicitAnyClasses", &ImplicitAnyClasses, CUPSD_VARTYPE_BOOLEAN }, + { "JobRetryLimit", &JobRetryLimit, CUPSD_VARTYPE_INTEGER }, + { "JobRetryInterval", &JobRetryInterval, CUPSD_VARTYPE_INTEGER }, + { "KeepAliveTimeout", &KeepAliveTimeout, CUPSD_VARTYPE_INTEGER }, + { "KeepAlive", &KeepAlive, CUPSD_VARTYPE_BOOLEAN }, + { "LimitRequestBody", &MaxRequestSize, CUPSD_VARTYPE_INTEGER }, + { "ListenBackLog", &ListenBackLog, CUPSD_VARTYPE_INTEGER }, + { "LogFilePerm", &LogFilePerm, CUPSD_VARTYPE_INTEGER }, + { "MaxActiveJobs", &MaxActiveJobs, CUPSD_VARTYPE_INTEGER }, + { "MaxClients", &MaxClients, CUPSD_VARTYPE_INTEGER }, + { "MaxClientsPerHost", &MaxClientsPerHost, CUPSD_VARTYPE_INTEGER }, + { "MaxCopies", &MaxCopies, CUPSD_VARTYPE_INTEGER }, + { "MaxEvents", &MaxEvents, CUPSD_VARTYPE_INTEGER }, + { "MaxJobs", &MaxJobs, CUPSD_VARTYPE_INTEGER }, + { "MaxJobsPerPrinter", &MaxJobsPerPrinter, CUPSD_VARTYPE_INTEGER }, + { "MaxJobsPerUser", &MaxJobsPerUser, CUPSD_VARTYPE_INTEGER }, + { "MaxLeaseDuration", &MaxLeaseDuration, CUPSD_VARTYPE_INTEGER }, + { "MaxLogSize", &MaxLogSize, CUPSD_VARTYPE_INTEGER }, + { "MaxPrinterHistory", &MaxPrinterHistory, CUPSD_VARTYPE_INTEGER }, + { "MaxRequestSize", &MaxRequestSize, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptions", &MaxSubscriptions, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptionsPerJob", &MaxSubscriptionsPerJob, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptionsPerPrinter",&MaxSubscriptionsPerPrinter, CUPSD_VARTYPE_INTEGER }, + { "MaxSubscriptionsPerUser", &MaxSubscriptionsPerUser, CUPSD_VARTYPE_INTEGER }, + { "PageLog", &PageLog, CUPSD_VARTYPE_STRING }, + { "PreserveJobFiles", &JobFiles, CUPSD_VARTYPE_BOOLEAN }, + { "PreserveJobHistory", &JobHistory, CUPSD_VARTYPE_BOOLEAN }, + { "Printcap", &Printcap, CUPSD_VARTYPE_STRING }, + { "PrintcapGUI", &PrintcapGUI, CUPSD_VARTYPE_STRING }, + { "ReloadTimeout", &ReloadTimeout, CUPSD_VARTYPE_INTEGER }, + { "RemoteRoot", &RemoteRoot, CUPSD_VARTYPE_STRING }, + { "RequestRoot", &RequestRoot, CUPSD_VARTYPE_STRING }, + { "RIPCache", &RIPCache, CUPSD_VARTYPE_STRING }, + { "RunAsUser", &RunAsUser, CUPSD_VARTYPE_BOOLEAN }, + { "RootCertDuration", &RootCertDuration, CUPSD_VARTYPE_INTEGER }, + { "ServerAdmin", &ServerAdmin, CUPSD_VARTYPE_STRING }, + { "ServerBin", &ServerBin, CUPSD_VARTYPE_STRING }, +#ifdef HAVE_SSL + { "ServerCertificate", &ServerCertificate, CUPSD_VARTYPE_STRING }, +# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS) + { "ServerKey", &ServerKey, CUPSD_VARTYPE_STRING }, +# endif /* HAVE_LIBSSL || HAVE_GNUTLS */ +#endif /* HAVE_SSL */ + { "ServerName", &ServerName, CUPSD_VARTYPE_STRING }, + { "ServerRoot", &ServerRoot, CUPSD_VARTYPE_STRING }, + { "StateDir", &StateDir, CUPSD_VARTYPE_STRING }, + { "TempDir", &TempDir, CUPSD_VARTYPE_STRING }, + { "Timeout", &Timeout, CUPSD_VARTYPE_INTEGER } +}; +#define NUM_VARS (sizeof(variables) / sizeof(variables[0])) + + +static unsigned ones[4] = + { + 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff + }; +static unsigned zeros[4] = + { + 0x00000000, 0x00000000, 0x00000000, 0x00000000 + }; + + +/* + * Local functions... + */ + +static http_addrlist_t *get_address(const char *value, int defport); +static int get_addr_and_mask(const char *value, unsigned *ip, + unsigned *mask); +static int parse_aaa(cupsd_location_t *loc, char *line, + char *value, int linenum); +static int read_configuration(cups_file_t *fp); +static int read_location(cups_file_t *fp, char *name, int linenum); +static int read_policy(cups_file_t *fp, char *name, int linenum); + + +/* + * 'cupsdReadConfiguration()' - Read the cupsd.conf file. + */ + +int /* O - 1 on success, 0 otherwise */ +cupsdReadConfiguration(void) +{ + int i; /* Looping var */ + cups_file_t *fp; /* Configuration file */ + int status; /* Return status */ + char temp[1024], /* Temporary buffer */ + *slash; /* Directory separator */ + char type[MIME_MAX_SUPER + MIME_MAX_TYPE]; + /* MIME type name */ + cups_lang_t *language; /* Language */ + struct passwd *user; /* Default user */ + struct group *group; /* Default group */ + char *old_serverroot, /* Old ServerRoot */ + *old_requestroot; /* Old RequestRoot */ + + /* + * Shutdown the server... + */ + + cupsdStopServer(); + + /* + * Save the old root paths... + */ + + old_serverroot = NULL; + cupsdSetString(&old_serverroot, ServerRoot); + old_requestroot = NULL; + cupsdSetString(&old_requestroot, RequestRoot); + + /* + * Reset the server configuration data... + */ + + cupsdDeleteAllLocations(); + + if (NumBrowsers > 0) + { + free(Browsers); + + NumBrowsers = 0; + } + + if (NumPolled > 0) + { + free(Polled); + + NumPolled = 0; + } + + if (NumRelays > 0) + { + for (i = 0; i < NumRelays; i ++) + if (Relays[i].from.type == AUTH_NAME) + free(Relays[i].from.mask.name.name); + + free(Relays); + + NumRelays = 0; + } + + if (NumListeners > 0) + { + free(Listeners); + NumListeners = 0; + } + + /* + * String options... + */ + + cupsdSetString(&ServerName, httpGetHostname(temp, sizeof(temp))); + cupsdSetStringf(&ServerAdmin, "root@%s", temp); + cupsdSetString(&ServerBin, CUPS_SERVERBIN); + cupsdSetString(&RequestRoot, CUPS_REQUESTS); + cupsdSetString(&CacheDir, CUPS_CACHEDIR); + cupsdSetString(&DataDir, CUPS_DATADIR); + cupsdSetString(&DocumentRoot, CUPS_DOCROOT); + cupsdSetString(&AccessLog, CUPS_LOGDIR "/access_log"); + cupsdSetString(&ErrorLog, CUPS_LOGDIR "/error_log"); + cupsdSetString(&PageLog, CUPS_LOGDIR "/page_log"); + cupsdSetString(&Printcap, "/etc/printcap"); + cupsdSetString(&PrintcapGUI, "/usr/bin/glpoptions"); + cupsdSetString(&FontPath, CUPS_FONTPATH); + cupsdSetString(&RemoteRoot, "remroot"); + cupsdSetString(&ServerHeader, "CUPS/1.1"); + cupsdSetString(&StateDir, CUPS_STATEDIR); + + strlcpy(temp, ConfigurationFile, sizeof(temp)); + if ((slash = strrchr(temp, '/')) != NULL) + *slash = '\0'; + + cupsdSetString(&ServerRoot, temp); + + cupsdClearString(&Classification); + ClassifyOverride = 0; + +#ifdef HAVE_SSL +# ifdef HAVE_CDSASSL + cupsdSetString(&ServerCertificate, "/var/root/Library/Keychains/CUPS"); +# else + cupsdSetString(&ServerCertificate, "ssl/server.crt"); + cupsdSetString(&ServerKey, "ssl/server.key"); +# endif /* HAVE_CDSASSL */ +#endif /* HAVE_SSL */ + + language = cupsLangDefault(); + + if (!strcmp(language->language, "C") || !strcmp(language->language, "POSIX")) + cupsdSetString(&DefaultLanguage, "en"); + else + cupsdSetString(&DefaultLanguage, language->language); + + cupsdSetString(&DefaultCharset, _cupsEncodingName(language->encoding)); + + cupsdSetString(&RIPCache, "8m"); + + if (getenv("TMPDIR") == NULL) + cupsdSetString(&TempDir, CUPS_REQUESTS "/tmp"); + else + cupsdSetString(&TempDir, getenv("TMPDIR")); + + /* + * Find the default system group: "sys", "system", or "root"... + */ + + group = getgrnam(CUPS_DEFAULT_GROUP); + endgrent(); + + NumSystemGroups = 0; + + if (group != NULL) + { + /* + * Found the group, use it! + */ + + cupsdSetString(&SystemGroups[0], CUPS_DEFAULT_GROUP); + + SystemGroupIDs[0] = group->gr_gid; + } + else + { + /* + * Find the group associated with GID 0... + */ + + group = getgrgid(0); + endgrent(); + + if (group != NULL) + cupsdSetString(&SystemGroups[0], group->gr_name); + else + cupsdSetString(&SystemGroups[0], "unknown"); + + SystemGroupIDs[0] = 0; + } + + /* + * Find the default user... + */ + + if ((user = getpwnam(CUPS_DEFAULT_USER)) != NULL) + User = user->pw_uid; + else + { + /* + * Use the (historical) NFS nobody user ID (-2 as a 16-bit twos- + * complement number...) + */ + + User = 65534; + } + + endpwent(); + + /* + * Find the default group (nobody)... + */ + + group = getgrnam("nobody"); + endgrent(); + + if (group != NULL) + Group = group->gr_gid; + else + { + /* + * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos- + * complement number...) + */ + + Group = 65534; + } + + /* + * Numeric options... + */ + + ConfigFilePerm = 0640; + DefaultAuthType = AUTH_BASIC; + JobRetryLimit = 5; + JobRetryInterval = 300; + FileDevice = FALSE; + FilterLevel = 0; + FilterLimit = 0; + FilterNice = 0; + HostNameLookups = FALSE; + ImplicitClasses = TRUE; + ImplicitAnyClasses = FALSE; + HideImplicitMembers = TRUE; + KeepAlive = TRUE; + KeepAliveTimeout = DEFAULT_KEEPALIVE; + ListenBackLog = SOMAXCONN; + LogFilePerm = 0644; + LogLevel = CUPSD_LOG_ERROR; + MaxClients = 100; + MaxClientsPerHost = 0; + MaxLogSize = 1024 * 1024; + MaxPrinterHistory = 10; + MaxRequestSize = 0; + ReloadTimeout = 60; + RootCertDuration = 300; + RunAsUser = FALSE; + Timeout = DEFAULT_TIMEOUT; + + BrowseInterval = DEFAULT_INTERVAL; + BrowsePort = ippPort(); + BrowseLocalProtocols = BROWSE_CUPS; + BrowseRemoteProtocols = BROWSE_CUPS; + BrowseShortNames = TRUE; + BrowseTimeout = DEFAULT_TIMEOUT; + Browsing = TRUE; + + cupsdClearString(&BrowseLocalOptions); + cupsdClearString(&BrowseRemoteOptions); + + JobHistory = DEFAULT_HISTORY; + JobFiles = DEFAULT_FILES; + JobAutoPurge = 0; + MaxJobs = 500; + MaxActiveJobs = 0; + MaxJobsPerUser = 0; + MaxJobsPerPrinter = 0; + MaxCopies = 100; + + cupsdDeleteAllPolicies(); + cupsdClearString(&DefaultPolicy); + + MaxSubscriptions = 100; + MaxSubscriptionsPerJob = 0; + MaxSubscriptionsPerPrinter = 0; + MaxSubscriptionsPerUser = 0; + DefaultLeaseDuration = 86400; + MaxLeaseDuration = 0; + + /* + * Read the configuration file... + */ + + if ((fp = cupsFileOpen(ConfigurationFile, "r")) == NULL) + return (0); + + status = read_configuration(fp); + + cupsFileClose(fp); + + if (!status) + return (0); + + if (RunAsUser) + RunUser = User; + else + RunUser = getuid(); + + /* + * Use the default system group if none was supplied in cupsd.conf... + */ + + if (NumSystemGroups == 0) + NumSystemGroups ++; + + /* + * Get the access control list for browsing... + */ + + BrowseACL = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL"); + + /* + * Open the system log for cupsd if necessary... + */ + +#ifdef HAVE_VSYSLOG + if (!strcmp(AccessLog, "syslog") || + !strcmp(ErrorLog, "syslog") || + !strcmp(PageLog, "syslog")) + openlog("cupsd", LOG_PID | LOG_NOWAIT | LOG_NDELAY, LOG_LPR); +#endif /* HAVE_VSYSLOG */ + + /* + * Log the configuration file that was used... + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Loaded configuration file \"%s\"", + ConfigurationFile); + + /* + * Validate the Group and SystemGroup settings - they cannot be the same, + * otherwise the CGI programs will be able to authenticate as root without + * a password! + */ + + if (!RunUser) + { + for (i = 0; i < NumSystemGroups; i ++) + if (Group == SystemGroupIDs[i]) + break; + + if (i < NumSystemGroups) + { + /* + * Log the error and reset the group to a safe value... + */ + + cupsdLogMessage(CUPSD_LOG_NOTICE, + "Group and SystemGroup cannot use the same groups!"); + cupsdLogMessage(CUPSD_LOG_INFO, "Resetting Group to \"nobody\"..."); + + group = getgrnam("nobody"); + endgrent(); + + if (group != NULL) + Group = group->gr_gid; + else + { + /* + * Use the (historical) NFS nobody group ID (-2 as a 16-bit twos- + * complement number...) + */ + + Group = 65534; + } + } + } + + /* + * Check that we have at least one listen/port line; if not, report this + * as an error and exit! + */ + + if (NumListeners == 0) + { + /* + * No listeners! + */ + + cupsdLogMessage(CUPSD_LOG_EMERG, + "No valid Listen or Port lines were found in the configuration file!"); + + /* + * Commit suicide... + */ + + cupsdEndProcess(getpid(), 0); + } + + /* + * Set the default locale using the language and charset... + */ + + cupsdSetStringf(&DefaultLocale, "%s.%s", DefaultLanguage, DefaultCharset); + + /* + * Update all relative filenames to include the full path from ServerRoot... + */ + + if (DocumentRoot[0] != '/') + cupsdSetStringf(&DocumentRoot, "%s/%s", ServerRoot, DocumentRoot); + + if (RequestRoot[0] != '/') + cupsdSetStringf(&RequestRoot, "%s/%s", ServerRoot, RequestRoot); + + if (ServerBin[0] != '/') + cupsdSetStringf(&ServerBin, "%s/%s", ServerRoot, ServerBin); + + if (StateDir[0] != '/') + cupsdSetStringf(&StateDir, "%s/%s", ServerRoot, StateDir); + + if (CacheDir[0] != '/') + cupsdSetStringf(&CacheDir, "%s/%s", ServerRoot, CacheDir); + +#ifdef HAVE_SSL + if (ServerCertificate[0] != '/') + cupsdSetStringf(&ServerCertificate, "%s/%s", ServerRoot, ServerCertificate); + + if (!strncmp(ServerRoot, ServerCertificate, strlen(ServerRoot))) + { + chown(ServerCertificate, RunUser, Group); + chmod(ServerCertificate, ConfigFilePerm); + } + +# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS) + if (ServerKey[0] != '/') + cupsdSetStringf(&ServerKey, "%s/%s", ServerRoot, ServerKey); + + if (!strncmp(ServerRoot, ServerKey, strlen(ServerRoot))) + { + chown(ServerKey, RunUser, Group); + chmod(ServerKey, ConfigFilePerm); + } +# endif /* HAVE_LIBSSL || HAVE_GNUTLS */ +#endif /* HAVE_SSL */ + + /* + * Make sure that directories and config files are owned and + * writable by the user and group in the cupsd.conf file... + */ + + chown(CacheDir, RunUser, Group); + chmod(CacheDir, 0775); + + snprintf(temp, sizeof(temp), "%s/ppd", CacheDir); + if (access(temp, 0)) + mkdir(temp, 0755); + chown(temp, RunUser, Group); + chmod(temp, 0755); + + chown(StateDir, RunUser, Group); + chmod(StateDir, 0775); + + snprintf(temp, sizeof(temp), "%s/certs", StateDir); + if (access(temp, 0)) + mkdir(temp, 0510); + chown(temp, User, SystemGroupIDs[0]); + if (RunUser) + chmod(temp, 0710); + else + chmod(temp, 0510); + + chown(ServerRoot, RunUser, Group); + chmod(ServerRoot, 0755); + + snprintf(temp, sizeof(temp), "%s/ppd", ServerRoot); + if (access(temp, 0)) + mkdir(temp, 0755); + chown(temp, RunUser, Group); + chmod(temp, 0755); + + snprintf(temp, sizeof(temp), "%s/ssl", ServerRoot); + if (access(temp, 0)) + mkdir(temp, 0700); + chown(temp, RunUser, Group); + chmod(temp, 0700); + + snprintf(temp, sizeof(temp), "%s/cupsd.conf", ServerRoot); + chown(temp, RunUser, Group); + chmod(temp, ConfigFilePerm); + + snprintf(temp, sizeof(temp), "%s/classes.conf", ServerRoot); + chown(temp, RunUser, Group); + chmod(temp, 0600); + + snprintf(temp, sizeof(temp), "%s/printers.conf", ServerRoot); + chown(temp, RunUser, Group); + chmod(temp, 0600); + + snprintf(temp, sizeof(temp), "%s/passwd.md5", ServerRoot); + chown(temp, User, Group); + chmod(temp, 0600); + + /* + * Make sure the request and temporary directories have the right + * permissions... + */ + + chown(RequestRoot, RunUser, Group); + chmod(RequestRoot, 0710); + + if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot)) || + access(TempDir, 0)) + { + /* + * Update ownership and permissions if the CUPS temp directory + * is under the spool directory or does not exist... + */ + + if (access(TempDir, 0)) + mkdir(TempDir, 01770); + + chown(TempDir, RunUser, Group); + chmod(TempDir, 01770); + } + + if (!strncmp(TempDir, RequestRoot, strlen(RequestRoot))) + { + /* + * Clean out the temporary directory... + */ + + cups_dir_t *dir; /* Temporary directory */ + cups_dentry_t *dent; /* Directory entry */ + char tempfile[1024]; /* Temporary filename */ + + + if ((dir = cupsDirOpen(TempDir)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Cleaning out old temporary files in \"%s\"...", TempDir); + + while ((dent = cupsDirRead(dir)) != NULL) + { + snprintf(tempfile, sizeof(tempfile), "%s/%s", TempDir, dent->filename); + + if (unlink(tempfile)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to remove temporary file \"%s\" - %s", + tempfile, strerror(errno)); + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed temporary file \"%s\"...", + tempfile); + } + + cupsDirClose(dir); + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to open temporary directory \"%s\" - %s", + TempDir, strerror(errno)); + } + + /* + * Setup environment variables... + */ + + cupsdInitEnv(); + + /* + * Check the MaxClients setting, and then allocate memory for it... + */ + + if (MaxClients > (MaxFDs / 3) || MaxClients <= 0) + { + if (MaxClients > 0) + cupsdLogMessage(CUPSD_LOG_INFO, "MaxClients limited to 1/3 (%d) of the file descriptor limit (%d)...", + MaxFDs / 3, MaxFDs); + + MaxClients = MaxFDs / 3; + } + + if ((Clients = calloc(sizeof(cupsd_client_t), MaxClients)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdReadConfiguration: Unable to allocate memory for %d clients: %s", + MaxClients, strerror(errno)); + exit(1); + } + else + cupsdLogMessage(CUPSD_LOG_INFO, "Configured for up to %d clients.", + MaxClients); + + /* + * Check the MaxActiveJobs setting; limit to 1/3 the available + * file descriptors, since we need a pipe for each job... + */ + + if (MaxActiveJobs > (MaxFDs / 3)) + MaxActiveJobs = MaxFDs / 3; + + if (Classification && strcasecmp(Classification, "none") == 0) + cupsdClearString(&Classification); + + if (Classification) + cupsdLogMessage(CUPSD_LOG_INFO, "Security set to \"%s\"", Classification); + + /* + * Update the MaxClientsPerHost value, as needed... + */ + + if (MaxClientsPerHost <= 0) + MaxClientsPerHost = MaxClients; + + if (MaxClientsPerHost > MaxClients) + MaxClientsPerHost = MaxClients; + + cupsdLogMessage(CUPSD_LOG_INFO, + "Allowing up to %d client connections per host.", + MaxClientsPerHost); + + /* + * Update the default policy, as needed... + */ + + if (DefaultPolicy) + DefaultPolicyPtr = cupsdFindPolicy(DefaultPolicy); + else + DefaultPolicyPtr = NULL; + + if (!DefaultPolicyPtr) + { + cupsd_policy_t *p; /* New policy */ + cupsd_location_t *po; /* New policy operation */ + + + if (DefaultPolicy) + cupsdLogMessage(CUPSD_LOG_ERROR, "Default policy \"%s\" not found!", + DefaultPolicy); + + if ((DefaultPolicyPtr = cupsdFindPolicy("default")) != NULL) + cupsdLogMessage(CUPSD_LOG_INFO, + "Using policy \"default\" as the default!"); + else + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Creating CUPS default administrative policy:"); + + DefaultPolicyPtr = p = cupsdAddPolicy("default"); + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + cupsdLogMessage(CUPSD_LOG_INFO, + ""); + cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); + + po = cupsdAddPolicyOp(p, NULL, IPP_SEND_DOCUMENT); + po->order_type = AUTH_ALLOW; + po->level = AUTH_USER; + + cupsdAddName(po, "@OWNER"); + cupsdAddName(po, "@SYSTEM"); + cupsdLogMessage(CUPSD_LOG_INFO, "Require user @OWNER @SYSTEM"); + + cupsdAddPolicyOp(p, po, IPP_SEND_URI); + cupsdAddPolicyOp(p, po, IPP_CANCEL_JOB); + cupsdAddPolicyOp(p, po, IPP_HOLD_JOB); + cupsdAddPolicyOp(p, po, IPP_RELEASE_JOB); + cupsdAddPolicyOp(p, po, IPP_RESTART_JOB); + cupsdAddPolicyOp(p, po, IPP_PURGE_JOBS); + cupsdAddPolicyOp(p, po, IPP_SET_JOB_ATTRIBUTES); + cupsdAddPolicyOp(p, po, IPP_CREATE_JOB_SUBSCRIPTION); + cupsdAddPolicyOp(p, po, IPP_RENEW_SUBSCRIPTION); + cupsdAddPolicyOp(p, po, IPP_CANCEL_SUBSCRIPTION); + cupsdAddPolicyOp(p, po, IPP_GET_NOTIFICATIONS); + cupsdAddPolicyOp(p, po, IPP_REPROCESS_JOB); + cupsdAddPolicyOp(p, po, IPP_CANCEL_CURRENT_JOB); + cupsdAddPolicyOp(p, po, IPP_SUSPEND_CURRENT_JOB); + cupsdAddPolicyOp(p, po, IPP_RESUME_JOB); + cupsdAddPolicyOp(p, po, CUPS_MOVE_JOB); + cupsdAddPolicyOp(p, po, CUPS_AUTHENTICATE_JOB); + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + + cupsdLogMessage(CUPSD_LOG_INFO, + ""); + cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); + cupsdLogMessage(CUPSD_LOG_INFO, "AuthType Basic"); + + po = cupsdAddPolicyOp(p, NULL, IPP_PAUSE_PRINTER); + po->order_type = AUTH_ALLOW; + po->type = AUTH_BASIC; + po->level = AUTH_USER; + + cupsdAddName(po, "@SYSTEM"); + cupsdLogMessage(CUPSD_LOG_INFO, "Require user @SYSTEM"); + + cupsdAddPolicyOp(p, po, IPP_RESUME_PRINTER); + cupsdAddPolicyOp(p, po, IPP_SET_PRINTER_ATTRIBUTES); + cupsdAddPolicyOp(p, po, IPP_ENABLE_PRINTER); + cupsdAddPolicyOp(p, po, IPP_DISABLE_PRINTER); + cupsdAddPolicyOp(p, po, IPP_PAUSE_PRINTER_AFTER_CURRENT_JOB); + cupsdAddPolicyOp(p, po, IPP_HOLD_NEW_JOBS); + cupsdAddPolicyOp(p, po, IPP_RELEASE_HELD_NEW_JOBS); + cupsdAddPolicyOp(p, po, IPP_DEACTIVATE_PRINTER); + cupsdAddPolicyOp(p, po, IPP_ACTIVATE_PRINTER); + cupsdAddPolicyOp(p, po, IPP_RESTART_PRINTER); + cupsdAddPolicyOp(p, po, IPP_SHUTDOWN_PRINTER); + cupsdAddPolicyOp(p, po, IPP_STARTUP_PRINTER); + cupsdAddPolicyOp(p, po, IPP_PROMOTE_JOB); + cupsdAddPolicyOp(p, po, IPP_SCHEDULE_JOB_AFTER); + cupsdAddPolicyOp(p, po, CUPS_ADD_PRINTER); + cupsdAddPolicyOp(p, po, CUPS_DELETE_PRINTER); + cupsdAddPolicyOp(p, po, CUPS_ADD_CLASS); + cupsdAddPolicyOp(p, po, CUPS_DELETE_CLASS); + cupsdAddPolicyOp(p, po, CUPS_ACCEPT_JOBS); + cupsdAddPolicyOp(p, po, CUPS_REJECT_JOBS); + cupsdAddPolicyOp(p, po, CUPS_SET_DEFAULT); + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + cupsdLogMessage(CUPSD_LOG_INFO, "Order Deny,Allow"); + + po = cupsdAddPolicyOp(p, NULL, IPP_ANY_OPERATION); + po->order_type = AUTH_ALLOW; + + cupsdLogMessage(CUPSD_LOG_INFO, ""); + cupsdLogMessage(CUPSD_LOG_INFO, ""); + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG,"NumPolicies=%d", NumPolicies); + for (i = 0; i < NumPolicies; i ++) + cupsdLogMessage(CUPSD_LOG_DEBUG, "Policies[%d]=\"%s\"", i, + Policies[i]->name); + + /* + * If we are doing a full reload or the server root has changed, flush + * the jobs, printers, etc. and start from scratch... + */ + + if (NeedReload == RELOAD_ALL || + !old_serverroot || !ServerRoot || strcmp(old_serverroot, ServerRoot) || + !old_requestroot || !RequestRoot || strcmp(old_requestroot, RequestRoot)) + { + cupsdLogMessage(CUPSD_LOG_INFO, "Full reload is required."); + + /* + * Free all memory... + */ + + cupsdDeleteAllSubscriptions(); + cupsdFreeAllJobs(); + cupsdDeleteAllClasses(); + cupsdDeleteAllPrinters(); + + DefaultPrinter = NULL; + + if (MimeDatabase != NULL) + mimeDelete(MimeDatabase); + + if (NumMimeTypes) + { + for (i = 0; i < NumMimeTypes; i ++) + free((void *)MimeTypes[i]); + + free(MimeTypes); + } + + /* + * Read the MIME type and conversion database... + */ + + snprintf(temp, sizeof(temp), "%s/filter", ServerBin); + + MimeDatabase = mimeLoad(ServerRoot, temp); + + if (!MimeDatabase) + { + cupsdLogMessage(CUPSD_LOG_EMERG, + "Unable to load MIME database from \'%s\'!", ServerRoot); + exit(errno); + } + + cupsdLogMessage(CUPSD_LOG_INFO, + "Loaded MIME database from \'%s\': %d types, %d filters...", + ServerRoot, MimeDatabase->num_types, MimeDatabase->num_filters); + + /* + * 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(temp, sizeof(temp), "%s/banners", DataDir); + cupsdLoadBanners(temp); + + /* + * Load printers and classes... + */ + + cupsdLoadAllPrinters(); + cupsdLoadAllClasses(); + cupsdLoadRemoteCache(); + cupsdWritePrintcap(); + + cupsdCreateCommonData(); + + /* + * Load queued jobs... + */ + + cupsdLoadAllJobs(); + + /* + * Load subscriptions... + */ + + cupsdLoadAllSubscriptions(); + + cupsdLogMessage(CUPSD_LOG_INFO, "Full reload complete."); + } + else + { + /* + * Not a full reload, so recreate the common printer attributes... + */ + + cupsdCreateCommonData(); + + /* + * Update all printers as needed... + */ + + cupsdUpdatePrinters(); + cupsdWritePrintcap(); + + cupsdLogMessage(CUPSD_LOG_INFO, "Partial reload complete."); + } + + /* + * Reset the reload state... + */ + + NeedReload = RELOAD_NONE; + + cupsdClearString(&old_serverroot); + cupsdClearString(&old_requestroot); + + /* + * Startup the server and return... + */ + + cupsdStartServer(); + + return (1); +} + + +/* + * 'get_address()' - Get an address + port number from a line. + */ + +static http_addrlist_t * /* O - Pointer to list if address good, NULL if bad */ +get_address(const char *value, /* I - Value string */ + int defport) /* I - Default port */ +{ + char buffer[1024], /* Hostname + port number buffer */ + defpname[255], /* Default port name */ + *hostname, /* Hostname or IP */ + *portname; /* Port number or name */ + http_addrlist_t *addrlist; /* Address list */ + + + /* + * Check for an empty value... + */ + + if (!*value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad (empty) address!"); + return (NULL); + } + + /* + * Grab a hostname and port number; if there is no colon and the port name + * is only digits, then we have a port number by itself... + */ + + strlcpy(buffer, value, sizeof(buffer)); + + if ((portname = strrchr(buffer, ':')) != NULL && !strchr(portname, ']')) + { + *portname++ = '\0'; + hostname = buffer; + } + else + { + for (portname = buffer; isdigit(*portname & 255); portname ++); + + if (*portname) + { + /* + * Use the default port... + */ + + sprintf(defpname, "%d", defport); + portname = defpname; + hostname = buffer; + } + else + { + /* + * The buffer contains just a port number... + */ + + portname = buffer; + hostname = NULL; + } + } + + if (hostname && !strcmp(hostname, "*")) + hostname = NULL; + + /* + * Now lookup the address using httpAddrGetList()... + */ + + if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, "Hostname lookup for \"%s\" failed!", + hostname ? hostname : "(nil)"); + + return (addrlist); +} + + +/* + * 'get_addr_and_mask()' - Get an IP address and netmask. + */ + +static int /* O - 1 on success, 0 on failure */ +get_addr_and_mask(const char *value, /* I - String from config file */ + unsigned *ip, /* O - Address value */ + unsigned *mask) /* O - Mask value */ +{ + int i, j, /* Looping vars */ + family, /* Address family */ + ipcount; /* Count of fields in address */ + unsigned ipval; /* Value */ + const char *maskval, /* Pointer to start of mask value */ + *ptr, /* Pointer into value */ + *ptr2; /* ... */ + static unsigned netmasks[4][4] = /* Standard IPv4 netmasks... */ + { + { 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffff00 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } + }; +#ifdef AF_INET6 + static unsigned netmasks6[8][4] = /* Standard IPv6 netmasks... */ + { + { 0xffff0000, 0x00000000, 0x00000000, 0x00000000 }, + { 0xffffffff, 0x00000000, 0x00000000, 0x00000000 }, + { 0xffffffff, 0xffff0000, 0x00000000, 0x00000000 }, + { 0xffffffff, 0xffffffff, 0x00000000, 0x00000000 }, + { 0xffffffff, 0xffffffff, 0xffff0000, 0x00000000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffff0000 }, + { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff } + }; +#endif /* AF_INET6 */ + + + /* + * Get the address... + */ + + memset(ip, 0, sizeof(unsigned) * 4); + + if ((maskval = strchr(value, '/')) != NULL) + maskval ++; + else + maskval = value + strlen(value); + +#ifdef AF_INET6 + /* + * Check for an IPv6 address... + */ + + if (*value == '[') + { + /* + * Parse hexadecimal IPv6 address... + */ + + family = AF_INET6; + + for (i = 0, ptr = value + 1; *ptr && i < 8; i ++) + { + if (*ptr == ']') + break; + else if (!strncmp(ptr, "::", 2)) + { + for (ptr2 = strchr(ptr + 2, ':'), j = 0; + ptr2; + ptr2 = strchr(ptr2 + 1, ':'), j ++); + + i = 7 - j; + } + else if (isxdigit(*ptr & 255)) + { + ipval = strtoul(ptr, (char **)&ptr, 16); + + if (ipval > 0xffff) + return (0); + + if (i & 1) + ip[i] |= ipval; + else + ip[i] |= ipval << 16; + } + else + return (0); + + while (*ptr == ':') + ptr ++; + } + + ipcount = i; + + if (*ptr && *ptr != '/') + return (0); + } + else +#endif /* AF_INET6 */ + { + /* + * Parse dotted-decimal IPv4 address... + */ + + family = AF_INET; + ipcount = sscanf(value, "%u.%u.%u.%u", ip + 0, ip + 1, ip + 2, ip + 3); + + ip[3] |= ((((ip[0] << 8) | ip[1]) << 8) | ip[2]) << 8; + ip[0] = ip[1] = ip[2] = 0; + } + + if (*maskval) + { + /* + * Get the netmask value(s)... + */ + + memset(mask, 0, sizeof(unsigned) * 4); + +#ifdef AF_INET6 + if (*maskval == '[') + { + /* + * Get hexadecimal mask value... + */ + + for (i = 0, ptr = maskval + 1; *ptr && i < 8; i ++) + { + if (*ptr == ']') + break; + else if (!strncmp(ptr, "::", 2)) + { + for (ptr2 = strchr(ptr + 2, ':'), j = 0; + ptr2; + ptr2 = strchr(ptr2 + 1, ':'), j ++); + + i = 7 - j; + } + else if (isxdigit(*ptr & 255)) + { + ipval = strtoul(ptr, (char **)&ptr, 16); + + if (ipval > 0xffff) + return (0); + + if (i & 1) + mask[i] |= ipval; + else + mask[i] |= ipval << 16; + } + else + return (0); + + while (*ptr == ':') + ptr ++; + } + + if (*ptr) + return (0); + } + else +#endif /* AF_INET6 */ + if (strchr(maskval, '.')) + { + /* + * Get dotted-decimal mask... + */ + + if (sscanf(maskval, "%u.%u.%u.%u", mask + 0, mask + 1, mask + 2, mask + 3) != 4) + return (0); + + mask[3] |= ((((mask[0] << 8) | mask[1]) << 8) | mask[2]) << 8; + mask[0] = mask[1] = mask[2] = 0; + } + else + { + /* + * Get address/bits format... + */ + + i = atoi(maskval); + +#ifdef AF_INET6 + if (family == AF_INET6) + { + i = 128 - i; + + if (i <= 96) + mask[0] = 0xffffffff; + else + mask[0] = (0xffffffff << (i - 96)) & 0xffffffff; + + if (i <= 64) + mask[1] = 0xffffffff; + else if (i >= 96) + mask[1] = 0; + else + mask[1] = (0xffffffff << (i - 64)) & 0xffffffff; + + if (i <= 32) + mask[2] = 0xffffffff; + else if (i >= 64) + mask[2] = 0; + else + mask[2] = (0xffffffff << (i - 32)) & 0xffffffff; + + if (i == 0) + mask[3] = 0xffffffff; + else if (i >= 32) + mask[3] = 0; + else + mask[3] = (0xffffffff << i) & 0xffffffff; + } + else +#endif /* AF_INET6 */ + { + i = 32 - i; + + mask[0] = 0xffffffff; + mask[1] = 0xffffffff; + mask[2] = 0xffffffff; + + if (i > 0) + mask[3] = (0xffffffff << i) & 0xffffffff; + else + mask[3] = 0xffffffff; + } + } + } +#ifdef AF_INET6 + else if (family == AF_INET6) + memcpy(mask, netmasks6[ipcount - 1], sizeof(unsigned) * 4); +#endif /* AF_INET6 */ + else + memcpy(mask, netmasks[ipcount - 1], sizeof(unsigned) * 4); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "get_addr_and_mask(value=\"%s\", " + "ip=[%08x:%08x:%08x:%08x], mask=[%08x:%08x:%08x:%08x]", + value, ip[0], ip[1], ip[2], ip[3], mask[0], mask[1], mask[2], + mask[3]); + + /* + * Check for a valid netmask; no fallback like in CUPS 1.1.x! + */ + + if ((ip[0] & ~mask[0]) != 0 || + (ip[1] & ~mask[1]) != 0 || + (ip[2] & ~mask[2]) != 0 || + (ip[3] & ~mask[3]) != 0) + return (0); + + return (1); +} + + +/* + * 'parse_aaa()' - Parse authentication, authorization, and access control lines. + */ + +static int /* O - 1 on success, 0 on failure */ +parse_aaa(cupsd_location_t *loc, /* I - Location */ + char *line, /* I - Line from file */ + char *value, /* I - Start of value data */ + int linenum) /* I - Current line number */ +{ + char *valptr; /* Pointer into value */ + unsigned ip[4], /* IP address components */ + mask[4]; /* IP netmask components */ + + + if (!strcasecmp(line, "Encryption")) + { + /* + * "Encryption xxx" - set required encryption level... + */ + + if (!strcasecmp(value, "never")) + loc->encryption = HTTP_ENCRYPT_NEVER; + else if (!strcasecmp(value, "always")) + { + cupsdLogMessage(CUPSD_LOG_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")) + loc->encryption = HTTP_ENCRYPT_REQUIRED; + else if (!strcasecmp(value, "ifrequested")) + loc->encryption = HTTP_ENCRYPT_IF_REQUESTED; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Encryption value %s on line %d.", value, linenum); + return (0); + } + } + else if (!strcasecmp(line, "Order")) + { + /* + * "Order Deny,Allow" or "Order Allow,Deny"... + */ + + if (!strncasecmp(value, "deny", 4)) + loc->order_type = AUTH_ALLOW; + else if (!strncasecmp(value, "allow", 5)) + loc->order_type = AUTH_DENY; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown Order value %s on line %d.", + value, linenum); + return (0); + } + } + else if (!strcasecmp(line, "Allow") || !strcasecmp(line, "Deny")) + { + /* + * Allow [From] host/ip... + * Deny [From] host/ip... + */ + + if (!strncasecmp(value, "from", 4)) + { + /* + * Strip leading "from"... + */ + + value += 4; + + while (isspace(*value & 255)) + 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")) + { + /* + * All hosts... + */ + + if (!strcasecmp(line, "Allow")) + cupsdAllowIP(loc, zeros, zeros); + else + cupsdDenyIP(loc, zeros, zeros); + } + else if (!strcasecmp(value, "none")) + { + /* + * No hosts... + */ + + if (!strcasecmp(line, "Allow")) + cupsdAllowIP(loc, ones, zeros); + else + cupsdDenyIP(loc, ones, zeros); + } + else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0] & 255)) + { + /* + * Host or domain name... + */ + + if (value[0] == '*') + value ++; + + if (!strcasecmp(line, "Allow")) + cupsdAllowHost(loc, value); + else + cupsdDenyHost(loc, value); + } + else + { + /* + * One of many IP address forms... + */ + + if (!get_addr_and_mask(value, ip, mask)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.", + value, linenum); + return (0); + } + + if (!strcasecmp(line, "Allow")) + cupsdAllowIP(loc, ip, mask); + else + cupsdDenyIP(loc, ip, mask); + } + } + else if (!strcasecmp(line, "AuthType")) + { + /* + * AuthType {none,basic,digest,basicdigest} + */ + + if (!strcasecmp(value, "none")) + { + loc->type = AUTH_NONE; + loc->level = AUTH_ANON; + } + else if (!strcasecmp(value, "basic")) + { + loc->type = AUTH_BASIC; + + if (loc->level == AUTH_ANON) + loc->level = AUTH_USER; + } + else if (!strcasecmp(value, "digest")) + { + loc->type = AUTH_DIGEST; + + if (loc->level == AUTH_ANON) + loc->level = AUTH_USER; + } + else if (!strcasecmp(value, "basicdigest")) + { + loc->type = AUTH_BASICDIGEST; + + if (loc->level == AUTH_ANON) + loc->level = AUTH_USER; + } + else + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Unknown authorization type %s on line %d.", + value, linenum); + return (0); + } + } + else if (!strcasecmp(line, "AuthClass")) + { + /* + * AuthClass anonymous, user, system, group + */ + + if (!strcasecmp(value, "anonymous")) + { + loc->type = AUTH_NONE; + loc->level = AUTH_ANON; + + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthClass %s\" is deprecated; consider removing " + "it from line %d.", + value, linenum); + } + else if (!strcasecmp(value, "user")) + { + loc->level = AUTH_USER; + + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthClass %s\" is deprecated; consider using " + "\"Require valid-user\" on line %d.", + value, linenum); + } + else if (!strcasecmp(value, "group")) + { + loc->level = AUTH_GROUP; + + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthClass %s\" is deprecated; consider using " + "\"Require @groupname\" on line %d.", + value, linenum); + } + else if (!strcasecmp(value, "system")) + { + loc->level = AUTH_GROUP; + + cupsdAddName(loc, "@SYSTEM"); + + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthClass %s\" is deprecated; consider using " + "\"Require @SYSTEM\" on line %d.", + value, linenum); + } + else + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Unknown authorization class %s on line %d.", + value, linenum); + return (0); + } + } + else if (!strcasecmp(line, "AuthGroupName")) + { + cupsdAddName(loc, value); + + cupsdLogMessage(CUPSD_LOG_WARN, + "\"AuthGroupName %s\" directive is deprecated; consider " + "using \"Require @%s\" on line %d.", + value, value, linenum); + } + else if (!strcasecmp(line, "Require")) + { + /* + * Apache synonym for AuthClass and AuthGroupName... + * + * Get initial word: + * + * Require valid-user + * Require group names + * Require user names + */ + + for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); + + if (*valptr) + *valptr++ = '\0'; + + if (!strcasecmp(value, "valid-user") || + !strcasecmp(value, "user")) + loc->level = AUTH_USER; + else if (!strcasecmp(value, "group")) + loc->level = AUTH_GROUP; + else + { + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Require type %s on line %d.", + value, linenum); + return (0); + } + + /* + * Get the list of names from the line... + */ + + for (value = valptr; *value;) + { + while (isspace(*value & 255)) + value ++; + + if (*value == '\"' || *value == '\'') + { + /* + * Grab quoted name... + */ + + for (valptr = value + 1; *valptr != *value && *valptr; valptr ++); + + value ++; + } + else + { + /* + * Grab literal name. + */ + + for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); + } + + if (*valptr) + *valptr++ = '\0'; + + cupsdAddName(loc, value); + + for (value = valptr; isspace(*value & 255); value ++); + } + } + else if (!strcasecmp(line, "Satisfy")) + { + if (!strcasecmp(value, "all")) + loc->satisfy = AUTH_SATISFY_ALL; + else if (!strcasecmp(value, "any")) + loc->satisfy = AUTH_SATISFY_ANY; + else + { + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown Satisfy value %s on line %d.", + value, linenum); + return (0); + } + } + else + return (0); + + return (1); +} + + +/* + * 'read_configuration()' - Read a configuration file. + */ + +static int /* O - 1 on success, 0 on failure */ +read_configuration(cups_file_t *fp) /* I - File to read from */ +{ + int i; /* Looping var */ + int linenum; /* Current line number */ + char line[HTTP_MAX_BUFFER], + /* Line from file */ + temp[HTTP_MAX_BUFFER], + /* Temporary buffer for value */ + temp2[HTTP_MAX_BUFFER], + /* Temporary buffer 2 for value */ + *ptr, /* Pointer into line/temp */ + *value, /* Pointer to value */ + *valueptr, /* Pointer into value */ + quote; /* Quote character */ + int valuelen; /* Length of value */ + cupsd_var_t *var; /* Current variable */ + http_addrlist_t *addrlist, /* Address list */ + *addr; /* Current address */ + unsigned ip[4], /* Address value */ + mask[4]; /* Netmask value */ + cupsd_dirsvc_relay_t *relay; /* Relay data */ + cupsd_dirsvc_poll_t *pollp; /* Polling data */ + cupsd_location_t *location; /* Browse location */ + cups_file_t *incfile; /* Include file */ + char incname[1024]; /* Include filename */ + struct group *group; /* Group */ + + + /* + * Loop through each line in the file... + */ + + linenum = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + /* + * Decode the directive... + */ + + if (!strcasecmp(line, "Include")) + { + /* + * Include filename + */ + + if (value[0] == '/') + strlcpy(incname, value, sizeof(incname)); + else + snprintf(incname, sizeof(incname), "%s/%s", ServerRoot, value); + + if ((incfile = cupsFileOpen(incname, "rb")) == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to include config file \"%s\" - %s", + incname, strerror(errno)); + else + { + read_configuration(incfile); + cupsFileClose(incfile); + } + } + else if (!strcasecmp(line, " + */ + + if (value) + { + linenum = read_location(fp, value, linenum); + if (linenum == 0) + return (0); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", + linenum); + return (0); + } + } + else if (!strcasecmp(line, " + */ + + if (value) + { + linenum = read_policy(fp, value, linenum); + if (linenum == 0) + return (0); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum); + return (0); + } + } + else if (!strcasecmp(line, "FaxRetryInterval")) + { + if (value) + { + JobRetryInterval = atoi(value); + cupsdLogMessage(CUPSD_LOG_WARN, + "FaxRetryInterval is deprecated; use " + "JobRetryInterval on line %d.", linenum); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum); + return (0); + } + } + else if (!strcasecmp(line, "FaxRetryLimit")) + { + if (value) + { + JobRetryLimit = atoi(value); + cupsdLogMessage(CUPSD_LOG_WARN, + "FaxRetryLimit is deprecated; use " + "JobRetryLimit on line %d.", linenum); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Syntax error on line %d.", linenum); + return (0); + } + } + else if (!strcasecmp(line, "Port") || !strcasecmp(line, "Listen") +#ifdef HAVE_SSL + || !strcasecmp(line, "SSLPort") || !strcasecmp(line, "SSLListen") +#endif /* HAVE_SSL */ + ) + { + /* + * Add listening address(es) to the list... + */ + + cupsd_listener_t *lis; /* New listeners array */ + + + /* + * Get the address list... + */ + + addrlist = get_address(value, IPP_PORT); + + if (!addrlist) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad %s address %s at line %d.", line, + value, linenum); + continue; + } + + /* + * Add each address... + */ + + for (addr = addrlist; addr; addr = addr->next) + { + /* + * Allocate another listener... + */ + + if (NumListeners == 0) + lis = malloc(sizeof(cupsd_listener_t)); + else + lis = realloc(Listeners, (NumListeners + 1) * sizeof(cupsd_listener_t)); + + if (!lis) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate %s at line %d - %s.", + line, linenum, strerror(errno)); + break; + } + + Listeners = lis; + lis += NumListeners; + + /* + * Copy the current address and log it... + */ + + memset(lis, 0, sizeof(cupsd_listener_t)); + memcpy(&(lis->address), &(addr->addr), sizeof(lis->address)); + +#ifdef HAVE_SSL + if (!strcasecmp(line, "SSLPort") || !strcasecmp(line, "SSLListen")) + lis->encryption = HTTP_ENCRYPT_ALWAYS; +#endif /* HAVE_SSL */ + +#ifdef AF_INET6 + if (lis->address.addr.sa_family == AF_INET6) + cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv6)", temp, + ntohs(lis->address.ipv6.sin6_port)); + else +#endif /* AF_INET6 */ +#ifdef AF_LOCAL + if (lis->address.addr.sa_family == AF_LOCAL) + cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s (Domain)", temp); + else +#endif /* AF_LOCAL */ + cupsdLogMessage(CUPSD_LOG_INFO, "Listening to %s:%d (IPv4)", temp, + ntohs(lis->address.ipv4.sin_port)); + + NumListeners ++; + } + + /* + * Free the list... + */ + + httpAddrFreeList(addrlist); + } + else if (!strcasecmp(line, "BrowseAddress")) + { + /* + * Add a browse address to the list... + */ + + cupsd_dirsvc_addr_t *dira; /* New browse address array */ + + + if (NumBrowsers == 0) + dira = malloc(sizeof(cupsd_dirsvc_addr_t)); + else + dira = realloc(Browsers, (NumBrowsers + 1) * sizeof(cupsd_dirsvc_addr_t)); + + if (!dira) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate BrowseAddress at line %d - %s.", + linenum, strerror(errno)); + continue; + } + + Browsers = dira; + dira += NumBrowsers; + + memset(dira, 0, sizeof(cupsd_dirsvc_addr_t)); + + if (!strcasecmp(value, "@LOCAL")) + { + /* + * Send browse data to all local interfaces... + */ + + strcpy(dira->iface, "*"); + NumBrowsers ++; + } + else if (!strncasecmp(value, "@IF(", 4)) + { + /* + * Send browse data to the named interface... + */ + + strlcpy(dira->iface, value + 4, sizeof(Browsers[0].iface)); + + ptr = dira->iface + strlen(dira->iface) - 1; + if (*ptr == ')') + *ptr = '\0'; + + NumBrowsers ++; + } + else if ((addrlist = get_address(value, BrowsePort)) != NULL) + { + /* + * Only IPv4 addresses are supported... + */ + + for (addr = addrlist; addr; addr = addr->next) + if (addr->addr.addr.sa_family == AF_INET) + break; + + if (addr) + { + memcpy(&(dira->to), &(addrlist->addr), sizeof(dira->to)); + httpAddrString(&(dira->to), temp, sizeof(temp)); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Sending browsing info to %s:%d (IPv4)", + temp, ntohs(dira->to.ipv4.sin_port)); + + NumBrowsers ++; + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.", + value, linenum); + + httpAddrFreeList(addrlist); + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad BrowseAddress %s at line %d.", + value, linenum); + } + else if (!strcasecmp(line, "BrowseOrder")) + { + /* + * "BrowseOrder Deny,Allow" or "BrowseOrder Allow,Deny"... + */ + + if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) + location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL"); + + if (location == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to initialize browse access control list!"); + else if (!strncasecmp(value, "deny", 4)) + location->order_type = AUTH_ALLOW; + else if (!strncasecmp(value, "allow", 5)) + location->order_type = AUTH_DENY; + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown BrowseOrder value %s on line %d.", + value, linenum); + } + else if (!strcasecmp(line, "BrowseProtocols") || + !strcasecmp(line, "BrowseLocalProtocols") || + !strcasecmp(line, "BrowseRemoteProtocols")) + { + /* + * "BrowseProtocol name [... name]" + */ + + if (strcasecmp(line, "BrowseLocalProtocols")) + BrowseRemoteProtocols = 0; + if (strcasecmp(line, "BrowseRemoteProtocols")) + BrowseLocalProtocols = 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")) + { + if (strcasecmp(line, "BrowseLocalProtocols")) + BrowseRemoteProtocols |= BROWSE_CUPS; + if (strcasecmp(line, "BrowseRemoteProtocols")) + BrowseLocalProtocols |= BROWSE_CUPS; + } + else if (!strcasecmp(value, "slp")) + { + if (strcasecmp(line, "BrowseLocalProtocols")) + BrowseRemoteProtocols |= BROWSE_SLP; + if (strcasecmp(line, "BrowseRemoteProtocols")) + BrowseLocalProtocols |= BROWSE_SLP; + } + else if (!strcasecmp(value, "ldap")) + { + if (strcasecmp(line, "BrowseLocalProtocols")) + BrowseRemoteProtocols |= BROWSE_LDAP; + if (strcasecmp(line, "BrowseRemoteProtocols")) + BrowseLocalProtocols |= BROWSE_LDAP; + } + else if (!strcasecmp(value, "all")) + { + if (strcasecmp(line, "BrowseLocalProtocols")) + BrowseRemoteProtocols |= BROWSE_ALL; + if (strcasecmp(line, "BrowseRemoteProtocols")) + BrowseLocalProtocols |= BROWSE_ALL; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown browse protocol \"%s\" on line %d.", + value, linenum); + break; + } + + for (value += valuelen; *value; value ++) + if (!isspace(*value) || *value != ',') + break; + } + } + else if (!strcasecmp(line, "BrowseAllow") || + !strcasecmp(line, "BrowseDeny")) + { + /* + * BrowseAllow [From] host/ip... + * BrowseDeny [From] host/ip... + */ + + if ((location = cupsdFindLocation("CUPS_INTERNAL_BROWSE_ACL")) == NULL) + location = cupsdAddLocation("CUPS_INTERNAL_BROWSE_ACL"); + + if (location == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to initialize browse access control list!"); + else + { + if (!strncasecmp(value, "from ", 5)) + { + /* + * 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")) + { + /* + * All hosts... + */ + + if (!strcasecmp(line, "BrowseAllow")) + cupsdAllowIP(location, zeros, zeros); + else + cupsdDenyIP(location, zeros, zeros); + } + else if (!strcasecmp(value, "none")) + { + /* + * No hosts... + */ + + if (!strcasecmp(line, "BrowseAllow")) + cupsdAllowIP(location, ones, zeros); + else + cupsdDenyIP(location, ones, zeros); + } + else if (value[0] == '*' || value[0] == '.' || !isdigit(value[0])) + { + /* + * Host or domain name... + */ + + if (value[0] == '*') + value ++; + + if (!strcasecmp(line, "BrowseAllow")) + cupsdAllowHost(location, value); + else + cupsdDenyHost(location, value); + } + else + { + /* + * One of many IP address forms... + */ + + if (!get_addr_and_mask(value, ip, mask)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.", + value, linenum); + break; + } + + if (!strcasecmp(line, "BrowseAllow")) + cupsdAllowIP(location, ip, mask); + else + cupsdDenyIP(location, ip, mask); + } + } + } + else if (!strcasecmp(line, "BrowseRelay")) + { + /* + * BrowseRelay [from] source [to] destination + */ + + if (NumRelays == 0) + relay = malloc(sizeof(cupsd_dirsvc_relay_t)); + else + relay = realloc(Relays, (NumRelays + 1) * sizeof(cupsd_dirsvc_relay_t)); + + if (!relay) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate BrowseRelay at line %d - %s.", + linenum, strerror(errno)); + continue; + } + + Relays = relay; + relay += NumRelays; + + memset(relay, 0, sizeof(cupsd_dirsvc_relay_t)); + + if (!strncasecmp(value, "from ", 5)) + { + /* + * 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 ++; + + strlcpy(temp, value, sizeof(temp)); + if ((ptr = strchr(temp, ' ')) != NULL) + *ptr = '\0'; + + relay->from.type = AUTH_NAME; + relay->from.mask.name.name = strdup(temp); + relay->from.mask.name.length = strlen(temp); + } + else + { + /* + * One of many IP address forms... + */ + + if (!get_addr_and_mask(value, ip, mask)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad netmask value %s on line %d.", + value, linenum); + break; + } + + relay->from.type = AUTH_IP; + memcpy(relay->from.mask.ip.address, ip, + sizeof(relay->from.mask.ip.address)); + memcpy(relay->from.mask.ip.netmask, mask, + sizeof(relay->from.mask.ip.netmask)); + } + + /* + * Skip value and trailing whitespace... + */ + + for (; *value; value ++) + if (isspace(*value)) + break; + + while (isspace(*value)) + value ++; + + if (!strncasecmp(value, "to ", 3)) + { + /* + * Strip leading "to"... + */ + + value += 3; + + while (isspace(*value)) + value ++; + } + + /* + * Get "to" address and port... + */ + + if ((addrlist = get_address(value, BrowsePort)) != NULL) + { + /* + * Only IPv4 addresses are supported... + */ + + for (addr = addrlist; addr; addr = addr->next) + if (addr->addr.addr.sa_family == AF_INET) + break; + + if (addr) + { + memcpy(&(relay->to), &(addrlist->addr), sizeof(relay->to)); + + httpAddrString(&(relay->to), temp, sizeof(temp)); + + if (relay->from.type == AUTH_IP) + snprintf(temp2, sizeof(temp2), "%u.%u.%u.%u/%u.%u.%u.%u", + relay->from.mask.ip.address[0], + relay->from.mask.ip.address[1], + relay->from.mask.ip.address[2], + relay->from.mask.ip.address[3], + relay->from.mask.ip.netmask[0], + relay->from.mask.ip.netmask[1], + relay->from.mask.ip.netmask[2], + relay->from.mask.ip.netmask[3]); + else + strlcpy(temp2, relay->from.mask.name.name, sizeof(temp2)); + + cupsdLogMessage(CUPSD_LOG_INFO, "Relaying from %s to %s:%d (IPv4)", + temp, temp2, ntohs(relay->to.ipv4.sin_port)); + + NumRelays ++; + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.", + value, linenum); + + httpAddrFreeList(addrlist); + } + else + { + if (relay->from.type == AUTH_NAME) + free(relay->from.mask.name.name); + + cupsdLogMessage(CUPSD_LOG_ERROR, "Bad relay address %s at line %d.", + value, linenum); + } + } + else if (!strcasecmp(line, "BrowsePoll")) + { + /* + * BrowsePoll address[:port] + */ + + char *portname; /* Port name */ + int portnum; /* Port number */ + struct servent *service; /* Service */ + + + /* + * Extract the port name from the address... + */ + + if ((portname = strrchr(value, ':')) != NULL && !strchr(portname, ']')) + { + *portname++ = '\0'; + + if (isdigit(*portname & 255)) + portnum = atoi(portname); + else if ((service = getservbyname(portname, NULL)) != NULL) + portnum = ntohs(service->s_port); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Lookup of service \"%s\" failed!", + portname); + continue; + } + } + else + portnum = ippPort(); + + /* + * Add the poll entry... + */ + + if (NumPolled == 0) + pollp = malloc(sizeof(cupsd_dirsvc_poll_t)); + else + pollp = realloc(Polled, (NumPolled + 1) * sizeof(cupsd_dirsvc_poll_t)); + + if (!pollp) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to allocate BrowsePoll at line %d - %s.", + linenum, strerror(errno)); + continue; + } + + Polled = pollp; + pollp += NumPolled; + + NumPolled ++; + memset(pollp, 0, sizeof(cupsd_dirsvc_poll_t)); + + strlcpy(pollp->hostname, value, sizeof(pollp->hostname)); + pollp->port = portnum; + + cupsdLogMessage(CUPSD_LOG_INFO, "Polling %s:%d", pollp->hostname, + pollp->port); + } + else if (!strcasecmp(line, "DefaultAuthType")) + { + /* + * DefaultAuthType {basic,digest,basicdigest} + */ + + if (!strcasecmp(value, "basic")) + DefaultAuthType = AUTH_BASIC; + else if (!strcasecmp(value, "digest")) + DefaultAuthType = AUTH_DIGEST; + else if (!strcasecmp(value, "basicdigest")) + DefaultAuthType = AUTH_BASICDIGEST; + else + { + cupsdLogMessage(CUPSD_LOG_WARN, + "Unknown default authorization type %s on line %d.", + value, linenum); + return (0); + } + } + else if (!strcasecmp(line, "User")) + { + /* + * User ID to run as... + */ + + if (value && isdigit(value[0] & 255)) + { + int uid = atoi(value); + + if (!uid) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Will not use User 0 as specified on line %d " + "for security reasons. You must use a non-" + "privileged account instead.", + linenum); + else + User = atoi(value); + } + else if (value) + { + struct passwd *p; /* Password information */ + + endpwent(); + p = getpwnam(value); + + if (p) + { + if (!p->pw_uid) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Will not use User %s (UID=0) as specified on line " + "%d for security reasons. You must use a non-" + "privileged account instead.", + value, linenum); + else + User = p->pw_uid; + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown User \"%s\" on line %d, ignoring!", + value, linenum); + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "User directive on line %d missing the username!", + linenum); + } + else if (!strcasecmp(line, "Group")) + { + /* + * Group ID to run as... + */ + + if (isdigit(value[0])) + Group = atoi(value); + else + { + endgrent(); + group = getgrnam(value); + + if (group != NULL) + Group = group->gr_gid; + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Group \"%s\" on line %d, ignoring!", + value, linenum); + } + } + else if (!strcasecmp(line, "SystemGroup")) + { + /* + * System (admin) group(s)... + */ + + for (i = NumSystemGroups; *value && i < MAX_SYSTEM_GROUPS;) + { + if (*value == '\'' || *value == '\"') + { + /* + * Scan quoted name... + */ + + quote = *value++; + + for (valueptr = value; *valueptr; valueptr ++) + if (*valueptr == quote) + break; + } + else + { + /* + * Scan space or comma-delimited name... + */ + + for (valueptr = value; *valueptr; valueptr ++) + if (isspace(*valueptr) || *valueptr == ',') + break; + } + + if (*valueptr) + *valueptr++ = '\0'; + + group = getgrnam(value); + if (group) + { + cupsdSetString(SystemGroups + i, value); + SystemGroupIDs[i] = group->gr_gid; + + i ++; + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown SystemGroup \"%s\" on line %d, ignoring!", + value, linenum); + + endgrent(); + + value = valueptr; + + while (*value == ',' || isspace(*value)) + value ++; + } + + if (i) + NumSystemGroups = i; + } + else if (!strcasecmp(line, "HostNameLookups")) + { + /* + * Do hostname lookups? + */ + + if (!strcasecmp(value, "off")) + HostNameLookups = 0; + else if (!strcasecmp(value, "on")) + HostNameLookups = 1; + else if (!strcasecmp(value, "double")) + HostNameLookups = 2; + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown HostNameLookups %s on line %d.", + value, linenum); + } + else if (!strcasecmp(line, "LogLevel")) + { + /* + * Amount of logging to do... + */ + + if (!strcasecmp(value, "debug2")) + LogLevel = CUPSD_LOG_DEBUG2; + else if (!strcasecmp(value, "debug")) + LogLevel = CUPSD_LOG_DEBUG; + else if (!strcasecmp(value, "info")) + LogLevel = CUPSD_LOG_INFO; + else if (!strcasecmp(value, "notice")) + LogLevel = CUPSD_LOG_NOTICE; + else if (!strcasecmp(value, "warn")) + LogLevel = CUPSD_LOG_WARN; + else if (!strcasecmp(value, "error")) + LogLevel = CUPSD_LOG_ERROR; + else if (!strcasecmp(value, "crit")) + LogLevel = CUPSD_LOG_CRIT; + else if (!strcasecmp(value, "alert")) + LogLevel = CUPSD_LOG_ALERT; + else if (!strcasecmp(value, "emerg")) + LogLevel = CUPSD_LOG_EMERG; + else if (!strcasecmp(value, "none")) + LogLevel = CUPSD_LOG_NONE; + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown LogLevel %s on line %d.", + value, linenum); + } + else if (!strcasecmp(line, "PrintcapFormat")) + { + /* + * Format of printcap file? + */ + + if (!strcasecmp(value, "bsd")) + PrintcapFormat = PRINTCAP_BSD; + else if (!strcasecmp(value, "solaris")) + PrintcapFormat = PRINTCAP_SOLARIS; + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown PrintcapFormat %s on line %d.", + value, linenum); + } + else if (!strcasecmp(line, "ServerTokens")) + { + /* + * Set the string used for the Server header... + */ + + struct utsname plat; /* Platform info */ + + + uname(&plat); + + if (!strcasecmp(value, "ProductOnly")) + cupsdSetString(&ServerHeader, "CUPS"); + else if (!strcasecmp(value, "Major")) + cupsdSetString(&ServerHeader, "CUPS/1"); + else if (!strcasecmp(value, "Minor")) + cupsdSetString(&ServerHeader, "CUPS/1.1"); + else if (!strcasecmp(value, "Minimal")) + cupsdSetString(&ServerHeader, CUPS_MINIMAL); + else if (!strcasecmp(value, "OS")) + cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s)", plat.sysname); + else if (!strcasecmp(value, "Full")) + cupsdSetStringf(&ServerHeader, CUPS_MINIMAL " (%s) IPP/1.1", + plat.sysname); + else if (!strcasecmp(value, "None")) + cupsdClearString(&ServerHeader); + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown ServerTokens %s on line %d.", + value, linenum); + } + else if (!strcasecmp(line, "PassEnv")) + { + /* + * PassEnv variable [... variable] + */ + + for (; *value;) + { + for (valuelen = 0; value[valuelen]; valuelen ++) + if (isspace(value[valuelen]) || value[valuelen] == ',') + break; + + if (value[valuelen]) + { + value[valuelen] = '\0'; + valuelen ++; + } + + cupsdSetEnv(value, NULL); + + for (value += valuelen; *value; value ++) + if (!isspace(*value) || *value != ',') + break; + } + } + else if (!strcasecmp(line, "SetEnv")) + { + /* + * SetEnv variable value + */ + + for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); + + if (*valueptr) + { + /* + * Found a value... + */ + + while (isspace(*valueptr & 255)) + *valueptr++ = '\0'; + + cupsdSetEnv(value, valueptr); + } + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing value for SetEnv directive on line %d.", + linenum); + } + else + { + /* + * Find a simple variable in the list... + */ + + for (i = NUM_VARS, var = variables; i > 0; i --, var ++) + if (!strcasecmp(line, var->name)) + break; + + if (i == 0) + { + /* + * Unknown directive! Output an error message and continue... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, "Unknown directive %s on line %d.", + line, linenum); + continue; + } + + switch (var->type) + { + case CUPSD_VARTYPE_INTEGER : + { + int n; /* Number */ + char *units; /* Units */ + + + n = strtol(value, &units, 0); + + if (units && *units) + { + if (tolower(units[0] & 255) == 'g') + n *= 1024 * 1024 * 1024; + else if (tolower(units[0] & 255) == 'm') + n *= 1024 * 1024; + else if (tolower(units[0] & 255) == 'k') + n *= 1024; + else if (tolower(units[0] & 255) == 't') + n *= 262144; + } + + *((int *)var->ptr) = n; + } + break; + + case CUPSD_VARTYPE_BOOLEAN : + if (!strcasecmp(value, "true") || + !strcasecmp(value, "on") || + !strcasecmp(value, "enabled") || + !strcasecmp(value, "yes") || + atoi(value) != 0) + *((int *)var->ptr) = TRUE; + else if (!strcasecmp(value, "false") || + !strcasecmp(value, "off") || + !strcasecmp(value, "disabled") || + !strcasecmp(value, "no") || + !strcasecmp(value, "0")) + *((int *)var->ptr) = FALSE; + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown boolean value %s on line %d.", + value, linenum); + break; + + case CUPSD_VARTYPE_STRING : + cupsdSetString((char **)var->ptr, value); + break; + } + } + } + + return (1); +} + + +/* + * 'read_location()' - Read a definition. + */ + +static int /* O - New line number or 0 on error */ +read_location(cups_file_t *fp, /* I - Configuration file */ + char *location, /* I - Location name/path */ + int linenum) /* I - Current line number */ +{ + cupsd_location_t *loc, /* New location */ + *parent; /* Parent location */ + char line[HTTP_MAX_BUFFER], + /* Line buffer */ + *value, /* Value for directive */ + *valptr; /* Pointer into value */ + + + if ((parent = cupsdAddLocation(location)) == NULL) + return (0); + + parent->limit = AUTH_LIMIT_ALL; + loc = parent; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + /* + * Decode the directive... + */ + + if (!strcasecmp(line, "")) + return (linenum); + else if (!strcasecmp(line, "limit = 0; + while (*value) + { + for (valptr = value; !isspace(*valptr & 255) && *valptr; valptr ++); + + if (*valptr) + *valptr++ = '\0'; + + if (!strcmp(value, "ALL")) + loc->limit = AUTH_LIMIT_ALL; + else if (!strcmp(value, "GET")) + loc->limit |= AUTH_LIMIT_GET; + else if (!strcmp(value, "HEAD")) + loc->limit |= AUTH_LIMIT_HEAD; + else if (!strcmp(value, "OPTIONS")) + loc->limit |= AUTH_LIMIT_OPTIONS; + else if (!strcmp(value, "POST")) + loc->limit |= AUTH_LIMIT_POST; + else if (!strcmp(value, "PUT")) + loc->limit |= AUTH_LIMIT_PUT; + else if (!strcmp(value, "TRACE")) + loc->limit |= AUTH_LIMIT_TRACE; + else + cupsdLogMessage(CUPSD_LOG_WARN, "Unknown request type %s on line %d!", + value, linenum); + + for (value = valptr; isspace(*value & 255); value ++); + } + + if (!strcasecmp(line, "limit = AUTH_LIMIT_ALL ^ loc->limit; + + parent->limit &= ~loc->limit; + } + else if (!strcasecmp(line, "")) + loc = parent; + else if (!parse_aaa(loc, line, value, linenum)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Location directive %s on line %d.", + line, linenum); + return (0); + } + } + + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unexpected end-of-file at line %d while reading location!", + linenum); + + return (0); +} + + +/* + * 'read_policy()' - Read a definition. + */ + +static int /* O - New line number or 0 on error */ +read_policy(cups_file_t *fp, /* I - Configuration file */ + char *policy, /* I - Location name/path */ + int linenum) /* I - Current line number */ +{ + int i; /* Looping var */ + cupsd_policy_t *pol; /* Policy */ + cupsd_location_t *op; /* Policy operation */ + int num_ops; /* Number of IPP operations */ + ipp_op_t ops[100]; /* Operations */ + char line[HTTP_MAX_BUFFER], + /* Line buffer */ + *value, /* Value for directive */ + *valptr; /* Pointer into value */ + + + /* + * Create the policy... + */ + + if ((pol = cupsdAddPolicy(policy)) == NULL) + return (0); + + /* + * Read from the file... + */ + + op = NULL; + num_ops = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + /* + * Decode the directive... + */ + + if (!strcasecmp(line, "")) + { + if (op) + cupsdLogMessage(CUPSD_LOG_WARN, + "Missing before on line %d!", + linenum); + + return (linenum); + } + else if (!strcasecmp(line, "") && op) + { + /* + * Finish the current operation limit... + */ + + if (num_ops > 1) + { + /* + * Copy the policy to the other operations... + */ + + for (i = 1; i < num_ops; i ++) + cupsdAddPolicyOp(pol, op, ops[i]); + } + + op = NULL; + } + else if (!op) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing directive before %s on line %d.", + line, linenum); + return (0); + } + else if (!parse_aaa(op, line, value, linenum)) + { + if (op) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Policy Limit directive %s on line %d.", + line, linenum); + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown Policy directive %s on line %d.", + line, linenum); + + return (0); + } + } + + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unexpected end-of-file at line %d while reading policy \"%s\"!", + linenum, policy); + + return (0); +} + + +/* + * End of "$Id: conf.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/scheduler/conf.h b/scheduler/conf.h new file mode 100644 index 000000000..314a0d7c6 --- /dev/null +++ b/scheduler/conf.h @@ -0,0 +1,211 @@ +/* + * "$Id: conf.h 4719 2005-09-28 21:12:44Z mike $" + * + * Configuration file definitions for the Common UNIX Printing System (CUPS) + * scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + + +/* + * Log levels... + */ + +typedef enum +{ + CUPSD_LOG_ATTR = -3, /* Used internally for attributes */ + CUPSD_LOG_STATE, /* Used internally for state-reasons */ + CUPSD_LOG_PAGE, /* Used internally for page logging */ + CUPSD_LOG_NONE, + CUPSD_LOG_EMERG, /* Emergency issues */ + CUPSD_LOG_ALERT, /* Something bad happened that needs attention */ + CUPSD_LOG_CRIT, /* Critical error but server continues */ + CUPSD_LOG_ERROR, /* Error condition */ + CUPSD_LOG_WARN, /* Warning */ + CUPSD_LOG_NOTICE, /* Normal condition that needs logging */ + CUPSD_LOG_INFO, /* General information */ + CUPSD_LOG_DEBUG, /* General debugging */ + CUPSD_LOG_DEBUG2 /* Detailed debugging */ +} cupsd_loglevel_t; + + +/* + * Printcap formats... + */ + +#define PRINTCAP_BSD 0 /* Berkeley LPD format */ +#define PRINTCAP_SOLARIS 1 /* Solaris lpsched format */ + + +/* + * Globals... + */ + +VAR char *ConfigurationFile VALUE(NULL), + /* Configuration file to use */ + *ServerName VALUE(NULL), + /* FQDN for server */ + *ServerAdmin VALUE(NULL), + /* Administrator's email */ + *ServerRoot VALUE(NULL), + /* Root directory for scheduler */ + *ServerBin VALUE(NULL), + /* Root directory for binaries */ + *StateDir VALUE(NULL), + /* Root directory for state data */ + *RequestRoot VALUE(NULL), + /* Directory for request files */ + *DocumentRoot VALUE(NULL); + /* Root directory for documents */ +VAR int NumSystemGroups VALUE(0); + /* Number of system group names */ +VAR char *SystemGroups[MAX_SYSTEM_GROUPS]; + /* System group names */ +VAR int SystemGroupIDs[MAX_SYSTEM_GROUPS]; + /* System group IDs */ +VAR char *AccessLog VALUE(NULL), + /* Access log filename */ + *ErrorLog VALUE(NULL), + /* Error log filename */ + *PageLog VALUE(NULL), + /* Page log filename */ + *CacheDir VALUE(NULL), + /* Cache file directory */ + *DataDir VALUE(NULL), + /* Data file directory */ + *DefaultLanguage VALUE(NULL), + /* Default language encoding */ + *DefaultCharset VALUE(NULL), + /* Default charset */ + *DefaultLocale VALUE(NULL), + /* Default locale */ + *RIPCache VALUE(NULL), + /* Amount of memory for RIPs */ + *TempDir VALUE(NULL), + /* Temporary directory */ + *Printcap VALUE(NULL), + /* Printcap file */ + *PrintcapGUI VALUE(NULL), + /* GUI program to use for IRIX */ + *FontPath VALUE(NULL), + /* Font search path */ + *RemoteRoot VALUE(NULL), + /* Remote root user */ + *Classification VALUE(NULL); + /* Classification of system */ +VAR uid_t User VALUE(1); + /* User ID for server */ +VAR gid_t Group VALUE(0); + /* Group ID for server */ +VAR int ClassifyOverride VALUE(0), + /* Allow overrides? */ + ConfigFilePerm VALUE(0640), + /* Permissions for config files */ + LogFilePerm VALUE(0644), + /* Permissions for log files */ + LogLevel VALUE(CUPSD_LOG_ERROR), + /* Log level */ + MaxClients VALUE(0), + /* Maximum number of clients */ + MaxClientsPerHost VALUE(0), + /* Maximum number of clients per host */ + MaxCopies VALUE(100), + /* Maximum number of copies per job */ + MaxLogSize VALUE(1024 * 1024), + /* Maximum size of log files */ + MaxPrinterHistory VALUE(10), + /* Maximum printer state history */ + 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? */ + FileDevice VALUE(FALSE), + /* Allow file: devices? */ + FilterLimit VALUE(0), + /* Max filter cost at any time */ + FilterLevel VALUE(0), + /* Current filter level */ + FilterNice VALUE(0), + /* Nice value for filters */ + ReloadTimeout VALUE(0), + /* Timeout before reload from SIGHUP */ + RootCertDuration VALUE(300), + /* Root certificate update interval */ + RunAsUser VALUE(FALSE), + /* Run as unpriviledged user? */ + RunUser, /* User to run as, used for files */ + PrintcapFormat VALUE(PRINTCAP_BSD); + /* Format of printcap file? */ +VAR cups_file_t *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_SSL +VAR char *ServerCertificate VALUE(NULL); + /* Server certificate file */ +# if defined(HAVE_LIBSSL) || defined(HAVE_GNUTLS) +VAR char *ServerKey VALUE(NULL); + /* Server key file */ +# else +VAR CFArrayRef ServerCertificatesArray VALUE(NULL); + /* Array containing certificates */ +# endif /* HAVE_LIBSSL || HAVE_GNUTLS */ +#endif /* HAVE_SSL */ + + +/* + * Prototypes... + */ + +extern char *cupsdGetDateTime(time_t t); +extern int cupsdReadConfiguration(void); +extern int cupsdLogRequest(cupsd_client_t *con, http_status_t code); +extern int cupsdLogMessage(int level, const char *message, ...) +#ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 2, 3))) +#endif /* __GNUC__ */ +; +extern int cupsdLogPage(cupsd_job_t *job, const char *page); + + +/* + * End of "$Id: conf.h 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/cups-deviced.c b/scheduler/cups-deviced.c new file mode 100644 index 000000000..6617d911c --- /dev/null +++ b/scheduler/cups-deviced.c @@ -0,0 +1,441 @@ +/* + * "$Id: cups-deviced.c 4881 2005-12-15 22:03:40Z mike $" + * + * Device scanning mini-daemon for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Scan for devices and return an IPP response. + * add_dev() - Add a new device to the list. + * compare_devs() - Compare device names for sorting. + * sigalrm_handler() - Handle alarm signals for backends that get hung + */ + +/* + * Include necessary headers... + */ + +#include "util.h" +#include +#include + + +/* + * 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 */ + device_id[1024]; /* 1284 Device ID */ +} dev_info_t; + + +/* + * Local globals... + */ + +static int alarm_tripped; /* Non-zero if alarm was tripped */ +static cups_array_t *devs; /* Device info */ + + +/* + * Local functions... + */ + +static dev_info_t *add_dev(const char *device_class, + const char *device_make_and_model, + const char *device_info, + const char *device_uri, + const char *device_id); +static int compare_devs(dev_info_t *p0, dev_info_t *p1); +static void sigalrm_handler(int sig); + + +/* + * 'main()' - Scan for devices and return an IPP response. + * + * Usage: + * + * cups-deviced request_id limit options + */ + +int /* O - Exit code */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + const char *server_bin; /* CUPS_SERVERBIN environment variable */ + char backends[1024]; /* Location of backends */ + int count; /* Number of devices from backend */ + int compat; /* Compatibility device? */ + FILE *fp; /* Pipe to device backend */ + cups_dir_t *dir; /* Directory pointer */ + cups_dentry_t *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 */ + device_id[1024]; /* 1284 device ID */ + int num_options; /* Number of options */ + cups_option_t *options; /* Options */ + const char *requested; /* requested-attributes option */ + int send_class, /* Send device-class attribute? */ + send_info, /* Send device-info attribute? */ + send_make_and_model, /* Send device-make-and-model attribute? */ + send_uri, /* Send device-uri attribute? */ + send_id; /* Send device-id attribute? */ + 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 */ + + + /* + * Check the command-line... + */ + + if (argc != 4) + { + fputs("Usage: cups-deviced request_id limit options\n", stderr); + return (1); + } + + num_options = cupsParseOptions(argv[3], 0, &options); + requested = cupsGetOption("requested-attributes", num_options, options); + + if (!requested || strstr(requested, "all")) + { + send_class = 1; + send_info = 1; + send_make_and_model = 1; + send_uri = 1; + send_id = 1; + } + else + { + send_class = strstr(requested, "device-class") != NULL; + send_info = strstr(requested, "device-info") != NULL; + send_make_and_model = strstr(requested, "device-make-and-model") != NULL; + send_uri = strstr(requested, "device-uri") != NULL; + send_id = strstr(requested, "device-id") != NULL; + } + + /* + * Try opening the backend directory... + */ + + if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL) + server_bin = CUPS_SERVERBIN; + + snprintf(backends, sizeof(backends), "%s/backend", server_bin); + + if ((dir = cupsDirOpen(backends)) == NULL) + { + fprintf(stderr, "ERROR: [cups-deviced] Unable to open backend directory \"%s\": %s", + backends, strerror(errno)); + return (1); + } + + /* + * Setup the devices array... + */ + + devs = cupsArrayNew((cups_array_func_t)compare_devs, NULL); + + /* + * Loop through all of the device backends... + */ + + while ((dent = cupsDirRead(dir)) != NULL) + { + /* + * Run the backend with no arguments and collect the output... + */ + + snprintf(filename, sizeof(filename), "%s/%s", backends, dent->filename); + 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_tripped = 0; + count = 0; + compat = !strcmp(dent->filename, "smb"); + + alarm(30); + + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * Reset the alarm clock... + */ + + alarm(30); + + /* + * Each line is of the form: + * + * class URI "make model" "name" ["1284 device ID"] + */ + + device_id[0] = '\0'; + + if (!strncasecmp(line, "Usage", 5)) + compat = 1; + else if (sscanf(line, + "%63s%1023s%*[ \t]\"%255[^\"]\"%*[ \t]\"%127[^\"]" + "%*[ \t]\"%1023[^\"]", + dclass, uri, make_model, info, device_id) < 4) + { + /* + * Bad format; strip trailing newline and write an error message. + */ + + if (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = '\0'; + + fprintf(stderr, "ERROR: [cups-deviced] Bad line from \"%s\": %s\n", + dent->filename, line); + compat = 1; + break; + } + else + { + /* + * Add the device to the array of available devices... + */ + + dev = add_dev(dclass, make_model, info, uri, device_id); + if (!dev) + { + cupsDirClose(dir); + return (1); + } + + fprintf(stderr, "DEBUG: [cups-deviced] Added device \"%s\"...\n", uri); + count ++; + } + } + + /* + * Turn the alarm clock off and close the pipe to the command... + */ + + alarm(0); + + if (alarm_tripped) + fprintf(stderr, "WARNING: [cups-deviced] Backend \"%s\" did not respond within 30 seconds!\n", + dent->filename); + + 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) + { + snprintf(line, sizeof(line), "Unknown Network Device (%s)", + dent->filename); + + dev = add_dev("network", line, "Unknown", dent->filename, ""); + if (!dev) + { + cupsDirClose(dir); + return (1); + } + + fprintf(stderr, "DEBUG: [cups-deviced] Compatibility device \"%s\"...\n", + dent->filename); + } + } + else + fprintf(stderr, "WARNING: [cups-deviced] Unable to execute \"%s\" backend: %s\n", + dent->filename, strerror(errno)); + } + + cupsDirClose(dir); + + /* + * Output the list of devices... + */ + + puts("Content-Type: application/ipp\n"); + + cupsdSendIPPHeader(IPP_OK, atoi(argv[1])); + cupsdSendIPPGroup(IPP_TAG_OPERATION); + cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); + cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US"); + + if ((count = atoi(argv[2])) <= 0) + count = cupsArrayCount(devs); + + if (count > cupsArrayCount(devs)) + count = cupsArrayCount(devs); + + for (dev = (dev_info_t *)cupsArrayFirst(devs); + count > 0; + count --, dev = (dev_info_t *)cupsArrayNext(devs)) + { + /* + * Add strings to attributes... + */ + + cupsdSendIPPGroup(IPP_TAG_PRINTER); + if (send_class) + cupsdSendIPPString(IPP_TAG_KEYWORD, "device-class", dev->device_class); + if (send_info) + cupsdSendIPPString(IPP_TAG_TEXT, "device-info", dev->device_info); + if (send_make_and_model) + cupsdSendIPPString(IPP_TAG_TEXT, "device-make-and-model", + dev->device_make_and_model); + if (send_uri) + cupsdSendIPPString(IPP_TAG_URI, "device-uri", dev->device_uri); + if (send_id) + cupsdSendIPPString(IPP_TAG_TEXT, "device-id", dev->device_id); + } + + cupsdSendIPPTrailer(); + + /* + * Free the devices array and return... + */ + + for (dev = (dev_info_t *)cupsArrayFirst(devs); + dev; + dev = (dev_info_t *)cupsArrayNext(devs)) + free(dev); + + cupsArrayDelete(devs); + + return (0); +} + + +/* + * 'add_dev()' - Add a new device to the list. + */ + +static dev_info_t * /* O - New device or NULL on error */ +add_dev( + const char *device_class, /* I - Device class */ + const char *device_make_and_model, /* I - Device make and model */ + const char *device_info, /* I - Device information */ + const char *device_uri, /* I - Device URI */ + const char *device_id) /* I - 1284 device ID */ +{ + dev_info_t *dev; /* New device */ + + + /* + * Allocate memory for the device record... + */ + + if ((dev = calloc(1, sizeof(dev_info_t))) == NULL) + { + fputs("ERROR: [cups-deviced] Ran out of memory allocating a device!\n", + stderr); + return (NULL); + } + + /* + * Copy the strings over... + */ + + strlcpy(dev->device_class, device_class, sizeof(dev->device_class)); + strlcpy(dev->device_make_and_model, device_make_and_model, + sizeof(dev->device_make_and_model)); + strlcpy(dev->device_info, device_info, sizeof(dev->device_info)); + strlcpy(dev->device_uri, device_uri, sizeof(dev->device_uri)); + strlcpy(dev->device_id, device_id, sizeof(dev->device_id)); + + /* + * Add the device to the array and return... + */ + + cupsArrayAdd(devs, dev); + + return (dev); +} + + +/* + * 'compare_devs()' - Compare device names for sorting. + */ + +static int /* O - Result of comparison */ +compare_devs(dev_info_t *d0, /* I - First device */ + dev_info_t *d1) /* I - Second device */ +{ + int diff; /* Difference between strings */ + + + /* + * Sort devices by device-info, device-class, and device-uri... + */ + + if ((diff = cupsdCompareNames(d0->device_info, d1->device_info)) != 0) + return (diff); + 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... */ + + alarm_tripped = 1; +} + + +/* + * End of "$Id: cups-deviced.c 4881 2005-12-15 22:03:40Z mike $". + */ diff --git a/scheduler/cups-driverd.c b/scheduler/cups-driverd.c new file mode 100644 index 000000000..21dd86dab --- /dev/null +++ b/scheduler/cups-driverd.c @@ -0,0 +1,1080 @@ +/* + * "$Id: cups-driverd.c 4812 2005-10-25 18:23:10Z mike $" + * + * PPD/driver support for the Common UNIX Printing System (CUPS). + * + * This program handles listing and installing both static PPD files + * in CUPS_DATADIR/model and dynamically generated PPD files using + * the driver helper programs in CUPS_SERVERBIN/driver. + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Scan for drivers and return an IPP response. + * add_ppd() - Add a PPD file. + * cat_ppd() - Copy a PPD file to stdout. + * compare_names() - Compare PPD filenames for sorting. + * compare_ppds() - Compare PPD file make and model names for sorting. + * list_ppds() - List PPD files. + * load_ppds() - Load PPD files recursively. + * load_drivers() - Load driver-generated PPD files. + */ + +/* + * Include necessary headers... + */ + +#include "util.h" +#include + + +/* + * PPD information structures... + */ + +typedef struct /**** PPD record ****/ +{ + time_t mtime; /* Modification time */ + size_t size; /* Size in bytes */ + char name[512 - sizeof(time_t) - sizeof(size_t)], + /* PPD name */ + natural_language[128], /* Natural language(s) */ + make[128], /* Manufacturer */ + make_and_model[256]; /* Make and model */ +} ppd_rec_t; + +typedef struct /**** In-memory record ****/ +{ + int found; /* 1 if PPD is found */ + ppd_rec_t record; /* PPDs.dat record */ +} ppd_info_t; + + +/* + * Globals... + */ + +int NumPPDs, /* Number of PPD files */ + SortedPPDs, /* Number of sorted PPD files */ + AllocPPDs; /* Number of allocated entries */ +ppd_info_t *PPDs; /* PPD file info */ +int ChangedPPD; /* Did we change the PPD database? */ + + +/* + * Local functions... + */ + +ppd_info_t *add_ppd(const char *name, const char *natural_language, + const char *make, const char *make_and_model, + time_t mtime, size_t size); +int cat_ppd(const char *name); +int compare_names(const ppd_info_t *p0, const ppd_info_t *p1); +int compare_ppds(const ppd_info_t *p0, const ppd_info_t *p1); +int list_ppds(int request_id, int limit, const char *opt); +int load_drivers(void); +int load_ppds(const char *d, const char *p); + + +/* + * 'main()' - Scan for drivers and return an IPP response. + * + * Usage: + * + * cups-driverd request_id limit options + */ + +int /* O - Exit code */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + /* + * Install or list PPDs... + */ + + if (argc == 3 && !strcmp(argv[1], "cat")) + return (cat_ppd(argv[2])); + else if (argc == 5 && !strcmp(argv[1], "list")) + return (list_ppds(atoi(argv[2]), atoi(argv[3]), argv[4])); + else + { + fputs("Usage: cups-driverd cat ppd-name\n", stderr); + fputs("Usage: cups-driverd list request_id limit options\n", stderr); + return (1); + } +} + + +/* + * 'add_ppd()' - Add a PPD file. + */ + +ppd_info_t * /* O - PPD */ +add_ppd(const char *name, /* I - PPD name */ + const char *natural_language, /* I - Language(s) */ + const char *make, /* I - Manufacturer */ + const char *make_and_model, /* I - NickName */ + time_t mtime, /* I - Modification time */ + size_t size) /* I - File size */ +{ + ppd_info_t *ppd; /* PPD */ + + + /* + * Add a new PPD file... + */ + + if (NumPPDs >= AllocPPDs) + { + /* + * Allocate (more) memory for the PPD files... + */ + + AllocPPDs += 128; + + if (!PPDs) + ppd = malloc(sizeof(ppd_info_t) * AllocPPDs); + else + ppd = realloc(PPDs, sizeof(ppd_info_t) * AllocPPDs); + + if (ppd == NULL) + { + fprintf(stderr, "ERROR: [cups-driverd] Ran out of memory for %d PPD files!\n", + AllocPPDs); + return (NULL); + } + + PPDs = ppd; + } + + ppd = PPDs + NumPPDs; + NumPPDs ++; + + /* + * Zero-out the PPD data and copy the values over... + */ + + memset(ppd, 0, sizeof(ppd_info_t)); + + ppd->found = 1; + ppd->record.mtime = mtime; + ppd->record.size = size; + + strlcpy(ppd->record.name, name, sizeof(ppd->record.name)); + strlcpy(ppd->record.natural_language, natural_language, + sizeof(ppd->record.natural_language)); + strlcpy(ppd->record.make, make, sizeof(ppd->record.make)); + strlcpy(ppd->record.make_and_model, make_and_model, + sizeof(ppd->record.make_and_model)); + + /* + * Return the new PPD pointer... + */ + + return (ppd); +} + + +/* + * 'cat_ppd()' - Copy a PPD file to stdout. + */ + +int /* O - Exit code */ +cat_ppd(const char *name) /* I - PPD name */ +{ + char scheme[256], /* Scheme from PPD name */ + *sptr; /* Pointer into scheme */ + char line[1024]; /* Line/filename */ + + + /* + * Figure out if this is a static or dynamic PPD file... + */ + + strlcpy(scheme, name, sizeof(scheme)); + if ((sptr = strchr(scheme, ':')) != NULL) + { + *sptr = '\0'; + + if (!strcmp(scheme, "file")) + { + /* + * "file:name" == "name"... + */ + + name += 5; + scheme[0] = '\0'; + } + } + else + scheme[0] = '\0'; + + if (scheme[0]) + { + /* + * Dynamic PPD, see if we have a driver program to support it... + */ + + const char *serverbin; /* CUPS_SERVERBIN env var */ + + + if ((serverbin = getenv("CUPS_SERVERBIN")) == NULL) + serverbin = CUPS_SERVERBIN; + + snprintf(line, sizeof(line), "%s/driver/%s", serverbin, scheme); + if (access(line, X_OK)) + { + /* + * File does not exist or is not executable... + */ + + fprintf(stderr, "ERROR: [cups-driverd] Unable to access \"%s\" - %s\n", + line, strerror(errno)); + return (1); + } + + /* + * Yes, let it cat the PPD file... + */ + + if (execl(line, scheme, "cat", name, (char *)NULL)) + { + /* + * Unable to execute driver... + */ + + fprintf(stderr, "ERROR: [cups-driverd] Unable to execute \"%s\" - %s\n", + line, strerror(errno)); + return (1); + } + } + else + { + /* + * Static PPD, see if we have a valid path and it exists... + */ + + cups_file_t *fp; /* PPD file */ + const char *datadir; /* CUPS_DATADIR env var */ + + + if (name[0] == '/' || strstr(name, "../") || strstr(name, "/..")) + { + /* + * Bad name... + */ + + fprintf(stderr, "ERROR: [cups-driverd] Bad PPD name \"%s\"!\n", name); + return (1); + } + + /* + * Try opening the file... + */ + + if ((datadir = getenv("CUPS_DATADIR")) == NULL) + datadir = CUPS_DATADIR; + + snprintf(line, sizeof(line), "%s/model/%s", datadir, name); + if ((fp = cupsFileOpen(line, "r")) == NULL) + { + fprintf(stderr, "ERROR: [cups-driverd] Unable to open \"%s\" - %s\n", + line, strerror(errno)); + return (1); + } + + /* + * Now copy the file to stdout... + */ + + while (cupsFileGets(fp, line, sizeof(line))) + puts(line); + + cupsFileClose(fp); + } + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'compare_names()' - Compare PPD filenames for sorting. + */ + +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.name, p1->record.name)); +} + + +/* + * 'compare_ppds()' - Compare PPD file make and model names for sorting. + */ + +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 */ +{ + int diff; /* Difference between strings */ + + /* + * First compare manufacturers... + */ + + if ((diff = strcasecmp(p0->record.make, p1->record.make)) != 0) + return (diff); + else if ((diff = cupsdCompareNames(p0->record.make_and_model, + p1->record.make_and_model)) != 0) + return (diff); + else + return (strcasecmp(p0->record.natural_language, + p1->record.natural_language)); +} + + +/* + * 'list_ppds()' - List PPD files. + */ + +int /* O - Exit code */ +list_ppds(int request_id, /* I - Request ID */ + int limit, /* I - Limit */ + const char *opt) /* I - Option argument */ +{ + int i; /* Looping var */ + int count; /* Number of PPDs to send */ + ppd_info_t *ppd; /* Current PPD file */ + cups_file_t *fp; /* ppds.dat file */ + struct stat fileinfo; /* ppds.dat information */ + char filename[1024], /* ppds.dat filename */ + model[1024]; /* Model directory */ + const char *cups_cachedir; /* CUPS_CACHEDIR environment variable */ + const char *cups_datadir; /* CUPS_DATADIR environment variable */ + int num_options; /* Number of options */ + cups_option_t *options; /* Options */ + const char *requested, /* requested-attributes option */ + *make; /* ppd-make option */ + int send_natural_language, /* Send ppd-natural-language attribute? */ + send_make, /* Send ppd-make attribute? */ + send_make_and_model, /* Send ppd-make-and-model attribute? */ + send_name; /* Send ppd-name attribute? */ + + + fprintf(stderr, "DEBUG2: [cups-driverd] list_ppds(request_id=%d, limit=%d, opt=\"%s\"\n", + request_id, limit, opt); + + /* + * See if we a PPD database file... + */ + + NumPPDs = 0; + AllocPPDs = 0; + PPDs = (ppd_info_t *)NULL; + ChangedPPD = 0; + + if ((cups_cachedir = getenv("CUPS_CACHEDIR")) == NULL) + cups_cachedir = CUPS_CACHEDIR; + + snprintf(filename, sizeof(filename), "%s/ppds.dat", cups_cachedir); + if (!stat(filename, &fileinfo) && + (fileinfo.st_size % sizeof(ppd_rec_t)) == 0 && + (NumPPDs = fileinfo.st_size / sizeof(ppd_rec_t)) > 0) + { + /* + * We have a ppds.dat file, so read it! + */ + + AllocPPDs = NumPPDs; + + if ((PPDs = malloc(sizeof(ppd_info_t) * NumPPDs)) == NULL) + { + fprintf(stderr, "ERROR: [cups-driverd] Unable to allocate memory for %d PPD files!\n", + NumPPDs); + NumPPDs = 0; + AllocPPDs = 0; + } + else if ((fp = cupsFileOpen(filename, "r")) != NULL) + { + for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++) + { + cupsFileRead(fp, (char *)&(ppd->record), sizeof(ppd_rec_t)); + ppd->found = 0; + } + + cupsFileClose(fp); + + fprintf(stderr, "INFO: [cups-driverd] Read \"%s\", %d PPDs...\n", + filename, NumPPDs); + } + else + { + fprintf(stderr, "ERROR: [cups-driverd] Unable to read \"%s\" - %s\n", filename, + strerror(errno)); + NumPPDs = 0; + } + } + + /* + * Load all PPDs in the specified directory and below... + */ + + SortedPPDs = NumPPDs; + + if ((cups_datadir = getenv("CUPS_DATADIR")) == NULL) + cups_datadir = CUPS_DATADIR; + + snprintf(model, sizeof(model), "%s/model", cups_datadir); + load_ppds(model, ""); + + /* + * Cull PPD files that are no longer present... + */ + + for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++) + if (!ppd->found) + { + /* + * Remove this PPD file from the list... + */ + + if (i > 1) + memmove(ppd, ppd + 1, (i - 1) * sizeof(ppd_info_t)); + + NumPPDs --; + ppd --; + } + + /* + * Sort the PPDs by name... + */ + + if (NumPPDs > 1) + qsort(PPDs, NumPPDs, sizeof(ppd_info_t), + (int (*)(const void *, const void *))compare_names); + + /* + * Write the new ppds.dat file... + */ + + if (ChangedPPD) + { + if ((fp = cupsFileOpen(filename, "w")) != NULL) + { + for (i = NumPPDs, ppd = PPDs; i > 0; i --, ppd ++) + cupsFileWrite(fp, (char *)&(ppd->record), sizeof(ppd_rec_t)); + + cupsFileClose(fp); + + fprintf(stderr, "INFO: [cups-driverd] Wrote \"%s\", %d PPDs...\n", + filename, NumPPDs); + } + else + fprintf(stderr, "ERROR: [cups-driverd] Unable to write \"%s\" - %s\n", + filename, strerror(errno)); + } + else + fputs("INFO: [cups-driverd] No new or changed PPDs...\n", stderr); + + /* + * Scan for dynamic PPD files... + */ + + load_drivers(); + + /* + * Add the raw driver... + */ + + add_ppd("raw", "en", "Raw", "Raw Queue", 0, 0); + + /* + * Sort the PPDs by make and model... + */ + + if (NumPPDs > 1) + qsort(PPDs, NumPPDs, sizeof(ppd_info_t), + (int (*)(const void *, const void *))compare_ppds); + + /* + * Send IPP attributes... + */ + + num_options = cupsParseOptions(opt, 0, &options); + requested = cupsGetOption("requested-attributes", num_options, options); + make = cupsGetOption("ppd-make", num_options, options); + + fprintf(stderr, "DEBUG: [cups-driverd] requested=\"%s\"\n", + requested ? requested : "(nil)"); + + if (!requested || strstr(requested, "all")) + { + send_name = 1; + send_make = 1; + send_make_and_model = 1; + send_natural_language = 1; + } + else + { + send_name = strstr(requested, "ppd-name") != NULL; + send_make = strstr(requested, "ppd-make,") != NULL || + strstr(requested, ",ppd-make") != NULL || + !strcmp(requested, "ppd-make"); + send_make_and_model = strstr(requested, "ppd-make-and-model") != NULL; + send_natural_language = strstr(requested, "ppd-natural-language") != NULL; + } + + puts("Content-Type: application/ipp\n"); + + cupsdSendIPPHeader(IPP_OK, request_id); + cupsdSendIPPGroup(IPP_TAG_OPERATION); + cupsdSendIPPString(IPP_TAG_CHARSET, "attributes-charset", "utf-8"); + cupsdSendIPPString(IPP_TAG_LANGUAGE, "attributes-natural-language", "en-US"); + + if (limit <= 0 || limit > NumPPDs) + count = NumPPDs; + else + count = limit; + + for (i = NumPPDs, ppd = PPDs; count > 0 && i > 0; i --, ppd ++) + if (!make || !strcasecmp(ppd->record.make, make)) + { + /* + * Send this PPD... + */ + + fprintf(stderr, "DEBUG: [cups-driverd] Sending %s (%s)...\n", + ppd->record.name, ppd->record.make_and_model); + + count --; + + cupsdSendIPPGroup(IPP_TAG_PRINTER); + + if (send_name) + cupsdSendIPPString(IPP_TAG_NAME, "ppd-name", ppd->record.name); + + if (send_natural_language) + cupsdSendIPPString(IPP_TAG_LANGUAGE, "ppd-natural-language", + ppd->record.natural_language); + + if (send_make) + cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make", ppd->record.make); + + if (send_make_and_model) + cupsdSendIPPString(IPP_TAG_TEXT, "ppd-make-and-model", + ppd->record.make_and_model); + + /* + * If we have only requested the ppd-make attribute, then skip + * the remaining PPDs with this make... + */ + + if (requested && !strcmp(requested, "ppd-make")) + { + const char *this_make; /* This ppd-make */ + + + for (this_make = ppd->record.make, i --, ppd ++; i > 0; i --, ppd ++) + if (strcasecmp(this_make, ppd->record.make)) + break; + + i ++; + ppd --; + } + } + + cupsdSendIPPTrailer(); + + return (0); +} + + +/* + * 'load_ppds()' - Load PPD files recursively. + */ + +int /* O - 1 on success, 0 on failure */ +load_ppds(const char *d, /* I - Actual directory */ + const char *p) /* I - Virtual path in name */ +{ + int i; /* Looping var */ + cups_file_t *fp; /* Pointer to file */ + cups_dir_t *dir; /* Directory pointer */ + cups_dentry_t *dent; /* Directory entry */ + 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" }, + { "danish", "da" }, + { "dutch", "nl" }, + { "english", "en" }, + { "finnish", "fi" }, + { "french", "fr" }, + { "german", "de" }, + { "greek", "el" }, + { "italian", "it" }, + { "japanese", "jp" }, + { "norwegian", "no" }, + { "polish", "pl" }, + { "portuguese", "pt" }, + { "russian", "ru" }, + { "slovak", "sk" }, + { "spanish", "es" }, + { "swedish", "sv" }, + { "turkish", "tr" } + }; + + + if ((dir = cupsDirOpen(d)) == NULL) + { + fprintf(stderr, "ERROR: [cups-driverd] Unable to open PPD directory \"%s\": %s\n", + d, strerror(errno)); + return (0); + } + + while ((dent = cupsDirRead(dir)) != NULL) + { + /* + * See if this is a file... + */ + + snprintf(filename, sizeof(filename), "%s/%s", d, dent->filename); + + if (p[0]) + snprintf(name, sizeof(name), "%s/%s", p, dent->filename); + else + strlcpy(name, dent->filename, sizeof(name)); + + if (S_ISDIR(dent->fileinfo.st_mode)) + { + /* + * Do subdirectory... + */ + + if (!load_ppds(filename, name)) + { + cupsDirClose(dir); + return (1); + } + + continue; + } + + /* + * See if this file has been scanned before... + */ + + if (SortedPPDs > 0) + { + strcpy(key.record.name, name); + + ppd = bsearch(&key, PPDs, SortedPPDs, sizeof(ppd_info_t), + (int (*)(const void *, const void *))compare_names); + + if (ppd && + ppd->record.size == dent->fileinfo.st_size && + ppd->record.mtime == dent->fileinfo.st_mtime) + { + ppd->found = 1; + continue; + } + } + else + ppd = NULL; + + /* + * No, file is new/changed, so re-scan it... + */ + + if ((fp = cupsFileOpen(filename, "r")) == NULL) + continue; + + /* + * Now see if this is a PPD file... + */ + + line[0] = '\0'; + cupsFileGets(fp, line, sizeof(line)); + + if (strncmp(line, "*PPD-Adobe:", 11)) + { + /* + * Nope, close the file and continue... + */ + + cupsFileClose(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 (cupsFileGets(fp, line, sizeof(line)) != NULL) + { + if (!strncmp(line, "*Manufacturer:", 14)) + sscanf(line, "%*[^\"]\"%255[^\"]", manufacturer); + else if (!strncmp(line, "*ModelName:", 11)) + sscanf(line, "%*[^\"]\"%127[^\"]", model_name); + else if (!strncmp(line, "*LanguageVersion:", 17)) + sscanf(line, "%*[^:]:%63s", language); + else if (!strncmp(line, "*NickName:", 10)) + sscanf(line, "%*[^\"]\"%255[^\"]", nick_name); + else if (!strncmp(line, "*OpenUI", 7)) + { + /* + * 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... + */ + + cupsFileClose(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] & 255)) + _cups_strcpy(make_model, make_model + 1); + + if (!make_model[0]) + continue; /* Nope... */ + + /* + * See if we got a manufacturer... + */ + + while (isspace(manufacturer[0] & 255)) + _cups_strcpy(manufacturer, manufacturer + 1); + + if (!manufacturer[0] || !strcmp(manufacturer, "ESP")) + { + /* + * Nope, copy the first part of the make and model then... + */ + + strlcpy(manufacturer, make_model, sizeof(manufacturer)); + + /* + * 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)) + strcpy(manufacturer, "AGFA"); + else if (!strncasecmp(manufacturer, "herk", 4) || + !strncasecmp(manufacturer, "linotype", 8)) + strcpy(manufacturer, "LHAG"); + else + strcpy(manufacturer, "Other"); + + /* + * Hack for various vendors... + */ + + if (!strcasecmp(manufacturer, "XPrint")) + strcpy(manufacturer, "Xerox"); + else if (!strcasecmp(manufacturer, "Eastman")) + strcpy(manufacturer, "Kodak"); + else if (!strcasecmp(manufacturer, "laserwriter")) + strcpy(manufacturer, "Apple"); + else if (!strcasecmp(manufacturer, "colorpoint")) + strcpy(manufacturer, "Seiko"); + else if (!strcasecmp(manufacturer, "fiery")) + strcpy(manufacturer, "EFI"); + else if (!strcasecmp(manufacturer, "ps") || + !strcasecmp(manufacturer, "colorpass")) + strcpy(manufacturer, "Canon"); + else if (!strncasecmp(manufacturer, "primera", 7)) + strcpy(manufacturer, "Fargo"); + else if (!strcasecmp(manufacturer, "designjet")) + strcpy(manufacturer, "HP"); + } + else if (!strncasecmp(manufacturer, "LHAG", 4) || + !strncasecmp(manufacturer, "linotype", 8)) + 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] = '_'; + _cups_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)) + 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) + { + /* + * Add new PPD file... + */ + + fprintf(stderr, "DEBUG: [cups-driverd] Adding ppd \"%s\"...\n", name); + + if (!add_ppd(name, language, manufacturer, make_model, + dent->fileinfo.st_mtime, dent->fileinfo.st_size)) + { + cupsDirClose(dir); + return (0); + } + } + else + { + /* + * Update existing record... + */ + + fprintf(stderr, "DEBUG: [cups-driverd] Updating ppd \"%s\"...\n", name); + + memset(ppd, 0, sizeof(ppd_info_t)); + + ppd->found = 1; + ppd->record.mtime = dent->fileinfo.st_mtime; + ppd->record.size = dent->fileinfo.st_size; + + strlcpy(ppd->record.name, name, sizeof(ppd->record.name)); + strlcpy(ppd->record.make, manufacturer, sizeof(ppd->record.make)); + strlcpy(ppd->record.make_and_model, make_model, + sizeof(ppd->record.make_and_model)); + strlcpy(ppd->record.natural_language, language, + sizeof(ppd->record.natural_language)); + } + + ChangedPPD = 1; + } + + cupsDirClose(dir); + + return (1); +} + + +/* + * 'load_drivers()' - Load driver-generated PPD files. + */ + +int /* O - 1 on success, 0 on failure */ +load_drivers(void) +{ + const char *server_bin; /* CUPS_SERVERBIN environment variable */ + char drivers[1024]; /* Location of driver programs */ + FILE *fp; /* Pipe to driver program */ + cups_dir_t *dir; /* Directory pointer */ + cups_dentry_t *dent; /* Directory entry */ + char filename[1024], /* Name of driver */ + line[2048], /* Line from driver */ + name[512], /* ppd-name */ + natural_language[128], /* ppd-natural-language */ + make[128], /* ppd-make */ + make_and_model[256]; /* ppd-make-and-model */ + + + /* + * Try opening the driver directory... + */ + + if ((server_bin = getenv("CUPS_SERVERBIN")) == NULL) + server_bin = CUPS_SERVERBIN; + + snprintf(drivers, sizeof(drivers), "%s/driver", server_bin); + + if ((dir = cupsDirOpen(drivers)) == NULL) + { + fprintf(stderr, "ERROR: [cups-driverd] Unable to open driver directory " + "\"%s\": %s\n", + drivers, strerror(errno)); + return (0); + } + + /* + * Loop through all of the device drivers... + */ + + while ((dent = cupsDirRead(dir)) != NULL) + { + /* + * Only look at executable files... + */ + + if (!(dent->fileinfo.st_mode & 0111) || !S_ISREG(dent->fileinfo.st_mode)) + continue; + + /* + * Run the driver with no arguments and collect the output... + */ + + snprintf(filename, sizeof(filename), "%s/%s", drivers, dent->filename); + if ((fp = popen(filename, "r")) != NULL) + { + while (fgets(line, sizeof(line), fp) != NULL) + { + /* + * Each line is of the form: + * + * \"ppd-name\" ppd-natural-language "ppd-make" "ppd-make-and-model" + */ + + if (sscanf(line, "\"%511[^\"]\"%127s%*[ \t]\"%127[^\"]\"%*[ \t]\"%256[^\"]\"", + name, natural_language, make, make_and_model) != 4) + { + /* + * Bad format; strip trailing newline and write an error message. + */ + + if (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = '\0'; + + fprintf(stderr, "ERROR: [cups-driverd] Bad line from \"%s\": %s\n", + dent->filename, line); + break; + } + else + { + /* + * Add the device to the array of available devices... + */ + + if (!add_ppd(name, natural_language, make, make_and_model, 0, 0)) + { + cupsDirClose(dir); + return (0); + } + + fprintf(stderr, "DEBUG: [cups-driverd] Added dynamic PPD \"%s\"...\n", + name); + } + } + + pclose(fp); + } + else + fprintf(stderr, "WARNING: [cups-driverd] Unable to execute \"%s\": %s\n", + filename, strerror(errno)); + } + + cupsDirClose(dir); + + return (1); +} + + +/* + * End of "$Id: cups-driverd.c 4812 2005-10-25 18:23:10Z mike $". + */ diff --git a/scheduler/cups-lpd.c b/scheduler/cups-lpd.c new file mode 100644 index 000000000..25c9e8b8d --- /dev/null +++ b/scheduler/cups-lpd.c @@ -0,0 +1,1441 @@ +/* + * "$Id: cups-lpd.c 4807 2005-10-21 19:17:52Z mike $" + * + * Line Printer Daemon interface for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * 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_state() - Send the queue state. + * smart_gets() - Get a line of text, removing the trailing CR + * and/or LF. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + * 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 */ + socklen_t hostlen; /* Size of client address */ + http_addr_t hostaddr; /* Address of client */ + char hostname[256], /* Name of client */ + hostip[256], /* IP address */ + *hostfamily; /* Address family */ + + + /* + * 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)); + strcpy(hostname, "unknown"); + } + else + { + httpAddrLookup(&hostaddr, hostname, sizeof(hostname)); + httpAddrString(&hostaddr, hostip, sizeof(hostip)); + +#ifdef AF_INET6 + if (hostaddr.addr.sa_family == AF_INET6) + hostfamily = "IPv6"; + else +#endif /* AF_INET6 */ + hostfamily = "IPv4"; + + syslog(LOG_INFO, "Connection from %s (%s %s)", hostname, hostfamily, hostip); + } + + /* + * Scan the command-line for options... + */ + + num_defaults = 0; + defaults = NULL; + + num_defaults = cupsAddOption("job-originating-host-name", hostname, + num_defaults, &defaults); + + 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 & 255); list ++); + + while (isspace(*list & 255)) + *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); + /* no status byte for this command */ + + 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); + /* no status byte for this command */ + + 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 & 255); list ++); + while (isspace(*list & 255)) + *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); +} + + +/* + * 'check_printer()' - Check that a printer exists and is accepting jobs. + */ + +int /* O - Job ID */ +check_printer(const char *name) /* I - Printer or class name */ +{ + 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 accepting; /* printer-is-accepting-jobs value */ + + + /* + * Setup a connection and request data... + */ + + if ((http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption())) == NULL) + { + syslog(LOG_ERR, "Unable to connect to server %s: %s", cupsServer(), + strerror(errno)); + return (0); + } + + /* + * 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)); + httpClose(http); + return (0); + } + + request->request.op.operation_id = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", name); + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requested-attributes", + NULL, "printer-is-accepting-jobs"); + + /* + * Do the request... + */ + + response = cupsDoRequest(http, request, "/"); + + if (response == NULL) + { + syslog(LOG_ERR, "Unable to check printer status - %s", + ippErrorString(cupsLastError())); + accepting = 0; + } + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + syslog(LOG_ERR, "Unable to check printer status - %s", + ippErrorString(response->request.status.status_code)); + accepting = 0; + } + else if ((attr = ippFindAttribute(response, "printer-is-accepting-jobs", + IPP_TAG_BOOLEAN)) == NULL) + { + syslog(LOG_ERR, "No printer-is-accepting-jobs attribute found in response from server!"); + accepting = 0; + } + else + accepting = attr->values[0].boolean; + + if (response != NULL) + ippDelete(response); + + httpClose(http); + cupsLangFree(language); + + return (accepting); +} + + +/* + * '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: %s", cupsServer(), + strerror(errno)); + return (0); + } + + /* + * 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)); + httpClose(http); + return (0); + } + + request->request.op.operation_id = IPP_PRINT_JOB; + request->request.op.request_id = 1; + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", name); + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, + language != NULL ? language->language : "C"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, uri); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", + NULL, 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) + { + syslog(LOG_ERR, "Unable to print file - %s", + ippErrorString(cupsLastError())); + jobid = 0; + } + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + syslog(LOG_ERR, "Unable to print file - %s", + ippErrorString(response->request.status.status_code)); + jobid = 0; + } + else if ((attr = ippFindAttribute(response, "job-id", IPP_TAG_INTEGER)) == NULL) + { + syslog(LOG_ERR, "No job-id attribute found in response from server!"); + jobid = 0; + } + else + { + jobid = attr->values[0].integer; + + syslog(LOG_INFO, "Print file - job ID = %d", jobid); + } + + 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 */ + const char *cupsd_job_sheets; /* Job sheets */ + 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'; + + strlcpy(queue, dest, sizeof(queue)); + + if ((instance = strrchr(queue, '/')) != NULL) + *instance++ = '\0'; + + num_dests = cupsGetDests(&dests); + if ((destptr = cupsGetDest(queue, instance, num_dests, dests)) == NULL) + { + /* + * If the queue name is blank or "lp" then use the default queue. + */ + + if (!queue[0] || !strcmp(queue, "lp")) + if ((destptr = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) + strlcpy(queue, destptr->name, sizeof(queue)); + + if (destptr == 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); + } + } + + if (!check_printer(queue)) + { + cupsFreeDests(num_dests, dests); + + putchar(1); + + return (1); + } + + 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 & 255); name ++); + while (isspace(*name & 255)) + *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\" - %s", + control, 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\" - %s", + control, 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; + } + + strlcpy(data[num_data], name, sizeof(data[0])); + + if ((fd = cupsTempFd(temp[num_data], sizeof(temp[0]))) < 0) + { + syslog(LOG_ERR, "Unable to open temporary data file \"%s\" - %s", + temp[num_data], 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 */ + strlcpy(title, line + 1, sizeof(title)); + break; + + case 'N' : /* Document name */ + strlcpy(docname, line + 1, sizeof(docname)); + break; + + case 'P' : /* User identification */ + strlcpy(user, line + 1, sizeof(user)); + 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 < destptr->num_options; i ++) + num_options = cupsAddOption(destptr->options[i].name, + destptr->options[i].value, + num_options, &options); + for (i = 0; i < num_defaults; i ++) + num_options = cupsAddOption(defaults[i].name, + defaults[i].value, + num_options, &options); + + /* + * If a banner was requested and it's not overridden by a + * command line option and the destination's default is none + * then add the standard banner... + */ + + if (banner && + cupsGetOption("job-sheets", num_defaults, defaults) == NULL && + ((cupsd_job_sheets = cupsGetOption("job-sheets", + destptr->num_options, + destptr->options)) == NULL || + !strcmp(cupsd_job_sheets, "none,none"))) + { + num_options = cupsAddOption("job-sheets", "standard", + num_options, &options); + } + + /* + * Add additional options as needed... + */ + + 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: %s", cupsServer(), + strerror(errno)); + return (1); + } + + language = cupsLangDefault(); + + /* + * Loop for each job... + */ + + while ((id = atoi(list)) > 0) + { + /* + * Skip job ID in list... + */ + + while (isdigit(*list & 255)) + list ++; + while (isspace(*list & 255)) + 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 * const ranks[10] = /* Ranking strings */ + { + "th", + "st", + "nd", + "rd", + "th", + "th", + "th", + "th", + "th", + "th" + }; + static const char * const 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... + */ + + strlcpy(queue, dest, sizeof(queue)); + + 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: %s", cupsServer(), + strerror(errno)); + printf("Unable to connect to server %s: %s", cupsServer(), strerror(errno)); + 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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)); + printf("Unable to get printer list: %s\n", + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (1); + } + + 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())); + printf("Unable to get printer list: %s\n", + ippErrorString(cupsLastError())); + 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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; + + 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 + strlcpy(namestr, jobname, sizeof(namestr)); + + printf("%s: %-33.33s [job %d localhost]\n", jobuser, rankstr, jobid); + printf(" %-39.39s %.0f bytes\n", namestr, 1024.0 * jobsize); + } + else + printf("%-7s %-7.7s %-7d %-31.31s %.0f bytes\n", rankstr, jobuser, + jobid, jobname, 1024.0 * 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: cups-lpd.c 4807 2005-10-21 19:17:52Z mike $". + */ diff --git a/scheduler/cups-polld.c b/scheduler/cups-polld.c new file mode 100644 index 000000000..42f4adae0 --- /dev/null +++ b/scheduler/cups-polld.c @@ -0,0 +1,405 @@ +/* + * "$Id: cups-polld.c 4638 2005-09-15 14:13:19Z mike $" + * + * Polling daemon for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Open sockets and poll until we are killed... + * poll_server() - Poll the server for the given set of printers or classes. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +int poll_server(http_t *http, cups_lang_t *language, ipp_op_t op, + int sock, int port, int interval, const char *prefix); + + +/* + * 'main()' - Open sockets 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 */ + int seconds, /* Seconds left from poll */ + remain; /* Total remaining time to sleep */ + char prefix[1024]; /* Prefix for log messages */ + + + /* + * Don't buffer log messages... + */ + + 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]); + + if (interval < 2) + interval = 2; + + snprintf(prefix, sizeof(prefix), "[cups-polld %s:%d]", argv[1], atoi(argv[2])); + + /* + * Open a broadcast socket... + */ + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + fprintf(stderr, "ERROR: %s Unable to open broadcast socket: %s\n", prefix, + strerror(errno)); + return (1); + } + + /* + * Set the "broadcast" flag... + */ + + val = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val))) + { + fprintf(stderr, "ERROR: %s Unable to put socket in broadcast mode: %s\n", + prefix, strerror(errno)); + + close(sock); + return (1); + } + + /* + * Open a connection to the server... + */ + + while ((http = httpConnectEncrypt(argv[1], atoi(argv[2]), + cupsEncryption())) == NULL) + { + fprintf(stderr, "ERROR: %s Unable to connect to %s on port %s: %s\n", + prefix, argv[1], argv[2], + h_errno ? hstrerror(h_errno) : strerror(errno)); + sleep (interval); + } + + /* + * Loop forever, asking for available printers and classes... + */ + + language = cupsLangDefault(); + + for (;;) + { + /* + * Get the printers, then the classes... + */ + + remain = interval; + + if ((seconds = poll_server(http, language, CUPS_GET_PRINTERS, sock, port, + interval, prefix)) > 0) + remain -= seconds; + + /* + * Sleep for any remaining time... + */ + + if (remain > 0) + sleep(remain); + } +} + + +/* + * 'poll_server()' - Poll the server for the given set of printers or classes. + */ + +int /* O - Number of seconds or -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 */ + int interval, /* I - Polling interval */ + const char *prefix) /* I - Prefix for log messages */ +{ + int seconds; /* Number of seconds */ + int count, /* Current number of printers/classes */ + max_count; /* Maximum printers/classes per second */ + 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 */ + int accepting; /* printer-is-accepting-jobs */ + struct sockaddr_in addr; /* Broadcast address */ + char packet[1540]; /* Data packet */ + static const char * const attrs[] = /* Requested attributes */ + { + "printer-info", + "printer-is-accepting-jobs", + "printer-location", + "printer-make-and-model", + "printer-name", + "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; + + 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); + + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, + "printer-type", 0); + ippAddInteger(request, IPP_TAG_OPERATION, IPP_TAG_ENUM, + "printer-type-mask", + CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT | + CUPS_PRINTER_NOT_SHARED); + + /* + * 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, "ERROR: %s get-%s failed: %s\n", prefix, + op == CUPS_GET_PRINTERS ? "printers" : "classes", + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (-1); + } + + /* + * Figure out how many printers/classes we have... + */ + + for (attr = ippFindAttribute(response, "printer-name", IPP_TAG_NAME), + max_count = 0; + attr != NULL; + attr = ippFindNextAttribute(response, "printer-name", IPP_TAG_NAME), + max_count ++); + + fprintf(stderr, "DEBUG: %s found %d %s.\n", prefix, max_count, + op == CUPS_GET_PRINTERS ? "printers" : "classes"); + + count = 0; + seconds = time(NULL); + max_count = max_count / interval + 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; + accepting = 1; + 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-is-accepting-jobs") == 0 && + attr->value_tag == IPP_TAG_BOOLEAN) + accepting = attr->values[0].boolean; + + 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; + } + + /* + * Send the printer information... + */ + + type |= CUPS_PRINTER_REMOTE; + + if (!accepting) + type |= CUPS_PRINTER_REJECTING; + + snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"\n", + type, state, uri, location, info, make_model); + + fprintf(stderr, "DEBUG2: %s Sending %s", prefix, packet); + + if (sendto(sock, packet, strlen(packet), 0, + (struct sockaddr *)&addr, sizeof(addr)) <= 0) + { + ippDelete(response); + perror("cups-polld"); + return (-1); + } + + /* + * Throttle the local broadcasts as needed so that we don't + * overwhelm the local server... + */ + + count ++; + if (count >= max_count) + { + /* + * Sleep for a second... + */ + + count = 0; + sleep(1); + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + fprintf(stderr, "ERROR: %s get-%s failed: %s\n", prefix, + op == CUPS_GET_PRINTERS ? "printers" : "classes", + ippErrorString(cupsLastError())); + return (-1); + } + + /* + * Return the number of seconds we used... + */ + + return (time(NULL) - seconds); +} + + +/* + * End of "$Id: cups-polld.c 4638 2005-09-15 14:13:19Z mike $". + */ 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.h b/scheduler/cupsd.h new file mode 100644 index 000000000..1152838cd --- /dev/null +++ b/scheduler/cupsd.h @@ -0,0 +1,201 @@ +/* + * "$Id: cupsd.h 4903 2006-01-10 20:02:46Z mike $" + * + * Main header file for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2006 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + + +/* + * Include necessary headers. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +# include +#else +# include +#endif /* WIN32 */ + +#include +#include +#include "mime.h" +#include +#include +#include +#include + +#if defined(HAVE_CDSASSL) +# include +#endif /* HAVE_CDSASSL */ + + +/* + * Some OS's don't have hstrerror(), most notably Solaris... + */ + +#ifndef HAVE_HSTRERROR +# define hstrerror cups_hstrerror + +extern const char *cups_hstrerror(int); +#endif /* !HAVE_HSTRERROR */ + + +/* + * Common constants. + */ + +#ifndef FALSE +# define FALSE 0 +# define TRUE (!FALSE) +#endif /* !FALSE */ + + +/* + * Implementation limits... + */ + +#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_CHARSET "utf-8" /* Default charset */ + + +/* + * Global variable macros... + */ + +#ifdef _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 /* _MAIN_C */ + + +/* + * Other stuff for the scheduler... + */ + +#include "statbuf.h" +#include "cert.h" +#include "auth.h" +#include "client.h" +#include "policy.h" +#include "printers.h" +#include "classes.h" +#include "job.h" +#include "conf.h" +#include "banners.h" +#include "dirsvc.h" +#include "network.h" +#include "subscriptions.h" + + +/* + * Reload types... + */ + +#define RELOAD_NONE 0 /* No reload needed */ +#define RELOAD_ALL 1 /* Reload everything */ +#define RELOAD_CUPSD 2 /* Reload only cupsd.conf */ + + +/* + * Globals... + */ + +VAR int MaxFDs, /* Maximum number of files */ + SetSize; /* The size of the input/output sets */ +VAR fd_set *InputSet, /* Input files for select() */ + *OutputSet; /* Output files for select() */ + +VAR time_t ReloadTime VALUE(0); + /* Time of reload request... */ +VAR int NeedReload VALUE(RELOAD_ALL); + /* Need to load configuration? */ + + +/* + * Prototypes... + */ + +extern void cupsdCatchChildSignals(void); +extern void cupsdClearString(char **s); +extern void cupsdHoldSignals(void); +extern void cupsdIgnoreChildSignals(void); +extern void cupsdReleaseSignals(void); +extern void cupsdSetString(char **s, const char *v); +extern void cupsdSetStringf(char **s, const char *f, ...) +#ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 2, 3))) +#endif /* __GNUC__ */ +; +extern void cupsdStartServer(void); +extern void cupsdStopServer(void); +extern void cupsdClosePipe(int *fds); +extern int cupsdOpenPipe(int *fds); + +extern void cupsdClearEnv(void); +extern void cupsdInitEnv(void); +extern int cupsdLoadEnv(char *envp[], int envmax); +extern void cupsdSetEnv(const char *name, const char *value); +extern void cupsdSetEnvf(const char *name, const char *value, ...) +#ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 2, 3))) +#endif /* __GNUC__ */ +; + +extern int cupsdEndProcess(int pid, int force); +extern int cupsdStartProcess(const char *command, char *argv[], + char *envp[], int infd, int outfd, + int errfd, int backfd, int root, int *pid); + + +/* + * End of "$Id: cupsd.h 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/scheduler/dirsvc.c b/scheduler/dirsvc.c new file mode 100644 index 000000000..c218a94ae --- /dev/null +++ b/scheduler/dirsvc.c @@ -0,0 +1,2635 @@ +/* + * "$Id: dirsvc.c 4906 2006-01-10 20:53:28Z mike $" + * + * Directory services routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdLoadRemoteCache() - Load the remote printer cache. + * cupsdProcessBrowseData() - Process new browse data. + * cupsdProcessImplicitClasses() - Create/update implicit classes as needed. + * cupsdSaveRemoteCache() - Save the remote printer cache. + * cupsdSendBrowseDelete() - Send a "browse delete" message for a + * printer. + * cupsdSendBrowseList() - Send new browsing information as necessary. + * cupsdSendCUPSBrowse() - Send new browsing information using the + * CUPS protocol. + * cupsdSendSLPBrowse() - Register the specified printer with SLP. + * cupsdStartBrowsing() - Start sending and receiving broadcast + * information. + * cupsdStartPolling() - Start polling servers as needed. + * cupsdStopBrowsing() - Stop sending and receiving broadcast + * information. + * cupsdStopPolling() - Stop polling servers as needed. + * cupsdUpdateCUPSBrowse() - Update the browse lists using the CUPS + * protocol. + * cupsdUpdatePolling() - Read status messages from the poll daemons. + * cupsdUpdateSLPBrowse() - Get browsing information via SLP. + * slp_attr_callback() - SLP attribute callback + * slp_dereg_printer() - SLPDereg() the specified printer + * slp_get_attr() - Get an attribute from an SLP registration. + * slp_reg_callback() - Empty SLPRegReport. + * slp_url_callback() - SLP service url callback + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" +#include + + +/* + * SLP definitions... + */ + +#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_s /**** SLP URL list ****/ +{ + struct _slpsrvurl_s *next; /* Next URL in list */ + char url[HTTP_MAX_URI]; + /* URL */ +} slpsrvurl_t; + + +/* + * Local functions... + */ + +static SLPBoolean slp_attr_callback(SLPHandle hslp, const char *attrlist, + SLPError errcode, void *cookie); +static void slp_dereg_printer(cupsd_printer_t *p); +static int slp_get_attr(const char *attrlist, const char *tag, + char **valbuf); +static void slp_reg_callback(SLPHandle hslp, SLPError errcode, + void *cookie); +static SLPBoolean slp_url_callback(SLPHandle hslp, const char *srvurl, + unsigned short lifetime, + SLPError errcode, void *cookie); +#endif /* HAVE_LIBSLP */ + + +/* + * 'cupsdLoadRemoteCache()' - Load the remote printer cache. + */ + +void +cupsdLoadRemoteCache(void) +{ + cups_file_t *fp; /* remote.cache file */ + int linenum; /* Current line number */ + char line[1024], /* Line from file */ + *value, /* Pointer to value */ + *valueptr; /* Pointer into value */ + cupsd_printer_t *p; /* Current printer */ + time_t now; /* Current time */ + + + /* + * Open the remote.cache file... + */ + + snprintf(line, sizeof(line), "%s/remote.cache", CacheDir); + if ((fp = cupsFileOpen(line, "r")) == NULL) + return; + + /* + * Read printer configurations until we hit EOF... + */ + + linenum = 0; + p = NULL; + now = time(NULL); + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + /* + * Decode the directive... + */ + + if (!strcasecmp(line, " or + */ + + if (p == NULL && value) + { + /* + * Add the printer and a base file type... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdLoadRemoteCache: Loading printer %s...", value); + + p = cupsdAddPrinter(value); + p->accepting = 1; + p->state = IPP_PRINTER_IDLE; + p->type |= CUPS_PRINTER_REMOTE; + p->browse_time = now + BrowseTimeout; + + /* + * Set the default printer as needed... + */ + + if (!strcasecmp(line, " or + */ + + if (p == NULL && value) + { + /* + * Add the printer and a base file type... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdLoadRemoteCache: Loading class %s...", value); + + p = cupsdAddClass(value); + p->accepting = 1; + p->state = IPP_PRINTER_IDLE; + p->type |= CUPS_PRINTER_REMOTE; + p->browse_time = now + BrowseTimeout; + + /* + * Set the default printer as needed... + */ + + if (!strcasecmp(line, "") || + !strcasecmp(line, "")) + { + if (p != NULL) + { + /* + * Close out the current printer... + */ + + cupsdSetPrinterAttrs(p); + + p = NULL; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else if (!p) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + else if (!strcasecmp(line, "Info")) + { + if (value) + cupsdSetString(&p->info, value); + } + else if (!strcasecmp(line, "MakeModel")) + { + if (value) + cupsdSetString(&p->make_model, value); + } + else if (!strcasecmp(line, "Location")) + { + if (value) + cupsdSetString(&p->location, value); + } + else if (!strcasecmp(line, "DeviceURI")) + { + if (value) + cupsdSetString(&p->device_uri, value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else if (!strcasecmp(line, "State")) + { + /* + * Set the initial queue state... + */ + + if (value && !strcasecmp(value, "idle")) + p->state = IPP_PRINTER_IDLE; + else if (value && !strcasecmp(value, "stopped")) + p->state = IPP_PRINTER_STOPPED; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else if (!strcasecmp(line, "StateMessage")) + { + /* + * Set the initial queue state message... + */ + + if (value) + strlcpy(p->state_message, value, sizeof(p->state_message)); + } + else if (!strcasecmp(line, "Accepting")) + { + /* + * Set the initial accepting state... + */ + + if (value && + (!strcasecmp(value, "yes") || + !strcasecmp(value, "on") || + !strcasecmp(value, "true"))) + p->accepting = 1; + else if (value && + (!strcasecmp(value, "no") || + !strcasecmp(value, "off") || + !strcasecmp(value, "false"))) + p->accepting = 0; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else if (!strcasecmp(line, "Type")) + { + if (value) + p->type = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else if (!strcasecmp(line, "BrowseTime")) + { + if (value) + { + time_t t = atoi(value); + + if (t > (now + BrowseInterval)) + p->browse_time = t; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else if (!strcasecmp(line, "JobSheets")) + { + /* + * Set the initial job sheets... + */ + + if (value) + { + for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); + + if (*valueptr) + *valueptr++ = '\0'; + + cupsdSetString(&p->job_sheets[0], value); + + while (isspace(*valueptr & 255)) + valueptr ++; + + if (*valueptr) + { + for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++); + + if (*valueptr) + *valueptr++ = '\0'; + + cupsdSetString(&p->job_sheets[1], value); + } + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else if (!strcasecmp(line, "AllowUser")) + { + if (value) + { + p->deny_users = 0; + cupsdAddPrinterUser(p, value); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else if (!strcasecmp(line, "DenyUser")) + { + if (value) + { + p->deny_users = 1; + cupsdAddPrinterUser(p, value); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of remote.cache.", linenum); + return; + } + } + else + { + /* + * Something else we don't understand... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown configuration directive %s on line %d of remote.cache.", + line, linenum); + } + } + + cupsFileClose(fp); + + /* + * Do auto-classing if needed... + */ + + cupsdProcessImplicitClasses(); +} + + +/* + * 'cupsdProcessBrowseData()' - Process new browse data. + */ + +void +cupsdProcessBrowseData( + 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 num_attrs, /* I - Number of attributes */ + cups_option_t *attrs) /* I - Attributes */ +{ + int update; /* Update printer attributes? */ + char finaluri[HTTP_MAX_URI], /* Final URI for printer */ + 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 */ + cupsd_printer_t *p; /* Printer information */ + const char *ipp_options; /* ipp-options value */ + + + /* + * Pull the URI apart to see if this is a local or remote printer... + */ + + httpSeparateURI(uri, method, sizeof(method), username, sizeof(username), + host, sizeof(host), &port, resource, sizeof(resource)); + + /* + * Determine if the URI contains any illegal characters in it... + */ + + if (strncmp(uri, "ipp://", 6) || !host[0] || + (strncmp(resource, "/printers/", 10) && + strncmp(resource, "/classes/", 9))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdProcessBrowseData: Bad printer URI in browse data: %s", + uri); + return; + } + + if (strchr(resource, '?') || + (!strncmp(resource, "/printers/", 10) && strchr(resource + 10, '/')) || + (!strncmp(resource, "/classes/", 9) && strchr(resource + 9, '/'))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdProcessBrowseData: Bad resource in browse data: %s", + resource); + return; + } + + /* + * OK, this isn't a local printer; add any remote options... + */ + + ipp_options = cupsGetOption("ipp-options", num_attrs, attrs); + + if (BrowseRemoteOptions) + { + if (BrowseRemoteOptions[0] == '?') + { + /* + * Override server-supplied options... + */ + + snprintf(finaluri, sizeof(finaluri), "%s%s", uri, BrowseRemoteOptions); + } + else if (ipp_options) + { + /* + * Combine the server and local options... + */ + + snprintf(finaluri, sizeof(finaluri), "%s?%s+%s", uri, ipp_options, + BrowseRemoteOptions); + } + else + { + /* + * Just use the local options... + */ + + snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, BrowseRemoteOptions); + } + + uri = finaluri; + } + else if (ipp_options) + { + /* + * Just use the server-supplied options... + */ + + snprintf(finaluri, sizeof(finaluri), "%s?%s", uri, ipp_options); + uri = finaluri; + } + + /* + * See if we already have it listed in the Printers list, and add it if not... + */ + + type |= CUPS_PRINTER_REMOTE; + type &= ~CUPS_PRINTER_IMPLICIT; + 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)) + { + *hptr = '\0'; + break; + } + else + hptr = strchr(hptr + 1, '.'); + } + } + + if (type & CUPS_PRINTER_CLASS) + { + /* + * Remote destination is a class... + */ + + if (!strncmp(resource, "/classes/", 9)) + snprintf(name, sizeof(name), "%s@%s", resource + 9, host); + else + return; + + if ((p = cupsdFindClass(name)) == NULL && BrowseShortNames) + { + if ((p = cupsdFindClass(resource + 9)) != NULL) + { + if (p->hostname && strcasecmp(p->hostname, host)) + { + /* + * 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) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Renamed remote class \"%s\" to \"%s@%s\"...", + p->name, p->name, p->hostname); + cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, + "Class \'%s\' deleted by directory services.", + p->name); + + cupsArrayRemove(Printers, p); + cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname); + cupsdSetPrinterAttrs(p); + cupsArrayAdd(Printers, p); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, + "Class \'%s\' added by directory services.", + p->name); + } + + p = NULL; + } + else if (!p->hostname) + { + /* + * Hostname not set, so this must be a cached remote printer + * that was created for a pending print job... + */ + + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + update = 1; + } + } + else + { + /* + * Use the short name for this shared class. + */ + + strlcpy(name, resource + 9, sizeof(name)); + } + } + else if (p && !p->hostname) + { + /* + * Hostname not set, so this must be a cached remote printer + * that was created for a pending print job... + */ + + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + update = 1; + } + + if (!p) + { + /* + * Class doesn't exist; add it... + */ + + p = cupsdAddClass(name); + + cupsdLogMessage(CUPSD_LOG_INFO, "Added remote class \"%s\"...", name); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, + "Class \'%s\' added by directory services.", name); + + /* + * Force the URI to point to the real server... + */ + + p->type = type & ~CUPS_PRINTER_REJECTING; + p->accepting = 1; + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + cupsdSetString(&p->hostname, host); + + 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 = cupsdFindPrinter(name)) == NULL && BrowseShortNames) + { + if ((p = cupsdFindPrinter(resource + 10)) != NULL) + { + if (p->hostname && strcasecmp(p->hostname, host)) + { + /* + * 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) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Renamed remote printer \"%s\" to \"%s@%s\"...", + p->name, p->name, p->hostname); + cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, + "Printer \'%s\' deleted by directory services.", + p->name); + + cupsArrayRemove(Printers, p); + cupsdSetStringf(&p->name, "%s@%s", p->name, p->hostname); + cupsdSetPrinterAttrs(p); + cupsArrayAdd(Printers, p); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, + "Printer \'%s\' added by directory services.", + p->name); + } + + p = NULL; + } + else if (!p->hostname) + { + /* + * Hostname not set, so this must be a cached remote printer + * that was created for a pending print job... + */ + + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + update = 1; + } + } + else + { + /* + * Use the short name for this shared printer. + */ + + strlcpy(name, resource + 10, sizeof(name)); + } + } + else if (p && !p->hostname) + { + /* + * Hostname not set, so this must be a cached remote printer + * that was created for a pending print job... + */ + + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + update = 1; + } + + if (!p) + { + /* + * Printer doesn't exist; add it... + */ + + p = cupsdAddPrinter(name); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, p, NULL, + "Printer \'%s\' added by directory services.", name); + + cupsdLogMessage(CUPSD_LOG_INFO, "Added remote printer \"%s\"...", name); + + /* + * Force the URI to point to the real server... + */ + + p->type = type & ~CUPS_PRINTER_REJECTING; + p->accepting = 1; + cupsdSetString(&p->hostname, host); + cupsdSetString(&p->uri, uri); + cupsdSetString(&p->device_uri, uri); + + update = 1; + } + } + + /* + * Update the state... + */ + + p->state = state; + p->browse_time = time(NULL); + + if (type & CUPS_PRINTER_REJECTING) + { + type &= ~CUPS_PRINTER_REJECTING; + + if (p->accepting) + { + update = 1; + p->accepting = 0; + } + } + else if (!p->accepting) + { + update = 1; + p->accepting = 1; + } + + if (p->type != type) + { + p->type = type; + update = 1; + } + + if (location && (!p->location || strcmp(p->location, location))) + { + cupsdSetString(&p->location, location); + update = 1; + } + + if (info && (!p->info || strcmp(p->info, info))) + { + cupsdSetString(&p->info, info); + update = 1; + } + + if (!make_model || !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 (!p->make_model || strcmp(p->make_model, local_make_model)) + { + cupsdSetString(&p->make_model, local_make_model); + update = 1; + } + + if (type & CUPS_PRINTER_DELETE) + { + cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, + "%s \'%s\' deleted by directory services.", + (type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", p->name); + + cupsdExpireSubscriptions(p, NULL); + + cupsdDeletePrinter(p, 1); + cupsdUpdateImplicitClasses(); + } + else if (update) + { + cupsdSetPrinterAttrs(p); + cupsdUpdateImplicitClasses(); + } + + /* + * See if we have a default printer... If not, make the first printer the + * default. + */ + + if (DefaultPrinter == NULL && Printers != NULL) + DefaultPrinter = (cupsd_printer_t *)cupsArrayFirst(Printers); + + /* + * Do auto-classing if needed... + */ + + cupsdProcessImplicitClasses(); + + /* + * Update the printcap file... + */ + + cupsdWritePrintcap(); +} + + +/* + * 'cupsdProcessImplicitClasses()' - Create/update implicit classes as needed. + */ + +void +cupsdProcessImplicitClasses(void) +{ + int i; /* Looping var */ + int update; /* Update printer attributes? */ + char name[IPP_MAX_NAME], /* Name of printer */ + *hptr; /* Pointer into hostname */ + cupsd_printer_t *p, /* Printer information */ + *pclass, /* Printer class */ + *first; /* First printer in class */ + int offset, /* Offset of name */ + len; /* Length of name */ + + + if (!ImplicitClasses || !Printers) + return; + + /* + * Loop through all available printers and create classes as needed... + */ + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers), len = 0, offset = 0, + update = 0, pclass = NULL, first = NULL; + p != NULL; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + /* + * Skip implicit classes... + */ + + if (p->type & CUPS_PRINTER_IMPLICIT) + { + len = 0; + continue; + } + + /* + * If len == 0, get the length of this printer name up to the "@" + * sign (if any). + */ + + cupsArraySave(Printers); + + 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 && strcasecmp(pclass->name, name)) + { + if (update) + cupsdSetPrinterAttrs(pclass); + + update = 0; + pclass = NULL; + } + + if (!pclass && (pclass = cupsdFindDest(name)) == NULL) + { + /* + * Need to add the class... + */ + + pclass = cupsdAddPrinter(name); + cupsArrayAdd(ImplicitPrinters, pclass); + + pclass->type |= CUPS_PRINTER_IMPLICIT; + pclass->accepting = 1; + pclass->state = IPP_PRINTER_IDLE; + + cupsdSetString(&pclass->location, p->location); + cupsdSetString(&pclass->info, p->info); + + update = 1; + + cupsdLogMessage(CUPSD_LOG_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) + { + first->in_implicit_class = 1; + cupsdAddPrinterToClass(pclass, first); + } + + first = NULL; + } + + for (i = 0; i < pclass->num_printers; i ++) + if (pclass->printers[i] == p) + break; + + if (i >= pclass->num_printers) + { + p->in_implicit_class = 1; + cupsdAddPrinterToClass(pclass, p); + update = 1; + } + } + 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 ((first = (hptr ? cupsdFindDest(name) : p)) != NULL && + !(first->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 && len < (sizeof(name) - 4)) + { + /* + * 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; + cupsArrayRestore(Printers); + continue; + } + } + + first = p; + } + + cupsArrayRestore(Printers); + } + + /* + * Update the last printer class as needed... + */ + + if (pclass && update) + cupsdSetPrinterAttrs(pclass); +} + + +/* + * 'cupsdSaveRemoteCache()' - Save the remote printer cache. + */ + +void +cupsdSaveRemoteCache(void) +{ + int i; /* Looping var */ + cups_file_t *fp; /* printers.conf file */ + char temp[1024]; /* Temporary string */ + cupsd_printer_t *printer; /* Current printer class */ + time_t curtime; /* Current time */ + struct tm *curdate; /* Current date */ + + + /* + * Create the remote.cache file... + */ + + snprintf(temp, sizeof(temp), "%s/remote.cache", CacheDir); + + if ((fp = cupsFileOpen(temp, "w")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to save remote.cache - %s", strerror(errno)); + return; + } + else + cupsdLogMessage(CUPSD_LOG_INFO, "Saving remote.cache..."); + + /* + * Restrict access to the file... + */ + + fchown(cupsFileNumber(fp), getuid(), Group); + fchmod(cupsFileNumber(fp), ConfigFilePerm); + + /* + * Write a small header to the file... + */ + + curtime = time(NULL); + curdate = localtime(&curtime); + strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); + + cupsFilePuts(fp, "# Remote cache file for " CUPS_SVERSION "\n"); + cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); + + /* + * Write each local printer known to the system... + */ + + for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers); + printer; + printer = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + /* + * Skip local destinations... + */ + + if (!(printer->type & CUPS_PRINTER_REMOTE)) + continue; + + /* + * Write printers as needed... + */ + + if (printer == DefaultPrinter) + cupsFilePuts(fp, "type & CUPS_PRINTER_CLASS) + cupsFilePrintf(fp, "Class %s>\n", printer->name); + else + cupsFilePrintf(fp, "Printer %s>\n", printer->name); + + cupsFilePrintf(fp, "Type %d\n", printer->type); + + cupsFilePrintf(fp, "BrowseTime %d\n", (int)printer->browse_time); + + if (printer->info) + cupsFilePrintf(fp, "Info %s\n", printer->info); + + if (printer->make_model) + cupsFilePrintf(fp, "MakeModel %s\n", printer->make_model); + + if (printer->location) + cupsFilePrintf(fp, "Location %s\n", printer->location); + + if (printer->device_uri) + cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri); + + if (printer->state == IPP_PRINTER_STOPPED) + { + cupsFilePuts(fp, "State Stopped\n"); + cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message); + } + else + cupsFilePuts(fp, "State Idle\n"); + + if (printer->accepting) + cupsFilePuts(fp, "Accepting Yes\n"); + else + cupsFilePuts(fp, "Accepting No\n"); + + cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0], + printer->job_sheets[1]); + + for (i = 0; i < printer->num_users; i ++) + cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow", + printer->users[i]); + + if (printer->type & CUPS_PRINTER_CLASS) + cupsFilePuts(fp, "\n"); + else + cupsFilePuts(fp, "\n"); + } + + cupsFileClose(fp); +} + + +/* + * 'cupsdSendBrowseDelete()' - Send a "browse delete" message for a printer. + */ + +void +cupsdSendBrowseDelete( + cupsd_printer_t *p) /* I - Printer to delete */ +{ + /* + * Only announce if browsing is enabled... + */ + + if (!Browsing || !p->shared) + return; + + /* + * First mark the printer for deletion... + */ + + p->type |= CUPS_PRINTER_DELETE; + + /* + * Announce the deletion... + */ + + if (BrowseLocalProtocols & BROWSE_CUPS) + cupsdSendCUPSBrowse(p); +#ifdef HAVE_LIBSLP + if (BrowseLocalProtocols & BROWSE_SLP) + slp_dereg_printer(p); +#endif /* HAVE_LIBSLP */ +} + + +/* + * 'cupsdSendBrowseList()' - Send new browsing information as necessary. + */ + +void +cupsdSendBrowseList(void) +{ + int count; /* Number of dests to update */ + cupsd_printer_t *p; /* Current printer */ + time_t ut, /* Minimum update time */ + to; /* Timeout time */ + + + if (!Browsing || !BrowseLocalProtocols || !Printers) + return; + + /* + * Compute the update and timeout times... + */ + + ut = time(NULL) - BrowseInterval; + to = time(NULL) - BrowseTimeout; + + /* + * Figure out how many printers need an update... + */ + + if (BrowseInterval > 0) + { + int max_count; /* Maximum number to update */ + + + /* + * Throttle the number of printers we'll be updating this time + * around based on the number of queues that need updating and + * the maximum number of queues to update each second... + */ + + max_count = 2 * cupsArrayCount(Printers) / BrowseInterval + 1; + + for (count = 0, p = (cupsd_printer_t *)cupsArrayFirst(Printers); + count < max_count && p != NULL; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (!(p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) && + p->shared && p->browse_time < ut) + count ++; + + /* + * Loop through all of the printers and send local updates as needed... + */ + + if (BrowseNext) + p = (cupsd_printer_t *)cupsArrayFind(Printers, BrowseNext); + else + p = (cupsd_printer_t *)cupsArrayFirst(Printers); + + for (; + count > 0; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + /* + * Check for wraparound... + */ + + if (!p) + p = (cupsd_printer_t *)cupsArrayFirst(Printers); + + if (!p) + break; + else if ((p->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) || + !p->shared) + continue; + else if (p->browse_time < ut) + { + /* + * Need to send an update... + */ + + count --; + + p->browse_time = time(NULL); + + if (BrowseLocalProtocols & BROWSE_CUPS) + cupsdSendCUPSBrowse(p); + +#ifdef HAVE_LIBSLP + if (BrowseLocalProtocols & BROWSE_SLP) + cupsdSendSLPBrowse(p); +#endif /* HAVE_LIBSLP */ + } + } + + /* + * Save where we left off so that all printers get updated... + */ + + BrowseNext = p; + } + + /* + * Loop through all of the printers and send local updates as needed... + */ + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + /* + * If this is a remote queue, see if it needs to be timed out... + */ + + if (p->type & CUPS_PRINTER_REMOTE) + { + if (p->browse_time < to) + { + cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, p, NULL, + "%s \'%s\' deleted by directory services (timeout).", + (p->type & CUPS_PRINTER_CLASS) ? "Class" : "Printer", + p->name); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Remote destination \"%s\" has timed out; deleting it...", + p->name); + + cupsArraySave(Printers); + cupsdDeletePrinter(p, 1); + cupsArrayRestore(Printers); + } + } + } +} + + +/* + * 'cupsdSendCUPSBrowse()' - Send new browsing information using the CUPS protocol. + */ + +void +cupsdSendCUPSBrowse(cupsd_printer_t *p) /* I - Printer to send */ +{ + int i; /* Looping var */ + cups_ptype_t type; /* Printer type */ + cupsd_dirsvc_addr_t *b; /* Browse address */ + int bytes; /* Length of packet */ + char packet[1453]; /* Browse data packet */ + char uri[1024]; /* Printer URI */ + char options[1024]; /* Browse local options */ + cupsd_netif_t *iface; /* Network interface */ + + + /* + * Figure out the printer type value... + */ + + type = p->type | CUPS_PRINTER_REMOTE; + + if (!p->accepting) + type |= CUPS_PRINTER_REJECTING; + + /* + * Initialize the browse options... + */ + + if (BrowseLocalOptions) + snprintf(options, sizeof(options), " ipp-options=%s", BrowseLocalOptions); + else + options[0] = '\0'; + + /* + * Send a packet to each browse address... + */ + + for (i = NumBrowsers, b = Browsers; i > 0; i --, b ++) + if (b->iface[0]) + { + /* + * Send the browse packet to one or more interfaces... + */ + + if (strcmp(b->iface, "*") == 0) + { + /* + * Send to all local interfaces... + */ + + cupsdNetIFUpdate(); + + for (iface = NetIFList; iface != NULL; iface = iface->next) + { + /* + * Only send to local, IPv4 interfaces... + */ + + if (!iface->is_local || !iface->port || + iface->address.addr.sa_family != AF_INET) + continue; + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, iface->hostname, + iface->port, + (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" : + "/printers/%s", + p->name); + snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n", + type, p->state, uri, p->location ? p->location : "", + p->info ? p->info : "", + p->make_model ? p->make_model : "Unknown", options); + + bytes = strlen(packet); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes, + iface->name, packet); + + iface->broadcast.ipv4.sin_port = htons(BrowsePort); + + sendto(BrowseSocket, packet, bytes, 0, + (struct sockaddr *)&(iface->broadcast), + sizeof(struct sockaddr_in)); + } + } + else if ((iface = cupsdNetIFFind(b->iface)) != NULL) + { + /* + * Send to the named interface using the IPv4 address... + */ + + while (iface) + if (strcasecmp(b->iface, iface->name)) + { + iface = NULL; + break; + } + else if (iface->address.addr.sa_family == AF_INET && iface->port) + break; + else + iface = iface->next; + + if (iface) + { + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, iface->hostname, + iface->port, + (p->type & CUPS_PRINTER_CLASS) ? "/classes/%s%s" : + "/printers/%s", + p->name); + snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n", + type, p->state, uri, p->location ? p->location : "", + p->info ? p->info : "", + p->make_model ? p->make_model : "Unknown", options); + + bytes = strlen(packet); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSendBrowseList: (%d bytes to \"%s\") %s", bytes, + iface->name, packet); + + iface->broadcast.ipv4.sin_port = htons(BrowsePort); + + sendto(BrowseSocket, packet, bytes, 0, + (struct sockaddr *)&(iface->broadcast), + sizeof(struct sockaddr_in)); + } + } + } + else + { + /* + * Send the browse packet to the indicated address using + * the default server name... + */ + + snprintf(packet, sizeof(packet), "%x %x %s \"%s\" \"%s\" \"%s\"%s\n", + type, p->state, p->uri, + p->location ? p->location : "", + p->info ? p->info : "", + p->make_model ? p->make_model : "Unknown", options); + + bytes = strlen(packet); + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdSendBrowseList: (%d bytes) %s", bytes, packet); + + if (sendto(BrowseSocket, packet, bytes, 0, + (struct sockaddr *)&(b->to), + sizeof(struct sockaddr_in)) <= 0) + { + /* + * Unable to send browse packet, so remove this address from the + * list... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdSendBrowseList: sendto failed for browser %d - %s.", + b - Browsers + 1, strerror(errno)); + + if (i > 1) + memcpy(b, b + 1, (i - 1) * sizeof(cupsd_dirsvc_addr_t)); + + b --; + NumBrowsers --; + } + } +} + + +#ifdef HAVE_LIBSLP +/* + * 'cupsdSendSLPBrowse()' - Register the specified printer with SLP. + */ + +void +cupsdSendSLPBrowse(cupsd_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 */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSendSLPBrowse(%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); + + cupsdLogMessage(CUPSD_LOG_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]) + strlcat(finishings, ",bind", sizeof(finishings)); + else + strcpy(finishings, "bind"); + } + + if (p->type & CUPS_PRINTER_PUNCH) + { + if (finishings[0]) + strlcat(finishings, ",punch", sizeof(finishings)); + else + strcpy(finishings, "punch"); + } + + if (p->type & CUPS_PRINTER_COVER) + { + if (finishings[0]) + strlcat(finishings, ",cover", sizeof(finishings)); + else + strcpy(finishings, "cover"); + } + + if (p->type & CUPS_PRINTER_SORT) + { + if (finishings[0]) + strlcat(finishings, ",sort", sizeof(finishings)); + else + strcpy(finishings, "sort"); + } + + if (!finishings[0]) + strcpy(finishings, "none"); + + /* + * Quote any commas in the make and model, location, and info strings... + */ + + for (src = p->make_model, dst = make_model; + src && *src && dst < (make_model + sizeof(make_model) - 2);) + { + if (*src == ',' || *src == '\\' || *src == ')') + *dst++ = '\\'; + + *dst++ = *src++; + } + + *dst = '\0'; + + if (!make_model[0]) + strcpy(make_model, "Unknown"); + + for (src = p->location, dst = location; + src && *src && dst < (location + sizeof(location) - 2);) + { + if (*src == ',' || *src == '\\' || *src == ')') + *dst++ = '\\'; + + *dst++ = *src++; + } + + *dst = '\0'; + + if (!location[0]) + strcpy(location, "Unknown"); + + for (src = p->info, dst = info; + src && *src && dst < (info + sizeof(info) - 2);) + { + 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_SSL + "(uri-security-supported=tls>)," +#else + "(uri-security-supported=none>)," +#endif /* HAVE_SSL */ + "(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" : ""); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "Attributes = \"%s\"", attrs); + + /* + * Register the printer with the SLP server... + */ + + error = SLPReg(BrowseSLPHandle, srvurl, BrowseTimeout, + SLP_CUPS_SRVTYPE, attrs, SLP_TRUE, slp_reg_callback, 0); + + if (error != SLP_OK) + cupsdLogMessage(CUPSD_LOG_ERROR, "SLPReg of \"%s\" failed with status %d!", p->name, + error); +} +#endif /* HAVE_LIBSLP */ + + +/* + * 'cupsdStartBrowsing()' - Start sending and receiving broadcast information. + */ + +void +cupsdStartBrowsing(void) +{ + int val; /* Socket option value */ + struct sockaddr_in addr; /* Broadcast address */ + + + BrowseNext = NULL; + + if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols)) + return; + + if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_CUPS) + { + /* + * Create the broadcast socket... + */ + + if ((BrowseSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartBrowsing: Unable to create broadcast socket - %s.", + strerror(errno)); + BrowseLocalProtocols &= ~BROWSE_CUPS; + BrowseRemoteProtocols &= ~BROWSE_CUPS; + return; + } + + /* + * Set the "broadcast" flag... + */ + + val = 1; + if (setsockopt(BrowseSocket, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartBrowsing: Unable to set broadcast mode - %s.", + strerror(errno)); + +#ifdef WIN32 + closesocket(BrowseSocket); +#else + close(BrowseSocket); +#endif /* WIN32 */ + + BrowseSocket = -1; + BrowseLocalProtocols &= ~BROWSE_CUPS; + BrowseRemoteProtocols &= ~BROWSE_CUPS; + 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))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartBrowsing: Unable to bind broadcast socket - %s.", + strerror(errno)); + +#ifdef WIN32 + closesocket(BrowseSocket); +#else + close(BrowseSocket); +#endif /* WIN32 */ + + BrowseSocket = -1; + BrowseLocalProtocols &= ~BROWSE_CUPS; + BrowseRemoteProtocols &= ~BROWSE_CUPS; + return; + } + + /* + * Close the socket on exec... + */ + + fcntl(BrowseSocket, F_SETFD, fcntl(BrowseSocket, F_GETFD) | FD_CLOEXEC); + + /* + * Finally, add the socket to the input selection set... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartBrowsing: Adding fd %d to InputSet...", + BrowseSocket); + + FD_SET(BrowseSocket, InputSet); + } + else + BrowseSocket = -1; + +#ifdef HAVE_LIBSLP + if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) + { + /* + * Open SLP handle... + */ + + if (SLPOpen("en", SLP_FALSE, &BrowseSLPHandle) != SLP_OK) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to open an SLP handle; disabling SLP browsing!"); + BrowseLocalProtocols &= ~BROWSE_SLP; + BrowseRemoteProtocols &= ~BROWSE_SLP; + } + + BrowseSLPRefresh = 0; + } +#endif /* HAVE_LIBSLP */ +} + + +/* + * 'cupsdStartPolling()' - Start polling servers as needed. + */ + +void +cupsdStartPolling(void) +{ + int i; /* Looping var */ + cupsd_dirsvc_poll_t *pollp; /* Current polling server */ + char polld[1024]; /* Poll daemon path */ + char sport[10]; /* Server port */ + char bport[10]; /* Browser port */ + char interval[10]; /* Poll interval */ + int statusfds[2]; /* Status pipe */ + char *argv[6]; /* Arguments */ + char *envp[100]; /* Environment */ + + + /* + * Don't do anything if we aren't polling... + */ + + if (NumPolled == 0) + { + PollPipe = -1; + PollStatusBuffer = NULL; + return; + } + + /* + * Setup string arguments for polld, port and interval options. + */ + + snprintf(polld, sizeof(polld), "%s/daemon/cups-polld", ServerBin); + + sprintf(bport, "%d", BrowsePort); + + if (BrowseInterval) + sprintf(interval, "%d", BrowseInterval); + else + strcpy(interval, "30"); + + argv[0] = "cups-polld"; + argv[2] = sport; + argv[3] = interval; + argv[4] = bport; + argv[5] = NULL; + + cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0]))); + + /* + * Create a pipe that receives the status messages from each + * polling daemon... + */ + + if (cupsdOpenPipe(statusfds)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create polling status pipes - %s.", + strerror(errno)); + PollPipe = -1; + PollStatusBuffer = NULL; + return; + } + + PollPipe = statusfds[0]; + PollStatusBuffer = cupsdStatBufNew(PollPipe, "[Poll]"); + + /* + * Run each polling daemon, redirecting stderr to the polling pipe... + */ + + for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++) + { + sprintf(sport, "%d", pollp->port); + + argv[1] = pollp->hostname; + + if (cupsdStartProcess(polld, argv, envp, -1, -1, statusfds[1], -1, + 0, &(pollp->pid)) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartPolling: Unable to fork polling daemon - %s", + strerror(errno)); + pollp->pid = 0; + break; + } + else + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdStartPolling: Started polling daemon for %s:%d, pid = %d", + pollp->hostname, pollp->port, pollp->pid); + } + + close(statusfds[1]); + + /* + * Finally, add the pipe to the input selection set... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartPolling: Adding fd %d to InputSet...", PollPipe); + + FD_SET(PollPipe, InputSet); +} + + +/* + * 'cupsdStopBrowsing()' - Stop sending and receiving broadcast information. + */ + +void +cupsdStopBrowsing(void) +{ + if (!Browsing || !(BrowseLocalProtocols | BrowseRemoteProtocols)) + return; + + if ((BrowseLocalProtocols | BrowseRemoteProtocols) & 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 */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopBrowsing: Removing fd %d from InputSet...", + BrowseSocket); + + FD_CLR(BrowseSocket, InputSet); + BrowseSocket = -1; + } + } + +#ifdef HAVE_LIBSLP + if ((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) + { + /* + * Close SLP handle... + */ + + SLPClose(BrowseSLPHandle); + } +#endif /* HAVE_LIBSLP */ +} + + +/* + * 'cupsdStopPolling()' - Stop polling servers as needed. + */ + +void +cupsdStopPolling(void) +{ + int i; /* Looping var */ + cupsd_dirsvc_poll_t *pollp; /* Current polling server */ + + + if (PollPipe >= 0) + { + cupsdStatBufDelete(PollStatusBuffer); + close(PollPipe); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopPolling: removing fd %d from InputSet.", PollPipe); + FD_CLR(PollPipe, InputSet); + + PollPipe = -1; + PollStatusBuffer = NULL; + } + + for (i = 0, pollp = Polled; i < NumPolled; i ++, pollp ++) + if (pollp->pid) + cupsdEndProcess(pollp->pid, 0); +} + + +/* + * 'cupsdUpdateCUPSBrowse()' - Update the browse lists using the CUPS protocol. + */ + +void +cupsdUpdateCUPSBrowse(void) +{ + int i; /* Looping var */ + int auth; /* Authorization status */ + int len; /* Length of name string */ + int bytes; /* Number of bytes left */ + char packet[1541], /* Broadcast packet */ + *pptr; /* Pointer into packet */ + socklen_t srclen; /* Length of source address */ + http_addr_t srcaddr; /* Source address */ + char srcname[1024]; /* Source hostname */ + unsigned address[4]; /* Source address */ + unsigned type; /* Printer type */ + unsigned 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 */ + cupsd_netif_t *iface; /* Network interface */ + int num_attrs; /* Number of attributes */ + cups_option_t *attrs; /* Attributes */ + + + /* + * Read a packet from the browse socket... + */ + + srclen = sizeof(srcaddr); + if ((bytes = recvfrom(BrowseSocket, packet, sizeof(packet) - 1, 0, + (struct sockaddr *)&srcaddr, &srclen)) < 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 && errno != EAGAIN) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Browse recv failed - %s.", + strerror(errno)); + cupsdLogMessage(CUPSD_LOG_ERROR, "Browsing turned off."); + + cupsdStopBrowsing(); + Browsing = 0; + } + + return; + } + + packet[bytes] = '\0'; + + /* + * Figure out where it came from... + */ + +#ifdef AF_INET6 + if (srcaddr.addr.sa_family == AF_INET6) + { + address[0] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[0]); + address[1] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[1]); + address[2] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[2]); + address[3] = ntohl(srcaddr.ipv6.sin6_addr.s6_addr32[3]); + } + else +#endif /* AF_INET6 */ + { + address[0] = 0; + address[1] = 0; + address[2] = 0; + address[3] = ntohl(srcaddr.ipv4.sin_addr.s_addr); + } + + if (HostNameLookups) + httpAddrLookup(&srcaddr, srcname, sizeof(srcname)); + else + httpAddrString(&srcaddr, srcname, sizeof(srcname)); + + len = strlen(srcname); + + /* + * Do ACL stuff... + */ + + if (BrowseACL) + { + if (httpAddrLocalhost(&srcaddr) || !strcasecmp(srcname, "localhost")) + { + /* + * 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 (cupsdCheckAuth(address, srcname, len, + BrowseACL->num_deny, BrowseACL->deny)) + auth = AUTH_DENY; + + if (cupsdCheckAuth(address, srcname, len, + BrowseACL->num_allow, BrowseACL->allow)) + auth = AUTH_ALLOW; + break; + + case AUTH_DENY : /* Order Allow,Deny */ + auth = AUTH_DENY; + + if (cupsdCheckAuth(address, srcname, len, + BrowseACL->num_allow, BrowseACL->allow)) + auth = AUTH_ALLOW; + + if (cupsdCheckAuth(address, srcname, len, + BrowseACL->num_deny, BrowseACL->deny)) + auth = AUTH_DENY; + break; + } + } + } + else + auth = AUTH_ALLOW; + + if (auth == AUTH_DENY) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdUpdateCUPSBrowse: Refused %d bytes from %s", bytes, + srcname); + return; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdUpdateCUPSBrowse: (%d bytes from %s) %s", bytes, + srcname, packet); + + /* + * Parse packet... + */ + + if (sscanf(packet, "%x%x%1023s", &type, &state, uri) < 3) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "cupsdUpdateCUPSBrowse: Garbled browse packet - %s", packet); + return; + } + + strcpy(location, "Location Unknown"); + strcpy(info, "No Information Available"); + make_model[0] = '\0'; + num_attrs = 0; + attrs = NULL; + + 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 & 255)) + pptr ++; + + if (*pptr == '\"') + { + for (i = 0, pptr ++; + i < (sizeof(info) - 1) && *pptr && *pptr != '\"'; + i ++, pptr ++) + info[i] = *pptr; + + info[i] = '\0'; + + if (*pptr == '\"') + pptr ++; + + while (*pptr && isspace(*pptr & 255)) + pptr ++; + + if (*pptr == '\"') + { + for (i = 0, pptr ++; + i < (sizeof(make_model) - 1) && *pptr && *pptr != '\"'; + i ++, pptr ++) + make_model[i] = *pptr; + + if (*pptr == '\"') + pptr ++; + + make_model[i] = '\0'; + + if (*pptr) + num_attrs = cupsParseOptions(pptr, num_attrs, &attrs); + } + } + } + + 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... + */ + + httpSeparateURI(uri, method, sizeof(method), username, sizeof(username), + host, sizeof(host), &port, resource, sizeof(resource)); + + DEBUG_printf(("host=\"%s\", ServerName=\"%s\"\n", host, ServerName)); + + /* + * Check for packets from the local server... + */ + + if (!strcasecmp(host, ServerName) && port == LocalPort) + { + cupsFreeOptions(num_attrs, attrs); + return; + } + + cupsdNetIFUpdate(); + + for (iface = NetIFList; iface != NULL; iface = iface->next) + if (!strcasecmp(host, iface->hostname) && port == iface->port) + { + cupsFreeOptions(num_attrs, attrs); + return; + } + + /* + * Do relaying... + */ + + for (i = 0; i < NumRelays; i ++) + if (cupsdCheckAuth(address, srcname, len, 1, &(Relays[i].from))) + if (sendto(BrowseSocket, packet, bytes, 0, + (struct sockaddr *)&(Relays[i].to), + sizeof(http_addr_t)) <= 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdUpdateCUPSBrowse: sendto failed for relay %d - %s.", + i + 1, strerror(errno)); + cupsFreeOptions(num_attrs, attrs); + return; + } + + /* + * Process the browse data... + */ + + cupsdProcessBrowseData(uri, (cups_ptype_t)type, (ipp_pstate_t)state, location, + info, make_model, num_attrs, attrs); + cupsFreeOptions(num_attrs, attrs); +} + + +/* + * 'cupsdUpdatePolling()' - Read status messages from the poll daemons. + */ + +void +cupsdUpdatePolling(void) +{ + char *ptr, /* Pointer to end of line in buffer */ + message[1024]; /* Pointer to message text */ + int loglevel; /* Log level for message */ + + + while ((ptr = cupsdStatBufUpdate(PollStatusBuffer, &loglevel, + message, sizeof(message))) != NULL) + if (!strchr(PollStatusBuffer->buffer, '\n')) + break; + + if (ptr == NULL) + { + /* + * All polling processes have died; stop polling... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdUpdatePolling: all polling processes have exited!"); + cupsdStopPolling(); + } +} + + +#ifdef HAVE_LIBSLP +/* + * 'cupsdUpdateSLPBrowse()' - Get browsing information via SLP. + */ + +void +cupsdUpdateSLPBrowse(void) +{ + slpsrvurl_t *s, /* Temporary list of service URLs */ + *next; /* Next service in list */ + cupsd_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 */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() Start..."); + + /* + * Reset the refresh time... + */ + + BrowseSLPRefresh = time(NULL) + BrowseInterval; + + /* + * Poll for remote printers using SLP... + */ + + s = NULL; + + SLPFindSrvs(BrowseSLPHandle, SLP_CUPS_SRVTYPE, "", "", + slp_url_callback, &s); + + /* + * Loop through the list of available printers... + */ + + for (; s; s = next) + { + /* + * Save the "next" pointer... + */ + + next = s->next; + + /* + * Load a cupsd_printer_t structure with the SLP service attributes... + */ + + SLPFindAttrs(BrowseSLPHandle, s->url, "", "", slp_attr_callback, &p); + + /* + * Process this printer entry... + */ + + uri = s->url + SLP_CUPS_SRVLEN + 1; + + if (!strncmp(uri, "http://", 7) || !strncmp(uri, "ipp://", 6)) + { + /* + * Pull the URI apart to see if this is a local or remote printer... + */ + + httpSeparateURI(uri, method, sizeof(method), username, sizeof(username), + host, sizeof(host), &port, resource, sizeof(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) + cupsdProcessBrowseData(uri, p.type, IPP_PRINTER_IDLE, p.location, + p.info, p.make_model, 0, NULL); + else if (strstr(uri, "/classes/") != NULL) + cupsdProcessBrowseData(uri, p.type | CUPS_PRINTER_CLASS, IPP_PRINTER_IDLE, + p.location, p.info, p.make_model, 0, NULL); + } + + /* + * Free this listing... + */ + + free(s); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdUpdateSLPBrowse() End..."); +} + + +/* + * 'slp_attr_callback()' - SLP attribute callback + */ + +static SLPBoolean /* O - SLP_TRUE for success */ +slp_attr_callback( + SLPHandle hslp, /* I - SLP handle */ + const char *attrlist, /* I - Attribute list */ + SLPError errcode, /* I - Parsing status for this attr */ + void *cookie) /* I - Current printer */ +{ + char *tmp = 0; + cupsd_printer_t *p = (cupsd_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(cupsd_printer_t)); + + p->type = CUPS_PRINTER_REMOTE; + + if (slp_get_attr(attrlist, "(printer-location=", &(p->location))) + return (SLP_FALSE); + if (slp_get_attr(attrlist, "(printer-info=", &(p->info))) + return (SLP_FALSE); + if (slp_get_attr(attrlist, "(printer-make-and-model=", &(p->make_model))) + return (SLP_FALSE); + + if (slp_get_attr(attrlist, "(color-supported=", &tmp)) + return (SLP_FALSE); + if (strcasecmp(tmp, "true") == 0) + p->type |= CUPS_PRINTER_COLOR; + + if (slp_get_attr(attrlist, "(finishings-supported=", &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 (slp_get_attr(attrlist, "(sides-supported=", &tmp)) + return (SLP_FALSE); + if (strstr(tmp,"two-sided")) + p->type |= CUPS_PRINTER_DUPLEX; + + cupsdClearString(&tmp); + + return (SLP_TRUE); +} + + +/* + * 'slp_dereg_printer()' - SLPDereg() the specified printer + */ + +static void +slp_dereg_printer(cupsd_printer_t *p) /* I - Printer */ +{ + char srvurl[HTTP_MAX_URI]; /* Printer service URI */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "slp_dereg_printer: printer=\"%s\"", p->name); + + if (!(p->type & CUPS_PRINTER_REMOTE)) + { + /* + * 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, slp_reg_callback, 0); + } +} + + +/* + * 'slp_get_attr()' - Get an attribute from an SLP registration. + */ + +static int /* O - 0 on success */ +slp_get_attr(const char *attrlist, /* I - Attribute list string */ + const char *tag, /* I - Name of attribute */ + char **valbuf) /* O - Value */ +{ + char *ptr1, /* Pointer into string */ + *ptr2; /* ... */ + + + cupsdClearString(valbuf); + + if ((ptr1 = strstr(attrlist, tag)) != NULL) + { + ptr1 += strlen(tag); + + if ((ptr2 = strchr(ptr1,')')) != NULL) + { + /* + * Copy the value... + */ + + *valbuf = calloc(ptr2 - ptr1 + 1, 1); + strncpy(*valbuf, ptr1, ptr2 - ptr1); + + /* + * Dequote the value... + */ + + for (ptr1 = *valbuf; *ptr1; ptr1 ++) + if (*ptr1 == '\\' && ptr1[1]) + _cups_strcpy(ptr1, ptr1 + 1); + + return (0); + } + } + + return (-1); +} + + +/* + * 'slp_reg_callback()' - Empty SLPRegReport. + */ + +static void +slp_reg_callback(SLPHandle hslp, /* I - SLP handle */ + SLPError errcode, /* I - Error code, if any */ + void *cookie) /* I - App data */ +{ + (void)hslp; + (void)errcode; + (void)cookie; + + return; +} + + +/* + * 'slp_url_callback()' - SLP service url callback + */ + +static SLPBoolean /* O - TRUE = OK, FALSE = error */ +slp_url_callback( + 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... + */ + + strlcpy(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); +} +#endif /* HAVE_LIBSLP */ + + +/* + * End of "$Id: dirsvc.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/scheduler/dirsvc.h b/scheduler/dirsvc.h new file mode 100644 index 000000000..b9da4e34e --- /dev/null +++ b/scheduler/dirsvc.h @@ -0,0 +1,162 @@ +/* + * "$Id: dirsvc.h 4822 2005-11-04 21:13:20Z mike $" + * + * Directory services definitions for the Common UNIX Printing System + * (CUPS) scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Include necessary headers... + */ + +#ifdef HAVE_LIBSLP +# include +#endif /* HAVE_LIBSLP */ + + +/* + * Browse protocols... + */ + +#define BROWSE_CUPS 1 /* CUPS */ +#define BROWSE_SLP 2 /* SLPv2 */ +#define BROWSE_LDAP 4 /* LDAP (not supported yet) */ +#define BROWSE_ALL 7 /* All protocols */ + + +/* + * Browse address... + */ + +typedef struct +{ + char iface[32]; /* Destination interface */ + http_addr_t to; /* Destination address */ +} cupsd_dirsvc_addr_t; + + +/* + * Relay structure... + */ + +typedef struct +{ + cupsd_authmask_t from; /* Source address/name mask */ + http_addr_t to; /* Destination address */ +} cupsd_dirsvc_relay_t; + + +/* + * Polling structure... + */ + +typedef struct +{ + char hostname[64]; /* Hostname (actually, IP address) */ + int port; /* Port number */ + int pid; /* Current poll server PID */ +} cupsd_dirsvc_poll_t; + + +/* + * Globals... + */ + +VAR int Browsing VALUE(TRUE), + /* Whether or not browsing is enabled */ + BrowseLocalProtocols + VALUE(BROWSE_ALL), + /* Protocols to support for local printers */ + BrowseRemoteProtocols + VALUE(BROWSE_ALL), + /* Protocols to support for remote printers */ + 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 char *BrowseLocalOptions + VALUE(NULL), + /* Options to add to local printer URIs */ + *BrowseRemoteOptions + VALUE(NULL); + /* Options to add to remote printer URIs */ +VAR cupsd_dirsvc_addr_t *Browsers VALUE(NULL); + /* Broadcast addresses */ +VAR cupsd_location_t *BrowseACL VALUE(NULL); + /* Browser access control list */ +VAR cupsd_printer_t *BrowseNext VALUE(NULL); + /* Next class/printer to broadcast */ +VAR int NumRelays VALUE(0); + /* Number of broadcast relays */ +VAR cupsd_dirsvc_relay_t *Relays VALUE(NULL); + /* Broadcast relays */ +VAR int NumPolled VALUE(0); + /* Number of polled servers */ +VAR cupsd_dirsvc_poll_t *Polled VALUE(NULL); + /* Polled servers */ +VAR int PollPipe VALUE(0); + /* Status pipe for pollers */ +VAR cupsd_statbuf_t *PollStatusBuffer VALUE(NULL); + /* Status buffer 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 cupsdLoadRemoteCache(void); +extern void cupsdProcessBrowseData(const char *uri, cups_ptype_t type, + ipp_pstate_t state, const char *location, + const char *info, const char *make_model, + int num_attrs, cups_option_t *attrs); +extern void cupsdProcessImplicitClasses(void); +extern void cupsdSaveRemoteCache(void); +extern void cupsdSendBrowseDelete(cupsd_printer_t *p); +extern void cupsdSendBrowseList(void); +extern void cupsdSendCUPSBrowse(cupsd_printer_t *p); +extern void cupsdSendSLPBrowse(cupsd_printer_t *p); +extern void cupsdStartBrowsing(void); +extern void cupsdStartPolling(void); +extern void cupsdStopBrowsing(void); +extern void cupsdStopPolling(void); +extern void cupsdUpdateCUPSBrowse(void); +extern void cupsdUpdatePolling(void); +extern void cupsdUpdateSLPBrowse(void); + + +/* + * End of "$Id: dirsvc.h 4822 2005-11-04 21:13:20Z mike $". + */ diff --git a/scheduler/env.c b/scheduler/env.c new file mode 100644 index 000000000..df13dab18 --- /dev/null +++ b/scheduler/env.c @@ -0,0 +1,224 @@ +/* + * "$Id: env.c 4719 2005-09-28 21:12:44Z mike $" + * + * Environment management routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdClearEnv() - Clear common environment variables. + * cupsdInitEnv() - Initialize the current environment with standard + * variables. + * cupsdLoadEnv() - Copy common environment variables into an array. + * cupsdSetEnv() - Set a common environment variable. + * cupsdSetEnvf() - Set a formatted common environment variable. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + + +/* + * Local globals... + */ + +static int num_common_env = 0; /* Number of common env vars */ +static char *common_env[100]; /* Common env vars */ + + +/* + * 'cupsdClearEnv()' - Clear common environment variables. + */ + +void +cupsdClearEnv(void) +{ + int i; /* Looping var */ + + + for (i = 0; i < num_common_env; i ++) + cupsdClearString(common_env + i); + + num_common_env = 0; +} + + +/* + * 'cupsdInitEnv()' - Initialize the current environment with standard variables. + */ + +void +cupsdInitEnv(void) +{ + /* + * Clear existing environment variables... + */ + + cupsdClearEnv(); + +#ifdef __APPLE__ + /* + * Add special voodoo magic for MacOS X - this allows MacOS X programs + * to access their bundle resources properly... + */ + + cupsdSetString(common_env, ""); + num_common_env = 1; +#endif /* __APPLE__ */ + + /* + * Set common variables... + */ + + cupsdSetEnv("CUPS_CACHEDIR", CacheDir); + cupsdSetEnv("CUPS_DATADIR", DataDir); + cupsdSetEnv("CUPS_DOCROOT", DocumentRoot); + cupsdSetEnv("CUPS_FONTPATH", FontPath); + cupsdSetEnv("CUPS_REQUESTROOT", RequestRoot); + cupsdSetEnv("CUPS_SERVERBIN", ServerBin); + cupsdSetEnv("CUPS_SERVERROOT", ServerRoot); + cupsdSetEnv("CUPS_STATEDIR", StateDir); + cupsdSetEnv("DYLD_LIBRARY_PATH", NULL); + cupsdSetEnv("LD_ASSUME_KERNEL", NULL); + cupsdSetEnv("LD_LIBRARY_PATH", NULL); + cupsdSetEnv("LD_PRELOAD", NULL); + cupsdSetEnv("NLSPATH", NULL); + cupsdSetEnvf("PATH", "%s/filter:/bin:/usr/bin", ServerBin); + cupsdSetEnv("SHLIB_PATH", NULL); + cupsdSetEnv("SOFTWARE", CUPS_MINIMAL); + cupsdSetEnv("TMPDIR", TempDir); + cupsdSetEnv("TZ", NULL); + cupsdSetEnv("USER", "root"); + cupsdSetEnv("VG_ARGS", NULL); +} + + +/* + * 'cupsdLoadEnv()' - Copy common environment variables into an array. + */ + +int /* O - Number of environment variables */ +cupsdLoadEnv(char *envp[], /* I - Environment array */ + int envmax) /* I - Maximum number of elements */ +{ + int i; /* Looping var */ + + + /* + * Leave room for a NULL pointer at the end... + */ + + envmax --; + + /* + * Copy pointers to the environment... + */ + + for (i = 0; i < num_common_env && i < envmax; i ++) + envp[i] = common_env[i]; + + /* + * NULL terminate the environment array and return the number of + * elements we added... + */ + + envp[i] = NULL; + + return (i); +} + + +/* + * 'cupsdSetEnv()' - Set a common environment variable. + */ + +void +cupsdSetEnv(const char *name, /* I - Name of variable */ + const char *value) /* I - Value of variable */ +{ + /* + * Check for room... + */ + + if (num_common_env >= (int)(sizeof(common_env) / sizeof(common_env[0]))) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdSetEnv: Too many environment variables set!"); + return; + } + + /* + * If "value" is NULL, try getting value from current environment... + */ + + if (!value) + value = getenv(name); + + if (!value) + return; + + /* + * Set the new environment variable... + */ + + cupsdSetStringf(common_env + num_common_env, "%s=%s", name, value); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetEnv: %s\n", + common_env[num_common_env]); + + num_common_env ++; +} + + +/* + * 'cupsdSetEnvf()' - Set a formatted common environment variable. + */ + +void +cupsdSetEnvf(const char *name, /* I - Name of variable */ + const char *value, /* I - Printf-style value of variable */ + ...) /* I - Additional args as needed */ +{ + char v[4096]; /* Formatting string value */ + va_list ap; /* Argument pointer */ + + + /* + * Format the value string... + */ + + va_start(ap, value); + vsnprintf(v, sizeof(v), value, ap); + va_end(ap); + + /* + * Set the env variable... + */ + + cupsdSetEnv(name, v); +} + + +/* + * End of "$Id: env.c 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/filter.c b/scheduler/filter.c new file mode 100644 index 000000000..dbf19a0de --- /dev/null +++ b/scheduler/filter.c @@ -0,0 +1,326 @@ +/* + * "$Id: filter.c 4833 2005-11-12 21:46:52Z mike $" + * + * File type conversion routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * mimeAddFilter() - Add a filter to the current MIME database. + * mimeFilter() - Find the fastest way to convert from one type to another. + * compare() - Compare two filter types... + * lookup() - Lookup a filter... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include + +#include +#include +#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; + strlcpy(temp->filter, filter, sizeof(temp->filter)); + } + } + else + { + /* + * Nope, add a new one... + */ + + if (mime->num_filters == 0) + temp = malloc(sizeof(mime_filter_t)); + else + temp = realloc(mime->filters, sizeof(mime_filter_t) * (mime->num_filters + 1)); + + if (temp == NULL) + return (NULL); + + mime->filters = temp; + temp += mime->num_filters; + mime->num_filters ++; + + /* + * Copy the information over and sort if necessary... + */ + + temp->src = src; + temp->dst = dst; + temp->cost = cost; + strlcpy(temp->filter, filter, sizeof(temp->filter)); + + if (mime->num_filters > 1) + qsort(mime->filters, mime->num_filters, sizeof(mime_filter_t), + (int (*)(const void *, const void *))compare); + } + + /* + * Return the new/updated filter... + */ + + return (temp); +} + + +/* + * 'mimeFilter()' - Find the fastest way to convert from one type to another. + */ + +mime_filter_t * /* O - Array of filters to run */ +mimeFilter(mime_t *mime, /* I - MIME database */ + mime_type_t *src, /* I - Source file type */ + mime_type_t *dst, /* I - Destination file type */ + int *num_filters, /* O - Number of filters to run */ + int max_depth) /* I - Maximum depth of search */ +{ + 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 */ + *current; /* Current filter */ + + + /* + * Range-check the input... + */ + + DEBUG_printf(("mimeFilter(mime=%p, src=%p(%s/%s), dst=%p(%s/%s), num_filters=%p(%d))\n", + mime, src, src ? src->super : "?", src ? src->type : "?", + dst, dst ? dst->super : "?", dst ? dst->type : "?", + num_filters, num_filters ? *num_filters : 0)); + + if (mime == NULL || src == NULL || dst == NULL || num_filters == NULL || + max_depth <= 0) + 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 ((mintemp = (mime_filter_t *)malloc(sizeof(mime_filter_t))) == NULL) + return (NULL); + + memcpy(mintemp, temp, sizeof(mime_filter_t)); + num_mintemp = 1; + mincost = mintemp->cost; + + DEBUG_puts(" Found direct filter:"); + DEBUG_printf((" %s (cost=%d)\n", mintemp->filter, mincost)); + } + else + { + /* + * No direct filter... + */ + + mincost = 9999999; + mintemp = NULL; + num_mintemp = 0; + } + + /* + * OK, now look for filters from the source type to any other type... + */ + + 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, + max_depth - 1)) == NULL) + continue; + + /* + * Found a match; see if this one is less costly than the last (if + * any...) + */ + + for (j = 0, cost = current->cost; j < num_temp; j ++) + cost += temp[j].cost; + + if (cost < mincost) + { + if (mintemp != NULL) + free(mintemp); + + /* + * Hey, we got a match! Add the current filter to the beginning of the + * filter list... + */ + + mintemp = (mime_filter_t *)realloc(temp, sizeof(mime_filter_t) * + (num_temp + 1)); + + if (mintemp == NULL) + { + *num_filters = 0; + return (NULL); + } + + memmove(mintemp + 1, mintemp, num_temp * sizeof(mime_filter_t)); + memcpy(mintemp, current, sizeof(mime_filter_t)); + + num_mintemp = num_temp + 1; + mincost = cost; + } + else + free(temp); + } + + if (mintemp != NULL) + { + /* + * Hey, we got a match! + */ + + *num_filters = num_mintemp; + +#ifdef DEBUG + printf(" Returning %d filters:\n", *num_filters); + for (i = 0; i < num_mintemp; i ++) + printf(" %s\n", mintemp[i].filter); +#endif /* DEBUG */ + + return (mintemp); + } + + DEBUG_puts(" Returning zippo..."); + + 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: filter.c 4833 2005-11-12 21:46:52Z mike $". + */ diff --git a/scheduler/ipp.c b/scheduler/ipp.c new file mode 100644 index 000000000..d69dec1e8 --- /dev/null +++ b/scheduler/ipp.c @@ -0,0 +1,8986 @@ +/* + * "$Id: ipp.c 4906 2006-01-10 20:53:28Z mike $" + * + * IPP routines for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdProcessIPPRequest() - 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_job_subscriptions() - Add any subcriptions for a job. + * 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 + * authenticate_job() - Set job authentication info. + * cancel_all_jobs() - Cancel all print jobs. + * cancel_job() - Cancel a print job. + * cancel_subscription() - Cancel a subscription. + * check_quotas() - Check quotas for a printer and user. + * copy_attribute() - Copy a single attribute. + * copy_attrs() - Copy attributes from one request to another. + * copy_banner() - Copy a banner file to the requests directory + * for the specified job. + * copy_file() - Copy a PPD file or interface script... + * copy_model() - Copy a PPD model file, substituting default + * values as needed... + * copy_subscription_attrs() - Copy subscription attributes. + * create_job() - Print a file to a printer or class. + * create_requested_array() - Create an array for the requested-attributes. + * create_subscription() - Create a notification subscription. + * 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_notifications() - Get events for a subscription. + * 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. + * get_subscription_attrs() - Get subscription attributes. + * get_subscriptions() - Get subscriptions. + * hold_job() - Hold a print job. + * move_job() - Move a job to a new destination. + * ppd_add_default() - Add a PPD default choice. + * ppd_parse_line() - Parse a PPD default line. + * print_job() - Print a file to a printer or class. + * read_ps_line() - Read a line from a PS file... + * read_ps_job_ticket() - Reads a job ticket embedded in a PS file. + * reject_jobs() - Reject print jobs to a printer. + * release_job() - Release a held print job. + * restart_job() - Restart an old print job. + * save_auth_info() - Save authentication information for a job. + * send_document() - Send a file to a printer or class. + * send_http_error() - Send a HTTP error back to the IPP client. + * send_ipp_status() - Send a 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. + * user_allowed() - See if a user is allowed to print to a queue. + * validate_job() - Validate printer options and destination. + * validate_name() - Make sure the printer name only contains + * valid chars. + * validate_user() - Validate the user for the request. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + +#ifdef HAVE_LIBPAPER +# include +#endif /* HAVE_LIBPAPER */ + + +/* + * PPD default choice structure... + */ + +typedef struct +{ + char option[PPD_MAX_NAME]; /* Main keyword (option name) */ + char choice[PPD_MAX_NAME]; /* Option keyword (choice name) */ +} ppd_default_t; + + +/* + * Local functions... + */ + +static void accept_jobs(cupsd_client_t *con, ipp_attribute_t *uri); +static void add_class(cupsd_client_t *con, ipp_attribute_t *uri); +static int add_file(cupsd_client_t *con, cupsd_job_t *job, mime_type_t *filetype, + int compression); +static void add_job_state_reasons(cupsd_client_t *con, cupsd_job_t *job); +static void add_job_subscriptions(cupsd_client_t *con, cupsd_job_t *job); +static void add_printer(cupsd_client_t *con, ipp_attribute_t *uri); +static void add_printer_state_reasons(cupsd_client_t *con, cupsd_printer_t *p); +static void add_queued_job_count(cupsd_client_t *con, cupsd_printer_t *p); +static void authenticate_job(cupsd_client_t *con, ipp_attribute_t *uri); +static void cancel_all_jobs(cupsd_client_t *con, ipp_attribute_t *uri); +static void cancel_job(cupsd_client_t *con, ipp_attribute_t *uri); +static void cancel_subscription(cupsd_client_t *con, int id); +static int check_quotas(cupsd_client_t *con, cupsd_printer_t *p); +static ipp_attribute_t *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, int quickcopy); +static int copy_banner(cupsd_client_t *con, cupsd_job_t *job, const char *name); +static int copy_file(const char *from, const char *to); +static int copy_model(cupsd_client_t *con, const char *from, const char *to); +static void copy_subscription_attrs(cupsd_client_t *con, + cupsd_subscription_t *sub, + cups_array_t *ra); +static void create_job(cupsd_client_t *con, ipp_attribute_t *uri); +static cups_array_t *create_requested_array(ipp_t *request); +static void create_subscription(cupsd_client_t *con, ipp_attribute_t *uri); +static void delete_printer(cupsd_client_t *con, ipp_attribute_t *uri); +static void get_default(cupsd_client_t *con); +static void get_devices(cupsd_client_t *con); +static void get_jobs(cupsd_client_t *con, ipp_attribute_t *uri); +static void get_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri); +static void get_notifications(cupsd_client_t *con, int id); +static void get_ppds(cupsd_client_t *con); +static void get_printers(cupsd_client_t *con, int type); +static void get_printer_attrs(cupsd_client_t *con, ipp_attribute_t *uri); +static void get_subscription_attrs(cupsd_client_t *con, int sub_id); +static void get_subscriptions(cupsd_client_t *con, ipp_attribute_t *uri); +static void hold_job(cupsd_client_t *con, ipp_attribute_t *uri); +static void move_job(cupsd_client_t *con, ipp_attribute_t *uri); +static int ppd_add_default(const char *option, const char *choice, + int num_defaults, ppd_default_t **defaults); +static int ppd_parse_line(const char *line, char *option, int olen, + char *choice, int clen); +static void print_job(cupsd_client_t *con, ipp_attribute_t *uri); +static void read_ps_job_ticket(cupsd_client_t *con); +static void reject_jobs(cupsd_client_t *con, ipp_attribute_t *uri); +static void release_job(cupsd_client_t *con, ipp_attribute_t *uri); +static void renew_subscription(cupsd_client_t *con, int sub_id); +static void restart_job(cupsd_client_t *con, ipp_attribute_t *uri); +static void save_auth_info(cupsd_client_t *con, cupsd_job_t *job); +static void send_document(cupsd_client_t *con, ipp_attribute_t *uri); +static void send_http_error(cupsd_client_t *con, http_status_t status); +static void send_ipp_status(cupsd_client_t *con, ipp_status_t status, + const char *message, ...) +# ifdef __GNUC__ +__attribute__ ((__format__ (__printf__, 3, 4))) +# endif /* __GNUC__ */ +; +static void set_default(cupsd_client_t *con, ipp_attribute_t *uri); +static void set_job_attrs(cupsd_client_t *con, ipp_attribute_t *uri); +static void start_printer(cupsd_client_t *con, ipp_attribute_t *uri); +static void stop_printer(cupsd_client_t *con, ipp_attribute_t *uri); +static int user_allowed(cupsd_printer_t *p, const char *username); +static void validate_job(cupsd_client_t *con, ipp_attribute_t *uri); +static int validate_name(const char *name); +static int validate_user(cupsd_job_t *job, cupsd_client_t *con, + const char *owner, char *username, + int userlen); + + +/* + * 'cupsdProcessIPPRequest()' - Process an incoming IPP request... + */ + +int /* O - 1 on success, 0 on failure */ +cupsdProcessIPPRequest( + cupsd_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 */ + int sub_id; /* Subscription ID */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdProcessIPPRequest(%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. + */ + + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, + "%04X %s Bad request version number %d.%d", + IPP_VERSION_NOT_SUPPORTED, con->http.hostname, + con->request->request.any.version[0], + con->request->request.any.version[1]); + + send_ipp_status(con, IPP_VERSION_NOT_SUPPORTED, + _("Bad request version number %d.%d!"), + con->request->request.any.version[0], + con->request->request.any.version[1]); + } + else if (con->request->attrs == NULL) + { + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, + "%04X %s No attributes in request", + IPP_BAD_REQUEST, con->http.hostname); + + send_ipp_status(con, IPP_BAD_REQUEST, _("No attributes in 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 && attr->group_tag != IPP_TAG_ZERO) + { + /* + * Out of order; return an error... + */ + + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, + "%04X %s Attribute groups are out of order", + IPP_BAD_REQUEST, con->http.hostname); + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Attribute groups are out of order (%x < %x)!"), + attr->group_tag, group); + 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 && !strcmp(attr->name, "attributes-charset") && + attr->value_tag == IPP_TAG_CHARSET) + charset = attr; + else + charset = NULL; + + if (attr) + attr = attr->next; + + if (attr && !strcmp(attr->name, "attributes-natural-language") && + 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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing attributes-charset attribute!"); + + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, + "%04X %s Missing attributes-charset attribute", + IPP_BAD_REQUEST, con->http.hostname); + } + + if (!language) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing attributes-natural-language attribute!"); + + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, + "%04X %s Missing attributes-natural-language attribute", + IPP_BAD_REQUEST, con->http.hostname); + } + + if (!uri) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Missing printer-uri or job-uri attribute!"); + + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, + "%04X %s Missing printer-uri or job-uri attribute", + IPP_BAD_REQUEST, con->http.hostname); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Request attributes follow..."); + + for (attr = con->request->attrs; attr != NULL; attr = attr->next) + cupsdLogMessage(CUPSD_LOG_DEBUG, + "attr \"%s\": group_tag = %x, value_tag = %x", + attr->name ? attr->name : "(null)", attr->group_tag, + attr->value_tag); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "End of attributes..."); + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Missing required attributes!")); + } + 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") && + strcasecmp(con->http.hostname, "localhost") && + strcmp(con->username, "root")) + { + /* + * Remote unauthenticated user masquerading as local root... + */ + + cupsdSetString(&(username->values[0].string.text), RemoteRoot); + } + } + + if ((attr = ippFindAttribute(con->request, "notify-subscription-id", + IPP_TAG_INTEGER)) != NULL) + sub_id = attr->values[0].integer; + else + sub_id = 0; + + /* + * Then try processing the operation... + */ + + if (uri) + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdProcessIPPRequest: URI=\"%s\"", + uri->values[0].string.text); + + 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; + + case CUPS_AUTHENTICATE_JOB : + authenticate_job(con, uri); + break; + + case IPP_CREATE_PRINTER_SUBSCRIPTION : + case IPP_CREATE_JOB_SUBSCRIPTION : + create_subscription(con, uri); + break; + + case IPP_GET_SUBSCRIPTION_ATTRIBUTES : + get_subscription_attrs(con, sub_id); + break; + + case IPP_GET_SUBSCRIPTIONS : + get_subscriptions(con, uri); + break; + + case IPP_RENEW_SUBSCRIPTION : + renew_subscription(con, sub_id); + break; + + case IPP_CANCEL_SUBSCRIPTION : + cancel_subscription(con, sub_id); + break; + + case IPP_GET_NOTIFICATIONS : + get_notifications(con, sub_id); + break; + + default : + cupsdAddEvent(CUPSD_EVENT_SERVER_AUDIT, NULL, NULL, + "%04X %s Operation %04X (%s) not supported", + IPP_OPERATION_NOT_SUPPORTED, con->http.hostname, + con->request->request.op.operation_id, + ippOpString(con->request->request.op.operation_id)); + + send_ipp_status(con, IPP_OPERATION_NOT_SUPPORTED, + _("%s not supported!"), + ippOpString(con->request->request.op.operation_id)); + break; + } + } + } + } + + if (con->response) + { + /* + * Sending data from the scheduler... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdProcessIPPRequest: %d status_code=%x (%s)", + con->http.fd, con->response->request.status.status_code, + ippErrorString(con->response->request.status.status_code)); + + if (cupsdSendHeader(con, HTTP_OK, "application/ipp")) + { + if (con->http.version == HTTP_1_1) + { + con->http.data_encoding = HTTP_ENCODE_CHUNKED; + + httpPrintf(HTTP(con), "Transfer-Encoding: chunked\r\n\r\n"); + } + else + { + con->http.data_encoding = HTTP_ENCODE_LENGTH; + con->http.data_remaining = ippLength(con->response); + + if (con->http.data_remaining < INT_MAX) + con->http._data_remaining = con->http.data_remaining; + else + con->http._data_remaining = INT_MAX; + + httpPrintf(HTTP(con), "Content-Length: " CUPS_LLFMT "\r\n\r\n", + CUPS_LLCAST con->http.data_remaining); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdProcessIPPRequest: Adding fd %d to OutputSet...", + con->http.fd); + + FD_SET(con->http.fd, OutputSet); + + /* + * Tell the caller the response header was sent successfully... + */ + + return (1); + } + else + { + /* + * Tell the caller the response header could not be sent... + */ + + return (0); + } + } + else + { + /* + * Sending data from a subprocess like cups-deviced; tell the caller + * everything is A-OK so far... + */ + + return (1); + } +} + + +/* + * 'accept_jobs()' - Accept print jobs to a printer. + */ + +static void +accept_jobs(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer or class URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer data */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "accept_jobs(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Accept jobs sent to the printer... + */ + + printer->accepting = 1; + printer->state_message[0] = '\0'; + + cupsdAddPrinterHistory(printer); + + if (dtype & CUPS_PRINTER_CLASS) + cupsdSaveAllClasses(); + else + cupsdSaveAllPrinters(); + + cupsdLogMessage(CUPSD_LOG_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(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - URI of class */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *pclass, /* Class */ + *member; /* Member printer/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 */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_class(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Do we have a valid URI? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + + if (strncmp(resource, "/classes/", 9) != 0 || strlen(resource) == 9) + { + /* + * No, return an error... + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("The printer-uri must be of the form " + "\"ipp://HOSTNAME/classes/CLASSNAME\".")); + return; + } + + /* + * Do we have a valid printer name? + */ + + if (!validate_name(resource + 9)) + { + /* + * No, return an error... + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("The printer-uri \"%s\" contains invalid characters."), + uri->values[0].string.text); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * See if the class already exists; if not, create a new class... + */ + + if ((pclass = cupsdFindClass(resource + 9)) == NULL) + { + /* + * Class doesn't exist; see if we have a printer of the same name... + */ + + if ((pclass = cupsdFindPrinter(resource + 9)) != NULL && + !(pclass->type & CUPS_PRINTER_REMOTE)) + { + /* + * Yes, return an error... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("A printer named \"%s\" already exists!"), + resource + 9); + return; + } + + /* + * No, add the pclass... + */ + + pclass = cupsdAddClass(resource + 9); + modify = 0; + } + else if (pclass->type & CUPS_PRINTER_IMPLICIT) + { + /* + * Rename the implicit class to "AnyClass" or remove it... + */ + + if (ImplicitAnyClasses) + { + cupsArrayRemove(Printers, pclass); + cupsdSetStringf(&pclass->name, "Any%s", resource + 9); + cupsArrayAdd(Printers, pclass); + } + else + cupsdDeletePrinter(pclass, 1); + + /* + * Add the class as a new local class... + */ + + pclass = cupsdAddClass(resource + 9); + modify = 0; + } + else if (pclass->type & CUPS_PRINTER_REMOTE) + { + /* + * Rename the remote class to "Class"... + */ + + cupsdDeletePrinterFilters(pclass); + cupsArrayRemove(Printers, pclass); + cupsdSetStringf(&pclass->name, "%s@%s", resource + 9, pclass->hostname); + cupsdSetPrinterAttrs(pclass); + cupsArrayAdd(Printers, pclass); + + /* + * Add the class as a new local class... + */ + + pclass = cupsdAddClass(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) + cupsdSetString(&pclass->location, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&pclass->info, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_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; + cupsdAddPrinterHistory(pclass); + } + + if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL) + { + if (pclass->shared && !attr->values[0].boolean) + cupsdSendBrowseDelete(pclass); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Setting %s printer-is-shared to %d (was %d.)", + pclass->name, attr->values[0].boolean, pclass->shared); + + pclass->shared = attr->values[0].boolean; + } + + if ((attr = ippFindAttribute(con->request, "printer-state", IPP_TAG_ENUM)) != NULL) + { + if (attr->values[0].integer != IPP_PRINTER_IDLE && + attr->values[0].integer != IPP_PRINTER_STOPPED) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Attempt to set %s printer-state to bad value %d!"), + pclass->name, attr->values[0].integer); + return; + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)", pclass->name, + attr->values[0].integer, pclass->state); + + if (attr->values[0].integer == IPP_PRINTER_STOPPED) + cupsdStopPrinter(pclass, 0); + else + cupsdSetPrinterState(pclass, (ipp_pstate_t)(attr->values[0].integer), 0); + } + if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) != NULL) + { + strlcpy(pclass->state_message, attr->values[0].string.text, + sizeof(pclass->state_message)); + cupsdAddPrinterHistory(pclass); + } + if ((attr = ippFindAttribute(con->request, "job-sheets-default", IPP_TAG_ZERO)) != NULL && + !Classification) + { + cupsdSetString(&pclass->job_sheets[0], attr->values[0].string.text); + if (attr->num_values > 1) + cupsdSetString(&pclass->job_sheets[1], attr->values[1].string.text); + else + cupsdSetString(&pclass->job_sheets[1], "none"); + } + if ((attr = ippFindAttribute(con->request, "requesting-user-name-allowed", + IPP_TAG_ZERO)) != NULL) + { + cupsdFreePrinterUsers(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 ++) + cupsdAddPrinterUser(pclass, attr->values[i].string.text); + } + else if ((attr = ippFindAttribute(con->request, "requesting-user-name-denied", + IPP_TAG_ZERO)) != NULL) + { + cupsdFreePrinterUsers(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 ++) + cupsdAddPrinterUser(pclass, attr->values[i].string.text); + } + if ((attr = ippFindAttribute(con->request, "job-quota-period", + IPP_TAG_INTEGER)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "add_class: Setting job-quota-period to %d...", + attr->values[0].integer); + cupsdFreeQuotas(pclass); + pclass->quota_period = attr->values[0].integer; + } + if ((attr = ippFindAttribute(con->request, "job-k-limit", + IPP_TAG_INTEGER)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "add_class: Setting job-k-limit to %d...", + attr->values[0].integer); + cupsdFreeQuotas(pclass); + pclass->k_limit = attr->values[0].integer; + } + if ((attr = ippFindAttribute(con->request, "job-page-limit", + IPP_TAG_INTEGER)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "add_class: Setting job-page-limit to %d...", + attr->values[0].integer); + cupsdFreeQuotas(pclass); + pclass->page_limit = attr->values[0].integer; + } + if ((attr = ippFindAttribute(con->request, "printer-op-policy", + IPP_TAG_NAME)) != NULL) + { + cupsd_policy_t *p; /* Policy */ + + + if ((p = cupsdFindPolicy(attr->values[0].string.text)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "add_class: Setting printer-op-policy to \"%s\"...", + attr->values[0].string.text); + cupsdSetString(&pclass->op_policy, attr->values[0].string.text); + pclass->op_policy_ptr = p; + } + else + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("add_class: Unknown printer-op-policy \"%s\"."), + attr->values[0].string.text); + return; + } + } + if ((attr = ippFindAttribute(con->request, "printer-error-policy", + IPP_TAG_NAME)) != NULL) + { + if (strcmp(attr->values[0].string.text, "abort-job") && + strcmp(attr->values[0].string.text, "retry-job") && + strcmp(attr->values[0].string.text, "stop-printer")) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("add_class: Unknown printer-error-policy \"%s\"."), + attr->values[0].string.text); + return; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "add_class: Setting printer-error-policy to \"%s\"...", + attr->values[0].string.text); + cupsdSetString(&pclass->error_policy, attr->values[0].string.text); + } + 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... + */ + + httpSeparateURI(attr->values[i].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &dtype, &member)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Add it to the class... + */ + + cupsdAddPrinterToClass(pclass, member); + } + } + + /* + * Update the printer class attributes and return... + */ + + cupsdSetPrinterAttrs(pclass); + cupsdSaveAllClasses(); + cupsdCheckJobs(); + + cupsdWritePrintcap(); + + if (modify) + { + cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, pclass, NULL, + "Class \"%s\" modified by \"%s\".", pclass->name, + con->username); + + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" modified by \"%s\".", + pclass->name, con->username); + } + else + { + cupsdAddPrinterHistory(pclass); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, pclass, NULL, + "New class \"%s\" added by \"%s\".", pclass->name, + con->username); + + cupsdLogMessage(CUPSD_LOG_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(cupsd_client_t *con, /* I - Connection to client */ + cupsd_job_t *job, /* I - Job to add to */ + mime_type_t *filetype, /* I - Type of file */ + int compression) /* I - Compression */ +{ + mime_type_t **filetypes; /* New filetypes array... */ + int *compressions; /* New compressions array... */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_file(con=%p[%d], job=%d, filetype=%s/%s, compression=%d)", + con, con->http.fd, job->id, filetype->super, filetype->type, + compression); + + /* + * Add the file to the job... + */ + + if (job->num_files == 0) + { + compressions = (int *)malloc(sizeof(int)); + filetypes = (mime_type_t **)malloc(sizeof(mime_type_t *)); + } + else + { + compressions = (int *)realloc(job->compressions, + (job->num_files + 1) * sizeof(int)); + filetypes = (mime_type_t **)realloc(job->filetypes, + (job->num_files + 1) * + sizeof(mime_type_t *)); + } + + if (compressions == NULL || filetypes == NULL) + { + cupsdCancelJob(job, 1); + + send_ipp_status(con, IPP_INTERNAL_ERROR, + _("Unable to allocate memory for file types!")); + return (-1); + } + + job->compressions = compressions; + job->compressions[job->num_files] = compression; + 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( + cupsd_client_t *con, /* I - Client connection */ + cupsd_job_t *job) /* I - Job info */ +{ + cupsd_printer_t *dest; /* Destination printer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_job_state_reasons(%p[%d], %d)", + con, con->http.fd, job ? job->id : 0); + + switch (job ? job->state->values[0].integer : IPP_JOB_CANCELLED) + { + case IPP_JOB_PENDING : + if (job->dtype & CUPS_PRINTER_CLASS) + dest = cupsdFindClass(job->dest); + else + dest = cupsdFindPrinter(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_job_subscriptions()' - Add any subcriptions for a job. + */ + +static void +add_job_subscriptions( + cupsd_client_t *con, /* I - Client connection */ + cupsd_job_t *job) /* I - Newly created job */ +{ + int i; /* Looping var */ + ipp_attribute_t *prev, /* Previous attribute */ + *next, /* Next attribute */ + *attr; /* Current attribute */ + cupsd_subscription_t *sub; /* Subscription object */ + const char *recipient, /* notify-recipient-uri */ + *pullmethod; /* notify-pull-method */ + ipp_attribute_t *user_data; /* notify-user-data */ + int interval; /* notify-time-interval */ + unsigned mask; /* notify-events */ + + + /* + * Find the first subscription group attribute; return if we have + * none... + */ + + for (attr = job->attrs->attrs, prev = NULL; + attr; + prev = attr, attr = attr->next) + if (attr->group_tag == IPP_TAG_SUBSCRIPTION) + break; + + if (!attr) + return; + + /* + * Process the subscription attributes in the request... + */ + + while (attr) + { + recipient = NULL; + pullmethod = NULL; + user_data = NULL; + interval = 0; + mask = CUPSD_EVENT_NONE; + + while (attr && attr->group_tag != IPP_TAG_ZERO) + { + if (!strcmp(attr->name, "notify-recipient") && + attr->value_tag == IPP_TAG_URI) + recipient = attr->values[0].string.text; + else if (!strcmp(attr->name, "notify-pull-method") && + attr->value_tag == IPP_TAG_KEYWORD) + pullmethod = attr->values[0].string.text; + else if (!strcmp(attr->name, "notify-charset") && + attr->value_tag == IPP_TAG_CHARSET && + strcmp(attr->values[0].string.text, "us-ascii") && + strcmp(attr->values[0].string.text, "utf-8")) + { + send_ipp_status(con, IPP_CHARSET, + _("Character set \"%s\" not supported!"), + attr->values[0].string.text); + return; + } + else if (!strcmp(attr->name, "notify-natural-language") && + (attr->value_tag != IPP_TAG_LANGUAGE || + strcmp(attr->values[0].string.text, DefaultLanguage))) + { + send_ipp_status(con, IPP_CHARSET, + _("Language \"%s\" not supported!"), + attr->values[0].string.text); + return; + } + else if (!strcmp(attr->name, "notify-user-data") && + attr->value_tag == IPP_TAG_STRING) + { + if (attr->num_values > 1 || attr->values[0].unknown.length > 63) + { + send_ipp_status(con, IPP_REQUEST_VALUE, + _("The notify-user-data value is too large " + "(%d > 63 octets)!"), + attr->values[0].unknown.length); + return; + } + + user_data = attr; + } + else if (!strcmp(attr->name, "notify-events") && + attr->value_tag == IPP_TAG_KEYWORD) + { + for (i = 0; i < attr->num_values; i ++) + mask |= cupsdEventValue(attr->values[i].string.text); + } + else if (!strcmp(attr->name, "notify-lease-duration")) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("The notify-lease-duration attribute cannot be " + "used with job subscriptions.")); + return; + } + else if (!strcmp(attr->name, "notify-time-interval") && + attr->value_tag == IPP_TAG_INTEGER) + interval = attr->values[0].integer; + + attr = attr->next; + } + + if (!recipient && !pullmethod) + break; + + if (mask == CUPSD_EVENT_NONE) + mask = CUPSD_EVENT_JOB_COMPLETED; + + sub = cupsdAddSubscription(mask, cupsdFindDest(job->dest), job, recipient, + 0); + + sub->interval = interval; + + cupsdSetString(&sub->owner, job->username); + + if (user_data) + { + sub->user_data_len = user_data->values[0].unknown.length; + memcpy(sub->user_data, user_data->values[0].unknown.data, + sub->user_data_len); + } + + ippAddSeparator(con->response); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-subscription-id", sub->id); + + if (attr) + attr = attr->next; + } + + cupsdSaveAllSubscriptions(); + + /* + * Remove all of the subscription attributes from the job request... + */ + + for (attr = job->attrs->attrs, prev = NULL; attr; attr = next) + { + next = attr->next; + + if (attr->group_tag == IPP_TAG_SUBSCRIPTION || + attr->group_tag == IPP_TAG_ZERO) + { + /* + * Free and remove this attribute... + */ + + _ipp_free_attr(attr); + + if (prev) + prev->next = next; + else + job->attrs->attrs = next; + } + else + prev = attr; + } + + job->attrs->last = prev; + job->attrs->current = prev; +} + + +/* + * 'add_printer()' - Add a printer to the system. + */ + +static void +add_printer(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - URI of printer */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer/class */ + ipp_attribute_t *attr; /* Printer attribute */ + cups_file_t *fp; /* Script/PPD file */ + 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 */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_printer(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Do we have a valid URI? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/printers/", 10) != 0 || strlen(resource) == 10) + { + /* + * No, return an error... + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("The printer-uri must be of the form " + "\"ipp://HOSTNAME/printers/PRINTERNAME\".")); + return; + } + + /* + * Do we have a valid printer name? + */ + + if (!validate_name(resource + 10)) + { + /* + * No, return an error... + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("The printer-uri \"%s\" contains invalid characters."), + uri->values[0].string.text); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * See if the printer already exists; if not, create a new printer... + */ + + if ((printer = cupsdFindPrinter(resource + 10)) == NULL) + { + /* + * Printer doesn't exist; see if we have a class of the same name... + */ + + if ((printer = cupsdFindClass(resource + 10)) != NULL && + !(printer->type & CUPS_PRINTER_REMOTE)) + { + /* + * Yes, return an error... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("A class named \"%s\" already exists!"), + resource + 10); + return; + } + + /* + * No, add the printer... + */ + + printer = cupsdAddPrinter(resource + 10); + modify = 0; + } + else if (printer->type & CUPS_PRINTER_IMPLICIT) + { + /* + * Rename the implicit printer to "AnyPrinter" or delete it... + */ + + if (ImplicitAnyClasses) + { + cupsArrayRemove(Printers, printer); + cupsdSetStringf(&printer->name, "Any%s", resource + 10); + cupsArrayAdd(Printers, printer); + } + else + cupsdDeletePrinter(printer, 1); + + /* + * Add the printer as a new local printer... + */ + + printer = cupsdAddPrinter(resource + 10); + modify = 0; + } + else if (printer->type & CUPS_PRINTER_REMOTE) + { + /* + * Rename the remote printer to "Printer@server"... + */ + + cupsdDeletePrinterFilters(printer); + cupsArrayRemove(Printers, printer); + cupsdSetStringf(&printer->name, "%s@%s", resource + 10, printer->hostname); + cupsdSetPrinterAttrs(printer); + cupsArrayAdd(Printers, printer); + + /* + * Add the printer as a new local printer... + */ + + printer = cupsdAddPrinter(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) + cupsdSetString(&printer->location, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "printer-info", IPP_TAG_TEXT)) != NULL) + cupsdSetString(&printer->info, attr->values[0].string.text); + + if ((attr = ippFindAttribute(con->request, "device-uri", IPP_TAG_URI)) != NULL) + { + /* + * Do we have a valid device URI? + */ + + httpSeparateURI(attr->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (!strcmp(method, "file")) + { + /* + * See if the administrator has enabled file devices... + */ + + if (!FileDevice && strcmp(resource, "/dev/null")) + { + /* + * File devices are disabled and the URL is not file:/dev/null... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("File device URIs have been disabled! " + "To enable, see the FileDevice directive in " + "\"%s/cupsd.conf\"."), + ServerRoot); + return; + } + } + else + { + /* + * See if the backend exists and is executable... + */ + + snprintf(srcfile, sizeof(srcfile), "%s/backend/%s", ServerBin, method); + if (access(srcfile, X_OK)) + { + /* + * Could not find device in list! + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad device-uri \"%s\"!"), + attr->values[0].string.text); + return; + } + } + + cupsdLogMessage(CUPSD_LOG_INFO, + "Setting %s device-uri to \"%s\" (was \"%s\".)", + printer->name, + cupsdSanitizeURI(attr->values[0].string.text, line, + sizeof(line)), + cupsdSanitizeURI(printer->device_uri, resource, + sizeof(resource))); + + cupsdSetString(&printer->device_uri, attr->values[0].string.text); + } + + if ((attr = ippFindAttribute(con->request, "port-monitor", IPP_TAG_KEYWORD)) != NULL) + { + ipp_attribute_t *supported; /* port-monitor-supported attribute */ + + + supported = ippFindAttribute(printer->attrs, "port-monitor-supported", + IPP_TAG_KEYWORD); + for (i = 0; i < supported->num_values; i ++) + if (!strcmp(supported->values[i].string.text, + attr->values[0].string.text)) + break; + + if (i >= supported->num_values) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Bad port-monitor \"%s\"!"), + attr->values[0].string.text); + return; + } + + cupsdLogMessage(CUPSD_LOG_INFO, + "Setting %s port-monitor to \"%s\" (was \"%s\".)", + printer->name, attr->values[0].string.text, + printer->port_monitor); + + if (strcmp(attr->values[0].string.text, "none")) + cupsdSetString(&printer->port_monitor, attr->values[0].string.text); + else + cupsdClearString(&printer->port_monitor); + } + + if ((attr = ippFindAttribute(con->request, "printer-is-accepting-jobs", IPP_TAG_BOOLEAN)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_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; + cupsdAddPrinterHistory(printer); + } + + if ((attr = ippFindAttribute(con->request, "printer-is-shared", IPP_TAG_BOOLEAN)) != NULL) + { + if (printer->shared && !attr->values[0].boolean) + cupsdSendBrowseDelete(printer); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Setting %s printer-is-shared to %d (was %d.)", + printer->name, attr->values[0].boolean, printer->shared); + + printer->shared = attr->values[0].boolean; + } + + if ((attr = ippFindAttribute(con->request, "printer-state", IPP_TAG_ENUM)) != NULL) + { + if (attr->values[0].integer != IPP_PRINTER_IDLE && + attr->values[0].integer != IPP_PRINTER_STOPPED) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad printer-state value %d!"), + attr->values[0].integer); + return; + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Setting %s printer-state to %d (was %d.)", printer->name, + attr->values[0].integer, printer->state); + + if (attr->values[0].integer == IPP_PRINTER_STOPPED) + cupsdStopPrinter(printer, 0); + else + cupsdSetPrinterState(printer, (ipp_pstate_t)(attr->values[0].integer), 0); + } + if ((attr = ippFindAttribute(con->request, "printer-state-message", IPP_TAG_TEXT)) != NULL) + { + strlcpy(printer->state_message, attr->values[0].string.text, + sizeof(printer->state_message)); + cupsdAddPrinterHistory(printer); + } + if ((attr = ippFindAttribute(con->request, "job-sheets-default", IPP_TAG_ZERO)) != NULL && + !Classification) + { + cupsdSetString(&printer->job_sheets[0], attr->values[0].string.text); + if (attr->num_values > 1) + cupsdSetString(&printer->job_sheets[1], attr->values[1].string.text); + else + cupsdSetString(&printer->job_sheets[1], "none"); + } + if ((attr = ippFindAttribute(con->request, "requesting-user-name-allowed", + IPP_TAG_ZERO)) != NULL) + { + cupsdFreePrinterUsers(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 ++) + cupsdAddPrinterUser(printer, attr->values[i].string.text); + } + else if ((attr = ippFindAttribute(con->request, "requesting-user-name-denied", + IPP_TAG_ZERO)) != NULL) + { + cupsdFreePrinterUsers(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 ++) + cupsdAddPrinterUser(printer, attr->values[i].string.text); + } + if ((attr = ippFindAttribute(con->request, "job-quota-period", + IPP_TAG_INTEGER)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-quota-period to %d...", + attr->values[0].integer); + cupsdFreeQuotas(printer); + printer->quota_period = attr->values[0].integer; + } + if ((attr = ippFindAttribute(con->request, "job-k-limit", + IPP_TAG_INTEGER)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-k-limit to %d...", + attr->values[0].integer); + cupsdFreeQuotas(printer); + printer->k_limit = attr->values[0].integer; + } + if ((attr = ippFindAttribute(con->request, "job-page-limit", + IPP_TAG_INTEGER)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "Setting job-page-limit to %d...", + attr->values[0].integer); + cupsdFreeQuotas(printer); + printer->page_limit = attr->values[0].integer; + } + if ((attr = ippFindAttribute(con->request, "printer-op-policy", + IPP_TAG_NAME)) != NULL) + { + cupsd_policy_t *p; /* Policy */ + + + if ((p = cupsdFindPolicy(attr->values[0].string.text)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Setting printer-op-policy to \"%s\"...", + attr->values[0].string.text); + cupsdSetString(&printer->op_policy, attr->values[0].string.text); + printer->op_policy_ptr = p; + } + else + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Unknown printer-op-policy \"%s\"."), + attr->values[0].string.text); + return; + } + } + if ((attr = ippFindAttribute(con->request, "printer-error-policy", + IPP_TAG_NAME)) != NULL) + { + if (strcmp(attr->values[0].string.text, "abort-job") && + strcmp(attr->values[0].string.text, "retry-job") && + strcmp(attr->values[0].string.text, "stop-printer")) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Unknown printer-error-policy \"%s\"."), + attr->values[0].string.text); + return; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Setting printer-error-policy to \"%s\"...", + attr->values[0].string.text); + cupsdSetString(&printer->error_policy, attr->values[0].string.text); + } + + /* + * See if we have all required attributes... + */ + + if (!printer->device_uri) + cupsdSetString(&printer->device_uri, "file:/dev/null"); + + /* + * See if we have an interface script or PPD file attached to the request... + */ + + if (con->filename) + { + strlcpy(srcfile, con->filename, sizeof(srcfile)); + + if ((fp = cupsFileOpen(srcfile, "rb")) != NULL) + { + /* + * Yes; get the first line from it... + */ + + line[0] = '\0'; + cupsFileGets(fp, line, sizeof(line)); + cupsFileClose(fp); + + /* + * Then see what kind of file it is... + */ + + snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot, + printer->name); + + if (!strncmp(line, "*PPD-Adobe", 10)) + { + /* + * 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)) + { + send_ipp_status(con, IPP_INTERNAL_ERROR, + _("Unable to copy interface script - %s!"), + strerror(errno)); + return; + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Copied interface script successfully!"); + chmod(dstfile, 0755); + } + } + + snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, + printer->name); + + if (!strncmp(line, "*PPD-Adobe", 10)) + { + /* + * 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)) + { + send_ipp_status(con, IPP_INTERNAL_ERROR, + _("Unable to copy PPD file - %s!"), + strerror(errno)); + return; + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "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); + } + } + } + else if ((attr = ippFindAttribute(con->request, "ppd-name", IPP_TAG_NAME)) != NULL) + { + if (!strcmp(attr->values[0].string.text, "raw")) + { + /* + * 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); + } + else + { + /* + * PPD model file... + */ + + snprintf(dstfile, sizeof(dstfile), "%s/interfaces/%s", ServerRoot, + printer->name); + unlink(dstfile); + + snprintf(dstfile, sizeof(dstfile), "%s/ppd/%s.ppd", ServerRoot, + printer->name); + + if (copy_model(con, attr->values[0].string.text, dstfile)) + { + send_ipp_status(con, IPP_INTERNAL_ERROR, _("Unable to copy PPD file!")); + return; + } + else + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Copied PPD file successfully!"); + chmod(dstfile, 0644); + } + } + } + + /* + * Make this printer the default if there is none... + */ + + if (DefaultPrinter == NULL) + DefaultPrinter = printer; + + /* + * Update the printer attributes and return... + */ + + cupsdSetPrinterAttrs(printer); + cupsdSaveAllPrinters(); + + if (printer->job != NULL) + { + cupsd_job_t *job; + + /* + * Stop the current job and then restart it below... + */ + + job = (cupsd_job_t *)printer->job; + + cupsdStopJob(job, 1); + job->state->values[0].integer = IPP_JOB_PENDING; + } + + cupsdCheckJobs(); + + cupsdWritePrintcap(); + + if (modify) + { + cupsdAddEvent(CUPSD_EVENT_PRINTER_MODIFIED, printer, NULL, + "Printer \"%s\" modified by \"%s\".", printer->name, + con->username); + + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" modified by \"%s\".", + printer->name, con->username); + } + else + { + cupsdAddPrinterHistory(printer); + + cupsdAddEvent(CUPSD_EVENT_PRINTER_ADDED, printer, NULL, + "New printer \"%s\" added by \"%s\".", printer->name, + con->username); + + cupsdLogMessage(CUPSD_LOG_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( + cupsd_client_t *con, /* I - Client connection */ + cupsd_printer_t *p) /* I - Printer info */ +{ + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "add_printer_state_reasons(%p[%d], %p[%s])", + con, con->http.fd, p, p->name); + + if (p->num_reasons == 0) + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-state-reasons", NULL, + p->state == IPP_PRINTER_STOPPED ? "paused" : "none"); + else + ippAddStrings(con->response, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-state-reasons", p->num_reasons, NULL, + (const char * const *)p->reasons); +} + + +/* + * 'add_queued_job_count()' - Add the "queued-job-count" attribute for + * the specified printer or class. + */ + +static void +add_queued_job_count( + cupsd_client_t *con, /* I - Client connection */ + cupsd_printer_t *p) /* I - Printer or class */ +{ + int count; /* Number of jobs on destination */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "add_queued_job_count(%p[%d], %p[%s])", + con, con->http.fd, p, p->name); + + count = cupsdGetPrinterJobCount(p->name); + + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "queued-job-count", count); +} + + +/* + * 'authenticate_job()' - Set job authentication info. + */ + +static void +authenticate_job(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Job URI */ +{ + ipp_attribute_t *attr; /* Job-id attribute */ + int jobid; /* Job ID */ + cupsd_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 */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "authenticate_job(%p[%d], %s)", + con, con->http.fd, uri->values[0].string.text); + + /* + * Start with "everything is OK" status... + */ + + con->response->request.status.status_code = IPP_OK; + + /* + * See if we have a job URI or a printer URI... + */ + + if (!strcmp(uri->name, "printer-uri")) + { + /* + * Got a printer URI; see if we also have a job-id attribute... + */ + + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6)) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("Job #%d does not exist!"), jobid); + return; + } + + /* + * See if the job has been completed... + */ + + if (job->state->values[0].integer != IPP_JOB_HELD) + { + /* + * Return a "not-possible" error... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job #%d is not held for authentication!"), + jobid); + return; + } + + /* + * See if we have already authenticated... + */ + + if (!con->username[0]) + { + send_ipp_status(con, IPP_NOT_AUTHORIZED, + _("No authentication information provided!")); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_ipp_status(con, IPP_FORBIDDEN, + _("You are not authorized to authenticate " + "job #%d owned by \"%s\"!"), + jobid, job->username); + return; + } + + /* + * Save the authentication information for this job... + */ + + save_auth_info(con, job); + + /* + * 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) + { + attr->value_tag = IPP_TAG_KEYWORD; + cupsdSetString(&(attr->values[0].string.text), "no-hold"); + } + + /* + * Release the job and return... + */ + + cupsdReleaseJob(job); + + cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was authenticated by \"%s\".", jobid, + con->username); +} + + +/* + * 'cancel_all_jobs()' - Cancel all print jobs. + */ + +static void +cancel_all_jobs(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Job or Printer URI */ +{ + http_status_t status; /* Policy status */ + const char *dest; /* Destination */ + cups_ptype_t dtype; /* Destination type */ + char method[HTTP_MAX_URI], /* Method portion of URI */ + userpass[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 */ + ipp_attribute_t *attr; /* Attribute in request */ + const char *username; /* Username */ + int purge; /* Purge? */ + cupsd_printer_t *printer; /* Printer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_all_jobs(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * See if we have a printer URI... + */ + + if (strcmp(uri->name, "printer-uri")) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("The printer-uri attribute is required!")); + return; + } + + /* + * Get the username (if any) for the jobs we want to cancel (only if + * "my-jobs" is specified... + */ + + if ((attr = ippFindAttribute(con->request, "my-jobs", IPP_TAG_BOOLEAN)) != NULL && + attr->values[0].boolean) + { + if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) + username = attr->values[0].string.text; + else + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Missing requesting-user-name attribute!")); + return; + } + } + else + username = NULL; + + /* + * Look for the "purge-jobs" attribute... + */ + + if ((attr = ippFindAttribute(con->request, "purge-jobs", IPP_TAG_BOOLEAN)) != NULL) + purge = attr->values[0].boolean; + else + purge = 1; + + /* + * And if the destination is valid... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + userpass, sizeof(userpass), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI? + */ + + if (!strncmp(resource, "/printers/", 10) || + !strncmp(resource, "/classes/", 9)) + { + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + else if (strcmp(resource, "/printers/")) + { + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer-uri \"%s\" is not valid."), + uri->values[0].string.text); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Cancel all jobs on all printers... + */ + + cupsdCancelJobs(NULL, username, purge); + + cupsdLogMessage(CUPSD_LOG_INFO, "All jobs were %s by \"%s\".", + purge ? "purged" : "cancelled", con->username); + } + else + { + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Cancel all of the jobs on the named printer... + */ + + cupsdCancelJobs(dest, username, purge); + + cupsdLogMessage(CUPSD_LOG_INFO, "All jobs on \"%s\" were %s by \"%s\".", + dest, purge ? "purged" : "cancelled", con->username); + } + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'cancel_job()' - Cancel a print job. + */ + +static void +cancel_job(cupsd_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 */ + cupsd_job_t *job; /* Job information */ + const char *dest; /* Destination */ + cups_ptype_t dtype; /* Destination type (printer or class) */ + cupsd_printer_t *printer; /* Printer data */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cancel_job(%p[%d], %s)", 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")) + { + /* + * Got a printer URI; see if we also have a job-id attribute... + */ + + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + if ((jobid = attr->values[0].integer) == 0) + { + /* + * Find the current job on the specified printer... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * See if the printer is currently printing a job... + */ + + if (printer->job) + jobid = ((cupsd_job_t *)printer->job)->id; + else + { + /* + * No, see if there are any pending jobs... + */ + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->state->values[0].integer <= IPP_JOB_PROCESSING && + !strcasecmp(job->dest, dest)) + break; + + if (job != NULL) + jobid = job->id; + else + { + send_ipp_status(con, IPP_NOT_POSSIBLE, _("No active jobs on %s!"), + dest); + return; + } + } + } + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6)) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_ipp_status(con, IPP_FORBIDDEN, + _("You are not authorized to delete job #%d " + "owned by \"%s\"!"), + jobid, job->username); + 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) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job #%d is already %s - can\'t cancel."), jobid, + job->state->values[0].integer == IPP_JOB_CANCELLED ? "cancelled" : + job->state->values[0].integer == IPP_JOB_ABORTED ? "aborted" : + "completed"); + return; + } + + /* + * Cancel the job and return... + */ + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job cancelled by \"%s\".", username); + + cupsdCancelJob(job, 0); + cupsdCheckJobs(); + + cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was cancelled by \"%s\".", jobid, + username); + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'cancel_subscription()' - Cancel a subscription. + */ + +static void +cancel_subscription( + cupsd_client_t *con, /* I - Client connection */ + int sub_id) /* I - Subscription ID */ +{ +} + + +/* + * 'check_quotas()' - Check quotas for a printer and user. + */ + +static int /* O - 1 if OK, 0 if not */ +check_quotas(cupsd_client_t *con, /* I - Client connection */ + cupsd_printer_t *p) /* I - Printer or class */ +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* Current attribute */ + char username[33]; /* Username */ + cupsd_quota_t *q; /* Quota data */ + struct passwd *pw; /* User password data */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "check_quotas(%p[%d], %p[%s])", + 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]) + strlcpy(username, con->username, sizeof(username)); + else if (attr != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "check_quotas: requesting-user-name = \"%s\"", + attr->values[0].string.text); + + strlcpy(username, attr->values[0].string.text, sizeof(username)); + } + 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 (cupsdGetPrinterJobCount(p->name) >= MaxJobsPerPrinter) + { + cupsdLogMessage(CUPSD_LOG_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 (cupsdGetUserJobCount(username) >= MaxJobsPerUser) + { + cupsdLogMessage(CUPSD_LOG_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) + { + pw = getpwnam(username); + endpwent(); + + for (i = 0; i < p->num_users; i ++) + if (p->users[i][0] == '@') + { + /* + * Check group membership... + */ + + if (cupsdCheckGroup(username, pw, p->users[i] + 1)) + break; + } + else if (!strcasecmp(username, p->users[i])) + break; + + if ((i < p->num_users) == p->deny_users) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Denying user \"%s\" access to printer \"%s\"...", + username, p->name); + return (0); + } + } + + /* + * Check quotas... + */ + + if (p->k_limit || p->page_limit) + { + if ((q = cupsdUpdateQuota(p, username, 0, 0)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_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)) + { + cupsdLogMessage(CUPSD_LOG_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 ipp_attribute_t * /* O - New attribute */ +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 */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "copy_attribute(%p, %p[%s,%x,%x])", to, attr, + attr->name ? attr->name : "(null)", attr->group_tag, + attr->value_tag); + + switch (attr->value_tag & ~IPP_TAG_COPY) + { + case IPP_TAG_ZERO : + toattr = 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; + + case IPP_TAG_BEGIN_COLLECTION : + toattr = ippAddCollections(to, attr->group_tag, attr->name, + attr->num_values, NULL); + + for (i = 0; i < attr->num_values; i ++) + { + toattr->values[i].collection = ippNew(); + copy_attrs(toattr->values[i].collection, attr->values[i].collection, + NULL, IPP_TAG_ZERO, 0); + } + 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 */ + } + + return (toattr); +} + + +/* + * '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 quickcopy) /* I - Do a quick copy? */ +{ + int i; /* Looping var */ + ipp_attribute_t *fromattr; /* Source attribute */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_attrs(%p, %p, %p, %x)", 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, quickcopy); + } +} + + +/* + * '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(cupsd_client_t *con, /* I - Client connection */ + cupsd_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 */ + cupsd_banner_t *banner; /* Pointer to banner */ + cups_file_t *in; /* Input file */ + cups_file_t *out; /* Output file */ + int ch; /* Character from file */ + char attrname[255], /* Name of attribute */ + *s; /* Pointer into name */ + ipp_attribute_t *attr; /* Attribute */ + + + cupsdLogMessage(CUPSD_LOG_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 = cupsdFindBanner(name)) == NULL) + return (0); + + /* + * Open the banner and job files... + */ + + if (add_file(con, job, banner->filetype, 0)) + return (0); + + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, + job->num_files); + if ((out = cupsFileOpen(filename, "w")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "copy_banner: Unable to create banner job file %s - %s", + filename, strerror(errno)); + job->num_files --; + return (0); + } + + fchmod(cupsFileNumber(out), 0640); + fchown(cupsFileNumber(out), RunUser, Group); + + /* + * Try the localized banner file under the subdirectory... + */ + + strlcpy(attrname, con->request->attrs->next->values[0].string.text, + sizeof(attrname)); + if (strlen(attrname) > 2 && attrname[2] == '-') + { + /* + * Convert ll-cc to ll_CC... + */ + + attrname[2] = '_'; + attrname[3] = toupper(attrname[3] & 255); + attrname[4] = toupper(attrname[4] & 255); + } + + snprintf(filename, sizeof(filename), "%s/banners/%s/%s", DataDir, + attrname, name); + + if (access(filename, 0) && strlen(attrname) > 2) + { + /* + * Wasn't able to find "ll_CC" locale file; try the non-national + * localization banner directory. + */ + + 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); + } + + if ((in = cupsFileOpen(filename, "r")) == NULL) + { + cupsFileClose(out); + unlink(filename); + cupsdLogMessage(CUPSD_LOG_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 = cupsFileGetChar(in)) != EOF) + if (ch == '{') + { + /* + * Get an attribute name... + */ + + for (s = attrname; (ch = cupsFileGetChar(in)) != EOF;) + if (!isalpha(ch & 255) && 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... + */ + + cupsFilePrintf(out, "{%s%c", attrname, ch); + continue; + } + + /* + * See if it is defined... + */ + + if (attrname[0] == '?') + s = attrname + 1; + else + s = attrname; + + if (strcmp(s, "printer-name") == 0) + { + cupsFilePuts(out, job->dest); + 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... + */ + + cupsFilePrintf(out, "{%s}", attrname); + } + + continue; + } + + /* + * Output value(s)... + */ + + for (i = 0; i < attr->num_values; i ++) + { + if (i) + cupsFilePutChar(out, ','); + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + if (strncmp(s, "time-at-", 8) == 0) + cupsFilePuts(out, cupsdGetDateTime(attr->values[i].integer)); + else + cupsFilePrintf(out, "%d", attr->values[i].integer); + break; + + case IPP_TAG_BOOLEAN : + cupsFilePrintf(out, "%d", attr->values[i].boolean); + break; + + case IPP_TAG_NOVALUE : + cupsFilePuts(out, "novalue"); + break; + + case IPP_TAG_RANGE : + cupsFilePrintf(out, "%d-%d", attr->values[i].range.lower, + attr->values[i].range.upper); + break; + + case IPP_TAG_RESOLUTION : + cupsFilePrintf(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 == '\\') + { + cupsFilePutChar(out, '\\'); + cupsFilePutChar(out, *p); + } + else if (*p < 32 || *p > 126) + cupsFilePrintf(out, "\\%03o", *p & 255); + else + cupsFilePutChar(out, *p); + } + } + else + cupsFilePuts(out, attr->values[i].string.text); + break; + + default : + break; /* anti-compiler-warning-code */ + } + } + } + else if (ch == '\\') /* Quoted char */ + { + ch = cupsFileGetChar(in); + + if (ch != '{') /* Only do special handling for \{ */ + cupsFilePutChar(out, '\\'); + + cupsFilePutChar(out, ch); + } + else + cupsFilePutChar(out, ch); + + cupsFileClose(in); + + kbytes = (cupsFileTell(out) + 1023) / 1024; + + if ((attr = ippFindAttribute(job->attrs, "job-k-octets", IPP_TAG_INTEGER)) != NULL) + attr->values[0].integer += kbytes; + + cupsFileClose(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 */ +{ + cups_file_t *src, /* Source file */ + *dst; /* Destination file */ + int bytes; /* Bytes to read/write */ + char buffer[2048]; /* Copy buffer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "copy_file(\"%s\", \"%s\")", from, to); + + /* + * Open the source and destination file for a copy... + */ + + if ((src = cupsFileOpen(from, "rb")) == NULL) + return (-1); + + if ((dst = cupsFileOpen(to, "wb")) == NULL) + { + cupsFileClose(src); + return (-1); + } + + /* + * Copy the source file to the destination... + */ + + while ((bytes = cupsFileRead(src, buffer, sizeof(buffer))) > 0) + if (cupsFileWrite(dst, buffer, bytes) < bytes) + { + cupsFileClose(src); + cupsFileClose(dst); + return (-1); + } + + /* + * Close both files and return... + */ + + cupsFileClose(src); + + return (cupsFileClose(dst)); +} + + +/* + * 'copy_model()' - Copy a PPD model file, substituting default values + * as needed... + */ + +static int /* O - 0 = success, -1 = error */ +copy_model(cupsd_client_t *con, /* I - Client connection */ + const char *from, /* I - Source file */ + const char *to) /* I - Destination file */ +{ + fd_set *input; /* select() input set */ + struct timeval timeout; /* select() timeout */ + int maxfd; /* Maximum file descriptor for select() */ + char tempfile[1024]; /* Temporary PPD file */ + int tempfd; /* Temporary PPD file descriptor */ + int temppid; /* Process ID of cups-driverd */ + int temppipe[2]; /* Temporary pipes */ + char *argv[4], /* Command-line arguments */ + *envp[100]; /* Environment */ + cups_file_t *src, /* Source file */ + *dst; /* Destination file */ + int bytes, /* Bytes from pipe */ + total; /* Total bytes from pipe */ + char buffer[2048], /* Copy buffer */ + *ptr; /* Pointer into buffer */ + int i; /* Looping var */ + char option[PPD_MAX_NAME], /* Option name */ + choice[PPD_MAX_NAME]; /* Choice name */ + int num_defaults; /* Number of default options */ + ppd_default_t *defaults; /* Default options */ + char cups_protocol[PPD_MAX_LINE]; + /* cupsProtocol attribute */ + int have_letter, /* Have Letter size */ + have_a4; /* Have A4 size */ +#ifdef HAVE_LIBPAPER + char *paper_result; /* Paper size name from libpaper */ + char system_paper[64]; /* Paper size name buffer */ +#endif /* HAVE_LIBPAPER */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "copy_model(con=%p, from=\"%s\", to=\"%s\")", + con, from, to); + + /* + * Run cups-driverd to get the PPD file... + */ + + argv[0] = "cups-driverd"; + argv[1] = "cat"; + argv[2] = (char *)from; + argv[3] = NULL; + + cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0]))); + + snprintf(buffer, sizeof(buffer), "%s/daemon/cups-driverd", ServerBin); + snprintf(tempfile, sizeof(tempfile), "%s/%d.ppd", TempDir, con->http.fd); + tempfd = open(tempfile, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (tempfd < 0) + return (-1); + + cupsdOpenPipe(temppipe); + + if ((input = calloc(1, SetSize)) == NULL) + { + close(tempfd); + unlink(tempfile); + + cupsdLogMessage(CUPSD_LOG_ERROR, + "copy_model: Unable to allocate %d bytes for select()...", + SetSize); + return (-1); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "copy_model: Running \"cups-driverd cat %s\"...", from); + + if (!cupsdStartProcess(buffer, argv, envp, -1, temppipe[1], CGIPipes[1], + -1, 0, &temppid)) + { + close(tempfd); + unlink(tempfile); + return (-1); + } + + close(temppipe[1]); + + /* + * Wait up to 30 seconds for the PPD file to be copied... + */ + + total = 0; + + if (temppipe[0] > CGIPipes[0]) + maxfd = temppipe[0] + 1; + else + maxfd = CGIPipes[0] + 1; + + for (;;) + { + /* + * See if we have data ready... + */ + + bytes = 0; + + FD_SET(temppipe[0], input); + FD_SET(CGIPipes[0], input); + + timeout.tv_sec = 30; + timeout.tv_usec = 0; + + if ((i = select(maxfd, input, NULL, NULL, &timeout)) < 0) + { + if (errno == EINTR) + continue; + else + break; + } + else if (i == 0) + { + /* + * We have timed out... + */ + + break; + } + + if (FD_ISSET(temppipe[0], input)) + { + /* + * Read the PPD file from the pipe, and write it to the PPD file. + */ + + if ((bytes = read(temppipe[0], buffer, sizeof(buffer))) > 0) + { + if (write(tempfd, buffer, bytes) < bytes) + break; + + total += bytes; + } + else + break; + } + + if (FD_ISSET(CGIPipes[0], input)) + cupsdUpdateCGI(); + } + + close(temppipe[0]); + close(tempfd); + + if (!total) + { + /* + * No data from cups-deviced... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, "copy_model: empty PPD file!"); + unlink(tempfile); + return (-1); + } + + /* + * Read the source file and see what page sizes are supported... + */ + + if ((src = cupsFileOpen(tempfile, "rb")) == NULL) + { + unlink(tempfile); + return (-1); + } + + have_letter = 0; + have_a4 = 0; + + while (cupsFileGets(src, buffer, sizeof(buffer)) != NULL) + if (!strncmp(buffer, "*PageSize ", 10)) + { + /* + * Strip UI text and command data from the end of the line... + */ + + if ((ptr = strchr(buffer + 10, '/')) != NULL) + *ptr = '\0'; + if ((ptr = strchr(buffer + 10, ':')) != NULL) + *ptr = '\0'; + + for (ptr = buffer + 10; isspace(*ptr); ptr ++); + + /* + * Look for Letter and A4 page sizes... + */ + + if (!strcmp(ptr, "Letter")) + have_letter = 1; + + if (!strcmp(ptr, "A4")) + have_a4 = 1; + } + + cupsFileRewind(src); + + /* + * Open the destination (if possible) and set the default options... + */ + + num_defaults = 0; + defaults = NULL; + cups_protocol[0] = '\0'; + + if ((dst = cupsFileOpen(to, "rb")) != NULL) + { + /* + * Read all of the default lines from the old PPD... + */ + + while (cupsFileGets(dst, buffer, sizeof(buffer)) != NULL) + if (!strncmp(buffer, "*Default", 8)) + { + /* + * Add the default option... + */ + + if (!ppd_parse_line(buffer, option, sizeof(option), + choice, sizeof(choice))) + num_defaults = ppd_add_default(option, choice, num_defaults, + &defaults); + } + else if (!strncmp(buffer, "*cupsProtocol:", 14)) + strlcpy(cups_protocol, buffer, sizeof(cups_protocol)); + + cupsFileClose(dst); + } +#ifdef HAVE_LIBPAPER + else if ((paper_result = systempapername()) != NULL) + { + /* + * Set the default media sizes from the systemwide default... + */ + + strlcpy(system_paper, paper_result, sizeof(system_paper)); + system_paper[0] = toupper(system_paper[0] & 255); + + if ((!strcmp(system_paper, "Letter") && have_letter) || + (!strcmp(system_paper, "A4") && have_a4)) + { + num_defaults = ppd_add_default("PageSize", system_paper, + num_defaults, &defaults); + num_defaults = ppd_add_default("PageRegion", system_paper, + num_defaults, &defaults); + num_defaults = ppd_add_default("PaperDimension", system_paper, + num_defaults, &defaults); + num_defaults = ppd_add_default("ImageableArea", system_paper, + num_defaults, &defaults); + } + } +#endif /* HAVE_LIBPAPER */ + else + { + /* + * Add the default media sizes... + * + * Note: These values are generally not valid for large-format devices + * like plotters, however it is probably safe to say that those + * users will configure the media size after initially adding + * the device anyways... + */ + + if (!DefaultLanguage || + !strcasecmp(DefaultLanguage, "C") || + !strcasecmp(DefaultLanguage, "POSIX") || + !strcasecmp(DefaultLanguage, "en") || + !strncasecmp(DefaultLanguage, "en_US", 5) || + !strncasecmp(DefaultLanguage, "en_CA", 5) || + !strncasecmp(DefaultLanguage, "fr_CA", 5)) + { + /* + * These are the only locales that will default to "letter" size... + */ + + if (have_letter) + { + num_defaults = ppd_add_default("PageSize", "Letter", num_defaults, + &defaults); + num_defaults = ppd_add_default("PageRegion", "Letter", num_defaults, + &defaults); + num_defaults = ppd_add_default("PaperDimension", "Letter", num_defaults, + &defaults); + num_defaults = ppd_add_default("ImageableArea", "Letter", num_defaults, + &defaults); + } + } + else if (have_a4) + { + /* + * The rest default to "a4" size... + */ + + num_defaults = ppd_add_default("PageSize", "A4", num_defaults, + &defaults); + num_defaults = ppd_add_default("PageRegion", "A4", num_defaults, + &defaults); + num_defaults = ppd_add_default("PaperDimension", "A4", num_defaults, + &defaults); + num_defaults = ppd_add_default("ImageableArea", "A4", num_defaults, + &defaults); + } + } + + /* + * Open the destination file for a copy... + */ + + if ((dst = cupsFileOpen(to, "wb")) == NULL) + { + if (num_defaults > 0) + free(defaults); + + cupsFileClose(src); + unlink(tempfile); + return (-1); + } + + /* + * Copy the source file to the destination... + */ + + while (cupsFileGets(src, buffer, sizeof(buffer)) != NULL) + { + if (!strncmp(buffer, "*Default", 8)) + { + /* + * Check for an previous default option choice... + */ + + if (!ppd_parse_line(buffer, option, sizeof(option), + choice, sizeof(choice))) + { + for (i = 0; i < num_defaults; i ++) + if (!strcmp(option, defaults[i].option)) + { + /* + * Substitute the previous choice... + */ + + snprintf(buffer, sizeof(buffer), "*Default%s: %s", option, + defaults[i].choice); + break; + } + } + } + + cupsFilePrintf(dst, "%s\n", buffer); + } + + if (cups_protocol[0]) + cupsFilePrintf(dst, "%s\n", cups_protocol); + + if (num_defaults > 0) + free(defaults); + + /* + * Close both files and return... + */ + + cupsFileClose(src); + + unlink(tempfile); + + return (cupsFileClose(dst)); +} + + +/* + * 'copy_subscription_attrs()' - Copy subscription attributes. + */ + +static void +copy_subscription_attrs( + cupsd_client_t *con, /* I - Client connection */ + cupsd_subscription_t *sub, /* I - Subscription */ + cups_array_t *ra) /* I - Requested attributes array */ +{ + ipp_attribute_t *attr; /* Current attribute */ + char printer_uri[HTTP_MAX_URI]; + /* Printer URI */ + int count; /* Number of events */ + unsigned mask; /* Current event mask */ + const char *name; /* Current event name */ + + + /* + * Copy the subscription attributes to the response using the + * requested-attributes attribute that may be provided by the client. + */ + + if (!ra || cupsArrayFind(ra, "notify-subscription-id")) + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-subscription-id", sub->id); + + if (!ra || cupsArrayFind(ra, "notify-events")) + { + if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL) + { + /* + * Simple event list... + */ + + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, + IPP_TAG_KEYWORD | IPP_TAG_COPY, + "notify-events", NULL, name); + } + else + { + /* + * Complex event list... + */ + + for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) + if (sub->mask & mask) + count ++; + + attr = ippAddStrings(con->response, IPP_TAG_SUBSCRIPTION, + IPP_TAG_KEYWORD | IPP_TAG_COPY, + "notify-events", count, NULL, NULL); + + for (mask = 1, count = 0; mask < CUPSD_EVENT_ALL; mask <<= 1) + if (sub->mask & mask) + { + attr->values[count].string.text = + (char *)cupsdEventName((cupsd_eventmask_t)mask); + + count ++; + } + } + } + + if (!ra || cupsArrayFind(ra, "notify-subscriber-user-name")) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_NAME, + "notify-subscriber-user-name", NULL, sub->owner); + + if (sub->recipient && (!ra || cupsArrayFind(ra, "notify-recipient-uri"))) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, + "notify-recipient-uri", NULL, sub->recipient); + else if (!ra || cupsArrayFind(ra, "notify-pull-method")) + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_KEYWORD, + "notify-pull-method", NULL, "ippget"); + + if (sub->user_data_len > 0 && (!ra || cupsArrayFind(ra, "notify-user-data"))) + ippAddOctetString(con->response, IPP_TAG_SUBSCRIPTION, "notify-user-data", + sub->user_data, sub->user_data_len); + + if (!sub->job && (!ra || cupsArrayFind(ra, "notify-lease-duration"))) + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-lease-duration", sub->lease); + + if (!ra || cupsArrayFind(ra, "notify-time-interval")) + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-time-interval", sub->interval); + + if (sub->dest && (!ra || cupsArrayFind(ra, "notify-printer-uri"))) + { + httpAssembleURIf(printer_uri, sizeof(printer_uri), "ipp", NULL, + con->servername, con->serverport, "/printers/%s", + sub->dest->name); + ippAddString(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_URI, + "notify-printer-uri", NULL, printer_uri); + } + + if (sub->job && (!ra || cupsArrayFind(ra, "notify-job-id"))) + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-job-id", sub->job->id); +} + + +/* + * 'create_job()' - Print a file to a printer or class. + */ + +static void +create_job(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_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 */ + cupsd_printer_t *printer; /* Printer data */ + int kbytes; /* Size of print file */ + int i; /* Looping var */ + int lowerpagerange; /* Page range bound */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "create_job(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check remote printing to non-shared printer... + */ + + if (!printer->shared && + strcasecmp(con->http.hostname, "localhost") && + strcasecmp(con->http.hostname, ServerName)) + { + send_ipp_status(con, IPP_NOT_AUTHORIZED, + _("The printer or class is not shared!")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + else if ((printer->type & CUPS_PRINTER_AUTHENTICATED) && !con->username[0]) + { + send_http_error(con, HTTP_UNAUTHORIZED); + return; + } + + /* + * See if the printer is accepting jobs... + */ + + if (!printer->accepting) + { + send_ipp_status(con, IPP_NOT_ACCEPTING, + _("Destination \"%s\" is not accepting jobs."), + dest); + return; + } + + /* + * Validate job template attributes; for now just copies and page-ranges... + */ + + if ((attr = ippFindAttribute(con->request, "copies", IPP_TAG_INTEGER)) != NULL) + { + if (attr->values[0].integer < 1 || attr->values[0].integer > MaxCopies) + { + send_ipp_status(con, IPP_ATTRIBUTES, _("Bad copies value %d."), + attr->values[0].integer); + ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, + "copies", attr->values[0].integer); + return; + } + } + + if ((attr = ippFindAttribute(con->request, "page-ranges", IPP_TAG_RANGE)) != NULL) + { + for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++) + { + if (attr->values[i].range.lower < lowerpagerange || + attr->values[i].range.lower > attr->values[i].range.upper) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad page-ranges values %d-%d."), + attr->values[i].range.lower, + attr->values[i].range.upper); + return; + } + + lowerpagerange = attr->values[i].range.upper + 1; + } + } + + /* + * Make sure we aren't over our limit... + */ + + if (cupsArrayCount(Jobs) >= MaxJobs && MaxJobs) + cupsdCleanJobs(); + + if (cupsArrayCount(Jobs) >= MaxJobs && MaxJobs) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Too many active jobs.")); + return; + } + + if (!check_quotas(con, printer)) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached.")); + 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 = cupsdAddJob(priority, printer->name)) == NULL) + { + send_ipp_status(con, IPP_INTERNAL_ERROR, + _("Unable to add job for destination \"%s\"!"), dest); + return; + } + + job->dtype = dtype; + job->attrs = con->request; + con->request = NULL; + + attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME); + + if (con->username[0]) + { + cupsdSetString(&job->username, con->username); + + if (attr) + cupsdSetString(&attr->values[0].string.text, con->username); + + save_auth_info(con, job); + } + else if (attr != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "create_job: requesting-user-name = \"%s\"", + attr->values[0].string.text); + + cupsdSetString(&job->username, attr->values[0].string.text); + } + else + cupsdSetString(&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; + cupsdSetString(&attr->name, "job-originating-user-name"); + } + + if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name", + IPP_TAG_ZERO)) != NULL) + { + /* + * Request contains a job-originating-host-name attribute; validate it... + */ + + if (attr->value_tag != IPP_TAG_NAME || + attr->num_values != 1 || + strcmp(con->http.hostname, "localhost") != 0) + { + /* + * Can't override the value if we aren't connected via localhost. + * Also, we can only have 1 value and it must be a name value. + */ + + switch (attr->value_tag) + { + case IPP_TAG_STRING : + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + 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 : + /* + * Free old strings... + */ + + for (i = 0; i < attr->num_values; i ++) + { + free(attr->values[i].string.text); + attr->values[i].string.text = NULL; + if (attr->values[i].string.charset) + { + free(attr->values[i].string.charset); + attr->values[i].string.charset = NULL; + } + } + + default : + break; + } + + /* + * Use the default connection hostname instead... + */ + + attr->value_tag = IPP_TAG_NAME; + attr->num_values = 1; + attr->values[0].string.text = strdup(con->http.hostname); + } + + attr->group_tag = IPP_TAG_JOB; + } + else + { + /* + * No job-originating-host-name attribute, so use the hostname from + * the connection... + */ + + 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... + */ + + cupsdSetJobHoldUntil(job, 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 | CUPS_PRINTER_IMPLICIT)) || + Classification) + { + /* + * Add job sheets options... + */ + + if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_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) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Classification=\"%s\", ClassifyOverride=%d", + Classification ? Classification : "(null)", + ClassifyOverride); + + if (ClassifyOverride) + { + if (!strcmp(attr->values[0].string.text, "none") && + (attr->num_values == 1 || + !strcmp(attr->values[1].string.text, "none"))) + { + /* + * Force the leading banner to have the classification on it... + */ + + cupsdSetString(&attr->values[0].string.text, Classification); + + cupsdLogMessage(CUPSD_LOG_NOTICE, "[Job %d] CLASSIFICATION FORCED " + "job-sheets=\"%s,none\", " + "job-originating-user-name=\"%s\"", + job->id, Classification, job->username); + } + 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! + */ + + cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text); + + cupsdLogMessage(CUPSD_LOG_NOTICE, "[Job %d] CLASSIFICATION FORCED " + "job-sheets=\"%s,%s\", " + "job-originating-user-name=\"%s\"", + job->id, attr->values[0].string.text, + attr->values[1].string.text, job->username); + } + else if (strcmp(attr->values[0].string.text, Classification) && + strcmp(attr->values[0].string.text, "none") && + (attr->num_values == 1 || + (strcmp(attr->values[1].string.text, Classification) && + strcmp(attr->values[1].string.text, "none")))) + { + if (attr->num_values == 1) + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION OVERRIDDEN " + "job-sheets=\"%s\", " + "job-originating-user-name=\"%s\"", + job->id, attr->values[0].string.text, job->username); + else + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION OVERRIDDEN " + "job-sheets=\"%s,%s\",fffff " + "job-originating-user-name=\"%s\"", + job->id, attr->values[0].string.text, + attr->values[1].string.text, job->username); + } + } + else if (strcmp(attr->values[0].string.text, Classification) != 0 && + (attr->num_values == 1 || + strcmp(attr->values[1].string.text, Classification) != 0)) + { + /* + * Force the banner to have the classification on it... + */ + + if (attr->num_values > 1 && + !strcmp(attr->values[0].string.text, attr->values[1].string.text)) + { + cupsdSetString(&(attr->values[0].string.text), Classification); + cupsdSetString(&(attr->values[1].string.text), Classification); + } + else + { + if (attr->num_values == 1 || + strcmp(attr->values[0].string.text, "none")) + cupsdSetString(&(attr->values[0].string.text), Classification); + + if (attr->num_values > 1 && + strcmp(attr->values[1].string.text, "none")) + cupsdSetString(&(attr->values[1].string.text), Classification); + } + + if (attr->num_values > 1) + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION FORCED " + "job-sheets=\"%s,%s\", " + "job-originating-user-name=\"%s\"", + job->id, attr->values[0].string.text, + attr->values[1].string.text, job->username); + else + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION FORCED " + "job-sheets=\"%s\", " + "job-originating-user-name=\"%s\"", + job->id, Classification, job->username); + } + } + + /* + * See if we need to add the starting sheet... + */ + + if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Adding start banner page \"%s\" to job %d.", + attr->values[0].string.text, job->id); + + kbytes = copy_banner(con, job, attr->values[0].string.text); + + cupsdUpdateQuota(printer, job->username, 0, kbytes); + } + } + else if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL) + job->sheets = attr; + + /* + * Fill in the response info... + */ + + snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName, + LocalPort, 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; + + /* + * Add any job subscriptions... + */ + + add_job_subscriptions(con, job); + + /* + * Set all but the first two attributes to the job attributes group... + */ + + for (attr = job->attrs->attrs->next->next; attr; attr = attr->next) + attr->group_tag = IPP_TAG_JOB; + + /* + * Save and log the job... + */ + + cupsdSaveJob(job); + + cupsdLogMessage(CUPSD_LOG_INFO, "Job %d created on \"%s\" by \"%s\".", + job->id, job->dest, job->username); + + cupsdAddEvent(CUPSD_EVENT_JOB_CREATED, printer, job, "Job created."); +} + + +/* + * 'create_requested_array()' - Create an array for the requested-attributes. + */ + +static cups_array_t * /* O - Array of attributes or NULL */ +create_requested_array(ipp_t *request) /* I - IPP request */ +{ + int i; /* Looping var */ + ipp_attribute_t *requested; /* requested-attributes attribute */ + cups_array_t *ra; /* Requested attributes array */ + char *value; /* Current value */ + + + /* + * Get the requested-attributes attribute, and return NULL if we don't + * have one... + */ + + if ((requested = ippFindAttribute(request, "requested-attributes", + IPP_TAG_KEYWORD)) == NULL) + return (NULL); + + /* + * If the attribute contains a single "all" keyword, return NULL... + */ + + if (requested->num_values == 1 && + !strcmp(requested->values[0].string.text, "all")) + return (NULL); + + /* + * Create an array using "strcmp" as the comparison function... + */ + + ra = cupsArrayNew((cups_array_func_t)strcmp, NULL); + + for (i = 0; i < requested->num_values; i ++) + { + value = requested->values[i].string.text; + + if (!strcmp(value, "job-template")) + { + cupsArrayAdd(ra, "copies"); + cupsArrayAdd(ra, "copies-default"); + cupsArrayAdd(ra, "copies-supported"); + cupsArrayAdd(ra, "finishings"); + cupsArrayAdd(ra, "finishings-default"); + cupsArrayAdd(ra, "finishings-supported"); + cupsArrayAdd(ra, "job-hold-until"); + cupsArrayAdd(ra, "job-hold-until-default"); + cupsArrayAdd(ra, "job-hold-until-supported"); + cupsArrayAdd(ra, "job-priority"); + cupsArrayAdd(ra, "job-priority-default"); + cupsArrayAdd(ra, "job-priority-supported"); + cupsArrayAdd(ra, "job-sheets"); + cupsArrayAdd(ra, "job-sheets-default"); + cupsArrayAdd(ra, "job-sheets-supported"); + cupsArrayAdd(ra, "media"); + cupsArrayAdd(ra, "media-default"); + cupsArrayAdd(ra, "media-supported"); + cupsArrayAdd(ra, "multiple-document-handling"); + cupsArrayAdd(ra, "multiple-document-handling-default"); + cupsArrayAdd(ra, "multiple-document-handling-supported"); + cupsArrayAdd(ra, "number-up"); + cupsArrayAdd(ra, "number-up-default"); + cupsArrayAdd(ra, "number-up-supported"); + cupsArrayAdd(ra, "orientation-requested"); + cupsArrayAdd(ra, "orientation-requested-default"); + cupsArrayAdd(ra, "orientation-requested-supported"); + cupsArrayAdd(ra, "page-ranges"); + cupsArrayAdd(ra, "page-ranges-supported"); + cupsArrayAdd(ra, "printer-resolution"); + cupsArrayAdd(ra, "printer-resolution-default"); + cupsArrayAdd(ra, "printer-resolution-supported"); + cupsArrayAdd(ra, "print-quality"); + cupsArrayAdd(ra, "print-quality-default"); + cupsArrayAdd(ra, "print-quality-supported"); + cupsArrayAdd(ra, "sides"); + cupsArrayAdd(ra, "sides-default"); + cupsArrayAdd(ra, "sides-supported"); + } + else if (!strcmp(value, "job-description")) + { + cupsArrayAdd(ra, "date-time-at-completed"); + cupsArrayAdd(ra, "date-time-at-creation"); + cupsArrayAdd(ra, "date-time-at-processing"); + cupsArrayAdd(ra, "job-detailed-status-message"); + cupsArrayAdd(ra, "job-document-access-errors"); + cupsArrayAdd(ra, "job-id"); + cupsArrayAdd(ra, "job-impressions"); + cupsArrayAdd(ra, "job-impressions-completed"); + cupsArrayAdd(ra, "job-k-octets"); + cupsArrayAdd(ra, "job-k-octets-processed"); + cupsArrayAdd(ra, "job-media-sheets"); + cupsArrayAdd(ra, "job-media-sheets-completed"); + cupsArrayAdd(ra, "job-message-from-operator"); + cupsArrayAdd(ra, "job-more-info"); + cupsArrayAdd(ra, "job-name"); + cupsArrayAdd(ra, "job-originating-user-name"); + cupsArrayAdd(ra, "job-printer-up-time"); + cupsArrayAdd(ra, "job-printer-uri"); + cupsArrayAdd(ra, "job-state"); + cupsArrayAdd(ra, "job-state-message"); + cupsArrayAdd(ra, "job-state-reasons"); + cupsArrayAdd(ra, "job-uri"); + cupsArrayAdd(ra, "number-of-documents"); + cupsArrayAdd(ra, "number-of-intervening-jobs"); + cupsArrayAdd(ra, "output-device-assigned"); + cupsArrayAdd(ra, "time-at-completed"); + cupsArrayAdd(ra, "time-at-creation"); + cupsArrayAdd(ra, "time-at-processing"); + } + else if (!strcmp(value, "printer-description")) + { + cupsArrayAdd(ra, "charset-configured"); + cupsArrayAdd(ra, "charset-supported"); + cupsArrayAdd(ra, "color-supported"); + cupsArrayAdd(ra, "compression-supported"); + cupsArrayAdd(ra, "document-format-default"); + cupsArrayAdd(ra, "document-format-supported"); + cupsArrayAdd(ra, "generated-natural-language-supported"); + cupsArrayAdd(ra, "ipp-versions-supported"); + cupsArrayAdd(ra, "job-impressions-supported"); + cupsArrayAdd(ra, "job-k-octets-supported"); + cupsArrayAdd(ra, "job-media-sheets-supported"); + cupsArrayAdd(ra, "multiple-document-jobs-supported"); + cupsArrayAdd(ra, "multiple-operation-time-out"); + cupsArrayAdd(ra, "natural-language-configured"); + cupsArrayAdd(ra, "notify-attributes-supported"); + cupsArrayAdd(ra, "notify-lease-duration-default"); + cupsArrayAdd(ra, "notify-lease-duration-supported"); + cupsArrayAdd(ra, "notify-max-events-supported"); + cupsArrayAdd(ra, "notify-notify-events-default"); + cupsArrayAdd(ra, "notify-notify-events-supported"); + cupsArrayAdd(ra, "notify-pull-method-supported"); + cupsArrayAdd(ra, "notify-schemes-supported"); + cupsArrayAdd(ra, "operations-supported"); + cupsArrayAdd(ra, "pages-per-minute"); + cupsArrayAdd(ra, "pages-per-minute-color"); + cupsArrayAdd(ra, "pdl-override-supported"); + cupsArrayAdd(ra, "printer-current-time"); + cupsArrayAdd(ra, "printer-driver-installer"); + cupsArrayAdd(ra, "printer-info"); + cupsArrayAdd(ra, "printer-is-accepting-jobs"); + cupsArrayAdd(ra, "printer-location"); + cupsArrayAdd(ra, "printer-make-and-model"); + cupsArrayAdd(ra, "printer-message-from-operator"); + cupsArrayAdd(ra, "printer-more-info"); + cupsArrayAdd(ra, "printer-more-info-manufacturer"); + cupsArrayAdd(ra, "printer-name"); + cupsArrayAdd(ra, "printer-state"); + cupsArrayAdd(ra, "printer-state-message"); + cupsArrayAdd(ra, "printer-state-reasons"); + cupsArrayAdd(ra, "printer-up-time"); + cupsArrayAdd(ra, "printer-uri-supported"); + cupsArrayAdd(ra, "queued-job-count"); + cupsArrayAdd(ra, "reference-uri-schemes-supported"); + cupsArrayAdd(ra, "uri-authentication-supported"); + cupsArrayAdd(ra, "uri-security-supported"); + } + else if (!strcmp(value, "subscription-template")) + { + cupsArrayAdd(ra, "notify-attributes"); + cupsArrayAdd(ra, "notify-charset"); + cupsArrayAdd(ra, "notify-events"); + cupsArrayAdd(ra, "notify-lease-duration"); + cupsArrayAdd(ra, "notify-natural-language"); + cupsArrayAdd(ra, "notify-pull-method"); + cupsArrayAdd(ra, "notify-recipient-uri"); + cupsArrayAdd(ra, "notify-time-interval"); + cupsArrayAdd(ra, "notify-user-data"); + } + else + cupsArrayAdd(ra, value); + } + + return (ra); +} + + +/* + * 'create_subscription()' - Create a notification subscription. + */ + +static void +create_subscription( + cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + int i; /* Looping var */ + ipp_attribute_t *attr; /* Current attribute */ + const char *dest; /* Destination */ + cups_ptype_t dtype; /* Destination type (printer or class) */ + char method[HTTP_MAX_URI], + /* Method portion of URI */ + userpass[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 */ + cupsd_printer_t *printer; /* Printer/class */ + cupsd_job_t *job; /* Job */ + int jobid; /* Job ID */ + cupsd_subscription_t *sub; /* Subscription object */ + const char *username, /* requesting-user-name or authenticated username */ + *recipient, /* notify-recipient-uri */ + *pullmethod; /* notify-pull-method */ + ipp_attribute_t *user_data; /* notify-user-data */ + int interval, /* notify-time-interval */ + lease; /* notify-lease-duration */ + unsigned mask; /* notify-events */ + + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + userpass, sizeof(userpass), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (!strcmp(resource, "/")) + { + dest = NULL; + dtype = (cups_ptype_t)0; + printer = NULL; + } + else if (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10) + { + dest = NULL; + dtype = (cups_ptype_t)0; + printer = NULL; + } + else if (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9) + { + dest = NULL; + dtype = CUPS_PRINTER_CLASS; + printer = NULL; + } + else if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if (printer) + { + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + } + else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Get the user that is requesting the subscription... + */ + + if (con->username[0]) + username = con->username; + else if ((attr = ippFindAttribute(con->request, "requesting-user-name", + IPP_TAG_NAME)) != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "create_subscription: requesting-user-name = \"%s\"", + attr->values[0].string.text); + + username = attr->values[0].string.text; + } + else + username = "anonymous"; + + /* + * Find the first subscription group attribute; return if we have + * none... + */ + + for (attr = con->request->attrs; attr; attr = attr->next) + if (attr->group_tag == IPP_TAG_SUBSCRIPTION) + break; + + if (!attr) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("No subscription attributes in request!")); + return; + } + + /* + * Process the subscription attributes in the request... + */ + + while (attr) + { + recipient = NULL; + pullmethod = NULL; + user_data = NULL; + interval = 0; + lease = DefaultLeaseDuration; + jobid = 0; + mask = CUPSD_EVENT_NONE; + + while (attr && attr->group_tag != IPP_TAG_ZERO) + { + if (!strcmp(attr->name, "notify-recipient") && + attr->value_tag == IPP_TAG_URI) + recipient = attr->values[0].string.text; + else if (!strcmp(attr->name, "notify-pull-method") && + attr->value_tag == IPP_TAG_KEYWORD) + pullmethod = attr->values[0].string.text; + else if (!strcmp(attr->name, "notify-charset") && + attr->value_tag == IPP_TAG_CHARSET && + strcmp(attr->values[0].string.text, "us-ascii") && + strcmp(attr->values[0].string.text, "utf-8")) + { + send_ipp_status(con, IPP_CHARSET, + _("Character set \"%s\" not supported!"), + attr->values[0].string.text); + return; + } + else if (!strcmp(attr->name, "notify-natural-language") && + (attr->value_tag != IPP_TAG_LANGUAGE || + strcmp(attr->values[0].string.text, DefaultLanguage))) + { + send_ipp_status(con, IPP_CHARSET, + _("Language \"%s\" not supported!"), + attr->values[0].string.text); + return; + } + else if (!strcmp(attr->name, "notify-user-data") && + attr->value_tag == IPP_TAG_STRING) + { + if (attr->num_values > 1 || attr->values[0].unknown.length > 63) + { + send_ipp_status(con, IPP_REQUEST_VALUE, + _("The notify-user-data value is too large " + "(%d > 63 octets)!"), + attr->values[0].unknown.length); + return; + } + + user_data = attr; + } + else if (!strcmp(attr->name, "notify-events") && + attr->value_tag == IPP_TAG_KEYWORD) + { + for (i = 0; i < attr->num_values; i ++) + mask |= cupsdEventValue(attr->values[i].string.text); + } + else if (!strcmp(attr->name, "notify-lease-duration") && + attr->value_tag == IPP_TAG_INTEGER) + lease = attr->values[0].integer; + else if (!strcmp(attr->name, "notify-time-interval") && + attr->value_tag == IPP_TAG_INTEGER) + interval = attr->values[0].integer; + else if (!strcmp(attr->name, "notify-job-id") && + attr->value_tag == IPP_TAG_INTEGER) + jobid = attr->values[0].integer; + + attr = attr->next; + } + + if (!recipient && !pullmethod) + break; + + if (mask == CUPSD_EVENT_NONE) + { + if (jobid) + mask = CUPSD_EVENT_JOB_COMPLETED; + else if (printer) + mask = CUPSD_EVENT_PRINTER_STATE_CHANGED; + else + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("notify-events not specified!")); + return; + } + } + + if (MaxLeaseDuration && lease > MaxLeaseDuration) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "create_subscription: Limiting notify-lease-duration to " + "%d seconds.", + MaxLeaseDuration); + lease = MaxLeaseDuration; + } + + if (jobid) + { + if ((job = cupsdFindJob(jobid)) == NULL) + { + send_ipp_status(con, IPP_NOT_FOUND, _("Job %d not found!"), jobid); + return; + } + } + else + job = NULL; + + sub = cupsdAddSubscription(mask, printer, job, recipient, 0); + + sub->interval = interval; + sub->lease = lease; + sub->expire = time(NULL) + lease; + + cupsdSetString(&sub->owner, username); + + if (user_data) + { + sub->user_data_len = user_data->values[0].unknown.length; + memcpy(sub->user_data, user_data->values[0].unknown.data, + sub->user_data_len); + } + + ippAddSeparator(con->response); + ippAddInteger(con->response, IPP_TAG_SUBSCRIPTION, IPP_TAG_INTEGER, + "notify-subscription-id", sub->id); + + if (attr) + attr = attr->next; + } + + cupsdSaveAllSubscriptions(); + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'delete_printer()' - Remove a printer or class from the system. + */ + +static void +delete_printer(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - URI of printer or class */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer/class */ + char filename[1024]; /* Script/PPD filename */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "delete_printer(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Do we have a valid URI? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Remove old jobs... + */ + + cupsdCancelJobs(dest, NULL, 1); + + /* + * Remove old subscriptions and send a "deleted printer" event... + */ + + cupsdAddEvent(CUPSD_EVENT_PRINTER_DELETED, printer, NULL, + "%s \"%s\" deleted by \"%s\".", + (dtype & CUPS_PRINTER_CLASS) ? "Class" : "Printer", + dest, con->username); + + cupsdExpireSubscriptions(printer, NULL); + + /* + * 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) + { + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" deleted by \"%s\".", dest, + con->username); + + cupsdDeletePrinter(printer, 0); + cupsdSaveAllClasses(); + } + else + { + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" deleted by \"%s\".", dest, + con->username); + + cupsdDeletePrinter(printer, 0); + cupsdSaveAllPrinters(); + } + + cupsdWritePrintcap(); + + /* + * Return with no errors... + */ + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'get_default()' - Get the default destination. + */ + +static void +get_default(cupsd_client_t *con) /* I - Client connection */ +{ + http_status_t status; /* Policy status */ + int i; /* Looping var */ + ipp_attribute_t *requested, /* requested-attributes */ + *history; /* History collection */ + int need_history; /* Need to send history collection? */ + char printer_uri[HTTP_MAX_URI]; + /* Printer URI */ + time_t curtime; /* Current time */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_default(%p[%d])", con, con->http.fd); + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + if (DefaultPrinter != NULL) + { + /* + * Copy the printer attributes to the response using requested-attributes + * and document-format attributes that may be provided by the client. + */ + + if (!ippFindAttribute(DefaultPrinter->attrs, "printer-uri-supported", + IPP_TAG_URI)) + { + httpAssembleURIf(printer_uri, sizeof(printer_uri), "ipp", NULL, + con->servername, con->serverport, "/printers/%s", + DefaultPrinter->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, + "printer-uri-supported", NULL, printer_uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"", + printer_uri); + } + + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", + DefaultPrinter->state); + + add_printer_state_reasons(con, DefaultPrinter); + + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-state-message", NULL, DefaultPrinter->state_message); + + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-accepting-jobs", + DefaultPrinter->accepting); + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", + DefaultPrinter->shared); + + curtime = time(NULL); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "printer-up-time", curtime); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "printer-state-change-time", DefaultPrinter->state_time); + ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", + ippTimeToDate(curtime)); + + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-error-policy", NULL, DefaultPrinter->error_policy); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-op-policy", NULL, DefaultPrinter->op_policy); + + add_queued_job_count(con, DefaultPrinter); + + requested = ippFindAttribute(con->request, "requested-attributes", + IPP_TAG_KEYWORD); + + copy_attrs(con->response, DefaultPrinter->attrs, requested, IPP_TAG_ZERO, 0); + copy_attrs(con->response, CommonData, requested, IPP_TAG_ZERO, IPP_TAG_COPY); + + need_history = 0; + + if (MaxPrinterHistory > 0 && DefaultPrinter->num_history > 0 && requested) + { + for (i = 0; i < requested->num_values; i ++) + if (!strcmp(requested->values[i].string.text, "all") || + !strcmp(requested->values[i].string.text, "printer-state-history")) + { + need_history = 1; + break; + } + } + + if (need_history) + { + history = ippAddCollections(con->response, IPP_TAG_PRINTER, + "printer-state-history", + DefaultPrinter->num_history, NULL); + + for (i = 0; i < DefaultPrinter->num_history; i ++) + copy_attrs(history->values[i].collection = ippNew(), + DefaultPrinter->history[i], + NULL, IPP_TAG_ZERO, 0); + } + + con->response->request.status.status_code = requested ? IPP_OK_SUBST : IPP_OK; + } + else + send_ipp_status(con, IPP_NOT_FOUND, _("No default printer")); +} + + +/* + * 'get_devices()' - Get the list of available devices on the local system. + */ + +static void +get_devices(cupsd_client_t *con) /* I - Client connection */ +{ + http_status_t status; /* Policy status */ + int i; /* Looping var */ + ipp_attribute_t *limit, /* Limit attribute */ + *requested; /* requested-attributes attribute */ + char command[1024], /* cups-deviced command */ + options[1024], /* Options to pass to command */ + attrs[1024], /* String for requested attributes */ + *aptr; /* Pointer into string */ + int alen; /* Length of attribute value */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_devices(%p[%d])", con, con->http.fd); + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Run cups-deviced command with the given options... + */ + + limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER); + requested = ippFindAttribute(con->request, "requested-attributes", + IPP_TAG_KEYWORD); + + if (requested) + { + for (i = 0, aptr = attrs; i < requested->num_values; i ++) + { + /* + * Check that we have enough room... + */ + + alen = strlen(requested->values[i].string.text); + if (alen > (sizeof(attrs) - (aptr - attrs) - 2)) + break; + + /* + * Put commas between values... + */ + + if (i) + *aptr++ = ','; + + /* + * Add the value to the end of the string... + */ + + strcpy(aptr, requested->values[i].string.text); + aptr += alen; + } + + /* + * If we have more attribute names than will fit, default to "all"... + */ + + if (i < requested->num_values) + strcpy(attrs, "all"); + } + else + strcpy(attrs, "all"); + + snprintf(command, sizeof(command), "%s/daemon/cups-deviced", ServerBin); + snprintf(options, sizeof(options), + "cups-deviced %d+%d+requested-attributes=%s", + con->request->request.op.request_id, + limit ? limit->values[0].integer : 0, + attrs); + + if (cupsdSendCommand(con, command, options, 1)) + { + /* + * Command started successfully, don't send an IPP response here... + */ + + ippDelete(con->response); + con->response = NULL; + } + else + { + /* + * Command failed, return "internal error" so the user knows something + * went wrong... + */ + + send_ipp_status(con, IPP_INTERNAL_ERROR, + _("cups-deviced failed to execute.")); + } +} + + +/* + * 'get_jobs()' - Get a list of jobs for the specified printer. + */ + +static void +get_jobs(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + 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 first_job_id; /* First job ID */ + int limit; /* Maximum number of jobs to return */ + int count; /* Number of jobs that match */ + cupsd_job_t *job; /* Current job pointer */ + char job_uri[HTTP_MAX_URI]; /* Job URI... */ + cupsd_printer_t *printer; /* Printer */ + cups_array_t *list; /* Which job list... */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_jobs(%p[%d], %s)", con, con->http.fd, + uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(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; + printer = NULL; + } + else if (strncmp(resource, "/printers", 9) == 0 && strlen(resource) <= 10) + { + dest = NULL; + dtype = (cups_ptype_t)0; + dmask = CUPS_PRINTER_CLASS; + printer = NULL; + } + else if (strncmp(resource, "/classes", 8) == 0 && strlen(resource) <= 9) + { + dest = NULL; + dtype = CUPS_PRINTER_CLASS; + dmask = CUPS_PRINTER_CLASS; + printer = NULL; + } + else if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + else + dmask = CUPS_PRINTER_CLASS; + + /* + * Check policy... + */ + + if (printer) + { + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + } + else if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * See if the "which-jobs" attribute have been specified... + */ + + if ((attr = ippFindAttribute(con->request, "which-jobs", IPP_TAG_KEYWORD)) != NULL && + !strcmp(attr->values[0].string.text, "completed")) + { + completed = 1; + list = Jobs; + } + else if (attr && !strcmp(attr->values[0].string.text, "all")) + { + completed = 0; + list = Jobs; + } + else + { + completed = 0; + list = ActiveJobs; + } + + /* + * 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; + + if ((attr = ippFindAttribute(con->request, "first-job-id", + IPP_TAG_INTEGER)) != NULL) + first_job_id = attr->values[0].integer; + else + first_job_id = 1; + + /* + * 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]) + strlcpy(username, con->username, sizeof(username)); + else if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) + strlcpy(username, attr->values[0].string.text, sizeof(username)); + 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 = (cupsd_job_t *)cupsArrayFirst(list); + count < limit && job; + job = (cupsd_job_t *)cupsArrayNext(list)) + { + /* + * Filter out jobs that don't match... + */ + + cupsdLogMessage(CUPSD_LOG_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' && strcasecmp(username, job->username) != 0) + continue; + + if (completed && job->state->values[0].integer <= IPP_JOB_STOPPED) + continue; + + if (job->id < first_job_id) + continue; + + count ++; + + cupsdLogMessage(CUPSD_LOG_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, + LocalPort, 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, 0); + + 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(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Job URI */ +{ + http_status_t status; /* Policy status */ + ipp_attribute_t *attr, /* Current attribute */ + *requested; /* Requested attributes */ + int jobid; /* Job ID */ + cupsd_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... */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_job_attrs(%p[%d], %s)", 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) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6) != 0) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Put out the standard attributes... + */ + + snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", + ServerName, LocalPort, 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, 0); + + 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_notifications()' - Get events for a subscription. + */ + +static void +get_notifications(cupsd_client_t *con, /* I - Client connection */ + int id) /* I - Subscription ID */ +{ +} + + +/* + * 'get_ppds()' - Get the list of PPD files on the local system. + */ + +static void +get_ppds(cupsd_client_t *con) /* I - Client connection */ +{ + http_status_t status; /* Policy status */ + int i; /* Looping var */ + ipp_attribute_t *limit, /* Limit attribute */ + *make, /* ppd-make attribute */ + *requested; /* requested-attributes attribute */ + char command[1024], /* cups-deviced command */ + options[1024], /* Options to pass to command */ + attrs[1024], /* String for requested attributes */ + *aptr; /* Pointer into string */ + int alen; /* Length of attribute value */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_ppds(%p[%d])", con, con->http.fd); + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Run cups-driverd command with the given options... + */ + + limit = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER); + make = ippFindAttribute(con->request, "ppd-make", IPP_TAG_TEXT); + requested = ippFindAttribute(con->request, "requested-attributes", + IPP_TAG_KEYWORD); + + if (requested) + { + for (i = 0, aptr = attrs; i < requested->num_values; i ++) + { + /* + * Check that we have enough room... + */ + + alen = strlen(requested->values[i].string.text); + if (alen > (sizeof(attrs) - (aptr - attrs) - 2)) + break; + + /* + * Put commas between values... + */ + + if (i) + *aptr++ = ','; + + /* + * Add the value to the end of the string... + */ + + strcpy(aptr, requested->values[i].string.text); + aptr += alen; + } + + /* + * If we have more attribute names than will fit, default to "all"... + */ + + if (i < requested->num_values) + strcpy(attrs, "all"); + } + else + strcpy(attrs, "all"); + + snprintf(command, sizeof(command), "%s/daemon/cups-driverd", ServerBin); + snprintf(options, sizeof(options), + "cups-driverd list+%d+%d+requested-attributes=%s%s%s", + con->request->request.op.request_id, + limit ? limit->values[0].integer : 0, + attrs, + make ? "%20ppd-make=" : "", + make ? make->values[0].string.text : ""); + + if (cupsdSendCommand(con, command, options, 0)) + { + /* + * Command started successfully, don't send an IPP response here... + */ + + ippDelete(con->response); + con->response = NULL; + } + else + { + /* + * Command failed, return "internal error" so the user knows something + * went wrong... + */ + + send_ipp_status(con, IPP_INTERNAL_ERROR, + _("cups-driverd failed to execute.")); + } +} + + +/* + * 'get_printer_attrs()' - Get printer attributes. + */ + +static void +get_printer_attrs(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer/class */ + char printer_uri[HTTP_MAX_URI]; + /* Printer URI */ + time_t curtime; /* Current time */ + int i; /* Looping var */ + ipp_attribute_t *requested, /* requested-attributes */ + *history; /* History collection */ + int need_history; /* Need to send history collection? */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printer_attrs(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + curtime = time(NULL); + + /* + * Copy the printer attributes to the response using requested-attributes + * and document-format attributes that may be provided by the client. + */ + + if (!ippFindAttribute(printer->attrs, "printer-uri-supported", + IPP_TAG_URI)) + { + httpAssembleURIf(printer_uri, sizeof(printer_uri), "ipp", NULL, + con->servername, con->serverport, "/printers/%s", + printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, + "printer-uri-supported", NULL, printer_uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"", + printer_uri); + } + + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", + printer->state); + + add_printer_state_reasons(con, printer); + + 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); + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", + printer->shared); + + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "printer-up-time", curtime); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "printer-state-change-time", printer->state_time); + ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", + ippTimeToDate(curtime)); + + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-error-policy", NULL, printer->error_policy); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-op-policy", NULL, printer->op_policy); + + add_queued_job_count(con, printer); + + requested = ippFindAttribute(con->request, "requested-attributes", + IPP_TAG_KEYWORD); + + copy_attrs(con->response, printer->attrs, requested, IPP_TAG_ZERO, 0); + copy_attrs(con->response, CommonData, requested, IPP_TAG_ZERO, IPP_TAG_COPY); + + need_history = 0; + + if (MaxPrinterHistory > 0 && printer->num_history > 0 && requested) + { + for (i = 0; i < requested->num_values; i ++) + if (!strcmp(requested->values[i].string.text, "all") || + !strcmp(requested->values[i].string.text, "printer-state-history")) + { + need_history = 1; + break; + } + } + + if (need_history) + { + history = ippAddCollections(con->response, IPP_TAG_PRINTER, + "printer-state-history", + printer->num_history, NULL); + + for (i = 0; i < printer->num_history; i ++) + copy_attrs(history->values[i].collection = ippNew(), printer->history[i], + NULL, IPP_TAG_ZERO, 0); + } + + con->response->request.status.status_code = requested ? IPP_OK_SUBST : IPP_OK; +} + + +/* + * 'get_printers()' - Get a list of printers or classes. + */ + +static void +get_printers(cupsd_client_t *con, /* I - Client connection */ + int type) /* I - 0 or CUPS_PRINTER_CLASS */ +{ + http_status_t status; /* Policy status */ + int i; /* Looping var */ + ipp_attribute_t *requested, /* requested-attributes */ + *history, /* History collection */ + *attr; /* Current attribute */ + int need_history; /* Need to send history collection? */ + int limit; /* Maximum number of printers to return */ + int count; /* Number of printers that match */ + cupsd_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 */ + const char *username; /* Current user */ + char *first_printer_name; /* first-printer-name attribute */ + char printer_uri[HTTP_MAX_URI]; + /* Printer URI */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "get_printers(%p[%d], %x)", con, + con->http.fd, type); + + if (!Printers || !cupsArrayCount(Printers)) + { + send_ipp_status(con, IPP_NOT_FOUND, _("No destinations added.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * 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; + + if ((attr = ippFindAttribute(con->request, "first-printer-name", + IPP_TAG_NAME)) != NULL) + first_printer_name = attr->values[0].string.text; + else + first_printer_name = NULL; + + /* + * 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, "printer-location", + IPP_TAG_TEXT)) != NULL) + location = attr->values[0].string.text; + else + location = NULL; + + if (con->username[0]) + username = con->username; + else if ((attr = ippFindAttribute(con->request, "requesting-user-name", + IPP_TAG_NAME)) != NULL) + username = attr->values[0].string.text; + else + username = NULL; + + requested = ippFindAttribute(con->request, "requested-attributes", + IPP_TAG_KEYWORD); + + need_history = 0; + + if (MaxPrinterHistory > 0 && requested) + { + for (i = 0; i < requested->num_values; i ++) + if (!strcmp(requested->values[i].string.text, "all") || + !strcmp(requested->values[i].string.text, "printer-state-history")) + { + need_history = 1; + break; + } + } + + /* + * OK, build a list of printers for this printer... + */ + + curtime = time(NULL); + + if (first_printer_name) + { + if ((printer = cupsdFindDest(first_printer_name)) == NULL) + printer = (cupsd_printer_t *)cupsArrayFirst(Printers); + } + else + printer = (cupsd_printer_t *)cupsArrayFirst(Printers); + + for (count = 0; + count < limit && printer != NULL; + printer = (cupsd_printer_t *)cupsArrayNext(Printers)) + if ((!type || (printer->type & CUPS_PRINTER_CLASS) == type) && + (printer->type & printer_mask) == printer_type && + (location == NULL || printer->location == NULL || + !strcasecmp(printer->location, location))) + { + /* + * If HideImplicitMembers is enabled, see if this printer or class + * is a member of an implicit class... + */ + + if (ImplicitClasses && HideImplicitMembers && + printer->in_implicit_class) + continue; + + /* + * If a username is specified, see if it is allowed or denied + * access... + */ + + if (printer->num_users && username && !user_allowed(printer, username)) + 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 + * printer-is-shared + * printer-up-time + * printer-state-change-time + * + all printer attributes + */ + + if (!ippFindAttribute(printer->attrs, "printer-uri-supported", + IPP_TAG_URI)) + { + httpAssembleURIf(printer_uri, sizeof(printer_uri), "ipp", NULL, + con->servername, con->serverport, "/printers/%s", + printer->name); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_URI, + "printer-uri-supported", NULL, printer_uri); + cupsdLogMessage(CUPSD_LOG_DEBUG2, "printer-uri-supported=\"%s\"", printer_uri); + } + + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "printer-state", printer->state); + + add_printer_state_reasons(con, printer); + + 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); + ippAddBoolean(con->response, IPP_TAG_PRINTER, "printer-is-shared", + printer->shared); + + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "printer-up-time", curtime); + ippAddInteger(con->response, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "printer-state-change-time", printer->state_time); + ippAddDate(con->response, IPP_TAG_PRINTER, "printer-current-time", + ippTimeToDate(curtime)); + + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-error-policy", NULL, printer->error_policy); + ippAddString(con->response, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-op-policy", NULL, printer->op_policy); + + add_queued_job_count(con, printer); + + copy_attrs(con->response, printer->attrs, requested, IPP_TAG_ZERO, 0); + + copy_attrs(con->response, CommonData, requested, IPP_TAG_ZERO, + IPP_TAG_COPY); + + if (need_history && printer->num_history > 0) + { + history = ippAddCollections(con->response, IPP_TAG_PRINTER, + "printer-state-history", + printer->num_history, NULL); + + for (i = 0; i < printer->num_history; i ++) + copy_attrs(history->values[i].collection = ippNew(), + printer->history[i], NULL, IPP_TAG_ZERO, 0); + } + } + + con->response->request.status.status_code = requested ? IPP_OK_SUBST : IPP_OK; +} + + +/* + * 'get_subscription_attrs()' - Get subscription attributes. + */ + +static void +get_subscription_attrs( + cupsd_client_t *con, /* I - Client connection */ + int sub_id) /* I - Subscription ID */ +{ + http_status_t status; /* Policy status */ + cupsd_subscription_t *sub; /* Subscription */ + cups_array_t *ra; /* Requested attributes array */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "get_subscription_attrs(con=%p[%d], sub_id=%d)", + con, con->http.fd, sub_id); + + /* + * Is the subscription ID valid? + */ + + if ((sub = cupsdFindSubscription(sub_id)) == NULL) + { + /* + * Bad subscription ID... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("notify-subscription-id %d no good!"), sub_id); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(sub->dest ? sub->dest->op_policy_ptr : + DefaultPolicyPtr, + con, sub->owner)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Copy the subscription attributes to the response using the + * requested-attributes attribute that may be provided by the client. + */ + + ra = create_requested_array(con->request); + + copy_subscription_attrs(con, sub, ra); + + cupsArrayDelete(ra); + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'get_subscriptions()' - Get subscriptions. + */ + +static void +get_subscriptions(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer/job URI */ +{ + http_status_t status; /* Policy status */ + int count; /* Number of subscriptions */ + int limit; /* Limit */ + cupsd_subscription_t *sub; /* Subscription */ + cups_array_t *ra; /* Requested attributes array */ + ipp_attribute_t *attr; /* 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 */ + cupsd_job_t *job; /* Job pointer */ + cupsd_printer_t *printer; /* Printer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "get_subscriptions(con=%p[%d], uri=%s)", + con, con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (!strcmp(resource, "/") || + (!strncmp(resource, "/jobs", 5) && strlen(resource) <= 6) || + (!strncmp(resource, "/printers", 9) && strlen(resource) <= 10) || + (!strncmp(resource, "/classes", 8) && strlen(resource) <= 9)) + { + printer = NULL; + job = NULL; + } + else if (!strncmp(resource, "/jobs/", 6) && resource[6]) + { + printer = NULL; + job = cupsdFindJob(atoi(resource + 6)); + + if (!job) + { + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%s does not exist!"), + resource + 6); + return; + } + } + else if (!cupsdValidateDest(host, resource, &dtype, &printer)) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + else if ((attr = ippFindAttribute(con->request, "notify-job-id", + IPP_TAG_INTEGER)) != NULL) + { + job = cupsdFindJob(attr->values[0].integer); + + if (!job) + { + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), + attr->values[0].integer); + return; + } + } + else + job = NULL; + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer ? printer->op_policy_ptr : + DefaultPolicyPtr, + con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Copy the subscription attributes to the response using the + * requested-attributes attribute that may be provided by the client. + */ + + ra = create_requested_array(con->request); + + if ((attr = ippFindAttribute(con->request, "limit", IPP_TAG_INTEGER)) != NULL) + limit = attr->values[0].integer; + else + limit = 0; + + /* + * See if we only want to see subscriptions for a specific user... + */ + + if ((attr = ippFindAttribute(con->request, "my-subscriptions", + IPP_TAG_BOOLEAN)) != NULL && + attr->values[0].boolean) + { + if (con->username[0]) + strlcpy(username, con->username, sizeof(username)); + else if ((attr = ippFindAttribute(con->request, "requesting-user-name", IPP_TAG_NAME)) != NULL) + strlcpy(username, attr->values[0].string.text, sizeof(username)); + else + strcpy(username, "anonymous"); + } + else + username[0] = '\0'; + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), count = 0; + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + if ((!printer || sub->dest == printer) && (!job || sub->job == job) && + (!username[0] || !strcasecmp(username, sub->owner))) + { + ippAddSeparator(con->response); + copy_subscription_attrs(con, sub, ra); + + count ++; + if (limit && count >= limit) + break; + } + + cupsArrayDelete(ra); + + if (count) + con->response->request.status.status_code = IPP_OK; + else + send_ipp_status(con, IPP_NOT_FOUND, _("No subscriptions found.")); +} + + +/* + * 'hold_job()' - Hold a print job. + */ + +static void +hold_job(cupsd_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 */ + cupsd_job_t *job; /* Job information */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "hold_job(%p[%d], %s)", 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")) + { + /* + * Got a printer URI; see if we also have a job-id attribute... + */ + + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6)) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_ipp_status(con, IPP_FORBIDDEN, + _("Not authorized to hold job #%d owned by \"%s\"!"), + jobid, job->username); + return; + } + + /* + * Hold the job and return... + */ + + cupsdHoldJob(job); + + 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... + */ + + cupsdSetJobHoldUntil(job, attr->values[0].string.text); + } + + cupsdLogMessage(CUPSD_LOG_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(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Job URI */ +{ + http_status_t status; /* Policy status */ + ipp_attribute_t *attr; /* Current attribute */ + int jobid; /* Job ID */ + cupsd_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 */ + cupsd_printer_t *printer; /* Printer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "move_job(%p[%d], %s)", 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) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6)) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("Job #%d does not exist!"), jobid); + return; + } + + /* + * See if the job has been completed... + */ + + if (job->state->values[0].integer > IPP_JOB_STOPPED) + { + /* + * Return a "not-possible" error... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job #%d is finished and cannot be altered!"), + jobid); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_ipp_status(con, IPP_FORBIDDEN, + _("You are not authorized to move job #%d owned " + "by \"%s\"!"), + jobid, job->username); + return; + } + + if ((attr = ippFindAttribute(con->request, "job-printer-uri", IPP_TAG_URI)) == NULL) + { + /* + * Need job-printer-uri... + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("job-printer-uri attribute missing!")); + return; + } + + /* + * Get the new printer or class... + */ + + httpSeparateURI(attr->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Move the job to a different printer or class... + */ + + cupsdMoveJob(job, dest); + + /* + * Start jobs if possible... + */ + + cupsdCheckJobs(); + + /* + * Return with "everything is OK" status... + */ + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'ppd_add_default()' - Add a PPD default choice. + */ + +static int /* O - Number of defaults */ +ppd_add_default( + const char *option, /* I - Option name */ + const char *choice, /* I - Choice name */ + int num_defaults, /* I - Number of defaults */ + ppd_default_t **defaults) /* IO - Defaults */ +{ + int i; /* Looping var */ + ppd_default_t *temp; /* Temporary defaults array */ + + + /* + * First check if the option already has a default value; the PPD spec + * says that the first one is used... + */ + + for (i = 0, temp = *defaults; i < num_defaults; i ++) + if (!strcmp(option, temp[i].option)) + return (num_defaults); + + /* + * Now add the option... + */ + + if (num_defaults == 0) + temp = malloc(sizeof(ppd_default_t)); + else + temp = realloc(*defaults, (num_defaults + 1) * sizeof(ppd_default_t)); + + if (!temp) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "ppd_add_default: Unable to add default value for \"%s\" - %s", + option, strerror(errno)); + return (num_defaults); + } + + *defaults = temp; + temp += num_defaults; + + strlcpy(temp->option, option, sizeof(temp->option)); + strlcpy(temp->choice, choice, sizeof(temp->choice)); + + return (num_defaults + 1); +} + + +/* + * 'ppd_parse_line()' - Parse a PPD default line. + */ + +static int /* O - 0 on success, -1 on failure */ +ppd_parse_line(const char *line, /* I - Line */ + char *option, /* O - Option name */ + int olen, /* I - Size of option name */ + char *choice, /* O - Choice name */ + int clen) /* I - Size of choice name */ +{ + /* + * Verify this is a default option line... + */ + + if (strncmp(line, "*Default", 8)) + return (-1); + + /* + * Read the option name... + */ + + for (line += 8, olen --; isalnum(*line & 255); line ++) + if (olen > 0) + { + *option++ = *line; + olen --; + } + + *option = '\0'; + + /* + * Skip everything else up to the colon (:)... + */ + + while (*line && *line != ':') + line ++; + + if (!*line) + return (-1); + + line ++; + + /* + * Now grab the option choice, skipping leading whitespace... + */ + + while (isspace(*line & 255)) + line ++; + + for (clen --; isalnum(*line & 255); line ++) + if (clen > 0) + { + *choice++ = *line; + clen --; + } + + *choice = '\0'; + + /* + * Return with no errors... + */ + + return (0); +} + + +/* + * 'print_job()' - Print a file to a printer or class. + */ + +static void +print_job(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_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 */ + 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 */ + cupsd_printer_t *printer; /* Printer data */ + struct stat fileinfo; /* File information */ + int kbytes; /* Size of file */ + int i; /* Looping var */ + int lowerpagerange; /* Page range bound */ + int compression; /* Document compression */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "print_job(%p[%d], %s)", con, con->http.fd, + uri->values[0].string.text); + + /* + * Validate job template attributes; for now just copies and page-ranges... + */ + + if ((attr = ippFindAttribute(con->request, "copies", IPP_TAG_INTEGER)) != NULL) + { + if (attr->values[0].integer < 1 || attr->values[0].integer > MaxCopies) + { + send_ipp_status(con, IPP_ATTRIBUTES, _("Bad copies value %d."), + attr->values[0].integer); + ippAddInteger(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_INTEGER, + "copies", attr->values[0].integer); + return; + } + } + + if ((attr = ippFindAttribute(con->request, "page-ranges", IPP_TAG_RANGE)) != NULL) + { + for (i = 0, lowerpagerange = 1; i < attr->num_values; i ++) + { + if (attr->values[i].range.lower < lowerpagerange || + attr->values[i].range.lower > attr->values[i].range.upper) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad page-ranges values %d-%d."), + attr->values[i].range.lower, + attr->values[i].range.upper); + return; + } + + lowerpagerange = attr->values[i].range.upper + 1; + } + } + + /* + * OK, see if the client is sending the document compressed - CUPS + * only supports "none" and "gzip". + */ + + compression = CUPS_FILE_NONE; + + if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) + { + if (strcmp(attr->values[0].string.text, "none") +#ifdef HAVE_LIBZ + && strcmp(attr->values[0].string.text, "gzip") +#endif /* HAVE_LIBZ */ + ) + { + send_ipp_status(con, IPP_ATTRIBUTES, + _("Unsupported compression \"%s\"!"), + attr->values[0].string.text); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, + "compression", NULL, attr->values[0].string.text); + return; + } + +#ifdef HAVE_LIBZ + if (!strcmp(attr->values[0].string.text, "gzip")) + compression = CUPS_FILE_GZIP; +#endif /* HAVE_LIBZ */ + } + + /* + * Do we have a file to print? + */ + + if (!con->filename) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("No file!?!")); + 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) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Could not scan type \"%s\"!"), + format->values[0].string.text); + return; + } + } + else + { + /* + * No document format attribute? Auto-type it! + */ + + strcpy(super, "application"); + strcpy(type, "octet-stream"); + } + + if (!strcmp(super, "application") && !strcmp(type, "octet-stream")) + { + /* + * Auto-type the file... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, "print_job: auto-typing file..."); + + filetype = mimeFileType(MimeDatabase, con->filename, &compression); + + 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) + { + send_ipp_status(con, IPP_DOCUMENT_FORMAT, + _("Unsupported format \'%s/%s\'!"), super, type); + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Do you have the raw file printing rules enabled?"); + + if (format) + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, + "document-format", NULL, format->values[0].string.text); + + return; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "print_job: request file type is %s/%s.", + filetype->super, filetype->type); + + /* + * Read any embedded job ticket info from PS files... + */ + + if (!strcasecmp(filetype->super, "application") && + !strcasecmp(filetype->type, "postscript")) + read_ps_job_ticket(con); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check remote printing to non-shared printer... + */ + + if (!printer->shared && + strcasecmp(con->http.hostname, "localhost") && + strcasecmp(con->http.hostname, ServerName)) + { + send_ipp_status(con, IPP_NOT_AUTHORIZED, _("Printer not shared!")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + else if ((printer->type & CUPS_PRINTER_AUTHENTICATED) && !con->username[0]) + { + send_http_error(con, status); + return; + } + + /* + * See if the printer is accepting jobs... + */ + + if (!printer->accepting) + { + send_ipp_status(con, IPP_NOT_ACCEPTING, + _("Destination \"%s\" is not accepting jobs."), dest); + return; + } + + /* + * Make sure we aren't over our limit... + */ + + if (cupsArrayCount(Jobs) >= MaxJobs && MaxJobs) + cupsdCleanJobs(); + + if (cupsArrayCount(Jobs) >= MaxJobs && MaxJobs) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Too many jobs - %d jobs, max jobs is %d."), + cupsArrayCount(Jobs), MaxJobs); + return; + } + + if (!check_quotas(con, printer)) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Quota limit reached.")); + 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 = cupsdAddJob(priority, printer->name)) == NULL) + { + send_ipp_status(con, IPP_INTERNAL_ERROR, + _("Unable to add job for destination \"%s\"!"), dest); + return; + } + + job->dtype = dtype; + job->attrs = con->request; + con->request = NULL; + + /* + * Copy the rest of the job info... + */ + + attr = ippFindAttribute(job->attrs, "requesting-user-name", IPP_TAG_NAME); + + if (con->username[0]) + { + cupsdSetString(&job->username, con->username); + + if (attr) + cupsdSetString(&attr->values[0].string.text, con->username); + + save_auth_info(con, job); + } + else if (attr != NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "print_job: requesting-user-name = \"%s\"", + attr->values[0].string.text); + + cupsdSetString(&job->username, attr->values[0].string.text); + } + else + cupsdSetString(&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; + cupsdSetString(&attr->name, "job-originating-user-name"); + } + + /* + * Add remaining job attributes... + */ + + if ((attr = ippFindAttribute(job->attrs, "job-originating-host-name", + IPP_TAG_ZERO)) != NULL) + { + /* + * Request contains a job-originating-host-name attribute; validate it... + */ + + if (attr->value_tag != IPP_TAG_NAME || + attr->num_values != 1 || + strcmp(con->http.hostname, "localhost") != 0) + { + /* + * Can't override the value if we aren't connected via localhost. + * Also, we can only have 1 value and it must be a name value. + */ + + switch (attr->value_tag) + { + case IPP_TAG_STRING : + case IPP_TAG_TEXTLANG : + case IPP_TAG_NAMELANG : + 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 : + /* + * Free old strings... + */ + + for (i = 0; i < attr->num_values; i ++) + { + free(attr->values[i].string.text); + attr->values[i].string.text = NULL; + if (attr->values[i].string.charset) + { + free(attr->values[i].string.charset); + attr->values[i].string.charset = NULL; + } + } + + default : + break; + } + + /* + * Use the default connection hostname instead... + */ + + attr->value_tag = IPP_TAG_NAME; + attr->num_values = 1; + attr->values[0].string.text = strdup(con->http.hostname); + } + + attr->group_tag = IPP_TAG_JOB; + } + else + { + /* + * No job-originating-host-name attribute, so use the hostname from + * the connection... + */ + + 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; + + cupsdUpdateQuota(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; + cupsdSetJobHoldUntil(job, attr->values[0].string.text); + } + + if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) || + Classification) + { + /* + * Add job sheets options... + */ + + if ((attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_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) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Classification=\"%s\", ClassifyOverride=%d", + Classification ? Classification : "(null)", + ClassifyOverride); + + 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... + */ + + cupsdSetString(&attr->values[0].string.text, Classification); + + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION FORCED " + "job-sheets=\"%s,none\", " + "job-originating-user-name=\"%s\"", + job->id, Classification, job->username); + } + 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! + */ + + cupsdSetString(&attr->values[1].string.text, attr->values[0].string.text); + + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION FORCED " + "job-sheets=\"%s,%s\", " + "job-originating-user-name=\"%s\"", + job->id, attr->values[0].string.text, + attr->values[1].string.text, job->username); + } + else if (strcmp(attr->values[0].string.text, Classification) && + strcmp(attr->values[0].string.text, "none") && + (attr->num_values == 1 || + (strcmp(attr->values[1].string.text, Classification) && + strcmp(attr->values[1].string.text, "none")))) + { + if (attr->num_values == 1) + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION OVERRIDDEN " + "job-sheets=\"%s\", " + "job-originating-user-name=\"%s\"", + job->id, attr->values[0].string.text, + job->username); + else + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION OVERRIDDEN " + "job-sheets=\"%s,%s\", " + "job-originating-user-name=\"%s\"", + job->id, attr->values[0].string.text, + attr->values[1].string.text, job->username); + } + } + else if (strcmp(attr->values[0].string.text, Classification) != 0 && + (attr->num_values == 1 || + strcmp(attr->values[1].string.text, Classification) != 0)) + { + /* + * Force the banner to have the classification on it... + */ + + if (attr->num_values > 1 && + !strcmp(attr->values[0].string.text, attr->values[1].string.text)) + { + cupsdSetString(&(attr->values[0].string.text), Classification); + cupsdSetString(&(attr->values[1].string.text), Classification); + } + else + { + if (attr->num_values == 1 || + strcmp(attr->values[0].string.text, "none")) + cupsdSetString(&(attr->values[0].string.text), Classification); + + if (attr->num_values > 1 && + strcmp(attr->values[1].string.text, "none")) + cupsdSetString(&(attr->values[1].string.text), Classification); + } + + if (attr->num_values > 1) + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION FORCED " + "job-sheets=\"%s,%s\", " + "job-originating-user-name=\"%s\"", + job->id, attr->values[0].string.text, + attr->values[1].string.text, job->username); + else + cupsdLogMessage(CUPSD_LOG_NOTICE, + "[Job %d] CLASSIFICATION FORCED " + "job-sheets=\"%s\", " + "job-originating-user-name=\"%s\"", + job->id, Classification, job->username); + } + } + + /* + * Add the starting sheet... + */ + + if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT))) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Adding start banner page \"%s\" to job %d.", + attr->values[0].string.text, job->id); + + kbytes = copy_banner(con, job, attr->values[0].string.text); + + cupsdUpdateQuota(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, compression)) + return; + + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, job->id, + job->num_files); + rename(con->filename, filename); + cupsdClearString(&con->filename); + + /* + * See if we need to add the ending sheet... + */ + + if (!(printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) && + attr->num_values > 1) + { + /* + * Yes... + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Adding end banner page \"%s\" to job %d.", + attr->values[1].string.text, job->id); + + kbytes = copy_banner(con, job, attr->values[1].string.text); + + cupsdUpdateQuota(printer, job->username, 0, kbytes); + } + + /* + * Fill in the response info... + */ + + snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName, + LocalPort, 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; + + /* + * Add any job subscriptions... + */ + + add_job_subscriptions(con, job); + + /* + * Set all but the first two attributes to the job attributes group... + */ + + for (attr = job->attrs->attrs->next->next; attr; attr = attr->next) + attr->group_tag = IPP_TAG_JOB; + + /* + * Log and save the job... + */ + + cupsdLogMessage(CUPSD_LOG_INFO, "Job %d queued on \"%s\" by \"%s\".", job->id, + job->dest, job->username); + cupsdLogMessage(CUPSD_LOG_DEBUG, "Job %d hold_until = %d", job->id, + (int)job->hold_until); + + cupsdSaveJob(job); + + cupsdAddEvent(CUPSD_EVENT_JOB_CREATED, printer, job, "Job created."); + + /* + * Start the job if possible... + */ + + cupsdCheckJobs(); +} + + +/* + * 'read_ps_job_ticket()' - Reads a job ticket embedded in a PS file. + * + * This function only gets called when printing a single PostScript + * file using the Print-Job operation. It doesn't work for Create-Job + + * Send-File, since the job attributes need to be set at job creation + * time for banners to work. The embedded PS job ticket stuff is here + * only to allow the Windows printer driver for CUPS to pass in JCL + * options and IPP attributes which otherwise would be lost. + * + * The format of a PS job ticket is simple: + * + * %cupsJobTicket: attr1=value1 attr2=value2 ... attrN=valueN + * + * %cupsJobTicket: attr1=value1 + * %cupsJobTicket: attr2=value2 + * ... + * %cupsJobTicket: attrN=valueN + * + * Job ticket lines must appear immediately after the first line that + * specifies PostScript format (%!PS-Adobe-3.0), and CUPS will stop + * looking for job ticket info when it finds a line that does not begin + * with "%cupsJobTicket:". + * + * The maximum length of a job ticket line, including the prefix, is + * 255 characters to conform with the Adobe DSC. + * + * Read-only attributes are rejected with a notice to the error log in + * case a malicious user tries anything. Since the job ticket is read + * prior to attribute validation in print_job(), job ticket attributes + * will go through the same validation as IPP attributes... + */ + +static void +read_ps_job_ticket(cupsd_client_t *con) /* I - Client connection */ +{ + cups_file_t *fp; /* File to read from */ + char line[256]; /* Line data */ + int num_options; /* Number of options */ + cups_option_t *options; /* Options */ + ipp_t *ticket; /* New attributes */ + ipp_attribute_t *attr, /* Current attribute */ + *attr2, /* Job attribute */ + *prev2; /* Previous job attribute */ + + + /* + * First open the print file... + */ + + if ((fp = cupsFileOpen(con->filename, "rb")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "read_ps_job_ticket: Unable to open PostScript print file " + "- %s", + strerror(errno)); + return; + } + + /* + * Skip the first line... + */ + + if (cupsFileGets(fp, line, sizeof(line)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "read_ps_job_ticket: Unable to read from PostScript print " + "file - %s", + strerror(errno)); + cupsFileClose(fp); + return; + } + + if (strncmp(line, "%!PS-Adobe-", 11) != 0) + { + /* + * Not a DSC-compliant file, so no job ticket info will be available... + */ + + cupsFileClose(fp); + return; + } + + /* + * Read job ticket info from the file... + */ + + num_options = 0; + options = NULL; + + while (cupsFileGets(fp, line, sizeof(line)) != NULL) + { + /* + * Stop at the first non-ticket line... + */ + + if (strncmp(line, "%cupsJobTicket:", 15) != 0) + break; + + /* + * Add the options to the option array... + */ + + num_options = cupsParseOptions(line + 15, num_options, &options); + } + + /* + * Done with the file; see if we have any options... + */ + + cupsFileClose(fp); + + if (num_options == 0) + return; + + /* + * OK, convert the options to an attribute list, and apply them to + * the request... + */ + + ticket = ippNew(); + cupsEncodeOptions(ticket, num_options, options); + + /* + * See what the user wants to change. + */ + + for (attr = ticket->attrs; attr != NULL; attr = attr->next) + { + if (attr->group_tag != IPP_TAG_JOB || !attr->name) + continue; + + if (!strcmp(attr->name, "job-originating-host-name") || + !strcmp(attr->name, "job-originating-user-name") || + !strcmp(attr->name, "job-media-sheets-completed") || + !strcmp(attr->name, "job-k-octets") || + !strcmp(attr->name, "job-id") || + !strncmp(attr->name, "job-state", 9) || + !strncmp(attr->name, "time-at-", 8)) + continue; /* Read-only attrs */ + + if ((attr2 = ippFindAttribute(con->request, attr->name, IPP_TAG_ZERO)) != NULL) + { + /* + * Some other value; first free the old value... + */ + + if (con->request->attrs == attr2) + { + con->request->attrs = attr2->next; + prev2 = NULL; + } + else + { + for (prev2 = con->request->attrs; prev2 != NULL; prev2 = prev2->next) + if (prev2->next == attr2) + { + prev2->next = attr2->next; + break; + } + } + + if (con->request->last == attr2) + con->request->last = prev2; + + _ipp_free_attr(attr2); + } + + /* + * Add new option by copying it... + */ + + copy_attribute(con->request, attr, 0); + } + + /* + * Then free the attribute list and option array... + */ + + ippDelete(ticket); + cupsFreeOptions(num_options, options); +} + + +/* + * 'reject_jobs()' - Reject print jobs to a printer. + */ + +static void +reject_jobs(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer or class URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer data */ + ipp_attribute_t *attr; /* printer-state-message text */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "reject_jobs(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Reject jobs sent to the printer... + */ + + printer->accepting = 0; + + if ((attr = ippFindAttribute(con->request, "printer-state-message", + IPP_TAG_TEXT)) == NULL) + strcpy(printer->state_message, "Rejecting Jobs"); + else + strlcpy(printer->state_message, attr->values[0].string.text, + sizeof(printer->state_message)); + + cupsdAddPrinterHistory(printer); + + if (dtype & CUPS_PRINTER_CLASS) + { + cupsdSaveAllClasses(); + + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" rejecting jobs (\"%s\").", + name, con->username); + } + else + { + cupsdSaveAllPrinters(); + + cupsdLogMessage(CUPSD_LOG_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(cupsd_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 */ + cupsd_job_t *job; /* Job information */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "release_job(%p[%d], %s)", 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")) + { + /* + * Got a printer URI; see if we also have a job-id attribute... + */ + + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6)) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + return; + } + + /* + * See if job is "held"... + */ + + if (job->state->values[0].integer != IPP_JOB_HELD) + { + /* + * Nope - return a "not possible" error... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not held!"), jobid); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_ipp_status(con, IPP_FORBIDDEN, + _("You are not authorized to release job id " + "%d owned by \"%s\"!"), + jobid, job->username); + 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... + */ + + cupsdReleaseJob(job); + + cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was released by \"%s\".", jobid, + username); + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'renew_subscription()' - Renew an existing subscription... + */ + +static void +renew_subscription( + cupsd_client_t *con, /* I - Client connection */ + int sub_id) /* I - Subscription ID */ +{ +} + + +/* + * 'restart_job()' - Restart an old print job. + */ + +static void +restart_job(cupsd_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 */ + cupsd_job_t *job; /* Job information */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "restart_job(%p[%d], %s)", 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")) + { + /* + * Got a printer URI; see if we also have a job-id attribute... + */ + + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6) != 0) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + 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... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, _("Job #%d is not complete!"), + jobid); + 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... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job #%d cannot be restarted - no files!"), jobid); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_ipp_status(con, IPP_FORBIDDEN, + _("You are not authorized to restart job id " + "%d owned by \"%s\"!"), + jobid, job->username); + return; + } + + /* + * Restart the job and return... + */ + + cupsdRestartJob(job); + + cupsdLogMessage(CUPSD_LOG_INFO, "Job %d was restarted by \"%s\".", jobid, + username); + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'save_auth_info()' - Save authentication information for a job. + */ + +static void +save_auth_info(cupsd_client_t *con, /* I - Client connection */ + cupsd_job_t *job) /* I - Job */ +{ + int i; /* Looping var */ + char filename[1024]; /* Job authentication filename */ + cups_file_t *fp; /* Job authentication file */ + char line[1024]; /* Line for file */ + + + /* + * This function saves the in-memory authentication information for + * a job so that it can be used to authenticate with a remote host. + * The information is stored in a file that is readable only by the + * root user. The username and password are Base-64 encoded, each + * on a separate line, followed by random number (up to 1024) of + * newlines to limit the amount of information that is exposed. + * + * Because of the potential for exposing of authentication information, + * this functionality is only enabled when running cupsd as root. + * + * This caching only works for the Basic and BasicDigest authentication + * types. Digest authentication cannot be cached this way, and in + * the future Kerberos authentication may make all of this obsolete. + * + * Authentication information is saved whenever an authenticated + * Print-Job, Create-Job, or CUPS-Authenticate-Job operation is + * performed. + * + * This information is deleted after a job is completed or canceled, + * so reprints may require subsequent re-authentication. + */ + + if (RunUser) + return; + + /* + * Create the authentication file and change permissions... + */ + + snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, job->id); + if ((fp = cupsFileOpen(filename, "w")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to save authentication info to \"%s\" - %s", + filename, strerror(errno)); + return; + } + + fchown(cupsFileNumber(fp), 0, 0); + fchmod(cupsFileNumber(fp), 0400); + + /* + * Write the authenticated username... + */ + + httpEncode64_2(line, sizeof(line), con->username, strlen(con->username)); + cupsFilePrintf(fp, "%s\n", line); + + /* + * Write the authenticated password... + */ + + httpEncode64_2(line, sizeof(line), con->password, strlen(con->password)); + cupsFilePrintf(fp, "%s\n", line); + + /* + * Write a random number of newlines to the end of the file... + */ + + for (i = (rand() % 1024); i >= 0; i --) + cupsFilePutChar(fp, '\n'); + + /* + * Close the file and return... + */ + + cupsFileClose(fp); +} + + +/* + * 'send_document()' - Send a file to a printer or class. + */ + +static void +send_document(cupsd_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 */ + cupsd_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 */ + cupsd_printer_t *printer; /* Current printer */ + struct stat fileinfo; /* File information */ + int kbytes; /* Size of file */ + int compression; /* Type of compression */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "send_document(%p[%d], %s)", 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")) + { + /* + * Got a printer URI; see if we also have a job-id attribute... + */ + + if ((attr = ippFindAttribute(con->request, "job-id", IPP_TAG_INTEGER)) == NULL) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6)) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_ipp_status(con, IPP_FORBIDDEN, + _("You are not authorized to send document " + "for job #%d owned by \"%s\"!"), + jobid, job->username); + return; + } + + /* + * OK, see if the client is sending the document compressed - CUPS + * only supports "none" and "gzip". + */ + + compression = CUPS_FILE_NONE; + + if ((attr = ippFindAttribute(con->request, "compression", IPP_TAG_KEYWORD)) != NULL) + { + if (strcmp(attr->values[0].string.text, "none") +#ifdef HAVE_LIBZ + && strcmp(attr->values[0].string.text, "gzip") +#endif /* HAVE_LIBZ */ + ) + { + send_ipp_status(con, IPP_ATTRIBUTES, _("Unsupported compression \"%s\"!"), + attr->values[0].string.text); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_KEYWORD, + "compression", NULL, attr->values[0].string.text); + return; + } + +#ifdef HAVE_LIBZ + if (!strcmp(attr->values[0].string.text, "gzip")) + compression = CUPS_FILE_GZIP; +#endif /* HAVE_LIBZ */ + } + + /* + * Do we have a file to print? + */ + + if (!con->filename) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("No file!?!")); + 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) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"!"), + format->values[0].string.text); + 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... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, "send_document: auto-typing file..."); + + filetype = mimeFileType(MimeDatabase, con->filename, &compression); + + 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) + { + send_ipp_status(con, IPP_DOCUMENT_FORMAT, + _("Unsupported format \'%s/%s\'!"), super, type); + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Do you have the raw file printing rules enabled?"); + + if (format) + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, + "document-format", NULL, format->values[0].string.text); + + return; + } + + cupsdLogMessage(CUPSD_LOG_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, compression)) + return; + + if (job->dtype & CUPS_PRINTER_CLASS) + printer = cupsdFindClass(job->dest); + else + printer = cupsdFindPrinter(job->dest); + + if (stat(con->filename, &fileinfo)) + kbytes = 0; + else + kbytes = (fileinfo.st_size + 1023) / 1024; + + cupsdUpdateQuota(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); + + cupsdClearString(&con->filename); + + cupsdLogMessage(CUPSD_LOG_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 | CUPS_PRINTER_IMPLICIT)) && + (attr = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL && + attr->num_values > 1) + { + /* + * Yes... + */ + + cupsdLogMessage(CUPSD_LOG_INFO, + "Adding end banner page \"%s\" to job %d.", + attr->values[1].string.text, job->id); + + kbytes = copy_banner(con, job, attr->values[1].string.text); + + cupsdUpdateQuota(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; + } + + cupsdSaveJob(job); + + /* + * Start the job if possible... Since cupsdCheckJobs() can cancel a + * job if it doesn't print, we need to re-find the job afterwards... + */ + + jobid = job->id; + + cupsdCheckJobs(); + + job = cupsdFindJob(jobid); + } + 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; + cupsdSaveJob(job); + } + } + + /* + * Fill in the response info... + */ + + snprintf(job_uri, sizeof(job_uri), "http://%s:%d/jobs/%d", ServerName, + LocalPort, jobid); + + 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", jobid); + + ippAddInteger(con->response, IPP_TAG_JOB, IPP_TAG_ENUM, "job-state", + job ? job->state->values[0].integer : IPP_JOB_CANCELLED); + add_job_state_reasons(con, job); + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'send_http_error()' - Send a HTTP error back to the IPP client. + */ + +static void +send_http_error(cupsd_client_t *con, /* I - Client connection */ + http_status_t status) /* I - HTTP status code */ +{ + cupsdLogMessage(CUPSD_LOG_ERROR, "%s: %s", + ippOpString(con->request->request.op.operation_id), + httpStatus(status)); + + cupsdSendError(con, status); + + ippDelete(con->response); + con->response = NULL; + + return; +} + + +/* + * 'send_ipp_status()' - Send a status back to the IPP client. + */ + +static void +send_ipp_status(cupsd_client_t *con, /* I - Client connection */ + ipp_status_t status, /* I - IPP status code */ + const char *message, /* I - Status message */ + ...) /* I - Additional args as needed */ +{ + va_list ap; /* Pointer to additional args */ + char formatted[1024]; /* Formatted errror message */ + + + if (message) + { + va_start(ap, message); + vsnprintf(formatted, sizeof(formatted), + _cupsLangString(con->language, message), ap); + va_end(ap); + + cupsdLogMessage(status >= IPP_BAD_REQUEST ? CUPSD_LOG_ERROR : CUPSD_LOG_INFO, + "%s %s: %s", + ippOpString(con->request->request.op.operation_id), + ippErrorString(status), formatted); + } + else + cupsdLogMessage(status >= IPP_BAD_REQUEST ? CUPSD_LOG_ERROR : CUPSD_LOG_INFO, + "%s %s", + ippOpString(con->request->request.op.operation_id), + 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); + + if (message) + ippAddString(con->response, IPP_TAG_OPERATION, IPP_TAG_TEXT, + "status-message", NULL, formatted); +} + + +/* + * 'set_default()' - Set the default destination... + */ + +static void +set_default(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_default(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(DefaultPolicyPtr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Set it as the default... + */ + + DefaultPrinter = printer; + + cupsdSaveAllPrinters(); + cupsdSaveAllClasses(); + + cupsdWritePrintcap(); + + cupsdLogMessage(CUPSD_LOG_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(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Job URI */ +{ + ipp_attribute_t *attr, /* Current attribute */ + *attr2; /* Job attribute */ + int jobid; /* Job ID */ + cupsd_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 */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "set_job_attrs(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Start with "everything is OK" status... + */ + + con->response->request.status.status_code = IPP_OK; + + /* + * 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) + { + send_ipp_status(con, IPP_BAD_REQUEST, + _("Got a printer-uri attribute but no job-id!")); + return; + } + + jobid = attr->values[0].integer; + } + else + { + /* + * Got a job URI; parse it to get the job ID... + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (strncmp(resource, "/jobs/", 6) != 0) + { + /* + * Not a valid URI! + */ + + send_ipp_status(con, IPP_BAD_REQUEST, + _("Bad job-uri attribute \"%s\"!"), + uri->values[0].string.text); + return; + } + + jobid = atoi(resource + 6); + } + + /* + * See if the job exists... + */ + + if ((job = cupsdFindJob(jobid)) == NULL) + { + /* + * Nope - return a "not found" error... + */ + + send_ipp_status(con, IPP_NOT_FOUND, _("Job #%d does not exist!"), jobid); + return; + } + + /* + * See if the job has been completed... + */ + + if (job->state->values[0].integer > IPP_JOB_STOPPED) + { + /* + * Return a "not-possible" error... + */ + + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job #%d is finished and cannot be altered!"), jobid); + return; + } + + /* + * See if the job is owned by the requesting user... + */ + + if (!validate_user(job, con, job->username, username, sizeof(username))) + { + send_ipp_status(con, IPP_FORBIDDEN, + _("You are not authorized to alter job id " + "%d owned by \"%s\"!"), + jobid, job->username); + 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, "attributes-charset") || + !strcmp(attr->name, "attributes-natural-language") || + !strcmp(attr->name, "document-compression") || + !strcmp(attr->name, "document-format") || + !strcmp(attr->name, "job-detailed-status-messages") || + !strcmp(attr->name, "job-document-access-errors") || + !strcmp(attr->name, "job-id") || + !strcmp(attr->name, "job-k-octets") || + !strcmp(attr->name, "job-originating-host-name") || + !strcmp(attr->name, "job-originating-user-name") || + !strcmp(attr->name, "job-printer-up-time") || + !strcmp(attr->name, "job-printer-uri") || + !strcmp(attr->name, "job-sheets") || + !strcmp(attr->name, "job-state-message") || + !strcmp(attr->name, "job-state-reasons") || + !strcmp(attr->name, "job-uri") || + !strcmp(attr->name, "number-of-documents") || + !strcmp(attr->name, "number-of-intervening-jobs") || + !strcmp(attr->name, "output-device-assigned") || + !strncmp(attr->name, "date-time-at-", 13) || + !strncmp(attr->name, "job-impressions", 15) || + !strncmp(attr->name, "job-k-octets", 12) || + !strncmp(attr->name, "job-media-sheets", 16) || + !strncmp(attr->name, "time-at-", 8)) + { + /* + * Read-only attrs! + */ + + send_ipp_status(con, IPP_ATTRIBUTES_NOT_SETTABLE, + _("%s cannot be changed."), attr->name); + + if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) + attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + + continue; + } + + if (!strcmp(attr->name, "job-priority")) + { + /* + * Change the job priority... + */ + + if (attr->value_tag != IPP_TAG_INTEGER) + { + send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-priority value!")); + + if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) + attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + } + else if (job->state->values[0].integer >= IPP_JOB_PROCESSING) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job is completed and cannot be changed.")); + return; + } + else if (con->response->request.status.status_code == IPP_OK) + cupsdSetJobPriority(job, attr->values[0].integer); + } + else if (!strcmp(attr->name, "job-state")) + { + /* + * Change the job state... + */ + + if (attr->value_tag != IPP_TAG_ENUM) + { + send_ipp_status(con, IPP_REQUEST_VALUE, _("Bad job-state value!")); + + if ((attr2 = copy_attribute(con->response, attr, 0)) != NULL) + attr2->group_tag = IPP_TAG_UNSUPPORTED_GROUP; + } + else + { + switch (attr->values[0].integer) + { + case IPP_JOB_PENDING : + case IPP_JOB_HELD : + if (job->state->values[0].integer > IPP_JOB_HELD) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job state cannot be changed.")); + return; + } + else if (con->response->request.status.status_code == IPP_OK) + job->state->values[0].integer = attr->values[0].integer; + break; + + case IPP_JOB_PROCESSING : + case IPP_JOB_STOPPED : + if (job->state->values[0].integer != attr->values[0].integer) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job state cannot be changed.")); + return; + } + break; + + case IPP_JOB_CANCELLED : + case IPP_JOB_ABORTED : + case IPP_JOB_COMPLETED : + if (job->state->values[0].integer > IPP_JOB_PROCESSING) + { + send_ipp_status(con, IPP_NOT_POSSIBLE, + _("Job state cannot be changed.")); + return; + } + else if (con->response->request.status.status_code == IPP_OK) + { + cupsdCancelJob(job, 0); + + if (JobHistory) + { + job->state->values[0].integer = attr->values[0].integer; + cupsdSaveJob(job); + } + } + break; + } + } + } + else if (con->response->request.status.status_code != IPP_OK) + continue; + else if ((attr2 = ippFindAttribute(job->attrs, attr->name, IPP_TAG_ZERO)) != NULL) + { + /* + * Some other value; first free the old value... + */ + + if (job->attrs->prev) + job->attrs->prev->next = attr2->next; + else + job->attrs->attrs = attr2->next; + + if (job->attrs->last == attr2) + job->attrs->last = job->attrs->prev; + + _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-hold-until")) + { + cupsdSetJobHoldUntil(job, attr->values[0].string.text); + + if (!strcmp(attr->values[0].string.text, "no-hold")) + cupsdReleaseJob(job); + else + cupsdHoldJob(job); + } + } + else if (attr->value_tag == IPP_TAG_DELETEATTR) + { + /* + * Delete the attribute... + */ + + if ((attr2 = ippFindAttribute(job->attrs, attr->name, + IPP_TAG_ZERO)) != NULL) + { + if (job->attrs->prev) + job->attrs->prev->next = attr2->next; + else + job->attrs->attrs = attr2->next; + + if (attr2 == job->attrs->last) + job->attrs->last = job->attrs->prev; + + _ipp_free_attr(attr2); + } + } + else + { + /* + * Add new option by copying it... + */ + + copy_attribute(job->attrs, attr, 0); + } + } + + /* + * Save the job... + */ + + cupsdSaveJob(job); + + /* + * Start jobs if possible... + */ + + cupsdCheckJobs(); +} + + +/* + * 'start_printer()' - Start a printer. + */ + +static void +start_printer(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer data */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "start_printer(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Start the printer... + */ + + printer->state_message[0] = '\0'; + + cupsdStartPrinter(printer, 1); + + if (dtype & CUPS_PRINTER_CLASS) + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" started by \"%s\".", name, + con->username); + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" started by \"%s\".", name, + con->username); + + cupsdCheckJobs(); + + /* + * Everything was ok, so return OK status... + */ + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'stop_printer()' - Stop a printer. + */ + +static void +stop_printer(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer data */ + ipp_attribute_t *attr; /* printer-state-message attribute */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "stop_printer(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((name = cupsdValidateDest(host, resource, &dtype, &printer)) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Stop the printer... + */ + + if ((attr = ippFindAttribute(con->request, "printer-state-message", + IPP_TAG_TEXT)) == NULL) + strcpy(printer->state_message, "Paused"); + else + { + strlcpy(printer->state_message, attr->values[0].string.text, + sizeof(printer->state_message)); + } + + cupsdStopPrinter(printer, 1); + + if (dtype & CUPS_PRINTER_CLASS) + cupsdLogMessage(CUPSD_LOG_INFO, "Class \"%s\" stopped by \"%s\".", name, + con->username); + else + cupsdLogMessage(CUPSD_LOG_INFO, "Printer \"%s\" stopped by \"%s\".", name, + con->username); + + /* + * Everything was ok, so return OK status... + */ + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'user_allowed()' - See if a user is allowed to print to a queue. + */ + +static int /* O - 0 if not allowed, 1 if allowed */ +user_allowed(cupsd_printer_t *p, /* I - Printer or class */ + const char *username) /* I - Username */ +{ + int i; /* Looping var */ + struct passwd *pw; /* User password data */ + + + if (p->num_users == 0) + return (1); + + if (!strcmp(username, "root")) + return (1); + + pw = getpwnam(username); + endpwent(); + + for (i = 0; i < p->num_users; i ++) + { + if (p->users[i][0] == '@') + { + /* + * Check group membership... + */ + + if (cupsdCheckGroup(username, pw, p->users[i] + 1)) + break; + } + else if (!strcasecmp(username, p->users[i])) + break; + } + + return ((i < p->num_users) != p->deny_users); +} + + +/* + * 'validate_job()' - Validate printer options and destination. + */ + +static void +validate_job(cupsd_client_t *con, /* I - Client connection */ + ipp_attribute_t *uri) /* I - Printer URI */ +{ + http_status_t status; /* Policy status */ + 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 */ + cupsd_printer_t *printer; /* Printer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "validate_job(%p[%d], %s)", con, + con->http.fd, uri->values[0].string.text); + + /* + * 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) + { + send_ipp_status(con, IPP_ATTRIBUTES, + _("Unsupported compression attribute %s!"), + attr->values[0].string.text); + 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) + { + send_ipp_status(con, IPP_BAD_REQUEST, _("Bad document-format \"%s\"!"), + format->values[0].string.text); + return; + } + + if ((strcmp(super, "application") != 0 || + strcmp(type, "octet-stream") != 0) && + mimeType(MimeDatabase, super, type) == NULL) + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Do you have the raw file printing rules enabled?"); + send_ipp_status(con, IPP_DOCUMENT_FORMAT, + _("Unsupported format \"%s\"!"), + format->values[0].string.text); + ippAddString(con->response, IPP_TAG_UNSUPPORTED_GROUP, IPP_TAG_MIMETYPE, + "document-format", NULL, format->values[0].string.text); + return; + } + } + + /* + * Is the destination valid? + */ + + httpSeparateURI(uri->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if (cupsdValidateDest(host, resource, &dtype, &printer) == NULL) + { + /* + * Bad URI... + */ + + send_ipp_status(con, IPP_NOT_FOUND, + _("The printer or class was not found.")); + return; + } + + /* + * Check policy... + */ + + if ((status = cupsdCheckPolicy(printer->op_policy_ptr, con, NULL)) != HTTP_OK) + { + send_http_error(con, status); + return; + } + + /* + * Everything was ok, so return OK status... + */ + + con->response->request.status.status_code = IPP_OK; +} + + +/* + * 'validate_name()' - Make sure the printer name only contains valid chars. + */ + +static int /* O - 0 if name is no good, 1 if name is good */ +validate_name(const char *name) /* I - Name to check */ +{ + const char *ptr; /* Pointer into name */ + + + /* + * Scan the whole name... + */ + + for (ptr = name; *ptr; ptr ++) + if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || *ptr == '#') + return (0); + + /* + * All the characters are good; validate the length, too... + */ + + return ((ptr - name) < 128); +} + + +/* + * 'validate_user()' - Validate the user for the request. + */ + +static int /* O - 1 if permitted, 0 otherwise */ +validate_user(cupsd_job_t *job, /* I - Job */ + cupsd_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 */ +{ + ipp_attribute_t *attr; /* requesting-user-name attribute */ + cupsd_printer_t *printer; /* Printer for job */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "validate_user(job=%d, con=%d, owner=\"%s\", username=%p, " + "userlen=%d)", + job ? job->id : 0, con->http.fd, owner ? owner : "(null)", + username, userlen); + + /* + * Validate input... + */ + + if (!con || !owner || !username || userlen <= 0) + return (0); + + /* + * Get the best authenticated username that is available. + */ + + if (con->username[0]) + strlcpy(username, con->username, userlen); + else if ((attr = ippFindAttribute(con->request, "requesting-user-name", + IPP_TAG_NAME)) != NULL) + strlcpy(username, attr->values[0].string.text, userlen); + else + strlcpy(username, "anonymous", userlen); + + /* + * Check the username against the owner... + */ + + if (job->dtype & CUPS_PRINTER_CLASS) + printer = cupsdFindClass(job->dest); + else + printer = cupsdFindPrinter(job->dest); + + return (cupsdCheckPolicy(printer ? printer->op_policy_ptr : DefaultPolicyPtr, + con, owner) == HTTP_OK); +} + + +/* + * End of "$Id: ipp.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/scheduler/job.c b/scheduler/job.c new file mode 100644 index 000000000..e66a7f1a1 --- /dev/null +++ b/scheduler/job.c @@ -0,0 +1,2718 @@ +/* + * "$Id: job.c 4906 2006-01-10 20:53:28Z mike $" + * + * Job management routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddJob() - Add a new job to the job queue... + * cupsdCancelJob() - Cancel the specified print job. + * cupsdCancelJobs() - Cancel all jobs for the given destination/user... + * cupsdCheckJobs() - Check the pending jobs and start any if the + * destination is available. + * cupsdCleanJobs() - Clean out old jobs. + * cupsdFreeAllJobs() - Free all jobs from memory. + * cupsdFindJob() - Find the specified job. + * cupsdGetPrinterJobCount() - Get the number of pending, processing, + * or held jobs in a printer or class. + * cupsdGetUserJobCount() - Get the number of pending, processing, + * or held jobs for a user. + * cupsdHoldJob() - Hold the specified job. + * cupsdLoadAllJobs() - Load all jobs from disk. + * cupsdMoveJob() - Move the specified job to a different + * destination. + * cupsdReleaseJob() - Release the specified job. + * cupsdRestartJob() - Restart the specified job. + * cupsdSaveJob() - Save a job to disk. + * cupsdSetJobHoldUntil() - Set the hold time for a job... + * cupsdSetJobPriority() - Set the priority of a job, moving it up/down + * in the list as needed. + * cupsdStartJob() - Start a print job. + * cupsdStopAllJobs() - Stop all print jobs. + * cupsdStopJob() - Stop a print job. + * cupsdUpdateJob() - Read a status update from a job's filters. + * compare_active_jobs() - Compare the job IDs and priorities of two jobs. + * compare_jobs() - Compare the job IDs of two jobs. + * ipp_length() - Compute the size of the buffer needed to hold + * the textual IPP attributes. + * set_hold_until() - Set the hold time and update job-hold-until attribute. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" +#include +#include +#include + + +/* + * Local globals... + */ + +static mime_filter_t gziptoany_filter = + { + NULL, /* Source type */ + NULL, /* Destination type */ + 0, /* Cost */ + "gziptoany" /* Filter program to run */ + }; + + +/* + * Local functions... + */ + +static int compare_active_jobs(void *first, void *second, void *data); +static int compare_jobs(void *first, void *second, void *data); +static int ipp_length(ipp_t *ipp); +static void set_time(cupsd_job_t *job, const char *name); +static void set_hold_until(cupsd_job_t *job, time_t holdtime); + + +/* + * 'cupsdAddJob()' - Add a new job to the job queue... + */ + +cupsd_job_t * /* O - New job record */ +cupsdAddJob(int priority, /* I - Job priority */ + const char *dest) /* I - Job destination */ +{ + cupsd_job_t *job; /* New job record */ + + + job = calloc(sizeof(cupsd_job_t), 1); + + job->id = NextJobId ++; + job->priority = priority; + job->back_pipes[0] = -1; + job->back_pipes[1] = -1; + job->print_pipes[0] = -1; + job->print_pipes[1] = -1; + + cupsdSetString(&job->dest, dest); + + /* + * Add the new job to the "all jobs" and "active jobs" lists... + */ + + cupsArrayAdd(Jobs, job); + cupsArrayAdd(ActiveJobs, job); + + return (job); +} + + +/* + * 'cupsdCancelJob()' - Cancel the specified print job. + */ + +void +cupsdCancelJob(cupsd_job_t *job, /* I - Job to cancel */ + int purge) /* I - Purge jobs? */ +{ + int i; /* Looping var */ + char filename[1024]; /* Job filename */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdCancelJob: id = %d", job->id); + + /* + * Remove the job from the active list... + */ + + cupsArrayRemove(ActiveJobs, job); + + /* + * Stop any processes that are working on the current job... + */ + + if (job->state->values[0].integer == IPP_JOB_PROCESSING) + cupsdStopJob(job, 0); + + cupsArrayRemove(ActiveJobs, job); + + job->state->values[0].integer = IPP_JOB_CANCELLED; + + set_time(job, "time-at-completed"); + + cupsdExpireSubscriptions(NULL, job); + + /* + * Remove any authentication data... + */ + + snprintf(filename, sizeof(filename), "%s/a%05d", RequestRoot, + job->id); + unlink(filename); + + /* + * Remove the print file for good if we aren't preserving jobs or + * files... + */ + + job->current_file = 0; + + if (!JobHistory || !JobFiles || purge || + (job->dtype & CUPS_PRINTER_REMOTE)) + for (i = 1; i <= job->num_files; i ++) + { + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, + job->id, i); + unlink(filename); + } + + if (JobHistory && !purge && !(job->dtype & CUPS_PRINTER_REMOTE)) + { + /* + * Save job state info... + */ + + cupsdSaveJob(job); + } + else + { + /* + * Remove the job info file... + */ + + snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, + job->id); + unlink(filename); + + /* + * Remove the job from the "all jobs" list... + */ + + cupsArrayRemove(Jobs, job); + + /* + * Free all memory used... + */ + + if (job->attrs != NULL) + ippDelete(job->attrs); + + if (job->num_files > 0) + { + free(job->compressions); + free(job->filetypes); + } + + cupsdClearString(&job->username); + cupsdClearString(&job->dest); + + free(job); + } +} + + +/* + * 'cupsdCancelJobs()' - Cancel all jobs for the given destination/user... + */ + +void +cupsdCancelJobs(const char *dest, /* I - Destination to cancel */ + const char *username, /* I - Username or NULL */ + int purge) /* I - Purge jobs? */ +{ + cupsd_job_t *job; /* Current job */ + + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + if ((dest == NULL || !strcmp(job->dest, dest)) && + (username == NULL || !strcmp(job->username, username))) + { + /* + * Cancel all jobs matching this destination/user... + */ + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + purge ? "Job purged." : "Job canceled."); + + cupsdCancelJob(job, purge); + } + + cupsdCheckJobs(); +} + + +/* + * 'cupsdCheckJobs()' - Check the pending jobs and start any if the destination + * is available. + */ + +void +cupsdCheckJobs(void) +{ + cupsd_job_t *job; /* Current job in queue */ + cupsd_printer_t *printer, /* Printer destination */ + *pclass; /* Printer class destination */ + + + DEBUG_puts("cupsdCheckJobs()"); + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + { + /* + * Start held jobs if they are ready... + */ + + if (job->state->values[0].integer == IPP_JOB_HELD && + job->hold_until && + job->hold_until < time(NULL)) + job->state->values[0].integer = IPP_JOB_PENDING; + + /* + * Start pending jobs if the destination is available... + */ + + if (job->state->values[0].integer == IPP_JOB_PENDING && !NeedReload) + { + printer = cupsdFindDest(job->dest); + pclass = NULL; + + while (printer && + (printer->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_CLASS))) + { + /* + * If the class is remote, just pass it to the remote server... + */ + + pclass = printer; + + if (!(pclass->type & CUPS_PRINTER_REMOTE)) + { + if (pclass->state != IPP_PRINTER_STOPPED) + printer = cupsdFindAvailablePrinter(job->dest); + else + printer = NULL; + } + } + + if (!printer && !pclass) + { + /* + * Whoa, the printer and/or class for this destination went away; + * cancel the job... + */ + + cupsdLogMessage(CUPSD_LOG_WARN, + "Printer/class %s has gone away; cancelling job %d!", + job->dest, job->id); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the destination printer/class has gone away."); + + cupsdCancelJob(job, 1); + } + else if (printer) + { + /* + * See if the printer is available or remote and not printing a job; + * if so, start the job... + */ + + if (pclass) + { + /* + * Add/update a job-actual-printer-uri attribute for this job + * so that we know which printer actually printed the job... + */ + + ipp_attribute_t *attr; /* job-actual-printer-uri attribute */ + + + if ((attr = ippFindAttribute(job->attrs, "job-actual-printer-uri", + IPP_TAG_URI)) != NULL) + cupsdSetString(&attr->values[0].string.text, printer->uri); + else + ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_URI, + "job-actual-printer-uri", NULL, printer->uri); + } + + if (printer->state == IPP_PRINTER_IDLE || /* Printer is idle */ + ((printer->type & CUPS_PRINTER_REMOTE) && /* Printer is remote */ + !printer->job)) /* and not printing a job */ + cupsdStartJob(job, printer); + } + } + } +} + + +/* + * 'cupsdCleanJobs()' - Clean out old jobs. + */ + +void +cupsdCleanJobs(void) +{ + cupsd_job_t *job; /* Current job */ + + + if (!MaxJobs) + return; + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job && cupsArrayCount(Jobs) >= MaxJobs; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + if (job->state->values[0].integer >= IPP_JOB_CANCELLED) + cupsdCancelJob(job, 1); +} + + +/* + * 'cupsdFinishJob()' - Finish a job. + */ + +void +cupsdFinishJob(cupsd_job_t *job) /* I - Job */ +{ + int job_history; /* Did cupsdCancelJob() keep the job? */ + cupsd_printer_t *printer; /* Current printer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdFinishJob: job %d, file %d is complete.", + job->id, job->current_file - 1); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFinishJob: job->status is %d", + job->status); + + if (job->status_buffer && job->current_file >= job->num_files) + { + /* + * Close the pipe and clear the input bit. + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdFinishJob: Removing fd %d from InputSet...", + job->status_buffer->fd); + + FD_CLR(job->status_buffer->fd, InputSet); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdFinishJob: Closing status input pipe %d...", + job->status_buffer->fd); + + cupsdStatBufDelete(job->status_buffer); + + job->status_buffer = NULL; + } + + if (job->status < 0) + { + /* + * Backend had errors; stop it... + */ + + printer = job->printer; + + switch (-job->status) + { + default : + case CUPS_BACKEND_FAILED : + /* + * Backend failure, use the error-policy to determine how to + * act... + */ + + cupsdStopJob(job, 0); + job->state->values[0].integer = IPP_JOB_PENDING; + cupsdSaveJob(job); + + /* + * If the job was queued to a class, try requeuing it... For + * faxes and retry-job queues, hold the current job for 5 minutes. + */ + + if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) + cupsdCheckJobs(); + else if ((printer->type & CUPS_PRINTER_FAX) || + !strcmp(printer->error_policy, "retry-job")) + { + /* + * See how many times we've tried to send the job; if more than + * the limit, cancel the job. + */ + + job->tries ++; + + if (job->tries >= JobRetryLimit) + { + /* + * Too many tries... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "Canceling job %d since it could not be sent after %d tries.", + job->id, JobRetryLimit); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled since it could not be sent after %d tries.", + JobRetryLimit); + + cupsdCancelJob(job, 0); + } + else + { + /* + * Try again in N seconds... + */ + + set_hold_until(job, time(NULL) + JobRetryInterval); + } + } + else if (!strcmp(printer->error_policy, "abort-job")) + cupsdCancelJob(job, 0); + break; + + case CUPS_BACKEND_CANCEL : + /* + * Cancel the job... + */ + + cupsdCancelJob(job, 0); + break; + + case CUPS_BACKEND_HOLD : + /* + * Hold the job... + */ + + cupsdStopJob(job, 0); + cupsdSetJobHoldUntil(job, "indefinite"); + cupsdSaveJob(job); + break; + + case CUPS_BACKEND_STOP : + /* + * Stop the printer... + */ + + cupsdStopJob(job, 0); + cupsdSaveJob(job); + cupsdSetPrinterState(printer, IPP_PRINTER_STOPPED, 1); + break; + + case CUPS_BACKEND_AUTH_REQUIRED : + cupsdStopJob(job, 0); + cupsdSetJobHoldUntil(job, "authenticated"); + cupsdSaveJob(job); + + cupsdAddEvent(CUPSD_EVENT_JOB_STOPPED, printer, job, + "Authentication is required for job %d.", job->id); + break; + } + + /* + * Try printing another job... + */ + + cupsdCheckJobs(); + } + else if (job->status > 0) + { + /* + * Filter had errors; cancel it... + */ + + if (job->current_file < job->num_files) + cupsdStartJob(job, job->printer); + else + { + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job aborted due to filter errors; please consult the " + "error_log file for details."); + + job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE); + + cupsdCancelJob(job, 0); + + if (job_history) + { + job->state->values[0].integer = IPP_JOB_ABORTED; + cupsdSaveJob(job); + } + + cupsdCheckJobs(); + } + } + else + { + /* + * Job printed successfully; cancel it... + */ + + if (job->current_file < job->num_files) + { + FilterLevel -= job->cost; + cupsdStartJob(job, job->printer); + } + else + { + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job completed successfully."); + + job_history = JobHistory && !(job->dtype & CUPS_PRINTER_REMOTE); + + cupsdCancelJob(job, 0); + + if (job_history) + { + job->state->values[0].integer = IPP_JOB_COMPLETED; + cupsdSaveJob(job); + } + + cupsdCheckJobs(); + } + } +} + + +/* + * 'cupsdFreeAllJobs()' - Free all jobs from memory. + */ + +void +cupsdFreeAllJobs(void) +{ + cupsd_job_t *job; /* Current job */ + + + cupsdHoldSignals(); + + cupsdStopAllJobs(); + + for (job = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + { + cupsArrayRemove(Jobs, job); + cupsArrayRemove(ActiveJobs, job); + + ippDelete(job->attrs); + + if (job->num_files > 0) + { + free(job->compressions); + free(job->filetypes); + } + + free(job); + } + + cupsdReleaseSignals(); +} + + +/* + * 'cupsdFindJob()' - Find the specified job. + */ + +cupsd_job_t * /* O - Job data */ +cupsdFindJob(int id) /* I - Job ID */ +{ + cupsd_job_t key; /* Search key */ + + + key.id = id; + + return ((cupsd_job_t *)cupsArrayFind(Jobs, &key)); +} + + +/* + * 'cupsdGetPrinterJobCount()' - Get the number of pending, processing, + * or held jobs in a printer or class. + */ + +int /* O - Job count */ +cupsdGetPrinterJobCount( + const char *dest) /* I - Printer or class name */ +{ + int count; /* Job count */ + cupsd_job_t *job; /* Current job */ + + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0; + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (!strcasecmp(job->dest, dest)) + count ++; + + return (count); +} + + +/* + * 'cupsdGetUserJobCount()' - Get the number of pending, processing, + * or held jobs for a user. + */ + +int /* O - Job count */ +cupsdGetUserJobCount( + const char *username) /* I - Username */ +{ + int count; /* Job count */ + cupsd_job_t *job; /* Current job */ + + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs), count = 0; + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (!strcasecmp(job->username, username)) + count ++; + + return (count); +} + + +/* + * 'cupsdHoldJob()' - Hold the specified job. + */ + +void +cupsdHoldJob(cupsd_job_t *job) /* I - Job data */ +{ + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdHoldJob: id = %d", job->id); + + if (job->state->values[0].integer == IPP_JOB_PROCESSING) + cupsdStopJob(job, 0); + + DEBUG_puts("cupsdHoldJob: setting state to held..."); + + job->state->values[0].integer = IPP_JOB_HELD; + + cupsdSaveJob(job); + + cupsdCheckJobs(); +} + + +/* + * 'cupsdLoadAllJobs()' - Load all jobs from disk. + */ + +void +cupsdLoadAllJobs(void) +{ + cups_dir_t *dir; /* Directory */ + cups_dentry_t *dent; /* Directory entry */ + char filename[1024]; /* Full filename of job file */ + int fd; /* File descriptor */ + cupsd_job_t *job; /* New 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 */ + const char *dest; /* Destination */ + mime_type_t **filetypes; /* New filetypes array */ + int *compressions; /* New compressions array */ + + + /* + * First create the job lists... + */ + + if (!Jobs) + Jobs = cupsArrayNew(compare_jobs, NULL); + + if (!ActiveJobs) + ActiveJobs = cupsArrayNew(compare_active_jobs, NULL); + + /* + * Then open the requests directory... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdLoadAllJobs: Scanning %s...", + RequestRoot); + + if ((dir = cupsDirOpen(RequestRoot)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Unable to open spool directory %s: %s", + RequestRoot, strerror(errno)); + return; + } + + /* + * Read all the c##### files... + */ + + while ((dent = cupsDirRead(dir)) != NULL) + if (strlen(dent->filename) >= 6 && dent->filename[0] == 'c') + { + /* + * Allocate memory for the job... + */ + + if ((job = calloc(sizeof(cupsd_job_t), 1)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Ran out of memory for jobs!"); + cupsDirClose(dir); + return; + } + + if ((job->attrs = ippNew()) == NULL) + { + free(job); + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Ran out of memory for job attributes!"); + cupsDirClose(dir); + return; + } + + /* + * Assign the job ID... + */ + + job->id = atoi(dent->filename + 1); + job->back_pipes[0] = -1; + job->back_pipes[1] = -1; + job->print_pipes[0] = -1; + job->print_pipes[1] = -1; + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdLoadAllJobs: Loading attributes for job %d...", + job->id); + + if (job->id >= NextJobId) + NextJobId = job->id + 1; + + /* + * Load the job control file... + */ + + snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->filename); + if ((fd = open(filename, O_RDONLY)) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Unable to open job control file \"%s\" - %s!", + filename, strerror(errno)); + ippDelete(job->attrs); + free(job); + unlink(filename); + continue; + } + else + { + if (ippReadFile(fd, job->attrs) != IPP_DATA) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Unable to read job control file \"%s\"!", + filename); + close(fd); + ippDelete(job->attrs); + free(job); + unlink(filename); + continue; + } + + close(fd); + } + + if ((job->state = ippFindAttribute(job->attrs, "job-state", IPP_TAG_ENUM)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Missing or bad job-state attribute in control file \"%s\"!", + filename); + ippDelete(job->attrs); + free(job); + unlink(filename); + continue; + } + + if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: No job-printer-uri attribute in control file \"%s\"!", + filename); + ippDelete(job->attrs); + free(job); + unlink(filename); + continue; + } + + httpSeparateURI(attr->values[0].string.text, method, sizeof(method), + username, sizeof(username), host, sizeof(host), &port, + resource, sizeof(resource)); + + if ((dest = cupsdValidateDest(host, resource, &(job->dtype), + NULL)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Unable to queue job for destination \"%s\"!", + attr->values[0].string.text); + ippDelete(job->attrs); + free(job); + unlink(filename); + continue; + } + + cupsdSetString(&job->dest, dest); + + job->sheets = ippFindAttribute(job->attrs, "job-media-sheets-completed", + IPP_TAG_INTEGER); + job->job_sheets = ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_NAME); + + if ((attr = ippFindAttribute(job->attrs, "job-priority", IPP_TAG_INTEGER)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Missing or bad job-priority attribute in control file \"%s\"!", + filename); + ippDelete(job->attrs); + free(job); + unlink(filename); + continue; + } + job->priority = attr->values[0].integer; + + if ((attr = ippFindAttribute(job->attrs, "job-originating-user-name", IPP_TAG_NAME)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Missing or bad job-originating-user-name attribute in control file \"%s\"!", + filename); + ippDelete(job->attrs); + free(job); + unlink(filename); + continue; + } + cupsdSetString(&job->username, attr->values[0].string.text); + + /* + * Insert the job into the array, sorting by job priority and ID... + */ + + cupsArrayAdd(Jobs, job); + if (job->state->values[0].integer < IPP_JOB_STOPPED) + cupsArrayAdd(ActiveJobs,job); + + /* + * Set the job hold-until time and state... + */ + + 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 + cupsdSetJobHoldUntil(job, attr->values[0].string.text); + } + else if (job->state->values[0].integer == IPP_JOB_PROCESSING) + job->state->values[0].integer = IPP_JOB_PENDING; + } + + /* + * Read all the d##### files... + */ + + cupsDirRewind(dir); + + while ((dent = cupsDirRead(dir)) != NULL) + if (strlen(dent->filename) > 7 && dent->filename[0] == 'd' && + strchr(dent->filename, '-')) + { + /* + * Find the job... + */ + + jobid = atoi(dent->filename + 1); + fileid = atoi(strchr(dent->filename, '-') + 1); + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdLoadAllJobs: Auto-typing document file %s...", + dent->filename); + + snprintf(filename, sizeof(filename), "%s/%s", RequestRoot, dent->filename); + + if ((job = cupsdFindJob(jobid)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllJobs: Orphaned print file \"%s\"!", + filename); + unlink(filename); + continue; + } + + if (fileid > job->num_files) + { + if (job->num_files == 0) + { + compressions = (int *)calloc(fileid, sizeof(int)); + filetypes = (mime_type_t **)calloc(fileid, sizeof(mime_type_t *)); + } + else + { + compressions = (int *)realloc(job->compressions, + sizeof(int) * fileid); + filetypes = (mime_type_t **)realloc(job->filetypes, + sizeof(mime_type_t *) * fileid); + } + + if (compressions == NULL || filetypes == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "cupsdLoadAllJobs: Ran out of memory for job file types!"); + continue; + } + + job->compressions = compressions; + job->filetypes = filetypes; + job->num_files = fileid; + } + + job->filetypes[fileid - 1] = mimeFileType(MimeDatabase, filename, + job->compressions + fileid - 1); + + if (job->filetypes[fileid - 1] == NULL) + job->filetypes[fileid - 1] = mimeType(MimeDatabase, "application", + "vnd.cups-raw"); + } + + cupsDirClose(dir); + + /* + * Clean out old jobs as needed... + */ + + cupsdCleanJobs(); +} + + +/* + * 'cupsdMoveJob()' - Move the specified job to a different destination. + */ + +void +cupsdMoveJob(cupsd_job_t *job, /* I - Job */ + const char *dest) /* I - Destination */ +{ + ipp_attribute_t *attr; /* job-printer-uri attribute */ + cupsd_printer_t *p; /* Destination printer or class */ + + + /* + * Find the printer... + */ + + if ((p = cupsdFindDest(dest)) == NULL) + return; + + /* + * Don't move completed jobs... + */ + + if (job->state->values[0].integer >= IPP_JOB_PROCESSING) + return; + + /* + * Change the destination information... + */ + + cupsdSetString(&job->dest, dest); + job->dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_REMOTE | + CUPS_PRINTER_IMPLICIT); + + if ((attr = ippFindAttribute(job->attrs, "job-printer-uri", IPP_TAG_URI)) != NULL) + cupsdSetString(&(attr->values[0].string.text), p->uri); + + cupsdSaveJob(job); +} + + +/* + * 'cupsdReleaseJob()' - Release the specified job. + */ + +void +cupsdReleaseJob(cupsd_job_t *job) /* I - Job */ +{ + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdReleaseJob: id = %d", job->id); + + if (job->state->values[0].integer == IPP_JOB_HELD) + { + DEBUG_puts("cupsdReleaseJob: setting state to pending..."); + + job->state->values[0].integer = IPP_JOB_PENDING; + cupsdSaveJob(job); + cupsdCheckJobs(); + } +} + + +/* + * 'cupsdRestartJob()' - Restart the specified job. + */ + +void +cupsdRestartJob(cupsd_job_t *job) /* I - Job */ +{ + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdRestartJob: id = %d", job->id); + + if (job->state->values[0].integer == IPP_JOB_STOPPED || JobFiles) + { + job->tries = 0; + job->state->values[0].integer = IPP_JOB_PENDING; + cupsdSaveJob(job); + cupsdCheckJobs(); + } +} + + +/* + * 'cupsdSaveJob()' - Save a job to disk. + */ + +void +cupsdSaveJob(cupsd_job_t *job) /* I - Job */ +{ + char filename[1024]; /* Job control filename */ + int fd; /* File descriptor */ + + + snprintf(filename, sizeof(filename), "%s/c%05d", RequestRoot, job->id); + + if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdSaveJob: Unable to create job control file \"%s\" - %s.", + filename, strerror(errno)); + return; + } + + fchmod(fd, 0600); + fchown(fd, RunUser, Group); + + ippWriteFile(fd, job->attrs); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdSaveJob: Closing file %d...", fd); + + close(fd); +} + + +/* + * 'cupsdSetJobHoldUntil()' - Set the hold time for a job... + */ + +void +cupsdSetJobHoldUntil(cupsd_job_t *job, /* I - Job */ + const char *when) /* I - When to resume */ +{ + time_t curtime; /* Current time */ + struct tm *curdate; /* Current date */ + int hour; /* Hold hour */ + int minute; /* Hold minute */ + int second; /* Hold second */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetJobHoldUntil(%d, \"%s\")", + job->id, when); + + second = 0; + + if (!strcmp(when, "indefinite") || !strcmp(when, "authenticated")) + { + /* + * Hold indefinitely... + */ + + job->hold_until = 0; + } + else if (!strcmp(when, "day-time")) + { + /* + * 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") || strcmp(when, "night")) + { + /* + * 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")) + { + /* + * 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")) + { + /* + * 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")) + { + /* + * Hold to weekend unless we are in the weekend. + */ + + curtime = time(NULL); + curdate = localtime(&curtime); + + if (curdate->tm_wday || 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; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdSetJobHoldUntil: hold_until = %d", + (int)job->hold_until); +} + + +/* + * 'cupsdSetJobPriority()' - Set the priority of a job, moving it up/down in + * the list as needed. + */ + +void +cupsdSetJobPriority( + cupsd_job_t *job, /* I - Job ID */ + int priority) /* I - New priority (0 to 100) */ +{ + ipp_attribute_t *attr; /* Job attribute */ + + + /* + * Don't change completed jobs... + */ + + if (job->state->values[0].integer >= IPP_JOB_PROCESSING) + return; + + /* + * Set the new priority and re-add the job into the active list... + */ + + cupsArrayRemove(ActiveJobs, job); + + 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); + + cupsArrayAdd(ActiveJobs, job); + + cupsdSaveJob(job); +} + + +/* + * 'cupsdStartJob()' - Start a print job. + */ + +void +cupsdStartJob(cupsd_job_t *job, /* I - Job ID */ + cupsd_printer_t *printer) /* I - Printer to print 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 */ + *valptr; /* Pointer in value string */ + 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 */ + int envc; /* Number of environment variables */ + char *argv[8], /* Filter command-line arguments */ + sani_uri[1024], /* Sanitized DEVICE_URI env var */ + 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 */ + *envp[100], /* Environment variables */ + charset[255], /* CHARSET environment variable */ + class_name[255],/* CLASS environment variable */ + classification[1024], + /* CLASSIFICATION environment variable */ + content_type[1024], + /* CONTENT_TYPE environment variable */ + device_uri[1024], + /* DEVICE_URI environment variable */ + lang[255], /* LANG environment variable */ + ppd[1024], /* PPD environment variable */ + printer_name[255], + /* PRINTER environment variable */ + rip_max_cache[255]; + /* RIP_MAX_CACHE environment variable */ + static char *options = NULL;/* Full list of options */ + static int optlength = 0; /* Length of option buffer */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob() id = %d, file = %d/%d", + job->id, job->current_file, job->num_files); + + if (job->num_files == 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Job ID %d has no files! Cancelling it!", + job->id); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because it has no files."); + + cupsdCancelJob(job, 0); + return; + } + + /* + * Figure out what filters are required to convert from + * the source to the destination type... + */ + + num_filters = 0; + job->cost = 0; + + if (printer->raw) + { + /* + * Remote jobs and raw queues go directly to the printer without + * filtering... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdStartJob: Sending job to queue tagged as raw..."); + + filters = NULL; + } + else + { + /* + * Local jobs get filtered... + */ + + filters = mimeFilter(MimeDatabase, job->filetypes[job->current_file], + printer->filetype, &num_filters, MAX_FILTERS - 1); + + if (num_filters == 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to convert file %d to printable format for job %d!", + job->current_file, job->id); + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Do you have ESP Ghostscript installed?"); + + if (LogLevel < CUPSD_LOG_DEBUG) + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Try setting the LogLevel to \"debug\"."); + + job->current_file ++; + + if (job->current_file == job->num_files) + { + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because it has no files that can be printed."); + + cupsdCancelJob(job, 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 ++) + job->cost += filters[i].cost; + } + } + + /* + * See if the filter cost is too high... + */ + + if ((FilterLevel + job->cost) > FilterLimit && FilterLevel > 0 && + FilterLimit > 0) + { + /* + * Don't print this job quite yet... + */ + + if (filters != NULL) + free(filters); + + cupsdLogMessage(CUPSD_LOG_INFO, + "Holding job %d because filter limit has been reached.", + job->id); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdStartJob: id=%d, file=%d, cost=%d, level=%d, limit=%d", + job->id, job->current_file, job->cost, FilterLevel, + FilterLimit); + return; + } + + FilterLevel += job->cost; + + /* + * Add decompression filters, if any... + */ + + if (job->compressions[job->current_file]) + { + /* + * Add gziptoany filter to the front of the list... + */ + + mime_filter_t *temp_filters; + + if (num_filters == 0) + temp_filters = malloc(sizeof(mime_filter_t)); + else + temp_filters = realloc(filters, + sizeof(mime_filter_t) * (num_filters + 1)); + + if (temp_filters == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add decompression filter - %s", + strerror(errno)); + + if (filters != NULL) + free(filters); + + job->current_file ++; + + if (job->current_file == job->num_files) + { + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the print file could not be decompressed."); + + cupsdCancelJob(job, 0); + } + + return; + } + + filters = temp_filters; + memmove(filters + 1, filters, num_filters * sizeof(mime_filter_t)); + *filters = gziptoany_filter; + num_filters ++; + } + + /* + * Add port monitor, if any... + */ + + if (printer->port_monitor) + { + /* + * Add port monitor to the end of the list... + */ + + mime_filter_t *temp_filters; + + if (num_filters == 0) + temp_filters = malloc(sizeof(mime_filter_t)); + else + temp_filters = realloc(filters, + sizeof(mime_filter_t) * (num_filters + 1)); + + if (temp_filters == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to add port monitor - %s", + strerror(errno)); + + if (filters != NULL) + free(filters); + + job->current_file ++; + + if (job->current_file == job->num_files) + { + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the port monitor could not be added."); + + cupsdCancelJob(job, 0); + } + + return; + } + + filters = temp_filters; + memset(filters + num_filters, 0, sizeof(mime_filter_t)); + snprintf(filters[num_filters].filter, sizeof(filters[num_filters].filter), + "%s/monitor/%s", ServerBin, printer->port_monitor); + num_filters ++; + } + + /* + * Update the printer and job state to "processing"... + */ + + job->state->values[0].integer = IPP_JOB_PROCESSING; + job->status = 0; + job->printer = printer; + printer->job = job; + cupsdSetPrinterState(printer, IPP_PRINTER_PROCESSING, 0); + + if (job->current_file == 0) + { + set_time(job, "time-at-processing"); + cupsdOpenPipe(job->back_pipes); + } + + /* + * Determine if we are printing a banner page or not... + */ + + if (job->job_sheets == NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, "No job-sheets attribute."); + if ((job->job_sheets = + ippFindAttribute(job->attrs, "job-sheets", IPP_TAG_ZERO)) != NULL) + cupsdLogMessage(CUPSD_LOG_DEBUG, + "... but someone added one without setting job_sheets!"); + } + else if (job->job_sheets->num_values == 1) + cupsdLogMessage(CUPSD_LOG_DEBUG, "job-sheets=%s", + job->job_sheets->values[0].string.text); + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "job-sheets=%s,%s", + job->job_sheets->values[0].string.text, + job->job_sheets->values[1].string.text); + + if (printer->type & (CUPS_PRINTER_REMOTE | CUPS_PRINTER_IMPLICIT)) + banner_page = 0; + else if (job->job_sheets == NULL) + banner_page = 0; + else if (strcasecmp(job->job_sheets->values[0].string.text, "none") != 0 && + job->current_file == 0) + banner_page = 1; + else if (job->job_sheets->num_values > 1 && + strcasecmp(job->job_sheets->values[1].string.text, "none") != 0 && + job->current_file == (job->num_files - 1)) + banner_page = 1; + else + banner_page = 0; + + cupsdLogMessage(CUPSD_LOG_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... :) + * + * First allocate/reallocate the option buffer as needed... + */ + + i = ipp_length(job->attrs); + + if (i > optlength) + { + if (optlength == 0) + optptr = malloc(i); + else + optptr = realloc(options, i); + + if (optptr == NULL) + { + cupsdLogMessage(CUPSD_LOG_CRIT, + "cupsdStartJob: Unable to allocate %d bytes for option buffer for job %d!", + i, job->id); + + if (filters != NULL) + free(filters); + + FilterLevel -= job->cost; + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the server ran out of memory."); + + cupsdCancelJob(job, 0); + return; + } + + options = optptr; + optlength = i; + } + + /* + * Now loop through the attributes and convert them to the textual + * representation used by the filters... + */ + + optptr = options; + *optptr = '\0'; + + snprintf(title, sizeof(title), "%s-%d", printer->name, job->id); + strcpy(copies, "1"); + + for (attr = job->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)) + strlcpy(title, attr->values[0].string.text, sizeof(title)); + 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 || + attr->value_tag == IPP_TAG_BEGIN_COLLECTION) /* Not yet supported */ + 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 || + strcmp(attr->name, "page-border") == 0 || + strncmp(attr->name, "number-up", 9) == 0 || + strcmp(attr->name, "page-set") == 0) && + banner_page) + continue; + + /* + * Otherwise add them to the list... + */ + + if (optptr > options) + strlcat(optptr, " ", optlength - (optptr - options)); + + if (attr->value_tag != IPP_TAG_BOOLEAN) + { + strlcat(optptr, attr->name, optlength - (optptr - options)); + strlcat(optptr, "=", optlength - (optptr - options)); + } + + for (i = 0; i < attr->num_values; i ++) + { + if (i) + strlcat(optptr, ",", optlength - (optptr - options)); + + optptr += strlen(optptr); + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + snprintf(optptr, optlength - (optptr - options), + "%d", attr->values[i].integer); + break; + + case IPP_TAG_BOOLEAN : + if (!attr->values[i].boolean) + strlcat(optptr, "no", optlength - (optptr - options)); + + case IPP_TAG_NOVALUE : + strlcat(optptr, attr->name, + optlength - (optptr - options)); + break; + + case IPP_TAG_RANGE : + if (attr->values[i].range.lower == attr->values[i].range.upper) + snprintf(optptr, optlength - (optptr - options) - 1, + "%d", attr->values[i].range.lower); + else + snprintf(optptr, optlength - (optptr - options) - 1, + "%d-%d", attr->values[i].range.lower, + attr->values[i].range.upper); + break; + + case IPP_TAG_RESOLUTION : + snprintf(optptr, optlength - (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 : + for (valptr = attr->values[i].string.text; *valptr;) + { + if (strchr(" \t\n\\\'\"", *valptr)) + *optptr++ = '\\'; + *optptr++ = *valptr++; + } + + *optptr = '\0'; + 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", job->id); + snprintf(filename, sizeof(filename), "%s/d%05d-%03d", RequestRoot, + job->id, job->current_file + 1); + + argv[0] = printer->name; + argv[1] = jobid; + argv[2] = job->username; + argv[3] = title; + argv[4] = copies; + argv[5] = options; + argv[6] = filename; + argv[7] = NULL; + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdStartJob: 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(job->attrs, "attributes-natural-language", + IPP_TAG_LANGUAGE); + + switch (strlen(attr->values[0].string.text)) + { + default : + /* + * This is an unknown or badly formatted language code; use + * the POSIX locale... + */ + + strcpy(lang, "LANG=C"); + break; + + case 2 : + /* + * Just the language code (ll)... + */ + + snprintf(lang, sizeof(lang), "LANG=%s", + attr->values[0].string.text); + break; + + case 5 : + /* + * Language and country code (ll-cc)... + */ + + snprintf(lang, sizeof(lang), "LANG=%c%c_%c%c", + attr->values[0].string.text[0], + attr->values[0].string.text[1], + toupper(attr->values[0].string.text[3] & 255), + toupper(attr->values[0].string.text[4] & 255)); + break; + } + + attr = ippFindAttribute(job->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(job->attrs, "attributes-charset", + IPP_TAG_CHARSET); + snprintf(charset, sizeof(charset), "CHARSET=%s", + attr->values[0].string.text); + } + + snprintf(content_type, sizeof(content_type), "CONTENT_TYPE=%s/%s", + job->filetypes[job->current_file]->super, + job->filetypes[job->current_file]->type); + snprintf(device_uri, sizeof(device_uri), "DEVICE_URI=%s", printer->device_uri); + cupsdSanitizeURI(printer->device_uri, sani_uri, sizeof(sani_uri)); + snprintf(ppd, sizeof(ppd), "PPD=%s/ppd/%s.ppd", ServerRoot, printer->name); + snprintf(printer_name, sizeof(printer_name), "PRINTER=%s", printer->name); + snprintf(rip_max_cache, sizeof(rip_max_cache), "RIP_MAX_CACHE=%s", RIPCache); + + envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0]))); + + envp[envc ++] = charset; + envp[envc ++] = lang; + envp[envc ++] = ppd; + envp[envc ++] = rip_max_cache; + envp[envc ++] = content_type; + envp[envc ++] = device_uri; + envp[envc ++] = printer_name; + + if (Classification && !banner_page) + { + if ((attr = ippFindAttribute(job->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); + + envp[envc ++] = classification; + } + + if (job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) + { + snprintf(class_name, sizeof(class_name), "CLASS=%s", job->dest); + envp[envc ++] = class_name; + } + + envp[envc] = NULL; + + for (i = 0; i < envc; i ++) + if (strncmp(envp[i], "DEVICE_URI=", 11)) + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: envp[%d]=\"%s\"", + i, envp[i]); + else + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdStartJob: envp[%d]=\"DEVICE_URI=%s\"", i, sani_uri); + + job->current_file ++; + + /* + * Now create processes for all of the filters... + */ + + if (cupsdOpenPipe(statusfds)) + { + cupsdLogMessage(CUPSD_LOG_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)); + + cupsdAddPrinterHistory(printer); + + if (filters != NULL) + free(filters); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the server could not create the job status pipes."); + + cupsdCancelJob(job, 0); + return; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: statusfds = [ %d %d ]", + statusfds[0], statusfds[1]); + +#ifdef FD_CLOEXEC + fcntl(statusfds[0], F_SETFD, FD_CLOEXEC); + fcntl(statusfds[1], F_SETFD, FD_CLOEXEC); +#endif /* FD_CLOEXEC */ + + job->status_buffer = cupsdStatBufNew(statusfds[0], "[Job %d]", + job->id); + job->status = 0; + memset(job->filters, 0, sizeof(job->filters)); + + filterfds[1][0] = open("/dev/null", O_RDONLY); + filterfds[1][1] = -1; + + if (filterfds[1][0] < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"/dev/null\" - %s.", + strerror(errno)); + snprintf(printer->state_message, sizeof(printer->state_message), + "Unable to open \"/dev/null\" - %s.", strerror(errno)); + + cupsdAddPrinterHistory(printer); + + if (filters != NULL) + free(filters); + + cupsdClosePipe(statusfds); + cupsdCancelJob(job, 0); + return; + } + + fcntl(filterfds[1][0], F_SETFD, fcntl(filterfds[1][0], F_GETFD) | FD_CLOEXEC); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: 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 + strlcpy(command, filters[i].filter, sizeof(command)); + + if (i < (num_filters - 1)) + { + if (cupsdOpenPipe(filterfds[slot])) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create job filter pipes - %s.", + strerror(errno)); + snprintf(printer->state_message, sizeof(printer->state_message), + "Unable to create filter pipes - %s.", strerror(errno)); + cupsdAddPrinterHistory(printer); + + if (filters != NULL) + free(filters); + + cupsdClosePipe(statusfds); + cupsdClosePipe(filterfds[!slot]); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the server could not create the filter pipes."); + + cupsdCancelJob(job, 0); + return; + } + } + else + { + if (job->current_file == 1) + { + if (strncmp(printer->device_uri, "file:", 5) != 0) + { + if (cupsdOpenPipe(job->print_pipes)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create job backend pipes - %s.", + strerror(errno)); + snprintf(printer->state_message, sizeof(printer->state_message), + "Unable to create backend pipes - %s.", strerror(errno)); + cupsdAddPrinterHistory(printer); + + if (filters != NULL) + free(filters); + + cupsdClosePipe(statusfds); + cupsdClosePipe(filterfds[!slot]); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the server could not create the backend pipes."); + + cupsdCancelJob(job, 0); + return; + } + } + else + { + job->print_pipes[0] = -1; + if (!strncmp(printer->device_uri, "file:/dev/", 10) && + strcmp(printer->device_uri, "file:/dev/null")) + job->print_pipes[1] = open(printer->device_uri + 5, + O_WRONLY | O_EXCL); + else if (!strncmp(printer->device_uri, "file:///dev/", 12) && + strcmp(printer->device_uri, "file:///dev/null")) + job->print_pipes[1] = open(printer->device_uri + 7, + O_WRONLY | O_EXCL); + else + job->print_pipes[1] = open(printer->device_uri + 5, + O_WRONLY | O_CREAT | O_TRUNC, 0600); + + if (job->print_pipes[1] < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to open output file \"%s\" - %s.", + printer->device_uri, strerror(errno)); + snprintf(printer->state_message, sizeof(printer->state_message), + "Unable to open output file \"%s\" - %s.", + printer->device_uri, strerror(errno)); + + cupsdAddPrinterHistory(printer); + + if (filters != NULL) + free(filters); + + cupsdClosePipe(statusfds); + cupsdClosePipe(filterfds[!slot]); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the server could not open the output file."); + + cupsdCancelJob(job, 0); + return; + } + + fcntl(job->print_pipes[1], F_SETFD, + fcntl(job->print_pipes[1], F_GETFD) | FD_CLOEXEC); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdStartJob: print_pipes = [ %d %d ]", + job->print_pipes[0], job->print_pipes[1]); + } + + filterfds[slot][0] = job->print_pipes[0]; + filterfds[slot][1] = job->print_pipes[1]; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: filter = \"%s\"", command); + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: filterfds[%d] = [ %d %d ]", + slot, filterfds[slot][0], filterfds[slot][1]); + + pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0], + filterfds[slot][1], statusfds[1], + job->back_pipes[0], 0, job->filters + i); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Closing filter pipes for slot %d [ %d %d ]...", + !slot, filterfds[!slot][0], filterfds[!slot][1]); + + cupsdClosePipe(filterfds[!slot]); + + if (pid == 0) + { + cupsdLogMessage(CUPSD_LOG_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)); + + cupsdAddPrinterHistory(printer); + + if (filters != NULL) + free(filters); + + cupsdAddPrinterHistory(printer); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the server could not execute a filter."); + + cupsdCancelJob(job, 0); + return; + } + + cupsdLogMessage(CUPSD_LOG_INFO, "Started filter %s (PID %d) for job %d.", + command, pid, job->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) + { + if (job->current_file == 1) + { + sscanf(printer->device_uri, "%254[^:]", method); + snprintf(command, sizeof(command), "%s/backend/%s", ServerBin, method); + + argv[0] = sani_uri; + + filterfds[slot][0] = -1; + filterfds[slot][1] = open("/dev/null", O_WRONLY); + + if (filterfds[slot][1] < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"/dev/null\" - %s.", + strerror(errno)); + snprintf(printer->state_message, sizeof(printer->state_message), + "Unable to open \"/dev/null\" - %s.", strerror(errno)); + + cupsdAddPrinterHistory(printer); + + if (filters != NULL) + free(filters); + + cupsdClosePipe(statusfds); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the server could not open a file."); + + cupsdCancelJob(job, 0); + return; + } + + fcntl(filterfds[slot][1], F_SETFD, + fcntl(filterfds[slot][1], F_GETFD) | FD_CLOEXEC); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartJob: backend = \"%s\"", + command); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdStartJob: filterfds[%d] = [ %d %d ]", + slot, filterfds[slot][0], filterfds[slot][1]); + + pid = cupsdStartProcess(command, argv, envp, filterfds[!slot][0], + filterfds[slot][1], statusfds[1], + job->back_pipes[1], 1, + &(job->backend)); + + if (pid == 0) + { + cupsdLogMessage(CUPSD_LOG_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)); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Closing print pipes [ %d %d ]...", + job->print_pipes[0], job->print_pipes[1]); + + cupsdClosePipe(job->print_pipes); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Closing back pipes [ %d %d ]...", + job->back_pipes[0], job->back_pipes[1]); + + cupsdClosePipe(job->back_pipes); + + cupsdAddEvent(CUPSD_EVENT_JOB_COMPLETED, job->printer, job, + "Job canceled because the server could not execute the backend."); + + cupsdCancelJob(job, 0); + return; + } + else + { + cupsdLogMessage(CUPSD_LOG_INFO, + "Started backend %s (PID %d) for job %d.", + command, pid, job->id); + } + } + + if (job->current_file == job->num_files) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Closing print pipes [ %d %d ]...", + job->print_pipes[0], job->print_pipes[1]); + + cupsdClosePipe(job->print_pipes); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Closing back pipes [ %d %d ]...", + job->back_pipes[0], job->back_pipes[1]); + + cupsdClosePipe(job->back_pipes); + } + } + else + { + filterfds[slot][0] = -1; + filterfds[slot][1] = -1; + + if (job->current_file == job->num_files) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Closing print pipes [ %d %d ]...", + job->print_pipes[0], job->print_pipes[1]); + + cupsdClosePipe(job->print_pipes); + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Closing filter pipes for slot %d [ %d %d ]...", + slot, filterfds[slot][0], filterfds[slot][1]); + + cupsdClosePipe(filterfds[slot]); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Closing status output pipe %d...", + statusfds[1]); + + close(statusfds[1]); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartJob: Adding fd %d to InputSet...", + job->status_buffer->fd); + + FD_SET(job->status_buffer->fd, InputSet); +} + + +/* + * 'cupsdStopAllJobs()' - Stop all print jobs. + */ + +void +cupsdStopAllJobs(void) +{ + cupsd_job_t *job; /* Current job */ + + + DEBUG_puts("cupsdStopAllJobs()"); + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->state->values[0].integer == IPP_JOB_PROCESSING) + { + cupsdStopJob(job, 1); + job->state->values[0].integer = IPP_JOB_PENDING; + } +} + + +/* + * 'cupsdStopJob()' - Stop a print job. + */ + +void +cupsdStopJob(cupsd_job_t *job, /* I - Job */ + int force) /* I - 1 = Force all filters to stop */ +{ + int i; /* Looping var */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStopJob: id = %d, force = %d", + job->id, force); + + if (job->state->values[0].integer != IPP_JOB_PROCESSING) + return; + + FilterLevel -= job->cost; + + if (job->status < 0 && + !(job->dtype & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT)) && + !(job->printer->type & CUPS_PRINTER_FAX) && + !strcmp(job->printer->error_policy, "stop-printer")) + cupsdSetPrinterState(job->printer, IPP_PRINTER_STOPPED, 1); + else if (job->printer->state != IPP_PRINTER_STOPPED) + cupsdSetPrinterState(job->printer, IPP_PRINTER_IDLE, 0); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStopJob: printer state is %d", + job->printer->state); + + job->state->values[0].integer = IPP_JOB_STOPPED; + job->printer->job = NULL; + job->printer = NULL; + + job->current_file --; + + for (i = 0; job->filters[i]; i ++) + if (job->filters[i] > 0) + { + cupsdEndProcess(job->filters[i], force); + job->filters[i] = 0; + } + + if (job->backend > 0) + { + cupsdEndProcess(job->backend, force); + job->backend = 0; + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopJob: Closing print pipes [ %d %d ]...", + job->print_pipes[0], job->print_pipes[1]); + + cupsdClosePipe(job->print_pipes); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopJob: Closing back pipes [ %d %d ]...", + job->back_pipes[0], job->back_pipes[1]); + + cupsdClosePipe(job->back_pipes); + + if (job->status_buffer) + { + /* + * Close the pipe and clear the input bit. + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopJob: Removing fd %d from InputSet...", + job->status_buffer->fd); + + FD_CLR(job->status_buffer->fd, InputSet); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopJob: Closing status input pipe %d...", + job->status_buffer->fd); + + cupsdStatBufDelete(job->status_buffer); + + job->status_buffer = NULL; + } +} + + +/* + * 'cupsdUpdateJob()' - Read a status update from a job's filters. + */ + +void +cupsdUpdateJob(cupsd_job_t *job) /* I - Job to check */ +{ + int i; /* Looping var */ + int copies; /* Number of copies printed */ + char message[1024], /* Message text */ + *ptr; /* Pointer update... */ + int loglevel; /* Log level for message */ + + + while ((ptr = cupsdStatBufUpdate(job->status_buffer, &loglevel, + message, sizeof(message))) != NULL) + { + /* + * Process page and printer state messages as needed... + */ + + if (loglevel == CUPSD_LOG_PAGE) + { + /* + * Page message; send the message to the page_log file and update the + * job sheet count... + */ + + if (job->sheets != NULL) + { + if (!strncasecmp(message, "total ", 6)) + { + /* + * Got a total count of pages from a backend or filter... + */ + + copies = atoi(message + 6); + copies -= job->sheets->values[0].integer; /* Just track the delta */ + } + else if (!sscanf(message, "%*d%d", &copies)) + copies = 1; + + job->sheets->values[0].integer += copies; + + if (job->printer->page_limit) + cupsdUpdateQuota(job->printer, job->username, copies, 0); + } + + cupsdLogPage(job, message); + + cupsdAddEvent(CUPSD_EVENT_JOB_PROGRESS, job->printer, job, + "Printed %d page(s).", job->sheets->values[0].integer); + } + else if (loglevel == CUPSD_LOG_STATE) + cupsdSetPrinterReasons(job->printer, message); + else if (loglevel == CUPSD_LOG_ATTR) + { + /* + * Set attribute(s)... + */ + + /**** TODO ****/ + } + + if (!strchr(job->status_buffer->buffer, '\n')) + break; + } + + if (ptr == NULL) + { + /* + * See if all of the filters and the backend have returned their + * exit statuses. + */ + + for (i = 0; job->filters[i] < 0; i ++); + + if (job->filters[i]) + return; + + if (job->current_file >= job->num_files && job->backend > 0) + return; + + /* + * Handle the end of job stuff... + */ + + cupsdFinishJob(job); + } +} + + +/* + * 'compare_active_jobs()' - Compare the job IDs and priorities of two jobs. + */ + +static int /* O - Difference */ +compare_active_jobs(void *first, /* I - First job */ + void *second, /* I - Second job */ + void *data) /* I - App data (not used) */ +{ + int diff; /* Difference */ + + + if ((diff = ((cupsd_job_t *)first)->priority - ((cupsd_job_t *)second)->priority) != 0) + return (diff); + else + return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id); +} + + +/* + * 'compare_jobs()' - Compare the job IDs of two jobs. + */ + +static int /* O - Difference */ +compare_jobs(void *first, /* I - First job */ + void *second, /* I - Second job */ + void *data) /* I - App data (not used) */ +{ + return (((cupsd_job_t *)first)->id - ((cupsd_job_t *)second)->id); +} + + +/* + * 'ipp_length()' - Compute the size of the buffer needed to hold + * the textual IPP attributes. + */ + +int /* O - Size of buffer to hold IPP attributes */ +ipp_length(ipp_t *ipp) /* I - IPP request */ +{ + int bytes; /* Number of bytes */ + int i; /* Looping var */ + ipp_attribute_t *attr; /* Current attribute */ + + + /* + * Loop through all attributes... + */ + + bytes = 0; + + for (attr = ipp->attrs; attr != NULL; attr = attr->next) + { + /* + * Skip attributes that won't be sent to filters... + */ + + 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; + + /* + * Add space for a leading space and commas between each value. + * For the first attribute, the leading space isn't used, so the + * extra byte can be used as the nul terminator... + */ + + bytes ++; /* " " separator */ + bytes += attr->num_values; /* "," separators */ + + /* + * Boolean attributes appear as "foo,nofoo,foo,nofoo", while + * other attributes appear as "foo=value1,value2,...,valueN". + */ + + if (attr->value_tag != IPP_TAG_BOOLEAN) + bytes += strlen(attr->name); + else + bytes += attr->num_values * strlen(attr->name); + + /* + * Now add the size required for each value in the attribute... + */ + + switch (attr->value_tag) + { + case IPP_TAG_INTEGER : + case IPP_TAG_ENUM : + /* + * Minimum value of a signed integer is -2147483647, or 11 digits. + */ + + bytes += attr->num_values * 11; + break; + + case IPP_TAG_BOOLEAN : + /* + * Add two bytes for each false ("no") value... + */ + + for (i = 0; i < attr->num_values; i ++) + if (!attr->values[i].boolean) + bytes += 2; + break; + + case IPP_TAG_RANGE : + /* + * A range is two signed integers separated by a hyphen, or + * 23 characters max. + */ + + bytes += attr->num_values * 23; + break; + + case IPP_TAG_RESOLUTION : + /* + * A resolution is two signed integers separated by an "x" and + * suffixed by the units, or 26 characters max. + */ + + bytes += attr->num_values * 26; + 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 : + /* + * Strings can contain characters that need quoting. We need + * at least 2 * len + 2 characters to cover the quotes and + * any backslashes in the string. + */ + + for (i = 0; i < attr->num_values; i ++) + bytes += 2 * strlen(attr->values[i].string.text) + 2; + break; + + default : + break; /* anti-compiler-warning-code */ + } + } + + return (bytes); +} + + +/* + * 'set_time()' - Set one of the "time-at-xyz" attributes... + */ + +static void +set_time(cupsd_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); + } +} + + +/* + * 'set_hold_until()' - Set the hold time and update job-hold-until attribute... + */ + +static void +set_hold_until(cupsd_job_t *job, /* I - Job to update */ + time_t holdtime) /* I - Hold until time */ +{ + ipp_attribute_t *attr; /* job-hold-until attribute */ + struct tm *holddate; /* Hold date */ + char holdstr[64]; /* Hold time */ + + + /* + * Set the hold_until value and hold the job... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, "set_hold_until: hold_until = %d", (int)holdtime); + + job->state->values[0].integer = IPP_JOB_HELD; + job->hold_until = holdtime; + + /* + * Update the job-hold-until attribute with a string representing GMT + * time (HH:MM:SS)... + */ + + holddate = gmtime(&holdtime); + snprintf(holdstr, sizeof(holdstr), "%d:%d:%d", holddate->tm_hour, + holddate->tm_min, holddate->tm_sec); + + if ((attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_KEYWORD)) == NULL) + attr = ippFindAttribute(job->attrs, "job-hold-until", IPP_TAG_NAME); + + /* + * Either add the attribute or update the value of the existing one + */ + + if (attr == NULL) + attr = ippAddString(job->attrs, IPP_TAG_JOB, IPP_TAG_KEYWORD, + "job-hold-until", NULL, holdstr); + else + cupsdSetString(&attr->values[0].string.text, holdstr); + + cupsdSaveJob(job); +} + + +/* + * End of "$Id: job.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/scheduler/job.h b/scheduler/job.h new file mode 100644 index 000000000..99799bcec --- /dev/null +++ b/scheduler/job.h @@ -0,0 +1,120 @@ +/* + * "$Id: job.h 4819 2005-11-04 18:39:32Z mike $" + * + * Print job definitions for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Job request structure... + */ + +typedef struct cupsd_job_s +{ + 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; /* Printing user */ + char *dest; /* Destination printer or class */ + cups_ptype_t dtype; /* Destination type (class/remote bits) */ + 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 */ + int *compressions; /* Compression status of each file */ + ipp_t *attrs; /* Job attributes */ + cupsd_statbuf_t *status_buffer; /* Status buffer for this job */ + int print_pipes[2], /* Print data pipes */ + back_pipes[2]; /* Backchannel pipes */ + int cost; /* Filtering cost */ + int filters[MAX_FILTERS + 1]; + /* Filter process IDs, 0 terminated */ + int backend; /* Backend process ID */ + int status; /* Status code from filters */ + cupsd_printer_t *printer; /* Printer this job is assigned to */ + int tries; /* Number of tries for this job */ +} cupsd_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 */ + MaxActiveJobs VALUE(0), + /* Max number of active jobs */ + MaxJobsPerUser VALUE(0), + /* Max jobs per user */ + MaxJobsPerPrinter VALUE(0); + /* Max jobs per printer */ +VAR int JobAutoPurge VALUE(0); + /* Automatically purge jobs */ +VAR cups_array_t *Jobs VALUE(NULL), + /* List of current jobs */ + *ActiveJobs VALUE(NULL); + /* List of active jobs */ +VAR int NextJobId VALUE(1); + /* Next job ID to use */ +VAR int JobRetryLimit VALUE(5), + /* Max number of tries */ + JobRetryInterval VALUE(300); + /* Seconds between retries */ + + +/* + * Prototypes... + */ + +extern cupsd_job_t *cupsdAddJob(int priority, const char *dest); +extern void cupsdCancelJob(cupsd_job_t *job, int purge); +extern void cupsdCancelJobs(const char *dest, const char *username, + int purge); +extern void cupsdCheckJobs(void); +extern void cupsdCleanJobs(void); +extern void cupsdDeleteJob(cupsd_job_t *job); +extern cupsd_job_t *cupsdFindJob(int id); +extern void cupsdFinishJob(cupsd_job_t *job); +extern void cupsdFreeAllJobs(void); +extern int cupsdGetPrinterJobCount(const char *dest); +extern int cupsdGetUserJobCount(const char *username); +extern void cupsdHoldJob(cupsd_job_t *job); +extern void cupsdLoadAllJobs(void); +extern void cupsdMoveJob(cupsd_job_t *job, const char *dest); +extern void cupsdReleaseJob(cupsd_job_t *job); +extern void cupsdRestartJob(cupsd_job_t *job); +extern void cupsdSaveJob(cupsd_job_t *job); +extern void cupsdSetJobHoldUntil(cupsd_job_t *job, const char *when); +extern void cupsdSetJobPriority(cupsd_job_t *job, int priority); +extern void cupsdStartJob(cupsd_job_t *job, cupsd_printer_t *printer); +extern void cupsdStopAllJobs(void); +extern void cupsdStopJob(cupsd_job_t *job, int force); +extern void cupsdUpdateJob(cupsd_job_t *job); + + +/* + * End of "$Id: job.h 4819 2005-11-04 18:39:32Z mike $". + */ diff --git a/scheduler/listen.c b/scheduler/listen.c new file mode 100644 index 000000000..176251cdc --- /dev/null +++ b/scheduler/listen.c @@ -0,0 +1,398 @@ +/* + * "$Id: listen.c 4780 2005-10-13 00:38:28Z mike $" + * + * Server listening routines for the Common UNIX Printing System (CUPS) + * scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdPauseListening() - Clear input polling on all listening sockets... + * cupsdResumeListening() - Set input polling on all listening sockets... + * cupsdStartListening() - Create all listening sockets... + * cupsdStopListening() - Close all listening sockets... + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + + +/* + * Make sure the IPV6_V6ONLY is defined on Linux - older versions of + * glibc don't define it even if the kernel supports it... + */ + +#if defined(__linux) && !defined(IPV6_V6ONLY) +# define IPV6_V6ONLY 26 +#endif /* __linux && !IPV6_V6ONLY */ + + +/* + * 'cupsdPauseListening()' - Clear input polling on all listening sockets... + */ + +void +cupsdPauseListening(void) +{ + int i; /* Looping var */ + cupsd_listener_t *lis; /* Current listening socket */ + + + if (NumListeners < 1) + return; + + if (NumClients == MaxClients) + cupsdLogMessage(CUPSD_LOG_WARN, + "Max clients reached, holding new connections..."); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdPauseListening: Clearing input bits..."); + + for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) + if (lis->fd >= 0) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdPauseListening: Removing fd %d from InputSet...", + lis->fd); + + FD_CLR(lis->fd, InputSet); + } +} + + +/* + * 'cupsdResumeListening()' - Set input polling on all listening sockets... + */ + +void +cupsdResumeListening(void) +{ + int i; /* Looping var */ + cupsd_listener_t *lis; /* Current listening socket */ + + + if (NumListeners < 1) + return; + + if (NumClients >= (MaxClients - 1)) + cupsdLogMessage(CUPSD_LOG_WARN, "Resuming new connection processing..."); + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdResumeListening: Setting input bits..."); + + for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) + if (lis->fd >= 0) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdResumeListening: Adding fd %d to InputSet...", + lis->fd); + FD_SET(lis->fd, InputSet); + } +} + + +/* + * 'cupsdStartListening()' - Create all listening sockets... + */ + +void +cupsdStartListening(void) +{ + int status; /* Bind result */ + int i, /* Looping var */ + p, /* Port number */ + val; /* Parameter value */ + cupsd_listener_t *lis; /* Current listening socket */ + char s[256]; /* String addresss */ + const char *have_domain; /* Have a domain socket? */ + static const char * const encryptions[] = + { /* Encryption values */ + "IfRequested", + "Never", + "Required", + "Always" + }; + + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdStartListening: NumListeners=%d", + NumListeners); + + /* + * Get the server's IP address... + */ + + if (ServerAddrs) + httpAddrFreeList(ServerAddrs); + + if ((ServerAddrs = httpAddrGetList(ServerName, AF_UNSPEC, NULL)) == NULL) + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartListening: Unable to find IP address for " + "server name \"%s\"!\n", ServerName); + + /* + * Setup socket listeners... + */ + + for (i = NumListeners, lis = Listeners, LocalPort = 0, have_domain = NULL; + i > 0; i --, lis ++) + { + httpAddrString(&(lis->address), s, sizeof(s)); + +#ifdef AF_INET6 + if (lis->address.addr.sa_family == AF_INET6) + p = ntohs(lis->address.ipv6.sin6_port); + else +#endif /* AF_INET6 */ +#ifdef AF_LOCAL + if (lis->address.addr.sa_family == AF_LOCAL) + p = 0; + else +#endif /* AF_LOCAL */ + p = ntohs(lis->address.ipv4.sin_port); + + /* + * Create a socket for listening... + */ + + lis->fd = socket(lis->address.addr.sa_family, SOCK_STREAM, 0); + + if (lis->fd == -1) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartListening: Unable to open listen socket for address %s:%d - %s.", + s, p, strerror(errno)); + continue; + } + + 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... + */ + +#ifdef AF_INET6 + if (lis->address.addr.sa_family == AF_INET6) + { +# ifdef IPV6_V6ONLY + /* + * Accept only IPv6 connections on this socket, to avoid + * potential security issues and to make all platforms behave + * the same. + */ + + val = 1; +# ifdef __sun + setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val)); +# else + setsockopt(lis->fd, IPPROTO_IPV6, IPV6_V6ONLY, &val, sizeof(val)); +# endif /* __sun */ +# endif /* IPV6_V6ONLY */ + + status = bind(lis->fd, (struct sockaddr *)&(lis->address), + httpAddrLength(&(lis->address))); + } + else +#endif /* AF_INET6 */ +#ifdef AF_LOCAL + if (lis->address.addr.sa_family == AF_LOCAL) + { + mode_t mask; /* Umask setting */ + + + /* + * Remove any existing domain socket file... + */ + + unlink(lis->address.un.sun_path); + + /* + * Save the curent umask and set it to 0... + */ + + mask = umask(0); + + /* + * Bind the domain socket... + */ + + status = bind(lis->fd, (struct sockaddr *)&(lis->address), + httpAddrLength(&(lis->address))); + + /* + * Restore the umask... + */ + + umask(mask); + } + else +#endif /* AF_LOCAL */ + status = bind(lis->fd, (struct sockaddr *)&(lis->address), + sizeof(lis->address.ipv4)); + + if (status < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartListening: Unable to bind socket for address %s:%d - %s.", + s, p, strerror(errno)); + close(lis->fd); + lis->fd = -1; + continue; + } + + /* + * Listen for new clients. + */ + + if (listen(lis->fd, ListenBackLog) < 0) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartListening: Unable to listen for clients on address %s:%d - %s.", + s, p, strerror(errno)); + exit(errno); + } + + if (p) + cupsdLogMessage(CUPSD_LOG_INFO, + "cupsdStartListening: Listening to %s:%d on fd %d...", + s, p, lis->fd); + else + cupsdLogMessage(CUPSD_LOG_INFO, + "cupsdStartListening: Listening to %s on fd %d...", + s, lis->fd); + + /* + * Save the first port that is bound to the local loopback or + * "any" address... + */ + + if (!LocalPort && p > 0 && + (httpAddrLocalhost(&(lis->address)) || + httpAddrAny(&(lis->address)))) + { + LocalPort = p; + LocalEncryption = lis->encryption; + } + +#ifdef AF_LOCAL + if (lis->address.addr.sa_family == AF_LOCAL && !have_domain) + have_domain = lis->address.un.sun_path; +#endif /* AF_LOCAL */ + } + + /* + * Make sure that we are listening on localhost! + */ + + if (!LocalPort && !have_domain) + { + cupsdLogMessage(CUPSD_LOG_EMERG, + "No Listen or Port lines were found to allow access via localhost!"); + + /* + * Commit suicide... + */ + + cupsdEndProcess(getpid(), 0); + } + + /* + * Set the CUPS_SERVER, IPP_PORT, and CUPS_ENCRYPTION variables based on + * the listeners... + */ + + if (have_domain) + { + /* + * Use domain sockets for the local connection... + */ + + cupsdSetEnv("CUPS_SERVER", have_domain); + } + else + { + /* + * Use the default local loopback address for the server... + */ + + cupsdSetEnv("CUPS_SERVER", "localhost"); + } + + cupsdSetEnv("CUPS_ENCRYPTION", encryptions[LocalEncryption]); + cupsdSetEnvf("IPP_PORT", "%d", LocalPort); + + /* + * Resume listening for connections... + */ + + cupsdResumeListening(); +} + + +/* + * 'cupsdStopListening()' - Close all listening sockets... + */ + +void +cupsdStopListening(void) +{ + int i; /* Looping var */ + cupsd_listener_t *lis; /* Current listening socket */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdStopListening: closing all listen sockets."); + + cupsdPauseListening(); + + for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) + { +#ifdef WIN32 + closesocket(lis->fd); +#else + close(lis->fd); +#endif /* WIN32 */ + +#ifdef AF_LOCAL + /* + * Remove domain sockets... + */ + + if (lis->address.addr.sa_family == AF_LOCAL) + unlink(lis->address.un.sun_path); +#endif /* AF_LOCAL */ + } +} + + +/* + * End of "$Id: listen.c 4780 2005-10-13 00:38:28Z mike $". + */ diff --git a/scheduler/log.c b/scheduler/log.c new file mode 100644 index 000000000..1aa41a704 --- /dev/null +++ b/scheduler/log.c @@ -0,0 +1,553 @@ +/* + * "$Id: log.c 4860 2005-12-01 22:07:26Z mike $" + * + * Log file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdGetDateTime() - Returns a pointer to a date/time string. + * cupsdLogMessage() - Log a message to the error log file. + * cupsdLogPage() - Log a page to the page log file. + * cupsdLogRequest() - 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 + +#ifdef HAVE_VSYSLOG +# include +#endif /* HAVE_VSYSLOG */ + + +/* + * Local functions... + */ + +static int check_log_file(cups_file_t **, const char *); + + +/* + * 'cupsdGetDateTime()' - Returns a pointer to a date/time string. + */ + +char * /* O - Date/time string */ +cupsdGetDateTime(time_t t) /* I - Time value */ +{ + struct tm *date; /* Date/time value */ + static time_t last_time = -1; /* Last time value */ + static char s[1024]; /* Date/time string */ + static const char * const months[12] =/* Months */ + { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + + if (t != last_time) + { + last_time = t; + + /* + * 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); +} + + +/* + * 'cupsdLogMessage()' - Log a message to the error log file. + */ + +int /* O - 1 on success, 0 on error */ +cupsdLogMessage(int level, /* I - Log level */ + const char *message, /* I - printf-style message string */ + ...) /* I - Additional args as needed */ +{ + int len; /* Length of message */ + va_list ap; /* Argument pointer */ + static const char levels[] = /* Log levels... */ + { + ' ', + 'X', + 'A', + 'C', + 'E', + 'W', + 'N', + 'I', + 'D', + 'd' + }; +#ifdef HAVE_VSYSLOG + static const 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 */ + static int linesize = 0; /* Size of line for output file */ + static char *line = NULL; /* Line for output file */ + + + /* + * See if we want to log this message... + */ + + if (level > LogLevel || !ErrorLog) + return (1); + +#ifdef HAVE_VSYSLOG + /* + * See if we are logging errors via syslog... + */ + + if (!strcmp(ErrorLog, "syslog")) + { + 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... + */ + + cupsFilePrintf(ErrorFile, "%c %s ", levels[level], cupsdGetDateTime(time(NULL))); + + /* + * Allocate the line buffer as needed... + */ + + if (!linesize) + { + linesize = 8192; + line = malloc(linesize); + + if (!line) + { + cupsFilePrintf(ErrorFile, + "ERROR: Unable to allocate memory for line - %s\n", + strerror(errno)); + cupsFileFlush(ErrorFile); + + return (0); + } + } + + /* + * Format the log message... + */ + + va_start(ap, message); + len = vsnprintf(line, linesize, message, ap); + va_end(ap); + + /* + * Resize the buffer as needed... + */ + + if (len >= linesize) + { + len ++; + + if (len < 8192) + len = 8192; + else if (len > 65536) + len = 65536; + + line = realloc(line, len); + + if (line) + linesize = len; + else + { + cupsFilePrintf(ErrorFile, + "ERROR: Unable to allocate memory for line - %s\n", + strerror(errno)); + cupsFileFlush(ErrorFile); + + return (0); + } + + va_start(ap, message); + len = vsnprintf(line, linesize, message, ap); + va_end(ap); + } + + if (len >= linesize) + len = linesize - 1; + + /* + * Then the log message... + */ + + cupsFilePuts(ErrorFile, line); + + /* + * Then a newline... + */ + + if (len > 0 && line[len - 1] != '\n') + cupsFilePutChar(ErrorFile, '\n'); + + /* + * Flush the line to the file and return... + */ + + cupsFileFlush(ErrorFile); + + return (1); +} + + +/* + * 'cupsdLogPage()' - Log a page to the page log file. + */ + +int /* O - 1 on success, 0 on error */ +cupsdLogPage(cupsd_job_t *job, /* I - Job being printed */ + const char *page) /* I - Page being printed */ +{ + ipp_attribute_t *billing, /* job-billing attribute */ + *hostname; /* job-originating-host-name attribute */ + + + billing = ippFindAttribute(job->attrs, "job-billing", IPP_TAG_ZERO); + hostname = ippFindAttribute(job->attrs, "job-originating-host-name", + IPP_TAG_ZERO); + +#ifdef HAVE_VSYSLOG + /* + * See if we are logging pages via syslog... + */ + + if (!strcmp(PageLog, "syslog")) + { + syslog(LOG_INFO, "PAGE %s %s %d %s %s %s", job->printer->name, + job->username ? job->username : "-", + job->id, page, billing ? billing->values[0].string.text : "-", + hostname->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 hostname + */ + + cupsFilePrintf(PageFile, "%s %s %d %s %s %s %s\n", job->printer->name, + job->username ? job->username : "-", + job->id, cupsdGetDateTime(time(NULL)), page, + billing ? billing->values[0].string.text : "-", + hostname->values[0].string.text); + cupsFileFlush(PageFile); + + return (1); +} + + +/* + * 'cupsdLogRequest()' - Log an HTTP request in Common Log Format. + */ + +int /* O - 1 on success, 0 on error */ +cupsdLogRequest(cupsd_client_t *con, /* I - Request to log */ + http_status_t code) /* I - Response code */ +{ + static const char * const 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")) + { + syslog(LOG_INFO, "REQUEST %s - %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT "\n", + con->http.hostname, con->username[0] != '\0' ? con->username : "-", + states[con->operation], con->uri, + con->http.version / 100, con->http.version % 100, + code, CUPS_LLCAST 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"... + */ + + cupsFilePrintf(AccessFile, + "%s - %s %s \"%s %s HTTP/%d.%d\" %d " CUPS_LLFMT " %s %s\n", + con->http.hostname, con->username[0] != '\0' ? con->username : "-", + cupsdGetDateTime(con->start), states[con->operation], con->uri, + con->http.version / 100, con->http.version % 100, + code, CUPS_LLCAST con->bytes, + con->request ? + ippOpString(con->request->request.op.operation_id) : "-", + con->response ? + ippErrorString(con->response->request.status.status_code) : + "-"); + + cupsFileFlush(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(cups_file_t **lf, /* 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 (!lf || !logname || !logname[0]) + return (1); + + /* + * Format the filename as needed... + */ + + if (!*lf || (cupsFileTell(*lf) > MaxLogSize && MaxLogSize > 0)) + { + /* + * Handle format strings... + */ + + filename[sizeof(filename) - 1] = '\0'; + + if (logname[0] != '/') + { + strlcpy(filename, ServerRoot, sizeof(filename)); + strlcat(filename, "/", sizeof(filename)); + } + 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... + */ + + strlcpy(ptr, ServerName, sizeof(filename) - (ptr - filename)); + ptr += strlen(ptr); + } + else + { + /* + * Otherwise just insert the character... + */ + + *ptr++ = *logname; + } + } + else + *ptr++ = *logname; + + *ptr = '\0'; + } + + /* + * See if the log file is open... + */ + + if (!*lf) + { + /* + * Nope, open the log file... + */ + + if ((*lf = cupsFileOpen(filename, "a")) == NULL) + { + syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename, + strerror(errno)); + + return (0); + } + + if (strncmp(filename, "/dev/", 5)) + { + /* + * Change ownership and permissions of non-device logs... + */ + + fchown(cupsFileNumber(*lf), RunUser, Group); + fchmod(cupsFileNumber(*lf), LogFilePerm); + } + } + + /* + * Do we need to rotate the log? + */ + + if (cupsFileTell(*lf) > MaxLogSize && MaxLogSize > 0) + { + /* + * Rotate log file... + */ + + cupsFileClose(*lf); + + strcpy(backname, filename); + strlcat(backname, ".O", sizeof(backname)); + + unlink(backname); + rename(filename, backname); + + if ((*lf = cupsFileOpen(filename, "a")) == NULL) + { + syslog(LOG_ERR, "Unable to open log file \"%s\" - %s", filename, + strerror(errno)); + + return (0); + } + + if (strncmp(filename, "/dev/", 5)) + { + /* + * Change ownership and permissions of non-device logs... + */ + + fchown(cupsFileNumber(*lf), RunUser, Group); + fchmod(cupsFileNumber(*lf), LogFilePerm); + } + } + + return (1); +} + + +/* + * End of "$Id: log.c 4860 2005-12-01 22:07:26Z mike $". + */ diff --git a/scheduler/main.c b/scheduler/main.c new file mode 100644 index 000000000..3bbd88876 --- /dev/null +++ b/scheduler/main.c @@ -0,0 +1,1508 @@ +/* + * "$Id: main.c 4838 2005-11-14 18:34:27Z mike $" + * + * Scheduler main loop for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for the CUPS scheduler. + * cupsdClosePipe() - Close a pipe as necessary. + * cupsdOpenPipe() - Create a pipe which is closed on exec. + * cupsdCatchChildSignals() - Catch SIGCHLD signals... + * cupsdHoldSignals() - Hold child and termination signals. + * cupsdIgnoreChildSignals() - Ignore SIGCHLD signals... + * cupsdReleaseSignals() - Release signals for delivery. + * cupsdSetString() - Set a string value. + * cupsdSetStringf() - Set a formatted string value. + * parent_handler() - Catch USR1/CHLD signals... + * process_children() - Process all dead children... + * 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. + * select_timeout() - Calculate the select timeout value. + * usage() - Show scheduler usage. + */ + +/* + * Include necessary headers... + */ + +#define _MAIN_C_ +#include "cupsd.h" +#include +#include +#include + +#if defined(HAVE_MALLOC_H) && defined(HAVE_MALLINFO) +# include +#endif /* HAVE_MALLOC_H && HAVE_MALLINFO */ + + +/* + * Local functions... + */ + +static void parent_handler(int sig); +static void process_children(void); +static void sigchld_handler(int sig); +static void sighup_handler(int sig); +static void sigterm_handler(int sig); +static long select_timeout(int fds); +static void usage(void); + + +/* + * Local globals... + */ + +static int parent_signal = 0; /* Set to signal number from child */ +static int holdcount = 0; /* Number of times "hold" was called */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) +static sigset_t holdmask; /* Old POSIX signal mask */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ +static int dead_children = 0; /* Dead children? */ +static int stop_scheduler = 0; /* Should the scheduler stop? */ + + +/* + * '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 */ + int fds; /* Number of ready descriptors select returns */ + fd_set *input, /* Input set for select() */ + *output; /* Output set for select() */ + cupsd_client_t *con; /* Current client */ + cupsd_job_t *job; /* Current job */ + cupsd_listener_t *lis; /* Current listener */ + time_t current_time, /* Current time */ + activity, /* Activity timer */ + browse_time, /* Next browse send time */ + senddoc_time, /* Send-Document time */ + expire_time; /* Subscription expire 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 + cups_file_t *fp; /* Fake lpsched lock file */ + struct stat statbuf; /* Needed for checking lpsched FIFO */ +#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... + */ + + cupsdSetString(&ConfigurationFile, argv[i]); + } + else + { + /* + * Relative directory... + */ + + char current[1024]; /* Current directory */ + + + getcwd(current, sizeof(current)); + cupsdSetStringf(&ConfigurationFile, "%s/%s", current, argv[i]); + } + break; + + case 'f' : /* Run in foreground... */ + fg = 1; + break; + + case 'F' : /* Run in foreground, but still disconnect from terminal... */ + 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 (!ConfigurationFile) + cupsdSetString(&ConfigurationFile, CUPS_SERVERROOT "/cupsd.conf"); + + /* + * If the user hasn't specified "-f", run in the background... + */ + + if (!fg) + { + /* + * Setup signal handlers for the parent... + */ + +#ifdef HAVE_SIGSET /* Use System V signals over POSIX to avoid bugs */ + sigset(SIGUSR1, parent_handler); + sigset(SIGCHLD, parent_handler); + + sigset(SIGHUP, SIG_IGN); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGUSR1); + action.sa_handler = parent_handler; + sigaction(SIGUSR1, &action, NULL); + sigaction(SIGCHLD, &action, NULL); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGHUP, &action, NULL); +#else + signal(SIGUSR1, parent_handler); + signal(SIGCLD, parent_handler); + + signal(SIGHUP, SIG_IGN); +#endif /* HAVE_SIGSET */ + + if (fork() > 0) + { + /* + * OK, wait for the child to startup and send us SIGUSR1 or to crash + * and the OS send us SIGCHLD... We also need to ignore SIGHUP which + * might be sent by the init script to restart the scheduler... + */ + + for (; parent_signal == 0;) + sleep(1); + + if (parent_signal == SIGUSR1) + return (0); + + if (wait(&i) < 0) + { + perror("cupsd"); + return (1); + } + else if (WIFEXITED(i)) + { + fprintf(stderr, "cupsd: Child exited with status %d!\n", WEXITSTATUS(i)); + return (2); + } + else + { + fprintf(stderr, "cupsd: Child exited on signal %d!\n", WTERMSIG(i)); + return (3); + } + } + } + + if (fg < 1) + { + /* + * 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... + */ + + setsid(); + + /* + * Close all open files... + */ + + getrlimit(RLIMIT_NOFILE, &limit); + + for (i = 0; i < limit.rlim_cur; i ++) + close(i); +#endif /* DEBUG */ + } + + /* + * Set the timezone info... + */ + + tzset(); + +#ifdef LC_TIME + setlocale(LC_TIME, ""); +#endif /* LC_TIME */ + + /* + * Set the maximum number of files... + */ + + getrlimit(RLIMIT_NOFILE, &limit); + + if (limit.rlim_max > CUPS_MAX_FDS) + MaxFDs = CUPS_MAX_FDS; + else + MaxFDs = limit.rlim_max; + + limit.rlim_cur = MaxFDs; + + setrlimit(RLIMIT_NOFILE, &limit); + + /* + * Allocate memory for the input and output sets... + */ + + SetSize = (MaxFDs + 31) / 8 + 4; + if (SetSize < sizeof(fd_set)) + SetSize = sizeof(fd_set); + + InputSet = (fd_set *)calloc(1, SetSize); + OutputSet = (fd_set *)calloc(1, SetSize); + input = (fd_set *)calloc(1, SetSize); + output = (fd_set *)calloc(1, SetSize); + + if (InputSet == NULL || OutputSet == NULL || input == NULL || output == NULL) + { + syslog(LOG_LPR, "Unable to allocate memory for select() sets - exiting!"); + return (1); + } + + /* + * Read configuration... + */ + + if (!cupsdReadConfiguration()) + { + syslog(LOG_LPR, "Unable to read configuration file \'%s\' - exiting!", + ConfigurationFile); + return (1); + } + + /* + * 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); + sigaddset(&action.sa_mask, SIGCHLD); + 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 */ + +#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 = cupsFileOpen("/var/spool/lp/SCHEDLOCK", "w")) == NULL) + { + syslog(LOG_LPR, "Unable to create fake lpsched lock file " + "\"/var/spool/lp/SCHEDLOCK\"\' - %s!", + strerror(errno)); + } + else + { + fchmod(cupsFileNumber(fp), 0644); + fchown(cupsFileNumber(fp), User, Group); + + cupsFileClose(fp); + } +#endif /* __sgi */ + + /* + * Initialize authentication certificates... + */ + + cupsdInitCerts(); + + /* + * If we are running in the background, signal the parent process that + * we are up and running... + */ + + if (!fg) + { + /* + * Send a signal to the parent process, but only if the parent is + * not PID 1 (init). This avoids accidentally shutting down the + * system on OpenBSD if you CTRL-C the server before it is up... + */ + + i = getppid(); /* Save parent PID to avoid race condition */ + + if (i != 1) + kill(i, SIGUSR1); + } + + /* + * If the administrator has configured the server to run as an unpriviledged + * user, change to that user now... + */ + + if (RunAsUser) + { + setgid(Group); + setgroups(1, &Group); + setuid(User); + } + + /* + * Catch signals... + */ + + cupsdCatchChildSignals(); + + /* + * Start any pending print jobs... + */ + + cupsdCheckJobs(); + + /* + * Loop forever... + */ + +#ifdef HAVE_MALLINFO + mallinfo_time = 0; +#endif /* HAVE_MALLINFO */ + browse_time = time(NULL); + senddoc_time = time(NULL); + expire_time = time(NULL); + fds = 1; + + while (!stop_scheduler) + { +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "main: Top of loop, dead_children=%d, NeedReload=%d", + dead_children, NeedReload); +#endif /* DEBUG */ + + /* + * Check if there are dead children to handle... + */ + + if (dead_children) + process_children(); + + /* + * Check if we need to load the server configuration file... + */ + + if (NeedReload) + { + /* + * Close any idle clients... + */ + + if (NumClients > 0) + { + for (i = NumClients, con = Clients; i > 0; i --, con ++) + if (con->http.state == HTTP_WAITING) + { + cupsdCloseClient(con); + con --; + } + else + con->http.keep_alive = HTTP_KEEPALIVE_OFF; + + cupsdPauseListening(); + } + + /* + * Check for any active jobs... + */ + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->state->values[0].integer == IPP_JOB_PROCESSING) + break; + + /* + * Restart if all clients are closed and all jobs finished, or + * if the reload timeout has elapsed... + */ + + if ((NumClients == 0 && (!job || NeedReload != RELOAD_ALL)) || + (time(NULL) - ReloadTime) >= ReloadTimeout) + { + if (!cupsdReadConfiguration()) + { + 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. + */ + + memcpy(input, InputSet, SetSize); + memcpy(output, OutputSet, SetSize); + + timeout.tv_sec = select_timeout(fds); + timeout.tv_usec = 0; + + if ((fds = 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. + */ + + cupsdLogMessage(CUPSD_LOG_EMERG, "select() failed - %s!", + strerror(errno)); + + strcpy(s, "InputSet ="); + slen = 10; + sptr = s + 10; + + for (i = 0; i < MaxFDs; i ++) + if (FD_ISSET(i, InputSet)) + { + snprintf(sptr, sizeof(s) - slen, " %d", i); + slen += strlen(sptr); + sptr += strlen(sptr); + } + + cupsdLogMessage(CUPSD_LOG_EMERG, s); + + strcpy(s, "OutputSet ="); + slen = 11; + sptr = s + 11; + + for (i = 0; i < MaxFDs; i ++) + if (FD_ISSET(i, OutputSet)) + { + snprintf(sptr, sizeof(s) - slen, " %d", i); + slen += strlen(sptr); + sptr += strlen(sptr); + } + + cupsdLogMessage(CUPSD_LOG_EMERG, s); + + for (i = 0, con = Clients; i < NumClients; i ++, con ++) + cupsdLogMessage(CUPSD_LOG_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 ++) + cupsdLogMessage(CUPSD_LOG_EMERG, "Listeners[%d] = %d", i, lis->fd); + + cupsdLogMessage(CUPSD_LOG_EMERG, "BrowseSocket = %d", BrowseSocket); + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + cupsdLogMessage(CUPSD_LOG_EMERG, "Jobs[%d] = %d < [%d %d] > [%d %d]", + job->id, + job->status_buffer ? job->status_buffer->fd : -1, + job->print_pipes[0], job->print_pipes[1], + job->back_pipes[0], job->back_pipes[1]); + break; + } + + current_time = time(NULL); + + /* + * Check for status info from job filters... + */ + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->status_buffer && FD_ISSET(job->status_buffer->fd, input)) + { + /* + * Clear the input bit to avoid updating the next job + * using the same status pipe file descriptor... + */ + + FD_CLR(job->status_buffer->fd, input); + + /* + * Read any status messages from the filters... + */ + + cupsdUpdateJob(job); + } + + /* + * Update CGI messages as needed... + */ + + if (CGIPipes[0] >= 0 && FD_ISSET(CGIPipes[0], input)) + cupsdUpdateCGI(); + + /* + * Update notifier messages as needed... + */ + + if (NotifierPipes[0] >= 0 && FD_ISSET(NotifierPipes[0], input)) + cupsdUpdateNotifierStatus(); + + /* + * Expire subscriptions as needed... + */ + + if (cupsArrayCount(Subscriptions) > 0 && current_time > expire_time) + { + cupsdExpireSubscriptions(NULL, NULL); + + expire_time = current_time; + } + + /* + * Update the browse list as needed... + */ + + if (Browsing && (BrowseLocalProtocols | BrowseRemoteProtocols)) + { + if (BrowseSocket >= 0 && FD_ISSET(BrowseSocket, input)) + cupsdUpdateCUPSBrowse(); + + if (PollPipe >= 0 && FD_ISSET(PollPipe, input)) + cupsdUpdatePolling(); + +#ifdef HAVE_LIBSLP + if (((BrowseLocalProtocols | BrowseRemoteProtocols) & BROWSE_SLP) && + BrowseSLPRefresh <= current_time) + cupsdUpdateSLPBrowse(); +#endif /* HAVE_LIBSLP */ + + if (current_time > browse_time) + { + cupsdSendBrowseList(); + browse_time = current_time; + } + } + + /* + * Check for new connections on the "listen" sockets... + */ + + for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) + if (lis->fd >= 0 && FD_ISSET(lis->fd, input)) + { + FD_CLR(lis->fd, input); + cupsdAcceptClient(lis); + } + + /* + * Check for new data on the client sockets... + */ + + for (i = NumClients, con = Clients; i > 0; i --, con ++) + { + /* + * Process the input buffer... + */ + + if (FD_ISSET(con->http.fd, input) || con->http.used) + { + FD_CLR(con->http.fd, input); + + if (!cupsdReadClient(con)) + { + if (con->pipe_pid) + FD_CLR(con->file, input); + + con --; + continue; + } + } + + /* + * Write data as needed... + */ + + if (con->pipe_pid && FD_ISSET(con->file, input)) + { + /* + * Keep track of pending input from the file/pipe separately + * so that we don't needlessly spin on select() when the web + * client is not ready to receive data... + */ + + FD_CLR(con->file, input); + con->file_ready = 1; + +#ifdef DEBUG + cupsdLogMessage(CUPSD_LOG_DEBUG2, "main: Data ready file %d!", + con->file); +#endif /* DEBUG */ + + if (!FD_ISSET(con->http.fd, output)) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "main: Removing fd %d from InputSet...", con->file); + FD_CLR(con->file, InputSet); + } + } + + if (FD_ISSET(con->http.fd, output)) + { + FD_CLR(con->http.fd, output); + + if (!con->pipe_pid || con->file_ready) + if (!cupsdWriteClient(con)) + { + con --; + continue; + } + } + + /* + * Check the activity and close old clients... + */ + + activity = current_time - Timeout; + if (con->http.activity < activity && !con->pipe_pid) + { + cupsdLogMessage(CUPSD_LOG_DEBUG, + "Closing client %d after %d seconds of inactivity...", + con->http.fd, Timeout); + + cupsdCloseClient(con); + con --; + continue; + } + } + + /* + * Update any pending multi-file documents... + */ + + if ((current_time - senddoc_time) >= 10) + { + cupsdCheckJobs(); + senddoc_time = current_time; + } + +#ifdef HAVE_MALLINFO + /* + * Log memory usage every minute... + */ + + if ((current_time - mallinfo_time) >= 60 && LogLevel >= CUPSD_LOG_DEBUG) + { + struct mallinfo mem; /* Malloc information */ + + + mem = mallinfo(); + cupsdLogMessage(CUPSD_LOG_DEBUG, + "mallinfo: arena = %d, used = %d, free = %d\n", + mem.arena, mem.usmblks + mem.uordblks, + mem.fsmblks + mem.fordblks); + mallinfo_time = current_time; + } +#endif /* HAVE_MALLINFO */ + + /* + * Update the root certificate once every 5 minutes... + */ + + if ((current_time - RootCertTime) >= RootCertDuration && RootCertDuration && + !RunUser) + { + /* + * Update the root certificate... + */ + + cupsdDeleteCert(0); + cupsdAddCert(0, "root"); + } + } + + /* + * Log a message based on what happened... + */ + + if (stop_scheduler) + cupsdLogMessage(CUPSD_LOG_INFO, "Scheduler shutting down normally."); + else + cupsdLogMessage(CUPSD_LOG_ERROR, + "Scheduler shutting down due to program error."); + + /* + * Close all network clients and stop all jobs... + */ + + cupsdStopServer(); + + cupsdStopAllJobs(); + +#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 */ + + /* + * Free memory used by FD sets and return... + */ + + free(InputSet); + free(OutputSet); + free(input); + free(output); + + return (!stop_scheduler); +} + + +/* + * 'cupsdClosePipe()' - Close a pipe as necessary. + */ + +void +cupsdClosePipe(int *fds) /* I - Pipe file descriptors (2) */ +{ + /* + * Close file descriptors as needed... + */ + + if (fds[0] >= 0) + { + close(fds[0]); + fds[0] = -1; + } + + if (fds[1] >= 0) + { + close(fds[1]); + fds[1] = -1; + } +} + + +/* + * 'cupsdOpenPipe()' - Create a pipe which is closed on exec. + */ + +int /* O - 0 on success, -1 on error */ +cupsdOpenPipe(int *fds) /* O - Pipe file descriptors (2) */ +{ + /* + * Create the pipe... + */ + + if (pipe(fds)) + return (-1); + + /* + * Set the "close on exec" flag on each end of the pipe... + */ + + if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC)) + { + close(fds[0]); + close(fds[1]); + return (-1); + } + + if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC)) + { + close(fds[0]); + close(fds[1]); + return (-1); + } + + /* + * Return 0 indicating success... + */ + + return (0); +} + + +/* + * 'cupsdCatchChildSignals()' - Catch SIGCHLD signals... + */ + +void +cupsdCatchChildSignals(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, SIGTERM); + 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 */ +} + + +/* + * 'cupsdClearString()' - Clear a string. + */ + +void +cupsdClearString(char **s) /* O - String value */ +{ + if (s && *s) + { + free(*s); + *s = NULL; + } +} + + +/* + * 'cupsdHoldSignals()' - Hold child and termination signals. + */ + +void +cupsdHoldSignals(void) +{ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + sigset_t newmask; /* New POSIX signal mask */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + holdcount ++; + if (holdcount > 1) + return; + +#ifdef HAVE_SIGSET + sighold(SIGTERM); + sighold(SIGCHLD); +#elif defined(HAVE_SIGACTION) + sigemptyset(&newmask); + sigaddset(&newmask, SIGTERM); + sigaddset(&newmask, SIGCHLD); + sigprocmask(SIG_BLOCK, &newmask, &holdmask); +#endif /* HAVE_SIGSET */ +} + + +/* + * 'cupsdIgnoreChildSignals()' - Ignore SIGCHLD signals... + * + * We don't really ignore them, we set the signal handler to SIG_DFL, + * since some OS's rely on signals for the wait4() function to work. + */ + +void +cupsdIgnoreChildSignals(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_DFL); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + sigaddset(&action.sa_mask, SIGCHLD); + action.sa_handler = SIG_DFL; + sigaction(SIGCHLD, &action, NULL); +#else + signal(SIGCLD, SIG_DFL); /* No, SIGCLD isn't a typo... */ +#endif /* HAVE_SIGSET */ +} + + +/* + * 'cupsdReleaseSignals()' - Release signals for delivery. + */ + +void +cupsdReleaseSignals(void) +{ + holdcount --; + if (holdcount > 0) + return; + +#ifdef HAVE_SIGSET + sigrelse(SIGTERM); + sigrelse(SIGCHLD); +#elif defined(HAVE_SIGACTION) + sigprocmask(SIG_SETMASK, &holdmask, NULL); +#endif /* HAVE_SIGSET */ +} + + +/* + * 'cupsdSetString()' - Set a string value. + */ + +void +cupsdSetString(char **s, /* O - New string */ + const char *v) /* I - String value */ +{ + if (!s || *s == v) + return; + + if (*s) + free(*s); + + if (v) + *s = strdup(v); + else + *s = NULL; +} + + +/* + * 'cupsdSetStringf()' - Set a formatted string value. + */ + +void +cupsdSetStringf(char **s, /* O - New string */ + const char *f, /* I - Printf-style format string */ + ...) /* I - Additional args as needed */ +{ + char v[4096]; /* Formatting string value */ + va_list ap; /* Argument pointer */ + char *olds; /* Old string */ + + + if (!s) + return; + + olds = *s; + + if (f) + { + va_start(ap, f); + vsnprintf(v, sizeof(v), f, ap); + va_end(ap); + + *s = strdup(v); + } + else + *s = NULL; + + if (olds) + free(olds); +} + + +/* + * 'parent_handler()' - Catch USR1/CHLD signals... + */ + +static void +parent_handler(int sig) /* I - Signal */ +{ + /* + * Store the signal we got from the OS and return... + */ + + parent_signal = sig; +} + + +/* + * 'process_children()' - Process all dead children... + */ + +static void +process_children(void) +{ + int status; /* Exit status of child */ + int pid; /* Process ID of child */ + cupsd_job_t *job; /* Current job */ + int i; /* Looping var */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "process_children()"); + + /* + * Reset the dead_children flag... + */ + + dead_children = 0; + + /* + * Collect the exit status of some children... + */ + +#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 */ + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "process_children: pid = %d, status = %d\n", pid, status); + + /* + * Ignore SIGTERM errors - that comes when a job is cancelled... + */ + + if (status == SIGTERM) + status = 0; + + if (status) + { + if (WIFEXITED(status)) + cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d stopped with status %d!", pid, + WEXITSTATUS(status)); + else + cupsdLogMessage(CUPSD_LOG_ERROR, "PID %d crashed on signal %d!", pid, + WTERMSIG(status)); + + if (LogLevel < CUPSD_LOG_DEBUG) + cupsdLogMessage(CUPSD_LOG_INFO, + "Hint: Try setting the LogLevel to \"debug\" to find out more."); + } + else + cupsdLogMessage(CUPSD_LOG_DEBUG2, "PID %d exited with no errors.", pid); + + /* + * Delete certificates for CGI processes... + */ + + if (pid) + cupsdDeleteCert(pid); + + /* + * Lookup the PID in the jobs list... + */ + + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->state != NULL && + job->state->values[0].integer == IPP_JOB_PROCESSING) + { + for (i = 0; job->filters[i]; i ++) + if (job->filters[i] == pid) + break; + + if (job->filters[i] || job->backend == pid) + { + /* + * OK, this process has gone away; what's left? + */ + + if (job->filters[i]) + job->filters[i] = -pid; + else + job->backend = -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->filters[i]) + job->status = status; /* Filter failed */ + else + job->status = -status; /* Backend failed */ + } + + /* + * If this is not the last file in a job, see if all of the + * filters are done, and if so move to the next file. + */ + + if (job->current_file < job->num_files) + { + for (i = 0; job->filters[i] < 0; i ++); + + if (!job->filters[i]) + { + /* + * Process the next file... + */ + + cupsdFinishJob(job); + } + } + break; + } + } + } +} + + +/* + * 'sigchld_handler()' - Handle 'child' signals from old processes. + */ + +static void +sigchld_handler(int sig) /* I - Signal number */ +{ + (void)sig; + + /* + * Flag that we have dead children... + */ + + dead_children = 1; + + /* + * Reset the signal handler as needed... + */ + +#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION) + signal(SIGCLD, sigchld_handler); +#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */ +} + + +/* + * 'sighup_handler()' - Handle 'hangup' signals to reconfigure the scheduler. + */ + +static void +sighup_handler(int sig) /* I - Signal number */ +{ + (void)sig; + + NeedReload = RELOAD_ALL; + ReloadTime = time(NULL); + +#if !defined(HAVE_SIGSET) && !defined(HAVE_SIGACTION) + signal(SIGHUP, sighup_handler); +#endif /* !HAVE_SIGSET && !HAVE_SIGACTION */ +} + + +/* + * 'sigterm_handler()' - Handle 'terminate' signals that stop the scheduler. + */ + +static void +sigterm_handler(int sig) /* I - Signal */ +{ + (void)sig; /* remove compiler warnings... */ + + /* + * Flag that we should stop and return... + */ + + stop_scheduler = 1; +} + + +/* + * 'select_timeout()' - Calculate the select timeout value. + * + */ + +static long /* O - Number of seconds */ +select_timeout(int fds) /* I - Number of ready descriptors select returned */ +{ + int i; /* Looping var */ + long timeout; /* Timeout for select */ + time_t now; /* Current time */ + cupsd_client_t *con; /* Client information */ + cupsd_printer_t *p; /* Printer information */ + cupsd_job_t *job; /* Job information */ + cupsd_subscription_t *sub; /* Subscription information */ + const char *why; /* Debugging aid */ + + + /* + * Check to see if any of the clients have pending data to be + * processed; if so, the timeout should be 0... + */ + + for (i = NumClients, con = Clients; i > 0; i --, con ++) + if (con->http.used > 0) + return (0); + + /* + * If select has been active in the last second (fds != 0) or we have + * many resources in use then don't bother trying to optimize the + * timeout, just make it 1 second. + */ + + if (fds || NumClients > 50) + return (1); + + /* + * Otherwise, check all of the possible events that we need to wake for... + */ + + now = time(NULL); + timeout = now + 86400; /* 86400 == 1 day */ + why = "do nothing"; + + /* + * Check the activity and close old clients... + */ + + for (i = NumClients, con = Clients; i > 0; i --, con ++) + if ((con->http.activity + Timeout) < timeout) + { + timeout = con->http.activity + Timeout; + why = "timeout a client connection"; + } + + /* + * Update the browse list as needed... + */ + + if (Browsing && BrowseLocalProtocols) + { +#ifdef HAVE_LIBSLP + if ((BrowseLocalProtocols & BROWSE_SLP) && (BrowseSLPRefresh < timeout)) + { + timeout = BrowseSLPRefresh; + why = "update SLP browsing"; + } +#endif /* HAVE_LIBSLP */ + + if (BrowseLocalProtocols & BROWSE_CUPS) + { + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + if (p->type & CUPS_PRINTER_REMOTE) + { + if ((p->browse_time + BrowseTimeout) < timeout) + { + timeout = p->browse_time + BrowseTimeout; + why = "browse timeout a printer"; + } + } + else if (!(p->type & CUPS_PRINTER_IMPLICIT)) + { + if (BrowseInterval && (p->browse_time + BrowseInterval) < timeout) + { + timeout = p->browse_time + BrowseInterval; + why = "send browse update"; + } + } + } + } + } + + /* + * Check for any active jobs... + */ + + if (timeout > (now + 10) && ActiveJobs) + { + for (job = (cupsd_job_t *)cupsArrayFirst(ActiveJobs); + job; + job = (cupsd_job_t *)cupsArrayNext(ActiveJobs)) + if (job->state->values[0].integer <= IPP_JOB_PROCESSING) + { + timeout = now + 10; + why = "process active jobs"; + break; + } + } + +#ifdef HAVE_MALLINFO + /* + * Log memory usage every minute... + */ + + if (LogLevel >= CUPSD_LOG_DEBUG && (mallinfo_time + 60) < timeout) + { + timeout = mallinfo_time + 60; + why = "display memory usage"; + } +#endif /* HAVE_MALLINFO */ + + /* + * Update the root certificate when needed... + */ + + if (!RunUser && RootCertDuration && + (RootCertTime + RootCertDuration) < timeout) + { + timeout = RootCertTime + RootCertDuration; + why = "update root certificate"; + } + + /* + * Expire subscriptions as needed... + */ + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + if (!sub->job && sub->expire < timeout) + { + timeout = sub->expire; + why = "expire subscription"; + } + + /* + * Adjust from absolute to relative time. If p->browse_time above + * was 0 then we can end up with a negative value here, so check. + * We add 1 second to the timeout since events occur after the + * timeout expires, and limit the timeout to 86400 seconds (1 day) + * to avoid select() timeout limits present on some operating + * systems... + */ + + timeout = timeout - now + 1; + + if (timeout < 1) + timeout = 1; + else if (timeout > 86400) + timeout = 86400; + + /* + * Log and return the timeout value... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "select_timeout: %ld seconds to %s", + timeout, why); + + return (timeout); +} + + +/* + * 'usage()' - Show scheduler usage. + */ + +static void +usage(void) +{ + fputs("Usage: cupsd [-c config-file] [-f] [-F]\n", stderr); + exit(1); +} + + +/* + * End of "$Id: main.c 4838 2005-11-14 18:34:27Z mike $". + */ diff --git a/scheduler/mime.c b/scheduler/mime.c new file mode 100644 index 000000000..236ae11dc --- /dev/null +++ b/scheduler/mime.c @@ -0,0 +1,573 @@ +/* + * "$Id: mime.c 4613 2005-08-30 12:41:48Z mike $" + * + * MIME database file routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * 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 +#include +#include + +#include +#include "mime.h" + +#ifdef WIN32 +# include +#else +# include +#endif /* WIN32 */ + + +/* + * Local functions... + */ + +static void load_types(mime_t *mime, const char *filename); +static void load_convs(mime_t *mime, const char *filename, + const char *filterpath); +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]->type); + 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 */ + const char *filterpath)/* 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); + + strlcpy(filename, pathname, sizeof(filename)); + + 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 */ + struct 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 (strlen(dent->d_name) > 6 && + strcmp(dent->d_name + strlen(dent->d_name) - 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 (strlen(dent->d_name) > 6 && + strcmp(dent->d_name + strlen(dent->d_name) - 6, ".convs") == 0) + { + /* + * Load a mime.convs file... + */ + + snprintf(filename, sizeof(filename), "%s/%s", pathname, dent->d_name); + load_convs(mime, filename, filterpath); + } + } + + 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 */ + const char *filename) /* I - Types file to load */ +{ + cups_file_t *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 = cupsFileOpen(filename, "r")) == NULL) + return; + + /* + * Then read each line from the file, skipping any comments in the file... + */ + + while (cupsFileGets(fp, line, sizeof(line)) != NULL) + { + /* + * Skip blank lines and lines starting with a #... + */ + + if (!line[0] || line[0] == '#') + continue; + + /* + * While the last character in the line is a backslash, continue on to the + * next line (and the next, etc.) + */ + + linelen = strlen(line); + + while (line[linelen - 1] == '\\') + { + linelen --; + + if (cupsFileGets(fp, line + linelen, sizeof(line) - linelen) == NULL) + line[linelen] = '\0'; + else + linelen += strlen(line + linelen); + } + + /* + * 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++ & 255); + + *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++ & 255); + + *temp = '\0'; + + /* + * Add the type and rules to the MIME database... + */ + + typeptr = mimeAddType(mime, super, type); + mimeAddTypeRule(typeptr, lineptr); + } + + cupsFileClose(fp); +} + + +/* + * 'load_convs()' - Load a xyz.convs file... + */ + +static void +load_convs(mime_t *mime, /* I - MIME database */ + const char *filename, /* I - Convs file to load */ + const char *filterpath) /* I - Directory to load */ +{ + int i; /* Looping var */ + cups_file_t *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 */ + char filterprog[1024]; /* Full path of filter... */ + + + /* + * First try to open the file... + */ + + if ((fp = cupsFileOpen(filename, "r")) == NULL) + return; + + /* + * Then read each line from the file, skipping any comments in the file... + */ + + while (cupsFileGets(fp, line, sizeof(line)) != NULL) + { + /* + * Skip blank lines and lines starting with a #... + */ + + if (!line[0] || line[0] == '#') + continue; + + /* + * Strip trailing whitespace... + */ + + for (lineptr = line + strlen(line) - 1; + lineptr >= line && isspace(*lineptr & 255); + 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++ & 255); + + *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++ & 255); + + *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; + +#ifndef WIN32 + if (strcmp(filter, "-") != 0) + { + /* + * Verify that the filter exists and is executable... + */ + + if (filter[0] == '/') + strlcpy(filterprog, filter, sizeof(filterprog)); + else + snprintf(filterprog, sizeof(filterprog), "%s/%s", filterpath, filter); + + if (access(filterprog, X_OK)) + continue; + } +#endif /* !WIN32 */ + + /* + * 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++ & 255); + + *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++ & 255); + + *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); + } + + cupsFileClose(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: mime.c 4613 2005-08-30 12:41:48Z mike $". + */ diff --git a/scheduler/mime.h b/scheduler/mime.h new file mode 100644 index 000000000..93a1f4ed3 --- /dev/null +++ b/scheduler/mime.h @@ -0,0 +1,147 @@ +/* + * "$Id: mime.h 4613 2005-08-30 12:41:48Z mike $" + * + * MIME type/conversion database definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_MIME_H_ +# define _CUPS_MIME_H_ + +# include +# include + + +/* + * C++ magic... + */ + +# ifdef _cplusplus +extern "C" { +# endif /* _cplusplus */ + + +/* + * Constants... + */ + +# define MIME_MAX_SUPER 16 /* Maximum size of supertype name */ +# define MIME_MAX_TYPE IPP_MAX_NAME /* 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_MAGIC_ISTRING /* Case-insensitive string matches */ +} 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; /* 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,filterpath) \ + mimeMerge((mime_t *)0, (pathname), (filterpath)) +extern mime_t *mimeMerge(mime_t *mime, const char *pathname, + const char *filterpath); +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, + int *compression); +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, int max_depth); + +# ifdef _cplusplus +} +# endif /* _cplusplus */ +#endif /* !_CUPS_MIME_H_ */ + +/* + * End of "$Id: mime.h 4613 2005-08-30 12:41:48Z mike $". + */ diff --git a/scheduler/network.c b/scheduler/network.c new file mode 100644 index 000000000..0065dc09c --- /dev/null +++ b/scheduler/network.c @@ -0,0 +1,576 @@ +/* + * "$Id: network.c 4779 2005-10-12 19:44:42Z mike $" + * + * Network interface functions for the Common UNIX Printing System + * (CUPS) scheduler. + * + * Copyright 1997-2005 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdNetIFFind() - Find a network interface. + * cupsdNetIFFree() - Free the current network interface list. + * cupsdNetIFUpdate() - Update the network interface list as needed... + * getifaddrs() - Get a list of network interfaces on the system. + * freeifaddrs() - Free an interface list... + */ + +/* + * Include necessary headers. + */ + +#include "cupsd.h" + +#include + +#ifdef HAVE_GETIFADDRS +/* + * Use native getifaddrs() function... + */ +# include +#else +/* + * Use getifaddrs() emulation... + */ + +# include +# ifdef HAVE_SYS_SOCKIO_H +# include +# endif + +# ifdef ifa_dstaddr +# undef ifa_dstaddr +# endif /* ifa_dstaddr */ +# ifndef ifr_netmask +# define ifr_netmask ifr_addr +# endif /* !ifr_netmask */ + +struct ifaddrs /**** Interface Structure ****/ +{ + struct ifaddrs *ifa_next; /* Next interface in list */ + char *ifa_name; /* Name of interface */ + unsigned int ifa_flags; /* Flags (up, point-to-point, etc.) */ + struct sockaddr *ifa_addr, /* Network address */ + *ifa_netmask, /* Address mask */ + *ifa_dstaddr; /* Broadcast or destination address */ + void *ifa_data; /* Interface statistics */ +}; + +int getifaddrs(struct ifaddrs **addrs); +void freeifaddrs(struct ifaddrs *addrs); +#endif /* HAVE_GETIFADDRS */ + + +/* + * 'cupsdNetIFFind()' - Find a network interface. + */ + +cupsd_netif_t * /* O - Network interface data */ +cupsdNetIFFind(const char *name) /* I - Name of interface */ +{ + cupsd_netif_t *temp; /* Current network interface */ + + + /* + * Update the interface list as needed... + */ + + cupsdNetIFUpdate(); + + /* + * Search for the named interface... + */ + + for (temp = NetIFList; temp != NULL; temp = temp->next) + if (!strcasecmp(name, temp->name)) + return (temp); + + return (NULL); +} + + +/* + * 'cupsdNetIFFree()' - Free the current network interface list. + */ + +void +cupsdNetIFFree(void) +{ + cupsd_netif_t *next; /* Next interface in list */ + + + /* + * Loop through the interface list and free all the records... + */ + + while (NetIFList != NULL) + { + next = NetIFList->next; + + free(NetIFList); + + NetIFList = next; + } +} + + +/* + * 'cupsdNetIFUpdate()' - Update the network interface list as needed... + */ + +void +cupsdNetIFUpdate(void) +{ + int i, /* Looping var */ + match; /* Matching address? */ + cupsd_listener_t *lis; /* Listen address */ + cupsd_netif_t *temp, /* New interface */ + *prev, /* Previous interface */ + *current; /* Current interface */ + struct ifaddrs *addrs, /* Interface address list */ + *addr; /* Current interface address */ + http_addrlist_t *saddr; /* Current server address */ + + + /* + * Update the network interface list no more often than once a + * minute... + */ + + if ((time(NULL) - NetIFTime) < 60) + return; + + NetIFTime = time(NULL); + + /* + * Free the old interfaces... + */ + + cupsdNetIFFree(); + + /* + * Grab a new list of interfaces... + */ + + if (getifaddrs(&addrs) < 0) + return; + + for (addr = addrs; addr != NULL; addr = addr->ifa_next) + { + /* + * See if this interface address is IPv4 or IPv6... + */ + + if (addr->ifa_addr == NULL || + (addr->ifa_addr->sa_family != AF_INET +#ifdef AF_INET6 + && addr->ifa_addr->sa_family != AF_INET6 +#endif + ) || + addr->ifa_netmask == NULL || addr->ifa_name == NULL) + continue; + + /* + * OK, we have an IPv4/6 address, so create a new list node... + */ + + if ((temp = calloc(1, sizeof(cupsd_netif_t))) == NULL) + break; + + /* + * Insert the node in sorted order; since we don't expect to + * have a lot of network interfaces, we just do a simple linear + * search... + */ + + for (current = NetIFList, prev = NULL; + current; + prev = current, current = current->next) + if (strcasecmp(addr->ifa_name, current->name) <= 0) + break; + + if (current) + temp->next = current; + + if (prev) + prev->next = temp; + else + NetIFList = temp; + + /* + * Then copy all of the information... + */ + + strlcpy(temp->name, addr->ifa_name, sizeof(temp->name)); + + if (addr->ifa_addr->sa_family == AF_INET) + { + /* + * Copy IPv4 addresses... + */ + + memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in)); + memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in)); + + if (addr->ifa_dstaddr) + memcpy(&(temp->broadcast), addr->ifa_dstaddr, + sizeof(struct sockaddr_in)); + } +#ifdef AF_INET6 + else + { + /* + * Copy IPv6 addresses... + */ + + memcpy(&(temp->address), addr->ifa_addr, sizeof(struct sockaddr_in6)); + memcpy(&(temp->mask), addr->ifa_netmask, sizeof(struct sockaddr_in6)); + + if (addr->ifa_dstaddr) + memcpy(&(temp->broadcast), addr->ifa_dstaddr, + sizeof(struct sockaddr_in6)); + } +#endif /* AF_INET6 */ + + if (!(addr->ifa_flags & IFF_POINTOPOINT) && + !httpAddrLocalhost(&(temp->address))) + temp->is_local = 1; + + /* + * Determine which port to use when advertising printers... + */ + + for (i = NumListeners, lis = Listeners; i > 0; i --, lis ++) + { + match = 0; + + if (httpAddrAny(&(lis->address))) + match = 1; + else if (addr->ifa_addr->sa_family == AF_INET && + lis->address.addr.sa_family == AF_INET && + (lis->address.ipv4.sin_addr.s_addr & + temp->mask.ipv4.sin_addr.s_addr) == + temp->address.ipv4.sin_addr.s_addr) + match = 1; +#ifdef AF_INET6 + else if (addr->ifa_addr->sa_family == AF_INET6 && + lis->address.addr.sa_family == AF_INET6 && + (lis->address.ipv6.sin6_addr.s6_addr[0] & + temp->mask.ipv6.sin6_addr.s6_addr[0]) == + temp->address.ipv6.sin6_addr.s6_addr[0] && + (lis->address.ipv6.sin6_addr.s6_addr[1] & + temp->mask.ipv6.sin6_addr.s6_addr[1]) == + temp->address.ipv6.sin6_addr.s6_addr[1] && + (lis->address.ipv6.sin6_addr.s6_addr[2] & + temp->mask.ipv6.sin6_addr.s6_addr[2]) == + temp->address.ipv6.sin6_addr.s6_addr[2] && + (lis->address.ipv6.sin6_addr.s6_addr[3] & + temp->mask.ipv6.sin6_addr.s6_addr[3]) == + temp->address.ipv6.sin6_addr.s6_addr[3]) + match = 1; +#endif /* AF_INET6 */ + + if (match) + { + if (lis->address.addr.sa_family == AF_INET) + temp->port = ntohs(lis->address.ipv4.sin_port); +#ifdef AF_INET6 + else if (lis->address.addr.sa_family == AF_INET6) + temp->port = ntohs(lis->address.ipv6.sin6_port); +#endif /* AF_INET6 */ + break; + } + } + + /* + * Finally, try looking up the hostname for the address as needed... + */ + + if (HostNameLookups) + httpAddrLookup(&(temp->address), temp->hostname, sizeof(temp->hostname)); + else + { + /* + * Map the default server address and localhost to the server name + * and localhost, respectively; for all other addresses, use the + * dotted notation... + */ + + if (httpAddrLocalhost(&(temp->address))) + strcpy(temp->hostname, "localhost"); + else + { + for (saddr = ServerAddrs; saddr; saddr = saddr->next) + if (httpAddrEqual(&(temp->address), &(saddr->addr))) + break; + + if (saddr) + strlcpy(temp->hostname, ServerName, sizeof(temp->hostname)); + else + httpAddrString(&(temp->address), temp->hostname, + sizeof(temp->hostname)); + } + } + + cupsdLogMessage(CUPSD_LOG_DEBUG, "cupsdNetIFUpdate: \"%s\" = %s...", + temp->name, temp->hostname); + } + + freeifaddrs(addrs); +} + + +#ifndef HAVE_GETIFADDRS +/* + * 'getifaddrs()' - Get a list of network interfaces on the system. + */ + +int /* O - 0 on success, -1 on error */ +getifaddrs(struct ifaddrs **addrs) /* O - List of interfaces */ +{ + int sock; /* Socket */ + char buffer[65536], /* Buffer for address info */ + *bufptr, /* Pointer into buffer */ + *bufend; /* End of buffer */ + struct ifconf conf; /* Interface configurations */ + struct sockaddr addr; /* Address data */ + struct ifreq *ifp; /* Interface data */ + int ifpsize; /* Size of interface data */ + struct ifaddrs *temp; /* Pointer to current interface */ + struct ifreq request; /* Interface request */ + + + /* + * Start with an empty list... + */ + + if (addrs == NULL) + return (-1); + + *addrs = NULL; + + /* + * Create a UDP socket to get the interface data... + */ + + memset (&addr, 0, sizeof(addr)); + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (-1); + + /* + * Try to get the list of interfaces... + */ + + conf.ifc_len = sizeof(buffer); + conf.ifc_buf = buffer; + + if (ioctl(sock, SIOCGIFCONF, &conf) < 0) + { + /* + * Couldn't get the list of interfaces... + */ + + close(sock); + return (-1); + } + + /* + * OK, got the list of interfaces, now lets step through the + * buffer to pull them out... + */ + +# ifdef HAVE_STRUCT_SOCKADDR_SA_LEN +# define sockaddr_len(a) ((a)->sa_len) +# else +# define sockaddr_len(a) (sizeof(struct sockaddr)) +# endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */ + + for (bufptr = buffer, bufend = buffer + conf.ifc_len; + bufptr < bufend; + bufptr += ifpsize) + { + /* + * Get the current interface information... + */ + + ifp = (struct ifreq *)bufptr; + ifpsize = sizeof(ifp->ifr_name) + sockaddr_len(&(ifp->ifr_addr)); + + if (ifpsize < sizeof(struct ifreq)) + ifpsize = sizeof(struct ifreq); + + memset(&request, 0, sizeof(request)); + memcpy(request.ifr_name, ifp->ifr_name, sizeof(ifp->ifr_name)); + + /* + * Check the status of the interface... + */ + + if (ioctl(sock, SIOCGIFFLAGS, &request) < 0) + continue; + + /* + * Allocate memory for a single interface record... + */ + + if ((temp = calloc(1, sizeof(struct ifaddrs))) == NULL) + { + /* + * Unable to allocate memory... + */ + + close(sock); + return (-1); + } + + /* + * Add this record to the front of the list and copy the name, flags, + * and network address... + */ + + temp->ifa_next = *addrs; + *addrs = temp; + temp->ifa_name = strdup(ifp->ifr_name); + temp->ifa_flags = request.ifr_flags; + if ((temp->ifa_addr = calloc(1, sockaddr_len(&(ifp->ifr_addr)))) != NULL) + memcpy(temp->ifa_addr, &(ifp->ifr_addr), sockaddr_len(&(ifp->ifr_addr))); + + /* + * Try to get the netmask for the interface... + */ + + if (!ioctl(sock, SIOCGIFNETMASK, &request)) + { + /* + * Got it, make a copy... + */ + + if ((temp->ifa_netmask = calloc(1, sizeof(request.ifr_netmask))) != NULL) + memcpy(temp->ifa_netmask, &(request.ifr_netmask), + sizeof(request.ifr_netmask)); + } + + /* + * Then get the broadcast or point-to-point (destination) address, + * if applicable... + */ + + if (temp->ifa_flags & IFF_BROADCAST) + { + /* + * Have a broadcast address, so get it! + */ + + if (!ioctl(sock, SIOCGIFBRDADDR, &request)) + { + /* + * Got it, make a copy... + */ + + if ((temp->ifa_dstaddr = calloc(1, sizeof(request.ifr_broadaddr))) != NULL) + memcpy(temp->ifa_dstaddr, &(request.ifr_broadaddr), + sizeof(request.ifr_broadaddr)); + } + } + else if (temp->ifa_flags & IFF_POINTOPOINT) + { + /* + * Point-to-point interface; grab the remote address... + */ + + if (!ioctl(sock, SIOCGIFDSTADDR, &request)) + { + temp->ifa_dstaddr = malloc(sizeof(request.ifr_dstaddr)); + memcpy(temp->ifa_dstaddr, &(request.ifr_dstaddr), + sizeof(request.ifr_dstaddr)); + } + } + } + + /* + * OK, we're done with the socket, close it and return 0... + */ + + close(sock); + + return (0); +} + + +/* + * 'freeifaddrs()' - Free an interface list... + */ + +void +freeifaddrs(struct ifaddrs *addrs) /* I - Interface list to free */ +{ + struct ifaddrs *next; /* Next interface in list */ + + + while (addrs != NULL) + { + /* + * Make a copy of the next interface pointer... + */ + + next = addrs->ifa_next; + + /* + * Free data values as needed... + */ + + if (addrs->ifa_name) + { + free(addrs->ifa_name); + addrs->ifa_name = NULL; + } + + if (addrs->ifa_addr) + { + free(addrs->ifa_addr); + addrs->ifa_addr = NULL; + } + + if (addrs->ifa_netmask) + { + free(addrs->ifa_netmask); + addrs->ifa_netmask = NULL; + } + + if (addrs->ifa_dstaddr) + { + free(addrs->ifa_dstaddr); + addrs->ifa_dstaddr = NULL; + } + + /* + * Free this node and continue to the next... + */ + + free(addrs); + + addrs = next; + } +} +#endif /* !HAVE_GETIFADDRS */ + + +/* + * End of "$Id: network.c 4779 2005-10-12 19:44:42Z mike $". + */ diff --git a/scheduler/network.h b/scheduler/network.h new file mode 100644 index 000000000..a04b539fd --- /dev/null +++ b/scheduler/network.h @@ -0,0 +1,64 @@ +/* + * "$Id: network.h 4719 2005-09-28 21:12:44Z mike $" + * + * Network interface definitions for the Common UNIX Printing System + * (CUPS) scheduler. + * + * Copyright 1997-2005 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 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Structures... + */ + +typedef struct cupsd_netif_s /**** Network interface data ****/ +{ + struct cupsd_netif_s *next; /* Next interface in list */ + char name[32], /* Network interface name */ + hostname[HTTP_MAX_HOST]; + /* Hostname associated with interface */ + int is_local, /* Local (not point-to-point) interface? */ + port; /* Listen port */ + http_addr_t address, /* Network address */ + mask, /* Network mask */ + broadcast; /* Broadcast address */ +} cupsd_netif_t; + + +/* + * Globals... + */ + +VAR time_t NetIFTime VALUE(0); + /* Network interface list time */ +VAR cupsd_netif_t *NetIFList VALUE(NULL); + /* List of network interfaces */ + +/* + * Prototypes... + */ + +extern cupsd_netif_t *cupsdNetIFFind(const char *name); +extern void cupsdNetIFFree(void); +extern void cupsdNetIFUpdate(void); + + +/* + * End of "$Id: network.h 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/policy.c b/scheduler/policy.c new file mode 100644 index 000000000..6f9371b21 --- /dev/null +++ b/scheduler/policy.c @@ -0,0 +1,337 @@ +/* + * "$Id: policy.c 4871 2005-12-07 00:41:11Z mike $" + * + * Policy routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddPolicy() - Add a policy to the system. + * cupsdAddPolicyOp() - Add an operation to a policy. + * cupsdCheckPolicy() - Check the IPP operation and username against + * a policy. + * cupsdDeleteAllPolicies() - Delete all policies in memory. + * cupsdFindPolicy() - Find a named policy. + * cupsdFindPolicyOp() - Find a policy operation. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + + +/* + * 'AddPolicy()' - Add a policy to the system. + */ + +cupsd_policy_t * /* O - Policy */ +cupsdAddPolicy(const char *policy) /* I - Name of policy */ +{ + cupsd_policy_t *temp, /* Pointer to policy */ + **tempa; /* Pointer to policy array */ + + + if (policy == NULL) + return (NULL); + + if (NumPolicies == 0) + tempa = malloc(sizeof(cupsd_policy_t *)); + else + tempa = realloc(Policies, sizeof(cupsd_policy_t *) * (NumPolicies + 1)); + + if (tempa == NULL) + return (NULL); + + Policies = tempa; + tempa += NumPolicies; + + if ((temp = calloc(1, sizeof(cupsd_policy_t))) != NULL) + { + temp->name = strdup(policy); + *tempa = temp; + + NumPolicies ++; + } + + return (temp); +} + + +/* + * 'cupsdAddPolicyOp()' - Add an operation to a policy. + */ + +cupsd_location_t * /* O - New policy operation */ +cupsdAddPolicyOp(cupsd_policy_t *p, /* I - Policy */ + cupsd_location_t *po, /* I - Policy operation to copy */ + ipp_op_t op) /* I - IPP operation code */ +{ + int i; /* Looping var */ + cupsd_location_t *temp, /* New policy operation */ + **tempa; /* New policy operation array */ + char name[1024]; /* Interface name */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPolicyOp(p=%p, po=%p, op=%x(%s))", + p, po, op, ippOpString(op)); + + if (p == NULL) + return (NULL); + + if (p->num_ops == 0) + tempa = malloc(sizeof(cupsd_location_t *)); + else + tempa = realloc(p->ops, sizeof(cupsd_location_t *) * (p->num_ops + 1)); + + if (tempa == NULL) + return (NULL); + + p->ops = tempa; + + if ((temp = calloc(1, sizeof(cupsd_location_t))) != NULL) + { + p->ops = tempa; + tempa[p->num_ops] = temp; + p->num_ops ++; + + temp->op = op; + temp->limit = AUTH_LIMIT_IPP; + + if (po) + { + /* + * Copy the specified policy to the new one... + */ + + temp->order_type = po->order_type; + temp->type = po->type; + temp->level = po->level; + temp->satisfy = po->satisfy; + temp->encryption = po->encryption; + + for (i = 0; i < po->num_names; i ++) + cupsdAddName(temp, po->names[i]); + + for (i = 0; i < po->num_allow; i ++) + switch (po->allow[i].type) + { + case AUTH_IP : + cupsdAllowIP(temp, po->allow[i].mask.ip.address, + po->allow[i].mask.ip.netmask); + break; + + case AUTH_INTERFACE : + snprintf(name, sizeof(name), "@IF(%s)", + po->allow[i].mask.name.name); + cupsdAllowHost(temp, name); + break; + + default : + cupsdAllowHost(temp, po->allow[i].mask.name.name); + break; + } + + for (i = 0; i < po->num_deny; i ++) + switch (po->deny[i].type) + { + case AUTH_IP : + cupsdDenyIP(temp, po->deny[i].mask.ip.address, + po->deny[i].mask.ip.netmask); + break; + + case AUTH_INTERFACE : + snprintf(name, sizeof(name), "@IF(%s)", + po->deny[i].mask.name.name); + cupsdDenyHost(temp, name); + break; + + default : + cupsdDenyHost(temp, po->deny[i].mask.name.name); + break; + } + } + } + + return (temp); +} + + +/* + * 'cupsdCheckPolicy()' - Check the IPP operation and username against a policy. + */ + +http_status_t /* I - 1 if OK, 0 otherwise */ +cupsdCheckPolicy(cupsd_policy_t *p, /* I - Policy */ + cupsd_client_t *con, /* I - Client connection */ + const char *owner) /* I - Owner of object */ +{ + cupsd_location_t *po; /* Current policy operation */ + + + /* + * Range check... + */ + + if (!p || !con) + { + cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdCheckPolicy: p=%p, con=%p!", p, con); + + return (0); + } + + /* + * Find a match for the operation... + */ + + if ((po = cupsdFindPolicyOp(p, con->request->request.op.operation_id)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdCheckPolicy: No matching operation, returning 0!"); + return (0); + } + + con->best = po; + + /* + * Return the status of the check... + */ + + return (cupsdIsAuthorized(con, owner)); +} + + +/* + * 'cupsdDeleteAllPolicies()' - Delete all policies in memory. + */ + +void +cupsdDeleteAllPolicies(void) +{ + int i, j; /* Looping vars */ + cupsd_policy_t **p; /* Current policy */ + cupsd_location_t **po; /* Current policy op */ + + + if (NumPolicies == 0) + return; + + for (i = NumPolicies, p = Policies; i > 0; i --, p ++) + { + for (j = (*p)->num_ops, po = (*p)->ops; j > 0; j --, po ++) + { + cupsdDeleteLocation(*po); + free(*po); + } + + if ((*p)->num_ops > 0) + free((*p)->ops); + + free(*p); + } + + free(Policies); + + NumPolicies = 0; + Policies = NULL; +} + + +/* + * 'cupsdFindPolicy()' - Find a named policy. + */ + +cupsd_policy_t * /* O - Policy */ +cupsdFindPolicy(const char *policy) /* I - Name of policy */ +{ + int i; /* Looping var */ + cupsd_policy_t **p; /* Current policy */ + + + /* + * Range check... + */ + + if (policy == NULL) + return (NULL); + + /* + * Check the operation against the available policies... + */ + + for (i = NumPolicies, p = Policies; i > 0; i --, p ++) + if (!strcasecmp(policy, (*p)->name)) + return (*p); + + return (NULL); +} + + +/* + * 'cupsdFindPolicyOp()' - Find a policy operation. + */ + +cupsd_location_t * /* O - Policy operation */ +cupsdFindPolicyOp(cupsd_policy_t *p, /* I - Policy */ + ipp_op_t op) /* I - IPP operation */ +{ + int i; /* Looping var */ + cupsd_location_t **po; /* Current policy operation */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp(p=%p, op=%x(%s))\n", + p, op, ippOpString(op)); + + /* + * Range check... + */ + + if (p == NULL) + return (NULL); + + /* + * Check the operation against the available policies... + */ + + for (i = p->num_ops, po = p->ops; i > 0; i --, po ++) + if ((*po)->op == op) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdFindPolicyOp: Found exact match..."); + return (*po); + } + + for (i = p->num_ops, po = p->ops; i > 0; i --, po ++) + if ((*po)->op == IPP_ANY_OPERATION) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdFindPolicyOp: Found wildcard match..."); + return (*po); + } + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdFindPolicyOp: No match found!"); + + return (NULL); +} + + +/* + * End of "$Id: policy.c 4871 2005-12-07 00:41:11Z mike $". + */ diff --git a/scheduler/policy.h b/scheduler/policy.h new file mode 100644 index 000000000..4f7165664 --- /dev/null +++ b/scheduler/policy.h @@ -0,0 +1,66 @@ +/* + * "$Id: policy.h 4871 2005-12-07 00:41:11Z mike $" + * + * Policy definitions for the Common UNIX Printing System (CUPS) + * scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + + +/* + * Policy structure... + */ + +typedef struct +{ + char *name; /* Policy name */ + int num_ops; /* Number of operations */ + cupsd_location_t **ops; /* Operations */ +} cupsd_policy_t; + + +/* + * Globals... + */ + +VAR int NumPolicies VALUE(0); + /* Number of policies */ +VAR cupsd_policy_t **Policies VALUE(NULL); + /* Policies */ + + +/* + * Prototypes... + */ + +extern cupsd_policy_t *cupsdAddPolicy(const char *policy); +extern cupsd_location_t *cupsdAddPolicyOp(cupsd_policy_t *p, + cupsd_location_t *po, + ipp_op_t op); +extern http_status_t cupsdCheckPolicy(cupsd_policy_t *p, cupsd_client_t *con, + const char *owner); +extern void cupsdDeleteAllPolicies(void); +extern cupsd_policy_t *cupsdFindPolicy(const char *policy); +extern cupsd_location_t *cupsdFindPolicyOp(cupsd_policy_t *p, ipp_op_t op); + + +/* + * End of "$Id: policy.h 4871 2005-12-07 00:41:11Z mike $". + */ diff --git a/scheduler/printers.c b/scheduler/printers.c new file mode 100644 index 000000000..556bf0297 --- /dev/null +++ b/scheduler/printers.c @@ -0,0 +1,2874 @@ +/* + * "$Id: printers.c 4903 2006-01-10 20:02:46Z mike $" + * + * Printer routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddPrinter() - Add a printer to the system. + * cupsdAddPrinterFilter() - Add a MIME filter for a printer. + * cupsdAddPrinterHistory() - Add the current printer state to the history. + * cupsdAddPrinterUser() - Add a user to the ACL. + * cupsdDeleteAllPrinters() - Delete all printers from the system. + * cupsdDeletePrinter() - Delete a printer from the system. + * cupsdDeletePrinterFilters() - Delete all MIME filters for a printer. + * cupsdFindPrinter() - Find a printer in the list. + * cupsdFreePrinterUsers() - Free allow/deny users. + * cupsdLoadAllPrinters() - Load printers from the printers.conf file. + * cupsdSaveAllPrinters() - Save all printer definitions to the printers.conf + * cupsdSetPrinterAttrs() - Set printer attributes based upon the PPD file. + * cupsdSetPrinterReasons() - Set/update the reasons strings. + * cupsdSetPrinterState() - Update the current state of a printer. + * cupsdStopPrinter() - Stop a printer from printing any jobs... + * cupsdUpdatePrinters() - Update printers after a partial reload. + * cupsdValidateDest() - Validate a printer/class destination. + * cupsdWritePrintcap() - Write a pseudo-printcap file for older + * applications that need it... + * cupsdSanitizeURI() - Sanitize a device URI... + * compare_printers() - Compare two printers. + * 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. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + + +/* + * Local functions... + */ + +static int compare_printers(void *first, void *second, void *data); +#ifdef __sgi +static void write_irix_config(cupsd_printer_t *p); +static void write_irix_state(cupsd_printer_t *p); +#endif /* __sgi */ + + +/* + * 'cupsdAddPrinter()' - Add a printer to the system. + */ + +cupsd_printer_t * /* O - New printer */ +cupsdAddPrinter(const char *name) /* I - Name of printer */ +{ + cupsd_printer_t *p; /* New printer */ + + + /* + * Range check input... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdAddPrinter(\"%s\")", name); + + /* + * Create a new printer entity... + */ + + if ((p = calloc(1, sizeof(cupsd_printer_t))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_CRIT, "Unable to allocate memory for printer - %s", + strerror(errno)); + return (NULL); + } + + cupsdSetString(&p->name, name); + cupsdSetString(&p->info, name); + cupsdSetString(&p->hostname, ServerName); + + cupsdSetStringf(&p->uri, "ipp://%s:%d/printers/%s", ServerName, LocalPort, name); + cupsdSetStringf(&p->device_uri, "file:/dev/null"); + + p->state = IPP_PRINTER_STOPPED; + p->state_time = time(NULL); + p->accepting = 0; + p->shared = 1; + p->filetype = mimeAddType(MimeDatabase, "printer", name); + + cupsdSetString(&p->job_sheets[0], "none"); + cupsdSetString(&p->job_sheets[1], "none"); + + cupsdSetString(&p->error_policy, "stop-printer"); + cupsdSetString(&p->op_policy, DefaultPolicy); + + p->op_policy_ptr = DefaultPolicyPtr; + + if (MaxPrinterHistory) + p->history = calloc(MaxPrinterHistory, sizeof(ipp_t *)); + + /* + * Insert the printer in the printer list alphabetically... + */ + + if (!Printers) + Printers = cupsArrayNew(compare_printers, NULL); + + cupsArrayAdd(Printers, p); + + if (!ImplicitPrinters) + ImplicitPrinters = cupsArrayNew(compare_printers, NULL); + + /* + * Return the new printer... + */ + + return (p); +} + + +/* + * 'cupsdAddPrinterFilter()' - Add a MIME filter for a printer. + */ + +void +cupsdAddPrinterFilter( + cupsd_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 || p->filetype == 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) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdAddPrinterFilter: 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] == '*' && strcasecmp((*temptype)->super, "printer") != 0) || + !strcasecmp((*temptype)->super, super)) && + (type[0] == '*' || !strcasecmp((*temptype)->type, type))) + { + cupsdLogMessage(CUPSD_LOG_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); + } +} + + +/* + * 'cupsdAddPrinterHistory()' - Add the current printer state to the history. + */ + +void +cupsdAddPrinterHistory( + cupsd_printer_t *p) /* I - Printer */ +{ + ipp_t *history; /* History collection */ + + + /* + * Stop early if we aren't keeping history data... + */ + + if (MaxPrinterHistory <= 0) + return; + + /* + * Retire old history data as needed... + */ + + p->sequence_number ++; + + if (p->num_history >= MaxPrinterHistory) + { + p->num_history --; + ippDelete(p->history[0]); + memmove(p->history, p->history + 1, p->num_history * sizeof(ipp_t *)); + } + + /* + * Create a collection containing the current printer-state, printer-up-time, + * printer-state-message, and printer-state-reasons attributes. + */ + + history = ippNew(); + ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-state", + p->state); + ippAddBoolean(history, IPP_TAG_PRINTER, "printer-is-accepting-jobs", + p->accepting); + ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-state-message", + NULL, p->state_message); + if (p->num_reasons == 0) + ippAddString(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-state-reasons", NULL, + p->state == IPP_PRINTER_STOPPED ? "paused" : "none"); + else + ippAddStrings(history, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "printer-state-reasons", p->num_reasons, NULL, + (const char * const *)p->reasons); + ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "printer-state-change-time", p->state_time); + ippAddInteger(history, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "printer-state-sequence-number", p->sequence_number); + + p->history[p->num_history] = history; + p->num_history ++; +} + + +/* + * 'cupsdAddPrinterUser()' - Add a user to the ACL. + */ + +void +cupsdAddPrinterUser( + cupsd_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 ++; +} + + +/* + * 'cupsdCreateCommonData()' - Create the common printer data. + */ + +void +cupsdCreateCommonData(void) +{ + int i; /* Looping var */ + ipp_attribute_t *attr; /* Attribute data */ + static const int nups[] = /* number-up-supported values */ + { 1, 2, 4, 6, 9, 16 }; + static const ipp_orient_t orients[4] =/* orientation-requested-supported values */ + { + IPP_PORTRAIT, + IPP_LANDSCAPE, + IPP_REVERSE_LANDSCAPE, + IPP_REVERSE_PORTRAIT + }; + static const char * const holds[] = /* job-hold-until-supported values */ + { + "no-hold", + "indefinite", + "day-time", + "evening", + "night", + "second-shift", + "third-shift", + "weekend" + }; + static const char * const versions[] =/* ipp-versions-supported values */ + { + "1.0", + "1.1" + }; + static const 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_CREATE_PRINTER_SUBSCRIPTION, + IPP_CREATE_JOB_SUBSCRIPTION, + IPP_GET_SUBSCRIPTION_ATTRIBUTES, + IPP_GET_SUBSCRIPTIONS, + IPP_RENEW_SUBSCRIPTION, + IPP_CANCEL_SUBSCRIPTION, + IPP_GET_NOTIFICATIONS, + 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_SET_DEFAULT, + CUPS_GET_DEVICES, + CUPS_GET_PPDS, + CUPS_MOVE_JOB, + CUPS_AUTHENTICATE_JOB, + IPP_RESTART_JOB + }; + static const char * const charsets[] =/* charset-supported values */ + { + "us-ascii", + "utf-8" + }; + static const char * const compressions[] = + { /* document-compression-supported values */ + "none" +#ifdef HAVE_LIBZ + ,"gzip" +#endif /* HAVE_LIBZ */ + }; + static const char * const multiple_document_handling[] = + { /* multiple-document-handling-supported values */ + "separate-documents-uncollated-copies", + "separate-documents-collated-copies" + }; + static const char * const errors[] = /* printer-error-policy-supported values */ + { + "abort-job", + "retry-job", + "stop-printer" + }; + static const char * const notify_attrs[] = + { /* notify-attributes-supported values */ + "printer-state-change-time", + "notify-lease-expiration-time", + "notify-subscriber-user-name" + }; + static const char * const notify_events[] = + { /* notify-events-supported values */ + "job-completed", + "job-config-changed", + "job-created", + "job-progress", + "job-state-changed", + "job-stopped", + "printer-added", + "printer-changed", + "printer-config-changed", + "printer-deleted", + "printer-finishings-changed", + "printer-media-changed", + "printer-modified", + "printer-restarted", + "printer-shutdown", + "printer-state-changed", + "printer-stopped", + "server-audit", + "server-restarted", + "server-started", + "server-stopped" + }; + + + if (CommonData) + ippDelete(CommonData); + + CommonData = ippNew(); + + /* + * This list of attributes is sorted to improve performance when the + * client provides a requested-attributes attribute... + */ + + /* charset-configured */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET, + "charset-configured", NULL, DefaultCharset); + + /* charset-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_CHARSET, + "charset-supported", sizeof(charsets) / sizeof(charsets[0]), + NULL, charsets); + + /* compression-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "compression-supported", + sizeof(compressions) / sizeof(compressions[0]), + NULL, compressions); + + /* TODO: move to printer-specific section! */ + /* copies-default */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "copies-default", 1); + + /* copies-supported */ + ippAddRange(CommonData, IPP_TAG_PRINTER, "copies-supported", 1, MaxCopies); + + /* TODO: move to printer-specific section! */ + /* document-format-default */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_MIMETYPE, + "document-format-default", NULL, "application/octet-stream"); + + /* document-format-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, + (ipp_tag_t)(IPP_TAG_MIMETYPE | IPP_TAG_COPY), + "document-format-supported", NumMimeTypes, NULL, MimeTypes); + + /* generated-natural-language-supported */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, + "generated-natural-language-supported", NULL, DefaultLanguage); + + /* ipp-versions-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "ipp-versions-supported", sizeof(versions) / sizeof(versions[0]), + NULL, versions); + + /* TODO: move to printer-specific section! */ + /* job-hold-until-default */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "job-hold-until-default", NULL, "no-hold"); + + /* job-hold-until-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "job-hold-until-supported", sizeof(holds) / sizeof(holds[0]), + NULL, holds); + + /* TODO: move to printer-specific section! */ + /* job-priority-default */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "job-priority-default", 50); + + /* job-priority-supported */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "job-priority-supported", 100); + + /* job-sheets-supported */ + if (NumBanners > 0) + { + /* + * Setup the job-sheets-supported attribute... + */ + + if (Classification && !ClassifyOverride) + attr = ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, + "job-sheets-supported", NULL, Classification); + else + attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, + "job-sheets-supported", NumBanners + 1, NULL, NULL); + + if (attr == NULL) + cupsdLogMessage(CUPSD_LOG_EMERG, + "cupsdSetPrinterAttrs: Unable to allocate memory for " + "job-sheets-supported attribute: %s!", strerror(errno)); + else if (!Classification || ClassifyOverride) + { + attr->values[0].string.text = strdup("none"); + + for (i = 0; i < NumBanners; i ++) + attr->values[i + 1].string.text = strdup(Banners[i].name); + } + } + else + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, + "job-sheets-supported", NULL, "none"); + + /* multiple-document-handling-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "multiple-document-handling-supported", + sizeof(multiple_document_handling) / + sizeof(multiple_document_handling[0]), NULL, + multiple_document_handling); + + /* multiple-document-jobs-supported */ + ippAddBoolean(CommonData, IPP_TAG_PRINTER, + "multiple-document-jobs-supported", 1); + + /* multiple-operation-time-out */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "multiple-operation-time-out", 60); + + /* natural-language-configured */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_LANGUAGE, + "natural-language-configured", NULL, DefaultLanguage); + + /* notify-attributes-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "notify-attributes-supported", + (int)(sizeof(notify_attrs) / sizeof(notify_attrs[0])), + NULL, notify_attrs); + + /* TODO: move to printer-specific section! */ + /* notify-lease-duration-default */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "notify-lease-duration-default", DefaultLeaseDuration); + + /* notify-lease-duration-supported */ + ippAddRange(CommonData, IPP_TAG_PRINTER, + "notify-lease-duration-supported", 0, + MaxLeaseDuration ? MaxLeaseDuration : 2147483647); + + /* notify-max-events-supported */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "notify-max-events-supported", MaxEvents); + + /* notify-notify-events-default */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "notify-events-default", NULL, "job-completed"); + + /* notify-notify-events-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "notify-events-supported", + (int)(sizeof(notify_events) / sizeof(notify_events[0])), + NULL, notify_events); + + /* notify-pull-method-supported */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "notify-pull-method-supported", NULL, "ippget"); + + /* TODO: scan notifier directory */ + /* notify-schemes-supported */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "notify-schemes-supported", NULL, "mailto"); + + /* TODO: move to printer-specific section! */ + /* number-up-default */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "number-up-default", 1); + + /* number-up-supported */ + ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_INTEGER, + "number-up-supported", sizeof(nups) / sizeof(nups[0]), nups); + + /* operations-supported */ + ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "operations-supported", + sizeof(ops) / sizeof(ops[0]) + JobFiles - 1, (int *)ops); + + /* TODO: move to printer-specific section! */ + /* orientation-requested-default */ + ippAddInteger(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "orientation-requested-default", IPP_PORTRAIT); + + /* orientation-requested-supported */ + ippAddIntegers(CommonData, IPP_TAG_PRINTER, IPP_TAG_ENUM, + "orientation-requested-supported", 4, (int *)orients); + + /* page-ranges-supported */ + ippAddBoolean(CommonData, IPP_TAG_PRINTER, "page-ranges-supported", 1); + + /* pdf-override-supported */ + ippAddString(CommonData, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "pdl-override-supported", NULL, "not-attempted"); + + /* printer-error-policy-supported */ + ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-error-policy-supported", + sizeof(errors) / sizeof(errors[0]), NULL, errors); + + /* printer-op-policy-supported */ + attr = ippAddStrings(CommonData, IPP_TAG_PRINTER, IPP_TAG_NAME, + "printer-op-policy-supported", NumPolicies, NULL, NULL); + for (i = 0; i < NumPolicies; i ++) + attr->values[i].string.text = strdup(Policies[i]->name); +} + + +/* + * 'cupsdDeleteAllPrinters()' - Delete all printers from the system. + */ + +void +cupsdDeleteAllPrinters(void) +{ + cupsd_printer_t *p; /* Pointer to current printer/class */ + + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (!(p->type & CUPS_PRINTER_CLASS)) + cupsdDeletePrinter(p, 0); +} + + +/* + * 'cupsdDeletePrinter()' - Delete a printer from the system. + */ + +void +cupsdDeletePrinter( + cupsd_printer_t *p, /* I - Printer to delete */ + int update) /* I - Update printers.conf? */ +{ + int i; /* Looping var */ +#ifdef __sgi + char filename[1024]; /* Interface script filename */ +#endif /* __sgi */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, "cupsdDeletePrinter(p=%p(%s), update=%d)", + p, p->name, update); + + /* + * Save the current position in the Printers array... + */ + + cupsArraySave(Printers); + + /* + * Stop printing on this printer... + */ + + cupsdStopPrinter(p, update); + + /* + * If this printer is the next for browsing, point to the next one... + */ + + if (p == BrowseNext) + { + cupsArrayFind(Printers, p); + BrowseNext = (cupsd_printer_t *)cupsArrayNext(Printers); + } + + /* + * Remove the printer from the list... + */ + + cupsArrayRemove(Printers, 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 = (cupsd_printer_t *)cupsArrayFirst(Printers); + + /* + * Remove this printer from any classes and send a browse delete message... + */ + + if (!(p->type & CUPS_PRINTER_IMPLICIT)) + { + cupsdDeletePrinterFromClasses(p); + cupsdSendBrowseDelete(p); + } + + /* + * Free all memory used by the printer... + */ + + if (p->printers != NULL) + free(p->printers); + + if (MaxPrinterHistory) + { + for (i = 0; i < p->num_history; i ++) + ippDelete(p->history[i]); + + free(p->history); + } + + for (i = 0; i < p->num_reasons; i ++) + free(p->reasons[i]); + + ippDelete(p->attrs); + + cupsdDeletePrinterFilters(p); + + cupsdFreePrinterUsers(p); + cupsdFreeQuotas(p); + + cupsdClearString(&p->uri); + cupsdClearString(&p->hostname); + cupsdClearString(&p->name); + cupsdClearString(&p->location); + cupsdClearString(&p->make_model); + cupsdClearString(&p->info); + cupsdClearString(&p->job_sheets[0]); + cupsdClearString(&p->job_sheets[1]); + cupsdClearString(&p->device_uri); + cupsdClearString(&p->port_monitor); + cupsdClearString(&p->op_policy); + cupsdClearString(&p->error_policy); + + free(p); + + /* + * Restore the previous position in the Printers array... + */ + + cupsArrayRestore(Printers); +} + + +/* + * 'cupsdDeletePrinterFilters()' - Delete all MIME filters for a printer. + */ + +void +cupsdDeletePrinterFilters( + cupsd_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) + memmove(filter, filter + 1, sizeof(mime_filter_t) * (i - 1)); + + filter --; + } +} + + +/* + * 'cupsdFindDest()' - Find a destination in the list. + */ + +cupsd_printer_t * /* O - Destination in list */ +cupsdFindDest(const char *name) /* I - Name of printer or class to find */ +{ + cupsd_printer_t key; /* Search key */ + + + key.name = (char *)name; + return ((cupsd_printer_t *)cupsArrayFind(Printers, &key)); +} + + +/* + * 'cupsdFindPrinter()' - Find a printer in the list. + */ + +cupsd_printer_t * /* O - Printer in list */ +cupsdFindPrinter(const char *name) /* I - Name of printer to find */ +{ + cupsd_printer_t *p; /* Printer in list */ + + + if ((p = cupsdFindDest(name)) != NULL && (p->type & CUPS_PRINTER_CLASS)) + return (NULL); + else + return (p); +} + + +/* + * 'cupsdFreePrinterUsers()' - Free allow/deny users. + */ + +void +cupsdFreePrinterUsers( + cupsd_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; +} + + +/* + * 'cupsdLoadAllPrinters()' - Load printers from the printers.conf file. + */ + +void +cupsdLoadAllPrinters(void) +{ + cups_file_t *fp; /* printers.conf file */ + int linenum; /* Current line number */ + char line[1024], /* Line from file */ + *value, /* Pointer to value */ + *valueptr; /* Pointer into value */ + cupsd_printer_t *p; /* Current printer */ + + + /* + * Open the printers.conf file... + */ + + snprintf(line, sizeof(line), "%s/printers.conf", ServerRoot); + if ((fp = cupsFileOpen(line, "r")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdLoadAllPrinters: Unable to open %s - %s", line, + strerror(errno)); + return; + } + + /* + * Read printer configurations until we hit EOF... + */ + + linenum = 0; + p = NULL; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + /* + * Decode the directive... + */ + + if (!strcasecmp(line, " or + */ + + if (p == NULL && value) + { + /* + * Add the printer and a base file type... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdLoadAllPrinters: Loading printer %s...", value); + + p = cupsdAddPrinter(value); + p->accepting = 1; + p->state = IPP_PRINTER_IDLE; + + /* + * Set the default printer as needed... + */ + + if (!strcasecmp(line, "")) + { + if (p != NULL) + { + /* + * Close out the current printer... + */ + + cupsdSetPrinterAttrs(p); + cupsdAddPrinterHistory(p); + + if (p->device_uri && strncmp(p->device_uri, "file:", 5) && + p->state != IPP_PRINTER_STOPPED) + { + /* + * See if the backend exists... + */ + + snprintf(line, sizeof(line), "%s/backend/%s", ServerBin, + p->device_uri); + + if ((valueptr = strchr(line + strlen(ServerBin), ':')) != NULL) + *valueptr = '\0'; /* Chop everything but URI scheme */ + + if (access(line, 0)) + { + /* + * Backend does not exist, stop printer... + */ + + p->state = IPP_PRINTER_STOPPED; + snprintf(p->state_message, sizeof(p->state_message), + "Backend %s does not exist!", line); + } + } + + p = NULL; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!p) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + else if (!strcasecmp(line, "Info")) + { + if (value) + cupsdSetString(&p->info, value); + } + else if (!strcasecmp(line, "Location")) + { + if (value) + cupsdSetString(&p->location, value); + } + else if (!strcasecmp(line, "DeviceURI")) + { + if (value) + cupsdSetString(&p->device_uri, value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "PortMonitor")) + { + if (value && strcmp(value, "none")) + cupsdSetString(&p->port_monitor, value); + else if (value) + cupsdClearString(&p->port_monitor); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "State")) + { + /* + * Set the initial queue state... + */ + + if (value && !strcasecmp(value, "idle")) + p->state = IPP_PRINTER_IDLE; + else if (value && !strcasecmp(value, "stopped")) + p->state = IPP_PRINTER_STOPPED; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "StateMessage")) + { + /* + * Set the initial queue state message... + */ + + if (value) + strlcpy(p->state_message, value, sizeof(p->state_message)); + } + else if (!strcasecmp(line, "StateTime")) + { + /* + * Set the state time... + */ + + if (value) + p->state_time = atoi(value); + } + else if (!strcasecmp(line, "Accepting")) + { + /* + * Set the initial accepting state... + */ + + if (value && + (!strcasecmp(value, "yes") || + !strcasecmp(value, "on") || + !strcasecmp(value, "true"))) + p->accepting = 1; + else if (value && + (!strcasecmp(value, "no") || + !strcasecmp(value, "off") || + !strcasecmp(value, "false"))) + p->accepting = 0; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "Shared")) + { + /* + * Set the initial shared state... + */ + + if (value && + (!strcasecmp(value, "yes") || + !strcasecmp(value, "on") || + !strcasecmp(value, "true"))) + p->shared = 1; + else if (value && + (!strcasecmp(value, "no") || + !strcasecmp(value, "off") || + !strcasecmp(value, "false"))) + p->shared = 0; + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "JobSheets")) + { + /* + * Set the initial job sheets... + */ + + if (value) + { + for (valueptr = value; *valueptr && !isspace(*valueptr & 255); valueptr ++); + + if (*valueptr) + *valueptr++ = '\0'; + + cupsdSetString(&p->job_sheets[0], value); + + while (isspace(*valueptr & 255)) + valueptr ++; + + if (*valueptr) + { + for (value = valueptr; *valueptr && !isspace(*valueptr & 255); valueptr ++); + + if (*valueptr) + *valueptr++ = '\0'; + + cupsdSetString(&p->job_sheets[1], value); + } + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "AllowUser")) + { + if (value) + { + p->deny_users = 0; + cupsdAddPrinterUser(p, value); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "DenyUser")) + { + if (value) + { + p->deny_users = 1; + cupsdAddPrinterUser(p, value); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "QuotaPeriod")) + { + if (value) + p->quota_period = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "PageLimit")) + { + if (value) + p->page_limit = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "KLimit")) + { + if (value) + p->k_limit = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "OpPolicy")) + { + if (value) + cupsdSetString(&p->op_policy, value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else if (!strcasecmp(line, "ErrorPolicy")) + { + if (value) + cupsdSetString(&p->error_policy, value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of printers.conf.", linenum); + return; + } + } + else + { + /* + * Something else we don't understand... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown configuration directive %s on line %d of printers.conf.", + line, linenum); + } + } + + cupsFileClose(fp); +} + + +/* + * 'cupsdSaveAllPrinters()' - Save all printer definitions to the printers.conf + * file. + */ + +void +cupsdSaveAllPrinters(void) +{ + int i; /* Looping var */ + cups_file_t *fp; /* printers.conf file */ + char temp[1024]; /* Temporary string */ + char backup[1024]; /* printers.conf.O file */ + cupsd_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)) + { + if (errno != ENOENT) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to backup printers.conf - %s", strerror(errno)); + } + + if ((fp = cupsFileOpen(temp, "w")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to save printers.conf - %s", strerror(errno)); + + if (rename(backup, temp)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to restore printers.conf - %s", strerror(errno)); + return; + } + else + cupsdLogMessage(CUPSD_LOG_INFO, "Saving printers.conf..."); + + /* + * Restrict access to the file... + */ + + fchown(cupsFileNumber(fp), getuid(), Group); + fchmod(cupsFileNumber(fp), ConfigFilePerm); + + /* + * Write a small header to the file... + */ + + curtime = time(NULL); + curdate = localtime(&curtime); + strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); + + cupsFilePuts(fp, "# Printer configuration file for " CUPS_SVERSION "\n"); + cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); + + /* + * Write each local printer known to the system... + */ + + for (printer = (cupsd_printer_t *)cupsArrayFirst(Printers); + printer; + printer = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + /* + * 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) + cupsFilePrintf(fp, "\n", printer->name); + else + cupsFilePrintf(fp, "\n", printer->name); + + if (printer->info) + cupsFilePrintf(fp, "Info %s\n", printer->info); + + if (printer->location) + cupsFilePrintf(fp, "Location %s\n", printer->location); + + if (printer->device_uri) + cupsFilePrintf(fp, "DeviceURI %s\n", printer->device_uri); + + if (printer->port_monitor) + cupsFilePrintf(fp, "PortMonitor %s\n", printer->port_monitor); + + if (printer->state == IPP_PRINTER_STOPPED) + { + cupsFilePuts(fp, "State Stopped\n"); + cupsFilePrintf(fp, "StateMessage %s\n", printer->state_message); + } + else + cupsFilePuts(fp, "State Idle\n"); + + cupsFilePrintf(fp, "StateTime %d\n", (int)printer->state_time); + + if (printer->accepting) + cupsFilePuts(fp, "Accepting Yes\n"); + else + cupsFilePuts(fp, "Accepting No\n"); + + if (printer->shared) + cupsFilePuts(fp, "Shared Yes\n"); + else + cupsFilePuts(fp, "Shared No\n"); + + cupsFilePrintf(fp, "JobSheets %s %s\n", printer->job_sheets[0], + printer->job_sheets[1]); + + cupsFilePrintf(fp, "QuotaPeriod %d\n", printer->quota_period); + cupsFilePrintf(fp, "PageLimit %d\n", printer->page_limit); + cupsFilePrintf(fp, "KLimit %d\n", printer->k_limit); + + for (i = 0; i < printer->num_users; i ++) + cupsFilePrintf(fp, "%sUser %s\n", printer->deny_users ? "Deny" : "Allow", + printer->users[i]); + + if (printer->op_policy) + cupsFilePrintf(fp, "OpPolicy %s\n", printer->op_policy); + if (printer->error_policy) + cupsFilePrintf(fp, "ErrorPolicy %s\n", printer->error_policy); + + cupsFilePuts(fp, "\n"); + +#ifdef __sgi + /* + * Make IRIX desktop & printer status happy + */ + + write_irix_state(printer); +#endif /* __sgi */ + } + + cupsFileClose(fp); +} + + +/* + * 'cupsdSetPrinterAttrs()' - Set printer attributes based upon the PPD file. + */ + +void +cupsdSetPrinterAttrs(cupsd_printer_t *p)/* I - Printer to setup */ +{ + char uri[HTTP_MAX_URI]; + /* URI for printer */ + char resource[HTTP_MAX_URI]; + /* Resource portion of URI */ + int i; /* Looping var */ + char filename[1024]; /* Name of PPD file */ + int num_media; /* Number of media options */ + cupsd_location_t *auth; /* Pointer to authentication element */ + const char *auth_supported;/* Authentication supported */ + cups_ptype_t cupsd_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 */ + *media_quality; /* EFMediaQualityMode options */ + ppd_attr_t *ppdattr; /* PPD attribute */ + ipp_attribute_t *attr; /* Attribute data */ + ipp_value_t *val; /* Attribute value */ + int num_finishings; /* Number of finishings */ + ipp_finish_t finishings[5]; /* finishings-supported values */ + static const char * const sides[3] = /* sides-supported values */ + { + "one", + "two-long-edge", + "two-short-edge" + }; + + + DEBUG_printf(("cupsdSetPrinterAttrs: entering name = %s, type = %x\n", p->name, + p->type)); + + /* + * Make sure that we have the common attributes defined... + */ + + if (!CommonData) + cupsdCreateCommonData(); + + /* + * Clear out old filters, if any... + */ + + cupsdDeletePrinterFilters(p); + + /* + * 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 = cupsdFindBest(resource, HTTP_POST)) == NULL) + auth = cupsdFindPolicyOp(p->op_policy_ptr, IPP_PRINT_JOB); + + if (auth) + { + if (auth->type == AUTH_BASIC || auth->type == AUTH_BASICDIGEST) + auth_supported = "basic"; + else if (auth->type == AUTH_DIGEST) + auth_supported = "digest"; + + if (auth->type != AUTH_NONE) + p->type |= CUPS_PRINTER_AUTHENTICATED; + else + p->type &= ~CUPS_PRINTER_AUTHENTICATED; + } + else + p->type &= ~CUPS_PRINTER_AUTHENTICATED; + } + + /* + * 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_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 ? p->location : ""); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", + NULL, p->info ? p->info : ""); + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, "printer-more-info", + NULL, p->uri); + + 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 && !(p->type & CUPS_PRINTER_REMOTE)) + { + /* + * Setup the job-sheets-default attribute... + */ + + 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 ? + Classification : p->job_sheets[0]); + attr->values[1].string.text = strdup(Classification ? + Classification : p->job_sheets[1]); + } + } + + cupsd_printer_type = p->type; + + p->raw = 0; + + 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_URI, + "printer-uri-supported", NULL, p->uri); + + if (p->make_model) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-make-and-model", NULL, p->make_model); + + p->raw = 1; + } + 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)) + { + p->raw = 1; + + /* + * Add class-specific attributes... + */ + + if ((p->type & CUPS_PRINTER_IMPLICIT) && p->num_printers > 0 && + p->printers[0]->make_model) + 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 (!p->device_uri) + strcpy(uri, "file:/dev/null"); + else if (strstr(p->device_uri, "://") != NULL) + { + /* + * http://..., ipp://..., etc. + */ + + cupsdSanitizeURI(p->device_uri, uri, sizeof(uri)); + } + else + { + /* + * file:..., serial:..., etc. + */ + + strlcpy(uri, p->device_uri, sizeof(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; + if ((ppdattr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL) + if (ppdattr->value && !strcasecmp(ppdattr->value, "true")) + p->type |= CUPS_PRINTER_FAX; + + 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); + + if (ppd->nickname) + cupsdSetString(&p->make_model, ppd->nickname); + else if (ppd->modelname) + cupsdSetString(&p->make_model, ppd->modelname); + else + cupsdSetString(&p->make_model, "Bad PPD File"); + + if (p->make_model) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, + "printer-make-and-model", NULL, p->make_model); + + /* + * 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; + + if ((media_quality = ppdFindOption(ppd, "EFMediaQualityMode")) != NULL) + num_media += media_quality->num_choices; + + if (num_media == 0) + { + cupsdLogMessage(CUPSD_LOG_CRIT, "cupsdSetPrinterAttrs: The PPD file for printer %s " + "contains no media options and is therefore " + "invalid!", p->name); + } + else + { + 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 (media_quality != NULL) + for (i = 0; i < media_quality->num_choices; i ++, val ++) + val->string.text = strdup(media_quality->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 if (media_quality != NULL) + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-default", + NULL, media_quality->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 a filter from application/vnd.cups-raw to printer/name to + * handle "raw" printing by users. + */ + + cupsdAddPrinterFilter(p, "application/vnd.cups-raw 0 -"); + + /* + * 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])); + cupsdAddPrinterFilter(p, ppd->filters[i]); + } + + if (ppd->num_filters == 0) + { + /* + * If there are no filters, add a PostScript printing filter. + */ + + cupsdAddPrinterFilter(p, "application/vnd.cups-postscript 0 -"); + } + + /* + * Show current and available port monitors for this printer... + */ + + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "port-monitor", + NULL, p->port_monitor ? p->port_monitor : "none"); + + + for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); + ppdattr; + i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL)); + + if (ppd->protocols) + { + if (strstr(ppd->protocols, "TBCP")) + i ++; + else if (strstr(ppd->protocols, "BCP")) + i ++; + } + + attr = ippAddStrings(p->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, + "port-monitor-supported", i, NULL, NULL); + + attr->values[0].string.text = strdup("none"); + + for (i = 1, ppdattr = ppdFindAttr(ppd, "cupsPortMonitor", NULL); + ppdattr; + i ++, ppdattr = ppdFindNextAttr(ppd, "cupsPortMonitor", NULL)) + attr->values[i].string.text = strdup(ppdattr->value); + + if (ppd->protocols) + { + if (strstr(ppd->protocols, "TBCP")) + attr->values[i].string.text = strdup("tbcp"); + else if (strstr(ppd->protocols, "BCP")) + attr->values[i].string.text = strdup("bcp"); + } + + /* + * Close the PPD and set the type... + */ + + ppdClose(ppd); + + cupsd_printer_type = p->type; + } + else if (!access(filename, 0)) + { + int pline; /* PPD line number */ + ppd_status_t pstatus; /* PPD load status */ + + + pstatus = ppdLastError(&pline); + + cupsdLogMessage(CUPSD_LOG_ERROR, "PPD file for %s cannot be loaded!", p->name); + + if (pstatus <= PPD_ALLOC_ERROR) + cupsdLogMessage(CUPSD_LOG_ERROR, "%s", strerror(errno)); + else + cupsdLogMessage(CUPSD_LOG_ERROR, "%s on line %d.", ppdErrorString(pstatus), + pline); + + cupsdLogMessage(CUPSD_LOG_INFO, "Hint: Run \"cupstestppd %s\" and fix any errors.", + filename); + + /* + * Add a filter from application/vnd.cups-raw to printer/name to + * handle "raw" printing by users. + */ + + cupsdAddPrinterFilter(p, "application/vnd.cups-raw 0 -"); + + /* + * Add a PostScript filter, since this is still possibly PS printer. + */ + + cupsdAddPrinterFilter(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); + cupsdAddPrinterFilter(p, filename); + } + else if (p->device_uri && + !strncmp(p->device_uri, "ipp://", 6) && + (strstr(p->device_uri, "/printers/") != NULL || + strstr(p->device_uri, "/classes/") != NULL)) + { + /* + * Tell the client this is really a hard-wired remote printer. + */ + + cupsd_printer_type |= CUPS_PRINTER_REMOTE; + + /* + * Point the printer-uri-supported attribute to the + * remote printer... + */ + + ippAddString(p->attrs, IPP_TAG_PRINTER, IPP_TAG_URI, + "printer-uri-supported", NULL, 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... + */ + + p->raw = 1; + } + 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"); + + p->raw = 1; + } + } + + 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... + */ + + if (!p->shared) + p->type |= CUPS_PRINTER_NOT_SHARED; + else + p->type &= ~CUPS_PRINTER_NOT_SHARED; + + ippAddInteger(p->attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "printer-type", + cupsd_printer_type); + + DEBUG_printf(("cupsdSetPrinterAttrs: 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 */ +} + + +/* + * 'cupsdSetPrinterReasons()' - Set/update the reasons strings. + */ + +void +cupsdSetPrinterReasons( + cupsd_printer_t *p, /* I - Printer */ + const char *s) /* I - Reasons strings */ +{ + int i; /* Looping var */ + const char *sptr; /* Pointer into reasons */ + char reason[255], /* Reason string */ + *rptr; /* Pointer into reason */ + + + if (s[0] == '-' || s[0] == '+') + { + /* + * Add/remove reasons... + */ + + sptr = s + 1; + } + else + { + /* + * Replace reasons... + */ + + sptr = s; + + for (i = 0; i < p->num_reasons; i ++) + free(p->reasons[i]); + + p->num_reasons = 0; + } + + /* + * Loop through all of the reasons... + */ + + while (*sptr) + { + /* + * Skip leading whitespace and commas... + */ + + while (isspace(*sptr & 255) || *sptr == ',') + sptr ++; + + for (rptr = reason; *sptr && !isspace(*sptr & 255) && *sptr != ','; sptr ++) + if (rptr < (reason + sizeof(reason) - 1)) + *rptr++ = *sptr; + + if (rptr == reason) + break; + + *rptr = '\0'; + + if (s[0] == '-') + { + /* + * Remove reason... + */ + + for (i = 0; i < p->num_reasons; i ++) + if (!strcasecmp(reason, p->reasons[i])) + { + /* + * Found a match, so remove it... + */ + + p->num_reasons --; + free(p->reasons[i]); + + if (i < p->num_reasons) + memmove(p->reasons + i, p->reasons + i + 1, + (p->num_reasons - i) * sizeof(char *)); + + i --; + } + } + else if (p->num_reasons < (int)(sizeof(p->reasons) / sizeof(p->reasons[0]))) + { + /* + * Add reason... + */ + + for (i = 0; i < p->num_reasons; i ++) + if (!strcasecmp(reason, p->reasons[i])) + break; + + if (i >= p->num_reasons) + { + p->reasons[i] = strdup(reason); + p->num_reasons ++; + } + } + } +} + + +/* + * 'cupsdSetPrinterState()' - Update the current state of a printer. + */ + +void +cupsdSetPrinterState( + cupsd_printer_t *p, /* I - Printer to change */ + ipp_pstate_t s, /* I - New state */ + int update) /* I - Update printers.conf? */ +{ + 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; + + if (old_state != s) + { + /* + * Let the browse code know this needs to be updated... + */ + + BrowseNext = p; + p->state_time = time(NULL); + p->browse_time = 0; + +#ifdef __sgi + write_irix_state(p); +#endif /* __sgi */ + } + + cupsdAddPrinterHistory(p); + + /* + * 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) && + update) + { + if (p->type & CUPS_PRINTER_CLASS) + cupsdSaveAllClasses(); + else + cupsdSaveAllPrinters(); + } +} + + +/* + * 'cupsdStopPrinter()' - Stop a printer from printing any jobs... + */ + +void +cupsdStopPrinter(cupsd_printer_t *p, /* I - Printer to stop */ + int update)/* I - Update printers.conf? */ +{ + cupsd_job_t *job; /* Active print job */ + + + /* + * Set the printer state... + */ + + cupsdSetPrinterState(p, IPP_PRINTER_STOPPED, update); + + /* + * See if we have a job printing on this printer... + */ + + if (p->job) + { + /* + * Get pointer to job... + */ + + job = (cupsd_job_t *)p->job; + + /* + * Stop it... + */ + + cupsdStopJob(job, 0); + + /* + * Reset the state to pending... + */ + + job->state->values[0].integer = IPP_JOB_PENDING; + + cupsdSaveJob(job); + } +} + + +/* + * 'cupsdUpdatePrinters()' - Update printers after a partial reload. + */ + +void +cupsdUpdatePrinters(void) +{ + cupsd_printer_t *p; /* Current printer */ + + + /* + * Loop through the printers and recreate the printer attributes + * for any local printers since the policy and/or access control + * stuff may have changed. Also, if browsing is disabled, remove + * any remote printers... + */ + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + { + if (!Browsing && (p->type & (CUPS_PRINTER_IMPLICIT | CUPS_PRINTER_REMOTE))) + { + if (p->type & CUPS_PRINTER_IMPLICIT) + cupsArrayRemove(ImplicitPrinters, p); + + cupsArraySave(Printers); + cupsdDeletePrinter(p, 0); + cupsArrayRestore(Printers); + continue; + } + else if (!(p->type & CUPS_PRINTER_REMOTE)) + cupsdSetPrinterAttrs(p); + + /* + * Update the operation policy pointer... + */ + + if ((p->op_policy_ptr = cupsdFindPolicy(p->op_policy)) == NULL) + p->op_policy_ptr = DefaultPolicyPtr; + } +} + + +/* + * 'cupsdValidateDest()' - Validate a printer/class destination. + */ + +const char * /* O - Printer or class name */ +cupsdValidateDest( + const char *hostname, /* I - Host name */ + const char *resource, /* I - Resource name */ + cups_ptype_t *dtype, /* O - Type (printer or class) */ + cupsd_printer_t **printer) /* O - Printer pointer */ +{ + cupsd_printer_t *p; /* Current printer */ + char localname[1024],/* Localized hostname */ + *lptr, /* Pointer into localized hostname */ + *sptr; /* Pointer into server name */ + + + DEBUG_printf(("cupsdValidateDest(\"%s\", \"%s\", %p, %p)\n", hostname, resource, + dtype, printer)); + + /* + * Initialize return values... + */ + + if (printer) + *printer = NULL; + + *dtype = (cups_ptype_t)0; + + /* + * See if the resource is a class or printer... + */ + + if (!strncmp(resource, "/classes/", 9)) + { + /* + * Class... + */ + + resource += 9; + } + else if (!strncmp(resource, "/printers/", 10)) + { + /* + * Printer... + */ + + resource += 10; + } + else + { + /* + * Bad resource name... + */ + + return (NULL); + } + + /* + * See if the printer or class name exists... + */ + + p = cupsdFindDest(resource); + + if (p == NULL && strchr(resource, '@') == NULL) + return (NULL); + else if (p != NULL) + { + if (printer) + *printer = p; + + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | + CUPS_PRINTER_REMOTE); + return (p->name); + } + + /* + * Change localhost to the server name... + */ + + if (!strcasecmp(hostname, "localhost")) + hostname = ServerName; + + strlcpy(localname, hostname, sizeof(localname)); + + if (!strcasecmp(hostname, ServerName)) + { + /* + * 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)) + { + *lptr = '\0'; + break; + } + else + lptr = strchr(lptr + 1, '.'); + } + } + } + + DEBUG_printf(("localized hostname is \"%s\"...\n", localname)); + + /* + * Find a matching printer or class... + */ + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (!strcasecmp(p->hostname, localname) && + !strcasecmp(p->name, resource)) + { + if (printer) + *printer = p; + + *dtype = p->type & (CUPS_PRINTER_CLASS | CUPS_PRINTER_IMPLICIT | + CUPS_PRINTER_REMOTE); + return (p->name); + } + + return (NULL); +} + + +/* + * 'cupsdWritePrintcap()' - Write a pseudo-printcap file for older applications + * that need it... + */ + +void +cupsdWritePrintcap(void) +{ + cups_file_t *fp; /* printcap file */ + cupsd_printer_t *p; /* Current printer */ + + +#ifdef __sgi + /* + * Update the IRIX printer state for the default printer; if + * no printers remain, then the default printer file will be + * removed... + */ + + write_irix_state(DefaultPrinter); +#endif /* __sgi */ + + /* + * See if we have a printcap file; if not, don't bother writing it. + */ + + if (!Printcap || !*Printcap) + return; + + /* + * Open the printcap file... + */ + + if ((fp = cupsFileOpen(Printcap, "w")) == NULL) + return; + + /* + * Put a comment header at the top so that users will know where the + * data has come from... + */ + + cupsFilePuts(fp, "# This file was automatically generated by cupsd(8) from the\n"); + cupsFilePrintf(fp, "# %s/printers.conf file. All changes to this file\n", + ServerRoot); + cupsFilePuts(fp, "# will be lost.\n"); + + if (Printers) + { + /* + * 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: + */ + + if (DefaultPrinter) + cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", DefaultPrinter->name, + DefaultPrinter->info, ServerName, DefaultPrinter->name); + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + if (p != DefaultPrinter) + cupsFilePrintf(fp, "%s|%s:rm=%s:rp=%s:\n", p->name, p->info, + ServerName, p->name); + break; + + case PRINTCAP_SOLARIS: + /* + * Each printer is put in the file as: + * + * _all:all=Printer1,Printer2,Printer3,...,PrinterN + * _default:use=DefaultPrinter + * Printer1:\ + * :bsdaddr=ServerName,Printer1:\ + * :description=Description: + * Printer2: + * :bsdaddr=ServerName,Printer2:\ + * :description=Description: + * Printer3: + * :bsdaddr=ServerName,Printer3:\ + * :description=Description: + * ... + * PrinterN: + * :bsdaddr=ServerName,PrinterN:\ + * :description=Description: + */ + + cupsFilePuts(fp, "_all:all="); + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayCurrent(Printers)) + cupsFilePrintf(fp, "%s%c", p->name, + cupsArrayNext(Printers) ? ',' : '\n'); + + if (DefaultPrinter) + cupsFilePrintf(fp, "_default:use=%s\n", DefaultPrinter->name); + + for (p = (cupsd_printer_t *)cupsArrayFirst(Printers); + p; + p = (cupsd_printer_t *)cupsArrayNext(Printers)) + cupsFilePrintf(fp, "%s:\\\n" + "\t:bsdaddr=%s,%s:\\\n" + "\t:description=%s:\n", + p->name, ServerName, p->name, p->info ? p->info : ""); + break; + } + } + + /* + * Close the file... + */ + + cupsFileClose(fp); +} + + +/* + * 'cupsdSanitizeURI()' - Sanitize a device URI... + */ + +char * /* O - New device URI */ +cupsdSanitizeURI(const char *uri, /* I - Original device URI */ + char *buffer, /* O - New device URI */ + int buflen) /* I - Size of new device URI buffer */ +{ + char *start, /* Start of data after scheme */ + *slash, /* First slash after scheme:// */ + *ptr; /* Pointer into user@host:port part */ + + + /* + * Range check input... + */ + + if (!uri || !buffer || buflen < 2) + return (NULL); + + /* + * Copy the device URI to the new buffer... + */ + + strlcpy(buffer, uri, buflen); + + /* + * Find the end of the scheme:// part... + */ + + if ((ptr = strchr(buffer, ':')) == NULL) + return (buffer); /* No scheme: part... */ + + for (start = ptr + 1; *start; start ++) + if (*start != '/') + break; + + /* + * Find the next slash (/) in the URI... + */ + + if ((slash = strchr(start, '/')) == NULL) + slash = start + strlen(start); /* No slash, point to the end */ + + /* + * Check for an @ sign before the slash... + */ + + if ((ptr = strchr(start, '@')) != NULL && ptr < slash) + { + /* + * Found an @ sign and it is before the resource part, so we have + * an authentication string. Copy the remaining URI over the + * authentication string... + */ + + _cups_strcpy(start, ptr + 1); + } + + /* + * Return the new device URI... + */ + + return (buffer); +} + + +/* + * 'compare_printers()' - Compare two printers. + */ + +static int /* O - Result of comparison */ +compare_printers(void *first, /* I - First printer */ + void *second, /* I - Second printer */ + void *data) /* I - App data (not used) */ +{ + return (strcasecmp(((cupsd_printer_t *)first)->name, + ((cupsd_printer_t *)second)->name)); +} + + +#ifdef __sgi +/* + * 'write_irix_config()' - Update the config files used by the IRIX + * desktop tools. + */ + +static void +write_irix_config(cupsd_printer_t *p) /* I - Printer to update */ +{ + char filename[1024]; /* Interface script filename */ + cups_file_t *fp; /* Interface script file */ + + + + /* + * 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 = cupsFileOpen(filename, "w")) != NULL) + { + cupsFilePuts(fp, "#!/bin/sh\n"); + + if ((attr = ippFindAttribute(p->attrs, "printer-make-and-model", + IPP_TAG_TEXT)) != NULL) + cupsFilePrintf(fp, "NAME=\"%s\"\n", attr->values[0].string.text); + else if (p->type & CUPS_PRINTER_CLASS) + cupsFilePuts(fp, "NAME=\"Printer Class\"\n"); + else + cupsFilePuts(fp, "NAME=\"Remote Destination\"\n"); + + if (p->type & CUPS_PRINTER_COLOR) + cupsFilePuts(fp, "TYPE=ColorPostScript\n"); + else + cupsFilePuts(fp, "TYPE=MonoPostScript\n"); + + cupsFilePrintf(fp, "HOSTNAME=%s\n", ServerName); + cupsFilePrintf(fp, "HOSTPRINTER=%s\n", p->name); + + cupsFileClose(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 = cupsFileOpen(filename, "w")) != NULL) + { + cupsFilePuts(fp, "/dev/null\n"); + + cupsFileClose(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 = cupsFileOpen(filename, "w")) != NULL) + { + cupsFilePuts(fp, "#!/bin/sh\n"); + cupsFilePrintf(fp, "%s -d %s -o \"$3\"\n", PrintcapGUI, p->name); + + cupsFileClose(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 = cupsFileOpen(filename, "w")) != NULL) + { + cupsFilePrintf(fp, "Printer Class | %s\n", + (p->type & CUPS_PRINTER_COLOR) ? "ColorPostScript" : "MonoPostScript"); + cupsFilePrintf(fp, "Printer Model | %s\n", p->make_model ? p->make_model : ""); + cupsFilePrintf(fp, "Location Code | %s\n", p->location ? p->location : ""); + cupsFilePrintf(fp, "Physical Location | %s\n", p->info ? p->info : ""); + cupsFilePrintf(fp, "Port Path | %s\n", p->device_uri ? p->device_uri : ""); + cupsFilePrintf(fp, "Config Path | /var/spool/lp/pod/%s.config\n", p->name); + cupsFilePrintf(fp, "Active Status Path | /var/spool/lp/pod/%s.status\n", p->name); + cupsFilePuts(fp, "Status Update Wait | 10 seconds\n"); + + cupsFileClose(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(cupsd_printer_t *p) /* I - Printer to update */ +{ + char filename[1024]; /* Interface script filename */ + cups_file_t *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 = cupsFileOpen(filename, "w")) != NULL) + { + cupsFilePrintf(fp, "Operational Status | %s\n", + (p->state == IPP_PRINTER_IDLE) ? "Idle" : + (p->state == IPP_PRINTER_PROCESSING) ? "Busy" : + "Faulted"); + cupsFilePrintf(fp, "Information | 01 00 00 | %s\n", CUPS_SVERSION); + cupsFilePrintf(fp, "Information | 02 00 00 | Device URI: %s\n", + p->device_uri ? p->device_uri : ""); + cupsFilePrintf(fp, "Information | 03 00 00 | %s jobs\n", + p->accepting ? "Accepting" : "Not accepting"); + cupsFilePrintf(fp, "Information | 04 00 00 | %s\n", p->state_message); + + cupsFileClose(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 = cupsFileOpen(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; + + cupsFilePuts(fp, "#!/bin/sh\n"); + cupsFilePrintf(fp, "#Tag %d\n", tag); + + cupsFileClose(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 = cupsFileOpen(filename, "w")) != NULL) + { + cupsFilePrintf(fp, "%s\n", DefaultPrinter->name); + + cupsFileClose(fp); + + chmod(filename, 0644); + chown(filename, User, Group); + } + } + else + unlink(filename); +} +#endif /* __sgi */ + + +/* + * End of "$Id: printers.c 4903 2006-01-10 20:02:46Z mike $". + */ diff --git a/scheduler/printers.h b/scheduler/printers.h new file mode 100644 index 000000000..2f740a02d --- /dev/null +++ b/scheduler/printers.h @@ -0,0 +1,146 @@ +/* + * "$Id: printers.h 4775 2005-10-12 14:27:37Z mike $" + * + * Printer definitions for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * 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 */ +} cupsd_quota_t; + + +/* + * Printer/class information structure... + */ + +typedef struct cupsd_printer_s +{ + char *uri, /* Printer URI */ + *hostname, /* Host printer resides on */ + *name, /* Printer name */ + *location, /* Location code */ + *make_model, /* Make and model */ + *info, /* Description */ + *op_policy, /* Operation policy name */ + *error_policy; /* Error policy */ + cupsd_policy_t *op_policy_ptr; /* Pointer to operation policy */ + int shared; /* Shared? */ + int accepting; /* Accepting jobs? */ + int in_implicit_class; /* In an implicit class? */ + ipp_pstate_t state; /* Printer state */ + char state_message[1024]; /* Printer state message */ + int num_reasons; /* Number of printer-state-reasons */ + char *reasons[16]; /* printer-state-reasons strings */ + time_t state_time; /* Time at this state */ + char *job_sheets[2]; /* 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; /* Device URI */ + char *port_monitor; /* Port monitor */ + int raw; /* Raw queue? */ + 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 cupsd_printer_s **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 */ + cupsd_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 */ + int num_history; /* Number of history collections */ + ipp_t **history; /* History data */ + int sequence_number; /* Increasing sequence number */ +} cupsd_printer_t; + + +/* + * Globals... + */ + +VAR ipp_t *CommonData VALUE(NULL); + /* Common printer object attrs */ +VAR cups_array_t *Printers VALUE(NULL), + /* Printer list */ + *ImplicitPrinters VALUE(NULL); + /* Implicit class printers */ +VAR cupsd_printer_t *DefaultPrinter VALUE(NULL); + /* Default printer */ +VAR char *DefaultPolicy VALUE(NULL); + /* Default policy name */ +VAR cupsd_policy_t *DefaultPolicyPtr + VALUE(NULL); + /* Pointer to default policy */ + + +/* + * Prototypes... + */ + +extern cupsd_printer_t *cupsdAddPrinter(const char *name); +extern void cupsdAddPrinterFilter(cupsd_printer_t *p, const char *filter); +extern void cupsdAddPrinterHistory(cupsd_printer_t *p); +extern void cupsdAddPrinterUser(cupsd_printer_t *p, const char *username); +extern cupsd_quota_t *cupsdAddQuota(cupsd_printer_t *p, const char *username); +extern void cupsdCreateCommonData(void); +extern void cupsdDeleteAllPrinters(void); +extern void cupsdDeletePrinter(cupsd_printer_t *p, int update); +extern void cupsdDeletePrinterFilters(cupsd_printer_t *p); +extern cupsd_printer_t *cupsdFindDest(const char *name); +extern cupsd_printer_t *cupsdFindPrinter(const char *name); +extern cupsd_quota_t *cupsdFindQuota(cupsd_printer_t *p, const char *username); +extern void cupsdFreePrinterUsers(cupsd_printer_t *p); +extern void cupsdFreeQuotas(cupsd_printer_t *p); +extern void cupsdLoadAllPrinters(void); +extern void cupsdSaveAllPrinters(void); +extern void cupsdSetPrinterAttrs(cupsd_printer_t *p); +extern void cupsdSetPrinterReasons(cupsd_printer_t *p, const char *s); +extern void cupsdSetPrinterState(cupsd_printer_t *p, ipp_pstate_t s, int update); +#define cupsdStartPrinter(p,u) cupsdSetPrinterState((p), IPP_PRINTER_IDLE, (u)) +extern void cupsdStopPrinter(cupsd_printer_t *p, int update); +extern void cupsdUpdatePrinters(void); +extern cupsd_quota_t *cupsdUpdateQuota(cupsd_printer_t *p, const char *username, + int pages, int k); +extern const char *cupsdValidateDest(const char *hostname, + const char *resource, + cups_ptype_t *dtype, + cupsd_printer_t **printer); +extern void cupsdWritePrintcap(void); + +extern char *cupsdSanitizeURI(const char *uri, char *buffer, + int buflen); + + +/* + * End of "$Id: printers.h 4775 2005-10-12 14:27:37Z mike $". + */ diff --git a/scheduler/process.c b/scheduler/process.c new file mode 100644 index 000000000..cba826f50 --- /dev/null +++ b/scheduler/process.c @@ -0,0 +1,224 @@ +/* + * "$Id: process.c 4719 2005-09-28 21:12:44Z mike $" + * + * Process management routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdEndProcess() - End a process. + * cupsdStartProcess() - Start a process. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" +#include + + +/* + * 'cupsdEndProcess()' - End a process. + */ + +int /* O - 0 on success, -1 on failure */ +cupsdEndProcess(int pid, /* I - Process ID */ + int force) /* I - Force child to die */ +{ + if (force) + return (kill(pid, SIGKILL)); + else + return (kill(pid, SIGTERM)); +} + + +/* + * 'cupsdStartProcess()' - Start a process. + */ + +int /* O - Process ID or 0 */ +cupsdStartProcess( + 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 backfd, /* I - Backchannel file descriptor */ + int root, /* I - Run as root? */ + int *pid) /* O - Process ID */ +{ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* POSIX signal handler */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartProcess(\"%s\", %p, %p, %d, %d, %d)", + command, argv, envp, infd, outfd, errfd); + + /* + * Block signals before forking... + */ + + cupsdHoldSignals(); + + if ((*pid = fork()) == 0) + { + /* + * Child process goes here... + * + * Update stdin/stdout/stderr as needed... + */ + + if (infd != 0) + { + close(0); + if (infd > 0) + dup(infd); + else + open("/dev/null", O_RDONLY); + } + if (outfd != 1) + { + close(1); + if (outfd > 0) + dup(outfd); + else + open("/dev/null", O_WRONLY); + } + if (errfd != 2) + { + close(2); + if (errfd > 0) + dup(errfd); + else + open("/dev/null", O_WRONLY); + } + if (backfd != 3) + { + close(3); + if (backfd > 0) + dup(backfd); + else + open("/dev/null", O_RDWR); + fcntl(3, F_SETFL, O_NDELAY); + } + + /* + * Change the priority of the process based on the FilterNice setting. + * (this is not done for backends...) + */ + + if (!root) + nice(FilterNice); + + /* + * Change user to something "safe"... + */ + + if (!root && !RunUser) + { + /* + * Running as root, so change to non-priviledged user... + */ + + if (setgid(Group)) + exit(errno); + + if (setgroups(1, &Group)) + exit(errno); + + if (setuid(User)) + exit(errno); + } + else + { + /* + * Reset group membership to just the main one we belong to. + */ + + setgroups(1, &Group); + } + + /* + * Change umask to restrict permissions on created files... + */ + + umask(077); + + /* + * Unblock signals before doing the exec... + */ + +#ifdef HAVE_SIGSET + sigset(SIGTERM, SIG_DFL); + sigset(SIGCHLD, SIG_DFL); +#elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_DFL; + + sigaction(SIGTERM, &action, NULL); + sigaction(SIGCHLD, &action, NULL); +#else + signal(SIGTERM, SIG_DFL); + signal(SIGCHLD, SIG_DFL); +#endif /* HAVE_SIGSET */ + + cupsdReleaseSignals(); + + /* + * Execute the command; if for some reason this doesn't work, + * return the error code... + */ + + if (envp) + execve(command, argv, envp); + else + execv(command, argv); + + perror(command); + + exit(errno); + } + else if (*pid < 0) + { + /* + * Error - couldn't fork a new process! + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork %s - %s.", command, + strerror(errno)); + + *pid = 0; + } + + cupsdReleaseSignals(); + + return (*pid); +} + + +/* + * End of "$Id: process.c 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/quotas.c b/scheduler/quotas.c new file mode 100644 index 000000000..03735b1ab --- /dev/null +++ b/scheduler/quotas.c @@ -0,0 +1,240 @@ +/* + * "$Id: quotas.c 4729 2005-09-30 17:46:19Z mike $" + * + * Quota routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddQuota() - Add a quota record for this printer and user. + * cupsdFindQuota() - Find a quota record. + * cupsdFreeQuotas() - Free quotas for a printer. + * cupsdUpdateQuota() - 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 cupsd_quota_t *q1, const cupsd_quota_t *q2); + + +/* + * 'cupsdAddQuota()' - Add a quota record for this printer and user. + */ + +cupsd_quota_t * /* O - Quota data */ +cupsdAddQuota(cupsd_printer_t *p, /* I - Printer */ + const char *username)/* I - User */ +{ + cupsd_quota_t *q; /* New quota data */ + + + if (!p || !username) + return (NULL); + + if (p->num_quotas == 0) + q = malloc(sizeof(cupsd_quota_t)); + else + q = realloc(p->quotas, sizeof(cupsd_quota_t) * (p->num_quotas + 1)); + + if (!q) + return (NULL); + + p->quotas = q; + q += p->num_quotas; + p->num_quotas ++; + + memset(q, 0, sizeof(cupsd_quota_t)); + strlcpy(q->username, username, sizeof(q->username)); + + if (p->num_quotas > 1) + qsort(p->quotas, p->num_quotas, sizeof(cupsd_quota_t), + (int (*)(const void *, const void *))compare); + + return (cupsdFindQuota(p, username)); +} + + +/* + * 'cupsdFindQuota()' - Find a quota record. + */ + +cupsd_quota_t * /* O - Quota data */ +cupsdFindQuota( + cupsd_printer_t *p, /* I - Printer */ + const char *username) /* I - User */ +{ + cupsd_quota_t *q, /* Quota data pointer */ + match; /* Search data */ + + + if (!p || !username) + return (NULL); + + if (p->num_quotas == 0) + q = NULL; + else + { + strlcpy(match.username, username, sizeof(match.username)); + + q = bsearch(&match, p->quotas, p->num_quotas, sizeof(cupsd_quota_t), + (int(*)(const void *, const void *))compare); + } + + if (q) + return (q); + else + return (cupsdAddQuota(p, username)); +} + + +/* + * 'cupsdFreeQuotas()' - Free quotas for a printer. + */ + +void +cupsdFreeQuotas(cupsd_printer_t *p) /* I - Printer */ +{ + if (!p) + return; + + if (p->num_quotas) + free(p->quotas); + + p->num_quotas = 0; + p->quotas = NULL; +} + + +/* + * 'cupsdUpdateQuota()' - Update quota data for the specified printer and user. + */ + +cupsd_quota_t * /* O - Quota data */ +cupsdUpdateQuota( + cupsd_printer_t *p, /* I - Printer */ + const char *username, /* I - User */ + int pages, /* I - Number of pages */ + int k) /* I - Number of kilobytes */ +{ + cupsd_quota_t *q; /* Quota data */ + cupsd_job_t *job; /* Current 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 = cupsdFindQuota(p, username)) == NULL) + return (NULL); + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdUpdateQuota: p=%s username=%s pages=%d k=%d", + p->name, username, pages, k); + + 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 = (cupsd_job_t *)cupsArrayFirst(Jobs); + job; + job = (cupsd_job_t *)cupsArrayNext(Jobs)) + { + 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) + cupsdCancelJob(job, 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 cupsd_quota_t *q1, /* I - First quota record */ + const cupsd_quota_t *q2) /* I - Second quota record */ +{ + return (strcasecmp(q1->username, q2->username)); +} + + +/* + * End of "$Id: quotas.c 4729 2005-09-30 17:46:19Z mike $". + */ diff --git a/scheduler/server.c b/scheduler/server.c new file mode 100644 index 000000000..7cf766391 --- /dev/null +++ b/scheduler/server.c @@ -0,0 +1,206 @@ +/* + * "$Id: server.c 4830 2005-11-12 03:27:16Z mike $" + * + * Server start/stop routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdStartServer() - Start the server. + * cupsdStopServer() - Stop the server. + */ + +/* + * Include necessary headers... + */ + +#include +#include "cupsd.h" +#include + + +/* + * Local globals... + */ + +static int started = 0; + + +/* + * 'cupsdStartServer()' - Start the server. + */ + +void +cupsdStartServer(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)); +#elif defined(HAVE_GNUTLS) + /* + * Initialize the encryption libraries... + */ + + gnutls_global_init(); +#endif /* HAVE_LIBSSL */ + + /* + * Startup all the networking stuff... + */ + + cupsdStartListening(); + cupsdStartBrowsing(); + cupsdStartPolling(); + + /* + * Create a pipe for CGI processes... + */ + + if (cupsdOpenPipe(CGIPipes)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "cupsdStartServer: Unable to create pipes for CGI status!"); + else + { + CGIStatusBuffer = cupsdStatBufNew(CGIPipes[0], "[CGI]"); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStartServer: Adding fd %d to InputSet...", + CGIPipes[0]); + FD_SET(CGIPipes[0], InputSet); + } + + started = 1; +} + + +/* + * 'cupsdStopServer()' - Stop the server. + */ + +void +cupsdStopServer(void) +{ + if (!started) + return; + + /* + * Close all network clients and stop all jobs... + */ + + cupsdCloseAllClients(); + cupsdStopListening(); + cupsdStopPolling(); + cupsdStopBrowsing(); + cupsdStopAllNotifiers(); + cupsdSaveRemoteCache(); + + if (Clients != NULL) + { + free(Clients); + Clients = NULL; + } + +#if defined(HAVE_SSL) && defined(HAVE_CDSASSL) + /* + * Free all of the certificates... + */ + + if (ServerCertificatesArray) + { + CFRelease(ServerCertificatesArray); + ServerCertificatesArray = NULL; + } +#endif /* HAVE_SSL && HAVE_CDSASSL */ + + /* + * Close the pipe for CGI processes... + */ + + if (CGIPipes[0] >= 0) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopServer: Removing fd %d from InputSet...", + CGIPipes[0]); + + FD_CLR(CGIPipes[0], InputSet); + + cupsdStatBufDelete(CGIStatusBuffer); + close(CGIPipes[1]); + + CGIPipes[0] = -1; + CGIPipes[1] = -1; + } + + /* + * Close all log files... + */ + + if (AccessFile != NULL) + { + cupsFileClose(AccessFile); + + AccessFile = NULL; + } + + if (ErrorFile != NULL) + { + cupsFileClose(ErrorFile); + + ErrorFile = NULL; + } + + if (PageFile != NULL) + { + cupsFileClose(PageFile); + + PageFile = NULL; + } + + started = 0; +} + + +/* + * End of "$Id: server.c 4830 2005-11-12 03:27:16Z mike $". + */ diff --git a/scheduler/statbuf.c b/scheduler/statbuf.c new file mode 100644 index 000000000..eedec49c3 --- /dev/null +++ b/scheduler/statbuf.c @@ -0,0 +1,330 @@ +/* + * "$Id: statbuf.c 4719 2005-09-28 21:12:44Z mike $" + * + * Status buffer routines for the Common UNIX Printing System (CUPS) + * scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdStatBufNew() - Create a new status buffer. + * cupsdStatBufDelete() - Destroy a status buffer. + * cupsdStatBufUpdate() - Update the status buffer. + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" +#include + + +/* + * 'cupsdStatBufNew()' - Create a new status buffer. + */ + +cupsd_statbuf_t * /* O - New status buffer */ +cupsdStatBufNew(int fd, /* I - File descriptor of pipe */ + const char *prefix, /* I - Printf-style prefix string */ + ...) /* I - Additional args as needed */ +{ + cupsd_statbuf_t *sb; /* New status buffer */ + va_list ap; /* Argument list */ + + + /* + * Range check input... + */ + + if (fd < 0) + return (NULL); + + /* + * Allocate the status buffer... + */ + + if ((sb = calloc(1, sizeof(cupsd_statbuf_t))) != NULL) + { + /* + * Assign the file descriptor... + */ + + sb->fd = fd; + + /* + * Format the prefix string, if any. This is usually "[Job 123]" + * or "[Sub 123]", and so forth. + */ + + if (prefix) + { + /* + * Printf-style prefix string... + */ + + va_start(ap, prefix); + vsnprintf(sb->prefix, sizeof(sb->prefix), prefix, ap); + va_end(ap); + } + else + { + /* + * No prefix string... + */ + + sb->prefix[0] = '\0'; + } + } + + return (sb); +} + + +/* + * 'cupsdStatBufDelete()' - Destroy a status buffer. + */ + +void +cupsdStatBufDelete(cupsd_statbuf_t *sb) /* I - Status buffer */ +{ + /* + * Range check input... + */ + + if (!sb) + return; + + /* + * Close the status pipe and free memory used... + */ + + close(sb->fd); + + free(sb); +} + + +/* + * 'cupsdStatBufUpdate()' - Update the status buffer. + */ + +char * /* O - Line from buffer, "", or NULL */ +cupsdStatBufUpdate(cupsd_statbuf_t *sb, /* I - Status buffer */ + int *loglevel, + /* O - Log level */ + char *line, + /* I - Line buffer */ + int linelen) + /* I - Size of line buffer */ +{ + int bytes; /* Number of bytes read */ + char *lineptr, /* Pointer to end of line in buffer */ + *message; /* Pointer to message text */ + + + /* + * Check if the buffer already contains a full line... + */ + + if ((lineptr = strchr(sb->buffer, '\n')) == NULL) + { + /* + * No, read more data... + */ + + if ((bytes = read(sb->fd, sb->buffer + sb->bufused, + CUPSD_SB_BUFFER_SIZE - sb->bufused - 1)) > 0) + { + sb->bufused += bytes; + sb->buffer[sb->bufused] = '\0'; + + /* + * Guard against a line longer than the max buffer size... + */ + + if ((lineptr = strchr(sb->buffer, '\n')) == NULL && + sb->bufused == (CUPSD_SB_BUFFER_SIZE - 1)) + lineptr = sb->buffer + sb->bufused; + } + else if (bytes < 0 && errno == EINTR) + { + /* + * Return an empty line if we are interrupted... + */ + + *loglevel = CUPSD_LOG_NONE; + line[0] = '\0'; + + return (line); + } + else + { + /* + * End-of-file, so use the whole buffer... + */ + + lineptr = sb->buffer + sb->bufused; + *lineptr = '\0'; + } + + /* + * Final check for end-of-file... + */ + + if (sb->bufused == 0 && bytes == 0) + lineptr = NULL; + } + + if (lineptr == NULL) + { + /* + * End of file... + */ + + *loglevel = CUPSD_LOG_NONE; + line[0] = '\0'; + + return (NULL); + } + + /* + * Terminate the line and process it... + */ + + *lineptr++ = '\0'; + + /* + * Figure out the logging level... + */ + + if (!strncmp(sb->buffer, "EMERG:", 6)) + { + *loglevel = CUPSD_LOG_EMERG; + message = sb->buffer + 6; + } + else if (!strncmp(sb->buffer, "ALERT:", 6)) + { + *loglevel = CUPSD_LOG_ALERT; + message = sb->buffer + 6; + } + else if (!strncmp(sb->buffer, "CRIT:", 5)) + { + *loglevel = CUPSD_LOG_CRIT; + message = sb->buffer + 5; + } + else if (!strncmp(sb->buffer, "ERROR:", 6)) + { + *loglevel = CUPSD_LOG_ERROR; + message = sb->buffer + 6; + } + else if (!strncmp(sb->buffer, "WARNING:", 8)) + { + *loglevel = CUPSD_LOG_WARN; + message = sb->buffer + 8; + } + else if (!strncmp(sb->buffer, "NOTICE:", 7)) + { + *loglevel = CUPSD_LOG_NOTICE; + message = sb->buffer + 7; + } + else if (!strncmp(sb->buffer, "INFO:", 5)) + { + *loglevel = CUPSD_LOG_INFO; + message = sb->buffer + 5; + } + else if (!strncmp(sb->buffer, "DEBUG:", 6)) + { + *loglevel = CUPSD_LOG_DEBUG; + message = sb->buffer + 6; + } + else if (!strncmp(sb->buffer, "DEBUG2:", 7)) + { + *loglevel = CUPSD_LOG_DEBUG2; + message = sb->buffer + 7; + } + else if (!strncmp(sb->buffer, "PAGE:", 5)) + { + *loglevel = CUPSD_LOG_PAGE; + message = sb->buffer + 5; + } + else if (!strncmp(sb->buffer, "STATE:", 6)) + { + *loglevel = CUPSD_LOG_STATE; + message = sb->buffer + 6; + } + else if (!strncmp(sb->buffer, "ATTR:", 5)) + { + *loglevel = CUPSD_LOG_ATTR; + message = sb->buffer + 5; + } + else + { + *loglevel = CUPSD_LOG_DEBUG; + message = sb->buffer; + } + + /* + * Skip leading whitespace in the message... + */ + + while (isspace(*message & 255)) + message ++; + + /* + * Send it to the log file as needed... + */ + + if (*loglevel > CUPSD_LOG_NONE && + (*loglevel != CUPSD_LOG_INFO || LogLevel == CUPSD_LOG_DEBUG2)) + { + /* + * General status message; send it to the error_log file... + */ + + if (message[0] == '[') + cupsdLogMessage(*loglevel, "%s", message); + else + cupsdLogMessage(*loglevel, "%s %s", sb->prefix, message); + } + + /* + * Copy the message to the line buffer... + */ + + strlcpy(line, message, linelen); + + /* + * Copy over the buffer data we've used up... + */ + + _cups_strcpy(sb->buffer, lineptr); + sb->bufused -= lineptr - sb->buffer; + + if (sb->bufused < 0) + sb->bufused = 0; + + return (line); +} + + +/* + * End of "$Id: statbuf.c 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/statbuf.h b/scheduler/statbuf.h new file mode 100644 index 000000000..fc3601533 --- /dev/null +++ b/scheduler/statbuf.h @@ -0,0 +1,59 @@ +/* + * "$Id: statbuf.h 4613 2005-08-30 12:41:48Z mike $" + * + * Status buffer definitions for the Common UNIX Printing System (CUPS) + * scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + + +/* + * Constants... + */ + +#define CUPSD_SB_BUFFER_SIZE 1024 /* Bytes or job status buffer */ + + +/* + * Types and structures... + */ + +typedef struct /**** Status buffer */ +{ + int fd; /* File descriptor to read from */ + char prefix[64]; /* Prefix for log messages */ + int bufused; /* How much is used in buffer */ + char buffer[CUPSD_SB_BUFFER_SIZE]; /* Buffer */ +} cupsd_statbuf_t; + + +/* + * Prototypes... + */ + +extern cupsd_statbuf_t *cupsdStatBufNew(int fd, const char *prefix, ...); +extern void cupsdStatBufDelete(cupsd_statbuf_t *sb); +extern char *cupsdStatBufUpdate(cupsd_statbuf_t *sb, int *loglevel, + char *line, int linelen); + + +/* + * End of "$Id: statbuf.h 4613 2005-08-30 12:41:48Z mike $". + */ diff --git a/scheduler/subscriptions.c b/scheduler/subscriptions.c new file mode 100644 index 000000000..88f7ffbbd --- /dev/null +++ b/scheduler/subscriptions.c @@ -0,0 +1,1530 @@ +/* + * "$Id: subscriptions.c 4840 2005-11-14 21:53:30Z mike $" + * + * Subscription routines for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdAddEvent() - Add an event to the global event cache. + * cupsdAddSubscription() - Add a new subscription object. + * cupsdDeleteAllEvents() - Delete all cached events. + * cupsdDeleteAllSubscriptions() - Delete all subscriptions. + * cupsdDeleteSubscription() - Delete a subscription object. + * cupsdEventName() - Return a single event name. + * cupsdEventValue() - Return the event mask value for a name. + * cupsdExpireSubscriptions() - Expire old subscription objects. + * cupsdFindSubscription() - Find a subscription by ID. + * cupsdLoadAllSubscriptions() - Load all subscriptions from the .conf file. + * cupsdSaveAllSubscriptions() - Save all subscriptions to the .conf file. + * cupsdSendNotification() - Send a notification for the specified event. + * cupsdStopAllNotifiers() - Stop all notifier processes. + * cupsdUpdateNotifierStatus() - Read messages from notifiers. + * cupsd_compare_subscriptions() - Compare two subscriptions. + * cupsd_delete_event() - Delete a single event... + * cupsd_start_notifier() - Start a notifier subprocess... + */ + +/* + * Include necessary headers... + */ + +#include "cupsd.h" + + +/* + * Local functions... + */ + +static int cupsd_compare_subscriptions(cupsd_subscription_t *first, + cupsd_subscription_t *second, + void *unused); +static void cupsd_delete_event(cupsd_event_t *event); +static void cupsd_start_notifier(cupsd_subscription_t *sub); + + +/* + * 'cupsdAddEvent()' - Add an event to the global event cache. + */ + +void +cupsdAddEvent( + cupsd_eventmask_t event, /* I - Event */ + cupsd_printer_t *dest, /* I - Printer associated with event */ + cupsd_job_t *job, /* I - Job associated with event */ + const char *text, /* I - Notification text */ + ...) /* I - Additional arguments as needed */ +{ + va_list ap; /* Pointer to additional arguments */ + char ftext[1024]; /* Formatted text buffer */ + cupsd_event_t *temp; /* New event pointer */ + cupsd_subscription_t *sub; /* Current subscription */ + + + /* + * Return if we aren't keeping events... + */ + + if (MaxEvents <= 0) + { + cupsdLogMessage(CUPSD_LOG_WARN, + "cupsdAddEvent: Discarding %s event since MaxEvents is %d!", + cupsdEventName(event), MaxEvents); + return; + } + + /* + * Allocate memory for the event cache as needed... + */ + + if (!Events) + { + Events = calloc(MaxEvents, sizeof(cupsd_event_t *)); + NumEvents = 0; + + if (!Events) + { + cupsdLogMessage(CUPSD_LOG_CRIT, + "Unable to allocate memory for event cache - %s", + strerror(errno)); + return; + } + } + + /* + * Then loop through the subscriptions and add the event to the corresponding + * caches... + */ + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions), temp = NULL; + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + { + /* + * Check if this subscription requires this event... + */ + + if ((sub->mask & event) != 0 && + (sub->dest == dest || !sub->dest) && + (sub->job == job || !sub->job)) + { + /* + * Need this event... + */ + + if (!temp) + { + /* + * Create the new event record... + */ + + if ((temp = (cupsd_event_t *)calloc(1, sizeof(cupsd_event_t))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_CRIT, + "Unable to allocate memory for event - %s", + strerror(errno)); + return; + } + + temp->event = event; + temp->time = time(NULL); + temp->attrs = ippNew(); + temp->job = job; + temp->dest = dest; + + /* + * Add common event notification attributes... + */ + + ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, + "notify-subscription-id", sub->id); + + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, + "notify-subscribed-event", NULL, cupsdEventName(event)); + + ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, + "printer-up-time", time(NULL)); + + va_start(ap, text); + vsnprintf(ftext, sizeof(ftext), text, ap); + va_end(ap); + + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_KEYWORD, + "notify-text", NULL, ftext); + + if (dest) + { + /* + * Add printer attributes... + */ + + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_URI, + "notify-printer-uri", NULL, dest->uri); + + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_NAME, + "printer-name", NULL, dest->name); + + ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM, + "printer-state", dest->state); + + if (dest->num_reasons == 0) + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "printer-state-reasons", NULL, + dest->state == IPP_PRINTER_STOPPED ? "paused" : "none"); + else + ippAddStrings(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "printer-state-reasons", + dest->num_reasons, NULL, + (const char * const *)dest->reasons); + + ippAddBoolean(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + "printer-is-accepting-jobs", dest->accepting); + } + + if (job) + { + /* + * Add job attributes... + */ + + ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, + "job-id", job->id); + ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_ENUM, + "job-state", (int)job->state); + + switch (job->state->values[0].integer) + { + case IPP_JOB_PENDING : + if (dest && dest->state == IPP_PRINTER_STOPPED) + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "job-state-reasons", NULL, + "printer-stopped"); + else + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + 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(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "job-state-reasons", NULL, + "job-hold-until-specified"); + else + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "job-state-reasons", NULL, + "job-incoming"); + break; + + case IPP_JOB_PROCESSING : + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "job-state-reasons", NULL, + "job-printing"); + break; + + case IPP_JOB_STOPPED : + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "job-state-reasons", NULL, + "job-stopped"); + break; + + case IPP_JOB_CANCELLED : + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "job-state-reasons", NULL, + "job-canceled-by-user"); + break; + + case IPP_JOB_ABORTED : + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "job-state-reasons", NULL, + "aborted-by-system"); + break; + + case IPP_JOB_COMPLETED : + ippAddString(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, + IPP_TAG_KEYWORD, "job-state-reasons", NULL, + "job-completed-successfully"); + break; + } + + ippAddInteger(temp->attrs, IPP_TAG_EVENT_NOTIFICATION, IPP_TAG_INTEGER, + "job-impressions-completed", + job->sheets ? job->sheets->values[0].integer : 0); + } + + /* + * Purge an old event as needed... + */ + + if (NumEvents >= MaxEvents) + { + /* + * Purge the oldest event in the cache... + */ + + cupsd_delete_event(Events[0]); + + NumEvents --; + + memmove(Events, Events + 1, NumEvents * sizeof(cupsd_event_t *)); + } + + /* + * Add the new event to the main cache... + */ + + Events[NumEvents] = temp; + NumEvents ++; + } + + /* + * Send the notification for this subscription... + */ + + cupsdSendNotification(sub, temp); + } + } + + if (temp) + cupsdSaveAllSubscriptions(); + else + cupsdLogMessage(CUPSD_LOG_DEBUG, "Discarding unused %s event...", + cupsdEventName(event)); +} + + +/* + * 'cupsdAddSubscription()' - Add a new subscription object. + */ + +cupsd_subscription_t * /* O - New subscription object */ +cupsdAddSubscription( + unsigned mask, /* I - Event mask */ + cupsd_printer_t *dest, /* I - Printer, if any */ + cupsd_job_t *job, /* I - Job, if any */ + const char *uri, /* I - notify-recipient-uri, if any */ + int sub_id) /* I - notify-subscription-id or 0 */ +{ + cupsd_subscription_t *temp; /* New subscription object */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdAddSubscription(mask=%x(%s), dest=%p(%s), job=%p(%d), uri=\"%s\")", + mask, cupsdEventName(mask), dest, dest ? dest->name : "", + job, job ? job->id : 0, uri); + + if (!Subscriptions) + Subscriptions = cupsArrayNew((cups_array_func_t)cupsd_compare_subscriptions, + NULL); + + if (!Subscriptions) + { + cupsdLogMessage(CUPSD_LOG_CRIT, + "Unable to allocate memory for subscriptions - %s", + strerror(errno)); + return (NULL); + } + + /* + * Limit the number of subscriptions... + */ + + if (cupsArrayCount(Subscriptions) >= MaxSubscriptions) + return (NULL); + + /* + * Allocate memory for this subscription... + */ + + if ((temp = calloc(1, sizeof(cupsd_subscription_t))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_CRIT, + "Unable to allocate memory for subscription object - %s", + strerror(errno)); + return (NULL); + } + + /* + * Fill in common data... + */ + + if (sub_id) + { + temp->id = sub_id; + + if (sub_id >= NextSubscriptionId) + NextSubscriptionId = sub_id + 1; + } + else + { + temp->id = NextSubscriptionId; + + NextSubscriptionId ++; + } + + temp->mask = mask; + temp->dest = dest; + temp->job = job; + temp->pipe = -1; + temp->first_event_id = 1; + temp->next_event_id = 1; + + cupsdSetString(&(temp->recipient), uri); + + /* + * Add the subscription to the array... + */ + + cupsArrayAdd(Subscriptions, temp); + + return (temp); +} + + +/* + * 'cupsdDeleteAllEvents()' - Delete all cached events. + */ + +void +cupsdDeleteAllEvents(void) +{ + int i; /* Looping var */ + + + if (MaxEvents <= 0 || !Events) + return; + + for (i = 0; i < NumEvents; i ++) + cupsd_delete_event(Events[i]); + + free(Events); + Events = NULL; +} + + +/* + * 'cupsdDeleteAllSubscriptions()' - Delete all subscriptions. + */ + +void +cupsdDeleteAllSubscriptions(void) +{ + cupsd_subscription_t *sub; /* Subscription */ + + + if (!Subscriptions) + return; + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + cupsdDeleteSubscription(sub, 0); + + cupsArrayDelete(Subscriptions); + Subscriptions = NULL; +} + + +/* + * 'cupsdDeleteSubscription()' - Delete a subscription object. + */ + +void +cupsdDeleteSubscription( + cupsd_subscription_t *sub, /* I - Subscription object */ + int update) /* I - 1 = update subscriptions.conf */ +{ + /* + * Close the pipe to the notifier as needed... + */ + + if (sub->pipe >= 0) + close(sub->pipe); + + /* + * Remove subscription from array... + */ + + cupsArrayRemove(Subscriptions, sub); + + /* + * Free memory... + */ + + cupsdClearString(&(sub->owner)); + cupsdClearString(&(sub->recipient)); + + if (sub->events) + free(sub->events); + + free(sub); + + /* + * Update the subscriptions as needed... + */ + + if (update) + cupsdSaveAllSubscriptions(); +} + + +/* + * 'cupsdEventName()' - Return a single event name. + */ + +const char * /* O - Event name */ +cupsdEventName( + cupsd_eventmask_t event) /* I - Event value */ +{ + switch (event) + { + default : + return (NULL); + + case CUPSD_EVENT_PRINTER_RESTARTED : + return ("printer-restarted"); + + case CUPSD_EVENT_PRINTER_SHUTDOWN : + return ("printer-shutdown"); + + case CUPSD_EVENT_PRINTER_STOPPED : + return ("printer-stopped"); + + case CUPSD_EVENT_PRINTER_FINISHINGS_CHANGED : + return ("printer-finishings-changed"); + + case CUPSD_EVENT_PRINTER_MEDIA_CHANGED : + return ("printer-media-changed"); + + case CUPSD_EVENT_PRINTER_ADDED : + return ("printer-added"); + + case CUPSD_EVENT_PRINTER_DELETED : + return ("printer-deleted"); + + case CUPSD_EVENT_PRINTER_MODIFIED : + return ("printer-modified"); + + case CUPSD_EVENT_PRINTER_STATE_CHANGED : + return ("printer-state-changed"); + + case CUPSD_EVENT_PRINTER_CONFIG_CHANGED : + return ("printer-config-changed"); + + case CUPSD_EVENT_PRINTER_CHANGED : + return ("printer-changed"); + + case CUPSD_EVENT_JOB_CREATED : + return ("job-created"); + + case CUPSD_EVENT_JOB_COMPLETED : + return ("job-completed"); + + case CUPSD_EVENT_JOB_STOPPED : + return ("job-stopped"); + + case CUPSD_EVENT_JOB_CONFIG_CHANGED : + return ("job-config-changed"); + + case CUPSD_EVENT_JOB_PROGRESS : + return ("job-progress"); + + case CUPSD_EVENT_JOB_STATE_CHANGED : + return ("job-state-changed"); + + case CUPSD_EVENT_SERVER_RESTARTED : + return ("server-restarted"); + + case CUPSD_EVENT_SERVER_STARTED : + return ("server-started"); + + case CUPSD_EVENT_SERVER_STOPPED : + return ("server-stopped"); + + case CUPSD_EVENT_SERVER_AUDIT : + return ("server-audit"); + + case CUPSD_EVENT_ALL : + return ("all"); + } +} + + +/* + * 'cupsdEventValue()' - Return the event mask value for a name. + */ + +cupsd_eventmask_t /* O - Event mask value */ +cupsdEventValue(const char *name) /* I - Name of event */ +{ + if (!strcmp(name, "all")) + return (CUPSD_EVENT_ALL); + else if (!strcmp(name, "printer-restarted")) + return (CUPSD_EVENT_PRINTER_RESTARTED); + else if (!strcmp(name, "printer-shutdown")) + return (CUPSD_EVENT_PRINTER_SHUTDOWN); + else if (!strcmp(name, "printer-stopped")) + return (CUPSD_EVENT_PRINTER_STOPPED); + else if (!strcmp(name, "printer-finishings-changed")) + return (CUPSD_EVENT_PRINTER_FINISHINGS_CHANGED); + else if (!strcmp(name, "printer-media-changed")) + return (CUPSD_EVENT_PRINTER_MEDIA_CHANGED); + else if (!strcmp(name, "printer-added")) + return (CUPSD_EVENT_PRINTER_ADDED); + else if (!strcmp(name, "printer-deleted")) + return (CUPSD_EVENT_PRINTER_DELETED); + else if (!strcmp(name, "printer-modified")) + return (CUPSD_EVENT_PRINTER_MODIFIED); + else if (!strcmp(name, "printer-state-changed")) + return (CUPSD_EVENT_PRINTER_STATE_CHANGED); + else if (!strcmp(name, "printer-config-changed")) + return (CUPSD_EVENT_PRINTER_CONFIG_CHANGED); + else if (!strcmp(name, "printer-changed")) + return (CUPSD_EVENT_PRINTER_CHANGED); + else if (!strcmp(name, "job-created")) + return (CUPSD_EVENT_JOB_CREATED); + else if (!strcmp(name, "job-completed")) + return (CUPSD_EVENT_JOB_COMPLETED); + else if (!strcmp(name, "job-stopped")) + return (CUPSD_EVENT_JOB_STOPPED); + else if (!strcmp(name, "job-config-changed")) + return (CUPSD_EVENT_JOB_CONFIG_CHANGED); + else if (!strcmp(name, "job-progress")) + return (CUPSD_EVENT_JOB_PROGRESS); + else if (!strcmp(name, "job-state-changed")) + return (CUPSD_EVENT_JOB_STATE_CHANGED); + else if (!strcmp(name, "server-restarted")) + return (CUPSD_EVENT_SERVER_RESTARTED); + else if (!strcmp(name, "server-started")) + return (CUPSD_EVENT_SERVER_STARTED); + else if (!strcmp(name, "server-stopped")) + return (CUPSD_EVENT_SERVER_STOPPED); + else if (!strcmp(name, "server-audit")) + return (CUPSD_EVENT_SERVER_AUDIT); + else + return (CUPSD_EVENT_NONE); +} + + +/* + * 'cupsdExpireSubscriptions()' - Expire old subscription objects. + */ + +void +cupsdExpireSubscriptions( + cupsd_printer_t *dest, /* I - Printer, if any */ + cupsd_job_t *job) /* I - Job, if any */ +{ + cupsd_subscription_t *sub; /* Current subscription */ + int update; /* Update subscriptions.conf? */ + time_t curtime; /* Current time */ + + + curtime = time(NULL); + update = 0; + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + if (sub->expire <= curtime || + (dest && sub->dest == dest) || + (job && sub->job == job)) + { + cupsdLogMessage(CUPSD_LOG_INFO, "Subscription %d has expired...", sub->id); + + cupsdDeleteSubscription(sub, 0); + + update = 1; + } + + if (update) + cupsdSaveAllSubscriptions(); +} + + +/* + * 'cupsdFindSubscription()' - Find a subscription by ID. + */ + +cupsd_subscription_t * /* O - Subscription object */ +cupsdFindSubscription(int id) /* I - Subscription ID */ +{ + cupsd_subscription_t sub; /* Subscription template */ + + + sub.id = id; + + return ((cupsd_subscription_t *)cupsArrayFind(Subscriptions, &sub)); +} + + +/* + * 'cupsdLoadAllSubscriptions()' - Load all subscriptions from the .conf file. + */ + +void +cupsdLoadAllSubscriptions(void) +{ + int i; /* Looping var */ + cups_file_t *fp; /* subscriptions.conf file */ + int linenum; /* Current line number */ + char line[1024], /* Line from file */ + *value, /* Pointer to value */ + *valueptr; /* Pointer into value */ + cupsd_subscription_t *sub; /* Current subscription */ + int hex; /* Non-zero if reading hex data */ + int delete_sub; /* Delete subscription? */ + + + /* + * Open the subscriptions.conf file... + */ + + snprintf(line, sizeof(line), "%s/subscriptions.conf", ServerRoot); + if ((fp = cupsFileOpen(line, "r")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "LoadAllSubscriptions: Unable to open %s - %s", line, + strerror(errno)); + return; + } + + /* + * Read all of the lines from the file... + */ + + linenum = 0; + sub = NULL; + delete_sub = 0; + + while (cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) + { + if (!strcasecmp(line, " + */ + + if (!sub && value && isdigit(value[0] & 255)) + { + sub = cupsdAddSubscription(CUPSD_EVENT_NONE, NULL, NULL, NULL, + atoi(value)); + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "")) + { + if (!sub) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + + if (delete_sub) + cupsdDeleteSubscription(sub, 0); + + sub = NULL; + delete_sub = 0; + } + else if (!sub) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + else if (!strcasecmp(line, "Events")) + { + /* + * Events name + * Events name name name ... + */ + + if (!value) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + + while (*value) + { + /* + * Separate event names... + */ + + for (valueptr = value; !isspace(*valueptr) && *valueptr; valueptr ++); + + while (isspace(*valueptr & 255)) + *valueptr++ = '\0'; + + /* + * See if the name exists... + */ + + if ((sub->mask |= cupsdEventValue(value)) == CUPSD_EVENT_NONE) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown event name \'%s\' on line %d of subscriptions.conf.", + value, linenum); + return; + } + + value = valueptr; + } + } + else if (!strcasecmp(line, "Owner")) + { + /* + * Owner + */ + + if (value) + cupsdSetString(&sub->owner, value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "Recipient")) + { + /* + * Recipient uri + */ + + if (value) + cupsdSetString(&sub->recipient, value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "JobId")) + { + /* + * JobId # + */ + + if (value && isdigit(*value & 255)) + { + if ((sub->job = cupsdFindJob(atoi(value))) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Job %s not found on line %d of subscriptions.conf.", + value, linenum); + delete_sub = 1; + } + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "PrinterName")) + { + /* + * PrinterName name + */ + + if (value) + { + if ((sub->dest = cupsdFindDest(value)) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Printer \'%s\' not found on line %d of subscriptions.conf.", + value, linenum); + delete_sub = 1; + } + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "UserData")) + { + /* + * UserData encoded-string + */ + + if (value) + { + for (i = 0, valueptr = value, hex = 0; i < 63 && *valueptr; i ++) + { + if (*valueptr == '<' && !hex) + { + hex = 1; + valueptr ++; + } + + if (hex) + { + if (isxdigit(valueptr[0]) && isxdigit(valueptr[1])) + { + if (isdigit(valueptr[0])) + sub->user_data[i] = (valueptr[0] - '0') << 4; + else + sub->user_data[i] = (tolower(valueptr[0]) - 'a' + 10) << 4; + + if (isdigit(valueptr[1])) + sub->user_data[i] |= valueptr[1] - '0'; + else + sub->user_data[i] |= tolower(valueptr[1]) - 'a' + 10; + + valueptr += 2; + + if (*valueptr == '>') + { + hex = 0; + valueptr ++; + } + } + else + break; + } + else + sub->user_data[i] = *valueptr++; + } + + if (*valueptr) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Bad UserData \'%s\' on line %d of subscriptions.conf.", + value, linenum); + } + else + sub->user_data_len = i; + } + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "LeaseDuration")) + { + /* + * LeaseDuration # + */ + + if (value && isdigit(*value & 255)) + sub->lease = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "Interval")) + { + /* + * Interval # + */ + + if (value && isdigit(*value & 255)) + sub->interval = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "ExpirationTime")) + { + /* + * ExpirationTime # + */ + + if (value && isdigit(*value & 255)) + sub->expire = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else if (!strcasecmp(line, "NextEventId")) + { + /* + * NextEventId # + */ + + if (value && isdigit(*value & 255)) + sub->next_event_id = sub->first_event_id = atoi(value); + else + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Syntax error on line %d of subscriptions.conf.", + linenum); + return; + } + } + else + { + /* + * Something else we don't understand... + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unknown configuration directive %s on line %d of subscriptions.conf.", + line, linenum); + } + } + + cupsFileClose(fp); +} + + +/* + * 'cupsdSaveAllSubscriptions()' - Save all subscriptions to the .conf file. + */ + +void +cupsdSaveAllSubscriptions(void) +{ + int i; /* Looping var */ + cups_file_t *fp; /* subscriptions.conf file */ + char temp[1024]; /* Temporary string */ + char backup[1024]; /* subscriptions.conf.O file */ + cupsd_subscription_t *sub; /* Current subscription */ + time_t curtime; /* Current time */ + struct tm *curdate; /* Current date */ + unsigned mask; /* Current event mask */ + const char *name; /* Current event name */ + int hex; /* Non-zero if we are writing hex data */ + + + /* + * Create the subscriptions.conf file... + */ + + snprintf(temp, sizeof(temp), "%s/subscriptions.conf", ServerRoot); + snprintf(backup, sizeof(backup), "%s/subscriptions.conf.O", ServerRoot); + + if (rename(temp, backup)) + { + if (errno != ENOENT) + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to backup subscriptions.conf - %s", + strerror(errno)); + } + + if ((fp = cupsFileOpen(temp, "w")) == NULL) + { + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to save subscriptions.conf - %s", + strerror(errno)); + + if (rename(backup, temp)) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to restore subscriptions.conf - %s", + strerror(errno)); + return; + } + else + cupsdLogMessage(CUPSD_LOG_INFO, "Saving subscriptions.conf..."); + + /* + * Restrict access to the file... + */ + + fchown(cupsFileNumber(fp), getuid(), Group); + fchmod(cupsFileNumber(fp), ConfigFilePerm); + + /* + * Write a small header to the file... + */ + + curtime = time(NULL); + curdate = localtime(&curtime); + strftime(temp, sizeof(temp) - 1, "%Y-%m-%d %H:%M", curdate); + + cupsFilePuts(fp, "# Subscription configuration file for " CUPS_SVERSION "\n"); + cupsFilePrintf(fp, "# Written by cupsd on %s\n", temp); + + /* + * Write every subscription known to the system... + */ + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + { + cupsFilePrintf(fp, "\n", sub->id); + + if ((name = cupsdEventName((cupsd_eventmask_t)sub->mask)) != NULL) + { + /* + * Simple event list... + */ + + cupsFilePrintf(fp, "Events %s\n", name); + } + else + { + /* + * Complex event list... + */ + + cupsFilePuts(fp, "Events"); + + for (mask = 1; mask < CUPSD_EVENT_ALL; mask <<= 1) + if (sub->mask & mask) + cupsFilePrintf(fp, " %s", cupsdEventName((cupsd_eventmask_t)mask)); + + cupsFilePuts(fp, "\n"); + } + + if (sub->owner) + cupsFilePrintf(fp, "Owner %s\n", sub->owner); + if (sub->recipient) + cupsFilePrintf(fp, "Recipient %s\n", sub->recipient); + if (sub->job) + cupsFilePrintf(fp, "JobId %d\n", sub->job->id); + if (sub->dest) + cupsFilePrintf(fp, "PrinterName %s\n", sub->dest->name); + + if (sub->user_data_len > 0) + { + cupsFilePuts(fp, "UserData "); + + for (i = 0, hex = 0; i < sub->user_data_len; i ++) + { + if (sub->user_data[i] < ' ' || + sub->user_data[i] > 0x7f || + sub->user_data[i] == '<') + { + if (!hex) + { + cupsFilePrintf(fp, "<%02X", sub->user_data[i]); + hex = 1; + } + else + cupsFilePrintf(fp, "%02X", sub->user_data[i]); + } + else + { + if (hex) + { + cupsFilePrintf(fp, ">%c", sub->user_data[i]); + hex = 0; + } + else + cupsFilePutChar(fp, sub->user_data[i]); + } + } + + if (hex) + cupsFilePuts(fp, ">\n"); + else + cupsFilePutChar(fp, '\n'); + } + + cupsFilePrintf(fp, "LeaseDuration %d\n", sub->lease); + cupsFilePrintf(fp, "Interval %d\n", sub->interval); + cupsFilePrintf(fp, "ExpirationTime %ld\n", (long)sub->expire); + cupsFilePrintf(fp, "NextEventId %d\n", sub->next_event_id); + + cupsFilePuts(fp, "\n"); + } + + cupsFileClose(fp); +} + + +/* + * 'cupsdSendNotification()' - Send a notification for the specified event. + */ + +void +cupsdSendNotification( + cupsd_subscription_t *sub, /* I - Subscription object */ + cupsd_event_t *event) /* I - Event to send */ +{ + ipp_state_t state; /* IPP event state */ + + + cupsdLogMessage(CUPSD_LOG_DEBUG, + "cupsdSendNotification(sub=%p(%d), event=%p(%s))\n", + sub, sub->id, event, cupsdEventName(event->event)); + + /* + * Allocate the events array as needed... + */ + + if (!sub->events) + { + sub->events = calloc(MaxEvents, sizeof(cupsd_event_t *)); + + if (!sub->events) + { + cupsdLogMessage(CUPSD_LOG_CRIT, + "Unable to allocate memory for subscription #%d!", + sub->id); + return; + } + } + + /* + * Add the event to the subscription. Since the events array is + * always MaxEvents in length, and since we will have already + * removed an event from the subscription cache if we hit the + * event cache limit, we don't need to check for overflow here... + */ + + sub->events[sub->num_events] = event; + sub->num_events ++; + + /* + * Deliver the event... + */ + + if (sub->recipient) + { + if (sub->pipe < 0) + cupsd_start_notifier(sub); + + if (sub->pipe >= 0) + { + event->attrs->state = IPP_IDLE; + + while ((state = ippWriteFile(sub->pipe, event->attrs)) != IPP_DATA) + if (state == IPP_ERROR) + break; + + if (state == IPP_ERROR) + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to send event for subscription %d (%s)!", + sub->id, sub->recipient); + } + } + + /* + * Bump the event sequence number... + */ + + sub->next_event_id ++; +} + + +/* + * 'cupsdStopAllNotifiers()' - Stop all notifier processes. + */ + +void +cupsdStopAllNotifiers(void) +{ + cupsd_subscription_t *sub; /* Current subscription */ + + + /* + * See if we have started any notifiers... + */ + + if (!NotifierStatusBuffer) + return; + + /* + * Yes, kill and processes that are left... + */ + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + if (sub->pid) + { + cupsdEndProcess(sub->pid, 0); + + close(sub->pipe); + sub->pipe = -1; + } + + /* + * Close the status pipes... + */ + + if (NotifierPipes[0] >= 0) + { + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "cupsdStopAllNotifiers: Removing fd %d from InputSet...", + NotifierPipes[0]); + FD_CLR(NotifierPipes[0], InputSet); + + cupsdStatBufDelete(NotifierStatusBuffer); + + close(NotifierPipes[0]); + close(NotifierPipes[1]); + + NotifierPipes[0] = -1; + NotifierPipes[1] = -1; + NotifierStatusBuffer = NULL; + } +} + + +/* + * 'cupsdUpdateNotifierStatus()' - Read messages from notifiers. + */ + +void +cupsdUpdateNotifierStatus(void) +{ + char *ptr, /* Pointer to end of line in buffer */ + message[1024]; /* Pointer to message text */ + int loglevel; /* Log level for message */ + + + while ((ptr = cupsdStatBufUpdate(NotifierStatusBuffer, &loglevel, + message, sizeof(message))) != NULL) + if (!strchr(NotifierStatusBuffer->buffer, '\n')) + break; +} + + +/* + * 'cupsd_compare_subscriptions()' - Compare two subscriptions. + */ + +static int /* O - Result of comparison */ +cupsd_compare_subscriptions( + cupsd_subscription_t *first, /* I - First subscription object */ + cupsd_subscription_t *second, /* I - Second subscription object */ + void *unused) /* I - Unused user data pointer */ +{ + (void)unused; + + return (first->id - second->id); +} + + +/* + * 'cupsd_delete_event()' - Delete a single event... + * + * Oldest events must be deleted first, otherwise the subscription cache + * flushing code will not work properly. + */ + +static void +cupsd_delete_event(cupsd_event_t *event)/* I - Event to delete */ +{ + cupsd_subscription_t *sub; /* Current subscription */ + + + /* + * Loop through the subscriptions and look for the event in the cache... + */ + + for (sub = (cupsd_subscription_t *)cupsArrayFirst(Subscriptions); + sub; + sub = (cupsd_subscription_t *)cupsArrayNext(Subscriptions)) + { + /* + * Only check the first event in the subscription cache, since the + * caller will only delete the oldest event in the cache... + */ + + if (sub->num_events > 0 && sub->events[0] == event) + { + /* + * Remove this event... + */ + + sub->num_events --; + sub->first_event_id ++; + + if (sub->num_events > 0) + { + /* + * Shift other events upward in cache... + */ + + memmove(sub->events, sub->events + 1, + sub->num_events * sizeof(cupsd_event_t *)); + } + } + } + + /* + * Free memory... + */ + + ippDelete(event->attrs); + free(event); +} + + +/* + * 'cupsd_start_notifier()' - Start a notifier subprocess... + */ + +static void +cupsd_start_notifier( + cupsd_subscription_t *sub) /* I - Subscription object */ +{ + int pid; /* Notifier process ID */ + int fds[2]; /* Pipe file descriptors */ + int envc; /* Number of environment variables */ + char *argv[4], /* Command-line arguments */ + *envp[100], /* Environment variables */ + user_data[128], /* Base-64 encoded user data */ + scheme[256], /* notify-recipient-uri scheme */ + *ptr, /* Pointer into scheme */ + command[1024]; /* Notifier command */ + + + /* + * Extract the scheme name from the recipient URI and point to the + * notifier program... + */ + + strlcpy(scheme, sub->recipient, sizeof(scheme)); + if ((ptr = strchr(scheme, ':')) != NULL) + *ptr = '\0'; + + snprintf(command, sizeof(command), "%s/notifier/%s", ServerBin, scheme); + + /* + * Base-64 encode the user data... + */ + + httpEncode64_2(user_data, sizeof(user_data), (char *)sub->user_data, + sub->user_data_len); + + /* + * Setup the argument array... + */ + + argv[0] = command; + argv[1] = sub->recipient; + argv[2] = user_data; + argv[3] = NULL; + + /* + * Setup the environment... + */ + + envc = cupsdLoadEnv(envp, (int)(sizeof(envp) / sizeof(envp[0]))); + + /* + * Create pipes as needed... + */ + + if (!NotifierStatusBuffer) + { + /* + * Create the status pipe... + */ + + if (cupsdOpenPipe(NotifierPipes)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create pipes for notifier status - %s", + strerror(errno)); + return; + } + + NotifierStatusBuffer = cupsdStatBufNew(NotifierPipes[0], "[Notifier]"); + + cupsdLogMessage(CUPSD_LOG_DEBUG2, + "start_notifier: Adding fd %d to InputSet...", + NotifierPipes[0]); + + FD_SET(NotifierPipes[0], InputSet); + } + + if (cupsdOpenPipe(fds)) + { + cupsdLogMessage(CUPSD_LOG_ERROR, + "Unable to create pipes for notifier %s - %s", + scheme, strerror(errno)); + return; + } + + /* + * Make sure the delivery pipe is non-blocking... + */ + + fcntl(fds[1], F_SETFL, fcntl(fds[1], F_GETFL) | O_NONBLOCK); + + /* + * Create the notifier process... + */ + + if (cupsdStartProcess(command, argv, envp, fds[0], -1, NotifierPipes[1], + -1, 0, &pid) < 0) + { + /* + * Error - can't fork! + */ + + cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to fork for notifier %s - %s", + scheme, strerror(errno)); + + cupsdClosePipe(fds); + } + else + { + /* + * Fork successful - return the PID... + */ + + cupsdLogMessage(CUPSD_LOG_DEBUG, "Notifier %s started - PID = %d", + scheme, pid); + + sub->pid = pid; + sub->pipe = fds[1]; + sub->status = 0; + + close(fds[0]); + } +} + + +/* + * End of "$Id: subscriptions.c 4840 2005-11-14 21:53:30Z mike $". + */ diff --git a/scheduler/subscriptions.h b/scheduler/subscriptions.h new file mode 100644 index 000000000..56f02a3ab --- /dev/null +++ b/scheduler/subscriptions.h @@ -0,0 +1,175 @@ +/* + * "$Id: subscriptions.h 4840 2005-11-14 21:53:30Z mike $" + * + * Subscription definitions for the Common UNIX Printing System (CUPS) scheduler. + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +/* + * Event mask enumeration... + */ + +typedef enum +{ + /* Individual printer events... */ + CUPSD_EVENT_PRINTER_RESTARTED = 0x0001, + /* Sent after printer restarted */ + CUPSD_EVENT_PRINTER_SHUTDOWN = 0x0002,/* Sent after printer shutdown */ + CUPSD_EVENT_PRINTER_STOPPED = 0x0004, /* Sent after printer stopped */ + CUPSD_EVENT_PRINTER_FINISHINGS_CHANGED = 0x0008, + /* Sent after finishings-supported changed */ + CUPSD_EVENT_PRINTER_MEDIA_CHANGED = 0x0010, + /* Sent after media-supported changed */ + CUPSD_EVENT_PRINTER_ADDED = 0x0020, /* Sent after printer added */ + CUPSD_EVENT_PRINTER_DELETED = 0x0040, /* Sent after printer deleted */ + CUPSD_EVENT_PRINTER_MODIFIED = 0x0080,/* Sent after printer modified */ + + /* Convenience printer event groupings... */ + CUPSD_EVENT_PRINTER_STATE_CHANGED = 0x0007, + /* RESTARTED + SHUTDOWN + STOPPED */ + CUPSD_EVENT_PRINTER_CONFIG_CHANGED = 0x0018, + /* FINISHINGS_CHANGED + MEDIA_CHANGED */ + CUPSD_EVENT_PRINTER_CHANGED = 0x00ff, /* All of the above */ + + /* Individual job events... */ + CUPSD_EVENT_JOB_CREATED = 0x0100, /* Send after job is created */ + CUPSD_EVENT_JOB_COMPLETED = 0x0200, /* Sent after job is completed */ + CUPSD_EVENT_JOB_STOPPED = 0x0400, /* Sent after job is stopped */ + CUPSD_EVENT_JOB_CONFIG_CHANGED = 0x0800, + /* Sent after set-job-attributes */ + CUPSD_EVENT_JOB_PROGRESS = 0x1000, /* Sent for each page */ + + /* Convenience job event grouping... */ + CUPSD_EVENT_JOB_STATE_CHANGED = 0x0700, + /* CREATED + COMPLETED + STOPPED */ + + /* Server events... */ + CUPSD_EVENT_SERVER_RESTARTED = 0x2000,/* Sent after server restarts */ + CUPSD_EVENT_SERVER_STARTED = 0x4000, /* Sent when server first starts */ + CUPSD_EVENT_SERVER_STOPPED = 0x8000, /* Sent when server is stopped */ + CUPSD_EVENT_SERVER_AUDIT = 0x10000, /* Security-related stuff */ + + /* Everything and nothing... */ + CUPSD_EVENT_NONE = 0, /* Nothing */ + CUPSD_EVENT_ALL = 0x1ffff /* Everything */ +} cupsd_eventmask_t; + + +/* + * Notiification support structures... + */ + +typedef struct cupsd_event_s /**** Event structure ****/ +{ + cupsd_eventmask_t event; /* Event */ + time_t time; /* Time of event */ + ipp_t *attrs; /* Notification message */ + cupsd_printer_t *dest; /* Associated printer, if any */ + cupsd_job_t *job; /* Associated job, if any */ +} cupsd_event_t; + +typedef struct cupsd_subscription_s /**** Subscription structure ****/ +{ + int id; /* subscription-id */ + unsigned mask; /* Event mask */ + char *owner; /* notify-subscriber-user-name */ + char *recipient; /* notify-recipient-uri, if applicable */ + unsigned char user_data[64]; /* notify-user-data */ + int user_data_len; /* Length of notify-user-data */ + int lease; /* notify-lease-duration */ + int interval; /* notify-time-interval */ + cupsd_printer_t *dest; /* notify-printer-uri, if any */ + cupsd_job_t *job; /* notify-job-id, if any */ + int pid; /* Process ID of notifier */ + int pipe; /* Pipe to notifier */ + int status; /* Exit status of notifier */ + time_t last; /* Time of last notification */ + time_t expire; /* Lease expiration time */ + int first_event_id, /* First event-id in cache */ + next_event_id, /* Next event-id to use */ + num_events; /* Number of cached events */ + cupsd_event_t **events; /* Cached events */ +} cupsd_subscription_t; + + +/* + * Globals... + */ + +VAR int MaxSubscriptions VALUE(100), + /* Overall subscription limit */ + MaxSubscriptionsPerJob VALUE(0), + /* Per-job subscription limit */ + MaxSubscriptionsPerPrinter VALUE(0), + /* Per-printer subscription limit */ + MaxSubscriptionsPerUser VALUE(0), + /* Per-user subscription limit */ + NextSubscriptionId VALUE(1), + /* Next subscription ID */ + DefaultLeaseDuration VALUE(86400), + /* Default notify-lease-duration */ + MaxLeaseDuration VALUE(0); + /* Maximum notify-lease-duration */ +VAR cups_array_t *Subscriptions VALUE(NULL); + /* Active subscriptions */ + +VAR int MaxEvents VALUE(100), /* Maximum number of events */ + NumEvents VALUE(0); /* Number of active events */ +VAR cupsd_event_t **Events VALUE(NULL); /* Active events */ + +VAR int NotifierPipes[2] VALUE2(-1, -1); + /* Pipes for notifier error/debug output */ +VAR cupsd_statbuf_t *NotifierStatusBuffer VALUE(NULL); + /* Status buffer for pipes */ + + +/* + * Prototypes... + */ + +extern void cupsdAddEvent(cupsd_eventmask_t event, cupsd_printer_t *dest, + cupsd_job_t *job, const char *text, ...); +extern cupsd_subscription_t * + cupsdAddSubscription(unsigned mask, cupsd_printer_t *dest, + cupsd_job_t *job, const char *uri, + int sub_id); +extern void cupsdDeleteAllEvents(void); +extern void cupsdDeleteAllSubscriptions(void); +extern void cupsdDeleteSubscription(cupsd_subscription_t *sub, int update); +extern const char * + cupsdEventName(cupsd_eventmask_t event); +extern cupsd_eventmask_t + cupsdEventValue(const char *name); + +extern cupsd_subscription_t * + cupsdFindSubscription(int id); +extern void cupsdExpireSubscriptions(cupsd_printer_t *dest, + cupsd_job_t *job); +extern void cupsdLoadAllSubscriptions(void); +extern void cupsdSaveAllSubscriptions(void); +extern void cupsdSendNotification(cupsd_subscription_t *sub, + cupsd_event_t *event); +extern void cupsdStopAllNotifiers(void); +extern void cupsdUpdateNotifierStatus(void); + + +/* + * End of "$Id: subscriptions.h 4840 2005-11-14 21:53:30Z mike $". + */ diff --git a/scheduler/testdirsvc.c b/scheduler/testdirsvc.c new file mode 100644 index 000000000..51c2cc523 --- /dev/null +++ b/scheduler/testdirsvc.c @@ -0,0 +1,275 @@ +/* + * "$Id: testdirsvc.c 4821 2005-11-04 19:36:39Z mike $" + * + * Browsing test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Simulate one or more remote printers. + * usage() - Show program usage... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include + + +/* + * Local functions... + */ + +void usage(void); + + +/* + * 'main()' - Simulate one or more remote printers. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, /* Looping var */ + printer, /* Current printer */ + num_printers, /* Number of printers */ + server, /* Current server */ + num_servers, /* Number of servers */ + count, /* Number of printers sent this cycle */ + interval, /* Browse Interval */ + continuous, /* Run continuously? */ + port, /* Browse port */ + sock, /* Browse socket */ + val, /* Socket option value */ + seconds, /* Seconds until next cycle */ + verbose; /* Verbose output? */ + const char *options; /* Options for URIs */ + time_t curtime; /* Current UNIX time */ + struct tm *curdate; /* Current date and time */ + struct sockaddr_in addr; /* Broadcast address */ + char packet[1540]; /* Data packet */ + static const char * const names[26] = /* Printer names */ + { + "alpha", + "bravo", + "charlie", + "delta", + "echo", + "foxtrot", + "golf", + "hotel", + "india", + "juliet", + "kilo", + "lima", + "mike", + "november", + "oscar", + "papa", + "quebec", + "romeo", + "sierra", + "tango", + "uniform", + "victor", + "wiskey", + "x-ray", + "yankee", + "zulu" + }; + + + /* + * Process command-line arguments... + */ + + num_printers = 10; + num_servers = 1; + interval = 30; + port = 0; + verbose = 0; + continuous = 0; + options = NULL; + + for (i = 1; i < argc; i ++) + { + if (!strcmp(argv[i], "-c")) + continuous = 1; + if (!strcmp(argv[i], "-v")) + verbose = 1; + else if (!strcmp(argv[i], "-i")) + { + i ++; + if (i < argc) + interval = atoi(argv[i]); + else + usage(); + } + else if (!strcmp(argv[i], "-o")) + { + i ++; + if (i < argc) + options = argv[i]; + else + usage(); + } + else if (!strcmp(argv[i], "-p")) + { + i ++; + if (i < argc) + num_printers = atoi(argv[i]); + else + usage(); + } + else if (!strcmp(argv[i], "-s")) + { + i ++; + if (i < argc) + num_servers = atoi(argv[i]); + else + usage(); + } + else if (isdigit(argv[i][0] & 255)) + { + port = atoi(argv[i]); + } + else + usage(); + } + + if (num_printers <= 0 || num_servers <= 0 || interval <= 0 || port <= 0) + usage(); + + /* + * Open a broadcast socket... + */ + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + { + perror("Unable to open broadcast socket"); + return (1); + } + + /* + * Set the "broadcast" flag... + */ + + val = 1; + if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &val, sizeof(val))) + { + perror("Unable to put socket in broadcast mode"); + + close(sock); + return (1); + } + + /* + * 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); + + /* + * Send virtual printers continuously until we are stopped. + */ + + for (;;) + { + /* + * Start a new cycle of N printers... + */ + + printf("Sending %d printers from %d servers...\n", num_printers, + num_servers); + + count = num_servers * num_printers / interval + 1; + curtime = time(NULL); + curdate = localtime(&curtime); + seconds = interval; + + for (i = 0, printer = 0; printer < num_printers; printer ++) + { + for (server = 0; server < num_servers; server ++, i ++) + { + if (i == count) + { + seconds --; + i = 0; + sleep(1); + curtime = time(NULL); + curdate = localtime(&curtime); + } + + snprintf(packet, sizeof(packet), + "%x %x ipp://testserver-%d/printers/%s-%d \"Server Room %d\" " + "\"Test Printer %d\" \"Acme Blazer 2000\"%s%s\n", + CUPS_PRINTER_REMOTE, IPP_PRINTER_IDLE, server + 1, + names[printer % 26], printer / 26 + 1, server + 1, + printer + 1, options ? " ipp-options=" : "", + options ? options : ""); + + if (verbose) + printf("[%02d:%02d:%02d] %s", curdate->tm_hour, curdate->tm_min, + curdate->tm_sec, packet); + + if (sendto(sock, packet, strlen(packet), 0, + (struct sockaddr *)&addr, sizeof(addr)) < 0) + perror("Unabled to send packet"); + } + } + + if (!continuous) + break; + + /* + * Sleep for any remaining time... + */ + + if (seconds > 0) + sleep(seconds); + } + + return (0); +} + + +/* + * 'usage()' - Show program usage... + */ + +void +usage(void) +{ + puts("Usage: testdirsvc [-i interval] [-o ipp-options] [-p printers] [-s servers] [-v] port"); + exit(0); +} + + +/* + * End of "$Id: testdirsvc.c 4821 2005-11-04 19:36:39Z mike $". + */ diff --git a/scheduler/testmime.c b/scheduler/testmime.c new file mode 100644 index 000000000..e84dbd568 --- /dev/null +++ b/scheduler/testmime.c @@ -0,0 +1,246 @@ +/* + * "$Id: testmime.c 4719 2005-09-28 21:12:44Z mike $" + * + * MIME test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Main entry for the test program. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include "mime.h" + + +/* + * Local functions... + */ + +static void print_rules(mime_magic_t *rules); + + +/* + * 'main()' - Main entry for the test program. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line args */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, j; /* Looping vars */ + const char *filter_path; /* Filter path */ + char super[MIME_MAX_SUPER], /* Super-type name */ + type[MIME_MAX_TYPE]; /* Type name */ + int compression; /* Compression of file */ + 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 = NULL; + src = NULL; + dst = NULL; + filter_path = "../filter"; + + for (i = 1; i < argc; i ++) + if (strcmp(argv[i], "-d") == 0) + { + i ++; + + if (i < argc) + mime = mimeLoad(argv[i], filter_path); + } + else if (strcmp(argv[i], "-f") == 0) + { + i ++; + + if (i < argc) + filter_path = argv[i]; + } + else if (src == NULL) + { + if (!mime) + mime = mimeLoad("../conf", filter_path); + + src = mimeFileType(mime, argv[i], &compression); + + if (src != NULL) + printf("%s: %s/%s%s\n", argv[i], src->super, src->type, + compression ? " (gzipped)" : ""); + else + { + printf("%s: unknown\n", argv[i]); + if (mime) + mimeDelete(mime); + return (1); + } + } + else + { + sscanf(argv[i], "%15[^/]/%31s", super, type); + dst = mimeType(mime, super, type); + + filters = mimeFilter(mime, src, dst, &num_filters, 10); + + if (filters == NULL) + { + printf("No filters to convert from %s/%s to %s.\n", src->super, + src->type, argv[i]); + } + else + { + for (j = 0; j < num_filters; j ++) + if (j < (num_filters - 1)) + printf("%s | ", filters[j].filter); + else + puts(filters[j].filter); + + free(filters); + } + } + + if (!mime) + mime = mimeLoad("../conf", filter_path); + + if (src == NULL) + { + 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); + } + + 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: testmime.c 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/testspeed.c b/scheduler/testspeed.c new file mode 100644 index 000000000..376ae1a03 --- /dev/null +++ b/scheduler/testspeed.c @@ -0,0 +1,305 @@ +/* + * "$Id: testspeed.c 4800 2005-10-18 18:06:20Z mike $" + * + * Scheduler speed test for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Send multiple IPP requests and report on the average response + * time. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +int do_test(const char *server, http_encryption_t encryption, + int requests, int verbose); +void usage(void); + + +/* + * '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 */ + const char *server; /* Server to use */ + http_encryption_t encryption; /* Encryption to use */ + int requests; /* Number of requests to send */ + int children; /* Number of children to fork */ + int pid; /* Child PID */ + int status; /* Child status */ + time_t start, /* Start time */ + end; /* End time */ + double elapsed; /* Elapsed time */ + int verbose; /* Verbosity */ + + + /* + * Parse command-line options... + */ + + requests = 100; + children = 5; + server = cupsServer(); + encryption = HTTP_ENCRYPT_IF_REQUESTED; + verbose = 0; + + for (i = 1; i < argc; i ++) + if (!strcmp(argv[i], "-c")) + { + i ++; + if (i >= argc) + usage(); + + children = atoi(argv[i]); + } + else if (!strcmp(argv[i], "-r")) + { + i ++; + if (i >= argc) + usage(); + + requests = atoi(argv[i]); + } + else if (!strcmp(argv[i], "-E")) + encryption = HTTP_ENCRYPT_REQUIRED; + else if (!strcmp(argv[i], "-v")) + verbose ++; + else if (argv[i][0] == '-') + usage(); + else + server = argv[i]; + + /* + * Then create child processes to act as clients... + */ + + printf("testspeed: Simulating %d clients with %d requests to %s with %s encryption...\n", + children, requests, server, + encryption == HTTP_ENCRYPT_IF_REQUESTED ? "no" : ""); + + start = time(NULL); + + if (children == 1) + { + do_test(server, encryption, requests, verbose); + } + else + { + for (i = 0; i < children; i ++) + if ((pid = fork()) == 0) + { + /* + * Child goes here... + */ + + exit(do_test(server, encryption, requests, verbose)); + } + else if (pid < 0) + { + perror("fork failed"); + break; + } + else + printf("testspeed(%d): Started...\n", pid); + + /* + * Wait for children to finish... + */ + + for (;;) + { + pid = wait(&status); + + if (pid < 0 && errno != EINTR) + break; + + printf("testspeed(%d): Ended (%d)...\n", pid, status); + } + } + + /* + * Compute the total run time... + */ + + end = time(NULL); + elapsed = end - start; + i = children * requests; + + printf("testspeed: %dx%d=%d requests in %.1fs (%.3fs/r, %.1fr/s)\n", + children, requests, i, elapsed, elapsed / i, i / elapsed); + + /* + * Exit with no errors... + */ + + return (status); +} + + +/* + * 'do_test()' - Run a test on a specific host... + */ + +int /* O - Exit status */ +do_test(const char *server, /* I - Server to use */ + http_encryption_t encryption, /* I - Encryption to use */ + int requests, /* I - Number of requests to send */ + int verbose) /* I - Verbose output? */ +{ + 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 */ + static ipp_op_t ops[4] = /* Operations to test... */ + { + IPP_PRINT_JOB, + CUPS_GET_PRINTERS, + CUPS_GET_CLASSES, + IPP_GET_JOBS + }; + + + /* + * Connect to the server... + */ + + http = httpConnectEncrypt(server, ippPort(), encryption); + + if (http == NULL) + { + perror("testspeed: unable to connect to server"); + return (1); + } + + language = cupsLangDefault(); + + /* + * Do multiple requests... + */ + + for (elapsed = 0.0, i = 0; i < requests; i ++) + { + if (verbose && (i % 10) == 0) + printf("testspeed(%d): %d%% complete...\n", (int)getpid(), + i * 100 / requests); + + /* + * Build a request which requires the following attributes: + * + * attributes-charset + * attributes-natural-language + * + * In addition, IPP_GET_JOBS needs a printer-uri attribute. + */ + + request = ippNew(); + + request->request.op.operation_id = ops[i & 3]; + 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); + + switch (request->request.op.operation_id) + { + case IPP_GET_JOBS : + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/printers/"); + + default : + response = cupsDoRequest(http, request, "/"); + break; + + case IPP_PRINT_JOB : + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", + NULL, "ipp://localhost/printers/test"); + response = cupsDoFileRequest(http, request, "/printers/test", + "../data/testprint.ps"); + break; + } + + gettimeofday(&end, NULL); + + if (response != NULL) + ippDelete(response); + + elapsed += (end.tv_sec - start.tv_sec) + + 0.000001 * (end.tv_usec - start.tv_usec); + } + + cupsLangFree(language); + httpClose(http); + + printf("testspeed(%d): %d requests in %.1fs (%.3fs/r, %.1fr/s)\n", + (int)getpid(), i, elapsed, elapsed / i, i / elapsed); + + return (0); +} + + +/* + * 'usage()' - Show program usage... + */ + +void +usage(void) +{ + puts("Usage: testspeed [-c children] [-h] [-r requests] [-v] [-E] hostname"); + exit(0); +} + + + +/* + * End of "$Id: testspeed.c 4800 2005-10-18 18:06:20Z mike $". + */ diff --git a/scheduler/type.c b/scheduler/type.c new file mode 100644 index 000000000..fbfcb07a3 --- /dev/null +++ b/scheduler/type.c @@ -0,0 +1,1165 @@ +/* + * "$Id: type.c 4613 2005-08-30 12:41:48Z mike $" + * + * MIME typing routines for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * mimeAddType() - Add a MIME type to a database. + * mimeAddTypeRule() - Add a detection rule for a file type. + * mimeFileType() - Determine the type of a file. + * mimeType() - Lookup a file type. + * compare() - Compare two MIME super/type names. + * checkrules() - Check each rule in a list. + * patmatch() - Pattern matching... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include + +#include +#include "mime.h" +#include + + +/* + * Local functions... + */ + +static int compare(mime_type_t **, mime_type_t **); +static int checkrules(const char *, cups_file_t *, 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; + strlcpy(temp->super, super, sizeof(temp->super)); + if ((temp->type = strdup(type)) == NULL) + { + mime->num_types --; + return (NULL); + } + + if (mime->num_types > 1) + qsort(mime->types, mime->num_types, sizeof(mime_type_t *), + (int (*)(const void *, const void *))compare); + + return (temp); +} + + +/* + * 'mimeAddTypeRule()' - 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 & 255)) + 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 & 255)) + { + /* + * Read an extension name or a function... + */ + + for (ptr = name; isalnum(*rule & 255) && (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 & 255)) + { + /* + * 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] & 255) && isxdigit(rule[1] & 255)) + { + 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, "istring") == 0) + op = MIME_MAGIC_ISTRING; + 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 : + case MIME_MAGIC_ISTRING : + 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 = (char)strtol(value[1], NULL, 0); + break; + case MIME_MAGIC_SHORT : + temp->offset = strtol(value[0], NULL, 0); + temp->value.shortv = (short)strtol(value[1], NULL, 0); + break; + case MIME_MAGIC_INT : + temp->offset = strtol(value[0], NULL, 0); + temp->value.intv = (int)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 *compression) /* O - Is the file compressed? */ +{ + int i; /* Looping var */ + cups_file_t *fp; /* File pointer */ + mime_type_t **types; /* File types */ + const char *filename; /* Base filename of file */ + + + DEBUG_printf(("mimeFileType(mime=%p, pathname=\"%s\", compression=%p)\n", + mime, pathname ? pathname : "(nil)", compression)); + + /* + * Range check input parameters... + */ + + if (mime == NULL || pathname == NULL) + return (NULL); + + /* + * Try to open the file... + */ + + if ((fp = cupsFileOpen(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)... + */ + + if (compression) + *compression = cupsFileCompression(fp); + + cupsFileClose(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... + */ + + strlcpy(key.super, super, sizeof(key.super)); + key.type = (char *)type; + + keyptr = &key; + + match = (mime_type_t **)bsearch(&keyptr, mime->types, mime->num_types, + sizeof(mime_type_t *), + (int (*)(const void *, const void *))compare); + + if (match == NULL) + return (NULL); + else + return (*match); +} + + +/* + * 'compare()' - Compare two MIME super/type names. + */ + +static int /* O - Result of comparison */ +compare(mime_type_t **t0, /* I - First type */ + mime_type_t **t1) /* I - Second type */ +{ + int i; /* Result of comparison */ + + + if ((i = strcasecmp((*t0)->super, (*t1)->super)) == 0) + i = strcasecmp((*t0)->type, (*t1)->type); + + return (i); +} + + +/* + * 'checkrules()' - Check each rule in a list. + */ + +static int /* O - 1 if match, 0 if no match */ +checkrules(const char *filename, /* I - Filename */ + cups_file_t *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 */ +#ifdef DEBUG + const char * const debug_tests[] = /* Test names... */ + { + "NOP", /* No operation */ + "AND", /* Logical AND of all children */ + "OR", /* Logical OR of all children */ + "MATCH", /* Filename match */ + "ASCII", /* ASCII characters in range */ + "PRINTABLE", /* Printable characters (32-255) in range */ + "STRING", /* String matches */ + "CHAR", /* Character/byte matches */ + "SHORT", /* Short/16-bit word matches */ + "INT", /* Integer/32-bit word matches */ + "LOCALE" /* Current locale matches string */ + "CONTAINS" /* File contains a string */ + "ISTRING" /* Case-insensitive string matches */ + }; +#endif /* DEBUG */ + + + DEBUG_printf(("checkrules(filename=\"%s\", fp=%p, rules=%p)\n", filename, + fp, rules)); + + 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... + */ + + cupsFileSeek(fp, rules->offset); + buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer)); + 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... + */ + + cupsFileSeek(fp, rules->offset); + buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer)); + 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 : + DEBUG_printf((" string(%d, \"%s\")\n", rules->offset, + rules->value.stringv)); + + /* + * Load the buffer if necessary... + */ + + if (bufoffset < 0 || rules->offset < bufoffset || + (rules->offset + rules->length) > (bufoffset + buflength)) + { + /* + * Reload file buffer... + */ + + cupsFileSeek(fp, rules->offset); + buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer)); + bufoffset = rules->offset; + + DEBUG_printf((" loaded %d byte buffer at %d, starts with \"%c%c%c%c\"...\n", + buflength, bufoffset, buffer[0], buffer[1], + buffer[2], buffer[3])); + } + + /* + * 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); + DEBUG_printf((" result=%d\n", result)); + break; + + case MIME_MAGIC_ISTRING : + /* + * Load the buffer if necessary... + */ + + if (bufoffset < 0 || rules->offset < bufoffset || + (rules->offset + rules->length) > (bufoffset + buflength)) + { + /* + * Reload file buffer... + */ + + cupsFileSeek(fp, rules->offset); + buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer)); + 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 = (strncasecmp((char *)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... + */ + + cupsFileSeek(fp, rules->offset); + buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer)); + 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... + */ + + cupsFileSeek(fp, rules->offset); + buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer)); + 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... + */ + + cupsFileSeek(fp, rules->offset); + buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer)); + 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 : +#if defined(WIN32) || defined(__EMX__) || defined(__APPLE__) + result = (strcmp(rules->value.localev, setlocale(LC_ALL, "")) == 0); +#else + result = (strcmp(rules->value.localev, setlocale(LC_MESSAGES, "")) == 0); +#endif /* __APPLE__ */ + 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... + */ + + cupsFileSeek(fp, rules->offset); + buflength = cupsFileRead(fp, (char *)buffer, sizeof(buffer)); + 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 (MIME_MAGIC_%s) is %d\n", rules, + debug_tests[rules->op], 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: type.c 4613 2005-08-30 12:41:48Z mike $". + */ diff --git a/scheduler/util.c b/scheduler/util.c new file mode 100644 index 000000000..b76826f0a --- /dev/null +++ b/scheduler/util.c @@ -0,0 +1,279 @@ +/* + * "$Id: util.c 4719 2005-09-28 21:12:44Z mike $" + * + * Mini-daemon utility functions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * cupsdCompareNames() - Compare two names. + * cupsdSendIPPGroup() - Send a group tag. + * cupsdSendIPPHeader() - Send the IPP response header. + * cupsdSendIPPInteger() - Send an integer attribute. + * cupsdSendIPPString() - Send a string attribute. + * cupsdSendIPPTrailer() - Send the end-of-message tag. + */ + +/* + * Include necessary headers... + */ + +#include "util.h" + + +/* + * 'cupsdCompareNames()' - Compare two names. + * + * This function basically does a strcasecmp() of the two strings, + * but is also aware of numbers so that "a2" < "a100". + */ + +int /* O - Result of comparison */ +cupsdCompareNames(const char *s, /* I - First string */ + const char *t) /* I - Second string */ +{ + int diff, /* Difference between digits */ + digits; /* Number of digits */ + + + /* + * Loop through both names, returning only when a difference is + * seen. Also, compare whole numbers rather than just characters, too! + */ + + while (*s && *t) + { + if (isdigit(*s & 255) && isdigit(*t & 255)) + { + /* + * Got a number; start by skipping leading 0's... + */ + + while (*s == '0') + s ++; + while (*t == '0') + t ++; + + /* + * Skip equal digits... + */ + + while (isdigit(*s & 255) && *s == *t) + { + s ++; + t ++; + } + + /* + * Bounce out if *s and *t aren't both digits... + */ + + if (isdigit(*s & 255) && !isdigit(*t & 255)) + return (1); + else if (!isdigit(*s & 255) && isdigit(*t & 255)) + return (-1); + else if (!isdigit(*s & 255) || !isdigit(*t & 255)) + continue; + + if (*s < *t) + diff = -1; + else + diff = 1; + + /* + * Figure out how many more digits there are... + */ + + digits = 0; + s ++; + t ++; + + while (isdigit(*s & 255)) + { + digits ++; + s ++; + } + + while (isdigit(*t & 255)) + { + 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 (0); +} + + +/* + * 'cupsdSendIPPGroup()' - Send a group tag. + */ + +void +cupsdSendIPPGroup(ipp_tag_t group_tag) /* I - Group tag */ +{ + /* + * Send IPP group tag (1 byte)... + */ + + putchar(group_tag); +} + + +/* + * 'cupsdSendIPPHeader()' - Send the IPP response header. + */ + +void +cupsdSendIPPHeader( + ipp_status_t status_code, /* I - Status code */ + int request_id) /* I - Request ID */ +{ + /* + * Send IPP/1.1 response header: version number (2 bytes), status code + * (2 bytes), and request ID (4 bytes)... + */ + + putchar(1); + putchar(1); + + putchar(status_code >> 8); + putchar(status_code); + + putchar(request_id >> 24); + putchar(request_id >> 16); + putchar(request_id >> 8); + putchar(request_id); +} + + +/* + * 'cupsdSendIPPInteger()' - Send an integer attribute. + */ + +void +cupsdSendIPPInteger( + ipp_tag_t value_tag, /* I - Value tag */ + const char *name, /* I - Attribute name */ + int value) /* I - Attribute value */ +{ + size_t len; /* Length of attribute name */ + + + /* + * Send IPP integer value: value tag (1 byte), name length (2 bytes), + * name string (without nul), and value (4 bytes)... + */ + + putchar(value_tag); + + len = strlen(name); + putchar(len >> 8); + putchar(len); + + fputs(name, stdout); + + putchar(value >> 24); + putchar(value >> 16); + putchar(value >> 8); + putchar(value); +} + + +/* + * 'cupsdSendIPPString()' - Send a string attribute. + */ + +void +cupsdSendIPPString( + ipp_tag_t value_tag, /* I - Value tag */ + const char *name, /* I - Attribute name */ + const char *value) /* I - Attribute value */ +{ + size_t len; /* Length of attribute name */ + + + /* + * Send IPP string value: value tag (1 byte), name length (2 bytes), + * name string (without nul), value length (2 bytes), and value string + * (without nul)... + */ + + putchar(value_tag); + + len = strlen(name); + putchar(len >> 8); + putchar(len); + + fputs(name, stdout); + + len = strlen(value); + putchar(len >> 8); + putchar(len); + + fputs(value, stdout); +} + + +/* + * 'cupsdSendIPPTrailer()' - Send the end-of-message tag. + */ + +void +cupsdSendIPPTrailer(void) +{ + putchar(IPP_TAG_END); + fflush(stdout); +} + + +/* + * End of "$Id: util.c 4719 2005-09-28 21:12:44Z mike $". + */ diff --git a/scheduler/util.h b/scheduler/util.h new file mode 100644 index 000000000..e08a3d73d --- /dev/null +++ b/scheduler/util.h @@ -0,0 +1,59 @@ +/* + * "$Id: util.h 4598 2005-08-25 21:36:26Z mike $" + * + * Mini-daemon utility definitions for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPSD_UTIL_H_ +# define _CUPSD_UTIL_H_ + +/* + * Include necessary headers... + */ + +# include +# include +# include +# include +# include +# include +# include + + +/* + * Prototypes... + */ + +extern int cupsdCompareNames(const char *s, const char *t); +extern void cupsdSendIPPGroup(ipp_tag_t group_tag); +extern void cupsdSendIPPHeader(ipp_status_t status_code, int request_id); +extern void cupsdSendIPPInteger(ipp_tag_t value_tag, const char *name, + int value); +extern void cupsdSendIPPString(ipp_tag_t value_tag, const char *name, + const char *value); +extern void cupsdSendIPPTrailer(void); + + +#endif /* !_CUPSD_UTIL_H_ */ + +/* + * End of "$Id: util.h 4598 2005-08-25 21:36:26Z mike $". + */ diff --git a/scripting/java/CUPSPrinter.java b/scripting/java/CUPSPrinter.java new file mode 100644 index 000000000..a6d7a3075 --- /dev/null +++ b/scripting/java/CUPSPrinter.java @@ -0,0 +1,438 @@ +// +import java.io.*; +import java.net.*; +import java.util.*; + +public class CUPSPrinter +{ + String printer_name; + String printer_location; + String printer_info; + String printer_more_info; + + String[] printer_uri_supported; // Strings + String[] uri_authentication_supported; // Strings + String[] uri_security_supported; // Strings + + String attributes_charset; + String attributes_natural_language; + + int printer_state; + String printer_state_reasons; + + boolean printer_is_accepting_jobs; + + long printer_up_time; + long printer_current_time; + + int queued_job_count; + + String[] pdl_override_supported; + String[] ipp_versions_supported; + + int[] operations_supported; // Integers + + boolean multiple_document_jobs_supported; + int multiple_operation_time_out; + int[] multiple_document_handling_supported; // Integers + + String charset_configured; + String natural_language_configured; + String generated_natural_language_supported; + String[] charset_supported; // Strings + + String document_format_default; + String[] document_format_supported; // Strings + + String[] compression_supported; // Strings + + int job_priority_default; + int job_priority_supported; + + int copies_default; + int lower_copies_supported; + int upper_copies_supported; + + boolean page_ranges_supported; + + int number_up_default; + int[] number_up_supported; // integers + + + int orientation_requested_default; + int[] orientation_requested_supported; // Integers + + int job_quota_period; + int job_k_limit; + int job_page_limit; + + String job_sheets_default; // Should this be a list too? + String[] job_sheets_supported; // Strings + + String device_uri; + + boolean color_supported; + int pages_per_minute; + + String printer_make_and_model; + + String media_default; + String[] media_supported; // Strings + + int finishings_default; + int[] finishings_supported; // Integers + + int printer_type; + + + + // --------------------------------------------- + // + // Basic constructor. + // + public CUPSPrinter() + { + } + + + + + // --------------------------------------------- + // + // Move the attributes from an ipp request + // into a CUPSPrinter object. + // + public void updateAttribute( IPPAttribute a ) + { + IPPValue v; + int i; + + + if (a.name.compareTo("printer-name") == 0) + { + v = (IPPValue)a.values.get(0); + printer_name = v.text; + } + else if (a.name.compareTo("printer-location") == 0) + { + v = (IPPValue)a.values.get(0); + printer_location = v.text; + } + else if (a.name.compareTo("printer-info") == 0) + { + v = (IPPValue)a.values.get(0); + printer_info = v.text; + } + else if (a.name.compareTo("printer-more-info") == 0) + { + v = (IPPValue)a.values.get(0); + printer_more_info = v.text; + } + else if (a.name.compareTo("printer-uri-supported") == 0) + { + printer_uri_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + printer_uri_supported[i] = v.text; + } + } + else if (a.name.compareTo("uri-authentication-supported") == 0) + { + uri_authentication_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + uri_authentication_supported[i] = v.text; + } + } + else if (a.name.compareTo("uri-security-supported") == 0) + { + uri_security_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + uri_security_supported[i] = v.text; + } + } + else if (a.name.compareTo("attributes-charset") == 0) + { + v = (IPPValue)a.values.get(0); + attributes_charset = v.text; + } + else if (a.name.compareTo("attributes-natural-language") == 0) + { + v = (IPPValue)a.values.get(0); + attributes_natural_language = v.text; + } + else if (a.name.compareTo("printer-state") == 0) + { + v = (IPPValue)a.values.get(0); + printer_state = v.integer_value; + } + else if (a.name.compareTo("printer-state-reasons") == 0) + { + v = (IPPValue)a.values.get(0); + printer_state_reasons = v.text; + } + else if (a.name.compareTo("printer-is-accepting-jobs") == 0) + { + v = (IPPValue)a.values.get(0); + printer_is_accepting_jobs = v.boolean_value; + } + else if (a.name.compareTo("printer-up-time") == 0) + { + v = (IPPValue)a.values.get(0); + printer_up_time = v.integer_value; + } + else if (a.name.compareTo("printer-current-time") == 0) + { + v = (IPPValue)a.values.get(0); + printer_current_time = v.unix_time; // *** FIX *** + } + else if (a.name.compareTo("queue-job-count") == 0) + { + v = (IPPValue)a.values.get(0); + queued_job_count = v.integer_value; + } + else if (a.name.compareTo("pdl-override-supported") == 0) + { + pdl_override_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + pdl_override_supported[i] = v.text; + } + } + else if (a.name.compareTo("ipp-versions-supported") == 0) + { + ipp_versions_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + ipp_versions_supported[i] = v.text; + } + } + else if (a.name.compareTo("operations-supported") == 0) + { + operations_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + operations_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("multiple-document-jobs-supported") == 0) + { + v = (IPPValue)a.values.get(0); + multiple_document_jobs_supported = v.boolean_value; + } + else if (a.name.compareTo("multiple-operation-time-out") == 0) + { + v = (IPPValue)a.values.get(0); + multiple_operation_time_out = v.integer_value; + } + else if (a.name.compareTo("multiple-document-handling-supported") == 0) + { + multiple_document_handling_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + multiple_document_handling_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("charset-configured") == 0) + { + v = (IPPValue)a.values.get(0); + charset_configured = v.text; + } + else if (a.name.compareTo("natural-language-configured") == 0) + { + v = (IPPValue)a.values.get(0); + natural_language_configured = v.text; + } + else if (a.name.compareTo("generated-natural-language-supported") == 0) + { + // *** Should this be a list too? + v = (IPPValue)a.values.get(0); + generated_natural_language_supported = v.text; + } + else if (a.name.compareTo("charset-supported") == 0) + { + charset_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + charset_supported[i] = v.text; + } + } + else if (a.name.compareTo("document-format-default") == 0) + { + v = (IPPValue)a.values.get(0); + document_format_default = v.text; + } + else if (a.name.compareTo("document-format-supported") == 0) + { + document_format_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + document_format_supported[i] = v.text; + } + } + else if (a.name.compareTo("compression-supported") == 0) + { + compression_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + compression_supported[i] = v.text; + } + } + else if (a.name.compareTo("job-priority-default") == 0) + { + v = (IPPValue)a.values.get(0); + job_priority_default = v.integer_value; + } + else if (a.name.compareTo("job-priority-supported") == 0) + { + // *** Should be a list? *** + v = (IPPValue)a.values.get(0); + job_priority_supported = v.integer_value; + } + else if (a.name.compareTo("copies-default") == 0) + { + v = (IPPValue)a.values.get(0); + copies_default = v.integer_value; + } + else if (a.name.compareTo("copies-supported") == 0) + { + v = (IPPValue)a.values.get(0); + lower_copies_supported = v.lower; + upper_copies_supported = v.upper; + } + else if (a.name.compareTo("page-ranges-supported") == 0) + { + v = (IPPValue)a.values.get(0); + page_ranges_supported = v.boolean_value; + } + else if (a.name.compareTo("number-up-default") == 0) + { + v = (IPPValue)a.values.get(0); + number_up_default = v.integer_value; + } + else if (a.name.compareTo("number-up-supported") == 0) + { + number_up_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + number_up_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("orientation-requested-default") == 0) + { + v = (IPPValue)a.values.get(0); + orientation_requested_default = v.integer_value; + } + else if (a.name.compareTo("orientation-requested-supported") == 0) + { + orientation_requested_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + orientation_requested_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("job-quota-period") == 0) + { + v = (IPPValue)a.values.get(0); + job_quota_period = v.integer_value; + } + else if (a.name.compareTo("job-k-limit") == 0) + { + v = (IPPValue)a.values.get(0); + job_k_limit = v.integer_value; + } + else if (a.name.compareTo("job-page-limit") == 0) + { + v = (IPPValue)a.values.get(0); + job_page_limit = v.integer_value; + } + else if (a.name.compareTo("job-sheets-default") == 0) + { + v = (IPPValue)a.values.get(0); + job_sheets_default = v.text; + } + else if (a.name.compareTo("job-sheets-supported") == 0) + { + job_sheets_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + job_sheets_supported[i] = v.text; + } + } + else if (a.name.compareTo("device-uri") == 0) + { + v = (IPPValue)a.values.get(0); + device_uri = v.text; + } + else if (a.name.compareTo("color-supported") == 0) + { + v = (IPPValue)a.values.get(0); + color_supported = v.boolean_value; + } + else if (a.name.compareTo("pages-per-minute") == 0) + { + v = (IPPValue)a.values.get(0); + pages_per_minute = v.integer_value; + } + else if (a.name.compareTo("printer-make-and-model") == 0) + { + v = (IPPValue)a.values.get(0); + printer_make_and_model = v.text; + } + else if (a.name.compareTo("media-default") == 0) + { + v = (IPPValue)a.values.get(0); + media_default = v.text; + } + else if (a.name.compareTo("media-supported") == 0) + { + media_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + media_supported[i] = v.text; + } + } + else if (a.name.compareTo("finishings-default") == 0) + { + v = (IPPValue)a.values.get(0); + finishings_default = v.integer_value; + } + else if (a.name.compareTo("finishings-supported") == 0) + { + finishings_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + finishings_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("printer-type") == 0) + { + v = (IPPValue)a.values.get(0); + printer_type = v.integer_value; + } + + } // End of updateAttribute() + + + + + +} // End of CUPSPrinter class + + diff --git a/scripting/java/classes/com/easysw/cups/Cups.class b/scripting/java/classes/com/easysw/cups/Cups.class new file mode 100644 index 0000000000000000000000000000000000000000..e259d5b73c89dabaf93489e005399bd5e3d092c6 GIT binary patch literal 12601 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 Xtv&zOXB=e0Ot^-6gum!l_P_oYPC)mT literal 0 Hc-jL100001 diff --git a/scripting/java/classes/com/easysw/cups/CupsJob.class b/scripting/java/classes/com/easysw/cups/CupsJob.class new file mode 100644 index 0000000000000000000000000000000000000000..8d3a55ceec42b054742fd69b413480fb1c4b8e5b GIT binary patch literal 2830 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 G)Bgb)><26W literal 0 Hc-jL100001 diff --git a/scripting/java/classes/com/easysw/cups/IPP.class b/scripting/java/classes/com/easysw/cups/IPP.class new file mode 100644 index 0000000000000000000000000000000000000000..4519d4d0f9b37d288091a1cd6080e0382e2abd68 GIT binary patch literal 2100 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 GZT%D8v`e%A literal 0 Hc-jL100001 diff --git a/scripting/java/classes/com/easysw/cups/IPPCalendar.class b/scripting/java/classes/com/easysw/cups/IPPCalendar.class new file mode 100644 index 0000000000000000000000000000000000000000..cc47184593a3bed74aa2eb17e67aaa45de5909a3 GIT binary patch literal 382 zc-mc$&q~8U5XQev(nMpl)mASehzHRg8t)Y^1tp?VuzKI7OIg`$B!8;DK_5mBUKBj| z06vLNAx>5;(uMtI_~th|J0D+f?*Ka3@Zn*tlBN$A%^J+HKRvWOtTVWWQp@6q!QR`y zW^j7xNHEmTq!t%tG8EZ>4^`!iMKO?xi1fKsO6I2FlwpbdD=qJOhJSZlw6JySw|Bz29sOG<-hs5L{ar#bY1bOrTabO(-c{q_s& R7Mx`IILCKM8x$?9egnUELDB#K literal 0 Hc-jL100001 diff --git a/scripting/java/classes/com/easysw/cups/IPPDefs.class b/scripting/java/classes/com/easysw/cups/IPPDefs.class new file mode 100644 index 0000000000000000000000000000000000000000..879dbe95b6a1b69d5307822b40644970bfd53baa GIT binary patch literal 7640 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 LqcM;z=Q{L%)8VW! literal 0 Hc-jL100001 diff --git a/scripting/java/classes/com/easysw/cups/IPPError.class b/scripting/java/classes/com/easysw/cups/IPPError.class new file mode 100644 index 0000000000000000000000000000000000000000..853b8d031403f3b22dcc79f92acc50155d3b77c8 GIT binary patch literal 2663 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 literal 0 Hc-jL100001 diff --git a/scripting/java/classes/com/easysw/cups/IPPURLConnection.class b/scripting/java/classes/com/easysw/cups/IPPURLConnection.class new file mode 100644 index 0000000000000000000000000000000000000000..6293c62d5377aaec0a3c4ae996afaf7dda77aa78 GIT binary patch literal 413 zc-n=J&q~8U5XQerVxnucR#4EBdTJFK>b2q}Ac#SN{|?^LbdeRiE7?TtJ9+UWc<=#y zC~=aOTD-W2Z+5=<&CKrC_s1uIF4hHHGy|*!Xc7D)rB!iEXtm?}^eGLsEW+!HxZk-U zc##=OLNiuco|mJ6%&*eH13RL$O5Y{9c^MPjcITE5WJYV56?M+NVyNuQ5|^gTGkKz_ z=8e-N;SJHGsEqDbiyQE;K-kI5D3qxk+vhMVA8q&-CTz~X^S6LqIQ+Bfc%W(;tIydU z`wmBc|KJ_;#y5T~tEk-`bBF9KVrj~6b0m(A`#NL&+Uc_jEKj+ux{CRc6D(qF{EwZn Ju2g%l`U9e2Mw?)k=XcJT&pGEi=ibl% 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 Su5YpYU!TaYUr*z|t^Nk|GN*C? literal 0 Hc-jL100001 diff --git a/scripting/java/docs/allclasses-frame.html b/scripting/java/docs/allclasses-frame.html new file mode 100644 index 000000000..fd8f6a4f3 --- /dev/null +++ b/scripting/java/docs/allclasses-frame.html @@ -0,0 +1,49 @@ + + + + + + +All Classes + + + + + +All Classes +
    + + + + + +
    Cups +
    +CupsJob +
    +CupsPrinter +
    +IPP +
    +IPPAttribute +
    +IPPDefs +
    +IPPError +
    +IPPHttp +
    +IPPMD5 +
    +IPPRequest +
    +IPPStatus +
    +IPPURLConnection +
    +IPPValue +
    +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/Cups.html b/scripting/java/docs/com/easysw/cups/Cups.html new file mode 100644 index 000000000..77f25a7f1 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/Cups.html @@ -0,0 +1,600 @@ + + + + + + +: Class Cups + + + + + + +
    + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class Cups

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.Cups
    +
    +
    +
    +
    public class Cups
    extends java.lang.Object
    + +

    +


    + +

    + + + + + + + + + + + + + + + + + + + +
    +Constructor Summary
    Cups() + +
    +          Void constructor.
    Cups(java.net.URL p_url) + +
    +          Constructor using a URL.
    +  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Method Summary
    + intcupsCancelJob(java.lang.String printer_name, + int p_job_id, + java.lang.String p_user_name) + +
    +          Cancel a job - send a job cancel request to the server.
    + java.lang.StringcupsGetDefault() + +
    +          Get default destination.
    + CupsJob[]cupsGetJobs(boolean showMyJobs, + boolean showCompleted) + +
    +          Get a list of jobs.
    + java.util.ListcupsGetPrinterAttributes(java.lang.String printer_name) + +
    +          Get printer attributes
    + java.lang.String[]cupsGetPrinters() + +
    +          Get a list of printers.
    + java.util.ListcupsGetPrinterStatus(java.lang.String printer_name) + +
    +           
    + CupsJobcupsPrintFile(java.lang.String p_filename, + IPPAttribute[] p_attrs) + +
    +          Print a file.
    + booleandoRequest() + +
    +          Do a CUPS request to the server.
    + booleandoRequest(java.io.File file) + +
    +          Send a FILE to the CUPS server.
    + booleandoRequest(java.lang.String from) + +
    +           
    + booleangetEncrypt() + +
    +          Get the value of the encrypt member.
    + voidsetDest(java.lang.String p_dest) + +
    +          Set the value of the dest member.
    + voidsetEncrypt(boolean p_encrypt) + +
    +          Set the value of the encrypt member.
    + voidsetInstance(java.lang.String p_instance) + +
    +          Set the value of the instance member.
    + voidsetPasswd(java.lang.String p_passwd) + +
    +          Set the value of the passwd member.
    + voidsetPath(java.lang.String p_path) + +
    +          Set the value of the path member.
    + voidsetPort(int p_port) + +
    +          Set the value of the port member.
    + voidsetProtocol(java.lang.String p_protocol) + +
    +          Set the value of the protocol member.
    + voidsetServer(java.lang.String p_server) + +
    +          Set the value of the server member.
    + voidsetUser(java.lang.String p_user) + +
    +          Set the value of the user member.
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + + + + +
    +Constructor Detail
    + +

    +Cups

    +
    +public Cups()
    +
    +
    Void constructor.
    +
    + +

    +Cups

    +
    +public Cups(java.net.URL p_url)
    +
    +
    Constructor using a URL.
    +
    Parameters:
    p_url - A URL object.
    +
    +
    + + + + + + + + +
    +Method Detail
    + +

    +setProtocol

    +
    +public void setProtocol(java.lang.String p_protocol)
    +
    +
    Set the value of the protocol member. Valid values + are ipp or http.
    +
    Parameters:
    p_protocol - String with protocol.
    +
    +
    +
    + +

    +setServer

    +
    +public void setServer(java.lang.String p_server)
    +
    +
    Set the value of the server member. This is an + IP address or a hostname.
    +
    Parameters:
    p_server - IP address or hostname.
    +
    +
    +
    + +

    +setPort

    +
    +public void setPort(int p_port)
    +
    +
    Set the value of the port member.
    +
    Parameters:
    p_port - Port number.
    +
    +
    +
    + +

    +setUser

    +
    +public void setUser(java.lang.String p_user)
    +
    +
    Set the value of the user member.
    +
    Parameters:
    p_user - User name.
    +
    +
    +
    + +

    +setPasswd

    +
    +public void setPasswd(java.lang.String p_passwd)
    +
    +
    Set the value of the passwd member.
    +
    Parameters:
    p_passwd - Password.
    +
    +
    +
    + +

    +setDest

    +
    +public void setDest(java.lang.String p_dest)
    +
    +
    Set the value of the dest member.
    +
    Parameters:
    p_dest - Destination.
    +
    +
    +
    + +

    +setInstance

    +
    +public void setInstance(java.lang.String p_instance)
    +
    +
    Set the value of the instance member.
    +
    Parameters:
    p_instance - Instance.
    +
    +
    +
    + +

    +setEncrypt

    +
    +public void setEncrypt(boolean p_encrypt)
    +
    +
    Set the value of the encrypt member.
    +
    Parameters:
    p_enrypt - Yes or no.
    +
    +
    +
    + +

    +getEncrypt

    +
    +public boolean getEncrypt()
    +
    +
    Get the value of the encrypt member.
    +
    Returns:
    boolean Encryption on or off.
    +
    +
    +
    + +

    +setPath

    +
    +public void setPath(java.lang.String p_path)
    +
    +
    Set the value of the path member. This is the + path that will be used in the POST method.
    +
    Parameters:
    p_path - Path on server.
    +
    +
    +
    + +

    +doRequest

    +
    +public boolean doRequest(java.lang.String from)
    +                  throws java.io.IOException
    +
    +
    +
    + +

    +doRequest

    +
    +public boolean doRequest()
    +                  throws java.io.IOException
    +
    +
    Do a CUPS request to the server.
    +
    Parameters:
    p_dest - Destination name.
    Returns:
    boolean True on success, false otherwise
    +
    +
    +
    + +

    +doRequest

    +
    +public boolean doRequest(java.io.File file)
    +                  throws java.io.IOException
    +
    +
    Send a FILE to the CUPS server.
    +
    Parameters:
    file - File to send.
    Returns:
    boolean True on success, false otherwise
    +
    +
    +
    + +

    +cupsGetJobs

    +
    +public CupsJob[] cupsGetJobs(boolean showMyJobs,
    +                             boolean showCompleted)
    +                      throws java.io.IOException
    +
    +
    Get a list of jobs.
    +
    Parameters:
    showMyJobs - Show only jobs for user.
    showCompleted - Show completed OR active jobs.
    Returns:
    CupsJob[] Array of job objects, or null.
    +
    +
    +
    + +

    +cupsGetPrinters

    +
    +public java.lang.String[] cupsGetPrinters()
    +                                   throws java.io.IOException
    +
    +
    Get a list of printers.
    +
    Returns:
    String[] Array of printers, or null.
    +
    +
    +
    + +

    +cupsGetDefault

    +
    +public java.lang.String cupsGetDefault()
    +                                throws java.io.IOException
    +
    +
    Get default destination.
    +
    Returns:
    String Name of default printer, or null.
    +
    +
    +
    + +

    +cupsGetPrinterAttributes

    +
    +public java.util.List cupsGetPrinterAttributes(java.lang.String printer_name)
    +                                        throws java.io.IOException
    +
    +
    Get printer attributes
    +
    Parameters:
    printer_name - Name of printer to get info for.
    Returns:
    List List of attributes.
    See Also:
    CupsPrinter
    +
    +
    +
    + +

    +cupsPrintFile

    +
    +public CupsJob cupsPrintFile(java.lang.String p_filename,
    +                             IPPAttribute[] p_attrs)
    +                      throws java.io.IOException
    +
    +
    Print a file.
    +
    Parameters:
    p_filename - Path of file to print.
    p_attrs[] - Array of print job attributes.
    Returns:
    CupsJob Object with job info.
    See Also:
    CupsJob
    +
    +
    +
    + +

    +cupsCancelJob

    +
    +public int cupsCancelJob(java.lang.String printer_name,
    +                         int p_job_id,
    +                         java.lang.String p_user_name)
    +                  throws java.io.IOException
    +
    +
    Cancel a job - send a job cancel request to the server.
    +
    Parameters:
    printer_name - Destination.
    p_job_id - ID of job.
    p_user_name - Requesting user name.
    +
    +
    +
    + +

    +cupsGetPrinterStatus

    +
    +public java.util.List cupsGetPrinterStatus(java.lang.String printer_name)
    +                                    throws java.io.IOException
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/CupsJob.html b/scripting/java/docs/com/easysw/cups/CupsJob.html new file mode 100644 index 000000000..c75fb8fa7 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/CupsJob.html @@ -0,0 +1,547 @@ + + + + + + +: Class CupsJob + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class CupsJob

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.CupsJob
    +
    +
    +
    +
    public class CupsJob
    extends java.lang.Object
    + +

    +


    + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Field Summary
    + java.lang.Stringdocument_format + +
    +           
    + java.lang.Stringjob_hold_until + +
    +           
    + intjob_id + +
    +           
    + intjob_k_octets + +
    +           
    + intjob_media_sheets_completed + +
    +           
    + java.lang.Stringjob_more_info + +
    +           
    + java.lang.Stringjob_name + +
    +           
    + java.lang.Stringjob_originating_host_name + +
    +           
    + java.lang.Stringjob_originating_user_name + +
    +           
    + longjob_printer_up_time + +
    +           
    + java.lang.Stringjob_printer_uri + +
    +           
    + intjob_priority + +
    +           
    + java.lang.Stringjob_sheets + +
    +           
    + intjob_state + +
    +           
    + java.lang.Stringjob_state_reasons + +
    +           
    + java.lang.Stringjob_uri + +
    +           
    + longtime_at_completed + +
    +           
    + longtime_at_creation + +
    +           
    + longtime_at_processing + +
    +           
    +  + + + + + + + + + + +
    +Constructor Summary
    CupsJob() + +
    +          Constructor - set some default values.
    +  + + + + + + + + + + + + + + + +
    +Method Summary
    + java.lang.StringjobStatusText() + +
    +          Convert a job status to a string.
    + voidupdateAttribute(IPPAttribute a) + +
    +          Process an attribute from a cups.doRequest() call + and move the value into a local member.
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + +
    +Field Detail
    + +

    +job_id

    +
    +public int job_id
    +
    +
    +
    + +

    +job_more_info

    +
    +public java.lang.String job_more_info
    +
    +
    +
    + +

    +job_uri

    +
    +public java.lang.String job_uri
    +
    +
    +
    + +

    +job_printer_uri

    +
    +public java.lang.String job_printer_uri
    +
    +
    +
    + +

    +job_printer_up_time

    +
    +public long job_printer_up_time
    +
    +
    +
    + +

    +job_name

    +
    +public java.lang.String job_name
    +
    +
    +
    + +

    +job_originating_user_name

    +
    +public java.lang.String job_originating_user_name
    +
    +
    +
    + +

    +document_format

    +
    +public java.lang.String document_format
    +
    +
    +
    + +

    +job_originating_host_name

    +
    +public java.lang.String job_originating_host_name
    +
    +
    +
    + +

    +job_priority

    +
    +public int job_priority
    +
    +
    +
    + +

    +job_state

    +
    +public int job_state
    +
    +
    +
    + +

    +job_media_sheets_completed

    +
    +public int job_media_sheets_completed
    +
    +
    +
    + +

    +job_k_octets

    +
    +public int job_k_octets
    +
    +
    +
    + +

    +time_at_creation

    +
    +public long time_at_creation
    +
    +
    +
    + +

    +time_at_processing

    +
    +public long time_at_processing
    +
    +
    +
    + +

    +time_at_completed

    +
    +public long time_at_completed
    +
    +
    +
    + +

    +job_hold_until

    +
    +public java.lang.String job_hold_until
    +
    +
    +
    + +

    +job_sheets

    +
    +public java.lang.String job_sheets
    +
    +
    +
    + +

    +job_state_reasons

    +
    +public java.lang.String job_state_reasons
    +
    +
    + + + + + + + + +
    +Constructor Detail
    + +

    +CupsJob

    +
    +public CupsJob()
    +
    +
    Constructor - set some default values.
    + + + + + + + + +
    +Method Detail
    + +

    +updateAttribute

    +
    +public void updateAttribute(IPPAttribute a)
    +
    +
    Process an attribute from a cups.doRequest() call + and move the value into a local member.
    +
    See Also:
    IPPDefs, +IPPValues, +IPPAttributes
    +
    +
    +
    + +

    +jobStatusText

    +
    +public java.lang.String jobStatusText()
    +
    +
    Convert a job status to a string.
    +
    See Also:
    IPPDefs
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/CupsPrinter.html b/scripting/java/docs/com/easysw/cups/CupsPrinter.html new file mode 100644 index 000000000..3235483a0 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/CupsPrinter.html @@ -0,0 +1,533 @@ + + + + + + +: Class CupsPrinter + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class CupsPrinter

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.CupsPrinter
    +
    +
    +
    +
    public class CupsPrinter
    extends java.lang.Object
    + +

    +


    + +

    + + + + + + + + + + + + + + + + + + + +
    +Constructor Summary
    CupsPrinter(Cups c) + +
    +          Constructor.
    CupsPrinter(Cups c, + java.lang.String name) + +
    +          Constructor with name.
    +  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Method Summary
    + booleangetAttributes(Cups c) + +
    +          Get the printer's attributes.
    + intgetCopiesDefault() + +
    +          Get the printer number of copies default.
    + java.lang.StringgetJobSheetsDefault() + +
    +          Get the default job sheets.
    + java.lang.String[]getJobSheetsSupported() + +
    +          Get the printer job sheets supported.
    + java.lang.StringgetLocation() + +
    +          Get the printer location.
    + intgetLowerCopiesSupported() + +
    +          Get the printer lower copies supported.
    + java.lang.StringgetMakeAndModel() + +
    +          Get the printer make and model.
    + intgetOrientationDefault() + +
    +          Get the default orientation.
    + int[]getOrientationSupported() + +
    +          Get the printer orientation supported.
    + booleangetPageRangesSupported() + +
    +          Get whether the printer supports page ranges.
    + java.lang.StringgetPrinterName() + +
    +          Get the printer name.
    + java.lang.StringgetStateReasons() + +
    +          Get the printer state reasons.
    + java.lang.StringgetStateText() + +
    +          Get the printer state text.
    + booleangetStatus(Cups c) + +
    +          Get the printer's status.
    + intgetUpperCopiesSupported() + +
    +          Get the printer upper copies supported.
    + voidsetDefaults() + +
    +          Initialize the members with mostly sane values.
    + voidupdateAttribute(IPPAttribute a) + +
    +          Process an attribute from the cups.doRequest() method and move + the values into local members.
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + + + + +
    +Constructor Detail
    + +

    +CupsPrinter

    +
    +public CupsPrinter(Cups c)
    +
    +
    Constructor. Does not get status or attributes.
    +
    Parameters:
    c - Cups object.
    See Also:
    Cups
    +
    +
    +
    + +

    +CupsPrinter

    +
    +public CupsPrinter(Cups c,
    +                   java.lang.String name)
    +
    +
    Constructor with name. Get status and attributes.
    +
    Parameters:
    c - Cups object.
    name - Name of printer.
    See Also:
    Cups
    +
    +
    + + + + + + + + +
    +Method Detail
    + +

    +setDefaults

    +
    +public void setDefaults()
    +
    +
    Initialize the members with mostly sane values.
    +
    + +

    +getStatus

    +
    +public boolean getStatus(Cups c)
    +
    +
    Get the printer's status.
    +
    Parameters:
    c - Cups object.
    Returns:
    Boolean True on success.
    See Also:
    Cups
    +
    +
    +
    + +

    +getAttributes

    +
    +public boolean getAttributes(Cups c)
    +
    +
    Get the printer's attributes.
    +
    Parameters:
    c - Cups object.
    Returns:
    Boolean True on success.
    See Also:
    Cups
    +
    +
    +
    + +

    +updateAttribute

    +
    +public void updateAttribute(IPPAttribute a)
    +
    +
    Process an attribute from the cups.doRequest() method and move + the values into local members.
    +
    Parameters:
    a - IPPAttribute.
    See Also:
    IPPAttributes, +IPPValues
    +
    +
    +
    + +

    +getPrinterName

    +
    +public java.lang.String getPrinterName()
    +
    +
    Get the printer name.
    +
    Returns:
    String Printer Name.
    +
    +
    +
    + +

    +getStateText

    +
    +public java.lang.String getStateText()
    +
    +
    Get the printer state text.
    +
    Returns:
    String State text.
    +
    +
    +
    + +

    +getStateReasons

    +
    +public java.lang.String getStateReasons()
    +
    +
    Get the printer state reasons.
    +
    Returns:
    String State reason.
    +
    +
    +
    + +

    +getLocation

    +
    +public java.lang.String getLocation()
    +
    +
    Get the printer location.
    +
    Returns:
    String State location.
    +
    +
    +
    + +

    +getMakeAndModel

    +
    +public java.lang.String getMakeAndModel()
    +
    +
    Get the printer make and model.
    +
    Returns:
    String Make and model.
    +
    +
    +
    + +

    +getJobSheetsDefault

    +
    +public java.lang.String getJobSheetsDefault()
    +
    +
    Get the default job sheets.
    +
    Returns:
    String Default job sheets.
    +
    +
    +
    + +

    +getJobSheetsSupported

    +
    +public java.lang.String[] getJobSheetsSupported()
    +
    +
    Get the printer job sheets supported.
    +
    Returns:
    String[] Array of supported job sheets.
    +
    +
    +
    + +

    +getOrientationDefault

    +
    +public int getOrientationDefault()
    +
    +
    Get the default orientation.
    +
    Returns:
    int Default page orientation.
    +
    +
    +
    + +

    +getOrientationSupported

    +
    +public int[] getOrientationSupported()
    +
    +
    Get the printer orientation supported.
    +
    Returns:
    int[] Array of supported orientations.
    +
    +
    +
    + +

    +getLowerCopiesSupported

    +
    +public int getLowerCopiesSupported()
    +
    +
    Get the printer lower copies supported.
    +
    Returns:
    int Lower of the range.
    +
    +
    +
    + +

    +getUpperCopiesSupported

    +
    +public int getUpperCopiesSupported()
    +
    +
    Get the printer upper copies supported.
    +
    Returns:
    int Upper of the range.
    +
    +
    +
    + +

    +getCopiesDefault

    +
    +public int getCopiesDefault()
    +
    +
    Get the printer number of copies default.
    +
    Returns:
    int Default number of copies.
    +
    +
    +
    + +

    +getPageRangesSupported

    +
    +public boolean getPageRangesSupported()
    +
    +
    Get whether the printer supports page ranges.
    +
    Returns:
    boolean True or false.
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPP.html b/scripting/java/docs/com/easysw/cups/IPP.html new file mode 100644 index 000000000..77f1284d7 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPP.html @@ -0,0 +1,417 @@ + + + + + + +: Class IPP + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPP

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.IPP
    +
    +
    +
    +
    public class IPP
    extends java.lang.Object
    + +

    +An IPP object is used to hold the various + attributes and status of an ipp request.. +

    +

    +
    Since:
    JDK1.3
    +
    +
    + +

    + + + + + + + + + + + + + + + + + + + + + + +
    +Field Summary
    + java.util.Listattrs + +
    +           
    + IPPRequestrequest + +
    +           
    + IPPStatusstatus + +
    +           
    +  + + + + + + + + + + +
    +Constructor Summary
    IPP() + +
    +           
    +  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Method Summary
    + booleanaddAttribute(IPPAttribute a) + +
    +          Add an attribute to the attibutes list + for later parsing.
    + voiddump_response() + +
    +           
    + IPPAttributegetCurrentAttribute() + +
    +          Get the current attribute pointed at by + current.
    + IPPAttributeippFindAttribute(java.lang.String p_name, + int p_type) + +
    +          Find the named attribute of the correct type.
    + IPPAttributeippFindNextAttribute(java.lang.String p_name, + int p_type) + +
    +          Find the named attribute of the correct type.
    + voidsetRequestID(short p_id) + +
    +          Set the IPP request ID.
    + voidsetRequestOperationID(short p_operation_id) + +
    +          Set the IPP operation ID.
    + intsizeInBytes() + +
    +          Get the size in bytes of an IPP request.
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + +
    +Field Detail
    + +

    +request

    +
    +public IPPRequest request
    +
    +
    +
    + +

    +status

    +
    +public IPPStatus status
    +
    +
    +
    + +

    +attrs

    +
    +public java.util.List attrs
    +
    +
    + + + + + + + + +
    +Constructor Detail
    + +

    +IPP

    +
    +public IPP()
    +
    +
    + + + + + + + + +
    +Method Detail
    + +

    +addAttribute

    +
    +public boolean addAttribute(IPPAttribute a)
    +
    +
    Add an attribute to the attibutes list + for later parsing.
    +
    Parameters:
    a - IPPAttribute to add.
    Returns:
    true always returns true + for now.
    See Also:
    IPPAttribute, +IPPValue
    +
    +
    +
    + +

    +getCurrentAttribute

    +
    +public IPPAttribute getCurrentAttribute()
    +
    +
    Get the current attribute pointed at by + current.
    +
    Returns:
    IPPAttribute Return the current attribute.
    +
    +
    +
    + +

    +ippFindAttribute

    +
    +public IPPAttribute ippFindAttribute(java.lang.String p_name,
    +                                     int p_type)
    +
    +
    Find the named attribute of the correct type. Both must match. + This methos searches from the beginning of the attribute list, + rather than from the current position.
    +
    Parameters:
    p_name - String containing the name.
    p_type - int attribute type.
    Returns:
    IPPAttribute Matching attribute if found.
    +
    +
    +
    + +

    +ippFindNextAttribute

    +
    +public IPPAttribute ippFindNextAttribute(java.lang.String p_name,
    +                                         int p_type)
    +
    +
    Find the named attribute of the correct type. Both must match. + This methos searches from the current position in the attribute list.
    +
    Parameters:
    p_name - String containing the name.
    p_type - int attribute type.
    Returns:
    IPPAttribute Matching attribute if found.
    +
    +
    +
    + +

    +sizeInBytes

    +
    +public int sizeInBytes()
    +
    +
    Get the size in bytes of an IPP request.
    +
    Returns:
    int Number of bytes for the request.
    +
    +
    +
    + +

    +setRequestID

    +
    +public void setRequestID(short p_id)
    +
    +
    Set the IPP request ID.
    +
    Parameters:
    p_id - short request id.
    +
    +
    +
    + +

    +setRequestOperationID

    +
    +public void setRequestOperationID(short p_operation_id)
    +
    +
    Set the IPP operation ID.
    +
    Parameters:
    p_operation_id - short operation id.
    +
    +
    +
    + +

    +dump_response

    +
    +public void dump_response()
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPPAttribute.html b/scripting/java/docs/com/easysw/cups/IPPAttribute.html new file mode 100644 index 000000000..544b0c368 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPPAttribute.html @@ -0,0 +1,466 @@ + + + + + + +: Class IPPAttribute + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPPAttribute

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.IPPAttribute
    +
    +
    +
    +
    public class IPPAttribute
    extends java.lang.Object
    + +

    +


    + +

    + + + + + + + + + + + + + + + + +
    +Constructor Summary
    IPPAttribute(int p_group_tag, + int p_value_tag, + java.lang.String p_name) + +
    +           
    +  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Method Summary
    + booleanaddBoolean(boolean p_bool) + +
    +           
    + booleanaddBooleans(boolean[] p_bools) + +
    +           
    + booleanaddDate(char[] p_date) + +
    +           
    + booleanaddEnum(int p_int) + +
    +           
    + booleanaddInteger(int p_int) + +
    +           
    + booleanaddIntegers(int[] p_ints) + +
    +           
    + booleanaddRange(int p_lower, + int p_upper) + +
    +           
    + booleanaddRanges(int[] p_lower, + int[] p_upper) + +
    +           
    + booleanaddResolution(byte p_units, + int p_xres, + int p_yres) + +
    +           
    + booleanaddResolutions(byte p_units, + int[] p_xres, + int[] p_yres) + +
    +           
    + booleanaddSeparator() + +
    +           
    + booleanaddString(java.lang.String p_charset, + java.lang.String p_text) + +
    +           
    + booleanaddStrings(java.lang.String p_charset, + java.lang.String[] p_texts) + +
    +           
    + voiddump_values() + +
    +           
    + byte[]getBytes(int sz, + int last_group) + +
    +           
    + intsizeInBytes(int last_group) + +
    +           
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + + + + +
    +Constructor Detail
    + +

    +IPPAttribute

    +
    +public IPPAttribute(int p_group_tag,
    +                    int p_value_tag,
    +                    java.lang.String p_name)
    +
    +
    + + + + + + + + +
    +Method Detail
    + +

    +addBoolean

    +
    +public boolean addBoolean(boolean p_bool)
    +
    +
    +
    + +

    +addBooleans

    +
    +public boolean addBooleans(boolean[] p_bools)
    +
    +
    +
    + +

    +addEnum

    +
    +public boolean addEnum(int p_int)
    +
    +
    +
    + +

    +addInteger

    +
    +public boolean addInteger(int p_int)
    +
    +
    +
    + +

    +addIntegers

    +
    +public boolean addIntegers(int[] p_ints)
    +
    +
    +
    + +

    +addString

    +
    +public boolean addString(java.lang.String p_charset,
    +                         java.lang.String p_text)
    +
    +
    +
    + +

    +addStrings

    +
    +public boolean addStrings(java.lang.String p_charset,
    +                          java.lang.String[] p_texts)
    +
    +
    +
    + +

    +addDate

    +
    +public boolean addDate(char[] p_date)
    +
    +
    +
    + +

    +addRange

    +
    +public boolean addRange(int p_lower,
    +                        int p_upper)
    +
    +
    +
    + +

    +addRanges

    +
    +public boolean addRanges(int[] p_lower,
    +                         int[] p_upper)
    +
    +
    +
    + +

    +addResolution

    +
    +public boolean addResolution(byte p_units,
    +                             int p_xres,
    +                             int p_yres)
    +
    +
    +
    + +

    +addResolutions

    +
    +public boolean addResolutions(byte p_units,
    +                              int[] p_xres,
    +                              int[] p_yres)
    +
    +
    +
    + +

    +addSeparator

    +
    +public boolean addSeparator()
    +
    +
    +
    + +

    +sizeInBytes

    +
    +public int sizeInBytes(int last_group)
    +
    +
    +
    + +

    +getBytes

    +
    +public byte[] getBytes(int sz,
    +                       int last_group)
    +
    +
    +
    + +

    +dump_values

    +
    +public void dump_values()
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPPDefs.html b/scripting/java/docs/com/easysw/cups/IPPDefs.html new file mode 100644 index 000000000..63901cb9c --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPPDefs.html @@ -0,0 +1,3330 @@ + + + + + + +: Class IPPDefs + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPPDefs

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.IPPDefs
    +
    +
    +
    +
    public class IPPDefs
    extends java.lang.Object
    + +

    +IPPDefs is a collection of constants for use + in the IPP and CUPS classes. +

    +

    +
    Since:
    JDK1.3
    +
    +
    + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Field Summary
    +static intACTIVATE_PRINTER + +
    +           
    +static intATTRIBUTE + +
    +           
    +static intATTRIBUTES + +
    +           
    +static intATTRIBUTES_NOT_SETTABLE + +
    +           
    +static intBAD_REQUEST + +
    +           
    +static intCANCEL_CURRENT_JOB + +
    +           
    +static intCANCEL_JOB + +
    +           
    +static intCANCEL_SUBSCRIPTION + +
    +           
    +static intCHARSET + +
    +           
    +static intCOMPRESSION_ERROR + +
    +           
    +static intCOMPRESSION_NOT_SUPPORTED + +
    +           
    +static intCONFLICT + +
    +           
    +static intCREATE_JOB + +
    +           
    +static intCREATE_JOB_SUBSCRIPTION + +
    +           
    +static intCREATE_PRINTER_SUBSCRIPTION + +
    +           
    +static intCUPS_ACCEPT_JOBS + +
    +           
    +static intCUPS_ADD_CLASS + +
    +           
    +static intCUPS_ADD_DEVICE + +
    +           
    +static intCUPS_ADD_PRINTER + +
    +           
    +static intCUPS_DELETE_CLASS + +
    +           
    +static intCUPS_DELETE_DEVICE + +
    +           
    +static intCUPS_DELETE_PRINTER + +
    +           
    +static intCUPS_GET_CLASSES + +
    +           
    +static intCUPS_GET_DEFAULT + +
    +           
    +static intCUPS_GET_DEVICES + +
    +           
    +static intCUPS_GET_PPDS + +
    +           
    +static intCUPS_GET_PRINTERS + +
    +           
    +static intCUPS_MOVE_JOB + +
    +           
    +static intCUPS_REJECT_JOBS + +
    +           
    +static intCUPS_SET_DEFAULT + +
    +           
    +static intDATA + +
    +           
    +static intDEACTIVATE_PRINTER + +
    +           
    +static intDEVICE_ERROR + +
    +           
    +static intDISABLE_PRINTER + +
    +           
    +static intDOCUMENT_ACCESS_ERROR + +
    +           
    +static intDOCUMENT_FORMAT + +
    +           
    +static intDOCUMENT_FORMAT_ERROR + +
    +           
    +static intENABLE_PRINTER + +
    +           
    +static intERROR + +
    +           
    +static intERROR_JOB_CANCELLED + +
    +           
    +static intFINISHINGS_BALE + +
    +           
    +static intFINISHINGS_BIND + +
    +           
    +static intFINISHINGS_BIND_BOTTOM + +
    +           
    +static intFINISHINGS_BIND_LEFT + +
    +           
    +static intFINISHINGS_BIND_RIGHT + +
    +           
    +static intFINISHINGS_BIND_TOP + +
    +           
    +static intFINISHINGS_BOOKLET_MAKER + +
    +           
    +static intFINISHINGS_COVER + +
    +           
    +static intFINISHINGS_EDGE_STITCH + +
    +           
    +static intFINISHINGS_EDGE_STITCH_BOTTOM + +
    +           
    +static intFINISHINGS_EDGE_STITCH_LEFT + +
    +           
    +static intFINISHINGS_EDGE_STITCH_RIGHT + +
    +           
    +static intFINISHINGS_EDGE_STITCH_TOP + +
    +           
    +static intFINISHINGS_FOLD + +
    +           
    +static intFINISHINGS_JOB_OFFSET + +
    +           
    +static intFINISHINGS_NONE + +
    +           
    +static intFINISHINGS_PUNCH + +
    +           
    +static intFINISHINGS_SADDLE_STITCH + +
    +           
    +static intFINISHINGS_STAPLE + +
    +           
    +static intFINISHINGS_STAPLE_BOTTOM_LEFT + +
    +           
    +static intFINISHINGS_STAPLE_BOTTOM_RIGHT + +
    +           
    +static intFINISHINGS_STAPLE_DUAL_BOTTOM + +
    +           
    +static intFINISHINGS_STAPLE_DUAL_LEFT + +
    +           
    +static intFINISHINGS_STAPLE_DUAL_RIGHT + +
    +           
    +static intFINISHINGS_STAPLE_DUAL_TOP + +
    +           
    +static intFINISHINGS_STAPLE_TOP_LEFT + +
    +           
    +static intFINISHINGS_STAPLE_TOP_RIGHT + +
    +           
    +static intFINISHINGS_TRIM + +
    +           
    +static intFORBIDDEN + +
    +           
    +static intGET_JOB_ATTRIBUTES + +
    +           
    +static intGET_JOBS + +
    +           
    +static intGET_NOTIFICATIONS + +
    +           
    +static intGET_PRINT_SUPPORT_FILES + +
    +           
    +static intGET_PRINTER_ATTRIBUTES + +
    +           
    +static intGET_PRINTER_SUPPORTED_VALUES + +
    +           
    +static intGET_SUBSCRIPTION_ATTRIBUTES + +
    +           
    +static intGET_SUBSCRIPTIONS + +
    +           
    +static intGONE + +
    +           
    +static intHEADER + +
    +           
    +static intHOLD_JOB + +
    +           
    +static intHOLD_NEW_JOBS + +
    +           
    +static intIDLE + +
    +           
    +static intIGNORED_ALL_NOTIFICATIONS + +
    +           
    +static intIGNORED_ALL_SUBSCRIPTIONS + +
    +           
    +static intINTERNAL_ERROR + +
    +           
    +static intJOB_ABORTED + +
    +           
    +static intJOB_CANCELLED + +
    +           
    +static intJOB_COMPLETED + +
    +           
    +static intJOB_HELD + +
    +           
    +static intJOB_PENDING + +
    +           
    +static intJOB_PROCESSING + +
    +           
    +static intJOB_STOPPED + +
    +           
    +static intLANDSCAPE + +
    +           
    +static intMAX_NAME + +
    +           
    +static intMAX_VALUES + +
    +           
    +static intMULTIPLE_JOBS_NOT_SUPPORTED + +
    +           
    +static intNOT_ACCEPTING + +
    +           
    +static intNOT_AUTHENTICATED + +
    +           
    +static intNOT_AUTHORIZED + +
    +           
    +static intNOT_FOUND + +
    +           
    +static intNOT_POSSIBLE + +
    +           
    +static intOK + +
    +           
    +static intOK_BUT_CANCEL_SUBSCRIPTION + +
    +           
    +static intOK_CONFLICT + +
    +           
    +static intOK_IGNORED_NOTIFICATIONS + +
    +           
    +static intOK_IGNORED_SUBSCRIPTIONS + +
    +           
    +static intOK_SUBST + +
    +           
    +static intOK_TOO_MANY_EVENTS + +
    +           
    +static intOPERATION_NOT_SUPPORTED + +
    +           
    +static intPAUSE_PRINTER + +
    +           
    +static intPAUSE_PRINTER_AFTER_CURRENT_JOB + +
    +           
    +static intPORT + +
    +           
    +static intPORTRAIT + +
    +           
    +static intPRINT_JOB + +
    +           
    +static intPRINT_SUPPORT_FILE_NOT_FOUND + +
    +           
    +static intPRINT_URI + +
    +           
    +static intPRINTER_BUSY + +
    +           
    +static intPRINTER_IDLE + +
    +           
    +static intPRINTER_IS_DEACTIVATED + +
    +           
    +static intPRINTER_PROCESSING + +
    +           
    +static intPRINTER_STOPPED + +
    +           
    +static intPRIVATE + +
    +           
    +static intPROMOTE_JOB + +
    +           
    +static intPURGE_JOBS + +
    +           
    +static intQUALITY_DRAFT + +
    +           
    +static intQUALITY_HIGH + +
    +           
    +static intQUALITY_NORMAL + +
    +           
    +static intREDIRECTION_OTHER_SITE + +
    +           
    +static intRELEASE_HELD_NEW_JOBS + +
    +           
    +static intRELEASE_JOB + +
    +           
    +static intRENEW_SUBSCRIPTION + +
    +           
    +static intREPROCESS_JOB + +
    +           
    +static intREQUEST_ENTITY + +
    +           
    +static intREQUEST_VALUE + +
    +           
    +static intRES_PER_CM + +
    +           
    +static intRES_PER_INCH + +
    +           
    +static intRESTART_JOB + +
    +           
    +static intRESTART_PRINTER + +
    +           
    +static intRESUME_JOB + +
    +           
    +static intRESUME_PRINTER + +
    +           
    +static intREVERSE_LANDSCAPE + +
    +           
    +static intREVERSE_PORTRAIT + +
    +           
    +static intSCHEDULE_JOB_AFTER + +
    +           
    +static intSEND_DOCUMENT + +
    +           
    +static intSEND_NOTIFICATIONS + +
    +           
    +static intSEND_URI + +
    +           
    +static intSERVICE_UNAVAILABLE + +
    +           
    +static intSET_JOB_ATTRIBUTES + +
    +           
    +static intSET_PRINTER_ATTRIBUTES + +
    +           
    +static intSHUTDOWN_PRINTER + +
    +           
    +static intSTARTUP_PRINTER + +
    +           
    +static intSUSPEND_CURRENT_JOB + +
    +           
    +static intTAG_ADMINDEFINE + +
    +           
    +static intTAG_BEGIN_COLLECTION + +
    +           
    +static intTAG_BOOLEAN + +
    +           
    +static intTAG_CHARSET + +
    +           
    +static intTAG_COPY + +
    +           
    +static intTAG_DATE + +
    +           
    +static intTAG_DEFAULT + +
    +           
    +static intTAG_DELETEATTR + +
    +           
    +static intTAG_END + +
    +           
    +static intTAG_END_COLLECTION + +
    +           
    +static intTAG_ENUM + +
    +           
    +static intTAG_EVENT_NOTIFICATION + +
    +           
    +static intTAG_INTEGER + +
    +           
    +static intTAG_JOB + +
    +           
    +static intTAG_KEYWORD + +
    +           
    +static intTAG_LANGUAGE + +
    +           
    +static intTAG_MASK + +
    +           
    +static intTAG_MEMBERNAME + +
    +           
    +static intTAG_MIMETYPE + +
    +           
    +static intTAG_NAME + +
    +           
    +static intTAG_NAMELANG + +
    +           
    +static intTAG_NOTSETTABLE + +
    +           
    +static intTAG_NOVALUE + +
    +           
    +static intTAG_OPERATION + +
    +           
    +static intTAG_PRINTER + +
    +           
    +static intTAG_RANGE + +
    +           
    +static intTAG_RESOLUTION + +
    +           
    +static intTAG_STRING + +
    +           
    +static intTAG_SUBSCRIPTION + +
    +           
    +static intTAG_TEXT + +
    +           
    +static intTAG_TEXTLANG + +
    +           
    +static intTAG_UNKNOWN + +
    +           
    +static intTAG_UNSUPPORTED_GROUP + +
    +           
    +static intTAG_UNSUPPORTED_VALUE + +
    +           
    +static intTAG_URI + +
    +           
    +static intTAG_URISCHEME + +
    +           
    +static intTAG_ZERO + +
    +           
    +static intTEMPORARY_ERROR + +
    +           
    +static intTIMEOUT + +
    +           
    +static intTOO_MANY_SUBSCRIPTIONS + +
    +           
    +static intURI_SCHEME + +
    +           
    +static intVALIDATE_JOB + +
    +           
    +static byte[]VERSION + +
    +           
    +static intVERSION_NOT_SUPPORTED + +
    +           
    +  + + + + + + + + + + +
    +Constructor Summary
    IPPDefs() + +
    +           
    +  + + + + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + +
    +Field Detail
    + +

    +VERSION

    +
    +public static final byte[] VERSION
    +
    +
    +
    + +

    +PORT

    +
    +public static final int PORT
    +
    +
    +
    + +

    +MAX_NAME

    +
    +public static final int MAX_NAME
    +
    +
    +
    + +

    +MAX_VALUES

    +
    +public static final int MAX_VALUES
    +
    +
    +
    + +

    +TAG_ZERO

    +
    +public static final int TAG_ZERO
    +
    +
    +
    + +

    +TAG_OPERATION

    +
    +public static final int TAG_OPERATION
    +
    +
    +
    + +

    +TAG_JOB

    +
    +public static final int TAG_JOB
    +
    +
    +
    + +

    +TAG_END

    +
    +public static final int TAG_END
    +
    +
    +
    + +

    +TAG_PRINTER

    +
    +public static final int TAG_PRINTER
    +
    +
    +
    + +

    +TAG_UNSUPPORTED_GROUP

    +
    +public static final int TAG_UNSUPPORTED_GROUP
    +
    +
    +
    + +

    +TAG_SUBSCRIPTION

    +
    +public static final int TAG_SUBSCRIPTION
    +
    +
    +
    + +

    +TAG_EVENT_NOTIFICATION

    +
    +public static final int TAG_EVENT_NOTIFICATION
    +
    +
    +
    + +

    +TAG_UNSUPPORTED_VALUE

    +
    +public static final int TAG_UNSUPPORTED_VALUE
    +
    +
    +
    + +

    +TAG_DEFAULT

    +
    +public static final int TAG_DEFAULT
    +
    +
    +
    + +

    +TAG_UNKNOWN

    +
    +public static final int TAG_UNKNOWN
    +
    +
    +
    + +

    +TAG_NOVALUE

    +
    +public static final int TAG_NOVALUE
    +
    +
    +
    + +

    +TAG_NOTSETTABLE

    +
    +public static final int TAG_NOTSETTABLE
    +
    +
    +
    + +

    +TAG_DELETEATTR

    +
    +public static final int TAG_DELETEATTR
    +
    +
    +
    + +

    +TAG_ADMINDEFINE

    +
    +public static final int TAG_ADMINDEFINE
    +
    +
    +
    + +

    +TAG_INTEGER

    +
    +public static final int TAG_INTEGER
    +
    +
    +
    + +

    +TAG_BOOLEAN

    +
    +public static final int TAG_BOOLEAN
    +
    +
    +
    + +

    +TAG_ENUM

    +
    +public static final int TAG_ENUM
    +
    +
    +
    + +

    +TAG_STRING

    +
    +public static final int TAG_STRING
    +
    +
    +
    + +

    +TAG_DATE

    +
    +public static final int TAG_DATE
    +
    +
    +
    + +

    +TAG_RESOLUTION

    +
    +public static final int TAG_RESOLUTION
    +
    +
    +
    + +

    +TAG_RANGE

    +
    +public static final int TAG_RANGE
    +
    +
    +
    + +

    +TAG_BEGIN_COLLECTION

    +
    +public static final int TAG_BEGIN_COLLECTION
    +
    +
    +
    + +

    +TAG_TEXTLANG

    +
    +public static final int TAG_TEXTLANG
    +
    +
    +
    + +

    +TAG_NAMELANG

    +
    +public static final int TAG_NAMELANG
    +
    +
    +
    + +

    +TAG_END_COLLECTION

    +
    +public static final int TAG_END_COLLECTION
    +
    +
    +
    + +

    +TAG_TEXT

    +
    +public static final int TAG_TEXT
    +
    +
    +
    + +

    +TAG_NAME

    +
    +public static final int TAG_NAME
    +
    +
    +
    + +

    +TAG_KEYWORD

    +
    +public static final int TAG_KEYWORD
    +
    +
    +
    + +

    +TAG_URI

    +
    +public static final int TAG_URI
    +
    +
    +
    + +

    +TAG_URISCHEME

    +
    +public static final int TAG_URISCHEME
    +
    +
    +
    + +

    +TAG_CHARSET

    +
    +public static final int TAG_CHARSET
    +
    +
    +
    + +

    +TAG_LANGUAGE

    +
    +public static final int TAG_LANGUAGE
    +
    +
    +
    + +

    +TAG_MIMETYPE

    +
    +public static final int TAG_MIMETYPE
    +
    +
    +
    + +

    +TAG_MEMBERNAME

    +
    +public static final int TAG_MEMBERNAME
    +
    +
    +
    + +

    +TAG_MASK

    +
    +public static final int TAG_MASK
    +
    +
    +
    + +

    +TAG_COPY

    +
    +public static final int TAG_COPY
    +
    +
    +
    + +

    +RES_PER_INCH

    +
    +public static final int RES_PER_INCH
    +
    +
    +
    + +

    +RES_PER_CM

    +
    +public static final int RES_PER_CM
    +
    +
    +
    + +

    +FINISHINGS_NONE

    +
    +public static final int FINISHINGS_NONE
    +
    +
    +
    + +

    +FINISHINGS_STAPLE

    +
    +public static final int FINISHINGS_STAPLE
    +
    +
    +
    + +

    +FINISHINGS_PUNCH

    +
    +public static final int FINISHINGS_PUNCH
    +
    +
    +
    + +

    +FINISHINGS_COVER

    +
    +public static final int FINISHINGS_COVER
    +
    +
    +
    + +

    +FINISHINGS_BIND

    +
    +public static final int FINISHINGS_BIND
    +
    +
    +
    + +

    +FINISHINGS_SADDLE_STITCH

    +
    +public static final int FINISHINGS_SADDLE_STITCH
    +
    +
    +
    + +

    +FINISHINGS_EDGE_STITCH

    +
    +public static final int FINISHINGS_EDGE_STITCH
    +
    +
    +
    + +

    +FINISHINGS_FOLD

    +
    +public static final int FINISHINGS_FOLD
    +
    +
    +
    + +

    +FINISHINGS_TRIM

    +
    +public static final int FINISHINGS_TRIM
    +
    +
    +
    + +

    +FINISHINGS_BALE

    +
    +public static final int FINISHINGS_BALE
    +
    +
    +
    + +

    +FINISHINGS_BOOKLET_MAKER

    +
    +public static final int FINISHINGS_BOOKLET_MAKER
    +
    +
    +
    + +

    +FINISHINGS_JOB_OFFSET

    +
    +public static final int FINISHINGS_JOB_OFFSET
    +
    +
    +
    + +

    +FINISHINGS_STAPLE_TOP_LEFT

    +
    +public static final int FINISHINGS_STAPLE_TOP_LEFT
    +
    +
    +
    + +

    +FINISHINGS_STAPLE_BOTTOM_LEFT

    +
    +public static final int FINISHINGS_STAPLE_BOTTOM_LEFT
    +
    +
    +
    + +

    +FINISHINGS_STAPLE_TOP_RIGHT

    +
    +public static final int FINISHINGS_STAPLE_TOP_RIGHT
    +
    +
    +
    + +

    +FINISHINGS_STAPLE_BOTTOM_RIGHT

    +
    +public static final int FINISHINGS_STAPLE_BOTTOM_RIGHT
    +
    +
    +
    + +

    +FINISHINGS_EDGE_STITCH_LEFT

    +
    +public static final int FINISHINGS_EDGE_STITCH_LEFT
    +
    +
    +
    + +

    +FINISHINGS_EDGE_STITCH_TOP

    +
    +public static final int FINISHINGS_EDGE_STITCH_TOP
    +
    +
    +
    + +

    +FINISHINGS_EDGE_STITCH_RIGHT

    +
    +public static final int FINISHINGS_EDGE_STITCH_RIGHT
    +
    +
    +
    + +

    +FINISHINGS_EDGE_STITCH_BOTTOM

    +
    +public static final int FINISHINGS_EDGE_STITCH_BOTTOM
    +
    +
    +
    + +

    +FINISHINGS_STAPLE_DUAL_LEFT

    +
    +public static final int FINISHINGS_STAPLE_DUAL_LEFT
    +
    +
    +
    + +

    +FINISHINGS_STAPLE_DUAL_TOP

    +
    +public static final int FINISHINGS_STAPLE_DUAL_TOP
    +
    +
    +
    + +

    +FINISHINGS_STAPLE_DUAL_RIGHT

    +
    +public static final int FINISHINGS_STAPLE_DUAL_RIGHT
    +
    +
    +
    + +

    +FINISHINGS_STAPLE_DUAL_BOTTOM

    +
    +public static final int FINISHINGS_STAPLE_DUAL_BOTTOM
    +
    +
    +
    + +

    +FINISHINGS_BIND_LEFT

    +
    +public static final int FINISHINGS_BIND_LEFT
    +
    +
    +
    + +

    +FINISHINGS_BIND_TOP

    +
    +public static final int FINISHINGS_BIND_TOP
    +
    +
    +
    + +

    +FINISHINGS_BIND_RIGHT

    +
    +public static final int FINISHINGS_BIND_RIGHT
    +
    +
    +
    + +

    +FINISHINGS_BIND_BOTTOM

    +
    +public static final int FINISHINGS_BIND_BOTTOM
    +
    +
    +
    + +

    +PORTRAIT

    +
    +public static final int PORTRAIT
    +
    +
    +
    + +

    +LANDSCAPE

    +
    +public static final int LANDSCAPE
    +
    +
    +
    + +

    +REVERSE_LANDSCAPE

    +
    +public static final int REVERSE_LANDSCAPE
    +
    +
    +
    + +

    +REVERSE_PORTRAIT

    +
    +public static final int REVERSE_PORTRAIT
    +
    +
    +
    + +

    +QUALITY_DRAFT

    +
    +public static final int QUALITY_DRAFT
    +
    +
    +
    + +

    +QUALITY_NORMAL

    +
    +public static final int QUALITY_NORMAL
    +
    +
    +
    + +

    +QUALITY_HIGH

    +
    +public static final int QUALITY_HIGH
    +
    +
    +
    + +

    +JOB_PENDING

    +
    +public static final int JOB_PENDING
    +
    +
    +
    + +

    +JOB_HELD

    +
    +public static final int JOB_HELD
    +
    +
    +
    + +

    +JOB_PROCESSING

    +
    +public static final int JOB_PROCESSING
    +
    +
    +
    + +

    +JOB_STOPPED

    +
    +public static final int JOB_STOPPED
    +
    +
    +
    + +

    +JOB_CANCELLED

    +
    +public static final int JOB_CANCELLED
    +
    +
    +
    + +

    +JOB_ABORTED

    +
    +public static final int JOB_ABORTED
    +
    +
    +
    + +

    +JOB_COMPLETED

    +
    +public static final int JOB_COMPLETED
    +
    +
    +
    + +

    +PRINTER_IDLE

    +
    +public static final int PRINTER_IDLE
    +
    +
    +
    + +

    +PRINTER_PROCESSING

    +
    +public static final int PRINTER_PROCESSING
    +
    +
    +
    + +

    +PRINTER_STOPPED

    +
    +public static final int PRINTER_STOPPED
    +
    +
    +
    + +

    +ERROR

    +
    +public static final int ERROR
    +
    +
    +
    + +

    +IDLE

    +
    +public static final int IDLE
    +
    +
    +
    + +

    +HEADER

    +
    +public static final int HEADER
    +
    +
    +
    + +

    +ATTRIBUTE

    +
    +public static final int ATTRIBUTE
    +
    +
    +
    + +

    +DATA

    +
    +public static final int DATA
    +
    +
    +
    + +

    +PRINT_JOB

    +
    +public static final int PRINT_JOB
    +
    +
    +
    + +

    +PRINT_URI

    +
    +public static final int PRINT_URI
    +
    +
    +
    + +

    +VALIDATE_JOB

    +
    +public static final int VALIDATE_JOB
    +
    +
    +
    + +

    +CREATE_JOB

    +
    +public static final int CREATE_JOB
    +
    +
    +
    + +

    +SEND_DOCUMENT

    +
    +public static final int SEND_DOCUMENT
    +
    +
    +
    + +

    +SEND_URI

    +
    +public static final int SEND_URI
    +
    +
    +
    + +

    +CANCEL_JOB

    +
    +public static final int CANCEL_JOB
    +
    +
    +
    + +

    +GET_JOB_ATTRIBUTES

    +
    +public static final int GET_JOB_ATTRIBUTES
    +
    +
    +
    + +

    +GET_JOBS

    +
    +public static final int GET_JOBS
    +
    +
    +
    + +

    +GET_PRINTER_ATTRIBUTES

    +
    +public static final int GET_PRINTER_ATTRIBUTES
    +
    +
    +
    + +

    +HOLD_JOB

    +
    +public static final int HOLD_JOB
    +
    +
    +
    + +

    +RELEASE_JOB

    +
    +public static final int RELEASE_JOB
    +
    +
    +
    + +

    +RESTART_JOB

    +
    +public static final int RESTART_JOB
    +
    +
    +
    + +

    +PAUSE_PRINTER

    +
    +public static final int PAUSE_PRINTER
    +
    +
    +
    + +

    +RESUME_PRINTER

    +
    +public static final int RESUME_PRINTER
    +
    +
    +
    + +

    +PURGE_JOBS

    +
    +public static final int PURGE_JOBS
    +
    +
    +
    + +

    +SET_PRINTER_ATTRIBUTES

    +
    +public static final int SET_PRINTER_ATTRIBUTES
    +
    +
    +
    + +

    +SET_JOB_ATTRIBUTES

    +
    +public static final int SET_JOB_ATTRIBUTES
    +
    +
    +
    + +

    +GET_PRINTER_SUPPORTED_VALUES

    +
    +public static final int GET_PRINTER_SUPPORTED_VALUES
    +
    +
    +
    + +

    +CREATE_PRINTER_SUBSCRIPTION

    +
    +public static final int CREATE_PRINTER_SUBSCRIPTION
    +
    +
    +
    + +

    +CREATE_JOB_SUBSCRIPTION

    +
    +public static final int CREATE_JOB_SUBSCRIPTION
    +
    +
    +
    + +

    +GET_SUBSCRIPTION_ATTRIBUTES

    +
    +public static final int GET_SUBSCRIPTION_ATTRIBUTES
    +
    +
    +
    + +

    +GET_SUBSCRIPTIONS

    +
    +public static final int GET_SUBSCRIPTIONS
    +
    +
    +
    + +

    +RENEW_SUBSCRIPTION

    +
    +public static final int RENEW_SUBSCRIPTION
    +
    +
    +
    + +

    +CANCEL_SUBSCRIPTION

    +
    +public static final int CANCEL_SUBSCRIPTION
    +
    +
    +
    + +

    +GET_NOTIFICATIONS

    +
    +public static final int GET_NOTIFICATIONS
    +
    +
    +
    + +

    +SEND_NOTIFICATIONS

    +
    +public static final int SEND_NOTIFICATIONS
    +
    +
    +
    + +

    +GET_PRINT_SUPPORT_FILES

    +
    +public static final int GET_PRINT_SUPPORT_FILES
    +
    +
    +
    + +

    +ENABLE_PRINTER

    +
    +public static final int ENABLE_PRINTER
    +
    +
    +
    + +

    +DISABLE_PRINTER

    +
    +public static final int DISABLE_PRINTER
    +
    +
    +
    + +

    +PAUSE_PRINTER_AFTER_CURRENT_JOB

    +
    +public static final int PAUSE_PRINTER_AFTER_CURRENT_JOB
    +
    +
    +
    + +

    +HOLD_NEW_JOBS

    +
    +public static final int HOLD_NEW_JOBS
    +
    +
    +
    + +

    +RELEASE_HELD_NEW_JOBS

    +
    +public static final int RELEASE_HELD_NEW_JOBS
    +
    +
    +
    + +

    +DEACTIVATE_PRINTER

    +
    +public static final int DEACTIVATE_PRINTER
    +
    +
    +
    + +

    +ACTIVATE_PRINTER

    +
    +public static final int ACTIVATE_PRINTER
    +
    +
    +
    + +

    +RESTART_PRINTER

    +
    +public static final int RESTART_PRINTER
    +
    +
    +
    + +

    +SHUTDOWN_PRINTER

    +
    +public static final int SHUTDOWN_PRINTER
    +
    +
    +
    + +

    +STARTUP_PRINTER

    +
    +public static final int STARTUP_PRINTER
    +
    +
    +
    + +

    +REPROCESS_JOB

    +
    +public static final int REPROCESS_JOB
    +
    +
    +
    + +

    +CANCEL_CURRENT_JOB

    +
    +public static final int CANCEL_CURRENT_JOB
    +
    +
    +
    + +

    +SUSPEND_CURRENT_JOB

    +
    +public static final int SUSPEND_CURRENT_JOB
    +
    +
    +
    + +

    +RESUME_JOB

    +
    +public static final int RESUME_JOB
    +
    +
    +
    + +

    +PROMOTE_JOB

    +
    +public static final int PROMOTE_JOB
    +
    +
    +
    + +

    +SCHEDULE_JOB_AFTER

    +
    +public static final int SCHEDULE_JOB_AFTER
    +
    +
    +
    + +

    +PRIVATE

    +
    +public static final int PRIVATE
    +
    +
    +
    + +

    +CUPS_GET_DEFAULT

    +
    +public static final int CUPS_GET_DEFAULT
    +
    +
    +
    + +

    +CUPS_GET_PRINTERS

    +
    +public static final int CUPS_GET_PRINTERS
    +
    +
    +
    + +

    +CUPS_ADD_PRINTER

    +
    +public static final int CUPS_ADD_PRINTER
    +
    +
    +
    + +

    +CUPS_DELETE_PRINTER

    +
    +public static final int CUPS_DELETE_PRINTER
    +
    +
    +
    + +

    +CUPS_GET_CLASSES

    +
    +public static final int CUPS_GET_CLASSES
    +
    +
    +
    + +

    +CUPS_ADD_CLASS

    +
    +public static final int CUPS_ADD_CLASS
    +
    +
    +
    + +

    +CUPS_DELETE_CLASS

    +
    +public static final int CUPS_DELETE_CLASS
    +
    +
    +
    + +

    +CUPS_ACCEPT_JOBS

    +
    +public static final int CUPS_ACCEPT_JOBS
    +
    +
    +
    + +

    +CUPS_REJECT_JOBS

    +
    +public static final int CUPS_REJECT_JOBS
    +
    +
    +
    + +

    +CUPS_SET_DEFAULT

    +
    +public static final int CUPS_SET_DEFAULT
    +
    +
    +
    + +

    +CUPS_GET_DEVICES

    +
    +public static final int CUPS_GET_DEVICES
    +
    +
    +
    + +

    +CUPS_GET_PPDS

    +
    +public static final int CUPS_GET_PPDS
    +
    +
    +
    + +

    +CUPS_MOVE_JOB

    +
    +public static final int CUPS_MOVE_JOB
    +
    +
    +
    + +

    +CUPS_ADD_DEVICE

    +
    +public static final int CUPS_ADD_DEVICE
    +
    +
    +
    + +

    +CUPS_DELETE_DEVICE

    +
    +public static final int CUPS_DELETE_DEVICE
    +
    +
    +
    + +

    +OK

    +
    +public static final int OK
    +
    +
    +
    + +

    +OK_SUBST

    +
    +public static final int OK_SUBST
    +
    +
    +
    + +

    +OK_CONFLICT

    +
    +public static final int OK_CONFLICT
    +
    +
    +
    + +

    +OK_IGNORED_SUBSCRIPTIONS

    +
    +public static final int OK_IGNORED_SUBSCRIPTIONS
    +
    +
    +
    + +

    +OK_IGNORED_NOTIFICATIONS

    +
    +public static final int OK_IGNORED_NOTIFICATIONS
    +
    +
    +
    + +

    +OK_TOO_MANY_EVENTS

    +
    +public static final int OK_TOO_MANY_EVENTS
    +
    +
    +
    + +

    +OK_BUT_CANCEL_SUBSCRIPTION

    +
    +public static final int OK_BUT_CANCEL_SUBSCRIPTION
    +
    +
    +
    + +

    +REDIRECTION_OTHER_SITE

    +
    +public static final int REDIRECTION_OTHER_SITE
    +
    +
    +
    + +

    +BAD_REQUEST

    +
    +public static final int BAD_REQUEST
    +
    +
    +
    + +

    +FORBIDDEN

    +
    +public static final int FORBIDDEN
    +
    +
    +
    + +

    +NOT_AUTHENTICATED

    +
    +public static final int NOT_AUTHENTICATED
    +
    +
    +
    + +

    +NOT_AUTHORIZED

    +
    +public static final int NOT_AUTHORIZED
    +
    +
    +
    + +

    +NOT_POSSIBLE

    +
    +public static final int NOT_POSSIBLE
    +
    +
    +
    + +

    +TIMEOUT

    +
    +public static final int TIMEOUT
    +
    +
    +
    + +

    +NOT_FOUND

    +
    +public static final int NOT_FOUND
    +
    +
    +
    + +

    +GONE

    +
    +public static final int GONE
    +
    +
    +
    + +

    +REQUEST_ENTITY

    +
    +public static final int REQUEST_ENTITY
    +
    +
    +
    + +

    +REQUEST_VALUE

    +
    +public static final int REQUEST_VALUE
    +
    +
    +
    + +

    +DOCUMENT_FORMAT

    +
    +public static final int DOCUMENT_FORMAT
    +
    +
    +
    + +

    +ATTRIBUTES

    +
    +public static final int ATTRIBUTES
    +
    +
    +
    + +

    +URI_SCHEME

    +
    +public static final int URI_SCHEME
    +
    +
    +
    + +

    +CHARSET

    +
    +public static final int CHARSET
    +
    +
    +
    + +

    +CONFLICT

    +
    +public static final int CONFLICT
    +
    +
    +
    + +

    +COMPRESSION_NOT_SUPPORTED

    +
    +public static final int COMPRESSION_NOT_SUPPORTED
    +
    +
    +
    + +

    +COMPRESSION_ERROR

    +
    +public static final int COMPRESSION_ERROR
    +
    +
    +
    + +

    +DOCUMENT_FORMAT_ERROR

    +
    +public static final int DOCUMENT_FORMAT_ERROR
    +
    +
    +
    + +

    +DOCUMENT_ACCESS_ERROR

    +
    +public static final int DOCUMENT_ACCESS_ERROR
    +
    +
    +
    + +

    +ATTRIBUTES_NOT_SETTABLE

    +
    +public static final int ATTRIBUTES_NOT_SETTABLE
    +
    +
    +
    + +

    +IGNORED_ALL_SUBSCRIPTIONS

    +
    +public static final int IGNORED_ALL_SUBSCRIPTIONS
    +
    +
    +
    + +

    +TOO_MANY_SUBSCRIPTIONS

    +
    +public static final int TOO_MANY_SUBSCRIPTIONS
    +
    +
    +
    + +

    +IGNORED_ALL_NOTIFICATIONS

    +
    +public static final int IGNORED_ALL_NOTIFICATIONS
    +
    +
    +
    + +

    +PRINT_SUPPORT_FILE_NOT_FOUND

    +
    +public static final int PRINT_SUPPORT_FILE_NOT_FOUND
    +
    +
    +
    + +

    +INTERNAL_ERROR

    +
    +public static final int INTERNAL_ERROR
    +
    +
    +
    + +

    +OPERATION_NOT_SUPPORTED

    +
    +public static final int OPERATION_NOT_SUPPORTED
    +
    +
    +
    + +

    +SERVICE_UNAVAILABLE

    +
    +public static final int SERVICE_UNAVAILABLE
    +
    +
    +
    + +

    +VERSION_NOT_SUPPORTED

    +
    +public static final int VERSION_NOT_SUPPORTED
    +
    +
    +
    + +

    +DEVICE_ERROR

    +
    +public static final int DEVICE_ERROR
    +
    +
    +
    + +

    +TEMPORARY_ERROR

    +
    +public static final int TEMPORARY_ERROR
    +
    +
    +
    + +

    +NOT_ACCEPTING

    +
    +public static final int NOT_ACCEPTING
    +
    +
    +
    + +

    +PRINTER_BUSY

    +
    +public static final int PRINTER_BUSY
    +
    +
    +
    + +

    +ERROR_JOB_CANCELLED

    +
    +public static final int ERROR_JOB_CANCELLED
    +
    +
    +
    + +

    +MULTIPLE_JOBS_NOT_SUPPORTED

    +
    +public static final int MULTIPLE_JOBS_NOT_SUPPORTED
    +
    +
    +
    + +

    +PRINTER_IS_DEACTIVATED

    +
    +public static final int PRINTER_IS_DEACTIVATED
    +
    +
    + + + + + + + + +
    +Constructor Detail
    + +

    +IPPDefs

    +
    +public IPPDefs()
    +
    +
    + + + + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPPError.html b/scripting/java/docs/com/easysw/cups/IPPError.html new file mode 100644 index 000000000..395f43759 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPPError.html @@ -0,0 +1,178 @@ + + + + + + +: Class IPPError + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPPError

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.IPPError
    +
    +
    +
    +
    public class IPPError
    extends java.lang.Object
    + +

    +


    + +

    + + + + + + + + + + + + + + + + +
    +Constructor Summary
    IPPError(int p_error) + +
    +          Constructor that sets error_string after creation.
    +  + + + + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + + + + +
    +Constructor Detail
    + +

    +IPPError

    +
    +public IPPError(int p_error)
    +
    +
    Constructor that sets error_string after creation.
    +
    Parameters:
    error_number - Error number to convert.
    See Also:
    IPPDefs
    +
    +
    + + + + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPPHttp.html b/scripting/java/docs/com/easysw/cups/IPPHttp.html new file mode 100644 index 000000000..2e6befb65 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPPHttp.html @@ -0,0 +1,2596 @@ + + + + + + +: Class IPPHttp + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPPHttp

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.IPPHttp
    +
    +
    +
    +
    public class IPPHttp
    extends java.lang.Object
    + +

    +


    + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Field Summary
    + intactivity + +
    +           
    + java.lang.Stringauth_type + +
    +           
    + java.io.BufferedReaderbr + +
    +           
    + java.net.Socketconn + +
    +           
    + booleanconnected + +
    +           
    +static java.lang.String[]days + +
    +           
    + interror + +
    +           
    + java.lang.Stringhostname + +
    +           
    +static intHTTP_0_9 + +
    +           
    +static intHTTP_1_0 + +
    +           
    +static intHTTP_1_1 + +
    +           
    +static intHTTP_ACCEPTED + +
    +           
    +static intHTTP_AUTH_BASIC + +
    +           
    +static intHTTP_AUTH_MD5 + +
    +           
    +static intHTTP_AUTH_MD5_INT + +
    +           
    +static intHTTP_AUTH_MD5_SESS + +
    +           
    +static intHTTP_AUTH_MD5_SESS_INT + +
    +           
    +static intHTTP_AUTH_NONE + +
    +           
    +static intHTTP_BAD_GATEWAY + +
    +           
    +static intHTTP_BAD_REQUEST + +
    +           
    +static intHTTP_CLOSE + +
    +           
    +static intHTTP_CONFLICT + +
    +           
    + inthttp_content_length + +
    +           
    +static intHTTP_CONTINUE + +
    +           
    +static intHTTP_CREATED + +
    +           
    +static intHTTP_DELETE + +
    +           
    +static intHTTP_ENCODE_CHUNKED + +
    +           
    +static intHTTP_ENCODE_LENGTH + +
    +           
    +static intHTTP_ENCRYPT_ALWAYS + +
    +           
    +static intHTTP_ENCRYPT_IF_REQUESTED + +
    +           
    +static intHTTP_ENCRYPT_NEVER + +
    +           
    +static intHTTP_ENCRYPT_REQUIRED + +
    +           
    +static intHTTP_ERROR + +
    +           
    +static intHTTP_FIELD_ACCEPT_LANGUAGE + +
    +           
    +static intHTTP_FIELD_ACCEPT_RANGES + +
    +           
    +static intHTTP_FIELD_AUTHORIZATION + +
    +           
    +static intHTTP_FIELD_CONNECTION + +
    +           
    +static intHTTP_FIELD_CONTENT_ENCODING + +
    +           
    +static intHTTP_FIELD_CONTENT_LANGUAGE + +
    +           
    +static intHTTP_FIELD_CONTENT_LENGTH + +
    +           
    +static intHTTP_FIELD_CONTENT_LOCATION + +
    +           
    +static intHTTP_FIELD_CONTENT_MD5 + +
    +           
    +static intHTTP_FIELD_CONTENT_RANGE + +
    +           
    +static intHTTP_FIELD_CONTENT_TYPE + +
    +           
    +static intHTTP_FIELD_CONTENT_VERSION + +
    +           
    +static intHTTP_FIELD_DATE + +
    +           
    +static intHTTP_FIELD_HOST + +
    +           
    +static intHTTP_FIELD_IF_MODIFIED_SINCE + +
    +           
    +static intHTTP_FIELD_IF_UNMODIFIED_SINCE + +
    +           
    +static intHTTP_FIELD_KEEP_ALIVE + +
    +           
    +static intHTTP_FIELD_LAST_MODIFIED + +
    +           
    +static intHTTP_FIELD_LINK + +
    +           
    +static intHTTP_FIELD_LOCATION + +
    +           
    +static intHTTP_FIELD_MAX + +
    +           
    +static intHTTP_FIELD_RANGE + +
    +           
    +static intHTTP_FIELD_REFERER + +
    +           
    +static intHTTP_FIELD_RETRY_AFTER + +
    +           
    +static intHTTP_FIELD_TRANSFER_ENCODING + +
    +           
    +static intHTTP_FIELD_UNKNOWN + +
    +           
    +static intHTTP_FIELD_UPGRADE + +
    +           
    +static intHTTP_FIELD_USER_AGENT + +
    +           
    +static intHTTP_FIELD_WWW_AUTHENTICATE + +
    +           
    +static java.lang.String[]http_fields + +
    +           
    +static intHTTP_FORBIDDEN + +
    +           
    +static intHTTP_GATEWAY_TIMEOUT + +
    +           
    +static intHTTP_GET + +
    +           
    +static intHTTP_GET_SEND + +
    +           
    +static intHTTP_GONE + +
    +           
    +static intHTTP_HEAD + +
    +           
    +static intHTTP_KEEPALIVE_OFF + +
    +           
    +static intHTTP_KEEPALIVE_ON + +
    +           
    +static intHTTP_LENGTH_REQUIRED + +
    +           
    +static intHTTP_METHOD_NOT_ALLOWED + +
    +           
    +static intHTTP_MOVED_PERMANENTLY + +
    +           
    +static intHTTP_MOVED_TEMPORARILY + +
    +           
    +static intHTTP_MULTIPLE_CHOICES + +
    +           
    +static intHTTP_NO_CONTENT + +
    +           
    +static intHTTP_NOT_ACCEPTABLE + +
    +           
    +static intHTTP_NOT_AUTHORITATIVE + +
    +           
    +static intHTTP_NOT_FOUND + +
    +           
    +static intHTTP_NOT_IMPLEMENTED + +
    +           
    +static intHTTP_NOT_MODIFIED + +
    +           
    +static intHTTP_NOT_SUPPORTED + +
    +           
    +static intHTTP_OK + +
    +           
    +static intHTTP_OPTIONS + +
    +           
    +static intHTTP_PARTIAL_CONTENT + +
    +           
    +static intHTTP_PAYMENT_REQUIRED + +
    +           
    +static intHTTP_POST + +
    +           
    +static intHTTP_POST_RECV + +
    +           
    +static intHTTP_POST_SEND + +
    +           
    +static intHTTP_PRECONDITION + +
    +           
    +static intHTTP_PROXY_AUTHENTICATION + +
    +           
    +static intHTTP_PUT + +
    +           
    +static intHTTP_PUT_RECV + +
    +           
    + java.lang.Stringhttp_request + +
    +           
    +static intHTTP_REQUEST_TIMEOUT + +
    +           
    +static intHTTP_REQUEST_TOO_LARGE + +
    +           
    +static intHTTP_RESET_CONTENT + +
    +           
    +static intHTTP_SEE_OTHER + +
    +           
    +static intHTTP_SERVER_ERROR + +
    +           
    +static intHTTP_SERVICE_UNAVAILABLE + +
    +           
    +static intHTTP_STATUS + +
    +           
    +static intHTTP_SWITCHING_PROTOCOLS + +
    +           
    +static intHTTP_TRACE + +
    +           
    +static intHTTP_UNAUTHORIZED + +
    +           
    +static intHTTP_UNSUPPORTED_MEDIATYPE + +
    +           
    +static intHTTP_UPGRADE_REQUIRED + +
    +           
    +static intHTTP_URI_TOO_LONG + +
    +           
    +static intHTTP_USE_PROXY + +
    +           
    +static intHTTP_WAITING + +
    +          Class constants - most not in use yet.
    + java.io.BufferedInputStreamis + +
    +           
    + java.lang.Stringmethod + +
    +           
    +static java.lang.String[]months + +
    +           
    + java.lang.Stringnonce + +
    +           
    + java.lang.Stringopaque + +
    +           
    + java.io.BufferedOutputStreamos + +
    +           
    + java.lang.Stringpasswd + +
    +           
    + java.lang.Stringpath + +
    +           
    + intport + +
    +           
    + char[]read_buffer + +
    +           
    + java.lang.Stringread_header_charset + +
    +           
    + java.lang.Stringread_header_content_language + +
    +           
    + intread_header_content_length + +
    +           
    + java.lang.Stringread_header_content_type + +
    +           
    + java.lang.Stringread_header_date + +
    +           
    + java.lang.Stringread_header_server + +
    +           
    + java.lang.Stringrealm + +
    +           
    + java.lang.Stringresource + +
    +           
    + intstatus + +
    +           
    + java.lang.Stringstatus_text + +
    +           
    + java.lang.Stringuser + +
    +           
    + java.lang.Stringversion + +
    +           
    + intwrite_content_length + +
    +           
    +  + + + + + + + + + + + + + +
    +Constructor Summary
    IPPHttp(java.lang.String request_url) + +
    +          Constructor using URL.
    IPPHttp(java.lang.String request_url, + java.lang.String p_auth_type, + java.lang.String p_user, + java.lang.String p_passwd) + +
    +          Constructor using URL, user and pass.
    +  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Method Summary
    + intcheckForResponse() + +
    +           
    + voidparseAuthenticate(java.lang.String p_auth) + +
    +           
    + IPPprocessResponse() + +
    +          Process the HTTP response from the server.
    + intread_header() + +
    +          Read the HTTP header from the input stream.
    + java.lang.Stringread_line() + +
    +          Read a line from the input stream.
    + char[]read(int count) + +
    +          Read up to count bytes from the input stream.
    + booleanreConnect() + +
    +          Re-establish a dropped connection.
    + voidsetPassword(java.lang.String p_passwd) + +
    +          Set the password.
    + voidsetUser(java.lang.String p_user) + +
    +          Set the user name.
    + voidwrite(byte[] bytes) + +
    +          Write bytes to the output stream.
    + voidwrite(byte[] bytes, + int length) + +
    +          Write bytes to the output stream.
    + intwriteHeader(java.lang.String request, + int content_length) + +
    +          Write the request header bytes to the server.
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + +
    +Field Detail
    + +

    +HTTP_WAITING

    +
    +public static final int HTTP_WAITING
    +
    +
    Class constants - most not in use yet.
    +
    + +

    +HTTP_OPTIONS

    +
    +public static final int HTTP_OPTIONS
    +
    +
    +
    + +

    +HTTP_GET

    +
    +public static final int HTTP_GET
    +
    +
    +
    + +

    +HTTP_GET_SEND

    +
    +public static final int HTTP_GET_SEND
    +
    +
    +
    + +

    +HTTP_HEAD

    +
    +public static final int HTTP_HEAD
    +
    +
    +
    + +

    +HTTP_POST

    +
    +public static final int HTTP_POST
    +
    +
    +
    + +

    +HTTP_POST_RECV

    +
    +public static final int HTTP_POST_RECV
    +
    +
    +
    + +

    +HTTP_POST_SEND

    +
    +public static final int HTTP_POST_SEND
    +
    +
    +
    + +

    +HTTP_PUT

    +
    +public static final int HTTP_PUT
    +
    +
    +
    + +

    +HTTP_PUT_RECV

    +
    +public static final int HTTP_PUT_RECV
    +
    +
    +
    + +

    +HTTP_DELETE

    +
    +public static final int HTTP_DELETE
    +
    +
    +
    + +

    +HTTP_TRACE

    +
    +public static final int HTTP_TRACE
    +
    +
    +
    + +

    +HTTP_CLOSE

    +
    +public static final int HTTP_CLOSE
    +
    +
    +
    + +

    +HTTP_STATUS

    +
    +public static final int HTTP_STATUS
    +
    +
    +
    + +

    +HTTP_0_9

    +
    +public static final int HTTP_0_9
    +
    +
    +
    + +

    +HTTP_1_0

    +
    +public static final int HTTP_1_0
    +
    +
    +
    + +

    +HTTP_1_1

    +
    +public static final int HTTP_1_1
    +
    +
    +
    + +

    +HTTP_KEEPALIVE_OFF

    +
    +public static final int HTTP_KEEPALIVE_OFF
    +
    +
    +
    + +

    +HTTP_KEEPALIVE_ON

    +
    +public static final int HTTP_KEEPALIVE_ON
    +
    +
    +
    + +

    +HTTP_ENCODE_LENGTH

    +
    +public static final int HTTP_ENCODE_LENGTH
    +
    +
    +
    + +

    +HTTP_ENCODE_CHUNKED

    +
    +public static final int HTTP_ENCODE_CHUNKED
    +
    +
    +
    + +

    +HTTP_ENCRYPT_IF_REQUESTED

    +
    +public static final int HTTP_ENCRYPT_IF_REQUESTED
    +
    +
    +
    + +

    +HTTP_ENCRYPT_NEVER

    +
    +public static final int HTTP_ENCRYPT_NEVER
    +
    +
    +
    + +

    +HTTP_ENCRYPT_REQUIRED

    +
    +public static final int HTTP_ENCRYPT_REQUIRED
    +
    +
    +
    + +

    +HTTP_ENCRYPT_ALWAYS

    +
    +public static final int HTTP_ENCRYPT_ALWAYS
    +
    +
    +
    + +

    +HTTP_AUTH_NONE

    +
    +public static final int HTTP_AUTH_NONE
    +
    +
    +
    + +

    +HTTP_AUTH_BASIC

    +
    +public static final int HTTP_AUTH_BASIC
    +
    +
    +
    + +

    +HTTP_AUTH_MD5

    +
    +public static final int HTTP_AUTH_MD5
    +
    +
    +
    + +

    +HTTP_AUTH_MD5_SESS

    +
    +public static final int HTTP_AUTH_MD5_SESS
    +
    +
    +
    + +

    +HTTP_AUTH_MD5_INT

    +
    +public static final int HTTP_AUTH_MD5_INT
    +
    +
    +
    + +

    +HTTP_AUTH_MD5_SESS_INT

    +
    +public static final int HTTP_AUTH_MD5_SESS_INT
    +
    +
    +
    + +

    +HTTP_ERROR

    +
    +public static final int HTTP_ERROR
    +
    +
    +
    + +

    +HTTP_CONTINUE

    +
    +public static final int HTTP_CONTINUE
    +
    +
    +
    + +

    +HTTP_SWITCHING_PROTOCOLS

    +
    +public static final int HTTP_SWITCHING_PROTOCOLS
    +
    +
    +
    + +

    +HTTP_OK

    +
    +public static final int HTTP_OK
    +
    +
    +
    + +

    +HTTP_CREATED

    +
    +public static final int HTTP_CREATED
    +
    +
    +
    + +

    +HTTP_ACCEPTED

    +
    +public static final int HTTP_ACCEPTED
    +
    +
    +
    + +

    +HTTP_NOT_AUTHORITATIVE

    +
    +public static final int HTTP_NOT_AUTHORITATIVE
    +
    +
    +
    + +

    +HTTP_NO_CONTENT

    +
    +public static final int HTTP_NO_CONTENT
    +
    +
    +
    + +

    +HTTP_RESET_CONTENT

    +
    +public static final int HTTP_RESET_CONTENT
    +
    +
    +
    + +

    +HTTP_PARTIAL_CONTENT

    +
    +public static final int HTTP_PARTIAL_CONTENT
    +
    +
    +
    + +

    +HTTP_MULTIPLE_CHOICES

    +
    +public static final int HTTP_MULTIPLE_CHOICES
    +
    +
    +
    + +

    +HTTP_MOVED_PERMANENTLY

    +
    +public static final int HTTP_MOVED_PERMANENTLY
    +
    +
    +
    + +

    +HTTP_MOVED_TEMPORARILY

    +
    +public static final int HTTP_MOVED_TEMPORARILY
    +
    +
    +
    + +

    +HTTP_SEE_OTHER

    +
    +public static final int HTTP_SEE_OTHER
    +
    +
    +
    + +

    +HTTP_NOT_MODIFIED

    +
    +public static final int HTTP_NOT_MODIFIED
    +
    +
    +
    + +

    +HTTP_USE_PROXY

    +
    +public static final int HTTP_USE_PROXY
    +
    +
    +
    + +

    +HTTP_BAD_REQUEST

    +
    +public static final int HTTP_BAD_REQUEST
    +
    +
    +
    + +

    +HTTP_UNAUTHORIZED

    +
    +public static final int HTTP_UNAUTHORIZED
    +
    +
    +
    + +

    +HTTP_PAYMENT_REQUIRED

    +
    +public static final int HTTP_PAYMENT_REQUIRED
    +
    +
    +
    + +

    +HTTP_FORBIDDEN

    +
    +public static final int HTTP_FORBIDDEN
    +
    +
    +
    + +

    +HTTP_NOT_FOUND

    +
    +public static final int HTTP_NOT_FOUND
    +
    +
    +
    + +

    +HTTP_METHOD_NOT_ALLOWED

    +
    +public static final int HTTP_METHOD_NOT_ALLOWED
    +
    +
    +
    + +

    +HTTP_NOT_ACCEPTABLE

    +
    +public static final int HTTP_NOT_ACCEPTABLE
    +
    +
    +
    + +

    +HTTP_PROXY_AUTHENTICATION

    +
    +public static final int HTTP_PROXY_AUTHENTICATION
    +
    +
    +
    + +

    +HTTP_REQUEST_TIMEOUT

    +
    +public static final int HTTP_REQUEST_TIMEOUT
    +
    +
    +
    + +

    +HTTP_CONFLICT

    +
    +public static final int HTTP_CONFLICT
    +
    +
    +
    + +

    +HTTP_GONE

    +
    +public static final int HTTP_GONE
    +
    +
    +
    + +

    +HTTP_LENGTH_REQUIRED

    +
    +public static final int HTTP_LENGTH_REQUIRED
    +
    +
    +
    + +

    +HTTP_PRECONDITION

    +
    +public static final int HTTP_PRECONDITION
    +
    +
    +
    + +

    +HTTP_REQUEST_TOO_LARGE

    +
    +public static final int HTTP_REQUEST_TOO_LARGE
    +
    +
    +
    + +

    +HTTP_URI_TOO_LONG

    +
    +public static final int HTTP_URI_TOO_LONG
    +
    +
    +
    + +

    +HTTP_UNSUPPORTED_MEDIATYPE

    +
    +public static final int HTTP_UNSUPPORTED_MEDIATYPE
    +
    +
    +
    + +

    +HTTP_UPGRADE_REQUIRED

    +
    +public static final int HTTP_UPGRADE_REQUIRED
    +
    +
    +
    + +

    +HTTP_SERVER_ERROR

    +
    +public static final int HTTP_SERVER_ERROR
    +
    +
    +
    + +

    +HTTP_NOT_IMPLEMENTED

    +
    +public static final int HTTP_NOT_IMPLEMENTED
    +
    +
    +
    + +

    +HTTP_BAD_GATEWAY

    +
    +public static final int HTTP_BAD_GATEWAY
    +
    +
    +
    + +

    +HTTP_SERVICE_UNAVAILABLE

    +
    +public static final int HTTP_SERVICE_UNAVAILABLE
    +
    +
    +
    + +

    +HTTP_GATEWAY_TIMEOUT

    +
    +public static final int HTTP_GATEWAY_TIMEOUT
    +
    +
    +
    + +

    +HTTP_NOT_SUPPORTED

    +
    +public static final int HTTP_NOT_SUPPORTED
    +
    +
    +
    + +

    +HTTP_FIELD_UNKNOWN

    +
    +public static final int HTTP_FIELD_UNKNOWN
    +
    +
    +
    + +

    +HTTP_FIELD_ACCEPT_LANGUAGE

    +
    +public static final int HTTP_FIELD_ACCEPT_LANGUAGE
    +
    +
    +
    + +

    +HTTP_FIELD_ACCEPT_RANGES

    +
    +public static final int HTTP_FIELD_ACCEPT_RANGES
    +
    +
    +
    + +

    +HTTP_FIELD_AUTHORIZATION

    +
    +public static final int HTTP_FIELD_AUTHORIZATION
    +
    +
    +
    + +

    +HTTP_FIELD_CONNECTION

    +
    +public static final int HTTP_FIELD_CONNECTION
    +
    +
    +
    + +

    +HTTP_FIELD_CONTENT_ENCODING

    +
    +public static final int HTTP_FIELD_CONTENT_ENCODING
    +
    +
    +
    + +

    +HTTP_FIELD_CONTENT_LANGUAGE

    +
    +public static final int HTTP_FIELD_CONTENT_LANGUAGE
    +
    +
    +
    + +

    +HTTP_FIELD_CONTENT_LENGTH

    +
    +public static final int HTTP_FIELD_CONTENT_LENGTH
    +
    +
    +
    + +

    +HTTP_FIELD_CONTENT_LOCATION

    +
    +public static final int HTTP_FIELD_CONTENT_LOCATION
    +
    +
    +
    + +

    +HTTP_FIELD_CONTENT_MD5

    +
    +public static final int HTTP_FIELD_CONTENT_MD5
    +
    +
    +
    + +

    +HTTP_FIELD_CONTENT_RANGE

    +
    +public static final int HTTP_FIELD_CONTENT_RANGE
    +
    +
    +
    + +

    +HTTP_FIELD_CONTENT_TYPE

    +
    +public static final int HTTP_FIELD_CONTENT_TYPE
    +
    +
    +
    + +

    +HTTP_FIELD_CONTENT_VERSION

    +
    +public static final int HTTP_FIELD_CONTENT_VERSION
    +
    +
    +
    + +

    +HTTP_FIELD_DATE

    +
    +public static final int HTTP_FIELD_DATE
    +
    +
    +
    + +

    +HTTP_FIELD_HOST

    +
    +public static final int HTTP_FIELD_HOST
    +
    +
    +
    + +

    +HTTP_FIELD_IF_MODIFIED_SINCE

    +
    +public static final int HTTP_FIELD_IF_MODIFIED_SINCE
    +
    +
    +
    + +

    +HTTP_FIELD_IF_UNMODIFIED_SINCE

    +
    +public static final int HTTP_FIELD_IF_UNMODIFIED_SINCE
    +
    +
    +
    + +

    +HTTP_FIELD_KEEP_ALIVE

    +
    +public static final int HTTP_FIELD_KEEP_ALIVE
    +
    +
    +
    + +

    +HTTP_FIELD_LAST_MODIFIED

    +
    +public static final int HTTP_FIELD_LAST_MODIFIED
    +
    +
    +
    + +

    +HTTP_FIELD_LINK

    +
    +public static final int HTTP_FIELD_LINK
    +
    +
    +
    + +

    +HTTP_FIELD_LOCATION

    +
    +public static final int HTTP_FIELD_LOCATION
    +
    +
    +
    + +

    +HTTP_FIELD_RANGE

    +
    +public static final int HTTP_FIELD_RANGE
    +
    +
    +
    + +

    +HTTP_FIELD_REFERER

    +
    +public static final int HTTP_FIELD_REFERER
    +
    +
    +
    + +

    +HTTP_FIELD_RETRY_AFTER

    +
    +public static final int HTTP_FIELD_RETRY_AFTER
    +
    +
    +
    + +

    +HTTP_FIELD_TRANSFER_ENCODING

    +
    +public static final int HTTP_FIELD_TRANSFER_ENCODING
    +
    +
    +
    + +

    +HTTP_FIELD_UPGRADE

    +
    +public static final int HTTP_FIELD_UPGRADE
    +
    +
    +
    + +

    +HTTP_FIELD_USER_AGENT

    +
    +public static final int HTTP_FIELD_USER_AGENT
    +
    +
    +
    + +

    +HTTP_FIELD_WWW_AUTHENTICATE

    +
    +public static final int HTTP_FIELD_WWW_AUTHENTICATE
    +
    +
    +
    + +

    +HTTP_FIELD_MAX

    +
    +public static final int HTTP_FIELD_MAX
    +
    +
    +
    + +

    +http_fields

    +
    +public static final java.lang.String[] http_fields
    +
    +
    +
    + +

    +days

    +
    +public static final java.lang.String[] days
    +
    +
    +
    + +

    +months

    +
    +public static final java.lang.String[] months
    +
    +
    +
    + +

    +conn

    +
    +public java.net.Socket conn
    +
    +
    +
    + +

    +connected

    +
    +public boolean connected
    +
    +
    +
    + +

    +is

    +
    +public java.io.BufferedInputStream is
    +
    +
    +
    + +

    +br

    +
    +public java.io.BufferedReader br
    +
    +
    +
    + +

    +os

    +
    +public java.io.BufferedOutputStream os
    +
    +
    +
    + +

    +write_content_length

    +
    +public int write_content_length
    +
    +
    +
    + +

    +read_header_date

    +
    +public java.lang.String read_header_date
    +
    +
    +
    + +

    +read_header_server

    +
    +public java.lang.String read_header_server
    +
    +
    +
    + +

    +read_header_charset

    +
    +public java.lang.String read_header_charset
    +
    +
    +
    + +

    +read_header_content_language

    +
    +public java.lang.String read_header_content_language
    +
    +
    +
    + +

    +read_header_content_type

    +
    +public java.lang.String read_header_content_type
    +
    +
    +
    + +

    +read_header_content_length

    +
    +public int read_header_content_length
    +
    +
    +
    + +

    +read_buffer

    +
    +public char[] read_buffer
    +
    +
    +
    + +

    +status

    +
    +public int status
    +
    +
    +
    + +

    +status_text

    +
    +public java.lang.String status_text
    +
    +
    +
    + +

    +version

    +
    +public java.lang.String version
    +
    +
    +
    + +

    +error

    +
    +public int error
    +
    +
    +
    + +

    +activity

    +
    +public int activity
    +
    +
    +
    + +

    +hostname

    +
    +public java.lang.String hostname
    +
    +
    +
    + +

    +port

    +
    +public int port
    +
    +
    +
    + +

    +path

    +
    +public java.lang.String path
    +
    +
    +
    + +

    +user

    +
    +public java.lang.String user
    +
    +
    +
    + +

    +passwd

    +
    +public java.lang.String passwd
    +
    +
    +
    + +

    +auth_type

    +
    +public java.lang.String auth_type
    +
    +
    +
    + +

    +realm

    +
    +public java.lang.String realm
    +
    +
    +
    + +

    +opaque

    +
    +public java.lang.String opaque
    +
    +
    +
    + +

    +nonce

    +
    +public java.lang.String nonce
    +
    +
    +
    + +

    +resource

    +
    +public java.lang.String resource
    +
    +
    +
    + +

    +method

    +
    +public java.lang.String method
    +
    +
    +
    + +

    +http_request

    +
    +public java.lang.String http_request
    +
    +
    +
    + +

    +http_content_length

    +
    +public int http_content_length
    +
    +
    + + + + + + + + +
    +Constructor Detail
    + +

    +IPPHttp

    +
    +public IPPHttp(java.lang.String request_url)
    +        throws java.io.IOException,
    +               java.net.UnknownHostException
    +
    +
    Constructor using URL.
    +
    Parameters:
    request_url - URL of server to connect to.
    +
    +
    +
    + +

    +IPPHttp

    +
    +public IPPHttp(java.lang.String request_url,
    +               java.lang.String p_auth_type,
    +               java.lang.String p_user,
    +               java.lang.String p_passwd)
    +        throws java.io.IOException,
    +               java.net.UnknownHostException
    +
    +
    Constructor using URL, user and pass.
    +
    Parameters:
    request_url - URL of server to connect to.
    p_auth_type - String basic or digest.
    p_user - String User name.
    p_passwd - String password.
    +
    +
    + + + + + + + + +
    +Method Detail
    + +

    +reConnect

    +
    +public boolean reConnect()
    +                  throws java.io.IOException
    +
    +
    Re-establish a dropped connection.
    +
    Returns:
    boolean True if connected.
    +
    +
    +
    + +

    +setUser

    +
    +public void setUser(java.lang.String p_user)
    +
    +
    Set the user name.
    +
    Parameters:
    p_user - String - user name.
    +
    +
    +
    + +

    +setPassword

    +
    +public void setPassword(java.lang.String p_passwd)
    +
    +
    Set the password.
    +
    Parameters:
    p_passwd - String - password.
    +
    +
    +
    + +

    +writeHeader

    +
    +public int writeHeader(java.lang.String request,
    +                       int content_length)
    +                throws java.io.IOException
    +
    +
    Write the request header bytes to the server.
    +
    Parameters:
    request - String - the request.
    content_length - int - size of the total request.
    +
    +
    +
    + +

    +checkForResponse

    +
    +public int checkForResponse()
    +
    +
    +
    + +

    +write

    +
    +public void write(byte[] bytes)
    +           throws java.io.IOException
    +
    +
    Write bytes to the output stream.
    +
    Parameters:
    bytes - Array of bytes to write to the stream.
    +
    +
    +
    + +

    +write

    +
    +public void write(byte[] bytes,
    +                  int length)
    +           throws java.io.IOException
    +
    +
    Write bytes to the output stream.
    +
    Parameters:
    bytes - Array of bytes to write to the stream.
    length - Number of bytes to write to the stream.
    +
    +
    +
    + +

    +read_header

    +
    +public int read_header()
    +                throws java.io.IOException
    +
    +
    Read the HTTP header from the input stream.
    +
    Returns:
    int Content length of response.
    +
    +
    +
    + +

    +read_line

    +
    +public java.lang.String read_line()
    +                           throws java.io.IOException
    +
    +
    Read a line from the input stream.
    +
    Returns:
    String Line read.
    +
    +
    +
    + +

    +read

    +
    +public char[] read(int count)
    +            throws java.io.IOException
    +
    +
    Read up to count bytes from the input stream.
    +
    Parameters:
    count - Number of bytes to read.
    Returns:
    char[] Character array of data read.
    +
    +
    +
    + +

    +processResponse

    +
    +public IPP processResponse()
    +
    +
    Process the HTTP response from the server.
    +
    Returns:
    IPP IPP object containing response data.
    See Also:
    IPP, +IPPRequest, +IPPAttribute, +IPPValue, +IPPDefs
    +
    +
    +
    + +

    +parseAuthenticate

    +
    +public void parseAuthenticate(java.lang.String p_auth)
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPPRequest.html b/scripting/java/docs/com/easysw/cups/IPPRequest.html new file mode 100644 index 000000000..82361d90f --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPPRequest.html @@ -0,0 +1,251 @@ + + + + + + +: Class IPPRequest + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPPRequest

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.IPPRequest
    +
    +
    +
    +
    public class IPPRequest
    extends java.lang.Object
    + +

    +An IPPRequest object is used to hold the + status and id's of a request. +

    +

    +
    Since:
    JDK1.3
    +
    +
    + +

    + + + + + + + + + + + + + + + + + + + +
    +Constructor Summary
    IPPRequest() + +
    +          Constructor
    IPPRequest(int p_request_id, + short p_operation_id) + +
    +          Constructor using request id and operation id.
    +  + + + + + + + + + + + + + + + +
    +Method Summary
    + voidsetOpStatus(short p_status_code) + +
    +          Set the operation status of a request.
    + voidsetStatus(short p_status_code) + +
    +          Set the current status of a request.
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + + + + +
    +Constructor Detail
    + +

    +IPPRequest

    +
    +public IPPRequest()
    +
    +
    Constructor
    +
    + +

    +IPPRequest

    +
    +public IPPRequest(int p_request_id,
    +                  short p_operation_id)
    +
    +
    Constructor using request id and operation id.
    +
    Parameters:
    p_request_id - ID of request.
    p_operation_id - Operation ID for request.
    See Also:
    IPPDefs
    +
    +
    + + + + + + + + +
    +Method Detail
    + +

    +setStatus

    +
    +public void setStatus(short p_status_code)
    +
    +
    Set the current status of a request.
    +
    Parameters:
    p_status_code - Status code.
    See Also:
    IPPDefs
    +
    +
    +
    + +

    +setOpStatus

    +
    +public void setOpStatus(short p_status_code)
    +
    +
    Set the operation status of a request.
    +
    Parameters:
    p_status_code - Operation status code.
    See Also:
    IPPDefs
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPPStatus.html b/scripting/java/docs/com/easysw/cups/IPPStatus.html new file mode 100644 index 000000000..ba8bcaad4 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPPStatus.html @@ -0,0 +1,185 @@ + + + + + + +: Class IPPStatus + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPPStatus

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.IPPStatus
    +
    +
    +
    +
    public class IPPStatus
    extends java.lang.Object
    + +

    +Class to convert a status code to text. +

    +

    +
    Since:
    JDK1.3
    +
    +
    + +

    + + + + + + + + + + + + + + + + +
    +Constructor Summary
    IPPStatus(int p_status) + +
    +          Constructor, access the status_text member + after creation.
    +  + + + + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + + + + +
    +Constructor Detail
    + +

    +IPPStatus

    +
    +public IPPStatus(int p_status)
    +
    +
    Constructor, access the status_text member + after creation.
    +
    Parameters:
    p_status - Status code to convert.
    See Also:
    IPPDefs
    +
    +
    + + + + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPPURLConnection.html b/scripting/java/docs/com/easysw/cups/IPPURLConnection.html new file mode 100644 index 000000000..3a02e1ae2 --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPPURLConnection.html @@ -0,0 +1,262 @@ + + + + + + +: Class IPPURLConnection + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPPURLConnection

    +
    +java.lang.Object
    +  |
    +  +--java.net.URLConnection
    +        |
    +        +--com.easysw.cups.IPPURLConnection
    +
    +
    +
    +
    public class IPPURLConnection
    extends java.net.URLConnection
    + +

    +


    + +

    + + + + + + + + + + + + + +
    Fields inherited from class java.net.URLConnection
    allowUserInteraction, connected, doInput, doOutput, ifModifiedSince, url, useCaches
    +  + + + + + + + + + + +
    +Constructor Summary
    IPPURLConnection(java.net.URL url) + +
    +          Constructor.
    +  + + + + + + + + + + + + + + + + + + + +
    +Method Summary
    + voidconnect() + +
    +          Not used.
    + voiddisconnect() + +
    +          Not used.
    + booleanusingProxy() + +
    +          Determine if using proxy.
    + + + + + + + +
    Methods inherited from class java.net.URLConnection
    getAllowUserInteraction, getContent, getContent, getContentEncoding, getContentLength, getContentType, getDate, getDefaultAllowUserInteraction, getDefaultRequestProperty, getDefaultUseCaches, getDoInput, getDoOutput, getExpiration, getFileNameMap, getHeaderField, getHeaderField, getHeaderFieldDate, getHeaderFieldInt, getHeaderFieldKey, getIfModifiedSince, getInputStream, getLastModified, getOutputStream, getPermission, getRequestProperty, getURL, getUseCaches, guessContentTypeFromName, guessContentTypeFromStream, setAllowUserInteraction, setContentHandlerFactory, setDefaultAllowUserInteraction, setDefaultRequestProperty, setDefaultUseCaches, setDoInput, setDoOutput, setFileNameMap, setIfModifiedSince, setRequestProperty, setUseCaches, toString
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
    +  +

    + + + + + + + + + + + +
    +Constructor Detail
    + +

    +IPPURLConnection

    +
    +public IPPURLConnection(java.net.URL url)
    +
    +
    Constructor.
    + + + + + + + + +
    +Method Detail
    + +

    +usingProxy

    +
    +public boolean usingProxy()
    +
    +
    Determine if using proxy.
    +
    Returns:
    boolean Always false for now.
    +
    +
    +
    + +

    +connect

    +
    +public void connect()
    +
    +
    Not used.
    +
    Overrides:
    connect in class java.net.URLConnection
    +
    +
    +
    + +

    +disconnect

    +
    +public void disconnect()
    +
    +
    Not used.
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/com/easysw/cups/IPPValue.html b/scripting/java/docs/com/easysw/cups/IPPValue.html new file mode 100644 index 000000000..96df5bc3a --- /dev/null +++ b/scripting/java/docs/com/easysw/cups/IPPValue.html @@ -0,0 +1,376 @@ + + + + + + +: Class IPPValue + + + + + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + +

    + +com.easysw.cups +
    +Class IPPValue

    +
    +java.lang.Object
    +  |
    +  +--com.easysw.cups.IPPValue
    +
    +
    +
    +
    public class IPPValue
    extends java.lang.Object
    + +

    +


    + +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    +Constructor Summary
    IPPValue(boolean p_boolean) + +
    +          Boolean constructor.
    IPPValue(byte p_byte) + +
    +          Byte constructor.
    IPPValue(byte p_units, + int p_xres, + int p_yres) + +
    +          Resolution constructor.
    IPPValue(char[] p_date) + +
    +          Date constructor.
    IPPValue(int p_int) + +
    +          Integer constructor.
    IPPValue(int p_int, + boolean anything) + +
    +          Enum constructor.
    IPPValue(int p_length, + char[] p_data) + +
    +          Raw data constructor.
    IPPValue(int p_lower, + int p_upper) + +
    +          Range constructor.
    IPPValue(short p_short) + +
    +          Short constructor.
    IPPValue(java.lang.String p_charset, + java.lang.String p_text) + +
    +          String constructor.
    +  + + + + + + + + + + + +
    +Method Summary
    + longIPPDateToTime() + +
    +          Convert an IPP Date value to Unix Time.
    + + + + + + + +
    Methods inherited from class java.lang.Object
    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    +  +

    + + + + + + + + + + + +
    +Constructor Detail
    + +

    +IPPValue

    +
    +public IPPValue(byte p_byte)
    +
    +
    Byte constructor.
    +
    Parameters:
    p_byte - Byte value.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(short p_short)
    +
    +
    Short constructor.
    +
    Parameters:
    p_short - Short value.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(int p_int)
    +
    +
    Integer constructor.
    +
    Parameters:
    p_int - Integer value.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(int p_int,
    +                boolean anything)
    +
    +
    Enum constructor.
    +
    Parameters:
    p_int - Integer value - force to IPP enum.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(boolean p_boolean)
    +
    +
    Boolean constructor.
    +
    Parameters:
    p_boolean - Boolean value.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(char[] p_date)
    +
    +
    Date constructor. Also set the unix_time member.
    +
    Parameters:
    p_date[] - Character array with date value.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(java.lang.String p_charset,
    +                java.lang.String p_text)
    +
    +
    String constructor. Set the string and + charset values.
    +
    Parameters:
    p_charset - Charset for string.
    p_text - Text for string.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(int p_lower,
    +                int p_upper)
    +
    +
    Range constructor. Automatically swap as needed.
    +
    Parameters:
    p_lower - Integer lower value.
    p_upper - Integer upper value.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(byte p_units,
    +                int p_xres,
    +                int p_yres)
    +
    +
    Resolution constructor.
    +
    Parameters:
    p_units - Unit of measure.
    p_xres - X resolution.
    p_yres - Y resolution.
    +
    +
    +
    + +

    +IPPValue

    +
    +public IPPValue(int p_length,
    +                char[] p_data)
    +
    +
    Raw data constructor.
    +
    Parameters:
    p_length - Size of array.
    p_data[] - Data.
    +
    +
    + + + + + + + + +
    +Method Detail
    + +

    +IPPDateToTime

    +
    +public long IPPDateToTime()
    +
    +
    Convert an IPP Date value to Unix Time.
    +
    Returns:
    long Unix time in seconds.
    See Also:
    IPPCalender
    +
    +
    + +
    + + + + + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/deprecated-list.html b/scripting/java/docs/deprecated-list.html new file mode 100644 index 000000000..3c2bcd94f --- /dev/null +++ b/scripting/java/docs/deprecated-list.html @@ -0,0 +1,89 @@ + + + + + + +: Deprecated List + + + + + + + + + + + + + + + + + +
    + +
    + + +
    +
    +

    +Deprecated API

    +
    +
    + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/help-doc.html b/scripting/java/docs/help-doc.html new file mode 100644 index 000000000..e564cd6ef --- /dev/null +++ b/scripting/java/docs/help-doc.html @@ -0,0 +1,138 @@ + + + + + + +: API Help + + + + + + + + + + + + + + + + + +
    + +
    + + +
    +
    +

    +How This API Document Is Organized

    +
    +This API (Application Programming Interface) document has pages corresponding to the items in the navigation bar, described as follows.

    +Package

    +
    + +

    +Each package has a page that contains a list of its classes and interfaces, with a summary for each. This page can contain four categories:

      +
    • Interfaces (italic)
    • Classes
    • Exceptions
    • Errors
    +
    +

    +Class/Interface

    +
    + +

    +Each class, interface, inner class and inner interface has its own separate page. Each of these pages has three sections consisting of a class/interface description, summary tables, and detailed member descriptions:

      +
    • Class inheritance diagram
    • Direct Subclasses
    • All Known Subinterfaces
    • All Known Implementing Classes
    • Class/interface declaration
    • Class/interface description +

      +

    • Inner Class Summary
    • Field Summary
    • Constructor Summary
    • Method Summary +

      +

    • Field Detail
    • Constructor Detail
    • Method Detail
    +Each summary entry contains the first sentence from the detailed description for that item. The summary entries are alphabetical, while the detailed descriptions are in the order they appear in the source code. This preserves the logical groupings established by the programmer.
    +

    +Tree (Class Hierarchy)

    +
    +There is a Class Hierarchy page for all packages, plus a hierarchy for each package. Each hierarchy page contains a list of classes and a list of interfaces. The classes are organized by inheritance structure starting with java.lang.Object. The interfaces do not inherit from java.lang.Object.
      +
    • When viewing the Overview page, clicking on "Tree" displays the hierarchy for all packages.
    • When viewing a particular package, class or interface page, clicking "Tree" displays the hierarchy for only that package.
    +
    +

    +Deprecated API

    +
    +The Deprecated API page lists all of the API that have been deprecated. A deprecated API is not recommended for use, generally due to improvements, and a replacement API is usually given. Deprecated APIs may be removed in future implementations.
    +

    +Index

    +
    +The Index contains an alphabetic list of all classes, interfaces, constructors, methods, and fields.
    +

    +Prev/Next

    +These links take you to the next or previous class, interface, package, or related page.

    +Frames/No Frames

    +These links show and hide the HTML frames. All pages are available with or without frames. +

    +

    +Serialized Form

    +Each serializable or externalizable class has a description of its serialization fields and methods. This information is of interest to re-implementors, not to developers using the API. While there is no link in the navigation bar, you can get to this information by going to any serialized class and clicking "Serialized Form" in the "See also" section of the class description. +

    + + +This help file applies to API documentation generated using the standard doclet. + +
    +


    + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/index-all.html b/scripting/java/docs/index-all.html new file mode 100644 index 000000000..21461d858 --- /dev/null +++ b/scripting/java/docs/index-all.html @@ -0,0 +1,1588 @@ + + + + + + +: Index + + + + + + + + + + + + + + + + + +
    + +
    + + +A B C D E F G H I J L M N O P Q R S T U V W
    +

    +A

    +
    +
    ACTIVATE_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    activity - +Variable in class com.easysw.cups.IPPHttp +
      +
    addAttribute(IPPAttribute) - +Method in class com.easysw.cups.IPP +
    Add an attribute to the attibutes list + for later parsing. +
    addBoolean(boolean) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addBooleans(boolean[]) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addDate(char[]) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addEnum(int) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addInteger(int) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addIntegers(int[]) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addRange(int, int) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addRanges(int[], int[]) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addResolution(byte, int, int) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addResolutions(byte, int[], int[]) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addSeparator() - +Method in class com.easysw.cups.IPPAttribute +
      +
    addString(String, String) - +Method in class com.easysw.cups.IPPAttribute +
      +
    addStrings(String, String[]) - +Method in class com.easysw.cups.IPPAttribute +
      +
    ATTRIBUTE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    ATTRIBUTES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    ATTRIBUTES_NOT_SETTABLE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    attrs - +Variable in class com.easysw.cups.IPP +
      +
    auth_type - +Variable in class com.easysw.cups.IPPHttp +
      +
    +
    +

    +B

    +
    +
    BAD_REQUEST - +Static variable in class com.easysw.cups.IPPDefs +
      +
    br - +Variable in class com.easysw.cups.IPPHttp +
      +
    +
    +

    +C

    +
    +
    CANCEL_CURRENT_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CANCEL_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CANCEL_SUBSCRIPTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CHARSET - +Static variable in class com.easysw.cups.IPPDefs +
      +
    checkForResponse() - +Method in class com.easysw.cups.IPPHttp +
      +
    com.easysw.cups - package com.easysw.cups
     
    COMPRESSION_ERROR - +Static variable in class com.easysw.cups.IPPDefs +
      +
    COMPRESSION_NOT_SUPPORTED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CONFLICT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    conn - +Variable in class com.easysw.cups.IPPHttp +
      +
    connect() - +Method in class com.easysw.cups.IPPURLConnection +
    Not used. +
    connected - +Variable in class com.easysw.cups.IPPHttp +
      +
    CREATE_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CREATE_JOB_SUBSCRIPTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CREATE_PRINTER_SUBSCRIPTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    Cups - class com.easysw.cups.Cups.
     
    CUPS_ACCEPT_JOBS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_ADD_CLASS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_ADD_DEVICE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_ADD_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_DELETE_CLASS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_DELETE_DEVICE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_DELETE_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_GET_CLASSES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_GET_DEFAULT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_GET_DEVICES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_GET_PPDS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_GET_PRINTERS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_MOVE_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_REJECT_JOBS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    CUPS_SET_DEFAULT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    Cups() - +Constructor for class com.easysw.cups.Cups +
    Void constructor. +
    Cups(URL) - +Constructor for class com.easysw.cups.Cups +
    Constructor using a URL. +
    cupsCancelJob(String, int, String) - +Method in class com.easysw.cups.Cups +
    Cancel a job - send a job cancel request to the server. +
    cupsGetDefault() - +Method in class com.easysw.cups.Cups +
    Get default destination. +
    cupsGetJobs(boolean, boolean) - +Method in class com.easysw.cups.Cups +
    Get a list of jobs. +
    cupsGetPrinterAttributes(String) - +Method in class com.easysw.cups.Cups +
    Get printer attributes +
    cupsGetPrinters() - +Method in class com.easysw.cups.Cups +
    Get a list of printers. +
    cupsGetPrinterStatus(String) - +Method in class com.easysw.cups.Cups +
      +
    CupsJob - class com.easysw.cups.CupsJob.
     
    CupsJob() - +Constructor for class com.easysw.cups.CupsJob +
    Constructor - set some default values. +
    CupsPrinter - class com.easysw.cups.CupsPrinter.
     
    CupsPrinter(Cups) - +Constructor for class com.easysw.cups.CupsPrinter +
    Constructor. +
    CupsPrinter(Cups, String) - +Constructor for class com.easysw.cups.CupsPrinter +
    Constructor with name. +
    cupsPrintFile(String, IPPAttribute[]) - +Method in class com.easysw.cups.Cups +
    Print a file. +
    +
    +

    +D

    +
    +
    DATA - +Static variable in class com.easysw.cups.IPPDefs +
      +
    days - +Static variable in class com.easysw.cups.IPPHttp +
      +
    DEACTIVATE_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    DEVICE_ERROR - +Static variable in class com.easysw.cups.IPPDefs +
      +
    DISABLE_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    disconnect() - +Method in class com.easysw.cups.IPPURLConnection +
    Not used. +
    DOCUMENT_ACCESS_ERROR - +Static variable in class com.easysw.cups.IPPDefs +
      +
    document_format - +Variable in class com.easysw.cups.CupsJob +
      +
    DOCUMENT_FORMAT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    DOCUMENT_FORMAT_ERROR - +Static variable in class com.easysw.cups.IPPDefs +
      +
    doRequest() - +Method in class com.easysw.cups.Cups +
    Do a CUPS request to the server. +
    doRequest(File) - +Method in class com.easysw.cups.Cups +
    Send a FILE to the CUPS server. +
    doRequest(String) - +Method in class com.easysw.cups.Cups +
      +
    dump_response() - +Method in class com.easysw.cups.IPP +
      +
    dump_values() - +Method in class com.easysw.cups.IPPAttribute +
      +
    +
    +

    +E

    +
    +
    ENABLE_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    error - +Variable in class com.easysw.cups.IPPHttp +
      +
    ERROR - +Static variable in class com.easysw.cups.IPPDefs +
      +
    ERROR_JOB_CANCELLED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +F

    +
    +
    FINISHINGS_BALE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_BIND - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_BIND_BOTTOM - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_BIND_LEFT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_BIND_RIGHT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_BIND_TOP - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_BOOKLET_MAKER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_COVER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_EDGE_STITCH - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_EDGE_STITCH_BOTTOM - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_EDGE_STITCH_LEFT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_EDGE_STITCH_RIGHT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_EDGE_STITCH_TOP - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_FOLD - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_JOB_OFFSET - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_NONE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_PUNCH - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_SADDLE_STITCH - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE_BOTTOM_LEFT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE_BOTTOM_RIGHT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE_DUAL_BOTTOM - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE_DUAL_LEFT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE_DUAL_RIGHT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE_DUAL_TOP - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE_TOP_LEFT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_STAPLE_TOP_RIGHT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FINISHINGS_TRIM - +Static variable in class com.easysw.cups.IPPDefs +
      +
    FORBIDDEN - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +G

    +
    +
    GET_JOB_ATTRIBUTES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    GET_JOBS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    GET_NOTIFICATIONS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    GET_PRINT_SUPPORT_FILES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    GET_PRINTER_ATTRIBUTES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    GET_PRINTER_SUPPORTED_VALUES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    GET_SUBSCRIPTION_ATTRIBUTES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    GET_SUBSCRIPTIONS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    getAttributes(Cups) - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer's attributes. +
    getBytes(int, int) - +Method in class com.easysw.cups.IPPAttribute +
      +
    getCopiesDefault() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer number of copies default. +
    getCurrentAttribute() - +Method in class com.easysw.cups.IPP +
    Get the current attribute pointed at by + current. +
    getEncrypt() - +Method in class com.easysw.cups.Cups +
    Get the value of the encrypt member. +
    getInstance() - +Static method in class com.easysw.cups.IPPMD5 +
    This returns the singleton instance +
    getJobSheetsDefault() - +Method in class com.easysw.cups.CupsPrinter +
    Get the default job sheets. +
    getJobSheetsSupported() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer job sheets supported. +
    getLocation() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer location. +
    getLowerCopiesSupported() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer lower copies supported. +
    getMakeAndModel() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer make and model. +
    getOrientationDefault() - +Method in class com.easysw.cups.CupsPrinter +
    Get the default orientation. +
    getOrientationSupported() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer orientation supported. +
    getPageRangesSupported() - +Method in class com.easysw.cups.CupsPrinter +
    Get whether the printer supports page ranges. +
    getPrinterName() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer name. +
    getStateReasons() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer state reasons. +
    getStateText() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer state text. +
    getStatus(Cups) - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer's status. +
    getUpperCopiesSupported() - +Method in class com.easysw.cups.CupsPrinter +
    Get the printer upper copies supported. +
    GONE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +H

    +
    +
    hashData(byte[]) - +Method in class com.easysw.cups.IPPMD5 +
      +
    HEADER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    hexStringFromBytes(byte[]) - +Method in class com.easysw.cups.IPPMD5 +
      +
    HOLD_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    HOLD_NEW_JOBS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    hostname - +Variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_0_9 - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_1_0 - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_1_1 - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_ACCEPTED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_AUTH_BASIC - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_AUTH_MD5 - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_AUTH_MD5_INT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_AUTH_MD5_SESS - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_AUTH_MD5_SESS_INT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_AUTH_NONE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_BAD_GATEWAY - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_BAD_REQUEST - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_CLOSE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_CONFLICT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    http_content_length - +Variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_CONTINUE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_CREATED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_DELETE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_ENCODE_CHUNKED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_ENCODE_LENGTH - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_ENCRYPT_ALWAYS - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_ENCRYPT_IF_REQUESTED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_ENCRYPT_NEVER - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_ENCRYPT_REQUIRED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_ERROR - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_ACCEPT_LANGUAGE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_ACCEPT_RANGES - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_AUTHORIZATION - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONNECTION - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONTENT_ENCODING - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONTENT_LANGUAGE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONTENT_LENGTH - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONTENT_LOCATION - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONTENT_MD5 - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONTENT_RANGE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONTENT_TYPE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_CONTENT_VERSION - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_DATE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_HOST - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_IF_MODIFIED_SINCE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_IF_UNMODIFIED_SINCE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_KEEP_ALIVE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_LAST_MODIFIED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_LINK - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_LOCATION - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_MAX - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_RANGE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_REFERER - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_RETRY_AFTER - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_TRANSFER_ENCODING - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_UNKNOWN - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_UPGRADE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_USER_AGENT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FIELD_WWW_AUTHENTICATE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    http_fields - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_FORBIDDEN - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_GATEWAY_TIMEOUT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_GET - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_GET_SEND - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_GONE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_HEAD - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_KEEPALIVE_OFF - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_KEEPALIVE_ON - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_LENGTH_REQUIRED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_METHOD_NOT_ALLOWED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_MOVED_PERMANENTLY - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_MOVED_TEMPORARILY - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_MULTIPLE_CHOICES - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_NO_CONTENT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_NOT_ACCEPTABLE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_NOT_AUTHORITATIVE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_NOT_FOUND - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_NOT_IMPLEMENTED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_NOT_MODIFIED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_NOT_SUPPORTED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_OK - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_OPTIONS - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_PARTIAL_CONTENT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_PAYMENT_REQUIRED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_POST - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_POST_RECV - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_POST_SEND - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_PRECONDITION - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_PROXY_AUTHENTICATION - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_PUT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_PUT_RECV - +Static variable in class com.easysw.cups.IPPHttp +
      +
    http_request - +Variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_REQUEST_TIMEOUT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_REQUEST_TOO_LARGE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_RESET_CONTENT - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_SEE_OTHER - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_SERVER_ERROR - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_SERVICE_UNAVAILABLE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_STATUS - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_SWITCHING_PROTOCOLS - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_TRACE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_UNAUTHORIZED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_UNSUPPORTED_MEDIATYPE - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_UPGRADE_REQUIRED - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_URI_TOO_LONG - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_USE_PROXY - +Static variable in class com.easysw.cups.IPPHttp +
      +
    HTTP_WAITING - +Static variable in class com.easysw.cups.IPPHttp +
    Class constants - most not in use yet. +
    +
    +

    +I

    +
    +
    IDLE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    IGNORED_ALL_NOTIFICATIONS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    IGNORED_ALL_SUBSCRIPTIONS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    INTERNAL_ERROR - +Static variable in class com.easysw.cups.IPPDefs +
      +
    IPP - class com.easysw.cups.IPP.
    An IPP object is used to hold the various + attributes and status of an ipp request..
    IPP() - +Constructor for class com.easysw.cups.IPP +
      +
    IPPAttribute - class com.easysw.cups.IPPAttribute.
     
    IPPAttribute(int, int, String) - +Constructor for class com.easysw.cups.IPPAttribute +
      +
    IPPDateToTime() - +Method in class com.easysw.cups.IPPValue +
    Convert an IPP Date value to Unix Time. +
    IPPDefs - class com.easysw.cups.IPPDefs.
    IPPDefs is a collection of constants for use + in the IPP and CUPS classes.
    IPPDefs() - +Constructor for class com.easysw.cups.IPPDefs +
      +
    IPPError - class com.easysw.cups.IPPError.
     
    IPPError(int) - +Constructor for class com.easysw.cups.IPPError +
    Constructor that sets error_string after creation. +
    ippFindAttribute(String, int) - +Method in class com.easysw.cups.IPP +
    Find the named attribute of the correct type. +
    ippFindNextAttribute(String, int) - +Method in class com.easysw.cups.IPP +
    Find the named attribute of the correct type. +
    IPPHttp - class com.easysw.cups.IPPHttp.
     
    IPPHttp(String) - +Constructor for class com.easysw.cups.IPPHttp +
    Constructor using URL. +
    IPPHttp(String, String, String, String) - +Constructor for class com.easysw.cups.IPPHttp +
    Constructor using URL, user and pass. +
    IPPMD5 - class com.easysw.cups.IPPMD5.
     
    IPPRequest - class com.easysw.cups.IPPRequest.
    An IPPRequest object is used to hold the + status and id's of a request.
    IPPRequest() - +Constructor for class com.easysw.cups.IPPRequest +
    Constructor +
    IPPRequest(int, short) - +Constructor for class com.easysw.cups.IPPRequest +
    Constructor using request id and operation id. +
    IPPStatus - class com.easysw.cups.IPPStatus.
    Class to convert a status code to text.
    IPPStatus(int) - +Constructor for class com.easysw.cups.IPPStatus +
    Constructor, access the status_text member + after creation. +
    IPPURLConnection - class com.easysw.cups.IPPURLConnection.
     
    IPPURLConnection(URL) - +Constructor for class com.easysw.cups.IPPURLConnection +
    Constructor. +
    IPPValue - class com.easysw.cups.IPPValue.
     
    IPPValue(boolean) - +Constructor for class com.easysw.cups.IPPValue +
    Boolean constructor. +
    IPPValue(byte) - +Constructor for class com.easysw.cups.IPPValue +
    Byte constructor. +
    IPPValue(byte, int, int) - +Constructor for class com.easysw.cups.IPPValue +
    Resolution constructor. +
    IPPValue(char[]) - +Constructor for class com.easysw.cups.IPPValue +
    Date constructor. +
    IPPValue(int) - +Constructor for class com.easysw.cups.IPPValue +
    Integer constructor. +
    IPPValue(int, boolean) - +Constructor for class com.easysw.cups.IPPValue +
    Enum constructor. +
    IPPValue(int, char[]) - +Constructor for class com.easysw.cups.IPPValue +
    Raw data constructor. +
    IPPValue(int, int) - +Constructor for class com.easysw.cups.IPPValue +
    Range constructor. +
    IPPValue(short) - +Constructor for class com.easysw.cups.IPPValue +
    Short constructor. +
    IPPValue(String, String) - +Constructor for class com.easysw.cups.IPPValue +
    String constructor. +
    is - +Variable in class com.easysw.cups.IPPHttp +
      +
    +
    +

    +J

    +
    +
    JOB_ABORTED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    JOB_CANCELLED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    JOB_COMPLETED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    JOB_HELD - +Static variable in class com.easysw.cups.IPPDefs +
      +
    job_hold_until - +Variable in class com.easysw.cups.CupsJob +
      +
    job_id - +Variable in class com.easysw.cups.CupsJob +
      +
    job_k_octets - +Variable in class com.easysw.cups.CupsJob +
      +
    job_media_sheets_completed - +Variable in class com.easysw.cups.CupsJob +
      +
    job_more_info - +Variable in class com.easysw.cups.CupsJob +
      +
    job_name - +Variable in class com.easysw.cups.CupsJob +
      +
    job_originating_host_name - +Variable in class com.easysw.cups.CupsJob +
      +
    job_originating_user_name - +Variable in class com.easysw.cups.CupsJob +
      +
    JOB_PENDING - +Static variable in class com.easysw.cups.IPPDefs +
      +
    job_printer_up_time - +Variable in class com.easysw.cups.CupsJob +
      +
    job_printer_uri - +Variable in class com.easysw.cups.CupsJob +
      +
    job_priority - +Variable in class com.easysw.cups.CupsJob +
      +
    JOB_PROCESSING - +Static variable in class com.easysw.cups.IPPDefs +
      +
    job_sheets - +Variable in class com.easysw.cups.CupsJob +
      +
    job_state - +Variable in class com.easysw.cups.CupsJob +
      +
    job_state_reasons - +Variable in class com.easysw.cups.CupsJob +
      +
    JOB_STOPPED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    job_uri - +Variable in class com.easysw.cups.CupsJob +
      +
    jobStatusText() - +Method in class com.easysw.cups.CupsJob +
    Convert a job status to a string. +
    +
    +

    +L

    +
    +
    LANDSCAPE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +M

    +
    +
    MAX_NAME - +Static variable in class com.easysw.cups.IPPDefs +
      +
    MAX_VALUES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    md - +Variable in class com.easysw.cups.IPPMD5 +
      +
    MD5Digest(String, String, String, String, String, String) - +Method in class com.easysw.cups.IPPMD5 +
      +
    method - +Variable in class com.easysw.cups.IPPHttp +
      +
    months - +Static variable in class com.easysw.cups.IPPHttp +
      +
    MULTIPLE_JOBS_NOT_SUPPORTED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +N

    +
    +
    nonce - +Variable in class com.easysw.cups.IPPHttp +
      +
    NOT_ACCEPTING - +Static variable in class com.easysw.cups.IPPDefs +
      +
    NOT_AUTHENTICATED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    NOT_AUTHORIZED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    NOT_FOUND - +Static variable in class com.easysw.cups.IPPDefs +
      +
    NOT_POSSIBLE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +O

    +
    +
    OK - +Static variable in class com.easysw.cups.IPPDefs +
      +
    OK_BUT_CANCEL_SUBSCRIPTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    OK_CONFLICT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    OK_IGNORED_NOTIFICATIONS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    OK_IGNORED_SUBSCRIPTIONS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    OK_SUBST - +Static variable in class com.easysw.cups.IPPDefs +
      +
    OK_TOO_MANY_EVENTS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    opaque - +Variable in class com.easysw.cups.IPPHttp +
      +
    OPERATION_NOT_SUPPORTED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    os - +Variable in class com.easysw.cups.IPPHttp +
      +
    +
    +

    +P

    +
    +
    parseAuthenticate(String) - +Method in class com.easysw.cups.IPPHttp +
      +
    passwd - +Variable in class com.easysw.cups.IPPHttp +
      +
    path - +Variable in class com.easysw.cups.IPPHttp +
      +
    PAUSE_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PAUSE_PRINTER_AFTER_CURRENT_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    port - +Variable in class com.easysw.cups.IPPHttp +
      +
    PORT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PORTRAIT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRINT_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRINT_SUPPORT_FILE_NOT_FOUND - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRINT_URI - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRINTER_BUSY - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRINTER_IDLE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRINTER_IS_DEACTIVATED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRINTER_PROCESSING - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRINTER_STOPPED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PRIVATE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    processResponse() - +Method in class com.easysw.cups.IPPHttp +
    Process the HTTP response from the server. +
    PROMOTE_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    PURGE_JOBS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +Q

    +
    +
    QUALITY_DRAFT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    QUALITY_HIGH - +Static variable in class com.easysw.cups.IPPDefs +
      +
    QUALITY_NORMAL - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +R

    +
    +
    read_buffer - +Variable in class com.easysw.cups.IPPHttp +
      +
    read_header_charset - +Variable in class com.easysw.cups.IPPHttp +
      +
    read_header_content_language - +Variable in class com.easysw.cups.IPPHttp +
      +
    read_header_content_length - +Variable in class com.easysw.cups.IPPHttp +
      +
    read_header_content_type - +Variable in class com.easysw.cups.IPPHttp +
      +
    read_header_date - +Variable in class com.easysw.cups.IPPHttp +
      +
    read_header_server - +Variable in class com.easysw.cups.IPPHttp +
      +
    read_header() - +Method in class com.easysw.cups.IPPHttp +
    Read the HTTP header from the input stream. +
    read_line() - +Method in class com.easysw.cups.IPPHttp +
    Read a line from the input stream. +
    read(int) - +Method in class com.easysw.cups.IPPHttp +
    Read up to count bytes from the input stream. +
    realm - +Variable in class com.easysw.cups.IPPHttp +
      +
    reConnect() - +Method in class com.easysw.cups.IPPHttp +
    Re-establish a dropped connection. +
    REDIRECTION_OTHER_SITE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    RELEASE_HELD_NEW_JOBS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    RELEASE_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    RENEW_SUBSCRIPTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    REPROCESS_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    request - +Variable in class com.easysw.cups.IPP +
      +
    REQUEST_ENTITY - +Static variable in class com.easysw.cups.IPPDefs +
      +
    REQUEST_VALUE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    RES_PER_CM - +Static variable in class com.easysw.cups.IPPDefs +
      +
    RES_PER_INCH - +Static variable in class com.easysw.cups.IPPDefs +
      +
    resource - +Variable in class com.easysw.cups.IPPHttp +
      +
    RESTART_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    RESTART_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    RESUME_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    RESUME_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    REVERSE_LANDSCAPE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    REVERSE_PORTRAIT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +S

    +
    +
    SCHEDULE_JOB_AFTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    SEND_DOCUMENT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    SEND_NOTIFICATIONS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    SEND_URI - +Static variable in class com.easysw.cups.IPPDefs +
      +
    SERVICE_UNAVAILABLE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    SET_JOB_ATTRIBUTES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    SET_PRINTER_ATTRIBUTES - +Static variable in class com.easysw.cups.IPPDefs +
      +
    setDefaults() - +Method in class com.easysw.cups.CupsPrinter +
    Initialize the members with mostly sane values. +
    setDest(String) - +Method in class com.easysw.cups.Cups +
    Set the value of the dest member. +
    setEncrypt(boolean) - +Method in class com.easysw.cups.Cups +
    Set the value of the encrypt member. +
    setInstance(String) - +Method in class com.easysw.cups.Cups +
    Set the value of the instance member. +
    setOpStatus(short) - +Method in class com.easysw.cups.IPPRequest +
    Set the operation status of a request. +
    setPasswd(String) - +Method in class com.easysw.cups.Cups +
    Set the value of the passwd member. +
    setPassword(String) - +Method in class com.easysw.cups.IPPHttp +
    Set the password. +
    setPath(String) - +Method in class com.easysw.cups.Cups +
    Set the value of the path member. +
    setPort(int) - +Method in class com.easysw.cups.Cups +
    Set the value of the port member. +
    setProtocol(String) - +Method in class com.easysw.cups.Cups +
    Set the value of the protocol member. +
    setRequestID(short) - +Method in class com.easysw.cups.IPP +
    Set the IPP request ID. +
    setRequestOperationID(short) - +Method in class com.easysw.cups.IPP +
    Set the IPP operation ID. +
    setServer(String) - +Method in class com.easysw.cups.Cups +
    Set the value of the server member. +
    setStatus(short) - +Method in class com.easysw.cups.IPPRequest +
    Set the current status of a request. +
    setUser(String) - +Method in class com.easysw.cups.IPPHttp +
    Set the user name. +
    setUser(String) - +Method in class com.easysw.cups.Cups +
    Set the value of the user member. +
    SHUTDOWN_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    sizeInBytes() - +Method in class com.easysw.cups.IPP +
    Get the size in bytes of an IPP request. +
    sizeInBytes(int) - +Method in class com.easysw.cups.IPPAttribute +
      +
    STARTUP_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    status - +Variable in class com.easysw.cups.IPPHttp +
      +
    status - +Variable in class com.easysw.cups.IPP +
      +
    status_text - +Variable in class com.easysw.cups.IPPHttp +
      +
    SUSPEND_CURRENT_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +T

    +
    +
    TAG_ADMINDEFINE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_BEGIN_COLLECTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_BOOLEAN - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_CHARSET - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_COPY - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_DATE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_DEFAULT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_DELETEATTR - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_END - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_END_COLLECTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_ENUM - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_EVENT_NOTIFICATION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_INTEGER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_KEYWORD - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_LANGUAGE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_MASK - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_MEMBERNAME - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_MIMETYPE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_NAME - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_NAMELANG - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_NOTSETTABLE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_NOVALUE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_OPERATION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_PRINTER - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_RANGE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_RESOLUTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_STRING - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_SUBSCRIPTION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_TEXT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_TEXTLANG - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_UNKNOWN - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_UNSUPPORTED_GROUP - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_UNSUPPORTED_VALUE - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_URI - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_URISCHEME - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TAG_ZERO - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TEMPORARY_ERROR - +Static variable in class com.easysw.cups.IPPDefs +
      +
    time_at_completed - +Variable in class com.easysw.cups.CupsJob +
      +
    time_at_creation - +Variable in class com.easysw.cups.CupsJob +
      +
    time_at_processing - +Variable in class com.easysw.cups.CupsJob +
      +
    TIMEOUT - +Static variable in class com.easysw.cups.IPPDefs +
      +
    TOO_MANY_SUBSCRIPTIONS - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +U

    +
    +
    updateAttribute(IPPAttribute) - +Method in class com.easysw.cups.CupsPrinter +
    Process an attribute from the cups.doRequest() method and move + the values into local members. +
    updateAttribute(IPPAttribute) - +Method in class com.easysw.cups.CupsJob +
    Process an attribute from a cups.doRequest() call + and move the value into a local member. +
    URI_SCHEME - +Static variable in class com.easysw.cups.IPPDefs +
      +
    user - +Variable in class com.easysw.cups.IPPHttp +
      +
    usingProxy() - +Method in class com.easysw.cups.IPPURLConnection +
    Determine if using proxy. +
    +
    +

    +V

    +
    +
    VALIDATE_JOB - +Static variable in class com.easysw.cups.IPPDefs +
      +
    version - +Variable in class com.easysw.cups.IPPHttp +
      +
    VERSION - +Static variable in class com.easysw.cups.IPPDefs +
      +
    VERSION_NOT_SUPPORTED - +Static variable in class com.easysw.cups.IPPDefs +
      +
    +
    +

    +W

    +
    +
    write_content_length - +Variable in class com.easysw.cups.IPPHttp +
      +
    write(byte[]) - +Method in class com.easysw.cups.IPPHttp +
    Write bytes to the output stream. +
    write(byte[], int) - +Method in class com.easysw.cups.IPPHttp +
    Write bytes to the output stream. +
    writeHeader(String, int) - +Method in class com.easysw.cups.IPPHttp +
    Write the request header bytes to the server. +
    +
    +A B C D E F G H I J L M N O P Q R S T U V W + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/index.html b/scripting/java/docs/index.html new file mode 100644 index 000000000..0d8e5330a --- /dev/null +++ b/scripting/java/docs/index.html @@ -0,0 +1,22 @@ + + + + + + +Generated Documentation (Untitled) + + + + + + + +<H2> +Frame Alert</H2> + +<P> +This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client. +<BR> +Link to <A HREF="com/easysw/cups/package-summary.html">Non-frame version.</A> + diff --git a/scripting/java/docs/overview-tree.html b/scripting/java/docs/overview-tree.html new file mode 100644 index 000000000..26375784a --- /dev/null +++ b/scripting/java/docs/overview-tree.html @@ -0,0 +1,101 @@ + + + + + + +: Class Hierarchy + + + + + + + + + + + + + + + + + +
    + +
    + + +
    +
    +

    +Hierarchy For All Packages

    +
    +
    +
    Package Hierarchies:
    com.easysw.cups
    +
    +

    +Class Hierarchy +

    + +
    + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/package-list b/scripting/java/docs/package-list new file mode 100644 index 000000000..87ef3d4ba --- /dev/null +++ b/scripting/java/docs/package-list @@ -0,0 +1 @@ +com.easysw.cups diff --git a/scripting/java/docs/packages.html b/scripting/java/docs/packages.html new file mode 100644 index 000000000..ed4ad951e --- /dev/null +++ b/scripting/java/docs/packages.html @@ -0,0 +1,26 @@ + + + + + + + + + + + + +
    + +
    + +
    +
    +The front page has been relocated.Please see: +
    +          Frame version +
    +          Non-frame version.
    + + + diff --git a/scripting/java/docs/serialized-form.html b/scripting/java/docs/serialized-form.html new file mode 100644 index 000000000..ed30f6fe6 --- /dev/null +++ b/scripting/java/docs/serialized-form.html @@ -0,0 +1,89 @@ + + + + + + +Serialized Form + + + + + + + + + + + + + + + + + +
    + +
    + + +
    +
    +

    +Serialized Form

    +
    +
    + + + + + + + + + + + + + +
    + +
    + + +
    + + + diff --git a/scripting/java/docs/stylesheet.css b/scripting/java/docs/stylesheet.css new file mode 100644 index 000000000..95f576498 --- /dev/null +++ b/scripting/java/docs/stylesheet.css @@ -0,0 +1,29 @@ +/* Javadoc style sheet */ + +/* Define colors, fonts and other style attributes here to override the defaults */ + +/* Page background color */ +body { background-color: #FFFFFF } + +/* Table colors */ +.TableHeadingColor { background: #CCCCFF } /* Dark mauve */ +.TableSubHeadingColor { background: #EEEEFF } /* Light mauve */ +.TableRowColor { background: #FFFFFF } /* White */ + +/* Font used in left-hand frame lists */ +.FrameTitleFont { font-size: normal; font-family: normal } +.FrameHeadingFont { font-size: normal; font-family: normal } +.FrameItemFont { font-size: normal; font-family: normal } + +/* Example of smaller, sans-serif font in frames */ +/* .FrameItemFont { font-size: 10pt; font-family: Helvetica, Arial, sans-serif } */ + +/* Navigation bar fonts and colors */ +.NavBarCell1 { background-color:#EEEEFF;}/* Light mauve */ +.NavBarCell1Rev { background-color:#00008B;}/* Dark Blue */ +.NavBarFont1 { font-family: Arial, Helvetica, sans-serif; color:#000000;} +.NavBarFont1Rev { font-family: Arial, Helvetica, sans-serif; color:#FFFFFF;} + +.NavBarCell2 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;} +.NavBarCell3 { font-family: Arial, Helvetica, sans-serif; background-color:#FFFFFF;} + diff --git a/scripting/java/example/GLP.class b/scripting/java/example/GLP.class new file mode 100644 index 0000000000000000000000000000000000000000..bfb69b487094f86c83c32fbeb6a11426a8b4afac GIT binary patch literal 1163 zc-nnb+fEZv6kVqjrX7Y$3kA6fa+}sdMM18jSSS`tX@U~Lr_=U82HP1jGhE_V_!m9{ zu@Ia10e+NmpJ@{yK_6z%p0(G$pEJMz{QL!A3ONYgD~PJ_OJo8u1y5Bd zwU4;eCKXJn#2r(R2;iBD7EG&nju%qQD43PVODX20n3rNf!J>jChG3Z+W{#Vp#L$yD z;-~yP;hY)fVPf+G&*w!^+KAV*Y?y|-!qA{ccNzRit0)-SGKML#C*{1biCvNiFSv$f z=7fD<*=12=c&vM26a36gh*M#@iB*rXF7+iZn5==JOaEMBmN=!~ac!!?v#UGSiCqvW zLna7pWO7rIrlAl08hX&HU|GW}^fPq-qX7*o=w(pI*X4Of!)v_Ju!^_T4`B@9dyXla zmu0F=0*A;hQzaFwX;?=}!v>NJ9k->fpBKcjY)QjAq%~~fy@m|7G-R>O(0()L!`kzfk^oOS$ zx$E*Vy~Ry_C~Fy|z)9P3oLq^!a;X{1`m$;kQ$m!ICGI#`Z&;o6r1#=7v^v7Q<4^;V zmPw6z<nd)H{Z zLQ@qAX@M&QFA=OjCFp|K41**G=>`JrbUif$5hB@vE_7lD5kyI&3qX1;PY*pl>3Qqk z#L>UqE&zo9 literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLP.java b/scripting/java/example/GLP.java new file mode 100644 index 000000000..815a21187 --- /dev/null +++ b/scripting/java/example/GLP.java @@ -0,0 +1,59 @@ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.net.URL; +import java.net.*; +import java.io.*; +import com.easysw.cups.*; + +public class GLP implements ActionListener +{ + private JTabbedPane mainPanel = null; + + // Constructor + public GLP() + { + GLPvars.init(); + + GLPvars.mainGLPPanel = new JTabbedPane(); + GLPvars.tabs = new GLPtabs(); + GLPvars.mainGLPPanel = GLPvars.tabs.getPanel(); + } + + // Implementation of ActionListener interface. + public void actionPerformed(ActionEvent event) + { + // if ("comboBoxChanged".equals(event.getActionCommand())) + // { + // update the icon to display the new phase + // phaseIconLabel.setIcon(images[phaseChoices.getSelectedIndex()]); + // } + } + + // main method + public static void main(String[] args) + { + // create a new instance of CupsApplet + GLP app = new GLP(); + + // Create a frame and container for the panels. + JFrame glpFrame = new JFrame("Java GLP"); + + // Set the look and feel. + try { + UIManager.setLookAndFeel( + UIManager.getCrossPlatformLookAndFeelClassName()); + } catch(Exception e) {} + + glpFrame.setContentPane(GLPvars.mainGLPPanel); + + // Exit when the window is closed. + glpFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + glpFrame.setSize(600,400); + + // Show the converter. + // glpFrame.pack(); + glpFrame.setVisible(true); + } +} diff --git a/scripting/java/example/GLPcolors.class b/scripting/java/example/GLPcolors.class new file mode 100644 index 0000000000000000000000000000000000000000..ad7faf183387df4223ad8eb0d245540899e986cf GIT binary patch literal 838 zc-nQ5Ur*Ce7{;HovVWy)-PiyT6$a=wV7v21!Uan(OBNxKka*davr(vRQaklKc)_)a zdFc7wAs&Wi*UEx#u%4JntQNJnBu06R>a(i$w3H!L((e z2-`x5rOYzRQemmG%(2X~EWj4X-wvj9)wsY32km|LRC)=0cfH%~Hjc1D`%<8N&C^Nq z)m=$@S^KQ^iuS7ZIqmb>7nG+U_$Ns3Q}uvckf)nh5SMf#utb_sFoPU5{BHe@H2Ao< zM(R}wKS$RUjL(=Fp>KBI?kkWUfsb@)l3`*PhAOgL*nPD^ft&(0yH>)v0{O|8n3HIF pe3|v<7n(42IwsaIji<2Cp)3z61xXpcrzamMvrp6`@K7c5=oi06sZam_ literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPcolors.java b/scripting/java/example/GLPcolors.java new file mode 100644 index 000000000..6cfa8d5ae --- /dev/null +++ b/scripting/java/example/GLPcolors.java @@ -0,0 +1,22 @@ + +import java.awt.*; +import javax.swing.*; +import com.easysw.cups.*; + +public class GLPcolors +{ + + public static Color backgroundColor = new Color(0xff,0xff,0xff); + public static Color errorlightColor = new Color(0xcf,0x66,0x66); + public static Color highlightColor = new Color(0x99,0x99,0x66); + public static Color foregroundColor = new Color(0,0,0); + + public static Color labelBackgroundColor = new Color( 0x66, 0xcf, 0x66 ); + + public static Color tabBackgroundColor = new Color(0x22,0x22,0x8f); + public static Color tabForegroundColor = new Color(0xff,0xff,0xff); + + public static Color buttonForegroundColor = new Color(0xff,0xff,0xff); + public static Color buttonBackgroundColor = new Color(0x22,0x22,0x8f); + +} diff --git a/scripting/java/example/GLPdetail.class b/scripting/java/example/GLPdetail.class new file mode 100644 index 0000000000000000000000000000000000000000..2d93c1bfa40b1bef2aee4e7debb26d1be3400021 GIT binary patch literal 5600 zc-qxid3aRS75|;d@@6J4B$*_vLINm;fEigt380Vw3Qb5PV2leonRy9=GxOrige0`? zd)2D7R;6NVwNjV165$1nO09~ZRZCr}bi=w^*H)>!J?AZxOfvBG-%h^o+;h)8_ug~Q zIlp`E%TwPx_y~Y1THwW%==I?HxL?RtA=`u)Li&Vk7xI9R2Zi*z@sP9+yYYy$JKXrK zw2un;osh?bJTBx31v|Ycl?|T6F5z}7c*=`0cv?EY_u?5mE8KJT*dM$o!yX}j6!Lr~ zPS$!sxZT3NDBMeCcNkZSKMfEMUdAg5_A2{0Nl z7xVECnem!%uM78vaBnJj%ZnPkt>7Im7UNw7|MX%h-j&XK!o9EH122~2L;HYfHYoT= z!N+d=%Zn4`m@IPR->LE4sX5Qt-7<0A%lO2NPo=Xz<%Ru&{qZvXagc6{Z<*Z9W6ndnI zV11z5pXdt5+WpH-={$lO)MLrG9HpMtGQ!A=YCN7h zKO74uk7b`#Og)L!YxR)EN39FTv=yDvRxQ3N&>CThC#iQVwrzE{Ye_p;BP*t6j&?yH zm<;Q&MlIf^$D>+^P*!1iC(xDjYwNXG(!a=5St9&A+1%TtcgBO7c!w~84{SN7N~WpU zj9;p_8b45RjgV`FT!$a3xE?=JaRYv=;zr!0;$|TmaT71mv{vsbuXSRi;wQL;U1>_| zd&(s$DmIxi(_!U-@;2UE#jUtS#ZU1w6}RE%DsIOeDt>`GIZDINs!*;<3b|GC5Cf+; zb;jf4;gFS)Y&+$tq*A^@BUCD&LY0chXDbiMJ5erHsYFOAjZ|rrtUX%D81kw#mc}V` zh)Uy4yUpEVTGGFIWgSOjX!_N3wzWx?C~K3+j%vSOr3qA~QaMdz?^Ms3HN$TwQi6vj ziL@kBo`_A8RXUX2LWhZAQ-nL5iV5Qml72F+f>1a#vqe6Y!#$AFD(=Ovm{297F(ayF z&NRopVcoy1VM%vT>yQK*8Wt1id_63Q$Mtx5L=S{mTy9%XUCw7*p*!93gci|)oE%ju zO{XLHS~9akGIPDAQk5LmFLEoF7DXcEs}t-l!sI~~ly|M=ycxcgLPx4JgJ!BUi)Jfy zluC0riRoxMMxnVXRnt6`=8G#lsbpt&4Fs{FbsZbWAkPRKahw*D@XGX{9?`|Fg4RIr ztoFFx84J~lh!-5dohe~-<|njdO-hg5S}{~d@TgQQN9zsztt_70Xl4wV=#~LC`wDw55L|V-;d-gnQcSnCh#X(fXfYOTL zm$1kSc@fKRd?7>wa_XW$C^XcSlMZl8IU3d;ttM1!hI-nTFV*8(nq1sHAmqE2Hzri3 zIX&8;$IOc`laOPleMR3I)7c}i$OAh@A4)szTR1< zq+)8OBIZu&7SCR@H?VIV(;;qwz5s&_<+ECxSA>m$M4~HX#n9oWRb;M4nFCi|anKSc zD&vM$p|nTC=rlja7-bSiGp~yhjOtW@kb=NZpHr+uSOwZE8udNa(AWbPFg~Gp(kx&@ zy=cK$ig7X^%Xp-i3v0*Kk`{G#gcu!*)1E~U)z@rq zw%d(%%T?EGH`(p2cFP6UY`MmoEtgrdC4}S5tY7zZ739Rkr1DdVj(4!{U~ke!$?_pD_p%8 zWnlDxFpGs*{TS1dotu->hp`66iNwvn?Ks51cKNQ?g+E%ak_!cn7NavAG2EeF`IpGly8oKqqpN2roOpMSb?d5 z>ORb?<5SIVnbwB|;>oQj>BX@Iju7Nt6%{EZqZ1Y(LRycf)frjSISYFRd zoR~V%%JgG2N$yzsih)(lTTEr&>Y*biHE-e1qo}LewE&Hro_BMyeuLwfPUfUl;Xyt| z@Lw?sFq(lh9zIM$2@dBEujv?x87w`TzoQpmENXEGPGF6COu$P1u4={NSUhv7K#V-d|o z4b@^XHDC#yilx+!I*Ou^Zoo>q4NY_pR&n;PrYF%%FX3c*1E8?DiagD?o zu1Pr4RfT}78m)X{&9w$?u61a4orQ?28&TKAIGeq2PYSAQY^biwgsJ9(Vd~^GOtqvi zb&83aKAh^{$z+FOsTZf+%$ViG_ML8Ejl-O=8KowlXW&eS3D{_B?M2X<o z<+uQ=aUsscMbL2xI&m3~Ue2ZODlTbPb8)(c3(3G2v#!Gxc z{#LTE#y1DQSGdg)cihK}b^KgYxR>d#@f%B(HgRQTSW?k61K+Ec!r;CWx(S*&OgBQw z-i++5`*E6soO2xJ++Lh#;C!ZAaRJBf!p(TbLDEGIb8-42!>4SNJw4{0L37XGfO^mY z-X#um>F@ox1`**fp1}8A9DC^ z&BtqegTKK~qBr?2ev9whw=oy*$iE5EfDdpoK13Tn;+y(o&a+QAr}lFmea4TW&pAK7 w;HS%%9Hp-~-oP#*>>(HSQWo}6Hs0sE`cv}YE6Sr>QmK#%*n<1a$Iq7k0w3AlZ2$lO literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPdetail.java b/scripting/java/example/GLPdetail.java new file mode 100644 index 000000000..c8e7b61ee --- /dev/null +++ b/scripting/java/example/GLPdetail.java @@ -0,0 +1,279 @@ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.net.URL; +import java.net.*; +import java.io.*; +import com.easysw.cups.*; + +public class GLPdetail implements ActionListener +{ + private JPanel mainPanel = null; + private JPanel controlPanel = null; + private JPanel detailPanel = null; + private JScrollPane jobPanel = null; + private BoxLayout mainLayout = null; + + private JLabel tmp = null; + + private JButton completedButton = null; + private JButton myJobsButton = null; + private JButton printFileButton = null; + + private String completedText = "Show Completed"; + private String myJobsText = "Show My Jobs"; + private String printFileText = "Print a file"; + + private GLPprinterDetail detail = null; + private GLPjobList joblist = null; + private CupsPrinter printer = null; + private Cups cups = null; + + + public GLPdetail() + { + URL u; + + mainPanel = new JPanel(); + mainPanel.setBackground(GLPcolors.backgroundColor); + + // Create the buttons panel + controlPanel = new JPanel(); + controlPanel.setLayout(new GridLayout(1,3,2,2)); + controlPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + controlPanel.setBackground(GLPcolors.backgroundColor); + completedButton = new JButton(completedText); + myJobsButton = new JButton(myJobsText); + printFileButton = new JButton(printFileText); + + completedButton.setActionCommand(completedText); + completedButton.addActionListener(this); + + myJobsButton.setActionCommand(myJobsText); + myJobsButton.addActionListener(this); + + printFileButton.setActionCommand(printFileText); + printFileButton.addActionListener(this); + + completedButton.setBackground(GLPcolors.buttonBackgroundColor); + completedButton.setForeground(GLPcolors.buttonForegroundColor); + + myJobsButton.setBackground(GLPcolors.buttonBackgroundColor); + myJobsButton.setForeground(GLPcolors.buttonForegroundColor); + + printFileButton.setBackground(GLPcolors.buttonBackgroundColor); + printFileButton.setForeground(GLPcolors.buttonForegroundColor); + + controlPanel.add(completedButton); + controlPanel.add(myJobsButton); + controlPanel.add(printFileButton); + + // ----------------------------------------------------------- + // + // Now get the printer objects + // + if (GLPvars.selectedPrinterName != null) + { + try + { + u = new URL("http://" + GLPvars.getServerName() + + ":631/printers/" + GLPvars.selectedPrinterName ); + cups = new Cups(u); + cups.setUser(GLPvars.cupsUser); + cups.setPasswd(GLPvars.cupsPasswd); + printer = new CupsPrinter( cups, GLPvars.selectedPrinterName ); + + detail = new GLPprinterDetail( printer ); + joblist = new GLPjobList(printer); + + detailPanel = detail.getPanel(); + jobPanel = joblist.getPanel(); + + mainLayout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS); + mainPanel.setLayout(mainLayout); + mainPanel.add(detailPanel); + mainPanel.add(controlPanel); + mainPanel.add(jobPanel); + } + catch (IOException e) + { + tmp = new JLabel("Error loading printer: " + GLPvars.selectedPrinterName); + mainPanel.add(tmp); + return; + } + } + else + { + tmp = new JLabel("No printer selected."); + mainPanel.add(tmp); + } + + + } // + + + + public void topDetail() + { + URL u; + + mainPanel = new JPanel(); + mainPanel.setBackground(GLPcolors.backgroundColor); + + // Create the buttons panel + controlPanel = new JPanel(); + controlPanel.setLayout(new GridLayout(1,3,2,2)); + controlPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + controlPanel.setBackground(GLPcolors.backgroundColor); + completedButton = new JButton(); + myJobsButton = new JButton(); + printFileButton = new JButton(printFileText); + + if (GLPvars.showCompletedJobs) + { + completedButton.setText("Show Active"); + completedButton.setActionCommand("Show Active"); + } + else + { + completedButton.setText("Show Completed"); + completedButton.setActionCommand("Show Completed"); + } + completedButton.addActionListener(this); + + if (GLPvars.showMyJobs) + { + myJobsButton.setText("Show All Users"); + myJobsButton.setActionCommand("Show All Users"); + } + else + { + myJobsButton.setText("Show My Jobs"); + myJobsButton.setActionCommand("Show My Jobs"); + } + myJobsButton.addActionListener(this); + + printFileButton.setActionCommand(printFileText); + printFileButton.addActionListener(this); + + completedButton.setBackground(GLPcolors.buttonBackgroundColor); + completedButton.setForeground(GLPcolors.buttonForegroundColor); + + myJobsButton.setBackground(GLPcolors.buttonBackgroundColor); + myJobsButton.setForeground(GLPcolors.buttonForegroundColor); + + printFileButton.setBackground(GLPcolors.buttonBackgroundColor); + printFileButton.setForeground(GLPcolors.buttonForegroundColor); + + controlPanel.add(completedButton); + controlPanel.add(myJobsButton); + controlPanel.add(printFileButton); + + // ----------------------------------------------------------- + // + // Now get the printer objects + // + if (GLPvars.selectedPrinterName != null) + { + try + { + // + // Create connection + // + u = new URL("http://" + GLPvars.getServerName() + + ":631/printers/" + GLPvars.selectedPrinterName ); + cups = new Cups(u); + cups.setUser(GLPvars.cupsUser); + cups.setPasswd(GLPvars.cupsPasswd); + // + // + + printer = new CupsPrinter( cups, GLPvars.selectedPrinterName ); + detail = new GLPprinterDetail( printer ); + joblist = new GLPjobList(printer); + + detailPanel = detail.getPanel(); + + jobPanel = joblist.getPanel(); + + mainLayout = new BoxLayout(mainPanel, BoxLayout.Y_AXIS); + mainPanel.setLayout(mainLayout); + mainPanel.add(detailPanel); + mainPanel.add(controlPanel); + mainPanel.add(jobPanel); + } + catch (IOException e) + { + tmp = new JLabel("IOException while loading printer: " + + GLPvars.selectedPrinterName); + mainPanel.add(tmp); + return; + } + } + else + { + tmp = new JLabel("No printer selected."); + mainPanel.add(tmp); + } + } + + public JPanel getPanel() + { + return(mainPanel); + } + + public void actionPerformed(ActionEvent e) + { + // String source = e.getActionCommand(); + Object source = e.getSource(); + if (source == completedButton) + { + if (GLPvars.showCompletedJobs) + { + GLPvars.showCompletedJobs = !GLPvars.showCompletedJobs; + completedButton.setText("Show Active"); + completedButton.setActionCommand("Show Active"); + GLPvars.tabs.updateDetailPanel(); + GLPvars.tabs.tabPanel.setSelectedIndex(2); + } + else + { + completedButton.setText("Show Completed"); + completedButton.setActionCommand("Show Completed"); + GLPvars.showCompletedJobs = !GLPvars.showCompletedJobs; + GLPvars.tabs.updateDetailPanel(); + GLPvars.tabs.tabPanel.setSelectedIndex(2); + } + } + else if (source == myJobsButton) + { + if (GLPvars.showMyJobs) + { + GLPvars.showMyJobs = !GLPvars.showMyJobs; + myJobsButton.setText("Show All Users"); + myJobsButton.setActionCommand("Show All Users"); + GLPvars.tabs.updateDetailPanel(); + GLPvars.tabs.tabPanel.setSelectedIndex(2); + } + else + { + GLPvars.showMyJobs = !GLPvars.showMyJobs; + myJobsButton.setText("Show My Jobs"); + myJobsButton.setActionCommand("Show My Jobs"); + GLPvars.tabs.updateDetailPanel(); + GLPvars.tabs.tabPanel.setSelectedIndex(2); + } + } + else if (source == printFileButton) + { + if (printer != null) + { + GLPvars.tabs.updateOptionsPanel(printer); + GLPvars.tabs.tabPanel.setSelectedIndex(3); + } + } + } + +} + diff --git a/scripting/java/example/GLPjobList.class b/scripting/java/example/GLPjobList.class new file mode 100644 index 0000000000000000000000000000000000000000..be74a67c9b1f8fa9d0daa2f61b15ecad69b841c0 GIT binary patch literal 3587 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 aRow && colCount >= aColumn) + return (rowData[aRow][aColumn]); + else + return(null); + } + + public void setValueAt(Object aValue, int aRow, int aColumn) + { + if (rowCount >= aRow && colCount >= aColumn) + rowData[aRow][aColumn] = aValue; + } + + public int getRowCount() + { + return (rowCount); + } + + public int getColumnCount() + { + return (colCount); + } + + public void setColumnName(int aColumn, String aName) + { + if (colCount >= aColumn) + { + colNames[aColumn] = aName; + } + } + + public String getColumnName(int aColumn) + { + if (colCount >= aColumn) + return (colNames[aColumn]); + else + return(""); + } + + public Class getColumnClass(int aColumn) + { + if (colCount >= aColumn) + { + if (rowData[0][aColumn] != null) + return (rowData[0][aColumn].getClass()); + else + return( null ); + } + else return(null); + } + + public boolean isCellEditable(int row, int column) + { + return(false); + } + + +// +// Implementation of the TableModelListener interface, +// + // By default forward all events to all the listeners. + public void tableChanged(TableModelEvent e) + { + fireTableChanged(e); + } +} diff --git a/scripting/java/example/GLPoptions$1.class b/scripting/java/example/GLPoptions$1.class new file mode 100644 index 0000000000000000000000000000000000000000..079ff0df4d1e1beb2ac55e0bf4f11e96a976851a GIT binary patch literal 1025 zc-nPS>rN9v7(LTsmo6j4a+QmCsnV9qf`T`0k}3w%K$8;xPuqbG+3u3v;o__K7A8;= zfA|2tfYBI@FJk;=Q3?Sz+4<)C<~wK3oZ0>I=hJ5ZQ&_RVF_c6HhRraN#4U{4xQ#nz zxNFjTHZr(x;{nD@nzfL#FkxYmA+ayq%vP0Qu(%`k#i0`(C~w<&v#MNKsQZ2>gL#Hz z`JJchQY&gq=(-9s(+s@$x>)jewer1?dJ+rDQ+kOZmp!|1HEr%KLtDYGNrqHWd2)TP zQIWx>sJNygss>+@!ImF1WQ}1o8&NspKs$0@dfHiuT3(rXL}r)$y`U=19z@X6FlBHY z-I(IIfiy=aQWhMJY0Ox7$nglX9CLWg@dQsTJmYwdc?%01i&)}V#tS-ai!U?70IIBc zo(u}E2tye%bVcf1LC4&v?8vHS7`aq%QH5F(k|CarWVe{f>4s2VNqEv_=sE9QR3)Pa zu5y&2Gpzdu8@tkbsf6oqGxVP^t>8CyeJ?U=jr`e`x-4DNDQhQ=b!BrW&B}L7g|@oB zMR8Le>QyCOx`To9icVLkm7j$&SVUhEx=yF~Pa9cN)&W7OzwdG;LWWYCl%Y3!5oio+ zH>%b}gSJUu?4XangZ>B-j~LSCu4&!{^Q6u7pJp+7yU{~=FU`g%k5f$LKZ51Qj}gmH z93%b#=BoQ>Oi%>A(%6rIe;`4iHi~okBgE;A9igp>Ym3A0kujwv66+^rYqE*Omq0zLC=Jr055R@Dn-w!YqE%1~((EgBYi16QUzhkH4f5_FDh| literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPoptions$MyTextListener.class b/scripting/java/example/GLPoptions$MyTextListener.class new file mode 100644 index 0000000000000000000000000000000000000000..fb4c7f5d6936deca7260aac2aa65c75c9598b3e1 GIT binary patch literal 1217 zc-nPSTTc@~7(Fvowp~`rMUX0@AYy5OqId~Km(HSxRjwRDcjoJa*=3Eyu`#y zOnle)0?#H;5>1TH{uTd&@tdWzQgAo>%{Ski^UayFyTAT?`vIT}x{6vf`%r@x6=%_^ z;G7R_IIqHkpo(^c6ogfH(IG>pTYYWhi$ROuMz4LDPry z`>C{JrYyUU!8f^PISaxuyQ}*!}H|&xv zG&JCvhC0+MxUQiWq_tiytVZk=(@I1}r^KogGevSvLBEC@7|?JNw-nsga0gL_YFA0p zAnb_ch=j<L!c<6b!<&;qMNoOERkWTEG=jw7LC!Q zVcWuHs48wbF}o<@bjZfT{3tdk3rbf4|22&qO9*GzD28LfcD-~9@79%b7NkS@~)U ziY8o<42+1CX(J)@)QZUDb@~g1J(vr5m`?A9xP@H^n(1e$1<9wUMt&?b9*4ZjC~H7~ z;t86yfYS}Ap&hVLcpLmH%@|HnET<9t5yeKF%Hsp{NIWZrEmLeNz<$%8=ArR(IES*I z@QihYw!pV=WCP)RmP7e?XAX+z3)W@nJG?WUJMiV8Zlhuo^LdI^plCT9-J=X2pj2+6 zCr|NjAehf`sM@2{9iUVf57CQCI>cjm`8sO(6EyLsXyeb&$Dbp{U*Z9Og&F=D7Jq{^ f{thqrd%Wcz@QHsUKTf-@oWW)3r0aMaE`j|8@r@f- literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPoptions.class b/scripting/java/example/GLPoptions.class new file mode 100644 index 0000000000000000000000000000000000000000..197db162216e4d67548023bb439a48a00d4be32d GIT binary patch literal 11082 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 Ra4z@CUvk{H=>J9He*l;)CwBk< literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPoptions.java b/scripting/java/example/GLPoptions.java new file mode 100644 index 000000000..1bd974e12 --- /dev/null +++ b/scripting/java/example/GLPoptions.java @@ -0,0 +1,662 @@ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.filechooser.*; +import java.net.URL; +import java.net.*; +import java.io.*; +import com.easysw.cups.*; + +public class GLPoptions implements ActionListener +{ + Cups cups = null; + CupsJob job = null; + CupsPrinter printer = null; + + String fileName = ""; + + JPanel mainPanel; + JTextField fileTextField; + JButton printButton; + GridBagLayout mainLayout; + GridBagConstraints mainConst; + + // + // Print options; + // + String[] jobSheetsNames; + String[] orientationNames; + int[] orientationValues; + String[] qualityNames; + int[] qualityValues; + + String jobSheetsOption = ""; + int orientationOption = -1; + int qualityOption = -1; + + int pageLowerOption = 0; + int pageUpperOption = 0; + boolean pagePrintAll = true; + + int numCopiesOption = 1; + int numLowerCopiesOption = -1; + int numUpperCopiesOption = -1; + + int selectedJobSheets = 0; + int selectedOrientation = 0; + int selectedQuality = 0; + + JComboBox orientationBox; + JComboBox jobSheetsBox; + JTextField numCopiesField; + JCheckBox printAllCheckBox; + JTextField pageLowerField; + JTextField pageUpperField; + MyTextListener textListener = new MyTextListener(); + + + // Constructor + public GLPoptions() + { + mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.setBackground(GLPcolors.backgroundColor); + JLabel label = new JLabel("No printer selected"); + label.setForeground(GLPcolors.foregroundColor); + mainPanel.add(label,BorderLayout.CENTER); + } + + // Constructor + public GLPoptions(CupsPrinter cp) + { + printer = cp; + if (printer != null) + { + load(printer); + } + else + { + mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.setBackground(GLPcolors.backgroundColor); + JLabel label = new JLabel("No printer selected"); + label.setForeground(GLPcolors.foregroundColor); + mainPanel.add(label,BorderLayout.CENTER); + } + } + + + private void load( CupsPrinter cp ) + { + + fillOptionValues(); + + // Create the main panel to contain the two sub panels. + mainPanel = new JPanel(); + mainLayout = new GridBagLayout(); + mainConst = new GridBagConstraints(); + + mainPanel.setLayout(mainLayout); + mainPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + mainPanel.setBackground(GLPcolors.backgroundColor); + + String tmp_s = "Printing to " + printer.getPrinterName() + + " on " + GLPvars.cupsServerName; + JLabel printerNameText = new JLabel(tmp_s); + printerNameText.setForeground(GLPcolors.foregroundColor); + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = 0; + mainConst.fill = GridBagConstraints.NONE; + mainConst.weightx = 0.0; + mainConst.weighty = 0.0; + mainConst.ipady = 4; + mainLayout.setConstraints( printerNameText, mainConst ); + mainPanel.add(printerNameText); + + JPanel filePanel = buildFilePanel(); + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = 1; + mainConst.fill = GridBagConstraints.HORIZONTAL; + mainConst.weightx = 1.0; + mainConst.weighty = 0.1; + mainConst.ipady = 4; + mainLayout.setConstraints( filePanel, mainConst ); + mainPanel.add(filePanel); + + JPanel orientationPanel = buildOrientationComboBox(); + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = 2; + mainConst.fill = GridBagConstraints.NONE; + mainConst.weightx = 0.8; + mainConst.weighty = 0.1; + mainConst.ipady = 4; + mainLayout.setConstraints( orientationPanel, mainConst ); + mainPanel.add(orientationPanel); + + JPanel jobSheetsPanel = buildJobSheetsComboBox(); + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = 3; + mainConst.fill = GridBagConstraints.NONE; + mainConst.weightx = 0.8; + mainConst.weighty = 0.1; + mainConst.ipady = 4; + mainLayout.setConstraints( jobSheetsPanel, mainConst ); + mainPanel.add(jobSheetsPanel); + + JPanel numCopiesPanel = buildNumCopiesPanel(); + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = 4; + mainConst.fill = GridBagConstraints.HORIZONTAL; + mainConst.weightx = 1.0; + mainConst.weighty = 0.1; + mainConst.ipady = 4; + mainLayout.setConstraints( numCopiesPanel, mainConst ); + mainPanel.add(numCopiesPanel); + + JPanel pageRangePanel = buildPageRangePanel(); + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = 5; + mainConst.fill = GridBagConstraints.HORIZONTAL; + mainConst.weightx = 1.0; + mainConst.weighty = 0.1; + mainConst.ipady = 4; + mainLayout.setConstraints( pageRangePanel, mainConst ); + mainPanel.add(pageRangePanel); + + JPanel buttonPanel = buildButtonPanel(); + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = 6; + mainConst.fill = GridBagConstraints.NONE; + mainConst.weightx = 1.0; + mainConst.weighty = 0.1; + mainConst.ipady = 4; + mainLayout.setConstraints( buttonPanel, mainConst ); + mainPanel.add(buttonPanel); + + } + + + // -------------------------------------------------------------- + // + // Filename / Browse panel + // + public JPanel buildFilePanel() + { + JPanel localPanel = new JPanel(); + final JFileChooser fc = new JFileChooser(); + + localPanel.setBackground(GLPcolors.backgroundColor); + localPanel.setLayout(new BorderLayout()); + + //Create a regular text field. + fileTextField = new JTextField(50); + fileTextField.addActionListener(this); + + //Create some labels for the fields. + JLabel fileFieldLabel = new JLabel(" File to print: "); + fileFieldLabel.setForeground(GLPcolors.foregroundColor); + // fileFieldLabel.setLabelFor(fileTextField); + + localPanel.add( fileFieldLabel, BorderLayout.WEST ); + localPanel.add( fileTextField, BorderLayout.CENTER ); + + //Create the open button + JButton openButton = new JButton("Browse ..." ); + openButton.addActionListener(new ActionListener() + { + public void actionPerformed(ActionEvent e) + { + int returnVal = fc.showOpenDialog(mainPanel); + if (returnVal == JFileChooser.APPROVE_OPTION) + { + File file = fc.getSelectedFile(); + // fileTextField.setText(file.getPath() + file.getName()); + fileTextField.setText(file.getPath()); + fileName = file.getPath(); + } + } + }); + openButton.setBackground(GLPcolors.buttonBackgroundColor); + openButton.setForeground(GLPcolors.buttonForegroundColor); + localPanel.add(openButton, BorderLayout.EAST ); + return(localPanel); + } + + + + public JPanel buildOrientationComboBox() + { + JPanel localPanel = new JPanel(); + localPanel.setLayout(new BorderLayout()); + localPanel.setBackground(GLPcolors.backgroundColor); + + JLabel localLabel = new JLabel("Page Orientation: "); + localLabel.setBackground(GLPcolors.backgroundColor); + localLabel.setForeground(GLPcolors.foregroundColor); + + orientationBox = new JComboBox(orientationNames); + if (selectedOrientation > 0) + orientationBox.setSelectedIndex(selectedOrientation); + orientationBox.addActionListener(this); + orientationBox.setBackground(GLPcolors.backgroundColor); + + localPanel.add(localLabel,BorderLayout.WEST); + localPanel.add(orientationBox,BorderLayout.CENTER); + + return(localPanel); + } + + + public JPanel buildJobSheetsComboBox() + { + JPanel localPanel = new JPanel(); + localPanel.setLayout(new BorderLayout()); + localPanel.setBackground(GLPcolors.backgroundColor); + + JLabel localLabel = new JLabel("Job Sheets: "); + localLabel.setBackground(GLPcolors.backgroundColor); + localLabel.setForeground(GLPcolors.foregroundColor); + + jobSheetsBox = new JComboBox(jobSheetsNames); + if (selectedJobSheets > 0) + jobSheetsBox.setSelectedIndex(selectedJobSheets); + jobSheetsBox.addActionListener(this); + jobSheetsBox.setBackground(GLPcolors.backgroundColor); + + localPanel.add(localLabel,BorderLayout.WEST); + localPanel.add(jobSheetsBox,BorderLayout.CENTER); + + return(localPanel); + } + + public JPanel buildNumCopiesPanel() + { + JPanel localPanel = new JPanel(); + localPanel.setLayout(new FlowLayout()); + localPanel.setBackground(GLPcolors.backgroundColor); + + JLabel localLabel = new JLabel("Number of copies: "); + localLabel.setBackground(GLPcolors.backgroundColor); + localLabel.setForeground(GLPcolors.foregroundColor); + + numCopiesField = new JTextField(3); + if (numCopiesOption > 0) + numCopiesField.setText(new Integer(numCopiesOption).toString()); + numCopiesField.addActionListener(this); + numCopiesField.addFocusListener(textListener); + numCopiesField.setBackground(GLPcolors.backgroundColor); + + localPanel.add(localLabel); + localPanel.add(numCopiesField); + + return(localPanel); + } + + + public JPanel buildPageRangePanel() + { + JPanel localPanel = new JPanel(); + localPanel.setLayout(new FlowLayout()); + localPanel.setBackground(GLPcolors.backgroundColor); + + printAllCheckBox = new JCheckBox("Print all", pagePrintAll ); + printAllCheckBox.setBackground(GLPcolors.backgroundColor); + printAllCheckBox.setForeground(GLPcolors.foregroundColor); + printAllCheckBox.addActionListener(this); + + JLabel localLabel = new JLabel("-or- pages: "); + localLabel.setBackground(GLPcolors.backgroundColor); + localLabel.setForeground(GLPcolors.foregroundColor); + + JLabel localLabel2 = new JLabel(" to "); + localLabel2.setBackground(GLPcolors.backgroundColor); + localLabel2.setForeground(GLPcolors.foregroundColor); + + pageLowerField = new JTextField(4); + pageUpperField = new JTextField(4); + + pageLowerField.addActionListener(this); + pageUpperField.addActionListener(this); + pageLowerField.addFocusListener(textListener); + pageUpperField.addFocusListener(textListener); + + pageLowerField.setBackground(GLPcolors.backgroundColor); + pageUpperField.setBackground(GLPcolors.backgroundColor); + pageLowerField.setEnabled(false); + pageUpperField.setEnabled(false); + + localPanel.add(printAllCheckBox); + localPanel.add(localLabel); + localPanel.add(pageLowerField); + localPanel.add(localLabel2); + localPanel.add(pageUpperField); + + return(localPanel); + } + + + + + public JPanel buildTextPanel() + { + JPanel localPanel = new JPanel(); + return(localPanel); + } + + public JPanel buildButtonPanel() + { + JPanel localPanel = new JPanel(); + localPanel.setLayout(new BorderLayout()); + printButton = new JButton(" Print "); + printButton.setBackground(GLPcolors.buttonBackgroundColor); + printButton.setForeground(GLPcolors.buttonForegroundColor); + printButton.addActionListener( this ); + localPanel.add(printButton, BorderLayout.WEST ); + return(localPanel); + } + + + + public void updateOptions(CupsPrinter cp) + { + printer = cp; + if (printer != null) + { + load(printer); + } + else + { + mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.setBackground(GLPcolors.backgroundColor); + JLabel label = new JLabel("No printer selected"); + label.setForeground(GLPcolors.foregroundColor); + mainPanel.add(label,BorderLayout.CENTER); + } + } + + public JPanel getPanel() + { + return(mainPanel); + } + + + + + public CupsJob printFile( String filename ) + { + Cups cups; + CupsJob job; + URL u; + IPPAttribute attrs[]; + + attrs = buildPrintAttributes(); + + // for (int i=0; i < attrs.length; i++) + // attrs[i].dump_values(); + + try + { + u = new URL("http://" + GLPvars.getServerName() + + ":631/printers/" + printer.getPrinterName() ); + cups = new Cups(u); + cups.setUser(GLPvars.cupsUser); + cups.setPasswd(GLPvars.cupsPasswd); + + job = cups.cupsPrintFile(filename,attrs); + return(job); + } + catch (IOException e) + { + return(null); + } + } + + + + + private void fillOptionValues() + { + IPPAttribute a; + int i, n; + + // + // Job sheets .... + // + jobSheetsNames = printer.getJobSheetsSupported(); + if (printer.getJobSheetsDefault() != "none") + { + for (i=0; i < jobSheetsNames.length; i++) + if (jobSheetsNames[i] == printer.getJobSheetsDefault()) + selectedJobSheets = i; + } + + // + // Orientation .... + // + orientationNames = new String[printer.getOrientationSupported().length]; + orientationValues = printer.getOrientationSupported(); + for (i=0; i < printer.getOrientationSupported().length; i++) + { + if (orientationValues[i] == printer.getOrientationDefault()) + selectedOrientation = i; + switch( orientationValues[i] ) + { + case IPPDefs.PORTRAIT: + orientationNames[i] = "Portrait"; + break; + case IPPDefs.LANDSCAPE: + orientationNames[i] = "Landscape"; + break; + case IPPDefs.REVERSE_LANDSCAPE: + orientationNames[i] = "Reverse Landscape"; + break; + case IPPDefs.REVERSE_PORTRAIT: + orientationNames[i] = "Reverse Portrait"; + break; + } + } + + if (printer.getLowerCopiesSupported() == + printer.getUpperCopiesSupported()) + { + numCopiesOption = printer.getCopiesDefault(); + } + else + { + numCopiesOption = printer.getLowerCopiesSupported(); + numLowerCopiesOption = printer.getLowerCopiesSupported(); + numUpperCopiesOption = printer.getUpperCopiesSupported(); + } + } + + + private IPPAttribute[] buildPrintAttributes() + { + IPPAttribute a; + IPPAttribute[] attrs; + int num_attrs = 0; + + if (orientationOption >= 0) + num_attrs++; + if (jobSheetsOption.length() > 0) + num_attrs++; + if (numCopiesOption > 1) + num_attrs++; + if ((pageLowerOption > 0) && (pageUpperOption > 0) && (!pagePrintAll)) + num_attrs++; + + if (num_attrs > 0) + attrs = new IPPAttribute[num_attrs]; + else + return(null); + + int i = 0; + if (jobSheetsOption.length() > 0) + { + attrs[i] = new IPPAttribute( IPPDefs.TAG_JOB, + IPPDefs.TAG_NAME, + "job-sheets" ); + attrs[i].addString( "", jobSheetsOption ); + i++; + } + if (orientationOption >= IPPDefs.PORTRAIT) + { + attrs[i] = new IPPAttribute( IPPDefs.TAG_JOB, + IPPDefs.TAG_ENUM, + "orientation-requested" ); + attrs[i].addEnum( orientationOption ); + i++; + } + if (numCopiesOption > 1) + { + attrs[i] = new IPPAttribute( IPPDefs.TAG_JOB, + IPPDefs.TAG_INTEGER, + "copies" ); + attrs[i].addInteger( numCopiesOption ); + i++; + } + if ((pageLowerOption > 0) && (pageUpperOption > 0) && (!pagePrintAll)) + { + attrs[i] = new IPPAttribute( IPPDefs.TAG_JOB, + IPPDefs.TAG_RANGE, + "page-ranges" ); + attrs[i].addRange( pageLowerOption, pageUpperOption ); + i++; + } + return(attrs); + } + + + + // Implementation of ActionListener interface. + public void actionPerformed(ActionEvent e) + { + Object source = e.getSource(); + + // + // Name typed in + // + if (source == printAllCheckBox) + { + JCheckBox cb = (JCheckBox)source; + pagePrintAll = cb.isSelected(); + pageLowerField.setEnabled(!pagePrintAll); + pageUpperField.setEnabled(!pagePrintAll); + } + else if (source == pageLowerField) + { + String s = pageLowerField.getText(); + if (s.length() > 1) + { + pageLowerOption = new Integer(s).intValue(); + // if (pageLowerOption > 0) + // printAllCheckBox.setChecked(false); + } + } + else if (source == pageUpperField) + { + String s = pageUpperField.getText(); + if (s.length() > 1) + { + pageUpperOption = new Integer(s).intValue(); + // if (pageUpperOption > 0) + // printAllCheckBox.setChecked(false); + } + } + else if (source == orientationBox) + { + JComboBox cb = (JComboBox)source; + selectedOrientation = cb.getSelectedIndex(); + orientationOption = orientationValues[selectedOrientation]; + } + else if (source == jobSheetsBox) + { + JComboBox cb = (JComboBox)source; + selectedJobSheets = cb.getSelectedIndex(); + jobSheetsOption = jobSheetsNames[selectedJobSheets]; + } + else if (source == numCopiesField) + { + String s = numCopiesField.getText(); + if (s.length() >= 1) + { + numCopiesOption = new Integer(s).intValue(); + } + } + else if (source == fileTextField) + { + String s = fileTextField.getText(); + if (s.length() > 1) + { + fileName = s; + } + } + else if (source == printButton) + { + if (fileName.length() > 1) + { + job = printFile( fileName ); + if (job != null) + { + fileName = ""; + fileTextField.setText(""); + JOptionPane.showMessageDialog(mainPanel, + "Job " + printer.getPrinterName() + "-" + + new Integer(job.job_id).toString() + + " queued."); + } + } + } + } + + + + + + public class MyTextListener implements FocusListener + { + + public void focusGained(FocusEvent e) + { + } + + public void focusLost(FocusEvent e) + { + JTextField txtField = (JTextField)e.getSource(); + if (txtField == numCopiesField) + { + String s = numCopiesField.getText(); + if (s.length() >= 1) + { + numCopiesOption = new Integer(s).intValue(); + } + } + else if (txtField == pageLowerField) + { + String s = pageLowerField.getText(); + if (s.length() >= 1) + { + pageLowerOption = new Integer(s).intValue(); + } + } + else if (txtField == pageUpperField) + { + String s = pageUpperField.getText(); + if (s.length() >= 1) + { + pageUpperOption = new Integer(s).intValue(); + } + } + } + } + +} diff --git a/scripting/java/example/GLPprinterDetail.class b/scripting/java/example/GLPprinterDetail.class new file mode 100644 index 0000000000000000000000000000000000000000..ffdcddb68ed42cc3e0df116e95dbe0e6e023bd4b GIT binary patch literal 4832 zc-pmBd3+T0761NbW;2`JNkTT~50Vf(N(dp*ir12&5QGLdhy;mIsZKUSvas2SyBm^t z)>cugR>iBu3q{2X4>S`rYPEP&TaRk7TD6{dReNA-FROiT_8^Io{?+i|z4!b5-u>S1 z{dS)D^1(*{)QhP;oQd_hI0Kh4xSYWiJ_1+jxXOndtmnl~bo|tZT&&lz!3RI%t9{7B zHOz6X57*&(rZ(o{2HeQhrt|?(I&Sizl=aXKGu)hI*r?+cA2#DwA1ZKLE^fyiOx@|l z7Cyc!mrUKw;2s9|GT6%CJ_h$Q7-Fv+W**kD&4)Uy_u>J@53=GBFCOB>!#+HMpXqqi zhuL^c$Irdk?#1Ii9E2xyJjwVr1{)b{V(^p~zwqK|CZBQD?+$1zwUO=o(skSQIql1@ zym;1!5T5hmc`sh@;@4ih=*3I9_ziZj$jc0V%W|*m5!^X3coo0%;x)#v>v+Ql3%_T} zZ)Sb{zkp5S_H?|Z<81-GHy(*4t++sCC~WsMSY~1{(ccj6>rFH?5m=f!o+IE(gyVKJ zy3~wW0y4DPTx$+AB>E$*=uK%gv4`?PyWk>=aOIm}^oxj^@}ZJ8k=b|Dk(g*SuX;GOeJr z<{Nl?t#)5LY%Pqi8zqZEOVh>|SV=Pyt!Ehn>u`aA@8c{3Kfn(SoQ-n~{0J8a1ir4* zz=gPo4Dv~X*`I7!6pwVyH@iaSpxu`gm@@vL$&MwGamsTtK^}}&INu&fNwEj-7DX!DeSBcxLwuy;V*`J{Ck8&nAJej~=J|HK(~4(g|AbG*dm1u3tf-DZ8~6)$vG&h& z{MEqUSl8#QOKYH#!!@xiBF9ZK(@CAeaF!&N*83GIhErlXfVisB^?x;ytT9cH@ zuK9hdR&h@j);C0Y%q}a@kk0TdLwH1vA$05_d-YwBRfh0lmo9P*;S>IGxoBqD=CBabHbo=hHPuPGy31xLP%%AGZ4D%?Sf|xl9icvr_b`8TFF9Fn zhyr|Oh)En*UbZF+?HE*1rMne3y6&|9oT zg0$))V2C17Y={!7m?&jXCdzdo4KZ0vAssP0W*MSFRHl=Y?XheRi7GDjdvwFb_c?9t z&csn2tF18kT3!>%>Y*kjz8KxLX1=1i2`iax=uvE`y%sY@9;dFn9NW;`mkZ5s(vA;O zwZd`BOj<|u^d<*WM*`Don(1%sW$kd!($aHM)-(K7HG5!nU8PvVcGQkjG7CD)@S3i; z-52X@;w=h$bcnP=+Vfa@mXDHIGoFXl=66TBx})?znbtIA4+DzWc@(7dMt;u&GpPMu_fKnY9n5ZB9q$W1`ph)IOuY+Ql z<1R}i*)JtcWe&=vwiVLBWU1xQpDQ(G1QqQw9aIjZDwr?xw_>V;YN^Tmz%&PYNuM%= zy`@hb!agqCSNc3d_?GnL4`I3sYow1dHbZ(z$mgJz>}w8YwvC{U%+3nbJ7^#S`w

    jv!Qv4d)SeMJI3-faB8Q|zWbrT#4F)!2221Ucbr^Gk z0U5}K*eC;TD!wBFDbBevkP$y@l=$H(aR>9xbXXzTeHh z-_5??&A#9DBbS8y?1wHr4vwVkhuQ-z+9YEbOE_b^@}yS9Y&38bn=En3rA(H(4({lckJ~m1T_DWjUkc zq-1owtdhkJPLL&TB38;$7k^Kdx%fm`?&6cAbg{{*9dulWwM+%V4mvkrHQ%lgSnXbq z$1{vo!{`c5l~ZMjgYGuMlO04DmpWL@c#4BHjHyIX#uW~F7?(SUF{a+I8B^(c8CN+t zxotDrGG_FznTe;(B+_P*X)}FkGi%dk`qO3x(q;w;yKQrdTkLG%-3Ii#4d{0p&|fgR z@KZB|r<9!9Rwr{DoJL4@aC%$aJrH7Fu~M9bU}}gdJa2*NG_Gn`Wm740LRl;!b-6(Iz%19;$U=& zmFOmK*NAnn#d`FL4LDhBLPBiETJbdc#q$^tJ1{6-!ztozoGL!RY2s6yEGquhw=lr6Yk*@lhEcHE#mhZ~hwag(wWH!Hhvi}DpV(`VAHs>JPTHSSQS z<4(06Ths$_m)eNC)h67l9*M1LEACT|$Ng#;L+Tnlpq_4!oyzW2Y9w`&vIf(9Xn1+B$r!U4&1l6MjrJOFe&; ag!%dN(2J+tlYQ%Q+|6ACFL58`OaBW^Gvv|$ literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPprinterDetail.java b/scripting/java/example/GLPprinterDetail.java new file mode 100644 index 000000000..4422c1e07 --- /dev/null +++ b/scripting/java/example/GLPprinterDetail.java @@ -0,0 +1,244 @@ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.net.URL; +import java.net.*; +import java.io.*; +import com.easysw.cups.*; + +public class GLPprinterDetail +{ + + private CupsPrinter printer = null; + private JScrollPane scrollPane = null; + private JPanel mainPanel = null; + + + // Constructor + public GLPprinterDetail( CupsPrinter cp ) + { + printer = cp; + load(); + } + + public void load() + { + mainPanel = new JPanel(); + mainPanel = printerInfoPanel( printer ); + } + + + + // ----------------------------------------------------------- + // + // Build an info panel for an individual printer. + // + private JPanel printerInfoPanel( CupsPrinter cp ) + { + JPanel printerPanel = new JPanel(); + BoxLayout printerBox; + + JPanel leftHeader = new JPanel(); + JPanel rightHeader = new JPanel(); + + JPanel leftPane = new JPanel(); + JPanel rightPane = new JPanel(); + + GridBagLayout leftLayout = new GridBagLayout(); + GridBagLayout rightLayout = new GridBagLayout(); + + GridBagConstraints leftConst = new GridBagConstraints(); + GridBagConstraints rightConst = new GridBagConstraints(); + + + JLabel printerIconLabel = null; + JLabel printerInfoLabel = null; + JLabel printerNameLabel = null; + JLabel printerMakeLabel = null; + + JTable printerStatusTable = null; + + printerBox = new BoxLayout(printerPanel, BoxLayout.X_AXIS); + printerPanel.setLayout(printerBox); + printerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + printerPanel.setBackground(GLPcolors.backgroundColor); + + // Add border around the panel. + + + // ------------------------------------------------------------ + // Left pane + // ------------------------------------------------------------ + leftPane.setLayout(leftLayout); + leftPane.setBackground(GLPcolors.backgroundColor); + + leftHeader.setLayout(new BorderLayout()); + leftHeader.setBackground(GLPcolors.highlightColor); + leftHeader.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); + + printerNameLabel = new JLabel(cp.getPrinterName()); + printerNameLabel.setForeground(Color.black); + leftHeader.add( printerNameLabel, BorderLayout.WEST); + leftConst.gridwidth = GridBagConstraints.RELATIVE; + leftConst.gridx = 0; + leftConst.gridy = 0; + leftConst.fill = GridBagConstraints.HORIZONTAL; + leftConst.weightx = 0.0; + leftConst.weighty = 0.0; + leftConst.ipady = 4; + leftLayout.setConstraints( leftHeader, leftConst ); + leftPane.add(leftHeader); + + String imageName = "./images/printer-" + + cp.getStateText() + ".gif"; + JButton printerButton; + try + { + URL iconURL = ClassLoader.getSystemResource(imageName); + ImageIcon icon = new ImageIcon(iconURL); + printerButton = new JButton( "
    " + + cp.getPrinterName() + + "
    ", + icon ); + } + catch (NullPointerException e) + { + printerButton = new JButton( "
    " + + cp.getPrinterName() + + "
    "); + } + printerButton.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); + printerButton.setBackground(GLPcolors.backgroundColor); + printerButton.setActionCommand( cp.getPrinterName() ); + // printerButton.addActionListener(this); + printerButton.setToolTipText("Click to go to " + cp.getPrinterName() + + "'s extended informtion page."); + + leftConst.gridwidth = GridBagConstraints.REMAINDER; + leftConst.gridx = 0; + leftConst.gridy = 1; + leftConst.fill = GridBagConstraints.BOTH; + leftConst.weightx = 1.0; + leftConst.weighty = 1.0; + leftConst.ipady = 4; + leftLayout.setConstraints( printerButton, leftConst ); + leftPane.add(printerButton); + + + // ------------------------------------------------------------ + // Right pane + // ------------------------------------------------------------ + rightPane.setLayout(rightLayout); + rightPane.setBackground(GLPcolors.backgroundColor); + + rightHeader.setLayout(new BorderLayout()); + rightHeader.setBackground(GLPcolors.highlightColor); + rightHeader.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); + + printerMakeLabel = new JLabel(cp.getMakeAndModel()); + printerMakeLabel.setForeground(Color.black); + rightHeader.add( printerMakeLabel, BorderLayout.WEST); + + rightConst.gridwidth = GridBagConstraints.RELATIVE; + rightConst.gridx = 0; + rightConst.gridy = 0; + rightConst.fill = GridBagConstraints.HORIZONTAL; + rightConst.weightx = 0.0; + rightConst.weighty = 0.0; + rightConst.ipady = 4; + rightLayout.setConstraints( rightHeader, rightConst ); + rightPane.add(rightHeader); + + + Font labelFont = new Font("Serif",Font.BOLD, 12 ); + // Font textFont = new Font("Serif", Font.NORMAL, 12 ); + Font messageFont = new Font("Serif", Font.ITALIC, 12 ); + + JLabel pdServerLabel = new JLabel("Server"); + JLabel pdNameLabel = new JLabel("Name"); + JLabel pdLocationLabel = new JLabel("Location"); + JLabel pdStatusLabel = new JLabel("Status"); + JLabel pdMessageLabel = new JLabel("Message"); + + JLabel pdServerText = new JLabel(GLPvars.cupsServerName); + JLabel pdNameText = new JLabel(cp.getPrinterName()); + JLabel pdLocationText = new JLabel(cp.getLocation()); + JLabel pdStatusText = new JLabel(cp.getStateText()); + JLabel pdMessageText = new JLabel(cp.getStateReasons()); + + pdServerLabel.setFont(labelFont); + pdNameLabel.setFont(labelFont); + pdLocationLabel.setFont(labelFont); + pdStatusLabel.setFont(labelFont); + pdMessageLabel.setFont(labelFont); + pdMessageText.setFont(messageFont); + + pdServerLabel.setForeground(Color.black); + pdNameLabel.setForeground(Color.black); + pdLocationLabel.setForeground(Color.black); + pdStatusLabel.setForeground(Color.black); + pdMessageLabel.setForeground(Color.black); + + + JPanel tablePane; + if ((cp.getStateReasons().length() > 0) && + (!cp.getStateReasons().equals("none"))) + { + tablePane = new JPanel(new GridLayout(5,2,2,2)); + tablePane.add(pdServerLabel); + tablePane.add(pdServerText); + + tablePane.add(pdNameLabel); + tablePane.add(pdNameText); + + tablePane.add(pdLocationLabel); + tablePane.add(pdLocationText); + + tablePane.add(pdStatusLabel); + tablePane.add(pdStatusText); + + tablePane.add(pdMessageLabel); + tablePane.add(pdMessageText); + } + else + { + tablePane = new JPanel(new GridLayout(4,2,2,2)); + tablePane.add(pdServerLabel); + tablePane.add(pdServerText); + + tablePane.add(pdNameLabel); + tablePane.add(pdNameText); + + tablePane.add(pdLocationLabel); + tablePane.add(pdLocationText); + + tablePane.add(pdStatusLabel); + tablePane.add(pdStatusText); + + } + tablePane.setBackground(GLPcolors.backgroundColor); + + // printerStatusTable.setShowGrid(false); + rightConst.gridwidth = GridBagConstraints.REMAINDER; + rightConst.gridx = 0; + rightConst.gridy = 1; + rightConst.fill = GridBagConstraints.BOTH; + rightConst.weightx = 1.0; + rightConst.weighty = 1.0; + rightConst.ipady = 4; + rightLayout.setConstraints( tablePane, rightConst ); + rightPane.add(tablePane); + + printerPanel.add(leftPane); + printerPanel.add(rightPane); + + return(printerPanel); + } + + + public JPanel getPanel() + { + return(mainPanel); + } +} diff --git a/scripting/java/example/GLPprinters.class b/scripting/java/example/GLPprinters.class new file mode 100644 index 0000000000000000000000000000000000000000..4322f43f8c6a8a21ed96d01bd289cceba4389804 GIT binary patch literal 8749 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 literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPprinters.java b/scripting/java/example/GLPprinters.java new file mode 100644 index 000000000..9a86a7950 --- /dev/null +++ b/scripting/java/example/GLPprinters.java @@ -0,0 +1,509 @@ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.net.URL; +import java.net.*; +import java.io.*; +import com.easysw.cups.*; + +public class GLPprinters implements ActionListener +{ + + private Cups cups = null; + public String cupsServerName = ""; + + private JScrollPane scrollPane = null; + private JPanel mainPanel = null; + private JPanel serverPanel = null; + private JPanel maskPanel = null; + + private GridBagLayout mainLayout = null; + private GridBagConstraints mainConst = null; + private GridBagLayout maskLayout = null; + private GridBagConstraints maskConst = null; + + private JLabel serverLabel = null; + + JTextField nameTextField = null; + protected static final String maskFieldString = "Printer Name:"; + protected static final String maskButtonString = "Apply"; + + private String currentMask = ""; + + + // Constructor + public GLPprinters() + { + cupsServerName = GLPvars.getServerName(); + load(); + } + + public void load() + { + String[] printer_names; + String default_printer; + int num_printers = 0; + int y = 0, i = 0; + URL u; + CupsPrinter cp; + + + // ----------------------------------------------------------- + // + // First get a list of printer names. + // + try + { + u = new URL("http://" + GLPvars.getServerName() + ":631/"); + cups = new Cups(u); + + // If authorization is required .... + cups.setUser(GLPvars.cupsUser); + cups.setPasswd(GLPvars.cupsPasswd); + + printer_names = cups.cupsGetPrinters(); + if (printer_names != null) + num_printers = printer_names.length; + else + num_printers = 0; + } + catch (IOException e) + { + mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + mainPanel.setBackground(GLPcolors.backgroundColor); + JLabel errorLabel = new JLabel("Error loading printers from " + + GLPvars.getServerName()); + errorLabel.setForeground(Color.red); + mainPanel.add( errorLabel, BorderLayout.CENTER ); + scrollPane = new JScrollPane(mainPanel); + return; + } + + // ----------------------------------------------------------- + // + // Now get the printer objects + // + CupsPrinter[] printers = new CupsPrinter[num_printers]; + for (i=0; i < num_printers; i++) + { + try + { + u = new URL("http://" + GLPvars.getServerName() + + ":631/printers/" + printer_names[i] ); + cups = new Cups(u); + + // If authorization is required .... + cups.setUser(GLPvars.cupsUser); + cups.setPasswd(GLPvars.cupsPasswd); + + printers[i] = new CupsPrinter( cups, printer_names[i] ); + } + catch (IOException e) + { + // System.out.println("GLPprinters: IOException"); + // return(null); + } + } + + + // + // Keep track in case it changes. + // + cupsServerName = GLPvars.getServerName(); + + if (printer_names != null) + num_printers = printer_names.length; + else + num_printers = 0; + + // default_printer = c.cupsGetDefault(); + + // Create the main panel to contain the two sub panels. + mainPanel = new JPanel(); + mainLayout = new GridBagLayout(); + mainConst = new GridBagConstraints(); + + mainPanel.setLayout(mainLayout); + mainPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + mainPanel.setBackground(GLPcolors.backgroundColor); + + // -------------------------------------------------------------- + // + // Add the server name label + // + serverPanel = new JPanel(); + serverPanel.setLayout( new BorderLayout()); + serverPanel.setBackground(GLPcolors.backgroundColor); + serverLabel = new JLabel("Printers on " + GLPvars.getServerName()); + serverLabel.setForeground(GLPcolors.foregroundColor); + serverPanel.add(serverLabel, BorderLayout.NORTH ); + + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = y++; + mainConst.fill = GridBagConstraints.BOTH; + mainConst.weightx = 0.0; + mainConst.weighty = 0.0; + mainConst.ipadx = 4; + mainConst.ipady = 4; + mainLayout.setConstraints( serverPanel, mainConst ); + mainPanel.add(serverPanel); + + // -------------------------------------------------------------- + // + // Add the printer masking panel + // + maskPanel = new JPanel(); + maskLayout = new GridBagLayout(); + maskConst = new GridBagConstraints(); + + maskPanel.setLayout(maskLayout); + maskPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + maskPanel.setBackground(GLPcolors.backgroundColor); + + JPanel localMaskPanel = buildMaskPanel(); + maskConst.gridwidth = GridBagConstraints.RELATIVE; + maskConst.gridx = 0; + maskConst.gridy = 0; + maskConst.fill = GridBagConstraints.NONE; + maskConst.weightx = 0.0; + maskConst.weighty = 0.0; + maskConst.ipadx = 4; + maskConst.ipady = 4; + maskLayout.setConstraints( localMaskPanel, maskConst ); + maskPanel.add(localMaskPanel); + + // + // Add the masking panel to the main panel. + // + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = y++; + mainConst.fill = GridBagConstraints.BOTH; + mainConst.weightx = 0.0; + mainConst.weighty = 0.0; + mainConst.ipadx = 4; + mainConst.ipady = 4; + mainLayout.setConstraints( maskPanel, mainConst ); + mainPanel.add(maskPanel); + + + + // -------------------------------------------------------------- + // + // Add the printers + // + double weight = 1.0 / (double)printers.length; + for (i=0; i < printers.length; i++) + { + JPanel subPanel = printerInfoPanel( printers[i] ); + mainConst.gridwidth = GridBagConstraints.RELATIVE; + mainConst.gridx = 0; + mainConst.gridy = y++; + mainConst.fill = GridBagConstraints.BOTH; + mainConst.weightx = 1.0; + mainConst.weighty = weight; + mainConst.ipady = 4; + mainLayout.setConstraints( subPanel, mainConst ); + mainPanel.add(subPanel); + } + + // ------------------------------------------------ + // + // Put the whole thing into a scroll pane. + // + scrollPane = new JScrollPane(mainPanel); + } + + + + // ----------------------------------------------------------- + // + // Build an info panel for an individual printer. + // + private JPanel printerInfoPanel( CupsPrinter cp ) + { + JPanel printerPanel = new JPanel(); + BoxLayout printerBox; + + JPanel leftHeader = new JPanel(); + JPanel rightHeader = new JPanel(); + + JPanel leftPane = new JPanel(); + JPanel rightPane = new JPanel(); + + GridBagLayout leftLayout = new GridBagLayout(); + GridBagLayout rightLayout = new GridBagLayout(); + + GridBagConstraints leftConst = new GridBagConstraints(); + GridBagConstraints rightConst = new GridBagConstraints(); + + + JLabel printerIconLabel = null; + JLabel printerInfoLabel = null; + JLabel printerNameLabel = null; + JLabel printerMakeLabel = null; + + JTable printerStatusTable = null; + + printerBox = new BoxLayout(printerPanel, BoxLayout.X_AXIS); + printerPanel.setLayout(printerBox); + printerPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + printerPanel.setBackground(GLPcolors.backgroundColor); + + // Add border around the panel. + + + // ------------------------------------------------------------ + // Left pane + // ------------------------------------------------------------ + leftPane.setLayout(leftLayout); + leftPane.setBackground(GLPcolors.backgroundColor); + + leftHeader.setLayout(new BorderLayout()); + leftHeader.setBackground(GLPcolors.highlightColor); + leftHeader.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); + + printerNameLabel = new JLabel(cp.getPrinterName()); + printerNameLabel.setForeground(Color.black); + leftHeader.add( printerNameLabel, BorderLayout.WEST); + leftConst.gridwidth = GridBagConstraints.RELATIVE; + leftConst.gridx = 0; + leftConst.gridy = 0; + leftConst.fill = GridBagConstraints.HORIZONTAL; + leftConst.weightx = 0.0; + leftConst.weighty = 0.0; + leftConst.ipady = 4; + leftLayout.setConstraints( leftHeader, leftConst ); + leftPane.add(leftHeader); + + String imageName = "./images/printer-" + cp.getStateText() + ".gif"; + URL iconURL = ClassLoader.getSystemResource(imageName); + ImageIcon icon = new ImageIcon(iconURL); + JButton printerButton = new JButton( "
    " + + cp.getPrinterName() + + "
    ", + icon ); + printerButton.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); + printerButton.setBackground(GLPcolors.backgroundColor); + printerButton.setActionCommand( cp.getPrinterName() ); + printerButton.addActionListener(this); + printerButton.setToolTipText("Click to go to " + cp.getPrinterName() + + "'s extended informtion page."); + + leftConst.gridwidth = GridBagConstraints.REMAINDER; + leftConst.gridx = 0; + leftConst.gridy = 1; + leftConst.fill = GridBagConstraints.BOTH; + leftConst.weightx = 1.0; + leftConst.weighty = 1.0; + leftConst.ipady = 4; + leftLayout.setConstraints( printerButton, leftConst ); + leftPane.add(printerButton); + + + // ------------------------------------------------------------ + // Right pane + // ------------------------------------------------------------ + rightPane.setLayout(rightLayout); + rightPane.setBackground(GLPcolors.backgroundColor); + + rightHeader.setLayout(new BorderLayout()); + rightHeader.setBackground(GLPcolors.highlightColor); + rightHeader.setBorder(BorderFactory.createEmptyBorder(3,3,3,3)); + + printerMakeLabel = new JLabel(cp.getMakeAndModel()); + printerMakeLabel.setForeground(Color.black); + rightHeader.add( printerMakeLabel, BorderLayout.WEST); + + rightConst.gridwidth = GridBagConstraints.RELATIVE; + rightConst.gridx = 0; + rightConst.gridy = 0; + rightConst.fill = GridBagConstraints.HORIZONTAL; + rightConst.weightx = 0.0; + rightConst.weighty = 0.0; + rightConst.ipady = 4; + rightLayout.setConstraints( rightHeader, rightConst ); + rightPane.add(rightHeader); + + + Font labelFont = new Font("Serif",Font.BOLD, 12 ); + // Font textFont = new Font("Serif", Font.NORMAL, 12 ); + Font messageFont = new Font("Serif", Font.ITALIC, 12 ); + + JLabel pdNameLabel = new JLabel("Name"); + JLabel pdLocationLabel = new JLabel("Location"); + JLabel pdStatusLabel = new JLabel("Status"); + JLabel pdMessageLabel = new JLabel("Message"); + + JLabel pdNameText = new JLabel(cp.getPrinterName()); + JLabel pdLocationText = new JLabel(cp.getLocation()); + JLabel pdStatusText = new JLabel(cp.getStateText()); + JLabel pdMessageText = new JLabel(cp.getStateReasons()); + + pdNameLabel.setFont(labelFont); + pdLocationLabel.setFont(labelFont); + pdStatusLabel.setFont(labelFont); + pdMessageLabel.setFont(labelFont); + pdMessageText.setFont(messageFont); + + pdNameLabel.setForeground(Color.black); + pdLocationLabel.setForeground(Color.black); + pdStatusLabel.setForeground(Color.black); + pdMessageLabel.setForeground(Color.black); + + JPanel tablePane; + if ((cp.getStateReasons().length() > 0) && + (!cp.getStateReasons().equals("none"))) + { + tablePane = new JPanel(new GridLayout(4,2,2,2)); + tablePane.add(pdNameLabel); + tablePane.add(pdNameText); + + tablePane.add(pdLocationLabel); + tablePane.add(pdLocationText); + + tablePane.add(pdStatusLabel); + tablePane.add(pdStatusText); + + tablePane.add(pdMessageLabel); + tablePane.add(pdMessageText); + } + else + { + tablePane = new JPanel(new GridLayout(3,2,2,2)); + tablePane.add(pdNameLabel); + tablePane.add(pdNameText); + + tablePane.add(pdLocationLabel); + tablePane.add(pdLocationText); + + tablePane.add(pdStatusLabel); + tablePane.add(pdStatusText); + + } + tablePane.setBackground(GLPcolors.backgroundColor); + + // printerStatusTable.setShowGrid(false); + rightConst.gridwidth = GridBagConstraints.REMAINDER; + rightConst.gridx = 0; + rightConst.gridy = 1; + rightConst.fill = GridBagConstraints.BOTH; + rightConst.weightx = 1.0; + rightConst.weighty = 1.0; + rightConst.ipady = 4; + rightLayout.setConstraints( tablePane, rightConst ); + rightPane.add(tablePane); + + printerPanel.add(leftPane); + printerPanel.add(rightPane); + + return(printerPanel); + } + + + + + + public JPanel buildMaskPanel() + { + + // Create the main panel to contain the two sub panels. + JPanel namePanel = new JPanel(); + GridBagLayout nameLayout = new GridBagLayout(); + GridBagConstraints nameConst = new GridBagConstraints(); + + namePanel.setLayout(nameLayout); + namePanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + namePanel.setBackground(GLPcolors.backgroundColor); + + + //Create a regular text field. + nameTextField = new JTextField(16); + nameTextField.setActionCommand(maskFieldString); + nameTextField.addActionListener(this); + nameTextField.setText(""); + + //Create some labels for the fields. + JLabel nameFieldLabel = new JLabel(maskFieldString); + nameFieldLabel.setForeground(GLPcolors.foregroundColor); + nameFieldLabel.setLabelFor(nameTextField); + + // Text + nameConst.gridwidth = GridBagConstraints.RELATIVE; + nameConst.gridx = 0; + nameConst.gridy = 0; + nameConst.fill = GridBagConstraints.HORIZONTAL; + nameConst.weightx = 0.0; + nameConst.weighty = 0.0; + nameConst.ipadx = 4; + nameConst.ipady = 4; + nameLayout.setConstraints( nameFieldLabel, nameConst ); + namePanel.add(nameFieldLabel); + + nameConst.gridwidth = GridBagConstraints.RELATIVE; + nameConst.gridx = 1; + nameConst.gridy = 0; + nameConst.fill = GridBagConstraints.HORIZONTAL; + nameConst.weightx = 0.0; + nameConst.weighty = 0.0; + nameConst.ipadx = 4; + nameConst.ipady = 4; + nameLayout.setConstraints( nameTextField, nameConst ); + namePanel.add(nameTextField); + + JButton applyButton = new JButton(maskButtonString); + applyButton.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createRaisedBevelBorder(), + BorderFactory.createEmptyBorder(2,2,2,2))); + applyButton.setActionCommand(maskButtonString); + applyButton.addActionListener(this); + nameConst.gridx = 2; + nameConst.gridy = 0; + nameConst.fill = GridBagConstraints.NONE; + nameLayout.setConstraints( applyButton, nameConst ); + nameConst.weightx = 0.0; + nameConst.weighty = 0.0; + nameConst.ipadx = 4; + nameConst.ipady = 4; + namePanel.add(applyButton); + + return(namePanel); + } + + + public void actionPerformed(ActionEvent e) + { + if (e.getActionCommand().equals(maskFieldString)) + { + String s = nameTextField.getText(); + if (s.length() > 1) + { + currentMask = s; + } + } + else if (e.getActionCommand().equals(maskButtonString)) + { + String s = nameTextField.getText(); + if (s.length() > 1) + { + currentMask = s; + } + } + else + { + GLPvars.selectedPrinterName = e.getActionCommand(); + GLPvars.tabs.updateDetailPanel(); + GLPvars.tabs.tabPanel.setSelectedIndex(2); + } + } + + + public JScrollPane getPanel() + { + return(scrollPane); + } +} diff --git a/scripting/java/example/GLPsearch.class b/scripting/java/example/GLPsearch.class new file mode 100644 index 0000000000000000000000000000000000000000..2db6a39499a76b5b407854e1d7117bcc46152a78 GIT binary patch literal 2428 zc-o~^+fx%~6#uOx*(5Bta4Cpr)oMcoB2ZEBE(*qmKn1jTDJ;nX(Xfeo0qsrOYVXtO zQ)k)-XWBma(wBB1IJMK6zSx;Q_7AH4og|>e*y&8k@H=O}?|kQ+-#O>o{o}8ne+AHm z&x2^kU;tqZ37ip#37i#pRUj@fERYZw31SqlsW>Nc%#U$DCW1JR3j(jp;-nuJRa^?9 z0fPdU1+ECZp<>F9X+QKJS}>y`8AKaW0T`GSZBDd#(b57}#pN||nF(@ZL4~Ozt0JeM zDw9p>nKN12N$3lPf>8XbzNkktx;YmebF8#EcSu3yx>0O&?P<)NNf?fT+V#B?sgz~d zwt}Xj57Tg>F+ypbeyWnLWf`V3l}$QwR*5O_CbOSX*~p0s z%QcB%(F1AIF)Yi?F^9lYQMk*{o?;gMIm0=xXI!JO&a8uDS=UM$gK3FVJrp0c4c$u4 zcS$%6`*B1=1bZ}e2y_Z`A*x|7x;69&^a{L!eH!|(PsMc&7FfEr^~z0{*UapaDTO_K zBWdKEbk@}1z-1Y`5B79*_Z{f!?&{vVmo@5Av8Z7QH#FSDn;PB{E3g0?*`IW0XAMik z+jvLdT@AOyRC^NjT%6UPcbr^*G|EW*eZAe$oK>iiEyQjsXkeA1hHl@qm!e5GXGaGJ zviF{f_ceSVZ13QnNi za4>ec$sz&vC%!g^3Yx?1&l|x?T0WWfhBd=~&U@{~H5q!H({HAX8zZv{8pCA%F>^!g}^TJ(n{~vg;`4HeSAobkrJ-{mZW3$*v_|HeJqsT{!-9=L>5p z8?dNbOv^9Lov;myi?-nuwV*7H>bAX<61s-7rdP|xkl~y%W_35iCipUjIp?sA0rEY0 zvsm!R^BF$ds~SC(8qbay)}mp>)3$@{d~LS#bsOM6uNUO6qa-^^lJ|_bNv>K!_LO9A zN%GDWWM4t5ye0c_fOwEkf5L+b%Bzu8C=q1^n*=HZJObW`X9d1U#R^mbzd%4B7-^Nq z2dJdceRzf=k!5)Es1g^UYVom*icn1+wMS&DqGC%Pb@cipBlqD5jzgo?&)5mn6E`yx zjXbMR&0jrg(2P31$wSz|r*-jOAq@&Iyk->|42DK8-)g&V>> ze9K}K3pc|O0ms<2U(m qHcGMgl1uQ1b#q@~F+)62)- 0)) + { + lookupAddress = InetAddress.getByName(host); + GLPvars.addToServerList(lookupAddress.getHostName()); + } + else + { + } + } + catch (IOException e) + { + } + } + if (!is_done) + is_completed = true; + is_done = true; + } + + public void interrupt() + { + is_done = true; + } + + public boolean completed() + { + return(is_completed); + } + + public boolean done() + { + return(is_done); + } + + public int getValue() + { + return(count); + } + +} diff --git a/scripting/java/example/GLPsearchProgressPanel$1.class b/scripting/java/example/GLPsearchProgressPanel$1.class new file mode 100644 index 0000000000000000000000000000000000000000..aed39b445d383877ce56b450ab83962c0e42cd2c GIT binary patch literal 2470 zc-oCtTT~NA82*NYY*-eBXw=BXNTUs?1W?g}XfcX~22Bl8kyhO#BZMZqbaw-2Z`RWL z{ocOx)F)p0Qfz~*r}oYE^tI>o)u+DnweQ-0b|Vo9J?5Ou%>U0n-+%dLX6KJPKi>q< zhOcC7LuVC2*ezoZ_R8qOJ~7%a<1us#u}6ppWc1>o&>a%u<6iX1IE<)hjtI?BFZyL1 z6T%Z1kT57?9iFTrA?C%95RQxHgoL<^0G<*vC&efsnqdj2WHjM)HAZnp%#DfW85z&w ztb}tC&Pz}kJk~_U47D?CiXDr^O|BZLiMXMU8{9PGs>ZWD3{{DXnl-_#Op5FeWVDQR zkfA=j+Jcr526t3XbB49CjK+`Wb4hLttI4d;s3|L>YjJK|(2X2VGi(XRCe>**qRv+2D0o*S@gCkM+RB$B)X4w_WkA!o5zVTm$xQ+9 zfrJkge1wk`e1cCEe1^{@e4*e=TwEQigYvK`%BmF2iR2_tSqzP3S&L;%i<3_VS6Fbj zp*$v$s-{vTh1%O`^KD;!GmVvI#8zAq7`)@$8d0-(Zu=T2L3RkpJ*z{;mKFEjIuqhtSTb8bon{{Q>L@p)fuou;HIaQ-W=`S8ioAHEYkiC5rB{Ci6vsNjRJtC5} zhm9nrChaT5w^B>sgfXoeCPNM7oUo6R*iRxH+6OBFVyFxc*hF|8*TX}E9DDG{kzEai z9o4h>oOWEz5n~&|1LgCR?{VBmUN_!f1ZUg#IR3VVm!)M1Uy=Jf3Y+R;OwPTxKDP2i z_c*0b@GQ5hKV;vTb>k1Hs4~sr<#iNQS#CpEjjNFm>aYW9`hNu4`)WG9OkX<8JC`Ty zocOY~&h<|fAsVYhKw?PItx4slOovm417A5prQ!lALw+i)THIM-r-2}SRJYNsww?Yy zam!QR0`aS$e=By7ypu-FBnyq)x(L>~<406{4{;mrqSiw_u$S64L>zne8{DX(ez&XF zb#NYATYo^sb+{TkZ^75FBoyF2-#h1GjkVsZcW*oD%7y|wt}eH$t8yMYi>CfcS{Nt^ z1xQ~*nRBywc&MGLWd2Hl@u%NS9e#Bzy#-ViL5p1hGNC&{wNELa=DzV7XS~)|TR`1) z__{p-&n=h%&&_X;yMcA1G;%Lu{WbU(;CJ~p6tL0NCCy_!i2;va>hw#l0yfP_%rBAc z)w}=PKwy+67qR&o>K9N?(+$)W(Aez_cyFL-lpnOR|p1?#1J^?bi^@@lemloeT|0kEl%M(jNm#> z;}?3n{EjjFMJsO8!{u+B#lO_w!8ulqB=aG~HY3eiaEWzN1QlqvH$w-Wrrt-RCOE&4 G)BOih&x{cO literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPsearchProgressPanel$2.class b/scripting/java/example/GLPsearchProgressPanel$2.class new file mode 100644 index 0000000000000000000000000000000000000000..131a55844b63cb263312191c49eed9506d9ba44a GIT binary patch literal 1188 zc-oCr+foxj5IsXemMjZ|Ajm}!A;1QZ2#OcPC`Q2O2B`|ggKwK;Og3&d)XpZrr|<PEPHlUE<)*4P4`Ui^yxF*J^TH~*KYvkkW&%EXcS$zrD6=@QX~{iw4)W1 zQcOjmBdKBIDj+Zhl;pMr_i=I_?R;9_u zRP*(QTjXnLCg{G3G7(2x5X;^*(h)LI!O|(;a&n15it60;pj+Yv;c%|UA1_Nsh{Z}Mr;T*`DLX{#jO#S2f za>J=sSL4nzgmjso#Q$WHp{LBfZCQk@SSeK-!lUCp#9OL0eG9V8a7|Ad7x_{SW0p8Y ztnGOFbdtPsmh;D)bxM5Chs-i4M7wFa)Mae}`>h;9Ty{^jUhtd3&%H#xXrq$<=DI?} z`}Az~Qc4|ySaY|@-3_xw%zJg?Vzq*%^vnYBh|1t{Nv@s6#*R4a8~@uixI^IE-PkFa z9uGYH{9}}!XpG)eH_fZad#UYXr(!e{C zH!%F`{4PTD%7Ldd#|RxDd`LQcg4W#Z7ep8i5cz-!S}P3cBeV^NjuAb9x)dG=e@6Qe zv?FvJqw_S#B%&lOwBbDwt`RYZ!U>GSqrXK1i)bQ^Jt8^clfQ{x(s5e#AQ)YN`U%o4 BB^m$# literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPsearchProgressPanel$ButtonListener.class b/scripting/java/example/GLPsearchProgressPanel$ButtonListener.class new file mode 100644 index 0000000000000000000000000000000000000000..40f8c1c1eb42d57e38d865672896d6ad09318e28 GIT binary patch literal 1686 zc-oCs-*XdH7(F)$-DF)$2~b;`mVhZHsU#ubFG8yjC>9rpB!Dgc+AP<0nPeAtZwijD zeelHx$Ke4Tbr@%?IF2JT5EvYN@-}H&svgTthZ`La%h;q5e;LADLATO z7RShN*`KW7Ee&%xuHbDAI!=(2)_`R%#xwF#a8ko5lqlc-B{aN)(;CXCNa`~h&f**; zR~F7C1@CH@M@hqi)I5*(6ui%nXtBm?j%n25UZZMr5vNq+#WSUH+~e*tcRdXs;0VKH z?^F_p8$vj?Zh3;+++`SC4`_2XJ&QHN^SH+_oqFA{X{)v+Q+h|MELjT~+n&_dyDOv?7>0Z2PMd9* zCiN2gb95*({STQ>dnM~#CcW%&-KhFUHM$XHP&_Uw{EArTX3f8U!q!A{xjaL@uju*C zKq1xL>1H6?yZhUIa#bif*Db$KF3vt}&aG2HEL(fPv@70*{oCXT!xbI9ywuzClzJ7b z&RtU5vH_$w#-Nq$>IDNlHL1&BZsC*UaISzRR=$^n1>c=VCMSY2=={sQQsoMzL zq#nagY6s{Ed_nClywIA@Dujjz{dcN~U^LXkrfc{-eG7rR7>FuOgk?Mw{sWP_P|pRY zS25ZeeJ1uhBJ;7(M|Yr=R{|_H6u$oWVQcK!=wK6@yW*kX%qk|<7LModw+AV1V#`X9 zjmy;!T41z^t*e;#4GsE+PP7eeBSX?dn<~~t6(g$cZ6gob;*`;FSNvS38VeYv_A6+( zO0~U)NqmhozQHs-XYnmg<2(AEd=C@X;ot{+M)3-M#FzMqMt{Z){DNQUcMreeKE;3I bHvT~q4+#k%;qS~O4#~YB#S!}7coX;!Szxz{ literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPsearchProgressPanel.class b/scripting/java/example/GLPsearchProgressPanel.class new file mode 100644 index 0000000000000000000000000000000000000000..2ccc411da14596677dcecb9d7928c54a17d4944a GIT binary patch literal 2709 zc-oCtTXz#x6#h;UI!PEP4J}uJ&>LxJo3`M!c%iYyVrZj*YCzCQGEGyGnL0CR=~5A| zC?ei3Fa82w)J4*@>{_~(kG}W^{1y7na_^a3OqwV!`|PvN{=T!%-e;eg-|zkW3xH94 z>q7+RSzKVTz~TiKFZwZtBx@HXT=L>2KfJii;);Zq{gCkrPZS9$FVcQ=;<67JsH`or zmSt^8Le7spSY~mRMV>{01$k-ESzBVUBH>j(jvy()@Z%_wJTX};dSUTc^kTI#uGyo6 zYZBJ|80J`x<24DdOL#+I=Tyl7BSayS~hYvUSFFO*k0} zWxR>&0t2mg>Thf$M%<9`7Ty*JY)yc`ki#5Yr$YqudRoZ`&0B_=1fv(?iJ++( ztEyp2ct^&&cu&UrxGCcU);`2dfqm^R25){##z(j<<73>B@d<8A_*BMcjQt#Unq#V5 z_8vAylr<|dr5hR5h$$4ECF2WxNxe0v8y02aD|}6PiK?2#&F-02OiQ3^%l)G8+9YaR z036{r)LpGz1a{exvY=6=~`4T6cjB(m!bV- zBtVyv$vA-etJhm0=d-J;bhb#NhYj=*XS7wb5Zu%xPXi(ii8SEv z@CG`?EhoWMJ0@x=IkVCVoPojNOjb zT}BT%>`A)2aBl;9OYqQw$6dxg9zA93ugnkdXhRP=+5=@As`wlxiX+Jl1UaU=kT!9Y zX1!(f@yrJGv&MS{2Fe($Ogw>OWrQjdS74}&FfkoZc8TFl4D$g-HZWR(`$syqz!b?V z*h_LRJm`iG`|1DT0R0ghq(7QNl)S^3rrA8D{0e%ph(7w$=*KDsa07$5g=6$y4BAyU=ub@GFM5~+qIlX#I57%4;oCUEA8H|V*v4O}I@6e;S~a_FYj)j% zGk{&rXE56W;Asyyi)UK^-0cA|oNEDawFk^my0!vDdq5n|RRBleCJj`*;}=WqkL|+q UwoFipfdFYTC48LpVS63_0O)p+rT_o{ literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPsearchProgressPanel.java b/scripting/java/example/GLPsearchProgressPanel.java new file mode 100644 index 000000000..7d1734f82 --- /dev/null +++ b/scripting/java/example/GLPsearchProgressPanel.java @@ -0,0 +1,195 @@ +import javax.swing.JTable; +import javax.swing.ListSelectionModel; +import javax.swing.event.ListSelectionListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.JScrollPane; +import javax.swing.JPanel; +import javax.swing.JFrame; +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; +import com.easysw.cups.*; + +public class GLPsearchProgressPanel +{ + private JProgressBar progressBar; + private Timer timer; + private JButton searchButton; + private JLabel progressLabel; + private GLPsearch tasks[]; + private JPanel panel = null; + + public GLPsearchProgressPanel() + { + //Create the demo's UI. + searchButton = new JButton("Search"); + searchButton.setActionCommand("Search"); + searchButton.addActionListener(new ButtonListener()); + + progressLabel = new JLabel("Search your local subnet for CUPS servers"); + progressLabel.setBackground(GLPcolors.backgroundColor); + progressLabel.setForeground(GLPcolors.foregroundColor); + + progressBar = new JProgressBar(0, 254); + progressBar.setValue(0); + progressBar.setBorderPainted(true); + progressBar.setOrientation(JProgressBar.HORIZONTAL); + progressBar.setBackground(GLPcolors.backgroundColor); + progressBar.setForeground( Color.blue ); + progressBar.setStringPainted(true); + + panel = new JPanel(); + panel.setLayout(new BorderLayout()); + panel.setBackground(GLPcolors.backgroundColor); + + panel.add(progressLabel,BorderLayout.NORTH); + panel.add(progressBar, BorderLayout.CENTER); + panel.add(searchButton, BorderLayout.EAST); + + //Create a timer. + timer = new Timer(300, new ActionListener() + { + + public void actionPerformed(ActionEvent evt) + { + int n = 0; + for (int i=0; i < 8; i++) + { + if (tasks[i] != null) + n += tasks[i].getValue(); + } + progressBar.setValue(n); + + + // + // See if all the threads completed yet. + // + int d = 0; + for (int j=0; j < 8; j++ ) + { + if (tasks[j] != null) + { + if (tasks[j].done()) + { + d++; + } + } + else d++; // Thread removed ??? + } + + if (d >= 8) + { + timer.stop(); + progressBar.setValue(progressBar.getMinimum()); + searchButton.setActionCommand("Search"); + searchButton.setText("Search"); + progressLabel.setText("Search local subnet for CUPS servers"); + + String[] servers = GLPvars.getServerList(); + if ((servers != null) && (servers.length > 0)) + { + GLPvars.searchTM = new GLPjobTableModel(servers.length,1); + GLPvars.searchTM.setColumnName(0,"Search Results"); + for (int i=0; i < servers.length; i++) + GLPvars.searchTM.setValueAt(servers[i],i,0); + GLPvars.searchTable = new JTable(GLPvars.searchTM); + + + GLPvars.searchTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + ListSelectionModel rowSM = GLPvars.searchTable.getSelectionModel(); + rowSM.addListSelectionListener(new ListSelectionListener() + { + public void valueChanged(ListSelectionEvent e) + { + //Ignore extra messages. + if (e.getValueIsAdjusting()) return; + + ListSelectionModel lsm = + (ListSelectionModel)e.getSource(); + if (lsm.isSelectionEmpty()) + { + //no rows are selected + } + else + { + int selectedRow = lsm.getMinSelectionIndex(); + String newServer = (String)GLPvars.searchTM.getValueAt(selectedRow,0); + GLPvars.setServerName(newServer); + GLPvars.tabs.updateServerPanel(GLPvars.cupsServerName); + } + } + }); + GLPvars.tabs.updateServerPanel(GLPvars.cupsServerName); + } + // DEBUG + + } // threads complete? + + + + } + }); + } + + + + + /** + * The actionPerformed method in this class + * is called when the user presses the start button. + */ + class ButtonListener implements ActionListener + { + + public void actionPerformed(ActionEvent evt) + { + + if (evt.getActionCommand().equals("Search")) + { + progressLabel.setText("Searching ....."); + // + // Create the search threads .... + // + tasks = new GLPsearch[8]; + for (int i=0; i < 8; i++) + tasks[i] = new GLPsearch(i+1); + + searchButton.setActionCommand("Stop"); + searchButton.setText("Stop"); + for (int i=0; i < 8; i++) + { + if (tasks[i] != null) + { + tasks[i].start(); + } + } + timer.start(); + } + else if (evt.getActionCommand().equals("Stop")) + { + progressLabel.setText("Search local subnet for CUPS servers"); + + for (int i=0; i < 8; i++) + { + if (tasks[i] != null) + { + tasks[i].interrupt(); + } + // tasks[i] = null; + } + + searchButton.setActionCommand("Search"); + searchButton.setText("Search"); + + } // Stop event + + } // actionPerformed + } // end of class + + public JPanel getPanel() + { + return(panel); + } + + +} diff --git a/scripting/java/example/GLPserver.class b/scripting/java/example/GLPserver.class new file mode 100644 index 0000000000000000000000000000000000000000..2ad5f77db7df9b2c0fdab3ad1c512af54bfb8ca5 GIT binary patch literal 4304 zc-oCu33yc175?wbB(w0yMp(ic5bb0mRuq&(0@-MA5&}U&M3k4z%VfeVVdhO1Q7O2h z#RatrZbdCFXbXXvqy}v1Vq06gxwLdqTe?@<+J&xP+jH)F6DEt;$@iVRob{gb-}7!> z`Ok|l0a%28yRZq{owy3uGr57ujZAjf@o^V2u+xcMxXFQ=d2x#axAJ(K9k;tM8M~Qz zhl|ATwBr*l8= zXY#NekGQY^kFxAzJbRqUryMxIvQJn$yYM70pK_9yPcu2l9_4_KFd5+GUMBmQJZuRbb)kmOR)b?1m8TcWUq_tApumi_==L8?>gvFa}&Q93zk{zG7;|l_lqI#r9 zk2Gl^Js^C$?%zOrbqKjbT0EqBYMkQQn0w1gBRD3I$}rGaEiy{59y7uU>n6`CcqX5YZO+N8FrH%=?F)HI_=DJo36E9qfGCiQqPYgAmzWD97o4ebKiV=K$DC++y6iZ4MUOU)7u1?%)^EMP=cd>LP%bTx(xOqdiz zl8l$}RZ8}FEU>|^srWkDRYVXTE0a9eNTyar{N5_f=h6DZF+*V1Sca@zMDvH(=_~k# z9p6;(D!!%S+xU(h-&OHFyr$xHykS`#j}#8+O%8UrvjHBFiGT%MwKFFq2meQzL#%gKSeRY!I5p<MQnM-S6u(h#_i5R>V&CcWY9dM_Ok}SdMfSfr}>$&~uJ%B%@EG z1PT;Qe7cD?DHSG?)@lBz?yaH>2a@=h<32Z*@=Q%>jB=b*+jK5ioeOaj@kSdbr!znJ zn?{iGje}J7*y7QbRo@oV0?{!aJnLE)UPW~xGu*97G@yrkTx0qO*PEb91&2Lq3SvGz z;x<9xYI-Rt{H3EelfoZ6Inwt|j`Yc+(Z+3AjvdzMvqt(N&^Q}i*h;nnQfD5mgDL9@ zq|=-}s6@MIXE*6l>qLFgAViUfLt&D}#Kt6j7#XcL+aT;m;TV7;E!UZVizc~~($W%8 zhcUU8R)feqimajpvX784fo<|(J&EXCaxfWAWYS+Yy*hI+gMwO!0+iCRm(r83hE^ZL z`J@#|hL!d%J+LzD8&g(=g~pGAyvEW2EKK11QsyLZL6PKqgg9}y zY0oX$g>ricMRLEmM2VxMBrT3oCW}ha<0vc1!-a8NRFWCT;u3ot7c;q}m`#)+sYOm*A;sa~9-P6xiUCB?h#L)1%?x}^zRmg?8`;eO|)_@&G&YZ*p)Yi`9LE?;KL zw+&&rmGvQ1Ca@ykmRpg)%6uDTx61U9&ORv2vf_Lj+nU%Fd&svXP)+u0sIs-o(u?xb z6R0B`nszc$VqL`s@=!l6+O(8t37J>4n7Z~6-7HhnGg@;1SxH5jCeYY2f?&~sR+^U* zju#Pf%P=OUQO^OXSD^A>^Wa3t3DsEF|<91~}b}JX)4y6otD&^RttiWALE$&uU z;~r%V?o~Emud)gEDO+&A(uoI@C}l|?3d3qh1JtC_XzU`Sui+cpv=7$RT-!jET4#F- zO(jEUmN$BR0$1{_po^KnhNrPaYE?+BB2%j+sWmfIYvWn1vmI**bt+KBR6K?}JWj3i z0QIRSP>3gqcaSRj3{~z~s?Z^9!1L6gU!azIn6zW)vEr|x_!Vx$#q5n5V$x&lL>{M6 tI|hzXkBq~C1a-$jLfH^;>BVbVoI@kG=yb;D;Stpgxp{(UzwGSS{STcKYnuQ7 literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPserver.java b/scripting/java/example/GLPserver.java new file mode 100644 index 000000000..ee24c8cca --- /dev/null +++ b/scripting/java/example/GLPserver.java @@ -0,0 +1,192 @@ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.net.URL; +import java.net.*; +import java.io.*; +import com.easysw.cups.*; + +public class GLPserver implements ActionListener +{ + + private JPanel serverPanel = null; + private JPanel searchPanel = null; + + private GLPjobTableModel tm = null; + private JTable table = null; + + protected JLabel currentLabel; + protected JLabel currentLabelValue; + protected JLabel actionLabel; + protected JTextField serverTextField; + + protected static final String serverFieldString = "New Server Name:"; + protected static final String applyButtonString = "Apply Changes"; + + + // Constructor + public GLPserver() + { + GLPvars.searchTM = new GLPjobTableModel(1,1); + GLPvars.searchTM.setColumnName( 0, "Search Results" ); + GLPvars.searchTM.setValueAt("No search results",0,0); + GLPvars.searchTable = new JTable(GLPvars.searchTM); + + load(); + } + + public void load() + { + GridBagLayout serverLayout; + GridBagConstraints serverConst; + + // Create the main panel to contain the two sub panels. + serverPanel = new JPanel(); + serverLayout = new GridBagLayout(); + serverConst = new GridBagConstraints(); + + serverPanel.setLayout(serverLayout); + serverPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); + serverPanel.setBackground(GLPcolors.backgroundColor); + + + //Create a regular text field. + serverTextField = new JTextField(32); + serverTextField.setActionCommand(serverFieldString); + serverTextField.addActionListener(this); + + //Create some labels for the fields. + JLabel serverFieldLabel = new JLabel(serverFieldString); + serverFieldLabel.setForeground(GLPcolors.foregroundColor); + serverFieldLabel.setLabelFor(serverTextField); + + currentLabel = new JLabel("Current Server Name: "); + currentLabel.setForeground(GLPcolors.foregroundColor); + currentLabelValue = new JLabel(GLPvars.getServerName()); + + serverConst.gridwidth = GridBagConstraints.RELATIVE; + serverConst.gridx = 0; + serverConst.gridy = 0; + serverConst.fill = GridBagConstraints.HORIZONTAL; + serverConst.weightx = 0.4; + serverConst.weighty = 0.0; + serverConst.ipadx = 4; + serverConst.ipady = 4; + serverLayout.setConstraints( currentLabel, serverConst ); + serverPanel.add(currentLabel); + + serverConst.gridwidth = GridBagConstraints.RELATIVE; + serverConst.gridx = 1; + serverConst.gridy = 0; + serverConst.fill = GridBagConstraints.HORIZONTAL; + serverConst.weightx = 0.4; + serverConst.weighty = 0.0; + serverConst.ipadx = 4; + serverConst.ipady = 4; + serverLayout.setConstraints( currentLabelValue, serverConst ); + serverPanel.add(currentLabelValue); + + // Text + serverConst.gridwidth = GridBagConstraints.RELATIVE; + serverConst.gridx = 0; + serverConst.gridy = 1; + serverConst.fill = GridBagConstraints.HORIZONTAL; + serverConst.weightx = 0.4; + serverConst.weighty = 0.0; + serverConst.ipadx = 4; + serverConst.ipady = 4; + serverLayout.setConstraints( serverFieldLabel, serverConst ); + serverPanel.add(serverFieldLabel); + + serverConst.gridwidth = GridBagConstraints.RELATIVE; + serverConst.gridx = 1; + serverConst.gridy = 1; + serverConst.fill = GridBagConstraints.HORIZONTAL; + serverConst.weightx = 0.4; + serverConst.weighty = 0.0; + serverConst.ipadx = 4; + serverConst.ipady = 4; + serverLayout.setConstraints( serverTextField, serverConst ); + serverPanel.add(serverTextField); + + JButton applyButton = new JButton(applyButtonString); + applyButton.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createRaisedBevelBorder(), + BorderFactory.createEmptyBorder(5,5,5,5))); + applyButton.setActionCommand(applyButtonString); + applyButton.addActionListener(this); + serverConst.gridx = 1; + serverConst.gridy = 2; + serverConst.fill = GridBagConstraints.NONE; + serverLayout.setConstraints( applyButton, serverConst ); + serverConst.weightx = 0.4; + serverConst.weighty = 0.0; + serverConst.ipadx = 4; + serverConst.ipady = 4; + serverPanel.add(applyButton); + + GLPsearchProgressPanel progress = new GLPsearchProgressPanel(); + searchPanel = progress.getPanel(); + serverConst.gridx = 1; + serverConst.gridy = 3; + serverConst.fill = GridBagConstraints.HORIZONTAL; + serverConst.weightx = 0.6; + serverConst.weighty = 0.3; + serverConst.ipadx = 4; + serverConst.ipady = 4; + serverLayout.setConstraints( searchPanel, serverConst ); + serverPanel.add(searchPanel); + + serverConst.gridx = 1; + serverConst.gridy = 4; + serverConst.fill = GridBagConstraints.HORIZONTAL; + serverConst.weightx = 1.0; + serverConst.weighty = 0.5; + serverConst.ipadx = 4; + serverConst.ipady = 4; + serverLayout.setConstraints( GLPvars.searchTable, serverConst ); + serverPanel.add(GLPvars.searchTable); + + } + + + public void actionPerformed(ActionEvent e) + { + if (e.getActionCommand().equals(serverFieldString)) + { + String s = serverTextField.getText(); + if (s.length() > 1) + { + GLPvars.setServerName(s); + serverTextField.setText(""); + currentLabelValue.setText(GLPvars.getServerName()); + } + } + else if (e.getActionCommand().equals(applyButtonString)) + { + String s = serverTextField.getText(); + if (s.length() > 1) + { + GLPvars.setServerName(s); + serverTextField.setText(""); + currentLabelValue.setText(GLPvars.getServerName()); + } + } + } + + public void updateServer( String server ) + { + GLPvars.setServerName(server); + load(); + serverTextField.setText(""); + currentLabelValue.setText(GLPvars.getServerName()); + } + + + public JPanel getPanel() + { + return(serverPanel); + } + +} diff --git a/scripting/java/example/GLPtabs$1.class b/scripting/java/example/GLPtabs$1.class new file mode 100644 index 0000000000000000000000000000000000000000..fcc52f67dc0a7249b96f423c97f8e938b28c0895 GIT binary patch literal 1097 zc-nnaZBx@g5Pl8{X~PvNFY+deh?*9qD87RzmKO^FnW^Ikzg^2s8zxO_axMB-{1?tZ zb^PED@JBiBr70o`$>eVL_SxNM_clL&eg6Sq9=3^oOeT=T6%$jqn!q(oCvY7zCT?KX z#7*2XNxiKXOIy==$(WeK9Rqg_EEu@Q(5os=FuTBzus7{JC5pik$%Rjzsz~LO2(avU zj#^>h)(Im0jvI< zY)VgM+tzh0hr!H3t>KsCh7$&e(#&f=jv?IVNa2!!MUDq}Xy6gYV>~hNl;ate3@mdz z$BKa$951oT@k)E-u*R{D4USE`HjwAo!Zwu_1)rtbLAmmtC;gl&f%cRU@soG^S3|ndYY%1!z5s_nv*L}xR(kC&g+ul(L z)OSi{=r1+uK|%UW>Fsy1qcq)MZ+GX$RJ59mQCL_t8x+urb#{_fF;rT}Ox=q30WVTQELjAv$Uy zuB8(#aZD*fr7zar%@+8dToaUyqN0Z;eGGZxwS`4&)9~*Qzwwaw1hSebc_hP1@Eb*6 B1)~4} literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPtabs.class b/scripting/java/example/GLPtabs.class new file mode 100644 index 0000000000000000000000000000000000000000..7604add7a4fdf930784bbd1eea692cbbe3bc9e49 GIT binary patch literal 2611 zc-nnd*>@9V6#q?=W|Cn_OQCEPTlTap0XLQw1X7E|04+hFpx`9=NCWAlW+pATfjf%( z`mE19C`ZFN^c>%O@yU1J{R@0ne|Kh*G-c_9~sObWTEmX6mnL|rR0ZrQ4+VO{E)HEZ2SICBL%pEz;W%4Aed?uIlhb5wa& zl>^CD&5|CMLLD>Zg6*oZvov5jTP_ugHNc#5twJ%7G)psXp=8$-Bfd3CrH-e@{R4HP zHGGQrSqqsolF zNY0ANOwMvudSUcEaWAe!(PC6-mrmq|1SF6hSr}Ni&pX`|UVl85Elnqs<=k}U64}a( zlSq<``{69a3Rn)k@m#&gB;=JF;Pl1^{-PA=)o4NDFd027?d%qL6UUG=@faRA z@dTbU@f7x%*e|;SLJnfc#4rw-IE<%F9KlfyYyQKKj@M1RfmP0kh z5^pj4>EQG>-qG={iT4EHecUnef$ToSomPvD=3$K&)LszpGArZt)`-;`fRZE1aSOI3 z*=I%?Enwm!++u&6t{p$dC%&p=Y0F*>VA95HTa}YV%W;$=N&D2qXZYO27dUR>OMGSG zYf0ocI6Gk6GF4`EsdZ=QOO0x5`L2 ztZprIZQ?>!j!MHzG~_~<>6wzPYhYBQnL&?(JbWYnhPhLMWoGolEmq?%^}xwO4XQKni&Z?uA^z-v5~KXPQFHB z{BhnOe;he)<6GCRriAm-7 zesP!VSQQ&38qwTD+FsLaZ)mpHH8)dpiyvbUPJ{xH``B8=HVnkZ7ui z%Q}yNNoIGjiX8!5Dp*hc2zg9AL;5}9r2VW$2W#DpN~NX z9kG$M-GotW!34JQ8(|yrysZ%9HecI!v4fA4o%jyBaE~7#50SvH*n{8MKYy@${$!v0 z#qRkB`!oXwv>qJP`Z1&pVp!XcLs}AtwNp5vox?FrVO*QWgjT^BdOC{Ze&6sHLYsIj zrQK1*&XyX7{1WeKMA*&PfD4FXl965Hr^F@RJX`BTt|9J#KEGPKTdLOX7i|&X74W-= zdkc>u!<#XjSi(hvE+z!gsA7*_&9;bN!bONz>0+KPPSM2zZ=ORcKwQsNTx<*9tLsEO j&NS&soC@SN1ah9^KeULJ>C|Zf!8j`h7~~Fk^ND`}BGp;~ literal 0 Hc-jL100001 diff --git a/scripting/java/example/GLPtabs.java b/scripting/java/example/GLPtabs.java new file mode 100644 index 000000000..477320d69 --- /dev/null +++ b/scripting/java/example/GLPtabs.java @@ -0,0 +1,117 @@ + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; +import java.net.URL; +import java.net.*; +import java.io.*; +import com.easysw.cups.*; + +public class GLPtabs extends JPanel +{ + JTabbedPane tabPanel = null; + + // + // Panels for the various tabs. + // + JPanel serverPanel = null; + JScrollPane printersPanel = null; + JPanel detailPanel = null; + JPanel optionsPanel = null; + + GLPserver server = null; + GLPprinters printers = null; + GLPdetail detail = null; + GLPoptions options = null; + + + + // Constructor + public GLPtabs() + { + tabPanel = new JTabbedPane(); + tabPanel.setBackground(Color.white); + + serverPanel = new JPanel(); + server = new GLPserver(); + serverPanel = server.getPanel(); + tabPanel.add("Server", serverPanel); + tabPanel.setBackgroundAt(0,GLPcolors.tabBackgroundColor); + tabPanel.setForegroundAt(0,GLPcolors.tabForegroundColor); + + printersPanel = new JScrollPane(); + printers = new GLPprinters(); + printersPanel = printers.getPanel(); + tabPanel.add( "Printers", printersPanel ); + tabPanel.setBackgroundAt(1,GLPcolors.tabBackgroundColor); + tabPanel.setForegroundAt(1,GLPcolors.tabForegroundColor); + + + detail = new GLPdetail(); + detailPanel = detail.getPanel(); + tabPanel.add( "Destination", detailPanel ); + tabPanel.setBackgroundAt(2,GLPcolors.tabBackgroundColor); + tabPanel.setForegroundAt(2,GLPcolors.tabForegroundColor); + + options = new GLPoptions(); + optionsPanel = new JPanel(); + optionsPanel.setBackground(GLPcolors.backgroundColor); + tabPanel.add( "Options", optionsPanel ); + tabPanel.setBackgroundAt(3,GLPcolors.tabBackgroundColor); + tabPanel.setForegroundAt(3,GLPcolors.tabForegroundColor); + + tabPanel.setSelectedIndex(0); + + tabPanel.addChangeListener(new ChangeListener() + { + public void stateChanged( ChangeEvent e ) + { + Object source = e.getSource(); + if (!printers.cupsServerName.equals(GLPvars.getServerName())) + { + printers.load(); + printersPanel = printers.getPanel(); + tabPanel.setComponentAt(1,printersPanel); + } + } + }); + + JPanel jobsPanel = new JPanel(); + JPanel filePanel = new JPanel(); + } + + + + public void updateServerPanel(String s) + { + server.updateServer(s); + serverPanel = server.getPanel(); + tabPanel.setComponentAt(0,serverPanel); + } + + public void updateDetailPanel() + { + detail.topDetail(); + detailPanel = detail.getPanel(); + tabPanel.setComponentAt(2,detailPanel); + } + + public void updateOptionsPanel(CupsPrinter cp) + { + options.updateOptions(cp); + optionsPanel = options.getPanel(); + tabPanel.setComponentAt(3,optionsPanel); + } + + public boolean updatePrintersTab() + { + return(true); + } + + public JTabbedPane getPanel() + { + return(tabPanel); + } + +} diff --git a/scripting/java/example/GLPvars.class b/scripting/java/example/GLPvars.class new file mode 100644 index 0000000000000000000000000000000000000000..7c9b46c349330ec63b35159232d50ddd488f4396 GIT binary patch literal 1592 zc-nPTT~`}b6x}x&$V`|J2!Tq2RQyb$Hd3pFg8dMsg$A0MK&w7Yl36e~WV&Vsus-`o zeDbw64_)Z0%cnl{fA}}leI^6pqh_sp&b{ZJv(MS*+{~+ge*Y7|Wjspb0LPG@UDVJxs+yA|5)8V%u*t1ht{f$b}#Wm~g? z;GnHw?pjXgPPJCEI<~7Y86o~y2@VKWS#4O&CV_ZIU@f$ofr3$`yKHGn2T?UuCkPcr zde!WOj$086@Abg8{ML43O=@M>j@KllYp;22+vWXGd@nYI{JG?=9VOZJ4%VKmdXimz zr!XppC2#k!Ym;WrKDg*~obZN1vRK+=txL?HkgYl$dwp-WY5Q>wP23bRTXuM|llfxl zb-m04r`^Vj=e;Cdw&jvY{X{deR=eHsPFngYd*|_D>HF8^)E8TB%q3m-_WYK;>`3J% z`?qiT!DWdtQO1Xyh3mB}ciRg>6K`OW!|#vaw(na{B$bI7yq&@W6W^e2qJa(0>TF^Y zn|NsAqJU_==P{}v`_!^;{V+d2XJQJICf>xfiA#9P#5;J`#Cv$(#0MyvD4|H_xWrTV z_nSL>j(okRUk4|}7M*En&v&83A!~v2lO2t7g_6A!*Ok(FXR@2%{|^{~Ax+@U5FU{( z#Cj^$tUuDEKpk}^I+IPLNhs3f6zNi=btvgKjje9Zr z41+I`p)4OFmB7QZH14vv6^vk&;h!;YFWe!Z0MAF^S1AvnE4+YlFS+)ko3WrE1 z@E45w&q@`Je17@&@A6aC=RS=Tg@#F4YJfTpH%o}O!&nP#i2c(=ENEC2ui01yBe z0009!2)Yn5q)5q{nV7DV`x2c8aADSz-i2bpnt|>##8X7yIA+uH4b!a~KovXD6eQQD QxKT0!L{Y^7$s_;(JJ*UWq5uE@ literal 0 Hc-jL100001 diff --git a/scripting/java/example/images/print-test-page.gif b/scripting/java/example/images/print-test-page.gif new file mode 100644 index 0000000000000000000000000000000000000000..8268a1d14502044077743b88d1bcc1415d19846c GIT binary patch literal 519 zc-jF60{Hz$Nk%w1VQc^w0OJ4v003rHRhc+Ah#VYu|NsB0s?2e5s>a6Mjg7nF;_f*) zh~wk#9UXW7|NsC0|NsC0EC2ui0Bisk000F35XecZy*TU5dksV=j)Z5PXo`a5sJ?J~ zvTZ5fcutdf@2fk}Z%EuI7CcK}xx5Gh1J9GWjH(7yL6LzJT1W*;fe^@OCu35%Gq6g6 z>mk=$2?Y$H^W^ES9BdL#2m}XJ9e8m7AcbQIMF4Yv6d@90cLf0m0tN+I1)T*50C)sp z6df7N6F+p}TR*1`+KBaUOHmH?EtlpoR(vx)==i{@eGeIp_26TdK&@Pye1 zLX-z+6PCd;SB|2x680oTOSSAz0c^bl68y4wD&(h;1O6qEOs~~V*J(n5} zMl5ww)hu`wH&&QsU=YHVM?d-MkY*-@n&oaDRRWWe0AE*s{Yh35VnUpwz-Em}XOc#! z7j>@eiiVIe0VZb+*j5XszEUg4p`%DH(S}*y^CnUxh7pGd<14vpEz!6>%QY4&ve>uB}(tM*u$=0 zh~*0aj!0x6HzDkv(CC0T1OcxjAXDO$YNXGu%!(~jZg(+7?vyLqy7<$y%2h8}_!c5O1#O@a zR!WRP_!jAB`?Z9$cdG_4C31H(A zdizN3T)OVI;oZx(uiw9b{pt&>?ju3M1^W$@co=a3AuVIfv^w~$y{pB-h-^IRve9Bg zZG=2w@aN}0nh$QUqw#^j(+Ej~1F`Ce!zK{J!PXLzHp!B$F;!J<`YG|1zggYpvXeMA z%FvQ4S$-^KZ{23iki0V_sP*gF|CtQpooYbnMxmBBKcy4M-C5$iA{&z@e5CS~(%)GY zwuySBIn~$SY5(E223JIZ}*y^LtUxh7o*d<14vpEz!6>%LuB}(tM*u$=0 zh~*myj!5JnHzDkv&}e`-1OcxjAXDO$YNXGu%!(}weV8v8{Hb9z$++MQBS{AMyne4< zPg!tsf`dqaWG`DLdy9O1et%1cW{D@23XFLUVl$E}mY<-ZqN56DR9c&K9d@8jryiYU zvOce{9C&d{6`PNLh*qjAvjj$XH@joJy)|yLZ(7L9e^IH1F zLyI0wx-^8frUUk5m6{($lP6iX&TwkxP?)kaCyX2}-JSFs9tCLZ!0u1?hk zx4T9zA5O7W3S386j!j09Ix3mZRpw$`N+@{m&Z!V1q&>o0?%loOjx9b{`_quYOaEm? zeBmB*TIHu7fAQF47gS^=HD6Vck>^l?Vfa!Pbqz-Mo=eSm=fP9kC6i!R8dex!Qr>`w z9*6ENg&|ewfq>OPD^Oa}{c(S6uiji|^0mQ_G<_92nSAtu+6 z!Xz0%BoKbnq+e+5r`BDI%qXK(Sk8qNLTowarFngYDGoeAaEaH2Q@|I9nu$$_A_SFr zxno678s`-Tl`Rn=T!+QMrhK8~IpiZ692QAY4l0u8RvAT_sG=?*I$EIbHE3x=j+G)2 YPqX2ntm^8kuqFTiJFzuv761SM literal 0 Hc-jL100001 diff --git a/scripting/java/example/images/restart-job.gif b/scripting/java/example/images/restart-job.gif new file mode 100644 index 0000000000000000000000000000000000000000..8dc072759f1c42c4919306c8a1c97de1e568bc18 GIT binary patch literal 440 zc-jHD0Z0BvNk%w1VO9Va0OJ4v003rHRhc+Ah#VYu|NsAujk~I<%yDt5;^OYc#@#tN zh~wk#9UXW7|NsC0|NsC0EC2ui09F7O000F35XecZy*TTQ1NmS`aAawol_!R1>%Nk@ zj&N;jvUu&=>7bc0lxywR7wvh=^57d}!~nADm4ccQ5qKsB6@mbXkU*0+ zK@b3X$lTP!mm%Fgd-WVTY-6BZyM%7>>Ww1>ZKA(#qAI4L;Kxn1L}JP%I#BI^L4gY8 zoV%1L0VPJgej(_Yj|Cn%1q>`PwOfSe2w`V>HEBnbnOUV4g-69A^5qzd{n#t4(M iC(;>3%eLr>ws6bNh)cKO42pHps-2s+?cNy?002AYBETg8 literal 0 Hc-jL100001 diff --git a/scripting/java/example/images/show-active.gif b/scripting/java/example/images/show-active.gif new file mode 100644 index 0000000000000000000000000000000000000000..0c1ef7d6c2ab991cdf692d6c2bdee9cd93d9d6b5 GIT binary patch literal 581 zc-jF)0=oT2Nk%w1VSWG?0OJ4v003rjajL4S%s4oRRaKcB9Cza4?*IS)#>U-^jk`HH zh~wk#9UXW7|NsC0|NsC0EC2ui0Db@$000F35XecZy*TU5yU)ZSj^y#3XsWJSSdwfk z&otn^X07kMb(g)MkoFr5k4Tha0mK9Zf`DW|DCnqF57nwF5C)j-iorBq3Yg1V&dwqEAMcbjaO5>EnP0U~^=ssOj6Q5cf|x~Fsk30$zN8BA#INX(`*-$>IT$!@Z@*`Xj~j*7|OH~egKHR#j*D28$C@F&;a<> z27tmznEV{#qe&pZXqos}wB`w*2@(4RZh7F7!C;$zh)|mNHb9L4X6z=sBk&EQD+v+v zgk$IIjUWn>R3`F>hYdasZ<2kvWYOiw7=_yo<9l5CEa zB8+A5*$!dZflbXCg4Q*J!fk9gbt4Kf$3MG%^MIXzXe?YjQc~8Ux54Mn35UqV6Z$Tm zLu(#M5*GALBRD#lhejr8ca3HMYY?C*weIA)LTFxs*5LTD%$LGm#d1Ru)-c_5Kq>N- zdkWYBpmq_jwR@oeMZS*~z+DFyl;2NaS(#3%ag!wA!&|7GRlNBld8iTU*H>!*!_L<9gkt7-?h literal 0 Hc-jL100001 diff --git a/scripting/java/example/images/show-completed.gif b/scripting/java/example/images/show-completed.gif new file mode 100644 index 0000000000000000000000000000000000000000..7603191525eb11220bbd34488f920cb87c174942 GIT binary patch literal 657 zc-jGx0&e|BNk%w1VU_?F0OJ4v003rjajL4S%s4oRRaKcB9Cza4?*IS)#>U-^jk`HH zh~wk#9UXW7|NsC0|NsC0EC2ui0G0q3000F35XecZy*TU5yZ@j>9As%8VXCfd+m5H{ z&U9^maE#u3@4vd;Z%8a!ax$ZG=~FCDnSekLkPHX~n^ZukU9+qLVQ~3k2;CLqS;80& z2*e=)5FFAoIpR&9+3^-+8zTZ2e;6b!Yi&nx00oJMGmr+42bF$z7;+qhhME_Nifk7n z2qIl}0SN+N15;J6RduZZQi1@Uv=Uo_Qv_VEeZK<3puM&vg|<_I1*`!F%N3Hy03^V( z&&6OIix&lN2)K4}mjDBoa&+e~U7QoT6A5r{WF&I+bJzN*n)G`P42UKT06=?n^i891 z=%7G;0kIe`Q0~JT4B?bXIFyK9mvjD{=oNGnuONjtx%Nf6{-%aJ`{YEmYrkSMNLQx;A5F{@Xz z84b+xU{g14fOWjGP*L^-9-ReTmGYdL^0RJJ?;lC*WRSF4LE zIrHKP;($B67q@D_Du>FwDO*UoCOvPa`L3L0Im9;sL<@M+O?Q$&PmA#qKxQa2ZtG{U z%KeBHf@JnCqjD8u%cgreE`$U2D^#Egbfy6*h7UG rYUo0T9@4-eh#{)rUWpEyk$Ci08>@BM~&35CH%?g+L?8 literal 0 Hc-jL100001 diff --git a/scripting/java/example/runit b/scripting/java/example/runit new file mode 100755 index 000000000..0abb92486 --- /dev/null +++ b/scripting/java/example/runit @@ -0,0 +1,2 @@ +#!/bin/sh +java GLP diff --git a/scripting/java/src/com/easysw/cups/Cups.java b/scripting/java/src/com/easysw/cups/Cups.java new file mode 100644 index 000000000..a2cbd92b9 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/Cups.java @@ -0,0 +1,1413 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * An Cups object is used for connecting to servers, + * reading and writing data, and performing common CUPS operations. + * + * @author TDB + * @version 1.0.1 + * @since JDK1.3 + */ + +import java.io.*; +import java.util.*; +import java.net.*; + +public class Cups +{ + + static final int REQ_STATE_CREATE_HTTP = 0; + static final int REQ_STATE_WRITE_HTTP_HEADER = 1; + static final int REQ_STATE_WRITE_IPP_HEADER = 2; + static final int REQ_STATE_WRITE_IPP_ATTRS = 3; + static final int REQ_STATE_FINISH_IPP_ATTRS = 4; + static final int REQ_STATE_READ_RESPONSE = 5; + static final int REQ_STATE_DONE = 6; + static final String[] req_state_names = + { "Create HTTP", + "Write Http Header", + "Write IPP Header", + "Write IPP Attrs", + "Finish IPP Attrs", + "Read Response", + "Done" + }; + + + static final int FILEREQ_STATE_CREATE_HTTP = 0; + static final int FILEREQ_STATE_WRITE_HTTP_HEADER = 1; + static final int FILEREQ_STATE_WRITE_IPP_HEADER = 2; + static final int FILEREQ_STATE_WRITE_IPP_ATTRS = 3; + static final int FILEREQ_STATE_FINISH_IPP_ATTRS = 4; + static final int FILEREQ_STATE_WRITE_FILE_DATA = 5; + static final int FILEREQ_STATE_READ_RESPONSE = 6; + static final int FILEREQ_STATE_DONE = 7; + static final String[] filereq_state_names = + { "Create HTTP", + "Write Http Header", + "Write IPP Header", + "Write IPP Attrs", + "Finish IPP Attrs", + "Write File Data", + "Read Response", + "Done" + }; + + + IPP ipp; // IPP Request + IPPHttp http; // Connection to server + + + String protocol; // Protocol name + String address; // address/name of server + int port; // Port # + String path; // Path .... + String dest; // Name of destination printer + String instance; // Instance of printer + + // + // encrypt, user, and passwd are not fully implemented! + // + boolean encrypt; // Open encrypted connection. + String user; // User to login as. + String passwd; // Password if needed. + + String site; // URL of site. + + int last_error; // Last error # + String error_text; // Text for error + + /** + * Void constructor. + */ + public Cups() + { + http = null; + ipp = null; + + protocol = "http"; + address = "localhost"; + port = 631; + path = "/"; + site = "http://localhost:631/"; + dest = ""; + instance = ""; + user = ""; + passwd = ""; + encrypt = false; + } + + /** + * Constructor using a URL. + * + * @param p_url A URL object. + */ + public Cups( URL p_url ) + { + http = null; + ipp = null; + + protocol = p_url.getProtocol() + "://"; + address = p_url.getHost(); + port = p_url.getPort(); + path = p_url.getPath(); + + site = protocol + address; + if (port > 0) + site = site + ":" + port; + + if (path.length() > 0) + site = site + path; + + dest = ""; + instance = ""; + user = ""; + passwd = ""; + encrypt = false; + } + + + /** + * Set the value of the protocol member. Valid values + * are ipp or http. + * + * @param p_protocol String with protocol. + */ + public void setProtocol( String p_protocol ) + { + protocol = p_protocol; + site = protocol + "://" + address + ":" + port + path; + } + + /** + * Set the value of the server member. This is an + * IP address or a hostname. + * + * @param p_server IP address or hostname. + */ + public void setServer( String p_server ) + { + address = p_server; + site = protocol + "://" + address + ":" + port + path; + } + + + /** + * Set the value of the port member. + * + * @param p_port Port number. + */ + public void setPort( int p_port ) + { + port = p_port; + site = protocol + "://" + address + ":" + port + path; + } + + + /** + * Set the value of the user member. + * + * @param p_user User name. + */ + public void setUser( String p_user ) + { + user = p_user; + } + + + /** + * Set the value of the passwd member. + * + * @param p_passwd Password. + */ + public void setPasswd( String p_passwd ) + { + passwd = p_passwd; + } + + + /** + * Set the value of the dest member. + * + * @param p_dest Destination. + */ + public void setDest( String p_dest ) + { + dest = p_dest; + } + + + /** + * Set the value of the instance member. + * + * @param p_instance Instance. + */ + public void setInstance( String p_instance) + { + instance = p_instance; + } + + + /** + * Set the value of the encrypt member. + * + * @param p_enrypt Yes or no. + */ + public void setEncrypt( boolean p_encrypt ) + { + encrypt = p_encrypt; + } + + + /** + * Get the value of the encrypt member. + * + * @return boolean Encryption on or off. + */ + public boolean getEncrypt() + { + return(encrypt); + } + + + /** + * Set the value of the path member. This is the + * path that will be used in the POST method. + * + * @param p_path Path on server. + */ + public void setPath( String p_path ) + { + path = p_path; + site = protocol + "://" + address + ":" + port + path; + } + + + + public boolean doRequest(String from) throws IOException + { + // System.out.println("doRequest From: " + from ); + return(doRequest()); + } + + + + /** + * Do a CUPS request to the server. + * + * @param p_dest Destination name. + * @return boolean True on success, false otherwise + * @throw IOException + */ + public boolean doRequest() throws IOException + { + IPPAttribute attr; + int state = REQ_STATE_CREATE_HTTP; + int errors = 0; + + while (true) + { + switch( state ) + { + + case REQ_STATE_CREATE_HTTP: + String url_str = site + dest; + + try + { + if (user.length() > 0 && passwd.length() > 0) + http = new IPPHttp(url_str, "", user, passwd ); + else + http = new IPPHttp(url_str); + state++; + } + catch (IOException e) + { + throw(e); + } + break; + + + + case REQ_STATE_WRITE_HTTP_HEADER: + // + // Send the HTTP header. + // + switch( http.writeHeader( http.path, ipp.sizeInBytes() )) + { + case IPPHttp.HTTP_FORBIDDEN: + case IPPHttp.HTTP_NOT_FOUND: + case IPPHttp.HTTP_BAD_REQUEST: + case IPPHttp.HTTP_METHOD_NOT_ALLOWED: + case IPPHttp.HTTP_PAYMENT_REQUIRED: + case IPPHttp.HTTP_UPGRADE_REQUIRED: + case IPPHttp.HTTP_ERROR: + case IPPHttp.HTTP_UNAUTHORIZED: + errors++; + if (errors < 5) + { + if (!http.reConnect()) + { + System.out.println("Could not reConnect(0)!"); + return(false); + } + } + else + { + return(false); + } + break; + + default: state++; + } + break; + + + + case REQ_STATE_WRITE_IPP_HEADER: + // + // Send the request header. + // + byte[] header = new byte[8]; + header[0] = (byte)1; + header[1] = (byte)1; + header[2] = (byte)((ipp.request.operation_id & 0xff00) >> 8); + header[3] = (byte)(ipp.request.operation_id & 0xff); + header[4] = (byte)((ipp.request.request_id & 0xff000000) >> 24); + header[5] = (byte)((ipp.request.request_id & 0xff0000) >> 16); + header[6] = (byte)((ipp.request.request_id & 0xff00) >> 8); + header[7] = (byte)(ipp.request.request_id & 0xff); + http.write( header ); + if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) + { + errors++; + if (errors < 5) + { + if (http.reConnect()) + state = REQ_STATE_WRITE_HTTP_HEADER; + else + { + System.out.println("Could not reConnect(1)\n"); + return(false); + } + } + else + { + return(false); + } + } + else state++; + break; + + + case REQ_STATE_WRITE_IPP_ATTRS: + // + // Send the attributes list. + // + byte[] bytes; + int sz; + int last_group = -1; + boolean auth_error = false; + for (int i=0; i < ipp.attrs.size() && !auth_error; i++) + { + attr = (IPPAttribute)ipp.attrs.get(i); + sz = attr.sizeInBytes(last_group); + bytes = attr.getBytes(sz,last_group); + last_group = attr.group_tag; + http.write(bytes); + + // + // Check for server response between each attribute. + // + if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) + { + errors++; + if (errors < 5) + { + if (!http.reConnect()) + { + System.out.println("Could not reConnect(2)"); + return(false); + } + state = REQ_STATE_WRITE_HTTP_HEADER; + auth_error = true; + } + else + { + return(false); + } + } + + } + if (!auth_error) + state++; + break; + + + + case REQ_STATE_FINISH_IPP_ATTRS: + // + // Send the end of attributes tag. + // + byte[] footer = new byte[1]; + footer[0] = (byte)IPPDefs.TAG_END; + http.write( footer ); + + // + // Keep checking ..... + // + if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) + { + errors++; + if (errors < 5) + { + if (!http.reConnect()) + { + System.out.println("Could not reConnect(3)"); + return(false); + } + state = REQ_STATE_WRITE_HTTP_HEADER; + } + else + { + return(false); + } + } + else state++; + break; + + + + case REQ_STATE_READ_RESPONSE: + // + // Now read back response + // + int read_length; + read_length = http.read_header(); + switch( http.status ) + { + case IPPHttp.HTTP_OK: + break; + + case IPPHttp.HTTP_UNAUTHORIZED: + http.reConnect(); + state = REQ_STATE_WRITE_HTTP_HEADER; + errors = 0; + break; + + default: + errors++; + if (errors < 5) + { + if (!http.reConnect()) + { + System.out.println("Could not reConnect(4)"); + return(false); + } + state = REQ_STATE_WRITE_HTTP_HEADER; + } + else + { + System.out.println("Too many errors: " + errors ); + return(false); + } + break; + } + + if ((read_length > 0) && (state == REQ_STATE_READ_RESPONSE)) + { + http.read_buffer = http.read(read_length); + ipp = http.processResponse(); + state++; + } + break; + + case REQ_STATE_DONE: + // + // success. + // + http.conn.close(); + http = null; + return(true); + } + } + + } // End of doRequest + + + + /** + * Send a FILE to the CUPS server. + * + * @param file File to send. + * @return boolean True on success, false otherwise + * @throw IOException + */ + public boolean doRequest(File file) throws IOException + { + IPPAttribute attr; + int state = FILEREQ_STATE_CREATE_HTTP; + int errors = 0; + FileInputStream fis = null; + + while (true) + { + switch( state ) + { + + case FILEREQ_STATE_CREATE_HTTP: + String url_str = site + dest; + try + { + if (user.length() > 0 && passwd.length() > 0) + http = new IPPHttp(url_str, "", user, passwd ); + else + http = new IPPHttp(url_str); + state++; + } + catch (IOException e) + { + throw(e); + } + break; + + + + case FILEREQ_STATE_WRITE_HTTP_HEADER: + + if (fis != null) + { + fis.close(); + } + + // + // Open an input stream to the file. + // + try + { + fis = new FileInputStream(file); + } + catch (IOException e) + { + last_error = -1; + error_text = "Error opening file input stream."; + throw(e); + } + + // + // Send the HTTP header. + // + int ippSz = ipp.sizeInBytes() + (int)file.length(); + switch( http.writeHeader( http.path, ippSz )) + { + case IPPHttp.HTTP_FORBIDDEN: + case IPPHttp.HTTP_NOT_FOUND: + case IPPHttp.HTTP_BAD_REQUEST: + case IPPHttp.HTTP_METHOD_NOT_ALLOWED: + case IPPHttp.HTTP_PAYMENT_REQUIRED: + case IPPHttp.HTTP_UPGRADE_REQUIRED: + case IPPHttp.HTTP_ERROR: + case IPPHttp.HTTP_UNAUTHORIZED: + errors++; + if (errors < 5) + { + http.reConnect(); + } + else + return(false); + break; + + default: state++; + } + break; + + + + case FILEREQ_STATE_WRITE_IPP_HEADER: + // + // Send the request header. + // + byte[] header = new byte[8]; + header[0] = (byte)1; + header[1] = (byte)1; + header[2] = (byte)((ipp.request.operation_id & 0xff00) >> 8); + header[3] = (byte)(ipp.request.operation_id & 0xff); + header[4] = (byte)((ipp.request.request_id & 0xff000000) >> 24); + header[5] = (byte)((ipp.request.request_id & 0xff0000) >> 16); + header[6] = (byte)((ipp.request.request_id & 0xff00) >> 8); + header[7] = (byte)(ipp.request.request_id & 0xff); + http.write( header ); + if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) + { + errors++; + if (errors < 5) + { + http.reConnect(); + state = FILEREQ_STATE_WRITE_HTTP_HEADER; + } + else + return(false); + } + else state++; + break; + + + case FILEREQ_STATE_WRITE_IPP_ATTRS: + // + // Send the attributes list. + // + byte[] bytes; + int sz; + int last_group = -1; + boolean auth_error = false; + for (int i=0; i < ipp.attrs.size() && !auth_error; i++) + { + attr = (IPPAttribute)ipp.attrs.get(i); + sz = attr.sizeInBytes(last_group); + bytes = attr.getBytes(sz,last_group); + last_group = attr.group_tag; + http.write(bytes); + + // + // Check for server response between each attribute. + // + if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) + { + errors++; + if (errors < 5) + { + http.reConnect(); + state = FILEREQ_STATE_WRITE_HTTP_HEADER; + auth_error = true; + } + else + return(false); + } + + } + if (!auth_error) + state++; + break; + + + + case FILEREQ_STATE_FINISH_IPP_ATTRS: + // + // Send the end of attributes tag. + // + byte[] footer = new byte[1]; + footer[0] = (byte)IPPDefs.TAG_END; + http.write( footer ); + + // + // Keep checking ..... + // + if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) + { + errors++; + if (errors < 5) + { + http.reConnect(); + state = FILEREQ_STATE_WRITE_HTTP_HEADER; + } + else + return(false); + } + else state++; + break; + + + + case FILEREQ_STATE_WRITE_FILE_DATA: + // + // Send the file data - this could be improved on ALOT. + // + int count; + byte[] b = new byte[1024]; + while ((state == FILEREQ_STATE_WRITE_FILE_DATA) && + ((count = fis.read(b)) != -1)) + { + // + // Keep checking ..... + // + if (http.checkForResponse() >= IPPHttp.HTTP_BAD_REQUEST) + { + errors++; + if (errors < 5) + { + http.reConnect(); + state = FILEREQ_STATE_WRITE_HTTP_HEADER; + } + else + { + return(false); + } + } + else + { + if (count > 0) + http.write( b, count ); + } + + } // while + + if (state == FILEREQ_STATE_WRITE_FILE_DATA) + { + fis.close(); + fis = null; + state++; + } + break; + + + + case FILEREQ_STATE_READ_RESPONSE: + // + // Now read back response + // + int read_length; + read_length = http.read_header(); + switch( http.status ) + { + case IPPHttp.HTTP_OK: + break; + + case IPPHttp.HTTP_UNAUTHORIZED: + http.reConnect(); + state = FILEREQ_STATE_WRITE_HTTP_HEADER; + errors = 0; + break; + + default: + errors++; + if (errors < 5) + { + http.reConnect(); + state = FILEREQ_STATE_WRITE_HTTP_HEADER; + } + else + { + return(false); + } + break; + } + + if ((read_length > 0) && (state == FILEREQ_STATE_READ_RESPONSE)) + { + http.read_buffer = http.read(read_length); + ipp = http.processResponse(); + state++; + } + break; + + case FILEREQ_STATE_DONE: + // + // success. + // + http.conn.close(); + http = null; + return(true); + } + } + + } // End of doRequest(file) + + + + + + + + /** + * Get a list of jobs. + * + * @param showMyJobs Show only jobs for user. + * @param showCompleted Show completed OR active jobs. + * + * @return CupsJob[] Array of job objects, or null. + * @throw IOException + */ + public CupsJob[] cupsGetJobs( boolean showMyJobs, boolean showCompleted ) + throws IOException + { + + IPPAttribute a; + + String req_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" + }; + + + ipp = new IPP(); + ipp.request = new IPPRequest( 1, (short)IPPDefs.GET_JOBS ); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, + "attributes-charset" ); + a.addString( "", "iso-8859-1" ); + ipp.addAttribute(a); + + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, + "attributes-natural-language" ); + a.addString( "", "en" ); + ipp.addAttribute(a); + + + // + // Add the printer uri + // + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, + "printer-uri" ); + + if (site != null) + a.addString( "", site ); + else + a.addString( "", "ipp://localhost/jobs" ); // Default ... + // a.dump_values(); + ipp.addAttribute(a); + + + // + // Add the requesting user name + // **FIX** This should be fixed to use the user member. + // + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME, + "requesting-user-name" ); + a.addString( "", "root" ); + ipp.addAttribute(a); + + // + // Show only my jobs? + // + if (showMyJobs) + { + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_BOOLEAN, + "my-jobs" ); + a.addBoolean( true ); + ipp.addAttribute(a); + } + + // + // Show completed jobs? + // + if (showCompleted) + { + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_KEYWORD, + "which-jobs" ); + a.addString( "", "completed" ); + ipp.addAttribute(a); + } + + // + // Get ALL attributes - to get only listed ones, + // uncomment this and fill in req_attrs. + // + // a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_KEYWORD, + // "requested-attributes" ); + // a.addStrings( "", req_attrs ); + // ipp.addAttribute(a); + + // + // Do the request and process the response. + // + if (doRequest("cupsGetJobs")) + { + + + // + // First we have to figure out how many jobs there are + // so we can create the array. + // + + // + // Skip past leading attributes + // + int i = 0; + int group_tag = -1; + while ((i < ipp.attrs.size()) && (group_tag != IPPDefs.TAG_JOB)) + { + a = (IPPAttribute)ipp.attrs.get(i); + group_tag = a.group_tag; + if (group_tag != IPPDefs.TAG_JOB) + i++; + } + + int num_jobs = 0; + group_tag = IPPDefs.TAG_JOB; + while ((i < ipp.attrs.size()) && (group_tag == IPPDefs.TAG_JOB)) + { + a = (IPPAttribute)ipp.attrs.get(i++); + if ((a != null) && (a.name.compareTo("job-id") == 0)) + num_jobs++; + // a.dump_values(); + } + + if (num_jobs < 1) + return(null); + + + // + // Now create the array of the proper size. + // + int n = 0; + CupsJob[] jobs = new CupsJob[num_jobs]; + for (n=0; n < num_jobs; n++) + { + jobs[n] = new CupsJob(); + } + + + + + // + // Skip past leading attributes + // + group_tag = -1; + i = 0; + while ((i < ipp.attrs.size()) && (group_tag != IPPDefs.TAG_JOB)) + { + a = (IPPAttribute)ipp.attrs.get(i); + group_tag = a.group_tag; + if (group_tag != IPPDefs.TAG_JOB) + i++; + } + + // + // Now we actually fill the array with the job data. + // + n = 0; + for (;i < ipp.attrs.size(); i++) + { + a = (IPPAttribute)ipp.attrs.get(i); + + if (a.group_tag == IPPDefs.TAG_ZERO) + { + n++; + continue; + } + else + { + try + { + jobs[n].updateAttribute( a ); + } + catch (ArrayIndexOutOfBoundsException e) + { + return(jobs); + } + } + } + return( jobs ); + } + return(null); + + } // End of cupsGetJobs + + + + /** + * Get a list of printers. + * + * @return String[] Array of printers, or null. + * @throw IOException + */ + public String[] cupsGetPrinters() + throws IOException + { + + IPPAttribute a; + + ipp = new IPP(); + + // + // Fill in the required attributes + // + ipp.request = new IPPRequest( 1, (short)IPPDefs.CUPS_GET_PRINTERS ); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, + "attributes-charset" ); + a.addString( "", "iso-8859-1" ); + ipp.addAttribute(a); + + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, + "attributes-natural-language" ); + a.addString( "", "en" ); + ipp.addAttribute(a); + + + if (doRequest("cupsGetPrinters")) + { + int num_printers = 0; + for (int i=0; i < ipp.attrs.size(); i++) + { + a = (IPPAttribute)ipp.attrs.get(i); + if ((a.name.compareTo("printer-name") == 0) && + (a.value_tag == IPPDefs.TAG_NAME)) + { + num_printers++; + } + } + if (num_printers < 1) + return(null); + + String[] printers = new String[num_printers]; + IPPValue val; + int n = 0; + for (int i=0; i < ipp.attrs.size(); i++) + { + a = (IPPAttribute)ipp.attrs.get(i); + if (a.group_tag < 2) + continue; + + if ((a.name.compareTo("printer-name") == 0) && + (a.value_tag == IPPDefs.TAG_NAME)) + { + val = (IPPValue)a.values.get(0); + if (val != null) + { + printers[n] = val.text; + n++; + } + } + } + return( printers ); + + } // if doRequest ... + + return(null); + + } // End of cupsGetPrinters + + + + + /** + * Get default destination. + * + * @return String Name of default printer, or null. + * @throw IOException + */ + public String cupsGetDefault() + throws IOException + { + + IPPAttribute a; + + + ipp = new IPP(); + // + // Fill in the required attributes + // + ipp.request = new IPPRequest( 1, (short)IPPDefs.CUPS_GET_DEFAULT); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, + "attributes-charset" ); + a.addString( "", "iso-8859-1" ); + ipp.addAttribute(a); + + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, + "attributes-natural-language" ); + a.addString( "", "en" ); + ipp.addAttribute(a); + + + if (doRequest("cupsGetDefault")) + { + if ((ipp == null) || (ipp.attrs == null)) + return(null); + + int num_printers = 0; + for (int i=0; i < ipp.attrs.size(); i++) + { + a = (IPPAttribute)ipp.attrs.get(i); + if ((a.name.compareTo("printer-name") == 0) && + (a.value_tag == IPPDefs.TAG_NAME)) + { + IPPValue val = (IPPValue)a.values.get(0); + if (val != null) + { + return( val.text ); + } + } + } + } // if doRequest ... + + return(null); + + } // End of cupsGetDefault + + + + + + + /** + * Get printer attributes + * + * @param printer_name Name of printer to get info for. + * @return List List of attributes. + * @throw IOException + * + * @see CupsPrinter + */ + public List cupsGetPrinterAttributes( String printer_name ) + throws IOException + { + + IPPAttribute a; + + ipp = new IPP(); + + // + // Fill in the required attributes + // + ipp.request = new IPPRequest( 1, (short)IPPDefs.GET_PRINTER_ATTRIBUTES ); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, + "attributes-charset" ); + a.addString( "", "iso-8859-1" ); + ipp.addAttribute(a); + + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, + "attributes-natural-language" ); + a.addString( "", "en" ); + ipp.addAttribute(a); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, + "printer-uri" ); + a.addString( "", site + "/printers/" + printer_name ); + ipp.addAttribute(a); + + if (doRequest("cupsGetPrinterAttributes")) + { + return(ipp.attrs); + } + + return(null); + + } // End of cupsGetPrinterAttributes + + + + + /** + * Print a file. + * + * @param p_filename Path of file to print. + * @param p_attrs[] Array of print job attributes. + * + * @return CupsJob Object with job info. + * + * @throw IOException + * + * @see CupsJob + */ + public CupsJob cupsPrintFile( String p_filename, + IPPAttribute p_attrs[] ) + throws IOException + { + + CupsJob job; + IPPAttribute a; + File file; + + + file = new File(p_filename); + if (!file.exists()) + { + last_error = -1; + error_text = "File does not exist."; + return(null); + } + + if (!file.canRead()) + { + last_error = -1; + error_text = "File cannot be read."; + return(null); + } + + + ipp = new IPP(); + // + // Fill in the required attributes + // + ipp.request = new IPPRequest( 1, (short)IPPDefs.PRINT_JOB ); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, + "attributes-charset" ); + a.addString( "", "iso-8859-1" ); + ipp.addAttribute(a); + + // ------------ + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, + "attributes-natural-language" ); + a.addString( "", "en" ); + ipp.addAttribute(a); + + // ------------ + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, + "printer-uri" ); + a.addString( "", site + dest ); + ipp.addAttribute(a); + + // ------------ + // **FIX** Fix this later. +/* + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME, + "requesting-user-name" ); + // a.addString( "", p_username ); + a.addString( "", "root"); + ipp.addAttribute(a); +*/ + + // ------------ + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME, + "job-name" ); + a.addString( "", file.getName() ); + ipp.addAttribute(a); + + if (p_attrs != null) + { + for (int i=0; i < p_attrs.length; i++) + { + a = p_attrs[i]; + ipp.addAttribute(a); + } + } + + if (doRequest(file)) + { + job = new CupsJob(); + for (int i=0; i < ipp.attrs.size(); i++) + { + a = (IPPAttribute)ipp.attrs.get(i); + job.updateAttribute(a); + } + return(job); + + } // if doRequest ... + + return(null); + + } // End of cupsPrintFile + + + + + + /** + * Cancel a job - send a job cancel request to the server. + * + * @param printer_name Destination. + * @param p_job_id ID of job. + * @param p_user_name Requesting user name. + * + * @throw IOException + */ + public int cupsCancelJob( String printer_name, + int p_job_id, + String p_user_name ) + throws IOException + { + + IPPAttribute a; + + ipp = new IPP(); + + // + // Fill in the required attributes + // + ipp.request = new IPPRequest( 1, (short)IPPDefs.CANCEL_JOB ); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, + "attributes-charset" ); + a.addString( "", "iso-8859-1" ); + ipp.addAttribute(a); + + // ------------ + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, + "attributes-natural-language" ); + a.addString( "", "en" ); + ipp.addAttribute(a); + + // ------------ + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, + "printer-uri" ); + a.addString( "", site + dest ); + ipp.addAttribute(a); + + // ------------ + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_INTEGER, + "job-id" ); + a.addInteger( p_job_id ); + ipp.addAttribute(a); + + // ------------ + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_NAME, + "requesting-user-name" ); + a.addString( "", p_user_name ); + ipp.addAttribute(a); + + if (doRequest("cupsCancelJob")) + { + for (int i=0; i < ipp.attrs.size(); i++) + { + a = (IPPAttribute)ipp.attrs.get(i); + a.dump_values(); + } + return(0); + + } // if doRequest ... + + return(0); + + } // End of cupsCancelJob + + + + + public List cupsGetPrinterStatus(String printer_name) + throws IOException + { + IPPAttribute a; + String p_uri; + + ipp = new IPP(); + + // + // Fill in the required attributes + // + ipp.request = new IPPRequest(1,(short)IPPDefs.GET_PRINTER_ATTRIBUTES); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_CHARSET, + "attributes-charset" ); + a.addString( "", "iso-8859-1" ); + ipp.addAttribute(a); + + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_LANGUAGE, + "attributes-natural-language" ); + a.addString( "", "en" ); + ipp.addAttribute(a); + + a = new IPPAttribute( IPPDefs.TAG_OPERATION, IPPDefs.TAG_URI, + "printer-uri" ); + p_uri = "ipp://" + address + ":" + + port + "/printers/" + printer_name; + a.addString( "", p_uri ); + ipp.addAttribute(a); + + if (doRequest("cupsGetPrinterStatus")) + { + return(ipp.attrs); + } + return(null); + } + + + + + +} // End of Cups class + diff --git a/scripting/java/src/com/easysw/cups/CupsJob.java b/scripting/java/src/com/easysw/cups/CupsJob.java new file mode 100644 index 000000000..4db08285f --- /dev/null +++ b/scripting/java/src/com/easysw/cups/CupsJob.java @@ -0,0 +1,216 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + + +/** + * A CupsJob object holds job data, and has methods to + * process cups job list responses into a usable form. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ + +// +import java.io.*; +import java.net.*; + +public class CupsJob +{ + public int job_id; + public String job_more_info; + public String job_uri; + public String job_printer_uri; + public long job_printer_up_time; + public String job_name; + public String job_originating_user_name; + public String document_format; + public String job_originating_host_name; + public int job_priority; + public int job_state; + public int job_media_sheets_completed; + public int job_k_octets; + public long time_at_creation; + public long time_at_processing; + public long time_at_completed; + public String job_hold_until; + public String job_sheets; + public String job_state_reasons; + + + /** + * Constructor - set some default values. + */ + public CupsJob() + { + job_id = -1; + job_more_info = ""; + job_uri = ""; + job_printer_uri = ""; + job_printer_up_time = 0; + job_name = ""; + job_originating_user_name = ""; + document_format = ""; + job_originating_host_name = ""; + job_priority = -1; + job_state = 0; + job_media_sheets_completed = 0; + job_k_octets = 0; + time_at_creation = 0; + time_at_processing = 0; + time_at_completed = 0; + job_hold_until = ""; + job_sheets = ""; + job_state_reasons = ""; + } + + + + + /** + * Process an attribute from a cups.doRequest() call + * and move the value into a local member. + * + * @see IPPDefs + * @see IPPValues + * @see IPPAttributes + */ + public void updateAttribute( IPPAttribute a ) + { + IPPValue val; + + // + // Kick out if no values are present. + // + if (a.values.size() < 1) + return; + + val = (IPPValue)a.values.get(0); + if (a.name.compareTo("job-more-info") == 0) + { + job_more_info = val.text; + } + else if (a.name.compareTo("job-uri") == 0) + { + job_uri = val.text; + } + else if (a.name.compareTo("job-printer-up-time") == 0) + { + job_printer_up_time = val.integer_value; + } + else if (a.name.compareTo("job-originating-user-name") == 0) + { + job_originating_user_name = val.text; + } + else if (a.name.compareTo("document-format") == 0) + { + document_format = val.text; + } + else if (a.name.compareTo("job-priority") == 0) + { + job_priority = val.integer_value; + } + else if (a.name.compareTo("job-originating-host-name") == 0) + { + job_originating_host_name = val.text; + } + else if (a.name.compareTo("job-id") == 0) + { + job_id = val.integer_value; + } + else if (a.name.compareTo("job-state") == 0) + { + job_state = val.integer_value; + } + else if (a.name.compareTo("job-media-sheets-completed") == 0) + { + job_media_sheets_completed = val.integer_value; + } + else if (a.name.compareTo("job-printer-uri") == 0) + { + job_printer_uri = val.text; + } + else if (a.name.compareTo("job-name") == 0) + { + job_name = val.text; + } + else if (a.name.compareTo("job-k-octets") == 0) + { + job_k_octets = val.integer_value; + } + else if (a.name.compareTo("time-at-creation") == 0) + { + time_at_creation = val.integer_value; + } + else if (a.name.compareTo("time-at-processing") == 0) + { + time_at_processing = val.integer_value; + } + else if (a.name.compareTo("time-at-completed") == 0) + { + time_at_completed = val.integer_value; + } + else if (a.name.compareTo("job-hold-until") == 0) + { + job_hold_until = val.text; + } + else if (a.name.compareTo("job-sheets") == 0) + { + job_sheets = val.text; + } + else if (a.name.compareTo("job-state-reasons") == 0) + { + job_state_reasons = val.text; + } + } + + + /** + * Convert a job status to a string. + * + * @see IPPDefs + */ + public String jobStatusText() + { + switch( job_state ) + { + case 3: return("Pending"); + case 4: return("Held"); + case 5: return("Processing"); + case 6: return("Stopped"); + case 7: return("Cancelled"); + case 8: return("Aborted"); + case 9: return("Completed"); + } + return("Unknown"); + } + + +} + +// eof .... diff --git a/scripting/java/src/com/easysw/cups/CupsPrinter.java b/scripting/java/src/com/easysw/cups/CupsPrinter.java new file mode 100644 index 000000000..34386ee9a --- /dev/null +++ b/scripting/java/src/com/easysw/cups/CupsPrinter.java @@ -0,0 +1,837 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * A CupsPrinter holds printer attribute / status information, + * and has methods to process CUPS server responses. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ + +import java.io.*; +import java.net.*; +import java.util.*; + +public class CupsPrinter +{ + + // + // Printer attributes / status members. + // + String printer_name; + + String printer_location; + String printer_info; + String printer_more_info; + + String[] printer_uri_supported; // Strings + String[] uri_authentication_supported; // Strings + String[] uri_security_supported; // Strings + + String attributes_charset; + String attributes_natural_language; + + int printer_state; + String printer_state_text; + String printer_state_reasons; + + boolean printer_is_accepting_jobs; + + long printer_up_time; + long printer_current_time; + + int queued_job_count; + + String[] pdl_override_supported; + String[] ipp_versions_supported; + + int[] operations_supported; // Integers + + boolean multiple_document_jobs_supported; + int multiple_operation_time_out; + int[] multiple_document_handling_supported; // Integers + + String charset_configured; + String natural_language_configured; + String generated_natural_language_supported; + String[] charset_supported; // Strings + + String document_format_default; + String[] document_format_supported; // Strings + + String[] compression_supported; // Strings + + int job_priority_default; + int job_priority_supported; + + int copies_default; + int lower_copies_supported; + int upper_copies_supported; + + boolean page_ranges_supported; + + int number_up_default; + int[] number_up_supported; // integers + + + int orientation_requested_default; + int[] orientation_requested_supported; // Integers + + int job_quota_period; + int job_k_limit; + int job_page_limit; + + String job_sheets_default; // Should this be a list too? + String[] job_sheets_supported; // Strings + + String device_uri; + + boolean color_supported; + int pages_per_minute; + + String printer_make_and_model; + + String media_default; + String[] media_supported; // Strings + + int finishings_default; + int[] finishings_supported; // Integers + + int printer_type; + + + + /** + * Constructor. Does not get status or attributes. + * + * @param c Cups object. + * + * @see Cups + */ + public CupsPrinter(Cups c) + { + setDefaults(); + } + + /** + * Constructor with name. Get status and attributes. + * + * @param c Cups object. + * @param name Name of printer. + * + * @see Cups + */ + public CupsPrinter(Cups c, String name) + { + setDefaults(); + printer_name = name; + + // + // + getStatus(c); + getAttributes(c); + } + + + + /** + * Initialize the members with mostly sane values. + * + */ + public void setDefaults() + { + printer_name = ""; + printer_location = ""; + printer_info = ""; + printer_more_info = ""; + printer_uri_supported = null; + uri_authentication_supported = null; + uri_security_supported = null; + attributes_charset = "us-ascii"; + attributes_natural_language = "en"; + printer_state = -1; + printer_state_text = ""; + printer_state_reasons = ""; + printer_is_accepting_jobs = false; + printer_up_time = 0; + printer_current_time = 0; + queued_job_count = 0; + pdl_override_supported = null; + ipp_versions_supported = null; + operations_supported = null; + multiple_document_jobs_supported = false; + multiple_operation_time_out = 0; + multiple_document_handling_supported = null; + charset_configured = ""; + natural_language_configured = ""; + generated_natural_language_supported = ""; + charset_supported = null; + document_format_default = ""; + document_format_supported = null; + compression_supported = null; + job_priority_default = -1; + job_priority_supported = -1; + copies_default = 1; + lower_copies_supported = 1; + upper_copies_supported = 1; + page_ranges_supported = false; + number_up_default = 0; + number_up_supported = null; + orientation_requested_default = 0; + orientation_requested_supported = null; + job_quota_period = 0; + job_k_limit = 0; + job_page_limit = 0; + job_sheets_default = "none,none"; + job_sheets_supported = null; + device_uri = ""; + color_supported = false; + pages_per_minute = 0; + printer_make_and_model = ""; + media_default = ""; + media_supported = null; + finishings_default = 0; + finishings_supported = null; + printer_type = 0; + } + + + /** + * Get the printer's status. + * + * @param c Cups object. + * + * @return Boolean True on success. + * + * @see Cups + */ + public boolean getStatus(Cups c) + { + List attrs; + IPPAttribute a; + String p_uri; + + try + { + attrs = c.cupsGetPrinterStatus(printer_name); + for (int i=0; i < attrs.size(); i++) + { + a = (IPPAttribute)attrs.get(i); + updateAttribute(a); + } + return(true); + } + catch (IOException e) + { + return(false); + } + } + + + + /** + * Get the printer's attributes. + * + * @param c Cups object. + * + * @return Boolean True on success. + * + * @see Cups + */ + public boolean getAttributes(Cups c) + { + List attrs; + IPPAttribute a; + String p_uri; + + try + { + attrs = c.cupsGetPrinterAttributes(printer_name); + for (int i=0; i < attrs.size(); i++) + { + a = (IPPAttribute)attrs.get(i); + updateAttribute(a); + } + return(true); + } + catch (IOException e) + { + return(false); + } + } + + + + + /** + * Process an attribute from the cups.doRequest() method and move + * the values into local members. + * + * @param a IPPAttribute. + * + * @see IPPAttributes + * @see IPPValues + */ + public void updateAttribute( IPPAttribute a ) + { + IPPValue v; + int i; + + // a.dump_values(); + + if (a.name.compareTo("printer-name") == 0) + { + v = (IPPValue)a.values.get(0); + printer_name = v.text; + } + else if (a.name.compareTo("printer-location") == 0) + { + v = (IPPValue)a.values.get(0); + printer_location = v.text; + } + else if (a.name.compareTo("printer-info") == 0) + { + v = (IPPValue)a.values.get(0); + printer_info = v.text; + } + else if (a.name.compareTo("printer-more-info") == 0) + { + v = (IPPValue)a.values.get(0); + printer_more_info = v.text; + } + else if (a.name.compareTo("printer-uri-supported") == 0) + { + printer_uri_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + printer_uri_supported[i] = v.text; + } + } + else if (a.name.compareTo("uri-authentication-supported") == 0) + { + uri_authentication_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + uri_authentication_supported[i] = v.text; + } + } + else if (a.name.compareTo("uri-security-supported") == 0) + { + uri_security_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + uri_security_supported[i] = v.text; + } + } + else if (a.name.compareTo("attributes-charset") == 0) + { + v = (IPPValue)a.values.get(0); + attributes_charset = v.text; + } + else if (a.name.compareTo("attributes-natural-language") == 0) + { + v = (IPPValue)a.values.get(0); + attributes_natural_language = v.text; + } + else if (a.name.compareTo("printer-state") == 0) + { + v = (IPPValue)a.values.get(0); + printer_state = v.integer_value; + switch( printer_state ) + { + case 3: printer_state_text = "idle"; + break; + case 4: printer_state_text = "processing"; + break; + case 5: printer_state_text = "stopped"; + break; + } + } + else if (a.name.compareTo("printer-state-reasons") == 0) + { + v = (IPPValue)a.values.get(0); + printer_state_reasons = v.text; + } + else if (a.name.compareTo("printer-is-accepting-jobs") == 0) + { + v = (IPPValue)a.values.get(0); + printer_is_accepting_jobs = v.boolean_value; + } + else if (a.name.compareTo("printer-up-time") == 0) + { + v = (IPPValue)a.values.get(0); + printer_up_time = v.integer_value; + } + else if (a.name.compareTo("printer-current-time") == 0) + { + v = (IPPValue)a.values.get(0); + printer_current_time = v.unix_time; // *** FIX *** + } + else if (a.name.compareTo("queue-job-count") == 0) + { + v = (IPPValue)a.values.get(0); + queued_job_count = v.integer_value; + } + else if (a.name.compareTo("pdl-override-supported") == 0) + { + pdl_override_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + pdl_override_supported[i] = v.text; + } + } + else if (a.name.compareTo("ipp-versions-supported") == 0) + { + ipp_versions_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + ipp_versions_supported[i] = v.text; + } + } + else if (a.name.compareTo("operations-supported") == 0) + { + operations_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + operations_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("multiple-document-jobs-supported") == 0) + { + v = (IPPValue)a.values.get(0); + multiple_document_jobs_supported = v.boolean_value; + } + else if (a.name.compareTo("multiple-operation-time-out") == 0) + { + v = (IPPValue)a.values.get(0); + multiple_operation_time_out = v.integer_value; + } + else if (a.name.compareTo("multiple-document-handling-supported") == 0) + { + multiple_document_handling_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + multiple_document_handling_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("charset-configured") == 0) + { + v = (IPPValue)a.values.get(0); + charset_configured = v.text; + } + else if (a.name.compareTo("natural-language-configured") == 0) + { + v = (IPPValue)a.values.get(0); + natural_language_configured = v.text; + } + else if (a.name.compareTo("generated-natural-language-supported") == 0) + { + // *** Should this be a list too? + v = (IPPValue)a.values.get(0); + generated_natural_language_supported = v.text; + } + else if (a.name.compareTo("charset-supported") == 0) + { + charset_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + charset_supported[i] = v.text; + } + } + else if (a.name.compareTo("document-format-default") == 0) + { + v = (IPPValue)a.values.get(0); + document_format_default = v.text; + } + else if (a.name.compareTo("document-format-supported") == 0) + { + document_format_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + document_format_supported[i] = v.text; + } + } + else if (a.name.compareTo("compression-supported") == 0) + { + compression_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + compression_supported[i] = v.text; + } + } + else if (a.name.compareTo("job-priority-default") == 0) + { + v = (IPPValue)a.values.get(0); + job_priority_default = v.integer_value; + } + else if (a.name.compareTo("job-priority-supported") == 0) + { + // *** Should be a list? *** + v = (IPPValue)a.values.get(0); + job_priority_supported = v.integer_value; + } + else if (a.name.compareTo("copies-default") == 0) + { + v = (IPPValue)a.values.get(0); + copies_default = v.integer_value; + } + else if (a.name.compareTo("copies-supported") == 0) + { + v = (IPPValue)a.values.get(0); + lower_copies_supported = v.lower; + upper_copies_supported = v.upper; + } + else if (a.name.compareTo("page-ranges-supported") == 0) + { + v = (IPPValue)a.values.get(0); + page_ranges_supported = v.boolean_value; + } + else if (a.name.compareTo("number-up-default") == 0) + { + v = (IPPValue)a.values.get(0); + number_up_default = v.integer_value; + } + else if (a.name.compareTo("number-up-supported") == 0) + { + number_up_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + number_up_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("orientation-requested-default") == 0) + { + v = (IPPValue)a.values.get(0); + orientation_requested_default = v.integer_value; + } + else if (a.name.compareTo("orientation-requested-supported") == 0) + { + orientation_requested_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + orientation_requested_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("job-quota-period") == 0) + { + v = (IPPValue)a.values.get(0); + job_quota_period = v.integer_value; + } + else if (a.name.compareTo("job-k-limit") == 0) + { + v = (IPPValue)a.values.get(0); + job_k_limit = v.integer_value; + } + else if (a.name.compareTo("job-page-limit") == 0) + { + v = (IPPValue)a.values.get(0); + job_page_limit = v.integer_value; + } + else if (a.name.compareTo("job-sheets-default") == 0) + { + v = (IPPValue)a.values.get(0); + job_sheets_default = v.text; + } + else if (a.name.compareTo("job-sheets-supported") == 0) + { + job_sheets_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + job_sheets_supported[i] = v.text; + } + } + else if (a.name.compareTo("device-uri") == 0) + { + v = (IPPValue)a.values.get(0); + device_uri = v.text; + } + else if (a.name.compareTo("color-supported") == 0) + { + v = (IPPValue)a.values.get(0); + color_supported = v.boolean_value; + } + else if (a.name.compareTo("pages-per-minute") == 0) + { + v = (IPPValue)a.values.get(0); + pages_per_minute = v.integer_value; + } + else if (a.name.compareTo("printer-make-and-model") == 0) + { + v = (IPPValue)a.values.get(0); + printer_make_and_model = v.text; + } + else if (a.name.compareTo("media-default") == 0) + { + v = (IPPValue)a.values.get(0); + media_default = v.text; + } + else if (a.name.compareTo("media-supported") == 0) + { + media_supported = new String[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + media_supported[i] = v.text; + } + } + else if (a.name.compareTo("finishings-default") == 0) + { + v = (IPPValue)a.values.get(0); + finishings_default = v.integer_value; + } + else if (a.name.compareTo("finishings-supported") == 0) + { + finishings_supported = new int[a.values.size()]; + for (i=0; i < a.values.size(); i++) + { + v = (IPPValue)a.values.get(i); + finishings_supported[i] = v.integer_value; + } + } + else if (a.name.compareTo("printer-type") == 0) + { + v = (IPPValue)a.values.get(0); + printer_type = v.integer_value; + } + + } // End of updateAttribute() + + + /** + * Get the printer name. + * + * @return String Printer Name. + */ + public String getPrinterName() + { + return(printer_name); + } + + /** + * Get the printer state text. + * + * @return String State text. + */ + public String getStateText() + { + return(printer_state_text); + } + + /** + * Get the printer state reasons. + * + * @return String State reason. + */ + public String getStateReasons() + { + return(printer_state_reasons); + } + + /** + * Get the printer location. + * + * @return String State location. + */ + public String getLocation() + { + return(printer_location); + } + + /** + * Get the printer make and model. + * + * @return String Make and model. + */ + public String getMakeAndModel() + { + return(printer_make_and_model); + } + + + + /** + * Get the default job sheets. + * + * @return String Default job sheets. + */ + public String getJobSheetsDefault() + { + return(job_sheets_default); + } + + /** + * Get the printer job sheets supported. + * + * @return String[] Array of supported job sheets. + */ + public String[] getJobSheetsSupported() + { + return(job_sheets_supported); + } + + + /** + * Get the default orientation. + * + * @return int Default page orientation. + */ + public int getOrientationDefault() + { + return(orientation_requested_default); + } + + /** + * Get the printer orientation supported. + * + * @return int[] Array of supported orientations. + */ + public int[] getOrientationSupported() + { + return(orientation_requested_supported); + } + + + /** + * Get the printer lower copies supported. + * + * @return int Lower of the range. + */ + public int getLowerCopiesSupported() + { + return(lower_copies_supported); + } + + + /** + * Get the printer upper copies supported. + * + * @return int Upper of the range. + */ + public int getUpperCopiesSupported() + { + return(upper_copies_supported); + } + + + /** + * Get the printer number of copies default. + * + * @return int Default number of copies. + */ + public int getCopiesDefault() + { + return(copies_default); + } + + + /** + * Get whether the printer supports page ranges. + * + * @return boolean True or false. + */ + public boolean getPageRangesSupported() + { + return(page_ranges_supported); + } + + + + /** + * Debug method. + */ + void dump() + { + int i; + + System.out.println("Printer Name: " + printer_name ); + System.out.println("Location: " + printer_location ); + System.out.println("Printer Info: " + printer_info ); + System.out.println("More Info: " + printer_more_info ); + + if (printer_uri_supported != null) + { + System.out.println("Printer URI's Supported: "); + for (i=0; i < printer_uri_supported.length; i++) + { + System.out.println(" " + printer_uri_supported[i] ); + } + } + + if (uri_authentication_supported != null) + { + System.out.println("URI Authentication Supported: "); + for (i=0; i < uri_authentication_supported.length; i++) + { + System.out.println(" " + uri_authentication_supported[i] ); + } + } + + if (uri_security_supported != null) + { + System.out.println("URI Security Supported: "); + for (i=0; i < uri_security_supported.length; i++) + { + System.out.println(" " + uri_security_supported[i] ); + } + } + + System.out.println("Attributes Charset: " + attributes_charset ); + System.out.println("Attributes Natural Language: " + attributes_natural_language ); + + System.out.println("Printer State: " + printer_state ); + System.out.println("Printer State Text: " + printer_state_text ); + System.out.println("Printer State Reasons: " + printer_state_reasons ); + + if (printer_is_accepting_jobs) + System.out.println("Accepting Jobs: Yes"); + else + System.out.println("Accepting Jobs: No"); + + +} + + + +} // End of CupsPrinter class + + diff --git a/scripting/java/src/com/easysw/cups/IPP.java b/scripting/java/src/com/easysw/cups/IPP.java new file mode 100644 index 000000000..919398179 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPP.java @@ -0,0 +1,251 @@ +package com.easysw.cups; + +/** + * @version 0.00 06-NOV-2001 + * @author Easy Software Products + * + * 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 + */ + +import java.util.*; + +/** + * An IPP object is used to hold the various + * attributes and status of an ipp request.. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ +public class IPP +{ + public IPPRequest request; // The request header + public IPPStatus status; // Status of request + public List attrs; // Attributes list. + + short state; // Current IPP state (of request???) + int current; // Index into attributes array. + int last; // Index into attributes array. + short current_tag; + + + // ------------------------------------------------------------------ + // + // Constructor + // + public IPP() + { + state = IPPDefs.IDLE; + attrs = new LinkedList(); + current = -1; + last = -1; + current_tag = IPPDefs.TAG_ZERO; + } + + + + /** + * Add an attribute to the attibutes list + * for later parsing. + * + * @param a IPPAttribute to add. + * @return true always returns true + * for now. + * + * @see IPPAttribute + * @see IPPValue + */ + public boolean addAttribute( IPPAttribute a ) + { + attrs.add(a); + return(true); + } + + /** + * Get the current attribute pointed at by + * current. + * + * @return IPPAttribute Return the current attribute. + * @return null Return null + * if current is 0. + */ + public IPPAttribute getCurrentAttribute() + { + if (current >= 0) + return( (IPPAttribute)attrs.get(current) ); + else + return( null ); + } + + // public void setCurrentAttribute( IPPAttribute p_attr ) + // { + // if (current >= 0) + // return( (IPPAttribute)attrs.get(current) ); + // } + + + /** + * + * Find the named attribute of the correct type. Both must match. + * This methos searches from the beginning of the attribute list, + * rather than from the current position. + * + * @param p_name String containing the name. + * @param p_type int attribute type. + * + * @return IPPAttribute Matching attribute if found. + * @return null null if not found. + */ + public IPPAttribute ippFindAttribute( String p_name, int p_type ) + { + if (p_name.length() < 1) + return(null); + current = -1; + return(ippFindNextAttribute(p_name, p_type)); + } + + + + + /** + * + * Find the named attribute of the correct type. Both must match. + * This methos searches from the current position in the attribute list. + * + * @param p_name String containing the name. + * @param p_type int attribute type. + * + * @return IPPAttribute Matching attribute if found. + * @return null null if not found. + */ + public IPPAttribute ippFindNextAttribute( String p_name, int p_type ) + { + int value_tag; + + if (p_name.length() < 1) + return(null); + + if ((current >= 0) && (current < (attrs.size() - 1))) + current++; + else + current = 0; + + for (int i = current; i < attrs.size(); i++) + { + IPPAttribute tmp = (IPPAttribute)attrs.get(i); + value_tag = (tmp.value_tag & IPPDefs.TAG_MASK); + if ((tmp.name.length() > 0) && (tmp.name == p_name) && + (value_tag == p_type || p_type == IPPDefs.TAG_ZERO || + (value_tag == IPPDefs.TAG_TEXTLANG && p_type == IPPDefs.TAG_TEXT) || + (value_tag == IPPDefs.TAG_NAMELANG && p_type == IPPDefs.TAG_NAME))) + { + current = i; + return(tmp); + } + } + return(null); + } + + + /** + * Get the size in bytes of an IPP request. + * + * @return int Number of bytes for the request. + */ + public int sizeInBytes() + { + IPPAttribute a; + int bytes = 8; + int last_group = IPPDefs.TAG_ZERO; + + for (int i=0; i < attrs.size(); i++) + { + a = (IPPAttribute)attrs.get(i); + bytes += a.sizeInBytes(last_group); + last_group = a.group_tag; + } + bytes++; // one for the end tag. + + return(bytes); + + } // End of IPP.sizeInBytes() + + + + + + int ippBytes() + { + int i = 0; + return(0); + } + + + + /** + * Set the IPP request ID. + * + * @param p_id short request id. + */ + public void setRequestID( short p_id ) + { + request.request_id = p_id; + } + + /** + * Set the IPP operation ID. + * + * @param p_operation_id short operation id. + */ + public void setRequestOperationID( short p_operation_id ) + { + request.operation_id = p_operation_id; + } + + + // + // Dump a list - for debugging. + // + public void dump_response() + { + IPPAttribute a; + int last_group = IPPDefs.TAG_ZERO; + + for (int i=0; i < attrs.size(); i++) + { + a = (IPPAttribute)attrs.get(i); + a.dump_values(); + last_group = a.group_tag; + } + return; + + } // End of IPP.dump_response() + + +} // End of IPP class + + + + +// +// End of IPP.java +// diff --git a/scripting/java/src/com/easysw/cups/IPPAttribute.java b/scripting/java/src/com/easysw/cups/IPPAttribute.java new file mode 100644 index 000000000..269a43885 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPAttribute.java @@ -0,0 +1,593 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ +/** + * An IPPAttribute object hold attributes for communicating + * messages to / from the CUPS server. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ +import java.util.*; + +public class IPPAttribute +{ + int group_tag; + int value_tag; + String name; + List values; + + + + public IPPAttribute( int p_group_tag, int p_value_tag, + String p_name ) + { + group_tag = p_group_tag; + value_tag = p_value_tag; + name = p_name; + values = new ArrayList(); + + } // End of IPPAttribute constructor. + + + // + // Add a boolean value to the objects values list. + // + public boolean addBoolean( boolean p_bool ) + { + IPPValue val = new IPPValue( p_bool ); + values.add(val); + return(true); + } + + + // + // Add a set of boolean values to the objects values list. + // + public boolean addBooleans( boolean p_bools[] ) + { + if (p_bools.length < 1) + return(false); + + for (int i=0; i < p_bools.length; i++ ) + { + IPPValue val = new IPPValue( p_bools[i] ); + values.add(val); + } + return(true); + } + + + // + // Add an enum value to the objects values list. + // + public boolean addEnum( int p_int ) + { + IPPValue val = new IPPValue( p_int, true ); + values.add(val); + return(true); + } + + + // + // Add an integer value to the objects values list. + // + public boolean addInteger( int p_int ) + { + IPPValue val = new IPPValue( p_int ); + values.add(val); + return(true); + } + + + // + // Add a set of integer values to the objects values list. + // + public boolean addIntegers( int p_ints[] ) + { + if (p_ints.length < 1) + return(false); + + for (int i=0; i < p_ints.length; i++ ) + { + IPPValue val = new IPPValue( p_ints[i] ); + values.add(val); + } + return(true); + } + + + // + // Add a string value to the objects values list. + // + public boolean addString( String p_charset, String p_text ) + { + String l_value; + String final_value; + + // + // Force the value to English for POSIX locale. + // + if ((value_tag == IPPDefs.TAG_LANGUAGE) && (p_text == "C")) + { + l_value = "en"; + } + else + { + l_value = p_text; + } + + + // + // Convert language values to lowercase and _ to - as needed. + // + if ((value_tag == IPPDefs.TAG_LANGUAGE) || + (value_tag == IPPDefs.TAG_CHARSET)) + { + StringBuffer temp = new StringBuffer(l_value.length()); + char c; + for (int i = 0; i < l_value.length(); i++) + { + c = l_value.charAt(i); + if (c == '_') + c = '-'; + else if (Character.isUpperCase(c)) + c = Character.toLowerCase(c); + temp.append(c); + } + final_value = temp.toString(); + } + else + { + final_value = l_value; + } + IPPValue val = new IPPValue( p_charset, final_value ); + values.add(val); + return(true); + } + + + // + // Add a set of strings to the objects values list. + // + public boolean addStrings( String p_charset, String p_texts[] ) + { + if (p_texts.length < 1) + return(false); + + // + // Just call the singular string method to save on coding. + // + for (int i=0; i < p_texts.length; i++ ) + { + addString( p_charset, p_texts[i] ); + } + return(true); + } + + // + // Add an ipp date value to the objects values list. + // + public boolean addDate( char p_date[] ) + { + IPPValue val = new IPPValue( p_date ); + values.add(val); + return(true); + } + + // + // Add a range value to the objects values list. + // + public boolean addRange( int p_lower, int p_upper ) + { + IPPValue val = new IPPValue( p_lower, p_upper ); + values.add(val); + return(true); + } + + + // + // Add a set of range values to the objects values list. + // + public boolean addRanges( int p_lower[], int p_upper[] ) + { + // + // Avoid index out of bounds errors. + // + if (p_lower.length != p_upper.length) + return(false); + + for (int i=0; i < p_lower.length; i++ ) + addRange( p_lower[i], p_upper[i] ); + return(true); + } + + + // + // Add a resolution value to the objects values list. + // + public boolean addResolution( byte p_units, int p_xres, int p_yres ) + { + IPPValue val = new IPPValue( p_units, p_xres, p_yres ); + values.add(val); + return(true); + } + + + // + // Add a set of resolution values to the objects values list. + // + public boolean addResolutions( byte p_units, int p_xres[], int p_yres[] ) + { + if (p_xres.length != p_yres.length) + return(false); + + for (int i=0; i < p_xres.length; i++) + addResolution( p_units, p_xres[i], p_yres[i] ); + return(true); + } + + + // + // Set the attribute as a separator. + // + public boolean addSeparator() + { + value_tag = IPPDefs.TAG_ZERO; + group_tag = IPPDefs.TAG_ZERO; + return(true); + } + + + + // + // Calculate the size in bytes for an IPP requests attributes. + // + public int sizeInBytes(int last_group) + { + IPPValue val; + int bytes = 0; // Start with one for the group tag. + + // + // Add 1 if first time, or group tag changes. + // + if (last_group != group_tag) + bytes ++; + + bytes ++; // Add 1 for the value tag. + bytes += 2; // Add 2 for the name length field. + bytes += name.length(); // Add the length of the name. + + for (int i=0; i < values.size(); i++ ) + { + val = (IPPValue)values.get(i); + + if (i > 0) + { + // If an array of values, add 1 for another value tag, plus + // 2 for zero length name. + // + bytes += 3; + } + + switch (value_tag) + { + case IPPDefs.TAG_INTEGER : + case IPPDefs.TAG_ENUM : + bytes += 2; + bytes += 4; + break; + + case IPPDefs.TAG_BOOLEAN : + bytes += 2; + bytes ++; + break; + + case IPPDefs.TAG_TEXT: + case IPPDefs.TAG_NAME: + case IPPDefs.TAG_KEYWORD: + case IPPDefs.TAG_STRING: + case IPPDefs.TAG_URI: + case IPPDefs.TAG_URISCHEME: + case IPPDefs.TAG_CHARSET: + case IPPDefs.TAG_LANGUAGE: + case IPPDefs.TAG_MIMETYPE: + bytes += 2; + bytes += val.text.length(); + break; + + case IPPDefs.TAG_DATE : + bytes += 2; + bytes += 11; + break; + + case IPPDefs.TAG_RESOLUTION : + bytes += 2; + bytes += 9; + break; + + case IPPDefs.TAG_RANGE : + bytes += 2; + bytes += 8; + break; + + case IPPDefs.TAG_TEXTLANG : + case IPPDefs.TAG_NAMELANG : + bytes += 6; // 2 overall len, 2 charset len, 2 text len + bytes += val.charset.length() + + val.text.length(); + break; + + default : + bytes += 2; + if (val.data != null) + bytes += val.data.length; + break; + } + } + + // bytes++; // 1 byte for end of values tag. + + return(bytes); + + } // End of IPPAttribute.sizeInBytes() + + + // + // Get the characters of an attribute + // + public byte[] getBytes( int sz, int last_group ) + { + IPPValue val; + + int i,j, n; + int bi = 0; // Start with one for the group tag. + byte[] bytes = new byte[sz]; + + if (group_tag != last_group) + { + bytes[bi++] = (byte)group_tag; + last_group = group_tag; + } + bytes[bi++] = (byte)value_tag; + + bytes[bi++] = (byte)((name.length() & 0xff00) >> 8); + bytes[bi++] = (byte)(name.length() & 0xff); + for (j=0; j < name.length(); j++) + bytes[bi++] = (byte)name.charAt(j); + + for (i=0; i < values.size(); i++ ) + { + if (i > 0) + { + bytes[bi++] = (byte)value_tag; + bytes[bi++] = (byte)0; + bytes[bi++] = (byte)0; + } + + val = (IPPValue)values.get(i); + switch (value_tag) + { + case IPPDefs.TAG_INTEGER : + case IPPDefs.TAG_ENUM : + bytes[bi++] = (byte)0; + bytes[bi++] = (byte)4; + bytes[bi++] = (byte)((val.integer_value & 0xff000000) >> 24); + bytes[bi++] = (byte)((val.integer_value & 0xff0000) >> 16); + bytes[bi++] = (byte)((val.integer_value & 0xff00) >> 8); + bytes[bi++] = (byte)(val.integer_value & 0xff); + break; + + case IPPDefs.TAG_BOOLEAN : + bytes[bi++] = (byte)0; + bytes[bi++] = (byte)1; + if (val.boolean_value) + bytes[bi++] = (byte)1; + else + bytes[bi++] = (byte)0; + break; + + case IPPDefs.TAG_TEXT : + case IPPDefs.TAG_NAME : + case IPPDefs.TAG_KEYWORD : + case IPPDefs.TAG_STRING : + case IPPDefs.TAG_URI : + case IPPDefs.TAG_URISCHEME : + case IPPDefs.TAG_CHARSET : + case IPPDefs.TAG_LANGUAGE : + case IPPDefs.TAG_MIMETYPE : + bytes[bi++] = (byte)((val.text.length() & 0xff00) >> 8); + bytes[bi++] = (byte)(val.text.length() & 0xff); + for (j=0; j < val.text.length(); j++) + { + bytes[bi++] = (byte)val.text.charAt(j); + } + break; + + case IPPDefs.TAG_DATE: + bytes[bi++] = (byte)0; + bytes[bi++] = (byte)11; + for (j=0; j < 11; j++) + bytes[bi++] = (byte)val.date_value[j]; + break; + + case IPPDefs.TAG_RESOLUTION : + bytes[bi++] = (byte)0; + bytes[bi++] = (byte)9; + bytes[bi++] = (byte)((val.xres & 0xff000000) >> 24); + bytes[bi++] = (byte)((val.xres & 0xff0000) >> 16); + bytes[bi++] = (byte)((val.xres & 0xff00) >> 8); + bytes[bi++] = (byte)(val.xres & 0xff); + bytes[bi++] = (byte)((val.yres & 0xff000000) >> 24); + bytes[bi++] = (byte)((val.yres & 0xff0000) >> 16); + bytes[bi++] = (byte)((val.yres & 0xff00) >> 8); + bytes[bi++] = (byte)(val.yres & 0xff); + bytes[bi++] = (byte)val.units; + break; + + case IPPDefs.TAG_RANGE : + bytes[bi++] = (byte)0; + bytes[bi++] = (byte)8; + bytes[bi++] = (byte)((val.lower & 0xff000000) >> 24); + bytes[bi++] = (byte)((val.lower & 0xff0000) >> 16); + bytes[bi++] = (byte)((val.lower & 0xff00) >> 8); + bytes[bi++] = (byte)(val.lower & 0xff); + bytes[bi++] = (byte)((val.upper & 0xff000000) >> 24); + bytes[bi++] = (byte)((val.upper & 0xff0000) >> 16); + bytes[bi++] = (byte)((val.upper & 0xff00) >> 8); + bytes[bi++] = (byte)(val.upper & 0xff); + break; + + case IPPDefs.TAG_TEXTLANG : + case IPPDefs.TAG_NAMELANG : + n = val.charset.length() + + val.text.length() + 4; + bytes[bi++] = (byte)((n & 0xff00) >> 8); + bytes[bi++] = (byte)(n & 0xff); + + n = val.charset.length(); + bytes[bi++] = (byte)((n & 0xff00) >> 8); + bytes[bi++] = (byte)(n & 0xff); + for (j=0; j < val.charset.length(); j++) + bytes[bi++] = (byte)val.charset.charAt(j); + + n = val.text.length(); + bytes[bi++] = (byte)((n & 0xff00) >> 8); + bytes[bi++] = (byte)(n & 0xff); + for (j=0; j < (byte)val.text.length(); j++) + bytes[bi++] = (byte)val.text.charAt(j); + + break; + + default : + if (val.data != null) + { + n = val.data.length; + bytes[bi++] = (byte)((n & 0xff00) >> 8); + bytes[bi++] = (byte)(n & 0xff); + for (j=0; j < val.data.length; j++) + bytes[bi++] = (byte)val.data[j]; + } + break; + } + } + + return(bytes); + + } // End of IPPAttribute.getBytes() + + + + + // + // + // + public void dump_values() + { + IPPValue val; + + if ((values == null) || (values.size() < 1)) + { + System.out.println( " ---- Separator ---- \n"); + return; + } + + for (int i=0; i < values.size(); i++ ) + { + val = (IPPValue)values.get(i); + + System.out.println("ATTR GTAG: " + group_tag ); + System.out.println("ATTR VTAG: " + value_tag ); + System.out.println("ATTR NAME: " + name ); + + // switch (value_tag & ~IPPDefs.TAG_COPY) + switch (value_tag) + { + case IPPDefs.TAG_INTEGER : + case IPPDefs.TAG_ENUM : + System.out.println( " INTEGER: " + val.integer_value ); + break; + + case IPPDefs.TAG_BOOLEAN : + System.out.println( " BOOLEAN: " + val.boolean_value ); + break; + + case IPPDefs.TAG_TEXT : + case IPPDefs.TAG_NAME : + case IPPDefs.TAG_KEYWORD : + case IPPDefs.TAG_STRING : + case IPPDefs.TAG_URI : + case IPPDefs.TAG_URISCHEME : + case IPPDefs.TAG_CHARSET : + case IPPDefs.TAG_LANGUAGE : + case IPPDefs.TAG_MIMETYPE : + System.out.println( " CHARSET: " + val.charset + + " TEXT: " + val.text ); + break; + + case IPPDefs.TAG_DATE : + System.out.println( " DATE: " + val.unix_time ); + break; + + case IPPDefs.TAG_RESOLUTION : + System.out.println( " UNITS: " + val.units + + " XRES: " + val.xres + + " YRES: " + val.yres ); + break; + + case IPPDefs.TAG_RANGE : + System.out.println( " LOWER: " + val.lower + + " UPPER: " + val.upper ); + break; + + case IPPDefs.TAG_TEXTLANG : + case IPPDefs.TAG_NAMELANG : + System.out.println( " CHARSET: " + val.charset + + " TEXT: " + val.text ); + break; + + case IPPDefs.TAG_ZERO: + System.out.println( " ---- Separator ---- \n"); + break; + + default : + break; + } + } + return; + + } + + + + +} // End of IPPAttribute class + + + + diff --git a/scripting/java/src/com/easysw/cups/IPPBase64Encoder.java b/scripting/java/src/com/easysw/cups/IPPBase64Encoder.java new file mode 100644 index 000000000..7e63b83a4 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPBase64Encoder.java @@ -0,0 +1,46 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * The IPPBase64Encoder overrides part of the sun encoder. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ + + +class IPPBase64Encoder extends sun.misc.BASE64Encoder +{ + protected void encodeLineSuffix(java.io.OutputStream out) + throws java.io.IOException + { + // do nothing. + } +} + diff --git a/scripting/java/src/com/easysw/cups/IPPCalendar.java b/scripting/java/src/com/easysw/cups/IPPCalendar.java new file mode 100644 index 000000000..d34fe1deb --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPCalendar.java @@ -0,0 +1,62 @@ +package com.easysw.cups; +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * An IPPCalendar object is used for date/time conversion. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ + +import java.util.*; + +class IPPCalendar extends GregorianCalendar +{ + /** + * Get the time in milliseconds from the GregorianCalendar + * class. + * + * @return long Time in milliseconds of a date. + */ + public long getTimeInMillis() + { + return(super.getTimeInMillis()); + } + + /** + * Get the unix time in seconds from the GregorianCalendar + * class. + * + * @return int Unix Time in seconds of a date. + */ + public int getUnixTime() + { + return( (int)(getTimeInMillis() / 1000) ); + } + +} // end of class diff --git a/scripting/java/src/com/easysw/cups/IPPDefs.java b/scripting/java/src/com/easysw/cups/IPPDefs.java new file mode 100644 index 000000000..f7e7706fc --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPDefs.java @@ -0,0 +1,310 @@ + +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +import java.io.*; +import java.util.*; + +/** + * IPPDefs is a collection of constants for use + * in the IPP and CUPS classes. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ +public class IPPDefs +{ + + /* + * IPP version string... + */ + public static final byte VERSION[] = { 1, 0 }; + + + /* + * 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! + */ + public static final int PORT = 631; + + + /* + * Common limits... + */ + public static final int MAX_NAME = 256; + public static final int MAX_VALUES = 10; /* Now just an allocation + increment */ + + + /* + * Format tags for attribute formats... + */ + public static final int TAG_ZERO = 0x00; + public static final int TAG_OPERATION = 0x01; + public static final int TAG_JOB = 0x02; + public static final int TAG_END = 0x03; + public static final int TAG_PRINTER = 0x04; + public static final int TAG_UNSUPPORTED_GROUP = 0x05; + public static final int TAG_SUBSCRIPTION = 0x06; + public static final int TAG_EVENT_NOTIFICATION = 0x07; + public static final int TAG_UNSUPPORTED_VALUE = 0x10; + public static final int TAG_DEFAULT = 0x11; + public static final int TAG_UNKNOWN = 0x12; + public static final int TAG_NOVALUE = 0x13; + public static final int TAG_NOTSETTABLE = 0x15; + public static final int TAG_DELETEATTR = 0x16; + public static final int TAG_ADMINDEFINE = 0x17; + public static final int TAG_INTEGER = 0x21; + public static final int TAG_BOOLEAN = 0x22; + public static final int TAG_ENUM = 0x23; + public static final int TAG_STRING = 0x30; + public static final int TAG_DATE = 0x31; + public static final int TAG_RESOLUTION = 0x32; + public static final int TAG_RANGE = 0x33; + public static final int TAG_BEGIN_COLLECTION = 0x34; + public static final int TAG_TEXTLANG = 0x35; + public static final int TAG_NAMELANG = 0x36; + public static final int TAG_END_COLLECTION = 0x37; + public static final int TAG_TEXT = 0x41; + public static final int TAG_NAME = 0x42; + public static final int TAG_KEYWORD = 0x44; + public static final int TAG_URI = 0x45; + public static final int TAG_URISCHEME = 0x46; + public static final int TAG_CHARSET = 0x47; + public static final int TAG_LANGUAGE = 0x48; + public static final int TAG_MIMETYPE = 0x49; + public static final int TAG_MEMBERNAME = 0x4A; + public static final int TAG_MASK = 0x7FFFFFFF; + public static final int TAG_COPY = 0x80000001; + + + /* + * Resolution units... + */ + public static final int RES_PER_INCH = 0x03; + public static final int RES_PER_CM = 0x04; + + + /* + * Finishings... + */ + public static final int FINISHINGS_NONE = 0x03; + public static final int FINISHINGS_STAPLE = 0x04; + public static final int FINISHINGS_PUNCH = 0x05; + public static final int FINISHINGS_COVER = 0x06; + public static final int FINISHINGS_BIND = 0x07; + public static final int FINISHINGS_SADDLE_STITCH = 0x08; + public static final int FINISHINGS_EDGE_STITCH = 0x09; + public static final int FINISHINGS_FOLD = 0x0A; + public static final int FINISHINGS_TRIM = 0x0B; + public static final int FINISHINGS_BALE = 0x0C; + public static final int FINISHINGS_BOOKLET_MAKER = 0x0D; + public static final int FINISHINGS_JOB_OFFSET = 0x0E; + public static final int FINISHINGS_STAPLE_TOP_LEFT = 0x14; + public static final int FINISHINGS_STAPLE_BOTTOM_LEFT = 0x15; + public static final int FINISHINGS_STAPLE_TOP_RIGHT = 0x16; + public static final int FINISHINGS_STAPLE_BOTTOM_RIGHT = 0x17; + public static final int FINISHINGS_EDGE_STITCH_LEFT = 0x18; + public static final int FINISHINGS_EDGE_STITCH_TOP = 0x19; + public static final int FINISHINGS_EDGE_STITCH_RIGHT = 0x1A; + public static final int FINISHINGS_EDGE_STITCH_BOTTOM = 0x1B; + public static final int FINISHINGS_STAPLE_DUAL_LEFT = 0x1C; + public static final int FINISHINGS_STAPLE_DUAL_TOP = 0x1D; + public static final int FINISHINGS_STAPLE_DUAL_RIGHT = 0x1E; + public static final int FINISHINGS_STAPLE_DUAL_BOTTOM = 0x1F; + public static final int FINISHINGS_BIND_LEFT = 0x32; + public static final int FINISHINGS_BIND_TOP = 0x33; + public static final int FINISHINGS_BIND_RIGHT = 0x34; + public static final int FINISHINGS_BIND_BOTTOM = 0x35; + + + /* + * Orientation... + */ + public static final int PORTRAIT = 0x03; + public static final int LANDSCAPE = 0x04; + public static final int REVERSE_LANDSCAPE = 0x05; + public static final int REVERSE_PORTRAIT = 0x06; + + + /* + * Qualities... + */ + public static final int QUALITY_DRAFT = 0x03; + public static final int QUALITY_NORMAL = 0x04; + public static final int QUALITY_HIGH = 0x05; + + + /* + * Job States.... + */ + public static final int JOB_PENDING = 0x03; + public static final int JOB_HELD = 0x04; + public static final int JOB_PROCESSING = 0x05; + public static final int JOB_STOPPED = 0x06; + public static final int JOB_CANCELLED = 0x07; + public static final int JOB_ABORTED = 0x08; + public static final int JOB_COMPLETED = 0x09; + + + /* + * Printer States.... + */ + public static final int PRINTER_IDLE = 0x03; + public static final int PRINTER_PROCESSING = 0x04; + public static final int PRINTER_STOPPED = 0x05; + + + /* + * IPP states... + */ + public static final int ERROR = 0xFFFFFFFF; + public static final int IDLE = 0x00; + public static final int HEADER = 0x01; + public static final int ATTRIBUTE = 0x02; + public static final int DATA = 0x03; + + + /* + * IPP operations... + */ + public static final int PRINT_JOB = 0x02; + public static final int PRINT_URI = 0x03; + public static final int VALIDATE_JOB = 0x04; + public static final int CREATE_JOB = 0x05; + public static final int SEND_DOCUMENT = 0x06; + public static final int SEND_URI = 0x07; + public static final int CANCEL_JOB = 0x08; + public static final int GET_JOB_ATTRIBUTES = 0x09; + public static final int GET_JOBS = 0x0A; + public static final int GET_PRINTER_ATTRIBUTES = 0x0B; + public static final int HOLD_JOB = 0x0C; + public static final int RELEASE_JOB = 0x0D; + public static final int RESTART_JOB = 0x0E; + public static final int PAUSE_PRINTER = 0x10; + public static final int RESUME_PRINTER = 0x11; + public static final int PURGE_JOBS = 0x12; + public static final int SET_PRINTER_ATTRIBUTES = 0x13; + public static final int SET_JOB_ATTRIBUTES = 0x14; + public static final int GET_PRINTER_SUPPORTED_VALUES = 0x15; + public static final int CREATE_PRINTER_SUBSCRIPTION = 0x16; + public static final int CREATE_JOB_SUBSCRIPTION = 0x17; + public static final int GET_SUBSCRIPTION_ATTRIBUTES = 0x18; + public static final int GET_SUBSCRIPTIONS = 0x19; + public static final int RENEW_SUBSCRIPTION = 0x1A; + public static final int CANCEL_SUBSCRIPTION = 0x1B; + public static final int GET_NOTIFICATIONS = 0x1C; + public static final int SEND_NOTIFICATIONS = 0x1D; + public static final int GET_PRINT_SUPPORT_FILES = 0x21; + public static final int ENABLE_PRINTER = 0x22; + public static final int DISABLE_PRINTER = 0x23; + public static final int PAUSE_PRINTER_AFTER_CURRENT_JOB = 0x24; + public static final int HOLD_NEW_JOBS = 0x25; + public static final int RELEASE_HELD_NEW_JOBS = 0x26; + public static final int DEACTIVATE_PRINTER = 0x27; + public static final int ACTIVATE_PRINTER = 0x28; + public static final int RESTART_PRINTER = 0x29; + public static final int SHUTDOWN_PRINTER = 0x2A; + public static final int STARTUP_PRINTER = 0x2B; + public static final int REPROCESS_JOB = 0x2C; + public static final int CANCEL_CURRENT_JOB = 0x2D; + public static final int SUSPEND_CURRENT_JOB = 0x2E; + public static final int RESUME_JOB = 0x2F; + public static final int PROMOTE_JOB = 0x30; + public static final int SCHEDULE_JOB_AFTER = 0x31; + public static final int PRIVATE = 0x4000; + public static final int CUPS_GET_DEFAULT = 0x4001; + public static final int CUPS_GET_PRINTERS = 0x4002; + public static final int CUPS_ADD_PRINTER = 0x4003; + public static final int CUPS_DELETE_PRINTER = 0x4004; + public static final int CUPS_GET_CLASSES = 0x4005; + public static final int CUPS_ADD_CLASS = 0x4006; + public static final int CUPS_DELETE_CLASS = 0x4007; + public static final int CUPS_ACCEPT_JOBS = 0x4008; + public static final int CUPS_REJECT_JOBS = 0x4009; + public static final int CUPS_SET_DEFAULT = 0x400A; + public static final int CUPS_GET_DEVICES = 0x400B; + public static final int CUPS_GET_PPDS = 0x400C; + public static final int CUPS_MOVE_JOB = 0x400D; + public static final int CUPS_ADD_DEVICE = 0x400E; + public static final int CUPS_DELETE_DEVICE = 0x400F; + + + + /* + * IPP status codes... + */ + public static final int OK = 0x00; + public static final int OK_SUBST = 0x01; + public static final int OK_CONFLICT = 0x02; + public static final int OK_IGNORED_SUBSCRIPTIONS = 0x03; + public static final int OK_IGNORED_NOTIFICATIONS = 0x04; + public static final int OK_TOO_MANY_EVENTS = 0x05; + public static final int OK_BUT_CANCEL_SUBSCRIPTION = 0x06; + public static final int REDIRECTION_OTHER_SITE = 0x300; + public static final int BAD_REQUEST = 0x400; + public static final int FORBIDDEN = 0x401; + public static final int NOT_AUTHENTICATED = 0x402; + public static final int NOT_AUTHORIZED = 0x403; + public static final int NOT_POSSIBLE = 0x404; + public static final int TIMEOUT = 0x405; + public static final int NOT_FOUND = 0x406; + public static final int GONE = 0x407; + public static final int REQUEST_ENTITY = 0x408; + public static final int REQUEST_VALUE = 0x409; + public static final int DOCUMENT_FORMAT = 0x40A; + public static final int ATTRIBUTES = 0x40B; + public static final int URI_SCHEME = 0x40C; + public static final int CHARSET = 0x40D; + public static final int CONFLICT = 0x40E; + public static final int COMPRESSION_NOT_SUPPORTED = 0x40F; + public static final int COMPRESSION_ERROR = 0x410; + public static final int DOCUMENT_FORMAT_ERROR = 0x411; + public static final int DOCUMENT_ACCESS_ERROR = 0x412; + public static final int ATTRIBUTES_NOT_SETTABLE = 0x413; + public static final int IGNORED_ALL_SUBSCRIPTIONS = 0x414; + public static final int TOO_MANY_SUBSCRIPTIONS = 0x415; + public static final int IGNORED_ALL_NOTIFICATIONS = 0x416; + public static final int PRINT_SUPPORT_FILE_NOT_FOUND = 0x417; + public static final int INTERNAL_ERROR = 0x500; + public static final int OPERATION_NOT_SUPPORTED = 0x501; + public static final int SERVICE_UNAVAILABLE = 0x502; + public static final int VERSION_NOT_SUPPORTED = 0x503; + public static final int DEVICE_ERROR = 0x504; + public static final int TEMPORARY_ERROR = 0x505; + public static final int NOT_ACCEPTING = 0x506; + public static final int PRINTER_BUSY = 0x507; + public static final int ERROR_JOB_CANCELLED = 0x508; + public static final int MULTIPLE_JOBS_NOT_SUPPORTED = 0x509; + public static final int PRINTER_IS_DEACTIVATED = 0x50A; + +} + + diff --git a/scripting/java/src/com/easysw/cups/IPPError.java b/scripting/java/src/com/easysw/cups/IPPError.java new file mode 100644 index 000000000..a0e5eca3d --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPError.java @@ -0,0 +1,159 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * An IPPError object is used for error conversion. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ + +import java.util.*; +import java.io.*; + + +public class IPPError +{ + private int error_number; + private String error_string; + + + /** + * Constructor that sets error_string after creation. + * + * @param error_number Error number to convert. + * @see IPPDefs + */ + public IPPError(int p_error) + { + error_number = p_error; + error_string = ippErrorString( error_number ); + } + + + /** + * Get the string associated with an error number. + * + * @param error Error number to convert. + * @see IPPDefs + */ + private String ippErrorString( int error ) + { + String unknown; + String 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" + }; + + String 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" + }; + + String 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 >= IPPDefs.OK) && (error <= IPPDefs.OK_BUT_CANCEL_SUBSCRIPTION)) + { + return (status_oks[error]); + } + else if (error == IPPDefs.REDIRECTION_OTHER_SITE) + { + return ("redirection-other-site"); + } + else if ((error >= IPPDefs.BAD_REQUEST) && + (error <= IPPDefs.PRINT_SUPPORT_FILE_NOT_FOUND)) + { + return (status_400s[error - IPPDefs.BAD_REQUEST]); + } + else if ((error >= IPPDefs.INTERNAL_ERROR) && + (error <= IPPDefs.PRINTER_IS_DEACTIVATED)) + { + return (status_500s[error - IPPDefs.INTERNAL_ERROR]); + } + + // + // No, build an "unknown-xxxx" error string... + // + + unknown = "unknown" + error; + + return (unknown); + } + + +} // End of IPPError class + + + diff --git a/scripting/java/src/com/easysw/cups/IPPHttp.java b/scripting/java/src/com/easysw/cups/IPPHttp.java new file mode 100644 index 000000000..f53bdff7b --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPHttp.java @@ -0,0 +1,1353 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * An IPPHttp object is used for reading/writing to the cups + * server, and processing responses. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ + +import java.io.*; +import java.util.*; +import java.net.*; +import java.security.*; + +public class IPPHttp +{ + + /** + * Class constants - most not in use yet. + */ + public static final int HTTP_WAITING = 0x00; + public static final int HTTP_OPTIONS = 0x01; + public static final int HTTP_GET = 0x02; + public static final int HTTP_GET_SEND = 0x03; + public static final int HTTP_HEAD = 0x04; + public static final int HTTP_POST = 0x05; + public static final int HTTP_POST_RECV = 0x06; + public static final int HTTP_POST_SEND = 0x07; + public static final int HTTP_PUT = 0x08; + public static final int HTTP_PUT_RECV = 0x09; + public static final int HTTP_DELETE = 0x0A; + public static final int HTTP_TRACE = 0x0B; + public static final int HTTP_CLOSE = 0x0C; + public static final int HTTP_STATUS = 0x0D; + + public static final int HTTP_0_9 = 0x09; + public static final int HTTP_1_0 = 0x64; + public static final int HTTP_1_1 = 0x65; + + public static final int HTTP_KEEPALIVE_OFF = 0x00; + public static final int HTTP_KEEPALIVE_ON = 0x01; + + public static final int HTTP_ENCODE_LENGTH = 0x00; + public static final int HTTP_ENCODE_CHUNKED = 0x01; + + public static final int HTTP_ENCRYPT_IF_REQUESTED = 0x00; + public static final int HTTP_ENCRYPT_NEVER = 0x01; + public static final int HTTP_ENCRYPT_REQUIRED = 0x02; + public static final int HTTP_ENCRYPT_ALWAYS = 0x03; + + public static final int HTTP_AUTH_NONE = 0x00; + public static final int HTTP_AUTH_BASIC = 0x01; + public static final int HTTP_AUTH_MD5 = 0x02; + public static final int HTTP_AUTH_MD5_SESS = 0x03; + public static final int HTTP_AUTH_MD5_INT = 0x04; + public static final int HTTP_AUTH_MD5_SESS_INT = 0x05; + + public static final int HTTP_ERROR = 0xFFFFFFFF; + public static final int HTTP_CONTINUE = 0x64; + public static final int HTTP_SWITCHING_PROTOCOLS = 0x65; + public static final int HTTP_OK = 0xC8; + public static final int HTTP_CREATED = 0xC9; + public static final int HTTP_ACCEPTED = 0xCA; + public static final int HTTP_NOT_AUTHORITATIVE = 0xCB; + public static final int HTTP_NO_CONTENT = 0xCC; + public static final int HTTP_RESET_CONTENT = 0xCD; + public static final int HTTP_PARTIAL_CONTENT = 0xCE; + public static final int HTTP_MULTIPLE_CHOICES = 0x12C; + public static final int HTTP_MOVED_PERMANENTLY = 0x12D; + public static final int HTTP_MOVED_TEMPORARILY = 0x12E; + public static final int HTTP_SEE_OTHER = 0x12F; + public static final int HTTP_NOT_MODIFIED = 0x130; + public static final int HTTP_USE_PROXY = 0x131; + public static final int HTTP_BAD_REQUEST = 0x190; + public static final int HTTP_UNAUTHORIZED = 0x191; + public static final int HTTP_PAYMENT_REQUIRED = 0x192; + public static final int HTTP_FORBIDDEN = 0x193; + public static final int HTTP_NOT_FOUND = 0x194; + public static final int HTTP_METHOD_NOT_ALLOWED = 0x195; + public static final int HTTP_NOT_ACCEPTABLE = 0x196; + public static final int HTTP_PROXY_AUTHENTICATION = 0x197; + public static final int HTTP_REQUEST_TIMEOUT = 0x198; + public static final int HTTP_CONFLICT = 0x199; + public static final int HTTP_GONE = 0x19A; + public static final int HTTP_LENGTH_REQUIRED = 0x19B; + public static final int HTTP_PRECONDITION = 0x19C; + public static final int HTTP_REQUEST_TOO_LARGE = 0x19D; + public static final int HTTP_URI_TOO_LONG = 0x19E; + public static final int HTTP_UNSUPPORTED_MEDIATYPE = 0x19F; + public static final int HTTP_UPGRADE_REQUIRED = 0x1AA; + public static final int HTTP_SERVER_ERROR = 0x1F4; + public static final int HTTP_NOT_IMPLEMENTED = 0x1F5; + public static final int HTTP_BAD_GATEWAY = 0x1F6; + public static final int HTTP_SERVICE_UNAVAILABLE = 0x1F7; + public static final int HTTP_GATEWAY_TIMEOUT = 0x1F8; + + public static final int HTTP_NOT_SUPPORTED = 0x1F9; + + public static final int HTTP_FIELD_UNKNOWN = 0xFFFFFFFF; + public static final int HTTP_FIELD_ACCEPT_LANGUAGE = 0x00; + public static final int HTTP_FIELD_ACCEPT_RANGES = 0x01; + public static final int HTTP_FIELD_AUTHORIZATION = 0x02; + public static final int HTTP_FIELD_CONNECTION = 0x03; + public static final int HTTP_FIELD_CONTENT_ENCODING = 0x04; + public static final int HTTP_FIELD_CONTENT_LANGUAGE = 0x05; + public static final int HTTP_FIELD_CONTENT_LENGTH = 0x06; + public static final int HTTP_FIELD_CONTENT_LOCATION = 0x07; + public static final int HTTP_FIELD_CONTENT_MD5 = 0x08; + public static final int HTTP_FIELD_CONTENT_RANGE = 0x09; + public static final int HTTP_FIELD_CONTENT_TYPE = 0x0A; + public static final int HTTP_FIELD_CONTENT_VERSION = 0x0B; + public static final int HTTP_FIELD_DATE = 0x0C; + public static final int HTTP_FIELD_HOST = 0x0D; + public static final int HTTP_FIELD_IF_MODIFIED_SINCE = 0x0E; + public static final int HTTP_FIELD_IF_UNMODIFIED_SINCE = 0x0F; + public static final int HTTP_FIELD_KEEP_ALIVE = 0x10; + public static final int HTTP_FIELD_LAST_MODIFIED = 0x11; + public static final int HTTP_FIELD_LINK = 0x12; + public static final int HTTP_FIELD_LOCATION = 0x13; + public static final int HTTP_FIELD_RANGE = 0x14; + public static final int HTTP_FIELD_REFERER = 0x15; + public static final int HTTP_FIELD_RETRY_AFTER = 0x16; + public static final int HTTP_FIELD_TRANSFER_ENCODING = 0x17; + public static final int HTTP_FIELD_UPGRADE = 0x18; + public static final int HTTP_FIELD_USER_AGENT = 0x19; + public static final int HTTP_FIELD_WWW_AUTHENTICATE = 0x1A; + public static final int HTTP_FIELD_MAX = 0x1B; + + public static final String 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" + }; + public static final String days[] = + { + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" + }; + public static final String months[] = + { + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + }; + + + + // + // Private class members. + // + private URL url; // URL of connection. + + public Socket conn; // Connection socket. + public boolean connected; // True when connected. + + public BufferedInputStream is; // Input stream. + public BufferedReader br; + public BufferedOutputStream os; // Output stream. + + private boolean encrypted; + + public int write_content_length; + private char write_buffer[]; + private int write_buffer_head; + private int write_buffer_tail; + + public String read_header_date; + public String read_header_server; + public String read_header_charset; + public String read_header_content_language; + public String read_header_content_type; + public int read_header_content_length; + + public char read_buffer[]; + private int read_buffer_head; + private int read_buffer_tail; + + public int status; + public String status_text; + public String version; + public int error; + public int activity; + + public String hostname; // Hostname from URL + public int port; // Port from URL. + public String path; // Path from URL. + public String user; // User name + public String passwd; // Password + + public String auth_type; // none, basic, digest + public String realm; // For digest auth + public String opaque; // For digest auth + public String nonce; // For digest auth + public String resource; // For digest auth + public String method; // For digest auth + + public String http_request; + public int http_content_length; + + + + /** + * Constructor using URL. + * + * @param request_url URL of server to connect to. + * @throw IOException + * @throw UnknownHostException + */ + public IPPHttp( String request_url ) + throws IOException, UnknownHostException + { + + encrypted = false; + status = 0; + status_text = ""; + version = "1.0"; + connected = false; + user = ""; + passwd = ""; + + auth_type = ""; + realm = ""; + nonce = ""; + resource = ""; + method = ""; + + try + { + // + // Create the URL and split it up. + // + url = new URL(request_url); + hostname = url.getHost(); + port = url.getPort(); + path = url.getPath(); + + + // + // Open the socket and set the options. + // + conn = new Socket(hostname, port); + conn.setSoTimeout(200); + + // + // Create the input and output streams. + // + is = new BufferedInputStream(new DataInputStream(conn.getInputStream())); + os = new BufferedOutputStream(new DataOutputStream(conn.getOutputStream())); + connected = true; + } + catch(UnknownHostException unknownhostexception) + { + throw unknownhostexception; + } + catch(IOException ioexception) + { + throw ioexception; + } + } + + + + /** + * Constructor using URL, user and pass. + * + * @param request_url URL of server to connect to. + * @param p_auth_type String basic or digest. + * @param p_user String User name. + * @param p_passwd String password. + * @throw IOException + * @throw UnknownHostException + */ + public IPPHttp( String request_url, String p_auth_type, + String p_user, String p_passwd ) + throws IOException, UnknownHostException + { + encrypted = false; + status = 0; + status_text = ""; + version = "1.0"; + connected = false; + + user = p_user; + passwd = p_passwd; + auth_type = p_auth_type; + + realm = ""; + nonce = ""; + resource = ""; + method = ""; + + try + { + // + // Create the URL and split it up. + // + url = new URL(request_url); + hostname = url.getHost(); + port = url.getPort(); + path = url.getPath(); + + // + // Open the socket and set the options. + // + conn = new Socket(hostname, port); + conn.setSoTimeout(200); + + // + // Create the input and output streams. + // + is = new BufferedInputStream(new DataInputStream(conn.getInputStream())); + os = new BufferedOutputStream(new DataOutputStream(conn.getOutputStream())); + connected = true; + } + catch(UnknownHostException unknownhostexception) + { + throw unknownhostexception; + } + catch(IOException ioexception) + { + throw ioexception; + } + } + + + + + /** + * Re-establish a dropped connection. + * + * @return boolean True if connected. + * + * @throw IOException + */ + public boolean reConnect() throws IOException + { + connected = false; + status = 0; + status_text = ""; + try + { + // + // Open the socket and set the options. + // + conn = new Socket(hostname, port); + conn.setSoTimeout(200); + + // + // Create the input and output streams. + // + is = new BufferedInputStream(new DataInputStream(conn.getInputStream())); + os = new BufferedOutputStream(new DataOutputStream(conn.getOutputStream())); + connected = true; + return(connected); + + } + catch (IOException ioexception) + { + connected = false; + throw(ioexception); + } + } + + + + /** + * Set the user name. + * + * @param p_user String - user name. + */ + public void setUser(String p_user ) + { + user = p_user; + } + + + /** + * Set the password. + * + * @param p_passwd String - password. + */ + public void setPassword(String p_passwd ) + { + passwd = p_passwd; + } + + + + + /** + * Write the request header bytes to the server. + * + * @param request String - the request. + * @param content_length int - size of the total request. + * @throw IOException + */ + public int writeHeader(String request, int content_length ) + throws IOException + { + + http_request = request; + http_content_length = content_length; + + try + { + String s1 = "POST " + request + " HTTP/1.0\r\n"; + os.write(s1.getBytes(), 0, s1.length()); + + s1 = "Content-type: application/ipp\r\n"; + os.write(s1.getBytes(), 0, s1.length()); + + + // + // Do basic style authorization if needed. + // + if (auth_type.compareTo("basic") == 0) + { + s1 = user + ":" + passwd; + IPPBase64Encoder encoder = new IPPBase64Encoder(); + String auth_string = encoder.encode(s1.getBytes()); + s1 = "Authorization: Basic " + auth_string + "\r\n"; + os.write(s1.getBytes(), 0, s1.length()); + } + else if (auth_type.compareTo("digest") == 0) + { + try + { + IPPMD5 md5 = IPPMD5.getInstance(); + String auth_string = md5.MD5Digest(user, passwd, realm, + "POST", path, nonce ); + s1 = "Authorization: Digest " + "username=\"" + user + "\", " + + "realm=\"" + realm + "\", " + + "nonce=\"" + nonce + "\", " + + "response=\"" + auth_string + "\"\r\n"; + + os.write(s1.getBytes(), 0, s1.length()); + } + catch(NoSuchAlgorithmException e) + { + System.out.println("No such algorithm: MD5."); + } + } + + s1 = "Content-length: " + content_length + "\r\n\r\n"; + os.write(s1.getBytes(), 0, s1.length()); + os.flush(); + } + catch(IOException ioexception) + { + error = HTTP_ERROR; + throw ioexception; + } + + + try + { + int local_status = 0; + + // + // Check for any response. + // + if (is.available() > 0) + { + StringBuffer http_version = new StringBuffer(32); + StringBuffer http_status = new StringBuffer(32); + StringBuffer http_text = new StringBuffer(256); + + String read_buffer; + status = 0; + is.mark(8192); + while (is.available() > 0) + { + read_buffer = read_line(); + + if (read_buffer.startsWith("HTTP/")) + { + int i,n; + String s2 = read_buffer.substring(5); + + + for (i=0;(i < s2.length() && s2.charAt(i) != ' '); i++) + { + http_version.append(s2.charAt(i)); + } + while (i < s2.length() && s2.charAt(i) == ' ') + i++; + for (;(i < s2.length() && s2.charAt(i) != '\n' && + s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++) + { + http_status.append(s2.charAt(i)); + } + + while (i < s2.length() && s2.charAt(i) == ' ') + i++; + for (n=0;(n < 256 && i < s2.length() && s2.charAt(i) != '\n' && + s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++) + { + http_text.append(s2.charAt(i)); + } + local_status = Integer.parseInt(http_status.toString(), 10); + } + } + is.reset(); + } + + // + // See if we need to reconnect and send authorization. + // + switch( local_status ) + { + // + // Not authorized. + // + case HTTP_UNAUTHORIZED: read_header(); + return( local_status ); + } + } + catch(IOException ioexception) + { + error = HTTP_ERROR; + throw ioexception; + } + return(0); + } + + + + + + + public int checkForResponse() + { + // + // Check for any response. + // + try + { + if (is.available() > 0) + { + StringBuffer http_version = new StringBuffer(32); + StringBuffer http_status = new StringBuffer(32); + StringBuffer http_text = new StringBuffer(256); + int local_status = 0; + String read_buffer; + + status = 0; + is.mark(8192); + while (is.available() > 0) + { + read_buffer = read_line(); + if (read_buffer.startsWith("HTTP/")) + { + int i,n; + String s2 = read_buffer.substring(5); + for (i=0;(i < s2.length() && s2.charAt(i) != ' '); i++) + { + http_version.append(s2.charAt(i)); + } + while (i < s2.length() && s2.charAt(i) == ' ') + i++; + for (;(i < s2.length() && s2.charAt(i) != '\n' && + s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++) + { + http_status.append(s2.charAt(i)); + } + + while (i < s2.length() && s2.charAt(i) == ' ') + i++; + for (n=0;(n < 256 && i < s2.length() && s2.charAt(i) != '\n' && + s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++) + { + http_text.append(s2.charAt(i)); + } + local_status = Integer.parseInt(http_status.toString(), 10); + status = local_status; + } + } + is.reset(); + + // + // See if we need to reconnect and send authorization. + // + switch( local_status ) + { + // + // Not authorized. + // + case HTTP_UNAUTHORIZED: read_header(); + return( local_status ); + } + } + } + catch (IOException e) + { + return(HTTP_ERROR); + } + return(0); + } + + + /** + * Write bytes to the output stream. + * + * @param bytes Array of bytes to write to the stream. + * @throw IOException + */ + public void write(byte bytes[]) + throws IOException + { + try + { + os.write(bytes, 0, bytes.length); + os.flush(); + } + catch(IOException ioexception) + { + error = HTTP_ERROR; + throw ioexception; + } + } + + + /** + * Write bytes to the output stream. + * + * @param bytes Array of bytes to write to the stream. + * @param length Number of bytes to write to the stream. + * @throw IOException + */ + public void write(byte bytes[], int length ) + throws IOException + { + try + { + os.write(bytes, 0, length); + os.flush(); + } + catch(IOException ioexception) + { + error = HTTP_ERROR; + throw ioexception; + } + } + + + + + + + + + + + /** + * Read the HTTP header from the input stream. + * + * @return int Content length of response. + * @return 0 Return zero on error. + * @throw IOException + */ + public int read_header() + throws IOException + { + boolean done = false; + read_header_content_length = 0; + + String read_buffer; + while (!done) + { + read_buffer = read_line(); + if (read_buffer.startsWith("HTTP/")) + { + int i,n; + String s2 = read_buffer.substring(5); + + StringBuffer http_version = new StringBuffer(32); + StringBuffer http_status = new StringBuffer(32); + StringBuffer http_text = new StringBuffer(256); + + for (i=0;(i < s2.length() && s2.charAt(i) != ' '); i++) + { + http_version.append(s2.charAt(i)); + } + while (i < s2.length() && s2.charAt(i) == ' ') + i++; + for (;(i < s2.length() && s2.charAt(i) != '\n' && + s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++) + { + http_status.append(s2.charAt(i)); + } + + while (i < s2.length() && s2.charAt(i) == ' ') + i++; + for (n=0;(n < 256 && i < s2.length() && s2.charAt(i) != '\n' && + s2.charAt(i) != '\r' && s2.charAt(i) != ' '); i++) + { + http_text.append(s2.charAt(i)); + } + version = http_version.toString(); + status = Integer.parseInt(http_status.toString(), 10); + status_text = http_text.toString(); + } + else if (read_buffer.startsWith("WWW-Authenticate: Basic")) + { + String s2=read_buffer.substring("WWW-Authenticate: Basic".length()); + auth_type = "basic"; + } + else if (read_buffer.startsWith("WWW-Authenticate: Digest")) + { + String s2=read_buffer.substring("WWW-Authenticate: Digest".length()); + auth_type = "digest"; + parseAuthenticate(s2); + } + else if (read_buffer.startsWith("Content-Length:")) + { + String s2 = read_buffer.substring(15); + read_header_content_length = Integer.parseInt(s2.trim(), 10); + } + else if (read_buffer.startsWith("Content-Language:")) + { + String s3 = read_buffer.substring(17); + read_header_content_language = s3.trim(); + } + else if (read_buffer.startsWith("Server:")) + { + String s4 = read_buffer.substring(7); + read_header_server = s4.trim(); + } + else if (read_buffer.startsWith("Date:")) + { + String s5 = read_buffer.substring(5); + read_header_date = s5.trim(); + } + else if (read_buffer.length() == 0) + { + done = true; + return( read_header_content_length ); + } + } + return( 0 ); + } + + + + /** + * Read a line from the input stream. + * + * @return String Line read. + * @throw IOException + */ + public String read_line() + throws IOException + { + StringBuffer sb = new StringBuffer(); + int c = 0; + + try + { + while ((c != -1) && (c != 10)) + { + c = is.read(); + switch( c ) + { + case -1: + case 10: + case 13: + break; + + default: sb.append((char)c); + } + } + } + catch (IOException e) + { + throw(e); + } + return(sb.toString()); + } + + + + + + /** + * Read up to count bytes from the input stream. + * + * @param count Number of bytes to read. + * @return char[] Character array of data read. + * @throw IOException + */ + public char[] read(int count) + throws IOException + { + char ac[] = new char[count]; + int j = 0; + try + { + for (int k = is.read(); k != -1 && j < count; k = is.read()) + { + ac[j++] = (char)k; + } + } + catch(IOException ioexception) + { + throw ioexception; + } + return(ac); + } + + + /** + * Process the HTTP response from the server. + * + * @return IPP IPP object containing response data. + * @see IPP + * @see IPPRequest + * @see IPPAttribute + * @see IPPValue + * @see IPPDefs + */ + public IPP processResponse() + { + IPP ipp; + IPPAttribute attr; // temp attribute + IPPValue val; // temp value + + short vtag; // Current value tag + short gtag; // Current group tag + + char[] buffer; + + ipp = new IPP(); + ipp.request = new IPPRequest(); + + int read_buffer_bytes = read_buffer.length; + int read_buffer_remaining = read_buffer_bytes; + int bufferidx = 0; + int n; + + + ipp.current = -1; // current attritue?? + ipp.last = -1; // last attr? + attr = null; + buffer = read_buffer; + gtag = -1; + vtag = -1; + + + // --------------------------------------------------------------- + // State machine to process response. + // + ipp.state = IPPDefs.IDLE; + while ((ipp.state != IPPDefs.TAG_END) && + (read_buffer_remaining > 0)) + { + switch (ipp.state) + { + case IPPDefs.IDLE : + ipp.state++; /* Avoid common problem... */ + + // + // Get the request header... + // + case IPPDefs.HEADER : + if (read_buffer_remaining < 8) + { + return (null); + } + + // + // Verify the major version number... + // + if (buffer[0] != (char)1) + { + return (null); + } + + // + // Then copy the request header over... + // + ipp.request.version[0] = buffer[bufferidx++]; + ipp.request.version[1] = buffer[bufferidx++]; + ipp.request.op_status = (short)((short)buffer[bufferidx] << 8) | + (short)buffer[bufferidx+1]; + bufferidx += 2; + + // + // Get the text version of the request status .... + // + ipp.status = new IPPStatus(ipp.request.op_status); + + ipp.request.request_id = (int)((int)buffer[bufferidx] << 24) | + ((int)buffer[bufferidx+1] << 16) | + ((int)buffer[bufferidx+2] << 8) | + ((int)buffer[bufferidx+3]); + bufferidx += 4; + read_buffer_remaining -= 8; + + ipp.state = IPPDefs.ATTRIBUTE; + ipp.current = -1; + ipp.current_tag = IPPDefs.TAG_ZERO; + break; + + case IPPDefs.ATTRIBUTE : + while (read_buffer_remaining > 0) + { + // + // Read the value tag first. + // + vtag = (short)buffer[bufferidx++]; + read_buffer_remaining--; + if (vtag == IPPDefs.TAG_END) + { + // + // No more attributes left... + // + ipp.state = IPPDefs.DATA; + if (attr != null) + { + ipp.addAttribute(attr); + attr = null; + } + break; + } + else if (vtag < IPPDefs.TAG_UNSUPPORTED_VALUE) + { + if (attr != null) + { + ipp.addAttribute(attr); + } + + // + // Group tag... Set the current group and continue... + // + gtag = vtag; + + // If still the same group .... + if (ipp.current_tag == gtag) + { + // + // Add a separator + // + attr = new IPPAttribute(IPPDefs.TAG_ZERO,IPPDefs.TAG_ZERO,""); + ipp.addAttribute(attr); + attr = null; + } + + + ipp.current_tag = gtag; + ipp.current = -1; + continue; + } + + // + // Get the name... + // + n = ((int)buffer[bufferidx] << 8) | (int)buffer[bufferidx+1]; + bufferidx += 2; + read_buffer_remaining -= 2; + + if (n == 0) + { + // + // Parse Error, can't add additional values to null attr + // + if (attr == null) + return (null); + + // + // More values for current attribute... + // + + // + // Make sure we aren't adding a new value of a different + // type... + // + + if (attr.value_tag == IPPDefs.TAG_STRING || + (attr.value_tag >= IPPDefs.TAG_TEXTLANG && + attr.value_tag <= IPPDefs.TAG_MIMETYPE)) + { + // + // String values can sometimes come across in different + // forms; accept sets of differing values... + // + if (vtag != IPPDefs.TAG_STRING && + (vtag < IPPDefs.TAG_TEXTLANG || vtag > IPPDefs.TAG_MIMETYPE)) + return (null); + } + else if (attr.value_tag != vtag) + return (null); + } + else + { + if (attr != null) + { + ipp.addAttribute(attr); + attr = null; + } + + // + // New Attribute + // + StringBuffer s = new StringBuffer(); + for (int i=0; i < n; i++) + { + s.append((char)buffer[bufferidx++]); + read_buffer_remaining--; + } + attr = new IPPAttribute( gtag, vtag, s.toString() ); + } + n = ((short)buffer[bufferidx] << 8) | (short)buffer[bufferidx+1]; + bufferidx += 2; + read_buffer_remaining -= 2; + + switch (vtag) + { + case IPPDefs.TAG_INTEGER : + case IPPDefs.TAG_ENUM : + n = (int)(((int)buffer[bufferidx] << 24) | + ((int)buffer[bufferidx+1] << 16) | + ((int)buffer[bufferidx+2] << 8) | + ((int)buffer[bufferidx+3])); + bufferidx += 4; + read_buffer_remaining -= 4; + attr.addInteger( n ); + break; + + case IPPDefs.TAG_BOOLEAN : + if ((byte)buffer[bufferidx++] > 0) + attr.addBoolean(true); + else + attr.addBoolean(false); + read_buffer_remaining --; + break; + + case IPPDefs.TAG_TEXT : + case IPPDefs.TAG_NAME : + case IPPDefs.TAG_KEYWORD : + case IPPDefs.TAG_STRING : + case IPPDefs.TAG_URI : + case IPPDefs.TAG_URISCHEME : + case IPPDefs.TAG_CHARSET : + case IPPDefs.TAG_LANGUAGE : + case IPPDefs.TAG_MIMETYPE : + StringBuffer s = new StringBuffer(); + for (int i=0; i < n; i++ ) + { + s.append( (char)buffer[bufferidx++] ); + read_buffer_remaining --; + } + attr.addString( "", s.toString() ); + break; + + + case IPPDefs.TAG_DATE : + char db[] = new char[11]; + for (int i=0; i < 11; i++ ) + { + db[i] = (char)buffer[bufferidx++]; + read_buffer_remaining --; + } + attr.addDate( db ); + break; + + + case IPPDefs.TAG_RESOLUTION : + if (read_buffer_remaining < 9) + return( null ); + + int x, y; + byte u; + x = (int)(((int)buffer[bufferidx] & 0xff000000) << 24) | + (((int)buffer[bufferidx+1] & 0x00ff0000) << 16) | + (((int)buffer[bufferidx+2] & 0x0000ff00) << 8) | + (((int)buffer[bufferidx+3] & 0x000000ff)); + bufferidx += 4; + read_buffer_remaining -= 4; + + y = (int)(((int)buffer[bufferidx] & 0xff000000) << 24) | + (((int)buffer[bufferidx+1] & 0x00ff0000) << 16) | + (((int)buffer[bufferidx+2] & 0x0000ff00) << 8) | + (((int)buffer[bufferidx+3] & 0x000000ff)); + bufferidx += 4; + read_buffer_remaining -= 4; + + u = (byte)buffer[bufferidx++]; + read_buffer_remaining--; + attr.addResolution( u, x, y ); + break; + + case IPPDefs.TAG_RANGE : + if (read_buffer_remaining < 8) + return (null); + + int lower, upper; + lower = (int)(((int)buffer[bufferidx] & 0xff000000) << 24) | + (((int)buffer[bufferidx+1] & 0x00ff0000) << 16) | + (((int)buffer[bufferidx+2] & 0x0000ff00) << 8) | + (((int)buffer[bufferidx+3] & 0x000000ff)); + bufferidx += 4; + read_buffer_remaining -= 4; + + upper = (int)(((int)buffer[bufferidx] & 0xff000000) << 24) | + (((int)buffer[bufferidx+1] & 0x00ff0000) << 16) | + (((int)buffer[bufferidx+2] & 0x0000ff00) << 8) | + (((int)buffer[bufferidx+3] & 0x000000ff)); + bufferidx += 4; + read_buffer_remaining -= 4; + + attr.addRange( (short)lower, (short)upper ); + break; + + case IPPDefs.TAG_TEXTLANG : + case IPPDefs.TAG_NAMELANG : + // + // text-with-language and name-with-language are composite + // values: + // + // charset-length + // charset + // text-length + // text + // + + n = ((int)buffer[bufferidx] << 8) | (int)buffer[bufferidx+1]; + bufferidx += 2; + + StringBuffer cs = new StringBuffer(); + for (int i=0; i < n; i++ ) + { + cs.append( (char)buffer[bufferidx++] ); + read_buffer_remaining --; + } + + n = ((int)buffer[bufferidx] << 8) | (int)buffer[bufferidx+1]; + bufferidx += 2; + + StringBuffer tx = new StringBuffer(); + for (int i=0; i < n; i++ ) + { + tx.append( (char)buffer[bufferidx++] ); + read_buffer_remaining --; + } + + attr.addString( cs.toString(), tx.toString() ); + break; + + + default : /* Other unsupported values */ + if (n > 0) + { + bufferidx += n; + read_buffer_remaining -= n; + } + break; + } + } // End of while + + if (attr != null) + { + ipp.addAttribute(attr); + attr = null; + } + break; + + case IPPDefs.DATA : + break; + + default : + break; /* anti-compiler-warning-code */ + } + } + return (ipp); +} + + + +// +// Parse a WWW-Authenticate: Digest request +// +public void parseAuthenticate( String p_auth ) +{ + String tmp; + StringBuffer val; + int i,n; + + tmp = p_auth; + while (tmp.length() > 0) + { + i = 0; + while (tmp.length() > 0 && (tmp.charAt(i) == ' ' || tmp.charAt(i) == '"')) + tmp = tmp.substring(1); + i = 0; + + if (tmp.startsWith("realm=")) + { + i = "realm=".length(); + tmp = tmp.substring(i); + i = 0; + while ((i < tmp.length()) && + (tmp.charAt(i) == ' ' || + tmp.charAt(i) == '"' || + tmp.charAt(i) == '=')) + { + i++; + } + val = new StringBuffer(1024); + while (i < tmp.length() && tmp.charAt(i) != '"') + val.append(tmp.charAt(i++)); + realm = val.toString(); + tmp = tmp.substring(i); + } + else if (tmp.startsWith("nonce=")) + { + i = "nonce=".length(); + tmp = tmp.substring(i); + i = 0; + while ((i < tmp.length()) && + (tmp.charAt(i) == ' ' || + tmp.charAt(i) == '"' || + tmp.charAt(i) == '=')) + { + i++; + } + val = new StringBuffer(1024); + while (i < tmp.length() && tmp.charAt(i) != '"') + val.append(tmp.charAt(i++)); + nonce = val.toString(); + tmp = tmp.substring(i); + } + else if (tmp.startsWith("opaque=")) + { + i = "opaque=".length(); + tmp = tmp.substring(i); + i = 0; + while ((i < tmp.length()) && + (tmp.charAt(i) == ' ' || + tmp.charAt(i) == '"' || + tmp.charAt(i) == '=')) + { + i++; + } + val = new StringBuffer(1024); + while (i < tmp.length() && tmp.charAt(i) != '"') + val.append(tmp.charAt(i++)); + opaque = val.toString(); + tmp = tmp.substring(i); + } + else + { + StringBuffer name = new StringBuffer(256); + while ((i < tmp.length()) && + (tmp.charAt(i) != ' ' || + tmp.charAt(i) != '"' || + tmp.charAt(i) != '=')) + { + name.append(tmp.charAt(i++)); + } + + i = name.toString().length(); + tmp = tmp.substring(i); + i = 0; + while ((i < tmp.length()) && + (tmp.charAt(i) == ' ' || + tmp.charAt(i) == '"' || + tmp.charAt(i) == '=')) + { + i++; + } + val = new StringBuffer(1024); + while (i < tmp.length() && tmp.charAt(i) != '"') + val.append(tmp.charAt(i++)); + //junk = val.toString(); + tmp = tmp.substring(i); + } + } +} + + + + + +} // End of IPPHttp class + + diff --git a/scripting/java/src/com/easysw/cups/IPPMD5.java b/scripting/java/src/com/easysw/cups/IPPMD5.java new file mode 100644 index 000000000..e20cbac1f --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPMD5.java @@ -0,0 +1,134 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * Digest MD5 password routines. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ +import java.security.*; + +public class IPPMD5 +{ + public MessageDigest md = null; + static private IPPMD5 md5 = null; + private static final char[] hexChars = {'0','1','2','3','4','5','6','7', + '8','9','a','b','c','d','e','f'}; + + /** + * Constructor is private so you must use the getInstance method + */ + private IPPMD5() throws NoSuchAlgorithmException + { + md = MessageDigest.getInstance("MD5"); + } + + + /** + * This returns the singleton instance + */ + public static IPPMD5 getInstance() throws NoSuchAlgorithmException + { + + if (md5 == null) + { + md5 = new IPPMD5(); + } + return (md5); + } + + + public String hashData(byte[] dataToHash) + { + return(hexStringFromBytes((calculateHash(dataToHash)))); + } + + + private byte[] calculateHash(byte[] dataToHash) + { + md.update(dataToHash, 0, dataToHash.length); + return(md.digest()); + } + + + public String hexStringFromBytes(byte[] b) + { + String hex = ""; + int msb; + int lsb = 0; + int i; + + // MSB maps to idx 0 + for (i = 0; i < b.length; i++) + { + msb = ((int)b[i] & 0x000000FF) / 16; + lsb = ((int)b[i] & 0x000000FF) % 16; + // System.out.println("I: " + i + " B: " + b[i] + " MSB: " + + // msb + " LSB: " + lsb ); + hex = hex + hexChars[msb] + hexChars[lsb]; + } + return(hex); + } + + + + + + public String MD5Digest( String user, String passwd, String realm, + String method, String resource, String nonce ) + { + String tmp; + String A1, A2; + String auth_string = ""; + + try + { + tmp = user + ":" + realm + ":" + passwd; + md = MessageDigest.getInstance("MD5"); + A1 = hexStringFromBytes(md.digest(tmp.getBytes())); + + tmp = method + ":" + resource; + md = MessageDigest.getInstance("MD5"); + A2 = hexStringFromBytes(md.digest(tmp.getBytes())); + + tmp = A1 + ":" + nonce + ":" + A2; + md = MessageDigest.getInstance("MD5"); + auth_string = hexStringFromBytes(md.digest(tmp.getBytes())); + return(auth_string); + } + catch (NoSuchAlgorithmException e) + { + } + return(""); + + } + + +} diff --git a/scripting/java/src/com/easysw/cups/IPPRequest.java b/scripting/java/src/com/easysw/cups/IPPRequest.java new file mode 100644 index 000000000..a0de169dc --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPRequest.java @@ -0,0 +1,97 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * An IPPRequest object is used to hold the + * status and id's of a request. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ +public class IPPRequest +{ + char[] version; // Proto version number + int request_id; // Unique ID + + int op_status; + short operation_id; + short status_code; + + /** + * Constructor + */ + public IPPRequest() + { + version = new char[2]; + } + + /** + * Constructor using request id and operation id. + * + * @param p_request_id ID of request. + * @param p_operation_id Operation ID for request. + * + * @see IPPDefs + */ + public IPPRequest( int p_request_id, short p_operation_id ) + { + version = new char[2]; + version[0] = (char)1; + version[1] = (char)1; + request_id = p_request_id; + operation_id = p_operation_id; + } + + /** + * Set the current status of a request. + * + * @param p_status_code Status code. + * @see IPPDefs + */ + public void setStatus( short p_status_code ) + { + status_code = p_status_code; + } + + /** + * Set the operation status of a request. + * + * @param p_status_code Operation status code. + * @see IPPDefs + */ + public void setOpStatus( short p_status_code ) + { + op_status = p_status_code; + } + +} // End of IPPRequest class + + + + diff --git a/scripting/java/src/com/easysw/cups/IPPStatus.java b/scripting/java/src/com/easysw/cups/IPPStatus.java new file mode 100644 index 000000000..d3e0c2541 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPStatus.java @@ -0,0 +1,195 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * Class to convert a status code to text. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ + +public class IPPStatus +{ + int status; + String status_text; + + /** + * Constructor, access the status_text member + * after creation. + * + * @param p_status Status code to convert. + * @see IPPDefs + */ + public IPPStatus( int p_status ) + { + status = p_status; + switch( status ) + { + case IPPDefs.OK: + status_text = "OK"; + break; + case IPPDefs.OK_SUBST: + status_text = "OK, substituted"; + break; + case IPPDefs.OK_CONFLICT: + status_text = "OK, conflict"; + break; + case IPPDefs.OK_IGNORED_SUBSCRIPTIONS: + status_text = "OK, ignored subscriptions"; + break; + case IPPDefs.OK_IGNORED_NOTIFICATIONS: + status_text = "OK, ignored notifications"; + break; + case IPPDefs.OK_TOO_MANY_EVENTS: + status_text = "OK, too many events"; + break; + case IPPDefs.OK_BUT_CANCEL_SUBSCRIPTION: + status_text = "OK, but cancel subscription"; + break; + case IPPDefs.REDIRECTION_OTHER_SITE: + status_text = "Redirected to other site"; + break; + case IPPDefs.BAD_REQUEST: + status_text = "Bad request"; + break; + case IPPDefs.FORBIDDEN: + status_text = "Forbidden"; + break; + case IPPDefs.NOT_AUTHENTICATED: + status_text = "Not authenticated"; + break; + case IPPDefs.NOT_AUTHORIZED: + status_text = "Not authorized"; + break; + case IPPDefs.NOT_POSSIBLE: + status_text = "Not possible"; + break; + case IPPDefs.TIMEOUT: + status_text = "Timeout"; + break; + case IPPDefs.NOT_FOUND: + status_text = "Not found"; + break; + case IPPDefs.GONE: + status_text = "Gone"; + break; + case IPPDefs.REQUEST_ENTITY: + status_text = "Request entity"; + break; + case IPPDefs.REQUEST_VALUE: + status_text = "Request value"; + break; + case IPPDefs.DOCUMENT_FORMAT: + status_text = "Document format"; + break; + case IPPDefs.ATTRIBUTES: + status_text = "Attributes"; + break; + case IPPDefs.URI_SCHEME: + status_text = "URI scheme"; + break; + case IPPDefs.CHARSET: + status_text = "Charset"; + break; + case IPPDefs.CONFLICT: + status_text = "Conflict"; + break; + case IPPDefs.COMPRESSION_NOT_SUPPORTED: + status_text = "Compression not supported"; + break; + case IPPDefs.COMPRESSION_ERROR: + status_text = "Compression error"; + break; + case IPPDefs.DOCUMENT_FORMAT_ERROR: + status_text = "Document format error"; + break; + case IPPDefs.DOCUMENT_ACCESS_ERROR: + status_text = "Document access error"; + break; + case IPPDefs.ATTRIBUTES_NOT_SETTABLE: + status_text = "Attributes not settable"; + break; + case IPPDefs.IGNORED_ALL_SUBSCRIPTIONS: + status_text = "Ignored all subscriptions"; + break; + case IPPDefs.TOO_MANY_SUBSCRIPTIONS: + status_text = "Too many subscriptions"; + break; + case IPPDefs.IGNORED_ALL_NOTIFICATIONS: + status_text = "Ingored all notifications"; + break; + case IPPDefs.PRINT_SUPPORT_FILE_NOT_FOUND: + status_text = "Support file not found"; + break; + case IPPDefs.INTERNAL_ERROR: + status_text = "Internal error"; + break; + case IPPDefs.OPERATION_NOT_SUPPORTED: + status_text = "Operation not supported"; + break; + case IPPDefs.SERVICE_UNAVAILABLE: + status_text = "Service unavailable"; + break; + case IPPDefs.VERSION_NOT_SUPPORTED: + status_text = "Version not supported"; + break; + case IPPDefs.DEVICE_ERROR: + status_text = "Device error"; + break; + case IPPDefs.TEMPORARY_ERROR: + status_text = "Temporary error"; + break; + case IPPDefs.NOT_ACCEPTING: + status_text = "Not accepting"; + break; + case IPPDefs.PRINTER_BUSY: + status_text = "Printer busy"; + break; + case IPPDefs.ERROR_JOB_CANCELLED: + status_text = "Error, job cancelled"; + break; + case IPPDefs.MULTIPLE_JOBS_NOT_SUPPORTED: + status_text = "Multiple jobs not supported"; + break; + case IPPDefs.PRINTER_IS_DEACTIVATED: + status_text = "Printer is de-activated"; + break; + default: + status_text = "Unknown error"; + } + } + + + + + +} // End of IPPStatus class + + + diff --git a/scripting/java/src/com/easysw/cups/IPPURLConnection.java b/scripting/java/src/com/easysw/cups/IPPURLConnection.java new file mode 100644 index 000000000..eee1b3542 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPURLConnection.java @@ -0,0 +1,78 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * Implementation of the URLConnection interface. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ + +import java.util.*; +import java.io.*; +import java.net.*; + +public class IPPURLConnection extends URLConnection +{ + + /** + * Constructor. + */ + public IPPURLConnection( URL url ) + { + super(url); + } + + /** + * Determine if using proxy. + * + * @return boolean Always false for now. + */ + public boolean usingProxy() + { + return(false); + } + + /** + * Not used. + */ + public void connect() + { + return; + } + + /** + * Not used. + */ + public void disconnect() + { + return; + } + +} // end of class diff --git a/scripting/java/src/com/easysw/cups/IPPValue.java b/scripting/java/src/com/easysw/cups/IPPValue.java new file mode 100644 index 000000000..43725d3ab --- /dev/null +++ b/scripting/java/src/com/easysw/cups/IPPValue.java @@ -0,0 +1,264 @@ +package com.easysw.cups; + +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * An IPPValue object is used to hold the + * different kinds of values in a generic object. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ +import java.util.*; + +public class IPPValue +{ + + int value_type; // Type of value for this object. + + int integer_value; // Integer value + boolean boolean_value; // Boolean value + + + char date_value[]; // Date/time value + long unix_time; // Unix time .... + + // + // Resolution Type + // + int xres; + int yres; + byte units; + + // + // Range Type + // + int lower; + int upper; + + // + // String Type + // + String charset; + String text; + + // + // Unknown Type + // + int length; + char data[]; + + + /** + * Byte constructor. + * + * @param p_byte Byte value. + */ + public IPPValue( byte p_byte ) + { + value_type = IPPDefs.TAG_INTEGER; + integer_value = (int)p_byte; + } + + /** + * Short constructor. + * + * @param p_short Short value. + */ + public IPPValue( short p_short ) + { + value_type = IPPDefs.TAG_INTEGER; + integer_value = (int)p_short; + } + + /** + * Integer constructor. + * + * @param p_int Integer value. + */ + public IPPValue( int p_int ) + { + value_type = IPPDefs.TAG_INTEGER; + integer_value = p_int; + } + + /** + * Enum constructor. + * + * @param p_int Integer value - force to IPP enum. + */ + public IPPValue( int p_int, boolean anything ) + { + value_type = IPPDefs.TAG_ENUM; + integer_value = p_int; + } + + /** + * Boolean constructor. + * + * @param p_boolean Boolean value. + */ + public IPPValue( boolean p_boolean ) + { + value_type = IPPDefs.TAG_BOOLEAN; + boolean_value = p_boolean; + } + + + /** + * Date constructor. Also set the unix_time member. + * + * @param p_date[] Character array with date value. + */ + public IPPValue( char p_date[] ) + { + value_type = IPPDefs.TAG_DATE; + date_value = p_date; + unix_time = IPPDateToTime(); + } + + + + /** + * String constructor. Set the string and + * charset values. + * + * @param p_charset Charset for string. + * @param p_text Text for string. + */ + public IPPValue( String p_charset, String p_text ) + { + value_type = IPPDefs.TAG_STRING; + charset = p_charset; + text = p_text; + } + + + /** + * Range constructor. Automatically swap as needed. + * + * @param p_lower Integer lower value. + * @param p_upper Integer upper value. + */ + public IPPValue( int p_lower, int p_upper ) + { + value_type = IPPDefs.TAG_RANGE; + if (p_lower < p_upper) + { + lower = p_lower; + upper = p_upper; + } + else + { + lower = p_upper; + upper = p_lower; + } + } + + + /** + * Resolution constructor. + * + * @param p_units Unit of measure. + * @param p_xres X resolution. + * @param p_yres Y resolution. + */ + public IPPValue( byte p_units, int p_xres, int p_yres ) + { + value_type = IPPDefs.TAG_RESOLUTION; + units = p_units; + xres = p_xres; + yres = p_yres; + } + + + /** + * Raw data constructor. + * + * @param p_length Size of array. + * @param p_data[] Data. + */ + public IPPValue( int p_length, char p_data[] ) + { + value_type = IPPDefs.TAG_UNKNOWN; + length = p_length; + data = p_data; + } + + + + /** + * Convert an IPP Date value to Unix Time. + * + * @return long Unix time in seconds. + * @see IPPCalender + */ + public long IPPDateToTime() + { + + // + // Compute the offset from GMT in milliseconds. + // + int raw_offset = (((int)date_value[9] * 3600) + ((int)date_value[10] * 60)) * 1000; + if (date_value[8] == '-') + raw_offset = 0 - raw_offset; + + // + // Get the timezone for that offset. + // + TimeZone tz = new SimpleTimeZone(raw_offset,"GMT"); + + // + // Create a subclassed gregorian calendar (sub classed so we have + // access to the getTimeInMillis() method). + // + IPPCalendar cl = new IPPCalendar(); + + int year = ((((int)date_value[0]) << 8) | (((int)date_value[1]) - 1900)); + int month = ((int)date_value[2]) - 1; + int day = (int)date_value[3]; + int hour = (int)date_value[4]; + int minute = (int)date_value[5]; + int second = (int)date_value[6]; + + // + // Now set the calendar to the matching time. + // + cl.setTimeZone( tz ); + cl.set( year, month, day, hour, minute, second ); + + // + // And finally get the unix time. + // + long the_time = cl.getTimeInMillis(); + the_time /= 1000; + + return(the_time); + } + +} // End of class diff --git a/scripting/java/src/com/easysw/cups/buildit b/scripting/java/src/com/easysw/cups/buildit new file mode 100755 index 000000000..b6be69521 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/buildit @@ -0,0 +1,9 @@ +#!/bin/sh +rm -f cups.jar +for x in `cat class.list`; do + javac -classpath /usr/java/classes $x.java + cp -f $x.class classes/ + mv -f $x.class ../../../../classes/com/easysw/cups +done +jar cvf cups.jar ../../../../classes/com/easysw/cups +mv cups.jar ../../../.. diff --git a/scripting/java/src/com/easysw/cups/class.list b/scripting/java/src/com/easysw/cups/class.list new file mode 100644 index 000000000..8211b4644 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/class.list @@ -0,0 +1,14 @@ +IPPBase64Encoder +IPPDefs +IPPError +IPPStatus +IPPCalendar +IPPValue +IPPAttribute +IPPRequest +IPPURLConnection +IPP +IPPHttp +CupsJob +Cups +CupsPrinter diff --git a/scripting/java/src/com/easysw/cups/cups.nfo b/scripting/java/src/com/easysw/cups/cups.nfo new file mode 100644 index 000000000..900db5150 --- /dev/null +++ b/scripting/java/src/com/easysw/cups/cups.nfo @@ -0,0 +1,34 @@ +/** + * @version 1.00 06-NOV-2002 + * @author Easy Software Products + * + * 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 + */ + +/** + * An IPP object is used to hold the various + * attributes and status of an ipp request.. + * + * @author TDB + * @version 1.0 + * @since JDK1.3 + */ diff --git a/scripting/perl/CUPS.pm b/scripting/perl/CUPS.pm new file mode 100644 index 000000000..5f2ed5f14 --- /dev/null +++ b/scripting/perl/CUPS.pm @@ -0,0 +1,144 @@ +package CUPS; + +use 5.006; +use strict; +use warnings; +use Carp; + +require Exporter; +require DynaLoader; +use AutoLoader; + +our @ISA = qw(Exporter DynaLoader); + +# Items to export into callers namespace by default. Note: do not export +# names by default without a very good reason. Use EXPORT_OK instead. +# Do not simply export all your public functions/methods/constants. + +# This allows declaration use CUPS ':all'; +# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK +# will save memory. +our %EXPORT_TAGS = ( 'all' => [ qw( + CUPS_DATE_ANY + CUPS_VERSION + HTTP_MAX_BUFFER + HTTP_MAX_HOST + HTTP_MAX_URI + HTTP_MAX_VALUE + IPP_MAX_NAME + IPP_MAX_VALUES + IPP_PORT + PPD_MAX_LINE + PPD_MAX_NAME + PPD_MAX_TEXT + PPD_VERSION +) ] ); + +our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); + +our @EXPORT = qw( + CUPS_DATE_ANY + CUPS_VERSION + HTTP_MAX_BUFFER + HTTP_MAX_HOST + HTTP_MAX_URI + HTTP_MAX_VALUE + IPP_MAX_NAME + IPP_MAX_VALUES + IPP_PORT + PPD_MAX_LINE + PPD_MAX_NAME + PPD_MAX_TEXT + PPD_VERSION +); +our $VERSION = '1.2'; + +sub AUTOLOAD { + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. If a constant is not found then control is passed + # to the AUTOLOAD in AutoLoader. + + my $constname; + our $AUTOLOAD; + ($constname = $AUTOLOAD) =~ s/.*:://; + croak "& not defined" if $constname eq 'constant'; + my $val = constant($constname, @_ ? $_[0] : 0); + if ($! != 0) { + if ($! =~ /Invalid/ || $!{EINVAL}) { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else { + croak "Your vendor has not defined CUPS macro $constname"; + } + } + { + no strict 'refs'; + # Fixed between 5.005_53 and 5.005_61 + if ($] >= 5.00561) { + *$AUTOLOAD = sub () { $val }; + } + else { + *$AUTOLOAD = sub { $val }; + } + } + goto &$AUTOLOAD; +} + +bootstrap CUPS $VERSION; + +# Preloaded methods go here. + +# Autoload methods go after =cut, and are processed by the autosplit program. + +1; +__END__ +# Below is stub documentation for your module. You better edit it! + +=head1 NAME + +CUPS - Perl extension for blah blah blah + +=head1 SYNOPSIS + + use CUPS; + blah blah blah + +=head1 DESCRIPTION + +Stub documentation for CUPS, created by h2xs. It looks like the +author of the extension was negligent enough to leave the stub +unedited. + +Blah blah blah. + +=head2 EXPORT + +None by default. + +=head2 Exportable constants + + CUPS_DATE_ANY + CUPS_VERSION + HTTP_MAX_BUFFER + HTTP_MAX_HOST + HTTP_MAX_URI + HTTP_MAX_VALUE + IPP_MAX_NAME + IPP_MAX_VALUES + IPP_PORT + PPD_MAX_LINE + PPD_MAX_NAME + PPD_MAX_TEXT + PPD_VERSION + + +=head1 AUTHOR + +A. U. Thor, Ea.u.thor@a.galaxy.far.far.awayE + +=head1 SEE ALSO + +L. + +=cut diff --git a/scripting/perl/CUPS.xs b/scripting/perl/CUPS.xs new file mode 100644 index 000000000..efaf6dc7a --- /dev/null +++ b/scripting/perl/CUPS.xs @@ -0,0 +1,270 @@ +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#include +#include +#include +#include +#include + +static int +not_here(char *s) +{ + croak("%s not implemented on this architecture", s); + return -1; +} + +static double +constant_PPD_M(char *name, int len, int arg) +{ + if (5 + 3 >= len ) { + errno = EINVAL; + return 0; + } + switch (name[5 + 3]) { + case 'L': + if (strEQ(name + 5, "AX_LINE")) { /* PPD_M removed */ +#ifdef PPD_MAX_LINE + return PPD_MAX_LINE; +#else + goto not_there; +#endif + } + case 'N': + if (strEQ(name + 5, "AX_NAME")) { /* PPD_M removed */ +#ifdef PPD_MAX_NAME + return PPD_MAX_NAME; +#else + goto not_there; +#endif + } + case 'T': + if (strEQ(name + 5, "AX_TEXT")) { /* PPD_M removed */ +#ifdef PPD_MAX_TEXT + return PPD_MAX_TEXT; +#else + goto not_there; +#endif + } + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + +static double +constant_P(char *name, int len, int arg) +{ + if (1 + 3 >= len ) { + errno = EINVAL; + return 0; + } + switch (name[1 + 3]) { + case 'M': + if (!strnEQ(name + 1,"PD_", 3)) + break; + return constant_PPD_M(name, len, arg); + case 'V': + if (strEQ(name + 1, "PD_VERSION")) { /* P removed */ +#ifdef PPD_VERSION + return PPD_VERSION; +#else + goto not_there; +#endif + } + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + +static double +constant_H(char *name, int len, int arg) +{ + if (1 + 8 >= len ) { + errno = EINVAL; + return 0; + } + switch (name[1 + 8]) { + case 'B': + if (strEQ(name + 1, "TTP_MAX_BUFFER")) { /* H removed */ +#ifdef HTTP_MAX_BUFFER + return HTTP_MAX_BUFFER; +#else + goto not_there; +#endif + } + case 'H': + if (strEQ(name + 1, "TTP_MAX_HOST")) { /* H removed */ +#ifdef HTTP_MAX_HOST + return HTTP_MAX_HOST; +#else + goto not_there; +#endif + } + case 'U': + if (strEQ(name + 1, "TTP_MAX_URI")) { /* H removed */ +#ifdef HTTP_MAX_URI + return HTTP_MAX_URI; +#else + goto not_there; +#endif + } + case 'V': + if (strEQ(name + 1, "TTP_MAX_VALUE")) { /* H removed */ +#ifdef HTTP_MAX_VALUE + return HTTP_MAX_VALUE; +#else + goto not_there; +#endif + } + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + +static double +constant_IPP_M(char *name, int len, int arg) +{ + if (5 + 3 >= len ) { + errno = EINVAL; + return 0; + } + switch (name[5 + 3]) { + case 'N': + if (strEQ(name + 5, "AX_NAME")) { /* IPP_M removed */ +#ifdef IPP_MAX_NAME + return IPP_MAX_NAME; +#else + goto not_there; +#endif + } + case 'V': + if (strEQ(name + 5, "AX_VALUES")) { /* IPP_M removed */ +#ifdef IPP_MAX_VALUES + return IPP_MAX_VALUES; +#else + goto not_there; +#endif + } + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + +static double +constant_I(char *name, int len, int arg) +{ + if (1 + 3 >= len ) { + errno = EINVAL; + return 0; + } + switch (name[1 + 3]) { + case 'M': + if (!strnEQ(name + 1,"PP_", 3)) + break; + return constant_IPP_M(name, len, arg); + case 'P': + if (strEQ(name + 1, "PP_PORT")) { /* I removed */ +#ifdef IPP_PORT + return IPP_PORT; +#else + goto not_there; +#endif + } + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + +static double +constant_C(char *name, int len, int arg) +{ + if (1 + 4 >= len ) { + errno = EINVAL; + return 0; + } + switch (name[1 + 4]) { + case 'D': + if (strEQ(name + 1, "UPS_DATE_ANY")) { /* C removed */ +#ifdef CUPS_DATE_ANY + return CUPS_DATE_ANY; +#else + goto not_there; +#endif + } + case 'V': + if (strEQ(name + 1, "UPS_VERSION")) { /* C removed */ +#ifdef CUPS_VERSION + return CUPS_VERSION; +#else + goto not_there; +#endif + } + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + +static double +constant(char *name, int len, int arg) +{ + errno = 0; + switch (name[0 + 0]) { + case 'C': + return constant_C(name, len, arg); + case 'H': + return constant_H(name, len, arg); + case 'I': + return constant_I(name, len, arg); + case 'P': + return constant_P(name, len, arg); + } + errno = EINVAL; + return 0; + +not_there: + errno = ENOENT; + return 0; +} + + +MODULE = CUPS PACKAGE = CUPS + + +double +constant(sv,arg) + PREINIT: + STRLEN len; + INPUT: + SV * sv + char * s = SvPV(sv, len); + int arg + CODE: + RETVAL = constant(s,len,arg); + OUTPUT: + RETVAL + diff --git a/scripting/perl/Makefile.PL b/scripting/perl/Makefile.PL new file mode 100644 index 000000000..f5e4bdd27 --- /dev/null +++ b/scripting/perl/Makefile.PL @@ -0,0 +1,17 @@ +use ExtUtils::MakeMaker; +# See lib/ExtUtils/MakeMaker.pm for details of how to influence +# the contents of the Makefile that is written. +WriteMakefile( + 'NAME' => 'CUPS', + 'VERSION_FROM' => 'CUPS.pm', # finds $VERSION + 'PREREQ_PM' => {}, # e.g., Module::Name => 1.1 + ($] >= 5.005 ? ## Add these new keywords supported since 5.005 + (ABSTRACT_FROM => 'CUPS.pm', # retrieve abstract from module + AUTHOR => 'A. U. Thor ') : ()), + 'LIBS' => ['-lcups '], # e.g., '-lm' + 'DEFINE' => '', # e.g., '-DHAVE_SOMETHING' + # Insert -I. if you add *.h files later: + 'INC' => '', # e.g., '-I/usr/include/other' + # Un-comment this if you add C files to link with later: + # 'OBJECT' => '$(O_FILES)', # link all the C files too +); diff --git a/scripting/perl/README b/scripting/perl/README new file mode 100644 index 000000000..1605c7798 --- /dev/null +++ b/scripting/perl/README @@ -0,0 +1,35 @@ +CUPS version 1.2 +================ + +The README is used to introduce the module and provide instructions on +how to install the module, any machine dependencies it may have (for +example C compilers and installed libraries) and any other information +that should be provided before the module is installed. + +A README file is required for CPAN modules since CPAN extracts the +README file from a module distribution so that people browsing the +archive can use it get an idea of the modules uses. It is usually a +good idea to provide version information here so that people can +decide whether fixes for the module are worth downloading. + +INSTALLATION + +To install this module type the following: + + perl Makefile.PL + make + make test + make install + +DEPENDENCIES + +This module requires these other modules and libraries: + + blah blah blah + +COPYRIGHT AND LICENCE + +Put the correct copyright and licence information here. + +Copyright (C) 2002 A. U. Thor blah blah blah + diff --git a/scripting/perl/test.pl b/scripting/perl/test.pl new file mode 100644 index 000000000..acf31916b --- /dev/null +++ b/scripting/perl/test.pl @@ -0,0 +1,17 @@ +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### + +# change 'tests => 1' to 'tests => last_test_to_print'; + +use Test; +BEGIN { plan tests => 1 }; +use CUPS; +ok(1); # If we made it this far, we're ok. + +######################### + +# Insert your test code below, the Test module is use()ed here so read +# its man page ( perldoc Test ) for help writing this test script. + diff --git a/scripting/php/Dependencies b/scripting/php/Dependencies new file mode 100644 index 000000000..c5e45a09c --- /dev/null +++ b/scripting/php/Dependencies @@ -0,0 +1,6 @@ +# DO NOT DELETE + +phpcups.o: php_phpcups.h ../../cups/cups.h ../../cups/ipp.h ../../cups/http.h +phpcups.o: ../../cups/md5.h ../../cups/ppd.h ../../cups/ipp.h +phpcups.o: ../../cups/language.h ../../cups/string.h ../../config.h +phpcups.o: ../../cups/debug.h diff --git a/scripting/php/Example/phpcups.inc.php4 b/scripting/php/Example/phpcups.inc.php4 new file mode 100644 index 000000000..dfb11fb09 --- /dev/null +++ b/scripting/php/Example/phpcups.inc.php4 @@ -0,0 +1,310 @@ +printer_name = ""; + $this->printer_destination = ""; + $this->is_default = 0; + $this->options = Array(); + $this->printer_state = -1; + $this->printer_state_message = ""; + $this->accepting_jobs = FALSE; + $this->queued_job_count = 0; + $this->description = ""; + $this->location = ""; + $this->printer_info = ""; + $this->printer_more_info = ""; + $this->make_and_model = ""; + $this->printer_uri_supported = Array(); + $this->device_uri = ""; + $this->job_quota_period = 0; + $this->job_k_limit = 0; + $this->job_page_limit = 0; + $this->color_supported = FALSE; + $this->pages_per_minute = 0; + $this->finishings_supported = Array(); + $this->finishings_default = 0; + $this->printer_type = 0; + $this->operations_supported = Array(); + $this->multiple_document_jobs_supported = FALSE; + $this->multiple_operation_time_out = 0; + $this->job_priority_supported_lower = 0; + $this->job_priority_supported_upper = 100; + $this->job_priority_default = 50; + $this->copies_supported_lower = 1; + $this->copies_supported_upper = 1; + $this->copies_default = 1; + $this->page_range_supported = FALSE; + $this->number_up_supported = Array(); + $this->number_up_default = 0; + $this->orientation_requested_supported = Array(); + $this->orientation_requested_default = 3; + $this->media_supported = Array(); + $this->media_default = ""; + + } // End of constructor + + + // + // Get the attributes + // + function getAttributes() + { + $o_arr = cups_get_dest_options($this->printer_server, + $this->printer_name, + $this->printer_instance); + $this->printer_options = $o_arr; + + $attrs = cups_get_printer_attributes( "localhost", $this->printer_name ); + while ($obj = current($attrs)) + { + next($attrs); + + if ($obj->name == "printer-state") + { + $this->printer_state = $obj->value; + } + else if ($obj->name == "printer-state-message") + { + $this->printer_state_message = $obj->value; + } + else if ($obj->name == "printer-location") + { + $this->location = $obj->value; + } + else if ($obj->name == "printer-make-and-model") + { + $this->description = $obj->value; + } + else if ($obj->name == "printer-uri-supported") + { + $this->printer_uri_supported[$obj->value] = $obj->value; + } + else if ($obj->name == "device-uri") + { + $this->device_uri = $obj->value; + } + else if ($obj->name == "queued-job-count") + { + $this->queued_job_count = $obj->value; + } + else if ($obj->name == "printer-is-accepting-jobs") + { + $this->accepting_jobs = $obj->value ? TRUE : FALSE; + } + else if ($obj->name == "color-supported") + { + $this->color_supported = $obj->value ? TRUE : FALSE; + } + else if ($obj->name == "pages-per-minute") + { + $this->pages_per_minute = $obj->value; + } + else if ($obj->name == "operations-supported") + { + $this->operations_supported["O$obj->value"] = $obj->value; + } + else if ($obj->name == "orientation-requested-supported") + { + $this->orientation_requested_supported["O$obj->value"] = $obj->value; + } + else if ($obj->name == "orientation-requested-default") + { + $this->orientation_requested_default = $obj->value; + } + else if ($obj->name == "finishings-supported") + { + $this->finishings_supported["F$obj->value"] = $obj->value; + } + else if ($obj->name == "finishings-default") + { + $this->finishings_default = $obj->value; + } + else if ($obj->name == "number-up-supported") + { + $this->number_up_supported["N$obj->value"] = $obj->value; + } + else if ($obj->name == "number-up-default") + { + $this->number_up_default = $obj->value; + } + else if ($obj->name == "printer-type") + { + $this->printer_type = $obj->value; + } + else if ($obj->name == "multiple-document-jobs-suppoted") + { + $this->multiple_document_jobs_supported = $obj->value ? TRUE : FALSE; + } + else if ($obj->name == "multiple-operation-time-out") + { + $this->multiple_operation_time_out = $obj->value; + } + else if ($obj->name == "job-priority-supported") + { + $this->job_priority_supported_upper = $obj->value; + } + else if ($obj->name == "job-priority-default") + { + $this->job_priority_default = $obj->value; + } + else if ($obj->name == "copies-supported") + { + $tmpa = explode("-",$obj->value); + if (count($tmpa) > 1) + { + $this->copies_supported_lower = $tmpa[0]; + $this->copies_supported_upper = $tmpa[1]; + } + else if (count($tmpa) == 1) + { + $this->copies_supported_lower = $tmpa[0]; + $this->copies_supported_upper = $tmpa[0]; + } + } + else if ($obj->name == "copies-default") + { + $this->copies_supported_default = $obj->value; + } + else if ($obj->name == "page-ranges-supported") + { + $this->page_ranges_supported = $obj->value ? TRUE : FALSE; + } + else if ($obj->name == "media-default") + { + $this->media_default = $obj->value; + } + else if ($obj->name == "media-supported") + { + $this->media_supported[$obj->value] = $obj->value; + } + + } // while + + } // End of getAttributes + + + } // End of CupsPrinter class + + + + + // + // Get the printer / destination list. + // + function phpcups_getDestList() + { + $return_value = Array(); + + // + // Get the destination objects array. + // + $p_arr = cups_get_dest_list(); + + if (!IS_ARRAY($p_arr)) + { + return(NULL); + } + + reset($p_arr); + + while ($p_obj = current($p_arr)) + { + next($p_arr); + + // + // Get the options for the current destination. + // + $o_arr = cups_get_dest_options("localhost",$p_obj->name,$p_obj->instance); + + $p = new CupsPrinter(); + $p->printer_name = $p_obj->name; + $p->printer_instance = $p_obj->instance; + $p->is_default = $p_obj->is_default; + $p->printer_options = $o_arr; + $p->getAttributes(); + + $return_value[$p->printer_name] = $p; + } + return($return_value); + + } // End of phpcups_getDestList() + + + + +} // if included. +?> diff --git a/scripting/php/Makefile b/scripting/php/Makefile new file mode 100644 index 000000000..c93559e4b --- /dev/null +++ b/scripting/php/Makefile @@ -0,0 +1,107 @@ +# +# "$Id: Makefile 3572 2003-04-08 19:56:25Z mike $" +# +# PHP Makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 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 + + +# +# Where to install the PHP module... +# + +PHPDIR = `php-config --extension-dir` +OPTIONS = `php-config --includes` -I../.. -DCOMPILE_DL_PHPCUPS +PHPLIBS = `php-config --ldflags` `php-config --libs` + +# +# Object files... +# + +OBJS = phpcups.o + + +# +# Targets in this directory... +# + +TARGETS = phpcups.so + + +# +# Make all targets... +# + +all: $(TARGETS) + + +# +# Remove object and target files... +# + +clean: + $(RM) $(OBJS) $(TARGETS) + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I../.. -fDependencies $(OBJS:.o=.c) >/dev/null 2>&1 + + +# +# Install object and target files... +# + +install: all + echo Installing $(TARGETS) in $(PHPDIR) + $(INSTALL_DIR) $(PHPDIR) + cp $(TARGETS) $(PHPDIR) + + +# +# phpcups.so +# + +phpcups.so: $(OBJS) ../../Makedefs + echo Linking $@... + if test `uname` = Darwin; then \ + DSOFLAGS="-bundle -flat_namespace -undefined suppress"; \ + else \ + DSOFLAGS="$(DSOFLAGS)"; \ + fi; \ + echo $(DSO) $$DSOFLAGS -o $@ $(OBJS) -L../../cups -lcups $(PHPLIBS); \ + $(DSO) $$DSOFLAGS -o $@ $(OBJS) -L../../cups -lcups $(PHPLIBS) + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 3572 2003-04-08 19:56:25Z mike $". +# diff --git a/scripting/php/README b/scripting/php/README new file mode 100644 index 000000000..0cb23f1d5 --- /dev/null +++ b/scripting/php/README @@ -0,0 +1,21 @@ +README - 04/08/2003 +------------------- + +This directory contains a dynamically loadable CUPS extension +module for PHP 4. To compile it type: + + make + +To install it, type: + + make install + +Questions should be reported to the CUPS newsgroups/mailing +lists at: + + http://www.cups.org/newsgroups.php + +Bug reports and enhancement requests can be submitted via the +form at: + + http://www.cups.org/str.php diff --git a/scripting/php/config.m4 b/scripting/php/config.m4 new file mode 100644 index 000000000..562e9e27b --- /dev/null +++ b/scripting/php/config.m4 @@ -0,0 +1,60 @@ +dnl $Id: config.m4 3867 2003-08-14 22:29:23Z ted $ +dnl config.m4 for extension phpcups + +dnl Comments in this file start with the string 'dnl'. +dnl Remove where necessary. This file will not work +dnl without editing. + +dnl If your extension references something external, use with: + +PHP_ARG_WITH(phpcups, for phpcups support, +dnl Make sure that the comment is aligned: +[ --with-phpcups Include phpcups support]) + +dnl Otherwise use enable: + +dnl PHP_ARG_ENABLE(phpcups, whether to enable phpcups support, +dnl Make sure that the comment is aligned: +dnl [ --enable-phpcups Enable phpcups support]) + +if test "$PHP_PHPCUPS" != "no"; then + dnl Write more examples of tests here... + + dnl # --with-phpcups -> check with-path + dnl SEARCH_PATH="/usr/local /usr" # you might want to change this + dnl SEARCH_FOR="/include/phpcups.h" # you most likely want to change this + dnl if test -r $PHP_PHPCUPS/; then # path given as parameter + dnl PHPCUPS_DIR=$PHP_PHPCUPS + dnl else # search default path list + dnl AC_MSG_CHECKING(for phpcups files in default path) + dnl for i in $SEARCH_PATH ; do + dnl if test -r $i/$SEARCH_FOR; then + dnl PHPCUPS_DIR=$i + dnl AC_MSG_RESULT(found in $i) + dnl fi + dnl done + dnl fi + dnl + dnl if test -z "$PHPCUPS_DIR"; then + dnl AC_MSG_RESULT(not found) + dnl AC_MSG_ERROR(Please reinstall the phpcups distribution) + dnl fi + + dnl # --with-phpcups -> add include path + PHP_ADD_INCLUDE(/var/httpd2/web2/cups) + PHP_ADD_INCLUDE(/var/httpd2/web2/cups/cups) + + dnl # --with-phpcups -> chech for lib and symbol presence + dnl LIBNAME=phpcups # you may want to change this + dnl LIBSYMBOL=phpcups # you most likely want to change this + dnl old_LIBS=$LIBS + dnl LIBS="$LIBS -L$PHPCUPS_DIR/lib -lm -ldl" + dnl AC_CHECK_LIB($LIBNAME, $LIBSYMBOL, [AC_DEFINE(HAVE_PHPCUPSLIB,1,[ ])], + dnl [AC_MSG_ERROR(wrong phpcups lib version or lib not found)]) + dnl LIBS=$old_LIBS + dnl + dnl PHP_SUBST(PHPCUPS_SHARED_LIBADD) + PHP_ADD_LIBRARY_WITH_PATH("cups", "/var/httpd2/web2/cups/cups", PHPCUPS_SHARED_LIBADD) + + PHP_EXTENSION(phpcups, $ext_shared) +fi diff --git a/scripting/php/php_phpcups.h b/scripting/php/php_phpcups.h new file mode 100644 index 000000000..8b3fdeede --- /dev/null +++ b/scripting/php/php_phpcups.h @@ -0,0 +1,87 @@ +/* + * "$Id: php_phpcups.h 4523 2005-05-23 20:14:19Z mike $" + * + * PHP module include file for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2003 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 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 PHP_PHPCUPS_H +# define PHP_PHPCUPS_H + +extern zend_module_entry phpcups_module_entry; +# define phpext_phpcups_ptr &phpcups_module_entry + +# ifdef PHP_WIN32 +# define PHP_PHPCUPS_API __declspec(dllexport) +# else +# define PHP_PHPCUPS_API +# endif + +# ifdef ZTS +# include "TSRM.h" +# endif + +PHP_MINIT_FUNCTION(phpcups); +PHP_MSHUTDOWN_FUNCTION(phpcups); +PHP_RINIT_FUNCTION(phpcups); +PHP_RSHUTDOWN_FUNCTION(phpcups); +PHP_MINFO_FUNCTION(phpcups); + +PHP_FUNCTION(confirm_phpcups_compiled); +PHP_FUNCTION(cups_get_dest_options); +PHP_FUNCTION(cups_get_dest_list); +PHP_FUNCTION(cups_get_jobs); +PHP_FUNCTION(cups_cancel_job); +PHP_FUNCTION(cups_print_file); +PHP_FUNCTION(cups_last_error); +PHP_FUNCTION(cups_get_printer_attributes); + +/* + Declare any global variables you may need between the BEGIN + and END macros here: + +ZEND_BEGIN_MODULE_GLOBALS(phpcups) + int global_value; + char *global_string; +ZEND_END_MODULE_GLOBALS(phpcups) +*/ + +/* In every utility function you add that needs to use variables + in php_phpcups_globals, call TSRM_FETCH(); after declaring other + variables used by that function, or better yet, pass in TSRMG_CC + after the last function argument and declare your utility function + with TSRMG_DC after the last declared argument. Always refer to + the globals in your function as PHPCUPS_G(variable). You are + encouraged to rename these macros something shorter, see + examples in any other php module directory. +*/ + +# ifdef ZTS +# define PHPCUPS_G(v) TSRMG(phpcups_globals_id, zend_phpcups_globals *, v) +# else +# define PHPCUPS_G(v) (phpcups_globals.v) +# endif + +#endif /* !PHP_PHPCUPS_H */ + + +/* + * End of "$Id: php_phpcups.h 4523 2005-05-23 20:14:19Z mike $". + */ diff --git a/scripting/php/phpcups.c b/scripting/php/phpcups.c new file mode 100644 index 000000000..5d34314c5 --- /dev/null +++ b/scripting/php/phpcups.c @@ -0,0 +1,1357 @@ +/* + +----------------------------------------------------------------------+ + | PHP version 4.0 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997, 1998, 1999, 2000, 2001 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: | + | | + +----------------------------------------------------------------------+ + */ + +/* + * "$Id: phpcups.c 4530 2005-06-01 20:15:51Z mike $" + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "php_phpcups.h" + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(WIN32) || defined(__EMX__) +# include +#else +# include +#endif /* WIN32 || __EMX__ */ + + +static int le_result, le_link, le_plink; + + + + +/* + * 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 */ + + + + + +/* + * ********************************************************************* + */ + + + + +/* If you declare any globals in php_phpcups.h uncomment this: +ZEND_DECLARE_MODULE_GLOBALS(phpcups) +*/ + +/* True global resources - no need for thread safety here */ +static int le_phpcups; + +/* + * Every user visible function must have an entry in phpcups_functions[]. + */ +function_entry phpcups_functions[] = { + PHP_FE(confirm_phpcups_compiled,NULL) + PHP_FE(cups_get_dest_list, NULL) + PHP_FE(cups_get_dest_options, NULL) + PHP_FE(cups_get_jobs, NULL) + PHP_FE(cups_cancel_job, NULL) + PHP_FE(cups_last_error, NULL) + PHP_FE(cups_print_file, NULL) + PHP_FE(cups_get_printer_attributes, NULL) + {NULL, NULL, NULL} +}; + + + + +zend_module_entry phpcups_module_entry = { + STANDARD_MODULE_HEADER, + "phpcups", + phpcups_functions, + PHP_MINIT(phpcups), + PHP_MSHUTDOWN(phpcups), + PHP_RINIT(phpcups), /* Replace with NULL if there's nothing to do at request start */ + PHP_RSHUTDOWN(phpcups), /* Replace with NULL if there's nothing to do at request end */ + PHP_MINFO(phpcups), + "0.1", /* Replace with version number for your extension */ + STANDARD_MODULE_PROPERTIES +}; + +#ifdef COMPILE_DL_PHPCUPS +ZEND_GET_MODULE(phpcups) +#endif + + + + +/* Remove comments and fill if you need to have entries in php.ini +PHP_INI_BEGIN() + STD_PHP_INI_ENTRY("phpcups.value", "42", PHP_INI_ALL, OnUpdateInt, global_value, zend_phpcups_globals, phpcups_globals) + STD_PHP_INI_ENTRY("phpcups.string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_phpcups_globals, phpcups_globals) +PHP_INI_END() +*/ + + + + +/* Uncomment this function if you have INI entries +static void php_phpcups_init_globals(zend_phpcups_globals *phpcups_globals) +{ + phpcups_globals->value = 0; + phpcups_globals->string = NULL; +} +*/ + + + + +PHP_MINIT_FUNCTION(phpcups) +{ + /* If you have INI entries, uncomment these lines + ZEND_INIT_MODULE_GLOBALS(phpcups, php_phpcups_init_globals, NULL); + REGISTER_INI_ENTRIES(); + */ + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(phpcups) +{ + /* uncomment this line if you have INI entries + UNREGISTER_INI_ENTRIES(); + */ + return SUCCESS; +} + +/* Remove if there's nothing to do at request start */ +PHP_RINIT_FUNCTION(phpcups) +{ + return SUCCESS; +} + +/* Remove if there's nothing to do at request end */ +PHP_RSHUTDOWN_FUNCTION(phpcups) +{ + return SUCCESS; +} + + + +PHP_MINFO_FUNCTION(phpcups) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "phpcups support", "enabled"); + php_info_print_table_end(); + + /* Remove comments if you have entries in php.ini + DISPLAY_INI_ENTRIES(); + */ +} + + + + + + + +/* Remove the following function when you have succesfully modified config.m4 + so that your module can be compiled into PHP, it exists only for testing + purposes. */ + +/* Every user-visible function in PHP should document itself in the source */ +PHP_FUNCTION(confirm_phpcups_compiled) +{ + char *arg = NULL; + int arg_len, len; + char string[256]; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { + return; + } + + len = sprintf(string, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "phpcups", arg); + RETURN_STRINGL(string, len, 1); +} +/* The previous line is meant for vim and emacs, so it can correctly fold and + unfold functions in source code. See the corresponding marks just before + function definition, where the functions purpose is also documented. Please + follow this convention for the convenience of others editing your code. +*/ + + + + + + + + + + + +/* + * Function: cups_get_dest_options + * + * Date: 8 April 2002 - TDB + * + * Parameters: d_name - String - Name of destination. + * d_instance - String - Name of instance on destination. + * + * Returns: Array of option "objects", with each object + * containing the members: + * + * name - String - Option name + * value - String - Option value + * + * Comments: + * + */ +PHP_FUNCTION(cups_get_dest_options) +{ + char *arg = NULL; + int arg_len, len; + + zval *new_object; + + zval **d_server, + **d_name, + **d_instance; + + char c_server[256], + c_name[256], + c_instance[256]; + + char l_server[256], + l_name[256], + l_instance[256]; + + cups_dest_t *dests, *dptr; + int num_dests; + int i, j; + + array_init(return_value); + + if ((ZEND_NUM_ARGS() != 3) || + (zend_get_parameters_ex(3,&d_server,&d_name,&d_instance) != SUCCESS)) + { + WRONG_PARAM_COUNT; + } + + convert_to_string_ex( d_server ); + convert_to_string_ex( d_name ); + convert_to_string_ex( d_instance ); + + /* + * Find the dest/instance we want options for. + */ + bzero( c_server, 256 ); + bzero( c_name, 256 ); + bzero( c_instance, 256 ); + + if ( (char *)(*d_server)->value.str.val != NULL ) + strcpy( c_server,(char *)(*d_server)->value.str.val ); + if ( (char *)(*d_name)->value.str.val != NULL ) + strcpy( c_name,(char *)(*d_name)->value.str.val ); + if ( (char *)(*d_instance)->value.str.val != NULL ) + strcpy( c_instance,(char *)(*d_instance)->value.str.val ); + + + if (strlen(c_server)) + cupsSetServer(c_server); + + num_dests = cupsGetDests(&dests); + for (i=0, j = -1; (i < num_dests) && (j < 0); i++) + { + dptr = &dests[i]; + + if (dptr->name == NULL) + strcpy( l_name, "" ); + else + strcpy( l_name, dptr->name ); + + if (dptr->instance == NULL) + strcpy( l_instance, "" ); + else + strcpy( l_instance, dptr->instance ); + + if ((!strcmp( l_name, c_name )) && + (!strcmp( l_instance, c_instance ))) + { + + for (j=0; j < dptr->num_options; j++ ) + { + if ((dptr->options[j].name != NULL) && + (dptr->options[j].value != NULL)) + { + MAKE_STD_ZVAL(new_object); + if (object_init(new_object) == SUCCESS) + { + add_property_string(new_object,"name",dptr->options[j].name, 1 ); + add_property_string(new_object,"value",dptr->options[j].value,1); + add_next_index_zval( return_value, new_object ); + } + } + } + } + } + cupsFreeDests(num_dests,dests); +} + + + + +/* + * Function: cups_get_dest_list + * + * Date: 8 April 2002 - TDB + * + * Parameters: cups server (optional) + * + * Returns: Array of destination "objects", with each object + * containing the members: + * + * name - String - Name of destination. + * instance - String - Name of instance on destination. + * is_default - Long - 1 if default printer. + * num_options - Long - Number of options for destination. + * + * Comments: + * + */ +PHP_FUNCTION(cups_get_dest_list) +{ + char *arg = NULL; + int arg_len, len; + + zval **z_server; + zval *new_object; + + char c_server[256]; + + char string[2560]; + char temp[256]; + + cups_dest_t *dests, *dptr; + int num_dests; + int i; + + /* + * Initialize the return array. + */ + array_init(return_value); + + switch (ZEND_NUM_ARGS()) + { + /* + * Change servers if passed. + */ + case 1: if (zend_get_parameters_ex(1,&z_server) != SUCCESS) + { + WRONG_PARAM_COUNT; + } + convert_to_string_ex( z_server ); + if ( (char *)(*z_server)->value.str.val != NULL ) + { + strcpy( c_server,(char *)(*z_server)->value.str.val ); + cupsSetServer( c_server ); + } + break; + } + + + /* + * First get the destination list from the cups server. + */ + num_dests = cupsGetDests(&dests); + + /* + * Loop through the list, create and fill in the objects, and + * add them to the array. + */ + string[0] = '\0'; + for (i=0; i < num_dests; i++) + { + dptr = &dests[i]; + + MAKE_STD_ZVAL(new_object); + if (object_init(new_object) == SUCCESS) + { + if (strlen(c_server)) + add_property_string( new_object, "server", c_server, 1 ); + else + add_property_string( new_object, "server", "", 1 ); + + if (dptr->name != NULL) + add_property_string( new_object, "name", dptr->name, 1 ); + else + add_property_string( new_object, "name", "", 1 ); + + if (dptr->instance != NULL) + add_property_string( new_object, "instance", dptr->instance, 1 ); + else + add_property_string( new_object, "instance", "", 1 ); + + add_property_long( new_object, "is_default", dptr->is_default ); + add_property_long( new_object, "num_options", dptr->num_options ); + add_next_index_zval( return_value, new_object ); + } + } + + /* + * free the list ..... + */ + cupsFreeDests(num_dests,dests); +} + + + +/* + * Function: cups_get_jobs + * + * Date: 8 April 2002 - TDB + * + * Parameters: server - String - Name or IP of cups server. Blank + * for localhost. + * + * name - String - Name of destination to query. + * + * user - String - Username to get job list for. + * * Optional, default all users + * + * my_jobs - Long - Show only my jobs + * * Optional, default FALSE + * + * completed - Long - Show completed jobs + * * Optional, default FALSE + * + * Returns: Array of print job "objects", with each object + * containing the members: + * + * id - Long - Job id + * dest - String - Name of destination. + * title - String - Title of document. + * user - String - User who submitted job. + * format - String - Document format (MIME type) + * state - Long - Current state of the job. + * size - Long - Size in bytes of the job. + * priority - Long - Job priority. + * completed_time - Long - Time job completed (UNIX time). + * creation_time - Long - Time job created (UNIX time). + * processing_time- Long - Processing time in seconds? + * + * Comments: + * + */ +PHP_FUNCTION( cups_get_jobs ) +{ + char *arg = NULL; + + int arg_len, + len; + + zval *new_object; + + zval **z_server, + **z_name, + **z_user, + **z_myjobs, + **z_completed; + + char p_server[256], + p_name[256], + p_user[256]; + + int p_myjobs, + p_completed; + + cups_job_t *jobs, + *jptr; + + int num_jobs; + int i; + + bzero( p_server, 256 ); + bzero( p_name, 256 ); + bzero( p_user, 256 ); + p_myjobs = 0; + p_completed = 0; + + /* + * Initialize return value. + */ + array_init(return_value); + + /* + * Parse params. + */ + switch(ZEND_NUM_ARGS()) + { + /* + * server, destination only provided. + */ + case 2: + if (zend_get_parameters_ex( 2, &z_server,&z_name ) == SUCCESS) + { + convert_to_string_ex( z_server); + if ( (char *)(*z_server)->value.str.val != NULL ) + strcpy( p_server,(char *)(*z_server)->value.str.val ); + convert_to_string_ex( z_name ); + if ( (char *)(*z_name)->value.str.val != NULL ) + strcpy( p_name,(char *)(*z_name)->value.str.val ); + } + break; + + /* + * server, destination and user + */ + case 3: + if (zend_get_parameters_ex( 3, &z_server, &z_name, + &z_user ) == SUCCESS) + { + convert_to_string_ex( z_name ); + convert_to_string_ex( z_user ); + convert_to_string_ex( z_server); + if ( (char *)(*z_server)->value.str.val != NULL ) + strcpy( p_server,(char *)(*z_server)->value.str.val ); + if ( (char *)(*z_name)->value.str.val != NULL ) + strcpy( p_name,(char *)(*z_name)->value.str.val ); + if ( (char *)(*z_user)->value.str.val != NULL ) + strcpy( p_user,(char *)(*z_user)->value.str.val ); + } + break; + + /* + * server, destination, user, and myjobs + */ + case 4: + if (zend_get_parameters_ex( 4, &z_server, &z_name, &z_user, + &z_myjobs ) == SUCCESS) + { + convert_to_string_ex( z_name ); + convert_to_string_ex( z_user ); + convert_to_string_ex( z_server); + if ( (char *)(*z_server)->value.str.val != NULL ) + strcpy( p_server,(char *)(*z_server)->value.str.val ); + if ( (char *)(*z_name)->value.str.val != NULL ) + strcpy( p_name,(char *)(*z_name)->value.str.val ); + if ( (char *)(*z_user)->value.str.val != NULL ) + strcpy( p_user,(char *)(*z_user)->value.str.val ); + + convert_to_string_ex( z_myjobs ); + p_myjobs = strtoul((char *)(*z_myjobs)->value.str.val,NULL,10); + } + break; + + /* + * server, destination, user, myjobs, and completed + */ + case 5: + if (zend_get_parameters_ex( 5, &z_server, &z_name, &z_user, + &z_myjobs, &z_completed ) == SUCCESS) + { + convert_to_string_ex( z_name ); + convert_to_string_ex( z_user ); + convert_to_string_ex( z_server); + if ( (char *)(*z_server)->value.str.val != NULL ) + strcpy( p_server,(char *)(*z_server)->value.str.val ); + if ( (char *)(*z_name)->value.str.val != NULL ) + strcpy( p_name,(char *)(*z_name)->value.str.val ); + if ( (char *)(*z_user)->value.str.val != NULL ) + strcpy( p_user,(char *)(*z_user)->value.str.val ); + + convert_to_string_ex( z_myjobs ); + p_myjobs = strtoul((char *)(*z_myjobs)->value.str.val,NULL,10); + + convert_to_string_ex( z_completed); + p_completed = strtoul((char *)(*z_completed)->value.str.val,NULL,10); + } + break; + } + + /* + * Set the cups server if given. + */ + if (strlen(p_server)) + cupsSetServer(p_server); + + /* + * Set the cups user if given, otherwise get all jobs. + */ + if (strlen(p_user)) + cupsSetUser(p_user); + else + cupsSetUser("root"); + + /* + * Get the jobs list from the CUPS server. + */ + num_jobs = cupsGetJobs(&jobs,p_name,p_myjobs,p_completed); + + /* + * Build the array of objects to return. + */ + for (i=0; i < num_jobs; i++) + { + jptr = &jobs[i]; + + MAKE_STD_ZVAL(new_object); + if (object_init(new_object) == SUCCESS) + { + add_property_long(new_object,"id",jptr->id ); + add_property_string(new_object,"dest",jptr->dest, 1 ); + add_property_string(new_object,"title",jptr->title, 1 ); + add_property_string(new_object,"user",jptr->user, 1 ); + add_property_string(new_object,"format",jptr->format, 1 ); + add_property_long(new_object,"state",jptr->state ); + add_property_long(new_object,"size",jptr->size ); + add_property_long(new_object,"priority",jptr->priority ); + add_property_long(new_object,"completed_time",jptr->completed_time); + add_property_long(new_object,"creation_time",jptr->creation_time); + add_property_long(new_object,"processing_time",jptr->processing_time); + add_next_index_zval( return_value, new_object ); + } + else + { + printf("\nError creating new object\n"); + } + } + cupsFreeJobs(num_jobs,jobs); +} + + + + +/* + * Function: cups_last_error + * + * Date: 8 April 2002 - TDB + * + * Parameters: none. + * + * Returns: error number - Long + * + * Comments: + * + */ +PHP_FUNCTION(cups_last_error) +{ + static char error[1024]; + + zval **z_server; + char c_server[256]; + + bzero( c_server, 256 ); + + switch (ZEND_NUM_ARGS()) + { + /* + * Change servers if passed. + */ + case 1: if (zend_get_parameters_ex(1,&z_server) != SUCCESS) + { + WRONG_PARAM_COUNT; + } + convert_to_string_ex( z_server ); + if ( (char *)(*z_server)->value.str.val != NULL ) + { + strcpy( c_server,(char *)(*z_server)->value.str.val ); + cupsSetServer( c_server ); + } + break; + } + sprintf( error,"%d", cupsLastError()); + + RETURN_STRINGL(error, strlen(error)+1, 1); +} + + + + + + +/* + * Function: cups_cancel_job + * + * Date: 8 April 2002 - TDB + * + * Parameters: server - String - Name or IP of cups server. + * name - String - Name of destination. + * job - Long - Job ID to cancel. + * + * Returns: error number - Long????????? + * + * Comments: + * + */ +PHP_FUNCTION(cups_cancel_job) +{ + zval **z_server, **z_name, **z_job; + + char p_server[256], p_name[256]; + int p_job; + + int ret_val = -1; + + /* + * Get parameters ..... + */ + if ((ZEND_NUM_ARGS() != 3) || + (zend_get_parameters_ex( 3, &z_server, &z_name, &z_job ) != SUCCESS)) + { + WRONG_PARAM_COUNT; + } + + convert_to_string_ex( z_server); + if ( (char *)(*z_name)->value.str.val != NULL ) + { + strcpy( p_server,(char *)(*z_server)->value.str.val ); + cupsSetServer(p_server); + } + + convert_to_string_ex( z_name ); + if ( (char *)(*z_name)->value.str.val != NULL ) + strcpy( p_name,(char *)(*z_name)->value.str.val ); + + convert_to_string_ex( z_job ); + p_job = strtoul((char *)(*z_job)->value.str.val,NULL,10); + + if (strlen(p_server)) + cupsSetServer(p_server); + cupsSetUser("root"); + + /* + * Errrr .... Cancel the job ...... + */ + ret_val = cupsCancelJob(p_name,p_job); + + RETURN_LONG(ret_val); +} + + + +cups_option_t *_phpcups_parse_options( cups_option_t *options, + int *num_options, char *param ) +{ + char name[1024], value[1024]; + + sscanf(param,"%1023[^=]=%1023s", name, value ); + + if (strlen(name) && strlen(value)) + { + if (options == NULL) + { + options = (cups_option_t *)emalloc(sizeof(cups_option_t)); + options->name = (char *)emalloc(strlen(name)+1); + options->value = (char *)emalloc(strlen(value)+1); + strcpy( options->name, name ); + strcpy( options->value, value ); + *num_options++; + } + else + { + options = (cups_option_t *)erealloc(options, + (*num_options+1) * sizeof(cups_option_t)); + options[*num_options].name = (char *)emalloc(strlen(name)+1); + options[*num_options].value = (char *)emalloc(strlen(value)+1); + strcpy( options[*num_options].name, name ); + strcpy( options[*num_options].value, value ); + *num_options++; + } + } + return(options); +} + + +/* + * Function: cups_print_file + * + * Date: 8 April 2002 - TDB + * + * Parameters: printer - String - Name of destination. + * filename - String - Name of file to print (full path). + * title - String - Title of document. + * + * Returns: Job ID - Long + * + * Comments: + * + */ +PHP_FUNCTION(cups_print_file) +{ + zval **z_server, **z_printer, **z_filename, **z_title, + **z_options, **keydata; + + HashTable *param_ht; + + char p_server[256]; + char p_printer[256]; + char p_filename[256]; + char p_title[256]; + + char temp[4096]; + cups_option_t *options = NULL; + + int count, current; + int ret_val = -1; + + bzero( p_server, 256 ); + bzero( p_printer, 256 ); + bzero( p_filename, 256 ); + bzero( p_title, 256 ); + bzero( temp, 4096); + current = 0; + + int zend_num_args = ZEND_NUM_ARGS(); + switch (zend_num_args) + { + /* + * Server / Destination / filename only. + */ + case 3: + if (zend_get_parameters_ex( 3, &z_server, &z_printer, + &z_filename) != SUCCESS) + { + WRONG_PARAM_COUNT; + } + convert_to_string_ex( z_server); + if ( (char *)(*z_server)->value.str.val != NULL ) + { + strcpy( p_server,(char *)(*z_server)->value.str.val ); + cupsSetServer(p_server); + } + convert_to_string_ex( z_printer); + if ( (char *)(*z_printer)->value.str.val != NULL ) + strcpy( p_printer,(char *)(*z_printer)->value.str.val ); + convert_to_string_ex( z_filename ); + if ( (char *)(*z_filename)->value.str.val != NULL ) + strcpy( p_filename,(char *)(*z_filename)->value.str.val ); + strcpy( p_title,"untitled"); + break; + + /* + * Server, destination, filename and title. + */ + case 4: + if (zend_get_parameters_ex( 4, &z_server, + &z_printer, + &z_filename, + &z_title) != SUCCESS) + { + WRONG_PARAM_COUNT; + } + + convert_to_string_ex( z_server); + if ( (char *)(*z_server)->value.str.val != NULL ) + { + strcpy( p_server,(char *)(*z_server)->value.str.val ); + cupsSetServer(p_server); + } + + convert_to_string_ex( z_printer); + if ( (char *)(*z_printer)->value.str.val != NULL ) + strcpy( p_printer,(char *)(*z_printer)->value.str.val ); + + convert_to_string_ex( z_filename ); + if ( (char *)(*z_filename)->value.str.val != NULL ) + strcpy( p_filename,(char *)(*z_filename)->value.str.val ); + + convert_to_string_ex( z_title ); + if ( (char *)(*z_title)->value.str.val != NULL ) + strcpy( p_title,(char *)(*z_title)->value.str.val ); + + _zz_internal_log( "cups_print_file", p_server ); + _zz_internal_log( "cups_print_file", p_printer ); + _zz_internal_log( "cups_print_file", p_filename ); + _zz_internal_log( "cups_print_file", p_title ); + break; + + /* + * Server, destination, filename and title plus printer options. + */ + case 5: + if (zend_get_parameters_ex( 5, &z_server, + &z_printer, + &z_filename, + &z_title, + &z_options) != SUCCESS) + { + WRONG_PARAM_COUNT; + } + convert_to_string_ex( z_server); + if ( (char *)(*z_server)->value.str.val != NULL ) + { + strcpy( p_server,(char *)(*z_server)->value.str.val ); + cupsSetServer(p_server); + } + convert_to_string_ex( z_printer); + if ( (char *)(*z_printer)->value.str.val != NULL ) + strcpy( p_printer,(char *)(*z_printer)->value.str.val ); + convert_to_string_ex( z_filename ); + if ( (char *)(*z_filename)->value.str.val != NULL ) + strcpy( p_filename,(char *)(*z_filename)->value.str.val ); + convert_to_string_ex( z_title ); + if ( (char *)(*z_title)->value.str.val != NULL ) + strcpy( p_title,(char *)(*z_title)->value.str.val ); + + _zz_internal_log( "cups_print_file(server)", p_server ); + _zz_internal_log( "cups_print_file(printer)", p_printer ); + _zz_internal_log( "cups_print_file(filename)", p_filename ); + _zz_internal_log( "cups_print_file(title)", p_title ); + + /* + * Convert options array. + */ + convert_to_array_ex( z_options ); + param_ht = Z_ARRVAL_PP( z_options ); + count = zend_hash_num_elements( param_ht ); + options = emalloc(sizeof(zval **) * count); + + current = 0; + zend_hash_internal_pointer_reset(param_ht); + for (current=0; current < count; current++) + { + zend_hash_get_current_data(param_ht,(void **)&keydata); + switch(Z_TYPE_PP(keydata)) + { + case IS_STRING: + convert_to_string_ex(keydata); + strcpy(temp,(char *)(*keydata)->value.str.val ); + _zz_internal_log( "cups_print_file(option)", temp ); + options = _phpcups_parse_options( options, ¤t, + temp ); + break; + } + zend_hash_move_forward(param_ht); + } + break; + + default: WRONG_PARAM_COUNT; + } + + if (current > 0) + { + + bzero(temp,4096); + sprintf(temp,"(2) - P: %s F: %s T: %s C: %d", p_printer, p_filename, + p_title, current ); + _zz_internal_log( "cups_print_file", temp ); + ret_val = cupsPrintFile( p_printer,p_filename,p_title,current,options); + for (current=0; current < count; current++) + { + efree( options[current].name ); + efree( options[current].value ); + } + efree(options); + } + else + { + _zz_internal_log( "cups_print_file", "going to print"); + ret_val = cupsPrintFile( p_printer,p_filename,p_title,0,NULL ); + } + + RETURN_LONG(ret_val); +} + + +int _phpcups_get_printer_status(char *server, int port, char *name ); + +typedef struct printer_attrs_type +{ + char *name; + char *value; +} printer_attrs_t; + + + +int num_attrs = 0; +printer_attrs_t *printer_attrs = NULL; + +void free_attrs_list(void); +void _phpcups_free_attrs_list(void); + +/* + * Function: cups_get_printer_attributes + * + * Date: 8 April 2002 - TDB + * + * Parameters: name - String - Name of destination. + * + * Returns: state - String + * + * Comments: + * + */ +PHP_FUNCTION(cups_get_printer_attributes) +{ + zval **z_server, **z_port, **z_name; + + zval *new_object; + + char p_server[256], p_name[256]; + int p_port = 631; + + int i, count; + + + /* + * Initialize return value. + */ + array_init(return_value); + + /* + * Get parameters ..... + */ + switch(ZEND_NUM_ARGS()) + { + // + // Destination name only, assume localhost + // + case 1: + if (zend_get_parameters_ex( 1, &z_name ) != SUCCESS) + { + WRONG_PARAM_COUNT; + } + strcpy( p_server,"localhost" ); + convert_to_string_ex( z_name ); + if ( (char *)(*z_name)->value.str.val != NULL ) + strcpy( p_name,(char *)(*z_name)->value.str.val ); + break; + + // + // Server and estination name only, assume port 631 + // + case 2: + if (zend_get_parameters_ex( 2, &z_server, &z_name ) != SUCCESS) + { + WRONG_PARAM_COUNT; + } + convert_to_string_ex( z_server); + if ((char *)(*z_server)->value.str.val != NULL) + strcpy( p_server,(char *)(*z_server)->value.str.val ); + convert_to_string_ex( z_name ); + if ( (char *)(*z_name)->value.str.val != NULL ) + strcpy( p_name,(char *)(*z_name)->value.str.val ); + break; + + // + // Server, destination name and port. + // + case 3: + if(zend_get_parameters_ex(3,&z_server,&z_port,&z_name) != SUCCESS) + { + WRONG_PARAM_COUNT; + } + convert_to_string_ex(z_server); + if ((char *)(*z_server)->value.str.val != NULL) + strcpy( p_server,(char *)(*z_server)->value.str.val ); + convert_to_string_ex(z_name); + if ( (char *)(*z_name)->value.str.val != NULL ) + strcpy( p_name,(char *)(*z_name)->value.str.val ); + convert_to_string_ex(z_port); + if ( (char *)(*z_port)->value.str.val != NULL ) + p_port = atoi( (char *)(*z_name)->value.str.val ); + break; + + default: WRONG_PARAM_COUNT; + } + + printer_attrs = NULL; + count = _phpcups_get_printer_status( p_server, p_port, p_name ); + + /* + * Create an array of objects containing name / value pairs. + */ + for (i=0; i < count; i++) + { + if ((printer_attrs[i].name != NULL) && (printer_attrs[i].value != NULL)) + { + MAKE_STD_ZVAL(new_object); + if (object_init(new_object) == SUCCESS) + { + add_property_string(new_object,"name",printer_attrs[i].name, 1 ); + add_property_string(new_object,"value",printer_attrs[i].value, 1 ); + add_next_index_zval( return_value, new_object ); + } + } + } + _phpcups_free_attrs_list(); +} + + + + +void _phpcups_free_attrs_list(void) +{ + int i; + + if (num_attrs < 1) + return; + + for ( i=0; i < num_attrs; i++ ) + { + if (printer_attrs[i].name != NULL) + efree(printer_attrs[i].name); + if (printer_attrs[i].value != NULL) + efree(printer_attrs[i].value ); + } + efree(printer_attrs); + num_attrs = 0; +} + + + + + + + +int _phpcups_update_attrs_list( char *name, char *value ) +{ + if (num_attrs < 1) + { + printer_attrs = (printer_attrs_t *)emalloc(sizeof(printer_attrs_t)); + printer_attrs->name = (char *)emalloc(strlen(name)+1); + printer_attrs->value = (char *)emalloc(strlen(value)+1); + strcpy( printer_attrs->name, name ); + strcpy( printer_attrs->value, value ); + num_attrs = 1; + } + else + { + printer_attrs = (printer_attrs_t *)erealloc(printer_attrs, + (num_attrs + 1) * sizeof(printer_attrs_t)); + + printer_attrs[num_attrs].name = (char *)emalloc(strlen(name)+1); + printer_attrs[num_attrs].value = (char *)emalloc(strlen(value)+1); + strcpy( printer_attrs[num_attrs].name, name ); + strcpy( printer_attrs[num_attrs].value, value ); + num_attrs++; + } + return(num_attrs); +} + + + +int _phpcups_get_printer_status( char *server, int port, char *name ) +{ + http_encryption_t encrypt = HTTP_ENCRYPT_IF_REQUESTED; + + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + cups_lang_t *language; /* Default language */ + + char printer_uri[1024]; + char temp[1024]; + static char *req_attrs[] = {"printer-state", "printer-state-reason" }; + int i; + FILE *fp; + + if (name == NULL) + { + last_error = IPP_INTERNAL_ERROR; + return (0); + } + + /* + * Try to connect to the server... + */ + + if ((cups_server = httpConnectEncrypt(server, port, encrypt)) == 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 = IPP_GET_PRINTER_ATTRIBUTES; + request->request.op.request_id = 1; + + language = cupsLangDefault(); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, + "attributes-charset", NULL, cupsLangEncoding(language)); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, + "attributes-natural-language", NULL, language->language); + + sprintf(printer_uri, "ipp://localhost/printers/%-s", name ); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, printer_uri ); + + /* + * Do the request and get back a response... + */ + + num_attrs = 0; + printer_attrs = 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->num_values < 1) + continue; + + if (attr->name != NULL && + strcasecmp(attr->name, "printer-state") == 0 && + attr->value_tag == IPP_TAG_ENUM) + { + strcpy( temp, "unknown" ); + switch( attr->values[0].integer ) + { + case 3: strcpy( temp, "idle" ); + break; + case 4: strcpy( temp, "processing" ); + break; + case 5: strcpy( temp, "stopped" ); + break; + default: continue; + } + _phpcups_update_attrs_list( attr->name, temp ); + } + else if (attr->name != NULL && + (attr->value_tag == IPP_TAG_TEXT || + attr->value_tag == IPP_TAG_URI || + attr->value_tag == IPP_TAG_KEYWORD || + attr->value_tag == IPP_TAG_STRING)) + { + for (i=0; i < attr->num_values; i++) + _phpcups_update_attrs_list(attr->name, attr->values[i].string.text ); + } + else if (attr->name != NULL && + (attr->value_tag == IPP_TAG_ENUM || + attr->value_tag == IPP_TAG_BOOLEAN || + attr->value_tag == IPP_TAG_INTEGER)) + { + for (i=0; i < attr->num_values; i++) + { + sprintf(temp,"%-d", attr->values[i].integer ); + _phpcups_update_attrs_list(attr->name, temp ); + } + } + else if (attr->name != NULL && + attr->value_tag == IPP_TAG_RESOLUTION) + { + for (i=0; i < attr->num_values; i++) + { + sprintf(temp,"%-dx%-dx%-d", + attr->values[i].resolution.xres, + attr->values[i].resolution.yres, + attr->values[i].resolution.units ); + _phpcups_update_attrs_list(attr->name, temp ); + } + } + else if (attr->name != NULL && + attr->value_tag == IPP_TAG_RANGE) + { + for (i=0; i < attr->num_values; i++) + { + sprintf(temp,"%d-%d", + attr->values[i].range.lower, + attr->values[i].range.upper ); + _phpcups_update_attrs_list(attr->name, temp ); + } + } + } + ippDelete(response); + } + else + { + last_error = IPP_BAD_REQUEST; + return(0); + } + return (num_attrs); +} + + +void _zz_internal_log( char *func, char *line ) +{ + FILE *fp; + + if ((fp = fopen("/var/log/cups/project.log","a")) == NULL) + return; + + fprintf(fp,"phpcups: %s - %s\n", func, line ); + fflush(fp); + fclose(fp); +} + + + +/* + * End of "$Id: phpcups.c 4530 2005-06-01 20:15:51Z mike $". + */ + + +/* + */ diff --git a/scripting/php/phpcups.php b/scripting/php/phpcups.php new file mode 100644 index 000000000..01ce6a8fc --- /dev/null +++ b/scripting/php/phpcups.php @@ -0,0 +1,53 @@ +\n"; + +foreach($functions as $func) { + echo $func."
    \n"; +} +echo "
    \n"; + +$function = 'confirm_' . $module . '_compiled'; +if (extension_loaded($module)) { + $str = $function($module); +} else { + $str = "Module $module is not compiled into PHP"; +} +echo "$str\n"; + +// +// End of "$Id: phpcups.php 3603 2003-04-11 18:42:52Z mike $". +// +?> diff --git a/standards/pwg5100.1.pdf b/standards/pwg5100.1.pdf new file mode 100644 index 0000000000000000000000000000000000000000..80260170f61d93fecc776cc63638c89364eeeb69 GIT binary patch literal 37359 zc-p+XRdD6Zk}Yg(Gh?@znQ@z$nVGklvCZsmGcz-_nVFfHnVH#c|9!qVXXeh#_un`V z6E{K+Rhg1X%9K{ES}Bn!h=|cK(K8bwknQeG%^|=NA}}!#G7{PuSt9W8ATY=PZOxp` z37MGx*pv_$#4N0xfsTX>V%CPvKoOv^oe7W-fsYTt$=MNTXoCPN5o#0NgBZYwEYg+p z$tW&c(3lv2i@|ua--F+QEYNLG4$1cXfO&7uzA_L?lvp(2DmSc@_2 zIMf}CHYFD{%Jhh3nj);5vG4Hd1`(}DE^_apNT0v3^euhOAieC;A#I=-0AcLq@10h( ze6~CD;M!d?}!DX6{VL#K?-kAY|d}qyTgjwzILfvjy5Z6LKOj2-{iPIV#&58UqQn{|sPj z0{jj%A!HB%x>^_mmBfVznc3I~IscI{Lf!vNA>&^u{4dEmSLZdy(Z=koFgT3zV9RF| z1)~>(=dowfyvCj#hK?ww!`M%V{^814ngH5ojH4NiZZRu)Mjj(1bF*zYAo_g(+uuIE zcR*rww;@duqrhnDBfW)$;x-~qw{ANSS64UEcG9iOsncoF^1%S<@xN@JvN&(NSIq~U z@;G!)*+Gy*)Oj$l|J+hWk<96^i+P3wdbb z9qYZ1S9{ofdu;aWD7BQ4q14xaAf+9%tk}tvKMbdg+EqoDrRa210Dmp|Bw51jF<-ul zU$RFJ(#Az@OZj0qiiaYh>OKE$U4Tfx_9$t0%iPQL8o@=g-E+xTyu*KheR3GnIlZVd zKP-JQyk(mtMU|O0{Q1iUX*v52Tf8FN5(qk2hL(o^)FhE?xfK^*uhN#+m zpsg#`i+rl4#Y|BGO2Ie2`zGp*TnI#r_QMG8_tLlwaE9k{Qm8BVyDa8P3oYXJ6v)EI z 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 literal 0 Hc-jL100001 diff --git a/standards/pwg5100.2.pdf b/standards/pwg5100.2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6b0ad3abc6f11c1ed5f8c23a97244ab64634df84 GIT binary patch literal 37360 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 literal 0 Hc-jL100001 diff --git a/standards/pwg5100.3.pdf b/standards/pwg5100.3.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0ac46446f8be2990b43052c2c40e6048035c57ac GIT binary patch literal 262279 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�P5U;Mcysgz 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 literal 0 Hc-jL100001 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 . + + 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 +#include +#include +#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/rfc2222.txt b/standards/rfc2222.txt new file mode 100644 index 000000000..2b0a2abc1 --- /dev/null +++ b/standards/rfc2222.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group J. Myers +Request for Comments: 2222 Netscape Communications +Category: Standards Track October 1997 + + + Simple Authentication and Security Layer (SASL) + +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 (1997). All Rights Reserved. + +Table of Contents + + 1. Abstract .............................................. 2 + 2. Organization of this Document ......................... 2 + 2.1. How to Read This Document ............................. 2 + 2.2. Conventions Used in this Document ..................... 2 + 2.3. Examples .............................................. 3 + 3. Introduction and Overview ............................. 3 + 4. Profiling requirements ................................ 4 + 5. Specific issues ....................................... 5 + 5.1. Client sends data first ............................... 5 + 5.2. Server returns success with additional data ........... 5 + 5.3. Multiple authentications .............................. 5 + 6. Registration procedures ............................... 6 + 6.1. Comments on SASL mechanism registrations .............. 6 + 6.2. Location of Registered SASL Mechanism List ............ 6 + 6.3. Change Control ........................................ 7 + 6.4. Registration Template ................................. 7 + 7. Mechanism definitions ................................. 8 + 7.1. Kerberos version 4 mechanism .......................... 8 + 7.2. GSSAPI mechanism ...................................... 9 + 7.2.1 Client side of authentication protocol exchange ....... 9 + 7.2.2 Server side of authentication protocol exchange ....... 10 + 7.2.3 Security layer ........................................ 11 + 7.3. S/Key mechanism ....................................... 11 + 7.4. External mechanism .................................... 12 + 8. References ............................................ 13 + 9. Security Considerations ............................... 13 + 10. Author's Address ...................................... 14 + + + +Myers Standards Track [Page 1] + +RFC 2222 SASL October 1997 + + + Appendix A. Relation of SASL to Transport Security .......... 15 + Full Copyright Statement .................................... 16 + +1. Abstract + + This document describes a method for adding authentication support to + connection-based protocols. To use this specification, a protocol + includes a command for identifying and authenticating a user to a + server and for optionally negotiating protection of subsequent + protocol interactions. If its use is negotiated, a security layer is + inserted between the protocol and the connection. This document + describes how a protocol specifies such a command, defines several + mechanisms for use by the command, and defines the protocol used for + carrying a negotiated security layer over the connection. + +2. Organization of this Document + +2.1. How to Read This Document + + This document is written to serve two different audiences, protocol + designers using this specification to support authentication in their + protocol, and implementors of clients or servers for those protocols + using this specification. + + The sections "Introduction and Overview", "Profiling requirements", + and "Security Considerations" cover issues that protocol designers + need to understand and address in profiling this specification for + use in a specific protocol. + + Implementors of a protocol using this specification need the + protocol-specific profiling information in addition to the + information in this document. + +2.2. Conventions Used in this Document + + In examples, "C:" and "S:" indicate lines sent by the client and + server respectively. + + The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" + in this document are to be interpreted as defined in "Key words for + use in RFCs to Indicate Requirement Levels" [RFC 2119]. + + + + + + + + + + +Myers Standards Track [Page 2] + +RFC 2222 SASL October 1997 + + +2.3. Examples + + Examples in this document are for the IMAP profile [RFC 2060] of this + specification. The base64 encoding of challenges and responses, as + well as the "+ " preceding the responses are part of the IMAP4 + profile, not part of the SASL specification itself. + +3. Introduction and Overview + + The Simple Authentication and Security Layer (SASL) is a method for + adding authentication support to connection-based protocols. To use + this specification, a protocol includes a command for identifying and + authenticating a user to a server and for optionally negotiating a + security layer for subsequent protocol interactions. + + The command has a required argument identifying a SASL mechanism. + SASL mechanisms are named by strings, from 1 to 20 characters in + length, consisting of upper-case letters, digits, hyphens, and/or + underscores. SASL mechanism names must be registered with the IANA. + Procedures for registering new SASL mechanisms are given in the + section "Registration procedures" + + If a server supports the requested mechanism, it initiates an + authentication protocol exchange. This consists of a series of + server challenges and client responses that are specific to the + requested mechanism. The challenges and responses are defined by the + mechanisms as binary tokens of arbitrary length. The protocol's + profile then specifies how these binary tokens are then encoded for + transfer over the connection. + + After receiving the authentication command or any client response, a + server may issue a challenge, indicate failure, or indicate + completion. The protocol's profile specifies how the server + indicates which of the above it is doing. + + After receiving a challenge, a client may issue a response or abort + the exchange. The protocol's profile specifies how the client + indicates which of the above it is doing. + + During the authentication protocol exchange, the mechanism performs + authentication, transmits an authorization identity (frequently known + as a userid) from the client to server, and negotiates the use of a + mechanism-specific security layer. If the use of a security layer is + agreed upon, then the mechanism must also define or negotiate the + maximum cipher-text buffer size that each side is able to receive. + + + + + + +Myers Standards Track [Page 3] + +RFC 2222 SASL October 1997 + + + The transmitted authorization identity may be different than the + identity in the client's authentication credentials. This permits + agents such as proxy servers to authenticate using their own + credentials, yet request the access privileges of the identity for + which they are proxying. With any mechanism, transmitting an + authorization identity of the empty string directs the server to + derive an authorization identity from the client's authentication + credentials. + + If use of a security layer is negotiated, it is applied to all + subsequent data sent over the connection. The security layer takes + effect immediately following the last response of the authentication + exchange for data sent by the client and the completion indication + for data sent by the server. Once the security layer is in effect, + the protocol stream is processed by the security layer into buffers + of cipher-text. Each buffer is transferred over the connection as a + stream of octets prepended with a four octet field in network byte + order that represents the length of the following buffer. The length + of the cipher-text buffer must be no larger than the maximum size + that was defined or negotiated by the other side. + +4. Profiling requirements + + In order to use this specification, a protocol definition must supply + the following information: + + 1. A service name, to be selected from the IANA registry of "service" + elements for the GSSAPI host-based service name form [RFC 2078]. + + 2. A definition of the command to initiate the authentication + protocol exchange. This command must have as a parameter the + mechanism name being selected by the client. + + The command SHOULD have an optional parameter giving an initial + response. This optional parameter allows the client to avoid a + round trip when using a mechanism which is defined to have the + client send data first. When this initial response is sent by the + client and the selected mechanism is defined to have the server + start with an initial challenge, the command fails. See section + 5.1 of this document for further information. + + 3. A definition of the method by which the authentication protocol + exchange is carried out, including how the challenges and + responses are encoded, how the server indicates completion or + failure of the exchange, how the client aborts an exchange, and + how the exchange method interacts with any line length limits in + the protocol. + + + + +Myers Standards Track [Page 4] + +RFC 2222 SASL October 1997 + + + 4. Identification of the octet where any negotiated security layer + starts to take effect, in both directions. + + 5. A specification of how the authorization identity passed from the + client to the server is to be interpreted. + +5. Specific issues + +5.1. Client sends data first + + Some mechanisms specify that the first data sent in the + authentication protocol exchange is from the client to the server. + + If a protocol's profile permits the command which initiates an + authentication protocol exchange to contain an initial client + response, this parameter SHOULD be used with such mechanisms. + + If the initial client response parameter is not given, or if a + protocol's profile does not permit the command which initiates an + authentication protocol exchange to contain an initial client + response, then the server issues a challenge with no data. The + client's response to this challenge is then used as the initial + client response. (The server then proceeds to send the next + challenge, indicates completion, or indicates failure.) + +5.2. Server returns success with additional data + + Some mechanisms may specify that server challenge data be sent to the + client along with an indication of successful completion of the + exchange. This data would, for example, authenticate the server to + the client. + + If a protocol's profile does not permit this server challenge to be + returned with a success indication, then the server issues the server + challenge without an indication of successful completion. The client + then responds with no data. After receiving this empty response, the + server then indicates successful completion. + +5.3. Multiple authentications + + Unless otherwise stated by the protocol's profile, only one + successful SASL negotiation may occur in a protocol session. In this + case, once an authentication protocol exchange has successfully + completed, further attempts to initiate an authentication protocol + exchange fail. + + + + + + +Myers Standards Track [Page 5] + +RFC 2222 SASL October 1997 + + + In the case that a profile explicitly permits multiple successful + SASL negotiations to occur, then in no case may multiple security + layers be simultaneously in effect. If a security layer is in effect + and a subsequent SASL negotiation selects no security layer, the + original security layer remains in effect. If a security layer is in + effect and a subsequent SASL negotiation selects a second security + layer, then the second security layer replaces the first. + +6. Registration procedures + + Registration of a SASL mechanism is done by filling in the template + in section 6.4 and sending it in to iana@isi.edu. IANA has the right + to reject obviously bogus registrations, but will perform no review + of clams made in the registration form. + + There is no naming convention for SASL mechanisms; any name that + conforms to the syntax of a SASL mechanism name can be registered. + + While the registration procedures do not require it, authors of SASL + mechanisms are encouraged to seek community review and comment + whenever that is feasible. Authors may seek community review by + posting a specification of their proposed mechanism as an internet- + draft. SASL mechanisms intended for widespread use should be + standardized through the normal IETF process, when appropriate. + +6.1. Comments on SASL mechanism registrations + + Comments on registered SASL mechanisms should first be sent to the + "owner" of the mechanism. Submitters of comments may, after a + reasonable attempt to contact the owner, request IANA to attach their + comment to the SASL mechanism registration itself. If IANA approves + of this the comment will be made accessible in conjunction with the + SASL mechanism registration itself. + +6.2. Location of Registered SASL Mechanism List + + SASL mechanism registrations will be posted in the anonymous FTP + directory "ftp://ftp.isi.edu/in-notes/iana/assignments/sasl- + mechanisms/" and all registered SASL mechanisms will be listed in the + periodically issued "Assigned Numbers" RFC [currently STD 2, RFC + 1700]. The SASL mechanism description and other supporting material + may also be published as an Informational RFC by sending it to "rfc- + editor@isi.edu" (please follow the instructions to RFC authors [RFC + 2223]). + + + + + + + +Myers Standards Track [Page 6] + +RFC 2222 SASL October 1997 + + +6.3. Change Control + + Once a SASL mechanism registration has been published by IANA, the + author may request a change to its definition. The change request + follows the same procedure as the registration request. + + The owner of a SASL mechanism may pass responsibility for the SASL + mechanism to another person or agency by informing IANA; this can be + done without discussion or review. + + The IESG may reassign responsibility for a SASL mechanism. The most + common case of this will be to enable changes to be made to + mechanisms where the author of the registration has died, moved out + of contact or is otherwise unable to make changes that are important + to the community. + + SASL mechanism registrations may not be deleted; mechanisms which are + no longer believed appropriate for use can be declared OBSOLETE by a + change to their "intended use" field; such SASL mechanisms will be + clearly marked in the lists published by IANA. + + The IESG is considered to be the owner of all SASL mechanisms which + are on the IETF standards track. + +6.4. Registration Template + + To: iana@iana.org + Subject: Registration of SASL mechanism X + + SASL mechanism name: + + Security considerations: + + Published specification (optional, recommended): + + Person & email address to contact for further information: + + Intended usage: + + (One of COMMON, LIMITED USE or OBSOLETE) + + Author/Change controller: + + (Any other information that the author deems interesting may be + added below this line.) + + + + + + +Myers Standards Track [Page 7] + +RFC 2222 SASL October 1997 + + +7. Mechanism definitions + + The following mechanisms are hereby defined. + +7.1. Kerberos version 4 mechanism + + The mechanism name associated with Kerberos version 4 is + "KERBEROS_V4". + + The first challenge consists of a random 32-bit number in network + byte order. The client responds with a Kerberos ticket and an + authenticator for the principal "service.hostname@realm", where + "service" is the service name specified in the protocol's profile, + "hostname" is the first component of the host name of the server with + all letters in lower case, and where "realm" is the Kerberos realm of + the server. The encrypted checksum field included within the + Kerberos authenticator contains the server provided challenge in + network byte order. + + Upon decrypting and verifying the ticket and authenticator, the + server verifies that the contained checksum field equals the original + server provided random 32-bit number. Should the verification be + successful, the server must add one to the checksum and construct 8 + octets of data, with the first four octets containing the incremented + checksum in network byte order, the fifth octet containing a bit-mask + specifying the security layers supported by the server, and the sixth + through eighth octets containing, in network byte order, the maximum + cipher-text buffer size the server is able to receive. The server + must encrypt using DES ECB mode the 8 octets of data in the session + key and issue that encrypted data in a second challenge. The client + considers the server authenticated if the first four octets of the + un-encrypted data is equal to one plus the checksum it previously + sent. + + The client must construct data with the first four octets containing + the original server-issued checksum in network byte order, the fifth + octet containing the bit-mask specifying the selected security layer, + the sixth through eighth octets containing in network byte order the + maximum cipher-text buffer size the client is able to receive, and + the following octets containing the authorization identity. The + client must then append from one to eight zero-valued octets so that + the length of the data is a multiple of eight octets. The client must + then encrypt using DES PCBC mode the data with the session key and + respond with the encrypted data. The server decrypts the data and + verifies the contained checksum. The server must verify that the + principal identified in the Kerberos ticket is authorized to connect + as that authorization identity. After this verification, the + authentication process is complete. + + + +Myers Standards Track [Page 8] + +RFC 2222 SASL October 1997 + + + The security layers and their corresponding bit-masks are as follows: + + 1 No security layer + 2 Integrity (krb_mk_safe) protection + 4 Privacy (krb_mk_priv) protection + + Other bit-masks may be defined in the future; bits which are not + understood must be negotiated off. + + EXAMPLE: The following are two Kerberos version 4 login scenarios to + the IMAP4 protocol (note that the line breaks in the sample + authenticators are for editorial clarity and are not in real + authenticators) + + S: * OK IMAP4 Server + C: A001 AUTHENTICATE KERBEROS_V4 + S: + AmFYig== + C: BAcAQU5EUkVXLkNNVS5FRFUAOCAsho84kLN3/IJmrMG+25a4DT + +nZImJjnTNHJUtxAA+o0KPKfHEcAFs9a3CL5Oebe/ydHJUwYFd + WwuQ1MWiy6IesKvjL5rL9WjXUb9MwT9bpObYLGOKi1Qh + S: + or//EoAADZI= + C: DiAF5A4gA+oOIALuBkAAmw== + S: A001 OK Kerberos V4 authentication successful + + + S: * OK IMAP4 Server + C: A001 AUTHENTICATE KERBEROS_V4 + S: + gcfgCA== + C: BAcAQU5EUkVXLkNNVS5FRFUAOCAsho84kLN3/IJmrMG+25a4DT + +nZImJjnTNHJUtxAA+o0KPKfHEcAFs9a3CL5Oebe/ydHJUwYFd + WwuQ1MWiy6IesKvjL5rL9WjXUb9MwT9bpObYLGOKi1Qh + S: A001 NO Kerberos V4 authentication failed + +7.2. GSSAPI mechanism + + The mechanism name associated with all mechanisms employing the + GSSAPI [RFC 2078] is "GSSAPI". + +7.2.1 Client side of authentication protocol exchange + + The client calls GSS_Init_sec_context, passing in 0 for + input_context_handle (initially) and a targ_name equal to output_name + from GSS_Import_Name called with input_name_type of + GSS_C_NT_HOSTBASED_SERVICE and input_name_string of + "service@hostname" where "service" is the service name specified in + the protocol's profile, and "hostname" is the fully qualified host + name of the server. The client then responds with the resulting + output_token. If GSS_Init_sec_context returns GSS_S_CONTINUE_NEEDED, + + + +Myers Standards Track [Page 9] + +RFC 2222 SASL October 1997 + + + then the client should expect the server to issue a token in a + subsequent challenge. The client must pass the token to another call + to GSS_Init_sec_context, repeating the actions in this paragraph. + + When GSS_Init_sec_context returns GSS_S_COMPLETE, the client takes + the following actions: If the last call to GSS_Init_sec_context + returned an output_token, then the client responds with the + output_token, otherwise the client responds with no data. The client + should then expect the server to issue a token in a subsequent + challenge. The client passes this token to GSS_Unwrap and interprets + the first octet of resulting cleartext as a bit-mask specifying the + security layers supported by the server and the second through fourth + octets as the maximum size output_message to send to the server. The + client then constructs data, with the first octet containing the + bit-mask specifying the selected security layer, the second through + fourth octets containing in network byte order the maximum size + output_message the client is able to receive, and the remaining + octets containing the authorization identity. The client passes the + data to GSS_Wrap with conf_flag set to FALSE, and responds with the + generated output_message. The client can then consider the server + authenticated. + +7.2.2 Server side of authentication protocol exchange + + The server passes the initial client response to + GSS_Accept_sec_context as input_token, setting input_context_handle + to 0 (initially). If GSS_Accept_sec_context returns + GSS_S_CONTINUE_NEEDED, the server returns the generated output_token + to the client in challenge and passes the resulting response to + another call to GSS_Accept_sec_context, repeating the actions in this + paragraph. + + When GSS_Accept_sec_context returns GSS_S_COMPLETE, the client takes + the following actions: If the last call to GSS_Accept_sec_context + returned an output_token, the server returns it to the client in a + challenge and expects a reply from the client with no data. Whether + or not an output_token was returned (and after receipt of any + response from the client to such an output_token), the server then + constructs 4 octets of data, with the first octet containing a bit- + mask specifying the security layers supported by the server and the + second through fourth octets containing in network byte order the + maximum size output_token the server is able to receive. The server + must then pass the plaintext to GSS_Wrap with conf_flag set to FALSE + and issue the generated output_message to the client in a challenge. + The server must then pass the resulting response to GSS_Unwrap and + interpret the first octet of resulting cleartext as the bit-mask for + the selected security layer, the second through fourth octets as the + maximum size output_message to send to the client, and the remaining + + + +Myers Standards Track [Page 10] + +RFC 2222 SASL October 1997 + + + octets as the authorization identity. The server must verify that + the src_name is authorized to authenticate as the authorization + identity. After these verifications, the authentication process is + complete. + +7.2.3 Security layer + + The security layers and their corresponding bit-masks are as follows: + + 1 No security layer + 2 Integrity protection. + Sender calls GSS_Wrap with conf_flag set to FALSE + 4 Privacy protection. + Sender calls GSS_Wrap with conf_flag set to TRUE + + Other bit-masks may be defined in the future; bits which are not + understood must be negotiated off. + +7.3. S/Key mechanism + + The mechanism name associated with S/Key [RFC 1760] using the MD4 + digest algorithm is "SKEY". + + The client sends an initial response with the authorization identity. + + The server then issues a challenge which contains the decimal + sequence number followed by a single space and the seed string for + the indicated authorization identity. The client responds with the + one-time-password, as either a 64-bit value in network byte order or + encoded in the "six English words" format. + + The server must verify the one-time-password. After this + verification, the authentication process is complete. + + S/Key authentication does not provide for any security layers. + + EXAMPLE: The following are two S/Key login scenarios in the IMAP4 + protocol. + + S: * OK IMAP4 Server + C: A001 AUTHENTICATE SKEY + S: + + C: bW9yZ2Fu + S: + OTUgUWE1ODMwOA== + C: Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA== + S: A001 OK S/Key authentication successful + + + + + +Myers Standards Track [Page 11] + +RFC 2222 SASL October 1997 + + + S: * OK IMAP4 Server + C: A001 AUTHENTICATE SKEY + S: + + C: c21pdGg= + S: + OTUgUWE1ODMwOA== + C: BsAY3g4gBNo= + S: A001 NO S/Key authentication failed + + The following is an S/Key login scenario in an IMAP4-like protocol + which has an optional "initial response" argument to the AUTHENTICATE + command. + + S: * OK IMAP4-Like Server + C: A001 AUTHENTICATE SKEY bW9yZ2Fu + S: + OTUgUWE1ODMwOA== + C: Rk9VUiBNQU5OIFNPT04gRklSIFZBUlkgTUFTSA== + S: A001 OK S/Key authentication successful + +7.4. External mechanism + + The mechanism name associated with external authentication is + "EXTERNAL". + + The client sends an initial response with the authorization identity. + + The server uses information, external to SASL, to determine whether + the client is authorized to authenticate as the authorization + identity. If the client is so authorized, the server indicates + successful completion of the authentication exchange; otherwise the + server indicates failure. + + The system providing this external information may be, for example, + IPsec or TLS. + + If the client sends the empty string as the authorization identity + (thus requesting the authorization identity be derived from the + client's authentication credentials), the authorization identity is + to be derived from authentication credentials which exist in the + system which is providing the external authentication. + + + + + + + + + + + + +Myers Standards Track [Page 12] + +RFC 2222 SASL October 1997 + + +8. References + + [RFC 2060] Crispin, M., "Internet Message Access Protocol - Version + 4rev1", RFC 2060, December 1996. + + [RFC 2078] Linn, J., "Generic Security Service Application Program + Interface, Version 2", RFC 2078, January 1997. + + [RFC 2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", RFC 2119, March 1997. + + [RFC 2223] Postel, J., and J. Reynolds, "Instructions to RFC + Authors", RFC 2223, October 1997. + + [RFC 1760] Haller, N., "The S/Key One-Time Password System", RFC + 1760, February 1995. + + [RFC 1700] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, + RFC 1700, October 1994. + +9. Security Considerations + + Security issues are discussed throughout this memo. + + The mechanisms that support integrity protection are designed such + that the negotiation of the security layer and authorization identity + is integrity protected. When the client selects a security layer + with at least integrity protection, this protects against an active + attacker hijacking the connection and modifying the authentication + exchange to negotiate a plaintext connection. + + When a server or client supports multiple authentication mechanisms, + each of which has a different security strength, it is possible for + an active attacker to cause a party to use the least secure mechanism + supported. To protect against this sort of attack, a client or + server which supports mechanisms of different strengths should have a + configurable minimum strength that it will use. It is not sufficient + for this minimum strength check to only be on the server, since an + active attacker can change which mechanisms the client sees as being + supported, causing the client to send authentication credentials for + its weakest supported mechanism. + + + + + + + + + + +Myers Standards Track [Page 13] + +RFC 2222 SASL October 1997 + + + The client's selection of a SASL mechanism is done in the clear and + may be modified by an active attacker. It is important for any new + SASL mechanisms to be designed such that an active attacker cannot + obtain an authentication with weaker security properties by modifying + the SASL mechanism name and/or the challenges and responses. + + Any protocol interactions prior to authentication are performed in + the clear and may be modified by an active attacker. In the case + where a client selects integrity protection, it is important that any + security-sensitive protocol negotiations be performed after + authentication is complete. Protocols should be designed such that + negotiations performed prior to authentication should be either + ignored or revalidated once authentication is complete. + +10. Author's Address + + John G. Myers + Netscape Communications + 501 E. Middlefield Road + Mail Stop MV-029 + Mountain View, CA 94043-4042 + + EMail: jgmyers@netscape.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Myers Standards Track [Page 14] + +RFC 2222 SASL October 1997 + + +Appendix A. Relation of SASL to Transport Security + + Questions have been raised about the relationship between SASL and + various services (such as IPsec and TLS) which provide a secured + connection. + + Two of the key features of SASL are: + + 1. The separation of the authorization identity from the identity in + the client's credentials. This permits agents such as proxy + servers to authenticate using their own credentials, yet request + the access privileges of the identity for which they are proxying. + + 2. Upon successful completion of an authentication exchange, the + server knows the authorization identity the client wishes to use. + This allows servers to move to a "user is authenticated" state in + the protocol. + + These features are extremely important to some application protocols, + yet Transport Security services do not always provide them. To + define SASL mechanisms based on these services would be a very messy + task, as the framing of these services would be redundant with the + framing of SASL and some method of providing these important SASL + features would have to be devised. + + Sometimes it is desired to enable within an existing connection the + use of a security service which does not fit the SASL model. (TLS is + an example of such a service.) This can be done by adding a command, + for example "STARTTLS", to the protocol. Such a command is outside + the scope of SASL, and should be different from the command which + starts a SASL authentication protocol exchange. + + In certain situations, it is reasonable to use SASL underneath one of + these Transport Security services. The transport service would + secure the connection, either service would authenticate the client, + and SASL would negotiate the authorization identity. The SASL + negotiation would be what moves the protocol from "unauthenticated" + to "authenticated" state. The "EXTERNAL" SASL mechanism is + explicitly intended to handle the case where the transport service + secures the connection and authenticates the client and SASL + negotiates the authorization identity. + + When using SASL underneath a sufficiently strong Transport Security + service, a SASL security layer would most likely be redundant. The + client and server would thus probably want to negotiate off the use + of a SASL security layer. + + + + + +Myers Standards Track [Page 15] + +RFC 2222 SASL October 1997 + + +Full Copyright Statement + + Copyright (C) The Internet Society (1997). 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 implmentation may be prepared, copied, published + andand 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. + + + + + + + + + + + + + + + + + + + + + + + + +Myers Standards Track [Page 16] + 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 . 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'; + + 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 . Information on the + group and information on how to subscribe to the list is at + . + + + +Dierks & Allen Standards Track [Page 78] + +RFC 2246 The TLS Protocol Version 1.0 January 1999 + + + Archives of the list can be found at: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +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/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: + C: + 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: + + + +Hoffman Standards Track [Page 4] + +RFC 2487 SMTP Service Extension January 1999 + + + C & S: + C & S: + C: + . . . + +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/rfc2554.txt b/standards/rfc2554.txt new file mode 100644 index 000000000..2922deaee --- /dev/null +++ b/standards/rfc2554.txt @@ -0,0 +1,619 @@ + + + + + + +Network Working Group J. Myers +Request for Comments: 2554 Netscape Communications +Category: Standards Track March 1999 + + + SMTP Service Extension + for 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. + + +1. Introduction + + This document defines an SMTP service extension [ESMTP] whereby an + SMTP client may indicate an authentication mechanism to the server, + perform an authentication protocol exchange, and optionally negotiate + a security layer for subsequent protocol interactions. This + extension is a profile of the Simple Authentication and Security + Layer [SASL]. + + +2. Conventions Used in this Document + + In examples, "C:" and "S:" indicate lines sent by the client and + server respectively. + + The key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY" + in this document are to be interpreted as defined in "Key words for + use in RFCs to Indicate Requirement Levels" [KEYWORDS]. + + +3. The Authentication service extension + + + (1) the name of the SMTP service extension is "Authentication" + + (2) the EHLO keyword value associated with this extension is "AUTH" + + + + +Myers Standards Track [Page 1] + +RFC 2554 SMTP Authentication March 1999 + + + (3) The AUTH EHLO keyword contains as a parameter a space separated + list of the names of supported SASL mechanisms. + + (4) a new SMTP verb "AUTH" is defined + + (5) an optional parameter using the keyword "AUTH" is added to the + MAIL FROM command, and extends the maximum line length of the + MAIL FROM command by 500 characters. + + (6) this extension is appropriate for the submission protocol + [SUBMIT]. + + +4. The AUTH command + + AUTH mechanism [initial-response] + + Arguments: + a string identifying a SASL authentication mechanism. + an optional base64-encoded response + + Restrictions: + After an AUTH command has successfully completed, no more AUTH + commands may be issued in the same session. After a successful + AUTH command completes, a server MUST reject any further AUTH + commands with a 503 reply. + + The AUTH command is not permitted during a mail transaction. + + Discussion: + The AUTH command indicates an authentication mechanism to the + server. If the server supports the requested authentication + mechanism, it performs an authentication protocol exchange to + authenticate and identify the user. Optionally, it also + negotiates a security layer for subsequent protocol + interactions. If the requested authentication mechanism is not + supported, the server rejects the AUTH command with a 504 + reply. + + The authentication protocol exchange consists of a series of + server challenges and client answers that are specific to the + authentication mechanism. A server challenge, otherwise known + as a ready response, is a 334 reply with the text part + containing a BASE64 encoded string. The client answer consists + of a line containing a BASE64 encoded string. If the client + wishes to cancel an authentication exchange, it issues a line + with a single "*". If the server receives such an answer, it + MUST reject the AUTH command by sending a 501 reply. + + + +Myers Standards Track [Page 2] + +RFC 2554 SMTP Authentication March 1999 + + + The optional initial-response argument to the AUTH command is + used to save a round trip when using authentication mechanisms + that are defined to send no data in the initial challenge. + When the initial-response argument is used with such a + mechanism, the initial empty challenge is not sent to the + client and the server uses the data in the initial-response + argument as if it were sent in response to the empty challenge. + Unlike a zero-length client answer to a 334 reply, a zero- + length initial response is sent as a single equals sign ("="). + If the client uses an initial-response argument to the AUTH + command with a mechanism that sends data in the initial + challenge, the server rejects the AUTH command with a 535 + reply. + + If the server cannot BASE64 decode the argument, it rejects the + AUTH command with a 501 reply. If the server rejects the + authentication data, it SHOULD reject the AUTH command with a + 535 reply unless a more specific error code, such as one listed + in section 6, is appropriate. Should the client successfully + complete the authentication exchange, the SMTP server issues a + 235 reply. + + The service name specified by this protocol's profile of SASL + is "smtp". + + If a security layer is negotiated through the SASL + authentication exchange, it takes effect immediately following + the CRLF that concludes the authentication exchange for the + client, and the CRLF of the success reply for the server. Upon + a security layer's taking effect, 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 SASL 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 SASL negotiation itself (with the + exception that a client MAY compare the list of advertised SASL + mechanisms before and after authentication in order to detect + an active down-negotiation attack). The client SHOULD send an + EHLO command as the first command after a successful SASL + negotiation which results in the enabling of a security layer. + + The server is not required to support any particular + authentication mechanism, nor are authentication mechanisms + required to support any security layers. If an AUTH command + fails, the client may try another authentication mechanism by + issuing another AUTH command. + + + +Myers Standards Track [Page 3] + +RFC 2554 SMTP Authentication March 1999 + + + If an AUTH command fails, the server MUST behave the same as if + the client had not issued the AUTH command. + + The BASE64 string may in general be arbitrarily long. Clients + and servers MUST be able to support challenges and responses + that are as long as are generated by the authentication + mechanisms they support, independent of any line length + limitations the client or server may have in other parts of its + protocol implementation. + + Examples: + S: 220 smtp.example.com ESMTP server ready + C: EHLO jgm.example.com + S: 250-smtp.example.com + S: 250 AUTH CRAM-MD5 DIGEST-MD5 + C: AUTH FOOBAR + S: 504 Unrecognized authentication type. + C: AUTH CRAM-MD5 + S: 334 + PENCeUxFREJoU0NnbmhNWitOMjNGNndAZWx3b29kLmlubm9zb2Z0LmNvbT4= + C: ZnJlZCA5ZTk1YWVlMDljNDBhZjJiODRhMGMyYjNiYmFlNzg2ZQ== + S: 235 Authentication successful. + + + +5. The AUTH parameter to the MAIL FROM command + + AUTH=addr-spec + + Arguments: + An addr-spec containing the identity which submitted the message + to the delivery system, or the two character sequence "<>" + indicating such an identity is unknown or insufficiently + authenticated. To comply with the restrictions imposed on ESMTP + parameters, the addr-spec is encoded inside an xtext. The syntax + of an xtext is described in section 5 of [ESMTP-DSN]. + + Discussion: + The optional AUTH parameter to the MAIL FROM command allows + cooperating agents in a trusted environment to communicate the + authentication of individual messages. + + If the server trusts the authenticated identity of the client to + assert that the message was originally submitted by the supplied + addr-spec, then the server SHOULD supply the same addr-spec in an + AUTH parameter when relaying the message to any server which + supports the AUTH extension. + + + + +Myers Standards Track [Page 4] + +RFC 2554 SMTP Authentication March 1999 + + + A MAIL FROM parameter of AUTH=<> indicates that the original + submitter of the message is not known. The server MUST NOT treat + the message as having been originally submitted by the client. + + If the AUTH parameter to the MAIL FROM is not supplied, the + client has authenticated, and the server believes the message is + an original submission by the client, the server MAY supply the + client's identity in the addr-spec in an AUTH parameter when + relaying the message to any server which supports the AUTH + extension. + + If the server does not sufficiently trust the authenticated + identity of the client, or if the client is not authenticated, + then the server MUST behave as if the AUTH=<> parameter was + supplied. The server MAY, however, write the value of the AUTH + parameter to a log file. + + If an AUTH=<> parameter was supplied, either explicitly or due to + the requirement in the previous paragraph, then the server MUST + supply the AUTH=<> parameter when relaying the message to any + server which it has authenticated to using the AUTH extension. + + A server MAY treat expansion of a mailing list as a new + submission, setting the AUTH parameter to the mailing list + address or mailing list administration address when relaying the + message to list subscribers. + + It is conforming for an implementation to be hard-coded to treat + all clients as being insufficiently trusted. In that case, the + implementation does nothing more than parse and discard + syntactically valid AUTH parameters to the MAIL FROM command and + supply AUTH=<> parameters to any servers to which it + authenticates using the AUTH extension. + + Examples: + C: MAIL FROM: AUTH=e+3Dmc2@example.com + S: 250 OK + + + + + + + + + + + + + + +Myers Standards Track [Page 5] + +RFC 2554 SMTP Authentication March 1999 + + +6. Error Codes + + The following error codes may be used to indicate various conditions + as described. + + 432 A password transition is needed + + This response to the AUTH command indicates that the user needs to + transition to the selected authentication mechanism. This typically + done by authenticating once using the PLAIN authentication mechanism. + + 534 Authentication mechanism is too weak + + This response to the AUTH command indicates that the selected + authentication mechanism is weaker than server policy permits for + that user. + + 538 Encryption required for requested authentication mechanism + + This response to the AUTH command indicates that the selected + authentication mechanism may only be used when the underlying SMTP + connection is encrypted. + + 454 Temporary authentication failure + + This response to the AUTH command indicates that the authentication + failed due to a temporary server failure. + + 530 Authentication required + + This response may be returned by any command other than AUTH, EHLO, + HELO, NOOP, RSET, or QUIT. It indicates that server policy requires + authentication in order to perform the requested action. + + + + + + + + + + + + + + + + + + +Myers Standards Track [Page 6] + +RFC 2554 SMTP Authentication March 1999 + + +7. Formal Syntax + + The following syntax specification uses the augmented Backus-Naur + Form (BNF) notation as specified in [ABNF]. + + Except as noted otherwise, all alphabetic characters are case- + insensitive. The use of upper or lower case characters to define + token strings is for editorial clarity only. Implementations MUST + accept these strings in a case-insensitive fashion. + + UPALPHA = %x41-5A ;; Uppercase: A-Z + + LOALPHA = %x61-7A ;; Lowercase: a-z + + ALPHA = UPALPHA / LOALPHA ;; case insensitive + + DIGIT = %x30-39 ;; Digits 0-9 + + HEXDIGIT = %x41-46 / DIGIT ;; hexidecimal digit (uppercase) + + hexchar = "+" HEXDIGIT HEXDIGIT + + xchar = %x21-2A / %x2C-3C / %x3E-7E + ;; US-ASCII except for "+", "=", SPACE and CTL + + xtext = *(xchar / hexchar) + + AUTH_CHAR = ALPHA / DIGIT / "-" / "_" + + auth_type = 1*20AUTH_CHAR + + auth_command = "AUTH" SPACE auth_type [SPACE (base64 / "=")] + *(CRLF [base64]) CRLF + + auth_param = "AUTH=" xtext + ;; The decoded form of the xtext MUST be either + ;; an addr-spec or the two characters "<>" + + base64 = base64_terminal / + ( 1*(4base64_CHAR) [base64_terminal] ) + + base64_char = UPALPHA / LOALPHA / DIGIT / "+" / "/" + ;; Case-sensitive + + base64_terminal = (2base64_char "==") / (3base64_char "=") + + continue_req = "334" SPACE [base64] CRLF + + + + +Myers Standards Track [Page 7] + +RFC 2554 SMTP Authentication March 1999 + + + CR = %x0C ;; ASCII CR, carriage return + + CRLF = CR LF + + CTL = %x00-1F / %x7F ;; any ASCII control character and DEL + + LF = %x0A ;; ASCII LF, line feed + + SPACE = %x20 ;; ASCII SP, space + + + + +8. References + + [ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", RFC 2234, November 1997. + + [CRAM-MD5] Klensin, J., Catoe, R. and P. Krumviede, "IMAP/POP + AUTHorize Extension for Simple Challenge/Response", RFC + 2195, September 1997. + + [ESMTP] Klensin, J., Freed, N., Rose, M., Stefferud, E. and D. + Crocker, "SMTP Service Extensions", RFC 1869, November + 1995. + + [ESMTP-DSN] Moore, K, "SMTP Service Extension for Delivery Status + Notifications", RFC 1891, January 1996. + + [KEYWORDS] 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. + + [SUBMIT] Gellens, R. and J. Klensin, "Message Submission", RFC + 2476, December 1998. + + [RFC821] Postel, J., "Simple Mail Transfer Protocol", STD 10, RFC + 821, August 1982. + + [RFC822] Crocker, D., "Standard for the Format of ARPA Internet + Text Messages", STD 11, RFC 822, August 1982. + + + + + + + + +Myers Standards Track [Page 8] + +RFC 2554 SMTP Authentication March 1999 + + +9. Security Considerations + + Security issues are discussed throughout this memo. + + If a client uses this extension to get an encrypted tunnel through an + insecure network to a cooperating server, it needs to be configured + to never send mail to that server when the connection is not mutually + authenticated and encrypted. Otherwise, an attacker could steal the + client's mail by hijacking the SMTP connection and either pretending + the server does not support the Authentication extension or causing + all AUTH commands to fail. + + Before the SASL negotiation 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 SASL negotiation upon completion + of a SASL negotiation which results in a security layer. + + This mechanism does not protect the TCP port, so an active attacker + may redirect a relay connection attempt to the submission port + [SUBMIT]. The AUTH=<> parameter prevents such an attack from causing + an relayed message without an envelope authentication to pick up the + authentication of the relay client. + + A message submission client may require the user to authenticate + whenever a suitable SASL mechanism is advertised. Therefore, it may + not be desirable for a submission server [SUBMIT] to advertise a SASL + mechanism when use of that mechanism grants the client no benefits + over anonymous submission. + + This extension is not intended to replace or be used instead of end- + to-end message signature and encryption systems such as S/MIME or + PGP. This extension addresses a different problem than end-to-end + systems; it has the following key differences: + + (1) it is generally useful only within a trusted enclave + + (2) it protects the entire envelope of a message, not just the + message's body. + + (3) it authenticates the message submission, not authorship of the + message content + + (4) it can give the sender some assurance the message was + delivered to the next hop in the case where the sender + mutually authenticates with the next hop and negotiates an + appropriate security layer. + + + + +Myers Standards Track [Page 9] + +RFC 2554 SMTP Authentication March 1999 + + + Additional security considerations are mentioned in the SASL + specification [SASL]. + + + +10. Author's Address + + John Gardiner Myers + Netscape Communications + 501 East Middlefield Road + Mail Stop MV-029 + Mountain View, CA 94043 + + EMail: jgmyers@netscape.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Myers Standards Track [Page 10] + +RFC 2554 SMTP Authentication March 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. + + + + + + + + + + + + + + + + + + + + + + + + +Myers Standards Track [Page 11] + 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... 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 = + + + + + +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 = + + 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 = + job = 1*3DIGIT ; job-number + files = *( "," ) ; 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 = + job = 1*3DIGIT + file-name = [ 1*DIGIT "copies of" SP ] + ; 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 + + 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 + + ... + 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" + + 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" + + S: * ACAP (SASL "CRAM-MD5" "PLAIN" "EXTERNAL") + C: a003 AUTHENTICATE "PLAIN" {21+} + C: timtanstaaftanstaaf + S: a003 OK CRAM-MD5 password initialized + + Note: In this example, 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 "*element" indicating at least and at most + 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: "(element)" is equivalent to + "*(element)"; that is, exactly 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 "#element" indicating at least + and at most 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 = + CHAR = + UPALPHA = + LOALPHA = + ALPHA = UPALPHA | LOALPHA + DIGIT = + CTL = + CR = + LF = + SP = + HT = + <"> = + + 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 = + + 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* + 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 = + + A string of text is parsed as a single word if it is quoted using + double-quote marks. + + quoted-string = ( <"> *(qdtext | quoted-pair ) <"> ) + qdtext = > + + 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 "." 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 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 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 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 + | + + 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 = * + + 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 = + + 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 + 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", , + 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=" 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 = + user-pass = userid ":" password + userid = * + 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 + 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 +#include + + + +Franks, et al. Standards Track [Page 27] + +RFC 2617 HTTP Authentication June 1999 + + +#include +#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 +#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*) + (O*) + (see [RFC2566] Section 4.2) + Group 3: Document Content (R) + + + 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*) + (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*) + (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*) + (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*) + + + 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) + (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) + (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) + (R*) + Group 3: Printer Object Attributes(R*) (see Note 2) + (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) + (R*) + Group 3: Job Object Attributes(R*) (see Note 2) + (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) + (R*) + Group 3: Job Object Attributes(R*) (see Note 2, 5) + (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 . .... 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 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 + 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 + . 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., ) 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 " (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: [SP ] + + 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 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 can contain more than just a + mailbox, however, contemporary systems SHOULD NOT use source routing + (see appendix C). + + The optional are associated with negotiated SMTP + service extensions (see section 2.2). + + The second step in the procedure is the RCPT command. + + RCPT TO: [ SP ] + + 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 can contain more than just a mailbox. + Historically, the 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 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 + + 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 + + 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 + 553-Harry Smith + 553 Melvin Smith + + or + + 553-Ambiguous; Possibilities + 553- + 553- + 553 + + 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 + S: 250-Fred Fonebone + S: 250 Sam Q. Smith + + 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., + "", 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 . The commands themselves are alphabetic + characters terminated by if parameters follow and + otherwise. (In the interest of improved interoperability, SMTP + receivers are encouraged to tolerate trailing white space before the + terminating .) 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 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: + 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: + RCPT TO: + + As provided in appendix C, xyz.com MAY also choose to relay the + message to hosta.int, using the envelope commands + + MAIL FROM: + RCPT TO:<@hosta.int,@jkl.org:userc@d.bar.org> + + or to jkl.org, using the envelope commands + + MAIL FROM: + 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:" ("" / "" / 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 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 "." (see section 4.5.2). This + is the end of mail data indication. Note that the first of + this terminating sequence is also the that ends the final line + of the data (message text) or, if there was no data, ends the DATA + command itself. An extra 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 + ; in that case, the originating SMTP system MUST either reject + the message as invalid or add in order to have the receiving + SMTP server recognize the "end of data" condition. + + The custom of accepting lines ending only in , 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 "." (bare line + feeds, without carriage returns) MUST NOT be treated as equivalent to + . 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, , one line of text, and , 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 , optionally + some text, and . As noted above, servers SHOULD send the + 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 or 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 Service ready + 221 Service closing transmission channel + 421 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 + (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 + (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 . + 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 Service ready + 221 Service closing transmission channel + 250 Requested mail action okay, completed + 251 User not local; will forward to + (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 . + + + + + + +Klensin Standards Track [Page 45] + +RFC 2821 Simple Mail Transfer Protocol April 2001 + + + 421 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 + (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 . + + When an SMTP server returns a positive completion status (2yz code) + after the DATA command is completed with ., 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 ., 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 ., 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 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 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 + +Time-stamp-line = "Received:" FWS Stamp + +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:" + (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 + "." 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 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 is 512 characters. More information may be + conveyed through multiple-line replies. + + text line + The maximum total length of a text line including the 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: + + 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 . 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 was a reverse source routing list of + hosts and a source mailbox. The first host in the + SHOULD be the host sending the MAIL command. Similarly, the + may be a source routing lists of hosts and a + destination mailbox. However, in general, the 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: + S: 250 OK + C: RCPT TO: + S: 250 OK + C: RCPT TO: + S: 550 No such user here + C: RCPT TO: + + + +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 . + 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: + S: 250 OK + C: RCPT TO: + S: 250 OK + C: RCPT TO: + 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: + S: 250 OK + C: RCPT TO:<@foo.com:Jones@XYZ.COM> + S: 250 OK + C: DATA + S: 354 Start mail input; end with . + 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 + 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: + S: 250 OK + C: DATA + S: 354 Start mail input; end with . + 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 + 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 + C: SEND FROM: + S: 250 OK + C: RCPT TO: + S: 250 OK + C: DATA + S: 354 Start mail input; end with . + 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 +To: Mary Smith +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 +Sender: Michael Jones +To: Mary Smith +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" +To: Mary Smith , jdoe@example.org, Who? +Cc: , "Giant; \"Big\" Box" +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 +To: A Group:Chris Jones ,joe@where.test,John ; +Cc: Undisclosed recipients:; +Date: Thu, 13 Feb 1969 23:32:54 -0330 +Message-ID: + +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 +To: Mary Smith +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 +To: John Doe +Reply-To: "Mary Smith: Personal Account" +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" +From: John Doe +Subject: Re: Saying Hello +Date: Fri, 21 Nov 1997 11:00:00 -0600 +Message-ID: +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 +To: Mary Smith +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 +Resent-To: Jane Brown +Resent-Date: Mon, 24 Nov 1997 14:22:01 -0800 +Resent-Message-ID: <78910@example.net> +From: John Doe +To: Mary Smith +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 ; 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 +To: Mary Smith +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) +To:A Group(Some people) + :Chris Jones , + joe@example.org, + John (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: + +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 +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 +To: Mary Smith +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 +To : Mary Smith +__ + +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... 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/standards/rfc2965.txt b/standards/rfc2965.txt new file mode 100644 index 000000000..8a4d02b17 --- /dev/null +++ b/standards/rfc2965.txt @@ -0,0 +1,1459 @@ + + + + + + +Network Working Group D. Kristol +Request for Comments: 2965 Bell Laboratories, Lucent Technologies +Obsoletes: 2109 L. Montulli +Category: Standards Track Epinions.com, Inc. + October 2000 + + + HTTP State Management Mechanism + +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. + +IESG Note + + The IESG notes that this mechanism makes use of the .local top-level + domain (TLD) internally when handling host names that don't contain + any dots, and that this mechanism might not work in the expected way + should an actual .local TLD ever be registered. + +Abstract + + This document specifies a way to create a stateful session with + Hypertext Transfer Protocol (HTTP) requests and responses. It + describes three new headers, Cookie, Cookie2, and Set-Cookie2, which + carry state information between participating origin servers and user + agents. The method described here differs from Netscape's Cookie + proposal [Netscape], but it can interoperate with HTTP/1.0 user + agents that use Netscape's method. (See the HISTORICAL section.) + + This document reflects implementation experience with RFC 2109 and + obsoletes it. + +1. TERMINOLOGY + + The terms user agent, client, server, proxy, origin server, and + http_URL have the same meaning as in the HTTP/1.1 specification + [RFC2616]. The terms abs_path and absoluteURI have the same meaning + as in the URI Syntax specification [RFC2396]. + + + + +Kristol & Montulli Standards Track [Page 1] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + Host name (HN) means either the host domain name (HDN) or the numeric + Internet Protocol (IP) address of a host. The fully qualified domain + name is preferred; use of numeric IP addresses is strongly + discouraged. + + The terms request-host and request-URI refer to the values the client + would send to the server as, respectively, the host (but not port) + and abs_path portions of the absoluteURI (http_URL) of the HTTP + request line. Note that request-host is a HN. + + The term effective host name is related to host name. If a host name + contains no dots, the effective host name is that name with the + string .local appended to it. Otherwise the effective host name is + the same as the host name. Note that all effective host names + contain at least one dot. + + The term request-port refers to the port portion of the absoluteURI + (http_URL) of the HTTP request line. If the absoluteURI has no + explicit port, the request-port is the HTTP default, 80. The + request-port of a cookie is the request-port of the request in which + a Set-Cookie2 response header was returned to the user agent. + + Host names can be specified either as an IP address or a HDN string. + Sometimes we compare one host name with another. (Such comparisons + SHALL be case-insensitive.) Host A's name domain-matches host B's if + + * their host name strings string-compare equal; or + + * A is a HDN string and has the form NB, where N is a non-empty + name string, B has the form .B', and B' is a HDN string. (So, + x.y.com domain-matches .Y.com but not Y.com.) + + Note that domain-match is not a commutative operation: a.b.c.com + domain-matches .c.com, but not the reverse. + + The reach R of a host name H is defined as follows: + + * If + + - H is the host domain name of a host; and, + + - H has the form A.B; and + + - A has no embedded (that is, interior) dots; and + + - B has at least one embedded dot, or B is the string "local". + then the reach of H is .B. + + + + +Kristol & Montulli Standards Track [Page 2] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + * Otherwise, the reach of H is H. + + For two strings that represent paths, P1 and P2, P1 path-matches P2 + if P2 is a prefix of P1 (including the case where P1 and P2 string- + compare equal). Thus, the string /tec/waldo path-matches /tec. + + Because it was used in Netscape's original implementation of state + management, we will use the term cookie to refer to the state + information that passes between an origin server and user agent, and + that gets stored by the user agent. + +1.1 Requirements + + The key words "MAY", "MUST", "MUST NOT", "OPTIONAL", "RECOMMENDED", + "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT" in this + document are to be interpreted as described in RFC 2119 [RFC2119]. + +2. STATE AND SESSIONS + + This document describes a way to create stateful sessions with HTTP + requests and responses. Currently, HTTP servers respond to each + client request without relating that request to previous or + subsequent requests; the state management mechanism allows clients + and servers that wish to exchange state information to place HTTP + requests and responses within a larger context, which we term a + "session". This context might be used to create, for example, a + "shopping cart", in which user selections can be aggregated before + purchase, or a magazine browsing system, in which a user's previous + reading affects which offerings are presented. + + Neither clients nor servers are required to support cookies. A + server MAY refuse to provide content to a client that does not return + the cookies it sends. + +3. DESCRIPTION + + We describe here a way for an origin server to send state information + to the user agent, and for the user agent to return the state + information to the origin server. The goal is to have a minimal + impact on HTTP and user agents. + +3.1 Syntax: General + + The two state management headers, Set-Cookie2 and Cookie, have common + syntactic properties involving attribute-value pairs. The following + grammar uses the notation, and tokens DIGIT (decimal digits), token + + + + + +Kristol & Montulli Standards Track [Page 3] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + (informally, a sequence of non-special, non-white space characters), + and http_URL from the HTTP/1.1 specification [RFC2616] to describe + their syntax. + + av-pairs = av-pair *(";" av-pair) + av-pair = attr ["=" value] ; optional value + attr = token + value = token | quoted-string + + Attributes (names) (attr) are case-insensitive. White space is + permitted between tokens. Note that while the above syntax + description shows value as optional, most attrs require them. + + NOTE: The syntax above allows whitespace between the attribute and + the = sign. + +3.2 Origin Server Role + + 3.2.1 General The origin server initiates a session, if it so + desires. To do so, it returns an extra response header to the + client, Set-Cookie2. (The details follow later.) + + A user agent returns a Cookie request header (see below) to the + origin server if it chooses to continue a session. The origin server + MAY ignore it or use it to determine the current state of the + session. It MAY send back to the client a Set-Cookie2 response + header with the same or different information, or it MAY send no + Set-Cookie2 header at all. The origin server effectively ends a + session by sending the client a Set-Cookie2 header with Max-Age=0. + + Servers MAY return Set-Cookie2 response headers with any response. + User agents SHOULD send Cookie request headers, subject to other + rules detailed below, with every request. + + An origin server MAY include multiple Set-Cookie2 headers in a + response. Note that an intervening gateway could fold multiple such + headers into a single header. + + + + + + + + + + + + + + +Kristol & Montulli Standards Track [Page 4] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + 3.2.2 Set-Cookie2 Syntax The syntax for the Set-Cookie2 response + header is + + set-cookie = "Set-Cookie2:" cookies + cookies = 1#cookie + cookie = NAME "=" VALUE *(";" set-cookie-av) + NAME = attr + VALUE = value + set-cookie-av = "Comment" "=" value + | "CommentURL" "=" <"> http_URL <"> + | "Discard" + | "Domain" "=" value + | "Max-Age" "=" value + | "Path" "=" value + | "Port" [ "=" <"> portlist <"> ] + | "Secure" + | "Version" "=" 1*DIGIT + portlist = 1#portnum + portnum = 1*DIGIT + + Informally, the Set-Cookie2 response header comprises the token Set- + Cookie2:, followed by a comma-separated list of one or more cookies. + Each cookie begins with a NAME=VALUE pair, followed by zero or more + semi-colon-separated attribute-value pairs. The syntax for + attribute-value pairs was shown earlier. The specific attributes and + the semantics of their values follows. The NAME=VALUE attribute- + value pair MUST come first in each cookie. The others, if present, + can occur in any order. If an attribute appears more than once in a + cookie, the client SHALL use only the value associated with the first + appearance of the attribute; a client MUST ignore values after the + first. + + The NAME of a cookie MAY be the same as one of the attributes in this + specification. However, because the cookie's NAME must come first in + a Set-Cookie2 response header, the NAME and its VALUE cannot be + confused with an attribute-value pair. + + NAME=VALUE + REQUIRED. The name of the state information ("cookie") is NAME, + and its value is VALUE. NAMEs that begin with $ are reserved and + MUST NOT be used by applications. + + The VALUE is opaque to the user agent and may be anything the + origin server chooses to send, possibly in a server-selected + printable ASCII encoding. "Opaque" implies that the content is of + interest and relevance only to the origin server. The content + may, in fact, be readable by anyone that examines the Set-Cookie2 + header. + + + +Kristol & Montulli Standards Track [Page 5] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + Comment=value + OPTIONAL. Because cookies can be used to derive or store private + information about a user, the value of the Comment attribute + allows an origin server to document how it intends to use the + cookie. The user can inspect the information to decide whether to + initiate or continue a session with this cookie. Characters in + value MUST be in UTF-8 encoding. [RFC2279] + + CommentURL="http_URL" + OPTIONAL. Because cookies can be used to derive or store private + information about a user, the CommentURL attribute allows an + origin server to document how it intends to use the cookie. The + user can inspect the information identified by the URL to decide + whether to initiate or continue a session with this cookie. + + Discard + OPTIONAL. The Discard attribute instructs the user agent to + discard the cookie unconditionally when the user agent terminates. + + Domain=value + OPTIONAL. The value of the Domain attribute specifies the domain + for which the cookie is valid. If an explicitly specified value + does not start with a dot, the user agent supplies a leading dot. + + Max-Age=value + OPTIONAL. The value of the Max-Age attribute is delta-seconds, + the lifetime of the cookie in seconds, a decimal non-negative + integer. To handle cached cookies correctly, a client SHOULD + calculate the age of the cookie according to the age calculation + rules in the HTTP/1.1 specification [RFC2616]. When the age is + greater than delta-seconds seconds, the client SHOULD discard the + cookie. A value of zero means the cookie SHOULD be discarded + immediately. + + Path=value + OPTIONAL. The value of the Path attribute specifies the subset of + URLs on the origin server to which this cookie applies. + + Port[="portlist"] + OPTIONAL. The Port attribute restricts the port to which a cookie + may be returned in a Cookie request header. Note that the syntax + REQUIREs quotes around the OPTIONAL portlist even if there is only + one portnum in portlist. + + + + + + + + +Kristol & Montulli Standards Track [Page 6] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + Secure + OPTIONAL. The Secure attribute (with no value) directs the user + agent to use only (unspecified) secure means to contact the origin + server whenever it sends back this cookie, to protect the + confidentially and authenticity of the information in the cookie. + + The user agent (possibly with user interaction) MAY determine what + level of security it considers appropriate for "secure" cookies. + The Secure attribute should be considered security advice from the + server to the user agent, indicating that it is in the session's + interest to protect the cookie contents. When it sends a "secure" + cookie back to a server, the user agent SHOULD use no less than + the same level of security as was used when it received the cookie + from the server. + + Version=value + REQUIRED. The value of the Version attribute, a decimal integer, + identifies the version of the state management specification to + which the cookie conforms. For this specification, Version=1 + applies. + + 3.2.3 Controlling Caching An origin server must be cognizant of the + effect of possible caching of both the returned resource and the + Set-Cookie2 header. Caching "public" documents is desirable. For + example, if the origin server wants to use a public document such as + a "front door" page as a sentinel to indicate the beginning of a + session for which a Set-Cookie2 response header must be generated, + the page SHOULD be stored in caches "pre-expired" so that the origin + server will see further requests. "Private documents", for example + those that contain information strictly private to a session, SHOULD + NOT be cached in shared caches. + + If the cookie is intended for use by a single user, the Set-Cookie2 + header SHOULD NOT be cached. A Set-Cookie2 header that is intended + to be shared by multiple users MAY be cached. + + The origin server SHOULD send the following additional HTTP/1.1 + response headers, depending on circumstances: + + * To suppress caching of the Set-Cookie2 header: + + Cache-control: no-cache="set-cookie2" + + and one of the following: + + * To suppress caching of a private document in shared caches: + + Cache-control: private + + + +Kristol & Montulli Standards Track [Page 7] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + * To allow caching of a document and require that it be validated + before returning it to the client: + + Cache-Control: must-revalidate, max-age=0 + + * To allow caching of a document, but to require that proxy + caches (not user agent caches) validate it before returning it + to the client: + + Cache-Control: proxy-revalidate, max-age=0 + + * To allow caching of a document and request that it be validated + before returning it to the client (by "pre-expiring" it): + + Cache-control: max-age=0 + + Not all caches will revalidate the document in every case. + + HTTP/1.1 servers MUST send Expires: old-date (where old-date is a + date long in the past) on responses containing Set-Cookie2 response + headers unless they know for certain (by out of band means) that + there are no HTTP/1.0 proxies in the response chain. HTTP/1.1 + servers MAY send other Cache-Control directives that permit caching + by HTTP/1.1 proxies in addition to the Expires: old-date directive; + the Cache-Control directive will override the Expires: old-date for + HTTP/1.1 proxies. + +3.3 User Agent Role + + 3.3.1 Interpreting Set-Cookie2 The user agent keeps separate track + of state information that arrives via Set-Cookie2 response headers + from each origin server (as distinguished by name or IP address and + port). The user agent MUST ignore attribute-value pairs whose + attribute it does not recognize. The user agent applies these + defaults for optional attributes that are missing: + + Discard The default behavior is dictated by the presence or absence + of a Max-Age attribute. + + Domain Defaults to the effective request-host. (Note that because + there is no dot at the beginning of effective request-host, + the default Domain can only domain-match itself.) + + Max-Age The default behavior is to discard the cookie when the user + agent exits. + + Path Defaults to the path of the request URL that generated the + Set-Cookie2 response, up to and including the right-most /. + + + +Kristol & Montulli Standards Track [Page 8] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + Port The default behavior is that a cookie MAY be returned to any + request-port. + + Secure If absent, the user agent MAY send the cookie over an + insecure channel. + + 3.3.2 Rejecting Cookies To prevent possible security or privacy + violations, a user agent rejects a cookie according to rules below. + The goal of the rules is to try to limit the set of servers for which + a cookie is valid, based on the values of the Path, Domain, and Port + attributes and the request-URI, request-host and request-port. + + A user agent rejects (SHALL NOT store its information) if the Version + attribute is missing. Moreover, a user agent rejects (SHALL NOT + store its information) if any of the following is true of the + attributes explicitly present in the Set-Cookie2 response header: + + * The value for the Path attribute is not a prefix of the + request-URI. + + * The value for the Domain attribute contains no embedded dots, + and the value is not .local. + + * The effective host name that derives from the request-host does + not domain-match the Domain attribute. + + * The request-host is a HDN (not IP address) and has the form HD, + where D is the value of the Domain attribute, and H is a string + that contains one or more dots. + + * The Port attribute has a "port-list", and the request-port was + not in the list. + + Examples: + + * A Set-Cookie2 from request-host y.x.foo.com for Domain=.foo.com + would be rejected, because H is y.x and contains a dot. + + * A Set-Cookie2 from request-host x.foo.com for Domain=.foo.com + would be accepted. + + * A Set-Cookie2 with Domain=.com or Domain=.com., will always be + rejected, because there is no embedded dot. + + * A Set-Cookie2 with Domain=ajax.com will be accepted, and the + value for Domain will be taken to be .ajax.com, because a dot + gets prepended to the value. + + + + +Kristol & Montulli Standards Track [Page 9] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + * A Set-Cookie2 with Port="80,8000" will be accepted if the + request was made to port 80 or 8000 and will be rejected + otherwise. + + * A Set-Cookie2 from request-host example for Domain=.local will + be accepted, because the effective host name for the request- + host is example.local, and example.local domain-matches .local. + + 3.3.3 Cookie Management If a user agent receives a Set-Cookie2 + response header whose NAME is the same as that of a cookie it has + previously stored, the new cookie supersedes the old when: the old + and new Domain attribute values compare equal, using a case- + insensitive string-compare; and, the old and new Path attribute + values string-compare equal (case-sensitive). However, if the Set- + Cookie2 has a value for Max-Age of zero, the (old and new) cookie is + discarded. Otherwise a cookie persists (resources permitting) until + whichever happens first, then gets discarded: its Max-Age lifetime is + exceeded; or, if the Discard attribute is set, the user agent + terminates the session. + + Because user agents have finite space in which to store cookies, they + MAY also discard older cookies to make space for newer ones, using, + for example, a least-recently-used algorithm, along with constraints + on the maximum number of cookies that each origin server may set. + + If a Set-Cookie2 response header includes a Comment attribute, the + user agent SHOULD store that information in a human-readable form + with the cookie and SHOULD display the comment text as part of a + cookie inspection user interface. + + If a Set-Cookie2 response header includes a CommentURL attribute, the + user agent SHOULD store that information in a human-readable form + with the cookie, or, preferably, SHOULD allow the user to follow the + http_URL link as part of a cookie inspection user interface. + + The cookie inspection user interface may include a facility whereby a + user can decide, at the time the user agent receives the Set-Cookie2 + response header, whether or not to accept the cookie. A potentially + confusing situation could arise if the following sequence occurs: + + * the user agent receives a cookie that contains a CommentURL + attribute; + + * the user agent's cookie inspection interface is configured so + that it presents a dialog to the user before the user agent + accepts the cookie; + + + + + +Kristol & Montulli Standards Track [Page 10] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + * the dialog allows the user to follow the CommentURL link when + the user agent receives the cookie; and, + + * when the user follows the CommentURL link, the origin server + (or another server, via other links in the returned content) + returns another cookie. + + The user agent SHOULD NOT send any cookies in this context. The user + agent MAY discard any cookie it receives in this context that the + user has not, through some user agent mechanism, deemed acceptable. + + User agents SHOULD allow the user to control cookie destruction, but + they MUST NOT extend the cookie's lifetime beyond that controlled by + the Discard and Max-Age attributes. An infrequently-used cookie may + function as a "preferences file" for network applications, and a user + may wish to keep it even if it is the least-recently-used cookie. One + possible implementation would be an interface that allows the + permanent storage of a cookie through a checkbox (or, conversely, its + immediate destruction). + + Privacy considerations dictate that the user have considerable + control over cookie management. The PRIVACY section contains more + information. + + 3.3.4 Sending Cookies to the Origin Server When it sends a request + to an origin server, the user agent includes a Cookie request header + if it has stored cookies that are applicable to the request, based on + + * the request-host and request-port; + + * the request-URI; + + * the cookie's age. + + The syntax for the header is: + +cookie = "Cookie:" cookie-version 1*((";" | ",") cookie-value) +cookie-value = NAME "=" VALUE [";" path] [";" domain] [";" port] +cookie-version = "$Version" "=" value +NAME = attr +VALUE = value +path = "$Path" "=" value +domain = "$Domain" "=" value +port = "$Port" [ "=" <"> value <"> ] + + The value of the cookie-version attribute MUST be the value from the + Version attribute of the corresponding Set-Cookie2 response header. + Otherwise the value for cookie-version is 0. The value for the path + + + +Kristol & Montulli Standards Track [Page 11] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + attribute MUST be the value from the Path attribute, if one was + present, of the corresponding Set-Cookie2 response header. Otherwise + the attribute SHOULD be omitted from the Cookie request header. The + value for the domain attribute MUST be the value from the Domain + attribute, if one was present, of the corresponding Set-Cookie2 + response header. Otherwise the attribute SHOULD be omitted from the + Cookie request header. + + The port attribute of the Cookie request header MUST mirror the Port + attribute, if one was present, in the corresponding Set-Cookie2 + response header. That is, the port attribute MUST be present if the + Port attribute was present in the Set-Cookie2 header, and it MUST + have the same value, if any. Otherwise, if the Port attribute was + absent from the Set-Cookie2 header, the attribute likewise MUST be + omitted from the Cookie request header. + + Note that there is neither a Comment nor a CommentURL attribute in + the Cookie request header corresponding to the ones in the Set- + Cookie2 response header. The user agent does not return the comment + information to the origin server. + + The user agent applies the following rules to choose applicable + cookie-values to send in Cookie request headers from among all the + cookies it has received. + + Domain Selection + The origin server's effective host name MUST domain-match the + Domain attribute of the cookie. + + Port Selection + There are three possible behaviors, depending on the Port + attribute in the Set-Cookie2 response header: + + 1. By default (no Port attribute), the cookie MAY be sent to any + port. + + 2. If the attribute is present but has no value (e.g., Port), the + cookie MUST only be sent to the request-port it was received + from. + + 3. If the attribute has a port-list, the cookie MUST only be + returned if the new request-port is one of those listed in + port-list. + + Path Selection + The request-URI MUST path-match the Path attribute of the cookie. + + + + + +Kristol & Montulli Standards Track [Page 12] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + Max-Age Selection + Cookies that have expired should have been discarded and thus are + not forwarded to an origin server. + + If multiple cookies satisfy the criteria above, they are ordered in + the Cookie header such that those with more specific Path attributes + precede those with less specific. Ordering with respect to other + attributes (e.g., Domain) is unspecified. + + Note: For backward compatibility, the separator in the Cookie header + is semi-colon (;) everywhere. A server SHOULD also accept comma (,) + as the separator between cookie-values for future compatibility. + + 3.3.5 Identifying What Version is Understood: Cookie2 The Cookie2 + request header facilitates interoperation between clients and servers + that understand different versions of the cookie specification. When + the client sends one or more cookies to an origin server, if at least + one of those cookies contains a $Version attribute whose value is + different from the version that the client understands, then the + client MUST also send a Cookie2 request header, the syntax for which + is + + cookie2 = "Cookie2:" cookie-version + + Here the value for cookie-version is the highest version of cookie + specification (currently 1) that the client understands. The client + needs to send at most one such request header per request. + + 3.3.6 Sending Cookies in Unverifiable Transactions Users MUST have + control over sessions in order to ensure privacy. (See PRIVACY + section below.) To simplify implementation and to prevent an + additional layer of complexity where adequate safeguards exist, + however, this document distinguishes between transactions that are + verifiable and those that are unverifiable. A transaction is + verifiable if the user, or a user-designated agent, has the option to + review the request-URI prior to its use in the transaction. A + transaction is unverifiable if the user does not have that option. + Unverifiable transactions typically arise when a user agent + automatically requests inlined or embedded entities or when it + resolves redirection (3xx) responses from an origin server. + Typically the origin transaction, the transaction that the user + initiates, is verifiable, and that transaction may directly or + indirectly induce the user agent to make unverifiable transactions. + + An unverifiable transaction is to a third-party host if its request- + host U does not domain-match the reach R of the request-host O in the + origin transaction. + + + + +Kristol & Montulli Standards Track [Page 13] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + When it makes an unverifiable transaction, a user agent MUST disable + all cookie processing (i.e., MUST NOT send cookies, and MUST NOT + accept any received cookies) if the transaction is to a third-party + host. + + This restriction prevents a malicious service author from using + unverifiable transactions to induce a user agent to start or continue + a session with a server in a different domain. The starting or + continuation of such sessions could be contrary to the privacy + expectations of the user, and could also be a security problem. + + User agents MAY offer configurable options that allow the user agent, + or any autonomous programs that the user agent executes, to ignore + the above rule, so long as these override options default to "off". + + (N.B. Mechanisms may be proposed that will automate overriding the + third-party restrictions under controlled conditions.) + + Many current user agents already provide a review option that would + render many links verifiable. For instance, some user agents display + the URL that would be referenced for a particular link when the mouse + pointer is placed over that link. The user can therefore determine + whether to visit that site before causing the browser to do so. + (Though not implemented on current user agents, a similar technique + could be used for a button used to submit a form -- the user agent + could display the action to be taken if the user were to select that + button.) However, even this would not make all links verifiable; for + example, links to automatically loaded images would not normally be + subject to "mouse pointer" verification. + + Many user agents also provide the option for a user to view the HTML + source of a document, or to save the source to an external file where + it can be viewed by another application. While such an option does + provide a crude review mechanism, some users might not consider it + acceptable for this purpose. + +3.4 How an Origin Server Interprets the Cookie Header + + A user agent returns much of the information in the Set-Cookie2 + header to the origin server when the request-URI path-matches the + Path attribute of the cookie. When it receives a Cookie header, the + origin server SHOULD treat cookies with NAMEs whose prefix is $ + specially, as an attribute for the cookie. + + + + + + + + +Kristol & Montulli Standards Track [Page 14] + +RFC 2965 HTTP State Management Mechanism October 2000 + + +3.5 Caching Proxy Role + + One reason for separating state information from both a URL and + document content is to facilitate the scaling that caching permits. + To support cookies, a caching proxy MUST obey these rules already in + the HTTP specification: + + * Honor requests from the cache, if possible, based on cache + validity rules. + + * Pass along a Cookie request header in any request that the + proxy must make of another server. + + * Return the response to the client. Include any Set-Cookie2 + response header. + + * Cache the received response subject to the control of the usual + headers, such as Expires, + + Cache-control: no-cache + + and + + Cache-control: private + + * Cache the Set-Cookie2 subject to the control of the usual + header, + + Cache-control: no-cache="set-cookie2" + + (The Set-Cookie2 header should usually not be cached.) + + Proxies MUST NOT introduce Set-Cookie2 (Cookie) headers of their own + in proxy responses (requests). + +4. EXAMPLES + +4.1 Example 1 + + Most detail of request and response headers has been omitted. Assume + the user agent has no stored cookies. + + 1. User Agent -> Server + + POST /acme/login HTTP/1.1 + [form data] + + User identifies self via a form. + + + +Kristol & Montulli Standards Track [Page 15] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + 2. Server -> User Agent + + HTTP/1.1 200 OK + Set-Cookie2: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme" + + Cookie reflects user's identity. + + 3. User Agent -> Server + + POST /acme/pickitem HTTP/1.1 + Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme" + [form data] + + User selects an item for "shopping basket". + + 4. Server -> User Agent + + HTTP/1.1 200 OK + Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; + Path="/acme" + + Shopping basket contains an item. + + 5. User Agent -> Server + + POST /acme/shipping HTTP/1.1 + Cookie: $Version="1"; + Customer="WILE_E_COYOTE"; $Path="/acme"; + Part_Number="Rocket_Launcher_0001"; $Path="/acme" + [form data] + + User selects shipping method from form. + + 6. Server -> User Agent + + HTTP/1.1 200 OK + Set-Cookie2: Shipping="FedEx"; Version="1"; Path="/acme" + + New cookie reflects shipping method. + + 7. User Agent -> Server + + POST /acme/process HTTP/1.1 + Cookie: $Version="1"; + Customer="WILE_E_COYOTE"; $Path="/acme"; + Part_Number="Rocket_Launcher_0001"; $Path="/acme"; + Shipping="FedEx"; $Path="/acme" + [form data] + + + +Kristol & Montulli Standards Track [Page 16] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + User chooses to process order. + + 8. Server -> User Agent + + HTTP/1.1 200 OK + + Transaction is complete. + + The user agent makes a series of requests on the origin server, after + each of which it receives a new cookie. All the cookies have the + same Path attribute and (default) domain. Because the request-URIs + all path-match /acme, the Path attribute of each cookie, each request + contains all the cookies received so far. + +4.2 Example 2 + + This example illustrates the effect of the Path attribute. All + detail of request and response headers has been omitted. Assume the + user agent has no stored cookies. + + Imagine the user agent has received, in response to earlier requests, + the response headers + + Set-Cookie2: Part_Number="Rocket_Launcher_0001"; Version="1"; + Path="/acme" + + and + + Set-Cookie2: Part_Number="Riding_Rocket_0023"; Version="1"; + Path="/acme/ammo" + + A subsequent request by the user agent to the (same) server for URLs + of the form /acme/ammo/... would include the following request + header: + + Cookie: $Version="1"; + Part_Number="Riding_Rocket_0023"; $Path="/acme/ammo"; + Part_Number="Rocket_Launcher_0001"; $Path="/acme" + + Note that the NAME=VALUE pair for the cookie with the more specific + Path attribute, /acme/ammo, comes before the one with the less + specific Path attribute, /acme. Further note that the same cookie + name appears more than once. + + A subsequent request by the user agent to the (same) server for a URL + of the form /acme/parts/ would include the following request header: + + + + + +Kristol & Montulli Standards Track [Page 17] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + Cookie: $Version="1"; Part_Number="Rocket_Launcher_0001"; + $Path="/acme" + + Here, the second cookie's Path attribute /acme/ammo is not a prefix + of the request URL, /acme/parts/, so the cookie does not get + forwarded to the server. + +5. IMPLEMENTATION CONSIDERATIONS + + Here we provide guidance on likely or desirable details for an origin + server that implements state management. + +5.1 Set-Cookie2 Content + + An origin server's content should probably be divided into disjoint + application areas, some of which require the use of state + information. The application areas can be distinguished by their + request URLs. The Set-Cookie2 header can incorporate information + about the application areas by setting the Path attribute for each + one. + + The session information can obviously be clear or encoded text that + describes state. However, if it grows too large, it can become + unwieldy. Therefore, an implementor might choose for the session + information to be a key to a server-side resource. Of course, using + a database creates some problems that this state management + specification was meant to avoid, namely: + + 1. keeping real state on the server side; + + 2. how and when to garbage-collect the database entry, in case the + user agent terminates the session by, for example, exiting. + +5.2 Stateless Pages + + Caching benefits the scalability of WWW. Therefore it is important + to reduce the number of documents that have state embedded in them + inherently. For example, if a shopping-basket-style application + always displays a user's current basket contents on each page, those + pages cannot be cached, because each user's basket's contents would + be different. On the other hand, if each page contains just a link + that allows the user to "Look at My Shopping Basket", the page can be + cached. + + + + + + + + +Kristol & Montulli Standards Track [Page 18] + +RFC 2965 HTTP State Management Mechanism October 2000 + + +5.3 Implementation Limits + + Practical user agent implementations have limits on the number and + size of cookies that they can store. In general, user agents' cookie + support should have no fixed limits. They should strive to store as + many frequently-used cookies as possible. Furthermore, general-use + user agents SHOULD provide each of the following minimum capabilities + individually, although not necessarily simultaneously: + + * at least 300 cookies + + * at least 4096 bytes per cookie (as measured by the characters + that comprise the cookie non-terminal in the syntax description + of the Set-Cookie2 header, and as received in the Set-Cookie2 + header) + + * at least 20 cookies per unique host or domain name + + User agents created for specific purposes or for limited-capacity + devices SHOULD provide at least 20 cookies of 4096 bytes, to ensure + that the user can interact with a session-based origin server. + + The information in a Set-Cookie2 response header MUST be retained in + its entirety. If for some reason there is inadequate space to store + the cookie, it MUST be discarded, not truncated. + + Applications should use as few and as small cookies as possible, and + they should cope gracefully with the loss of a cookie. + + 5.3.1 Denial of Service Attacks User agents MAY choose to set an + upper bound on the number of cookies to be stored from a given host + or domain name or on the size of the cookie information. Otherwise a + malicious server could attempt to flood a user agent with many + cookies, or large cookies, on successive responses, which would force + out cookies the user agent had received from other servers. However, + the minima specified above SHOULD still be supported. + +6. PRIVACY + + Informed consent should guide the design of systems that use cookies. + A user should be able to find out how a web site plans to use + information in a cookie and should be able to choose whether or not + those policies are acceptable. Both the user agent and the origin + server must assist informed consent. + + + + + + + +Kristol & Montulli Standards Track [Page 19] + +RFC 2965 HTTP State Management Mechanism October 2000 + + +6.1 User Agent Control + + An origin server could create a Set-Cookie2 header to track the path + of a user through the server. Users may object to this behavior as + an intrusive accumulation of information, even if their identity is + not evident. (Identity might become evident, for example, if a user + subsequently fills out a form that contains identifying information.) + This state management specification therefore requires that a user + agent give the user control over such a possible intrusion, although + the interface through which the user is given this control is left + unspecified. However, the control mechanisms provided SHALL at least + allow the user + + * to completely disable the sending and saving of cookies. + + * to determine whether a stateful session is in progress. + + * to control the saving of a cookie on the basis of the cookie's + Domain attribute. + + Such control could be provided, for example, by mechanisms + + * to notify the user when the user agent is about to send a + cookie to the origin server, to offer the option not to begin a + session. + + * to display a visual indication that a stateful session is in + progress. + + * to let the user decide which cookies, if any, should be saved + when the user concludes a window or user agent session. + + * to let the user examine and delete the contents of a cookie at + any time. + + A user agent usually begins execution with no remembered state + information. It SHOULD be possible to configure a user agent never + to send Cookie headers, in which case it can never sustain state with + an origin server. (The user agent would then behave like one that is + unaware of how to handle Set-Cookie2 response headers.) + + When the user agent terminates execution, it SHOULD let the user + discard all state information. Alternatively, the user agent MAY ask + the user whether state information should be retained; the default + should be "no". If the user chooses to retain state information, it + would be restored the next time the user agent runs. + + + + + +Kristol & Montulli Standards Track [Page 20] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + NOTE: User agents should probably be cautious about using files to + store cookies long-term. If a user runs more than one instance of + the user agent, the cookies could be commingled or otherwise + corrupted. + +6.2 Origin Server Role + + An origin server SHOULD promote informed consent by adding CommentURL + or Comment information to the cookies it sends. CommentURL is + preferred because of the opportunity to provide richer information in + a multiplicity of languages. + +6.3 Clear Text + + The information in the Set-Cookie2 and Cookie headers is unprotected. + As a consequence: + + 1. Any sensitive information that is conveyed in them is exposed + to intruders. + + 2. A malicious intermediary could alter the headers as they travel + in either direction, with unpredictable results. + + These facts imply that information of a personal and/or financial + nature should only be sent over a secure channel. For less sensitive + information, or when the content of the header is a database key, an + origin server should be vigilant to prevent a bad Cookie value from + causing failures. + + A user agent in a shared user environment poses a further risk. + Using a cookie inspection interface, User B could examine the + contents of cookies that were saved when User A used the machine. + +7. SECURITY CONSIDERATIONS + +7.1 Protocol Design + + The restrictions on the value of the Domain attribute, and the rules + concerning unverifiable transactions, are meant to reduce the ways + that cookies can "leak" to the "wrong" site. The intent is to + restrict cookies to one host, or a closely related set of hosts. + Therefore a request-host is limited as to what values it can set for + Domain. We consider it acceptable for hosts host1.foo.com and + host2.foo.com to share cookies, but not a.com and b.com. + + Similarly, a server can set a Path only for cookies that are related + to the request-URI. + + + + +Kristol & Montulli Standards Track [Page 21] + +RFC 2965 HTTP State Management Mechanism October 2000 + + +7.2 Cookie Spoofing + + Proper application design can avoid spoofing attacks from related + domains. Consider: + + 1. User agent makes request to victim.cracker.edu, gets back + cookie session_id="1234" and sets the default domain + victim.cracker.edu. + + 2. User agent makes request to spoof.cracker.edu, gets back cookie + session-id="1111", with Domain=".cracker.edu". + + 3. User agent makes request to victim.cracker.edu again, and + passes + + Cookie: $Version="1"; session_id="1234", + $Version="1"; session_id="1111"; $Domain=".cracker.edu" + + The server at victim.cracker.edu should detect that the second + cookie was not one it originated by noticing that the Domain + attribute is not for itself and ignore it. + +7.3 Unexpected Cookie Sharing + + A user agent SHOULD make every attempt to prevent the sharing of + session information between hosts that are in different domains. + Embedded or inlined objects may cause particularly severe privacy + problems if they can be used to share cookies between disparate + hosts. For example, a malicious server could embed cookie + information for host a.com in a URI for a CGI on host b.com. User + agent implementors are strongly encouraged to prevent this sort of + exchange whenever possible. + +7.4 Cookies For Account Information + + While it is common practice to use them this way, cookies are not + designed or intended to be used to hold authentication information, + such as account names and passwords. Unless such cookies are + exchanged over an encrypted path, the account information they + contain is highly vulnerable to perusal and theft. + +8. OTHER, SIMILAR, PROPOSALS + + Apart from RFC 2109, three other proposals have been made to + accomplish similar goals. This specification began as an amalgam of + Kristol's State-Info proposal [DMK95] and Netscape's Cookie proposal + [Netscape]. + + + + +Kristol & Montulli Standards Track [Page 22] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + Brian Behlendorf proposed a Session-ID header that would be user- + agent-initiated and could be used by an origin server to track + "clicktrails". It would not carry any origin-server-defined state, + however. Phillip Hallam-Baker has proposed another client-defined + session ID mechanism for similar purposes. + + While both session IDs and cookies can provide a way to sustain + stateful sessions, their intended purpose is different, and, + consequently, the privacy requirements for them are different. A + user initiates session IDs to allow servers to track progress through + them, or to distinguish multiple users on a shared machine. Cookies + are server-initiated, so the cookie mechanism described here gives + users control over something that would otherwise take place without + the users' awareness. Furthermore, cookies convey rich, server- + selected information, whereas session IDs comprise user-selected, + simple information. + +9. HISTORICAL + +9.1 Compatibility with Existing Implementations + + Existing cookie implementations, based on the Netscape specification, + use the Set-Cookie (not Set-Cookie2) header. User agents that + receive in the same response both a Set-Cookie and Set-Cookie2 + response header for the same cookie MUST discard the Set-Cookie + information and use only the Set-Cookie2 information. Furthermore, a + user agent MUST assume, if it received a Set-Cookie2 response header, + that the sending server complies with this document and will + understand Cookie request headers that also follow this + specification. + + New cookies MUST replace both equivalent old- and new-style cookies. + That is, if a user agent that follows both this specification and + Netscape's original specification receives a Set-Cookie2 response + header, and the NAME and the Domain and Path attributes match (per + the Cookie Management section) a Netscape-style cookie, the + Netscape-style cookie MUST be discarded, and the user agent MUST + retain only the cookie adhering to this specification. + + Older user agents that do not understand this specification, but that + do understand Netscape's original specification, will not recognize + the Set-Cookie2 response header and will receive and send cookies + according to the older specification. + + + + + + + + +Kristol & Montulli Standards Track [Page 23] + +RFC 2965 HTTP State Management Mechanism October 2000 + + + A user agent that supports both this specification and Netscape-style + cookies SHOULD send a Cookie request header that follows the older + Netscape specification if it received the cookie in a Set-Cookie + response header and not in a Set-Cookie2 response header. However, + it SHOULD send the following request header as well: + + Cookie2: $Version="1" + + The Cookie2 header advises the server that the user agent understands + new-style cookies. If the server understands new-style cookies, as + well, it SHOULD continue the stateful session by sending a Set- + Cookie2 response header, rather than Set-Cookie. A server that does + not understand new-style cookies will simply ignore the Cookie2 + request header. + +9.2 Caching and HTTP/1.0 + + Some caches, such as those conforming to HTTP/1.0, will inevitably + cache the Set-Cookie2 and Set-Cookie headers, because there was no + mechanism to suppress caching of headers prior to HTTP/1.1. This + caching can lead to security problems. Documents transmitted by an + origin server along with Set-Cookie2 and Set-Cookie headers usually + either will be uncachable, or will be "pre-expired". As long as + caches obey instructions not to cache documents (following Expires: + or Pragma: no-cache (HTTP/1.0), or Cache- + control: no-cache (HTTP/1.1)) uncachable documents present no + problem. However, pre-expired documents may be stored in caches. + They require validation (a conditional GET) on each new request, but + some cache operators loosen the rules for their caches, and sometimes + serve expired documents without first validating them. This + combination of factors can lead to cookies meant for one user later + being sent to another user. The Set-Cookie2 and Set-Cookie headers + are stored in the cache, and, although the document is stale + (expired), the cache returns the document in response to later + requests, including cached headers. + +10. ACKNOWLEDGEMENTS + + This document really represents the collective efforts of the HTTP + Working Group of the IETF and, particularly, the following people, in + addition to the authors: Roy Fielding, Yaron Goland, Marc Hedlund, + Ted Hardie, Koen Holtman, Shel Kaphan, Rohit Khare, Foteos Macrides, + David W. Morris. + + + + + + + + +Kristol & Montulli Standards Track [Page 24] + +RFC 2965 HTTP State Management Mechanism October 2000 + + +11. AUTHORS' ADDRESSES + + David M. Kristol + Bell Laboratories, Lucent Technologies + 600 Mountain Ave. Room 2A-333 + Murray Hill, NJ 07974 + + Phone: (908) 582-2250 + Fax: (908) 582-1239 + EMail: dmk@bell-labs.com + + + Lou Montulli + Epinions.com, Inc. + 2037 Landings Dr. + Mountain View, CA 94301 + + EMail: lou@montulli.org + +12. REFERENCES + + [DMK95] Kristol, D.M., "Proposed HTTP State-Info Mechanism", + available at , September, 1995. + + [Netscape] "Persistent Client State -- HTTP Cookies", available at + , + undated. + + [RFC2109] Kristol, D. and L. Montulli, "HTTP State Management + Mechanism", RFC 2109, February 1997. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2279] Yergeau, F., "UTF-8, a transformation format of Unicode + and ISO-10646", RFC 2279, January 1998. + + [RFC2396] Berners-Lee, T., Fielding, R. and L. Masinter, "Uniform + Resource Identifiers (URI): Generic Syntax", RFC 2396, + August 1998. + + [RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and T. + Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", + RFC 2616, June 1999. + + + + + + +Kristol & Montulli Standards Track [Page 25] + +RFC 2965 HTTP State Management Mechanism October 2000 + + +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. + + 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. + + + + + + + + + + + + + + + + + + + +Kristol & Montulli Standards Track [Page 26] + diff --git a/standards/rfc3239.txt b/standards/rfc3239.txt new file mode 100644 index 000000000..edd131517 --- /dev/null +++ b/standards/rfc3239.txt @@ -0,0 +1,843 @@ + + + + + + +Network Working Group C. Kugler +Request for Comments: 3239 H. Lewis +Category: Informational IBM Corporation + T. Hastings + Xerox Corporation + February 2002 + + + Internet Printing Protocol (IPP): + Requirements for Job, Printer, and Device Administrative Operations + + +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 (2002). All Rights Reserved. + +Abstract + + This document specifies the requirements and uses cases for some + optional administrative operations for use with the Internet Printing + Protocol (IPP) version 1.0 and version 1.1. Some of these + administrative operations operate on the IPP Job and Printer objects. + The remaining operations operate on a new Device object that more + closely models a single output device. + +Table of Contents + + 1 Introduction.....................................................2 + 2 Terminology......................................................2 + 3 Requirements and Use Cases.......................................3 + 4 IANA Considerations.............................................10 + 5 Internationalization Considerations.............................10 + 6 Security Considerations.........................................10 + 7 References......................................................11 + Appendix A: Description of base IPP documents......................12 + Authors' Addresses.................................................14 + Full Copyright Statement...........................................15 + +List of Tables + + Table 1 - List of Printer Operations and corresponding Device + Operations ..................................................... 9 + + + +Kugler, Lewis & Hastings Informational [Page 1] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + +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 (for + a description of the base IPP documents, see Appendix A). This + document defines the requirements and use cases for additional + optional end user, operator, and administrator operations used to + control Job objects, Printer objects (see [RFC2911]) and a new Device + object. The new Device object more closely models a single output + device and has no notion of a job, while the Printer object models a + print service which understands jobs and may represent one or more + output devices. + + The scope of IPP is characterized in RFC 2567 [RFC2567] "Design Goals + for an Internet Printing Protocol". It is not the intent of this + document to revise or clarify this scope or conjecture as to the + degree of industry adoption or trends related to IPP within printing + systems. It is the intent of this document to extend the original + set of operations - in a similar fashion to the Set1 extensions which + referred to IPP/1.0 and were later incorporated into IPP/1.1. + +2 Terminology + + This section defines terminology used throughout this document and + the corresponding documents that define the Administrative operations + on Job, Printer, and Device objects. + + This document uses terms such as "client", "Printer", "Job", + "attributes", "keywords", and "support". These terms have special + meaning and are defined in the model terminology [RFC2911] section + 12.2. + + In addition, the following capitalized terms are defined: + + IPP Printer object (or Printer for short) - a software abstraction + defined by [RFC2911]. + + Printer Operation - an operation whose target is an IPP Printer + object and whose effect is on the Printer object. + + Output Device - the physical imaging mechanism that an IPP Printer + controls. Note: while this term is capitalized in this + specification (but not in [RFC2911]), there is no formal object + called an Output Device. + + + + + +Kugler, Lewis & Hastings Informational [Page 2] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + + Device Operation - an operation whose target is an IPP Printer + object and whose defined effect is on an Output Device. + + Output Device Fan-Out - a configuration in which an IPP Printer + controls more that one output-device. + + Printer fan-out - a configuration in which an IPP Printer object + controls more than one Subordinate IPP Printer object. + + Printer fan-in - a configuration in which an IPP Printer object is + controlled by more than one IPP Printer object. + + Subordinate Printer - an IPP Printer object that is controlled by + another IPP Printer object. Such a Subordinate Printer may + have one or more Subordinate Printers. + + Leaf Printer - a Subordinate Printer that has no Subordinate + Printers. + + Non-Leaf Printer - an IPP Printer object that has one or more + Subordinate Printers. + + Chained Printer - a Non-Leaf Printer that has exactly one + Subordinate Printer. + + Job Creation operations - IPP operations that create a Job object: + Print-Job, Print-URI, and Create-Job. + +3 Requirements and Use Cases + + The Administrative operations for Job and Printer objects will be + defined in one document [ipp-ops-set2]. The Administrative + operations for Device objects will be defined in a separate document. + The requirements are presented here together to show the parallelism. + + 1. Have separate operations for affecting the IPP Printer + versus affecting the Output Device, so its clear what the + intent of each is, and implementers can implement one or the + other or both. + + 2. Support fan-out of Printer objects. + + 3. Support fan-out of Output Devices. + + 4. Support fan-in of Printer objects, as long as it doesn't + make the semantics more complicated when not supporting + fan-in. + + + + +Kugler, Lewis & Hastings Informational [Page 3] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + + 5. Support fan-in of output objects, as long as it doesn't make + the semantics more complicated when not supporting fan-in. + + 6. Instead of having operation attributes that alter the + behavior of the operation significantly, have separate + operations, so that it is simple and clear to a client which + semantics the Printer is supporting (by querying the + "operations-supported" attribute) and it is simple to + describe the capabilities of a Printer implementation in + written documentation (just list the optional operations + supported). + + 7. Need a Printer Operation to prevent a Printer object from + accepting new IPP jobs, but currently accepted jobs continue + unaffected to be scheduled and processed. Need a companion + one to restore the Printer object to accept new IPP jobs. + + Usage: Operator is preparing to take the IPP Printer out of + service or to change the configuration of the IPP Printer. + + Suggested name and operations: Disable-Printer and Enable- + Printer + + 8. Need a Device Operation to prevent an Output Device from + accepting any new jobs from any job submission protocol and + a companion one to restore the Output Device to accepting + any jobs. + + Usage: Operator is preparing to take the Output Device out + of service. + + Suggested name and operations: Disable-Device and Enable + Device + + 9. Need a Printer Operation to stop the processing after the + current IPP job completes and not start processing any + additional IPP jobs (either by scheduling the jobs or + sending them to the Output Device), but continue to accept + new IPP jobs. Need a companion operation to start + processing/sending IPP jobs again. + + Usage: Operator wants to gracefully stop the IPP Printer at + the next job boundary. The Pause-Printer-After-Current-Job + operation is also invoked implicitly by the Deactivate- + Printer and the Shutdown-Printer Operations. + + Suggested name and operations: Pause-Printer-After- + Current-Job, (IPP/1.1) Resume-Printer + + + +Kugler, Lewis & Hastings Informational [Page 4] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + + 10. Need a Device Operation to stop the processing the current + job "immediately", no matter what protocol. Its like the + Pause button on the Output Device. This operation is for + emergencies. The stop point depends on implementation, but + can be mid page, end of page, end of sheet, or after a few + sheets for Output Devices that can't stop that quickly. The + paper path isn't run out. Need a companion operation to + start processing the current any-protocol job without losing + any thing. + + Usage: Operator sees something bad about to happen, such as + the paper is about to jam, or the toner is running out, or + the device is overheating or wants to add more paper. + + Suggested name and operations: Pause-Device-Now, Resume- + Device + + 11. Need a Printer Operation to stop the processing of IPP jobs + after all of the currently accepted jobs have been + processed, but any newly accepted jobs go into the + 'processing-held' state. + + Usage: This allows an operator to reconfigure the Output + Device in order to let jobs that are held waiting for + resources, such as special media, get a chance. Then the + operator uses another operation after reconfiguring. He + repeats the two operations to restore the Output Device to + its normal media. + + Suggested name and operations: Hold-New-Jobs, Release- + Held-New-Jobs + + 12. Need a Device Operation to stop processing the current any- + protocol job at a convenient point, such as after the + current copy (or end of job if last or only copy). Need a + companion operation to start processing the current any- + protocol job or next job without losing any thing. + + Usage: The operator wants to empty the output bin that is + near full. The paper path is run out. + + Suggested name and operations: Pause-Device-After-Current- + Copy, Resume-Device + + + + + + + + +Kugler, Lewis & Hastings Informational [Page 5] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + + 13. Need a Device Operation that always pauses on a device- + defined boundary, no matter how many copies, in order to not + break up a job. Need a companion operation to start + processing the current any-protocol job or next job without + losing any thing. + + Usage: The operator wants to empty the output bin that is + near full, but he doesn't want to break up a job in case it + has multiple copies. The paper path is run out. + + Suggested name and operations: Pause-Device-After-Current- + Job, Resume-Device + + 14. Need a Printer Operation that combines Disable-Printer, + Pause-Printer-After-Current-Job, and rejects all other Job, + Printer, and Device Operations, except Job and Printer + queries, System Administrator Set-Printer-Attributes, and + the companion operation to resume activity. In other words, + this operation makes the Printer a read-only object in a + graceful manner for end-users and the operator. + + Usage: The administrator wants to reconfigure the Printer + object using the Set-Printer-Attributes operation without + disturbing the current in process work, but wants to make + sure that the operator isn't also trying to change the + Printer object as part of running the Printer. + + Suggested name and operation: Deactivate-Printer, + Activate-Printer + + 15. Need a Device Operation that combines Disable-Device, + Pause-Device-After-Current-Job, and rejects all other Device + Operations, except Job and Printer queries and the companion + operation to resume activity. In other words, this + operation makes the Output Device a read-only object in a + graceful manner. + + Usage: The field service person wants to open up the device + without disturbing the current in process work, perhaps to + replace staples, or replace the toner cartridge. + + Suggested name and operation: Deactivate-Device, Activate- + Device + + + + + + + + +Kugler, Lewis & Hastings Informational [Page 6] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + + 16. Need a Printer Operation to recover from the IPP Printer + software that has gotten confused (run out of heap memory or + gotten into a state that it doesn't seem to be able to get + out of). This is a condition that shouldn't happen, but + does in real life. Any volatile information is saved if + possible before the software is re-initialized. No + companion operation is needed to undo this. We don't want + to go back to the "confused" state :-). + + Usage: The IPP Printer software has gotten confused or + isn't responding properly. + + Suggested name and operation: Restart-Printer + + 17. Need a Device Operation to recover from the Output Device + hardware and software that has gotten confused (gotten into + a state that it doesn't seem to be able to get out of, run + out of heap memory, etc.). This is a condition that + shouldn't happen, but does in real life. This is the same + and has the same options as the Printer MIB reset. No + companion operation is needed to undo this. We don't want + to go back to the "confused" state :-). + + Usage: The Output Device has gotten confused or need + resetting to some initial conditions. + + Suggested name and operation: Reset-Device + + 18. Need a Printer Operation to put the IPP Printer object out + of business with no way in the protocol to bring that + instantiation back to life (but see Startup-Printer which + brings up exactly one new instantiation to life with the + same URL). Any volatile information is saved if possible. + + Usage: The Printer is being moved or the building's power + is being shut off. + + Suggested name and operation: Shutdown-Printer + + 19. Need a Printer Operation to bring an IPP Printer to life + when there is an already running host. + + Usage: After the host is started (by means outside the IPP + protocol), the operator is able to ask the host to bring up + any number of Printer objects (that the host has been + configured in some way) each with distinct URLs. + + Suggested name and operation: Startup-Printer + + + +Kugler, Lewis & Hastings Informational [Page 7] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + + 20. Need a Device Operation to power off the Output Device after + writing out any software state. It is assumed that other + operations have more gracefully prepared the Output Device + for this drastic and immediate. There is no companion + Device Operation to bring the power back on. + + Usage: The Output Device is going to be moved, the power in + the building is going to be shutoff, the repair man has + arrived and needs to take the Output Device apart. + + Suggested name and operation: Power-Off-Device + + 21. Need a Device Operation to startup a powered-off device. + + Usage: After a Power-Off-Device, if the device can be + powered back up (possibly by an intervening host that + supports the Device Operation). + + Suggest name and operation: Power-On-Device + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kugler, Lewis & Hastings Informational [Page 8] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + + The tentative list of Printer and the corresponding Device Operations + is shown in Table 1: + + Table 1 - List of Printer Operations and corresponding Device + Operations + + Printer Operation Corresponding Device Operation + equivalent + + Disable-Printer Disable-Device + + Enable-Printer Enable-Device + + Pause-Printer (IPP/1.1 - [RFC2911] Pause-Device-Now + - one interpretation) + + no Pause-Device-After-Current-Copy + + Pause-Printer-After-Current-Job Pause-Device-After-Current-Job + + Resume-Printer (IPP/1.1 - Resume-Device + [RFC2911]) + + Hold-New-Jobs no + + Release-Held-New-Jobs no + + Deactivate-Printer Deactivate-Device + + Activate-Printer Activate-Device + + Purge-Jobs (IPP/1.1 - [RFC2911]) Purge-Device + + Restart-Printer Reset-Device + + Shutdown-Printer Power-Off-Device + + Startup-Printer Power-On-Device + + There are no conformance dependencies between Printer Operations and + Device Operations. Either may be supported without supporting the + corresponding operations. + + + + + + + + + +Kugler, Lewis & Hastings Informational [Page 9] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + +4 IANA Considerations + + This document does not define anything to be registered. When a + document is produced that defines operations that meet the + requirements in this document, those operations will be registered + according to the procedures in [RFC2911] section 6.4. + +5 Internationalization Considerations + + This document has the same localization considerations as the + [RFC2911]. + +6 Security Considerations + + This document defines the requirements for operations that are + intended to be used by an operator or system administrator. These + operations, when defined, would affect how the Printer behaves and + establish policy and/or operating behavior that ordinary users + shouldn't be able to perform. Printer implementations that support + such operations should authenticate users and authorized them as + being an operator or a system administrator for the system. + Otherwise, unprivileged users could affect the policy and behavior of + IPP Printers, thereby affecting other users. Similarly clients that + supports such operations should be prepared to provide the necessary + authentication information. See the security provisions in [RFC2911] + for authentication, such as TLS. + + + + + + + + + + + + + + + + + + + + + + + + + +Kugler, Lewis & Hastings Informational [Page 10] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + +7 References + + [ipp-ntfy] Herriot, R., Hastings, T., Isaacson, S., Martin, J., + deBry, R., Shepherd, M. and R. Bergman, "Internet + Printing Protocol/1.1: IPP Event Notifications and + Subscriptions", Work in Progress. + + [ipp-ops-set2] Kugler, C., Hastings, T. and H. Lewis, "Internet + Printing Protocol (IPP): Job and Printer + Administrative Operations", Work in Progress. + + [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. and 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. 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. + + [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Tuner, + "Internet Printing Protocol/1.1: Encoding and + Transport", RFC 2910, September 2000. + + [RFC2911] deBry, R., Hastings, T., Herriot, R., Isaacson, S. and + P. Powell, "Internet Printing Protocol/1.0: Model and + Semantics", RFC 2911, September 2000. + + [RFC3196] Hastings, T., Manros, C., Zehler, P., Kuger, C. and H. + Holst, "Internet Printing Protocol/1.1: Implementer's + Guide", RFC 3196, November 2001. + + + + + + +Kugler, Lewis & Hastings Informational [Page 11] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + +Appendix A: Description of base IPP documents + + The base 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 [RFC3196] + Mapping between LPD and IPP Protocols [RFC2569] + Internet Printing Protocol (IPP): IPP Event Notifications and + Subscriptions [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 the 'ippget' scheme for + identifying IPP printers and jobs. + + + + + + + +Kugler, Lewis & Hastings Informational [Page 12] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + + 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 "IPP Event Notifications and Subscriptions" document defines an + extension to IPP/1.0 [RFC2566, RFC2565] and IPP/1.1 [RFC2911, + RFC2910]. This extension allows a client to subscribe to printing + related Events and defines the semantics for delivering asynchronous + + Event Notifications to the specified Notification Recipient via a + specified Delivery Method (i.e., protocols) defined in (separate) + Delivery Method documents. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Kugler, Lewis & Hastings Informational [Page 13] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + +Authors' Addresses + + Carl Kugler + IBM + Boulder CO + + Phone: (303) 924-5060 + EMail: 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 + EMail: hastings@cp10.es.xerox.com + + + Harry Lewis + IBM + Boulder CO + + Phone: (303) 924-5337 + EMail: harryl@us.ibm.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 + the IPP Mailing List in order to participate in any discussions of + clarification issues and review of registration proposals for + additional attributes and values. In order to reduce spam the + mailing list rejects mail from non-subscribers, so you must subscribe + to the mailing list in order to send a question or comment to the + mailing list. + + + + + + +Kugler, Lewis & Hastings Informational [Page 14] + +RFC 3239 IPP: Req. for Job and Printer Admin Ops February 2002 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). 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. + + + + + + + + + + + + + + + + + + + +Kugler, Lewis & Hastings Informational [Page 15] + diff --git a/standards/rfc3380.txt b/standards/rfc3380.txt new file mode 100644 index 000000000..6ea6c07ce --- /dev/null +++ b/standards/rfc3380.txt @@ -0,0 +1,3307 @@ + + + + + + +Network Working Group T. Hastings +Request for Comments: 3380 Xerox Corporation +Updates: 2910, 2911 R. Herriot +Category: Standards Track Consultant + C. Kugler + H. Lewis + IBM Corporation + September 2002 + + + Internet Printing Protocol (IPP): + Job and Printer Set Operations + +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 (2002). All Rights Reserved. + +Abstract + + This document is an OPTIONAL extension to the Internet Printing + Protocol (IPP/1.0 and IPP/1.1). This document specifies 3 additional + OPTIONAL operations for use with the Internet Printing Protocol/1.0 + (IPP) and IPP/1.1. 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 Get- + Printer-Supported-Values administrative operation returns values that + the IPP Printer will accept for setting its "xxx-supported" + attributes. + + + + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 1] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +Table of Contents + + 1 Introduction......................................................4 + 2 Terminology.......................................................5 + 2.1 Conformance Terminology.........................................5 + 2.2 Other terminology...............................................5 + 3 Requirements and Use Cases........................................5 + 4 Definition of the Set operations..................................6 + 4.1 Set-Printer-Attributes Operation................................7 + 4.1.1 Settable and READ-ONLY Printer Description attributes.........9 + 4.1.2 Set-Printer-Attributes Request...............................10 + 4.1.3 Set-Printer-Attributes Response..............................12 + 4.2 Set-Job-Attributes Operation...................................13 + 4.2.1 Settable and READ-ONLY Job Description attributes............16 + 4.2.2 Set-Job-Attributes Request...................................17 + 4.2.3 Set-Job-Attributes Response..................................18 + 4.3 Get-Printer-Supported-Values Operation.........................19 + 4.3.1 Definition of the usage of the 'admin-define' out-of-band + attribute value..............................................20 + 5 New Operation attributes.........................................22 + 5.1 printer-message-from-operator (text(127))......................22 + 5.2 job-message-from-operator (text(127))..........................23 + 6 New Printer Description Attributes...............................24 + 6.1 printer-settable-attributes-supported (1setOf type2 keyword)...24 + 6.2 job-settable-attributes-supported (1setOf type2 keyword).......25 + 6.3 document-format-varying-attributes (1setOf type2 keyword)......25 + 6.4 printer-message-time (integer(MIN:MAX))........................25 + 6.5 printer-message-date-time (dateTime)...........................26 + 6.6 printer-xri-supported (1setOf collection)......................26 + 6.7 xri-uri-scheme-supported (1setOf uriScheme)....................28 + 6.8 xri-authentication-supported (1setOf type2 keyword)............29 + 6.9 xri-security-supported (1setOf type2 keyword)..................29 + 7 Additional status codes..........................................29 + 7.1 client-error-attributes-not-settable (0x0413)..................29 + 8 Additional out-of-band values....................................30 + 8.1 'not-settable' out-of-band value...............................30 + 8.1.1 Encoding of the 'not-settable' out-of-band attribute value...30 + 8.2 'delete-attribute' out-of-band value...........................30 + 8.2.1 Encoding of the 'delete-attribute' out-of-band value.........31 + 8.3 'admin-define' out-of-band attribute value.....................31 + 8.3.1 Encoding of the 'admin-define' out-of-band attribute value...32 + 9 New Values for Existing Printer Description Attributes...........33 + 9.1 operations-supported (1setOf type2 enum).......................33 + 10 Conformance Requirements........................................33 + 11 IANA Considerations.............................................34 + 11.1 Operation Registrations.......................................35 + 11.2 Additional Enum Attribute Value Registrations for the + "operations-supported" Printer Attribute......................35 + + + +Hastings, et. al. Standards Track [Page 2] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 11.3 Attribute Registrations.......................................35 + 11.4 Status code Registrations.....................................36 + 11.5 Out-of-band Attribute Value Registrations.....................36 + 12 Internationalization Considerations.............................37 + 13 Security Considerations.........................................37 + 14 References......................................................38 + 14.1 Normative References..........................................38 + 14.2 Informative References........................................38 + Appendix A: Allowed Values for Set-Printer-Attributes and Set-Job- + Attributes requests (Normative)........................39 + Appendix B: Attributes returned from Get-Printer-Supported-Values + (Normative)............................................50 + Appendix C: Description of the Base IPP Documents (Informative)....55 + Authors' Addresses.................................................56 + Full Copyright Statement...........................................58 + +Table of Tables + + Table 1 - Operation-Id assignments.................................7 + Table 2 - Job State Transition Table for the Set-Job-Attributes + operation ..............................................15 + Table 3 - Member attributes of "printer-xri-supported" (1setOf + collection) ............................................27 + Table 4 - Operation-id assignments................................33 + Table 5 - Validation rules for 'Any of "xxx-supported" '..........40 + Table 6 - Validation rules for 'From Get-Printer-Supported-Values'41 + Table 7 - Values allowed for Job Template Attributes in the Set-Job- + Attributes Operation ...................................42 + Table 8 - Values allowed for Job Description Attributes in the Set- + Job-Attributes Operation ...............................43 + Table 9 - Values allowed for Printer Job Template Attributes in the + Set-Printer-Attributes Operation .......................44 + Table 10 - Values allowed for Printer Description Attributes in the + Set-Printer-Attributes Operation .......................47 + Table 11 - Printer Job Template Attributes returned from Get-Printer- + Supported-Values .......................................51 + Table 12 - Printer Job Template Attributes returned from Get-Printer- + Supported-Values .......................................51 + Table 13 - Printer Description Attributes returned from Get-Printer- + Supported-Values .......................................51 + Table 14 - Printer Job Template Attributes returned from Get-Printer- + Supported-Values .......................................52 + Table 15 - Printer Job Template Attributes returned from Get-Printer- + Supported-Values .......................................52 + Table 16 - Printer Description Attributes returned from Get-Printer- + Supported-Values .......................................53 + + + + + +Hastings, et. al. Standards Track [Page 3] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +1 Introduction + + This document is an OPTIONAL extension to IPP/1.0 [RFC2565, RFC2566] + and IPP/1.1 [RFC2911, RFC2910]. For a description of the base IPP + documents see Appendix C. + + 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 Get-Printer-Supported-Values + administrator 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. + + 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) + + 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. + + + + + +Hastings, et. al. Standards Track [Page 4] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + A Printer implementation can make the value of some attributes + dependent on the document-format, e.g., "resolution-supported". + +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 as defined in BCP 14, RFC 2119 [RFC2119] and [RFC2911] + section 12.1. If an implementation supports the extension defined in + this document, then these terms apply; otherwise, they do not. These + terms define conformance to this document only; they do not affect + conformance to other documents, unless explicitly stated otherwise. + +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. Standards Track [Page 5] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 operations (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 the IPP/1.1 Model and Semantics document [RFC2911], + section 3.1. + + The Set-Job-Attributes operations (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 + 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 + + + + + +Hastings, et. al. Standards Track [Page 6] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + "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- + 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. + + + + + +Hastings, et. al. Standards Track [Page 7] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 the 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 8.3 and + Appendix A). + + 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 are 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 + 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" attributes 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 + + + +Hastings, et. al. Standards Track [Page 8] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 the 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. + + 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 examples: + + 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, + + + +Hastings, et. al. Standards Track [Page 9] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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, + 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. + + + + + + +Hastings, et. al. Standards Track [Page 10] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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. + + 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 + + + +Hastings, et. al. Standards Track [Page 11] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 yet been + configured, and so assumed the 'no-value' out-of-band value (see + [RFC2911] section 4.1), the supplied value(s) replaces 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 3.1.6 + and 13. + + 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 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 returns 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). + + + + + + + +Hastings, et. al. Standards Track [Page 12] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 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 + + + +Hastings, et. al. Standards Track [Page 13] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 8.3 and Appendix A). 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 + 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 + + + + + +Hastings, et. al. Standards Track [Page 14] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 operation 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. + + Table 2 - Job State Transition Table for the Set-Job-Attributes + operation + + Current New IPP object's response status code + "job-state" "job-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' + + + +Hastings, et. al. Standards Track [Page 15] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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. + +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" + Job Description attribute in Group 2 in the Set-Job-Attributes + request, then the Printer MUST set the "job-message-from-operator" + Job Description attribute to this new value. + + If the Printer supports the Set-Job-Attributes operation, then it + SHOULD support the 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). + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 16] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +4.2.2 Set-Job-Attributes Request + + The following sets of attributes are part of the Set-Job-Attributes + Request: + + Group 1: Operation Attributes + + Natural Language and Character Set: + The "attributes-charset" and "attributes-natural-language" + attributes as described in [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 defines 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. + + + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 17] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +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 3.1.6 + and 13. + + 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 returns 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). + + + + +Hastings, et. al. Standards Track [Page 18] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 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],y 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- + + + + + +Hastings, et. al. Standards Track [Page 19] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 + 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. + + + + +Hastings, et. al. Standards Track [Page 20] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + For example, if the Get-Printer-Supported-Values operation returns + several keywords as the value of the "media-supported" attribute, + 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. Standards Track [Page 21] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +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 Operation 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, + + 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. + + + + + + + +Hastings, et. al. Standards Track [Page 22] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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). + + 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. + + + + +Hastings, et. al. Standards Track [Page 23] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 Description 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 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. + + + + + + +Hastings, et. al. Standards Track [Page 24] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +6.2 job-settable-attributes-supported (1setOf type2 keyword) + + This REQUIRED READ-ONLY Printer Description 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 are 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 + 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" Printer Description attribute was + last set. + + + + + + +Hastings, et. al. Standards Track [Page 25] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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" Printer Description + 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. + +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 + [RFC3382]), 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 + + + + + +Hastings, et. al. Standards Track [Page 26] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 "printer-xri-supported" (1setOf collection) attribute can + be put into a directory schema that requires a single text string + value, such as could be used with SLPv2 [RFC2608], [RFC2609] or + LDAPv3 [RFC2251], [RFC2252], [RFC2926], by using suitable delimiting + characters to separate member attributes of the collection and/or + terminating collection values. + + The member attributes of the "printer-xri-supported" (1setOf + collection) are given in Table 3. + + 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 (type2 keyword) yes yes + + xri-security (type2 keyword) yes yes + + 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 + + + +Hastings, et. al. Standards Track [Page 27] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 + 16. + + For example: + + "printer-xri-supported = + { "xri-uri" = ipp://abc.com/p1 + "xri-authentication" = basic + "xri-security" = tls + }, + { "xri-uri" = ipp://abc.com/p2 + "xri-authentication" = digest + "xri-security" = tls + }, + { "xri-uri" = ipp://abc.com/p3 + "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/p2, + ipp://abc.com/p3 } + "uri-authentication-supported" = { basic, digest, none } + "uri-security-supported" = { tls, tls, none } + +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 "printer-xri-supported" (1setOf collection) Printer Description + attribute (see section 6.6). + + A Printer MUST support this attribute if it supports the setting of + the "printer-xri-supported" (1setOf collection) with the Set- + Printer-Attributes operation. + + + + + + + + +Hastings, et. al. Standards Track [Page 28] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +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 "printer-xri-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 "printer-xri-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). + 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. + + + + + + + + +Hastings, et. al. Standards Track [Page 29] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +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 responses + 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. + +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. + + + + +Hastings, et. al. Standards Track [Page 30] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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. + +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 values 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 + + + + + +Hastings, et. al. Standards Track [Page 31] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 + 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. + + + + + + +Hastings, et. al. Standards Track [Page 32] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +9 New Values for Existing Printer Description Attributes + + This section contains those attributes for which additional values + are added. + +9.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 + + 0x0013 Set-Printer-Attributes + + 0x0014 Set-Job-Attributes + + 0x0015 Get-Printer-Supported-Values + +10 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. + + 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). + + + + +Hastings, et. al. Standards Track [Page 33] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 5. if the "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. + + 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. + + + + + + + + + +Hastings, et. al. Standards Track [Page 34] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +11 IANA Considerations + + This section contains registration information for IANA to add to the + various IPP Registries according to the procedures defined in RFC + 2911 [RFC2911], section 6. The resulting registrations will be + published in the http://www.iana.org/assignments/ipp-registrations + registry. + +11.1 Operation Registrations + + The following table lists all of the operations defined in this + document. These are to be registered according to the procedures + defined in RFC 2911 [RFC2911], section 6.4. + + Operations: Ref. Section: + Set-Printer-Attributes RFC 3380 4.1 + Set-Job-Attributes RFC 3380 4.2 + Get-Printer-Supported-Values RFC 3380 4.3 + +11.2 Additional Enum Attribute Value Registrations for the + "operations-supported" Printer Attribute + + The following table lists all the new enum attribute values defined + in this document as additional type2 enum values for use with the + "operations-supported" Printer Description attribute. These are to + be registered according to the procedures defined in RFC 2911 [RFC + 2911], section 6.1. + + Enum Attribute Values: Value Ref. Section: + Set-Printer-Attributes 0x0013 RFC 3380 4 + Set-Job-Attributes 0x0014 RFC 3380 4 + Get-Printer-Supported-Values 0x0015 RFC 3380 4 + + + + + + + + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 35] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +11.3 Keyword attribute value registrations + + The following table lists all of the attributes defined in this + standard which have keywords values defined: + + printer-settable-attributes-supported (1setOf type2 keyword) + RFC 3380 6.1 + none RFC 3380 6.1 + + job-settable-attributes-supported (1setOf type2 keyword) + RFC 3380 6.2 + none RFC 3380 6.2 + + document-format-varying-attributes (1setOf type2 keyword) + RFC 3380 6.3 + none + + xri-security-supported (1setOf type2 keyword) RFC 3380 6.9 + none RFC 2911 4.4.3 + ssl3 RFC 2911 4.4.3 + tls' RFC 2911 4.4.3 + xri-authentication-supported (1setOf type2 keyword) + none RFC 2911 4.4.2 + requesting-user-name RFC 2911 4.4.2 + basic RFC 2911 4.4.2 + digest RFC 2911 4.4.2 + certificate RFC 2911 4.4.2 + + + + + + + + + + + + + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 36] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +11.4 Attribute Registrations + + The following table lists all of the attributes defined in this + document. These are to be registered according to the procedures in + RFC 2911 [RFC2911], section 6.2. + + Operation attributes: Ref. Section: + printer-message-from-operator (text(127)) RFC 3380 5.1 + job-message-from-operator (text(127)) RFC 3380 5.2 + + Printer Description attributes: Ref. Section: + printer-settable-attributes-supported (1setOf type2 keyword) + RFC 3380 6.1 + job-settable-attributes-supported (1setOf type2 keyword) + RFC 3380 6.2 + document-format-varying-attributes (1setOf type2 keyword) + RFC 3380 6.3 + printer-message-time (integer(MIN:MAX)) RFC 3380 6.4 + printer-message-date-time (dateTime) RFC 3380 6.5 + printer-xri-supported (1setOf collection) RFC 3380 6.6 + xri-uri (uri) RFC 3380 6.6 + xri-authentication (type2 keyword) RFC 3380 6.6 + xri-security (type2 keyword) RFC 3380 6.6 + xri-uri-scheme-supported (1setOf uriScheme) RFC 3380 6.7 + xri-authentication-supported (1setOf type2 keyword) 6.8 + xri-security-supported (1setOf type2 keyword) RFC 3380 6.9 + +11.5 Status code Registrations + + The following table lists the status code defined in this document. + This is to be registered according to the procedures in RFC 2911 + [RFC2911], section 6.6. + + Status codes: Ref. Section: + client-error-attributes-not-settable (0x0413) RFC 3380 7.1 + +11.6 Out-of-band Attribute Value Registrations + + The following table lists all of the out-of-band attribute values + defined in this document. These are to be registered according to + the procedures in RFC 2911 [RFC2911] section 6.7. + + Value: Out-of-band Attribute value name: Ref. Section: + 0x15 not-settable RFC 3380 8.1 + 0x16 delete-attribute RFC 3380 8.2 + 0x17 admin-define RFC 3380 8.3 + + + + + +Hastings, et. al. Standards Track [Page 37] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +12 Internationalization Considerations + + This document has the same localization considerations as [RFC2911]. + +13 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 + addition, store the Client Authentication with each Job so that only + the job owner End User can modify his/her own job. + + + + + + + + +Hastings, et. al. Standards Track [Page 38] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +14 References + +14.1 Normative References + + [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. + + [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Turner, + "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.0: Model and + Semantics", RFC 2911, September 2000. + + [RFC3382] deBry, R., Hastings, T., Herriot, R., Ocke, K. and P. + Zehler, "Internet Printing Protocol (IPP): The + 'collection' attribute syntax", RFC 3382, September 2002. + +14.2 Informative References + + [RFC2251] Wahl, M., Howes, T. abd S. Kille, "Lightweight Directory + Access Protocol (v3)", RFC 2251, December 1997. + + [RFC2252] Wahl, M., Coulbeck, A., Howes, T. and S. Kille, + "Lightweight Directory Access Protocol (v3): Attribute + Syntax Definitions", RFC 2252, December 1997. + + [RFC2608] Guttman, E., Perkins, C., Veizades, J. and M. Day, + "Service Location Protocol, Version 2", RFC 2608, June + 1999. + + [RFC2609] Guttman, E., Perkins, C. and J. Kempf, "Service Templates + and service: Schemes", RFC 2609, June 1999. + + [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C. and H. + Holst, "Internet Printing Protocol/1.1: Implementor's + Guide", RFC 3196, November 2001. + + + + + + + + +Hastings, et. al. Standards Track [Page 39] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +Appendix A: Allowed Values for Set-Printer-Attributes and + Set-Job-Attributes requests (Normative) + + 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 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 + value(s) are obtained from a Get-Printer-Supported-Values + response (see the tables in this Appendix). + + + + + + + + + + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 40] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Table 5 - 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" + [RFC3196]. + + 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 6 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. Standards Track [Page 41] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Table 6 - Validation rules for 'From Get-Printer-Supported-Values' + + Type of - + "xxx" supported" value Validates if: + value to + be set Type of "xxx + + + 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" + [RFC3196]. + + 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'. 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. Standards Track [Page 42] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Table 7 - 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. Standards Track [Page 43] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Table 8 - 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. Standards Track [Page 44] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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) + + Table 9 - 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" + + + +Hastings, et. al. Standards Track [Page 45] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Printer Job Template Attributes Values allowed + for Set + + 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 + + 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 + + + + +Hastings, et. al. Standards Track [Page 46] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Printer Job Template Attributes Values allowed + for Set + + 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 + + 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. Standards Track [Page 47] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Table 10 - 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 (type2 keyword) any keyword of + "xri- + authentication- + supported" from + Get-Printer- + Attributes + + xri-security (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) + + + + + + + + +Hastings, et. al. Standards Track [Page 48] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Printer Description Attributes Values allowed for + Set + + printer-name (name(127)) Any name(127) + + 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 + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 49] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Printer Description Attributes Values allowed for + Set + + natural-language-configured Any of "xxx- + (naturalLanguage) supported", use + "generated-natural- + language-supported" + + generated-natural-language-supported From Get-Printer- + (1setOf naturalLanguage) Supported-Values + + 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 + + + + + + + +Hastings, et. al. Standards Track [Page 50] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Printer Description Attributes Values allowed for + Set + + 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 + + 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. + +Appendix B: Attributes returned from Get-Printer-Supported-Values + (Normative) + + 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. Standards Track [Page 51] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Table 11 - 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 12 - 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. + + Table 13 - 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 values returned by the Get- + Printer-Supported-Values operation. + + + + + + + + + +Hastings, et. al. Standards Track [Page 52] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Table 14 - 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. + + Table 15 - 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) + + + + + + +Hastings, et. al. Standards Track [Page 53] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Printer Job Template Attributes Values Returned + + 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. + + Table 16 - 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 + + printer-xri-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 + + + + +Hastings, et. al. Standards Track [Page 54] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + Printer Description Attributes Values allowed for + Set + + 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 + + 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. + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 55] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +Appendix C: Description of the Base IPP Documents (Informative) + + The base 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 [RFC3196] + 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 [RFC2566, RFC2565]. A few OPTIONAL operator + operations have been added to IPP/1.1 [RFC2911, RFC2910]. + + 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 IPP 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. 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 "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 also 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 the 'ipp' scheme 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 + + + + +Hastings, et. al. Standards Track [Page 56] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 are 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. + +Authors' Addresses + + Carl Kugler + IBM + P.O. Box 1900 + Boulder, CO 80301-9191 + + Phone: (303) 924-5060 + EMail: 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 + EMail: hastings@cp10.es.xerox.com + + + Robert Herriot + Consultant + 706 Colorado Ave + Palo Alto, CA 94303 + + Phone: 650-327-4466 + Fax: 650-327-4466 + EMail: bob@Herriot.com + + + Harry Lewis + IBM + 6300 Diagonal Hwy. + Boulder, CO 80301-9191 + + Phone: (303) 924-5337 + EMail: harryl@us.ibm.com + + + + + +Hastings, et. al. Standards Track [Page 57] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + + 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 + the IPP Mailing List in order to participate in any discussions of + clarification issues and review of registration proposals for + additional attributes and values. In order to reduce spam the + mailing list rejects mail from non-subscribers, so you must subscribe + to the mailing list in order to send a question or comment to the + mailing list. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 58] + +RFC 3380 IPP: Job and Printer Set Operations September 2002 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). 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 59] + diff --git a/standards/rfc3381.txt b/standards/rfc3381.txt new file mode 100644 index 000000000..d7fd60f81 --- /dev/null +++ b/standards/rfc3381.txt @@ -0,0 +1,955 @@ + + + + + + +Network Working Group T. Hastings +Request for Comments: 3381 Xerox Corporation +Updates: 2910 H. Lewis +Category: Standards Track IBM Printing Company + R. Bergman + Hitachi Koki Imaging Solutions + September 2002 + + + Internet Printing Protocol (IPP): + Job Progress Attributes + +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 (2002). All Rights Reserved. + +Abstract + + This document defines four new Job Description attributes for + monitoring job progress to be registered as OPTIONAL extensions to + the Internet Printing Protocol (IPP/1.0 and IPP/1.1). These + attributes are drawn from the PWG Job Monitoring MIB. 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. + + + + + + + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 1] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + +Table of Contents + + 1 Introduction.....................................................2 + 2 Terminology......................................................2 + 2.1 Conformance Terminology........................................4 + 2.2 Other terminology..............................................4 + 3 Job Template attributes..........................................4 + 3.1 sheet-collate (type2 keyword)..................................4 + 4 IPP Job Description attributes for monitoring Job Progress.......6 + 4.1 job-collation-type (type2 enum)................................9 + 4.2 sheet-completed-copy-number (integer(0:MAX))..................11 + 4.3 sheet-completed-document-number (integer(0:MAX))..............11 + 4.4 impressions-completed-current-copy (integer(0:MAX))...........11 + 5 Conformance Requirements........................................11 + 6 IANA Considerations.............................................12 + 6.1 Attributes.................................................... + 6.2 Keyword Attribute Values...................................... + 6.3 Enum Attribute Values......................................... + 7 Internationalization Considerations.............................12 + 8 Security Considerations.........................................12 + 9 References......................................................12 + 10 Description of the Base IPP Documents..........................13 + 11 Authors' Addresses.............................................15 + 12 Full Copyright Statement.......................................16 + +1 Introduction + + This document defines four new Job Description attributes for + monitoring job progress to be registered as OPTIONAL extensions to + IPP/1.0 [RFC2566] and IPP/1.1 [RFC2911]. These attributes are drawn + from the PWG Job Monitoring MIB [RFC2707]. See section 10 for a + description of the base IPP documents. 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, et. al. Standards Track [Page 2] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + +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, as defined in RFC 2119 [RFC2119] and [RFC2911] section + 12.1. If an implementation supports the extension defined in this + document, then these terms apply; otherwise, they do not. These + terms define conformance to this document only; they do not affect + conformance to other documents, unless explicitly stated otherwise. + +2.2 Other terminology + + This document uses terms such as Job object (or Job), IPP Printer + object (or Printer), "operation", "attribute", "keyword", "support", + and "impression". These terms have special meaning and are defined + in the model terminology [RFC2911], section 12.2. + +3 Job Template attributes + +3.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. + + + +Hastings, et. al. Standards Track [Page 3] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + 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 is 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] are 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 + 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". + + + + + + + + + + + + + + + + +Hastings, et. al. Standards Track [Page 4] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + The following table describes the interaction of "sheet-collate" with + multiple document handling. + + "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". + + + + + + +Hastings, et. al. Standards Track [Page 5] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + From the above table it is obvious that the implicit value of the + "sheet-collate" attribute in a printer that does not support the + "sheet-collate" attribute, is 'collated.' The semantics of + "multiple-document-handling" are otherwise nonsensical in the case + of separate documents. + +4 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 as + 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 the processing of each sheet + is completed. 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. + + + + + + + +Hastings, et. al. Standards Track [Page 6] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + 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: + + "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, et. al. Standards Track [Page 7] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + "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, et. al. Standards Track [Page 8] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + "job-collation-type" = 'uncollated-documents(5)' + + "job- "impressions- "sheet- "sheet- + impressions- completed- completed- completed- + completed" current-copy" copy-t 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 + +4.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 the 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 3.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. If the device has an output bin collator, + the 'uncollated-sheets(3)' value may actually + + + +Hastings, et. al. Standards Track [Page 9] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + 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 from 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 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 made + 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. + + + + + + + + + + +Hastings, et. al. Standards Track [Page 10] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + +4.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 + 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]. + +4.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 job SHOULD NOT + implement this attribute. + +4.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 MUST be reset to 0 for each document in the job and for + each document copy. + +5 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 client and/or a Printer + to support, so that client and Printer implementers MAY implement any + combination of these attributes. + + + + + + + +Hastings, et. al. Standards Track [Page 11] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + +6 IANA Considerations + + This section contains registration information for IANA to add to the + IPP Registry according to the procedures defined in RFC 2911 + [RFC2911], section 6. The resulting registrations will be published + in the http://www.iana.org/assignments/ipp-registrations registry. + +6.1 Attributes + + Job Template attributes: Ref. Section: + sheet-collate (type2 keyword) RFC 3381 3.1 + sheet-default (type2 keyword) RFC 3381 3.1 + sheet-supported (1setOf type2 keyword) RFC 3381 3.1 + + Job Description attributes: Ref. Section: + job-collation-type (type2 enum) RFC 3381 4.1 + sheet-completed-copy-number (integer(0:MAX)) RFC 3381 4.2 + sheet-completed-document-number (integer(0:MAX))RFC 3381 4.3 + impressions-completed-current-copy (integer(0:MAX)) + RFC 3381 4.4 +6.2 Keyword Attribute Values + + The following table provides registration information for all of the + attributes defined in this document that have keyword values. These + keywords are to be registered according to the procedures defined in + RFC 2911 [RFC2911] section 6.1. + + sheet-collate (type2 keyword) RFC 3381 3.1 + 'uncollated' RFC 3381 3.1 + 'collated' RFC 3381 3.1 + sheet-collate-default (type2 keyword) RFC 3381 3.1 + See "sheet-collate" attribute + sheet-collate-supported (1setOf type2 keyword) RFC 3381 3.1 + See "sheet-collate" attribute + +6.3 Enum Attribute Values + + The following table provides registration information for all of the + attributes defined in this document that have enum values. These + enums are to be registered according to the procedures defined in RFC + 2911 [RFC2911] section 6.1. + + job-collation-type (type2 enum) RFC 3381 4.1 + '1' 'other' RFC 3381 4.1 + '2' 'unknown' RFC 3381 4.1 + '3' 'uncollated-sheets' RFC 3381 4.1 + '4' 'collated-documents' RFC 3381 4.1 + '5' 'uncollated-documents' RFC 3381 4.1 + + + +Hastings, et. al. Standards Track [Page 12] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + +7 Internationalization Considerations + + The IPP extensions defined in this document require the same + internationalization considerations as any of the Job Template and + Job Description attributes defined in IPP/1.1 [RFC2911]. + +8 Security Considerations + + The IPP extensions defined in this document require the same security + considerations as any of the Job Template attributes and Job + Description attributes defined in IPP/1.1 [RFC2911]. + +9 References + +9.1 Normative References + + [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Turner, + "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. + +9.2 Informative References + + [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, F.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. + + [RFC2707] Bergman, R., Hastings, T., Isaacson, S. and H. Lewis, "PWG + Job Monitoring MIB - V1", RFC 2707, November 1999. + + + + +Hastings, et. al. Standards Track [Page 13] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C. and H. + Holst, "Internet Printing Protocol/1.1: Implementor's + Guide", RFC 3196, November 2001. + + [ipp-ntfy] Herriot, R., Hastings, T., et. al., "Internet Printing + Protocol (IPP): Event Notification and Subscriptions", + Work in Progress. + +10 Description of the Base IPP Documents + + The base 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 [RFC3196] + 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 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 [RFC2566, RFC2565]. A few OPTIONAL operator + operations have been added to IPP/1.1 [RFC2911, RFC2910]. + + 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 IPP 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. 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 "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 also 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 + + + +Hastings, et. al. Standards Track [Page 14] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + + "application/ipp". This document defines the 'ipp' scheme 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. + + In addition to the base IPP documents, the "Event Notification + Specification" document [ipp-ntfy] 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, et. al. Standards Track [Page 15] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + +11 Authors' Addresses + + 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 + + Harry Lewis + IBM + 6300 Diagonal Hwy + Boulder, CO 80301-9191 + + Phone: (303) 924-5337 + EMail: 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 + + 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 + the IPP Mailing List in order to participate in any discussions of + clarification issues and review of registration proposals for + additional attributes and values. In order to reduce spam, the + mailing list rejects mail from non-subscribers, so you must subscribe + to the mailing list in order to send a question or comment to the + mailing list. + + + + + +Hastings, et. al. Standards Track [Page 16] + +RFC 3381 IPP: Job Progress Attributes September 2002 + + +12 Full Copyright Statement + + Copyright (C) The Internet Society (2002). 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 17] + diff --git a/standards/rfc3382.txt b/standards/rfc3382.txt new file mode 100644 index 000000000..4181c5bc5 --- /dev/null +++ b/standards/rfc3382.txt @@ -0,0 +1,2131 @@ + + + + + + +Network Working Group R. deBry +Request for Comments: 3382 Utah Valley State College +Updates: 2910, 2911 R. Herriot +Category: Standards Track Consultant + T. Hastings + K. Ocke + P. Zehler + Xerox Corporation + September 2002 + + + Internet Printing Protocol (IPP): + The 'collection' attribute 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 (2002). All Rights Reserved. + +Abstract + + This document specifies an OPTIONAL attribute syntax called + 'collection' for use with the Internet Printing Protocol (IPP/1.0 and + IPP/1.1). 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. + +Table of Contents + + 1 Introduction.....................................................3 + 1.1 Problem Statement..............................................3 + 1.2 Solution.......................................................3 + 2 Terminology......................................................4 + 2.1 Conformance Terminology........................................4 + 2.2 Other terminology..............................................5 + 3 Definition of a Collection Attribute.............................5 + 3.1 Information to Include.........................................5 + + + +deBry, et. al. Standards Track [Page 1] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 3.2 Nested Collections.............................................9 + 4 Collection Attributes as Attributes in Operations................9 + 4.1 General Rules..................................................9 + 4.2 Unsupported Values.............................................9 + 5 Example definition of a collection attribute.....................9 + 5.1 media-col (collection)........................................10 + 5.1.1 media-color (type3 keyword | name(MAX)......................10 + 5.1.2 media-size (collection).....................................11 + 5.2 media-col-default (collection)................................11 + 5.3 media-col-ready (1setOf collection)...........................12 + 5.4 media-col-supported (1setOf type2 keyword)....................12 + 6 A Second Example Definition Of A Collection Attribute...........12 + 7 Encoding........................................................13 + 7.1 Additional tags defined for representing a collection + attribute value...............................................13 + 7.2 Example encoding: "media-col" (collection)....................14 + 8 Legacy issues...................................................20 + 9 IANA Considerations.............................................20 + 10 Internationalization Considerations............................20 + 11 Security Considerations........................................21 + 12 References.....................................................21 + Appendix A: Encoding Example of a Simple Collection (Informative).22 + Appendix B: Encoding Example of 1setOf Collection (Informative)...25 + Appendix C: Encoding Example of Collection containing 1setOf XXX + attribute (Informative)...............................31 + Appendix D: Description of the Base IPP Documents (Informative)...35 + Authors' Addresses................................................36 + Full Copyright Statement..........................................38 + +Table of Tables + + Table 1 - "media-col" member attributes...........................10 + Table 2 - "media-size" collection member attributes...............11 + Table 3 - Tags defined for encoding the 'collection' attribute + syntax .................................................13 + Table 4 - Overview Encoding of "media-col" collection.............15 + Table 5 - Example Encoding of "media-col" collection..............16 + Table 6 - Overview Encoding of simple collection..................22 + Table 7 - Example Encoding of simple collection...................22 + Table 8 - Overview Encoding of 1setOf collection..................25 + Table 9 - Example Encoding of 1setOf collection...................26 + Table 10 - Overview Encoding of collection with 1setOf value......31 + Table 11 - Example Encoding of collection with 1setOf value.......32 + + + + + + + + +deBry, et. al. Standards Track [Page 2] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + +1 Introduction + + This document is an OPTIONAL extension to IPP/1.0 [RFC2565, RFC2566] + and IPP/1.1 [RFC2911, RFC2910]. For a description of the base IPP + documents see Appendix D. + +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 + the 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 a 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-valued + (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. Standards Track [Page 3] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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 contain 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 [RFC2911] section 13.1.4.1), or + (2) accept the request and use only one of each duplicate member + attributes. + +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 as defined in BCP 14, RFC 2119 [RFC2119] and [RFC2911], + section 12.1. If an implementation supports the extension defined in + this document, then these terms apply; otherwise, they do not. These + terms define conformance to this document only; they do not affect + conformance to other documents, unless explicitly stated otherwise. + + + + + +deBry, et. al. Standards Track [Page 4] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + +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. + + 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. + + + +deBry, et. al. Standards Track [Page 5] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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 support + 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. + + 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 be + unique across the entire IPP attribute name space. + + + +deBry, et. al. Standards Track [Page 6] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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 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 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 + + + + +deBry, et. al. Standards Track [Page 7] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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 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 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". If optional member + attributes are absent, the Printer uses the defaulting rules of + item 5g) above. + + 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. + + + + + + + + +deBry, et. al. Standards Track [Page 8] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + +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. + +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. + + + +deBry, et. al. Standards Track [Page 9] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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: + + Table 1 - "media-col" member attributes + + Attribute name attribute syntax request Printer + 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'. + + + + + +deBry, et. al. Standards Track [Page 10] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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 name attribute syntax request Printer + Support + + x-dimension integer (0:MAX) MUST MUST + + y-dimension integer (0:MAX) MUST MUST + + The definitions for the member attributes are 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 attributes in the Job Creation operation and + the PDL do not include a media specification. The member attributes + + + +deBry, et. al. Standards Track [Page 11] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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. + +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. + + + + + + +deBry, et. al. Standards Track [Page 12] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + If "job-sheet-col" attribute was 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 + defined in this document MUST be used by all collection attributes + defined in other documents. However, the example of their use is + illustrative only. + +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 + value Meaning + + 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 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). + + + + +deBry, et. al. Standards Track [Page 13] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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 + 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 card and takes 216 + octets. The Appendices contain more complex examples. + + + +deBry, et. al. Standards Track [Page 14] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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 5. A simplified view of the encoding + looks like this: + + 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 "" "" + + + + + + + + + + +deBry, et. al. Standards Track [Page 15] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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 + + 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) + + + + + + + + +deBry, et. al. Standards Track [Page 16] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 0x0004 value- + length + + blue blue value value of 1st member + attribute + + + 0x4A memberAttrName value-tag starts a new member + attribute: "media-size" + + 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" + + + + + + + + +deBry, et. al. Standards Track [Page 17] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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) + + 0x000B value- length of "x-dimension" + length keyword + + 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 + + + + + + + + +deBry, et. al. Standards Track [Page 18] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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 + + 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 + + + + + + + + + + +deBry, et. al. Standards Track [Page 19] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + no name (since name-length + was 0) + + 0x0000 value- defined to be 0 for this + length type + + no value (since value- + length was 0) + +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 + + The following table provides registration for the 'collection' + attribute syntax defined in this document. This is to be registered + according to the procedures in RFC 2911 [RFC2911] section 6.3. + + Tag value: Attribute Syntaxes: Ref. Section: + collection RFC 3382 3 + 0x34 begCollection RFC 3382 7.1 + 0x37 endCollection RFC 3382 7.1 + 0x4A memberAttrName RFC 3382 7.1 + + The resulting attribute syntax registration will be published in the + http://www.iana.org/assignments/ipp-registrations registry. + +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 + internationalization considerations, as may any attribute, according + to [RFC2911]. + + + + +deBry, et. al. Standards Track [Page 20] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + +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 + +12.1 Normative References + + [RFC2910] Herriot, R., Butler, S., Moore, P. and R. Turner, "Internet + Printing Protocol/1.1: Encoding and Transport", RFC 2910, + September 2000. + + [RFC2911] Isaacson, S., deBry, R., Hastings, T., Herriot, R. and P. + Powell, "Internet Printing Protocol/1.1: Model and + Semantics", RFC 2911, September 2000. + +12.2 Informative References + + [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. + + [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. + + [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C. and H. + Holst, "Internet Printing Protocol/1.1: Implementor's + Guide", RFC 3196, November 2001. + + + +deBry, et. al. Standards Track [Page 21] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + +Appendix A: Encoding Example of a Simple Collection (Informative) + + 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 + + 0x000A name- length of (collection) + length attribute name + + media-size media-size name name of (collection) + attribute + + + + + + + + +deBry, et. al. Standards Track [Page 22] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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 + + 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) + + + + +deBry, et. al. Standards Track [Page 23] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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 + + no value (since value- + length was 0) + + + + + + + + + + + + + + + +deBry, et. al. Standards Track [Page 24] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + +Appendix B: Encoding Example of 1setOf Collection (Informative) + + 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 "" "" + + begCollection "" "" + + memberAttrName "" x-dimension + + integer "" 3 + + memberAttrName "" y-dimension + + integer "" 5 + + endCollection "" "" + + + + + + + + +deBry, et. al. Standards Track [Page 25] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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) + + 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) + + + + + + + + +deBry, et. al. Standards Track [Page 26] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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) + + 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) + + + + + + +deBry, et. al. Standards Track [Page 27] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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 + + 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 + + + + + + + + +deBry, et. al. Standards Track [Page 28] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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 + + no name (since name-length + was 0) + + 0x0004 value- length of an integer = 4 + length + + 0x0005 value value of 2nd collection + member attribute + + + + + + + + +deBry, et. al. Standards Track [Page 29] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +deBry, et. al. Standards Track [Page 30] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + +Appendix C: Encoding Example of Collection containing 1setOf XXX + attribute (Informative) + + 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 + + Tag Value Name Value + + begCollection wagons "" + + memberAttrName "" colors + + keyword "" red + + keyword "" blue + + memberAttrName "" sizes + + integer "" 4 + + integer "" 6 + + integer "" 8 + + endCollection "" "" + + + + + + + + + + + + + + + + + +deBry, et. al. Standards Track [Page 31] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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) + + 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 colors 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 + + + + + + +deBry, et. al. Standards Track [Page 32] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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 + + 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 + + + + + + +deBry, et. al. Standards Track [Page 33] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + 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 length of an integer = 4 + + 0x0006 value 2nd 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 + + 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 + + + + + + + +deBry, et. al. Standards Track [Page 34] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Octets Symbolic Value Protocol comments + field + + no value (since value- + length was 0) + +Appendix D: Description of the Base IPP Documents (Informative) + + The base 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 [RFC3196] + 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 [RFC2566, RFC2565]. A few OPTIONAL operator + operations have been added to IPP/1.1 [RFC2911, RFC2910]. + + 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 IPP 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. 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 "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 also 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 the 'ipp' scheme for + identifying IPP printers and jobs. + + + +deBry, et. al. Standards Track [Page 35] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + 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. + +Authors' 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 + EMail: hastings@cp10.es.xerox.com + + + Robert Herriot + Consultant + 706 Colorado Ave + Palo Alto, CA 94303 + + Phone: 650-327-4466 + Fax: 650-327-4466 + EMail: bob@herriot.com + + + + + + + + + + + +deBry, et. al. Standards Track [Page 36] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + + Kirk Ocke + Xerox Corp. + 800 Phillips Rd + M/S 128-30E + Webster, NY 14580 + + Phone: (585) 442-4832 + EMail: KOcke@crt.xerox.com + + + Peter Zehler + Xerox Corp. + 800 Phillips Rd + M/S 128-30E + Webster, NY 14580 + + Phone: (585) 265-8755 + EMail: PZehler@crt.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 + + Implementers of this specification document are encouraged to join + the IPP Mailing List in order to participate in any discussions of + clarification issues and review of registration proposals for + additional attributes and values. In order to reduce spam the + mailing list rejects mail from non-subscribers, so you must subscribe + to the mailing list in order to send a question or comment to the + mailing list. + + + + + + + + + + + + + + +deBry, et. al. Standards Track [Page 37] + +RFC 3382 IPP: The 'collection' attribute syntax September 2002 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2002). 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. + + + + + + + + + + + + + + + + + + + +deBry, et. al. Standards Track [Page 38] + diff --git a/standards/rfc3510.txt b/standards/rfc3510.txt new file mode 100644 index 000000000..c61ce5f2b --- /dev/null +++ b/standards/rfc3510.txt @@ -0,0 +1,899 @@ + + + + + + +Network Working Group R. Herriot +Request for Comments: 3510 I. McDonald +Updates: 2910 High North Inc. +Category: Standards Track April 2003 + + + Internet Printing Protocol/1.1: + IPP URL Scheme + +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 (2003). All Rights Reserved. + +Abstract + + This memo defines the "ipp" URL (Uniform Resource Locator) scheme. + This memo updates IPP/1.1: Encoding and Transport (RFC 2910), by + expanding and clarifying Section 5, "IPP URL Scheme", of RFC 2910. + An "ipp" URL is used to specify the network location of a print + service that supports the IPP Protocol (RFC 2910), or of a network + resource (for example, a print job) managed by such a print service. + +Table of Contents + + 1. Introduction ............................................... 2 + 2. Terminology ................................................ 3 + 2.1. Conformance Terminology .............................. 3 + 2.2. Model Terminology .................................... 3 + 3. IPP Model for Printers and Jobs ............................ 3 + 4. IPP URL Scheme ............................................. 4 + 4.1. IPP URL Scheme Applicability ......................... 4 + 4.2. IPP URL Scheme Associated Port ....................... 4 + 4.3. IPP URL Scheme Associated MIME Type .................. 5 + 4.4. IPP URL Scheme Character Encoding .................... 5 + 4.5. IPP URL Scheme Syntax ................................ 5 + 4.6. IPP URL Examples ..................................... 6 + 4.6.1. IPP Printer URL Examples ..................... 6 + 4.6.2. IPP Job URL Examples ......................... 6 + 4.7. IPP URL Comparisons .................................. 7 + + + + +Herriot & McDonald Standards Track [Page 1] + +RFC 3510 IPP URL Scheme April 2003 + + + 5. Conformance Requirements ................................... 8 + 5.1. IPP Client Conformance Requirements .................. 8 + 5.2. IPP Printer Conformance Requirements ................. 8 + 6. IANA Considerations ........................................ 9 + 7. Internationalization Considerations ........................ 9 + 8. Security Considerations .................................... 9 + 9. Intellectual Property Rights ............................... 10 + 10. Normative References ....................................... 11 + 11. Informative References ..................................... 11 + 12. Acknowledgments ............................................ 12 + Appendix A - Registration of "ipp" URL Scheme .................. 13 + Authors' Addresses ............................................. 15 + Full Copyright Statement ....................................... 16 + +1. Introduction + + This memo conforms to all of the requirements in Registration + Procedures for URL Scheme Names [RFC2717]. This memo also follows + all of the recommendations in Guidelines for new URL Schemes + [RFC2718]. + + See section 1, "Introduction", of [RFC2911] and section 1, + "Introduction", of [RFC3196] for overview information about IPP. See + section 10, "Description of the Base IPP Documents", of [RFC3196] for + a full description of the IPP document set. + + This memo updates IPP/1.1: Encoding and Transport (RFC 2910), by + expanding and clarifying Section 5, "IPP URL Scheme", of RFC 2910, + but does not define any new parameters or other new extensions to the + syntax of IPP URLs. + + The IPP URL scheme defined in this document is based on the ABNF for + the HTTP URL scheme defined in HTTP [RFC2616], which in turn is + derived from the URI Generic Syntax [RFC2396] and further updated for + IPv6 by [RFC2732]. An IPP URL is transformed into an HTTP URL + according to the rules specified in section 5 of IPP Protocol + [RFC2910]. + + This document defines IPP URL scheme applicability, associated port + (631), associated MIME type ("application/ipp"), character encoding, + and syntax. + + This document is laid out as follows: + + - Section 2 defines the terminology used throughout the document. + + - Section 3 supplies references to the IPP Printer and IPP Job + object model defined in IPP Model [RFC2911]. + + + +Herriot & McDonald Standards Track [Page 2] + +RFC 3510 IPP URL Scheme April 2003 + + + - Section 4 specifies the IPP URL scheme. + + - Section 5 specifies the conformance requirements for IPP Clients + and IPP Printers that claim conformance to this document. + + - Sections 6, 7, and 8 specify IANA, internationalization, and + security considerations. + + - Sections 9, 10, 11, 12, and 13 specify normative references, + informative references, acknowledgements, authors' addresses, and + full IETF copyright statement. + + - Section 14 (Appendix A) is a completed registration template for + the IPP URL Scheme (see section 6.0 of [RFC2717]). + +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 + [RFC2119]. These terms are used to specify conformance + requirements for all implementations (both print clients and print + services) of this specification. + +2.2. Model Terminology + + See section 12.2, "Model Terminology", in IPP Model [RFC2911]. + +3. IPP Model for Printers and Jobs + + See section 2, "IPP Objects", section 2.1, "Printer Object", and + section 2.2, "Job Object", in [RFC2911] 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 the IPP Protocol [RFC2910] to a print spooler, print + gateway, or physical printing device. + + + + + + + + +Herriot & McDonald Standards Track [Page 3] + +RFC 3510 IPP URL Scheme April 2003 + + + In this document, "IPP Printer object" means the software (on some + hardware platform) that receives print jobs and/or printer/job + operations via the IPP Protocol [RFC2910] 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 instantiated 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 + section 5, "IPP URL Scheme", of [RFC2910]). + +4. IPP URL Scheme + +4.1. IPP URL Scheme Applicability + + The "ipp" URL scheme MUST only be used to specify absolute URLs + (relative IPP URLs are not allowed) for IPP print services and + their associated network resources. The "ipp" URL scheme MUST + only be used to specify the use of the abstract protocol defined + in IPP Model [RFC2911] over an HTTP [RFC2616] transport, as + defined in IPP Protocol [RFC2910]. Any other transport binding + for the abstract protocol defined in IPP Model [RFC2911] would + require a different URL scheme. + + The "ipp" URL scheme allows an IPP client to choose an appropriate + IPP print service (for example, from a directory). The IPP client + can establish an HTTP connection to the specified IPP print + service. The IPP client can send IPP protocol requests (for + example, a "Print-Job" request) and receive IPP protocol responses + over that HTTP connection. + +4.2. IPP URL Scheme Associated Port + + All IPP URLs which do NOT explicitly specify a port MUST be + resolved to IANA-assigned well-known port 631, as registered in + [IANA-PORTREG]. + + See: IANA Port Numbers Registry [IANA-PORTREG]. + See: IPP Protocol [RFC2910]. + + + + + +Herriot & McDonald Standards Track [Page 4] + +RFC 3510 IPP URL Scheme April 2003 + + +4.3. IPP URL Scheme Associated MIME Type + + All IPP URLs MUST be used to specify network print services which + support the "application/ipp" MIME media type as registered in + [IANA-MIMEREG] for IPP protocol requests and responses. + + See: IANA MIME Media Types Registry [IANA-MIMEREG]. + See: IPP Protocol [RFC2910]. + +4.4. IPP URL Scheme Character Encoding + + IPP URLs MUST use [RFC2396] encoding, as do their equivalent HTTP + URLs. Characters other than those in the "reserved" and "unsafe" + sets [RFC2396] are equivalent to their ""%" HEX HEX" encoding. + +4.5. IPP URL Scheme Syntax + + The abstract protocol defined in IPP Model [RFC2911] places a + limit of 1023 octets (NOT characters) on the length of a URI (see + section 4.1.5, "uri", in [RFC2911]). + + Note: IPP Printers ought to be cautious about depending on URI + lengths above 255 bytes, because some older client implementations + might not properly support these lengths. + + IPP URLs MUST be represented in absolute form. Absolute URLs MUST + 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 "host", "port", "abs_path", + and "query" from [RFC2396], as updated for IPv6 by [RFC2732]. + + 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 + [RFC2616]) is located at the IPP print service listening for HTTP + connections on that port of that host, and the Request-URI for the + identified resource is 'abs_path'. + + 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]). + + + + + + +Herriot & McDonald Standards Track [Page 5] + +RFC 3510 IPP URL Scheme April 2003 + + +4.6. IPP URL Examples + + Note: Literal IPv4 or IPv6 addresses SHOULD NOT be used in IPP URLs. + +4.6.1. IPP Printer URL Examples + + The following are examples of well-formed IPP URLs for IPP Printers + (for example, to be used as protocol elements in 'printer-uri' + operation attributes of 'Print-Job' request messages): + + ipp://example.com + ipp://example.com/printer + ipp://example.com/printer/tiger + ipp://example.com/printer/fox + ipp://example.com/printer/tiger/bob + ipp://example.com/printer/tiger/ira + + Each of the above URLs are well-formed URLs for IPP Printers and each + would reference a logically different IPP Printer, even though some + of those IPP Printers might share the same host system. The 'bob' or + 'ira' last path components might represent two different physical + printer devices, while 'tiger' might represent some grouping of IPP + Printers (for example, a load-balancing spooler). Or the 'bob' and + 'ira' last path components might represent separate human recipients + on the same physical printer device (for example, a physical printer + supporting two job queues). In either case, both 'bob' and 'ira' + would behave as different and independent IPP Printers. + + The following are examples of well-formed IPP URLs for IPP Printers + with (optional) ports and paths: + + ipp://example.com + ipp://example.com/~smith/printer + ipp://example.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.7 below). + +4.6.2. IPP Job URL Examples + + The following are examples of well-formed IPP URLs for IPP Jobs (for + example, to be used as protocol elements in 'job-uri' attributes of + 'Print-Job' response messages): + + ipp://example.com/printer/123 + ipp://example.com/printer/tiger/job123 + + + + +Herriot & McDonald Standards Track [Page 6] + +RFC 3510 IPP URL Scheme April 2003 + + + IPP Job URLs are valid and meaningful only until Job completion and + possibly an implementation defined optional period of persistence + after Job completion (see IPP Model [RFC2911]). + + Ambiguously, section 4.3.1 'job-uri' of IPP Model [RFC2911] states + that: + + "the precise format of a Job URI is implementation dependent." + + Thus, the relationship between the value of the "printer-uri" + operation attribute used in a 'Print-Job' request and the value of + the "job-uri" attribute returned in the corresponding 'Print-Job' + response is implementation dependent. Also, section 4.3.3 'job- + printer-uri' of IPP Model [RFC2911] states that the 'job-printer-uri' + attribute of a Job object: + + "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." + + However, the above statement is false, because the transform from an + IPP Job URL to the corresponding IPP Printer URL is unspecified in + either IPP Model [RFC2911] or IPP Protocol [RFC2910]. + + IPP Printers that conform to this specification SHOULD only generate + IPP Job URLs (for example, in the "job-uri" attribute in a 'Print- + Job' response) by appending exactly one path component to the + corresponding IPP Printer URL (for interoperability). + +4.7. IPP URL Comparisons + + When comparing two IPP URLs to decide if they match or not, an IPP + Client MUST use the same rules as those defined for HTTP URI + comparisons in [RFC2616], with the sole following exception: + + - A port that is empty or not given MUST be treated as equivalent to + the well-known port for that IPP URL (port 631); + + See: Section 3.2.3, "URI Comparison", in [RFC2616]. + + + + + + + + + + + + +Herriot & McDonald Standards Track [Page 7] + +RFC 3510 IPP URL Scheme April 2003 + + +5. Conformance Requirements + +5.1. IPP Client Conformance Requirements + + IPP Clients that conform to this specification: + + a) MUST only send IPP protocol connections to the port specified in + each given IPP URL (if present) or otherwise to IANA assigned + well-known port 631; + + b) MUST only send IPP URLs used as protocol elements in outgoing IPP + protocol request messages (for example, in the "printer-uri" + operation attribute in a 'Print-Job' request) that conform to the + ABNF specified in section 4.5, "IPP URL Scheme Syntax, of this + document; + + c) MUST only convert IPP URLs to their corresponding HTTP URL forms + according to the rules in section 5, "IPP URL Scheme", in + [RFC2910]. + +5.2. IPP Printer Conformance Requirements + + IPP Printers that conform to this specification: + + a) MUST listen for incoming IPP protocol connections on IANA-assigned + well-known port 631, unless explicitly configured by system + administrators or site policies; + + b) SHOULD NOT listen for incoming IPP protocol connections on any + other port, unless explicitly configured by system administrators + or site policies; + + c) SHOULD only accept IPP URLs used as protocol elements in incoming + IPP protocol request messages (for example, in the "printer-uri" + operation attribute in a 'Print-Job' request) that conform to the + ABNF specified in section 4.5, "IPP URL Scheme Syntax", of this + document; + + d) SHOULD only send IPP URLs used as protocol elements in outgoing + IPP protocol response messages (for example, in the "job-uri" + attribute in a 'Print-Job' response) that conform to the ABNF + specified in section 4.5, "IPP URL Scheme Syntax", of this + document; + + e) SHOULD only generate IPP Job URLs (for example, in the "job-uri" + attribute in a 'Print-Job' response) by appending exactly one path + component to the corresponding IPP Printer URL (for + interoperability); + + + +Herriot & McDonald Standards Track [Page 8] + +RFC 3510 IPP URL Scheme April 2003 + + + f) SHOULD NOT use literal IPv6 or IPv4 addresses in configured or + locally generated IPP URLs. + +6. IANA Considerations + + This IPP URL Scheme specification does not introduce any additional + IANA considerations, beyond those described in [RFC2910] and + [RFC2911]. + + See: Section 6, "IANA Considerations" in [RFC2910] + See: Section 6, "IANA Considerations" in [RFC2911]. + +7. Internationalization Considerations + + This IPP URL Scheme specification does not introduce any additional + internationalization considerations, beyond those described in + [RFC2910] and [RFC2911]. + + See: Section 7, "Internationalization Considerations", in [RFC2910]. + See: Section 7, "Internationalization Considerations", in [RFC2911]. + +8. Security Considerations + + This IPP URL Scheme specification does not introduce any additional + security considerations, beyond those described in [RFC2910] and + [RFC2911], except the following: + + a) An IPP URL might be faked to point to a rogue IPP print service, + thus collecting confidential document contents from IPP clients. + Server authentication mechanisms and security mechanisms specified + in the IPP Protocol [RFC2910] are sufficient to address this + threat. + + b) An IPP URL might be used to access an IPP print service by an + unauthorized IPP client. Client authentication mechanisms and + security mechanisms specified in the IPP Protocol [RFC2910] are + sufficient to address this threat. + + c) An IPP URL might be used to access an IPP print service at a print + protocol application layer gateway (for example, an IPP to LPD + gateway [RFC2569]) causing silent compromise of IPP security + mechanisms. There is no practical defense against this threat by + a client system. System administrators should avoid such + compromising configurations. + + d) An IPP URL does not have parameters to specify the required client + authentication mechanism (for example, 'certificate' as defined in + section 4.4.2, "uri-authentication-supported", of IPP Model + + + +Herriot & McDonald Standards Track [Page 9] + +RFC 3510 IPP URL Scheme April 2003 + + + [RFC2911]) and required security mechanism (for example, 'tls' as + defined in section 4.4.3, "uri-security-supported", of IPP Model + [RFC2911]). Service discovery or directory protocols might be + used to discover the required client authentication and security + mechanisms associated with given IPP URLs. + + Historical Note: During the development of this document, + consideration was given to the addition of standard IPP URL + parameters for the client authentication and security mechanisms. + However, based on a strong IETF IPP Working Group consensus, no + parameters were added to the "ipp" URL scheme as originally defined + in IPP Protocol [RFC2910] in September 2000, for reasons of backwards + compatibility with the many currently shipping implementations of + IPP/1.1. + + See: Section 8, "Security Considerations", in [RFC2910]. + See: Section 8, "Security Considerations", in [RFC2911]. + +9. Intellectual Property Rights + + 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. + + 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. + + + + + + + + + + + + +Herriot & McDonald Standards Track [Page 10] + +RFC 3510 IPP URL Scheme April 2003 + + +10. Normative References + + [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. + + [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. + + [RFC2732] Hinden, R., Carpenter, B. and L. Masinter, "Format for + Literal IPv6 Addresses in URL's", RFC 2732, December + 1999. + + [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J. + Wenn, "IPP/1.1 Encoding and Transport [IPP Protocol]", + RFC 2910, September 2000. + + [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S. and + P. Powell, "IPP/1.1 Model and Semantics [IPP Model]", + RFC 2911, September 2000. + + [US-ASCII] Coded Character Set -- 7-bit American Standard Code + for Information Interchange, ANSI X3.4-1986. + +11. Informative References + + [IANA-MIMEREG] IANA MIME Media Types Registry. + ftp://ftp.iana.org/in-notes/iana/assignments/media- + types/... + + [IANA-PORTREG] IANA Port Numbers Registry. ftp://ftp.iana.org/in- + notes/iana/assignments/port-numbers + + [RFC2569] Herriot, R., Hastings, T., Jacobs, N. and J. Martin, + "Mapping between LPD and IPP Protocols", RFC 2569, + April 1999. + + [RFC2717] Petke, R. and I. King, "Registration Procedures for + URL Scheme Names", RFC 2717, November 1999. + + [RFC2718] Masinter, L., Alvestrand, H., Zigmond, D. and R. + Petke, "Guidelines for new URL Schemes", RFC 2718, + November 1999. + + + + +Herriot & McDonald Standards Track [Page 11] + +RFC 3510 IPP URL Scheme April 2003 + + + [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C. and + H. Holst, "Internet Printing Protocol/1.1: + Implementor's Guide", RFC 3196, November 2001. + +12. Acknowledgments + + This document is a product of the Internet Printing Protocol Working + Group of the Internet Engineering Task Force (IETF). + + Thanks to Pat Fleming (IBM), Tom Hastings (Xerox), Harry Lewis (IBM), + Hugo Parra (Novell), Don Wright (Lexmark), and all the members of the + IETF IPP WG. + + Section 5, "IPP URL Scheme", in IPP Protocol [RFC2910] was the + primary input to this IPP URL Scheme specification. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herriot & McDonald Standards Track [Page 12] + +RFC 3510 IPP URL Scheme April 2003 + + +Appendix A - Registration of "ipp" URL Scheme + + Note: The following registration obsoletes section 5, "IPP URL + Scheme", of IPP Protocol [RFC2911]. + + URL Scheme Name: ipp + + URL Scheme Syntax: + + ipp-URL = "ipp:" "//" host [ ":" port ] [ abs_path [ "?" query ]] + + Character Encoding Considerations: + + IPP URLs MUST use [RFC2396] encoding, as do their equivalent HTTP + URLs. Characters other than those in the "reserved" and "unsafe" + sets [RFC2396] are equivalent to their ""%" HEX HEX" encoding. + + Intended Usage: + + The intended usage of the "ipp" URL scheme is COMMON. + + An "ipp" URL is used to specify the network location of a print + service that supports the IPP Protocol [RFC2910], or of a network + resource (for example, a print job) managed by such a print + service. An IPP client can choose to establish an HTTP connection + to the specified print service for transmission of IPP protocol + requests (for example, IPP print job submission requests). + + Applications or Protocols which use this URL scheme: + + See: Section 5, "IPP URL Scheme", in IPP Protocol [RFC2910]. + + Interoperability Considerations: + + See: Section 9, "Interoperability with IPP/1.0 Implementations", + in IPP Protocol [RFC2910]. + + Security Considerations: + + See: Section 8, "Security Considerations", in IPP Protocol + [RFC2910]. + + Relevant Publications: + + [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R. and J. Wenn, + "IPP/1.1 Encoding and Transport [IPP Protocol]", RFC 2910, + September 2000. + + + + +Herriot & McDonald Standards Track [Page 13] + +RFC 3510 IPP URL Scheme April 2003 + + + [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. + + [RFC3510] Herriot, R. and I. McDonald, "IPP/1.1: IPP URL Scheme", RFC + 3510, April 2003. + + Person & email address to contact for further information: + + Robert Herriot + Consultant + 706 Colorado Ave + Palo Alto, CA 94303 + + Phone: +1 650-327-4466 + EMail: bob@herriot.com + + Ira McDonald + High North Inc + 221 Ridge Ave + Grand Marais, MI 49839 + + Phone: +1 906-494-2434 + EMail: imcdonald@sharplabs.com + + + + + + + + + + + + + + + + + + + + + + + + + + + +Herriot & McDonald Standards Track [Page 14] + +RFC 3510 IPP URL Scheme April 2003 + + +Authors' Addresses + + Robert Herriot + Consultant + 706 Colorado Ave + Palo Alto, CA 94303 + + Phone: +1 650-327-4466 + EMail: bob@herriot.com + + + Ira McDonald + High North Inc + 221 Ridge Ave + Grand Marais, MI 49839 + + Phone: +1 906-494-2434 + EMail: imcdonald@sharplabs.com + + Usage questions and comments on this IPP URL Scheme should be sent + directly to the editors at their above addresses (and to the IPP + mailing list, if you are a subscriber - see below). + + 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 + + Implementers of this specification are encouraged to join the IPP + Mailing List in order to participate in any discussions of + clarification issues and comments. In order to reduce spam the + mailing list rejects mail from non-subscribers, so you must subscribe + to the mailing list in order to send a question or comment to the IPP + mailing list. + + + + + + + + + + + +Herriot & McDonald Standards Track [Page 15] + +RFC 3510 IPP URL Scheme April 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). 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 & McDonald Standards Track [Page 16] + diff --git a/standards/rfc3986.txt b/standards/rfc3986.txt new file mode 100644 index 000000000..c56ed4eb7 --- /dev/null +++ b/standards/rfc3986.txt @@ -0,0 +1,3419 @@ + + + + + + +Network Working Group T. Berners-Lee +Request for Comments: 3986 W3C/MIT +STD: 66 R. Fielding +Updates: 1738 Day Software +Obsoletes: 2732, 2396, 1808 L. Masinter +Category: Standards Track Adobe Systems + January 2005 + + + Uniform Resource Identifier (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 (2005). + +Abstract + + A Uniform Resource Identifier (URI) is a compact sequence of + characters that identifies an abstract or physical resource. This + specification defines the generic URI syntax and a process for + resolving URI references that might be in relative form, along with + guidelines and security considerations for the use of URIs on the + Internet. The URI syntax defines a grammar that is a superset of all + valid URIs, allowing an implementation to parse the common components + of a URI reference without knowing the scheme-specific requirements + of every possible identifier. This specification does not define a + generative grammar for URIs; that task is performed by the individual + specifications of each URI scheme. + + + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 1] + +RFC 3986 URI Generic Syntax January 2005 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4 + 1.1. Overview of URIs . . . . . . . . . . . . . . . . . . . . 4 + 1.1.1. Generic Syntax . . . . . . . . . . . . . . . . . 6 + 1.1.2. Examples . . . . . . . . . . . . . . . . . . . . 7 + 1.1.3. URI, URL, and URN . . . . . . . . . . . . . . . 7 + 1.2. Design Considerations . . . . . . . . . . . . . . . . . 8 + 1.2.1. Transcription . . . . . . . . . . . . . . . . . 8 + 1.2.2. Separating Identification from Interaction . . . 9 + 1.2.3. Hierarchical Identifiers . . . . . . . . . . . . 10 + 1.3. Syntax Notation . . . . . . . . . . . . . . . . . . . . 11 + 2. Characters . . . . . . . . . . . . . . . . . . . . . . . . . . 11 + 2.1. Percent-Encoding . . . . . . . . . . . . . . . . . . . . 12 + 2.2. Reserved Characters . . . . . . . . . . . . . . . . . . 12 + 2.3. Unreserved Characters . . . . . . . . . . . . . . . . . 13 + 2.4. When to Encode or Decode . . . . . . . . . . . . . . . . 14 + 2.5. Identifying Data . . . . . . . . . . . . . . . . . . . . 14 + 3. Syntax Components . . . . . . . . . . . . . . . . . . . . . . 16 + 3.1. Scheme . . . . . . . . . . . . . . . . . . . . . . . . . 17 + 3.2. Authority . . . . . . . . . . . . . . . . . . . . . . . 17 + 3.2.1. User Information . . . . . . . . . . . . . . . . 18 + 3.2.2. Host . . . . . . . . . . . . . . . . . . . . . . 18 + 3.2.3. Port . . . . . . . . . . . . . . . . . . . . . . 22 + 3.3. Path . . . . . . . . . . . . . . . . . . . . . . . . . . 22 + 3.4. Query . . . . . . . . . . . . . . . . . . . . . . . . . 23 + 3.5. Fragment . . . . . . . . . . . . . . . . . . . . . . . . 24 + 4. Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 + 4.1. URI Reference . . . . . . . . . . . . . . . . . . . . . 25 + 4.2. Relative Reference . . . . . . . . . . . . . . . . . . . 26 + 4.3. Absolute URI . . . . . . . . . . . . . . . . . . . . . . 27 + 4.4. Same-Document Reference . . . . . . . . . . . . . . . . 27 + 4.5. Suffix Reference . . . . . . . . . . . . . . . . . . . . 27 + 5. Reference Resolution . . . . . . . . . . . . . . . . . . . . . 28 + 5.1. Establishing a Base URI . . . . . . . . . . . . . . . . 28 + 5.1.1. Base URI Embedded in Content . . . . . . . . . . 29 + 5.1.2. Base URI from the Encapsulating Entity . . . . . 29 + 5.1.3. Base URI from the Retrieval URI . . . . . . . . 30 + 5.1.4. Default Base URI . . . . . . . . . . . . . . . . 30 + 5.2. Relative Resolution . . . . . . . . . . . . . . . . . . 30 + 5.2.1. Pre-parse the Base URI . . . . . . . . . . . . . 31 + 5.2.2. Transform References . . . . . . . . . . . . . . 31 + 5.2.3. Merge Paths . . . . . . . . . . . . . . . . . . 32 + 5.2.4. Remove Dot Segments . . . . . . . . . . . . . . 33 + 5.3. Component Recomposition . . . . . . . . . . . . . . . . 35 + 5.4. Reference Resolution Examples . . . . . . . . . . . . . 35 + 5.4.1. Normal Examples . . . . . . . . . . . . . . . . 36 + 5.4.2. Abnormal Examples . . . . . . . . . . . . . . . 36 + + + +Berners-Lee, et al. Standards Track [Page 2] + +RFC 3986 URI Generic Syntax January 2005 + + + 6. Normalization and Comparison . . . . . . . . . . . . . . . . . 38 + 6.1. Equivalence . . . . . . . . . . . . . . . . . . . . . . 38 + 6.2. Comparison Ladder . . . . . . . . . . . . . . . . . . . 39 + 6.2.1. Simple String Comparison . . . . . . . . . . . . 39 + 6.2.2. Syntax-Based Normalization . . . . . . . . . . . 40 + 6.2.3. Scheme-Based Normalization . . . . . . . . . . . 41 + 6.2.4. Protocol-Based Normalization . . . . . . . . . . 42 + 7. Security Considerations . . . . . . . . . . . . . . . . . . . 43 + 7.1. Reliability and Consistency . . . . . . . . . . . . . . 43 + 7.2. Malicious Construction . . . . . . . . . . . . . . . . . 43 + 7.3. Back-End Transcoding . . . . . . . . . . . . . . . . . . 44 + 7.4. Rare IP Address Formats . . . . . . . . . . . . . . . . 45 + 7.5. Sensitive Information . . . . . . . . . . . . . . . . . 45 + 7.6. Semantic Attacks . . . . . . . . . . . . . . . . . . . . 45 + 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 46 + 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 46 + 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 46 + 10.1. Normative References . . . . . . . . . . . . . . . . . . 46 + 10.2. Informative References . . . . . . . . . . . . . . . . . 47 + A. Collected ABNF for URI . . . . . . . . . . . . . . . . . . . . 49 + B. Parsing a URI Reference with a Regular Expression . . . . . . 50 + C. Delimiting a URI in Context . . . . . . . . . . . . . . . . . 51 + D. Changes from RFC 2396 . . . . . . . . . . . . . . . . . . . . 53 + D.1. Additions . . . . . . . . . . . . . . . . . . . . . . . 53 + D.2. Modifications . . . . . . . . . . . . . . . . . . . . . 53 + Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 60 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 61 + + + + + + + + + + + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 3] + +RFC 3986 URI Generic Syntax January 2005 + + +1. Introduction + + A Uniform Resource Identifier (URI) provides 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 these identifiers + dates from 1990 and is described in "Universal Resource Identifiers + in WWW" [RFC1630]. The syntax 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 obsoletes [RFC2396], which merged "Uniform Resource + Locators" [RFC1738] and "Relative Uniform Resource Locators" + [RFC1808] in order to define a single, generic syntax for all URIs. + It obsoletes [RFC2732], which introduced syntax for an IPv6 address. + It excludes portions of RFC 1738 that defined the specific syntax of + individual URI schemes; those portions will be updated as separate + documents. The process for registration of new URI schemes is + defined separately by [BCP35]. Advice for designers of new URI + schemes can be found in [RFC2718]. All significant changes from RFC + 2396 are noted in Appendix D. + + This specification uses the terms "character" and "coded character + set" in accordance with the definitions provided in [BCP19], and + "character encoding" in place of what [BCP19] refers to as a + "charset". + +1.1. Overview of URIs + + URIs are characterized as follows: + + 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. 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. + + + + + + + +Berners-Lee, et al. Standards Track [Page 4] + +RFC 3986 URI Generic Syntax January 2005 + + + Resource + + This specification does not limit the scope of what might be a + resource; rather, the term "resource" is used in a general sense + for whatever might be identified by a URI. Familiar examples + include an electronic document, an image, a source of information + with a consistent purpose (e.g., "today's weather report for Los + Angeles"), a service (e.g., an HTTP-to-SMS gateway), and a + collection of other resources. A resource is not necessarily + accessible via the Internet; e.g., human beings, corporations, and + bound books in a library can also be resources. Likewise, + abstract concepts can be resources, such as the operators and + operands of a mathematical equation, the types of a relationship + (e.g., "parent" or "employee"), or numeric values (e.g., zero, + one, and infinity). + + Identifier + + An identifier embodies the information required to distinguish + what is being identified from all other things within its scope of + identification. Our use of the terms "identify" and "identifying" + refer to this purpose of distinguishing one resource from all + other resources, regardless of how that purpose is accomplished + (e.g., by name, address, or context). These terms should not be + mistaken as an assumption that an identifier defines or embodies + the identity of what is referenced, though that may be the case + for some identifiers. Nor should it be assumed that a system + using URIs will access the resource identified: in many cases, + URIs are used to denote resources without any intention that they + be accessed. Likewise, the "one" resource identified might not be + singular in nature (e.g., a resource might be a named set or a + mapping that varies over time). + + A URI is an identifier consisting of a sequence of characters + matching the syntax rule named in Section 3. It enables + uniform identification of resources via a separately defined + extensible set of naming schemes (Section 3.1). How that + identification is accomplished, assigned, or enabled is delegated to + each scheme specification. + + This specification does not place any limits on the nature of a + resource, the reasons why an application might seek to refer to a + resource, or the kinds of systems that might use URIs for the sake of + identifying resources. This specification does not require that a + URI persists in identifying the same resource over time, though that + is a common goal of all URI schemes. Nevertheless, nothing in this + + + + + +Berners-Lee, et al. Standards Track [Page 5] + +RFC 3986 URI Generic Syntax January 2005 + + + specification prevents an application from limiting itself to + particular types of resources, or to a subset of URIs that maintains + characteristics desired by that application. + + URIs have a global scope and are interpreted consistently regardless + of context, though the result of that interpretation may be in + relation to the end-user's context. For example, "http://localhost/" + has the same interpretation for every user of that reference, even + though the network interface corresponding to "localhost" may be + different for each end-user: interpretation is independent of access. + However, an action made on the basis of that reference will take + place in relation to the end-user's context, which implies that an + action intended to refer to a globally unique thing must use a URI + that distinguishes that resource from all other things. URIs that + identify in relation to the end-user's local context should only be + used when the context itself is a defining aspect of the resource, + such as when an on-line help manual refers to a file on the end- + user's file system (e.g., "file:///etc/hosts"). + +1.1.1. Generic Syntax + + Each URI begins with a scheme name, as defined in Section 3.1, that + refers to a specification for assigning identifiers within that + scheme. As such, the URI syntax is a federated and extensible naming + system wherein each scheme's specification may further restrict the + syntax and semantics of identifiers using that scheme. + + This specification defines those elements of the URI syntax that are + required of all URI schemes or are common to many URI schemes. It + thus defines the syntax and semantics needed to implement a scheme- + independent parsing mechanism for URI references, by which the + scheme-dependent handling of a URI can be postponed until the + scheme-dependent semantics are needed. Likewise, protocols and data + formats that make use of URI references can refer to this + specification as a definition for the range of syntax allowed for all + URIs, including those schemes that have yet to be defined. This + decouples the evolution of identification schemes from the evolution + of protocols, data formats, and implementations that make use of + URIs. + + A parser of the generic URI syntax can parse any URI reference into + its major components. Once the scheme is determined, further + scheme-specific parsing can be performed on the components. In other + words, the URI generic syntax is a superset of the syntax of all URI + schemes. + + + + + + +Berners-Lee, et al. Standards Track [Page 6] + +RFC 3986 URI Generic Syntax January 2005 + + +1.1.2. Examples + + The following example URIs illustrate several URI schemes and + variations in their common syntax components: + + ftp://ftp.is.co.za/rfc/rfc1808.txt + + http://www.ietf.org/rfc/rfc2396.txt + + ldap://[2001:db8::7]/c=GB?objectClass?one + + mailto:John.Doe@example.com + + news:comp.infosystems.www.servers.unix + + tel:+1-816-555-1212 + + telnet://192.0.2.16:80/ + + urn:oasis:names:specification:docbook:dtd:xml:4.1.2 + + +1.1.3. 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 URIs + that, in addition to identifying a resource, provide a means of + locating the resource by describing its primary access mechanism + (e.g., its network "location"). The term "Uniform Resource Name" + (URN) has been used historically to refer to both URIs under the + "urn" scheme [RFC2141], which are required to remain globally unique + and persistent even when the resource ceases to exist or becomes + unavailable, and to any other URI with the properties of a name. + + An individual scheme does not have to be classified as being just one + of "name" or "locator". Instances of URIs from any given scheme may + have the characteristics of names or locators or both, often + depending on the persistence and care in the assignment of + identifiers by the naming authority, rather than on any quality of + the scheme. Future specifications and related documentation should + use the general term "URI" rather than the more restrictive terms + "URL" and "URN" [RFC3305]. + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 7] + +RFC 3986 URI Generic Syntax January 2005 + + +1.2. Design Considerations + +1.2.1. Transcription + + The URI syntax has been designed with global transcription as one of + its main considerations. A URI is a sequence of characters from a + very limited set: 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 + character encoding octets. The interpretation of a URI depends only + on the characters used and not on how those characters are + represented in a network protocol. + + The goal of transcription 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 considerations revealed by the scenario: + + o A URI is a sequence of characters that is not always represented + as a sequence of octets. + + o A URI might be transcribed from a non-network source and thus + should consist of characters that are most likely able to be + entered into a computer, within the constraints imposed by + keyboards (and related input devices) across languages and + locales. + + o A URI often has to be remembered by people, and it is easier for + people to remember a URI when it consists of meaningful or + familiar components. + + These design considerations 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 a resource identifier from one + medium to another has been considered more important than having a + URI consist of the most meaningful of components. + + In local or regional contexts and with improving technology, users + might benefit from being able to use a wider range of characters; + such use is not defined by this specification. Percent-encoded + octets (Section 2.1) may be used within a URI to represent characters + outside the range of the US-ASCII coded character set if this + + + +Berners-Lee, et al. Standards Track [Page 8] + +RFC 3986 URI Generic Syntax January 2005 + + + representation is allowed by the scheme or by the protocol element in + which the URI is referenced. Such a definition should specify the + character encoding used to map those characters to octets prior to + being percent-encoded for the URI. + +1.2.2. Separating Identification from Interaction + + A common misunderstanding of URIs is that they are only used to refer + to accessible resources. The URI itself only provides + identification; access to the resource is neither guaranteed nor + implied by the presence of a URI. Instead, any operation associated + with a URI reference is defined by the protocol element, data format + attribute, or natural language text in which it appears. + + Given a URI, a system may attempt to perform a variety of operations + on the resource, as might be characterized by words such as "access", + "update", "replace", or "find attributes". Such operations are + defined by the protocols that make use of URIs, not by this + specification. However, we do use a few general terms for describing + common operations on URIs. URI "resolution" is the process of + determining an access mechanism and the appropriate parameters + necessary to dereference a URI; this resolution may require several + iterations. To use that access mechanism to perform an action on the + URI's resource is to "dereference" the URI. + + When URIs are used within information retrieval systems to identify + sources of information, the most common form of URI dereference is + "retrieval": making use of a URI in order to retrieve a + representation of its associated resource. A "representation" is a + sequence of octets, along with representation metadata describing + those octets, that constitutes a record of the state of the resource + at the time when the representation is generated. Retrieval is + achieved by a process that might include using the URI as a cache key + to check for a locally cached representation, resolution of the URI + to determine an appropriate access mechanism (if any), and + dereference of the URI for the sake of applying a retrieval + operation. Depending on the protocols used to perform the retrieval, + additional information might be supplied about the resource (resource + metadata) and its relation to other resources. + + URI references in information retrieval systems are designed to be + late-binding: the result of an access is generally determined when it + is accessed and may vary over time or due to other aspects of the + interaction. These references are created in order to be used in the + future: what is being identified is not some specific result that was + obtained in the past, but rather some characteristic that is expected + to be true for future results. In such cases, the resource referred + to by the URI is actually a sameness of characteristics as observed + + + +Berners-Lee, et al. Standards Track [Page 9] + +RFC 3986 URI Generic Syntax January 2005 + + + over time, perhaps elucidated by additional comments or assertions + made by the resource provider. + + Although many URI schemes are named after protocols, this does not + imply that use of these URIs will result in access to the resource + via the named protocol. URIs are often used simply for the sake of + identification. Even when a URI is used to retrieve a representation + of a resource, that access might be through gateways, proxies, + caches, and name resolution services that are independent of the + protocol associated with the scheme name. The resolution of some + URIs may require the use of more than one protocol (e.g., both DNS + and HTTP are typically used to access an "http" URI's origin server + when a representation isn't found in a local cache). + +1.2.3. Hierarchical Identifiers + + The URI syntax is organized hierarchically, with components listed in + order of decreasing significance from left to right. For some URI + schemes, the visible hierarchy is limited to the scheme itself: + everything after the scheme component delimiter (":") is considered + opaque to URI processing. Other URI schemes make the hierarchy + explicit and visible to generic parsing algorithms. + + The generic syntax uses the slash ("/"), question mark ("?"), and + number sign ("#") characters to delimit components that are + significant to the generic parser's hierarchical interpretation of an + identifier. In addition to aiding the readability of such + identifiers through the consistent use of familiar syntax, this + uniform representation of hierarchy across naming schemes allows + scheme-independent references to be made relative to that hierarchy. + + It is often the case that a group or "tree" of documents has been + constructed to serve a common purpose, wherein the vast majority of + URI references in these documents point to resources within the tree + rather than outside 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 referencing of URIs + 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 with relative references. Furthermore, such + document trees can be moved, as a whole, without changing any of the + relative references. + + A relative reference (Section 4.2) refers to a resource by describing + the difference within a hierarchical name space between the reference + context and the target URI. The reference resolution algorithm, + + + +Berners-Lee, et al. Standards Track [Page 10] + +RFC 3986 URI Generic Syntax January 2005 + + + presented in Section 5, defines how such a reference is transformed + to the target URI. As relative references can only be used within + the context of a hierarchical URI, designers of new URI schemes + should use a syntax consistent with the generic syntax's hierarchical + components unless there are compelling reasons to forbid relative + referencing within that scheme. + + NOTE: Previous specifications used the terms "partial URI" and + "relative URI" to denote a relative reference to a URI. As some + readers misunderstood those terms to mean that relative URIs are a + subset of URIs rather than a method of referencing URIs, this + specification simply refers to them as relative references. + + All URI references are parsed by generic syntax parsers when used. + However, because hierarchical processing has no effect on an absolute + URI used in a reference unless it contains one or more dot-segments + (complete path segments of "." or "..", as described in Section 3.3), + URI scheme specifications can define opaque identifiers by + disallowing use of slash characters, question mark characters, and + the URIs "scheme:." and "scheme:..". + +1.3. Syntax Notation + + This specification uses the Augmented Backus-Naur Form (ABNF) + notation of [RFC2234], including the following core ABNF syntax rules + defined by that specification: ALPHA (letters), CR (carriage return), + DIGIT (decimal digits), DQUOTE (double quote), HEXDIG (hexadecimal + digits), LF (line feed), and SP (space). The complete URI syntax is + collected in Appendix A. + +2. Characters + + The URI syntax provides a method of encoding data, presumably for the + sake of identifying a resource, as a sequence of characters. The URI + characters are, in turn, frequently encoded as octets for transport + or presentation. This specification does not mandate any particular + character encoding for mapping between URI characters and the octets + used to store or transmit those characters. When a URI appears in a + protocol element, the character encoding is defined by that protocol; + without such a definition, a URI is assumed to be in the same + character encoding as the surrounding text. + + The ABNF notation defines its terminal values to be non-negative + integers (codepoints) based on the US-ASCII coded character set + [ASCII]. Because a URI is a sequence of characters, we must invert + that relation in order to understand the URI syntax. Therefore, the + + + + + +Berners-Lee, et al. Standards Track [Page 11] + +RFC 3986 URI Generic Syntax January 2005 + + + integer values used by the ABNF must be mapped back to their + corresponding characters via US-ASCII in order to complete the syntax + rules. + + A URI is composed from a limited set of characters consisting of + digits, letters, and a few graphic symbols. A reserved subset of + those characters may be used to delimit syntax components within a + URI while the remaining characters, including both the unreserved set + and those reserved characters not acting as delimiters, define each + component's identifying data. + +2.1. Percent-Encoding + + A percent-encoding mechanism is used to represent a data octet in a + component when that octet's corresponding character is outside the + allowed set or is being used as a delimiter of, or within, the + component. A percent-encoded octet is encoded as a character + triplet, consisting of the percent character "%" followed by the two + hexadecimal digits representing that octet's numeric value. For + example, "%20" is the percent-encoding for the binary octet + "00100000" (ABNF: %x20), which in US-ASCII corresponds to the space + character (SP). Section 2.4 describes when percent-encoding and + decoding is applied. + + pct-encoded = "%" HEXDIG HEXDIG + + The uppercase hexadecimal digits 'A' through 'F' are equivalent to + the lowercase digits 'a' through 'f', respectively. If two URIs + differ only in the case of hexadecimal digits used in percent-encoded + octets, they are equivalent. For consistency, URI producers and + normalizers should use uppercase hexadecimal digits for all percent- + encodings. + +2.2. Reserved Characters + + URIs include components and subcomponents that are delimited by + characters in the "reserved" set. These characters are called + "reserved" because they may (or may not) be defined as delimiters by + the generic syntax, by each scheme-specific syntax, or by the + implementation-specific syntax of a URI's dereferencing algorithm. + If data for a URI component would conflict with a reserved + character's purpose as a delimiter, then the conflicting data must be + percent-encoded before the URI is formed. + + + + + + + + +Berners-Lee, et al. Standards Track [Page 12] + +RFC 3986 URI Generic Syntax January 2005 + + + reserved = gen-delims / sub-delims + + gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + + sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" + + The purpose of reserved characters is to provide a set of delimiting + characters that are distinguishable from other data within a URI. + URIs that differ in the replacement of a reserved character with its + corresponding percent-encoded octet are not equivalent. Percent- + encoding a reserved character, or decoding a percent-encoded octet + that corresponds to a reserved character, will change how the URI is + interpreted by most applications. Thus, characters in the reserved + set are protected from normalization and are therefore safe to be + used by scheme-specific and producer-specific algorithms for + delimiting data subcomponents within a URI. + + A subset of the reserved characters (gen-delims) is used as + delimiters of the generic URI components described in Section 3. A + component's ABNF syntax rule will not use the reserved or gen-delims + rule names directly; instead, each syntax rule lists the characters + allowed within that component (i.e., not delimiting it), and any of + those characters that are also in the reserved set are "reserved" for + use as subcomponent delimiters within the component. Only the most + common subcomponents are defined by this specification; other + subcomponents may be defined by a URI scheme's specification, or by + the implementation-specific syntax of a URI's dereferencing + algorithm, provided that such subcomponents are delimited by + characters in the reserved set allowed within that component. + + URI producing applications should percent-encode data octets that + correspond to characters in the reserved set unless these characters + are specifically allowed by the URI scheme to represent data in that + component. If a reserved character is found in a URI component and + no delimiting role is known for that character, then it must be + interpreted as representing the data octet corresponding to that + character's encoding in US-ASCII. + +2.3. Unreserved Characters + + Characters that are allowed in a URI but do not have a reserved + purpose are called unreserved. These include uppercase and lowercase + letters, decimal digits, hyphen, period, underscore, and tilde. + + unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + + + + + +Berners-Lee, et al. Standards Track [Page 13] + +RFC 3986 URI Generic Syntax January 2005 + + + URIs that differ in the replacement of an unreserved character with + its corresponding percent-encoded US-ASCII octet are equivalent: they + identify the same resource. However, URI comparison implementations + do not always perform normalization prior to comparison (see Section + 6). For consistency, percent-encoded octets in the ranges of ALPHA + (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E), + underscore (%5F), or tilde (%7E) should not be created by URI + producers and, when found in a URI, should be decoded to their + corresponding unreserved characters by URI normalizers. + +2.4. When to Encode or Decode + + Under normal circumstances, the only time when octets within a URI + are percent-encoded is during the process of producing the URI from + its component parts. This is when an implementation determines which + of the reserved characters are to be used as subcomponent delimiters + and which can be safely used as data. Once produced, a URI is always + in its percent-encoded form. + + When a URI is dereferenced, the components and subcomponents + significant to the scheme-specific dereferencing process (if any) + must be parsed and separated before the percent-encoded octets within + those components can be safely decoded, as otherwise the data may be + mistaken for component delimiters. The only exception is for + percent-encoded octets corresponding to characters in the unreserved + set, which can be decoded at any time. For example, the octet + corresponding to the tilde ("~") character is often encoded as "%7E" + by older URI processing implementations; the "%7E" can be replaced by + "~" without changing its interpretation. + + Because the percent ("%") character serves as the indicator for + percent-encoded octets, it must be percent-encoded as "%25" for that + octet to be used as data within a URI. Implementations must not + percent-encode or decode the same string more than once, as decoding + an already decoded string might lead to misinterpreting a percent + data octet as the beginning of a percent-encoding, or vice versa in + the case of percent-encoding an already percent-encoded string. + +2.5. Identifying Data + + URI characters provide identifying data for each of the URI + components, serving as an external interface for identification + between systems. Although the presence and nature of the URI + production interface is hidden from clients that use its URIs (and is + thus beyond the scope of the interoperability requirements defined by + this specification), it is a frequent source of confusion and errors + in the interpretation of URI character issues. Implementers have to + be aware that there are multiple character encodings involved in the + + + +Berners-Lee, et al. Standards Track [Page 14] + +RFC 3986 URI Generic Syntax January 2005 + + + production and transmission of URIs: local name and data encoding, + public interface encoding, URI character encoding, data format + encoding, and protocol encoding. + + Local names, such as file system names, are stored with a local + character encoding. URI producing applications (e.g., origin + servers) will typically use the local encoding as the basis for + producing meaningful names. The URI producer will transform the + local encoding to one that is suitable for a public interface and + then transform the public interface encoding into the restricted set + of URI characters (reserved, unreserved, and percent-encodings). + Those characters are, in turn, encoded as octets to be used as a + reference within a data format (e.g., a document charset), and such + data formats are often subsequently encoded for transmission over + Internet protocols. + + For most systems, an unreserved character appearing within a URI + component is interpreted as representing the data octet corresponding + to that character's encoding in US-ASCII. Consumers of URIs assume + that the letter "X" corresponds to the octet "01011000", and even + when that assumption is incorrect, there is no harm in making it. A + system that internally provides identifiers in the form of a + different character encoding, such as EBCDIC, will generally perform + character translation of textual identifiers to UTF-8 [STD63] (or + some other superset of the US-ASCII character encoding) at an + internal interface, thereby providing more meaningful identifiers + than those resulting from simply percent-encoding the original + octets. + + For example, consider an information service that provides data, + stored locally using an EBCDIC-based file system, to clients on the + Internet through an HTTP server. When an author creates a file with + the name "Laguna Beach" on that file system, the "http" URI + corresponding to that resource is expected to contain the meaningful + string "Laguna%20Beach". If, however, that server produces URIs by + using an overly simplistic raw octet mapping, then the result would + be a URI containing "%D3%81%87%A4%95%81@%C2%85%81%83%88". An + internal transcoding interface fixes this problem by transcoding the + local name to a superset of US-ASCII prior to producing the URI. + Naturally, proper interpretation of an incoming URI on such an + interface requires that percent-encoded octets be decoded (e.g., + "%20" to SP) before the reverse transcoding is applied to obtain the + local name. + + In some cases, the internal interface between a URI component and the + identifying data that it has been crafted to represent is much less + direct than a character encoding translation. For example, portions + of a URI might reflect a query on non-ASCII data, or numeric + + + +Berners-Lee, et al. Standards Track [Page 15] + +RFC 3986 URI Generic Syntax January 2005 + + + coordinates on a map. Likewise, a URI scheme may define components + with additional encoding requirements that are applied prior to + forming the component and producing the URI. + + When a new URI scheme defines a component that represents textual + data consisting of characters from the Universal Character Set [UCS], + the data should first be encoded as octets according to the UTF-8 + character encoding [STD63]; then only those octets that do not + correspond to characters in the unreserved set should be percent- + encoded. For example, the character A would be represented as "A", + the character LATIN CAPITAL LETTER A WITH GRAVE would be represented + as "%C3%80", and the character KATAKANA LETTER A would be represented + as "%E3%82%A2". + +3. Syntax Components + + The generic URI syntax consists of a hierarchical sequence of + components referred to as the scheme, authority, path, query, and + fragment. + + URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + + hier-part = "//" authority path-abempty + / path-absolute + / path-rootless + / path-empty + + The scheme and path components are required, though the path may be + empty (no characters). When authority is present, the path must + either be empty or begin with a slash ("/") character. When + authority is not present, the path cannot begin with two slash + characters ("//"). These restrictions result in five different ABNF + rules for a path (Section 3.3), only one of which will match any + given URI reference. + + The following are two example URIs and their component parts: + + foo://example.com:8042/over/there?name=ferret#nose + \_/ \______________/\_________/ \_________/ \__/ + | | | | | + scheme authority path query fragment + | _____________________|__ + / \ / \ + urn:example:animal:ferret:nose + + + + + + + +Berners-Lee, et al. Standards Track [Page 16] + +RFC 3986 URI Generic Syntax January 2005 + + +3.1. Scheme + + Each URI begins with a scheme name that refers to a specification for + assigning identifiers within that scheme. As such, the URI syntax is + a federated and extensible naming system wherein each scheme's + specification may further restrict the syntax and semantics of + identifiers using that scheme. + + Scheme names consist of a sequence of characters beginning with a + letter and followed by any combination of letters, digits, plus + ("+"), period ("."), or hyphen ("-"). Although schemes are case- + insensitive, the canonical form is lowercase and documents that + specify schemes must do so with lowercase letters. An implementation + should accept uppercase letters as equivalent to lowercase in scheme + names (e.g., allow "HTTP" as well as "http") for the sake of + robustness but should only produce lowercase scheme names for + consistency. + + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + + Individual schemes are not specified by this document. The process + for registration of new URI schemes is defined separately by [BCP35]. + The scheme registry maintains the mapping between scheme names and + their specifications. Advice for designers of new URI schemes can be + found in [RFC2718]. URI scheme specifications must define their own + syntax so that all strings matching their scheme-specific syntax will + also match the grammar, as described in Section 4.3. + + When presented with a URI that violates one or more scheme-specific + restrictions, the scheme-specific resolution process should flag the + reference as an error rather than ignore the unused parts; doing so + reduces the number of equivalent URIs and helps detect abuses of the + generic syntax, which might indicate that the URI has been + constructed to mislead the user (Section 7.6). + +3.2. Authority + + Many URI schemes include a hierarchical element for a naming + authority so that governance of the name space defined by the + remainder of the URI is delegated to that authority (which may, in + turn, delegate it further). The generic syntax provides a common + means for distinguishing an authority based on a registered name or + server address, along with optional port and user information. + + The authority component is preceded by a double slash ("//") and is + terminated by the next slash ("/"), question mark ("?"), or number + sign ("#") character, or by the end of the URI. + + + + +Berners-Lee, et al. Standards Track [Page 17] + +RFC 3986 URI Generic Syntax January 2005 + + + authority = [ userinfo "@" ] host [ ":" port ] + + URI producers and normalizers should omit the ":" delimiter that + separates host from port if the port component is empty. Some + schemes do not allow the userinfo and/or port subcomponents. + + If a URI contains an authority component, then the path component + must either be empty or begin with a slash ("/") character. Non- + validating parsers (those that merely separate a URI reference into + its major components) will often ignore the subcomponent structure of + authority, treating it as an opaque string from the double-slash to + the first terminating delimiter, until such time as the URI is + dereferenced. + +3.2.1. User Information + + The userinfo subcomponent may consist of a user name and, optionally, + scheme-specific information about how to gain authorization to access + the resource. The user information, if present, is followed by a + commercial at-sign ("@") that delimits it from the host. + + userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + + Use of the format "user:password" in the userinfo field is + deprecated. Applications should not render as clear text any data + after the first colon (":") character found within a userinfo + subcomponent unless the data after the colon is the empty string + (indicating no password). Applications may choose to ignore or + reject such data when it is received as part of a reference and + should reject the storage of such data in unencrypted form. The + passing of authentication information in clear text has proven to be + a security risk in almost every case where it has been used. + + Applications that render a URI for the sake of user feedback, such as + in graphical hypertext browsing, should render userinfo in a way that + is distinguished from the rest of a URI, when feasible. Such + rendering will assist the user in cases where the userinfo has been + misleadingly crafted to look like a trusted domain name + (Section 7.6). + +3.2.2. Host + + The host subcomponent of authority is identified by an IP literal + encapsulated within square brackets, an IPv4 address in dotted- + decimal form, or a registered name. The host subcomponent is case- + insensitive. The presence of a host subcomponent within a URI does + not imply that the scheme requires access to the given host on the + Internet. In many cases, the host syntax is used only for the sake + + + +Berners-Lee, et al. Standards Track [Page 18] + +RFC 3986 URI Generic Syntax January 2005 + + + of reusing the existing registration process created and deployed for + DNS, thus obtaining a globally unique name without the cost of + deploying another registry. However, such use comes with its own + costs: domain name ownership may change over time for reasons not + anticipated by the URI producer. In other cases, the data within the + host component identifies a registered name that has nothing to do + with an Internet host. We use the name "host" for the ABNF rule + because that is its most common purpose, not its only purpose. + + host = IP-literal / IPv4address / reg-name + + The syntax rule for host is ambiguous because it does not completely + distinguish between an IPv4address and a reg-name. In order to + disambiguate the syntax, we apply the "first-match-wins" algorithm: + If host matches the rule for IPv4address, then it should be + considered an IPv4 address literal and not a reg-name. Although host + is case-insensitive, producers and normalizers should use lowercase + for registered names and hexadecimal addresses for the sake of + uniformity, while only using uppercase letters for percent-encodings. + + A host identified by an Internet Protocol literal address, version 6 + [RFC3513] or later, is distinguished by enclosing the IP literal + within square brackets ("[" and "]"). This is the only place where + square bracket characters are allowed in the URI syntax. In + anticipation of future, as-yet-undefined IP literal address formats, + an implementation may use an optional version flag to indicate such a + format explicitly rather than rely on heuristic determination. + + IP-literal = "[" ( IPv6address / IPvFuture ) "]" + + IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + + The version flag does not indicate the IP version; rather, it + indicates future versions of the literal format. As such, + implementations must not provide the version flag for the existing + IPv4 and IPv6 literal address forms described below. If a URI + containing an IP-literal that starts with "v" (case-insensitive), + indicating that the version flag is present, is dereferenced by an + application that does not know the meaning of that version flag, then + the application should return an appropriate error for "address + mechanism not supported". + + A host identified by an IPv6 literal address is represented inside + the square brackets without a preceding version flag. The ABNF + provided here is a translation of the text definition of an IPv6 + literal address provided in [RFC3513]. This syntax does not support + IPv6 scoped addressing zone identifiers. + + + + +Berners-Lee, et al. Standards Track [Page 19] + +RFC 3986 URI Generic Syntax January 2005 + + + A 128-bit IPv6 address is divided into eight 16-bit pieces. Each + piece is represented numerically in case-insensitive hexadecimal, + using one to four hexadecimal digits (leading zeroes are permitted). + The eight encoded pieces are given most-significant first, separated + by colon characters. Optionally, the least-significant two pieces + may instead be represented in IPv4 address textual format. A + sequence of one or more consecutive zero-valued 16-bit pieces within + the address may be elided, omitting all their digits and leaving + exactly two consecutive colons in their place to mark the elision. + + IPv6address = 6( h16 ":" ) ls32 + / "::" 5( h16 ":" ) ls32 + / [ h16 ] "::" 4( h16 ":" ) ls32 + / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + / [ *4( h16 ":" ) h16 ] "::" ls32 + / [ *5( h16 ":" ) h16 ] "::" h16 + / [ *6( h16 ":" ) h16 ] "::" + + ls32 = ( h16 ":" h16 ) / IPv4address + ; least-significant 32 bits of address + + h16 = 1*4HEXDIG + ; 16 bits of address represented in hexadecimal + + A host identified by an IPv4 literal address is represented in + dotted-decimal notation (a sequence of four decimal numbers in the + range 0 to 255, separated by "."), as described in [RFC1123] by + reference to [RFC0952]. Note that other forms of dotted notation may + be interpreted on some platforms, as described in Section 7.4, but + only the dotted-decimal form of four octets is allowed by this + grammar. + + IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + + dec-octet = DIGIT ; 0-9 + / %x31-39 DIGIT ; 10-99 + / "1" 2DIGIT ; 100-199 + / "2" %x30-34 DIGIT ; 200-249 + / "25" %x30-35 ; 250-255 + + A host identified by a registered name is a sequence of characters + usually intended for lookup within a locally defined host or service + name registry, though the URI's scheme-specific semantics may require + that a specific registry (or fixed name table) be used instead. The + most common name registry mechanism is the Domain Name System (DNS). + A registered name intended for lookup in the DNS uses the syntax + + + +Berners-Lee, et al. Standards Track [Page 20] + +RFC 3986 URI Generic Syntax January 2005 + + + defined in Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123]. + Such a name consists of 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 in DNS may be followed by a + single "." and should be if it is necessary to distinguish between + the complete domain name and some local domain. + + reg-name = *( unreserved / pct-encoded / sub-delims ) + + If the URI scheme defines a default for host, then that default + applies when the host subcomponent is undefined or when the + registered name is empty (zero length). For example, the "file" URI + scheme is defined so that no authority, an empty host, and + "localhost" all mean the end-user's machine, whereas the "http" + scheme considers a missing authority or empty host invalid. + + This specification does not mandate a particular registered name + lookup technology and therefore does not restrict the syntax of reg- + name beyond what is necessary for interoperability. Instead, it + delegates the issue of registered name syntax conformance to the + operating system of each application performing URI resolution, and + that operating system decides what it will allow for the purpose of + host identification. A URI resolution implementation might use DNS, + host tables, yellow pages, NetInfo, WINS, or any other system for + lookup of registered names. However, a globally scoped naming + system, such as DNS fully qualified domain names, is necessary for + URIs intended to have global scope. URI producers should use names + that conform to the DNS syntax, even when use of DNS is not + immediately apparent, and should limit these names to no more than + 255 characters in length. + + The reg-name syntax allows percent-encoded octets in order to + represent non-ASCII registered names in a uniform way that is + independent of the underlying name resolution technology. Non-ASCII + characters must first be encoded according to UTF-8 [STD63], and then + each octet of the corresponding UTF-8 sequence must be percent- + encoded to be represented as URI characters. URI producing + applications must not use percent-encoding in host unless it is used + to represent a UTF-8 character sequence. When a non-ASCII registered + name represents an internationalized domain name intended for + resolution via the DNS, the name must be transformed to the IDNA + encoding [RFC3490] prior to name lookup. URI producers should + provide these registered names in the IDNA encoding, rather than a + percent-encoding, if they wish to maximize interoperability with + legacy URI resolvers. + + + + + +Berners-Lee, et al. Standards Track [Page 21] + +RFC 3986 URI Generic Syntax January 2005 + + +3.2.3. Port + + The port subcomponent of authority is designated by an optional port + number in decimal following the host and delimited from it by a + single colon (":") character. + + port = *DIGIT + + A scheme may define a default port. For example, the "http" scheme + defines a default port of "80", corresponding to its reserved TCP + port number. The type of port designated by the port number (e.g., + TCP, UDP, SCTP) is defined by the URI scheme. URI producers and + normalizers should omit the port component and its ":" delimiter if + port is empty or if its value would be the same as that of the + scheme's default. + +3.3. Path + + The path component contains data, usually organized in hierarchical + form, that, along with data in the non-hierarchical query component + (Section 3.4), serves to identify a resource within the scope of the + URI's scheme and naming authority (if any). The path is terminated + by the first question mark ("?") or number sign ("#") character, or + by the end of the URI. + + If a URI contains an authority component, then the path component + must either be empty or begin with a slash ("/") character. If a URI + does not contain an authority component, then the path cannot begin + with two slash characters ("//"). In addition, a URI reference + (Section 4.1) may be a relative-path reference, in which case the + first path segment cannot contain a colon (":") character. The ABNF + requires five separate rules to disambiguate these cases, only one of + which will match the path substring within a given URI reference. We + use the generic term "path component" to describe the URI substring + matched by the parser to one of these rules. + + path = path-abempty ; begins with "/" or is empty + / path-absolute ; begins with "/" but not "//" + / path-noscheme ; begins with a non-colon segment + / path-rootless ; begins with a segment + / path-empty ; zero characters + + path-abempty = *( "/" segment ) + path-absolute = "/" [ segment-nz *( "/" segment ) ] + path-noscheme = segment-nz-nc *( "/" segment ) + path-rootless = segment-nz *( "/" segment ) + path-empty = 0 + + + + +Berners-Lee, et al. Standards Track [Page 22] + +RFC 3986 URI Generic Syntax January 2005 + + + segment = *pchar + segment-nz = 1*pchar + segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + ; non-zero-length segment without any colon ":" + + pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + + A path consists of a sequence of path segments separated by a slash + ("/") character. A path is always defined for a URI, though the + defined path may be empty (zero length). Use of the slash character + to indicate hierarchy is only required when a URI will be used as the + context for relative references. For example, the URI + has a path of "fred@example.com", whereas + the URI has an empty path. + + The path segments "." and "..", also known as dot-segments, are + defined for relative reference within the path name hierarchy. They + are intended for use at the beginning of a relative-path reference + (Section 4.2) to indicate relative position within the hierarchical + tree of names. This is similar to their role within some operating + systems' file directory structures to indicate the current directory + and parent directory, respectively. However, unlike in a file + system, these dot-segments are only interpreted within the URI path + hierarchy and are removed as part of the resolution process (Section + 5.2). + + Aside from dot-segments in hierarchical paths, a path segment is + considered opaque by the generic syntax. URI producing applications + often use the reserved characters allowed in a segment to delimit + scheme-specific or dereference-handler-specific subcomponents. For + example, the semicolon (";") and equals ("=") reserved characters are + often used to delimit parameters and parameter values applicable to + that segment. The comma (",") reserved character is often used for + similar purposes. For example, one URI producer might use a segment + such as "name;v=1.1" to indicate a reference to version 1.1 of + "name", whereas another might use a segment such as "name,1.1" to + indicate the same. Parameter types may be defined by scheme-specific + semantics, but in most cases the syntax of a parameter is specific to + the implementation of the URI's dereferencing algorithm. + +3.4. Query + + The query component contains non-hierarchical data that, along with + data in the path component (Section 3.3), serves to identify a + resource within the scope of the URI's scheme and naming authority + (if any). The query component is indicated by the first question + mark ("?") character and terminated by a number sign ("#") character + or by the end of the URI. + + + +Berners-Lee, et al. Standards Track [Page 23] + +RFC 3986 URI Generic Syntax January 2005 + + + query = *( pchar / "/" / "?" ) + + The characters slash ("/") and question mark ("?") may represent data + within the query component. Beware that some older, erroneous + implementations may not handle such data correctly when it is used as + the base URI for relative references (Section 5.1), apparently + because they fail to distinguish query data from path data when + looking for hierarchical separators. However, as query components + are often used to carry identifying information in the form of + "key=value" pairs and one frequently used value is a reference to + another URI, it is sometimes better for usability to avoid percent- + encoding those characters. + +3.5. Fragment + + The fragment identifier component of a URI allows indirect + identification of a secondary resource by reference to a primary + resource and additional identifying information. The identified + secondary resource may be some portion or subset of the primary + resource, some view on representations of the primary resource, or + some other resource defined or described by those representations. A + fragment identifier component is indicated by the presence of a + number sign ("#") character and terminated by the end of the URI. + + fragment = *( pchar / "/" / "?" ) + + The semantics of a fragment identifier are defined by the set of + representations that might result from a retrieval action on the + primary resource. The fragment's format and resolution is therefore + dependent on the media type [RFC2046] of a potentially retrieved + representation, even though such a retrieval is only performed if the + URI is dereferenced. If no such representation exists, then the + semantics of the fragment are considered unknown and are effectively + unconstrained. Fragment identifier semantics are independent of the + URI scheme and thus cannot be redefined by scheme specifications. + + Individual media types may define their own restrictions on or + structures within the fragment identifier syntax for specifying + different types of subsets, views, or external references that are + identifiable as secondary resources by that media type. If the + primary resource has multiple representations, as is often the case + for resources whose representation is selected based on attributes of + the retrieval request (a.k.a., content negotiation), then whatever is + identified by the fragment should be consistent across all of those + representations. Each representation should either define the + fragment so that it corresponds to the same secondary resource, + regardless of how it is represented, or should leave the fragment + undefined (i.e., not found). + + + +Berners-Lee, et al. Standards Track [Page 24] + +RFC 3986 URI Generic Syntax January 2005 + + + As with any URI, use of a fragment identifier component does not + imply that a retrieval action will take place. A URI with a fragment + identifier may be used to refer to the secondary resource without any + implication that the primary resource is accessible or will ever be + accessed. + + Fragment identifiers have a special role in information retrieval + systems as the primary form of client-side indirect referencing, + allowing an author to specifically identify aspects of an existing + resource that are only indirectly provided by the resource owner. As + such, the fragment identifier is not used in the scheme-specific + processing of a URI; instead, the fragment identifier is separated + from the rest of the URI prior to a dereference, and thus the + identifying information within the fragment itself is dereferenced + solely by the user agent, regardless of the URI scheme. Although + this separate handling is often perceived to be a loss of + information, particularly for accurate redirection of references as + resources move over time, it also serves to prevent information + providers from denying reference authors the right to refer to + information within a resource selectively. Indirect referencing also + provides additional flexibility and extensibility to systems that use + URIs, as new media types are easier to define and deploy than new + schemes of identification. + + The characters slash ("/") and question mark ("?") are allowed to + represent data within the fragment identifier. Beware that some + older, erroneous implementations may not handle this data correctly + when it is used as the base URI for relative references (Section + 5.1). + +4. Usage + + When applications make reference to a URI, they do not always use the + full form of reference defined by the "URI" syntax rule. To save + space and take advantage of hierarchical locality, many Internet + protocol elements and media type formats allow an abbreviation of a + URI, whereas others restrict the syntax to a particular form of URI. + We define the most common forms of reference syntax in this + specification because they impact and depend upon the design of the + generic syntax, requiring a uniform parsing algorithm in order to be + interpreted consistently. + +4.1. URI Reference + + URI-reference is used to denote the most common usage of a resource + identifier. + + URI-reference = URI / relative-ref + + + +Berners-Lee, et al. Standards Track [Page 25] + +RFC 3986 URI Generic Syntax January 2005 + + + A URI-reference is either a URI or a relative reference. If the + URI-reference's prefix does not match the syntax of a scheme followed + by its colon separator, then the URI-reference is a relative + reference. + + A URI-reference is typically parsed first into the five URI + components, in order to determine what components are present and + whether the reference is relative. Then, each component is parsed + for its subparts and their validation. The ABNF of URI-reference, + along with the "first-match-wins" disambiguation rule, is sufficient + to define a validating parser for the generic syntax. Readers + familiar with regular expressions should see Appendix B for an + example of a non-validating URI-reference parser that will take any + given string and extract the URI components. + +4.2. Relative Reference + + A relative reference takes advantage of the hierarchical syntax + (Section 1.2.3) to express a URI reference relative to the name space + of another hierarchical URI. + + relative-ref = relative-part [ "?" query ] [ "#" fragment ] + + relative-part = "//" authority path-abempty + / path-absolute + / path-noscheme + / path-empty + + The URI referred to by a relative reference, also known as the target + URI, is obtained by applying the reference resolution algorithm of + Section 5. + + A relative reference that begins with two slash characters is termed + a network-path reference; such references are rarely used. A + relative reference that begins with a single slash character is + termed an absolute-path reference. A relative reference that does + not begin with a slash character is termed a relative-path reference. + + A path segment that contains a colon character (e.g., "this:that") + cannot be used as the first segment of a relative-path reference, as + it would be mistaken for a scheme name. Such a segment must be + preceded by a dot-segment (e.g., "./this:that") to make a relative- + path reference. + + + + + + + + +Berners-Lee, et al. Standards Track [Page 26] + +RFC 3986 URI Generic Syntax January 2005 + + +4.3. Absolute URI + + Some protocol elements allow only the absolute form of a URI without + a fragment identifier. For example, defining a base URI for later + use by relative references calls for an absolute-URI syntax rule that + does not allow a fragment. + + absolute-URI = scheme ":" hier-part [ "?" query ] + + URI scheme specifications must define their own syntax so that all + strings matching their scheme-specific syntax will also match the + grammar. Scheme specifications will not define + fragment identifier syntax or usage, regardless of its applicability + to resources identifiable via that scheme, as fragment identification + is orthogonal to scheme definition. However, scheme specifications + are encouraged to include a wide range of examples, including + examples that show use of the scheme's URIs with fragment identifiers + when such usage is appropriate. + +4.4. Same-Document Reference + + When a URI reference refers to a URI that is, aside from its fragment + component (if any), identical to the base URI (Section 5.1), that + reference is called a "same-document" reference. The most frequent + examples of same-document references are relative references that are + empty or include only the number sign ("#") separator followed by a + fragment identifier. + + When a same-document reference is dereferenced for a retrieval + action, the target of that reference is defined to be within the same + entity (representation, document, or message) as the reference; + therefore, a dereference should not result in a new retrieval action. + + Normalization of the base and target URIs prior to their comparison, + as described in Sections 6.2.2 and 6.2.3, is allowed but rarely + performed in practice. Normalization may increase the set of same- + document references, which may be of benefit to some caching + applications. As such, reference authors should not assume that a + slightly different, though equivalent, reference URI will (or will + not) be interpreted as a same-document reference by any given + application. + +4.5. Suffix Reference + + The URI syntax is designed for unambiguous reference to resources and + extensibility via the URI scheme. However, as URI identification and + usage have become commonplace, traditional media (television, radio, + newspapers, billboards, etc.) have increasingly used a suffix of the + + + +Berners-Lee, et al. Standards Track [Page 27] + +RFC 3986 URI Generic Syntax January 2005 + + + URI as a reference, consisting of only the authority and path + portions of the URI, such as + + www.w3.org/Addressing/ + + or simply a DNS registered name on its own. Such references are + primarily intended for human interpretation rather than for machines, + with the assumption that context-based heuristics are sufficient to + complete the URI (e.g., most registered names beginning with "www" + are likely to have a URI prefix of "http://"). Although there is no + standard set of heuristics for disambiguating a URI suffix, many + client implementations allow them to be entered by the user and + heuristically resolved. + + Although this practice of using suffix references is common, it + should be avoided whenever possible and should never be used in + situations where long-term references are expected. The heuristics + noted above will change over time, particularly when a new URI scheme + becomes popular, and are often incorrect when used out of context. + Furthermore, they can lead to security issues along the lines of + those described in [RFC1535]. + + As a URI suffix has the same syntax as a relative-path reference, a + suffix reference cannot be used in contexts where a relative + reference is expected. As a result, suffix references are limited to + places where there is no defined base URI, such as dialog boxes and + off-line advertisements. + +5. Reference Resolution + + This section defines the process of resolving a URI reference within + a context that allows relative references so that the result is a + string matching the syntax rule of Section 3. + +5.1. Establishing a Base URI + + The term "relative" implies that a "base URI" exists against which + the relative reference is applied. Aside from fragment-only + references (Section 4.4), relative references are only usable when a + base URI is known. A base URI must be established by the parser + prior to parsing URI references that might be relative. A base URI + must conform to the syntax rule (Section 4.3). If the + base URI is obtained from a URI reference, then that reference must + be converted to absolute form and stripped of any fragment component + prior to its use as a base URI. + + + + + + +Berners-Lee, et al. Standards Track [Page 28] + +RFC 3986 URI Generic Syntax January 2005 + + + The base URI of a reference can be established in one of four ways, + discussed 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 follows: + + .----------------------------------------------------------. + | .----------------------------------------------------. | + | | .----------------------------------------------. | | + | | | .----------------------------------------. | | | + | | | | .----------------------------------. | | | | + | | | | | | | | | | + | | | | `----------------------------------' | | | | + | | | | (5.1.1) Base URI embedded in content | | | | + | | | `----------------------------------------' | | | + | | | (5.1.2) Base URI of the encapsulating entity | | | + | | | (message, representation, or none) | | | + | | `----------------------------------------------' | | + | | (5.1.3) URI used to retrieve the entity | | + | `----------------------------------------------------' | + | (5.1.4) Default Base URI (application-dependent) | + `----------------------------------------------------------' + +5.1.1. Base URI Embedded in Content + + Within certain media types, a base URI for relative references can be + embedded within the content itself so that it can be readily obtained + by a parser. This can be useful for descriptive documents, such as + tables of contents, which may be transmitted to others through + protocols other than their usual retrieval context (e.g., email or + USENET news). + + It is beyond the scope of this specification to specify how, for each + media type, a base URI can be embedded. The appropriate syntax, when + available, is described by the data format specification associated + with each media type. + +5.1.2. Base URI from the Encapsulating Entity + + If no base URI is embedded, the base URI is defined by the + representation's retrieval context. For a document that is enclosed + within another entity, such as a message or archive, the retrieval + context is that entity. Thus, the default base URI of a + representation is the base URI of the entity in which the + representation is encapsulated. + + + + + + +Berners-Lee, et al. Standards Track [Page 29] + +RFC 3986 URI Generic Syntax January 2005 + + + A mechanism for embedding a base URI within MIME container types + (e.g., the message and multipart types) is defined by MHTML + [RFC2557]. Protocols that do not use the MIME message header syntax, + but that do allow some form of tagged metadata to be included within + messages, may define their own syntax for defining a base URI as part + of a message. + +5.1.3. Base URI from the Retrieval URI + + If no base URI is embedded and the representation is not encapsulated + within some other entity, then, if a URI was used to retrieve the + representation, 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., the URI that resulted in the actual retrieval of the + representation) is the base URI. + +5.1.4. Default Base URI + + If none of the conditions described above apply, then the base URI is + defined by the context of the application. As this definition is + necessarily application-dependent, failing to define a base URI by + using one of the other methods may result in the same content being + interpreted differently by different types of applications. + + A sender of a representation containing relative references is + responsible for ensuring that a base URI for those references can be + established. Aside from fragment-only references, relative + references can only be used reliably in situations where the base URI + is well defined. + +5.2. Relative Resolution + + This section describes an algorithm for converting a URI reference + that might be relative to a given base URI into the parsed components + of the reference's target. The components can then be recomposed, as + described in Section 5.3, to form the target URI. This algorithm + provides definitive results that can be used to test the output of + other implementations. Applications may implement relative reference + resolution by using some other algorithm, provided that the results + match what would be given by this one. + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 30] + +RFC 3986 URI Generic Syntax January 2005 + + +5.2.1. Pre-parse the Base URI + + The base URI (Base) is established according to the procedure of + Section 5.1 and parsed into the five main components described in + Section 3. Note that only the scheme component is required to be + present in a base URI; the other components may be empty or + undefined. A component is undefined if its associated delimiter does + not appear in the URI reference; the path component is never + undefined, though it may be empty. + + Normalization of the base URI, as described in Sections 6.2.2 and + 6.2.3, is optional. A URI reference must be transformed to its + target URI before it can be normalized. + +5.2.2. Transform References + + For each URI reference (R), the following pseudocode describes an + algorithm for transforming R into its target URI (T): + + -- The URI reference is parsed into the five URI components + -- + (R.scheme, R.authority, R.path, R.query, R.fragment) = parse(R); + + -- A non-strict parser may ignore a scheme in the reference + -- if it is identical to the base URI's scheme. + -- + if ((not strict) and (R.scheme == Base.scheme)) then + undefine(R.scheme); + endif; + + + + + + + + + + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 31] + +RFC 3986 URI Generic Syntax January 2005 + + + if defined(R.scheme) then + T.scheme = R.scheme; + T.authority = R.authority; + T.path = remove_dot_segments(R.path); + T.query = R.query; + else + if defined(R.authority) then + T.authority = R.authority; + T.path = remove_dot_segments(R.path); + T.query = R.query; + else + if (R.path == "") then + T.path = Base.path; + if defined(R.query) then + T.query = R.query; + else + T.query = Base.query; + endif; + else + if (R.path starts-with "/") then + T.path = remove_dot_segments(R.path); + else + T.path = merge(Base.path, R.path); + T.path = remove_dot_segments(T.path); + endif; + T.query = R.query; + endif; + T.authority = Base.authority; + endif; + T.scheme = Base.scheme; + endif; + + T.fragment = R.fragment; + +5.2.3. Merge Paths + + The pseudocode above refers to a "merge" routine for merging a + relative-path reference with the path of the base URI. This is + accomplished as follows: + + o If the base URI has a defined authority component and an empty + path, then return a string consisting of "/" concatenated with the + reference's path; otherwise, + + + + + + + + +Berners-Lee, et al. Standards Track [Page 32] + +RFC 3986 URI Generic Syntax January 2005 + + + o return a string consisting of the reference's path component + appended to all but the last segment of the base URI's path (i.e., + excluding any characters after the right-most "/" in the base URI + path, or excluding the entire base URI path if it does not contain + any "/" characters). + +5.2.4. Remove Dot Segments + + The pseudocode also refers to a "remove_dot_segments" routine for + interpreting and removing the special "." and ".." complete path + segments from a referenced path. This is done after the path is + extracted from a reference, whether or not the path was relative, in + order to remove any invalid or extraneous dot-segments prior to + forming the target URI. Although there are many ways to accomplish + this removal process, we describe a simple method using two string + buffers. + + 1. The input buffer is initialized with the now-appended path + components and the output buffer is initialized to the empty + string. + + 2. While the input buffer is not empty, loop as follows: + + A. If the input buffer begins with a prefix of "../" or "./", + then remove that prefix from the input buffer; otherwise, + + B. if the input buffer begins with a prefix of "/./" or "/.", + where "." is a complete path segment, then replace that + prefix with "/" in the input buffer; otherwise, + + C. if the input buffer begins with a prefix of "/../" or "/..", + where ".." is a complete path segment, then replace that + prefix with "/" in the input buffer and remove the last + segment and its preceding "/" (if any) from the output + buffer; otherwise, + + D. if the input buffer consists only of "." or "..", then remove + that from the input buffer; otherwise, + + E. move the first path segment in the input buffer to the end of + the output buffer, including the initial "/" character (if + any) and any subsequent characters up to, but not including, + the next "/" character or the end of the input buffer. + + 3. Finally, the output buffer is returned as the result of + remove_dot_segments. + + + + + +Berners-Lee, et al. Standards Track [Page 33] + +RFC 3986 URI Generic Syntax January 2005 + + + Note that dot-segments are intended for use in URI references to + express an identifier relative to the hierarchy of names in the base + URI. The remove_dot_segments algorithm respects that hierarchy by + removing extra dot-segments rather than treat them as an error or + leaving them to be misinterpreted by dereference implementations. + + The following illustrates how the above steps are applied for two + examples of merged paths, showing the state of the two buffers after + each step. + + STEP OUTPUT BUFFER INPUT BUFFER + + 1 : /a/b/c/./../../g + 2E: /a /b/c/./../../g + 2E: /a/b /c/./../../g + 2E: /a/b/c /./../../g + 2B: /a/b/c /../../g + 2C: /a/b /../g + 2C: /a /g + 2E: /a/g + + STEP OUTPUT BUFFER INPUT BUFFER + + 1 : mid/content=5/../6 + 2E: mid /content=5/../6 + 2E: mid/content=5 /../6 + 2C: mid /6 + 2E: mid/6 + + Some applications may find it more efficient to implement the + remove_dot_segments algorithm by using two segment stacks rather than + strings. + + Note: Beware that some older, erroneous implementations will fail + to separate a reference's query component from its path component + prior to merging the base and reference paths, resulting in an + interoperability failure if the query component contains the + strings "/../" or "/./". + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 34] + +RFC 3986 URI Generic Syntax January 2005 + + +5.3. Component Recomposition + + Parsed URI components can be recomposed to obtain the corresponding + URI reference string. Using pseudocode, this would be: + + result = "" + + if defined(scheme) then + append scheme to result; + append ":" to result; + endif; + + if defined(authority) then + append "//" to result; + append authority to result; + endif; + + append path to result; + + if defined(query) then + append "?" to result; + append query to result; + endif; + + if defined(fragment) then + append "#" to result; + append fragment to result; + endif; + + return result; + + Note that we are 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. + +5.4. Reference Resolution Examples + + Within a representation with a well defined base URI of + + http://a/b/c/d;p?q + + a relative reference is transformed to its target URI as follows. + + + + + + + +Berners-Lee, et al. Standards Track [Page 35] + +RFC 3986 URI Generic Syntax January 2005 + + +5.4.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/d;p?y" + "g?y" = "http://a/b/c/g?y" + "#s" = "http://a/b/c/d;p?q#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/d;p?q" + "." = "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" + +5.4.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 that above. + + Parsers must be careful in handling cases where there are more ".." + segments in a relative-path reference 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. + + "../../../g" = "http://a/g" + "../../../../g" = "http://a/g" + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 36] + +RFC 3986 URI Generic Syntax January 2005 + + + Similarly, parsers must remove the dot-segments "." and ".." when + they are complete components of a path, but not when they are only + part of a segment. + + "/./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 reference 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" + + Some applications fail to separate the reference's query and/or + fragment components from the path component before merging it with + the base path and removing dot-segments. This error is rarely + noticed, as 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" + + Some parsers allow the scheme name to be present in a relative + reference 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 but is allowed for backward + compatibility. + + "http:g" = "http:g" ; for strict parsers + / "http://a/b/c/g" ; for backward compatibility + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 37] + +RFC 3986 URI Generic Syntax January 2005 + + +6. Normalization and Comparison + + One of the most common operations on URIs is simple comparison: + determining whether two URIs are equivalent without using the URIs to + access their respective resource(s). A comparison is performed every + time a response cache is accessed, a browser checks its history to + color a link, or an XML parser processes tags within a namespace. + Extensive normalization prior to comparison of URIs is often used by + spiders and indexing engines to prune a search space or to reduce + duplication of request actions and response storage. + + URI comparison is performed for some particular purpose. Protocols + or implementations that compare URIs for different purposes will + often be subject to differing design trade-offs in regards to how + much effort should be spent in reducing aliased identifiers. This + section describes various methods that may be used to compare URIs, + the trade-offs between them, and the types of applications that might + use them. + +6.1. Equivalence + + Because URIs exist to identify resources, presumably they should be + considered equivalent when they identify the same resource. However, + this definition of equivalence is not of much practical use, as there + is no way for an implementation to compare two resources unless it + has full knowledge or control of them. For this reason, + determination of equivalence or difference of URIs is based on string + comparison, perhaps augmented by reference to additional rules + provided by URI scheme definitions. We use the terms "different" and + "equivalent" to describe the possible outcomes of such comparisons, + but there are many application-dependent versions of equivalence. + + Even though it is possible to determine that two URIs are equivalent, + URI comparison is not sufficient to determine whether two URIs + identify different resources. For example, an owner of two different + domain names could decide to serve the same resource from both, + resulting in two different URIs. Therefore, comparison methods are + designed to minimize false negatives while strictly avoiding false + positives. + + In testing for equivalence, applications should not directly compare + relative references; the references should be converted to their + respective target URIs before comparison. When URIs are compared to + select (or avoid) a network action, such as retrieval of a + representation, fragment components (if any) should be excluded from + the comparison. + + + + + +Berners-Lee, et al. Standards Track [Page 38] + +RFC 3986 URI Generic Syntax January 2005 + + +6.2. Comparison Ladder + + A variety of methods are used in practice to test URI equivalence. + These methods fall into a range, distinguished by the amount of + processing required and the degree to which the probability of false + negatives is reduced. As noted above, false negatives cannot be + eliminated. In practice, their probability can be reduced, but this + reduction requires more processing and is not cost-effective for all + applications. + + If this range of comparison practices is considered as a ladder, the + following discussion will climb the ladder, starting with practices + that are cheap but have a relatively higher chance of producing false + negatives, and proceeding to those that have higher computational + cost and lower risk of false negatives. + +6.2.1. Simple String Comparison + + If two URIs, when considered as character strings, are identical, + then it is safe to conclude that they are equivalent. This type of + equivalence test has very low computational cost and is in wide use + in a variety of applications, particularly in the domain of parsing. + + Testing strings for equivalence requires some basic precautions. + This procedure is often referred to as "bit-for-bit" or + "byte-for-byte" comparison, which is potentially misleading. Testing + strings for equality is normally based on pair comparison of the + characters that make up the strings, starting from the first and + proceeding until both strings are exhausted and all characters are + found to be equal, until a pair of characters compares unequal, or + until one of the strings is exhausted before the other. + + This character comparison requires that each pair of characters be + put in comparable form. For example, should one URI be stored in a + byte array in EBCDIC encoding and the second in a Java String object + (UTF-16), bit-for-bit comparisons applied naively will produce + errors. It is better to speak of equality on a character-for- + character basis rather than on a byte-for-byte or bit-for-bit basis. + In practical terms, character-by-character comparisons should be done + codepoint-by-codepoint after conversion to a common character + encoding. + + False negatives are caused by the production and use of URI aliases. + Unnecessary aliases can be reduced, regardless of the comparison + method, by consistently providing URI references in an already- + normalized form (i.e., a form identical to what would be produced + after normalization is applied, as described below). + + + + +Berners-Lee, et al. Standards Track [Page 39] + +RFC 3986 URI Generic Syntax January 2005 + + + Protocols and data formats often limit some URI comparisons to simple + string comparison, based on the theory that people and + implementations will, in their own best interest, be consistent in + providing URI references, or at least consistent enough to negate any + efficiency that might be obtained from further normalization. + +6.2.2. Syntax-Based Normalization + + Implementations may use logic based on the definitions provided by + this specification to reduce the probability of false negatives. + This processing is moderately higher in cost than character-for- + character string comparison. For example, an application using this + approach could reasonably consider the following two URIs equivalent: + + example://a/b/c/%7Bfoo%7D + eXAMPLE://a/./b/../b/%63/%7bfoo%7d + + Web user agents, such as browsers, typically apply this type of URI + normalization when determining whether a cached response is + available. Syntax-based normalization includes such techniques as + case normalization, percent-encoding normalization, and removal of + dot-segments. + +6.2.2.1. Case Normalization + + For all URIs, the hexadecimal digits within a percent-encoding + triplet (e.g., "%3a" versus "%3A") are case-insensitive and therefore + should be normalized to use uppercase letters for the digits A-F. + + When a URI uses components of the generic syntax, the component + syntax equivalence rules always apply; namely, that the scheme and + host are case-insensitive and therefore should be normalized to + lowercase. For example, the URI is + equivalent to . The other generic syntax + components are assumed to be case-sensitive unless specifically + defined otherwise by the scheme (see Section 6.2.3). + +6.2.2.2. Percent-Encoding Normalization + + The percent-encoding mechanism (Section 2.1) is a frequent source of + variance among otherwise identical URIs. In addition to the case + normalization issue noted above, some URI producers percent-encode + octets that do not require percent-encoding, resulting in URIs that + are equivalent to their non-encoded counterparts. These URIs should + be normalized by decoding any percent-encoded octet that corresponds + to an unreserved character, as described in Section 2.3. + + + + + +Berners-Lee, et al. Standards Track [Page 40] + +RFC 3986 URI Generic Syntax January 2005 + + +6.2.2.3. Path Segment Normalization + + The complete path segments "." and ".." are intended only for use + within relative references (Section 4.1) and are removed as part of + the reference resolution process (Section 5.2). However, some + deployed implementations incorrectly assume that reference resolution + is not necessary when the reference is already a URI and thus fail to + remove dot-segments when they occur in non-relative paths. URI + normalizers should remove dot-segments by applying the + remove_dot_segments algorithm to the path, as described in + Section 5.2.4. + +6.2.3. Scheme-Based Normalization + + The syntax and semantics of URIs vary from scheme to scheme, as + described by the defining specification for each scheme. + Implementations may use scheme-specific rules, at further processing + cost, to reduce the probability of false negatives. For example, + because the "http" scheme makes use of an authority component, has a + default port of "80", and defines an empty path to be equivalent to + "/", the following four URIs are equivalent: + + http://example.com + http://example.com/ + http://example.com:/ + http://example.com:80/ + + In general, a URI that uses the generic syntax for authority with an + empty path should be normalized to a path of "/". Likewise, an + explicit ":port", for which the port is empty or the default for the + scheme, is equivalent to one where the port and its ":" delimiter are + elided and thus should be removed by scheme-based normalization. For + example, the second URI above is the normal form for the "http" + scheme. + + Another case where normalization varies by scheme is in the handling + of an empty authority component or empty host subcomponent. For many + scheme specifications, an empty authority or host is considered an + error; for others, it is considered equivalent to "localhost" or the + end-user's host. When a scheme defines a default for authority and a + URI reference to that default is desired, the reference should be + normalized to an empty authority for the sake of uniformity, brevity, + and internationalization. If, however, either the userinfo or port + subcomponents are non-empty, then the host should be given explicitly + even if it matches the default. + + Normalization should not remove delimiters when their associated + component is empty unless licensed to do so by the scheme + + + +Berners-Lee, et al. Standards Track [Page 41] + +RFC 3986 URI Generic Syntax January 2005 + + + specification. For example, the URI "http://example.com/?" cannot be + assumed to be equivalent to any of the examples above. Likewise, the + presence or absence of delimiters within a userinfo subcomponent is + usually significant to its interpretation. The fragment component is + not subject to any scheme-based normalization; thus, two URIs that + differ only by the suffix "#" are considered different regardless of + the scheme. + + Some schemes define additional subcomponents that consist of case- + insensitive data, giving an implicit license to normalizers to + convert this data to a common case (e.g., all lowercase). For + example, URI schemes that define a subcomponent of path to contain an + Internet hostname, such as the "mailto" URI scheme, cause that + subcomponent to be case-insensitive and thus subject to case + normalization (e.g., "mailto:Joe@Example.COM" is equivalent to + "mailto:Joe@example.com", even though the generic syntax considers + the path component to be case-sensitive). + + Other scheme-specific normalizations are possible. + +6.2.4. Protocol-Based Normalization + + Substantial effort to reduce the incidence of false negatives is + often cost-effective for web spiders. Therefore, they implement even + more aggressive techniques in URI comparison. For example, if they + observe that a URI such as + + http://example.com/data + + redirects to a URI differing only in the trailing slash + + http://example.com/data/ + + they will likely regard the two as equivalent in the future. This + kind of technique is only appropriate when equivalence is clearly + indicated by both the result of accessing the resources and the + common conventions of their scheme's dereference algorithm (in this + case, use of redirection by HTTP origin servers to avoid problems + with relative references). + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 42] + +RFC 3986 URI Generic Syntax January 2005 + + +7. Security Considerations + + A URI does not in itself pose a security threat. However, as URIs + are often used to provide a compact set of instructions for access to + network resources, care must be taken to properly interpret the data + within a URI, to prevent that data from causing unintended access, + and to avoid including data that should not be revealed in plain + text. + +7.1. Reliability and Consistency + + There is no guarantee that once a URI has been used to retrieve + information, the same information will be retrievable by that URI in + the future. Nor is there any guarantee that the information + retrievable via that URI in the future will be observably similar to + that retrieved in the past. The URI syntax does not constrain how a + given scheme or authority apportions its namespace or maintains it + over time. Such guarantees can only be obtained from the person(s) + controlling that namespace and the resource in question. A specific + URI scheme may define additional semantics, such as name persistence, + if those semantics are required of all naming authorities for that + scheme. + +7.2. Malicious Construction + + It is sometimes possible to construct a URI so that an attempt to + perform a seemingly harmless, idempotent operation, such as the + retrieval of a representation, will in fact cause a possibly damaging + remote operation. The unsafe URI is typically constructed by + specifying a port number other than that reserved for the network + protocol in question. The client unwittingly contacts a site running + a different protocol service, and data within the URI contains + instructions that, when interpreted according to this other protocol, + cause an unexpected operation. A frequent example of such abuse has + been the use of a protocol-based scheme with a port component of + "25", thereby fooling user agent software into sending an unintended + or impersonating message via an SMTP server. + + Applications should prevent dereference of a URI that specifies a TCP + port number within the "well-known port" range (0 - 1023) unless the + protocol being used to dereference that URI is compatible with the + protocol expected on that well-known port. Although IANA maintains a + registry of well-known ports, applications should make such + restrictions user-configurable to avoid preventing the deployment of + new services. + + + + + + +Berners-Lee, et al. Standards Track [Page 43] + +RFC 3986 URI Generic Syntax January 2005 + + + When a URI contains percent-encoded octets that match the delimiters + for a given resolution or dereference protocol (for example, CR and + LF characters for the TELNET protocol), these percent-encodings must + not be decoded before transmission across that protocol. Transfer of + the percent-encoding, which might violate the protocol, is less + harmful than allowing decoded octets to be interpreted as additional + operations or parameters, perhaps triggering an unexpected and + possibly harmful remote operation. + +7.3. Back-End Transcoding + + When a URI is dereferenced, the data within it is often parsed by + both the user agent and one or more servers. In HTTP, for example, a + typical user agent will parse a URI into its five major components, + access the authority's server, and send it the data within the + authority, path, and query components. A typical server will take + that information, parse the path into segments and the query into + key/value pairs, and then invoke implementation-specific handlers to + respond to the request. As a result, a common security concern for + server implementations that handle a URI, either as a whole or split + into separate components, is proper interpretation of the octet data + represented by the characters and percent-encodings within that URI. + + Percent-encoded octets must be decoded at some point during the + dereference process. Applications must split the URI into its + components and subcomponents prior to decoding the octets, as + otherwise the decoded octets might be mistaken for delimiters. + Security checks of the data within a URI should be applied after + decoding the octets. Note, however, that the "%00" percent-encoding + (NUL) may require special handling and should be rejected if the + application is not expecting to receive raw data within a component. + + Special care should be taken when the URI path interpretation process + involves the use of a back-end file system or related system + functions. File systems typically assign an operational meaning to + special characters, such as the "/", "\", ":", "[", and "]" + characters, and to special device names like ".", "..", "...", "aux", + "lpt", etc. In some cases, merely testing for the existence of such + a name will cause the operating system to pause or invoke unrelated + system calls, leading to significant security concerns regarding + denial of service and unintended data transfer. It would be + impossible for this specification to list all such significant + characters and device names. Implementers should research the + reserved names and characters for the types of storage device that + may be attached to their applications and restrict the use of data + obtained from URI components accordingly. + + + + + +Berners-Lee, et al. Standards Track [Page 44] + +RFC 3986 URI Generic Syntax January 2005 + + +7.4. Rare IP Address Formats + + Although the URI syntax for IPv4address only allows the common + dotted-decimal form of IPv4 address literal, many implementations + that process URIs make use of platform-dependent system routines, + such as gethostbyname() and inet_aton(), to translate the string + literal to an actual IP address. Unfortunately, such system routines + often allow and process a much larger set of formats than those + described in Section 3.2.2. + + For example, many implementations allow dotted forms of three + numbers, wherein the last part is interpreted as a 16-bit quantity + and placed in the right-most two bytes of the network address (e.g., + a Class B network). Likewise, a dotted form of two numbers means + that the last part is interpreted as a 24-bit quantity and placed in + the right-most three bytes of the network address (Class A), and a + single number (without dots) is interpreted as a 32-bit quantity and + stored directly in the network address. Adding further to the + confusion, some implementations allow each dotted part to be + interpreted as decimal, octal, or hexadecimal, as specified in the C + language (i.e., a leading 0x or 0X implies hexadecimal; a leading 0 + implies octal; otherwise, the number is interpreted as decimal). + + These additional IP address formats are not allowed in the URI syntax + due to differences between platform implementations. However, they + can become a security concern if an application attempts to filter + access to resources based on the IP address in string literal format. + If this filtering is performed, literals should be converted to + numeric form and filtered based on the numeric value, and not on a + prefix or suffix of the string form. + +7.5. Sensitive Information + + URI producers should not provide a URI that contains a username or + password that is intended to be secret. URIs are frequently + displayed by browsers, stored in clear text bookmarks, and logged by + user agent history and intermediary applications (proxies). A + password appearing within the userinfo component is deprecated and + should be considered an error (or simply ignored) except in those + rare cases where the 'password' parameter is intended to be public. + +7.6. Semantic Attacks + + Because the userinfo subcomponent is rarely used and appears before + the host in the authority component, it can be used to construct a + URI intended to mislead a human user by appearing to identify one + (trusted) naming authority while actually identifying a different + authority hidden behind the noise. For example + + + +Berners-Lee, et al. Standards Track [Page 45] + +RFC 3986 URI Generic Syntax January 2005 + + + ftp://cnn.example.com&story=breaking_news@10.0.0.1/top_story.htm + + might lead a human user to assume that the host is 'cnn.example.com', + whereas it is actually '10.0.0.1'. Note that a misleading userinfo + subcomponent could be much longer than the example above. + + A misleading URI, such as that above, is an attack on the user's + preconceived notions about the meaning of a URI rather than an attack + on the software itself. User agents may be able to reduce the impact + of such attacks by distinguishing the various components of the URI + when they are rendered, such as by using a different color or tone to + render userinfo if any is present, though there is no panacea. More + information on URI-based semantic attacks can be found in [Siedzik]. + +8. IANA Considerations + + URI scheme names, as defined by in Section 3.1, form a + registered namespace that is managed by IANA according to the + procedures defined in [BCP35]. No IANA actions are required by this + document. + +9. Acknowledgements + + This specification is derived from RFC 2396 [RFC2396], RFC 1808 + [RFC1808], and RFC 1738 [RFC1738]; the acknowledgements in those + documents still apply. It also incorporates the update (with + corrections) for IPv6 literals in the host syntax, as defined by + Robert M. Hinden, Brian E. Carpenter, and Larry Masinter in + [RFC2732]. In addition, contributions by Gisle Aas, Reese Anschultz, + Daniel Barclay, Tim Bray, Mike Brown, Rob Cameron, Jeremy Carroll, + Dan Connolly, Adam M. Costello, John Cowan, Jason Diamond, Martin + Duerst, Stefan Eissing, Clive D.W. Feather, Al Gilman, Tony Hammond, + Elliotte Harold, Pat Hayes, Henry Holtzman, Ian B. Jacobs, Michael + Kay, John C. Klensin, Graham Klyne, Dan Kohn, Bruce Lilly, Andrew + Main, Dave McAlpin, Ira McDonald, Michael Mealling, Ray Merkert, + Stephen Pollei, Julian Reschke, Tomas Rokicki, Miles Sabin, Kai + Schaetzl, Mark Thomson, Ronald Tschalaer, Norm Walsh, Marc Warne, + Stuart Williams, and Henry Zongaro are gratefully acknowledged. + +10. References + +10.1. Normative References + + [ASCII] American National Standards Institute, "Coded Character + Set -- 7-bit American Standard Code for Information + Interchange", ANSI X3.4, 1986. + + + + + +Berners-Lee, et al. Standards Track [Page 46] + +RFC 3986 URI Generic Syntax January 2005 + + + [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", RFC 2234, November 1997. + + [STD63] Yergeau, F., "UTF-8, a transformation format of + ISO 10646", STD 63, RFC 3629, November 2003. + + [UCS] International Organization for Standardization, + "Information Technology - Universal Multiple-Octet Coded + Character Set (UCS)", ISO/IEC 10646:2003, December 2003. + +10.2. Informative References + + [BCP19] Freed, N. and J. Postel, "IANA Charset Registration + Procedures", BCP 19, RFC 2978, October 2000. + + [BCP35] Petke, R. and I. King, "Registration Procedures for URL + Scheme Names", BCP 35, RFC 2717, November 1999. + + [RFC0952] Harrenstien, K., Stahl, M., and E. Feinler, "DoD Internet + host table specification", RFC 952, October 1985. + + [RFC1034] Mockapetris, P., "Domain names - concepts and facilities", + STD 13, RFC 1034, November 1987. + + [RFC1123] Braden, R., "Requirements for Internet Hosts - Application + and Support", STD 3, RFC 1123, October 1989. + + [RFC1535] Gavron, E., "A Security Problem and Proposed Correction + With Widely Deployed DNS Software", RFC 1535, + October 1993. + + [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. + + [RFC1736] Kunze, J., "Functional Recommendations for Internet + Resource Locators", RFC 1736, February 1995. + + [RFC1737] Sollins, K. and L. Masinter, "Functional Requirements for + Uniform Resource Names", RFC 1737, December 1994. + + [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform + Resource Locators (URL)", RFC 1738, December 1994. + + [RFC1808] Fielding, R., "Relative Uniform Resource Locators", + RFC 1808, June 1995. + + + + +Berners-Lee, et al. Standards Track [Page 47] + +RFC 3986 URI Generic Syntax January 2005 + + + [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail + Extensions (MIME) Part Two: Media Types", RFC 2046, + November 1996. + + [RFC2141] Moats, R., "URN Syntax", RFC 2141, May 1997. + + [RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform + Resource Identifiers (URI): Generic Syntax", RFC 2396, + August 1998. + + [RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter, S., and D. + Jensen, "HTTP Extensions for Distributed Authoring -- + WEBDAV", RFC 2518, February 1999. + + [RFC2557] Palme, J., Hopmann, A., and N. Shelness, "MIME + Encapsulation of Aggregate Documents, such as HTML + (MHTML)", RFC 2557, March 1999. + + [RFC2718] Masinter, L., Alvestrand, H., Zigmond, D., and R. Petke, + "Guidelines for new URL Schemes", RFC 2718, November 1999. + + [RFC2732] Hinden, R., Carpenter, B., and L. Masinter, "Format for + Literal IPv6 Addresses in URL's", RFC 2732, December 1999. + + [RFC3305] Mealling, M. and R. Denenberg, "Report from the Joint + W3C/IETF URI Planning Interest Group: Uniform Resource + Identifiers (URIs), URLs, and Uniform Resource Names + (URNs): Clarifications and Recommendations", RFC 3305, + August 2002. + + [RFC3490] Faltstrom, P., Hoffman, P., and A. Costello, + "Internationalizing Domain Names in Applications (IDNA)", + RFC 3490, March 2003. + + [RFC3513] Hinden, R. and S. Deering, "Internet Protocol Version 6 + (IPv6) Addressing Architecture", RFC 3513, April 2003. + + [Siedzik] Siedzik, R., "Semantic Attacks: What's in a URL?", + April 2001, . + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 48] + +RFC 3986 URI Generic Syntax January 2005 + + +Appendix A. Collected ABNF for URI + + URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] + + hier-part = "//" authority path-abempty + / path-absolute + / path-rootless + / path-empty + + URI-reference = URI / relative-ref + + absolute-URI = scheme ":" hier-part [ "?" query ] + + relative-ref = relative-part [ "?" query ] [ "#" fragment ] + + relative-part = "//" authority path-abempty + / path-absolute + / path-noscheme + / path-empty + + scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + + authority = [ userinfo "@" ] host [ ":" port ] + userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + host = IP-literal / IPv4address / reg-name + port = *DIGIT + + IP-literal = "[" ( IPv6address / IPvFuture ) "]" + + IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + + IPv6address = 6( h16 ":" ) ls32 + / "::" 5( h16 ":" ) ls32 + / [ h16 ] "::" 4( h16 ":" ) ls32 + / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + / [ *4( h16 ":" ) h16 ] "::" ls32 + / [ *5( h16 ":" ) h16 ] "::" h16 + / [ *6( h16 ":" ) h16 ] "::" + + h16 = 1*4HEXDIG + ls32 = ( h16 ":" h16 ) / IPv4address + IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + + + + + + + +Berners-Lee, et al. Standards Track [Page 49] + +RFC 3986 URI Generic Syntax January 2005 + + + dec-octet = DIGIT ; 0-9 + / %x31-39 DIGIT ; 10-99 + / "1" 2DIGIT ; 100-199 + / "2" %x30-34 DIGIT ; 200-249 + / "25" %x30-35 ; 250-255 + + reg-name = *( unreserved / pct-encoded / sub-delims ) + + path = path-abempty ; begins with "/" or is empty + / path-absolute ; begins with "/" but not "//" + / path-noscheme ; begins with a non-colon segment + / path-rootless ; begins with a segment + / path-empty ; zero characters + + path-abempty = *( "/" segment ) + path-absolute = "/" [ segment-nz *( "/" segment ) ] + path-noscheme = segment-nz-nc *( "/" segment ) + path-rootless = segment-nz *( "/" segment ) + path-empty = 0 + + segment = *pchar + segment-nz = 1*pchar + segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + ; non-zero-length segment without any colon ":" + + pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + + query = *( pchar / "/" / "?" ) + + fragment = *( pchar / "/" / "?" ) + + pct-encoded = "%" HEXDIG HEXDIG + + unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + reserved = gen-delims / sub-delims + gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" + sub-delims = "!" / "$" / "&" / "'" / "(" / ")" + / "*" / "+" / "," / ";" / "=" + +Appendix B. Parsing a URI Reference with a Regular Expression + + As the "first-match-wins" algorithm is identical to the "greedy" + disambiguation method used by POSIX regular expressions, it is + natural and commonplace to use a regular expression for parsing the + potential five components of a URI reference. + + The following line is the regular expression for breaking-down a + well-formed URI reference into its components. + + + +Berners-Lee, et al. Standards Track [Page 50] + +RFC 3986 URI Generic Syntax January 2005 + + + ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))? + 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 + as $. 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 = + $7 = + $8 = #Related + $9 = Related + + where 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 five components as + + scheme = $2 + authority = $4 + path = $5 + query = $7 + fragment = $9 + + Going in the opposite direction, we can recreate a URI reference from + its components by using the algorithm of Section 5.3. + +Appendix C. Delimiting a URI in Context + + URIs are often transmitted through formats that do not provide a + clear context for their interpretation. For example, there are many + occasions when a URI is included in plain text; examples include text + sent in email, USENET news, and on printed 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, URIs are delimited in a variety of ways, but usually + within double-quotes "http://example.com/", angle brackets + , or just by using whitespace: + + + +Berners-Lee, et al. Standards Track [Page 51] + +RFC 3986 URI Generic Syntax January 2005 + + + http://example.com/ + + These wrappers do not form part of the URI. + + In some cases, extra whitespace (spaces, line-breaks, tabs, etc.) may + have to be added to break a long URI across lines. The whitespace + should be ignored when the URI is extracted. + + 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 it, the interpreter of a URI + containing a line break immediately after a hyphen should ignore all + 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 a reference that contains embedded whitespace. + + The prefix "URL:" (with or without a trailing space) was formerly + recommended as a way to help distinguish a URI from other bracketed + designators, though it is not commonly used in practice and is no + longer recommended. + + For robustness, software that accepts user-typed URI should attempt + to recognize and strip both delimiters and embedded whitespace. + + For example, the text + + Yes, Jim, I found it under "http://www.w3.org/Addressing/", + but you can probably pick it up from . Note the warning in . + + contains the URI references + + http://www.w3.org/Addressing/ + ftp://foo.example.com/rfc/ + http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 52] + +RFC 3986 URI Generic Syntax January 2005 + + +Appendix D. Changes from RFC 2396 + +D.1. Additions + + An ABNF rule for URI has been introduced to correspond to one common + usage of the term: an absolute URI with optional fragment. + + IPv6 (and later) literals have been added to the list of possible + identifiers for the host portion of an authority component, as + described by [RFC2732], with the addition of "[" and "]" to the + reserved set and a version flag to anticipate future versions of IP + literals. Square brackets are now specified as reserved within the + authority component and are not allowed outside their use as + delimiters for an IP literal within host. In order to make this + change without changing the technical definition of the path, query, + and fragment components, those rules were redefined to directly + specify the characters allowed. + + As [RFC2732] defers to [RFC3513] for definition of an IPv6 literal + address, which, unfortunately, lacks an ABNF description of + IPv6address, we created a new ABNF rule for IPv6address that matches + the text representations defined by Section 2.2 of [RFC3513]. + Likewise, the definition of IPv4address has been improved in order to + limit each decimal octet to the range 0-255. + + Section 6, on URI normalization and comparison, has been completely + rewritten and extended by using input from Tim Bray and discussion + within the W3C Technical Architecture Group. + +D.2. Modifications + + The ad-hoc BNF syntax of RFC 2396 has been replaced with the ABNF of + [RFC2234]. This change required all rule names that formerly + included underscore characters to be renamed with a dash instead. In + addition, a number of syntax rules have been eliminated or simplified + to make the overall grammar more comprehensible. Specifications that + refer to the obsolete grammar rules may be understood by replacing + those rules according to the following table: + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 53] + +RFC 3986 URI Generic Syntax January 2005 + + + +----------------+--------------------------------------------------+ + | obsolete rule | translation | + +----------------+--------------------------------------------------+ + | absoluteURI | absolute-URI | + | relativeURI | relative-part [ "?" query ] | + | hier_part | ( "//" authority path-abempty / | + | | path-absolute ) [ "?" query ] | + | | | + | opaque_part | path-rootless [ "?" query ] | + | net_path | "//" authority path-abempty | + | abs_path | path-absolute | + | rel_path | path-rootless | + | rel_segment | segment-nz-nc | + | reg_name | reg-name | + | server | authority | + | hostport | host [ ":" port ] | + | hostname | reg-name | + | path_segments | path-abempty | + | param | * | + | | | + | uric | unreserved / pct-encoded / ";" / "?" / ":" | + | | / "@" / "&" / "=" / "+" / "$" / "," / "/" | + | | | + | uric_no_slash | unreserved / pct-encoded / ";" / "?" / ":" | + | | / "@" / "&" / "=" / "+" / "$" / "," | + | | | + | mark | "-" / "_" / "." / "!" / "~" / "*" / "'" | + | | / "(" / ")" | + | | | + | escaped | pct-encoded | + | hex | HEXDIG | + | alphanum | ALPHA / DIGIT | + +----------------+--------------------------------------------------+ + + Use of the above obsolete rules for the definition of scheme-specific + syntax is deprecated. + + Section 2, on characters, has been rewritten to explain what + characters are reserved, when they are reserved, and why they are + reserved, even when they are not used as delimiters by the generic + syntax. The mark characters that are typically unsafe to decode, + including the exclamation mark ("!"), asterisk ("*"), single-quote + ("'"), and open and close parentheses ("(" and ")"), have been moved + to the reserved set in order to clarify the distinction between + reserved and unreserved and, hopefully, to answer the most common + question of scheme designers. Likewise, the section on + percent-encoded characters has been rewritten, and URI normalizers + are now given license to decode any percent-encoded octets + + + +Berners-Lee, et al. Standards Track [Page 54] + +RFC 3986 URI Generic Syntax January 2005 + + + corresponding to unreserved characters. In general, the terms + "escaped" and "unescaped" have been replaced with "percent-encoded" + and "decoded", respectively, to reduce confusion with other forms of + escape mechanisms. + + The ABNF for URI and URI-reference has been redesigned to make them + more friendly to LALR parsers and to reduce complexity. As a result, + the layout form of syntax description has been removed, along with + the uric, uric_no_slash, opaque_part, net_path, abs_path, rel_path, + path_segments, rel_segment, and mark rules. All references to + "opaque" URIs have been replaced with a better description of how the + path component may be opaque to hierarchy. The relativeURI rule has + been replaced with relative-ref to avoid unnecessary confusion over + whether they are a subset of URI. The ambiguity regarding the + parsing of URI-reference as a URI or a relative-ref with a colon in + the first segment has been eliminated through the use of five + separate path matching rules. + + The fragment identifier has been moved back into the section on + generic syntax components and within the URI and relative-ref rules, + though it remains excluded from absolute-URI. The number sign ("#") + character has been moved back to the reserved set as a result of + reintegrating the fragment syntax. + + The ABNF has been corrected to allow the path component to be empty. + This also allows an absolute-URI to consist of nothing after the + "scheme:", as is present in practice with the "dav:" namespace + [RFC2518] and with the "about:" scheme used internally by many WWW + browser implementations. The ambiguity regarding the boundary + between authority and path has been eliminated through the use of + five separate path matching rules. + + Registry-based naming authorities that use the generic syntax are now + defined within the host rule. This change allows current + implementations, where whatever name provided is simply fed to the + local name resolution mechanism, to be consistent with the + specification. It also removes the need to re-specify DNS name + formats here. Furthermore, it allows the host component to contain + percent-encoded octets, which is necessary to enable + internationalized domain names to be provided in URIs, processed in + their native character encodings at the application layers above URI + processing, and passed to an IDNA library as a registered name in the + UTF-8 character encoding. The server, hostport, hostname, + domainlabel, toplabel, and alphanum rules have been removed. + + The resolving relative references algorithm of [RFC2396] has been + rewritten with pseudocode for this revision to improve clarity and + fix the following issues: + + + +Berners-Lee, et al. Standards Track [Page 55] + +RFC 3986 URI Generic Syntax January 2005 + + + o [RFC2396] section 5.2, step 6a, failed to account for a base URI + with no path. + + o Restored the behavior of [RFC1808] where, if the reference + contains an empty path and a defined query component, the target + URI inherits the base URI's path component. + + o The determination of whether a URI reference is a same-document + reference has been decoupled from the URI parser, simplifying the + URI processing interface within applications in a way consistent + with the internal architecture of deployed URI processing + implementations. The determination is now based on comparison to + the base URI after transforming a reference to absolute form, + rather than on the format of the reference itself. This change + may result in more references being considered "same-document" + under this specification than there would be under the rules given + in RFC 2396, especially when normalization is used to reduce + aliases. However, it does not change the status of existing + same-document references. + + o Separated the path merge routine into two routines: merge, for + describing combination of the base URI path with a relative-path + reference, and remove_dot_segments, for describing how to remove + the special "." and ".." segments from a composed path. The + remove_dot_segments algorithm is now applied to all URI reference + paths in order to match common implementations and to improve the + normalization of URIs in practice. This change only impacts the + parsing of abnormal references and same-scheme references wherein + the base URI has a non-hierarchical path. + +Index + + A + ABNF 11 + absolute 27 + absolute-path 26 + absolute-URI 27 + access 9 + authority 17, 18 + + B + base URI 28 + + C + character encoding 4 + character 4 + characters 8, 11 + coded character set 4 + + + +Berners-Lee, et al. Standards Track [Page 56] + +RFC 3986 URI Generic Syntax January 2005 + + + D + dec-octet 20 + dereference 9 + dot-segments 23 + + F + fragment 16, 24 + + G + gen-delims 13 + generic syntax 6 + + H + h16 20 + hier-part 16 + hierarchical 10 + host 18 + + I + identifier 5 + IP-literal 19 + IPv4 20 + IPv4address 19, 20 + IPv6 19 + IPv6address 19, 20 + IPvFuture 19 + + L + locator 7 + ls32 20 + + M + merge 32 + + N + name 7 + network-path 26 + + P + path 16, 22, 26 + path-abempty 22 + path-absolute 22 + path-empty 22 + path-noscheme 22 + path-rootless 22 + path-abempty 16, 22, 26 + path-absolute 16, 22, 26 + path-empty 16, 22, 26 + + + +Berners-Lee, et al. Standards Track [Page 57] + +RFC 3986 URI Generic Syntax January 2005 + + + path-rootless 16, 22 + pchar 23 + pct-encoded 12 + percent-encoding 12 + port 22 + + Q + query 16, 23 + + R + reg-name 21 + registered name 20 + relative 10, 28 + relative-path 26 + relative-ref 26 + remove_dot_segments 33 + representation 9 + reserved 12 + resolution 9, 28 + resource 5 + retrieval 9 + + S + same-document 27 + sameness 9 + scheme 16, 17 + segment 22, 23 + segment-nz 23 + segment-nz-nc 23 + sub-delims 13 + suffix 27 + + T + transcription 8 + + U + uniform 4 + unreserved 13 + URI grammar + absolute-URI 27 + ALPHA 11 + authority 18 + CR 11 + dec-octet 20 + DIGIT 11 + DQUOTE 11 + fragment 24 + gen-delims 13 + + + +Berners-Lee, et al. Standards Track [Page 58] + +RFC 3986 URI Generic Syntax January 2005 + + + h16 20 + HEXDIG 11 + hier-part 16 + host 19 + IP-literal 19 + IPv4address 20 + IPv6address 20 + IPvFuture 19 + LF 11 + ls32 20 + OCTET 11 + path 22 + path-abempty 22 + path-absolute 22 + path-empty 22 + path-noscheme 22 + path-rootless 22 + pchar 23 + pct-encoded 12 + port 22 + query 24 + reg-name 21 + relative-ref 26 + reserved 13 + scheme 17 + segment 23 + segment-nz 23 + segment-nz-nc 23 + SP 11 + sub-delims 13 + unreserved 13 + URI 16 + URI-reference 25 + userinfo 18 + URI 16 + URI-reference 25 + URL 7 + URN 7 + userinfo 18 + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 59] + +RFC 3986 URI Generic Syntax January 2005 + + +Authors' Addresses + + Tim Berners-Lee + World Wide Web Consortium + Massachusetts Institute of Technology + 77 Massachusetts Avenue + Cambridge, MA 02139 + USA + + Phone: +1-617-253-5702 + Fax: +1-617-258-5999 + EMail: timbl@w3.org + URI: http://www.w3.org/People/Berners-Lee/ + + + Roy T. Fielding + Day Software + 5251 California Ave., Suite 110 + Irvine, CA 92617 + USA + + Phone: +1-949-679-2960 + Fax: +1-949-679-2972 + EMail: fielding@gbiv.com + URI: http://roy.gbiv.com/ + + + Larry Masinter + Adobe Systems Incorporated + 345 Park Ave + San Jose, CA 95110 + USA + + Phone: +1-408-536-3024 + EMail: LMM@acm.org + URI: http://larry.masinter.net/ + + + + + + + + + + + + + + + +Berners-Lee, et al. Standards Track [Page 60] + +RFC 3986 URI Generic Syntax January 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM 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. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights 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; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the IETF's procedures with respect to rights in IETF Documents can + be found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat 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 on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + +Berners-Lee, et al. Standards Track [Page 61] + diff --git a/standards/rfc3995.txt b/standards/rfc3995.txt new file mode 100644 index 000000000..9a8013b89 --- /dev/null +++ b/standards/rfc3995.txt @@ -0,0 +1,5323 @@ + + + + + + +Network Working Group R. Herriot +Request for Comments: 3995 Global Workflow Solutions +Category: Standards Track T. Hastings +Updates: 2911, 2910 Xerox Corporation + March 2005 + + + Internet Printing Protocol (IPP): + Event Notifications and Subscriptions + +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 (2005). + +Abstract + + This document describes an OPTIONAL extension to the Internet + Printing Protocol/1.1: Model and Semantics (RFC 2911, RFC 2910). + 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 Events + occurs, the Printer delivers an asynchronous Event Notification to + the specified Notification Recipient via the specified Push or Pull + 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 & Hastings Standards Track [Page 1] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.1. Notification Overview. . . . . . . . . . . . . . . . . . 5 + 2. Models for Notification. . . . . . . . . . . . . . . . . . . . 8 + 2.1. Model for Simple Notification (Normative). . . . . . . . 8 + 2.2. Additional Models for Notification (Informative) . . . . 9 + 3. Terminology. . . . . . . . . . . . . . . . . . . . . . . . . . 9 + 3.1. Conformance Terminology. . . . . . . . . . . . . . . . . 9 + 3.2. Other Terminology. . . . . . . . . . . . . . . . . . . . 10 + 4. Object Relationships . . . . . . . . . . . . . . . . . . . . . 12 + 4.1. Printer and Per-Printer Subscription Objects . . . . . . 13 + 4.2. Printer, Job and Per-Job Subscription Objects. . . . . . 13 + 5. Subscription Object. . . . . . . . . . . . . . . . . . . . . . 13 + 5.1. Rules for Support of Subscription Template Attributes. . 14 + 5.2. Rules for Processing Subscription Template Attributes. . 15 + 5.3. Subscription Template Attributes . . . . . . . . . . . . 18 + 5.3.1. notify-recipient-uri (uri) . . . . . . . . . . . 20 + 5.3.2. notify-pull-method (type2 keyword) . . . . . . . 21 + 5.3.3. notify-events (1setOf type2 keyword) . . . . . . 22 + 5.3.4. notify-attributes (1setOf type2 keyword) . . . . 29 + 5.3.5. notify-user-data (octetString(63)) . . . . . . . 30 + 5.3.6. notify-charset (charset) . . . . . . . . . . . . 31 + 5.3.7. notify-natural-language (naturalLanguage). . . . 31 + 5.3.8. notify-lease-duration (integer(0:67108863)). . . 32 + 5.3.9. notify-time-interval (integer(0:MAX)). . . . . . 33 + 5.4. Subscription Description Attributes. . . . . . . . . . . 34 + 5.4.1. notify-subscription-id (integer (1:MAX)). . . . 35 + 5.4.2. notify-sequence-number (integer (0:MAX)) . . . . 35 + 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)) . . . . . . . . . 37 + 5.4.7. notify-subscriber-user-name (name(MAX)). . . . . 38 + 6. Printer Description Attributes Related to Notification . . . . 38 + 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 . . . . 39 + 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. . . . 44 + 9.1.1. Event Notification Content Common to All Events. 44 + 9.1.2. Additional Event Notification Content for Job + Events . . . . . . . . . . . . . . . . . . . . . 45 + + + + +Herriot & Hastings Standards Track [Page 2] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 . . . . . . . . . . . . . . . . . 49 + 10. Delivery Methods . . . . . . . . . . . . . . . . . . . . . . . 50 + 11. Operations for Notification. . . . . . . . . . . . . . . . . . 52 + 11.1. Subscription Creation Operations . . . . . . . . . . . . 52 + 11.1.1. Create-Job-Subscriptions Operation . . . . . . . 52 + 11.1.2. Create-Printer-Subscriptions operation . . . . . 55 + 11.1.3. Job Creation Operations - Extensions for + Notification . . . . . . . . . . . . . . . . . . 56 + 11.2 Other Operations. . . . . . . . . . . . . . . . . . . . . 58 + 11.2.1. Restart-Job Operation - Extensions for + Notification . . . . . . . . . . . . . . . . . . 58 + 11.2.2. Validate-Job Operation - Extensions for + Notification . . . . . . . . . . . . . . . . . . 59 + 11.2.3. Get-Printer-Attributes - Extensions for + Notification . . . . . . . . . . . . . . . . . . 59 + 11.2.4. Get-Subscription-Attributes operation. . . . . . 60 + 11.2.5. Get-Subscriptions operation. . . . . . . . . . . 63 + 11.2.6. Renew-Subscription operation . . . . . . . . . . 66 + 11.2.7. Cancel-Subscription operation. . . . . . . . . . 68 + 12. Status Codes . . . . . . . . . . . . . . . . . . . . . . . . . 70 + 12.1. successful-ok-ignored-subscriptions (0x0003) . . . . . . 70 + 12.2. client-error-ignored-all-subscriptions (0x0414). . . . . 71 + 13. Status Codes in Subscription Attributes Groups . . . . . . . . 71 + 13.1. client-error-uri-scheme-not-supported (0x040C) . . . . . 71 + 13.2. client-error-attributes-or-values-not-supported (0x040B) 71 + 13.3. client-error-too-many-subscriptions (0x0415) . . . . . . 72 + 13.4. successful-ok-too-many-events (0x0005) . . . . . . . . . 72 + 13.5. successful-ok-ignored-or-substituted-attributes (0x0001) 72 + 14. Encodings of Additional Attribute Tags . . . . . . . . . . . . 72 + 15. Conformance Requirements . . . . . . . . . . . . . . . . . . . 72 + 15.1. Conformance requirements for clients . . . . . . . . . . 73 + 15.2. Conformance requirements for Printers. . . . . . . . . . 73 + 16. Model for Notification with Cascading Printers (Informative) . 74 + 17. Distributed Model for Notification (Informative) . . . . . . . 75 + 18. Extended Notification Recipient (Informative). . . . . . . . . 76 + 19. Object Model for Notification (Normative). . . . . . . . . . . 77 + 19.1. Object relationships . . . . . . . . . . . . . . . . . . 78 + 19.2. Printer Object and Per-Printer Subscription Objects. . . 79 + 19.3. Job Object and Per-Job Subscription Objects. . . . . . . 79 + 20. Per-Job versus Per-Printer Subscription Objects (Normative). . 79 + 21. Normative References . . . . . . . . . . . . . . . . . . . . . 80 + + + +Herriot & Hastings Standards Track [Page 3] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 22. Informative References . . . . . . . . . . . . . . . . . . . . 80 + 23. IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 81 + 23.1. Attribute Registrations. . . . . . . . . . . . . . . . . 82 + 23.2. Additional Enum Attribute Value Registrations within + the IPP registry . . . . . . . . . . . . . . . . . . . . 83 + 23.3. Operation Registrations. . . . . . . . . . . . . . . . . 83 + 23.4. Status code Registrations. . . . . . . . . . . . . . . . 83 + 23.5. Attribute Group tag Registrations. . . . . . . . . . . . 84 + 23.6. Registration of Events . . . . . . . . . . . . . . . . . 84 + 23.7. Registration of Event Notification Delivery Methods. . . 85 + 23.7.1. Requirements for Registration of Event + Notification Delivery Methods. . . . . . . . . . 85 + 23.7.2. Registration Procedure . . . . . . . . . . . . . 86 + 23.7.3. Delivery Method Document Registrations . . . . . 87 + 23.7.4. Registration Template. . . . . . . . . . . . . . 88 + 24. Internationalization Considerations. . . . . . . . . . . . . . 89 + 25. Security Considerations. . . . . . . . . . . . . . . . . . . . 89 + 25.1. Client access rights . . . . . . . . . . . . . . . . . . 89 + 25.2. Printer security threats . . . . . . . . . . . . . . . . 91 + 25.3. Notification Recipient security threats. . . . . . . . . 91 + 26. Description of the base IPP documents (Informative). . . . . . 92 + 27. Contributors . . . . . . . . . . . . . . . . . . . . . . . . . 93 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 94 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 95 + +Tables + + Table 1 - Subscription Template Attributes. . . . . . . . . . . . 20 + 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. . . . . . . . 45 + Table 6 - Additional Event Notification Content for Job Events. . 46 + Table 7 - Combinations of Events and Subscribed Events for + "job-impressions-completed" . . . . . . . . . . . . . . 46 + Table 8 - Additional Event Notification Content for Printer + Events. . . . . . . . . . . . . . . . . . . . . . . . . 46 + 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. . . . . . . . 48 + Table 12 - Job Name in Event Notification Content. . . . . . . . . 49 + Table 13 - Job State in Event Notification Content . . . . . . . . 49 + Table 14 - Printer State in Event Notification Content . . . . . . 50 + Table 15 - Information about the Delivery Method . . . . . . . . . 51 + Table 16 - Printer Conformance Requirements for Operations . . . . 74 + + + + + +Herriot & Hastings Standards Track [Page 4] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +Figures + + Figure 1 - Model for Notification. . . . . . . . . . . . . . . . . 9 + Figure 2 - Model for Notification with Cascading Printers. . . . . 75 + Figure 3 - Opaque Use of a Notification Server Transparent to the + Client. . . . . . . . . . . . . . . . . . . . . . . . . 76 + Figure 4 - Use of an Extended Notification Recipient transparent + to the Printer. . . . . . . . . . . . . . . . . . . . . 77 + Figure 5 - Object Model for Notification . . . . . . . . . . . . . 78 + +1. Introduction + + This IPP notification specification is an OPTIONAL extension to + Internet Printing Protocol/1.1: Model and Semantics [RFC2911, + RFC2910]. See Appendix 29 for a description of the base IPP + documents. This document in combination with the following documents + is intended to meet the most important notification requirements + described in [RFC3997]: + + Internet Printing Protocol (IPP): "Job Progress Attributes" + [RFC3381] + + Internet Printing Protocol (IPP): "The 'ippget' Delivery Method + for Event Notifications" [RFC3996] + + This specification REQUIRES that clients and Printers support the + 'ippget' Pull Delivery Method [RFC3996]. Conforming client and + Printer implementations MAY support additional Push or Pull Delivery + Methods as well. Note: this document does not define any Delivery + Methods itself, but it does define the rules for conformance for + Delivery Method Documents and their registration with IANA (see + section 23.7.3). + + 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 delivers 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 + + + +Herriot & Hastings Standards Track [Page 5] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 for a Push + Delivery Method or the method for a Pull Delivery Method. + + 3. The Delivery Method (i.e., the protocol) which the Printer uses to + deliver the Event Notification. + + 4. Some opaque data that the Printer delivers to the Notification + Recipient in the Event Notification. For example, 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 + + 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 + + + + +Herriot & Hastings Standards Track [Page 6] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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): + + - Restart-Job operation: When a client performs the Restart-Job + operation [RFC2911], the Printer re-uses the same Job and its + Subscription Objects. + + - 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. + + + + + +Herriot & Hastings Standards Track [Page 7] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + - 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 (1) cancels the + lease on the specified Per-Printer Subscription Object and thereby + deletes the Per-Printer Subscription Object or (2) deletes the + Per-Job 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) If the Delivery Method is a Push Delivery Method as indicated + by the presence of the Subscription Object's "notify- + recipient-uri" attribute, delivers the Event Notification + using the Delivery Method and target address identified in the + Subscription Object's "notify-recipient-uri" attribute, OR + + ii) If the Delivery Method is a Pull Delivery Method as indicated + by the presence of the Subscription Object's "notify-pull- + method" attribute, saves Event Notification for a time period + called the Event Life defined by the Delivery Method, i.e., + the Notification Recipient is expected to fetch the Event + Notifications. + +2. Models for Notification + +2.1. Model for Simple Notification (Normative) + + 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 + + + +Herriot & Hastings Standards Track [Page 8] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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. Additional Models for Notification (Informative) + + Additional models have been proposed (see Appendices 16, 17, and 18). + +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 as defined in RFC 2119 [RFC2119] and [RFC2911] section + 12.1. If an implementation supports the extension defined in this + document, then these terms apply; otherwise, they do not. These + terms define conformance to this document only; they do not affect + conformance to other documents, unless explicitly stated otherwise. + + 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. + + + + + +Herriot & Hastings Standards Track [Page 9] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +3.2. Other Terminology + + This document uses the same terminology as [RFC2911], such as + "client", "Printer", "attribute", "attribute value", "keyword", + "operation", "request", "response", "administrator", "operator", and + "support". In addition, the following terms are defined for use in + this document and the Delivery Method Documents: + + Compound Event Notification - two or more Event Notifications that a + Printer delivers together as a single request or response. The + Delivery Method Document specifies whether the Delivery Method + supports Compound Event Notifications. + + Delivery Method - the mechanism by which the Printer delivers an + Event Notification. + + Delivery Method Document - a document, separate from this document, + that defines a Delivery Method. + + 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. + + Event Life - For a Pull Delivery Method, the length of time in + seconds after an Event occurs during which the Printer will retain + that Event for delivery in an Event Notification. After the Event + Life expires, the Printer will no longer deliver an Event + Notification for that Event in such a response. + + Event Notification - the information about an Event that the Printer + delivers when an Event occurs. + + Event Notification Attributes Group - The attributes group which is + used to deliver an Event Notification in a request (Push Delivery + Methods) or a response (Pull Delivery Methods). + + 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. + + Job Creation operation - One of the operations that creates a Job + object: Print-Job, Print-URI and Create-Job. The Restart-Job + operation [RFC2911] is not considered a Job Creation operation, since + the Printer re-uses the existing Job object. The Validate-Job + operation is not considered a Job Creation operation because no Job + + + +Herriot & Hastings Standards Track [Page 10] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + object is created. Therefore, when a statement also applies to + either the Restart-Job and/or the Validate-Job operation, they are + mentioned explicitly. + + Job Event - an Event caused by some change in a particular job on the + Printer, e.g., 'job-completed'. + + Machine Consumable Event Notification - bytes for program + consumption. The bytes are formatted according to the Delivery + Method document. + + Notification - when not in the phrases 'Event Notification' and + 'Notification Recipient' - the concepts of this specification, i.e., + Events, Subscription Objects, and Event Notifications. + + Notification Recipient - the entity to which the Printer delivers an + Event Notification. For Push Delivery Methods, the IPP Printer sends + the Notifications to a Notification Recipient. For Pull Delivery + Methods, the Notification Recipient is acting in the role of an IPP + client and requests Event Notifications and so the terms "client" and + + "Notification Recipient" are used interchangeably with such Delivery + Methods. For example, see [RFC3996]. + + 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. + + Printer Event - an Event caused by some change in the Printer that is + not specific to a job, e.g., 'printer-state-changed'. + + Pull Delivery Method - The Printer saves Event Notifications for some + event life time and expects the Notification Recipient to request + Event Notifications. The Printer delivers the Event Notifications in + a response to such a request. + + Push Delivery Method -The Printer delivers the Event Notification + shortly after an Event occurs. + + 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. + + + +Herriot & Hastings Standards Track [Page 11] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Subscribed Printer Event - a Subscribed Event that is a Printer + Event. + + Subscribing Client - The client that creates the Subscription Object. + + Subscription Attributes Group - The attributes group in a response + that contains Subscription Object attributes. + + Subscription Creation Operation - An operation that creates a + Subscription Object: Job Creation operations, Create-Job- + Subscriptions operation, 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 one + or more Subscription objects. The Restart-Job operation [RFC2911] is + not considered a Subscription Creation Operation, since the Printer + re-uses the Job's existing Subscription Objects, rather than creating + any new Subscription Objects. + + Subscription Creation Request - The request portion of a Subscription + Creation Operation. + + Subscription Description Attributes - Subscription Object attributes + that a Printer supplies during a Subscription Creation Operation. + + Subscription Object - An object containing a set of attributes that + indicate: the Notification Recipient (for Push Delivery Method + only), the Delivery Method, the Subscribed Events that cause the + Printer to deliver an Event Notification, and the information to + include in an Event Notification. + + 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 Template Attributes Group - The attributes group in a + request that contains Subscription Object attributes that are + Subscription Template Attributes. + +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 19. + + + + + + +Herriot & Hastings Standards Track [Page 12] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +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. + +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 deliver Event Notifications for Push Delivery + Methods only, how to deliver them, and what to include 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. + + + + +Herriot & Hastings Standards Track [Page 13] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +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. + + 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. + + + + +Herriot & Hastings Standards Track [Page 14] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 - see section 11.2.3). + +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 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 + 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 + + + +Herriot & Hastings Standards Track [Page 15] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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: + + a) the status code 'client-error-bad-request' AND + + b) 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: + + 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 + + + + +Herriot & Hastings Standards Track [Page 16] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 5.4.1), if + and only if the Printer creates a Subscription Object. + + b) the "notify-lease-duration" attribute (see section 5.3.8), 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.8). If a client supplies this attribute in the + creation of a Per-Job Subscription Object, it MUST appear in + 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 13 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 13.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. + + + + + + +Herriot & Hastings Standards Track [Page 17] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 'client-error-attributes-or-values-not-supported': the + Subscription Object was not created because the method of + the "notify-pull-method" attribute is not supported. See + section 13.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 MAY try again + later. See section 13.3 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 13.4 for + more details about this status code. See step #2 in this + section and section 5.3.3 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 13.5 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 + 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. + + + + + + +Herriot & Hastings Standards Track [Page 18] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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. + + The "notify-recipient-uri" attribute is for use with Push Delivery + Methods. The "notify-pull-method" attribute is for use with Pull + Delivery Methods. + + For Push Delivery Methods, a Printer MUST support all attributes in + Table 1 below except for "notify-pull-method" and "notify-attributes" + (and "notify-pull-method-supported" and "notify-attributes- + supported"). For Pull Delivery Methods, a Printer MUST support all + attributes in Table 1 below except for "notify-recipient-uri" and + "notify-attributes" (and "notify-schemes-supported" and "notify- + attributes-supported"). If a Printer supports both Push and Pull + Delivery Methods, then it MUST support both "notify-recipient-uri" + and "notify-pull-method" attributes. + + For Pull Delivery Methods, 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. For Push Delivery + Methods, a client MUST supply "notify-pull-method" and MAY omit any + of the rest of the attributes in column 1 of Table 1 in a + Subscription Creation Request. A client MUST NOT supply both + "notify-recipient-uri" and "notify-pull-method" attributes in the + same Subscription Creation Request. + + Note: The Default and Supported Printer attributes listed in column + 2 of Table 1 do not have separate sections in this specification + defining their semantics. Instead, the section for the corresponding + Subscription Object attribute (column 1 of Table 1) contains the + semantics of these Printer attributes. This approach follows the + precedence of the Job Template attributes in section 4.2 of [RFC2911] + where the corresponding "xxx-default" and "xxx-supported" Printer + attributes are defined in the same section as the "xxx" Job + attribute. + + + + + + + + +Herriot & Hastings Standards Track [Page 19] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Table 1 - Subscription Template Attributes + + Attribute in Subscription Default and Supported Printer + Object Attributes + + notify-recipient-uri (uri) * notify-schemes-supported (1setOf + uriScheme) + notify-pull-method (type2 notify-pull-method-supported (1setOf + keyword) ** type2 keyword) + 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-language 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)) + + * "notify-recipient-uri" is for Push Delivery Methods only. + ** "notify-pull-method" is for Pull Delivery Methods only. + +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 Push Delivery + Method for each Event Notification associated with this Subscription + Object. + + If a Printer supports any Push Delivery Methods, a Printer MUST + support this attribute and return the value as supplied by the client + (no case conversion or other canonicalization) in any operation + response that includes this attribute. + + + + + +Herriot & Hastings Standards Track [Page 20] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + For a Push Delivery Method, a client MUST supply this attribute in a + Subscription Creation Operation. Thus there is no need for a default + Printer attribute. + + The URI scheme of the value of this attribute on a Subscription + object MUST be a value of the "notify-schemes-supported (1setOf + uriScheme)" Printer attribute (see section 5.3.1.1). Note: According + to [RFC2396] the ":" terminates the scheme and so is not part of the + scheme. Therefore, values of the "notify-schemes-supported" Printer + attribute do not include the ":" character. + + 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. + +5.3.1.1. notify-schemes-supported (1setOf uriScheme) + + This attribute contains the URI schemes supported in the "notify- + recipient-uri" Subscription Template attribute. See sections 5.1 and + 5.2 for the behavior of "xxx-supported" Subscription Template Printer + attributes. + +5.3.2. notify-pull-method (type2 keyword) + + This attribute's value is a type2 keyword indicating which Pull + Delivery Method is to be used. + + Since a Printer MUST support the 'ippget' Pull Delivery Method + [RFC3996] (see section 15), a Printer MUST support this attribute and + return the value as supplied by the client in any operation response + that includes this attribute. + + For a Pull Delivery Method, a client MUST supply this attribute in a + Subscription Creation Operation. Thus there is no need for a default + Printer attribute. + + The keyword value of this attribute on a Subscription object MUST be + a value of the "notify-pull-method-supported (1setOf type2 keyword)" + Printer attribute. + + If the client supplies an unsupported method 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-attributes-or-values-not-supported' value in the Subscription + Attributes Group in the response. + + + + +Herriot & Hastings Standards Track [Page 21] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +5.3.2.1. notify-pull-method-supported (1setOf type2 keyword) + + See sections 5.1 and 5.2 for the behavior of "xxx-supported" + Subscription Template Printer attributes. + +5.3.3. 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 + delivers an Event Notification using information in the Subscription + Object. The details of "matching" are described subsection 5.3.3.5. + + 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 keyword value of this attribute on a Subscription Object MUST be + a value of the "notify-events-supported (1setOf type2 keyword)" + Printer 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.3.1. notify-events-default (1setOf type2 keyword) + + See sections 5.1 and 5.2 for the behavior of "xxx-default" + Subscription Template Printer attributes. + +5.3.3.2. notify-events-supported (1setOf type2 keyword) + + See sections 5.1 and 5.2 for the behavior of "xxx-supported" + Subscription Template Printer attributes. + + + + + + + + + +Herriot & Hastings Standards Track [Page 22] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +5.3.3.3. notify-max-events-supported (integer(2:MAX)) + + This attribute specified the maximum number of events that the + Printer supports for the "notify-events" Subscription Template + attribute. See sections 5.1 and 5.2 for the behavior of "xxx- + supported" Subscription Template Printer attributes. + +5.3.3.4. 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- + change'. See section 5.3.3.5 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.3.4.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 delivery 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.3.4.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. + + + + + +Herriot & Hastings Standards Track [Page 23] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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'. + + '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". 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 + + + +Herriot & Hastings Standards Track [Page 24] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + "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.3.4.3. Subscribed Job Events + + The standard keyword values for Subscribed Job Events are: + + 'job-state-changed': REQUIRED - the job has changed from any state + to any other state. Specifically, the Printer delivers this Event + whenever the value of the "job-state" attribute or "job-state- + reasons" attribute changes. When a Job is removed from the Job + Retention or Job History phases (see [RFC2911] section 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, a Restart-Job operation [RFC2911], or any + job operation that creates a Job object from an existing Job + object. The Printer populates the job's "time-at-creation" + attribute value (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). When a Job completes, a Notification + Recipient MAY query the Job using the Get-Job-Attributes + operation. To allow such a query, the Printer retains the Job + in the Job Retention and/or the Job History phases (see + [RFC2911] section 4.3.7.1) for a suitable amount of time that + depends on implementation and the Delivery Methods supported. + The Printer also delivers this Event when a Job is removed with + the Purge-Job operation (see [RFC2911] section 3.2.9). In this + + + +Herriot & Hastings Standards Track [Page 25] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + case, the Event Notification MUST report the 'job-state' as + 'canceled' and the Job object is no longer present for query. + + '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. 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 [RFC3381] specification for additional + attributes that a Printer MAY deliver in an Event Notification + caused by this Event. The "notify-time-interval" attribute + affects this Event by causing the Printer NOT to deliver an Event + Notification every time a 'job-progress' Events occurs. See + section 5.3.9 for full details. + +5.3.3.5. 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.3.5.1. Rules for Matching of Printer Events + + Given 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 delivers an Event Notification to + the Notification Recipients of Subscription Objects A, B, and C + + + +Herriot & Hastings Standards Track [Page 26] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + because this is a Printer Event. Note if Job 1 has already + completed, the Printer would not deliver an Event Notification for + its Subscription Object, even if Job 1 is retained in the Job + Retention and/or the Job History phases (see [RFC2911] section + 4.3.7.1). + +5.3.3.5.2. Rules for Matching of Job Events + + Given 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- + 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 delivers 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 delivers 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 deliver 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.3.5.3. Special Cases for Matching Rules + + This section contains two rules for the special case where a single + Event produces multiple Event Notifications destined for the same + Notification Recipient. These two rules clarify whether a Printer + + + +Herriot & Hastings Standards Track [Page 27] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + should send multiple Event Notifications or consolidate them into a + single Event Notification. + + If an Event matches Subscribed Events in two different Subscription + Objects and the Printer would deliver two identical Event + Notifications (except for the "notify-subscription-id" attribute) to + the same Notification Recipient using the same Delivery Method, the + Printer MUST deliver 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. + + Consider the example: At the time a Job completes, there are two + Per-Printer Subscription Objects A and B with the same Notification + Recipient R. Subscription Object A has the Subscribed Job Event + 'job-state-changed'. Subscription Object B has the Subscribed Job + Event 'job-completed'. Both Subscription Objects match the Event + 'job-completed'. The Printer delivers two Event Notifications to the + Notification Recipient R. One with the value of 'job-state-changed' + for the "notify-subscribed-event" attribute and the other with the + value of 'job-completed' for the "notify-subscribed-event" + attribute. + + If an Event matches two Subscribed Events in a single Subscription + object (e.g., a value and its sub-value), a Printer MAY deliver one + Event Notification for each matched value in the Subscription Object + or it MAY deliver only a single Event Notification. The rules in + sections 5.3.3.5.1 and 5.3.3.5.2 are purposefully flexible about the + number of Event Notifications sent when Event E matches two or more + values in a Subscription Object. + + Consider the example: At the time a Job completes, a Subscription + Object A has two Subscribed Job Events 'job-state-changed' and 'job- + completed'. Both Subscribed Job Events match the Event 'job- + completed'. The Printer delivers either one or two Event + Notifications to the Notification Recipient of Subscription Object A, + depending on implementation. If it delivers two Event Notifications, + one has the value of 'job-state-changed' for the "notify- + subscribed-event" attribute, and the other has the value of 'job- + completed' for the "notify-subscribed-event" attribute. If it + delivers one Event Notification, it has the value of either 'job- + state-changed' or 'job-completed' for the "notify-subscribed-event" + attribute, depending on implementation. The algorithm for choosing + such a value is implementation dependent. + + + + + + +Herriot & Hastings Standards Track [Page 28] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +5.3.4. notify-attributes (1setOf type2 keyword) + + This attribute contains a set of attribute names. When a Printer + delivers 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 either (1) MAY contain the + "notify-attributes" attribute with a 'none' value or (2) NEED NOT + contain the attribute at all. There is no "notify-attributes- + default" Printer attribute. + + Each keyword value of this attribute on a Subscription Object MUST be + a value of the "notify-attributes-supported (1setOf type2 keyword)" + Printer attribute (see section 5.3.4.1). 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 & Hastings Standards Track [Page 29] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + - 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.1. notify-attributes-supported (1setOf type2 keyword) + + See sections 5.1 and 5.2 for the behavior of "xxx-supported" + Subscription Template Printer attributes. + +5.3.5. 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 the + Subscription Creation Operation, the Subscription Object either (1) + MAY contain the "notify-user-data" attribute with a zero length value + or (2) NEED NOT contain the attribute at all. There is no "notify- + user-data-default" Printer attribute. + + + + + + + +Herriot & Hastings Standards Track [Page 30] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + There is no "notify-user-data-supported" Printer 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.6. 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. + + 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" Printer attribute. + + The value of this attribute on a Subscription Object MUST be a value + of the "charset-supported (1setOf charset)" Printer attribute. + +5.3.7. 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] + section 3.1.4). 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 (see [RFC2911] section 4.4.19). There + is no "notify-natural-language-default" Printer attribute. + + + + +Herriot & Hastings Standards Track [Page 31] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + The value of this attribute on a Subscription Object MUST be a value + of the "generated-natural-language-supported (1setOf type2 + naturalLanguage)" Printer attribute (see [RFC2911] section 4.4.20). + +5.3.8. 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. See section 5.4.3 on "notify-lease-expiration-time + (integer(0:MAX))" for more details. + + 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 discussion of the 'job-completed' event + in section 5.3.3.4.3 about retention of the Job object after + completion. + + 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 updates 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))) Printer attribute. + + + + + +Herriot & Hastings Standards Track [Page 32] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 the + Printer adds it to the Printer's "printer-up-time" attribute value + (see [RFC2911] section 4.4.29) to produce the "notify-lease- + expiration-time" Subscription Description attribute value (see + section 5.4.3). + +5.3.8.1. notify-lease-duration-default (integer(0:67108863)) + + See sections 5.1 and 5.2 for the behavior of "xxx-default" + Subscription Template Printer attributes. + +5.3.8.2. notify-lease-duration-supported (1setOf (integer(0: 67108863) | + rangeOfInteger(0:67108863))) + + See sections 5.1 and 5.2 for the behavior of "xxx-supported" + Subscription Template Printer attributes. + +5.3.9. 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 + 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 in the + Subscription Creation Operation, the Subscription Object either (1) + MAY contain the "notify-time-interval" attribute with a '0' value or + (2) NEED NOT contain this attribute at all. There is no "notify- + time-interval-default" Printer attribute. + + There is no "notify-time-interval-supported" Printer attribute. + + + + + + +Herriot & Hastings Standards Track [Page 33] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 deliver 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 deliver 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 delivers an Event Notification for a Per-Job + Subscription Object. + + b) Otherwise, the Printer MUST NOT generate or deliver 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 + delivers Event Notifications requests. + + This attribute MUST NOT effect any Events other than 'job-progress'. + +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. + There are no corresponding default or supported attributes. + + + + + + + + +Herriot & Hastings Standards Track [Page 34] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 MAY assign the value of this attribute sequentially as it + creates Subscription Objects. However, if there is no security on + Subscription objects, sequential assignment exposes the system to a + passive traffic monitoring threat. + + 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 MIB table index values, which are recommended not + to 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 deliver an Event Notification + for this Subscription object. 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 populate this + attribute with a value of 0. This value indicates that the Printer + has not sent any Event Notifications for this Subscription Object. + + + +Herriot & Hastings Standards Track [Page 35] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Each time the Printer delivers 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 + delivering 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. See also the discussion of the + 'job-completed' event in section 5.3.3.4.3 about retention of the Job + object after completion so that a Notification Recipient can query + the Job object after receiving the 'job-completed' Event + Notification. + + 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 populate this attribute in each + persistent Subscription Object with a value 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.6). + + + +Herriot & Hastings Standards Track [Page 36] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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). In other words, when + this attribute is queried with the Get-Subscriptions or Get- + Subscription-Attributes operations (see sections 11.2.4 and 11.2.5), + the value returned is the current value of the Printer's "printer- + up-time" attribute, rather than the time at which the Subscription + Object was created. + + 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. + + 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. + + + +Herriot & Hastings Standards Track [Page 37] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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. See discussion of the 'job-completed' event in section + 5.3.3.4.3 about retention of the Job object after completion so that + a Notification Recipient can query the Job object after receiving the + 'job-completed' Event Notification. + +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 MUST populates this attribute with 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 + attributes, indicates the Printer support required for conformance, + and whether or not the attribute is READ-ONLY (see section 3.1): + + + + + + + + +Herriot & Hastings Standards Track [Page 38] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 OPTIONAL 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 populate this attribute with 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 update this attribute with the value of the Printer's + "printer-up-time" attribute. + +6.2. printer-state-change-date-time (dateTime) + + This OPTIONAL 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 populate this attribute with 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 + Printer MUST update this attribute with 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. + + + + + +Herriot & Hastings Standards Track [Page 39] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +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 deliver 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 deliver this Event Notification. + This 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 deliver an Event + Notification for either the 'job-completed' or 'job-state-changed' + Subscribed Events and to deliver the 'job-completed' or 'job-state- + changed' value for this attribute, respectively. See section 5.3.3.5 + 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. + + + + + + + + +Herriot & Hastings Standards Track [Page 40] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +8.2. notify-text (text(MAX)) + + This attribute contains a Human Consumable text message (see section + 9.2). 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. + + Note: this attribute contains a text message only and must not + contain any encoding information, such as 'text/plain'. The + 'text/plain' encoding is implicit and thus the charset must be + specified by an alternate mechanism, namely the "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 + delivers 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.3.5 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'. + + Event Notification Ordering: + + When a Printer delivers Event Notifications, the Event Notifications + from any given Subscription Object MUST be in time stamp order, i.e., + in order of increasing "printer-up-time" attribute value in the Event + Notification (see Table 5). These Event Notifications MAY be + interleaved with those from other Subscription Objects, as long as + those others are also in time stamp order. The Printer MUST observe + these ordering requirements whether delivering multiple pending + Events as multiple separate Event Notifications or together in a + single Compound Event Notification. + + + + + +Herriot & Hastings Standards Track [Page 41] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + If a Subscribing Client wants the Printer to deliver certain Event + Notifications in time stamp order, the Subscribing Client uses a + single Subscription Object. Even so, depending on the underlying + transport, the actual order that a Notification Recipient receives + separate Event Notifications may differ from the order sent by the + Printer (e.g., email). + + Example: Consider two Per-Printer Subscription Objects: SO1 and SO2. + SO1 requests 'job-state-changed' events and SO2 requests 'printer- + state-changed' events. The number in parens is the time stamp. The + following Event Notification sequences are the only ones that conform + to the ordering requirements for the Printer to deliver the Event + Notifications: + + (a) SO1: 'job-created' (1000), SO1: 'job-stopped' (1005), SO1: + 'job-completed' (1009), SO2: 'printer-stopped' (1005) + + (b) SO1: 'job-created' (1000), SO1: 'job-stopped' (1005), SO2: + 'printer-stopped' (1005), SO1: 'job-completed' (1009) + + (c) SO1: 'job-created' (1000), SO2: 'printer-stopped' (1005), SO1: + 'job-stopped' (1005), SO1: 'job-completed' (1009) + + (d) SO2: 'printer-stopped (1005), SO1: 'job-created' (1000), SO1: + 'job-stopped' (1005), SO1: 'job-completed' (1009) + + Examples (b) and (c) are interleaved; examples (a) and (d) are not + interleaved and are not appropriate for some Delivery Methods. + + 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- + 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, + + + +Herriot & Hastings Standards Track [Page 42] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 delivers the Event Notification + shortly after an Event occurs. For some Push Delivery Methods, + the Notification Recipient MUST deliver a response; for others it + MUST NOT deliver a response. + + Pull Delivery Method: The Printer saves Event Notifications for + some Event Life 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 delivering of an Event Notification + generated from Subscription Object S AND + + b) the error would continue to occur every time the Printer delivers + an Event Notification generated from Subscription Object S in the + future. + + For example, if the address of the "notify-recipient-uri" of + Subscription Object A references a non-existent target and the + Printer determines this fact, it MUST delete Subscription Object A. + + The next two sections describe the values that a Printer delivers 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: + + 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) Delivers: if the Printer supports the value (column 1) on the + Source Object (column 3) the Delivery Method MUST specify: + + MUST: that the Printer MUST deliver the value. + + + + + +Herriot & Hastings Standards Track [Page 43] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + SHOULD: either that the Printer MUST deliver 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 deliver 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 delivers 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 delivers 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 + +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. + + + + + +Herriot & Hastings Standards Track [Page 44] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Table 5 - Attributes in Event Notification Content + + Source Value Delivers 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 deliver this value only if and only if it supports + the Printer's "printer-current-time" attribute. + + ** If the Subscription Object does not contain a "notify-user-data" + attribute and the Delivery Method Document REQUIRES the Printer to + deliver the "notify-user-data" source value in the Event + Notification, the Printer MUST deliver 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. + + + + + + +Herriot & Hastings Standards Track [Page 45] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Table 6 - Additional Event Notification Content for Job Events + + Source Value Delivers 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 deliver the "job-impressions-completed" attribute + in an Event Notification only for the combinations of Events and + Subscribed Events shown in Table 7. + + 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 Delivers Source Object + + printer-state (type1 enum) MUST Printer + printer-state-reasons (1setOf type2 MUST Printer + keyword) + 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 deliver it: + + a) the Printer name (see Table 9) + + + +Herriot & Hastings Standards Track [Page 46] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + b) the time of the Event (see Table 11) + + c) for Printer Events only: + + 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 delivers 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 + + + + + +Herriot & Hastings Standards Track [Page 47] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 deliver + 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 deliver the value of the "notify-printer-uri" + attribute. + + Table 9 - Printer Name in Event Notification Content + + Source Value Delivers 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 Delivers 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 deliver 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 deliver + the "printer-up-time" value instead, since it is not an allowed + option for human consumable information. + + Table 11 - Event Time in Event Notification Content + + Source Value Delivers Source Object + + printer-current-time (dateTime) MAY Printer + + + + + +Herriot & Hastings Standards Track [Page 48] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +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 Delivers 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. + + Table 13 - Job State in Event Notification Content + + Source Value Delivers 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 & Hastings Standards Track [Page 49] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Table 14 - Printer State in Event Notification Content + + Source Value Delivers 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 specification REQUIRES + that the 'ippget' Pull Delivery Method [RFC3996] be supported. + Conforming implementations MAY support additional Push or Pull + Delivery Methods as well. 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 23.7.3). + + The following sorts of Delivery Methods are possible: + + - The Notification Recipient polls for Event Notifications at + intervals directed by the Printer + + - The Printer delivers Event Notifications to the Notification + Recipient using http as the transport. + + - The Printer delivers 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 [RFC3995] because the table contains an [RFC3995] + reference. + + If a Printer supports this Delivery Method, the following are its + characteristics. + + + +Herriot & Hastings Standards Track [Page 50] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Table 15 - Information about the Delivery Method + + Document Method Conformance Requirement Delivery Method + Realization + + 1. What is the URL scheme name for the Push Delivery Method or the + keyword method name for the Pull 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 + [RFC3995] 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 + [RFC3995] and the 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 delivers 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? + + + + +Herriot & Hastings Standards Track [Page 51] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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). + + 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. + + + + + +Herriot & Hastings Standards Track [Page 52] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Access Rights: To create Per-Job Subscription Objects, the + authenticated user (see [RFC2911] section 8.3) performing this + operation MUST (1) be the job owner, (2) have Operator or + Administrator access rights for this Printer (see [RFC2911] sections + 1 and 8.5), or (3) be otherwise authorized by the Printer's + administrator-configured security policy to create Per-Job + Subscription Objects for the target job. 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. + + 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. + +11.1.1.1.1. 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. + + + + +Herriot & Hastings Standards Track [Page 53] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +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 + 3.1.6. + + In this group, the Printer can return any status codes defined in + [RFC2911] and section 12. The following is a description of the + important status codes: + + successful-ok: the Printer created all Subscription Objects + requested (see [RFC2911]). + + 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 (see section 12.1). + + 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 (see section 12.2). + + client-error-not-possible: For this operation and other Per-Job + Subscription operations, this error can occur because the + specified Job has already completed (see [RFC2911], whether or + not the Job is retained in the Job Retention and/or Job History + phases (see [RFC2911] section 4.3.7.1). + + 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). + + + + +Herriot & Hastings Standards Track [Page 54] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 13 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 (1) Operator or Administrator access rights for + this Printer (see [RFC2911] sections 1 and 8.5), or (2) be otherwise + authorized by the Printer's administrator-configured security policy + to create Per-Printer Subscription Objects for this 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.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. + + + + + +Herriot & Hastings Standards Track [Page 55] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +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 Operations - Extensions for Notification + + This document extends the Job Creation operations (see section 3.2) + to create Subscription Objects as a part of the operation. + + The Job Creation operations are identical to Create-Job-Subscriptions + operation with exceptions noted in this section. + + Unlike the Create-Job-Subscriptions operation, a Job Creation + 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 Job Creation 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. + + After completion of a successful Job Creation operation, the Printer + generates a 'job-created' event (see section 5.3.3.4.3). + + Access Rights: To create Per-Job Subscription Objects, the + authenticated user (see [RFC2911] section 8.3) performing this + operation MUST either have permission to create Jobs on the Printer + 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. + + + + + + + +Herriot & Hastings Standards Track [Page 56] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +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 12. The following is a description of + the important status codes: + + successful-ok: the Printer created the Job and all + Subscription Objects requested (see [RFC2911]. + + successful-ok-ignored-subscriptions: the Printer created + the Job and not all of the Subscription Objects requested + + + +Herriot & Hastings Standards Track [Page 57] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + (see section 12.1). This 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 + + The "job-id" of the Job Object just created, etc., 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. Restart-Job Operation - Extensions for Notification + + The Restart-Job operation [RFC2911] is neither a Job Creation + operation nor a Subscription Creation operation (see section 3.2). + + For the Restart-Job operation, the client MUST NOT supply any Job + Subscription Attributes Groups. The Printer MUST treat any supplied + Job Subscription Attributes as unsupported attributes. + + For this operation, the Printer does not return a job-id or any + Subscription Attributes groups because the Printer reuses the + existing Job object with the same job-id and the existing Per-Job + Subscription Objects with the same subscription-ids. However, after + + + +Herriot & Hastings Standards Track [Page 58] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + successful completion of this operation, the Printer generates a + 'job-created' event (see section 5.3.3.4.3). + +11.2.2. 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 + 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 13). 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.3. 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. + + + +Herriot & Hastings Standards Track [Page 59] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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.4. Get-Subscription-Attributes operation + + This operation allows a client to request the values of the + attributes of a Subscription Object. + + 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. + + Access Rights: The authenticated user (see [RFC2911] section 8.3) + performing this operation MUST (1) be the Subscription Object owner, + (2) have Operator or Administrator access rights for this Printer + (see [RFC2911] sections 1 and 8.5), or (3) be otherwise authorized by + the Printer's administrator-configured security policy to query the + Subscription Object for the target job. 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. Furthermore, the Printer's security + policy MAY limit which attributes are returned, in a manner similar + to the Get-Job-Attributes operation (see [RFC2911] end of section + 3.3.4.2). + +11.2.4.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: + + + +Herriot & Hastings Standards Track [Page 60] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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. + + Requesting User Name: + The "requesting-user-name" attribute SHOULD be supplied by the + client as described in [RFC2911] section 8.3. + +11.2.4.1.1. "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. + +11.2.4.1.2. "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). + + - '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.4.2. Get-Subscription-Attributes Response + + The Printer returns the following sets of attributes as part of the + Get-Subscription-Attributes Response: + + + +Herriot & Hastings Standards Track [Page 61] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 and section 3.2.5.2 for details on + returning Unsupported Attributes. + + The response NEED NOT contain the "requested-attributes" operation + attribute with any supplied keyword values 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, the values of the + "requested-attributes" attribute returned MUST include only the + unsupported keywords that were requested by the client. If the + client had requested a group name, such as 'all', the resulting + unsupported attributes returned MUST NOT include attribute keyword + names 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 returned 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 creator of + a Subscription Object from seeing some or all of its attributes. + See [RFC2911] end of section 3.3.4.2 and section 8. + + The Printer can return the attributes of the Subscription Object + in any order. The client MUST accept the attributes in any order. + + + + + + +Herriot & Hastings Standards Track [Page 62] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +11.2.5. 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. + + Access Rights: To query Per-Job Subscription Objects of the + specified job (client supplied the "notify-job-id" operation + attribute - see section 11.2.5.1.1), the authenticated user (see + [RFC2911] section 8.3) performing this operation MUST (1) be the + Subscription Object owner, (2) have Operator or Administrator access + rights for this Printer (see [RFC2911] sections 1 and 8.5), or (3) be + otherwise authorized by the Printer's administrator-configured + security policy to query the Subscription Object for the target job. + To query Per-Printer Subscription Objects of the Printer (client + omits the "notify-job-id" operation attribute - see section + 11.2.5.1.1), the authenticated user (see [RFC2911] section 8.3) + performing this operation MUST (1) have Operator or Administrator + access rights for this Printer (see [RFC2911] sections 1 and 8.5), or + (2) be otherwise authorized by the Printer's administrator-configured + security policy to query Per-Printer Subscription Objects for the + target 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. Furthermore, the Printer's security policy MAY limit + which attributes are returned, in a manner similar to the Get-Jobs + and Get-Printer-Attributes operations (see [RFC2911] end of sections + 3.2.6.2 and 3.2.5.2). + +11.2.5.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. + + + +Herriot & Hastings Standards Track [Page 63] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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. + +11.2.5.1.1. "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 known to the Printer in a single operation. A Get-Jobs + operation followed by a Get-Subscriptions operation for each Job will + return all Per-Job Subscriptions. + +11.2.5.1.2. "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. + +11.2.5.1.3. "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.4.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'. + + + + + + +Herriot & Hastings Standards Track [Page 64] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +11.2.5.1.4. "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.5.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]. + + 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, + + + + +Herriot & Hastings Standards Track [Page 65] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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.4.2) for the + attributes that a Printer returns in this group. + +11.2.6. 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 (1) be the owner of the Per-Printer + Subscription Object, (2) have Operator or Administrator access rights + for the Printer (see [RFC2911] sections 1 and 8.5), or (3) be + otherwise authorized by the Printer's administrator-configured + security policy to renew Per-Printer Subscription Objects for the + target 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.2.6.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. + + + +Herriot & Hastings Standards Track [Page 66] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Requesting User Name: + The "requesting-user-name" (name(MAX)) attribute SHOULD be + supplied by the client as described in [RFC2911] section 8.3. + +11.2.6.1.1. "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. + + Group 2: Subscription Template Attributes + +11.2.6.1.2. "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.8 for more details. + +11.2.6.2. Renew-Subscription Response + + The Printer returns the following sets of attributes as part of the + Renew-Subscription Response: + + Group 1: Operation Attributes + + Status Message: + Same as [RFC2911]. + + The following are some of the status codes returned (see + [RFC2911]: + + 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. + + + + + +Herriot & Hastings Standards Track [Page 67] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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: + +11.2.6.2.1. "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.8 for details, such as the value of this attribute when + the Printer doesn't support the requested value). + +11.2.7. Cancel-Subscription operation + + This operation allows a client to delete a Subscription Object and + stop the Printer from delivering more Event Notifications. Once + performed, there is no way to reference the Subscription Object. + + A Printer MUST supported this operation. + + 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. + + 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 + + + +Herriot & Hastings Standards Track [Page 68] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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. + + Access Rights: The authenticated user (see [RFC2911] section 8.3) + performing this operation MUST (1) be the owner of the Subscription + Object, (2) have Operator or Administrator access rights for the + Printer (see [RFC2911] sections 1 and 8.5), or (3) be otherwise + authorized by the Printer's administrator-configured security policy + to cancel the target Subscription Object. 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.7.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. + + Requesting User Name: + The "requesting-user-name" attribute SHOULD be supplied by the + client as described in [RFC2911] section 8.3. + +11.2.7.1.1. "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 & Hastings Standards Track [Page 69] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +11.2.7.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 (see + [RFC2911]: + + 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. 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. + +12.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 + + + + +Herriot & Hastings Standards Track [Page 70] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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'. + +12.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. + +13. 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. + +13.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 5.3.1. + +13.2. client-error-attributes-or-values-not-supported (0x040B) + + 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. + + + +Herriot & Hastings Standards Track [Page 71] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + The method of the client-supplied keyword in a "notify-pull-method" + Subscription Template Attribute in a Subscription Creation Operation + is not supported. See section 5.3.2. + +13.3. 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). + +13.4. 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.3). + +13.5. 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. + +14. 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" + +15. Conformance Requirements + + It is OPTIONAL for IPP clients and Printers to implement this Event + Notification specification. + + + + + + +Herriot & Hastings Standards Track [Page 72] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +15.1. Conformance requirements for clients + + If this Event Notification specification is implemented by a client, + the client MUST support the 'ippget' Pull Delivery Method and meet + the conformance requirements as defined in [RFC3996] for clients. A + client MAY support additional Delivery Methods. + +15.2. Conformance requirements for Printers + + If this Event Notification specification is implemented by a Printer, + the Printer MUST: + + - meet the Conformance Requirements detailed in section 5 of + [RFC2911]. + + - support the Subscription Template Attributes Group in requests and + the Subscription Attributes Group in responses. + + - support all of the following attributes: + + a. REQUIRED Subscription Object attributes in section 5. + b. REQUIRED Printer Description object attributes in section 6. + c. REQUIRED attributes in Event Notification content in section 8. + + - support the 'ippget' Pull Delivery Method and meet the conformance + requirements as defined in [RFC3996] for Printers. The Printer + MAY support additional Push and Pull Delivery Methods. + + - deliver Event Notifications that conform to the requirements of + section 9 and the requirements of the Delivery Method Document for + each supported Delivery Method (the conformance requirements for + Delivery Method Documents is specified in section 10). + + - for all of the Job Creation Operations that the Printer supports, + MUST support the REQUIRED extensions for notification defined in + section 11.1.3. + + - meet the conformance requirements for operations as described in + Table 16 and meet the requirements for Printers as specified in + the indicated sub-sections of section 11: + + + + + + + + + + + +Herriot & Hastings Standards Track [Page 73] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Table 16 - Printer Conformance Requirements for Operations + + Operation Printer + Conformance + Requirements + + Create-Printer-Subscriptions (section 11.1.2) REQUIRED + Create-Job-Subscriptions (section 11.1.1) OPTIONAL + Get-Subscription-Attributes (section 11.2.3) REQUIRED + Get-Subscriptions (section 11.2.5) REQUIRED + Renew-Subscription (section 11.2.6) REQUIRED + Cancel-Subscription (section 11.2.7) REQUIRED + +16. Model for Notification with Cascading Printers (Informative) + + With this model (see Figure 2 below), there is an intervening Print + server between the human user and the output-device. So the system + effectively has two Printer objects. 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 delivers 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 + deliver 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 delivers 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 Subscription Creation Operation to Printer + 2 if it would create a duplicate Subscription Object on Printer + 2. + + + + + +Herriot & Hastings Standards Track [Page 74] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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 + +17. Distributed Model for Notification (Informative) + + A Printer implementation could use some other remote notification + server to provide some or most of the service. For example, the + remote notification server could deliver Event Notifications using + Delivery Methods that are not directly supported by the output device + or Printer object. Or, the remote notification server 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 deliver the Event Notifications to the Notification Recipient(s). + + Figure 3 shows this partitioning. The interface between the output + device (or Printer object) and the remote notification server is + outside the scope of this document and is intended to be transparent + to the client and this document. + + + + + + + +Herriot & Hastings Standards Track [Page 75] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + *********************** + * + * Printer in combination + * with the distributed + * Notification Server) + * + * output device or server + * +---------------+ + PDA, desktop, or server * + ########### + + +--------+ * | # # | + | client |---IPP Subscription--------># Printer # | + +--------+ Creation operation * | # Object # | + * | #####|##### | + * +-------|-------+ + * | Subscriptions + * | OR Event + +------------+ * | Notifications + |Notification| IPP-defined * +------v--------+ + |Recipient |<--Event Notifications---| Notification | + +------------+ * | Server | + * +---------------+ + * + ************************* + *** = Implementation configuration opaque boundary + + Figure 3 - Opaque Use of a Notification Server Transparent to the + Client + +18. Extended Notification Recipient (Informative) + + The model allows for an extended Notification Recipient that is + itself a notification server 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 + "notify-user-data" or some additional parameter in the value of + "notify-recipient-uri". The client also subscribes directly with the + + + +Herriot & Hastings Standards Track [Page 76] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + extended Notification Recipient (by means outside this document), + since it is a notification server 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 Server) + + Figure 4 - Use of an Extended Notification Recipient transparent to + the Printer + +19. Object Model for Notification (Normative) + + 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 & Hastings Standards Track [Page 77] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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. + +19.1. 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 + + + + + +Herriot & Hastings Standards Track [Page 78] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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: + +19.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). + +19.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. + +20. Per-Job versus Per-Printer Subscription Objects (Normative) + + 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. + + + +Herriot & Hastings Standards Track [Page 79] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 2. For Per-Job Subscription Objects, the Subscription Object is only + valid while the job is "not-complete" (see sections 5.4.3) 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. + +21. Normative References + + [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. + + [RFC2717] Petke, R. and I. King, "Registration Procedures for + URL Scheme Names", RFC 2717, November 1999. + + [RFC2910] Herriot, R., Butler, S., Moore, P., and R. Turner, + "Internet Printing Protocol/1.1: Encoding and + Transport", RFC 2910, September 2000. + + [RFC2911] deBry, R., Hastings, T., Herriot, R., Isaacson, S., + and P. Powell, "Internet Printing Protocol/1.1: + Model and Semantics", RFC 2911, September 2000. + + [RFC3381] Hastings, T., Lewis, H., and R. Bergman, "IPP: Job + Progress Attributes", RFC 3381, September 2002. + + [RFC3996] Herriot, R., Hastings, T., and H. Lewis, "Internet + Printing Protocol (IPP): The 'ippget' Delivery + Method for Event Notifications", RFC 3996, March + 2005. + +22. Informative References + + [IANA-CON] Narten, T. and H. Alvestrand, "Guidelines for + Writing an IANA Considerations Section in RFCs", + BCP 26, RFC 2434, October 1998. + + + + + + +Herriot & Hastings Standards Track [Page 80] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + [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. + + [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. + + [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C., + and H. Holst, "Internet Printing Protocol/1.1: + Implementer's Guide", RFC 3196, November 2001. + + [RFC3997] Hastings, T., Editor, deBry, R., and H. Lewis, + "Internet Printing Protocol (IPP): Requirements for + IPP Notifications", RFC 3997, March 2005. + +23. IANA Considerations + + This section contains the registration information that IANA added to + the IPP Registry according to the procedures defined in RFC 2911 + [RFC2911] section 6 to cover the definitions in this document. In + addition, this section defines how Events and Delivery Methods will + be registered when they are defined in other documents. The + resulting registrations have been published in the + http://www.iana.org/assignments/ipp-registrations registry. + + + + + + + + + + +Herriot & Hastings Standards Track [Page 81] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +23.1. Attribute Registrations + + The following table lists all the attributes defined in this + document. These have been registered according to the procedures in + RFC 2911 [RFC2911] section 6.2. + + Subscription Template attributes: Reference Section + --------------------------------- --------- ------- + notify-attributes (1setOf type2 keyword) [RFC3995] 5.3.4 + notify-attributes-supported (1setOf type2 keyword) + [RFC3995] 5.3.4.1 + notify-charset (charset) [RFC3995] 5.3.6 + notify-events (1setOf type2 keyword) [RFC3995] 5.3.3 + notify-events-default (1setOf type2 keyword) [RFC3995] 5.3.3.1 + notify-events-supported (1setOf type2 keyword) [RFC3995] 5.3.3.2 + notify-lease-duration (integer(0:67108863)) [RFC3995] 5.3.8 + notify-lease-duration-default (integer(0:67108863)) + [RFC3995] 5.3.8.1 + notify-lease-duration-supported (1setOf (integer(0: 67108863) | + rangeOfInteger(0:67108863))) [RFC3995] 5.3.8.2 + notify-max-events-supported (integer(2:MAX)) [RFC3995] 5.3.3.3 + notify-natural-language (naturalLanguage) [RFC3995] 5.3.7 + notify-pull-method (type2 keyword) [RFC3995] 5.3.2 + notify-pull-method-supported (1setOf type2 keyword) + [RFC3995] 5.3.2.1 + notify-recipient-uri (uri) [RFC3995] 5.3.1 + notify-schemes-supported (1setOf uriScheme) [RFC3995] 5.3.1.1 + notify-time-interval (integer(0:MAX)) [RFC3995] 5.3.9 + notify-user-data (octetString(63)) [RFC3995] 5.3.5 + + Subscription Description Attributes: + notify-job-id (integer(1:MAX)) [RFC3995] 5.4.6 + notify-lease-expiration-time (integer(0:MAX)) [RFC3995] 5.4.3 + notify-printer-up-time (integer(1:MAX)) [RFC3995] 5.4.4 + notify-printer-uri (uri) [RFC3995] 5.4.5 + notify-sequence-number (integer (0:MAX)) [RFC3995] 5.4.2 + notify-subscriber-user-name (name(MAX)) [RFC3995] 5.4.7 + notify-subscription-id (integer (1:MAX)) [RFC3995] 5.4.1 + + Printer Description Attributes: + printer-state-change-date-time (dateTime) [RFC3995] 6.2 + printer-state-change-time (integer(1:MAX)) [RFC3995] 6.1 + + Attributes Only in Event Notifications + notify-subscribed-event (type2 keyword) [RFC3995] 8.1 + notify-text (text(MAX)) [RFC3995] 8.2 + + + + + +Herriot & Hastings Standards Track [Page 82] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +23.2. Additional Enum Attribute Value Registrations within the IPP + registry + + The following table lists all the new enum attribute values defined + in this document. These have been registered within the IPP registry + according to the procedures in RFC 2911 [RFC2911] section 6.1. + + Attribute + Value Name Reference Section + ------ ----------------------------- --------- ------- + operations-supported (1setOf type2 enum) [RFC2911] 4.4.15 + 0x0016 Create-Printer-Subscriptions [RFC3995] 7.1 + 0x0017 Create-Job-Subscriptions [RFC3995] 7.1 + 0x0018 Get-Subscription-Attributes [RFC3995] 7.1 + 0x0019 Get-Subscriptions [RFC3995] 7.1 + 0x001A Renew-Subscription [RFC3995] 7.1 + 0x001B Cancel-Subscription [RFC3995] 7.1 + +23.3. Operation Registrations + + The following table lists all of the operations defined in this + document. These have been registered according to the procedures in + RFC 2911 [RFC2911] section 6.4. + + Operation Name Reference Section + --------------------------------- --------- ------- + Cancel-Subscription [RFC3995] 11.2.7 + Create-Job - Extensions [RFC3995] 11.1.3 + Create-Job-Subscriptions [RFC3995] 11.1.1 + Create-Printer-Subscriptions [RFC3995] 11.1.2 + Get-Printer-Attributes - Extensions [RFC3995] 11.2.3 + Get-Subscription-Attributes [RFC3995] 11.2.4 + Get-Subscriptions [RFC3995] 11.2.5 + Print-Job - Extensions [RFC3995] 11.1.3 + Print-URI - Extensions [RFC3995] 11.1.3 + Renew-Subscription [RFC3995] 11.2.6 + Validate-Job Operation - Extensions [RFC3995] 11.2.2 + +23.4. Status code Registrations + + The following table lists all the status codes defined in this + document. These have been registered according to the procedures in + RFC 2911 [RFC2911] section 6.6. + + + + + + + + +Herriot & Hastings Standards Track [Page 83] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Value Status Code Name Reference Section + ----- ---------------------------- --------- ------- + 0x0000:0x00FF - Successful: + 0x0003 successful-ok-ignored-subscriptions [RFC3995] 12.1 + 0x0005 successful-ok-too-many-events [RFC3995] 13.4 + + 0x0400:0x04FF - Client Error: + 0x0414 client-error-ignored-all-subscriptions [RFC3995] 12.2 + 0x0415 client-error-too-many-subscriptions [RFC3995] 13.3 + +23.5. Attribute Group tag Registrations + + The following table lists all the attribute group tags defined in + this document. These have been registered according to the + procedures in RFC 2911 [RFC2911] section 6.5. + + Value Attribute Group Tag Name Reference Section + ----- -------------------------------- -------- ------- + 0x06 subscription-attributes-tag [RFC3995] 14 + 0x07 event-notification-attributes-tag [RFC3995] 14 + +23.6. Registration of Events + + The following table lists all the Events defined in this document as + type2 keywords to be used with the "notify-events", "notify-events- + default", and "notify-events-supported" Subscription Template + attributes (see section 5.3.3)). Rather than creating a separate + section in the IPP Registry for Events, these event keywords have + been registered according to the procedures of [RFC2911] section 7.1 + as additional keyword attribute values for use with the "notify- + events" Subscription Template attribute (see section 5.3.3), i.e., + registered as keyword values for the "notify-events", "notify- + events-default", and "notify-events-supported" attributes: + + Attribute (attribute syntax) + Value Reference Section + --------------------- --------- ------- + notify-events (1setOf type2 keyword) [RFC3995] 5.3.3 + notify-events-default (1setOf type2 keyword) [RFC3995] 5.3.3.1 + notify-events-supported (1setOf type2 keyword) [RFC3995] 5.3.3.2 + notify-subscribed-event (type2 keyword) [RFC3995] 8.1 + No Events: + none [RFC3995] 5.3.3.4.1 + Printer Events: + printer-state-changed [RFC3995] 5.3.3.4.2 + printer-restarted [RFC3995] 5.3.3.4.2 + printer-shutdown [RFC3995] 5.3.3.4.2 + printer-stopped [RFC3995] 5.3.3.4.2 + + + +Herriot & Hastings Standards Track [Page 84] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + printer-config-changed [RFC3995] 5.3.3.4.2 + printer-media-changed [RFC3995] 5.3.3.4.2 + printer-finishings-changed [RFC3995] 5.3.3.4.2 + printer-queue-order-changed [RFC3995] 5.3.3.4.2 + Job Events: + job-state-changed [RFC3995] 5.3.3.4.3 + job-created [RFC3995] 5.3.3.4.3 + job-completed [RFC3995] 5.3.3.4.3 + job-stopped [RFC3995] 5.3.3.4.3 + job-config-changed [RFC3995] 5.3.3.4.3 + job-progress [RFC3995] 5.3.3.4.3 + +23.7. Registration of Event Notification Delivery Methods + + This section describes the requirements and procedures for + registration and publication of Event Notification Delivery Methods + and for the submission of such proposals. + +23.7.1. Requirements for Registration of Event Notification Delivery + Methods + + Registered IPP Event Notification Delivery Methods are expected to + follow a number of requirements described below. + +23.7.1.1. Required Characteristics + + A Delivery Method Document MUST either (1) contain all of the + semantics of the Delivery Method or (2) contain the IPP Delivery + Method registration requirements and a profile of some other protocol + that in combination is the Delivery Method (e.g., mailto). The + Delivery Method Document (and any documents it requires) MUST define + either (1) a URL for a Push Delivery Method that the meets the + requirements of [RFC2717]. or (2) a keyword for a Pull Delivery + method. + + IPP Event Notification Delivery Method Documents MUST meet the + requirements of this document (see sections 9 and 10). + + In addition, a Delivery Method Document MUST contain the following + information: + + Type of registration: IPP Event Notification Delivery Method + Name of this delivery method: + Proposed URL scheme name of this Push Delivery Method or the + keyword name of this Pull Delivery Method: + Name of proposer: + Address of proposer: + + + + +Herriot & Hastings Standards Track [Page 85] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Email address of proposer: + Is this delivery method REQUIRED or OPTIONAL for conformance to + the IPP Event Notification and Subscriptions document: + Is this delivery method defining Machine Consumable and/or Human + Consumable content: + +23.7.1.2. Naming Requirements + + Exactly one (URL scheme or keyword) name MUST be assigned to each + Delivery Method. + + Each assigned name MUST uniquely identify a single Delivery Method. + All Push Delivery Method names MUST conform to the rules for URL + scheme names, according to [RFC2396] and [RFC2717] for schemes in the + IETF tree. All Pull Delivery Method names MUST conform to the rules + for keywords according to [RFC2911]. + +23.7.1.3. Functionality Requirements + + Delivery Methods MUST function as a protocol that is capable of + delivering (push or pull) IPP Event Notifications to Notification + Recipients. + +23.7.1.4. Usage and Implementation Requirements + + Use of a large number of Delivery Methods may hamper + interoperability. However, the use of a large number of undocumented + and/or unlabeled Delivery Methods hampers interoperability even more. + + A Delivery Method should therefore be registered ONLY if it adds + significant functionality that is valuable to a large community, OR + if it documents existing practice in a large community. Note that + Delivery Methods registered for the second reason should be + explicitly marked as being of limited or specialized use and should + only be used with prior bilateral agreement. + +23.7.1.5. Publication Requirements + + Delivery Method Documents MUST be published in a standards track, + informational, or experimental RFCs. + +23.7.2. Registration Procedure + + The IPP WG is developing a small number of Delivery Methods which are + intended to be published as standards track RFCs. However, some + parties may wish to register additional Delivery Methods in the + future. This section describes the procedures for these additional + Delivery Methods. + + + +Herriot & Hastings Standards Track [Page 86] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +23.7.2.1. Present the proposal to the Community + + First the Delivery Method Document MUST be an Internet-Draft with a + target category of standards track, informational, or experimental. + The same MUST be true for any documents that it references. + + Deliver the proposed Delivery Method Document proposal to the + "ipp@pwg.org" mailing list. This mailing list has been established + by [RFC2911] for reviewing proposed registrations and discussing + other IPP matters. Proposed Delivery Method Documents are not + formally registered and MUST NOT be used until approved. + + The intent of the public posting is to solicit comments and feedback + on the definition and suitability of the Delivery Method and the name + chosen for it over a four week period. + +23.7.2.2. Delivery Method Reviewer + + The Delivery Method Reviewer is the same person who has been + appointed by the IETF Application Area Director(s) as the IPP + Designated Expert according to [RFC2911] and [IANA-CON]. When the + four week period is over and the IPP Designated Expert is convinced + that consensus has been achieved, the IPP Designated Expert either + approves the request for registration or rejects it. Rejection may + occur because of significant objections raised on the list or + objections raised externally. + + Decisions made by the Reviewer must be posted to the ipp@pwg.org + mailing list within 14 days. Decisions made by the Reviewer may be + appealed to the IESG. + +23.7.2.3. IANA Registration + + Provided that the Delivery Method registration proposal has either + passed review or has been successfully appealed to the IESG, the IANA + will be notified by the delivery method reviewer and asked to + register the Delivery Method and make it available to the community. + +23.7.3. Delivery Method Document Registrations + + Each Push Delivery Method Document defines a URI scheme. Such a URI + scheme is used in a URI value of the "notification-recipient" (uri) + Subscription Template attribute (see section 5.3.1) and the uriScheme + value of the "notify-schemes-supported" (1setOf uriScheme 5.3.1.1) + Printer attribute(see section ). Rather than creating a separate + section in the IPP Registry for Delivery Methods, Push Delivery + Methods will be registered as an additional value of the "notify- + schemes-supported" Printer attribute. These uriScheme values will be + + + +Herriot & Hastings Standards Track [Page 87] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + registered according to the procedures of [RFC2911] section 7.1 for + additional attribute values. Therefore, the IPP Registry entry for a + Push Delivery Method will be of the form: + + Attribute + Value Ref. Section + --------------------- -------- ------- + notify-schemes-supported (1setOf uriScheme) [RFC3995] 5.3.1.1 + RFC xxxx m.n + + Each Pull Delivery Method Document defines a keyword method which is + registered as an additional value of the "notify-pull-method" and + "notify-pull-method-supported" Printer attributes. These keyword + values will be registered according to the procedures of [RFC2911] + section 7.1 for additional attribute values. Therefore, the IPP + Registry entry for a Pull Delivery Method will be of the form: + + Attribute + Value Ref. Section + --------------------- -------- ------- + notify-pull-method (type2 keyword) [RFC3995] 5.3.2 + notify-pull-method-supported (1setOf type2 keyword) + [RFC3995] 5.3.2.1 + RFC xxxx m.n + +23.7.4. Registration Template + + To: ipp@pwg.org + Subject: Registration of a new Delivery Method + + Delivery Method name: + + (All Push Delivery Method names must be suitable for use as the value + of a URL scheme in the IETF tree and all Pull Delivery Method names + must be suitable IPP keywords according to [RFC2911]) + + Published specification(s): + + (A specification for the Delivery Method must be openly available + that accurately describes what is being registered.) + + Person & email address to contact for further information: + + + + + + + + + +Herriot & Hastings Standards Track [Page 88] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +24. 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 delivers + 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. + +25. Security Considerations + + Clients submitting Notification requests to the IPP Printer have the + same security issues as submitting an IPP/1.1 print job request (see + [RFC2911] section 3.2.1 and section 8). 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. As with IPP/1.1 Print Job Objects, if there is no security + on Subscription Objects, sequential assignment of subscription-ids + exposes the system to a passive traffic monitoring threat. + +25.1. Client access rights + + The Subscription Object access control model is the same as the + access control model for Job objects. The client MUST have the + following access rights for the indicated Subscription operations: + + 1. Create-Job-Subscriptions (see section 11.1.1): A Per-Job + Subscription object is associated with a Job. To create Per-Job + Subscription Objects, the authenticated user (see [RFC2911] + section 8.3) performing this operation MUST (1) be the job owner, + (2) have Operator or Administrator access rights for this Printer + (see [RFC2911] sections 1 and 8.5), or (3) be otherwise authorized + by the Printer's administrator-configured security policy to + create Per-Job Subscription Objects for the target job. + + 2. Create-Printer-Subscriptions (see section 11.1.2): A Per-Printer + Subscription object is associated with the Printer. To create + Per-Printer Subscription Objects, the authenticated user (see + [RFC2911] section 8.3) performing this operation MUST (1) have + Operator or Administrator access rights for this Printer (see + + + +Herriot & Hastings Standards Track [Page 89] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + [RFC2911] sections 1 and 8.5) or (2) be otherwise authorized by + the Printer's administrator-configured security policy to create + Per-Printer Subscription Objects for this Printer. + + 3. Get-Subscription-Attributes (see section 11.2.4): The access + control model for this operation is the same as that of the Get- + Job-Attributes operation (see [RFC2911] section 3.3.4). The + primary difference is that a Get-Subscription-Attributes operation + is directed at a Subscription Object rather than at a Job object, + and a returned attribute group contains Subscription Object + attributes rather than Job object attributes. To query the + specified Subscription Object, the authenticated user (see + [RFC2911] section 8.3) performing this operation MUST (1) be the + Subscription Object owner, (2) have Operator or Administrator + access rights for this Printer (see [RFC2911] sections 1 and 8.5), + or (3) be otherwise authorized by the Printer's administrator- + configured security policy to query the Subscription Object for + the target job. Furthermore, the Printer's security policy MAY + limit which attributes are returned, in a manner similar to the + Get-Job-Attributes operation (see [RFC2911] end of section + 3.3.4.2). + + 4. Get-Subscriptions (see section 11.2.5): The access control model + for this operation is the same as that of the Get-Jobs operation + (see [RFC2911] section 3.2.6). The primary difference is that the + operation is directed at Subscription Objects rather than at Job + objects, and the returned attribute groups contain Subscription + Object attributes rather than Job object attributes. To query + Per-Job Subscription Objects of the specified job (client supplied + the "notify-job-id" operation attribute - see section 11.2.5.1.1), + the authenticated user (see [RFC2911] section 8.3) performing this + operation MUST (1) be the Subscription Object owner, (2) have + Operator or Administrator access rights for this Printer (see + [RFC2911] sections 1 and 8.5), or (3) be otherwise authorized by + the Printer's administrator-configured security policy to query + the Subscription Object for the target job. To query Per-Printer + Subscription Objects of the Printer (client omits the "notify- + job-id" operation attribute - see section 11.2.5.1.1), the + authenticated user (see [RFC2911] section 8.3) performing this + operation MUST (1) have Operator or Administrator access rights + for this Printer (see [RFC2911] sections 1 and 8.5), or (2) be + otherwise authorized by the Printer's administrator-configured + security policy to query Per-Printer Subscription Objects for the + target Printer. Furthermore, the Printer's security policy MAY + limit which attributes are returned, in a manner similar to the + Get-Job-Attributes operation (see [RFC2911] end of section + 3.2.6.2). + + + + +Herriot & Hastings Standards Track [Page 90] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 5. Renew-Subscriptions (see section 11.2.6): The authenticated user + (see [RFC2911] section 8.3) performing this operation MUST (1) be + the owner of the Per-Printer Subscription Object, (2) have + Operator or Administrator access rights for the Printer (see + [RFC2911] sections 1 and 8.5), or (3) be otherwise authorized by + the Printer's administrator-configured security policy to renew + Per-Printer Subscription Objects for the target Printer + + 6. Cancel-Subscription (see section 11.2.7): The authenticated user + (see [RFC2911] section 8.3) performing this operation MUST (1) be + the owner of the Subscription Object, (2) have Operator or + Administrator access rights for the Printer (see [RFC2911] + sections 1 and 8.5), or (3) be otherwise authorized by the + Printer's administrator-configured security policy to cancel the + target Subscription Object. + + The standard security concerns (delivery to the right user, privacy + of content, tamper proof content) apply to each Delivery Method. + Some Delivery Methods are more secure than others. Each Delivery + Method Document MUST discuss its Security Considerations. + +25.2. Printer security threats + + Notification trap door: If a Printer supports the OPTIONAL "notify- + attributes" Subscription Template attribute (see section 5.3.4) where + the client can request that the Printer return any specified Job, + Printer, and Subscription object attributes, the Printer MUST apply + the same security policy to these requested attributes in the Get- + Notifications request as it does for the Get-Jobs, Get-Job- + Attributes, Get-Printer-Attributes, and Get-Subscription-Attributes + requests. + +25.3. Notification Recipient security threats + + Unwanted Events Notifications (spam): For any Push Delivery Method, + by far the biggest security concern is the abuse of notification: + delivering unwanted Event Notifications to third parties (i.e., + spam). The problem is made worse by notification addresses that may + be redistributed to multiple parties. There exist scenarios where + third party notification is used (see Scenario #2 and #3 in + [RFC3997]). Any fully secure solution would require active agreement + of all recipients before delivering anything. + + + + + + + + + +Herriot & Hastings Standards Track [Page 91] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +26. Description of the base IPP documents (Informative) + + The base 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 [RFC3196] + 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 [RFC2566, RFC2565]. A few OPTIONAL operator + operations have been added to IPP/1.1 [RFC2911, RFC2910]. + + 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 IPP 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. 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 "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 also 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 the 'ipp' scheme 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 + + + +Herriot & Hastings Standards Track [Page 92] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + 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. + +27. Contributors + + The following people made significant contributions to the design and + review of this specification: + + Scott A. Isaacson + Novell, Inc. + 122 E 1700 S + Provo, UT 84606 + + Phone: 801-861-7366 + Fax: 801-861-2517 + EMail: sisaacson@novell.com + + + Roger deBry + Utah Valley State College + Orem, UT 84058 + + Phone: 801-863-8848 + EMail: debryro@uvsc.edu + + + Jay Martin + Underscore Inc. + 9 Jacqueline St. + Hudson, NH 03051-5308 + + Phone: 603-889-7000 + Fax: 775-414-0245 + EMail: jkm@underscore.com + + + Michael Shepherd + Xerox Corporation + 800 Phillips Road MS 128-51E + Webster, NY 14450 + + Phone: 716-422-2338 + Fax: 716-265-8871 + EMail: mshepherd@usa.xerox.com + + + +Herriot & Hastings Standards Track [Page 93] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + + Ron Bergman + Ricoh Printing Systems America + 1757 Tapo Canyon Road + Simi Valley, CA 93063-3394 + + Phone: 805-578-4421 + Fax: 805-578-4001 + EMail: ron.bergman@rpsa.ricoh.com + +Authors' Addresses + + Robert Herriot + Global Workflow Solutions + 706 Colorado Ave. + Palo Alto, CA 94303 + + Phone: 650-324-4000 + EMail: bob@herriot.com + + + Tom Hastings + Xerox Corporation + 701 S Aviation Blvd, ESAE 242 + El Segundo, CA 90245 + + Phone: 310-333-6413 + Fax: 310-333-6342 + EMail: hastings@cp10.es.xerox.com + + + + + + + + + + + + + + + + + + + + + + + +Herriot & Hastings Standards Track [Page 94] + +RFC 3995 IPP: Event Notifications and Subscriptions March 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM 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. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights 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; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat 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 on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Herriot & Hastings Standards Track [Page 95] + diff --git a/standards/rfc3996.txt b/standards/rfc3996.txt new file mode 100644 index 000000000..c2a2a86d6 --- /dev/null +++ b/standards/rfc3996.txt @@ -0,0 +1,1739 @@ + + + + + + +Network Working Group R. Herriot +Request for Comments: 3996 Global Workflow Solutions +Updates: 2911 T. Hastings +Category: Standards Track Xerox Corp. + H. Lewis + IBM Corp. + March 2005 + + + Internet Printing Protocol (IPP): + The 'ippget' Delivery Method for Event Notifications + +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 (2005). + +Abstract + + This document describes an extension to the Internet Printing + Protocol1.1: Model and Semantics (RFC 2911, RFC 2910). This document + specifies the 'ippget' Pull Delivery Method for use with the + "Internet Printing Protocol (IPP): Event Notifications and + Subscriptions" specification (RFC 3995). This IPPGET Delivery Method + is REQUIRED for all clients and Printers that support RFC 3995. The + Notification Recipient, acting as a client, fetches (pulls) Event + Notifications by using the Get-Notifications operation defined in + this document. + +Table of Contents + + 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2.1. Conformance Terminology . . . . . . . . . . . . . . . . 4 + 2.2. Other Terminology . . . . . . . . . . . . . . . . . . . 4 + 3. Model and Operation . . . . . . . . . . . . . . . . . . . . . 4 + 4. General Information . . . . . . . . . . . . . . . . . . . . . 5 + 5. Get-Notifications Operation . . . . . . . . . . . . . . . . . 7 + 5.1. Get-Notifications Request . . . . . . . . . . . . . . . 8 + 5.1.1. notify-subscription-ids (1setOf integer(1:MAX)) 8 + 5.1.2. notify-sequence-numbers (1setOf integer(1:MAX)) 9 + + + +Herriot, et al. Standards Track [Page 1] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + 5.1.3. notify-wait (boolean) . . . . . . . . . . . . . 10 + 5.2. Get-Notifications Response. . . . . . . . . . . . . . . 10 + 5.2.1. notify-get-interval (integer(0:MAX)). . . . . . 13 + 5.2.2. printer-up-time (integer(1:MAX)). . . . . . . . 14 + 6. Additional Information about Subscription Template Attributes 17 + 6.1. notify-pull-method (type2 keyword). . . . . . . . . . . 17 + 7. Subscription Description Attributes . . . . . . . . . . . . . 18 + 8. Additional Printer Description Attributes . . . . . . . . . . 18 + 8.1. ippget-event-life (integer(15:MAX)) . . . . . . . . . . 18 + 9. New Values for Existing Printer Description Attributes. . . . 19 + 9.1. notify-pull-method-supported (1setOf type2 keyword) . . 19 + 9.2. operations-supported (1setOf type2 enum). . . . . . . . 19 + 10. New Status Codes. . . . . . . . . . . . . . . . . . . . . . . 19 + 10.1. successful-ok-events-complete (0x0007) . . . . . . . . 20 + 11. Encoding and Transport. . . . . . . . . . . . . . . . . . . . 20 + 12. Conformance Requirements. . . . . . . . . . . . . . . . . . . 21 + 12.1. Conformance for IPP Printers . . . . . . . . . . . . . 21 + 12.2. Conformance for IPP Clients. . . . . . . . . . . . . . 22 + 13. Normative References. . . . . . . . . . . . . . . . . . . . . 23 + 14. Informative References. . . . . . . . . . . . . . . . . . . . 23 + 15. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 24 + 15.1. Attribute Registrations. . . . . . . . . . . . . . . . 24 + 15.2. Delivery Method and Additional Keyword Attribute Value + registrations for Existing Attributes. . . . . . . . . 24 + 15.3. Additional Enum Attribute Values . . . . . . . . . . . 25 + 15.4. Operation Registrations. . . . . . . . . . . . . . . . 25 + 15.5. Status Code Registrations. . . . . . . . . . . . . . . 25 + 16. Internationalization Considerations . . . . . . . . . . . . . 25 + 17. Security Considerations . . . . . . . . . . . . . . . . . . . 26 + 17.1. Notification Recipient Client Access Rights. . . . . . 26 + 17.2. Printer Security Threats . . . . . . . . . . . . . . . 27 + 17.3. Notification Recipient Security Threats. . . . . . . . 27 + 17.4. Security Requirements for Printers . . . . . . . . . . 27 + 17.5. Security Requirements for clients. . . . . . . . . . . 28 + 18. Description of Base IPP Documents (Informative) . . . . . . . 28 + 19. Contributors. . . . . . . . . . . . . . . . . . . . . . . . . 29 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 30 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 31 + +Table of Tables + + Table 1. Information about the Delivery Method. . . . . . . . . . 5 + Table 2. Combinations of "notify-wait", "status-code", and + "notify-get-interval". . . . . . . . . . . . . . . . . . 13 + Table 3. Attributes in Event Notification Content . . . . . . . . 15 + Table 4. Additional Attributes in Event Notification Content for + Job Events . . . . . . . . . . . . . . . . . . . . . . . 16 + + + + +Herriot, et al. Standards Track [Page 2] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + Table 5. Combinations of Events and Subscribed Events for "job- + impressions-completed" . . . . . . . . . . . . . . . . . 17 + Table 6. Additional Attributes in Event Notification Content for + Printer Events . . . . . . . . . . . . . . . . . . . . . 17 + Table 7. Operation-id Assignments . . . . . . . . . . . . . . . . 19 + Table 8. The "event-notification-attributes-tag" Value. . . . . . 21 + +1. Introduction + + This document describes an extension to the Internet Printing + Protocol/1.1: Model and Semantics [RFC 2911], [RFC 2910]. This + document specifies the 'ippget' Pull Delivery Method for use with the + "Internet Printing Protocol (IPP): Event Notifications and + Subscriptions" specification [RFC3995]. This IPPGET Delivery Method + is REQUIRED for all clients and Printers that support [RFC3995]. The + Notification Recipient, acting as a client, fetches (pulls) Event + Notifications by using the Get-Notifications operation defined in + this document. For a description of the base IPP documents, see + section 21 of this document. For a description of the IPP Event + Notification Model, see [RFC3995]. + + With this Pull Delivery Method, when an Event occurs, the Printer + saves the Event Notification for a period of time called the Event + Life. The Notification Recipient fetches (pulls) the Event + Notifications by using the Get-Notifications operation. This + operation causes the Printer to return all Event Notifications held + for the specified Subscription object(s). If the Notification + Recipient has selected the Event Wait Mode option to wait for + additional Event Notifications, the Printer MAY continue to return + Event Notifications to the Notification Recipient as asynchronous + Get-Notification responses as Events occur using the transaction + originated by the Notification Recipient. + + The Notification Recipient can terminate Event Wait Mode (without + closing the connection) by supplying the "notify-wait" (boolean) + attribute with a 'false' value in a subsequent Get-Notifications + request. Similarly, the Printer can terminate Event Wait Mode + (without closing the connection) by returning the "notify-get- + interval" (integer) operation attribute in a Get-Notifications + response that tells the Notification Recipient how long to wait + before trying again. + +2. Terminology + + This section defines the following terms that are used throughout + this document: + + + + + +Herriot, et al. Standards Track [Page 3] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + +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 as defined in [RFC2119] and [RFC2911], section 12.1. If + an implementation supports the extension defined in this document, + then these terms apply; otherwise, they do not. These terms define + conformance to this document only; they do not affect conformance to + other documents, unless it is explicitly stated otherwise. + +2.2. Other terminology + + This document uses the same terminology as [RFC2911], including + "client", "Printer", "Job", "attribute", "attribute value", + "keyword", "operation", "request", "response", and "support", with + the same meanings. This document also uses terminology defined in + [RFC3995], such as "Subscription (object)", "Notification Recipient", + "Event", "Event Notification", "Compound Event Notification", "Event + Life", and "Event Notification Attribute Group", with the same + meanings. In addition, this document defines the following terms for + use in this document: + + Event Wait Mode: The mode requested by a Notification Recipient + client in its Get-Notifications Request and granted by a Printer + to keep the connection open while the Printer sends subsequent + Get-Notification operation responses to the Notification + Recipient in the form of Event Notifications as they occur. + +3. Model and Operation + + In a Subscription Creation Operation, when the "notify-pull-method" + attribute is present and has the "ippget" keyword value, the client + is requesting that the Printer use the "ippget" Pull Delivery Method + for the Event Notifications associated with the new Subscription + Object. + + When an Event occurs, the Printer MUST generate an Event Notification + and MUST assign it the Event Life. The Printer MUST hold an Event + Notification for its assigned Event Life. + + When a Notification Recipient wants to receive Event Notifications + for a Subscription object, it performs the Get-Notifications + operation supplying the Subscription object's subscription-id, which + causes the Printer to return all un-expired Event Notifications held + for that Subscription object. If the Notification Recipient has + selected the Event Wait Mode option to wait for additional Event + Notifications, the response to the Get-Notifications request + continues indefinitely as the Printer continues to send Event + + + +Herriot, et al. Standards Track [Page 4] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + Notifications in the response as Events occur for that Subscription + object. + + 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 + MUST save Event Notifications for at least 15 seconds (see section + 8.1), the Notification Recipient is unlikely to miss any Event + Notifications that occur between the Subscription Creation and the + Get-Notifications operation. + + The 'ippget' Delivery Method is designed primarily for (1) a client + that wants to get Events (from the job's Per-Job Subscription object) + for a job that it has submitted and (2) a privileged client that + wants to get all job or printer Events from a Per-Printer + Subscription object. + +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 Requirement Delivery Method + Realization + + 1. What is the URL scheme name for the 'ippget' keyword method + Push Delivery Method, or the keyword name + method name for the Pull Delivery + Method? + + 2. Is the Delivery Method REQUIRED, REQUIRED + RECOMMENDED, or OPTIONAL for an IPP + Printer to support? + + 3. What transport and delivery protocols IPP with one new + does the Printer use to deliver the operation. + Event Notification Content; i.e., + what is the entire network stack? + + 4. Can several Event Notifications be Yes. + combined into a Compound Event + Notification? + + + + + + +Herriot, et al. Standards Track [Page 5] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + 5. Is the Delivery Method initiated by This Delivery Method is + the Notification Recipient (pull), a pull method with + or by the Printer (push)? aspects of a push + method, though the + Printer does not + initiate the operation. + + 6. Is the Event Notification content Machine Consumable. + Machine Consumable or Human + Consumable? + + 7. What section in this document answers Section 5. + the following questions? For a Machine + Consumable Event Notification, what is + the representation and encoding of + values defined in section 9.1 of + [RFC3995], and what are 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 + [RFC3995], and the conformance + requirements thereof? + + 8. What are the latency and reliability Same as IPP and the + of the transport and delivery underlying HTTP + protocol? transport. + + 9. What are the security aspects of the Same as IPP and the + transport and delivery protocol; underlying HTTP + e.g., how it is handled in transport and in the + firewalls? same direction, so no + new firewall + considerations. + + 10. What are the content length None. + restrictions? + + 11. What are the additional values or None. + pieces of information that a Printer + sends in an Event Notification content + and the conformance requirements + thereof? + + + + + + + +Herriot, et al. Standards Track [Page 6] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + 12. What are the additional Subscription None. + Template and/or Subscription + Description attributes and the + conformance requirements thereof? + + 13. What are the additional Printer "ipp-event-life" + Description attributes and the (integer (15: MAX)) + conformance requirements thereof? + +5. Get-Notifications Operation + + This operation is issued by a client acting in the role of a + Notification Recipient requesting the Printer to return all Event + Notifications held for the identified Subscription object(s). + + A Printer MUST support this operation, 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. + + When a Printer performs this operation, it MUST return all and only + those Event Notifications + + 1. whose associated Subscription Object's "notify-subscription-id" + Subscription Description attribute equals one of the values of + the "notify-subscription-ids" (1setOf integer(1:MAX)) operation + attribute AND + + 2. whose associated Subscription Object contains the "notify-pull- + method" attribute and it has the 'ippget' keyword value, AND + + 3. whose "notify-sequence-number" is equal to or greater than the + corresponding value of the "notify-sequence-numbers" (1setOf + integer(1:MAX)) operation attribute if supplied AND + + 4. whose Event Life has not yet expired AND + + 5. where the Notification Recipient client has read-access rights to + the identified Subscription Object (see Access Rights paragraph + below). + + The Notification Recipient client MUST either (a) request Event Wait + Mode by supplying the "notify-wait" operation attribute with a 'true' + value or (b) suppress Event Wait Mode by omitting the "notify-wait" + operation attribute or by supplying it with a 'false' value. To + terminate Event Wait Mode subsequently, the Notification Recipient + client MUST close the connection. To terminate Event Wait Mode, the + Printer MUST either (a) return the "notify-get-interval" operation + + + +Herriot, et al. Standards Track [Page 7] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + attribute in a Get-Notifications response (RECOMMENDED behavior) or + (b) close the connection. The "notify-get-interval" operation + attributes tell the Notification Recipient how long to wait before + trying a subsequent Get-Notifications request. + + Access Rights: The authenticated user (see [RFC2911], section 8.3) + performing this operation MUST be (1) the owner of each Subscription + Object identified by the "notify-subscription-ids" operation + attribute (see section 5.1.1), (2) an operator or administrator of + the Printer (see [RFC2911], sections 1 and 8.5), or (3) otherwise + authorized by the Printer's administrator-configured security policy + to request Event Notifications from the target Subscription + Object(s). Otherwise, the IPP Printer MUST reject the operation and + return: 'client-error-forbidden', 'client-error-not-authenticated', + or 'client-error-not-authorized' status code, as appropriate. + Furthermore, the Printer's security policy MAY limit the attributes + returned by the Get-Notifications operation, in a manner similar to + that of the Get-Job-Attributes operation (see [RFC2911], end of + section 3.3.4.2). + +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 that 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. + +5.1.1. notify-subscription-ids (1setOf integer(1:MAX)) + + This attribute identifies one or more Subscription objects for which + Events are requested. The client MUST supply this attribute with at + least one value. The Printer object MUST support this attribute with + multiple values. + + If no Subscription Object exists with the supplied identifier, or if + the identified Subscription Object does not contain the "notify- + + + +Herriot, et al. Standards Track [Page 8] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + pull-method" attribute with the 'ippget' keyword value, the Printer + MUST return the 'client-error-not-found' status code. + + Note: The name of both the "notify-subscription-ids" and + "notify-sequence-numbers" end in 's', as they are multi-valued. + However, there are other occurrences of these attribute names + without the 's' that are single valued. + +5.1.2. notify-sequence-numbers (1setOf integer(1:MAX)) + + This attribute specifies one or more of the lowest Event Notification + sequence number values for the Subscription objects identified by the + corresponding values of the "notify-subscription-ids" operation + attribute. The Notification Recipient SHOULD supply this attribute, + and the number of values SHOULD be the same as that of the "notify- + subscriptions-ids" attribute. The Printer MUST support this + attribute with multiple values. + + The Printer MUST NOT return Notification Events with lower sequence + numbers for the corresponding Subscription object. Therefore, by + supplying the proper values for this attribute the Notification + Recipient can prevent getting the same Event Notifications from a + Subscription object that were returned on a previous Get- + Notifications request. The Notification Recipient SHOULD remember + the highest "notify-sequence-number" value returned for each + Subscription object requested and SHOULD pass that value for each + requested Subscription object on the next Get-Notifications request. + + If the Notification Recipient supplies fewer values for this + attribute (including omitting this attribute) than it does for the + "notify-subscription-ids" operation attribute, the Printer assumes a + '1' value for each missing value. A value of '1' causes the Printer + to return any un-expired Event Notification for that Subscription + object, as '1' is the lowest possible sequence number. If the + Notification Recipient supplies more values for this attribute than + the number of values for the "notify-subscription-ids" operation + attribute, the Printer ignores the extra values. + + Note: If a Notification Recipient performs two consecutive Get- + Notifications operations with the same value for "notify-sequence- + number" (or omits the attribute), the time stamp value of the first + Event Notification in the second Get-Notifications Response may be + less than that of the time stamp of the last Event Notification in + the first Get-Notification Response. This happens because the + Printer sends all unexpired Event Notifications with an equal or + higher sequence number according to the ordering specified in + [RFC3995], and some Event Notifications from the first Get- + + + + +Herriot, et al. Standards Track [Page 9] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + Notifications operation may not have expired by the time the second + Get-Notifications operation occurs. + +5.1.3. notify-wait (boolean) + + This value indicates whether the Notification Recipient wants Event + Wait Mode. The client MAY supply this attribute. The Printer object + MUST support both values of this attribute. + + If the client supplies the 'false' value or omits this attribute, the + client is not requesting Event Wait Mode. If the value is 'true', + the client is requesting Event Wait Mode. See the beginning of + section 5.2 for the rules for Event Wait Mode. + +5.2. Get-Notifications Response + + The Printer has the following options for responding to a Get- + Notifications Request: + + 1. The Printer can reject the request and return the 'server-error- + busy' status code if the Printer is too busy to accept this + operation at this time. In this case, the Printer MUST return + the "get-notify-interval" operation attribute to indicate when + the client SHOULD try again. + + 2. If the Notification Recipient did not request Event Wait Mode + ("notify-wait-mode" = 'false' or omitted), the Printer MUST + immediately return whatever Event Notifications it currently + holds in the requested Subscription object(s) and MUST return the + "notify-get-interval" operation attribute with the number of + seconds from now, at which the Notification Recipient SHOULD + repeat the Get-Notifications Request to get future Event + Notifications. + + 3. If the Notification Recipient requested Event Wait Mode + ("notify-wait-mode" = 'true'), the Printer MUST immediately + return whatever Event Notifications it currently holds in the + requested Subscription object(s) and MUST continue to return + Event Notifications as they occur until all the requested + Subscription Objects are canceled. A Subscription Object is + canceled either via the Cancel-Subscription operation or by the + Printer (e.g., the Subscription Object is canceled when the + associated Job completes and is no longer in the Job Retention or + Job History phase; see the "ippget-event-life (integer(15:MAX))" + attribute discussion in section 8.1). + + However, the Printer MAY decide to terminate Event Wait Mode at + any time, including in the first response. In this case, the + + + +Herriot, et al. Standards Track [Page 10] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + Printer MUST return the "notify-get-interval" operation + attribute. This attribute indicates that the Printer wishes to + leave Event Wait Mode and the number of seconds in the future + that the Notification Recipient SHOULD try the Get-Notifications + operation again. The Notification Recipient MUST accept this + response and MUST disconnect. If the Notification Recipient does + not disconnect, the Printer SHOULD do so. + + 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 Group per Event Notification + that the Printer is holding. After the initial burst of data, if the + Notification Recipient has selected the Event Wait Mode 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 attribute is encoded by 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. See section 11 for the encoding and transport + rules. + + 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-xxx', the Printer MUST + NOT return any Event Notification Attribute groups. The + following are descriptions of the important status codes: + + successful-ok: The response contains all Event Notification + associated with the specified subscription-ids that had + been supplied in the "notify-subscription-ids" operation + attribute in the request. If the requested Subscription + Objects have no associated Event Notification, the + response MUST contain zero Event Notifications. + + + + +Herriot, et al. Standards Track [Page 11] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + successful-ok-events-complete: Indicates when this return + is the last return for all Subscription objects that + match the request, whether or not Event Notifications are + returned. This condition occurs for Event Wait Mode with + Notification Recipients waiting for responses when (1) + the Subscription Object is canceled with a Cancel- + Subscription operation, (2) the Subscription Object is + deleted, when the Per-Printer Subscription lease time + expires, or (3) the 'job-completed' event occurs for a + Per-Job Subscription. This condition also occurs for a + Get-Notifications request that a Notification Recipient + makes after the job completes, but before the Event Life + expires. See section 10.1. + client-error-not-found: The Printer has no Subscription + Objects whose "notify-subscription-id" attribute equals + any of the values of the "notify-subscription-ids" + operation attribute supplied, or the identified + Subscription Object does not contain the "notify-pull- + method" attribute with the 'ippget' keyword value. + server-error-busy: The Printer is too busy to accept this + operation. The Printer SHOULD return the "notify-get- + interval" operation attribute in the Operation Attributes + of the response; then the Notification Recipient SHOULD + wait for the number of seconds specified by the "notify- + get-interval" operation attribute before performing this + operation again. If the "notify-get-interval" Operation + Attribute is not present, the Notification Recipient + SHOULD use the normal network back-off algorithms to + determine when to perform this operation again. + + Natural Language and Character Set: + The "attributes-charset" and "attributes-natural-language" + attributes, as described in [RFC2911], section 3.1.4.2. + + 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 + + + +Herriot, et al. Standards Track [Page 12] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + is critical because a bad choice may leave it unable to send + some 'text' and 'name' values accurately. + +5.2.1. notify-get-interval (integer(0:MAX)) + + The value of this operation attribute is the number of seconds that + the Notification Recipient SHOULD wait before trying the Get- + Notifications operation again. The Printer MUST return this + operation attribute if (1) it is too busy to return events, (2) the + Notification Recipient client did not request Event Wait Mode, or (3) + the Printer is terminating Event Wait Mode. The client MUST accept + this attribute and SHOULD reissue the Get-Notifications operation + (with or without "notify-wait" = 'true') at the indicated number of + seconds in the future in order to get more Event Notifications This + value is intended to help the client be a good network citizen. + + The value of this attribute MUST be at least as large as that of the + Printer's "ippget-event-life" Printer Description attribute (see + section 8.1). The Printer MAY return a value that is larger than + that of the "ippget-event-life" Printer Description attribute + provided that the Printer increases the Event Life for this + Subscription object so that Notification Recipients taking account of + the larger value and polling with a longer interval will not miss + events. Note: Implementing such an algorithm requires some hidden + attributes in the Subscription object that are IMPLEMENTATION + DEPENDENT. + + If the Printer wants to remain in Event Wait Mode, then the Printer + MUST NOT return this attribute in the response. + + Here is a complete table of combinations of "notify-wait", "status- + code", "notify-get-interval", and Event Notification Attributes + Groups for Get-Notification initial (Wait and No Wait) Responses and + subsequent Event Wait Mode Responses (which may stay in Event Wait + Mode or may request the Notification Recipient to leave Event Wait + Mode): + + Table 2. Combinations of "notify-wait", "status-code", and + "notify-get-interval" + + Client sends: Printer returns: Printer Event + returns: Notification + "notify-wait" "status-code" "notify-get- Attribute + interval" Groups + + 1. 'false'* 'successful-ok' MUST return N maybe + 2. 'false'* 'not-found' MUST NOT MUST NOT + 3. 'false'* 'busy' MUST return N MUST NOT + + + +Herriot, et al. Standards Track [Page 13] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + 4. 'false'* 'events- MUST NOT 'job- + complete' completed' + 5. 'true' 'successful-ok' MUST NOT MUST + 6. 'true' 'successful-ok' MUST return N maybe + 7. 'true' 'not-found' MUST NOT MUST NOT + 8. 'true' 'busy' MUST return N MUST NOT + 9. 'true' 'events- MUST NOT 'job- + complete' completed' or + maybe other + * 'false' or client omits the "notify-wait" attribute. + + Explanation: + + 1-4: Client does not request Event Wait Mode. + 5-9: Client requests Event Wait Mode. + 2,7: Subscription object not found, or was canceled earlier; + client should NOT try again. + 3,8: Server busy, tells client to try later; client should try + again in N seconds. + 4: Client polled after job completed, but before Event Life + expired, and got the 'job-completed' event, so the client + shouldn't bother trying again; client should NOT try + again later. + 5: Printer returns one or more Event Notifications and is OK + to stay in Event Wait Mode; the client waits for more + Event Notifications to be returned. + 6: Printer wants to leave Event Wait mode. Can happen on + the first response (with or without Event Notifications) + or happen on a subsequent response with or without Event + Notifications; the client SHOULD try again in N seconds. + 9: Either (1) the printer returns 'job-completed' event, or + (2) the Subscription Object was canceled by either a + Cancel-Job or a Per-Printer Subscription expired without + being renewed. For case (1), at least one Event + Notification MUST be returned; for case (2), it is + unlikely that any Event Notifications are returned, and + the client should NOT try again. + +5.2.2. printer-up-time (integer(1:MAX)) + + The value of this attribute is the Printer's "printer-up-time" + attribute at the time when the Printer sends this response. The + Printer MUST return this attribute. 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. + + + + +Herriot, et al. Standards Track [Page 14] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + Group 2: Unsupported Attributes + See [RFC2911], section 3.1.7, for details on returning + Unsupported Attributes. + + Group 3 through N: Event Notification Attributes + The Printer responds with one Event Notification Attributes + Group per matched Event Notification. The entire response is + considered a single Compound Event Notification (see + [RFC3995]). The matched Event Notifications are all un-expired + Event Notifications associated with the matched Subscription + Objects and MUST follow the "Event Notification Ordering" + requirements for Event Notifications within a Compound Event + Notification specified in [RFC3995] section 9. In other words, + the Printer MUST order these Event Notification groups in + ascending time stamp (and sequence number) order for a + Subscription object. If Event Notifications for multiple + Subscription objects are being returned, the Notification + Events for the next Subscription object follow in ascending + time stamp order, etc. + + Each Event Notification Group MUST contain all of attributes + specified in section 9.1 ("Content of Machine Consumable Event + Notifications") of [RFC3995], with exceptions denoted by + asterisks in the tables below. + + The tables below are identical to those in section 9.1 + ("Content of Machine Consumable Event Notifications") of + [RFC3995], except that each cell in the "Sends" column is a + "MUST". + + If more than one Event Notification is being returned and the + status of each is not the same, then the Printer MUST return a + "notify-status-code" attribute in each Event Notification + Attributes group to indicate the differing status values. + + For an Event Notification for all Events, the Printer includes + the attributes shown in Table 3. + + 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(1:MAX)) * MUST Printer + printer-current-time (dateTime) MUST ** Printer + + + +Herriot, et al. Standards Track [Page 15] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + 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 + + * As specified in [RFC3995] section 9, the value of the + "printer-up-time" attribute sent in each Event Notification + MUST be the time at which the Event occurred, not the time at + which the Event Notification was sent. + + ** 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 + 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 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 (integer(0:MAX)) MUST * Job + + + + + + + +Herriot, et al. Standards Track [Page 16] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + * 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 includes + the additional attributes shown in Table 6. + + 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 + +6. Additional Information about Subscription Template Attributes + + The 'ippget' Delivery Method does not define any addition + Subscription Template attributes and has the conformance requirements + for Subscription Template attributes defined in [RFC3995]. This + section defines additional information about Subscription Template + attributes defined in [RFC3995]. + +6.1. notify-pull-method (type2 keyword) + + This Subscription Template attribute identifies the Pull Delivery + Method to be used for the Subscription Object (see [RFC3995]). To + support the 'ippget' Pull Delivery Method defined in this document, + the Printer MUST support this attribute with the following keyword + value: + + 'ippget': Indicates that the 'ippget' Pull Delivery Method is to + be used for this Subscription Object. + + + + + + + +Herriot, et al. Standards Track [Page 17] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + +7. Subscription Description Attributes + + The 'ippget' Delivery Method has the conformance requirements for + Subscription Description attributes defined in [RFC3995]. The + 'ippget' Delivery Method does not define any addition Subscription + Description attributes. + +8. Additional Printer Description Attributes + + This section defines additional Printer Description attributes for + use with the 'ippget' Delivery Method. + +8.1. ippget-event-life (integer(15:MAX)) + + This Printer Description attribute specifies the Event Life value + that the Printer assigns to each Event; i.e., the number of seconds + after an Event occurs during which a Printer will return that Event + in an Event Notification in a Get-Notifications response. After the + Event Life expires for the Event, the Printer MAY no longer return an + Event Notification for that Event in a Get-Notifications response. + + The Printer MUST support this attribute if it supports the 'ippget' + Delivery Method. The value MUST be 15 or more (at least 15 seconds), + and 60 (seconds) is the RECOMMENDED value to align with the PWG Job + Monitoring MIB [RFC2707] jmGeneralJobPersistence and + jmGeneralAttributePersistence objects. + + For example, assume the following: + + 1. A client performs a Job Creation operation that creates a + Subscription Object associated with the 'ippget' Delivery Method; + + 2. An Event associated with the new Job occurs immediately after the + Subscription Object is created; + + 3. the same client or some other client performs a Get-Notifications + operation so that the client is connected N seconds after the Job + Creation operation. + + Then, if N is less than the value of this attribute, the client(s) + performing the Get-Notifications operations can expect not to miss + any Event-Notifications, barring some unforeseen lack of memory space + in the Printer. Note: The client MUST initiate the Get- + Notifications at a time that is sufficiently less that N seconds to + account for network latency so that it is connected to the Printer + before N seconds elapses. + + + + + +Herriot, et al. Standards Track [Page 18] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + If a Printer supports the 'ippget' Delivery Method, it MUST keep + 'completed', 'canceled', or 'aborted' Job objects in the Job + Retention and/or Job History phases for at least as long as this + attribute's value. The Printer MAY retain jobs longer that this + value. See [RFC2911], section 4.3.7.1, and the discussion in + [RFC3995] (regarding the 'job-completed' event). The latter explains + that a Notification Recipient can query the Job after receiving a + 'job-completed' Event Notification in order to find out other + information about the job that is 'completed', 'aborted', or + 'canceled'. However, this attribute has no effect on the Cancel- + Subscription operation, which deletes the Subscription object + immediately whether or not it contains the "notify-pull-method" + attribute with the 'ippget' keyword value. Immediately thereafter, + subsequent Get-Notifications Responses MUST NOT contain Event + Notifications associated with the canceled Subscription object. + +9. New Values for Existing Printer Description Attributes + + This section defines additional values for existing Printer + Description attributes as defined in [RFC3995]. + +9.1. notify-pull-method-supported (1setOf type2 keyword) + + The following keyword value for the "notify-pull-method-supported" + attribute is added in order to support the new Delivery Method + defined in this document: + + 'ippget': The IPP Notification Pull Delivery Method defined in + this document. + +9.2. operations-supported (1setOf type2 enum) + + Table 7 lists the "operation-id" value defined in order to support + the new Get-Notifications operation defined in this document. + + Table 7. Operation-id Assignments + + Value Operation Name + + 0x001C Get-Notifications + +10. New Status Codes + + The following status code is defined as an extension for this + Delivery Method and is returned as the status code of the Get- + Notifications operation in Group 1 or Group 3 to N (see section 5.2). + + + + + +Herriot, et al. Standards Track [Page 19] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + +10.1. successful-ok-events-complete (0x0007) + + The Printer MUST return the 'successful-ok-events-complete' status + code to indicate when this Get-Notifications response is the last + response for a Subscription object, whether or not there are Event + Notifications being returned. This condition occurs for Event Wait + Mode with Notification Recipients waiting for responses when (1) the + Subscription Object is canceled with a Cancel-Subscription operation, + (2) the Subscription object is deleted, when the Per-Printer + Subscription lease time expires, or (3) the 'job-completed' event + occurs for a Per-Job Subscription. This condition also occurs for a + Get-Notifications request that a Notification Recipient makes after + the job completes, but before the Event Life expires. + +11. Encoding and Transport + + This section defines the encoding and transport considerations for + this Delivery Method based on [RFC2910]. + + The encoding of a Get-Notifications Response is modeled after the + Get-Jobs Response (see [RFC2911]). In a Get-Notifications Response, + each Event Notification Attributes Group MUST start with an 'event- + notification-attributes-tag' (see the section "Encodings of + Additional Attribute Tags" in [RFC3995]), and end with an 'end-of- + attributes-tag'. In addition, for Event Wait Mode the multi- + part/related is used to separate each multiple response (in time) to + a single Get-Notifications Request. + + The Printer returns Get-Notification Response as follows: + + 1. If the Notification Recipient client did not request Event Wait + Mode ("notify-wait" = 'false' or omitted), the Printer ends the + response with an 'end-of-attributes-tag' (see [RFC2911], Get-Jobs + encoding), as with any operation response. + + 2. If the Notification Recipient client requests Event Wait Mode + ("notify-wait" = 'true') and the Printer wishes to honor the + request, the Printer MUST return the response as an + application/ipp part inside a multi-part/related MIME media type. + When one or more additional Events occur, the Printer returns + each as an additional Event Notification Group using a separate + application/ipp part under the multi-part/related type. + + 3. If the client requested Event Wait Mode ("notify-wait" = 'true'), + but the Printer does not wish to honor the request in the initial + response and wants the client explicitly polled for Event + Notifications, the Printer MUST return the "notify-get-interval" + operation attribute (see section 5.2.1). The Printer returns the + + + +Herriot, et al. Standards Track [Page 20] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + response as an application/ipp part that MAY be inside an multi- + part/related type. The client MUST accept this response and + reissue the Get-Notifications request in the future indicated by + the value of the "notify-get-interval" attribute value. + + 4. If the client requested Event Wait Mode ("notify-wait" = 'true'), + and the Printer initially honored the request but later wishes to + leave Event Wait Mode, the Printer MUST return the "notify-get- + interval" operation attribute (see section 5.2.1). The Printer + returns the response as an application/ipp part that MUST be + inside an multi-part/related type. + + NOTE: If a Notification Recipient fails to receive a response, it + can ask the Printer for the same Event Notifications again. The + Notification Recipient will receive the same Event Notifications that + it should have received the first time, except for those Event + Notifications that have expired in the meantime. + + The Printer MAY chunk the responses, but this has no significance to + the IPP semantics. + + This notification delivery method uses the IPP transport and encoding + [RFC2910] for the Get-Notifications operation with the following + extension, allocated in [RFC3995]: + + Table 8. The "event-notification-attributes-tag" Value + + Tag Value (Hex) Meaning + + 0x07 "event-notification-attributes-tag" + +12. Conformance Requirements + + This section lists the conformance requirements for clients and + Printers. + +12.1. Conformance for IPP Printers + + It is OPTIONAL for a Printer to support IPP Notifications as defined + in [RFC3995]. However, if a Printer supports IPP Notifications, the + Printer MUST support the 'ippget' Delivery Method, as defined in this + document, as one of its Delivery Methods. IPP Printers that conform + to this specification + + 1. MUST meet the conformance requirements defined in [RFC3995] for a + Pull Delivery Method; + + + + + +Herriot, et al. Standards Track [Page 21] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + 2. MUST support the Get-Notifications operation defined in section + 5, including Event Wait Mode; + + 3. MUST support the Subscription Template object attributes, as + defined in section 6; + + 4. MUST support the Subscription Description object attributes, as + defined in section 7; + + 5. MUST support the "ippget-event-life" Printer Description + attribute defined in section 8.1, including retaining jobs in the + Job Retention and/or Job History phases for at least as long as + the value specified by the Printer's "ippget-event-life"; + + 6. MUST support the additional values for IPP/1.1 Printer + Description attributes defined in section 9; + + 7. MUST support the 'successful-ok-events-complete' status code, as + described in section 10.1; + + 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; and + + 10. MUST meet the security conformance requirements stated in section + 18.4. + +12.2. Conformance for IPP Clients + + It is OPTIONAL for an IPP Client to support IPP Notifications as + defined in [RFC3995]. However, if a client supports IPP + Notifications, the client MUST support the 'ippget' Delivery Method + as defined in this document as one of its Delivery Methods. IPP + Clients that conform to this specification: + + 1. MUST create Subscription Objects by sending Subscription Creation + operation requests containing the "notify-pull-method" attribute + (as opposed to the "notify-recipient-uri" attribute) using the + 'ippget' keyword value (see sections 6.1 and 15.2); + + 2. MUST send IPP Get-Notifications operation requests (see section + 5.1) via the port specified in the associated 'ipp' URL (if + present) or otherwise via IANA-assigned well-known port 631; + + + + +Herriot, et al. Standards Track [Page 22] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + 3. MUST convert the associated 'ipp' URLs for use in IPP Get- + Notifications operation to their corresponding 'http' URL forms + for use in the HTTP layer, according to the rules in section 5, + "IPP URL Scheme", in [RFC2910]; and + + 4. MUST meet the security conformance requirements stated in section + 18.5. + +13. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [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. + + [RFC3995] Herriot, R. and T. Hastings, "Internet Printing Protocol + (IPP): Event Notifications and Subscriptions", RFC 3995, + March 2005. + +14. Informative References + + [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, F., "Design Goals for an Internet Printing + Protocol", RFC 2567, April 1999. + + [RFC2568] Zilles, S., "Rationale for the Structure of the 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. + + + + + + +Herriot, et al. Standards Track [Page 23] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + [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. + + [RFC2707] Bergman, R., Hastings, T., Isaacson, S., and H. Lewis, + "Job Monitoring MIB - V1.0", RFC 2707, November 1999. + + [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C., and H. + Holst, "Internet Printing Protocol/1.1: Implementor's + Guide", RFC 3196, November 2001. + + [RFC3997] Hastings, T., Ed., deBry, R., and H. Lewis, "Internet + Printing Protocol (IPP): Requirements for IPP + Notifications", RFC 3997, March 2005. + +15. IANA Considerations + + This section contains the exact information that the IANA has added + to the IPP Registries according to the procedures defined in + [RFC2911], section 6. These registrations have been published in the + http://www.iana.org/assignments/ipp-registrations registry. + +15.1. Attribute Registrations + + The following table lists the attributes defined in this document. + This has been registered according to the procedures in RFC 2911 + [RFC2911] section 6.2. + + Printer Description attributes: Reference Section + ------------------------------- --------- ------- + ippget-event-life (integer(15:MAX)) [RFC3996] 8.1 + +15.2. Delivery Method and Additional Keyword Attribute Value + Registrations for Existing Attributes + + This section lists additional keyword attribute value registrations + for use with existing attributes defined in other documents. These + have been registered according to the procedures in [RFC2911], + section 6.1. According to [RFC3995], section 24.7.3, Pull Delivery + Method registrations are the keyword attribute value registrations + for the "notify-pull-method" and "notify-pull-method-supported" + attributes. + + + + + + + + + +Herriot, et al. Standards Track [Page 24] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + Attribute (attribute syntax) + Values Reference Section + ----------------------- --------- ------- + notify-pull-method (type2 keyword) [RFC3995] 5.3.2 + notify-pull-method-supported (1setOf type2 keyword) + [RFC3995] 5.3.2.1 + ippget [RFC3996] 9.1 + +15.3. Additional Enum Attribute Values + + The following table lists the enum attribute values defined in this + document. These have been registered according to the procedures in + [RFC2911], section 6.1. + + Attribute (attribute syntax) + Value Name Reference Section + ------ ----------------------------- --------- ------- + operations-supported (1setOf type2 enum) [RFC2911] 4.4.15 + 0x001C Get-Notifications [RFC3996] 9.2 + +15.4. Operation Registrations + + The following table lists the operations defined in this document. + This has been registered according to the procedures in RFC 2911 + [RFC2911] section 6.4. + + Operations: Reference Section + ----------- --------- ------- + Get-Notifications [RFC3996] 5 + +15.5. Status Code Registrations + + The following table lists the status codes defined in this document. + This has been registered according to the procedures in [RFC2911], + section 6.6. + + Status codes: Reference Section + ------------- --------- ------- + successful-ok-events-complete (0x0007) [RFC3996] 10.1 + +16. Internationalization Considerations + + The IPP Printer MUST localize the "notify-text" attribute as + specified in section 14 of [RFC3995]. + + + + + + + +Herriot, et al. Standards Track [Page 25] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + 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. + +17. Security Considerations + + The IPP Model and Semantics document [RFC2911, section 8] discusses + high-level security requirements (Client Authentication, Server + Authentication and Operation Privacy). The IPP Transport and + Encoding document [RFC2910, section 8] discusses the security + requirements for the IPP protocol. 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 'ippget' Delivery Method with its Get-Notifications operations + leverages the security mechanism that are used in IPP/1.1 [RFC2910 + and RFC2911] without adding any additional security mechanisms in + order to maintain the same security support as IPP/1.1. + + The access control model for the Get-Notifications operation defined + in this document is the same as the access control model for the + Get-Job-Attributes operation (see [RFC2911], section 3.2.6). The + primary difference is that a Get-Notifications operation is directed + at Subscription Objects rather than at Job objects, and a returned + attribute group contains Event Notification attributes rather than + Job object attributes. + +17.1. Notification Recipient Client Access Rights + + The Notification Recipient client MUST have the following access + rights to the Subscription object(s) targeted by the Get- + Notifications operation request: + + The authenticated user (see [RFC2911], section 8.3) performing + this operation MUST be (1) the owner of each Subscription Object + identified by the "notify-subscription-ids" operation attribute + (see section 5.1.1), (2) an operator or administrator of the + Printer (see [RFC2911], sections 1 and 8.5), or (3) otherwise + authorized by the Printer's administrator-configured security + policy to request Event Notifications from the target Subscription + Object(s). Furthermore, the Printer's security policy MAY limit + + + + + + +Herriot, et al. Standards Track [Page 26] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + the attributes returned by the Get-Notifications operation, in a + manner similar to that of the Get-Job-Attributes operation (see + [RFC2911], end of section 3.3.4.2). + +17.2. Printer Security Threats + + Because the Get-Notifications operation is sent in the same direction + as are Job Creation operations, usually by the same client, this + Event Notification Delivery Method poses no additional + authentication, authorization, privacy, firewall, or port assignment + issues above those for the IPP Get-Job-Attributes and Get-Printer- + Attributes operations (see [RFC2911], sections 3.2.6 and 3.2.5). + +17.3. Notification Recipient Security Threats + + Unwanted Events Notifications (spam): Unlike Push Event Notification + Delivery Methods in which the IPP Printer initiates the Event + Notification, with the Pull Delivery Method defined in this document, + the Notification Recipient is the client that initiates the Get- + Notifications operation (see section 5). Therefore, with this method + there is no chance of "spam" notifications. + + Note: When a client stays connected to a Printer by using the Event + Wait Mode (see section 5.1.3) in order to receive Event Notifications + as they occur, it can close down the IPP connection at any time and + so can avoid future unwanted Event Notifications at any time. + + It is true that the client has control over whether to ask for Event + Notifications. However, if the client subscribes to an event and + does a Get-Notifications request, it gets all events for the + Subscription Object in the sequence number range (see section 5.1.2), + not just those it wants. If a client subscribes to a Per-Printer + Subscription job event, such as 'job-completed', and someone then + starts and cancels thousands of jobs, the client would have to + receive these events in addition to those it is interested in. A + client can protect itself better by subscribing to its own jobs by + using a Per-Job Subscription, rather than create a Per-Printer + subscription whose Job events apply to all jobs. + +17.4. Security Requirements for Printers + + For the Get-Notifications operation defined in this document, the + same Printer conformance requirements apply for supporting and using + Client Authentication, Server Authentication and Operation Privacy as + stated in [RFC2910] section 8 for all IPP operations. + + + + + + +Herriot, et al. Standards Track [Page 27] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + +17.5. Security Requirements for Clients + + For the Get-Notifications operation defined in this document, the + same client conformance requirements apply for supporting and using + Client Authentication, Server Authentication, and Operation Privacy + as stated in [RFC2910], section 8, for all IPP operations. + +18. Description of Base IPP Documents (Informative) + + The base set of IPP documents includes the following: + + 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 [RFC3196] + Mapping between LPD and IPP Protocols [RFC2569] + + "Design Goals for an Internet Printing Protocol" takes a broad look + at distributed printing functionality, and it enumerates real-life + scenarios that help 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 [RFC2566, RFC2565]. A few OPTIONAL operator operations have + been added to IPP/1.1. + + "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. + + "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. + + "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 [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 the 'ipp' scheme for identifying IPP printers and jobs. + + + +Herriot, et al. Standards Track [Page 28] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + + "Internet Printing Protocol/1.1: Implementer's Guide" 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. + + "Mapping between LPD and IPP Protocols" gives some advice to + implementers of gateways between IPP and LPD (Line Printer Daemon) + implementations. + +19. Contributors + + Carl Kugler and Harry Lewis contributed the basic idea of in-band + "smart polling" coupled with multiple responses for a single + operation on the same connection, with one response for each event as + it occurs. Without their continual persuasion, we would not have + arrived at this Delivery Method specification and would not have been + able to agree on a single REQUIRED Delivery Method for IPP. + + Carl Kugler + IBM Corporation + 6300 Diagonal Highway + Boulder, CO 80301 + + EMail: kugler@us.ibm.com + + + + + + + + + + + + + + + + + + + + + + + + +Herriot, et al. Standards Track [Page 29] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + +Authors' Addresses + + Robert Herriot + Global Workflow Solutions + 706 Colorado Ave. + Palo Alto, CA 94303 + + Phone: 650-324-4000 + EMail: bob@herriot.com + + + Thomas N. Hastings + Xerox Corporation + 710 S Aviation Blvd. ESAE 242 + El Segundo CA 90245 + + Phone: 310-333-6413 + Fax: 310-333-6342 + EMail: hastings@cp10.es.xerox.com + + + Harry Lewis + IBM Corporation + 6300 Diagonal Hwy + Boulder, CO 80301 + + Phone: (303) 924-5337 + EMail: harryl@us.ibm.com + + + + + + + + + + + + + + + + + + + + + + + +Herriot, et al. Standards Track [Page 30] + +RFC 3996 IPP: The 'ippget' Delivery Method March 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM 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. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights 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; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat 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 on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Herriot, et al. Standards Track [Page 31] + diff --git a/standards/rfc3997.txt b/standards/rfc3997.txt new file mode 100644 index 000000000..3dc0e1eb5 --- /dev/null +++ b/standards/rfc3997.txt @@ -0,0 +1,955 @@ + + + + + + +Network Working Group T. Hastings, Ed. +Request for Comments: 3997 Xerox Corporation +Category: Informational R. K. deBry + Utah Valley State College + H. Lewis + IBM Corporation + March 2005 + + + Internet Printing Protocol (IPP): + Requirements for IPP Notifications + +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 (2005). + +Abstract + + This document is one of a set of documents that together describe all + aspects of the 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 an optional part of an IPP + Service. + +Table of Contents + + 1. Introduction. . . . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Terminology . . . . . . . . . . . . . . . . . . . . . . . . . 2 + 3. Scenarios . . . . . . . . . . . . . . . . . . . . . . . . . . 6 + 4. Requirements. . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5. Security Considerations for IPP Notifications Requirements. . 12 + 6. Internationalization Considerations . . . . . . . . . . . . . 13 + 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 13 + 8. References. . . . . . . . . . . . . . . . . . . . . . . . . . 14 + 8.1. Normative References. . . . . . . . . . . . . . . . . . 14 + 8.2. Informative References. . . . . . . . . . . . . . . . . 14 + 9. Appendix A: Description of the Base IPP Documents . . . . . . 15 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 16 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 17 + + + +Hastings, et al. Informational [Page 1] + +RFC 3997 IPP: Notification Requirements March 2005 + + +1. Introduction + + This document is one of a set of documents that together describe all + aspects of the 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 an optional part of an IPP + Service. See section 10 for a description of the base IPP documents. + + The scope of this requirements document covers functionality used by + the following kinds of IPP Users: End Users, Print Administrators, + and Operators. See [RFC3995] for the extensions to the Internet + Printing Protocol/1.0 (IPP) [RFC2565], [RFC2566], IPP/1.1 [RFC2911], + [RFC2910], and future versions. + +2. Terminology + + It is necessary to define a set of terms 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, that 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. + + + + +Hastings, et al. Informational [Page 2] + +RFC 3997 IPP: Notification Requirements March 2005 + + +2.5. Security Domain + + For the purposes of this discussion, the set of network components + that can communicate without going through a proxy or firewall. A + security domain may be geographically very large; for example, + anywhere within example.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. + +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, and the person whom 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, 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 + XYZ'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. The Job Recipient + Proxy physically picks up the printed document from the Printer if + the Job Recipient cannot do so. 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 a Job- + Submitting End User and a 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. + + + + + +Hastings, et al. Informational [Page 3] + +RFC 3997 IPP: Notification Requirements March 2005 + + +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, a + Job-Submitting Application, a Job Recipient, a Job Recipient Proxy, + an Operator, an Administrator, etc., and his or her representative, + log file, usage statistics-gathering application, or other active or + passive entities. + +2.12. Notification Recipient Agent + + A program that 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 + + An Event is an 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 by 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 an event occurs. + + + + + + + + +Hastings, et al. Informational [Page 4] + +RFC 3997 IPP: Notification Requirements March 2005 + + +2.16. Notification Attributes + + IPP Objects (for example, a print job) from which notification are + being sent may have associated attributes. A user may want to have + one or more of these returned along with a particular notification. + In general, these may include any attribute associated with the + object emitting the notification. Examples include the following: + + 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 + 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 by using a Delivery Method. An + example of a Delivery Method is email. + +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 that are not necessarily delivered to Notification + Recipients immediately but are queued for delivery by an intermediate + network application, for later retrieval. Email is an example of a + store-and-forward notification delivery method. + + + + + + + + +Hastings, et al. Informational [Page 5] + +RFC 3997 IPP: Notification Requirements March 2005 + + +2.20. Reliable Delivery of Notifications + + Notifications that are delivered by a reliable delivery of packets or + character stream, with acknowledgement and retry, so that delivery of + the notification is guaranteed within determinate time limits. For + example, if the Notification Recipient has logged off and gone home + for the day, an immediate notification cannot be guaranteed, 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 acknowledgement or retry is required. + Process-to-process communications, if involved, are unconstrained. + +2.22. Human-Consumable Notification + + Notifications 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 + + Notifications that 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. Sitting in my office, I 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: + + + + + + +Hastings, et al. Informational [Page 6] + +RFC 3997 IPP: Notification Requirements March 2005 + + + - Notification Recipient: Me + - Notification Events: All + - Notification Attributes: Job-state-reason + - Notification Type: Immediate + + 2. Working from home, I submit a print job to the same printer as + in the previous example. However, 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 that it + doesn't get lost or misfiled. I'd also like a store-and-forward + notification sent to my email so that when I get to work I can + tell whether 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. Sitting in my office, I submit a print job to a client at an + engineering firm my company works 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 her building. It is important that she review it + right away and send 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. From a hotel room, I 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. As 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 whether the + file has been printed. An email notification is sufficient for + this purpose. I submit the print job with the following + attributes: + + + + + +Hastings, et al. Informational [Page 7] + +RFC 3997 IPP: Notification Requirements March 2005 + + + - 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 one of 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 persist across + power cycles. I subscribe with the following attributes: + + - Notification Recipient: Me + - Notification Type: Immediate + - 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 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. + + + +Hastings, et al. Informational [Page 8] + +RFC 3997 IPP: Notification Requirements March 2005 + + + 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 that + 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 represents. When I accept an IPP job creation + requests, I convert it 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 to be able to send IPP + Notifications to subscribed Notification Recipients. + + 11. I am an IPP Server that controls one or more devices and that + 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 objects 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) by + replacing the notification submitted with the Job to indicate me + as the Notification Recipient; in turn I will forward + Notifications to the Notification Recipients requested by my + clients. Most of the rest of the contents of the IPP Job I send + to the IPP Printers I control will be the same as those that I + receive from my IPP clients. + + 12. I am an IPP Server that controls one or more devices and that + 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 controlled by other servers (using IPP or other protocols), I + only want job events for the jobs that I send, but I do want + Printer events all the time, so that I can show proper Printer + + + +Hastings, et al. Informational [Page 9] + +RFC 3997 IPP: Notification Requirements March 2005 + + + state to my clients. So I subscribe to these IPP Printers for + Printer events with a long-standing subscription, with myself 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 "piggybacking"). These IPP + Printers automatically remove their job subscriptions when the + job finishes, 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 following + are true for the resulting IPP Notification Specification document: + + 1. It 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. It must be designed so that an IPP Printer can transparently + support the IPP Notification semantics by using third-party + notification services that exist today or that may be + standardized in the future. + + 3. It must define a 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. It must define a means, when specifying a Notification Recipient, + for a Notification Subscriber to specify one or more notification + events for that Notification Recipient, subject to administrative + and security policy restrictions. Any of the following + constitute Job or Printer Events for which a Job Submitting End + User can specify that notifications be sent: + + - Any standard Printer MIB alert + - 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) + + + + + + +Hastings, et al. Informational [Page 10] + +RFC 3997 IPP: Notification Requirements March 2005 + + + - 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, such as paused, purged + - Device problems for which the job is destined + - Job (interpreter) issues + + 5. It must define how an End User or Operator subscribes for + + - any set of Job Events for a specific job, or + - any set of Printer Events while a specific job is not + complete. + + 6. It 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. It 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. It must define common delivery methods: e.g., email. + + 9. It must define how an IPP Printer validates its ability to + deliver an Event by using the specified delivery scheme. If it + does not support the specified scheme, or if the specified + scheme is invalid for some reason, then the IPP Printer accepts + and performs the request anyway and indicates the unsupported + attribute values. There is no requirement for the IPP Printer + receiving the print request to validate the identity of a + Notification Recipient, or 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). + + 10. It must define a class of IPP event notification delivery + methods that 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. + + + + + +Hastings, et al. Informational [Page 11] + +RFC 3997 IPP: Notification Requirements March 2005 + + + 11. It may define a means to deliver a notification to the + submitting client when the delivery of an event notification to + a specified Notification Recipient fails. A fallback means of + subscribers to determine whether notifications have failed + (i.e., polling) may be provided. + + 12. It must define a mechanism for localizing Human-Consumable + Notifications by the Notification Source. + + 13. It may define a way to specify whether 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 be removed. However, a subscription must not be + deemed stale only if it is unable to deliver an Event + Notification, as 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 sent 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). Scenarios + exist in which third-party notification is required (see scenarios 2 + and 3). The fully secure solution would require active agreement of + all recipients before anything is sent out. However, requirement 9 + ("There is no requirement for an 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). + + The same security issues are present when Clients submit notification + requests to the IPP Printer as when they submit an IPP/1.1 print job + request. The same mechanisms used by IPP/1.1 can therefore be used + + + + +Hastings, et al. Informational [Page 12] + +RFC 3997 IPP: Notification Requirements March 2005 + + + 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 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 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 + + Some notification delivery methods have been registered with IANA for + use in URLs. These will be defined in other documents. + + + + + + + + + + + + + + +Hastings, et al. Informational [Page 13] + +RFC 3997 IPP: Notification Requirements March 2005 + + +8. References + +8.1. Normative References + + [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. + + [RFC3995] Herriot, R. and T. Hastings, "Internet Printing Protocol + (IPP): Event Notifications and Subscriptions", RFC 3995, + March 2005. + +8.2. Informative References + + [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, F., "Design Goals for an Internet Printing + Protocol", RFC 2567, April 1999. + + [RFC2568] Zilles, S., "Rationale for the Structure of the 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. + + [RFC2639] Hastings, T., Manros, C., Zehler, P., Kugler, C., and H. + Holst, "Internet Printing Protocol/1.1: Implementor's + Guide", RFC 3196, November 2001. + + + + + + + + + + + +Hastings, et al. Informational [Page 14] + +RFC 3997 IPP: Notification Requirements March 2005 + + +9. Appendix A: Description of the Base IPP Documents + + The base set of IPP documents includes the following: + + 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 [RFC3196] + Mapping between LPD and IPP Protocols [RFC2569] + + "Design Goals for an Internet Printing Protocol" takes a broad look + at distributed printing functionality, and it enumerates real-life + scenarios that help 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 [RFC2566], [RFC2565]. A few OPTIONAL operator operations + have been added to IPP/1.1 [RFC2911], [RFC2910]. + + "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 IPP working group's major decisions. + + "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 security, internationalization, and directory issues. + + "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 [RFC2616]. It also 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 the "ipp" scheme for identifying IPP printers and jobs. + + "Internet Printing Protocol/1.1: Implementer's Guide" 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, et al. Informational [Page 15] + +RFC 3997 IPP: Notification Requirements March 2005 + + + "Mapping between LPD and IPP Protocols" gives some advice to + implementers of gateways between IPP and LPD (Line Printer Daemon ) + implementations. + +Authors' Addresses + + Tom Hastings (editor) + Xerox Corporation + 701 S Aviation Blvd, ESAE 242 + El Segundo, CA 90245 + + Phone: 310-333-6413 + Fax: 310-333-6342 + EMail: hastings@cp10.es.xerox.com + + + Roger deBry + Utah Valley State College + + Phone: (801) 863-8848 + EMail: debryro@uvsc.edu + + + Harry Lewis + IBM Corporation + 6300 Diagonal Hwy + Boulder, CO 80301 + + Phone: (303) 924-5337 + EMail: harryl@us.ibm.com + + + + + + + + + + + + + + + + + + + + + +Hastings, et al. Informational [Page 16] + +RFC 3997 IPP: Notification Requirements March 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM 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. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights 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; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat 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 on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Hastings, et al. Informational [Page 17] + diff --git a/standards/rfc3998.txt b/standards/rfc3998.txt new file mode 100644 index 000000000..f2ba35f80 --- /dev/null +++ b/standards/rfc3998.txt @@ -0,0 +1,2579 @@ + + + + + + +Network Working Group C. Kugler +Request for Comments: 3998 H. Lewis +Category: Standards Track IBM Corporation + T. Hastings, Ed. + Xerox Corporation + March 2005 + + + Internet Printing Protocol (IPP): + Job and Printer Administrative Operations + +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 (2005). + +Abstract + + This document specifies the following 16 additional OPTIONAL system + administration operations for use with the Internet Printing + Protocol/1.1 (IPP), plus a few associated attributes, values, and + status codes, and using the IPP Printer object to manage printer + fan-out and fan-in. + + Printer operations: Job operations: + Enable-Printer and Disable-Printer Reprocess-Job + Pause-Printer-After-Current-Job Cancel-Current-Job + Hold-New-Jobs and Release-Held-New-Jobs Suspend-Current-Job + Deactivate-Printer and Activate-Printer Resume-Job + Restart-Printer Promote-Job + Shutdown-Printer and Startup-Printer Schedule-Job-After + + + + + + + + + + + + + +Kugler, et al. Standards Track [Page 1] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +Table of Contents + + 1. Introduction.................................................. 4 + 2. Terminology................................................... 4 + 2.1. Conformance Terminology................................. 4 + 2.2. Other Terminology....................................... 5 + 3. Definition of the Printer Operations.......................... 6 + 3.1. The Disable and Enable Printer Operations............... 7 + 3.1.1. Disable-Printer Operation....................... 7 + 3.1.2. Enable-Printer Operation........................ 8 + 3.2. The Pause and Resume Printer Operations................. 8 + 3.2.1. Pause-Printer-After-Current-Job Operation....... 9 + 3.3. Hold and Release New Jobs Operations.................... 11 + 3.3.1. Hold-New-Jobs Operation......................... 11 + 3.3.2. Release-Held-New-Jobs Operation................. 12 + 3.4. Deactivate and Activate Printer Operations.............. 12 + 3.4.1. Deactivate-Printer Operation.................... 13 + 3.4.2. Activate-Printer Operation...................... 13 + 3.5. Restart-Printer, Shutdown-Printer, + and Startup-Printer Operations.......................... 14 + 3.5.1. Restart-Printer Operation....................... 14 + 3.5.2. Shutdown-Printer Operation...................... 14 + 3.5.3. Startup-Printer Operation....................... 15 + 4. Definition of the Job Operations.............................. 16 + 4.1. Reprocess-Job Operation................................. 17 + 4.2. Cancel-Current-Job Operation............................ 17 + 4.3. Suspend and Resume Job Operations....................... 18 + 4.3.1. Suspend-Current-Job Operation................... 19 + 4.3.2. Resume-Job Operation............................ 20 + 4.4. Job Scheduling Operations............................... 20 + 4.4.1. Promote-Job Operation........................... 20 + 4.4.2. Schedule-Job-After Operation.................... 21 + 5. Additional Status Codes....................................... 23 + 5.1. 'server-error-printer-is-deactivated' (0x050A).......... 23 + 6. Use of Operation Attributes + That Are Messages from the Operator........................... 23 + 7. New Printer Description Attributes............................ 26 + 7.1. subordinate-printers-supported (1setOf uri)............. 26 + 7.2. parent-printers-supported (1setOf uri).................. 26 + 8. Additional Values for + the "printer-state-reasons" Printer Description Attribute..... 26 + 8.1. 'hold-new-jobs' Value................................... 27 + 8.2. 'deactivated' Value..................................... 27 + 9. Additional Values for + the "job-state-reasons" Job Description attribute............. 27 + 9.1. 'job-suspended' Value................................... 27 + 10. Use of the Printer Object to Represent + IPP Printer Fan-Out and IPP Printer Fan-In.................... 27 + + + +Kugler, et al. Standards Track [Page 2] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + 10.1. IPP Printer Fan-Out..................................... 28 + 10.2. IPP Printer Fan-In...................................... 28 + 10.3. Printer Object Attributes Used + to Represent Printer Fan-Out and Printer Fan-In......... 29 + 10.4. Subordinate Printer URI................................. 29 + 10.5. Printer Object Attributes Used + to Represent Output Device Fan-Out...................... 30 + 10.6. Figures to Show All Possible Configurations............. 30 + 10.7. Forwarding Requests..................................... 33 + 10.7.1. Forwarding Requests + that Affect Printer Objects..................... 33 + 10.7.2. Forwarding Requests that Affect Jobs............ 35 + 10.8. Additional Attributes to Help with Fan-Out.............. 37 + 10.8.1. output-device-assigned (name(127)) + Job Description Attribute - from [RFC2911]...... 37 + 10.8.2. original-requesting-user-name (name(MAX)) + Operation and Job Description Attribute......... 37 + 10.8.3. requesting-user-name (name(MAX)) + Operation Attribute - Additional Semantics...... 38 + 10.8.4. job-originating-user-name (name(MAX)) + Job Description Attribute - + Additional Semantics............................ 38 + 11. Conformance Requirements...................................... 38 + 12. Normative References.......................................... 39 + 13. Informative References........................................ 40 + 14. IANA Considerations........................................... 40 + 14.1. Attribute Registrations................................. 41 + 14.2. Attribute Value Registrations........................... 41 + 14.3. Additional Enum Attribute Value Registrations........... 41 + 14.4. Operation Registrations................................. 42 + 14.5. Status Code Registrations............................... 43 + 15. Internationalization Considerations........................... 43 + 16. Security Considerations....................................... 43 + 17. Summary of Base IPP Documents................................. 44 + Authors' Addresses................................................ 45 + Full Copyright Statement.......................................... 46 + +List of Tables + + Table 1. Printer Operation Operation-Id Assignments.............. 6 + Table 2. Pause and Resume Printer Operations..................... 9 + Table 3. State Transition Table for + Pause-Printer-After-Current-Job Operation............... 10 + Table 4. Job Operation Operation-Id Assignments.................. 16 + Table 5. Operation Attribute Support for Printer Operations...... 24 + Table 6. Operation Attribute Support for Job Operations.......... 25 + Table 7. Forwarding Operations that Affect Printer Objects....... 34 + Table 8. Forwarding Operations that Affect Jobs Objects.......... 36 + + + +Kugler, et al. Standards Track [Page 3] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Table 9. Conformance Requirement Dependencies for Operations..... 38 + Table 10. Conformance Requirement Dependencies + for "printer-state-reasons" Values...................... 39 + Table 11. Conformance Requirement Dependencies + for "job-state-reasons" Values.......................... 39 + +List of Figures + + Figure 1. Embedded Printer Object................................ 31 + Figure 2. Hosted Printer Object.................................. 31 + Figure 3. Output Device Fan-Out.................................. 31 + Figure 4. Chained IPP Printer Objects............................ 32 + Figure 5. IPP Printer Object Fan-Out............................. 32 + Figure 6. IPP Printer Object Fan-In.............................. 33 + +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 operations used to control Jobs and Printers. In + addition, this document extends the semantic model of the Printer + object by allowing them to be configured into trees and/or inverted + trees that represent Printer object Fan-Out and Printer object Fan- + In, respectively. The special case of a tree with only a single + Subordinate node represents Chained Printers. This document is a + registration proposal for an extension to IPP/1.0 and IPP/1.1 + following the registration procedures in those documents. + + The requirements and use cases for this document are defined in + [RFC3239]. + +2. Terminology + + This section defines the 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 as defined in RFC 2119 [RFC2119] and [RFC2911], section + 12.1. If an implementation supports the extension defined in this + document, then these terms apply; otherwise, they do not. These + terms define conformance to this document only; they do not affect + conformance to other documents, unless explicitly stated otherwise. + + + + +Kugler, et al. Standards Track [Page 4] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +2.2. Other Terminology + + This document uses terms such as "client", "Printer", "Job", + "attributes", "keywords", "operation", and "support". These terms + have special meaning and are defined in the model terminology + ([RFC2911], section 12.2). + + In addition, the following capitalized terms are defined: + + IPP Printer object (or Printer for short) - A software abstraction + defined by [RFC2911]. + + Printer Operation - An operation whose target is an IPP Printer + object and whose effect is on the Printer object. + + Output Device - The physical imaging mechanism that an IPP Printer + controls. Note: although this term is capitalized in this + specification (but not in [RFC2911]), there is no formal object + called an Output Device defined in this document (or in [RFC2911]). + + Output Device Fan-Out - A configuration in which an IPP Printer + controls more than one Output Device. + + Printer Fan-Out - A configuration in which an IPP Printer object + controls more than one Subordinate IPP Printer object. + + Printer Fan-In - A configuration in which an IPP Printer object is + controlled by more than one IPP Printer object. + + Subordinate Printer - An IPP Printer object that is controlled by + another IPP Printer object. Such a Subordinate Printer MAY have zero + or more Subordinate Printers. + + Leaf Printer - An IPP Printer object that has no Subordinate + Printers. + + Non-Leaf Printer - An IPP Printer object that has one or more + Subordinate Printers. A Non-Leaf Printer is also called a Parent + Printer. + + Chained Printer - a Non-Leaf Printer that has exactly one Subordinate + Printer. + + Job Creation operations - IPP operations that create a Job object: + Print-Job, Print-URI, and Create-Job. + + + + + + +Kugler, et al. Standards Track [Page 5] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +3. Definition of the 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. These descriptions + assume all of the common semantics of the IPP/1.1 Model and Semantics + document ([RFC2911], section 3.1). + + The Printer Operations defined in this document are summarized in + Table 1. + + Table 1. Printer Operation Operation-Id Assignments + + Operation Name Operation-Id Brief Description + -------------------------------------------------------------------- + Enable-Printer 0x22 Allows the target Printer to accept + Job Creation operations. + + Disable-Printer 0x23 Prevents the target Printer from + accepting Job Creation operations. + + Pause-Printer- 0x24 Pauses the Printer after the current + After-Current- job has been sent to the Output + Job Device. + + Hold-New-Jobs 0x25 Finishes processing all currently + pending jobs. Any new jobs are + placed in the 'pending-held' state. + + Release-Held- 0x26 Releases all jobs to the 'pending' + New-Jobs state that had been held by the + effect of a previous Hold-New-Jobs + operation and condition the Printer + so that it no longer holds new jobs. + + Deactivate- 0x27 Puts the Printer into a read-only + Printer deactivated state. + + Activate- 0x28 Restores the Printer to normal + Printer activity. + + Restart-Printer 0x29 Restarts the target Printer and re- + initializes the software. + + Shutdown- 0x2A Shuts down the target Printer so that + Printer it cannot be restarted or queried. + + + + + +Kugler, et al. Standards Track [Page 6] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Startup-Printer 0x2B Starts up the instance of the Printer + object. + + All of the operations in this document are OPTIONAL for an IPP object + to support. Unless the specification of an OPTIONAL operation + requires support of another OPTIONAL operation, conforming + implementations may support any combination of these operations. + Many of the operations come in pairs, so both are REQUIRED if either + one is implemented. + +3.1. The Disable and Enable Printer Operations + + This section defines the OPTIONAL Disable-Printer and Enable-Printer + operations that stop and start the IPP Printer object from accepting + new IPP jobs. If either of these operations are supported, both MUST + be supported. + + These operations allow the operator to control whether the Printer + will accept new Job Creation (Print-Job, Print-URI, and Create-Job) + operations. These operations have no other effect on the Printer, so + the Printer continues to accept all other operations and continues to + schedule and process jobs normally. In other words, these operations + control the "input of new jobs" to the IPP Printer, and the Pause and + Resume operations (see section 3.2) independently control the "output + of new jobs" from the IPP Printer to the Output Device. + +3.1.1. Disable-Printer Operation + + This OPTIONAL operation allows a client to stop the Printer object + from accepting new jobs; i.e., it causes the Printer to reject + subsequent Job Creation operations and return the 'server-error-not- + accepting-jobs' status code. The Printer still accepts all other + operations, including Validate-Job, Send-Document, and Send-URI + operations. Thus a Disable-Printer operation allows a client to + continue submitting multiple documents of a multiple document job if + the Create-Job operation had already been accepted. All previously + created or submitted Jobs and all Jobs currently processing continue + unaffected. + + The IPP Printer MUST accept the request in any state. The Printer + sets the value of its "printer-is-accepting-jobs" READ-ONLY Printer + Description attribute to 'false' (see [RFC2911], section 4.4.20), no + matter what the previous value was. This operation has no immediate + or direct effect on the Printer's "printer-state" and "printer- + state-reasons" attributes. + + + + + + +Kugler, et al. Standards Track [Page 7] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + 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). + + The Disable-Printer Request and Disable-Printer Response have the + same attribute groups and attributes as do the Pause-Printer + operation (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including + the new "printer-message-from-operator" operation attribute (see + section 6). + +3.1.2. Enable-Printer Operation + + This OPTIONAL operation allows a client to start the Printer object + accepting jobs; i.e., it causes the Printer to accept subsequent Job + Creation operations. The Printer still accepts all other operations. + All previously submitted and currently processing Jobs continue + unaffected. + + The IPP Printer MUST accept the request in any state. The Printer + sets the value of its "printer-is-accepting-jobs" READ-ONLY Printer + Description attribute to 'true' (see [RFC2911], section 4.4.20), no + matter what the previous value was. This operation has no immediate + or direct effect on the Printer's "printer-state" and "printer- + state-reasons" attributes. + + 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). + + The Enable-Printer Request and Enable-Printer Response have the same + attribute groups and attributes as does the Pause-Printer operation + (see [RFC2911], sections 3.2.8.1 and 3.2.8.2), including the new + "printer-message-from-operator" operation attribute (see section 6). + +3.2. The Pause and Resume Printer Operations + + This section leaves the OPTIONAL IPP/1.1 Pause-Printer (see + [RFC2911], sections 3.2.7) ambiguous as to whether it stops the + Printer immediately or after the current job. It also defines the + OPTIONAL Pause-Printer-After-Current-Job operation as following the + current job. These operations affect the scheduling of IPP jobs. If + either of these Pause Printer operations are supported, then the + Resume-Printer operation MUST be supported. + + These operations allow the operator to control whether the Printer + will send new IPP jobs to the associated Output Device(s) that the + IPP Printer object represents. These operations have no other effect + on the Printer, so the Printer continues to accept all operations. + + + +Kugler, et al. Standards Track [Page 8] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + In other words, these operations control the "output of new jobs" to + the Output Device(s), and the Disable and Enable Printer Operations + (see section 3.1) independently control the "input of new jobs" to + the IPP Printer. + + Table 2. Pause and Resume Printer Operations + + Pause and Resume Printers Description + -------------------------------------------------------------------- + IPP/1.1 Pause Printer Stops the IPP Printer from sending + new IPP Jobs to the Output Device(s) + either immediately or after the + current job completes, depending on + implementation, as defined in + [RFC2911]. + + Pause-Printer-After- Stops the IPP Printer from sending + Current-Job new IPP Jobs to the Output Device(s) + after the current jobs finish. + + Resume-Printer Starts the IPP Printer sending IPP + Jobs to the Output Device again. + +3.2.1. Pause-Printer-After-Current-Job Operation + + This OPTIONAL operation allows a client to stop the Printer object + from sending IPP jobs to any of its Output Devices or Subordinate + Printers. If the IPP Printer is in the middle of sending an IPP job + to an Output Device or Subordinate Printer, the IPP Printer MUST + complete sending that Job. However, after receiving this operation, + the IPP Printer MUST NOT send any additional IPP jobs to any of its + Output Devices or Subordinate Printers. In addition, after having + received this operation, the IPP Printer MUST NOT start processing + any more jobs, so additional jobs MUST NOT enter the 'processing' + state. + + If the IPP Printer is not sending an IPP Job to the Output Device or + Subordinate Printer (whether or not the Output Device or Subordinate + Printer is busy processing any jobs), the IPP Printer object + transitions immediately to the 'stopped' state by setting its + "printer-state" attribute to 'stopped', removing the 'moving-to- + paused' value, if present, from its "printer-state-reasons" + attribute, and adding the 'paused' value to its "printer-state- + reasons" attribute. + + If the implementation will take appreciable time to complete sending + an IPP job that it has started sending to an Output Device or + Subordinate Printer, the IPP Printer adds the 'moving-to-paused' + + + +Kugler, et al. Standards Track [Page 9] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + value to the Printer object's "printer-state-reasons" attribute (see + section [RFC2911], 4.4.12). When the IPP Printer has completed + sending IPP jobs that it was in the process of sending, the Printer + object transitions to the 'stopped' state by setting its "printer- + state" attribute to 'stopped', removing the 'moving-to-paused' value, + if present, from its "printer-state-reasons" attribute, and adding + the 'paused' value to its "printer-state-reasons" attribute. + + This operation MUST NOT affect the acceptance of Job Creation + requests (see Disable-Printer Operation, section 3.1.1). + + For any jobs that are 'pending' or 'pending-held', the 'printer- + stopped' values of the jobs' "job-state-reasons" attribute also + apply. However, the IPP Printer NEED NOT update those jobs' "job- + state-reasons" attributes and only have to return the 'printer- + stopped' value when those jobs are queried by using the Get-Job- + Attributes or Get-Jobs operations (so-called "lazy evaluation"). + + The IPP Printer MUST accept the request in any state and transition + the Printer to the indicated new "printer-state", and it MUST add the + indicated value to "printer-state-reasons" attribute before returning + as follows: + + Table 3. State Transition Table for Pause-Printer-After-Current-Job + Operation + + Current New "printer IPP Printer's response status + "printer- "printer- -state- code and action (REQUIRED/ + state" state" reasons" OPTIONAL state transition for + a Printer to support): + -------------------------------------------------------------------- + 'idle' 'stopped' 'paused' REQUIRED: 'successful-ok' + + 'processing' 'processing' 'moving- OPTIONAL: 'successful-ok'; + to- Later, when the IPP Printer + paused' has finished sending IPP jobs + to an Output Device, the + "printer-state" becomes + 'stopped', and the 'paused' + value replaces the 'moving-to- + paused' value in the "printer- + state-reasons" attribute + + 'processing' 'stopped' 'paused' REQUIRED: 'successful-ok'; + the IPP Printer wasn't in the + middle of sending an IPP job + to an Output Device + + + + +Kugler, et al. Standards Track [Page 10] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + 'stopped' 'stopped' 'paused' REQUIRED: 'successful-ok' + + 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). + + The Pause-Printer-After-Current-Job Request and Pause-Printer-After- + Current-Job Response have the same attribute groups and attributes as + does the Pause-Printer operation (see [RFC2911], sections 3.2.7.1 and + 3.2.7.2), including the new "printer-message-from-operator" operation + attribute (see section 6). + +3.3. Hold and Release New Jobs Operations + + This section defines operations to condition the Printer to hold any + new jobs and to release them. + +3.3.1. Hold-New-Jobs Operation + + This OPTIONAL operation allows a client to condition the Printer to + complete the current 'pending' and 'processing' IPP Jobs but not to + start processing any subsequently created IPP Jobs. If the IPP + Printer is in the middle of sending an IPP job to an Output Device or + Subordinate Printer, the IPP Printer MUST complete sending that Job. + Furthermore, the IPP Printer MUST send all of the current 'pending' + IPP Jobs to the Output Device(s) or Subordinate IPP Printer + object(s). Any subsequently received Job Creation operations will + cause the IPP Printer to put the Job into the 'pending-held' state, + with the 'job-held-on-create' value being added to the job's "job- + state-reasons" attribute. Thus all newly accepted jobs will be + automatically held by the Printer. + + When the Printer completes all the 'pending' and 'processing' jobs, + it enters the 'idle' state as usual. An operator monitoring Printer + state changes will know when the Printer has completed all current + jobs because the Printer enters the 'idle' state. + + This operation MUST NOT affect the acceptance of Job Creation + requests (see Disable-Printer Operation, section 3.1.1), except to + put the Jobs into the 'pending-held' state, instead of the 'pending' + or 'processing' state. + + The IPP Printer MUST accept the request in any state, MUST NOT + transition the Printer to any other "printer-state", and MUST add the + 'hold-new-jobs' value to the Printer's "printer-state-reasons" + attribute (whether the value was present or not). + + + + + +Kugler, et al. Standards Track [Page 11] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + 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). + + The Hold-New-Jobs Request and Hold-New-Jobs Response have the same + attribute groups and attributes as does the Pause-Printer operation + (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including the new + "printer-message-from-operator" operation attribute (see section 6). + +3.3.2. Release-Held-New-Jobs Operation + + This OPTIONAL operation allows a client to undo the effect of a + previous Hold-New-Jobs operation. In particular, the Printer + releases all the jobs that it held as a consequence of a Hold-New- + Jobs operations; i.e., while the 'hold-new-jobs' value was present in + the Printer's "printer-state-reasons" attribute. In addition, the + Printer MUST accept this request in any state, MUST NOT transition + the Printer to any other "printer-state", and MUST remove the 'hold- + new-jobs' value from its "printer-state-reasons" attribute (whether + the value was present or not) so that the Printer no longer holds + newly created jobs. + + 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). + + The Release-Held-New-Jobs Request and Release-Held-New-Jobs Response + have the same attribute groups and attributes as the Pause-Printer + operation (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including + the new "printer-message-from-operator" operation attribute (see + section 6). + +3.4. Deactivate and Activate Printer Operations + + This section defines the OPTIONAL Deactivate-Printer and Activate- + Printer operations that stop and start the IPP Printer object from + accepting all requests except queries and performing work. If either + of these operations are supported, both MUST be supported. + + These operations allow the operator to put the Printer into a dormant + read-only condition and to take it out of this condition. + + + + + + + + + + +Kugler, et al. Standards Track [Page 12] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +3.4.1. Deactivate-Printer Operation + + This OPTIONAL operation allows a client to stop the Printer object + from sending IPP jobs to any of its Output Devices or Subordinate + Printers (Pause-Printer-After-Current-Job) and to stop the Printer + object from accepting any requests but query requests. The Printer + performs a Disable-Printer and a Pause-Printer-After-Current-Job + operation immediately. If these two operations cannot be completed + immediately, it includes use of all of the "printer-state-reasons". + In addition, the Printer MUST immediately reject all requests, except + for Activate-Printer, queries (Get-Printer-Attributes, Get-Job- + Attributes, Get-Jobs, etc.), Send-Document, and Send-URI (so that + partial job submission can be completed, see section 3.1.1). The + Printer MUST then return the 'server-error-service-unavailable' + status code. + + The IPP Printer MUST accept the request in any state. Immediately, + the Printer MUST set the 'deactivated' value in its "printer-state- + reasons" attribute. Note: neither the Disable-Printer nor the + Pause-Printer-After-Current-Job set the 'deactivated' value. + + 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). + + The Deactivate-Printer Request and Deactivate-Printer Response have + the same attribute groups and attributes as does the Pause-Printer + operation (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including + the new "printer-message-from-operator" operation attribute (see + section 6). + +3.4.2. Activate-Printer Operation + + This OPTIONAL operation allows a client to undo the effects of the + Deactivate-Printer; i.e., it allows the Printer object to start + sending IPP jobs to any of its Output Devices or Subordinate Printers + (Pause-Printer-After-Current-Job) and starts the Printer object from + accepting any requests. The Printer performs an Enable-Printer and a + Resume-Printer operation immediately. In addition, the Printer MUST + immediately start accepting all requests. + + The IPP Printer MUST accept the request in any state. The Printer + MUST immediately remove the 'deactivated' value from its "printer- + state-reasons" attribute (whether it is present or not). + + 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). + + + +Kugler, et al. Standards Track [Page 13] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + The Activate-Printer Request and Activate-Printer Response have the + same attribute groups and attributes as the Pause-Printer operation + (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including the new + "printer-message-from-operator" operation attribute (see section 6). + +3.5. Restart-Printer, Shutdown-Printer, and Startup-Printer Operations + + This section defines the OPTIONAL Restart-Printer, Shutdown-Printer, + and Startup-Printer operations that initialize, shutdown, and start + up the Printer object, respectively. Each of these operations is + OPTIONAL, and any combination MAY be supported. + +3.5.1. Restart-Printer Operation + + This OPTIONAL operation allows a client to restart a Printer object + whose operation is in need of initialization because of incorrect or + erratic behavior; i.e., perform the effect of a software re-boot. + The implementation MUST attempt to save any information about Jobs + and the Printer object before re-initializing. However, this + operation MAY have drastic consequences on the running system, so the + client SHOULD first try the Deactivate-Printer operation to minimize + the effect on the current state of the system. The effects of + previous Disable-Printer, Pause Printer, and Deactivate-Printer + operations are lost. + + The IPP Printer MUST accept the request in any state. The Printer + object MUST initialize its Printer's "printer-state" to 'idle', + remove the state reasons from its "printer-state-reasons" attribute, + and change its "printer-is-accepting-jobs" attribute to 'true'. + + 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). + + The Restart-Printer Request and Restart-Printer Response have the + same attribute groups and attributes as does the Pause-Printer + operation (see [RFC2911], sections 3.2.8.1 and 3.2.8.2), including + the new "printer-message-from-operator" operation attribute (see + section 6). + +3.5.2. Shutdown-Printer Operation + + This OPTIONAL operation allows a client to shutdown a Printer; i.e., + to stop processing jobs without losing any jobs and to make the + Printer object unavailable for any operations using the IPP protocol. + There is no way to bring the instance of the Printer object back to + being used, except for the Startup-Printer (see section 3.5.3), which + starts up a new instance of the Printer object for hosted + + + +Kugler, et al. Standards Track [Page 14] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + implementations. The purpose of Shutdown-Printer is to shutdown the + Printer for an extended period, not to reset the device(s) or modify + a Printer attribute. See Restart-Printer (section 3.5.1) and + Startup-Printer (section 3.5.3) for the way to initialize the + software. See the Disable-Printer operation (section 3.1) for a way + for the client to stop the Printer from accepting Job Creation + requests without stopping processing or shutting down. + + The Printer MUST add the 'shutdown' value (see [RFC2911], section + 4.4.11) immediately to its "printer-state-reasons" Printer + Description attribute. It then performs a Deactivate-Printer + operation (see section 3.4.1), which in turn performs Disable-Printer + and Pause-Printer-After-Current-Job operations). + + Note: To shutdown the Printer after all the currently submitted jobs + have completed, the operator issues a Disable-Printer operation (see + section 3.1.1) and then waits until all the jobs have completed. The + Printer goes into the 'idle' state before issuing the Shutdown- + Printer operation. + + The Printer object MUST accept this operation in any state and + transition the Printer object through the "printer-states" and + "printer-state-reasons" defined for the Pause-Printer-After-Current- + Job operation until the activity is completed and the Printer object + disappears. + + 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). + + The Shutdown-Printer Request and Shutdown-Printer Response have the + same attribute groups and attributes as does the Pause-Printer + operation (see [RFC2911], sections 3.2.7.1 and 3.2.7.2), including + the new "printer-message-from-operator" operation attribute (see + section 6). + +3.5.3. Startup-Printer operation + + This OPTIONAL operation allows a client to start up an instance of a + Printer object, provided that there isn't one already initiated. The + purpose of Startup-Printer is to allow a hosted implementation of the + IPP Printer object (i.e., a Server that implements an IPP Printer on + behalf of a networked or local Output Device) to be started after the + host is available (by means outside this document). See section + 3.5.1 for the way to initialize the software or reset the Output + Device(s) when the IPP Printer object has already been initiated. + + + + + +Kugler, et al. Standards Track [Page 15] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + The host MUST accept this operation only when the Printer object has + not been initiated. If the Printer object already exists, the host + must return the 'client-error-not-possible' status code. + + The result of this operation MUST be with the Printer object's + "printer-state" set to 'idle', the state reasons removed from its + "printer-state-reasons" attribute, and its "printer-is-accepting- + jobs" attribute set to 'false'. Then the operator can reconfigure + the Printer before performing an Enable-Printer operation. However, + when a Printer is first powered up, it is RECOMMENDED that its + "printer-is-accepting-jobs" attribute be set to 'true' in order to + achieve easy "out of the box" operation. + + 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). + + The Shutdown-Printer Request and Shutdown-Printer Response have the + same attribute groups and attributes as does the Pause-Printer + operation (see [RFC2911] sections 3.2.7.1 and 3.2.7.2), including the + new "printer-message-from-operator" operation attribute (see section + 6). + +4. Definition of the Job Operations + + All Job operations are directed at Job objects. A client MUST always + supply some means to identify the Job object in order to select the + correct target of the operation. That job identification MAY either + be a single Job URI or a combination of a Printer URI and a Job ID. + The IPP object implementation MUST support both forms of + identification for every job. + + The Job Operations defined in this document are summarized in Table + 4. + + Table 4. Job Operation Operation-Id Assignments + + Operation Name Operation-Id Brief description + -------------------------------------------------------------------- + Reprocess-Job 0x2C Creates a copy of a completed target + job with a new Job ID and processes it. + + Cancel-Current- 0x2D Cancels the current job on the target + Job Printer or the specified job if it is + the current job. + + + + + + +Kugler, et al. Standards Track [Page 16] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Suspend- 0x2E Suspends the current processing job on + Current-Job the target Printer or the specified + job if it is the current job, allowing + other jobs to be processed instead. + + Resume-Job 0x2F Resumes the suspended target job. + + Promote-Job 0x30 Promotes the pending target job to be + next after the current job(s) complete. + + Schedule-Job- 0x31 Schedules the target job immediately + After after the specified job, all other + scheduling factors being equal. + +4.1. Reprocess-Job Operation + + This OPTIONAL operation is a create job operation that allows a + client to re-process a copy of a job that had been retained in the + queue after processing was completed, canceled, or aborted (see + [RFC2911], section 4.3.7.2). This operation is the same as the + Restart-Job operation (see [RFC2911], section 3.3.7), except that the + Printer creates a new job that is a copy of the target job and the + target job is unchanged. New values are assigned to the "job-uri" + and "job-id" attributes. The new job's Job Description attributes + that track job progress, such as "job-impressions-completed", "job- + media-sheets-completed", and "job-k-octets-processed", are + initialized to 0, as with any create job operation. The target job + moves to the Job History after a suitable period, independent of + whether one or more Reprocess-Job operations have been performed upon + it. + + If the Set-Job-Attributes operation is supported, then the "job- + hold-until" operation attribute MUST be supported with at least the + 'indefinite' value, so that a client can modify the new job before it + is scheduled for processing by using the Set-Job-Attributes + operation. After modifying the job, the client can release the job + for processing by using the Release-Job operation specifying the + newly assigned "job-uri" or "job-id" for the new job. + +4.2. Cancel-Current-Job Operation + + This OPTIONAL operation allows a client to cancel the current job on + the target Printer or the specified job if it is the current job on + the Printer. See [RFC2911], section 3.3.3, for the semantics of + canceling a job. Since a Job might already be marking by the time a + Cancel-Current-Job is received, some media sheet pages might print + before the job is actually terminated. + + + + +Kugler, et al. Standards Track [Page 17] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + If the client does not supply a "job-id" operation attribute, the + Printer MUST accept the request and cancel the current job if there + is a current job in the 'processing' or 'processing-stopped' state; + otherwise, it MUST reject the request and return the 'client-error- + not-possible' status code. If more than one job is in the + 'processing' or 'processing-stopped' state, the one that is marking + is canceled, and the others are unaffected. + + Warning: On a shared printer, there is a race condition. Between + the time when a user issues this operation and the time of its + acceptance, the current job might change to a different job. If the + user or operator is authenticated to cancel the new job, the wrong + job is canceled. To prevent this race from canceling the wrong job, + the client MAY supply the "job-id" operation attribute, which is + checked against the current job's job-id. If the job identified by + the "job-id" attribute is not the current job on the Printer (i.e., + is not in the 'processing' or 'processing-stopped' state), the + Printer MUST reject this operation and return the 'client-error-not- + possible' status code. Otherwise, the Printer cancels the specified + job. + + 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). + + The Cancel-Current-Job Request and Cancel-Current-Job Response have + the same attribute groups and attributes as does the Resume-Printer + operation (see [RFC2911], section 3.2.8), including the new "job- + message-from-operator" operation attribute (see section 6), with the + addition of the following Group 1 Operation attribute in the request: + + "job-id" (integer(1:MAX)): + The client OPTIONALLY supplies this Operation attribute to verify + that the identified job is still the current job on the target + Printer object. The IPP object MUST support this operation + attribute if it supports this operation. + +4.3. Suspend and Resume Job Operations + + This section defines the Suspend-Current-Job and Resume-Job + operations. These operations allow an operator or user to suspend a + job while it is processing, allowing other jobs to be processed, and + to resume the suspended job at a later point without losing any of + the output. + + + + + + +Kugler, et al. Standards Track [Page 18] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + If either of these operations is supported, both MUST be supported. + + The Hold-Job and Release-Job operations ([RFC2911], section 3.3.5) + are for holding and releasing held jobs, not suspending and resuming + suspended jobs. + +4.3.1. Suspend-Current-Job Operation + + This OPTIONAL operation allows a client to stop the current job on + the target Printer or the specified job if it is the current job on + the Printer, to allow other jobs to be processed instead. The + Printer moves the current job or the target job to the 'processing- + stopped' state and sets the 'job-suspended' value (see section 9.1) + in the job's "job-state-reasons" attribute and processes other jobs. + + If the client does not supply a "job-id" operation attribute, the + Printer MUST accept the request and suspend the current job if there + is a current job in the 'processing' or 'processing-stopped' state. + Otherwise, it MUST reject the request and return the 'client-error- + not-possible' status code. If more than one job is in the + 'processing' or 'processing-stopped' state, all of them are + suspended. + + Warning: On a shared printer, there is a race condition. Between + the time when a user issues this operation and the time of its + acceptance, the current job might change to a different job. If the + user or operator is authenticated to suspend the new job, the wrong + job is suspended. To prevent this race from pausing the wrong job, + the client MAY supply the "job-id" operation attribute, which is + checked against the current job's job-id. If the job identified by + the "job-id" attribute is not the current job on the Printer (i.e., + is not in the 'processing' or 'processing-stopped' state), the + Printer MUST reject this operation and return the 'client-error-not- + possible' status code. Otherwise, the Printer suspends the specified + job and processed other jobs. + + The Printer MUST reject a Suspend-Current-Job request (and return the + 'client-error-not-possible') for a job that has been suspended, i.e., + for a job in the 'processing-stopped' state, with the 'job-suspended' + value in its "job-state-reasons" attribute. + + Access Rights: The authenticated user (see [RFC2911], section 8.3) + performing this operation must be either 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). + + + + + + +Kugler, et al. Standards Track [Page 19] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + The Suspend-Current-Job Request and Suspend-Current-Job Response have + the same attribute groups and attributes as does the Pause-Printer + operation (see [RFC2911], section 3.2.8 ), including the new "job- + message-from-operator" operation attribute (see section 6), with the + addition of the following Group 1 Operation attribute in the request: + + "job-id" (integer(1:MAX)): + The client OPTIONALLY supplies this Operation attribute to verify + that the identified job is still the current job on the target + Printer object. The IPP object MUST support this operation + attribute if it supports this operation. + +4.3.2. Resume-Job Operation + + This OPTIONAL operation allows a client to resume the target job at + the point where it was suspended. The Printer moves the target job + to the 'pending' state and removes the 'job-suspended' value from the + job's "job-state-reasons" attribute. + + If the target job is not in the 'processing-stopped' state, with the + 'job-suspended' value in the job's "job-state-reasons" attribute, the + Printer MUST reject the request and return the 'client-error-not- + possible' status code, since the job was not suspended. + + Access Rights: The authenticated user (see [RFC2911], section 8.3) + performing this operation must be either 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). + + The Resume-Job Request and Resume-Job Response have the same + attribute groups and attributes as the Release-Job operation (see + [RFC2911], section 3.3.6), including the new "job-message-from- + operator" operation attribute (see section 6). + +4.4. Job Scheduling Operations + + This section defines jobs that allow an operator to control the + scheduling of jobs. + +4.4.1. Promote-Job Operation + + This OPTIONAL operation allows a client to make the pending target + job be processed next after the current job completes. This + operation is especially useful in a production printing environment + where the operator is involved in job scheduling. + + + + + + +Kugler, et al. Standards Track [Page 20] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + If the target job is in the 'pending' state, this operation does not + change the job's state but causes the job to be processed after the + current job(s) complete. If the target job is not in the 'pending' + state, the Printer MUST reject the request and return the 'client- + error-not-possible' status code. + + If the Printer implements the "job-priority" Job Template attribute + (see [RFC2911], section 4.2.1), the Printer sets the job's "job- + priority" to the highest value supported (so that the job will print + before any of the other pending jobs). The Printer returns the + target job immediately after the current job(s) in a Get-Jobs + response (see [RFC2911], section 3.2.6) for the 'not-completed' jobs. + + When the current job is completed, canceled, suspended (see section + 4.3.1), or aborted, the target of this operation is processed next. + + If a client issues this request (again) before the target of the + operation of the original request started processing, the target of + this new request is processed first. + + IPP is specified not to require queues for job scheduling, as there + are other implementation techniques for scheduling multiple jobs, + such as re-evaluating a criteria function for each job on a + scheduling cycle. However, if an implementation does implement + queues for jobs, then the Promote-Job operation puts the specified + job at the front of the queue. A subsequent Promote-Job operation + prior to the processing of the first job puts that specified job at + the front of the queue, so that it is "in front" of the previously + promoted job. + + 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). + + The Promote-Job Request and Promote-Job Response have the same + attribute groups and attributes as does the Cancel-Job operation (see + [RFC2911], section 3.3.3), including the new "job-message-from- + operator" operation attribute (see section 6). + +4.4.2. Schedule-Job-After Operation + + This OPTIONAL operation allows a client to request that the Printer + schedule the target job so that it will be processed immediately + after the specified predecessor job, all other scheduling factors + being equal. This operation is specially useful in a production + printing environment where the operator is involved in job + scheduling. + + + + +Kugler, et al. Standards Track [Page 21] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + If the target job is in the 'pending' state, this operation does not + change the job's state but causes the job to be processed after the + preceding job completes. The preceding job can be in the target + 'pending', 'processing', or 'processing-stopped' state. If the + target job is not in the 'pending' state, or if the predecessor job + is not in the 'pending', 'processing', or 'processing-stopped' state, + the Printer MUST reject the request, and it returns the 'client- + error-not-possible' status code, as the job cannot have its position + changed. + + If the Printer implements the "job-priority" Job Template attribute + (see [RFC2911], section 4.2.1), the Printer sets the job's "job- + priority" to that of the predecessor job (so that the job will print + after the predecessor job). The Printer returns the target job + immediately after the predecessor in a Get-Jobs response (see + [RFC2911], section 3.2.6) for the 'not-completed' jobs. + + When the predecessor job completes processing or is canceled or + aborted while processing, the target of this operation is processed + next. + + If the client does not supply a predecessor job, this operation has + the same semantics as Promote-Job (see section 4.4). + + IPP is specified not to require queues for job scheduling, as there + are other implementation techniques for scheduling multiple jobs, + such as re-evaluating a criteria function for each job on a + scheduling cycle. However, if an implementation does implement + queues for jobs, then the Schedule-Job-After operation puts the + specified job immediately after the specified job in the queue. A + subsequent Schedule-Job-After operation specifying the same job will + cause its target job to be placed after that job, even though it is + between the first target job and the specified job. For example, + suppose the job queue consisted of jobs A, B, C, D, and E, in that + order. A Schedule-Job-After with job E as the target and B as the + specified job would result in the following queue: A, B, E, C, D. A + subsequent Schedule-Job-After with Job D as the target and B as the + specified job would result in the following queue: A, B, D, E, C. + + In other words, the link between the two jobs in a Schedule-Job-After + operation is not retained; i.e., there is no attribute on either job + that points to the other job as a result of this operation. + + 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). + + + + + +Kugler, et al. Standards Track [Page 22] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + The Schedule-Job-After Request have the same attribute groups and + attributes as does the Cancel-Job operation (see [RFC2911], section + 3.3.3), plus the new "job-message-from-operator" operation attribute + (see section 6). In addition, the following operation attribute is + defined: + + "predecessor-job-id": + The client OPTIONALLY supplies this attribute. The Printer MUST + support it, if it supports this operation. This attribute + specifies the job after which the target job is to be processed. + If the client omits this attribute, the Printer MUST process the + target job next, i.e., after the current job, if there is one. + + The Schedule-Job-After Response has the same attribute groups, + attributes, and status codes as does the Cancel-Job operation (see + [RFC2911], section 3.3.3). The following status codes have + particular meaning for this operation: + + 'client-error-not-possible' - The target job was not in the 'pending' + state, or the predecessor job was not in the 'pending', 'processing', + or 'processing-stopped' state. + + 'client-error-not-found' - Either the target job or the predecessor + job was not found. + +5. Additional Status Codes + + This section defines new status codes used by the operations defined + in this document. + +5.1. 'server-error-printer-is-deactivated' (0x050A) + + The Printer has been deactivated by the Deactivate-Printer operation + and is only accepting the Activate-Printer (see section 3.5.1), Get- + Job-Attributes, Get-Jobs, Get-Printer-Attributes, and any other Get- + Xxxx operations. An operator can perform the Activate-Printer + operation to allow the Printer to accept other operations. + +6. Use of Operation Attributes That Are Messages from the Operator + + This section summarizes the usage of the "printer-message-from- + operator" and "job-message-from-operator" operation attributes + [RFC3380] that set the corresponding Printer and Job Description + attributes (see [RFC2911] for the definition of these). These + operation attributes are defined for most of the Printer and Job + operations that operators are likely to perform, respectively, so + that operators can indicate the reasons for their actions. + + + + +Kugler, et al. Standards Track [Page 23] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Table 5 shows the operation attributes defined for use with the + Printer Operations. + + Table 5. Operation Attribute Support for Printer Operations + + Operation Attribute A B + --------------------------------------------- + attributes-charset REQ REQ + attributes-natural-language REQ REQ + printer-uri REQ REQ + requesting-user-name REQ REQ + printer-message-from-operator Note OPT + + Legend: + A: Get-Printer-Attributes, Set-Printer-Attributes + B: All other Printer administrative operations, including, but + not limited to, Pause-Printer, Pause-Printer-After-Current- + Job, Resume-Printer, Hold-New-Jobs, Release-Held-New-Jobs, + Purge-Jobs, Enable-Print, Disable-Printer, Restart- + Printer, Shutdown-Printer, and Startup-Printer. + REQ: REQUIRED for a Printer to support. + OPT: OPTIONAL for a Printer to support; the Printer ignores the + attribute if it is not supported. + Note: According to [RFC3380], the Client MUST NOT supply the + "printer-message-from-operator" operation attribute in a + Get-Printer-Attributes or Set-Printer-Attributes operation; + the Printer MUST ignore this operation attribute in these + two operations. Instead, when it is used by an + operator, the client MUST supply the + "printer-message-from-operator" as (one of the) explicit + attributes being set on the Printer object with the + Set-Printer-Attributes operation. + + + + + + + + + + + + + + + + + + + +Kugler, et al. Standards Track [Page 24] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Table 6 shows the operation attributes defined for use with the Job + operations. + + Table 6. Operation Attribute Support for Job Operations + + Operation Attribute A B C F + --------------------------------------------------------- + attributes-charset REQ REQ REQ REQ + attributes-natural-language REQ REQ REQ REQ + printer-uri REQ REQ REQ REQ + job-uri REQ REQ REQ + job-id REQ REQ REQ REQ + requesting-user-name REQ REQ REQ REQ + job-message-from-operator OPT OPT OPT Note + message** OPT OPT OPT n/a + job-hold-until n/a n/a OPT* n/a + + Legend: + A: Cancel-Job, Resume-Job, Restart-Job, Promote-Job, Schedule-Job- + After + B: Cancel-Current-Job, Suspend-Current-Job + C: Hold-Job, Release-Job, Reprocess-Job + F: Get-Job-Attributes, Set-Job-Attributes + + REQ; REQUIRED for a Printer to support. + OPT: OPTIONAL for a Printer to support; the Printer ignores the + attribute if it is supplied, but not supported. + n/a: not applicable for use with the operation; the Printer ignores + the attribute. + Note: According to [RFC3380], the Client MUST NOT supply the "job- + message-from-operator" operation attribute in a Get-Job- + Attributes or Set-Job-Attributes operation; the Printer MUST + ignore this operation attribute in these two operations. + Instead, when used by an operator, the client MUST supply the + "job-message-from-operator" as (one of the) explicit attributes + being set on the Job object with the Set-Job-Attributes + operation. + *: The Printer MUST support the "job-hold-until" operation + attribute if it supports the "job-hold-until" Job Template + attribute. For the Reprocess-Job operation, the client can + hold the job and then modify the job before releasing it to + be processed. + **: In [RFC2911], the "message" operation attribute is defined to + contain a message to the operator, but [RFC2911] does not + define a Job Description attribute to store the message. + + + + + + +Kugler, et al. Standards Track [Page 25] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +7. New Printer Description Attributes + + The following new Printer Description attributes are needed to + support the new operations defined in this document and the concepts + of Printer Fan-Out (see section 10). + +7.1. subordinate-printers-supported (1setOf uri) + + This Printer attribute is REQUIRED if an implementation supports + Subordinate Printers (see section 10) and contains the URIs of the + immediate Subordinate Printer object(s) associated with this Printer + object. Each Non-Leaf Printer object MUST support this Printer + Description attribute. A Leaf Printer object either does not support + the "subordinate-printers-supported" attribute or does so with the + 'no-value' out-of-band value (see [RFC2911], section 4.1), depending + on the implementation. + + The precise format of the Subordinate Printer URIs is implementation + dependent (see section 10.4). + + If the Printer object does not have an associated Output Device, the + Printer MAY automatically copy the value of the Subordinate Printer + object's "printer-name" attribute to the Job object's "output- + device-assigned" attribute (see [RFC2911], section 4.3.13). The + "output-device-assigned" Job attribute identifies the Output Device + to which the Printer object has assigned a job; for example, when a + single Printer object is supporting Device Fan-Out or Printer Fan- + Out. + +7.2. parent-printers-supported (1setOf uri) + + This Printer attribute is REQUIRED if an implementation supports + Subordinate Printers (see section 10) and contains the URI of the + Non-Leaf printer object(s) for which this Printer object is the + immediate Subordinate; i.e., this Printer's immediate "parent" or + "parents". Each Subordinate Printer object MUST support this Printer + Description attribute. A Printer that has no parents either does not + support the "parent-printers-supported" attribute or does so with the + 'no-value' out-of-band value (see [RFC2911], section 4.1), depending + on the implementation. + +8. Additional Values for the "printer-state-reasons" Printer + Description Attribute + + This section defines additional values for the "printer-state- + reasons" Printer Description attribute. + + + + + +Kugler, et al. Standards Track [Page 26] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +8.1. 'hold-new-jobs' Value + + 'hold-new-jobs': The operator has issued the Hold-New-Jobs operation + (see section 3.3.1) or other means, but the output-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 + Hold-New-Jobs operation is supported and the implementation takes + significant time to pause a device in certain circumstances. + +8.2. 'deactivated' Value + + 'deactivated': A client has issued a Deactivate-Printer operation + for the Printer object (see section 3.4.1), and the Printer is in + the process of becoming deactivated or has become deactivated. + The Printer MUST reject all requests except for Activate-Printer, + queries (Get-Printer-Attributes, Get-Job-Attributes, Get-Jobs, + etc.), Send-Document, and Send-URI (so that partial job submission + can be completed; see section 3.1.1), and then return the + 'server-error-service-unavailable' status code. + +9. Additional Values for the "job-state-reasons" Job Description + Attribute + + This section defines additional values for the "job-state-reasons" + Job Description attribute. + +9.1. 'job-suspended' Value + + 'job-suspended': While job processing has been suspended by the + Suspend-Current-Job operation, other jobs can be processed on the + Printer. The Job can be resumed with the Resume-Job operation, + which removes this value. + +10. Use of the Printer Object to Represent IPP Printer Fan-Out and IPP + Printer Fan-In + + This section defines how the Printer object MAY be used to represent + IPP Printer Fan-Out and IPP Printer Fan-In. In Fan-Out, an IPP + Printer is used to represent other IPP Printer objects. In Fan-In, + several IPP Printer objects are used to represent another IPP Printer + object. + + + + + + + + +Kugler, et al. Standards Track [Page 27] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +10.1. IPP Printer Fan-Out + + The IPP/1.1 Model and Semantics introduces the semantic concept of an + IPP Printer object that represents more than one Output Device (see + [RFC2911], section 2.1). This concept is called "Output Device Fan- + Out". However, with Fan-Out there was no way to represent the + individual states of the Output Devices or to perform operations on a + specific Output Device. This document generalizes the semantics of + the Printer object to represent Subordinate Fan-Out Output Devices + such as IPP Printer objects. This concept is called "Printer object + Fan-Out". A Printer object that has a Subordinate Printer object is + called a Non-Leaf Printer object. Thus, a Non-Leaf Printer object + supports one or more Subordinate Printer objects in order to + represent Printer object Fan-Out. A Printer object that does not + have any Subordinate Printer objects is called a Leaf Printer object. + + Each Non-Leaf Printer object submits jobs to its immediate + Subordinate Printers and otherwise controls the Subordinate Printers + by using IPP or other protocols. Whether pending jobs are kept in + the Non-Leaf Printer until a Subordinate Printer can accept them or + are kept in the Subordinate Printers depends on implementation and/or + configuration policy. Furthermore, a Subordinate Printer object MAY, + in turn, have Subordinate Printer objects. Thus a Printer object can + be both a Non-Leaf Printer and a Subordinate Printer. + + A Subordinate Printer object MUST be a conforming Printer object, so + it MUST support all of the REQUIRED [RFC2911] operations and + attributes. However, with access control, the Subordinate Printer + MAY be configured so that end-user clients are not permitted to + perform any operations (or just Get-Printer-Attributes) while one or + more Non-Leaf Printer object(s) are permitted to perform any + operation. + +10.2. IPP Printer Fan-In + + The IPP/1.1 Model and Semantics did not preclude the semantic concept + of multiple IPP Printer objects that represent a single Output Device + (see [RFC2911], section 2.1). However, there was no way for the + client to determine whether there was a Fan-In configuration; nor was + there a way to perform operations on the Subordinate device. This + specification generalizes the semantics of the Printer object to + allow several Non-Leaf IPP Printer objects to represent a single + Subordinate Printer object. Thus a Non-Leaf Printer object MAY share + a Subordinate Printer object with one or more other Non-Leaf Printer + objects in order to represent IPP Printer Fan-In. + + As with Fan-Out (see section 10.1), when a Printer object is a Non- + Leaf Printer, it MUST NOT have an associated Output Device. As with + + + +Kugler, et al. Standards Track [Page 28] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Fan-Out, a Leaf Printer object has one or more associated Output + Devices. As with Fan-Out, the Non-Leaf Printer objects submit jobs + to their Subordinate Printer objects and otherwise control the + Subordinate Printer. As with Fan-Out, whether pending jobs are kept + in the Non-Leaf Printers until the Subordinate Printer can accept + them or are kept in the Subordinate Printer depends on the + implementation and/or configuration policy. + +10.3. Printer Object Attributes Used to Represent Printer Fan-Out and + Printer Fan-In + + The following Printer Description attributes are defined to represent + the relationship between Printer object(s) and their Subordinate + Printer object(s): + + 1. "subordinate-printers-supported" (1setOf uri) - Contains the + URI of the immediate Subordinate Printer object(s). + + 2. "parent-printers-supported (1setOf uri) - Contains the URI of + the Non-Leaf printer object(s) for which this Printer object is + the immediate Subordinate; i.e., this Printer's immediate + "parent" or "parents". + +10.4. Subordinate Printer URI + + Each Subordinate Printer object has a URI used as the target of each + operation on the Subordinate Printer. The means to configure URIs + for Subordinate Printer objects is implementation-dependent, as are + all URIs. However, there are two distinct approaches: + + a. When the implementation seeks to make sure that no operation on + a Subordinate Printer object "sneaks by" the parent Printer + object (or that no Subordinate Printer is fronting for a device + that is not networked), the host part of the URI specifies the + host of the parent Printer. Then the parent Printer object can + easily reflect the state of the Subordinate Printer objects in + the parent's Printer object state and state reasons as the + operation passes "through" the parent Printer object. + + b. When the Subordinate Printer is networked and the + implementation allows operations to go directly to the + Subordinate Printer (with proper access control) without + knowledge of the parent Printer object, the host part of the + URI is different from the host part of the parent Printer + object. In this a case, the parent Printer object MAY keep its + "printer-state" and "printer-state-reasons" up to date, either + by polling the Subordinate Printer object or by subscribing to + events with the Subordinate Printer object (see [RFC3995] for + + + +Kugler, et al. Standards Track [Page 29] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + means to subscribe to event notification when the Subordinate + Printer object supports IPP notification). Alternatively, the + parent Printer MAY wait until its "printer-state" and + "printer-state-reasons" attributes are queried and then query + all its Subordinate Printers in order to return the correct + values. + +10.5. Printer Object Attributes Used to Represent Output Device Fan-Out + + Only Leaf IPP Printer objects are allowed to have one or more + associated Output Devices. Each Leaf Printer object MAY support the + "output-devices-supported" (1setOf name(127)) to indicate the user- + friendly name(s) of the Output Device(s) that the Leaf Printer object + represents. It is RECOMMENDED that each Leaf Printer object have + only one associated Output Device, so that the individual Output + Devices can be represented completely and controlled completely by + clients. In other words, the Leaf Printer's "output-devices- + supported" attribute SHOULD have only one value. + + Non-Leaf Printer MUST NOT have associated Output Devices. However, a + Non-Leaf Printer SHOULD support an "output-devices-supported" (1setOf + name(127)) Printer Description attribute that contains all the values + of its immediate Subordinate Printers. As these Subordinate Printers + MAY be Leaf or Non-Leaf, the same rules apply to them. Thus any + Non-Leaf Printer SHOULD have an "output-devices-supported" (1setOf + name(127)) attribute that contains all the values of the Output + Devices associated with Leaf Printers of its complete sub-tree. + + When a configuration of Printers and Output Devices is added, moved, + or changed, there can be moments when the tree structure is not + consistent; i.e., times when a Non-Leaf Printer's "subordinate- + printers-supported" does not agree with the Subordinate Printer's + "parent-printers-supported". Therefore, the operator SHOULD first + Deactivate all Printers being configured in this way, update all + pointer attributes, and then reactivate them. A useful client tool + would validate a tree structure before Activating the Printers + involved. + +10.6. Figures to Show All Possible Configurations + + Figures 1, 2, and 3 are taken from [RFC2911] to show the + configurations possible with IPP/1.0 and IPP/1.1 where all Printer + objects are Leaf Printer objects. The remaining figures show + additional configurations using Non-Leaf and Leaf Printer objects. + + + + + + + +Kugler, et al. Standards Track [Page 30] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Legend: + + ----> indicates a network protocol with the direction of its requests + + ##### indicates a Printer object that is either + embedded in an Output Device, or + 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. + + Output Device + +---------------+ + | ########### | + O +--------+ | # (Leaf) # | + /|\ | client |------------IPP-----------------># Printer # | + / \ +--------+ | # Object # | + | ########### | + +---------------+ + + Figure 1. Embedded Printer Object + + + ########### Output Device + O +--------+ # (Leaf) # +---------------+ + /|\ | client |---IPP----># Printer #---any->| | + / \ +--------+ # object # | | + ########### +---------------+ + + Figure 2. Hosted Printer Object + + + +---------------+ + | | + +->| Output Device | + ########### any/ | | + O +--------+ # (Leaf) # / +---------------+ + /|\ | client |---IPP----># Printer #--* + / \ +--------+ # Object # \ +---------------+ + ########### any\ | | + +->| Output Device | + | | + +---------------+ + + Figure 3. Output Device Fan-Out + + + + +Kugler, et al. Standards Track [Page 31] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + ########### ########### + O +--------+ # Non-Leaf# # subord. # + /|\ | client |---IPP----># Printer #---IPP----># Printer # + / \ +--------+ # object # # object # + ########### ########### + + The Subordinate Printer can be a Non-Leaf Printer, as in Figures 4 + through 6, or can be a Leaf Printer, as in Figures 1 through 3. + + Figure 4. Chained IPP Printer Objects + + + +------IPP--------------------->########### + / +---># subord. # + / / # Printer # + / ########### IPP # object # + O +--------+ # Non-Leaf# / ########### + /|\ | client |---IPP----># Printer #--* + / \ +--------+ # object # \ + \ ########### IPP ########### + \ \ # subord. # + \ +---># Printer # + +------IPP---------------------># object # + ########### + + The Subordinate Printer can be a Non-Leaf Printer, as in Figures 4 + through 6, or can be a Leaf Printer, as in Figures 1 through 3. + + Figure 5. IPP Printer Object Fan-Out + + + + + + + + + + + + + + + + + + + + + + +Kugler, et al. Standards Track [Page 32] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + ########### + # Non-Leaf# + +---># Printer #-+ + / # object # \ + IPP ########### \ ########### + O +--------+ / +-IPP-># subord. # + /|\ | client |--+-----------IPP---------------># Printer # + / \ +--------+ \ +-IPP-># object # + IPP ########### / ########### + \ # Non-Leaf# / + +---># Printer #-+ + # object # + ########### + + The Subordinate Printer can be a Non-Leaf Printer, as in Figures 4 + through 6, or can be a Leaf Printer, as in Figures 1 through 3. + + Figure 6. IPP Printer Object Fan-In + +10.7. Forwarding Requests + + This section describes the forwarding of Job and Printer requests to + Subordinate Printer objects. + +10.7.1. Forwarding Requests that Affect Printer Objects + + In Printer Fan-Out, Printer Fan-In, and Chained Printers, the Non- + Leaf IPP Printer object MUST NOT forward the operations that affect + Printer objects to its Subordinate Printer objects. If a client + seeks to explicitly target a Subordinate Printer, the client MUST + specify the URI of the Subordinate Printer. The client can determine + the URI of any Subordinate Printers by querying the Printer's + "subordinate-printers-supported (1setOf uri) attribute (see section + 7.1). + + Table 7 lists the operations that affect Printer objects and the + forwarding behavior that a Non-Leaf Printer MUST exhibit to its + immediate Subordinate Printers. Operations that affect jobs have a + different forwarding rule (see section 10.7.2 and Table 8): + + + + + + + + + + + + +Kugler, et al. Standards Track [Page 33] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Table 7. Forwarding Operations that Affect Printer Objects + + Printer Operation Non-Leaf Printer Action + --------------------------------------------------------------- + Printer Operations: + + Enable-Printer MUST NOT forward to any of its Subordinate + Printers + Disable-Printer MUST NOT forward to any of its Subordinate + Printers + Hold-New-Jobs MUST NOT forward to any of its Subordinate + Printers + Release-Held-New- MUST NOT forward to any of its Subordinate + Jobs Printers + Deactivate-Printer MUST NOT forward to any of its Subordinate + Printers + Activate-Printer MUST NOT forward to any of its Subordinate + Printers + Restart-Printer MUST NOT forward to any of its Subordinate + Printers + Shutdown-Printer MUST NOT forward to any of its Subordinate + Printers + Startup-Printer MUST NOT forward to any of its Subordinate + Printers + + IPP/1.1 Printer See [RFC2911] + Operations: + + Get-Printer- MUST NOT forward to any of its Subordinate + Attributes Printers + Pause-Printer MUST NOT forward to any of its Subordinate + Printers + Resume-Printer MUST NOT forward to any of its Subordinate + Printers + + Set Operations: See [RFC3380] + + Set-Printer- MUST NOT forward to any of its Subordinate + Attributes Printers + + + + + + + + + + + + +Kugler, et al. Standards Track [Page 34] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +10.7.2. Forwarding Requests that Affect Jobs + + Unlike Printer Operations that only affect Printer objects (see + section 10.7.1), a Non-Leaf Printer object MUST forward operations + that directly affect jobs to the appropriate Job object(s) in one or + more of its immediate Subordinate Printer objects. Forwarding is + REQUIRED since the purpose of this Job operation is to affect the + indicated job, which may have been forwarded itself. This forwarding + MAY be immediate or queued, depending on the operation and the + implementation. For example, a Non-Leaf Printer object MAY + queue/spool jobs, feeding a job at a time to its Subordinate + Printer(s), or MAY forward jobs immediately to one of its Subordinate + Printers. In either case, the Non-Leaf Printer object forwards Job + Creation operations to one of its Subordinate Printers. Only the + time of forwarding of the Job Creation operations depends on whether + the policy is to queue/spool jobs in the Non-Leaf Printer or the + Subordinate Printer. + + When a Non-Leaf Printer object creates a Job object in its + Subordinate Printer, whether that Non-Leaf Printer object keeps a + fully formed Job object or just keeps a mapping from the "job-ids" + that it assigned to those assigned by its Subordinate Printer object + is IMPLEMENTATION-DEPENDENT. In either case, the Non-Leaf Printer + MUST be able to accept and carry out future Job operations that + specify the "job-id" that the Non-Leaf Printer assigned and returned + to the job submitting client. + + Table 8 lists the operations that directly affect jobs and the + forwarding behavior that a Non-Leaf Printer MUST exhibit to its + Subordinate Printers. + + + + + + + + + + + + + + + + + + + + + +Kugler, et al. Standards Track [Page 35] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Table 8. Forwarding Operations that Affect Jobs Objects + + Operation Non-Leaf Printer action + --------------------------------------------------------------- + Job operations: + + Reprocess-Job MUST forward to the appropriate Job in one of + its Subordinate Printers + Cancel-Current- MUST NOT forward + Job + Resume-Job MUST forward to the appropriate Job in one of + its Subordinate Printers + Promote-Job MUST forward to the appropriate Job in one of + its Subordinate Printers + + IPP/1.1 Printer + operations: + + Print-Job MUST forward immediately or queue to the + appropriate Subordinate Printer + Print-URI MUST forward immediately or queue to the + appropriate Subordinate Printer + Validate-Job MUST forward to the appropriate Subordinate + Printer + Create-Job MUST forward immediately or queue to the + appropriate Subordinate Printer + Get-Jobs MUST forward to all its Subordinate Printers + Purge-Jobs MUST forward to all its Subordinate Printers + + IPP/1.1 Job + operations: + + Send-Document MUST forward immediately or queue to the + appropriate Job in one of its Subordinate + Printers + Send-URI MUST forward immediately or queue to the + appropriate Job in one of its Subordinate + Printers + Cancel-Job MUST forward to the appropriate Job in one of + its Subordinate Printers + Get-Job- MUST forward to the appropriate Job in one of + Attributes its Subordinate Printers if the Non-Leaf + Printer doesn't know the complete status of the + Job object + Hold-Job MUST forward to the appropriate Job in one of + its Subordinate Printers + Release-Job MUST forward to the appropriate Job in one of + its Subordinate Printers + + + +Kugler, et al. Standards Track [Page 36] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Restart-Job MUST forward to the appropriate Job in one of + its Subordinate Printers + + IPP Set operations: See [RFC3380] + + Set-Job- MUST forward to the appropriate Job in one of + Attributes its Subordinate Printers + + When a Printer receives a request that REQUIRES forwarding, it does + so on a "best efforts basis" and returns a response to its client + without waiting for responses from any of its Subordinate Printers. + Such forwarded requests could fail. + +10.8. Additional Attributes to Help with Fan-Out + + The following operation and Job Description attributes are defined to + help represent Job relationships for Fan-Out and forwarding of jobs. + +10.8.1. output-device-assigned (name(127)) Job Description Attribute - + from [RFC2911] + + [RFC2911] defines "output-device-assigned" as follows: "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 + "Device Fan-Out" see [RFC2911] section 2.1)." See also section 10.1 + in this specification. + +10.8.2. original-requesting-user-name (name(MAX)) Operation and Job + Description Attribute + + The operation attribute containing the user name of the original + user; i.e., corresponding to the "requesting-user-name" operation + attribute (see [RFC2911], section 3.2.1.1) that the original client + supplied to the first Printer object. The Printer copies the + "original-requesting-user-name" operation attribute to the + corresponding Job Description attribute. + + + + + + + + + + +Kugler, et al. Standards Track [Page 37] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +10.8.3. requesting-user-name (name(MAX)) Operation Attribute - + Additional Semantics + + The IPP/1.1 "requesting-user-name" operation attribute (see [RFC2911] + section 3.2.1.1) is updated by each client to be itself on each hop; + i.e., the "requesting-user-name" represents the client forwarding the + request, not the original client. + +10.8.4. job-originating-user-name (name(MAX)) Job Description Attribute + - Additional Semantics + + The "job-originating-user-name" Job Description attribute (see + [RFC2911], section 4.3.6) remains as the authenticated original user, + not the parent Printer's authenticated host, and is forwarded by each + client without changing the value. + +11. Conformance Requirements + + The Job and Printer Administrative operations defined in this + document are OPTIONAL operations. However, some operations MUST be + implemented if others are implemented, as shown in Table 9. + + Table 9. Conformance Requirement Dependencies for Operations + + Operations REQUIRED If any of these operations are + supported: + -------------------------------------------------------------------- + Enable-Printer Disable-Printer + Disable-Printer Enable-Printer + Pause-Printer Resume-Printer + Resume-Printer Pause-Printer, + Pause-Printer-After-Current-Job + Hold-New-Jobs Release-Held-New-Jobs + Release-Held-New-Jobs Hold-New-Jobs + Activate-Printer, Deactivate-Printer + Disable-Printer, + Pause-Printer-After-Current-Job + Deactivate-Printer, Activate-Printer + Enable-Printer, + Resume-Printer + Restart-Printer none + Shutdown-Printer none + Startup-Printer none + Reprocess-Job none + Cancel-Current-Job none + Resume-Job Suspend-Current-Job + Suspend-Current-Job Resume-Job + + + + +Kugler, et al. Standards Track [Page 38] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Promote-Job none + Schedule-Job-After Promote-Job + + Tables 10 and 11 list the "printer-state-reasons" and "job-state- + reasons" values that are REQUIRED if the indicated operations are + supported. + + Table 10. Conformance Requirement Dependencies for + "printer-state-reasons" Values + + "printer-state- Conformance If any of the following Printer + reasons" values: Requirement Operations are supported: + -------------------------------------------------------------------- + 'paused' REQUIRED Pause-Printer, + Pause-Printer-After-Current-Job, + or Deactivate-Printer + 'hold-new-jobs' REQUIRED Hold-New-Jobs + 'moving-to-paused' OPTIONAL Pause-Printer, + Pause-Printer-After-Current-Job, + Deactivate-Printer + 'deactivated' REQUIRED Deactivate-Printer + + + Table 11. Conformance Requirement Dependencies for "job-state- + reasons" Values + + "job-state-reasons" Conformance If any of the following Job + values: Requirement operations are supported: + + 'job-suspended' REQUIRED Suspend-Current-Job + 'printer-stopped' REQUIRED Always REQUIRED + +12. Normative References + + [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 Version 1.0", + RFC 2246, 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. + + [RFC2910] Herriot, R., Butler, S., Moore, P., Turner, R., and J. + Wenn, "Internet Printing Protocol/1.1: Encoding and + Transport", RFC 2910, September 2000. + + + + +Kugler, et al. Standards Track [Page 39] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + [RFC2911] Hastings, T., Herriot, R., deBry, R., Isaacson, S., and P. + Powell, "Internet Printing Protocol/1.1: Model and + Semantics", RFC 2911, September 2000. + + [RFC3380] Hastings, T., Herriot, R., Kugler, C., and H. Lewis, + "Internet Printing Protocol (IPP): Job and Printer Set + Operations", RFC 3380, September 2002. + +13. Informative References + + [RFC2567] Wright, F., "Design Goals for an Internet Printing + Protocol", RFC 2567, April 1999. + + [RFC2568] Zilles, S., "Rationale for the Structure of the 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. + + [RFC3196] Hastings, T., Manros, C., Zehler, P., Kugler, C., and H. + Holst, "Internet Printing Protocol/1.1: Implementor's + Guide", RFC 3196, November 2001. + + [RFC3239] Kugler, C., Lewis, H., and T. Hastings, "Internet Printing + Protocol (IPP): Requirements for Job, Printer, and Device + Administrative Operations", RFC 3239, February 2002. + + [RFC3995] Herriot, R. and T. Hastings, "Internet Printing Protocol + (IPP): Event Notifications and Subscriptions", RFC 3995, + February 2005. + +14. IANA Considerations + + This section contains the registration information that IANA added to + the IPP Registry according to the procedures defined in [RFC2911], + section 6, to cover the definitions in this document. The resulting + registrations have been published as additions to the + http://www.iana.org/assignments/ipp-registrations file. + + + + + + + + + + + +Kugler, et al. Standards Track [Page 40] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +14.1. Attribute Registrations + + The following table lists all the attributes defined in this + document. These have been registered according to the procedures in + [RFC2911], section 6.2. + + Name Reference Section + -------------------------------------- --------- ------- + Job Description attributes: + original-requesting-user-name (name(MAX)) [RFC3998] 10.8.2 + + Printer Description attributes: + subordinate-printers-supported (1setOf uri) [RFC3998] 7.1 + parent-printers-supported (1setOf uri) [RFC3998] 7.2 + + Operation attributes: + original-requesting-user-name (name(MAX)) [RFC3998] 10.8.2 + +14.2. Attribute Value Registrations + + This section lists the additional values defined in this document for + existing attributes. + + Attribute + Value Reference Section + --------------------- --------- ------- + job-state-reasons (1setOf type2 keyword) + job-suspended [RFC3998] 9.1 + + + printer-state-reasons (1setOf type2 keyword) + hold-new-jobs [RFC3998] 8.1 + deactivated [RFC3998] 8.2 + +14.3. Additional Enum Attribute Value Registrations + + The following table lists all the new enum attribute values defined + in this document. These have been registered according to the + procedures in [RFC2911], section 6.1. + + + + + + + + + + + + +Kugler, et al. Standards Track [Page 41] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Attribute (attribute syntax) + Value Name Reference Section + ------- -------------------- --------- ------- + operations-supported (1setOf type2 enum) [RFC2911] 4.4.1 + 0x0022 Enable-Printer [RFC3998] 3 + 0x0023 Disable-Printer [RFC3998] 3 + 0x0024 Pause-Printer-After-Current-Job [RFC3998] 3 + 0x0025 Hold-New-Jobs [RFC3998] 3 + 0x0026 Release-Held-New-Jobs [RFC3998] 3 + 0x0027 Deactivate-Printer [RFC3998] 3 + 0x0028 Activate-Printer [RFC3998] 3 + 0x0029 Restart-Printer [RFC3998] 3 + 0x002A Shutdown-Printer [RFC3998] 3 + 0x002B Startup-Printer [RFC3998] 3 + 0x002C Reprocess-Job [RFC3998] 4 + 0x002D Cancel-Current-Job [RFC3998] 4 + 0x002E Suspend-Current-Job [RFC3998] 4 + 0x002F Resume-Job [RFC3998] 4 + 0x0030 Promote-Job [RFC3998] 4 + 0x0031 Schedule-Job-After [RFC3998] 4 + +14.4. Operation Registrations + + The following table lists all the operations defined in this + document. These have been registered according to the procedures in + [RFC2911], section 6.4. + + Name Reference Section + ----------------------------- --------- ------- + Activate-Printer [RFC3998] 3.4.2 + Cancel-Current-Job [RFC3998] 4.2 + Deactivate-Printer [RFC3998] 3.4.1 + Disable-Printer [RFC3998] 3.1.1 + Enable-Printer [RFC3998] 3.1.2 + Hold-New-Jobs [RFC3998] 3.3.1 + Pause-Printer-After-Current-Job [RFC3998] 3.2.1 + Promote-Job [RFC3998] 4.4.1 + Release-Held-New-Jobs [RFC3998] 3.3.2 + Reprocess-Job [RFC3998] 4.1 + Restart-Printer [RFC3998] 3.5.1 + Resume-Job [RFC3998] 4.3.2 + Schedule-Job-After [RFC3998] 4.4.2 + Shutdown-Printer [RFC3998] 3.5.2 + Startup-Printer [RFC3998] 3.5.3 + Suspend-Current-Job [RFC3998] 4.3.1 + + + + + + +Kugler, et al. Standards Track [Page 42] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +14.5. Status Code Registrations + + The following table lists the status code defined in this document. + This has been registered according to the procedures in [RFC2911], + section 6.6. + + Value Name Reference Section + ------ ------------------------ --------- ------- + 0x0000:0x00FF - "successful" + none at this time + + 0x0100:0x01FF - "informational" + none at this time + + 0x0300:0x03FF - "redirection" See RFC 2911 Errata + none at this time + + 0x0400:0x04FF - "client-error" + none at this time + + 0x0500:0x05FF - "server-error" + 0x050A server-error-printer-is-deactivated [RFC3998] 5.1 + +15. Internationalization Considerations + + This document has the same localization considerations as [RFC2911]. + +16. 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. + + Printer operations defined in this specification (see section 3), as + well as Pause-Printer, Resume-Printer, and Purge-Job (defined in + [RFC2911]) are intended for use by an operator and/or administrator. + Job operations defined in this specification (see section 4) and + Cancel-Job, Hold-Job, and Release-Job (defined in [RFC2911]) are + intended for use by the job owner, operator, or administrator of the + Printer object. These operator and administrator operations affect + service for all users. + + + + + +Kugler, et al. Standards Track [Page 43] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + Inappropriate use of an administrative operation by an + unauthenticated end user can affect the quality of service for all + users. Therefore, IPP Printer implementations MUST support both + successful certificate-based TLS [RFC2246] client authentication and + successful operator/administrator authorization (see [RFC2911], + sections 5.2.7 and 8, and [RFC2910]) to perform the administrative + operations defined in this document. [RFC2910] requires the IPP + Printer to support the minimum cipher suite specified for TLS/1.0. + The means for authorizing an operator or administrator of the Printer + object are outside the scope of this specification, RFC 2910, and RFC + 2911. + + The use of TLS and Client Authentication solves the Denial of + Service, Man in the Middle, and Masquerading security threats. + +17. Summary of Base IPP Documents + + The base set of IPP documents includes the following: + + 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 [RFC3196] + Mapping between LPD and IPP Protocols [RFC2569] + + "Design Goals for an Internet Printing Protocol" takes a broad look + at distributed printing functionality, and it enumerates real-life + scenarios that help clarify the features that have 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. + + "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. + + "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. + + + +Kugler, et al. Standards Track [Page 44] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + + "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 [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 the 'ippget' scheme for identifying IPP printers and jobs. + + "Internet Printing Protocol/1.1: Implementer's Guide" 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. + + "Mapping between LPD and IPP Protocols" gives some advice to + implementers of gateways between IPP and LPD (Line Printer Daemon) + implementations. + +Authors' Addresses + + Carl Kugler + IBM Corporation, 003G + 6300 Diagonal Hwy + Boulder, CO 80301 + + Phone: (303) 924-5060 + EMail: kugler@us.ibm.com + + + Tom Hastings, editor + Xerox Corporation + 701 S Aviation Blvd. ESAE 242 + El Segundo, CA 90245 + + Phone: 310-333-6413 + Fax: 310-333-6342 + EMail: hastings@cp10.es.xerox.com + + + Harry Lewis + IBM Corporation + 6300 Diagonal Hwy + Boulder, CO 80301 + + Phone: (303) 924-5337 + EMail: harryl@us.ibm.com + + + +Kugler, et al. Standards Track [Page 45] + +RFC 3998 IPP: Job and Printer Operations March 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM 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. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights 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; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat 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 on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + ipr@ietf.org. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Kugler, et al. Standards Track [Page 46] + diff --git a/standards/wd-ippmailto10-20050519.pdf b/standards/wd-ippmailto10-20050519.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1ec8c996f0ac8ed3e60722bf0a975c9402d2ef54 GIT binary patch literal 75741 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/dev/null 2>&1 + + +# +# Install all targets... +# + +install: all + $(INSTALL_DIR) $(SBINDIR) + $(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_DIR) $(BINDIR) + $(INSTALL_BIN) cancel $(BINDIR) + $(INSTALL_BIN) cupstestppd $(BINDIR) + $(RM) $(SBINDIR)/disable + $(LN) accept $(SBINDIR)/disable + $(RM) $(SBINDIR)/enable + $(LN) accept $(SBINDIR)/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) || $(INSTALL_BIN) 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 + + +# +# cancel +# + +cancel: cancel.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o cancel cancel.o $(LIBS) + + +# +# cupsaddsmb +# + +cupsaddsmb: cupsaddsmb.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o cupsaddsmb cupsaddsmb.o $(LIBS) + + +# +# cupstestppd +# + +cupstestppd: cupstestppd.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o $@ cupstestppd.o $(LIBS) + + +# +# lp +# + +lp: lp.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lp lp.o $(LIBS) + + +# +# lpadmin +# + +lpadmin: lpadmin.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpadmin lpadmin.o $(LIBZ) $(LIBS) + + +# +# lpinfo +# + +lpinfo: lpinfo.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpinfo lpinfo.o $(LIBS) + + +# +# lpmove +# + +lpmove: lpmove.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpmove lpmove.o $(LIBS) + + +# +# lpoptions +# + +lpoptions: lpoptions.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpoptions lpoptions.o $(LIBZ) $(LIBS) + + +# +# lppasswd +# + +lppasswd: lppasswd.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lppasswd lppasswd.o $(LIBZ) $(LIBS) + + +# +# lpstat +# + +lpstat: lpstat.o ../cups/$(LIBCUPS) + echo Linking $@... + $(CC) $(LDFLAGS) -o lpstat lpstat.o $(LIBS) + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4791 2005-10-14 01:39:44Z mike $". +# diff --git a/systemv/accept.c b/systemv/accept.c new file mode 100644 index 000000000..ba65ca191 --- /dev/null +++ b/systemv/accept.c @@ -0,0 +1,294 @@ +/* + * "$Id: accept.c 4906 2006-01-10 20:53:28Z mike $" + * + * "accept", "disable", "enable", and "reject" commands for the Common + * UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and accept/reject jobs or disable/enable printers. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +/* + * '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 */ + uri[1024], /* Printer URI */ + *reason; /* Reason for reject/disable */ + ipp_t *request; /* IPP request */ + ipp_t *response; /* IPP response */ + ipp_op_t op; /* Operation */ + cups_lang_t *language; /* Language */ + int cancel; /* Cancel jobs? */ + + + /* + * See what operation we're supposed to do... + */ + + if ((command = strrchr(argv[0], '/')) != NULL) + command ++; + else + command = argv[0]; + + cancel = 0; + language = cupsLangDefault(); + + if (!strcmp(command, "accept")) + op = CUPS_ACCEPT_JOBS; + else if (!strcmp(command, "reject")) + op = CUPS_REJECT_JOBS; + else if (!strcmp(command, "disable")) + op = IPP_PAUSE_PRINTER; + else if (!strcmp(command, "enable")) + op = IPP_RESUME_PRINTER; + else + { + _cupsLangPrintf(stderr, language, _("%s: Don't know what to do!\n"), + command); + return (1); + } + + http = NULL; + reason = NULL; + + /* + * Process command-line arguments... + */ + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-') + switch (argv[i][1]) + { + case 'E' : /* Encrypt */ +#ifdef HAVE_SSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + + if (http) + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); +#else + _cupsLangPrintf(stderr, language, + _("%s: Sorry, no encryption support compiled in!\n"), + command); +#endif /* HAVE_SSL */ + break; + + case 'c' : /* Cancel jobs */ + cancel = 1; + break; + + case 'h' : /* Connect to host */ + if (http != NULL) + httpClose(http); + + if (argv[i][2] != '\0') + cupsSetServer(argv[i] + 2); + else + { + i ++; + if (i >= argc) + { + _cupsLangPrintf(stderr, language, + _("%s: Expected server name after -h!\n"), + command); + return (1); + } + + cupsSetServer(argv[i]); + } + break; + + case 'r' : /* Reason for cancellation */ + if (argv[i][2] != '\0') + reason = argv[i] + 2; + else + { + i ++; + if (i >= argc) + { + _cupsLangPrintf(stderr, language, + _("%s: Expected reason text after -r!\n"), + command); + return (1); + } + + reason = argv[i]; + } + break; + + default : + _cupsLangPrintf(stderr, language, _("%s: Unknown option \'%c\'!\n"), + command, argv[i][1]); + return (1); + } + else + { + /* + * Accept/disable/enable/reject a destination... + */ + + if (http == NULL) + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, language, + _("%s: Unable to connect to server: %s\n"), + command, strerror(errno)); + 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; + + 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", argv[i]); + 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) + { + _cupsLangPrintf(stderr, language, + _("%s: Operation failed: %s\n"), + command, ippErrorString(cupsLastError())); + return (1); + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, language, + _("%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); + + 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) + { + _cupsLangPrintf(stderr, language, + _("%s: Operation failed: %s\n"), + command, ippErrorString(cupsLastError())); + return (1); + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, language, + _("%s: Operation failed: %s\n"), + command, ippErrorString(cupsLastError())); + return (1); + } + } + } + + if (http != NULL) + httpClose(http); + + return (0); +} + + +/* + * End of "$Id: accept.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/cancel.c b/systemv/cancel.c new file mode 100644 index 000000000..06c6075c1 --- /dev/null +++ b/systemv/cancel.c @@ -0,0 +1,390 @@ +/* + * "$Id: cancel.c 4906 2006-01-10 20:53:28Z mike $" + * + * "cancel" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and cancel jobs. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include + + +/* + * 'main()' - Parse options and cancel jobs. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + http_t *http; /* HTTP connection to server */ + int i; /* Looping var */ + int job_id; /* Job ID */ + int num_dests; /* Number of destinations */ + cups_dest_t *dests; /* Destinations */ + char *dest, /* Destination printer */ + *job, /* Job ID pointer */ + *user; /* Cancel jobs for a user */ + int purge; /* Purge or cancel jobs? */ + char uri[1024]; /* Printer or job URI */ + ipp_t *request; /* IPP request */ + ipp_t *response; /* IPP response */ + ipp_op_t op; /* Operation */ + cups_lang_t *language; /* Language */ + + + /* + * Setup to cancel individual print jobs... + */ + + op = IPP_CANCEL_JOB; + purge = 0; + job_id = 0; + dest = NULL; + user = NULL; + http = NULL; + num_dests = 0; + dests = NULL; + language = cupsLangDefault(); + + + /* + * 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_SSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + + if (http) + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); +#else + _cupsLangPrintf(stderr, language, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + break; + + case 'a' : /* Cancel all jobs */ + purge = 1; + op = IPP_PURGE_JOBS; + break; + + case 'h' : /* Connect to host */ + if (http != NULL) + httpClose(http); + + if (argv[i][2] != '\0') + cupsSetServer(argv[i] + 2); + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, language, + _("cancel: Error - expected hostname after " + "\'-h\' option!\n")); + return (1); + } + else + cupsSetServer(argv[i]); + } + break; + + case 'u' : /* Username */ + op = IPP_PURGE_JOBS; + + if (argv[i][2] != '\0') + user = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, language, + _("cancel: Error - expected username after " + "\'-u\' option!\n")); + return (1); + } + else + user = argv[i]; + } + break; + + default : + _cupsLangPrintf(stderr, language, + _("cancel: Unknown option \'%c\'!\n"), argv[i][1]); + return (1); + } + else + { + /* + * Cancel a job or printer... + */ + + if (num_dests == 0) + num_dests = cupsGetDests(&dests); + + if (strcmp(argv[i], "-") == 0) + { + /* + * Delete the current job... + */ + + dest = ""; + job_id = 0; + } + else if (cupsGetDest(argv[i], NULL, num_dests, dests) != NULL) + { + /* + * Delete the current job on the named destination... + */ + + dest = argv[i]; + job_id = 0; + } + else if ((job = strrchr(argv[i], '-')) != NULL && isdigit(job[1] & 255)) + { + /* + * Delete the specified job ID. + */ + + dest = NULL; + op = IPP_CANCEL_JOB; + job_id = atoi(job + 1); + } + else if (isdigit(argv[i][0] & 255)) + { + /* + * Delete the specified job ID. + */ + + dest = NULL; + op = IPP_CANCEL_JOB; + job_id = atoi(argv[i]); + } + else + { + /* + * Bad printer name! + */ + + _cupsLangPrintf(stderr, language, + _("cancel: Unknown destination \"%s\"!\n"), argv[i]); + return (1); + } + + /* + * For Solaris LP compatibility, ignore a destination name after + * cancelling a specific job ID... + */ + + if (job_id && (i + 1) < argc && + cupsGetDest(argv[i + 1], NULL, num_dests, dests) != NULL) + i ++; + + /* + * Open a connection to the server... + */ + + if (http == NULL) + if ((http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption())) == NULL) + { + _cupsLangPuts(stderr, language, + _("cancel: Unable to contact server!\n")); + 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; + + 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) + { + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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); + } + + if (user) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, user); + ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); + } + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, cupsUser()); + + if (op == IPP_PURGE_JOBS) + ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", purge); + + /* + * Do the request and get back a response... + */ + + if (op == IPP_PURGE_JOBS && (!user || strcasecmp(user, cupsUser()))) + response = cupsDoRequest(http, request, "/admin/"); + else + response = cupsDoRequest(http, request, "/jobs/"); + + if (response == NULL || + response->request.status.status_code > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, language, _("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); + } + + if (num_dests == 0 && op == IPP_PURGE_JOBS) + { + /* + * Open a connection to the server... + */ + + if (http == NULL) + if ((http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption())) == NULL) + { + _cupsLangPuts(stderr, language, _("cancel: Unable to contact server!\n")); + 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); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, "ipp://localhost/printers/"); + + if (user) + { + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, user); + ippAddBoolean(request, IPP_TAG_OPERATION, "my-jobs", 1); + } + else + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, + "requesting-user-name", NULL, cupsUser()); + + ippAddBoolean(request, IPP_TAG_OPERATION, "purge-jobs", purge); + + /* + * Do the request and get back a response... + */ + + response = cupsDoRequest(http, request, "/admin/"); + + if (response == NULL || + response->request.status.status_code > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, language, _("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: cancel.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/cupsaddsmb.c b/systemv/cupsaddsmb.c new file mode 100644 index 000000000..1ed9d26d6 --- /dev/null +++ b/systemv/cupsaddsmb.c @@ -0,0 +1,1032 @@ +/* + * "$Id: cupsaddsmb.c 4916 2006-01-11 21:42:55Z mike $" + * + * "cupsaddsmb" command for the Common UNIX Printing System (CUPS). + * + * Copyright 2001-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Export printers on the command-line. + * convert_ppd() - Convert a PPD file to a form usable by any of the + * Windows PostScript printer drivers. + * do_samba_command() - Do a SAMBA command, asking for a password as needed. + * export_dest() - Export a destination to SAMBA. + * ppd_gets() - Get a CR and/or LF-terminated line. + * usage() - Show program usage and exit... + * write_option() - Write a CUPS option to a PPD file. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * Local globals... + */ + +int Verbosity = 0; +const char *SAMBAUser, + *SAMBAPassword, + *SAMBAServer; + + +/* + * Local functions... + */ + +int convert_ppd(const char *src, char *dst, int dstsize, ipp_t *info); +int do_samba_command(const char *command, const char *address, + const char *subcommand); +int export_dest(const char *dest); +char *ppd_gets(FILE *fp, char *buf, int buflen); +void usage(void); +int write_option(FILE *dstfp, int order, const char *name, + const char *text, const char *attrname, + ipp_attribute_t *suppattr, ipp_attribute_t *defattr, + int defval, int valcount); + + +/* + * '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 export_all; /* Export all printers? */ + int num_dests; /* Number of printers */ + cups_dest_t *dests; /* Printers */ + + + /* + * Parse command-line arguments... + */ + + export_all = 0; + + SAMBAUser = cupsUser(); + SAMBAPassword = NULL; + SAMBAServer = NULL; + + for (i = 1; i < argc; i ++) + if (!strcmp(argv[i], "-a")) + export_all = 1; + else if (!strcmp(argv[i], "-U")) + { + char *sep; /* Separator for password */ + + + i ++; + if (i >= argc) + usage(); + + SAMBAUser = argv[i]; + + if ((sep = strchr(argv[i], '%')) != NULL) + { + /* + * Nul-terminate the username at the first % and point the + * password at the rest... + */ + + *sep++ = '\0'; + + SAMBAPassword = sep; + } + } + else if (!strcmp(argv[i], "-H")) + { + i ++; + if (i >= argc) + usage(); + + SAMBAServer = argv[i]; + } + else if (!strcmp(argv[i], "-h")) + { + i ++; + if (i >= argc) + usage(); + + cupsSetServer(argv[i]); + } + else if (!strcmp(argv[i], "-v")) + Verbosity = 1; + else if (argv[i][0] != '-') + { + if (SAMBAServer == NULL) + SAMBAServer = cupsServer(); + + if ((status = export_dest(argv[i])) != 0) + return (status); + } + else + usage(); + + /* + * See if the user specified "-a"... + */ + + if (export_all) + { + /* + * Export all printers... + */ + + if (SAMBAServer == NULL) + SAMBAServer = cupsServer(); + + num_dests = cupsGetDests(&dests); + + for (j = 0, status = 0; j < num_dests; j ++) + if (!dests[j].instance) + { + if ((status = export_dest(dests[j].name)) != 0) + break; + } + + cupsFreeDests(num_dests, dests); + + if (status) + return (status); + } + + return (0); +} + + +/* + * 'convert_ppd()' - Convert a PPD file to a form usable by any of the + * Windows PostScript printer drivers. + */ + +int /* O - 0 on success, 1 on failure */ +convert_ppd(const char *src, /* I - Source (original) PPD */ + char *dst, /* O - Destination PPD */ + int dstsize, /* I - Size of destination buffer */ + ipp_t *info) /* I - Printer attributes */ +{ + FILE *srcfp, /* Source file */ + *dstfp; /* Destination file */ + int dstfd; /* Destination file descriptor */ + ipp_attribute_t *suppattr, /* IPP -supported attribute */ + *defattr; /* IPP -default attribute */ + char line[256], /* Line from PPD file */ + junk[256], /* Extra junk to throw away */ + *ptr, /* Pointer into line */ + option[41], /* Option */ + choice[41]; /* Choice */ + int jcloption, /* In a JCL option? */ + linenum; /* Current line number */ + time_t curtime; /* Current time */ + struct tm *curdate; /* Current date */ + + + /* + * Open the original PPD file... + */ + + if ((srcfp = fopen(src, "rb")) == NULL) + return (1); + + /* + * Create a temporary output file using the destination buffer... + */ + + if ((dstfd = cupsTempFd(dst, dstsize)) < 0) + { + fclose(srcfp); + + return (1); + } + + if ((dstfp = fdopen(dstfd, "w")) == NULL) + { + /* + * Unable to convert to FILE *... + */ + + close(dstfd); + + fclose(srcfp); + + return (1); + } + + /* + * Write a new header explaining that this isn't the original PPD... + */ + + fputs("*PPD-Adobe: \"4.3\"\n", dstfp); + + curtime = time(NULL); + curdate = gmtime(&curtime); + + fprintf(dstfp, "*%% Modified on %04d%02d%02d%02d%02d%02d+0000 by cupsaddsmb\n", + curdate->tm_year + 1900, curdate->tm_mon + 1, curdate->tm_mday, + curdate->tm_hour, curdate->tm_min, curdate->tm_sec); + + /* + * Read the existing PPD file, converting all PJL commands to CUPS + * job ticket comments... + */ + + jcloption = 0; + linenum = 0; + + while (ppd_gets(srcfp, line, sizeof(line)) != NULL) + { + linenum ++; + + if (!strncmp(line, "*PPD-Adobe:", 11)) + { + /* + * Already wrote the PPD header... + */ + + continue; + } + else if (!strncmp(line, "*JCLBegin:", 10) || + !strncmp(line, "*JCLToPSInterpreter:", 20) || + !strncmp(line, "*JCLEnd:", 8) || + !strncmp(line, "*Protocols:", 11)) + { + /* + * Don't use existing JCL keywords; we'll create our own, below... + */ + + fprintf(dstfp, "*%% Commented out by cupsaddsmb...\n*%%%s", line + 1); + continue; + } + else if (!strncmp(line, "*JCLOpenUI", 10)) + { + jcloption = 1; + fputs(line, dstfp); + } + else if (!strncmp(line, "*JCLCloseUI", 11)) + { + jcloption = 0; + fputs(line, dstfp); + } + else if (jcloption && + strncmp(line, "*End", 4) && + strncmp(line, "*Default", 8) && + strncmp(line, "*OrderDependency", 16)) + { + if ((ptr = strchr(line, ':')) == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("cupsaddsmb: Missing value on line %d!\n"), linenum); + fclose(srcfp); + fclose(dstfp); + close(dstfd); + unlink(dst); + return (1); + } + + if ((ptr = strchr(ptr, '\"')) == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("cupsaddsmb: Missing double quote on line %d!\n"), + linenum); + fclose(srcfp); + fclose(dstfp); + close(dstfd); + unlink(dst); + return (1); + } + + if (sscanf(line, "*%40s%*[ \t]%40[^/]", option, choice) != 2) + { + _cupsLangPrintf(stderr, NULL, + _("cupsaddsmb: Bad option + choice on line %d!\n"), + linenum); + fclose(srcfp); + fclose(dstfp); + close(dstfd); + unlink(dst); + return (1); + } + + if (strchr(ptr + 1, '\"') == NULL) + { + /* + * Skip remaining... + */ + + while (ppd_gets(srcfp, junk, sizeof(junk)) != NULL) + { + linenum ++; + + if (!strncmp(junk, "*End", 4)) + break; + } + } + + snprintf(ptr + 1, sizeof(line) - (ptr - line + 1), + "%%cupsJobTicket: %s=%s\n\"\n*End\n", option, choice); + + fprintf(dstfp, "*%% Changed by cupsaddsmb...\n%s", line); + } + else + fputs(line, dstfp); + } + + fclose(srcfp); + + /* + * Now add the CUPS-specific attributes and options... + */ + + fputs("\n*% CUPS Job Ticket support and options...\n", dstfp); + fputs("*Protocols: PJL\n", dstfp); + fputs("*JCLBegin: \"%!PS-Adobe-3.0<0A>\"\n", dstfp); + fputs("*JCLToPSInterpreter: \"\"\n", dstfp); + fputs("*JCLEnd: \"\"\n", dstfp); + + fputs("\n*OpenGroup: CUPS/CUPS Options\n\n", dstfp); + + if ((defattr = ippFindAttribute(info, "job-hold-until-default", + IPP_TAG_ZERO)) != NULL && + (suppattr = ippFindAttribute(info, "job-hold-until-supported", + IPP_TAG_ZERO)) != NULL) + write_option(dstfp, 10, "cupsJobHoldUntil", "Hold Until", "job-hold-until", + suppattr, defattr, 0, 1); + + if ((defattr = ippFindAttribute(info, "job-priority-default", + IPP_TAG_INTEGER)) != NULL && + (suppattr = ippFindAttribute(info, "job-priority-supported", + IPP_TAG_RANGE)) != NULL) + write_option(dstfp, 11, "cupsJobPriority", "Priority", "job-priority", + suppattr, defattr, 0, 1); + + if ((defattr = ippFindAttribute(info, "job-sheets-default", + IPP_TAG_ZERO)) != NULL && + (suppattr = ippFindAttribute(info, "job-sheets-supported", + IPP_TAG_ZERO)) != NULL) + { + write_option(dstfp, 20, "cupsJobSheetsStart", "Start Banner", + "job-sheets", suppattr, defattr, 0, 2); + write_option(dstfp, 21, "cupsJobSheetsEnd", "End Banner", + "job-sheets", suppattr, defattr, 1, 2); + } + + fputs("*CloseGroup: CUPS\n", dstfp); + + fclose(dstfp); + close(dstfd); + + 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 *address, /* I - Address for command */ + const char *subcmd) /* I - Sub-command */ +{ + int status; /* Status of command */ + char temp[4096]; /* Command/prompt string */ + int pid; /* Process ID of child */ + + + DEBUG_printf(("do_samba_command(command=\"%s\", address=\"%s\", subcmd=\"%s\")\n", + command, address, subcmd)); + DEBUG_printf(("SAMBAUser=\"%s\", SAMBAPassword=\"%s\"\n", SAMBAUser, + SAMBAPassword)); + + for (status = 1; status; ) + { + if (!SAMBAPassword) + { + snprintf(temp, sizeof(temp), + _("Password for %s required to access %s via SAMBA: "), + SAMBAUser, SAMBAServer); + + if ((SAMBAPassword = cupsGetPassword(temp)) == NULL) + break; + } + + snprintf(temp, sizeof(temp), "%s%%%s", SAMBAUser, SAMBAPassword); + + if (Verbosity) + _cupsLangPrintf(stdout, NULL, + _("Running command: %s %s -N -U \'%s%%%s\' -c \'%s\'\n"), + command, address, SAMBAUser, SAMBAPassword, subcmd); + + if ((pid = fork()) == 0) + { + /* + * Child goes here, redirect stdin/out/err and execute the command... + */ + + close(0); + open("/dev/null", O_RDONLY); + + if (!Verbosity) + { + close(1); + open("/dev/null", O_WRONLY); + close(2); + dup(1); + } + + execlp(command, command, address, "-N", "-U", temp, "-c", subcmd, + (char *)0); + exit(errno); + } + else if (pid < 0) + { + status = -1; + + _cupsLangPrintf(stderr, NULL, _("cupsaddsmb: Unable to run \"%s\": %s\n"), + command, strerror(errno)); + } + else + { + /* + * Wait for the process to complete... + */ + + while (wait(&status) != pid); + } + + DEBUG_printf(("status=%d\n", status)); + + if (Verbosity) + _cupsLangPuts(stdout, NULL, "\n"); + + if (status) + { + if (SAMBAPassword[0]) + SAMBAPassword = NULL; + else + 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 newppd[1024], /* New PPD file for printer drivers */ + file[1024], /* File to test for */ + address[1024], /* Address for command */ + uri[1024], /* Printer URI */ + subcmd[1024]; /* Sub-command */ + const char *datadir; /* CUPS_DATADIR */ + http_t *http; /* Connection to server */ + cups_lang_t *language; /* Default language */ + ipp_t *request, /* IPP request */ + *response; /* IPP response */ + static const char *pattrs[] = /* Printer attributes we want */ + { + "job-hold-until-supported", + "job-hold-until-default", + "job-sheets-supported", + "job-sheets-default", + "job-priority-supported", + "job-priority-default" + }; + + + /* + * Get the location of the printer driver files... + */ + + if ((datadir = getenv("CUPS_DATADIR")) == NULL) + datadir = CUPS_DATADIR; + + language = cupsLangDefault(); + + /* + * Open a connection to the scheduler... + */ + + if ((http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption())) == NULL) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: Unable to connect to server \"%s\" for " + "%s - %s\n"), + cupsServer(), dest, strerror(errno)); + return (1); + } + + /* + * Get the PPD file... + */ + + if ((ppdfile = cupsGetPPD2(http, dest)) == NULL) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: No PPD file for printer \"%s\" - " + "skipping!\n"), + dest); + httpClose(http); + return (0); + } + + /* + * Append the supported banner pages to the PPD file... + */ + + 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); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/printers/%s", dest); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, uri); + + 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) + { + if (response->request.status.status_code > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: get-printer-attributes failed for " + "\"%s\": %s\n"), + dest, + ippErrorString(response->request.status.status_code)); + ippDelete(response); + cupsLangFree(language); + httpClose(http); + unlink(ppdfile); + return (2); + } + } + else + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: get-printer-attributes failed for " + "\"%s\": %s\n"), + dest, ippErrorString(cupsLastError())); + cupsLangFree(language); + httpClose(http); + unlink(ppdfile); + return (2); + } + + /* + * Convert the PPD file to the Windows driver format... + */ + + if (convert_ppd(ppdfile, newppd, sizeof(newppd), response)) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: Unable to convert PPD file for %s - %s\n"), + dest, strerror(errno)); + ippDelete(response); + cupsLangFree(language); + httpClose(http); + unlink(ppdfile); + return (3); + } + + ippDelete(response); + cupsLangFree(language); + httpClose(http); + + /* + * Remove the old PPD and point to the new one... + */ + + unlink(ppdfile); + + ppdfile = newppd; + + /* + * See which drivers are available; the new CUPS v6 and Adobe drivers + * depend on the Windows 2k PS driver, so copy that driver first: + * + * Files: + * + * ps5ui.dll + * pscript.hlp + * pscript.ntf + * pscript5.dll + */ + + snprintf(file, sizeof(file), "%s/drivers/pscript5.dll", datadir); + if (!access(file, 0)) + { + /* + * Windows 2k driver is installed; do the smbclient commands needed + * to copy the Win2k drivers over... + */ + + snprintf(address, sizeof(address), "//%s/print$", SAMBAServer); + + snprintf(subcmd, sizeof(subcmd), + "mkdir W32X86;" + "put %s W32X86/%s.ppd;" + "put %s/drivers/ps5ui.dll W32X86/ps5ui.dll;" + "put %s/drivers/pscript.hlp W32X86/pscript.hlp;" + "put %s/drivers/pscript.ntf W32X86/pscript.ntf;" + "put %s/drivers/pscript5.dll W32X86/pscript5.dll", + ppdfile, dest, datadir, datadir, datadir, datadir); + + if ((status = do_samba_command("smbclient", address, subcmd)) != 0) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: Unable to copy Windows 2000 printer " + "driver files (%d)!\n"), + status); + unlink(ppdfile); + return (4); + } + + /* + * See if we also have the CUPS driver files; if so, use them! + */ + + snprintf(file, sizeof(file), "%s/drivers/cupsps6.dll", datadir); + if (!access(file, 0)) + { + /* + * Copy the CUPS driver files over... + */ + + snprintf(subcmd, sizeof(subcmd), + "put %s/drivers/cups6.ini W32X86/cups6.ini;" + "put %s/drivers/cupsps6.dll W32X86/cupsps6.dll;" + "put %s/drivers/cupsui6.dll W32X86/cupsui6.dll", + datadir, datadir, datadir); + + if ((status = do_samba_command("smbclient", address, subcmd)) != 0) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: Unable to copy CUPS printer driver " + "files (%d)!\n"), + status); + unlink(ppdfile); + return (4); + } + + /* + * Do the rpcclient command needed for the CUPS drivers... + */ + + snprintf(subcmd, sizeof(subcmd), + "adddriver \"Windows NT x86\" \"%s:" + "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:" + "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf," + "cups6.ini,cupsps6.dll,cupsui6.dll\"", + dest, dest, dest); + } + else + { + /* + * Don't have the CUPS drivers, so just use the standard Windows + * drivers... + */ + + snprintf(subcmd, sizeof(subcmd), + "adddriver \"Windows NT x86\" \"%s:" + "pscript5.dll:%s.ppd:ps5ui.dll:pscript.hlp:NULL:RAW:" + "pscript5.dll,%s.ppd,ps5ui.dll,pscript.hlp,pscript.ntf\"", + dest, dest, dest); + } + + if ((status = do_samba_command("rpcclient", SAMBAServer, subcmd)) != 0) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: Unable to install Windows 2000 printer " + "driver files (%d)!\n"), + status); + unlink(ppdfile); + return (5); + } + } + + snprintf(file, sizeof(file), "%s/drivers/ADOBEPS4.DRV", datadir); + if (!access(file, 0)) + { + /* + * Do the smbclient commands needed for the Adobe Win9x drivers... + */ + + snprintf(address, sizeof(address), "//%s/print$", SAMBAServer); + + 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/ICONLIB.DLL WIN40/ICONLIB.DLL;" + "put %s/drivers/PSMON.DLL WIN40/PSMON.DLL;", + ppdfile, dest, datadir, datadir, datadir, datadir, datadir); + + if ((status = do_samba_command("smbclient", address, subcmd)) != 0) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: Unable to copy Windows 9x printer " + "driver files (%d)!\n"), + status); + unlink(ppdfile); + return (6); + } + + /* + * Do the rpcclient commands needed for the Adobe Win9x drivers... + */ + + snprintf(subcmd, sizeof(subcmd), + "adddriver \"Windows 4.0\" \"%s:ADOBEPS4.DRV:%s.PPD:NULL:" + "ADOBEPS4.HLP:PSMON.DLL:RAW:" + "ADOBEPS4.DRV,%s.PPD,ADOBEPS4.HLP,PSMON.DLL,ADFONTS.MFM," + "ICONLIB.DLL\"", + dest, dest, dest); + + if ((status = do_samba_command("rpcclient", SAMBAServer, subcmd)) != 0) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: Unable to install Windows 9x printer " + "driver files (%d)!\n"), + status); + unlink(ppdfile); + return (7); + } + } + + unlink(ppdfile); + + /* + * Finally, associate the drivers we just added with the queue... + */ + + snprintf(subcmd, sizeof(subcmd), "setdriver %s %s", dest, dest); + + if ((status = do_samba_command("rpcclient", SAMBAServer, subcmd)) != 0) + { + _cupsLangPrintf(stderr, language, + _("cupsaddsmb: Unable to set Windows printer driver (%d)!\n"), + status); + return (8); + } + + return (0); +} + + +/* + * 'ppd_gets()' - Get a CR and/or LF-terminated line. + */ + +char * /* O - Line read or NULL on eof/error */ +ppd_gets(FILE *fp, /* I - File to read from*/ + char *buf, /* O - String buffer */ + int buflen) /* I - Size of string buffer */ +{ + int ch; /* Character from file */ + char *ptr, /* Current position in line buffer */ + *end; /* End of line buffer */ + + + /* + * Range check input... + */ + + if (!fp || !buf || buflen < 2 || feof(fp)) + return (NULL); + + /* + * Now loop until we have a valid line... + */ + + for (ptr = buf, end = buf + buflen - 1; ptr < end ;) + { + if ((ch = getc(fp)) == EOF) + { + if (ptr == buf) + return (NULL); + else + break; + } + + *ptr++ = ch; + + if (ch == '\r') + { + /* + * Check for CR LF... + */ + + if ((ch = getc(fp)) != '\n') + ungetc(ch, fp); + else if (ptr < end) + *ptr++ = ch; + + break; + } + else if (ch == '\n') + { + /* + * Line feed ends a line... + */ + + break; + } + } + + *ptr = '\0'; + + return (buf); +} + + +/* + * 'usage()' - Show program usage and exit... + */ + +void +usage(void) +{ + _cupsLangPuts(stdout, NULL, + _("Usage: cupsaddsmb [options] printer1 ... printerN\n" + " cupsaddsmb [options] -a\n" + "\n" + "Options:\n" + " -H samba-server Use the named SAMBA server\n" + " -U samba-user Authenticate using the named SAMBA user\n" + " -a Export all printers\n" + " -h cups-server Use the named CUPS server\n" + " -v Be verbose (show commands)\n")); + exit(1); +} + + +/* + * 'write_option()' - Write a CUPS option to a PPD file. + */ + +int /* O - 0 on success, 1 on failure */ +write_option(FILE *dstfp, /* I - PPD file */ + int order, /* I - Order dependency */ + const char *name, /* I - Option name */ + const char *text, /* I - Option text */ + const char *attrname, /* I - Attribute name */ + ipp_attribute_t *suppattr, /* I - IPP -supported attribute */ + ipp_attribute_t *defattr, /* I - IPP -default attribute */ + int defval, /* I - Default value number */ + int valcount) /* I - Number of values */ +{ + int i; /* Looping var */ + + + if (!dstfp || !name || !text || !suppattr || !defattr) + return (1); + + fprintf(dstfp, "*JCLOpenUI *%s/%s: PickOne\n" + "*OrderDependency: %d JCLSetup *%s\n", + name, text, order, name); + + if (defattr->value_tag == IPP_TAG_INTEGER) + { + /* + * Do numeric options with a range or list... + */ + + fprintf(dstfp, "*Default%s: %d\n", name, defattr->values[defval].integer); + + if (suppattr->value_tag == IPP_TAG_RANGE) + { + /* + * List each number in the range... + */ + + for (i = suppattr->values[0].range.lower; + i <= suppattr->values[0].range.upper; + i ++) + { + fprintf(dstfp, "*%s %d: \"", name, i); + + if (valcount == 1) + fprintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname, i); + else if (defval == 0) + fprintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, i); + else if (defval < (valcount - 1)) + fprintf(dstfp, ",%d\"\n", i); + else + fprintf(dstfp, ",%d\n\"\n*End\n", i); + } + } + else + { + /* + * List explicit numbers... + */ + + for (i = 0; i < suppattr->num_values; i ++) + { + fprintf(dstfp, "*%s %d: \"", name, suppattr->values[i].integer); + + if (valcount == 1) + fprintf(dstfp, "%%cupsJobTicket: %s=%d\n\"\n*End\n", attrname, + suppattr->values[i].integer); + else if (defval == 0) + fprintf(dstfp, "%%cupsJobTicket: %s=%d\"\n", attrname, + suppattr->values[i].integer); + else if (defval < (valcount - 1)) + fprintf(dstfp, ",%d\"\n", suppattr->values[i].integer); + else + fprintf(dstfp, ",%d\n\"\n*End\n", suppattr->values[i].integer); + } + } + } + else + { + /* + * Do text options with a list... + */ + + fprintf(dstfp, "*Default%s: %s\n", name, + defattr->values[defval].string.text); + + for (i = 0; i < suppattr->num_values; i ++) + { + fprintf(dstfp, "*%s %s: \"", name, suppattr->values[i].string.text); + + if (valcount == 1) + fprintf(dstfp, "%%cupsJobTicket: %s=%s\n\"\n*End\n", attrname, + suppattr->values[i].string.text); + else if (defval == 0) + fprintf(dstfp, "%%cupsJobTicket: %s=%s\"\n", attrname, + suppattr->values[i].string.text); + else if (defval < (valcount - 1)) + fprintf(dstfp, ",%s\"\n", suppattr->values[i].string.text); + else + fprintf(dstfp, ",%s\n\"\n*End\n", suppattr->values[i].string.text); + } + } + + fprintf(dstfp, "*JCLCloseUI: *%s\n\n", name); + + return (0); +} + + +/* + * End of "$Id: cupsaddsmb.c 4916 2006-01-11 21:42:55Z mike $". + */ diff --git a/systemv/cupstestppd.c b/systemv/cupstestppd.c new file mode 100644 index 000000000..cb16ec5b2 --- /dev/null +++ b/systemv/cupstestppd.c @@ -0,0 +1,1386 @@ +/* + * "$Id: cupstestppd.c 4906 2006-01-10 20:53:28Z mike $" + * + * PPD test program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products, all rights reserved. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * PostScript is a trademark of Adobe Systems, Inc. + * + * This file is subject to the Apple OS-Developed Software exception. + * + * Contents: + * + * main() - Main entry for test program. + * show_conflicts() - Show option conflicts in a PPD file. + * usage() - Show program usage... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include + + +/* + * Error codes... + */ + +#define ERROR_NONE 0 +#define ERROR_USAGE 1 +#define ERROR_FILE_OPEN 2 +#define ERROR_PPD_FORMAT 3 +#define ERROR_CONFORMANCE 4 + + +/* + * Local functions... + */ + +void show_conflicts(ppd_file_t *ppd); +void usage(void); + + +/* + * 'main()' - Main entry for test program. + */ + +int /* O - Exit status */ +main(int argc, /* I - Number of command-line arguments */ + char *argv[]) /* I - Command-line arguments */ +{ + int i, j, k, m, n; /* Looping vars */ + int len; /* Length of option name */ + char *opt; /* Option character */ + const char *ptr; /* Pointer into string */ + int files; /* Number of files */ + int verbose; /* Want verbose output? */ + int status; /* Exit status */ + int errors; /* Number of conformance errors */ + int ppdversion; /* PPD spec version in PPD file */ + ppd_status_t error; /* Status of ppdOpen*() */ + int line; /* Line number for error */ + int xdpi, /* X resolution */ + ydpi; /* Y resolution */ + ppd_file_t *ppd; /* PPD file record */ + ppd_attr_t *attr; /* PPD attribute */ + ppd_size_t *size; /* Size record */ + ppd_group_t *group; /* UI group */ + ppd_option_t *option; /* Standard UI option */ + ppd_group_t *group2; /* UI group */ + ppd_option_t *option2; /* Standard UI option */ + ppd_choice_t *choice; /* Standard UI option choice */ + static char *uis[] = { "BOOLEAN", "PICKONE", "PICKMANY" }; + static char *sections[] = { "ANY", "DOCUMENT", "EXIT", + "JCL", "PAGE", "PROLOG" }; + + + /* + * Display PPD files for each file listed on the command-line... + */ + + ppdSetConformance(PPD_CONFORM_STRICT); + + verbose = 0; + ppd = NULL; + files = 0; + status = ERROR_NONE; + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-' && argv[i][1]) + { + for (opt = argv[i] + 1; *opt; opt ++) + switch (*opt) + { + case 'q' : /* Quiet mode */ + if (verbose > 0) + { + _cupsLangPuts(stderr, NULL, + _("cupstestppd: The -q option is incompatible " + "with the -v option.\n")); + return (1); + } + + verbose --; + break; + + case 'r' : /* Relaxed mode */ + ppdSetConformance(PPD_CONFORM_RELAXED); + break; + + case 'v' : /* Verbose mode */ + if (verbose < 0) + { + _cupsLangPuts(stderr, NULL, + _("cupstestppd: The -v option is incompatible " + "with the -q option.\n")); + return (1); + } + + verbose ++; + break; + + default : + usage(); + break; + } + } + else + { + /* + * Open the PPD file... + */ + + if (files && verbose >= 0) + _cupsLangPuts(stdout, NULL, "\n"); + + files ++; + + if (argv[i][0] == '-') + { + /* + * Read from stdin... + */ + + if (verbose >= 0) + printf("(stdin):"); + + ppd = ppdOpen(stdin); + } + else + { + /* + * Read from a file... + */ + + if (verbose >= 0) + printf("%s:", argv[i]); + + ppd = ppdOpenFile(argv[i]); + } + + if (ppd == NULL) + { + error = ppdLastError(&line); + + if (error <= PPD_ALLOC_ERROR) + { + status = ERROR_FILE_OPEN; + + if (verbose >= 0) + _cupsLangPrintf(stdout, NULL, + _(" FAIL\n" + " **FAIL** Unable to open PPD file - %s\n"), + strerror(errno)); + } + else + { + status = ERROR_PPD_FORMAT; + + if (verbose >= 0) + { + _cupsLangPrintf(stdout, NULL, + _(" FAIL\n" + " **FAIL** Unable to open PPD file - " + "%s on line %d.\n"), + ppdErrorString(error), line); + + switch (error) + { + case PPD_MISSING_PPDADOBE4 : + _cupsLangPuts(stdout, NULL, + _(" REF: Page 42, section 5.2.\n")); + break; + case PPD_MISSING_VALUE : + _cupsLangPuts(stdout, NULL, + _(" REF: Page 20, section 3.4.\n")); + break; + case PPD_BAD_OPEN_GROUP : + case PPD_NESTED_OPEN_GROUP : + _cupsLangPuts(stdout, NULL, + _(" REF: Pages 45-46, section 5.2.\n")); + break; + case PPD_BAD_OPEN_UI : + case PPD_NESTED_OPEN_UI : + _cupsLangPuts(stdout, NULL, + _(" REF: Pages 42-45, section 5.2.\n")); + break; + case PPD_BAD_ORDER_DEPENDENCY : + _cupsLangPuts(stdout, NULL, + _(" REF: Pages 48-49, section 5.2.\n")); + break; + case PPD_BAD_UI_CONSTRAINTS : + _cupsLangPuts(stdout, NULL, + _(" REF: Pages 52-54, section 5.2.\n")); + break; + case PPD_MISSING_ASTERISK : + _cupsLangPuts(stdout, NULL, + _(" REF: Page 15, section 3.2.\n")); + break; + case PPD_LINE_TOO_LONG : + _cupsLangPuts(stdout, NULL, + _(" REF: Page 15, section 3.1.\n")); + break; + case PPD_ILLEGAL_CHARACTER : + _cupsLangPuts(stdout, NULL, + _(" REF: Page 15, section 3.1.\n")); + break; + case PPD_ILLEGAL_MAIN_KEYWORD : + _cupsLangPuts(stdout, NULL, + _(" REF: Pages 16-17, section 3.2.\n")); + break; + case PPD_ILLEGAL_OPTION_KEYWORD : + _cupsLangPuts(stdout, NULL, + _(" REF: Page 19, section 3.3.\n")); + break; + case PPD_ILLEGAL_TRANSLATION : + _cupsLangPuts(stdout, NULL, + _(" REF: Page 27, section 3.5.\n")); + break; + default : + break; + } + } + } + + continue; + } + + /* + * Show the header and then perform basic conformance tests (limited + * only by what the CUPS PPD functions actually load...) + */ + + errors = 0; + ppdversion = 43; + + if (verbose > 0) + _cupsLangPuts(stdout, NULL, + _("\n DETAILED CONFORMANCE TEST RESULTS\n")); + + if ((attr = ppdFindAttr(ppd, "FormatVersion", NULL)) != NULL && + attr->value) + ppdversion = (int)(10 * atof(attr->value) + 0.5); + + if (verbose > 0) + { + /* + * Look for default keywords with no matching option... + */ + + for (i = 0; i < ppd->num_attrs; i ++) + { + attr = ppd->attrs[i]; + + if (!strcmp(attr->name, "DefaultColorSpace") || + !strcmp(attr->name, "DefaultFont") || + !strcmp(attr->name, "DefaultImageableArea") || + !strcmp(attr->name, "DefaultOutputOrder") || + !strcmp(attr->name, "DefaultPaperDimension") || + !strcmp(attr->name, "DefaultTransfer")) + continue; + + if (!strncmp(attr->name, "Default", 7) && + !ppdFindOption(ppd, attr->name + 7)) + _cupsLangPrintf(stdout, NULL, + _(" WARN %s has no corresponding " + "options!\n"), + attr->name); + } + } + + if ((attr = ppdFindAttr(ppd, "DefaultImageableArea", NULL)) == NULL) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED DefaultImageableArea\n" + " REF: Page 102, section 5.15.\n")); + } + + errors ++; + } + else if (ppdPageSize(ppd, attr->value) == NULL && + strcmp(attr->value, "Unknown")) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** BAD DefaultImageableArea %s!\n" + " REF: Page 102, section 5.15.\n"), + attr->value); + } + + errors ++; + } + else + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS DefaultImageableArea\n")); + } + + if ((attr = ppdFindAttr(ppd, "DefaultPaperDimension", NULL)) == NULL) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED DefaultPaperDimension\n" + " REF: Page 103, section 5.15.\n")); + } + + errors ++; + } + else if (ppdPageSize(ppd, attr->value) == NULL && + strcmp(attr->value, "Unknown")) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** BAD DefaultPaperDimension %s!\n" + " REF: Page 103, section 5.15.\n"), + attr->value); + } + + errors ++; + } + else if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS DefaultPaperDimension\n")); + + for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) + for (k = 0, option = group->options; k < group->num_options; k ++, option ++) + { + /* + * Verify that we have a default choice... + */ + + if (option->defchoice[0]) + { + if (ppdFindChoice(option, option->defchoice) == NULL && + strcmp(option->defchoice, "Unknown")) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** BAD Default%s %s\n" + " REF: Page 40, section 4.5.\n"), + option->keyword, option->defchoice); + } + + errors ++; + } + else if (verbose > 0) + _cupsLangPrintf(stdout, NULL, + _(" PASS Default%s\n"), + option->keyword); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** REQUIRED Default%s\n" + " REF: Page 40, section 4.5.\n"), + option->keyword); + } + + errors ++; + } + } + + if (ppdFindAttr(ppd, "FileVersion", NULL) != NULL) + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS FileVersion\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED FileVersion\n" + " REF: Page 56, section 5.3.\n")); + } + + errors ++; + } + + if (ppdFindAttr(ppd, "FormatVersion", NULL) != NULL) + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS FormatVersion\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED FormatVersion\n" + " REF: Page 56, section 5.3.\n")); + } + + errors ++; + } + + if (ppd->lang_encoding != NULL) + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS LanguageEncoding\n")); + } + else if (ppdversion > 40) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED LanguageEncoding\n" + " REF: Pages 56-57, section 5.3.\n")); + } + + errors ++; + } + + if (ppd->lang_version != NULL) + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS LanguageVersion\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED LanguageVersion\n" + " REF: Pages 57-58, section 5.3.\n")); + } + + errors ++; + } + + if (ppd->manufacturer != NULL) + { + if (!strncasecmp(ppd->manufacturer, "Hewlett-Packard", 15) || + !strncasecmp(ppd->manufacturer, "Hewlett Packard", 15)) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** BAD Manufacturer (should be " + "\"HP\")\n" + " REF: Page 211, table D.1.\n")); + } + + errors ++; + } + else if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS Manufacturer\n")); + } + else if (ppdversion >= 43) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED Manufacturer\n" + " REF: Pages 58-59, section 5.3.\n")); + } + + errors ++; + } + + if (ppd->modelname != NULL) + { + for (ptr = ppd->modelname; *ptr; ptr ++) + if (!isalnum(*ptr & 255) && !strchr(" ./-+", *ptr)) + break; + + if (*ptr) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** BAD ModelName - \"%c\" not " + "allowed in string.\n" + " REF: Pages 59-60, section 5.3.\n"), + *ptr); + } + + errors ++; + } + else if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS ModelName\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED ModelName\n" + " REF: Pages 59-60, section 5.3.\n")); + } + + errors ++; + } + + if (ppd->nickname != NULL) + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS NickName\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED NickName\n" + " REF: Page 60, section 5.3.\n")); + } + + errors ++; + } + + if (ppdFindOption(ppd, "PageSize") != NULL) + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS PageSize\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED PageSize\n" + " REF: Pages 99-100, section 5.14.\n")); + } + + errors ++; + } + + if (ppdFindOption(ppd, "PageRegion") != NULL) + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS PageRegion\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED PageRegion\n" + " REF: Page 100, section 5.14.\n")); + } + + errors ++; + } + + if (ppd->pcfilename != NULL) + { + if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS PCFileName\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED PCFileName\n" + " REF: Pages 61-62, section 5.3.\n")); + } + + errors ++; + } + + if (ppd->product != NULL) + { + if (ppd->product[0] != '(' || + ppd->product[strlen(ppd->product) - 1] != ')') + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** BAD Product - not \"(string)\".\n" + " REF: Page 62, section 5.3.\n")); + } + + errors ++; + } + else if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS Product\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED Product\n" + " REF: Page 62, section 5.3.\n")); + } + + errors ++; + } + + if ((attr = ppdFindAttr(ppd, "PSVersion", NULL)) != NULL && + attr->value != NULL) + { + char junkstr[255]; /* Temp string */ + int junkint; /* Temp integer */ + + + if (sscanf(attr->value, "(%[^)])%d", junkstr, &junkint) != 2) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** BAD PSVersion - not \"(string) " + "int\".\n" + " REF: Pages 62-64, section 5.3.\n")); + } + + errors ++; + } + else if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS PSVersion\n")); + } + else + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED PSVersion\n" + " REF: Pages 62-64, section 5.3.\n")); + } + + errors ++; + } + + if (ppd->shortnickname != NULL) + { + if (strlen(ppd->shortnickname) > 31) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** BAD ShortNickName - longer " + "than 31 chars.\n" + " REF: Pages 64-65, section 5.3.\n")); + } + + errors ++; + } + else if (verbose > 0) + _cupsLangPuts(stdout, NULL, _(" PASS ShortNickName\n")); + } + else if (ppdversion >= 43) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED ShortNickName\n" + " REF: Page 64-65, section 5.3.\n")); + } + + errors ++; + } + + if (ppd->patches != NULL && strchr(ppd->patches, '\"') && + strstr(ppd->patches, "*End")) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** BAD JobPatchFile attribute in file\n" + " REF: Page 24, section 3.4.\n")); + } + + errors ++; + } + + /* + * Check for page sizes without the corresponding ImageableArea or + * PaperDimension values... + */ + + if (ppd->num_sizes == 0) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPuts(stdout, NULL, + _(" **FAIL** REQUIRED PageSize\n" + " REF: Page 41, section 5.\n" + " REF: Page 99, section 5.14.\n")); + } + + errors ++; + } + else + { + for (j = 0, size = ppd->sizes; j < ppd->num_sizes; j ++, size ++) + { + /* + * Don't check custom size... + */ + + if (!strcmp(size->name, "Custom")) + continue; + + /* + * Check for ImageableArea... + */ + + if (size->left == 0.0 && size->bottom == 0.0 && + size->right == 0.0 && size->top == 0.0) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** REQUIRED ImageableArea for " + "PageSize %s\n" + " REF: Page 41, section 5.\n" + " REF: Page 102, section 5.15.\n"), + size->name); + } + + errors ++; + } + + /* + * Check for PaperDimension... + */ + + if (size->width == 0.0 && size->length == 0.0) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** REQUIRED PaperDimension " + "for PageSize %s\n" + " REF: Page 41, section 5.\n" + " REF: Page 103, section 5.15.\n"), + size->name); + } + + errors ++; + } + } + } + + /* + * Check for valid Resolution, JCLResolution, or SetResolution values... + */ + + if ((option = ppdFindOption(ppd, "Resolution")) == NULL) + if ((option = ppdFindOption(ppd, "JCLResolution")) == NULL) + option = ppdFindOption(ppd, "SetResolution"); + + if (option != NULL) + { + for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++) + { + /* + * Verify that all resolution options are of the form NNNdpi + * or NNNxNNNdpi... + */ + + xdpi = strtol(choice->choice, (char **)&ptr, 10); + if (ptr > choice->choice && xdpi > 0) + { + if (*ptr == 'x') + ydpi = strtol(ptr + 1, (char **)&ptr, 10); + else + ydpi = xdpi; + } + else + ydpi = xdpi; + + if (xdpi <= 0 || ydpi <= 0 || strcmp(ptr, "dpi")) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** Bad %s choice %s!\n" + " REF: Page 84, section 5.9\n"), + option->keyword, choice->choice); + } + + errors ++; + } + } + } + + /* + * Check for a duplex option, and for standard values... + */ + + if ((option = ppdFindOption(ppd, "Duplex")) == NULL) + if ((option = ppdFindOption(ppd, "JCLDuplex")) == NULL) + if ((option = ppdFindOption(ppd, "EFDuplex")) == NULL) + option = ppdFindOption(ppd, "KD03Duplex"); + + if (option != NULL) + { + if (ppdFindChoice(option, "None") == NULL) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** REQUIRED %s does not define " + "choice None!\n" + " REF: Page 122, section 5.17\n"), + option->keyword); + } + + errors ++; + } + + for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++) + if (strcmp(choice->choice, "None") && + strcmp(choice->choice, "DuplexNoTumble") && + strcmp(choice->choice, "DuplexTumble") && + strcmp(choice->choice, "SimplexTumble")) + { + if (verbose >= 0) + { + if (!errors && !verbose) + _cupsLangPuts(stdout, NULL, _(" FAIL\n")); + + _cupsLangPrintf(stdout, NULL, + _(" **FAIL** Bad %s choice %s!\n" + " REF: Page 122, section 5.17\n"), + option->keyword, choice->choice); + } + + errors ++; + } + } + + if (errors) + status = ERROR_CONFORMANCE; + else if (!verbose) + _cupsLangPuts(stdout, NULL, _(" PASS\n")); + + if (verbose >= 0) + { + if (option && + strcmp(option->keyword, "Duplex") && + strcmp(option->keyword, "JCLDuplex")) + { + _cupsLangPrintf(stdout, NULL, + _(" WARN Duplex option keyword %s " + "should be named Duplex or JCLDuplex!\n" + " REF: Page 122, section 5.17\n"), + option->keyword); + } + + ppdMarkDefaults(ppd); + if (ppdConflicts(ppd)) + { + _cupsLangPuts(stdout, NULL, + _(" WARN Default choices conflicting!\n")); + + show_conflicts(ppd); + } + + if (ppdversion < 43) + { + _cupsLangPrintf(stdout, NULL, + _(" WARN Obsolete PPD version %.1f!\n" + " REF: Page 42, section 5.2.\n"), + 0.1f * ppdversion); + } + + if (!ppd->lang_encoding && ppdversion < 41) + { + _cupsLangPuts(stdout, NULL, + _(" WARN LanguageEncoding required by PPD " + "4.3 spec.\n" + " REF: Pages 56-57, section 5.3.\n")); + } + + if (!ppd->manufacturer && ppdversion < 43) + { + _cupsLangPuts(stdout, NULL, + _(" WARN Manufacturer required by PPD " + "4.3 spec.\n" + " REF: Pages 58-59, section 5.3.\n")); + } + + /* + * Treat a PCFileName attribute longer than 12 characters as + * a warning and not a hard error... + */ + + if (ppd->pcfilename && strlen(ppd->pcfilename) > 12) + { + _cupsLangPuts(stdout, NULL, + _(" WARN PCFileName longer than 8.3 in " + "violation of PPD spec.\n" + " REF: Pages 61-62, section 5.3.\n")); + } + + if (!ppd->shortnickname && ppdversion < 43) + { + _cupsLangPuts(stdout, NULL, + _(" WARN ShortNickName required by PPD " + "4.3 spec.\n" + " REF: Pages 64-65, section 5.3.\n")); + } + + /* + * Check the Protocols line and flag PJL + BCP since TBCP is + * usually used with PJL... + */ + + if (ppd->protocols) + { + if (strstr(ppd->protocols, "PJL") && + strstr(ppd->protocols, "BCP") && + !strstr(ppd->protocols, "TBCP")) + { + _cupsLangPuts(stdout, NULL, + _(" WARN Protocols contains both PJL " + "and BCP; expected TBCP.\n" + " REF: Pages 78-79, section 5.7.\n")); + } + + if (strstr(ppd->protocols, "PJL") && + (!ppd->jcl_begin || !ppd->jcl_end || !ppd->jcl_ps)) + { + _cupsLangPuts(stdout, NULL, + _(" WARN Protocols contains PJL but JCL " + "attributes are not set.\n" + " REF: Pages 78-79, section 5.7.\n")); + } + } + + /* + * Check for options with a common prefix, e.g. Duplex and Duplexer, + * which are errors according to the spec but won't cause problems + * with CUPS specifically... + */ + + for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) + for (k = 0, option = group->options; k < group->num_options; k ++, option ++) + { + len = strlen(option->keyword); + + for (m = 0, group2 = ppd->groups; + m < ppd->num_groups; + m ++, group2 ++) + for (n = 0, option2 = group2->options; + n < group2->num_options; + n ++, option2 ++) + if (option != option2 && + len < strlen(option2->keyword) && + !strncmp(option->keyword, option2->keyword, len)) + { + _cupsLangPrintf(stdout, NULL, + _(" WARN %s shares a common " + "prefix with %s\n" + " REF: Page 15, section " + "3.2.\n"), + option->keyword, option2->keyword); + } + } + } + + if (verbose > 0) + { + if (errors) + _cupsLangPrintf(stdout, NULL, _(" %d ERROR%s FOUND\n"), + errors, errors == 1 ? "" : "S"); + else + _cupsLangPuts(stdout, NULL, _(" NO ERRORS FOUND\n")); + } + + + /* + * Then list the options, if "-v" was provided... + */ + + if (verbose > 1) + { + _cupsLangPrintf(stdout, NULL, + "\n" + " language_level = %d\n" + " color_device = %s\n" + " variable_sizes = %s\n" + " landscape = %d\n", + ppd->language_level, + ppd->color_device ? "TRUE" : "FALSE", + ppd->variable_sizes ? "TRUE" : "FALSE", + ppd->landscape); + + switch (ppd->colorspace) + { + case PPD_CS_CMYK : + _cupsLangPuts(stdout, NULL, " colorspace = PPD_CS_CMYK\n"); + break; + case PPD_CS_CMY : + _cupsLangPuts(stdout, NULL, " colorspace = PPD_CS_CMY\n"); + break; + case PPD_CS_GRAY : + _cupsLangPuts(stdout, NULL, " colorspace = PPD_CS_GRAY\n"); + break; + case PPD_CS_RGB : + _cupsLangPuts(stdout, NULL, " colorspace = PPD_CS_RGB\n"); + break; + default : + _cupsLangPuts(stdout, NULL, " colorspace = \n"); + break; + } + + _cupsLangPrintf(stdout, NULL, " num_emulations = %d\n", + ppd->num_emulations); + for (j = 0; j < ppd->num_emulations; j ++) + _cupsLangPrintf(stdout, NULL, " emulations[%d] = %s\n", + j, ppd->emulations[j].name); + + _cupsLangPrintf(stdout, NULL, " lang_encoding = %s\n", + ppd->lang_encoding); + _cupsLangPrintf(stdout, NULL, " lang_version = %s\n", + ppd->lang_version); + _cupsLangPrintf(stdout, NULL, " modelname = %s\n", ppd->modelname); + _cupsLangPrintf(stdout, NULL, " ttrasterizer = %s\n", + ppd->ttrasterizer == NULL ? "None" : ppd->ttrasterizer); + _cupsLangPrintf(stdout, NULL, " manufacturer = %s\n", + ppd->manufacturer); + _cupsLangPrintf(stdout, NULL, " product = %s\n", ppd->product); + _cupsLangPrintf(stdout, NULL, " nickname = %s\n", ppd->nickname); + _cupsLangPrintf(stdout, NULL, " shortnickname = %s\n", + ppd->shortnickname); + _cupsLangPrintf(stdout, NULL, " patches = %d bytes\n", + ppd->patches == NULL ? 0 : (int)strlen(ppd->patches)); + + _cupsLangPrintf(stdout, NULL, " num_groups = %d\n", ppd->num_groups); + for (j = 0, group = ppd->groups; j < ppd->num_groups; j ++, group ++) + { + _cupsLangPrintf(stdout, NULL, " group[%d] = %s\n", + j, group->text); + + for (k = 0, option = group->options; k < group->num_options; k ++, option ++) + { + _cupsLangPrintf(stdout, NULL, + " 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") || + !strcmp(option->keyword, "PageRegion")) + { + for (m = option->num_choices, choice = option->choices; + m > 0; + m --, choice ++) + { + size = ppdPageSize(ppd, choice->choice); + + if (size == NULL) + _cupsLangPrintf(stdout, NULL, + " %s (%s) = ERROR", + choice->choice, choice->text); + else + _cupsLangPrintf(stdout, NULL, + " %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)) + _cupsLangPuts(stdout, NULL, " *\n"); + else + _cupsLangPuts(stdout, NULL, "\n"); + } + } + else + { + for (m = option->num_choices, choice = option->choices; + m > 0; + m --, choice ++) + { + _cupsLangPrintf(stdout, NULL, " %s (%s)", + choice->choice, choice->text); + + if (!strcmp(option->defchoice, choice->choice)) + _cupsLangPuts(stdout, NULL, " *\n"); + else + _cupsLangPuts(stdout, NULL, "\n"); + } + } + } + } + + _cupsLangPrintf(stdout, NULL, " num_profiles = %d\n", + ppd->num_profiles); + for (j = 0; j < ppd->num_profiles; j ++) + _cupsLangPrintf(stdout, NULL, + " 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]); + + _cupsLangPrintf(stdout, NULL, " num_fonts = %d\n", ppd->num_fonts); + for (j = 0; j < ppd->num_fonts; j ++) + _cupsLangPrintf(stdout, NULL, " fonts[%d] = %s\n", + j, ppd->fonts[j]); + + _cupsLangPrintf(stdout, NULL, " num_attrs = %d\n", ppd->num_attrs); + for (j = 0; j < ppd->num_attrs; j ++) + _cupsLangPrintf(stdout, NULL, + " attrs[%d] = %s %s%s%s: \"%s\"\n", j, + ppd->attrs[j]->name, ppd->attrs[j]->spec, + ppd->attrs[j]->text[0] ? "/" : "", + ppd->attrs[j]->text, + ppd->attrs[j]->value ? + ppd->attrs[j]->value : "(null)"); + } + + ppdClose(ppd); + } + + if (!files) + usage(); + + return (status); +} + + +/* + * 'show_conflicts()' - Show option conflicts in a PPD file. + */ + +void +show_conflicts(ppd_file_t *ppd) /* I - PPD to check */ +{ + int i, j; /* Looping variables */ + ppd_const_t *c; /* Current constraint */ + ppd_option_t *o1, *o2; /* Options */ + ppd_choice_t *c1, *c2; /* Choices */ + + + /* + * Loop through all of the UI constraints and report 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") || + !strcasecmp(c1->choice, "Off") || + !strcasecmp(c1->choice, "False")) + 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") || + !strcasecmp(c2->choice, "Off") || + !strcasecmp(c2->choice, "False")) + c2 = NULL; + } + + /* + * If both options are marked then there is a conflict... + */ + + if (c1 != NULL && c1->marked && c2 != NULL && c2->marked) + _cupsLangPrintf(stdout, NULL, + _(" WARN \"%s %s\" conflicts with \"%s %s\"\n" + " (constraint=\"%s %s %s %s\")\n"), + o1->keyword, c1->choice, o2->keyword, c2->choice, + c->option1, c->choice1, c->option2, c->choice2); + } +} + + +/* + * 'usage()' - Show program usage... + */ + +void +usage(void) +{ + _cupsLangPuts(stdout, NULL, + _("Usage: cupstestppd [-q] [-r] [-v[v]] filename1.ppd[.gz] " + "[... filenameN.ppd[.gz]]\n" + " program | cupstestppd [-q] [-r] [-v[v]] -\n")); + + exit(ERROR_USAGE); +} + + +/* + * End of "$Id: cupstestppd.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/lp.c b/systemv/lp.c new file mode 100644 index 000000000..13acd1676 --- /dev/null +++ b/systemv/lp.c @@ -0,0 +1,813 @@ +/* + * "$Id: lp.c 4906 2006-01-10 20:53:28Z mike $" + * + * "lp" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and send files for printing. + * restart_job() - Restart a job. + * set_job_attrs() - Set job attributes. + * sighandler() - Signal catcher for when we print from stdin... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include + + +#ifndef WIN32 +# include +# include + + +/* + * Local functions. + */ + +void sighandler(int); +#endif /* !WIN32 */ +int restart_job(int job_id); +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 */ + struct sigaction oldaction; /* Old 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")) + 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] == '-' && argv[i][1]) + switch (argv[i][1]) + { + case 'E' : /* Encrypt */ +#ifdef HAVE_SSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); +#else + _cupsLangPrintf(stderr, NULL, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected destination after -d option!\n")); + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected form after -f option!\n")); + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected hostname after -h option!\n")); + return (1); + } + + cupsSetServer(argv[i]); + } + break; + + case 'i' : /* Change job */ + if (argv[i][2]) + val = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected job ID after -i option!\n")); + return (1); + } + + val = argv[i]; + } + + if (num_files > 0) + { + _cupsLangPuts(stderr, NULL, + _("lp: Error - cannot print files and alter " + "jobs simultaneously!\n")); + return (1); + } + + if (strrchr(val, '-') != NULL) + job_id = atoi(strrchr(val, '-') + 1); + else + job_id = atoi(val); + + if (job_id < 0) + { + _cupsLangPuts(stderr, NULL, _("lp: Error - bad job ID!\n")); + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected copies after -n option!\n")); + return (1); + } + + num_copies = atoi(argv[i]); + } + + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected option string after -o option!\n")); + 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 + { + if ((i + 1) >= argc) + { + _cupsLangPrintf(stderr, NULL, + _("lp: Expected priority after -%c option!\n"), + argv[i][1]); + return (1); + } + + i ++; + + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Priority must be between 1 and 100.\n")); + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected title after -t option!\n")); + return (1); + } + + title = argv[i]; + } + break; + + case 'y' : /* mode-list */ + if (!argv[i][2]) + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected mode list after -y option!\n")); + return (1); + } + } + + _cupsLangPuts(stderr, NULL, + _("lp: Warning - mode option ignored!\n")); + break; + + case 'H' : /* Hold job */ + if (argv[i][2]) + val = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected hold name after -H option!\n")); + return (1); + } + + val = argv[i]; + } + + if (!strcmp(val, "hold")) + num_options = cupsAddOption("job-hold-until", "indefinite", + num_options, &options); + else if (!strcmp(val, "resume") || + !strcmp(val, "release")) + num_options = cupsAddOption("job-hold-until", "no-hold", + num_options, &options); + else if (!strcmp(val, "immediate")) + num_options = cupsAddOption("job-priority", "100", + num_options, &options); + else if (!strcmp(val, "restart")) + { + if (job_id < 1) + { + _cupsLangPuts(stderr, NULL, + _("lp: Need job ID (-i) before \"-H restart\"!\n")); + return (1); + } + + if (restart_job(job_id)) + return (1); + } + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected page list after -P option!\n")); + 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) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected character set after -S option!\n")); + return (1); + } + } + + _cupsLangPuts(stderr, NULL, + _("lp: Warning - character set option ignored!\n")); + break; + + case 'T' : /* Content-Type */ + if (!argv[i][2]) + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lp: Expected content type after -T option!\n")); + return (1); + } + } + + _cupsLangPuts(stderr, NULL, + _("lp: Warning - content type option ignored!\n")); + break; + + default : + _cupsLangPrintf(stderr, NULL, _("lp: Unknown option \'%c\'!\n"), + argv[i][1]); + return (1); + } + else if (!strcmp(argv[i], "-")) + { + if (num_files || job_id) + { + _cupsLangPuts(stderr, NULL, + _("lp: Error - cannot print from stdin if files or a " + "job ID are provided!\n")); + return (1); + } + + break; + } + else if (num_files < 1000 && job_id == 0) + { + /* + * Print a file... + */ + + if (access(argv[i], R_OK) != 0) + { + _cupsLangPrintf(stderr, NULL, _("lp: Unable to access \"%s\" - %s\n"), + argv[i], strerror(errno)); + return (1); + } + + files[num_files] = argv[i]; + num_files ++; + + if (title == NULL) + { + if ((title = strrchr(argv[i], '/')) != NULL) + title ++; + else + title = argv[i]; + } + } + else + _cupsLangPrintf(stderr, NULL, _("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); + + if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) + { + printer = dest->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); + } + } + + if (printer == NULL) + { + val = NULL; + + if ((printer = getenv("LPDEST")) == NULL) + { + if ((printer = getenv("PRINTER")) != NULL) + { + if (!strcmp(printer, "lp")) + printer = NULL; + else + val = "PRINTER"; + } + } + else + val = "LPDEST"; + + if (printer && !cupsGetDest(printer, NULL, num_dests, dests)) + _cupsLangPrintf(stderr, NULL, + _("lp: error - %s environment variable names " + "non-existent destination \"%s\"!\n"), + val, printer); + else if (cupsLastError() == IPP_NOT_FOUND) + _cupsLangPuts(stderr, NULL, + _("lp: error - no default destination available.\n")); + else + _cupsLangPuts(stderr, NULL, + _("lp: error - scheduler not responding!\n")); + + 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); + if (sigset(SIGINT, sighandler) == SIG_IGN) + sigset(SIGINT, SIG_IGN); + sigset(SIGTERM, sighandler); +# elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = sighandler; + + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, NULL, &oldaction); + if (oldaction.sa_handler != SIG_IGN) + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); +# else + signal(SIGHUP, sighandler); + if (signal(SIGINT, sighandler) == SIG_IGN) + signal(SIGINT, SIG_IGN); + signal(SIGTERM, sighandler); +# endif +#endif /* !WIN32 */ + + temp = cupsTempFd(tempfile, sizeof(tempfile)); + + if (temp < 0) + { + _cupsLangPrintf(stderr, NULL, + _("lp: unable to create temporary file \"%s\" - %s\n"), + tempfile, strerror(errno)); + return (1); + } + + while ((i = read(0, buffer, sizeof(buffer))) > 0) + if (write(temp, buffer, i) < 0) + { + _cupsLangPrintf(stderr, NULL, + _("lp: error - unable to write to temporary file " + "\"%s\" - %s\n"), + tempfile, strerror(errno)); + close(temp); + unlink(tempfile); + return (1); + } + + i = lseek(temp, 0, SEEK_CUR); + close(temp); + + if (i == 0) + { + _cupsLangPuts(stderr, NULL, + _("lp: stdin is empty, so no job has been sent.\n")); + unlink(tempfile); + 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) + { + _cupsLangPrintf(stderr, NULL, + _("lp: unable to print file: %s\n"), + ippErrorString(cupsLastError())); + return (1); + } + else if (!silent) + _cupsLangPrintf(stdout, NULL, + _("request id is %s-%d (%d file(s))\n"), + printer, job_id, num_files); + + return (0); +} + + +/* + * 'restart_job()' - Restart a job. + */ + +int /* O - Exit status */ +restart_job(int job_id) /* I - Job ID */ +{ + 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_RESTART_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", 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()); + + if ((response = cupsDoRequest(http, request, "/jobs")) != NULL) + { + if (response->request.status.status_code > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, NULL, _("lp: restart-job failed: %s\n"), + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (1); + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, NULL, _("lp: restart-job failed: %s\n"), + ippErrorString(cupsLastError())); + return (1); + } + + 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 */ + + + if (num_options == 0) + return (0); + + 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) + { + _cupsLangPrintf(stderr, NULL, _("lp: set-job-attributes failed: %s\n"), + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (1); + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, NULL, _("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: lp.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/lpadmin.c b/systemv/lpadmin.c new file mode 100644 index 000000000..4f12b43e4 --- /dev/null +++ b/systemv/lpadmin.c @@ -0,0 +1,2173 @@ +/* + * "$Id: lpadmin.c 4906 2006-01-10 20:53:28Z mike $" + * + * "lpadmin" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * 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 + * valid chars... + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBZ +# include +#endif /* HAVE_LIBZ */ + + +/* + * Local functions... + */ + +static int add_printer_to_class(http_t *, char *, char *); +static int default_printer(http_t *, char *); +static int delete_printer(http_t *, char *); +static int delete_printer_from_class(http_t *, char *, char *); +static int enable_printer(http_t *, char *); +static char *get_line(char *, int, FILE *fp); +static int set_printer_device(http_t *, char *, char *); +static int set_printer_file(http_t *, char *, char *); +static int set_printer_info(http_t *, char *, char *); +static int set_printer_location(http_t *, char *, char *); +static int set_printer_model(http_t *, char *, char *); +static int 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 = NULL; + printer = NULL; + num_options = 0; + options = NULL; + + 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(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to add a printer to the class:\n" + " You must specify a printer name " + "first!\n")); + return (1); + } + + if (argv[i][2]) + pclass = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected class name after \'-c\' " + "option!\n")); + return (1); + } + + pclass = argv[i]; + } + + if (!validate_name(pclass)) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Class name can only contain printable " + "characters!\n")); + return (1); + } + + if (add_printer_to_class(http, printer, pclass)) + return (1); + break; + + case 'd' : /* Set as default destination */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (argv[i][2]) + printer = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected printer name after \'-d\' " + "option!\n")); + return (1); + } + + printer = argv[i]; + } + + if (!validate_name(printer)) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Printer name can only contain " + "printable characters!\n")); + return (1); + } + + if (default_printer(http, printer)) + return (1); + + i = argc; + break; + + case 'h' : /* Connect to host */ + if (http) + { + httpClose(http); + http = NULL; + } + + if (argv[i][2] != '\0') + cupsSetServer(argv[i] + 2); + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected hostname after \'-h\' " + "option!\n")); + return (1); + } + + cupsSetServer(argv[i]); + } + break; + + case 'i' : /* Use the specified interface script */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to set the interface script:\n" + " You must specify a printer name " + "first!\n")); + return (1); + } + + if (argv[i][2]) + { + if (set_printer_file(http, printer, argv[i] + 2)) + return (1); + } + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected interface after \'-i\' " + "option!\n")); + return (1); + } + + if (set_printer_file(http, printer, argv[i])) + return (1); + } + break; + + case 'E' : /* Enable the printer */ + if (printer == NULL) + { +#ifdef HAVE_SSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + + if (http) + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); +#else + _cupsLangPrintf(stderr, NULL, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + break; + } + + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (enable_printer(http, printer)) + return (1); + break; + + case 'm' : /* Use the specified standard script/PPD file */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to set the interface script or " + "PPD file:\n" + " You must specify a printer name " + "first!\n")); + return (1); + } + + if (argv[i][2]) + { + if (set_printer_model(http, printer, argv[i] + 2)) + return (1); + } + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected model after \'-m\' " + "option!\n")); + return (1); + } + + if (set_printer_model(http, printer, argv[i])) + return (1); + } + break; + + case 'o' : /* Set option */ + if (argv[i][2]) + num_options = cupsParseOptions(argv[i] + 2, num_options, &options); + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected name=value after \'-o\' " + "option!\n")); + return (1); + } + + num_options = cupsParseOptions(argv[i], num_options, &options); + } + break; + + case 'p' : /* Add/modify a printer */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (argv[i][2]) + printer = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected printer after \'-p\' " + "option!\n")); + return (1); + } + + printer = argv[i]; + } + + if (!validate_name(printer)) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Printer name can only contain " + "printable characters!\n")); + return (1); + } + break; + + case 'r' : /* Remove printer from class */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to remove a printer from the " + "class:\n" + " You must specify a printer name " + "first!\n")); + return (1); + } + + if (argv[i][2]) + pclass = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected class after \'-r\' " + "option!\n")); + return (1); + } + + pclass = argv[i]; + } + + if (!validate_name(pclass)) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Class name can only contain printable " + "characters!\n")); + return (1); + } + + if (delete_printer_from_class(http, printer, pclass)) + return (1); + break; + + case 'u' : /* Allow/deny users */ + if (argv[i][2]) + val = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected allow/deny:userlist after " + "\'-u\' option!\n")); + return (1); + } + + val = argv[i]; + } + + if (!strncasecmp(val, "allow:", 6)) + num_options = cupsAddOption("requesting-user-name-allowed", + val + 6, num_options, &options); + else if (!strncasecmp(val, "deny:", 5)) + num_options = cupsAddOption("requesting-user-name-denied", + val + 5, num_options, &options); + else + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unknown allow/deny option \"%s\"!\n"), + val); + return (1); + } + break; + + case 'v' : /* Set the device-uri attribute */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to set the device URI:\n" + " You must specify a printer name " + "first!\n")); + return (1); + } + + if (argv[i][2]) + { + if (set_printer_device(http, printer, argv[i] + 2)) + return (1); + } + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected device URI after \'-v\' " + "option!\n")); + return (1); + } + + if (set_printer_device(http, printer, argv[i])) + return (1); + } + break; + + case 'x' : /* Delete a printer */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (argv[i][2]) + printer = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected printer or class after " + "\'-x\' option!\n")); + return (1); + } + + printer = argv[i]; + } + + if (!validate_name(printer)) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Printer name can only contain " + "printable characters!\n")); + return (1); + } + + if (delete_printer(http, printer)) + return (1); + + i = argc; + break; + + case 'D' : /* Set the printer-info attribute */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to set the printer " + "description:\n" + " You must specify a printer name " + "first!\n")); + return (1); + } + + if (argv[i][2]) + { + if (set_printer_info(http, printer, argv[i] + 2)) + return (1); + } + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected description after " + "\'-D\' option!\n")); + return (1); + } + + if (set_printer_info(http, printer, argv[i])) + return (1); + } + break; + + case 'I' : /* Set the supported file types (ignored) */ + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected file type(s) after \'-I\' " + "option!\n")); + return (1); + } + + _cupsLangPuts(stderr, NULL, + _("lpadmin: Warning - content type list ignored!\n")); + break; + + case 'L' : /* Set the printer-location attribute */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to set the printer location:\n" + " You must specify a printer name " + "first!\n")); + return (1); + } + + if (argv[i][2]) + { + if (set_printer_location(http, printer, argv[i] + 2)) + return (1); + } + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected location after \'-L\' " + "option!\n")); + return (1); + } + + if (set_printer_location(http, printer, argv[i])) + return (1); + } + break; + + case 'P' : /* Use the specified PPD file */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to set the PPD file:\n" + " You must specify a printer name " + "first!\n")); + return (1); + } + + if (argv[i][2]) + { + if (set_printer_file(http, printer, argv[i] + 2)) + return (1); + } + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Expected PPD after \'-P\' option!\n")); + return (1); + } + + if (set_printer_file(http, printer, argv[i])) + return (1); + } + break; + + default : + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unknown option \'%c\'!\n"), argv[i][1]); + return (1); + } + else + { + _cupsLangPrintf(stderr, NULL, _("lpadmin: Unknown argument \'%s\'!\n"), + argv[i]); + return (1); + } + + /* + * Set options as needed... + */ + + if (num_options) + { + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (printer == NULL) + { + _cupsLangPuts(stderr, NULL, + _("lpadmin: Unable to set the printer options:\n" + " You must specify a printer name first!\n")); + return (1); + } + + if (set_printer_options(http, printer, num_options, options)) + return (1); + } + + if (printer == NULL) + { + _cupsLangPuts(stdout, NULL, + _("Usage:\n" + "\n" + " lpadmin [-h server] -d destination\n" + " lpadmin [-h server] -x destination\n" + " lpadmin [-h server] -p printer [-c add-class] " + "[-i interface] [-m model]\n" + " [-r remove-class] [-v device] " + "[-D description]\n" + " [-P ppd-file] [-o name=value]\n" + " [-u allow:user,user] " + "[-u deny:user,user]\n" + "\n")); + } + + if (http) + httpClose(http); + + return (0); +} + + +/* + * 'add_printer_to_class()' - Add a printer to a class. + */ + +static int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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 (0); + } + + /* + * OK, the printer isn't part of the class, so add it... + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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())); + + return (1); + } + 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); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'default_printer()' - Set the default printing destination. + */ + +static int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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())); + + return (1); + } + 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); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'delete_printer()' - Delete a printer from the system... + */ + +static int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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())); + + return (1); + } + 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); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'delete_printer_from_class()' - Delete a printer from a class. + */ + +static int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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 (1); + } + + /* + * 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 (1); + } + + 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 (1); + } + + 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())); + return (1); + } + 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); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'enable_printer()' - Enable a printer... + */ + +static int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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 (enable) failed: %s\n", + ippErrorString(cupsLastError())); + return (1); + } + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + fprintf(stderr, "lpadmin: add-printer (enable) failed: %s\n", + ippErrorString(response->request.status.status_code)); + + ippDelete(response); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * '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 int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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 (set device) failed: %s\n", + ippErrorString(cupsLastError())); + return (1); + } + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + fprintf(stderr, "lpadmin: add-printer (set device) failed: %s\n", + ippErrorString(response->request.status.status_code)); + + ippDelete(response); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'set_printer_file()' - Set the interface script or PPD file. + */ + +static int /* O - 0 on success, 1 on fail */ +set_printer_file(http_t *http, /* I - Server connection */ + char *printer, /* I - Printer */ + char *file) /* I - PPD file or interface script */ +{ + ipp_status_t status; /* IPP status code */ + 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")) + { + /* + * Yes, the file is compressed; uncompress to a temp file... + */ + + if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to create temporary file: %s\n"), + strerror(errno)); + return (1); + } + + if ((gz = gzopen(file, "rb")) == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to open file \"%s\": %s\n"), + file, strerror(errno)); + close(fd); + unlink(tempfile); + return (1); + } + + 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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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) + status = cupsLastError(); + else + { + status = response->request.status.status_code; + ippDelete(response); + } + +#ifdef HAVE_LIBZ + /* + * Remove the temporary file as needed... + */ + + if (file == tempfile) + unlink(tempfile); +#endif /* HAVE_LIBZ */ + + if (status > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: add-printer (set model) failed: %s\n"), + ippErrorString(status)); + + return (1); + } + else + return (0); +} + + +/* + * 'set_printer_info()' - Set the printer description string. + */ + +static int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: add-printer (set description) failed: %s\n"), + ippErrorString(cupsLastError())); + return (1); + } + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: add-printer (set description) failed: %s\n"), + ippErrorString(response->request.status.status_code)); + + ippDelete(response); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'set_printer_location()' - Set the printer location string. + */ + +static int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: add-printer (set location) failed: %s\n"), + ippErrorString(cupsLastError())); + + return (1); + } + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: add-printer (set location) failed: %s\n"), + ippErrorString(response->request.status.status_code)); + + ippDelete(response); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'set_printer_model()' - Set the driver model file. + */ + +static int /* O - 0 on success, 1 on fail */ +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 + */ + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: add-printer (set model) failed: %s\n"), + ippErrorString(cupsLastError())); + + return (1); + } + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: add-printer (set model) failed: %s\n"), + ippErrorString(response->request.status.status_code)); + + ippDelete(response); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'set_printer_options()' - Set the printer options. + */ + +static int /* O - 0 on success, 1 on fail */ +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 */ + const char *protocol; /* Protocol */ + + + DEBUG_printf(("set_printer_options(%p, \"%s\", %d, %p)\n", http, printer, + num_options, options)); + + language = cupsLangDefault(); + + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/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; + httpAssembleURIf(uri, sizeof(uri), "ipp", NULL, "localhost", 0, + "/classes/%s", printer); + } + } + + 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... + */ + + if ((outfd = cupsTempFd(tempfile, sizeof(tempfile))) < 0) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to create temporary file - %s\n"), + strerror(errno)); + ippDelete(request); + unlink(ppdfile); + return (1); + } + + if ((in = fopen(ppdfile, "rb")) == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpadmin: Unable to open PPD file \"%s\" - %s\n"), + ppdfile, strerror(errno)); + ippDelete(request); + unlink(ppdfile); + close(outfd); + unlink(tempfile); + return (1); + } + + out = fdopen(outfd, "wb"); + protocol = cupsGetOption("protocol", num_options, options); + + while (get_line(line, sizeof(line), in) != NULL) + { + if (!strncmp(line, "*cupsProtocol:", 14) && protocol) + { + /* + * Set a new output protocol (BCP or TBCP) below... + */ + + continue; + } + else if (strncmp(line, "*Default", 8)) + fprintf(out, "%s\n", line); + else + { + /* + * Get default option name... + */ + + strlcpy(keyword, line + 8, sizeof(keyword)); + + for (keyptr = keyword; *keyptr; keyptr ++) + if (*keyptr == ':' || isspace(*keyptr & 255)) + 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); + } + } + + if (protocol) + fprintf(out, "*cupsProtocol: \"%s\"\n", protocol); + + 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) + { + _cupsLangPrintf(stderr, NULL, _("lpadmin: %s failed: %s\n"), + op == CUPS_ADD_PRINTER ? "add-printer" : "add-class", + ippErrorString(cupsLastError())); + + return (1); + } + else if (response->request.status.status_code > IPP_OK_CONFLICT) + { + _cupsLangPrintf(stderr, NULL, _("lpadmin: %s failed: %s\n"), + op == CUPS_ADD_PRINTER ? "add-printer" : "add-class", + ippErrorString(response->request.status.status_code)); + + ippDelete(response); + + return (1); + } + else + { + ippDelete(response); + + return (0); + } +} + + +/* + * 'validate_name()' - Make sure the printer name only contains valid chars. + */ + +static int /* O - 0 if name is no good, 1 if name is good */ +validate_name(const char *name) /* I - Name to check */ +{ + const char *ptr; /* Pointer into name */ + + + /* + * Scan the whole name... + */ + + for (ptr = name; *ptr; ptr ++) + if (*ptr == '@') + break; + else if ((*ptr >= 0 && *ptr <= ' ') || *ptr == 127 || *ptr == '/' || + *ptr == '#') + return (0); + + /* + * All the characters are good; validate the length, too... + */ + + return ((ptr - name) < 128); +} + + +/* + * End of "$Id: lpadmin.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/lpinfo.c b/systemv/lpinfo.c new file mode 100644 index 000000000..41ffad206 --- /dev/null +++ b/systemv/lpinfo.c @@ -0,0 +1,466 @@ +/* + * "$Id: lpinfo.c 4906 2006-01-10 20:53:28Z mike $" + * + * "lpinfo" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and show information. + * show_devices() - Show available devices. + * show_models() - Show available PPDs. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * 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 = NULL; + long_status = 0; + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-') + switch (argv[i][1]) + { + case 'E' : /* Encrypt */ +#ifdef HAVE_SSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + + if (http) + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); +#else + _cupsLangPrintf(stderr, NULL, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + break; + + case 'l' : /* Show long listing */ + long_status = 1; + break; + + case 'm' : /* Show models */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpinfo: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (show_models(http, long_status)) + return (1); + break; + + case 'v' : /* Show available devices */ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpinfo: Unable to connect to server: %s\n"), + strerror(errno)); + return (1); + } + } + + if (show_devices(http, long_status)) + return (1); + break; + + case 'h' : /* Connect to host */ + if (http) + { + httpClose(http); + http = NULL; + } + + if (argv[i][2] != '\0') + cupsSetServer(argv[i] + 2); + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("Error: need hostname after \'-h\' option!\n")); + return (1); + } + + cupsSetServer(argv[i]); + } + break; + + default : + _cupsLangPrintf(stderr, NULL, _("lpinfo: Unknown option \'%c\'!\n"), + argv[i][1]); + return (1); + } + else + { + _cupsLangPrintf(stderr, NULL, _("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) + { + _cupsLangPrintf(stderr, NULL, _("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") && + attr->value_tag == IPP_TAG_KEYWORD) + device_class = attr->values[0].string.text; + + if (!strcmp(attr->name, "device-info") && + attr->value_tag == IPP_TAG_TEXT) + device_info = attr->values[0].string.text; + + if (!strcmp(attr->name, "device-make-and-model") && + attr->value_tag == IPP_TAG_TEXT) + device_make = attr->values[0].string.text; + + if (!strcmp(attr->name, "device-uri") && + 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) + { + _cupsLangPrintf(stdout, language, + _("Device: uri = %s\n" + " class = %s\n" + " info = %s\n" + " make-and-model = %s\n"), + device_uri, device_class, device_info, device_make); + } + else + _cupsLangPrintf(stdout, language, "%s %s\n", device_class, device_uri); + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, NULL, _("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) + { + _cupsLangPrintf(stderr, NULL, _("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") && + attr->value_tag == IPP_TAG_LANGUAGE) + ppd_language = attr->values[0].string.text; + + if (!strcmp(attr->name, "ppd-make-and-model") && + attr->value_tag == IPP_TAG_TEXT) + ppd_make = attr->values[0].string.text; + + if (!strcmp(attr->name, "ppd-name") && + 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) + { + _cupsLangPrintf(stdout, language, + _("Model: name = %s\n" + " natural_language = %s\n" + " make-and-model = %s\n"), + ppd_name, ppd_language, ppd_make); + } + else + _cupsLangPrintf(stdout, language, "%s %s\n", ppd_name, ppd_make); + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, NULL, _("lpinfo: cups-get-ppds failed: %s\n"), + ippErrorString(cupsLastError())); + + return (1); + } + + return (0); +} + + +/* + * End of "$Id: lpinfo.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/lpmove.c b/systemv/lpmove.c new file mode 100644 index 000000000..5980a972d --- /dev/null +++ b/systemv/lpmove.c @@ -0,0 +1,241 @@ +/* + * "$Id: lpmove.c 4906 2006-01-10 20:53:28Z mike $" + * + * "lpmove" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and move jobs. + * move_job() - Move a job. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include + + +/* + * 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 */ + int num_dests; /* Number of destinations */ + cups_dest_t *dests; /* Destinations */ + const char *dest; /* New destination */ + + + http = NULL; + job = NULL; + dest = NULL; + num_dests = 0; + dests = NULL; + + for (i = 1; i < argc; i ++) + if (argv[i][0] == '-') + switch (argv[i][1]) + { + case 'E' : /* Encrypt */ +#ifdef HAVE_SSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + + if (http) + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); +#else + _cupsLangPrintf(stderr, NULL, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + break; + + case 'h' : /* Connect to host */ + if (http) + { + httpClose(http); + http = NULL; + } + + if (argv[i][2] != '\0') + cupsSetServer(argv[i] + 2); + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("Error: need hostname after \'-h\' option!\n")); + return (1); + } + + cupsSetServer(argv[i]); + } + break; + + default : + _cupsLangPrintf(stderr, NULL, _("lpmove: Unknown option \'%c\'!\n"), + argv[i][1]); + return (1); + } + else if (job == NULL) + { + if (num_dests == 0) + num_dests = cupsGetDests(&dests); + + if ((job = strrchr(argv[i], '-')) != NULL && + cupsGetDest(argv[i], NULL, num_dests, dests) == NULL) + job ++; + else + job = argv[i]; + } + else if (dest == NULL) + dest = argv[i]; + else + { + _cupsLangPrintf(stderr, NULL, _("lpmove: Unknown argument \'%s\'!\n"), + argv[i]); + return (1); + } + + if (job == NULL || dest == NULL) + { + _cupsLangPuts(stdout, NULL, _("Usage: lpmove job dest\n")); + return (1); + } + + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpmove: Unable to connect to server: %s\n"), + strerror(errno)); + 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()); + + httpAssembleURIf(printer_uri, sizeof(printer_uri), "ipp", NULL, "localhost", 0, + "/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) + { + _cupsLangPrintf(stderr, NULL, _("lpmove: move-job failed: %s\n"), + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return; + } + + ippDelete(response); + } + else + _cupsLangPrintf(stderr, NULL, _("lpmove: move-job failed: %s\n"), + ippErrorString(cupsLastError())); +} + + +/* + * End of "$Id: lpmove.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/lpoptions.c b/systemv/lpoptions.c new file mode 100644 index 000000000..3792ab499 --- /dev/null +++ b/systemv/lpoptions.c @@ -0,0 +1,456 @@ +/* + * "$Id: lpoptions.c 4906 2006-01-10 20:53:28Z mike $" + * + * Printer option program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * 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 +#include +#include +#include +#include + + +/* + * 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) + { + _cupsLangPuts(stderr, NULL, + _("lpoptions: Unknown printer or class!\n")); + 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 ++) + 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 'h' : /* -h server */ + if (argv[i][2]) + cupsSetServer(argv[i] + 2); + else + { + i ++; + if (i >= argc) + usage(); + + cupsSetServer(argv[i]); + } + break; + + case 'E' : /* Encrypt connection */ + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + break; + + case 'l' : /* -l (list options) */ + if (dest == NULL) + { + if (num_dests == 0) + num_dests = cupsGetDests(&dests); + + if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) == NULL) + dest = dests; + } + + if (dest == NULL) + _cupsLangPuts(stderr, NULL, _("lpoptions: No printers!?!\n")); + 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) + { + _cupsLangPrintf(stderr, NULL, + _("lpoptions: Unable to add printer or " + "instance: %s\n"), + strerror(errno)); + return (1); + } + } + + 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 '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) + { + cupsFreeOptions(dest->num_options, dest->options); + + /* + * If we are "deleting" the default printer, then just set the + * number of options to 0; if it is also the system default + * then cupsSetDests() will remove it for us... + */ + + if (dest->is_default) + { + dest->num_options = 0; + dest->options = NULL; + } + else + { + 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; + changes = -1; + break; + + default : + usage(); + } + } + else + usage(); + + if (num_dests == 0) + num_dests = cupsGetDests(&dests); + + if (dest == NULL) + { + if ((dest = cupsGetDest(NULL, NULL, 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); + } + } + + 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) + _cupsLangPuts(stdout, NULL, " "); + + if (!options[i].value[0]) + _cupsLangPrintf(stdout, NULL, "%s", options[i].name); + else if (strchr(options[i].value, ' ') != NULL || + strchr(options[i].value, '\t') != NULL) + _cupsLangPrintf(stdout, NULL, "%s=\'%s\'", options[i].name, + options[i].value); + else + _cupsLangPrintf(stdout, NULL, "%s=%s", options[i].name, + options[i].value); + } + + _cupsLangPuts(stdout, NULL, "\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 ++) + { + _cupsLangPrintf(stdout, NULL, "%s/%s:", option->keyword, option->text); + + for (j = option->num_choices, choice = option->choices; j > 0; j --, choice ++) + if (choice->marked) + _cupsLangPrintf(stdout, NULL, " *%s", choice->choice); + else + _cupsLangPrintf(stdout, NULL, " %s", choice->choice); + + _cupsLangPuts(stdout, NULL, "\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) + { + _cupsLangPrintf(stderr, NULL, + _("lpoptions: Destination %s has no PPD file!\n"), + dest->name); + return; + } + + if ((ppd = ppdOpenFile(filename)) == NULL) + { + unlink(filename); + _cupsLangPrintf(stderr, NULL, + _("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) +{ + _cupsLangPuts(stdout, NULL, + _("Usage: lpoptions [-h server] [-E] -d printer\n" + " lpoptions [-h server] [-E] [-p printer] -l\n" + " lpoptions [-h server] [-E] -p printer -o " + "option[=value] ...\n" + " lpoptions [-h server] [-E] -x printer\n")); + + exit(1); +} + + +/* + * End of "$Id: lpoptions.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/lppasswd.c b/systemv/lppasswd.c new file mode 100644 index 000000000..306d29ff5 --- /dev/null +++ b/systemv/lppasswd.c @@ -0,0 +1,517 @@ +/* + * "$Id: lppasswd.c 4906 2006-01-10 20:53:28Z mike $" + * + * MD5 password program for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Add, change, or delete passwords from the MD5 password file. + * usage() - Show program usage. + */ + +/* + * Include necessary headers... + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef WIN32 +# include +# include +#endif /* !WIN32 */ + + +/* + * 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 */ + int error; /* Write error */ +#if defined(HAVE_SIGACTION) && !defined(HAVE_SIGSET) + struct sigaction action; /* Signal action */ +#endif /* HAVE_SIGACTION && !HAVE_SIGSET*/ + + + /* + * Check to see if stdin, stdout, and stderr are still open... + */ + + if (fcntl(0, F_GETFD, &i) || + fcntl(1, F_GETFD, &i) || + fcntl(2, F_GETFD, &i)) + { + /* + * No, return exit status 2 and don't try to send any output since + * someone is trying to bypass the security on the server. + */ + + return (2); + } + + /* + * Find the server directory... + * + * We use the CUPS_SERVERROOT environment variable when we are running + * as root or when lppasswd is not setuid... + */ + + if ((root = getenv("CUPS_SERVERROOT")) == NULL || + (getuid() != geteuid() && getuid())) + root = CUPS_SERVERROOT; + + snprintf(passwdmd5, sizeof(passwdmd5), "%s/passwd.md5", root); + snprintf(passwdold, sizeof(passwdold), "%s/passwd.old", root); + snprintf(passwdnew, sizeof(passwdnew), "%s/passwd.new", root); + + /* + * Find the default system group... + */ + + if (getgrnam(CUPS_DEFAULT_GROUP)) + groupname = CUPS_DEFAULT_GROUP; + 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() && getuid() != geteuid() && (op != CHANGE || username)) + { + _cupsLangPuts(stderr, NULL, + _("lppasswd: Only root can add or delete passwords!\n")); + 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) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: Unable to copy password string: %s\n"), + strerror(errno)); + 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) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: Unable to copy password string: %s\n"), + strerror(errno)); + return (1); + } + + if ((passwd = cupsGetPassword(_("Enter password again:"))) == NULL) + return (1); + + if (strcmp(passwd, newpass) != 0) + { + _cupsLangPuts(stderr, NULL, + _("lppasswd: Sorry, passwords don't match!\n")); + return (1); + } + + /* + * Check that the password contains at least one letter and number. + */ + + flag = 0; + + for (passwd = newpass; *passwd; passwd ++) + if (isdigit(*passwd & 255)) + flag |= 1; + else if (isalpha(*passwd & 255)) + 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) + { + _cupsLangPuts(stderr, NULL, + _("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")); + return (1); + } + } + + /* + * Ignore SIGHUP, SIGINT, SIGTERM, and SIGXFSZ (if defined) for the + * remainder of the time so that we won't end up with bogus password + * files... + */ + +#ifndef WIN32 +# if defined(HAVE_SIGSET) + sigset(SIGHUP, SIG_IGN); + sigset(SIGINT, SIG_IGN); + sigset(SIGTERM, SIG_IGN); +# ifdef SIGXFSZ + sigset(SIGXFSZ, SIG_IGN); +# endif /* SIGXFSZ */ +# elif defined(HAVE_SIGACTION) + memset(&action, 0, sizeof(action)); + action.sa_handler = SIG_IGN; + + sigaction(SIGHUP, &action, NULL); + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); +# ifdef SIGXFSZ + sigaction(SIGXFSZ, &action, NULL); +# endif /* SIGXFSZ */ +# else + signal(SIGHUP, SIG_IGN); + signal(SIGINT, SIG_IGN); + signal(SIGTERM, SIG_IGN); +# ifdef SIGXFSZ + signal(SIGXFSZ, SIG_IGN); +# endif /* SIGXFSZ */ +# endif +#endif /* !WIN32 */ + + /* + * Open the output file. + */ + + if ((fd = open(passwdnew, O_WRONLY | O_CREAT | O_EXCL, 0400)) < 0) + { + if (errno == EEXIST) + _cupsLangPuts(stderr, NULL, _("lppasswd: Password file busy!\n")); + else + _cupsLangPrintf(stderr, NULL, + _("lppasswd: Unable to open password file: %s\n"), + strerror(errno)); + + return (1); + } + + if ((outfile = fdopen(fd, "w")) == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: Unable to open password file: %s\n"), + strerror(errno)); + + unlink(passwdnew); + + return (1); + } + + setbuf(outfile, NULL); + + /* + * Open the existing password file and create a new one... + */ + + infile = fopen(passwdmd5, "r"); + if (infile == NULL && errno != ENOENT && op != ADD) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: Unable to open password file: %s\n"), + strerror(errno)); + + fclose(outfile); + + unlink(passwdnew); + + return (1); + } + + /* + * Read lines from the password file; the format is: + * + * username:group:MD5-sum + */ + + error = 0; + userline[0] = '\0'; + groupline[0] = '\0'; + md5line[0] = '\0'; + + 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; + + if (fputs(line, outfile) == EOF) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: Unable to write to password file: %s\n"), + strerror(errno)); + error = 1; + break; + } + } + + if (!error) + { + while (fgets(line, sizeof(line), infile) != NULL) + if (fputs(line, outfile) == EOF) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: Unable to write to password file: %s\n"), + strerror(errno)); + error = 1; + break; + } + } + } + + if (op == CHANGE && + (strcmp(username, userline) || strcmp(groupname, groupline))) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: user \"%s\" and group \"%s\" do not exist.\n"), + username, groupname); + error = 1; + } + else if (op != DELETE) + { + if (oldpass && + strcmp(httpMD5(username, "CUPS", oldpass, md5new), md5line) != 0) + { + _cupsLangPuts(stderr, NULL, + _("lppasswd: Sorry, password doesn't match!\n")); + error = 1; + } + else + { + snprintf(line, sizeof(line), "%s:%s:%s\n", username, groupname, + httpMD5(username, "CUPS", newpass, md5new)); + if (fputs(line, outfile) == EOF) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: Unable to write to password file: %s\n"), + strerror(errno)); + error = 1; + } + } + } + + /* + * Close the files... + */ + + if (infile) + fclose(infile); + + if (fclose(outfile) == EOF) + error = 1; + + /* + * Error out gracefully as needed... + */ + + if (error) + { + _cupsLangPuts(stderr, NULL, _("lppasswd: Password file not updated!\n")); + + unlink(passwdnew); + + return (1); + } + + /* + * Save old passwd file + */ + + unlink(passwdold); + if (link(passwdmd5, passwdold) && errno != ENOENT) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: failed to backup old password file: %s\n"), + strerror(errno)); + unlink(passwdnew); + return (1); + } + + /* + * Install new password file + */ + + if (rename(passwdnew, passwdmd5) < 0) + { + _cupsLangPrintf(stderr, NULL, + _("lppasswd: failed to rename password file: %s\n"), + strerror(errno)); + unlink(passwdnew); + return (1); + } + + return (0); +} + + +/* + * 'usage()' - Show program usage. + */ + +static void +usage(FILE *fp) /* I - File to send usage to */ +{ + if (getuid()) + { + _cupsLangPuts(fp, NULL, _("Usage: lppasswd [-g groupname]\n")); + } + else + { + _cupsLangPuts(fp, NULL, + _("Usage: lppasswd [-g groupname] [username]\n" + " lppasswd [-g groupname] -a [username]\n" + " lppasswd [-g groupname] -x [username]\n")); + } + + exit(1); +} + + +/* + * End of "$Id: lppasswd.c 4906 2006-01-10 20:53:28Z mike $". + */ diff --git a/systemv/lpstat.c b/systemv/lpstat.c new file mode 100644 index 000000000..d789f04e7 --- /dev/null +++ b/systemv/lpstat.c @@ -0,0 +1,2208 @@ +/* + * "$Id: lpstat.c 4922 2006-01-12 22:05:06Z mike $" + * + * "lpstat" command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2006 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and show status information. + * check_dest() - Verify that the named destination(s) exists. + * connect_server() - Connect to the server as necessary... + * 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 +#include +#include +#include +#include +#include +#include + + +/* + * Local functions... + */ + +static void check_dest(http_t *, const char *, int *, cups_dest_t **); +static http_t *connect_server(http_t *); +static int show_accepting(http_t *, const char *, int, cups_dest_t *); +static int show_classes(http_t *, const char *); +static void show_default(int, cups_dest_t *); +static int show_devices(http_t *, const char *, int, cups_dest_t *); +static int show_jobs(http_t *, const char *, const char *, int, int, + const char *); +static int 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 */ + status; /* Exit status */ + 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? */ + const char *which; /* Which jobs to show? */ + char op; /* Last operation on command-line */ + + +#ifdef LC_TIME + setlocale(LC_TIME, ""); +#endif /* LC_TIME */ + + http = NULL; + num_dests = 0; + dests = NULL; + long_status = 0; + ranking = 0; + status = 0; + which = "not-completed"; + op = 0; + + 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_SSL + cupsSetEncryption(HTTP_ENCRYPT_REQUIRED); + + if (http) + httpEncryption(http, HTTP_ENCRYPT_REQUIRED); +#else + _cupsLangPrintf(stderr, NULL, + _("%s: Sorry, no encryption support compiled in!\n"), + argv[0]); +#endif /* HAVE_SSL */ + break; + + case 'P' : /* Show paper types */ + op = 'P'; + break; + + case 'R' : /* Show ranking */ + ranking = 1; + break; + + case 'S' : /* Show charsets */ + op = 'S'; + if (!argv[i][2]) + i ++; + break; + + case 'W' : /* Show which jobs? */ + if (argv[i][2]) + which = argv[i] + 2; + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("lpstat: Need \"completed\" or " + "\"not-completed\" after -W!\n")); + return (1); + } + + which = argv[i]; + } + + if (strcmp(which, "completed") && strcmp(which, "not-completed")) + { + _cupsLangPuts(stderr, NULL, + _("lpstat: Need \"completed\" or " + "\"not-completed\" after -W!\n")); + return (1); + } + break; + + case 'a' : /* Show acceptance status */ + op = 'a'; + http = connect_server(http); + + if (argv[i][2] != '\0') + { + check_dest(http, argv[i] + 2, &num_dests, &dests); + + status |= show_accepting(http, argv[i] + 2, num_dests, dests); + } + else if ((i + 1) < argc && argv[i + 1][0] != '-') + { + i ++; + + check_dest(http, argv[i], &num_dests, &dests); + + status |= show_accepting(http, argv[i], num_dests, dests); + } + else + { + if (num_dests == 0) + num_dests = cupsGetDests2(http, &dests); + + status |= show_accepting(http, NULL, num_dests, dests); + } + break; + +#ifdef __sgi + case 'b' : /* Show both the local and remote status */ + op = 'b'; + http = connect_server(http); + + 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... + */ + + check_dest(http, argv[i] + 2, &num_dests, &dests); + + puts(""); + status |= show_jobs(http, argv[i] + 2, NULL, 3, ranking, which); + } + else + { + _cupsLangPuts(stderr, NULL, + _("lpstat: The -b option requires a destination " + "argument.\n")); + + return (1); + } + break; +#endif /* __sgi */ + + case 'c' : /* Show classes and members */ + op = 'c'; + http = connect_server(http); + + if (argv[i][2] != '\0') + { + check_dest(http, argv[i] + 2, &num_dests, &dests); + + status |= show_classes(http, argv[i] + 2); + } + else if ((i + 1) < argc && argv[i + 1][0] != '-') + { + i ++; + + check_dest(http, argv[i], &num_dests, &dests); + + status |= show_classes(http, argv[i]); + } + else + status |= show_classes(http, NULL); + break; + + case 'd' : /* Show default destination */ + op = 'd'; + http = connect_server(http); + + if (num_dests == 0) + num_dests = cupsGetDests2(http, &dests); + + show_default(num_dests, dests); + break; + + case 'f' : /* Show forms */ + op = 'f'; + if (!argv[i][2]) + i ++; + break; + + case 'h' : /* Connect to host */ + if (http) + { + httpClose(http); + http = NULL; + } + + if (argv[i][2] != '\0') + cupsSetServer(argv[i] + 2); + else + { + i ++; + + if (i >= argc) + { + _cupsLangPuts(stderr, NULL, + _("Error: need hostname after \'-h\' option!\n")); + return (1); + } + + cupsSetServer(argv[i]); + } + break; + + case 'l' : /* Long status or long job status */ +#ifdef __sgi + op = 'l'; + http = connect_server(http); + + if (argv[i][2] != '\0') + { + check_dest(http, argv[i] + 2, &num_dests, &dests); + + status |= show_jobs(http, argv[i] + 2, NULL, 3, ranking, which); + } + else +#endif /* __sgi */ + long_status = 2; + break; + + case 'o' : /* Show jobs by destination */ + op = 'o'; + http = connect_server(http); + + if (argv[i][2] != '\0') + { + check_dest(http, argv[i] + 2, &num_dests, &dests); + + status |= show_jobs(http, argv[i] + 2, NULL, long_status, + ranking, which); + } + else if ((i + 1) < argc && argv[i + 1][0] != '-') + { + i ++; + + check_dest(http, argv[i], &num_dests, &dests); + + status |= show_jobs(http, argv[i], NULL, long_status, + ranking, which); + } + else + status |= show_jobs(http, NULL, NULL, long_status, + ranking, which); + break; + + case 'p' : /* Show printers */ + op = 'p'; + http = connect_server(http); + + if (argv[i][2] != '\0') + { + check_dest(http, argv[i] + 2, &num_dests, &dests); + + status |= show_printers(http, argv[i] + 2, num_dests, dests, long_status); + } + else if ((i + 1) < argc && argv[i + 1][0] != '-') + { + i ++; + + check_dest(http, argv[i], &num_dests, &dests); + + status |= show_printers(http, argv[i], num_dests, dests, long_status); + } + else + { + if (num_dests == 0) + num_dests = cupsGetDests2(http, &dests); + + status |= show_printers(http, NULL, num_dests, dests, long_status); + } + break; + + case 'r' : /* Show scheduler status */ + op = 'r'; + http = connect_server(http); + + show_scheduler(http); + break; + + case 's' : /* Show summary */ + op = 's'; + http = connect_server(http); + + if (num_dests == 0) + num_dests = cupsGetDests2(http, &dests); + + show_default(num_dests, dests); + status |= show_classes(http, NULL); + status |= show_devices(http, NULL, num_dests, dests); + break; + + case 't' : /* Show all info */ + op = 't'; + http = connect_server(http); + + if (num_dests == 0) + num_dests = cupsGetDests2(http, &dests); + + show_scheduler(http); + show_default(num_dests, dests); + status |= show_classes(http, NULL); + status |= show_devices(http, NULL, num_dests, dests); + status |= show_accepting(http, NULL, num_dests, dests); + status |= show_printers(http, NULL, num_dests, dests, long_status); + status |= show_jobs(http, NULL, NULL, long_status, ranking, which); + break; + + case 'u' : /* Show jobs by user */ + op = 'u'; + http = connect_server(http); + + if (argv[i][2] != '\0') + status |= show_jobs(http, NULL, argv[i] + 2, long_status, + ranking, which); + else if ((i + 1) < argc && argv[i + 1][0] != '-') + { + i ++; + status |= show_jobs(http, NULL, argv[i], long_status, + ranking, which); + } + else + status |= show_jobs(http, NULL, NULL, long_status, + ranking, which); + break; + + case 'v' : /* Show printer devices */ + op = 'v'; + http = connect_server(http); + + if (argv[i][2] != '\0') + { + check_dest(http, argv[i] + 2, &num_dests, &dests); + + status |= show_devices(http, argv[i] + 2, num_dests, dests); + } + else if ((i + 1) < argc && argv[i + 1][0] != '-') + { + i ++; + + check_dest(http, argv[i], &num_dests, &dests); + + status |= show_devices(http, argv[i], num_dests, dests); + } + else + { + if (num_dests == 0) + num_dests = cupsGetDests2(http, &dests); + + status |= show_devices(http, NULL, num_dests, dests); + } + break; + + + default : + _cupsLangPrintf(stderr, NULL, + _("lpstat: Unknown option \'%c\'!\n"), argv[i][1]); + return (1); + } + else + { + http = connect_server(http); + + status |= show_jobs(http, argv[i], NULL, long_status, ranking, which); + op = 'o'; + } + + if (!op) + { + http = connect_server(http); + + status |= show_jobs(http, NULL, cupsUser(), long_status, ranking, which); + } + + return (status); +} + + +/* + * 'check_dest()' - Verify that the named destination(s) exists. + */ + +static void +check_dest(http_t *http, /* I - HTTP connection */ + const char *name, /* I - Name of printer/class(es) */ + int *num_dests, /* IO - Number of destinations */ + cups_dest_t **dests) /* IO - Destinations */ +{ + const char *dptr; + char *pptr, + printer[128]; + + + /* + * Load the destination list as necessary... + */ + + if (*num_dests == 0) + *num_dests = cupsGetDests2(http, dests); + + /* + * Scan the name string for printer/class name(s)... + */ + + for (dptr = name; *dptr != '\0';) + { + /* + * Skip leading whitespace and commas... + */ + + while (isspace(*dptr & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + + /* + * Extract a single destination name from the name string... + */ + + for (pptr = printer; !isspace(*dptr & 255) && *dptr != ',' && *dptr != '\0';) + { + if ((pptr - printer) < (sizeof(printer) - 1)) + *pptr++ = *dptr++; + else + { + _cupsLangPrintf(stderr, NULL, + _("lpstat: Invalid destination name in list \"%s\"!\n"), + name); + exit(1); + } + } + + *pptr = '\0'; + + /* + * Check the destination... + */ + + if (cupsGetDest(printer, NULL, *num_dests, *dests) == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpstat: Unknown destination \"%s\"!\n"), printer); + exit(1); + } + } +} + + +/* + * 'connect_server()' - Connect to the server as necessary... + */ + +static http_t * /* O - New HTTP connection */ +connect_server(http_t *http) /* I - Current HTTP connection */ +{ + if (!http) + { + http = httpConnectEncrypt(cupsServer(), ippPort(), + cupsEncryption()); + + if (http == NULL) + { + _cupsLangPrintf(stderr, NULL, + _("lpstat: Unable to connect to server %s on port %d: %s\n"), + cupsServer(), ippPort(), strerror(errno)); + exit(1); + } + } + + return (http); +} + + +/* + * 'show_accepting()' - Show acceptance status. + */ + +static int /* O - 0 on success, 1 on fail */ +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 */ + 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 (1); + + 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 = ippNewRequest(CUPS_GET_PRINTERS); + + 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) + { + _cupsLangPrintf(stderr, NULL, + _("lpstat: get-printers failed: %s\n"), + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (1); + } + + /* + * 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") && + attr->value_tag == IPP_TAG_NAME) + printer = attr->values[0].string.text; + + if (!strcmp(attr->name, "printer-state-message") && + attr->value_tag == IPP_TAG_TEXT) + message = attr->values[0].string.text; + + if (!strcmp(attr->name, "printer-is-accepting-jobs") && + 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 & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + + /* + * Compare names... + */ + + for (ptr = printer; + *ptr != '\0' && *dptr != '\0' && tolower(*ptr & 255) == tolower(*dptr & 255); + ptr ++, dptr ++); + + if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' || isspace(*dptr & 255))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr & 255) && *dptr != ',' && *dptr != '\0') + dptr ++; + while (isspace(*dptr & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + } + } + + /* + * Display the printer entry if needed... + */ + + if (match) + { + if (accepting) + _cupsLangPrintf(stdout, NULL, + _("%s accepting requests since Jan 01 00:00\n"), + printer); + else + _cupsLangPrintf(stdout, NULL, + _("%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) && dests[i].instance) + { + if (accepting) + _cupsLangPrintf(stdout, NULL, + _("%s/%s accepting requests since Jan 01 00:00\n"), + printer, dests[i].instance); + else + _cupsLangPrintf(stdout, NULL, + _("%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 + { + _cupsLangPrintf(stderr, NULL, _("lpstat: get-printers failed: %s\n"), + ippErrorString(cupsLastError())); + return (1); + } + + return (0); +} + + +/* + * 'show_classes()' - Show printer classes. + */ + +static int /* O - 0 on success, 1 on fail */ +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 */ + 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 (1); + + 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 = ippNewRequest(CUPS_GET_CLASSES); + + 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) + { + _cupsLangPrintf(stderr, NULL, + _("lpstat: get-classes failed: %s\n"), + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (1); + } + + /* + * 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") && + attr->value_tag == IPP_TAG_NAME) + printer = attr->values[0].string.text; + + if (!strcmp(attr->name, "printer-uri-supported") && + attr->value_tag == IPP_TAG_URI) + printer_uri = attr->values[0].string.text; + + if (!strcmp(attr->name, "member-names") && + 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) + { + httpSeparateURI(printer_uri, method, sizeof(method), + username, sizeof(username), server, sizeof(server), + &port, resource, sizeof(resource)); + + if (!strcasecmp(server, http->hostname)) + http2 = http; + else + http2 = httpConnectEncrypt(server, port, cupsEncryption()); + + if (http2 != NULL) + { + /* + * Build an IPP_GET_PRINTER_ATTRIBUTES request, which requires the + * following attributes: + * + * attributes-charset + * attributes-natural-language + * printer-uri + * requested-attributes + */ + + request = ippNewRequest(IPP_GET_PRINTER_ATTRIBUTES); + + 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); + + if (http2 != http) + 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 & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + + /* + * Compare names... + */ + + for (ptr = printer; + *ptr != '\0' && *dptr != '\0' && tolower(*ptr & 255) == tolower(*dptr & 255); + ptr ++, dptr ++); + + if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' || isspace(*dptr & 255))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr & 255) && *dptr != ',' && *dptr != '\0') + dptr ++; + while (isspace(*dptr & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + } + } + + /* + * Display the printer entry if needed... + */ + + if (match) + { + _cupsLangPrintf(stdout, NULL, _("members of class %s:\n"), printer); + + if (members) + { + for (i = 0; i < members->num_values; i ++) + _cupsLangPrintf(stdout, NULL, "\t%s\n", + members->values[i].string.text); + } + else + _cupsLangPuts(stdout, NULL, "\tunknown\n"); + } + + if (response2) + ippDelete(response2); + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, NULL, _("lpstat: get-classes failed: %s\n"), + ippErrorString(cupsLastError())); + return (1); + } + + return (0); +} + + +/* + * '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 */ +{ + cups_dest_t *dest; /* Destination */ + const char *printer, /* Printer name */ + *val; /* Environment variable name */ + + if ((dest = cupsGetDest(NULL, NULL, num_dests, dests)) != NULL) + { + if (dest->instance) + _cupsLangPrintf(stdout, NULL, _("system default destination: %s/%s\n"), + dest->name, dest->instance); + else + _cupsLangPrintf(stdout, NULL, _("system default destination: %s\n"), + dest->name); + } + else + { + val = NULL; + + if ((printer = getenv("LPDEST")) == NULL) + { + if ((printer = getenv("PRINTER")) != NULL) + { + if (!strcmp(printer, "lp")) + printer = NULL; + else + val = "PRINTER"; + } + } + else + val = "LPDEST"; + + if (printer && !cupsGetDest(printer, NULL, num_dests, dests)) + _cupsLangPrintf(stdout, NULL, + _("lpstat: error - %s environment variable names " + "non-existent destination \"%s\"!\n"), + val, printer); + else + _cupsLangPuts(stdout, NULL, _("no system default destination\n")); + } +} + + +/* + * 'show_devices()' - Show printer devices. + */ + +static int /* O - 0 on success, 1 on fail */ +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 */ + 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 (1); + + 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 = ippNewRequest(CUPS_GET_PRINTERS); + + 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) + { + _cupsLangPrintf(stderr, NULL, _("lpstat: get-printers failed: %s\n"), + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (1); + } + + /* + * 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") && + attr->value_tag == IPP_TAG_NAME) + printer = attr->values[0].string.text; + + if (!strcmp(attr->name, "printer-uri-supported") && + attr->value_tag == IPP_TAG_URI) + uri = attr->values[0].string.text; + + if (!strcmp(attr->name, "device-uri") && + 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 & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + + /* + * Compare names... + */ + + for (ptr = printer; + *ptr != '\0' && *dptr != '\0' && tolower(*ptr & 255) == tolower(*dptr & 255); + ptr ++, dptr ++); + + if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' || isspace(*dptr & 255))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr & 255) && *dptr != ',' && *dptr != '\0') + dptr ++; + while (isspace(*dptr & 255) || *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); + _cupsLangPrintf(stdout, NULL, + _("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) + _cupsLangPrintf(stdout, NULL, + _("Output for printer %s is sent to %s\n"), + printer, device + 5); + else + _cupsLangPrintf(stdout, NULL, + _("Output for printer %s is sent to %s\n"), + printer, device); + + for (i = 0; i < num_dests; i ++) + if (!strcasecmp(printer, dests[i].name) && dests[i].instance) + { + if (device == NULL) + _cupsLangPrintf(stdout, NULL, + _("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)) + _cupsLangPrintf(stdout, NULL, + _("Output for printer %s/%s is sent to %s\n"), + printer, dests[i].instance, device + 5); + else + _cupsLangPrintf(stdout, NULL, + _("Output for printer %s/%s is sent to %s\n"), + printer, dests[i].instance, device); + } +#else + if (device == NULL) + _cupsLangPrintf(stdout, NULL, _("device for %s: %s\n"), + printer, uri); + else if (!strncmp(device, "file:", 5)) + _cupsLangPrintf(stdout, NULL, _("device for %s: %s\n"), + printer, device + 5); + else + _cupsLangPrintf(stdout, NULL, _("device for %s: %s\n"), + printer, device); + + for (i = 0; i < num_dests; i ++) + if (!strcasecmp(printer, dests[i].name) && dests[i].instance) + { + if (device == NULL) + _cupsLangPrintf(stdout, NULL, _("device for %s/%s: %s\n"), + printer, dests[i].instance, uri); + else if (!strncmp(device, "file:", 5)) + _cupsLangPrintf(stdout, NULL, _("device for %s/%s: %s\n"), + printer, dests[i].instance, device + 5); + else + _cupsLangPrintf(stdout, NULL, _("device for %s/%s: %s\n"), + printer, dests[i].instance, device); + } +#endif /* __osf__ */ + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, NULL, _("lpstat: get-printers failed: %s\n"), + ippErrorString(cupsLastError())); + return (1); + } + + return (0); +} + + +/* + * 'show_jobs()' - Show active print jobs. + */ + +static int /* O - 0 on success, 1 on fail */ +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? */ + const char *which) /* I - Show which jobs? */ +{ + ipp_t *request, /* IPP Request */ + *response; /* IPP Response */ + ipp_attribute_t *attr; /* Current attribute */ + 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[255], /* Temporary buffer */ + date[255]; /* 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 (1); + + 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 = ippNewRequest(IPP_GET_JOBS); + + 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/"); + + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "which-jobs", + NULL, which); + + /* + * 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) + { + _cupsLangPrintf(stderr, NULL, _("lpstat: get-jobs failed: %s\n"), + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (1); + } + + 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; + + 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 & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + + /* + * Compare names... + */ + + for (ptr = dest; + *ptr != '\0' && *dptr != '\0' && tolower(*ptr & 255) == tolower(*dptr & 255); + ptr ++, dptr ++); + + if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' || isspace(*dptr & 255))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr & 255) && *dptr != ',' && *dptr != '\0') + dptr ++; + while (isspace(*dptr & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + } + } + + if (users != NULL && username != NULL) + { + for (dptr = users; *dptr != '\0';) + { + /* + * Skip leading whitespace and commas... + */ + + while (isspace(*dptr & 255) || *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 & 255))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr & 255) && *dptr != ',' && *dptr != '\0') + dptr ++; + while (isspace(*dptr & 255) || *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... + */ + + if (!strftime(date, sizeof(date), "%b %d %H:%M", jobdate)) + strcpy(date, "Unknown"); + + _cupsLangPrintf(stdout, NULL, "%s;%s;%d;%s;%s\n", + temp, username ? username : "unknown", + size, title ? title : "unknown", date); + } + else + { + if (!strftime(date, sizeof(date), "%c", jobdate)) + strcpy(date, "Unknown"); + + if (ranking) + _cupsLangPrintf(stdout, NULL, "%3d %-21s %-13s %8.0f %s\n", + rank, temp, username ? username : "unknown", + 1024.0 * size, date); + else + _cupsLangPrintf(stdout, NULL, "%-23s %-13s %8.0f %s\n", + temp, username ? username : "unknown", + 1024.0 * size, date); + if (long_status) + _cupsLangPrintf(stdout, NULL, _("\tqueued for %s\n"), dest); + } + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, NULL, _("lpstat: get-jobs failed: %s\n"), + ippErrorString(cupsLastError())); + return (1); + } + + return (0); +} + + +/* + * 'show_printers()' - Show printers. + */ + +static int /* O - 0 on success, 1 on fail */ +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 */ + *jobattr, /* Job ID attribute */ + *reasons; /* Job state reasons attribute */ + const char *printer, /* Printer name */ + *message, /* Printer state message */ + *description, /* Description of printer */ + *location, /* Location of printer */ + *make_model, /* Make and model of printer */ + *uri; /* URI of printer */ + ipp_attribute_t *allowed, /* requesting-user-name-allowed */ + *denied; /* requestint-user-name-denied */ + ipp_pstate_t pstate; /* Printer state */ + cups_ptype_t ptype; /* Printer type */ + time_t ptime; /* Printer state time */ + struct tm *pdate; /* Printer state date & time */ + 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 */ + printer_state_time[255];/* Printer state time */ + const char *root; /* Server root directory... */ + static const char *pattrs[] = /* Attributes we need for printers... */ + { + "printer-name", + "printer-state", + "printer-state-message", + "printer-state-reasons", + "printer-state-change-time", + "printer-type", + "printer-info", + "printer-location", + "printer-make-and-model", + "printer-uri-supported", + "requesting-user-name-allowed", + "requesting-user-name-denied" + }; + static const char *jattrs[] = /* Attributes we need for jobs... */ + { + "job-id" + }; + + + DEBUG_printf(("show_printers(%p, %p)\n", http, dests)); + + if (http == NULL) + return (1); + + 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 = ippNewRequest(CUPS_GET_PRINTERS); + + 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) + { + _cupsLangPrintf(stderr, NULL, _("lpstat: get-printers failed: %s\n"), + ippErrorString(response->request.status.status_code)); + ippDelete(response); + return (1); + } + + /* + * 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; + ptime = 0; + ptype = CUPS_PRINTER_LOCAL; + pstate = IPP_PRINTER_IDLE; + message = NULL; + description = NULL; + location = NULL; + make_model = NULL; + reasons = NULL; + uri = NULL; + jobid = 0; + allowed = NULL; + denied = NULL; + + while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER) + { + if (!strcmp(attr->name, "printer-name") && + attr->value_tag == IPP_TAG_NAME) + printer = attr->values[0].string.text; + else if (!strcmp(attr->name, "printer-state") && + attr->value_tag == IPP_TAG_ENUM) + pstate = (ipp_pstate_t)attr->values[0].integer; + else if (!strcmp(attr->name, "printer-type") && + attr->value_tag == IPP_TAG_ENUM) + ptype = (cups_ptype_t)attr->values[0].integer; + else if (!strcmp(attr->name, "printer-state-message") && + attr->value_tag == IPP_TAG_TEXT) + message = attr->values[0].string.text; + else if (!strcmp(attr->name, "printer-state-change-time") && + attr->value_tag == IPP_TAG_INTEGER) + ptime = (time_t)attr->values[0].integer; + else if (!strcmp(attr->name, "printer-info") && + attr->value_tag == IPP_TAG_TEXT) + description = attr->values[0].string.text; + else if (!strcmp(attr->name, "printer-location") && + attr->value_tag == IPP_TAG_TEXT) + location = attr->values[0].string.text; + else if (!strcmp(attr->name, "printer-make-and-model") && + attr->value_tag == IPP_TAG_TEXT) + make_model = attr->values[0].string.text; + else if (!strcmp(attr->name, "printer-uri-supported") && + attr->value_tag == IPP_TAG_URI) + uri = attr->values[0].string.text; + else if (!strcmp(attr->name, "printer-state-reasons") && + attr->value_tag == IPP_TAG_KEYWORD) + reasons = attr; + else if (!strcmp(attr->name, "requesting-user-name-allowed") && + attr->value_tag == IPP_TAG_NAME) + allowed = attr; + else if (!strcmp(attr->name, "requesting-user-name-denied") && + attr->value_tag == IPP_TAG_NAME) + denied = attr; + + 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 & 255) || *dptr == ',') + dptr ++; + + if (*dptr == '\0') + break; + + /* + * Compare names... + */ + + for (ptr = printer; + *ptr != '\0' && *dptr != '\0' && tolower(*ptr & 255) == tolower(*dptr & 255); + ptr ++, dptr ++); + + if (*ptr == '\0' && (*dptr == '\0' || *dptr == ',' || isspace(*dptr & 255))) + { + match = 1; + break; + } + + /* + * Skip trailing junk... + */ + + while (!isspace(*dptr & 255) && *dptr != ',' && *dptr != '\0') + dptr ++; + while (isspace(*dptr & 255) || *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 = ippNewRequest(IPP_GET_JOBS); + + request->request.op.operation_id = IPP_GET_JOBS; + request->request.op.request_id = 1; + + ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, + "requested-attributes", + sizeof(jattrs) / sizeof(jattrs[0]), NULL, jattrs); + + httpAssembleURIf(printer_uri, sizeof(printer_uri), "ipp", NULL, + "localhost", 0, "/printers/%s", printer); + ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, + "printer-uri", NULL, printer_uri); + + if ((jobs = cupsDoRequest(http, request, "/")) != NULL) + { + /* + * Get the current active job on this queue... + */ + + jobid = 0; + + for (jobattr = jobs->attrs; jobattr; jobattr = jobattr->next) + { + if (!jobattr->name) + continue; + + if (!strcmp(jobattr->name, "job-id") && + jobattr->value_tag == IPP_TAG_INTEGER) + jobid = jobattr->values[0].integer; + else if (!strcmp(jobattr->name, "job-state") && + jobattr->value_tag == IPP_TAG_ENUM && + jobattr->values[0].integer == IPP_JOB_PROCESSING) + break; + } + + ippDelete(jobs); + } + } + + /* + * Display it... + */ + + pdate = localtime(&ptime); + strftime(printer_state_time, sizeof(printer_state_time), "%c", pdate); + + switch (pstate) + { + case IPP_PRINTER_IDLE : + _cupsLangPrintf(stdout, NULL, + _("printer %s is idle. enabled since %s\n"), + printer, printer_state_time); + break; + case IPP_PRINTER_PROCESSING : + _cupsLangPrintf(stdout, NULL, + _("printer %s now printing %s-%d. " + "enabled since %s\n"), + printer, printer, jobid, printer_state_time); + break; + case IPP_PRINTER_STOPPED : + _cupsLangPrintf(stdout, NULL, + _("printer %s disabled since %s -\n"), + printer, printer_state_time); + break; + } + + if ((message && *message) || pstate == IPP_PRINTER_STOPPED) + { + if (!message || !*message) + _cupsLangPuts(stdout, NULL, _("\treason unknown\n")); + else + _cupsLangPrintf(stdout, NULL, "\t%s\n", message); + } + + if (long_status > 1) + _cupsLangPuts(stdout, NULL, + _("\tForm mounted:\n" + "\tContent types: any\n" + "\tPrinter types: unknown\n")); + + if (long_status) + { + _cupsLangPrintf(stdout, NULL, _("\tDescription: %s\n"), + description ? description : ""); + + if (reasons) + { + _cupsLangPuts(stdout, NULL, _("\tAlerts:")); + for (i = 0; i < reasons->num_values; i ++) + _cupsLangPrintf(stdout, NULL, " %s", + reasons->values[i].string.text); + _cupsLangPuts(stdout, NULL, "\n"); + } + } + if (long_status > 1) + { + _cupsLangPrintf(stdout, NULL, _("\tLocation: %s\n"), + location ? location : ""); + + if (ptype & CUPS_PRINTER_REMOTE) + { + _cupsLangPuts(stdout, NULL, _("\tConnection: remote\n")); + + if (make_model && !strstr(make_model, "System V Printer") && + !strstr(make_model, "Raw Printer") && uri) + _cupsLangPrintf(stdout, NULL, _("\tInterface: %s.ppd\n"), + uri); + } + else + { + _cupsLangPuts(stdout, NULL, _("\tConnection: direct\n")); + + if (make_model && strstr(make_model, "System V Printer")) + _cupsLangPrintf(stdout, NULL, + _("\tInterface: %s/interfaces/%s\n"), + root, printer); + else if (make_model && !strstr(make_model, "Raw Printer")) + _cupsLangPrintf(stdout, NULL, + _("\tInterface: %s/ppd/%s.ppd\n"), root, printer); + } + _cupsLangPuts(stdout, NULL, _("\tOn fault: no alert\n")); + _cupsLangPuts(stdout, NULL, _("\tAfter fault: continue\n")); + // TODO update to use printer-error-policy + if (allowed) + { + _cupsLangPuts(stdout, NULL, _("\tUsers allowed:\n")); + for (i = 0; i < allowed->num_values; i ++) + _cupsLangPrintf(stdout, NULL, "\t\t%s\n", + allowed->values[i].string.text); + } + else if (denied) + { + _cupsLangPuts(stdout, NULL, _("\tUsers denied:\n")); + for (i = 0; i < denied->num_values; i ++) + _cupsLangPrintf(stdout, NULL, "\t\t%s\n", + denied->values[i].string.text); + } + else + { + _cupsLangPuts(stdout, NULL, _("\tUsers allowed:\n")); + _cupsLangPuts(stdout, NULL, _("\t\t(all)\n")); + } + _cupsLangPuts(stdout, NULL, _("\tForms allowed:\n")); + _cupsLangPuts(stdout, NULL, _("\t\t(none)\n")); + _cupsLangPuts(stdout, NULL, _("\tBanner required\n")); + _cupsLangPuts(stdout, NULL, _("\tCharset sets:\n")); + _cupsLangPuts(stdout, NULL, _("\t\t(none)\n")); + _cupsLangPuts(stdout, NULL, _("\tDefault pitch:\n")); + _cupsLangPuts(stdout, NULL, _("\tDefault page size:\n")); + _cupsLangPuts(stdout, NULL, _("\tDefault port settings:\n")); + } + + for (i = 0; i < num_dests; i ++) + if (!strcasecmp(printer, dests[i].name) && dests[i].instance) + { + switch (pstate) + { + case IPP_PRINTER_IDLE : + _cupsLangPrintf(stdout, NULL, + _("printer %s/%s is idle. " + "enabled since %s\n"), + printer, dests[i].instance, + printer_state_time); + break; + case IPP_PRINTER_PROCESSING : + _cupsLangPrintf(stdout, NULL, + _("printer %s/%s now printing %s-%d. " + "enabled since %s\n"), + printer, dests[i].instance, printer, jobid, + printer_state_time); + break; + case IPP_PRINTER_STOPPED : + _cupsLangPrintf(stdout, NULL, + _("printer %s/%s disabled since %s -\n"), + printer, dests[i].instance, + printer_state_time); + break; + } + + if ((message && *message) || pstate == IPP_PRINTER_STOPPED) + { + if (!message || !*message) + _cupsLangPuts(stdout, NULL, _("\treason unknown\n")); + else + _cupsLangPrintf(stdout, NULL, "\t%s\n", message); + } + + if (long_status > 1) + _cupsLangPuts(stdout, NULL, + _("\tForm mounted:\n" + "\tContent types: any\n" + "\tPrinter types: unknown\n")); + + if (long_status) + { + _cupsLangPrintf(stdout, NULL, _("\tDescription: %s\n"), + description ? description : ""); + + if (reasons) + { + _cupsLangPuts(stdout, NULL, _("\tAlerts:")); + for (i = 0; i < reasons->num_values; i ++) + _cupsLangPrintf(stdout, NULL, " %s", + reasons->values[i].string.text); + _cupsLangPuts(stdout, NULL, "\n"); + } + } + if (long_status > 1) + { + _cupsLangPrintf(stdout, NULL, _("\tLocation: %s\n"), + location ? location : ""); + + if (ptype & CUPS_PRINTER_REMOTE) + { + _cupsLangPuts(stdout, NULL, _("\tConnection: remote\n")); + + if (make_model && !strstr(make_model, "System V Printer") && + !strstr(make_model, "Raw Printer") && uri) + _cupsLangPrintf(stdout, NULL, _("\tInterface: %s.ppd\n"), + uri); + } + else + { + _cupsLangPuts(stdout, NULL, _("\tConnection: direct\n")); + + if (make_model && strstr(make_model, "System V Printer")) + _cupsLangPrintf(stdout, NULL, + _("\tInterface: %s/interfaces/%s\n"), + root, printer); + else if (make_model && !strstr(make_model, "Raw Printer")) + _cupsLangPrintf(stdout, NULL, + _("\tInterface: %s/ppd/%s.ppd\n"), root, printer); + } + _cupsLangPuts(stdout, NULL, _("\tOn fault: no alert\n")); + _cupsLangPuts(stdout, NULL, _("\tAfter fault: continue\n")); + // TODO update to use printer-error-policy + if (allowed) + { + _cupsLangPuts(stdout, NULL, _("\tUsers allowed:\n")); + for (i = 0; i < allowed->num_values; i ++) + _cupsLangPrintf(stdout, NULL, "\t\t%s\n", + allowed->values[i].string.text); + } + else if (denied) + { + _cupsLangPuts(stdout, NULL, _("\tUsers denied:\n")); + for (i = 0; i < denied->num_values; i ++) + _cupsLangPrintf(stdout, NULL, "\t\t%s\n", + denied->values[i].string.text); + } + else + { + _cupsLangPuts(stdout, NULL, _("\tUsers allowed:\n")); + _cupsLangPuts(stdout, NULL, _("\t\t(all)\n")); + } + _cupsLangPuts(stdout, NULL, _("\tForms allowed:\n")); + _cupsLangPuts(stdout, NULL, _("\t\t(none)\n")); + _cupsLangPuts(stdout, NULL, _("\tBanner required\n")); + _cupsLangPuts(stdout, NULL, _("\tCharset sets:\n")); + _cupsLangPuts(stdout, NULL, _("\t\t(none)\n")); + _cupsLangPuts(stdout, NULL, _("\tDefault pitch:\n")); + _cupsLangPuts(stdout, NULL, _("\tDefault page size:\n")); + _cupsLangPuts(stdout, NULL, _("\tDefault port settings:\n")); + } + } + } + + if (attr == NULL) + break; + } + + ippDelete(response); + } + else + { + _cupsLangPrintf(stderr, NULL, _("lpstat: get-printers failed: %s\n"), + ippErrorString(cupsLastError())); + return (1); + } + + return (0); +} + + +/* + * 'show_scheduler()' - Show scheduler status. + */ + +static void +show_scheduler(http_t *http) /* I - HTTP connection to server */ +{ + if (http) + _cupsLangPuts(stdout, NULL, _("scheduler is running\n")); + else + _cupsLangPuts(stdout, NULL, _("scheduler is not running\n")); +} + + +/* + * End of "$Id: lpstat.c 4922 2006-01-12 22:05:06Z mike $". + */ diff --git a/templates/Makefile b/templates/Makefile new file mode 100644 index 000000000..4225d336c --- /dev/null +++ b/templates/Makefile @@ -0,0 +1,110 @@ +# +# "$Id: Makefile 4881 2005-12-15 22:03:40Z mike $" +# +# Template makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1993-2005 by Easy Software Products. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + +# +# Template files... +# + +FILES = add-class.tmpl \ + add-printer.tmpl \ + admin-op.tmpl \ + admin.tmpl \ + choose-device.tmpl \ + choose-make.tmpl \ + choose-model.tmpl \ + choose-serial.tmpl \ + choose-uri.tmpl \ + class-added.tmpl \ + class-confirm.tmpl \ + class-deleted.tmpl \ + classes.tmpl \ + class-modified.tmpl \ + edit-config.tmpl \ + error.tmpl \ + header.tmpl \ + help-header.tmpl \ + job-cancel.tmpl \ + job-hold.tmpl \ + job-op.tmpl \ + job-release.tmpl \ + job-restart.tmpl \ + jobs.tmpl \ + modify-class.tmpl \ + modify-printer.tmpl \ + option-boolean.tmpl \ + option-conflict.tmpl \ + option-header.tmpl \ + option-pickmany.tmpl \ + option-pickone.tmpl \ + option-trailer.tmpl \ + printer-accept.tmpl \ + printer-added.tmpl \ + printer-configured.tmpl \ + printer-confirm.tmpl \ + printer-default.tmpl \ + printer-deleted.tmpl \ + printer-modified.tmpl \ + printer-purge.tmpl \ + printer-reject.tmpl \ + printer-start.tmpl \ + printers.tmpl \ + printer-stop.tmpl \ + restart.tmpl \ + set-printer-options-header.tmpl \ + set-printer-options-trailer.tmpl \ + test-page.tmpl \ + trailer.tmpl \ + users.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: Makefile 4881 2005-12-15 22:03:40Z mike $". +# diff --git a/templates/add-class.tmpl b/templates/add-class.tmpl new file mode 100644 index 000000000..ec13434e9 --- /dev/null +++ b/templates/add-class.tmpl @@ -0,0 +1,33 @@ +

    + + +

    Add Class

    + + + + + + + + + + + + + + + + + + + + + + +
    Name:
    Location:
    Description:
    Members: + +
    + + diff --git a/templates/add-printer.tmpl b/templates/add-printer.tmpl new file mode 100644 index 000000000..dd913312f --- /dev/null +++ b/templates/add-printer.tmpl @@ -0,0 +1,28 @@ +
    + + +

    Add New Printer

    + + + + + + + + + + + + + + + + + + +
    Name:
    +(May contain any printable characters except "/", "#", and space)
    Location:
    +(Human-readable location such as "Lab 1")
    Description:
    +(Human-readable description such as "HP LaserJet with Duplexer")
    + +
    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 @@ +

    Unsupported administration operation "{op}". diff --git a/templates/admin.tmpl b/templates/admin.tmpl new file mode 100644 index 000000000..af88e33b3 --- /dev/null +++ b/templates/admin.tmpl @@ -0,0 +1,71 @@ + + +
    + +

    Classes

    + +

    + + +

    + +

    Jobs

    + +

    +Manage
+Jobs +

    + +

    Printers

    + +

    +Add Printer + +

    + +{#device_uri=0?:

    New Printers Found:

      {[device_uri] +
    • {device_make_and_model} ({device_info}) +Add This Printer
    • +}
    } + +
          + +

    Server

    + +

    +Edit Configuration
+File +View Access Log +View Error Log +View Page Log +

    + +
    + +

    Basic Server Settings:

    + +

    + Show printers shared by other systems
    + Share published printers connected to this system
    + Allow remote administration
    + Allow users to cancel any job (not just their own)
    + Save debugging information for troubleshooting

    + +

    + +
    + +
    diff --git a/templates/choose-device.tmpl b/templates/choose-device.tmpl new file mode 100644 index 000000000..440e539f0 --- /dev/null +++ b/templates/choose-device.tmpl @@ -0,0 +1,26 @@ +

    + + + + + + +

    Device for {printer_name}

    + + + + + + + + + + +
    Device: + +
    + +
    diff --git a/templates/choose-make.tmpl b/templates/choose-make.tmpl new file mode 100644 index 000000000..5bc0e67ec --- /dev/null +++ b/templates/choose-make.tmpl @@ -0,0 +1,42 @@ +
    + + + + + + + + + + +

    Make/Manufacturer for {printer_name}

    + + + + + + + + + + + + + + + + + + + + + + +
    Make: + +
     
    Or Provide a PPD File:
    + +
    diff --git a/templates/choose-model.tmpl b/templates/choose-model.tmpl new file mode 100644 index 000000000..c0c2ef2c0 --- /dev/null +++ b/templates/choose-model.tmpl @@ -0,0 +1,34 @@ +
    + + + + + + + + + + +

    Model/Driver for {printer_name}

    + + + + + + + + + + + + + + +
    Model: + +
    Or Provide a PPD File:
    + +
    diff --git a/templates/choose-serial.tmpl b/templates/choose-serial.tmpl new file mode 100644 index 000000000..f90dd6a01 --- /dev/null +++ b/templates/choose-serial.tmpl @@ -0,0 +1,47 @@ +
    + + + + + + +

    Serial Port Settings for {printer_name}

    + + + + + + + + + + + + + + + + + + + + + + +
    Baud Rate:
    Parity:
    Data Bits:
    Flow Control:
    + +
    diff --git a/templates/choose-uri.tmpl b/templates/choose-uri.tmpl new file mode 100644 index 000000000..ae72d1c17 --- /dev/null +++ b/templates/choose-uri.tmpl @@ -0,0 +1,40 @@ +
    + + + + + + +

    Device URI for {printer_name}

    + + + + + + + + + + + + + + +
    Device URI:
    Examples: +
    +    file:/path/to/filename.prn
    +    http://hostname:631/ipp/
    +    http://hostname:631/ipp/port1
    +    ipp://hostname/ipp/
    +    ipp://hostname/ipp/port1
    +    lpd://hostname/queue
    +    socket://hostname
    +    socket://hostname:9100
    +
    + +

    See "Network +Printers" for the correct URI to use with your printer.

    + +
    + +
    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 @@ +

    Class {printer_name} has been added +successfully. diff --git a/templates/class-confirm.tmpl b/templates/class-confirm.tmpl new file mode 100644 index 000000000..4a9afc6de --- /dev/null +++ b/templates/class-confirm.tmpl @@ -0,0 +1,7 @@ +

    Warning: Are you sure you want to delete class +{printer_name}?

    + +

    Delete Class

    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 @@ +

    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 @@ +

    Class {printer_name} has been +modified successfully. diff --git a/templates/classes.tmpl b/templates/classes.tmpl new file mode 100644 index 000000000..2f582ea23 --- /dev/null +++ b/templates/classes.tmpl @@ -0,0 +1,60 @@ +

    Add Class

    + +{#printer_name=0?No classes: +

    Server Default Destination: {default_name?{default_name}:none}

    +{[printer_name] +

    {printer_name}{default_name={printer_name}? (Default Printer):}

    + + + + + + +
    +Description: {printer_info}
    +Location: {printer_location}
    +Class State: {printer_state=3?idle:{printer_state=4?processing:stopped}}, +{printer_is_accepting_jobs=0?rejecting jobs:accepting jobs}, {printer_is_shared=0?not:} published. +{?printer_state_message=?:
    "{printer_state_message}"} +{?member_uris=?:
    Members: {member_uris}} + +

    + +Print Test Page +{printer_state=5? + +Start Class +: + +Stop Class +} +{printer_is_accepting_jobs=0? + +Accept Jobs +: + +Reject Jobs +} + +Cancel All Jobs +{printer_is_shared=0? + +Publish Printer +: + +Unpublish Printer +} + +Modify Class + +Delete Class + +Set As Default + +Set Allowed Users +

    +
    + +}} diff --git a/templates/edit-config.tmpl.in b/templates/edit-config.tmpl.in new file mode 100644 index 000000000..2aeaec0d6 --- /dev/null +++ b/templates/edit-config.tmpl.in @@ -0,0 +1,90 @@ + + +

    Server Configuration File

    + +
    + + + + + +

    + +
    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 @@ +

    Error: + +

    {error}
    diff --git a/templates/header.tmpl b/templates/header.tmpl new file mode 100644 index 000000000..7f5ab2375 --- /dev/null +++ b/templates/header.tmpl @@ -0,0 +1,62 @@ + + + + + {title} - {cups_version} + + + + {refresh_page?:} + + + + + + + + + + + + + + + + + diff --git a/templates/option-conflict.tmpl b/templates/option-conflict.tmpl new file mode 100644 index 000000000..5086a649f --- /dev/null +++ b/templates/option-conflict.tmpl @@ -0,0 +1,7 @@ +

    Error: The following options are conflicting:

    + + + +

    Please change one or more of the options to resolve the conflicts.

    diff --git a/templates/option-header.tmpl b/templates/option-header.tmpl new file mode 100644 index 000000000..cafc9f9fe --- /dev/null +++ b/templates/option-header.tmpl @@ -0,0 +1,3 @@ +

    {printer_name}: {group}

    + +

    {title}

    + +  Home   + +   Administration   + +   Classes   + +   Documentation/Help   + +   Jobs   + +   Printers   + +
      diff --git a/templates/help-header.tmpl b/templates/help-header.tmpl new file mode 100644 index 000000000..21e0ec445 --- /dev/null +++ b/templates/help-header.tmpl @@ -0,0 +1,28 @@ +
    +{TOPIC?:} + +

    Search in +{HELPTITLE?{HELPTITLE}:{TOPIC?{TOPIC}:All Documents}}:

    + +
    + + + + +{QUERY?

    Search Results in {HELPFILE?{HELPTITLE}:{TOPIC?{TOPIC}:All Documents}}\:

    +{QTEXT?:} +:

    No matches found.

    } +{HELPTITLE?
    :}:} +{HELPTITLE?

    {HELPTITLE}

    :} diff --git a/templates/job-cancel.tmpl b/templates/job-cancel.tmpl new file mode 100644 index 000000000..fbdda31dd --- /dev/null +++ b/templates/job-cancel.tmpl @@ -0,0 +1 @@ +

    Job {job_id} has been cancelled. diff --git a/templates/job-hold.tmpl b/templates/job-hold.tmpl new file mode 100644 index 000000000..3e391543b --- /dev/null +++ b/templates/job-hold.tmpl @@ -0,0 +1 @@ +

    Job {job_id} has been held from printing. diff --git a/templates/job-op.tmpl b/templates/job-op.tmpl new file mode 100644 index 000000000..19520367f --- /dev/null +++ b/templates/job-op.tmpl @@ -0,0 +1 @@ +

    Unsupported job operation "{op}". diff --git a/templates/job-release.tmpl b/templates/job-release.tmpl new file mode 100644 index 000000000..d04622353 --- /dev/null +++ b/templates/job-release.tmpl @@ -0,0 +1 @@ +

    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..d575c47a7 --- /dev/null +++ b/templates/job-restart.tmpl @@ -0,0 +1 @@ +

    Job {job_id} has been restarted. diff --git a/templates/jobs-header.tmpl b/templates/jobs-header.tmpl new file mode 100644 index 000000000..fef904715 --- /dev/null +++ b/templates/jobs-header.tmpl @@ -0,0 +1,17 @@ +{?printer_name=?:

    Jobs

    } + +

    {?which_jobs=?Show Completed Jobs +Show All Jobs:{which_jobs=all?Show Completed Jobs +Show Active Jobs:Show Active Jobs +Show All Jobs}}

    + +

    Showing {#job_id} of {total} {?which_jobs=?active:{which_jobs=all?:completed}} job{total=1?:s}.

    diff --git a/templates/jobs.tmpl b/templates/jobs.tmpl new file mode 100644 index 000000000..aeac2002c --- /dev/null +++ b/templates/jobs.tmpl @@ -0,0 +1,44 @@ +{#job_id=0?: + + + + + + + + + + + +{[job_id] + + + + + + + + + +} +
    ID Name User Size Pages State Control 
    {job_printer_name}-{job_id} {?job_name=?Unknown:{job_name}} {job_originating_user_name} {job_k_octets}k {job_media_sheets_completed=0?Unknown:{?job_media_sheets_completed}}{job_state=3?pending since
    {time_at_creation}:{job_state=4?held since
    {time_at_creation}: +{job_state=5?processing since
    {time_at_processing}:{job_state=6?stopped at
    {time_at_completed}: +{job_state=7?cancelled at
    {time_at_completed}:{job_state=8?aborted:completed at
    {time_at_completed}}}}}}} 
    +{job_state>5? +{job_k_octets>0? + +Reprint Job +:}:} +{job_state>6?: +{job_state=4? + +Release Job +: + +Hold Job +} + +Cancel Job +} + 
    +} diff --git a/templates/modify-class.tmpl b/templates/modify-class.tmpl new file mode 100644 index 000000000..6a35cce94 --- /dev/null +++ b/templates/modify-class.tmpl @@ -0,0 +1,34 @@ +
    + + +

    Modify Class {printer_name}

    + + + + + + + + + + + + + + + + + + + + + + +
    Name: +{printer_name}
    Location:
    Description:
    Members: + +
    + +
    diff --git a/templates/modify-printer.tmpl b/templates/modify-printer.tmpl new file mode 100644 index 000000000..37847a59e --- /dev/null +++ b/templates/modify-printer.tmpl @@ -0,0 +1,29 @@ +
    + +{?device_uri=?:} +{?printer_make_and_model=?:} + +

    Modify Printer {printer_name}

    + + + + + + + + + + + + + + + + + + +
    Name:{printer_name}
    Location:
    +(Human-readable location such as "Lab 1")
    Description:
    +(Human-readable description such as "HP LaserJet with Duplexer")
    + +
    diff --git a/templates/option-boolean.tmpl b/templates/option-boolean.tmpl new file mode 100644 index 000000000..72c85189a --- /dev/null +++ b/templates/option-boolean.tmpl @@ -0,0 +1,6 @@ +
    {keytext}: +{[choices]{text}} +
    diff --git a/templates/option-pickmany.tmpl b/templates/option-pickmany.tmpl new file mode 100644 index 000000000..d2534af75 --- /dev/null +++ b/templates/option-pickmany.tmpl @@ -0,0 +1,6 @@ + + + + diff --git a/templates/option-pickone.tmpl b/templates/option-pickone.tmpl new file mode 100644 index 000000000..08342d06e --- /dev/null +++ b/templates/option-pickone.tmpl @@ -0,0 +1,6 @@ + + + + diff --git a/templates/option-trailer.tmpl b/templates/option-trailer.tmpl new file mode 100644 index 000000000..a8ff4c6fe --- /dev/null +++ b/templates/option-trailer.tmpl @@ -0,0 +1,5 @@ + + + + +
    {keytext}:
    {keytext}:
    diff --git a/templates/page.tmpl b/templates/page.tmpl new file mode 100644 index 000000000..a949fe8c5 --- /dev/null +++ b/templates/page.tmpl @@ -0,0 +1,7 @@ + + + + + + +
    {PREVURL?Show Previous: }{ORDER=dec?Show Ascending:Show Descending}{NEXTURL?Show Next: }
    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 @@ +

    Printer {printer_name} 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 @@ +

    Printer {printer_name} 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 @@ +

    Printer {printer_name} has +been configured successfully. diff --git a/templates/printer-confirm.tmpl b/templates/printer-confirm.tmpl new file mode 100644 index 000000000..046acb93d --- /dev/null +++ b/templates/printer-confirm.tmpl @@ -0,0 +1,7 @@ +

    Warning: Are you sure you want to delete printer +{printer_name}?

    + +

    Delete Printer

    diff --git a/templates/printer-default.tmpl b/templates/printer-default.tmpl new file mode 100644 index 000000000..e5dd0b08c --- /dev/null +++ b/templates/printer-default.tmpl @@ -0,0 +1,4 @@ +

    Printer {printer_name} has been +made the default printer on the server. Please note that any user default +that has been set via the lpoptions command will override this +default setting. 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 @@ +

    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 @@ +

    Printer {printer_name} has been +modified successfully. diff --git a/templates/printer-purge.tmpl b/templates/printer-purge.tmpl new file mode 100644 index 000000000..863d33916 --- /dev/null +++ b/templates/printer-purge.tmpl @@ -0,0 +1 @@ +

    Printer {printer_name} has been purged of all jobs. 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 @@ +

    Printer {printer_name} 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 @@ +

    Printer {printer_name} 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 @@ +

    Printer {printer_name} has been +stopped. diff --git a/templates/printers.tmpl b/templates/printers.tmpl new file mode 100644 index 000000000..44d28dfb3 --- /dev/null +++ b/templates/printers.tmpl @@ -0,0 +1,68 @@ +

    Add Printer

    + +{#printer_name=0?No printers: +

    Server Default Destination: {default_name?{default_name}:none}

    +{[printer_name] +

    {printer_name}{default_name={printer_name}? (Default Printer):}

    + + + + + + +
    + +Description: {printer_info}
    +Location: {printer_location}
    +Make and Model: {printer_make_and_model}
    +Printer State: {printer_state=3?idle:{printer_state=4?processing:stopped}}, +{printer_is_accepting_jobs=0?rejecting jobs:accepting jobs}, {printer_is_shared=0?not:} published. +{?printer_state_message=?:
    "{printer_state_message}"} +{?printer_state_history2.printer_state_message=?:
    "{printer_state_history2.printer_state_message}"} +{?printer_state_history3.printer_state_message=?:
    "{printer_state_history3.printer_state_message}"} +{?printer_state_history4.printer_state_message=?:
    "{printer_state_history4.printer_state_message}"} +{?printer_state_history5.printer_state_message=?:
    "{printer_state_history5.printer_state_message}"} +{?device_uri=?:
    Device URI: {device_uri}} + +

    + +Print Test Page +{printer_state=5? + +Start Printer +: + +Stop Printer +} +{printer_is_accepting_jobs=0? + +Accept Jobs +: + +Reject Jobs +} + +Cancel All Jobs +{printer_is_shared=0? + +Publish Printer +: + +Unpublish Printer +} + +Modify Printer + +Set Printer Options + +Delete Printer + +Set As Default + +Set Allowed Users +

    +
    + +}} diff --git a/templates/restart.tmpl b/templates/restart.tmpl new file mode 100644 index 000000000..63ff47d9f --- /dev/null +++ b/templates/restart.tmpl @@ -0,0 +1 @@ +

    Please stand by while the server restarts...

    diff --git a/templates/search.tmpl b/templates/search.tmpl new file mode 100644 index 000000000..ee4e48c00 --- /dev/null +++ b/templates/search.tmpl @@ -0,0 +1,10 @@ +
    +{WHICH_JOBS?:} +{ORDER?:} + +

    Search in +{SECTION=classes?Classes:{SECTION=jobs?Jobs:Printers}}: +

    + +
    diff --git a/templates/set-printer-options-header.tmpl b/templates/set-printer-options-header.tmpl new file mode 100644 index 000000000..864f9f0ce --- /dev/null +++ b/templates/set-printer-options-header.tmpl @@ -0,0 +1,3 @@ +
    + + diff --git a/templates/set-printer-options-trailer.tmpl b/templates/set-printer-options-trailer.tmpl new file mode 100644 index 000000000..a3d1e1ffa --- /dev/null +++ b/templates/set-printer-options-trailer.tmpl @@ -0,0 +1 @@ +
    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 @@ +

    Test page sent; job ID is +{printer_name}-{job_id}. diff --git a/templates/trailer.tmpl b/templates/trailer.tmpl new file mode 100644 index 000000000..9fe5f6788 --- /dev/null +++ b/templates/trailer.tmpl @@ -0,0 +1,21 @@ + +  + + + + + +

    The Common UNIX Printing System, CUPS, and the CUPS logo are the +trademark property of Easy Software +Products. CUPS is copyright 1997-2006 by Easy Software Products, +All Rights Reserved.

    + + + + + + + + diff --git a/templates/users.tmpl b/templates/users.tmpl new file mode 100644 index 000000000..a5734416a --- /dev/null +++ b/templates/users.tmpl @@ -0,0 +1,25 @@ +
    + + + +

    Allowed Users For {printer_name}

    + + + + + + + + + + +
    Users: + +
    +Allow these users to print +Prevent these users from printing +
    + +
    + +
    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..38565cdf4 --- /dev/null +++ b/test/4.2-cups-printer-ops.test @@ -0,0 +1,241 @@ +# +# "$Id: 4.2-cups-printer-ops.test 4837 2005-11-14 04:13:13Z 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 "Subscribe to Printer Events" + + # The operation to use + OPERATION Create-Printer-Subscription + 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/ + ATTR name requesting-user-name $user + + GROUP subscription + ATTR uri notify-recipient testnotify + ATTR keyword notify-events printer-added,printer-modified,printer-deleted + + # What statuses are OK? + STATUS successful-ok + + # What attributes do we expect? + EXPECT attributes-charset + EXPECT attributes-natural-language + EXPECT notify-subscription-id +} +{ + # 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 4837 2005-11-14 04:13:13Z mike $" +# diff --git a/test/4.3-job-ops.test b/test/4.3-job-ops.test new file mode 100644 index 000000000..7d33b383e --- /dev/null +++ b/test/4.3-job-ops.test @@ -0,0 +1,301 @@ +# +# "$Id: 4.3-job-ops.test 4837 2005-11-14 04:13:13Z 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 + + GROUP subscription + ATTR uri notify-recipient testnotify + + 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 + EXPECT notify-subscription-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 4837 2005-11-14 04:13:13Z mike $" +# diff --git a/test/4.4-subscription-ops.test b/test/4.4-subscription-ops.test new file mode 100644 index 000000000..c3098ef07 --- /dev/null +++ b/test/4.4-subscription-ops.test @@ -0,0 +1,122 @@ +# +# "$Id: 4.4-subscription-ops.test 4840 2005-11-14 21:53:30Z mike $" +# +# Verify that the CUPS subscription operations work. +# +{ + # The name of the test... + NAME "Add Printer Subscription w/Lease" + + # The operation to use + OPERATION Create-Printer-Subscription + 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 + + GROUP subscription + ATTR uri notify-recipient testnotify + ATTR keyword notify-events printer-state-changed + ATTR integer notify-lease-duration 5 + + # What statuses are OK? + STATUS successful-ok + + # What attributes do we expect? + EXPECT attributes-charset + EXPECT attributes-natural-language + EXPECT notify-subscription-id + DISPLAY notify-subscription-id +} +{ + # The name of the test... + NAME "Verify Subscription Expiration" + + # Delay test for 6 seconds to allow lease to expire... + DELAY 6 + + # The operation to use + OPERATION Get-Subscription-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 + ATTR integer notify-subscription-id $notify-subscription-id + + # 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 2 Printer Subscriptions w/Lease" + + # The operation to use + OPERATION Create-Printer-Subscription + 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 + + GROUP subscription + ATTR uri notify-recipient testnotify + ATTR keyword notify-events printer-state-changed + ATTR integer notify-lease-duration 5 + + GROUP subscription + ATTR uri notify-recipient testnotify + ATTR keyword notify-events printer-config-changed + ATTR integer notify-lease-duration 5 + + # What statuses are OK? + STATUS successful-ok + + # What attributes do we expect? + EXPECT attributes-charset + EXPECT attributes-natural-language + EXPECT notify-subscription-id + DISPLAY notify-subscription-id +} +{ + # The name of the test... + NAME "List Printer Subscriptions" + + # The operation to use + OPERATION Get-Subscriptions + 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 + EXPECT notify-subscription-id + DISPLAY notify-subscription-id + EXPECT notify-printer-uri + DISPLAY notify-printer-uri + EXPECT notify-events + DISPLAY notify-events +} + +# +# End of "$Id: 4.4-subscription-ops.test 4840 2005-11-14 21:53:30Z mike $" +# diff --git a/test/5.1-lpadmin.sh b/test/5.1-lpadmin.sh new file mode 100644 index 000000000..d73b99293 --- /dev/null +++ b/test/5.1-lpadmin.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# +# "$Id: 5.1-lpadmin.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the lpadmin command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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: 5.1-lpadmin.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/5.2-lpc.sh b/test/5.2-lpc.sh new file mode 100644 index 000000000..282b63cf1 --- /dev/null +++ b/test/5.2-lpc.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# +# "$Id: 5.2-lpc.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the lpc command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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: 5.2-lpc.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/5.3-lpq.sh b/test/5.3-lpq.sh new file mode 100644 index 000000000..a77e4d65e --- /dev/null +++ b/test/5.3-lpq.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# +# "$Id: 5.3-lpq.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the lpq command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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: 5.3-lpq.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/5.4-lpstat.sh b/test/5.4-lpstat.sh new file mode 100644 index 000000000..9d1b1cc09 --- /dev/null +++ b/test/5.4-lpstat.sh @@ -0,0 +1,40 @@ +#!/bin/sh +# +# "$Id: 5.4-lpstat.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the lpstat command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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: 5.4-lpstat.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/5.5-lp.sh b/test/5.5-lp.sh new file mode 100644 index 000000000..7fd6e22aa --- /dev/null +++ b/test/5.5-lp.sh @@ -0,0 +1,71 @@ +#!/bin/sh +# +# "$Id: 5.5-lp.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the lp command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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 "" + +echo "LP Flood Test" +echo "" +echo " lp -d Test1 testfile.jpg ($1 times in parallel)" +i=0 +while test $i -lt $1; do + echo " flood copy $i..." 1>&2 + ../systemv/lp -d Test1 testfile.jpg 2>&1 & + lppid=$! + i=`expr $i + 1` +done +wait $lppid +if test $? != 0; then + echo " FAILED" + exit 1 +else + echo " PASSED" +fi +echo "" + +# +# End of "$Id: 5.5-lp.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/5.6-lpr.sh b/test/5.6-lpr.sh new file mode 100644 index 000000000..c16a121dc --- /dev/null +++ b/test/5.6-lpr.sh @@ -0,0 +1,71 @@ +#!/bin/sh +# +# "$Id: 5.6-lpr.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the lpr command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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 "" + +echo "LPR Flood Test" +echo "" +echo " lpr -P Test1 testfile.jpg ($1 times in parallel)" +i=0 +while test $i -lt $1; do + echo " flood copy $i..." 1>&2 + ../berkeley/lpr -P Test1 testfile.jpg 2>&1 & + lprpid=$! + i=`expr $i + 1` +done +wait $lppid +if test $? != 0; then + echo " FAILED" + exit 1 +else + echo " PASSED" +fi +echo "" + +# +# End of "$Id: 5.6-lpr.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/5.7-lprm.sh b/test/5.7-lprm.sh new file mode 100644 index 000000000..500c8f458 --- /dev/null +++ b/test/5.7-lprm.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# "$Id: 5.7-lprm.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the lprm command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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: 5.7-lprm.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/5.8-cancel.sh b/test/5.8-cancel.sh new file mode 100644 index 000000000..34be1712f --- /dev/null +++ b/test/5.8-cancel.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# "$Id: 5.8-cancel.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the cancel command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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: 5.8-cancel.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/5.9-lpinfo.sh b/test/5.9-lpinfo.sh new file mode 100644 index 000000000..13a58ced4 --- /dev/null +++ b/test/5.9-lpinfo.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# +# "$Id: 5.9-lpinfo.sh 4494 2005-02-18 02:18:11Z mike $" +# +# Test the lpinfo command. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +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: 5.9-lpinfo.sh 4494 2005-02-18 02:18:11Z mike $". +# diff --git a/test/Dependencies b/test/Dependencies new file mode 100644 index 000000000..cb014d95d --- /dev/null +++ b/test/Dependencies @@ -0,0 +1,4 @@ +# DO NOT DELETE + +ipptest.o: ../cups/string.h ../config.h ../cups/cups.h ../cups/ipp.h +ipptest.o: ../cups/http.h ../cups/md5.h ../cups/ppd.h ../cups/language.h diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 000000000..14b8ab5bc --- /dev/null +++ b/test/Makefile @@ -0,0 +1,77 @@ +# +# "$Id: Makefile 4837 2005-11-14 04:13:13Z mike $" +# +# IPP test makefile for the Common UNIX Printing System (CUPS). +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +include ../Makedefs + + +# +# Make all targets... +# + +all: ipptest + + +# +# Clean all object files... +# + +clean: + $(RM) ipptest ipptest.o + + +# +# Update dependencies (without system header dependencies...) +# + +depend: + makedepend -Y -I.. -fDependencies ipptest.c >/dev/null 2>&1 + + +# +# Install all targets... +# + +install: + + +# +# ipptest +# + +ipptest: ipptest.o ../cups/libcups.a + echo Linking $@... + $(CC) $(LDFLAGS) -o ipptest ipptest.o ../cups/libcups.a \ + $(SSLLIBS) $(COMMONLIBS) $(LIBZ) + + +# +# Dependencies... +# + +include Dependencies + + +# +# End of "$Id: Makefile 4837 2005-11-14 04:13:13Z mike $". +# 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..5a9ea38ca --- /dev/null +++ b/test/get-printer-attributes.test @@ -0,0 +1,43 @@ +# 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 +} diff --git a/test/ipptest.c b/test/ipptest.c new file mode 100644 index 000000000..14d26e055 --- /dev/null +++ b/test/ipptest.c @@ -0,0 +1,786 @@ +/* + * "$Id: ipptest.c 4837 2005-11-14 04:13:13Z mike $" + * + * IPP test command for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + * + * Contents: + * + * main() - Parse options and do tests. + * do_tests() - Do tests as specified in the test file. + * 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 +#include +#include +#include +#include + +#include +#include + + +/* + * Local functions... + */ + +int do_tests(const char *, const char *); +ipp_op_t ippOpValue(const char *); +ipp_status_t ippErrorValue(const char *); +ipp_tag_t get_tag(const char *); +char *get_token(FILE *, char *, int, int *linenum); +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: ipptest 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 */ + int linenum; /* Current line number */ + int version; /* IPP version number to use */ + 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 */ + int num_displayed; /* Number of displayed attributes */ + char *displayed[100]; /* Displayed 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 */ + int subscription_id; /* Subscription 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; + subscription_id = 0; + version = 1; + linenum = 1; + + while (get_token(fp, token, sizeof(token), &linenum) != NULL) + { + /* + * Expect an open brace... + */ + + if (strcmp(token, "{")) + { + printf("Unexpected token %s seen on line %d - aborting test!\n", token, + linenum); + httpClose(http); + return (0); + } + + /* + * Initialize things... + */ + + httpSeparate(uri, method, userpass, server, &port, resource); + + request = ippNew(); + op = (ipp_op_t)0; + group = IPP_TAG_ZERO; + value = IPP_TAG_ZERO; + num_statuses = 0; + num_expects = 0; + num_displayed = 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), &linenum) != NULL) + { + if (!strcmp(token, "}")) + break; + else if (!strcasecmp(token, "NAME")) + { + /* + * Name of test... + */ + + get_token(fp, name, sizeof(name), &linenum); + } + else if (!strcasecmp(token, "VERSION")) + { + /* + * IPP version number for test... + */ + + get_token(fp, temp, sizeof(temp), &linenum); + sscanf(temp, "%*d.%d", &version); + } + else if (!strcasecmp(token, "RESOURCE")) + { + /* + * Resource name... + */ + + get_token(fp, resource, sizeof(resource), &linenum); + } + else if (!strcasecmp(token, "OPERATION")) + { + /* + * Operation... + */ + + get_token(fp, token, sizeof(token), &linenum); + op = ippOpValue(token); + } + else if (!strcasecmp(token, "GROUP")) + { + /* + * Attribute group... + */ + + get_token(fp, token, sizeof(token), &linenum); + value = get_tag(token); + + if (value == group) + ippAddSeparator(request); + + group = value; + } + else if (!strcasecmp(token, "DELAY")) + { + /* + * Delay before operation... + */ + + int delay; + + get_token(fp, token, sizeof(token), &linenum); + if ((delay = atoi(token)) > 0) + sleep(delay); + } + else if (!strcasecmp(token, "ATTR")) + { + /* + * Attribute... + */ + + get_token(fp, token, sizeof(token), &linenum); + value = get_tag(token); + get_token(fp, attr, sizeof(attr), &linenum); + get_token(fp, temp, sizeof(temp), &linenum); + + 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)) + { + strlcpy(tokenptr, uri, sizeof(token) - (tokenptr - token)); + tempptr += 4; + } + else if (!strncasecmp(tempptr + 1, "method", 6)) + { + strlcpy(tokenptr, method, sizeof(token) - (tokenptr - token)); + tempptr += 7; + } + else if (!strncasecmp(tempptr + 1, "username", 8)) + { + strlcpy(tokenptr, userpass, sizeof(token) - (tokenptr - token)); + tempptr += 9; + } + else if (!strncasecmp(tempptr + 1, "hostname", 8)) + { + strlcpy(tokenptr, server, sizeof(token) - (tokenptr - token)); + tempptr += 9; + } + else if (!strncasecmp(tempptr + 1, "port", 4)) + { + snprintf(tokenptr, sizeof(token) - (tokenptr - token), + "%d", port); + tempptr += 5; + } + else if (!strncasecmp(tempptr + 1, "resource", 8)) + { + strlcpy(tokenptr, resource, sizeof(token) - (tokenptr - token)); + tempptr += 9; + } + else if (!strncasecmp(tempptr + 1, "job-id", 6)) + { + snprintf(tokenptr, sizeof(token) - (tokenptr - token), + "%d", job_id); + tempptr += 7; + } + else if (!strncasecmp(tempptr + 1, "notify-subscription-id", 22)) + { + snprintf(tokenptr, sizeof(token) - (tokenptr - token), + "%d", subscription_id); + tempptr += 23; + } + else if (!strncasecmp(tempptr + 1, "user", 4)) + { + strlcpy(tokenptr, cupsUser(), sizeof(token) - (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")) + 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 : + if (!strchr(token, ',')) + ippAddString(request, group, value, attr, NULL, token); + else + { + /* + * Multiple string values... + */ + + int num_values; /* Number of values */ + char *values[100], /* Values */ + *ptr; /* Pointer to next value */ + + + values[0] = token; + num_values = 1; + + for (ptr = strchr(token, ','); ptr; ptr = strchr(ptr, ',')) + { + *ptr++ = '\0'; + values[num_values] = ptr; + num_values ++; + } + + ippAddStrings(request, group, value, attr, num_values, + NULL, (const char **)values); + } + break; + } + } + else if (!strcasecmp(token, "FILE")) + { + /* + * File... + */ + + get_token(fp, filename, sizeof(filename), &linenum); + } + else if (!strcasecmp(token, "STATUS") && + num_statuses < (int)(sizeof(statuses) / sizeof(statuses[0]))) + { + /* + * Status... + */ + + get_token(fp, token, sizeof(token), &linenum); + statuses[num_statuses] = ippErrorValue(token); + num_statuses ++; + } + else if (!strcasecmp(token, "EXPECT") && + num_expects < (int)(sizeof(expects) / sizeof(expects[0]))) + { + /* + * Expected attributes... + */ + + get_token(fp, token, sizeof(token), &linenum); + expects[num_expects] = strdup(token); + num_expects ++; + } + else if (!strcasecmp(token, "DISPLAY") && + num_displayed < (int)(sizeof(displayed) / sizeof(displayed[0]))) + { + /* + * Display attributes... + */ + + get_token(fp, token, sizeof(token), &linenum); + displayed[num_displayed] = strdup(token); + num_displayed ++; + } + else + { + printf("Unexpected token %s seen on line %d - aborting test!\n", token, + linenum); + httpClose(http); + ippDelete(request); + return (0); + } + } + + /* + * Submit the IPP request... + */ + + request->request.op.version[1] = version; + request->request.op.operation_id = op; + request->request.op.request_id = 1; + +#ifdef DEBUG + for (attrptr = request->attrs; attrptr; attrptr = attrptr->next) + print_attr(attrptr); +#endif /* DEBUG */ + + 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); + + puts("FAIL]"); + printf(" ERROR %04x (%s) @ %s\n", cupsLastError(), + ippErrorString(cupsLastError()), ctime(&curtime)); + pass = 0; + } + else + { + if ((attrptr = ippFindAttribute(response, "job-id", + IPP_TAG_INTEGER)) != NULL) + job_id = attrptr->values[0].integer; + + if ((attrptr = ippFindAttribute(response, "notify-subscription-id", + IPP_TAG_INTEGER)) != NULL) + subscription_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) + pass = 0; + else + { + for (i = 0; i < num_expects; i ++) + if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL) + { + pass = 0; + break; + } + } + + if (pass) + { + puts("PASS]"); + printf(" RECEIVED: %lu bytes in response\n", + (unsigned long)ippLength(response)); + + if (num_displayed > 0) + { + for (attrptr = response->attrs; attrptr != NULL; attrptr = attrptr->next) + if (attrptr->name) + { + for (i = 0; i < num_displayed; i ++) + if (!strcmp(displayed[i], attrptr->name)) + { + print_attr(attrptr); + break; + } + } + } + } + else + { + puts("FAIL]"); + printf(" RECEIVED: %lu bytes in response\n", + (unsigned long)ippLength(response)); + + for (i = 0; i < num_statuses; i ++) + if (response->request.status.status_code == statuses[i]) + break; + + if (i == num_statuses && num_statuses > 0) + puts(" BAD STATUS"); + + printf(" status-code = %04x (%s)\n", + response->request.status.status_code, + ippErrorString(response->request.status.status_code)); + + for (i = 0; i < num_expects; i ++) + if (ippFindAttribute(response, expects[i], IPP_TAG_ZERO) == NULL) + printf(" EXPECTED: %s\n", expects[i]); + + 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_tag()' - Get an IPP value or group tag from a name... + */ + +ipp_tag_t /* O - Value/group tag */ +get_tag(const char *name) /* I - Name of value/group tag */ +{ + int i; /* Looping var */ + static const char * const names[] = + { /* Value/group tag names */ + "zero", "operation", "job", "end", "printer", + "unsupported-group", "subscription", "event-notification", + "", "", "", "", "", + "", "", "", "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])) + 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 *linenum) /* IO - Current line number */ +{ + 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))) + { + if (ch == '\n') + (*linenum) ++; + } + + /* + * 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; + + (*linenum) ++; + } + 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: ipptest.c 4837 2005-11-14 04:13:13Z mike $". + */ 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..8f506093d --- /dev/null +++ b/test/run-stp-tests.sh @@ -0,0 +1,553 @@ +#!/bin/sh +# +# "$Id: run-stp-tests.sh 4891 2006-01-07 04:50:14Z mike $" +# +# Perform the complete set of IPP compliance tests specified in the +# CUPS Software Test Plan. +# +# Copyright 1997-2005 by Easy Software Products, all rights reserved. +# +# These coded instructions, statements, and computer programs are the +# property of Easy Software Products and are protected by Federal +# copyright law. Distribution and use rights are outlined in the file +# "LICENSE.txt" which should have been included with this file. If this +# file is missing or damaged please contact Easy Software Products +# at: +# +# Attn: CUPS Licensing Information +# Easy Software Products +# 44141 Airport View Drive, Suite 204 +# Hollywood, Maryland 20636 USA +# +# Voice: (301) 373-9600 +# EMail: cups-info@cups.org +# WWW: http://www.cups.org +# + +# +# Make the IPP test program... +# + +make + +# +# Greet the tester... +# + +echo "Welcome to the CUPS Automated Test Script." +echo "" +echo "Before we begin, it is important that you understand that the larger" +echo "tests require significant amounts of RAM and disk space. If you" +echo "attempt to run one of the big tests on a system that lacks sufficient" +echo "disk and virtual memory, the UNIX kernel might decide to kill one or" +echo "more system processes that you've grown attached to, like the X" +echo "server. The question you may want to ask yourself before running a" +echo "large test is: Do you feel lucky?" +echo "" +echo "OK, now that we have the Dirty Harry quote out of the way, please" +echo "choose the type of test you wish to perform:" +echo "" +echo "0 - No testing, keep the scheduler running for me (all systems)" +echo "1 - Basic conformance test, no load testing (all systems)" +echo "2 - Basic conformance test, some load testing (minimum 256MB VM, 50MB disk)" +echo "3 - Basic conformance test, extreme load testing (minimum 1GB VM, 500MB disk)" +echo "4 - Basic conformance test, torture load testing (minimum 2GB VM, 1GB disk)" +echo "" +echo "Please enter the number of the test you wish to perform:" + +read testtype + +case "$testtype" in + 0) + echo "Running in test mode (0)" + nprinters1=0 + nprinters2=0 + pjobs=0 + ;; + 2) + echo "Running the medium tests (2)" + nprinters1=10 + nprinters2=20 + pjobs=20 + ;; + 3) + echo "Running the extreme tests (3)" + nprinters1=500 + nprinters2=1000 + pjobs=100 + ;; + 4) + echo "Running the torture tests (4)" + nprinters1=10000 + nprinters2=20000 + pjobs=200 + ;; + *) + echo "Running the timid tests (1)" + nprinters1=0 + nprinters2=0 + pjobs=0 + ;; +esac + +# +# See if we want to do SSL testing... +# + +echo "" +echo "Now you can choose whether to create a SSL/TLS encryption key and" +echo "certificate for testing; these tests currently require the OpenSSL" +echo "tools:" +echo "" +echo "0 - Do not do SSL/TLS encryption tests" +echo "1 - Create a SSL/TLS certificate and key, but do not require encryption" +echo "2 - Create a SSL/TLS certificate and key and require encryption" +echo "" + +read ssltype + +case "$ssltype" in + 1 | 2) + if test -f server.key; then + echo "Using existing SSL/TLS certificate and key..." + else + echo "Generating SSL/TLS certificate and key..." + openssl req -new -x509 -keyout server.key -out server.crt -days 3650 -nodes >/dev/null </tmp/cups-$user/cupsd.conf < + +Order Deny,Allow +Deny from all +Allow from 127.0.0.1 +$encryption + + +EOF + +touch /tmp/cups-$user/classes.conf +touch /tmp/cups-$user/printers.conf + +# +# Setup lots of test queues - 500 with PPD files, 500 without... +# + +i=1 +while test $i -le $nprinters1; do + cat >>/tmp/cups-$user/printers.conf < +Accepting Yes +DeviceURI file:/dev/null +Info Test PS printer $i +JobSheets none none +Location CUPS test suite +State Idle +StateMessage Printer $1 is idle. + +EOF + + cp testps.ppd /tmp/cups-$user/ppd/test-$i.ppd + + i=`expr $i + 1` +done + +while test $i -le $nprinters2; do + cat >>/tmp/cups-$user/printers.conf < +Accepting Yes +DeviceURI file:/dev/null +Info Test raw printer $i +JobSheets none none +Location CUPS test suite +State Idle +StateMessage Printer $1 is idle. + +EOF + + i=`expr $i + 1` +done + +cp /tmp/cups-$user/printers.conf /tmp/cups-$user/printers.conf.orig + +cp $root/conf/mime.types /tmp/cups-$user/mime.types +cp $root/conf/mime.convs /tmp/cups-$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 + +LD_PRELOAD="$root/cups/libcups.so.2:$root/filter/libcupsimage.so.2" +export LD_PRELOAD + +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 + +if test "x$SHLIB_PATH" = x; then + SHLIB_PATH="$root/cups:$root/filter" +else + SHLIB_PATH="$root/cups:$root/filter:$SHLIB_PATH" +fi + +export SHLIB_PATH + +CUPS_SERVER=localhost; export CUPS_SERVER +CUPS_SERVERROOT=/tmp/cups-$user; export CUPS_SERVERROOT +CUPS_STATEDIR=/tmp/cups-$user; export CUPS_STATEDIR +CUPS_DATADIR=/tmp/cups-$user/share; export CUPS_DATADIR + +# +# Set a new home directory to avoid getting user options mixed in... +# + +HOME=/tmp/cups-$user +export HOME + +# +# Start the server; run as foreground daemon in the background... +# + +echo "Starting scheduler:" +echo " $valgrind ../scheduler/cupsd -c /tmp/cups-$user/cupsd.conf -f >/tmp/cups-$user/log/debug_log &" +echo "" + +$valgrind ../scheduler/cupsd -c /tmp/cups-$user/cupsd.conf -f >/tmp/cups-$user/log/debug_log & +cupsd=$! + +#if test -x /usr/bin/strace; then +# # Trace system calls in cupsd if we have strace... +# /usr/bin/strace -tt -o /tmp/cups-$user/log/cupsd.trace -p $cupsd & +#fi + +if test "x$testtype" = x0; then + echo "Scheduler is PID $cupsd and is listening on port 8631." + echo "" + echo "Set the IPP_PORT environment variable to 8631 to test the software" + echo "interactively from the command-line." + exit 0 +fi + +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.2-`date +%Y-%m-%d`-`whoami`.shtml + +rm -f $strfile +cat str-header.html >$strfile + +# +# Run the IPP tests... +# + +echo "Running IPP compliance tests..." + +echo "

    IPP Compliance Tests

    " >>$strfile +echo "

    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 "

    " >>$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 "
    " >>$strfile + +# +# Run the command tests... +# + +echo "Running command tests..." + +echo "

    Command Tests

    " >>$strfile +echo "

    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 "

    " >>$strfile
    +
    +for file in 5*.sh; do
    +	echo "Performing $file..."
    +	echo "" >>$strfile
    +	echo "\"$file\":" >>$strfile
    +
    +	sh $file $pjobs >>$strfile
    +	status=$?
    +
    +	if test $status != 0; then
    +		echo Test failed.
    +		fail=`expr $fail + 1`
    +	fi
    +done
    +
    +echo "
    " >>$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 "

    Log Files

    " >>$strfile + +echo "

    access_log

    " >>$strfile +echo "
    " >>$strfile
    +cat /tmp/cups-$user/log/access_log >>$strfile
    +echo "
    " >>$strfile + +echo "

    error_log

    " >>$strfile +echo "
    " >>$strfile
    +cat /tmp/cups-$user/log/error_log >>$strfile
    +echo "
    " >>$strfile + +echo "

    page_log

    " >>$strfile +echo "
    " >>$strfile
    +cat /tmp/cups-$user/log/page_log >>$strfile
    +echo "
    " >>$strfile + +if test -f /tmp/cups-$user/log/cupsd.trace; then + echo "

    cupsd.trace

    " >>$strfile + echo "
    " >>$strfile
    +	cat /tmp/cups-$user/log/cupsd.trace >>$strfile
    +	echo "
    " >>$strfile +fi + +# +# 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 + +if test "x$valgrind" != x; then + echo "Valgrind log files can be found in /tmp/cups-$user/log." +fi + +echo "" +echo "See the following files for details:" +echo "" +echo " $htmlfile" +echo " $pdffile" +echo "" + +# +# End of "$Id: run-stp-tests.sh 4891 2006-01-07 04:50:14Z mike $" +# 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..60656b6a6 --- /dev/null +++ b/test/str-header.html @@ -0,0 +1,35 @@ + + + + + + + CUPS Software Test Report + + + +

    Scope

    + +

    Identification

    + +

    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. + + + +

    Document Overview

    + +

    This software test plan is organized into the following sections: + +

      +
    • 1 - Scope
    • +
    • 2 - References
    • +
    • 3 - IPP Compliance Tests
    • +
    • 4 - Command Tests
    • +
    • 5 - Log Files
    • +
    • A - Glossary
    • +
    + + + 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 @@ + + + + + diff --git a/test/testfile.jpg b/test/testfile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9f4b39938a936e21f1c15cc2828f286a3ed4422c GIT binary patch literal 598930 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%0DngoXvd&QApq)a2&G0m{>!aWRuM5bHG| zEoV7|PHjO=Nv^8_Oh~Vux8{(utj5%ji{Ny&QKP1&u#T@$ZtmN_2}TFk3WAgY*lz=x z43>j2Chy@d#>Q^)1|!d$i0(-liN&OsrL-}csR!GB=C987iQt6F0%DbO)~K@$e_Gg5 zj?fKB&Hv>G=)EpC>Zj%+1uQhEy7U^`PRk_Te)4-OFSWsO@iMI&zg8>AQ%HWYg>^~~ zqSp&iX41%hf0-`BYJ%4;{^2c5clY!Uzh$XqrL-PRM;{73a#pC1 ztZ15R%^Lz&CQ{{>bQadaG(nL80z3AD5VN^0c7hcwaTP6_Un3GwI}5LbGgs6D+({6T zz<27>O$WLMpSejN4eHMfcHEhHwryiIRNgZ$P0Tt#T|-7a^>3X`{Ln%Q?OF5MrOzSC z2z%(%@W57crzpq;+P(Z;S$fuZbJ(GFqF2E$FFt0NIXuYbAeUW0_ZPOqF#w zXbdC04VERoi^PIQW_6r3cgk3VN$njIR(;Fo6df~PMQ;xET`EY%2g4-xB+;a$<;j%& z5GR}T%+kV=oQ$`?`*AvTpapxiLysw&+&1V|e4W+sM~V}1`-8m7+@2kf5cxUMdhG?K zyU(TH^#_h@8 zJhLCZ$vG2xwHOlRElG&#g|OLj3-(to`plPx#vPnl9A=gQ$!vs%8Gh;e?aX&}@5rmd zQ}O-Y=Km3W(_h+@Kg4ih|4bdQRp)jh#P!Ebe>%knHywF%vq^lHXllSi&Gi>ett>hu zD&r>&`oR5+y-S{MUn0GB>IsI(Jn|?hZ3fT}AB6p5hqUv}zke)ehEQu68NgLUPwF}B zoyqmfrlEiXG7R0q-WC6gpOTv+T)TE|9e0CdOaF#DuG7{L%b)-gB|IuH^r)pb`Q1$g z7YH}o_oE^C|F)hJS$`_~T{H-n7t#HZ%2TR$(2>VSeVqUe@=ZWjtK;}#VU#qe_8=N& zCYbPSLc$z45_&1~y7N!{_ zx^9;KeA{4Lb4`+_Z~5Q*z{DfVD+>90q-u?AzU(KeM={w92i!5)*wko>8Vbn6Lr{?j zCf*%d^LvXdBE#yk3r%S>=(%`Iw;bTjpU6M!1DWVdreGM4QYn6^4ha~@7nE(ERYR{W zk;R6dlsGRKDQZ%yulzn8IjeDoE2K9>h8et{7@Mjto*I6C@s(_T)kz+vcMTPgwJD9{ z%CcA;_BgWF6|H1DMIFGK^xz77KPp(IB=IA51E6XRwze?GyfsQ9E zn!5I&$g^>Yf5La+rOHozq#WNRN*||63MWcMOKo`94-YTi)JKJsFI)%52Q@9)>SU1l z(s54lug&}CSsfj!9~#}&hjSPYik&)Q-O`TDtC0Ln^o#ZDgP!7Q_S~}d1Wf~NYaKq9wXtV`&r0jRv*+6v zO)f3G1Gw7sf)2keM+q;@F8Ab}fti;xOI=n%-PuW^#rOM>+!*5!H8cB8!3v@9N+Pm{mZp7~$- zwyg9wt9QtTvTIHp?_cmO;fl_{Uu0YUOmuC#jd#BCoO#bFU;H?V%!Bp9t|6sDahMw~$j&Fh~2 zH?D{$VPJ3sxRxC;3d;!(vN)780hDzs>#1g`_UWqh|H%ApbPcVRm8*EsM)!S%3baK zHpXnbA`v6G$MsaO$f(}qGDOwgm%av~zJOx4!?(Romm4q4ol$E(yEc_8sMC4jOWq1! zBbBXWAuvn-g$d4r8)}R$Pi{f8h>fdXydA;MmjB3;%KMPbv=wKhBI-SNm~5QU#+7*# zF>AJb!|;Hgc1nLv8h;9;ztG9*E)ULEr(GY-9|QRLV{TBWj!Sbs_Bkbi`WIh2XAv#T z)(2)~PRWu0;x^*HR7a4UMnrb_QqvM)@@}nLkk0*4gj)MuV5M++sM)-2BY{Gx)93Vf zv}N1-smNo6xi!SM1+a^n%kak;IL5`-2@J64wcuq$J?B?gw=MYR;wtb z4dnocYdJChh-|WIk6EVxZ2>;~EM-ZdlAN3@dC-u^m`RIEMvlxpfN%ZpZ-y^RM)qO^ zSp4H2X!m>)|2E*|%3JI!pf}&WC>@4;yO#U_D~;r~=4Ce9wltQRr>RKbo=(xvOf-9a zvBK{5;ayF#W@~?8NdU;w=XZv@mBHtQ)+N47t|&<-#Cjb8)bcXXuUG%fta97IOO)RV zMjqX6K4}X5T#Muxxe>#2$tEzsi1SBx&MMOA%S376k|S#HccHX*_Bx?0_dVbM{!MrD zgye0XWoMBlysBUL6k+-Y8A*v(_CQLX3~38=lKsrEx#n91e>ZQ`Kz~_Zd%*Qh>*Id% zw=R_P>3dtP?HH`Qg?~ki6<1|yr$nbF0~26@qk7+1!o(Wn2#ClrW+Mez7w(tc)kt(@ zldk`zODKy>lAa~VBtM$@QCz4w!7I?%>74P6I4OM)Ls**X$$aR!*1_EG=cXw)_(}ZP zWOVxlsZT;HuP7ZuUOr8?{PBukEY=G$mu{Z zK#<#Uh5B_PbYEz^>bI4v$@KKI!1BbMSo)-{jRyMNj-5w6b;T5ep4riJO6;7!*A7*T za%V}c6QAs_Lf%dlBanaEEW}wnu^uiveAK?{Zmc?$g3sxnEG4Sw*Fk$;Xr$umG0PwU zA(sI&>74w^IH+rT9{pFtajcpoWyjhXwE7h#iKyc-7EYWJENw#cxVTgPwo-h4~>@ocET3>)QzdeKoR$2QOR~ z-Ku%P!a*8pmApI^X`!;{hswjn3UJEsnTYY5`6Xq#i2}7Fg6_eb-%BQ&HEbc(8FhP- ztB4g!%|lB8!6;6&gAdfNjw{o2GhD4KsrgMa(6tK+TH<*}m8&VO^193KGY3|dtS{03g0-#u4m4JE%p3;E(~y_$N8zFZo8{3$Ty3VWLR=tj9qhak_%d9dN;`_(F*~`Z4vvR?`DF(XSa^()ccON(5G68@I z3${NC`$H%La@LDPc#-A`HNg_*%8bbdk=Cay>pgO!lzrUa^RL=NL2q2T&)4TQ80-Fh zS~MZFd#S_zblSORk#ayC_fL>54Iu*R*{(f1oli!X-1JhXWx+^Ho9KIX$gh5 zj5>KE#09~~jCl)mmLA^`^NnS#@KGu&THAMi=&)trgP<1d?Q=*8Wa{S$Xsx9)5*V2) z5~>ybOqOA9Tmk^M zqz~p!=^TW+tUCy#H09Heo7^&KB3AI18}N!_!Db6_`%s{B^oP>)Vet>iihH|b6>9~B zmaHm8nyT%PzXhe{T&$*9eNRpx!HP_AUz3u0gIVRP%TSN2A48YgrG!|^uu$nrHq@Z^ z1jL8l#4c}3Rngux;3fiC-l1OdC5=`*YW9?9q{{z=7L+^X4EjiJk?>0Fs|9P`Q38Kw zM_2V16_lAyRfo3Xuh&&*!|kV(%lst_y<2Vd-D+iVOMIqGH|kvpDhQ457xX+wbWI{6 zgv8lCEJWD-0LSh?`0L@Q(Ld>Cw~Lg2jk zayhtCs{4fAhLQ{J7JRhW&AK=d6`&R}s+ zG_*cXRYB?N{(e!3H9U$0)O_OhqQ`Z8&up{k?y>U+jZRG$ySdQuilaEoI zVc&7zScI`4L9fvZnsy8yb;V6+4s-_y4kDamEhZ?dHAIoA6 ztK}Tj96Yv0`YU-LE&5|G4UD+74WEo@ivCFJA5Ny1x|9H6(Qv^%f)T9lGZ#T&`oqC% z6zq?AL}$$07UXl2Oj5cE+X@6He{uavD%j+6Lo&JQb1{>TR`T&p+db?a6&VRYw0WH2 z%ooE{zA)MajO8>;7P4&>rx(u<;QPyuOxE&yih2FbPA<+0{m1oloe6p>p z&iUR~PBp-2i8}tAH|YYkD8@*oqU4)*{nLkH(Qx;MZ-Ed?BN5}^{mt2IzVjnob4#eK z`R|N^C!I*5TA}5oc_+>(QW#{h+&Z%$96LXqyX*5YWEEXFzUSO@BCHGGghDTilIuvl0eck@c(4y|TnuB(Nzjg1HBp4A2c@`)4EM|JdF+IG&DJj1D8k8Q<$k22VXpc-!RT;Bl9WYbw zCC~f!DZHO9_=D`MuI~F^PBD0-$+WT9Pa^HOi_6^v59i()l`Bb?@z^Q_o?`>NW7PWM z>Fe%=_v$SW&H;S`E`fsD%*;;Ru`H)epv45X3DU7)~!F7TqHWcwb86h zHiP8o-|VdWuc*dFlls8T$#EfMCaikZ)(tT)#gN8$_c#1SMXc) zqaFkQ??l7K z1nKidgm!$#Zqdh@TE4%caFEHBIcc4HJpCUaR^GeGj_!G#&M;zp)^8$l|LRxh)dNhv z`73eX=fpQ}SEp~*abg_di@gjCx*uCbaS%&QZ^lgM#4T=G)#uV|xmUOYXP+E2vSUIS z{WkukG2k^cA{$rqYsJB{;pIJ5b=g40kCK*Vxib6O+T)4^L&bD(3-{vTI{ z`t}oc;Uw=EEVVTbIM_6?X@zYzpd4f{QCfGZnhht|!+S4(2}EB9&t|oEg(;yJI`=JZ zP@9p1(yQN=g$}aE5BJ*dwK>i6tHkVk4t&Is87=mc3IjYcvvDS2Ma@K&6)AL{`TlCm z#O874+J?+z&p&JYIqCRvM_AWu9bQYR<@58sHU?{_=Fwb^Jj6t{O#~Xh_!XPd->Ywt z>WLcg$69RY8ytG&&p(D}GBc&9ke|vzig} zplF^2?)q%;G1}6^!Ovm}xDZg|0YHdeJu9Y%DkNQ;(EYM_c ziAq8Rh=zN7E!>wKud>ffU)@VImX<^(LzyS8j(nH(2@V@`4i&d}*#!ynzRDSc-~Dj4 zYiyqw)6QExYl5-dX1G=^Y7pw9(BEqiUt0tMBHy@b9Ay9I%BIg~oXufFv1^d|Wu))W z1iGQpKD^i4ig$A5pr{o*&c-Hhxf2F0uJ}E_i|VIA%ukwUJGTIqsM$-6+8&iZU3}lx z5_IbCf{ykNTM=W=&}+%=9BXv>X4BE3&K&MxkFPtvG5cm0SSd8CGcx+Wwf$ZDb+^~N zCdDpUJzDYZRl$pQ+pm4wj;BZdNv`T@BEdlNQ_SWL{F zp5ZfwdED)8oW!Z5DnEA@`0f4ULe8WMz)QtUm76WUO;a8<4wO) z0bdzDP^6FrRMpt?CwMb0f#*zl%E#X~x_KRn`aZ{Hd&q<*u#UXp-wFH(hLB zRn%#8MIANVf?A?f2WIblATP>wfimD(|E3GSN52nUxQ94&I{N%lP645;Ug_&XPr4}xy2hGOEn_x^81Tm3Fxnfwlq z>2D0!OqQi+E*9&U=^7=NX$V*jn!X^;gS^FmO6h+|;1R8iyBxY&EI((vVh3v~A*R&% zE4@hZ&$*oU=+j?sP!F&_b4JgIT=s+%Y|zg?9Wqs=%Ty}&Z@@zCi#ozJbN8e&q;lHx z#!Q5BK@9c7IrJRw4`&5}8(IOCcFnBtIwLx+_U zNYh)NJE)Z)Z@s^In*6KGD!WVl+yzbT?Ye!L3S`4uW&rY{mC&iGg z?{r@gg4h28XdwSFZ+&-zy*HpXvVo7LeWo$95}|?r{ceft39Yq~`)uF-;oe~NyCg4=m~u=&o21) zFzaKtZOzMSn0jPuVs=KSbN4jo`29+b8_8?$BZo~M<8$0QNp{o+Mqzb0Dne0W{m%kB zb7{r!`E#dX;a7zY1dTY7WzBY#W3g8j>d>P6V8YU zgQnh?3$0HC19`>_G~2K@qRi{_ui~Shyv}SLS!yH%$5qmqB+$&CpN+e3$!emGSN;vC zC>44=7}~ioU2E!IO3^OkiXQy(eM%JsPi|eNTwqrY1PQGfQ)Zh5xN)-Oeugo(V2|muJ7VlwEL=?3LW4A>|;j zE2mBaOt&gOr#5GBybY-9~jGLA4Zn46Js7e7Ht z%CvG$-4_I!AIvC)}9r@=UF|t{?kb%db~=Pp=7v8%!`!Mg?R9cd6Mr zT;Z)%GPVzsI+dKdr|Em2omtofeQFZ<576^ylgrdxY=`%Yg-k8P{7`RF)TPf^> z>NCvf+uRI=@U^tnU)|Es#SekH4?n*1q5chu;miNEel%##+oSl2Xs`6fABar1s#+F5 z2Cw|Uw_DKXgfnoX^>uV)8#-(Kxaan#z5rN~7x7Xx!TDm7eUhS9KnT_F$26FNZTA`Y zz@uInZ=tk0zcs7=jM6ob3XZc8Bt^~7ZIe(WDoQ2O#oQiO=ECoe6d1gaRUgZbn#%w%Y+OrG2#;Kz~ z3?ASDah=IFe`@~fzP8A;x`%n_ej4$v+uEHfW`eb9f!RXIOGO3T^n4Zh8nYw=-}ez~ zNYEm&r7zzc6WroHHQ{-=527-eHiIAVkb}QARnXxCZ2B_7*gV_**cE*tA@VZRYJIa| z;_KWd^p{_zQk0BQW8vJGdtpZmVIsXGz615GWqrX#GuyoGKY)zXx}s&_L&QmWEY4t< z-D0@TMe=bnRP|Ih<91aGasC!0p@K%0;9nH$FO56BLV9*;h7$EPu-4Ur*9crlO78@# zBt<0BZyak-eQ!2AP~a*rHG8%^5XJ9PVoisK9^QU!V&m$d#rvfc;b4r(W-#S-XU;o{ zr*l2B-7Q~-bJs7BHtZ!Hn?=joruxRhE9g&-h}oWhZbly8gjOdX?6&;@`f&boZK62|CZ|o?`X+UQEjMk3MCcOOjm+FQ~E!_*(wE{swV?IXIw{b0( z{FdsLbe8I0K1Z)l`wR(*{Yv&Rhi{n#Q6#&({ONh5!e{U4;(y9k==%47%)m5yS%2|^ z-Ry_Xd0WpPba^gRxSbh3HP$iQ}@{Y7QI#iEJx2hr3>L{+cxPI-T?#3>RN5B0e|2|{$m zl>)>l!!GWP7H0KkZ4q@fwO=ls$JgZ3eoS7})%o8^{94&q?~ou4MYFJk*{0vLWgi4Y zp8nR7nH6m*4cn}dq!*5}9>M;?8Sq!ManN6$j>XT&&dTI09c-v-otvs^EVq)b9UY3g z?OEOBU;RdXI%7 z4?NzRy3*OHx;eUs16Klh+Uytpa<5_9U5sHD--y=Q-;^E&N35~Vw{xySx4$N*ORwCt zEb|J0g(f1ysZHTiqwBEdumXuNGo{X8QR;w0a2)F!a#3aU-w)ntQWkr-%I1;F zn+&N$9DpTa$}!YAH9mB=k*V`O{TW6=Dl+?CX4x;@7|l9EONw(Q5fwED%lsoU(r#(y z^-pQ~5nI7Ee7I9n8JmTSOqk(nibz+6VLh!sdk>65P z({RpW384ObxHDqDU&9Bcc!3$`qFkJz{2t8LEk7L}2pl=Xbyc8qK8WVx$NVLEy%M9L zlxL^fSd;CY{>@~E?c@>~o*|U9UD|)C$2!R2oL|I3pUf&w zqSHl38^;+cly)zl<@`YufU|dh?nrNC|>T6qW=KNP=bby&L-_h zCMNP1?og(zr~XS*=R2wa03!i@1~L86-^}h0B zsmy0|qd?fem{@Y`gD2Fu**Z4XP)^=z&)Fh#RsLx}d$gKTI2>YJN_+)Ur2D6lveS+8 z7$C>{*mKrC0Mk`i`CL<$lKpd&H52^blRpLO+DNHyr(wjJ&oH8a(eE7|&KTp*~v zL7PVbWBbEX4P7QtOiBg| zcr^KBNqiO(zn%PT_5oq`h!`RU#7DC)_AqH#^XW;hcIFY_wRe$+YIRt-=Sm zhVIVFmpt!|SDPOY!fW}(n$?e`Tm5Ax=#;8>nz<$!#r#@td3wEXtRH5DXE1h{bvhrn zw%jGQH=$3Y+)tBII*ZzGM-2*!jXKb0NaOLB(~~_d7#W$48Pw{IbJl-=qOC2&&opUs zf4S3!3rk{gK`r1^Z_CBCfQdM5Wd)^ae5WakUt7K|wcPS2dP`POop||a()M%~b%m%e znj2V3qF##YHcpvZwKBS=-^X-0sXd>ov>&pCSkX7-#2E(FatEh;wv$MY*^%JRo4UDu zm87psC+%zaH4(b9={t7LlQC`d2gaL#v1U8!5_>9$Bp$PrEk$yRkmBq%7xLd8Ejw;} zlt7=~S@>qYThRLXvDif`0oElgx%LzDk09_GrJKE4L&^*gTguQat!@WD+#>GCtYb&h5SoiQpiThm8yoepvrFf_G@gGsp^sNCsK{9?mN&&G z!TF}85$yh)1ci9%x~0!U`)g}`Is4R;@&lzkE?e#^qLP?j)9dBUJN)|`;n^pZG_T18O$^PjI zyCjRR(#gaj!N~ z#w=T6;eW)H)uUSJ6 zeU>^y(#>`YB);i=QSfxY0#Nli+Qh#`@}lYdY_8q@u$(BB`D)KLpQu<^mBiX#=sUD^?e@S8Ye+-40u2vda=6Z1VLl(X5%NL;JDi1j9fM zX6Y+3&p*e+B)HGVEWv;J+O4dg>Sp&yMXqb!cxaw>!{W|way5$HGVZA{GcHSodHQyD z?zi9Cwui=$MzShQouO(Pz4l;J5LhP87-F^tWnqh4YXMgQy{lyJ!>pVx4Ym`Aaiof$AV^XL+nK-)c@J9z!sZsn6}d zLCQ?y%l6??R%Omik|oWaQB$i8N@dai~C`sU3z($$au5Owh};jVe0DzPNMwO%WP&3U6Qd3pVnQtE$ zn|WYA`n%%imP(5=J;=3@&!JIXWsTNbuKF+EQ)H^_px%V^pwcfvc`|f*-O9&l>Nsw< zJb1NxxweMVI|SQ+8fP4R(wM67s;^dQUOrX8n#jQz>t_Nhe6?a;;oP9HgaRRN(|gJ5 zZZ_QdUVdzyD2T$|j#F;_s5X?z177*_Y7Hdt&~n=IwKNReQ=o{DrTobthX9*m7&@`! zVWX!_8Gbks^l9Oj?O1_YL6HKtk-`1WVW4>&h|vN+1|Q?nsXb>?H;FG&Rb#1`D!mh+ z8OJyFx12s9#L=G~b?{WpvpRQrof%I_Rt<5*Q!N8SnRhtc5Edgnd~bawICQF?Cb#|N z6p&o#C^y)1bYG;*d1;KRadG7`2TClfojJfstcx%|d=#Z$R3(dY>kHAhv;)-TK}7Y> z3PPc8g5h;-1mTjiNkUx!`?!yoy$=@kO}?iC2XfFdPIu-#cghp*!kej}=`_4b)@%Mj z$T7fMWG@lG;>#E8E4yGPlVcg5h#5>jvKE9+t5@uNIT4Nm0A}D}GX_OD*x$MU zZbH4Qeuz5uOw_n(@Q)y$Zry3_j9cPmdOv0ca=I4`VBUcCT-LUHPS5ffO{jdxhRt9x zyK^myH54W8ikZBhZ)1D5cEzHsK{QM0#%LJ#lLg_fQCa-;}C z(seR@SKb}iQy=GKfF{Nyx@UBW6jyV717(gY9_H1w1x#Q?fztzn$`Yb!vx$Ocmmz$< zj~DfZByrO+SmkV~K~eJyGJX&%o;0*!bn8b5b2ZR?;~SqHsst&@pFPrg>KDq_A}^dT z*&TXprnYFQbMZ_AihrFZHP;qrW z>2`^q-mPOQVo>+Z3+9}+8=S3PYi)`onI9U~>%Mb@iZOibHk^c7GEKHas#d;_9_)Wj z+CD?t%lb3wNv+mdv@~V1sTlcjERG*(cy!f3DUvH zZ+(Qr@0r`n!cNNId4%h%W+$x6? zRzwzwtRbkDn`IGy{-ss)`r+tJK*D;{3vZg+do->03{qp#pnMw_egRT{$$24tmya?V z{sS=l2iW4MbtF84yy@Uj+}S!mz~89AjGF55Hh-uDHw8k9)}&sYAuq)@Vo871X13In zz@ZZ?P4%+*iN!!J&OrEC}1FK(=*A>2lgO<(@CD z$KR{zk=>#N{(EGPozVD>&zC^SNCI3HvhN&j{K}a!H3S-16YZw;7>n$B29!e7^k#+ zF9!8F%M%+f89=W_wZnXdP9^RnE$*F4Lj0JVf|BC!PgV$*^~>iAO<>Yz#OjRSm19ms zrS88OQ)BbZac~(K0W#EM2HWckQjCb~A#UnFfRn-bA1YZ6`q}&k(f!~+;3j0vF^saaBg7e@%5`;S-daWbS8VEshp`54{SZE z-dU`rkAF8a@A#zCrtf7TlHD%D)0(d@?t==1iTB|Ukf{_)J+)P?H46WWGg-OBbWi_-m|yv)YR7&9T$q> zN)}D)j&2n=x>2VeEv+n)>^u70_Fuii={S`p$VRSO{19tc#`w<_E!asJF~!&g%+|)5 zeSs^m3Ww{InB+Y9E+9iRA^$|_VdD*VSLdbsK+w#Kn$#IqggpoO#2T^P31oLs)z^K# zsOmcG%k+AG?Z#lR!iadLmZ70tQnP`9>T0|6&=_xr zbn~Um30UB%h)8|ht431nzt^kp&|=?6-rcO03rXzjWUK*M5jDpY=NJ=6VoUx#q=UdY z8s*bs@YZT|jl|7w+@tWYRaSks!dCgGWu(&NzlA z&CWJ4%zjXRIGecN*XxI6SHhcrj8_cgKg1XLtd?bt;w9diU8U7di%CeZef+5(*qW6v zHGe@uh>r2}qt&KTJKV>NjQlwM+JG=qWAo+63j{ZiVNDV5#eYmhDquC>_IA?d_mN9o z@lyFE^9EV$%oa=mU%w0tA$(iELMEy(^V^J0T*@mSVhVpoN$Je(@Wqszj%a z_)B_3a}5SDSR-wPwjt7;)+WGUaFG?dQ$n7NPcB;g?1%( zu)d}n^z4t1@~sYC#nCklf_N5!cK#SoW8%iT6!}ANY@8v7q*G(?ND+ z4UEc0R?s;4qgtp;vgZh)6K1=Dzjw>5ZNX-~nR3`%)nw!b;R%LG0o1{;2Ly8N?%!@> zz79R>=VP(7IIJ3rD{&oP%8U%7WHJ*ZcrY?(UgbH1YWWW^cbUZxe}q!5)$iAw%E zj3G7eia=hHR<*_%?MTroJ`#1URODYO)!@L9(`{Qu(e~IsdfnDrI8z4ydBA=vTwpfXzS(QGJ?5t|0+qA zAOsEm55NjJx3uC3xAWR@u2^8n3FneodnGV%5uonl<15St-DJEQupO)1tqYjg{2D^b z82CUnM9t8bj-Qni7L(Rziq`&Up1tuW;R~v}Bvmx**EIBqQit%%k_e9o8DS>0&%9wH zy=rA|quW5hsf*M0H0MDTU22oir~+~(o{jo1gV8B(e!4C3i>Mx^IKoiyiPzGw&VVO| z(er@v1JK+{2u8CU~wad%y;SGCR_??xJ!m72Qt2-s&y+j6I6QY zx$rH+daKik$yodValR!h6?c=IAi?)9#`ENJG6!II8c%o;6!BpyhtreFh3clO*gDI+ zsMu?k!Y_PVbO)NzRm^vm-mv|@gBtoDz;VNFkBN&Jy4>=qsmgf{*BX(Q@^#IpX2=B( zS^e;sFiC=ItKwMaGo@S6ElZt!D@W7)u>s0 zNMqckS1bSJ?{)!eK0VC8rU^(e;Z} zJq3=8A>JDT!dVyrCLPmE>R!LUm=?m`>BM)A+`;Cnpvl~0KyCZW9<8=^FrWb%zOnZ6 zLrFQ!JABN2sAUNjvvx54_bC&L05J_{PwuiCQ*Z{=bQ&WcJe?CXBdjm2pR95;-+nv+ zm+tww9-U)0St1#t`82^HKCYPxoVn~Q2#I-t*8Vv+t_HKF30G%f*#*B1kRN;a_^fT% z;IaGT&1)p0NxY+siW(9oS1A8ippwV2aqt_4z!k1}MF=+6Z)(AFl1TJfuR(fZ=|p$L zJ#5F9GgeFX72as9C~F*=I-X$Djgpszy7W$+#}DVJa|#4JjD0%Q-%=7RLzlgXkGvvB zS>p9TrCO>UxX2l2Pw8XAdN>e}9`Zk}<75By8V ze{oS$pG){<=-#NcZ4xHH&CiU?&QX@@Sg6c)S}q0pan6XIi;s5Wb2MO zpk_)La&m8#iHs<|W*U*@zN7U%%VZ+=o`1_DN8u>;dQFx%?;GSp0NZ=Ab*vCaZY_dN zoU7VCN<-^+n~kf@#1>i4Z-0Kv*uRILQBBS~1#WxnZ95yGW>xC!+z+H#`vN1TTtUCQ z{}}yDO&yU|kKz*WmTS%aiVAC+@0^7}+ujSivH;(`sOt(gMYvKv_(ATvId}Kd3=??B zLVJ8*#d?Kv;l_8Ixio(Jw8`Lf7iZVgGcDm%sYFfC_ z?;h@JF$a#iFvy6dB^TMMQcR^PDZO*DIetl%ZrX$=82*NA!+o{RjwI#*y_|Y#_Y!sM z5#S%KwbY#uS=T6%pIv3jSDNk(A!KrCWH`=uTPtlI9&9xs=|$>5g@1Q$;MH8WLqT2=zn5I-LSKA}xm2O&_X5z`7! zvBP7L=Sw+X%ygXN!pUTB^sv$DY$HbP(o0+t>-@4_8B_LS@o1ngg!_YI1$W1!=NSnC zSpL3htmeB?w8K?!=+*D^X9}Wbnv9bhu_p?xn5tMN%y%vKjy0#1TJh*9-KMEricz zN?U=r{RSb~bNZ%{kgcR(^h({Fv!w-`W#F<;WU(QI@8#=_9#C|KKXo^*vB`P|5l~*6zbG z^3U}CE+j6vk=&7gKP3!a8l&Q2B{DfCu#US_nO+kypa?pt*7HSM2ekE(=lVV48F-ji z2vs`gqE0k`HupA`Nw-@{mlY!p6_n;Bnh|(HE_EgQ^W0DnKAhllOva!Ob!jcmc3z2A zw-EynIT;C&uKW+zMA|Zxvrb{56MkKJBh`;jfNLp2dp=1NArpfZ3u6q*vggM@T#Jygerp=&wMLx0P_MO?* zYtKigNr__#b&`?x6#FL`nC&5I{P& zAA00j6~Mdk%BR((N8edM%855>lkP#yd&7mr7SpVz#>QW9v@pj-Buwz4d-Rl?q!91Js4`lA#Vr`V`miAmO=0EJ4yp&e8)IDl} zp=IB#*1J-%b5-kh9$8hIZ5`QuEiFZ!AthxI>YZUGCT!{aV!!Af1v!gnQ_kd1WNje@ zqNC53b+kO{LK6G4mwB{?d>(c9gGCN<>K;VUXNQ1>stRo(a#}N99-$H>Gs+txdN(aA zG%8=Oth5KklZIn%yvGT=rS?4^5Vl5)Zf~@CPzy;N2ejf$eklEi9lVzka z`wFgmUNC$&C=ASGFu3(H&o*hQEo}MVg(qW*L!f(QQNA~h3G0pRl( z3Ip(-jeEct!lbPs*dsa%XJrBmpV3dT1W&85Icj^xTKNcOGL@PpZ!AmevCS-0+^^Z}fS$}MJ9odK8;6k_ty zr&px)O7p3(3hUeHHMGR%jpP_!hjat3Oy#cPV#95C_kRHGC}~f1us%Kg!@O^Zd#rXe zsKcrJn-_!ImPH7;quEBU#7mjkp$!K}{St~+)3rEOh!O);1^Spd`>%e|jUVs@t9x`T zVqnJ6xUZ5`pB+Q|EG)nJN5_sjIM|)Y2nc*MNK1Al2QV=BE=Y`@kL*3eZLxWcS&L#{ zjg!5+C1-ovVwz1f+J5(R6rI7JenhxM35&3Rv@e4N^b9&bPEaZ-&t%W=M;Yy|j~ofo z6P#$Cta}ko5|x2GFSVR~Rw{=i7@9lcD&;CBoDW~OufAite|{egu4t`(RWZfU{E6KC zgUCo{K!;bezC`JX*l{{n`qogOt1r7zYgOdt)`<-5ymIWcaEgax+0;3x%0NR@M#LSB zcu=mBakw@&I#az@ex`}r5jw37|p@jDn~utN^KLA6oK<>Z{H!^!0Yor zPgZF&x@WVLC{T7=YWFJ-Cmf9 z?Irkr_)j|7)=w$M)oj*ZR~9lq!nGHLyK^y3{%&r??mDOHFz^$9o{6GX`Fr%ofjgwe zD*Hj)`YaAwc3-Rnw7LHe(A09HKf75YA}Z-d?n}ik+apsWuGdddjtXZ*K8z!e!zqRv zMc-O`p}suF{Mo~sYfOf}=}C4bRB74J@n?aVZl{fuPERQj=BidHLcQ^nsD$K$b7t`S zc9B6|a8P7=tWy}*`ijEKJ`=O;^nCtLkxL4yihCN{S(n6(h{fse-Ufolu84ba5P5mB zhP0_M3ohH(w8`gu|FtiLQj{tprpqLPfasPbWb2;gw8&`dC!N!5{xs{V$x@z!|Cc}d zQwlH&FJejKZ!1qEdAvi?+TQi(R6hp0dy$@eJ#l=#?j|P(3c2Q{f`e$#4@e(c{Rg1S z>dUTRo)dclZSpgqx11B%jezR(l#hw2(7!VmOBg@B8vOF68#OS_?7f0C+W67z_fQ@7 z+P|g8qKn+UYGsQct5k;Mflf|YW&4nVWXFcVDgHBoxBB|7#R0DwxfbH@D^bj&ReqOf z7tIxg2l(4n9Yi|V;y%R_A1=eLpy$w4GpCkFIMZF!xYAAf8u)0bSB>gB9#Cnyg#@E6+N_DPCIevE?gB^f^vacsrSI()8^%NmaoQm3RaD1F zhxXLGs^98t=XA%sb_Wsoz8Rl9obi~0!K=1~H7EQ9fT(YP`S9j2vq0$VSI8)jQChwJU;PLu+3 zs$U%*mJhx7GQ^mZ)47t3^RTTT(7LRJu*^+xf0VA}QrxWEt!n0NZEatu#_XB4alxy( z+*f*kOP{Bl7#WV-&Z(w`P7re9l{*C5>srp<+!mPi@H4xdRS5k5AMmX&3@#p@IIxBQ zPE-zX{1_vPVhm^Z3~pcS)^8fdjGJYJL8ZTsFj59Bdi%*>q=VD#^~ zJvVDFN$M`Qdz-itu9Lpsd{dKmj4T4-eY5PeW1Bi-rR?pu+qqZbaB5lf&hw3P=F-gA zsyL(bK4yQJ^?Tk~QEmzkg`xxlofiu%GE2RY3(u-G}+*|xm+sqtTohvGo z1F3puul)1(qDnSa*~gD7MDtlZZFzQNf!p){$H-Z}HQ{*ge+Yb;Oa%hFC^Gi2G%OoQkrRkWt~_JPITFbcnpzFrg=X0=@D zySmmiht*lAg}JX^bXVsMC}aC3Hi0F%DW!#Zq<78r+(TMx*QK_ipL?lq#)Nd~Zht>R za-s3arTnBknPQN%(X8;ziRFXU;0ZlD$ZJUx&ou(%*mlKoN3A zPrZ~#vp~m7h-2H<`|y=ddfWP!0&^2-5+DE?cfPl^SY?rKH|~u1RVD#w?Ke;DZ#Tzt zjl8>*9xEj?m(kEpQeDNScMZ;plujb=x>3L9qOAtFxq-j$Rin%%+yg~hki$*VZ+&tn z$^va~K0C28`+xx}+A=TA+0`zURc}AMrU39Rs`d%N6)6iZb%IUGd^47MHhC4+pef#a zw>6~$Lac@4L>fr|6-~0A2C%TkrzvmnQ6) zFp7{G0|}KTJs6-4$6qE!&5rW*%EPk?H~ZN$)U)VVsMmL~*g(##fw3_oB6_VM@Rlcf zEL}K!rd1UCSE+BjtQHjzX}rwk5=qp-YTP5Z>Me~l-mb`!FvH30yxkEdb@~}JCTw8Q z2<(&0_zIg=R2##S0!xstO!=f04yH6@eICjC9fd4Rq%eoLRx~tpo%v|RY!^2AD9%3V z0I%acT2}eIep=sNUnl*@gsq6hrOtMucJ8wKnhAQ!Dge+C79 z&LyT_Gk9Eul}?-B#%(}Kj6qm|1JX&BMLyK)?8IJK<)a7_nh+RU%E1J+#k6rI;Aw29 zcVm7y76`qxDu*Ta^erfF8rz}VE}3D&QqB@wTJ?~<#8lyZzK+lq5%{i|`#q25%ZW1E zBkpmA<@e2Dq0571carY7fYhus07)Oce~?2<}(J{?P@vgP|fH;@G`5*6^Pd5SYWt395XEXMn!Q$zutpFa0 zed6dZOq1>!xCd^))qh2C90pc@V;HC#8y03r7w+2hrz}|WrWIurF_ZuC5|a5*IHsvJ zN_EG!fXVVFsd?n)P~m@#u?>R^HMfx+LOGAIu%8#Cg-P{f1*NBSPn8BJrWbH*WIt&x z*tJaD5gITikpWEOkL{ht;xQ=>fwX6@|4i;^!sGIXJgMhmbr@D}>3utwpfX0TrqWA; ztQ7-^v<~DHW43RZp?njCyCTT=-hc`FR}}_XqI0(=whAV!DhSDdE0CvZnPE$cvAJ!- z0q!030B--3&EHmaLw--tjEDlxwf8bf4G2RI4?q#HJL0}(^*Eg$&3*0KL!{GbgACD%TMNg);ditZ)Wsmre4>p*|ee=eR0}kuo#}4M4Tc6F2*T+kxob^jf zx?3&5MDFK5u$>XM*VydcHC%}4f_Gpy_$X^{&H3K)H?lOlwP|{E?Imez%C8x1TtkfX zc|Aq(JH7F97Y>mriBj|1#W#Pnzjp)7^gmf72Rh~* z_=xkrz%PtRcrTQ1g>TN9Co1N1GA)@O-uBCZ0h`tz)pKb>EP;5vA^JPDpn9A8-ochl zwqhv|=H&1pAWmRdosdaoaejy`C{<7S+981~hRD>Iw`KGkg!Z@>^P!a?fJxL-8y>To z7X$We%i@$*MdB-844S?SZN*RR!ogA9od^;}yIBF)*GU}8ViW8s+WmE9wef2y+{@7HcMw-9fKcLR2{4IZo zmW0&yo}eH-YJzfwV@Icu@yT7K9s+=k&iQX*xFh9(8bB>o`8x&jQ3643$NTg0_Gw}! zekLcXA2~F6{mL1)3YmYcc&)aiH->Mf=I!PoDSV*v_En~h9aQBde8RD-1aPMKH}+S7 zb$KS-v%_o=LBn`%qcUjrdUi;`b8chvW4*qLnSCK4u59A*C)x|al{c+47Z@LznYM(k z&DMn5?*&J4IHDh`MLGl1+@T!jUnAUfpPTXmIn$&XYP}ft9E!gEPtVGb5_OF`cUgLeQ zu8a-syE}3;jV5!4X}!;nT${2y;s&gdw8*4`18@M}<2b(5vL5xbbQ}s6P~i!iv;dNw zy9T9%-v@Fmmm?(YS-IZZB-xij-LXT9&xQyN&kSV?6GiGMm6)Zka#LbCfp`4JEX)g`H}tn9Zt7^y{G?*Kn18 zEQBjv!;~$+Ht__l3Wn5rqNy@d8hZo9Tg3EQk`_NO*+Jv77I2OD*1KgE@1`*<9*iGN zQY)KzwzA|HPIiR47G}&w=|_e))bQn6&~*iANpG^TnAX$xH25jd9ofcfvc*4tPC(YQ^p`}q<=Z42i&zPsqnRHY z#@-QW>TAybNABgefX-MeR)`RC-a+%iE8t9bK|mB{@`xQT)`)u2%nX;%Gchc}R4gqX zQ2;mUf_VUP$KVgM8C$LkE76V5X_wB|$y$wuE!pB5?AyK%kp4O1o$Ja8$Ydd`JtqRI z8I)%kBG&(|7jPw699#F#iyO*(v~o?RvfO-Z{MJajR$;ZL1>IO-%PlM32m!EgCx&)4Jo#Q=O%&f zUK2)aL)WGtB4a|pJJ?*T-!4xS|C#f;^!mG^)}@-75O5kXl}C2<)|$NchduaVu;D)d zS-rwL?#;~xqUtj$_g52)T>ib|iaX=><|jg(zdt$B}ulO%3GN?kNZS$aM_Q z7rmihKQAAXV93)vzdlY6&f6;%RMWkU5^ozg(;VwtNN4ck5!M`eSRVL~G|QLUmCwZ^ zi$=1W^G91sgd^d}F9G;x<<15(u#3A*XHuR?sDpz&|4f(KQJ3wv%^-28Voy}Ak0tv* zKt*XMRJuN@@MmzBuh=ty@-~Rnb;fJ<Ujfpcdk3js$Ng7f;^U@pRUzX2r)`8`L@gV}sQfn;}_8Rg! zwqD)X;M`Wv2R%3U=Z)w#(2B?|V%fcsJ1zY9l?d8E1Nac$us8O4O+aRFoFNZ{@zKJ_ zH;SicdzneM4bj=7h=GUX9Xx#YJk71fS0f<3y+~tKl6a2E3j&dz7u$x_ z&jsnz#Y~AoYtmE@4sUHwYjQzx*>we_6(6k1>}RPE#!;6=na;t5uBqJc1zo|p&0LER zZpA4J z_NTxe?^fiz%h_rFoOPgkr-LV?6n5JZU|nGy^b9f)eJ-+-9A){gMyRzBMa{o#XRqEt z;X)dE?the3D>!C6r>Vp0Oh;LBEQa{@S8lER&}4@%FGD5d7a{uh@ExvbTSH(L*GT^D zzSv`zc-cD1k48n9xuq*_jSPw3pS4&%2!Gmi4cD&b?DdFYUnJ_s(KPax*xwwuZf}I| znD#CCibQ)7a=~d?BWn};@ogWy6FjuyHLYA_a+L4j-0{|8?$^_nb);ZqRCt1~ODy*H zyw~ZMfBH_)$6Ln7%nV*aOvlwS$O|tiuW% zjfhq+TW^_i-0JET@bB^A;U*kxNv24al+OhzW=?Bg|Lm0R)8qNJIJ){;UuT#(C448? zo@nT|s<71ZI;UOcpZQL&yLdj^BDe#tV|4;QOYnHnlJMO>z;}UrT8sdV>wU+=waz7w zqM6wLCi$*G_1RO_u3sgLau>{0Nm&m48n1YETqwkegc0dd{ryu(-;uRLl1)cN#EPe6 zL7Bku+ggvtm^H#Xsg=~&`kJ0Kjbfp1IUqOVjX@^P%s*o%x>b@WWL_QaBL>Ryde{3% zJ8ujqETpm0^oHrZ*KC000qF8JPq;H#?P=Zj_fii<%b*1q{rU%Ru>^*#}$wD^!;;?kN%Oc-onTI2+9aQ z)(=|U+(Okyy?-T!hDWsqE|%Yw-%^QEkTQ}D6<5u753Fh3I^{XpCkQHQT<7}|C4oNk z>Ws5_;d3~O*#M~;gxkxQ*RILZwHUOvw{L|bPuIGldX?JMvywO*W#Y1Ky|{k|U3Tun z&Z7@D@py{hMc*Pi*aBCV%TEk^g2)IPr9^I6dA`m0aB6vDB!=4>=N`GZl*@g!dH0dH z)YEDD=t+zD+&y^pfKV-Svh@ssAbVyCHH|&0>r>r{IYlqRr(ZPacxmPQbtlgPn{!oK zyIJuXD zaC2(0e{1{TbEf9O!)VTsb@8VbaOePw&0)J$3t$t+H4rH^xiK*6lW{moia7(o?$bqf zCiVP^X;DlUGyIbAvFqCzZ2EJN{xRfEGz9CLeR<-kY^5H+H69 zP41-zG%lAlnqQ3h@ls$oMxC;-Qbd^l#M0f)MOs=V9L3eV`;E_n{p$Ml_pycB#79E| zc*`yHq&KD{4s*)O?3I>h~t(VjVLv)L}|+t-Gi;*r_VWfS71Jj86suUEN{<0JM+ zIP9e31FK^o$aNP*8;MAI_2Or(fu^<-{+n@-qG!}2zpifA#aA?0M|*kH257eGQw4Pp zt|4K|M*5}mXWCuZeY2T(sGNy&&gkA->t+oXFe6!bEw%5^#U?$J>PIsN3N`ooP2l7> z7bbJfKCcvs&`6RBwL|8XwpTZDik^@&`}Gi9Nmh*wHN^_fuD135cq`2CIKE40gv+aI zyYe!kOkO2CJNLV-oal_R^IjliJc{GFbc&)fR~7Kk;2~$qX01E_YJ} zmXi23%fTyVL#-n1j6_NvZgtkwY|l{{K@C%@-WqQkJ3{I2e;PL`KRL4X00ZD4sN(6P zJTd%=X~Zk9sRXCeTXX7{LuzX45bX@zTm_8>Tv*Jx_J0hQ^y7Oog zf7&dmdFzi@v@I0{i7!GNpqjWq#;Cb)A@R1x}(2d|eGudER!=fo!P1DeQ5yaM2F+Nmy>`pjNq_c*6Q9`*Z zpmgXU%eJ_vpKGKl$%NSHWF>dmM}`oN(z^~=9A7i%UQZ#2f@O}&+x?Z%c?R~ImOsDFT>Fj-DRle``|jJ+Cqs3^ zg`q=7=!Q@XA6uNM?wR?^4CgBJyD=7zQmBGPo3Q;*K}Dypo@Z-VtHRdlA&YldJ$ODH zedY&@+1sv3CyQDD{nn6154XZc(H#-L6UXzSl(NZt*`l7=C44j+l^Sfysk4?e<=@Ax z`3ScHz2CiGsM@VStH+tIx{lD3xd%(sG&NbwySk3Piw*y^6*s^7UNdkopSokieCk`8 z-}I-xp;*cCc9l+vGrYl)6QSoDS$%i77QRAz`zq`r>b-sGER6)3-Vzd|9UD9PZp`WX z_qTEKY)%0aZ`HkV*+@xnB+apitu%Bl4Ru1^%uv{dFE)oX5NFr4jXQipyLs+$?(UN&BE-KYAfE|X!1<{y9 z-MW=W%x%G)ywW8>#cqS;dJd?e;e-d0t`D`!8s-#?NX*%Fl>p8qKVC3C%s--z=|kZx{Zi zsYALtvYiHs$s?ZNg240JkP*sh%si$2TqcwbwrqAy;&khDDH4m*E0BA>uS@zmqgW+g z{mH;#@bFSsK?q;B=(LY6H}`IMs18Q?0>grsWx9zGV`(|8jm)Yt-yp{5I_(g>`Br`r zk;6|ILv5tj^oCpAzT!C|iGBpx_D3%m&v-+PhuFu+dCc+o(4!So%f2r>KWR+7W?FBB zr_~wMCU`=hHLL76(C4#yRKuwQ&S1(Uf0UE*mil39e6EgI z)b+k->TFWjXh-}SWL=i7frXv61@gH>+^M(*NmI9{QzruhSt8-`7_Lc0KZtj$7`Ep= zwe8EZ8BJ`=5xYP-Ws(Z~x)vPYYm{;Z=AO`k)wEB~v#=o26h(i!4 ziKm0@zJAX)(j1v>Ps6b&#harRJ<3ld?45*483pfh+_o`;cCeD!`SHxj6bsF?+bTMG zn!<9EX*Pfy7odtixgxw+sd&qHZ_qOq8^E-5$~dqYd|7lm#%P{+9uc=zPd-{2d@ ze9BQdwrzj)g8G=+B&Lbb^xemcR~LIzpAeWGjE%l)T(e6PgJZNknKgJWA`tF?UB{Xl zL{V>>?1v$Sp5t+-l{7$6)5#5@cL#`HRFpj2FeP<@1&>6uM5J{C_2U8mpra*qj`JqL z^X0Z!(Gk!PE-=RhpD->qSq85x@{N?Ts2byM9Wh@EkW0X!PeXBC8fXbz!2Y*(nUBbkXvCQPwZ!Un^U!M%*KNpP-Ef28e(>kC+8RO_s!4nyYp zW9btARg2%2qn2t$avCGox|00MJv1_HXJQO-VNJD!0-df_LW)EVcdgET|qRHCX)~qOJEnxX<{fZJ^ZJ!r_ef-wI!bG};YSmGvct zO1Cs>#*jg@wV;xb9%Vl1R=7~^Y)&oY!!n9KS8F`r>w;SJu%7P4bgxhcX`J5&HQ0?<_==uj}Gn#D}>f7(&%k{!=q_r>yxwZ(FI77r$NOOjt)>cwcn8To) zWCUcF$iHsga;2Cp?$oQir?H%elk z!s5{_uu)RE{W4r+zq0$t!9>wnSbNLq;KPmoRt0MpR`2hb;nlR1ifL(Izf$ZJ?~vGZ z8-mQ^yM8yN!{fL;KGw`1iKa)fV?z?~?6+3RGl*6OsMBxwIO(w_lr0L83P)z$wolP? zcS)QC$+sBXDHo4+ILZ{rw7+nRH4|z(O)#0T4V>h}{i^l$9V5QYIR@yDn)Ncg?po>( z%yTm}vt`Oiez_5tx>q;-wBSWu0rz*kCT7w{MBCwwq@rKr?#73Td$@+g9LUMgvwo74+U zNxqh}{EyY+c75X(EBYj%cj8VSCM^S8S$7(JK8gao&AO`l>H)9)ryO9Q)A-iIbDcpR zf)|WA`O`{GRuf-XDY*_p_YLX&yLbTCHGJB|T(Pk(bwk$hv;C;Canw2Be zKj^R4oO)f08WTlP>TrbJd(zwf0|ZTmuxJl<-@$DFq@V!de*kc;8MUj1N(t<@;RfSk z^d;VcBjZa;GJ&i4?z8Krg|S(CFqkd5fYfbdyngf9bb(&}!^fOrx;lyq*)#R2s%(=ICjnG?r4shkP0rkX?RI?ru|Z1AVL zEGEtV_I5R+G#H=2o!m973rX_I$!lT76^SdOQ9nWxbRgWl}hNSgShPD>;o{0CnCuzXsL>m7Zz@H1-jheaFao=a@y zdyf@Qb3#fN{mp_58akp&lI&go;|_Z;wW&>n`8U4)Yrsn@Q!8e8CzFnA{Gk*@U6mCi zs64@vB8-!Omr(FiEl064b)OYfxFSY;bW+mW_;QmJ!XO{shm%0*c?Bq!hUXfBNpRU= z&?@&Py0`PhOE<=&2bpzG4y#Z@n!MF7Cu0rMa_<;}o`v_BgU@%Giq)VG?FYX4<9+tC zR|YMHG}nf=1+9T+WqT}pm4Up2K-nohj)v&e8fcAM=cp*o{m|04YK+f^9B%$7m!p6x zr%Qt3sOZFizv?duf@+0-r^8?q)l>bP=`Wi$Hx6t6T5Rh7>b%hzO<^o3;KvNAAOS5 zznz=`Ojv70zkX{@Nc~J(jlncU;?G1{cljZlSKvX+$Kt(8p3$jqbcXgbOz3jC6%_IM zPr9B~&x$=gp7m~n0xe4|3Pz3Rg1-Xv1-y;F$t#u(YRO$$+};_6LumVrfllVuRl8NT zStL2l4ag?aXO%vaxr^8d;6glIC8V$s(E7^XqWr(yn*a}J5bwJUqmGC}S>pUx2JN$7 zh_}nWtKqM$CCf{SyM!c^+GO-B3@eSyj@VS-4R`$NPy7UdI0T)=>_!PE$UoE@rS8o8 zO9Qb(+xez3zHpX0P|KLMj3lc`uv?R_&G`6uIyZ7`frDaevst8S8r{y@V{Gn-G(ct< zG7zQ?tbAzL6PuUkptd`K$(r=>lUEjIrk!PVo}B1TClAE;jF^`=F-l(`}hgOG!Uk?T4RCCXHQC6 z0zEie5Di*;FDCYc`^>8b_XC*soX|B-!8E9H-EvQhoR(#$8 z&?0!tqv`-{`wy^8{=rOa#fLjwe#x8>aVjL$Z`C;NQa0A=F+pY? zGr15)UXYJ|iEders@!@IyJwef{odv)onm4J-D9Bi;Y5*-GE+~D4;Qs_Da7TReMpUe z<$|=}q~Y5^1}-Ow-ryU+HI1cFCXW8kSXUclHiaqpY;t}Cda8}Ot|>Y}i@;3NYy`Ib zs*HYyzVNJ1D_~KN-DZixS^$ji(p3H2Vv&e%>O~{U$UZQzo`C5qRf%12PSVWCNojnu zMF3>YZ|;AN+!(rzZd!U#@jzYI&5>y;(q{K1T9U^$9jPtL@SxM4j8_WHk$TLK7sswl z^>iBmQn7yyYco>{U+)&cO73J0lHzCWxWc;agQe@rQd?aTM`my+>NqYFt9bXI&|x$n0^QdsOU(xAAPgr%c>(@ zHORxwy}q!=)bhy=E!N;E#uNmbo6;wTaEgrr+V~kUrL`@5=XGQ3B9NR-JHQaXpxCGP zSk91-e8DF0ki``=siO66q<;Xfh*x{n!c%#A+A0fNYrn**BVmbUX+89&u6QwDTl?vA zieXXalYU5Yd5`6G>j$WQf*e`AgOn*#oRb32(IuCO)cA_E)wxLR&?vSRmdE2M-6Sn8 ztFbk7=DAv>qNn$q9Vzt4wb&PvG`YMkkoHNWuwifVA%rO_hy)h1ZSYd$#W1C0H&}#0$j1=n9Nk+#%8$e*Th%!Vzd1(&`;p?CRY~nEX&X>fQE-z0$LGuEMwcWb;X@ z4A*$(=HK*mJ@M%@(6F~;BgB|dmux0b8maMPh9G@xOS1t#)6nxC`b9=ONjzMGw&GIx ziy<{M;n3}So7Kr)woq~7=kE55N$uQzGCgT+3+JMPSx&fw6+&p25!tuUN5o`p494b= z{Qjh02O?kEbc?Zbz?r}?GBh}45kTGE>W;YIB=lGU`*(9 z;VUF^wgT6Zs#t3H2WZ^>agz9#L;(J?hYYIPd;Ky)lVji5Q?lZl>PtHm^UT<=n9M>D zMR(;dn2c1}7h5kuucg$--O|aS5^;Zy`AJ!s2d&Z+9Nwji{{uAXA1V2{x;3`hWGQ3P zpD%?4{-#8BtyEB6OnhLI(*b6Yt{TUE^ZuTMoQ=i;&mJaG%%J0fzFIx3fqkP-F_<%` zz}%?AtV3~3wL?4uQ%MHM_evICugBjdYr~h@t|tT2NI|*T4K(zWmWQ_8wxAF~Nk>#( zyIOe%E~Vq#tw9nG)t@xT8=oRFJ93Pybr2ql$GnmBeNU&ejX=^hwaU~hBAO2K(CdRTS8856 zSkSUo=>%rHs>cg<3s+AKS|o8!Rpy5k!=H% znTtgIMF+>4hxUioH~e4T{u*_y&k2K${aJkbEbCzRk{WSmQb^QMNGxOK8nXrOSd!x` zPnwFO1kQ?E?7=+lPjC1j;C(U(nmok1S*v)UE~ZR)Ff=Rsous21_MkqgiWr;;d`p*Q z>Tr!eY9Gs)xD4P+kSW7H4?!}43GDB{G8T4H<`XUirJP` z3oSLdvaAl5zZ(oZe13P-FtIlHTEAt4=dgibnnRFJ2NO` zLFyhunveA%O$&77eSX6EqW{^uGHCygHBBg;cPC4$69mACxnBompZ7$fg@*6d@lB(i z{p?@8Ay(>NcPeeO4*n^+OYLHP+0AtYoFr$(>EbsWhplXs``64`Bd%1Im;1Z2?vd@e zF|;hBayuZZ6JECm@kM(QhRYBCZM^0Dg`kLG=j{r^2Vmy#QSKBS}^d_isP z5=Uj#Ps_jE7-*B@!RS_xum1t6j^V^HB&vtt6}q}WV+Vep2s05ee#rzsJgxK>rTwgF znXs~Amor9OV^3N<#4z0F@{TVD`4sB3MQfL&3{BEv8H9X5H?=6Ds8IEnE<&*`>1 zd2*SY;-}C6BsSb)M=ySJJ#|lhUXv3Um9B^zng*=ncHM$fuT)I=96-*I;xa>`Kag~5 zwWCb*p#N^F@}ejbCu33>tA+BGPi%ecl%3h#-nk!06}vAC!Lcu^!&It<-y&ER6^fg`)U zkUVLRd6RE=(lqtycK2LRxrHaY5v{s-XfQ70&*qtup=S-XEqJ+i)vy-tYZTGgD3yrO zY^xFK=b&A9!fmz~87WR3cUTJheNQ;u5y_TDY)Oz=rJ(IFySe>YWVl?(Oe%bX)YODe z@6aCFze2#K3OaTcg0fu!Q~4p@^B!5)Q7e~O0~DPqI1$IZ?e@0d(ZgSerwpHYFvB7G zN>FUAK9E)BeD%Nm%qvxvfeiDfQz3rgD)yA1Sv-u?y=B3?wo4o6&6^!6I-<{))PnoE z$E{0&6DQ3`C;IO~kr%(J7@me#71=WR-p)MlnRYGqcFSX~ZT1+kf|7FeuZ!5C`8t$W zLW^!ikRpsVl)t|kkvWyyuQ4CyoW1>3w9f7Fa=n`JYw9E%MH+{-HWlO99QLe(MSh^`25jKnX!5X$vA`yMY9tQp`b*|>MY0WIM&#$r zHhKD6pN6oN)*Day#J{&XWUdBEQoUQP`{iQv-z9-#Dl-s zvsb{^y5;yCM4d+x3;M2Adc9z%A8nd&D+UFgWoCU~^CyK&X!Nv63Gg#U%!uZt!fXL# zjMuKWU1#zUro2m`54*j~01sYKvcq#8WzuZ~=F=<%Zmk%}vgzffZo1h#VDrLQCvt+L z?%ZcJRMtKqGPT8JJEp6+6j~bKvF9cI4PL4VT~=QTy%qyYO;QuWcD0p?p$7!_9N|VE zXI4*+)Xi4BrT9J+_2v93{o>|E-~uUS`}t@yE+0@k3+n(KsU8&BA(O;$G>@n=%|aLm zOVSX-RFzvngthzI4Q9dMg1AOe)hR^ z^oNgLBNwCEGMa-elfbn*%B=SXo_%qj0NuOx$vFkAOzrD;r&*`Xrui~2TQA>O3mUX* zTx+{bJ>yuAdfphz{d+<9z0m9L*fVSP?qi|`$|^S-LQoM=q)i(aMY)iTY!-7TG+(bENx214#~E(sAhW!IFbmS+{ORfc(TeE7Y? z_q1As>-DrnWb}$&w2Ptyp~8)K1YTkfhW`L~<<+Hq>=lujWdY>?3gxik508H*g^+|x zf`^PVKu^y7-v5{^dQVnWPvu@3iEIF#L-PBt&dd^hRCqG`_dx{Z*>;iK=9mQd$ zXDk0zQ(l^Y4p}7v1-Bo^hEUJU9q@=xR_!5NMpT+Jj;$nqofTm`Wts2ucCs8$(glGM zatm1hrCNeymEVvh;I_N_WX12C33t2MW#R=axc*{)l+j@NM>K;@V&Vv$ZOFB|pU;n# z2?yGmz00;{B|0!mpUQKfwoE+xD5aMjGjO=`ahk4eB{ZLopASm@Cwj#|<^`kHT1Lq= zM*1gtkQ=X&lMhQBQ|l^9`}0&3hl%&(?Wj8*(N_k-_`*JJ zWUPkL6eP7f+IqUTcUUNe>GT_xB$*al^&a52xfnVdVz)HpN%NM^(@<5+Nh|ELiAIOx z{4#N0P?79Jk6DNLT$bNQ^Hg+0_qglI!0Z+)Uhp@>Zk;#c%qN1^PgBvg%GUK|l;Pcn zA3qEvC9?Jr0{vXnS0tZ&Uc|GWdWm3sfW2zADUnyA2kBI}kL_T^u(qh3prczgEJhzd z*r7Tiqe{S)r1xRmUW|Ipp@7_5ceYvgip@RS{f76Zw4Bqw@$&BmGbg^s6^|-#5}Q{5c|Yb}4!TCin{L!lKM3P$U(F{tu~D?KxB{lu-z@pX-&3Lq0`) zBI#b*Nl%kvTu^r?|BGS#;`!eeV9`9x0DOYO>sL=ph`Zqfw=&-tr5&x?W?mRYpTA5a z7-fhoz6di?p3wXUATFCg9f_9I03vu?*XCZaPw&ipS-J5td$bKC3Inq^F;beX&cr32 z0@`boGv{05N^O-fy z$>X)o@f%TvH7>kEMtHcp!t-tFU!}HPB)0$_4|8=T4m?x#5`%lu62Ryvyy(oB0qwVQ_IL{Z_&`~GbyU&t_cXg zLhWvCknlBTZpc_@Y~_(LuQX!%&$0BmPZ_^qtN;@`{@_FjX`R#w;-x-1wnU(J)>#RD zx9Z%|5>nDEhi-k-H%iqt$1XPKWhjFi>;X)RNT!CRJ_~GWE|l{AP04Sj2bWT#;cw}( zss0DxOog{>(1WD4juzB1CxX{(g#Dth_1?8DVnVJTOK}N@CK~FM)*gR81R;zf0-f=s z)3_{OxznCMmOS-=U2WJ~vnOVUP3Prt=QDJ}GrF!Hw>Axnd%7LJNrW|eNPeUCQY?HR z0=Vu>I3~g=`xZJxt=?w1`lJs|foEGhV&DSOW_ejIm0IjnVhy%l?R`7JY1}dEj%Q2$ zj0+l*K@+Ygqu%@>7GCf|96nHy zv}0_L?^++;A>u0ZH3de6J{#9$eE-%upQbp_-V1%bn`jav2e&Zc)((5No^wq$%QA3RMuq83L zjq~lWQV@T2c0N<3Z}!qV4IzjlQHYNaGi)!^hxBDJ@4b09gep(LV=;GR{g?gUL9!|<;qYp;VAIcsj@AH|x#4j<{_ksjeaFC(j~4iWr4H!3aOGNXNBysl zQX6;UVOA;z$j`}d{Mh~AjMun^*|>q7hx!V>6og!Q;@(!+0ENoiXH@k?F}Q4T#@QX) zFYEz%68`>}einMF@i`$>O^Lfdaw2nRsK@V)GhxO@n@%B&nl)+fhz=NEY!@HMB9N|@ z5awm!1ygRndZ4NgYYs~o85*RGIj2u&xT{A8jp{Ja;YE*v*Qz@ff8883>fH+Nd%wH~ z9`C*FT9<_9%QyCjWV-C6EzmS_P8IFl(Q<#)EN96CerSNYk##rJ_6}b9$A6Gbjjef+ zTg!}ki1(U^_>xZIpyPs)g?v*Lj`STaH$#pDXSCN@>%0;Z1!`` zSm4%}R4@too0>~XcRNc<3Zy}CwWFg>(y1tTzHG}d3iR83Yv;G#b3Ej%uve4yqIfPd zDz`&6^(8!t9(F!BZhX>$Gq;D1LJG#n&>+0ZHM_xRH-YBBwe^cug7CN36~7eyDj`pr zZQMSob*~&1*8k;AK+evG;@)!+iRuJ$VU&a;oehOE=^Tw=J=k@>_JfkFC&h__6J+$Q zwf0J8A`~S4xlW87k#*DzmVJA#MQ3eh9ZDhvSL$UTsQH1R$_`0dW>H|fOZNl)>3{i6emgbz>vGqAKeEdKXoiOACPTqi?t zyTSQbqPNAVvH4reUB$J58ZV-G?s4*~!&9;ri0xGBPlK+N|DhHAv^DSvK@$D3k0=g# z<25YD041L-(##(5&nJ|{6FLA?h$Uk0@f&{egB)*>P;tMQ5M}btP}M0V#U}k9!e#pj zk9q=l$=U+k2Jq~g3rd9qKP&)@6--%g+7|u+bW!=w-VRh5n>`H46iz|@a{HzM(Qr|f zrPi=%*X;(1JFWEv!6E!?{=GG#LGMq~2t~$}WSs6tWqbZn&o(iw5~s4*p;^PpZGxnCjqU$EdF71Tewc6J zT#Mu0JFR-N&m4TkAs!!~%fM#HD$o(|jim9!TmN2Fv>eQ$z}!{L^919uH&e#fDG=EZ zDJ5*z){|!h!nXVaz+SMPQiZkX%^qb0O@1p93Mz+O8KQ^hXpkii-RTDfiCIL?e+h*Q zge26|gnVpeT2tM-G|Y0C>wO%+G%SFk(@ewH6v}thFq`%cgq^y5wBdfbnF&}Cv-l_m zzU?HB?9eX`D>>jer;Ezu}+A@4Y#<4q_VsmPG_REauRF>^0nkdxM~JY}n_&7Guq3TFYjGJ*1A z`wch(q?F-feyvz1DV&VNqbC5zidhBf>_rh20G7^tXzc4uA^gqWq zt;n+kQ3)l?(l3?C-2TKEL?Fj3DIK$11`^pO8F$7efSps}$;-WCnX72H98OxH9ye`KIyi(ad&7+3f#g>@3)taJ;`gB$X0DYJ^Hj zO1BtDmvkc?j*S>y(mlFMxGSTVf!_asU&H5An2-{up z<7O0DQv2D}Jhej02R#l8mDB2!Ns7c%+YIhA}rV)LV#Ncg}) zyDZ9~%3v-15WH{;e-8JvYjAcm%wmEL<39q(oa-2(O9gz6WSQoH!s2GzKuk~X>M#Q` z5n=TjYAOQHoR|tJGQtsCa&54jo$5az#qp(E8OH>5TsP>@*Km48D;|`l))QU5qJFVe z62y9NS>>i9mavsP7VS~5Ce#a-Fu5#(4T9*GiHZNxaJ$P9i0KS*ec!Or{I$Au6*n$E z(4)QCc8S|>6F*;?RQ#F2(KO*(xvpVCnn8!J?qfm?l*NA*JVM zCBlLQ6)*0M&`V3fU+fZ<=O$XJmvX`>aEPY4m4lNMne}6rVgScCprPuZv6?Cn8x=cD z*k)fW+VcE{M$*E{*-B>WV)2LXiZP>_s+wPY?}CEsyhJBS%i2)?DzV0Kk%-Kj+byWf zH9gRiwtxQ6lUrKnr3nAvtqmPumhPR?4-9o-p=ZvtL?ZDau>sEy$$|>^We+LwJ+O8$ zW+>m+7HSK^kqoq+(V)2gULQS}orw@B5~@~0Ot8i$ZllCsxF%b)r_dOER^l7!u;dZe zOL{1BtlP8=x8H^>#X3PVF#z9zJn(oL{l(YP8h@1>rY<{%@dja+_94+3Yz6D6dn^9} zc{lX>u2~O}qpUJIHXCFcUtz3>;X%-#yYhwWLt`Au4wZ>v5=%%5oRw(*bzk0L7;?cmxo# z*2RNzO~*WipR_+2;OQ6(JYm?Q4u*%XsY5v{T3JDf!K1^Z@CLK6;xkXY-%L^#s${l! zh+Xl$KnJ?N&IiHKsWUS|q&@5IFU89u2^}&EMUx<6EU72(IVaX@eJ955c4l2kW`o|{ z=W;1Y1C6^Jsexi2$W)+=RKnpLQv-hS-9mMUn7^P;k`zp(D;=(dIXIuuFTc2 zRvGQRttEFU)?7spF;c5e|cs3+n;m@b@Xf=HZYntnGs~WnnzO2(u65K{)s6Z?nU3fgU!$ zA6vn>;{=-)E4T5bM;0nDEmbAjFxFUH`|;I>!wT7!7A@_A&Bz_!GBM}`(G?#jm}-H5XBAFUr10iGF-t@=^)<<0x@dJTkxB8H{ED{^UVG`%%ri?dtLaf zG7s!Su#=4&B#DlGeimD3`|skvuJyx1D{v*tuYvTAE{UmOjXX zq`5vR%Y?dgFrTo5RKq>aF%FI@knR9XC%kYhBXQ1hbpH z=Gg{O4utdXqi?39jsG@mt=a9j68HgpM^3dL$}2JL)f56}unU1DMdaXzmu`vZ@#v37 z?VTYOW8Xe5NUlr3e{E2>xHp#eKsuEMr;q2QkxODL-`q?@BL@xkgm~l93AM-E>X3Jz z-t7~OAmV{^lsF)yxo5}zeMFa@Zy6`4uL7osr+K4>KKDojwD=k)9@-Fal&)L(lLQt| zdfl48c!{rJwan9%54e-O;!4$z;n8TaAJ>1GGdx`54LKArdy3u54nY z@Jh16xuK!jQ}qk14(SfwLeMs$;4h|iDlDYPe+3{$?|)h;vr?9rAt z3`sz;wkw5i2vC-5eG8*^rIFY*-6uLk-1n+_0rrKT@#dJa zfSuLzn79TS(Y+K9yDru7p(T~HO~0hHbR7ShXR{MJH`2BoT2%e*I}><7LSoY|<)I3^ zJvEyU0#g|-$?K?;iwO$1lnGE67J{p^*6S6YtE2QfrYg(H|LpI-zHo(65uSGd(!1(& z$!XzzqxGkFRqh-WctJ-v+l$L$zaA1A`Zo{y?G}kwa^-t}W*WXF^>%^u!d{MfMWQi| zJYbY|DyCHtiZ_|evf58d1k4NRVo4FC+X$s@Y%~$ZW}lK9^Sn{ty+>gKCAsNO$5jXx zArLp+!)&9y%BqkkThosmR`6>BYgEFr$`kVV;IRx!%Pz~K)oX4(4rR_#7~I2o7r8Lf z5#7x9p!c}Rs>irTfqE5`k5Kl9yAeM8XrBV`+xS#XPS<+?T6ZRYMT()6F+jw|-fJHZGET;t`Qxgr!b ztQFmJR{($JZ}bMG##|PG-aPSaz2d?KqT7aiN{7TMuq~8(!wU)Dd85Iu(95|RYMEyX z$U<^bzHhp~73EEUy*uozrRJe`c>eSG51%oX2wNTdpb>ZPS>vRJT)I)#-NTy5 zB|F|3xu~&*+Bvn~(J4L7<(t(OQ<@Wo=N?1i-e%8U)Dv>8c(mwpH?MQi#tP|6G-r#- zi^p3-5gS)7q>$ola*=~JnF*a@sxi_bN?A2@Yu5U`c5~7ANiF_=0Dan}!KsY!?5mdk zd50WE1-6uaYxkw1xHQA;@WDON37W+vKh}+w)w}_%*B-$~!U7S?YLZKK{!{+^j|4|?z1#-(F*M%<_~>2f z`C2I&)}6UysvW(t(|q`F=Z=y80LrQXd_UexYn00Dei#d1Z${ygf8?#K(Prrl{=5+U z{@=3^tO?U^Lqaw8<=)!nnY|X|Muu>M03^Z~cSx-`Ls#265k^V*Lj_N2x} z>I5UXE{5*k?Hc$S6K3Ppf`{4G&eGAH7wYMT#5Hw_zeP=s^a#r@e!Vqhx)A-k<368Z zwIXiS(%6<1zMEG}>O|ZD))J+xOjlvt0~~*HxQXE#mzftEY2y1{V=16iLao5& zwDPDXH<7iUPUE+a@F$%?Eb8W%`yr*M!jREYkIP$7uk*6O+Tm_)Vf8VM5U5nf=4jx$(tMRfIKBsqY2dbY z;e+x)p4N99J%3|Ru&|7yh$6e|zN$Y9^>g~Lv^yN&C?Nb)!z+2SCS%t>yfR4&Vb5zD z;VQwylhUGsvj+6y;S(ZKTW&In+aF%JW;O~DqQ5c42o#eGx@oh$Y7{;!(D4i<0n*9F z56BG&q$j&{h-tFb2Lb=o4I|&Rni+ZGgL97S+D-vWputjDTI<$t1FLv-o~tFn64)`8IgKO8S>h*t*QP)SFLCQUm|p@sH{No5^t!yV z#Es&8EVw5swbKTCh5oRnTbNBMq=5_dfXC(LmItnkLE3%bbt48hdNqaB*0b=SgyA8< z*d=&5&GbF@PDb~hM511?tb__8d-CW!84IgEuFM=HdKuX1 z3<9snsBp()j#-9pXp~&tf1exvhW-ZtH4ObS>SB#`;hk*h?v?xpVyE4p=I_2CX#V60 z#A#V(rdLh<71W1S<773gUnKSlqwa8^y*)8sJuS)q%hG2zJnUybm$~Jp)$2}1?SN;m zHtRVReKWwL`{x)>1a1}Ae0yp9CIC#$dh>xIcN{sy{JE8QfvV^qV-*t%ld4upQ0Gp7 zF&1Q#{*-XXN1)(6{N^_ol48~}k*?mu6#~{!d6F;wL5lRXgE{pimiO_Gpsp<|fWe)N zmD%OlyoKwR&cS6$BZ4K^zcACrG=~Y9yoxbWUns!I^5k*e$Tp+Qsx&Ir=EUPligzl% z98G5kLH`F3%?C*S^`Sh1=1;eiZ8RXc)_~O5gQ_JAR%|Q6GQzZXOKcUlfB3e7 zP29MywZ5={uu2V%_ z!Q#oN37Osdf3h}KVLYr+d}r98${^o^bvGnS16`~b+2Ru(w}Y0M z!QaNIyPc#@vW66`gE^#-l7!M`V~@t$bVQ%W@N@U|7Ctni|veO%a7K&NUZ~#5e zBw)$48lLx+cF7tKHX2cQ@H<@6k55dA1$%^gp>}4ecg?>{7b;A>bDHa>314CazUHHo z*F-GeXN!#PwRWZmPsVo=j(uvBe0v5E6hI??g;%j`#9WI$QU&A61p?fNafciA<~vGh zLmX+Tk)!65!sM=tdg}cW_1WpI<}#_ZJ}LbjP8UiFr$KkKVq|w(d(#pP-&eDtnv5r` zMpaA6iJd{KBc6^=kJekB{`S-yVhGmP)ew5hCv^Z?berXUFCtbWD@1%D(6YOxi_YrM zzc2bp9sn>J5Ll6mV!^^O>W8PxOQ`MOWP+dbiUd~~<1A1XQL zu_ZfDI)#&eIHJX1N#*PAeOHQrKlO@(8WM4Wt`YVn)DMM-g%w7uImfN%u=`{kR?) zyCbqJi9AJ;urq2I-ktL$D5xVF{DG?fcZOoz54{AOsx5QA1yjJi+t;m4dJ_*TH7c#n z!7QGKK*dFGL;K?5=-0ezHacH}EGt*s(?J^2~8#+=^xlL$!Fl|~!Lt=h(ET_`@j*%NbO>w4Bb@O(Go z$eC!8nT<>GFgo}j=JVDoQi$FmV5jUIzJvuzHCGjtLm47tz9-VMn~*Eg9C?A5{6!I| zdo>gE!!tYf?t~?Dhesk~z<}{samvzn?bWbt+%kZE?et~p zm*`jfTcy#WFHBQokt0#}%KIA|PfNnbdkdmn%B(G&?WHjHOZK@s_bN>ij;5ghl_?o( zE^RB3_vL=ts)CYtQKK^SYpYp|U;e?)#hE#KD(&k@f~P&+4WGD6ipRt5_`OjG2@GRsn9Y)uy?B^Nz)p4<2hDFhjB{ib`=1SQ+f@a;Q3>~E zIpKR}{uFtQsHsIa3kk2J;2~i+O=P4qZ_h8MWHf_{Z8*RxHTv?$&pqC-Z$fxkn+&WY z>x^zr^M1>`=PCLH=qd{Th#4%&g|j||@)P=7&abX2t2Kt(V%y>PdzA=BdG#Y}*pfFv zuJCW;>UW_Xx-lYbYJ46o6BAMfwAf}eD~zCd#fksl^Nmv7)dt3^0eS3_^WFnPdqc&4 z0BiP*W}?GIQ*P@tJ7Rkv$oElsWvn|#Ni(P~W@-bWB!823L*T#&hT5#XHJ!2ScHk_& zV{3F48E;+DRkTi6wp>6ZXLlN73+J~)`t?TG1*(kA3CursWPPWCJaErm92^L^@EO`y z8e++;Oet_V_nLzz2nbCLaCZ|Ex<|et-G_dCq;WEgQDL=76}b#NF|kVL1O4L%{&T0M znd+TK^&cpqTQ4aB^l*%HOtOAV1`7O$Sr9eJ|8CC9th{1jLNcSlE2mn6_UN?@ZlrjDY-qk;>1!&)>6`0}7QMVm z(ysHg^3BFFop@~5DfJmx?YSjSe?CyFc`zMsT3~~|@v_v`G0rTl5^6$fERF!3KmYX34?YEo~PlMPPK3vs(PG9L4q zH!mm1iijsjdNvuk$Ua21U{8aZ*?d{bDK;#vh%;>a+-ZBjh4{(vaH%UQbpa73Dq^%} zpsNlZ8~6U|aIhxS<7>aT={P@xCA;8)Ix{G(n-PG9l1T&H9pd;;qg^<&SI3_|f>8K* z*}$5T+y>D?{@nz~LgEjBG2OQJk(r8Q0)TgG3C37mnJ>KzOaa$m@M`DQcA4h;X|CIW z=P50sK2@~;Q!O6S(K9gs^0e>JL@5N&Y z(UJmU#*(TwQy+wpl)FGljze-?K2=M}QUgof*t+Jm97PW7|3pSFLA(x`4s5y))89bg z*nKe)p1&p>K9qc8<7C-;XzW791@y;QLqFcUjC0g}>Fw5SJKBG^$(-SUM$96j2*&Bp`z^`IYY3W!pJ zPyQ?n6WE|1K7P{LbEXuVJWTpe8N+@$wp~Ld3jYJVPwVEB?y=1H53mHiW;N`aZWfqc zKmm-gD7_hpKrU4QRfsQUb}SQMN8Pc!)5mOGPCuQf9s}jhB7f;Or0IyC_t1>S?q-Az-;}kf~b& z7ZjgUi4dZ>MN1ryBze4dY?2FFl82l>8z0K8TC-R~{ZfgkF8$tL0k0g~4+}&+QaC>w zc?kqcZHNuuy8RLYVL6Y>p#D`myu*HOic7$flc&5aACIs&;Iv#2%k1_EC!&9HhEgrW zLwe5NjD1c5Er-~dQ_L)Z#Y!xIBdIY9y01&?Yp#O=u5Y-m_Tj3Hr`F>Zu<-7Uu4Zj( zC+o#sK!o6_Lq~7*L|KX&t^cuc%Hr}6GjZgr2VQ$7F2MY+3`hhzUQeje`=#hjg%EE# zzalh&YHxWTdm!WTaBTeii~WmC&B6J=RFx!`5yjxdS{_lCVPdFp(g>BF1<rWF`Hm2O9Vlxk!`6wR#rT&%;MFO&S&St$-)mpEn4hgtNP_lOY^j3QCIMMOLxJ1?kpZjF>3+lSqnLk&S`+1uSB1NCUKiua`1luS;r1Gtt zTH<14DM>eC{FB}#LqaXwuI*zM0E&8i!>=Ql&wOCtIOY0u(FI7a!Ar*^8U;vDGCUw!U}oHyGg+mDxw|x&{p<bhFFk)(aiBNA&8h6Z{?DS}7P$Rodfq?Hwv${2I7_0jvILQ>rF;AEoQLcpK`BrmtGIB`HuhR9f=;%Iy{zb4bG+xq{?5Z5g*9^L%aTc4=Co?OU8&xg~Hw zD$V2Fq{&{EFZr(YKfv@IXwL9XKlx9G)W*O4VjSumbY(;W9n|>~-XCI9O_O1-T*w`$ zJwa!&*l|`ZwFV{qkNE7q^v_*K4Ev!PcFNTW{PKM8lSMtQZ@Frv^Shu?K3-efY*&Uf z``+*~6dJO+BiMkL;GFIr5QtB(jZBvlQg0t1B}WAYa2tlBXOqUlMxjb-RzS22%kfW- z)t!d298m^@NwBQn_%QLoBKC{SM)J%+X77K1;;8=d$8>``3D^4$&Y#Rq+|GMdl?i)H zl|p$>5`|>tPLUUbz<{crWJsYQJ^rlp-D-8(=dH@(SLuAQ?71dhhv2$MV$M2#Uu6a! z_7U?Dfiyj&$x-sA_ydC)LYVleMi=Iz^C+k{}1f;tb@C_w~qC{U+wE$Kfk6HH|&wC6>a53EvY(&AqXja zgWSV>upS4X&S568#Y&O;6|2-81d6gi%-~eMS+~A=>}{K^jIvC?!L!V`!_dpG*-6cO zqR$2d=ee$pR;8!*K9_Rl94E@Yg|fuv{c#0v3~8XoO$YJIi%#{0bMvODr#i+TYE^>I zNM*DS7<{}>?#d7NmcM0<;1cY)7E00}Yy*$#ut!76Ru^@s3wm~g(^K?)Y3u6_M})XR zwu$hCLEzZ{v|b;_)6mr1ln%(KFJshi>f01kI!!}Xj8A6kk<=LB=|~W*^RLH9BD;LM zSsVZYKc@3^oS+Z~XTU7XuE;LUCyLY=;E=Cr6W;T8(DwOmX+3f5p<^|E3%Yx|)ik~r z>{J5D?Zdt|X4TU9-7ZiTC~9_R?*h$DTPL;!W`izy+`Z1oEOjoP{`P2jahJmyXbq+B zmg-!+VR=h4cU_*E+D@ z#tJ{<_q#d?wXr`2@K8(zT)D5e7*j+zyP=6gtt7 zTOb>}=L$VG>@ndWi*U$Lz4*uVB|y?RnJ0qB5#o)Xvf+MC*kojw&FVC~e}N4YlXN?1 z`PIMGakwB?rfYm#elfiNlahqeBN<>7+q=H^4a}3<=8Z79Zrifw`~PP+sqa&&oh zARG%*Njkdk-bn{2Y zQEh(r{!UTw*Y2lI;W3)w7O^%$ugh^o#zsu7Dx?R34>+;?2yqKsZn^3Yc=+_$OKHAY zF{ZM(EOq1V*A3raTG?=iRy&TSedVDmXHnS)%pUxyup9?t+*oA&38Qz9>N&J@l^2B+ ztwxRhS=_W|gGKIIs=eQNvp^);_;iucT;9Egr7^<4d|!uee~@+NwYnRY3-6sz*lQ8P zVkHXiU-k>O*wSJga`v-6vNp!7X^GtOCGqHKN^45yWMoW=aI`I(jiJzQ_SAEdJ%Poe zV!X|2sGg!nP7?)wqnF1$6~^V{zf4B>kzq}U%2mbPru_NIHidsYdz7Q77~!{XB9Wzg zyiuc@e13X&4(HS@X_{0}pEg(OUmY8XXt(+MCA*<(Tg>^AUr{vegJ^7cryU>t3$evR z;rnNe>rT0GZV+cO7yPmVqXo;x+2foh+^p00MaBgjU?+Hu`eX32ISQRl?id$}gnKB6 zXJeBKq_5V%{v#5pxo08V7jl($cFSMX;dC0Px6idieGILkxyLAi5DNs>Qb1TqI`D8$ zO68abx#*uOf1Mi>`2lYevC^OO(?i@o!!owLucZ;j@XpumhOYo4llFqUbt#+67>OL`}9wSH_ZoGO8M)7#9Cpwj#X&5`5;;U_4uWIlQ=N zwq;I55XEq#!W)uXWPBS^mX#6eO_vzHd&Yk1seS!cUAvOp9fU2h57EBYSzF5rJ((RE z+x$8Bm+QSWySMBQ!c0XZn7=%t($*trg70#_shj-VK_%i!@ny&U~VFUY;m}(aQ!+*Hm|G7rPHWuXzlaEKGIXI9W66C@ zJ&ZpgGI;|2bWX7TFpo>72iMWG}OK04$m=V2uNQ{4pjPF&SxC!cAD@wn|&tV^(_e zW+mhQw#q1xRVbOEVg=T&42dyjFAl%GVA_F0fJRHgfzr6Q{{ttKl3ADLAQZjYH`X>= zUg)TqOdGG+(K9e+2gw?0{=i1SqV+iOWPLGRa$dna`3p{(9`*uO(&t#*n-A_`^bB#F z0Au`+hxON9CE5n}Ue<~6$h^Vo<^TD-Ca=gFJaJOsm=q&ghuC+x z^{F&00_*%H${L8G=Q5a~tSvxKEq_y2c4S~S)VG~UWEo-=NppGSR4#hs&$X<#z%^{~ zy55UsMzgY&rKo{;Xei$Sya1Bxq7Bnld2NGL!|uU&C!sA%diNZC`N8M9GuMCfZ0nZL zZ8?ghHZ-S@3WwKw;A7cI1Ji^HRv zw^3#BqRvCmH8Y#y)$0$LpQ`*RUd>1~j;{Vb9t7OJP?$Q`7CFwHjv?tJf>wdp5^qjv zJ3Df!|Ho04+FpKKV8*D#DCs=M4s>;9;`d2y(u{C6Hfi&$iylz!`($%L;3Tns48(}m zwxlfT`;DRfSkkjYZS61Mnf^IiLx6mFw)9nLDX5qcyfZ*qVjSPmW*WfJht-XwsyxG*H&>9i5TrkNr60!lf z?H0{iSke)*z`^nzvyRTpGL^TSg@I3An~QZ=Zn>5zqQ6APN)nDvVk+2S!DnvqfYzI$ zZ*VKB1ck4RR1M*c`%LQ^xt)fB{RDARQEsMvz1+OZe?P6#w@y!yvrrVo>LPvmIYsE&ziM?b zhsnrM$zk|I$M6@m>Zp95uE>9+c|TA_^U@-{^`|t_+s%LV?Ca_BQwXm^as4Gg?%=2F zPk$1n=*at^XNcD};aPdj4WMmMi3Q^Vsj-vm=&|z0r_n@f+1g%BGLmoeen}1ajuykD z5RByLk5%S=GemT>LI$g%O?&DgBU&}l9L@G6!|v1;?WtD2d*luj^(Ae&DT(7feFioO z)Z2-pb-b;CtZRFEr=e+6@8b#Ix$OSk$`Gqf)N+XRueVN3q8x%du=+ijyYH=|j;!o8 zXOvZRkO2uJb!+I;rIV|oSoY_H!5zW^O3E7|pdE)iA&3Up?GYwd(!ni<}6I}kmRJt%`swdh-W#DT0o;8TBR;0cei{K<`oFsDOuj?p&NM0ulDo*@Q6FPVxCP6nM$f}LY!vq1DgUNo zs@asAkvNy3$kO2B;(n8k@az@U%b-y@gv80KOHzmXC-d{v+cr^T4NAX^dE=fF#d!^# zi8+68h2d;CD#ZkKe>=8=0yi9<04VqajuzsrcFD!LDa!wUnj6%gE zmk#53q#Iz3Kb`8ys7O0OEWT;&(J=u}Jj|auK}rw zUB?W|*^$Z zDHK_D78w2?VD59&e9~w4=^+gDgwV&+@O_`>R2tmM{re+k>tK-6EIdT@Cwu4k)Obu| zDUky4M!f;Z1)6>q{+8rkb|j4FT(k z+d8Kt5tyIIog(OD-vZu@pQyCWa=*WZOZCo7r1Q1jtPEqo>Xj!UBXE!$d7kYxqIuf`EgoWRP9}rayJ*| zMm!h?8a9jNn;W@Mu7n0?S!Ex$2~%z$mbB3ET>|1Nc9a>O?&@gydWPjB*470ka`uej3Hq)A#fkTORrSmInJn9j%< z3b03vSe4nAo?~DhkQJ@zi&N{vTCgIhjSpQEC7cebWwRS@szXVqJaTK!nBvXlG(exl zRgS3@!7z$*P>tF#XZ7ZmMoTGP7x=ar5tU;eZQKa>k+P}a1fE=H-7xkID3_E&0yB_7OFkI})7X4fs{Z+@C%>i;m z4zeUxuWWi<=R6EqiAI-IhH~&xw+s%E>#87|vgEou*DIIQs%uzZ)-v;+8(Ae=$v=FR zQzQ(qlhi()`#iVuBC%pC^%#A5&)|Y%wBwujkF|0O5iB z63_5NEljGMdKx&jBX!8%HGC8^V1CWl(WMx#h0mvRh6MS5q4UxR$uHl9GVah~0)wt6Bb@cH_`OVJ&NXyuM?I5oy;J zZGrx$0p=Y={{hst(&ugBKO8V+4^(bBymq|e3%ZuT9Q_2k8#;i-*gjYoFf7XBH)e{E{6qQABkw%}wp?s_rmIi8g5cm zDyeLOqUxOuXvfDnTDB9W3A?_1Hcp(%#RQa8XC)5g9~!i4eH?3i$>4so<7Jrx zO@Z5D*f_aw+|5Q6#s1Xd3o;9-filas^vpTmR!h-4d%BxY7dN}511q+NG9)p(V+u$%H^Vz5o>?wG-*Gmh@~s2`P$0VWKlfU$^wv>){1PO!Ij=cC_AF%5O! zZ*{1?#SV}%@aU6%UHHV4a)$ELXw~@KywU!@RKAC($7Y&3X4!vExV%XlCJS*7`kP&m zDQtby=*3~jeP9jRB=KYc`*7LB>U0M()I#U%=YC)N^HK zD!*p_4vhWfY#sZXF24HNo0P9Qas9KOS{nPH$sWaRpOs(dQZZ&l4=rAoH>@KqtGpKg ze1Jdb`Jq(++q{>&j+Y*D0&DVw0K%}@J8Ra!l{5EnuL%*fP@s#)MsUyAN8eE=3v5hk z$`D365Hf$sFx(?kYj5K1zq?p3%MzNHHg+@kH^F`A)@1IiBFo$=&9fErN&-Xj@H60G zSs_V42mt!T+K)f>s9-8)pklDM6x`V=zj{r&=yli(=CNNgkuo2x>Fr9U@ ze4ofqIw&|dAG6i-x#)OxPRjAS%j4%N8Mu=JD^#L-vPE8WDQfjTc~^OWfX|ZGchl;W zl|VjepjB)`qDR|mr!<;pDogL@FF}*hH=FmABP*BHb(&-9gIrjn&U1T%$p!JmRz#kx z=`4uROLR~`jJ6au#(@l~7vAg8YYcIE4nEzkmqepi_Z_xk#RYcKM)Bj)esP}`s2;GT z>8INYN_(~(RTxT{^kq@6+{qgg$G?PRUWjJ1naKPSPX25i`AcdpRwrT!>B=!*& zQ((47qVLh^Wk)pHD(;~S98#aD@+MAcWQ5D)fPt-k4io;fPt=%;N1w7X5KVUAOKX$)A2J`@7zkW`J0STl%QmU zj+KD={@P-==;zCHwc_pNU;bn9ud2kTHUrRK?|u3^*pbzsi<{7I!F(SGUB+DL8ooRb zrw`KQKT^Q|g(Z#+o3d{dy_(U^e?0i@d?O`kcTT_}?VoGHYmwMq#2QC{&;;kYphRhY z6SIAIF2>5#tSmqq-)KFK2XR1?0x45s&RTZ19IRsjEyoTtc(CsB@)V-iCnXP)>@wFd z2gw+>H~$>GTo$aa-F|XTb>ue0zQ}r`6e%`uc9eXpCy6y7Jwfz|=sVth=d{T9*iABO zTODuuady!GEq$_yJ~MPnN%~^ymA8@psq~&xcy6YTs_`V9RfBQEq8+hTE5b}{Mp0p0 z@gDl3Je)@++GI{YO>~b8C;!L^XA2(O64yd6DW8Rvn0rpgF#o;=Y7NRRc-^C70wWg~ zvUfN_PC`^f)P>wLvN zNirJ6+FNgEezI3o8O|bQEUo4Uw!oQ}P)|oMLiB1l57!;?3JVJsy{UyhcN2hoCE^8k zhO7!UHFUBUvM`xPd*+~$ER}29`!tlnVhqgZrwBnAbsi$8^DbvmN|wWte6_|zt;gq7 zI+edi!u{B7KsKb$G-g`kt4p*Gm-B9YUfmwx=$l7<(;_4Q*;3v!4h+NinMHThpMdh? z2y((A68Ts-v4`a2jecSzxP%o+_NJoxK}+?01zB$Azgk9ojb9RimIepJI7tE0yG_G? z1@)4!ei9fg$ICRHiRe6{D7s($8K&l*BfjuCK9dEWu?eQ4jsW#_MES?0I&Rbhz|8Xe|Hg^AenK& zw}>>7w?jJsum`^1M!9S(7q_g&T@)+!D_Kj*LuFa~QP!d?c?G6{AGyz84SQx(92*Od zdV#~*6MRyabSFDX3xOJn-NqU9zX@rG&yN2X`I&a7>972`w*Bc-26DRrB|(Z1Z; zl;#y_>`4Zl2Gj2C5oVQqv$FqM5DU zc*RU(Ep-&=qiZguF~g)nLq?!2#I_N2Q_VvqFDqhoA?Mk$&;(KTDVWil9h{H547`E+ z?mF>mBhqT1B>d@Z-{ceB!zI1heY2@Fe6#puKK` zM0^(6*|4E*D*a*P2KNmC&_NZQEJox|UG4NPGTbC0jsh&1tly+0BS$5{+s{_i3Hm#uBQL<3L3Dm&eQZ$ER!Z^81E5slXjA}Z`fEG29^O_#vi z^2IqBV9YF{U=eI8T{8_CFDO8e6I^>ZoNN6aX#AA8PA#4a)>c(N!Bxpvv*$Ny?#Fh= z#eQek)A{~PhPePO{_;z&FM)DFS#Ht7icMWI4Je~aDT3a7B)+|4v)4Fdt+yPU#Q`un z{-@l%kRBm_dVA2^E-ApfECqT)Fy6!BtJE42h?eoVOIuBkseD^>Tw%XL%KxE6RE^KG zeR<3wBqS1q7~qKOv%PYqojjsMvsmi<`5$0D{|8WPP*C3g`)P{*bXOHvf==k$y)6}s zvYd+KMzu;)k1X97d%%KTU6?XkrDBNRrlQ!WS$meX>xK#4dlZZf`l{q9h<^xeHazsUkUJ+%zx$t{brVa^RNB*%B zo^=8+gF}Qg+SrS)jele#@@8fT1k-}wVu;>ZQ@apgXl$1?+=pj;<{2qTG%ZtHgjiQvdA`1xBxnoZ=-PewLm^@DsgJ)n1?RfF-pbgiF@p1`<81BQr|nNcTvMkLPO{bPHa zv3)>l1(?y6Mpv6>iuspHmc*x4GxB#LO|aZ%+f8@+;Fo;*eP&kgBc{?}T==yGZstFu zyY1;2R1PDIf${%JWMmVW#DdGu9ZBiviSy|Fnp^TJ<0AJ(wCIiHaqzvu1aeU`=y)7Z5z7@03{DSAa)VTLonWrhQ>-YwXZVhzbvi(#qeLNrAc21Q|50w1O>Hp1 z+D?nL#i6*nI|R2T zot?dAXH5)O@nPAxweI{?pf!<0NmI}3)k=xC`+ZS0^igz}I zQT=_Z{UV2x6cyRwgh4zao;URaT_O!_=ycEf%7J+6a92#~FzEKr#s56e)jAEIdJJ$V zp-CCsR%AT0lDn(MnwZw5(JQr-135w8QX8!;yaRG$4!B@q=JKzuS zHH;j&Bk4b9%O;paNQ5PCm#wJmT1rBLu-KF~Bq6sjh9-I=YugcgST2_6+Z9oPSM^fN z1Ijn|tDsIY$a5_~vIiUP8shMdm2GvMDKV$qUEcoC`3gYX&nAB!-gVCYLl8Sdn%p}U zPkafrw%5dC{@pR*Ve7)h@oD@dmYiBysh0c~->8C$vQQ$vc27q$h~fR=jL$jI zj?+YQQVa(%80Iy4%)MhH!d@jq$<|I!^j&QZt*`4sJO@yhLi#f;K3_u_P00fzS5rC% z@SY1FWA`+1{@meD9IXd~P1aYdj?v|1T_MrbRYGQ=@GpsI>N}wkLPSc~KbDQ;j*RS+ zT@~cZ8oV3dBdyTk(AYFa=Eb$EX_oxS9u(RY>XkVM&TummL39=BkM7P&So)a(K0j z1Wn;r5e89|ARXyNgwAV_Q;ZjF;bb2s>Ca5z79=<4>{_e&6tcjXop#asE&B=JnMjW z5nNcLr|;FG0pxf}3f(zet$f4!;|p^4=Djq#N>B z|Iq}UWYE(SHZ>3}%4B3&A~Lw=$rcWzn#Q$R^%Z0cesDK8XTE>{uu3!yH)%c7YJTMuxq#W_}Q!gWf)|Uqgj`y{+izS5A z*BvRg`U6S>I}pR6v)d8Q-&<;bn)Sv;B+<)Q{HnB1o^ZJ-LgOS0!qon9Vhrf z%7~hFwY2_E0YW8aUZdxvIly#-b8QAYV5!pm(gJyGRAD({P$nU%GY@PR%5 zqC+l8Y8iLmwWyJ~S$!RrX+s5VS$Jae?l7aW0iWx_5mLJY$^5rRRFT z{gVy&7yT(62zq4z{6>e?*0jlgt=hqMW6$=d+{Ohv*`gR12NVy7L;)IXN1l!wH!U4W zpzmo*ENR>afu{TLMmjTBhw2$$f=TmaKAlkxjUfT`r5kK7-><@Lcb`#L9E#^iKQ#3k z-&gF}i?`Tt^5WP}KoFk4pP!aJd~(fw{YXWQ^q+-yB*c0boq?qH;PQF#8%|LA;=%%+ z8zxav-@zrZnV%eM_-72uB(f!L0gu1bP&LsbtW9TlYO(hpWg6(q-e_j~-uhDG9E}F~ zRY$|}(KD|A&*XfU(8+2dFQ4d-&iR8P_04+iE%p%o1Y{?Xp^bMo$KYSMLQzGg{tH*r zWCOuVZU!HGnKb97f72ltJ>kE>Ef+eYiNh;{Q+k@6Q?5)lUoo? zz`N%JXBLbUy^yz1JN{OdBj^m)QMuopt(=`HSBA$GzPpL`*1bbe$P|Rd5jnqoQ0V$G zpE7f32Og)=yj3tO^JjZvOts%@+%^jANU`R)+8>P}frxn#=l$w-v8_4Sxrt3TpbtV_ z+%e(YS1%PPzxkEPR{+H0KjLE<3m4kr!dE&LuO8)7_7HnktW^M=h3D49RgMcQve=l z%tLS*@p=4QUdz1Dx=NFmakBNy1@+1vb>Fh#fw50ND>D=8;)C{kH5((%+q*p^Rp|4+ zNyt)5#81LQ%W5rKL2J*b1+aOk-;@*pjQ)EZ^I7cU2j5gxN)*f(0Ps|jcLh{;t7{m$ zIxSoa_21t^SNr5P8)B5z5zgyLAME0CrV2Y~()qIG`04vUfTn+xmbT3@$%9Z!9lsDR z)1ID#KOyU*BI_^nlT06dbSc~VY}mSpbxKB|SR$|_KaV_4T%dJ`*>Eq7*AP)V;?Q!~ z87-=RSR9)K218C?Ui({;jeo4kMWi0dZ`|kl?##vhHv~ZnzfHKTwqzPbOtgf5`ta`= zPplTUuVhlDsppTP$Y8FXf{R~0c=f-NyIQ)O<46IQGj!7j!=K;-pN5H7T7NjX**EGP zl-OUt+wroPzBj1UqVCvDcq_ceTs?X+6y8O|H~v6fSzA7-uMcZpqXI>)U2lIouX6Bd5r9=s-0Qv`!%KTr z80eipKW_oUp&Sr&4|OI-+If9;$p#9DcGIC@*RVuFJ{4pj=BBf*;e`gnIEl{ba7zu? zclC+3p(k|_dW zTZPk+me9LN$&!Y0LzXXz@I~MCK#fpDUEcRqngzq0g;mbniKf+}NBnUQ8J=>_19wa3 zd<1p}W-nD4ht}?#PZiu$q1cRDPfzISgZCKWojk?fGvVfV&KhhQgrB??t91c&_Q5V_`1N3N|FIzKDzhMgi(Zm_0yasO-N6I(o6bPL zuBE`9`pFBwuC?aHW*ojoCLAV~Wc-CQI;2!bi$&#_&@tY3Dz+S_yjD0%>yUAur!+Z3 ztH>aMRHncqHK#oKDJ%CWLF3aeLH8{^z|y&vF33y1KNaRbKl}-C`xiNbt^>N)ILb5d8&kyWeIQmp`Pq&A zALtKUbJ7V#kB4XBDo-97$TH4MCU9M8_0s3#jjk~cqUH!yptmT|EBm~LilBHvnZI&7 zZB%!pN8zn#=CTJoE>qz3!Rb~z6WhwS`B`+``j2JT7@bus2lwUxV$R29o0X^ZX|MVp zz{A$X@PpW=nz6+vCe&Ro*N0Y$xraKmx4YHYjQInPCbEs>LZi*FqI1&7dyQH=f!SSz zNbsV8N%Sbuhac~6P7(hAiqFUH?>SB>>V}xwG6v2x*Mtqs5IGWTDw60}L&CH3qOU0r zGiavN?ZFzR!nc9h9$HS~Kb=D6_8R2V)#I@Uy^J4WPPqpYilOiR0iIR<0T!N*)|1#J z)&2q8uB&4A&r=Twx)IJ`pH=WpfMk+n)pfw#!8``N?JLjg{=Rf5n(+EIDJECabyZA5 z%K@z9%^0gh^83zy|5>s3$wv1Vk6Z4>NmaEnU+K0oT{RaATH64A=p!Ul_#; zDV2SkwEd5b)Pfd+NUK_IAV2M}fXs3~cE6VG9;1@k z+sl){hD7Je9@^<>M*&)Ns#nWNfjQDjx6xspQt*+y@D+7LD^oL)Uv9S9f6MIVfWJfD z@Wb4mkJN;oEH*dxX-`eqP`%I%HWsMFu*%D*%^ByBEM>l`p!d2zKz z)r#d5LLzL$WK&f9r<5s${n6OwmOtZL2XDrFb357M^Oj2a_Xe}JWZ}iAtCCY(U|A~c zYmqLd*wF(e>st#Di84o7F(5Oru~zZmQyFSFNVp1;t3{gh=P!Z?UXb1|VYA#jn71@V ziX{LRKrqe9OTN-}bcV7nNegv*Y6ri55unRGj9FG!>wQMFJ3kVqAfVMSD8dZLQ8IG% zz7uvTK;FWB@>fy+@!qPBM`!-i;Ob>3HF_o_!EgV7Z5~%=V|1^y;>zb^PGmMscK<}9 zA~EUwAfaI>j>@2IwG{B!o$E_fHcRa-W|XZYz*)x|#m|BaZ?BVk{gHB~a!H>ZI94yXGg z(HC^{{@tz8Z@j??8R!B308gus5vJbf$(ak?7Yq3j8F;mU|=evpx$2Yc2zLJ0|(twwL^skpsecJY}79QRWz5G6i2< zAU*$Oot}LV!+nk5DbXa4-~*gxatGd2a{lFsYyCN30ukj#<}*RRjXC(J7V(g+M$+9u zxqWZpT03L8du@$%3L+$=Y85Bc&v~~+Qp<7_N9H-?ZkoY)*3@y<5%$rKW#8J!d)5nZ zNdT7d*E&HR*t1!YkAPoSea?yU4sAV+_~vmwShIUt?I$aVC<4v6LA~w z_UF-NIT`=g?TxnRWFTJ4mUK8_OJ-oKEa>%4_IxN8%kNK=@q3kn{pd0mLQR>_4g? z(c-UEb3sKc`;F1_Efx3&rXlru)iq?kgVv8+R z*v^t@Ns)CTZ)|ezX@|#pS=!!Fg#pT}vJazWy<~HVg9%jm&g~ zOpci%Vw*fxFx_dlo=gN)h$hR@;xxxjyd6~04>^6}S|s$dJ}WKlTUzS>NwCvVscltd$YQ+4P@_F0n3T0l8F5E|Ovmb5 z&S0eMlbFL_t!J4N9 zTGY_5R2*NcBS89$7Tju#gLOa zRVJ0K{v$K|DS$&I3s^v!L3A_ZN>#CuDbQp>o}kIyDrhHOLP1Wz>ptnmKU+||T16q} zDR@z-zi}4rG%CQe+!)lk9=aBYA}X(Jt);s3vvT@}p)o zFBW!nprb;`f@2ocCGA&~qx5k~VC&RbLWw;_8I%tCLf;834?!bQ3 z#EBs_Sws=TX|@#BWcXy6_?{0FT{iNlv0qQ-TfuBd91Jx3;gxM*>$D zY?d-KxUv0{y1Olojao~G{I2`Z)4d*}%`<&N+gBJ!aH4ewl02x0&)~*~BWNq`Tjj4J zmNH$V#_a&hLj~P zG0QOYR2UWXLs~RN4L%aMoU@M+u?A%sh#aT;@jj5I{Saecp&?Isyj;=cjH`?YH^jWmH1q>hbtO!F~t>D#D{{Rkic77;zsDxtC zsfqN06HR3Y#ouOR>G!hw$%-05EIVj(1PD*1U-Sf4%)w844vJ__(FPui2G-i;?4Ojp z$GBG-42iNGsv>d)ERA*7hF8AC(OV7uCPfPm$}H9tOw`f1OaGZhoJ9t9*!Kv#(3B@m zxWu>qp1u#hVyX6Q+QrkK)_IpI;!HP@b{kfzQU$3nVzIaj&p*Ww6zc{q{HXUlw@|6& zz!WqE=oO(atDR}v*|l1IlGRinn~?V}SybHl6vj8G?q~6sNlHnV>}3J=^L>Kr9j5bZ z{H$x}?0I>=TMoqyzOi@z!a34o$o0$SaO-2s%0d=HoLsv8rm1wZSWi`2@B5vy99`D6 zO)|=httqUHt4n(J8TV^Vne21y3~OugH(iJe{b9Xh0&Xyt~s8XAYA%9<&w&pGM@A|Q9HtOjTzo$ClyY= z`V~eb4Jyh)m1O?Zu`6^m0h_#JODing;b)MT-6BX#e(Z3DvdLoOz;;Gj_{^+dg}5vw zBqE4%g0FGMtI`+!aLipf;>+67jfaucmU)hqe6-NCrnHyFr~+n|^b0$1pRIBFs}Jk6 zme%ZTi)A!PhB77J+D;6-yVIA_H^ndz-Cr7(^+(|`RrvdCA*7nRxz^#vF%{?)y>GzJ z7*jiTP)tu!kK}hZYLyeDd(+ZbzA&7uYLGJ3^VlkKHlVn2E8d4s_YTc~4D!Gk^;4FU zA$nAG|2>QT@7u9kLii(=F*1x|rtbSkZZ$O|1@Ty;+?p*^#|aw`YBH!hSydy+z=T?O z9c!tIO60eO-mjxX7>H+@4Nc3zv@FG}Cap~3(qEgTM@p5vMenU4i;Lk_;0OIdnVp84 zo4*3pUX@dwarvi6=g1Q5%M@5ulvj%_%jH(aL-QCrqhSlg-X?e>LzOC-%nSP30j zIK26>seG&UY9sGlynxy6D`ZBW2aZpfV6s)c#N4;TWZPIam?S2UCIcbAkDY|E!|~Jn zN<&3{2!~-fOsc8-(}2tS7`k5>QOVbeg66$n?u21rev-^;I!IV`0luahnM{oF-2$2G z?)jvg_YG*Zl+yQ}yC#AtE4o5^CoCCy=c{VTi$W)Q=~FUAr*b~PY6TPMf2 ziv`KyL=%^DK)q$l_nVEy`>O33mf~X}o==VUj=JHQ|H@Fl=!;PojWmXupX{tKDEb?@ z!HRJILrj9x+h2q6KIHA`VAAVWKj}Y(2{)?HKV~!u&EB?_(IL8r$AN9OZSfW^rHHYY1U-~lyq2t&S zb!v`MO5D>^)QTv_gH4?@U6>dGFUZm%YuU9m=P~lu%Em&o=AHh={+m_Lor>+=WrIkb zB&5X#t7P|o0N5z<>MtlX>&KOHW^#yYTn<}dQNazX!ZKS-c@CeFFQv*Ib~aD;ZI;!s z>0_|yPi5i>09e1<6man{Cpdxx;e8S)m9?-ebp;-kanVDev2H~!_4mQI)W@Lw0Bu z5Q7Y|SBhpF+BXabaEfW!<#~gU;I_1nF-E4*vZH@$_oL%j63`$YTheqMSHKDA?Yz0^8k7l=zZ{RSDuA!j(68tBt_(WK zt1~c^a^!{}qIZQ{G}UAf`2I$^S7e&jVY^D$r38mK{em3Jm0oZhX!&Ew)XEBeW1;1* znD>8U0JU5ATv^b^oG?AU;?p-l#STE@Es1YExq$(vjSW--yR+20khekYf3frf(P8k-vY` zF&<~?VSrZOgxhg)4*CH#n-~4Kcyk4Xsfs^XBQ0OND8D0W^n7tZPugA+>%Dv>^S}h6 zFQ)z26j%LvP*v@WWewW!G?MYBm%7^2=_O!?51e}Z>BzTfZj0xRl?griWxm;jrix*9 zqXPb{O1JE2vA;hlj%sY$k_jvdBb2u; zNtti7VPJf&A4i*Lsa6o`H^z@ZXh`!!=gs_>*QHn^br+!^{-oGeWTbFRV;kE;{the( za2Mr)xpl2k`&2r=MW&S=K^0ZiagTpE5u5*^emRfh3;$AQj_DG|E#;0$=mP9aZC!G1 zBHLbQq|ui>6mw)bY@_TQILx#PD+zCxNP$d3L|{>N+%D%Br-G> z*I1rcy`xa6t`;O8+|#q##*hvbq{BSpq}-5tnCFSyy5SpUfyCr&819qd2Zl6~dy%!m z^hP)1k%OE6keU6p2$|-x`3FG#?pm{zGDt8`i}C4EbEf0;WkcBDnxBQ7gQdU;A5?TK zFMrgq|9bPXDt;!3QV9)V*8lBDj1=&8WWIwbeEx$&*5SLAUCLdFysV6rxMkXeCU7jotytXr$)t zU2{&8p1zcelXSsSy}4VpGq5f}0nO5b(xG9&v3@!rwc!5C)lUE>p^m`3M=D@DIWC4n zqEstek0%XN2PkToSPE(|QUm8_!FGzgs1;jPvOaEEeoD=P zts<2z(oWI&j={EY6IEJPPBH`5^0Mfu=z@as#tB;5AD?BZ|5p#B|96qF7}{U#3Tbqo zMCFfh{OJ32ZG0b+!Vy6;b6!USGFTjj_vD||5P{t+=>gg-W^L|dWDj}1ZCJ&H88dbw^HL&Ji>>WBI%qW3w?AW^JFL}Dw?QaoI8Gico zipayCRf@~dEwHZxkRFqnd@DE%xGXBzloNh|OQ(FlC2U`S3{I3h$H-EA1(ESlfMe@L z*3n^cNwY_&+WZ6m0Ft)mu-;uP`-`k8Ij7X6gq?gco8rO~3tL-H6VZxD`{aFQhk-V` zM&W`ATcqam{)580pLJlu!!cU@V*-&Mx6t7htIpl%g6x^=mbj&Pv@*Seyi}0^ydE-t zzfUor8;6(bYdJX6LkSHoGJIIB&89T8`VP_7)|MNV%}ce-Ff4jtS;o9?kU1I%`0rDM zqP2tBP$KvDK007<&&rB(nbD0}n$~z3M>oSIt2XeJUQ~p!K@r=AZzWLNnv)odtK165 z^w&Haqy2&OOoi@v3ZGqd#p3i26s|RJK`JWv>EDL2f+!pt-IFH=jTZwa8;G6>wI@a~ z7454?A;5*Wd=tt0PO5KG=TFps5d}+HU`2JlVjoQ8G_qZr)52WtdIc{#%=39(OGMqJTxJt{}IywSI#B_6U8pZ2kZ_E*94&XfvE$qgkb zkC&vb4o@CaA9f?*uJ4~3D*z=h8WjE+xQvTwPJUM7ufEOgmux0 z`LS{3ditc-&LUx*ea?C{6N*JlSu2GQzzuEBCA1yjqhcL=@z+T_|l0vIGjR)CI zdao*k$MNZD=Wr)cesS0tGlDZ(wpF;r(8%nUxHeNNeB4&FJS{xaV}&5DCO#QZA%3i5idq4Rm3(%`?uX`s6+f7h$Vd@==w*n`^M2c{ulBX{Q*{!z zZi*vk4(nHd5=@yu+wO_I+Ujev`GprII&)vp@N%?2ctwd~p&CThPn0*)B3Qpl$ z+MNnP@(o%$9U@xKO+4O-f``i~D}R-mTr32VzvTHL#$(iV^lkDX2A>BTmqeK%S;BZ8 z)4y$qVh$g8FXj_hn;%Eq=qG_0OwHoy4Z>AbP(;JqQ9XvtJU2r>frq(2g#CkY5JBzO~3BmkH)^8|g1LdhTJd5TOk8cpZQQ{i4~v#ROD#CO?U#v0z?PlQczB z!EgF$5wprtjW^`DJfv!;qV`g{p{EFBxUnzXvEew~7@@@-J}{WLPrS5+)Z5@9vJzI^ zW9}gs?6O%E3IFSnwKP>!C<_VU@&$tmpzuXBHA zK8a+U8xigE&dE`7AaGAkc@w&WWy{sHk&Av-TDrz)oeKYEo3*50Qdht}me7(V8wnI8 zySKH(%MmIpKV>zhz_u}-FfhyC^%oy8($e^~51q0|n3j9*rjInLy7W-#+9>jqcc(#x zdRZVGY|l0PdFkp#PM39EhA&<1Zo$~e8aOZrcGm&spO=BRoyYceyw{C8S@}vWFu^Ed zwQtAz_EDc7{RkDd++vm&Mig!6*n&ojACC(%MoTH0nt@cxi;`k*YS9N6z%pk~hD-a( zHmxk3mk|RCwYGcEH0O~&rVr;Ao#j}hkF3olr9}leTI!1f;-bG}tee-K&k(pA8ef)?Zwt*R1kWZ`B#40WGJ#oOV0iO|MmXsQle_ zg%xz+_Zq0OvK@WbouVsB6&nw*=Er%5q}~{@(lEn+DUv6xM*;jsPUjw6ToiMSxR4uyyp?Ft{hmAaNnbvbzVZ@GmSZXFsIa zpKE1U$Ik7#Hm{0*S%^(>u<@V+femk4PveagFX*8jtBRW$^`SZZPW?>SJZ*&vh%@<$QZge)1=+f~A2dd1Sd%5y_X@ z{9~^0s?aDFmM@_Ss)-5;W1E|%fU7P6!N~jQ0wGrB{EE|ZWo1_SxycAT6>yIgRVehJDZseO4747*O5?IQY-< z)=srlIV0;PIpv$EsnK5&)$p8gjclkvG|Vj45hC`^N3IWKnj7rXJeaZTy22a$o1A>0J$+Y(rNJ z`dqK{Agt8(dQ(#7;NawcZYgS@Y8^?R;b&gemuQsK;QVr+A0rGy z2{okPXfYW1eI2LuL+Z_j$Su4stUNXO!`|v#)Y;i`;urW*-Ey8~tc$3T?s^`>XLBXR zU@Q*IF?&vXtn!-JnVN*MA@(A9&m<7Ian);*D=eXGRI%1}3^QZvbWTz)?mayMrP>X$ z((GUv!fnI}Uf5aY92`x|nv>C>qoT&FZS25i`13r!{XkC`HzUTKI<$glxmYwJ=6rKH z!*9tcLbh%hLvt$2ZCfwx+{M*Uq{fq)D1$)!*>=^kOUDldu|0cuhkmBw`npaSrAh7_;yr{kq1E9b+y{%Gf00SfmN zj)5Z?R>#}MGiN6{bEVxH)@j*T8NO2P@7{>86Kr)jtSyJG+xF6qQ5z8}9D>KOC?p4{ zL4AC%(V(1_0Obfda-n0}Mh$bFXOx=qyN(>??X~(yJM_|VQiCTv^z%b{5axpxUQ%{% z9_M9$yD5fUTBu8ujf^y}z7gC%72Ky1X*6p4`QS*^n=&yO{fjw!PW=gpZmG>l|_IWu^lY45ubDWV)u5Mudmd9 zZJ1Z-L)4LHR3V1a$R?a^YyIVEiDRD2lx&bE0Rm#>gCk@DepQPiD-52Mgn3z!Ow>Mx z5{nwMYhokkDH5~%+G&K#Gl{s0B&C^?dkS7ZvpcU9B!`rIiqos6BTeg&RKL|;DZGF* zBb--(d>&O{;|(~jm1>o}T5@qEuH_(b?q1KbM1F(dNfbTp>TPhWNMS^?6Co_=!|CWI z4)8-{%(f?}B5U%#VDHgD#Y6uD>x(i`8IG)h4jCDUek=br*3avJ2-HX1$PlrqYK?)a zHOI$}`~~uf${~uA$OAsNkz|RVSuv)@RnV>nCYycErVzqBsXPv5*MHC`rfR~uETZCJ z{k?^B{g#s6)|s{s_YIS*f}(9yZ$i*BHG@oYiA^Fiscc_tsV&;wx0b;@^x(ef0O%~+7EM%Qm8Q|D!UUJvAfTDs7U2)QIFGotr zTOCIQ7dIQcwHZ)8Ud)&YY>NihmiQpQ*`0OZ7P9VT;ZcgLIVutHDGUb^8)9iUG$*;h zS0vCEs8+y#ta^0k1F*RVa$l`kM@T8?3@BF6f6p9S!=d{#Z5xg4b5AT6+k?3V3^668 z8G>)@VP@-3VJO$uc#7sIzvuI2UX*9Nlc!su(38=aHCLgIC5%2Szh1}od1A2PNdoYX z_mBXSN2BnKoY#BKq=J~8e*k%RT&igo{kvI-e}E|B>8-7g@90kH!Cpl3!w&alkuD;J zJUIhovL6Xw7D?8xe-wP}Lvo`)?+o1@EKgsR>yKbp1*#iw8KY@2f>AA(j@U$}QRd?j zVGj)Oj823$F#($$(9daFo)mWF_T=6qe(Ri)=TYFr`Z-; z`}S&I050?gTNmSbHAhN~1@XKln1M7+toN!z!(kyushA9H>lUC&g*wkvK{~C1m}MOH z#$$RHRH22#*4E7SDaDr7F%XGsin4YBMdDj>G}>Z~ru476%bLQeQ;!^QQAnPioKa+A z&%`q3EJaB-@zfMRkscGM$8VZUW|-?br>TH61Vs6gYTtKUFs-fV8zN8RBml$B(aKI- z?O4^8I@W(Gb5T$ZdfTlsBDiY_A@B!AmbITYX=$l{9AS-)tYR*wWwR&H!d0CpFW>}6 zyJYwpj|a~>_uVy#E*&B%I{wzpj_T^R{DZh?KJ#5m+wQGqiOI865sM!hE_7=}d#i1^ zzrYt}C7?i)0(U5oNB*o5Ld)2V z`!VGIe+y?u{`~EK&+^~*nq|Mn^NR;tj>j_|($6-&a3;P$KEZkaESjr~Bjr=0A$9#U z*fUF5+nl=~pRw=wf$7LXi6{^kJ<|;rkCu8Gl~rU5JlmmuzBBNg=#!!`W=9|+f(xWHO>g(=Z{IJ`1kr<*j@(?)1`-Zyg zkZg#T5Zi;0iIH|2BKlVB%`LgM#`C_;nnd6_H?jQ#Op29`I>|NQ+ zyGEZ|0(im1GbaXBkUJj32H7fA8te`z-zHWrPMFo)ngy(mEhs0JzPC4v|3K@h$- zuyd_mt#KFiDE)iX16(?<~dMXxq`2jApDz*g_o2nhS67J=xU9_;LM^}!Dtf!B{(awt3Rg9;u0Gk-m$;!AY?_RAv`C(8wA@1#7I?sgWjs*x_xHVaN=Kc8Ai3 ztiGAZbgb>zY2w;+KMMKyqiv3Nm+;tsPGnEQhYo{|+xCN8YJ2#$SwIEgd`7<7U1aVX zzwWY(iykRgp}xS?S64$8@5;Db{9isIx1r2X&s1rf(Ckk*`s|;^dQgvGBbp~NbXs2t z`tyd(>LdgOwJbPpRc6P3G#ez=?dm8~+qr9wNY7fAV7g~-7H9?y27ScvY#osIG09kF zQ=CO1oR7%-2XLIEdRi~5G9{n;^G5Ra=G{L)$73|jSUOWk(CS6$~=4lq%F-_wZNn3OK)|4ZUtz zBJVWIBbeQ)8MN-D%bHsujKaJ*4zOAe6`VW%{78%xX+PFP+tJCw$?kUg6&=3F=b;gx zW=2&yc&URS$UWtKCZ?SceTppVEcl_RnLJN>?X$MLnV_|&9MWFJqG*+^cjHJp zTw@%Y14cO=NMPH;$|+S#X)CbjMVMq-z5Cp!CtYXjPAN5-huLwkFn0=iZ` z=ESF4)O;?gT@)`6ApNV+8(*%>k^)8TZwZh0;t;9)sLA+#<*1Qp&;hV^H}y)&GFuhW zrcSo9^?EB~PDE5zXI=7abZM98XH~d3beZQc=%q4zy;GUfSzcU%C%U^RWi#8CQ(;L* zU1|#17@Kk^{NsMV>;c+2*};ma_Y9DF6X-nitPRO=pYpl`7nW8L;eA?I67T|>t_ov? z-t5#3eqCB>PPa-^Qm`2(cLX-E*}%%7Dc$Fg<@Yw!JZ)4c(4Us0=xYZ%91UKS2zaen zONHmWN9*78uWLP?Q7rkKV9v3zvCSQ>@&pbx#<1=!+S{g9Qg>%cd5^(y};TwXVC8 z;z;=R@1?#QNj-IH9?vkCnJp$32ff#6EpS=pn!RK+^`b%#g^whm|1n4=s#9Z(t=P6C z+7{VdgRnsO&B*2ux`Ds=F~gcwlKA%}M^dg;brfY=Ru&7tDXZ~))b_It{#9F^#?v%H zpylf7W^#>;%GZNXSVlP`d=NgSKM6|4M)R0ilyR$7(oq=BOYa`%IAv+;6Lq>(d92`G zVlmBw}y&cqy^L(YV_lb#Uopmy@_~}-)Q@D$X;+fEZ(d)VxmyRl9C&*NRoQjc# z9tw^F-w9*e6;Ln{&82s-%X{4jt5CU8LrXS%EBxK6?gA@IY_9(gMf~NbgpN~Z%*QGX z=M@vIsFKj=XltG+1k&!)@|&{-{CqDq3e{8tVO^s>A;_;I6QvQG?}tyOQy@2KVNTS= zsB;Pei>WyW{Uf2G%3ixNOEC0HD4`O&L9$`l)PU-&ZcY|D7k$YB69Sub_EDAL>QG=i1>l`avo{t{dqpG&qjl;XF zZMeNhE+puzvAE4fi`!fQ=0Hr+M78B%`92}{O>a)-F}vakPk#IKHP~Lqc%s_W;?HZ& z+ji8+Sh*Diu{qn5+zJNzzKZqi83I2CdF`>4j%CqFt)N+zTOSxtf8^~d4j|>ejfR%Pp zuE0v*O4P`3IZ;g_hVa{g>mGH(vCFVZ2JKx-LS{P-s@ZONr-=8;O3@y&VIo)ci{@#Z z?z&ZN5!#VV3xx!jOJ(zjosM$Tv#zy3(L5HH{>?20ok6g_Ec6`V( zI5~^yvoluJ%7*qvD)K|eOzbbAQI6q{U`xS279at2i-?d#(QQx+8ns?BrDTG#*-U9ukNlqw-Sf5_` zUp2*#(7t=)7@SZmdjj?!R8K7iPNlT-k4zOOmIK^Vj>HE?+mw`}U60!H5nO%7am9Ip zr(_t(c@({wYw`a8#V%Rz4UV!rqyx6WwElb_$>u_}#BQB+&nWpF|2F{S-hTo5(oGi^4Kvu38i0%52sq5qH8(RL>O&f8%>y8)1c1 zAQ}($gc>DuNcV3`rlG~otHygc==cS%J4&WvyCmFch$ilFF3G4Ob*uu~=in7VcU|qeztT9s4e-p;*4*nV zZA=VzU2+b4L_&YvFbx@+2u1LIamTUk*9}o4IcQq$%QV@|uN=lTYeBWX(b9q0AG@Gu z;`0o^`fIU!ZwDJ$GneVTJk^|5(%m}W8`4g>c*wTtBY_^LZ6;%?d+^#e+xlM~rP#cP z@j!wrvIh~TI)OOhcNhuF4Lp0#fBi}i?fS^|-aI>wQF;GYgjTJDTQ0xA5JQ7APW!;; zN>?nCsG?#1uj{&nfOwnC}`;m5I@L9a1s@Hjc zuuAX{i%spy*GvhKK<&`@MS5X*gllW5J+biv&CHA_VgJ!F#XrDSITedIscP<7P-zb; zXb3apy9`bowP)w|A&z8Iqk$#;(TaG=EZu$IIs;*ZWgK7fdUnE28djR7!$8h%X{+)NBCZXg!Pa4mI&>mpk$ zkB47V2HcIey5^?T9p9{lq0JLlt>br9Og6n_iobm5TpK4E;=sm3r<9;md`RWym0->h z@7d?G*($WJZ~-mp>s0;~%$W$GaI(yl(vdx}2#OK2Sl-GjO+k+EZt$9NmZ4AOAIBn0 z*;~!ws<>4B@sV#o7ndDNi0-O3{vTt16%>aP^o_zx&;%#JEog$fOCUG|cNPe+__EmI zk|4ohg9LXAu)$%G#ogWAon0(Q2uaTWeZJ?rI9KPLi>ayZo~o{ynrf+E_Y^Cyy_>RQ z73!$&;4S(to1>_7fNFu4$NF%_#=>U{4GfeZu|-83%Mv|RydD?@<|(xw`8-_39$)XO zKWX?KCeN5dXuTZ9F>crbeM<=f_bmy^VPXdr)v`b6VFlv8Q~Ti;OhE@ieP(K}F)A+2 zKsOACW2xuFKL+Z`1Sdd171E}3(ZGLzzgc(QBab3Illa{xwtV)cM-Ek*OTxKlj3jsr z2aB92VMQe=x#*a>|MZc1Utaz{3tDm|Mg9L4ipy|LW*0+pQc=#>=y2)87=i+<&rR*s=Z|2iDYQ;n;PVV3wPvKP3Bx37~OS<-Cgv zkvK0{V}*7sK|#}}YLXUK`LB{OH@=8_iq&`2t;v@ORweUq%j1dM(kbbUMfNT}tO?GK z^ox+a<6dC(Vru=w!M=mA_pekmk@s)CA_UOZ4S z^ZCYIN=oG;fekYQkOjBmy2z#!Ili+b$mKAWt6i1B_7Ah%e%ZP;8J zv1qD2wwb0_#XP^9knNA@9O!|5*DT@;%g~f1lUX)W@)T5Fsrsk%>xO z3R`DHTMy@ih+JHf7z3A~8YRSFkf>Sgz>X8nFzJ9phS@gmt3*K*w?FECmUD)yKZ;)| z%uX^aVrw3i7MX=;I zsN)ap zzu~{4>)qc^5w=TzO{ke(Fi#;)OHh5_JqY@iP+Eav8C^caTJ~h|2Fon={uX&=j{%xc zDQ{^AZW71IN8r zS{Vu8 zC4Au_omm>C4cCxo%IS=`9=91_n~L)--Iq4t7?(($yB0sY`5Ri-_AV8VlLheb!h)#E zASheZN|nfco*wnd=1k}EuC=dYLv-GxYQd$_|4Y4^?dbFpWt=n7w)w4&1~9Ot?IZT- zj+8|GbtEHOBhF~%CQiYMCSjb7g&SKU9tuV5XQW`sp3?7+ZMpfO3ArMWm;wb~o31Q} zR?2TuDmHeshma5^8jRI!;UTx8}dt>32Ud7yM7A=-Q55AP=lGX{TOX{rYfh!)jsi%`s+r zSg44?X(o4Y?miXv70hG4PO4;9m_0n4O&2V@=g*Tn{b%+CrQU-_VuU_;^|!YsyGaKSYr5WxeCe zsfxx&-Pr@rg%71AWnrfKptxc_W~uf@&xz>=-ndYk*gRNMo6yEtgD9TK*3SZ>OX)Qz z1TrGjQ0!rDUq1&0>hO1t79}S}8hp5u8yY22QRXJH=&0iP%&Sq>f7RlADLQ%T7@jfM z#j@gQ;bz;2s?NjzR#jb9npULloK`Pgq#|ZBy9*_ea1psN<2I&93lUWF5adS|VTMH1 zW3q22jqV8!G4NESK_cuJ$G(w?OnUJJVz@9xZ;A9k4B=1bd zEtYK1jnW%ah3)t5Uj2UZVnC?0Cef2k+x_35kL-RbkoiUE@z z$z_zrzFM@`oYW4b2S15ZU0SkbrPmKIf8{l=5>lPL=BsULIxgEbXJNUDbw*Z%(|(x! z5R{|+E@JUii@D@Wn&4Ds|K@6TH6O_y=lT13br+c;sw~KweOFd*kfr7n;q~tJ?x;iH zQpMt)fXLsP4|hn5gjT-SKfjy^Xt4y58nmJdqm{T7iB4FgqFEGLt`XnDqiwu?UcG-j zVf=7)KRqqf!btmZ+X!A1`!?f-cF2yaKSgmdHz4~-80daADb>sfzlEkS#Df$$HiQTg z4|xCrRe(cTS#=@vLrT#JBJ26^z^W(l15tWbO$ZCs4wFkf(H*4DSErGP+CH(acVJ-2 z!Vmq+{j5$G|M%O&z$}FeFuh8K>R`A~uDh7yI@f;8EjdvTe`J(!8_%PgomAB2NgaW? zd}>EV!-3erL-WWo;kms=R^?VZ z7d-ISi{?oy+EAOp7g2{pnthpZwu!o@H-aORmJM`_``&D2G9?V4u*6q)R|`!@4tw{-1*rqa?YQ6tO8msO3}%D;>DxS@Zd$&)1q7DdHQ%ipA? zs7UKm$iB0ikR3TKlNPJ@3hm>{f&6(|Y-LFm>HH8kQ*R0>`L{WdCU>WX<`b}ElYzlHSIAPIanuMTFB ziQ%?*Lx){PrEDz=X<94H(H(1b)eUsReZ($f46&{Eagkv~I&6P)ja8vBo>W*C^|9Y5 zd3w>)J^o8!=D>*h?H}%WIr$~zPG*;c*-2fji^_{Q;>!MFFVeb>W3;k;9O0^jUuxVl zcwtzzdeA%a%*x;rFBgC6b?llAT)9@yTRKl5+dlwNC3MVWXRX1w*L_!DH>{X|+X)Q) za02wJCk)&&L?BVtzvyfPHBI||CZ#uYv3jN>(4t+N=YS)4s#1g+8*8HOV{IHinM5*v zr*Wyhhud zn?9~eb2gV2H@z?y?$H2RKf)*tcXh?d-!e>sO`8)|d;R@mRFQ!I2);Dw^N9=vxxH+T zZC#$gF~%^Z@}QO%n;VdHYFUl{zOk77@cC2tcG3KTBw%+`Wdafy0?hv!^N>mc$_S*w zsEki*T3Rv;efUd9TlK-gLcXKw^7uRGlhSC=I)fDOjmwb_A;>N z+hWL1;qCn)HTlz3IG6Uo0Ql-;@J%#Qd|g!llV@_EzoT!G;VQaX;rzea}Obv!cf+=2ubqc}OEmDh;N_!9!A zJGw^Q{>*F;N=l=0F7GVrwQCUq1`Rz$3<@D!>gm4ATA_*W1{ef?tH z6c6MlZG~V6bL|FDz3)eJ=NP^In3>!%p@DzJ`#g8i`|^9N)lJUGS>*P~PdH|Z3U*_b zZj`RT^aF=Xx+AZzkzoHJm&l}skSA{{-UT+2I5z2dr=D(Y%b>k2WOdg_l|VZz;gy6@>r;M&H6iWdW(?^FXuD&(}mc?@44%t**YR zwPd$^g+)?gO+ZBHHv2nP8&zFwWzlCrtH#7(+vp*2csLHOcsZO@75JNqwf(P#d7V=1 ze2>hB{(93>g*G)-N{N_O_p8=-({!hDDQM~AEECZ!y|G#X;{|LPJAHMEO ztLWJOxWzW*<*{qzh6Zvq3FL}OUjKIpha*YRaINRl&sOS)6BxBA2V8wjN^GRfk3BpUl00q%pKhAD?DqVfT~J?a z|C>RaoUKdYgsFUBj%j5@uyxg%iZ9}INilpTvPgH1Wf86y-)-JUa-#9O9P_U~h_@u@UC$E}D=It> z>^YCa7zrM}yfiN{yw%^+v{SWBNGjtVr|8Tw=Tn9i<-aVQ91>McSl#x;&0tBoG#75M zF4#5Q#<_}o4#G_Xxgk{QXP?%xDE4FDW5@k&{T3U2fs>WdeElw0_iIcNz%8}S2{|Iq z!kT)i=DA`f&qlJWJM^-)#TIJ9%JSBqrt({ji(z4ATiJUR=BmgLwTK~tgYCh4hP|r! zAo9w-IJ?@Qh_sfryBmFJ&bg>N!-ojlt4u7S*Zi*cDI1PAtbu9lT@49ylPjFgbh{_C z_^$Yq+ih0TVl!4%5SE_K4?skC9C`CQR(Wo(>#6PZdZ{+f+^ftUvHb zqbdcy8W&IA(?g{JGkfr=EGOPwseN14bdqVn9W3q@RlK)fbO{OB(mJ(8v1a5C+RJkr zW0Ga2c=3(NHnrmhg}&R#L`k){$>vEnuUTIje`Hk#@% ze;*^cnSNgCMeoK`@whv_#&22O&#rRuinJf*aA9*~9aL$=)n>#7)ALBQC&?hUbn9bS zmD(KOJ-I>~I&0}sFaNSDXhiAF6-fD!dxQ%Um;Xl6RUubRS<>O$oq6Jl=4@`rYC20w_Vdwy+0Z+Ub)53Mg zsd!Kbzgp$;Oh4t)#j3#)cBWXunPV)vN;&0J>5`>3<&k2~qcA>T+eoJ!nO*tvwaT=Od!D!530JyGe`cz zgG1Vj;XKeAX+gSbR&U3SkU0?K6MpYc3ClKG2br9lX-%!0SC^e)TgyqMW!r|K)z4Ne z_DdzdS2X@o(#fKvwfpSHDB1?vyD5hek3+1tiQ+c_@^3HnU2QjNlCIeq*sb4iz%dNDVUV5KmIX^jj=HxD~I>N0;!)a_k#N zW{;de4-{pxotW9G*{?IOy-PJr6z>L~7HDB$HZ+o0cP(;Z%_{BWlN+|8sfkIoJ*aqn zNI}u20kcXiPlo9e>7DoG>rt%x-TKD+3!b3#h-e;T_37gM1Qq%Cw9*e!y{Qy$Wozh2 zlr-^~d`xmC2oY_r!G%>QhKL^_GA?b$|&1W`QrlA(E8NNpg|d9XI64Ii@$m7v;-&^u^RBk@}9dB zHGnc)W~m`~xRXP{M&-LyUxbFDrdUo-`aV>_jMu{m&!r_Fcs{=JJ!1w{97HPfAGkLe zi;4U^LSGv7!ET-FrjotTiVmXAZK|iRmA#S0%cj%9gL=fZ9ZX?^w~pX*cofTSQIobw z-K`HWr(SdmAO^(y!sq6YyEx|S$m7O#tX4*JH-5fcu{mfZc(fxf-fuhIbhiSeDAdiTSdj%9iJY*@s^ z^?s0RYiq;S%G{4|!r-dvirm^AzVBtx13GfUR}Y#p0ZB^(D#hoHE6an+n}a9fU4Hqs z90=u0+3!^ewgSqavY4-<(A>Jl zZ`@JMLmH-N>nst{#H_4!sJdv!7q2=iFA)SdEY3t<bN9sIXaiI(vPr$@8_WK@CV%H8TCKqhz-Gda)fR zk+4#3{)v)H7k@kTio|>^d5M0VqTS!yX9cE}mW(sq$1T)()p*Z}X^cx`$>rPE0xD;^ z<=-96q*LQ*sKk3>*~YFKuZH4!)hjqnY&$s-;ynI^{Kc>D`Qkgea^UEH$1sz$54Ntl zfCO+|?b)NWge;b?n(n-7hjQ8#@Yh{Mc=#M~!Jcc$#Vo;=v`h{l&-48dC1mJc(NNsv z(ymBmTn_M+dw4BTt54^yu*q9?sP#8xPl*H~Vh>g^>prGti(#8W zQ;T8F#!{08p+ZDxQ<_Ok?VGoN&_91UIYImlm2w6h5uvXw@2-rtguLd(KKU@-8h3Bb z8a0wFrr2zccYBLIyqz`5nF3{IbLGrpTpir3I2R_8P??QLy%(}*8dYw-j<||>4Y@uxH?u(8=^0Tw zX6hYv91OH#0&rHe{{ERi3S{AX9{knLK~kRWr-y5L*UW;RI#>qvy0zqxr7YT%skYH> z(S4dhG3BNb2F>9i`Y_QVCfXU7?^>}F<{XHtxOZP5RRAtOD$+wP@P_qN*73e6*!&03 z>nNQap6=#eaz>%{Dc%h3nAuJw;+i*}1rn)#D<26{vFNTf0c@z^9388C80_EB(3nX0 z2f(&NMJHU#O#B(fG&;LED;m(p2gG%J&tmND62ZN;ch#fQ(r22-ci9N}m4+*+qG;v{ z?bp)tqWg1i%G{c4-&%APhwpW;Z&<(jdMH_qhlegi?9t%O3dZ^Hk|N>io=;x7$>t*R zWd?0izsZV2)@;W>6;turixZpFYgHEe+(h&bNJ4ZYIdP=Uu{kx1idR~gEOtN_KIqo3 zlUDJ_hRP#N{5NN;%aE+6XZ=wUIv3~u5`W~kfF{+ORsW{u&R8Ri*jcOPk{bi-_#c96 zTzR{gcwz@fT|l;MWBfU9%aNFog!jj#v0cv#qwn$Hlw?vKHfJVli8s1|T5mnjOPBM- z1H~xaiv5Bi_hK%7D(4a3&7Ism_B1-Qico#ycG&7A9pjT^-5sa)M9sDOKfr34)Kh-M z_v?QEc*{`#LI2;VmQPv{H9TfpiEr^oK4Xj%-U>_#n>s%PKKl|m)Mt`Y)Qe7-a_o}# zEE>*ix_?pj!&a}Eto!W=k@d=B5)n88(J@@7b6Q^NZ5t^|T9%hXTkoL zz1?^Dc=W=YkGgL>e)PoN1IjJ(Z1v9zWiA|s$EGRnmiA?2*03X^#@pyUZ!(eA42I`mZT(LcMzL>P z1F9}B$M`tjqkE zL~~*#2;cZr;d0D$L-Ex#Ty(JYC7fA3lB>tQTyx}Q>-CL@2zspzEQ-IrWU9V}XFs>;jq{d6ty@F(YQ z!o#Xvb8zDuoX($;976?>`GRv2fLRKw)Azd&0BiiMV$-@1&5_!w{v^2RT}MN9M%#P!qJ! zr8zO)cSw|1#5ts$%i_NZ00d;G>Obnvp2kmOj;KC@L>64@&bEKJxBsv(vqe@d@*e=p zmD9uEmB?}qgjWZ7v!Q+?XM6hGC$Z&e>t$Bg3#}V{e#Y1h8W}X}KR|tlUC_*l)GP7) z5(3SY7}&R_)bIkUr9Zm|&6EM+D+i>5mU~v%OS7M1YALPEF%<3X&EVHydt8qkg5ve= znIrG*Ao{+^JqF>zUe9zrk&O;(x*|wiRQpO7imx&R@ZWF*>{pGY*9R%-lG-)Cfd3Ef z;r|7O(AN8pqE%>MV5mQj7aJ?e868urqy+rlLry9gp{x7Ko9#d0)Bj|2|Np!43JrCt z3~7IW0t-EvdB6N$rW?#8cvKhHJ`7oVHc&?9YUF5#MQEKVb%`Y1G&i);G#={`{P_{u zB1(sL^DNR3@TvCfKhcQ%eOffZWwQAcLi|dNw|Sn&PL;5g%|ZmKbS*M@CCOu9Xi(FX zo$VZ_I>bRehQxnc&8`yJ?CC;&lgm?;`ZhDKqAW#(v*Lpt2PEE=lE&ml->OWe*mAGf zyV(%N;^Z3Kqg95Zf)DY2rIwTq*6^NjyL`Kohx1{1+4%&+i5D^wpMC6a>SRh6B2hpK zeBb1!ANZn9nvc1+KUhhI{$wG;Btnm1H05FTO^2$Tj=lOC(;=7im#d6FMKZqM_l6N-&Q#t&6C{v#f;H z8ENH+xyYzBU}|hukul)98$*(Gs>eluP6YKG?#&`3u-#rO2Ab?ET8sfwU~1}dL;TjY zCgx9n=%vJ~MT?8fYoRspa4yDdh_)od)rdG=xBcK5MwBdbEPGAmNthOnZ93kA?Tos3 zt@_d)O@7G3tGnA|7YkE)gB3N2m>02&6X_cD9Er>YouGjVLIxF_8hFA( zf6gFXtUlfj%W1pWz%}Xi8%m&spie;dg-@>XuQZ5;23qMB)4Q{}*FrZ8*;;wN#ZdCH z#mw2>p*r@Dyamek{RhJNJ>-(;&>;#WGnEiV8Zj>(3!r;c^({_X*{mkZn*GCX-58o7qqisoQ>f-a<%s)gJt} z$mIfib^WI6b@OtmmlsJ(BkXvtAHLpp$8)i=|H=RjtAGWX4~c9iZp+Vjd(Z#8b%7Se zsQ_G*i}no520SPi7bJZn*BQ(gFEE|T`{VOR1{|EmO2@dV)A+XwtT7vjwILLTNdXMpaG)Vk8(GS=neGEbR1 zX{LYOlBletYk{WvNO@^tY85Jf17_r#$r1UE>rp6X z+xVhmFt98un(6f2$EWRWEmV$@xLH%FQq9yMqS+%zFxk0%0mYp(A%;auI$iP2)>&<- zD6?POyiq*md%Ig%1vLL<5qqBnu(}}PJ1>;JXw~AEvC~C4X=nF}&9^4Y+iyULL9{;8 zsPd>%ZDidN6NJA^cM**8dNQlYO_WQGW89v@mX??+ znKML?*XMh|!YpR)~cT%zo!N}ymfJX5C5Itd}WQxq77dc8*U>DNi#STdIE{R8O#SeY41Z_sD7 zb^u)TN+yAyPOHIg8>yYQRheZ{zv(7ne`b|pyLWVhdcOQlZ;n4dXl`?r2biLa$o`h~ zIL941F2EQLq8CRP(Dk{rt~_i#6E~cQuq6-CBjj`!X-0MoxAX!Lix>w{9>)ez28{>g z&;E~5f^^3&G*AEoa1=A#_~r53Ft`nHzlDS3<BP=NnGz$agm70fNE?0liI=oVas z5n~??&-qnsLWtrAze-<6y4^u>vG#xyM7!bFFclkScw%i%&m^x;c#;!sg%ILK@**Nx z%IeZ(2hucM!Eb#ze!oa9C4qO*oGp1W0}McS4J;ztxqpPumk<3=HS2zw;=7PM(hi#& z!L$X3w=IcX(2r(*)CJOmm)T*eX2LuWw6tqoZRT@c0_upLkWLCUULjXlJM=R7jklt} zKB#ifrdRCp%5+WKC6j<(JTmv=(ug9eP0~kkedFk(_-r3U7nUP9WsS~vUc~JWjt$Om zh?wF%pA%(Yd~O{rdU?Q0iaxvj`y1Y)uOBtK8m`F{DQELK`?-n$s4XBN?d@*vZ4pJ2 z#{0>l!bE1UCnD69tQJluh!%^2hRw*e_ynV_7h7 zMD@mZ2JRVTHN+fV)+2c*rW_j-vWtV-4H8$r=pjiN{5JWltxS9|pa%(qPHDl{h-Z0z z#aW`7OrlJ!gRMbEv!=_Y)Stob_!-Bykf#6(xgTL!5;@DoP?lCgi3ae|?GMW(oS_xz z7#5J_w3a>P7Ia2`e6^y%!J050V^vJZ@=xwI;-$`nxQCw=RC{yaRl zhJbC0wa6Br1=SWprNF~ZXNlLRHRor`+>z-%dy#VtW5)A0sS~c?xMmH%HOXa4fN4}@AR0@^GW=Lo(t{MCr*cm&H?j285_XzoGfXE zb9ScVEY~8~C1od@C=jI+fj>W4;mv`jBlxQ#q@2FDTklN$=R^gT{5duX4=_Lzjm zCK=>ar8fw;YyCN^iMuU1P-1qc=UhxO!Xl-!xYo*6A4eZ;0*XkQ!-=1jyU8+kSbP`O zmv&-)ChqG-jkb5MBf_~~dM|0J{$I?zPEXBzuoAf`COyw-EUwIa-j}y_E{AiJADfNG zUpF3@gTX%W&eYV{Qgl&V+kq?V<{K&013r0qVi|Z)aK6|K^si)B5ya`(w#QlYpu`*+ zuw=MbTzZ+2?l|jDZrHr0QSvS@1p#h&Cg(@ddYY(3ch{ui>(jda4-jnN9Aj=v;A0=^ zDe`Mk-FJu!_A5@6LW(5IIQX~VLGTz$gTlGDbg1$CAX`GFwwHJw68vlNjfTJL<#{%^ z^-_j>BD2wlby_u zETsU?J9-DWv;&Ok2DkBP(WSY_+@#+Z zI$^qra3)&Mmm<8$lBm6NX{qR0qR{elT4hT9rf0!xe`$N^j(4oXOt}~WbF$ATlKGpmA@C+<$H#!Yz&8AG;FJMazvc*oY z1r;k;{9G^R1KVKUni8i70skB%WJuS+jtF+g|Kd_ToxLroiNANxm% z62gOAMMMd(fRIBbV@e*#%yiGej)b<*Id5S4hak}xcg-4boG5A1!%BD?zUN`205~oi zZ0A)hr`&8jWFzwMR^vEX)c|LGp%rndQ6q?45hB+)_^Jdf7aq$rkWi?ojD*R~I+!>I z_d)kxaWb&>)zPRJ%*pCg`CIYDHw)1HXJfdef4TPpQx{YCoBLgFIKvvh4kFO}z#&72 z(Hr{uub$guCvMtO8ena>=STZr*P?GXSSB*M&G)7W)gSI()`$oh8mpsk6>Bp4Z=rFW zh+9G>msGD5eRX-5;|6WW+@7t=?$Qc>czyM}dk{dNCcADu`n&+-&zHE0(y67YU*Bta$-socw8h9BM0 zfYH%zq$)6Ky62M63JPKR&z~l5e^dyU{qx}h_svM7q0UCEuHYLDHU*Z1&bd4n+CzU1 zQq5OaF-%Fx{O5<_;*5S4;tnvV-^QRZt@NOxff57`=j5!wQc@&WQZiU(W_I~s^n;S( zGW`EEc+eH)jEybFE06u33Jxqq-C9M(RV713{YK7ET?3B6d&(kal!2lmmZIGM*Tl%H zZO$=buLr4)1@yCKy{DQUyb)_P+O>V0%X;_9!YZOPzDqF19(w3e>)#w|)W)URdTZE9 zxL_UF&Rb%3{VYPLhFjs@*mVC>cDdbBh2teB=Zx*)y{Y@P?C-@MtBf;iBr;oC-!~#W zA{MTHlb%N6jWeJP^Oc9Xi z%&yiS>Au)*VYH~|+6-(y)J#1uA0Yk*hznFfzlW9lG`oFzM}{iTq(fm$w5egbk+VLd zI3B@%J-PJD*T<@p*#S%C=o!R&)5(-vv;0!PgW# zd4k)Gm?%_8*!^(r4_S%x&NMX#G7J?pU1pKF{r>%;ksc^O2QyT;Y?=1*^Om zSj;b8U|W_j%NX28A!WyTNn$GW8e@g*?1r$mc@Zgjy<8Am^Oneui04X*hueg>V%N2z zaurAK+O)6|(2>V(GLmn?r@FhY`W-b(imKslnP z-oUF%>$+74I^V|>9XxfSE+{GY%A{Iffo-4Ib(Vb5cNB47U-QPtA%?u%{GCpjxW(2G zbME8^UOh2I0fO^IG|ww*WHOlVf-C8iL*=c=Iwrv`{{X#L2Jnh9jU39OI z^Q$T;k-?V`nv$8Gq(fs@?6Ap)0BmhrJ4p_8b8YU_8d^k;56P0x&#F3Jrh@$OmhwrL zz8=@wmA^lM&1Sd2dqBfv+QH$)@V zBcv=Mtt+;DyJK9Nz8>qjPr62b6QhAa1CvrMXk)G+a&LkjIHwK$8OcO&p7G<7A{`CY z*m~}0-&dUh(+D+uRBHDbT2X7^a2_XMoPu-246`J#*gGPkho-tOa@dWiMf$f0`>K=m z+-_^7>>K^*S)Dk$P#E94_Eec2kLWKouVPAMJ{T*`osr15O$d%&K5%XwN zom+V>rAAQIR!L92U!OsD=3`hTOUB<=ajjUvT$*@aV0}&TNP#;&)Aom&L5s;+z*r3Q z@*g1Jvf{5KQSHn9GUXL5+7H3$!&||NV%Ao_$=^}HpF6l-Ne8Cx`rbGU2y>B(C@3(c zsm5czKWy$w?}m7@%b`c9fUL<%c%$R1z?uOS;;ubxoqNxuz6l4vx+;%@QAuvm?{9Q6 zHXn8aai&CDF0VH1@?bf0vg&3(4qwZnN2wQ}7A3`(St`+nsQifpStU@g*rx@`6kkYR z4m**+vwQrF?gUAH&liarT;{CqV}ZDBGW99{07^ezdh$Sx^z}~E#-I8xg87aXR2Hs( zmF+6-oq9gg^awNBdYkC0dU<7-=4kQeq46HPyl4P$(TJMbMd8bk_S0*YK*Yb(?<|}ecgIYJ{vKyWF#xV+Ol6;0_0+r}}NVvu)sTFpbPRjg=7vD{{ zgBt6lrE%k{iQ3GcPy6%ayv}kL3VnUyRKH-TXV{6i^%_(;L%&hTlKKzeC2A@~_x`zt zby?CRQ$hXVcG6PeslK!r&DFKnCaN{rEGwKT@V6hZILk#_e!r4uN+??hFK{KZ1S)-d zWCtav)4JiFM6m;KyMWS;^7S@C)5F6YCkIK_c7ihdc5OX~sK~!y-aHf%L2~$QwyVB^ zKJzZb{b0MmK$D=Fj~E;g?lVu!mKX4Sc&c;r{E47TvgZ_)G?C0tr8=FKOOY{XYUjQ2 zBXwKLBB=Xf^vo@C99vXlS;`Q9|CjCf3BZBLt?olvF&NNfV{CA_H`Z~UVGmXcRW>+m zQ#2j2Ncwg^E$o--!ImY`?U(#akB^L>(B$sH)VRqmI-&bzS!`bxsMvGso(~_tFGuzd z{gCBn!S839ijPioqn>kV?+LTrE=E8+R(U3S&|4xR$WJlaX9!ogmmq*{$8AvG>5Q7K zY5c|H4tjEj=e!9ob3L5P_6JIy*r%`x^YeH!H#G~GhI=sKSqvuC$QGBGP&;s#!@Bzd zB4ME=q)W9ocfg!B;*`1!da+z#pcO;km0(qV?lLm9MWrGqBNZkB@?S5d~?Yy=`yyHQOz(A z?JcutHX$(=bVV_WtdcBB&Dd9>1S5l%$Y!lFz9RAkHNk{`!=Tm4Wjx-!cWwMgG@I?+Fq(K#= z3{(UedLe4&klulYqO$&+tveUb^)gwr5)5fP5I6q8momFQv$+f3TxyqDUovQms~j*n zx%A87R-jYJnJa(N`Q%;M8)z?HZ?dtHP9Zrt>J7}sBz5(XrCtlHTf$a zaa#!qxK=j}ZZbKHba15G9_PM|mg0SnH@gZjh%_Xg{Z3u!nXDCFh|lP_g9irsCRu6S zHAVgYX)4A4uxAz6V7WAg630&P_BB#AU7_Qp+bK9LQKB7B8h)A*9hn0jtBlu4A*u8A zvpb+}B5&1JG~Cso5r`!vv(5}#E6ESgHVeMRvsdo|dF$8;+=A798+mp=U6avTVbbhX zP2J@3ae@6t(e2yRPeh!9pL+XbYJDI4Uq2q#$ zguO%TKK*pp7NC|l;G)&vZ_lBF!O=8MRUwB4LbT!Q=4bcbH~Pg+q{+AusM2|t!pwvV zXstdM&E{nu2hPjrm%69F7}h8!uQ7vnd_~05o=3|q9qo*;In6DW1+KaJyI|K8T_YXs z$}{VFF}z@-7?hTAp|iVQF5I>)6;6&G!Vk7ufU`oP$M;onJFbnB%zftA6@I!~?foS- z!>eZc=QCFOp64F-Vki2ZHh|?r^TN$R8`3OC8nqaalb5 zxYgngX~xE=`0Reg3X_Gk8! z-S_gHCj*0tm7UqNLkTHS)3j3zF$~BMNczAzr^g!dqBd;Krm3s&+`c;~UH|juSA@A= zAT{e2e)-mw$|~YCUo=>xydw-T33Qu2mr~A1l?nbcw;4T1U0N{{R^9L3`^7mW_3%TEItv>qGeTJ;SUHR*BhCr~KSh zg}xJW0(Rk~#{?HDW9?IjpBK=~-j3kwZo&KYIkDovEt^$&)Rq-RyFOyHBKP9^ENQSL zSBdKvHra$O!=ydWA3-(JA`P_kjg0RH?{GI)X*uj=)T9^ryBAv*uZ>eRnS@Wzpi+g@ zx!_-%Ez77@11sKl9fysE9&UjU?i!fXOK+%|s+e)8wdaq8uewxs5lG?N>1`DSjGlnyXzx4nuifPp_#b6Qx zxtLH0g|)JZdv}TWZ*uL(l#qTuT@9hfqg%K#;XkYT=ETa@s=5S^kt%(0?<3zOSYk`) zAzfMAxPm_GSo}06;ay)2ECAl;oxckjY3-QB$`-Ca_GdVlvHc;EYFzRa2V zGH2pBXXcrd?Eza569gtPJGz2x>##}HCZw~`mbE=98esn})b%eazqY`dS z)GIIf{qdug^F~WKkF==M@h?ek+O_~={4-p5h%5G#em7P>rZ=EY~|YylX$I=rR6CK;pTcb5A(F&xYGIHN!Z`^gukap#?kLm$Q9pn z+s1Rc(;#FpxYgVt`gDKSP==})+!11V!B4sM1Keb(a|Haz#J~pK<_zESVBaQW@9{gG z-(WhO=kM4eTh3oGeg4oN`E_!R0eqk|FE4>P^Odm)kL4(gS%c(mujU~j*ZIBs<7+bw z(qkU<0d$iu7D~5|e-2(0S70ynR1|fzw6^ZjqWjDMsneB}{})>s7r9_*avE7l#Hb*X%NFUiidUfE4xB)NpOljFl-MY^S$2rnXTfcy@YS zdbiQ!w93dnRiy~}pa-uk)zUr&OOVQ|md;yORC>YVV~Wh)p1tADR1ae}{~T$lhKi?Wz6C{qLLf~LxheljRgMCUo*Eu-tG=>SWCZYp!%x716eqdB zKeE9z9Yt4kYWW7+4Ks9(9KMGv*5xd)kN7T@+=WYBMkp>yT3;d3aQ#}3nPpd^#ci%y zhgf|d3dIHoI3hSbpU0-(QXxH`(o%6fkw_4HY;R7^TVd&fOh5h;2I@}bj@Yg4ISvMa z!o5~YDZg;R#kZSlqal5OOU~uj6AVvsw}5pOE_W0V>*O_irE2`7FedbxU5_IleSD|G z_Qp5a+u2bal;&6h zy9E3C9E4H8uv8{>)oh$3e@GT8C-XsfOaI~gpn{DVXU#Y97v!H1bWbRSl%l;B4FT&- z`<6bZ&#TG+<^Fy-0&sbpgG*N->_obht=+;bMqP@xw68yxu*sH6s=xoo_2#HEuQ+Ap z&p-$Uwj`ioA(1pCCq!%evJLAqDmP6B+Nj2jH@JqUUQpvtN{&r=&N=NitZ8v~k*|Xy zXUC#Y;J3@u(qib4LW@xSg!3mPmzfu*K<9LnT{nwy)GQWxz`K)cWhA%6FC9Wa(3w96 zuFMMyhfCypZtt0jyOz>&0fkuWjiZP6cNlHdh4@6kpR@N8MCDqdv7wW4T#V~)V~mWK zSJxhYnnbOrN3W{chKTS8k%?s)?bHUzsYC6d&lfRJuV#W3@-wK=xr-WEd`~O)c-E5& z7JPeo(S(NxDmntFcLfMKR@On73MK_-9RRg~^LqrX@`XeL%=J}_1@j5dnAJ8^?6J6` zT;!n6+@KhP3IeBDOKS2peS%HQ4rJZTf7S(34UC7T*&Voy_@2RT?kH^R zq|ez%>wr-e8}1|M%3#xU+HWq@O0&!9kq;(uG;`Xjsw&b?Z&6`+3i@ppos}o9F#X-3 zqNdv01$3sb*BCCAV0cXYRm*x7BTlOuue$%)qqD}2_@ z_=nOIBrlty7S^vi*lmT|lU)C4Q{3&<8OVjvdr8_nB7s(-xB=wg zL6iDrW?8Ct0Bu=>Yxvz^k~F3xAKj}RQ@*;uM=5)|^$|;-e<&Xq{Syg2YTx&`ANBW} zY2sRWn>7m>7JhxW*1!Hpnv?h1Kvq~$=u9m4=cbuKv6QCB!11!}ADzVQyUW!BFR%SH zqQ=Qfvh_(RmC7PuYZPHnTDc7|Idx~rW&pmf&yM^WRNxYK_Tu)LHwP=c_|rp`f9_iI z$PEYE*qhBxYH3DepyTuwpQe|$l(|RC)a%Z4&9gXZr-Eh;zd-IP*0PUrQv1rQ=3}nT zaWABDgx*(#9!3-=KF(&>+7u%pGl3_>k&f!!%I-Jpk$EPozB;r(L*b1(2fOyPH$g__ zR|QgIUDcqHLjH6&QWG-_H+?31!RK@n+@U8W?GU}zFbAtQ#2;U=Q-~cr);uuDtA^!J ze6zoe|1!|GjJ@8w7GKvy^Amyp3Ep@CtrE;X4l~SV6kE%p4p4Ytv_4xwZI-VO(l?Mk zX=zC}jCc0(5}aFDRB;|DazS2nU6dS&RU9Xsj6F9HZ&z4Kt5TQF8;%{Bg>1KhVm-PT z%VX?v#S`)47RLyMVLefZV1#%fTGMRvcMiT+4!i}l!yYj(_2LBo1KF�EKz0iIh`R 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�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

    tSpU>$WWzREY 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%0DnVM`hO`i!*C>J&(~I~XIGAo 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 W1*gEy-ImP!e=?`|e;0IrR{jUkVNOQ? literal 0 Hc-jL100001 diff --git a/test/testfile.pdf b/test/testfile.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8ae73cb58f1b58b77d03b1a411ee0d665d5f7773 GIT binary patch literal 36613 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 TN6^T~%Sg%43JGZ&>CpZkN{3NR literal 0 Hc-jL100001 diff --git a/test/testfile.ps b/test/testfile.ps new file mode 100644 index 000000000..01c4c08e7 --- /dev/null +++ b/test/testfile.ps @@ -0,0 +1,594 @@ +%!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.2 0 +% +% PostScript test page for the Common UNIX Printing System ("CUPS"). +% +% Copyright 1993-2005 Easy Software Products +% +% These coded instructions, statements, and computer programs are the +% property of Easy Software Products and are protected by Federal +% copyright law. Distribution and use rights are outlined in the file +% "LICENSE.txt" which should have been included with this file. If this +% file is missing or damaged please contact Easy Software Products +% at: +% +% Attn: CUPS Licensing Information +% Easy Software Products +% 44141 Airport View Drive, Suite 204 +% Hollywood, Maryland 20636 USA +% +% Voice: (301) 373-9600 +% EMail: cups-info@cups.org +% WWW: http://www.cups.org +% +/SEXTANT { % Draw a color wheel sextant... + % (name) white radius r g b SEXTANT - + % Loop through 100 shades... + 0 0.010101 0.98 { + % Set the color... + dup 0.75 le { % Get "white" value + % Start from black + dup 0.75 div % val2 = val / 0.75 + + 0 index 5 index mul % R = R * val2 + 1 index 5 index mul % G = G * val2 + 2 index 5 index mul % B = B * val2 + + 4 -1 roll pop % Discard val2 + } { + % Fade to white + dup neg 1 add 4 mul % val2 = (1 - val) * 4 + + 0 index 5 index mul % R = R * val2 + 1 index neg 1 add add % + (1 - val2) + 1 index 5 index mul % G = G * val2 + 2 index neg 1 add add % + (1 - val2) + 2 index 5 index mul % B = B * val2 + 3 index neg 1 add add % + (1 - val2) + + 4 -1 roll pop % Discard val2 + } ifelse + setrgbcolor % Set the color... + + % Draw the polygon... + newpath % Start a new path... + dup 5 index mul % r1 = radius * val + 0 0 3 -1 roll 0 60 arc % Draw the inner arc + + dup 0.010101 add 5 index mul% r2 = (radius + 0.010101) * val + 0 0 3 -1 roll 60 0 arcn % Draw the outer arc + + closepath % Close the path + fill % Fill it... + + pop % Pop value... + } for + + % Draw a line around the polygons... + pop pop pop dup % Pop R, G, B, start + 0 setgray % Black + newpath + 0 0 moveto % Center + 0 0 3 -1 roll 0 60 arc % Arc around octant + closepath % Back to center + stroke % Stroke it... + + % Draw the label... + dup % Save radius + dup 30 cos mul % X = radius * cos(30) + exch 30 sin mul % Y = radius * sin(30) + moveto % Position label + + gsave + 30 rotate % Rotate label + dup 0.05 mul % Offset to the right + exch -0.05 mul % and down... + 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 + + % Set text font and color... + mediumFont setfont % Font + 0 setgray % Color + + % Draw the color wheel... + 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) 3 -1 roll 0 1 1 SEXTANT 60 rotate + dup (M) 3 -1 roll 1 0 1 SEXTANT 60 rotate + dup (Y) 3 -1 roll 1 1 0 SEXTANT 60 rotate + dup (R) 3 -1 roll 1 0 0 SEXTANT 60 rotate + dup (G) 3 -1 roll 0 1 0 SEXTANT 60 rotate + dup (B) 3 -1 roll 0 0 1 SEXTANT 60 rotate + + pop + 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 the gray ramp... + gsave + % Position the gray ramp in the center... + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 54 mul % y = pageHeight * 3/4 * 72 + wheelSize sub % - wheelSize + translate + + % Loop through 100 shades... + 0 0.010101 0.98 { + % Set the color... + dup setgray % Set the grayscale... + + % Draw the polygon... + newpath % Start a new path... + + wheelSize -0.2 mul % X = -wheelSize / 5 + 1 index 2 mul wheelSize mul % Y = val * 2 * wheelSize + moveto % Move there... + + wheelSize 0.4 mul 0 rlineto % Right side... + + wheelSize 0.2 mul % X = wheelSize / 5 + 1 index 0.010101 add 2 mul wheelSize mul + % Y = (val + 0.010101) * 2 * wheelSize + lineto % Move there... + + wheelSize -0.4 mul 0 rlineto % Left side... + + closepath % Close the path + fill % Fill it... + + pop % Pop value... + } for + + 0 setgray % Black + + newpath % Start a new path + wheelSize -0.2 mul 0 moveto % Bottom left + wheelSize 0.4 mul 0 rlineto % Bottom right + 0 wheelSize 2 mul rlineto % Upper right + wheelSize -0.4 mul 0 rlineto % Upper left + closepath % Close the path + stroke % Stroke it... + + 0 wheelSize -0.2 mul moveto % Center bottom for label + (K) CENTER % Center K at bottom + + 0 wheelSize 2.05 mul moveto % Center top for label + (W) CENTER % Center W at top + grestore + + % Label the gray ramp... + pageWidth 36 mul % x = pageWidth * 1/2 * 72 + pageHeight 44 mul % y = pageHeight * 19/32 * 72 + moveto % Position the text + (Gray Ramp) 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.2.x) CENTER % Show text centered + + pageHeight 2 mul sub % Move down... + 2 copy moveto % Position text + smallFont setfont % Font + (Copyright 1993-2005 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, 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 4551 2005-07-28 13:45:00Z 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..3e3e10f53 --- /dev/null +++ b/test/testhp.ppd @@ -0,0 +1,195 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: testhp.ppd 4494 2005-02-18 02:18:11Z mike $" +*% +*% Test HP PPD file for the Common UNIX Printing System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*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: "<>setpagedevice" +*PageSize Legal/US Legal: "<>setpagedevice" +*PageSize Executive/US Executive: "<>setpagedevice" +*PageSize Tabloid/US Tabloid: "<>setpagedevice" +*PageSize A3/A3: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/US Letter: "<>setpagedevice" +*PageRegion Legal/US Legal: "<>setpagedevice" +*PageRegion Executive/US Executive: "<>setpagedevice" +*PageRegion Tabloid/US Tabloid: "<>setpagedevice" +*PageRegion A3/A3: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "18 36 594 756" +*ImageableArea Legal/US Legal: "18 36 594 972" +*ImageableArea Executive/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: "<>setpagedevice" +*MediaType Bond/Bond Paper: "<>setpagedevice" +*MediaType Special/Special Paper: "<>setpagedevice" +*MediaType Transparency/Transparency: "<>setpagedevice" +*MediaType Glossy/Glossy Paper: "<>setpagedevice" +*CloseUI: *MediaType + +*OpenUI *InputSlot/Media Source: PickOne +*OrderDependency: 10 AnySetup *InputSlot +*DefaultInputSlot: Tray +*InputSlot Tray/Tray: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 100dpi +*Resolution 75dpi/75 DPI: "<>setpagedevice" +*Resolution 100dpi/100 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/CMYK Color: "<>setpagedevice" +*ColorModel RGB/CMY Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: testhp.ppd 4494 2005-02-18 02:18:11Z mike $". +*% diff --git a/test/testps.ppd b/test/testps.ppd new file mode 100644 index 000000000..9694923c2 --- /dev/null +++ b/test/testps.ppd @@ -0,0 +1,192 @@ +*PPD-Adobe: "4.3" +*% +*% "$Id: testps.ppd 4494 2005-02-18 02:18:11Z mike $" +*% +*% Test PS PPD file for the Common UNIX Printing System (CUPS). +*% +*% Copyright 1997-2005 by Easy Software Products. +*% +*% These coded instructions, statements, and computer programs are the +*% property of Easy Software Products and are protected by Federal +*% copyright law. Distribution and use rights are outlined in the file +*% "LICENSE.txt" which should have been included with this file. If this +*% file is missing or damaged please contact Easy Software Products +*% at: +*% +*% Attn: CUPS Licensing Information +*% Easy Software Products +*% 44141 Airport View Drive, Suite 204 +*% Hollywood, Maryland 20636 USA +*% +*% Voice: (301) 373-9600 +*% EMail: cups-info@cups.org +*% WWW: http://www.cups.org +*% +*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: "<>setpagedevice" +*PageSize Legal/US Legal: "<>setpagedevice" +*PageSize Executive/US Executive: "<>setpagedevice" +*PageSize Tabloid/US Tabloid: "<>setpagedevice" +*PageSize A3/A3: "<>setpagedevice" +*PageSize A4/A4: "<>setpagedevice" +*PageSize A5/A5: "<>setpagedevice" +*PageSize B5/B5 (JIS): "<>setpagedevice" +*PageSize EnvISOB5/Envelope B5: "<>setpagedevice" +*PageSize Env10/Envelope #10: "<>setpagedevice" +*PageSize EnvC5/Envelope C5: "<>setpagedevice" +*PageSize EnvDL/Envelope DL: "<>setpagedevice" +*PageSize EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageSize + +*OpenUI *PageRegion: PickOne +*OrderDependency: 10 AnySetup *PageRegion +*DefaultPageRegion: Letter +*PageRegion Letter/US Letter: "<>setpagedevice" +*PageRegion Legal/US Legal: "<>setpagedevice" +*PageRegion Executive/US Executive: "<>setpagedevice" +*PageRegion Tabloid/US Tabloid: "<>setpagedevice" +*PageRegion A3/A3: "<>setpagedevice" +*PageRegion A4/A4: "<>setpagedevice" +*PageRegion A5/A5: "<>setpagedevice" +*PageRegion B5/B5 (JIS): "<>setpagedevice" +*PageRegion EnvISOB5/Envelope B5: "<>setpagedevice" +*PageRegion Env10/Envelope #10: "<>setpagedevice" +*PageRegion EnvC5/Envelope C5: "<>setpagedevice" +*PageRegion EnvDL/Envelope DL: "<>setpagedevice" +*PageRegion EnvMonarch/Envelope Monarch: "<>setpagedevice" +*CloseUI: *PageRegion + +*DefaultImageableArea: Letter +*ImageableArea Letter/US Letter: "18 36 594 756" +*ImageableArea Legal/US Legal: "18 36 594 972" +*ImageableArea Executive/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: "<>setpagedevice" +*MediaType Bond/Bond Paper: "<>setpagedevice" +*MediaType Special/Special Paper: "<>setpagedevice" +*MediaType Transparency/Transparency: "<>setpagedevice" +*MediaType Glossy/Glossy Paper: "<>setpagedevice" +*CloseUI: *MediaType + +*OpenUI *InputSlot/Media Source: PickOne +*OrderDependency: 10 AnySetup *InputSlot +*DefaultInputSlot: Tray +*InputSlot Tray/Tray: "<>setpagedevice" +*InputSlot Manual/Manual Feed: "<>setpagedevice" +*InputSlot Envelope/Envelope Feed: "<>setpagedevice" +*CloseUI: *InputSlot + +*OpenUI *Resolution/Output Resolution: PickOne +*OrderDependency: 20 AnySetup *Resolution +*DefaultResolution: 100dpi +*Resolution 75dpi/75 DPI: "<>setpagedevice" +*Resolution 100dpi/100 DPI: "<>setpagedevice" +*CloseUI: *Resolution + +*OpenUI *ColorModel/Output Mode: PickOne +*OrderDependency: 10 AnySetup *ColorModel +*DefaultColorModel: CMYK +*ColorModel CMYK/CMYK Color: "<>setpagedevice" +*ColorModel RGB/CMY Color: "<>setpagedevice" +*ColorModel Gray/Grayscale: "<>setpagedevice" +*CloseUI: *ColorModel + +*DefaultFont: Courier +*Font AvantGarde-Book: Standard "(001.006S)" Standard ROM +*Font AvantGarde-BookOblique: Standard "(001.006S)" Standard ROM +*Font AvantGarde-Demi: Standard "(001.007S)" Standard ROM +*Font AvantGarde-DemiOblique: Standard "(001.007S)" Standard ROM +*Font Bookman-Demi: Standard "(001.004S)" Standard ROM +*Font Bookman-DemiItalic: Standard "(001.004S)" Standard ROM +*Font Bookman-Light: Standard "(001.004S)" Standard ROM +*Font Bookman-LightItalic: Standard "(001.004S)" Standard ROM +*Font Courier: Standard "(002.004S)" Standard ROM +*Font Courier-Bold: Standard "(002.004S)" Standard ROM +*Font Courier-BoldOblique: Standard "(002.004S)" Standard ROM +*Font Courier-Oblique: Standard "(002.004S)" Standard ROM +*Font Helvetica: Standard "(001.006S)" Standard ROM +*Font Helvetica-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow: Standard "(001.006S)" Standard ROM +*Font Helvetica-Narrow-Bold: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-BoldOblique: Standard "(001.007S)" Standard ROM +*Font Helvetica-Narrow-Oblique: Standard "(001.006S)" Standard ROM +*Font Helvetica-Oblique: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Bold: Standard "(001.009S)" Standard ROM +*Font NewCenturySchlbk-BoldItalic: Standard "(001.007S)" Standard ROM +*Font NewCenturySchlbk-Italic: Standard "(001.006S)" Standard ROM +*Font NewCenturySchlbk-Roman: Standard "(001.007S)" Standard ROM +*Font Palatino-Bold: Standard "(001.005S)" Standard ROM +*Font Palatino-BoldItalic: Standard "(001.005S)" Standard ROM +*Font Palatino-Italic: Standard "(001.005S)" Standard ROM +*Font Palatino-Roman: Standard "(001.005S)" Standard ROM +*Font Symbol: Special "(001.007S)" Special ROM +*Font Times-Bold: Standard "(001.007S)" Standard ROM +*Font Times-BoldItalic: Standard "(001.009S)" Standard ROM +*Font Times-Italic: Standard "(001.007S)" Standard ROM +*Font Times-Roman: Standard "(001.007S)" Standard ROM +*Font ZapfChancery-MediumItalic: Standard "(001.007S)" Standard ROM +*Font ZapfDingbats: Special "(001.004S)" Standard ROM +*% +*% End of "$Id: testps.ppd 4494 2005-02-18 02:18:11Z mike $". +*% diff --git a/tools/makesrcdist b/tools/makesrcdist new file mode 100755 index 000000000..b0cb5dfe1 --- /dev/null +++ b/tools/makesrcdist @@ -0,0 +1,71 @@ +#!/bin/sh +# +# "$Id$" +# +# makesrcdist - make a source distribution of CUPS. +# + +# Make sure we are running in the right directory... +if test ! -f tools/makesrcdist; then + echo "Run this script from the top-level CUPS source directory, e.g.:" + echo "" + echo " tools/makesrcdist $*" + echo "" + exit 1 +fi + +if test $# = 0; then + echo Updating for snapshot... + svn up + rev=`svnversion . | sed -e '1,$s/[a-zA-Z]//g'` + version="1.2svn" + fileversion="1.2svn-r$rev" + fileurl="ftp://ftp.easysw.com/pub/cups/test/cups-$fileversion-source.tar.bz2" + url="." +else + echo Creating tag for release... + rev="1" + version=$1 + fileversion=$1 + fileurl="ftp://ftp.easysw.com/pub/cups/$version/cups-$fileversion-source.tar.bz2" + url="https://svn.easysw.com/public/cups/tags/release-$version" + + svn copy https://svn.easysw.com/public/cups/trunk "$url" \ + -m "Tag $version" || exit 1 +fi + +echo Exporting $fileversion... +rm -rf /tmp/cups-$version +svn export $url /tmp/cups-$version + +echo Updating version information... +cd /tmp/cups-$version/config-scripts + +sed -e '1,$s/^CUPS_VERSION=.*/CUPS_VERSION='$version'/' \ + cups-common.m4.new +mv cups-common.m4.new cups-common.m4 +cd .. +fileurl=`echo $fileurl | sed -e '1,$s/\\//\\\\\\//g'` +sed -e '1,$s/@CUPS_VERSION@/'$version'/' \ + -e '1,$s/^Release:.*/Release: '$rev'/' \ + -e '1,$s/^Source:.*/Source: '$fileurl'/' \ + packaging/cups.spec + +echo Configuring... +autoconf -f +rm -rf autom4te*.cache +rm -rf standards +rm -rf tools +cd .. + +echo -n Archiving...gz +tar czf cups-$version-r$rev-source.tar.gz cups-$version +echo -n ...bz2 +tar cjf cups-$version-r$rev-source.tar.bz2 cups-$version +echo "..." + +echo "Done!" + +# +# End of "$Id$". +# diff --git a/tools/testosx b/tools/testosx new file mode 100755 index 000000000..d96e9f472 --- /dev/null +++ b/tools/testosx @@ -0,0 +1,87 @@ +#!/bin/sh +# Make sure we are running in the right directory... +if test ! -f tools/testosx; then + echo "Run this script from the top-level CUPS source directory, e.g.:" + echo "" + echo " tools/testosx" + echo "" + exit 1 +fi + +# Update the current working copy... +svn up +rev=`svnversion . | sed -e '1,$s/[a-zA-Z]//g'` + +# Make everything... +make all + +# Setup an install directory... +user=`whoami` +topdir=`pwd` +pkgdir="/tmp/cups.pkg-$user" + +echo Building package using temp directory $pkgdir... +rm -rf $pkgdir +mkdir -p $pkgdir/Package +mkdir -p $pkgdir/Resources + +# Install CUPS into the Package directory... +#make INSTALL=$topdir/install-sh BUILDROOT=$pkgdir/Package install +make BUILDROOT=$pkgdir/Package install + +# Install resource files into the Resources directory... +echo Installing resource files... +cp packaging/LICENSE.rtf $pkgdir/Resources/ReadMe.rtf +cp packaging/WELCOME.rtf $pkgdir/Resources/Welcome.rtf +cp packaging/installer.tif $pkgdir/Resources/background.tif + +cat >$pkgdir/Resources/preflight <$pkgdir/Resources/postflight <packaging/cups-desc.plist +sed -e '1,$s/@CUPS_VERSION@/1.2svn-r'$rev'/g' \ + -e '1,$s/@CUPS_RELEASE@/1.2.'$rev'/g' \ + packaging/cups-info.plist +sed -e '1,$s/@CUPS_VERSION@/1.2svn-r'$rev'/g' \ + doc/index.html + +# Figure out where PackageMaker is installled... +if test -d /Developer/Applications/Utilities/PackageMaker.app; then + PackageMaker=/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker +else + PackageMaker=/Developer/Applications/PackageMaker.app/Contents/MacOS/PackageMaker +fi + +# Create the package... +echo Creating MacOS X package... +rm -rf cups.pkg +echo $PackageMaker -build -v -p cups.pkg \ + -f $pkgdir/Package \ + -r $pkgdir/Resources \ + -d packaging/cups-desc.plist \ + -i packaging/cups-info.plist +$PackageMaker -build -v -p cups.pkg \ + -f $pkgdir/Package \ + -r $pkgdir/Resources \ + -d packaging/cups-desc.plist \ + -i packaging/cups-info.plist + +# Create a disk image... +echo Creating MacOS X disk image... +hdiutil create -ov -srcfolder cups.pkg cups-1.2svn-r$rev.dmg + +# Cleanup temp files... +echo Removing temporary files... +rm -rf $pkgdir diff --git a/tools/testrpm b/tools/testrpm new file mode 100755 index 000000000..047200ef7 --- /dev/null +++ b/tools/testrpm @@ -0,0 +1,28 @@ +#!/bin/sh +# +# "$Id$" +# +# Test script for making RPMs... +# + +# Make sure we are running in the right directory... +if test ! -f tools/testrpm; then + echo "Run this script from the top-level CUPS source directory, e.g.:" + echo "" + echo " tools/testrpm" + echo "" + exit 1 +fi + +# Get a snapshot of the current source... +. tools/makesrcdist + +# Build the RPM... +echo Building rpm... +rm -f /usr/src/redhat/RPMS/i386/cups*.rpm +rm -f /usr/src/redhat/SRPMS/cups*.rpm +rpmbuild -ta cups-$fileversion-source.tar.bz2 + +# +# End of "$Id$". +# diff --git a/vcnet/config.h b/vcnet/config.h new file mode 100644 index 000000000..c5f1752d0 --- /dev/null +++ b/vcnet/config.h @@ -0,0 +1,352 @@ +/* + * "$Id: config.h 4828 2005-11-11 12:53:38Z mike $" + * + * Configuration file for the Common UNIX Printing System (CUPS). + * + * Copyright 1997-2005 by Easy Software Products. + * + * These coded instructions, statements, and computer programs are the + * property of Easy Software Products and are protected by Federal + * copyright law. Distribution and use rights are outlined in the file + * "LICENSE.txt" which should have been included with this file. If this + * file is missing or damaged please contact Easy Software Products + * at: + * + * Attn: CUPS Licensing Information + * Easy Software Products + * 44141 Airport View Drive, Suite 204 + * Hollywood, Maryland 20636 USA + * + * Voice: (301) 373-9600 + * EMail: cups-info@cups.org + * WWW: http://www.cups.org + */ + +#ifndef _CUPS_CONFIG_H_ +#define _CUPS_CONFIG_H_ + +/* + * Compiler stuff... + */ + +#undef const +#undef __CHAR_UNSIGNED__ + + +/* + * Version of software... + */ + +#define CUPS_SVERSION "CUPS v1.2svn" +#define CUPS_MINIMAL "CUPS/1.2svn" + + +/* + * Default user and group... + */ + +#define CUPS_DEFAULT_USER "lp" +#define CUPS_DEFAULT_GROUP "sys" + + +/* + * Default IPP port... + */ + +#define CUPS_DEFAULT_IPP_PORT 631 + + +/* + * Maximum number of file descriptors to support. + */ + +#define CUPS_MAX_FDS 4096 + + +/* + * Do we have domain socket support? + */ + +#undef CUPS_DEFAULT_DOMAINSOCKET + + +/* + * Where are files stored? + * + * Note: These are defaults, which can be overridden by environment + * variables at run-time... + */ + +#define CUPS_CACHEDIR "C:/CUPS/cache" +#define CUPS_DATADIR "C:/CUPS/share" +#define CUPS_DOCROOT "C:/CUPS/share/doc" +#define CUPS_FONTPATH "C:/CUPS/share/fonts" +#define CUPS_LOCALEDIR "C:/CUPS/locale" +#define CUPS_LOGDIR "C:/CUPS/logs" +#define CUPS_REQUESTS "C:/CUPS/spool" +#define CUPS_SERVERBIN "C:/CUPS/lib" +#define CUPS_SERVERROOT "C:/CUPS/etc" +#define CUPS_STATEDIR "C:/CUPS/run" + + +/* + * Do we have various image libraries? + */ + +#undef HAVE_LIBPNG +#undef HAVE_LIBZ +#undef HAVE_LIBJPEG +#undef HAVE_LIBTIFF + + +/* + * Do we have PAM stuff? + */ + +#ifndef HAVE_LIBPAM +#define HAVE_LIBPAM 0 +#endif /* !HAVE_LIBPAM */ + +#undef HAVE_PAM_PAM_APPL_H + + +/* + * Do we have ? + */ + +#undef HAVE_SHADOW_H + + +/* + * Do we have ? + */ + +#undef HAVE_CRYPT_H + + +/* + * Use , , and/or ? + */ + +#define HAVE_STRING_H +#undef HAVE_STRINGS_H +#undef HAVE_BSTRING_H + + +/* + * Do we have the long long type? + */ + +#undef HAVE_LONG_LONG + +#ifdef HAVE_LONG_LONG +# define CUPS_LLFMT "%lld" +# define CUPS_LLCAST (long long) +#else +# define CUPS_LLFMT "%ld" +# define CUPS_LLCAST (long) +#endif /* HAVE_LONG_LONG */ + + +/* + * Do we have the strtoll() function? + */ + +#undef HAVE_STRTOLL + +#ifndef HAVE_STRTOLL +# define strtoll(nptr,endptr,base) strtol((nptr), (endptr), (base)) +#endif /* !HAVE_STRTOLL */ + + +/* + * Do we have the strXXX() functions? + */ + +#define HAVE_STRDUP +#define HAVE_STRCASECMP +#define HAVE_STRNCASECMP +#undef HAVE_STRLCAT +#undef HAVE_STRLCPY + + +/* + * Do we have the geteuid() function? + */ + +#undef HAVE_GETEUID + + +/* + * 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 langinfo.h header file? + */ + +#undef HAVE_LANGINFO_H + + +/* + * Which encryption libraries do we have? + */ + +#undef HAVE_CDSASSL +#undef HAVE_GNUTLS +#undef HAVE_LIBSSL +#undef HAVE_SSL + + +/* + * Do we have the OpenSLP library? + */ + +#undef HAVE_LIBSLP + + +/* + * Do we have libpaper? + */ + +#undef HAVE_LIBPAPER + + +/* + * Do we have ? + */ + +#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_af()? + */ + +#undef HAVE_RRESVPORT_AF + + +/* + * Do we have getaddrinfo()? + */ + +#define HAVE_GETADDRINFO + + +/* + * Do we have getnameinfo()? + */ + +#define HAVE_GETNAMEINFO + + +/* + * Do we have getifaddrs()? + */ + +#undef HAVE_GETIFADDRS + + +/* + * Do we have hstrerror()? + */ + +#undef HAVE_HSTRERROR + + +/* + * Do we have the header file? + */ + +#undef HAVE_SYS_SOCKIO_H + + +/* + * Does the sockaddr structure contain an sa_len parameter? + */ + +#undef HAVE_STRUCT_SOCKADDR_SA_LEN + + +/* + * Do we have the AIX usersec.h header file? + */ + +#undef HAVE_USERSEC_H + +/* + * Do we have pthread support? + */ + +#undef HAVE_PTHREAD_H + + +/* + * Various scripting languages... + */ + +#undef HAVE_JAVA +#define CUPS_JAVA "/usr/bin/java" +#undef HAVE_PERL +#define CUPS_PERL "/usr/bin/perl" +#undef HAVE_PHP +#define CUPS_PHP "/usr/bin/php" +#undef HAVE_PYTHON +#define CUPS_PYTHON "/usr/bin/python" + + +#endif /* !_CUPS_CONFIG_H_ */ + +/* + * End of "$Id: config.h 4828 2005-11-11 12:53:38Z mike $". + */ diff --git a/vcnet/cups.sln b/vcnet/cups.sln new file mode 100644 index 000000000..093265c9d --- /dev/null +++ b/vcnet/cups.sln @@ -0,0 +1,21 @@ +Microsoft Visual Studio Solution File, Format Version 8.00 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcups2", "libcups2.vcproj", "{CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}" + ProjectSection(ProjectDependencies) = postProject + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfiguration) = preSolution + Debug = Debug + Release = Release + EndGlobalSection + GlobalSection(ProjectConfiguration) = postSolution + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug.ActiveCfg = Debug|Win32 + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Debug.Build.0 = Debug|Win32 + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release.ActiveCfg = Release|Win32 + {CB4AA6F2-3E84-45BE-B505-95CD375E8BE3}.Release.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + EndGlobalSection + GlobalSection(ExtensibilityAddIns) = postSolution + EndGlobalSection +EndGlobal diff --git a/vcnet/libcups2.def b/vcnet/libcups2.def new file mode 100644 index 000000000..3aa6c9cb7 --- /dev/null +++ b/vcnet/libcups2.def @@ -0,0 +1,247 @@ +LIBRARY libcups2 +VERSION 2.6 +EXPORTS +cupsAddDest +cupsAddOption +cupsArrayAdd +cupsArrayClear +cupsArrayCount +cupsArrayCurrent +cupsArrayDelete +cupsArrayDup +cupsArrayFind +cupsArrayFirst +cupsArrayLast +cupsArrayNew +cupsArrayNext +cupsArrayPrev +cupsArrayRemove +cupsArrayRestore +cupsArraySave +cupsBackchannelRead +cupsBackchannelWrite +cupsCancelJob +cupsCharmapFlush +cupsCharmapFree +cupsCharmapGet +cupsCharsetToUTF8 +cupsDirClose +cupsDirOpen +cupsDirRead +cupsDirRewind +cupsDoAuthentication +cupsDoFileRequest +cupsEncodeOptions +cupsEncodeOptions2 +cupsEncodingName +cupsEncryption +cupsFileClose +cupsFileCompression +cupsFileEOF +cupsFileFlush +cupsFileGetChar +cupsFileGetConf +cupsFileGets +cupsFileLock +cupsFileNumber +cupsFileOpen +cupsFileOpenFd +cupsFilePeekChar +cupsFilePrintf +cupsFilePutChar +cupsFilePuts +cupsFileRead +cupsFileRewind +cupsFileSeek +cupsFileTell +cupsFileUnlock +cupsFileWrite +cupsFreeDests +cupsFreeJobs +cupsFreeOptions +cupsGetClasses +cupsGetDefault +cupsGetDefault2 +cupsGetDest +cupsGetDests +cupsGetDests2 +cupsGetFd +cupsGetFile +cupsGetJobs +cupsGetJobs2 +cupsGetOption +cupsGetPassword +cupsGetPPD +cupsGetPPD2 +cupsGetPrinters +cupsLangEncoding +cupsLangFlush +cupsLangFree +cupsLangGet +cupsLangPrintf +cupsLangPuts +cupsLastError +cupsMarkOptions +_cups_md5_append +_cups_md5_finish +_cups_md5_init +cupsNormalizeMapsFlush +cupsNormalizeMapsFree +cupsNormalizeMapsGet +cupsParseOptions +cupsPrintFile +cupsPrintFile2 +cupsPrintFiles +cupsPrintFiles2 +cupsPutFd +cupsPutFile +_cupsRestoreLocale +_cupsSaveLocale +cupsServer +cupsSetDests +cupsSetDests2 +cupsSetEncryption +cupsSetPasswordCB +cupsSetServer +cupsSetUser +_cups_strcpy +_cups_strlcat +_cups_strlcpy +cupsTempFd +cupsTempFile +cupsTempFile2 +cupsUser +cupsUTF16ToUTF32 +cupsUTF16ToUTF8 +cupsUTF32CaseFold +cupsUTF32CharacterProperty +cupsUTF32CompareCaseless +cupsUTF32CompareIdentifier +cupsUTF32Normalize +cupsUTF32ToUTF16 +cupsUTF32ToUTF8 +cupsUTF8CaseFold +cupsUTF8CompareCaseless +cupsUTF8CompareIdentifier +cupsUTF8Normalize +cupsUTF8ToCharset +cupsUTF8ToUTF16 +cupsUTF8ToUTF32 +httpAddrAny +httpAddrConnect +httpAddrEqual +httpAddrFreeList +httpAddrGetList +httpAddrLength +httpAddrLocalhost +httpAddrLookup +httpAddrString +httpAssembleURI +httpAssembleURIf +httpCheck +httpClearCookie +httpClose +httpConnect +httpConnectEncrypt +httpDecode64 +httpDecode64_2 +httpDelete +httpEncode64 +httpEncode64_2 +httpEncryption +httpFlush +httpFlushWrite +httpGet +httpGetDateString +httpGetDateString2 +httpGetDateTime +httpGetHostByName +httpGetHostname +httpGetLength +httpGetLength2 +httpGets +httpGetSubField +httpGetSubField2 +httpHead +httpInitialize +httpMD5 +httpMD5Final +httpMD5String +httpOptions +httpPost +httpPrintf +httpPut +httpRead +httpReconnect +httpSeparate +httpSeparate2 +httpSeparateURI +httpSetCookie +httpSetField +httpSetLength +httpStatus +httpTrace +httpUpdate +httpWait +httpWrite +_ipp_add_attr +ippAddBoolean +ippAddBooleans +ippAddCollection +ippAddCollections +ippAddDate +ippAddInteger +ippAddIntegers +ippAddRange +ippAddRanges +ippAddResolution +ippAddResolutions +ippAddSeparator +ippAddString +ippAddStrings +ippDateToTime +ippDelete +ippDeleteAttribute +ippErrorString +ippErrorValue +ippFindAttribute +ippFindNextAttribute +_ipp_free_attr +ippLength +ippNew +ippOpString +ippOpValue +ippPort +ippRead +ippReadFile +ippReadIO +ippSetPort +ippTimeToDate +ippWrite +ippWriteFile +ippWriteIO +ppdClose +ppdCollect +ppdConflicts +ppdEmit +ppdEmitFd +ppdEmitJCL +ppdEmitJCLEnd +ppdErrorString +ppdFindAttr +ppdFindChoice +ppdFindMarkedChoice +ppdFindNextAttr +ppdFindOption +ppdIsMarked +ppdLastError +ppdMarkDefaults +ppdMarkOption +ppdOpen +ppdOpen2 +ppdOpenFd +ppdOpenFile +ppdPageLength +ppdPageSize +ppdPageWidth +ppdSetConformance diff --git a/vcnet/libcups2.vcproj b/vcnet/libcups2.vcproj new file mode 100644 index 000000000..af3d2deb3 --- /dev/null +++ b/vcnet/libcups2.vcproj @@ -0,0 +1,286 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- 2.39.2

    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Ô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 F`wtb9$D{xN literal 0 Hc-jL100001 diff --git a/doc/idd.shtml b/doc/idd.shtml new file mode 100644 index 000000000..37821ab7f --- /dev/null +++ b/doc/idd.shtml @@ -0,0 +1,1445 @@ + + + + + + CUPS Interface Design Description + + + +

    CUPS Configuration Management Plan
    +

    CUPS Configuration Management Plan


    +CUPS-CMP-1.1
    +Easy Software Products
    +Copyright 1997-2005, All Rights Reserved
    +